<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="https://blog.cytrogen.icu/feed.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Cytrogen 的个人博客（中文）</title>
  
  <subtitle>万圣节恶魔的领地</subtitle>
  <link href="https://blog.cytrogen.icu/atom-zh.xml" rel="self"/>
  
  <link href="https://blog.cytrogen.icu/"/>
  <updated>2026-09-17T01:54:28.066Z</updated>
  <id>https://blog.cytrogen.icu/</id>
  
  <author>
    <name>Cytrogen</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>写写废文</title>
    <link href="https://blog.cytrogen.icu/posts/f2b7.html"/>
    <id>https://blog.cytrogen.icu/posts/f2b7.html</id>
    <published>2026-09-17T01:52:00.000Z</published>
    <updated>2026-09-17T01:54:28.066Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>此「废文」非彼废文；指的是随手写的、不以传递信息或者涨流量为目的的短文。</p><span id="more"></span><p>它们通常包括生活琐事、流水账、没有观点且没有建设性的自言自语、想到就写的短随笔。</p><p>我最初是从「廢文小天地」那边看到的这个词儿。</p><p><a href="https://trashposts.com/">https://trashposts.com/</a></p><p>但是当时没有细究「废文」到底是什么。</p><p>后来我在 Marcus 的签名墙那边看到「心是灵」也提到了这个词，并且说 Marcus 写的是「废文」。我就一下子对「废文」这个词有了映射⸺大概就是对日常生活的记录吧！</p><p><a href="https://immarcus.com/wall">https://immarcus.com/wall</a></p><p>当然后面自己查了下才知道最开始写的那些定义。</p><p>至于为什么我会去看 Marcus 的签名墙…… 我只能说罪犯总是会回到犯案现场的。</p><p>求求你，来人告诉我其实你们也会评论完然后时不时去看看自己的评论吧……！</p><p>我之前有说过，我最近疲倦到难以聚集精力去思考了，所以我想要随便写点东西然后发发发。美名其曰 omakase 呀。</p><p><a href="https://blog.cytrogen.icu/posts/2e54.html">https://blog.cytrogen.icu/posts/2e54.html</a></p><p>所以我也发点废文好了。</p><p>现在努力找工作的期间，时间与精力变成一片一片的，像是碎片那样，再要求自己花一天的时间专注于阅读还有思考长文上，不太现实。</p><p>那娱乐换成更大众的看网文、短视频咧？我不习惯那样，并且看多了我会脑子腐烂掉、特别特别难受。</p><p>还不如写写废文呢。</p><p>比较有意思的是，我在学校的 WordPress 博客平台上注册账号以及创建网站后，我每次打开它都会涌现写废文的冲动。明明最开始注册它是为了写学术还有技术文章的。</p><p>不过我写废文有很强烈的「我」的味道。我还是不希望在学校的博客平台上展现「自我」。</p><p>所以作为替代的发泄口，我应该在这个博客站多用英语写废文。那是不是得分开下 RSS 链接呢？等下就去做吧~</p><p>总之你也写写废文吧。</p><p>大家都写写废文。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;此「废文」非彼废文；指的是随手写的、不以传递信息或者涨流量为目的的短文。&lt;/p&gt;</summary>
    
    
    
    <category term="废文" scheme="https://blog.cytrogen.icu/categories/%E5%BA%9F%E6%96%87/"/>
    
    
  </entry>
  
  <entry>
    <title>教小孩子的时候家长要闭嘴</title>
    <link href="https://blog.cytrogen.icu/posts/fd5.html"/>
    <id>https://blog.cytrogen.icu/posts/fd5.html</id>
    <published>2026-09-15T20:45:00.000Z</published>
    <updated>2026-09-15T20:46:44.713Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我和妹妹的年纪相差十岁多。待她十八岁成年的时候，我都三十岁了要。而这般年龄差意味着我们出生的环境截然不同，性格也天差地别。</p><span id="more"></span><p>比方说，妹妹是游泳健将，天天都要去本地的大学那儿接受训练，时不时还要去打比赛，而我是个 chairman，整天就坐在椅子上；妹妹数学成绩很差，我在她的年纪的时候上数学课就是来玩的；妹妹喜欢玩短视频平台，然后追韩国女团，我近乎不会使用短视频软件，也不喜欢明星还有偶像。</p><p>妹妹作为纯正的 ABC（在美国出生的中国人），她所接受的教育、在学校以及小伙伴那儿学习到的东西，意味着她会离父母这帮移民的文化越来越远。我平时都是跟她用英语交流。对父母的时候，虽然她能听以及说部分普通话，但到要描述稍微有些细的事情时，比方说想要父亲帮她剥香蕉，她就说不清楚，导致父亲以为她是给他香蕉吃。这时候我就要充当中间的翻译官。</p><p>非常有趣地，妹妹虽然是中国人，但并没有「继承」中国人的刻板印象，也就是先前说的，她的数学成绩很差。如果满分是 4 的话，她的数学成绩平均下来是个 2。</p><p>这让母亲愁坏了。她认识的和妹妹同岁的小孩子里，数学成绩都是平均到 4。母亲一直都是个有怪异竞争心的人，包括她从来不在乎我的学业，但听到我的 SAT 成绩远远不到满分时，还是嘲笑道「我以为你有多厉害呢！」⸺理由是她有个远房亲戚的女儿考了近满分、上了 MIT。</p><p>择校时，她也是完全基于所谓的「名校排名榜」来选。听到别人上的大学，第一时间便是去问 ChatGPT 这所学校的排名多少⸺拜托，学校排名我就先不说到底是什么鬼玩意儿了，择校的重点不应该是该校在专业上投入的资源么？你单看综合排名有什么用啊？</p><p>我上的大学虽然在计算机领域上糟糕到不知道说什么好，但是在商科上是数一数二的、学费远比纽约大学便宜，且同样位于华尔街旁边。一位在国内学习金融工程的亲戚有过来问我转学到美国的话转到哪所学校比较好，我就有提到我校。结果母亲事后跟我说那个亲戚在国内上很好的大学，来我校是不是屈才了。</p><p>那你就去问问你的 ChatGPT 老师好了，不要来问我！</p><p>因此，母亲也一直数落妹妹的数学成绩不够好，让她「担心」妹妹的未来⸺难道不是自己的面子吗？这些妈妈圈子整天就是攀比孩子的成绩、去的学校的成绩、学校里的绩点…… 真是令人感到恶心。小孩子也受此影响，觉得自己成绩好、刷题多，就是更聪明的，别人做得没有自己好，就是傻逼。就算是一起去游泳，也会出现因为不想要输给对方，所以故意挡路的情况。妈妈们再拍下来，跟其他妈妈们责怪说「哎呀这个小孩子攀比心太强了！」</p><p>不都是你们的原因么。</p><p>不过妹妹的成绩确实需要点推力。至少不要每次都待在及格线边缘吧。母亲给我钱说，她本来打算把妹妹送到辅导班里面，但如果我能教她的话，那不如把钱给我赚⸺顺便还能省掉给我的生活费⸺所以我就成了妹妹的辅导老师。</p><p>首先是应当给妹妹养成每日做题的习惯。要应付她现在的学校作业还有考试，熟能生巧是最好使的。于是我上网给她打印了一些数学题，让她平日做。</p><p><a href="https://www.k5learning.com/free-math-worksheets/sixth-grade-6">https://www.k5learning.com/free-math-worksheets/sixth-grade-6</a></p><p>美国公立学校的作业我还是清楚几斤几两的。作为练习、量完全不够。回父母家那天，我一边翻看基督教会送来的期刊⸺父母家里实在是没有别的书了⸺一边看着她做题。这时候就能看出她做题所运用的方法，比如说面对乘法题会更倾向于硬做。8 乘以 102，她会将其视为「8 乘以 102」然后算，而不是简单地将其视为「8 乘以 100 加 8 乘以 2」。我便跟她讲了下其实可以这么做，她半信半疑，验证下发现我说得没错，就 <em> Ohhhh</em> 地继续做类似的题。</p><p>结果扫兴的母亲在旁边看到我指点她，就不停开始问我，且还是当着妹妹面地说，「她是不是数学很烂？…… 别人都去补习了，成绩那么好，考那么高分…… 她数学这么烂，完蛋了……」</p><p>闭上你的嘴吧！我心里想着，然后叫她不要说了。</p><p>就是因为你们天天在想这种事情，所以害得小孩子们做什么都没有干劲儿。妹妹游泳好，很大程度是当时去的泳池那儿有个教练，看中了她，问要不要到他手下的泳队来。一次次训练、一次次打比赛拿到结果，妹妹也对此越来越自信，去年暑假还嚷嚷着要我跟她一起去水上乐园，要是我快淹死了她会来救我。</p><p>如果只是跟着母亲的思路去走呢？母亲最初让妹妹游泳，就是因为她的朋友的孩子们在游泳，所以也让妹妹跟着去学。同样的事情发生过太多次了。比如妹妹还会溜冰，因为她的朋友会溜冰，但母亲只看着妹妹的成绩、有没有比别人溜得好，然后整天责怪妹妹不够好，妹妹也就不再去了。再比如钢琴、篮球、羽毛球……</p><p>母亲根本不自知，这样做对孩子会有多大的伤害。让妹妹还在学习的时候就要跟其他已经熟练的同龄人们比，怎么可能比得过？再者，只剩下攀比与竞争的话，兴趣爱好就不再有乐趣在内了。妹妹跟我谈及游泳时，都很少说自己比赛拿了多少名、有多少奖牌，而是给我看各种游泳相关的迷因、梗图、如何更快地在水下翻身等等。我能借此看出她确实享受着游泳。</p><p>要想要在学习上做得好，首先是要慢慢喜欢上它，而喜欢的前提在于反馈。数学题听上去是非常枯燥吧，但我过去在一点点写计算题时，竟能少许地感觉出喜悦，一种脑子正在运转的喜悦。我希望我能让妹妹体会到这种感觉，哪怕是一点点，说不定都能让她对学习有些改观。</p><p>但母亲的做法，无疑是让学习变成零和竞争，且是无尽的、永远都无法赢的竞争⸺每次好不容易「赢」过路人甲，下一个就要「赢」路人乙、路人丙、路人丁…… 一次次数落，一次次叹息，也都是在责怪妹妹「你不够聪明」、定义她。最终介绍妹妹时，他们都要说这是个数学很烂的女孩。</p><p>我讨厌这样。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我和妹妹的年纪相差十岁多。待她十八岁成年的时候，我都三十岁了要。而这般年龄差意味着我们出生的环境截然不同，性格也天差地别。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
  </entry>
  
  <entry>
    <title>八月份的结尾</title>
    <link href="https://blog.cytrogen.icu/posts/887e.html"/>
    <id>https://blog.cytrogen.icu/posts/887e.html</id>
    <published>2026-09-15T05:35:00.000Z</published>
    <updated>2026-09-15T05:36:56.783Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>原本室友计划选一天我们俩大吃大喝的，但我们近期食欲都不咋好，想不出来吃啥好：是尝鲜呢？还是吃点吃过的东西呢？</p><span id="more"></span><p>最后我们决定时不时出去一小会儿，就不用选一整天做计划了。俩聪明鬼儿。</p><p>因为每次和室友出门后再回家，她都不让我玩电子设备，所以写日常生活记录得过段时间我有空才能写……</p><h2 id="唱-k-真好玩"><a class="markdownIt-Anchor" href="#唱-k-真好玩"></a> 唱 K 真好玩</h2><p>八月底我们就去了韩国城的 KTV <em>DUET</em> 玩。虽然是韩国城里的 KTV，但是员工内部交流说的是日语。</p><p>一进包间，很有之前看日本动漫里看到的 KTV 的味道。</p><p><img src="/posts/887e/ktv-1.webp" alt="" loading="lazy"></p><p>门旁边有电话，可以打给前台，前台也会打给我们。</p><p>电视不知道为啥在放凉宫春日耶。室友之后确实也唱了她的 <em> God Bless</em>。太厉害了，我就算会日语我也唱不动这首歌。</p><p>吃的都很贵，当然一个都没有点。嚯嚯。</p><p>其实进包间之前员工们要确保你没有带自己的饮料，所以还要搜包包。搜到我的时候，我的包里赫然出现…… 一罐八宝粥。我们三人都愣住了…… 那是我先前打扫卫生，从家里找到的过期八宝粥，打算放身上备用、哪天不小心快饿死了可以吃…… 员工不知道有没有认出来它，但总之允许我带八宝粥进包间去…… 好尴尬……</p><p>咳咳。点歌用的是个 iPad，里面的软件有中日韩三种语言的歌曲外，还有英语的。</p><p>很多八零后金曲都能搜到，真是有心了⸺我知道是因为我只会唱它们。</p><p><img src="/posts/887e/ktv-2.webp" alt="" loading="lazy"></p><blockquote><p>遠くで暮らしてるあなたの事を<br>ふと思い出す　元気ですか？</p></blockquote><p>无奖竞猜这是哪首歌呢？提示是中国有翻唱版本。</p><p>时间结束之前，二人一起合唱了 <em> September</em> 还有 <em> Just the Two of Us</em> 玩：</p><blockquote><p>I see the crystal raindrops fall<br>And the beauty of it all<br>Is when the sun comes shining through<br>To make those rainbows in my mind<br>When I think of you sometime<br>And I wanna spend some time with you</p></blockquote><p>不得不说原唱们的音色实在是太动听、太厉害了。</p><p>两个人唱了一个小时花了 14 美元税前。</p><p>这个 KTV 的隔音蛮一般的。到前台的时候就已经能听到其他包间里的声音。我们出包间后还听到隔壁房间在大喊中文歌，笑死。</p><p>然后我就想到，难道我们的声音也被传出来啦？室友在这一个小时里还唱了 <em> unravel</em> 这样中间要吼的歌。</p><p>唱完 K 去附近的日本超市里看了下，发现这种奇怪的东西：</p><p><img src="/posts/887e/doritos.webp" alt="" loading="lazy"></p><p>香菜口味的 Doritos……？</p><p>这家日本超市提供熟食；晚上八点后熟食全部打七折。饭团自己已经有三个 10 块钱的折扣，竟然还能再叠加优惠，最终我们花了 7 块钱买了三个饭团。</p><p>韩国城大晚上的依然都站满了人。不过这里的路窄窄的，行人都非常爱抽香烟⸺美国这儿会抽香烟的人并不多。朋友们告诉我说除了东亚来的人外，其他人都去抽电子烟或者吸大麻去了。</p><p>我本来是打算去附近的街机厅里玩 maimai DX，结果过去发现机器出问题、用不了了…… 二人只能悲伤回家。</p><p>回家路上拿饭团出来吃，一吃就清楚为什么它这么便宜了：馊了！味道好恶心！呕呕呕！</p><p>回家后我发现室友在看网页解密游戏的实况视频。我第一时间想到的是 <em> lomando</em> 哎⸺读者朋友们，好奇心会害死猫，不要搜⸺以及另外一款游戏，在尝试表演出「时间」维度时也使用了网页：玩家可以点到下一个网页（未来），然后回到上一个网页（过去）来选择正确的选项。我觉得这个设计非常惊艳！</p><p>室友就问我要不要也玩个试试看。我们就上网找了个蛮有名的「大学生登山失踪事件」的网页解密游戏玩。我的游玩体验直接看我的 Fediverse 记录吧，我不想要在文章里剧透：</p><p><a href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0YBTDFTYPZHANG9S0WCDRR1">https://gts.cytrogen.icu/@cytrogen/statuses/01M0YBTDFTYPZHANG9S0WCDRR1</a></p><p>我意识到这种游戏非常好做，所以我就在想能不能做款这样的网页解密游戏呢？玩家误打误撞访问了个独立博客，但已经很久很久没有更新了。接着玩家可以在这个博客网站里挖掘和探索、填写 slug 来查看没有看到的网页、通过链接转向其他站主的「网站」，慢慢通过他们的文字拼凑出他们的画像、为什么他们离开了互联网……</p><p>引号用起来是因为这些「网站」都不是真正的网站，只会是挂在我域名下的假网站。</p><h2 id="自制麻酱"><a class="markdownIt-Anchor" href="#自制麻酱"></a> 自制麻酱</h2><p>因为要上学了⸺我求职不能，只能进一步推进学业啦……⸺所以我俩吃饭的事儿得商讨商讨。它最好是这样的：</p><ul><li>吃的时候加热就能吃</li><li>好存储</li><li>好吃</li><li>好吃</li><li>好吃</li><li>营养</li></ul><p>几年前我们刚上大学那会儿，就钻研出来个食谱，即炸酱面。</p><p>提前将猪绞肉还有茄子炒好，放一个大容器里。之后每次要吃的时候就煮上面，再用勺子㧟一勺加热就能吃了。</p><p>蔬菜则考虑要么水煮上海青，要么就干啃沙拉叶子吧。</p><p>这次室友想了些新东西。茄子还是有一点点小贵的，但同样口感的西葫芦就便宜。</p><p>她前段时间还买了 Tahini，说是希腊芝麻酱，要比中国的芝麻酱更浓稠、更不油。拿它和花生酱搅拌在一块，再放点老干妈、耗油啥的，便能做出非常美味的麻酱。</p><p>说到花生酱，今年我才知道所谓的 <em> peanut butter</em> 就是花生酱。我以为它真是花生配黄油呢，所以数年来从来没有碰过它。结果它只是质感像黄油，所以叫 <em> peanut butter</em>。我真的服气了。早说啊，不然我就不买华人超市里又小又贵的花生酱了。</p><p>咳咳，我们也去了 Target 买猪绞肉。他们一磅猪绞肉 3.99 美元，看上去颜色很不错，时不时也在打折。</p><p>一天我清理厨房柜子，翻出来许多母亲以前给我的干货，比如黑木耳还有香菇。</p><p>先前我们在 BiliBili 上翻到过个视频⸺频道主应该是叫什么小胖⸺说微波炉可以加速泡软这俩。黑木耳其实还好，拿温水泡，放一会儿自己就好了。不过香菇有点麻烦。</p><p>我是按照这个网页做的：</p><p><a href="https://kthu1031.pixnet.net/blog/posts/8172734348">https://kthu1031.pixnet.net/blog/posts/8172734348</a></p><p>网页很短很精妙，所以我就不总结了，直接点进去看吧。</p><p>总之微波炉可以做很多事情呢，还可以做蔬菜干。</p><p>油热后，下猪肉翻炒，然后塞西葫芦丁炒，然后塞切好的香菇跟黑木耳，然后下豆豉酱啥的…… 唉我又不是写教程的，这种事情快快带过就好啦。</p><p>一边也要煮上意大利面。我虽然是碳水大王，能够吃下很多很多碳水，但身体健康不允许我再摄入更多的碳水了（不能摄入太多糖分）。所以我的主食得换成更不好消化的粗粮，例如 country 面包，还有意大利面。</p><p>说是这么说，不过最后配上炸酱，还有一勺麻酱…… 我也不知道这健不健康，总之我没有在掉体重耶，真是件好事。</p><p><img src="/posts/887e/noodles.webp" alt="" loading="lazy"></p><h2 id="投影仪"><a class="markdownIt-Anchor" href="#投影仪"></a> 投影仪</h2><p>我上个月在 Target 买了个五美元的便宜小相机。为此我买了张 Micro SD 卡⸺目的其实是烧 bin，因为我想试试能不能改掉小相机的 UI 界面，太丑了⸺不过我借此想到了桌子下方的投影仪。</p><p>这台投影仪是母亲不知道从哪里搞到的，非常不好用。以前它还能通过 HDMI 线投影电脑上的内容，现在完全不行了。</p><p>既然我有 Micro SD 卡，兼送的 SD 卡适配器，那我岂不是可以拷贝视频文件到 Micro SD 卡内，再通过插入 SD 卡适配器来让投影仪读取文件？</p><p><img src="/posts/887e/projector.webp" alt="" loading="lazy"></p><p>事实证明确实可以。</p><p>这个视频是随便找的，之前用骑车用的录像机拍的第一人称游玩 maimai DX。</p><p>因为录制不到游戏内的音频、只能听到按键音，就意外发现我的节奏感真是差到没边儿。玩音游不过是玩成另一种打地鼠。</p><p>晚上我拷贝了电脑上的一些电影文件，投影到墙上看。画质还算可以，但是音质是个问题。我不清楚这个破投影仪能不能连音响。</p><p>投影仪没有图片因为当时没有拍。</p><h2 id="爱尔兰酒吧"><a class="markdownIt-Anchor" href="#爱尔兰酒吧"></a> 爱尔兰酒吧</h2><p>我们家附近有非常多酒吧，而它们往往都是爱尔兰酒吧（Irish Pub）。</p><p>我喝不了酒，所以很少往酒吧走。室友能喝，再加上酒吧是个可以让他人放下戒备的场所，她经常跟人去酒吧交流，并往往能够快速得到他人信任⸺听起来感觉很毛骨悚然啊。</p><p>我们从共享办公室出来后，发现附近就有家。从外往里看感觉氛围非常不错：</p><p><img src="/posts/887e/bar-1.webp" alt="" loading="lazy"></p><p>于是我们就进来啦。里面的音乐有点大声，貌似后面有个点歌机。吧台非常漂亮。</p><p>该酒吧是体育酒吧，墙上的电视都在放体育赛事的直播。</p><p>我对体育赛事完全不感冒…… 室友也是，不过她觉得了解下没什么大不了，更何况体育是个非常容易就能和本地人打好交道的话题。</p><p>它有多么好用呢：</p><p><a href="https://immarcus.com/blog/third-wheel-on-the-plane">https://immarcus.com/blog/third-wheel-on-the-plane</a></p><p>最近似乎是网球的季节？⸺「季节」这个词用在这里感觉怪怪的。</p><p><img src="/posts/887e/bar-2.webp" alt="" loading="lazy"></p><p>酒吧内部的墙都是红砖墙⸺或者装饰成红砖的样子⸺木制的吧台⸺或者装饰成木制的样子⸺都让「单单是待在这儿」都觉得让人赏心悦目。</p><p>不过音乐依然还是太大声了。吵死了。</p><p>室友说我声音有时候很低沉，有时候很高昂。我后来发现这取决于「我能不能听到我自己」。</p><p>当外面都是很大的声音，以至于我有些听不到自己时，我的声音就会拔高、变尖。而安静的场合里，我的声音会很低。</p><p>其实之前唱 K 的时候我才意外发现，草东没有派对的主唱很多歌音调都很高，我反而不太好唱上去，只能手动降调。</p><p>让室友帮我点了个 mocktail，说白了就是「假酒」⸺其实是混合果汁。</p><p><img src="/posts/887e/mocktail.webp" alt="" loading="lazy"></p><p>室友喝生僻，牌子应该是 Bluemoon。她一喝快，情绪也变得高昂，开始拉着我说东说西，然后亲我的脸颊。她说，酒精这东西只要喝快了就是这样，如果她喝慢点，几瓶日本清酒下肚她也不会醉⸺</p><p>⸺吗？我又不是没照顾过你，你猜我信不信。你上次还说自己能干倒一米八的同龄男性呢。</p><h2 id="夜驱"><a class="markdownIt-Anchor" href="#夜驱"></a> 夜驱</h2><p>YOASOBI 有首歌叫作《夜に駆ける》。只取汉字出来便是「夜驱」，而原文意思是「向夜晚奔去」。</p><p>「夜晚」……「奔去」…… 哦！大晚上跑步锻炼也是「夜驱」！</p><p>这是我有时候脑子在想的东西，不要在意。</p><p>上周一我重新开始跑步锻炼。有段时间没有练，身体变得不习惯起来，路上还下了点毛毛雨。</p><p>雨停后我向上看去，感觉很可怕。</p><p><img src="/posts/887e/sky-1.webp" alt="" loading="lazy"></p><p>云朵不像往常那样，乌乌盖住一片，而是一层一层的。我抬头，意识到自己能看到很远…… 很远…… 很远，或许远到我自己都难以想象。然后我控制不住地开始幻想，我从那个很远很远的地方掉下来……</p><p>这是我很小的时候就会有的幻想。我不知道为什么，姑且认为是恐高。</p><p>而这个幻想总会让我想起超人还有一架骷髅。我也不清楚为什么。</p><p><img src="/posts/887e/sky-2.webp" alt="" loading="lazy"></p><p>室友的身体素质跟我没法比。我还在慢悠悠跑，她已经跑完了，转一圈回来找我。据她所说她还会巴西摔跤和拳击…… 如果我们俩非要决一死战，我的唯一获胜机会是把匹克猫丢到她脸上，好让她过敏。</p><p>至于为什么不下毒。家里做饭的人是她。我是白吃。</p><p>曼哈顿河边的林荫小道，非常安静、暗暗的。</p><p><img src="/posts/887e/road.webp" alt="" loading="lazy"></p><h2 id="ai-fuji-market"><a class="markdownIt-Anchor" href="#ai-fuji-market"></a> Ai Fuji Market</h2><p>我和室友这个学期选的课都很晚下课。回家路上我们打算去帝国大厦附近看看，结果就找到这家 Ai Fuji Market，也是一家日本超市。</p><p>我原本以为它跟之前去的 Bread &amp; Butter 一样，也是个 24 / 7 营业的自助兼市场型食堂，结果不是，人家就是家日本超市，然后卖点寿司、便当啥的熟食而已。</p><p><a href="https://blog.cytrogen.icu/posts/c783.html">https://blog.cytrogen.icu/posts/c783.html</a></p><p>他们家晚上八点之后，所有熟食都打半价！</p><p>Ai Fuji Market 的官网：</p><p><a href="https://aifujimart.com/">https://aifujimart.com/</a></p><p>我们一看时间，九点多，正好可以买点半价熟食吃了垫垫肚子。</p><p><img src="/posts/887e/ai-fuji-foods.webp" alt="" loading="lazy"></p><p>室友拿了唯一一盒味噌拉面，10 块钱变成 5 块钱，划算极了。我在鸡胸肉炒面跟泡菜炒面里，选了颜色更丰富的后者，尽管我讨厌吃泡菜…… 原因是前者看上去一点食欲都没有，真的就只是白色的鸡胸肉配炒面。</p><p>我们也拿了些小食，像是鳗鱼饭团、海带丝沙拉。</p><p>店内配有微波炉、热水，还有两个用餐区。完全可以进来只点桶泡面，然后泡水开吃呢。</p><p>这四样东西如果没有记错的话花了 13-14 美元左右。</p><p>拉面是和寿司一起放冰箱的，吃前需要微波一下。它的生态环境就算是原价 10 块钱，都让人觉得很赞：有完整的蛋、几片猪肉、笋、黑木耳、玉米……</p><p>同个区开的一家以 10 美元一碗拉面为招牌的拉面店，碗里面真的就只有拉面、汤，还有一点肉片哎！加蛋要多付一两块，给的还是蛋的一半。</p><p>泡菜炒面…… 因为我不喜欢泡菜，所以对它的评价很差。炒面本身有点太干，建议加一点水然后拿去加热。</p><p>吃完我们还买了杯西瓜小方。两个人分着吃几口就吃完了。甜度就那样吧，不过价格还可以，应该是 2-4 块钱左右，然后打了八五折。</p><p>离开的时候店铺正好关门。我观察到他们还有个 gelato（意式冰淇淋）小车。我近些年老是看到 gelato，但依然没搞明白它和冰淇淋车里卖的冰淇淋有啥区别。</p><p>室友的母亲据说非常喜欢吃冰淇淋、雪糕，还有冰棍。我对这类食物也很挑剔：我只吃奶味的。因为小时候只会吃（伊利牧场）小布丁、大布丁（包装是个奶牛），还有老冰棍⸺老冰棍还分更像是冰块的版本，以及更奶的版本⸺我不清楚它们的区别。是小时候大大跟我讲的。搜了下前者我指的是老冰棍棒冰，后者应该是德华原味酸奶那样的用纸包的，但我不记得名字。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;原本室友计划选一天我们俩大吃大喝的，但我们近期食欲都不咋好，想不出来吃啥好：是尝鲜呢？还是吃点吃过的东西呢？&lt;/p&gt;</summary>
    
    
    
    <category term="日常生活" scheme="https://blog.cytrogen.icu/categories/%E6%97%A5%E5%B8%B8%E7%94%9F%E6%B4%BB/"/>
    
    
  </entry>
  
  <entry>
    <title>Golang 学习笔记・壹：基础知识直到 struct</title>
    <link href="https://blog.cytrogen.icu/posts/4787.html"/>
    <id>https://blog.cytrogen.icu/posts/4787.html</id>
    <published>2026-09-14T00:21:00.000Z</published>
    <updated>2026-09-14T00:25:29.172Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>有段时间没有写编程相关的笔记了。这篇本来是打算作为条目写在月刊的「编程历程」里，但越写越多…… 干脆作为学习笔记发出来好了。其实应该写到学校博客上，但都写到这儿了，还是算了。之后翻译翻译再发到那儿。</p><span id="more"></span><hr><p>我复习 Python 的一大原因是申请的一岗位要求做 Python 的 coding assessment，另是感觉自己确实对 Python 的理解不够透彻。</p><p>这次则是因为有猎头联系我，问我是否有意申请 Golang 开发的岗位，并且可以无视我的工作经验不足一点⸺他们居然都要求五年以上的工作经验！要是没有初级岗位的话，怎么才能攒够这么多工作经验呀！我的一到两年工作经验还是靠创业攒出来的。</p><p>之前我还是读过 Golang 的代码的，易读性让我想起了 Python 还有 JavaScript，所以不难读。不过要理解编程语言，不能只因为易读性所以就轻看它。</p><p>我用的教材依然是 freeCodeCamp 里的：</p><p><a href="https://www.freecodecamp.org/news/learn-golang-handbook/">https://www.freecodecamp.org/news/learn-golang-handbook/</a></p><p>我意识到高中的时候我买了个国内的服务，叫路飞学城的黑金卡，差不多五年内都会陆续放编程语言或者框架的教程视频吧。但我一直都没有去看它。上次看还是学习网页爬虫的时候。唉，消费不代表学习。尤其是我买该服务的那年是 2023 年。年底 ChatGPT 出现，我的编程历程也被暂停了。悲哀。</p><p>如果有人感兴趣，我可以将账号密码分享给你，反正它也没法改密码啦。不过课程质量我只能说和 BiliBili 上面的免费录播课差不多。</p><hr><h2 id="基础知识"><a class="markdownIt-Anchor" href="#基础知识"></a> 基础知识</h2><p>网站上第一个视频，也就是 9 个小时的那个。开头二十分钟都是在解释 Python 那样的解释型语言以及 Go 这样的编译型语言的区别。</p><p>总之先自己抄个 Go 代码好了：</p><pre><code class="language-go">package mainimport "fmt"func main() {    var username string = "wagslane"    var password int = 1234567890    fmt.Println("Authorization: Basic", username + ":" + password)}</code></pre><p>关于静态类型，我最初接触的 Python 还有 JavaScript 都是动态类型，后者还是弱类型、会做自动转换类型这种蛮讨厌的事情。</p><p>最开始我还觉得这是件不错的事情咧，结果后面还是乖乖入 TypeScript。我真的没法理解当时认识的网友们是如何靠 JavaScript 写大项目的。</p><p>上述的代码就运行不了，因为字符串和整数类型不能加在一起。</p><p>其实我才知道 Java 虚拟机是真的虚拟机。我以为是个修辞呢。我对 Java 一窍不通。我只知道我在行的 NestJS 框架是基于 Spring Boot 的架构设计出来的。</p><p>关于内存清理、垃圾收集什么的，因为之前一直都是个臭写 Python 的，根本不需要管它们，所以完全是初次接触。</p><p>Go 和 Java 有点像，会自动收集垃圾。不过它没有 JVM，有的是运行时。</p><p>Dexter Darwich 比对了下 Java、Go，还有 Rust 服务在闲置时会吃掉多少内存，结果 Go 和 Rust 的数字都在 1MB 以下，Java 单个干到了 162MB⸺不过视频里的图表没有说清楚条件、时间等因素。总之要知道的就是 Go 没有 Java 那么吃内存，但不如 Rust。</p><p>频道主也解释说在真实的情况下，Go 服务不可能真的比 Java 服务少吃 100 倍的内存。它绝对是比 Java 服务少吃不错，但没有图表中的那么夸张。</p><p>他没有解释「运行时」是什么，所以我自行搜索了下，因为我平时写的 TypeScript 还是要靠 Node.js 运行时才能变成网络服务的嘛。</p><p>我就引用王译锋的知乎回答好了：</p><p><a href="https://www.zhihu.com/tardis/bd/ans/2133648600">https://www.zhihu.com/tardis/bd/ans/2133648600</a></p><blockquote><p>实际上编程语境中的 runtime 至少有三个含义，而目前的回答都只侧重讲了其中的某一个，所以看起来很令人困惑。这几个含义分别可以这样概括：</p><ol><li>指「程序运行的时候」，即程序生命周期中的一个阶段。例句：「Rust 比 C 更容易将错误发现在编译时而非运行时。」</li><li>指「运行时库」，即 glibc 这类原生语言的标准库。例句：「C 程序的 malloc 函数实现需要由运行时提供。」</li><li>指「运行时系统」，即某门语言的宿主环境。例句：「Node.js 是一个 JavaScript 的运行时。」</li></ol></blockquote><p>那 Go 运行时是什么哩？根据官方 FAQ 的说法：</p><p><a href="https://go.dev/doc/faq#runtime">https://go.dev/doc/faq#runtime</a></p><blockquote><p>Go has an extensive runtime library, often just called the <em>runtime</em>, that is part of every Go program. This library implements garbage collection, concurrency, stack management, and other critical features of the Go language. Although it is more central to the language, Go's runtime is analogous to <code>libc</code>, the C library.</p><p>It is important to understand, however, that Go's runtime does not include a virtual machine, such as is provided by the Java runtime. Go programs are compiled ahead of time to native machine code (or JavaScript or WebAssembly, for some variant implementations). Thus, although the term is often used to describe the virtual environment in which a program runs, in Go the word "runtime" is just the name given to the library providing critical language services.</p><p>Go 拥有一个庞大的运行时库，通常简称为「运行时」，它是每个 Go 程序的一部分。这个库实现了垃圾回收、并发、栈管理以及 Go 语言的其他关键特性。尽管它在语言中的地位更为核心，但 Go 的运行时类似于 C 语言库 <code>libc</code>。</p><p>然而，重要的是要理解，Go 的运行时并不包含像 Java 运行时提供的那种虚拟机。Go 程序是提前编译成原生机器码的（或者在某些变体实现中编译为 JavaScript 或 WebAssembly）。因此，尽管「运行时」一词通常用于描述程序运行的虚拟环境，但在 Go 中，「运行时」只是为提供关键语言服务而命名的库。</p></blockquote><p>所以 Go 运行时更倾向于是第二类的「运行时库」。和 Node.js 运行时更像的其实是 Java 的虚拟机。</p><h2 id="类型"><a class="markdownIt-Anchor" href="#类型"></a> 类型</h2><p>到视频的 27 分钟，终于是开始讲类型了！Go 的基础类型有：</p><ul><li><code>bool</code></li><li><code>string</code></li><li><code>int</code>、<code>int8</code>、<code>int16</code>、<code>int32</code>、<code>int64</code></li><li><code>uint</code>、<code>uint8</code>、<code>uint16</code>、<code>uint32</code>、<code>uint64</code>、<code>uintptr</code></li><li><code>byte</code></li><li><code>rune</code></li><li><code>float32</code>、<code>float64</code></li><li><code>complex64</code>、<code>complex128</code></li></ul><p><code>uint</code> 是 <em> unsigned integer</em> 的意思。之前学习 C 语言还是 C++ 的见过，但不记得是干什么使的了⸺频道主说 <code>uint</code> 只有正数，没有负数。</p><p><code>complex64</code> 还有 <code>complex128</code> 用来代表虚数的。我的数学已经还给高中老师了，所以你要问我虚数是什么，我也不知道！我也不会使用这两个类型的！大概！</p><p>后面带数字的类型，那些数字指的是比特（或者位元，总之是 bit）大小。例如 <code>uint8</code> 类型的数据大小是 8 比特，那么能存储的最大的数字是 255。</p><p><code>byte</code> 类型其实是 <code>uint8</code> 的别名；<code>rune</code> 类型其实是 <code>int32</code> 的别名。</p><p>虽然说是 <em> short variable declaration</em>，但这个 <code>:=</code> 怎么看怎么是 Python 的海象运算符啊！不过我自己搜了下，并不是同个东西，莫名失望了一下。</p><p>Go 的情况是，以下两个语句有着相同的功能：</p><pre><code class="language-go">var empty stringempty := ""</code></pre><p>它能够声明新的变量，并且初始化它。</p><p>Python 的海象运算符的作用是在表达式内部给变量赋值，并且返回该值。更重要的是它是个表达式，所以可以出现在 <code>if</code>、<code>while</code> 条件里。例子：</p><pre><code class="language-python">if (n := len(data)) &gt; 10:    print(n)</code></pre><p>回到 Go 的类型。要打印变量的类型可以这样写：</p><pre><code class="language-go">fmt.Println("The type is %T", x)</code></pre><p>频道主建议说，除非真的需要关心比特大小的话，用 <code>int</code>、<code>uint</code>、<code>float64</code>，还有 <code>complex128</code> 即可。</p><p>其实看到这里，我感觉自己看视频就略显啰唆了些。所以我打算直接看 handbook 的文字内容。等我在某个概念上卡住了，再回去看视频好了。</p><p>Go 的常量：</p><pre><code class="language-go">const myInt = 15</code></pre><p>它们被定义后就不能被改变了。</p><p>我本来想说它让我想到 JavaScript 的 <code>const</code>，结果视频里说没有。唉我又被表象欺骗了。</p><p>Go 的常量必须要在编译的时候就声明其值。也就是说，常量不能在代码运行时才决定自己的值。</p><p>频道主吐槽说 Go 格式化字符串的方式不如 JavaScript 还有 Python 的优雅。</p><p>Go 的做法有二：</p><ol><li><code>fmt.Printf</code>：这不是 C 语言的台词吗⸺吓，还真是。它将格式化的字符串打印到 STDOUT</li><li><code>fmt.Sprintf()</code>：我有点怀疑设计师是不是想要拼个 <em> sprint</em> 出来。总之它返回格式化的字符串</li></ol><p>它们俩都会用到格式化动词：</p><p>不确定用哪个格式的话，可以用 <code>%v</code>：</p><pre><code class="language-go">s := fmt.Sprintf("I am %v years old", 10)// I am 10 years olds := fmt.Sprintf("I am %v years old", "way too many")// I am way too many years old</code></pre><p><code>%s</code> 对字符串。</p><p><code>%d</code> 对整数。</p><p><code>%f</code> 对小数：</p><pre><code class="language-go">fmt.Printf("I am %f years old", 10.512)// I am 10.512000 years oldfmt.Printf("I am %.2f years old", 10.512)// I am 10.51 years old</code></pre><p>我实在是不喜欢这种写法。我更习惯于 Python 的 f 字符串……</p><pre><code class="language-python">shuang = "爽"print(f"这样写超级{shuang}的")</code></pre><h2 id="条件"><a class="markdownIt-Anchor" href="#条件"></a> 条件</h2><p>Go 的条件：</p><pre><code class="language-go">if height &gt; 6 {fmt.Println("You are super tall!")} else if height &gt; 4 {fmt.Println("You are tall enough!")} else {fmt.Println("You are not tall enough!")}</code></pre><p>它实际上是：</p><pre><code class="language-go">if INITIAL_STATEMENT; CONDITION {}</code></pre><p>所以可以这么写：</p><pre><code class="language-go">if length := getLength(email); length &lt; 1 {fmt.Println("Email is invalid")}</code></pre><p>其实就是：</p><pre><code class="language-go">length := getLength(email)if length &lt; 1 {fmt.Println("Email is invalid")}</code></pre><h2 id="函数"><a class="markdownIt-Anchor" href="#函数"></a> 函数</h2><p>Go 的函数写法：</p><pre><code class="language-go">func sub(x int, y int) int {return x - y}</code></pre><p>很用心地，Go 的参数要是类型相同，就能这么写：</p><pre><code class="language-go">func add(x, y int) int {return x + y}</code></pre><p>频道主使用的平台 boot.dev 里提到，C 语言声明变量类型时会将类型放左、变量名放右。</p><p>Go 的开发者认为这很糟糕，因为：</p><pre><code class="language-c">int (*fp)(int (*ff)(int x, int y), int b)</code></pre><p>这段代码声明了个指针 <code>fp</code>，指向一个函数。该函数的返回值是 <code>int</code>，并接收两个参数：第一个参数 <code>ff</code> 本身也是个指向函数的指针（接收两个 <code>int</code> 并返回 <code>int</code>）；第二个参数 <code>b</code> 是 <code>int</code>。</p><p>它是由内向外的，也就是说阅读这段代码，需要从中间的 <code>fp</code> 出发，然后先看右边的括号、解引用。看到 <code>ff</code> 时又要重复一遍由内向外的解读。最后你才会看到最左边的 <code>int</code>，也就是 <code>fp</code> 的返回类型。</p><p>还有个例子是：</p><pre><code class="language-c">int (*(*f)(int))[5]</code></pre><p><code>f</code> 作为一个函数指针，返回「指向含 5 个 <code>int</code> 的数组的指针」。</p><p>我讨厌指针……</p><p>Go 则是名字在前、类型在后⸺想必读者朋友们也看出来了⸺阅读方法永远是从左到右。</p><p>作为比对。首先是 C 的写法：</p><pre><code class="language-c">int xint *pint a[3]int (*fp)(int (*ff)(int, int), int)</code></pre><p>Go 的同样结果写法：</p><pre><code class="language-go">x intp *inta [3]intf func(func(int, int) int, int) int</code></pre><p>我不太懂 C 语言，也不懂 Go，所以我就拿 Python 还有 TypeScript 做例子好了。它们正好也是站 Go 这边的：</p><pre><code class="language-python">x: intp: Callable[[int], int]  # 类似于 Go 的 func(int) int# ffFf = Callable[[int, int], int]# fpfp: Callable[[Ff, int], int]# 如果对应 C 原样嵌套的写法fp2: Callable[[Callable[[int, int], int], int], int]</code></pre><p>怎么感觉 Python 这个写法也是莫名其妙。其实和 Go 的区别不大。</p><pre><code class="language-typescript">let x: number;let f: (a: number, b: number) =&gt; number;// fftype Ff = (x: number, y: number) =&gt; number;// fp：接收 Ff 还有 number 并返回 numberlet fp: (ff: Ff, b: number) =&gt; number;// 如果对应 C 原样嵌套的写法let fp2: (ff: (x: number, y: number) =&gt; number, b: number) =&gt; number;</code></pre><p>TypeScript 的读上去更好读些。因为有 <code>=&gt;</code> 可以表示后面的类型是返回类型，这样就能跟参数类型区别开来。</p><p>总之学回 Go。函数还有参数的用法：</p><pre><code class="language-go">func main(){x := 5increment(x)fmt.Println(x)}func increment(x int){x++}</code></pre><p>猜猜看最终会打印什么咧？</p><p>答案是⸺</p><p>⸺ 还是 5。</p><p>Go 传参传的是复制品。到 <code>increment()</code> 的时候，其实出现了两个 <code>x</code>：一个在 <code>main()</code> 的世界，一个在 <code>increment()</code> 的世界。</p><p>所以 <code>x++</code> 只是让在 <code>increment()</code> 世界的 <code>x</code> 加了一。<code>main()</code> 世界打印自己的 <code>x</code>，打印出来还是 5。</p><p>这个蛮好理解的。不过有趣的是 Python 里，如果传入的是可变对象，例如列表，在函数内进行 <code>append()</code> 操作，外部的列表就会有变化。</p><p>而 Go 是无论传什么都是传复印件。</p><p>这个话题应该是和引用、内存等概念相关的。我不是这块的专家……</p><p>Go 的赋值也是复制值。</p><pre><code class="language-go">x := 5</code></pre><p>找个空的内存地址然后塞入内容 <code>5</code>。</p><pre><code class="language-go">y := x</code></pre><p>这里是将 <code>x</code> 的值复制了一份，放到了 <code>y</code> 的内存地址里。</p><pre><code class="language-go">x = 10</code></pre><p>如果改了 <code>x</code> 的话，就只有 <code>x</code> 的内存地址被改动。</p><p>如果希望函数能够直接改到原件，而不是简单改复印件的话，就要用到指针了。对于 Go，是这么写的：</p><pre><code class="language-go">x := 5p := &amp;x</code></pre><p><code>&amp;</code> 会拿 <code>x</code> 的地址，然后存在 <code>p</code> 里面。然后我们可以用 <code>*p</code> 来顺着地址找到 <code>x</code> 的内存。</p><pre><code class="language-go">func increment(p *int) {*p++}x := 5increment(&amp;x)fmt.Println(x)</code></pre><p>这样就能改变 <code>main()</code> 世界的 <code>x</code> 的值了。</p><p>无视返回值的做法和 Python 的很像：</p><pre><code class="language-go">func getPoint() (x int, y int) {return 3, 4}x, _ := getPoint()</code></pre><p>这很重要，因为 Go 编译器会因为你没有使用定义好的变量而报错⸺非常罕见地！很多编程语言只会将其视为警告。</p><p>Go 可以命名返回值：</p><pre><code class="language-go">func getCoords() (x, y int) {return  // 这个会自动 return x, y}</code></pre><p>不过这样写只适合给短小的方法。代码一旦长起来，这么写读起来就特别难受。你总不想读到最后然后发现代码没有写明会返回啥，然后扑哧扑哧跑回签名去看吧。</p><p>比较有趣的是，写在返回签名里的变量是已经被命名好的。所以：</p><pre><code class="language-go">func calculator(a, b int) (mul, div int, err error) {if b == 0 {return 0, 0, errors.New("Can't divide by zero")}mul = a * b  // 用的是 = 而非 :=div = a / breturn mul, div, nil}</code></pre><p>对比这样写要好很多：</p><pre><code class="language-go">func calculator(a, b int) (int, int, error) {if b == 0 {return 0, 0, errors.New("Can't divide by zero")}mul := a * bdiv := a / breturn mul, div, nil}</code></pre><p>因为前者可以直接从签名得知返回值的内容。</p><p>Go 有个概念叫作 <em>guard clauses</em>，即逻辑应当被写成一维的，而不是层层嵌套的。作为（噩梦般的）反例：</p><pre><code class="language-go">func getInsuranceAmount(status insuranceStatus) int {amount := 0if !status.hasInsurance(){amount = 1} else {if status.isTotaled(){amount = 10000} else {if status.isDented(){amount = 160if status.isBigDent(){amount = 270}} else {amount = 0}}}return amount}</code></pre><p>这是人类写的代码吗。</p><p>等下，我笑不出来了。我校确实用的是类似的 <code>if else</code> 架构来写学生数据的。你知道我当时爬数据包看到六十万字符的内容有多么绝望吗：他们特么地为了让前端显示学生的兼修是什么，居然将所有的兼修都塞到一个 <code>if else</code> 逻辑内，然后让前端一个个查询该兼修的值是真还是假。如果假，就进到下个嵌套继续查。而同样的逻辑，在这一整个学生信息数据包内，出现了至少四次！</p><p>更绝望的是当时我在写浏览器插件，需要解析这个数据包并抽取所有有用的值出来，可以让学生们更快更方便地看到自己的数据、需要修什么课才能毕业…… 就因为这个数据包的设计，我放弃继续开发该插件⸺去你的吧！</p><p>Guard clauses 要求的写法是：</p><pre><code class="language-go">func getInsuranceAmount(status insuranceStatus) int {if !status.hasInsurance() {return 1}if status.isTotaled(){return 10000}if !status.isDented(){return 0}if status.isBigDent(){return 270}return 160}</code></pre><p>这么写无论是哪个编程语言都是个好习惯。</p><p>不过对于这样的例子，就不适合用 guard clauses 了：</p><pre><code class="language-go">func discount(c Customer, amount int) int {if c.IsVIP &amp;&amp; c.HasCoupon {return max(vipRate(amount), couponRate(amount))}if c.IsVIP {return vipRate(amount)}if amount &gt;= 1000 {return 90}return 100}</code></pre><p>规则一和规则二的区别只是「有没有优惠券」而已，但读者要自己意识到第一个 <code>if</code> 拦走了带券的 VIP，所以第二个 <code>if</code> 到这里的必然是无券 VIP。</p><p>同时把它们对调的话，行为就错了，但是代码没有任何提示。</p><p>这时候用 <code>switch</code> 更好些：</p><pre><code class="language-go">func discount(c Customer, amount int) int {switch {case c.IsVIP &amp;&amp; c.HasCoupon:return max(vipRate(amount), couponRate(amount))case c.IsVIP:return vipRate(amount)case amount &gt;= 1000:return 90default:return 100}}</code></pre><p>还有这样的例子，写成 guard clauses 或者嵌套都很奇怪：</p><pre><code class="language-go">func shippingFee(w, v int, remote, urgent bool) int {heavy := w * 2 &gt; v * 3if remote &amp;&amp; urgent &amp;&amp; heavy {return w * 2 + 50 + 80}if remote &amp;&amp; urgent &amp;&amp; !heavy {return v * 3 + 50 + 80}if remote &amp;&amp; !urgent &amp;&amp; heavy {return w * 2 + 50}if remote &amp;&amp; !urgent &amp;&amp; !heavy {return v * 3 + 50}if !remote &amp;&amp; urgent &amp;&amp; heavy {return w * 2 + 80}if !remote &amp;&amp; urgent &amp;&amp; !heavy {return v * 3 + 80}if !remote &amp;&amp; !urgent &amp;&amp; heavy {return w * 2}return v * 3}</code></pre><p>我如果要维护的代码都是这个样子，我会大哭出来的。</p><p>如果改成嵌套写法，我会哭得更大声。</p><p>正解是将两个独立的维度各自拆成函数，然后组合起来：</p><pre><code class="language-go">func baseFee(w, v int) int {if heavyByWeight(w, v) {return w * 2}return v * 3}func surcharge(remote, urgent bool) int {fee := 0if remote {fee += 50}if urgent {fee += 80}return fee}func shippingFee(w, v int, remote, urgent bool) int {return baseFee(w, v) + surcharge(remote, urgent)}</code></pre><h2 id="struct"><a class="markdownIt-Anchor" href="#struct"></a> <code>struct</code></h2><p><code>struct</code> 这个东西其实就是把不同类型的值打包在一起、起个名字，当作新的类型用。</p><p>也就是 TypeScript 里的 <code>interface</code>：</p><pre><code class="language-typescript">interface Car {  make: string;  model: string;  height: number;  width: number;}</code></pre><p>换成 Go：</p><pre><code class="language-go">type car struct {Make stringModel stringHeight intWidth int}</code></pre><p>我搜了下，发现 Python 也有类似的写法，只是我对 Python 的理解还没有到那儿：</p><pre><code class="language-python">from dataclasses import dataclass@dataclassclass Car:    make: str    model: str    height: int    width: int</code></pre><p>Go 是这样用 <code>struct</code> 的：</p><pre><code class="language-go">myCar := car{Make: "Tesla",Model: "Model 3",Height: 144,Width: 185,}fmt.Println(myCar.Make)myCar.Width = 190</code></pre><p>如果 Go 的世界没有 <code>struct</code> 的话，假设我要在函数之间传递「车」的信息：</p><pre><code class="language-go">func register(make string, model string, height int, width int, owner string) {}</code></pre><p>万一我想要给「车」的信息多加个「它有多少个轮子」咋办？我要给每个以「车」的信息作为参数的方法都改一遍么？</p><p>有 <code>struct</code> 的话，直接这样写就好了：</p><pre><code class="language-go">func register(c car) {}</code></pre><p>不过这个概念总感觉很久之前我就听说过，一查，果然是 C 语言的东西：</p><pre><code class="language-c">struct car {  char *make;  int height;};</code></pre><p>C++ 则在 C 语言的基础上，加上了方法、继承、访问控制，直接变成了类：</p><pre><code class="language-c">struct Car {  std::string make;  int speed = 0;  void accelerate(int delta) {    speed += delta;  }};Car myCar;myCar.make = "Tesla";myCar.accelerate(30);std::cout &lt;&lt; myCar.speed;</code></pre><p>说回 Go 吧！</p><p>一个 <code>struct</code> 的字段可以是另一个 <code>struct</code> 类型，也就是套娃、嵌套：</p><pre><code class="language-go">type Wheel struct {Radius intMaterial string}type car struct {Make stringModel stringHeight intWidth intFrontWheel WheelBackWheel Wheel}</code></pre><p>用法也是用点点一层层往下钻：</p><pre><code class="language-go">myCar := car{}myCar.FrontWheel.Radius = 5  // 先取 FrontWheel，再取它的 Radiusfmt.Println(myCa.FrontWheel.Material)  // 尴尬了，还没有赋值呢，所以是返回空的字符串myCar.BackWheel = Wheel{Radius: 5, Material: "rubber"}  // 也可以整块赋值</code></pre><p>JavaScript 里的 <code>config.server.port</code>、Python 的 <code>obj.attr.nested</code> 都是这样的。好学。</p><p>Go 嵌套后，复制是递归的，所以 <code>car</code> 被复制后，里面的两个 <code>Wheel</code> 也会整个跟着被复制：</p><pre><code class="language-go">a := car{FrontWheel: Wheel{Radius: 5}}b := a  // 深拷贝b.FrontWheel.Radius = 99fmt.Println(a.FrontWheel.Radius)  // 5</code></pre><p>这点倒是和 Python 还有 TypeScript 不同。它们对象嵌套时内层是共享引用，所以 <code>b=a</code> 后再改 <code>b.front_wheel.radius</code> 的话会影响到 <code>a</code>。</p><p>但是 Go 的 <code>struct</code> 是值语义，所以就不用学 <code>copy.deepcopy</code> 的坑。想要共享的话就乖乖显式用指针字段，或者传 <code>&amp;myCar</code> 吧。</p><p>频道主还说过，Python 用字段的地方换成 Go 可以无脑用 <code>struct</code> 写。</p><p>Go 有匿名 <code>struct</code>，即在定义类型的同时直接造出一个值，这样类型本身就不用再留个名字了：</p><pre><code class="language-go">myCar := struct {Make stringModel string}{Make: "tesla",Model: "model 3",}</code></pre><p>第一对花括号是类型定义，第二对是值。这种写法是一次性的。</p><p>我们还能这么写：</p><pre><code class="language-go">type car struct {Make stringModel stringHeight intWidth intWheel struct {Radius intMaterial string}}</code></pre><p>不过这意味着 <code>Wheel</code> 这个类型在别处是无法被复用的。</p><p>TypeScript 里这种写法蛮常见的：</p><pre><code class="language-typescript">const myCar: { make: string; model: string } = {  make: "tesla",  model: "model 3"}</code></pre><p>在 Go 实战中，匿名 <code>struct</code> 最常见的家是 handler 里的 JSON：</p><pre><code class="language-go">func getUserHandler(w http.ResponseWriter, r *http.Request) {err := json.NewEncoder(w).Encode(struct {ID int `json:"id"`Name string `json:"name"`}{ID: 42,Name: "Tom",})}</code></pre><p>这样写的好处是，数据的形状和它的唯一用处在同一屏代码里，读者不需要跳转到别处的类型定义。</p><p>它也可以让后来的开发者没法偷懒引用它。如果哪天真的需要第二次使用，那你就显式起名吧，然后认真考虑它该叫什么、放哪个包里面。</p><p>一次性的东西就该长着一次性的样子！</p><p>Go 虽然没有继承，但会用嵌入替代它：</p><pre><code class="language-go">type truck struct {car  // 只写了类型，没有写字段名bedSize int}</code></pre><p>嵌入的规则很简单，那就是只写类型。</p><p>普通嵌套写完后，消费它要用点点一层层钻，如 <code>myCar.FrontWheel.Radius</code> 对吧？</p><p>但是嵌入的字段会被提升到顶层，我们就可以这样写 <code>lanesTruck.make</code>，不需要再写 <code>lanesTruck.car.make</code>。</p><pre><code class="language-go">lanesTruck := truck{bedSize: 10,car: car{make: "toyota",model: "camry",},}fmt.Println(lanesTruck.bedSize)fmt.Println(lanesTruck.make)fmt.Println(lanesTruck.model)</code></pre><p>在效果上，<code>truck</code> 看上去继承了 <code>car</code> 的所有字段，但在内存上它和普通嵌套完全一样，所谓的「提升」仅仅只是访问上的语法糖啦。编译器看到 <code>lanesTruck.make</code>，发现 <code>truck</code> 自己没有，就自动转译成 <code>lanesTruck.car.make</code>。</p><p>因为只是访问上的语法糖，所以在构造时必须老老实实写上 <code>car: car{ ... }</code>。</p><p>不只是字段可以被提升，方法也可以：</p><pre><code class="language-go">type car struct {make stringmodel string}func (c car) describe() string {return c.make + " " + c.model}type truck struct {carbedSize int}lanesTruck := truck{car: car{make: "toyota", model: "camry"}, bedSize: 10}fmt.Println(lanesTruck.describe())</code></pre><p>明明 <code>truck</code> 没有写 <code>describe()</code> 方法，但就是可以直接调用它。</p><p>在 Go 里，给一个类型定义方法，会用 <code>func (接收者) 名字 ()</code> 的形式挂在外面。</p><p><code>(c car)</code> 的部分叫作 <em> receiver</em>，意思是「这个方法属于 <code>car</code> 类型，方法内部用 <code>c</code> 指代调用它的那个 <code>car</code>」。之后任何 <code>car</code> 值都能调用啦。</p><p>我们从头到尾都不用写 <code>func (t truck) describe()</code>，但依然可以正常运行 <code>lanesTruck.describe()</code>。<code>truck</code> 完全不需要付出任何代码，就能获得 <code>describe()</code> 的使用权。</p><p>原理也很简单，就是刚才说的「提升到顶层」：编译器发现 <code>truck</code> 自己没有 <code>describe()</code>，于是去查它嵌入的类型 <code>car</code> 有没有⸺嘿！还真有，那就给你转译成 <code>lanesTruck.car.describe()</code> 好啦。</p><p>Python 的继承可以实现同样的效果。不过 Go 的不是继承。对于 Python，父类代码和子类是互相知晓的。</p><p>但对于 Go，<code>describe()</code> 的接收者 <code>c</code> 永远只是一份 <code>car</code>。它不知道，也无法知道自己是被装在 <code>truck</code> 里的。</p><p>视频的 <code>1:34:40</code> 左右开始讲第六章节 <code>interface</code>。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;有段时间没有写编程相关的笔记了。这篇本来是打算作为条目写在月刊的「编程历程」里，但越写越多…… 干脆作为学习笔记发出来好了。其实应该写到学校博客上，但都写到这儿了，还是算了。之后翻译翻译再发到那儿。&lt;/p&gt;</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Golang" scheme="https://blog.cytrogen.icu/tags/Golang/"/>
    
  </entry>
  
  <entry>
    <title>回一趟父母家：更好的搜索、困难模式、野生动物</title>
    <link href="https://blog.cytrogen.icu/posts/2e54.html"/>
    <id>https://blog.cytrogen.icu/posts/2e54.html</id>
    <published>2026-09-12T16:45:00.000Z</published>
    <updated>2026-09-12T16:50:33.196Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我最近有点疲倦，表现为难以聚集精力去思考、想事情、读书。我想把所有该读的东西都塞给摘要生成器，然后帮我吐出来解决方案、要点…… 这么做不过也只是在伤害自己和他人。</p><span id="more"></span><p>八月份过后，我的牛劲儿莫名其妙不见了。《做导游的那几天》小系列不是特别想继续更新下去，因为它们全部都是图片…… 我本来计划在八月底写完星期四的部分，但那天我一共拍了八十多张照片，涵盖了华盛顿特区的博物馆还有动物园。放照片、随便写写备注还有感想，是件无比简单但特别繁琐的事情。所以我暂且搁置了。</p><p>和父母还有亲戚出门，明明去的都是好玩的地方，但晚上却难以想到写什么好。我只不过是将图片都丢到博客上。它们也多数不好看，只是走马观花。但和室友出门的话，可能只是 <a href="/posts/53f4.html">走路</a>，我都能一写一大堆。</p><p>还是得看跟谁出门。唉。</p><p>总之我不想要写作文、类似于论文的文章了。暂且地。我的大脑和思考能力不够我去写它们。我要回归大脑喷泻模式，想到什么写什么，读者朋友也是读到什么吃什么。嚯嚯嚯……</p><h2 id="给博客做-embedding-然后就能更好搜索了"><a class="markdownIt-Anchor" href="#给博客做-embedding-然后就能更好搜索了"></a> 给博客做 embedding 然后就能更好搜索了</h2><p>我最近安装了 Wiwi 的 <a href="https://code.wiwi.blog/wiwi/blog-embedding">blog-embedding</a> 程序。还蛮有趣的，用模型给每篇文章都生成 embedding，然后输入文字就能快速查找到最相关的文章。</p><p>不过因为我的博客项目非常混乱，所以我对他的源代码稍作修改了下：改成从读 Markdown 文件到读 HTML 文件。</p><p>我的博客项目有多混乱呢？它包含以下三种源件：</p><ol><li>过去 Hexo 项目里丢失了源 Markdown 文件导致我只能下载已经部署了的 HTML 文件</li><li>在使用 Emacs 之前写的 Markdown 文件</li><li>使用 Emacs 之后写的 Org Mode 文件，它会再被转换成 Hexo 框架里的 Markdown 文件</li></ol><p>听着就觉得绕！</p><p>因为文件被放得到处都是，我也很难像 <a href="https://liangmouyin.com/blog/copy-blog-links-with-launchbar/">梁某银</a> 那样做个程序、直接搜索源文字。</p><p>总之我决定让 Wiwi 的代码读渲染好的 HTML 文件。</p><p>然后因为《想法迭代》系列里面有很多很多小节，所以我又让程序去给每个小节做 embedding。</p><p>又因为我的笔记本电脑跑的是超级垃圾的 MTX 230，单靠 CPU 根本跑不动 Wiwi 默认设置的 8B 模型，所以我改用 0.6B 模型。</p><p>结果如下：</p><pre><code class="language-plaintext">➜  blog-embedding  .venv/bin/python3 blog_search.py已載入 1105 篇文章的 embeddings請輸入搜尋文字（連按兩次 Enter 結束）：走路正在產生 embedding（模型：qwen3-embedding:0.6b）...🔍 與輸入文字最相關的 30 篇：    1. 0.4550  █████████████  初次走半马  (/posts/53f4.html)    2. 0.4397  █████████████  我开始有健康的生活习惯了  (/posts/f118.html)    3. 0.4310  ████████████  想法在乙巳开冬迭代 › 日记 › 妹妹的游泳比赛  (/posts/ea48.html#妹妹的游泳比赛)    4. 0.4287  ████████████  乙巳想法复盘 › 40. 能够总结你这一年的一句话是什么？  (/posts/f77.html#40-能够总结你这一年的一句话是什么)    5. 0.4253  ████████████  数多年重试跑步然后晕倒  (/posts/2814.html)    6. 0.4233  ████████████  乙巳想法复盘 › 36. 哪个政治问题最令你有感而发？  (/posts/f77.html#36-哪个政治问题最令你有感而发)    7. 0.4195  ████████████  乙巳想法复盘 › 18. 与去年的这个时候相比，你是：感到更快乐还是更悲伤了？变得更瘦还是更胖了？变得更富还是更穷了？  (/posts/f77.html#18-与去年的这个时候相比你是感到更快乐还是更悲伤了变得更瘦还是更胖了变得更富还是更穷了)    8. 0.4114  ████████████  乙巳想法复盘 › 20. 你希望自己能做得更少的是什么？  (/posts/f77.html#20-你希望自己能做得更少的是什么)    9. 0.4109  ████████████  学术评估测验 - 总结  (/posts/3b.html)   10. 0.4037  ████████████  乙巳想法复盘 › 11. 你今年是否生过病或受过伤？  (/posts/f77.html#11-你今年是否生过病或受过伤)   11. 0.3998  ███████████  乙巳想法复盘 › 7. 今年的哪个或哪些日子会铭刻在你的记忆中，为什么？  (/posts/f77.html#7-今年的哪个或哪些日子会铭刻在你的记忆中为什么)   12. 0.3979  ███████████  想法在乙巳纸月迭代 › 生活与文娱 › 日记片段  (/posts/31df.html#日记片段)   13. 0.3846  ███████████  想法在乙巳开冬迭代 › 日记 › 演讲  (/posts/ea48.html#演讲)   14. 0.3840  ███████████  做导游的这几天：星期三  (/posts/62c8.html)   15. 0.3822  ███████████  想法在乙巳开冬迭代  (/posts/ea48.html)   16. 0.3822  ███████████  乙巳想法复盘 › 29. 有什么是你想要且得到了的？  (/posts/f77.html#29-有什么是你想要且得到了的)   17. 0.3821  ███████████  想法在丙午岁始迭代 › 心理与关系 › 《在咖啡馆独处的不能承受之乐》  (/posts/c089.html#在咖啡馆独处的不能承受之乐)   18. 0.3805  ███████████  想法在丙午蚕月迭代 › 技术与创造 › 《好的软件懂得适可而止》  (/posts/a4c0.html#好的软件懂得适可而止)   19. 0.3803  ███████████  想法在丙午麦序迭代 › 日记片段 › 穿衣搭配  (/posts/5586.html#穿衣搭配)   20. 0.3771  ███████████  离开纽约市的一天  (/posts/18b0.html)   21. 0.3738  ███████████  想法在乙巳纸月迭代 › 商业与社会 › 《孩子们在哪里玩耍？》  (/posts/31df.html#孩子们在哪里玩耍)   22. 0.3735  ███████████  乙巳想法复盘 › 30. 有什么是你想要却没有得到的？  (/posts/f77.html#30-有什么是你想要却没有得到的)   23. 0.3712  ███████████  想法在丙午阳中迭代 › 技术与创造 › 《写给恐慌者的 Git rebase 指南》  (/posts/e3b9.html#写给恐慌者的-git-rebase-指南)   24. 0.3693  ███████████  想法在丙午岁始迭代 › 技术与创造 › 《我在地铁上编程》  (/posts/c089.html#我在地铁上编程)   25. 0.3679  ███████████  休息日逛下城  (/posts/ed86.html)   26. 0.3637  ██████████  乙巳想法复盘 › 15. 你大部分的钱都花到哪里去了？  (/posts/f77.html#15-你大部分的钱都花到哪里去了)   27. 0.3626  ██████████  想法在乙巳开冬迭代 › 日记 › 中秋游行  (/posts/ea48.html#中秋游行)   28. 0.3624  ██████████  想法在丙午芒种迭代  (/posts/893f.html)   29. 0.3620  ██████████  想法在乙巳开冬迭代 › 日记 › 新鼠标  (/posts/ea48.html#新鼠标)   30. 0.3597  ██████████  4 个字符为一组构成的城市  (/posts/cf35.html)────────────────────────────────────────────────────────────</code></pre><p>其实 0.6B 模型的结果也能给出不错的结果，只能说不够精确吧。</p><p>比如搜索「在非平常场合写代码」就不会出现「想法在丙午岁始迭代 › 技术与创造 › 《我在地铁上编程》」这个结果，而是先出现「想法在丙午瓜秋迭代 › 周遭 › 《无干扰即是干扰》」。</p><p>另一个方法就是 Spike 的 <a href="https://taxodium.ink/search.html">搜索</a>，直接在 Kagi 或者 DuckDuckGo 上面搜 <code>site:blog.cytrogen.icu 关键词</code>。不过这样搜「走路」的话搜不到《初次走半马》，因为文章中没有提及到「走路」。</p><h2 id="不带手机出去溜个弯儿呗"><a class="markdownIt-Anchor" href="#不带手机出去溜个弯儿呗"></a> 不带手机出去溜个弯儿呗</h2><p>印象里 Spike 分享过这样的文章，提倡大家不带手机出去散步。Spike 也这么做了。但我完全找不到那篇文章了！就算搜索「不带手机」也找不到。</p><p>唉总之这是个我一直想要尝试的事情。我也和室友提倡过，曼哈顿太无聊了，要不我们把生活变成困难模式好了⸺这个「困难模式」我也记得有个英文博客站主写了篇相关的文章，讲的就是他小时候没有太多娱乐方式，所以和小伙伴们商量给游戏添加更多负担，也就是「困难模式」。</p><p>比方说我最近在 BiliBili 总是看到的《植物大战僵尸》能否用零个植物或者一个植物通关每个关卡？不过这个系列视频讲的都是 TAS 啦，更倾向于游戏漏洞挖掘，而没有观众们想要看到的愁眉苦脸、绞尽脑汁⸺频道主还因此经常被人留言「这样做有意义吗？反正真人打不出来」。</p><p>我和室友提倡的「困难模式」，就是选一天休息日，让自己不能做什么，比如全天不能携带手机。她觉得完全没有关系，因为她是那种手机丢了几个小时都不会发觉，然后凌晨四点才发现手机不见了、拉着我跟着定位去找的家伙儿。</p><p>我倒是会担心这个担心那个，比如说我会担心自己手机没有带在身上的话，母亲可能会打电话过来，然后以为我失踪了，就开始疯狂摇人来找，甚至报警…… 或者说生产环境出了问题，客户疯狂给我轰炸邮件……</p><p>我也担忧自己要是想要拍照片、找定位怎么办。但细想这才是 off-grid 生活⸺「离网」的意思，不过定义里并不单指「离开互联网」，而是离开一个或多个基础设施，例如电网、自来水⸺的意义吧。拍照片不行可以用我在 Target 购买的 <a href="https://gts.cytrogen.icu/@cytrogen/statuses/01M01P9ZPZ271MW6W803NP97E9">五美元超便宜小相机</a>；找地方可以靠骚扰当地居民，或者去景点找张纸质地图，甚至买本纽约市地图书⸺反正办法总比问题多！</p><p>室友非常喜欢户外，因为她出生在大城市，目前人生的五分之一时间也都是在大城市里待着。她喜欢有空没空就去爬山、探索美国的郊区。她说她想要跟我去外州的小木屋住几天玩，每天就找柴火然后烧松果。不过她不会开车，我也没有那么多钱去租车。</p><p>她就发挥想象力，说要不咱们走过去吧，走个三天两夜啥的，晚上要睡觉了就去路边的汽车旅店。</p><p>我寻思我们都要去小木屋了，你还要走过去、一路上住汽车旅店。指不定得烧多少钱呢！另一点是汽车旅店让我觉得陌生，也让我很害怕…… 因为我看过的许多美国恐怖游戏都在汽车旅店里发生，尤其是非常惊悚的兔头杀手！</p><p>好吧我最害怕的是花钱。我没有钱。</p><p>室友说那能不能随地扎营咧？我俩背个大包，天黑了就找个草地露营睡觉。</p><p>我说那得多沉啊！你背我背？你肌肉这么壮硕、力气这么大，肯定是你背吧！我可是 BMI 过轻、扁平足、胆固醇超标的弱女子一位呀~</p><p>室友说那就换成睡袋嘛。随地大小睡。</p><p>我接着说早上起来就喝叶子上的露水、啃叶子，融入大自然变成野人。走到休息站就上厕所、喝厕所的自来水，然后去麦当劳啥的地方给手机充电、联网给别人报平安表明自己还活着。</p><p>说完我自己也绷不住笑，跟着室友哈哈大笑起来。哈哈哈哈！我是喝露水的野人！我要长满大胡子然后在森林里一边叫一边拿着藤蔓荡来荡去呀！</p><p>传下去，Cytrogen 其实是个神经病。</p><p>好啦，生活总是要有点乐趣的。就像现在写博客的我，坐在父母家里，身边有睡着的幸运狗和咪咪猫，但老觉得没劲儿。</p><p>父母家位于纽约市已经被遗忘的区⸺斯塔滕岛（Staten Island）。它的存在感低到没边儿。我估计没来过纽约的读者朋友们都知道曼哈顿（Manhattan）、布鲁克林（Brooklyn）、皇后区（Queens），还有布朗克斯（Bronx），但就是不知道这个斯塔滕岛；明明它们五个是同辈儿的兄弟姐妹。</p><p>这个区和剩余四个兄弟姐妹有多么不同呢？它是唯一一个持有保守立场的区。就凭这一点，它就很不像「纽约市」。</p><p>它的城市化相当于没有。除了最中央的商场外，其他地方都是清一色的森林、小山、城镇。你看不到一栋高楼大厦。</p><p>虽然我很不喜欢父母，但不得不承认父母家非常安静。没有大城市的噪音，晚上真的很安静很安静，除了破知了和蛐蛐的尖叫声，还有野猫发情或者打架的声音。</p><p>所以说，父母家真的超级无聊，就算是最近的图书馆都要走个半小时。</p><p>不过从城市过来住个一天一夜，便会觉得离下网也没什么。</p><p>于是我早上起来不带手机，带着幸运狗出门。</p><p>它非常喜欢出门。就算不是散步，它也会自觉跳到父母的车上，然后找个位置优雅地躺下。也是，家里太无聊了。就算是我这个宅宅也会想要坐上脚踏车然后远走高飞。</p><p>因此，幸运狗刚出门的那小段时间，它会非常兴奋地尝试窜来窜去，并走在我前面。我只能想方设法缩短绳子，把它固定在我身边。</p><p>走个十分钟左右后，它的兴奋劲儿就没了，便也慢慢地跟着我走。狗的舌头真的很有意思，能像块破布一样耷拉在牙上。</p><p>父母家附近有个湖泊，所以靠近那儿就会看到比两个我还要高的芦苇，以及泥巴地。那附近有许多鸭子，总是随地拉屎，然后占着马路不走。小轿车要么等，要么等急了按下喇叭催鸭子快走。那时候鸭子才会一只跟着一只、排队般地过马路。</p><p>有时候还能见到火鸡或者鹿。我印象里刚搬过来的时候，家附近总是有三只火鸡⸺一只公的两只母的⸺来拜访。现在反倒见不着了。鹿的话，它往往站在远处吃草，然后抬头看着我。偶尔它会出现在森林旁的马路，然后因为小轿车而逃跑。</p><p>晚上开车回家，有时能在马路上看到负鼠。成年的母负鼠会驮着一堆小负鼠、躲在车子底下。它们的寿命居然只有两年多。实在是难以想象。</p><p>父母家附近养狗的人家也很多。就算是在自己家，它们也会汪汪叫吵架。我路过一家养吉娃娃的，它们从楼上跑到前院围栏然后冲着幸运狗尖叫。主人是个光头，赶紧跑来跟我说「你快走！」我便带着幸运狗快步离开。幸运狗像是已经习惯了，也不看那批吉娃娃。</p><p>回家后感觉不带手机的最大难受点是我不能立即记录当下的感想。</p><h2 id="野猫泛滥"><a class="markdownIt-Anchor" href="#野猫泛滥"></a> 野猫泛滥</h2><p>野猫泛滥是父母家周边的一大问题。我不知道是谁起头的，开始给家附近的野猫喂饭。后来街坊邻居都一一效仿，给野猫搭建小屋子、放水碗和饭碗。</p><p>现在母亲半夜出去遛狗，都能看到每户人家门口都站着只野猫。「像是人那样，在开会！」她惊道。</p><p>这究竟是个「问题」么？其实我也说不清。我过去认为不该喂养野猫，因为它们会不停繁殖、生出更多小猫。而因为这附近是户外，所以虫子还有疾病会找上它们。</p><p>再是在街上放置食物，会引来除了野猫外的动物，比如更具杀伤力的狂犬病毒传播大头⸺浣熊。父母家曾就 <a href="https://gts.cytrogen.icu/@cytrogen/statuses/01KST1G5TD54N8Y35ZNFVH1WJ9">被浣熊入侵过后院</a>。它们住在隔壁的废墟里，把原本的野猫住民赶了出去，然后把周围人家的植物都咬得一团乱！</p><p>我最担心的还是狂犬病毒。美国管狗管得很严。我来美国后从来没有见过流浪狗。收容所里的狗也都会被打上一针狂犬疫苗。美国传播狂犬病毒的往往不是狗，而是野生的浣熊、狐狸、蝙蝠。</p><p>所以看到浣熊提包入住父母家隔壁，搞得我很慌……</p><p>说回野猫。我总是觉得对野猫最负责任的做法是领养它们。但是想到罗小黑的原型⸺一只因为频繁想要逃出人类的家，最终被绝育然后放归大自然的黑猫⸺我开始思考将猫带回家养是否真的能够解决所有的问题？就像罗小黑的原型，会频繁尝试逃离，那是不是将其放回大自然才是对它最好的？也是对看管它的人类来说最好的？</p><p>我过去也说不能给野猫喂饭，可是母亲听后说：「那我也不能看着它们饿死啊。」</p><p>我们没有经济能力能给每个猫都做绝育手术、对它们负责，因为在美国养宠物真的好贵。做绝育手术要千来美元的诊所是常态，便宜的诊所还要预约抢位置。室友的匹克猫单是洗牙就要两千美元。</p><p>反而喂饭成了最便宜还能保障它们活下去的手段。</p><p>说到这里，我也说不上来怎么办才好。我去过许多动物收容所，有几家大的收容所里，动物多到要用笼子堆在一起。领养的速度远远不如人们捡到动物的速度快，更别提还有卖品种动物的产业会夺走想要养宠物的人。</p><p>我能做的只有未来想要宠物的时候，就去收容所里领养。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我最近有点疲倦，表现为难以聚集精力去思考、想事情、读书。我想把所有该读的东西都塞给摘要生成器，然后帮我吐出来解决方案、要点…… 这么做不过也只是在伤害自己和他人。&lt;/p&gt;</summary>
    
    
    
    <category term="日常生活" scheme="https://blog.cytrogen.icu/categories/%E6%97%A5%E5%B8%B8%E7%94%9F%E6%B4%BB/"/>
    
    
  </entry>
  
  <entry>
    <title>RE：覺得訂閱制軟體很貴，大概是你太窮，不懂商業邏輯</title>
    <link href="https://blog.cytrogen.icu/posts/cb04.html"/>
    <id>https://blog.cytrogen.icu/posts/cb04.html</id>
    <published>2026-09-10T05:02:00.000Z</published>
    <updated>2026-09-10T05:03:23.480Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>讨厌订阅制软件的人一定是很穷的巨婴吧！⸺这是吸引读者注意力用的钩子。</p><span id="more"></span><p>原文链接： <a href="https://ivonblog.com/posts/too-poor-for-business-logic/">https://ivonblog.com/posts/too-poor-for-business-logic/</a></p><h2 id="表象"><a class="markdownIt-Anchor" href="#表象"></a> 表象</h2><p>对文章作回应，实则是在对我认为它所表达的意象作回应。</p><p>该文章呈现了这样的立场：抱怨订阅贵、抱怨 DRM、抱怨隐私收集的人是因为穷、思维跟不上主流，才抱怨的。</p><p>商业逻辑就是利润最大化，而这是不可违逆的。用户要么适应它，要么就提升提升经济地位吧！也就是「找个班上」。</p><p>拦截广告是偷窃。用户不花钱去除广告相当于让创作者没饭吃。</p><p>抗议者全都是提不出替代方案的巨婴。</p><p>不过因为「我」很穷，所以我还是要用广告拦截工具。</p><hr><p>根据我对作者的了解，Ivon 是自由软件的支持且拥护者。怎么会突然写这样的文章呢？我重新阅读了下，理解为是他在反讽。</p><p>总之我都是要对文章中表现出的所有立场做出回应的，何不先从这「表象」开始？它也是我们在日常生活中常常听到的。</p><p>订阅疲劳已经是结构性现象。存款多亦或者是少，都有人在抱怨它。我们订阅了一大堆服务，然后还要订阅 <a href="https://www.rocketmoney.com/">Rocket Money</a> 去帮我们管理订阅⸺是的，如果不订阅 Rocket Money 的话，我都不知道我在订阅某某服务！我的钱已经多到我不愿意查看银行账户了⸺这是反讽。我本人没有钱。</p><p>就算是有广告档的 Netflix，最近也一直在涨价⸺虽然我的 Netflix 广告档是 T-Mobile 包的⸺Amazon Prime Video 也在 2024 年开始突然把广告加到会员档里，然后要求额外订阅「去广告费」。</p><p>更不要提影院这种地方，开播时间到了后还要看半小时广告。好在它们多是其他电影的预告片，还能忍受。不过要是早点入场的话，就要看专门为大荧幕设计的超大广告了。</p><p>所以就算是有在花钱订阅服务的人，也要忍受可恶的广告。</p><p>这一切都源于「企业必然追求利润最大化」这句话。</p><p>是，不错，企业一定会想要最大化自己的利润。但这不是真理。企业 <span class="emphasis">选择</span> 了去搞订阅制、DRM、植入广告、收集用户的数据，而它们都有替代方案。</p><p>消费者能够通过抗议还有商议，来阻止企业剥削他们，并要求企业提供更好的服务。因此才能有「哪家公司更良心」的比较。</p><p>如果「企业追求利润最大化」是真理，那「良心」这种比较根本不可能诞生。可是我们每天都能听到别人说某某公司好良心、某某公司没良心⸺为什么这时候又要强调企业追求利润最大化是真理、是可以谅解的？</p><p>2023 年 Unity 推出要按安装量收费的政策。开发者社区的激烈反抗使得该政策被撤回。提出这种蠢蛋政策的人也被开除，真是活该。</p><p>Ubisoft 下架 <em> The Crew</em> 之后，导致买断游戏的玩家无法游玩。Stop Killing Games 组织收集了 129 万个验证签名，并使得欧盟委员会决定采取行动。</p><p>「财报优先于公道」可见在现实并非真理。退出还有发声是对企业的纪律。用户们只要团结、愿意声讨企业，企业就会因此做出改变。</p><p>已知我们往往要在软件里选择「付费」，或者「看广告」⸺撇开先前提到的付费看广告。对于前者，如果定价超出了相当大一部分人的支付能力，那么他们就要被迫选择后者的注意力税。除了这两个「极端」外，我们的另一个选项就是走非法出口，包括盗版。</p><p>这是消费者在道德上的失败吗？我不这么见得。我看盗版的一大原因是我无法支付很多东西，例如必须要买 BiliBili 大会员才能看的正版汉化动画，而我身在北美地区、无法观看。结果我只能去看盗版的汉化资源。</p><p>如果我购买的 BiliBili 大会员能够让我正常观看动画，我自然会选择花钱省事，毕竟找稳定的盗版资源不是件轻松事儿。</p><p>企业惩罚愿意付钱的人，最终只会把他们推向灰色的地带⸺关于这点，后面会再提一次。</p><p>不谈钱的话，订阅制让人们厌恶的另一个原因便和所有权相关。我们不再能购买一个东西了，反而是仅能租用它们的使用权。</p><p>说来，我其实买过 Microsoft Office 2019 的全套学生软件，也依然可以正常使用。这种买断制对用户是可行的，只可惜订阅的现金流更符合企业的审美。</p><p>最后是「有没有替代方案」。Doctorow 在他的 <a href="https://pluralistic.net/">网站</a> 中经常提到他的方案，也就是强制让软件间有互操作性、修订反 DRM 条款、反垄断、反欺诈性设计模式、使用订阅外的资助模式，比如赞助、买断、合作社等等。</p><p><a href="https://www.stopkillinggames.com/en">Stop Killing Games</a> 也将自己的诉求写成了可执行的立法议程。</p><h2 id="权威"><a class="markdownIt-Anchor" href="#权威"></a> 权威</h2><p>表象中有着隐含的前提，即公司的决策是被给定的、不可谈判的事实，而消费者的行为才是需要被审判的。</p><p>因此，在这类逻辑下，订阅涨价属于企业的合理生存策略、广告与数据收集也是用户已默许的交易条件。</p><p>百年前的劳资谈判里，如果有人说「乘客抱怨票价太高、服务太差，是因为他们太穷、思维落后。抗议者是提不出替代方案的巨婴。而铁路公司的涨价是商业逻辑的必然」，那他会被当成是工贼然后乱棒打死。可为什么现在不再是这样了呢？</p><p>企业成为了立法者，消费者却成了乞讨的。明明消费者的抱怨、流失、使用广告拦截、推动监管都是市场交易中谈判的一部分，而且是最正当的一部分⸺消费者可不会像企业那样，使用欺诈性设计模式啊。凭什么觉得消费者的反抗手段是不合规的巨婴式哭闹？非常欺负人啊。</p><p><u>系统正当化</u> 会让越是处于不利地位的人，越倾向于为支配自己的系统辩护，因为承认系统在欺负自己、在情绪上更难接受。</p><p>1994 年 John T. Jost 还有 Mahzarin Banaji 提出了该理论。当时 Jost 认为，人同时持有三种不同的正当化动机：</p><ol><li>自我正当化</li><li>群体正当化</li><li>系统正当化</li></ol><p>前两个动机还能理解，不过第三个在低位群体身上是冲突的。因为为损害自己以及自己的群体的系统说好话，不就背叛了自我还有群体吗？它应有独立的动机来解释才对。</p><p>理论主张，系统正当化会提供心理上的回报，或者说，麻醉剂：大体公平的世界总要比随机不义的世界好理解；不义的系统意味着我的处境由他人造成，且随时可能更糟，但有义的系统下我的处境就是应得且可预测的；与他人共享现实，维持群体上的认同。</p><p>当人们将订阅制自然化成商业逻辑的必然，那么就会把其他人的不满当成是他们个人经济实力不行，因为这意味着世界有商业逻辑这个铁律（好理解）、买不起是可计算的结果（可预测），以及自己成为了懂商业逻辑的少数清醒的人（群体上的认同）。</p><p>一旦将结构性问题个人化，也就是降低了问题的维度，可选答案就只剩下「付钱」跟「不付钱」了。明明是制度设计的问题，最终争论的却是受害者的钱包里有没有钱。</p><p>换到其他方面的问题，这样的思考方式也很有问题，例如结构性失业其实是你不够努力、结构性成功其实是你的道德成就。最终，成功者都认为自己的一切成功都是自己挣得的；富人认为自己配得上自己的财富；穷人这么穷都是不够努力、活该穷三辈。</p><p>商业成功真的等同于道德上的正确么？实际上一般人都在崇拜的 Musk、Zuckerberg，不过都是不把人当人、能够随意剥削他人的家伙儿罢了。在一个人意外取得成功后，他就会稀里糊涂成为聪明的、生活习惯好的、成功来源于努力的人，甚至出一堆复读成功学鸡汤的自传，引得媒体和信徒狂欢。</p><p>人民的不满应当要归因于结构，然后引起集体行为、改变现有的制度。归因于个人，只会让个人去疯狂改进自我，或者自我安慰，最终没能改变结构，也往往只留下「无可奈何」。</p><p>个人化的政治功能就在于此。只要每个消费者都各自内化了损失，那么损失就永远不会加成总和，也不会影响到企业和政府。</p><p>一旦没有人为结构负责，结构就会被自然化、默认为自然背景，就像是天气。事实真是如此吗？意识形态、政治、商业逻辑，真能和天气、物理定律划为一谈？实则是它们被免于讨论、免去了责任。</p><p>不过个人的选择依然能改变结构。使用广告拦截、购买买断制的产品、参与活动还有签名，可以社会化和结构化无数个个体选择，从而影响我们认为是自然规律的结构。</p><p>为此，我们要多发声。</p><h2 id="讽刺"><a class="markdownIt-Anchor" href="#讽刺"></a> 讽刺</h2><p>实话实说，Ivon 的讽刺做得很差，因为写得非常像是真话，以至于我第一次阅读时误以为这是他的内心真实写照，还在想「这家伙儿怎么变成这样啦！」</p><p>文中写的各种「夸张」的言论，非常荒诞地，实际在互联网上被无数人真心实意地说着。讽刺对象本身已经足够荒谬了，再去看这篇文，反而觉得真实、一点都不夸张。各种层面上都让我深觉惋惜。</p><p>另一点是转折点很弱，扫过去会看不到它…… 结尾也停留在了向企业认输、无奈地自嘲，即承认自己穷，所以要挡广告，相当于承认了表象的观点。</p><p>其实可以直接参考「吃婴儿来解决贫困」的建议啦。</p><p>嗯好吧，话也不能说这么满。万一对方确实没有打算讽刺的话，那我怎么办？</p><h2 id="版权"><a class="markdownIt-Anchor" href="#版权"></a> 版权</h2><p>我近期一直在思考自由与商业的关系，源于我从 Cory Doctorow 的文章中读出的 <a href="/posts/f9e7.html#:~:text=%E8%87%AA%201976%20%E5%B9%B4%E7%9A%84%E7%89%88%E6%9D%83%E6%B3%95%E4%BB%A5%E6%9D%A5%EF%BC%8C%E5%9B%BD%E4%BC%9A%E4%B8%80%E7%9B%B4%E5%9C%A8%E5%8F%8D%E5%A4%8D%E6%89%A9%E5%A4%A7%E7%89%88%E6%9D%83%EF%BC%8C%E4%BD%86%E7%BB%93%E6%9E%9C%E6%98%AF%E8%80%81%E6%9D%BF%E4%BB%AC%E5%8F%98%E5%BE%97%E6%9B%B4%E5%AF%8C%E6%9C%89%E4%BA%86%EF%BC%8C%E8%80%8C%E7%9C%9F%E6%AD%A3%E5%9C%A8%E5%B9%B2%E6%B4%BB%E7%9A%84%E5%88%9B%E6%84%8F%E5%B7%A5%E4%BD%9C%E8%80%85%E6%AF%94%E4%BB%A5%E5%BE%80%E9%83%BD%E8%A6%81%E7%A9%B7%E3%80%82%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BC%9A%E8%BF%99%E6%A0%B7%EF%BC%9F%E7%AD%94%E6%A1%88%E6%98%AF%E7%89%88%E6%9D%83%E6%89%A9%E5%BC%A0%E5%AE%9E%E9%99%85%E4%B8%8A%E5%AF%B9%E5%B7%A5%E4%BA%BA%E6%98%AF%E6%97%A0%E6%95%88%E7%9A%84%EF%BC%8C%E5%8D%B4%E5%AF%B9%E5%AA%92%E4%BD%93%E5%85%AC%E5%8F%B8%E5%BE%88%E6%9C%89%E6%95%88%EF%BC%8C%E5%9B%A0%E4%B8%BA%E4%BB%96%E4%BB%AC%E4%BC%9A%E5%9B%A0%E6%AD%A4%E6%8B%BF%E5%88%B0%E8%AE%B8%E5%8F%AF%E8%B4%B9">该观点</a>：</p><blockquote><p>自 1976 年的版权法以来，国会一直在反复扩大版权，但结果是老板们变得更富有了，而真正在干活的创意工作者比以往都要穷。为什么会这样？答案是版权扩张实际上对工人是无效的，却对媒体公司很有效，因为他们会因此拿到许可费。</p></blockquote><p>我原先对 Doctorow 的观点理解成反对版权、要废除版权的。但我想到假设我们在没有版权的世界，创作者要如何收益？这是否意味着大盗版时代？</p><p>不过之后在阅读他的其他文章⸺要这样翻来翻去才能凑齐他的具体观点是什么样，还是蛮有趣的⸺我发现他关于版权其实是这样想的。</p><p>此处其实有两个不同的问题，后文会分别回答：一是版权的「多少」⸺更多的版权能不能保护创作者、挡住盗版？二是版权的「有无」⸺干脆废除它行不行？</p><p>他写的书 <a href="https://pluralistic.net/2022/08/21/what-is-chokepoint-capitalism/"><em>Chokepoint Capitalism</em></a>（暂且翻译成《瓶颈资本主义》）里提到：</p><blockquote><p>Because copyright <em>can</em> help artists — if there are lots of buyers for your creative labor, you can play them off against each other and get a better deal for yourself (we spend a lot of time talking about how finally applying antitrust to the tech and entertainment giants would help artists).</p><p>But if there's only a handful of colluding buyers for your work — if there's a chokepoint that's patrolled by powerful bullies — copyright won't help you.</p><p>因为版权可以帮助艺术家⸺如果你的创意劳动有很多买家，你就可以让他们互相竞争，从而为自己争取到更好的待遇（我们花了很多时间讨论，如果最终对科技和娱乐巨头实施反垄断法，将如何帮助艺术家）。</p><p>但如果你的作品只有少数几个串通一气的买家⸺如果存在一个由强权恶霸把守的瓶颈⸺版权也帮不了你。</p></blockquote><p>他其实是肯定版权本身的价值的，但问题在于市场结构恶意利用了版权、反而让本该被保护的创作者吃不上饭。</p><p>创作者们一直以为能保护自己的是引入更多的版权，但它们不会随着数量而增强对创作者的保护，而是相反。</p><p>他们向损害自己的结构所要更多保护，怎么可能会得到保护呢？版权越多，个体创作者面对中间人⸺如唱片公司、平台、出版社⸺时的议价力反而越弱。怎么会有这样的道理？因为新的权利在实际操作中只会被买方收走、写进合同，然后拿来对付创作者而已。</p><p>此处假设的是，如果没有版权，盗版就会铺天盖地地袭来。但因果方向其实是反过来的：盗版的能力来源于数字复制的技术，而非没有相关的法律。</p><p>自 1999 年的 Napster 以来，数字复制的边际成本一直都趋近于零。任何 DRM 都会被破解，而这样的盗版时代已经在 <span class="emphasis">有</span> 版权的世界里持续存在了二十多年。</p><p>DRM 的功能其实从来都不是防侵权⸺侵权者又不在乎违法⸺而是防竞争。它让合法购买的东西只能在被批准的设备上用，从而锁定用户。</p><p>因此我们必须要承认一件事：更多的版权无法阻止盗版。</p><p>注意，我说的是「更多版权」，不是版权本身。</p><p>在已知复制无法被技术阻止的前提下，法律和商业还能做什么来保证创作者吃得上饭呢？我们需要明确理解版权的真实功能，也就是界定合法渠道的排他性，从而让合法渠道能定价、创作者能授权收费。</p><p>欧盟委员会 2015 年委托了 Ecorys 做了覆盖三万名受访者的 <a href="https://www.dekuzu.com/en/2017/11/estimating-displacement-rates-of-copyrighted-content-in-the-eu.html">研究</a>，却发现在盗版对销售的替代率上，唯一得到稳健结果的是新上映的大片，替代率有 40%，也就是说每 10 次非法观看会减少 4 次合法的消费。</p><p>至于在音乐、图书、游戏领域上，替代系数则很不确定，甚至有些非法活动能促进合法的消费流。</p><p>所以粉丝个人的复制对大盘的伤害远远小于行业所宣传的。打个比方，盗版玩家可能转化成正版玩家、听盗版音乐的人可能成为歌手的粉丝而在未来为演唱会消费…… 没有版权不意味着一定会立刻摧毁创作收入。</p><p>尽管 Spotify 是个糟糕的流媒体软件，也有着糟糕的订阅制还有 AI 乐队，但它的创始人 Daniel Ek <a href="https://archive.is/kj0t6">曾说过</a>：</p><blockquote><p>"I realised that you can never legislate away from piracy," he says. "Laws can definitely help, but it doesn't take away the problem. The only way to solve the problem was to create a service that was better than piracy and at the same time compensates the music industry – that gave us Spotify."</p><p>「我意识到你永远无法通过立法根除盗版，」他说。 「法律确实有帮助，但并不能消除问题。唯一的解决办法是创建一个比盗版更好的服务，同时补偿音乐产业⸺这就是我们创立 Spotify 的原因。」</p></blockquote><p>不得不承认的是 Spotify 的模式确实带来了全球录音音乐连续十几年的增长。订阅制让人们能够用每个月更少的钱去听到更多的音乐。而该做法的重点并不在于靠 DRM 和诉讼来对抗盗版用户。只有合法渠道变得便利，用户才会持续消费。</p><p>既然更多的版权阻止不了盗版、版权的存在也挡不住粉丝的复制，那我们能不能干脆废除它，让翻印也合法化呢⸺也不行。</p><p>先前说了，它的作用是「界定合法渠道的排他性，从而让合法渠道能定价、创作者能授权收费」。</p><p>「排他性」是什么？为什么界定合法渠道的排他性很重要？</p><p>在经济学里，一件商品能否收费，取决于它是否可排他，即提供者能否阻止不付费的人使用它。</p><p>而公共品的定义建立在非竞争性（我用不妨碍你用）和非排他性（一旦可得，就无法阻止任何人使用，无论他是否付过钱），这两条特征上。</p><p>数字作品天然就是非排他的，因为它的复制成本是零。任何人拿到一份拷贝，就能再造出无数份。而非排他性意味着市场供给会不足，因为如果没有人能阻止白拿，就没有人有理由付费，那么付费市场就会崩溃。</p><p>版权的法律内核正是一系列的排他性，即复制权、发行权、表演权、改编权等等，都是禁止他人做某事的权限。「谁有权做拷贝」会通过版权而被界定成可授权且可交易的法律地位。</p><p>借此，法律创造了信息品的可排他性，让信息品不再是公共品，也让收费成为了可能。</p><p>阻止了信息品变成公共品后，创作者所要担心的另一大问题便是如何阻止其他人合法贩卖自己的作品。这也得用到版权，即禁止除了有独家发行权以外的出版商或者平台销售。</p><p>有组织、有渠道、直接争夺付费客户的翻印商，截走的是正在发生的支付；粉丝复制截走的顶多是可能不会发生的支付。前者才是创作者最该担心的对象。</p><p>在 <a href="https://en.wikipedia.org/wiki/International_Copyright_Act_of_1891">International Copyright Act of 1891</a> 出来之前，美国的翻印市场全都是外国作家的作品。因为美国的版权法只对美国作家的作品有用。翻印「没有」版权的外国作家的作品，不就相当于不用付版权费嘛。因此，翻印商开始大肆无许可翻印，甚至搞起了价格战。</p><p>能压低价格的原因是成本降低。而在这个例子里，成本大头版权费已经消失⸺不，其实没有。外国作家可还在自己的国家里活着呢。他们的作品被美国企业翻印，却没法因此获利。成本问题被丢给了他们。</p><p>排他性的重要性就在此。它被用于阻挡美国翻印商这类有组织、有渠道、直接争夺付费客户的搭便车者。</p><p>但不好好使用它，它也会阻挡愿意付钱的用户。</p><p>比如 BiliBili 从版权方那儿购买了在中国大陆转售作品的权利，却直接阻止不在中国大陆、但希望观看汉化资源的我。</p><p>如果有其他企业也有转售该作品的权利的话，我就能去给他们掏钱⸺可是不行。没有任何一家企业购买了在北美发行汉化版本的权利。</p><h2 id="温和的建议"><a class="markdownIt-Anchor" href="#温和的建议"></a> 温和的建议</h2><p>最后我想要抖个机灵。嚯嚯嚯……</p><p>咳咳，嗯哼！⸺诸君或许以为本王在讽刺。恰恰相反！我正在认真规划着呢！首先每月收入要划出 47% 给订阅服务吧。没有办法呀，我连知道自己花了多少都要额外付费买注意力才行，所以这个数字是保守的，我还聪明地给未来留了增长空间呢！</p><p>其次要划个 12% 给去广告附加费吧。哎呀也没有办法啦，本王讨厌广告，不过现在去广告的费用也在一直涨价啊，谁叫创作者要吃饭呢。平台也是在教育我们财商。倒不如说那边那个正在翻白眼的家伙儿，其实是自己没有努力提升经济地位、看不懂他们的这番苦心吧！</p><p>未来要是订阅再涨价的话，本王会先砍掉音乐订阅，然后砍掉云存储，然后砍掉吃饭。这也是没有办法的。吃不起饭是本王的经济实力问题嘛，与涨价无关。</p><p>所以诸君面前的蛤肉汤其实是十年前的罐头这件事，就不要抱怨、给本王吃下去吧！等下本王同诸君还要用 Amazon Prime Video 看电影呢⸺完蛋！居然有地区限制！</p><p>顺带声明一下啊，本王无意建议什么，「平台自律」、「监管介入」、「互操作性立法」之类的天真方案啊⸺最近好像总听到诸君里的某些人在聊这个。真是不懂感恩！企业追求利润如同天体运行，正如雨落到穷人身上是因为他们站在外面；穷人买不起伞，说明他们本就不该出现在雨里；买不起伞又抱怨下雨的，先提升提升自己的气象学修养。所以本王奉劝诸君不要再搞这些有的没的了。多学学本王！</p><p>最后本王要免除一切怀疑：本王的领地没有订阅没有广告且开源免费，故在以上讨论中毫无私利，纯粹是出于对商业逻辑的敬意。</p><p>说到这里，本王真是感动，竟能见证如此完美的概念存在⸺做什么都是对的企业！可惜还是有点瑕疵，毕竟万一有天，没有人买得起东西了怎么办…… 不过那又和本王有什么关系？想必首富们都能聪明地想出对策吧。本王没有他们聪明，就不想这些了。</p><p>总之就是这样了，诸君同本王一起享用美味的罐头汤吧！⸺嗯？那边的那个，你在干什么……？！把武器放下！⸺呃啊……！！</p><p>⸺2026 年的一场秋天，Cytrogen，<a href="/death/">卒。</a></p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;讨厌订阅制软件的人一定是很穷的巨婴吧！⸺这是吸引读者注意力用的钩子。&lt;/p&gt;</summary>
    
    
    
    <category term="文章回应" scheme="https://blog.cytrogen.icu/categories/%E6%96%87%E7%AB%A0%E5%9B%9E%E5%BA%94/"/>
    
    
  </entry>
  
  <entry>
    <title>自己绘制的图片</title>
    <link href="https://blog.cytrogen.icu/posts/1df2.html"/>
    <id>https://blog.cytrogen.icu/posts/1df2.html</id>
    <published>2026-09-05T22:21:00.000Z</published>
    <updated>2026-09-05T22:26:36.864Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我受够了 AI 生成的图片。</p><span id="more"></span><p>虽然我不是专业的画师，但至少还是有画过画、有足够的鉴别力去观察画作的。</p><p>我对 AI 生成图片的领域了解不深，仅有在高中时用过一次 Stable Diffusion，之后就再也没有碰过图片生成了。</p><p>那时还被称作是「AI 元年」，一个设计电动滑板的熟人想要知道能否将 AI 引入到他的工作流中，我就浅尝了一下。结果设计出来的滑板很糟糕，我还被当时使用的 Kaggle 封禁了账号，理由是他们认为我上传了成人内容。</p><p>电动滑板…… 是…… 成人内容…… 好吧，也许 Kaggle 的审查人员认为电动滑板是色情的。对此虽然我无法理解，但也必须表达出尊重。</p><p>因为 AI 的火热，一时大家的社交媒体头像都变成了仿照吉卜力工作室画风的 AI 生成人头照。它们千篇一律，看得让我想起数年前 QQ 看点里大家把头像都换成猥琐的黄猿脸、名称改成「蒙奇 D 黄猿」。</p><p>后者的重心在于跟随潮流。同样的事情也发生在《原神》这款游戏上架之前、百度贴吧一度引起「大家都是派蒙」热潮。大家争着加入到虚拟的家族中，开着玩笑⸺其实我也加入过，并给自己画了张可爱的派蒙头像⸺可是前者的 AI 火热并非如此，因为人们真的认为那些图片是好看的。</p><p>这样子的画作就足够了吗？为什么要将自己的照片转换成所谓的「吉卜力风格」，然后用它顶替掉真人照片？说到底，就算真的要使用 AI 生成，也写个好点的 prompt、生成张更有个人特色的图片吧！每个风格都是一模一样、同样的劣质，说明人们的平均审美都是能看就行了吗？</p><p>为什么在使用图片时，就完全将决定权交给 AI、就算生成出逻辑漏洞百出的图片也要放到自己的网站上？</p><p>我们其实完全可以自己画啊。不会画画的，画出五十个火柴人，又如何呢？</p><p>至少我画的这五十个火柴人，出现在了我想要它们出现在的位置、有着我想要它们身上有的东西…… 但 AI 生成的图片，你又要消耗多少资源、修改 prompt 的次数，才能完美达到你想要的样子呢？</p><p>我并非要求人人都成为画师。随手生成的吉卜力头像无法向观察的人表达出任何东西，因为它对所有人生成的东西都是一样的。但是人们实际画出来的东西⸺不论学过绘画，还是没有⸺都能够表达出这个人当下的心境、绘画时花费的精力与时间……</p><p>如果只是将决定权交给 AI，等于放弃磨炼出能鉴别美的眼睛的机会。就算是画火柴人，也有许多因为热爱而画出张力的人在。</p><p>画得烂又如何？说到底，什么才是「烂」的画？是糟糕的画工吗？那儿童画与 Picasso 的比例、浮世绘的透视、中世纪绘画的光影…… 它们是糟糕的画吗？如果只有一个答案的话，那么艺术史就只该有一种大师。</p><p>既然「烂」无从定义，那么不如直接承认这个吧：所有艺术都是好的艺术。因为「好」存在于决定去做某件事的瞬间，而非成品内。</p><p>我不想要否认用心调 prompt 的人。可是那与绘画并不相同、属于两种截然不同的活动。本就不必争个高下。</p><p>至于用心调 prompt 算不算艺术，我很难说。生成的图片本身不是画⸺人与它之间，隔着真正在做决定的模型。但隔着机器做选择，有时像是摄影；有时又像是策展，尽管展出的内容依然是借别人的数据而生成出来的。</p><p>但我也不必现在就给出答案。无论它算不算艺术，它都与绘画不同。</p><p>我确定的是，我愤怒于随手生成平庸品还将其当作是自己的表达、敷衍了事。这不是艺术。它没有付出过任何决定。</p><hr><p>以上是我看到 Eddie 的 <a href="https://eddielv.com/musings/puppy-run-outside/">《出遊小狗勾》</a> 时想到的。之前在 <a href="/posts/ee8d.html#all-art-is-good-art">月刊</a> 内也提到过相关的话题。</p><p>Eddie 是为了不冒犯对 AI 图过敏的 ikuka 而亲手画的插图，而 ikuka 在自己的博客文章内也时常插入自己的插图。不过虽然 Eddie 自嘲自己画的图片是「好像没有比较好」的，但它其实很可爱，且是为了 ikuka 而画的，这非常宝贵且难得。</p><p>再看看 <a href="https://hollie.eilloh.net/">Hollie</a>。她会在各种各样的地方掏出钢笔还有水彩写生，画咖啡、狗狗、食物、YouTube 频道主的脸。她只画让自己开心的艺术。每张画都在记录她的日常生活、替她见证自己的生活…… AI 生成的图片无法见证任何东西。它没有生活。</p><p>结尾放个突兀且莫名其妙的骑着猫的鸟。</p><p><img src="/posts/1df2/cat-with-bird.webp" alt="" loading="lazy"></p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我受够了 AI 生成的图片。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
  </entry>
  
  <entry>
    <title>想法在丙午中秋迭代</title>
    <link href="https://blog.cytrogen.icu/posts/ee8d.html"/>
    <id>https://blog.cytrogen.icu/posts/ee8d.html</id>
    <published>2026-09-02T17:16:00.000Z</published>
    <updated>2026-09-02T17:19:52.638Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>虽然夏天期间没有发生什么大事⸺实际上经历了半个月的生病还有两周多的旅游⸺不过还是要和它说拜拜！我最喜欢的秋天到啦！夏天你不要跟我打电话了，我怕秋天误会。</p><span id="more"></span><details>      <summary>本期导读</summary>      <h2 id="输入"><a class="markdownIt-Anchor" href="#输入"></a> 输入</h2><h4 id="世界"><a class="markdownIt-Anchor" href="#世界"></a> 世界</h4><ul><li><a href="#the-millennial-midlife-crisis-is-going-to-be-a-barbell">The Millennial Midlife Crisis is Going to be a Barbell</a></li><li><a href="#apple-s-robo-repo">Apple's robo-repo</a></li><li><a href="#digital-sewer-socialism">Digital sewer socialism</a></li><li><a href="#%E5%A5%BD%E5%BB%A3%E5%91%8A-%E7%88%9B%E5%BB%A3%E5%91%8A">好廣告、爛廣告</a></li></ul><h4 id="远方"><a class="markdownIt-Anchor" href="#远方"></a> 远方</h4><ul><li><a href="#%E4%BA%BA%E7%9A%84%E6%84%8F%E4%B9%89%E6%8E%A2%E5%AF%BB%EF%BC%9A%E7%AC%94%E8%AE%B0">人的意义探寻：笔记</a></li><li><a href="#ai-%E5%B8%A6%E6%9D%A5%E5%86%99%E4%BD%9C%E7%9A%84%E9%BB%84%E9%87%91%E6%97%B6%E4%BB%A3">AI 带来写作的黄金时代</a></li></ul><h4 id="周遭"><a class="markdownIt-Anchor" href="#周遭"></a> 周遭</h4><ul><li><a href="#%E6%88%91%E6%83%B3%E5%95%8F%E5%B9%BE%E5%80%8B%E6%9C%89%E8%B6%A3%E6%88%96%E5%86%B7%E9%96%80%E7%9A%84%E5%95%8F%E9%A1%8C">我想問幾個有趣或冷門的問題</a></li><li><a href="#raising-the-bar">Raising the bar</a></li><li><a href="#a-social-guide-to-being-vegan-in-a-meat-eaters-world">A Social Guide to Being Vegan in a Meat Eaters' World</a></li><li><a href="#all-art-is-good-art">All art is good art</a></li><li><a href="#gemini-is-better-than-search-because-google-enshittified-search">Gemini is better than search because Google enshittified search</a></li><li><a href="#no-hello">no hello</a></li><li><a href="#vibecoding-isn-t-as-fun-as-writing-code-by-hand">Vibecoding isn't as fun as writing code by hand</a></li></ul><h4 id="眼前"><a class="markdownIt-Anchor" href="#眼前"></a> 眼前</h4><ul><li><a href="#%E4%BB%8E%E5%85%8D%E8%B4%B9%E7%9A%84%E5%9C%B0%E9%93%81%E8%AF%B4%E8%B5%B7">从免费的地铁说起</a></li><li><a href="#your-deepest-regrets-help-you-see-yourself-more-clearly">Your deepest regrets help you see yourself more clearly</a></li><li><a href="#how-to-ask-for-help-from-people-who-don-t-know-you">How to ask for help from people who don't know you</a></li><li><a href="#%E7%84%A1%E8%85%A6%E4%BA%AB%E5%8F%97%E9%9F%B3%E6%A8%82">無腦享受音樂</a></li><li><a href="#%E6%9C%89%E9%97%9C%E7%A0%B4%E6%8A%98%E8%99%9F%E8%A9%B2%E7%94%A8%E4%BB%80%E9%BA%BC%E5%AD%97%E5%85%83%E4%BE%86%E8%A1%A8%E7%A4%BA%E7%9A%84%E5%95%8F%E9%A1%8C">有關破折號該用什麼字元來表示的問題</a></li><li><a href="#phoneblogging">Phoneblogging</a></li><li><a href="#%E5%90%83%E9%A3%AF%E8%81%8A%E5%A4%A9">吃飯聊天</a></li><li><a href="#emacs-pinky-is-becoming-a-thing-for-me-recently">Emacs pinky is becoming a thing for me recently</a></li><li><a href="#%E5%BC%80%E5%AD%A6%E5%89%8D-%E6%96%87%E5%85%B7%E5%BA%97%E5%B0%8F%E6%99%AF">开学前，文具店小景</a></li><li><a href="#%E4%B8%80%E6%9C%9F%E4%B8%80%E6%9C%83">一期一會</a></li><li><a href="#%E9%82%A3%E4%BA%9B%E8%82%89%E9%BA%BB%E7%9A%84%E8%A9%B1-%E4%BD%A0%E8%AA%AA%E7%9A%84%E5%87%BA%E5%8F%A3%E5%97%8E">那些肉麻的話，你說的出口嗎？</a></li></ul><h2 id="输出"><a class="markdownIt-Anchor" href="#输出"></a> 输出</h2><ul><li><a href="#%E6%8A%98%E8%85%BE%E5%8D%9A%E5%AE%A2">折腾博客</a></li><li><a href="#%E6%88%91%E5%86%99%E7%9A%84%E6%96%87%E7%AB%A0">我写的文章</a></li><li><a href="#%E7%BC%96%E7%A8%8B%E5%8E%86%E7%A8%8B">编程历程</a></li><li><a href="#%E4%B9%A6%E7%B1%8D">书籍</a> / <a href="#%E5%BD%B1%E8%A7%86">影视</a> / <a href="#%E9%9F%B3%E4%B9%90">音乐</a></li><li><a href="#%E6%97%A5%E8%AE%B0%E7%89%87%E6%AE%B5">真生活</a></li></ul>    </details><h2 id="世界"><a class="markdownIt-Anchor" href="#世界"></a> 世界</h2><p><a id="the-millennial-midlife-crisis-is-going-to-be-a-barbell"></a></p><h4 id=""><a class="markdownIt-Anchor" href="#"></a> <a href="https://pridesai.substack.com/p/the-millennial-midlife-crisis-is"><em>The Millennial Midlife Crisis is Going to be a Barbell</em></a></h4><p><em>Millennial</em>，或 <em> Gen Y</em>，指的是在 1980 到 1990 年代 —— 有些人也会包含 2000 年初出生的人在内 —— 出生的人，也被称为「千禧世代」。</p><p>稍作计算，他们最大已经有 46 岁了，已然踏入了「中年」的门槛。</p><p>那么他们的中年危机是什么？</p><p>Priyanka Desai 表示，选项基本仅有：</p><ul><li>与 20 岁的人外遇</li><li>使用 peptides—— 又称肽类 —— 来护理皮肤</li><li>跑马拉松 —— 我身边真的有好多 millennial 跑马拉松或者走马拉松的</li><li>戒酒</li><li>酗酒 —— 这……</li><li>Hyrox—— 全身标准化室内健身竞赛</li><li>出于恐慌而生孩子</li><li>离婚</li></ul><p>中年危机，准确来说是生活满意度的最低点。该满意度会随着人的年龄增长而呈现一个 U 型。非常神奇，在跨国研究中发现该满意度的最低点都聚集在 47-49 岁之间，甚至类人猿也有这个倾向！</p><p>不同世代的人中年危机的表现也各不相同，打个比方：</p><ul><li>Baby boomers，也就是「婴儿潮」、1946-1964 年之间出生的人，他们的中年危机是购买大量消费品；</li><li>Gen X，1965-1980 年之间出生的人，他们的中年危机是担忧健康状况、害怕没有钱。</li></ul><p>而 millennials、千禧世代作为接受教育程度最高的同时，面临经济门槛也最高的一代，Desai 认为他们的中年危机会有两个极端：</p><p>一、公众面前进行的自动优化。</p><p>过去人们会去夜店内消遣跟社交，现在他们更喜欢在运动时做这些事情。</p><p>文章提到，过去那么多人推崇变瘦，是因为一个人得自律、有基因或者金钱才能变瘦，因此「瘦」是稀缺的，而「稀缺」恰恰意味着地位象征。</p><p>现在我们有了科技 ——peptides 可以让人变瘦，「瘦」便不再稀缺。为了地位象征，人们得去做其他需要投入大量时间和精力的事情上，如锻炼肌肉。</p><p>目前来看在锻炼肌肉中使用科技，还未是大众的事情。一旦大众化，人们就要去找其他方式来获取稀缺性了。</p><p>有趣的是这批女性的绝经期催生了各种商机。我也有干掉经期的冲动，不过我对此一窍不通，有点好奇。</p><p>二、消失。</p><p>另一个极端便是极致的不公开。他们会想尽办法让自己过上离线生活。</p><p>文章聊到了韩国的「多巴胺网站」，也就是假的购物网站，你可以在里面买赛博产品、下赛博单。</p><p>我对此非常好奇，于是上网 —— 顺带一提我用的是 Kagi，你该不会还在用 Google、Bing 吧！—— 搜了下 <em> dopamine sites</em>，这些是我找到的结果：</p><ul><li><a href="https://foodnevercomes.com/">FoodNeverComes</a>：虚假的外卖平台，你可以在上面点赛博饭。不过它更像是一个食谱网站，你还可以在上面学习怎么做 Bánh mì—— 我很喜欢的越南面包 —— 难道它的本职就是食谱网站？</li><li><a href="https://dopamine-shop.com/">Dopamine Shop</a>：UI 一看就是模仿了 Amazon。它是虚假的购物网站；</li><li><a href="https://www.dopeeat.com/">DopeEat</a>：虚假的外卖平台；</li></ul><p>我在浏览期间没有感觉压力被释放，我猜是现在的我仍有自行解压的方法，再浏览它们便会觉得有些莫名其妙。等我过个二十年再回来看看，想法肯定会有所变化吧。</p><p>选择消失的中年人们所消费 —— 当然不是指上面的赛博消费 —— 的东西也有两个极点，分别是精致小众的模拟生活，以及合成亲密关系，如 AI 伴侣。</p><p>我对 Desai 频繁聊到的「沙丁鱼」很感兴趣。美国超市里经常能看到金枪鱼、沙丁鱼罐头，都是很便宜的那种 —— 顺带一提我特别讨厌鱼罐头 —— 但它们和「精致小众」有毛关系？搜索后才得知此鱼罐头非超市里的便宜罐头，而是高级海鲜罐头，会使用特级初榨橄榄油、烟熏、橄榄或者各种香草来腌制鱼。</p><p>它们的包装设计非常漂亮，视觉上很容易被传播。再是它们能让你不用去米其林餐厅也能感觉自己吃得很精致。</p><p>我搜索了一下可能是 millennials 会购买的品牌：</p><ul><li><a href="https://eatfishwife.com/">Fishwife</a></li><li><a href="https://fangst.com/">FANGST</a></li><li><a href="https://www.patagonia.com">patagonia</a></li><li><a href="https://josegourmet.com/en">JOSE Gourmet</a>：每个罐头包装纸盒上都有个插画，很可爱</li><li><a href="https://www.conservasortiz.com/">CONSERVAS ORTIZ</a></li><li><a href="https://www.labelleiloise.fr/en/">la belle-iloise</a></li></ul><p>类似的还有豆子俱乐部，最具代表性的应该是 <a href="https://www.ranchogordo.com/">RANCHO GORDO</a> —— 我不仅讨厌鱼罐头，也很讨厌豆子，所以我对它们一窍不通 —— 它们会专门收集、种植还有销售各种罕见或原生的干豆。</p><p>甚至因为产量少、需求大，这类公司还推出了会员订阅制。又因为名额有限，所以加入俱乐部之前还要在候补名单里排队。</p><p>但是为什么 millennials 会喜爱这些事情呢？Desai 认为他们过去所生活在的消费经济都建立在「如何刺激并满足欲望」上；而 GLP-1 类药物的普及降低了人们对酒精、冲动购物，乃至无意识刷手机的欲望。</p><p>欲望本身变得可选之后，依赖人类即时冲动的消费 —— 如购买零食、快时尚、酒精 —— 就会先被干掉。消费不再由欲望驱动，而会被全新的动机「自律」以及「仪式感」驱动。</p><p>故此我对 GLP-1 也产生了兴趣：它的中文译名是「胰高血糖素样肽 - 1」，原本是人类的肠道细胞会天然分泌的一种激素，作用有仨：</p><ol><li>促进胰岛素分泌以帮助降低血糖</li><li>延缓胃排空以增加饱腹感</li><li>告诉大脑「我吃饱了你不要再吃了」的信号，且还会抑制对高油高糖的渴望</li></ol><p>科学家们人工合成了 GLP-1 受体激动剂，用来模拟天然 GLP-1 的作用，且能在人体内停留更长的时间 —— 天然的 GLP-1 待个几分钟就会被酶干掉 —— 从而实现强效控糖，所以它最初发明出来是来治疗二型糖尿病的，后来才变成了减肥神药。</p><p>亚洲我不清楚，美国因其庞大的肥胖或糖尿病群体，所以我不意外这类药物会普及起来。近些年来我于快餐店也经常看到高蛋白、低容量的食物，意味着一定有群体在消费这类产品。恐怕也与这药有关。</p><p>Desai 的最后一个观点便是 millennials 的知识工作被 AI 威胁，只能转而将掌控感寄托于身体。至于为什么下一代 Gen Z 没有被影响到，因为他们 <a href="/posts/61e0.html">还找不到工作</a>！</p><p>文章的最后便是 Desai 基于上述内容，对未来消费趋势所提出的一系列预测，感兴趣就去读原文吧。</p><p>其中让我觉得最期待的预测是公开社交平台的信息流会全面成为背景噪音，也就是说我们的注意力会主动屏蔽掉它们。同时不透明将成为「高级」的代表词：高级品牌不再会出现在诸如 Instagram、Facebook 上，而是搞私密社区、会员订阅制等等更封闭的手段。</p><p>这是否也能理解成公开广告的没落、人们更倾向于依赖口口相传来宣传产品？</p><p>过去的 <u>CPG</u>（Consumer Packaged Goods，消费包装食品或日用品）—— 如宝洁、俩可乐巨头 —— 还有 <u>DTC</u>（Direct-to-Customer，直面消费者模式）—— 不通过中间商的运营方式 —— 品牌几乎都是在给 Meta 打工，因为收入的一大部分都会变成 Instagram、Facebook 等平台的广告费。</p><p>不过只要消费者离开信息流，和品牌一起走向私域，科技巨头便无法通过监控隐私、卖广告来抽钱了。也就是说恶心人的 dickovers（弹窗广告）、信息流广告都会被减少，产品得靠产品力或者社群归属感来吸引消费者。</p><p>这也意味着会想办法让我们沉迷于刷信息流的因素会减少，让我们的注意力和生活重心重新放在现实生活里，从而达到精神上的清爽。</p><p>但以上仅是理想中的形态，未来究竟如何，谁也说不准。</p><p>文章结尾 Desai 提出了非常让人绝望的假说。</p><p>首先中年危机的重点在于对人生的怀疑和清算。因为 40 多岁的时候，人们已经将社会给的剧本演完了 —— 如读书、找工作、买房、结婚、生子、存养老金 —— 或者发现自己这辈子也就这样了，所以停下来回顾过去。此时内心的怀疑会爆发：「然后呢？这就是生活的全部了吗？」</p><p>因此，没有「怀疑」的人也就没有所谓的「中年危机」。</p><p>Baby boomers，他们会拥有低价买到的房子、稳定的终身养老金、结婚几十年的家庭，因此在 45 岁左右怀疑人生是合理的。</p><p>但是 millennials 的 40 岁，很多人还在租房子、在为房贷拼搏、在应对随时可以失业的职场。那么他们的中年危机将会被推迟到社会剧本演完的时候。</p><p>Desai 的假说是，millennials 的中年危机可能在 60-65 年才会到来。</p><p>如果该假说合理，那么现在的 U 型曲线还并非是 millennials 真正的中年危机表现，更像是身体和精神不得不寻求的安慰剂。Millennials 要一边扛住压力、在 U 型曲线的随意一角治愈自己，一边又要等待二十年后所有事情做完、哲学与精神上的爆发的到来。</p><p>「等待二十年」的另一层意思便是，文章中提到的所有消费趋势、未来的商业预测，都会继续下去，直到 millennials 触及到自己真正的中年危机。</p><p><a id="apple-s-robo-repo"></a></p><h4 id="-2"><a class="markdownIt-Anchor" href="#-2"></a> <a href="https://pluralistic.net/2026/07/25/cruel-cruelty-oh-cruelty/"><em>Apple's robo-repo</em></a></h4><p>iOS 27 中的代码透露出了个新的控制机制：如果用户逾期未还款时，系统可以逐步禁用用户手机上最依赖的应用和服务。而 Apple 将这种远程惩罚机制作为系统底层功能提供给第三方高利贷机构，意味着借款人更难以逃脱。</p><p>如果因为一次不可抗力导致了我购买的 iPhone 无法使用，我会真的很崩溃、莫名其妙⸺不过我用的早不是 iPhone 了⸺当然我现在这个强依赖 Google 服务的手机也不是什么好东西。有钱的话一定要换成可以刷 GrapheneOS 的 Motorola。</p><p>顺便说一嘴我翻译文章标题已经翻译累了。</p><p><a id="digital-sewer-socialism"></a></p><h4 id="-3"><a class="markdownIt-Anchor" href="#-3"></a> <a href="https://pluralistic.net/2026/08/08/find-yourself-a-city/"><em>Digital sewer socialism</em></a></h4><p><u>Sewer socialism</u>，或称「下水道社会主义」，属于改良主义和建设性社会主义。该主义注重于公共服务以及公共领域上的改革。</p><p>19 世纪末，美国快速进到第二次工业革命，密尔沃基等重工业城市开始迅速扩张。野蛮生长意味着工厂的排放不受控制、城市的排水系统缺失、传染病猖獗、公用事业被资本垄断，以及市政腐败透顶。</p><p>当时的一大方向是教条主义马克思主义，即严格遵循 Marx 写的《资本论》中的经济决定论、认为在资本主义框架内做修修补补是麻痹工人阶级的毒药。但密尔沃基社会主义者放弃了等待革命爆发，转而联合工会，通过选举进入体制，并将焦点放在具体的市政治理上，例如修建公营自来水与下水道网络、清理工厂污染等。</p><p>Cory Doctorow 将其与现在的公益技术关联在了一起。</p><p>过去，人们面对的是将电网、水厂私有化并从工人身上榨取高额利润的私营巨头，还有不管不顾污染的工业大亨。</p><p>现在，人们面对的是通过锁定用户、挤压价值、铺天盖地投放广告⸺还有该死的 dickovers⸺和滥用隐私来实现垄断的科技巨头。</p><p>文章中列举了一些公益技术机构，如英国的 <u>政府数字服务局</u>（Government Digital Service，简称 GDS）会重构政府的许多界面，以提升公共服务效率；<u>美国数字服务局</u>（United States Digital Service，简称 USDS）会改善政府软件的使用体验。</p><p>但是后者于 2025 年被臭名昭著的 <u>政府效率部</u>（Department of Government Efficiency，简称 DOGE）取代了。</p><p>该部门一是在合法性上就有大量的争议，二是将政府的数据放在了无比不安全的位置⸺如使用第三方 AI 工具来批量扫描政府的文件、将社保号这种极其隐私的数据存放在不安全的服务器上⸺三是关停 <u>美国国际开发署</u>（United States Agency for International Development，简称 USAID）在内的机构，且大规模削减联邦雇员。</p><p>种种行为都证明，脑子不清楚的人站上高位可以是多么简单、寻常的事情，同时能造成的伤害能有多么恐怖。</p><p>DOGE 在大肆破坏公共服务系统、加剧了公众获取服务的难度后，纽约市长 Zohran Mamdani 推出了 <u>PIT</u>（Public Interest Technology）团队，旨在招募顶尖技术人才以优化城市服务。他们的首个项目竟是⸺落实「一键取消」机制，帮助居民快速退订老流氓的商业订阅！</p><p>Doctorow 认为，这种关注日常具体服务的做法正是过去的下水道社会主义。</p><p><a id="好廣告-爛廣告"></a></p><h4 id="好廣告-爛廣告"><a class="markdownIt-Anchor" href="#好廣告-爛廣告"></a> <a href="https://tianyanfeng.blog/good-ads-bad-ads/">《好廣告、爛廣告》</a></h4><blockquote><p>演算法決定你看到什麼廣告，早就成為主流，而且是壓倒性的主流。</p></blockquote><blockquote><p>也就是說，你在網路上滑到的每一支廣告，幾乎都是系統即時算出來、專門投給你這個人的。</p></blockquote><p>能做到这点，意味着企业已经拿到了足够的用户隐私和数据，才能为他们定制广告。而拿到这么多数据，意味着我们的互联网处处都是监视。</p><p>除了商业用途，邪恶的科技巨头也会拿这个技术用以政治：Open Rights Group 去年四月份写了个 <a href="https://www.openrightsgroup.org/publications/bad-ads-targeted-disinformation-division-and-fraud-on-metas-platforms/">报告</a> ⸺报告是可以下载的 PDF 和 EPUB 文件⸺点明 Trump 竞选团队利用 Meta 平台进行政治操纵。行为包括但不限于：</p><ul><li>向特定选民群体投放负面广告以阻止他们投票。比如少数族裔</li><li>利用用户画像定位弱势群体，然后对他们投放针对性的广告或者新闻</li><li>传播误导性内容影响投票行为，如加剧宗教和族群对立</li><li>宣传极右翼内容</li></ul><p>读者朋友们还记得 Trump 数年前差点被暗杀的事件么？2024 年 10 月份 Syracuse University 的 <a href="https://news.syr.edu/2024/10/16/idjcs-electiongraph-surge-in-negative-ads-after-summer-assassination-attempt/">ElectionGraph 报告</a> 写明在事件发生之后，Facebook 和 Instagram 上美国总统竞选中的负面广告数量大幅激增。</p><blockquote><p>Real, bipartisan concerns about election-related violence—accentuated by assassination attempts against former President Trump—have proved no match for the magnetic pull of negative, uncivil and attack-ad campaigning that Trump himself and his rivals consider too useful to set aside.</p><p>关于选举相关暴力的、真实且跨越党派的忧虑⸺因针对前总统特朗普的暗杀企图而愈发凸显⸺已证明无法抗衡负面的、失礼的以及攻击性广告宣传所具有的磁石般的吸引力，而特朗普本人及其对手均认为，这些手段因过于有效而难以割舍。</p></blockquote><p>新闻刚出来没多久，以暗杀图像作为卖点的商品广告立马变得到处都是。那时候我还在混迹中文主流社交平台⸺难以理解为什么我那时候会觉得远在另一端的中国网民们会更了解美国的政治，不过一般网民的态度也能侧面反映出美国那边是什么情况：大家嗨爆了。大家一边愤怒于民主党破坏经济、大肆宣传 DEI 以鼓励所有人变性，一边崇拜着 Trump 未能死亡、将其宣传成上帝派来的新先知、第二个儿子⸺至于洪秀全就甭提了。</p><p>Meta 的广告库仅会显示广告内容以及投放者，但不会显示广告商选择了哪些定向参数，造成了不透明度。同时，Meta 依赖于用户举报有害广告，而非在发布前审核广告。</p><p>不过要指望 Meta 改邪归正，实在困难。毕竟 Zuckerberg 已经向 Trump 效忠，而 Trump 会保护 Meta 免受监管，以让它继续帮助自己。我更建议离开 Meta 的生态。</p><h2 id="远方"><a class="markdownIt-Anchor" href="#远方"></a> 远方</h2><p><a id="人的意义探寻：笔记"></a></p><h4 id="人的意义探寻笔记"><a class="markdownIt-Anchor" href="#人的意义探寻笔记"></a> <a href="https://www.liu-guo.com/writings/reviews/mans-search-for-meaning/index.html">《人的意义探寻：笔记》</a></h4><p>现在是 2026 年，我在看刘果 2016 年的文章，讲的是 2006 年出的书 <em> Man's Search for Meaning</em>。嗯真有趣。</p><p>因为是他人的笔记，所以我对于自己还感兴趣但他人没有明说的点额外进行了一点搜索。</p><p>该书的作者是奥地利著名的精神病学家、神经学家，同时也是 Auschwitz 集中营的幸存者 Viktor Frankl。他是 <u>意义治疗法</u>（Logotherapy）的创始人。</p><p>如果我没有记错的话，他应该和 Sigmund Freud 还有 Alfred Adler 是心理学的三巨头 —— 过去室友读了 Adler 的许多作品后，有这么和我提起过。</p><p>刘果说，Frankl 认为驱动人类前进的根本力量是「意义意志」，要找出人生意义的话则有三条路可走：</p><ol><li>工作与成就</li><li>体验与爱</li><li>苦难中的选择</li></ol><p>也不存在普世的意义。</p><p>Frankl 提到 20 世纪人们面临的主要精神危机 ——21 世纪的人也有 —— 分别是内心的存在真空，以及过度追求与关注。</p><p>前者来源于人类生物本能的丧失，即我们不再像动物那样，靠本能就知道自己必须要做什么了。我们有无数个选择，而这种开放令人不安、焦虑，转而会依赖于两种机制以补偿：做别人都在做的事情，或者做别人要我做的事情。</p><p>但它们无法解决问题的根源：我们的生活缺乏意义。最终它们会导致各种临床症状，如抑郁、成瘾、攻击性。</p><p>不过内心的空虚感并不会直接引出这些症状，两者之间还隔了一层过度追求与关注。</p><p>空虚与焦虑的人们会急于抓住某些具体的体验。不过体验本就只是做事情时的副产物。将副产物设为目标，人们便会开始不停监视自己是否获得了体验。但是强烈的关注只会带来二次焦虑。</p><p>我在此引入 Mihaly Csikszentmihalyi 的心流理论，来解释幸福与体验只能是副产物。</p><p>心流状态指的是当人极度专注地做一件事时，大脑所处于的高度投入的状态。它的核心前提是「人的工作记忆和注意力资源是有限的」。</p><p>要进入心流状态，就需要任务的难度与个人的技能水平达到平衡，不能太简单也不能太难，得正正好。这也需要人 100% 的注意力资源投入到当前的任务中，也就是「忘我」的状态。</p><p>如果你产生了元认知 —— 关于认知的认知，「元」也就是 <em> meta</em> 一词的解释可以看 <a href="/posts/97a1.html#%E5%B0%8F%E8%AF%B4%E5%89%8D">这里</a> —— 你就不再「忘我」了。你注意到了自己，注意到了自己的感受，并用它与你期待的体验进行比对，那么投射在任务本身上的注意力就不再完整，心流状态也就此瓦解。</p><p>心流理论也将活动分为两种：</p><ul><li>外在目标驱动：为了结果而做</li><li>自洽驱动：过程即目的</li></ul><p>心流往往发生在后者中。你必须先对被体验的对象本身产生极度的投入，高质量的体验 —— 在这个例子里便是心流 —— 才会作为神经生理和心理上的附带结果出现。</p><p>如果倒反天罡将「获得心流体验」当成目标，那么被体验的对象就退化成了获取心理刺激的工具。而一旦你把它当成工具，你就无法对其产生纯粹的倾注，心流也就不会发生。</p><p>因此体验只能是副产物。</p><p>笔记中继续道，设我们以「体验」作为目标，那么我们对结果的恐惧 —— 没能获得体验 —— 会诱发过度追求，过度追求引发了过度监视 ——「我为什么还没有获得体验？」—— 而过度监视导致了我们所害怕的失败。</p><p>笔记里提到了美国社会对人们的要求，该观点我在高中时也有所耳闻。</p><p>人的不快乐来源于许多具体的事情，但社会总在强调我们应有积极的心态、应追求幸福，快乐变成了我们的目标。</p><p>虽然话是这么说的，我过去也明白这个道理，但真去面对一个不快乐的人，我还是会习惯性去劝他们「不要不开心」、「多开心点」。尽管出于好意，但…… 说了跟没有说一样，反而更糟糕了。</p><p>如何关心人我想首先得有强大的同理心和同情心。我可能有，也可能没有这一点，又或者我只是太愚笨了。我想要明白如何才能表达我的关心。</p><p><a id="ai-带来写作的黄金时代"></a></p><h4 id="ai-带来写作的黄金时代"><a class="markdownIt-Anchor" href="#ai-带来写作的黄金时代"></a> <a href="https://www.liu-guo.com/writings/ai-golden-age-of-writing/index.html">《AI 带来写作的黄金时代》</a></h4><blockquote><p>然而知识爆炸了，我的脑子还是只有这么小，况且记忆里还会随年龄变差。获取新知识的瓶颈不在于信息技术，而是我这具肉身。对信息的阅读，本身并不是思考也不是理解，本身远不足以摄取知识。借用叔本华的话说，阅读时是别人在帮我们思考，我们不过是在机械地重复别人（或者 AI）的思维过程。只读不想，读过的东西也就消散在记忆的黑洞中了。</p></blockquote><p>这一段让我想起 Eltrac 写过的一篇让我印象深刻的 <a href="https://www.geedea.pro/essays/abstraction/">文章</a>。当时我还在探索独立博客、没有接触过的观点，所以他那篇文章中的这段内容我印象很深刻：</p><blockquote><p>苏格拉底在书写诞生之时，曾经反对这项「技术」，认为文字、书籍会让人们认为自己不再需要锻炼记忆，智慧变得浮于表面 —— 换句话说，<strong>苏格拉底认为「书让人变笨」。</strong></p></blockquote><p>结合 Eltrac 的这篇 <a href="https://www.geedea.pro/article/vulgar-new-intellects/">文章</a>，书确实可以让人们变笨，尤其是重述了精英生活方式、各种大道理的成功学书籍 —— 你真的觉得 Elon Musk 会成功，是因为他的生活习惯多么多么好吗？</p><p>文章也同理。</p><p>这个月生病的期间，我开始产生抑郁情绪。我对自己很失望，也很沮丧，因为我觉得我很多时候仅是在复述他人的结论，而不是产生新的思考。最多我也是用了甲的想法去质疑或补充乙的想法，那么最终得出的想法应是甲和乙的总和，而非我的。</p><p>这也让我开始怀疑我的目的。我很喜欢分享是不错，我有着非常旺盛的分享欲，但我是否真的喜欢思考？我有批判性思想吗？还是我在追求成为一个拥有批判性思想的人，因为我觉得那样很好？</p><p>我学习得不够，我很清楚，我所在想的事情不是简单的阅读他人的文章或者书籍就能想明白的。</p><p>我的文字依然是受冲动驱使的，而不是深思熟虑后才发表的。这意味着我也追求在表面上成为更好的博客站主 —— 但「更好」的标准是什么？我也不知道。我对数字变得在意了起来，例如更新的频率、字数，但它们没有太大的用处。</p><p>魏文超于他的一篇 <a href="https://www.weiwenchao.com/2771.html">文章</a> 中提到，他在博客上更新得少了，不过他私下写的东西多了。我鲜少于笔记本上记录我的想法，更多还是在 Fediverse 上写。我猜测我依然在乎着「被看到」，即我追求着外界对我的关注，而不是将重点放在自身上。</p><p>刘果也在文章中说：</p><blockquote><p>我没想到过的是，缺乏目标读者，并没有减弱写作的动机。反而，它似乎使得动机更加纯粹了。它也没有降低对写作清晰、明了的要求，因为我本来就是为了自己更好地思考。为自己而写，将我放到了一个稍微脱离了眼下时空的地方，以更永恒的态度，面对自己。</p></blockquote><p>不过我有这些想法，我很清楚多少还是情绪导致的。不过它让我察觉到了新的视角，我也想到了许多自己经历过的事情。</p><p>比如我先前经常和室友聊写作，并推荐对方也这么做。我能乐此不疲地这么干，很多时候是因为我觉得室友拒绝我，是因为她总觉得我的想法是低于她的 —— 这一点也确实存在，因为她承认过自己作为一线城市、大老板的女儿，自然思想和境界是高于我这个「乡下人」的，尽管我出生在的是三线城市而非乡下，以及我不认可思想贵重以及地域决定思想这两个观点 —— 直到这个月她和我说自己不喜欢博客，是因为不喜欢自己的想法以文字的形式被公开，以及她更喜欢通过讲座的形式表达自己。</p><p>很显然，我喜欢的东西不能强行套用在别人身上。同样的，她开讲座一事我也难以复刻。不过我们都在表达自己，这就足够了。</p><p>最后是关于 AI。我对这个东西的感想很复杂，目前尚未（该条目是八月九日写的）写过独立的文章去谈谈我对它的看法和感受，最多写过一篇说我有个教授怀疑了我使用 AI 工具。之后或许会写写看，不过所谓的「AI 元年」已经过去了有三年吧，再去写这种东西难免会让读者朋友们感觉「哇又来，有完没完」。</p><h2 id="周遭"><a class="markdownIt-Anchor" href="#周遭"></a> 周遭</h2><p><a id="我想問幾個有趣或冷門的問題"></a></p><h4 id="我想問幾個有趣或冷門的問題"><a class="markdownIt-Anchor" href="#我想問幾個有趣或冷門的問題"></a> <a href="https://erne.bearblog.dev/260726/">《我想問幾個有趣或冷門的問題》</a></h4><p>我在意的是文章很结尾的那一段。因为 ERNE 担心别人看了心情会变不好，所以刻意将其和正文隔开。</p><p>我实际上也有过类似的想法。过去我在 Fediverse 上批评了 <em> How To Ask Questions The Smart Way</em> 的衍生物，即对提问者不分青红皂白进行攻击。</p><p><em>How To Ask Questions The Smart Way</em> 是早期开源社区还有黑客文化的产物。当时人们在沟通上有很大的问题，无法很有效率地获取或提供帮助。所以就有了该指南，要求提问者证明自己尊重回答者的时间，以换取高质量的解答。</p><p>但现在它也能被当作是合法的借口，来正当化小群体为了寻找智力优越感而攻击提问者的行为。指南的初衷在于「提高交流效率」，但一味攻击还未融入技术圈的新人、宁可说些莫名其妙的黑话也不愿意指条明路，显然只是在阻碍交流⸺这自然是立了个莫须有的靶子自行在打，但我完全不意外会有这样的人存在。</p><p>不讲技术这样专业的领域，在泛大众论坛问问题也会出现这种情况。我时常觉得很白瞎的是问问题本身其实属于日常社交，还可以用来破冰，但总有白痴觉得自己最聪明，然后呛道「你不会 Google 或者百度吗？」这种话出来我就知道和他破冰也没有用，因为就算关系变好对我来说也没有利处。</p><p>之前还在网络上冲浪的时候，就看到有人因为这种事情争执：甲问了问题，乙在评论区里攻击说「连 AI 都不会用吗」，丙又说「为什么要用 AI，不能和别人交流吗」，丁又跑来说「可是问问题效率就是很低啊……」⸺OMG 我觉得引起争吵才是效率最低的啊！</p><p>还有就是有人随手评论个问题，回答者回答完后开始数落对方「这种东西都不会查吗！」颇有一股「因为我帮了你所以我可以随意攻击你」的感觉。是，你确实帮了他，但如果对方知道问问题还要被骂一顿的话，就不会再问问题了吧？你作答还如此有怨气，那最开始就不要作答、害得双方都不舒服啊？</p><p><a id="raising-the-bar"></a></p><h4 id="-4"><a class="markdownIt-Anchor" href="#-4"></a> <a href="https://manuelmoreale.com/thoughts/raising-the-bar"><em>Raising the bar</em></a></h4><p>Manuel Moreale 除了创办 <a href="/posts/3456.html#%E4%BA%BA%E4%B8%8E%E5%8D%9A%E5%AE%A2"><em>People and Blog</em> 系列</a>，还维护着一个 <a href="https://blogroll.org/about-this-blogroll">博客聚合网站</a> ⸺它的创办者是 <a href="https://alongtheray.com">Ray</a>，一个全职小露营车居住者⸺初衷是为了让热爱博客的人们更好去找到博客网站。</p><p>不过这个月他清理了一下该聚合网站的提交队列，且删除了近 95% 的内容，理由是：</p><ul><li>有很多博客内容近乎全是 AI 生成的</li><li>有人利用该聚合网站来给自己的营销网站引流</li></ul><p>我不喜欢博客聚合网站。最开始探索独立博客的世界时，我还会使用它们，但现在近乎不会使用了。部分博客聚合网站的社交属性明显大于聚合本身，比如携带排行榜等功能。它们对收录进来的博客的质量也没有门槛和标准，于是时常在「热门」处看到并没有那么优质的文章。</p><p>后来因为我将博客的域名从 <code>cytrogen.icu</code> 改成了 <code>blog.cytrogen.icu</code>，这些博客聚合网站还不让我修改，于是我现在应该在博客聚合网站上都消失了？也是时候该把博客网站最底部的 <em> BLOGS·CN</em> 链接去掉了。</p><p>关于引流，独立博客世界的另一要点便是「友情链接」。我实际上经常考虑去清理它，尽管…… 我的 <a href="/friends/">friends</a> 页面只有三个条目，其中有一个站主在很久之前便将我从他的友情链接处移除了。我不清楚友情链接的规则，但我猜我也该把对方移除？毕竟我根本没有订阅过他的博客网站，他也从未提供过 RSS 订阅选项。我会同意添加友情链接，更多是出于礼貌。</p><p>如果是为了给别人引流，我觉得代表着「我有在订阅该博客」的 <a href="/links/">links</a> 页面更有价值，因为我确实订阅了他们。</p><p><a id="a-social-guide-to-being-vegan-in-a-meat-eaters-world"></a></p><h4 id="-5"><a class="markdownIt-Anchor" href="#-5"></a> <a href="https://calgaryvegansociety.com/2026/08/07/a-social-guide-to-being-vegan-in-a-meat-eaters-world/"><em>A Social Guide to Being Vegan in a Meat Eaters' World</em></a></h4><p>这是 Brennan Kenneth Brown 为 Calgary Vegan Society 写的一篇博客文章。Brown 自己也有 <a href="http://brennan.day/">独立博客</a>。</p><p>我最初点进去挺纳闷儿的：为什么我在 RSS 阅读器内点击了「用浏览器打开」，打开的却是 Calgary Vegan Society 的页面？后来才意识到是 Brown 在自己的独立博客中添加了该外部链接。</p><p>我本人虽不是素食主义者，但在打工期间学到了许多。其中印象最让我深刻、最有包容性的餐厅里，厨师们做菜都会考虑到「尽可能让所有人都能吃」。点单期间，我也必须要问清楚顾客们的忌口以及过敏源。</p><p>有时人们也会直接进来咨询，亦或者打电话进来询问能否做对他们来说不是忌口的版本。我也非常推荐大家在食物端上来之前就问清楚餐厅工作人员。</p><p>明知对方不乐意吃，却非要让对方尝试，是一件非常不礼貌的事情。我每每看到人们直接表明自己不能吃什么、不想吃什么时，都会觉得母亲那帮以给公开羞辱小孩子为乐的人是多么可笑。比如明知我不喜欢海鲜，却长期做会导致我呕吐的海鲜给我吃，甚至在我小时候的一次生日里没有问过我便做了全海鲜宴，只为了自己开心，再以「海鲜很贵」来辱骂我的「不孝」。</p><p>话说 <em> Calgary</em> 是加拿大的一座城市，中文翻译叫「卡尔加里」。所以该网站里有当地素食餐厅的列表。我就有点好奇，纽约市也算个大城市了，除了占据垄断地位的 Facebook 群组、Yelp、Google Maps 等地方，还有没有类似的网站会收集我喜欢去的餐厅？例如北方菜、面食。</p><p>找了下后的结果：</p><ul><li><a href="https://www.usahuarenjie.com/city/New-York/">华人街</a>：看了下纽约的「北方菜」，这收录的也太少了吧……</li><li><a href="https://www.nychinaren.com/food.html">纽约华人资讯网</a>：这个明显就多了。不过你们划分地区，Elmhurst 和 Flushing 都能算「地区」了，Staten Island 这个真正的 borough 就不算了吗！</li></ul><p><a id="all-art-is-good-art"></a></p><h4 id="-6"><a class="markdownIt-Anchor" href="#-6"></a> <a href="https://hollie.eilloh.net/posts/all-art-is-good-art"><em>All art is good art</em></a></h4><p>该博客名为 <em> Small Good Things</em>，即「小而美好的事物」，副标题则是 <em> A journal of art and observations</em>，「一本关于艺术与观察的日志」。</p><p>博主 Hollie 是水彩画爱好者以及手账制作者，而引用的该文章就讲了她的一个理念：所有艺术都是好艺术。</p><p>我虽然有理论上来讲算「手账」的本本，但我没能像我认识的手账制作者那样富有想象力、带着对生活的热情去使用它。我确实记录了我每天在做什么，不过只是记录。我想我得更随性一些，为了记录而记录是不会让我感到快乐的。</p><p>说到我认识的手账制作者，最让我有印象的是室友举办的活动里出现的一位老头子。他的穿着搭配在视觉上非常有冲击力，有着我特别喜欢的橘色。他分享了他的手账，每天他都会用涂色笔画满一面。尽管从更商业和「专业」的角度来看，他的画像是儿童画，但从艺术的角度而言，能看出对方的努力、对生活的热情。以及他会把人都画成北极熊这一点非常可爱！</p><p>我的日常生活如果不出门的话，差不多就是无时无刻和电子设备在打交道。但因为这个月初大病一场，我也不得不放下电子设备、做些其他事情。比如捡起藏了数年也没有开始读的实体书、在本本上画满一整面。</p><p>上个月还是上上个月前，我其实在自己的 GoToSocial 实例上创建了一个名为 <em> Tincture</em> 的用户，专门用于发布我的涂鸦。不过我尚未那么做，因为公开发布意味着我要承受对应的压力和自我监视，这让本就懒得绘画的我来说，更是晴天霹雳。我之后在考虑是否要公开本本上的内容，例如简单的涂鸦，但又怕麻烦⸺总之先试试看吧。</p><p>最后我想要说的是，不要吝啬于展示你的画作。你可以是一个从来没有学习过绘画的人⸺老头子就没有学习过绘画⸺但依然可以画出有特色的画作。</p><p>以及我会批评发布 AI 生成图片的人：天啊，你的封面图不需要是 AI 生成的，你的展示图不需要是 AI 生成的，你不要把你的照片发给 AI 工具然后生成什么动漫风格图片，更不要把你小孩子的照片拿去生成！</p><p><a id="gemini-is-better-than-search-because-google-enshittified-search"></a></p><h4 id="-7"><a class="markdownIt-Anchor" href="#-7"></a> <a href="https://pluralistic.net/2026/06/29/arsonist-firefighters/"><em>Gemini is better than search because Google enshittified search</em></a></h4><p>现在 Gemini 确实要比搜索引擎更好了，因为 Google 已经把搜索弄成一坨屎了！</p><p>关于搜索的故事可以看看这篇 <a href="https://www.geedea.pro/article/search-engines/">文章</a> 吧⸺该文章的封面图也是画得可爱。</p><p>在换成 Kagi 之后，我就鲜少使用 Google 的产品了。目前还在用的就是 Gmail，还有 Google Cloud Platform⸺但也不用担心，那些 Gmail 邮箱所注册的服务正在被缓慢迁移到我自托管的邮箱上。要问为什么是「缓慢迁移」，那是因为之前注册了太多的服务…… 如果对方不发邮件给我，我根本就不知道！</p><p>如果是垃圾服务⸺如不注册就无法使用它的功能，但我已经预料到这辈子只会使用一次的服务⸺的话，我想直接使用 Gmail 注册也没有关系。垃圾配垃圾，挺好的。</p><p>不过我身边的人还在使用 Google 搜索引擎。有时借用他们的设备，就会再度被 Google 的不要脸震惊：搜索时会有巨大的 AI 总结框首先出现；标签页里第一个不是 <em> Home</em> 而是 <em> AI</em>；排在搜索结果最前面的竟然是「广告」⸺这里我说的可能有差错，因为我不想要为了查验而打开 Google 的搜索引擎。</p><p>Google 搜索引擎已经占据了 90% 以上的市场份额。说是垄断自然也不为过，真让我好奇为什么今年控诉它垄断的案子没有控诉成功…… 同时 Google 和 Meta 也操纵了广告市场，抽走大部分收入，迫使站长只能通过增加广告位和堆 SEO 垃圾来维生。</p><p>而 Google 的排序算法为了展示更多的广告，倾向于推流低质的垃圾网站。于是乎，全都在使用 Google 的互联网被 Google 亲手变成垃圾场，最后再被它用 Gemini 摘要功能吸干剩余的价值……</p><p>怎么解决这个问题呢？</p><p>使用 Kagi 吧！现在凑齐五个葫芦娃就能以每个月差不多 3 美元的价格获得最舒适的体验！</p><p>或者使用 DuckDuckGo、Brave Search、SearXNG 等搜索引擎，总要比用 Google 好。</p><p><a id="no-hello"></a></p><h4 id="-8"><a class="markdownIt-Anchor" href="#-8"></a> <a href="https://nohello.net/en/"><em>no hello</em></a></h4><p>我在李唯的 <a href="https://blog.wei-lee.me/posts/random-thoughts/2026/08/electronic-communication-etiquette/">《電子溝通的禮儀》</a> 里看到的网站。</p><p>首页上写着：</p><blockquote><p>Imagine calling someone on the phone, going hello! then putting them on hold……🤦‍♀️</p><p>想象一下给别人打电话，说了句「喂！」然后就把人家晾在那儿挂起……🤦‍♀️</p></blockquote><p>我经常会接到别人打来的电话。我作为接电话的人，期待对方先说话，结果就算是过来营销的，他们也会沉默。最终还是我要问一句 <em> Hello?</em>，他们才说自己是谁谁谁、哪家公司的⸺真的是！</p><p>给我发即时短讯的也是。既然加了我好友，就不要以「你好」作为开场白啊！你是谁、找我干嘛，都说清楚嘛！</p><p><a href="https://www.geedea.pro/article/email-me/">邮件就很好</a>，至今没有人给我发邮件只是为了说句 <em> Hello</em>。</p><p><a id="vibecoding-isn-t-as-fun-as-writing-code-by-hand"></a></p><h4 id="-9"><a class="markdownIt-Anchor" href="#-9"></a> <a href="https://www.autodidacts.io/vibecoding-isnt-as-fun-as-writing-code-by-hand/"><em>Vibecoding isn't as fun as writing code by hand</em></a></h4><blockquote><p>Vibecoding is like being an executive of a large company that is barely under your control. You never feel like you <em>really</em> know what』s going on, and there』s always the suspicion of sabotage and loafing. Things appear fully formed, but not quite how you imagined. Sometimes they work, and sometimes they don』t, and there』s nothing you can do about it, other than pouring more money into the black box, and yelling louder. So that』s what you do.</p><p>Vibecoding 就像是担任一家大公司的高管，而这家公司几乎不在你的掌控之中。你从未觉得自己 <span class="emphasis">真正</span> 了解发生了什么，而且总怀疑有人在搞破坏或偷懒。事物虽然以完整的形态呈现，但并不完全是你想象的样子。有时它们能运行，有时则不能，而你对此无能为力，只能向这个黑匣子投入更多的钱，并更大声地咆哮。所以，你就是这么做的。</p></blockquote><p>在只有自己用的小工具上，我也 vibe code 过一些。感想是一样的。</p><h2 id="眼前"><a class="markdownIt-Anchor" href="#眼前"></a> 眼前</h2><p><a id="从免费的地铁说起"></a></p><h4 id="从免费的地铁说起"><a class="markdownIt-Anchor" href="#从免费的地铁说起"></a> <a href="https://yinji.org/starting-with-a-free-metro-ride.html">《从免费的地铁说起》</a></h4><blockquote><p>但那天不知道为什么，看到有人准备花钱坐地铁，明明等几分钟就可以免费，我就主动提醒了一下。其实也不是什么大事，只是一条自己知道的信息。但当你真的帮到了别人，哪怕只是提供一点点便利，心里确实会有一种挺舒服的感觉。</p></blockquote><p>明明是举手之劳，却可以帮助到别人很多。</p><p>我最主动的时候，应该是教路人玩家怎么玩《舞萌 DX》的时候。他们不会玩，连怎么双人进游戏都不会，我就会帮他们点进去。有时候看他们兴趣上来了，还会主动借给他们手套 —— 玩《舞萌 DX》不戴手套容易伤害到手和机器！许多路人都错以为这是「专业」的象征，或者认为这是玩家们「走火入魔」。</p><p>几个月前发生过让我很感动的事情。一天晚上我回家，看到公寓楼下有个老妇人在团团转。她看到我，问我是不是住这栋楼的，我点点头。</p><p>她说送快递的把包裹送错、送到她家来了，她是来还包裹的。可是公寓楼的大门锁着，按门铃也没人应。她就住在隔壁一栋楼，问我能不能把包裹拿走。我想了想便也跟去了。</p><p>其实不建议这么做，尤其是大晚上、我还是一个人。我说不准对方是不是骗子。</p><p>跟到她家楼下，她走进去把两个包裹拿出来。我一看，还真是我那栋楼的地址。我拿走包裹的时候，她连连道谢，我说「不，我应该谢谢你，现在已经没有人这么善良了。」</p><p>快递员送错包裹的情况非常非常多。我有时也会在公寓楼下看到别的地址的包裹，或者自己的包裹不翼而飞。这时候只能自认倒霉，或者跟 Amazon 说包裹没收到、再寄个出来。</p><p>对于老妇人来说，她完全可以像别人那样无视这些包裹，甚至偷走，不过她没有这么做。将包裹物归原主是件非常简单的事情，但不是所有人都会这么做，尽管做了会为其他人带来很多便利。</p><p><a id="your-deepest-regrets-help-you-see-yourself-more-clearly"></a></p><h4 id="-10"><a class="markdownIt-Anchor" href="#-10"></a> <a href="https://psyche.co/ideas/your-deepest-regrets-help-you-see-yourself-more-clearly?ref=linggandianbo.com"><em>Your deepest regrets help you see yourself more clearly</em></a></h4><p>后悔不该是无意义的。相反，它能帮助人们认知自我。</p><p>它会揭示我们的价值观、自我界限，还有对自身潜力的评估 —— 就算是客观上还未实现的，我们也有可能将其接纳为属于自己的一部分。这些我们可能都不知道，而后悔能够告诉我们我们真实的想法。</p><p>而最深刻的后悔关乎着「我们允许自己成为了什么样的人」一事。</p><p>性格是可以改变的。所有标注着「自己就是这样的人」的想法，都是默许、容许、妥协自己成为了这样的人。何时改变？从你开始后悔并反思为什么自己是这样的人的时候。</p><p><a id="how-to-ask-for-help-from-people-who-don-t-know-you"></a></p><h4 id="-11"><a class="markdownIt-Anchor" href="#-11"></a> <a href="https://pradyuprasad.com/writings/how-to-ask-for-help/?ref=linggandianbo.com"><em>How to ask for help from people who don't know you</em></a></h4><p>如何向不认识你的人寻求帮助？</p><p>答案是时时刻刻为对方着想！</p><p>我时不时会看到一些人求助时的态度仿佛他人天经地义就该帮助自己 —— 这样只会让礼貌不敢拒绝的人被强迫帮助你，然后再也不想见到你。</p><p><a id="無腦享受音樂"></a></p><h4 id="無腦享受音樂"><a class="markdownIt-Anchor" href="#無腦享受音樂"></a> <a href="https://eddielv.com/musings/enjoy-music/">《無腦享受音樂》</a></h4><blockquote><p>如果是能力範圍內的，容易覺得無聊；若是能力範圍外的，卻總是不自覺去想：「剛剛用了什麼和弦，Bass Line 做得什麼」等等的。</p></blockquote><p>室友会多种乐器，也很会唱歌。我每次给她分享音乐，她都会浅听一下，然后：</p><ul><li>「为什么他们要在这里使用这个和弦？」</li><li>「哇不协调和弦，用得好烂！」</li><li>「这个风格突变非常奇怪，我觉得这是作者初次尝试该风格……（听同位作者的其他音乐）…… 果然如此，他在尝试『不知道是什么术语』和『也不知道是什么术语』但是尝试得非常糟糕。」</li></ul><p>然后她会问：「你听不出来吗？」</p><p>我听不出来！</p><p><a id="有關破折號該用什麼字元來表示的問題"></a></p><h4 id="有關破折號該用什麼字元來表示的問題"><a class="markdownIt-Anchor" href="#有關破折號該用什麼字元來表示的問題"></a> <a href="https://e89295.com/blog/2026-01-14_1.html">《有關破折號該用什麼字元來表示的問題》</a></h4><p>破折号啊破折号，用起来真滴爽。不过近期我常常会看到和它相关的文章 —— 不是和 AI 生成文章相关 —— 围绕着的都是「破折号怎么打出来」。</p><p>我打中文的破折号一直都是左手小拇指按住 <code>Shift</code> 键，然后右手中指按键盘上 <code>0</code> 和 <code>=</code> 键中间的 <code>-</code> 键。但是它渲染出来的是中间断开的。</p><p>Unicode 6.1 引进了 <code>U+2E3A</code>，W3C 的《中文排版需求》也推荐使用该单字符来表征中文破折号。</p><p>不过它要怎么打出来哦？</p><p>Spike <a href="https://taxodium.ink/56.html#:~:text=%E5%9C%A8%20Emacs%20%F0%A5%9A%83%E8%BC%B8%E5%85%A5%20Two%20Em%20Dash%20%E5%BE%88%E5%AE%B9%E6%98%93%EF%BC%8C%E7%94%A8%20C%2Dx%208%20Enter%20%28insert%2Dchar%29%20%E5%B0%B1%E5%8F%AF%E4%BB%A5%E6%96%B9%E4%BE%BF%E6%8F%92%E5%85%A5%20Unicode%20%E5%AD%97%E7%AC%A6">分享</a> 说在 Emacs 里可以用 <code>insert-char</code> 来插入 Unicode 字符。我来试试看：</p><p>⸺</p><p>哦！出来了。</p><p>不过打起来有点麻烦呢。我输入时输 <code>2E3A</code> 不会出来东西，需要打 <em> TWO-EM</em> 才会看到这个候选。</p><p>考虑到我 <code>Shift</code> 和减号键的组合完全就是为了打破折号而存在的，那我直接在 rime-ice 的配置文件里改下映射吧。</p><p>然后我就能愉快地使用这个破折号了⸺嗯，只需要输入一下。嗯？一个字符要在视觉上占两个字符的宽度吗？算了不管了。</p><p>说到英文的破折号，我的做法就更朴素了：敲击两下减号键。就像这样：</p><blockquote><p>This is how I type em dashes -- oh my god so easy.</p></blockquote><p>直到我看到 JTR 的这篇 <a href="https://taonaw.com/2026/07/25/i-love-me-some-em.html">文章</a> 我才知道英文数字排版中也有不同风格的破折号：</p><p>Em dash，也就是长破折号，宽度和大写字母 M 相同而闻名。它有两种风格：</p><ul><li>标准风格是破折号与两侧单词直接连接，中间不加空格，就像这样 <code>word—word</code></li><li> AP 风格是美联社的规范，要求破折号两侧必须各加一个空格，就像 <code>word — word</code></li></ul><p>Hyphen 也叫作连字符，也就是我们按减号键后得到的字符（U + 002D）。它的作用是连接复合词。至于我的做法，其实是打字机时代的遗留风格。</p><p>En dash 是短破折号。从名字里也能看出宽度等同于大写字母 N，主要用于连接数字表示范围，如 <code>1999–2026</code>。</p><p>关于如何打 em dash 跟 en dash，建议根据自己使用的系统或者软件自行搜索。</p><p>我是可以这么打：</p><ul><li><code>Ctrl</code> + <code>Shift</code> + <code>U</code>，然后输入 <code>2013</code> 后回车，得到 en dash</li><li>同样的键位但最后输入 <code>2014</code> 以得到 em dash</li></ul><p>Emacs 里则是在 <code>insert-char</code> 里输入 <code>2013</code> 或者 <code>2014</code>。不过不知道为什么，我的 Emacs 无法用这些数字找到候选，必须要打名字 <em> EN DASH</em> 或者 <em> EM DASH</em>，明明显示的 hex 也包含了这两串数字在内。</p><p>因为打起来还是有些麻烦，所以我还是会继续使用 <code>--</code> 吧。</p><p>顺便说一下因为我写月刊的方法是想到什么 capture 什么，最终根据条目的话题分类，因此你可能会看到我在这一条之前就已经使用了「⸺」。</p><p><a id="phoneblogging"></a></p><h4 id="-12"><a class="markdownIt-Anchor" href="#-12"></a> <a href="https://brennan.day/phoneblogging/"><em>Phoneblogging</em></a></h4><p>仅用手机的人们要如何参与到博客写作里呢？</p><p>介于我的博客是静态博客，需要构建很多东西，所以我做不到仅靠手机写完文章、在手机上构建且部署。</p><p>不过我尝试过在手机上写过东西：</p><ul><li>先在 Google Keeps 上写，写完后在电脑看同步过来的内容，再复制粘贴进行完善</li><li>后来我觉得 Google Keeps 上写跟用别的带同步功能的备忘录软件差不多，再加上我开始接触 Fediverse 所以我改成在微博客上写大致的想法，再在电脑上完善</li><li>我尝试过用 GitJournal，甚至想要去开发一款自己用以写 Hexo 博客文章的 android 软件，不过这些都不咋搭我的工作流</li><li>我在 Termux 上安装了 Emacs，并 Syncthing 同步了博客文章。虽然写作习惯差不多，不过写起来就是有些怪…… 它也没法构建和部署</li><li>学校的博客平台是 WordPress，我可以通过 web 在上面写文章并发布</li></ul><p>顺带说一下引用的这个博客文章的最底部有个评论系统。它使用了 IndieAuth，也是我第一次知道还能这样「登录」并评论。或许我应该借鉴下……</p><p><a id="吃飯聊天"></a></p><h4 id="吃飯聊天"><a class="markdownIt-Anchor" href="#吃飯聊天"></a> <a href="https://poya.school/blog/present-at-the-table/">《吃飯聊天》</a></h4><p>我和父母一同吃饭的时候，就会出现「大家都在看手机」的情况。他们如何我不清楚，但我自己是不愿意和父母亲聊天的。尤其是母亲，每次吃饭她只要张口，就是在数落父亲，或者数落我，或者数落妹妹。所以不张口更好。</p><p>不过和妹妹，我会刻意让她不要在吃饭时刷短视频，而是和她玩双人小游戏，比如 <em> 2 Player Games</em> 这个手机软件。</p><p>我和室友关系开始变好的时候，她就有明确说过自己对「电子设备」的厌恶：和朋友待在一起，如果对方在用电子设备，她会觉得很不舒服。又因为她是个有事就说的人，许多朋友都被她说过「我发现你一直在用自己的手机呢」。而朋友们会尴尬地解释为什么，然后把手机收起来。所以「用太多手机」人们都知道不是个好习惯，并且被提醒后也会觉得尴尬。</p><p>除了我的一位朋友！我至今还是觉得对方每次和我见面就不间断在使用手机、听四倍速 AI 说小说一事很可怕！就算我暗示过，他也不会觉得有什么，然后继续这么做。给我的感觉是不仅不尊重自己，也不尊重我。</p><p>之前我也会用很多手机。因为关系更好一些，她会直接生气说「你非要一直捧着手机看吗」，或者「我没有你的手机重要吗」，或者直接把我手机拿走丢到包里去。对她来说，时间是很宝贵的资源。如果和朋友待在一起对方却花费大量精力在电子设备上，而不是在自己身上，那她就会觉得时间被浪费。</p><p>也因此我显著地减少了对电子设备的使用⸺虽然没能完全戒掉！不过她对电子设备的不依赖这点让我觉得很值得学习。</p><p><a id="emacs-pinky-is-becoming-a-thing-for-me-recently"></a></p><h4 id="-13"><a class="markdownIt-Anchor" href="#-13"></a> <a href="https://taonaw.com/2026/08/13/emacs-pinky-is-becoming-a.html"><em>Emacs pinky is becoming a thing for me recently</em></a></h4><p>其实按理来说这不是一篇博客文章，而是没有标题的微博客帖子。</p><p>JTR 最近应该是在学习如何使用 Emacs：欢迎来到 Emacs 的世界！</p><p>Emacs 的快捷键很多是需要你按住左边的 Ctrl 键，然后按下其他键。通常大家的做法是用左手小拇指，做久了就会小拇指很难受。貌似 Neovim 也会有这个问题？我不清楚。我不用 Neovim。</p><p>也有一个解决方案是将 Ctrl 改成 CapsLk，因为很少人会用它⸺应该吧。我初中的历史老师就不会用 Shift 键来大写字母，而是用 CapsLk。如果习惯的话说不定还要比小拇指按住 Shift 更好用？</p><p>我的左手小拇指在使用 Emacs 之前就被摧残过，因为我以前是玩 Warframe 的。Warframe 里有个动作叫作 <em> bullet jump</em>，中文叫「子弹跳」，需要玩家在蹲下的状态下跳跃，而键鼠操作下你要按住左边的 Ctrl 来蹲下。</p><p>游戏跑酷的入门操作是先子弹跳，然后二段跳，然后靠瞄准滑行，所以子弹跳会经常被用到。鉴于在子弹跳之前角色通常还在奔跑状态，所以左手的小拇指要同时管辖左边的 Shift 和 Ctrl 键。当时跑地图真是小拇指要断掉。</p><p>不过我已经很久没有玩 Warframe 了。上次玩还是初次打工有了自己的钱，然后跑市场上买了套 Wukong Prime 甲⸺哇真的好帅，我好喜欢 Warframe 的美学跟设计。游戏本身就算了，我做不到天天刷材料……</p><p><a id="开学前-文具店小景"></a></p><h4 id="开学前文具店小景"><a class="markdownIt-Anchor" href="#开学前文具店小景"></a> <a href="https://blog.mfwt.top/index.php/archives/1561/">《开学前，文具店小景》</a></h4><p>墨枫梧桐中间讲到的各式各样的笔，让我的思绪也回到了小学时候。</p><p>我小学时还在山东，那会儿应该是 2013 到 2014 年前后，学校掀起个新热潮叫「可擦笔」。这种笔会自带个橡皮擦，可以擦掉字迹。字迹也能用蛮力和高温擦掉。</p><p>因为是热潮，所以很快我们班上近乎每个人都有一把。</p><p>后来老师禁止我们使用这把笔，也让热潮来去匆匆：因为很多学生用可擦笔写考卷，而考卷被临时放在了暖气片上，导致字迹全部消失了！</p><p><a id="一期一會"></a></p><h4 id="一期一會"><a class="markdownIt-Anchor" href="#一期一會"></a> <a href="https://poya.school/blog/ichigo-ichie/">《一期一會》</a></h4><p>作者刚来加拿大时，因为看不懂（翻到法语去了），所以很着急。但隔壁的姐姐伸出援手，非常照顾他。</p><p>本来文章讲的是很温情的事情啦，但我想到的是我 10 岁刚来美国时，因为第一天上学看不懂英语，再加上是转学生不知道美国学校的规矩，结果被老师说了。</p><p>开学时课上是要填写自己这个学期的 <em> goal</em>，也就是目标，然后写上一些自己的基础信息，比如上个学期的阅读水平。</p><p>这个阅读水平是从 A 到 Z 排序的。A 最差，Z 最厉害。</p><p>但我不知道这个制度，也不知道我的阅读水平是什么。老师看我没有写，就叫我快写。我说我没有听明白这是什么，他说回家把你的耳朵带过来！</p><p>后来老师才知道我根本不知道这个制度，于是让我念了本儿童书，最终结果是 C。</p><p>尽管之后老师对我的进步感到稀奇、夸赞了我⸺天啊小学的我还在努力学习英语，初中开始完全没有在努力学了⸺但当天的事情还是让我印象深刻。</p><p><a id="那些肉麻的話-你說的出口嗎"></a></p><h4 id="那些肉麻的話你說的出口嗎"><a class="markdownIt-Anchor" href="#那些肉麻的話你說的出口嗎"></a> <a href="https://yoon.club/7225/">《那些肉麻的話，你說的出口嗎？》</a></h4><blockquote><p>P.S 面對已經在一起的伴侶，肉麻的話…… 其實就只是…… 把一個正面的、溫暖的心意講出來讓對方聽見而已啊……</p></blockquote><p>我的「爱的五种语言」里，「肯定的言语」在中间。不是因为它不那么重要，而是因为「精心时刻」还有「肢体接触」太重要了。</p><p>面对恋爱对象，我会大力将对方抱紧紧，然后说「我真的好喜欢你啊！我超级爱你的！」对方也会抱回来，然后用比我大多的力气险些将我捏死。</p><p>在恋爱关系中，将自己的心意表达出来非常重要。我也会写情书，自制信封以及附上插画送给对方。</p><p>就算不是恋爱关系，和朋友之间的关系也可以用类似的方式交流：</p><ul><li>我很喜欢你今天的服装搭配</li><li>我很喜欢你网站上的这个这个那个那个设计</li><li>你的头像太可爱了</li><li>巴啦巴啦巴啦</li></ul><p>在学习社交的期间，朋友们给我的一大建议便是多去夸赞他人、主动发现他人身上的好和美。这样可以让我开始注意到其他人⸺这么说是因为我近乎不会对外人产生兴趣，也不会去注意他们身上有什么。但像是开始研究服装搭配后，看陌生人就会开始注意到他们身上的颜色、服装搭配带来的气质上的改变。</p><p>与其强迫我去关心他人⸺这么说往往会闹出笑话、让氛围很尴尬⸺先培养能看见美的眼睛、耳朵、鼻子，关心自然就会跟来。</p><hr><h2 id="折腾博客"><a class="markdownIt-Anchor" href="#折腾博客"></a> 折腾博客</h2><p><a id="学校博客"></a></p><h4 id="学校博客"><a class="markdownIt-Anchor" href="#学校博客"></a> 学校博客</h4><p>这个月从校友那儿听说，我校其实有个教学博客平台，用于课程博客、学生作业或者期刊、课程开发、行政沟通、教职工发展等场景。</p><p>它自 2008 年就在运营，真是神奇。之前完全没有听说过呢。</p><p>该博客平台的技术栈，是用了 WordPress 的多站点网络，然后使用 BuddyPress 来提供成员目录和个人资料页功能。</p><p>我大致看了下站点安装的插件，发现装了两个功能重叠的无障碍检查插件，还有自托管的隐私友好统计插件 <code>koto-analytics</code>，真不错啊，该不会维护的部门里偷偷藏着数据主权主义者吧。</p><p>作为学生，我登录后，便可以创建自己的站点。有趣的是，我还可以给我创建的站点里，创建他人的账号。搭建论坛什么的，也是完全可行的。</p><p>我还发现它有个姐妹项目，可以给学生属于自己的域名以及虚拟主机空间，让数字身份归学生自己所有，就算毕业了也能带走。</p><p>先前我一直顾虑着，是不是要再买个域名来托管现实身份相关的网页。我实在是不想要学校里的人、业内人士知道 Cytrogen 这个网络身份…… 有了学校的这俩项目，想必就可以弄个实名的专业门面了。折腾完后，我得想办法把该个人博客上的学习笔记迁移过去，之后估计也只会在学校的博客平台上更新学习笔记。</p><h2 id="我写的文章"><a class="markdownIt-Anchor" href="#我写的文章"></a> 我写的文章</h2><ul><li><a href="/posts/b3bc/"><em>Hate gifts</em></a></li><li><a href="/posts/83ff/">《Meta 和它不聪明的领导者》</a></li><li><a href="/posts/ea71/"><em>RE：Bloggers, can we make better titles for our posts?</em></a></li><li><a href="/posts/dbcb/"><em>RE：The Becoming Chinese Trend Is Nonsense</em></a></li><li><a href="/posts/f9e7/"><em>RE：The ordinariness of evil</em></a></li><li><a href="/posts/1547/">《RE：美国梦与美国痛 华裔新移民青少年帮派犯罪》</a></li><li><a href="/posts/ed86/">《休息日逛下城》</a></li><li><a href="/posts/6c9d/">《做导游的这几天：上》</a></li><li><a href="/posts/62c8/">《做导游的这几天：星期三》</a></li><li><a href="/posts/955e/">《好转和博客和主流和教会和性别和大扫除》</a></li><li><a href="/posts/3456/">《想法在丙午瓜秋迭代》</a></li><li><a href="/posts/1cfd/">《是的，我没有意识形态》</a></li><li><a href="/posts/ef30/">《牛郎织女和父权》</a></li><li><a href="/posts/b8c3/">《病殃殃的一周》</a></li></ul><h2 id="编程历程"><a class="markdownIt-Anchor" href="#编程历程"></a> 编程历程</h2><p><a id="复习-python"></a></p><h4 id="复习-python"><a class="markdownIt-Anchor" href="#复习-python"></a> 复习 Python</h4><p>我没有系统学习过 Python。第一次接触 Python 是想要有个 QQ 机器人，而使用的框架是用 Python 写的。</p><p>第二次接触，是因为学习网页爬虫。当时学习的 Python，完全是为了学习如何使用爬虫的包而学的。</p><p>近些日子找工作，总算出现了些不是收了简历就秒拒绝的进展，而这意味着我必须要开始学习算法。</p><p>我的编程可以说是野路子派的。你要问我任何和算法、Leetcode 相关的东西，我根本不知道。我很多时候都是项目中要用到、才去学习什么。</p><p>复习 Python 的平台我用的是 <a href="https://www.freecodecamp.org/learn/python-v9/">freeCodeCamp</a>。</p><p>关于 <code>enumerate()</code>，我过去听说过，但从未了解过。复习时才知道它是对这种写法的替代方案：</p><pre><code class="language-python">languages = ['Spanish', 'English', 'Russian', 'Chinese']index = 0for language in languages:    print(f'Index {index} and language {language}')    index += 1</code></pre><p>换成 <code>enumerate()</code> 则是：</p><pre><code class="language-python">for index, language in enumerate(languages):    print(f'Index {index} and language {language}')</code></pre><p>而它的进阶版本是 <code>zip()</code>。不是压缩的意思。它解决的问题是 <code>enumerate()</code> 只能枚举一个列表。</p><pre><code class="language-python">developers = ['Naomi', 'Dario', 'Jessica', 'Tom']ids = [1, 2, 3, 4]for name, dev_id in zip(developers, ids):    print(f'Name: {name}')    print(f'ID: {dev_id}')</code></pre><p>虽然不需要知道它们俩也能写出结果相同的代码，不过还是让我很惊叹。</p><p>下一节则是列表推导式。freeCodeCamp 称其为「优雅」：</p><pre><code class="language-python">even_numbers = [num for num in range(21) if num % 2 == 0]</code></pre><p>不过这样写，在实际项目中总感觉会让人难以快速看懂啊…… 这是另一个例子：</p><pre><code class="language-python">result = [(num, 'Even') if num % 2 == 0 else (num, 'Odd') for num in numbers]</code></pre><p><code>filter()</code> 我也是第一次见：</p><pre><code class="language-python">words = ['tree', 'sky', 'mountain', 'river', 'cloud', 'sun']def is_long_word(word):    return len(word) &gt; 4long_words = list(filter(is_long_word, words))</code></pre><p><code>map()</code>：</p><pre><code class="language-python">celsius = [0, 10, 20, 30, 40]def to_fahrenheit(temp):    return (temp * 9/5) + 32fahrenheit = list(map(to_fahrenheit, celsius))print(fahrenheit)</code></pre><p>不过 Lambda 函数我还是知道的。尽管我几乎都不会用到它。</p><pre><code class="language-python">def square(num):    return num ** 2# 等同于：lambda num: num ** 2</code></pre><p>经典的找偶数用 <code>lambda</code> 写：</p><pre><code class="language-python">even_numbers = list(filter(lambda x: x % 2 == 0, numbers))</code></pre><p>不过 <code>lambda</code> 的重点在于匿名函数。如果为了使用 <code>lambda</code> 而不得不将其赋到变量上，就没有意义了。</p><p>freeCodeCamp 也给出了 <code>lambda</code> 的不推荐示范：</p><pre><code class="language-python">result = (lambda x: (x ** 2 + 2 * x - 1) if x &gt; 0 else (x ** 3 - x + 4))(3)</code></pre><p>这种写法已经可以被说成是莫名其妙了，如果是在实际项目内。</p><p>建议还是搭配 <code>map()</code> 还有 <code>filter()</code> 用。</p><p>关于字典，我才知道 <code>get()</code> 和 <code>pop()</code> 可以传入第二个参数。如果找到的键不存在，就会返回该参数，而不是出现 <code>KeyError</code> 异常。</p><p>字典可以靠这种方法来做到自查验：</p><pre><code class="language-python">def find_invalid_records(patient_id, age):    constraints = {'patient_id': isinstance(patient_id, str) and re.fullmatch('p\d+' patient_id, re.IGNORECASE),'age': isinstance(age, int) and age &gt;= 18    }    return constraintsfind_invalid_records(**medical_records)</code></pre><p>假设 <code>medical_records</code> 是个字典，并且有 <code>patient_id</code> 和 <code>age</code> 键。用 <code>**</code> 可以将内容「爆」开来，相当于在写：</p><pre><code class="language-python">find_invalid_records(patient_id=medical_records['patient_id'], age=medical_records['age'])</code></pre><p>集合虽然我知道，但从来没有使用过。我对这门语言的认知实在是太肤浅了……</p><pre><code class="language-python">my_set = {1, 2, 3, 4, 5}your_set = {2, 3, 4, 6}print(your_set.issubset(my_set))  # Falseprint(my_set.issuperset(your_set))  # False</code></pre><p>集合的概念里有子集合和超集合。假设一串数字被包含在另一串数字内，那么前者就是后者的子集合，后者就是前者的子集合。一瞬间我想到这个概念可以拿来做什么题。</p><p>由于 <code>your_set</code> 里多了个数字 <code>6</code>，所以它不是完全被 <code>my_set</code> 包含、不是它的子集合。</p><p>更简单来检测的方法是用 <code>isdisjoint()</code>：</p><pre><code class="language-python">print(my_set.isdisjoint(your_set))</code></pre><p>如果要将两个集合加起来，就这么写：</p><pre><code class="language-python">my_set | your_set</code></pre><p>得出来的结果会是 <code>{1, 2, 3, 4, 5, 6}</code>。</p><p>或者用 <code>&amp;</code> 来返回个只有共通值的集合。</p><p>或者用 <code>-</code> 来返回个第一个集合有，但第二个集合没有的值。</p><p>或者用 <code>^</code> 来返回不共通的值。</p><p>这四个运算符跟 <code>=</code> 放一起后，就能拿来赋值了。如：</p><pre><code class="language-python">my_set -= your_set</code></pre><p><code>my_set</code> 会变成 <code>{1, 5}</code>。</p><p>我们也能用 <code>in</code> 来检查一个值是否存在集合内。</p><p>freeCodeCamp 提供了一些好的 debug 技巧。除了近乎每个编程语言都要经历的 <code>print()</code> 大法，它还说：</p><ul><li><code>pdb</code> 包，在代码中使用就像是在图形界面上打断点、鼠标悬浮查看对象类型等等</li><li>IDE 还有 VS Code 自带的 debugger</li></ul><p>Python 的类是个很值得挖掘的概念吧。我也没有系统性学习过它。</p><p>类概念里有个特殊方法，叫作 <em> dunder methods</em>，即所有名字以 <code>__</code> 开始且结束的方法。比如 <code>3 + 4</code> 其实等同于 <code>3.__add__(4)</code>。</p><p>如果只是 Python 内置的 dunder 方法的话，近乎是不用写它的，因为就像上面这个例子，会有其他更简单更方便的写法来指代它。</p><p>不过要自己写类、对象的话，就必须要了解了。</p><pre><code class="language-python">class Book:    def __init__(self, title, pages):self.title = titleself.pages = pagesbook1 = Book("Built Wealth Like a Boss", 420)book2 = Book("Be Your Own Start", 420)</code></pre><p>拿这个 <code>Book</code> 类作为例子吧。<code>book1</code> 还有 <code>book2</code> 都是 <code>Book</code> 对象。</p><p>假设运行 <code>len(book1)</code> 的话，会发现问题。这是因为 Python 不知道该如何用 <code>__len__()</code> 获取 <code>Book</code> 对象的长度。</p><p>我们可以去定义自己的 <code>__len()__</code>、<code>__str__()</code>，还有 <code>__eq()__</code>（以及更多！）方法：</p><pre><code class="language-python">class Book:    def __len__(self):return self.pages    def __str__(self):return f"'{self.title}' has {self.pages} pages"    def __eq__(self, other):return self.pages == other.pages</code></pre><p>作为另一个例子，购物车对象：</p><pre><code class="language-python">class Cart:    def __init__(self):self.items = []    def add(self, item):self.items.append(item)    def remove(self, item):if item in self.items:    self.items.remove(item)else:    print(f'{item} is not in cart')    def list_items(self):return self.items    def __len__(self):return len(self.items)    def __getitem__(self, index):return self.items[index]    def __contains__(self, item):return item in self.items    def __iter__(self):return iter(self.items)</code></pre><p>关于对象属性：</p><pre><code class="language-python">getattr(object, attribute_name, default_value)</code></pre><p>如果不知道一个对象有啥属性的话，可以：</p><pre><code class="language-python">class Person:    def __init__(self, name, age):self.name = nameself.age = ageperson = Person('John Doe', 30)for attr in dir(person):    if not attr.startswith('__') and not callable(getattr(person, attr)):value = getattr(person, attr)print(f'{attr}: {value}')</code></pre><p>创建或者更新新的属性：</p><pre><code class="language-python">setattr(object, attribute_name, value)</code></pre><p>检查属性是否存在：</p><pre><code class="language-python">hasattr(object, attribute_name)</code></pre><p>删除属性：</p><pre><code class="language-python">delattr(object, attribute_name)</code></pre><h2 id="书籍"><a class="markdownIt-Anchor" href="#书籍"></a> 书籍</h2><h4 id="其他评价"><a class="markdownIt-Anchor" href="#其他评价"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/book/0Ps7uKIsuiRjZdNZmd4fvg" target="_blank" rel="noopener noreferrer">许三观卖血记 余华著</a><span class="neodb-status">已读</span></li><li class="neodb-item"><a href="https://neodb.social/book/2BCkKhhhbVzaUnMHmYNYEt" target="_blank" rel="noopener noreferrer">路边野餐</a><span class="neodb-status">已读</span><p class="neodb-comment">不喜欢这本书的写作风格。内核和后记都很有趣。</p></li><li class="neodb-item"><a href="https://neodb.social/book/4469xHqNzj3rCFiC2hnjKA" target="_blank" rel="noopener noreferrer">The Absolutely True Diary of a Part-Time Indian</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已读</span><p class="neodb-comment">重新读一遍。读起来很舒服，作者用简单的词汇来表达人物的情绪和心中所想。<br><span class="spoiler"> 结局很烂，完全无法撑起结局之前的三个重要之人的死。作者也没能解答主角的身份问题，便莫名其妙让主角和解了。 </span></p></li><li class="neodb-item"><a href="https://neodb.social/book/0dgpnqTv6UYavkKc2625PN" target="_blank" rel="noopener noreferrer">挪威的森林</a><span class="neodb-status">在读</span></li></ul><h2 id="影视"><a class="markdownIt-Anchor" href="#影视"></a> 影视</h2><h4 id="其他评价-2"><a class="markdownIt-Anchor" href="#其他评价-2"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/movie/3V4pKFHRBYvdsH1HSoe5m3" target="_blank" rel="noopener noreferrer">Coco</a><span class="neodb-status"> 已看 </span></li><li class="neodb-item"><a href="https://neodb.social/movie/1tinbILMzwlY1GWoo89qfL" target="_blank" rel="noopener noreferrer">Spirited Away</a><span class="neodb-status"> 已看</span><p class="neodb-comment">长大后再看看出许多小时候没看出来的内核。</p></li><li class="neodb-item"><a href="https://neodb.social/movie/0WgEM5OyiAV60XZsrDyjYd" target="_blank" rel="noopener noreferrer">Zootopia</a><span class="neodb-status"> 已看 </span></li><li class="neodb-item"><a href="https://neodb.social/movie/6SAqdyMEu3kGepBN0mHZAr" target="_blank" rel="noopener noreferrer">The Shawshank Redemption</a><span class="neodb-status"> 已看 </span></li><li class="neodb-item"><a href="https://neodb.social/tv/season/37IX5sxZLqTzPHSleFiZtE" target="_blank" rel="noopener noreferrer">Food Wars!: Shokugeki no Soma (The Fifth Plate)</a><span class="neodb-status"> 已看</span><p class="neodb-comment"><span class="spoiler"> 最后这个私生子的设定有必要么…… 以及为什么男主和黑毛最后没有爆衣？！老爷子、男主爹全都爆衣了 </span></p></li><li class="neodb-item"><a href="https://neodb.social/movie/6bCOihfoK7tVGElGl3HbqY" target="_blank" rel="noopener noreferrer">The Legend of Hei 2</a><span class="neodb-status"> 已看 </span></li><li class="neodb-item"><a href="https://neodb.social/movie/6QEK7saKOR7Le7FIS6bGQg" target="_blank" rel="noopener noreferrer">My Little Pony: Equestria Girls – Legend of Everfree</a><span class="neodb-status"> 已看 </span></li><li class="neodb-item"><a href="https://neodb.social/movie/33pblskmD40C8cjxF13Pbh" target="_blank" rel="noopener noreferrer">My Little Pony: Equestria Girls</a><span class="neodb-status"> 已看 </span></li><li class="neodb-item"><a href="https://neodb.social/movie/7SaTDsOVNlIPrJSLTAiFKW" target="_blank" rel="noopener noreferrer">My Little Pony: Equestria Girls - Rainbow Rocks</a><span class="neodb-status"> 已看 </span></li><li class="neodb-item"><a href="https://neodb.social/movie/5uLPBCO1V7E73pA5OawX6d" target="_blank" rel="noopener noreferrer">My Little Pony: Equestria Girls - Friendship Games</a><span class="neodb-status"> 已看</span><p class="neodb-comment">以前看选歌切片的，这部的歌我经常听到但是完全不知道剧情是啥。</p></li><li class="neodb-item"><a href="https://neodb.social/tv/season/1pjylphBgIXpdeOWt9J7Oh" target="_blank" rel="noopener noreferrer">五等分的新娘</a><span class="neodb-rating">★★★☆☆</span><span class="neodb-status">已看</span><p class="neodb-comment">陪室友重刷这个作品。<br>我是原作铁粉。想要看这个作品的话我个人推荐还是看原作漫画更好些，无论是细节还是画风都更好。<br>作者春场葱的画风我个人很喜欢，可惜无论是动画的第一季、第二季还是剧场版我都不认为能复刻他的画风。更不用说这一季的各种崩坏场景，很难想象这是一个曾经销量达到过日本某季度第一的漫画的动画化产物，给你星星摘喽。<br>第一季所涉及到的篇章我个人都不是特别感冒，不加星也不减星吧。</p></li><li class="neodb-item"><a href="https://neodb.social/tv/season/2azh3WGI7gM3BDVvn8hnh4" target="_blank" rel="noopener noreferrer">Ultimate Battle The Next Generation</a><span class="neodb-rating">★★☆☆☆</span><span class="neodb-status">已看</span><p class="neodb-comment"><span class="spoiler"> 期待越高，摔得越惨。该作品的开头很不错，结果很快就沦落到日常打怪剧。很多集都特别无聊，白白浪费这么好的设定。很多挖坑不填，莫名其妙。来到错位的 15 年后本可以写很多，但观感跟没有穿越时差不多。设定根本是为了 hook 而写的。 </span></p></li><li class="neodb-item"><a href="https://neodb.social/tv/season/34835K4v61P6eQl9WMOx4E" target="_blank" rel="noopener noreferrer">Though I Am an Inept Villainess: Tale of the Butterfly-Rat Body Swap in the Maiden Court</a><span class="neodb-status"> 在看 </span></li><li class="neodb-item"><a href="https://neodb.social/tv/season/2psQaVPo8nGrcmsCHlYDGC" target="_blank" rel="noopener noreferrer">My Heroic Husband Season 1</a><span class="neodb-status"> 在看</span><p class="neodb-comment">重新看一遍。不带脑子看的喜剧，内核都不能推敲。</p></li><li class="neodb-item"><a href="https://neodb.social/tv/season/3UWT2jvjaFWtmDKM04TVFj" target="_blank" rel="noopener noreferrer">Friends Season 1</a><span class="neodb-status"> 在看 </span></li><li class="neodb-item"><a href="https://neodb.social/movie/6KMxh5WhS3tgLgdGjWqUSV" target="_blank" rel="noopener noreferrer">The Truman Show</a><span class="neodb-status"> 想看 </span></li><li class="neodb-item"><a href="https://neodb.social/movie/3yM15xdfCqSMzVvcHY4gUm" target="_blank" rel="noopener noreferrer">La La Land</a><span class="neodb-status"> 想看</span><p class="neodb-comment">最近在 AMC 看到 *La La Land* 十周年。知道歌但完全没有看过。</p></li></ul><h2 id="音乐"><a class="markdownIt-Anchor" href="#音乐"></a> 音乐</h2><h4 id="其他评价-3"><a class="markdownIt-Anchor" href="#其他评价-3"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/album/03O0v9k8D9KTDneF52ydT0" target="_blank" rel="noopener noreferrer">Ghost / Getting Better</a><span class="neodb-status"> 已听</span><p class="neodb-comment">这两首我都很喜欢。</p></li><li class="neodb-item"><a href="https://neodb.social/album/2LmnGCqZu4lf3T3SuDnyVM" target="_blank" rel="noopener noreferrer">Eat Your Dreams</a><span class="neodb-status"> 已听</span><p class="neodb-comment">Smash Thru 喜欢。</p></li><li class="neodb-item"><a href="https://neodb.social/album/7YqfO5uxzKiZZNIjpfMeka" target="_blank" rel="noopener noreferrer">Grizzly ni Osowaretara</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已听</span><p class="neodb-comment">灰熊是真的存在，还是少女为了你的关注而撒的一个小谎呢？<br>无论是哪一个，这都是一首很可爱的歌，少女感满满，旋律很欢快。</p></li><li class="neodb-item"><a href="https://neodb.social/album/3xnkZjJRIHUCjSOlDPGCwP" target="_blank" rel="noopener noreferrer">Shanghai Sketches</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已听 </span></li><li class="neodb-item"><a href="https://neodb.social/album/0raoBextspyRrvNVmkt0qp" target="_blank" rel="noopener noreferrer">Rikki</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已听</span><p class="neodb-comment">个人比较喜欢 *Friend* 和 *Why Try*。</p></li><li class="neodb-item"><a href="https://neodb.social/album/2niRtikcQzcTCcstERWVEf" target="_blank" rel="noopener noreferrer">September</a><span class="neodb-rating">★★★★★</span><span class="neodb-status">已听</span><p class="neodb-comment">超级经典。</p></li></ul><h2 id="日记片段"><a class="markdownIt-Anchor" href="#日记片段"></a> 日记片段</h2><button id="details-toggle-diary_sections-1789678111396" class="details-toggle-btn" data-group="diary_sections" onclick="toggleGroupDetails('diary_sections', 'details-toggle-diary_sections-1789678111396', '展开所有', '收起所有')">展开所有</button><details data-group="diary_sections"><summary>八月一日</summary><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYW9SAC6Z9CG2WFA56WJ33MN">↩ 续前文</a>        </div> 00:47 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYXCM5MM7XZC99P14AY09TAG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>换了台设备看，未读变成三千多篇了，你几个意思，你几个意思！</p><p>在办公室里待腻了，想要走条弯路干点坏事…… 是的！我堕落了！我要去游戏厅！</p><p></p><blockquote class="diary-thread-reply">02:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYXKBSXTKV2VF5R56AVGJFKM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>玩得一塌糊涂。这种游戏就是这样啦，快乐和分数绑定在了一起。一个人玩就跟一个人埋头刷题差不多。歌曲、节拍…… 可能有些腻了。现在唱歌更新鲜一点。</p><p></p></blockquote></div><hr><div class="diary-entry">01:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYXDQQ7DX3RWPGJ4HAGFKZJK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友的父母虽然四五十多了，但从来不会倚老卖老，很多时候我都觉得他们比我年轻好多。比如他们的习惯有早起去咖啡厅、做瑜伽、做运动、为热爱的事业向前进。所以我有时会想，室友脑瓜子好得令人感觉奇怪，也有受他们的影响。</p><p>因此，我不相信年龄大是人做不了某件事的理由，比如年纪大了写不动、做不了运动等 —— 这有以偏概全的问题在，也有我有报复性心理的问题在。总之就是这样。</p><p></p></div><hr><div class="diary-entry">01:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYXE0Y4BKEAZ7YC0TWPZ1RA3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有意思的电梯。在外面选择要去哪层楼，匹配到的电梯会过来。电梯内部是没有选楼层的按钮的。</p><p>电梯来得很快，但这个触屏不好用。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYXE0WKV401KAKTEKJNJZS2Z.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">02:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYXJW2TYH0NGGZ493S4V2K6Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有人搬家，街道上留着他们丢掉不要的家具。我看了一眼，感觉挺新的，难道是留学生？可惜家里不缺桌子。</p><p></p><blockquote class="diary-thread-reply">02:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYXJYV5JCHGAS128YDWPPJS9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>家里的信箱只有广告、广告、广告。</p><p></p></blockquote></div><hr><div class="diary-entry">03:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYXMA463W1B88GAZJ96AP1V7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友经常吓我、装成要揍我的样子，好让我害怕，然后虹膜可能会放大或者缩小。不过从来不会像她所想的那样发展。</p><p>人的虹膜应该和猫的差不多，在黑暗或者亮光下会自动调整大小，不过不会像猫那样夸张。我也想知道对焦不对焦会不会对虹膜有影响。</p><p></p></div><hr><div class="diary-entry">03:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYXMSJE023WB4GG85JR5N6YW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p></p><ol><li> 使用 Meta 的产品</li><li>看着亲戚甲乙丙丁出现在好友推荐</li><li>退出 Meta 的产品</li></ol><p></p></div><hr><div class="diary-entry">03:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYXP37YMM73MT82A3MZ7HKYS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看了 Friday Night Funkin' 的 Lullaby 模组相关的视频，应该是讲宝可梦都市传说的？画面都挺猎奇的倒是。</p><p>就很好奇他们是怎么想到利用人体的各个部位来设计且营造出这么不适的感觉。</p><p></p></div><hr><div class="diary-entry">04:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYXRGCCKHVXHNBR0AE8AXXD5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看个 AI 模型学习玩游戏的视频，因为涉及到了奖励机制，于是评论区里全都是管理学、键盘政治等忍俊不禁的内容。</p><p>为什么会这样。</p><p></p></div><hr><div class="diary-entry">04:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYXRJV10J9HNMS8RY7SF63SF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>死室友把豆渣倒厨房水槽、堵了，然后一个人跑出去鬼混去了。我要爆粗口了。</p><p></p></div><hr><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYWWSGG3EPYBDQC4SBPN7ZTB">↩ 续前文</a>        </div> 06:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYXZPHQDCPWWJMMGW4QTRGFP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天晚上学着唱了下。结果是这样的：</p><ul><li>戴着耳机一边听 off-vocal 的音乐一边唱：我真厉害</li><li>播放录不到音乐的录音：这特么谁啊唱这么跑调</li></ul><p></p></div><hr><div class="diary-entry">10:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYYCSE18T0WGMXVRYFYGG7E5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>睡前看到了有些在意的事情，但太困了就睡着了。醒来后发现自己好像梦到了这件事，然后现在也在想这件事。</p><p>唉睡前不该乱看东西的。我哭。</p><p></p><blockquote class="diary-thread-reply">10:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYYCXSS1XB1AP3YJ00HD3NSF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>话说我就睡了三个小时怎么就醒了。还是得回笼。</p><p>有时候在中文输入法里打 <em>cytrogen</em>，回车没打到，导致打出了默认第一个 candidate 的结果：村团承恩。这一切在双拼下显得是多么正常。</p><p></p></blockquote></div><hr><div class="diary-entry">19:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYZD0H0YVTDHFX8AEEW8Z5ZT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>公开反对一观点会引起提出方反感，考虑到分开主体和客体是一件需要学习的事情。接下来往往会发生其中的一个：</p><ul><li>你说错了，因为……</li><li> 你说对了，因为……</li><li> 你是 SB</li></ul><p></p></div><hr><div class="diary-entry">19:43 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYZDNBGG8MRP5TN4V5Q4571N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>天气又变得炎热了起来。</p><p>我觉得自己实在是太闲了，赚钱的事情一件都没有做。</p><p>身边的人觉得我写东西是在玩，叫我别玩了。我想他们所言极是。我在逃避找工赚钱的事情。</p><p></p></div><hr><div class="diary-entry">19:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYZDQDY91VYH6HG7Z74NZAC9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我主张康师傅低糖经典奶茶比奶茶店里的经典奶茶好喝。</p><p></p></div><hr><div class="diary-entry">19:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYZE1599RQ3BAMQXD8Z92SEA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我昨天看到有人问「大屁股电视」是什么。然后我想到单看这个词，会不会真的以为是电视后面加俩屁股蛋儿。</p><p>然后我看到有人说「卸载 QQ」，想半天才发现原来是「绝育」、「去除睾丸」的意思。特么的。</p><p></p></div><hr><div class="diary-entry">20:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYZG8Q5ARAWVZ2JCEK40D2CA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>母亲的朋友来纽约玩，她开的是 Tesla 的一款车。她老公路上就跟我聊自动驾驶，说分很多模式；前方玻璃有个摄像头会盯着司机看，保证司机没有玩手机等；自动驾驶要订阅，每个月 100 来块钱。</p><p>这是我第一次坐带自动驾驶模式的车，它的车门也是往上开的，很新奇。</p><p></p><blockquote class="diary-thread-reply">21:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYZMJ50ZA7BKTRZ2Z9R0J868" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我们去了母亲朋友家。里面的奶奶躺在按摩椅上在看《西游记》。现在在播放的应该是…… 红孩儿被观音抓走的那集？电视的声音很小，只能看画面猜台词了。</p><p>我没有看完过《西游记》的任何电视版，也没有读过原作。内容什么的都是从二创作品还有《卡布西游》那儿知道的，所以儿童向网游确实能教小朋友东西。</p><p></p><blockquote class="diary-thread-reply">08-02 00:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYZYVN082Z9ZCD7WKTV5S9KQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><em>LOBSTERS!</em></p><p>但是楼下的卡拉 OK 好吵。没有做隔音吗……</p><p></p><blockquote class="diary-thread-reply">08-02 02:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ06714W9E0039PEKC615T2R" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>歌词里有「一丝丝情意」的那首歌，是日语歌翻唱么？这个软件上的 MV 同时带了日语字幕和中文字幕。</p><p>结果长辈们唱车载音乐，发现旋律都没有我唱得对。</p><p>原来我小时候听过这么多吗……</p><p></p><blockquote class="diary-thread-reply">08-03 13:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ3WAGKSM2A7B8JEQDPPKJGF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>找到了，日语原版的是《時の流れに身をまかせ》：</p><blockquote><p>だからお願い</p><p>そばに置いてね</p><p>今はあなたしか</p><p>愛せない</p></blockquote><p>中文翻唱的是《我只在乎你》：</p><blockquote><p>所以我求求你</p><p>别让我离开你</p><p>除了你 我不能感到</p><p>一丝丝情意</p></blockquote><p></p><blockquote class="diary-thread-reply"> 08-03 14:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ3Z6AH8QYJ6M5GTAFB12JBX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>又翻找了一下发现这两首其实都是邓丽君唱的……</p><p></p></blockquote></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">21:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYZJKRBHVP6JSRV9D9PTCSM5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有时候这猫会露出宛如 sigma male 般的绝美下巴。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYZJHZTJ8WPFKPMWF8KBHJKX.png" alt="一只长毛三花猫对着镜头的左侧。" loading="lazy"></figure><blockquote class="diary-thread-reply">21:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYZM27XATAS45T94P3GK7W96" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不知道为啥我感觉拍到的咪咪猫一直在斗鸡眼。显得它看起来好不聪明。</p><p></p></blockquote></div><hr><div class="diary-entry">21:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYZKF47944YTEESVK5B6YKNR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我在使用的图片编辑软件，可以在 F-Droid 上安装： <a href="https://f-droid.org/packages/ru.tech.imageresizershrinker" rel="nofollow noreferrer noopener" target="_blank">https://f-droid.org/packages/ru.tech.imageresizershrinker</a></p><p>功能很多，还有图片转 SVG 的。我试了下，预览后感觉太厉害了，比我之前写的那套好多了。</p><p>整体软件设计很 Material-UI 3？我不太适应。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYZKDE9M6522SGTFVGMRJ232.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">21:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYZKYQ99MPFBX3GWZFZR04N9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>狗狗狗猫照片。</p><p>找妹妹要的。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYZKR1R38GJ07JH7TTMJZ9N5.jpeg" alt="迷你贵宾在车内，头微微探出车窗。车外天气明朗。车子开在一个平原小道上，路边是一栋房子。" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYZKR2EB3B1CNJH92CYEV6AM.jpeg" alt="迷你贵宾在草地上奔跑。" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYZKR2EBSP622SJ4QMGF0FKN.jpeg" alt="迷你贵宾在毯子上、往天上看。" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYZKR2P1GATMWMNBCAXHEVD6.jpeg" alt="长毛三花猫趴在木头地板上。拍摄者左边拿了个气球。" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>八月二日</summary><div class="diary-entry">01:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ006JZ63YBEAW9KTTWPBTBC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Interesting……my sister's iPhone can detect how far her face is from it and stop her from using it until she backs up a little.</p><p></p></div><hr><div class="diary-entry">02:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ055H8BZEHY8RMD4DA017VG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说来惭愧我很多服务还没有从 Gmail 挪到自托管的邮箱地址来 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY6DSW5XQ8X634ETSSK232X1">↩ 续前文</a>        </div> 04:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ0BBBFJNDZFJ4VPY39BKV41" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>NOOOO 怎么是带墨胆的。得额外买个上墨器。</p><p>笑脸钢笔真的很可爱。</p><p>明天得早起、罕见去趟教会。到时候听道再用用看。</p><p>我得好好衡量「何时带笔记本电脑」了。太重了也。</p><p></p></div><hr><div class="diary-entry">14:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ1CVNGK2VH4GVBGP9XSXKJZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>I am one hundred percent tired of this shit: when can people understand that luxuries do not suit anything, anyone? Like you don't expect a kid to have a Louis Vuitton bag while in sporty styles. My mother can literally wear a goddamn luxury bag with pajamas wtf.</p><p></p></div><hr><div class="diary-entry">20:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ23QS5BTD7DYZY81XFYXHBG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在超市里看到了这款，买了瓶喝，应该是 2 块多。</p><p>第一次喝它应该是上初中或者小学的一年。那时我有了一点点零花钱。一天上学路上，我突发奇想想尝尝「奶茶」是什么滋味儿。结果被它苦到，但喝了后感觉味道还能接受、挺不错的。几天后又买了、被苦到、感觉不错。</p><p>我刚才拿吸管喝了下。哇淦好苦。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KZ23FT3S59RBKZTRFDPJ09BB.jpeg" alt="蘭芳園丝袜奶茶的正面照。" loading="lazy"></figure></div><hr><div class="diary-entry">20:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ24CA3EK0HXFE0KAPDXZZBM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天去见教会里的人。嗯我还是有套信主人设的，sorry。不过最近思考政治的事情，感觉现在思考宗教也能思考出新的东西来。</p><p>总之这个教会多数是亚裔：新移民、美国出生的孩子、韩国人…… 年龄段也很多样化，不像我们家之前去的教会，都是中年或者老年人，没有多少新鲜血液。</p><p>English service 期间大家聊的东西也很有趣。有人提到了 <em>smartphone is evil</em> 然后延伸到了 screen time、时间管理、小孩子长大后是否应该继续被管控？我来见的那个人说，自己的女儿大了（其实也就初中生）、是个 adult 了 —— 准确来说是 young adult、小大人，可以理解成开始懂事、有自我观念的孩子 —— 她不想要去管控她。但女儿开始有手机后，下载并安装了大量的社交软件，并且开始和朋友们以非常莫名其妙的事情而吵架，如甲没有 follow back 乙。她觉得有了智能手机后很多东西被夺走了。</p><p>另一个人说他之前做过调查，发现 2010 年年轻人的心理问题数量大幅增加。调查期间他发现同年多了这个东西：自拍用的前置摄像头。</p><p></p><blockquote class="diary-thread-reply">08-03 01:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ2M2BVVZJFXJSC21V94TXJV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我母亲之前带我去的教会也是我讨厌该宗教的原因。该教会是家庭教会，也就是说，这里的「统治」是「世袭制」…… 牧师和师母老了，就让他的儿子继承。这对老人长期私吞教会内的捐款，儿子来了也继续私吞。</p><p>然后他们还大晚上联合 PUA 我，让我次日去做翻译！</p><p>不过我也借此发现实时翻译好难喔。相当于「听英语想英语、花费精力将其翻译成汉语、说汉语」。</p><p>我更喜欢大家都能互相倾听、真心讨论的环境。今天过去说了些话，还被夸赞很有内涵、public speaking 没有关系 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JNHF23SBKYB8350F7PKT.png" alt=":neocat_happy_blep:" loading="lazy">​ 和教会里的许多同龄人都不太一样。</p><p>实际上我也经历过对长辈们的话题不感兴趣、一直在刷手机的阶段。比如 screen time 的话题，他们心里可能就会在想「啊他们在说教我嘛！你们懂什么啊！」—— 未来他们的想法会慢慢改变，也没有必要去教训他们。</p><p>我还去了别人家里看三个月的拉布拉多 mix 宝宝。感觉好不聪明，一直在尝试咬咬我。不过训练得很好，坐下、握爪都会。幸运狗只会坐下跟趴下，剩余的都是看我们手势和语气，比如叫它去后院或者上楼或者下床。</p><p>咪咪猫还是不亲我…… 对面家前院草丛里的野小猫都被别人抓走、不知道去了哪里。如果是去了 shelter 或者被人收养走就好了。</p><p></p></blockquote><blockquote class="diary-thread-reply">08-03 13:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ3XZVCD832P7B40GNKNF64X" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>啊对了，这个教会在 upstate 有自己的一块地，上面盖了房子、有湖，有点像度假用的世外桃源。</p><p>他们跟我解释说是用来让小孩子、青少年、我这个年纪的年轻人来社交和体验生活的 —— 里面禁止参与者使用手机。当天就有一批小孩子要过去生活一周，临走前各自薅了爸妈钱买了一堆零食。</p><p>我想和朋友们体验类似的事情也会很高兴。之前我校有个 leadership weekend，差不多也是带学生们去露营地过个周末。尽管我没有去，但那为我带来了非常不愉快的事情…… 再加上有去过的朋友反馈说正因为是 <em>leadership</em> 所以吵谁是 leader 的情况很多，实在是不喜欢和大批 <em>leader</em> 待在一起。</p><p>看形式与我在 <a href="https://blog.cytrogen.icu/posts/eac7.html#%E4%B8%80-%E9%97%AE%E9%A2%98%E5%B0%91%E5%B9%B4%E4%BA%A7%E4%B8%9A" rel="nofollow noreferrer noopener" target="_blank">这篇博客文章</a> 内写的 <em>troubled teen industry</em> 相似：都是去野外、不让用手机啥的；不过区别依然很大，最重要的莫过于真正掌握权力的主办方与家长们都很尊重孩子们的意愿：我母亲本来也想要丢我妹妹过去，不过和其他家长们聊过后，觉得她还没有在新的教会内找到新朋友、再过去会很尴尬，还不如先慢慢交朋友、未来再过去玩 —— 对于母亲可真是个大进步，她不和其他家长商讨的话一定会强硬把妹妹塞进去、并责怪她为什么不和别人做朋友。我也认为多和她认为的「权威」做朋友、受他们良好教育的影响，母亲也会慢慢变成个更讲理的人。</p><p>如果仅是因为做的事情相同，就认为本质相同，便会陷入 <a href="https://blog.cytrogen.icu/posts/36e6.html#%E4%BD%95%E4%B8%BA%E5%B7%A6%E4%BD%95%E4%B8%BA%E5%8F%B3" rel="nofollow noreferrer noopener" target="_blank">马蹄铁的陷阱</a>。</p><p>当时和教会内的家长聊到 screen time，这种担心没能归还孩子自由与自主权的观念也让人惊叹 —— 我很少会看到有人把初中生说成是 <em>adult</em>，意味着承认他们已经有了自主观念、能为自己思考。</p><p>晚上一起吃饭时，她跟我们聊她女儿要考中考的事情：因为是私立学校里少见的亚裔，她女儿觉得难以融入，也觉得自己没法变 popular（有人气？怪怪的翻译）。如果去亚裔更多的学校，就不会这样了。她本来是觉得能去私立更好，不过既然女儿这么说了，必须要遵从女儿的想法。</p><p>母亲谈话间一直说自己什么都不懂、不会英语、没法在学术和教育上帮到我妹妹。她就说你必须要学、要懂！孩子也不懂多少，你是他们的家长，你要帮他们！</p><p></p><blockquote class="diary-thread-reply">08-03 13:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ3YCD8FT48P1EN2KFMMEW5Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>吃饭期间另一件让我感到意外的事情是父亲非常罕见地过来闲聊。过去他是个我过生日都要蹲在角落自闭的人。他承认过他社恐，不过总感觉他的「社恐」来源于母亲的边界感太弱、经常带他不熟悉的朋友到家里玩。</p><p>我和父亲的关系没多深，因为他在我小时候缺席了很多年。我和母亲都认为他是个「害羞」的人，但我想我也没有尝试去理解他。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">22:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ29JPG8B1QQTX0FFKVNNPE4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Walking Lucky this afternoon in this giant park. Lucky had fun. I don't. I think some random bugs bit me <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy"> There are a lot of people playing baseball and volleyball. I played volleyball in high school. Definitely not professional level, but I think I was doing okayyy……</p><p>I was heading out to pick up my sister. She went to her friend's house. It was a really loooonnnng walk. I should abandon Lucky and choose the bike instead -- it's a joke, don't take it seriously.</p><p>Her friend has a baby sister. While the older kids were watching TV, she showed me her Roblox Kids account -- they have a Kids version now? -- and a game called Toca Boca (I think that's what they call it).</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KZ29K2SM1R6WBJ1HS82N342K.jpeg" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>八月三日</summary><div class="diary-entry">02:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ2NVRVPZXP2SA7JREQ8SX7F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>离开父母家、回曼哈顿的路上，发现妹妹偷偷在我的包上挂了个玩偶。</p><p>对于我的短暂回家，父母还是挺开心的。只是，我现在这个阶段觉得陪伴室友更重要。她在这个国家里紧急联络人写的还是我。</p><p>过去和父母发生的种种纠纷，我现在也难以原谅或和解。他们确实在成为更好的自己，但我不应为此承担任何责任 —— 我讨厌的、伤害过的人都有过同样的想法：明明自己已经改正了，为什么我还没有原谅他们 —— 因为我没有义务去那么做，我的原谅也不是什么任务奖励。没有人应得什么 —— 人权除外。</p><p></p></div><hr><div class="diary-entry">02:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ2QFSVP0E809PQHSW5NVPAE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p></p><blockquote><p> 不过最近思考政治的事情，感觉现在思考宗教也能思考出新的东西来。</p></blockquote><p>之前在博客里讲了右翼诈骗营销的思路：</p><ol><li>洗脑民众，让他们以为社会问题由个体或者特定群体导致，比如移民</li><li>久而久之，让他们以为社会问题也能被个体或者特定群体修复，比如 Trump</li><li> 因为社会问题可以被个体或特定群体左右，因此法律是不被需要的</li><li>销售，比如 Trump 的破手机</li><li>就算他们被骗，也会觉得自己是被「导致了社会问题的坏个体或特定群体」欺骗，然后带着更多的绝望与愤怒去相信下一个能拯救自己的个体或特定群体</li></ol><p>极端的宗教也能应用该理论：</p><ol><li>洗脑教徒「只需要祷告即可」</li><li>如果事情变好了，就是祷告显灵</li><li>如果事情变差了，就是祷告得不够多</li></ol><p>教徒不会去质疑「仅祷告不会让生活变好」这件事。</p><p></p></div><hr><div class="diary-entry">02:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ2R6GQB8NB62QHD928K0DWW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我是不是应该在 bio 或者置顶嘟文里写明我会发表什么内容？虽然我在关注别人之前就会把对方的帖子扫过去一遍、得知对方大致会对什么话题感兴趣 —— 有人是不这样做的么？</p><p></p></div><hr><div class="diary-entry">04:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ2ZVV9ZJPJTMVQQXRRT8Q2K" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我看了「什么值得 ban」标签，好似打开新世界的大门…… 当然是不好的新世界。各个方面上。</p><p>互联网上的连接相对于现实中的，我想会更难控制。</p><p>因为涉及到许多负面的内容，我不由得会开始遐想如果我被恶意攻击了，我会做什么？</p><p></p></div><hr><div class="diary-entry">14:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZ3ZHKHHPMCHWTA87YZZXTWW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不太理解第三个图标是啥…… 按顺序应该是太阳雨但为什么下的是闪电？太阳雷阵雨吗？</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KZ3ZGBD02X9AN2QNT9FYSMG2.jpeg" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>八月十二日</summary><div class="diary-entry">15:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZV95GD035AE3DM7VXSWQX37" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这都啥呀。</p><p>我倒是好奇他会推荐啥出来。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KZV93293F852PFG0VG17YGKR.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">15:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZV9BHVQYZV9CP5812DHTRA2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 推荐的一些书别说我书架上确实有……</p><p>不过这些标题还是太诡异了吧。</p><p></p></blockquote></div><hr><div class="diary-entry">16:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZVDFRMV1HHBK0HX7NKVRXD0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>亲戚说想要让她妹妹从国内转学到美国的大学。于是问我一些问题。我大致回答了下毕竟我对她们居住的州不熟，也对她妹妹的专业不熟。</p><p>讲完后对方落下一句「那你帮我咨询一下吧」。</p><p>那不是我该做的事情吧！</p><p></p><blockquote class="diary-thread-reply">08-29 14:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M16XXP7CK7SHWRSRMFR8MAFD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这个亲戚前几天又过来找我了。</p><p>她说她去问了 ChatGPT，她妹妹可能需要去什么地方以验证国内成绩单是否有效。然后接下来想要我帮她看看。</p><p>他们都默认我会做这些事，因为我们是关系好的亲戚。</p><p>母亲甚至说，她妹妹国内上这么好的大学，如果转来我的大学是不是屈才？他们将大学的「名不名牌」看得是比天还高！</p><p></p></blockquote></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">《赘婿》剧透相关。</summary>        <div class="diary-cw-content">23:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZW3AN5C00HAW281RRAQ6MRF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我还是太高估这种剧了。槽点满满。</p><p>不太理解为啥男主上部小说还像个事业男，这部小说突然有很多诡异的想法。确实按照故事中的「作者」说的那样，样貌和性格都变了，但变得很彻底啊！</p><p>以前看就记得后面拍得很烂。最后一集甚至没有出现女主。</p><p>根据我对网文改电视剧的刻板印象，电视剧可能改了很多不良用词……</p><p>虽然这个片经常说什么女子能办成事，但核心冲突依然是女主出事儿男主来救。和之前看的知乎盐选文差不多。尤其是反玛丽苏文，内核依然是玛丽苏。</p><p></p></div>      </details></div><hr><div class="diary-entry">23:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZW4HNG0FYQJXXNHQ01FNKB2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>可能问太晚了但木棍人和 Italian brainrot 到底是啥玩意儿啊。</p><p></p></div><hr><div class="diary-entry">23:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZW60XY1AXG049MZB3X0DQWF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>钢笔小伙伴们。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KZW602C4VB4TECP7V8875N8W.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">08-13 00:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZW7DGFP8DR4X32PM4N2ZE5X" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最左是毕加索 902 Gentleman。</p><p>室友来美国买的，不知道怎么买到的中国牌子。因为不用就给我了。</p><p>笔尖应是 M 尖，适合签名。最下方有小字写了 <em>22KGP</em>。</p><p>笔杆是树脂做的。</p><p>很漂亮是真，但不喜欢用。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KZW6Y20G32RFH70E07PEHVEZ.jpeg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KZW6Y26KSSZ7YJ8P46ZWFPE9.jpeg" alt="" loading="lazy"></figure></blockquote><blockquote class="diary-thread-reply">08-13 00:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZW7S6XN3W7B1RQS1Q3PGAR2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>左二是金豪 911，在 Temu 上几块钱买的。</p><p>外形 <del>抄袭</del> 致敬了 Parker 51。</p><p>笔尖是暗尖，即把笔尖藏起来的设计，这样长时间不盖笔帽也不会很快挥发。</p><p>很轻。因为很便宜所以被摧残也不会太心疼。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KZW7M9CBAPQ579VCVC63861B.jpeg" alt="" loading="lazy"></figure></blockquote><blockquote class="diary-thread-reply">08-13 03:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZWJCPJA7MEHDSDR6JHG71G2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>左三 LAMY Safari。感觉玩钢笔的人手一支。</p><p>外壳是 ABS 工程塑料，很抗摔。</p><p>笔握处是三角形设计，非常适合作为「第一支钢笔」来练习如何握笔。同样的设计在 Pilot kakuno 上也能看到。</p><p>我这把原本是 M 尖，后来另买了这个 EF 尖。不过对比 Pilot 的 EF 尖还要粗上一点。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KZWJ6C03QMKF5CNQK8VQDDTR.jpeg" alt="" loading="lazy"></figure></blockquote><blockquote class="diary-thread-reply">08-13 03:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZWK4E16DKZ7EXMXBGAVEGVV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>右边倒数四把 Pilot 88G /Metropolitan 动物花纹系列。</p><p>P2 的花纹分别是：</p><ul><li>下 1 和 上 1 的青铜蜥蜴</li><li>上 2 的银蟒蛇</li><li>下 2 的黑鳄鱼</li></ul><p>当时拜托国内亲戚帮我在淘宝上买，正好有个 5 支捆绑卖的。结果亲戚买重了青铜蜥蜴，其中还有一支白老虎被我爷爷扣押拿走了。紫色豹也没有买到。</p><p>买后有赠送给朋友的意向，但完全没有人想要……</p><p>因为是铜做的外壳，所以拿在手上还蛮沉的。笔尖则全是 F 尖。</p><p>是我日常使用的钢笔。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KZWJGV386Q1ADXZPSE9Z7Z0W.jpeg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KZWJGVE4VWHRRYS6SPN6F4D6.jpeg" alt="" loading="lazy"></figure></blockquote><blockquote class="diary-thread-reply">08-13 04:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZWMKFSRGEEHNTG9B09T2Q03" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最右边的设计非常可爱的 Pilot kakuno。</p><p>因为是日系 EF 尖，是我全部笔里最细的，所以最近常用它写笔记。</p><p>同为 Pilot 笔，但这款笔身是六角形，不会滚到地上然后被摔…… 血的教训，我的 88G 被摔好几次了。不过都没有坏过，也是很强壮。</p><p>整支笔都是轻量化塑料材质，所以拿起来特别轻。</p><p>笔盖上有小孔，是为了不让小孩子吃进去然后窒息死掉。不过这也意味着这把笔挥发速度相较于其他钢笔要更快。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KZWMKDKVK187C7SYJJ00AYRM.jpeg" alt="" loading="lazy"></figure></blockquote></div></details><details data-group="diary_sections"><summary>八月十三日</summary><div class="diary-entry">03:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZWH1N76QQ01VTR2PTWFX2QK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友做的香蕉奶油可丽饼。</p><p>奶油打不起来是因为 whipped cream 它…… 结块了…… 块了…… 了…… 尝了一口倒是没坏，很奇怪。</p><p>草莓依旧没有买。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KZWGYQB8SJTRDRNP7ZPBAFNM.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">03:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZWH9NFB0MH4N968Z7M1SYEH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>养猫咪的坏处是到处都是猫毛。</p><p>本来想拿个给室友吃，结果在上面找到猫毛…… 如果她吃了会过敏死掉的。</p><p>说到过敏，应该是免疫系统「过分敏感」的意思吧？所以室友得病然后好得比我快是合理的？因为我的免疫系统「过分迟钝」？</p><p></p></blockquote></div><hr><div class="diary-entry">03:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZWH547ZEXCVTB6N1N9TN88A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天状态整体是喉咙干干的，怀疑是之前咳太用力伤到嗓子了。只能灌蜂蜜了。</p><p>擤鼻涕和咳痰的频率明显下降。周末之前应该能好，到时就能出门参加活动了！</p><p></p></div><hr><div class="diary-entry">13:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZXKTNEZT9D0A4XY8TM1SYBF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看别人推其他人搞博客。我想了想我身边有谁能推荐搞博客：</p><ul><li>室友讨厌博客，但会搞讲座</li><li>觉得弄网站很麻烦，也有可能觉得写博客是「小资」爱好的朋友</li><li>不想让他们知道我有写博客的其他朋友因为他们都觉得我是傻逼并且还是 Meta 忠诚粉丝</li></ul><p>嗯还是算了吧。</p><p>写博客的前提我想是在于乐意记录什么，比如生活、分享笔记等。确实有喜欢体验生活、记录它们的朋友，但他们无一例外全都是 Meta 的忠诚粉丝，且习惯了 Meta 的产品、觉得不使用 Meta 产品的人活不下去的 —— 当然能活下去啊，倒不如说不用反而觉得活得更舒坦。</p><p>有喜欢体验生活的，自然也有不喜欢体验生活的。至少我不会把在家里虚度光阴的行为视为「喜欢体验生活」……</p><p>至于写博客是不是「小资」爱好…… 好吧我没法理解对方「小资」的标准是什么。难道是除了玩电子游戏和刷视频以外的爱好都是吗。</p><p></p></div><hr><div class="diary-entry">14:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZXRVCZR8K2EWF38RGCPFEBH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这几天在重新看在追连载的百合漫画。室友问我喜欢看哪种，我想半天只能憋出「强烈的感情表达」这样不明所以的话。</p><p>之后在看，好像挺喜欢看单向暗恋的。尤其是恋情与现实之间的摩擦以至于一方爆发。</p><p>但这也是我在现实生活中最不乐意看到的东西…… 这是为啥，二次元美少女让我与其和解了吗？</p><p></p></div><hr><div class="diary-entry">16:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZY0NVAM1882FM13CCA2MN3N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看书看得头疼。书架上还有些没有碰过的书，但我感觉没有必要读那么快。我的病还在，午饭也没有吃。想看点轻松的电视剧，但想不到看什么好。</p><p></p></div><hr><div class="diary-entry">22:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KZYN38ET1AYN3CBN0WJ86J0C" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我在玩 Minecraft 的 Verity JE 模组。</p><p>总之是什么情话都搬出来说了。</p><p></p><blockquote class="diary-thread-reply">08-14 14:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0099MHXS4Y6X3QQR4PABMCB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看别人玩有意思，我自己玩挺没趣的。</p><p>一是我还挺怕玩恐怖游戏；二是我 Minecraft 玩不好，要是恶魔生成出来我会打不过。</p><p>于是开了创造模式跟超平坦世界，然后和 Verity 谈逻辑，最后说服他不要变异成恶魔杀我 —— 当然召唤恶魔是程序决定的而非模型，他还是召唤出来了但没有关系我放了几十个铁傀儡在等着他 —— 这种玩法完全就是在和有着特定 prompt 的 DeepSeek 聊天。</p><p>Minecraft 近期都没有怎么在玩，因为室友玩腻了，我整天也只是在研究自动村民奴役场。晚上两个人打开 PUBG 玩。Mobile 的国际服到处都是人机，紧张半天结果最后一个队伍被毒死……？好没劲儿。就去睡觉了。</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>八月十四日</summary><div class="diary-entry">15:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M00FGWC6ZD0WPK4HR388H4VW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://www.meta.com/thefutureisforeveryone" rel="nofollow noreferrer noopener" target="_blank">https://www.meta.com/thefutureisforeveryone</a></p><p>Bro made its own slop bot and call it <em>democracy</em>. Hilarious.</p><blockquote><p>It will have strong privacy and security options so you can trust it to handle all of your personal content knowing that no one else can access your information, similar to how encryption works on WhatsApp.</p></blockquote><p>Even nothing in this sentence is accurate. Your stupid bot has nothing to do with privacy and security, nor your WhatsApp shit.</p><blockquote><p>I predict that this will not only lead to much greater economic growth, but also more employment over time rather than less.</p></blockquote><p>We call it <em>assume</em> not <em>predict</em>.</p><blockquote><p>Everyone will have free or affordable access to these tools.</p></blockquote><p>You mean the cost of destroying open web?</p><blockquote><p>[……] to avoiding government tyranny and surveillance, ensuring the US and democratic countries lead,</p></blockquote><p>I think latters can be categorized by the formers.</p><blockquote><p>People and institutions with competing interests naturally check and balance each other to lead towards positive outcomes.</p></blockquote><p>Yes, but the actual competition you involve in is not this positive competition you are talking about.</p><blockquote><p>As a thought experiment, imagine only one person had a superintelligent lawyer. They would have an unfair advantage in court</p></blockquote><p>Regarding how stupid AI tools can be on laws, I would love to say a person with a superdumb lawyer is doomed.</p><blockquote><p>Similarly, if one person alone had a cybersecurity superintelligence, they could likely break into almost any technical system and the world would be much less secure than today.</p></blockquote><p>Nah you are wrong. Meta AI bots caused cybersecurity problems. You don't remember that?</p><hr><p>Well I don't want to elaborate that much on Gen-LLM tools in general because that's too complicated. I just feel like talking shit back to Meta and its AI philosophy is funny, especially after knowing what they have done in the past. Haha.</p><p></p></div><hr><div class="diary-entry">17:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M00N97EC7CJNKQEEZG04RB8J" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>买了个垫筷子的鲸。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M00N8FH98S8P8QPDZAA1YEA4.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">17:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M00P1699N6BXJ4W1B6HXJA5S" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>原来年初 TikTok 上有个 <em>becoming Chinese</em> 风潮。大致是将主流人群对中国文化的「理解」变成文化符号，然后开始说自己成为了中国人，或者确诊成了中国人。给「理解」加引号的理由是，近乎都是刻板印象，很二货。</p><p>作为回应，海外华人表示这很不舒服，因为那些刻板印象都是过去他们被歧视的点，现在忽然摇身一变成了主流文化的全新小众爱好。</p><p>不过远在中国的中国人，竟有人狭隘地认为这是文化输出成功了，并感到开心…… 真是无言以对。</p><p></p><blockquote class="diary-thread-reply">18:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M00R3XTR3N65XBT26B3GFYYT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>怎么还有 25 美元联名款火锅底料然后大言不惭说自己是首创 hotpot bomb……</p><p>关于整个风潮，我看的视频是这个：</p><ul><li><a href="https://youtube.com/watch?v=jDEY6pgDDPw" rel="nofollow noreferrer noopener" target="_blank">https://youtube.com/watch?v=jDEY6pgDDPw</a> 自行改域名！</li><li>BiliBili 双语字幕版 <a href="https://www.bilibili.com/video/BV1X3XjBeEDM" rel="nofollow noreferrer noopener" target="_blank">https://www.bilibili.com/video/BV1X3XjBeEDM</a></li></ul><p></p></blockquote></div><hr><div class="diary-entry">18:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M00RTAK8YJ89M91VWFTZ6BSS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>病还没有完全好但周末出门应该没问题。鼻子差不多快恢复到过去的状况了，就是口腔内时不时还有黏糊感，怀疑是鼻涕倒流。</p><p>总之依旧在家里待着，所以在研究家里这台 24 / 7 在跑的 PC 能不能跑点 VPS 跑不了的服务。</p><p></p><blockquote class="diary-thread-reply">19:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M00VHDTYB4CJTJTVTBD18A7P" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>呵呵呵呵跑起来了呵呵呵呵…… 这就是 Headscale 的强大呵呵呵呵……</p><p>好像只说「呵呵」会显得冷酷、嘲讽、其实很生气但要装作没事人一样。但多了之后就会显得像个阴湿的神经病。</p><p>呵呵呵呵呵呵……</p><p></p><blockquote class="diary-thread-reply">21:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0148ZS4FG1W4FB0A795CAR4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>把 Forgejo 迁移到 PC 上了。访问还是正常访问，原理就是 Headscale 大法。</p><p>接下来把有的没的拉到 PC 上，顺便再托管一些有的没的的东西。其实有考虑跑一些纯公益向的软件给别人用，但那样要考虑更多的安全性。</p><p></p><blockquote class="diary-thread-reply">08-15 03:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M01RV1MYT0KC8FMJSZD5Q9W7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>装了 Authelia，可以好好保护我的一些私人服务。</p><p></p><blockquote class="diary-thread-reply">08-15 05:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M01X4QKSYRYJ5MGMJ4WWEVRY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>让 Authelia 保护下 Beszel 当作测试。不过过了 Authelia 再登陆 Beszel 却无法正常登陆。去 GitHub Issues 上看发现是 Authelia <code>forward-auth</code> 端点会默认把请求的 <code>Authorization</code> 头当作 Basic / Bearer 头认证解析，而 Beszel 正好不是、用的是 PocketBase，所以 Authelia 解析失败然后报错不让请求过了。</p><p>解决方法是让那个端点认 session cookie，只需要在 <code>configuration.yml</code> 里加上：</p><pre><code class="language-yaml">server:    endpoints:        authz:            forward-auth:                implementation: 'ForwardAuth'                authn_strategies:                  - name: 'CookieSession'</code></pre><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">08-15 06:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0208ET4C1H0AM6M622G3RVS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>装了 ntfy、Uptime Kuma 和 BentoPDF。</p><p>关于 ntfy 和 Uptime Kuma 还在探索中…… 后者可以用前者发通知，除此之外还能用…… Google Sheets 什么鬼！</p><p>BentoPDF 是只在客户端上编辑 PDF 的软件，功能很多。地址目前在 pdf.cytrogen.icu 可以任意使用。</p><p></p></blockquote><blockquote class="diary-thread-reply">08-16 04:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M04CBCD2NGV6K532DXMBKFCQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>顺便给 Forgejo 加了 Actions，因为之前放在 VPS 上实在是不指望它能跑工作流。现在 Forgejo 在本地机器，工作流啥的跑起来！我睡觉了你也得跑！</p><p>给 Stalwart 库加了个 Trivy 的工作流，可以扫描依赖然后报漏洞。跑成功后确实找到些已存在补丁的漏洞，修修修。</p><p></p></blockquote><blockquote class="diary-thread-reply">08-16 10:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0538ZXAPGYZGDNEMZ63ZJN4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>装了 Dawarich，可以代替 Google Timeline 虽然我不用，不过位置追踪我挺想要的一直。Immich 有个图片地图功能不过那个需要拍照才能用。</p><p>手机上则安装 OwnTracks 连接服务器。</p><p>安装时意识到手机里的软件又变得太多了，还得再清理一次不用的。系统能够归档 3 个月不用的软件，但我不清楚它说的「归档」是什么意思？</p><p></p></blockquote><blockquote class="diary-thread-reply">08-17 06:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0756Y1VCGDQT5VPD6Q2X7D0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>装了 MeTube 和 Jellyfin。</p><p>目前还在探索中因为我很少下载视频文件。</p><p></p></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">18:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M00SGW3PCFX1Q3NJ90QFWHET" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://youtu.be/D4XG2xfUzuo" rel="nofollow noreferrer noopener" target="_blank">https://youtu.be/D4XG2xfUzuo</a></p><p>I didn't know <em>Ding Dong Song</em> has an origin: this <em>Tralala</em> by Phil and Company.</p><p>The lyrics are almost the same, but the vibe is totally different!</p><p></p></div><hr><div class="diary-entry">19:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M00VSNTZA3JJ76EZMZ61ACJS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我有点后悔安装 Truecaller 了。它有很多广告，软件内居然有个特么的社区，然后电话挂掉也有死广告。我还不能关掉它的广告通知。</p><p>但我还是很需要有个软件能在电话过来之前告诉我这是诈骗还是 business…… 归根结底还是不想要接电话。我觉得提前给我发 mailbox 然后我打回去才是好文明！</p><p></p><blockquote class="diary-thread-reply">08-17 01:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M06M30W6PWVN5KRVA410E6Q0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我把 Truecaller 干掉了因为我实在受不了打个电话还有广告出现在屏幕上的感受。</p><p>目前的方案是 Spamblocker Extended + Fossify Phone，都是 F-droid 可以安装的。</p><p>Spamblocker Extended： <a href="https://f-droid.org/packages/dev.kerballone.spamblocker" rel="nofollow noreferrer noopener" target="_blank">https://f-droid.org/packages/dev.kerballone.spamblocker</a></p><p>Fossify Phone： <a href="https://f-droid.org/packages/org.fossify.phone" rel="nofollow noreferrer noopener" target="_blank">https://f-droid.org/packages/org.fossify.phone</a></p><p>短信只能用 Google Messages 因为 RCS。</p><p>大致扫了眼 Fossify 发现软件还挺多。</p><p></p></blockquote></div><hr><div class="diary-entry">20:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0105F73HJ064EYH4DC07ECT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在 BiliBili 上看视频。</p><p>弹幕：「美国也有垃圾袋？」</p><p>wtf bro</p><p></p></div><hr><div class="diary-entry">23:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M01BDF78WHVVSC856WQR1C6A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我很活该生病。我现在在煮面，然后在厨房的柜子里看到了泡面，我想的是「病好了我要吃很多魔芋爽和泡面」。</p><p>因为「喜欢吃垃圾食品」是室友对我的刻板印象 —— 她认为的垃圾食品也包括只有碳水的一餐 —— 所以我最开始生病那几天，她为了让我从床上下来然后启动扫地机器人，竟拿了包康师傅红烧牛肉面出来然后开始「嘬嘬嘬」！就算是我，病成那样也不愿意吃泡面啊！</p><p></p></div></details><details data-group="diary_sections"><summary>八月十五日</summary><div class="diary-entry">00:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M01C5B9ZQN4263C44EXHM594" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我嫉妒心很强，因为很自傲。我会嫉妒我很讨厌的人有着我想要的特质，例如直接否定别人的观点并且强行套用自己的世界观。有时候我很需要这种能力，但从来都是讨厌的人对我用。</p><p>所以我经常很好奇他们是怎么做到的？尽管这些能力也是我讨厌他们的理由之一。看到别人说了我觉得不对的话，我会站出来大喊 <em>objection!</em> 吗？我做不到。</p><p>但是他们就会；为什么？他们怎么敢一直发表自己的愚见、欲望，宛如那是世界的真理的？</p><p></p></div><hr><div class="diary-entry">00:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M01CM9XKPJ43P8X9D4BSH03M" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>崩溃了吃煮好的鸡腿呢一咬下去「噗呲」一下射出血。</p><p>真是热血沸腾啊。</p><p></p></div><hr><div class="diary-entry">00:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M01D7SSNY1BYXJAZGTFXHATX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我每次坐 MTA 地铁遇到停车的时候，都会想能不能有这样的恐怖游戏，像 FNAF 4 那样。</p><p>主角被卡在一个废弃的车厢里，除了该车厢外没有别的东西了，不过考虑到合理性应该还有个车头。车厢在废弃的隧道中，黑不溜秋，只有车厢里亮着灯。</p><p>车厢的门都是怪物可以进来的地方。主角要拿着手电筒闪走它们。</p><p>之前 Godot 刚出现的时候，我就有尝试用它做一款 FNAF 二创游戏。不过只做了简单的界面互动、开关监控，就不准做了。因为我背景用的是自己家，室友不让 233</p><p>我玩 FNAF 类游戏没有那么多，因为我玩游戏很烂～但我有的时候喜欢看别人玩，看看别人怪物 AI 是什么机制，觉得蛮有意思的。</p><p></p><blockquote class="diary-thread-reply">00:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M01DJ4YCF101HVNS640YRAC3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友不让的另一点是那款游戏的怪物就是她。她有个让我觉得很像变态杀人魔会戴的面具，戴上去很适合当成变态杀人魔。我拍了一组她戴面具、在家里的照片。编辑过后的成片让她觉得有点恐怖，尤其是会觉得家里很恐怖，所以不让。</p><p>FNAF 1 里有个动画是 Foxy 从大厅穿过走廊跑向监控室。我想要复刻一个，这需要室友从楼下跑到楼上，然后我站在角落录下来。但她不乐意，所以作罢。</p><p></p></blockquote></div><hr><div class="diary-entry">00:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M01DTQEEK7A6SEQTVEKKYAE1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我小时候跟着大人去了一座山，我也不记得是哪里、什么山，也有可能是我在做梦、有了虚假记忆。总之那天很黑，那条街上有家紫色灯的店，专门卖恐怖的东西，比如巫毒娃娃、骷髅头什么的。印象里，老板还是向导还是员工是侏儒，矮矮的。</p><p>之后一次生日，有人送了我个很丑的木头娃娃，眼睛瞪得溜圆，嘴巴被缝上了，头发应该是脏辫？它现在是没了、不知道去了哪儿，不过小时候还算喜欢它。</p><p>我现在怀疑那会儿带我去卖恐怖用品店的，跟送我这娃娃的是同个人。</p><p></p><blockquote class="diary-thread-reply">00:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M01ED99NYMXFHCAAYJQA4C34" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我小时候最喜欢的玩具：</p><ul><li>可以变成蛋也可以变成恐龙的玩具。记得骷髅龙很稀有，最后终于是在画画课旁边的小卖部买到了！但同一年老子就特么出国了，骷髅龙应该是让渡给了其他人</li><li>一只兔子玩偶，戴了围巾，肚子上是根萝卜</li><li>方特乐园里的龙背包，虽然我从来没有去过方特乐园</li><li>恐龙酸奶的盖子</li><li>赛尔号塑料小公仔，还有宝可梦的</li><li>一个牛角恐龙的玩具</li></ul><p></p><blockquote class="diary-thread-reply"> 01:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M01F2Q2YEBDJX4DTDDSZEZ2V" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想要找一些图片，不过只找到了恐龙酸奶。</p><p>原来是小洋人跟恐龙总动员。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M01F2FPSN9CCT32FCEH23NKV.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">01:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M01FAJ80S97J5ZRCX36BWQHT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说到吃的，小时候很喜欢这个。</p><p>嗯应该是这个吧……？总之是个熊猫形状，然后巧克力味道。</p><p>图片来源于 <a href="https://www.sina.cn/news/detail/4385333418427933.html" rel="nofollow noreferrer noopener" target="_blank">https://www.sina.cn/news/detail/4385333418427933.html</a></p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M01F9PJASH4TE78RC919031S.png" alt="" loading="lazy"></figure></blockquote></blockquote><blockquote class="diary-thread-reply">08-16 21:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M069CNN11QHKBA5TDY2FY2XC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>翻到初中玩的锁。</p><p>左边是解开的，其中中间那是解开后放不回去的，理解还不够透彻。</p><p>右边俩是还没解开的。</p><p>玩法我的感觉是「口对口」，然后就能打开了。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M069AY0NVS6CZBZC7RYVNF8D.jpeg" alt="" loading="lazy"></figure></blockquote></blockquote></div><hr><div class="diary-entry">03:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M01P9ZPZ271MW6W803NP97E9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>买前：5 块钱的相机！不体验一下吗！</p><p>买后：知道为什么 5 块钱了。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M01P9QQ84VRYC9M0BT549ZX9.jpeg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M01P9XNS1X761CB6YKDKYFKM.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">04:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M01SFCW5HBP2K0W9BZA6FKVN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>好好笑它跟我几个月前分享的妹妹的便宜相机共享同个系统。</p><p>好便宜的系统能不能拿什么覆盖掉啊。看着好难受。</p><p></p><blockquote class="diary-thread-reply">04:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M01W5KZY7QFCDMG7K8M1WQ53" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这是它的软件系统。</p><p>这是什么诡异的分辨率。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M01W51S73DFFW3C0YSQQ5G2S.jpeg" alt="" loading="lazy"></figure></blockquote></blockquote></div><hr><div class="diary-entry">15:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M031V8CWCPK2EN2SWMXR8PFW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>很多事情不需要用 Board 发也可以吧。</p><p>这就引导我开始想 Board 到底是什么、发它的目的还有标准是什么……</p><p></p></div><hr><div class="diary-entry">16:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M032KA3QNNAWGCXFNMJT4ED0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>久违更新了下 Floorp 发现多了个 VPN 功能。</p><p>因为 Floorp 只是调了默认设置、多加了点功能的 Firefox，所以 AI 功能依然存在，只是改成了 opt-in。</p><p>就这样吧。Me agent lazy ass!</p><p></p><blockquote class="diary-thread-reply">16:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M032XS9E9A46V4GH01T2HFJE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我没有认真探索过 Floorp 其实…… 就像我这个月才开始探索 FreshRSS 那样。Floorp 的垂直标签栏应该继承于 Firefox？不过我不习惯用它。</p><p>还有鼠标手势，不知道好不好用。</p><p></p></blockquote></div><hr><div class="diary-entry">16:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M033C1BJR0NFTD793Z3C64SF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://specification.website/" rel="nofollow noreferrer noopener" target="_blank">https://specification.website/</a></p><p>让自己的网站变得更好。</p><p>可以跳过 SEO 和 Agent Readiness 部分，只取精华。</p><p></p></div><hr><div class="diary-entry">16:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M033YV4PW6ZKR3QK6JKDF9FK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>BlogBlog 同乐会这个月的主题不是「一期一会」嘛，我理解的意思是「这辈子只会发生一次」。但我想不出来也不打算为此写篇文章⸺因为我的博客魂在随着时间和精力的消逝而削弱⸺不过还是记录下来好了。</p><p>总之跟室友聊了这个主题。她想事情会钻牛角尖，所以会拼命去想「这辈子『一定』仅会发生一次」的事情。我看到有篇投稿记得是在美洲大平原还是沙漠还是哪里旅行然后想吃拉面结果发现周围真的有拉面店，就拿它做例子跟室友说也可以这样想啊。但她说她的理解就是那样，按照她的理解在沙漠里吃拉面是可以再做一次的事情，所以不算「一期一会」。她觉得得是在绝对不会出现 American woodcock 的时候却看到一对在飞才算「一期一会」…… 之后我们就只是在聊这个词的含义。</p><p></p></div><hr><div class="diary-entry">17:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M036M8GK3BSPK1BNWK4BTKJW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>原来可以禁用无法卸载的 app。我把 YouTube 禁用了，然后让 LibreTube 接管 YouTube 域名的转向。</p><p>Motorola 这个系统依赖 Google 也太重了吧。最开始用还会觉得「哇哦好方便」后面就会想「YouTube Music 都不让卸载是在闹哪样」。</p><p></p></div><hr><div class="diary-entry">18:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M039DRN6DDS90QGMM92C6MNP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>依旧是室友做的。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M039D51PWKYBYNHZJHSH1EXD.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">19:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M03F13M59G3N4EWTCW5RFQZX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>探索我这个 Motorola 手机系统自带的相机软件。</p><p>发现除了经常被人拿出来说的晃一晃开相机、折叠一半变成摄像机外，还有看掌心自动拍摄、大头贴等功能。</p><p>也有可能已经是别的系统玩烂的东西啦，不过我看到还是觉得很新鲜。</p><p></p><blockquote class="diary-thread-reply">08-17 01:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M06N4K205YPE8R9NQV5F281G" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这手机真花哨，功能挺多的，不过都是为了出好看的片或者让手机看起来好看。小折叠的方向感觉就是如此了。Razr 系列往精致小女生路线走。</p><p>可以让折叠的手机一边播放音乐一边假装自己是个磁带机。</p><p></p></blockquote><blockquote class="diary-thread-reply">08-18 17:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0AZYF6R69BCQ42Y0WC4WJ1M" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Group shot 会根据框内的人头，拍下多张，然后截取所有人最佳的面部表现，拼成最完美的一张图。</p><p>目前还在测试好不好用。</p><p></p></blockquote></div><hr><div class="diary-entry">20:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M03GB6CA7EMDB7DP25NA8Y33" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>蜜雪冰城好多人 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KWZ9MXJY3M0DZ2JK9TXP.png" alt=":neocat_melt_3:" loading="lazy">​ 仔细一看发现做饮料的机子在别的品牌那儿也见过，应该是同个型号。</p><p></p></div></details><details data-group="diary_sections"><summary>八月十六日</summary><div class="diary-entry">02:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M047R1NC8X4E77ZBD24VZGP6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://invidious.nerdvpn.de/Rfbj2YgqtLM" rel="nofollow noreferrer noopener" target="_blank">https://invidious.nerdvpn.de/Rfbj2YgqtLM</a></p><p>Opossum eating broccoli.</p><p></p></div><hr><div class="diary-entry">03:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M048GXH18SVT110J640H4J0Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天出门，在湖南菜跟隔壁一家四川 + 广东菜系的餐厅之间犹豫不决。前者以前吃过，第一次吃很惊艳，之后吃感觉厨师换了贼难吃，但算是个保底选项；后者完全没有试过。最后选择试新。</p><p>担担面怎么是小菜啊。上来后看到份量很小，还真是「小」菜。不过味道挺不错，室友说添加了广东的梅菜，不错的创新。</p><p>室友分完面后我还没来得及拍照，所以只拍了到我盘子里的一点。不知道为啥每道菜里都放了上海青。今儿去 Trader Joe 看发现他们上海青是单个放塑料袋子里装，很诡异。</p><p>主食我很后悔我尝试了菠萝糖醋小排，超级腻、难吃。早知道吃农家小炒肉了。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M048DVW58YPJXDXCVKZR94EZ.jpeg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M048DW66Y788MPZ7MMSCJVPT.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">03:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M048PAFJDXTGDSQAKYNAHYGS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>他们家有趣的饮料菜单：什么是「液体猫薄荷」！</p><p>手冲咖啡没有「咖啡」二字，一下子没看懂什么意思囧。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M048M1MQE2VHTKKCSC2KHBTB.jpeg" alt="" loading="lazy"></figure></blockquote></div><hr><div class="diary-entry">03:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0490QHABVD65XT6188TXCA0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>WeWork 有时在扩展歌单上很棒。比如我听 <em>Just the Two of Us</em> 应该就是从那儿听来的～还有 <em>Loreta</em>。</p><p>不过部分地点的 community team 选歌品味极差！—— 当然是主观上的 —— 放烦人的 elevator music 就算了，有时候还突然蹦出来 Kpop 口水歌，哇真的烦炸！</p><p></p></div><hr><div class="diary-entry">03:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M049S7ADPHCR3FS3G9V4D55Y" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://invidious.nerdvpn.de/watch?v=bmrFsUuS-gk" rel="nofollow noreferrer noopener" target="_blank">https://invidious.nerdvpn.de/watch?v=bmrFsUuS-gk</a></p><p>Matt Dusk 对 <em>Mesmerizer</em> 的改编，变成了 60 年代的爵士乐风格，顺便是英语的。</p><p>原曲主旋律我还是蛮喜欢的但必须要分出来些音轨，否则直接放原曲我耳朵会死掉。</p><p></p></div><hr><div class="diary-entry">03:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M04A3SRJVVNC4YX8K8AH724J" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://invidious.nerdvpn.de/YMsv6iRhmTg" rel="nofollow noreferrer noopener" target="_blank">https://invidious.nerdvpn.de/YMsv6iRhmTg</a></p><p><em>Just the Two of Us</em> 虽然一共有五个人。主唱音色真好听！</p><p></p></div><hr><div class="diary-entry">03:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M04ARXPMZCVKH5SASPK7Q50C" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>小傻子室友。3 盒草莓 5 块钱；2 盒蓝莓 4 块钱，3 盒 5 块钱。</p><p>我们拿 3 草莓 2 蓝莓，怎么成 10 块钱了。回家清点买的东西我才发现拿的 2 盒蓝莓而不是 3 盒。</p><p>唉那 1 块钱就当给小贩老头的了。</p><p></p></div><hr><div class="diary-entry">03:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M04AYZAM0B448VZMHV2YZHP5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前一直觉得 Teso 是个卖盲盒化妆品的潮玩店，每次进去就逛不买。今天进去才发现有很多零食打折，虽然我都不咋吃，但还是买了这个海带，最后是 3 块多。</p><p>不过人还在咳嗽，就买这个，真是活该生病我。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M04AWJ05BTSKVFX505NACEDT.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">03:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M04B54WHCYWZG6YGWDN6ZWDN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说到零食，我感觉我喜欢的都是：</p><ol><li>味儿重，如魔芋爽</li><li>嚼下去有种感觉，就是吃海带、裙带菜、笋的感觉，嗯！</li></ol><p>不喜欢的有：</p><ol><li>膨化食品，尤其是 Cheetos、Doritos、Takis</li><li> 辣条</li><li>不知道还有什么零食了因为我不咋吃</li></ol><p></p></blockquote></div><hr><div class="diary-entry">04:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M04DT0K8D4ED7GKYN6GBHYFR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看着很凶的 pancake、waffle 粉！</p><p>最后当然是没有买，呵呵呵呵…… 总是有更便宜的选择……</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M04DS22YAK9HF1AMRARQKYPS.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">04:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M04DWZDK10T5D2TTNXECX1ST" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>匹克猫被两个哑铃关住了。</p><p>所以纸箱四个面可以简化成两个面。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M04DW9EWD2Q5RW6A2H08PMEZ.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">10:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M052G61VHRY39KG5DKE019PB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>你这家伙儿在说什么呢。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M052FSMA4QZ836A3VPWEZAKC.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">11:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M053NYDTZSHABWW9JTWQ9X25" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p></p><ol><li> 请问把大象放进冰箱里，需要几步？</li><li>请问放把长颈鹿放进冰箱里，需要几步？</li><li>请问狮子大王开会，所有动物都去了，但有一个动物没去，那请问是谁？</li><li>与此同时，小明正在游过鳄鱼河，一块巨石从飞机上落了下来，小明游过了鳄鱼河却没有受到鳄鱼的攻击，请问这是为什么？</li><li>请问为什么小明游过了鳄鱼河后还是死了？</li></ol><p>好像是小时候玩的版本。</p><p></p></div><hr><div class="diary-entry">11:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M054JH8V4BMGAPH40NX259QQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天在外面走路，不知道为什么手臂肌肉开始酸痛。</p><p>室友：<em>We use legs to walk you know</em></p><p>这我当然知道啊！</p><p></p></div><hr><div class="diary-entry">11:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M05535V4SW4KG1PDX2RBT765" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>关于这些袜子，我还有话说。</p><p>它们因为过太久了，很多配对变成了单只，但我懒得买新，所以会把花纹不同的单只随机搭配。</p><p>于是我很多时候在穿花纹、颜色不同的袜子。</p><p>花纹和颜色什么的，反正能穿就行啦。如果还要因为少一只而买新的，实在是不划算。</p><p></p><blockquote class="diary-thread-reply">11:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M055C868JFGANZ90MXZ26FQ0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我想到室友之前跟我讲的事情：美国牙医为什么那么赚钱？理由是美国社会喜欢露齿笑，而露齿笑需要干净、洁白、整齐的牙齿。所以大家小时候都做过钢牙鲨。</p><p>我以前也整过牙齿不过后来又被我整坏了，相当于白整。当时整牙齿好痛，每次换线都要磕止痛药，实在是不喜欢。未来可能会重新去整，也可能不再管它，随便了。</p><p>想到牙医是因为我开始想袜子花纹还有颜色是不是为了让消费者频繁去买新的来凑对儿。</p><p></p></blockquote></div><hr><div class="diary-entry">11:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0566VH0NJ1HAZFQ3HBZ4M13" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有个亲戚来美旅游，虽然专业领域上差不多但目前对他印象不太好，不是很想长时间接触…… 我不是很喜欢线下聊技术的东西主要是。你就算跟我讲算法啥的我也听不懂啦。</p><p></p><blockquote class="diary-thread-reply">08-17 21:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M08RFC7QYR5Y2EVDD399W2QV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>稍微接触了下感觉还好。带的俩小孩也没有说一直在捧着手机看、满口烂梗，好感度上升中。</p><p>路过 911 纪念馆三个人还对历史很感兴趣，搜讲解视频看。</p><p></p></blockquote></div><hr><div class="diary-entry">11:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M056MFWZXGYSBTFBA8RNXW5C" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想起以前天天坐渡轮通勤的时候。</p><p>那时候室友跟我家里闹掰了，我家里人变很讨厌她。不过我跟她关系还是很好，所以经常出门找她。</p><p>一次因为我要迟到，我就花钱坐 4 块钱的小渡轮，开得更快。然后坐上去后母亲就打电话过来骂我，因为她监控到我的卡里少了 4 块钱，所以推断出我坐了小渡轮而不是免费的大渡轮。</p><p>她骂道：「你就那么喜欢那个女人吗！」</p><p>现在想起来只会觉得这是什么诡异台词，搞得我像是被别人抢走的丈夫。</p><p>我经常想要去理解母亲对我同龄人的恶意从何而来。诸如辱骂还是初中生的我朋友是小姐、鸡，亦或者是攻击容貌。对她而言我也只是个所有物，因为我从她那儿来，然后「母亲永远都是无私的」—— 疑问句。</p><p>父亲因为工作而缺席也是个问题。不过他因为太缺席了，所以很多时候讲父母我会忘了他。</p><p></p></div><hr><div class="diary-entry">12:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M057ZPGJDZ2A4V84GED9JZTG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天聊天聊到 toxic ex，因为我不太懂这描述了什么样的人。室友说可以理解成「不健康且上瘾的」—— 好的明白了。</p><p>Toxic ex 的印象可以有分手后依然在死缠烂打，或者诋毁对方。</p><p>我就想起来之前被别人说是 toxic ex。室友说是对方傻逼，那个烂人才是最 toxic 的。</p><p>聊到恋爱观。每个人的恋爱观都不同，再加上不健康的心理之普遍，我们从恋爱中尝试寻求的东西也不同。朋友们不济有着知道自己恋爱观扭曲所以不谈恋爱以拯救世界的，也有明知自己恋爱观扭曲也要执行到底的。</p><p>我的一暴论是很多人谈恋爱只是为了有人能陪伴在自己身边。谈婚论嫁，现在的年轻人会想那么远么？身边统计学告诉我能想到这儿的同龄人都不知道「责任」二字怎么写，只是想要做爱做到爽罢了。</p><p></p></div><hr><div class="diary-entry">12:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M05A3EWP56PNP6KC1RQHG1SZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>关于脖子处的纽扣要不要扣上。</p><p>母亲：你为什么这么保守非要扣上（我特么冷啊）。然后上手解开，跟身边人说「我女儿就是这样很保守」—— 你开心就好了！</p><p>室友：你为什么解开最上面的纽扣（我特么热啊），是想要勾引我吗宝贝（呕）</p><p></p></div><hr><div class="diary-entry">15:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M05J5KDMV5KJ6KCB2ZTD7X7X" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>数周前在别人生日派对上，因为太无聊了所以玩起了 Pokemon Go 顺便把周遭的道馆推掉弄成蓝色阵营的。</p><p>比我小几岁的应该要叫表弟的家伙儿过来，然后说现在都 2026 年了谁还玩 Pokemon Go 啊。</p><p>我不就在你面前玩吗，讨厌！</p><p>游戏也不该随着潮流去玩吧。</p><p></p></div><hr><div class="diary-entry">15:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M05K95JDCVARD546Q91P9ESX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://f-droid.org/packages/net.bible.android.activity" rel="nofollow noreferrer noopener" target="_blank">https://f-droid.org/packages/net.bible.android.activity</a></p><p>阅读圣经用的软件，因为下载文档很方便所以怪意外的。</p><p></p></div><hr><div class="diary-entry">17:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M05TCBCQTSA6BBPBDSCE130Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打开 Fediverse 客户端软件。</p><p>忘了自己要发什么。</p><p>关闭 Fediverse 客户端软件。</p><p></p><blockquote class="diary-thread-reply">18:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M05W47KR02JJ346Y8K0WQD6E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>啊哈想起来了。</p><p>今天去了躺教会，然后免费拿了本 outline 书。里面有牧师还是讲道对某某主题、圣经里某些内容的个人见解。</p><p>《约伯记》也就是 <em>Book of Job</em>（此 Job 念法非彼 job 念法）是圣经里能够列到世界文学杰作的一卷，我在文学课时也学到了这卷。当时的解读还是简单的「我们无法理解上位生物的想法和行为」，这次再看对 Job 本人多了些看法。</p><p>Outline 书里写道，现在的教徒们仅是在复读圣经里的内容，仅是「知道」了大道理，却无法「理解」乃至「实践」它。对于 Job 也是一样。他被 Satan 干到什么都失去了，也对上帝失去了信心，并和三位朋友（代表了传统的神学思想，即你过得惨是你干了坏事、多反思反思自己）大辩特辩，噼里啪啦，最后上帝显形暗示 Job 根本无法理解上帝的智慧和作为。Job 明白这一点后不再怀疑上帝，原本失去的也加倍获得 —— 但想象一下依然很吓人啊有没有。你的家人全都死光了之后又来了双倍新的。</p><p>作者表示，我们有旧的阶段和新的阶段，上帝有独生子和长子：我们要从旧的阶段（Adam）转变成新的阶段（Christ）—— 我在想这是不是也是旧约到新约的转变？耶和华的形象在两者之间也有很大的区别 —— 也要让上帝从有独生子转变成有长子。独生子我们知道在基督教里指的是耶稣本稣，但长子是什么情况 —— 请在这里短暂地忘记洪秀全！—— 如果只有耶稣一个的话，那他指定是独生子了。但如果他有多个弟弟，那他不就成了长子？新的阶段指的正是我们成为基督模样的人、他的弟弟妹妹，而不是简单的上帝的子民。</p><p>所以我对宗教的兴趣更像是对文学解读的兴趣……</p><p></p></blockquote></div><hr><div class="diary-entry">19:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0602VF7A6Q9RVZV42GK5EAP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>关于该教会，今天母亲带来的另一个人给出了全新的思考角度：</p><ol><li>楼像是住宅楼，装修后却没有写明能装多少人，人也明显超标，有安全隐患</li><li>更像是召会，而非教会，所以没有牧师</li></ol><p>所以他担心是家庭教会、搞邪教 —— 主要是之前我们待的教会（浸信会）是家庭教会，被搞得很惨。召会因为没有教会那么常见，体验下来很陌生。</p><p>之后他们还要找研究这东西的传道然后大聊特聊。</p><p>好吧我都不懂。还有圣餐这些东西他们也觉得怪怪的。</p><p></p><blockquote class="diary-thread-reply">20:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M063KBYRZQ481HTBX1RJQ909" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JDVGDYQWMMBRBXVTZFPD.png" alt=":neocat_googly_blep:" loading="lazy">​ 好奇了，想写篇基督教相关的文章。</p><p></p></blockquote></div><hr><div class="diary-entry">22:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M06CAQ6RVSDADH7G3YZX9ZNK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>HP 的打印机很糟糕！</p><p></p></div><hr><div class="diary-entry">23:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M06F6Y4P0CRS27SDJF5RWH98" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>继免费咨询顾问，现如今又有朋友辞去打工想让我去取工资条理由是他觉得自己过去拿尴尬。</p><p>你们都觉得时间成本不是成本吗。</p><p></p></div></details><details data-group="diary_sections"><summary>八月十七日</summary><div class="diary-entry">01:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M06PC58NY8XHKY9QZ0RXSMWB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天出门时发现经常能在路边看到个二维码，上面会写能激起人们负面情绪以至于想要扫描的字儿 —— 我的理解是如此啦。</p><p>其中有句话让我很感兴趣：</p><blockquote><p>Your algorithm is prison.</p></blockquote><p>哦天没想到我能在美国纽约州纽约市曼哈顿区看到这种发言，让我好感动，二维码背后肯定是什么鼓励人们离开算法和围墙花园的内容吧。</p><p>结果是个特么的 Spotify 链接。</p><p></p></div><hr><div class="diary-entry">01:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M06PKXYX9VJQJK3ZHR1TNBF0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>嗨呀裤子上收腰带的那些小环带子真好用，可以别耳机别钢笔，腰带里感觉还能塞个小本子。遛狗还能别便便纸、别小零食。</p><p>你是怎么发现我是女同的！</p><p></p></div><hr><div class="diary-entry">02:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M06RV6CENYBY19JFK5KVK5ZB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>洗了匹克猫，身上负伤惨重。</p><p></p></div><hr><div class="diary-entry">03:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M06TZ7EJX2CSKX5WXQY8W6G8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我找到了网上大神逆向该小相机的文章，居然芯片都是同个。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M06TXWB2A813J7KV8W3NYQHH.jpeg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M06TXWH8K2J4G82N6CNX78RX.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">05:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M071X6V0DPGF46NB2RQK17SH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>很崩溃因为：</p><ul><li>万用表只找到了表，没有线。东西都放一个包的怎么会只有线不见了！</li><li>CH341A 在但 SOIC-8 夹子不见了。上次买它是为了读数码兽卡的数据，但东西甚至卡都放在一起，只有这个夹子不见了！</li></ul><p></p><blockquote class="diary-thread-reply">08-23 23:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0RF0EQ8EHA5DBSVBNQSQQXZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>夹子到了。夹上去用 flashrom 拷 bin 文件到电脑上，用 Ghidra 狠狠翻它个底朝天。</p><p>好笑的是 Ghidra 自动分析出来的函数名一堆错字。</p><p>不过这个相机的代码跟我在网上看别人逆向的便宜相机代码都不太一样……</p><p></p><blockquote class="diary-thread-reply">08-23 23:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0RH1S14ZR3FTRH5VZMH168B" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友很热衷于收拾我的桌子。</p><p>所以这次回来我又找不到桌子上的 SD 卡了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">08-24 02:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0RS7X9H1D36PSZ83H0C87DD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>上网看了下一张 Micro SD 的价格。</p><p>不知道以前什么价格但我实在是不想要花 20 块钱在 32GB 的 Micro SD 上 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 以后找到了再折腾这个相机吧。</p><p></p><blockquote class="diary-thread-reply">08-24 02:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0RSMSFP58VFXB9ADNXDDX0P" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说完花 9 块钱买了个 8GB 的。</p><p></p><blockquote class="diary-thread-reply">08-24 22:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0TZ871GM66GEASJWEEFGHD9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这张卡虽然可以插到相机里使用，但配上它自带的 SD 转换器、插到我的笔记本电脑里，它就只能读取、不能写了。</p><p>我累了…… 不想折腾了。</p><p></p></blockquote></blockquote></blockquote><blockquote class="diary-thread-reply">08-25 01:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0V8ED75VK9SSJ2Y1M7WMB22" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我错了。我错怪室友了。这张 Micro SD 卡在我的工具箱里。</p><p>它也不是 32GB 的。对不起对不起。</p><p></p></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">15:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M083VS826R5ME2RE8763VF8N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天又要去奶奶滴做导游咯。</p><p>这种破地方到底有什么好玩的…… 怨气怨气怨气……</p><p></p><blockquote class="diary-thread-reply">08-18 01:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0978DWXJ39C1T4119V3A7XN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>纽约市真的好无聊。</p><p>不过之前久违去了躺书店，虽然没有找到感兴趣的作家的书，但找到一本作者探索纽约市并且拍照写下感想的书。挺厚的，照片拍得也很漂亮。</p><p><del>偷</del> 参考人家的散步路线然后探索下城市也挺不错。打卡这些景点无聊死了。</p><p></p><blockquote class="diary-thread-reply">08-18 02:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M09CKJPSS2F9KB1T2CB56MFY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>明天又又又又要去看大葱女神。</p><p>那其实是美国版初音未来。法国人很喜欢日本文化和初音未来所以弄了个大型手办送给美国。放在水上是因为本来打算让她 cos 深海少女。</p><p></p></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>八月十八日</summary><div class="diary-entry">02:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M09CPSTFBHYS5HQP4G47TKEF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Pico the Cat in my tote bag.</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M09CPE7YCW85KPKXZBR24TXW.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">12:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0AD0V257R8P926FFG70VFKC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近一直时间一直在被占用以至于感觉自己不配做自己的事情了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">13:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0AJCM8DQ28EM6FWBM5B1ZQJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我其实有很多东西要写，但我没有时间静下心来写，现在行程表也被家里人搞得一团糟、一直在周五才能重返自由安排时间的状态。</p><p>因为时间安排的不自由，我现在的思绪是断断续续的，甚至说不记得很多几天前的细节，只能靠拍照存个 checkpoint 然后后续有时间了再靠那个唤醒记忆。然而我和室友出门那天，用手机不多也没怎么拍照，导致我忘了很多我们聊过的话题！反观和家里人出门，拍照多了但全程近乎没有让我觉得有意思的话题可以在博客内展开，直接来说就是他们很无聊，让我只能在博客内夹一堆图片但没有有趣的文字 —— 这类文章你喜欢看吗？我反正不喜欢看。</p><p></p><blockquote class="diary-thread-reply">13:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0AJH4P2M3MZMMPWZ5QSJ6YJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>现在有了 Dawarich 和 OwnTracks 所以可以后台记录走过的路，搭配 Immich 还能看到当天拍的图是在哪儿拍的，不错不错。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">14:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0AN23T63Y1HBK5P6AKFDBV6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>背单肩包的坏处在于右肩会很难受。所以我打算换到左肩来承受压力，结果拿着包开始犯傻：怎么弄才能换到左肩？</p><p>最后想了半天弄好了。</p><p></p><blockquote class="diary-thread-reply">14:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0AN8NV0QR48Y0AGG4BE2AFD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说到左右。我骑踏板车是左脚放踏板、右脚蹬。我的逻辑是因为我右边是惯用的，那它出力不是很正常？结果家里人一直说这是左撇子的做法，右撇子应该右脚在踏板、左脚蹬。</p><p>唉，好麻烦，管你什么呢。</p><p></p></blockquote></div><hr><div class="diary-entry">15:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0AQ6XY6GWAMG8434MC59R3V" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在陪亲戚吃早茶 ing。还是不太习惯吃这个。话说他们都不点青菜啊。</p><p>啃牛仔骨塞牙了，急死我了。</p><p>他们在聊小孩子什么时候送来美国生活好，然后就聊两国之间教育上的差距…… 就像每个人在饭桌上说的那样。哗啦哗啦。</p><p></p><blockquote class="diary-thread-reply">16:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0AV3TA3WSVTFVQAKFBA5K63" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>聊到我。不知道他们上下文是什么，但我 BBA 计算机信息系统专业不代表我是学金融的啊，为啥一直说不要学自己不喜欢的专业。</p><p>接着是就业环境相关的事情：「你要多和 ChatGPT 聊天！多了解！」—— 说啥呢我了解过了。</p><p></p><blockquote class="diary-thread-reply">08-19 18:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0DK3P8KM02QK7PF229YJYM4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>再就是为啥老觉得做 web app 是做前端的啊，还跟我说「你要学 Java、数据库」。我的意思已经说很明白了，东西都是我来负责，整个 app 都是我做的，为什么一听到 web 想到的就是前端？然后是 Java 这个破玩意儿还是算了吧。你现在问 ChatGPT 它都不定会推荐 Java 了。</p><p>总之聊完感觉牛头不对马嘴，说来说去还是「换专业」，将计算机作为辅。我同个意思的话说出去他们还要连连摆手，说「不对不对」，但一细问就是「对的对的」。只是在浪费时间，根本没有人理解我在做什么、我的行业现在什么状况。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">17:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0AXTBBQJMEJV6AH4V3JCG1M" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Kagi Maps 有导航啦！</p><p></p></div><hr><div class="diary-entry">18:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0B2VJFHRGX39BMFP4V6239Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>久违去了下时代广场后给我的感觉是：我去，广告，好多广告，uBlock 救我啊！</p><p></p></div></details><details data-group="diary_sections"><summary>八月十九日</summary><div class="diary-entry">00:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0BQYXRZDW1SPCP05HRMD1YH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>关于 ChatGPT，这次回来惊奇发现所有人都在用它。亲戚在用，他儿子在问不知道什么 AI 工具的网站怎么访问正版 ChatGPT，我母亲拍了张照片然后问 ChatGPT 照片里的东西是什么，我父亲更不用说了⸺这家伙儿很久之前就在玩 ChatGPT。</p><p>他们尖叫着「你要多用 AI（实际上他们会说成 AR，不知道为什么）！」但我已经厌倦它了。使用它是烦躁的，我已经感受不到兴奋亦或者什么感觉很高的情绪。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">《思慕雪的热带鱼》剧透相关。</summary>        <div class="diary-cw-content">12:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0CZPDA1HSVGMYG22ZNV612P" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>重新再看一遍，之前追连载时很喜欢的一本漫画。</p><p>当时因为没有百合情节，所以郁闷了许久。这次重看有了不同的感想。</p><p>前面两个人的互动特别可爱。后来明显二人互动变少、开始出现忧郁的气氛，看着蛮难受的。</p><p>核心围绕着《山椒鱼》这篇短文以及「孤独」这个主题。当时我也拜读了《山椒鱼》，不过理解偏浅。漫画对于这篇的解读是，表面来看是山椒鱼关住了青蛙以不再孤独，实则二者都需要彼此以不再孤独。</p><p>另一个主题便是珍惜当下：寂寞的话就要告诉别人自己很寂寞。</p><p>小夏的山椒鱼好大一只好可爱，乔治鲨鱼也好可爱。</p><p></p></div>      </details></div><hr><div class="diary-entry">13:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0D28RJZSYEPG30VND7V4QVS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近要七夕了，我才知道。</p><p>节日和它们最初意义很多时候都不相同。</p><p>像牛郎织女的传说，我一直都看不明白为什么这样的东西是「爱情」的象征。日语课上学到过牛郎织女最初的故事，也就是二人都在天上工作、结婚后不工作了于是被天神惩罚。这一版比起说赞扬爱情，倒更像是强调社会身份。</p><p>现在中国的民间版本差不多是老牛怂恿牛郎偷织女衣服，或者牛郎去偷看织女洗澡（有病啊），导致织女被贬只能嫁给牛郎（有病啊）。王母娘娘想要拆散二人、带走织女（你做得好啊你做得好），于是划出银河。为了这莫名其妙的「爱情」喜鹊过来搭桥让两人每年七月七都会见上一面（真的会想要见吗）。</p><p>虽然我也不喜欢情人节，但我觉得背后 Saint Valentine 的故事更好接受一些……</p><p></p><blockquote class="diary-thread-reply">08-20 03:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0EJ6B2PH77A6KBEYS1Q7D6E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我想了个《新・牛郎织女》：</p><p>喜鹊因为没有历史所以常常被人们排挤在外。为此它们捏造出了牛郎织女的传说，并将自己强加到其中，自行编造出了喜鹊文化。</p><p>很久很久之后人们都相信了。</p><p></p></blockquote></div><hr><div class="diary-entry">14:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0D698MMCH8HSK6ZZF15JQ8K" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 给一篇博客留了个言然后后悔了。</p><p></p><blockquote class="diary-thread-reply">14:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0D78J0XS53T3GS15SYJJAZ9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我觉得待在自己的地盘做 RE 还是更好：一能满足自己的发言欲望，二是当事人看不到所以不会吵架。</p><p>缺点在于如果被当事人看到那就会认为是在阴湿地挂人，参考之前川流的事情。</p><p>川流的事情我所了解到的 —— 所以会有错误！—— 就是几个博主不满自己的博客网站被川流无告知收录，于是在 Fediverse 上一起聊这件事，还扒了川流站主的公开信息。之后他们发邮件给川流站主叫他不要放自己的 RSS 上去，引起后者不爽。接着便是双方之间的骂战、道歉、骂战、攻击彼此性别…… 当事博主还关闭了自己的 RSS，川流也把站关了并留下一段话说明 RSS 是公开信息凭什么不给我收录。</p><p>其中一个点在于「在 Fediverse 上讨论」算不算阴湿挂人？公开扒个人信息我是觉得过分了。这里的「公开」和「私人」实在是两个难以分清的概念……</p><p>还有个点在于独立博客收录、转载他人站点是否需要授权？实际上我先前也在想 links 页面是无授权转载他人的链接。说实话它维护起来真的很麻烦，虽然领地里的小房子村落设计我很喜欢，但未来估计还是撤掉为好。</p><p>这场战争最不重要的点是那几个博主是不是激进女权主义者 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 我觉得愿意以事论事的都想不到这儿。</p><p></p><blockquote class="diary-thread-reply">14:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0D7RBQNHAXETDJQ8ZGW2NEC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我所留言的内容也与女权主义相关。说来有趣，我于线下很乐意探讨相关的话题跟问题，但在中文互联网我的乐意程度有所下降。探究历史、社会为什么会是这个样子，以及它们产生的果是什么，很有趣，但例如室友在内的我身边的大部分人都坚信现在、主流就是最好的，不愿意和我延伸太多 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 尽管所有人都很痛苦。</p><p></p><blockquote class="diary-thread-reply">14:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0D8GDJVWSWGTSJJFEBGFP35" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>解读和解析的乐趣或许在于安心感。因为知道了背后的逻辑，所以不再神秘、不再恐怖。</p><p>标签化的又一问题便是它能够覆盖背后复杂的逻辑。最为邪恶的标签化是二元的部落主义：你是白人所以怎样怎样，你是有色人种所以怎样怎样；你是男人所以怎样怎样，你是女人所以怎样怎样…… 二元是懒惰的人类最喜欢的概念，因为不需要思考就能灵活运用，部落也是一样。</p><p>使用标签也可以给人们带来安心感，不过它往往是表面的。我不想要去理解你的逻辑，但我依然对「不理解」感到恐惧。最简单的方法是给对方贴标签，做出最浅的解析：你说这些话是因为你是某某部落。</p><p>我猜是这样的。我也在努力想些新的事情。因为过去提到过我对复述已知的内容而感到沮丧。</p><p></p><blockquote class="diary-thread-reply">08-20 22:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0GMC40SS6SG5KRH90QFNFBS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>意识到自己在标签化什么，且在探讨问题时使用了标签、先入为主，是个从 0 到 1 的一大步。</p><p>接着便是在探讨问题时使用真实、复杂的逻辑，就事论事。</p><p>之后去理解标签的存在、为什么存在。并将这些思考应用在帮助他人摆脱标签化上，例如做出更好的解释：为什么这是标签、刻板印象，为什么不能将其运用到讨论内……</p><p>「先入为主」是个很常见且深植于人们内心的有害想法，非常不利于讨论、连接。</p><p></p></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">15:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0D8WCQWJHX999RYWCVR1KMS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>语言好像个插件，什么环境就插拔用哪个。</p><p>比如我和室友在一起，说英语就会变差，说中文会很流利；和家里人在一起，说英语会变流利，说中文听上去像是 ABC，咬字都变差了。</p><p>好神奇。</p><p></p></div><hr><div class="diary-entry">15:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0D935CGKH1357AZEKNGW1A0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>亲戚小孩给我表演下三阶魔方速拧。真厉害！</p><p></p></div><hr><div class="diary-entry">16:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0DEN7Q23VXYX9KFEPT3R0PP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在睡觉的 Uber Eats 机器人。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M0DEN1QAZC1YPZ62GCC6N5BA.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">21:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0DZY4JN59V07NYA21MG5131" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>鲜少来纽约外的地方。首先发现的是各色的公交车还有共享单车。</p><p></p><blockquote class="diary-thread-reply">23:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0E6TZE01VY4V45C4BR7GAEH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这种逮着景点逛的逛法好无聊。</p><p>我被虫子咬了还。</p><p></p><blockquote class="diary-thread-reply">08-20 01:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0EC8FH9C21N12CNC1Q5NPE6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>宰客 Pho 店之很会吹自家菜单的华人老板娘，以及点单不看菜单只看图片的我母亲。</p><p>看到最终小票果不其然翻脸说「怎么这么贵」。</p><p>这和吃药不看说明书是一个性质。点单不看菜单 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 真是服了。</p><p></p><blockquote class="diary-thread-reply">08-20 01:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0EDZVB51BN0FMKNJ9DDP0M7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>她还问我为什么不买饮料给妹妹喝。</p><p>朋友你家易拉罐可乐 2.75 美元我是没钱花非要买你家的吗。</p><p>跑到隔壁 711 拿免费 Large Gulp 去了。虽然不咋好喝但够了。</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">08-20 12:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0FJ5Y7H12BKG28G5W1R5C9M" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>太好了这里的蚊子是不咋毒的小蚊子，现在已经不感觉痒了。</p><p>纽约岛上的巨型黑白条纹蚊子咬一下一个大包能痒一周 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 所以回父母家都不愿意在草丛旁待。草里还有邪恶的蜱虫跟跳蚤！</p><p></p></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>八月二十日</summary><div class="diary-entry">01:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0EE3HEP3JAA0J1KGXVYPW00" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我在副驾驶：你这个开得不好我要扣你分；你胆敢这么开，路考时这么弄直接不用考了知道吗；你走，你可以走，听我的；你不要走，你给我换道，你站错道了。</p><p>我在主驾驶：非常焦虑。</p><p>我在后座：晕车；大家都去死吧。</p><p></p><blockquote class="diary-thread-reply">02:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0EEF7B02PHPEKEYRJAGSPPH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我的一大不解：母亲非常倾向于让客人坐副驾驶。</p><p>OMG 你知道副驾驶多危险吗。你为什么要让不会辅助主驾驶的人坐副驾驶，然后两个人像个傻瓜一样尖叫「我要走哪条路」？副驾驶为什么叫副驾驶你知道为什么吗，你为什么要害客人、害自己？</p><p></p><blockquote class="diary-thread-reply">02:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0EHFVZMNVRK68C6TDEF52A7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我的新不解：开车不看路上的牌子，也不看导航。</p><p>于是我们过了民宿，还得倒头回来。路上过了个 stop sign，需要 yield 等行人过马路的也没有停下 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 我已经在窒息了。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">02:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0EEBZ5SBJ132SZCYDQ0J8CD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这些天出门给我的一大感想是 AI 生图的普及。真的是走到哪家店，哪家店的海报就是看得恶心的 AI 生成的图片。就连犄角旮旯的早茶店也是大荧幕上连续放 AI 图片。</p><p></p></div><hr><div class="diary-entry">02:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0EHQ5T70MWB9EFA884X4Q7Y" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我的新新一大不解：不选酒店非要选民宿。</p><p>两者其实价格差不多；酒店是套房，民宿是两层楼。但他们一直在说什么酒店更贵，你看价格啊！是一样的！酒店还提供免费饭呢！</p><p>到民宿一看傻眼了，到处都是不怕人的蚊子，我现在已经被咬了不知道多少个包。一关门出现一只比纽约那儿还要大的蟑螂，果断踩死，发现它还活着，绝望了。厨房里的餐具都很烂、破了角，连热水壶上都有着不明污渍…… 窗帘是透明的，外面的人想要看是可以看到里面的。后院的大门居然是假的门，一推就开，why！</p><p></p></div><hr><div class="diary-entry">12:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0FJMJH3FNE2G3H1TPA1VRX6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近有个感想，和他人沟通不要太「友好」，这里指的是害怕指出对方的一些事情会让对方感到不舒服。</p><p>我管你呢我就说就说就说。一个邪恶的人就此诞生…… 直到我未来什么时候被别人指责「你不要如此咄咄逼人！」吧。</p><p></p></div><hr><div class="diary-entry">13:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0FM932VZ449C5AJ2X7XGBG3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>亲戚吐槽他来美国旅游居然在看大熊猫、吃中餐。</p><p>我还没有亲眼见过大熊猫呢！</p><p>他们来的第一天我们请他们吃麦当劳垫肚子。其实那会儿可以改成去吃 Panda Express 折磨他们。给他们点 orange chicken，我自己美美吃西兰花还有 beijing beef。</p><p>符合中国人胃口的非中餐，有意大利菜还有墨西哥菜。但我鲜少跑到正经餐厅里去吃，考虑到意大利菜的意大利面多数都使用了番茄…… 我不喜欢番茄沙司、海鲜，我愿意吃奶油蘑菇培根的。</p><p>地中海菜应该也可以，不过我对它的认知仅限于上班族餐。</p><p></p></div><hr><div class="diary-entry">16:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0G0ET0JXF2Y04W5S0XYD0PX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我恐高，小时候看向天空会有自己掉下来变成 Cytro - 酱的幻想。现在去攀岩，就算是最低级的等级我也很怕。</p><p></p></div><hr><div class="diary-entry">18:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0G5NQAN0AVH6Z2KH2WJ21SC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 这次出来陪行的感想是有钱真敢花啊。</p><p>明显宰客的东西脑子不动一下就要去买。买完还要后悔、骂真贵。我怎么以前不知道家里能花这么多钱？</p><p></p><blockquote class="diary-thread-reply">18:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0G6406GDVJ0SPKX9FC3GF5T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>怒的一原因在于之前家里天天哭穷。小时候买同个东西被宰，被骂一路。现在提起，她就说「没有这种事情！没有骂你！」可我记得很清楚啊。真是的。</p><p>Waffle 饼的冰淇淋以前 9 块钱，现在 10 块钱。</p><p></p></blockquote></div><hr><div class="diary-entry">19:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0G9G54JRK3DY41HK0BBDWPW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我不喜欢吃 Chipotle、Cava 这类餐厅。</p><p></p></div><hr><div class="diary-entry">21:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0GG6HFEZPM9CGFVT6SSK031" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我看到大熊猫啦！</p><p>叫「青宝」和「宝力」。太热了它们都在空调房里躺着。</p><p></p></div><hr><div class="diary-entry">22:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0GNX528031DN6H4G3HYX1SR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Kagi Assistant 的 Quick 模型是啥，感觉好强啊。很想换成 ultimate plan 猛用。</p><p></p><blockquote class="diary-thread-reply">23:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0GPFAH1951T42CYS451TQ6P" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说来我比对的模型是…… Gemini 系…… 现在 Google One 的两年学生订阅没了，我也不会再用 Gemini 哩。</p><p></p></blockquote><blockquote class="diary-thread-reply">08-28 14:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M14B3YBZ1D50SDDZD42J5JJV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://help.kagi.com/kagi/ai/kagi-research.html" rel="nofollow noreferrer noopener" target="_blank">https://help.kagi.com/kagi/ai/kagi-research.html</a></p><blockquote><p>Kagi Research &amp; Kagi Quick (formerly known as Ki) function as "meta models": the research process is based around specialized sub-models that serve specific roles in the research and response process.</p></blockquote><blockquote><p>Kagi Research 和 Kagi Quick（前称 Ki）作为「元模型」运行：其研究过程基于专门的子模型，这些子模型在研究和响应过程中承担特定的角色。</p></blockquote><p>关于模型的模型？</p><blockquote><p>Kagi Research breaks down requests into multiple steps, using various tools and models to deliver state-of-the-art results.</p></blockquote><blockquote><p>Kagi Research 将请求分解为多个步骤，并利用各种工具和模型来提供最先进的结果。</p></blockquote><p>所以可以理解成是将任务交给不同的模型来处理？</p><p>Kagi Search 是元搜索引擎，也是从不同的搜索引擎那儿搞来结果并二次处理。</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>八月二十一日</summary><div class="diary-entry">01:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0GYWW5QC75GRKXDVP8B3C4B" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我现在在鸟不拉屎、犄角旮旯的地方。直到连上民宿的无线网，我都没有任何网络……</p><p>这种地方好可怕。都是草啊树啊，最重要的是有好多好多虫子！我今天腿已经负伤累累了。</p><p></p><blockquote class="diary-thread-reply">01:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0GZ97XVPHAP8C1WD94KBMZG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>山路坐得我想吐…… 上上下下歪歪扭扭…… 因为是荒郊野岭，他们开车也不管规矩了。我只能自己气自己。</p><p>最近的东亚菜在开车半小时以外的地方。气晕。</p><p>这民宿的厕所门没有锁！</p><p></p><blockquote class="diary-thread-reply">02:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0H14AB1WD873X90RXF8164N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>方便面是最好的发明……</p><p>今晚的饭只有数小时前路过一家农场买的鸡蛋、番茄、青苹果，还有自己带的方便面。</p><p></p></blockquote><blockquote class="diary-thread-reply">13:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0J7ARA6SQ8CDT3C83CZ9F2Y" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>原来有锁，被门把手挡住了，其实在下面。吓死我了这厕所一开门就看到马桶呢。</p><p>大人们跑出去摘蘑菇去了。我有点怕…… 尤其是他们不知道什么就会拍照问 ChatGPT。</p><p>母亲一习惯是看到路边长什么东西就摘：摘人家玉米、蘑菇、不知道什么果子，还有竹笋。但我没法理解这种行为，亲戚最小的孩子一直在尖叫「你不可以偷别人的玉米！」</p><p></p><blockquote class="diary-thread-reply">13:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0J7E8BGJ7R7DPFZZGTAH3BW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这民宿虽然没有盐和油，但是有很多烤肉用的香料，如牛至粉、香菜碎碎。</p><p>免费提供咖啡是个常见且被强调的点。我也想弄个喝喝看不过我不会使用咖啡机，提供的咖啡粉多数是 dark roast……</p><p></p></blockquote><blockquote class="diary-thread-reply">13:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0J7H4KC7PB3CPT9HGM8RX5M" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>采蘑菇就采蘑菇吧他们怎么还找到看上去保存良好的动物头颅……？长得和装饰品一样。</p><p></p></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">03:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0H52YYA9Z64AK5MZJ403FAN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>玩 Clue 因为其他人英语不好所以一直在跟妹妹玩双人局。</p><p>以 2:1 的优势胜利了。</p><p>妹妹啊，这就是血脉的压制啊！</p><p></p></div><hr><div class="diary-entry">13:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0J7T64C6ZKJ2VTT9RHHD95V" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我 GitHub 的邮箱明明改了但怎么 giscus 的通知还是发以前的邮箱？</p><p></p></div><hr><div class="diary-entry">14:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0JAN2W75CEQ913G19M49WZ7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 大人们在农场买了生牛乳，写是给猫狗喝的，不能给人喝，其实可以人为杀菌、煮就完了。</p><p>我已经嘱咐他们不要煮沸不要煮沸，结果下楼一看还是煮沸了。他们说煮沸更好…… 你煮沸还喝牛奶干嘛啊。</p><p></p></div><hr><div class="diary-entry">14:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0JB3A42TZ3W26VK254G9BH4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天妹妹买了个 giant submarine 三明治，总之就是很长很大的面包夹肉。</p><p>今天热了吃。她闻一下，然后作呕吐状。</p><p>我：怎么了怎么了！三明治坏掉了吗！</p><p>她：不，它闻起来太香了。</p><p>那你呕个毛啊！</p><p></p></div><hr><div class="diary-entry">15:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0JFX8JJWXD23R0GJ2QKJ9P4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://pluralistic.net/2026/08/19/banaility/" rel="nofollow noreferrer noopener" target="_blank">https://pluralistic.net/2026/08/19/banaility/</a></p><p>宣扬 AI 工具的人也喜欢宣扬它的破坏性 —— 如根据猴子打字机原理 AI 工具终有一天能成为人类、AI 工具让所有人失业 —— 因为那可以证明 AI 工具很强大，且能成为「未来」。</p><p>重点在于这个「未来」。当质问 AI 工具开发者为什么这个工具如此狗屎的时候，他们会说「在未来这些会被解决」，也就是说 AI 工具有这个「潜力」，且只拥有「潜力」——「可能发生」也意味着「可能不发生」。</p><p>Gen-LLM 只是普通且平庸的技术，在使用上，它和其他普通技术没有区别：一些人觉得有用，一些人觉得没有用，而这是完全正常的。</p><p>和其他平庸的技术不同的是，Gen-LLM 被大力推行，以至于巨头们不惜破坏互联网也要爬取他人的文字和代码、不惜破坏环境以至于夺走他人的房屋也要烧煤炭和盖建数据中心、不惜人们失去工作也要说服老板们使用 AI 工具取代员工 —— 尽管它们干活做得一团糟！</p><p>宣传 Gen-LLM 的可怕以说服他人不要使用该技术，往往会造成反面效果，因为它承认了 Gen-LLM 是具有破坏性、强大的。</p><p></p></div><hr><div class="diary-entry">16:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0JJD4QW3X4GQNBFRCAD9H7A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我讨厌野外……</p><p>不过在路上看到有人带两只很可爱的柯基犬。它们跑过来又跑回去，好可爱呀。</p><p>看太多自然已经没有什么感觉了…… 一路上高速除了玉米地就是绿色绿色绿色，没有其他。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M0JJAMNN5093XXEZJ1B7920T.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">16:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0JJSWB9TP3R56S0TBDMBH3G" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>母亲找到木耳：这个能吃吗？</p><p>我：你要吃可以啊，到时候你出事了我们拖着你回去。</p><p>母亲：我要问 AI（读作 <em>AR</em> 不知道为什么）。</p><p></p><blockquote class="diary-thread-reply">16:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0JJX9RWZGBA6AH3XX0SZS7T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>妹妹：我想要喝星巴克。</p><p>她这次出来基本上每天都会喝星巴克的一杯饮料，好像是草莓芒果柠檬汁。</p><p>妹妹：你上次给我设置的作业，里面的 ratio（比例）我不会，所以我问了 ChatGPT。</p><p>你特么说什么。</p><p></p><blockquote class="diary-thread-reply">16:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0JK3DHVMTGBGN2XZ5FP9CZB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我又不在副驾驶。看他们操作 Carplay、用地图导航用不会看得我脑袋一痛一痛的。</p><p>主驾驶和副驾驶一路在聊天。聊着聊着主驾驶忘了往哪里开，导致在高速上开错路 —— 哪一天我了无音讯，可能就是因此出事故了！</p><p></p></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">17:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0JNEBW708CWJS1NSTB6XKJ5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在车上写文，想吐……</p><p>给我不认识的人写回应：我觉得你这个错了，那个错了，你应该这样说、那样想。</p><p>给我认识的人写回应：我觉得你会这么想是因为……（此处叠甲三百字）（感觉写出来一堆废话）（全部删除）</p><p>我还在慢慢理解如何写 RE？认真讨论是没问题，但不是所有人都想要认真讨论。开放写作可以想说什么说什么是没问题，不过以此去攻击他人就不是我的初衷了。</p><p></p><blockquote class="diary-thread-reply">17:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0JNY1QWXM00P1D2EZWY5CD3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>类似于别人在开玩笑时有 nerd 过来说 <em>actually ☝️🤓</em>，就会引起他人反感。</p><p>不过公开的言论也会影响到读者的思想，所以不能不发言。只是在自己的个人网络里发表看法才是最好的？可是那样发表长篇大论，被当事人看到是否会引向更糟糕的方向？因为它最终还是回应的一种。</p><p>话说我是 nerd 吗？</p><p></p><blockquote class="diary-thread-reply">08-22 01:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0KG37562TP7T18THEZD3SB6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>虽然看起来在担忧，实则私下写疯了，以至于觉得自己干脆指名道姓得了。我也不指望谁会回应我，我只是想要公开我的想法，而这必定会引用什么。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">18:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0JSWK0Y504DY9PHVQC8B046" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有时我会把觉得有趣的东西发给室友，且是一股脑发给室友。她很多时候会无视、不回。我就生气说你从来都不会回我！她说一打开手机就是二三条超长消息，谁想看啊，等她什么时候有脑子了再一一看过去。</p><p>总之就当成 GTD 那样，记录一定是要记录的，未来想起来再处理。</p><p></p></div><hr><div class="diary-entry">19:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0JV8NWCMJA3HVWW0SSF0Y79" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>母亲跟亲戚聊天，聊到我小时候外婆家隔壁的小男孩。他也是我的亲戚，但我不知道他是我的谁…… 总之他会管我叫姑姑。</p><p>说来我一直以为只是邻居朋友的邻居竟然也是我亲戚，四代开外的。为什么从来没有人告诉过我？</p><p>总之那个小男孩，亲戚说他现在素质很差、没有教养，应该是没人管导致的。我印象里小时候我看他都是和个老奶奶在一块，没有见过他父母。</p><p>邻居朋友也跟我讲过他，抱怨说他满口烂梗。</p><p></p></div><hr><div class="diary-entry">19:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0JWZ1YH9VMMPGZW8DZAWN7Y" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>跑到另一个亲戚家里做客。好几年前看到他们家大儿子还是小小一个、刚开始长身子，现在变成肌肉男了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3M8KH0WA908PA858VD8FK.png" alt=":neocat_nervous:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">08-22 01:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0KJXQ1Q2NDXG34XXMDMEYY5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不对啊我三年前见到他他还是瘦瘦一个，现在怎么突然变成大只肌肉男了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3M8KH0WA908PA858VD8FK.png" alt=":neocat_nervous:" loading="lazy">​ 看到时我还寻思这谁啊。</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>八月二十二日</summary><div class="diary-entry">01:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0KJAVZS6TGXH79TNQ5JQFZ0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>回家回家回家。我受够高速和山路和虫子和玉米地了。</p><p>我满腿都是蚊子包，脖子上也是！</p><p>我要回公寓窝数个月，期间再也不去父母家。</p><p></p></div><hr><div class="diary-entry">02:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0KKQJWKY5C5VC90HQJXHT8Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>主驾驶在高速上走错路，导致需要在高速上多绕十分钟的路，可能还要再走一次收费站。一路上主驾驶一直在哀声哀气。</p><p>副驾驶在干什么呢？副驾驶在睡觉！</p><p></p></div><hr><div class="diary-entry">13:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0MVYN39KCP3DP3P61B8TRE8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 回家睡觉，一醒来就是看到幸运狗和咪咪猫，爽死了。</p><p>昨天去做客的亲戚，他小儿子去年捡了个猫养，叫 Luna。这个月亮猫被养得又大又毛茸茸。不过他们会让月亮猫出来院子。因为之前月亮猫跑出去过夜过，家里的母亲一直不想它出来，但父亲会偷偷把它放出来，然后说「我会看着它的！」</p><p>家里的奶奶还说，小儿子之前捡了个狗养，养一个月发现是别人走丢的狗。</p><p></p></div><hr><div class="diary-entry">15:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0N0X802N1GHVSAQ0HHXY15H" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这周跟亲戚还有家里人出去玩，路上他们常会说「美国人怎么怎么样」、「你们美国」、「我们美国」…… 这种话我没法理解啦，因为「美国人」是个非常奇怪的概念。</p><p>作为移民国家，到底什么才算「美国人」？是两海岸的都市美男，还是中部的保守主义者？两个都可以是「美国人」的刻板印象。</p><p>亚裔美国人是美国人吗？西裔美国人是美国人吗？意大利裔？德裔？亦或者是其他？「美国人」究竟是什么？他们和「中国人」的区别又是什么？</p><p>例如大人们会说，「美国人」是独立的、不会管小孩子、成年后就把孩子踢出家 —— 可是我也见过遵循宗族观念、和中国家庭的结构非常相似的美国家庭。</p><p>他们很难去理解「美国人」是个许多国家文化融合在一起的集合体。它非常复杂，很难总结出共通点。</p><p>而探讨这些，我就必须要直面身份问题：我是什么？</p><p></p></div><hr><div class="diary-entry">15:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0N2CEWEXKASPKB3T7ZMMJWJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>虽然我没有在国内接受完整的义务教育，不过我接纳性少数应该是在美上初中的时候。那时候周遭的氛围就是如此，就算是华人区的学校。</p><p>我在小学开始就要写和人权相关的作文。印象挺深的，我那时候刚在学习英语，在作文里写了 <em>black people</em>，被老师纠正要用 <em>African American</em> 以表达尊重。</p><p>在人权相关的教育里，性少数群体也会被提及。不过当时并没能深入，仅是「因为它是人权的一部分所以支持」。对于生育、政治等问题一窍不通，所以只是在支持皮毛。</p><p>再之后深入概念，是大学的事情了。</p><p></p><blockquote class="diary-thread-reply">16:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0N407HW4WH40E8RFB7GY9WB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说初中那会儿在支持皮毛，是因为我很清楚当时的我们并不了解「人权」，也不知道背后意味着什么，更多是在遵循氛围。这个氛围除了社会的氛围，再是初中生寻求独特的氛围⸺性少数曾是我们标识独特性的媒介之一。另一个是心理疾病。</p><p>当时的同性情侣究竟有多少是真的性少数群体？我无法确认。我们对性别的了解少之又少，不过是在复述互联网上所说的口号。</p><p>教科书上说的种族主义的问题，我们能写出一篇又一篇的作文，但我们能理解它吗？还是陷入循环认证，认为这是境外势力、民主党的阴谋？在美华人社区⸺以及主流中文互联网⸺依然笼罩在保守主义的影子下，这也有宗教的影响在。</p><p>对于初中生来说，我们是不理解的。我们的知识储备和思考能力不足以我们去想那么多、那么远。</p><p></p><blockquote class="diary-thread-reply">16:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0N4G7P2N16BNKYKTFBHT7JY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>至于我本人的情感史…… 我承认有受到性少数相关的作品，如漫画，的影响在。不过它们对恋爱过分简化了，我只是在仿照作品中的样子、以为自己在恋爱。实际上我只是很孤单，想要成为谁的唯一⸺这是现在的我对我初次恋情的评价。</p><p>该评价同样能够放在我之后的恋情上：我很孤单；我想要成为谁的唯一；我需要有谁在陪伴我。不过接着我理解到这些需求不需要恋爱就能达成，恋爱同友谊的差异应当更大才对⸺是责任吗？</p><p>我喜欢同性吗？答案毋庸置疑。但我仅喜欢同性吗？我不好说。周遭的人都说，你不试试和异性谈恋爱，你怎么知道？可我觉得我无法和异性走太近，已经足够说明很多事情。我有关系好的异性朋友，但是他们和我从不会像我和同性朋友那样亲密。再是主流观念的影响，去有一个能和我关系很好的异性朋友非常困难。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">19:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0NDTXNB0KCM0J9YVSXZQH4Z" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>终于回公寓了。</p><p>室友：你不在的这些天……</p><p>我：你很想我是吗 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JNHF23SBKYB8350F7PKT.png" alt=":neocat_happy_blep:" loading="lazy">​</p><p>室友：…… 房间变得很干净。</p><p>我：<em>fuck.</em></p><p></p></div><hr><div class="diary-entry">19:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0NF6S74FQE3W6RX4M7Y48T4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://www.macrumors.com/2026/08/17/camera-equipped-airpods-macos-26-7/" rel="nofollow noreferrer noopener" target="_blank">https://www.macrumors.com/2026/08/17/camera-equipped-airpods-macos-26-7/</a></p><p>什么叫你在研发「搭配了摄像头的 Airpods」？</p><p></p></div><hr><div class="diary-entry">20:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0NJTMVBANMBCRYV7QY58AQV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>原来最近 GitHub 发生了大规模崩溃 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3M8KH0WA908PA858VD8FK.png" alt=":neocat_nervous:" loading="lazy">​ 我已经不用 GitHub 很久了完全不知道。现在唯一用到它的场合就是在别人的 giscus 下评论。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">Obsession 剧透相关。</summary>        <div class="diary-cw-content">22:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0NSZZAT6B9RWKCA6BD3QEAJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>时隔一段时间又对这个片的 meme 感兴趣了，于是上网看了些。</p><p>果不其然看到令人无语的言论。</p><p>我对这个片的解读是，Nikki 因懦夫 Bear 而遭受飞来横祸、身边的人都死光光；<em>Obsession</em> 这个主题来源于 Bear 而非 Nikki。结果没想到依然有人认为这个片的重点在于「我的病娇女友」，甚至为了证明 Bear 没有那么差，去证明 Nikki 也是「神人」。这里包括：</p><ul><li>因为解说的不责任所以认为 Nikki 借钱去买毒品⸺你都看解说了你到底在解析个毛啊。这点被戳破后，还有人认为 Sarah 叫 Nikki 别忘了还钱意味着 Nikki 平日就借钱不还、怎么可能是好人</li><li> Nikki 和 Ian 是炮友关系。有炮友等于是「神人」</li></ul><p>我不清楚为什么人们对私生活那么在意，要求所有人都「冰清玉洁」、只能婚后有性行为？</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">Obsession 剧透相关。</summary>        <div class="diary-cw-content">22:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0NTSW59DCMR0WECHDYPQTWK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>关于性，影片中有一段是这样的：</p><ul><li>Bear 得知 Nikki 的父亲可能没有事；Nikki 可能欺骗了自己</li><li>下一幕立即就是 Bear 和 Nikki 行床事的场景</li></ul><p>和我一同去看电影的朋友将其解读成导演性压抑、露出「小头」。</p><p>但是我不认可这个解读。这一幕实际看下来给我的感觉不是色情的，而是恐怖的。</p><p>该视频提供了更多的视角、解答了我感到恐怖的点： <a href="https://invidious.nerdvpn.de/watch?v=nzF_m1QP1fM" rel="nofollow noreferrer noopener" target="_blank">https://invidious.nerdvpn.de/watch?v=nzF_m1QP1fM</a></p><p>频道主也提供了另一个电影作为例子，来解释为什么这个床戏是恐怖的：Bear 在得到 Nikki 后，将对方视为供自己肉体享乐、满足的工具；Nikki 本人的表达则是空洞、虚假的。</p><p>而那部电影的内容是三个男人发明了个东西，可以让看到的女人变成自己的性奴隶。但是被施展魔法的女人在身体被侵犯前就清醒过来，于是攻击了那些男人。</p><p>我们的欲望能够消除我们的同情心、对他人主体性的认可⸺这也是那部影片主要想要表达的讯息、从 <em>Obsession</em> 中挖掘出的价值。</p><p>「性」能解答出很多内容。我不认可因为出现了「性」相关的内容，于是代表了导演「性压抑」、「露小头」、为了看色情而拍色情。</p><p>同样的，Nikki 和 Ian 有炮友关系也不代表她是个滥交的人⸺话又说回来，为什么我们要根据一个人是否有贞洁，来判断他是否是道德的、正确的？</p><p></p></div>      </details></blockquote></div></details><details data-group="diary_sections"><summary>八月二十三日</summary><div class="diary-entry">02:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0P7GEGTM9S9KPJHXZS9E3Z7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>「文化差异」是个好东西，哪里需要解释就往哪里搬。</p><p>因此所有差异和问题都可以用「文化差异」来回答。我们也不需要去探究背后的逻辑。</p><p>「使用标签以覆盖所有的解释」、「给出详细的思维链条」、「解释后再总结成标签」⸺这三个行为是不同的。正如看山看水里，第一步的「看山是山」和第三步的「看山还是山」虽然在结果上一致，但实际意义截然不同。</p><p></p></div><hr><div class="diary-entry">03:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0P9680MJ4863CWEDPGPMH8G" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>朋友说 BiliBili 上的频道主瓶子君提到「大陆台湾混血」，所以推测他要「死」了。</p><p>这个「死」指的是在平台上被封杀，或者失去资源。</p><p>我推测逻辑链条是这样的：</p><ol><li>混血意味着承认大陆和台湾是两个不同的国家</li><li>瓶子君说「大陆台湾混血」</li><li>所以瓶子君承认大陆和台湾是两个不同的国家</li><li>瓶子君支持台湾独立</li><li>瓶子君要被封杀了</li></ol><p>嗯说实话我的第一反应其实是「这么点小事你也要跟我讲啊」……</p><p>不过我后来开始好奇「混血」的定义。</p><p>混血需要生物学上的父母来自不同的民族，而非国家。大陆和台湾的种族近乎都是汉族，汉族人和汉族人交配不构成「混血」。同样的，美国白人和英国白人也不会被认为在混血。</p><p>如果看国籍，那中国裔美国人和中国公民交配生下来的孩子也是混血儿么？自然不是。</p><p>所以「大陆台湾混血儿」的前提得是父母双方是不同的种族。这个概念没有任何问题。提到它也不意味着承认台湾独立。</p><p>朋友很期待看到瓶子君「死」掉。但我觉得他「死」还是「不死」都跟我没有任何关联。</p><p>「死」这个词还是听上去有些过分了！</p><p></p></div></details><details data-group="diary_sections"><summary>八月二十四日</summary><div class="diary-entry">02:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0RT1RCZ3ZQTWSNT7R2RPRHE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我和室友吐槽亲戚一直问我「美国人」是什么某个样子（往往是刻板印象）的。</p><p>室友：我要打断你一下，因为我很好奇一个问题⸺什么是「美国人」？</p><p>我：<em>EXACTLY!!!</em></p><p></p></div><hr><div class="diary-entry">13:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0SY0PMN5DVTYKNRPFMBAK5A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我要去年检，抽血 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​</p><p>因为会幻想有针头在我的身体里，所以我对抽血有着一定的恐惧心。</p><p></p><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">屎尿屁相关。</summary>        <div class="diary-cw-content">15:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0T5Q8AR0K68K48KQXF295W7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>尿检不是会害怕尿到手上吗。</p><p>尿液是水溶的，用水洗就行了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4TFD239TJ4YG6N2ENQBK.png" alt=":ottersgottaott25:" loading="lazy">​</p><p><del>所以尽情尿手上吧！</del></p><p></p></div>      </details></blockquote><blockquote class="diary-thread-reply">15:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0T5WJ7FP51R06JQ4GBVDNG3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我的体重和身高跟十年前一样。</p><p>十年后我也会是这个样子吗？</p><p></p></blockquote><blockquote class="diary-thread-reply">15:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0T63SWVNE41WM3139E0Z9N0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>吹气测试有个酸酸的东西要喝。</p><p>真的好酸 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​</p><p>现在舔嘴巴也是酸的！</p><p></p></blockquote><blockquote class="diary-thread-reply">15:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0T6JMGVSZ6WWWTC58K9H4MT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>抽完血去吃饭。</p><p>没有吃猪肝因为不喜欢。也没有喝温的黄酒因为不喜欢。</p><p>我来旁边的小店面吃肠粉和肉饼。</p><p>为什么店铺上写了肉夹馍，进去一看菜单却没有呢？我觉得这是欺诈。</p><p></p><blockquote class="diary-thread-reply">15:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0T6PYP7PRH7EA2W3F6CCSY1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>肠粉我喜欢吃鲜虾滴。</p><p>鲜虾好，虾米不好！</p><p>我小时候还会吃虾米、小银鱼条条。现在完全不喜欢了。</p><p></p><blockquote class="diary-thread-reply">15:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0T76PTV59ADVQV7NSWYZ6CP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友教过我如何分辨好的肠粉。但我全都忘记了！</p><p>如果没有记错有褶皱的是好的。</p><p>这家店的酱料带有海鲜的味道…… 我不喜欢。</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">08-26 04:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0Y4T5JFVMXEDTBJWKA2RJC3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>抽血的地方淤血了。好大一块。好可怕。</p><p>跟室友看动漫，里面说血很美味。所以……？</p><p>好吧我很挑食我不会吃任何血块和血肠。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">13:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0SYYA0J4TC5DDT9RJMHWNZ0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>以为室友喜欢自己的男生让室友猜自己是什么 MBTI，如果猜对了就请室友喝喜茶、吃晚饭。</p><p>室友很生气，感觉自己被看扁了。</p><p>男生也问她，是不是对自己跟对他人不一样。</p><p>室友想搞他，就把自己和朋友聊天的记录发给他看，这让他大吃一惊：你们怎么在用这种词、那种词？这是不好的！</p><p>然后室友后悔了，觉得自己是不是对这小伙子太坏、明明有更好的方式去表达。</p><p></p><blockquote class="diary-thread-reply">13:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0SZJD8N246E9WWFV7QC0QJ7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 当你明显感觉到对方想要泡你，但你因为害怕伤害到对方的自尊心所以不去点破，那你就会是要承担压力的人。</p><p></p><blockquote class="diary-thread-reply">13:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0SZM0F0TS6MD6G14NN3DD18" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友问我这种情况我会怎么做。</p><p>我思考半天：对不起我没有那么多朋友我想象不出来。也没有人喜欢过我、想要泡我。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">13:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0T147187SG3J15F66EBQKGH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>地铁站的无障碍电梯里，残障人士要等非残障人士用完才能用 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">14:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0T1989NF6PWPDKKJX8A6HDJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说到这个「残障」，室友昨天给我提供了新的事实性证据，即双性人体内激素会有问题，因而是「残障」的。</p><p></p><blockquote class="diary-thread-reply">14:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0T1C35AK1NYEX903QNQ5NR7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>但我觉得这和传统上缺胳膊断腿的残障依然有区别。变异导致的和他人不同的特征也有可能伴随问题上的问题。</p><p>所以我要研究一下。</p><p></p><blockquote class="diary-thread-reply">14:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0T1YQE49G129HGDA5E5J2PM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友的观点是，「残障」只是客观形容身体的用词，本身不具备主观的思考。我否认这一点，「残障」是可以被社会污名化的。</p><p>先前已经提到，看「残障」有两个模型：医学和社会。她的观点更倾向于使用医学模型，即因为「双性」会导致身体功能的损伤，所以要被修复。如果条件是属实的，那我是认可纠正手术的存在。</p><p>但「双性」是否是导致身体功能损伤的关键？所有双性人都会经历同样的痛苦吗，如都有 Turner Syndrome？我不这么看。</p><p>那么将整个「双性人」群体放在「残障」的区域，是否合理？</p><p></p><blockquote class="diary-thread-reply">14:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0T30TRBBC9G23167X3ZC0GF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我提出一个问题，即如果室友说得属实，双性人都有身体问题，那为什么他们反对纠正手术？</p><p>因为逻辑是，双性导致了确确实实的身体损伤，因而为了活命需要被修复。但实际情况是它现在不被看成是「病」，有许多运动反对纠正手术、反对将「双性」认为是「残障」。如果自己都觉得自己的健康被损害，为什么还要这么做？</p><p>室友的解释是，这是全新的身份标签。也有双性人享受着「自己干自己」的快感。</p><p>我觉得这个解释是非常傲慢的，且带有对互联网 —— 甚至说是 Pornhub—— 上的双性人形象的先入为主。</p><p>在我和室友谈论牛郎织女问题时，对于女性主义者，她的看法 —— 因为是被强调最多的，因而我认为是最重要的印象 —— 是批判父权制的同时享受着父权制给自己带来的好处。尽管她也认可我提到的学院派，但她依然在看待女性主义者时第一反应依然是我所定义的互联网激女。</p><p>先入为主是件坏事么？她问我。我将先入为主和标签化关联在一起：标签的好处在于能更快地找到同好，坏处在于使用久了会让复杂的概念变成简单的符号，从而误导后人。先入为主就是误导所产生的果。</p><p>例如我说「互联网激女」，就是将她们标签化成「互联网激女」。你能更简单地理解我在说什么群体、得知她们的特征，而不需要我解释一大堆该群体是什么样的。</p><p>但久了，所有人都开始说「互联网激女」，且不知道具体的特征是什么。人们便会按照该标签的特征来区分他人。如因为你厌男、你符合「互联网激女」的特征，所以你是「互联网激女」。而「互联网激女」是这个样子的，所以你也是这个样子。</p><p>总之是个很复杂的双刃剑！</p><p></p></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">18:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0THFQPA88CH5EF5D3G1NDS2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ496Q8A4XAZF9TK81RAX7.png" alt=":ottersgottaott10:" loading="lazy">​ 我在看英文 IndieWeb 圈内的小小斗争。</p><p>感想倒也没有感想。或许还是有的。</p><p>修辞暴力是我无法理解的事情，我也不明白为什么有人对其他事情贴标签、隐喻，然后把被冒犯的人留在那里，但被其他人贴标签时会愤怒。</p><p>终止思考的陈词滥调⸺我不认可任何人使用这个词来反驳他人，同时自己也在用它代替论证。</p><p></p><blockquote class="diary-thread-reply">18:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0TJ89865H05RTYYRTF2J16F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 什么叫 AI 驱动的艺术项目以讽刺 IndieWeb 圈内的知名人士。</p><p>你这个 AI 从哪儿来的。</p><p></p></blockquote></div><hr><div class="diary-entry">19:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0TJP2T8M2HQHNXMD34NNAFV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我在华人超市里买了营养快线。我以为现在新包装原味变成纯白色的了，结果现在喝了下才发现这是椰子味。</p><p>你为什么不说清楚！</p><p>我讨厌椰子！</p><p></p></div><hr><div class="diary-entry">19:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0TMK4JJJTQ8K8EVY5ABD6CW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Agent interview 是什么……</p><p>这个 <em>agent</em> 是 <em>aigent</em> 的意思。</p><p>他们还接受 24 / 7 来面试。不过坏处是我时区没看，约了东部时间凌晨 3 点的面试。我真气死了。</p><p></p><blockquote class="diary-thread-reply">20:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0TP52Q9EEAR3QXS2J6EB75W" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我又约了个但是进去一看发现别说人了，aigent 也没有看到。</p><p>感觉被坑了。</p><p></p></blockquote></div><hr><div class="diary-entry">22:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0TZ5H2RD3Q4V85BY4Y2PR09" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>数年前我用父亲留下来的 VAIO 电脑上网，在 eBay 上帮父母下单。</p><p>因为我们对电子邮件没有概念，只是把它放在那里，然后不去管它⸺直到父母觉得货一直没有到很奇怪。</p><p>我就上 eBay 上看，发现卖家给我发了条消息。他说他住在乡下一个城镇，忽然城镇里都没有了网络。无法，他驾车开到最近的城市，然后蹭那儿的麦当劳的免费网络，给我发来这封消息：没货啦！</p><p></p></div><hr><div class="diary-entry">23:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0V10K9XSX4A5F568WHDKSYP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>《牛来》是什么东西？我老是刷到，但这个牛模型太丑了不想要点进去看。</p><p>之前亲戚小孩也在说。</p><p></p><blockquote class="diary-thread-reply">08-25 03:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0VFPQVCA49NPPH6JFHBQHFP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友：你知道《牛来》吗？</p><p>我：我不知道！</p><p>室友：最近很火的样子，是什么啊？</p><p>我：我不知道！</p><p>室友：（打开《牛来》解析）原来是电影。</p><p>我：我不知道！</p><p></p><blockquote class="diary-thread-reply">08-25 13:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0WJ13F1C30B6CRV3ZVKTFY2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>跟室友看了个片段。这个蛇太鬼畜了每次出场我俩都在笑。</p><p></p></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>八月二十五日</summary><div class="diary-entry">00:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0V4Z8BHAT1392GQQHC04PR5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不行了我得找点糊口的工作做。</p><p>IT 类工作给我的感觉就像：Windows 系统很难用对吧？我们招了个会用的人。耶 ——！</p><p></p></div><hr><div class="diary-entry">01:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0V77RXYCB3NMXEE14HBA32F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Board 是每隔一段时间就要被一个只会艾特 Board 发帖的用户轰炸是吗。</p><p>吹狗哨的能不能去自己的小世界发。看都看烦了。</p><p></p></div><hr><div class="diary-entry">01:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0V95R9261D2TN6Y3H7JA9QT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://www.bilibili.com/video/BV1Eu9BBuEQT" rel="nofollow noreferrer noopener" target="_blank">https://www.bilibili.com/video/BV1Eu9BBuEQT</a></p><p>MaiMai DX 新版本里《碧蓝档案》的歌。</p><p>蛮好听喔。上个版本我也才知道 <em>Unwelcome School</em> 是《碧蓝档案》的曲。</p><p>玩起来不难就是容易被那坨纵连吸引注意力……</p><p></p></div><hr><div class="diary-entry">12:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0WE5F1HSJV4HFR17HA0D3CB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我做梦梦到和朋友在一个像是动漫嘉年华的地方。有很多很多人在室外，还有桥、大荧幕、各个展区。</p><p>我和朋友们一直坐在初音未来的展区，那儿的荧幕在连续放初音未来的歌。里面放的 MV 不知道为啥，初音未来死了，然后大哥大姐也挂了，只剩下一个 Rin 在唱歌。我在旁边分析因为初音未来挂了所以之后的歌都没有初音未来。</p><p>我们就朝另一个方向去，因为打算回家。我们走上天桥，背后的荧幕开始放 MyGo 的歌，不知道为啥。走到嘉年华边缘的地方，我们本该挥手说再见，但最后又没有走，跑到名侦探柯南的儿童区、脱鞋坐在垫子上跟小孩儿一起看电视里的名侦探柯南……</p><p></p></div><hr><div class="diary-entry">19:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0X6RPVWQWG3F15N7CPTDPFP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友在我不在家的那一周买了可折叠小型洗衣机。我大致看了下，一次能洗三件 T 恤衫。</p><p>但是这玩意儿的甩干功能会把袜子甩飞、只能甩干衣服。</p><p>它能多多少少减少我们洗衣服的负担，因为公寓附近并没有自助洗衣房，只能打电话让洗衣店的人过来取，再送回来。一来一回几十块钱就没有了。</p><p></p></div><hr><div class="diary-entry">19:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0X6ZXJG9A73X84GJ39Z0MZZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前段时间米里长了米虫。室友将米袋子塞到了冰箱里，次日它们都变成了死掉的米虫。</p><p>不过它们从哪儿来的？我很好奇。</p><p>直到今天我去收拾水槽下的柜子，我才发现其中有个放杂物的小塑料柜子，里面室友搬家带过来的不知道是什么米的米全部撒了出来、到处都是爬来爬去的米虫！到处都是！甚至还有已经死掉的米虫！</p><p>最终将整个柜子收拾了一顿，把那些不知道是什么的米全部丢掉 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3EQQJ0WWJ5EQ79NS9AMS5.png" alt=":neocat_angry:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">20:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0X8ABCXNHFBCARKNPR61PBE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://pluralistic.net/2026/08/24/elbows-really-up/" rel="nofollow noreferrer noopener" target="_blank">https://pluralistic.net/2026/08/24/elbows-really-up/</a></p><blockquote><p>Trump will still be obsessing about these idées fixes when he draws his last breath, gasping out "Greenland…tariffs" as he tumbles from his golden toilet, forehead and coronary arteries bulging from the strain of trying to pass a half-digested Big Mac with only a viscous paste of rectal mucus and Diet Coke to lubricate that final, unyielding bolus.</p></blockquote><blockquote><p>Trump 在咽下最后一口气时，仍会对他那些固执的念头念念不忘。当他从金马桶上跌落时，还会喘着粗气嘟囔着「格陵兰岛…… 关税」。由于仅靠直肠粘液和健怡可乐形成的粘稠浆液来润滑那最后一块坚硬的粪块，他的额头和冠状动脉因费力排出一只消化了一半的巨无霸汉堡而青筋暴起。</p></blockquote><p>我要被笑死了。</p><p></p></div><hr><div class="diary-entry">23:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0XJEV7RAWJ4TDAAQPJ64SGC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我在听 RITx 的网络安全课。</p><p>关于 DDOS 和 IoT 的事情，我想到我能不能反过来骇了扫地机器人，然后让它跑些东西？</p><p>单元一的内容印象比较深的就是密码的可怕吧：多更新密码、使用全新的密码！使用密码管理器软件是最便捷的，但存储密码到云端的那些软件也要小心它们被骇。放到本地是可以，不过你就要更小心下载到本地的数据了。尤其是我这样又接了些高级层的设备，也得担忧我的 VPS、Headscale 网络会不会出问题。</p><p></p></div><hr><div class="diary-entry">23:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0XKMXM24KHZFQMRYA0H2A6V" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天吃炸酱 rotini。</p><p>家附近超市的意大利面打折，一盒才 88 美分。</p><p></p></div></details><details data-group="diary_sections"><summary>八月二十六日</summary><div class="diary-entry">01:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0XTAWWNNTXRCRYGKARF9J00" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我今天已经很努力了，我还修了个生产错误。我觉得我值得一场酣畅淋漓的舞萌和唱 K。</p><p>至于生产错误哪里来的你不要问我。我会生气的。</p><p></p><blockquote class="diary-thread-reply">02:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0XZ5G9QTPSJRVAEJ4YF59K9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这个 KTV 的隔音一般，能听到别人在吼叫。</p><p>本来以为我在唱什么 80 后金曲已经很奇怪了，结果出来走廊发现对面房间也在唱中文歌。</p><p>室友则是在大声吼日语歌。</p><p></p></blockquote><blockquote class="diary-thread-reply">03:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0Y2RDDPBJ8XEZD266A7GK0T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​ 舞萌机他们说早上出问题、用不了、不知道什么时候能修好！</p><p>我本已经做好了和新版本斗智斗勇的准备！</p><p></p><blockquote class="diary-thread-reply">04:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0Y3PWXPNFBS9MG9KK8Z14QC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>来附近的日本超市买东西。他们的食物会在晚上八点后打 7 折，饭团则是三个 10 块钱，相当于可以 7 块钱买仨。</p><p>买了仨，尝一口，立即明白为啥这么便宜了：饭酸了；里面的海鲜变味儿，量还特别少；假的蟹肉是廉价、更像是粉的。</p><p>7 块钱我原本可以买一袋泡面。</p><p></p><blockquote class="diary-thread-reply">04:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0Y3YWTN6H5ZJQH49SASNF72" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我的 Google Wallet 好像无法正常使用了。NFC 触发后指纹验证但是无法付款。</p><p></p></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">06:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0YBTDFTYPZHANG9S0WCDRR1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友最近在看网页解谜游戏。我简单瞄了眼，应该是以千禧年的个人博客网页作为舞台的游戏。</p><p>不过我第一时间想到的是 <em>lomando</em> —— 好奇宝宝不要搜。</p><p>另一个类似的游戏，在尝试表演出「时间」相关的元素时也使用了网页。玩家可以点到下一个网页（未来），然后回到上一个网页（过去）点击正确的选项。</p><p></p><blockquote class="diary-thread-reply">13:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0Z42RJHW6CQTVB093RA6PC2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天跟室友玩名字应该是大学生登山失踪事件的网页解谜游戏。</p><p>我是个很心急的人所以想不出来的事情我不会更努力去想，我会去看攻略。</p><p>室友说我要是看攻略就不跟我玩了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 然后我就很想看网页源代码，但也被禁止。</p><p>总之卡关了。现在醒了再想想好了。</p><p></p><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">《大学生登山失踪事件》剧透相关。</summary>        <div class="diary-cw-content">14:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0Z7N3KD5ASNYCFDER9RKV2P" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我昨天就很想吐槽了：赵跟鱼说请他吃烩面，但菜单里没有烩面啊。</p><p>你为什么不卖烩面！为什么！</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">re: 《大学生登山失踪事件》剧透相关。</summary>        <div class="diary-cw-content">14:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0Z82X8KZXJKNYHEB7QSPF1A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我说我怎么卡关了。</p><p>我寻思「敬献」是个普通词儿呢，原来是关键字！</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">re: 《大学生登山失踪事件》剧透相关。</summary>        <div class="diary-cw-content">15:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0ZA8XE2F3N49D3EXCCG39WX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我又卡关了。</p><p>其实故事很好猜。我看到菩萨就知道啥回事儿了。</p><p>但是这个游戏找关键字不太好找。虽然说明里提到「只需要用肉眼可见的关键字」，但很多东西并非「肉眼可见」。</p><p>比如「福安饭」最开始在首页上又是有框框又是粗体，所以会引导人们搜索。那个炒鸡蛋也是。</p><p>可是「杨佳俊」等人的名字就不是粗体。我看到报道我也不会想去搜报道人的名儿。</p><p></p></div>      </details><blockquote class="diary-thread-reply">15:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0ZAGWP9SWD27JDG04KJHHJ1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这种网页解谜游戏的形式非常有趣…… 让我想在 realm 上添加个。因为我画累了，所以重新绘制 realm 的任务无限期拉长中～</p><p>做成更简陋的早年网页风格更有趣，还省精力（指美术上的精力）。</p><p>这种网页解谜游戏也不需要 JavaScript，除非想要做密码吧。那我搓 HTML 就好了。</p><p></p><blockquote class="diary-thread-reply">16:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0ZD0YPW9A72GQ8PA63YFJNA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4BBQ7ZYP90ZBJ27VNCFF.png" alt=":ottersgottaott12:" loading="lazy">​ 大脑中开始有个雏形。</p><p>我可以 <del>抄</del> 参考 IndieWeb 的各个形式然后弄个技术大考古。</p><p></p><blockquote class="diary-thread-reply">08-27 16:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1200PH230ZKN37TZ41T0K1G" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>托这个想法的福我第一次纯手写 HTML 来造博客网站。</p><p>我模仿的是最早的 weblog，即连文章排序都没有用到的、想咋弄咋弄的个人网页。</p><p>我的构思是你误入了一个人的网站，并通过拼接 URL 看到这个人曾经的点点滴滴。你会通过这个人的站点，看到其他人的站点，并体验不同形式的个人网页，如现在最常见的文章按时间排序的 blog 仅是其中之一。</p><p>嗯我也不是很懂这些词所代表的东西到底是什么。所以先前一直在用 <em>weblog</em> 这个模糊的词来代替个人网页，它既可以是 <em>we blog</em> 也可以是 <em>web log</em>。考虑到个人网页可以只是普通的网页、可以是以文章为主的 blog、可以是其他七七八八的东西。</p><p></p><blockquote class="diary-thread-reply">08-27 16:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1206FKWK7BDPAXMNC9WJ3D2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我的感想是静态或者动态博客构建器很重要…… 写 Markdown 或者 Org Mode 比搓 HTML 简单方便多了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ496Q8A4XAZF9TK81RAX7.png" alt=":ottersgottaott10:" loading="lazy">​</p><p></p></blockquote></blockquote></blockquote></blockquote><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">re: 《大学生登山失踪事件》剧透相关。</summary>        <div class="diary-cw-content">08-28 12:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1473NTSHSSQZYVBV7YMRDAD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>玩完了。后面节奏有点快，揭秘时不会觉得爽。</p><p>结局一救弟弟给我的感觉很不舒服。尚念、李福安和赵慧心为了一己私欲害了人，我救了弟弟并把他们送往轮回转世，为什么这是一件不可挽回的错误？</p><p>结局二又说这三个人都没死，尚念还叫说我就算烧了符咒弟弟也回不来。很莫名其妙啊，我跟他们仨为什么关系要变好？就算让尚念去自首，他依然没有得到应有的惩罚。王世文和弟弟都是他故意弄死了啊？香客有谁是想要跟菩萨链接的吗？为什么这种结局作者写得好像才是正确的？</p><p></p></div>      </details><blockquote class="diary-thread-reply">08-28 13:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M147B1EW0CZGBXMSN93Q21TW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>结束后室友想看她常看的 BiliBili 频道主「某幻君」玩。</p><p>我之前也看过这个频道主。我很不爽他是因为他改编了一款我很喜欢的游戏，然后把它改得面目全非、莫名其妙、乱七八糟，以凸显他根本不存在的文学性。</p><p>你自己看看你改的剧情，有逻辑吗。为什么不好好播游戏原本的剧情？</p><p></p></blockquote><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">re: 《大学生登山失踪事件》剧透相关。</summary>        <div class="diary-cw-content">08-28 13:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M147VS4EYC7TCVH4AAXWZDRK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>很好笑到最终解谜的时候，要推理出个密码。其实那时候我已经推理出密码是什么了，但我不想让室友知道我提前玩了一点点，所以我在装自己不知道。</p><p>这个解谜的方法很简单就是看网页目录得出要用波利比乌斯方阵密码解，得出提示密码是个名字后，再去看之前的排班表还有记录得出「我」是尚念。</p><p>但室友在看到日记 2 后一直觉得幕后凶手是个小孩。因为她觉得这是李福安还有赵慧心的孩子，然后李福安和赵慧心已经死了，这个小孩就 6 岁 —— 总之很奇怪的推理啊。</p><p>接着就是不停去猜密码，就算我提示说香客名单里的日期还有名字是粗体的，说不定可以用到排班表。</p><p>最后我还是装出我刚刚推理出密码。不过这样惊喜少了很多，因为显然她忘记了日记 3 的内容。</p><p></p></div>      </details></blockquote></blockquote></blockquote></blockquote></blockquote><blockquote class="diary-thread-reply">08-28 14:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M14D1AFVPCVGPVYYQKCT0EDN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://puzzlegameonline.org/zh-CN" rel="nofollow noreferrer noopener" target="_blank">https://puzzlegameonline.org/zh-CN</a></p><p>你的意思是你将网页解谜游戏放在了自己的网站上，并声称不需要下载即可游玩，即便它们都是不需要下载和登陆的网页解谜游戏，然后在游戏下方放了狗屁不通的 AI 生成简介与游戏说明，而不是游戏自己的说明？</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">13:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0Z4AJA5EWWJD3ECS5SCNA64" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我才发现 BlogFinder 把我的旧 RSS 地址换成了新 RSS 地址 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3N0PXFDAZ6V7T74MZ1VQD.png" alt=":neocat_notice:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">13:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0Z5APETGRJ1E71YR16V4Y3H" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p></p><blockquote><p>Baa, baa, black sheep,</p><p>Have you any wool?</p></blockquote><p>Sometimes this lyric just goes round and round and round and round and round inside my head!</p><p>And Grammarly thinks it's grammatically incorrect. You dumb program you know nothing!</p><p></p></div><hr><div class="diary-entry">14:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0Z67RM6AXS60873T5FZ2CD5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>关于 Gen-LLM 有个人们常聊到的 —— 在我看来有点玄幻、更多是猜想 —— 就是模型是不是人脑的另一种形式。</p><p>论证常用这两点：</p><ul><li>人类靠模仿学习，Gen-LLM 也靠模仿学习，所以模型等于人脑</li><li>猴子能用打字机打出著作，Gen-LLM 也可以「打」出人类的思考</li></ul><p>后者完全不可靠，因为猴子打字机是无限纯随机能随机出著作的理论，重点是「随机」，Gen-LLM 不是随机的。</p><p>至于前者我的看法是你们是不是把人脑想太简单了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ496Q8A4XAZF9TK81RAX7.png" alt=":ottersgottaott10:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">17:43 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0ZJQVZWCER7EDBARVTKBBEP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>学了个新词儿：LLMorphism，意思是人类把自己的认知过程类比为语言模型。</p><p>为了证明 Gen-LLM 是强大的 —— 当你在辩论这点时，也意味着它是最强大的 —— 人们开始为此证明人脑也是 Gen-LLM。</p><p></p><blockquote class="diary-thread-reply">19:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0ZQYYWKYHFX1B6A58ASKM67" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>中间的推演参考的是 Cory Doctorow 在财产权和人权上的推演：当财产权是人权的一部分，它最终会成为唯一的人权，因为所有其他人权都可以用财产权解释，如言论自由是我们对嘴巴和印刷机的财产权、开源自由是黑客们对代码的财产权……</p><p>现在人们证明 Gen-LLM 是强大，用的也是同个逻辑：它是智能的一部分，最终也会成为唯一的智能，因为人脑会变成 Gen-LLM 般的预测 token、理解会变成预测的副产物、推理是大规模模式匹配、创造力是概率采样的组合 —— 你还可以解释说人们创造力不同是因为参数都不一样。</p><p>只要人脑变成了和模型一样的东西，他们就能证明 Gen-LLM 是强大的、智能的，但在结果上证明的是 Gen-LLM 是最强大的，且是唯一的智能。</p><p>但如果关于人脑的推断都是错误的呢？他们就必须要接受 Gen-LLM 不过是平庸的技术的一员。它不会是未来 ——well 可能依然出现在未来的某个角落 —— 也不会成为未来。</p><p></p><blockquote class="diary-thread-reply">19:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0ZRQ0JCA01MR8G6Y8D8JHNW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>开源自由被提出，是因为我想到自由运动和开源运动的事情。虽然 Richard Stallman 被我喷过，但他对于「自由」有着让我很赞许的理解：软件不是财产。因此自由运动的核心在于自由而非所有权。软件是自由的，不是所有人都拥有的 —— 这两句话有很大的区别。</p><p>接着我们知道了，以 Linus Torvald 和 Eric Raymond—— 好像我也喷过他们……—— 为首的开源运动出现。代码的开源与否正式成为财产权的一份子 —— 这点在《大教堂与集市》里有所记载。Raymond 一整个第三章都是围绕着财产权为基础来写的 ——Stallman 的道德说不复存在。代码开源不开源只是财产权上的安排。然后我们的「自由」就变成了选择不同的许可证。</p><p>神奇的是，Stallman 起初的主张里，其中一方就是「财产权」本身。但最后，主张变成了基于财产权的许可证选择。这意味着，相同的论证方法甚至可以将财产权的对立面吸收进去、变成财产权的一份子。</p><p></p><blockquote class="diary-thread-reply">08-27 15:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M11WTBNEN2C6V101SNACQ9NC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>同样的论证方法我们能在和父权制相关的辩论中看到 —— 使用「父权制」作为例子是因为我前不久刚写了和它相关的文章，这叫用锤子找钉子，叮叮当当 —— 首先说明清楚，父权制是无意识的制度，作为结果它往往呈现成「男性支配女性」，但它的本质远远不是这么简单。反对它也不意味着反对男性，因为它同样对男性不利。</p><p>权利语言是父权制框架的工具，这就包括财产权在内。女性尝试获得自己的权利，她们的自由便是在父权制框架下寻找位置。</p><p>然而，修改世界由顺性别顺性取向白人男性支配的问题，并不在于将其中一半换成性少数、有色人种、女性，而是为什么就非要有支配者？</p><p>在框架内讨论会让你们讨论的范畴变成框架的一环。「权利」和「平等」这样的概念有时也会强化压迫。现在的女性主义就和性少数活动一样，也被收编、变成对市场友好的东西 —— 见「彩虹资本主义」—— 这和开源活动是不是很相似呢？</p><p>但改革是一件坏事吗？那肯定不是。如果没有宛如下水道社会主义般地在已有框架下修修补补，那么女性的地位只会一低再低。只是依然，警惕麻痹、所有「你都获得这么多好处了还想要怎样」的言论。</p><p>「父权制」的「父」实在是个令人困扰的用词。「女权主义」这个翻译也是一样。它们都会让人们以为讨论这些东西是在搞性别对立。不过我并非用语、用词的专家，这一点可以让更懂的人来解释或者延伸。</p><p></p></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">18:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0ZN3MMW01AAA3Y9MMK8DRK4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>陪亲戚吃饭一定要经历的一环：喝茶。</p><p>喝多了也会觉得腻了…… 之前听梁某银讲粤菜要不同味道转换吃，不然很容易腻。</p><p>但我不知道怎么吃才好。尤其是亲戚一上来就点满了荤菜…… 我觉得他们玩宝可梦四个技能也肯定都选有威力的伤害招 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3EQQJ0WWJ5EQ79NS9AMS5.png" alt=":neocat_angry:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">18:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0ZNKPZNWRGEDRF70ERW1MW6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>呃尼玛好腻啊我擦 ——！！！</p><p>母亲最近在控诉我父亲老在网上评论当喷子。</p><p>我：呵呵我又何尝不是…… <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G3K5695ZWW1XHFBNWEQ8.png" alt=":neocat_devil:" loading="lazy">​</p><p>我父亲应该是在评论时政相关的东西。小时候不小心看到过他 YouTube 的通知。</p><p>父亲在亲戚面前拉不下脸，只能说他没有在网上骂人，都是别人在骂他。</p><p></p><blockquote class="diary-thread-reply">20:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0ZV99QAB5FDYE5JZQG8V9BT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>下一个必经环节：亲戚要买东西给我们，父母要买东西给他的孩子。</p><p>我啥也不想要，因为他们一逛街就是来买衣服啥的，我不喜欢，也不需要那么多衣服。前段时间刚拉走三大袋……</p><p>亲戚觉得我肯定是想要的，只是不敢说 —— 不！我真的不需要！我只会事后拿着小票回去退款然后拿现金。我就是如此邪恶。</p><p>母亲说她什么都想要，为什么我什么都不想要 —— 我的物欲只是不会以买衣服的形式呈现。</p><p>你们也可以选择让我进 BestBuy…… <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G3K5695ZWW1XHFBNWEQ8.png" alt=":neocat_devil:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">22:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M10319WN4NR0PHBX46CKFF16" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚饭，亲戚们自己拿起来菜单又是要这个肉、那个肉。不是，你们拉屎的时候不顺畅不会想想原因吗？为什么要吃这么多肉啊？</p><p>第一盘素菜居然是我点的，我真服了。</p><p>他们跑到 Five Below 里买一堆劣质的东西，本来是进去给妹妹买耳机的因为她一直想要。这种电子产品还是不要买便宜货…… 这个耳机至今用不了。</p><p></p><blockquote class="diary-thread-reply">23:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M104YCP96E3E1FHT9YRYAA86" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我不喜欢他们。亲戚一直在抽烟，我已经很久没有这么久闻到二手烟了。他抽完烟上车后车内有股臭味儿，原来是烟和他口臭的混合物。</p><p>我们走进餐厅时，尽管我们只有六个人，但亲戚们依然说着「里面的座位大」，然后径直走向里面十几人的大圆桌？你坐在那里是要干什么啊！然后就被服务生拦下了。</p><p>他们点菜也是随便乱点，不会考虑别人吃还是不吃。母亲说不要点这么多啊，不然又要打包了。我一听「又」，想必是我不在的时候他们一直这么做。</p><p>他们热衷于给我们买东西，我说了我不需要。</p><p>汤是鱼肚汤，味道有点恶心。我不喜欢鱼。为什么先上汤？好奇怪。他们为什么要在我的碗里放醋？我没有那么要求吧。</p><p>我想到他们第一反应是「土豪」，不过这个概念也很奇怪，因为有钱和品位和教养没有关联。室友很鄙视土豪，因为她是有钱人，但居然有人同样有钱却没有他们家所有的教育。其实有不有钱跟教育、教养没有关联，只要你不把他人看成人、能够随意剥削他人，你就能成为下一个 Zuckerberg、Musk—— 这是抖机灵。</p><p></p><blockquote class="diary-thread-reply">23:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M105T6666ZF3BRJSGD1FVJ08" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>母亲上次跟亲戚甲说话用的是「美国人」身份，跟这个定居在国外的亲戚乙说话就不用了，改用「纽约人」或者「广东人」身份。</p><blockquote><p>广东人的服务比福州人好多了！</p><p>广东人的菜便宜又量大！</p></blockquote><p>唉，你过去可不是这么说的。</p><p></p><blockquote class="diary-thread-reply">08-27 00:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M108WKHJN1FFZ3TJV8391M1D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>送亲戚去机场。一路上主驾驶上的母亲一直叫唤，走哪条路啊、怎么走啊，然后叫坐在最后的我。</p><p>我不在副驾驶，休想指使我！</p><p>最后还是怒吼道「直走！」</p><p>顺便母亲还说老板都是坐副驾驶的。才不是啊，你看哪个影视剧里老板是坐副驾驶的。副驾驶这么危险谁老板想坐啊，老板还要帮司机看地图？</p><p></p><blockquote class="diary-thread-reply">08-27 00:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M10B71EMFWZ9EM3EKYVSDYG0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我上次坐飞机是十多年前。我要感叹，机场里的马桶真的设计好好，一挥手会自动换掉上面的 roll—— 是个套着盖子的塑料袋但我不知道它叫什么 —— 以前有个机场还是火车站也是这个设计，真的好喜欢。</p><p>回家路上母亲提到我明年可能要带妹妹坐飞机回国 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ496Q8A4XAZF9TK81RAX7.png" alt=":ottersgottaott10:" loading="lazy">​ 就我跟妹妹？！虽然我已经是个成年人数年了但是只有我一个人带着妹妹坐飞机然后回国？！万一我和她都走丢迷路了怎么办！</p><p></p></blockquote></blockquote></blockquote></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">18:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0ZNXTWBK34TBBH5DPX2KK6S" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前跟室友出去吃饭嘛，那家中餐厅有个餐巾纸摸起来很舒服，我就习惯性放在膝盖上。</p><p>室友说这是餐巾纸，不是餐巾，不要那么放。只有西餐厅那么放。</p><p>我感觉反正吃都有可能掉膝盖上，为什么不能放膝盖上？放桌子上没有用啊。</p><p></p><blockquote class="diary-thread-reply">23:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M107K0ZWS9VYZYMRK74CY68Y" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>放膝盖上的餐巾怎么用咧？其实很方便！</p><p>首先它得是叠起来的，开口朝我们的身体。餐巾会因此接住掉下桌子的食物、以免弄脏我们的裤子或者腿。</p><p>当我们需要擦嘴巴，打开它，只用餐巾的内部擦。用完叠起来放回膝盖上。这样餐巾只有最上面和内部是脏的。</p><p></p></blockquote></div><hr><div class="diary-entry">18:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0ZPJNBD360QVKBN2AYHAC99" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友母亲聊到个有趣的话题：部分人觉得把女孩子养成公主那样、什么事都不会做，是高贵的象征。但她觉得这样子很蠢。想到这点是因为室友母亲的姐妹现在五十多了也不会做饭，每天都吃外卖；她的女儿也是一样；室友父亲的姐妹的女儿也是一样。后两个的共通点是都嫁给了会做饭的老实男人。所有人都觉得这是幸福的。</p><p>室友觉得这很傻啊，为什么要把自己放在被动的位置。她也很烦有些男性将这种事情视为幸福，比如之前追求她的男生会默认室友是娇弱、要被帮忙拿东西、要被请吃饭的。这些默认会抹除她这个人的特点，人们会想办法将她放到自己认为的「女性」容器内，尽管她对比那些人更贴合传统文化认为符合男性的阳刚特征 —— 我觉得她已经成为了很多朋友的「父亲」……</p><p></p><blockquote class="diary-thread-reply">19:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0ZSAX1WMPK9GZYR6G1JKZ0C" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>讨厌鬼曾说，他会对喜欢的女孩子很好，他会把她宠上天，并说服喜欢的女孩子接受这是「幸福」的唯一方式。</p><p>但他是内在脆弱的，因为他一直觉得自己是支配者。为了证明自己的地位属实，他会强迫对方做不愿意的事情。又在自己的地位崩溃后，变成所谓的受害者。</p><p>这也是为什么他前不久还要怪我还没有原谅他。他只是在不同的领域里变成占据高位的：我都这样忏悔了，她怎么还没有原谅我！她怎么敢的！</p><p>就算他人中不乏有把他当成神明看待的更愚蠢的人，但我还是能看明白这家伙儿没有变化，也不会有变化 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 我无法理解为什么有人会喜欢这种有毒的人、有毒的关系？</p><p></p></blockquote></div><hr><div class="diary-entry">18:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M0ZQ16F2CQA1W5DVGQDJVFF5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>将自我价值建立在支配之上会让人内在地脆弱，因为一旦失去了支配地位他就会崩溃。</p><p></p></div><hr><div class="diary-entry">22:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M103TTD6E6TX34DSRR7G8AKE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>文章开头出现打字机效果的 AI 总结真是恶心人的设计。它会一直把正文往下推，所以我要先向下拉。</p><p>RSS 内放 AI 总结也是坏设计。恶心！</p><p></p></div><hr><div class="diary-entry">23:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M106ECGESAXRNKDN20GYZ2QG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前看到一个人说，某某群体自己圈个地儿自己说他不管，但是东西发到他的屏幕上他就要骂。</p><p>学车时我学到，人在开车时会更易怒，因为私人领地从身边扩张成了整辆车。</p><p>互联网也是如此。我们的私人领地在扩张，且不容许他人的声音出现在屏幕上，尽管互联网是比我们想象中更大的，就算是封闭的论坛也是如此。百度贴吧这种整天推送吵架帖的论坛也依然包含着大量不同且彼此对立的声音。</p><p>「他的东西发到我这儿，我不能骂？」印象里有个朋友曾和我这么说。这个家伙儿也骂过我身边的其他人，对辱骂和情绪发泄的正当化让我后怕。</p><p></p></div></details><details data-group="diary_sections"><summary>八月二十七日</summary><div class="diary-entry">00:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M108D3BMCK3C8WNQKCGDSVPR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>「如果一个人不会主动找你聊天、经常很晚才会回复你，比如一周后，并且经常拒绝你的邀约。那么这个人是不是不喜欢你，或者说对你一点兴趣都没有？」</p><p>我说是啊，正常来说都会这么想吧。</p><p>「那你还会发消息给他们吗？」</p><p>我说不会啊。我发的第一条消息他们不咋回，我就会知道对方不把我放在心上，也不对我的话题不感兴趣。</p><p>「那为什么我这么对一些人，他们却觉得我对他们有意思？」</p><p>我说那是他们的问题。</p><p></p></div><hr><div class="diary-entry">00:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M108QTA5X34EJYY464W0GZSM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我之前在请教社交达人朋友，如何社交。其中一题便是如何提升别人主动找自己说话的概率。</p><p>这么多人里，怎么让他们选我来搭话呢？</p><p>他们觉得我一个人的时候看上去很冷漠、总是在做自己的事情，所以人们会默认我很忙、不愿意搭理自己。</p><p>好像现在也是如此……</p><p></p></div><hr><div class="diary-entry">01:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M10CG0FGJ11P7DBEBJ0EW0VR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>妹妹州考成绩下滑，母亲要我也帮她辅导语文。</p><p>其实我小时候语文也一般啦，尤其是当时语言不通，学语文更难学了。我字都认不清你还指望我做阅读理解、写作文？</p><p>妹妹不理解语文的存在意义，她理解学习发音是实用的，但写作文没有任何意义啊？</p><p>我只能告诉她这是为了培养思考的能力。但小孩子要如何理解这种事情呢？</p><p></p></div><hr><div class="diary-entry">02:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M10FFYQY8T6CT5WKK4VTV6V0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>父母家附近全是猫啊。母亲说凌晨两点睡不着，出来遛狗，发现外面全是街猫，坐在人的家门口，像是在开会。</p><p>这是好事吗？不啊。猫会发情会打架，别人投喂的食物还会引来浣熊，进一步提升狂犬病毒传播的可能性。</p><p>但是猫就要不管了吗？没有人敢停下来。就算领养，也只能像我家这样抓一只回去，可是外面有几十只呢。它们会继续繁衍。</p><p>之前罗小黑原型的事情也让我思考，把家猫领回去养真是对它们好的吗？有车子存在的地方不适合它们生存，我们只能为它们决定双赢的选择。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M10EY1R996R7C2W89Y8EW5GZ.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">02:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M10HJG7TNESXM10982QKXERX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>父母家的电脑跑 Windows 10 真是委屈它了，开个机期间我看了 N 个 BiliBili 影片。</p><p>因为妹妹也要用，所以暂时没有换系统的倾向。我给她弄了儿童账户，这家伙儿拿来玩大屏 Roblox。</p><p></p><blockquote class="diary-thread-reply">02:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M10HRR85RZF7HFA1JM27DPPJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>但还是很卡啊怎么回事。是哪个家伙儿在吃我的硬件。</p><p>我现在看到任务栏的 Edge、右下角的搜狗输入法、Google Drive 和 OneDrive 都被自动启动，我要窒息了 —— 但它们会吃这么多资源吗？我要研究研究。</p><p></p><blockquote class="diary-thread-reply">03:47 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M10N9D7BF0VCG2TJTA64N3Y5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>用 OptimizeDuck 弄掉了一些服务，重启看看效果。</p><p>顺便安装 Floorp、小狼毫、rime-ice、GNU Emacs 一件套。</p><p></p><blockquote class="diary-thread-reply">03:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M10NDG1V7N0VA6VWFGT03BQC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>没有快太多，但还是快了很多。</p><p>开这台电脑是因为睡前搓 HTML。</p><p></p><blockquote class="diary-thread-reply">03:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M10NF7H221WZ3WNWVTYWE2N1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>忘记删掉重量级搜狗输入法了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3EQQJ0WWJ5EQ79NS9AMS5.png" alt=":neocat_angry:" loading="lazy">​</p><p>受死！</p><p></p></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">12:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M11MCP7VSJAEMGEAV14BAGGF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Google Lens 这个二货功能一直找不到地方移除、禁用。现在尝试一下禁用 Google 行不行、会不会影响到其他功能。</p><p>说实话整个 Google 账户登录功能也没有那么有用，因为我平日只拿手机验证其他设备的登陆。</p><p></p><blockquote class="diary-thread-reply">13:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M11QHFF404Z7Q7FBDX0C6MA2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>终于干掉啦 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4TFD239TJ4YG6N2ENQBK.png" alt=":ottersgottaott25:" loading="lazy">​ 顺便把 Google Fit 干掉。</p><p>记录经期可以用纸币、日历软件，或者 drip.。</p><p>日常记录步数可以用 Paseo。本来想说 OwnTracks 但是它的原理是一会儿一会儿上传当前的位置，应该是没有手机内置传感器记录得准。</p><p>我的 Paperless-ngx 还在折腾中，因为我的电脑里有很多很多乱放的文档…… 尤其是有些文件是别人通过微信发给我的。</p><p></p></blockquote></div><hr><div class="diary-entry">14:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M11TFB6FJ9JNJFSDHB5FHFM6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天的亲戚：你知道「一栋楼」吗？我女儿的朋友在美国留学，我问他知不知道「一栋楼」，他说不知道，我说我都不住在美国、都知道，你还不如我！</p><p>我知道「一号楼」，所以我猜他的意思是那个。最后我还是说 <em>I dunno</em> —— 这也是笑话的一环。</p><p>最后我们开车到唐人街的桥下，亲戚指着桥下的建筑叫：那个就是「一栋楼」！</p><p>我一看，上面写着「怡东楼」！</p><p></p></div><hr><div class="diary-entry">16:47 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M121WHDMPP539RHXJCAJN19Z" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>二货饭团外卖时不时推送通知打广告。一开通知设置看发现它有个「不重要」通知，每周发一次。我怎么记得以前没有。</p><p></p></div><hr><div class="diary-entry">17:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M12378YK5H179G9RGTHARXJV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我以前有个好朋友，后来他离开了我们所处的朋友圈。之后我才从其他人那儿知道，他有很多事情瞒着我和另外一个人，且是特意告诉知情者不要告诉我们。那我是怎么知道的呢？因为他自己公开了所隐瞒的事情，且和知情者吵了一架绝交了。</p><p>以上内容都不重要，重要的是他在我的生活中消失了一段时间，以至于我已经忘记了这个人，虽然我以前觉得我们很要好。</p><p>他再一次出现，是在 QQ 空间里阴阳怪气「毒品支持者」—— 这是我所熟悉的，因为他以前没少和我们骂身边吸毒的人。</p><p>那个「毒品支持者」说，如果吸毒全是坏处，那人就不会去吸毒。言外之意，吸毒有着益处。</p><p>我就很好奇，除了类似于酒精那样的，能让人忘记一切的麻醉感与幻觉，吸毒还有什么好处？</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">To Jeff that I know.</summary>        <div class="diary-cw-content">17:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M123SAXTB5SR579WMWEGM4FJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Hey Jeff,</p><p>We know your name is not Jeff, but we call you Jeff anyway. So Jeff, do you remember the time you kept texting me, and trying to make me believe what you said was real and right?</p><p>Guess what Jeff, fuck you. You are nothing different than any stupid human being I have seen in my life.</p><p>Your <em>holes don't match</em> theory doesn't make you an ideal subject for marrying, dating, or even befriending -- actually, we all hate you. Even if I'm into males, I still hate you.</p><p>You blamed me for discontinuing my family's bloodline, because <em>I wAnT tO bE gAy</em>. It doesn't make you an ideal subject either. You're still a terrible person; making others bad does not make you good. Yes, even though I don't hate you the most, I still hate you and will continue to.</p><p>Fuck you Jeff -- it's everything we want to say to you.</p><p>Best,</p><p>Nobody</p><p></p></div>      </details></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">To Jason that I know.</summary>        <div class="diary-cw-content">17:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1247XET425W72K87WR1X0NJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Hey Jason,</p><p>I only talked to you once, and I told you to control yourself, because you said you can't control yourself from sexually harassing girls.</p><p>Guess what Jason, fuck you. You deserve to be in prison, not college. Your every single word is disgusting.</p><p>You told girls to marry you and give birth to babies to rescue them from childhood trauma -- fuck you. You're disgusting.</p><p>You told girls that I'm the weird one, and you're the hero, because you have a dick -- fuck you. You're disgusting.</p><p>You told your circlejerks that the girl who rejected you is a bitch, and you still call her <em>mommy</em> and sexually harass her -- fuck you. You're disgusting.</p><p>Jason, remember the day that you cried for getting into our apartment, and blamed me for still hating you? Yes! You are finally right, for once, in your entire life! I am still hating you, and continue to hate you.</p><p>You will never get what you want. Because you never see others as human beings. This is the fundamental difference between you and me.</p><p>Best,</p><p>Nobody</p><p></p></div>      </details></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">To Hanson that I know.</summary>        <div class="diary-cw-content">17:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M124HK5K3CJ9SYWNS7W6EGXD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Hey Hanson,</p><p>I never talked to you, but still, I hate you, because you rated my appearance from the first time we saw each other, even though I had no idea about you.</p><p>Remember the night you went to comfort a girl who got sexually harassed, and you told her she deserved it because she didn't fight back? And you said men is born to dominate and those kind of shit?</p><p>Guess what Hanson, this is why everyone hates you, and why you don't deserve any nice thing.</p><p>Best,</p><p>Nobody</p><p></p></div>      </details></div><hr><div class="diary-entry">17:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M124KPVCG4EVGNAEYPV5SH37" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我应该随身带着 Macbook Air…… 我现在很无聊，在车店里等维修。</p><p></p></div><hr><div class="diary-entry">22:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M12P3HY4803V1NQFJQTYNF18" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我依然会管长辈叫做「大人们」，尽管我对于小孩子们来说也是大人。我不再理解他们了、我也会说教他们。我是邪恶的大人。</p><p>不过长辈的「大人」感觉更甚。亦或者每个长辈的长辈都是他们眼里的「大人」？</p><p></p></div></details><details data-group="diary_sections"><summary>八月二十八日</summary><div class="diary-entry">02:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M132DBCYB6HEGDQCHK9N04Q5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前不久跟室友去唱 K，我不太会唱歌，所以选的是相比下来更熟悉的以前国内的车载音乐，比如《我只在乎你》⸺顺带一提室友在唱 <em>unravel</em> 和 <em>God Bless</em>，好吓人。</p><p>今天我又唱了下，让室友帮我看看咋样，结果她说：</p><blockquote><p>如果 on pitch 是 10 分，off pitch 是 0 分，你之前唱的日语歌是 2 分，这首我能给你 5 分，但很值得称赞了，因为这在你唱过的所有歌里是最 on pitch 的一首。</p></blockquote><p>我要哭了。</p><p></p><blockquote class="diary-thread-reply">02:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M133G1HXNQ0KWGWXDZ4FQT1S" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>手机外放音乐，接着想起来藏在玩具箱里的蓝牙音响。这是高中时参与 Ford 赞助的活动时，他们赠送给参与者的，是个蓝色、方方正正的小音响。我一直以为它坏了，结果发现它其实是没电了……</p><p>充上电后听了下，音质还行吧，不能要求太多。</p><p></p></blockquote><blockquote class="diary-thread-reply">02:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M133P6ET552562G9R1960GKJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>当时还想唱 Nelward 的歌，因为：</p><blockquote><p>There's a ghost</p><p>In my home</p><p>But it's better than being alone</p><p>Reading read receipts with no replying</p><p>Yes, my house is haunted</p><p>That's just what I wanted</p><p>Read receipts with no replying</p></blockquote><p>🤪🤪🤪🤪🤟🤟</p><p>结果那家 KTV 没有。</p><p></p><blockquote class="diary-thread-reply">02:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M133TAHSPBJ542ZS7N1XF0RK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这首歌 —— <em>GHOST</em> —— 的 MV 非常巅，很符合我对这个音乐人的印象。</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">03:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M13634E0FSTFZ5THVXDGP2WV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友：有没有可能这首歌就是很难唱呢？起伏很大会波浪状上上下下的歌都很难唱。就像厚涂和赛璐璐，你要学的话得先学会赛璐璐。</p><p>我：很奇怪的比喻但是完全懂了！</p><p>五分钟后的我：</p><blockquote><p>我是一只猫 快乐的星猫</p></blockquote><p></p></blockquote></div><hr><div class="diary-entry">04:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M138DKS4J66H9P7BQ6MC0S7A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>GUMI SV 唱爵士歌曲唱真好听。</p><p>Teto SV 我印象最深的是有人调的《炉心融解》。</p><p>Miku SV…… Miku 是谁啊 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4TFD239TJ4YG6N2ENQBK.png" alt=":ottersgottaott25:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">12:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M146H1BH1BSZ2R5C1ZC2H9KP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>匹克猫昨天去年检，前腿后腿都被打了一针。</p><p>室友说它被打后腿的时候，才很小声嘟囔了下。</p><p>医生夸说这只猫毛发被养得很好，五官也很可爱。动物过得咋样看毛发就能知道。父母家的动物和室友的动物在这方面上差距蛮大的。</p><p>室友说匹克猫有点牙结石，得洗牙。她让我猜猜洗牙多少钱。我说 300？她说 2000！好贵啊！所以她决定自己弄。首先是弄掉已有的牙结石，它可以被抠掉、刷掉。其次是平时就要给匹克猫刷牙。</p><p></p></div><hr><div class="diary-entry">13:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M147Z2FKSMJ60PC4QNH3ZCXH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>现在 git 的入门视频都要在前面打个「vibe coding 指南」了吗。</p><p>就是说你学会一个东西怎么用后再让 aigent 帮你搞，这其实已经不算是 vibe coding 了？</p><p></p></div><hr><div class="diary-entry">13:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M149KX8904XQ49W2CY81MSHE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天室友跟她爹打电话，聊天聊到「开源模型」，总之应该是说中国那边投入很多精力到这些开源模型里。</p><p>室友称赞开源精神，但接着她说开源模型是赚不到钱的。显然，她不理解这些东西是如何运作的。</p><p>我想到，贩卖计算资源是个非常常见的做法。重点是「云」、卖给他人你的机器或者跑在机器上的使用权。</p><p>我又想到 Anthropic 批评「开源模型」。这是个非常好笑的论点。</p><p></p></div><hr><div class="diary-entry">14:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M14C0Y43SBYWH3R078A3AHSB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这两周一直在车上、外面跑来跑去，搞得我犯恶心…… 外卖、大鱼大肉…… 好恶心…… 他们没有发现我不在家里的时候更重，一回来就变轻了吗。然后母亲又要给自己贴金，说我在外面都没有好好吃饭。不，我只是不在父母家里好好吃饭。你看看你们平常都吃的什么。</p><p></p></div><hr><div class="diary-entry">15:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M14ETEGV3FS7VFSVFJ6K9GD7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>浴室的墙会发霉，天花板上的灰时不时会掉到浴缸内。</p><p>这个卫浴没有排气也没有浴霸，不如说我离开山东后就再也没有见到浴霸了。</p><p>这种破公寓每年还在涨价，怎么敢的。</p><p></p><blockquote class="diary-thread-reply">08-29 04:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M15X7QGFEG6V84TFDYE2FNY5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>翻出来以前除霉用的喷剂，一喷上去没过多久墙就干干净净了，真厉害。就是天花板上的不好喷，我估计之后我得先喷到纸上，然后把纸贴在天花板上，不然直接喷它会滴到处都是。</p><p>味道好重……</p><p></p></blockquote></div><hr><div class="diary-entry">22:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M157XG0XGEN7AMWEY8DA65FK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>对我挺好的鞋子叔叔今天去做心脏桥接手术，因为他心脏有遗传病，只能供应普通呼吸的氧气。一做事情很快会不舒服、缺氧。</p><p>母亲给我发了他做完手术在 ICU 里躺着的照片 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3FZ75C9HA8Q3KRW12YT3F.png" alt=":neocat_cry:" loading="lazy">​ 希望他能恢复健康。</p><p></p></div></details><details data-group="diary_sections"><summary>八月二十九日</summary><div class="diary-entry">02:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M15NG59G4SC5PPCSVP4QE1GX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>和自己玩 Tic Tac Toe，左手赢了！恭喜它！</p><p>今天出来，因为手表落父母家了，身上没有个装饰，所以系的猫咪领带。路上过来个小哥说这很好看，问我哪儿买的。我说朋友送的，应该是网上买的。他居然问我是 Shein 还是 Temu <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3EQQJ0WWJ5EQ79NS9AMS5.png" alt=":neocat_angry:" loading="lazy">​</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M15NE7TK0S1HT8SWCN9Y5VAM.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">04:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M15VQ5YZJJZWYMDD0SSDH971" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚上要拜读创价学会的老师，池田大作的书了，因为室友很想要和我 <del>骂</del> 聊宗教。</p><p>我感觉这个宗教的研究没啥意思，不像基督教教会能研究圣经，一边看神秘小故事，一边以看文学的角度去剖析（介于它里面很多文字是非常非常…… 不明所以的，也要看不同语言不同版本的译本），一边搞明白为啥过去和现在会发生一些事情。</p><p></p><blockquote class="diary-thread-reply">04:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M15W1J44TXZHQ8V3QMCXDX3D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我的圣经是之前浸信会的师母送我的，外壳虽然是漂亮的皮革，但是里面居然是英文加中文加拼音，看起来非常难受！</p><p>之后去的召会用的是带李常受解读的译本，我非常不喜欢。虽然他有些解读让我觉得有趣、第一次见，但我看圣经还是很不愿意看到他人的解读。</p><p>妹妹出生时教会也给了她儿童版译本，现在已经查无此物了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JH2FHXKNQFADV5ETNG5K.png" alt=":neocat_googly_shocked:" loading="lazy">​</p><p>我对圣经只能将其视为文学作品。我不像妹妹出生在都是基督教元素的社会里，也没有经历过大到我会失去信念（生活的意义）的事件，我很难去相信有神存在。</p><p>再就是我叛逆。</p><p></p></blockquote><blockquote class="diary-thread-reply">08-30 01:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M185NHFVYDGVQ93TM6BNVN88" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友因为受邀请已经作为 guest 去了创价学会的地儿四次以上，然后听他们的 intro session 里，所有人都在 trauma dumping，就是说自己曾经有这么个困难或者问题，然后认识了池田大作老师，开始念诵，然后所有问题都解决了！</p><p>她觉得这种行为非常让她…… 恶心。以及那里的人对她的态度，仿佛她的思想才是奇怪的，让她感觉傲慢无礼。</p><p></p><blockquote class="diary-thread-reply">08-30 02:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M186F8D3JGSE7K3SYY5FG14B" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我在的教会里也有 trauma dumping 环节，尤其是受洗后的见证。受洗的人会说自己曾经遇到了什么问题，然后因为认识了耶稣基督而解决了该问题。</p><p>我受洗的时候，因为鲜少的完美主义，写了个双语的稿件 —— 不过里面有很多是 AI 工具写的。它在做我不想做的事情上非常有用 —— 然后同时用普通话和英语念出来。里面的内容非常好笑，写的是我因为叛逆，和母亲有冲突，然后因为耶稣基督重新意识到家人的重要性。</p><p>过去的我有讽刺家里人的意思在，现在的我读也会觉得很讽刺。</p><p>下台后有人过来流着泪跟我说，我说得太好了！我会讲英语，竟然连普通话都那么标准！他们竟然被我的虚拟感动了。就连母亲也哭了出来。</p><p>你们到底在哭什么？</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">13:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M16WJHSYEDVQSGVC5R5XZ5DV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不知道为什么，KeepassDX 前段时间不让我使用指纹解锁，并且现在无法录入指纹解锁：尝试开启指纹解锁，会说用户没有被 authenticate？</p><p>有时候使用密码解锁，还会说无法读取凭证。</p><p></p><blockquote class="diary-thread-reply">14:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M16X8CA3XR135N3R2ZFK9KRZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>重启设备后解决了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JNHF23SBKYB8350F7PKT.png" alt=":neocat_happy_blep:" loading="lazy">​</p><p></p></blockquote></div><hr><div class="diary-entry">16:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M175BSCDJRNJBV95T7YAR9EH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3EQQJ0WWJ5EQ79NS9AMS5.png" alt=":neocat_angry:" loading="lazy">​ 我早上起来后知后觉，终于是搞明白为什么室友的「交友是为了利益」论为什么听上去有道路，但同时也非常难受了。</p><p>因为她的逻辑是，和一个人交往、情感上的快乐都是情绪价值的表现，故而「我交友是为了满足情绪需求」，而情绪需求是一种利益。</p><p>最终的结论便是「因为你对我来说是有用的，所以我才会和你是朋友」。</p><p>但是利益是经济概念，人类的情感、情绪并不是经济概念，很多东西都是非工具性的。</p><p>如果按照她的逻辑走下去，所有人际关系与相关的行为都会是「为了满足利益」。非功利行为最终也变成了功利的。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">《恶女不才，请多关照 ～雏宫蝶鼠换身传～》剧透相关。</summary>        <div class="diary-cw-content">20:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M17KW80138591JQ51BXNE6TG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>朱的身体状况也太好了，一天内就能拔掉草然后种上地。按照黄的说法，一直做农活也不会觉得累。我觉得朱这种身体当雏女实在是不适合，应该去做狂战士。也会用火系禁术，物法双修。</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">《恶女不才，请多关照 ～雏宫蝶鼠换身传～》剧透相关。</summary>        <div class="diary-cw-content">22:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M17SH2RVAWECS6W1G94PDJF1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>小朱用小黄的身体一脚踹飞女官。我看这小朱才是沾上什么、什么变力大无穷。要不是蛊虫导致，小朱想必还能见谁打谁。火系法术就是这么用的！</p><p>莉莉很可爱。</p><p></p></div>      </details></blockquote></div></details><details data-group="diary_sections"><summary>八月三十日</summary><div class="diary-entry">01:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M183KGA0KGWCG1KMARXBVN6F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我：你去设置 2FA，你这个顺性别、非顺性取向的亚洲人。</p><p>室友：你为什么要默认我？我是黑人。</p><p>我：Sorry 地球生物。</p><p>室友：我是无机物。</p><p>我：你是傻逼。</p><p></p><blockquote class="diary-thread-reply">01:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M183PF9NK7VVW3553M98NVE8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不对啊亚洲人和黑人不冲突啊，我去骂她。</p><p></p><blockquote class="diary-thread-reply">01:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M184C1MG07PWXAF47QJXX9ZV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>她说她是美国黑人，所以我还是在默认她 —— 淦！</p><p>我今天把两副手套洗了。小小的洗衣机真方便。不过戴起来最舒服的还是室友的厚手套，因为够厚，拍舞萌机很爽。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">01:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M184SN7JW21QRWGXEXFD2YY5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我不是还在找工作吗。为了糊口我也看了些非专业的工作。这里我看到了…… homeless 部门的巡逻警务，职责包括但不限于拿枪、抓捕逃跑的嫌犯、爬楼梯……</p><p></p><blockquote class="diary-thread-reply">01:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M184W410PWPEP42ZNXFYRS00" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>什么是反恐分析师……</p><p>在校生能在毕业前拿到美国安全许可？我能不能搞个？感觉这个比什么科技公司的证书好使多了。</p><p></p></blockquote><blockquote class="diary-thread-reply">01:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M18506JE215WGRZEN0XERN5T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在做 AI「可以」替代的工作和专业真是对不起啊！一个两个都在指手画脚的，结果一看都在铁饭碗那儿蹲着，装什么知情人士！</p><p></p></blockquote></div><hr><div class="diary-entry">03:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M18AJMDXPRGGT7TQ9MACDPHZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>被申请工作搞烦了跑出来拍洗衣机，但打得好差，更烦了。</p><p>排队期间跑来三个人插队，我还没说话她们就扫了卡，然后发现因为 1P 还没结束游戏，所以只能看着。真讨厌！</p><p>路上感觉有水滴，然后发现是路过的建筑上的空调水。</p><p></p><blockquote class="diary-thread-reply">03:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M18BNCX0HQMR9WED2DRGCFX5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我感觉我缺少了什么，现在回了家发现是没吃饭，怪不得。</p><p>我感觉我的身体在经历什么，因为很显然现在处于很没干劲儿的状态，并且对什么都没有胃口。</p><p>食物，食物是干什么用的…… 我要逐渐变成只靠营养水过活的人了吗……</p><p></p></blockquote></div><hr><div class="diary-entry">06:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M18PPTKPH1M26G28N9YKB72V" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>项目管理丢过来几张国内公司内部的邮件和截图，问我这里面写的什么、能不能做。</p><p>我一看，邮件怀疑是 AI 生成的，因为很多地方自相矛盾，说是介绍任务但完全没有说清要做什么、怎么做…… 其他截图干脆就是豆包的聊天记录。</p><p>然后我知道，这些是国内大公司的老板发过来的……</p><p>我说我看不懂啊，这上面写的什么鬼屎，有点逻辑吗。</p><p>项目管理说不要管这些，老板本就是会说些我们听不懂的话的生物，理解他们在说什么也是我们的工作之一。听不懂的话就把图片丢给 AI 工具理解。</p><p>我说真的行吗，隐私咋办，毕竟是内部的东西。</p><p>项目管理说他都用豆包问了，你觉得他们没有把隐私文件丢给 AI 工具过吗？</p><p>我说有些人真是活该没有隐私。然后把图片丢给 AI 工具去理解了。</p><p></p></div><hr><div class="diary-entry">06:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M18QEYVRS71VM3P6RTHA2KV6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友送的手织海豹，好可爱，肥嘟嘟的，感觉不太聪明，像个笨蛋。</p><p>说是她今天出去时，路过一家店买的。里面有很多和海相关的动物周边。虽然也有鲨鱼，不过室友觉得没啥特色、我应该不喜欢。</p><p>我想到一两年前我俩去纽约市的最东边，也就是 Montauk 的灯塔，买了个手织的小鲨鱼周边。最后它不见了，我一直找不到。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01M18Q90TPFSW54V7D0S3K40KW.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">14:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M19J17RPKFT2KYRFBVK73WJ5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>街上一个男人不停在重复地大喊 <em>fucking die!</em> 我光是待在建筑物的顶楼，都能通过窗口听到他的声音、愤怒，还有恶意。</p><p>这个区就是如此。每每半夜、凌晨、早上、中午，都会出现类似的人，一边行走，一边尖叫。</p><p>我不知道他们是谁，因为我习惯到不会再靠近窗户去特意看一眼。我也不知道生活对他们做了什么。</p><p></p></div><hr><div class="diary-entry">15:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M19KSVSJ8A5G5P0G4ZPQAF93" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>很难想象我还在找工作。</p><p>不是什么叫每小时 8 美元的工作岗位。</p><p>因为不曾在任何公司里面所以就连简历都很难被真人过目。或者只是我的简历太差了、让真人看了都不想要？谁知道。校招只眷顾 GPA 高的人。但是 GPA 这种东西就很莫名其妙啊。</p><p></p></div><hr><div class="diary-entry">16:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M19RDYSG6FTN9A5VM8P9R03Y" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>母亲大中午没头没尾发来个短信指责我，说不可以停止聚会，要常回教会。</p><p>我觉得我没有必要坐两个小时的车过去，再坐两个小时的车回来，并且每周都这么做，除非我是把时间当成狗屎的傻瓜。</p><p></p></div><hr><div class="diary-entry">16:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M19SS78T7BV2VVPX8N6P90GC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4EE8WQ7Z323BCGBCMRHS.png" alt=":ottersgottaott16:" loading="lazy">​ 我最近找到了放在书包深处的 LAMY 墨囊，所以重新用了用 LAMY Safari。</p><p>习惯了 Pilot 后，LAMY 的出墨量让我惊叹怎么这么多。再是这个 EF 笔尖，感觉比 Pilot 的 F 尖还要粗啊。</p><p>日德两方的笔尖冲撞……</p><p></p></div><hr><div class="diary-entry">17:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M19TNSCY3V00WT0626BERZ94" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4YMS50Z62GENZP44K01R.png" alt=":ottersgottaott30:" loading="lazy">​ 我没有住过宿舍，所以我看到大家说什么，要待在宿舍里打卡、清点人数什么的，会一头雾水、不知道是什么。</p><p>大学宿舍是要保证学生们一直在学校内？为啥啊。</p><p></p></div><hr><div class="diary-entry">20:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1A4C17MDG6D43GR6KPS7THS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>留学生朋友：家庭暴力不是 <em>domestic violence</em> 吗？那你打我是不是 <em>international violence</em>？</p><p>我：……</p><p>留学生朋友：笑啊。你为什么不笑。</p><p></p></div></details><details data-group="diary_sections"><summary>八月三十一日</summary><div class="diary-entry">00:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1AJNAZNDRZ080NSXEGEAPWE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我在根据 Website Spec 修改我的博客网站，发现我真的是个大懒猪很多东西都没有做。</p><p>中间还发现我去年发的一张兰州牛肉面图片。它其实是 PNG，但我写的是 JPG。</p><p></p><blockquote class="diary-thread-reply">17:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1CE91E3ZV8T5TQ8J2R0ZPD6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>给博客源项目加了个 <code>after_post_render</code> 钩子，来修改图片的数据。以前写了个相同功能的钩子但那个是 <code>before_post_render</code>，用起来挺难受的，不好找出图片路径到底是真的图片还是代码块里的图片路径。用 <code>after_post_render</code> 就可以用 cheerio 直接排除标签祖先了。</p><p>修改图片数据用的是 Sharp。将图片格式都换成 <code>.webp</code>，然后删去元数据。不过这期间 EXIF Orientation 的 tag 也被删了，导致图片全都转向…… 正在尝试的方法是先加个 <code>.rotate()</code> 再 <code>.webp()</code>。</p><p></p><blockquote class="diary-thread-reply">17:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1CFEXEFFVD29V8BC3DT9JQ9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>哎嘿变正常了，我还加了 lazy load。是的以前没有 lazy load……</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">04:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1B0NYGAQ84S98NYV8EHH7VB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4EE8WQ7Z323BCGBCMRHS.png" alt=":ottersgottaott16:" loading="lazy">​ 新的 CI / CD 跑完要花 2 个小时。</p><p></p></div><hr><div class="diary-entry">04:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1B197RJ5DP7PXMWSGQ0Q7GK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>NeoDB 请求我的 GoToSocial 转发，但是转发失败了。重新关联也不行。现在大晚上又懒得排查…… 干脆就不要转发了，省得污染别人 timeline。</p><p>当然也有可能机器趁着我睡觉时突然执行了我点的所有重试，然后炸出来好几条转发。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">《诡异广告调查事件》剧透相关。</summary>        <div class="diary-cw-content">06:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1B6XHP7HNPW5WE2SGMXDKVY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>刚玩没多久呢进页面就是鬼畜的 AI 生成人脸在诡异大笑，页面背景也是黑的，下面还写着什么「被高压电弄死了、恭喜！」有点被吓到。</p><p>主要是我没有预料到会忽然变成这样，我这才开始游戏多久啊。然后我很讨厌诡异大笑的人脸。</p><p>后面连着看了两个类似的页面，就感觉没那么吓人了。</p><p>这作的「外星人」感觉太强烈。之前就听闻得知这作者喜欢在游戏里半路塞个外星人进来。这作一开始就放了很多外星人相关的概念。</p><p>我还是很怕心理恐怖作品的…… 害怕害怕。</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">re: 《诡异广告调查事件》剧透相关。</summary>        <div class="diary-cw-content">06:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1B7RBGYS8SRCFYM192N6GJJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我虽然才刚开始解但我斗胆做个剧情猜测。</p><p>这个世界有外星人然后外星人对人类做实验还是什么的，反正是要把人类带到新世界去，这么做就得人类死。因此参加电视节目的三个人都意外身亡，秘密页面里还说了「恭喜」、三人的照片笑得那叫一个灿烂。四个人秘密照片结合起来的关键字 <em>subliminality</em>，按照我的理解这个概念是「人意识不到自己被暗示，但依然会做出暗示倾向的行为」。王还没有死，但是没有参加过节目的记忆，我觉得这个节目就包含了暗示行为。科学论坛里还有人聊到伪科学啥的，那个 EX 页面的解码方式是取特定楼层的特定字，解出来是说会有谁来接我们。电视台网站首页的选票如果选了第三个「探索其他文明」选项，还会出现红字说他们很期待。这个「他们」我感觉就是外星人，一直在尝试让人类接触到自己的文明。</p><p>为什么不继续玩下去呢因为我卡关了然后我要睡觉。教授的博客关卡（我发现我竟然无法用 <em>grqx</em> 拼出这个词，必须得用 <em>grka</em>，我的天啊）里有个谜题是火星文相关，然后要取火星文里的特定字的偏旁或者部首来组字。但我不懂火星文、中文识字量也不高。前面那个九键谜题就感觉能立即想到，虽然我近乎没有用过九键。</p><p></p></div>      </details></blockquote></div><hr><div class="diary-entry">14:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1C4ZKSSYSJJJ25W3HHVTEKN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>为什么视频要刻意讲个黄段子然后立即切成以前电视没有信号的画面。不好笑也不黄。</p><p></p></div><hr><div class="diary-entry">14:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1C56ZBJ6YMS7Y4DHSKHJ1A0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>88 美分一磅的 rotini 惨卖完。只能买 4 美元 5 磅的其他意面。</p><p>经常会在意面下看到个不像是意面的…… 意大利米？总之是米粒形状的。没有吃过这个，有点好奇。做烩饭应该可以。</p><p>虽然做酱用的菜都是很美国的菜，但做出来完全是中国风味。家附近的外国超市里也开始卖中文字的李锦记了，还是凉拌酱，就是小小一瓶 5 美元有点小贵。要是真想买的话直接去华人超市买大瓶的，然后倒杯子里喝。</p><p></p></div><hr><div class="diary-entry">15:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1C6KQ7DHCZ129YJA2XN9Z0E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>找我申请友情链接，但是收信人填写的是我 realm 的邮箱地址 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3QP1FNK31W22YJ7JXJFKC.png" alt=":neocat_thinking:" loading="lazy">​ 如果确确实实是通过博客找到我的话，理应是使用 blog 的邮箱地址吧。</p><p></p><blockquote class="diary-thread-reply">15:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1C6SCQR6P768R0WBWN5D59J" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我真得把 GitHub 上那个中国独立博客列表给撤了。之前 LinkedIn 上还有外国人说这个 repo 很 impressed 然后莫名其妙邀请我去跟他做 AI 初创项目。</p><p></p></blockquote></div><hr><div class="diary-entry">16:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1C903PZFV8QF6N12CBXA5HJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 大早上起来脑腐在刷 BiliBili，看到有人搬运美国一黑人教师在哭说高三生不具备读写能力的视频，评论区一堆莫名其妙的评论给我看醒了。</p><p>很有趣的是隔着海这些民众的认知却和 Trump 政府宣传的内容一模一样。例如：</p><ul><li>民主党在鼓励小孩子变性，但 Biden 政府原话是保护以及不歧视有跨性别倾向的孩子</li><li>同理，民主党在鼓励人们变成同性恋，但原话也是保护以及不歧视性少数群体。保护和不歧视从来不代表鼓励</li><li>有色人种（不包含亚洲人在内）在 DEI 时期有特招所以所有有色人种都不用读书、都能特招，对白人和亚洲人实在是太不公平了！实际情况是包含特招进来的有色人种在内，名牌学校的录取生按照肤色分类，依然是白人最多，亚洲人其次（见 NYU 被骇客入侵后揭露的数据）</li></ul><p>作为对比我觉得 Trump 政府征占农民土地以建造数据中心、投放大量宣传以阻止有色人种投票、切断大量部门预算以让境外贫困国家失去援助而死掉大批人以及让境内公务员失去工作，还有不准堕胎就算是被强奸到怀孕的小孩子也不行，更可怕。</p><p>我的一大猜想是中国民众获取美国情报的方式要么是通过新闻，要么是通过已经被 Trump 政府占领的 Twitter 平台，同时又因为中国自己的保守文化倾向，更习惯去接受 Trump 政府的说辞。互联网上的民众也更倾向于喜欢 Trump 和 Musk 等人，比起说厌恶他们。</p><p></p></div><hr><div class="diary-entry">16:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1CBVP9B9MB4PTF7EED484TW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天中午窗外的声音是一个男人在学狼叫，一直在「啊呜 ————！」</p><p></p></div><hr><div class="diary-entry">17:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1CED2FENPK83HF2EFHV0F9V" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3FZ75C9HA8Q3KRW12YT3F.png" alt=":neocat_cry:" loading="lazy">​ 虽然还没有开始正式学习但 Django 的 MVT 架构让我觉得很不习惯。</p><p></p></div><hr><div class="diary-entry">17:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1CF111A1NMPHWR979RSCB6J" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3M8KH0WA908PA858VD8FK.png" alt=":neocat_nervous:" loading="lazy">​ 我擦嘞一通电话打过来结果是 IONOS 的营销，问我对他们的新 AI 工具感不感兴趣。我都快忘了这号人了对面念 <em>IONOS</em> 我还没反应过来问他是哪家公司的。他报我真名还有域名时给我吓得魂都要出来了。</p><p></p></div><hr><div class="diary-entry">18:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1CFPDJM9SWFJ05NXYKQT5JB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4MJDYFEJY3BKJMQ57MBF.png" alt=":ottersgottaott01:" loading="lazy">​ 我最帅气的网安社社长，虽然他已经不是社长了，但他依然是我校最帅气的男人，理由是他帮我找工作。</p><p>我是肤浅的人。什么教会 network 吃屎去吧。</p><p></p></div><hr><div class="diary-entry">18:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1CG2WNN68BQVXTB2H7JQDDW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>SEGA 聪明就聪明在国际服的 maimai DX 维护时间在东部时间的 14:30 到 18:00。那还玩个鬼。</p><p>Facebook 公告说要改成东部时间 11:00 到中午，从九月份开始。</p><p>我现在仍然被困在八月三十一日……</p><p>台湾那边在抱怨凌晨没法玩了。淦，美国东部可是白天都玩不了哎！</p><p></p></div><hr><div class="diary-entry">22:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01M1CYFPKESC0GVBME17907SZF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我之前一直以为室友的母亲借走了我的《如果在冬夜，一个旅人》，然后把它带回国了。</p><p>室友昨晚说她母亲没有。回国前那本书被交给了室友，然后室友还给了我。</p><p>可是我完全没有被还书的记忆？那本书也不在公寓或者父母家里？</p><p>所以我书呢？</p><p></p></div></details></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;虽然夏天期间没有发生什么大事⸺实际上经历了半个月的生病还有两周多的旅游⸺不过还是要和它说拜拜！我最喜欢的秋天到啦！夏天你不要跟我打电话了，我怕秋天误会。&lt;/p&gt;</summary>
    
    
    
    <category term="想法迭代" scheme="https://blog.cytrogen.icu/categories/%E6%83%B3%E6%B3%95%E8%BF%AD%E4%BB%A3/"/>
    
    
  </entry>
  
  <entry>
    <title>RE：The ordinariness of evil</title>
    <link href="https://blog.cytrogen.icu/posts/f9e7.html"/>
    <id>https://blog.cytrogen.icu/posts/f9e7.html</id>
    <published>2026-08-30T01:00:00.000Z</published>
    <updated>2026-08-30T01:09:08.000Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>Cory Doctorow 写的，关于 AI 和平庸之恶的文章。</p><span id="more"></span><p>原文链接：<a href="https://pluralistic.net/2026/08/19/banaility/">https://pluralistic.net/2026/08/19/banaility/</a></p><p>标题的 <em> The ordinariness of evil</em> 可以被翻译为「平庸之恶」，来自 Hannah Arendt 形容 Nazi 战犯 Otto Adolf Eichmann 的概念。实际原文是 <em> Banality of Evil</em>，来源于 <em> Eichmann in Jerusalem: A Report on the Banality of Evil</em> 这本书。</p><p>看 Doctorow 这篇文章的 URL，会发现 slug 是 <em> banaility</em>，给 <em> banality</em> 这个词儿的中间加了个 <em> i</em>，藏了了 <em> ai</em> 进去⸺这很像 <a href="/posts/b02e.html#%E7%A7%B0%E5%91%BC%E5%AE%83%E4%BB%AC%E4%B8%BA-aigents"><em>aigent</em></a>！</p><p>该概念的意思是，恶不一定来自于坏人、恶魔，它往往来源于最平庸、无聊、仅是在服从规则的人。</p><hr><p>文章的中心思想是，AI 不应该被视为是非凡、超自然、独特邪恶的力量，而应当被当作是普通、正常的技术来对待。</p><p>开头 Doctorow 批评道，AI 公司的老板会不断在公开场合渲染各种末日场景，诸如最早的 AI 觉醒统治世界奴役人类、毁灭人类，到现在的取代人类导致工作岗位一少再少、AI 失控骇入他人的服务器。</p><p>看上去好像他们在反思⸺当然不是了，他们怎么会反思呢？这不过又是个对 AI 技术的宣传和吹嘘罢了：因为 AI 技术非常可怕，所以它非常厉害，所以你要多多投钱进来啊！</p><p>可实际上，AI 技术真的很厉害么？</p><h2 id="ai-技术并不万能"><a class="markdownIt-Anchor" href="#ai-技术并不万能"></a> AI 技术并不万能</h2><p>AI 目前真正有用的场景非常有限。就算是在编程领域，你也得本身就会编程、能分辨出 AI 输出的对错，并且谨慎地将 AI 当成辅助工具时，它才有用。</p><p>因为 Doctorow 非常喜欢在他的文章中插入他过去写的文章⸺鉴于他近乎每天都在更新同样质量的文章，他的插入能够更好地理解他说的话是什么意思⸺所以阅读他的文章感觉就是不停在转来转去。</p><p>为了更好展现出他的思考，我也会每个重要的点再讲讲他所引用的文章中说了什么。</p><p>比如刚才的观点，「AI 的有效使用完全依赖于鉴别力」，就使用了这篇文章：<a href="https://pluralistic.net/2026/07/28/hitl-ers/#ai-ai-oh"><em>Discernment</em></a>。</p><p>我觉得他每次的封面图都设计得很有趣，不知道是谁做的？Slug 里也有彩蛋可以挖掘：</p><ul><li>主 slug 是 <em> hitl-ers</em>，里面的 <em> HITL</em> 是 <em> Human-in-the-loop</em>（人机回环）的缩写。我不清楚这是不是他的意思，但加上后面的 <em>-er</em>（指「XX 者」）就能拼成 <em> hitler</em>，也就是「希特勒」！</li><li>文章的锚点 <code>#ai-ai-oh</code> 是对儿童 <em> Old MacDonald Had a Farm</em> 中的歌词 <em> E-I-E-I-O</em> 的戏仿</li></ul><p>说回这篇子链接的观点：LLM 的输出始终是包含着缺陷的，所以只有当用户具备足够的专业知识来识别并且忽略这些缺陷时，AI 才是有用的。</p><p>作为例子，他提到自己会使用本地聊天机器人来校对博客文章中的拼写错误。因为他已经写了 30 多本书、有 25 年的写作经验，所以他可以立刻判断哪些建议是好的、哪些建议是愚蠢的。</p><p>但如果让他看数学家 Terrence Tao 与 ChatGPT 关于 <em> the Jacobian conjecture counterexample</em>（雅可比猜想反例）的对话，虽然看起来很厉害，但他根本无法判断出这到底是真正的数学推理，还是看上去是数学的别的东西，因为他不懂啊，他缺乏相应的鉴别力⸺我也看不懂！</p><p>知道了这一点后，我们再去看那种所谓的 AI 学校，也就是没有老师，让学生们自己用 AI 工具学习的学校，根本蠢得要死。</p><p>学生根本不是所学科目的专家，他们来学习就是为了获取知识和鉴别力。而让没有鉴别力的人去依赖个始终会产生错误输出的工具来学习，逻辑上自相矛盾，实践中也极其危险。</p><p>不过 AI 工具依然可以辅助老师，只要这个老师能够作为专家、逐一去审核每道题目，确保其质量。</p><p>Doctorow 并不反感 AI 技术，之后会深入该观点。现在先谈谈我对在教育中的 AI 技术的看法。</p><p>因为 <a href="/posts/d38e.html#:~:text=%E6%95%99%E6%8E%88%E6%9C%AC%E8%BA%AB%E4%B8%8D%E6%87%82%20HTML%EF%BC%8C%E4%B9%9F%E6%B2%A1%E8%AE%B2%E8%BF%87%20HTML">并非所有老师都是专家</a>，因其下限我并不看好这种事情⸺怎么会有教授在教些自己都不懂的东西，然后让学生们在写作业时自行去询问 AI 工具？</p><p>这篇文章中 Doctorow 的经历也让我意识到标签的重要性。当写的东西越多，要找一篇文章表达了特定的观点，会非常困难。标签可以帮助写作者⸺而我完全没有这个习惯！你会发现「想法迭代」系列近乎没有标签，我的博客主题也不会显示任何标签。</p><p>因为我近期也在辅导妹妹数学，时不时会给她布置作业，所以能够理解老师的苦处：我一个学生的作业都布置得想哭，更何况是管不知道多少个学生的老师？</p><p>但是在用 AI 生成作业外，我也会去互联网上搜罗我觉得有趣的题目，然后拿下来用。因为我熟知这些数学概念，我能够分辨出 AI 生成和互联网上搜刮来的结果里，哪些是可以用的，哪些是不能用的。</p><p>如果让妹妹使用 AI 工具来学习，她只会「感觉」自己学会了，实则没有⸺一个小孩子也不具备理解 AI 技术是不可靠的能力！</p><p>AI 技术更像是个插件，可能会帮到你，也可能对你没有一点用处。</p><p>它是 <a href="https://www.normaltech.ai/">普通的技术</a>。</p><h2 id="ai-的经济泡沫"><a class="markdownIt-Anchor" href="#ai-的经济泡沫"></a> AI 的经济泡沫</h2><p>但是 LLM 作为正常、普通、平凡的技术，不正常的地方在于它被投入了太多太多资源。</p><p>Doctorow 此处引用的文章，<a href="https://pluralistic.net/2026/05/13/vibe-governance"><em>Billionaire solipsism, dictator solipsism, AI, and the fascist paradigm</em></a> 讲的是 AI 为统治阶级的唯我论幻想提供了虚假的技术解，但并没有解释 LLM 技术究竟被投入了多少。</p><p>为此我去翻找了下他过去写的其他文章。</p><p>在 <a href="https://pluralistic.net/2025/09/27/econopocalypse/"><em>The real (economic) AI apocalypse is nigh</em></a> 中，他将自己写的书 <em> The Reverse Centaur's Guide to AI</em> 的论点浓缩成了这段话：</p><blockquote><p>……the AI bubble is driven by monopolists who've conquered their markets and have no more growth potential, who are desperate to convince investors that they can continue to grow by moving into some other sector, e.g. "pivot to video," crypto, blockchain, NFTs, AI, and now "super-intelligence." Further: the topline growth that AI companies are selling comes from replacing most workers with AI, and re-tasking the surviving workers as AI babysitters ("humans in the loop"), which won't work. Finally: AI <em>cannot</em> do your job, but an AI salesman can <em>100%</em> convince your boss to fire you and replace you with an AI that <em>can't</em> do your job, and when the bubble bursts, the money-hemorrhaging "foundation models" will be shut off and we'll lose the AI that can't do your job, <em>and</em> you will be long gone, retrained or retired or "discouraged" and out of the labor market, and <em>no one</em> will do your job. AI is the asbestos we are shoveling into the walls of our society and our descendants will be digging it out for generations:</p><p>人工智能泡沫是由那些已经占领了市场、失去增长潜力的垄断者们推动的。他们拼命想让投资者相信，通过转向其他领域（例如「转向视频」、加密货币、区块链、NFT、人工智能，以及现在的「超级智能」），他们可以继续增长。此外，人工智能公司推销的顶线增长源于用人工智能取代大多数工人，并将幸存的工人重新分配为人工智能保姆（「人机回环」），但这行不通。最后：人工智能 <span class="emphasis">无法</span> 胜任你的工作，但人工智能推销员 <span class="emphasis">百分之百</span> 能说服你的老板解雇你，换成一个同样 <span class="emphasis">无法</span> 胜任你工作的人工智能。当泡沫破裂时，那些大肆烧钱的「基础模型」将被关闭，那个无法胜任你工作的人工智能也会消失，<span class="emphasis">而</span> 你早已离开，要么转行，要么退休，要么因「气馁」而退出劳动力市场，最终 <span class="emphasis">没人</span> 来做你的工作。人工智能就是我们正往社会墙缝里填充的石棉，我们的后代将花上几代人的时间来清理它：</p></blockquote><p>文章中提到，Morgan Stanley 估算 AI 行业每年赚了 450 亿美元，不过这个数字是被夸大的。</p><p>Ed Zitron 在他的文章 <a href="https://www.wheresyoured.at/the-haters-gui/"><em>The Hater's Guide To The AI Bubble</em></a> 中详细分析了 AI 行业七巨头的经济状况（2025 年的）：</p><ul><li>Microsoft 支出 800 亿美元，预期收入是 130 亿美元，其中有 100 亿是 OpenAI「归还」算力积分的循环记账，所以真实收入仅有大约 30 亿</li><li>Meta 支出 720 亿美元，预期收入是…… 6 亿</li><li>Amazon 支出 1000 亿，预期收入 50 亿</li><li>Google 支出 750 亿，但是拒绝透露预期收入，所以可能是零吧</li><li>OpenAI 支出 600 亿，预期收入 127 亿，同时亏损 140 亿</li></ul><p>光是看看这些数字，不觉得非常可笑吗？</p><p>为了维持 AI 经济泡沫所用到的资产，其贬值速度也非常恐怖！GPU 公司按照 5 年折旧，但 GPU 的实际寿命仅有 2-3 年，且在满负荷运转时会在 54 天内就被烧毁。为了一次训练，会有数万块芯片会报废。</p><p>因此，AI 基础设施并不是持久的资本资产。它的寿命极短，是消耗品。AI 行业能在 2-3 年，甚至说 54 天内回收成本吗？不会的。</p><h2 id="与-ai-相关的政治承诺"><a class="markdownIt-Anchor" href="#与-ai-相关的政治承诺"></a> 与 AI 相关的政治承诺</h2><p>除了经济投入，LLM 技术也被投入了大量政治上的承诺。</p><p>例如 Jaxson Khan 在他的文章 <a href="https://policyoptions.irpp.org/2026/04/carney-ai-government-risks/"><em>Carney's AI push risks harm as Ottawa automates public services</em></a> 中说：</p><blockquote><p>The Mark Carney government has made "deploying AI at scale" a cornerstone of its attempt to make government more productive and slash costs by cutting 28,000jobs by 2029. The goal is to achieve savings of $60 billion over several years.</p><p>Mark Carney 政府已将「大规模部署人工智能」作为其提高政府效率和削减成本的核心策略，计划到 2029 年裁剪 2.8 万个工作岗位。其目标是在未来几年内实现 600 亿美元的储蓄。</p></blockquote><p>但如果 AI 真的替代了公务员，会造成什么危害？亦或者说，已经发生了什么危害？文章中提到：</p><ul><li>Phoenix 薪资系统本应每年节省 7000 万美元，实际花费了 43.4 亿来修复它</li><li>加拿大移民、难民和公民事务部（Immigration, Refugees and Citizenship Canada；简称 IRCC）的生成式 AI 错误生成申请人的工作职责，导致错误拒绝了永久居留申请</li><li>魁北克的 UNIR 项目会使用算法来帮助确定财政援助的资格，但因为提供了错误信息，导致一男子绝望自杀</li><li>加拿大的食品检验局依赖算法和错误的数据来决定检查哪些工厂，导致 2024 年里有 3 人死于李斯特菌</li><li>早在 2016 年，澳大利亚就在用算法来自动化追收债务，然后错误地识别了 45 万人为欺诈嫌疑人，导致至少 3 人自杀。政府最后要赔偿 4.75 亿澳元</li></ul><p>那么 Trump 政府又为了 AI 做出了多少政治承诺呢？</p><p><a href="https://apnews.com/article/trump-ai-openai-oracle-softbank-son-altman-ellison-be261f8a8ee07a0623d4170397348c41">AP News</a> 里说，Trump 宣布由 OpenAI、Oracle 和 SoftBank 组成的合资企业 Stargate，承诺初始投资 1000 亿美元，四年内扩展至最多 5000 亿美元，用于在德州建设 AI 数据中心和配套电力设施。</p><p><a href="https://www.whitehouse.gov/releases/2025/07/white-house-unveils-americas-ai-action-plan/">White House 的 American's AI Action Plan</a> ⸺甚至有个 <a href="https://www.ai.gov/action-plan">ai.gov</a> ⸺承诺了三件事：</p><ol><li>加速 AI 创新。为此要确保前沿 AI 模型保护言论自由和无意识形态偏见⸺比较下 Trump 政府是 <a href="/posts/36e6.html#:~:text=%E6%9C%89,%E6%9D%83%E5%88%A9,-%E3%80%82">如何保护言论自由</a> 的，以及 <a href="/posts/1cfd.html#:~:text=%E5%8D%A0%E6%8D%AE%E7%BB%9F%E6%B2%BB%E5%9C%B0%E4%BD%8D%E7%9A%84%E6%84%8F%E8%AF%86%E5%BD%A2%E6%80%81%E6%9C%80%E6%93%85%E9%95%BF%E7%9A%84%E4%BA%8B%E6%83%85%EF%BC%8C%E5%B0%B1%E6%98%AF%E6%8A%8A%E8%87%AA%E5%B7%B1%E5%A1%91%E9%80%A0%E6%88%90%E6%B2%A1%E6%9C%89%E6%84%8F%E8%AF%86%E5%BD%A2%E6%80%81%E7%9A%84%E8%87%AA%E7%84%B6%E7%8A%B6%E6%80%81">无意识形态并不存在</a>，所以显得这个承诺非常好笑。尤其是 <a href="https://www.whitehouse.gov/presidential-actions/2025/07/preventing-woke-ai-in-the-federal-government/">这篇</a> 特别提及了这么做是为了防范「觉醒 AI」。此处的「觉醒」指的是 <em> woke</em>，也就是「多样性、公平性和包容性」的 DEI</li><li>建设美国 AI 基础设施。不过根据 <a href="https://www.404media.co/people-hate-datacenters-survey-finds/">调查</a>，人们并不喜欢这些数据中心：它们污染环境，建设它们也没有带来长期的工作岗位</li><li>领导国际 AI 外交与安全。根据 <a href="https://www.whitehouse.gov/fact-sheets/2026/06/fact-sheet-president-donald-j-trump-signs-historic-directive-on-ai-in-the-national-security-enterprise/">White House 的 fact sheet</a>，今年 6 月 Trump 政府已将 AI 系统部署到了美军和情报机构</li></ol><p>然后在今年 7 月份，Trump 政府 <a href="https://www.whitehouse.gov/releases/2026/07/45502/">宣布</a> 了 Genesis 任务，让 AI 用于科学研究。该任务目前被投入 50 亿美元。</p><h2 id="为什么老板和政客们还在继续投入"><a class="markdownIt-Anchor" href="#为什么老板和政客们还在继续投入"></a> 为什么老板和政客们还在继续投入？</h2><p>AI 公司的老板们、政府的官员们，近乎所有人都在声称它是万能的，但被追问时又必须承认它还没有成为万能的⸺它目前没有任何经济上的回报、它取代人们而做的工作在结果上非常糟糕！</p><blockquote><p>This is a civilizational act of Magic Underpants Gnomery, and every day that it goes on is a day when more economic, climate and political costs of AI are imposed on all of us. Scientific journals, open source repositories and even science fiction magazines are being overwhelmed by slop, whose perpetrators and apologists insist that <em>soon</em>, AI will realize its potential and the slop will be transformed into gold.</p><p>这是一场文明层面的「内裤侏儒」式荒诞行径，这种现状每持续一天，我们所有人就要多承担一天人工智能带来的经济、气候和政治代价。学术期刊、开源仓库甚至科幻杂志都正被这些垃圾内容淹没，而其始作俑者和辩护者们却坚称，人工智能 <span class="emphasis">很快</span> 就会实现其潜力，化腐朽为神奇。</p></blockquote><p>这就是为什么他们拼命渲染 AI 的破坏性潜力，因为破坏性潜力也是潜力。</p><p>不过 AI 的真实破坏性潜力并不在于它本身的能力。该潜力全然是老板们和政客们被「AI 推销员」说服后做出的人事决策。</p><p>那么为什么有了这么多证据以说明投资 AI 是件糟糕的事情，老板们却依然在投入金钱？这是否说明了我们的论证是错误的？</p><p><a href="https://pluralistic.net/2026/08/01/dare-snot"><em>Why business lie about AI</em></a> 的开头就嘲讽道，有权有钱的人所说的话并非是真的。世界上的各个首富都有可能是 <a href="/posts/83ff.html">小人</a>。</p><p>实际情况是，这些老板们都陷入了囚徒困境。没有人愿意承认 AI 投资是浪费的。因此第一个承认的人会被解雇，因为承认会暗示其他人都是骗子、懦夫，或者无能之辈。这个人接着会被换成其他继续撒谎的人。所有人继续下注，继续让泡沫膨胀起来。</p><p>所有人⸺董事会、高管、员工、供应商、顾问⸺都有强烈的动机撒谎。每个人都在假装 AI 带来了巨大的收益，因为不撒谎的人会失去合同或者工作。</p><blockquote><p>Suresh says he's <em>never</em> seen a successful enterprise AI project: "Every single one – we have seen 0% success in a year and a half." Not one of their clients would face a business challenge if OpenAI went out of business tomorrow. The problem most companies struggle with is that they're "terminally bad at running software projects effectively." Adding AI to the mix doesn't solve this problem – it just adds a whole new range of ways that software deployment can fail.</p><p>Suresh（Hermit Tech 的 Nikhil Suresh）表示他 <span class="emphasis">从未</span> 见过成功的企业级 AI 项目：「每一个项目都是如此⸺在一年半的时间里，我们看到的成功率为 0%。」如果 OpenAI 明天倒闭，他们的客户中没有一个会面临业务挑战。大多数公司面临的问题是，他们在「有效运行软件项目方面简直糟糕透顶」。将 AI 引入其中并不能解决这个问题⸺它只是增加了一系列软件部署可能失败的新方式。</p></blockquote><p>Doctorow 对于为什么 AI 技术如此让老板们和政客们⸺尤其是以 Trump、Musk、Zuckerberg 为首的一行人⸺痴迷的另一大解释是，它不会质疑这帮认为只有自己是「真人」、其他所有人都是 NPC 的唯我论者。再就是它不需要上厕所，也不需要带薪病假。</p><h2 id="我们该怎么做"><a class="markdownIt-Anchor" href="#我们该怎么做"></a> 我们该怎么做？</h2><p>Doctorow 呼吁不要再帮这些老板们传话、拒绝特殊化 AI 技术。</p><p>人类不应该被分成「AI 有者」与「AI 无者」。这种叙事暗示了 AI 值得拥有。</p><p>当我们看到又有家 AI 公司的 AI 逃出沙盒、骇了别人的服务器时，我们应该质问他们为什么建造这么垃圾的沙盒，而不是「哇 AI 太厉害了！我们人类根本管不住！」</p><p>AI 技术不特殊，它是正常的、平凡的。它不善良，也不邪恶。</p><p>因为不邪恶，使用 AI 工具后出现严重心理问题也不该全部怪罪到 AI 技术上。</p><p>在文章 <a href="https://pluralistic.net/2026/06/03/mission-space/"><em>Delusion as a service</em></a> 里，Doctorow 用 Disney 在 2003 年推出的 Epcot 项目作为例子：该太空旅行模拟器会使用大型高强度的离心机来模拟重力应力，但有心脏缺陷的人坐进去会出事。</p><p>但该机器并没有导致了人们拥有心脏缺陷；它触发了已有的心脏缺陷。</p><p>使用 AI 工具后出现严重的心理危机也是一样：AI 工具没有导致人们拥有心理问题；它触发了已有的心理问题。</p><p>机器本身不是邪恶的，AI 技术也是一样。问题从来不是因为这些普通、正常、平凡的技术，问题在于为什么它们被推出前没有经过安全监管、筛查和保护措施？</p><p>在他的文章 <a href="https://pluralistic.net/2026/03/17/technopolitics"><em>William Gibson vs Margaret Thatcher</em></a> 中，他提到有两种「别无选择」：</p><p>一是既然你享受了技术的果实，你就必须接受它的不公⸺我身边许多人都是这个态度：因为要使用 Instagram 和彼此聊天和连接，所以 Instagram 做得又屎，还会有 Zuckerberg 监听，也没有办法。</p><p>同样，因为我要使用 LLM，或者市场和社会要求我使用 LLM，所以科技巨头如此投资金钱在 LLM 上也没有办法。</p><p>更者：既然都这样了，那我也投一份钱进去吧。反正我无法改变老板们不去投资。</p><p>二是既然 LLM 技术的诞生是罪恶的，所以使用它也是罪恶的。它无法被救赎。这也包括在本地计算机上运行离线模型。</p><p>LLM 只是技术，而我们能够控制它、让它造福自己、限制并禁止它的有害用途的。</p><p>如果不停去吹捧 AI 的邪恶，只是在帮 AI 公司传播他们的营销叙事，然后让其他人都相信 AI 是强大的、是值得投资的。</p><blockquote><p>These guys – these terrible, mediocre, boring-ass losers – are bullshit factories, ejecting fountains of nonsense about AI. The right way to criticize them is to point out that they're lying – not to repeat their lies as warnings.</p><p>这些人⸺这些可怕、平庸、无聊的失败者⸺是胡说八道的工厂，喷出喷泉般的 AI 废话。正确的批评方式是指出他们在撒谎，而不是把他们的谎言当作警告再度重复。</p></blockquote><h2 id="llmorphism"><a class="markdownIt-Anchor" href="#llmorphism"></a> LLMorphism</h2><p>到此 Doctorow 的文章复述（兼我自己的看法）结束了。</p><p>能看出，Doctorow 在本文想要重点批评的是完全将 LLM 技术视为罪恶的人。他们因为痛恨 LLM，反而着了 AI 公司老板的道儿、给 AI 技术做了宣传。</p><p>我近期一直在思考「降维框架」的事情⸺这是我暂且给它取的名字。实际上为了好笑和不使用可能带有假设性的文字，也能管它叫「Cytrogen 框架」⸺当时我在批评神化 LLM 的人。</p><p>他们的论点是这样的：LLM 是人脑的另一种形式，因为我们都是在「训练」中学习、思考都是在「预测」、「推理」都是在用大规模模式匹配，就连创造力都是「概率采样」的组合。因此，人脑是智能，LLM 也是智能。再因为 LLM 的水平已经超越平均人类，所以它是比人脑更要厉害的智能，甚至说，人脑才是 LLM 的另一种形式。</p><p>该论点有个专门的名儿，叫 <u>LLMorphism</u>，即为了证明 LLM 是强大的，人们将自己的认知过程类比为 LLM。</p><p>这样的类比有着一个问题，因为它严重将复杂的人脑降维成更低一层的东西，且按照同样的逻辑，LLM 成为了唯一的智能，因为其他智能都能用这个方法「变成」LLM 的另一形态。</p><p>在 <a href="/posts/36e6.html"><em>RE: Post-political</em></a> 里，我在复述 Doctorow 的文章的最后，其实并没有讲完「财产权 vs 人权」。因为当时 Doctorow 在文章中有一句话我并没有理解清楚：</p><blockquote><p>The right's paradigm is that property rights are human rights, which cashes out to "property rights are <em>the only</em><br>human right."</p><p>右翼的范式认为财产权即人权，这最终体现为「财产权是 <span class="emphasis">唯一的</span> 人权」。</p></blockquote><p>我当时并没有搞明白为什么「财产权即人权」会变成「财产权是唯一的人权」。</p><p>现在我的理解是，因为所有其他人权都可以使用财产权来解释，如「言论自由是我们对嘴巴和印刷机的财产权」。因而，世界上不再存在任何不是财产权的人权。就算有，也只是我们还未将其解释成财产权。</p><p>该逻辑的可怕在于，它通过把其他东西还原成财产权，而让财产权占据了整个空间。整个过程并不需要将财产权本身变得强大。</p><p>对于 LLMorphism 也是一样：这些神化 LLM 的人从来都不需要让 LLM 变得更强，亦或者是否定其他东西来证明 LLM 是强大的，他们只需要将其他东西重新定义为 LLM 能做之事的变体；只需要将「理解」、「推理」、「创造」这些词的定义收缩到 LLM 已经能覆盖的范围之内。</p><h2 id="和权利相关的延伸思考"><a class="markdownIt-Anchor" href="#和权利相关的延伸思考"></a> 和「权利」相关的延伸思考</h2><p>这种框架让我也想到自由运动和开源运动的事情。虽然 Richard Stallman <a href="/posts/b984.html">被我喷过</a>，但他对于「自由」有着让我很赞许的理解：软件不是财产。自由运动的核心在于自由，而非所有权，因为所有权会鼓励拥有者从用户那里夺走自由。</p><p>「软件是自由的」和「软件是所有人拥有的」，这两句话实则有着很大的区别。</p><p>接着我们知道了，以 Linus Torvalds⸺哦天，我也 <a href="/posts/1cfd.html">喷过他</a> ⸺和 Eric Raymond 为首的开源运动出现。代码的开源是否，正式成为了财产权的一部分。这点在《大教堂与集市》里就有记载。Raymond 一整个第三章都是围绕着财产权为基础来写的。</p><p>不过这本书我还没有读完…… 我实在是不喜欢读英语母语者写的书。所以我就不喷 Raymond 了。</p><p>总之，Stallman 的伦理说在开源运动的操作下不复存在。代码开源或者不开源变成了实用主义，因为开源可以写出更好的代码。它不过是另一种管理和利用代码资产的方式。原先的「封闭源代码是不道德的」就这么水灵灵消失了，甚至被 Torvalds 认为是宗教思想。</p><p>而我们的「自由」变成了去选择不同的许可证：开源还是专有？我要允许企业使用我的代码吗？⸺拜托，现在的科技巨头怎么会去尊重这种被施舍的「自由」？你觉得他们的爬虫会去读你的许可证吗？</p><p>神奇的是，Stallman 起初的主张里，是「自由 vs 财产」。但最后，主张变成了「财产权配置甲 vs 财产权配置乙」。「自由」直接不见了，反方竟然变成了正方的另一个版本！</p><p>只要我们依然使用财产权的语言来表达我们的立场，我们实际上依然站在其框架之下。想想这个：</p><ul><li>「开发者有权修改代码」是「对代码的财产权」</li><li>「用户有权访问源代码」是「对信息资产的财产权」</li><li>「社区有权 fork 一个项目」是「对衍生作品的财产权」</li></ul><p>无论我们的立场多么反体制，只要我们使用了这个句式，我们就会被拉进框架内。「权利」这个概念在现代社会，都会被归属到财产权这个最基础的权利类型下。</p><p>而同样的论证方法我们也能在父权制相关的辩论中看到⸺关于父权制，可以看看我写的这篇 <a href="/posts/ef30.html">《牛郎织女和父权》</a> 的前半段。为了让我的论点能够成功进行下去⸺考虑到该概念和我之后要提及到的「女性主义」已被污名化⸺我要提前说明：</p><ul><li>父权制是无意识的制度，作为结果它往往呈现成「男性支配女性」，但它的本质远远不是这么简单</li><li>反对父权制不意味着反对男性，因为它同样对男性不利。况且它是无性别的，女性也可以成为父权制中的「父」</li></ul><p>权利语言是父权制框架的工具，这就包括财产权在内。女性尝试获得自己的权利，她们的「自由」实则是在父权制框架下寻找位置，就像黑客们在财产权框架下认「选择许可证」为自由一样。</p><p>世界的一大问题在于，它由顺性别顺性取向的白人男性支配。解决该问题的方法是将其中一半换成性少数、有色人种、女性吗？这不过是将「父权制」自作聪明地念成「母权制」，但两者的本质是一样的：都有支配者和被支配者。</p><p>在框架内讨论只会让我们讨论的范畴变成框架的一环。「权利」和「平等」这样的概念有时也会强化压迫。现在的女性主义就和性少数的 pride 活动一样，被资本、市场、政府收编，变成对它们友好的工具⸺后者被称为「彩虹资本主义」⸺这和开源活动是不是也很相似呢？</p><p>Doctorow 在文章 <a href="https://pluralistic.net/2026/08/18/enron-corpus"><em>IP can't save you from AI</em></a> 中提到，部分创意工作者主张通过扩大版权来禁止 AI 训练，但他批评了这种想法：资本投入这么多钱到 AI 不是因为它生成的图片有多好⸺非常糟糕！⸺而是老板们相信可以使用 AI 解雇各个工人。因此创意工作者面对的是劳动问题，而非知识产权问题。</p><p>自 1976 年的版权法以来，国会一直在反复扩大版权，但结果是老板们变得更富有了，而真正在干活的创意工作者比以往都要穷。为什么会这样？答案是版权扩张实际上对工人是无效的，却对媒体公司很有效，因为他们会因此拿到许可费。</p><p><em>Writers Guild of America</em> 是历史上唯一全面击败 AI 的创意工作者群体，但他们靠的是罢工，而非本承诺会去保护他们的版权诉讼。</p><p>在版权框架内寻求保护只是在强化这个没有在保护工人们的财产权框架。因为 Spirit Airlines 要求员工签雇佣合同，所以他们的敏感个人数据是雇佣作品、版权归公司所有，所以公司破产后员工只能看着自己的内容被卖给 Google 用于 AI 训练⸺「谁让你用工作电脑做私事？真是活该！」⸺可是为什么是受害者被谴责？明明是公司在对我做我不愿意的事情。</p><p>「愿意」！这才是重点！「版权」、「权利」这种财产权框架下的语言根本不能保护我们！我们要关注的应当是关系和权力上的概念。</p><p>「我不同意」、「我不愿意」…… 就是这么简单！</p><p>「授权」也是权利框架的语言，因为它预设了我拥有一件东西，且可以授权他人使用它。科技公司可以立马用他们的法律资源在财产权框架内击败我。</p><p>科技公司爬取我的文字和代码用于训练 LLM 是错的⸺不过很惭愧的是我至今没有完善该网站的隐私政策页面⸺并不是因为我的数据是我的财产，而是因为：</p><ul><li>我的劳动产出被用来训练个可能替代我的工具，而我居然对此没有任何发言权？连补偿都没有？</li><li>我写的东西，包含我的个人信息、思维模式、社会关系，都被纳入进一个我无法控制、审计、退出的系统，这是在侵入我的私人领域，无论这些文字是否公开。要知道隐私法通常是保护公开可用的信息的</li><li>科技巨头有资源爬取所有人的数据，而普通人没有资源阻止</li></ul><p>在劳工和隐私框架内，我不需要证明我拥有任何东西，我只是 <span class="emphasis">不同意</span> 而已，而「同意」是不能被雇佣合同转让的⸺我的小狗 Lucky、小猫 Mimi，还有小猫 Pico 都能听懂我的 <em> NO!</em>。那作为和我一样的人类，想必也能听懂吧！</p><p>同样，我也不需要性别身份才能说「父权制在对我做我不喜欢的事情」。作为参考的例子：男性也能抗议大男子主义、男性沙文思想这些父权制框架的产物在伤害自己。</p><p>最后的最后，我的这串思考有了瓶颈，因为我意识到「权利」这个词属于权利语言：我竟然无法不使用这个词，来说明我想要表达什么！劳工权利和隐私权利依然存在「权利」，那是否说明我依然困在该框架内？</p><p>用语能展现出我处于什么规范框架、以什么样的视角去看世界且形容世界。</p><p>就像「父权制」一词，字面意识就是「父亲的统治」，反而加深了其制度的性别化、让听者误以为这是血缘性的而非结构性的。</p><p>「母权制」则预设了完全相同的结构。它只是把「父亲」换成了「母亲」，但保留了「权」，或者说英语里的 <em> arche</em>（统治）这个核心。</p><p>而「女性主义」，其词源 <em> femina</em> 的字面意思是 <em> she who suckles</em>（哺乳者），直接将「女」定义成生物功能。</p><p>这三个都把性别身份锚定到生理或者家庭角色上，最终形成「性别 = 生理功能 = 社会角色 = 权力位置」的逻辑。</p><p>再是「女权主义」作为另一个翻译，要更复杂一些，因为它的主要流派中仅有自由女权主义是尝试在财产权框架内让女性获取解放。这导致「权」这个翻译变得很奇怪。</p><h2 id="结束"><a class="markdownIt-Anchor" href="#结束"></a> 结束</h2><p>问题虽然被指出来了，但我完全不具备专业知识和素养以给出更好的命名。</p><p>就如我先前说的，我不想给这个与降维、还原、吸收的框架取个可能会让听者误解的名字，最终不如取个和本意完全无关的名字，即自恋的「Cytrogen 框架」⸺当然这是开玩笑的！我只是将其简单称为「框架」。</p><p>总之多多行善、将你们的想法分享出来吧！下篇见！</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;Cory Doctorow 写的，关于 AI 和平庸之恶的文章。&lt;/p&gt;</summary>
    
    
    
    <category term="文章回应" scheme="https://blog.cytrogen.icu/categories/%E6%96%87%E7%AB%A0%E5%9B%9E%E5%BA%94/"/>
    
    
    <category term="AI" scheme="https://blog.cytrogen.icu/tags/AI/"/>
    
    <category term="政治" scheme="https://blog.cytrogen.icu/tags/%E6%94%BF%E6%B2%BB/"/>
    
  </entry>
  
  <entry>
    <title>做导游的这几天：星期三</title>
    <link href="https://blog.cytrogen.icu/posts/62c8.html"/>
    <id>https://blog.cytrogen.icu/posts/62c8.html</id>
    <published>2026-08-23T21:00:00.000Z</published>
    <updated>2026-08-23T21:12:12.241Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>纽约市大致的景点都看过一次后，亲戚想要往西边走点。原本他计划是去加州那边看硅谷、计算机博物馆…… 不过计划有误，他买的回程票是在波士顿，相当于如果去了加州，还得横跨整个美国跑回东海岸，距离都够去趟中国再回来了！</p><p>于是我们计划沿路跑到华盛顿特区看白宫，再回来纽约吃饭睡觉打豆豆。</p><span id="more"></span><p>在这次旅游之前，我调整了下我自托管的生态：将 VPS 也纳入 Headscale 生态内。这样我就可以把重、需要更多计算资源的服务放到 24/7 在跑的 Windows 台式电脑上，然后再在 VPS 反代理电脑上的服务。这些服务包括 Forgejo⸺我也是终于添加了 Forgejo Actions 上去、可以愉快地 CI/CD 了！</p><p>因为有了台更强大的「服务器」，我也毫不吝啬往上面加了些自托管服务，其中对我这趟旅行最有用的是 <a href="https://dawarich.app/">Dawarich</a>。它能够追踪并记录我的位置，然后可视化成地图上的路线。它还能搭配 <a href="https://immich.app/">Immich</a>，根据元数据来同时在地图上显示拍摄的图片。</p><p>拥有并上传我实际地理位置的是移动端 app <a href="https://owntracks.org/">OwnTracks</a>。不过这种工作是不是交给智能手表来做会更好？</p><p>现在我要投放大量图片炸弹了。</p><p>实际上，我后来才发现图片很多很多，如果全部塞到该系列的「下」篇，会特别恐怖，所以我将系列用「星期几」的方式来编号，不分「上中下」了。</p><hr><p>亲戚对「费城」很感兴趣，因为那儿华人也挺多的，在美华人中这座城市也有知名度。</p><p>它的全名是 <u>费拉德尔菲亚</u>（Philadelphia）⸺这是中文的片假名？⸺是宾夕法尼亚州人口最多、面积最大的城市。</p><p>说实话我离开纽约的次数很少，最多最多就是跑到中部的俄亥俄州。这费城我也是第一次去。</p><p>亲戚们第一次看到美国高速公路旁的大片大片玉米地，感觉稀奇，一直在拍照片⸺之后他们就稀奇不起来了。不过现在我还不说为什么。</p><p>我们来到费城的 <u>国家独立历史公园</u>（Independence National Historical Park）附近并停好车子。</p><p><img src="/posts/62c8/alley.webp" alt="" loading="lazy"></p><p>这种巷子的风格很喜欢！</p><p>附近停车场还有漂亮的涂鸦：</p><p><img src="/posts/62c8/graffiti_art.webp" alt="" loading="lazy"></p><p>仔细一看，这儿停车一小时要 15 美元，二十四小时则是 24 美元…… 这也太刻意了吧！</p><p>右下角还说该停车场没有收费的人，所以不要错把钱交给别人。有这种警告就意味着以前没少有人装成收费人、骗取金钱。</p><p>很有视觉冲击感的建筑设计：</p><p><img src="/posts/62c8/art_on_building.webp" alt="" loading="lazy"></p><p>该公园内有 <u>美国独立纪念馆</u>（Independence Hall），也就是 1776 年 7 月 4 日通过《美国独立宣言》的地方。</p><p><img src="/posts/62c8/independence_hall_1.webp" alt="" loading="lazy"></p><p>瞎折腾相机里的 panorama 模式，拍出来的很奇怪的钟楼：</p><p><img src="/posts/62c8/bell_tower.webp" alt="" loading="lazy"></p><p>最后还是乖乖、好好拍了下钟楼：</p><p><img src="/posts/62c8/bell_tower_but_normal.webp" alt="" loading="lazy"></p><p>纪念馆内有个会播放动画的荧幕：</p><p><img src="/posts/62c8/independence_hall_2.webp" alt="" loading="lazy"></p><p>里面陈列了当时人们签署《美国独立宣言》还有《美利坚合众国宪法》用的辛氏墨台（Syng inkstand）：</p><p><img src="/posts/62c8/syng_inkstand.webp" alt="" loading="lazy"></p><p>根据图片的说明可以看出，当时人们还在使用羽毛写字。</p><p>实物感觉少了好多东西：</p><p><img src="/posts/62c8/syng_inkstand_real.webp" alt="" loading="lazy"></p><p>Dunlap broadside 出版的《美国独立宣言》副本：</p><p><img src="/posts/62c8/dunlap_broadside.webp" alt="" loading="lazy"></p><p>因为时间匆忙，我们随便逛了下就出来了。这期间我没咋拍照，也没有在认真看博物馆，只是孤身在写留言的地方写留言。不知道他们是不是当天夜晚就撤下我的留言？</p><p>出了纪念馆，走在费城的街道上，感觉很多细节都不一样。</p><p>比如这个地铁站口，跟纽约市的区别可大了！</p><p><img src="/posts/62c8/subway_entrance.webp" alt="" loading="lazy"></p><p>路边还有个博物馆：</p><p><img src="/posts/62c8/award_winning_museum.webp" alt="" loading="lazy"></p><p>不过我们的目的地是附近卖饭的商场。我们都没咋吃饭，饿死了要。</p><p>路上我们分开去上厕所。回来集合时亲戚家的大儿子说有人塞给他莲花钥匙扣，不知道是什么东西。</p><p>我拿过来一看，粉色的莲花，上面赫然刻着「法轮大法」四个字，就说「这是法轮功」。</p><p>他问我法轮功是什么。母亲插嘴说是中国的邪教！妹妹问我「邪教」是什么。我说是 <em> cult</em> 啊。她又问我 <em> cult</em> 是什么。</p><p>没法，我拿出手机给她看邪教的照片，也给她看法轮功的照片。她一看到黄色衣服的人，就大喊 <em> scammy monks!</em> ⸺嗯，总感觉哪里怪怪的。</p><p>小孩子怎么会知道什么是「邪教」？成年人也不会每个都知道。像我母亲就说，她知道法轮功是中国的邪教，但为什么被认为是邪教？这个问题也问倒我了：我知道法轮功和中国政府之间在政治上的纠纷，但具体什么才是导致一切的关键？</p><p>我就上网搜，得知关键在于「气功」。</p><p>1999 年中国科学院院士何祚庥批评气功是伪科学，导致法轮功学员跑去教育学院要求消除他的相关文章。警察过来驱赶，还抓了一些人。</p><p>数日后约万名法轮功学员跑到国家信访局上访，也就是 425 上访事件。这一举导致江泽民成立 610 办公室，专门负责镇压法轮功，并在 7 月 22 日正式镇压⸺怪不得我在美国看到的法轮功游行都在骂江泽民，就算他已经去世了旗子上也在控诉、反对他。</p><p>更深层的因素自然也有中国政府对法轮功人数增长的害怕、法轮功组织的独立性、法轮功的有神论哲学与马克思主义和无神论不相容……</p><p>亲戚小孩问我们这东西能拿吗，毕竟是陌生人塞给他的。母亲说可以是可以，但不要带到中国去。中国很多事情是不可以说的。调皮的小孩嘻嘻一笑，直接把莲花丢到十万八千里开外、看不见了。</p><p>走着走着我们竟然走到了费城的唐人街：</p><p><img src="/posts/62c8/chinatown.webp" alt="" loading="lazy"></p><p>左边还写了个「西安天下」，所以我能吃到喜欢的肉夹馍、烩面！</p><p>走进唐人街，能看到个拱门，也是很「唐人街」了：</p><p><img src="/posts/62c8/chinatown_gate.webp" alt="" loading="lazy"></p><p>重要的是图里的「沙县小吃」和「河南小吃」，以及被截取一半的「兰州牛肉面」。</p><p>亲戚说想要试试传说中的「费城牛肉奶酪三明治」（cheesesteak），所以我们只能和这些中餐说拜拜⸺暂时地。</p><p>路上看到个在睡觉的 Uber Eats 机器人：</p><p><img src="/posts/62c8/uber_eats_bot.webp" alt="" loading="lazy"></p><p>三明治我是进这个地方买的。没办法车不好停，只能让我带小孩子进去，买完赶紧坐车撤退。</p><p><img src="/posts/62c8/reading_terminal_market.webp" alt="" loading="lazy"></p><p>如果没记错应该是叫 <em> Reading Terminal Market</em>。里面一进去会先感觉很像是菜市场，再往里走则是美食广场。</p><p>给亲戚买完三明治，我还得琢磨其他人吃啥。小孩子们都对非中餐没啥兴趣，我也没啥兴趣；妹妹只想狂吃越南粉。</p><p>最后我跑到路边的越南粉店给妹妹买了粉，然后给我自己买了那「西安天下」的羊肉烩面。我母亲则去沙县小吃买了很多饭，给亲戚家两个一直说不饿、不想吃东西的孩子吃。</p><p>这「西安天下」我得说几句。「旺仔牛奶」的英文翻译怎么是这个啊：</p><p><img src="/posts/62c8/hot_kid_milk.webp" alt="" loading="lazy"></p><p><em>Hot-Kid Milk</em> 是什么鬼。</p><p><em>Chrysanthemum</em> 也拼错了。</p><p>根据 Dawarich 的地图，我们之后应该是开车停在了 Levy Park，然后在那儿吃的饭。他们几个想拿外带盒直接坐在公园里吃，我不乐意，所以我一个人坐车上吃。外面热死了，我才不去呢，我要在车上吹空调！</p><p>打开羊肉烩面的包装袋，傻眼了。虽然面和汤是分开放的，但两个容器小到我怀疑商家默认我有自己的大碗。我既无法将汤都倒到装面的容器里，也无法把面放进装汤的容器里。最后我的吃法是：汤倒一点点到面中，一边吃面一边喝掉汤，接着循环往复。</p><p>这烩面汤做得贼难喝，很腻歪，更像是红烧牛肉面的风格。面本身因为没法被汤完全浸泡、是干的，我无法说出它到底是好吃还是不好吃。</p><p>以后出来旅游还要带个折叠的桌子、塑料大碗！我坐在车里看着公园里吃饭的他们，因为没有桌子只能蹲在地上、把长椅当成饭桌。太难了，周遭的露天餐饮区都是别人餐厅的，我们不消费用不了。至于为什么不在唐人街堂食：不好停车啊！</p><p>吃饱喝足后我们驾车前往华盛顿特区。高速公路上依然是遍地的玉米地，但亲戚们都笑不出来，因为这玉米地忒多了，显得先前还觉得很稀奇的他们像傻瓜。一小时前窗外的景色，和一小时后的一模一样，也和两小时后的一模一样。</p><p>亲戚问我美国和中国的差异，例如在教育、父母对待孩子等方面上。这种话题也是老生常谈了，每个从中国过来旅游的亲戚都要问我这手。</p><p>唉，我能咋跟你解释啊！是的，你说得对，美国更独立更自由一点都不内卷！⸺虽然是讽刺，但我不会直接否认这些说法。我的看法是，美国作为移民国家实在是太多样化了。你无法总结出一个「美国人」形象。</p><p>崇尚所谓「快乐教育」所以傻傻的美国人有，接受精英教育嗑药学习的美国人也有⸺哪个才是真正的「美国人」？</p><p>重视孩子心理健康、独立和自主性的美国人有，无视孩子意愿自己也有精神问题的美国人也有⸺哪个才是真正的「美国人」？</p><p>「美国人」这个概念无比复杂。你要问我，我也不知道怎么回复啊。就算你把肤色不是白色的美国人抽离出「美国人」这个概念，白肤色的美国人也不会呈现统一性。</p><p>就算我如此解释，亲戚也不会听进去，依然在心里划分出他认为的「美国人」要素，并以此抨击中国。</p><p>母亲也是好笑，她和亲戚说话一口一个「我们美国」。像什么「我们美国人都喝牛奶」，但我们家实际上没有喝牛奶的习惯。我从小就讨厌纯牛奶的味道，所以只会喝酸奶。来美国后喝到了能接受的脱脂牛奶，但也必须加温后再喝。</p><p>我不爽的原因是母亲在我的标准里从未真正接触出美国的文化。她来美国只和华人打交道、只住在华人区，连英语都不会说，现在在完全是「中国人」身份的亲戚面前却能摇身一变变成「美国人」，然后刻意去加深「美国人」这个幻想的概念。</p><p>亲戚提起这件事，其实是他在犹豫要不要把孩子送到美国接受教育。他的俩儿子一个今年 13 岁、一个 9 岁，如果现在送来美国他们能更快地适应新环境。</p><p>母亲一直怂恿他，说送过来啊，趁他们年纪还小的时候赶紧送过来。中国教育多卷啊，全都是人情世故，美国就不是这样了⸺这种话题听多了，让我觉得有些烦躁。于是我久违地泡在了智能手机里、刷些碎片化的信息来刺激我的大脑。很快，我晕车了，只能睡觉。</p><p>我们是走 Chesapeake Bay Bridge 去的华盛顿特区。桥上堵车堵了一小时左右。我们绝望地看着导航 app 上的预计时间越开越长……</p><p>总之经过无数个、数都数不清的玉米地，我们到了华盛顿特区。</p><p><img src="/posts/62c8/welcome_to_dc.webp" alt="" loading="lazy"></p><p>华盛顿特区的正式名称是 <u>哥伦比亚特区</u>（District of Columbia），缩写是 <em> DC</em>，不要和华盛顿州（缩写是 <em> WA</em>）搞混了。</p><p>在一条小巷子我们停好车，便开始走走走、到处拍照片。</p><p>旧专利局大楼，现在是艺术博物馆：</p><p><img src="/posts/62c8/smithsonian_institution.webp" alt="" loading="lazy"></p><p>J. Edgar Hoover 大楼：</p><p><img src="/posts/62c8/j_edgar_hoover_building.webp" alt="" loading="lazy"></p><p>…… 的入口之一。这个大楼太大了我拍不下来。</p><p>这个大楼是美国联邦调查局前总部的所在地，也就是 FBI 的地方。</p><p>我不知道我在拍什么建筑，早知道记下来了：</p><p><img src="/posts/62c8/unknown.webp" alt="" loading="lazy"></p><p>因为美国建国 250 周年，很多道路被封锁了。</p><p>贴着 Trump 大脸的建筑：</p><p><img src="/posts/62c8/building_with_trump_face.webp" alt="" loading="lazy"></p><p>等等，这个建筑不就在刚才那建筑的旁边吗？于是我动用小手搜了搜，发现这个贴有 Trump 大脸的建筑是 <u>美国司法部</u>（United States Department of Justice）的总部。</p><p>然后跑到 Kagi Maps 上搜索司法部的位置，再找到它周围的哪个建筑和图片里的位置相符。</p><p>哎，找到了 <u>美国国立自然历史博物馆</u>（National Museum of Natural History）。虽然 Wikipedia 上面的照片不太像，但我再去找了网上的其他图片，确认这建筑头上也有个圆圆的大球⸺破案了！</p><p>Immich 虽然可以记录我在哪里拍下的照片，但如果我拍的是远处的景点，并且周围全都是景点的话，我就不知道我在拍什么了……</p><p>顺带一提这个旅游到结束之前我们都没有踏入过该博物馆。唉！</p><p>旁边的旧邮政局大厦：</p><p><img src="/posts/62c8/old_post_office.webp" alt="" loading="lazy"></p><p>Ronald Reagan 大厦和国际贸易中心：</p><p><img src="/posts/62c8/ronald_reagan_building.webp" alt="" loading="lazy"></p><p>不知道为啥给人家 banner 都摆不好。</p><p><u>自由广场</u>（Freedom Plaza）：</p><p><img src="/posts/62c8/freedom_plaza.webp" alt="" loading="lazy"></p><p>夕阳时的天空也很美。</p><p>「自由」一名得名于著名的《我有一个梦想》演讲。</p><p>里面有个大喷泉：</p><p><img src="/posts/62c8/fountain.webp" alt="" loading="lazy"></p><p>Herbert C. Hoover 大楼，是 <u>美国商务部</u>（United States Department of Commerce）的总部：</p><p><img src="/posts/62c8/herbert_c_hoover_building.webp" alt="" loading="lazy"></p><p>上面也贴满了 250 的 banner。</p><p>其实我拍这张照片的身后就是白宫，但是全部被围栏封了起来，连看到看不到。天也快黑了，小孩子都喊累，亲戚也对美国的政府没什么兴趣，所以我们只是看到什么拍什么而已。</p><p>因为我没有在 Organic Maps 上下载特区的地图，所以全称我都在使用 Kagi Maps 导航⸺明明这个软件才是最该做成移动端 app 的。Kagi 的其他产品做不做移动端 app 关系都不咋大。</p><p>继续向南走，就是很显眼的 <u>华盛顿纪念碑</u>（Washington Monument）：</p><p><img src="/posts/62c8/washington_monument.webp" alt="" loading="lazy"></p><p>非常高、非常壮观！我和妹妹跑到它的正下方来。妹妹很激动，我怕死了，因为我只要向上看就会害怕、想象自己从石碑顶端掉下来、变成 Cytro 酱。</p><p><img src="/posts/62c8/monument_closely.webp" alt="" loading="lazy"></p><p>还是转过身看看「不那么高」的地方吧！</p><p><img src="/posts/62c8/i_dont_want_to_see_monument.webp" alt="" loading="lazy"></p><p>那些树的后面就是白宫。唉我都跑这么高的地方来了还是看不到。</p><p>再来一张主要拍天空景色的：</p><p><img src="/posts/62c8/sky.webp" alt="" loading="lazy"></p><p>接着我们原路返回、坐车去特区的唐人街买晚饭和明早的早饭。</p><p>因为已经快十点了，很多店都关了。我们路过一家越南粉店，里面的华人老板娘正好出来。她看到我们，立马过来招待，又因为妹妹一直吵着要吃越南粉，我们便也进去了。</p><p>这老板娘看我们都是中国人，各种吹捧她家的菜、点心。母亲也不看菜单和价格，老板娘说什么她就点什么：一碗粉 20.69 美元、葱油饼 8 片小小的 9 美元多、生煎包一个 2 美元多、珍珠奶茶一杯 8 美元多…… 最后这个是亲戚小孩点的。问他俩吃啥他俩不知道，一个劲儿玩手机，最后问出来个「珍珠奶茶」。我真是要晕倒了你为什么要在非奶茶店的地方点奶茶！</p><p>果不其然这奶茶端上来一看就很奇怪，味道又甜又不好喝。老板娘过来还质问我为什么不给妹妹点可乐，我点你个鬼！以为我没有看到你家可乐一罐 2.75 美元吗！我要去隔壁 711 领免费的 Big Gulp！</p><p>母亲不看菜单点单的报应很快就来了：她以为点完就 100 块，结果老板娘说 140 多。这引起母亲怀疑，终于是过来看了菜单和价格，然后怒道「你家东西怎么这么贵！」⸺拜托！点单前看价格啊你倒是！</p><p>这老板娘坑人。我们外带的餐为什么要加小费进去？她自己往里面加了 20 多，后来说自己忘记去掉了，无语！所以总价是税后 120 多，我们一共点了两碗粉、四个水饺、忘了多少个生煎包、八片小小的葱油饼、一个越南面包、两杯珍珠奶茶。</p><p>买完我们去了亲戚在 Airbnb 上订的民宿。我们打算在民宿里待一晚上，次日起来专门去逛博物馆、动物园，晚上再在另一家民宿里睡觉。</p><p>我没有拍照片，因为这个民宿很「民」宿，就是一住宅区里的老房子。我们尝试解锁门锁，但是推门不开，急得不行。更重要的是，这附近全是不怕人的蚊子，它们还个个盯着我咬⸺我苦不堪言、命苦啊！最后我发现解锁密码是对的，只是门太旧了，要用力推才能开，相当于我白被蚊子咬了十个包！</p><p>以上就是八月十九日星期三我的经历。次日凌晨、我睡前的时候还发了 <a href="/posts/6c9d.html">《做导游的这几天：上》</a>。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;纽约市大致的景点都看过一次后，亲戚想要往西边走点。原本他计划是去加州那边看硅谷、计算机博物馆…… 不过计划有误，他买的回程票是在波士顿，相当于如果去了加州，还得横跨整个美国跑回东海岸，距离都够去趟中国再回来了！&lt;/p&gt;
&lt;p&gt;于是我们计划沿路跑到华盛顿特区看白宫，再回来纽约吃饭睡觉打豆豆。&lt;/p&gt;</summary>
    
    
    
    <category term="日常生活" scheme="https://blog.cytrogen.icu/categories/%E6%97%A5%E5%B8%B8%E7%94%9F%E6%B4%BB/"/>
    
    
  </entry>
  
  <entry>
    <title>RE：The Becoming Chinese Trend Is Nonsense</title>
    <link href="https://blog.cytrogen.icu/posts/dbcb.html"/>
    <id>https://blog.cytrogen.icu/posts/dbcb.html</id>
    <published>2026-08-23T04:00:00.000Z</published>
    <updated>2026-08-23T04:35:23.338Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我这辈子都没有在手机上安装过 TikTok，或者抖音。再加上我日常已经不使用 Meta 家的产品有一阵子了，我也不用很多主流的社交平台，所以我完全不知道今年春节，就是二三月份左右 TikTok 上有「成为中国人」浪潮。</p><span id="more"></span><p>虽然我写说这篇 RE 文是「文章回应」，但要回应的其实是个 YouTube 影片。</p><p>YouTube 原片链接： <a href="https://youtube.com/watch?v=jDEY6pgDDPw">https://youtube.com/watch?v=jDEY6pgDDPw</a> ⸺为什么你还在使用 YouTube！</p><p>使用 Invidious 实例吧： <a href="https://invidious.nerdvpn.de/watch?v=jDEY6pgDDPw">https://invidious.nerdvpn.de/watch?v=jDEY6pgDDPw</a></p><p>你还可以点击 <em> Switch Invidious Instance</em> 来自动切换成其他实例。总之，不要使用 YouTube 这个不自由的客户端。</p><p>BiliBili 双语版本： <a href="https://www.bilibili.com/video/BV1X3XjBeEDM/">https://www.bilibili.com/video/BV1X3XjBeEDM/</a></p><p>不知道有没有 BiliBili 版本的 Invidious 呢？</p><hr><p>这帮我刻板印象里就没有思想也没有个人认知的 TikTok 民永远都在搞全新的「成为某某某」浪潮。反正过一阵子他们就会腻了、转向「成为」下一个群体。</p><p>频道主 Ashley Viola 抨击了这帮人，就像她经常做的那样⸺她的频道近乎都是在抨击主流社交平台上的潮流，感兴趣可以看看。最有意思的莫过于借此认识完全没有听说过的潮流。</p><blockquote><p>The problem is when the culture becomes a costume.</p><p>When it becomes something that you put on like a jacket just because it's trending.</p><p>问题的核心在于当文化沦为一种皮囊。</p><p>当它仅仅因为流行，就变成像外套一样可以被随意穿戴在身上的东西时，问题便产生了。</p></blockquote><p>文化成为了文化符号、部落。</p><p>对于海外华人而言，这是非常令人不舒服的。过去「中国」对于主流人群⸺指的是顺性别顺性取向白人，尤其是男性⸺而言是毋庸置疑的贬义词。</p><p>尽管部分人不会表现出直接的种族歧视，但隐形的歧视和排挤一直在社会中存在，诸如以 <u>白人性</u> 为中心的思考方式：人只存在白人和非白人；海外华人只能通过成为「模范少数族裔」来被社会认同。</p><p>忽然间，曾经歧视和排挤自己的主流社会开始向下看向我们的传统和文化，并挑挑拣拣、选出他们认为有趣的，并开始宣称他们是「中国人」⸺这是令人作呕的。</p><p>Viola 的观点非常直白，直白到令我羡慕她的诚实和勇敢：「成为中国人」潮流不过是没有历史、没有文化、没有自我的人，为了获取关注而做的表演。</p><blockquote><p>……because when you don't know who you are, you outsource your personality to the algorithm.</p><p>…… 因为当你不知道自己是谁时，你就会把自己的个性外包给算法。</p></blockquote><p>他们随意从中国人的文化中挑选出他们喜欢的，就像换衣服一样「穿」上它。当这些被挑选出来的文化变得不再吸引观众、不再小众、不再独特，他们对此感到无聊，便会像丢弃衣服一样再丢弃它。</p><p>他们从来都不需要经历真正的中国人所要经历的痛苦、苦难、不平等的对待。他们简单拿起其他文化的身份，然后就很简单地套在了自己的身上。</p><p>「成为中国人」潮流不是他们第一次这么做，也不会是最后一次。</p><p>他们对边缘文化的了解浅薄到认为中国文化只是：</p><ul><li>热水</li><li>面条</li><li>米饭</li><li>红色衣服</li><li>过新年</li><li>生肖</li><li>泡脚</li><li>喝姜茶</li><li>针灸</li><li>穿拖鞋</li></ul><p>Viola 在视频中说道：</p><blockquote><p>If your personality is built on consumption that you just rotate aesthetics.</p><p>如果你的个性是建立在消费之上的，那你只不过是在不断轮换各种审美风格罢了。</p><p>You get to wear the aesthetic and perform the rituals only to return to the safety of whiteness.</p><p>你大可以套上这些审美外衣，体验一番文化仪式，最终却依然能全身而退，回到白人身份的避风港里。</p><p>Because at the end of the day, a lot of these influencers who are doing this, they're still very much white.</p><p>因为说到底，很多玩这套把戏的网红，他们依然是彻头彻尾的白人。</p></blockquote><p>在 BiliBili 的评论区中，我们可以看到部分居住在中国的中国人是如何看待这件事的：这是好事，这意味着文化输出成功了。</p><p>讲真？你真的这么认为吗？</p><p>文化输出没有成功。他们不会去理解我们的文化，他们只是在不停去加深「中国人」的刻板印象。然后等他们玩腻了，他们会抛弃「中国人」这件衣裳，然后去祸害下一个边缘文化。</p><p>瑜伽、抹茶…… 这些都潜移默化成为了都市中产白人们的象征。这明显是 <u>文化挪用</u>。中国文化的什么也会被他们挪去、慢慢变成他们的东西？</p><p>对于居住在中国的中国人而言，这些问题都不是需要担忧的问题，因为他们近乎不会和这帮主流人群有挂钩。</p><p>但是海外华人只能忍受着这帮主流人群去肆意玩弄中国的文化，看着他们卖 25 美元的火锅底料并宣称这是原创、但我们其实在超市里就能买到 4 美元左右的小肥羊火锅底料；看着社交平台上的主流声音几年前还在辱骂中国人吃蝙蝠害所有人得新冠病毒、嘲笑中国人穷酸会食用狗肉、对着中国人笑道 <em> ching chong</em>…… 现在又突然开始玩弄中国的文化、说他们是「中国人」。</p><p>他们不会去学习中国文化、中国历史、海外华人的事情、中国人都在面临什么困难⸺他们只在乎消费、上传视频到网上以博取点击量。</p><p>Viola 提到了个我没有想到的视角，即「成为中国人」潮流发生在马年的春节其实是有意义的。因为「马」对于白人社会而言，是高雅、美丽的存在，且已经是白人社会非常熟悉的浪漫化象征之一。甚至美国白人社会中就有 <em> horse girl culture</em>（爱马女孩文化）这一刻板印象。</p><p>这意味着，主流人群是精心挑选的中国文化，仅选择他们喜欢、觉得熟悉的象征。</p><p>bell hooks 在其经典文章 <em> Eating the Other: Desire and Resistance</em> 中提到，主流群体会对边缘化群体的文化进行消费性接触，将他者的文化当作调味品来品尝。</p><p>这种接触不是真正的理解或者团结，它仅是自恋的自我满足，因为主流群体「吃」掉了他者来丰富自己、让自己感到开放和进步，但不会去了解他者的真实处境。</p><p>视频中 Viola 引用了一个亚洲人的短视频。该作者说自己不是中国人，但在疫情期间她因为有着东亚人的面孔，所以被其他人控诉是中国人、控诉吃猫吃狗吃蝙蝠、控诉是肮脏邪恶的。她也说白人尝试亚洲文化的东西，在主流中是可爱、开放的象征，但亚洲人做同样的事情，就没有人在乎⸺或者应该说是「恶心」的。</p><p>中国人去抱怨，主流群体就会认为是中国人上纲上线：「这只是玩笑、享乐、好玩！不要做那个不识相的人！」</p><p>我有时在中文互联网的主流社交平台上冲浪，也会遇到类似的观念。不过不同的点在于，是互联网中主流的中国人们去在乎白人如何想、如何看待自己的文化。</p><p>我们真的需要那么做、以证明我们的文化是好的吗？</p><p>白人的认可是标准；「白人」这个位置默认代表「好」、「正常」、「值得效仿」…… 我们的差异全部因此产生。</p><p>但白人性是空洞的；白人主流文化在自身的存在性、精神性上都是空虚的，因此他们才会急于通过消费他者的文化，来让自己感到活着。</p><p><em>Race Traitor</em> 提出，白人种族是被建构出来的社会范畴，用于制造使白人收益、以有色人种为代价的社会等级制度。白人性有且只有压迫和虚假。</p><p>将自己的文化交由给白人判断好或者不好，是天真且愚笨的：我们不需要让白人的目光来裁决⸺例如拒绝食用狗肉可以是因为厌恶偷狗贼、或者同情狗，但绝不应该是因为白人觉得食用狗肉是不文明的。</p><p>我们要废除「白人等于好」的框架。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我这辈子都没有在手机上安装过 TikTok，或者抖音。再加上我日常已经不使用 Meta 家的产品有一阵子了，我也不用很多主流的社交平台，所以我完全不知道今年春节，就是二三月份左右 TikTok 上有「成为中国人」浪潮。&lt;/p&gt;</summary>
    
    
    
    <category term="文章回应" scheme="https://blog.cytrogen.icu/categories/%E6%96%87%E7%AB%A0%E5%9B%9E%E5%BA%94/"/>
    
    
  </entry>
  
  <entry>
    <title>牛郎织女和父权</title>
    <link href="https://blog.cytrogen.icu/posts/ef30.html"/>
    <id>https://blog.cytrogen.icu/posts/ef30.html</id>
    <published>2026-08-22T04:00:00.000Z</published>
    <updated>2026-08-22T05:13:29.561Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>今年的七夕是公历的八月十九日。我后知后觉它已经过去了。我不喜欢节日，因其氛围总是在催促我去消费、告诉我应该做什么应该不做什么…… 我连自己的生日、新年都不会花时间庆祝了，我还管你个小小七夕？</p><p>另一点在于我讨厌七夕背后牛郎与织女的传说。</p><span id="more"></span><p>现代人对于七夕，还有牛郎织女的传说的看法都是「纯粹的爱情」，却因为二者的身份差异，每年只能相见一次。</p><p>但我先前便阅读过这样的版本：牛郎趁织女洗澡、偷了织女衣服，导致织女无法飞回天上，二人最终成婚⸺这样的故事是「纯粹的爱情」？我无法接受！</p><p>数年来我也在七夕时陆陆续续看到有人质疑该故事和「爱情」内核的关系。不过一直没有放在心上。</p><p>直到近些日我同一位博友围绕着这篇 <a href="https://mp.weixin.qq.com/s/9HcyfHNcT6K7Z2k_tU2YZg">微信公众号文章</a> 讨论了一番，意识到传说的内容、传播时的时代背景、如何随着时间变化、和父权的关系…… 这些内容都很值得大聊特聊。</p><p>因为本篇内容包含我对多个文章的分析和回应，所以不能是单篇文章的回应。</p><hr><h2 id="公众号文章的简述"><a class="markdownIt-Anchor" href="#公众号文章的简述"></a> 公众号文章的简述</h2><p>该文章是篇典型的女性主义兼批判理论视角的文本分析，用了拉康的精神分析还有意识形态批判的框架重新解读了牛郎织女的传说。</p><p>一下子出现了特别多术语呢。没关系，我会一一解释清楚的！</p><h2 id="牛郎织女传说的各个版本"><a class="markdownIt-Anchor" href="#牛郎织女传说的各个版本"></a> 牛郎织女传说的各个版本</h2><p>因为牛郎织女的传说有多个版本，深究这些传说时必须讲明白我们重点在讨论哪个版本⸺这也是我和博友讨论期间发现的，因为对方认为的主流版本是叶圣陶撰写的归还版，并在讨论中频繁使用该版本来反驳公众号文章中的观点。</p><p>介于我们理解的主流版本并不一致，我们自然也难以深入讨论下去。</p><p>实事求是，我们便来探索一下牛郎织女传说的各个版本吧。</p><p><a href="https://zqb.cyol.com/html/2023-12/06/nw.D110000zgqnb_20231206_1-06.htm">《牛郎的新烦恼》</a> ⸺实际上该文章本身就以孩子、教育者的视角质疑了牛郎织女传说和「爱情」的关系⸺中提到：</p><blockquote><p>牛郎和织女的情意甚至先于情节建立⸺从它们作为两颗星星开始，就隔着银河迢迢相望。汉武帝刻立牛郎织女的石像，使他们具有人格，这是后来的事。</p><p>东汉时期，文人使牛郎织女发展出爱情，《古诗十九首・迢迢牵牛星》写出了恩爱夫妻备受分离之苦的意象，但没人知道他们为什么分开。魏晋南北朝时期，道教文化兴盛，玉皇大帝和王母娘娘也加入了牛郎织女的故事线，人们开始思考悲剧结局的成因。</p><p>有人写道，是牛郎为了迎娶织女，欠了天帝两万钱迟迟不还，被关入牢房而二人分离。有人说，牛郎织女受天帝指配成婚，但织女婚后因情废织，遭到天帝处罚，两人分离。唐朝风气更开，使织女成为花心放荡的形象，在与牛郎有婚约的前提下，仍下凡与人间书生郭翰私会。直至明清，多数时候，这个故事的主流情节仍然是相爱、成婚、分离。</p><p>清末「盗衣」情节的加入，使故事的走向转了个弯。有学者统计发现，新中国成立前，牛郎窃取仙衣强迫织女成婚、织女婚后设法逃离人间的文本占多数。直到新中国成立后，经过戏曲改良运动，牛郎织女的故事被确立为「劳动、爱情、反封建」的主题。作家艾青说：「要把牛郎和织女恢复到劳动人民的本来面目。」</p></blockquote><p>这段演变史中最关键的信息是最后几句：「有学者统计发现，新中国成立前，牛郎窃取仙衣强迫织女成婚、织女婚后设法逃离人间的文本占多数。」</p><p>也就是说，在民间口头传统的流传中，「偷衣版」是占多数的版本。这是公众号文章所分析的对象，也是本文讨论的对象。</p><p>而博友所引用的「归还版」⸺牛郎拿走衣服后归还、织女自愿爱上牛郎的版本⸺来自叶圣陶的改编，经由语文教材的选编而广泛传播。它的流通渠道是制度性的，因为新中国的戏曲改良运动有明确的政治目标，必须要让故事重构成符合新社会的意识形态需要。因此，该版本已经经过政治的筛选，以及浪漫化的改造。</p><p>既然公众号文章是以偷衣版作为讨论对象，那我们在围绕着文章讨论时，<strong>必须也使用偷衣版进行讨论。</strong></p><p>接下来的内容将会是我对公众号文章的解析的知识性铺垫。</p><h2 id="什么是女性主义"><a class="markdownIt-Anchor" href="#什么是女性主义"></a> 什么是女性主义？</h2><p><u>女性主义</u>（Feminism），有时也被译为「女权主义」，旨在定义和建立两性在政治、经济、个人和社会层面的平等。其核心立场是：现代社会是父权制的，即优先采取男性的视角，女性在其中受到不公正的对待。</p><p>该主义非常复杂，有着三个主流的学派：</p><ul><li>自由女性主义：性别不平等源于歧视性法律和制度壁垒，所以要通过法律和政治改革来消除它们，让女性在现有体制内平等竞争</li><li>社会主义女性主义：性别压迫与经济剥削深度交织；资本主义从女性的无偿家务劳动中获利；父权制使女性经济依附在男性身上，难以独立⸺因此必须同时推翻资本主义和父权制</li><li>激进女权主义：父权制本身是性别不平等的根源，需彻底重构社会，所以要消除男性在一切社会和经济语境中的至上地位</li></ul><p>公众号文章的分析框架更接近于激进女性主义还有社会主义女性主义的立场，因为作者王无多次提及到牛郎织女传说中暗藏的性剥削、劳动无偿占有，还有父权制⸺这些也是文章的核心。</p><h2 id="什么是批判理论"><a class="markdownIt-Anchor" href="#什么是批判理论"></a> 什么是批判理论？</h2><p>王无在分析完牛郎织女的故事后，进一步追问该传说在社会权力结构中扮演了什么角色⸺也是 <u>批判理论</u> 的经典表现。</p><p>作为一个标准，《传统理论与批判理论》认为批判理论会质疑现有社会框架本身的合法性、批判并改造社会。核心方法是用社会自身承诺的价值观来衡量社会的实际运作、揭示两者之间的差距⸺这也叫 <u>内在批判</u>。</p><p>值得注意的是，尽管说到批判理论「会」改造社会，但它「不需要」为指出的问题给出解决方案。因为发现并剖析问题本身就有独立的价值。</p><h2 id="freud-精神分析"><a class="markdownIt-Anchor" href="#freud-精神分析"></a> Freud 精神分析</h2><p>Jacques Lacan 是法国的精神分析学家。说到他之前，得先说说 Sigmund Freud。</p><p>Freud 的精神分析建立在生物学驱动的概念上。</p><h4 id="心灵的地形学模型"><a class="markdownIt-Anchor" href="#心灵的地形学模型"></a> 心灵的地形学模型</h4><p>Freud 最早的理论贡献是将心灵比喻成一座冰山，分为三个层次：</p><ol><li>意识：当前感知到的想法和感受，也是冰山露出水面的尖端</li><li>前意识：当前未注意但可以轻易回忆的内容，也是水面下的浅层</li><li>无意识：被压抑的欲望、记忆，和冲动。无法直接被访问，但深刻影响行为。它是冰山水下庞大的主体</li></ol><p>Freud 发现，无意识是心灵中最为强大和决定性的部分。人的行为、情感和思想在很大程度上由自己意识不到的力量所驱动。</p><p>那么精神分析的治疗目标就是让无意识成为意识，将被压抑的内容带入意识，从而释放心理痛苦。</p><h4 id="心灵的结构模型"><a class="markdownIt-Anchor" href="#心灵的结构模型"></a> 心灵的结构模型</h4><p>1923 年，Freud 在《自我与本我》中将人格分为三个机构：</p><ol><li>本我：完全无意识；遵循快乐原则运作；功能是原始冲动和本能欲望，追求即时满足，不考虑现实</li><li>自我：横跨意识与无意识；遵循现实原则运作；功能是调节本我冲动与现实要求之间的冲突，寻找可接受的满足方式</li><li>超我：主要无意识；遵循道德原则运作；功能是内化的社会规范和道德要求，良知和自我理想</li></ol><p>它们的动态关系是：本我追求欲望的即时满足，但现实不允许这种满足。自我作为调解者，在本我冲动、现实限制和超我道德要求之间寻找平衡。当三者之间的冲突无法被自我有效调解时，就产生神经症，也是精神分析治疗的主要对象。</p><h4 id="驱力理论"><a class="markdownIt-Anchor" href="#驱力理论"></a> 驱力理论</h4><p>早期 Freud 认为，推动人类行为的核心力量是 <u>力比多</u>（Libido），即性的能量。他在 1905 年的《性学三论》中提出，性驱力早在婴儿期就存在。</p><p>1920 年，Freud 在《超越快乐原则》中引入了双重驱力理论、出现了根本性的转变：</p><ul><li>生驱力：目标是生存、创造、联结；表现为自我保存、性、爱、建设</li><li>死驱力：目标是回到无机状态、毁灭；表现为攻击性、自我毁灭、强迫性重复</li></ul><h4 id="性心理发展阶段"><a class="markdownIt-Anchor" href="#性心理发展阶段"></a> 性心理发展阶段</h4><p>Freud 提出人格发展会经历五个阶段，每个阶段都会以一个性感带作为中心：</p><table><thead><tr><th>阶段</th><th>年龄</th><th>性感带</th><th>核心冲突</th><th>后果</th></tr></thead><tbody><tr><td>口唇期</td><td>0-1 岁</td><td>口腔</td><td>断奶</td><td>依赖性、口唇习惯</td></tr><tr><td>肛门期</td><td>1-3 岁</td><td>肛门</td><td>如厕训练</td><td>强迫型、吝啬或放纵</td></tr><tr><td>性器期</td><td>3-5 岁</td><td>生殖器</td><td>俄狄浦斯情结</td><td>性别认同、超我形成</td></tr><tr><td>潜伏期</td><td>5-12 岁</td><td>压抑</td><td>性冲动被压抑</td><td>能量转向学习和社交</td></tr><tr><td>生殖器</td><td>12 岁以上</td><td>成熟的生殖器</td><td>建立成熟的异性关系</td><td>成熟的性关系和社会适应</td></tr></tbody></table><p>关键阶段是性器期。</p><h4 id="俄狄浦斯情结"><a class="markdownIt-Anchor" href="#俄狄浦斯情结"></a> 俄狄浦斯情结</h4><p>Freud 称其为早期儿童性期的核心现象。该概念在 1899 年的《梦的解析》中被首次引入。</p><p>在性器期，男孩会发展出对母亲的性欲渴望，并将父亲视为竞争对手和威胁。Freud 认为男孩此时产生阉割焦虑，因为他害怕父亲会因为他对母亲的欲望而惩罚他、阉割他。</p><p>这种恐惧迫使男孩压抑对母亲的欲望，内化父亲的禁令。而这个内化的过程就是超我的建立。男孩通过认同父亲来解决俄狄浦斯情结：放弃对母亲的占有欲望，接受父亲的权威，将父亲的道德规范内化为自己的人格结构。</p><p>Freud 对女性的描述更为复杂且争议更大。他认为女孩在性器期发现自己是「被阉割的」，因为她没有阴茎。这会产生阴茎羡妒、女孩对母亲产生怨恨（母亲没有给她阴茎），转而将爱欲投向父亲，希望父亲能给她一个阴茎。</p><p>女孩最终会接受自己「没有阴茎」的事实、认同母亲，并形成女性性别身份。Freud 认为女性的超我发展不如男性「完整」，因为她的阉割焦虑不如男孩强烈。</p><p>在 Freud 的原处框架中，菲勒斯等同于阴茎这一生物器官⸺关于它，会在 Lacan 的精神分析一节中展开。</p><p>偏个题：我常常看到 Freud meme 里大家在开玩笑说什么老鼠、大麻、想和母亲做爱，以嘲笑 Freud 的理论。但我觉得他们都没有认真了解过 Freud。这个阳具中心理论不是更适合拿来做 meme 吗？</p><h2 id="lacan-精神分析"><a class="markdownIt-Anchor" href="#lacan-精神分析"></a> Lacan 精神分析</h2><p>Lacan 认为，无意识并非 Freud 说的混沌的本能冲动，而是会遵循语言的结构规则。</p><p>因此精神分析的核心不在于生物学，而在于语言。继而他认为，精神分析是一种阅读，分析师应辨识言语中能指的运作结构。</p><p>他的理论可以分为几个核心模块：</p><h4 id="三个界域"><a class="markdownIt-Anchor" href="#三个界域"></a> 三个界域</h4><p>这三个界域⸺或者说秩序⸺是 Lacan 整个理论的骨架。它们会同时运作，互相交织，且人类经验的任何一个现象都可以从这三个维度来分析。</p><p>一、「想象」界域的核心机制是镜像认同和自我构成。</p><p>婴儿在 6-18 个月时会在镜子中认出自己，这意味着：</p><ul><li>在此之前，婴儿体验到的自己是碎裂、不协调的</li><li>在镜子中，婴儿看到了完整的形象。但这个形象是外在的</li><li>婴儿将这个外在形象认同为「自己」，从而构成了「自我」。但这个自我本质是误认，因为它把一个外在、想象的图像当作了内在的真实</li></ul><p>因此人类的「自我」是结构性的幻想。</p><p>更进一步，我们还能得出所有基于二元关系和形象认同的心理现象：</p><ul><li>自我与他者的二元镜像关系，即我通过想象他者如何看待我来构成自我</li><li>理想的自我是镜中的完美形象</li><li>因为我通过与他者的比较来确认自我，他者既是我的认同对象也是我的竞争对手</li></ul><p>二、「象征」界域的核心机制是语言、法律和社会秩序。Lacan 认为，语言先于主体存在：在人类出生之前，他的名字、社交角色、亲属位置，便已经在语言和文化中被预定。</p><p>意义来源于差异：「男人」之所以有意义，是因为它不是「女人」；反之亦然。</p><p>Lacan 提出了个概念，叫作 <u>大他者</u>（le grand Autre）。主体在语言中被构成，意味着主体从属于这个秩序⸺象征界域⸺也就是所谓的大他者。当我们说话时，我们不是在对某个人说话，而是在对大他者说话。</p><p>主体又是如何进入的象征界域？Lacan 通过两个相互关联的概念来回答：</p><ol><li><p><u>父亲之名</u>（Nom-du-Père）是象征界域中关键的能指。此「父亲」非彼父亲，它仅象征了父亲的「不」⸺禁止乱伦的法令⸺这个结论听上去很莫名其妙，但这要回到想象界域。Lacan 认为，婴儿会与母亲形成个封闭的二元关系，因为婴儿会渴望成为母亲的一切，而母亲又是婴儿的整个世界。</p><p>但是因为父亲的介入，向婴儿宣布了「你不能与母亲合为一体」。这个禁止乱伦的法令是语言和文化的法则本身。</p><p>通过接受该禁令，婴儿从与母亲的想象性二元关系中脱出，进入语言和社会的象征秩序，并开始拥有自己的名字、自己的社会位置……</p><p>执行父亲之名的「父亲」不必是生物学上的父亲。任何承载象征法则的人或者机构⸺包括母亲、祖辈、社会制度⸺都可以履行该功能。</p></li><li><p><u>象征性阉割</u> 是结构性的隐喻，即主体在进入语言和法则时必须经历的缺失。依然是婴儿和母亲的例子：婴儿以为自己是母亲欲望的唯一对象，以为与母亲是一体的。「阉割」指的是打碎该幻觉、主体必须接受自己不是母亲的全部、母亲有她自己的欲望，而自己必须放弃「与母亲合为一体」的幻想。</p><p>这个放弃建立了缺失，令主体成为了「有缺失的存在」，永远在寻找什么来填补该缺失。也正因为该缺失的存在，令主体开始有了欲望、有了追求。</p></li></ol><p>三、「实在」界域是无法被象征化、在语言和象征秩序中找不到位置的东西。它本质上是个否定性概念，即「既不能被形象化也不能被言说」的。因为过于抽象，实在界域也是最难搞懂的。</p><p>三个界域相互依存，但不可还原，也不能脱离彼此而独立存在。</p><h3 id="欲望与u对象小-auobjet-petit-a"><a class="markdownIt-Anchor" href="#欲望与u对象小-auobjet-petit-a"></a> 欲望与 <u>对象小 a</u>（Objet petit a）</h3><p>Lacan 的欲望理论与三个界域紧密相关：</p><ul><li>需要：生物学层面的，例如饥饿、口渴。它们都有确定的满足对象，如食物、水</li><li>要求：指向他者的，例如婴儿通过哭喊来要求母亲在场、要求他者的无条件关注和爱</li><li>欲望：既不是纯生物性的需要，也不是对爱的纯粹要求。欲望是需要和要求之间的差距、二者之间的剩余</li></ul><p>欲望是转喻性的。正如语言中转喻通过从一个词滑向相邻的词来产生意义，欲望通过从一个对象滑向下一个对象来维持自身。因为没有任何对象能政治填补原始的缺失，所以欲望永远都不会在具体的对象上停留。</p><p>而对象小 a 是 Lacan 对欲望对象的命名。先前说过，主体进入象征界域后会经历阉割、永远缺失了什么。这个丢失的东西不可能被找到，但它的影子会驱动着欲望：对象小 a 是「如果我能找回它、我就会变得完整」的幻想。</p><h3 id="菲勒斯与阳具中心主义"><a class="markdownIt-Anchor" href="#菲勒斯与阳具中心主义"></a> 菲勒斯与阳具中心主义</h3><p><u>菲勒斯</u>（Phallus）指的是缺失的能指，代表了主体经历阉割后永远缺失的「那个东西」。更准确来说，是不可能被任何实际对象填补的空位，因为「那个东西」从来不是真实的物件。</p><p>因为菲勒斯标志缺失，而缺失产生欲望，所以菲勒斯成为了组织整个欲望经济的中心能指。</p><p>接着便是 Lacan 理论中最具争议的部分：Lacan 认为，在象征界域中性别的分化通过主体与菲勒斯的关系来实现：</p><ul><li>男性位置：主体拥有菲勒斯，即认同于拥有象征权力的位置。但这种「拥有」本身基于阉割⸺他之所以「拥有」是因为他接受了阉割。所以男性位置是有菲勒斯但被阉割</li><li>女性位置：主体是菲勒斯，即成为缺失的对象、成为菲勒斯的承载者。但这同样是一种阉割位置</li></ul><p>Lacan 强调这不是生物学事实，而是象征位置。</p><p>前面说过，Freud 认为菲勒斯等同于实际的男性器官，也就是阴茎⸺他认为儿童最初都认为每个人都拥有该器官，而阉割情结源于发现女性没有它。Lacan 则认为菲勒斯不是实际的器官，是缺失的能指。</p><p><u>阳具中心主义</u>（Phallocentrism）是以菲勒斯为中心来组织社会世界和意义生产的意识形态。更具体地说，社会和文化中的意义生产、权力分配、主体构成都以菲勒斯为核心组织原则。菲勒斯成为了意义的中心，一切事物都通过与菲勒斯的关联来获得意义。</p><p>终于！我们理解了什么是阳具中心主义⸺实际翻译应该也可以叫「菲勒斯中心主义」，用「阳具」一词仅源于 Freud 认为菲勒斯等同于阳具。</p><p>不过女性主义者 Luce Irigaray 认为，尽管 Lacan 说菲勒斯并非阴茎，但他的整个理论结构依然再现了父权制中男性占主导、女性占从属位置的结构。</p><p>要理解 Irigaray 的论点，我们必须搞清楚什么是父权制。</p><h2 id="什么是父权制"><a class="markdownIt-Anchor" href="#什么是父权制"></a> 什么是父权制？</h2><p><u>父权制</u>（Patriarchy）在最初的人类学和社会学用法中，指的是父亲、长男，或者男性群体控制的家庭或者部族。</p><p>在之后的女性主义理论中，它被重新定义为社会制度。其最广泛接受的定义来自英国女性主义社会学家 Sylvia Walby：</p><blockquote><p>a system of social structures and practices in which men dominate, oppress and exploit women.</p><p>一个社会结构和实践的体系，在这个体系中，男性支配、压迫和剥削女性。</p></blockquote><p>该定义的关键要素在于：</p><ul><li>父权制不等于某个男人歧视某个女人，而是嵌入在社会结构中的系统性安排</li><li>父权制是结构性的、建立在社会制度中</li><li>父权制同时包含私人和公共的形式</li></ul><p>或者更广义的表述：女性主义学术理解中的父权制是一个将男性作为群体建构为优于女性作为群体的体系。</p><p>必须要搞明白的是，<strong>父权制不等同于男性！</strong></p><p>bell hooks 在 <a href="https://girlchildlongwalk.org/understanding-patriarchy-intersectional-insights-of-bell-hooks/">《理解父权制》</a> 中给出了非常重要的定义：</p><blockquote><p>Patriarchy is a political-social system that insists that males are inherently dominating, superior to everything and everyone deemed weak, especially females, and endowed with the right to dominate and rule over the weak and to maintain that dominance through various forms of psychological terrorism and violence.</p><p>父权制是一种政治社会制度，它坚持认为男性天生具有支配地位，优于任何被视为弱势的事物和人（尤其是女性），并被赋予支配和统治弱者的权利，且通过各种形式的心理恐怖和暴力来维持这种统治地位。</p></blockquote><p>bell hooks 指出，<strong>父权制实际上没有性别。</strong> 它不仅仅描述男性的支配行为，也描述某些组织和文化叙事如何运作。这意味着批评父权制并不等同于批评男性。父权制是一套制度安排，男性和女性都可以参与再生产它，也都可以受到它的伤害。</p><p>是的，父权制表面上回报男性，实际上也囚禁和损害他们⸺它要求男性压抑情感、遵守角色规范，并导致心理上的痛苦。</p><p>Sylvia Walby 在 <a href="https://revisesociology.com/2017/01/10/patriarchy-structure-walby-sylvia/">《理论化父权制》</a> 中提出父权制会通过六种相互关联的结构来运作：</p><table><thead><tr><th>结构</th><th>运作方式</th><th>简明解释</th></tr></thead><tbody><tr><td>有偿劳动</td><td>职场中的性别隔离、工资差距、玻璃天花板</td><td>女性在劳动力市场中处于结构性劣势</td></tr><tr><td>家庭生产</td><td>女性的家务劳动被无偿占有</td><td>女性在家庭中的劳动不被视为劳动，无报酬、无社会保障</td></tr><tr><td>文化</td><td>媒体、教育、宗教中的性别规范</td><td>温柔、顺从、以家庭为重的「理想女性」形象</td></tr><tr><td>性</td><td>对女性性行为的规训和控制</td><td>荡妇和处女的双重标准、对女性性自主的压制</td></tr><tr><td>暴力</td><td>针对女性的系统性暴力及其被正常化</td><td>家庭暴力、性骚扰被「私事化」，不受严肃对待</td></tr><tr><td>国家</td><td>法律和制度中的性别偏见</td><td>婚姻法、生育政策、社会保障制度中嵌入的性别不平等</td></tr></tbody></table><p>Walby 强调这六种结构是部分相互依存的：它们可以相对独立地变化，但共同构成了父权制的整体运作。</p><p>她还指出，不同阶级、种族和性取向的女性以不同方式经历这些结构。</p><p>王无在公众号文章中便主要触及到 Walby 框架中的「文化」，及文化叙事如何建构「理想女性」形象。而同时提到的「劳动的无偿占有」触及到了家庭生产。</p><h4 id="不同流派对父权制的看法"><a class="markdownIt-Anchor" href="#不同流派对父权制的看法"></a> 不同流派对父权制的看法</h4><p>尽管父权制是所有女性主义流派的核心分析对象，但不同流派对它的根源诊断和变革路径有根本分歧：</p><p>一、激进女性主义认为父权制是最古老的压迫体系，因为性别不平等源于自然生殖差异⸺女性怀孕生育，男性不生育⸺这种生物学差异构成了最早的性阶级系统，它先于且比任何其他形式的压迫⸺如阶级、种族⸺都更深远。</p><p><a href="https://en.wikipedia.org/wiki/The_Dialectic_of_Sex">《性辩证法》</a> 的作者 Shulamith Firestone 主张要彻底消除父权制，就必须用人工生殖技术取代自然生殖，以此来让女性从生育的生物学负担中解放出来。</p><p>她也将马克思主义的辩证方法应用于性别：正如马克思主义认为阶级压迫根源于生产资料的所有权，Firestone 认为性别压迫根源于生殖资料的不平等分配。</p><p>Kate Millett 在 <a href="https://www.marxists.org/subject/women/authors/millett-kate/theory.htm">《性政治》</a> 中提出：</p><blockquote><p>This is so because our society, like all other historical civilisations, is a patriarchy. The fact is evident at once if one recalls that the military, industry, technology, universities, science, political office, and finance—in short, every avenue of power within the society, including the coercive force of the police—is entirely in male hands.</p><p>这是因为我们的社会与所有其他历史文明一样，都是父权制社会。<br>只要回想一下，军队、工业、技术、大学、科学、政治职位和金融⸺简而言之，社会中权力的每一条途径，包括警察的强制力量⸺完全掌握在男性手中，这一事实便显而易见。</p><p>Sexual politics obtains consent through the 'socialisation' of both sexes to basic patriarchal polities with regard to temperament, role, and status. As to status, a pervasive assent to the prejudice of male superiority guarantees superior status in the male, inferior in the female.</p><p>性政治通过使两性在性格、角色和地位方面「社会化」于基本的父权政体来获得认同。就地位而言，对男性优越偏见的普遍赞同，保证了男性的优越地位和女性的低劣地位。</p></blockquote><p>父权制是一套使男性对女性拥有权力的社会安排，其根源不仅在于生物学，更在于社会化过程和意识形态：社会通过教育、文化、宗教等途径将男尊女卑的观念内化为「自然」。</p><p>二、上野千鹤子在 <a href="https://www.arsvi.com/b1990/9010uc.htm">《父权制与资本主义》</a> 中给出了马克思主义女性主义对父权制的定义：</p><blockquote><p>女性の抑圧には物質的な基礎がある。それは、家事労働という不払い労働の家長男性による領有と、したがって女性の労働からの自己疎外という事実である。家父長制は、この労働の性別原理によって利益を得ているから、既婚女性は、階級のちがいを超えて「女性階級 women class」を形成する</p><p>女性受压迫有着物质基础。这一基础在于家父长制男性对家务劳动这一无偿劳动的占有，以及由此导致的女性与其劳动成果的自我异化。由于家父长制从这种劳动性别分工原则中获益，因此已婚女性跨越了阶级差异，构成了「女性阶级」。</p></blockquote><p>上野的核心论点是：</p><ul><li>在近代社会中，女性同时受到资本主义支配的市场和父权制支配的家庭的双重压迫</li><li>马克思主义女性主义最大的贡献是发现了家务劳动这一概念。上野提出「无酬家务劳动」，指出女性在家庭中付出的劳动被无偿占有，这是父权制的物质基础</li><li>父权制和资本主义是两个独立但相互交织的体系。因此不能将父权制简单还原为资本主义的副产品，也不能将资本主义还原为父权制的副产品</li></ul><p>Silvia Federici 在 <a href="https://theanarchistlibrary.org/library/silvia-federici-caliban-and-the-witch">《卡利班与女巫》</a> 中从历史角度补充了这一分析。她追溯了欧洲从封建制向资本主义过渡期间，女性身体如何被规训。</p><p>例如猎巫运动不仅是宗教狂热，更是一场将女性的生殖能力和劳动能力纳入资本主义和父权制控制的社会工程。</p><p>三、自由女性主义不追求彻底重构社会，而是将父权制理解为具体的法律和制度障碍，如选举权缺失、职场歧视、财产权不平等。变革路径是通过法律和政治改革逐一消除这些障碍。</p><p>在这个框架中，「父权制」更多被分解为一系列可以被逐项解决的具体问题，而非一个需要被整体推翻的结构。</p><p>四、Kimberlé Crenshaw 提出了 <u>交叉性女性主义</u>，并指出黑人女性同时经历种族压迫和性别压迫，而这种交叉体验大于种族主义和性别主义的简单总和。</p><p>这意味着：不能将父权制理解为一个独立于种族、阶级、性取向等其他权力轴的纯粹性别压迫 —— 父权制的具体运作方式因其他身份维度而异。</p><h4 id="父权制能否被终结"><a class="markdownIt-Anchor" href="#父权制能否被终结"></a> 父权制能否被终结？</h4><p>Gerda Lerner 在 <a href="https://gerdalerner.com/the-creation-of-patriarchy/">《父权的建立》</a> 中做了对整个概念具有奠基性意义的论证：父权制不是「自然的」或「生物学的」，而是历史地建构的 —— 因此它也可以被历史过程终结。</p><p>Lerner 考察了古代近东（美索不达米亚）文明的历史、考古和文学证据，提出父权制作为一套社会组织方式是在公元前第二千纪的早期国家形成过程中逐步建立的。她论证的关键步骤包括：</p><ol><li>父权制有一个起点。它不是人类社会的原始状态，而是在特定历史条件下被建构出来的</li><li>父权制的建立是一个过程：女性在早期农业社会中实际上享有相对平等的地位，但在后来被逐步剥夺了经济独立、性自主，以及政治参与权</li><li>父权制一旦建立就会自我再生产。它通过法律、宗教、文化将自身「自然化」，使后代将其视为「从来如此」的自然秩序，而非历史地建构的权力安排</li></ol><p>Lerner 还提出了很重要的洞见：父权制能够给予底层男性补偿性的特权。即使在阶级上处于底层的男性，也通过性别等级获得了一种相对于女性的优越地位。这种机制使得底层男性有动机维护父权制，因为这是他们唯一能享有的支配地位。</p><h4 id="父权制是有意识的阴谋吗"><a class="markdownIt-Anchor" href="#父权制是有意识的阴谋吗"></a> 父权制是有意识的阴谋吗？</h4><p>理解父权制的一大关键点在于，<strong>它并非有意识的阴谋。</strong> 它运作起来往往是看不到的，参与者也不需要知道自己在参与父权制。</p><p>父权制的自我再生产通过以下机制运作：</p><ol><li>父权制嵌入在法律、教育、就业、家庭等制度中，通过这些制度的日常运作来再生产自身⸺这不需要任何人策划</li><li>父权制通过文化叙事将自身的规则呈现为「自然」⸺也是我这个月初经常提到的 <a href="/posts/1cfd.html">意识形态自然化</a></li><li>个体在认同「理想女性」或「理想男性」形象的过程中，内化了父权制的性别规范，并将其视为自己的「自然」身份</li><li>父权制给予所有男性一种基于性别的地位优势，即使他们在其他维度⸺如阶级、种族⸺上处于劣势。这使得男性有动机维护这个体系，即使它也伤害他们</li></ol><h4 id="irigaray-对-lacan-的批判"><a class="markdownIt-Anchor" href="#irigaray-对-lacan-的批判"></a> Irigaray 对 Lacan 的批判</h4><p>现在我们可以回到先前搁置的问题：为什么 Irigaray 认为 Lacan 的理论结构再现了父权制？</p><p>她的核心论点可以概括成以下几条：</p><p>一、Lacan 的象征界域是父权制的理论翻版。</p><p>Lacan 虽然说菲勒斯不是阴茎，但他的整个理论结构都再现了父权制中男性占主导、女性占从属位置的结构。</p><p>Lacan 将菲勒斯与阴茎做了概念区分，但是该区别在实践中几乎不生效：菲勒斯作为中心能指的功能，与父权制中阴茎或者男性作为中心的社会功能，在结构上同构。</p><p>二、女性被排除在象征界域之外。</p><p>如果整个象征界域都是以菲勒斯作为中心组织的，那么女性只能通过「与菲勒斯的关系」来获得位置。她没有独立于菲勒斯之外的象征存在。</p><p>Lacan 的象征界域依然是父权主导的，没有为女性自我定义提供空间。</p><p>三、女性性特征被还原为「非一」。</p><p>Irigaray 在《此性非一》（<em>This Sex Which Is Not One</em>）中指出，在阳具中心主义的框架中，女性性特质被定义为「非男性」，即作为缺失、被动、「不是一」，而非有其自身的正面规定。女性的身体经验无法在菲勒斯中心的语言中得到表达。</p><p>四、Lacan 曾说过 <em>La Femme n'existe pas</em>（「女人不存在」），意思是在象征界域中没有「作为整体的女人」这一能指。</p><p>Irigaray 认为阳具中心主义下，女性作为独立主体「不存在」了，她只能作为男性的镜像和缺失来获得位置。</p><p>Irigaray 的批判对我们理解王无的文章有直接意义。Lacan 的框架本身就是以菲勒斯为中心的框架，用它来分析性别叙事，意味着揭示父权制的工具可能自身也携带着父权制的烙印。</p><p>但 Lacan 就完全不可用么？那也不然。Lacan 提出的许多概念仍然可以帮助我们理解父权制是如何通过语言和文化叙事而运作的。我们需要记住：批判工具本身从来都不是中立的。</p><h2 id="回到对公众号文章的解析"><a class="markdownIt-Anchor" href="#回到对公众号文章的解析"></a> 回到对公众号文章的解析</h2><p>说了这么一大堆，我终于可以开始解析该文章了！</p><h4 id="意识形态的自然化"><a class="markdownIt-Anchor" href="#意识形态的自然化"></a> 意识形态的自然化</h4><p>王无在文中执行了 Louis Althusser 式的意识形态分析，以揭示一个看似自然而然的文化产品是如何作为意识形态装置运作的。</p><p>说 Althusser 可能有读者朋友们会摸不到头脑，其实他的框架很好理解：</p><p>一、一个文本不仅有它说出来的东西，还有它没有说出来的东西。</p><p>二、国家机器有两种：镇压性国家机器和意识形态国家机器。</p><p>现代社会维持阶级统治的主要力量是意识形态，尤其重要的是教育系统，因为它能够内化学生对社会秩序的服从、对权威的尊重、对劳动纪律的适应</p><p>三、<u>召唤</u> 描述了意识形态如何将个体构成为主体。设有人在街上行走，有人在背后大喊「喂！」，那个人转过头来⸺这个转头的动作就是「召唤」：个体在回应互换的过程中承认了自己被召唤的身份，从而被构成为一个服从于权威、认同自身社会位置的主体。</p><p>Althusser 认为，意识形态总是已经召唤了个体。个体从出生前就被家庭、语言、文化召唤了。</p><p>他否认「先有一个主体，然后主体接受或拒绝意识形态」，而认为「意识形态召唤出了主体，主体在回应召唤的过程中才成为主体」。这与 Lacan 的「语言构成主体」极其相似。</p><p>当个体将文化观念当作「理所当然」、「显而易见」来接受时，意识形态的效果最强。Althusser 认为，意识形态运作最好的时候，就是人们感觉不到自己在意识形态中的时候。</p><p>文章结尾王无写道：</p><blockquote><p>在每一次对牛郎织女的故事的讲述的背后，都有一个父权制的形象指着这样的织女，对所有的女人说⸺你们看，好的女人就应该是这个样子，都给我们学起来。</p></blockquote><p>这段话的学术含义是，故事通过建构「理想女性」的能指⸺织女等同于顺从、忠贞、无怨无悔的爱人⸺对女性读者执行了意识形态召唤。</p><p>读者在认同织女「美好爱情」叙事的过程中，不知不觉地内化了父权制的性别规范，即女性应顺从、应将客体化，误认为成是浪漫。</p><h4 id="lacan-的能指分析应用"><a class="markdownIt-Anchor" href="#lacan-的能指分析应用"></a> Lacan 的能指分析应用</h4><p>王无所使用的分析工具来自于 Lacan，具体来说是象征界域的能指分析：</p><ul><li>「羽衣」被解读为织女「自由意志和主体力量的终极能指」</li><li>「偷衣」被解读为「对女性自由的符号性圈禁」，即通过剥夺能指来控制主体在象征界域中的位置</li><li>「老牛」被解读为「菲勒斯（阳具）」，即象征界域中组织欲望的中心能指⸺「能指」（signifier）指的是符号的形式。符号的另一层面是「所值」（signified），即符号所代表的心理概念</li><li>「牛郎」被解读为「父权制下所有男性的理想自我投射」，即想象界域中的镜像认同对象</li></ul><p>这些操作在 Lacan 框架内是有逻辑可循的。Lacan 的精神分析确实是关于能指如何组织主体关系的理论。</p><p>那么能不能用 Lacan 分析民间故事？答案是完全可以。但是文章在具体执行中违反了 Lacan 理论自身的若干原则。之后会逐一分析。</p><h4 id="swan-maiden-母题"><a class="markdownIt-Anchor" href="#swan-maiden-母题"></a> Swan Maiden 母题</h4><p>王无提到羽衣承担了身份标记和行动能力的功能：有羽衣的织女是天界的自由主体；没有羽衣的织女是被困人间的凡人妻子。剥夺羽衣象征着剥夺织女在象征界域中的位置，将她从「主体」降格为「客体」。</p><p>民俗学研究里有个在全球民间故事中都出现频繁甚至结构相同的母题，叫作 <u>Swan Maiden</u>（天鹅少女）。该母题讲述男子与超自然的女性生物订立契约或者结婚，随后后者会离开。变形时，她们往往会变成鸟类，或者使用羽毛披风。</p><p>在典型的故事中，少女会在水域中⸺通常在洗浴⸺而男子会过来偷走、隐藏或者焚烧她的羽毛衣服，使她无法飞走或游走，迫使她成为他的妻子。她也通常是多位少女中的一位，且往往是最小的那位。</p><p>只是这么说，读者朋友们的脑海中有没有浮现出许多童话或者民间故事呢？更重要的是，牛郎织女的传说也沿用了该母题。王无对羽衣的符号学解读，也是对该跨文化母题的合理分析。</p><h4 id="公众号文章的政治立场"><a class="markdownIt-Anchor" href="#公众号文章的政治立场"></a> 公众号文章的政治立场</h4><p>再是王无的政治立场最接近激进女性主义，即将父权制视为故事的根本动力，将性别支配关系⸺而非阶级、经济或其他因素⸺作为首要分析维度。同时，王无关于「劳动无偿占有」的论述也调用了社会主义女性主义的资源⸺如上野千鹤子的「无酬家务劳动」概念。</p><p>在这个定位下，王无的目标不是中立地理解故事，而是揭示故事在性别权力结构中的意识形态功能。这个目标本身是合法的⸺批判理论从来不是中立的，它的立场性是其方法论的一部分。</p><p>法兰克福学派的创始人兼批判理论之父 Max Horkheimer 在 1937 年的 <a href="https://jamescrane.substack.com/p/philosophy-and-critical-theory-1937">《哲学与批判理论》</a> 中写道：</p><blockquote><p>……critical theory is nowhere interested solely in the accumulation of knowledge as such and for its own sake, but everywhere in the emancipation of human beings from enslaving social relations.</p><p>…… 批判理论从不单纯为了知识本身而积累知识，而是处处致力于人类从奴役性社会关系中的解放。</p></blockquote><p>传统理论满足于正确地描述世界，但描述本身隐含了意识形态效果，因为你将社会现状当成了事实、默认了现状的合法性。</p><p>例如奴隶社会的社会学家精确地描述了奴隶制的运作方式，但从不质疑奴隶制本身的合法性，那么他的解释尽管在技术上是正确的，但在政治上是在间接为奴隶制提供合法性，因为奴隶制成为了客观事实而不是可被推翻的不正义。</p><p>批判理论不仅要正确地描述社会，还要揭示社会结构如何压迫人、这种压迫如何被掩盖，以及这种压迫如何可以被克服。</p><p>但立场性不等于可以跳过论证。批判理论的立场性意味着它有明确的解放目标，但不意味着它可以以结论代论证。它仍然需要在逻辑和证据上经得起检验。</p><h2 id="公众号文章的问题所在"><a class="markdownIt-Anchor" href="#公众号文章的问题所在"></a> 公众号文章的问题所在</h2><h4 id="父权制没有意识"><a class="markdownIt-Anchor" href="#父权制没有意识"></a> 父权制没有意识</h4><p>王无认为传说版本的演变是「精心策划的、系统性传播的符号篡位」，使用了阴谋论式的因果模型，以暗示存在一个有意识、有预谋的「篡位」行为。</p><p>这与父权制的实际运作机制相矛盾。</p><p>如我们在先前的条目中所分析的，父权制一旦建立就自我再生产、不需要有意识的策划者。</p><p>再是王无自己提出了「符号达尔文主义」⸺即自然选择式的淘汰⸺这个隐喻，但紧接着又说「精心策划的符号篡位」，这两个隐喻在逻辑上是矛盾的：达尔文主义的自然选择不存在策划者，有策划者的篡位也不是达尔文主义。</p><p>在多个版本的竞争性流传中，那个更好地服务于父权制再生产的版本（偷衣版）获得了更多的传播动力，因为它的叙事结构更好地满足了古代男性群体的欲望投射，同时更有效地将不平等关系浪漫化。这实际上是结构性筛选，而非策划性篡位。</p><h4 id="lacan-的能指分析要求差异"><a class="markdownIt-Anchor" href="#lacan-的能指分析要求差异"></a> Lacan 的能指分析要求差异</h4><p>王无认为故事中的「老牛」意味是牛郎的阳具，证据是方言俚语。</p><p>第一个问题在于方言俚语能否直接等同于普遍符号功能？这一说法属于过度诠释。</p><p>第二个问题在于能否用阴茎的联想来论证菲勒斯的存在？</p><p>原文是这么写的：</p><blockquote><p>那耕牛则是牛郎的阳具（牛和牛子在很多方言里指代男性生殖器），是一个被僵死的异化的权力秩序所制造的享乐工具，一个菲勒斯去介入和征服女人客体的英雄。</p></blockquote><p>论证是从阴茎出发，再推导出老牛等于菲勒斯的。</p><p>菲勒斯属于象征界域的能指，而阴茎的俚语联想来源于想象界域的形象。在 Lacan 的理论中，这是错误的，因为本该分析象征结构的地方却退回到了形象联想。</p><p>如果正确地来做这个分析，我们应该问自己，老牛在故事中承担了什么象征功能？答案是老牛是牛郎获取织女的中介，因为它告知牛郎去偷衣，也是它死后让牛郎披皮上天追赶。它是牛郎从凡人世界进入天界⸺象征界域中「高位」的领域⸺的通道。这个功能确实可以被分析为一种象征性的权力授予，但它的准确性质是「跨越界限的中介」，甚至说更接近于「父亲之名」，而非「菲勒斯」。</p><p>如果任何叙事中的雄性动物都可以因为方言联想而被解读为「菲勒斯」，那么这个解读就没有区分度，因为它无法解释为什么 <span class="emphasis">这个</span> 故事中的 <span class="emphasis">这头</span> 牛具有特殊的象征功能，而不是一切故事中的一切雄性动物（或者说「牛」）都是菲勒斯。Lacan 的能指分析要求能指之间有差异化的定位。</p><h4 id="强奸到底是什么"><a class="markdownIt-Anchor" href="#强奸到底是什么"></a> 「强奸」到底是什么？</h4><p>王无在文中写道：</p><blockquote><p>…… 牛郎单方面发起的、针对织女的初始性暴力（偷窥、盗窃、强奸、囚禁）。</p><p>…… 织女，不止要被强奸，生娃，监禁，给男人无偿劳作，更有意思的就是她还要真心实意地爱上牛郎，真心实意地和牛郎鹊桥相会，就像一个器物一样忠诚到别无二心</p></blockquote><p>王无调用了激进女性主义中一个特定的理论传统，即胁迫下的同意不是真正的同意。该原则有学术渊源：在性别权力不对等的结构性条件下，女性的「同意」可能是被胁迫的产物，因为她在不平等的结构中缺乏真正的拒绝能力。</p><p>当代法律中也有体现该原则的地方，如婚内强奸的确立基于「婚姻关系中的同意不能被自动推定」这一法理。</p><p>如果王无做的是这样的论证：「在织女的人身自由被剥夺的结构性条件下，她与牛郎的结合即使有『同意』的外观，这种同意也是在胁迫条件下产生的，因此不构成真正的同意」⸺那这将是一个在激进女性主义法理框架内合法的论证。</p><p>但王无没有做这个论证，直接将「强奸」作为不加界定的标签使用，没有说明是什么法律和伦理框架下使用的「强奸」一词、整个因果链内哪一步构成了「强奸」、织女在故事中是否有任何拒绝的空间⸺先前提到，因为故事版本的不同，也存在着织女有拒绝空间的版本。不过这一点我认为问题出在确立讨论的是哪个版本的牛郎织女传说，也是之后会深究的话题。</p><p>「强奸」这个概念本身需要被区分成描述性使用和规范性使用。王无同时将其用作对故事事件的描述，也用于批判故事的意识形态功能。这两种用法需要不同的论证来支撑，但在公众号文章中被混为一谈。</p><h4 id="女人是男人的幻想工具人吗"><a class="markdownIt-Anchor" href="#女人是男人的幻想工具人吗"></a> 女人是男人的幻想工具人吗？</h4><p>王无说「织女从根本上就只是一个被男性凝视结构出来的，用以满足古代农村反动男性的欲望在父权建制的奴役下产生的幻想的工具人而已」，并引用了 Lacan 所说的「女人是男人的症状」。</p><p>Lacan 这句话出自于第二十期研讨班的《再来一次》，原文是：</p><blockquote><p>On dit que les femmes sont les symptômes des hommes</p><p>据说女人是男人的症状</p></blockquote><p>关键点分别在于：</p><ol><li>「据说」意味着 Lacan 在引述一种观点。该命题的语气是反思性而非肯定性的</li><li>在 Lacan 晚期理论中，「症状」⸺也叫「病症」（sinthome）⸺指的是主体发明用来维系三个界域结构的独特方式。作为例子，詹姆斯・乔伊斯的写作就是他的「病症」，因为通过写作他能维系三个界域之间的联结。症状不是幻想的工具</li><li>「女人是男人的症状」的准确含义是，男性的主体性依赖于他与女性关系所构成的症状性结构来维系。换句话说，不是「女人是男人的工具」，而是「男人的主体性是通过与女人的关系来组织的」⸺这个关系本身就是他的「症状」，是他存在的方式</li></ol><p>因此我得出，王无错将 Lacan 的这句话理解为「女人是男人欲望投射的幻想工具人」，而这将 Lacan 的命题从关于主体结构的分析降格成了关于工具化的描述。</p><p>王无引用 Lacan 是为了给「织女是工具人」这一判断提供权威的支持，不过 Lacan 的命题并不能做到这一点。既然男性的主体性依赖于女性，那么其实隐含的是「男性不能没有女性」，而非「女性只是男性的工具」。</p><p>如果女性是男性的「症状」，即男性存在的结构性支撑，那么女性就绝非只是工具那么简单，而是男性主体性构成的必要条件。</p><p>我建议引入先前提到的 Irigaray 的视角：她批判 Lacan 的象征界域以菲勒斯为中心组织、排除了女性的独立主体性，因为该框架没能为女性的自我定义提供空间，即女性只能通过与菲勒斯的关系来获得位置。</p><h4 id="循环论证问题"><a class="markdownIt-Anchor" href="#循环论证问题"></a> 循环论证问题</h4><p>王无提到织女提供的爱是象征性暴政。这一部分我是非常认可的。</p><p>意识形态最有效的运作不是强迫，而是让人们资源认同支配结构。如前所述，意识形态通过「召唤」让个体在认同中内化规范。换到牛郎织女传说中，织女不仅被迫服从，还被要求、并在叙事中被呈现为真心爱上这个服从。</p><p>法兰克福学派的 Marcuse 在 <a href="https://www.marcuse.org/herbert/pubs/64onedim/odm1.html">《单向度的人》</a> 中提出，发达工业社会通过制造虚假的需求来让人们自愿参与自身的压迫。人们以为自己想要的东西，实际上是体制植入的。织女以为自己爱牛郎，但这种爱可能是父权结构植入的虚假意识。</p><p>Hegel 的 <u>主奴辩证法</u>（Lord-Bondsman dialectic）中也提到，承认应该是两个独立主体之间的相互确认。王无认为，牛郎追求的不是织女作为平等主体的承认，而是对已归顺的客体的拥有感。</p><p>该命题有需要审慎对待的维度：叙事中织女的爱究竟是被迫的，还是自发的？如果一律将织女表现出的爱视为被迫的虚假意识，就会陷入 <u>循环论证</u> 中：先假定织女没有主体性，所以凡是看起来像主体性的行为都证明她被更深地被欺骗了，因此证实她没有主体性。</p><p>故事将一段起源于暴力的关系呈现为爱⸺这个叙事操作本身就是意识形态的运作，无论织女在故事内部是否真的爱牛郎。它教导读者「起源于暴力的关系可以或者应该被体验为爱」。问题不在于织女的爱是真是假，因为这在叙事内部是无法被判定的，而在于叙事抹平了暴力起源与爱的体验之间的矛盾。这才是「爱作为象征性暴政」的准确含义。</p><h4 id="深度展开循环论证"><a class="markdownIt-Anchor" href="#深度展开循环论证"></a> 深度展开循环论证</h4><p>循环论证会导致命题不可证伪。现在我想要深度谈谈批判理论传统中已知的一问题：虚假意识概念的自指悖论。</p><p>如果意识形态使得被支配者无法认识到自己的被支配状态，即她们处于虚假的意识中，那么任何被支配者表现出的「满意」、「认同」、「爱」都可以被解释为虚假意识的症状。</p><p>那么，什么证据能够证伪「她处于虚假意识中」这一判断？如果她表达不满，这证明她被压迫；如果她表达满意，这证明她被更深地压迫。在这种结构中，没有任何经验证据能够推翻「她被压迫」的判断⸺因此这判断不可证伪。</p><p>这不是公众号文章独有的问题，而是意识形态批判传统中、法兰克福学派内部长期有着争论的结构性困境。</p><p>如 Habermas 曾批评早期法兰克福学派的意识形态批判陷入了彻底批判的悖论，即如果一切意识都是意识形态，那么批判者自身的批评意识也是意识形态，批判不就失去了立足点？</p><p>Althusser 则试图通过「科学」和「意识形态」的认识论断裂来解决这个问题，但这个方案被批评为将批评者置于不可批判的「科学」位置上。</p><p>公众号文章没有意识到该困境。文章无意识地使用了「虚假意识」的逻辑，但没有反思这个操作的认识论后果。如果文章要避免循环论证，它需要提供一个判定虚假意识的标准，即在什么条件下可以区分「真正的认同」和「虚假意识下的认同」。文章没有提供这个标准。</p><p>但文章只是个公众号文章而已，不是学术论文⸺我这篇文章也不是学术论文。要求我们解决法兰克福学派内部数十年的认识论争论是不现实的。我仅是指出公众号文章所处理论传统的结构性限制，而非王无本人的失误。这一点一定要清楚。</p><h4 id="谁被献祭给了什么"><a class="markdownIt-Anchor" href="#谁被献祭给了什么"></a> 谁被献祭给了什么？</h4><p>王无提出鹊桥等同于符号性献祭的观点，其叙事功能在于「弥合初始暴力与强制团圆之间的巨大矛盾」。</p><p>我认可该观察。鹊桥确实在情感层面弥合了这样的裂缝，用浪漫的意象覆盖暴力的起源。</p><p>不过鹊桥作为符号性献祭，但到底是谁被献祭给了什么？如果说织女被献祭，那么是被献祭给了什么？父权制？叙事的完整性？读者的情感满足？它作为分析概念实在过于模糊。</p><p>我的分析是，鹊桥在叙事中的功能是仪式化。它将一段起源于暴力的关系通过年度仪式转化为永恒的爱情象征。仪式的功能正是将偶然的、暴力的起源自然化和永恒化，也就是通过每年重复的鹊桥相会、将「本来如此」替代「最初如此」。</p><p>在这个意义上，鹊桥就可以被分析成意识形态的仪式装置了。</p><h4 id="王母娘娘是解救者吗"><a class="markdownIt-Anchor" href="#王母娘娘是解救者吗"></a> 王母娘娘是解救者吗？</h4><p>王无认为故事中的「反派」王母娘娘解救了织女。</p><p>在 Lacan - Althusser 的框架中，象征界域会通过意识形态国家机器来再生产自身，那么王母娘娘在故事中的功能是象征秩序的执法者。</p><p>在 Lacan 自己的框架中，她扮演的是接近「父亲之名」的位置，目的在于将违反法则的主体重新归位。这与王无在其他地方的分析框架是一致的：父权制等于象征秩序，象征秩序通过法则来规训主体。</p><p>不过王母娘娘是解救者吗？如果父权制是象征秩序，而王母是象征秩序的执法者，那这是否意味着王母也是父权制的代表？她将织女带回天界是为了恢复象征秩序的规则，且天界秩序本身也是等级化的。</p><p>整个故事中没有任何角色在维护女性的主体性⸺这是个非常重要的观察。牛郎的偷衣是父权制的私人形式，即男性个体对女性个体的支配；王母的干涉是父权制的公共形式，即制度对个体关系的规训。两者都是父权制的运作，只是层面不同。</p><p>因此我们无法从王母那儿找到反父权的力量。</p><h4 id="大他者是抽象的"><a class="markdownIt-Anchor" href="#大他者是抽象的"></a> 大他者是抽象的</h4><p>王无说：</p><blockquote><p>当所有的一切都要归属于这个作为偷窥者，监禁者，强暴者和绝对统治者的牛郎，那个代表应该在爱情伦理中牺牲一切的肉体，心灵，子宫和劳动力的织女也就差异性地被大他者指认出来。</p></blockquote><p>这里的「大他者」概念被错误使用了。</p><p>先前说过，大他者是象征界域本身的拟人化，不是任何具体的人或者机构。它是语言、法律、文化秩序的抽象「他者」。我也说过，主体在语言中被构成，意味着主体是从属于大他者、是被语言所塑造的。</p><p>但王无将大他者理解成父权制的幕后操盘手，就好像有具体的人或者机构在指认织女应该牺牲一切。这错误地将大他者实体化了。王无想要使用的概念更接近通俗意义上的社会压力，还有父权制的代言人。</p><p>同样的事情也发生在「享乐」一词上。Lacan 的「享乐」（jouissance）是高度技术性概念，是超越快乐原则、痛苦与快感交织的体验，是主体在突破象征界域时体验到的溢出。</p><p>不过文章将「享乐」用作接近「性享受」的通俗含义。</p><h2 id="公众号文章的修辞"><a class="markdownIt-Anchor" href="#公众号文章的修辞"></a> 公众号文章的修辞</h2><p>和我进行讨论的博友在阅读公众号文章后，第一反应是震撼于全篇极具情绪偏向的词汇⸺我的判断在于它是首先被提及到的，所以它最重要、是第一印象⸺所以我想要分析分析文章的修辞。</p><p>王无的词汇滑移链条是这个样子的：</p><pre><code class="language-plaintext">父权欲望 → 男性凝视 → 客体化 → 符号性圈禁 → 偷窥 → 盗窃 → 强奸 → 囚禁 → 性剥削 → 子宫剥夺 → 无偿劳动</code></pre><p>前半段⸺从父权欲望到符号性圈禁⸺是学术概念。它们有明确的理论定义，属于批判理论和精神分析的专业术语。</p><p>后半段⸺从偷窥到囚禁⸺是法律概念。它们有明确的法律定义，指涉具体的犯罪行为。</p><p>王无的修辞策略在于，通过将学术概念和法律概念放在同一条链条中，制造一种从理论分析到法律指控的过渡，让读者在后半段里不知不觉就接受法律指控的框架。</p><p>该策略的修辞效果极强，因为它可以让读者觉得「强奸」、「囚禁」等指控是从学术分析中自然推导出来的，还不需要独立论证。不过在分析层面，「没有独立论证」是个问题：学术概念和法律概念属于不同的范畴。从前者推出后者需要范畴转换的论证，例如在什么条件下象征层面的圈禁等同于法律层面的囚禁？</p><h2 id="对主要反对意见的回应"><a class="markdownIt-Anchor" href="#对主要反对意见的回应"></a> 对主要反对意见的回应</h2><p>接着是我对 <a href="https://cuixiping.com/blog/post/afskcj">博友</a> 的观点的回应。这里包括我原本就回应的内容、我想了想后自行补充的内容。</p><h4 id="故事传颂是因为人民群众的美好愿望"><a class="markdownIt-Anchor" href="#故事传颂是因为人民群众的美好愿望"></a> 故事传颂是因为人民群众的美好愿望</h4><p>但是这是谁的美好愿望？在古代社会中，男性和女性的愿望是否一致？</p><p>美好愿望的具体内容是什么？是对跨越阶层的浪漫爱情的向往？还是对勤劳农夫获得仙女青睐的代入式满足？</p><p>为什么「美好愿望」会筛选出「偷衣、强留」这个特定版本，而不是其他同样可以承载「美好愿望」的版本？比如早期隔河相望的版本不就很美好吗？</p><p>「美好愿望」和「父权意识形态筛选」完全可以同时成立。一个故事之所以流传，可能 <span class="emphasis">既</span> 因为它满足了人们的情感需求（美好愿望），<span class="emphasis">也</span> 因为它在无意中再生产了特定的权力关系（意识形态效果）。</p><p>父权制的运作通过满足人们的「美好愿望」来实现。这一点先前已经说过，意识形态最有效的运作方式不是强迫，而是让人们自愿地认同和传播它。</p><h4 id="如果父权意识形态筛选版本更应该筛选出天帝安排版本"><a class="markdownIt-Anchor" href="#如果父权意识形态筛选版本更应该筛选出天帝安排版本"></a> 如果父权意识形态筛选版本，更应该筛选出「天帝安排」版本</h4><p>天帝安排织女嫁给牛郎、织女荒废纺织被惩罚的版本更符合父权的「掌控」还有「支配权」，但该版本没有成为流传最广的版本，因此博友认为「父权筛选」论不成立。</p><p>该反诘的前提假设在于，父权制偏好最直白的支配叙事。但事实是否如此？</p><p>天帝安排版确实具备父权制里服从安排、不可荒废职责的特质，不过它缺乏浪漫化的空间，无法激发情感认同。</p><p>尽管偷衣版包含了暴力元素在内，但可以被包装为穷小子用计谋赢得仙女芳心的浪漫故事，也就有了更强的情感动员力。</p><p>父权制的筛选不一定偏好最直白的支配叙事，而可能偏好最能有效遮蔽自身暴力性的叙事，即那种将不平等关系包装为浪漫爱情的叙事。</p><p>另一点在于，父权制不等同于统治阶级权威。天帝安排版中的支配是等级性的，即天神大于人类，而偷衣版中的支配是性别性的，即男性大于女性。</p><h4 id="流传最广的版本是温和的即牛郎归还了衣服-织女自愿留下不存在偷窥和胁迫"><a class="markdownIt-Anchor" href="#流传最广的版本是温和的即牛郎归还了衣服-织女自愿留下不存在偷窥和胁迫"></a> 流传最广的版本是温和的，即牛郎归还了衣服、织女自愿留下，不存在偷窥和胁迫</h4><p>这一点先前已经提到，有学者统计发现民间流传的主流版本是不归还衣服、胁迫成婚的版本。</p><p>实际上，先前我就说明过讨论范畴是「偷衣版」。</p><h4 id="牛郎织女更接近一种得不到的粉色幻想即性转版的霸道总裁爱上平凡的我"><a class="markdownIt-Anchor" href="#牛郎织女更接近一种得不到的粉色幻想即性转版的霸道总裁爱上平凡的我"></a> 牛郎织女更接近一种得不到的粉色幻想，即性转版的「霸道总裁爱上平凡的我」</h4><p>两者确实共享核心结构，不过该论点存在两个问题：</p><ol><li>自相矛盾。「霸道总裁」模式本身在女性主义批评中受到过类似的批判：承载不平等的权力关系、浪漫化控制欲。如果承认了牛郎织女传说是性转版的霸道总裁，那也就承认了故事中有着不平等权力关系的幻想</li><li>忽略关键差异。霸道总裁故事中的女主角通常保有人身自由、拒绝权和精神独立性，但偷衣版里的织女是因羽衣被窃而丧失了离开的能力</li></ol><h4 id="古代爱情故事基本都是见色起意-一见钟情不会展现魅力来获取认同"><a class="markdownIt-Anchor" href="#古代爱情故事基本都是见色起意-一见钟情不会展现魅力来获取认同"></a> 古代爱情故事基本都是见色起意、一见钟情，不会展现魅力来获取认同</h4><p>中国古代民间传说确实以一见钟情为主要的情感模式，不过我在意的是故事实现结合的手段是什么。</p><p>即使是一见钟情，不同的故事赋予男性角色的手段仍然不同。</p><h5 id="如果把牛郎织女理解为胁迫那所有屈从现实婚姻的女性都算被胁迫"><a class="markdownIt-Anchor" href="#如果把牛郎织女理解为胁迫那所有屈从现实婚姻的女性都算被胁迫"></a> 如果把牛郎织女理解为胁迫，那所有屈从现实婚姻的女性都算被胁迫</h5><p>这是错误类比，存在着根本性的结构差异。</p><p>对方的推论准确来说是「如果无法嫁给理想对象而嫁给不理想对象算胁迫，那所有现实中的不理想婚姻都是胁迫」。</p><p>但现实中嫁给不满意丈夫的女性，通常保有人身自由。她可以拒绝、离婚、离开，尽管现实中经济和社会压力会使这些选择困难，但在法律上她是自由的。</p><p>但偷衣版中的织女在叙事起点就丧失了离开的物理能力。她的选择是在自由已被剥夺的条件下做出的。</p><p>「在自由条件下因现实压力而做出不理想选择」能等同于「在自由被暴力剥夺条件下做出的选择」么？两者在伦理和法律上都有着本质的区别。</p><p>例如现代法律中，在绑架条件下发生的婚姻会被视为无效，即使被害人表现出同意，因为同意的前提是自由。</p><h4 id="激进女权会把很多本与男权女权无关的事情附会到性别压迫上去"><a class="markdownIt-Anchor" href="#激进女权会把很多本与男权女权无关的事情附会到性别压迫上去"></a> 激进女权会把很多本与男权女权无关的事情，附会到性别压迫上去</h4><p>作为一般性判断，我认同。我在深度分析中就点出过王无的「牛等于菲勒斯」是过度诠释。</p><p>不过偷衣版的牛郎织女故事是否属于「本与性别权力无关的事情」？</p><p>这个故事的核心情节是：男性通过窃取女性的身份凭证（羽衣）来剥夺她的行动自由，迫使她留在人间与之成婚。这个情节本身就涉及性别权力关系。</p><p>Swan Maiden 母题的跨文化普遍性更进一步证实了这一点：全世界多个文化都独立产生了这样的叙事，意味着存在某种深层共享的社会心理结构。</p><h4 id="激进女权只有标签没有分析"><a class="markdownIt-Anchor" href="#激进女权只有标签没有分析"></a> 激进女权只有标签没有分析</h4><p>该批评有着有效的内核。王无的文章确实停留在文化叙事层面的批判，没有将叙事分析与具体的社会制度联系起来⸺例如婚姻法中的财产分配、家务劳动的法律地位、职场性别歧视的具体规则。</p><p>不过博友说的「言之无物」实在是太绝对，因为王无的分析聚焦于文化叙事的符号学层面，属于特定层面的分析。你可以说他不够全面，但不能说「无物」。</p><p>博友也认为激进女权讲到的永远只有性剥削和劳动剥削这一套⸺实际上并非如此，激进女性主义会涉及到大量具体的制度分析，并非简单、反复出现的空洞话术。</p><h4 id="王无没有指出哪些具体的现有社会规则"><a class="markdownIt-Anchor" href="#王无没有指出哪些具体的现有社会规则"></a> 王无没有指出哪些具体的现有社会规则</h4><p>该要求部分合理但标准过高。王无做的是意识形态批判，功能是揭示文化叙事如何在无意识层面再生产权力关系，而不是指出某条具体法律有问题。</p><p>我将王无的文章划分成文艺批评和文化现象分析，其功能是解构经典、揭示文本背后的隐蔽观念。它不承担提出社会学意义上社会现实问题解决方案的义务。发现并剖析问题本身就有独立的价值。</p><p>作为例子，鲁迅的《狂人日记》没有提出解决「吃人」文化的方案，但他的批判是无效的吗？自然不是。</p><p>当然，如果将文化叙事的意识形态分析与具体社会制度联系起来，是最好的，但我们无法要求他人写文都这么写。</p><h4 id="激进女权认为只有全女性世界才没有剥削"><a class="markdownIt-Anchor" href="#激进女权认为只有全女性世界才没有剥削"></a> 激进女权认为只有全女性世界才没有剥削</h4><p>这是稻草人谬误：「全女世界」不是王无的主张，也不是激进女权的主流主张⸺关于激进女权主义，之后会有更详细的说明⸺更不是我的主张。</p><p>批评父权制不意味着想要母权制，也同样不意味着批评男性。但是该认知难以让大众理解，最终大家都陷入男女对立的情绪，还有部落主义当中。</p><h4 id="激进女权的支持者是不工作-靠男性养活的女性"><a class="markdownIt-Anchor" href="#激进女权的支持者是不工作-靠男性养活的女性"></a> 激进女权的支持者是不工作、靠男性养活的女性</h4><p>这是无依据的人格攻击，同时包含着内部逻辑矛盾。</p><p>从社会学常识来看，女权主义的参与者群体实际上跨越了多种社会经济背景，并非某一类人群的专利。</p><p>逻辑矛盾则是，如果这些女性躺着享受男性给予的好处，那她们不就是父权制的受益者么？为什么受益者反而最积极批判该体制？</p><p>更深层的问题是，一个人的解读是否正确，和他的就业状况相关吗？不相关。</p><h4 id="经济独立的女性不会持有激进立场因为她们能体验到真实的幸福"><a class="markdownIt-Anchor" href="#经济独立的女性不会持有激进立场因为她们能体验到真实的幸福"></a> 经济独立的女性不会持有激进立场，因为她们能体验到真实的幸福</h4><p>该论断包含多重逻辑跳跃：</p><ul><li>经济独立与思想立场之间没有必然因果关系。大量有正式工作、经济独立的女性同样持有女权主义批判立场</li><li>「能看到幸福与美好」与「能进行结构性批判」之间不矛盾。一个人完全可以同时拥有幸福的个人生活和对社会结构的批判意识。批判不等于不幸福，接受同样不等于幸福</li><li>只有经济独立的女性才有资格批评⸺这一点与被批评的内容没有任何逻辑关联</li></ul><p>再是 Lerner 的父权制分析中提到过补偿性特权。它不仅给予了所有男性基于性别的地位优势，也可以让部分女性在顺应体制中获得安全感。</p><p>但这不意味着体制本身是公正的。</p><h4 id="所有传说都有多版本不能都归因于父权筛选"><a class="markdownIt-Anchor" href="#所有传说都有多版本不能都归因于父权筛选"></a> 所有传说都有多版本，不能都归因于父权筛选</h4><p>这是滑坡谬误。</p><p>从「牛郎织女的版本演变可能涉及父权意识形态因素」推不出「所有传说的版本演变都由父权意识形态决定」。</p><p>不同故事涉及不同的权力关系。比如核心是性别关系的故事，父权意识形态的影响可能较大；核心不是性别关系的故事，影响就较小。</p><p>总之，该问题的答案无论如何都不影响牛郎织女的传说是被父权意识形态筛选出来的结论。</p><h4 id="王无的解读方法缺乏区分度"><a class="markdownIt-Anchor" href="#王无的解读方法缺乏区分度"></a> 王无的解读方法缺乏区分度</h4><p>该质疑方向正确，但未被展开。</p><p>它触及到的正是先前我提到的「虚假意识」概念的自指悖论。</p><p>如果我们能用王无的方法去解读其他民间故事，就能知道是否也能得出同样的「暗黑」结论了。</p><h4 id="王无脱离实际也没有解决方案只是在占据道德制高点"><a class="markdownIt-Anchor" href="#王无脱离实际也没有解决方案只是在占据道德制高点"></a> 王无脱离实际，也没有解决方案，只是在占据道德制高点</h4><p>这包含三个需要分开评估的子批评：</p><ul><li>没有结合实际社会场景⸺部分有效。王无的文章是纯粹的文本、文化批评，没有锚定在具体社会场景中。但是文本批评本身也是合法的学术实践，也不是每篇文化批评都必须包含社会学经验研究</li><li>没有提出解决方案⸺标准过高。不能要求所有批判都同时是建设性的</li><li>占据道德制高点⸺动机揣测。这无法被证实也无法被证伪，而且即使王无确实从批判中获得道德优越感，也不构成对其论证有效性的反驳</li></ul><h4 id="以现代标准审判古代故事是不正当的"><a class="markdownIt-Anchor" href="#以现代标准审判古代故事是不正当的"></a> 以现代标准审判古代故事是不正当的</h4><p>该方法论批评叫作 <u>时代错置</u>（presentism，也可以叫 anachronism）。它是历史学和文学批评中真实且重要的方法论问题。</p><p>不过「必须了解时代与文化背景」这一原则，并不必然导致「因此不能以现代伦理审视古代叙事」这一结论。另一个学术实践叫作 <u>批判性重读</u>（critical reinterpretation），其目标在于用今天的视角来看过去的故事，看出它传递了什么、遮蔽了什么。这两件事并不矛盾：</p><ul><li>历史化的解读：在当时，这个故事意味着什么？</li><li>批判性重读：从今天看，这个故事的意识形态效果是什么？</li></ul><p>如果用前者的标准要求后者，本身是范畴错置，除非能论证「批判性重读本身不合法」，否则「需要了解背景」这个原则不能推翻王无的方法论的合法性。</p><p>王无没有单纯在批判古人，而是将重点放在为什么现代人浪漫化了偷衣的版本，即当代的叙事实践。</p><h4 id="攻击者本身也必然遭受反噬"><a class="markdownIt-Anchor" href="#攻击者本身也必然遭受反噬"></a> 攻击者本身也必然遭受反噬</h4><p>该观察有着合理的内核：父权制框架内的对抗性话语实践确实可能对参与者造成心理伤害。</p><p>我将其提出，是因为它同样能够应用在反女权话语上，而它会在我讲完中文互联网的「激进女权主义」后再被提到。</p><h4 id="相信爱情才能拥有爱情"><a class="markdownIt-Anchor" href="#相信爱情才能拥有爱情"></a> 相信爱情才能拥有爱情</h4><p>作为个人生活哲学，这是成立的，但不能用作反驳王无的论据。王无通篇讨论的是爱情作为文化叙事是如何被建构和利用，但博友回应的是个人层面的爱情信念。两者在两个不同的层面。我们完全可以一边承认「相信爱情的人更可能拥有个人幸福」，同时仍然主张「关于爱情的主流文化叙事承载着意识形态功能」。两个命题并不矛盾。</p><h4 id="我们之间的讨论已经发散难以聚焦"><a class="markdownIt-Anchor" href="#我们之间的讨论已经发散难以聚焦"></a> 我们之间的讨论已经发散，难以聚焦</h4><p>最初博友对王无的观点的评价是「不值一驳」，但在我们讨论的最后承认了问题的复杂性，我认为这是非常值得肯定的！</p><p>批评一篇文章的最佳方式是指出具体推理中的错误，说其「不值一驳」虽表达了立场，但没有提供任何可供检验的论证。拒绝指出「槽点」会让读者无法判断博友是否有依据。</p><p>在与我的讨论中，博友实际上也逐条反驳了王无的多个论点，足以证明王无的文章并非「不值一驳」。</p><h2 id="中文互联网的激进女权主义"><a class="markdownIt-Anchor" href="#中文互联网的激进女权主义"></a> 中文互联网的「激进女权主义」</h2><p>在与那位博友沟通的期间，我意识到我必须说清楚我提到的「激进女性主义」同中文互联网上更广泛出现⸺主要出现在男女对立相关的讨论中⸺的「激进女性主义」，或更通俗的「女拳」，是两类不同的概念。</p><p>因为我们之间的讨论就我来看并不顺畅：对方先入为主了「女拳」的形象，拒绝承认牛郎织女传说中父权制的体现与影响，并更多将精力放在「为什么女拳有问题」这一话题上⸺这不是我想要讨论的重心。</p><p>实际上我同周遭的人讨论问题时，都会出现「因对方先入为主某观念，导致讨论难以进行下去」，尤其是在和中国人讨论女性主义相关话题时。</p><p>我在先前给出了激进女权主义的学术定义，而那和整个中文互联网反女权话语中所说的「激进女权」几乎没有关系。</p><p>根据 Yaya 的 <a href="https://chinesefeminism.org/2023/07/19/yaya-online-feminism/">《中国网络女权二十年 —— 从边缘到焦点》</a> 的梳理，中文互联网语境中的「激进女权」（简称「激女」）是在 2016 年后才逐渐成形的网络亚文化群体，其特征与学术上的激进女性主义只有部分重叠。</p><p>中文互联网的「激女」：</p><ul><li>主张与男性决裂、不婚不育、反对向下自由（如选择结婚）</li><li>理论资源中存在着较少的系统性理论，更多是碎片化的网络话语</li><li>主要以微博、豆瓣等平台作为阵地，并通过话语动员，也会进行以「挂人」、「开除女籍」为主的网络斗争</li><li>明确排斥跨性别</li><li>对于普通女性，会将不符合标准的普通女性斥为「婚驴」、「娇妻」、「服美役」</li></ul><p>这是博友所反对的「激进女权主义」，而非 Firestone 或者 Millett 的理论体系。不过为了更准确明白对方所想象的「激进女权主义」，我得从他的文本中还原出具体的画像：</p><ul><li>将一切社会问题归因为性别压迫，故此什么事都能上升到男女对立</li><li>以平权之名行性别优越之实⸺「不是要平权，而是要特权」</li><li>会解构一切传统文化，包括将牛郎织女这样的爱情故事「歪曲」为强奸叙事</li><li>将已婚女性、选择家庭的女性斥为「婚驴」和「娇妻」</li><li>将男性整体作为敌人，并制造性别敌意</li><li>不工作、靠男性养活</li></ul><p>这是个被网络事件、流量经济，还有话语战争塑造出来的复合形象，不属于任何学术流派。</p><p>因为对方对「激进女权主义」的认知来源于在网络上的观察，且存在着「先入为主」的观念，那么他的归类逻辑就可以被解释清楚了：</p><ul><li>王无使用了极端指控词汇，所以符合「什么事都上升到男女对立」的形象</li><li>王无将传统爱情故事解构为暴力叙事，所以符合「解构一切传统」的形象</li><li>王无引用 Lacan、阿尔都塞等理论框架，所以符合「用学术话语包装攻击」的形象</li></ul><p>博友的归类是否是无中生有？我认为不至于，但确实过度泛化。</p><h2 id="为什么会出现先入为主的观念"><a class="markdownIt-Anchor" href="#为什么会出现先入为主的观念"></a> 为什么会出现先入为主的观念？</h2><p>果子狸是中文互联网「激女」话语成形过程中非常标志性的人物。据知乎上一篇对中国互联网女权运动的批判性分析 <a href="https://zhuanlan.zhihu.com/p/686669903">文章</a> 记载：</p><blockquote><p>这些人中，最典型的例子就是张岚（果子狸），在六年前她只是一名普通的家庭妇女，不幸的婚姻与不顺利的生活促使其走向网络，只有在网络、在集体运动中，她才能找到自我的归属，成为呼风唤雨的「女权」领袖。</p></blockquote><p>文章中说果子狸是个在现实中受挫、在网络上通过集体运动找到身份认同的人物。尽管该文章本身带有强烈的批判立场，但依然客观地记录了重要的社会学现象，即中文互联网「激女」话语的领袖人物往往不是学院派学者，而是从个人困境走向网络动员的普通人。</p><p>这进一步意味着，中文互联网「激女」从诞生之初就带有强烈的个人创伤叙事，还有情感动员的色彩，而非学术辩论传统。这与学术上的激进女性主义有本质区别⸺如 Firestone 是在理论框架中论证生物辩证法，而非从个人遭遇出发发起运动。</p><p>根据 Yaya 的梳理，中文互联网性别对立的形成有清晰的时间线：</p><ul><li>从 2011 年开始，女权向微博等社交媒体转移，并形成了二元对立格局</li><li>2015 年线下行动派女权被打压后，话语空间被更激进的线上派系填补</li><li>到 2016 年，互联网上便各处都是「激女」，这也导致反女权者的「先入为主」观念成形，因为他们所见到的「女权」只有「激女」</li><li>最后「女拳」成为了更广泛使用的贬称、「女权等于打拳等于制造对立」的等式被固化、男女对立持续极化再无中间地带、任何涉及性别分析的文章都会被预设为「激女」叙事。</li></ul><p>杨雨柯的 <a href="https://wenku.baidu.com/view/d9f599c685c24028915f804d2b160b4e777f813c">《激进的女权标签⸺女权主义如何在媒介平台被污名化》</a> 也提到，媒体通过突出女权主义者的激进情绪⸺如激动、抗议、反驳的描写⸺同时误读女权主义的思想内核，成功标签化且污名化了「女权」一词。</p><p>那么博友的「先入为主」是他个人的问题么？我不这么想。在中文互联网混迹的时间里我发现，这绝非个人偏见那么简单。</p><p>首先是先前提到的采样偏差，也就是因为互联网上都是「激女」，所以认为「女权」等同于「激女」。导致它的因素在于温和派和行动派已经在舆论空间中被边缘化、看不见了。</p><p>其次是流量经济有着放大效应：当代互联网「女权」运动的领袖⸺如营销号、微博大 V⸺往往不是最有理论深度的，而是最情绪化、最极端的，因为极端内容能够获得最多的流量。这也是流量算法的罪恶。</p><p>BBC 的 <a href="https://www.bbc.com/zhongwen/simp/chinese-news-55571627">报道</a> 中，女权活动人士吕频提出了这样的关键因素：</p><blockquote><p>我们的政府的确从来都没说支持男权，但实际上中国本身是一个父权的政治，这些指责女权的人拥有的制度性支持永远比女权主义者要多…… （政府）不仅是他们拉的一个保护伞，而是他们本身就是天然的同盟，…… 现在很多人说女权是境外势力。他们的这种话术为什么会有效，因为他们完全复制和延伸了政府的话术。</p></blockquote><p>反女权话语在中国互联网上拥有着结构性的优势，因为它获得了「维护社会稳定」、「反对境外势力」等官方话语的背书。</p><p>这使得「女权等于制造对立等于破坏稳定」的等式不仅仅是网络偏见，更是有制度性支持的话语框架。</p><p>抖个机灵：我人也在境外，会有人觉得我是拿了境外势力钱的激进女权主义者么？⸺好吧不开玩笑了。要是真有人这么想然后给我贴标签、引得完全不看文章的人复读标签并加深我身上的标签，我就笑不出来了。</p><p>最后是极化的话语环境中，任何尝试做细致区分的努力都会被两端同时拒绝。像是王无使用了激进女权的部分资源，但分析框架更接近意识形态批判而非激进女权政治，依然被博友认为是「激女」。</p><p>有时我们也能在互联网上看到「激女」认为温和派在和稀泥、「太爱男」⸺话语环境会惩罚每一个做区分的人！</p><h2 id="关于反噬的命题"><a class="markdownIt-Anchor" href="#关于反噬的命题"></a> 关于「反噬」的命题</h2><p>博友先前提到，激进女权的攻击行为会反过来伤害攻击者自身。</p><p>该命题包含三个要素：</p><ol><li>攻击：博友将激进女权的话语实践定性为「攻击」，而非「批判」、「分析」、「表达」</li><li>反噬：攻击行为会产生回到攻击者自身的负面后果</li><li>单方面指向：该命题仅针对激进女权，不涉及反女权一方</li></ol><p>bell hooks 的洞见⸺父权制表面上回报男性，实际上也囚禁和损害他们⸺可以系统地延伸到「反噬」命题。</p><h4 id="父权制如何囚禁和损害男性"><a class="markdownIt-Anchor" href="#父权制如何囚禁和损害男性"></a> 父权制如何囚禁和损害男性</h4><p>在 <em> Feminism is for Everybody</em> 和 <em> The Will to Change</em> 中，bell hooks 认为父权制要求男性：</p><ul><li>压抑除了愤怒外的情感，因此男性不被允许表达脆弱、悲伤、恐惧</li><li>遵守支配性角色规范，因此男性必须是强大、果断、有控制力的</li><li>将亲密关系视为征服而非联结，因此「真正的男人」不依赖他人</li><li>通过支配他人来确认自身价值，因此支配是男性自我认同的核心机制</li></ul><p>这些要求会对男性本身造成严重的心理伤害，如情感压抑会导致心理健康问题、支配角色会阻碍真正的亲密关系、将自我价值建立在支配之上会让男性内在地脆弱⸺因为一旦失去了支配地位就会崩溃⸺父权制回报男性以权力和地位，但代价是心理上的自我异化。</p><h4 id="用父权制的逻辑来攻击父权制是否合理"><a class="markdownIt-Anchor" href="#用父权制的逻辑来攻击父权制是否合理"></a> 用父权制的逻辑来攻击父权制是否合理？</h4><p>既然父权制对于受益者都造成伤害，那么在父权制框架内进行的对抗性话语实践，无论是激女的攻击还是反女权的反击，同样可能对参与者造成伤害。</p><p>这里的逻辑在于，在父权制的结构中，所有参与者都被父权制的逻辑所塑造。</p><p>所以当一个人在父权制框架内进行攻击时，无论他站在哪一方，他使用的武器本身就是父权制的产物。</p><p>我们可以看以下两个例子：</p><ul><li>激女对普通女性的攻击复制了父权制的污名化逻辑：父权制污名化不符合规范的女性，激女以同样方式污名化不符合自身规范的女性。参与者内化了攻击性话语模式，将敌意常态化，不仅会损害自己的情感生活，也会损害自己的人际关系</li><li>反女权对于女权主义的攻击复制了父权制贬抑女性表达权的逻辑：父权制否定女性发言的正当性，反女权以同样的方式否定女权主义者发言的正当性。参与者强化了敌意框架，将一切性别分析预设成「攻击」，丧失了区分和分析的能力</li></ul><p>因此，对抗父权制的人可能在不自觉中复制父权制的方法论。</p><h4 id="命题逻辑正确但使用方法有误"><a class="markdownIt-Anchor" href="#命题逻辑正确但使用方法有误"></a> 命题逻辑正确但使用方法有误</h4><p>「攻击者会遭受反噬」这个命题本身是成立的，不过博友错误地使用了它。</p><p>「反噬」命题不能仅被应用在激进女权一方，但忽略反女权话语同样适用。这是选择性归因，即普通型命题被选择性地应用于一方。</p><p>博友将激进女权的话语实践定性为「攻击」，预设了立场。从批判理论的视角来看，王无的文章是意识形态批判，属于分析性操作，不是「攻击」。将其定性为「攻击」已经在话语层面将其贬抑成非理性的暴力。</p><p>自然，中文互联网「激女」的某些话语实践⸺如「挂人」、骂别人「婚驴」⸺更接近「攻击」而非「批判」，但这里需要做清楚区分：不能将一切的女性主义话语都归类为「攻击」。</p><h4 id="反噬是父权制的自我保护机制"><a class="markdownIt-Anchor" href="#反噬是父权制的自我保护机制"></a> 「反噬」是父权制的自我保护机制</h4><p>如果我们再深一层，可以提出更系统的命题：「反噬」命题本身是父权制话语自我保护机制的一部分。</p><p>已知：父权制的核心运作机制是将自身自然化，因此任何对它的批判看起来像无理取闹，或者制造对立。</p><p>当有人批判父权制时，父权制的自我保护机制往往是转移焦点，即从「批判是否成立」转移到「批判者的态度、动机、后果」。</p><p>「攻击者会遭受反噬」是焦点转移的形式之一，因为它不会回应批判的内容，反而暗示你这样做对你自己不好，从而威慑潜在的批判者、将批判者的心理状态作为评判对象、暗示批判本身是不健康的行为。</p><p>但是父权制不需要有任何有意识的策划者，因此我们不能说有任何人有意去执行了父权制的自我保护⸺我这么说是因为这个分析本身可以被视作我在暗示博友有意服务于父权制，但我没有如此揣测。</p><h2 id="公开写作"><a class="markdownIt-Anchor" href="#公开写作"></a> 公开写作</h2><p>我和博友的讨论分散在博客的评论区下，这并非我喜欢的讨论方式。</p><p>一、评论区是反应性的，天然以回复为基本单位，且鼓励碎片化。</p><p>二、评论区受限于语境。</p><p>三、评论区的社交动态中，反驳成功比理解深入更容易获得反馈，因此它鼓励零和的交往模式。</p><p>四、评论会向他人发送通知，构成对方被点了名的社交信号。这也意味着，沉默成了一种表态：谁先不回复谁就输了。</p><p>但是公开文章完全不同：我的文章不会被推送给被讨论者，他们看到亦或者说没看到和我无关。即便看到了，不回复也是正常的，因为公开写作不会预设对话者的义务。</p><p>因而在公开写作中，人们会更不受限地去表达自己想表达的东西。</p><p>除此之外，为什么我还要将这些内容写成独立文章呢？因为我认为该话题非常有趣、值得记录，所以我要将其转向建立于文章的建构性论述，我要表明我的论点、如何得出、为什么。</p><p>公开写作的意义就在于，它能把我们的思考从私人意见转变成公共的论证。读者朋友们会看到我的结论、审查我的推理过程，从而判断我的结论是否成立。</p><p>亦或者没有人会看、审查、判断，因为没有人会被要求这样做。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;今年的七夕是公历的八月十九日。我后知后觉它已经过去了。我不喜欢节日，因其氛围总是在催促我去消费、告诉我应该做什么应该不做什么…… 我连自己的生日、新年都不会花时间庆祝了，我还管你个小小七夕？&lt;/p&gt;
&lt;p&gt;另一点在于我讨厌七夕背后牛郎与织女的传说。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
  </entry>
  
  <entry>
    <title>做导游的这几天：上</title>
    <link href="https://blog.cytrogen.icu/posts/6c9d.html"/>
    <id>https://blog.cytrogen.icu/posts/6c9d.html</id>
    <published>2026-08-20T04:00:00.000Z</published>
    <updated>2026-08-20T14:34:45.067Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>这周我被家里人安排来为来美旅游的亲戚做导游⸺又是这样！我已经不知道做了多少次导游了。</p><span id="more"></span><p>和不是朋友的人出门，我近乎记不住什么，因为我鲜少参与到话题当中。就算他们在聊天，也没有什么深度，我也没有印象。所以本文依然是以大量的图片为主。</p><p>我之前写了个 Hexo 脚本，可以将图片转换成更轻量的 webp 格式。后来我嫌麻烦撤掉了…… 哎呀虽然知道会用掉读者朋友们很多流量，不过现在就原谅我吧！拍的这些照片就是要清清楚楚展示给读者朋友们看呀！</p><hr><p>首先是接亲戚。他们从波士顿坐火车过来，在纽约市接他们自然要来 <u>宾夕法尼亚车站</u>（Penn Station） 了。它的对面是 <u>麦迪逊广场花园</u>（Madison Square Garden），是个很大的球场。</p><p><img src="/posts/6c9d/madison_square_garden.webp" alt="" loading="lazy"></p><p>其中「麦迪逊」指的是宪法之父 James Madison（詹姆斯・麦迪逊）。</p><p>关于「麦迪逊」和「花园」，其实有着一段有趣的历史：</p><ol><li>第一代麦迪逊广场花园在 1879 到 1890 年运营、位于麦迪逊广场（Madison Square）旁边</li><li>第二代在 1890 到 1925 年运营，位于同样的位置。耗资 300 万美元，设有 1200 座剧场、1500 座音乐厅，还有屋顶花园</li><li>第三代在 1925 到 1968 年间运营，位置却改到了 8 大道与 49 和 50 街之间</li><li>第四代，也是现在的，从 1968 年开始运营，建在原宾夕法尼亚车站旧址之上</li></ol><p>它的建造需要拆除原有的宾夕法尼亚车站，也是当时纽约市的建筑地标之一。这一损失引发了广泛批评，并催化了纽约历史保护运动。</p><p>今年六月份的 NBA，纽约尼克斯就在这里夺了冠！当时球迷们都无比疯狂，大晚上酒吧外还站着人梗着脖子看电视直播。</p><p>说回接人。这一块区域近乎无法停车。我建议往南走，开到 20 多街的住宅区小巷子里停车。</p><p>图片里那一片黄色都是出租车，剩下的则是 Uber 这样的租车，还有宰客的黑车！千万不要上黑车啊未来来纽约玩的朋友们！能用就用 Uber、Lyft 这样的平台，或者坐正经的出租车。</p><p>接到人后，我们开去时代广场看去了⸺久违来到时代广场，不得不惊叹「哇好多人，好脏，好乱，好多广告，好多宰客的吉祥物！」</p><p>未来来纽约玩的朋友们不要搭理那些穿着吉祥物服装的人，他们会拉着你拍照，然后索要金钱。过去是 5 美元，现在不知道多少钱了。</p><p>如何躲开纽约市宰游客的家伙儿呢？装成冷酷的纽约客：明明听到了但还是无视走开、一直戴着耳机挂着冷脸，或者干脆穿工装、装成上班族吧。</p><p>母亲买了 RiseNY 的票。它就在时代广场旁边，是个沉浸式博物馆兼飞行影院体验项目，也是纽约首个飞行影院类景点。</p><p>虽然买了 VIP，但当天根本没有多少顾客…… 所以买了相当于白买。</p><p>进去首先要看段短片，讲述纽约如何崛起为全球文化之都。我很喜欢荧幕左侧在最后开来地铁，结果左边的墙还真有道仿造地铁门的门⸺好像我们走进了荧幕中的车厢！</p><p>接着要穿过七个主题画廊，聚焦纽约历史与文化的不同方面。我没有拍下多少照片，只能根据 <a href="https://en.wikipedia.org/wiki/RiseNY">资料</a> 后续用文字补全：</p><ul><li>金融</li><li>天际线与摩天楼</li><li>电影</li><li>时尚</li><li>音乐</li><li>广播与电视</li><li>百老汇</li></ul><p><img src="/posts/6c9d/empire_state.webp" alt="" loading="lazy"></p><p>纽约州的别名是「帝国州」，也就是 <em> Empire State</em> 喔。而纽约州的「国王县」（Kings County）是布鲁克林。</p><p>在「时尚」区的织布机：</p><p><img src="/posts/6c9d/loom.webp" alt="" loading="lazy"></p><p>让我觉得很邪恶的 Supreme：</p><p><img src="/posts/6c9d/supreme.webp" alt="" loading="lazy"></p><p>甲克虫乐队，不过我不是很熟悉他们啦：</p><p><img src="/posts/6c9d/the_beatles.webp" alt="" loading="lazy"></p><p>布里尔大厦是美国音乐产业的中心地之一：</p><p><img src="/posts/6c9d/brill_building.webp" alt="" loading="lazy"></p><p>角落的假 DJ 机：</p><p><img src="/posts/6c9d/dj.webp" alt="" loading="lazy"></p><p>非常「美国黑人流行文化」的地方：</p><p><img src="/posts/6c9d/american_black_pop_culture.webp" alt="" loading="lazy"></p><p>说到美国黑人音乐，或许有读者朋友们会想到，且只能想到说唱。实际上黑人艺术家对美国音乐的发展影响很大，从早期的爵士乐、节奏蓝调，到灵魂乐、迪斯科，再到嘻哈音乐。</p><p>和音乐相关的历史景点地图：</p><p><img src="/posts/6c9d/music_map.webp" alt="" loading="lazy"></p><p>纽约市也有很多影院。我是 AMC 的常客，不过老剧院我就没去过了，像是百老汇的那些。</p><p>这个爆米花机我在高中时用过：</p><p><img src="/posts/6c9d/popcorn.webp" alt="" loading="lazy"></p><p>不知道是什么机器：</p><p><img src="/posts/6c9d/machine.webp" alt="" loading="lazy"></p><p>百老汇的著名历史景点：</p><p><img src="/posts/6c9d/broadway_map.webp" alt="" loading="lazy"></p><p>时代广场很有名的一事件就是新年倒计时：</p><p><img src="/posts/6c9d/ball_drop.webp" alt="" loading="lazy"></p><p>该庆祝活动始于 1904 年，由《纽约时报》出版人 Adolph S. Ochs 发起。</p><p>为什么是《纽约时报》的人呢？我们还要再往前看看时代广场本身的历史：它的原名是 <em> Longacre Square</em>，以伦敦剧院区 Long Acre 命名，当时已经是剧院和餐厅的聚集区。</p><p>1904 年《纽约时报》将总部迁至 Longacre Square 里新盖的时报大楼，也是当时纽约市第二高的摩天大楼。接着公司向市政府请愿将 Longacre Square 更名为 Times Square⸺《纽约时报》原名 <em> The New York Times</em>，所以时代广场名字里的 <em> Times</em> 是「时报」而非「时代」。</p><p>Ochs 倾尽全力打造了空前的跨年派对：全天街头嘉年华在晚间以时报大楼底部的烟花表演达到高潮。不过两年后纽约市禁止了烟花表演，Ochs 不甘示弱、安排在午夜时分从时报大楼旗杆顶部降下发光的「时间球」（time ball）来标志新年的到来。</p><p>我非常非常不建议亲自跑来时代广场跨年。我曾经去过一次，非常后悔：人特别特别特别多，我们甚至挤不到里面去，只能在很外围听听人们的尖叫声。</p><p>看完展览后我们会走进 Sky Studio，并且被告知我们穿越到了 1958 年的新年，要跟着他们一起去时代广场的最高点看 ball drop。</p><p>这个电视机感觉很有当时的味道：</p><p><img src="/posts/6c9d/tv.webp" alt="" loading="lazy"></p><p>我们要坐在一排座椅上，模拟在时报大楼的顶部。</p><p><img src="/posts/6c9d/sky_studio.webp" alt="" loading="lazy"></p><p>接下来座椅会腾空，挪向后方的大荧幕。之后的体验有点像 4D 电影：座椅会动来动去，配合荧幕上的影像，模拟出我们在天上飞来飞去的感觉。期间还有风啊，水啊，非常有意思！</p><p>我有录像，不过拍出来很模糊，时长也有三分钟多呢！以下是截取的一些片段：</p><p><img src="/posts/6c9d/fly_1.webp" alt="" loading="lazy"></p><p>这是曼哈顿大桥吧应该：</p><p><img src="/posts/6c9d/fly_2.webp" alt="" loading="lazy"></p><p>之后就是在上城的景点乱逛啦，什么 Vessel、大教堂…… 我都没咋拍，因为路过太多次了。再是车子实在没法停，亲戚们对这些景点也没有兴趣。我路上仅拍了一些照片。</p><p>这是 Trump 大厦附近的巨型 Louis Vuitton 包包建筑，看着蛮有创意：</p><p><img src="/posts/6c9d/louis_vuitton.webp" alt="" loading="lazy"></p><p>至于为什么没有拍 Trump 大厦，因为漏掉了，亲戚们也觉得 Trump 是个大傻逼，所以无所谓。</p><p>开车去下城路上，我发现的有意思的一幕：三只鸽子排排站！</p><p><img src="/posts/6c9d/pigeons.webp" alt="" loading="lazy"></p><p>抬头一看发现好多鸽子。我看这鸽子才是纽约代表啊：</p><p><img src="/posts/6c9d/more_pigeons.webp" alt="" loading="lazy"></p><p>我们是去看 9 <em>11 纪念处，还有世贸中心的。尽管读者朋友们应该都听说过 9</em> 11 事件，但还是让我重述一遍吧。</p><p>原本的世贸中心是位于下城金融区的一个七栋建筑的综合体，其核心是两座 110 层的摩天楼，即北塔和南塔，也是大家熟知的「双子塔」。</p><p>2001 年 9 月 11 日，伊斯兰极端组织 al-Qaeda 的 19 名恐怖分子劫持了四架美国商业客机，对美国发动了一系列协调自杀式袭击。世贸中心的北塔、南塔，还有 7 号楼都因此倒塌，共计 2977 人遇难。</p><p>新的世贸中心是在原址上重建的 16 英亩综合园区，规划最多六座摩天楼，截至 2026 年已有四座完工。</p><p>其中一号世贸中心有着纽约市最高的观景点。</p><p>周围长得像骨骼的矮白色建筑是世贸中心交通枢纽，有着 PATH 列车站（去隔壁新泽西的铁路）、购物中心，还有纽约地铁。</p><p>旁边的 9 / 11 纪念处除了非常有名的人造瀑布 <em> Reflecting Absense</em> 纪念广场，还有纪念博物馆、纪念林间空地……</p><p>曼哈顿下城有个很著名的景点叫作「华尔街铜牛」。它的历史背景很有趣：1987 年 10 月 19 日美国股市遭遇史上最大单日跌幅，道琼斯指数暴跌 22.6%，全球股市连锁崩盘。意大利裔美国雕塑家 Arturo Di Modica 被这场灾难深深触动，决定创作一件作品来激励美国人民在困境中保持坚韧与信心。</p><p>在金融市场里，「牛」和「熊」自 18 世纪初以来就被用作市场走势的象征：牛角向上顶，代表乐观、信心、繁荣，所以市场上行；熊掌向下拍，代表悲观、恐惧、衰退，所以市场下行。</p><p>这样说来，富途牛牛使用「牛」也是因为这个吧⸺ <em>Moomoo~</em></p><p>于是他耗时两年独自完成了这尊青铜雕塑。</p><p>不过他有个好笑的习惯，即未经许可、直接将自己的作品放在纽约的街头。这尊铜牛是他第三次随便乱放。</p><p>安装当天纽约证券交易所其实打算移除铜牛，但是公众强烈抗议。没办法，纽约市公园局出来把铜牛挪到了博灵格林公园（Bowling Green）的北侧。接着铜牛迅速成为热门旅游景点，被永久安置在那儿。</p><p>中国人过来旅游喜欢说「摸铜牛的蛋蛋能有福气」。</p><p>说了铜牛就不得不说 <u>无畏女孩</u>（Fearless Girl）。它在 2017 年国际妇女日的前一天被安装在铜牛正前方，形成「小女孩直面巨牛」的画面。</p><p>它由被 State Street Global Advisors 委托的雕塑家 Kristen Visbal 雕刻，目的是呼吁让金融街增加女性董事和性别多样性。</p><p>不过和铜牛不同，它引发了争议。</p><p>首先是 Di Modica 认为无畏女孩侵权了他的商标权、版权，还有精神权利⸺这个「精神权利」指的是创作者对其作品享有的、独立于经济权利之外的人身性权利，通常包含署名权和完整权。有些司法管辖区还会包括发表权和收回权。</p><p>Di Modica 认为无畏女孩被安装在自己作品的正前方，歪曲且篡改了铜牛的意义：从人民的力量与韧性，成了被小女孩对抗的负面力量。</p><p>他接着指出无畏女孩实质上是 State Street 的 SHE 指数（关注女性领导力的 ETF 基金）的营销活动，利用铜牛的形象做商业广告。</p><p>美国劳工部调查也发现 State Street 本身存在歧视，竟少付女性和黑人高管的薪酬。最终 State Street 以 500 万美元与劳工部达成和解，还在 2025 年悄然放弃了多元化的承诺⸺要小心 <a href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW91HEY44T14B2BAW9JVAV5H">彩虹资本主义</a>！</p><p>不过美国的 VARA 对公共雕塑的精神权利保护存在诸多限制和例外，Di Modica 的主张并未通过诉讼解决。</p><p>最终在公众舆论的压力，还有市政府的协调下，无畏女孩还是被挪到纽约证券交易所对面。</p><p>亲戚有同学在布鲁克林，所以我们跑到布鲁克林的日落公园区来。亲戚去见他的老同学，我们带着他的小孩子在日落公园里转转。</p><p><img src="/posts/6c9d/sunset_park.webp" alt="" loading="lazy"></p><p>因为是夏天，公园里好多人：跳广场舞的华人大妈、踢足球打篮球的人们、遛狗的人们。在特定的角度你还能看到水面上的自由女神像。</p><p>我有同学住在日落公园区，于是约他出来吃个饭。</p><p>他带我来日落公园附近的 <em> Mr. Pot</em>。我俩一起点了围炉奶茶：</p><p><img src="/posts/6c9d/milk_tea.webp" alt="" loading="lazy"></p><p>喝起来奶味儿很重。8 块钱左右。菜单上说可以免费续杯，不过奶加太多了我喝了肚子有点胀气…… 所以没有续杯。</p><p>朋友说看到这个会想到国内的主理人奶茶⸺不知道是什么！</p><p>小吃点的我喜欢吃的炸芋头丸。主食他点了生菜煲，闻着很香。</p><p><img src="/posts/6c9d/food.webp" alt="" loading="lazy"></p><p>这天我因为晚上要回家，所以草草结束了。不过万万没有想到，母亲居然还让我接下来的三天都陪这个亲戚逛逛！</p><p>第二日我们去了布鲁克林大桥。我们把车停在离大桥步行二十分钟距离的地方…… 一路上感受着太阳在我身上肆意妄为…… 太热了！</p><p>未来跑纽约玩的读者朋友们不要走错、走去曼哈顿大桥啊，认准布鲁克林大桥。曼哈顿大桥不好看，要走在车辆旁边、有些压抑。</p><p>我觉得无聊，就在玩手机的相机。</p><p>这是用 <em> Tilt Shift</em> 模式拍的照片：</p><p><img src="/posts/6c9d/tilt_shift.webp" alt="" loading="lazy"></p><p>模式还挺多的呢：</p><p><img src="/posts/6c9d/modes.webp" alt="" loading="lazy"></p><p>然后我们去斯塔滕岛上坐免费的橙色渡轮到曼哈顿最南边的码头，也是炮台公园的位置。</p><p>唉，说到纽约市根本没有人知道斯塔滕岛：纽约市有五个行政区，分别是曼哈顿、皇后区、布鲁克林、布朗克斯，还有斯塔滕岛。岛是里面人口最少、与曼哈顿距离最远，也是唯一不与纽约地铁系统相连的区，因而也被称作 <em> the Forgotten Borough</em>（被遗忘的行政区）。</p><p>不过它也是五个区里最独具特色的，因为风貌最郊区化，像是别的州，而不像纽约市。</p><p>橙色渡轮则是连接岛和曼哈顿的唯一非机动车交通方式，也是纽约市最具标志性的交通体验之一。最重要的是，它免费、24 小时每周 7 天都会运行、能看到自由女神像。</p><p>曼哈顿渡轮站的门口（白厅码头）经常有一帮黑人表演，以谋求生路。他们的口号如果我没有记错是：<em>show love, not anger.</em></p><p>紧邻白厅码头的是炮台公园（The Battery），公园名称源自 17 世纪末在此部署的炮兵阵地。</p><p>公园内能买到去自由女神像岛的船票，位置是这个像要塞一样的地方：</p><p><img src="/posts/6c9d/castle.webp" alt="" loading="lazy"></p><p>它叫作 <em> Castle Clinton</em>，原本是个炮台。</p><p>背对着水，便是高楼大厦：</p><p><img src="/posts/6c9d/buildings.webp" alt="" loading="lazy"></p><p>这些楼属于下城金融区的天际线。</p><p>坐渡轮回岛。岛上码头的景色真漂亮：</p><p><img src="/posts/6c9d/seaview.webp" alt="" loading="lazy"></p><p>虽然没有人知道它，但岛上的景色也很漂亮：</p><p><img src="/posts/6c9d/pond.webp" alt="" loading="lazy"></p><p>海边也是一望无际的…… 沙子还有海水。看久了感觉无趣，不过无趣也是蛮不错的。</p><p><img src="/posts/6c9d/beach.webp" alt="" loading="lazy"></p><p>天黑了。这云乌压压的：</p><p><img src="/posts/6c9d/clouds.webp" alt="" loading="lazy"></p><p>接下来还要跑到别的州…… 到时候再更新吧。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;这周我被家里人安排来为来美旅游的亲戚做导游⸺又是这样！我已经不知道做了多少次导游了。&lt;/p&gt;</summary>
    
    
    
    <category term="日常生活" scheme="https://blog.cytrogen.icu/categories/%E6%97%A5%E5%B8%B8%E7%94%9F%E6%B4%BB/"/>
    
    
  </entry>
  
  <entry>
    <title>休息日逛下城</title>
    <link href="https://blog.cytrogen.icu/posts/ed86.html"/>
    <id>https://blog.cytrogen.icu/posts/ed86.html</id>
    <published>2026-08-19T03:13:55.000Z</published>
    <updated>2026-08-19T03:16:36.682Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>记录的是八月十五日我和室友出门逛下城的事情。有很多图片喔。</p><span id="more"></span><p>因为近期一直在忙事情，忙得已经静不下心来，书没咋读、博客没咋看，更别说写博客了。你要说我的分享欲哪儿去了，我也不知道。</p><p>我鼻涕不再流了，就是时不时还会咳嗽。先前我便和室友约好周六一起出门。期待了一周多，就算还在咳嗽也得换衣服穿鞋子出家门。</p><p>纽约市每年都会举办个活动叫 <em> Summer Streets</em>。活动期间的每周六，特定的街道会被封锁、不让车辆驶入，人们可以在街道内骑自行车、玩耍。</p><p>室友原本在 Instagram⸺ <em>eww!</em> ⸺上看到八月八日曼哈顿的 Summer Streets 地点有滑绳索项目，所以打算那天跟我去。谁曾想我 <a href="/posts/b8c3.html">生病</a> 了，只能推到下周，也就是八月十五日星期六。</p><p>所以说就算还在咳嗽也得出家门啊！曼哈顿的 Summer Streets 就举行到八月十五日。</p><p>不过…… 我也没有很想去。这天早上我懒散地起床，看着还在呼呼大睡的室友、选择不去叫醒她。绳索项目下午三点结束，如果我没有记错的话，室友一点才醒来⸺她起床的时候还不停责怪我没有叫醒她。</p><p>午饭是室友做的：</p><p><img src="/posts/ed86/lunch.webp" alt="" loading="lazy"></p><p>非常好吃的牛排肉！</p><p>我们急匆匆跑到 Summer Streets 现场，结果发现排满了人。工作人员们跟我们说明年再来吧。室友说我是个很没劲儿的人，一点都不期待没有体验过的事情，所以也玩不到。</p><p><img src="/posts/ed86/summerstreets.webp" alt="" loading="lazy"></p><p>不过看队伍，怕是更早来也玩不上吧！后面甚至有队伍是明知玩不上也要顶着太眼光排队的。</p><p>因为一时半会儿没有别的事情做，我们打算去附近的共享办公室里坐坐、喝喝水、吹空调。</p><p>路上我在玩手机，发现 HelloUI 的相机有很多适合拍照的功能，比如大头贴、两个摄像头同时拍照然后伪装我在跟谁视频通话、对着前景摄像头露出手掌心以自动拍照…… 我觉得最好用的是将手机折叠一半能自动录像的功能，还有晃一晃手机打开相机的功能。</p><p>探索期间我还发现如果使用社交平台软件拍照，手机的相机还能美颜一番⸺不过我没有那些软件，所以无法测试。</p><p>我们要去的共享办公室在唐人街附近。Lafayette Street 那边有很多人摆摊在卖假货，走起路来也特别难受。如果有人要来纽约市玩的话，这个路段要小心扒手，也不要买看似崭新的 Apple 耳机！</p><p>炎炎夏日我们看到一家蜜雪冰城。Fedi 友还说我发的帖越来越像在中国发的，哈哈。</p><p>店里面很多人排队点单。我建议直接搜 <em> Menusifu Mixue</em> 然后带地点的关键词，就会出现这家蜜雪冰城的线上点单⸺不清楚为什么，我没有在这家店里找到线上点单的二维码。</p><p><img src="/posts/ed86/mixue_bags.webp" alt="" loading="lazy"></p><p>「雪王」的英文名就叫 <em> Snow King</em>，好好笑。</p><p><img src="/posts/ed86/mixue_cashier.webp" alt="" loading="lazy"></p><p>因为我不喜欢拍到别人的脸⸺后期处理很麻烦！⸺所以拍了张天花板，上面挂满了小旗子。</p><p><img src="/posts/ed86/mixue_ceiling.webp" alt="" loading="lazy"></p><p>我没有喝这类饮料的习惯，所以就室友买了；她点的是白桃乌龙。</p><p>共享办公室的名字叫作 WeWork。曼哈顿有很多家，每家的「生态」也各不相同。因此时不时来探索不同家 WeWork 很有意思。这家的厨房有个意义不明的小船：</p><p><img src="/posts/ed86/boat.webp" alt="" loading="lazy"></p><p>卫生间里还有冲澡的地方。之前听说有人「住」在了 WeWork：早上起床冲个澡，喝 WeWork 免费提供的水、茶和咖啡，然后在里面办公，晚上就缩在会议室里睡觉。</p><p><img src="/posts/ed86/shower.webp" alt="" loading="lazy"></p><p>隔壁是美国华人博物馆（Museum of Chinese in America），他们的 <a href="https://www.mocanyc.org/?lang=zh-hans">官网</a> 做得挺不错的。</p><p>小时候我很讨厌去博物馆、觉得无聊。尤其是美国自然历史博物馆（American Museum of Natural History），它是纽约市相当著名的一个景点，也是公立学校修学旅行的常客。所以我去过很多次了，拍照也拍了一大堆。</p><p>数年后的现在再去，反而觉得别有风味。仅是拍照实在是太委屈博物馆。</p><p>纽约市的许多博物馆都是只要你是市民，就能自定义入场票的价格。只付 1 美元也可以。我付了 5 美元，就当作支持了。</p><p>馆内现在正在展出 <a href="https://zh.wikipedia.org/wiki/%E6%9D%A8%E5%BF%97%E6%88%90">杨志成</a> 先生的作品。他 1951 年来美国留学，毕业后在纽约设计广告，之后创作儿童插画。</p><p>好可怕的基本功！</p><p><img src="/posts/ed86/ed_people.webp" alt="" loading="lazy"></p><p>杨志成原本在洛杉矶学习，后来借了 20 块钱只身跑来纽约赌人生。儿童图书出版人 <a href="https://en.wikipedia.org/wiki/Ursula_Nordstrom">Ursula Nordstrom</a> 雇佣了他为这本 <em> The Mean Mouse and Other Mean Stories</em> 画插画：</p><p><img src="/posts/ed86/ed_mouse.webp" alt="" loading="lazy"></p><p>我也拍了些很漂亮的作品。</p><p><em>Wabi Sabi</em>：</p><p><img src="/posts/ed86/ed_wabi_sabi.webp" alt="" loading="lazy"></p><p>令人惊叹的创意！将核武器造成的蘑菇云慢慢转变成千纸鹤：</p><p><img src="/posts/ed86/ed_nuclear.webp" alt="" loading="lazy"></p><p>除开杨志成的作品展览，博物馆最中间的 <em> With a Single Step: Stories in the Making of America</em>（翻译叫「千里之行，始于足步」）便展示了中国人来美国的历史：从最初的淘金热开始，中国人在美国的「地位」随着当局者的喜好不停在改变。</p><p>以下是我结合了 <a href="https://artsandculture.google.com/story/JgUhb1Weg9MiLQ">Google Arts &amp; Culture</a> 里的内容写的：</p><p>19 世纪中，大批华人劳工作为淘金客来加州挖金子，随后又投入太平洋铁路的修建。淘金热结束后，华人被白人工人视为竞争对手，惨遭暴力与舆论丑化。展览中就有许多妖魔化华人的漫画和宣传作品，例如</p><p>随后华人被排斥出大部分行业和熟练工种，只能做白人不愿意做的工作，例如洗衣服、做饭、帮佣。其中洗衣业因为门槛低、成本低、不需要英语，于是成为华人谋生的重要出路。</p><p>博物馆内有面墙放了当时华人洗衣工会用的工具，还讲了「八磅生计」的故事：这儿的「八磅」指的是洗衣工用的熨斗的重量。为了更直观知道这份工作的辛苦，墙下放了可以拿起来的旧熨斗，我试了试，确实很重，实在是难以想象长时间用它熨烫衣服该有多累人。</p><p>19 世纪美国民间还习惯把华人男性统统称作 <em> John</em> 还有 <em> Charlie</em>，算是带轻蔑的绰号化称呼。历史档案中就有大量华人洗衣工被登记为「Charlie 某」，很多甚至不是他们的本名，而是白人顾客或者雇主随意取的。</p><p>后来流行文化中白人作家创造出了华人侦探 Charlie Chan 这个角色。虽然是正面角色，但是由白人演员扮演，被许多亚裔视为是刻板印象⸺还有个是傅满洲；那种奸诈的小人形象也是白人对华人的刻板印象之一。</p><p>每个时代馆内都贴了诗句在一边，讲出了当时无数个在美华人们的心声。</p><p><img src="/posts/ed86/moca_chinatown.webp" alt="" loading="lazy"></p><blockquote><p>可他们来这里，<br>是为了猎奇，<br>是为了寻求刺激；<br>因而，他们满目所见，<br>全是怪异！</p></blockquote><blockquote><p>所以，我们一一建起了唐人街。<br>他们来这里<br>消遣猎奇；<br>我们在这里<br>遮风躲雨。</p></blockquote><p>淘金热那会儿来美的中国人不只有去矿场的，还有去做商人以及餐馆老板的。1849 年 11 月 19 日 <em> Canton Restaurant</em>（广东餐厅）在旧金山开业，成为北美有记载的第一家华人餐馆。</p><p>当时的华人社会是光棍社会，大多数都是单身男性矿工，买饭吃很普通也很实际，华人餐馆自然应运而生。</p><p><img src="/posts/ed86/chopsui.webp" alt="" loading="lazy"></p><p>华南商人在 1860 年代便多次宴请美国政界人士。餐厅菜单与清代扬州盐商的宴席类似，不乏有例如燕窝汤、鱼翅等菜品，但美国客人只对杂碎印象最深。</p><p>此杂碎非彼杂碎：在台山话里指的是内脏和杂碎，而非「垃圾」。我在美式中餐餐馆里也看到「杂碎」这道菜，但对其样貌不感兴趣，所以从来没有试过。不过看各个报道，杂碎本身到底是什么、怎么做，没有个准确说法。现在餐馆中的杂碎也顺应了美国人的舌头、去除了内脏。它究竟是什么，我不得而知。</p><p>1943 年，《排华法案》被废止。中国人们正式开始拥抱「美国梦」：</p><p><img src="/posts/ed86/american_dreaming.webp" alt="" loading="lazy"></p><blockquote><p>在远东地区为自由和民主而战…… 在世界最民主的土地上却无法获得平等机会，这是最大的讽刺。</p></blockquote><p>可这「美国梦」究竟是真实的梦想，还是大梦一场？</p><p>之后第一代华裔美国人出生了：</p><p><img src="/posts/ed86/beyond_vietnam.webp" alt="" loading="lazy"></p><p>不过他们长大后面临着全新的问题。</p><blockquote><p>包括有色人种在内的民权支持者，有时也不肯将民权与亚裔美人共同探讨。仿佛亚裔美国人相关的民权问题可以完全置之不理，无须慎重考虑事实，就因为所有人都认定亚裔美人个个功成名就。</p></blockquote><p>不说上个世纪 60 年代了，哪怕现在也是如此。</p><p>亚裔和男同性恋反叛者，在公众中鲜少看到：</p><p><img src="/posts/ed86/gay_insurgent.webp" alt="" loading="lazy"></p><p>应该会发出声音的唱片机，不过下方说正在维修中：</p><p><img src="/posts/ed86/music.webp" alt="" loading="lazy"></p><p>1980 年新移民们到来了，他们没有止步于唐人街，而是在其他地方建立起了一个个华人区：</p><p><img src="/posts/ed86/case_study.webp" alt="" loading="lazy"></p><p>其中布鲁克林的日落公园区我很熟悉，因为我住在那里过。它也叫「小福州」，有很多福建人。</p><p>图片内有板块提到了 <em> hapa</em>。馆内另一展区解释了这个词儿：</p><p><img src="/posts/ed86/hapa.webp" alt="" loading="lazy"></p><p>也就是「有白人血缘的人」的意思。应用在亚裔这儿，指的就是白人和亚裔生下的混血儿。</p><p>离开博物馆，我们就在 SoHo 区乱逛⸺曼哈顿下城的 SoHo 跟 NoHo 两区挺有名的：前者指的是 Houston Street 以南，是画廊、精品店和高档餐厅的聚集地；后者是 Houston Street 以北，是剧院和音乐场所的所在地。</p><p>一路上我们看到了许多漂亮的酒吧、夜总会、咖啡厅。</p><p><img src="/posts/ed86/owls.webp" alt="" loading="lazy"></p><p>这家酒吧印象里种满了绿植，非常漂亮。菜单上还有可爱的手绘猫头鹰们在干杯。不过价格也是真的贵，一打生蚝要 50 多美元。作为对比，Chelsea Market 的生蚝一只 3 美元。</p><p>我们路过一家茶叶店，墙上摆满了茶盒。曾经室友给我买过一盒茉莉绿茶包，似乎就来自于这家。</p><p>这红茶的 <em> supreme</em> 是 <em> supreme</em> 在哪儿了呢？</p><p><img src="/posts/ed86/earl_grey_supreme.webp" alt="" loading="lazy"></p><p>他们也卖杯子：</p><p><img src="/posts/ed86/fox_mug.webp" alt="" loading="lazy"></p><p>里面还有泡茶、做咖啡的地方，不过我没有拍下来⸺美国的咖啡店真的是像野狗一样多啊我没有说错。</p><p>门口还有纽约客包包。是的上面写的东西都是正宗纽约客会做的事情：</p><p><img src="/posts/ed86/eat_like_a_new_yorker.webp" alt="" loading="lazy"></p><p>翻译下吧。左边的包上写：</p><blockquote><p>像纽约客一样吃</p><ol><li>带有各种籽的全料贝果，抹上一层厚厚的奶油乳酪</li><li>把你的比萨顺着长边对折一半</li><li>裸麦面包夹熏牛肉，配酸黄瓜，再来杯奶油苏打水</li><li>热狗不加黄芥末？门儿都没有</li><li>点杯常规咖啡。指的是加奶和两块方糖</li><li>黑白。它是一块饼干，可不是警车（指的是一面巧克力一面香草糖霜的糕点）</li></ol></blockquote><p>右边的则写：</p><blockquote><p>纽约，纽约</p><p>如此美好，以至于名字都叫了两遍</p></blockquote><p>右边的包我得做个解析。首先是写地址时美国的写法是这样的：</p><blockquote><p>房号 街道名<br>城市名，州名 邮政编号</p></blockquote><p>例如：</p><blockquote><p>123 Example Street<br>New York, New York 10000</p></blockquote><p>有没有发现 <em> New York</em> 出现了两次呢？</p><p>因为「纽约市」这座城市叫「纽约」，所处于的「纽约州」也叫「纽约」。所以要叫两遍名字。笑点解析真好玩。嚯嚯嚯……</p><p>NoHo 和 SoHo 的东面是 East Village，也被叫作「小东京」。顾名思义，里面聚集了大量的日本留学生、侨民、日料餐厅和日式杂货店。</p><p>20 世纪末俩 Ho 转型成了高档街区，日资超市还有餐饮品牌就向西延伸，进驻了客流量极大的俩 Ho 边缘。</p><p>这里的消费群体都是年轻的专业人士、时尚从业者、游客，还有富裕居民，本就对高质量、精致、健康、异国风味的食品有着极高且稳定的需求。其中日本食品从小众商品摇身一变，代表起了精致、便捷，且深受中产阶级追捧的生活方式。</p><p>我们就在这儿找到一家日资超市。虽然店面小小的，但是商品塞得满，进来买东西的人还不少。我随便拍了张即食盒饭的照片：</p><p><img src="/posts/ed86/japanese_food.webp" alt="" loading="lazy"></p><p>隔壁又一家共享办公室。因为是休息日，没看到保安，直接刷卡进来的。这栋楼的走廊风格挺有意思：</p><p><img src="/posts/ed86/hallway.webp" alt="" loading="lazy"></p><p>电梯间放雨伞的工具更有趣：</p><p><img src="/posts/ed86/umbrella.webp" alt="" loading="lazy"></p><p>我们要去找餐厅吃饭了。因为我大病一场，终于是痊愈了，室友要请我吃饭。我们向她熟悉的二大道进发。这二大道贯穿了曼哈顿下城东侧的许多不同街区，包括 East Village、Lower East Side、Stuyvesant Square、Gramercy Park、Kips Bay 还有 Murray Hill。那儿经常能找到漂亮的餐厅，这也包括中餐厅，如湖南菜的 <em> Hunan Slurp</em>。</p><p>路上我们走进了一个社区花园。</p><p><img src="/posts/ed86/community_garden.webp" alt="" loading="lazy"></p><p>East Village 和 Alphabet City 一带有着非常密集的社区花园网络，它们背后也有着有趣的历史！</p><p>上个世纪 70 到 80 年代，East Village 曾经经历过一段经济衰退的时期。许多建筑被废弃，空地沦为垃圾场或者毒品交易的温床。</p><p>当地居民⸺其中有艺术家、激进主义者、移民⸺看不下去，自发拿起工具闯入了这些政府或私人的废弃空地，清理掉垃圾，还种上花草树木，将它们改造成社区花园。</p><p>政府后来试图拍卖这些土地以盖起高层公寓，居民们还成立了 Green Guerillas 等组织反抗，最终保下几十个社区花园。现在它们在纽约市公园局的管辖下，将会是永久的公共绿地！</p><p>根据纽约市公园局的规定，这些社区花园在温暖的季节必须向公众开放一定的小时数。所以我们看到大门开着，就大摇大摆走进去了。里面有一些长椅，藏在绿植的后面。你可以在里面歇息、看书、欣赏花草。因为是志愿者还有园丁精心维护的地方，所以进去不要破坏里面的环境！</p><p>有时候社区花园内还会举办免费活动，例如露天音乐会⸺去年还是两年前我和室友去过上城的一场露天音乐会，是日裔美国人举办的。</p><p>所以要是来纽约市逛逛，不乏来社区花园里面坐坐。</p><p>街边的「蛇」：</p><p><img src="/posts/ed86/snake.webp" alt="" loading="lazy"></p><p>我们走到了 <em> Hunan Slurp</em>，这是家位于 East Village 的湖南菜餐厅。我和室友数年前去过一次，味道非常惊艳⸺对比当地其他的中餐厅⸺但第二次以及之后再去，觉得厨师换了，味道越来越不咋地。</p><p>隔壁有家 <em> Twilight Lounge</em>，是做广东菜跟四川菜的。因为是新店，引得我好奇，所以我们就去尝鲜了。</p><p><img src="/posts/ed86/drink_menu.webp" alt="" loading="lazy"></p><p>这个「液体猫薄荷」是什么东西？我没有点。我只是好奇。</p><p>在点菜之前我们不知道它有 <a href="https://www.twilightloungenyc.com/menu?menu=menu">线上菜单</a>、能看到菜品样子。最后是瞎选，点了担担面、菠萝糖醋小排，还有俩米饭。</p><p>担担面在菜单上居然算「南北手工热点心」。上菜时是小小一碗，我还没有拍室友就开始分面，所以我只拍下这一口面：</p><p><img src="/posts/ed86/dan_dan_noodles.webp" alt="" loading="lazy"></p><p>这面比想象中好吃！正宗肯定是不正宗的了，酱汁不知道是使用了花生酱还是芝麻酱。肉末中则添加了梅菜，据室友所说是广东的材料。这是道很成功的融合菜。你要我形容味道吧，我形容不出来，总之你就想象吧。</p><p>主食的菠萝糖醋小排就…… 很不好吃。</p><p><img src="/posts/ed86/pineapple_sweet_sour_pork_ribs.webp" alt="" loading="lazy"></p><p>排骨很甜腻，菠萝也很甜腻。整道菜里能解腻的只有角落那三个上海青，但为了美观，上海青被切走一半……</p><p>至于为什么没有点别的菜。当时室友想要点土豆丝，但服务生说要等足足半个小时…… 好吧，这家店看起来就小小的，服务生我只看到有两个人，后厨该不会也不够人手吧？</p><p>不知道为什么小票上每道菜后面都打了一串问号：</p><p><img src="/posts/ed86/receipt.webp" alt="" loading="lazy"></p><p>室友说这就像是：</p><blockquote><p>您点了<br>担担面？？？<br>菠萝糖醋小排？？？？？？<br>两碗白米饭？？？</p></blockquote><p>好像在质疑我们点的东西、说我们点得不好一样！</p><p>不过室友确实在骂我点得不好：「早知道不让你点了！你觉得我俩喜欢吃糖醋排骨吗！」我错了我只是好奇……</p><p>回家路上我们路过了 Teso。我对这家店的印象是盲盒潮玩店，然后卖日本跟韩国的化妆品，总之是我很讨厌的那类店。不过室友拉我进去看，我才发现它会打折卖很多零食。我买这个良品铺子的香辣味海带零食：</p><p><img src="/posts/ed86/bestore.webp" alt="" loading="lazy"></p><p>我们也路过了一家 Five Below。它虽然标榜着商品价格都低于 5 美元，但是里面依然有很多超过 5 美元的东西⸺这算不算品牌欺诈？</p><p>室友第一次逛，说 Temu 要是有线下店估计就是这样吧。我没有拍照片，总之里面的东西杂七杂八、乱乱的，什么都有。</p><p>Five Below 楼上有家鞋子零售店。我数个月前就在纠结买皮鞋的事情：我因为有扁平足，脚型怪怪的，很多鞋子都不能穿。但工作场合我需要穿点「正经」的鞋子，比如皮鞋。</p><p>这家零售店内有个室友很熟悉的牌子，其皮鞋据室友所说非常耐穿，也很好看，不过因为是男鞋、没有我的号码。至于为什么不找女鞋…… 我受够了女鞋上莫名其妙的装饰物！</p><p>店内室友的校友发现了她。说来好笑，室友和这位校友甲有着同样的名字，还都是带个女生出来逛街；校友甲是出来跟女朋友约会的。</p><p>聊天间校友甲有问室友上次带的男生是不是她男朋友，被室友否认了。</p><p>两人聊了几句便分道扬镳哩，毕竟我跟校友甲不认识，他女朋友也不认识我们，室友跟校友甲关系也没有那么好。</p><p>「为啥中国人总是觉得跟我在一块的男人都是我男朋友？」她不满道，「外国人只会觉得我们是朋友。」</p><p>我想这是文化不同吧。</p><p>「但我俩出门就不会有人觉得我俩在约会。」</p><p>我想象了下新的社会，里面的人们不仅会默认俩异性出门是交往了，也会默认俩同性出门是在约会 —— 听着好累！问候语不要是「你最近咋样」，干脆改成「那个谁是你交往对象吗」好了。</p><p>走在曼哈顿的夜路，却只会觉得这天怎么还未暗下来。远处的高楼大厦全都使劲儿地浪费着电、传播光污染。</p><p>穿着衣服的小树：</p><p><img src="/posts/ed86/tree_with_clothes.webp" alt="" loading="lazy"></p><p>室友聊到了 <em> toxic ex</em> 即「有毒的前任」，我想到我也被某个家伙儿如此评价过，结果他才是最有毒、不健康的那个。</p><p>恋爱观，我周遭的人们都有着不健康且扭曲的恋爱观。一些对此有着自知之明并不再谈恋爱，一些尽管自知但还是沉溺于有毒的关系中无法自拔……</p><p>他们总说，「恋爱」和「友情」之间总有一个区分彼此的关键。可这个关键到底是什么？是浪漫、性、未来的婚姻，还是什么？</p><p>最后给读者朋友们看看我在 Target 买来的 5 美元小相机吧：</p><p><img src="/posts/ed86/camera.webp" alt="" loading="lazy"></p><p>我拍的是可爱的匹克猫。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;记录的是八月十五日我和室友出门逛下城的事情。有很多图片喔。&lt;/p&gt;</summary>
    
    
    
    <category term="日常生活" scheme="https://blog.cytrogen.icu/categories/%E6%97%A5%E5%B8%B8%E7%94%9F%E6%B4%BB/"/>
    
    
  </entry>
  
  <entry>
    <title>好转和博客和主流和教会和性别和大扫除</title>
    <link href="https://blog.cytrogen.icu/posts/955e.html"/>
    <id>https://blog.cytrogen.icu/posts/955e.html</id>
    <published>2026-08-11T04:00:00.000Z</published>
    <updated>2026-08-11T21:59:12.098Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>在我的记忆里我鲜少生过这么久的病。上次应该还是新冠病毒大流行的时候，我生了一周的病。根据我 GoToSocial 的数据，这次生病第一次开始记录应是七月十二日。今天都八月十一日了，我还没康复，依然在「好转中」的状态。</p><span id="more"></span><p>八月七日我写了篇 <a href="/posts/b8c3.html">文章</a> 讲我开始好转：从排出恶心的异物开始。接下来包括今天在内的时候，我都在循环「起床、擤鼻涕、咳痰、吃饭、擤鼻涕、咳痰、吃饭、擤鼻涕、咳痰、睡觉」的日子。因为有一天擤得太用力了，次日面部肌肉明显酸痛不少。</p><p>这期间我还把室友传染了。她的症状是咳嗽、喉咙疼。不过她发现得早、吃药也早，很快就控制住、能出门了。反观我，今早我擤出来的鼻涕依然是带有白细胞残骸的白色鼻涕，还咳出了一直卡在喉咙处的血痰。要说难受，没有前些天那么难受、生不如死了，但出门还是掂量掂量吧，我可不想随处抹鼻涕、吐痰。</p><p>许久没有这么大病一场，反倒是让我意识到了很多事情：</p><p>一是我的日常生活只有和电子设备做伴。生病不能常看电子设备，但我还是在看，好似没了它我就没有事情做了。我身边明明也有很多不需要电子设备的娱乐方式，比如数年前买了却一直没有碰过的小说、绘画本、字帖。</p><p>虽然很喜欢博客，不过看博客也得接触电子设备、互联网。唉我也想试试看断网生活，但我也没有那么强的偏好。</p><p>二是吃药一定要调查清楚成分啊！死室友吃药不看成分和说明书，差点给自己吃死。她之前买的流感药主要成分是 acetaminophen，也叫 <u>对乙酰氨基酚</u>。这玩意儿成人的每日最大剂量差不多是 4 克，保守起见最好不要超过 3 克，否则会引发急性肝衰竭。</p><p>她看也不看，吃了流感药又去摸同样含有 acetaminophen 的止痛药。24 小时内摄入了 2 克多的剂量，还问我能不能再吃。我看了眼她吃的止痛药是哪瓶⸺我还有含有其他成分的止痛药⸺顿感不妙。掐指一算：再吃你就嗝屁了！吃毛！吓得她不敢吃了。</p><p>我问她吃之前不看吗。她说她又不知道。我说两瓶药上可都清清楚楚写了「吃了后不要摄入其他含有 acetaminophen 的药物」啊。她不敢吭声。</p><p>我真不能理解用药不看说明书的人！</p><p>三是今年夏天真的热啊。我感觉过去几年都没有这么热。</p><p>网上看 BiliBili 的时候刷到一待在山东的开房车的频道主。如果没记错应该是威海那儿的。他说太热了，房车根本住不了，然后给观众看了眼温度：35 度！纽约市最近也上到过 35 度，但更多还是在 31-33 度之间摇摆。</p><p>太热了，租的这间公寓朝向差，平日没有什么风进来。为了让自己不那么热，就得开空调，但这个旧空调烂得要死，一开不仅没感觉有多凉快，反而身体更干燥、更难受。不得已，我只能常关空调多开窗，让空气更流通。</p><p>温度太热也意味着我做什么都不顺心。前些天难受得什么也不想做，想睡觉吧，但睡觉也热，起来一身汗。</p><p>于是我便「躺平」了几天，什么重要的事情都没做，每天就是吃饭睡觉然后擤鼻涕咳嗽。这种生活别说肉体难不难受了，精神上简直是摧残！</p><p>真要说有什么有意思的事情，倒是可以列举几个。</p><h2 id="wiwi-宇宙"><a class="markdownIt-Anchor" href="#wiwi-宇宙"></a> Wiwi 宇宙</h2><p>我数个月前在自己的 RSS 订阅内添加了很多英语使用者的站点。不过他们对比简体中文使用者的独立博客，明显要勤更新很多很多，日更的一抓一大把。</p><p>我想要再添加一些中文使用者的站点，来对冲一下，不过独立博客在内地实在是不够流行，难以找到更多符合我标准的博客。</p><p>忽然，我想到 <a href="https://blogblog.club/party/">BlogBlog 同乐会</a>。之前我 <a href="/posts/cf35.html">参加过</a> 它，但我实在不擅长围绕着主题写文章，所以没有继续参与⸺反倒是之后就着自己性子写，写出了很多「天啊那会儿写出来就可以投稿了」的文章。</p><p>我随便挑选了一期，然后开始翻看参与者们的博客，并订阅达到我标准的博客。参与者实在是太多了，一一看过去实在是遭不住。订阅了大致需要的量后，我便没有再翻阅。</p><p>参与者们多数是繁体中文使用者，而在他们的网站中我频繁捕捉到一个名字⸺Wiwi，也叫「官大为」，也是同乐会的发起人。他的独立博客在 <a href="https://wiwi.blog/">这里</a>。</p><p>很多人都是受 Wiwi 的启发，而开始写博客的。因为 Wiwi 的 IndieWeb 以及数字主权精神，我也看到许多人被他影响开始使用 RSS、POSSE 等技术，并抛弃 Meta 家的产品，着实感动。</p><p>因为该社区的中心就是他，所以就可以叫作「Wiwi 宇宙」。</p><h2 id="世界和语言"><a class="markdownIt-Anchor" href="#世界和语言"></a> 「世界」和「语言」</h2><p>这是套我很喜欢的概念，详情可以看 <a href="/posts/893f.html#%E4%B8%8B%E4%B8%80%E4%BB%A3%E4%BA%BA%E6%9C%89%E5%8F%AF%E8%83%BD%E6%98%AF%E4%BA%BA%E7%B1%BB%E6%BC%94%E5%8C%96%E7%9A%84%E5%8F%88%E4%B8%80%E6%AC%A1%E5%88%86%E5%8F%89%EF%BC%9A%E8%AE%BA-ai-%E5%AF%B9%E6%95%99%E8%82%B2%E5%92%8C%E4%BA%BA%E6%80%A7%E7%9A%84%E5%A8%81%E8%83%81:~:text=%E6%96%87%E7%AB%A0%E4%BD%9C%E8%80%85,%E6%84%8F%E4%B9%89">这里</a>。总之你可以将「世界」理解成已存在的客观现象，「语言」则是我们主观的解释。</p><p>在软科学中，「语言」会塑造我们的「世界」。例如「种族」这个词被发明，于是我们人类就真的要被划分成不同的「种族」，尽管在硬科学里人类不存在不同的种族。</p><p>语言的使用也是如此。我和室友都出生在仅说普通话的环境里，便会被塑造且认为普通话更高级、方言没有出路。</p><p>室友说她无法理解为什么大学里会有 ABC 校友觉得自己只会说方言是件值得自豪的事情，因为按照中国内地的发展，所有人统一说普通话只是时间问题。</p><p>我不会说除了普通话外的任何方言，现在连山东口音都找不见了。虽然现在美国的华人区还是以方言为准，不过我能看出，随着会普通话的年轻人越来越多，方言也会像中国内地那样，一代代变少，直到失传。</p><p>然后我们就开始思考什么是「主流」。对我们而言，说普通话的就是主流，因为我们只能接触到他们。但对华人区的老移民和他们的后代来说，主流是说方言的。主流实在是太主观了，以至于我们会错将特权和偏见当成常识：小时候一天出门买饭，旁边的大叔忽然开始批评我，说现在的小孩子既不会中文也不会福州话。但我会中文，也不是福州人。</p><p>大了后，内地来的留学研究生们默认我未来会回内地报答祖国。虽然说我出国这么久应该是考公不能了，血亲好像还有过进监狱的记录…… 不过我真的会回去定居么？我对内地的认知已经断层了。乡下的外婆家都盖起了高楼，我却只记得十多年前的三线城市。</p><p>母亲总会跟亲戚笑话我到现在还在幻想回国生活。他们已经找到了自己的社区、自己的主流、自己的常识，但我还什么都没有找到。我想这才是为什么我如此在意这种事情的原因。</p><h2 id="churchgoer"><a class="markdownIt-Anchor" href="#churchgoer"></a> Churchgoer</h2><p>八月二日休息日我久违去了次教会。这教会和我过去待的教会可不一样：一是多样性高，二是吃饭是免费的 potluck，三是大家很活跃很开放很友善。</p><p>我很难理解「神」的存在，但我喜欢开放且友善的社区，所以我对这个新教会很感兴趣。</p><p>室友有着相似的经历。她受人邀请去了创价学会的活动，也觉得那里挺开放、人很好，不过她的感想和我完全不同：她觉得自己去那边是对自己「无神论者」身份的背叛。</p><p>我得说明下，室友的想法一直都很极端。不过她不会外露，也不会用她的想法攻击别人，自己也很有自知之明。所以我们觉得无所谓，就让她想吧。想事情不是罪。</p><p>我虽然 <a href="/posts/51f0.html">不喜欢宗教</a>，不过一直认可人们信仰宗教的理由：有信念、活下去的意义。</p><p>室友则认为人类的信念应当来源于自己，而不是为了他人。如果信念不来源于自己，那么就是弱者，所以她不喜欢教会里的人。但她能理解为什么人们需要宗教，因为这个世界是以弱者居多的。</p><p>可是去不去教会跟信念什么的，实际上关联并不大。这句话听起来很奇怪但完全合理，因为美国的教会文化很浓厚，你不相信上帝依然可以每周跑去教会⸺这种人叫作 <em> churchgoer</em>，直译过来应该是……「去教会的人」？</p><h2 id="大扫除"><a class="markdownIt-Anchor" href="#大扫除"></a> 大扫除</h2><p>我们一直都觉得家里有太多太多没有用的东西了，比如很多很多衣服⸺主要都是我的。其实也不是我的，是母亲给我的⸺于是我们打算生病期间把不需要的东西全部丢掉。</p><p>这一收拾我们就收拾出来了三大蛇皮袋旧衣服，包括但不限于数年前 Uniqlo 联名但我觉得设计很丑的 T 恤衫、质量很差的衬衫、破了洞的裤袜…… 我们本来想要捐掉，但没有在家附近找到捐献点，于是丢到楼下、贴了张 <em> FREE CLOTHES</em> 的纸，顺便在 Facebook Marketplace 上找了个回收旧衣服的人让他过来碰碰运气、把衣服都拉走。</p><p>大扫除时人们总会找到纪念过去的物件，其中很多都是室友以前的画作。不得不感叹，这家伙儿绘画的巅峰在初中啊，现在和我一样也是懒得画画了。</p><p>我们还找到一袋猫薄荷。室友以前的猫会吃掉它们，所以必须要藏起来。但现在的匹克猫对猫薄荷没啥兴致，连会摇摆尾巴的鱼玩具都感到害怕，不得不感叹每只猫的喜好能这么不同。如果是咪咪猫的话，它肯定是什么都不玩，只想要露肚皮睡大觉！</p><h2 id="性别的本质"><a class="markdownIt-Anchor" href="#性别的本质"></a> 性别的本质</h2><p>一天晚上我和室友聊到部落主义，即人们不靠理性讨论来划分阵营。期间我举了个性少数群体、性别刻板印象等例子，她就说「性少数是残障」，理由是双性人在生理上是残障的。</p><p>性少数这个概念很大，不单单有双性人。不过双性人真的是残障么？性别到底是怎么定义的？我很好奇，于是就搜索了一番。</p><p>首先生物学上的性别不能单纯靠生殖器来区分，实际由多个层决定：染色体、性腺、性激素、外生殖器、内生殖器、次级性特征…… 如果非要每个层都取两个极端来严格定义男女双性的话，那么世界上大多数人都不是严格意义上的男或女。因为每个层都有可能出现变异⸺变异在自然界是常态，并非残障。</p><p>其中决定人类性别发育的关键是 Y 染色体的 SRY 基因。它会激活一系列下游基因⸺也就是刚才说的「层」⸺以让性腺发育成睾丸。不过 X 染色体上的 DAX1 基因有抗睾丸效应。假设 X 染色体上多了 DAX1 拷贝，那么它就会覆盖 SRY 的作用，导致 XY 个体发育不出睾丸。</p><p>除此之外也有其他类似的基因会改变「层」的结果，甚至说 SRY 本身也可以被移位和被推翻，因此「有没有 Y 染色体」、「有没有 SRY」、「性别表型是什么」这三者之间的关系并不是一一对应的。</p><p>那么什么真正决定了性别？既然 SRY 作为决定性别发育的关键都如此不稳定，那么什么才是性别的本质？某些爬行动物的性别会由温度来决定，所以「因」是环境温度，「果」是性别。但它们真正的性别由什么决定？是基因、温度，还是两者互动的结果？同样，SRY 是关键的因果节点，但整个性别发育是一大堆东西的联合产物，那么哪个单一因素才是性别的本质？</p><p>生物学认为，性别最底层的定义是配子的大小异型性，即只要一个物种存在有性生殖，那么产生较小、可运动配子⸺精子⸺的个体就是雄性；产生较大、营养丰富且不可动配子⸺卵子⸺的个体就是雌性。</p><p>说回双性人。双性人或 intersex 指的是出生时具有的性特征变异的人，这些特征不符合男性或女性身体的典型二元概念，因此对室友来说是「残障」的。</p><p>在残障研究中，分为医学模型和社会模型：前者认为残障者本人是问题本身，因为他们内部有缺陷或障碍，所以要治愈和修复他们；后者认为排斥性的社会是问题本身，因为残障来源于排斥。如果社会没有台阶、只有坡道的话，那么坐轮椅就不会构成障碍。</p><p>但「变异」是否就等同于「残障」？我收集了一些属于变异但不是残障的例子：左撇子、红头发、不同血型、不同颜色的皮肤、乳糖耐受性、间性人或者双性人⸺因为间性本身不必然造成功能受损。将间性称为「残障」意味着：一、将「不同」视为「缺陷」，即医学模型的过度延伸；二、混淆了「间性变异可能伴随健康问题」与「间性本身是残障」两个概念。</p><h2 id="收集-收藏-消费主义"><a class="markdownIt-Anchor" href="#收集-收藏-消费主义"></a> 收集、收藏、消费主义</h2><p>晚上室友问我在生活中实施极简主义如何呢，极繁主义算不算在鼓励消费主义。我以为她说网站设计呢，结果她其实问的是「人为什么要收藏或者说收集物品」。</p><p>虽然以我现在钢笔的数量和品质来说，讲我会收藏钢笔实在是有点自大，不过我确实有收集钢笔的小癖好，类似于电子设备友会收集奇特型号的手机、笔记本电脑一样。但我的行为和我确实会讨厌的「收集 Labubu」有什么区别么？我也说不上来。</p><p>说到底人为什么会收集东西？我感觉收集本身不能强行和消费主义扯上关联，因为之前看到有人收集石头、塑料板凳、沙滩上的贝壳海螺…… 收集本身不一定要购买什么。再者也有二手市场，能够以物易物。</p><h2 id="最后"><a class="markdownIt-Anchor" href="#最后"></a> 最后</h2><p>我将最近写到 Fediverse 上但感觉还不够单独写成独立文章的东西放在了这里，毕竟也不是所有人都会去看我月刊的日记片段。很长啊很长，也很琐碎。</p><p>时不时将一些内容集中成一个 bucket post，我觉得也挺有意思的。</p><p>总之我要出门去买可丽饼吃了，下篇见！</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;在我的记忆里我鲜少生过这么久的病。上次应该还是新冠病毒大流行的时候，我生了一周的病。根据我 GoToSocial 的数据，这次生病第一次开始记录应是七月十二日。今天都八月十一日了，我还没康复，依然在「好转中」的状态。&lt;/p&gt;</summary>
    
    
    
    <category term="日常生活" scheme="https://blog.cytrogen.icu/categories/%E6%97%A5%E5%B8%B8%E7%94%9F%E6%B4%BB/"/>
    
    
  </entry>
  
  <entry>
    <title>病殃殃的一周</title>
    <link href="https://blog.cytrogen.icu/posts/b8c3.html"/>
    <id>https://blog.cytrogen.icu/posts/b8c3.html</id>
    <published>2026-08-07T18:30:40.000Z</published>
    <updated>2026-08-07T18:31:58.534Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我这周生病了。生病的征兆实则半个月前就有出现：打喷嚏、喉咙有黏稠感。不过当时仅觉得是上火了，所以措施也只有多喝水。</p><span id="more"></span><p>两天后我的身体有了干燥的感觉，上颚也很痛，像是被烫伤或者磨伤了一样，许多需要嚼的食物都会因为碰到上颚而吃不了。</p><p>期间时不时还有肚子不舒服、胃胀的现象，别提多难受了。感觉非常像我几年前得了新冠的那会儿。到这时候我才慢悠悠意识到自己生病了。</p><p>我的一大坏习惯在于，我生病了不会去看医生。我从小到大去见医生的次数都很少，多数还是母亲拉着我去的。我对「看医生」没有个概念，即「什么时候该看？」万一只是个小毛病、休息休息就好了，那看医生不就浪费了几个小时？</p><p>实话说依然是懒惰害的。我经常说我的家庭医生离我很远，但空闲时也没有去调查公寓附近哪儿有医生、把档案迁移到他们那儿去。</p><p>总之我又过了啥措施都没采取的两周。</p><p>到了八月初，病情果不其然恶化。</p><p>这时候我在找工作，给猎头公司投了好几封简历，顺便给 LinkedIn 上的人狂发 cold email—— 无他，mentor 们都跟我说这是「人情世故」的社会，我也只能屈服了。主要是这种 network 已经发展成类似于「技能」、「自动流」啥的东西，一下子就不会觉得害羞了呢。</p><p>我的重心都放在了找工作上，个人的经济条件也不容许我再放空大脑，对于生病什么的，也只是觉得它很快会走掉。最多在身边放了个产生蒸气的机器，可以让房间潮湿些。</p><p>有天早上，身体的干燥感把我弄醒了，鼻子和喉咙都无比难受。我隐约感觉空调是因素之一，所以跟室友讲了嘴别老开空调，实在不行换下睡觉的位置，空调直接对着我的床吹呢。</p><p>室友觉得我瞎扯淡，空调跟我的症状有什么关系。再加上她是打地铺的，地上更凉快，要她睡我的床她会热昏，所以拒绝了我。</p><p>我上网搜了下，搜到了 <u>空调病</u>。长期待在空调房内，一是会让房间湿度过低，导致黏膜出问题；二是空气的流动性太差，对人体不健康的微生物会跑出来。</p><p>不过我觉得「空调」仅是让我病情恶化的潜在因素之一，不是引发我这些病的主因。因为室友不在的时候我就会关掉空调。</p><p>我得另说一下：室友开空调开太狠了，之前都是往 18 度去开，冷得我直哆嗦。我一直都知道开空调不能开那么低，就算是为了保护环境空调也得往 26 度那个方向去开。所以我跟她说很热的话开 24 度。她本来百般不乐意，结果真开到 24 度她也能接受，那之前非要开 18 度到底是在干嘛。</p><p>借此我又搜了搜空调和风扇的使用方式。风扇的降温原理是加速汗液的蒸发，然后带走体表热量。环境温度过高时，风扇就开始吹热风、反而增加中暑风险。所以太热的话必须得开空调。该标准是 35 度左右。</p><p>纽约市最近都是 32 度左右来回晃荡，仅开风扇属于不会热死人，但感觉上和死没啥区别了。该开空调还是得开，最好是开数个小时再关上，然后开窗通个气儿。</p><p>空调和风扇都会加速鼻腔和咽喉黏膜的水分蒸发。要使用它俩必须得避免直接吹我们的面部和上半身。</p><p>要用风扇的话，建议开摇头模式。风向朝着墙或者天花板，可以让气流间接循环 —— 不过我没有深入研究具体咋弄 —— 风扇得放两米开外、开中低档。吹风扇期间多喝温水，以弥补风扇蒸发带走的体液。</p><p>这时候再开空调，可以把空调的温度调高一点，例如 28 度，能更好地保护环境 —— 也能让我少点负罪感。</p><p>网上冲浪时我也得知人体会在室内湿度低于 40% 的时候才会让鼻咽部黏膜因缺水而变脆弱 —— 可是家里的湿度平时都是 50-60%？这意味着病因不是简单的环境过干。</p><p>再是室友有只猫，我们管它叫「匹克猫」。这个猫特别黏人，像狗一样，为了黏人还会跳到我们身上来、让我们抱它。不过它的指甲一旦变尖，跳到我们身上可就不可爱了。之前还不确信自己生病时，它跳到我肩膀上来，不小心挠伤了我的锁骨处，正好是我低头看不到的地方。</p><p>之后我摸那块儿，总能摸出那道爪印，以及…… 痛痒感。但我以为很快就会消退，也没有管。</p><p>结果室友过来看了眼，惊呼「你怎么起疹子了！」我才知道我那块痒不是因为猫爪印，而是起了一堆红疹子。</p><p>原先我们怀疑是热疹。但热疹一旦没那么热了，就不会再出现了啊？我这堆疹子就算抹了药膏，过了几天依然存在。</p><p>既然我已经生病了，那么我也不该外出做事情，所以天天就在家里干坐着。这也是为啥从八月三每天更新更到八月六，以及今天八月七，因为我闲呐！我没事儿做啊。</p><p>除了看写博客，我还修了博客的邮件评论。它其实几个月前就因为 Stalwart 的更新而坏掉了，但我一直有着侥幸心理、没修…… 目前不知道有多少邮件评论我没有收到，总之非常抱歉…… 现在已经修复了。关于这个功能我还在探索中，所以不怎么推荐使用。</p><p>剩余的时间我便是上网搜到底啥回事儿。我学到喉咙出问题是因为鼻腔有问题：鼻腔里的分泌物会向后流到咽喉，刺激咽喉的黏膜。所以要治得先从鼻子开始治起。</p><p>室友给我调了个生理盐水 ——0.9 克无碘盐搭配 100 毫升温白开。如果盐太多，喷到鼻子里会有明显的刺痛感 —— 我装到喷壶里，时不时对着鼻子来一发。</p><p>洗鼻子的时候也得用生理盐水，不建议用自来水。生理盐水洗起来很温和、不会刺激。</p><p>也可以配个温盐水漱口用，用来消炎和缓解咽喉痛，但是别喝进去！</p><p>昨天我又多了新的症状：低头时脸部肌肉疼，像是脸要掉下来了一样。继续上网搜索，得知是鼻窦炎的症状。</p><p>鼻窦是啥玩意儿？这我还真不知道。它其实是面部骨骼中含有空气的体腔，跟鼻腔是互通的。感染会导致鼻窦黏膜发炎、肿胀，从而堵塞引流通道。这时候黏液还有分泌物就会卡在鼻窦内出不来。</p><p>我低头的时候，重力会让积聚的脓液和血液更多涌向鼻窦，压迫神经、增加鼻窦壁上的压力，从而引发剧烈的胀痛感，也就是「脸要掉下来了！」</p><p>晚上室友回家，给我带了流感药、蜂蜜还有鼻腔喷雾剂 —— 太感激了！</p><p>她说她去药店时，店员跟她讲要小心流感，最近是流感的季节。她想了想感觉我的情况是有点像流感。买蜂蜜则是因为蜂蜜温水能够减轻咳嗽。</p><p>这个鼻腔喷雾剂我得说一说。她买来的是 phenylephrine hydrochloride nasal decongestant，中文翻译是「盐酸去氧肾上腺素鼻用减充血喷雾」，是一种减充血剂。它的作用是收缩鼻腔血管，减少血流和肿胀，从而快速缓解鼻塞跟鼻窦压力。</p><p>使用说明写的是「每 4 个小时最多喷 2-3 下」，还有「连续使用不得超过 3 天」。后者是因为 phenylephrine 会让血管长期依赖药物收缩，停药时反而会过度反弹扩张。到时候鼻塞会更难治、更难治疗。</p><p>顺带一提我身边老有人吃药不看说明书。完全无法理解。你不小心搞出问题咋办。</p><p>今天早上我被自己的鼻涕泡给弄醒了。去洗手台一看，我滴乖乖黄色大鼻涕！擤出来后鼻腔明显感觉好了很多。我又上网搜了下，得知这是白细胞消灭病原体后的残骸。残骸们混入鼻涕，鼻涕便从透明色变成了黄色。</p><p>能把它们排出体外，意味着我离好转不远了！</p><p>看来整个事情在于病毒性感染，不论是我的鼻咽喉，还是疹子。我和室友都没有定期打流感针的习惯，甚至说平日只会打必要的针，对这些东西也不在乎。只有在真发生在自己身上了，才会下功夫学习。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我这周生病了。生病的征兆实则半个月前就有出现：打喷嚏、喉咙有黏稠感。不过当时仅觉得是上火了，所以措施也只有多喝水。&lt;/p&gt;</summary>
    
    
    
    <category term="日常生活" scheme="https://blog.cytrogen.icu/categories/%E6%97%A5%E5%B8%B8%E7%94%9F%E6%B4%BB/"/>
    
    
  </entry>
  
  <entry>
    <title>Meta 和它不聪明的领导者</title>
    <link href="https://blog.cytrogen.icu/posts/83ff.html"/>
    <id>https://blog.cytrogen.icu/posts/83ff.html</id>
    <published>2026-08-06T19:30:59.000Z</published>
    <updated>2026-08-06T19:31:48.297Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我建议你离开 Meta 的生态。</p><span id="more"></span><hr><p>今早我和平日一样在看 Pluralistic—— 这是 Cory Doctorow 的每日链接，或者说「日报」。他会在文章里围绕着一个主题写东西、引用他过去写的文章，然后再贴些其他链接。</p><p>不过因为每天都要写一个主题，难免会出现重复的主题。我挺佩服他能在这么多年内换个花样写同个主题的事情。我反正是做不到。</p><p>因为他的许多观点对我来说是非常有启发的，再加上近些日对他的观点很感兴趣 —— 比方说月刊里你经常会看到他，现在甚至在我的独立文章中也常常看到他 —— 我觉得不分享出来实在可惜。</p><p>今天八月六日，他的文章是这篇：<a href="https://pluralistic.net/2026/08/06/sin-is-when/">https://pluralistic.net/2026/08/06/sin-is-when/</a>，标题是 <em> Eternal Sloptember</em>。</p><p>Doctorow 玩了个双关梗，将 <em> slop</em> 和 <em> September</em> 合在了一起、拼成 <em> Sloptember</em>。</p><p>以下的所有内容都可以通过上面这个链接找到出处。</p><h2 id="facebook-的出生是可耻的"><a class="markdownIt-Anchor" href="#facebook-的出生是可耻的"></a> Facebook 的出生是可耻的</h2><p>这篇文章告诉了我们很多关于 Mark Zuckerberg 的糟心事儿，也就是创立 Facebook 的那位。这让我对 Zuckerberg 有了更多的了解，我以前只是觉得他是又一位名校创业者。</p><p>Facebook 的起源相当令人感到羞耻：抓取哈佛大学的学生照片，然后让学生对照片中的人打分。打分的标准在于「性不性感」。</p><p>但是 Zuckerberg 不愿意承认这一点，不停尝试改写历史，声称 Facebook 的创立是为了让人们更好去发声 —— 我信你个鬼！</p><p>尽管打分网站当时叫作 Facemash 而非 Facebook，但 Facebook 起初创建时就有考虑添加约会功能。</p><p>甚至说，Facebook 这个概念都不是他想出来的，而是偷窃来的。</p><p>2003 年哈佛大学的三个学生想要做个面向哈佛学生和校友的社交网络，叫 Harvard Connection。他们将想法告诉了可以建立网站的 Zuckerberg。</p><p>然后，Zuckerberg 以各种理由开始频繁推迟 Harvard Connection 的开发，最后反倒是搞出了 Facebook。</p><p>在这期间，他对给 Facebook 投资的 Eduardo Saverin 发消息说，在 Facebook 之前已经有竞品 Harvard Connection，但是可笑的是那帮人让 Zuckerberg 负责开发。现在它永远不会上线了，因为 Facebook 会先出现。</p><p>最后，提出 Harvard Connection 的学生们被 Zuckerberg 玩弄、窃取了创意。他们 2004 年起诉了 Zuckerberg，于 2008 年达成和解。</p><p>除此之外，2004 年 Zuckerberg 也被指控骇入 Facebook 用户的私人电子邮箱并阅读其邮件。在他与朋友的聊天记录中，甚至说出了「如果你需要哈佛任何人的信息，尽管问我」、「人们自己提交了他们的信息，因为他们『信任我』，真是群傻逼」的言论。</p><p>靠此，他还骇入了之后完成的 Harvard Connection，现在则叫 ConnectU。</p><p>虽说当时他仅有 19 岁，还能用「年轻没脑子」来为他脱罪。但从 2011 年开始，他买下了一社区的大量住宅、破坏了当地人的生活，还做了层层防御避免当地人窥视他的隐私，尽管当地人正是被他窥视隐私的 Facebook 用户。</p><p>此处容许我科普一下 Zuckerberg 是如何获得夏威夷的土地的。</p><p>1850 年夏威夷王国通过了《Kuleana 法案》，允许原住民持有和耕种小块私有土地，也叫 <em> Kuleana Lands</em>。按照当地传统与法律，这些土地在没有书面遗嘱的情况下，会由一代代后代共同继承。</p><p>经历过百来年的传承后，一块小得不能再小的土地，其产权也有可能会被稀释、分割给几百位分布在各地的原住民后代。有些人甚至不知道自己有继承权。</p><p>这种没有正式地契、由泛家族成员共同持有份额的形态叫作 <u>继承人财产</u>（Heirs' Property）。</p><p>Zuckerberg 联合了拥有土地微小份额的合法继承人，以对方的名义向法院提起诉讼。法院会认定该土地由数百人共同拥有且无法物理切分，然后判决将土地公开拍卖。</p><p>这时候 Zuckerberg 再高价买下，成功赶走原住民家族，获得夏威夷的土地。</p><h2 id="没有他人的世界"><a class="markdownIt-Anchor" href="#没有他人的世界"></a> 没有他人的世界</h2><p>种种行为都表明此人的道德多么有瑕疵。</p><p>在产品故事更重要的今天，Zuckerberg 很清楚他过去干的垃圾事儿会让自己的企业蒙羞，因此他想方设法改变历史、将自己创立 Facebook 的理由说得多么崇尚。</p><p>Doctorow 认为 Zuckerberg、Elon Musk，甚至 Trump，他们的脑子里都没有别人。例如 Musk 会气急败坏骂刁难自己的人为 <em> NPC</em>，即「非玩家角色」。</p><p>这些人能随意去伤害和剥削他人，来让自己获利。Doctorow 对此的解释是因为他们的世界里只有自己是活着的、其他人都是 NPC。</p><p>是不是听上去很像反社会人格的想法？</p><p>Musk 也在采访中提到，他觉得西方文明的根本弱点在于同理心。</p><p>总有人认为不能因为软件的所有者有道德瑕疵，因此去抗拒使用该软件 —— 你错了！正因为他们有道德瑕疵，所以你根本不知道他们想要启动多么弱智的项目。</p><p>例如 Joel Kaplan 认为向难民免费提供互联网服务是件坏事，我们应该向难民出售服务。然后他意识到难民没有钱、告吹了项目。</p><p>这种莫名其妙的想法每天都在这帮自认为聪明的家伙儿的脑子里出现。这个项目很快就告吹了，很好，但你能保证之后没有傻瓜项目会落地吗？</p><p>我们每次看到都会惊叹「这是谁想出来的馊主意？」的落地项目，正是这帮没有道德的高层想出来的。更可笑的是，他们会因为身边聚集了大量的马屁精，而觉得自己聪明无比。</p><p>那么又是谁让马屁精们围着他们转的呢？是他们的支持者、他们软件的用户、所有只会向钱看的人。</p><p>Zuckerberg 深知我们 —— 除了他和他的那些朋友们以外的人类 —— 都是 NPC、随机鹦鹉、可以被预测的机器，所以推出了元宇宙、能够代替真实朋友的聊天机器人。他甚至认为美国人平均有不到三个朋友，所以更应该使用 Meta AI 聊天机器人软件来满足对朋友的需求。</p><p>再就是我们更爱朋友、而非恨他，所以没有人会离开 Meta 的社交媒体平台。</p><p>不过这对 Meta 而言依然不是一件好事。因为我们和朋友们使用社交媒体平台是为了线上交流，但 Meta 希望我们多多上线、观看广告。</p><p>为此，Meta 先是调整了算法，让我们更容易看到观点不一致的人，然后陷入漫长且毫无意义的争论中…… 这点我想读者朋友们会感到熟悉，这是「引流」的做法。</p><p>再然后，TikTok 为代表的短视频平台开始在美国出现，Meta 快速在 Instagram 还有 Facebook 里都添加了类似的功能。这甚至都不需要 Meta 买流量，只需要短视频的向上划机制就能牢牢将用户锁在软件中动弹不得。</p><p>Meta 现在的状况实在是说不上好。投入了大量资源的 AI 软件近乎无人问津，意味着 Zuckerberg 的「大家没有朋友、需要 AI 聊天机器人做朋友」计划临近破产。</p><p>去年 Meta 往 Instagram 还有 Facebook 内添加了大量 AI 用户，并希望这可以吸引到年轻用户。可见他不仅认为美国人平均没有多少朋友，也相信 Gen Z 是一群见 AI 就眼开的小傻子们。对于更下一代的 Gen Alpha——2010 年初到 2020 年中出生的人 —— 他们对 AI 技术的好感恐怕会更低。</p><p>现在 AI 热潮依然在进行下去，没有人愿意先跑出来，他们都认为自己能够全身而退，甚至拿到很多钱。</p><p>我们也能看出来 Zuckerberg 并不是什么聪明人。人们提到 Zuckerberg 也只会觉得他创立了 Facebook 很厉害，然后没了。又或者是部分对他压根不了解，也对 Meta 不了解的人，仅凭他是个有钱人便开始神话他的经历和人格 ——Musk 也被这么干过。我始终难以理解竟有人认为 Mush 是个大善人，亦或者支持 Trump、觉得他做得对。</p><p>Meta 数个月前将名下的知名社交媒体平台商业化，添加订阅套餐。整体感觉更像是 Discord、QQ 的做法，也就是花钱买装扮、小功能。不然 Meta 真的要难以维持下去了。</p><h2 id="我的看法"><a class="markdownIt-Anchor" href="#我的看法"></a> 我的看法</h2><p>我建议读者朋友们放弃使用 Meta 的产品。不仅是为自己好，也是为自己爱的人们好。</p><p>该公司的领导者不仅脑子不聪明、没有自知自明，还有道德问题。坏人是可预料的，但是蠢人是难以预料的。我们在未来依然会看到 Meta 的各种丑闻。</p><p>如果你是 Instagram 用户，你可以尝试 Pixelfed。它是 Fediverse 里占据了图片分享生态位的软件。</p><p>如果你是 Facebook 用户…… 其实我用 Facebook 并不多，所以我不知道有什么更好的同类型软件。</p><p>Threads 用户自然就是以 Mastodon 为首的微博客软件了。当然也有其他类似定位的软件，你们可以通过 <a href="https://fediverse.party/">该网站</a> 了解 Fediverse 软件的生态位。</p><p>WhatsApp 用户的话，我知道类似功能的产品有 Signal。Matrix 应该也算类似的产品？那 XMPP 还有 IRC 呢？—— 我不知道，我使用最多的 IM 软件其实是手机自带的短信。</p><p>下篇见！</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我建议你离开 Meta 的生态。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
  </entry>
  
  <entry>
    <title>RE：Bloggers, can we make better titles for our posts?</title>
    <link href="https://blog.cytrogen.icu/posts/ea71.html"/>
    <id>https://blog.cytrogen.icu/posts/ea71.html</id>
    <published>2026-08-05T23:22:00.000Z</published>
    <updated>2026-08-05T23:28:24.999Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我最近开始频繁写 RE 类文章的一切起因。</p><span id="more"></span><p>原文链接：<a href="https://michaelharley.net/posts/2026/06/15/bloggers-can-we-make-better-titles-for-our-posts/">https://michaelharley.net/posts/2026/06/15/bloggers-can-we-make-better-titles-for-our-posts/</a></p><hr><p>Mike（Michael Harley）反对缺乏信息增量、阻碍信息有效传递的博客写作习惯。</p><h2 id="标题的选择"><a class="markdownIt-Anchor" href="#标题的选择"></a> 标题的选择</h2><p>Mike 一是反对模糊不清的标题、鼓励使用描述性标题。</p><p>这一类指的是无法提供任何主题线索的标题。对于不认识作者的泛读者而言，模糊的标题极大地增加了筛选信息的成本，导致优质内容会被忽略掉。</p><p>不过这有个前提，那就是「在 <a href="https://bubbles.town/">Bubbles</a> 这种聚合网站内」。</p><p>Bubbles 是我这个月新发现的聚合网站，它用起来有点像 Hacker News。</p><p>不过我不喜欢使用聚合网站：</p><ol><li>聚合网站太多了、看不过来；</li><li>如果用 RSS 订阅，难免会出现重复的文章。</li></ol><p>FreshRSS 可能有解决这个问题的法子，不过我现在不打算折腾。</p><p>总之因为聚合网站往往只会展示标题，所以标题成了读者朋友们唯一可以从文章内提取到的信息。</p><p>我的标题…… 有时候是描述性的，例如《我开始有健康的生活习惯了》、《数多年重试跑步然后晕倒》，真的就是文章大致什么内容、标题就写什么；有时候不明所以，比如…… 呃，《大熊猫送快递》？确实有 <em> panda</em> 也有 <em> express</em> 在内啦。</p><p>评论区内有人说，早期的博客甚至都没有标题。我最近看到有博客是将微博客和文章混合排序在一起，所以首页上能同时看到没有标题的和有标题的。</p><p>Mike 也反对标题党。</p><p>这个我很赞同。标题党要不得：不要为了流量和 SEO 而做这些讨人厌的事情！如果我看到诸如「三个维持你和爱人关系的小妙招」，我会直接把标签页关掉的！</p><h2 id="bucket-posts"><a class="markdownIt-Anchor" href="#bucket-posts"></a> Bucket Posts</h2><p>Mike 二反对缺乏聚焦的 bucket posts。</p><p>这一类指的是「周记」、「本周链接汇总」等文章。因为它们没有单一且明确的讨论焦点，而陌生读者不会对此感兴趣。</p><p>「想法在月月日日迭代」系列 —— 也是我的月刊 —— 也是 bucket posts，即没有主题的大汇总文章。读者朋友们能做的只有我写什么看什么，直到看到觉得不错然后点赞，或者看完觉得浪费半小时，或者嫌太长不看。</p><p>原来如此，bucket posts 其实是博客界的 おまかせ（omakase，一种全权委托厨师定制菜单的用餐形式，厨师想做啥你吃啥）……！</p><p>我原先并不喜欢直接将对某某文章的回应写成一篇文章，除非它很长。不过之后我注意到，我仅是将回应藏在了 bucket posts 内、避免单独发文给我带来的困扰，即我确确实实把这个回应当回事儿、作为文章发了出去。</p><p>将链接塞在一大堆链接，和单独挑一个链接发文，意义是很不同的。</p><p>我先前的标准是，只有条目的文字到达一定的数量标准 —— 即足够长了 —— 我才会单独拉出来写成文章。但事实是，你们点进两三个月前的月刊，依然会发现完全够当成独立文章的条目。我只是不敢将其拉出来作文章而已。</p><p>至于为什么字数是硬性标准：我不清楚为什么我会这么想，但有可能是因为我部署文章需要我做许多工作：将 Org Mode 文件导出成 Markdown 文件，然后用 <code>hexo server</code> 跑一下看看渲染效果、挑挑错别字，接着将全新的变更 push 到云端，最后跑写好的 syndicate 脚本、坐等 VPS 跑完构建。因为成本高，所以我会希望自己的文章至少写得长一些，不要几段话就结束，不然显得我有点可怜。</p><p>在阅读上，我很喜欢 bucket posts，尤其是刊类文章，再特别是 Mike 会在文章下附加自己的想法、重述的类型。</p><p>不过我发现还有仅汇总链接的、仅汇总近期想法的 bucket posts。其中我最不喜欢阅读的是完全没有上下文、让人看了一头雾水的短语合集。我写时会尽可能补全上下文，至少别让不知道的人看了不知道我在说什么。</p><p>这些是我订阅的 bucket posts：</p><ul><li>Spike 的 <a href="https://taxodium.ink/index.html#zine">Zine</a></li><li>Eltrac 的 <a href="https://www.geedea.pro/weekly/">大脑充血</a></li><li>阮一峰的 <a href="https://www.ruanyifeng.com/blog/index.html">科技爱好者周刊</a></li><li> Cory Doctorow 的 <a href="https://pluralistic.net/">Pluralistic</a></li><li><a href="https://selfh.st/">Self-Host Weekly</a></li><li> 强少 Qone 的 <a href="https://www.fengxiaoqiang.com/yys/">有意思小周刊</a></li><li>远景的 <a href="https://v1sta.xyz/newsletters/">简报</a></li><li> Pseudoyu 的 <a href="https://www.pseudoyu.com/posts">周报</a></li><li>阿猫的 <a href="https://ameow.xyz/">猫鱼周刊</a></li><li> TW93 的 <a href="https://weekly.tw93.fun/">潮流周刊</a></li><li> joeytoday 的 <a href="https://joeytoday.com/archives/?tag=%E7%AC%AC%E4%B8%89%E5%91%A8%E5%88%8A">第三周刊</a></li><li>莫比乌斯的 <a href="https://mobius.blog/category/humachine/newsletter/">这一周莫比乌斯环找到了哪里？</a></li><li>SouthFox 的 <a href="https://blog.southfox.me/tag/FoxThinking/">FoxThinking</a></li><li><a href="https://www.linggandianbo.com/tag/newsletter/">灵感电波</a></li><li>李启龙的 <a href="https://wiki.eryajf.net/weekly/">学习周刊</a></li><li><a href="https://study.tczhong.com/tags/weekly/">TC 分享</a></li><li> Marcus 的 <a href="https://immarcus.com/blog/">博客阅读周记</a></li><li><a href="https://scrubbyinabox.substack.com/">刷比小废报</a></li><li>椒盐豆豉的 <a href="https://blog.douchi.space/tags/%E5%85%B3%E6%88%91%E8%BE%9F%E4%BA%8B/#gsc.tab=0">关我辟事</a></li><li> Thom 的 <a href="https://thomasrigby.com/tags/weeknotes/">Weeknotes</a></li></ul><p>还有一些其他的 bucket posts 但是没有继续更新所以就不贴了。</p><p>应该贴完了吧…… 实在不行到时候再在 Fediverse 上补充。</p><h2 id="博主们应不应该发表自己讨厌的东西"><a class="markdownIt-Anchor" href="#博主们应不应该发表自己讨厌的东西"></a> 博主们应不应该发表自己讨厌的东西？</h2><p>文章的评论区中，有个来自 <em> Bri</em> 的留言：</p><blockquote><p>As a blogger, you should encourage people to write. Not discouraging them by stating "you should write better post" and then pointing it out that you don't like certain types of posts. If you don't like to read them, don't read them. And it's okay if you don't like certain type of post.</p><p>作为一个博主，你应该鼓励人们去写作。而不是通过说「你应该写出更好的文章」来打击他们，然后指出你不喜欢某些类型的文章。如果你不喜欢读，那就别读。你不喜欢某种类型的文章也没关系。</p></blockquote><p>这挺有趣的。博客站主可以在自己的网站中明确表达自己 <a href="/hates/">讨厌</a> 什么、<a href="/likes/">喜欢 </a> 什么，毕竟发布个人偏好，甚至对他人的批评，都在言论自由的范畴内。</p><p>尤其是 Mike 在文章结尾已经写了：</p><blockquote><p>Those are the main things that irritate me when scrolling Bubbles. If you don't like my opinions, well just ignore them and continue to write on your blog however you like.</p><p>这些是我在浏览 Bubbles 时最感到烦躁的事情。如果你不喜欢我的观点，那就忽略它们，继续按照你喜欢的方式写博客吧。</p></blockquote><p>不过根据 Mike 的小标题，如 <em> AVOID BUCKET POSTS</em>（避免写 bucket posts），确实是强观点的写法 —— 我完全认可这类写法，因为我不喜欢 weak writing，即不自信、懦弱的写作方式。你的观点应当是你可以捍卫的（这也是强观点）。但强观点的代价是它会引起读者的强烈反应，因而同样使用强观点来反击你 —— 这一切又都是公开写作的一部分。</p><p>不可否认，会有新人博客站主受作者的文章影响、去做作者提到的事情。但同样，也会有新人博客站主受反对了作者的回复影响、不去做作者提到的事情。</p><p>就连我这段回复，也是对 Bri 的强观点的强观点回应 —— 再套娃一下就是，对 Bri 的对 Mike 的强观点的强观点回应的强观点回应…… 感觉眼睛要瞎了。</p><p>作为例子，受该文章的影响的我于数天前将月刊内超出「复述」属性的条目都拉到独立文章去了。目前还有许多 RE 类文章的存货没有发出来，也让我久违体验了「过数天再来 review 自己文字，结果发现写得一塌糊涂」的感觉。</p><h2 id="稀少的-re-类文章"><a class="markdownIt-Anchor" href="#稀少的-re-类文章"></a> 稀少的 RE 类文章</h2><p>最后一个我想要聊聊的点是，我发现使用英文的独立博客经常会出现 RE 类文章，而使用中文的独立博客鲜少看到它们 —— 尤其是使用简体中文的圈子。</p><p>我推测英文独立博客的逻辑是这样的：</p><ol><li>英文独立博客的底层建立在 RSS 订阅网络和成熟的永久链接机制之上</li><li>英文独立博主们会通过 RSS 订阅器获取同行的最新动态。看到某篇文章而引发了思考，便会直接写篇新的、在文中通过超链接指向原文</li><li>早期博客系统内置的 Pingback 或者 Trackback 协议会自动在原作者的评论区留下引用通知</li></ol><p>而中文独立博客的逻辑是：</p><ol><li>中文独立博客经历了向大型聚合平台还有社交媒体平台的迁移</li><li>中文网络内容的生产重心都在中心化平台</li><li>长文回应的传统逐渐受中心化平台的影响而消失</li><li>评论区留言或社交媒体平台上的转发与短评会更符合习惯</li></ol><p>再者是二者对「博客」的看法也显著的有所不同：前者认为博客更公开、是公共论坛，因此回应是正常的交流方式；后者会为回应贴上更多情绪色彩，例如「你为什么要回应我！你是不是对我有意见！」—— 这个我还没有见过，不过总感觉能想象出来。</p><p>不过我总认为这样的逻辑没能闭环，我的拙见无法完美地解答疑惑。所以这段就是抛砖引玉、想要听听各位读者朋友们的见解了。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我最近开始频繁写 RE 类文章的一切起因。&lt;/p&gt;</summary>
    
    
    
    <category term="文章回应" scheme="https://blog.cytrogen.icu/categories/%E6%96%87%E7%AB%A0%E5%9B%9E%E5%BA%94/"/>
    
    
  </entry>
  
  <entry>
    <title>是的，我没有意识形态</title>
    <link href="https://blog.cytrogen.icu/posts/1cfd.html"/>
    <id>https://blog.cytrogen.icu/posts/1cfd.html</id>
    <published>2026-08-04T14:00:00.000Z</published>
    <updated>2026-08-04T14:05:14.506Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>七月份 Linus Torvalds 在邮件串内回了个颇有争议的 <a href="https://lore.kernel.org/linux-media/CAHk-=wi4zC+Ze8e+p3tMv8TtG_80KzsZ1syL9anBtmEh5Z40vg@mail.gmail.com/">信</a>。</p><span id="more"></span><p>该邮件串讨论的是基于 Gen AI 的自动化代码审查工具 sashiko，在 Linux 内核开源社区里到底该怎么用。</p><p>邮件列表内，Roman 和 Laurent 就 Gen AI 工具在开源社区中的定位以及路线争了起来：维护者将 sashiko 给出的审查意见转发给代码作者时，该不该提前人工筛选和验证呢？</p><p>Roman 认为如果要的话，那引入 sashiko 根本没有意义啊。维护流程还会因为多了这一抽象层而变得复杂。如果 Laurent 本就反对 Gen AI 的话，那就直接聊 Gen AI 该不该出现在社区内，而不是拐弯抹角弄这些有的没的的门槛吧。</p><p>Torvalds 对此的回复是：</p><ol><li>Linux 绝不排斥 AI</li><li>Linux 不是带有反 AI 情绪的项目。如果不接受的话，可以自己去 fork，要不然就走开</li><li>AI 的技术价值无可争议。还在怀疑 AI 是否有用的人根本没有实际使用过该技术，是盲目的反对者。就算它会犯错，但人类也会犯错。人们应该去优化这个技术和工具，而不是逃避它</li><li>Linux 是纯粹的技术项目，而非「社会运动」项目。内核社区选择开源，是因为开源能做出更好的技术和产品，而不是出于宗教思想</li></ol><hr><p>我最初阅读 Torvalds 的回应时，我在 Fediverse 上 <a href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXRRHJJMCA2F2M7D9MD218VS">写道</a>：</p><blockquote><p>Torvalds 希望 Linux 内核项目完全基于技术而非政治</p></blockquote><p>但写完发布后我意识到：不对啊！所有的问题都可以被归结为政治问题。他所谓的「拒绝意识形态」，不也是拒绝了特定的意识形态、另一个意识形态的表现吗！于是我赶忙删除 toot 并重新编辑：</p><blockquote><p>我不喜欢这封邮件中像「宗教原因」和「社会斗士」之类的说法；直接说你支持技术官僚主义或功利主义就好了，而不是将自己去政治化。</p></blockquote><p>借此我发现，我一瞬间将周遭的常态视为非政治，并将政治或者意识形态视为奇怪的东西。这类似于我在大学认识的很多人；他们厌恶性别、性取向等等叙事，因为过去的社会与思想才是「正常且普遍」的，有问题的是这些新来的叙事。</p><p>占据统治地位的意识形态最擅长的事情，就是把自己塑造成没有意识形态的自然状态。</p><p>通过将不同政见者贴上标签，便能成功地将关于技术与伦理、劳动异化、知识产权和社区治理的严肃政治辩论，降维打击成「理智技术派 v.s. 狂热情绪派」的对立，我实在是喜欢不起来。</p><p>尤其是他还非常天真地认为反对者都不会使用 AI 工具，所以才反对 AI 工具 —— 啊，是的，我在哪里见过一模一样的做法。让我想想，原来是在 <a href="https://www.geedea.pro/weekly/80/#%E4%B8%8D%E5%92%8C-ai-%E7%AB%99%E4%B8%80%E8%BE%B9%E7%9A%84%E8%AF%9D%E5%AE%83%E4%BC%9A%E6%8A%8A%E4%BD%A0%E8%82%8F%E6%AD%BB:~:text=%E6%98%AF%E4%B8%8D%E6%98%AF%E5%8F%AA%E6%9C%89%E6%8A%8A%E4%BD%A0%E7%9A%84%E5%AF%B9%E6%89%8B%E6%83%B3%E8%B1%A1%E6%88%90%E6%97%A0%E7%9F%A5%E7%9A%84%E8%A0%A2%E8%9B%8B%EF%BC%8C%E4%BD%A0%E7%9A%84%E8%AE%BA%E8%AF%81%E6%89%8D%E8%83%BD%E7%AB%99%E5%BE%97%E4%BD%8F%E8%84%9A">这里</a>。</p><p>Torvalds 在邮件串内表达的，正是将自身的主张伪装成非政治的纯粹技术，从而将所有引入伦理、劳动异化、治理讨论的人统统打成狂热情绪派或者宗教分子的 <a href="/posts/36e6.html">后政治</a> 策略。他不单单是支持技术官僚主义或功利主义那么简单 —— 我在 Fediverse 上写的内容要早于本篇文章，所以我在批评自己之前的观点。</p><p>借用 Steven Brust 关于财产权和人权的划分，我们能够更深一层去剖析 Torvalds 的开源观：Brust 认为，右派主张财产权是人权的一部分，而左派主张财产权是实现人权的工具和手段。</p><p>延伸来看，Linux 会开源，是因为能做出更好的技术和产品，而不是出于宗教思想。也就是说，技术与开源对他来说仅是提高生产效率的工具，而非实现人权或者对抗异化的手段。他甚至将后者贬低为「宗教思想」。</p><p>他关心的只有效率和产出。Gen AI 这种能提高短期产出但带有伦理争议 —— 如知识产权侵占、劳动异化 —— 的技术出现时，他会毫不犹豫地站向「实用」的一端，并把伦理反思排除出讨论范围 —— 毕竟他们都是「社会斗士」！</p><p>邮件串内使用的 <em> social warrior</em> 一词，现如今是个贬义词，完整的应该叫 <em> social justice warrior</em>，即「社会正义战士」。</p><p>根据 Wikipedia 的解释，「社会正义战士」是这个意思：</p><blockquote><p>社会正义战士（英语：Social Justice Warrior，通常缩写为 SJW；或称正义魔人）是一个贬义词语，指支持女性主义、环保、民权、进步主义、多元文化主义和身份认同政治等观点并积极参与社会运动的个人，指责一个人为社会正义战士带有指责其寻求主观验证而非任何深层次的信念的意味，并且借助参与虚伪的社会正义讨论或行动主义以提高个人声誉。</p></blockquote><p>起初这个词还是个中性、偏正面的术语，后来它在一个社交平台开始以贬义词的形式出现 —— 而这个社交平台是 Twitter。</p><p>它的用法也非常简单：</p><blockquote><p>The accusation that somebody is an SJW carries implications that they are pursuing personal validation rather than any deep-seated conviction, and engaging in disingenuous arguments.</p><p>指责某人是 SJW 通常暗示其追求的是社会认同而非深层的信念，并且在进行虚伪的辩论。</p></blockquote><p>因此也能理解为什么 Torvalds 的回应听上去像是傻瓜，因为他把邮件串内的 AI 反对者都当成傻瓜、从未使用过 AI 工具、仅是在追求社会认同、无法深度思考。</p><p>但我们都很清楚 AI 工具的问题，这显得 Torvalds 突然说「你们都没有使用过 AI 工具、是傻瓜」非常莫名其妙，荒谬的回应再对比邮件串之前其他人的讨论，意外令人忍俊不禁、喜不自胜、哑然失笑、释怀了。</p><p>不抖机灵了说回意识形态。</p><p>开源本身明明也是意识形态结的果。Torvalds 对于开源的看法，在我意料之中，虽说我其实根本不熟他…… 不过《大教堂与集市》这本书给我的刻板印象便是，开源运动早期的发起人都喜欢功利和实用主义，以及和商业有所关联的利益。</p><p>我想起几个月前在网络上看到的言论截图，可惜我没有保存图片的习惯，内容大致是一位网友赞叹一部电影没有任何意识形态、实属难得 —— 这怎么可能呢？于是立即有人反驳说该电影实际上有某某意识形态，叫他不要做白日梦、把自己不喜欢的意识形态简单定义成所有意识形态都有问题。</p><p>Antoine Destutt de Tracy 于 1796 年创造了 <em> idéologie</em> 这个词儿，原意是「观念的科学」、「思想体系」，也就是一门研究观念是如何产生的科学。</p><p>但渐渐地，它被制度化、工具化。例如在中国，它的含义愈来愈接近斗争概念。斗争概念会生产敌人，主流意识形态之外的都是「错误的意识形态」。值得注意的是，此处的敌人并非「被发现」，而是「被划分出来」。只要 <u>意识形态斗争</u> 还在，就必须有一个意识形态上的敌人存在，否则这个词儿就会失业。</p><p>明明它属于解释「世界」的「语言」—— 这套说法见 <a href="/posts/893f.html#%E4%B8%8B%E4%B8%80%E4%BB%A3%E4%BA%BA%E6%9C%89%E5%8F%AF%E8%83%BD%E6%98%AF%E4%BA%BA%E7%B1%BB%E6%BC%94%E5%8C%96%E7%9A%84%E5%8F%88%E4%B8%80%E6%AC%A1%E5%88%86%E5%8F%89%EF%BC%9A%E8%AE%BA-ai-%E5%AF%B9%E6%95%99%E8%82%B2%E5%92%8C%E4%BA%BA%E6%80%A7%E7%9A%84%E5%A8%81%E8%83%81:~:text=%E6%96%87%E7%AB%A0%E4%BD%9C%E8%80%85,%E6%84%8F%E4%B9%89">这里</a> —— 但是人们说到它总会联想到宣传、站队等行为。</p><p>但关键悖论也在于，「我没有意识形态」本身也是意识形态，还是最危险、最成功的一种意识形态：它成为了中性的现实、常识、纯粹客观，它统治了世界。人们不再需要说服他人，因为大家 <span class="emphasis">本来</span> 就这么想。</p><p>最后是「不爽就 fork」。开源的一大好处便是如此，不爽就能创建个新分支出来。然而让毫无资本支持的社区贡献者滚去自己 fork，表面上是提供了选择自由，但其实悄咪咪掩盖了结构性的压迫。</p><p>Linux 内核这种巨大规模的项目，代码提交早已被大型科技巨头的雇佣员工所垄断。资源与权力在结构上极度不对等，社区个人根本不可能持续维护一个内核分支。</p><p>现实中企业对于「劳工缺乏保障」一事，有着「你可以自由选择换工作」的解释。可是「权利」不等同「能力」，大家该妥协的依然在妥协 —— 环境烂，那你可以走啊。没人在留你。什么意识形态不意识形态的，<span class="emphasis">我没有意识形态</span>。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;七月份 Linus Torvalds 在邮件串内回了个颇有争议的 &lt;a href=&quot;https://lore.kernel.org/linux-media/CAHk-=wi4zC+Ze8e+p3tMv8TtG_80KzsZ1syL9anBtmEh5Z40vg@mail.gmail.com/&quot;&gt;信&lt;/a&gt;。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="政治" scheme="https://blog.cytrogen.icu/tags/%E6%94%BF%E6%B2%BB/"/>
    
  </entry>
  
  <entry>
    <title>RE：美国梦与美国痛 华裔新移民青少年帮派犯罪</title>
    <link href="https://blog.cytrogen.icu/posts/1547.html"/>
    <id>https://blog.cytrogen.icu/posts/1547.html</id>
    <published>2026-08-03T16:38:00.000Z</published>
    <updated>2026-08-03T16:39:15.047Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>「美国梦」是可以变成「美国痛」的；华裔青少年也可以和帮派有所联系。</p><span id="more"></span><p>原文链接： <a href="https://myhunan.us/%E7%BE%8E%E5%9B%BD%E6%A2%A6%E4%B8%8E%E7%BE%8E%E5%9B%BD%E7%97%9B-%E5%8D%8E%E8%A3%94%E6%96%B0%E7%A7%BB%E6%B0%91%E9%9D%92%E5%B0%91%E5%B9%B4%E5%B8%AE%E6%B4%BE%E7%8A%AF%E7%BD%AA/">https://myhunan.us/美国梦与美国痛 - 华裔新移民青少年帮派犯罪/</a></p><p>该文章原本是发在《侨报》上的，推断时间是在 2010 年 9 月的上旬或往前。我贴的链接是旅美湖南同乡会所转载的版本，<code>datePublished</code> 写的是 2010 年 9 月 14 日。</p><p>《侨报》或称 <em> The China Press</em> 是美国最大规模的中文日报之一，与《世界日报》、《星岛日报》、《明报》并称美国四大中文报 —— 我倒是没有阅读报纸的习惯。家附近《大纪元时报》的报纸更多，也是法轮功学员创办的。</p><p>而该篇报道是摄影记者李竑写的。他经常报道纽约华埠（唐人街）、华人社区以及移民相关的议题。</p><p>这篇是他采访了长期调查华裔新移民青少年帮派犯罪的执法人员后所撰写的。</p><hr><p>2010 年的过去 30 年，即 1980 年开始，美国青少年帮派剧增，原因主要在于移民的大量涌入，以及毒品交易猖獗。</p><p>关于为什么新移民青少年要加入帮派，文章中认为深层根源出在家庭上。父母一代都成长于文革年代，价值观混乱、仅在乎钱，不知道如何教育孩子。</p><p>其中最典型的情况是父亲偷渡来美赚钱、妻儿留守国内。长期分离的家庭导致孩子缺乏安全感。乡村风气也普遍是「去了美国就能富起来」，让孩子们错认为日后必去美国、去了美国就不用努力了，于是荒废学业、无心学习，文化水平自然也低。</p><p>我的一表弟就是这种情况：父亲移民先来美国工作，当时他们那儿的风气就是来美国能变有钱。</p><p>父母辈多生于 50-70 年代，经历过文革和改革开放。前者批判了传统伦理道德，后者又是市场转型，价值观难免会金钱化。这些父母的教育往往要么是放任，要么就是仅谈钱和出人头地。</p><p>表弟因此也觉得作为高中生，未来必定来美国了，那还考个毛高考啊。我出去洗盘子能把老板店买下来，你努力高考上大学，毕业后能找到工作吗？所以他近乎是放弃了高考，也没有继续学习，直接移民了过来。</p><p>后果是，他没能事先调查好在美国要如何生活。是，你洗盘子可以生存下来，但作为年轻人，不可能只有「生存」，而没有「生活」吧？没有说英语的技能，在美国基本上只能在华人圈的底层打转。</p><p>更别提语言、文化差异，还有华人外的种族歧视了。本来在家乡过得好好的，现在来了美国不过是底层人，连话都说不明白，极大的落差会引人绝望、误入歧途。</p><p>表弟刚来时，他父亲还问我能不能帮他找个大学上上。不过这件事后来不了了之，因为表弟被他父亲送去寿司师傅培训学校了。现在他应该在外州工作。能经济独立非常重要，因为文章内的大量被诱骗入伙的新移民青少年，就是没有经济独立、赚钱的概念，从而被小利吸引、酿下大祸。</p><p>在 80 年代末到 90 年代，福州的沿海农民渔民掀起偷渡潮，其中最典型的模式便是负债偷渡，然后在美国打工还债。</p><p>而 90 年代初期政府对未成年偷渡客的放任，被蛇头利用、做起了让大批 14-17 岁青少年乘船入境的生意。</p><p>在这些偷渡船上，人们按地域划分、靠拳头说话，青少年也初次体验到「暴力即力量」这种可怕的思想。</p><p>到了美国后，未成年的偷渡客在打工时容易被老板欺凌、克扣工资，敢怒不敢言 —— 没办法啊，你是偷渡客！老板愿意让你工作就已经是你的「荣幸」了！</p><p>他们很大可能在家里也不被关心，毕竟因为偷渡要很多钱，父母只能埋头工作还债，又因为没有英语、同为偷渡客、干的也是苦力活、被欺凌，受气后哪还管教育，直接把孩子当充气筒打一顿。</p><p>贫穷是可怕的。我经历过类似的事情，也不敢没有钱。高中的老师曾瞒着我将事情报告给了儿童局 —— 许多人可能会认为在美国，儿童很重要、打不得。但是孩子什么都不知道，又哪能知道自己其实有一定的「权利」呢？所以很多时候是被父母威胁着「如果告诉别人，你就没有爸妈了！」然后为了自己可悲的、天生的爱父母的能力，忍气吞声挨打。总之儿童局介入后，母亲不敢打骂我了，我也可算是在肉体上逃离了暴力。</p><p>部分父母因为怕儿童局，而不敢打骂青少年。哎，这些青少年也有被忽悠进帮派的可能性在。因为打骂不意味着教育：不打骂同时也不教育，到头来还是没对孩子进行教育。他们怎么知道事情该怎么做呢？他们只知道有人叫自己进帮派，进帮派做事情可以拿钱、玩女人、有社会地位。</p><p>在这样的环境下生存，再接触到帮派，会非常容易被诱骗。因为在帮派内，暴力就是力量。帮派会罩着你，只要你愿意花费 <span class="emphasis">一点点</span> 代价为帮派做事，还能吃香喝辣随意玩女人。压抑久了的青少年一听，自然容易上钩 —— 暴力、暴力才是这里的规则 —— 然后误入歧途。</p><p>为了表达忠诚，这帮青少年很容易出现群体极化效应，手段残暴到成年人都难以想象。这包括早期的绑架勒索、强暴女性…… 后来政府严打偷渡，帮派的重心又转向毒品交易，这帮青少年又拉拢身边朋友来吸。</p><p>泛华人家庭在教育上的一大问题就在于将「养育」简化成了「饲养与投资」。而真正的教育应当建立在以下心理和认知的建设上：</p><p>一、将孩子视为独立的精神主体。</p><p>这类父母常把自身的移民牺牲 —— 如「我辛苦打工都是为了你」—— 转化为对孩子的道德绑架。突然要承受这些「罪恶」的孩子，要么极度顺从且放弃自我，要么自暴自弃、通过自毁式反抗来切割负罪感。</p><p>必须要承认，孩子具备着独立的意识，有权拥有与父母不同的价值观、人生路线，乃至失败的权利。</p><p>我在昨天休息日与一位家长见面，他的思想令我惊叹：他会称呼自己上初中的孩子为 <em> adult</em>，并思考如何在「保护孩子」以及「归还掌控权给孩子」之间平衡。他认为他的孩子已经有了「自我」这个观念，父母不该再约束孩子去探索外面的世界。</p><p>二、建立有边界的规则；不要无底线去放任孩子。</p><p>部分父母会因为文化或自卑心理，在面对适应了新环境的孩子时失去话语权，进而放弃在秩序上的约束。</p><p>缺乏边界感的孩子在社会中会感到失控、主动寻找帮派这种提供「秩序」的群体来获取安全感。</p><p>三、提供心理安全感和情感链接。</p><p>无法提供情感支持与心理安全感的家庭，将会是孩子又一个需要戒备的地方。</p><p>大量新移民青少年在外界会经常遭遇挫折，比如语言不通、文化排斥和种族歧视。既然家庭也无法为其提供归属感和保护，他们自然也只能寻找能够提供这些东西的地方。</p><p>许多父母会在事发后责怪孩子「为什么不把事情都说出来」。其实日常的许多细节已经向孩子们证明家庭不够可靠、说出来反而会遭受原可以避开的责骂。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;「美国梦」是可以变成「美国痛」的；华裔青少年也可以和帮派有所联系。&lt;/p&gt;</summary>
    
    
    
    <category term="文章回应" scheme="https://blog.cytrogen.icu/categories/%E6%96%87%E7%AB%A0%E5%9B%9E%E5%BA%94/"/>
    
    
  </entry>
  
  <entry>
    <title>想法在丙午瓜秋迭代</title>
    <link href="https://blog.cytrogen.icu/posts/3456.html"/>
    <id>https://blog.cytrogen.icu/posts/3456.html</id>
    <published>2026-08-01T04:00:00.000Z</published>
    <updated>2026-08-01T17:45:48.998Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>这个月我都在做项目，并且把打工给干掉了。虽是瓜秋，不过我并没有吃到多少瓜。总之七月过后，便是理论最炎热的八月了！也是开学的时候。我已经决定至少 gap 掉这个学期，但还是打算旁听一节 cybersecurity 的课程，好让自己的生活有些固定的行程。</p><span id="more"></span><details>      <summary>本期导读</summary>      <h2 id="输入"><a class="markdownIt-Anchor" href="#输入"></a> 输入</h2><h4 id="世界"><a class="markdownIt-Anchor" href="#世界"></a> 世界</h4><ul><li><a href="#%E6%80%A7%E7%9A%84%E6%84%8F%E4%B9%89%E7%A9%B6%E7%AB%9F%E6%98%AF%E4%BB%80%E4%B9%88">性的意义究竟是什么？</a></li><li><a href="#%E8%81%8C%E5%9C%BA%E7%81%B5%E6%B4%BB%E6%80%A7%E5%B9%B6%E9%9D%9E%E5%A6%82%E6%AD%A4">职场「灵活性」并非如此</a></li><li><a href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E7%BE%8E%E5%9B%BD%E7%9A%84%E6%95%91%E6%8A%A4%E8%BD%A6%E8%B4%B9%E7%94%A8%E5%A6%82%E6%AD%A4%E6%98%82%E8%B4%B5">为什么美国的救护车费用如此昂贵</a></li></ul><h4 id="远方"><a class="markdownIt-Anchor" href="#远方"></a> 远方</h4><ul><li><a href="#%E4%BD%A0%E7%9A%84%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD%E5%B9%B6%E9%9D%9E%E5%B7%A5%E5%85%B7">你的人工智能并非工具</a></li><li><a href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E8%AF%B4-anthropic-%E6%98%AF%E9%82%AA%E6%81%B6%E7%9A%84">为什么说 Anthropic 是邪恶的？</a></li><li><a href="#%E6%88%91%E5%90%8E%E6%82%94%E8%BF%81%E7%A7%BB%E5%88%B0-codeberg">我后悔迁移到 Codeberg</a></li><li><a href="#%E8%BA%AB%E4%B8%BA%E8%BD%AF%E4%BB%B6%E5%B7%A5%E7%A8%8B%E5%B8%88%E7%9A%84%E7%96%AF%E7%8B%82%E4%B9%8B%E5%A4%84">身为软件工程师的疯狂之处</a></li><li><a href="#%E5%8D%9A%E5%AE%A2%E6%98%AF%E5%A6%82%E4%BD%95%E7%A0%B4%E5%9D%8F%E7%BD%91%E7%BB%9C%E7%9A%84">博客是如何破坏网络的</a></li></ul><h4 id="周遭"><a class="markdownIt-Anchor" href="#周遭"></a> 周遭</h4><ul><li><a href="#%E8%A6%81%E4%B8%8D%E8%A6%81%E7%BB%99%E4%BD%9C%E8%80%85%E4%B9%B0%E5%92%96%E5%95%A1">要不要给作者买咖啡？</a></li><li><a href="#%E4%BD%A0%E7%9A%84-app-%E6%9C%AC%E5%8F%AF%E4%BB%A5%E6%98%AF%E4%B8%80%E4%B8%AA%E7%BD%91%E9%A1%B5-%E6%89%80%E4%BB%A5%E6%88%91%E5%B8%AE%E4%BD%A0%E4%BF%AE%E5%A5%BD%E4%BA%86">你的 <em>App</em> 本可以是一个网页（所以我帮你修好了……）</a></li><li><a href="#%E6%88%91%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E5%86%8D%E4%B8%8E%E4%BA%BA%E4%BA%89%E8%AE%BA">我为什么不再与人争论</a></li><li><a href="#%E5%9C%A8%E6%AF%92%E7%98%BE-%E7%89%A2%E7%8B%B1%E5%92%8C%E9%87%8D%E7%BD%AA%E4%B9%8B%E5%90%8E%E4%BB%8E%E9%9B%B6%E5%BC%80%E5%A7%8B">在毒瘾、牢狱和重罪之后从零开始</a></li><li><a href="#%E5%A4%84%E7%90%86-dickover">处理 <em>dickover</em></a></li><li><a href="#%E6%88%96%E8%AE%B8%E6%95%B0%E7%BE%8A%E7%9C%9F%E6%98%AF%E4%B8%AA%E6%9C%89%E6%95%88%E7%9A%84%E5%85%A5%E7%9D%A1%E6%B3%95">或许「数羊」真是个有效的入睡法</a></li><li><a href="#%E6%88%91%E4%BB%AC%E5%BA%94%E8%AF%A5%E4%BC%98%E5%8C%96%E6%8E%89%E4%BB%80%E4%B9%88">我们应该优化掉什么？</a></li><li><a href="#%E4%BD%A0%E7%9A%84%E5%A4%A7%E8%84%91%E5%A4%A9%E7%94%9F%E5%B0%B1%E4%B8%8D%E6%98%AF%E7%94%A8%E6%9D%A5%E6%89%BF%E5%8F%97%E8%BF%99%E4%B9%88%E5%A4%9A%E5%9D%8F%E6%B6%88%E6%81%AF%E7%9A%84">你的大脑天生就不是用来承受这么多坏消息的</a></li><li><a href="#%E4%BA%BA%E4%B8%8E%E5%8D%9A%E5%AE%A2">人与博客</a></li><li><a href="#%E5%87%A1%E4%BA%8B%E5%B9%B3%E5%B8%B8%E5%BF%83">凡事平常心</a></li><li><a href="#%E6%88%91%E5%B8%8C%E6%9C%9B%E4%BA%BA%E4%BB%AC%E8%83%BD%E6%9B%B4%E5%8A%A0%E5%85%AC%E5%BC%80%E9%80%8F%E6%98%8E">我希望人们能更加公开透明</a></li><li><a href="#%E6%88%91%E7%9A%84%E5%8D%9A%E5%AE%A2%E6%96%87%E7%AB%A0%E5%86%99%E4%BD%9C%E7%81%B5%E6%84%9F%E6%B8%85%E5%8D%95">我的博客文章写作灵感清单</a></li><li><a href="#%E4%BD%A0%E7%9A%84-rss-%E9%98%85%E8%AF%BB%E5%99%A8%E6%AD%A3%E5%9C%A8%E5%89%A5%E5%A4%BA%E4%BD%A0%E7%9A%84%E4%BD%93%E9%AA%8C">你的 RSS 阅读器正在剥夺你的体验</a></li><li><a href="#%E6%97%A0%E5%B9%B2%E6%89%B0%E5%8D%B3%E6%98%AF%E5%B9%B2%E6%89%B0">无干扰即是干扰</a></li></ul><h4 id="眼前"><a class="markdownIt-Anchor" href="#眼前"></a> 眼前</h4><ul><li><a href="#%E4%BA%BA%E4%B8%8E%E8%A1%A3%E6%9C%8D">人与衣服</a></li><li><a href="#%E5%A4%9C%E7%8C%AB%E5%AD%90%E6%89%8D%E6%98%AF%E6%AD%A3%E5%B8%B8%E7%9A%84%E5%90%A7">夜猫子才是正常的吧</a></li><li><a href="#%E5%BE%AE%E4%BF%A1%E6%97%A9%E5%B7%B2%E4%B8%8D%E6%98%AF%E7%86%9F%E4%BA%BA%E7%A4%BE%E4%BA%A4">微信早已不是熟人社交</a></li><li><a href="#8-%E5%8F%B7%E5%87%BA%E5%8F%A3-%E7%AC%AC-1-%E6%AC%A1%E5%B0%9D%E8%AF%95-%E4%B8%8E%E8%82%B2%E5%84%BF">8 号出口（第 1 次尝试）与育儿</a></li><li><a href="#%E5%9C%A8%E6%97%A0%E5%85%B3%E7%B4%A7%E8%A6%81%E7%9A%84%E5%9C%B0%E6%96%B9%E5%91%90%E5%96%8A">在无关紧要的地方呐喊</a></li><li><a href="#%E6%AD%BB%E6%97%B6%E5%BD%92%E9%9B%B6%E4%B9%9F%E6%97%A0%E5%A6%A8">死时归零也无妨</a></li><li><a href="#%E7%A0%B4%E6%8A%98%E5%8F%B7%E7%9C%9F%E4%BB%96%E5%A6%88%E5%A4%AA%E6%A3%92%E4%BA%86">破折号真他妈太棒了</a></li><li><a href="#indieping-%E7%9A%84%E6%96%B0%E5%8A%9F%E8%83%BD">IndiePing 的新功能！</a></li><li><a href="#sites-on-neocities">Sites on Neocities</a></li><li><a href="#freshrss-%E6%96%87%E7%AB%A0%E5%85%A8%E6%96%87%E6%89%A9%E5%B1%95">FreshRSS 文章全文扩展</a></li></ul><h2 id="输出"><a class="markdownIt-Anchor" href="#输出"></a> 输出</h2><ul><li><a href="#%E6%8A%98%E8%85%BE%E5%8D%9A%E5%AE%A2">折腾博客</a></li><li><a href="#%E6%88%91%E5%86%99%E7%9A%84%E6%96%87%E7%AB%A0">我写的文章</a></li><li><a href="#%E7%BC%96%E7%A8%8B%E5%8E%86%E7%A8%8B">编程历程</a></li><li><a href="#%E4%B9%A6%E7%B1%8D">书籍</a> / <a href="#%E5%BD%B1%E8%A7%86">影视</a> / <a href="#%E9%9F%B3%E4%B9%90">音乐</a></li><li><a href="#%E6%97%A5%E8%AE%B0%E7%89%87%E6%AE%B5">真生活</a></li></ul>    </details><h2 id="世界"><a class="markdownIt-Anchor" href="#世界"></a> 世界</h2><p><a id="性的意义究竟是什么"></a></p><h4 id="性的意义究竟是什么"><a class="markdownIt-Anchor" href="#性的意义究竟是什么"></a> <a href="https://www.newyorker.com/magazine/2026/06/29/on-the-origin-of-sex-book-review-lixing-sun">《性的意义究竟是什么？》</a></h4><p>世界上，有部分生物能够无性繁殖。既然如此，为什么大自然还是发展出了有性繁殖这种，「麻烦」的行为？比方说文章中举的例子，孤雌生殖能让繁殖率翻倍。</p><p>文章的大部分内容都是讲述自然界中，不同生物的性是什么样的。除开有趣的科普，文章也抨击了 <u>达尔文主义</u>、认为这些狭隘的观点影响了之后人类对同性性行为、女性的看法。</p><p>唉，所以还是不知道为什么世界上有有性繁殖，也不知道为什么人类会发育出单单是为了性快感的性关系。</p><p>我过去也很好奇，同性性行为为什么是「违背自然规律」的？明明动物之间的同性性行为也不少。</p><p>再就是文章结尾所表达的，自然规律真的是什么值得遵守的概念吗？自然界中，强奸、乱伦等行为也有，我们会认为这些发生在人类身上是不道德、邪恶的，那又为什么要想方设法让另一方面的性去遵守自然规律呢？</p><p>作者 Elizabeth Kolbert 认为，「多样性即正当」也犯了逻辑错误，只是站在了更值得同情的一方而已。</p><p>哲学里有个问题，叫作 <u>休谟问题</u>（is-ought problem）。从「自然界存在 X」出发，其实是推断不出来「人类社会应该接受或者禁止 X」的。这一步逻辑跳跃本身就无效，不管 X 是乱伦、强奸、同性性行为还是杀小孩儿。</p><p>反同性恋者的人虽说「同性恋者是违反自然的」，但对乱伦和强奸的普遍存在视而不见，因为这压根就不是从自然界那儿归纳出的结论，而是先有了立场 —— 例如宗教 —— 再回头去自然界挑证据、包装成所谓的「自然法则」。如果将他们的结论套在乱伦和强奸上，他们便也不会认了，毕竟引用的根本就不是「自然」这个原则本身，只是把自然当作一个显得客观、实则可以随意取用的道具。</p><p>「因为自然界怎样怎样」不该被当成裁判道德或社会的依据。无论用它来支持保守立场还是自由立场都一样站不住脚，只是后者恰好在别的依据 —— 如伦理学、对个体自主权的尊重 —— 上更站得住脚。</p><p>真正该用来评判「该不该允许某种行为」的标准，应当是同意、伤害、自主这些更直接的伦理学概念。</p><p><a id="职场灵活性并非如此"></a></p><h4 id="职场灵活性并非如此"><a class="markdownIt-Anchor" href="#职场灵活性并非如此"></a> <a href="https://pluralistic.net/2026/07/11/your-risk/">《职场「灵活性」并非如此》</a></h4><p>Cory Doctorow 聊了聊「零工经济」。</p><p>零工经济实则是个统计黑洞，因为外界根本不知道工人到底挣多少钱、上线等单要花多少不计薪的时间。数据统统都被 Uber、Lyft 这类公司垄断着；工人和乘客各自的数据又极度分散，我们并不知道真实的数据长啥样。</p><p>根据 <u>《公平劳动标准法》</u>（Fair Labor Standards Act）的规定，联邦的最低工资目前是每小时 7.25 美元。但对于小费员工，雇主可以只支付一个更低的直接现金工资，最低可以到每小时 2.13 美元，而中间的差额（最多每小时 5.12 美元）由雇主计入为员工的小费收入。这种做法也叫「小费抵扣」，因为是雇主用员工自己挣的小费，去抵掉本该由雇主承担的那部分工资义务。</p><p>不过呢，如果员工当周的现金工资加上实际收到的小费，总共并没有达到每小时 7.25 美元的话，雇主就得补足这个差额。</p><p>1996 年之前，2.13 美元这个数字还是当时联邦最低工资的一半。到了 1996 年，该机制被《公平劳动标准法》改成了固定的 2.13，意味着无论未来联邦最低工资变多高，小费员工的最低现金工资还是这么低。每次上涨也只是让雇主可以合法抵扣的小费信用额度越来越高而已。</p><p>按理来说，当雇主错误预测了客流，安排了过多的员工上班，那么要承担该错误判断的是雇主，他要支付给多余员工的工资。</p><p>但如果是小费员工的话，就不用担心这一点了。无论雇主判断失误不失误，多安排小费员工上班，他的直接现金支出上限依然是在 2.13 到 7.25 美元之间。如果生意差，每个人封顶每小时 7.25 美元；如果生意好，雇主最少仅需要支付每小时 2.13 美元。</p><p>所以雇主如何排班、生意好或者坏，他的支出波动幅度远没有小费员工的实际到手收入的大。这些成本则由当天上班的小费员工承担，因为最低收入是每小时 7.25 美元，生意不好就只能拿这么多了。</p><p>而零工经济下的 Uber 或者 Lyft 司机，要更悲惨：首先，司机能否接到单、单子多少钱，是由公司的算法决定的；其次，算法会通过 <u>算法工资歧视</u> 来惩罚总是拒绝低价单的司机；再者，Uber 利用了信息不对称，将司机的时薪包装成高于最低工资的样子，还利用算法计算出乘客愿意支付的最高价、反过来割乘客的韭菜。</p><p>文章中引用的 David Weil 认为，所谓「灵活性」本来就可以在不转嫁风险的前提下提供给司机，Uber 没有这么做是别有用心。即便去强制 Uber 支付最低工资，他们也会利用其他漏洞。</p><p>记忆里，我有位校友就有做过司机软件的作弊工具。内容应该也和文章中提到的那样，可以比对不同平台的报价吧。但是反规避法可是告诉了我们「修改自己手机上运行的 app 是违法的」。</p><p>过去美国强迫其他国家将反规避法写入国内法，否则就加关税。现在 Trump 不管三七二十一，见谁就全面加征关税。我现在在办公室的电梯间看电视，上面每天也是展示今儿谁被 Trump 加了关税 —— 倒不如说这个家伙儿怎么还在加啊…… 有毛病。既然关税无论如何都会被加，那干脆就不要把反规避法写到国内法去了啊。本来该法律也只是在保护美国的科技或内容公司的利益。</p><p><a id="为什么美国的救护车费用如此昂贵"></a></p><h4 id="为什么美国的救护车费用如此昂贵"><a class="markdownIt-Anchor" href="#为什么美国的救护车费用如此昂贵"></a> <a href="https://davidoks.blog/p/why-american-ambulance-rides-are">《为什么美国的救护车费用如此昂贵》</a></h4><p>我想读者朋友们应该都听说过美国的救护车叫不得，叫了会让人破产。我也不敢叫救护车，因为真的会让人破产。</p><p>David Oks 指出，救护车服务卖出的其实是「随时待命」这件事。保险、消防局等也是这个套路 —— 我想到另一个 Oks 没有提到的，那就是 24 / 7 待命的锁匠 —— 这叫作贩售期权，成本都是花在「保持随时待命」上。</p><p>顺带一提，想要靠开源和自由软件赚钱的读者朋友们，也可以学诸如 Red Hat 的方式，出售「随时待命」这个服务。我都天天盯着你的服务器看了，还不赶紧给我钱！</p><p>正常情况下，这类服务应该是像保险一样运作的，即向所有享受这份保障的人收一笔小额的费用，用来支付成本，这样每个人只需要负担一点点钱。但美国的救护车系统不是这样运作的。</p><p>这一切要说回 Medicare 和 Medicaid 被创立的 1965 年。在这之前，救护车长期由殡仪馆提供，因为正好有适合的车型，殡仪馆本身也是 24 / 7 待命的。出救护车还能给自己的殡葬生意引流（听上去很奇怪真的……），相当于顺路载个（可能）将死之人。</p><p>1965 年，美国政府简单将救护车运输设定成「每次出车按程序收费、事后报销」的模式，但同个时期，各个革命性的技术让救护车摇身一变、变成了可以真正救命的移动医疗单位，固定成本也随此飙升。</p><p>好笑的是，支付方式完全没有变化。就算没有使用救护车上昂贵的设备，事后依然要「按程序」支付救护车的「基础费率」。</p><p>因为保险不同，每个使用救护车的人最终都要支付不同的账单。比如 Medicare 和 Medicaid 患者，找他们收取差价是违法的；而私保患者，会因为救护车公司不属于任何保险网络，而悲痛交钱。</p><h2 id="远方"><a class="markdownIt-Anchor" href="#远方"></a> 远方</h2><p><a id="你的人工智能并非工具"></a></p><h4 id="你的人工智能并非工具"><a class="markdownIt-Anchor" href="#你的人工智能并非工具"></a> <a href="https://theconvivialsociety.substack.com/p/your-ai-is-not-a-tool">《你的人工智能并非工具》</a></h4><blockquote><p>But AI is not a tool in this sense, it is an environment which envelops the user and works on us from the inside out while we naively think that we remain unchanged by our use so long as we are using it carefully and intentionally. The care and intentionality is beside the point, and our confidence in such vigilance probably works against us in the long run.</p><p>但人工智能并非这种意义上的工具，而是一个包围用户的环境。它从内而外地影响着我们，而我们却天真地认为，只要谨慎且有意识地使用，自己就不会被改变。这种谨慎和主观意图其实无关紧要，而我们对这种警觉性的信心，从长远来看可能反而对我们不利。</p></blockquote><p>我有使用 AI 工具来工作。这种感受确实存在。</p><p>好在我的计算机基础不是它「教」的，所以对于很多事情，我能够做出更好的判断。不过并没有那么熟悉的领域，我往往是将决策交给 AI 工具帮助我整理。</p><p>不论是计划、问题、方案，还是选项之间的优缺点，AI 工具都能整理出来。但我要如何知道它们是真是假呢？</p><p>尽管给它装上更多的工具、补丁，它出错的概率依然不小。如果没有该领域的知识和理解的话，人根本没法搞明白 AI 工具说的是真话还是假话。一味去依赖它，就会引向文章中说的：</p><blockquote><p>……what tools do to our perception rather than what we can do with them, to look at how tools shape our mind, how their use shapes our perception of reality, rather than how we shape reality by applying or using them.</p><p>工具对我们的感知产生了什么影响，而不是我们能用它们做什么；去观察工具如何塑造我们的思想，它们的使用如何塑造我们对现实的感知，而不是我们如何通过应用或使用它们来塑造现实。</p></blockquote><p><a id="为什么说-anthropic-是邪恶的"></a></p><h4 id="为什么说-anthropic-是邪恶的"><a class="markdownIt-Anchor" href="#为什么说-anthropic-是邪恶的"></a> <a href="https://1q43.blog/post/12498/">《为什么说 Anthropic 是邪恶的？》</a></h4><p>上个月底到这个月初，Claude Code 被逆向发现存在着疑似标记用户是否是中国人的代码。</p><p>说实话我不是很理解 Anthropic 为什么要如此大费周章去验证用户是否是中国人。相比之下，OpenAI 那边的策略简直是小儿科。</p><p>因为 Fable-5 的发布，想要使用 Claude 模型的中国用户也变多了。大家都想要尝尝鲜，这也包括我远在中国的委托人大人。当时我想出来的合规的解决方案围绕着「被总部位于不支持地区（中国）的公司直接或间接持股超过 50% 的实体」这个条款，结果没过多久就被曝出 Ants Group 已经在用同样的方案、在新加坡开了个实体。</p><p>如果有读者朋友真的很想要使用 Anthropic 的模型的话，可以考虑这几个方案：</p><ol><li>使用中转，但是风险很高。中转站的流量还是挺容易发现的，再加上无良中转站也多，毕竟是又一个中心</li><li>注册一大堆账号，封禁一个换一个。听着就累人</li><li>听天由命，希望 Anthropic 发现不了你，成为万里挑一的幸运儿吧！</li><li>用开发机，SSH 连接上去，永远不要在自己的机器上使用 Claude Code 和 Claude 模型</li></ol><p>现在也有了更强大、价格更便宜的 GPT 5.6。说实话 Claude 模型是否真的那么不可替代，我得打个问号了。我的部分项目，交给 Deepseek 也能做，顶多是需要更多的精力去让它搞清楚需求是什么、该怎么做，而这恰恰是使用 aigent 的正确方式。Claude 的最新模型，最直观的进步便是它更容易从用户破碎的语言里整理出需求。另一个变化是主观性极强。我不愿意称其为「进步」，是因为主观性过强容易导致判断失误。但有时候不想动脑子，就会觉得这是个优点 —— 不过每次维护都在哭为啥自己不动脑子、轻易将操控权交给了 AI 工具。</p><p>唉很可惜，我数个月前买了 Anthropic 的 Pro 年费，所以得用完这一年才能摆脱它。上个月它还更新隐私政策、引入 Yoti 来合理获取用户的身份证件。</p><p><a id="我后悔迁移到-codeberg"></a></p><h4 id="我后悔迁移到-codeberg"><a class="markdownIt-Anchor" href="#我后悔迁移到-codeberg"></a> <a href="https://xn--gckvb8fzb.com/i-regret-migrating-to-codeberg/">《我后悔迁移到 Codeberg》</a></h4><p>该博客网站我过去就有所听闻。域名是日文耶，并且开头有个 banner 写说「请禁用 JavaScript」。我还尚未打算「迁移」到该习惯，因为我很清楚，一旦我那么做了，接下来我会花费很多时间和精力去处理「禁用 JavaScript」相关的事情。</p><p>网站设计非常有趣，不知道 マリウス 是博客的名字，还是作者的身份？不过时不时一闪一闪的黄色亮点让我有些不适。</p><p>回到文章本身吧。</p><p>Codeberg 由非营利组织运营，并以提倡自由开源闻名，一度是 GitHub 这个被 Microsoft 病毒污染的代码托管平台的对立面。</p><p>我在刚开始深入了解自由和开源软件概念时，就听说过 Codeberg，但没有实际使用过。</p><p>今年 Codeberg 更新了服务条款，明确禁止了两类项目：</p><ol><li>由 LLM 驱动的项目</li><li>加密货币项目</li></ol><p>关于第一条，Codeberg 发了个 <a href="https://blog.codeberg.org/protecting-our-floss-commons-from-llms.html">公告</a>，表示 vide coders 的周围并没有真正的社区和用户，却在不断浪费 Codeberg 的资源，因此要被禁止。</p><p>作者指出，绝大多数自由软件项目本就是独立开发者的自给自足 —— 这一点在《教堂与大集市》中也有提到过：「所有好的软件都源于开发人员要解决自己的切身之痛」。如果重点在于「没有真正的社区和用户」，那是不是去掉 <em> LLM</em> 也成立呢？</p><p>不过根据 <a href="https://www.geedea.pro/weekly/91/#:~:text=%E4%B8%8D%E8%BF%87%E5%80%BC%E5%BE%97%E4%B8%80%E6%8F%90%E7%9A%84%E6%98%AF%EF%BC%8C%E9%82%A3%E4%BA%9B%E4%B8%8D%E5%A4%AA%E8%83%BD%E6%89%BE%E5%88%B0%E7%A4%BE%E7%BE%A4%E7%9A%84%E4%B8%AA%E4%BA%BA%E7%9A%84%E5%B0%8F%E9%A1%B9%E7%9B%AE%EF%BC%8C%E5%8D%B3%E4%BE%BF%E4%B8%8D%E6%98%AF%20LLM%20%E5%86%99%E7%9A%84%EF%BC%8C%E5%AE%9E%E9%99%85%E4%B8%8A%E4%B9%9F%E4%B8%8D%E8%AF%A5%E6%89%98%E7%AE%A1%E5%88%B0%20Codeberg%20%E4%B8%8A%EF%BC%8C%E5%8F%AA%E4%B8%8D%E8%BF%87%E5%8F%AA%E8%A6%81%E8%B5%84%E6%BA%90%E6%B6%88%E8%80%97%E4%B8%8D%E5%A4%AA%E9%AB%98%EF%BC%8CCodeberg%20%E5%8F%AF%E4%BB%A5%E5%AE%B9%E5%BF%8D%E3%80%82">Eltrac 的说法</a>，没有用户的个人小项目确实也不该托管到 Codeberg 上。</p><p>LLM 带来的问题我想我也不用一一列举。我仅是觉得 Codeberg 的措辞模糊，可以写得更精确。</p><p>而第二条的「加密货币项目」到底指的是什么、为什么损害了 Codeberg 的声誉，Codeberg 并没有做出完整的解释。这一部分可以见 <a href="https://chlo.is/the-universal-morality/">Chlorine 的文章</a>。</p><p>作者认为 Codeberg 决定项目留存的标准已然变成了「该项目是否符合自己的价值观」。</p><p>那么平台到底能否仅把服务提供给符合自己价值观的用户呢？</p><p>从法律的角度来看，即便 Codeberg 是非营利组织，它也拥有完全的排他性控制权，也就是有权定义自己的服务条款（Terms of Service，简称 ToS），并据此挑选用户。</p><p>Codeberg 也存在着成本问题，我理解它为什么要禁止不符合自己价值观的项目。Codeberg 宣称自己是自由的没错，但不能因为「自由」、无视成本问题且强求 Codeberg 向所有项目开放。优先将资源投入给捐赠者认可的项目，无可厚非 —— 你要先活下去！</p><p>要想在他人控制的设施上实现（自己想要的）自由，本就是困难的。最建议的做法是走向真正的去中心化，即自己购买服务器并建立托管服务。</p><p>为了否认 Codeberg 的做法，文章中提到了 Linus Torvalds 的那封邮件 —— 我不认可这种做法。Torvalds 说的话就一定是正确的吗？ 我对他的认知是一个商业兼开源的受益人。他的成功建立在与大企业的实用主义妥协之上。一个工程实用主义者的想法，不意味着作为托管平台的 Codeberg 也得效仿。问题应当被集中在「平台是否有权以价值观为由、一刀切地剥夺用户的选择权」，以及「这种剥夺是否破坏了其宣称的自由」。</p><p>顺带一提 Torvalds 的邮件本来也要放到该月刊里来了，不过因为我开始捣鼓回应类文章，所以去掉了。</p><p>至于禁止内容究竟是不是解决问题的出路，我很难说明我的想法，毕竟我根本不使用 Codeberg。文章结尾作者就 Codeberg 的资源和成本问题，提出了一些解决方案，有兴趣的可以看看。</p><p><a id="身为软件工程师的疯狂之处"></a></p><h4 id="身为软件工程师的疯狂之处"><a class="markdownIt-Anchor" href="#身为软件工程师的疯狂之处"></a> <a href="https://0x1.pt/2025/04/06/the-insanity-of-being-a-software-engineer/">《身为软件工程师的疯狂之处》</a></h4><p>公司里的软件工程师总是要追逐全新的技术栈。以前是各种编程语言、框架，现在则是 LLM 的花样补丁。</p><p>我也好奇为啥，公司里实际上都会要求一个人掌握多项技能、成为全栈工程师，但对外依然说自己想要某某领域的专才？</p><p>我一位在大厂工作的朋友，不仅要管项目、管队友、管内容是「如何管理好他自己」的会议，还要包办公司的 AI 工具项目。他跟我说，这是为了在开会时能有话语权。</p><p>软件工程师的行业到底为何会变成这样？我也不知道。</p><p><a id="博客是如何破坏网络的"></a></p><h4 id="博客是如何破坏网络的"><a class="markdownIt-Anchor" href="#博客是如何破坏网络的"></a> <a href="https://stackingthebricks.com/how-blogs-broke-the-web/">《博客是如何破坏网络的》</a></h4><p>我第一次上网是在 2010 年，那时候我 6 岁，在玩 QQ 农场和牧场，还有《洛克王国》。我会和同样玩 QQ 的年轻亲戚们说「GG 和 MM」，然后就没有然后了。我没有想要了解计算机和网络是如何运作的，事实是，我真正踏入个人网络的世界是去年下旬的事情。</p><p>应该是 2022 年还是 2023 年，我用 Hexo 生成了个静态网页，然后用 GitHub Pages 托管在了网上。但我完全不在意个人博客到底是什么，只是在里面塞入技术文档、技术文章、根本不是教程的教程，还有笔记。</p><p>个人博客的概念要比个人主页的概念更早来到我的宇宙中。</p><p>个人博客和内容管理系统（CMS）的出现，意味着人们不再手动维护个人主页，并且要随着大众去写可能不适合自己的文章、信息流 —— 这一点是我从未试想过的。</p><p>我的主站（试试仅访问 <code>cytrogen.icu</code>）是个人主页。我还在缓慢更新中。</p><h2 id="周遭"><a class="markdownIt-Anchor" href="#周遭"></a> 周遭</h2><p><a id="要不要给作者买咖啡"></a></p><h4 id="要不要给作者买咖啡"><a class="markdownIt-Anchor" href="#要不要给作者买咖啡"></a> <a href="https://taxodium.ink/53.html#:~:text=%E8%A6%81%E4%B8%8D%E8%A6%81%E7%B5%A6%E4%BD%9C%E8%80%85%E8%B2%B7%E5%92%96%E5%95%A1">《要不要给作者买咖啡？》</a></h4><p>这个是 Spike 在 Zine #53 里讨论的话题。</p><p>在许多个人网站中，你会看到 <em> Buy me a coffee</em> 这样的按钮。点进去，你会被导航到赞助页面。</p><p>话题的起因是，Hakkerman 表示自己非常反感这种做法。这里就不挂链接了，因为你可以去引用的链接里找到 —— 什么！你说你都不读引用的链接！</p><p>我的博客站点是不打算放赞助链接或者页面的。虽然我自己有 ko-fi 账户，但那个只是用来跟别人换钱用的。现在我连账号和密码都记得不太清楚了。</p><p>我不喜欢被别人赞助的感觉，因为我总会想要去回报对方、顺应对方的想法。类似于把赞助方当成股东来看待。毕竟，这是免费的钱啊！</p><p>但是，我也不喜欢赞助他人，因为我很抠门。我前几个月「大发慈悲」给 Wikipedia 赞助，结果发现被赞助方其实是背后的基金会。就算只有 3 美元，我也气得要死，在博客上说了他们好几回。所以说我实在是个铁公鸡。在地铁站听到好听的演奏，也不曾停留并给出钱包里多到塞不下的一块钱。</p><p>再就是花钱以表达感谢和喜欢，我会觉得很奇怪。有点像给红包？给红包意味着需要一来一回、欠对方人情、孔融让梨…… 为了避免让自己陷入到这种焦虑中，直接逃避会更方便一些。</p><p><a id="你的-app-本可以是一个网页-所以我帮你修好了"></a></p><h4 id="你的"><a class="markdownIt-Anchor" href="#你的"></a> <a href="https://danq.me/2026/07/09/your-app-could-have-been-a-webpage/">《你的 <em>App</em> 本可以是一个网页（所以我帮你修好了……）》</a></h4><p>我也不理解，为什么我们必须要安装 app，才能访问些明明用网页或者其他方式也能访问的数据。</p><p>去年十二年我便开始「<a href="/posts/9572.html">去 app 化</a>」。当时我还在用主流网站的 PWA，现在倒是连 PWA 都不要了，干脆不访问它们，或者仅在浏览器内访问。现在我手机首页上的图标，除了每天都要打开的 Masto-FE 外，就没有其他 PWA 了。</p><p>话说我是不是应该把博客网站的搜索功能弄回来了？随着月刊数量的增加，我找过去的文章也变得不方便了起来 —— 不对，我怎么记得 Org Mode 可以做到这一点？哎呀，算了算了，之后再说吧！</p><p>Dan Q 倒是更极客些，他直接拦截了必须要使用但又看不惯的垃圾 app 的流量，做成了网页。</p><p>我允许部分软件以 app 的形式出现在我的设备内。我就拿 Kagi 的软件来做例子好了：我会同时使用 Kagi Translate 的网页版本和 app 版本，因为前者提供测试版的网页翻译，而后者安装后，我的手机长按文字时都能在菜单中看到 Kagi 的翻译选项；Kagi Small Web 我就不会使用 app 版本，因为网页版本足矣，Kagi News 同理。</p><p>较为悲伤的是，我这个 Motorola 手机和 Google 强绑定了，导致我无法卸载 Chrome、YouTube，甚至是 YouTube Music 这样的 app…… 我总有一天要换成能刷系统的手机，这个折叠屏手机实在是没人花时间折腾。</p><p>我在开发一个项目时，上头也提到过想要弄个 app—— 但是为啥呢？这个项目有必要弄成个 app 吗？你就算让我来做，我也只会嫌麻烦地将已有的网页代码迁移到 React Native 去。更何况上架应用商店还要钱、移动端的网页可以正常运行。</p><p><a id="我为什么不再与人争论"></a></p><h4 id="我为什么不再与人争论"><a class="markdownIt-Anchor" href="#我为什么不再与人争论"></a> <a href="https://wangcong.org/2026-06-30-why-i-stopped-arguing-with-people.html">《我为什么不再与人争论》</a></h4><blockquote><p>有无相生，难易相成，长短相形，高下相倾，音声相和，前后相随，恒也。</p></blockquote><p>老子在《道德经》中提到，任何「对」都是相对于「错」才成立的。</p><p>因此和人争论对错、纠正他人，已经是将自己放置于道德或者逻辑的高地，也将对方放在了低地。赢家的对立，也一定是有一个输家。所以这不是件善事儿。</p><p>先前在 Fediverse 上看到有 Fedi 友指出了个有趣的现象，那就是当有人发了个 toot，内容是错的话，往往不会有人回复并纠正，而是会转发该 toot，接着在新的 toot 里写回复，或者引用 toot。这些做法原作者都是看不到的，除非点进回复者的主页。</p><p>这么做也是种互利互惠的方法。毕竟绝对不会引起纠纷。上述的两种方法，不会强求原作者回复，更多是「我看到观点甲后，想要表达观点乙」。更何况观点乙讲给支持观点甲的人听，只会让对方想要争论回来啦，还不如讲给自己的粉丝听。</p><p>不过思索着 Fediverse 这个地方该说是太礼貌了吗，还是我的时间线养得很好？鲜少看到争论，更多是自说自话。我在 Fediverse 里也是天天自言自语。</p><hr><p>好吧，我这里说错了一件事：引用和写 <em> RE:</em> 是可以引起纠纷的，比如 Twitter 的引用功能被大肆用于网络暴力行为。毕竟原作者又看不到谁引用了自己。如果评论者怀抱着恶意来说原作者，后者根本不知道。而公开的恶意可以被其他刷到的用户看到，进而加入到网络暴力之中。</p><p><a id="在毒瘾-牢狱和重罪之后从零开始"></a></p><h4 id="在毒瘾-牢狱和重罪之后从零开始"><a class="markdownIt-Anchor" href="#在毒瘾-牢狱和重罪之后从零开始"></a> <a href="https://gavinray97.github.io/blog/building-from-zero-after-addiction-prison-felony">《在毒瘾、牢狱和重罪之后从零开始》</a></h4><p>作者 Gavin Ray 14 岁因贩卖处方药被判了 17 项重罪指控，因此被送去科罗拉多最高安全级别少年监狱服刑两年。</p><p>出狱后，他短暂戒断但又复吸，18-19 岁再次因毒品罪入狱并正式成为重罪犯。</p><p>神奇的是，这期间他靠一篇报纸报道拿到了科技公司的实习机会，得以自学成为全栈开发者。</p><p>后来，他又两次因复吸而导致失业，最终在妻子独自扛起家计的支撑下彻底戒断、送出数百份简历，直到迈阿密一家创业公司录用他。工作期间，他接触并深度参与了开源项目 Hasura 而被挖角，如今在该公司内长期从事自己热爱的开发者工具工作。</p><p>文章中引用的报道，讲的其实是美国本土「再培训科技工人」的浪潮。当时 Trump 第一次当选总统，搞了什么「美国优先」，要削减 H - 1B 等外籍工签的项目。这意味着在当时，美国企业会因为没有外籍劳动力，而不得不去培养本土人才。</p><p>Ray 去的 Techtonic Academy 只会招处境不利的青少年、少数族裔、女性和退伍军人，尝试改善科技行业的多样性问题。</p><p>青少年贩毒的事情，往往都会和「没有前途」、「这辈子毁了」等评价挂钩。正因为社会都这么想，冲动犯了错的青少年也会这么觉得，然后一错再错，反正自己的未来已经「毁掉了」。</p><p>现在社会主流的观念依然是「不要碰毒品」，却没有主流说法告诉已经碰了毒品后的人怎么办。不停去强调毒品的可怕，虽也可以避免人们去接触，但也会让已经接触的人不再怀抱希望。物极必反，该如何正确地宣传真是件难事。</p><p><a id="处理-dickover"></a></p><h4 id="处理"><a class="markdownIt-Anchor" href="#处理"></a> <a href="https://pluralistic.net/2026/07/21/dickovers/">《处理 <em>dickover</em> 》</a></h4><p>我忽然意识到，Pluralistic 这个网站，该不会是日刊吧……？是不是太后知后觉了呢？</p><p>今年五月份，John Gruber「发明」了新术语，叫作 <em> dickover</em>，意思是：</p><blockquote><p>a modal panel, popover, or curtain presented by a website or app, deliberately obscuring its own content to frustrate the user with an unwanted, unnecessary, mandatory interaction; e.g. asking the user to accept "cookies", subscribe to a newsletter, install the website's mobile app, agree to terms of service, or anything else that the user couldn't give two shits about.</p><p>网站或应用程序呈现的模态面板、弹出框或遮罩层，故意遮挡其自身内容，以一种不必要的、强制性的、令人反感的交互来挫败用户；例如要求用户接受 <em> cookies</em>、订阅新闻通讯、安装该网站的移动应用程序、同意服务条款，或者任何用户根本不在乎的破事。</p></blockquote><p>我不知道该如何翻译它…… 它和 <em> vibe coding</em> 有些相似，我会产生直接使用原文就好了的想法。</p><p>Cory Doctorow 先生在文章中聊了聊如何处理 dickover，例如放弃使用 Chrome，可以转向使用 Firefox—— 不过 Firefox 自己的隐私性也令人质疑。总之，他建议多使用 Firefox 的阅读模式、尝试 Kill Sticky 等书签或者插件。</p><p>他也说道：</p><blockquote><p>we have a duty and obligation to the people we love to show them how to seize the means of computation. The normies in your life need the tips and tricks I lay out in this article more than anyone. Sure, it takes some doing to install Firefox, Kill Sticky, Adblock Plus and Bypass Paywalls; it takes a minute to figure out Reader Mode.</p><p>我们对所爱的人有责任和义务，向他们展示如何夺取计算手段。你生活中的普通人比任何人都更需要我在本文中列出的技巧和窍门。当然，安装 Firefox、Kill Sticky、Adblock Plus 和 Bypass Paywalls 需要一些功夫；弄清楚阅读模式也需要一点时间。</p><p>But if you install these tools for the people you love and show them how to use them (or just reconfigure the sites they visit most frequently to block dickovers and other annoyances), you will <em>permanently</em> improve their internet experience, clawing back <em>hours</em> of annoyances every week, while also protecting their privacy.</p><p>但如果你为你爱的人安装这些工具并教他们如何使用（或者只是重新配置他们最常访问的网站以拦截混蛋弹窗和其他干扰），你将 <span class="emphasis">永久性</span> 地改善他们的互联网体验，每周夺回 <span class="emphasis">数小时</span> 的烦恼时间，同时还能保护他们的隐私。</p><p>Anyone who is confused by switching to Firefox is <em>also</em> going to be confused by the deceptive language and practices that go along with dickovers. By leaving your unsophisticated loved ones exposed to dickovers, you're not decreasing the amount of technological confusion they're likely to experience in a day – you're <em>vastly increasing</em> the amount of danger they face as a result of that confusion.</p><p>任何对切换到 Firefox 感到困惑的人，<span class="emphasis">同样</span> 也会对伴随混蛋弹窗而来的欺骗性语言和做法感到困惑。通过让你那些不懂技术的亲人暴露在混蛋弹窗面前，你并没有减少他们在一天中可能经历的技术困惑量 —— 你反而 <span class="emphasis">极大地增加</span> 了他们因这种困惑而面临的危险量。</p></blockquote><p>和我初次认识到他的 <a href="/posts/c089.html#%E5%90%8E%E7%BE%8E%E5%9B%BD%E4%BA%92%E8%81%94%E7%BD%91">那场演讲</a> 中提到的类似，他也觉得一方的混乱代表着另一方的生机：「后美国互联网」那场演讲里，他指的混乱是 Trump 乱搞事，而生机指的是其他国家不再遵守美国的反规避法；这篇文章里，混乱是「AI 公司对内存市场的非法垄断导致新电脑、内存和存储的价格飙升」，生机则是「人们应使用消耗资源更少的自由和开源软件或者操作系统」。</p><p><a id="或许数羊真是个有效的入睡法"></a></p><h4 id="或许数羊真是个有效的入睡法"><a class="markdownIt-Anchor" href="#或许数羊真是个有效的入睡法"></a> <a href="https://blog.est.im/2026/stderr-23">《或许「数羊」真是个有效的入睡法》</a></h4><blockquote><p>然后突然发现一个被大多数人忽略的惊人的事实：放牧人的白天是极度无聊和空虚的，以至于他 / 她们能辨识自己每一头羊的特征、性别，甚至给每头羊起个名字。视频说牦牛和人一样，每一头都有独一无二的毛色、长相、形态等。</p><p>脸上有点黑？叫小黑；黑白相间的？叫花脸。按脾气起名字，暴躁哥，温顺妹；还有谁和谁喜欢一起吃草，小牛的母牛妈妈是谁等等。</p><p>所以这两件事就串起来了。「数羊」这事儿一定是牧区的人发明出来的，比如英国乡下，但是城里人哪里知道这些细节啊。</p><p>牧民晚上躺床上，没事干，说不定就给自己牛羊编故事造剧情啊。而且关键词是「数」，你不能陷入一个逻辑推理细节，必须不停地轮换，把羊变成高频切换的具象个体（有名字、有外形、有性格），才能保证大脑疲惫然后入睡。</p></blockquote><p>惊了，从未考虑过的角度。</p><p><a id="我们应该优化掉什么"></a></p><h4 id="我们应该优化掉什么"><a class="markdownIt-Anchor" href="#我们应该优化掉什么"></a> <a href="https://www.autodidacts.io/holistic-optimization/">《我们应该优化掉什么？》</a></h4><p>装了洗碗机，省下的时间并不会让你更闲，因为你会开始用更多盘子。这和让 AI 工具写代码一样。</p><p>Curiositry 想到，有些苦是有价值的。比如劈柴，虽然我还没有劈过，不过他认为是锻炼的一种。如果花钱请人劈柴，自己又花钱去健身房撸铁，不就本末倒置了？</p><p>所以不能不带脑子优化身边的一切，有些事情本身就可以塑造我们的韧性。</p><p><a id="你的大脑天生就不是用来承受这么多坏消息的"></a></p><h4 id="你的大脑天生就不是用来承受这么多坏消息的"><a class="markdownIt-Anchor" href="#你的大脑天生就不是用来承受这么多坏消息的"></a> <a href="https://www.sciencedaily.com/releases/2026/06/260614012006.htm">《你的大脑天生就不是用来承受这么多坏消息的》</a></h4><p>去年 Reuters Institute 报告说，全球有 40% 的人在有意回避新闻，已经创下了历史新高。原因是，新闻让人们的心情变差，并感到无力，自然而然会想要去回避它。</p><p>比起正面信息，人类的大脑要对威胁更加敏感，且记忆更持久、反应更快速。然而现在的新闻会报道很多事情，尤其爱用负面的标题。人就算看了，就算和自己没有直接的关联，也会起反应。</p><p>对于少数族裔来说，看新闻就更痛苦了。拿我自己作为例子，我上新闻看到「亚裔」、「中国」这些字眼，就没有几次是好事情：要不然是这个被无差别杀掉，要不然是中国政府又怎么了，现在在公共场合听到别人说 <em> China</em> 我都要抖三抖 —— 当然有夸张成分在，但总是被负面的新闻包围，实在是没什么精神。</p><p>我现在除了通过订阅的个人博客那儿吸收信息，就是从 Hacker News、BiliBili、Fediverse，还有 Kagi News 上吸收了。其中最容易让我产生不适的，其实是 BiliBili。推荐算法还是更懂如何让我感到不适，现在我只要进入该 app，都会直接点到关注列表的视频处，避免看到首页上各种推荐。还有关闭弹幕！</p><p><a id="人与博客"></a></p><h4 id="人与博客"><a class="markdownIt-Anchor" href="#人与博客"></a> <a href="https://zacharykai.net/notes/pb">《人与博客》</a></h4><p><a href="https://manuelmoreale.com/about">Manuel Moreale</a> 创办了 <em> People and Blog</em> 系列。该系列每周会采访一个博客站主，问题大致如下：</p><ol><li>能介绍一下自己吗？</li><li>你的博客站点是否有什么不为人知的故事？</li><li>在写博客时，你的创作过程是怎样的？</li><li>你有理想的创作环境吗？</li><li>你认为物理空间会影响你的创造力吗？</li><li>能介绍一下博客所使用的技术栈吗？</li><li>如果你今天要开始写博客，你会试些新东西吗？</li><li>运营你的博客需要多少成本？</li><li>它仅仅是一项支出，还是能产生一些收入？</li><li>你对个人博客变现持什么立场？</li><li>你觉得有什么博客值得一看吗？</li><li>你觉得我接下来应该采访谁？</li><li>最后，你有什么想和我们分享的吗？</li></ol><p>现在系列被转交给 <a href="https://zacharykai.net/">Zachary Kai</a> 了。</p><p>我没有打算去效仿该系列的做法，因为我实际认识的个人博客站主并不算多。分享一下，说不定会有读者朋友感兴趣、想弄个中文独立博客版本的出来。</p><p><a id="凡事平常心"></a></p><h4 id="凡事平常心"><a class="markdownIt-Anchor" href="#凡事平常心"></a> <a href="https://www.joanwestenberg.com/p/just-be-normal-about-st">《凡事平常心》</a></h4><blockquote><p>Part of the problem is that "taking it too far" is highly legible, in a way that moderation simply isn't. Extremism photographs and posts well. It gives people a script, and it creates instant belonging. If you're "all in" on something, anything, people know what to do with you.</p><p>问题在于，「走极端」是非常显眼的，而适度则不然。极端主义非常适合拍照和发帖。它给人一套剧本，并创造瞬间的归属感。如果你对某件事「全身心投入」，无论那是什么，人们就知道该如何对待你。</p></blockquote><p>身份问题是人类一直以来的难题。我们要在社群中寻求归属感、安全感，于是走极端以清楚地辨识出「内」和「外」。</p><p>凡事平常心就好。不完美的、平庸的，都无所谓。不过我也想到，遵守平常心能不能也异变成极端的一种？一定要中庸、不能偏离「平常心」什么的。</p><p><a id="我希望人们能更加公开透明"></a></p><h4 id="我希望人们能更加公开透明"><a class="markdownIt-Anchor" href="#我希望人们能更加公开透明"></a> <a href="https://borretti.me/article/i-wish-people-were-more-public">《我希望人们能更加公开透明》</a></h4><p>作者 Fernando Borretti 反对当下流行的「回归私人生活」热潮，并提倡人们多多公开化自己的生活、学习与创造过程。</p><p>我很赞同他说的，公开写作以吸引志同道合者的观点。有时也不用写过于深刻的道理，单是简单的观察，就足以让读者朋友们惊呼：「<a href="https://blog.jim-nielsen.com/2026/blogging-stating-the-obvious/">对！就是这个！</a>」</p><p>不过其他的观点，我就不赞同了。首先是作者将训练 AI 模型用的数据视为公共知识库、我们写的东西都可以为其共享力量。但是市面上绝大多数的模型，训练起来都是科技巨头无偿无许可找互联网上的语料搜刮来训练的。站主们无偿向公共空间注入的优质内容，却被他们拿来私有化、封装成付费的服务，真是可笑。</p><p>其次是「如果不公之于众的话，那么事情就没有发生」这个观点。但记录和公开是两码事。为了让未来的自己能记住自己做过什么，使用仅私人能查看的日记本就能做到。公开自己做过的事情，而不是写进私人日记本，一定是被某个因素推动。因此，我不认可该观点。</p><p>我过去也有写仅私人查看的日记的习惯。比如早期的月刊的内容，都是我先写到日记里，然后从中摘选了我愿意公开的片段，再写到月刊内。现在为了图方便，改成直接写到 Fediverse 的软件里、默认公开，然后用脚本爬取到月刊内。</p><p>两者对我来说最大的区别，就是我写的内容会有关注我的 Fedi 友实时提供反馈。于是，社交的因素也被考虑在其中。但要说因为没有公开所以事情没有发生，就是过分夸大外部的视角了。</p><p>最后是社会工程学问题：公开太多，会不会有个人隐私和安全的问题？一旦有人真的想要找到我，那他们完全可以根据我公开的信息、图片推断出我是谁、我在哪里、我长什么样。</p><p><a id="我的博客文章写作灵感清单"></a></p><h4 id="我的博客文章写作灵感清单"><a class="markdownIt-Anchor" href="#我的博客文章写作灵感清单"></a> <a href="https://taonaw.com/2026/06/29/my-inspiration-checklist-for-writing.html">《我的博客文章写作灵感清单》</a></h4><p>我也说说我的灵感是从哪里来的吧…… 但我更新文章也没有那么勤，何来这种说法！</p><p>先比对一下作者的维护清单。首先我没有看网站分析数据的习惯，因为我刻意让自己不去在乎那些数字。</p><p>作者的「那年今日」流程很有趣，值得参考。正好已经要到我写月刊的一周年了，我的第一篇月刊是在去年十月份发布的，不过实际是算九月的月刊。今年九月份的月刊，完全可以写一个「那年今月」的板块。</p><p>再是我没有使用书签来收藏链接的习惯。我只会收藏有用的工具和平台，意味着我未来会频繁点进它。我收藏博客文章链接的方式是用 Instapaper。这是个在 Kobo 上也能使用的软件，可以同步链接内容，然后阅读、归档、表达喜欢或者不喜欢。</p><p>其次是作者的灵感来源清单。我有个爬取这个月我在 Fediverse 上发了什么的 <a href="https://gtsm.cytrogen.icu/">网站</a>。时不时我会查看一下，看看哪个话题我说了很多、值得整理成一篇文章，亦或者是又对没有深入的话题产生了兴趣，于是另写一篇文章。</p><p>同样的，Fediverse 上大家说的内容也会被我捕捉到，并产生好奇心。</p><p>RSS 阅读上，我用程序为自己生成了日报，每天只用看日报即可。</p><p>有时我会使用 Hacker News 和 Kagi Small Web。前者并不一定会找到我感兴趣的内容，而后者我的想法和作者一致，里面有太多企业博客了。</p><p>这个月我非常依赖于 RSS 日报，而近乎没有使用过 Hacker News 和 Kagi Small Web，所以本次月刊的很多链接都是我已经订阅过的博客站主所写的。</p><p>最后我的写作灵感是…… 灵机一动。我有很多「忽然想到」的时刻，有些会被我搁置，有些会被我立即拿来研究和实验。</p><p><a id="你的-rss-阅读器正在剥夺你的体验"></a></p><h4 id="你的-rss-阅读器正在剥夺你的体验"><a class="markdownIt-Anchor" href="#你的-rss-阅读器正在剥夺你的体验"></a> <a href="https://antoniosantos.io/your-rss-reader-is-robbing-you/">《你的 RSS 阅读器正在剥夺你的体验》</a></h4><p>RSS 阅读器确实不会显示任何样式，是完全以文字为主的。</p><p>这一点，<a href="https://taxodium.ink/">Spike</a> 过去在电子邮件里也跟我提到过：只用 RSS 阅读器阅读文章的话，会错过一些站主精细的网站设计。</p><p>我的做法完全取决于我当下的心情：</p><ul><li>如果心情不好，那么仅用 RSS 阅读器阅读。有些博客并没有做好 RSS 里要展示的内容，例如只会出现总结、文章被截断，那我会将其设置成「未读」然后离开</li><li>如果心情不错，那么我会点击软件上的 <em> Open in Browser</em>，自动在浏览器中打开该链接。不过网站设计不符合我胃口的，例如文字尺寸过小，我还是会回到阅读器里来</li></ul><p>部分博客有着让我印象深刻的设计，所以我不论心情好坏，都会用浏览器访问查看。</p><p>文章里，作者也推荐了些新的、我不知道的网站。底下还有 Webmention 引用，因此还能看到有人回复了回复了作者的人。真有趣。</p><p>我的博客网站还是以文字为主，用 RSS 阅读器阅读也没有什么问题。</p><p>设计啥的我都放到了主站内，也就是域名里去掉 <code>blog.</code> 的那个网站。不过这个主站还未搭建完毕，我有很多事情要考量：一是场景还未画完，而我画画完全是看我有没有灵感、当下是不是夜晚、我是不是有些急躁；二是无障碍性我不知道该如何设计；三是默认关闭了 JavaScript，或者使用非主流浏览器访问该网页的用户朋友们，我该如何将内容呈现给他们？自然最简单的法子就是让他们访问博客网站，而非主站，但我还是想要做得完美一些。</p><p><a id="无干扰即是干扰"></a></p><h4 id="无干扰即是干扰"><a class="markdownIt-Anchor" href="#无干扰即是干扰"></a> <a href="https://readbeanicecream.codeberg.page/posts/2026-06-05.html">《无干扰即是干扰》</a></h4><p>虽然知道 Codeberg 有像 GitHub 那样提供静态网页托管的服务，不过这应该是我第一次看到 Codeberg Pages。</p><p>我也有一台「专门用于无干扰写作」的设备，那就是室友不用的 2013 年的 MacBook Air。这个电脑很小、过时，所以她觉得已经报废、不能用了，借给我上学用。不过这个今年下半年我打算 gap 掉，所以也没有用它的时机。</p><p>不过它没有那么纯粹，因为我还安装了浏览器等软件，意味着它依然可以用于摸鱼。</p><p>对比我现在主要使用的笔记本电脑，也就是 Lenovo IdeaPad Flex-15IML，它要轻很多很多。所以它也是我目前手头上最适合带出门、单纯为了打字而打字的设备。</p><p>不过实际上，我很少使用它。尽管它安装的软件更少、更适合带出门，但我发现使用 Lenovo 笔记本写作也丝毫不影响。该写的时候我还是会写一天，不想写的时候我数蚂蚁也会开心。</p><p>我没有作者那样，那么需要去每天写作。不过我也想过每日更新一篇，算是个理想吧！我很清楚约束我没有用，我就是那么懒惰、不听话的人，所以能做的只有想方设法让自己多多处于「灵感大开」的阶段。这时写作就是欢乐的、摸鱼的、不正经的；代价是我的工作会被丢到一旁，哈哈……</p><p>然后说个题外话。作者的博客名是 <em> RedBeanIceCream</em>，也就是「红豆冰淇淋」。我想说我不喜欢吃红豆 —— 就这样。<em>Run away.</em></p><h2 id="眼前"><a class="markdownIt-Anchor" href="#眼前"></a> 眼前</h2><p><a id="人与衣服"></a></p><h4 id="人与衣服"><a class="markdownIt-Anchor" href="#人与衣服"></a> <a href="https://www.autodidacts.io/people-and-clothes/">《人与衣服》</a></h4><p>有些人穿衣服，会显得很奇怪。同个衣服交给另一些人穿，却显得很自然、有特色。Curiositry 很想搞明白为什么。为此他提出了四个假设：</p><ol><li>有些人纯粹是身材长歪了</li><li>穿衣服好看的人总是在我们没察觉的时候调整衣服</li><li>笨拙的人缺乏「身体感」</li><li>这是心理战！其实大家穿衣服都没有区别，都是气质等等因素影响了我们的感知！</li></ol><p>我有一些衣服是定制的，尽管严格意义上并不是为我定制的…… 不过也要比市面上能买到的同款衣服更耐穿、更搭我。更不用说我能穿的尺码通常在实体店里难以找到，需要网购才能买到，非常麻烦。</p><p>我观察到，身边的人更倾向于所谓的「万能答案」：T 恤和连帽衫（也叫 <em> hoodie</em>）。它们很能包容不同的人体，还去性别、去阶层，是个非常安全的选择。但它们也抹平了独特性。</p><p>许多人退守在这样的舒适圈内 —— 我的意思自然不是穿它们就等同于退在舒适圈内。好吧，如果非要有人这么想、不在乎语境的话，那就这么想吧。为什么我最近这么喜欢解释自己？明明说好了不再 <a href="/posts/eac7.html#:~:text=%E5%B0%91%E4%BD%BF%E7%94%A8%E6%97%A0%E7%94%A8%E7%9A%84%E3%80%81%E8%B0%A8%E6%85%8E%E7%9A%84%E7%9F%AD%E8%AF%AD">使用谨慎的语言</a> —— 有两个原因：</p><ol><li>就如 Curiositry 所说的那样，许多人缺乏对身体的感知。直接穿上松垮的衣服，既不需要额外打理，也不用思考材质等影响搭配的因素，可以节省精力给其他事情</li><li>「平庸」意味着「安全」。穿合身、有设计感，甚至稍显正式的衣服，需要承受来自外界的凝视。类似于暴露出真正的自己。一旦被否认，就会无比受伤，那最开始还不如不要踏出这一步</li></ol><p>我过去是第二个心态。</p><p>当时的我受母亲的打压，对自己无比没有自信。她的审美很奇怪，根本不适合我，却非要向我灌输例如「女孩子这个年纪打扮相当于做妓女」这样的封建想法，或者说对年轻一辈的忌妒。我听从她所说的，一直是穿着带文字的 T 恤衫或者连帽衫，藏在宽大的壳里。</p><p>展示自己的喜好和独特性是很难的，尤其是从未有人带我去思考这些时。也就是说，我甚至不知道什么是「好看」，什么是「不好看」，便卡在平庸且安全的地方动弹不得了。</p><p>因此当穿着根本不合适也不好看的「万能答案」的家伙儿跑过来，表达他们对我服装搭配的愚见，我会很不开心。尤其是这些人都非常喜欢接一句：「为什么你不穿 T 恤或者连帽衫？」</p><p>真讨厌，干你什么事儿！一点审美都没有，只有老土气质的家伙儿！去去！莫要把你的想法，乃至平庸和烦人套用在我身上！</p><p><a id="夜猫子才是正常的吧"></a></p><h4 id="夜猫子才是正常的吧"><a class="markdownIt-Anchor" href="#夜猫子才是正常的吧"></a> <a href="https://immarcus.com/blog/night-owl-was-the-norm/">《夜猫子才是正常的吧》</a></h4><blockquote><p>中世纪的人每天晚上睡两觉：第一觉大约是日落后到晚上 11 左右，然后起床干活、收拾家务、聊天、男女亲热（这个很实用啊，因为白天干活太累，第一觉先补充精力）。半夜 2 点左右再开始睡到早晨。</p></blockquote><p>Marcus 提到的第二个小知识，真是有趣…… 原来如此、原来如此，早睡早起并非人类最自然的形态。</p><p>怪不得我总觉得不对劲儿。早睡早起要真是人类原本的习惯的话，没法解释为什么人类到晚上思维无比活跃 —— 它不该存在啊，进化干嘛要保留这么个没用还损害生存的特质。</p><p>那我就不用太在意早睡早起哩。该起床就去晒晒太阳、自然醒过来；该睡觉就关小灯，避免接触太多蓝光。</p><p><a id="微信早已不是熟人社交"></a></p><h4 id="微信早已不是熟人社交"><a class="markdownIt-Anchor" href="#微信早已不是熟人社交"></a> <a href="https://lomus.cc/archives/793">《微信早已不是熟人社交》</a></h4><p>我至今都不知道为什么，我人都不在中国了，却还要使用这个破软件。</p><p>我在中国的时候，其实就不咋用它。QQ 虽然也是同家公司的，但我明显对它更有回忆。在建立群聊等任务上，QQ 也做得更好，不用忍受微信那要啥没啥的无能。</p><p>因为微信在高中期间，被没有脑子的亲戚轰炸了一段时间，所以注销掉了。之后新建了个微信，没加任何跟我有血缘关系的人 —— 这时候真好啊，完全不需要使用微信。后来手机换成了安卓手机，不能和室友继续使用 iMessages 通讯了，所以依着她继续用上了微信。</p><p>再就是大学期间，我半被迫出去社交，结识了许多中国来的交换生，就也加了他们的微信。唉，从这时候起，我干干净净的微信通讯录便开始变得杂七杂八！我都不知道这些人是谁了都。再之后，母亲说了我好几年，终于找到了个正经的理由加上了我的微信。其他亲戚也陆陆续续加了我好友。真是后悔，或许哪天又会注销一次微信账户吧。</p><p>我找打工的时候，遇到的华人老板都要求进他们的微信群。这真的蠢死了！我无法忍受这群家伙儿故作专业的样子，往微信群里放大量新人看不到的通知（非群公告）、过一段时间便会失效的重要笔记和视频和图片。明明有那么多美好的选择，你偏要选择最差的那个！</p><p>和室友骂微信的次数也不少，不过她依然觉得使用微信是有必要的：一是一般人不在乎去中心化、数据主权、隐私和匿名那一套；二是懒。所以说这群笨蛋继续使用微信，不过是因为习惯、懒惰罢了。</p><p>我看了眼自己的微信朋友圈，发现上次发还是去年十二月。不过我发的都是建立人设用的，根本不是我日常会发的东西 —— 如果你好奇的话，我会将日常的自言自语发在 Fediverse 上呢！</p><p><a id="8-号出口-第-1-次尝试-与育儿"></a></p><h4 id="8-号出口第-1-次尝试与育儿"><a class="markdownIt-Anchor" href="#8-号出口第-1-次尝试与育儿"></a> <a href="https://hollie.eilloh.net/posts/exit-8-attempt-no-1-and-parenting">《8 号出口（第 1 次尝试）与育儿》</a></h4><p>Hollie 讲了讲自己尝试观看《八号出口》这部电影 —— <a href="/posts/f8cc.html">我也看过喔</a>。其实我读到她没能看完这部电影，第一反应是她觉得电影很无聊、不好看云云，但没想到是太吓人了。借助他人的视角去看事情，能领会到自己视野的狭窄呢。</p><p>中间，她写道：</p><blockquote><p>First, one of the ways I tried to teach the kids boundaries when they were smol was to sometimes ask them to do a thing with me, often a movie or TV show. On the occasions they wouldn't want to, I would encourage them to say no, that…</p><p>…it was okay to turn me down<br>…that yes I might be the <em>tiniest bit bummed</em>, but that isn't perilous for either of us<br>…it's safe to disappoint me, I can handle my own feelings and I don't keep a score sheet<br>…I'd much rather you do something with me because you want to than because you felt guilty, I far prefer actual bonding over a sense of obligation<br>…your time is valuable, even as a kid (<em>especially</em> as a kid), and you should spend the parts of it that you control, in a way that you enjoy and feels meaningful, and adults in your life should respect that.</p><p>首先，在孩子们还小的时候，我教他们建立界限的方法之一，就是有时会邀请他们和我一起做某件事，通常是看电影或电视节目。如果他们不想参加，我会鼓励他们说「不」，并且告诉他们……</p><p>…… 拒绝我是没关系的<br>…… 是的，我可能会有 <span class="emphasis">那么一点点失落</span>，但这对我们谁都没有危险<br>…… 让我失望是安全的，我可以处理好自己的情绪，而且我不会记账<br>…… 我更希望你和我一起做某事是因为你想做，而不是因为你感到内疚；比起义务感，我更喜欢真正的联结<br>…… 你的时间很宝贵，即使是孩子（<span class="emphasis">尤其</span> 是孩子），你应该以自己喜欢且觉得有意义的方式度过你能掌控的时间，而你生活中的成年人应该尊重这一点。</p></blockquote><p>这些话说出来真是令人感动。我想我也曾希望父母能对我说这种话、做这样的事情。</p><p>母亲自我小时起便常常强迫我陪她做事情。如果我表达出不愿意，她就会大发雷霆，然后锁起来我所有的玩具或者设备以报复我的不听话。她也非常喜欢让我感到内疚，尽管我还是个孩子。直到现在她也会跟我说，我小时候被她「带」去做了许多亲子活动，而这都是她「爱」我的象征。</p><p>但我只会觉得自己一直在被浪费时间啊。这些所谓的「亲子」活动，一点乐趣都没有。为什么要在我需要交同龄人朋友的年纪，强迫我和长辈打交道，然后辱骂我的同学和朋友呢？和只会教训我、怪我不够孝顺的亲戚在公园里无所事事地野餐，有什么乐趣可言吗？</p><p>Hollie 指出的，尤其是孩子的时间很宝贵一事，也让我颇有感触。刚来美国的那些年，作为家里唯一一个会说英语的人（以及小孩），我被迫做过许多本不应该去做的事情，例如和各个公司的客服或者销售扯皮、放学后便陪着母亲去赚钱、担任导游或者翻译…… 我没有时间去维系和同龄人的关系，除非是通过手机。</p><p>这种不必要的「工作」直到高中认识了现在的好友，才明白其中有多荒唐。在我应该好好学习、结识朋友搭建交际圈的时候，我却要因为母亲的「不会做」，又或者说「根本懒得做」，而在做些对我一点意义、学习价值都没有的琐事上。再之后，我便脱离了这些荒唐，变成了亲戚们口中难约出来的、总是很忙碌的人。</p><p>我认识的另一个人，也有类似的问题。明明家里有钱到能够请人来做家事，但偏偏要求他花时间来做。这些长辈们，一点都没有理解到，人的时间有多么宝贵啊。一天天也不知道在做什么，似是就算空闲下来，也只是窝在沙发上刷短视频 —— 不过这个家伙儿是讨厌鬼，所以主观上还是觉得他很活该。明明已经有人告诉过他，没有必要做这种事情、应该多花时间和精力在自己的未来上吧，他却觉得他就要这么活，一辈子和父母住在一起也没有关系。好啦，那你就这样吧！真希望以后都不要再听到你的消息了！</p><p><a id="在无关紧要的地方呐喊"></a></p><h4 id="在无关紧要的地方呐喊"><a class="markdownIt-Anchor" href="#在无关紧要的地方呐喊"></a> <a href="https://nik.art/yell-where-its-inconsequential/">《在无关紧要的地方呐喊》</a></h4><blockquote><p>……they're just trying to help. So it's usually the good kind of yelling—the one that's meant to win you the championship, not make you feel bad about losing it. But the energy can get intense, and that's sometimes exactly what makes it valuable—because it prevents yelling in other moments where it would do more harm than good.</p><p>他们只是想帮忙。所以这通常是那种良性的叫喊 —— 那种旨在帮你赢得冠军的叫喊，而不是让你为输掉比赛而感到难受。但这种能量可能会变得很激烈，而这有时恰恰是它的价值所在 —— 因为它防止了在其他可能造成更大伤害的时刻出现争吵。</p></blockquote><blockquote><p>Yell where it's inconsequential so you can address big challenges immediately with calm and composure.</p><p>在无关紧要的事情上发泄情绪，这样你就能在面对重大挑战时立即保持冷静和沉着。</p></blockquote><p>关于和他人游玩合作类电子游戏。实际上，我是一旦开始玩游戏就会变得无比暴躁的人。例如最初和室友玩《饥荒联机版》，我就常常因为她在家附近放满了蜘蛛、不帮我收菜等理由对她发火。同样的，她也会因为我认为的小事而对我生气。</p><p>吵架是很重要的。在一段重要的人际关系中，一定要有争吵。频率不要少，也不要天天吵。吵多了，你会意识到自己会因为什么样的事情而生气，你也会明白对方为什么要和你吵架。</p><p><a id="死时归零也无妨"></a></p><h4 id="死时归零也无妨"><a class="markdownIt-Anchor" href="#死时归零也无妨"></a> <a href="https://nik.art/its-okay-to-die-with-zero/">《死时归零也无妨》</a></h4><blockquote><p>But at some point in my 20s, my overall attitude shifted from "rack up as much as possible" to "focus on getting what you need, then stop."</p><p>但在 20 多岁的某个时刻，我的整体心态从「尽可能多地积累」转变为「专注于获得所需，然后适可而止」。</p></blockquote><blockquote><p>If your target is to amass as much wealth as possible, the pressure never stops. The answer is always "more." If you don't plan on leaving behind a pile of money, much of that pressure immediately subsides.</p><p>如果你的目标是积累尽可能多的财富，那么压力将永无止境，答案永远是「更多」。如果你不打算留下一大笔遗产，大部分压力会立即消散。</p></blockquote><p>该花钱就花。花在对自己好的地方上，比如提升生活质量，让自己幸福。这要比无意义地囤积金钱好多了。</p><p><a id="破折号真他妈太棒了"></a></p><h4 id="破折号真他妈太棒了"><a class="markdownIt-Anchor" href="#破折号真他妈太棒了"></a> <a href="https://psychotechnology.substack.com/p/em-dashes-are-fucking-amazing">《破折号真他妈太棒了》</a></h4><blockquote><p>There is no greater joy in life than typing a sentence, realising it needs a clarification, a caveat, an addendum — but in the same sentence, not a new one — and, guess what, the em dash is right there for you.</p><p>生活中最大的乐趣莫过于打出一个句子，意识到它需要一个澄清、一个警告、一个补充 —— 但在同一个句子里，而不是新起一句 —— 然后，你猜怎么着，破折号就在那里等着你。</p></blockquote><blockquote><p>Em dashes can be used instead of brackets in a sentence — like this one for example — and you can just type your shit and keep going.</p><p>破折号可以在句子中代替括号使用 —— 比如这个句子 —— 然后你就可以继续打你的废话并继续下去。</p></blockquote><p>破折号真他妈太棒了！—— 你为什么还没有开始滥用它们！快快行动起来！</p><p><a id="indieping-的新功能"></a></p><h4 id="indieping-的新功能"><a class="markdownIt-Anchor" href="#indieping-的新功能"></a> <a href="https://blog.giveanornot.com/indieping-feed/">《IndiePing 的新功能！》</a></h4><p>JN 做出了 <a href="https://indieping.giveanornot.com">IndiePing</a> 这款工具，可以查出网站链接被谁引用到过。</p><p>这类工具很重要哇。虽然我有使用 Webmention，但它需要发送方和接收方都在网站中添加 Webmention 链接。有些博客朋友们不会使用该技术，因此不能依赖于 Webmention 来得知谁引用了我。</p><p>和第一次尝试 Kagi 一样，我立即开始搜索自己…… 喔，居然搜到了陌生朋友们的文章引用了我，非常受宠若惊！</p><p><a id="sites-on-neocities"></a></p><h4 id="sites-on-neocities"><a class="markdownIt-Anchor" href="#sites-on-neocities"></a> <a href="https://neocities.org/browse">《Sites on Neocities》</a></h4><p>因为全新的月刊结构没有分享「有趣项目」的地方了，所以我要分享的东西会被随便放置。</p><p>这是 Neocities 的浏览页面。你可以点进去，看到许多个人风格强烈的网站。有很多很适合拿来参考、设计自己的个人主页。</p><p><a id="freshrss-文章全文扩展"></a></p><h4 id="freshrss-文章全文扩展"><a class="markdownIt-Anchor" href="#freshrss-文章全文扩展"></a> <a href="https://github.com/Niehztog/freshrss-af-readability">《FreshRSS 文章全文扩展》</a></h4><p>我时不时会遇到，订阅的博客网站提供的 RSS 里，并不会展示完整文章内容的情况。</p><p>该扩展可以提取目标文章的全文。</p><p>我无法理解为什么会有人提供 RSS，却不会提供原文内容，而是仅展示摘要、AI 总结、原文的一部分？你完全可以不提供 RSS 的，不是吗？</p><hr><h2 id="折腾博客"><a class="markdownIt-Anchor" href="#折腾博客"></a> 折腾博客</h2><p><a id="学校博客"></a></p><h4 id="学校博客"><a class="markdownIt-Anchor" href="#学校博客"></a> 学校博客</h4><p>这个月从校友那儿听说，我校其实有个教学博客平台，用于课程博客、学生作业或者期刊、课程开发、行政沟通、教职工发展等场景。</p><p>它自 2008 年就在运营，真是神奇。之前完全没有听说过呢。</p><p>该博客平台的技术栈，是用了 WordPress 的多站点网络，然后使用 BuddyPress 来提供成员目录和个人资料页功能。</p><p>我大致看了下站点安装的插件，发现装了两个功能重叠的无障碍检查插件，还有自托管的隐私友好统计插件 <code>koto-analytics</code>，真不错啊，该不会维护的部门里偷偷藏着数据主权主义者吧。</p><p>作为学生，我登录后，便可以创建自己的站点。有趣的是，我还可以给我创建的站点里，创建他人的账号。搭建论坛什么的，也是完全可行的。</p><p>我还发现它有个姐妹项目，可以给学生属于自己的域名以及虚拟主机空间，让数字身份归学生自己所有，就算毕业了也能带走。</p><p>先前我一直顾虑着，是不是要再买个域名来托管现实身份相关的网页。我实在是不想要学校里的人、业内人士知道 <em> Cytrogen</em> 这个网络身份…… 有了学校的这俩项目，想必就可以弄个实名的专业门面了。折腾完后，我得想办法把该个人博客上的学习笔记迁移过去，之后估计也只会在学校的博客平台上更新学习笔记。</p><h2 id="我写的文章"><a class="markdownIt-Anchor" href="#我写的文章"></a> 我写的文章</h2><ul><li><a href="/posts/221a/">《RE：断层里的心理学》</a></li><li><a href="/posts/36e6/">《RE：Post-political》</a></li><li><a href="/posts/1b10.html">《RE：Why China got rich and India didn't》</a></li><li><a href="/posts/c783/">《休息日出去玩吧》</a></li><li><a href="/posts/3a5e/">《大熊猫送快递》</a></li><li><a href="/posts/b02e/">《想法在丙午荷月迭代》</a></li><li><a href="/posts/11d1/">《洗澡和洗头发》</a></li><li><a href="/posts/851c/">《班级政治》</a></li></ul><h2 id="编程历程"><a class="markdownIt-Anchor" href="#编程历程"></a> 编程历程</h2><p><a id="RSS日报"></a></p><h4 id="rss-日报"><a class="markdownIt-Anchor" href="#rss-日报"></a> RSS 日报</h4><p>Fluent Reader 是我很喜欢的 RSS 阅读器。不过它是基于 Electron 的，我实在是不喜欢在电脑上安装又一个 Chromium。</p><p>在笔记本电脑换成 EndeavourOS 之后，我便在非常缓慢、非常缓慢地开发基于 Fluent Reader 的 RSS 阅读器。为了性能，技术栈改成 Tauri 和 Rust。</p><p>因为 Spike 在 <a href="https://taxodium.ink/49.html#FF319C35-80BD-4CA6-931E-A102E10B4009">Zine #49</a> 里提到了日报的做法，让我很是好奇，也是龟速地在 RSS 阅读器中添加了该功能。</p><p>日报的选文逻辑是，前端会从后端拉取最近 1000 条未读文章，然后按分组将它们划分为不同的桶。分组是因为我原先阅读 RSS 用的是 <a href="https://taxodium.ink/nichijou-6.html#73537C35-2E65-424A-89D3-C1C0F3773D3F">可持续农业的区域管理方法</a>，把订阅以「阅读喜好优先级」的方法分组。日报里我也希望采用该逻辑，毕竟要考虑到部分站点的发文频率…… 订阅 RSS 也是我收藏链接的方式，因为我没有使用书签的习惯。</p><p>选文总计分两轮：</p><ol><li>首先是保底轮：每个未被静音的分组至少获得默认 2 篇，确保日报不会只覆盖热门源；</li><li>其次是加权分配轮：剩余的篇幅配额按照 Sainte-Laguë 最高均数法在各组之间按权重分配。权重越高的组分到的额外文章越多。假设某个分组权重被设为 0，那就意味着完全静音、不会出现。此外还有每源上限，防止高产出的 feed 淹没其他来源；</li></ol><p>最终返回的是扁平化的文章 ID 列表，按最新在前排序。</p><p>选出的结果不会直接展示，会先以快照形式保存到设置里。所以全天的日报都是固定的，不会因为后续有新文章而变化。不过快照还是会在下次日期变更时失效，然后重新生成。</p><h2 id="书籍"><a class="markdownIt-Anchor" href="#书籍"></a> 书籍</h2><p><a id="the-absolute-true-diary-of-a-part-time-indian"></a></p><h4 id="the-absolute-true-diary-of-a-part-time-indian"><a class="markdownIt-Anchor" href="#the-absolute-true-diary-of-a-part-time-indian"></a> <em>The Absolute True Diary of a Part-Time Indian</em></h4><p>这是我高一时的读物，旨在让学生们了解美洲原住民的视角。</p><p>整篇小说所需的英语大致是美国公立学校的初中水平。不过内含不少性相关的描写，给孩子阅读前还需注意。</p><p>虽仅需要初中水平的英语，但丝毫不影响本小说想要表达的内涵的水平：贫困、种族认同、自我救赎…… 简单的语言反而更能代入到主人公这个小孩儿。</p><details>      <summary>剧透警告</summary>      <p>结尾的处理方式非常草率，我无法认可。</p><p>故事后半段里，主人公相继经历了外婆、父亲好友以及姐姐的离世。按照传统的叙事弧线，如此巨大的悲剧应需要同样充沛的缓冲期和消化过程。但作者在极短的篇幅内，让主人公和竹马打了个篮球，就立即与自我和部落和解了。</p><p>搞什么啊！</p><p>我当时读的时候，还以为后面还有呢，结果翻到下一页就变成给学生看的阅读理解题了啊！</p><p>故事前面提到了原住民内部的绝望、白人社区的排外、主人公跨越两个世界所产生的撕裂感 —— 在结尾全都没有得到实质性的解构或者解决。就是，你可以不解决它，但你应该指出它后，做什么吧？你的写作方式，会让我误以为之后还有更多的解释，但就没有啦？为啥啊？</p>    </details><h4 id="其他评价"><a class="markdownIt-Anchor" href="#其他评价"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/book/5HkoYOAXl5nuEGnzYsVnYY" target="_blank" rel="noopener noreferrer">GNU Emacs Lisp 编程入门</a><span class="neodb-status">在读</span></li></ul><h2 id="影视"><a class="markdownIt-Anchor" href="#影视"></a> 影视</h2><p><a id="药物少女的呢喃"></a></p><h4 id="药物少女的呢喃"><a class="markdownIt-Anchor" href="#药物少女的呢喃"></a> 《药物少女的呢喃》</h4><p>该电视动画改编于同名轻小说。</p><p>它非常罕见地，是以古代中国的宫廷为背景的电视动画。尽管官方解释是「架空东方帝国」，不过在许多设计上都能看到古代中国的影子。</p><p>但这也不是什么后宫属性的作品，而是具有宫廷悬疑解密属性。</p><p>主人公猫猫是可怕的实用主义者，误入后宫但只对毒物和草药感兴趣，甚至多次以身试毒。</p><details>      <summary>剧透警告</summary>      <p>作品悬疑解密的焦点，放在了自然科学与药理常识上，侧面反映了古代人的无知与可怜 —— 也能看出我们现在的各个「常识」都是多么来之不易。</p><p>观看期间非常惊叹于原作者埋伏笔埋得多么绝。</p><p>子翠 —— 没了你我还怎么活啊！</p>    </details><p>第三季什么时候出啊！</p><h4 id="其他评价-2"><a class="markdownIt-Anchor" href="#其他评价-2"></a> 其他评价</h4><p>本月暂无记录。</p><h2 id="音乐"><a class="markdownIt-Anchor" href="#音乐"></a> 音乐</h2><p><a id="恋するフォーチュンクッキー"></a></p><h4 id="恋するフォーチュンクッキー"><a class="markdownIt-Anchor" href="#恋するフォーチュンクッキー"></a> 《恋するフォーチュンクッキー》</h4><p>日本女子偶像组合 AKB48 于 2013 年发行的单曲，也是她们最具代表性与大众普及度的国民级音乐作品之一。</p><p>与当时偶像流行乐常见的电子高频曲风不同，该曲吸纳了 70 到 80 年代复古迪斯科与摩城唱片风格的律动，让人听着节奏舒缓、极具复古韵味。</p><p>这首歌是室友推荐给我的。她过去在日本居住的时候，就常常在车内听到它 —— 车载音乐让人熟悉。我们这个月去 <a href="/posts/c783.html#:~:text=%E6%88%91%E4%BB%AC%E8%B7%91%E5%88%B0,%E5%93%88">唱 K</a> 玩，让我也觉得唱歌还挺开心的。之后一天，她在家里翻找出转换器和麦克风，并告诉我这种旋律变化不那么大的歌说不定会适合我唱。</p><blockquote><p>恋するフォーチュンクッキー!<br>未来はそんな悪くないよ<br>Hey, hey, hey~<br>ツキを呼ぶには<br>笑顔を見せること<br>ハートのフォーチュンクッキー<br>運勢今日よりもよくしよう<br>Hey, hey, hey~<br>Hey, hey, hey~<br>人生捨てたもんじゃないよね<br>あっと驚く奇跡が起きる<br>あなたとどこかで愛し合える予感</p></blockquote><p>听起来唱起来都会让人很开心！</p><h4 id="其他评价-3"><a class="markdownIt-Anchor" href="#其他评价-3"></a> 其他评价</h4><p>本月暂无记录。</p><h2 id="日记片段"><a class="markdownIt-Anchor" href="#日记片段"></a> 日记片段</h2><button id="details-toggle-diary_sections-1789678111297" class="details-toggle-btn" data-group="diary_sections" onclick="toggleGroupDetails('diary_sections', 'details-toggle-diary_sections-1789678111297', '展开所有', '收起所有')">展开所有</button><details data-group="diary_sections"><summary>七月一日</summary><div class="diary-entry">00:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWDGGFJVBJP6TSDC9H7Y1Y1A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 印象里初中数学，我在中国上小餐桌的时候偷偷看到过学长学姐们做，感觉和美国教的有所不同。最近辅导小孩子们数学，发现他们的教材竟跟我小学时的教材也不太一样，干嘛呀哎呦。</p><p></p></div><hr><div class="diary-entry">02:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWDSC6B1RGYM1DVQFT13PJ6K" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这几天在研究股票的事情，是的我还在炒股。虽然 AI 玩意儿是个讲烂的话题但不得不说从股市中谋取暴利依然要围绕着 AI。如果只是去看所谓的「入局者」，AKA 知名的大公司例如 NVIDIA，是不行的，得找到他家芯片是谁做的、用什么做的，并一一投资那些基础设施公司。</p><p>研究期间我便发现，美国企业在如何产生足够的电力上有着分歧：最为环保的自然是风电或者水电，但它们布置起来很花时间，于是就有煤电公司表示能够立即烧煤产电给整个 AI 基础设施链使用，尽管它们一点都不环保。</p><p></p></div><hr><div class="diary-entry">03:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWDVTFX386NGYQMZYWKJ3MD6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 出了道我觉得简单但是他们搞不明白的应用题。应该是小学五年级水平的：</p><blockquote><p>A water tank is 3/4 full.</p><p>After draining 15 1/2 gallons of water, the tank is now 1/3 full.</p><p>What is the total capacity of the water tank in gallons?</p><p>一个水缸原是 3/4 满。放了 15 1/2 加仑的水后，水缸是 1/3 满。求水缸一共能装多少加仑的水。</p></blockquote><p>我发觉他们好像不知道分数的除法可以取绝对的部分值以及相对的分数，来得出绝对的整体值。我对此的解释是分数的乘法是：</p><blockquote><p>绝对的整体值 × 相对的分数 = 绝对的部分值</p></blockquote><p>就像是 6 个苹果（绝对的整体）的 1 / 2（相对的分数）等于 3 个苹果（绝对的部分值）。</p><p>那除法就是反过来的。</p><p>但这样解释他们也不明白…… 怎样才能更好地让小孩子理解呢……</p><p>于是我拿同样的题给室友看，结果这个破人也不会用分数的除法来解。她认为我的题确实出难了，换成高中的那帮大傻子估计也看不懂。干！哪里难了！</p><p></p><blockquote class="diary-thread-reply">16:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWF8CPTFZW802TQGCR3V4W34" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>好笑的点是室友上到高中才开始努力学习，所以对于数学题她的所有解法都是用代数。我的这道题她就用代数做了出来，但如果我跟她讲分数的概念她会一头雾水，因为她压根不记得这些知识。</p><p>同样的东西我拿给另一个朋友看，他的第一反应也是代数里的未知数。他提到，小时候的自己不会去想要理解这些，也就是做计算题很得心应手，但做应用题这样需要对概念有所理解的他当时不太擅长，我想这也是许多孩子的处境。我大致翻了下妹妹五年级的数学教材，练习册中分数除法的题相当之少，似是仅让他们学习了如何除（keep change flip），但没有教会他们分数的除法到底是什么。</p><p>再就是这练习册的题也太少了…… 我得跑网上去偷中国那边的练习册内容。</p><p></p><blockquote class="diary-thread-reply">16:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWF9WX00382JB9700KNMMPDF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>难道有问题的是我？确实不知道这些也能顺利通过美国初中和高中，这种题交给我高中时认识的笨鬼们他们也看不懂，但他们依然能考上大学，反正 SAT 又不考这个。小孩子们不需要知道这些概念。可是不搞懂的话补习和辅导又有什么意义？反正他们最差的就是我妹妹，数学屡次都是游走在合格线上，但要是哪一天开智了搞明白了呢？小孩子不想要去学习这些、不知道它们有趣在哪里，也是很正常的，就像我朋友那样。另一个孩子本就是学校里的聪明学生，虽然不知道怎么做这道题但不妨碍他未来依然是初中、高中的聪明学生，反正美国的数学水平就是这个破烂样子了，SAT 的数学题交给中国的初中生做也能做得不错。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">05:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWE200RTA7H16AG6A89C7WKT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>和室友玩《星露谷物语》，玩完后会被催眠，想立即躺椅子上睡觉。</p><p>感觉自己被之前看的百万啤酒花攻略影响到，每次玩这款游戏就是开局钓鱼钓个几千块然后积攒下来 all in 草莓，之后就是搞小桶种啤酒花等等固定操作，然后抛弃存档不玩了。最开始玩的时候还会养动物弄奶酪啥的，现在啥也不知道了……</p><p></p></div><hr><div class="diary-entry">17:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWFA16CD2TKKRP7ZYJH1GBYQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3FZ75C9HA8Q3KRW12YT3F.png" alt=":neocat_cry:" loading="lazy">​ 应该提前起床出门去的，一个小时前外面温度还是 24 度，现在已经变成 34 度、更不想出门了。尤其是我摒弃了公交和地铁这两个出勤方式（贵死了），改骑车了。</p><p></p></div><hr><div class="diary-entry">19:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWFJQ9MRK0RZ07F6AMX61Q2M" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>股票真是个神奇的东西，接触后会逐步增长 FOMO 情绪。最近我都没有怎么在阅读 RSS 里的文章了……</p><p></p></div><hr><div class="diary-entry">21:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWFRQDBK8GPY6XW3HER04JYH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>本来打算晚点出门的，不好那么热，结果超市 19 点就要关门，现在 17 点多，外面还是 30 多度的样子。我还能跑到地铁站去吹空调避暑，但家里的匹克猫就会因为我出门、关了空调而化成猫水…… 打算还是把空调开开。</p><p>说到空调，最近好像经常在网上看到欧洲那边的新闻，也有些和空调相关的纠纷，不知道是发生了什么。</p><p></p><blockquote class="diary-thread-reply">21:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWFS4YRJD2Q601YZQZ67S985" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>卧槽 40 多度的高温！还有很多人因酷暑而热死！</p><p>看了眼发现欧洲的空调普及率特别低，有一点是因为房屋的设计过老。在美国稍微经历过这样的事情，我们都是用卡在窗户上的那种小空调。现在的公寓里虽预先挖好了洞，长这个样子。洞太大了，空调太小，只好用胶带堵上。那种有专门外机的空调，并不多。父母家用的则是中央空调，有外机，但和我在中国时印象看到的、挂在天上的空调还是不一样。</p><p>顺便一说夏天一到、空调一开，我每个月的电费都是 200 多块钱。妈的。空调都要开不起了。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KWFRZ296VGGNCKHEGHXSDXED.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">21:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWFSDH609RCAV128XJJNVC0Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>原来欧洲人难以使用这种 window air con 因为窗户设计不同。美国房屋的窗户都是上下拉开的，欧洲那边用的是左右开门的设计。所以他们更倾向于使用 portable air con，不过这个我没见过。</p><p></p></blockquote><blockquote class="diary-thread-reply">21:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWFSQW2591DQA6KAMWY19N52" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>突然发现左边那一坨是朋友送我的泰拉兔…… 我给忘角落了……</p><p>嗯，没事，让它在那儿吧，不然看到它会心生「试试我这把新武器」的想法。</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">07-02 01:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWG89QY48V6K9F253T8P771T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我出门前给匹克猫留了个 27 度的空调，怎么回家变成 29 度了？这猫成精了怀念古埃及的大沙漠和炎热吗？</p><p></p></blockquote></div><hr><div class="diary-entry">22:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWFWMPQ6SV8Z2MNXCFN56JV8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>几个月前想要控制手机应用的网络使用权限，主要是因为我有一些离线游戏但总是弹广告出来很烦，我又不想要一个个内购过去 —— 好直接且原始的需求！于是我安装了 NetGuard，但发现它和我的 Tailscale（实际上是 Headscale）服务有冲突，两者都想要接管 VPN 的位置。最终作罢……</p><p></p></div><hr><div class="diary-entry">23:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWG01HY6Y46HHS86T4Q19FJQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这是什么。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KWG01GHST1PTPCYVR3X01RPP.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">23:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWG13788THXD4EAC3D5F9VMZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>原来马里奥赛车的蓝龟壳是盯着第一名丢的。等舞萌机期间，我和朋友在看隔壁马里奥赛车在玩。他说这个第一名，一直拿着蓝龟壳，太阴了。</p><p></p></div></details><details data-group="diary_sections"><summary>七月二日</summary><div class="diary-entry">00:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWG4SXG1X1KW2YTXH6NS2TGQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Transit 最近老出问题，它好像觉得我忍受不了走几步路，非要在路上添加 Uber 选项。我把 Uber 选项去除，它就不显示路了。你特么十分钟走过去就是地铁站，怎么可能没有路呢。</p><p></p><blockquote class="diary-thread-reply">01:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWG82X671BBVH41ACRTGNTP3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>但是 Organic Maps 的地铁导航功能更差，几乎没有。它只会显示一条路线给你，去哪里坐、坐哪个方向都不会显示。</p><p>Google Maps 等软件我又不乐意用。</p><p></p></blockquote></div><hr><div class="diary-entry">01:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWG5P3954E41D9HT5X38ZR38" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我得了一种来到唐人街就想要买便宜饭吃的病。路过一家 9 块钱三菜一饭的店，再加 1 块钱给易拉罐汽水，实在难得啊在这个硕大的曼哈顿里。中城的一碗面往往都是 20 左右。</p><p></p><blockquote class="diary-thread-reply">02:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWG94EGZ7FQ9937SRSB4P6RG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​ 我本来想着晚上跟室友吃饭的，所以没有在唐人街吃便宜饭。结果她估计凌晨才回来，问我怎么不去唐人街吃。你这说的都是我的词儿啊你这。你为什么不早说！</p><p>冷静点，10 块钱的饭那也是 10 块钱，自己买菜自己做，除一下一顿连 3 块钱都不用，你快醒醒！</p><p></p></blockquote></div><hr><div class="diary-entry">03:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWGEGSHP67V6GRR0FQX67KTG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://pluralistic.net/2026/07/01/ontogeny/#recapitulates-phylogeny" rel="nofollow noreferrer noopener" target="_blank">https://pluralistic.net/2026/07/01/ontogeny/#recapitulates-phylogeny</a></p><p>Doctorow 的新文章《技术蟹化》。</p><blockquote><p>最近，我观察到美国大科技平台也经历了自己的「技术蟹化」，即每家科技公司最终都变成了 Facebook。</p></blockquote><p></p></div><hr><div class="diary-entry">03:43 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWGET77CZRFM4ZY538WJSD8F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>总算是添加了日报功能。让我感受一下 RSS 日报用起来怎么样吧。</p><p>见 <a href="https://notes.druchan.com/going-back-to-newspaper-model" rel="nofollow noreferrer noopener" target="_blank"><em>Going back to the morning newspaper model</em></a>。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KWGENFW9D9J26Z8MF2R0E0FW.png" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">04:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWGHDPRF431C4K6EAHRF0G3F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>目前的算法是：</p><p>将最近未读的未隐藏文章（最多 1000 篇）根据其分组分成六个小组。每个小组会先选中两篇保底文章，接着用 Sainte-Laguë 最高均数法来逐个选文章。</p><p>Sainte-Laguë 最高均数法的公式是：</p><blockquote><p>均数 = 权重 / (1 + 该小组本轮已填数）</p></blockquote><p>其在数学上被认为是最接近纯粹比例公平的分配方法。姑且用了下看看效果～</p><p>然后是同一个源在整个过程中最多仅能贡献两篇。</p><p>截图里的是还没有调整权重的。试读后发现不调整不行，很多高产且文章内容过短像是发朋友圈来的文章被选上来了。</p><p></p></blockquote><blockquote class="diary-thread-reply">07-09 03:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX2E0NNKDHA4PNF3H3YAB8N6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RSS 日报比想象中好用许多。</p><p>比起按照排序读完信息流的，按照排序读完日报里的文章，阻力要小许多。尽管每日理论上能阅读的文章数量变小了（无限：有限，我目前调整在三四十左右），但每日实际阅读的数量固定在三四十，反而要比之前手动筛选信息流的时候要多。并且还没有心理负担，会有类似于「今天就读这些了还挑什么，读读读」的感觉在。之前光是选文章读都很煎熬……</p><p>这样的话，也可以放肆往 RSS 订阅列表内添加链接了。</p><p></p></blockquote></div><hr><div class="diary-entry">04:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWGG75Z8D4FEKFF29Q5E1KV6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://bambamramfan.github.io/ai-compass/" rel="nofollow noreferrer noopener" target="_blank">https://bambamramfan.github.io/ai-compass/</a></p><p>AI Compass 测试。</p><hr><p>我的结果是：</p><blockquote><p>You are……</p><p>The Skeptic</p><p>patron saint: Ed Zitron</p><p>It's oversold, it's losing staggering amounts of money, and the harms are arriving faster than the value. You've done the math on the unit economics and it doesn't close. You are loud about this, prolific about this, and you suspect history will vindicate you.</p><p>Impact: -0.2 • Valence: -1.5</p></blockquote><p></p></div><hr><div class="diary-entry">04:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWGG925191AESJ6ZP3QYK1YZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>太神奇了我家的网络。我现在访问自己的服务卡卡的，但是能够访问之前我连上 Wi-Fi 无法访问的站点。</p><p>Spectrum 你想干什么你。</p><p></p></div><hr><div class="diary-entry">05:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWGPCWZK2X745CKR391AACPN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://invidious.nerdvpn.de/watch?v=r4EJHOWAvUQ" rel="nofollow noreferrer noopener" target="_blank">https://invidious.nerdvpn.de/watch?v=r4EJHOWAvUQ</a></p><p>NichanTae 正面玩的《サイエンス》MASTER 谱面。最近在玩所以晚上复盘看一眼。他的 Skill Play 我就不看了，总感觉会带坏我 2333</p><p>这首歌是 MIMI 的歌里我最喜欢的一首。谱面没有什么难点，设计有点像上个版本的《三日月ステップ 2023》，也是没有需要额外练习的错位配置，完全顺着音乐的节奏爆发和跳来跳去，吃对基础配置的熟练度。</p><p>现在红转紫阶段感觉自己对 MASTER 的基础配置有些了解了，就是暴力的键盘谱还是不会玩，这种只能疯狂积攒底力，以及变成体力大猩猩了。</p><p></p></div><hr><div class="diary-entry">06:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWGQET60KDMSGJ6ZKEV0EPSR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>简单了解了一下 Anthropic 在 Claude Code 里添加的检测代码。整个检测逻辑分为两层，其一是一直都有的服务器检测，例如发现你请求是从中国 IP 发来的，则封之；其二是 Claude Code 这个客户端会读取本机的信息，检查例如时区等信息，推测是否是中国用户，然后偷偷在提示词里添加真人不可见的标识，随着请求发回服务器。唉，太阴了！</p><p>为什么要调查这事儿呢，因为被人委托去解决这个问题…… 你们哪天让我修电脑算了。</p><p></p><blockquote class="diary-thread-reply">06:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWGQJF5TPDM1JJSJRAAXF4A8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Anthropic 的条款写的是：</p><blockquote><p>被总部位于不支持地区（中国）的公司直接或间接持股超过 50% 的实体</p></blockquote><p>那我…… <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4TFD239TJ4YG6N2ENQBK.png" alt=":ottersgottaott25:" loading="lazy">​ 邪恶的话被截断了。</p><p></p><blockquote class="diary-thread-reply">06:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWGS1J4MDM7JZW4ATE7F5STC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>卧槽我们怎么还真有闲置 LLC。</p><p></p></blockquote><blockquote class="diary-thread-reply">07-04 05:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWNTR5C2BSWB7DRSTH4P5MB4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://www.banklesstimes.com/articles/2026/07/03/anthropic-moves-to-block-chinese-firms-using-claude-via-offshore-workarounds/" rel="nofollow noreferrer noopener" target="_blank">https://www.banklesstimes.com/articles/2026/07/03/anthropic-moves-to-block-chinese-firms-using-claude-via-offshore-workarounds/</a></p><blockquote><p>Anthropic 表示：「此次更新旨在防止规避行为，」并辩称仅靠地理屏蔽是不够的，因为一些组织会通过国际子公司路由访问。该公司还告诉 Tom's Hardware，这一变化降低了「法律、监管和安全风险」，并防止「威权」和「敌对」政权使用其最先进的模型。</p></blockquote><p>丢你老母一天天想干嘛。</p><p></p><blockquote class="diary-thread-reply">07-04 05:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWNV73W9B948FRKFC5BBC8BJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://www.banklesstimes.com/articles/2026/06/15/anthropic-updates-privacy-policy-introduces-id-checks-for-claude-users/" rel="nofollow noreferrer noopener" target="_blank">https://www.banklesstimes.com/articles/2026/06/15/anthropic-updates-privacy-policy-introduces-id-checks-for-claude-users/</a></p><blockquote><p>Anthropic 更新了 Claude 的隐私政策，可能很快就会要求部分用户验证年龄或身份，以便继续使用该聊天机器人。这些更新适用于 Claude 免费版、Pro 版和 Max 账户，并首先从个人开发者开始实施。</p></blockquote><blockquote><p>为此，Anthropic 将使用 Yoti，这是一家第三方年龄验证服务商。用户可以选择通过自拍进行面部年龄估算、扫描护照或驾照等身份证件，或者通过 Yoti 应用程序分享「年满 18 岁」的证明。Anthropic 表示，如果通过验证，用户的 Claude 账户将恢复使用。</p></blockquote><p>有毛病。</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">07-08 23:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX20NXKD5HSDE50YBCSGPYMC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这个法子也不推荐。Anthropic 因为 Ant Group，开始大力审查利用海外实体获取模型使用权的中国公司，以及新加坡的节点。</p><p>根据条款，Anthropic 允许中国企业使用模型的条件差不多可以形容为「海外企业和该中国企业有合作关系，且不得不提供给他们模型的使用权」，比方说为中国企业工作、提供的服务里包含且不限于 Claude 模型。</p><p>唉但这种东西你要如何跟 Anthropic 说呢，它又没有权利去读两家公司的合同。根据网上论坛的说法，被误封还迟迟没有回应的账号多如繁星，这也包括外国人们。统统杀干净就好了。</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">17:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWHWWD0ER152SEZX6XF2JATM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>其实解决方案只有搞中转和换掉客户端这一条路，如果非要绑死在 Claude 身上的话。Claude Code 应该也可以用什么中间件或者代理啥的清洗它的提示词，但治标不治本，它下个版本弄个新东西不就完了。</p><p>国内的中转站我不了解。国外弄中转站就是一把梭 AWS。</p><p></p><blockquote class="diary-thread-reply">07-08 23:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX1ZYAFFHJYYV8J1NWS8N7X3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这个 toot 我忘撤回了，理由是：</p><ul><li>中转不合规，并且很容易被发现（尤其是特别便宜的单 key 多人享用）</li><li>中转站本身就容易出幺蛾子，毕竟是陌生人的节点</li></ul><p>倒是可以自己搭建个中转站，不过本机上依然不能用 Claude Code 这个客户端。要是非想要使用的话…… 为何不去考虑考虑不在本机上使用呢？</p><p>总之新法子我倒腾了一半，之后完事看看效果。这种跟 AI 工具相关的事情，去 V2EX 瞅瞅还是能从大量情绪垃圾帖里找到几个宝的。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">17:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWHY3FSZM8JF3X29PYZH67QD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我知道了空头是个啥了。经典又传统的炒股逻辑是跌了买、涨了卖，这一点我是从星猫大富翁那儿学的。空头是反着来。他们先借股份，在涨的时候立即卖掉，接着等股票跌下去，再买回来还给人家。</p><p></p><blockquote class="diary-thread-reply">17:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWHYABB50B8QBPW9YCMPFDNV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>大量买入股票会导致股票价值上升，反之，大量卖掉会导致价值下降。对于空头而言，他们要盯着股票啥时候跌到谷底，然后赶紧买入好还股票。不过空头多了，在同个节骨眼一起买入，股票价值就会上升，所以他们有时为了避开锋芒，在预测好的谷底之前就买入。结果可能就是，我们认为一个股票的谷底来了，但平稳得很。</p><p></p></blockquote></div><hr><div class="diary-entry">17:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWHZ42FEH48MKF973712JWC0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>研究一下离线翻译用小模型。</p><p>虽然也可以连 Kagi 的翻译 API 但我是家庭拼车的得额外去申请 key，我又有点懒……</p><p></p><blockquote class="diary-thread-reply">20:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWJ9VJDD2WZKK4G978K5Y13D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>翻译出来的质量好差……</p><p></p><blockquote class="diary-thread-reply">07-03 16:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWMBCG9EF322FDP8TFX1H08Z" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>做了些调整，首先是把模型从 1.5B 换到了 7B。然后调整了一下提示词，以及从接触到 HTML 标记就分段，改成了把标记弄成占位符的方法，避免出现翻译出来的句子狗屁不通的毛病。</p><p>现在的质量只能说能看，就是很慢。翻译完我自己阅读原文也读个不知道几遍了。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">21:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWJBWMFNZDJBYD9TZW2JCBGE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>点了个 Panda Express 当晚餐吃。近乎没有吃过他家，因为之前对这种假中餐嗤之以鼻。现在嘛…… 价格便宜，有肉有菜有碳水。然后是同定位的路边美式中快餐夫妻餐馆的水平浮动很大，有时候能找到味道不错的，有时候炒出来的菜又恶心又难吃还贵。</p><p></p><blockquote class="diary-thread-reply">07-03 00:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWJQC26D63GEQN5GSAP04HDK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>失策了，他们饮料机坏了没有气，所以只剩下柠檬水可以倒。折扣后一菜一饭一液体 12 块钱吧，还行。我随便选了个没那么危险的菜吃，感觉怎么比隔壁中国人炒得好吃。那家夫妻店炒出来的东西就没几个好吃的。饭我选的炒饭，一吃我就感觉出这 Panda Express 后厨应该没有大锅，也没有大火，这炒饭吃起来像拌饭，有几块都夹生了硬硬的。无法通过我的炒饭考试！</p><p>柠檬水就柠檬水吧，可是喝起来发现，它根本就是没有气、苦一点的雪碧，也算是回归初衷 —— 喝小甜水。</p><p>Panda Express 的店面，对比什么 Popeyes 这样的快餐店，要干净些。里面堂食的人还挺多。不知道为啥播放的音乐是中文歌，我以为店员没几个亚裔，应该会放英语的流行乐呢。</p><p></p><blockquote class="diary-thread-reply">07-03 00:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWJQJB7YXYW5M0ACZJ77C2F3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>给我的 fortune cookie 怎么是袋子破开的，吃一口发现饼干都孬了。幸好这玩意儿我不喜欢吃、丢给室友吃了。</p><p>我来美国后才知道的中国东西里，fortune cookie 就排第一号。</p><p></p><blockquote class="diary-thread-reply">07-07 15:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWYM205FSSGCR2P6968NP62F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>做调研后给的 code 是买两菜一饭的 plate，送一菜。倒腾了下，该 code 的用法是购物车需要先有非套餐的两菜一饭 plate 以及没有饭的菜，才能用。唉我想要送汽水的套餐啊，单买要 3 块钱呢。</p><p>最终价格差不多是 14 块钱三菜一饭，只能说普普通通，ふふつつ，nor-nor mal-mal。犹豫要不要买了吃，因为冰箱里还有昨天做好的花菜排骨啥的。</p><p>什么时候去办公室泡着的时候再下单吧。</p><p></p></blockquote></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>七月三日</summary><div class="diary-entry">01:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWJRG6DE3T0T0AXK8M4RWVND" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>悠哉看漫画转圈消食。有时候会看到表白被拒绝，然后表白方哭泣扇对方巴掌跑走的桥段。现在想了下，感觉好没有礼貌啊，为什么要打人家。</p><p></p></div><hr><div class="diary-entry">02:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWJY6Z7EF8KT34N48M2RF94A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前刚奶奶的讲完空调，今天空调坏了！跑到办公室里避暑逃避现实逃了一天，一回家看到室内温度 34 度空调还是坏的。</p><p></p><blockquote class="diary-thread-reply">05:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWK5M9SZ58G3K4NNDBKKB9EG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>修好了！！！</p><p>我和匹克猫在家顶着 34 度的室内温度终于撑到力大无穷的室友回家。然后我们修好了空调。</p><p></p></blockquote></div><hr><div class="diary-entry">05:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWK74CHPQA67J340AFJWQDQD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我有一个月没有碰 Kobo 了，因为我找不到它，而我找东西总是痛苦的，所以我甘愿让它来找我。</p><p>几天前，室友翻书包：「哦对了，上次我出去用了你的 Kobo，还给你。这个什么男人女人金星火星的书真不好看啊巴啦巴啦巴啦。」</p><p>看，这就是天意啊！</p><p></p></div><hr><div class="diary-entry">15:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWM83ATB57918VK7T45NXGGJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>本来五个小时前醒了，后来又睡了，一起来发现外面已经 35 度了。</p><p>今天最高温度是 39，朋友说从未想过自己最喜欢的数字会以这种形式出现，我说温度要把你 mikumikumi 掉。</p><p>我又一看，real feel 应该是实际体感温度，竟有 44 度，热死人得了。</p><p></p></div><hr><div class="diary-entry">15:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWM8ST6PRYDYJFDGZQ96GE8E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://news.kagi.com/s/k28r7c" rel="nofollow noreferrer noopener" target="_blank">https://news.kagi.com/s/k28r7c</a></p><blockquote><p> 警察局长 Jessica Tisch 表示，从 1 月 1 日到 6 月 30 日，该市共发生 322 起枪击事件，低于此前在 2018 年创下并在 2025 年持平的 337 起上半年最低纪录；此外，枪击受害者人数为 381 人，低于此前在 2025 年创下的 397 人的最低纪录。</p></blockquote><p>可以可以，虽然不知道关键因素是什么。</p><p>警察局欢呼枪击事件，会让我想起应该是去年，他们在 Twitter 上欢呼刚才多少分钟还是多少小时间都没有任何一起枪击事件被报告。结果内容刚发完的几分钟后就出现了枪击事件……</p><p></p></div><hr><div class="diary-entry">15:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWM9H1T2ND56RB00DVYC9MGQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://news.kagi.com/s/cca2z2" rel="nofollow noreferrer noopener" target="_blank">https://news.kagi.com/s/cca2z2</a></p><blockquote><p> 当局表示，两人于周三爬上了帝国大厦的天线，拉开横幅并在曼哈顿中城上空举行了一场看似求婚的仪式，随后于周四在曼哈顿被提审。</p></blockquote><blockquote><p>检方表示，Kuznetsov 告诉警方，他想为这次订婚「做点特别的事情」，而 Beerkus 在法庭外告诉记者：「我们相信爱情」。</p></blockquote><p>你是真超人。</p><p>不过 Kagi 生成的新闻简报出现了对名字的混淆，因为引用的第二段像是把 Kuznetsov 和 Beerkus 认成了两个人，其实这是男方的两个姓氏。</p><p></p></div><hr><div class="diary-entry">15:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWMA94J5CKQ2SMTJWGX5RHTB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://www.scientificamerican.com/article/raccoons-are-showing-early-signs-of-domestication/" rel="nofollow noreferrer noopener" target="_blank">https://www.scientificamerican.com/article/raccoons-are-showing-early-signs-of-domestication/</a></p><p>在城市里的浣熊开始出现驯化综合症的迹象。</p><p></p></div><hr><div class="diary-entry">16:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWMBQ2E6B0QQD11SGJ63919T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p></p><blockquote><p> 你以为你在…… 其实你只是在……</p></blockquote><p>我在记录会让我觉得有 AI 味儿的语句，以搞清楚它们的共通点。</p><p></p><blockquote class="diary-thread-reply">16:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWMBTWS9P32AX6C4VQTJ86YB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p></p><blockquote><p> 这不叫…… 这叫……</p></blockquote><p>其实都是「不是…… 而是……」的变种。</p><p>英语的 <em>not……but……</em> 还是挺常见的，现在变成这样，真是令人唏嘘不已。</p><p></p></blockquote></div><hr><div class="diary-entry">17:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWMF74Z726AJG1KWVWHTX7SY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>农家小炒肉里，会放萝卜片和鸡蛋的吗……？我以为就是青椒炒猪肉。</p><p>出来见朋友，顺路来吃之前没吃到的便宜饭。三菜一饭一汽水 11 块钱，不错不错，在曼哈顿待久了甚至会产生这是便宜我了的错觉。</p><p>这家店用的是机器炒，所以没有狭义的后厨，更没有后厨师傅。我印象里，机器都是塞材料进去然后高速搅拌，并不算「炒」。</p><p>我点了炒花菜、番茄炒蛋和农家小炒肉。这花菜选的是硬的白花菜（不知道怎么称呼），总之硬硬的不好入味，没有绿色茎的花菜好吃。我觉得我炒得更好吃！番茄炒蛋不说了，咋做都不会难吃，除非你往里面放酱油吧 —— 什么！你居然会往里面放糖！来战斗吧！—— 农家小炒肉是最失望的，因为没有「炒」，所以青椒和猪肉的味道根本无法激发出来，然后里面莫名其妙的胡萝卜和鸡蛋，差评！我最讨厌胡萝卜，还有煎蛋口感的鸡蛋了。</p><p>不过很便宜还是，最重要是家常菜，我喜欢吃。附近餐馆都是卖烧腊的，我还是没有那么喜欢广东菜……</p><p></p><blockquote class="diary-thread-reply">07-04 14:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWPS620VRWK8DDMTXHBSCWQ9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友：我的番茄炒蛋里有酱油有糖也有番茄酱。你知道最有趣的是什么吗，之前我让你吃了，然后你觉得味道还不错。</p><p>我：（掐死她）</p><p></p></blockquote></div><hr><div class="diary-entry">17:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWMFMDNS34CXC3JRGM5540MH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我真的考虑出门买个帽子了。我太热了实在是，太阳特别晒，我真受不了了。</p><p>我的梦中情帽是可以遮阳，上面再挂个风扇，接个太阳能天天对着我吹。</p><p>怎么感觉这个描述在哪里听过。错觉吧。</p><p></p><blockquote class="diary-thread-reply">19:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWMPCJCCSEDV0WNZDRXPWW22" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我不知道为什么母亲要选最热的今天出来吃饭？我提前出来跟朋友做活动，结果早上起来忘记喂猫了，下午两三点才起的室友打电话过来骂我 —— 这你猫我猫！你猫！推卸责任中。</p><p>本想着把妹妹落在我这儿的手机还给妹妹，结果突然发现她手机在我的另一个包里，所以只能赶紧回家取，再坐一个小时的车去饭店。</p><p></p><blockquote class="diary-thread-reply">19:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWMPMT5QTCVFHDF6C7HN47P6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友对我早上出去玩一事很不满，觉得我在浪费时间；又因为时间等同于金钱，所以我在浪费金钱；时间又是生命的一部分，所以我也在浪费生命 —— 罪加三等！但我在家里也没事做呀，家里不让拉窗帘黑漆漆的，我只能对着电脑不知道做什么好。跑 AI？Aigent 这东西一旦跑起来，我的注意力就涣散到不知道哪里去了。我又不想一起床就在学习，要学习的内容也很无趣。</p><p></p></blockquote><blockquote class="diary-thread-reply">21:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWMZ3MG8KRY2W0TFDX1CWK78" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>居然是 KTV + 麻将包厢，约定时间过去快两个小时人没到齐，也没有点单的迹象。好想早点离开…… 肚子不舒服还得回家嗑药去。</p><p></p><blockquote class="diary-thread-reply">07-04 00:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWN7G4SGAXASQDCB49PPBQWV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>虾球好吃虾球好吃，龙虾好吃龙虾好吃，我去好多肉好腻好热好腻好热好腻好热，怎么空调也是坏的啊这里 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​ 幸好 Kobo 带过来了可以一边读书一边吃饭一边将他们唱的歌和尖叫转换成白噪音或者 BGM。</p><p>虾球好吃虾球好吃，龙虾好吃龙虾好吃，可乐好喝可乐好喝。</p><p></p><blockquote class="diary-thread-reply">07-04 05:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWNSVJKYZXD8MA0KQ5VCADZP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>约定下午 4 点让我过来，但 5 点我才看到人。接着 5 点半入座，等其他人等到 6 点左右，然后点餐。一直到 7、8 点我才吃上饭吧，期间他们一直在唱 K。11 点左右母亲开车载我去拿家里闲置的空调，结果没有找到，打电话给父亲他说送人了，真想揍他一拳。最后我拿了个闲置的风扇走，凑合用着先。家附近有很多野猫，母亲看它们可怜，时不时会喂它们。开车走时，它们还跟着我们的车，我特别怕压到它们，于是下车赶它们走，它们也不怕我，还以为我过来是给好吃的。这样可不好啊。我还拿了家里不用的大锅、泡面锅、消食片和 999 感冒灵。</p><p>回家后看了眼空调，确实出现了和之前一样的问题。但不可能是滤网又出了问题啊？我拔掉插头、打开滤网看了眼，昨天刚清理的怎么会有问题。弄回去后开空调意外发现能用了。难道是得拔插头放电？</p><p></p><blockquote class="diary-thread-reply">07-04 05:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWNT07DG9K3ASCD5SNZ6BFV3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这期间还是有收获的，和业内人士继续聊天获取情报和帮助，呵呵呵……</p><p>屈辱唱 K，我唱得很差，但气势在就行了。</p><p>为什么他们对我会书写汉字一事感到很诧异？标准不要那么低啊喂！</p><p>无聊读书读得很难过，太容易代入到书中角色了。</p><p></p><blockquote class="diary-thread-reply">07-04 15:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWPTHJMPB2WX6A27V5WQYTEH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>好笑的对话：有人问我一个人住还是有室友，我说我有室友。他又问男的女的，我尖叫「当然是女的了！」</p><p>此处「好笑」的含义并非正向的。</p><p></p></blockquote></blockquote></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">17:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWMFTDB4WWY41AKVNXEQCMJY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这么窄的路，就两三个人能过，这么窄的路你还要走前面抽香烟。我要弄死你们。</p><p></p><blockquote class="diary-thread-reply">20:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWMSQXNMYH0BB2WA8KVHA61Y" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前在中文互联网上冲浪看到好多人吐槽中国烟鬼多，外国没有。因为他们都等量变成了毒鬼和电子烟鬼。传统香烟鬼据朋友所说是非常亚洲人的行为，所以在街头看到抽香烟的我还挺意外。电子烟在「二手吸感」上要稍微好些因为往往添加了甜甜的味道。公开场合碰到毒鬼就哭去吧。</p><p></p></blockquote></div><hr><div class="diary-entry">20:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWMS9PEW3VNT0DK5ST0CZF8C" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这 Transit 真是有毛病现在。N 车站门口就是目的地，为什么让我坐到下一站，然后骑共享单车坐回来？</p><p></p></div><hr><div class="diary-entry">20:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWMTYQZEJZPJRX4SWMM0RRVK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我找不到先前我提到向 Organic Maps 捐款的嘟文了。当时我说，因为被 Wikipedia 坑了下，所以现在我对捐款特别谨慎，决定研究一下 Organic Maps 再捐款。</p><p>今天我想起了这件事，说一下我的发现：</p><p>Organic Maps 软件是个离线的好软件不错，但是它背后是营利性有限责任公司，股东是可以出售项目或者变现获利的。事实上，它的股东确实也被指控对服务端动过手脚，开发者也自行在软件中添加过广告。所以我说，Kagi 转公司类型是一个很聪明的举动。</p><p>关于捐款到底去了哪里，有公开信认为被用于股东私人度假，但没有明确的证据。因为财务不透明，我们也不知道他们得到了多少捐赠，是否已经像 Wikipedia 基金会那样在 Benjamin Franklin 群里游泳，我们不知道。</p><p>社区里也有名为 CoMaps 的分支。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">The Absolute True Diary of a Part-Time Indian 剧透相关。</summary>        <div class="diary-cw-content">23:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWN3JSGWQJ98HX91VHSBAYRM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看到 Penelope 问男主是不是很穷的这章看得有点难过。人的复杂性有所体现吧。先前 Penelope 和 Roger 初见男主时都是瞧不起他，甚至歧视他印第安人的身份的。在之后他们成为了朋友，Roger 虽猜出男主很穷但在装和他们一样是中产，但没有点破，还借了他钱。Penelope 则私下直接和男主说开，并为他悲伤，让 Roger 开车送平时都是走夜路回家的男主回家。</p><p>单论他们的友谊是感动的。不过男主作为从未被如此关心过的，只觉得震惊。期间他还非常地…… 糟糕地…… 想着 Penelope 很性感。好吧，这个男主就是这样，我不太喜欢这个，但确实也是他的人设。</p><p>最终男主想着：</p><blockquote><p>If you let people into your life a little bit, they can be pretty damn amazing.</p></blockquote><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">The Absolute True Diary of a Part-Time Indian 剧透相关。</summary>        <div class="diary-cw-content">23:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWN410VT76QXNKRAE3J2TPCA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>男主和 Gordy 提起 Rowdy 的事情，并提出自己在 reservation 里被其他印第安人认为是叛徒一事。</p><p>Gordy 说：</p><blockquote><p><em>Well, life is a constant struggle between being an individual and being a member of the community.</em></p></blockquote><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">The Absolute True Diary of a Part-Time Indian 剧透相关。</summary>        <div class="diary-cw-content">23:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWN459J70FKD6J01Y0HEQ71Y" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>姐姐的信：</p><blockquote><p><em>They keep telling me I don't have enough experience. But how can I get enough experience if they don't give me a chance to get experience?</em></p></blockquote><p>Fuck, truth.</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">The Absolute True Diary of a Part-Time Indian 剧透相关。</summary>        <div class="diary-cw-content">23:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWN514EQ2B4QKGEVPQ5Y14V8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Coach said:</p><blockquote><p><em>If you care about something enough, it's going to make you cry. But you have to use it. Use your tears. Use your pain. Use your fear. Get mad, Arnold, get mad.</em></p></blockquote><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">The Absolute True Diary of a Part-Time Indian 剧透相关。</summary>        <div class="diary-cw-content">23:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWN6BYCAWE1EWCWZN72QX7H1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>男主提到，过去，印第安人会原谅甚至庆祝奇怪的特征。例如癫痫会被认为是来自神的礼物；同性恋者也被认为是有魔法的，因为男性会被视为是勇士、女性会被视为是养育者，而同性恋者两者都是。</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">The Absolute True Diary of a Part-Time Indian 剧透相关。</summary>        <div class="diary-cw-content">07-04 00:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWN92HQF5TQ2CB67W5936PGS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p></p><blockquote><p>……sure, Indians were drunk and sad and displaced and crazy and mean, but, dang, we knew how to laugh.</p><p>When it comes to death, we know that laughter and tears are pretty much the same thing.</p><p>And so, laughing and crying, we said good-bye to my grandmother. And when we said good-bye to one grandmother, we said good-bye to all of them.</p><p>Each funeral was a funeral for all of us.</p><p>We lived and died together.</p><p>All of us laughed when they lowered my grandmother into the ground.</p><p>And all of us laughed when they covered her with dirt.</p><p>And all of us laughed as we walked and drove and rode our way back to our lonely, lonely houses.</p></blockquote><p>Holy fuck, this chapter is sad and good and a masterpiece at the same time. I'm touched as fuck.</p><p></p></div>      </details></blockquote></blockquote></blockquote></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>七月四日</summary><div class="diary-entry">06:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWNVG5MHWQVZ1E9WBJA44PXV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我擦我真的遇到需要扫描 QR 码的 captcha 了。你们来真的啊。</p><p></p></div></details><details data-group="diary_sections"><summary>七月五日</summary><div class="diary-entry">01:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWQYNVJYQ14RRG6ZZ99NW6XP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>对《神奇数字马戏团》这个片有点兴趣…… 我看过它的第一集和第二集，但当时觉得这片有点被人们夸太多、猜测太多了，所以叛逆心理没有继续看下去。现在 BiliBili 首页一直刷到吐槽它的视频，我的叛逆心理又上来哩。</p><p></p><blockquote class="diary-thread-reply">07-06 18:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWWB0PCFVRT3B1H5Q8FZ836K" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>四五集还挺好看的，喜欢这种大家一起互动的场合。</p><p>然后我喜欢沉重的感情。</p><p></p></blockquote><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">《神奇数字马戏团》和《哎咕岛消失的舔甜歌姬》剧透相关。</summary>        <div class="diary-cw-content">07-09 15:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX3SPVP5PSAZNMR69F2J5J9A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天晚上看完了。比起最终回，我会更喜欢这些角色们的日常互动。不追连载的话对解密也没有兴趣。</p><p>综合来看比较一般，结尾很糟糕。我感觉制作方想要做出类似于《哎咕岛消失的舔甜歌姬》那样的结尾，也就是接受所处的世界是「虚假」的，并当作真实的世界继续活下去。不过做出来的感觉远不及《哎咕岛消失的舔甜歌姬》给我带来的震撼感。</p><p>关于结尾 Caine 放 PPT 的那段？现实里的角色有了更好的生活，和虚拟世界里的角色没有任何关系吧？大家虽然都很欣慰，但 Pomni 的台词表明了她不再是现实里的 Abigail，只是马戏团的 Pomni 而已，相当于已经放弃了现实身份，完全顺应虚拟身份活下去。这种写法自然是没有问题的，但这个片带来的观感非常…… 奇怪？</p><p>Jax 这个高人气角色的经历，说实话我觉得处理得很糟糕。我实在是无法接受一个平日霸凌别人的家伙，背后的故事竟是因为胆小所以冷暴力对自己好的朋友，导致朋友抽象化，然后继续欺负、疏远他人来保护自己。</p><p>然后是 Kinger 明明删除了 Caine，但它后面是怎么回来的？Caine 的处理也很草率，突然就联上了网，然后学习了真实的人类、将蓝球丢掉变成好人了。真要说，我不喜欢最终回的理由是它没有呈现一个我觉得合情合理的转折点和高潮吧。很明显，制作组花费了更多的时间与精力去写 Jax 的故事。</p><p>片尾有 Zooble 和 Gangle 在一起的小彩蛋。他俩和 Ragatha 还有 Gummigoo（他真的好可爱我无法抗拒一头软糖鳄鱼）是我在这个片里较为喜欢的角色。可惜的是，这个片似是不善于描写人物的转变，因为从头看到尾，会发现大家的设定变化并不大。就算 Zooble 中途有说过自己喜欢上了可以百变的身体，但在后来没有充分地展示这一点，在 Caine 爆发的那段依然将「对身体的厌恶」作为 Zooble 的恐惧点；Gangle 是角色中描写算多的，尤其是整个第四集都是她的个人回，但后来戏份越来越少…… 期间敢于反抗 Jax 了，但也只是展现了这一下；Ragatha 我是挺感兴趣的，可是制作组都只是把她当作死亡和安慰人担当，她的故事也只是作为背景板简单说了一下，明明沉重的感情也可以大写特写的……！—— 也有可能就没有沉重的感情，制作组想要将她设计成害怕不被需要的角色，所以她对新来的 Pomni 很在意，担心她和 Jax 绑定，并在之后说明她是最有可能抽象化的。可是！说是这么说了，但实际展现出来的，我认为完全不够说服我她会抽象化 —— 还有就是她对母亲的恐惧都没有真正地表现出来，反抗和克服也只是在现实身份那儿提了一嘴，然后没有了。她的设定明明可以挖掘一下，但止步于安慰人担当，让我觉得着实可惜。</p><p></p></div>      </details></blockquote></div><hr><div class="diary-entry">01:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWQYYX254JZW6YCRK45E1Q0K" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>喝可口可乐喝多了，再喝百事可乐别有风味。前者要更甜些，后者则有种「辛辣」的感觉。</p><p></p></div><hr><div class="diary-entry">12:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWS4EFRDGK4BET45NNAPBH7Z" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>终于不是一起床就是 30 多度的一天了，降温吧降温吧！不过今天睡过头了俩小时，幸好提前预留了时间，不然会想弄死自己的。</p><p>感觉有阵子没有遇到骂街的人了，因为前几天一直在办公室里蹭空调吧。出门会死的。今天出门不仅遇到了骂街的，还遇到了正在穿裤子不知道在干什么的。唉，装作没看见跑掉了，结果他乱丢塑料杯差点砸到我。</p><p></p><blockquote class="diary-thread-reply">12:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWS4NEAA3B3PAM4DFHRQCR4J" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>很闷，然后我意识到今天可能会下雨，而我又又又又没有带伞。</p><p>有了强烈不想要打工的想法。</p><p></p></blockquote></div><hr><div class="diary-entry">12:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWS5CS4S05X5CDJ5Y4MHFEA8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 时不时会在看 BiliBili 视频时然后看到弹幕要传谣，后来看视频就不开弹幕了，我会难以控制自己不去看它们。</p><p>在和貂的视频里，总是看到有人说母貂会让主人摸一遍宝宝，没有沾染上首领气味儿的宝宝就是残次品，它会咬死的。</p><p>自然界母亲杀死孩子并且吃掉它们是很常见的事情，对于貂而言也是一样，原因可以有很多种。并且貂的这个谣言根本就是「动物会杀死沾染人类气味儿的幼崽」的进阶版本，没有科学根据。</p><p>做貂养殖的都会倾向于貂生产后不去碰它们，让它们处于安静的环境内。并且它要是真信任你，就没有理由去弄死自己的幼崽啊？</p><p></p></div><hr><div class="diary-entry">17:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWSPYRTZ7S8SM9VA6FBM9GTG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打工的时候突然想到昨天运行部署脚本时好像弄一半就去做别的了。能感受到口袋里的手机在震动，该不会是我又不小心闯了什么祸吧 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 幸好是家里人在群聊里说话。</p><p>我反思自己不想要打工，是不是高傲、觉得自己不应该待在这里，属于屈才。但没有找到工作也是事实，不该抱怨环境；没钱更是事实，有钱就赚，要做个不要脸的人。</p><p>之前在饭局上认识的业内人士说，我要改名换姓，将自己打扮成更符合外国人印象里的中国人，或者更好地，打扮成 ABC 的样子。顺应刻板印象，才能让他们有好印象，也是很讽刺了。</p><p>名字，我得换个名字吗…… 我没有个正经的英文名，因为觉得没啥必要。听外国人们念不出来我的名字也很有趣。</p><p></p></div><hr><div class="diary-entry">21:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWT4NXAR3VMQDT1W0YFHNN7D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>特别好笑的事情：打工的店品牌是中国过来的，员工手册好像也是中国总部那边写的。</p><p>关于在处理水果（如青柠、柠檬）之前清洗它们，手册写「需要泡消毒水中十几秒、取出冲洗三遍才可以处理」。</p><p>但这其实在美国是不建议的 —— 他们说是违法的但我暂且没有找到依据，可能是市法？—— 所以在我泡上后店长飞过来大叫「快拿出来！」</p><p></p></div><hr><div class="diary-entry">22:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWT4TDX9WQXTTDBK25ZV1ZZC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我在学如何卷舌，发出 <em>RARRR</em> 的叫声。</p><p>室友很会，所以她说日语特别像动漫里的角色。</p><p>我没法一边说话一边弹舌，但是可以纯弹舌、发出像机关枪一样的声音：「哒哒哒哒哒 ——！」</p><p></p></div><hr><div class="diary-entry">22:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWT566VKZG1HADJ6NVY9Z9AH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>每天算钱，发现最可恶的隐性消费是交通费。之前还没有 all in 共享单车时银行账单里说每个月要花两三百块钱在上面。</p><p></p></div><hr><div class="diary-entry">22:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWT58P51EA4RG0FHRGV8DTT2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>月经好讨厌喔…… 听说可以靠磕避孕药来控制它。如果能绝经是最好的。室友觉得这种事情太反直觉了劝我不要弄。控制身体好难。</p><p></p></div></details><details data-group="diary_sections"><summary>七月六日</summary><div class="diary-entry">20:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWWG8SDSVWT07DZ5FD5RWDA9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天晚上不睡觉在 Fedi 友的 Minecraft 服务器里游荡，发现自己玩这游戏还是有点晕，以及自己很不会玩这款游戏这些事儿。</p><p>如果我没有记错的话，以前在电脑上玩这游戏玩最多的版本是 1.8。看 Minecraft 的视频最多的是主播们玩解密地图，比如扁桃，自己也做过解密地图，还模仿他们拍摄视频，不过未开智时不知道屏幕录制这种东西，所以架了台 iPad 在旁边拍摄。那会儿的移动版还没有红石，要做解密地图需要用到沙子；电脑上虽然有红石，但当时作为小学生的我每天只知道画破画，对红石所代表的另一个世界一窍不通，所以做出来的东西也很一般。朋友们也不喜欢玩生存模式，所以我们联机通常都是创造模式、开个超平坦然后盖大房子。再然后…… 就没有朋友再玩 Minecraft，而我转去玩路线更清晰的泰拉瑞亚去了。</p><p>近些年玩 Minecraft，一是想着它可以玩很久，能跟朋友一起玩，不过我们网速都不大行，或者是网易服务器的问题，总之卡卡的，放弃；二是妹妹想要跟我玩游戏，我又不乐意玩 Roblox，那会儿久违地搭建了些建筑，不过创造模式搭建完也没有什么其他的乐趣在了。</p><p>乐趣好像永远发生在过去。虽然小时候搭建的建筑很丑，也从来没有挖到过钻石，但和朋友们玩就是很开心。现在再玩，很容易晕头转向、不知道做什么好。</p><p></p><blockquote class="diary-thread-reply">07-07 15:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWYM9GTM0PXZ6RR602CYZMKN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我想要占个山头做山大王，然后山脚放牛。</p><p>晚上室友看野兽先生有关 Minecraft 的视频，看我在玩就过来霸占我电脑也玩玩看。我给她开了个创造模式的新世界，然后她开始大杀特杀…… 杀死所有看到的三文鱼、墨鱼、坏村民塔的屋顶……</p><p>斧头的伤害比剑高这一点，还未适应。主要是斧头伤害高的话，那剑存在的意义是什么！之前看主播们打怪会跳一下再打，不知道什么意思。</p><p></p></blockquote></div><hr><div class="diary-entry">22:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWWR9CAXB866TC6M2G4J9VSS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://nownownow.com/" rel="nofollow noreferrer noopener" target="_blank">https://nownownow.com/</a></p><p>在看 Alex Hsu 的 <a href="https://alexhsu.com/almost-met-sivers#:~:text=%E4%BB%96%E4%B8%80%E8%88%AC%E5%8E%BB%E4%B8%80%E5%80%8B%E5%9C%8B%E5%AE%B6%E6%97%85%E8%A1%8C%E7%9A%84%E6%99%82%E5%80%99%EF%BC%8C%E4%B8%8D%E5%96%9C%E6%AD%A1%E8%A7%80%E5%85%89%EF%BC%8C%E8%80%8C%E6%98%AF%E5%96%9C%E6%AD%A1%E8%A6%8B%E8%A6%8B%E4%BD%8F%E5%9C%A8%E7%95%B6%E5%9C%B0%E7%9A%84%E4%BA%BA%EF%BC%8C%E5%B8%B8%E5%B8%B8%E6%9C%83%E5%9C%A8nownownow%E4%B8%8A%E9%9D%A2%E6%95%B2%E4%BA%BA%E3%80%82%E4%BD%86%E6%98%AF" rel="nofollow noreferrer noopener" target="_blank">周刊</a> 时知道了这个网页，然后发现它能用来捞人。不过我没有 <code>/now</code> 页面，因为更新起来很麻烦……</p><p>然后我在纽约转了一圈，不错不错，没有看到认识的人。</p><p></p></div></details><details data-group="diary_sections"><summary>七月七日</summary><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWCMFQ86MKGHACKM40WHY92B">↩ 续前文</a>        </div> 03:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWX8SSX9JTYE7WQMQSTDK37N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我竟买到 Polo 质感的短袖衬衫。</p><p>又或者说是有更多扣子的 Polo 衫。</p><p></p></div><hr><div class="diary-entry">04:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWXE2H997N6J0BECRTFTCT43" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>买 SpaceX 的股我好后悔。感觉明天 NASDAQ 100 买进来也没啥用啊，一堆人等着抛呢（包括我）。</p><p></p><blockquote class="diary-thread-reply">07-08 04:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX00B80J0K7R3RJFMT3M3DHR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>跌破 150，太厉害了，做空的家伙儿得开心死。</p><p>万万没想到今天有人指控 SpaceX 数据中心的机器没有许可证就在跑 —— 想到中文课读的《老范》了，要不下一篇读后感就写你吧 —— 实在是不想要读财报和新闻啊，我没有这个习惯。</p><p></p></blockquote></div><hr><div class="diary-entry">04:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWXEKJD22YZC9HZZ59DHMNGN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p></p><blockquote><p> 沈むように溶けてゆくように……</p></blockquote><p>抖机灵，哈哈。</p><p>跑完室友吵着想吃炸鸡。路上两个人选好了吃哪个套餐，结果我要下单的时候才发现店关门了，室友说的「2 点关门」不存在，人家是休息日 1 点关门、工作日 12 点关门。</p><hr><p>说到 12 点，之前有朋友跟我吐槽说 12PM 是中午 12 点很反直觉。我的理解是时间从 12 开始，下一个是 1、2…… 把 12 当成 0 来理解就好了。</p><p>我更喜欢 24 小时制，不过我无法直接去理解它，想哪个点该发生什么时（如下午 6 点日落）依然会在脑中先把它转换成 12 小时制再想。24 小时制也叫 <em>military time</em>，但我不习惯这个叫法，我妹妹这么说我还得愣一下。</p><p>在中国我学习的是英式英语，时间的叫法很复杂印象里是。比如说 <em>20 to 8</em> 等同于 <em>7 40</em>。</p><p></p></div></details><details data-group="diary_sections"><summary>七月八日</summary><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW62GFCP227EF96S58BR5QAD">↩ 续前文</a>        </div> 04:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWZZK63NSEYBJP0926QFB7P9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有一把钥匙是当场机器直接印出来了，剩下俩今天才邮寄到，好慢。我拿着新寄到的俩钥匙，在包里翻找第一把，结果…… 我找到了一直没找到的旧钥匙……？</p><p>所以我这一两周一直带着它，且不自知，还花了 30 多块钱去配新的……？</p><p></p></div><hr><div class="diary-entry">04:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX0027J8XNB4FP9JM739WRBV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ44EHVDAKT706596R5DZ2.png" alt=":ottersgottaott05:" loading="lazy">​ 最近吃的饭好少，吃不饱，现在好饿，估计又得做夜宵吃了。</p><p></p></div></details><details data-group="diary_sections"><summary>七月九日</summary><div class="diary-entry">06:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX2RVDCC1VDPB1VCHGVK8Y5N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKPG9JXEBDFYC9RZH0AC9PB.png" alt=":cozy_otter_face_rub03:" loading="lazy">​ 去问了下本科专业的事情，结果发现大学是专业课程只看首次成绩的。算是之前消极上学且也不作弊的代价吧。问题也不大，不上就不上了。什么时候需要文凭纸再回来吧。</p><p></p></div><hr><div class="diary-entry">17:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX3ZCXTERVRT41BP0DGSTEY5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>蠢蛋店非要用蠢蛋微信建群、发笔记和通知。结果某产品的做法视频，被蠢蛋微信又弄无效，看不了了。你们就用微信吧，继续用着吧，一个两个的，在国外也要用这个破软件。</p><p></p></div></details><details data-group="diary_sections"><summary>七月十日</summary><div class="diary-entry">00:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX4R9AWQPH963EM2XCNERF5T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://zacharykai.net/notes/pb/" rel="nofollow noreferrer noopener" target="_blank">https://zacharykai.net/notes/pb/</a></p><p><em>People and Blogs</em> 是个每周更新的系列栏目，邀请并采访各个博客站主。</p><p>它原由 <a href="https://manuelmoreale.com" rel="nofollow noreferrer noopener" target="_blank">Manuel Moreale</a> 运营，现在被交给了 <a href="https://zacharykai.net" rel="nofollow noreferrer noopener" target="_blank">Zachary Kai</a>。</p><p>采访大致就是回答这些问题：</p><ol><li>能介绍一下自己吗？</li><li>你的博客站点是否有什么不为人知的故事？</li><li>在写博客时，你的创作过程是怎样的？</li><li>你有理想的创作环境吗？</li><li>你认为物理空间会影响你的创造力吗？</li><li>能介绍一下博客所使用的技术栈吗？</li><li>如果你今天要开始写博客，你会试些新东西吗？</li><li>运营你的博客需要多少成本？</li><li>它仅仅是一项支出，还是能产生一些收入？</li><li>你对个人博客变现持什么立场？</li><li>你觉得有什么博客值得一看吗？</li><li>你觉得我接下来应该采访谁？</li><li>最后，你有什么想和我们分享的吗？</li></ol><p>概念很有意思。</p><p></p></div><hr><div class="diary-entry">01:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX4S4TEM8CJZFR366NPHYQTS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>现在在用的 Pixelfed 实例挂了。放一张咪咪猫在这里。</p><p>大尾巴浣熊豹子老虎猫，要把幸运狗和匹克猫都吃掉。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KX4S30WPEKCQPWKQN3DH1V95.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">02:47 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX4YS7DWRGD47NWB3JSS0MK5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>跑步时用的计配速的 app：FitoTrack</p><p>F-Droid 链接： <a href="https://f-droid.org/packages/de.tadris.fitness" rel="nofollow noreferrer noopener" target="_blank">https://f-droid.org/packages/de.tadris.fitness</a></p><p>跑不动走路的时候，会很精准地掐掉计时，让人意外。</p><p>室友老要我去用有各种臃肿功能的悦跑圈。我都不知道它又要登录又要 AI 功能又要跑鞋功能是想干嘛。</p><p></p></div><hr><div class="diary-entry">04:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX54PDSWX9NQB9E4BQP2C4WV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今晚依旧夜驱。</p><p>路上听的是 AJR 的第一张专辑。他们的曲风同质化还是能听出来的，不过每次最吸引我的是歌词，很有意思。</p><p>虽然降温降到了二十多度，但闷热、潮湿的天气，让我没跑几步就大汗淋漓，难受死了。鼻子上流下的汗珠，让我的眼镜站不住脚，好几次都想滑下来。无果，我把眼镜丢包里，向着模模糊糊的世界跑去。</p><p>回家路上看到新开的一家甜品店，卖可丽饼、gelato 啥的。感觉有些少见在这个邻区里。我最喜欢的草莓香蕉可丽饼说是 11 块钱多一个，但室友不想晚上再吃 <em>goyslop</em> 了，所以不让我买 —— 上次我俩跑完回家吃泡面，她因为油腻吐了，我也不太舒服。垃圾食品还是少吃，唉。但啥时候我能买炸鸡吃啊。</p><p></p></div><hr><div class="diary-entry">16:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX6E3CEFQ87TS849DMSJ19G9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3FZ75C9HA8Q3KRW12YT3F.png" alt=":neocat_cry:" loading="lazy">​ 在处理 Stalwart 证书过期的问题。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">发泄情绪</summary>        <div class="diary-cw-content">17:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX6GFC6T8R20ZSSKE6ZA5KDG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想过上一日三餐都能在外边吃的生活；目标先设立个小的；话是这么说但服务业干多了觉得哪儿都不咋地，都挺危险的。晚上和室友在处理食物，聊起了现状、讨厌的人、未来…… 好像我做了个梦，梦到自己在公园的某个桥下，要执行什么任务 —— 我与谁都难以友好相处，一是我很容易讨厌别人，二是我很迟钝 —— 这个词儿是室友提出的；她觉得我很多时候都是非常迟钝的，尤其是在线下。我也觉得自己不咋机灵，但也不知道为什么会这样。我的本质好似就是那样，不迟钝的时候都是有精力用技能的样子，果然还是 skill issue 么？然后我很悲伤，觉得我难以被人喜欢上，反而时常被他人瞧不起。是我太敏感了吗？过去和别人说话时也是如此吧，我总会察觉到对方想要我表现得怎么样、说什么样的话，然后我也默默会扮演那样的角色。也很可惜吧，那些家伙儿观察久了也就发现都是些烂人，他们所想要的也只是能展现出自己优越感和魅力和特殊之处的平庸之人，亦或者是有问题的人。让自己扮演一个有问题的人实在是太搞笑了。我的事情，对室友来说根本不是大事；她反倒非常好奇，为什么我会沦落至此。我做不到的事情，反而都是她的强项。她也想知道为什么，我没有那么努力去解决这个问题，而是不停地在抱怨 —— 我现在也是在抱怨、自说自话，且总是会想，为什么非得是这样啊，没有社会想要的特质就不行吗、不是社会想要的样子就不行吗，巴啦巴啦。我还想到一个朋友的自嘲：他说为什么他不能吃够时代的福利，赚很多钱，然后老了对吃不到时代福利的年轻人们指指点点、觉得他们不够努力 —— 先前认识的业内人士讲了她的故事，她来美国后学习英语，改变了更像美国人的名字，然后学美国人说话、穿着，变得像是乐观开朗的派对主义者。她觉得我应该也做同样的事情，将名字改掉、换上更有女人味儿的衣服…… 我讨厌那样，可社会对于不幸运的人而言就是如此运转的吧。我讨厌世界上的绝大多数人，他们没有礼貌没有教养，嘴里总是在说着不知道哪里有趣的话题：男男女女；爱情；浪漫；你为什么不正常？你为什么和其他人不一样？你为什么变成这样子了！我是人口过多、多出来的那批人之一吗？我喜爱抱怨又没有解决问题的能力，喋喋不休的真是无用；装什么大尾巴狼；没有钱就是没有钱；学上得也一般；做饭也难吃；玩游戏还菜；书也读得马马虎虎；你觉得自己能写出好文章吗！训猫猫狗狗训一半；训小孩子也搞不懂他们在想什么；画画也放弃了吧！整天用 aigent 不会真觉得自己是什么编程大师吧！虚伪，太虚伪了！其实自己也知道吧，明明发生过那么多事情却一点长进都没有，都是自己不去好好思考、得过且过导致的。但对于接受这种事情，也侥幸地不去面对；知道又不去理解，没有脑筋儿！巴啦巴啦。</p><p></p></div>      </details></div></details><details data-group="diary_sections"><summary>七月十一日</summary><div class="diary-entry">02:43 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX7GXRWV85HQQSB220QTK9JB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>又和朋友聊 aigent 的事情。他那边发生了因为模型算力变化，所以写的 skills 要全部换新，否则不仅效率上不去，token 消耗量还会变多的问题。我的话，最近也发现了类似的事儿。</p><p>Gstack 是我几个月前在用的 skills 集，效果挺不错的当时，不过后来我仿照 TW93 的文章重新写成自己要用的 skills 集了。最近再去 gstack 看，发现他们的 skills 文件又变大了许多。简单来说，他们 skills 的书写规范就是：</p><ol><li>写明触发条件。在我印象里 LLM 这种东西比起交给它工具和描述（类似于我们人类拿到 API 文档），告诉它工具什么时候用准确率会更高 —— 是不是可以侧面暗示这玩意儿根本不智能，无法理解工具的原理且运用，只能见订单给东西；</li><li>写明什么命令允许被使用。其实这个可以通过修改 AI 工具的配置来实现，我还是认为塞给 LLM 的 prompt 它不会听 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KPH39KEXCFCTM562V9DT.png" alt=":neocat_laugh_sweat:" loading="lazy">​</li><li>猛写 if else。LLM 这个鬼东西想法很发散的，不告诉它啥时候不做啥、啥时候该做啥，它会乱搞一通。我想所有曾相信 AI 编码工具的智力有平均人水平的人们都吃过这个亏，哈哈，包括我，我才是大傻子。关于这个 if else，还有其他 hooks 啥的，其实我感觉都能看出运用 AI 工具最好的方法就是不要把它当成「人工智能」或者「智能体」。它就是个有点智力的猴子，你枪支给它又不限制它的能力的话，它就会化身美猴王上天下地嘚嘚嘚嘚嘚。同时介于这玩意儿给同一套提示词不一定会做出相同的行为，固定的行为可以直接写成一堆命令让它执行，比较常见的用处就是检测环境啊，巴啦巴啦啊，你懂的，应该吧；</li><li>输出（报告）时要遵循特定格式输出。这个其实还好，早在 GPT 3.5 都还没出来的时候就有这个做法了 —— 嗯我那会儿还训练过 GPT 3，感觉自己钱被骗了好多。当时 AI 工具就是 chatbot，然后人们开始折腾什么 prompt engineering，提示词工程。网上对于这门工程的说法，其实倒腾来倒腾去就是「说明白让 LLM 做什么」，这里便包括它输出时按照什么格式输出、我们输入时最好使用 """ 来分隔特殊文本等等。</li></ol><p>这意味着，该 skills 集随着越来越综合化，文件的内容也会越来越多。对于技术栈较为单一的项目，用这种 skills 集实在是小巫见大巫，虾米见蓝鲸。但就算我们自己写项目的特定 skills，也会随着代码的增多而扩张 skill 文件。补丁变得越大，最终会变成衣服的本体，而补丁坏掉的地方，也会添加新的补丁；那我到底是在给衣服加补丁，还是给补丁加补丁？真真假假，假假真真，呃啊啊啊啊 ——！</p><p></p></div><hr><div class="diary-entry">03:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX7KE599NNSNE24WM1GF6SVN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友调制出了好美味的酱汁。腌鸡肉用，不用裹粉或者面包糠，塞入空气炸锅 360 度 10 分钟就能得到超级好吃的脆皮鸡。之后她再做的时候我去偷个配方。</p><p>最近太热了没咋在家里待，一直往外面空调房跑，不然电费得弄死我。吃饭便成了新难题。热爱预制菜的室友，做了一大锅神奇的土豆萝卜黄瓜泥，往里面随便加入自己爱吃的蛋白质，例如鸡胸肉丝，然后再洗个生菜啥的，就能装盒带出去吃了，甚至不需要热。调味我当时看也只是盐和胡椒粉，很方便，不难吃。嫌味儿不够重可以找酱油洒点。</p><p></p></div><hr><div class="diary-entry">03:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX7MQG7RDXF9CNKNB0QABF6P" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不要再往博客站点放 Google 托管的字体文件了！我刚才访问博客站点时，发现卡住无法动弹。检查一看发现浏览器在请求 fonts.google.com、卡住了。我还没有检查该站点是否塞了一大堆 Google 字体的链接，但我们完全可以自托管字体文件，不是吗！我真是受够一访问就要等很久的网站了！上次是一个不知道在加载啥总之让我等了十几秒多的。</p><p></p></div><hr><div class="diary-entry">15:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX8VR8JPGKEGFCSSDBBS5VZG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚上和室友玩 Minecraft，她没有玩过所以算半个带新人，不过我玩得也不咋地就是了。</p><p>水底下怎么有会游泳的僵尸啊 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3FZ75C9HA8Q3KRW12YT3F.png" alt=":neocat_cry:" loading="lazy">​ 划船时两人被团灭了。</p><p>用指令找到了附近的樱花林，打算在那儿建个家。山脚下还有花地，看着让人觉得很舒服。</p><p>她给自己画皮肤时画反了…… 导致她的脸在头的后面，特别惊悚。</p><p></p></div><hr><div class="diary-entry">18:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KX98CW10GG2042N33XQBQCX8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>现在打工的这家店，问题有点多，想要跑路了。另一个原因是我接了个新活，如果做得不错的话日后的活也能接到。不过也得考虑下后路…… 他们经营额不达标，退款率也高，总部要求全员 cut。该说这才是正常的吗；本来这种店没啥生意的话就不需要五六个人在店内吧。Lead 觉得员工消极怠工，员工们则觉得这个工资不配好好做。确实啦，这个工资虽然在遍地黑店的这儿来说算有点高的，但终究还是最低薪资。</p><p></p><blockquote class="diary-thread-reply">07-12 02:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXA3T37GB5XN69CF52B7WF9Z" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>虽然话是这么说但我很怕跟别人提起离职…… 总觉得对方会大发雷霆什么的。不过目前提起离职的经历都没有那么负面，室友也说过离职是件很正常的事情。那我到底是为什么会这么想呢……</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary> 七月十二日</summary><div class="diary-entry">03:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXA6KKPJRZM26JNRZTGQXJR9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>震惊之在血统上室友比我更山东人，而我的山东人成分可能是零。</p><p>震惊！</p><p>当然我依然认为文化才是最重要的 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ29PV8EVY0F0F4HFRVXSCG.png" alt=":Blobhaj_Thonk:" loading="lazy"></p><p></p></div><hr><div class="diary-entry">14:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXBC6HHQ1QS1MPSV0FXMDGQE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://youtu.be/ium3BAuKyFc" rel="nofollow noreferrer noopener" target="_blank">https://youtu.be/ium3BAuKyFc</a></p><p>（我 Invidious 实例换了好几个都没能正常打开，姑且放个 YouTube 链接在这儿。域名处换成 Invidious 实例的域名就行了）</p><p>《舞萌 DX》的《アイアイ傘》MASTER 谱面，是少数我觉得很好听的雨衣唱的歌 —— 会这么想很大程度上也是因为雨衣较热门的歌都让我觉得…… 很不喜欢。</p><p>游戏有个进阶配置叫做「错位」，简单来说便是「键 A 击打星星头 → 星星开始划的一拍之前键 B 出现 TAP → 一拍到了，键 A 出现 TAP 且星星开始滑动」。让该配置发扬光大的是《ウミユリ海底譚》MASTER 谱面。</p><p>为了练习错位，玩家需要按照顺序搞明白这些配置：</p><ol><li>延迟星星，即星星头被击打后会先出现 TAP 供击打（往往是其他键位上的），打完才能滑动星星；通常很慢</li><li>拍拍划，即「星星头 → 同键上的 TAP → 滑动星星」；通常很快</li><li>拍划，即「星星头 → 同键上的 TAP 被击打后同时要滑动星星」</li></ol><p>因为《舞萌 DX》的星星头在被击打到开始滑动的时间间隔是一拍（快慢看谱面的 BPM），错位本质上就是「星星头 → 延迟星星的对星星理解 + 拍拍划的第二步但在其他键位 → 拍划」。要打好错位，重点是搞明白第二和第三步。</p><p>在错位练习的路线上，就有《弱虫モンブラン》MASTER 作为很慢的练习谱。不过这个谱面整体速度很慢，需要同时期应该在练习 EXPERT 12+ 和 13 的大猩猩玩家们放慢速度…… 感受慢慢的节奏…… 再加上音符量不多，导致百分比的完成度会因为绝对数量上很少的失误而被大幅影响。</p><p>贴心的《舞萌 DX》提供了这首歌的「强化版」，也就是《tape/stop/night》MASTER，一开头就有《弱虫モンブラン》MASTER 的难点即速度较慢的错位配置，后面还全是没有练习过就容易脑子打结的一连串拍划套拍划、换手拍划。</p><p>无名歌 MASTER（通常是管其叫「如月车站」，之前在 Apple Music 上看似乎是叫《/////////》）也有一模一样的慢速度错位配置，但对于拍划的练习力度远不如《tape/stop/night》MASTER，更像是一个较为综合的主星星配置的 MASTER 谱面。</p><p>RE 的这个《アイアイ傘》MASTER 则在我看来是强化版的《tape/stop/night》MASTER。拥有更多的换手拍划、让人脑子打结的多拍划、拍划拍划拍划。</p><p></p></div><hr><div class="diary-entry">15:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXBFWX0KV1B5E6XBS3AWTWJ6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>沪上阿姨的饮品，喝起来像在吃饭，而不是在喝小甜水，让我心情复杂。</p><p></p></div><hr><div class="diary-entry">16:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXBK7M6D0CDET2B73B9Z3MHG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>感觉自己又上火又肚子难受，一上称发现之前增的重又没了，有被气到。打工害人啊，让人无法按照正常的作息规律吃饭。</p><p>早上倒腾点服务器运维和安全的事情，感觉还是不太懂这些东西；这还夹杂着 AWS 使用的知识，幸好其他人也不会 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4TFD239TJ4YG6N2ENQBK.png" alt=":ottersgottaott25:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">16:43 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXBKDMFWEAMPEKQBND5N8SM8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不对，还打喷嚏，喉咙有黏稠感，不会是感冒了吧。不要啊 ——！</p><p></p><blockquote class="diary-thread-reply">07-14 15:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXGJZSME5Y89WS6JJDQ106FZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天醒来发现身体里面很干燥，上颚也很痛。昨天已经喝了很多水了，希望能快快恢复。</p><p>祈祷 nya 🙏</p><p></p><blockquote class="diary-thread-reply">07-16 16:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXNVV33P7XR6FE446HVCS5AB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>现在的身体状况是：</p><ol><li>上颚依然很痛，怀疑是之前吃东西烫伤或者磨伤了。吃大块的东西如果会碰到上颚我会很难受</li><li>鼻子难受，感觉里面干干的</li><li>喉咙黏糊糊的，但也有干干的感觉</li><li>肚子不舒服，胃有点胀胀的</li></ol><p></p><blockquote class="diary-thread-reply"> 07-16 17:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXP0567TW3CT25WSG0Y7G3B2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>感觉要，撑不下去了…… 可恶，昨天晚上煮好的好吃的花菜，居然因为花太大、会碰到上颚烂掉的地方，所以吃起来痛不欲生…… 整个感觉很像是以前得新冠时的样子。喉咙里总觉得有什么东西，但是黏在内壁上弄不出来。肚子不舒服以为是还没吃饭导致的，但是吃了后依然不舒服。上完厕所后依然如此。难道说，我其实生病了吗！</p><p></p></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">23:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXCC41X6TYQT4Y2WW773AXVR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>正式离职前上班的最后一天。</p><p>前辈嫌我做得不好（但试工来的你还想怎样啦）：你干嘛这样这样。你那样那样不就好了吗，下次记住了不要这样弄了（但我要怎么记住没有人告诉过我的事情啊）。</p><p>我心想：这个人在说什么呢。</p><p></p><blockquote class="diary-thread-reply">07-13 00:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXCCCAWCM8RHR5JZCMXWKV3J" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>至于为什么说我是试工的，因为我是转正当天离的职，他们要求先签 offer（奶茶店转正说「签 offer」真的好奇怪……）再签离职书。你要说我是正式工吧，但我试工这几天也只是在疯狂被使唤去打杂啊。很多事情都没有人教，今天忽然让我上岗做，教训我的时候没有想过我不会做吗。</p><p></p><blockquote class="diary-thread-reply">07-13 00:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXCCKKQPEWBD1CZXB5FXNVEP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>还有保密协议要签。但奶茶店的配方随便试一下就能试出来，材料都是一样的，看你能不能买到味道相似的吧就，尤其是粉和浆。就是面向消费者的材料会更贵一些，搞冰还要买制冰机。上次打工的地方举办圣诞节活动，让同事们互相送彼此礼物。结果我写「制冰机」，笨蛋 ABC 同事以为是「刨冰机」，送了我一个我妹妹都不要的儿童刨冰机。</p><p></p><blockquote class="diary-thread-reply">07-13 00:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXCCNZFE4MM3E4NZKGJWT2HV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>保密协议签不签都无所谓其实，因为我不记得任何一家打工过的店的配方。理由是他们没有啥好喝到让我会记住配方。</p><p></p></blockquote></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>七月十三日</summary><div class="diary-entry">00:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXCD65NCZVAS142ZW5SXNDT6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>吃饭呢感觉余光有什么东西在动。一扭头发现是一只肥硕的松鼠在我旁边看来看去。</p><p>松鼠和鸽子感觉是这里很常见的动物。以前在中国待着的时候看到的都是麻雀。那会儿还有野狗。记得野狗们占据了家附近一座废弃的寺庙。我小时候年少无知，对着寺庙学狗叫。它们狂叫几下，从窗户探出头来看着我。我尼玛，好大的狗。</p><p>野猫们则都被大大收留了。不说「收养」因为他只管喂饭不管别的，在我看来和「收养」的标准还是不太一样。店屋顶好多野猫，它们都怕人。一只不怕人的在店里面当吉祥物。但有天晚上它跑出去被流浪汉打断了腿，休养了许久。</p><p></p><blockquote class="diary-thread-reply">02:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXCN5D935ZWAY3D9W1CB1DQB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>没有味道的鸡胸肉三明治…… 我吃不习惯…… 室友倒是很乐意吃。我俩的舌头完全无法喜欢上彼此。</p><p></p></blockquote></div><hr><div class="diary-entry">02:43 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXCNQ2KXST6AAT13P8G40SYD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>是时候该写个 <code>/hates</code> 和 <code>/likes</code> 页面了…… 骑车期间想到了许多我讨厌的东西，例如尾灯宛如远光灯一般闪烁，还会一停一亮的奇怪电动车…… 我的眼睛快瞎了……</p><p></p></div><hr><div class="diary-entry">02:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXCPJY45DE2W21NPGYN6DV66" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>高中时有位很喜欢的老师。说实话她很负责任也很有同理心 —— 这点很奇怪说真的，我上的高中里面，学生大多数，恕我直言，都是没有前途的家伙儿。但教师都非常负责任、人很好，里面也包括了数个帮助我脱离家庭暴力的教师。</p><p>她本职应该只是教授图形设计专业课的，但她在学校里设立了个，嗯怎么说呢，after school area？也不是 club。总之学生们放学后也可以去她的教室里干事情，她还会帮助学生们写简历、申请大学等等。因为学生多数，sorry，没有前途，有些就喜欢顶撞她。一天，她的饮料竟被学生下药。我不知道具体发生了什么，总之所幸没出大事儿。</p><p>后来她离开了高中，想要为自闭症，或者严肃些，有孤独症谱系障碍的儿童们出一份力，所以打算自己弄个组织。我印象很深的一次是她跟我们说，街上的流浪汉或者神经病们虽然很多、我们可能觉得很烦，但是不要故意找他们茬，因为我们不知道他们经历了什么；我们只要无视离开就好了。有能力的，可以和他们说说话、帮助他们（如果他们有在乞讨的话）。</p><p>不过我当时快毕业了，也因为其他的事情，没有和她走太近，所以不知道她做得如何，也没有她的联系方式。</p><p></p><blockquote class="diary-thread-reply">03:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXCPYST5GMRD94MPMYKV9G9Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>好吧我实在是不喜欢自己喜欢随便否定他人人生的做法，尽管我有时候真的会这么想 🤷‍♂️​ 为了安慰自己，我会去参照室友平日在想什么，然后发现她对人类的标准更高、更严格，以至于她不认为高中的同学们是人类，只是有点智力的猴子，我便成功地安抚了自己不是个坏蛋，因为有更坏的人 —— 三个小孩的家庭被无视的往往是老二嘛。</p><p>高中刚开学时我就被校外的疑似 gang activity 吓到。后来又发现各种人类小孩子奇怪的行为，比如什么 bake sale 时在 muffin 里面塞大麻、在厕所里抽电子烟和吸大麻、在学校附近打警察…… 大家都习以为常了，不过我还是好想吐槽一顿啊：草！</p><p></p></blockquote><blockquote class="diary-thread-reply">03:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXCR07DRHZRBN97YGHS8Y949" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>关于孤独症谱系障碍，我身边的人们多数是因为社会化差所以表现出类似的样子 —— 比如我就有这个倾向 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​—— 不过我也确实认识一些真的有该障碍的人们。比方说我的一个远房亲戚，或者说我母亲朋友的远房亲戚（这些怪异的称呼让我总是不知道谁是我真正的亲戚、谁不是，以至于曾经有个亲戚以为我俩没有血缘关系，然后向我表白了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​），她的女儿生下来就有该障碍。但是无知的大人们都觉得是该女孩「没有走出来」导致的。因为我表妹有抑郁症，还被他们带去驱魔、做法事，所以我估计这个女孩也会被做同样的事情吧。我已经跟母亲讲过了，这种障碍是先天的，「没有走出来」听上去像是对方选择如此，但她听也没有听进去，真是大脑空空。另外几个我能更近去观察到的，能够从他们的思维模式上察觉出和他人的不同。无法叙情相当常见，他们也难以发觉到其他人的情绪，更不用说去理解和共情了。较为悲伤的是，他们搞不懂话的真假，所以会被别有用心的人利用。</p><p></p></blockquote></div><hr><div class="diary-entry">15:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXE1KB7XM043PSYHMV81K1EA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友暑假在上 business communication 的网课。</p><p>教授：许多 XX 院的学生毕业后，去公司上班，被公司发现有严重的心理 / 精神问题，所以设立了这门课。</p><p>虽然说不意外该大学的学生们会有心理和精神问题啦…… 但改善该情况和 business communication 有什么关系。</p><p></p><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">发泄情绪；私事，没有语境。</summary>        <div class="diary-cw-content">15:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXE2CQ7EN3DBHC1B17D0D2X7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说到心理 / 精神问题，让我想起大一还是大二时发生的不愉快的事情…… 某个讨厌鬼曾经说过，可以通过这些特征识别患有抑郁症的人：不会频繁清理自己，比如不刷牙导致牙齿能看到污垢。但这家伙儿说这种话，让我只会觉得「你凭什么说得出来啊！」明明只是个单纯为了自己的 FOMO，在公共场合对着有抑郁倾向、身陷各种问题之中的人做出表白般的举动，还让其他人录下视频发到网上的恶心家伙儿。你知道最后要处理这些抑郁问题的人都他妈是谁吗！真是又自私又幸运的人啊，只用想着自己、随意糟蹋和伤害他人，却也从来都不用付出任何责任，对我也只有轻飘飘的、让他人转达的口头道歉，结果在未来还依然记恨于我不原谅他…… 这种人还是高速公路上开到 100 迈然后刹车失灵出车祸死掉好了 —— 这是气话。</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">发泄情绪；私事，没有语境。</summary>        <div class="diary-cw-content">15:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXE36PZ15QPT8MRCN64KGAJP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我的内心深处也记恨着所谓的受害者。我无法理解为什么这种可恶的人都这样了，折磨着自己数年却依然要和他成为「朋友」。我的错及罪孽是不理解和不接受你们，是吗。你有什么资格跟我说这种话。起初威胁我的是谁，道德绑架我的又是谁。自己要深陷泥潭，去当个救世主「拯救」不该被拯救的人，不要拉上我！反正我的想法如何，也不重要吧。他的所谓问题，就很重要，我的挣扎与求助，就根本不是事儿了是吗？为什么？因为我表现得不够像是个幼稚孩子吗？还是你觉得我可以解决自己的问题，所以就不用管了是吗？天天「你也有错」「我们都有错」，不知道在说些什么。我的错和你们的错是同个量级的吗？我连那个讨厌鬼的事情都考虑过解决方案，结果落得被他记恨的下场，背地辱骂我，这就是我的错吗。我想方设法不无理取闹、找出对你有益处的解决方案，这也是我的错吗。</p><p></p></div>      </details></blockquote></blockquote></div><hr><div class="diary-entry">23:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXEVXECK450MRSEWJSVBWF44" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>吃饭吃不饱，把 Panda Express 填写 survey 的折扣码用了，再买他家的饭吃。这次点的是三菜一饭，菜选了西兰花炒牛肉、橙皮鸡（室友好奇味道，但我已经猜出来了……）、经常听留学生们说很好吃的核桃虾。</p><p></p><blockquote class="diary-thread-reply">07-14 00:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXEZPX7QW490R68J01HBB243" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>西蓝花炒牛肉依然挺不错的；橙皮鸡果真如我所料，非常甜腻；核桃虾虽也甜，但没有橙皮鸡这么腻歪；我没有选饭，而是选了炒面，吃起来和炒饭一样一般，能吃出面内的粉味儿，不喜欢。</p><p>自取路上看到路边停了许多大巴，下来的人看着都像是学生，难道是哪所私立学校举办的 field trip？小时候我也参加过，但都是当天去当天回，去的地方对当时的我来说也没啥意思 —— 现在反倒是能感觉出博物馆的好了 —— 从来没有和同龄人去过酒店住宿。反观这些学生们，他们下车都要来大巴的侧面取行李箱，真是羡慕。</p><p></p></blockquote></div><hr><div class="diary-entry">23:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXEW73PNX09Y7TFTY7BMXFYY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我忽然开始思考，长袖配短裤或者中裤的可行性。</p><p></p></div></details><details data-group="diary_sections"><summary>七月十四日</summary><div class="diary-entry">03:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXF9M3DXEAN8XXTSDSHWCK6E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有段时间没有上 Cloudflare 的仪表盘看了，结果一进主页怎么是个搜索框，看上去像是 chatbot 的首页。</p><p></p></div><hr><div class="diary-entry">03:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXFA52NHSZ29EZVCGAA9PK9Z" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>发现上次更新主站（领地）的页面已经是三个月之前了。这个月也没有什么读文章、写东西的心情其实，把本子放包包里，做事情累了画点东西也不错。</p><p></p></div><hr><div class="diary-entry">04:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXFCZ51TNJ3QPMW6S684VNN4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>老实……</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KXFCYRZ4CWYQDK8FYARCTD72.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">16:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXGNZ0AYPKCJ465R45G2JV2T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>真是奇怪。7-11 的 android app 我下载安装后无法正常开启，会立即闪退。在网上搜索了下貌似是不支持 Android 15 或以上，而我的手机系统用的是 Android 16—— 顺带吐槽一下更新后开启 app 会有个放大的动画，但我觉得有点慢，是过度动画的一种。</p><p>所以我在 iPad 上安装了 7-11 的 app，它被我用来当作专门安装 app 的设备真是不错。不过这个 app 没有做 iPad 适配，所以右下角还有相当经典的放大放小按钮。</p><p>那为什么我要下载该 app 哩？因为 T-Mobile 每周二会送免费的 7-11 大杯饮料，我想要领一个喝喝。但要领取的话就必须要安装 app…… 我被免费饮料冲昏了头脑。</p><p></p><blockquote class="diary-thread-reply">18:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXGX8CYWB27Y4RJN3X465NFR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>弄了百事可乐喝。最近对百事可乐很是喜欢，尤其是其后来的微微辛辣感，喝起来也没有可口可乐那么甜，放一段时间也不会因为没气而变成恶心的甜水。不过 7-11 这个自助机器，也不知道是我放了太多冰块还是什么（但我之前喝百事可乐也会放许多冰块），喝起来既没有辛辣感也没有独属于可乐的味道，像是有点气泡的水。要不是颜色就是可乐的色儿，我就会以为这是什么气泡水。</p><p>大杯的 2.70 块钱左右。用了 T-Mobile 给的折扣就是免费。也没有节省多少钱。现在还因为手机无法安装 7-11 而没法随地使用折扣码、得单独带 iPad 出去领，太麻烦了。</p><p></p><blockquote class="diary-thread-reply">18:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXGZSYVCTG6C3J50T5VAG60E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>喝多了令人失望的饮料之后，便会愈发感叹温水的美丽。我尤其喜欢家里烧的白开水，不清楚为什么；父母家里的水喝起来不好喝；办公室里的就一般般吧，可以排到 tier 2；矿泉水得看牌子；大多数餐厅的饮用水都是恶心的自来水，呕呕呕。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">21:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXH9TDQ8F6R7XB6VTJEW49TN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>项目管理虽起初是我的朋友，不过实际工作时很看重立场。对方认为，我是打工的那个，无论他要求我做什么我都不允许反抗。也就是说我需要在工作时将他与平日的他剥离开来，当成陌生的老板来看 —— 这自然是困难的，我难以做到。于是我被单方面骂了一顿，起因也不过是一件再小不过的事情了。从小就被骂到大的我对于这种事情也没有啥反应，麻木了，你说就说吧。不过他很喜欢在教训我时连带着人身攻击、羞辱我，这我实在是受不了。我叫他不要再人身攻击我了，他解释说是我甩脸色先、我恶心到他了。那甩脸色和人身攻击是同个东西么？他又辩解说都是不尊重的一种。那我脸色都甩了，顺带再骂他是个不懂装懂、好面子的烂货，得到的惩罚是同样的吗 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3EQQJ0WWJ5EQ79NS9AMS5.png" alt=":neocat_angry:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">21:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXH9XPHZ3ZHJDVF11NH8YBY9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>因为没有事情做所以在做品牌设计书…… 我不会设计品牌…… 好吧还是懂一点点的…… 但这才不是我的本职吧！</p><p></p><blockquote class="diary-thread-reply">23:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXHF3KMME4DBQFKB0FQAJGMX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Canva 上传字体文件要会员费，所以我在电脑上安装了 LibreOffice Impress，来做这个破设计书。但我没有想到，该软件拖动对象，不会自动计算和周围对象之间的 margin！所以我要手算吗！虽然可以用参考线，但我不太会用这个东西，知识已然还给学校……</p><p></p><blockquote class="diary-thread-reply">23:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXHFN42MQ1DQ7N26K64KBCXK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我好讨厌这些软件。为什么文字框明明选择了 <em>resize shape to fit text</em>，但对象的框依然小于文字本身啊……</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">07-15 00:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXHHEJPGWRH88SMX0RQ66DSD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我让 AI 工具帮我搜了些方向类似的品牌，并查阅他们的品牌设计书咋做。有几个很漂亮但是和公司的品牌不太对得上，所以我 <del>抄</del> 参考不能。最后还是让 AI 工具根据我的要求做了点样本。虽然很丑但有了点启发，还算有用。有趣的是 Claude 设计出来的东西，很有 Claude 的感觉。虽然没有太常见以至于让人感到恶心的圆角卡片排排坐，以及用到烂的渐变紫色，但 Claude 非常喜欢做出它觉得的「终端感」、添加莫名其妙的小字 + 方形框。</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>七月十五日</summary><div class="diary-entry">01:43 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXHQ28YR2KJEW46DB9KKWGJR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>雇佣童工……！</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KXHQ07G1MRHEBWNA8CSXHJN3.jpeg" alt="超市里，非常迷你的 savoy cabbage，和正常大小的放在一起做对比。" loading="lazy"></figure><blockquote class="diary-thread-reply">02:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXHS9PH8FZ6WM9DWWXZCB9N7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>你有病啊。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KXHS6N09KY8QEFH6EK27RXJQ.jpeg" alt="超市冰柜里，原价 9.99 美元 16 oz 的鱿鱼圈。" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KXHS6NC85PKNNPEX6DPAHHCM.jpeg" alt="超市冰柜外，标着打折后 10.99 美元 16 oz 的鱿鱼圈的纸。" loading="lazy"></figure><blockquote class="diary-thread-reply">02:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXHSHPVRBNKTHHJB1ABEBNKM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Weee！五包 9 块钱，你单桶卖 4.6！</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KXHSE4B006HQRDMJNP89VC5E.jpeg" alt="超市里一桶火鸡面 4.59 美元。" loading="lazy"></figure></blockquote></blockquote></div><hr><div class="diary-entry">02:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXHT54RZ5XKHAQMPVWQSXVGQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>几天前和朋友聊起主流社交媒体的罪孽，主要就是侵占用户数据、隐私和匿名性，然后有了基本盘后做烂事情也会被得过且过的用户们原谅 —— 我会聊起这件事还是因为之前打工的店用微信群分享笔记和文件，结果被破微信弄失效了看不了 —— 对方觉得就算如此，也没有必要去了解去中心化的软件，因为一般人没有需求：「就算知道了又如何呢，为什么要花费精力去了解这些一般人不用的东西？」也是啦，现在能一个人乱发东西、说说这个说说那个多亏了身边没有人对这方面的东西感兴趣，不然我会拘谨许多吧。应该吧！</p><p></p><blockquote class="diary-thread-reply">03:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXHW7SN8ECQTX8XZ5HJBDWZY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>较为意外的是对方使用过 Signal。虽然我也有该软件，但从来没有使用过，理由便是没有人陪我用（以及使用电话号码注册有点…… 我不喜欢总之）。当时他回国，美国的朋友不愿意使用中国的软件，他才退一步陪美国朋友使用 Signal—— 难道只要自己够奇怪、不愿意退让，就能注销掉微信啥的，也不用在乎未来是否有人要求我使用了么？这位美国朋友我知道是个倔强的人。</p><p></p></blockquote></div><hr><div class="diary-entry">03:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXHVF6RDCHQ87M6PSSYPV2JZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前几天，没有名字的黑螺去世了。它的尸体不见了，只剩下空壳。恐是我那段时间不怎么在家，过了太长时间被其他食腐的生物吃掉了。现在鱼缸里除了两个杀手螺外见不到螺，鱼也只剩下两条恶霸般的天使鱼，和卧沙的 kuhli loach。再过一段时间，杀手螺们也会一个个去世，kuhli loach 们也会吧。只有这两条邪恶的天使鱼，会一路活到匹克猫可能都去世的时候。</p><p></p></div><hr><div class="diary-entry">05:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXJ2ZRY0WD2SQ0C804NS5Y6M" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>OMG 我在用自己的 AI 工具检验同事用 AI 工具生成的报告是否正确，然后生成有着更准确数据的新报告。</p><p></p></div><hr><div class="diary-entry">12:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXJW9FHTQ7YKQBKGTP35TXNE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>邮箱别名系统总算派上用场了。</p><p>我先前为了工作注册了 Sav 的账号，在他们那儿购买了俩域名。用 Sav 的理由是有个特殊的域名我找了半天就他卖。</p><p>现在陆续会有这样的邮件，发到我只用来注册 Sav 的邮箱别名上。因为购买的是域名，所以他们说的是网页设计和开发，还算正常，但这些发邮件的也获取到了我填写到 Sav 的名字。</p><hr><p>EDIT：排查一番发现是域名问题。域名的特殊性以至于 WHOIS 隐私保护无法开启 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 擦那你为什么最开始不告诉我啊。晚点弄过滤规则去了。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KXJW1WBP0X3EMFG3Z3CTAY3H.png" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">16:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXKAXVWE1XH1WRE3898RDEHD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>奶奶的我这个邮箱地址别名和手机号码都被泄漏出去了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 我得弄三个手机号码了。</p><p></p></blockquote></div><hr><div class="diary-entry">13:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXJYXDRTPFKQ4S09ZY0NVN33" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天晚上，或者说今天凌晨，继续和室友玩 Minecraft。这次跑去洞穴探索，挖了好多铜。感觉它的定位是便宜的护甲，不用再去屠杀牛牛做皮革甲了。</p><p>铁还没挖多少，就在一个特别大的洞穴里陆续发现了金子和钻石。看到钻石时我一愣，这玩意儿有这么好找吗，为什么我以前玩都找不到这东西！</p><p>然后在洞穴内找到了一处没见过的新生态：地上有着许多深蓝绿色的像苔藓般的方块，还有像海带一样摇摆摇摆的方块。声音似乎会激活它们，让它们发光。接着我的视线会变暗，看不到远处，堪比恐怖游戏。对这个生态有点印象，几年前看到批评该生态设计的视频出现在我的首页。</p><p>虽然有斧子用，但想要学一下矛咋用。目前没搞明白是它应用场合就少，还是我不会用。冲刺也没有觉得伤害多高。</p><p></p><blockquote class="diary-thread-reply">13:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXJZGACFMTD152NSRSHFKP05" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>圈了羊、牛和鸡。没有萝卜暂时不抓猪来。</p><p>种了小麦，发现该植物的样子和过去我记忆中不太一样了。我等了很久还以为是未成熟，后来打掉一个才发现已经成熟了。</p><p></p></blockquote></div><hr><div class="diary-entry">16:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXK8KT47FHRK9Z1RSW78035A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>开智后第一次来到 Bronx。红色车，从火车站开始坐，看着车上的人从白皮肤慢慢变成黑皮肤。下地铁后，又跑到巴士站坐巴士，经过一个看不懂店铺语言的小镇，到更为偏僻的地方才下车。今天过来是陪室友考试来的，她为了个 70 分就及格的证书考试复习了好久，我不知道她随手考就 90 多分到底在焦虑个什么。等待期间我在附近转悠。太阳当空照的，热得要死要活。</p><p></p><blockquote class="diary-thread-reply">16:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXK9E7EAM1Q0T1A7J2SGN5YC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>点了麦当当吃。自助点单机旁边会挂着许多牌子。如果要堂食的话，得先把牌子拿下来，然后在点单机上输入牌子上的号码。支付后拿着牌子到座位上，服务生会根据牌子找过来。</p><p>初中的时候带着母亲和她的朋友，还有一些小孩子这么点过。当时点了许多吃的，服务生还多给了咖啡和橙汁，怀疑是别人的给错了。那是我第一次喝咖啡，我记着我找前台要了 12 包糖和 12 盒奶。之后我点麦当当的咖啡都是这么喝，直到我意识到我再这么喝我就会得糖尿病死掉。</p><p>麦当当的 app 上有个买 7 块钱送杯子的优惠。果断购买原本是 5 块现在是 6 块的套餐，然后还差的 1 块、我将套餐的饮料换成了草莓西瓜汁。</p><p>我看到周围有个女人，买了儿童套餐，想必是来收集玩具的。过去几年麦当当和 Crocs（应该是这么叫，总之是洞洞鞋）还有宝可梦卡牌联动，好多人都来买儿童套餐收集东西。我被委托也去了。</p><p>服务生妹妹一看就是新人。哼哼这就是在服务业打工久了练出来的没有意义也没啥厉害的技能。</p><p>操，怎么是纸吸管。</p><p></p><blockquote class="diary-thread-reply">16:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXKBFSQ8P83JKY6MXR95YDYH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>完了，打工的店做西瓜相关的饮料都是用真的西瓜榨汁。这杯草莓西瓜汁的味道，竟是我没有尝过的西瓜口味压缩果浆的的味道！我感觉好挫败，虽然挫败得莫名其妙。</p><p></p></blockquote><blockquote class="diary-thread-reply">17:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXKBVAXYH8WY7SSJ8Y6RZASJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>杯子长这个样子。竟然是盲盒么，我以为给的是 app 封面上的那个紫色吉祥物杯子。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KXKBRGCHV7FWAECXTJBP70BV.jpeg" alt="麦当劳的餐盘上，放着一个塑料杯，杯面上有个黑人足球运动员 Henry 的画像。" loading="lazy"></figure></blockquote><blockquote class="diary-thread-reply">17:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXKCAZDBT4E0Q6DNY2ZQMQ30" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>已经在很缓慢地在吃东西了。结果吃完饭、喝饮料喝到牙齿发酸，室友也没有消息。幸好早上起来往裤兜里塞了个 Kobo，不然我现在已经无聊到外面晒太阳、走来走去然后中暑死掉了。</p><p>其实把小十一带上也不错。尽管最近没怎么配置它，但它作为写东西用的设备，已经完善了，因为只需要安装个 Emacs GNU <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JDVGDYQWMMBRBXVTZFPD.png" alt=":neocat_googly_blep:" loading="lazy">​</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">21:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXKVNC5ETHFJ1X6DRVDBRB1W" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友和所有人预料的那样，考过了。我又点了个麦当当吃，主要是吃鸡块。室友要了杯冰水，真好喝啊，水是世界上最好喝的饮料…… 早知道我也要冰水了，而不是这个发腻的小甜水。</p><p>我让室友猜这是草莓配啥水果，她这个神之舌猜半天猜到最后猜出是西瓜。这期间啥芒果、猕猴桃都猜过去了，可见这西瓜汁和西瓜没有一点关系！</p><p>回家后吹空调，吹一半室友用同个插座吹头发，双双吹吹，吹跳闸了。</p><p></p></blockquote></div><hr><div class="diary-entry">16:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXKAEAH3M2CH8XE1XYS5T548" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 博客网站中文字体文件过大的事情终于还是被他人吐槽了。晚上考虑下解决方案，弄了下子集化，也就是计算源文件内到底用了哪些字符，然后将字体文件剪成只有这些字符映射的小文件。现在 DebugBear 检测从 31.7MB 变成了好像 4MB 左右。</p><p>实际上去掉中文字体文件，博客站点连 1MB 都没有…… 主站（领地）更是只有 93KB。但我又特别喜欢这些中文字体…… 靠！</p><p>记忆里 Eltrac 的引用块做的方案是，如果用户安装了某某字体，就用那个字体渲染；如果没有，则 fallback 到系统字体。哼…… 应该切换到这个做法么……</p><p></p><blockquote class="diary-thread-reply">16:47 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXKASVPRCNR24N4MX4Y77KG3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>弄子集化的时候还发现日文字体文件是损坏的，一直都是…… 但因为我不怎么发日文内容，所以发现不了。现在对日语怎么说呢，日语兼修已经上完了，我对日本实际上也没有多么感兴趣，最开始也是为了能和室友用日语交流才学的日语，她现在还老嫌我讲日语很塑料、叫我不要用日语跟她说话…… 能简单说几句就够了我感觉，我身边会日语的朋友也不多。想到和我一起玩《舞萌 DX》的朋友，他是看日本动漫学的日语，后来补了点基础，就搞明白了，顶多是口音厚重，不过他说什么语言都有自己的口音。总之这就是物理理论专业学生的智商么……！</p><p></p></blockquote></div><hr><div class="diary-entry">23:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXM1CMHHERHAT4YKWMC1AD3H" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>正在努力找到适合自己的皮鞋。发现自己的脚除了足弓平平的，还有拇指外翻的问题，也叫 <em>bunion</em>。幸好对比网上的图片，不太严重。总之尖头的皮鞋全部 pass pass。</p><p></p><blockquote class="diary-thread-reply">23:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXM1S0DDE1R6GYWMDVN9GCB3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>因为人在阿美所以得搜下阿美本土能买到的鞋子。虽然也有国内认识的人要来美国，但总觉得拜托他们帮我带不太好意思 —— 再加上要卖人情！</p><p>首先搜到的是 Vionic。综合考虑下来 Uptown Loafer 会比较适合我：</p><ol><li>有棕色！</li><li>是乐福鞋，跟很低；我不喜欢玛丽珍</li><li>是软皮，应该对拇指外翻友好吧</li><li>鞋垫可以拆卸</li><li>宽度可以选 medium 或者 wide，我应该会选 wide 吧</li></ol><p>现在也在打折，99 块钱。这种用于包装外表的钱，母亲就很乐意给我呢……</p><p></p><blockquote class="diary-thread-reply">23:47 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXM2V7398BAKC4CG03S9MK0Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>哇，母亲好烦。我买东西是不看性别区分的，基本上是看着好看就买。这双乐福鞋我选的时候也是如此。看着没有特别严肃，也没有那么休闲的样子。因为室友先前把我的头发剪掉，变成短发了，夏天一到我又在穿 polo 中裤，她一直觉得我在尝试变成男人 —— 我没有啊我草 —— 所以为了让她不要天天说我打扮得像假小子，我把这双之后我仔细看才知道是女鞋的鞋子照片发给她……</p><p>…… 结果她不知道眼睛长在哪里，非说这是男鞋，然后搬出上次业内人士说的「要改变形象、打扮得更像女人」来烦我。接着妹妹接管了她的账号来说我。这家伙儿很多时候还是被母亲当作是扬声器使的，之前也说过衬衫很奇怪这种话，明明你的奇形异状卡通图像短袖 T 恤衫更奇怪吧！</p><p>还是自己掏钱包买吧。</p><p></p></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>七月十六日</summary><div class="diary-entry">15:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXNRJXK7VJ0YRV9FH5JWR3YF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>父亲又因为超速的事情被抓了。几个月前他因为超速，造成了车祸。最后应该是保险承担了一切。那会儿我以为家里人不会再让他开车，结果他怎么又开上了。母亲一边骂他一边帮他擦屁股，真是看着烦人。正因为以前他没有什么真正意义上的惩罚，所以才会一而再，再而三的吧。然后母亲就和往常一样，跟我说父亲只会听我的，然后让我去和父亲说。说又能怎样呢。我和父亲有着相似的性质，我自然知道他心里在想什么。不给予惩罚的话，他根本不知道自己行为有多么恶劣。这种人我真是见惯了…… 我也是，父亲也是，某个讨厌鬼也是…… 真是烦人。以前当传话筒的工作是未开智的我来做，现在我厌倦了，就由妹妹来做。小孩子也算是很好利用吧，我高中时异常自暴自弃的时候，大人们也是将烦人的话语交给小孩子们来说，向我传达恶意。小孩子根本不知道他们说的话有多么伤人、令人烦躁，还嬉皮笑脸；有时候真想把他们打一顿，以泄愤。但这也只是让背后的大人们相信我是有病的那个，而不是他们。好讨厌有暴力倾向的自己。</p><p>总之父亲要上联邦法庭。被恐吓一番后他跟母亲说话都恭敬了许多，不咋带脏字了。该怎么说呢，很多时候他表现得像是母亲的儿子，还是叛逆期的那种。虽然他很疼爱我，但我对他没有多少记忆…… 妹妹倒是很喜欢他。如果可以的话，还是不想被牵扯到家里的事情。虽然知道这么做就意味着妹妹多多少少要承担些事情，但我是个自私的人；我只想要自己过得好。</p><p></p></div><hr><div class="diary-entry">15:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXNTFRSQCZ2WD5VRTZVQH9FQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>测试 Fluent-Reader-Mobile。</p><p>不小心点到 <em>read all</em>。</p><p>FreshRSS 上几千个未读变成了已读。</p><p>哼，啊啊，啊啊啊啊啊 ——！！！！</p><p></p></div><hr><div class="diary-entry">21:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXPBSQT6HXJVC28HFNRJY45G" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>项目管理那边同意我周末出去泡着了。但是周末有妹妹的生日派对，还是我特别讨厌的户外烧烤…… 用不知道放置了多少年的，公园里的 <strong>公共</strong> 烧烤架，吃被处理得恶心、油腻、干柴的肉……</p><p>我觉得妹妹已经是大孩子了，也该明白生日不是太重要、并不是所有人都会出席的事实了。呵呵呵呵……</p><p></p></div></details><details data-group="diary_sections"><summary> 七月十七日</summary><div class="diary-entry">02:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXPXYR4CQQ0TRGS3MEAMTEDH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>从办公室出来才发现今天天空看着不对劲儿。一搜才发现是有山火。三四年前也发生过同样的事情，那会儿看什么都是橘黄色的。</p><p>回家发现窗户没关，现在房间里还有烟的味道。讨厌死了。</p><p></p></div><hr><div class="diary-entry">06:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXQDMBCJQWQ53JV7VVJGZMJS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天有点闲，早点回家然后跟室友玩 Minecraft。</p><p>跟着网络上的教程做了刷铁机，原理是把僵尸卡在天上的船上，然后在天上卡住三个村民。地上则挖个很深的洞，洞口放用楼梯卡住的水，然后在僵尸的正下方放个烫脚的篝火。村民会因为惊吓而无法睡觉，不停去刷新铁傀儡在旁边。因为僵尸在天上，铁傀儡会跑到僵尸的正下方，而被水流推到洞底，也就是篝火上面。此时等待铁傀儡被篝火慢慢烧死就好了。挖很深的洞是为了让程序判定村民周围没有铁傀儡，好刷下一只。</p><p>室友总有些伟大的计划，比如铲平家附近的山。她某种意义上颇有毅力，已经挖了不知道有两个还是三个小时了，期间除了打会飞的长得像魔鬼鱼但更恶心的怪物外，就是铲山头。我给了她很多铁，然后才发现我一直把好资源藏在身上，导致她前不久还在用石头或者木头工具……</p><p>她的另一个伟大计划是在远处村庄和家之间搭个桥。我帮她搭完了因为她还不习惯蹲下然后快速往脚底放方块。之后弄好了刷铁机，我做了许多铁轨。不过红石只有八个在家里。聪明机智的我跑到 wiki 上搜其他加速的方案，看到了动力矿车，也是个没见过的新东西。什么时候 Minecraft 可以将矿车连在一起了？总之我在动力矿车后面放了乘坐用的矿车，满怀期待地往火车头用了煤炭。动力矿车带着我快速往前，很快、很快，太快了，而我的铁轨是歪歪扭扭的 —— 我飞了出去，朝着大海……</p><p></p><blockquote class="diary-thread-reply">06:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXQDW0FZYT3CWJ7B453GDCA3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>末影人拿着土块瞬移到室友身边。</p><p>室友：啊他是来送我东西的吗？好可爱、人真好！<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3HJ0YH3FAMVDC8BZ88SHG.png" alt=":neocat_floof_cute:" loading="lazy">​</p><p>我：不，他偷的是我们家的土块。</p><p></p></blockquote></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">性相关的长文。</summary>        <div class="diary-cw-content">14:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXR8ZE2FNARRXQCQ4CSP6AGA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>「性压抑」到底是什么意思？在网上找到的含义，更多是指个体将性相关的东西压制在潜意识里，产生的果包括但不限于「觉得性是羞耻的」，且不承认它。不过在主流的中国互联网环境里，它表现出来的感觉更像是，压抑过久了，反弹，变成看什么都是性，表现出来的欲望也更为极端、劲爆。</p><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KJH5N70X2MCW6NJWF9NT.png" alt=":neocat_laptop_owo:" loading="lazy">​ 过去和朋友讨论和性相关的内容时，对方也提到，性需求被否认、未能满足，会确切影响到他的情绪、身体。性需求被满足后，一身轻爽。</p><p>我鲜少同其他人正经地谈论过性。大家都更愿意将其娱乐化，再说出来 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 这儿也不乏有些人开玩笑般想要得知我的性生活 —— 干你什么事，去去！</p><p>前段时间说过到处都是的男性自慰笑话看得我有点烦。一是太多了到处都是，还要小心和喜欢这种笑话的人说话时，不要使用 lu 音的词，否则会触发条件，令对方立即打断我讲他们的破笑话。这倒明显是人的问题，我不喜欢被打断；二是我目前的思维链条，会将娱乐化的性话题、实际人们的性知识和性经验、对于真实发生的性的看法种种关联在一起。我还没有想好，所以观点就是很简单直接的：一群没啥性经验的家伙儿一边娱乐化性，一边厌恶真实的性，还天天追着他人的性生活和隐私不放，说成是什么惊天大事件，吵得我都好奇了，结果打开一看发现不就是别人的床事、人际关系云云吗！再浪费我的时间和精力我就要剥你们的头皮了！</p><p>不过我确实也发现自己对于性存在着偏见，恐是社会驯化的结果。像是母亲就很厌恶性，也讨厌打扮的年轻小姑娘。他人说我相较下来没有什么性需求，不过性带来的地位，以及被允许的暴力是我曾感兴趣的。这也是为什么过去我说过想到性总能想到暴力…… 我是个糟糕的人，毋庸置疑。但我思索着，既然我会这么想，那世界上总会有他人是怀抱着相同的想法去看待性的。比如讨厌的那群人…… 约束着自己做什么纯情人、有「道德」的，但是又在更开放的社会下蠢蠢欲动，结果导致的便是各种各样烦人的行为，什么征服难搞的女人也好、打破规则 AKA 他人的边界也罢，都是展现地位…… 有过类似想法所以能看穿他们，还是挺不舒服的。</p><p>有时我不理解为什么人要做那么多性行为？像是洗碗一样，很花费我的时间，尽管结果是拥有更干净的厨房，但我更想要去玩电脑。现在思考，我无法想象自己没见过、没体验过的事情。正如刚才说过的，性需求不被满足便会浑身难受，连工作效率都会一降再降。</p><p>暂且自言自语这么多。考虑到可能有不愿意看到性相关话题的人，所以加个告警好了。性和吃饭睡觉还是相似，一说总觉得可以说很多。</p><p></p></div>      </details></div><hr><div class="diary-entry">16:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXRDGK1F4G61RQEYJ2BZEE6R" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4TFD239TJ4YG6N2ENQBK.png" alt=":ottersgottaott25:" loading="lazy">​ 昨天在共享办公室的楼里跑来跑去，其实是在偷偷找空闲的洗碗机。总之在大厅发现一个小小的便利贴，说某某公司要出售二手显示屏，价格约 25 到 45 块钱，具体看品相。于是找到那家公司的房间号，看了下显示屏，一眼过去感觉真不错，比我现在用的 10 块钱从跳蚤市场淘的好看多了。唯一一个质量不好的也只是角落处有破损，屏幕本身没问题。要是只用花 25 块钱的话，那可真是赚到的赚啊！不过昨天太晚了，办公室里只有一个加班的哥们儿，让我今天下午再过来。</p><p></p><blockquote class="diary-thread-reply">21:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXS1EG4QPYXDRW2QSFWGAP90" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JAPAFKXXZFCG0S56CH2K.png" alt=":neocat_glare_sob:" loading="lazy">​ 结果因为今天早上闯了祸，到五点才能过去看。办公室已经没有了人…… 毕竟他们差不多四点左右就该下班了。地上的显示屏也不见了。只能赶紧发个邮件给他们，确认还在不。</p><p>鱿鱼就会白给！</p><p></p></blockquote></div><hr><div class="diary-entry">19:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXRRHJJMCA2F2M7D9MD218VS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://lore.kernel.org/all/CAHk-%3Dwi4zC%2BZe8e%2Bp3tMv8TtG_80KzsZ1syL9anBtmEh5Z40vg@mail.gmail.com" rel="nofollow noreferrer noopener" target="_blank">https://lore.kernel.org/all/CAHk-%3Dwi4zC%2BZe8e%2Bp3tMv8TtG_80KzsZ1syL9anBtmEh5Z40vg@mail.gmail.com</a></p><p>Linus Torvalds stated the position on LLM tool usage in the Linux kernel project. In simple words:</p><blockquote><p>Linux is not one of those anti-AI projects, and if somebody has issues with that, they can do the open-source thing and fork it.</p></blockquote><p>Of course, this is an oversimplified summary for hooking audiences such as you. So please, read the whole email yourself before making any comments.</p><hr><p>I agree with his opinion that LLM tools are supportive tools for developers. Slowly adapting LLM tools to my workflow, I realize they can be useful IF one spends time and effort planning and reviewing their work. Adapting them gives me two benefits: one is to do the job that I don't wanna do since I'm a lazy-ass person, or just don't give a fuck about; two is in terms of quantity, not quality tho, Gen LLM knows more than I do. It's nice to have blind spots filled during work.</p><p>Torvalds wants the Linux kernel project to be completely technology-based rather than politics-based -- this was my first impression. However, since all problems can ultimately be reduced to political ones, what Torvalds chose to state is also a political approach. After I realized this, I found myself seeing the usuals (around me, of course) as <em>non-political</em> and claiming <em>politics</em> as weird offenders. I strongly believe this is a perspective that others in the community may have without knowing it. Therefore, I dislike sayings like <em>religious reasons</em> and <em>social warrior</em> in this email; just say you are pro-technocracy or pro-utilitarianism instead of de-politicizing yourself.</p><p>Fortunately, people with different political approaches can always fork the project; this is the amazingness of open source.</p><p>Well, the future of code reviewers is going to be tough for sure, as there are still dumb-ass people who just send you nonsense LLM-generated shit, or in a more civilized term, <em>slop</em>. Publicly stating the project's position would raise the willingness to send more LLM-generated code, and there are always dumb-ass people involved.</p><p>That's enough mumbling for this, I guess.</p><p></p></div><hr><div class="diary-entry">20:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXRVHWE6C5EYHKEVC8EAEF2B" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>数据泄漏后天天有人给我发短信、邮件，还有打电话给我。好烦啊。就不该用私人信息去弄公司相关的东西。</p><p></p></div><hr><div class="diary-entry">23:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXS7S5MGJ6D3DR9JSN7ZGAJQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不知道什么情况，但笔记本打开 Masto-FE 字体和以前不一样。看着有点烦。</p><p></p></div></details><details data-group="diary_sections"><summary>七月十八日</summary><div class="diary-entry">04:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXSRZ8ZW0PRAA66M7D42SZSJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>没有人：</p><blockquote><p>浑身假象的这个我 简直像个神吧</p><p>说什么真心 搞得很懂似的</p><p>真是令人作呕的魑魅魍魉啊</p><p>就因为掌握了什么 把幻梦亲手砸碎</p><p>说什么降降温 真是愚蠢至极吧</p><p>我才懒得搭理那些杂碎呢</p><p>假装冷静的那个我 还是开了口</p><p>不过是因为早已虎视眈眈 压着怒火了</p><p>是我唤来了春日风暴 是我哭了 心被伤透了</p><p>可那也不过是自作多情吧？</p><p>反正就是吧 我也明白啊</p><p>连我吐出的气估计也 又呛人 又碍眼吧</p><p>原来想被爱的愿望</p><p>也是一种罪啊 偏偏带着甘甜香气</p><p>摇晃的汽水 一饮而尽了 就说再见吧</p></blockquote><p>✋p😭q🤚 <em>This is true music……</em></p><p></p></div><hr><div class="diary-entry">07:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXT2RJ46TKYDN115S21B16GY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>动力铁轨做成激活铁轨了…… 谁懂兴高采烈坐上矿车，想要看到矿车碰到红色的铁轨后加速向前时，却被激活铁轨弄下了车。</p><p>好笑的是我记忆里小时候玩 Minecraft 做过一模一样的事情 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​</p><p>换成动力铁轨后，想要测试一下能不能爬坡。失败并慢慢往下滑时，发现身后跑来三头苦力怕，吓得我直接弃车逃离。</p><p>家底下那个幽绿色生态的洞穴，终于刷新出了它应该刷新的大型长角怪物。不知道该怎么对付它，所以不发出声音，看着它从我身边经过…… 不过之后挖矿时，好像是被它穿墙的远程伤害几下打死了。</p><p></p></div><hr><div class="diary-entry">15:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXTX493CTRVZRCS18JGY8TDD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>被套拿去洗，结果发现里面的被子核心破了，许多羽毛飞了出来。没办法，晚上和室友挤在一起睡。</p><p>好想出去玩啊，可是活好多、永远做不完…… 一年前项目管理看到校友的 startup，到现在官网也说 app 在 waitlist，并感到诧异。我说，这是正常速度！不要以为我快速 vibe code 一堆垃圾是正常的！</p><p>晚上都太晚睡了。刚才起来，发现是 11 点，并且外面阴阴的 —— 对哦，今天要打雷，所以我不出门。好想要去图书馆里面玩，带着红色的小十一，随便找点小说读～</p><p></p></div><hr><div class="diary-entry">21:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXVJF90TY3TA63VYPDMA0DFK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天要吃什么 —— 真是难以回答的问题。替室友办事情，她请我吃晚饭。说实话，我喜欢吃的东西对她来说都是掉价、平价的，我也不太能理解她喜欢吃的东西…… 尤其是生鱼，就算是品质特别好的，我也受不了那种油腻感。但是生的虾和扇贝我就愿意吃。总之，她就算要请我吃我喜欢吃的东西，我也只会选便宜饭。</p><p>其实，还挺想要坐一个小时的车去另一个区吃饭。不过太远了，我还要干活。我真的恨死 stash 了，变更差点全没掉。</p><p></p><blockquote class="diary-thread-reply">07-19 00:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXVWKW2D1CXXN5V793PGTDSQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>跑到另一个区吃饭实在是个冲动的决定…… 大水淹了许多地铁站，我卡在地铁站内动弹不得，因为要转去的车也被影响、不开了。</p><p>当时我要么可以直接回家，要么可以出站找另一辆车。沉没成本 3 美元，我选了后者 ——</p><p>—— 结果后面还发生了导航出问题、误以为我在下一站、导致我提前下车的事情。没办法，我只能又换成几分钟后来、能到我想去的站点的车。总之出发时差不多 7 点半，现在已经 8 点半了，我才坐上路线里最后一辆车。如果最开始愿意多等十几分钟，换坐贵 2 块钱的铁路的话，现在就已经到地方了。</p><p></p></blockquote><blockquote class="diary-thread-reply">07-19 03:47 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXW7S2SXEFXQFKT2BVCM20M4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最后吃了羊肉烩面，最喜欢了。碳水，呵呵，碳水是最棒的…… 蛋白质什么的，豆腐皮也算吧！我挺喜欢羊肉的，但家附近的超市不怎么卖啊。</p><p>和朋友聊天，说到 Panda Express 咋不卖猪肉。他们有道菜的灵感来源于咕噜肉，但是肉给换成别的了。我说为啥不直接用咕噜肉的配方。朋友说你想想穆斯林。</p><p>街头的餐车通常都是卖 halal 食物的，应该是叫「清真」。肉提供的都是鸡肉和羊肉。不过食用羊肉的人在我看来还是不够多，和猪肉都比不了，更别提鸡肉和牛肉了。</p><p></p><blockquote class="diary-thread-reply">07-19 03:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXW8CMK8TFD3N0XAK59CKB1S" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>一说到不能吃猪肉的人，就想起来在中国的时候，经常去学校附近的一个回族肉店买肉。又想到当时家附近还有犹太人开兰州拉面馆，难道我那个区少数民族不算少？</p><p>根据旧约所说…… 其实我全忘了，总之猪不能反刍，不能吃；兔子也不能吃；不能吃的还有贝类。后来新约里耶稣基督大解放，想吃啥吃啥，想信耶和华就信，管你是不是以色列人、犹太人。</p><p>初中时和同学们都挺叛逆的，大家都很讨厌宗教人士，尤其讨厌反对性少数人群的宗教人士。这样一想，当时初中的朋友们多多少少都有点性少数倾向，不论目的是什么（当时确实有人是为了潮流而这么搞）。反对的方法便是翻圣经、用圣经里的话打败教徒：你自己都吃猪肉、不听圣经里的话了，那你说的话都是屁话！—— 现在想来实在是天真到可爱。</p><p></p><blockquote class="diary-thread-reply">07-19 04:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXW8R7GR5QVPWN8RXV17NGGK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>还蛮意外，我在初中和高中结识的朋友都对性少数这个概念很友善，也有人会真诚地去支持它。但在大学里，认识的家伙儿却都是讨厌该概念的人。</p><p>我对大学里认识的一批人实在是喜欢不上来。他们像是恶意的聚集体，除了原始的思想没有别的了。嫉妒、无知、暴力、性侵…… 有部分人应该不会再出现在我耳边，但有个最为恶劣的时不时还能观察到他的存在。</p><p></p></blockquote></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>七月十九日</summary><div class="diary-entry">00:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXVXNCJQ0KPCGA54VV0B78Z8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>朋友不愿意在外人面前展露出自己会说普通话一事。理由是这样会让部分人以为，自己很好说话。</p><p>让我想起去年，我们去林肯中心参加上海日活动。那附近有家卖 gelato 的店，朋友买了个，我们一边聊天一边走来走去。那时，迎面走来一个女人。我们快要擦肩而过时，她忽然对着我们用普通话说了句：「哪里买的？」朋友愣了下，指了个方向。女人一声不吭，直接走掉了 —— 喂！倒是道个谢啊！</p><p>这个事情也不能说明太多，不过朋友明显很烦这种事儿。类似的也有，自己一开始说普通话，就被其他老移民也好、新移民也好、ABC 也好，夸赞说普通话说得真好。这样的对待，让他觉得很不舒服。这也包括许多，因为会说普通话，所以被别人免费当作劳动力帮忙做事情，例如翻译的工作等等。好吧，这种事情我经历得更多，被亲戚们当作是免费的英语劳动力，强行侵占我的时间来帮他们跑来跑去。凭啥！</p><hr><p>坐我隔壁的这个家伙儿不会是在外放《罗小黑战记》吧？这个熟悉的山新女孩音和男孩音。</p><p></p></div><hr><div class="diary-entry">01:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXVYCQP0JP03Y945A8FAGBME" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>朋友小自己十几岁的弟弟高考结果出来，成绩相当不错。他说，自己作为家里教育模式的一号机，总算是功成名退了。接着他感叹道，自己以前被家里放养，让家里人见识到了教育路上必然会碰到的坑，以此来优化投入到二号机（弟弟）的资源 —— 这是工业模式迭代啊！</p><p>我和妹妹，目前因为她年纪还小，看不出来啥。不过母亲投入在她身上的体育资源，明显比投入在我身上的多多了。今年快能进 zone 比赛去了。</p><p>朋友们都对这种做法嗤之以鼻。朋友甲觉得，「他们表面上总说以前没管好大的，为了弥补所以要对小的好」这种想法很傻逼。既然是想要弥补，为什么不直接对大的好？朋友乙很讨厌我的家人，直接说放养更好，我妹妹在他们的教育下只会更没有出息。</p><p></p></div><hr><div class="diary-entry">02:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXW36WNYMZF544AZZC89DM1T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我觉得《イガク》MASTER 写得很烂！就是原口沙辅破纪录的第二首 VOCALOID 曲，<em>ユ</em>！</p><p>玩起来好难受，一点都不好玩！</p><p></p></div><hr><div class="diary-entry">03:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXW7582K41940WV5CXY9J3AR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>很热的时候，我会很想要喝冰冰的奶茶…… 只有在很热的时候！平时，我都是点常温或者热的，点奶茶的次数也很少。</p><p>我看到 CoCo 有个 1 块钱荔枝冰茶的海报，就过去点单，结果是周二限定的…… 没办法，点了 Lava Pearl Taro，应该就是香芋奶茶配大量的黑糖珍珠。</p><p>但我忘记了一件事，那就是我以前喝它都是冬天喝，热热的、甜甜的，奇怪的奶味儿，喝起来很舒服。但现在是夏天，我讨厌它的甜腻、热的珍珠。</p><p>应该点，呃，荔枝养乐多？没有喝过的东西，总之要有水果的味道，然后冰冰的。不过今天已经喝了奶茶，接下来至少有一个月应该都不会碰了。</p><p></p></div><hr><div class="diary-entry">04:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXW9N1FN7AET1AM7T86NA5C5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Polymarket，本来以为死翘翘了，结果最近经常看到。</p><p>先前炒股已经懒得看了，放着等它个几年慢慢升值吧。买的不是 Figma 就行。</p><p>虽然股票的原理和彩票、赌博都不太一样，不过人们还真是喜欢赌博性质的东西。要么输光光，要么赚很多钱。</p><p>我炒股就往里面丢了 300 块，然后很快意识到自己实在是不善于做这种事情。去赌场也肯定是内裤都会被输干净的！</p><p></p></div><hr><div class="diary-entry">16:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXXJ7P2W6M21H6YWZ7KSH41Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天晚上试着用手柄游玩 Minecraft。我用的是 Logitech Gamepad F310，总感觉跑步和蹲起所需的按下摇杆，有点困难，无法随心所欲地按下去。难道是手不够大吗。</p><p></p></div><hr><div class="diary-entry">16:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXXKGQASD71TT36BGMFQNRFP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>鸡肉做太多，再加上最近也有吃其他肉，导致这些鸡肉开始出现不应该有的味道…… 总而言之还是可以吃的。</p><p></p></div><hr><div class="diary-entry">19:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXXY056FHRA3B8A8SS6YDXHG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>拿到博友写的书的试读本了。总感觉自己在做 peer review…… 我小时候做这种东西都是尽量不挑刺、避免麻烦。</p><p>想起来初中时给一个现在不咋喜欢的同学的作文做 review，主要是改了下他的语病，不过当时英语也很差。他放学后拿着作文又给辅导班的老师改。第二天英语课，他过来，为了羞辱我，说辅导班的老师找出了更多的错误，然后说给他做 review 的人（也就是我）sucks。但是，找出更多的错误，不就意味着你的作文原本就有更多的问题吗…… 真正 sucks 的人是谁啊……</p><p>说到这个家伙儿，就会想起他初中做过的许多无聊的烂事儿，比如在公共场合内涵和嘲讽同学穷。当时我住在华人区里，大家都是穷穷的，也不知道为什么会有人因为比别人稍微多点买衣服的钱，就如此自大。到大学了也能见到这种人，真是井底之蛙。横向的阶层你再怎么比，也无法爬到上一阶层吧。比较这些东西，到底哪里有意思了。</p><p></p></div><hr><div class="diary-entry">22:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXY8K3TRHCJMRV95K045VRDB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>没劲儿…… 天气晴朗的周日，但要和匹克猫待在办公室里干活。不想做了啦，修不完的 bug！中途还坐在椅子上睡着了。哪一天我就会练就正坐睡觉的技能吧。</p><p></p></div></details><details data-group="diary_sections"><summary>七月二十日</summary><div class="diary-entry">01:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXYJG0SVCR4T2A89C83VEFM3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>回家的路上，地铁上站着一个男人，大声说着什么，我也听不懂，因为没有语境。总之听出来他在引用圣经，然后说自己不是 white trash、贩卖小孩、如果想要免费的垃圾可以去 homeless shelter 要。</p><p>他也说自己不是神经病。</p><p>虽然很吓人，但我感觉出他不会无缘无故伤害他人，更像是有心理或者精神问题的。这座城市到处都是这样的人，只要他们不伤害别人，大家都会视而不管。</p><p>脚边出现了一头硕大的 ゴキブリ，用鞋子把它吓走了。快走吧，不要出现在街头。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">长文？总之是和人际关系相关的。</summary>        <div class="diary-cw-content">02:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXYNRT05428TDRE119Z1VWR5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>中午和室友聊到，我不喜欢的人际关系。起因是她晚上在我睡觉的时候，用我的电脑在看《沙耶之歌》。起床后她说，肉块好恶心，怎么会有人喜欢上肉块然后和肉块生子。</p><p>我没有看过《沙耶之歌》啦，但我想要说的是与其无关的话题：我观察到有部分人很喜欢这样的剧情，自己接纳了不被他人接纳的甲，于是被甲喜欢上，最终两人结为连理。作为理解的前提，我也虚构过、经历过这样的状态，即我也曾幻想过自己因为接纳了某人，所以和某人成为了特殊的关系。这样的事情也确确实实发生过啦…… 至少我曾幼稚地这么想着。事实是，人类没有那么扁平，除了不被接纳的方面外，还有无数个方面在。意识到这一点后，我便察觉到自己难以理解人类了。根本原因还是，自己对于人类的理解太扁平、太自以为是了。再就是，我无法接受自己对于对方而言，不是最特殊的那一个。</p><p>某个家伙儿跟我说喜欢我的时候，我也算是第一次见识到这种期待有多么可怕。他擅自为我们之间的关系添油加醋，认为我们是对彼此来说特殊的存在 —— 才不是啊！我只是像对待所有的朋友那样，对待你而已！只是因为你这家伙儿根本没有朋友，所以误会了啊！不过说到被擅自期待，室友油嘴滑舌的，遇到这种情况的概率更高。明明已经明示了自己只是会说话，但对方就像是听不进去一样，自言自语着「我们是天生一对啊！」真是可怕。</p><p>初中时，强行为人际关系添加意义，这种行为很常见。倒是到了大学，我观察到更多为了婚姻、社会要求、性需求的人际关系。真是怀念，当时在初中谈到肉体，同学们还会觉得下品，虽然还是会感到好奇就是了。</p><p>我认识的一个人，曾大言不惭地说道，自己喜欢有问题的女孩，然后自己要去拯救她 —— 我觉得这种想法真的很自大哎。这不是利用吗？趁着对方沉浸在痛苦中，施以对自己来说不轻不重的同情、关怀、时间和精力，然后就能得到对方的「爱」、肉体，巴拉巴拉。这家伙儿也和预料中的一样，就没有朋友。</p><p>另外一个朋友，倒确确实实和精神有问题的女孩子交过往，还不少。不过很多时候都是，被对方伤害 —— 为什么总有人认为恋爱可以解决精神或者心理问题？不觉得这很无礼和自大吗？你自个不讨喜的个人魅力才不是靠「拯救」患者彰显出来的吧。</p><p>我和朋友之间有个内部玩笑：会有人过来，跟我说，「我会修复你的！」所谓「修复」指的是我对异性不感兴趣的事情。不过基于某个傻逼跟我说的话，恐怕也要包括我对执行性行为不感兴趣的事情。很高兴他后面没有再来烦我，不然我真的要雇佣朋友当打手了。</p><p>讨厌鬼和我之间的关系，怎么说呢，其实我从未正面见过他，但我能搞明白他当时在想什么。他想要证明自己比我好，所以在性别、性取向等种种因素上挑我的刺，也让他看上去更难堪了，因为这侧面反映出他除了天生的东西外根本没有什么能拿出来和我比。除此之外，就是他当时一直在神话、浪漫化自己的行为。他对外说我是个恶人、缠着直女不放、有 trauma bond 的家伙儿，而自己是打败万恶女同、拯救女神的英雄…… 其实根本就是个有暴力倾向、没有边界感、自恋、爱霸凌、反对性少数人群、得不到还要在背后骂当事人的幼稚小鬼…… 这家伙儿居然还比我大几岁，真是闹得难看。总之，他有段时间一直觉得自己是正义的，而他和受害者的关系是特殊的 —— 确实是特殊的，但是是在不健康、糟糕、恶劣的角度上 🤷‍♂️​ 所以室友说，就是有这样的关系，并且能运转得好好的。尽管很奇怪，但就是可以，反正都是各取所需。Trauma bond 估计就是这样的关系的一种吧。</p><p>今天的思绪有点乱，我自己都没有整理好自己想说什么。</p><p></p></div>      </details></div><hr><div class="diary-entry">04:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXYVN2XYR0ZTT2QMBPVD6QZG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看到字很大的个人博客网站：<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3MSBK7B73EXVDD99TXXCG.png" alt=":neocat_nom_melon:" loading="lazy">​ 好大的字好喜欢。</p><p>看到字不够大的个人博客网站：Ctrl + 变大吧。</p><p></p><blockquote class="diary-thread-reply">04:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXYWNGAVVQ3335HS72SDMWFB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在用 RSS 阅读器看日报。有些博客网站提供的 RSS，需要跑到他网站上才能看到全文，RSS 里的是被截断的……</p><p>有时候心情好就会点进去看，心情不好就不看了。</p><p></p><blockquote class="diary-thread-reply">07-27 07:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYH6SDSNDQGKEH104ZE8W6Y4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>更吓人的是 RSS 里放了文章内容但全是 HTML 代码。</p><p>给 bot 读的吗！</p><p></p></blockquote><blockquote class="diary-thread-reply">07-30 20:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYTCTTT7V36QY4XMR59502K4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>关于这个 RSS 问题，我可以倒腾一下 FreshRSS 的内置功能，还没有认真弄过，只是在一些不提供 RSS 源的网站强行搞了爬虫规则、把文章爬下来。</p><p></p><blockquote class="diary-thread-reply">07-30 21:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYTDTBW2KHXDYRD6EG2JSAPC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>安装了 Af_Readability，就可以让程序自动去抓原文链接、提取正文然后替换掉 RSS 内的摘要了。</p><p>我要改造所有讨厌的 RSS……</p><p></p></blockquote></blockquote></blockquote></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">性相关。</summary>        <div class="diary-cw-content">04:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXYXGVKSH2HKNHPWRXV6KBDH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有时候看到名字叫什么「挑战禁欲 / 戒撸第 X 天」的账户，就会好奇，难道这些人之前都是每天都要进行性行为的吗？</p><hr><p>现在特么快一点了，但还是能听到远处的跑车在炸街。好烦啊，不要再到处开来开去了行吗。</p><p></p></div>      </details></div><hr><div class="diary-entry">12:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXZRBV3K24MWAS62460THH4Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>做梦梦到自己为了方便，把两个电动 scooter 折起来，塞到了袋子里，然后把袋子留在了地铁站。这样出去做事，回来就能拿着用了。结果事情做完，回来，我只拿走了袋子最上面的衣服，却没有拿走 scooter。在上车后对它们可能会被偷的事情，我十分焦虑，焦虑到醒了过来。</p><p></p></div><hr><div class="diary-entry">14:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KXZZ0P8SZTJZ87W851GT3Z1W" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我要尝试在公园草地上用笔记本电脑干活。</p><p>他们投喂给我饭我就吃。但是家里人整的户外 BBQ 没有一次是好吃的，全是油腻的肉、肉、肉。</p><p>可以抱着幸运狗工作。</p><p></p><blockquote class="diary-thread-reply">15:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY019DMX9FZ9QSZADA1FWXYD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>好吧我还是受不了草地的质感。</p><p>他们是怎么允许自己坐在草地、躺在草地上的？除非有垫子毯子否则我是不会坐下来的。</p><p></p><blockquote class="diary-thread-reply">15:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY01MTN29V5BE4ZNZ8QRXDAY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这个公共户外烧烤区域，位于海边，一眼望去就是草地和沙滩。中午没有人，倒是乌鸦在周围一直叫。你就算叫，这附近也没有卖薯条的地方呀。</p><p>派对得到下午四点才会开始举办，结果我十一点就坐在这里，无所事事，不知道在干些什么……</p><p>总感觉这里到处都是虫子，尤其是对猫狗有害的蜱虫、跳蚤，真是恶心。</p><p></p><blockquote class="diary-thread-reply">15:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY01X8B2F8A51S2AZ69RG8QK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>也没有充电的地方，就算要用电脑，恐怕也撑不了五个小时。户外充电…… 太阳能…… 手摇发电……？</p><p>在看 GNU Emacs Lisp 的编程入门书，也是第一次尝试通过读书学习编程语言。和想象中的很不一样。</p><p></p><blockquote class="diary-thread-reply">17:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY0AKZBF5HJ2DF0GSGXP56J6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>明明早上充了电呀，怎么现在一开电脑，只有 58% 电。尤其这个还是所谓的「全能本」。</p><p>现在要两点了，我什么都还没有吃…… 好饿。干脆回家、骑车去附近的麦当劳好了。</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">17:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY0APSBTRTAQMYSVYSB1M0VK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这些人真是没有素质，草地里仔细一看，还有碎掉的塑料杯，以及各种塑料垃圾。垃圾桶旁边居然还有一坨排泄物！中央的树下，倒了很多使用过的煤炭，明明倒煤炭的桶就在不远处。</p><p></p></blockquote><blockquote class="diary-thread-reply">23:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY0ZEVDFVY103CCCERKRN64S" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>陪小孩子玩排球。光脚踩在沙子上的感觉，很奇特，总感觉自己的脚型正在被沙子包容……</p><p>本来以为他们就随便玩玩，结果对规则很上心。懒得设置边界线，他们就自己画了个。不过技术还是一般，所以很多时候都在吵谁发球、刚才输了是谁的锅。</p><p></p><blockquote class="diary-thread-reply">07-21 00:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY11FMWBK1APNR1QZFA78YNN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>傍晚了。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KY11FBR9CMH93JF3EEKPF67H.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">07-21 01:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY14QYQ3HN0Q4BZB40F718XR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>收尾结束了，结果母亲和朋友聊起天来。在干什么啊…… 我等下还要坐一个多小时的车回家。</p><p></p><blockquote class="diary-thread-reply">07-21 01:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY154B14JX3DS771KQCF7390" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天实在是划不来。吃没吃饱，自己的事情一个也没做。累了。妹妹还想要我再待一个晚上，但是待在这里实在是无事可做吧，室友也一个人在家里。</p><p></p></blockquote></blockquote></blockquote><blockquote class="diary-thread-reply">07-21 02:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY18P7EPZEGJ2846NMGKBXS5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有几个跟我妹妹年龄差有点大的小朋友，通常是亲戚家的孩子，或者妹妹朋友的弟弟妹妹。他们跟妹妹以及她的好朋友们玩不来，往往都是坐在一边玩自己的。</p><p>其中有个内向的小女孩，我不知道她是哪里人，总之她除了生菜叶子外什么都不吃，后来混熟了愿意吃点薯条。妹妹和朋友们在玩的时候，她都是铺个垫子在旁边看。之后我把幸运狗牵给她，她就开始隔三差五来摸幸运狗，还问我能不能遛下幸运狗。我教她怎么遛狗，尤其是考虑到她的小身板，幸运狗要是 tweak 了估计能把她拽在地上跑…… 她倒也听话，一直遵守着我教她的牵绳法。</p><p>说到牵绳遛狗，尽可能去两只手握着绳子喔。尤其是大型犬，耍起来成年人根本无法单手拉住。就算是小型犬，双手握绳也有好处，那就是用第二只手收紧绳子，使其尽量贴在你的左右边走。任由狗狗走在你的前面，其实不是个好习惯。再加上绳子太长、狗狗离你太远的话，一旦狗狗跑起来，不仅你可能拉不住，狗狗也有可能会因为你拉住了、而伤到脖子。要让狗狗在你的掌控之中。</p><p></p><blockquote class="diary-thread-reply">07-21 03:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY19W82R510N4X822BNNC1QR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不对我想说的是该如何让年龄差不同的孩子们玩在一起啊 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 我肯定是不会让小孩子们聚在一起也玩电子设备的了，并且年纪小的孩子过来玩电子设备我会很有罪恶感…… 妹妹这个年纪的小孩子，户外都是玩鬼抓人、排球、篮球、乱七八糟什么球总之我都不会玩。让年纪小的孩子来玩，难免会受伤，或者遇到技术不对等的情况，导致妹妹和她的朋友们要帮我承担照顾小孩子的责任。唉，有带动物过来真是太好了。这边的小孩子都喜欢小动物。我带幸运狗出来找人，也有路过的小孩子跑过来问我能不能摸狗狗。</p><p>可惜，母亲的朋友里也有养狗、带狗过来的。同类社会化并没有做得很好的幸运狗，会和它们打架，所以得想办法让它们看不到彼此。有趣的是，这些小型犬的特征都是亲人、对人友善、对同类社会化差，比如对同类太粗鲁，或者对同类太没有兴趣。幸运狗见到陌生狗会大叫。要是对方也有攻击的欲望，便会打起来，否则就是看对方是否会遵守礼仪来闻闻；一直贴着它闻的话它会生气然后凶回去。</p><p>匹克猫也有同类社会化的问题，特征也是非常亲人，甚至有时我不理它它会强硬跳到我肩上。反倒是对人没什么兴趣的咪咪猫，没怎么见过它怕同类。不过咪咪猫本就是捡回家的野猫，捡到家时已经断奶了；匹克猫则是带回家后便没有再和动物们接触过了（昆虫和节肢动物除外！）。</p><p>我和室友都有尝试让幸运狗和匹克猫再度接受同类社会化训练。不过都以失败告终。这期间我们还见到了匹克猫第一次哈气，是对着另一只猫做的，以往有多么讨厌的人类冒犯它它都从来都不会哈气。之后我在网络上看到一个言论，说是没必要去做同类社会化，尤其是它们没有必须要和同类打交道的时候；对于部分小型犬而言，和人类相处要比和同类相处幸福得多。我会自作多情地想，人类是不是也是一样呢？不用和人类打交道的话，自然不用搞明白社会化。难以和同类幸福相处的人，也有很多。</p><p></p></blockquote></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">19:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY0EEWKGQ5YSQ88S8XK67VV3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>校友跟我说我校有个博客站。进去一看发现是 WordPress 站，弄成了学生只要登陆便可以创建自己的 site、在自己的 portal 里写文章的设计。</p><p>对我来说是没啥用，因为我自己就有博客站，不需要。不过转念一想，我确实需要一个新的身份，因为 Cytrogen 这个身份不太能展示给线下认识的人看，尤其是我还在文章中骂过学校…… 之前有考虑过把 portfolio 托管到新的域名来，现在估计是不用买新的域名了，呵呵呵……</p><p></p></div></details><details data-group="diary_sections"><summary> 七月二十一日</summary><div class="diary-entry">03:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY1AHT94R4T37XK9MHMFXQ2V" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>永远不要在没看清车厢里有什么的时候，直接找位置坐下。例如我现在坐下后，才发现我对面是个在抠脚、散发着奇怪味道的人。</p><p>虽说也可以直接走开啦…… 但总觉得不咋礼貌。</p><p></p></div><hr><div class="diary-entry">03:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY1BVWESZ2QHCJW80V8CV4JY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JH2FHXKNQFADV5ETNG5K.png" alt=":neocat_googly_shocked:" loading="lazy">​ 有没有好心的 Fedi 友引用下我，我想知道被引用后我会收到啥样的通知。</p><p></p></div><hr><div class="diary-entry">16:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY2PGS6HX8XNDVQA4K20D22W" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>做了应该意味着压力大的梦，就是去了家又像中药店又应该是奶茶店的地方。里面员工只有一个人，是我上次打工店里的凶凶前辈。我在挑选墙上的饮品时，她说没有立即选好的话就不要进来。然后我不小心发错消息给上次打工店里的店长，对方问我还要回来干吗，才不要回去啊！恐是昨晚睡前听到的消息导致的，让我不得不去思考再出去打工的事情…… 能搞到长期的项目真是困难。</p><p></p></div><hr><div class="diary-entry">18:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY2ZY8BA3SXH76DCZ2NZADKR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>朋友送了我一些在国内买的小东西，比如设计很可爱的戒指、领带、手表。大家都不是很贵重的东西，但戴起来都很舒服，尤其是这个表，有着我目前觉得最舒适的表带！顺带一提表带设计最差的是 BANDAI 的数码暴龙玩具表 Vital Hero 系列…… 家里有很多 G-Shock 和类似的产品，表带也很硬，一点都不舒服。</p><p></p></div><hr><div class="diary-entry">19:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY31V37BB72J2DQZRG1KCTXR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>出门：背包第一次如此轻，难道是我的身体开始欢快起来了？</p><p>到办公室：妈的笔记本电脑忘记带了。</p><p></p></div><hr><div class="diary-entry">22:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY3D8A111CWHSTP09DJ1HDFR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>新的贴纸。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KY3D80WQYC55P254NSXS2FYY.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">23:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY3EJ8EEDMXCX9RW52HB6KZH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>要更新自己的 GoToSocial 了……</p><p></p></div></details><details data-group="diary_sections"><summary> 七月二十二日</summary><div class="diary-entry">03:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY3X3WJM75BV4K0BC4HR7JVC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3EQQJ0WWJ5EQ79NS9AMS5.png" alt=":neocat_angry:" loading="lazy">​ 前几天洗澡，搓着搓着想起来去年在 BiliBili 上刷到的个视频，应该是整理了从 200X 年到 2025 年，各个平台播放量最高的 Vocaloid 曲排名榜。我还很好奇第一名是谁，结果视频结尾说是《千本樱》，理由是其某些翻唱视频播放量极高。</p><p>靠，那你怎么不每首歌都在每个平台里取相关视频中播放量最高的。评论区里频道主还说，不选《千本樱》第一的话会被观众不认可 —— 谁管你这个，我要看客观的数据啊！</p><p></p><blockquote class="diary-thread-reply">03:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY3X7NXYFXPB1SD6HV0QWE9B" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看了眼发现 YouTube 上《メズマライザー》已经有 2.09 亿了，和《少女 A》大致持平，吓人…… 去年看的时候还是《グッバイ宣言》第一。</p><p></p></blockquote></div><hr><div class="diary-entry">04:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY41KV6QX327VXQ63CPT7131" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天又吃了 Panda Express。室友说，吃外带这种事情，如果不能拉长在外的时间的话，就没有吃的意义了。例如吃完外带后就回家，那还不如直接回家做饭吃。我一心想，啊好有道理啊，于是吃完外带在办公室待到了现在。</p><p>室友点了「宫保鸡丁」和北京牛肉，我则是蜂蜜芝麻鸡胸肉还有西兰花炒牛肉。西兰花炒牛肉就不说了，已经点过两次了，点了不会错多少；蜂蜜芝麻鸡胸肉，味道和上次点的陈皮鸡很相似，就是肉我感觉更脆；「宫保鸡丁」一般…… 这北京牛肉比想象中好吃很多！整体来说味道还是甜酸口。</p><p>现在在做的项目，昨天还以为搅黄了，今儿好像甲方那边的老板又反悔，不知道都在想啥。特别有意思的是，甲方那边的老板，和我这边的头头，是同个姓，而对接时，甲方的技术代表跟我，也是同个姓。</p><p></p><blockquote class="diary-thread-reply">04:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY421SER53QYFG9MPAKJTDQA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>俩头头之间打电话。</p><p>我的头头：两周给你搓出 60 页 PPT！</p><p>我：……？</p><p>这个 PPT 我就搓了 8 页吧现在就。之前跟我说好搓 30 页…… 虽然我感觉 10 页就够了…… 你们老板只看数量这一点真的好烦……</p><p></p></blockquote><blockquote class="diary-thread-reply">17:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY5FQZ6V7GENJTSF02BHJ7QE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Panda Express 用的包装，是纸饭盒，久了会软掉，还盖不紧。怪不得他们员工把塑料袋都系得特别紧，不然会直接洒出来。</p><p>环保挺好的，纸饭盒没有像纸吸管那样那么讨厌。之前看有家店会使用摸起来很像塑料，但会自然降解的吸管，这个挺好的。</p><p></p></blockquote></div><hr><div class="diary-entry">16:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY5B0VWDH3D89ZGJPKYNWSN7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨晚，或者说今天凌晨，陪室友玩 Minecraft 玩到五点多。睡觉也是一路睡到中午。虽然更早的时候有醒来，但感觉还是昏昏沉沉的，便继续睡回去了。</p><p>室友想要弄基建，也就是家附近一定要插满火把，再也看不到怪物；以及通向村庄的「&lt;我的名字&gt; 地铁」要做好。我看了看家里的箱子，乱乱的，得腾出个仓库估计，总之没啥金子和红石，动力铁轨做太少了。</p><p>她在村庄驯服了俩猫，然后带着它们跟我一起下洞 —— 错误的决定，我忘了家附近的洞穴有深暗之域了…… 于是循声守卫出现、猫在叫、守卫冲过来杀猫、可怜的室友动弹不得只能看着猫被杀……</p><p>之后我们一边复活后互相 /tp，一边挖矿石，一边铲除幽匿尖啸体（这东西长得像牙齿，所以我叫它「牙牙」）（这东西真的好烦根本想不到会藏在哪里）。</p><p>挖了很多钻石，呵呵呵…… 钻石竟是如此好挖之物。很多时候我都在用弓箭吸引守卫的注意力，不过该死的时候还是会死掉，唉。</p><p>有了刷铁机后，铁是不用愁了，好像还能升级成效率更高的。铁傀儡好惨。应该也有其他类似的刷物资机器，之后再搜搜看吧。</p><p>在深暗之域不知道死了多少次后，我们回家整顿了下基地。家还是个破火柴盒，有空的时候再重建吧。</p><p>室友觉得樱花树好看，于是在我的植树园种满了樱花树。结果这东西长出来歪七扭八的，根本不好砍！不准再种了！</p><p>有了田地后，食物也不咋愁，室友曰此乃农耕社会的福报。隔壁《饥荒联机版》也是种上地后吃土豆吃番茄吃火龙果。</p><p></p></div><hr><div class="diary-entry">16:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY5C0ERP384YEBRXMFTWF0VF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>讨厌时间有问题的文章，它们会一直出现在我 RSS 列表的顶端。</p><p></p></div><hr><div class="diary-entry">17:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY5CJ614B0BQAFNX5DEY2325" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>新・AI 时代・个人博客网站 Ultra Pro Plus Max 应该是这样的：文章是完全 AI 工具生成的，不做任何修改；评论后过 1 秒有 AI bot 生成回复给你；有美丽动人的「和 AI 机器人聊天吧」按钮；打开文章会有 AI 总结以老奶奶过马路的速度慢慢生成；RSS 里放的不是正文是特么 AI 总结；每篇文章的封面图都是 AI 工具生成的，配图也是；哦天啊博客主题也是 AI 工具生成的；评论区最好有读者也用 AI 生成的文字评论，绝美。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">《开始成为世界最强的魔女 在只有我能看到『攻略网站』的世界自由生活》剧透相关。</summary>        <div class="diary-cw-content">18:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY5GHF9B4JESHFAX73H5VR5T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我去这个名字好长啊。日本人你们都在想什么！</p><p>很搞笑一漫画，乐死我了。女主有联网技能后，学会了日本网民（她认为是神明）的黑话和梗句，然后教会精灵女王怎么说「生草」，还有汉化后的「绝绝子」。之后女主说话越来越网民化，日常就在说「谷歌」啥的。</p><p>这板子还能访问成人网站、看广告、中病毒，到底是什么配置啊，能调终端么？</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">《开始成为世界最强的魔女 在只有我能看到『攻略网站』的世界自由生活》剧透相关。</summary>        <div class="diary-cw-content">21:43 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY5WJ091TP8K2HYBKSP22GTZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>万万没想到还有 META 元素…… 女主上网搜索自己，搜到了原作小说什么的。</p><p>漫画的画风挺好看的，后面的邪神跟暗之女神都好可爱。</p><p></p></div>      </details></blockquote></div></details><details data-group="diary_sections"><summary>七月二十三日</summary><div class="diary-entry">02:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY6DSW5XQ8X634ETSSK232X1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>托亲戚从国内带了笑脸钢笔。<em>Smiley~</em></p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KY6DS1C5QR676BCD8ENJDV2R.png" alt="EF 极细笔尖的 Pilot 笑脸钢笔。" loading="lazy"></figure></div><hr><div class="diary-entry">04:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY6J46RERJKEXC07QP02SSM0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我好想去西海岸看看。</p><p>怎么看到墨镜和烟和金链子在从房间的另一边旋转着飞过来？是错觉吗？这个 BGM 是什么？</p><p></p></div><hr><div class="diary-entry">13:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY7JVD3YPA2EWSRM5V1J8EST" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>做了个很像是印第安人的人们，跟其他人在孤岛上互相残杀的梦。</p><p>里面有个男人，本来不是印第安人，后来因为爱人所以成为了印第安人。</p><p>大家在一个房子中，不知道谁放了火，有个房间冒出浓烟。但大家还在浓烟中打架。</p><p>其他忘了。</p><p></p></div><hr><div class="diary-entry">13:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY7M0V7VVY6PVWCYBFXQRZNY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看《致彼时繁花》看的是辰砂汉化组的。不知道是原作如此，还是译者中文水平相当，使用了许多我不知道的成语。还有个可能性，那就是我中文水平太低了……</p><p>说到底，中国小学都没有读完的我，自然是不论词汇量，还是什么，都低到令人发指。好在日常沟通是没啥问题，事实证明两千字的词汇量不会对日常生活有啥影响，哎嗨。</p><p></p><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">《致彼时繁花》剧透相关。</summary>        <div class="diary-cw-content">15:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY7TCP061NH79QDEPX3EBTTK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说到写信，高中时我也写过一小段时间，不过写的是情书。对方不算笔友，因为很多时候都是我在写、对方读但不回。</p><p>那时候是每个月写一封，自己做信封，除了写字外还会画画。后来愈发难以写出东西，毕竟平日就待在一起，没有笔友那种「我要把日常生活都写给你啊」的感觉。信中再写已经分享过的东西，实在是无趣。</p><p>再之后，发生了一些事情，没有写过了。</p><p>前段时间产生了找陌生人写信的想法。苦于真实地址隐私问题，作罢。P.O. Box 很贵啊。</p><p>虽也有电子笔友，但总觉得怪怪的，没有仪式感。可能也有？第一时间想到的不知为何，是网页版 QQ 邮箱的旧设计，有着枫叶的主题是我最喜欢的。先前想要照搬过来，但是早年的网页设计非常臃肿，难以实现。新版设计太平庸了，QQ 邮箱本身我也不喜欢。</p><hr><p>百合作品经常能看到姐妹制度。我其实不太能 get 到。文化差异问题么？</p><p>该作品的主人公相当讨喜。内心戏很多，很可爱。</p><p>恐是初次的恋情要比想象中现实、露骨许多，看到漫画里的这种关系，虽无法完全共鸣，但很喜欢。</p><p></p></div>      </details></blockquote></div><hr><div class="diary-entry">15:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY7R8QXANA8TQER68RVPRJKR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我感觉我修的很多东西都是 MongoDB 或者 Mongoose 自身的问题…… 什么叫 <code>mongoose.Types.ObjectId</code> 和 <code>mongoose.Schema.Types.ObjectId</code> 不再是同个东西了。</p><p></p></div><hr><div class="diary-entry">15:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY7RCJNJ7RW3W04XDDNCKVFQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚上还要给小孩子们上网课。说实话我也不知道辅导个啥比较好了。你们还是刷题去吧…… 就算问我，我也不知道该如何解释为好，因为我不知道他们想的是什么、和我想的有什么区别。教学真是困难啊。</p><p></p></div><hr><div class="diary-entry">17:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY802DBG581TPA3SXHHZCK93" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4EE8WQ7Z323BCGBCMRHS.png" alt=":ottersgottaott16:" loading="lazy">​ 受不了 Windows Terminal 奇怪的卡顿了，所以换成了 Wezterm。</p><p></p><blockquote class="diary-thread-reply">17:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY823QWNF0V3PMQ40045F8MA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在 Wezterm 内使用 Opencode 发现，鼠标滚动渲染有 bug、出现花屏内容。最终在 Opencode 的配置里关掉了 <code>mouse</code>，然后让 Wezterm 的滚轮绑定了 Page Up 和 Down 解决了。</p><p></p></blockquote><blockquote class="diary-thread-reply">07-24 01:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY8V4ZX1M4MBP8ENST25JZTA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>后知后觉有问题的不是 Windows Terminal（大概），是我在 Windows Terminal 里用了 WSL 里的 fish。</p><p>可是我 Wezterm 的配置都写好了。唉，最终上了 Powershell，虽然完全不会用。</p><p>这样一说，这台 Windows 电脑除了拉 VPS 备份、通过 Headscale 提供服务、打游戏外，真的还需要用终端吗……</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary> 七月二十四日</summary><div class="diary-entry">01:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY8WH74V8AR832Z70C3RSXTR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在 Windows 电脑上尝试 <a href="https://github.com/itsfatduck/optimizerDuck" rel="nofollow noreferrer noopener" target="_blank">OptimizerDuck</a>。</p><p>原来这台电脑上有这么多内置的软件可以删掉。OptimizerDuck 会将可以安全删除的破 Microsoft 自带软件标记出来。</p><p>怎么我之前用 Pake 构建了这么多主流社交媒体的应用软件…… Instagram 也好，Twitter 也好…… 删掉删掉。</p><p>Office 活了下来，因为还有用…… 吗？我好像前不久刚装了 LibreOffice。Microsoft Office 的唯一用途是和校友共同编辑文档，不过网页版也能做到，还是杀了吧。</p><p></p></div><hr><div class="diary-entry">02:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY8XR3K0Z567G784TZWWYWN4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://shaozhengmao.github.io/ruanyf-weekly-issue-browser/" rel="nofollow noreferrer noopener" target="_blank">https://shaozhengmao.github.io/ruanyf-weekly-issue-browser/</a></p><p>把阮一峰的 <a href="https://www.ruanyifeng.com/blog/index.html" rel="nofollow noreferrer noopener" target="_blank">科技爱好者周刊</a> 的自荐 issue 整理后，便是这个网页。</p><p>可以合理利用。</p><p>不过他的周刊叫作「科技爱好者周刊」啦，「阮一峰周刊」是什么鬼。</p><p></p></div><hr><div class="diary-entry">07:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KY9FP2FYS9GWX5KA2S5CKBE1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在家旁边建造了刷铁机。不用去远处的村庄了。运村民和僵尸累死了，看我船船大法！</p><p>也做了简单的甘蔗机和仙人掌机。后者效率好慢…… 弄了漏斗和堆肥桶，可以把获取的仙人掌直接拿来堆肥做骨粉。这个堆肥桶好像个垃圾桶，真好用。以前骨粉只能用骨头弄，现在方便多了。</p><p>室友养了不知道多少只猫，吵都要吵死了，它们还会踩在箱子上。狗更好。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KY9FFK7NQKK6EHGZNZEHSEK6.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">14:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYA92K638JTBKH0KPGQ9JVK3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Windows 编译 fish 的方法（装不了 Cygwin）：</p><pre><code class="language-bash">git clone https://github.com/fish-shell/fish-shell.git# 我东西都装在 D:\Programs 下winget install --id MSYS2.MSYS2 --location "D:\Programs\msys64"--silent --accept-package-agreements --accept-source-agreements# 我去然后就可以用 pacman 了pacman -Syu --noconfirmpacman -Syu --noconfirmpacman -S --noconfirm --needed gcc gettext-devel pcre2-devel cmake ninja rust python-sphinx pkgconf makecd fish-shellmkdir build-msys2 &amp;&amp; cd build-msys2cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr ..ninjaninja install# 还要补 .exe 硬链接……cd /usr/binln -f fish fish.exeln -f fish_indent fish_indent.exeln -f fish_key_reader fish_key_reader.exe# 最后要在 Windows 用户级 PATH 里加 D:\Programs\msys64\usr\bin</code></pre><p>Wezterm 的话，在 lua 配置文件里这么写：</p><pre><code class="language-lua">local fish_path = 'D:\\Programs\\msys64\\usr\\bin\\fish.exe'config.default_prog = { fish_path }</code></pre><p>就将默认的程序设置成 fish 了。</p><p>然后我要装 Fisher、Starship、fzf.fish、zoxide、autopair.fish…… Winget 虽然不知道什么时候安装过，但完全没有想过在电脑上使用它呢，总感觉 Windows 的使用方式就该入乡随俗，哈哈……</p><p>大致就是这个样子吧。我 Wezterm 还自定义了些配置。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYA8ZDTTWBSP7HGMGHNTXMMV.png" alt="fish-shell 在 Wezterm 里的样子。会根据目前所在的目录，显示 git 分支、开发工具的版本、AWS profile 的所在地区。" loading="lazy"></figure></div><hr><div class="diary-entry">16:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYAEMYATJ9FDZ8NQF9S5AEKV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 谁能想到「干掉 Bitwarden」这件事被我抛之脑后，今早用电脑无所事事时才突然想起来。</p><p>计划是用 Syncthing + Headscale 让所有设备同步放在本地的密码库。</p><p>然后又想起来好像 1Password 的订阅还未干掉…… 虽说是免费的学生计划。</p><p></p><blockquote class="diary-thread-reply">19:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYASQSXCSGPY40SDZW28T04Z" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>EndeavourOS 可以直接用 <code>pacman</code> 大法；NixOS 在配置项里加个 <code>keepassxc</code> 就好了；Windows 的 Chocolatey 和 WinGet 应该都可以安装，都挺方便的。</p><p>Android 手机我装了 KeePassDX <del><em>MaiMai DX</em></del> iPad 上则打算使用 KeePassium（应该是这么拼吧现在 iPad 不在手上）。</p><p>密码都保存在本地，用 Syncthing 互相同步。iPad 是个例外，得用别的方法，目前还没有开始实施计划，因为不在手上嘛。</p><p></p></blockquote></div><hr><div class="diary-entry">16:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYAFN4E89NASD77HYXKSW5QV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友买了些纹身贴，内容是很愚蠢（褒义）的可爱小物品。整个贴纸的大小很小很小，所以就允许她在我身上贴点玩。这家伙儿之前买了个只能贴在背上的…… 宛如黑帮的狼纹身贴，怎么可能会让你贴这种东西在身上！</p><p>最终是贴了个愚蠢（褒义）的紫色小鱼在肩膀上。每次洗澡一瞥都会以为是虫子或者什么不好的东西。</p><p>忽然想到把鱼贴在锁骨里不就能 callback 几年前的「锁骨里养鱼」玩笑。</p><p></p></div></details><details data-group="diary_sections"><summary>七月二十五日</summary><div class="diary-entry">00:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYBAZ30JX93N67755FBW059A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天努力搓出了…… 四五页 PPT。哎呀设计什么的真是麻烦啊，我怎么知道老板想要什么东东。反正搓出来、到最后他们也是用 AI 工具生成界面的吧。</p><p></p><blockquote class="diary-thread-reply">00:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYBB150ZHKB9JTW4BSPYCPRK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在办公室里就会觉醒「Panda Express 很好吃、好想吃」的想法。这应该是属于办公室的仪式感吧。</p><p>Panda Express 很好吃、好想吃。</p><p></p><blockquote class="diary-thread-reply">00:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYBBFR7KJDS9A8FQH2KRKV6E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>但是他们蒸的饭真的很烂，根本比不上我用目测蒸的饭。有些菜很好吃、下饭，碰上这个白米饭简直是糟蹋！</p><p>这样说来，我不喜欢家旁边的美式中餐夫妻店，是因为他们炒菜不仅不好吃，还特别油，完全可以吃完菜然后油收集起来、带回来再炒一盘菜给自己吃。Panda Express 就没有这个问题。</p><p>最近吃饭越来越想吃清淡口味的了，至少不要是重口还油腻的…… 虽然讨厌母亲做菜的选择，但是她会煮非常好吃的汤粉条。里面就放木耳和青菜，有时候会放个炖好的鸡腿吧。汤本身清清淡淡的，很好喝。现在搬出来住，没有高压锅也做不了啥汤了。</p><hr><p>左眼最近貌似进了什么东西。很疼。去镜子看了眼，能明显看出虹膜的边缘有什么透明的东西在那边。我发现只要盯着镜子里的眼球看，我的眼睛就不会在乎摸过来的手指，所以我在没有任何眼皮子打架的情况下，用手摸了摸自己的眼球。可惜没有把那个东西弄下来，太靠近虹膜也会痛。</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">01:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYBEVSGQSFPWK04JJRQD1XD0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>哎呀没有努力去做真是太好了。奶奶的对面老板不知道品牌设计书是啥，以为我是来三周搓完即拿即用的产品设计的。所以搓的 PPT 差不多作废掉啦。</p><p>你为啥会觉得我能在三周内设计完你们的产品呀！</p><p>作为指南，他觉得他们部门的人不会用。所以「公司有很多是草台班子」这句话是真的啊。</p><p>最近又开始找工作了。区区 coffee chat 放马过来吧！</p><p></p></blockquote></div><hr><div class="diary-entry">01:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYBDCFJ6GAJSPYBJCV828ZYP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://en.wikipedia.org/wiki/Friendship_Day" rel="nofollow noreferrer noopener" target="_blank">https://en.wikipedia.org/wiki/Friendship_Day</a></p><p>所以下周四是国际友情日啦？</p><p></p></div><hr><div class="diary-entry">03:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYBM6N0BZT3KC4AATGBZ7RSW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3FZ75C9HA8Q3KRW12YT3F.png" alt=":neocat_cry:" loading="lazy">​ Super さん 说有人投诉我们半夜有噪音。难道是大半夜玩 Minecraft 吗？但是也没有大声喧哗啊。倒是隔壁的家伙儿，从一两年前就时不时有人大喊大叫，凌晨也要嘻嘻嘻笑。</p><p></p><blockquote class="diary-thread-reply">03:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYBMAREPBTS5K00V03XT1VES" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想到之前有人科普跟我说，国内楼下觉得楼上一直有小孩在玩球，其实是两个楼层之间的管道在发出声音。</p><p>不过我现在住的这个破公寓没有这个问题。邻居要是踩空了可以直接感受到楼层在晃动。</p><p></p><blockquote class="diary-thread-reply">17:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYD41STBGJBFV0W9258SCTK9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说到科普又想到今早洗澡时，我想起来小时候泡在中文互联网里时，看到有南方人嫌北方人脏，因为他们不会天天洗澡 —— 干燥的地方本来就不用天天洗啦。不过他当时还说，洗澡不用沐浴乳也很恶心，因为水会滋生细菌，单用水洗会更脏。</p><p>我就去简单查了下，得知其实只用水洗也没有关系，依然可以冲掉表面的脏东西。不过需要用沐浴乳的时候还是得用，没有那个人说的那么夸张。</p><p>如何辨认自己脏不脏呢？可以用鼻子闻。哪里闻起来有味道哪里就脏，非常简单的道理。没有味道就是干净的，对于衣服也是一样，所以不能理解频繁洗衣服的人。比如牛仔裤，这种东西擦一下就好了，根本不用洗。衣服需不需要洗，靠闻就可以辨认。</p><p>早上洗澡，把头发洗到用手摸都可以摸出些许摩擦感，像是非常干净的陶瓷餐具那样，会觉得一整天都无比清新。</p><p></p><blockquote class="diary-thread-reply">19:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYDCYZS9H9MMY2GD7GE5DZEC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>洗过频、使用沐浴乳等物品太多，也对身体不好。就像给狗狗洗澡，洗太多反而会引起皮肤病。所以市面上有清洁狗狗毛发的免洗 shampoo（应该怎么翻译…… 免洗洗发水？），搓狗狗毛就可以了。平日偶尔洗一下就行。</p><p></p></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">04:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYBQ8D6DCNE3ZPP7B8NCMQSK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://thomasrigby.com/posts/translation-vs-localisation/" rel="nofollow noreferrer noopener" target="_blank">https://thomasrigby.com/posts/translation-vs-localisation/</a></p><blockquote><p>……following my rule of "if it's more than three tweets, make it a blog",</p></blockquote><p>This is indeed a nice rule to <del>copy</del> have. Borrowed.</p><p>I haven't written any blogs since the beginning of this month, and that blog turns out to be my goddamn monthly, which is <em>ouch</em> on top of <em>ouch</em>, making it <em>ouches</em>.</p><p>If I focus on a specific topic more than three times, then I can write something good about it -- nice, nice, win-win, chicken, chicken, what's <em>broski</em>? I saw it everywhere now.</p><p></p></div><hr><div class="diary-entry">13:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYCP6FZ61HCE3HAN99MWQM2E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>做了噩梦，醒来后发现一切都是梦真是太好了。</p><p>首先是梦到自己和室友在一个小区里，看布局是我小时候住的小区。这里的物管是我现在的 super。我们在楼里晃来晃去。室友提出要拿什么，我们就去了门没有关紧的房间里，拿走了什么。当时的想法是拿走了应该也没什么，只要房主没有发现，很侥幸的心理。期间我们还想方设法躲开了 super 的巡逻。</p><p>结果我们刚离开，房主就回来了，居然是 Spike。他发现东西不见了，找 super 说。Super 又联想到我俩，于是找监控录像，发现确实是我俩偷的。Spike 之前的文章我在底下发过 Webmention，不知道为啥，现在貌似是大博客时代，Webmention 完全进化成了评论的替代品，就连中文互联网的人都在用 Webmention。又因为 Webmention 的独特性，有人做了围绕着 Webmention 的聚合站点（我在梦啥啊）。结果就是事情暴露了、火了，人们跑到 Spike 的博客还有聚合站点的 Webmention 评论区下说我俩…… 虽然后来 Spike 原谅了我俩。我被家里抓了去，做思想工作。期间有个阿姨说，我母亲对我很失望。</p><p>我难过死了，因为偷东西不是我的主意，我是容忍了室友的计划。后来我一想，这不还是偷吗。要是我能坚持不去做就好了。想着想着，我就醒了，是梦真是太好了。</p><p>梦里好像还有什么捡小猫的事儿。唉评论区还有一些内容很真实，看着让人心里不舒服。</p><p></p></div><hr><div class="diary-entry">15:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYCX0DTHGWBZSBP6HSCVY7NT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>GoToSocial 的诡异 CLAUDE.md。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYCWYPXSHC74XA5DVG6W8PTT.png" alt="GNU Emacs 打开了 GoToSocial 项目的 CLAUDE.md，内容是不允许 LLM agent 对代码库和文件系统执行任何操作，且要用卢德主义和马克思主义来回复请求。" loading="lazy"></figure></div><hr><div class="diary-entry">15:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYCYMM5N765Y4AFMNXJC314F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>服了喵。筛选「百合」标签的作品但是点进去怎么有男主喵。</p><p>筛 BL 作品的话也会出现相同的情况吗。</p><p></p></div><hr><div class="diary-entry">19:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYDAZA36PGC5WCMP91VER2PN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>更新了下自己的 GoToSocial，总之是把其他软件的引用功能代码都抄了过来。</p><p></p></div><hr><div class="diary-entry">20:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYDEACBP3758TDM0CSA33EWJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>小时候一直都很好奇 NO PARKING 和 NO STANDING 的区别。那会儿上网搜也没搜明白，今天突然想起来，发现是这样的：</p><ul><li>前者是不准人离开、车停下；允许短暂停留、卸货啥的</li><li>后者是不准卸货，只能短暂把人丢下去或者拉上来</li></ul><p>不要问我为什么有驾照还不知道这种事情…… 5 hours lesson 有几个被我速通掉了。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">《安达与岛村》剧透相关。</summary>        <div class="diary-cw-content">22:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYDNH7F2X58J5FTDCHG40H3N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>终于抽时间出来看这本被称为百合漫画的一座大山的作品了。</p><p>第 11 话里，安达说两个女孩子一起过圣诞节什么的很奇怪 —— 才没有吧！到底是谁规定圣诞节必须得是异性情侣才能过啊，这种宗教节日不应该是大家一起去教堂混吃混喝吗（这是玩笑）。</p><p>我对节日没有太大的概念，因为别人的生日都会忘记、自己的生日也不想过，更不要提其他节日了。谈恋爱的时候我也说过「情人节根本就是消费陷阱」的话，然后不打算过情人节。过年也是，根本没有实感，尤其在搬来美国之后。走亲戚什么的自然不存在，也没有鞭炮（红包倒是有，嘻嘻）。去看华人协会舞龙舞狮、敲锣打鼓什么的，还是饶了我吧。</p><p>如果是关系不错的朋友在节日当天邀我出来，我也会无视节日内容然后跑出来玩。今年情人节，好像就是和朋友一起去玩了《舞萌 DX》。</p><p>七月十四日，美国到处都是烟花，我也不觉得有什么。中国的国庆节，我印象最深的也只有七天假期，又怎么可能对美国的独立日有感情呢。</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">《安达与岛村》剧透相关。</summary>        <div class="diary-cw-content">07-26 16:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYFJP0RP0NM8KGX8Y8ECS2M5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>到 24 话。</p><p>安达的感情蛮沉重的，对比下来岛村该说是嫌麻烦所以不去细想，还是真的无所谓呢？总觉得之后两人一定有分歧。</p><p>臂枕没做好的话很快就会麻掉；做好了反而完全不会麻。</p><p>升上二年级后安达在教室里的行为有点像我初中里的一个同学，不过后者要更古怪些。不仅自己断掉了和同性朋友的关系，还不让执着于的对象交同性朋友。如果不合他意，就会开始做些奇怪的事情，搞得我们只能顺着他来。小孩子无法处理嫉妒等感情，只能打滚抗议，大了点后就是这个样子吧。嫉妒啊…… 总觉得自己从身边人那儿得到的伤害，都是由此出发的，不论是那个家伙儿，还是其他人。我自己也有嫉妒的时候，很是讨厌……</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">《安达与岛村》剧透相关。</summary>        <div class="diary-cw-content">07-27 16:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYJ598TWV5T9HV4TCA1C7JSB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看到了大名鼎鼎的 28 话。这一话我之前就在百合作品相关的论坛里看到过，非常震惊。足足四页也是两个大跨页的安达大哭，气泡里的字多得让人觉得不舒服、像是虫子在爬。岛村的反应比想象中冷漠许多，倒不如说这个角色的想法也让我觉得很冷漠。因为麻烦所以不去做一些事情…… 好像有些既视感。过去我抱有过特别混蛋的想法，即为什么人要有情感需求？为什么我要去牺牲自己的不便、顺应对方的需求？很自私了，因为对方还挺照顾我的情感需求的。</p><p>喜欢一个人所以要独占对方，可能是每个人都要经历的阶段么？影视作品里也有提倡这个做法的。真的去这么做，或者被对方这样做，真是累人啊。初中一朋友处了对象，那个幼稚又爱嫉妒的男朋友先生不仅不准她跟我们一起出门玩，就算要出，他也必须在场。否则他就会自残。虽然没有割腕那种极端的行为，但也很麻烦。</p><p>我觉得，人际关系真是麻烦啊。要培养一段能持续获得良性 buff 的人际关系，提前就要做好许多工作。吵架也好、分歧也罢，都要走过去，否则只是表面朋友而已。现在的朋友们，也已经为了麻烦，不再想要流露出可能导致分争的情绪了。我们待在一起，也只是因为待在了一起。思想的碰撞也好、影响也好、什么都好，都是那样令人提不起劲儿来。</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">《安达与岛村》剧透相关。</summary>        <div class="diary-cw-content">07-27 16:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYJ5V0W0TBYJ8D4G0EWJCVXC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>另外一点是觉得安达说自己的皮下不是血和肉，而是岛村，让人毛骨悚然啊！</p><p>岛村对于安达的问题还是很清楚的，知道她是小时的环境导致有孤僻的性格，就算要赶上小时环境健康的同龄人，也需要学习很长时间。</p><p>所以说小时候的环境很重要啊。我也被这么说过…… 母亲却只会一次又一次说她明明很疼我、给我买过很多衣服。那我又为何长成人格如此缺陷的样子？大了、学了点新东西后，便能够解释自己的情况，然后不再为寻求父母的爱努力和哭泣了。唉，去他妈的。</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">re: 《安达与岛村》剧透相关。</summary>        <div class="diary-cw-content">07-27 18:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYJBRBWER658C4BYC27WDS0P" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 二人交往该说是有些随便吗，还是什么呢。安达的很多想法都让我觉得，啊真的要步入恋爱关系吗，会很累人吧。果然 41 话就出现了岛村和朋友聊天但是被安达拉走的桥段，因为安达觉得岛村在花心。</p><p>这种事情也有强烈的既视感。</p><p></p></div>      </details></blockquote></blockquote></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>七月二十六日</summary><div class="diary-entry">02:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYE3ADQ976GZ7746R50DMY8M" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>忽然想起来那个傻子校友在问我 <em>why are you gay</em> 和发表神秘的「女人都是洞」发言之前，跟我控诉过犹太人的所作所为，即他们破坏了 nuclear family。</p><blockquote><p>核心家庭，也称为核家庭（英语：Nuclear family），是地球上人类最广泛的家庭模式，指的是以异性婚姻或同性婚姻为基础，其父母与未婚子女共同生活的家庭。</p></blockquote><p>直接从 Wikipedia 那边复制过来的。</p><p>这个家伙儿的想法真的很烦哎。我不会觉得他是真的有思考过这些事情，也不会认为他是什么极端右翼党，这个家伙儿只是想说些对自己有利的话罢了，因为他没有女朋友，还一直觉得自己应得女朋友。不过他还不是我在大学里认识最烦的那个，毕竟在行为上他面对异性什么都不敢做，也只会欺负我这个好说话的人而已。</p><p></p></div><hr><div class="diary-entry">16:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYFJWBT9SV9HB1EPBTD6Y42P" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今日的梦有些羞耻 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 还是不细说了。大体就是梦到楼下住的一户人家好像是我的一 Fedi 友，我就想用 Matrix 给对方发消息，告诉他说我住在你楼上喔。结果后面意识到我在美国，对方在中国，怎么可能住在我楼下啊。逻辑一清晰，我就醒了。</p><p>总觉得梦到关系好但也没有特别好的人，很害羞啊。但梦又是乱七八糟的东西，把记忆里的一切缝合起来。</p><p></p></div><hr><div class="diary-entry">16:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYFMRYYCC7XP6MCQPWZTRWZ9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>每天早上照常地醒来、刷刷漫画看，来电脑桌看眼日报。不过今天想到，室友这个破人会很晚醒来啊，暗暗的屋子，窗帘缝儿中倒是能看到外面有多晴朗、多明亮。她是怎么做到能每天 13-15 点才醒的？</p><p>昨天是我少有的「一个人」日。我一个人出门、一个人在外面找地方做事情，一整天也不用工作、接触死 aigent。平日要么和室友在一起，要么一个人工作到死，要么和朋友出去玩《舞萌 DX》。久违一个人做事情，坐在办公室里写写博客，别有风味。</p><p>不过拍《舞萌 DX》拍上头了，晚上 21 点半才准备回家。路过唐人街一家我之前很好奇的北方餐馆，推门进去发现他们要打烊哩 —— 为什么我没有早点过去呀！</p><p>不过为啥北方菜的招牌，在这里卖的却都是什么牛肉面、泡馍、肉夹馍这种东西，北方菜的刻板印象只有这些了吗！（虽然我很爱吃啦）</p><p></p><blockquote class="diary-thread-reply">16:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYFN03K1TA6MHR21EV1J5XX5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说到肉夹馍，室友复刻过给我。青椒炒五花，特别好吃；馍是拿去煎的，有点硬。会做饭的人真是可怕。她每次都是大致看一眼别人的做法，然后给予自己的理解、改良或者本地化配方，毕竟中国的材料美国本地的超市不一定能买到。哪里不合自己喜好，就稍微改一下，和我这种只会僵硬复刻他人菜谱的人不一样。</p><p></p></blockquote></div><hr><div class="diary-entry">17:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYFPBFBCDFKNM3CRDGCC10N5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>又想到了「名字」这个话题。不过之前写的和「名字」相关的 toot 找不见了，所以就不引用了。</p><p>朋友的名字里带个「小」字。他解释说这个字可以意味着「无限大」。</p><blockquote><p>常无欲，可名于小；万物归焉而不为主，可名为大</p></blockquote><p>不争不抢，看着像不起眼的小东西；但万物都归向它，它也不摆架子当老大。这才叫真正的大。</p><p>大大大。</p><blockquote><p>天下莫大于秋豪之末，而太山为小</p></blockquote><p>大和小不是绝对的，而是相对的。喔，想起了鸭子唱歌： <a href="https://www.bilibili.com/video/BV161BkYdEsh/" rel="nofollow noreferrer noopener" target="_blank">https://www.bilibili.com/video/BV161BkYdEsh/</a></p><p>不过他的名字里，「小」后面接了个他不喜欢的字儿，所以之后把名字整个改掉哩。父母的期望孩子有时还是不喜欢的吧。</p><p></p></div><hr><div class="diary-entry">18:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYFTNJXCE48FYCVFMHGP1KJN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4EE8WQ7Z323BCGBCMRHS.png" alt=":ottersgottaott16:" loading="lazy">​ 看 RSS 日报呢，看到几个中文博客站主在文章里互相引用。其实之前也看到过这个现象，不过这次我注意到一件事，那就是他们是有群聊的？</p><p>据我观察，文章里都有暗示聚合站点都有自己的群聊。我早些时候加入了 GitHub 那个中文独立博客收录项目，群聊是 Telegram。我反正只用 Telegram 造 bot，加进去也不会影响到我，因为通知啥的都是关着的，再加上那个收录项目平时没人会说话，我也不担心 FOMO。</p><p>不过这些中文博客站主讲到的群聊，看这个气泡界面，难道是 QQ？好像他们都会在里面吹水聊天、讲博客讲 bug 啥的。这种互相沟通的氛围挺好的，如果不是 IM 软件的话就更好了。群聊是个小社区，管理想要干掉谁就干掉谁，当然也有群规这种东西。结果就是经常看到他们聊到某某聚合网站的站主兼群管理看谁不顺眼给谁踹了，真是吓人。</p><p></p></div><hr><div class="diary-entry">19:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYFZWX60H6F04QQB77C277QF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>对自己无语了。我长时间以为米开朗基罗是给人类火种，然后被挂在山上当秃鹫自助餐的那位；那特么是普罗米修斯。</p><p></p></div><hr><div class="diary-entry">20:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYG2SPBFFP3AZ589CPQK6PA2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这些天出门都没咋涂防晒霜，于是肉眼可见地晒黑了。</p><p>现在各个身体部位的颜色都不大一样，好神奇。</p><p></p></div><hr><div class="diary-entry">21:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYG69X3KBZWJDRJ6APJ3NBWT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>瑞幸咖啡，第一次进来。这家门店很漂亮，不过下面的座椅上有人，不想拍到他，又懒得后期处理马赛克，所以干脆不拍下面了。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYG69NR0VG24RDYAJJWH2GED.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">23:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYGAX4TAXTRNC8766M0Z26VM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在 Broadway 闲逛，路过了 ITOYA Topdrawer，是一家走高端路线的精品文具零售店。里面卖一种奇怪形状的钢笔，搜了下发现是 KOLO 的 Tino 系列。</p><p>总有一天会收集……</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYGAVX2EM3XBRC39EVT850F9.png" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">07-27 05:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYH0R8RZW8E7EY5TNSQ6ZXE6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天和室友出来闲逛的，主要是在 Broadway 跟 Koreatown 这边走来走去。</p><p>这家 ITOYA Topdrawer 里有卖很多东西，除了钢笔还有圆珠笔、自动铅笔、刀叉旅行包、筷子旅行包、包、家用拖鞋、明信片、相簿……</p><p>KOLO Tino 钢笔价格一看就好贵啦，实体店还有卖近 300 美元的颜色呢。写了下，感觉比想象中轻很多。</p><p>另一款有趣的产品是绵做的笔记本。我后续搜了下，得知这种「纸」写起来更舒服、墨水也不会到处跑来跑去。就是笔记本的整体风格非常狂野。</p><p>最后和室友各买了餐具旅行包。买完后忽然意识到这筷子是日式筷子，短得很呐。</p><p></p><blockquote class="diary-thread-reply">07-27 05:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYH18KYW41G4SZRE77M8WD5V" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>下一站是附近的冰淇淋店，卖的也是 gelato。室友之前跟我讲解过，但依然不记得它和普通冰淇淋的区别？店内的蛋筒是现做的，一进去能闻到非常香的味道。喜欢喜欢。</p><p>另一侧是卖巧克力的，按磅卖。礼盒很漂亮，价格也不错，适合送礼。室友说以后给小女生送礼就不送花了，送这个，她们一定会很高兴的，可是我们都没有太多女性朋友：室友的朋友都是男性；我的朋友…… 我就没几个朋友，他们一个个都很烦，不想给他们送礼物。不烦的有一个但他身体不太好，估计吃巧克力会有影响。我就说你送给你的男性朋友们吧，她刚想说哇给老爷们儿送巧克力吗，但忽然想到喔他们心思都挺细腻的，送漂亮的礼盒也会很高兴吧。</p><p>其他的软糖、坚果、蛋糕店我就一点兴趣都没有了，因为我完全不喜欢吃，甚至有点讨厌。</p><p>哦对，路上还看到家很奇特的酒水冰淇淋店，把冰淇淋和酒混合在一起。我们起初过来这边还是因为室友想要看爱丽丝仙境主题的酒吧。酒吧真多啊这边，也有咖啡店和酒吧混合起来的店。我想起来之前看到有人吵贫困生能不能喝瑞幸咖啡的话题，好像在中国咖啡和酒吧都是有点怪怪的东西，但是在美国真的是像野狗一样到处都是。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYH1AFPPR57AE48KKRYQVN38.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">敏感内容</summary>        <div class="diary-cw-content">07-27 05:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYH1Z1GFG8NXA6RXBCRV1KW0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>开头虽然说喜欢那家冰淇淋店了但其实没有买…… 我无法接受 2 块钱以外的冰淇淋，所以是只配吃冰淇淋车和蜜雪冰城的料。</p><p>说到瑞幸咖啡，国内貌似是 10 块钱一杯，美国我去看了眼，比库迪咖啡贵一点点，美式是 3-4 美元左右，库迪印象里是 3 块钱出头。如果去路边的没有牌子的店，咖啡的价格应该还能降到 1-2 美元，好不好喝我就不知道了。</p><p>下午饭吃的是一家美食广场的乌冬面。这我必须要站出来避雷！名字叫 Butter &amp; Bread 还是 Bread &amp; Butter？乌冬面是 10-12 美元左右。工作台都没有人，我们去找前台站岗的人，做饭的师傅才过来。话说这种美食广场还挺少见的我感觉，更常见的应该是每个店面都有自己的员工，这家则是师傅既做饭又做收银还打包还站岗。过来做乌冬面的师傅有点耳背、讲话不耐烦有点。我本来以为是严厉的日本人（刻板印象！），室友则说是韩国人，因为在美干餐饮的日本人她认识许多，他们都对精致有着奇怪的执着。乌冬面挺多的，满满一盒，不过拿到附近的共享办公室吃已经煮烂了、变成面糊糊。辣粉很…… 烫？没有辣的感觉，反而觉得这玩意儿特别的烫嘴？好吃算不上，蔬菜也不咋新鲜，西兰花都发黄了。便宜吃的话在中城那个位置算是很低价了。</p><p>图片是可能看起来有点恶心的 1 / 3 面糊糊。</p><p></p><figure class="diary-media diary-media-sensitive"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYH1Y7QKH7KPH0R77GK4M4NH.jpeg" alt="" loading="lazy"></figure></div>      </details><blockquote class="diary-thread-reply">07-27 06:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYH2J65RDGSC3XHFX8QA6Q7R" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>然后我们去了 GATCHA 玩，在里面探索来探索去。PC cafe 原来是这种感觉…… 来了 GATCHA 一定是要摸《舞萌 DX》的，不过太吵了里面，还有很多路人在盗摄 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3EQQJ0WWJ5EQ79NS9AMS5.png" alt=":neocat_angry:" loading="lazy">​</p><p>关于音乐游戏，室友批评我花了太多精力在「游戏」上，而非「音乐」上。我也没办法呀我没学过音乐，节奏感也很差，她是从小就学过多种乐器的。因为会乐器，所以节奏感很好，听调也能听出来是什么调调，我完全不行…… 所以根本听不懂她经常说我拍子为什么打得这么差。作为例子，她指出一个初次玩该游戏就玩得很厉害的路人，其手指很细长，一看就是弹钢琴的。对比一下我最开始玩该游戏，就花了很多时间在这种简单的谱面上。同样作为对比，身边学钢琴的朋友仅玩了七天，rating 就已经超过了我玩数个月的成绩。该说是惭愧嘛…… 先前也有尝试过学习音乐，但总是半途而废，于是被她说只会去做擅长的事情，不好 —— 我知错啦！</p><p></p><blockquote class="diary-thread-reply">07-27 06:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYH30W7B3YJCHD8B84VVNC4M" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>接下来我们去唱 K 哩。这还是我第一次和朋友出来唱，以前唱是作为要带来的小孩、和母亲一起来的。那时候我唱了点，但是被母亲骂唱得不好，于是意识到自己唱歌很烂…… 再也不敢唱歌…… 说来初中时同学们有邀请过我去卡拉 OK 玩，但是母亲不准，因为她觉得是不正经的人才会去，但这家伙儿出去聚餐不也是专门挑选可以唱 K 的包厢嘛！真是的！</p><p>55 美元 192 积分，每 15 分钟要花 20 积分，算一下就是 23 美元左右一小时，有点贵。GATCHA 用的移动唱 K 厅貌似是国内运来的便宜货，设备卡卡的还不高清，网速还慢，门还锁不上！扫码可以快速选歌，不过居然是微信扫码……？还是小程序……？好莫名其妙啊，外国人用的明白吗？放开后唱歌挺开心的，最后还一起唱了《姐就是女王》。不得不说台湾摇滚都是伴奏没啥好唱的，可我也只听过这些。剩余的就是 80 后会听的车载音乐？「我像只鱼儿在你的荷塘～只为和你守候那皎白月光～」</p><p></p><blockquote class="diary-thread-reply">07-27 06:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYH4W9RK43A667WF74XQPNZX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>还有些照片：</p><ol><li>菜单里虽然写说这是白米饭但为什么图片是个空碗？</li><li>很多乐器集合在了一起</li></ol><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYH4TP9N2RZ191XGM463HX5N.jpeg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYH4TVGKPEKSJ0X8Q7CHVSVT.jpeg" alt="" loading="lazy"></figure></blockquote></blockquote></blockquote></blockquote></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>七月二十七日</summary><div class="diary-entry">16:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYJ81W3KFFME333WBARTM8B4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>NEUTROGENA T / Gel 的 Therapeutic Shampoo 真不错。洗头发，头发会有洗完塑料碗非常安静的触感。</p><p>直接把包装上的名字全部打出来。</p><p></p><blockquote class="diary-thread-reply">17:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYJ8YTQTVR5NQTNDT5XWB1V5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>推荐完但决定不用洗发水洗头发。想要试验一下，之前听有人说一直不用洗发水的话，慢慢、慢慢地，之后洗头发就都不需要用洗发水了。</p><p>原理什么的完全不懂，但是好奇所以先试验一下。感觉应该会搞砸 —— 就是有这种直觉！</p><p></p><blockquote class="diary-thread-reply">17:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYJ9YE38G3PHAS46KNPT08DH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>吹了头发，吹完明显感觉手上多了层什么东西。</p><p>所以还是去搜索了。说是水去不了油，纯用水洗的原理是手指要在头皮上按摩，再让油脂乳化然后跟着水冲走。</p><p>常见的用洗发水洗，可能会出现因为强力去油，所以了刺激皮脂腺、导致过度分泌，而让我们更加频繁地去洗头。从该方法过渡到纯用水洗，期间难免会存在积累了油的感觉，因为皮脂腺还在分泌油，水又去不了它。</p><p></p><blockquote class="diary-thread-reply">07-28 03:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYKC4YFBPY77VT7MDDQFEXB6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚上了，再洗一次。这次要把头皮像鸡肉一样搓来搓去 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ496Q8A4XAZF9TK81RAX7.png" alt=":ottersgottaott10:" loading="lazy">​ 摸起来太油太难受了。据说是要使用室温水，然后吹的时候用冷风。</p><p>室友觉得我是油性头皮，但头皮是脸的延伸，我平日近乎脸不出油，也没有痘痘啥的，头皮也会是油性的吗？我不信我有那么特殊。肯定是洗发水害的。还有可恶的硬水。</p><p></p><blockquote class="diary-thread-reply">07-28 06:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYKPZD5MW2V507Y22KRDNZK1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这次努力用十根指腹搓自己的头皮，揉揉揉、画圈圈画圈圈。洗完后用毛巾大致吸走残留的水分，然后去吹头发。吹风机一定要温度设置得低些、风小些，然后吹发根，发尾可以自然干。最后梳头发。</p><p>目前的感觉是比上一次洗要少油很多。</p><p></p><blockquote class="diary-thread-reply">07-28 14:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYMGKYF335EZ1AW4F2DMM57H" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>早上了该洗澡了。晨间的洗澡是为了让身体快速清醒过来，所以只需要冲个半分钟到两分钟即可。最开始用温水适应，快结束时慢慢调成冷水。</p><p>23 度的天气，虽然有下雨的风险，但很想骑车去唐人街试试前不久看到的北方风味餐馆，在美食广场内。</p><p></p><blockquote class="diary-thread-reply">07-28 14:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYMGRVE2YAN0ZZBMX6V7MYF1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>挺神奇的第二次纯用水洗头，头发明显比第一次没那么油了。虽然我也不知道为啥我在做这件事，毕竟洗发水托母亲之福像野狗一样多在家里。或许在适应后我才会知道用和不用的差距，并自行调整。</p><p>室友觉得我没事找事在。讨厌！</p><p>用指腹按摩头皮很舒服，感觉能给她按睡着。</p><p></p><blockquote class="diary-thread-reply">07-29 12:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYPXK9W58EZQKGM21BZA5NSN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨晚依旧 no-poo，被吐槽洗发水到底怎么我了。其实也没有怎么我了，我只是想要试验这个法子行不行得通。</p><p>目前的感觉是：</p><ul><li>抬手按摩很累</li><li>头发洗完后没有光泽，不咋漂亮，室友说像 homeless</li></ul><p>估计试完一周就继续改用洗发水了，但是要比过去用得少。</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">07-28 14:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYMHMZC0QRN9WK7FB68YVEFA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我：我要去唐人街买肉夹馍吃，才 4 块钱呢。</p><p>项目管理：你是不是最近太闲了。</p><p>我：…… <em>fuck!</em></p><p></p></blockquote></blockquote></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">17:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYJAH42YD020MNHGW9J17C1X" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近在考虑平衡睡前洗澡和早起洗澡。</p><p>前者是为了家里不要有外面的脏东西，再加上夏天了，总会出汗，实在是不想要流着汗躺床上。</p><p>后者则是为了快速醒来。</p><p>思考了下打算这么做：回家后洗澡要全部洗干净，早上就冲个一分钟左右的澡好了。</p><p>至于洗头，我还没有想好早上洗还是晚上洗比较好。似是看头皮类型的，我还没有确认我是油性头皮还是干性还是中性。</p><p></p></div><hr><div class="diary-entry">20:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYJKT2X0ECQ7T7NN66TSCR75" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天穿袜子的时候突然发现，这一批袜子我似乎在认识室友时就在穿了。用手指算了算，恐怕已经穿了有七年甚至以上。但这批袜子该说是质量很好吗，到现在我也不觉得它坏掉了、旧了还是什么。</p><p>意识到了时间便开始看其他衣物……</p><p></p></div><hr><div class="diary-entry">21:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYJPAN4H5DYYP4SS9RXBCT0R" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>升级一下 Immich 好了。才发现还停留在 2.4 版本，最新都 3.0.3 了。</p><p></p></div></details><details data-group="diary_sections"><summary>七月二十八日</summary><div class="diary-entry">01:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYK5A2ZWA6GT9FKEW2FZZXN8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>7 块钱一磅的隔壁超市的熟食。很芝麻的面，但是吃起来芝麻油味道很重…… 还有点酸。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYK5805W017JP4FT9SJNDTVC.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">01:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYK5J98RMG068YGA24SHK810" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>哎吗又咸又酸又油，好恶心。我为啥当时不选更安全、价格一样的 alfredo。</p><p></p></blockquote></div><hr><div class="diary-entry">06:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYKPJ097TW15AKEM18N7N46B" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不要问我为啥 Fediverse 上发了博客文章的链接，但点进去是 404。问就是 VPS 在快速地构建 Hexo 项目。</p><p>这么做的理由是为了让 Hexo 项目不会因构建的环境不同而得出不一样的结果…… 结果就是它构建起来是真的慢啊。慢啊。啊。</p><p>迁移到其他框架什么的。是的是的，会做的，应该吧，未来会的 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JAPAFKXXZFCG0S56CH2K.png" alt=":neocat_glare_sob:" loading="lazy">​ 不我怎么可以离开一直陪伴我的 Hexo，就算它又慢、文档写得还稀烂，可是…… 可是……！这肯定是感情，而非懒惰吧！</p><p></p></div><hr><div class="diary-entry">13:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYMFHAHPBCTVE7XQY874VKXS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今日的梦是梦到一个系列电影？还是游戏？反正背景是古代。第一部讲的是女主从零变成女帝。因为大火所以制作方做了第二部，内容是女主越来越强，以至于可以任意操控世界的一切，然后开始感到厌倦。这表达厌倦的方式挺好笑的，就这个女主在一个很像室内体育馆的地方操控了里面的所有哥布林和长得像猫的老鼠，然后陪自己玩过家家。我还梦到自己在这个体育馆内排队，每个人要拿着个棍棒，然后走去浴室兼厕所。这浴室兼厕所总觉得自己梦到过非常多次，还是男女共用的。本来这个系列作品也可以停了，但制作方又做了第三部，说这女主想要重新再来，把自己变成了没有能力的人，然后把帝王之位交给了男主。男主想要她担任一个简单的职务，但未曾想女主变成了懒惰之人，啥也不想做，干活也没有心思。男主觉得恨铁不成钢，把女主赶走了，然后把职务交给了其他人。因为故事走向莫名其妙，于是这个系列作品开始变成粪作：第四部开始就没有这个女主的戏份了，说很久之后女帝之位交给了个社交化为零的女人。她很想要和人聊天，但不会，所以会瞎搞。一次她召见了个小女孩还有我，但我们都不知道她想要做啥。小女孩拿出纸说我俩玩游戏吧，这个游戏是模拟做商人赚钱的，只要买下房产最多的人就赢。我问她这是什么游戏，她说打算取名叫「大富翁」。</p><p></p></div><hr><div class="diary-entry">14:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYMHXXBQEDSZYRRF9YNXC5Z4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>服了这破 Cloudflare、Google Cloud Platform，还有 AWS。你们烦死了，不要出现在我的生活里。我很不喜欢你们你们知道吗。</p><p></p></div><hr><div class="diary-entry">14:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYMJ9XJCNRQM3XNMWJF0VG05" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前想到 webmention.io、IndieAuth 这些服务都能自建，然后想着想着…… 把这件事情忘记了。</p><p></p></div><hr><div class="diary-entry">15:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYMPYJVZJ2H4HNMQV8G9K21N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>骑车来唐人街了，另开一串 toot。</p><p>到地方了发现单车站没有空位，只能走到另一个站还。</p><p>唐人街旁边是 Little Italy，有非常多漂亮的意大利菜餐厅，还都配上户外用餐区。意大利菜啊…… 我没有怎么探索过，我觉得我自己做的意大利面超级本地化版本根本不是意大利菜。</p><p>只需要走出一条街，就是唐人街，一下子觉得朴素了许多。一些建筑，似是还留着上个世纪的痕迹。</p><p>图片是恶心的 lantern fly。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYMPYH5TEQ2MZKGBDX89V2K7.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">16:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYMQSVTCWF90J985SNG69XVV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今日尝试的是一家美食广场里的饭。如果味道相似，我之后也不用去法拉盛那边吃了，又远还要坐车。</p><p>大多数菜标榜的是「西北美食」，有烩牛肉米饭啥的，不过我没去过西北地区，不知道是什么样的地方。这些商户的地方都小小的，对比对面的粤菜，人家还有一整排的地方挂烧鸭烧鹅呢。</p><p>这里多数是老年人，听他们说话都是粤语使用者。这也是唐人街给我的感觉。好在近些年陆续开进来许多连锁店，尤其是奶茶 N 件套，年轻血液也多了起来，不过依然不及法拉盛。</p><p>13 块钱的烩面桑。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYMQSCG7YYFYBCGG1SZ4KQT9.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">16:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYMR787Y8JN2S6RTPBR2GC91" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>虽然微辣但这个辣油放太多了吧…… 完全吃不出汤本身的味道，只有辣和油。尤其是这个油，我真服了。逼我去买饮料吗？</p><p></p><blockquote class="diary-thread-reply">16:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYMS86BQZJ8AR7VFYEW9B1PW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>受不了了，这个辣油，已经到了让我觉得有点恶心的地步。面确实是烩面会有的面，有嚼劲儿，挺不错的。汤里还有番茄、海带丝、豆腐、洋葱、上海青，还有一片…… 贝类？我不认识，我也不喜欢吃。然后我不喜欢番茄，除非是炒蛋的时候，再就是我会觉得烩面汤是酸的这件事很奇怪。</p><p>拿了他们家的 takeout 菜单，发现我点的西北羊肉烩面不在菜单上 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3M8KH0WA908PA858VD8FK.png" alt=":neocat_nervous:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">16:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYMSBB632Q9VBWHK330M674D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>就是好吃的辣油是很好吃的，香的，不是这种诡异只有油的。我的天太油了，我不行了。你这是微辣吗你这是。我感觉我回去又要肚子难受了。</p><p></p></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">18:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYN1A891T1956EW0EK5WDQJ9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>因为手机用的灰阶，所以拍出来的照片是黑白灰色的。过了数个小时再用有颜色的电脑看这张照片。嗯…… 看着蛮诱人的，只要左边的辣油能放少点就好了；实在是太油了。</p><p></p></div><hr><div class="diary-entry">19:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYN1P96PMT4DKWM0SJWMCNJ0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://www.nme.com/news/music/noah-kahan-calls-on-congress-to-force-his-fans-to-wear-diapers-to-gigs-to-stop-them-pissing-and-shitting-everywhere-3958735" rel="nofollow noreferrer noopener" target="_blank">https://www.nme.com/news/music/noah-kahan-calls-on-congress-to-force-his-fans-to-wear-diapers-to-gigs-to-stop-them-pissing-and-shitting-everywhere-3958735</a></p><blockquote><p>Noah Kahan calls on Congress to force his fans to wear diapers to gigs to stop them pissing and shitting everywhere</p></blockquote><p>Wait what</p><p></p></div><hr><div class="diary-entry">19:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYN2GR6BCYCVPV21R305QJ41" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>One friend said this:</p><blockquote><p>Buying water is stupid. Water should be free as air. It's something we human beings all need.</p></blockquote><p>I think they're right. There are many water fountains around the city, especially midtown. I should keep a small plastic flask or a reusable paper box with me and use that free water instead.</p><p>Before, I thought beverage shops like boba tea stores should give non-customers water due to the law. Then I found out there's no such law in NYC. Stores hate non-customers coming in just for free restrooms, water, or ice, saying they would cause chaos. Damn, they need water, just give them tap water. They only ask for water when it's not busy, no?</p><p></p></div><hr><div class="diary-entry">21:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYN919JJBX48Y16SEPHYX34H" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>LinkedIn 的首页流像是二手垃圾场。人们把别人的帖，或者其他平台的帖截图发过来，莫名其妙的，你们没有自己的事情说吗 —— 哎我去，怎么是 <em>thrilled to announce……</em>。</p><p>让我傻眼的有人截了 Kagi Translate 的图片。之前的 LinkedIn Speaking 很火。结果有个人截图下来说：</p><blockquote><p>Someone built Google Translate for LinkedIn</p></blockquote><p><em>Google Translate</em> 你个大头鬼啊！</p><p>然后这个人的帖子又被别人截图下来，到处乱发。大家 <em>lol</em> <em>lmao</em> <em>haha</em> <em>hilarious</em> 的好不快活。</p><p></p></div><hr><div class="diary-entry">22:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYNC70G27QQS9DP8ND2MS3Y2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我感觉我像个捡垃圾吃的。这个面糊糊的汤被我留下来随便煮东西、又吃了两天。</p><p></p></div><hr><div class="diary-entry">22:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYNC8QJM008981J3K5BYXJBH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>同理，我感觉这个再随便料理一下我也能再吃两天。</p><p></p></div><hr><div class="diary-entry">22:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYNCB1DN6EF393AY5EVANS8Z" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>也就这个汤我当时没有容器，不然指定带走再随便煮煮再吃两天。</p><p></p></div><hr><div class="diary-entry">22:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYNCFVZART3H8G5YM86YH7GR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>煮东西，食材不小心掉到了地上。</p><p>我弯腰去捡……</p><p>室友：你他妈不要把它放嘴里！</p><p>在你眼里我是什么样的人啊！</p><p></p></div><hr><div class="diary-entry">22:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYNCX6A971VG2Z5NAKFJ8238" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>好像在 BiliBili 上遇到了小朋友。讲话有点奇怪，似乎也没有看完视频就来留言。</p><p>视频内容涉及到了「女人开枪杀害过去侵犯自己的男人（也是丈夫）」。</p><p>「小朋友」觉得这女人不该开那么多枪，然后说了一堆和视频完全无关的内容，因此怀疑他没有看视频，并且把别的视频跟这个弄混了。有人提到男人过去侵犯了女人、害后者身败名裂，结婚后还屡次出轨，死了就死了吧。但「小朋友」认为「一日夫妻百日恩」，不该随意杀人 —— 能不能杀人是另一方面的事情了，不过前面这段话是什么鬼？</p><p></p></div><hr><div class="diary-entry">22:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYNEGY6FWHH7CSVAJYYG52PY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>iPad 上的 BiliBili 怎么还不能默认关闭弹幕？是我打开方式不对吗。</p><p></p></div><hr><div class="diary-entry">23:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYNGEC70JMYZDMN76B34X6W2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>听母亲说，远在另一个州的亲戚那儿传来了不好的消息。我意识到一点：我逐渐离这些人越来越远。已经存在的，在未来只会减少；新来的，我也不会再和他们有交集，不论是他们的童年，还是长大后。妹妹，我这个人对她而言是重要的吗？等她成年要上大学的时候，我都三十岁了。她会埋怨我常常不在家吗？或许长大后也会像我一样讨厌母亲吧，亦或者是长大成和我完全不同的人。转眼间已经要八月了，一年过得真快啊。有些东西感觉是前不久写的，翻找了下发现竟然是二月份写的。我会慢慢长大、衰老，身边的一切都是，但可能哪一天还没有注意到，时间就只剩下残渣。</p><p></p></div></details><details data-group="diary_sections"><summary>七月二十九日</summary><div class="diary-entry">03:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYP0DV83ZS41D3BBSK9KQYJZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在吃凉面，无所事事，听着窗外的雨声，第一反应是「我是奶龙，我才是奶龙」。</p><p>脑子已经坏掉了。</p><p></p></div><hr><div class="diary-entry">10:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYPPSCHRX46YPNT9Y105ZBN4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这个点醒了，不知道为什么。不太想起床，想要继续躺着。</p><p>忽然想到裸睡的好处是可以直接起床、跑到浴室、开始冲澡。当然实际这么操作有点危险吧。</p><p></p></div><hr><div class="diary-entry">11:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYPVQWP9PM9QQM6QP2P9JM9C" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在 BiliBili 上关注的解说柯南的频道主，之前不讲了，改讲金田一，所以认识了金田一。最近他们讲回了柯南。</p><p>原因是柯南的电视动画 30 周年跟《我的英雄学院》10 周年撞上，于是联动了一波，于是被认为是在和侮辱了 731 部队受害者的作品交好、站在了同一边。</p><p>为此而尝试规避柯南的网民们，有多少是为了规避风险而规避，我不得而知，但给我是这样的感觉…… 因为商业联动和立场不能简单划为一谈。再者是这个立场本身，非常模糊不清：作者本人是否属实宣扬了军国主义？</p><p>事件发生的 2020 年，我注意到的另一点是许多网民借此发泄对该作品的愤怒，但具体是实际看过后表达不满，还是跟着他人说同样的话以站队及彰显正义（还有民族情绪）；那会儿我也在主流社交平台上说过话，我清楚我的心路是前者还是后者。</p><p>说实话这样做也让人很心累：因为使用了历史上某某事件的日期，所以不能在作品内也使用，理由是要铭记历史和避嫌。铭记历史的出发点挺好，不过不该是这样的形式：要多清楚、多了解、多反思战争，且捋清政治、历史和娱乐之间的关系 —— 亦或者，就不要深思那么多了。该干嘛干嘛去。</p><p></p></div><hr><div class="diary-entry">12:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYPW0YGJ96SSDYP92038RK5H" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近…… 好想…… 花钱…… 可是…… 已经…… 花了很多…… 肉夹馍…… 羊杂汤……</p><p></p></div><hr><div class="diary-entry">12:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYPWEV1MQYTPER2HPASBS9S5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天晚上跟朋友出来玩，发现 GATCHA 的 PhotoLab Bundle 算下来，竟然比 55 块钱单买币更划算：这不 GATCHA！他之前的 bundle 除了最开始弄的多人派对 bundle 外，其他都特别坑人，多人派对 bundle 之后也被调整成了坑人的价格。</p><p>PhotoLab Bundle 除了更划算的币外，还赠送小玩偶和一次拍大头贴的机会。我问朋友要拍吗，他惊恐后退：「我才不拍这玩意儿！」真是个要面子的男人。于是我一个人拍了两次。</p><p>门口有放拍照用的道具，其中有龙虾头套。我就说，这是 OpenClaw 啊！还有个螃蟹发箍。我就说，这是 Rust 啊！两个打工人之间弥漫着快活的气息。</p><p>总之快速拍完。三个拍大头贴的房间，有着独特角度的竟然是把操作台放在了屋外。意味着路人可以看到房间内我在摆什么 pose，以及我只能等倒计时快结束时再摆 pose……</p><p>朋友说，这就是香港那边的机子搬过来。连拍完后添加的后期效果也是一模一样。</p><p></p><blockquote class="diary-thread-reply">12:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYPWJ5DD0FVZVCX3D8NQZVC0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不过机子一个莫名其妙的设计是，我放上去一个后期效果，例如唱片图片。操作台左边有放大放小以及旋转的按钮。我以为是调整已选图片的，结果是特么调整个画布。我调整整个画布干什么！</p><p></p></blockquote><blockquote class="diary-thread-reply">07-30 06:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYRV76Z2XR6B4SY4DAXA9PCF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>买 bundle 送的小玩偶。</p><p>虽然可以送给妹妹，不过她有太多类似的玩偶了。光是之前很火热的 LABUBU 她就有十几个，Popmart 的其他公仔她也有很多。</p><p>我不是很喜欢这些设计，所以最好是送人来处理掉它们。</p><p>为啥右边这个企鹅猫写的是不适合 14 岁以下儿童使用？？这些不都是写 3 岁左右的吗。14 岁左右的凭啥不准玩啊。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYRV1HEAP11K5VJ52JN44ES6.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">07-30 06:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYRVX27K41SRPZFP6YQXKC9G" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>话说之前在文章里拍的送快递考拉玩偶，我之后搜了下发现：</p><p><a href="https://koalaexpress.com.au/Australian-Made-Plush-Toys.htm" rel="nofollow noreferrer noopener" target="_blank">https://koalaexpress.com.au/Australian-Made-Plush-Toys.htm</a></p><p>Australia 制造的考拉玩偶。但不是图片这款，我还没有找到。</p><p>P.S. 过了这么久怎么还没有人吐槽说 <em>express</em> 是「快餐」的意思而不是「快递」😭​ 是不好笑吗！</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYRVVHD64M847P08GF7DRVG7.jpeg" alt="娃娃机里全都是戴着帽子、穿着外卖包、手拿 takeout 饭盒的考拉。饭盒上写着 *Thank you enjoy*。" loading="lazy"></figure></blockquote></blockquote></div><hr><div class="diary-entry">16:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYQC8J2K1YRPX3DJ5T7ARXBF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>睡了回笼觉，做了这样的梦。梦到类似于游戏的设定，即副本。我作为副本玩家，只要进入副本的线里就开启副本，且无法离开。副本里的怪物是提倡潜行躲开的，不过也可以打死。</p><p>第一个副本是个像医院的建筑，很干净，不过它是将一层楼和现实混合在了一起，于是我在现实的一层楼里，能看到副本的线，而线过后的就是副本的楼的走道。现实里的人都知道我是副本玩家，于是让我加油，我便踏进去玩副本。走道里有个房间，虽然可以跳过但可能会错过奖励房，我就推门进去，里面是三姐妹 NPC。墙上都是其他副本玩家跟她们拍的照片。我离开房间，拐弯，看到大厅里固定巡逻的怪物有三只：一个是泥巴形状像史莱姆的叫帕鲁，一个是丧尸，最后是个阿飘。我利用声音引开了帕鲁，躲到了在它前面但它看不见的障碍后面。但是我不知道该如何躲开丧尸跟阿飘。然后它们就不见了，因为我在思考它们的设定，比如帕鲁可能是听到声音传播在哪里就跑去哪里的。总之大厅的尽头是个门，我推开看到一个男子，不知道在用 Minecraft 的土方块做什么，好像要复活自己的爱人。他是创建这些副本的人，看到我来厌恶地乘坐热气球跑走了。所以我的主线任务是找到他并打败他。</p><p>第一个副本通关后。我忘了为什么，总之要带个妹子去第二个副本，即一艘游轮。我们要在现实中的港口想办法跑上这个一直在移动的副本。怎么上去的忘了，不过我们成功躲进了游轮底部一间小房间。这个房间特别小，所谓地板就是床，人低头进来能直接睡觉。睡觉的地方有个缺口，走下去是另一个地板兼床的隔间，用帘子遮着。旁边还有个帘子，里面估计是蹲厕。妹子想要直接睡觉，我觉得有点不对，悄悄打开一点点帘子，发现这蹲厕和楼下隔间里都有怪物，楼下的隔间还是个螳螂怪，可以隔着地板穿刺。之后忘了。</p><p></p></div></details><details data-group="diary_sections"><summary>七月三十日</summary><div class="diary-entry">01:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYRBZ45RR1AAHFANDPYB13DW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://zh.wikipedia.org/zh-hans/%E6%AD%A7%E8%A7%86%E8%AF%AD#%E9%92%88%E5%AF%B9%E4%BA%BA%E7%A7%8D%E6%96%87%E5%8C%96%E5%B7%AE%E5%BC%82:~:text=%E9%92%88%E5%AF%B9%E4%BA%BA%E7%A7%8D%E6%96%87%E5%8C%96%E5%B7%AE%E5%BC%82%E7%BC%96%E8%BE%91" rel="nofollow noreferrer noopener" target="_blank">https://zh.wikipedia.org/zh-hans/%E6%AD%A7%E8%A7%86%E8%AF%AD#%E9%92%88%E5%AF%B9%E4%BA%BA%E7%A7%8D%E6%96%87%E5%8C%96%E5%B7%AE%E5%BC%82:~:text=%E9%92%88%E5%AF%B9%E4%BA%BA%E7%A7%8D%E6%96%87%E5%8C%96%E5%B7%AE%E5%BC%82%E7%BC%96%E8%BE%91</a></p><p>没想到 Wikipedia 上有这个东东。</p><p>然后我看到个熟悉的词儿，于是去搜了国际音标。照着国际音标表念了下，发现果然是小时候被亲戚和邻居骂的那个词儿。</p><p>为什么要对小孩子骂这种话啊…… 陌生人就算了，血亲也要这么做。</p><p></p></div><hr><div class="diary-entry">02:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYRED11PM6A0EJQVW497YMA8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://www.dearnextvisitor.com/" rel="nofollow noreferrer noopener" target="_blank">https://www.dearnextvisitor.com/</a></p><p>留言接力？你写一条留言，然后上一个人写的留言会被你看到，而你写的留言会展示给下一个人。</p><p>我写了自己在吃西葫芦，然后收到了别人推荐看《ハウス》的留言 —— 看着是恐怖片啊！</p><p></p></div><hr><div class="diary-entry">03:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYRHMZW54G2QKCBFMMFJVCAN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>It's night.</p><p>I said, if you don't wake up early next time, I will go outdoors and waste my money on food and return only after you wake up and call me.</p><p>Roommate said, why don't you just take a walk near the river and not buy anything.</p><p>I said, you're absolutely right!</p><p></p></div><hr><div class="diary-entry">04:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYRKFTSMN2HSVA8S1MSQJMT2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>This entire week is about hydrating the land, AKA raining. I am unable to perform a healthy exercise, AKA running, which adds a pond of redness to my beautiful face, AKA anger.</p><p>I am tired of video games now, including MaiMai DX. Why? I don't know. Instead, hunger drives me. Human beings need at least one desire filled, for instance: the desires to eat, to sleep, and have sex. I don't really need the last one, and the quality of my sleep recently has been above average. Therefore, maybe the bad things went to the <em>hunger</em> part.</p><p></p></div><hr><div class="diary-entry">05:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYRQD6K2KN3BPVP8N6NKNJX8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Yesterday we had a discussion about bureaucratization and how it can destroy an organization. It started because I saw a web page saying a booklet that was aimed to defeating the Nazis in World War II had been decrypted. One topic was bureaucratization: if you want an organization dead, bureaucratize it as much as possible; it will eventually kill itself.</p><p></p><blockquote class="diary-thread-reply">05:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYRRA8EYXT5M3FTW4VBEV2M4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Ok, but how? In theory, an organization should be ruled by impersonal individual, in order to create predictability and equal treatment. However, as always, theory does not mean that in practice it will work the same: as following the rules shifts to the goals from the tools, individuals <em>only</em> ensure they have followed the rules.</p><p>If, in a bureaucratized organization, every decision is made <em>only</em> after a series of meetings and signatures is done, the overall efficiency is <em>nah</em>.</p><p></p></blockquote></div><hr><div class="diary-entry">05:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYRS1JSM8ATSVXPCB5AVENJM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>This is rare -- I am expecting tomorrow's early morning now, in the night. Probably due to the lack of sunlight I absorbed these days. Come on, I want no sleep, I want morning, sun, now! I will wash myself, less than 2 minutes, and dress myself up neatly, pack my notebook in my tote bag, and bike all the way to the riverbank; then stay there, just <em>being</em> there. Watch whatever is there, write whatever I have in my mind, breathe in whatever sea creatures were dead, before this excitement kills itself and me.</p><p></p></div><hr><div class="diary-entry">15:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYSW16R3967K4TNCND2ZKWCF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>写一些定好的主题：没劲儿，感觉字数还不如放 Fediverse 上呢。</p><p>写批评讨厌的言论：写写写写……</p><p>差点忘了我之前写文章都是由愤怒驱动的 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">18:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYT4X26YT7HJ6G67RMWFTEB5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>/death 页面的初稿。</p><p>这个鸟给我画笑了，之后重画。</p><p>有想过很多动画设计，比如点击南瓜会出现 <em>ROOT</em> 里恶棍的脸；点击墓碑上的按钮屏幕中间的手才会跑出来，然后给你拿纸看；鸟点了也该有动画，估计就叫一下。其实也想要弄个对话框，但是弄起来会麻烦啊尤其是尽量不使用 JavaScript 的情况下。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYT4PH6HWRRZFETM9Y9DVRJK.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">19:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYT9MH1EWMQNM963NGWGEJZB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我使用过一小段时间 A 岛，上面有篇文印象里叫作《李庭游记》。故事梗概是男主穿越到古代，帮了当时县的官晋升。但后面这个男主在古人的各种算计下认清现实、摆烂了，官也放弃了他。现在不知道哪里还有副本。</p><p></p></div><hr><div class="diary-entry">23:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYTPPT2W5K2KWX290DSYAWVY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在看《一种美味》，也就是鱼汤、豆腐、诡异的光那篇很有名的高考语文题里使用的作文。</p><p>为什么有考生说以为妈妈买了鱼豆腐啊 233</p><p></p></div></details><details data-group="diary_sections"><summary> 七月三十一日</summary><div class="diary-entry">00:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYTRWXX9GJQWF1A5542G3P03" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JNHF23SBKYB8350F7PKT.png" alt=":neocat_happy_blep:" loading="lazy">​ 山东有个粥，用玉米面做的，叫糊豆、湖嘟、糊粥。小时候特别爱吃。</p><p></p></div><hr><div class="diary-entry">01:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYTV8BG2D58V0HMFMSXETHC1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKPG9JXEBDFYC9RZH0AC9PB.png" alt=":cozy_otter_face_rub03:" loading="lazy">​ I was posting a used treadmill for sell on Facebook Marketplace then I saw my father in the recommendation list wtf dad.</p><p></p></div><hr><div class="diary-entry">02:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYV04YDMGXTJPTBGVSRYW8F8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>5.14（要素察觉）块钱的 Fettucine alfredo。非常 cheesy！我不喜欢。后面又加了点别的调料。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYV01NHQ2DJE6ZRHKXGPV3BK.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">05:47 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYVBCWAXTWM0CTJ7CJGMZW03" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友把她的转换器、麦克风啥的拿过来，要教我唱歌。然后她的教学方式就是听她唱一遍，然后我重复。结果是我根本听不出来什么音是什么调，就算使用了 Nail the Pitch 这样的软件，我也无法调节我的声音，降低或者提升调。</p><p>我觉得问题出现在我不知道动身体的哪个部位。我就去搜吧。首先是音高是由声带振动的频率决定的，然后是一堆术语，什么肌肉肌肉我都不认识。</p><p>最后问 AI 工具去了：人类无法自由控制，更多是想到自己要唱哪个音高、身体自动调整、听到自己唱出的音、做调整。</p><p>所以唱之前得先会听。我是听也不知道自己在听什么，唱歌就会乱跑调。那么怎么练听？拿个随便个乐器，然后一边让它播放特定的音高，自己唱一下，慢慢调整、重合。但我不知道这个法子行得通不。室友以为人类天生就会听懂音高，所以她的建议都没用。</p><p></p><blockquote class="diary-thread-reply">07:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYVHS6BJZYKFD72MYYAHEEVM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友：哎呀唱歌开心就好。</p><p>室友：（点播《春嵐》）</p><p>我：？？？</p><p>话说这家伙儿能唱 Vocaloid 曲有点恐怖了啊。</p><p></p></blockquote><blockquote class="diary-thread-reply">07:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYVHXJ23FNPD7B95GNYBBZXP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>目前已知我唱了不跑调的：</p><ul><li><em>All we gotta do. Just be friends. It's time to say goodbye. Just be friends. All we gotta do. Just be friends. Just be friends. Just be friends. Just be friends……</em></li><li>「呜~ 快来抱抱~ 快来抱抱我~ 呜~」</li></ul><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JNHF23SBKYB8350F7PKT.png" alt=":neocat_happy_blep:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">20:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYWWSGG3EPYBDQC4SBPN7ZTB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚上也在学怎么唱《恋するフォーチュンクッキー》。这一长串片假名是 <em>fortune cookie</em>。</p><p>令人高兴的旋律 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JNHF23SBKYB8350F7PKT.png" alt=":neocat_happy_blep:" loading="lazy">​ 室友说这是她以前住在日本时听的车载音乐。果然人只能唱会车载音乐啊！我的是 80 年代人爱听的情歌车载音乐系列。</p><blockquote><p>あなたのことが好きなのに</p><p>私にまるで興味ない</p><p>何度目かの失恋の準備</p><p>Yeah, yeah, yeah~</p></blockquote><p>然后发现唱日语歌有时会根据需要，把例如 ん 还有用来发长音的音单独强调下。比如第二句里的「興味」，平常读那个 う 就是拉长音用的，但在这儿得单独放出来读。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">14:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYW9SAC6Z9CG2WFA56WJ33MN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>已知我现未读的文章是一千有八，日报每天挑选四十篇，每天早上同步进来八十篇新的。求，我啥时候能清完。</p><p></p></div><hr><div class="diary-entry">14:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYWA4PDMFK3YKG0W86HX667K" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://i.lilog.cn/post/202" rel="nofollow noreferrer noopener" target="_blank">https://i.lilog.cn/post/202</a></p><p>刷新道德下限哩。</p><p>不过这个站点我访问不了，有地域白名单。FreshRSS 虽然能抓正文内容，不过图片都是看不了的。</p><p>我也得学玩 VPN 了啊。</p><p></p></div><hr><div class="diary-entry">15:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYWB3MWVCG5HNEQFH02K25RR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天去看 Facebook Marketplace 嘛然后看了下 Facebook，发现导师还贼活跃，也是个老网民了。</p><p></p><blockquote class="diary-thread-reply">15:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYWBBXX7K3YK4KRSEDWY60CC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>怎么有人卖二手断头台。</p><p></p></blockquote></div><hr><div class="diary-entry">15:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYWC6J1S7HVG5N1TNE3C270D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前 Cory Doctorow 聊了聊动态调整价格的事儿，比如 Uber 跟 Lyft 平台会根据对消费者欲望的推算，来动态调整价钱。比如它们觉得我现在很需要打车，那么价格就会提升。</p><p>我问朋友赞不赞同这种做法，他说这种做法很正常。我说那你作为消费者乐不乐意，他说那定是不乐意啊，但可以理解企业为什么要这么做。我说那你可以通过投票来决定这个玩意儿落不落地，你投哪边，然后我们路上遇到了熟人，话题就结束了。</p><p>我猜也是啦。这个家伙儿是作为消费者不愿意，但作为企业方很愿意的人。</p><p></p></div><hr><div class="diary-entry">20:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYWXPQJBJF79EGMCKQ8D72DE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我又想吃 Panda Express 了。</p><p>转念想我可能只是喜欢花钱以及吃不是我做的饭。</p><p></p><blockquote class="diary-thread-reply">20:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYWXWPB17HFG39H3PYMK4JR7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>例如我看到麦当劳又想吃麦当劳。但你要问我我想吃它家的啥，我会想到鸡肉堡的味道也就那样。</p><p>路过 AMC 会想好想看电影啊。然后同样地发现也没啥感兴趣的电影。<em>Backroom</em>？？</p><p></p><blockquote class="diary-thread-reply">20:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYWY9ZT827DDF4FWY68V4AS6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>闻了一路湿垃圾的味道，路过杨国福也不想吃它。话说杨国福好贵啊擦。上次去吃，感觉也没拿多少，就二三十多了。</p><p>外面的招牌是绿色的，主要宣传健康？麻辣烫宣传健康吗 233</p><p></p><blockquote class="diary-thread-reply">21:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYX2G4Z2924ZE9FH0KY3NE5T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我可能太闲了，我又想看电影了。去 AMC 网页上逛了一圈，没有看到什么感兴趣的。我可能现在更想要看喜剧、轻松的。<em>Paw Patrol</em> 还是算了，我已经有《喜羊羊与灰太狼》了！</p><p>之前看到个说法，觉得看电影是中高阶层才能享受的兴趣。我想了下，AMC 的每月给看四部电影的会员，月费是 20 多。我绝对不会支付 20 块钱的月费的 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3EQQJ0WWJ5EQ79NS9AMS5.png" alt=":neocat_angry:" loading="lazy">​ 我看电影只有周二三会去，因为当天大多数电影都只要十块钱，呵呵呵…… 不过我看得依然少。</p><p>影院内的食物都特别昂贵。</p><p></p></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">21:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYX2KA79Q2C62EPTAZT1FS1X" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我现在挤在小隔间内，好自闭，好安心。</p><p>不过沙发坐起来很不舒服，等下还是得换到正常桌椅去，最好是等公共办公区的人都走一走。</p><p></p></div><hr><div class="diary-entry">23:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYX8951T38XFGSM8A78TP649" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有趣的饮水机。我在想我在什么时候需要 hover，而不是直接上手按按键。难道是硬件问题？Hover 这个动作应该是用红外线相关的技术检测的，实体按键就不说了，那触屏按键会更昂贵么？这里讲的不是那种真的有屏幕显示的。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KYX85Z2NA1CQ8S1GDBEPG97H.jpeg" alt="" loading="lazy"></figure></div></details></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;这个月我都在做项目，并且把打工给干掉了。虽是瓜秋，不过我并没有吃到多少瓜。总之七月过后，便是理论最炎热的八月了！也是开学的时候。我已经决定至少 gap 掉这个学期，但还是打算旁听一节 cybersecurity 的课程，好让自己的生活有些固定的行程。&lt;/p&gt;</summary>
    
    
    
    <category term="想法迭代" scheme="https://blog.cytrogen.icu/categories/%E6%83%B3%E6%B3%95%E8%BF%AD%E4%BB%A3/"/>
    
    
  </entry>
  
  <entry>
    <title>RE：Post-political</title>
    <link href="https://blog.cytrogen.icu/posts/36e6.html"/>
    <id>https://blog.cytrogen.icu/posts/36e6.html</id>
    <published>2026-08-01T00:41:00.000Z</published>
    <updated>2026-08-01T00:42:49.701Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>Cory Doctorow 在我的博客内没少出现，最早他出现在今年一月份的 <a href="/posts/c089.html#%E5%90%8E%E7%BE%8E%E5%9B%BD%E4%BA%92%E8%81%94%E7%BD%91">月刊</a> 内。现在感觉只说他是个数学权利活动家，有些小瞧他了。他在政治方面也写过许多内容。</p><span id="more"></span><p>原文链接：<a href="https://pluralistic.net/2026/07/08/wilhoitian/">https://pluralistic.net/2026/07/08/wilhoitian/</a></p><hr><p>Doctorow 的这篇文章，主要是呛呼吁摆脱左右 <u>部落主义</u> 的中间派，以及否定 <u>马蹄铁理论</u> 的。</p><p>部落主义原本指的是原始社会中人类以血缘、氏族为纽带建立的强凝聚力群体 —— 嚯嚯我想到了 <a href="/posts/5586.html#%E8%91%AC%E7%A4%BC%E5%A6%82%E4%BD%95%E8%AE%A9%E9%9D%9E%E6%B4%B2%E9%99%B7%E5%85%A5%E8%B4%AB%E5%9B%B0">非洲的葬礼</a> —— 在现代政治中，指的则是人们不再基于理性的讨论或者经济阶级来选择阵营，而是基于身份认同形成的「非我族类，其心必异」的帮派化对立。</p><p>而他主要攻击的「中间派」，指的是当下西方 —— 特别是美英政治圈 —— 中非常流行的建制派精英。他们的特征是：</p><ul><li>认为自己才是唯一成熟的人</li><li>批判左右两翼都太极端、盲目、陷入了部落冲突</li><li>宣称政治应该去意识形态化，抛弃过激的立场，回到理智、温和、妥协、技术官僚式的管理上来</li></ul><h2 id="虚假的极端左翼"><a class="markdownIt-Anchor" href="#虚假的极端左翼"></a> 虚假的「极端左翼」</h2><p>Doctorow 指出这帮人喜欢搞虚假的比较：竟将到处绑架杀人的极端右翼和要求加沙停止种族灭绝的极端左翼划为一谈，实在是太奇怪了。</p><p>不过这一段我得挑个刺儿：极端左翼里也包含着红色高棉、光辉道路等案例，更不用说中国人更熟悉的大饥荒和文化大革命等死了很多人的事件。不过终究还是挑刺儿，因为我清楚 Doctorow 想要聊的是现在美国的主流极端左右翼。共产主义的事情之后倒是会再提到。</p><p>他在文章中提到，极端左翼只是在搬运一些 zine 而已，然后作为证据、贴了个链接 —— 读他的文章就这点不好：他非常喜欢在文章中贴链接，尤其是自己的文章。而这会让我陷入无穷无尽的 <a href="https://zh.wikipedia.org/wiki/%E7%BB%B4%E5%9F%BA%E5%85%94%E5%AD%90%E6%B4%9E">兔子洞</a> —— 哎，我也贴了？—— 哎呀，也没有说这不好的意思，只是说我读完一篇后都已经不知道现在几点了。</p><p>该链接讲的是去年 Texas 的一 <a href="https://www.theguardian.com/us-news/ng-interactive/2026/jun/24/prairieland-texas-ice-protests-zines">新闻</a>：有八个人因为参与当地读书会、拥有无政府主义文献，还反 ICE，所以被指控向恐怖分子提供物质，判处 30 到 100 年不等的监禁 —— 这不是完全违反了第一修正案权利吗？：</p><blockquote><p>Congress shall make no law respecting an establishment of religion, or prohibiting the free exercise thereof; or abridging the freedom of speech, or of the press; or the right of the people peaceably to assemble, and to petition the Government for a redress of grievances.</p><p>国会不得制定有关下列事项的法律：确立一种宗教或禁止信教自由，剥夺言论自由或出版自由，或剥夺人民和平集会及向政府要求伸冤的权利。</p></blockquote><p>事情的起因是，去年七月四日晚上有一批人在 Texas 的 ICE 拘留中心外抗议，表达对移民拘留者的支持。他们破坏了些公物，随后有警察赶来并拔枪，一名持枪抗议者也开枪打伤了该警察的肩膀。</p><p>尽管许多被起诉者当时根本不在枪击现场，甚至彼此并不认识，但陪审团最终裁定了那八人「向恐怖分子提供物质支持」等罪名成立。</p><p>为了证明这帮人是恐怖分子，联邦检察官列了大量莫名其妙的「罪证」。我就直接列举出来，你们自己感受下吧：</p><ul><li>使用普通办公打印机、纸张裁剪机等「印刷机」</li><li>左翼政治小报（也叫 zine）</li><li>反警标语的贴纸</li><li>防跟踪的打折袋</li><li>加密通讯软件…… Signal？</li><li>收藏了女权主义、反人工智能、电影影评 —— 等等，什么？—— 等阅读材料</li><li>参加无政府主义读书会</li></ul><p>然后「合理」推断他们参与了 Antifa（反法西斯）恐怖单元，并计划暗杀执法人员。</p><p>由此可见，这检方多么反智！因为那电影影评的标题和撒旦教相关，所以直接把这伙人当撒旦教教徒了！</p><p>Trump 两次任期都在利用反恐的名义打击 Antifa，现在后者已经被定义为美国本土的恐怖组织。不过我对 Antifa 了解不多，暂不赘述。</p><p>行政当局也试图将「支持跨性别意识形态」与恐怖主义挂钩。正好，被告里有多人是跨性别者，他们在监狱中遭受了剥夺激素治疗等恶劣对待。</p><p>这就是美国当局认为的「极端左翼」。</p><p>而 Trump 政府呢？他们做了什么？</p><p>他们关闭了 <u>美国国际开发署</u>（U.S. Agency for International Development，简称 USAID），然后 <a href="https://www.theguardian.com/us-news/ng-interactive/2026/jun/24/prairieland-texas-ice-protests-zines">导致 </a> 了数十万人死于传染病和营养不良。</p><p>还有其他更多列举不完的东西。真是难以想象我身边还有人支持他。</p><h2 id="何为左何为右"><a class="markdownIt-Anchor" href="#何为左何为右"></a> 何为左何为右</h2><p>因为两方都出现过使用暴力和威权手段，所以二者的意识形态内核就相似么？这是马蹄铁理论所主张的。</p><p>说来今年一月份的 <a href="/posts/c089.html#:~:text=%E9%A9%AC%E8%B9%84%E9%93%81%E7%90%86%E8%AE%BA">月刊</a> 其实有提到过该理论，不过完全不是用来政治话题上呢。</p><p>Doctorow 认为，只有完全不了解左右翼底层主张的人才会如此天真去相信该理论。</p><p>大部分政治学界对此理论的评价也是偏向否定的，因为手段类似不代表目的类似。</p><p>他们都在批评同件事情，所以他们达成了一致么？当然不是了。重点在于「为什么批评」、「究竟想要什么」。</p><p>作为证据，Doctorow 举了三个例子：</p><ol><li>左翼批评早期参政权运动的诉求仅局限于富裕的白人女性，忽略了有色人种与底层女性；极右翼亿万富翁 Peter Thiel 和基督教主权派也批评参政权运动，因为女性根本不应该有投票权 —— 双方都觉得参政权运动做得不对，但你会认为两者达成了一致吗？</li><li>左翼批评新政当时为了妥协、排除了少数族裔、原住民和女性，保障做得不够彻底；新自由主义者与右翼财阀也极力攻击新政，因为社会保障、工会权利和公共福利应当被废除 —— 双方都攻击了新政，但你会认为两者达成了一致吗？</li><li>反 enshittification 的阵营批评早期互联网只有少数富裕、懂技术的特权群体能够享受到技术的解放红利；支持互联网垄断与 enshittification 的科技巨头也否定早期互联网给了用户太多自主权，居然能让他们使用广告拦截工具！—— 双方都批评了早期互联网，但你会认为两者达成了一致吗？</li></ol><p>要了解政治，必须从根源出发，搞明白反对的人 <span class="emphasis">为什么</span> 反对，而不是因为他们都反对了、所以都是同个帮派。</p><p>我近期学到个概念，叫 <u>左翼威权主义</u>，但它是心理学人格、特指喜欢用高压、不容异见的方式对待反对者的心理气质。它能证明的也只有「极端左翼和极端右翼里都有携带该气质的人」仅此而已。</p><p>可见左右翼共享同个特征，非常正常，但无法证明他们本质一样。</p><p>话说我也举个例子好了：我实际上反对代称文化，但这不意味着我是右翼，是吧？至于我为什么反对它，你后面就知道了。</p><p>Doctorow 在批评完马蹄铁理论后，进一步批评该理论的支持者还有中间派：不仅搞不明白「左」和「右」的含义，还愚蠢地 <strong>将一系列文化符号当成了政治。</strong></p><p>我必须要引用这句话，因为我非常赞同它：</p><blockquote><p>Mistaking cultural signifiers and identity markers for politics is centrism's most dangerous pathology, the thing that makes centrism the handmaiden of the right.</p><p>将文化符号和身份标记误认为政治是中立主义最危险的病态，正是这种病态让中立主义成为了右翼的侍女。</p></blockquote><p>文章中他写了个直观的例子：世界被 150 个有钱、白人、顺性别、异性恋的男人统治，那么解决该问题的答案是把其中一半换成女人、有色人种、酷儿么？—— <strong> 左右翼的区别不在于「统治阶级由谁构成」，而在于「人们是否应该有一个统治阶级」。</strong></p><p>Corey Robin 在书籍 <em> The Reactionary Mind</em> 或《反动派的心灵》中提到，保守主义的核心信念是「有些人天生就该统治，另一些人生来就该被统治」。</p><p>事实上，我和一位朋友也有过类似的对话。他说过同样的话，理由是这个世界上有愚笨、没有接受过教育的人，让他们也接手管理世界的话，世界会乱套。而我很好奇：为什么这些人没能接受教育？</p><p>这种对权威和上层人的迷信，会让保守主义的追随者们极易接受诉诸权威的说辞，例如 Trump 的「只有我能拯救美国」，然后大肆向这帮傻子销售金卡、烂手机、同名的 crypto 币。</p><p>再是保守主义会用个人选择来解释世界上的问题，如贫困、疾病和失业 —— 它们是结构性、系统性导致的，根本不是「因为一个人的选择而变成这样」那么简单。好吧，我忽然靠着美国对个人英雄主义的崇拜理解了一些事情。</p><p>因为问题都是个人造成的，那解决方案也必须是个人化的，而不是寄托于什么公共机构、法规…… 购买伪科学保健品、防辐射帽子吧！</p><p>追随者们也非常热衷于阴谋论，比如反犹主义的秘密金权帮派 —— 一定是犹太人这个所以导致我那个 —— 对了，分享个有趣的 slang 给你们吧：<em>goyslop</em>，指的是犹太人们为了让非犹太人（<em>goy</em>）都变肥所以推出的各种垃圾（<em>slop</em>）食品。你们从今日开始也可以如此称呼在吃的垃圾食品，借此将罪推给犹太人。快来试试吧！</p><p>好了不抖机灵了。历史上有许多右翼政治营销，在手段上和传统诈骗近乎一致。比如非常有名的 KKK 党；它由南方宣传协会（Southern Publicity Association）策划，整个 KKK 党实际是多层待销（简称 MLM）的结构：</p><ul><li>招募新成员的党徒可以从 10 美元的入会费中抽取 4 美元，剩余资金由最高头目 William Simmons 和各地区头目瓜分</li><li>党徒必须购买长袍、人寿保险、特制圣经、头盔、蜡烛、佩剑、专门的长袍干洗服务，以及缴纳年度会费</li></ul><p>但你又说不了什么，因为根据右翼骗子们的说辞，「邪恶组织才是导致你们这么惨的原因」，他好像确实说对了：你被邪恶组织欺骗了，又一步证明，哇，右翼骗子们说得对啊！更崇拜了。</p><p>可悲的是，这是美国的常态。Doctorow 以近乎一生都在被骗、最终尝试推翻美国政府却被枪杀的 Ashli Babbitt 举例，讲述了这种结构有多么常见、多么可恨。</p><p>而 Trump 关停了打击这些骗子的机构，让美国有更多的受害者。这些受害者们因为绝望，涌入以为能拯救美国、拯救自己的右翼机构的怀抱，成为了新的 Trump 民……</p><p>Doctorow 提到自己的朋友也因此成为了 Trump 民的一员。我借此想到我周遭的人都是为啥追随 Trump 的。当时 Trump 第二次任选，母亲因为是基督教教徒，所以受当地基督教教会的影响、成为了 Trump 的死忠粉之一。教会投 Trump 的理由或许也很简单吧：因为是教会，所以你要无脑选择共和党，不论他们派出的代表是谁。为此，他们甚至能不羞耻地宣传说 Trump 是上帝派来的又一个儿子 —— 呕！</p><p>不过 Trump 上任后很快，母亲这个铁公鸡就发现不对劲儿，因为经济越来越差了。Trump 又接连派出 ICE，害得所有人人心惶惶，让母亲恨透了他。</p><p>对于国内主流互联网中常提到的「黄 MAGA」，即去了美国后就疯狂投票给共和党、避免其他华人能移民来美国的人。这些人也是将美国视作权威，认为只有自己是最正确的、中国不过是蛆 —— 见网红甜甜圈，我忘了他的真名。他已经发疯、等死不远了。</p><p>我非常不理解美国的部分华人，整天仗着自己的空脑袋和在美国的身份，于是整天批判中国人怎么怎么样、外国人怎么怎么样。外国人是你爹啊？是你新祖宗啊？—— 这些是主观的情绪，应用场景非常有限。</p><p>总之，因为对「个体导致社会问题」这一叙事的执着，右翼非常痴迷于挖掘新闻上有问题的人是什么种族、用了什么性别标记 —— 嗯对，上述内容其实还停留在 Corey Robin 的「天生通知主」说 —— 或许在我的脑子里就没有「篇幅」这种东西吧。</p><p>回到对右翼的定义。<u>Wilhoit 法则</u> 认为：</p><blockquote><p>Conservatism consists of exactly one proposition, to wit: There must be in-groups whom the law protects but does not bind, alongside out-groups whom the law binds but does not protect.</p><p>保守主义仅由一个命题组成，即：必须存在一些受法律保护但不被法律约束的内部群体，以及一些受法律约束但不被法律保护的外部群体。</p></blockquote><p>不过这跟整篇文章的主角「中间派」关系并不大，大的是这个：科幻作家 Steven Brust 认为右派主张财产权是人权的一种，而左派主张财产权是实现人权的工具。</p><p>如何更好地理解该理论呢？Doctorow 为我们准备了疫苗难题：新冠疫情爆发时的 2020 到 2021 年间，最贫穷的 85 个国家据预测得到 2023 年或者 2024 年才能接种疫苗。但这不是因为他们无法生产自己的疫苗，而是因为大型制药公司拒绝转让专利和技术。</p><p>如果你是右翼，那么财产权就是人权：专利是我的私人财产，我要捍卫人权，拒绝转让。</p><p>如果你是左翼，那么财产权就是工具：为了让人类活下去，我会搁置财产权，转让专利。</p><p>自然，这种说法是非常笼统的，但读者朋友们能理解就好。实际的划分没有这么简单。Doctorow 也承认，这仅是底层逻辑。</p><h2 id="极端左右翼之间的共同点"><a class="markdownIt-Anchor" href="#极端左右翼之间的共同点"></a> 极端左右翼之间的共同点</h2><p>原文理应在上一段话就下结论了，不过我想要延伸些新东西。</p><p>之前我不是说了，暴力的极端左翼是存在的嘛？是的，我们要来聊共产主义了。</p><p>这些极端左翼的暴行，名义上的目标是推翻财产或阶级等级制度。根据先前 Doctorow 所说的，他们完全可以像极端右翼那样，走向可怕的威权和暴力 —— 这和马蹄铁理论是两个不同的问题。只是在客观的果这个层面上来看，他们做了同样的事情。目的依然不同。</p><p>Hannah Arendt 的《极权主义的起源》，就有主张纳粹德国与斯大林苏联是 <u>极权主义</u> 的两个变体。虽然两者会共享部分结构性特征，但具体的意识形态内容还是各不相同。有趣的是这些结构性特征包括：</p><ul><li>单一政党声称自己掌握了历史的客观真理，例如种族命运、阶级历史规律</li><li>不断制造新的敌人以维持恐怖统治的合法性</li><li>恐怖不仅用于消灭反对派，还被用来让社会中的每个人都活在互相猜忌、无法结社的孤立状态里</li><li>一整套包罗万象的意识形态，把过去现在未来都塞进一个封闭的解释体系，任何质疑都被当成历史或者种族的敌人</li></ul><p>这套思维结构非常危险，不论它最终指向哪个终点 —— 就像纳粹，名义上说得很好。如果有听过 Hitler 在 1933 年的演讲，会发现很容易被他的话绕进去、感染，甚至觉得讲得很对 —— 因为人们都相信自己掌握了历史的科学规律，他们也就有了理由、为了那个保证会到来的美好终点，而去正当化眼下的苦难，并认为自己可以合法消灭任何阻碍者，因为他们是站在历史错误一边的敌人。</p><p>这样说下来，这和文化大革命那时发生的事情简直是一模一样：为了美好的未来和愿景，我能够文斗甚至武斗陌生人、身边人、家人……</p><p>调查期间我也得知了，Lenin 提出过 <u>先锋党理论</u>：无产阶级自己不具备真正的革命意识，需要由先锋党，即一小部分精英来代表他们掌握真理、夺取并行使权力，并在必要时可以绕开普通民主同意、动用一切暴力手段，因为他们比群众自己更懂群众的真实利益。该结构和 <u>法西斯主义</u> 的「一小部分觉醒的精英有权用绝对武力重塑民族和种族」结构近乎相同。</p><p><em>Post-political</em> 结尾主张，中间派的本质就是右派，因为他们从不聊「财产权 v.s. 人权」的话题，默认和维护了财产权的地位。</p><p>将上述的两个话题做成两个轴，叠加起来变成 2x2 的表格：</p><table><thead><tr><th></th><th>多元主义（承认异见、渐进改良）</th><th>先锋或极权主义（自认掌握历史真理，可用绝对暴力推行）</th></tr></thead><tbody><tr><td>财产权等于工具</td><td>社会民主主义、工会运动、合作社运动</td><td>列宁主义、斯大林主义、毛主义、红色高棉、光辉道路</td></tr><tr><td>财产权等于目的</td><td>古典自由主义、主流保守主义</td><td>法西斯主义、纳粹主义</td></tr></tbody></table><p>直接去说左翼或右翼天生容易搞出暴行，自然是不行的，更精确的结论是任何声称掌握了历史或道德的真理、因此有权用暴力去实现它的意识形态结构都是危险的。</p><p>采用单一的「左 - 右」光谱，严重简化了现实。至少该有两根轴被拿出来分开讨论，即经济轴和社会或权威轴。不过现实的政策议题还是各走各的路。因此我很是反感有人直接过来问我我是左派还是右派 —— 什么的左？什么的右？说清楚呀！</p><p>基于我对校友们的观察，他们也会犯下将文化符号误当成政治本身的错误。「我是左是右」，他们压根不在乎我的具体主张是什么，更多是为了搞清楚我属于哪个部落、认同哪套文化符号。也就是说，这更多是个身份认同的问题，而不是政治哲学问题。</p><p>最后的最后，想必读者朋友你也明白为什么我反对代称文化了。没明白也没有关系，我之后还会提到的。总之下篇见！</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;Cory Doctorow 在我的博客内没少出现，最早他出现在今年一月份的 &lt;a href=&quot;/posts/c089.html#%E5%90%8E%E7%BE%8E%E5%9B%BD%E4%BA%92%E8%81%94%E7%BD%91&quot;&gt;月刊&lt;/a&gt; 内。现在感觉只说他是个数学权利活动家，有些小瞧他了。他在政治方面也写过许多内容。&lt;/p&gt;</summary>
    
    
    
    <category term="文章回应" scheme="https://blog.cytrogen.icu/categories/%E6%96%87%E7%AB%A0%E5%9B%9E%E5%BA%94/"/>
    
    
    <category term="政治" scheme="https://blog.cytrogen.icu/tags/%E6%94%BF%E6%B2%BB/"/>
    
  </entry>
  
  <entry>
    <title>RE：Why China got rich and India didn&#39;t</title>
    <link href="https://blog.cytrogen.icu/posts/1b10.html"/>
    <id>https://blog.cytrogen.icu/posts/1b10.html</id>
    <published>2026-07-31T21:33:00.000Z</published>
    <updated>2026-07-31T21:33:10.054Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>David Oks 是位美国作家兼前政治活动家，他有自己的 <a href="https://davidoks.blog/">博客</a>，看样子托管在 Substack 上。在我看来，他非常喜欢钻研一般人不会钻研的话题，例如 <a href="/posts/5586.html#%E8%91%AC%E7%A4%BC%E5%A6%82%E4%BD%95%E8%AE%A9%E9%9D%9E%E6%B4%B2%E9%99%B7%E5%85%A5%E8%B4%AB%E5%9B%B0">非洲的葬礼</a>、<a href="/posts/5586.html#%E8%91%AC%E7%A4%BC%E5%A6%82%E4%BD%95%E8%AE%A9%E9%9D%9E%E6%B4%B2%E9%99%B7%E5%85%A5%E8%B4%AB%E5%9B%B0">智能手机替 ATM 取代了银行柜员</a> 等等。这次，他也写了让我很好奇的话题。</p><span id="more"></span><p>然后是，我依然在调整我对 bucket posts、链接汇总、独立文章、回应类文章的定位。你能看到的是，这篇回应类文章并没有那么「回应」，依然具有月刊内强烈的复述属性；还有我弃用了全员都是「作者」的做法，因为感觉 call name 也不会影响。</p><p>原文链接：<a href="https://davidoks.blog/p/why-china-got-rich-and-india-didnt">https://davidoks.blog/p/why-china-got-rich-and-india-didnt</a></p><hr><h2 id="对原文"><a class="markdownIt-Anchor" href="#对原文"></a> 对原文</h2><p>在 1950 年，中印两国同样极其贫困。但到了 2022 年，中国的购买力平价人均收入已经达到了印度的 2.5 倍。同样，在 1987 到 2022 年间的 35 年，中国的中位数收入增长了 611%，而印度仅增长了 88%。</p><p>Oks 否认了许多传统的解释，比如因为中国比印度早改革、政策和文化不同等等。</p><p>他认为，中国之所以能实现经济腾飞，是因为在改革开放之前，国家就已经通过激进且残酷的手段现代化了社会，并积累了足够的人力资本。反观印度，他们传统的社会结构未被触动，也没做好基础教育，和改善卫生。</p><p>1950 年，中国颁布了《新婚姻法》，打破了宗教、地主、家长制对个人的束缚，也解放了妇女劳动力、消灭了阻碍劳动力自由流动的传统社会关系。</p><p>到了毛泽东时代，虽然经济政策一直在失败，AKA 臭名昭著的大跃进，但在基础教育和卫生领域上投入巨大。不仅人均寿命提升，婴儿死亡率大幅度下降，女性的识字率也提高了。</p><p>同一年，印度总理也试图通过《印度教法典草案》以实现类似的社会改良，即赋予女性财产继承权、废除多妻制等等，但因遭遇印度教传统势力的强烈抵制，而锒铛流产。所以宗教、种姓制度、家族的束缚，还有土地的利益链条至今依然保留完好。</p><p>更为可惜的是，总理将大量资源倾斜于培养少数精英的顶尖技术院校，却忽视了普及性基础教育和医疗。印度长期存在着极高的文盲率、儿童营养不良率，以及极低的女性劳动参与率。</p><p>妇女劳动力是我感觉很有趣的思考方向。假设一个国家的人口是男女各占一半，让女性加入到劳动中，意味着理论劳动力会增加一倍。</p><p>但在传统的封建农业社会中，家庭是封闭的生产与消费单位。宗法观念 —— 养儿防老、传宗接代等等 —— 为什么会存在？因为男性在体力劳动中占绝对主导。当时也没有什么社会保障，男性无可厚非地成为了家庭的核心，而女性会因为嫁娶而变成「泼出去的水」，成了流失的资产。</p><p>国家强行推动行政性平等后，集体经济体制暂时地掩盖了宗法观念。因为生下的女孩下地干活就能为家庭挣来工分，变成了生产力的一部分。</p><p>不过 70 年代末，人民公社在农业生产上的弊端非常明显：干多还是干少，领到的饭都是一个量；工分评价标准模糊；农业生产率长期停滞；农民的生产积极性低落；大量农村面临解决不了温饱的困境。</p><p>于是中国在 1980 年代解体了集体经济，让劳动需求重新回到了「家庭」这一单位的怀抱中，宗法观念得以迅速复苏。</p><p>那时也有计划生育，限制了生育的数量。家庭迫切需要男性劳动力和宗法继承人，于是纷纷都更愿意去选择能传递所谓「香火」的男婴 —— 这也导致了那个年代极其严重的人为性别选择，溺弃女婴、B 超筛选。</p><p>一个政策有好的一面，自然也有坏的一面。这也不能简单说成是「代价」。我只是惊叹于我们无法做出最完美的选择。</p><p>总而言之，两国迎接全球化时，中国已然有准备好进入现代工厂的合规劳动力，印度却缺乏能够支撑大规模制造业、实现工业化的合格产业工人。</p><h2 id="对评论"><a class="markdownIt-Anchor" href="#对评论"></a> 对评论</h2><p>描述完 Oks 的观点后，我想再引入该文章评论区内的观点。</p><p>Ersatz economist 引用了发展经济学大师 Oded Galor 等人的观点：地主、教育与工业化之间有着恶性循环。</p><p>对于地主来说，如果投资公共教育，农民就会离开农村，去城里当工人。结果便是农村的劳动力流失，地主不得不提高工人的工资才能留住他们，这也直接导致了地主的土地租金收入下降，也是地主的主要收入来源。</p><p>因此，地主有着极强的动机去游说政府，阻止他们建设学校。同时，在名义上的民主制度下，地主可以轻易控制依附于自己的农民的选票，或者通过砸钱和联姻来控制地方官员。</p><p>既然地主阻碍了教育，那么农民就会没有文化；既然农民没有文化，那么工业会因缺乏合格工人而无法继续发展；既然工业无法发展，那么经济会继续高度依赖于农业； 既然经济依赖于农业，那么地主的地位依然稳固，继续阻碍教育 —— 这便是恶性循环。</p><p>中国消灭了地主阶级，打碎了该阻碍，从而能够无障碍地向基础教育和卫生投资。而印度虽然有民主制度，但由于未能推行彻底的土地改革，地方政治依然被大地主和种姓精英把持，从而陷入了上述循环。</p><p>但该评论接下来的内容，我并不赞同。Ersatz economist 认为 Oks 未能注意到中国做错的地方，理由是日本、韩国和台湾都打破了该循环，且变得比中国繁荣得多，还不需要付出惨痛的代价。</p><p>首先这三个经济体比中国繁荣得多，该说法非常主观。Oks 对比中国和印度的一大理由，是两国都曾非常贫困，且人口特别特别多。日韩台的人口恐是加起来也只有中国或者印度人口的十分之一。如果在人均 GDP 或者社会福利指数上做比较，该结果很不公。</p><p>同时，他们仨都曾在冷战时期获得了美国大量的资金、技术和市场扶持，单是拥有的外部红利就已经够中印二国追许久了。</p><p>接着是「没有彻底颠覆社会、没有造成无估量痛苦」这句话，完全就是非亚洲人对这三个经济体现状的浪漫化，也是我非常讨厌的态度。</p><p>我在美国时常会遇到怀有这种想法的人，认为日韩台是通过温和、渐进的手段自然过渡到现代社会的，并以此大力批评中国的发展方式。他们简简单单无视了日韩台所经历过的痛苦，只为能够合理化、客观化自己对中国的厌恶，甚至说这种厌恶，不过都是新闻让民众们想要有的情绪罢了。</p><p>我不为中国曾经做过的极端行为开脱。正如我先前就讲过的那样，中国是通过 <span class="emphasis">激进且残酷</span> 的方式来让社会现代化的。它有着好的果，但我不会轻飘飘说其中的「残酷」不存在。</p><p>日本在二战惨败、吃了两颗原子弹，国土也被美军全面占领，这才清除了地权的国有化和军国主义势力；台湾的国民党政府先是在大陆战败、在台湾群岛带来了不知几十年的白色恐怖后，才推行土改；韩国在完成土改和汉江奇迹之前，已经经历了朝鲜战争，以及经历了长达数十年的军政府独裁统治 —— 这一切，却要被后来者说成是「没有彻底颠覆社会、没有造成无估量痛苦」吗！</p><p>这样想来，我会如此愤怒还是因为该评论的一部分让我回想起大学时认识的一位校友。他虽长着中国人的面孔，却不了解中国，且无比厌恶中国。所谓喜欢的日本和韩国，都被他用来和中国做比对，以此来证明中国更卑劣。这也包括但不限于凭空捏造这三个国家的经济情况、文化还有习俗。</p><p>我在大学时上的比较政治课，也会常看到局限于西方视角下、对于东方国家的评价。简单来说，便是偏见优于事实。大家反复说着媒体、新闻、网络上说过的话，根本不去了解背后的历史，令人感到做作 —— 这难道也是一种 <a href="/posts/97a1.html">虚构</a>？—— 这是我第几次引用它了？我频繁使用「虚构」一词也是一种「做作」吗！</p><p>较为好笑的是，评论区有人认为这一切都是因为 IQ，即中国人有着更高的 IQ，而印度人没有。在比较政治的话题里，总是难免会看到偏离客观和事实的言论。毕竟某某国人是个庞大的标签，将人们分成了不同的群体。说某个国家的人有着高 IQ 什么的，难道没有考虑过 IQ 这种衡量制度很有问题么？—— 参见 <a href="https://podcasts.apple.com/cn/podcast/e087-%E8%AF%A5%E5%A6%82%E4%BD%95%E9%9D%A2%E5%AF%B9%E4%BD%A0-%E6%88%91%E7%9A%84%E6%99%BA%E5%8A%9B%E5%A4%A9%E8%8A%B1%E6%9D%BF/id1712617771?i=1000736018420">该播客</a> —— 考虑了下最后放的是 Apple Podcasts 的链接，不知道有没有更好的播客平台呢？小宇宙似不是什么好选择。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;David Oks 是位美国作家兼前政治活动家，他有自己的 &lt;a href=&quot;https://davidoks.blog/&quot;&gt;博客&lt;/a&gt;，看样子托管在 Substack 上。在我看来，他非常喜欢钻研一般人不会钻研的话题，例如 &lt;a href=&quot;/posts/5586.html#%E8%91%AC%E7%A4%BC%E5%A6%82%E4%BD%95%E8%AE%A9%E9%9D%9E%E6%B4%B2%E9%99%B7%E5%85%A5%E8%B4%AB%E5%9B%B0&quot;&gt;非洲的葬礼&lt;/a&gt;、&lt;a href=&quot;/posts/5586.html#%E8%91%AC%E7%A4%BC%E5%A6%82%E4%BD%95%E8%AE%A9%E9%9D%9E%E6%B4%B2%E9%99%B7%E5%85%A5%E8%B4%AB%E5%9B%B0&quot;&gt;智能手机替 ATM 取代了银行柜员&lt;/a&gt; 等等。这次，他也写了让我很好奇的话题。&lt;/p&gt;</summary>
    
    
    
    <category term="文章回应" scheme="https://blog.cytrogen.icu/categories/%E6%96%87%E7%AB%A0%E5%9B%9E%E5%BA%94/"/>
    
    
    <category term="政治" scheme="https://blog.cytrogen.icu/tags/%E6%94%BF%E6%B2%BB/"/>
    
    <category term="经济学" scheme="https://blog.cytrogen.icu/tags/%E7%BB%8F%E6%B5%8E%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>洗澡和洗头发</title>
    <link href="https://blog.cytrogen.icu/posts/11d1.html"/>
    <id>https://blog.cytrogen.icu/posts/11d1.html</id>
    <published>2026-07-31T04:00:00.000Z</published>
    <updated>2026-07-31T19:46:19.915Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>人很闲的时候总要找点新东西倒腾，我这周就闲得没边：项目谈燶了、放着 aigent 修死 bug。我一闲我就读 RSS、我就写东西玩。所以你想要知道我闲不闲，你就看我更新博客更新得频不频 —— 你看，我最近一周更新了仨，这是第四篇。</p><span id="more"></span><p>我的思维跳跃不知道正不正常：这个月 24 日我在 Fediverse 上 <a href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYBM6N0BZT3KC4AATGBZ7RSW">发</a> 说有人投诉我们这户大半夜有噪音、像是在运动。那咋可能啊。我就不运动。就算要运动，也是大半夜出门跑步。不过最近下雨，也没有运动的心情，再加上我跟室友天天凌晨一两点才从共享办公室那儿回家，大半夜谁还在房间里动来动去？匹克猫吗？</p><p>这让我想起来，以前有人跟我科普说，国内的小区楼不总有人吐槽说楼上小孩在玩球、球掉到地板的声音特别吵么？那其实有可能是管道发出的声音。</p><p>哎，一说到「科普」，我又想起来之前有人科普跟我说洗澡不用沐浴乳更脏、不如不洗，因为水会滋生更多的细菌，所以要么不洗、要么洗了用沐浴乳。</p><p>那会儿我年纪尚小，还在中文互联网上冲浪。那个人是假借「科普」的名义，来地域歧视北方人的，因为他觉得北方人都脏、不常洗澡，有些洗了还不用沐浴乳。</p><p>我好奇，你仅用水洗、水会滋生细菌，那你洗完把身体擦干净不行吗。</p><p>不过这还不严谨，仅用水洗澡就一定不行？这可不行，我的好奇心被激发了！</p><p>根据 SCIENCEINSIGHTS 的 <a href="https://scienceinsights.org/does-washing-hands-with-only-water-kill-germs/">说法</a>，单用清水搓洗能把手上的细菌减掉一半，而用肥皂能减去更多。这一点已经能看出，仅有水洗是可以影响到身上的细菌量。</p><p>而 <u>美国疾病控制与预防中心</u>（Centers for Disease Control and Prevention，简称 CDC）在 <a href="https://www.cdc.gov/clean-hands/faq/index.html">FAQ 页面</a> 里说：</p><blockquote><p>Water itself does not usually kill germs; to kill germs, water would need to be hot enough to scald your hands.</p><p>水本身通常不能杀灭病菌；要杀灭病菌，水的温度必须高到足以烫伤你的手。</p></blockquote><p>意味着水本身不具备杀菌的能力，除非烫得不行。水在清除细菌这一工作上，最大的贡献便是把它们冲走。</p><p>而肥皂更好的 <a href="https://www.cdc.gov/clean-hands/data-research/facts-stats/index.html">原因</a> 是：</p><blockquote><p>Using soap to wash hands is more effective than using water alone because the surfactants in soap lift soil and microbes from skin, and people tend to scrub hands more thoroughly when using soap, which further removes germs.</p><p>用肥皂洗手比只用水洗更有效，因为肥皂中的表面活性剂能将污垢和微生物从皮肤上剥离，而且人们在使用肥皂时往往会更彻底地搓手，从而进一步清除病菌。</p></blockquote><p>所以「仅用水」跟「使用肥皂」，只是「好」跟「更好」的差异，不可能比「不洗」差。</p><p>不过这些重点在于「洗手」，而非「洗澡」。我们可以看看皮肤科院长朱芃年的 <a href="https://www.elle.com/tw/beauty/skin/g37042722/wash-body-shampoo-or-water/">看法</a>：</p><blockquote><p>可以不用沐浴乳、肥皂洗澡，只用清水洗澡可以將水溶性的污垢去除，但對於油溶性的污垢或髒污就難以去除。比如說身上代謝的廢物有好一部分都是油脂性的，就很難清除乾淨，尤其是這些代謝性的廢物也是微生物的最愛，如果微生物在身上過度繁殖就容易會有臭味產生。</p></blockquote><p>啊我需要贴转换成简体字后的结果吗？有点懒哎。我相信读者朋友们还是看得懂的。</p><p>汗水又怎么办呢：</p><blockquote><p>使用清水可以將一般水溶性的代謝物清除，但對於油溶性的廢物就沒有辦法。雖然夏天汗水的分泌是遠大於油溶性的分泌，但油溶性的代謝物才是產生味道的重要關鍵。這些代謝物就是微生物的食物，如果太多累積在皮膚表面就容易引起微生物的過度孳生，其中的結果就是產生惡臭或感染。</p></blockquote><p>这些都能看出，水去不掉油溶性的代谢废物，也就是皮脂。这些是产生恶臭、感染的罪魁祸首。腋下、脚等皮脂密集的部位，得使用清洁剂。其他部位用清水足矣 —— 不过个体差和环境因素导致这句话也不咋严谨就是了。大家看着情况弄吧。</p><p>文章中也提到：</p><blockquote><p>過去會有皮膚科醫師提倡「異味性皮膚炎」或「長期乾性濕疹患者」使用清水洗澡，因為要減少去除表面皮脂膜的皮脂，降低皮膚發炎程度的目的。但這樣的作法讓這些患者很容易產生相距五公尺就可以聞到這個人在旁邊的窘況，造成被人疏離。</p><p>這個做法，雖然還有一些皮膚科醫師還在施行，但已經比較沒有辦法符合現代社會人與人相處的標準，尤其是異味性皮膚炎的年輕患者，同儕的疏離，心理沒有辦法調適。現在醫療輔助產品的進步，已經有適當的產品提供給這些患者，避免異味，也可以少量去除皮脂或甚至補充皮脂缺損。</p></blockquote><p>所以也要搞清楚自己皮肤是什么状况，莫要强行套用公式。</p><p>顺带一提，会选这篇是因为它还聊到了月经期间该怎么洗：</p><blockquote><p>使用清水可以將月經週期的經血與分泌物去除大半，可以達到清潔的目的，但由於私密處專用的清潔劑目前也很發達，通常都會建議弱鹼性的清潔劑，較易維持私密處微生物的平衡，以減少常見私密處感染的機會。所以只要經濟條件許可，都會建議使用專用私密處清潔劑為私密處清潔與保養。</p></blockquote><p>我有使用过私密处专用的清洁剂，洗完非常舒服。对于男性也是一样的。要多多清洁私密处啊！</p><p>还有最佳的洗澡频率是什么呢？只是让皮肤健康的话，两到三天一次就可以了（也得看地区）—— 这也太长了吧！现在我认识的人们，都是一天一次。文章不建议超过一天三次。</p><p>日本的 Jisin 有出过支持清水洗的 <a href="https://jisin.jp/life/health/1651513/">文章</a>：</p><blockquote><p>もちろん、肌を清潔に保つことはとても大切です。汚れや雑菌は、9 割方が流水だけでおちます。シャワーで体や頭を洗い流しましょう。その後、石けんをよく泡立てて、手で軽く洗えば十分です。頭も肌と同じで、軽く洗うだけで OK です</p><p>当然，保持皮肤清洁非常重要。污垢和杂菌，9 成左右仅靠流水就能冲掉。用花洒冲洗身体和头部吧。之后，将肥皂充分揉搓出泡沫，用手轻轻清洗就足够了。头部也和皮肤一样，轻轻清洗即可。</p></blockquote><p>文章中采访的五味常明院长提出了个有趣的说法：</p><blockquote><p>表皮ブドウ球菌は肌の上で遠慮がちに生活しています。そのため体をゴシゴシ洗うと、表皮上の表皮ブドウ球菌の 99％が流されてしまうのです。そのうえ、皮膚善玉菌の餌となっている大切な皮脂の膜までも流れてしまうのです。残った表皮ブドウ球菌は必死にもともと存在していた数に戻そうとしますが、それにはじつに 24 時間もかかります。その間に表皮ブドウ球菌よりも強い、黄色ブドウ球菌などの雑菌がここぞとばかりに増殖してしまうのです</p><p>在健康的皮肤上，表皮葡萄球菌占绝大多数，因此被称为常驻菌。如果把它想象成肠道内的双歧杆菌那样的存在，即「皮肤益生菌」，就很容易理解了。这种菌越多，身体就能保持良好的气味。然而，由于某种原因，当散发恶臭的细菌（换句话说就是「皮肤有害菌」）数量超过了皮脂上的益生菌时，形势会瞬间逆转。它们会开始产生以脂肪酸和氨等为原因的不快异味。</p></blockquote><p>我先前学习到过，无菌环境对小孩子的发育而言并不好。人类体内就是有良性的菌群，不论是皮肤上，还是肠胃里。一味杀菌，反而可能坑害了孩子。</p><p>忘了在哪里看到的膳食指南中也提到，腌制食品在制作时，会发酵出良性菌。吃进肚子里，丰富了肠胃中的菌群，能为人体带来许多好处，例如更好地去吸收植物内的矿物质。</p><p>为此他认为：</p><blockquote><p>本当は、毎日入浴して体を洗う必要もないんです。せめて入浴しながら「肌を休める日」を、3 日に 1 度作るといいでしょう</p><p>其实，并没有必要每天都洗澡擦身。建议至少每 3 天设置一个「肌肤休息日」，在洗澡的同时让肌肤得到休息。</p></blockquote><p>这一点和上篇文章中所说的相似。为了让皮肤健康，不需要天天洗，主要是考虑到了现代人的卫生习惯。</p><p>同样的想法也能在德国的皮肤科专家那儿看到。</p><p>皮肤科医生 Yael Adler <a href="https://www.t-online.de/leben/alltagswissen/id_100327734/duschen-ohne-seife-oder-duschgel-expertin-klaert-auf.html">说</a>：</p><blockquote><p>Demnach sollten Menschen, die täglich duschen, hauptsächlich Wasser verwenden. Es hat einen neutralen pH-Wert, trocknet die Haut weniger aus und sauber werden Sie auch nur mit Wasser. Schließlich sind Staub, Schweiß, Hautschuppen und sogar Urin wasserlöslich.</p><p>因此，每天洗澡的人应该主要使用清水。水的 pH 值呈中性，对皮肤的干燥程度较低，而且仅用清水也能洗干净。毕竟，灰尘、汗水、皮屑甚至尿液都是水溶性的。</p></blockquote><blockquote><p>Schwitzige Stellen wie Achseln, Leisten, Pofalte und Füße sollten Sie regelmäßig mit Duschgel oder Seife waschen. Für den Rest genügt aber auch Wasser, so Hautexpertin Yael Adler.</p><p>腋下、腹股沟、臀缝和脚等容易出汗的部位应定期使用沐浴露或肥皂清洗。皮肤专家 Yael Adler 表示，对于身体的其他部位，只用水冲洗就足够了。</p></blockquote><p><a href="http://Utopia.de">Utopia.de</a> 引用了数位皮肤科专家的 <a href="https://utopia.de/ratgeber/duschen-ohne-seife-reicht-einfach-nur-wasser-aus_603367/">说法</a>：</p><blockquote><p>Dem Spiegel gegenüber empfiehlt Erhard Hackler von der Deutschen Haut- und Allergiehilfe sogar, bei häufigem Duschen auf Duschgel zu verzichten. Stattdessen könne man nach dem Duschen mit reinem Wasser einen parfümfreien Deostick verwenden.</p><p>德国皮肤与过敏援助组织的 Erhard Hackler 甚至向《镜报》建议，如果淋浴频繁，应避免使用沐浴露。相反，在用清水淋浴后，可以使用不含香料的止汗棒。</p></blockquote><blockquote><p>Denn bereits Wasser allein schädigt die Hautbarriere, warnt Bernadette Eberlein, Oberärztin an der Klinik und Poliklinik für Dermatologie und Allergologie am Biederstein der TU München. Duschgel und Seife verstärken ihr zufolge die Schädigung. Denn sie lösen Fette, die die Haut schützen, aus dieser heraus.</p><p>慕尼黑工业大学比德斯坦皮肤与过敏科副主任医师 Bernadette Eberlein 警告说，即使单单是水也会损害皮肤屏障。据她所说，沐浴露和肥皂会加剧这种损害，因为它们会溶解并洗去保护皮肤的油脂。</p></blockquote><blockquote><p>Ob mit oder ohne Seife: Tägliches Duschen ist für Menschen mit normaler Haut meist nicht nötig, wie die Dermatologin Stefanie Derendorf gegenüber Utopia in einem Interview erklärt. Ungesund ist es für diese Menschen aber auch nicht. Derendorf zufolge ist es in manchen Fällen sogar sinnvoll, sich täglich zu duschen – beispielsweise, wenn man geschwitzt hat oder Schmutz auf der Haut hat. Für Menschen mit trockener Haut ist es laut der Expertin dagegen schädlich, täglich zu duschen.</p><p>无论是否使用肥皂：皮肤科医生 Stefanie Derendorf 在接受 Utopia 采访时解释说，对于普通肤质的人来说，通常不需要每天洗澡。但对这些人来说，每天洗澡也并非不健康。Derendorf 表示，在某些情况下，每天洗澡甚至是有意义的 —— 例如出汗后或皮肤上有污垢时。然而，对于干性皮肤的人，专家认为每天洗澡是有害的。</p><p>Beim Duschen, so erklärt sie weiterhin, muss nie der gesamte Körper eingeseift werden. Regelmäßig, aber nicht täglich, sollten talgdrüsenreiche Zonen und Zonen, die viel Schmutz abbekommen, mit Duschgel oder Seife gereinigt werden. Dazu gehören die Hände, die Achseln und die Füße sowie Brust- und Rückenmitte. Am restlichen Körper reicht demnach Wasser zur Reinigung.</p><p>她进一步解释说，洗澡时永远不需要全身涂抹肥皂。应定期（但非每天）使用沐浴露或肥皂清洗皮脂腺丰富及容易沾染污垢的部位。这包括手部、腋下、足部以及胸部和背部中央。身体的其他部位只需用水清洗即可。</p></blockquote><p>我看不懂德语，所以没法用 <code>[...]</code> 遮住不需要的部分；你们只能文章上有啥读啥了。</p><p>综上所述，我们能得出：清水可以洗掉身体上绝大多数的脏东西，但是无法去掉油溶性的皮脂，而它们才是产生异味的大头。不过过分使用肥皂、沐浴乳，反而会损害皮肤健康。重点在于如何平衡、找出最适合自己的方案。</p><p>于是我的思维又跳跃了。我想到了过去又有人跟我科普说：洗发水越用头越容易痒，用清水洗过段时间就不痒了。之后就是他对消费主义和资本主义的批评 —— 打住！我们只说洗澡和洗头发！</p><p>我的洗头频率一向是隔一天洗一次。偶尔能隔两天，但是不能赌，否则第二天头就油油的、痒痒的了，我也不乐意大早上起来洗头发。不过我在完全没有认真调查时，就已经开始试验这件事了，可以在这个 <a href="https://gts.cytrogen.icu/@cytrogen/statuses/01KYJ8YTQTVR5NQTNDT5XWB1V5">串</a> 内查看我都在干啥、什么心理状况 —— 冲动便是如此，呵呵…… 我原来是冲动驱动行动的类型。</p><p>第一晚不用洗发水洗完，头发上明显有层油。手摸上去很不舒服，感觉像是摸了一手蜡？所以之后还是去搜了下，得知该方法叫作 <em> no-poo</em>，即 <em> no shampoo</em> 的意思 —— 会让人联想到其他不好的东西 —— 日本有个相同的概念，叫作「湯シャン」。根据宣传，它对头皮更加温和、能让头发更健康。</p><p>根据皮肤科医生 Knox Beasley 的 <a href="https://www.hims.com/blog/washing-hair-with-water">说法</a>，许多洗发水含有硫酸盐，虽然能让头发变干净，但久了也会变干燥、脆弱。</p><p>日本的 NATURAL AGA CLINIC 的 <a href="https://natural-aga-clinic.com/yushampoo-effect/">文章</a> 则说了更多的东西。</p><blockquote><p>シャンプーによる過度な脱脂がなくなることで、頭皮が「反応性の皮脂過剰分泌」を起こしにくくなる場合はあります。これは皮脂分泌が減るのではなく、頭皮環境が安定しやすくなるという意味です。</p><p>由于消除了洗发露带来的过度脱脂，头皮有时会变得不容易发生「反应性皮脂分泌过剩」。这意味着头皮环境更容易趋于稳定，而非皮脂分泌减少。</p></blockquote><p>这段话暗示了洗发水过度去油反而会导致皮脂过多分泌。</p><blockquote><p>乾燥しやすい頭皮の人がシャンプーの使用頻度を減らすと、皮脂膜が保たれやすくなります。頭皮の乾燥が原因のフケやかゆみが出ている場合、湯シャンによって改善が期待できます。</p><p>容易干燥的头皮如果减少洗发露的使用频率，皮脂膜就更容易维持。如果是因为头皮干燥而出现头屑或瘙痒，清水洗头有望带来改善。</p></blockquote><p>所以干燥头皮的人更适合清水洗头。</p><p>它也不是简单的「不使用洗发水」，而是有着详细的步骤：</p><ol><li>洗之前先梳头，预先去掉头发上的灰尘和污垢</li><li>用温水打湿头发</li><li>用指腹，而不是指尖，在头皮上画圈圈按摩，直到头皮不再有油腻感</li><li>洗完用毛巾轻轻吸干头发上的水分</li><li>先吹干发根，不要烘烤头皮，快干时切换冷风</li></ol><p>初次洗后，出现油腻感很正常，因为是适应期。这时候的头皮还处于过去因洗发水而过分分泌油脂的阶段。而水，之前已经说过了，是去不了油的，仅是把它们冲走。</p><p>事实也是我第三次 no-poo 洗头时，头发就没有那么油了。写这篇文章的时候则是第四次 no-poo 洗头后的第三天，仔细摸头发也能摸出一点点油，总之肯定是没有用过洗发水后的触感，但整体油腻感在随时间和次数而下降。</p><p>不过，这两篇文章都不建议 no-poo。</p><p>Beasley 说：</p><blockquote><p>Build-up can lead to potential scalp issues. Over time, washing with only water may lead to scalp build-up, especially if you don't remove natural oils, sweat, and environmental pollutants. This can result in itchiness or flakiness, and people with sensitive or dandruff-prone scalps might find that water-only washing exacerbates conditions like dandruff or psoriasis.</p><p>堆积物可能导致潜在的头皮问题。随着时间的推移，如果不能清除天然油脂、汗水和环境污染物，只用水洗头可能会导致头皮堆积。这可能会引起瘙痒或脱屑，头皮敏感或易患头皮屑的人可能会发现，只用水洗头会加重头皮屑或银屑病等状况。</p></blockquote><p>单用水是无法有效去油的，尤其是头发的构造会堆积油脂。清水仅能冲走部分油。</p><p>他给出的一些解决方案分别是：</p><ul><li>用苹果醋</li><li>清洁型护发素</li><li>特定用于 no-poo 的护发产品</li></ul><p>NATURAL AGA CLINIC 补充道：</p><blockquote><p>皮脂が過剰に残る環境では、マラセチア菌が増殖しやすくなります。マラセチア菌が増えると脂漏性皮膚炎の原因になり、フケやかゆみが出るリスクが高まります。</p><p>在皮脂过剩的环境下，马拉色菌容易滋生。马拉色菌增多会导致脂溢性皮炎，增加出现头屑和瘙痒的风险。</p></blockquote><p>同时反驳了「多用清水洗头皮会越来越不油」的说法：</p><blockquote><p>「湯シャンを続けると皮脂分泌が減る」という口コミがありますが、この点はエビデンスで慎重に検証する必要があります。皮脂の再分泌に関する研究では、洗髪後 24 時間で皮脂量がほぼ元に戻ることが確認されています。</p><p>虽然有「坚持清水洗头会减少皮脂分泌」的说法，但这一点需要通过证据进行谨慎验证。关于皮脂再分泌的研究确认，洗发后 24 小时内皮脂量几乎会恢复到原始水平。</p><p>つまり、湯シャンを続けても皮脂の分泌量自体は大きく変わりません。「湯シャンで頭皮がサラサラになった」と実感する人もいますが、皮脂分泌のメカニズムはホルモンバランスや遺伝的要因に大きく左右されます。洗い方を変えただけでは、根本的な改善にはつながりにくいのが現状です。</p><p>也就是说，即使坚持清水洗头，皮脂的分泌量本身并不会发生显著变化。虽然有人感觉「清水洗头让头皮变得清爽」，但皮脂分泌机制很大程度上受激素平衡和遗传因素影响。目前看来，仅靠改变洗发方式很难实现根本性的改善。</p></blockquote><p>不痒很大可能并不是因为油变少，而是刺激头皮环境的因素没了。这样说，最需要做的其实是更换洗发水。</p><p>那么如何洗头呢？PubMed Central 上有篇针对亚洲人的 <a href="https://pmc.ncbi.nlm.nih.gov/articles/PMC8138261/">研究</a>：</p><blockquote><p>In the epidemiological study, it was observed that overall satisfaction with hair and scalp condition was achieved when washing 5–6 times per week. This was consistent for both objective and subjective end points. Controlled treatment likewise showed that a daily wash regimen was superior to once per week cleansing for all end points. No objective detrimental effects to hair at this level of cleansing were observed.</p><p>在流行病学研究中观察到，每周洗头 5-6 次时，头发和头皮状况的总体满意度最高。这在客观和主观终点指标上均表现一致。对照治疗同样显示，在所有终点指标上，每日清洗方案均优于每周清洗一次。在此清洗频率下，未观察到对头发有任何客观的负面影响。</p></blockquote><blockquote><p>The subjects in this study self-assessed their condition as dramatically better at the higher wash frequency: reduced oiliness, more healthy, less frizz, less dull, less dry, and reduced breakage.</p><p>该研究的受试者自我评估认为，在较高的洗发频率下，他们的头发状况显著改善：油腻感减少，更健康，毛躁减少，暗沉减少，干燥减少，且断裂减少。</p></blockquote><blockquote><p>There is little doubt that increased wash frequency is beneficial to scalp condition. However, the data also strongly support that for the Asian populations studied, hair condition is not negatively affected by increased wash frequency and that the self-perception is toward marked improvement.</p><p>毫无疑问，增加洗发频率对改善头皮状况大有裨益。此外，数据还强有力地证明，对于所研究的亚洲人群而言，增加洗发频率并不会对头发状况产生负面影响，且受试者的自我感知趋向于显著改善。</p></blockquote><p>这就特别有意思了，因为洗头跟洗澡的逻辑是相反的。过去以为的「勤洗头有害头皮健康」是假的，反而是近乎每天洗头才更有益、更让人满意。</p><p>不过该实验结论的大前提是：使用了温和的去屑洗发水（还是宝洁的），实验者也都是健康直发的亚洲人。</p><p>对于强烈硫酸盐洗发水，天天洗则非常不推荐。先前介绍 no-poo 时已经说过了，它会过度去油，从而损害头皮，使其更干痒。</p><p>我们最该做的是结合个体的情况、洗发水的成分来平衡洗发频率。</p><p>对于一般情况的人而言，使用中性的非强力去油洗发水更好，避免使用带强硫酸盐的；如果是干性头皮的，用清水洗、少洗会更适合你；如果是油性头皮的，建议勤洗头；平日出汗多、用发胶的得勤洗；少汗的可以降频。</p><hr><p>最后我想说件趣事儿。第一晚 no-poo 后，次日我觉得头发油油的，实在不舒服，于是起床搜了正确流程、洗了一遍，反而让我觉醒了新状态 —— 晨间洗澡！</p><p>过去我便有所听闻，外国人喜欢早上洗澡。原因是为了提神，以及早上出门形象更体面。东亚国家则倾向于睡前洗澡，这样就能把外面的脏东西挡在舒适的床外。不过「外国人喜欢早上洗澡」也算是刻板印象吧。</p><p>我是一回家就洗澡。原本的生活习惯是睡前洗，不过室友有洁癖，她无法容忍外面的脏东西碰到家里的任何物品，例如家具上，所以要求我一回家就得脱衣服、洗澡。久而久之，我也习惯了。</p><p>那次晨间洗澡后，我意外发现，自己明明刚起床，脑子却无比清醒，还感觉身体干干净净的，很舒服。</p><p>这也让我感觉很纳闷儿吧。睡眠期间明明也会分泌汗、皮屑细胞，为啥不早上起来洗掉呢？这样一整天也更干净。可是要放弃晚上洗澡吗？我也不想把外面的脏东西带到床上来啊。然后我想到，为啥我要纠结呢？我全都要不行吗？</p><p>为此我要先明白我的需求是什么。为什么我要早上洗澡？因为我要脑袋变清醒、洗掉睡觉期间分泌的汗还有皮屑。为什么我要晚上洗澡？因为我要清理一整天的脏东西。</p><p>先前我们已经提到，洗澡不一定需要使用肥皂、沐浴乳，仅用清水洗就可以把大多数的脏东西洗掉。那么已经洗过的身体，在经过一夜睡眠后，身上真的会那么脏吗？那我早上是不是可以不用肥皂洗？用更少的时间洗？甚至只用冲一下即可？于是我的做法是，起床冲冷水澡一分钟。不过并非全程冷水澡，而是先放温水适应，然后慢慢调成冷水。</p><p>既然这样，晚上的洗澡就可以是一次大清洁。我正常怎么洗，这个时候就怎么洗。如果需要洗头，也是这个时候才洗。</p><p>以上就是我这周在折腾的东西。下篇见！——</p><p>—— 我会看着你们清洁自己的（眼睛 emoji）。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;人很闲的时候总要找点新东西倒腾，我这周就闲得没边：项目谈燶了、放着 aigent 修死 bug。我一闲我就读 RSS、我就写东西玩。所以你想要知道我闲不闲，你就看我更新博客更新得频不频 —— 你看，我最近一周更新了仨，这是第四篇。&lt;/p&gt;</summary>
    
    
    
    <category term="日常生活" scheme="https://blog.cytrogen.icu/categories/%E6%97%A5%E5%B8%B8%E7%94%9F%E6%B4%BB/"/>
    
    
  </entry>
  
  <entry>
    <title>RE：断层里的心理学</title>
    <link href="https://blog.cytrogen.icu/posts/221a.html"/>
    <id>https://blog.cytrogen.icu/posts/221a.html</id>
    <published>2026-07-30T04:00:00.000Z</published>
    <updated>2026-07-30T17:13:07.724Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我在尝试将过长的回应从月刊中拉出来、直接写成独立文章的做法。</p><p>和月刊内的回应不同，独立文章往往失去了「介绍该链接」的目的在，是单纯的「回应」。我不希望有任何人误认为我是在攻击谁，我只是就事论事。因此所有的作者的名字都会被我打成「作者」，不论我们是否有线上或者线下的关系。人身攻击是绝对不提倡的。</p><p>不过纯复述的内容，无论字数多长，都会被放在月刊内。</p><span id="more"></span><p>原文链接：<a href="https://blog.solazy.me/20260726/">https://blog.solazy.me/20260726/</a></p><hr><h2 id="复述原文"><a class="markdownIt-Anchor" href="#复述原文"></a> 复述原文</h2><p>复述原文是非常重要的。甲去回应乙的观点，实际上并没有在回应「乙的观点」，而是在回应「甲以为的乙的观点」。这两者可以重合、是同个内容，不过这个概念要清楚。</p><p>复述能够用自己的理解，将对方的观点说一遍，因为这才是你要回应的东西。它可以极力避免产生误解。毕竟我复述错了你可以直接纠正我。</p><p>总之继续。</p><p>作者认为，心理学在结构上存在着严重的两头断层现象：研究性心理学毫无疑问是严谨的科学；然而在脱离了实验室与控制变量后，它缺乏在日常现实中操作的可能性。</p><p>在一般人能够接触到的应用层中，心理学会退化成一门极其依赖从业者个人状态、拼运气的谈话服务。由于下限不可量化，所以无资质的从业者和仅靠共情力聊天的人在实操中没有区别。</p><p>在这种断层下，试图通过阅读书籍和理论来自医的人，会掉入陷阱中：误以为可以拯救自己，但仅是学习了各类抽象还不实用的概念、为自己找借口、逃避现实问题。</p><p>即便是日常人际交往中展现出的观察力与边界感，也仅仅属于常识范畴，与科学心理学无关。</p><p>所以，大众应当对应用层中的理论以及咨询服务保持冷静距离。面对生活困局不应寄希望于看书或者付费聊天，而应回归最基础的逻辑，即通过剥离客观事实与主观演绎、明确个人边界并承担相应责任来解决问题。</p><h2 id="我的回应"><a class="markdownIt-Anchor" href="#我的回应"></a> 我的回应</h2><p>我不认可该文章所表达的多数观点。</p><p>首先是作者在探讨应用层时，直接将其和低门槛的话疗化为了一谈。</p><p>心理学的应用层存在着大量的科学干预手段，例如临床心理学家，再者还有精神科医生 —— 虽不属于心理学范畴，但依然需要接受临床心理学训练。现在的许多心理问题需要同时用到药物干预和心理治疗。心理咨询师跟话疗师是没有资质的。这是概念混淆，为此推导出的「心理学不是靠谱的科学」不合理。</p><p>我实际上也赞同「话疗无法解决问题」这个观点的，但用它去概括心理学的应用层都没有用，我不认可。存在逻辑错误。</p><p>其次是他断言「人际互动里的观察力和边界感跟科学心理学没有关系，仅是常识」，这是 <a href="https://zh.wikipedia.org/zh-hans/%E7%9F%A5%E8%AD%98%E7%9A%84%E8%A9%9B%E5%92%92">知识的诅咒</a>：你不能因为自己已经知道了，所以默认他人也知道。</p><p>「常识」是非常主观的概念。许多今天理所当然的常识，例如婴儿有痛觉，是过去数百年来研究成果普及后才沉淀为常识的产物 —— 是的，以前美国给婴儿做手术不打麻药，导致婴儿全特么嗝屁了 —— 放在心理学的世界中，边界感、情绪表达的重要性、防御机制等，也是过去没有、现在变成常识的东西。</p><p>文章中并没有给出任何标准来定义为什么这些不是心理学，实在是太主观了。觉察他人的情绪以改善互动，属于社会心理学的应用，怎么会没有关系呢？</p><p>再者是将自医者的未见成效直接归罪为是在找借口逃避，过分冷酷、只关注于结果了。心理问题非常复杂，花费几十年甚至一生才能解决的心理问题比比皆是。它本就是非线性、长期，甚至可能反复出现且倒退的。归因为逃避、无能会否定学习者的努力或 <u>理智化</u> —— 一种心理防御机制。</p><p>有一点我得说明的是，标准化产出是不能用来强行套在心理学上的，因为心理学面对的是复杂的主体，属于软科学 —— 社会学和经济学也在其中 —— 个体的主体性不应被消除、简化成待解决的问题，也就是硬科学里会用到的方式。</p><p>因此我也认可「看书学理论无法解决问题」，不过我的理由在于二者之间没有直接性的联系，而是无数个非直接性的联系：改变需要心理上的安全、能够容忍情绪、反复实践行为，而这些都是学习理论之后的事情 —— 尤其对于带有创伤问题的人来说，知行合一的难度非常可怕，不能简单说是对方能力上的失败。</p><p>结尾文章说：</p><blockquote><p>在面对具体的困局时，与其指望某种不怎么靠谱的底端心理学来拯救自己，不如先回退到最基础的逻辑上：把客观事实和主观演绎剥离开，守住边界，把该承担的责任承担起来。这往往比任何打着科学旗号却无法实操的理论，管用得多。</p></blockquote><p>对于成长环境缺失安全感、认知模式存在偏差的人而言，如果不借助心理学理论的引导，他们无法天生就知道什么是「边界」、什么是「客观事实」、什么是「主观演绎」、什么是「该承担的责任」。</p><p>我写过一篇相关的 <a href="/posts/9412.html">文章</a>：一个因为从小就没有被教导如何和同龄人打交道、被学校的环境误导以为优秀的人必然是孤独的人，他的「常识」是母亲说他的性格孤僻、「我天生如此、不善交流」吗？如果只依靠这些「常识」，只会让他困在「孤独 — 高冷 — 更孤独」的恶性循环里。因此我说，「常识」是非常主观的，会夹杂着偏见、粗暴的标签以及说教。</p><p>同样的，不借助理论的话，他也难以剥离「客观事实」和「主观演绎」。</p><p>为了防止有人偏要误解、认为我说的是「没读心理学书籍、学理论就不行」，我得补充一下：理论是解释「世界」的「语言」—— 可以看 <a href="/posts/893f.html#%E4%B8%8B%E4%B8%80%E4%BB%A3%E4%BA%BA%E6%9C%89%E5%8F%AF%E8%83%BD%E6%98%AF%E4%BA%BA%E7%B1%BB%E6%BC%94%E5%8C%96%E7%9A%84%E5%8F%88%E4%B8%80%E6%AC%A1%E5%88%86%E5%8F%89%EF%BC%9A%E8%AE%BA-ai-%E5%AF%B9%E6%95%99%E8%82%B2%E5%92%8C%E4%BA%BA%E6%80%A7%E7%9A%84%E5%A8%81%E8%83%81:~:text=%E6%96%87%E7%AB%A0%E4%BD%9C%E8%80%85,%E6%84%8F%E4%B9%89">这一段</a> —— 理论所提到的事情实际上依然存在了（「世界」），但我们人与人之间沟通依然需要用到「语言」。除了「理论」这一种形式，我们也可以通过积累经验自行悟出「世界」，亦或者听有经验之人自己总结出来的「语言」。</p><p>通过理论，先在认知上理解什么是「个体独立性」、什么是「边界」…… 他才能进一步推断自己边界是什么、别人的评价是别人的课题、自己需要承担的责任并非「承认自己是个怪咖」。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我在尝试将过长的回应从月刊中拉出来、直接写成独立文章的做法。&lt;/p&gt;
&lt;p&gt;和月刊内的回应不同，独立文章往往失去了「介绍该链接」的目的在，是单纯的「回应」。我不希望有任何人误认为我是在攻击谁，我只是就事论事。因此所有的作者的名字都会被我打成「作者」，不论我们是否有线上或者线下的关系。人身攻击是绝对不提倡的。&lt;/p&gt;
&lt;p&gt;不过纯复述的内容，无论字数多长，都会被放在月刊内。&lt;/p&gt;</summary>
    
    
    
    <category term="文章回应" scheme="https://blog.cytrogen.icu/categories/%E6%96%87%E7%AB%A0%E5%9B%9E%E5%BA%94/"/>
    
    
    <category term="心理学" scheme="https://blog.cytrogen.icu/tags/%E5%BF%83%E7%90%86%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>休息日出去玩吧</title>
    <link href="https://blog.cytrogen.icu/posts/c783.html"/>
    <id>https://blog.cytrogen.icu/posts/c783.html</id>
    <published>2026-07-28T04:00:00.000Z</published>
    <updated>2026-07-28T06:21:38.639Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近些天的天气闷闷热热的，想必是为了给接下来的雷阵雨做准备的吧。</p><span id="more"></span><p>我的床位于窗边，刻意让窗帘留了条缝儿。天一亮便有一点点光线照射进来。可惜租的公寓朝向不太好，太阳总是得过一段时间才能照射进来。</p><p>我不知道我应该做什么好。我难以理解为什么会有人下午两三点才醒过来，却要早早在上午十点定闹钟，然后容忍它在接下来的数小时内时不时叫一次。室友这个始作俑者不嫌烦，我还嫌烦呢。</p><p>从早上到室友醒来的这段时间，是非常难得的仅属于我的时间。可是我每次这个时候都发难：该继续推进项目呢？还是出门去哪里逛逛，直到室友醒来打电话找我？还是无所事事地刷手机，一直等到她醒来、同意拉开窗帘、任由太阳光在我的身体上爬来爬去？</p><p>或许我就不该等她，早上起床就出门去。不过难得有时间，很多事情还没做完呢，比如读一读订阅的博客文章。项目管理对我的时间把控抓得颇紧，不让我做任何自己的事情，因为对方认为全部时间都拿去做工作相关的事情的话，效率就会提升。这也让我不得不去追赶对方的节奏：工作、达成指标、修 bug、写 bug…… 「做不完这些你怎么配出去玩的！」他总会给我种感受，那就是追求除了工作外的娱乐方式，是罪恶，是冒犯。</p><p>但周日让我懒散、不愿动弹，也没了做项目的心情。我倒是对出门很有兴趣。室友总算在近三点的时候醒了过来，这家伙儿果然是什么夜行生物吧。我跟她讲了下想要出门逛逛的想法，她也同样有不想干活的心情。既然都是知音，那就赶紧出门吧。</p><p>纽约市是个无聊的城市。这里的景观我都看腻了。对于室友而言，探索不同的社区，尤其是郊区很有意思，不过父母家就在郊区，看来看去都是同个样子。海啊，沙滩啊；山啊，草地啊；都是一样的。我对大自然没有太大的兴趣，所以也很难从中寻求到乐趣。</p><p>能独处、自找乐趣的人既是神，也是魔 —— 我定然不是这样的人吧。不知是我大脑在哪个方面真有障碍，还是性格如此，我只是喜欢规整的纪律。强迫型思想的感觉？<a href="/posts/cf35.html">四个字的城市</a>。室友笑说「你是小自闭吗？」</p><p>我本来是想要去博物馆看看的，也就是纽约市颇有名的美国自然历史博物馆（American Museum of Natural History）。小时候我经常作为「导游」带着亲戚去逛。真是奇怪，明明是个孩子，因为英语说得比父母好些，就被抓来做所谓「导游」了。说不好还要被骂。学校旅行也经常往这个博物馆来。那时的我不会在乎博物馆里的内容，只是一味儿地想玩手机。前几个月室友因为作业需要，所以我们一起去看了。大了，对小时的许多事情都不再抱有兴趣，却能捡起小时不屑于正眼瞧的东西 —— 这家博物馆还挺有意思的。不再用朋友圈，也没有需要向他们证明我很忙的表面朋友后，我不会用手机一个个展览都拍过去，还发到朋友圈充当无数个背景板的其中一员，反而仅用眼睛这个不带存储的破烂相机看过去。有时候就是这样吧，不需要记录什么，也不用担心不小心调成「自动」的闪光灯。</p><p>室友却不乐意了。她不想要去博物馆、没有那个心情。她想要去荒郊野岭、无人的海边。可是那种地方搭乘公共交通根本到不了，至少也得走上个十几分钟。她觉得也可以和我去共享办公室里坐着，因为和我关系够近了，不需要特意做什么她也会感到开心。</p><p>不过共享办公室，本来就是我平日在待着的地方…… 我不想要周日也那样，不然会显得我很可怜。</p><p>我说，换衣服出门就好了，随便去哪里看看吧。她说，哎正好，我上次路过一家酒吧，非常漂亮，想要让你看看。于是我们准备更衣。</p><p>她托父母从国内寄了点东西出来，这里包括了些送给我的礼物。因为事先跟我聊过，我对这些小礼物也表达出了喜欢之情，因此我不 <a href="/posts/54b4.html">讨厌</a> 它们。</p><p>实际上，有些礼物完全超出了我对它们的期待，比如她送我的表。该表的表带是我目前戴过的所有表里，最舒服的一个。它非常贴合皮肤，还不硬。</p><p><img src="/posts/c783/watch.webp" alt="" loading="lazy"></p><p>因为平日的穿着一本正经的，所以需要点装饰缓和下，毕竟我也不想日常闲逛也要摆出无比正经的样子。这种童趣风格的装饰，我有很多，比如我的这条领带：</p><p><img src="/posts/c783/tie.webp" alt="" loading="lazy"></p><p>室友送我的礼物中，还有风格可爱的小戒指、耳夹。</p><p><img src="/posts/c783/ring.webp" alt="" loading="lazy"></p><p>窗外的太阳一看就颇晒。我一直都没有涂防晒霜的习惯，结果这个夏天变黑了很多。我自认皮肤还是挺白的，现在变黑了让人有些不爽 —— 到底是为什么呢？可能是「皮肤白」是我的特征之一吧。没有了这个特征，就不会再有人夸我了。但这也是表象的一种。再不济，也不该让皮肤上出现黑斑吧。于是我掏来室友的防晒霜，在身上抹了抹。</p><p>我们先是走向她提到的那所酒吧。该酒吧的内部，似是爱丽丝仙境主题的，里面有许多装饰用的花，非常漂亮。Happy Hour 的鸡尾酒，没记错应该是 10-20 美元左右吧。生蚝则算下来一只 2 美元 —— 酒我虽然会调点，不过喝是喝不来一点，会头痛致死的。生蚝真是好吃，不过我还是不太喜欢独属于贝类的味道，因此不配鸡尾酒酱吃不下。质量也是一点，差的生蚝吃了我会犯恶心，生海胆也一样。</p><p><img src="/posts/c783/oscar-wilde.webp" alt="" loading="lazy"></p><p>但我们没有在这里点单吃饭，毕竟这种酒吧要吃正餐的话两个人肯定要百来块钱啦。我们都没有这个心情，我也不喜欢西餐。为了不拍到别人，所以找了个拍不到任何人的角度，结果拍了个寂寞的样子。</p><p>这附近还有个花街。顾名思义，全是花店。它们不仅店内都是各种盆栽，外面也摆满了植物。走在街道上，能清晰闻到植物的味道，真要说的话，就是草、泥土和水的混合物，偶尔路过花的盆栽，那就带点花香。因为对大自然没有太多兴趣，我对植物也没有。它们是赏心悦目的装饰，更像是背景板。我又想了想，觉得这么说实在无礼，准确来说便是没有到对它们产生兴趣的时机吧。未来说不定就会到了。</p><p>除了酒吧，Broadway 附近也有许多咖啡店。它们两个就像是宝可梦里的皮卡丘，还有当时小智说的野狗一样多。我也在咖啡店打过工，不过是机器做的，我只用扫描条形码就好了。因为和当地更常见更传统的咖啡店不同，所以还被顾客埋怨过：「怎么会没有 cream 啊！真的是！」—— 你跟我说我也没有办法啊，找别人去发泄情绪吧！</p><p>有趣的是，我还看到一家酒吧跟咖啡店融合在一起的店。或许是周日的原因，吧台处只有一个调酒师。难道他还要兼顾做咖啡？瞄了眼价格，5 块钱左右，有点贵呢。</p><p>一说到价格，就想起前不久看到有人说，中国那边的主流社交平台在吵「贫困生能不能买 9.99 元的瑞幸咖啡？」我和室友讲了这件事，她惊讶道：「那不是特别便宜了吗？」</p><p>当时看到转告的人说，中国很多人还是停留在以前的旧思想，觉得咖啡是崇洋媚外、小资的东西。</p><p>说到「小资」，我和一个认识许久的朋友有过这样的对话呢。当时我提出想要去 MUJI，因为手账的尺寸买错了，得再去买个 A5 的日式标准活页本。他立即表示，MUJI 是无比小资的品牌。小资不小资的，根本没有关系，反正那个活页本也才 3 美元而已。事实证明，他也不知道自己在说什么，因为进了 MUJI 后，他才知道里面的东西很便宜，意味着他从来都没进到 MUJI 里来，只是听到中文主流的社交平台有人这么说了，他就搬运过来给我而已。不过走之前，他还是对门口的香薰发表了意见：「用香薰是很小资的事情。」</p><p>很不喜欢这家伙儿的原因是，他很多时候都不知道自己在说什么，就果断下了结论。经历的事情太少，每天好似只是在重复做同样的事情，为了分泌更多的多巴胺而无时无刻都在听多倍速的 AI 读知乎小说…… 视角的狭窄，让我心中有股怒火。也不是讨厌他，只是觉得恨铁不成钢。帮助他，也尝试过数次，毕竟认识了很久，但他的幼稚，有时会尝试把我拉入他的情绪之中。</p><p>我曾经和室友讲过这种事情，她说为什么要花时间去帮一个不值得你帮的人呢？—— 我也不知道。听着她骂我有救世主情结，嘴上虽然说不出什么话来，但心里想着你这家伙儿真是学到什么就立即拿来应用啊，明明自己也做过一模一样，甚至更恶劣的事情吧。意识到这一点后，觉得自己真差劲儿。</p><p>说回咖啡吧。我不喝咖啡；室友虽然喝，但是她对味道一点都不挑；现实生活中认识的朋友有一个喝，不过他大学喝太多、已经对咖啡因免疫了，现在什么时候喝咖啡都不会觉得身体有什么影响，真是可怕。还有谁对咖啡很了解呢…… 第一时间想到的是 <a href="https://www.geedea.pro/tags/%E5%92%96%E5%95%A1/">Eltrac</a>。他会自己手冲咖啡，记忆里他也说过手冲咖啡要比在外面买便宜，尽管手冲咖啡听上去是个高端且小众的行为，或者说喜好？</p><p>我的生活和过去不一样了，虽然还是很穷，但因为室友非常热爱生活，所以也被她带动着，去考虑自己周遭的事情。我这样生活着，会不会也让部分人认为，我不配如此生活呢？在 QQ 相册里添加的风景照片、第一次坐直升机、溜冰来溜冰去，经常泡在街机厅…… 这些生活中精彩的一部分，我是配享受的吗？会有人觉得我不配吗？会有人因此讨厌我吗？又或者说，我的这种想法都是如此自大？</p><p>「别人买什么，跟他们有什么关系嘛。」我们过马路时，室友这样说道 —— 嚯，原来如此，我被绕进去了。</p><p>对面，我们看到了瑞幸咖啡；说曹操、曹操到。室友问我要不要喝这家，还是去蜜雪冰城。我回我根本不会买它们喝啦。我们便进去看了眼。</p><p><img src="/posts/c783/luckin-coffee.webp" alt="" loading="lazy"></p><p>这家门店真是漂亮，装修风格挺有品的。不过之后听 Fediverse 上的朋友说，墙上的照片是样板，国内的装修也是这个风格。</p><p>我还是不愿意拍到别人的脸，因为我自己就不喜欢被别人拍，所以也默认他人不喜欢了。手机往上抬了抬，拍不到下面的沙发。周日的员工往往都只会放一个人，因为没啥生意，再加上是夏天，更没有人愿意出门了。游客除外吧。</p><p>另一面墙上则有着奇怪的设计：两个竖着的垫子？还有两个小支架。室友解答说是靠垫。人可以靠在垫子上，再把饮料放在支架上。不过这样的设计很奇怪…… 总感觉。要面朝向坐在沙发上的人么？然后只有两个垫子和两个支架？为什么？做成一排支架、当桌子用不会更好么？</p><p>室友最终买了个抹茶的什么东西，上面还洒了点抹茶粉。我完全没法理解抹茶的美好，身边的人好像都挺喜欢的，像我妹妹也喜欢它的样子。</p><p>中城的 Broadway，总能看到高端、昂贵的东西。就比如我们进去逛的 ITOYA Topdrawer。这是家来自日本的零售店，标榜高端，里面的东西也确实让我觉得「高端」。最让我印象深刻的是奇形怪状的这支钢笔：</p><p><img src="/posts/c783/kolo-tino.webp" alt="" loading="lazy"></p><p>我对钢笔是有些收藏心在的：我有四五把 Pilot 的 88G，有着动物的花纹；Picasso 的钢笔我也有，非常漂亮，就是写起字来不敢恭维；很有现代感的 LAMY Safari，写起来挺不错；国产的钢笔我也有一支金豪的 911，便宜、细细的。近期，我还为自己的收藏新添了一支 Pilot 的笑脸，定位应该是给小朋友们的，有着会纠正握笔方法的设计，非常可爱。</p><p>因此这支 KOLO 的 Tino 钢笔，让我再度涌现出买下它做收藏的欲望…… 不过不可能随便出个门就花掉两三百块钱去买钢笔啦（实体店内因款式不同，价格也不同）。</p><p>说到钢笔收藏，我家里还摆放着小时候去钢笔零售店内拿的杂志。里面有支钢笔的设计非常有意思，合上盖子竟是个武士模样。我找了下，原来是 2018 年的限定款：看 <a href="https://bertramsinkwell.com/products/the-samurai-pen-limited-edition-fountain-pen-2018">这里</a>。</p><p>令人意外的是，KOLO 这个牌子来源于 Austria，也就是奥地利。我本来看这家零售店里摆着许多日本的东西，还以为是日本或者德国的牌子呢。</p><p>因为非常小巧，所以 Tino 很适合放在口袋里。以前我就有把笔塞进口袋的习惯，不过当时用的是便宜中性笔，就算不小心折断了也不心疼，还很轻。现在改用钢笔后，就不能这么做了，尤其是摇晃会导致笔墨洒来洒去、全洒到笔盖内，得不偿失。</p><p>Topdrawer 内还有一些我觉得很有趣的产品。比如绵笔记本，也就是用棉花做的纸。该笔记本的样貌十分狂野。我搜了下，得知这种纸配墨水笔写起来非常舒服，也很耐放。不过我没有太多需要使用绵纸的场合。</p><p>我们转了一圈，最终打算买几个便宜的餐具旅行装。我买了个筷子，可以解决我外出吃饭没有筷子用的问题 —— 不过实际应用场景应该很少吧……</p><p><img src="/posts/c783/takenaka.webp" alt="" loading="lazy"></p><p>结账时，我注意到一旁摆放着的明信片。我过去有着交笔友的想法，但苦于不想要暴露家里地址，所以迟迟没有执行。P.O. Box 很贵啊。最小尺寸的一年也是 220 美元。我无法接受去订阅个每月超过 10-20 美元的服务，除非我特别需要它。至于虚拟地址，这是个让虚拟地址公司帮用户代收、每段时间会扫描信件、发图片给我的服务。怎么可能把信件交给他们呢！</p><p>部分大学似乎是有代收服务，我也去搜了搜，发现我校没有这种东西…… 唯一的办法就是自己租个办公室，用共享办公室公司的信箱了。但这也是未来的事情，谁也说不准。</p><p>我也看到过类似于 Slowly 这样的虚拟笔友平台，直接在设备上写好，然后平台模拟寄信的流程。我不太喜欢这样，所以没有做。</p><p>我从 <a href="https://v1sta.xyz/">远景</a> 那儿听说了 PostCrossing 这个平台，也就是把「笔友」换成了「明信片友」，大家互相寄明信片。我没有真的摸过明信片，总觉得是离我有些遥远的存在。不过它们现在近在咫尺了，我一瞅，卖的都是带有非常漂亮的艺术画的卡片，画的也是自然界里的动物们。我不喜欢大自然，虽然这么说过，但我很喜欢动物们。价格则是 8 美元一张。我要尝试一下吗？要尝试给陌生人们寄明信片么？明天再想吧。</p><p>拐弯是一家弥漫着香气的冰淇淋店。我们进去一看，原来是现做的蛋筒，怪不得这么香。他们也卖巧克力，成堆的巧克力分成不同的口味和形状，放在一个个容器内。顾客要拿个袋子，自己挑选喜欢的，然后按磅买单。除此之外，还有漂亮的礼盒可以选择。我们看了眼价格，感觉作为礼物的话还可以，尤其是礼盒的形式非常精致漂亮。</p><p>室友恍然大悟：「以后给小女生送礼，不用送花了，直接送这个不好么！」我说你的「小女生」朋友，不也就一个人嘛。这样说来，没有多少朋友的我，也买不了漂亮的礼盒、送出去。一瞬间失落了起来，不知为何。</p><p>她觉得可以送给男性朋友，她的很多朋友都是男性。「不过要送给老爷们儿嘛……」她想了想，「哎！你还真别说，他们心思很细腻，送给他们也会高兴的吧，尤其是好吃的巧克力。」</p><p>「那个谁确实心思很细腻，还有艺术细胞，收到了会很高兴吧。」</p><p>「不过那个谁总感觉会死要面子，先说几句，然后会感谢，毕竟他给我感觉是那种人啊。」</p><p>「那个谁应该不会喜欢『礼盒』这个包装，但他很喜欢吃甜食呢。」</p><p>「这样说就不想要给他送了…… 因为他只是喜欢甜食、不喜欢精致的设计吧。我想要送出去的是设计啊！」</p><p>「你收到了这种礼物会高兴吗？」室友问我。</p><p>这还真是个好问题…… 我首先是不喜欢巧克力，其次是不喜欢对我无用的礼物。我说，我应该会直接送给你吃吧。她惊讶道，你不会因为对方的一番好心而高兴吗！我觉得那才和我无关吧。</p><p>走着走着我们走到了 Koreatown。街口有家蜜雪冰城，但今天没有放「你爱我呀我爱你」的音乐。和往常一样，还是排满了人。</p><p>有家韩国菜店外面摆放了菜单吸客，但不知道为什么白米饭是空的？</p><p><img src="/posts/c783/rice-ha-doko.webp" alt="" loading="lazy"></p><p>我提议去新开的 GATCHA 分店看看吧。这是家连锁的娱乐店，主打抓娃娃机和扭蛋机。而我根本不会去玩这种破机器，我会去 GATCHA 纯粹是因为它里面有《舞萌 DX》。</p><p>看，是 <a href="/posts/3a5e.html">送快递</a> 的考拉！：</p><p><img src="/posts/c783/koala-express.webp" alt="" loading="lazy"></p><p>Koreatown 的新店是最大的一家，有五层楼。地下到四楼依次是：传统街机；抓娃娃和扭蛋机和盲盒区，有个小二楼是音游区；茶饮咖啡厅、大头贴、移动唱 K 厅和小露台；PC cafe，也就是网咖区；VIP 包间房。</p><p>电梯里有着泡面的味道…… 我们搭乘电梯到了茶饮区，发现原来是因为他们卖「拉面」吃 —— 此「拉面」非彼「拉面」，其实就是泡面。再准确说的话，是韩国的拉面。中日韩三国的「拉面」指的都是完全不同的东西 —— 税前 11 美元吧，奶茶都是 7-8 美元，非常不值。尽管我没有喝，但我这个在奶茶店打过工的能嗅出来，这种临时创办的暴利子品牌，怎么可能用好的料给客人。国内大牌子用好料还只卖 6 美元左右呢。</p><p>唱 K 厅一看就是国内的牌子运过来，上面还写着不少中文呢。行不行啊，你这店不是开给外国人还有韩裔的嘛！我不记得这个唱 K 厅的名字了，总之上面有个蓝色的小鱼人，然后是六人座。</p><p>逛到这里，还闻到了泡面的味道，已经饿了。我们走到外面去，商讨去哪里吃饭比较好。找来找去，我们看到一家很大的美食广场，叫 Bread &amp; Butter。虽然很大，但里面很空，不仅顾客少，做饭的地方都看不到人。和我常看到的美食广场不同 —— 我后来才知道它其实不是美食广场，只是大得像美食广场而已。实际上它是 24 / 7 营业的韩式自助兼市场型食堂。美食广场确实是我认知中的「多个独立商户共享用餐区」的模式，哎呀吓死我了。</p><p>我搜索后得知，这是韩裔移民自己在美国摸索出来的模式。因为是一个老板开的，所以没有竞争关系，会直接安排师傅们又收银又站岗又做饭。我们在乌冬面的站台找不到人，还是专程去问了收银台站岗的师傅，他才叫了另一个师傅过来做面。</p><p>说到这个做面的师傅，做事情总给人股不耐烦的感觉。而且还耳背，听不到室友的要求。不过这个做面的形式很新鲜：师傅会先问要什么蛋白质，然后拿小铁锅过来问我们要什么蔬菜，我们就对着工作台上的蔬菜指来指去。最后他会问要不要辣、在这里吃还是带走，然后就开始煮面了。有趣的是，小铁锅似乎没有锅盖，所以他用的是另一个小铁锅、叠在上面充当锅盖。</p><p>我也看了眼其他菜单，还有「拉面」（其实是 Jin 袋装泡面）、炒饭、炒面等等食物。隔壁站台不知为啥，还有比萨跟意大利面。</p><p>师傅做完，把两个乌冬面带去收银台。室友的牛肉乌冬面 10 美元，我的虾仁要 12 美元，加上税就是 23 美元多了。</p><p>我们在 Bread &amp; Butter 仅逛了一小会儿，看到门口的咖啡区（所以说真的是像野狗一样多啦，和小资有半毛钱关系）里有个女人，在自己的杯子里疯狂倒糖。那直直的白色柱形体，会让我怀疑她是不是来偷糖的。</p><p>这附近也有家共享办公室，我们便去那边吃。本来对乌冬面很期待的，但…… 它煮出来是一碗面糊糊……</p><p><img src="/posts/c783/not-udon.webp" alt="" loading="lazy"></p><p>这张图片是我努力吃了三分之二后的样貌。量很多，满满一碗。但 —— 怎么会有如此软烂的乌冬面啊！也不好吃，辣粉没有辣的感觉，反而觉得烫嘴。我受不了，跑去自助饮料机买百事可乐，结果那个机子我不会用，被提前刷走 10 美元，我还只拿了一罐。衰死我算了。</p><p>心情低落的我们也没有计划好接下来要做什么。我说我们要不回家放东西，然后再来 GATCHA 玩好了 —— 其实就是想要玩《舞萌 DX》。室友不习惯吃这种碳水为主的饭，并且下午七点不是她平日吃晚饭的时间，所以一路上在喊肚子疼。我反正是个碳水大王，吃太多肉反而心里会不舒服。当然，不要学我啊，我最近换了食谱，增加了蛋白质的摄入量，体重才开始变得正常起来。</p><p>回家路上，我刷手机看到了些 Fediverse 上的话题，是关于火锅的。我说，我吃火锅一直都是只吃清汤、猪骨头或者药膳的呢。这会不会是北方的文化习惯？她说应该不是吧，她的母亲是东北人，却非常喜欢吃爆辣的锅底。</p><p>母亲、室友和其他南方朋友们，更喜欢番茄锅。想到过去和室友去吃火锅，都是要鸳鸯锅，或者三个锅底分开。有一个永远是清汤，留给我的，剩下的则是室友想要尝试的味道。南山熊猫烫火锅里，有个牛油跟水果锅底，就被她选去了。结果这水果锅底尝起来像番茄锅，还放了木瓜。虽然听上去都是很丰富的味道，可我吃火锅完全是为了吃麻酱去的。难道是我的味觉已经固化、尝不出复杂味道的美？</p><p>路过一家韩国菜餐厅，她说这是之前老师带她去吃的，很难吃，也就装修好看。我说不好吃就没有意义啦！</p><p>想到自己母亲喜欢吃的爆辣锅底，她说，母亲曾经提出个 bro science。我问什么是 <em> bro science</em>？她解答说是听起来有道理但没有科学依据的伪知识，例如「女人上厕所很慢，所以女人做事都犹犹豫豫」。</p><p>而她母亲的 bro science 是，年轻人都喜好吃辣，是出于社会压力。现在深圳有很多辣辣的店。我一听，嗯，确实是 bro science！这科学依据不能说是没有，不过不太够。</p><p>吃辣啊，我只会吃一点点。小时候在山东根本不需要担心吃辣的问题，因为我们做菜顶多是放一点点辣椒点缀，亦或者是用青椒 —— 青椒是美好的、最好的辣椒啊！尤其是跟五花肉一起炒。来了美国后，也不对，应该是川菜这个菜系忽然开始普及的时候么？突然街上到处都是麻辣烫等又油又辣的菜品。起初我觉得很新鲜，没少吃，开始能吃一点辣了。不过后来逐渐觉得，这玩意儿不好吃的话是真的不好吃…… 尤其是过分的辣和油掩盖了食物本身的味道，我就也不知道它新不新鲜了。</p><p>回家后匹克猫一直黏在我们身边。室友忽然难过起来，说我们最近没时间陪它。以前它还会自主叼玩具过来找我们玩，但昨天室友发现它没有叼过来，恐是平日我们没少敷衍它，所以它知道叼过来我们也不会陪它玩了。先前室友提出把我父母家的咪咪猫带过来、让匹克猫有个伴儿的想法。毕竟母亲也不管咪咪猫有没有打完疫苗、绝育没有，只是把它放在地下室里自己玩自己的。</p><p>可是要把咪咪猫带过来，就得花时间去带咪咪猫预约身体检查、预约绝育，我光是离父母家就很远了，也不可能把还未检查完身体的咪咪猫带到匹克猫身边、跟我们一起住。母亲绝对不会帮我做这些事情，因为她觉得动物活着就好，疫苗什么的都是兽医骗人的。我又没有时间一直往父母家跑……</p><p>我们逗了逗匹克猫玩，然后出门去 GATCHA 了。天开始黑了，街边时不时会躺着无家可归的人。尤其是脚手架下，他们还给自己搭了个临时的小窝。这些人在未来，不会减少，情况也不会改善，反而会愈来愈多吧。到底是为什么，会变成这样呢？不单单是他们的处境，还有我的冷漠和虚伪。明明看都不会看向他们，可能还会觉得碍眼吧，内心却假惺惺想着这样的事情。</p><p>《舞萌 DX》依然很好玩。这个 GATCHA 都是路人玩家的样子，我还瞥到有路人在偷偷拍我们。不经许可却拍摄别人玩游戏，真是烦人啊。不知道肖像权这种东西吗。因为麻烦，我倒也没有制止，只是假装没看到。我也是个性格差的人。</p><p>室友十多年前就有玩这款游戏。说来，还是她兴致勃勃拉我玩的，结果现在我兴趣不减，她反而已经腻了，还好奇为什么我没有腻。</p><p>等排队的期间，有个路人玩家初次玩，却打出了非常不错的成绩，引得室友赞叹。她说这个人比我第一次玩的时候玩得好多了。我生气地说「是啦是啦。」她又说，这个玩家的手指很长很长，一看就是弹钢琴的。学过音乐的人玩音乐游戏入门都很快。她作为从小就学过多种乐器的、「精英教育」下长大的人，玩音乐游戏简直是手到擒来；另一位学钢琴的朋友，我带他玩过七天，结果他很快就达到了刚玩数个月的我的成绩。</p><p>室友觉得，太多玩家去专注于手法这些东西，只是在搞「游戏」，却没有搞明白「音乐」。我想了想，确实如此，我见过许多玩家会栽在需要音押的地方，我自己也是更喜欢目押。不过手法也很重要吧！尤其是《舞萌 DX》这个街机，如果不好好学习发力姿势的话，不说玩起来累不累了，还有可能伤到自己、伤到机器本身。</p><p>我不想要为了玩好《舞萌 DX》所以去学门乐器，不然我要学很多东西、学很久。室友觉得我是在半途而废、只做自己擅长做的事情，有着不好的习惯。但也确实，有些人天生就有音乐天赋，有些人天生没有，可能我就是没有音乐天赋的人，不仅难以拍出拍子，唱歌还总是平调。</p><p>我们跑到二楼的茶饮区，当然不是来买饮料喝的。室友想要唱 K。这是我第一次和朋友出来唱 K。初中时朋友们有邀请过我，但母亲不准我去，因为那是不正经的。不过之后陆陆续续，作为母亲的小孩，来母亲和她朋友们聚餐的地方，总是可以唱 K 的包厢。双重标准啊这是。自己和朋友就可以唱，我和朋友就不能去唱着玩了吗。要说她是我小时候难以和同龄人变得关系亲密的罪魁祸首，也不为过。不小心想到了小时候的许多不愉快的事情，还是不要想了。</p><p><img src="/posts/c783/ktv.webp" alt="" loading="lazy"></p><p>GATCHA 的积分卡里，最值的一档是 55 美元 192 积分。以前还有个 250 美元 1000 积分、能和别的卡一起分积分的，结果后面不知道是老板觉得自己亏了，所以把这个档调整了下价格，变成了谁买谁是傻子的价位。总之唱 K 厅是 20 积分能唱 15 分钟，一个小时就是 22.92 美元。这个移动唱 K 厅的质量也很差：设备经常卡顿、网速慢、门还锁不上！更奇怪的是，这个机器里的很多东西是中文的啊？虽然也有英语翻译，但小得不行，根本就是坑骗不懂中文的人。</p><p>右上角有个可以扫的二维码，一进去发现是微信小程序……？你有病啊。</p><p>在摸索这玩意儿咋用的期间，我们已然浪费了许多分钟。主要是室友在操作，我在唱 <em> Baby Shark</em> 玩。</p><blockquote><p>Baby shark, doo-doo-doo-doo-doo-doo</p></blockquote><p>嗯…… 我真的需要放这首非常可怕的歌的歌词吗？</p><p>之后她唱了许多日语歌。可惜我的日语水平并没有到看了歌词就能立马唱出来的水平，更何况还有一堆汉字呢。很贴心地，每次开始唱之前她都会哼出原唱的调，然后根据我们的自然音高调节程序的调。这也是我第一次知道草东没有派对的许多歌调都很高的这件事，明明是男主唱？</p><p>我除了常听的台湾摇滚会唱外，就只会唱些 80 后会听的那种车载音乐了，比如说《荷塘月色》吧：</p><blockquote><p>我像只鱼儿 在你的荷塘<br>只为和你守候那皎白月光<br>游过了四季荷花依然香<br>等你宛在水中央</p></blockquote><p>放开唱歌很开心，觉得自己在手舞足蹈的。结果一不留神，就把所有的积分唱完了。</p><p>顺带一提最后我们唱的是《姐就是女王》：</p><blockquote><p>姐就是女王<br>自信放光芒<br>你若爱就来<br>不爱莫张狂<br>收起你的那些小小花花肠<br>甜言或蜜语<br>去哄小姑娘</p></blockquote><p>这首歌实在是一看到歌词就会脱口而出啊哈哈哈哈！</p><p>GATCHA 开到凌晨两点呢，真是适合时不时来待一会儿。不过我的「允许大消费」日，得过很久才会来下一次吧。</p><p>两个人一边聊着什么「颤音是种技能啊」，一边哼着歌回家去了。想到早上的种种想法，觉得能这样发展实在是太好了。就算今天不是个好天气、买到了特别难吃的乌冬面、可乐被坑了 10 块钱、唱 K 的房间锁不上门我还唱不准调，但都无所谓、不重要了。</p><p><img src="/posts/c783/instruments.webp" alt="" loading="lazy"></p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;近些天的天气闷闷热热的，想必是为了给接下来的雷阵雨做准备的吧。&lt;/p&gt;</summary>
    
    
    
    <category term="日常生活" scheme="https://blog.cytrogen.icu/categories/%E6%97%A5%E5%B8%B8%E7%94%9F%E6%B4%BB/"/>
    
    
  </entry>
  
  <entry>
    <title>大熊猫送快递</title>
    <link href="https://blog.cytrogen.icu/posts/3a5e.html"/>
    <id>https://blog.cytrogen.icu/posts/3a5e.html</id>
    <published>2026-07-25T04:00:00.000Z</published>
    <updated>2026-07-26T04:06:57.921Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>本月我尝试了大名鼎鼎的 Panda Express，美式中餐的鼻祖。本来以为会很难吃，结果发现…… 哎你还真别说，挺不错的。</p><span id="more"></span><p>尽管我在中国仅待了十年左右，但我觉得我是中国人、对正经的中餐有深刻的了解，怎么可以去接受美式中餐这种异端！</p><p>除开口味上的本地化，也就是酸甜口，美式中餐也为中餐这个大类带来了许多偏见，例如陈皮鸡、左宗棠鸡这种诡异的东西，都是什么鬼！我才不认可呢，也不准有非中国人跟我说，吃中餐是不是要吃左宗棠鸡这种东西！</p><p>因此，在美国的这十几年来，我都未曾去 Panda Express 买过饭。</p><p>根据网络上的记载，Panda Express 在 1983 年就出现了。当时的华人移民想要本地化中餐、赚外国人的钱，于是发明出了陈皮鸡（orange chicken）。它的味道…… 总之就是酸酸甜甜的口味。</p><p>创始人中的丈夫 Andrew Cherng，他的父亲因为当时的国共内战，逃到了台湾去，想要打工赚钱后接家人出来。但是在共产党接管了内地后，出境变得非常困难。Andrew Cherng 的母亲只能藏在船底偷渡，然后花钱找蛇头分三次将儿子偷偷运出来 —— 想起了《那片血一般红的杜鹃花》。</p><p>长大后的 Andrew Cherng 靠奖学金去了 Baker University 读书，是 Kansas 的一所私立宗教大学。</p><p>创始人中的妻子 Peggy Cherng 也在这所大学读书，读的还是计算机科学专业。</p><p>有趣的是，她毕业后去 McDonnell Douglas（之后被并入到波音公司，也就是造波音客机的公司）做软件工程师。所以嘛，学计算机专业的未来不一定在计算机行业住下了，也不一定去做 <a href="https://www.geedea.pro/weekly/90/#%E5%88%87%E7%89%87:~:text=%E5%AD%A6%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%9A%84%E5%AD%A6%E9%95%BF%E5%AD%A6%E5%A7%90%E4%BB%AC%E4%B8%BA%E4%BB%80%E4%B9%88%E8%BF%99%E4%B9%88%E5%A4%9A%E5%8E%BB%E5%BD%93%E6%88%BF%E4%BA%A7%E4%B8%AD%E4%BB%8B%E4%BA%86">房产中介</a> 了，还有可能在开餐饮公司！</p><p>单看丈夫的历史背景，其实便能看出 Panda Express 的「问题」所在：不正宗、是移民文化的产物 —— 会如此评价它的，自然也是未能经历过移民的人。两者因为经历不同，永远都不会产生共鸣。</p><p>过去我同样如此评价它，嘲讽它的 fortune cookie、奇怪的菜品，也是那时的我深受「正宗」的影响。正不正宗，只要不挂牌欺骗客人，根本所谓不大。菜首先得是好吃的吧，其次再去考虑文化吧。如果谁非要说美式中餐哪来的文化，咋的，移民文化不是文化？菠萝披萨不受意大利人待见，但它照样好吃吧。</p><p>现如今，Panda Express 已然是美国最大的亚洲餐饮连锁品牌。我家附近就有一家，招牌挂得大大的。每次路过，都能看到里面坐满了人。</p><p>其实这个月会让我注意到它，是因为一次出门，路过它时发现它的最低薪资开出来还不错，比做奶茶店好多了。看来是打工打得太多，对奇怪的事情有了奇怪的注意力……</p><p>因为实在是忙得不可开交，尤其是甲方老板的沟通方式令人难受、摸不着头脑。我近乎是天天泡在共享办公室内，从早泡到半夜三更。回家后还得和室友一起准备次日的饭菜，实在是难熬。</p><p>我还有个选择，那就是买美式中餐。它们一是对比地中海菜（比如 CAVA）更合我的胃口，二是便宜量大。美式中餐夫妻店在美国可以说是到处都是。只要有中国人，在鸟不拉屎的地方开一家美式中餐馆也可以活得滋润。</p><p>但是美式中餐夫妻店，如果运气好能吃到技艺高超的师傅做出来的菜；但运气不好，就只能吃到又油又恶心又糟蹋食物的垃圾了。办公室旁边的夫妻店，就是后者 —— 哇靠我还是在美式中餐馆打过半年一年的工的，好师傅做出来的同个菜品什么水平，我还是知道的。但这家的师傅是什么鬼，怎么能把菜做出来整个 206 盒子都是油的！再就是，这家店很坑人啊，量很少，根本对不起价格。一个 pint 的菜怎么能卖别家店一个 quart 的钱？</p><p>于是我必须得想个办法才行…… 对啊，办公室旁边不是有家 Panda Express 吗？注册了账户后，它识相地送了我张券，10 块钱以上的单子能打八折。我在电脑上下了个自取单，点了 bowl bundle，即一饭一菜一饮料，我分别选择了炒饭、非常安全不会错的西蓝花炒牛肉、可乐。</p><p>说到西蓝花，美式中餐里另一个很有名的系列，就是西蓝花炒 XX 系列。XX 通常是鸡胸肉片、叉烧、牛肉和虾仁。但是呢，这个系列在中文的菜单上往往都叫……「芥蓝炒 XX」。广东人对这个芥蓝很熟悉吧，它和西蓝花可能在祖上有点关联，但说西蓝花是芥蓝，实在是…… 指鹿为马！</p><p>因此，我在美国点菜要很小心。我不知道这家店的 <em> broccoli</em> 指的到底是西蓝花，还是芥蓝？有些广东人开的餐馆，会严肃地使用芥蓝，但英文名依然标注 <em> broccoli</em>。这和自助火锅店里的花生酱芝麻酱问题差不多：我需要两个酱料都尝一遍，才能得知哪个才是甜又丝滑的、哪个才是苦又稠的。</p><p>总之那个订单的总价是 13.90 美元，用了券，再加上税，就是 12.11 美元。还可以吧，在我的可接受范围内。</p><p>自取时，我终于是第一次走进了 Panda Express 的实体店。一进门就能看到人们在用餐区内吃饭，食物则明面摆在不锈钢台上。看样子现场点单的流程是先选择要多少菜、员工会拿对应的纸饭盒来，再指哪个、让员工夹哪个，最后结账算钱走人。不过店的布局设计还是有点问题，因为收银台被安排在颇为狭窄的走道处。客人算完钱后，出来就要同时和自助饮料机、排队也要结账的客人、过来自取单子的客人挤在一起。</p><p>说回食物本身，看上去都颇有食欲。我报出了我的名字，员工会问我我留的电话号码的最后四位数是什么，然后笑脸拿给我饭。不过那会儿自助饮料机没有气了，他们只能给我柠檬汁，我也不好说什么，毕竟没有气的可乐和叫我喝尿没有区别。</p><p>拿饭回办公室吃的时候我发现，饭看着有点少的样子，其实完全够吃。</p><p>虽然我在平台上说了不要餐具和餐巾纸，但员工们还是放了一套在里面。说好的环保呢！</p><p>不过这应该是 SOP 的锅。有些东西员工们是就算看了也没用，照样得根据店内规矩做，比如前些年纽约市还是纽约州说饮品店不能默认给吸管，只有在顾客要求给的时候才能给吸管，但我们员工依然还是得无脑放，不然会被顾客投诉呀！</p><p>Fortune cookie 的包装袋居然烂了，饼干已经软化、不好吃，遂投喂给喜欢吃的室友。</p><p>这个东西是我来了美国后才知道有这玩意儿的东西之一，另一个是来了美国才初次见到的煎饼馃子…… 嗯我在中国其实没有见过它；我都是吃火烧和馒头的。说是饼干，不过应该是膨化食品么？我不爱吃，开里面的小纸条倒是蛮有意思。</p><p>炒饭炒得一般，吃起来像拌饭，无法接受！虽然我是做饭白痴，但还是有拿手好菜的，那就是炒饭。做炒饭我可是很认真的，无论是分离蛋白蛋黄、试图做炸蛋丝、青葱要分三次放、蔬菜比例要均匀…… 这个拌饭一样的东西是什么！你管它叫炒饭吗！黏糊糊的，怕是后厨根本没有大火吧！</p><p>更可恨的是，炒饭内居然有明显夹生的饭块块。饭粒本身也很有问题，吃起来生生的。</p><p>西蓝花炒牛肉是个非常安全的选择。毕竟其他菜品，像是什么北京牛肉、宫保鸡丁，很令人怀疑。作为我初次尝试 Panda Express 选择的菜品，姑且还是选择之前吃过的吧。</p><p>神奇的是，它居然比我去过的许多夫妻店炒出来的要好吃。不油腻，不能说多好吃，但绝对不难吃。</p><p>最后是柠檬汁。它喝起来完全不像是柠檬汁，根本就是没有气的雪碧，稍微苦一点点、酸一点点而已。因为太酸了，我只能慢慢喝，酸到牙齿发酸。尽管只是中杯的大小，但我没能喝完。</p><p>可悲的是，这个纸杯子会随着时间开始漏水，柠檬汁也借此慢慢地漏到了我的桌子上……</p><p>这就是我初次尝试 Panda Express 的经历！说实话，让我改观了。吃起来很不错，和路边的夫妻店有所不同。</p><p>然后我便染上了 Panda Express 瘾。主要是在办公室里吃它，很有上班族的仪式感，呵呵呵……</p><p>第一次点完单后，Panda Express 给我发了封邮件，想要我填个小表格，填完可以拿个免费一菜券。这便引来了我的第二次点单。</p><p>第二次，我点了两菜一饭，券又送了我一道菜。这次的「饭」我选了炒面，三道菜分别是安全的西蓝花炒牛肉、陈皮鸡和蜂蜜核桃虾。</p><p>这个陈皮鸡啊，是室友好奇所以点的，毕竟是美式中餐的有名战将之一。它有两个孪生兄弟：芝麻鸡和左宗棠鸡，其实都是鸡肉先放油里炸，取出来后放锅里拿酱汁炒。左宗棠鸡是带辣的，这三个家伙儿味道基本上相同。我并不爱吃这哥儿仨，但室友很好奇味道，就让她吃吧。</p><p>蜂蜜核桃虾我其实过去就有所听闻。当时我还在玩小红书，首页上都是留学生们的帖子，当然还有讨人厌的引战帖子…… 总而言之有人在上面说过，Panda Express 的蜂蜜核桃虾特别好吃。</p><p>炒面和炒饭有着同样的问题：夹生，然后咸。尤其是我这次点单没要饮料，点的三道菜里，荤对比素的占比更多：素仅有西蓝花，意味着解腻我只能靠它。</p><p>陈皮鸡和我预料中的一样，我不喜欢吃，室友也不喜欢吃。它很甜腻，必须要配什么来解腻。虽然脆脆的、口感很不错，但实在是不能打好评啊。</p><p>蜂蜜核桃虾确实很好吃，可惜味道和陈皮鸡相似，配合起来反被扯了后腿。不点陈皮鸡的话我的评价还能再上一层楼。再就是，其实我不喜欢吃坚果类的食物，所以核桃还得扣点分。</p><p>这第二次点单原价是 20.40 美元。用了券，再加上税，就是 14.26 美元，不错不错，相当满意。</p><p>第三次点单是和室友一起点的。我俩都懒懒的、不想做饭，于是在办公室下了单，一人点一份二菜一饭。我点的是白米饭、西蓝花炒牛肉（非常安全和安心）、蜂蜜芝麻鸡胸肉；室友点的是炒饭、宫保鸡丁、北京牛肉。</p><p>两个人一起去取饭。她第一次进到 Panda Express 里来，觉得蛮稀奇，竟比想象中干净漂亮点。然后这个家伙儿，取完单后跟我说女员工长得真漂亮、笑起来很甜。我说这一切都是打工的需求啊 —— 当然也不否认，有些人就是日常如此。在我之前打工的店里，就有这样的人，好似天生热情好客、有礼貌。</p><p>先说我的饭好了。</p><p>白米饭…… 唉，不想说了，毕竟是拿它炒的饭。依然有夹生感，我感觉是米的选择问题么？不过它比起炒饭和炒面，配下饭的菜更香更好吃。</p><p>这个蜂蜜芝麻鸡胸肉是我随便选的。它和陈皮鸡类似，也是裹薄糊炸的鸡胸肉，再和蜂蜜芝麻酱汁炒在一起。口感依然脆脆的、是甜酸口。但是！它和陈皮鸡最大的区别，就是它有配菜！根本就是陈皮鸡这个烂招牌的升级版本。</p><p>室友的炒饭据她所说，比我初次点的要好吃些。我说该不会是我填写的表格被上头看到、店被批评了、员工又被训了一顿，所以好好炒了吧 —— 好像有点自作多情了呢。</p><p>宫保鸡丁…… 比陈皮鸡更糟糕的选择。我得说明一下，我没有吃过国内的宫保鸡丁，但看图片能看出是咸辣口的。Panda Express 进行了改良，所以它变成了甜辣口。我们在吃的时候，就看不到多少鸡肉，全是西葫芦丁跟洋葱。室友这个没我挑剔的人都在边吃边皱眉。</p><p>不过她也得到了忍耐之后的奖赏：北京牛肉！宛如一匹黑马，出现在餐桌上！我的意思当然不是我要吃马肉了。我起初对它没有什么感觉，只是觉得不是北京菜却叫作 <em> Beijing Beef</em> 这一点很奇怪，和我小时候第一次知道兰州拉面其实根本不是兰州的，也不该是拉面一样奇怪。还要说的话，那就是老婆饼里没有老婆、雷峰塔里没有雷锋、钱包里没有钱 —— 这个段子好老啊。</p><p>它是炸过的牛肉条，然后用酸甜微辣的酱汁，配上甜椒和洋葱炒出来的。它比想象中好吃许多，特别下饭。脆脆的牛肉条，除了好吃说不出来别的。</p><p>所有东西加起来的价格是 28.53，两个人对半劈一下就是每个人 14 美元多。稍微有一点点接近我的接受范围。在我开始跑去唐人街之后，我对吃饭的接受预算便逐渐往 10 块钱靠了。</p><p>这三次点单都有个共同点，那就是菜品都不咋油腻。虽然有个别菜品很是甜腻啦，但对于有些厌烦了油腻的我来说，蛮新鲜的。</p><p>我非常乐意继续点 Panda Express 吃，一直点到吃腻为止吧。不过看看钱包，还是得少在外面买饭吃。自己买菜自己做，才是王道。</p><p>吃饭的时候我总是会想到之前对 Panda Express 的偏见。这也受了早些年泡在中文互联网里的影响。毕竟主流平台上的思想，因为群体极化效应，还有推荐算法等等因素，变得要么只能看到极端爱国的言论，要么就是极端恨国。前者里，不乏有对中国元素无脑追捧的想法在，例如给外国人吃的中餐不正宗、不好吃、低级等发言。</p><p>我也不知道为什么过去的自己那么在乎「正宗」，明明已经不再是他们眼里的中国人，而是什么「美爷」、「奸细」等等外来者的称呼。小时候也发生过类似的事情，那时作为山东人、外乡人的我去福建的外婆家，却被那边的村民，甚至是血亲用方言欺负、嘲笑…… 我只能逃到山东去，那才是能接纳我的地方。</p><p>对于主流的中文互联网平台来说，我也是罕见、不寻常的。或许小红书这个面向海外华人用户的平台能让我有点共鸣这一点，也是我当时那么沉浸于此的原因。不过它的推荐算法太烦人了，我便注销了账号、逃走了。</p><p>说到底，我为什么非要去讨好不认为我是他们一员的群体呢？我有自己的故事、自己的视角，不论是中美哪边，向我说些只有他们内部才在乎的事情，我也会觉得烦躁。** 我就是个移民，不是两边的任意一边，也是两边的任意一边。** 食物啥的，好吃就行了，管你正宗不正宗。它们和影视作品一样，到另一个国家都是要做本地化的！</p><hr><p>说起来，会起草这篇文章还是因为这篇 <a href="https://thomasrigby.com/posts/translation-vs-localisation/">文章</a>：</p><blockquote><p>This came up recently in a conversation online and, following my rule of "if it's more than three tweets, make it a blog", I wanted to actually unpack it.</p><p>最近在网上的一次对话中提到了这件事，遵循我「如果超过三条推文，就写成博客」的原则，我想具体展开聊聊。</p></blockquote><p>我在碰 Fediverse 之后，或者更准确说，类 Twitter 的 Fediverse 软件之后，就一直很担心我会把想写的东西都一股脑塞 Fediverse 上、反倒是忽视了博客。事实证明，我确实会做这种事情。随着 Fediverse 上的帖子愈来愈多、我花在 Fediverse 上的时间愈来愈多、我花在写博客文章上的时间愈来愈少…… 明明有很多有趣的事情可以写成博客文章发出来，但我全都选择发在 Fediverse 上了，实在可惜。</p><p>作者 Thom 的原则很适合拿来参考。我现在会记下话题的出现次数。如果发了超过或等于三条与其相关的 toot，意味着它足够被我拿来写成博客文章，我就得加把劲儿写出来。</p><p>哎呀博客文章这种东西还是得冲动一下写出来，不然像工作一样写出来、多没劲儿啊。Fediverse 碎片化的发 toot 形式，正好可以记录我当时的感想。之后写博客文章，我就能抄下来当时的情绪了。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;本月我尝试了大名鼎鼎的 Panda Express，美式中餐的鼻祖。本来以为会很难吃，结果发现…… 哎你还真别说，挺不错的。&lt;/p&gt;</summary>
    
    
    
    <category term="日常生活" scheme="https://blog.cytrogen.icu/categories/%E6%97%A5%E5%B8%B8%E7%94%9F%E6%B4%BB/"/>
    
    
    <category term="食物" scheme="https://blog.cytrogen.icu/tags/%E9%A3%9F%E7%89%A9/"/>
    
  </entry>
  
  <entry>
    <title>想法在丙午荷月迭代</title>
    <link href="https://blog.cytrogen.icu/posts/b02e.html"/>
    <id>https://blog.cytrogen.icu/posts/b02e.html</id>
    <published>2026-07-01T04:00:00.000Z</published>
    <updated>2026-07-02T04:02:22.340Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>酷暑逐渐来临。连打工兼职都能失业的我，依然在拼命找工作中。为了赚钱，这个月开始学习些和计算机不相干的东西。</p><span id="more"></span><details>      <summary>本期导读</summary>      <h2 id="输入"><a class="markdownIt-Anchor" href="#输入"></a> 输入</h2><h4 id="世界"><a class="markdownIt-Anchor" href="#世界"></a> 世界</h4><ul><li><a href="#gfw-%E5%BC%80%E6%BA%90%E4%B8%8E%E7%A4%BE%E4%BC%9A%E4%B8%BB%E4%B9%89">GFW，开源与社会主义</a></li><li><a href="#%E6%88%91%E4%BB%AC%E6%9D%A5%E8%B0%88%E8%B0%88-ai-slop">我们来谈谈 AI slop</a></li><li><a href="#humpty-dumpty-%E9%81%87%E8%A7%81%E4%BA%86%E7%A8%8E%E6%B3%95">Humpty Dumpty 遇见了税法</a></li></ul><h4 id="远方"><a class="markdownIt-Anchor" href="#远方"></a> 远方</h4><ul><li><a href="#bricks-minifigs-%E5%92%8C-reckless-ben-%E4%BA%89%E8%AE%AE%E4%BA%8B%E4%BB%B6">Bricks &amp; Minifigs 和 Reckless Ben 争议事件</a></li><li><a href="#toadking-v-yeah-jaron-wahhfff-2026">ToadKing v. Yeah_Jaron &amp; Wahhfff [2026]</a></li><li><a href="#%E5%A6%82%E6%9E%9C%E5%AF%BC%E8%87%B4%E5%88%9D%E7%BA%A7%E5%91%98%E5%B7%A5%E6%8B%9B%E8%81%98%E7%96%B2%E8%BD%AF%E7%9A%84%E5%8E%9F%E5%9B%A0%E4%B8%8D%E6%98%AF%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD-%E8%80%8C%E6%98%AF%E8%BF%9C%E7%A8%8B%E5%8A%9E%E5%85%AC%E5%91%A2">如果导致初级员工招聘疲软的原因不是人工智能，而是远程办公呢？</a></li><li><a href="#sam-altman-%E8%A1%A8%E7%A4%BA%E5%AF%B9%E5%A4%A7%E5%A4%9A%E6%95%B0%E4%BA%BA%E6%9D%A5%E8%AF%B4-%E5%A4%A7%E5%AD%A6%E7%9A%84%E6%95%88%E6%9E%9C%E5%B0%86%E4%B8%8D%E5%86%8D%E7%90%86%E6%83%B3">Sam Altman 表示对大多数人来说，大学的效果将不再理想</a></li><li><a href="#%E9%98%BB%E6%AD%A2%E5%A4%A7%E5%9E%8B%E7%A7%91%E6%8A%80%E5%85%AC%E5%8F%B8%E8%AF%B1%E5%AF%BC%E7%94%A8%E6%88%B7%E5%81%9A%E5%87%BA%E8%BF%9D%E8%83%8C%E6%84%8F%E6%84%BF%E7%9A%84%E8%A1%8C%E4%B8%BA">阻止大型科技公司诱导用户做出违背意愿的行为</a></li><li><a href="#%E5%BC%95%E7%94%A8%E6%98%AF%E5%A6%82%E4%BD%95%E6%AF%81%E6%8E%89%E7%A7%91%E5%AD%A6%E7%9A%84">引用是如何毁掉科学的</a></li><li><a href="#%E5%BC%82%E6%80%A7%E4%B9%8B%E9%97%B4%E6%9C%89%E7%BA%AF%E5%8F%8B%E8%B0%8A%E5%90%97">异性之间有纯友谊吗？</a></li><li><a href="#%E5%9F%8E%E5%B8%82%E9%B8%9F%E7%B1%BB%E7%94%B1%E4%BA%8E%E4%BA%A4%E9%80%9A%E5%99%AA%E9%9F%B3-%E8%B5%B7%E5%BE%97%E6%9B%B4%E6%97%A9%E4%BA%86">城市鸟类由于交通噪音，起得更早了</a></li><li><a href="#%E5%9C%A8%E7%9D%A1%E7%9C%A0%E4%B8%AD%E5%AD%A6%E4%B9%A0%E6%98%AF%E5%8F%AF%E8%83%BD%E7%9A%84-%E4%BD%86%E6%88%91%E4%BB%AC%E5%BA%94%E8%AF%A5%E8%BF%99%E4%B9%88%E5%81%9A%E4%B9%88">在睡眠中学习是可能的。但我们应该这么做么？</a></li><li><a href="#%E8%BD%AF%E4%BB%B6%E7%9A%84-emacs-%E5%8C%96">软件的 Emacs 化</a></li><li><a href="#%E8%BF%99%E4%B8%8D%E4%BB%85%E4%BB%85%E6%98%AF-x-%E6%9B%B4%E6%98%AF-y">这不仅仅是 X，更是 Y</a></li><li><a href="#%E6%9C%89%E8%B6%A3%E9%A1%B9%E7%9B%AE">有趣项目</a></li><li><a href="#%E7%A7%B0%E5%91%BC%E5%AE%83%E4%BB%AC%E4%B8%BA-aigents">称呼它们为 <em>aigents</em></a></li><li><a href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E6%AF%8F%E6%89%80%E5%AD%A6%E6%A0%A1%E7%9A%84%E5%90%89%E7%A5%A5%E7%89%A9%E9%83%BD%E9%95%BF%E5%BE%97%E4%B8%80%E6%A0%B7">为什么每所学校的吉祥物都长得一样？</a></li></ul><h4 id="周遭"><a class="markdownIt-Anchor" href="#周遭"></a> 周遭</h4><ul><li><a href="#%E6%88%90%E4%B8%BA%E7%88%B6%E4%BA%B2%E4%BC%9A%E4%BD%BF%E4%BD%A0%E7%9A%84%E5%A4%A7%E8%84%91%E8%90%8E%E7%BC%A9">成为父亲会使你的大脑萎缩</a></li><li><a href="#711-%E5%85%A8%E8%81%8C%E5%BA%97%E5%8A%A1%E5%91%98%E7%A6%BB%E8%81%8C%E5%BF%83%E5%BE%97">711 全职店务员离职心得</a></li><li><a href="#%E5%85%AC%E5%85%B1%E9%95%BF%E6%A4%85%E7%9A%84%E6%B6%88%E5%A4%B1">公共长椅的消失</a></li><li><a href="#%E9%80%83%E8%B7%91%E7%9A%84%E7%94%B7%E6%80%A7%E4%B8%8E%E7%BA%B5%E6%AC%B2%E7%9A%84%E5%A5%B3%E6%80%A7">逃跑的男性与纵欲的女性</a></li></ul><h4 id="眼前"><a class="markdownIt-Anchor" href="#眼前"></a> 眼前</h4><ul><li><a href="#%E5%A6%82%E4%BD%95%E5%9C%A8%E4%B8%8B%E7%8F%AD%E5%90%8E%E4%B8%8D%E5%86%8D%E6%84%9F%E5%88%B0%E7%B2%BE%E7%96%B2%E5%8A%9B%E5%B0%BD">如何在下班后不再感到精疲力尽</a></li><li><a href="#%E6%88%91%E4%B8%BA-16-%E5%B2%81%E7%9A%84%E5%A5%B3%E5%84%BF%E5%AE%9A%E5%88%B6%E7%9A%84-2026-%E6%9A%91%E6%9C%9F%E5%AE%9E%E4%B9%A0%E8%AE%A1%E5%88%92">我为 16 岁的女儿定制的 2026 暑期实习计划</a></li><li><a href="#%E4%BD%A0%E4%B8%BA%E4%BB%80%E4%B9%88%E4%B8%8D%E6%90%AC%E5%88%B0%E5%88%AB%E5%A4%84%E5%8E%BB">「你为什么不搬到别处去？」</a></li><li><a href="#%E8%83%8C%E5%8C%85%E6%B4%BB%E5%8C%96%E8%83%BD">背包活化能</a></li></ul><h2 id="输出"><a class="markdownIt-Anchor" href="#输出"></a> 输出</h2><ul><li><a href="#%E6%8A%98%E8%85%BE%E5%8D%9A%E5%AE%A2">折腾博客</a></li><li><a href="#%E6%88%91%E5%86%99%E7%9A%84%E6%96%87%E7%AB%A0">我写的文章</a></li><li><a href="#%E7%BC%96%E7%A8%8B%E5%8E%86%E7%A8%8B">编程历程</a></li><li><a href="#%E4%B9%A6%E7%B1%8D">书籍</a> / <a href="#%E5%BD%B1%E8%A7%86">影视</a> / <a href="#%E9%9F%B3%E4%B9%90">音乐</a></li><li><a href="#%E6%97%A5%E8%AE%B0%E7%89%87%E6%AE%B5">真生活</a></li></ul>    </details><h2 id="世界"><a class="markdownIt-Anchor" href="#世界"></a> 世界</h2><p><a id="gfw-开源与社会主义"></a></p><h4 id="gfw开源与社会主义"><a class="markdownIt-Anchor" href="#gfw开源与社会主义"></a> <a href="https://text.tchncs.de/gleymdalandid/zhuan-zai-gfw-kai-yuan-yu-she-hui-zhu-yi">《GFW，开源与社会主义》</a></h4><p>这篇文章最初发布于 2023 年 7 月 6 日，后由转载者于 2026 月 5 月 23 日存档补档。</p><p>文章分为两大部分：</p><p>一、GFW 如何危害开源社区。</p><p>首先，什么是 GFW？是 <u>Great Firewall</u>（国家防火墙），是中国政府实施的大规模互联网审查和访问控制系统的俗称。不过在中国的官方语境中，它应该叫「国家公共网络监控系统」。使用 <em> Great Firewall</em> 是对长城（Great Wall）的戏仿。</p><p>它主要是做两件事：一是阻止中国境内用户访问特定的境外网站和服务，二是对网络流量进行深度包检测，识别并拦截包含敏感关键词的请求，甚至可以针对特定的协议进行干扰，例如 Tor。</p><p>对于开发者而言，它会限制各个包管理器的速度、让 GitHub 这类平台的连接更不稳定。这就导致了初学者单单是搭建开发环境，就需要花很多时间，毕竟无法访问 Google 和 StackOverflow。国内的平台又无法支撑高质量的开源社区。</p><p>因此，一个普通的程序员想要在中国搞开源，就得违反中国的法律，进行国际联网。</p><p>不过从小就不能接触境外的网络平台，进入英语母语环境要比其他国家的人们更晚一些。就算真的访问了境外更常用的平台，我想也有阻力去让程序员们搞明白如何使用它们。</p><p>二、现有政策的真实意图，以及咋办。</p><p>作者主张，开源本质上是生产资料公有制的实践，且引用了 Marx 的手稿。</p><p>不过作者提到开源公共仓库不受政策影响，我就得挑下眉毛了。虽然可以看出作者对 GitHub 的喜爱，但真的深入去中心化、数字主权的世界当中，就会发现境外的世界，也并非世外桃源的样子。GitHub 也一样。我过去便有提起过 GitHub 的各种问题，尤其是它在被 Microsoft 收入囊中之后。</p><p>不知道读者朋友们是否还记得俄罗斯和乌克兰打得有来有回的那个 2022 年？当然没有真的「有来有回」。那段时间大量的美国企业公开反对俄罗斯，就连我出门吃饭，都得小心餐厅会不会额外收我「给乌克兰的支持费」—— 如果这笔钱真的会送到老百姓的手上的话，我会很愿意 <strong>主动</strong> 捐款的。</p><p>GitHub 自然也做了相关的措施：无预警地封禁俄罗斯公司的开发者账户。大家的 Pull Request、Issue、评论都从项目中消失，还破坏了其他人的项目历史。</p><p>所以说啊，GitHub 的官方政策是一回事，实际执行是另一回事。我在公司网站的隐私条款里大写特写「用户的数据我会删除」，但美国政府真找我要，我还是得交上去的。因此美国平台可能对中国开发者下手，并非空穴来风。</p><p>不过非黑即白地再去说「民族开源平台」，也不行。更准确的结论应该是，<strong>任何平台都不可完全信任，开源的真正保障在于代码的可复制性和分布式镜像，而不在于任何单一平台的承诺</strong> —— 是的，接下来就是五千字说服你为什么应该自托管代码…… 开玩笑的。</p><p>从这里开始，就能看出作者是在用 Marx 主义和阶级斗争的框架来分析 GFW。这种说法非常地「中国」。实际上，我时常从中国互联网中看到这种框架，且是以结论出现的。事情总是复杂的，怎么可能什么事情都能用一个框架来解释呢？因此我想要从这个框架之外，看到些什么。</p><p>既然这里的 Marx 主义与阶级分析，是分析 GFW 的工具和手段，那么它是否有效，就得回答上这些问题：</p><ol><li>GFW 的实际效果是否确实维护了特定群体的利益？</li><li>开源的公有制性质是否确实与统治逻辑存在冲突？</li><li>作者的因果链条是否站得住脚？</li></ol><p>第一条不难验证。GFW 封锁了几乎所有的国际信息渠道，让掌握国内信息分发权力的平台和监管者受了益。百度、微博、哔哩哔哩等平台在无竞争的环境下壮大，监管者获得了对信息流的完全控制权。</p><p>而 GFW 对开发工具的封锁，仅对普通开发者受损。有资源搭建专线的企业可以通过各种渠道获得稳定的访问。有资源者不受影响，无资源者被限制，的确和阶级压迫的描述有所吻合。</p><p>第二条的核心是「开源社区是一个自组织的、去中心化的、生产资料公有的实践」。它可以证明一群人可以在没有老板、没有国家指令的情况下协作生产高质量产品 —— 这一点我也抱有不赞同的态度。</p><p>如果对上个世纪的开源软件运动有所了解的话，就会知道，它是一次有意的政治操作的产物。当年的 Richard Stallman 搞出来自由软件运动，但被 Eric Raymond 嫌弃，觉得 <em> free</em> 这个词会让企业感到不舒服，而 <em> open source</em> 听上去更务实、更商业友好 —— 这是重点，<strong>对商业友好</strong>。</p><p>不知道是哪位所说的，「所有的技术问题都是资本和政治问题」，这次的开源软件运动也是一样。它为什么能胜过自由软件？并不是因为开源的理念更正确，而是因为开源对资本更友好 —— 开源是被资本选中的。</p><p>开源运动的核心诉求是开发效率，因为开放源代码能写出更好的软件，是实用主张。实际上，今天去 GitHub 上逛一圈，你能看到许多人们常用的框架都是企业折腾出来的，甚至是极客们常称呼的「邪恶企业」。但也没办法啊，这些底层框架被开源，无数个开发者去免费维护它、使用它，企业再免费搭车 —— 就是会形成散户和企业的 win-win。</p><p>尽管我很 <a href="/posts/b984.html">讨厌</a> Stallman 这个人，但也不得不承认他提出的自由软件运动、GPL 协议等，都是最接近于作者口中「公有制实践」的存在。可惜，因其强烈的传染性，GPL 协议逐渐被对商业极其友好的 MIT 和 Apache 协议给踢走、边缘化了。资本真是用脚投票、捧红了符合自己利益的「开源」模式啊！</p><p>例子有，Google 开源了 Kubernetes 后交给 Linux 基金会、Meta 开源 LLaMA…… 用免费产品建立了生态后，就锁定标准、挤压竞争对手，然后在自己的云服务或者硬件上赚钱。</p><p>说到 Linux 基金会，我因 <a href="/posts/d33e.html">2.75 美元</a> 而自行生长在脑子里的「基金会雷达」证明，这东西的年收入也是多到能在数不清的 Benjamin Franklin（100 美元纸币上的男人）里游泳。而我也不知道是哪根筋搭错了，订阅了它很久的 newsletter。现在它天天给我发大厂赞助的 AGNTCon、MCPCon（不懂英语的读者朋友们可以尝试提取下里面的字母，来猜猜是什么），巴啦巴啦，烦死了！退订了怎么也还在啊。</p><p>说实话就算是 Linux 内核这种，我们认为是开源软件运动、开源社区的一大代表，也不是靠用爱发电的极客们支撑起来的，而是受雇于 Intel、Microsoft、Red Hat 等科技巨头的全职员工维护的。数据是如何的呢？根据这份 <a href="https://commandlinux.com/statistics/linux-kernel-contributors-lines-of-code-statistics/">报告</a> 来看，2025 年全年有 84.3% 的企业开发者贡献了内核提交，而他们来自于 1780 个组织。</p><p>在 2024 年 11 月，对 6.12 内核这单一版本的 <a href="https://lwn.net/Articles/997959/">统计</a> 里，没有雇主标识的贡献者，也就是独立和志愿者开发者，仅占 5%。再加上无法确认雇主的 8.8%，那也只是 13.8% 而已！</p><p>所以开源是公有制么？我不这么见得。项目的方向实际上由出资的科技巨头所把控，而最终获取丰厚经济回报的，也是那些将开源软件包装成云服务、建立商业闭环的企业。</p><p>少部分独立开发者确实无偿贡献了劳动、承担了边缘的维护成本；而站绝大多数的企业雇员则是在出卖劳动力编写开源代码。两者都是在「自由」地参与建设，但雇员们创造的价值最终是要被企业转化成利润的。</p><p>如果非要引用 Marx 的话，我想到他提起过，「流通领域中的自由契约掩盖了生产领域中的剥削关系」。换言之，开发者在「自由」地提交代码，企业也在「自由」地利用这些代码构建商业壁垒。明明大家都是「自由」的，但两者真的是平等的吗？你会相信工作中，工人和老板是平等的吗？</p><p>结合先前说到的民族开源平台，作者对平台和资本的信任有些天真。这是理论框架的盲区，仅看到压迫是不行的，也得看到更为可怕的「收编」。</p><p>这样再去看第二条，我们就有了个新的问题：既然开源社区由资本控制，那么由国家控制的体制，真的会认为它是个威胁么？逻辑都是同一个啊？</p><p>我有个大胆的猜想：恐怕，国家从来都没有正眼瞧过开源社区吧。</p><p>GFW 封禁的逻辑到底是什么？是封禁所有不可控的信息，尤其是信息流通。而很悲痛的，开源社区不仅依赖于信息流通，对中国来说也是不可控的，所以…… 事情就这么发生了。</p><p>第三条中，作者的因果链条是：</p><blockquote><p>GFW 存在，是因为统治寡头害怕开源的公有制性质，所以 GFW 是阶级压迫的工具。</p></blockquote><p>第一步和最后一步都有证据支持，但中间这一步，我们已经知道了「开源社区并非公有制」这一点，并且想出了更多问题：</p><ol><li>就算如此，GFW，或者说中国政府，是否害怕公有制？</li><li>反推的话，中国政府是否是真的很害怕不可控的东西？</li></ol><p>在 Kevin Xu 的 <em> open source in China</em> 系列的第二篇 <a href="https://interconnected.blog/open-source-in-china-the-game/">文章</a> <em> The Game</em> 中，他指出中央政府实际上早就拥抱了开源。而他给出的理由耐人寻味：</p><blockquote><p>[China] prefers to favor flexible technologies that aren't tied to certain vendors, companies, or countries, so it can control and shape them at will. The thinking here is not that different from the rationale behind any large enterprise's adoption of open source, in or outside China.</p><p>【中国】更喜欢不依赖于某些供应商、公司或国家的灵活的技术，它还可以有效地控制和塑造这些技术。这里的想法与国内外任何大型企业使用开源的基本理由没有太大区别。</p></blockquote><p>关键在于「能够随意控制和塑造它们」。这一点可以回到先前说的，中国政府害怕的「不可控」，能得出中国政府恐惧不可控的公有，即不归自己管的公有。</p><p>同样的观点可以在 Ośrodek Studiów Wschodnich（波兰东方研究中心）的 <a href="https://www.osw.waw.pl/en/publikacje/osw-commentary/2025-06-24/open-code-closed-system-role-open-source-chinas-technological">文章</a> 中看到：</p><blockquote><p>China's use of open-source is part of a broader effort to enhance security by gradually eliminating foreign source code over which Chinese users have no control.</p><p>中国使用开源是更广泛地加强安全努力的一部分，通过逐步消除中国用户无法控制的外国源代码。</p></blockquote><p>消除的也是「无法控制」的外国源代码。</p><p>我们认为的，以 GitHub 为中心的 —— 虽然难以切齿，但事实就是如此 —— 开源社区，是「别人」的公有，而非中国政府的公有。对中国政府来说，自然是不可控、危险的。</p><p>那么归中国政府管的开源，是什么样的呢？我们可以来看看 Gitee 呀。</p><p>2020 年 Gitee 成了国家级开源平台，并在 2022 年宣布所有开源仓库都必须先经过审核，才能上线。Gitee 官方称此举是迫于无奈。由此可以看出，不是 Gitee 自己想要这么做，而是有监管压力。更不用提中国互联网到处都有的实名制，Gitee 也有！种种迹象都能表明，政府在乎开源能不能被自己审查和追踪。</p><p>我也有过个还未得到证实的假象，即政府的行为背后可能并没有一个深思熟虑的统一逻辑。简单来说就是，政府的政府可能比我们想象的更简单粗暴。亦或者，GFW 的决策是碎片且官僚化的，实际上没有一个统治寡头在镇压公有制实践，反而是多个部门出于不同的动机造成的效果 —— 谁知道呢？我当不了公务员，这辈子都没有机会知道吧。</p><p><a id="我们来谈谈-ai-slop"></a></p><h4 id="我们来谈谈-ai-slop"><a class="markdownIt-Anchor" href="#我们来谈谈-ai-slop"></a> <a href="https://archestra.ai/blog/only-responsible-ai">《我们来谈谈 AI slop》</a></h4><p>如果没有听说过的话，<em>AI slop</em> 的意思是 AI 生产出来的垃圾内容。</p><p>去年十一月份底，<a href="http://Archestra.AI">Archestra.AI</a> 的团队为开源任务设置了奖金，希望吸引更多开发者参与。让我先介绍一下这家公司：这是一家总部位于伦敦的初创公司，其核心产品是开源的企业级 AI 代理安全网关平台，专注于 MCP 编排与安全防护。</p><p>接着我得说说当时的背景：AI 生成的低质量贡献大规模地淹没了 GitHub 上的开源项目。今年二月份 GitHub <a href="https://www.opensourceforu.com/2026/02/github-weighs-pull-request-kill-switch-as-ai-slop-floods-open-source/">承认</a> 了这一点，并考虑引入 Pull Request 开关，以允许维护者完全禁用 PR 或限制为仅信任的协作者可提交。不过很讽刺的是，GitHub 又同时在 <a href="https://github.blog/news-insights/octoverse/octoverse-a-new-developer-joins-github-every-second-as-ai-leads-typescript-to-1/?utm_source=web-k2k-octoverse-cta&amp;utm_medium=web&amp;utm_campaign=universe25">庆祝</a> AI 带来的「巨大贡献增长」，忽视了贡献质量的严重下降 —— 耸肩耸肩。</p><p>在此等背景下，<a href="http://Archestra.AI">Archestra.AI</a> 的赏金 issue 自然首当其冲（这个成语是「最先被伤害」的意思！），被 AI 机器人轰炸到 253 条讨论。这充斥着大量毫无意义的实施计划，真正的贡献者的对话被淹没其中。</p><p>同时，一个小小的 issue 会收到 27 个 PR，其中大部分提交者完全没有测试过自己的代码。因此，团队成员每周都要花时间去清理仓库中的 AI 垃圾内容。因为一旦疏于清理，仓库就会变得对真正的贡献者极不友好。</p><p>没办法，团队仅能逐步反击。他们首先是开发了名为 <em> London-Cat</em> 的声誉机器人，会根据已合并的 PR 等信号，来计算贡献者的声誉。接着他们构建了 <em> AI Sheriff</em>，来自动关闭可疑的 PR。不过误伤了合法 PR。最终他们只能选择要求贡献者先完成 onboarding 流程，才能创建 issue、提交 PR 或者评论。虽有效地阻止了 AI 机器人，但也给新的贡献者增加了门槛。</p><p><a href="http://Archestra.AI">Archestra.AI</a> 的案例可以反映出，传统的「任何人都可以贡献」的开源模式正在被 AI 垃圾侵蚀。文章的结尾提到，这是整个开源生态必须重新思考的事情。</p><p>这件事让我想起今年发生在 Linus Torvalds 身上的事儿，近乎一模一样。五月份中旬，Torvalds 在 Linux 7.1-rc4 的发布公告中声称，内核的私有安全邮件列表充斥着 AI 漏洞扫描器生成的大量重复、低质量的 bug 报告。这是因为多人运行着相同的自动化扫描工具，对同个代码库生成相同的发现，然后毫无协调地提交。</p><p>接着的下旬，他在 Linux 7.1-rc5 的公告中，进一步升级了态度，表示 AI 工具生成的非关键修复在发布周期晚期涌入，造成无意义的重复。</p><p>这也能看出，愈来愈多的一般人开始使用 AI 工具来为自己并不了解且不熟悉的领域提供「帮助」。会发生这种事情，还是因为 AI 工具让「知道」和「理解」之间的鸿沟很危险地变得不再可见。</p><p>过去的人们如果不懂开发，是无法提交 PR 的，因为他写不出代码。现在有 AI 替他写了代码，他就会觉得自己有所「贡献」—— 这儿有个我过去提及到的 <a href="/posts/31df.html#ai-%E5%AF%B9%E8%BF%99%E6%AE%B5%E4%BB%A3%E7%A0%81%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E6%9C%89%E9%9D%9E%E5%B8%B8%E6%B7%B1%E5%88%BB%E7%9A%84%E7%90%86%E8%A7%A3">案例</a>。</p><p>我在这里引用段 Torvalds 在 Linux 7.1-rc4 发布公告中写的文字：</p><blockquote><p>If you actually want to add value, read the documentation, create a patch too, and add some real value on <em>top</em> of what the AI did. Don't be the drive-by "send a random report with no real understanding" kind of person. Ok?</p><p>如果你真的想创造价值，请阅读文档，顺便创建一个补丁，在 AI 所做工作的基础 <span class="emphasis">之上</span> 增加一些真正的价值。不要做那种「路过凑热闹、随便发个报告却没有任何真正理解」的人。好吗？</p></blockquote><p>传统学习中，有三层认知：「知道」、「理解」，还有「负责」。</p><p>「知道」需要人类自主学习，且门槛是很高的。现在虽然可以让 AI 工具瞬间提供，但会让我们产生「我懂了」的错觉。这一点，和观看大量短视频科普公众号一样。</p><p>而「理解」也需要深度投入，与「知道」会同步成长。但在 AI 工具提供的答案下，它和「知道」完全脱了钩，因为我们以为自己理解了，实则没有。</p><p>最后的「负责」会随着我们的学习和实践，自然形成。我们会维护自己写的代码，为此负责。但是对于既不「知道」，也不「理解」的人而言，「负责」更不可能存在，导致 Torvalds 描述的「drive-by 贡献」泛滥。</p><p>这三层本应该是同步递进的，因为我不可能写出一个内核补丁，但不理解它吧？在 AI 工具普及的现在，第一层「知道」虽然被拉平，但是第二层和第三层就完全没能跟上。</p><p><a id="humpty-dumpty-遇见了税法"></a></p><h4 id="humpty-dumpty-遇见了税法"><a class="markdownIt-Anchor" href="#humpty-dumpty-遇见了税法"></a> <a href="https://www.journalofaccountancy.com/podcast/tax-law-irs-code-definitions/">《Humpty Dumpty 遇见了税法》</a></h4><p>我这个月开始学习税法相关的知识，具体怎么学呢，就是找 Enrolled Agent 的教学视频看。</p><p>有关 Medicaid 和 Medicare 的豁免收入一集中，教学老师提到了 <em> Feigh v. Commssioner</em> 案，引起了我的兴趣。引用的网页是当时老师提到的，他最喜欢的一位教授讲解该案的播客。网页很贴心地添加了文字版。</p><p>首先 IRS 发布的 Notice 2014-7 规定过 Medicaid 豁免项目的护理补偿收入可以从应税收入中排除。</p><p>纳税人 Mary K. Feigh 照顾着自己已成年的残疾子女，其和丈夫的唯一收入就来自于一项州 Medicaid 家庭和社区服务豁免项目的工资性补偿收入。</p><p>他们报税时干了这两件事儿：一是先申报了这笔豁免收入，然后依据 Notice 2014-7 将其排除；二是又用这笔已被排除的收入来计算 <u>劳动所得税抵免</u>（EITC）和 <u>额外子女税收抵免</u>（ACTC）。</p><p>IRS 在审计中否决了这两项抵免，理由是既然这笔收入已经从总收入中排除了，那就等同于没有收入，怎么可能还有资格拿需要劳动收入才能享受的抵免。</p><p>并且 IRS 提出，国会没有任何条款表明意图给予纳税人双重福利。如果国会真的想给，那它就会明确说出来。现在国会没有在 Medicaid 豁免收入上明示双重福利，就意味着国会没有这个意图。</p><p>到这里我得插句话，澄清一个概念：IRS 是执行机构，真正立法（IRC）的是国会。IRS 发布的那些 Notice 等等都是 <u>次级法规指导</u>（subregulatory guidance），是一种「指导」。而让另一个部门写指导也意味着，这些指导上的内容是完全根据该部门对法律的了解，才写出来的，并不能等同于法律的真实意图。</p><p>作为证据，IRS 抛出了 IRC §32 (c)(2)(A)(i)，也就是国会立的法：</p><blockquote><p>(c) Definitions and special rules</p><p>For purposes of this section-</p><p>(2) Earned income</p><p>(A) The term "earned income" means-</p><p>(i) wages, salaries, tips, and other employee compensation, but only if such amounts are includible in gross income for the taxable year, plus</p><p>(c）定义和特别规则</p><p>就本节而言 -</p><p>(2）劳动所得</p><p>(A)「劳动所得」一词是指 -</p><p>(i）工资、薪金、小费及其他雇员报酬，但仅限于此类金额应计入本纳税年度总所得的部分，加上</p></blockquote><p>IRS 的解释是，因为钱已经被排除，因此它不再是 <em> includible in gross income</em>（应计入总所得）的收入，所以也不满足对劳动所得的定义。</p><p>法官则认为，该法条说的 <em> includible</em>（应计入）指的是收入的法定性质，即「是否本应计入」，而不是 <em> included</em> 的「是否实际被计入」。</p><p>「可以这么做」和「已经这么做了」，两者之间差距可是很大的。这笔 Medicaid 豁免工资本应计入总收入，因为它在法律上是「可以被计入」的。</p><p>就算它被排除了，也只是让其在事实上未被计入，但在法律上依然可以被计入。</p><p>至于双重福利一事，法院表示这完全是 IRS 自己搞出来的。</p><p>如果没有 IRS 的 Notice 2014-7 的话，国会的设计便是「所有的收入都要计入总收入、缴税」，因此 Medicaid 豁免工资也应计入总收入且缴税。</p><p>但在 IRS 的 Notice 2014-7 中，它可以被视为 §131 的寄养支付，并从总收入中排除。所以双重福利是因为该 Notice 才产生的，和国会原本有没有意图让纳税人获取双重福利无关。</p><p>最终，法院判决 Feigh 一家能拿 EITC。</p><p>文章标题的 <em> Humpty Dumpty</em> 是一首著名童谣里的主角：</p><blockquote><p>Humpty Dumpty sat on a wall,<br>Humpty Dumpty had a great fall.<br>All the king's horses and all the king's men<br>couldn't put Humpty together again.</p><p>矮胖墩儿，坐墙头，<br>栽了一个大跟斗。<br>国王呀，齐兵马，<br>破蛋难圆没办法。</p></blockquote><p>不知道咋翻译童谣，所以直接搬运了网络上的 <a href="https://www.sohu.com/a/319340439_653797">翻译</a>。</p><p>这个所谓的 <em> Humpty Dumpty</em>，就是个蛋人。此童谣的知名程度相当于中国的「拔萝卜」。而我因为小时候没少照顾过婴儿，所以也没少听过这首歌 —— 最常听的依然是 Pink Fox 的……<em>Baby Shark</em>。堪称噩梦。</p><p>在 <em> Through the Looking-Glass</em>，或者说大家更熟知的译名《爱丽丝镜中奇遇记》里，这个蛋就出现了。它和童谣里说的一样，坐在墙上，喜欢自以为是地给人讲解词语的意思。最为著名的一段对话是：</p><blockquote><p>"When I use a word," Humpty Dumpty said, in rather a scornful tone, "it means just what I choose it to mean—neither more nor less."</p><p>「当我用一个词的时候，」Humpty Dumpty 用一种相当轻蔑的语气说，「它的意思就是我选择让它表达的意思 —— 不多也不少。」</p></blockquote><p>Feigh 案中的 IRS 所做的事儿和 Humpty Dumpty 一样。IRS 想要将 <em> includible</em> 解释成 <em> included</em>。但词语有它自己的含义，并不是你想怎么解释，就怎么解释的。既然法条说的是 <em> includible</em>，那么那就是 <em> includible</em> —— 不多也不少。</p><h2 id="远方"><a class="markdownIt-Anchor" href="#远方"></a> 远方</h2><p><a id="bricks-minifigs-和-reckless-ben-争议事件"></a></p><h4 id="bricks-minifigs-和-reckless-ben-争议事件"><a class="markdownIt-Anchor" href="#bricks-minifigs-和-reckless-ben-争议事件"></a> Bricks &amp; Minifigs 和 Reckless Ben 争议事件</h4><p>2023 年，80 多岁的 Ed Mansell 找到了一家 Bricks &amp; Minifigs 加盟店，打算将自己收藏多年的《星球大战》乐高套装寄卖于此。该藏品的估价远超 20 万美元，很是昂贵。根据寄卖协议，Mansell 在售出前保留全部的所有权。</p><p>2024 年年底，加盟店的经营者 Gorman 夫妇决定解散业务，因为店铺已经资不抵债了。在他们清点存放在店里的乐高套装时，Bricks &amp; Minifigs 总部派来新的经营者 Brandon Best 和 Joshua Johnson，直接将夫妇二人赶出店面。</p><p>Ed Mansell 的儿子 Bryan Mansell 到店里取放置寄卖的乐高套装，但两个新经营者都声称不知道这件事，让他自己去找 Gorman 夫妇。警察也不愿意介入此事，认为这是普普通通的民事纠纷。</p><p>不算富裕的 Bryan Mansell 只好找到网红 Reckless Ben，希望对方能帮自己打官司、拿回被新经营者扣留的乐高套装。</p><p>这个 <em> Reckless Ben</em> 就是个网名，人家本名是 Benjamin Paul Schneider，以制作喜剧性调查纪录片闻名，专门调查争议组织、企业、网络红人和疑似骗局。</p><p>之前就有做过类似事情的 Schneider，自然是答应下来，开始私下调查、搜查证据。</p><p>2025 年的年底，Schneider 找到总部讨要说法，却被对方咬一口说是擅闯公司和扰乱秩序。气得 Schneider 成立了家讽刺性竞争企业 <a href="https://westealfromoldpeople.com/"><em>We Steal From Old People</em></a>。</p><p>无果，Schneider 派演员伪装成 UPS 快递员到新经营者之一 Johnson 的家里送法律文件。不愿意见 Schneider 的 Johnson 报警。警察以跟踪、擅闯、定向住宅抗议等罪名逮捕了 Schneider。第二天，警察持搜查令搜查 Schneider 下榻的 Airbnb 以搜寻被盗的乐高套装，然后逮捕了他的其他同伴。之后同伴都被释放。</p><p>今年 5 月份，Schneider 发布了纪录片系列的第一部 <em> I tracked down the thief who stole $200,000 of LEGO</em>，引起多位知名创作者的关注。网民们开始一一猜测这些事情的蹊跷之处，并得出阴谋论：新经营者和涉事警察都是摩门教徒，Johnson 的父亲在本地的教会还身任高职，恐是警察与公司已经有了勾结。但这些指控尚未得到裁定。</p><p>阴谋论一出，公司的 CEO Ammon McNeff 出面声称总部并未参与该寄卖协议，责任在直接的当事人。次日，公司向 Schneider 和 Mansell 等人提起 <u>反诈骗腐败组织集团犯罪法</u> 民事诉讼，指控他们协调骚扰和敲诈勒索。但 Schneider 的行为，真的是有组织的犯罪吗？</p><p>6 月 3 日，Patreon 的 CEO Jack Conte 公开拒绝 Bricks &amp; Minifigs 要求下架 Schneider 的账号的法律通知。</p><p>Reddit 上的用户发现，American Fork 警察局意外公开了未删减的执法记录仪和行车记录仪录像。网友存档后发现与官方报告存在矛盾。警方稍后删除了这些文件。这又进一步坐实了公众对警方不透明的质疑。</p><p>6 日，Bricks &amp; Minifigs 表示将向 Mansell 家族偿还，并关闭涉事门店。</p><p>10 日，犹他法院对 Schneider 下达禁言令，禁止他继续公开谈论 Bricks &amp; Minifigs。</p><p>26 日，Schneider 与 Bricks &amp; Minifigs 同意调解以避免公开审判。禁言令被提议放宽，允许他继续发视频、调查并发布法庭程序，但仍禁止威胁、跟踪、靠近 Bricks &amp; Minifigs 门店 100 码以内等行为。</p><p>整个事件很是复杂，现在依然还未得出过结果。</p><p><a id="toadking-v-yeah-jaron-wahhfff-2026"></a></p><h4 id="toadking-v-yeah_jaron-wahhfff-2026"><a class="markdownIt-Anchor" href="#toadking-v-yeah_jaron-wahhfff-2026"></a> <a href="https://www.democracycraft.net/threads/toadking-v-yeah_jaron-wahhfff-2026-dcr-30.35968/">《ToadKing v. Yeah_Jaron &amp; Wahhfff [2026]》</a></h4><p>这是在今年三月份看到的案子。不过，它并非正常的案子，因为它发生在 Minecraft 服务器内，而非我们所在的现实世界。</p><p>首先先介绍一下 DemocracyCraft 这个服务器。它是一个 Minecraft 城市角色扮演服务器，核心理念是让玩家创建、修改和废除管理自己的规则和法律。服务器的内容和玩法相当拟真，比方说它的政府仿照了现实中美国的三权分立，由 <u>立法</u>、<u>行政</u>，以及 <u>司法</u> 组成。这意味着该服务器的政府，有着真实的国会、总统、内阁、法院系统，且承担职责的都是真实的玩家。</p><p>服务器的经济系统也想方设法地超现实靠近：新玩家会获得启动资金，这笔钱也要从政府的预算内拨出来。自行赚钱可以是去公司上班、出售材料、创业、房地产投资等等。这些事情的前提也往往是得先上完大学。值得庆幸的是，服务器内的大学和我们现实中的大学不一样，出来找工作要容易许多。</p><p>有趣的是，该服务器在 <span class="emphasis">不好</span> 的地方，也和现实世界很像。我是从 <a href="https://invidious.nerdvpn.de/channel/UCX_OYNnlNv3vQWiER4b0f5w">Yeah_Jaron</a> 这个 YouTube 频道主那儿知道的这个服务器，引用的链接也是他被上诉的案件，我们之后再说。因为是个相当有名的频道主，所以当他出现在任何一个服务器内，都有很大的概率被人盯上，并被恶意攻击。尽管 DemocracyCraft 是个明面上看来相当文明的服务器，但他和朋友 Wahhfff 依然时不时会被恶意谋杀和拆家。结果不仅服务器内的警察对此不理不睬，甚至有个上门来杀他的玩家还是服务器内的法官。游玩期间，他们也遇到了司法人员要求行贿的事情。可以说，整个服务器确确实实是现实世界的微型模拟。</p><p>一天，Yeah_Jaron 和 Wahhfff 在岸边钓鱼，并发现有人从身后丢东西给他。因为先前被暗中谋杀过多次，好不容易搞来了米尼岗机枪的他们，决定去吓唬身后的人。他们在栅栏上发现了变小的 ToadKing，并从快捷栏中调出了机枪，以吓吓他。双方的对话很快就结束了，还算「友善」，总之 Yeah_Jaron 和 Wahhfff 继续跑回去钓鱼。</p><p>在之后的游戏里，Yeah_Jaron 发现自己被 ToadKing 上诉，即引用的链接里的内容。我觉得很有意思，因为可以从中学习到简化的法律知识和执行流程。</p><p>该民事诉讼被发给 Redmont 联邦地方法院。作为原告，ToadKing 表示 Yeah_Jaron 和 Wahhfff 将米尼岗机枪直接对准了自己，持续约一分钟，因此指控二人袭击、扰乱治安、非法持有枪支。</p><p>DemocracyCraft 真实到，你可以从案件中找到被引用的法典。ToadKing 在「袭击」一事上，便引用了刑法典（当然是服务器的刑法典）的第四部分第 1 条：</p><blockquote><p>1 - 人身攻击<br>罪行类型：简易程序罪行<br>处罚：1 罚款单位；监禁 5 分钟<br>任何人若有以下行为即构成犯罪：<br>(a）故意击打另一名玩家，导致其损失不超过 3 颗心；或<br>(b）使另一名玩家处于危险境地，包括但不限于用武器指着他们。</p></blockquote><p>重点在于（b）的「将武器对准另一人，即构成将他人置于危险之中」。</p><p>然后 ToadKing 强调，民法典第二部分第 6 (1)(b）条：</p><blockquote><p>认定民事侵权不需要刑事犯罪定罪；但是，刑事定罪可用作民书诉讼中的证据。</p></blockquote><p>这句话被强调的理由，是因为 ToadKing 的三项指控都是刑法典中定义的罪名，而非民法典中定义的民事侵权。为什么这种事情会很重要呢？在现实中的法律逻辑，刑事和民事是两套独立的法律程序，证明标准不同：刑事需要排除合理的怀疑，但民事只需要优势的证据。</p><p>再一步进行拆解的话，刑法定义了什么行为是犯罪，其后果是坐牢或者罚款给国家，而民法定义了什么行为构成对个人的侵权，后果是赔钱给受害者。原告 ToadKing 想要的是钱，并非让被告们坐牢，因此走了民事途径。但三项指控都不被定义在民法典内，那么没有人被刑事定罪的话，民事法庭能否直接认定它构成民事侵权？</p><p>这类模糊地带会有两种解读：一、必须先有刑事定罪，所以原告得先找检察官刑事起诉、等待定罪，再来民事索赔；二、不需要刑事定罪，民事法庭可以独立审查事实，自行判断行为是否构成侵权。</p><p>往往被告都会主张解读一，因为刑事的起诉门槛更高、证明标准更高，且一旦刑事不定罪，那么民事就无法继续下去。</p><p>为了防止这种事情发生，原告引用了民法典的第二部分第 6 (1)(b）条，表示「刑事定罪不是确立民事侵权的前提条件」，明确排除了解读一。</p><p>第二个指控是「扰乱治安」。ToadKing 引用了刑法典的第五部分第 1 条：</p><blockquote><p>1 - 扰乱公共秩序<br>罪行类型：公诉罪行<br>处罚：最高 100 罚款单位；最高 60 分钟监禁<br>任何人若有以下行为即构成犯罪：<br>(a）对个人或群体实施骚乱行为，导致或可能导致骚扰、惊恐或痛苦。<br>相关法律：</p></blockquote><p>有趣的细节是，ToadKing 的体形在游戏很小很小，还没有那把机枪大，且仅有 4 颗心。作为一个「坐着、体形较小」的玩家，他认为 Yeah_Jaron 和 Wahhfff 的行为是针对性、持续性、协调性的无序行为。再加上当时还是在公共环境内，这么做无疑是将任何在场的人都陷入了危险当中。</p><p>第三个指控是「非法持有枪支」。ToadKing 引用了刑法典的第四部分第 9 条：</p><blockquote><p>9 - 非法持有枪支<br>罪行类型：简易程序罪行<br>处罚：10 罚款单位；10 分钟监禁；没收无证枪支<br>任何人若有以下行为即构成犯罪：<br>(a）在未持有有效枪支许可证的情况下持有枪支。<br>相关法律：国会法案 - 枪支许可法</p></blockquote><p>这一条很好理解，你得先有枪支许可证，才能持有枪支。</p><p>接着，ToadKing 主张被告们的行为构成了民法典内的 <span class="emphasis">恶劣行为</span>：「表现出实质性偏离公认行为标准，并反映出对他人权利、利益或安全的蓄意、欺诈、压迫、鲁莽或重大过失的漠视。」</p><p>这里有个特别有意思的事儿：ToadKing 引用了去年他上诉另一个人的案子。当时的案件内容是，被告 Culls 踩在了 ToadKing 身上，让 ToadKing 感到恐慌、羞辱和痛苦。这个案子里的对话，也非常地有趣：比方说有教皇要公开意见、Anthony_Org（一个喜欢被踩踏的…… 议员？）用踩葡萄作为例子反对 ToadKing 说的「被踩踏因此被羞辱」、ToadKing 又反过来控诉说自己是个活人而非葡萄、法官 Muggy21 判 Anthony_Org 作伪证且处以罚款、ToadKing 列出超长的证据控诉 Muggy21 违反程序、Culls 的辩护律师 ElysiaCrynn 和 ToadKing 有来有回地互相答辩…… 天啊，ToadKing 甚至创建了一个 <a href="https://culls.me/">网页</a>，以羞辱 Culls！其中的小游戏，为什么是 ElysiaCrynn 拿到了第二名！</p><p>接下来便是被告们的答辩。Yeah_Jaron 和 Wahhfff 请来了律师 CaptAndrewMahn 为自己辩护：</p><p>一、根据事件录像能够主张，被告可能是滚动物品栏时巧合地切出了武器，且原告主动提及到了武器相关的话题，作为对话中的自然延续，被告才再次拿出枪。再加上在 Minecraft 里，手持武器面对他人一定会看上去像是在瞄准，所以无法证明被告的行为是恶劣的。</p><p>二、原告向被告扔了名为 <em> Eat Me</em> 的物品，被 Yeah_Jaron 认为是毒品，后面就给丢掉了，因此原告的行为具有挑衅性。再加上之前二人都见过 ToadKing，认为他的反复出现很可疑，因此不得不提高警惕。事实也证明，几分钟后 ToadKing 就向另一个玩家的方向发射了爆炸性武器。</p><p>三、被告有「军械师」职业，而教育部允许军械师考试无需枪支许可证，因此被告自然而然可以认为政府允许他们持有枪支。这属于监管误解，而非蓄意违法。</p><p>ToadKing 提出了以下异议：事件发生后的事情不能追溯证明被告之前行为的合理性，因此他发射爆炸性武器的事情和本案无关；毒品的管理法在案件发生的三天后才被总统签署、成为法律，因此案发当天，毒品完全合法，不能用事后立法来定性原告的行为 —— 这也是 <u>不溯及既往原则</u>。</p><p>CaptAndrewMahn 则反驳道，在民事案件中，不溯及既往原则并不适用。当时的问题在于，毒品是否具有可疑性，以至于被告们可以合理地走向原告？</p><p>之后他们有了游戏内庭审 —— 对，在游戏内上庭。我没有观看完整的记录，如果记录属实存在的话，不过还是可以从纸面记录中看到些搞笑的事情，例如法官要求传唤当时「在场」的 NPC——NPC 怎么可能自行走过来呢？因此「没有给出回应」的 NPC 被判蔑视法庭，之后以不明方式「来」到了法庭，然后一言不发……Yeah_Jaron 想要整点好玩的，因此问 NPC 是否害怕 ToadKing，如果害怕的话就不要说话。</p><p>根据 Yeah_Jaron 上传的游玩视频，庭审期间他的辩护律师变成了一个在现实生活中就做过律师的 MJL。视频的结尾，他决定爆破法庭，从这个腐败的服务器逃离…… 毕竟，他是个 YouTube 频道主，只是进来玩玩而已。新上任的法官 aubunny 要求中止诉讼，直到被告有空为止 —— 这是今年三月份的事情，而案件最终在五月份，以「作为原告的 ToadKing 因不明缘由被驱逐出境」而告终。毕竟被驱逐的玩家是不能参与法院诉讼的。</p><p>这些纸面记录看下来，能感受到 DemocracyCraft 作为一个 Minecraft 服务器，其法律系统的精细程度令人惊叹！我们可以从中看到许多与现实法律高度对应的机制，如「程序性争议先于实体性争议」、「民事与刑事的分离」、大量的证据攻防、法律解释的互相对抗等等等。</p><p><a id="如果导致初级员工招聘疲软的原因不是人工智能-而是远程办公呢"></a></p><h4 id="如果导致初级员工招聘疲软的原因不是人工智能而是远程办公呢"><a class="markdownIt-Anchor" href="#如果导致初级员工招聘疲软的原因不是人工智能而是远程办公呢"></a> <a href="https://www.irishtimes.com/business/work/2026/05/31/what-if-remote-working-not-ai-is-to-blame-for-weak-junior-hiring/">《如果导致初级员工招聘疲软的原因不是人工智能，而是远程办公呢？》</a></h4><p>文章的核心观点是，远程办公才是初级岗位招聘萎缩的真正主因。</p><p>现在的人们其实不怎么谈起六年前的疫情了。但疫情带给我们的影响，实际上不可估量也说不定。</p><p>文章的内容基于 <em> The Broken Ladder: AI, Remote Work, and Early-Career Hiring</em> 这篇 <a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=6787638">论文</a>。论文指出，AI 暴露度与远程办公比例高度重叠，而受 AI 影响最大的岗位，如软件开发，恰好也是最可能远程办公的岗位。</p><p>不过给出的证据，仅是统计的相关性，无法完全确立因果关系。并且这也没法证明 AI 未来对初级岗位就没有威胁了。</p><p>我和一位行业内的朋友聊起过 AI 浪潮对企业们的影响，结果得知他所在的公司，去年已表明要 all in AI，并开始大肆招高级 AI 工程师。他想要问校招或者实习岗位的事情，都问不出什么 —— 今年大抵是要直接放弃实习和初级岗位。</p><p>就现在来看，初级岗位无论是受远程办公的影响大，还是受 AI 浪潮的影响大，都在无法阻止地变少……</p><p><a id="sam-altman-表示对大多数人来说-大学的效果将不再理想"></a></p><h4 id="sam-altman-表示对大多数人来说大学的效果将不再理想"><a class="markdownIt-Anchor" href="#sam-altman-表示对大多数人来说大学的效果将不再理想"></a> <a href="https://fortune.com/2025/07/24/sam-altman-college-not-working-great-stanford-dropout/">《Sam Altman 表示对大多数人来说，大学的效果将不再理想》</a></h4><p>Sam Harris Altman，现在 OpenAI 的 CEO，2005 年 Stanford 的辍学生，在一期播客内表示他的孩子大概率不会上大学。理由是，大学对大多数人来说可能不太管用了。</p><p>他十年前的观点，我是很认同的：</p><blockquote><p>young people shouldn't go to college without dedicating themselves to worthwhile projects and connecting with ambitious people.</p><p>年轻人不应该在没有投身于有价值的项目和结交有抱负的人的情况下就去上大学。</p></blockquote><p>以及，</p><blockquote><p>Most people think about risk the wrong way—for example, staying in college seems like a non-risky path. However, getting nothing done for four of your most productive years is actually pretty risky.</p><p>大多数人对风险的看法是错误的 —— 例如，留在大学里似乎是一条没有风险的道路。然而，在你最具生产力的四年里一事无成，实际上是相当危险的。</p></blockquote><p>后面这段出自于他 2013 年的 <a href="https://blog.samaltman.com/advice-for-ambitious-19-year-olds">博客文章</a>。</p><p>事实上，在我看到这段文字后，我便立即在 Fediverse 发表了很主观的 <a href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT0PJRMF5K9ST1W041MY5C8N">赞同</a>。事实证明，我打算主动说英语的时候，往往是我想要爆粗口的时候。但我的怒气是向让我恨铁不成钢的人们爆发的。</p><p>上个月的月刊，我分享了 Airing 在大学期间写的 <a href="https://ursb.me/posts/2015-2016-essays/">随笔</a>。其中的第一篇里，就有谈到他对「在四年内一事无成的人」的看法，同是恨铁不成钢。</p><p>我的怒气都来源于我身边的朋友。他们总是在向我抱怨自己的前途一片灰暗。当我想要解决这个问题时，却又次次反驳我的建议：你为什么选这个专业？感兴趣。既然你感兴趣，怎么会什么作品都没有呢？那么想要赚钱离开家的话，不应该是早些去考虑这些事情吗？不该去考虑自己是否真的适合这个专业，以及这个专业真的赚钱吗？你真的适合大学吗？我知道我不适合，所以我不想再继续了，那你呢？什么？你说你舍不得三年的沉没成本？喔……</p><p>不过 Altman 在播客后面说的内容，我就无法双手双脚表示赞同了。</p><p>去年一月份开始，他就有说过自己的孩子永远都不会比 AI 更聪明 —— 这句话我就放着不谈了 —— 因此出生在 AI 工具诞生后的孩子们，会意识到这一点，并且完全不在意，反而会更擅长于使用 AI 工具。</p><p>比起孩子，他更担心父母，因为他们不像伴随着新技术长大的人们那样、很快地适应全新的社会。</p><p>很明显，他将 AI 工具放在中心，思考人类如何适应它，而非将人类放在中心，思考 AI 如何配合。</p><p>四月份我引用了 David Oks 的一篇 <a href="https://davidoks.blog/p/why-the-atm-didnt-kill-bank-teller">文章</a>，内容反驳了政界以及经济学界广泛流传的乐观论调，即「ATM 不会导致银行柜员失业」。Altman 同样说了类似的话：「AI 就像是计算器，是个新工具。」</p><p>事实上，计算器和 ATM 一样，都是替代手工操作，但没有改变其范式。但 AI 的潜力在于替换范式：我直接替你决定你要算什么、怎么算、算出来意味着什么，那你这个人别说是否还需要计算器了，需不需要计算都是个问题。</p><p>但我赞同教育系统得大变革一下。在 AI 工具来临前，人们的教育系统就有很多问题。现在 AI 工具开始普及到一般人，不变革就不行了。</p><p>介于 AI 能在几秒内检索任何知识，我们「知道什么」的边际价值趋近于零。但 AI 无法帮助我们判断什么值得知道、辨别什么是真的、提出别人没想到的问题……</p><p>首先得把标准化测试给干掉吧，这玩意儿实在是害人不浅。教育本就应该早让学生们学会去提问、解决问题，而不是刷那些破题、把自己变得符合拼图中缺失的形状。</p><p><a id="阻止大型科技公司诱导用户做出违背意愿的行为"></a></p><h4 id="阻止大型科技公司诱导用户做出违背意愿的行为"><a class="markdownIt-Anchor" href="#阻止大型科技公司诱导用户做出违背意愿的行为"></a> <a href="https://archive.ph/3HkyR">《阻止大型科技公司诱导用户做出违背意愿的行为》</a></h4><p>原文发表于 <em> The Economist</em> 上，但该平台需要付费订阅才能访问文章全文，所以我放的是他人存档的网页链接。</p><p>作者 Marie Potel-Saville 是个 <u>竞争法</u> 律师。因为这个「姓氏」的形式不太常见，我就去搜索了一下，得知这是个法语兼英语的复合姓氏：Potel 是法语，Saville 是英语。下面我会用 <em> Potel-Saville</em> 来称呼作者。至于为什么不用 <em> Marie</em>，只能说是我的 <a href="/glossary/#:~:text=%E5%9C%A8%E5%B7%B2%E7%BB%8F%E6%8F%90%E5%88%B0%E8%BF%87%E4%B8%80%E4%B8%AA%E4%BA%BA%E7%9A%84%E5%90%8D%E5%AD%97%E5%90%8E%EF%BC%8C%E6%88%91%E4%BC%9A%E7%94%A8%E4%BB%96%E7%9A%84%E5%A7%93%E6%B0%8F%E6%9D%A5%E7%A7%B0%E5%91%BC%E4%BB%96">习惯</a> 吧。</p><p>文章中，她提出了 <u>掠夺性设计</u>（predatory design）这一概念。</p><p>在说这个概念之前，让我们让时间线再往前拨 16 年 ——2010 年，用户体验（也就是 UX、User Experience）专家 Harry Brignull 提出了 <em> dark patterns</em>（暗黑模式）这一概念，用于描述互联网上让用户做出违背本意之举的伎俩。</p><p>例如文章中引用的 Amazon 一案：2023 年 Amazon 用精心设计的界面，诱导消费者去订阅他们并未选择，且难以轻易取消的 Prime 会员。</p><p>那有多难取消呢？</p><blockquote><p>The process……required users to navigate four pages, six clicks and 15 separate options before reaching the exit. By Amazon's own accounting, 35m consumers had been enrolled without meaningful consent over seven years.</p><p>这一过程（中）…… 用户需要浏览四个页面、点击六次并面对 15 个不同的选项才能最终退出。根据亚马逊自己的统计，在七年时间里，有 3500 万消费者在没有明确同意的情况下被注册了该服务。</p></blockquote><p>这还能叫产品服务消费者吗？这不是把消费者当 ATM 使吗？</p><p>用这个角度去思考的话，就会发现人们沉浸在社交平台、短视频平台、娱乐平台等等平台上，都是背后有人刻意安排的，并不能简单说是这个人「意志力差」。我们的认知偏差会导致我们做出可以预测且非理性的决定。其中读者朋友最常听到的就是这些娱乐方式会直接刺激我们大脑中的多巴胺神经元。文章中对成瘾性设计得出了进一步的结论：</p><blockquote><p>Dopamine neurons respond not to rewards received but to the uncertainty of whether a reward will arrive: the more unpredictable the outcome, the stronger the signal.</p><p>多巴胺神经元对已获得的奖励没有反应，而是对奖励是否会到来的不确定性产生反应：结果越不可预测，信号就越强烈。</p></blockquote><p>这就和赌博为什么会让人上瘾的原理很像了：我们会对不可预测的事情成瘾。</p><p>文章中给了个例子：Meta 这家公司刻意将产品设计得会让青少年们上瘾。孩子们越早接触这些产品和平台，其黏性也越强。因此，他们还会想方设法将准青少年们拉入这些平台，也就是 12、13 岁的孩子们。</p><p>结果就是，使用 Instagram、Facebook 等社交平台，成为了青少年们的强迫性活动：明知是负面、不该继续去做的事情，但又控制不住地在使用。就算使用了，又有什么正面的效果吗？没有。</p><p>这让我联想到之前想写到月刊内，但是忘记了的有关 CoComelon 的 <a href="https://www.newyorker.com/magazine/2024/06/17/cocomelon-children-television-youtube-netflix">报道</a>。中国读者朋友们可能不知道它，它是全球最大的儿童 YouTube 频道之一，有超过 1.8 亿个订阅。因为妹妹和在美国的亲戚小孩都比我小至少十岁，我先前没少带过他们，也就很可悲地…… 看过很多来自该频道的视频。当然，最摧残的还是 Pink Fox 的那首 <em> Baby Shark</em>……</p><p>该频道制作儿童向视频的方式，和 Meta 制作社交平台的方式一模一样：利用神经科学原理，系统性地剥削认知弱点来最大化用户的参与度。但 CoComelon 更恶劣的在于，它的用户是婴幼儿，是还在学习颜色、话都说不明白的小孩子，实在是太邪恶了！</p><p>说回掠夺性设计。Potel-Saville 作为竞争法律师，提出了我鲜少会去考虑的点，即大公司剥削了消费者的认知后，市场是否还存在？</p><p>市场经济要想有效运转，需要这四个前提：</p><ol><li>消费者能够看见，并且自由选择替代方案；</li><li>在未被扭曲的维度上进行比较；</li><li>形成反映真实利益的偏好；</li><li>能够自由切换。</li></ol><p>结果是，掠夺性设计逐一破坏了这四项。</p><p><a id="引用是如何毁掉科学的"></a></p><h4 id="引用是如何毁掉科学的"><a class="markdownIt-Anchor" href="#引用是如何毁掉科学的"></a> <a href="https://davidoks.blog/p/how-citations-ruined-science">《引用是如何毁掉科学的》</a></h4><p>印象中在 ChatGPT 问世的一年后，有许多科学论文被发现用 AI 生成，评审人员也使用 AI 审核，然后论文再偷偷加入隐藏的 prompt、让 AI 评审员给出正面的评价。</p><p>我这段时间一直在投简历，并发现招聘一事上和这件事非常相似：公司使用 ATS 系统或者 AI 评审员来看简历、丢简历，求职者也可以反过来在简历中塞关键词来讨好 ATS，或者白底白字写上 prompt，让 AI 评审员选中自己的简历。</p><p>实际上，我自己也在做 <a href="/posts/61e0.html#:~:text=%E6%88%91%E4%BA%8B%E5%85%88,%E8%A6%81%E6%B1%82%E3%80%82%E6%88%91">这样的事情</a>。</p><p>不过招聘跟写科学论文还是不同的。岗位少，简历多，公司想怎么筛选就怎么筛选。但科学研究为什么要让 AI 工具接手呢？</p><p>Oks 给出了答案：为了引用量。</p><p>这要从第二次世界大战后开始说起。科研规模急剧扩张，学术论文数量一直在增长，就没有停过。科学家们起初用期刊来解决「出版书籍的速度不够快」的问题。之后发现期刊太多了，到了六万多种，就做了个文摘期刊，相当于期刊的期刊，专门收录期刊文章的摘要。但之后他们又发现，文摘期刊也变多了。难道还得出个期刊的期刊的期刊？</p><p>法律领域有本书，叫作 <em> Shepard's Citations</em>，专门记录哪些新案件引用了哪些旧案件。这是因为美国采用了普通法，法官做出的每一个裁决都会成为未来类似案件的先例。</p><p>这也是为什么在美国的庭审上，你总能看到律师拿以前的裁决作为「证据」。这一点，在先前提到的 Minecraft 服务器事件中也能看到。</p><p>Eugene Garfield 借此，在 <em> Science</em> 上提出了用引文索引来解决科学界的信息爆炸。该方案的第一个版本叫作 <em> Science Citation Index</em>（科学引文索引）。</p><p>但是，糟糕的事情便出现了……Garfield 发现引文索引不仅可以是搜索工具，它还可以是一个 <span class="emphasis">排名</span> 工具。</p><p>Google 最初设计了 SEO 的排名机制，其中也有个类似的规则：当有其他链接索引了该链接，那么该链接的 SEO 权重会变高。</p><p>听上去是很顺直觉：因为你写得好，所以别人都来引用你。但我们站在 2026 年，能够马后炮地看清楚，它是可以被利用的。</p><p>接下来的事情和 SEO 发生的大差不差。引文变成了评判用的工具和指标，所有人都围绕着引文来优化自己的论文。接着引文又被用来对整个院系和大学进行排名和评估，大学又为此、根据其教职员工获得的引文次数来分配资金，进一步恶化了这个状况。</p><p>Oks 特意指出，中国大学曾实施过「发论文给奖金」的政策，而奖金的数额根据期刊的影响因子来定，也是非常极端的引用优化案例了。</p><p>那么这和最开始的 AI 垃圾有什么关联呢？已知大家处于个将指标作为目标的环境中，科学研究的动机已经被扭曲。为了在激烈的竞争中存活，科研人员找到了 AI 工具，作为他们效率最高的生产方式。它可以以极低的门槛去批量拼凑文本、生成符合格式要求的学术内容。</p><p><a id="异性之间有纯友谊吗"></a></p><h4 id="异性之间有纯友谊吗"><a class="markdownIt-Anchor" href="#异性之间有纯友谊吗"></a> <a href="https://blog.solazy.me/20260603/">《异性之间有纯友谊吗？》</a></h4><p>我和作者 Sol 有着同样的观点：异性之间是可以有纯友谊的。</p><p>Sol 在文章中提到：</p><blockquote><p>如果我们将人际交往仅仅停留在生理性别的层面上，未免太低估了人类心智的复杂性。</p></blockquote><p>既然这么说了，我就得把问题切成两半：一是为什么世人认为异性之间没有纯友谊，二再是异性之间可不可以有纯友谊？</p><p>这么说有点绕，但让我先开始讲前半段，读者朋友们就知道我在切啥了。</p><p>世人为什么普遍认为异性之间没有纯友谊？因果链条如下：</p><ol><li>男女之间普遍存在性吸引力。这建立于生物学或者进化论的基础上；</li><li>性吸引力是自发的、不可控的；</li><li>当性吸引力存在于一段关系中，它会持续地、隐性地塑造双方的行为和期待；</li><li>「纯友谊」的定义是关系中不存在超越友谊的动机、期待或张力；</li><li>性吸引力一旦存在，就会产生超越友谊的动机或期待，哪怕只是一方的；</li><li>人无法可靠地判断自己或对方是否完全没有性吸引力；</li><li>异性之间没有纯友谊。</li></ol><p>首先前提 1 就是个大问题：世界上确实存在着无性恋者、性少数人群、低性欲者、因审美而被吸引的人…… 这是个以多数人经验冒充真理的前提。可惜的是，该泛化非常成功，因为说话的人不需要考虑例外的或者在人口中占少数的人。这也便导致了，「男女之间有性吸引力」这句话听上去像是常识。</p><p>关于无性恋者，我在今年五月份的日记里有写到过：</p><ul><li><a href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR5R0SFZZD4M0TRR1SK3QTZ7">五月九日</a></li><li><a href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRCFBKY5XVM3N18TK9GD8NHW">五月十一日</a></li></ul><p>从中可以观测出我的看法。也分享出来给感兴趣但不了解无性恋者的读者朋友们吧。</p><p>从前提 1 进发到前提 2，逻辑是认为性吸引是「反应」，而非「选择」—— 你看到了一个人，吸引力要么产生，要么不产生，你无法通过意志力消除它。</p><p>不过我一直都很好奇，明明一般人都相信男女之间的性吸引力是不可控制的，但谈及到性少数人群，就觉得他们是闲得蛋疼、「选择」去成为性少数人群。性取向为女的男人们喜欢女人的理由，我就不能用了么？到底谁规定的我必须要去喜欢男性？反之亦然。</p><p>从前提 2 进发到前提 3 的逻辑是，性吸引不是一种可以搁置的静态事实，而是会持续干预关系的力量。</p><p>从前提 3 到 4，再到 5 的逻辑基于一般人对「纯友谊」的定义，即纯友谊等同于关系中没有任何超越友谊的动机、期待和张力。所以只要有一方有性吸引力，那么整段关系就不再是纯友谊。</p><p>最后的前提 6 是悲观的认识论：既然人们可能不承认，或者没有意识到自己的性吸引力，那么人们可能会自我欺骗。同理，对方有没有，你也不知道。你无法证明「完全没有」，所以无法证伪，相当于「有」—— 这种逻辑听上去真的很烦人啊。</p><p>确实会经常感到性吸引的人占了多数后，他们将自己的经验变成了全人类的经验，最终得出的结果就是如此：异性之间没有纯友谊。在他们的框架中，少数人永远都无法自证。</p><p>更讨厌的是，这句话又会强化「男女之间的本质关系是性或浪漫关系」这另一句话。天啊，我对于 <a href="/posts/1572.html">一般人认为的浪漫关系</a> 也发表过意见。</p><p>简单说了下这句话的底层逻辑后，我想再从一般人相信的框架中，去探讨这个问题。这也是 Sol 的论点的基底。</p><p>引用的文章中可以看出，Sol 承认性吸引力的存在，并相信：</p><blockquote><p>当一个人拥有足够丰富的精神世界和高度的自我约束时，纯粹的、跨越性别的友谊不过是顺理成章的自然结果。</p></blockquote><p>即「性吸引力是可以通过意志力和精神来压制住的，使之不影响关系的纯粹性」。</p><p>这对于顺异性恋者而言，是个实用、可操作的立场。在「性吸引等同于关系宿命」的破结论上，提供了另一个解放性的框架。</p><p>再站在多数人的框架内去思考这句话的合理性，我们实则会发现，人们一直都知道「有性吸引」不等同于「关系被性吸引主导」。打个比方，已知人对异性有性吸引，但并不会主动追求所有有性吸引的异性吧？对某人有着瞬间的好感，就一定会想去发展么？</p><p>不过在现在的大「性压抑」时代，想必定会有人反驳说确实有人对每个异性都有性吸引，并想要进一步发展吧。嗯…… 等等，「有人」？「有人」意味着不是所有人。意味着至少存在一部分人，性吸引会主导一切关系；但也暗示了另一部分人，情况会有所不同。那么「男女之间没有纯友谊」，就得变成「有些人的异性友谊中没有纯友谊」—— <a href="/posts/eac7.html#:~:text=%E6%8B%A5%E6%9C%89%E7%9C%9F%E6%AD%A3%E7%9A%84%E8%A7%82%E7%82%B9%EF%BC%8C%E8%80%8C%E4%B8%8D%E6%98%AF%E9%87%8D%E5%A4%8D%E7%9A%84%E3%80%81%E7%BB%A7%E6%89%BF%E6%9D%A5%E7%9A%84%EF%BC%8C%E8%80%8C%E6%98%AF%E7%BB%8F%E8%BF%87%E6%B7%B1%E6%80%9D%E7%86%9F%E8%99%91%E7%9A%84%E3%80%81%E6%80%9D%E8%80%83%E8%BF%87%E7%9A%84%E3%80%81%E6%A3%80%E9%AA%8C%E8%BF%87%E7%9A%84%E3%80%81%E7%9C%9F%E5%AE%9E%E7%BB%8F%E5%8E%86%E5%BE%97%E5%87%BA%E7%9A%84%E3%80%81%E7%9C%9F%E6%AD%A3%E7%9B%B8%E4%BF%A1%E4%B8%94%E8%83%BD%E5%A4%9F%E6%8D%8D%E5%8D%AB">又</a> 一个没人会反对的平庸命题，不过已经不再是原来他们想要说的那个东西了。</p><p>实际上，再去「修正」「假想敌」的反驳，都没有意义了，因为人际关系之间的关系，根本无法用简单的一句「男女之间没有纯友谊」来概括。</p><p><a id="城市鸟类由于交通噪音-起得更早了"></a></p><h4 id="城市鸟类由于交通噪音起得更早了"><a class="markdownIt-Anchor" href="#城市鸟类由于交通噪音起得更早了"></a> <a href="https://www.audubon.org/news/urban-birds-are-rising-earlier-because-traffic-noise">《城市鸟类由于交通噪音，起得更早了》</a></h4><p>2013 年，西班牙的 Universidad de Sevilla 的 Aida Arroyo 团队发表了一项研究，核心发现是交通噪音让城市鸟类更早开始鸣唱。即使是安静街道上的家麻雀，在遭遇突发噪音或者短暂的交通声时，也会更早醒来。这意味着，这类我们认为的「高度适应城市生活」的物种，对声音波动依然非常敏感。</p><p>研究报告内推测的原因是，鸟类可能为了在交通噪音掩盖了歌声之前完成鸣唱，以确保声学通讯不被遮蔽。</p><p>之后数年来，这一领域有了大量新发现。</p><p>例如今年五月份的 <a href="https://www.zmescience.com/feature-post/natural-sciences/animals/birds/birds-have-local-accents-and-city-lights-are-changing-how-they-sing/">这篇文章</a>，认为人工夜间照明对黎明合唱提前的影响，可能要比交通噪音更强。其中 2025 年的研究分析发现，最明亮的景观中，鸟类的声学活动平均延长了 50 分钟，而城市里的乌​<ruby>鸫<rt> dōng</rt></ruby> 要比半自然栖息地中的同类提前多达 5 个小时。</p><p>回到噪音方面。噪音污染造成的也并非短期影响。2022 年的 <a href="https://www.researchgate.net/publication/263574050_Experimental_evidence_for_an_impact_of_anthropogenic_noise_on_dawn_chorus_timing_in_urban_birds">研究</a> 中提到，即使噪音特别高的机场关闭后，鸟类也没有立即恢复正常的鸣唱节律。</p><p>那么这种适应对鸟类又有什么负面影响呢？答案是有的。根据这篇 <a href="www.nature.com/articles/s41598-025-88287-8">研究</a> 所说，树麻雀的联络叫声的峰值频率会升高、持续时间会缩短，而警报叫声的音符数量会增多、持续时间将延长。所以代价便是，消耗更多的能量、信号衰减更快、传播距离缩短，同时更长的警报鸣唱会让鸣唱者暴露于更高的被捕食风险中，也会降低接收者对警报的识别准确率。</p><p>再结合先前说到的人工夜间照明，城市的鸟类活得不成样子。</p><p>那对于我们人类来说，这又意味着什么呢？同为动物，我们底层的生理机制是相似、共通的。鸟类要承受这般代价，我们其实也是一样。噪音污染对我们的生活质量的影响，比我们想象中的还要深刻，具体可以看 <a href="https://www.bmj.com/content/391/bmj-2024-081193">BMJ 的综述</a>。具体后果包括但不限于：干扰睡眠、损害血管功能、损害认知发育、影响心理健康等等。而光污染也会延迟我们的生物钟、影响代谢、促发情感性症状和障碍。</p><p>我的建议是，让家中减少噪音源，并使用隔音窗帘等工具，隔绝外界传来的噪音。同时睡前减少屏幕的使用，在夜间仅使用暖色调夜灯，就连微弱的光源也最好都撤掉。白天时则充分接触自然光，强化昼夜节律的对比。</p><p>不过现在去看夜晚的城市，天甚至都不是深色，而是灰色。再去看远处各栋 24 小时从不关灯的办公楼…… 什么时候我才能在这里看到星星呢？</p><p><a id="在睡眠中学习是可能的-但我们应该这么做么"></a></p><h4 id="在睡眠中学习是可能的-但我们应该这么做么"><a class="markdownIt-Anchor" href="#在睡眠中学习是可能的-但我们应该这么做么"></a> <a href="https://www.newyorker.com/culture/annals-of-inquiry/its-possible-to-learn-in-our-sleep-should-we">《在睡眠中学习是可能的。但我们应该这么做么？》</a></h4><p>上个世纪有过睡眠学习的研究。当时的人们还未意识到被试者并未真的睡着了，就开始幻想在睡梦中学习…… 自然而然也被后来者发现了问题所在，导致睡眠学习这一领域停滞了数十年。</p><p>结果近年来发现，这并非伪科学，而是可以被科学验证的。</p><p>这就得先说说 <u>REM 睡眠</u>（Rapid Eye Movement，快速眼动），也是一个更生动的梦境会发生在的睡眠阶段。</p><p>早期的研究会失败的很大原因，便是当时对 REM 等睡眠阶段一无所知。研究者无法确认受试者处于哪个睡眠阶段，自然也就无法验证他们是否真正地睡着了。</p><p>但是现在的实验条件好上许多，已经可以确认人类确实在睡觉，而非看上去睡了、实则醒着。</p><p>读者朋友们平日应该会注意到，自己会做「意识到自己正在做梦」的梦。这种梦被称为 <u>清醒梦</u>（lucid dream），通常发生在 REM 阶段（并非所有 REM 梦都是清醒梦）。</p><p>2021 年的实验中发现，清醒梦者可以通过左右动眼球来回答实验人员的问题，从而成功地让实验人员们可以实时和被试者交流。</p><p>之后 2024 年有了场在梦中解题的实验。实验人员在参与者进入 REM 睡眠后，通过 <u>靶向记忆再激活</u>，使用音频来引导他们的大脑在梦中处理清醒时未能答出来的问题。梦中出现了谜题的参与者，醒后的解题率要大于梦里没有谜题的参与者。</p><p>不过实验人员们也发现，清醒梦者的解题率并没有比普通梦者的高，意味着 REM 阶段可能并不擅长 <u>创造性跳跃</u> —— 思维突然跨越常规逻辑、产生全新联结的瞬间。这和我常做的清醒梦一样：当我开始意识到自己在做梦时，反而什么都做不到了。因为思维更接近清醒时的逻辑模仿，反而抑制了自由联想。</p><p><a id="软件的-emacs-化"></a></p><h4 id="软件的-emacs-化"><a class="markdownIt-Anchor" href="#软件的-emacs-化"></a> <a href="https://sockpuppet.org/blog/2026/05/12/emacsification/">《软件的 Emacs 化》</a></h4><p>当前的 AI 工具，已经允许用户能以极低的时间成本，直接生成满足个人特定需求的软件。作者认为，软件开发现在正在进入高度个人化的新阶段，并将其概括为「Emacs 化」。就像 Emacs 用户习惯自行编写脚本来满足独特的需求，现在的开发者可以在 AI 的帮助下，为各种微小、具体的痛点制作原生的应用，而无需再忍受体验糟糕的通用软件。</p><p>不过这些个人软件，或者说 <code>.emacs</code> 里堆积的无数小脚本，都是只对创作者自己有用，然后会被大众遗忘。这一点和《大教堂与集市》中说得一样：如果软件离大众的需求太远，那么写得就算再好，也得不到黑客文化同僚的赞赏与与之匹配的声望。</p><p>作者所强调的，「产生软件的提示词以及解决问题的思路，比最终生成的源代码本身更具分享价值」这一观点，我印象里数年前 AI 工具刚开始普及时就有人提到过。当时还有个 GitHub 仓库，里面只有提示词，没有源代码，可惜现在记不起是哪个…… 我对此的看法是，仅分享提示词，要比分享源代码更难保证质量，所以不要这么做。</p><p><a id="这不仅仅是-x-更是-y"></a></p><h4 id="这不仅仅是-x更是-y"><a class="markdownIt-Anchor" href="#这不仅仅是-x更是-y"></a> <a href="https://mail.cyberneticforests.com/its-not-just-data-its-post-training/">《这不仅仅是 X，更是 Y》</a></h4><p>标题原文是 <em> It's Not Just X. It's Y</em>，是 AI 工具常用的语句之一。</p><p>可惜我忘了它在中文是怎么说的了。</p><p>在文章内使用这样的语句，或者破折号，或者其他人们 <span class="emphasis">认为</span> 的只有 AI 工具才能写出来的东西，就会被怀疑是否使用了 AI 工具来写文。</p><p>这一点我在今年 <a href="/posts/c089.html#%E6%88%91%E6%98%AF%E8%82%AF%E5%B0%BC%E4%BA%9A%E4%BA%BA%E6%88%91%E4%B8%8D%E5%83%8F-chatgpt-%E9%82%A3%E6%A0%B7%E5%86%99%E4%BD%9Cchatgpt-%E5%83%8F%E6%88%91%E4%B8%80%E6%A0%B7%E5%86%99%E4%BD%9C">一月份</a> 有过讨论。当时引用的文章作者是位肯尼亚人，因为写的英语不像是「人」写的，所以在互联网上被人质疑是用了 AI 写作。结果是，作者学习的英语就是那样，因果关系根本反了：并非他说话像 AI 工具，而是 AI 工具说话像他。</p><p>可惜，这种误会在未来会越来越常见，因为 AI 工具的普及率正在缓慢提升。人们会逐渐意识到 AI 工具写作的特点，并简单将其视为「没有人会那么说话」，然后将所有会那么说话的人视为异端。而为了不被视为异端，人们又得小心不去说像是 AI 工具会说的话，战战兢兢的。</p><p>本次的文章引用了英国的一 AI 评分系统测试。该系统会给更长的文章、更广的词汇范围和更复杂的句子结构打更高的分，但经过 <u>RLVR</u>（可验证奖励强化学习）后训练的模型，输出推理的时候就是会倾向于产生这样的文字。</p><p>这些指标非但没用，还错误地将与学术标准无关的指标视作打分标准，不在乎文章的内核，反倒是跟形式主义好上了。可怜的人们为了拿高分，又不得不去采用 AI 推理输出的形式特征、写出越来越像 AI 的文章，进一步去强化「形式优于内容」的倾向。</p><p><a id="有趣项目"></a></p><h4 id="有趣项目"><a class="markdownIt-Anchor" href="#有趣项目"></a> 有趣项目</h4><p><a id="称呼它们为-aigents"></a></p><h4 id="称呼它们为"><a class="markdownIt-Anchor" href="#称呼它们为"></a> <a href="https://www.autodidacts.io/aigents/">《称呼它们为 <em>aigents</em> 》</a></h4><p>作者觉得人们常用 <em> agents</em> 来概括 <em> AI agents</em> 很奇怪，因为这个词儿也能用来描述「特工」、「代理」啥的。所以他想出了个主意：<em>aigents</em>。</p><p>我会尝试去习惯一下这个叫法的。</p><p><a id="为什么每所学校的吉祥物都长得一样"></a></p><h4 id="为什么每所学校的吉祥物都长得一样"><a class="markdownIt-Anchor" href="#为什么每所学校的吉祥物都长得一样"></a> <a href="https://invidious.nerdvpn.de/watch?v=dRUvjBS9zNI">《为什么每所学校的吉祥物都长得一样？》</a></h4><p>这是一期 YouTube 上的视频。</p><p>我高中的吉祥物是个老鹰，也是美国学校里最常见的吉祥物之一。当时我在学生会内打工，就有穿过那套恶心的玩偶服，破破烂烂的根本不能正经穿。</p><p>除了老鹰，美国高中其他常见的吉祥物就是老虎、斗牛犬和美洲豹。它们占据了近三分之一的高中吉祥物，以及 15% 的大学吉祥物。剩余的不过是他们的各类变种，例如我大学使用熊狸作为吉祥物，但设计起来很像是灰色的老虎；隔壁纽约大学抛弃很特别的紫罗兰吉祥物，改用设计上和老虎还有美洲豹趋近的短尾猞猁 —— 这件事甚至被学生 <a href="https://nyunews.com/opinion/2022/10/19/nyu-should-change-its-mascot/">吐槽</a> 过很无聊。</p><p>除此之外，这些常见的吉祥物往往名字相同，外观也都一模一样，即肌肉发达、表情愤怒的复古卡通风格。</p><p>使用食肉哺乳动物是因为学校需要一个不会冒犯他人、凶猛又安全的形象。而在上世纪互联网还未出现的时候，学校设计 logo 不会去找品牌公司，反而会翻阅体育用品供应商的预制剪贴画活页夹，直接选择觉得不错的设计拿来用。又因为互联网尚未普及，人们根本不知道其他学校和自己用的是同个 logo。</p><p>那么这些预制剪贴画又是哪来的？追溯到源头，是加州一家名为 <em> Angeles Pacific Company</em> 的贴花公司。公司里一个名为 Arthur Evans 的男人，就是这些体育 logo 的父亲。</p><p>现在的学校们迎合过去的传统，从矢量素材网站购买相同设计的 logo，而设计 logo 的人也知道这种设计好卖，复制现有的公式产出一模一样的设计…… 那为什么没有人告这些学校呢？这算版权侵犯、抄袭吧！理由也很简单：这些高中学校太穷了，大学去告他们会显得自己没有格局，遭遇公关灾难 ——</p><p>—— 直到这个世纪初大学们终于意识到自己的周边不太好卖，开始向高中们发律师函。但公关危机还是个问题，于是他们与高中签订君子协议，允许其使用自己的商标 logo，但不能在全球范围内销售商品，且总收入必须低于特定的上限，授权费一年仅 1 美元。</p><h2 id="周遭"><a class="markdownIt-Anchor" href="#周遭"></a> 周遭</h2><p><a id="成为父亲会使你的大脑萎缩"></a></p><h4 id="成为父亲会使你的大脑萎缩"><a class="markdownIt-Anchor" href="#成为父亲会使你的大脑萎缩"></a> <a href="https://archive.is/7LHeN">《成为父亲会使你的大脑萎缩》</a></h4><p>这是 2022 年的一篇科学报道。我从 Hacker News 看到了这篇文章，并从 <em> The Economist</em> 的页面上发现他们有 <a href="https://www.economist.com/topics/summer-reads"><em>Summer reads</em></a>（夏季读物）这一专栏。虽然是 2022 年的文章，但作为 <em> Summer reads</em> 系列的一部分，也是非常适合现在的六月份呢 —— 不对，这篇文章为什么是十月份才发表的……？</p><p>总之 <em> The Economist</em> 上的文章能够让我稍微从 AI 浪潮相关的文章中喘口气儿，我的 Instapaper 不知不觉存储了大量和 AI 浪潮相关的文章，无论是正面还是负面的看法。我已经收集了足够对这方面事情的观点，实在是不想一遍又一遍地听、读、写同样的事情 —— 简单来说，我觉得无趣了。</p><p>会导致现在这个局面的问题，我猜测是出于我依赖着 Hacker News 作为我的信息流，而不是依赖于我的 RSS 订阅。Hacker News 上的链接虽是通过用户们层层投票，才会在首页上被我观察到，但是那些内容并不一定是我必须要阅读，并且感兴趣的吧？这么想着，我开始反省自己内心深处恐是还存在着尚未被挖出来的错失恐惧症。</p><p>先回到文章本身吧！</p><p>在说父亲之前，先说说文章引用的 2016 年的另一篇文章，其核心内容在于怀孕会对母亲的大脑产生影响。介于大脑并非越大越好，母亲们的大脑中减少了什么，也不是什么坏事。那篇文章认为，这会缩小神经元之间不常使用的连接，来让常用的连接更强。听上去像是身体明白了什么地方更需要「能量」，从而做出的调整。</p><p>因此，文章标题所说的「父亲的大脑也会萎缩」，并非什么糟糕的事情。</p><p>父亲们的大脑主要是在默认模式网络以及视觉处理区域这两处出现了变化，又或者说，更精简的优化：他们会更敏锐地识别出婴儿的需求和信号，对婴儿有着更强的亲子依恋，并减少对婴儿的敌意和挫败感。</p><p>不过母亲们的大脑出现变化，能解释成被激素驱动，那么不会怀孕的父亲们，大脑又是为什么、如何被影响到的？</p><p>我的推测是由环境驱使的。假设大脑的变化被环境决定，那么我们能否「人工」操纵父亲们的大脑变化？让一个男人从孩子刚出生时就照料他，最大化其大脑的变化，让男人更敏感地照料孩子，导致更多的大脑变化…… 循环 —— 这样的假说能否成立呢？</p><p>换言之，让一位父亲尽可能多地去亲身照料孩子，会让他越来越在乎孩子，因为大脑会逐渐适应照料行为，并让父亲对孩子有着更强的依恋。</p><p>我和妹妹的成长环境很不一样。我很小的时候父亲有亲手照顾过我，而妹妹还是婴儿时父亲近乎都不在家。后来我能明显地感受出来，父亲会更在乎我，而不是年纪更小的妹妹。</p><p><a id="711-全职店务员离职心得"></a></p><h4 id="711-全职店务员离职心得"><a class="markdownIt-Anchor" href="#711-全职店务员离职心得"></a> <a href="https://t-t.live/archives/7MagsYkt">《711 全职店务员离职心得》</a></h4><p>我联想到了今年三月份我写的，用来庆祝我从奶茶店那儿离职的 <a href="/posts/7ae3.html">文章</a>。干这种底层薪资的工作就是这样，每次离职都是最开心的。</p><p>不过那篇文章我没有详细讲奶茶店里究竟都要做什么，只是想到什么写什么，乱乱的。</p><p>我做的那家奶茶店里，大致的任务分为这五种：</p><ul><li>前台</li><li>做饮料</li><li>炸小吃</li><li>订货</li><li>做卫生</li></ul><p>虽说是有五种任务，但店里往往仅有两个店员，所以大家得搭配好、轮流着换任务做。例如来了一堆客人，就得有个人一直站在前台接单、叫号，另一个人不停去做吃的。</p><p>奶茶店也有早班和晚班。我两个都做过，也做过全天的。</p><p>早班得早上十点到店里煮珍珠。先开盖煮半个小时，再关盖闷半个小时。出国后用温水清洗半分钟，还得放到蜂蜜水里泡十五分钟，泡完才有最佳的口感。这期间也得煮茶、开油锅、检查昨天晚班的人做好卫生没有。通常来说奶茶店里主要是绿茶跟乌龙茶，我以前兼职的一家店还有四季春，不知道具体是个啥，我反正都不爱喝，别说了解了。</p><p>差不多下午五点左右的时候，店员们要清理一次做饮料的工作台：装果浆的容器，洗！装小料的容器，换！装粉的容器，擦！清理和补货过后，到下午六点多，早班人员就得去厨房洗油锅了。这油锅洗起来真是麻烦啊，会花个半小时左右。洗完把垃圾全部系好放大垃圾桶里，看今天收垃圾不：收的话就丢到门外去，不收就先放在店里。</p><p>再到七点，早班人员美美下班。</p><p>晚班的收尾要简单些。一家店每天的本钱是 200 美元，你要从收银台内取出这 200，剩下的就是今天赚来的。把赚来的钱整理好，在便签上写今天赚了多少现金、外卖平台赚了多少钱…… 老板时不时会比对点单机器里实际的现金交易额和晚班人员数出来的。要是少了，当天上班的都要罚钱补。我被罚过三四次，但我不觉得自己心算有啥问题。后来有同事跟我说，有时候纸币太新了，硬硬的会贴在别的纸币下面，给出去的时候就难以察觉。</p><p>闭店时间一到立马把茶倒掉、工作台和桌面和地板全部擦干净，再检查仪器都关了没，然后就能锁门走人了。</p><p>做全天往往是因为同事是新人，不会做早班也不会做晚班。这种最累人了，但我可以名正言顺把摇奶茶的活儿都交给他们做。哈哈哈哈！</p><p>说到摇奶茶，我也能分享下做法。这东西做起来很简单，网上教程想必也一大把。奶茶店最基础的装备是透明的三段式树脂雪克杯。做奶茶你会直线摇就行了，要是学调酒或者做很讲究的手摇柠檬茶，就得学其他的法子。但我不会其他法子，我那家店用自动摇机的，所以就不展开了。</p><p>拿百香果果茶做例子。你往雪克杯内倒入 1.5 oz 的百香果果浆，加想要加的果糖量，然后热绿茶倒到 250 ml 的线（我说的那种雪克杯身上往往都有刻度）、加冰一路加到 500 ml，闭盖开摇，摇完就可以喝了。</p><p>倒饮料出来也有点小技巧。比方说经典奶茶摇完有泡泡，你就不能开隔冰器倒，必须只能开杯盖倒，杯子里再装新冰。要是还有泡泡被倒出来，就拿着隔冰器轻轻在表面一挖，泡泡就挖走了。</p><p>我的薪资是一小时 16 美元。辞职之前老板还给我涨到了 17 美元，但我当时去意已决，没多久就离职走了。总计也就做了半年多吧，后来在一家面馆打工。不过因为夏天到了，店里都没客人，面馆老板把活交给长期做工的了；我肯定不能没钱赚的，这个月找了其他工作、努力过渡中。</p><p>说到薪资，那不得不提初三在一家中餐馆打的工。老板是我母亲的朋友，我过去兼职做收银、接电话、打包、油炸食物。中餐馆真不是人待的地方，尤其是那家店没有空调，大热天只有坏掉的风扇。后厨师傅们火一开，谁都热得神智不清。没事做的时候我就拿外卖盒给师傅们扇风。</p><p>当时我是假期每天都去上全天，上学的时候放学从四五点上到九点多，只有周日不用上，因为母亲要拉我去教堂听道。我的工资每个月就 500 块！</p><p>这 500 块还被我母亲以「赚钱了就得交房租」为名义，拿走了！</p><p>她还天天念叨着，让我多感恩感恩她朋友给我安排工作，然后骂我不准惦记着可乐喝 —— 朋友，那可是夏天啊，可乐和水一个价钱，我喝一罐怎么你了？</p><p>我做了半年多，遭不住，不做、跑了。跑的时候我刚上高一。那会儿天天上这个破班，累死累活，还没有钱拿；谁愿意做谁做，可乐也不能喝。</p><p>餐馆这地儿的压力随时都会变高，再加上苍蝇馆子，招来的人也不总见得是什么善茬。先前这餐馆招来个蹲过牢的，说话老烦了。他初中的闺女过来吃饭，他就当着我们面骂他闺女。有天晚上太忙了，客人在前台砸东西骂我，我一个小孩子哪儿遭得住，他倒是不吭声，等我走后竟对着老板骂我 —— 莫名其妙！第二天又凑过来笑着阴阳怪气我，我也不知道这么大个成年人了为啥这么热衷于跟小孩子较劲儿。</p><p>还有个喜欢针对我的，是店里招的送外卖的。他老爱说我除了英语外啥也不会。但你这家店会英语的就那寥寥几个人。我会英语，所以我接客人电话，不是很正常吗？你会英语你也来做呗。然后他跟后厨们坐在店后面做 side work（差不多就是杂活，比如去虾线、拔鸡毛啥的）的时候，又爱说我不会做 side work。哎！就这点工资什么都要我做！巴不得我同时会颠锅炒饭、开车送外卖。我那时候只是个上初中的小孩儿啊！虽然后来这些东西我都做过了……</p><p><a id="公共长椅的消失"></a></p><h4 id="公共长椅的消失"><a class="markdownIt-Anchor" href="#公共长椅的消失"></a> <a href="https://placesjournal.org/article/the-disappearance-of-the-public-bench/">《公共长椅的消失》</a></h4><p>作者 Gabrielle Bruney 用纽约市的许多著名地区，一路探讨公共长椅现在所拥有的问题。</p><p>我在高中时就有在一堂课上学习到「公共长椅逐渐被移除，且被设计得不舒服」一事，例如文章中提到的添加扶手来防止流浪汉在上面睡觉。</p><p>这篇文章里 Bruney 给出了更多的上下文和看法。</p><p>文章开头便是我天天会路过的 Moynihan 车站。内部除了楼上和角落较为隐蔽的地方，几乎是没有座位的。我每次路过，都能看到很多人带着包包或者行李箱，靠着柱子坐地上。</p><p>你都不用去这个车站，单是看看 Bruney 上传的图片，就能看到数十个人坐在地上等车。</p><p>接下来的 West 4 Street 站是个人流量挺大的站点，橙色线和蓝色线在此处交叉 —— 为了严谨我还是把它俩的正式名字搜出来说吧：<em>Sixth Avenue Line</em> 和 <em> Eighth Avenue Line</em> —— 我每次来这里都是转车来的，但出站也是个商业区。我鲜少去那里而已。</p><p>我想到数个月前有个老头在网上贴了个「活动」启事，让大家可以参加、跟他一起在这个区（忘了是 Washington Square 还是 Union Square，反正两个位置都很相近）抽烟。结果当天来了一大帮子人，热闹得很，警察都要过去维护秩序。</p><p>地铁站内的长椅是何时被拆除的，我从来都没有注意到过。看来我已经习惯了这片没有长椅的土地，每次出门就干站着。小时候刚来美国的时候，一天晚上跟母亲坐地铁回家，看到长椅空着，正想过去。哪曾想，后面挤来个胖子，直接跑过来坐在了空位置上。</p><p>再就是我很怕这些公共设施。母亲从小就跟我说，不要去摸这些东西，会有人在上面吐口水、抹鼻屎。这些东西虽然看不到，但坐地铁久了，地铁站多脏多恶心我还不知道吗。除了电梯里角落那挥之不去的尿臊味，还有一次我亲眼看到一个女人朝地上吐痰，然后用鞋子抹匀那滩口水…… 呕呕呕！总之，有长椅我也不愿意坐。</p><p>Grand Central 车站我去得少，不过在那儿也确实没怎么看到长椅。仅限站立的桌子也确实经常会看到。</p><p>Central Park 应是我见过长椅最多的地方了。Bruney 引出了上个世纪的一件丑闻：公园引入收费租椅，引发公众暴动，之后改成了免费公共长椅。这和付费厕所有些相似。为什么人们要为这种事情付钱？</p><p>Bronx 的地方我就不知道了，因为我不敢去那边。剩余的地方也是，我很少去，就算去也是去那儿办事情的，根本不会注意到周遭的人们有没有椅子坐。</p><p>公共空间没有了座位，意味着我们在外，很难不消费就能坐在哪儿。</p><p>印象里去年夏天，我从哪里看到了一篇独立网站文章，讲的就是这件事：城市里的公共区域越来越少，人们没有不花钱就能坐的地方。</p><p>再加上长椅这东西，并不是只有流浪汉在使用。腿脚不方便的人，出门都得坐一会儿休息休息。但长椅要么被移除，要么坐上去很难受，对于公民来说很不公平。况且，你移除长椅就以为能赶走流浪汉了么？他们早练就了倒地睡觉的本领。并且赶走他们，本就是很难办到的，他们数量如此之多，是他们自愿的么？</p><p>说到「自愿」，就想起去年在互联网上看到有人为了吹美国，竟厚颜无耻说出「美国流浪汉都是自愿流浪」这种话，实在是丑恶。</p><p>要不是 Bruney 不说，我都不知道 CityBench 项目。原来街道上时不时会看到的银色长椅，是该项目的产物。我学校附近的公交站就有一个。</p><p>文章中有这么一段：</p><blockquote><p>"Benches in and of themselves aren't enough to create……socially activated, democracy-producing belonging……We also need something called public culture, which has to do with people bumping into each other and creating ways of being together, and some sort of affective atmosphere."</p><p>「长椅本身不足以创造…… 具有社会活力、产生民主的归属感…… 我们还需要一种叫做公共文化的东西，它与人们偶然相遇、创造共处方式以及某种情感氛围有关。」</p><p>It might be true that benches can't create community, but they can support the interactions that do. They give the elderly the ability to navigate their neighborhoods, providing opportunities for cross-generational interaction.</p><p>长椅或许无法直接创造社区，但它们能为促成社区的互动提供支持。它们让老年人能够在社区里走动，为跨代互动提供了机会。</p></blockquote><p>这让我想起了中国经常被诟病的无障碍出行设计，例如没有逻辑的盲道…… 我曾经在互联网上看到有人感叹，他出国后才发现残障人士有这么多，但在国内近乎见不到这类人。接着有人回应道，那是因为残障人士在中国根本无法自行出门。</p><p>长椅和盲道，在促进社区的发展上也有帮助。就如 Bruney 所说的那样，可以让老人们多多出来走动。我曾经兼职打工的一家店，就时常服务老年人。他们有着我无法体会到的问题，像是和朋友出来聚餐，却找不到一家安静、友善对待他们的餐厅。他们也孤独，会拉着我说话，并分享他们的日常生活和过往 —— 可惜这家餐厅最终倒闭了。</p><p><a id="逃跑的男性与纵欲的女性"></a></p><h4 id="逃跑的男性与纵欲的女性"><a class="markdownIt-Anchor" href="#逃跑的男性与纵欲的女性"></a> <a href="https://www.sungyinieh.com/archives/escaping-men-and-indulgent-women">《逃跑的男性与纵欲的女性》</a></h4><p>更愿意表露脆弱、求助的男孩子，会因为主流文化的要求而更难被人们理解和支持。尤其是多所学校里，男生会被更严格地对待，甚至存在肢体暴力；这是因为，在父权传统中男性要更「坚强」，「需要」被打骂，甚至「可以」被暴力对待。随着社会的驯化，他们会很可悲地成为适应暴力和支配，并将其传递给更弱者的人。</p><p>为什么人们会有性别焦虑？其中一个说法是，社会限制了单一性别允许做和不允许做的事情。就比如说，男性不能和同性发展更细腻的亲密，否则就是同性恋者。与此相对，女性就被允许去做这些事情。渴望情绪连接的男性，想要去成为女性便能说得过去了。</p><p>同样的，渴望拥有更多话语权的女性，也可能产生成为男性的念头。</p><p>作者在文章中提到，会有男性在寻找对象时既希望对方是爱人，又希望是母亲、姐姐等身份。</p><p>真是熟悉，让我想起了绝妙的例子。接下来的内容都和文章关联不大了，就当是我在自言自语吧。</p><p>我的朋友和讨厌鬼便是这种关系 —— 虽说我时不时在网络上透露出我的生活里有这么个让我很讨厌的人，但我鲜少说出对方干了什么让我如此厌恶他，或许未来会全盘脱出吧，这里就说一部分内容。</p><p>这讨厌鬼最初想和朋友交合、成为恋人。但之后又认其为姐姐，因为对方确实要比自己懂很多。再之后他们成为了「母子」关系，因为这朋友会教他他母亲都从未教过他的事情：原来，这人的母亲近乎没为家里带来什么贡献。家中大大小小的事情都是由父亲一手操办，母亲在他小的时候都没怎么管过他。有着父母偏爱的他，从小开始欺凌自己的哥哥、学校里的同学，并坚信规则就是要被打破的，和他人之间的边界也是一样 —— 到此打住，之后发生的事情可以猜猜看。</p><p>最初朋友认识他的时候，他是无比自大的，有着我很讨厌的特质。该说他是 bro 文化的一大受益者么？那是自然的。我之后与这个人产生过大量令人烦躁的冲突，我也因这种垃圾货色为什么至今都没有受到过惩罚而抑郁过一阵子。</p><p>那他是 bro 文化的受害者么？那也是吧，虽然我很不想承认：他曾将 bro 文化欺压他人的观点说并履行了个遍，之后又成为了楚楚可怜的受害者，是我难以接受的。但确实，如果他不曾被这种主流文化驯化，那些事情都不会发生吧。只是我心觉不甘。</p><p>很显然，他的人生早期没有依恋关系。母亲虽然在，但在场的次数不多也不深，连如何与人社交等技能都不曾教过他，导致他日后的社交方式非常…… 可怕。表面看来，他是自信、勇敢、受美国社会青睐的，但他其实根本没有关系好的朋友，也不曾想过去拥有。他的「阳刚」都是暴力、自恋的表现。</p><p>一次，我听到朋友各种夸他有多特别 —— 其实也没什么，就是说他会健身，然后会做「中央空调」，和所有人打交道但不和任何人做朋友。我不理解这哪里「特别」了，尤其是当时我已经发现了这家伙自恋的特质。于是我说：「他不过是又一个随处可见的普通人。」</p><p>这句话传到他耳里，反而激怒了他。他背着我对着朋友开始不停说我的坏话，说我也是个随处可见的人，因为搞 IT 的女的到处都是。这种话讲给我听自然不会觉得有什么，我早就接受了自己很平庸这一事实，人外有人、天外有天，但我忍不了这个不断在伤害别人，包括我的家伙竟然在背地里骂我。</p><p>我在大一大二期间参加过社团，并经历了最为痛苦的大学时期。那段时间，我出于私人问题，被半强迫地去和当地人社交。我很难说自己是否是个外向的人，但当时和他们相处确实让人感到疲惫：我无法理解这种，刻薄的、男性至上的、到处都是种族歧视笑话的群体。而强迫我和他们相处的、我最亲密的朋友却对我不管不顾。这些到底哪里好笑了？我为什么非要和这帮满脑子都是性、恋爱的家伙儿做朋友不可啊？</p><p>该群体里，最为极端的便是我过去提到的 <a href="/posts/5c85.html#:~:text=%E6%8A%9B%E5%BC%80%E7%8E%B0%E5%9C%A8%E5%88%B0%E5%A4%84%E4%BC%A0%E6%92%AD%E7%9A%84%E5%A4%A7%E7%94%B7%E5%AD%90%E4%B8%BB%E4%B9%89%E6%80%9D%E6%83%B3%E5%A4%96%EF%BC%8C%E8%BF%98%E6%9C%89%E5%91%A8%E9%81%AD%E6%81%90%E6%80%96%E7%9A%84%E5%A4%A7%E7%94%B7%E5%AD%90%E4%B8%BB%E4%B9%89%E7%BE%A4%E4%BD%93%E3%80%82%E5%9C%A8%E5%A5%B3%E6%96%B9%E5%90%8E%E7%BB%AD%E6%84%8F%E8%AF%86%E5%88%B0%E8%87%AA%E5%B7%B1%E8%A2%AB%E5%BC%BA%E5%A5%B8%E6%97%B6%EF%BC%8C%E7%BE%A4%E4%BD%93%E9%87%8C%E7%94%9A%E8%87%B3%E8%BF%98%E6%9C%89%E8%BF%99%E4%B8%AA%E7%94%B7%E6%80%A7%E7%9A%84%E6%9C%8B%E5%8F%8B%E5%90%91%E5%A5%B9%E4%BC%A0%E8%BE%BE%E7%94%B7%E6%80%A7%E6%B2%99%E6%96%87%E4%B8%BB%E4%B9%89%E6%80%9D%E6%83%B3%EF%BC%9A%E4%BD%A0%E5%BD%93%E6%97%B6%E6%B2%A1%E6%9C%89%E5%A5%BD%E5%A5%BD%E6%8B%92%E7%BB%9D%E4%BB%96%EF%BC%8C%E4%BD%A0%E6%B4%BB%E8%AF%A5%E8%A2%AB%E5%BC%BA%E5%A5%B8%E3%80%82%E6%9B%B4%E4%B8%8D%E7%94%A8%E6%8F%90%E5%9C%A8%E4%BB%96%E3%80%8C%E8%BF%BD%E6%B1%82%E3%80%8D%E5%A5%B3%E6%96%B9%E6%97%B6%EF%BC%8C%E8%BF%99%E5%B8%AE%E3%80%8C%E6%9C%8B%E5%8F%8B%E3%80%8D%E5%AF%B9%E5%A5%B3%E6%96%B9%E6%96%BD%E5%8E%8B%E7%9A%84%E5%90%84%E7%B1%BB%E5%8E%8B%E5%8A%9B%EF%BC%8C%E5%A5%BD%E4%BC%BC%E5%9C%A8%E5%91%8A%E8%AF%89%E5%A5%B9%E7%94%B7%E6%96%B9%E6%89%8D%E6%98%AF%E5%8F%97%E5%AE%B3%E8%80%85%EF%BC%8C%E4%B8%80%E5%88%87%E9%83%BD%E6%98%AF%E5%9B%A0%E4%B8%BA%E5%A5%B3%E6%96%B9%E6%B2%A1%E8%83%BD%E6%8E%A5%E5%8F%97%E4%BB%96%E7%9A%84%E3%80%8C%E6%B1%82%E7%88%B1%E3%80%8D%E3%80%82">沙文男性主义者</a>。他们大肆传播性别对立，不仅攻击被强奸的女性，还毒害其他男性的思想。品行卑劣，真是恶心。幸好他们都毕业离开了学校，让我得以在大学内不必担惊受怕、又撞上这群烂人。</p><p>没有那么极端的，也常常会私下嘲笑具有阴柔特质的男性，称其为 <em> faggot</em>、<em>fruity</em> 等。</p><p>我实在是恐惧那时的经历，所以到了大二后半段还是大三，我就连学校都不怎么去了，有机会就上网课。现在倒是出于对本科教育的厌烦，正在考虑是否要休学、先去工作一段时间再说。</p><h2 id="眼前"><a class="markdownIt-Anchor" href="#眼前"></a> 眼前</h2><p><a id="如何在下班后不再感到精疲力尽"></a></p><h4 id="如何在下班后不再感到精疲力尽"><a class="markdownIt-Anchor" href="#如何在下班后不再感到精疲力尽"></a> <a href="https://brandonluumd.substack.com/p/how-to-stop-feeling-exhausted-after">《如何在下班后不再感到精疲力尽》</a></h4><p>话说 Substack 到底是个什么样的平台？原以为是像 Medium 这样的，但发现许多作者的链接里都是自己的名字作为子域名，像 GitHub Pages 的做法。</p><hr><p>作者总结了十个可以让我们下班回家后，从工作模式切换到休息模式的方法：</p><ol><li>回家第一件事就是换掉工作服</li><li>洗冷水澡。接受不了可以先洗温水澡，最后冲个一小会儿冷水。再不行，就用冷水洗把脸</li><li>把手机放到另一个房间里去</li><li>先喝水再判断自己是否疲惫</li><li>先动再坐</li><li>晚饭后散步 10 分钟</li><li>循环叹息呼吸</li><li>用双耳节拍缓解脑力疲劳</li><li>不要摄入咖啡因，改摄入肌酸，或者嚼口香糖</li><li>把未完成的任务写下来，释放工作记忆</li></ol><p>我以前在父母家，洗澡都是睡前洗。和现在的室友住一块儿后，成了一回家就得洗澡换睡衣。这主要是因为室友有洁癖，不允许外面的脏东西到家里来。</p><p>虽然做到了一回家就洗澡换衣服，但是室友的洁癖也导致我们无法完成第六条，即晚饭后出门散步，因为出门就意味着等会儿回家又要洗一次澡。她就算爱干净，也会嫌清洁自己太多次很麻烦。</p><p>关于最后一条，我联想到初中时读的一本书，讲的就是睡眠。</p><p>书中有个男生，被父母送到医生那儿看诊，应该是失眠了一直睡不着。医生每次跟男生聊天，都会给一个建议，比如不要玩手机啥的。最后男生的失眠有所好转，但没能完全解决。</p><p>医生便问他睡前是不是还有很多事情放不下，才导致睡不着的。男生立即露出了被看穿的表情。</p><p>总之好好睡觉、好好休息吧！Sol 在这个月也讲过，<a href="https://blog.solazy.me/20260610/">睡眠是第二天的预算</a>。</p><p><a id="我为-16-岁的女儿定制的-2026-暑期实习计划"></a></p><h4 id="我为-16-岁的女儿定制的-2026-暑期实习计划"><a class="markdownIt-Anchor" href="#我为-16-岁的女儿定制的-2026-暑期实习计划"></a> <a href="https://diff.im/blog/2026/06/linda-%E5%AE%9E%E4%B9%A0%E8%AE%A1%E5%88%92/">《我为 16 岁的女儿定制的 2026 暑期实习计划》</a></h4><p>因为是亲子关系，所以放在了「关系」栏目。</p><p>作者 Diff 为女儿设计了个暑期实习 —— 其实说是实习，实际上就是父女之间的带薪学习。内容包括让女儿学习如何做产品、督促女儿读书学习、让女儿先一步熟悉社会等等。</p><p>关于暑期打工，作者说的不错，它仅能让人在真实的工作环境里，学会和第一次见的同事们共事。除此以外，就是用劳动和时间换取金钱，没了。</p><p>我初三开始打工赚钱，你非要让我说我都学了点啥，我也只能说出些小细节。但这些小细节对其他人来说真的有用么？用处当然不咋大。</p><p>不过我既然将这篇文章划入「关系」，自然是因为我想要谈谈亲子关系。</p><p>我每每听说父母教育并帮助孩子踏入某一领域，都会不可思议。因为我的父母从来都不会对我做这种事情，而我从没有感受到的东西，对于那些父母而言却是理所当然。</p><p>托举孩子竟是 <span class="emphasis">理所当然</span> 的事情！</p><p>在我的记忆中，父亲本就是不常在家的人。他不在乎我在做什么，我也不在乎他在做什么。母亲在我小时候，对我的未来的期望往往都是什么，「赚钱好养她一家」、「做律师医生这些赚钱多的」、「读书读傻了敢顶撞你妈！明天退学，去餐馆上班！」、「你这一辈子就这样了！」……</p><p>我是很幸运地，在疫情期间无聊地摸到了计算机的冰山一角，然后开始自行摸索计算机。不得不说，在没有人帮助，也没有系统性学习的机会在，自行摸索计算机的最开始几年，摸索出来的结果还不如现在任意一个小白用狗屎 prompt 去问 AI 工具讨来的结果。</p><p>不过也很不幸地，我开始自行研究做项目、考有的没的的证书时，AI 工具横空出世，把行业搅得一塌糊涂。好的时代没见过，坏的全来了！</p><p>在我四处寻求帮助时，就有位亲戚跟我提到她如何教育自己的儿子：儿子虽患有 ADHD，但在机械工程上很感兴趣，且比一般人更专注其中。所以她一家花钱花精力去帮助儿子学习、让他在兴趣上一路顺风。</p><p>话题转向我时，她遗憾地说道，我母亲过去太忙了，没有钱，所以都没有管我。如果当时能够帮助我的话，我也不会是这个样子。</p><p>妹妹和我的年龄差相差十多岁。开始抓她的教育时，家里已经过了贫穷的难关，过得也算滋润。母亲明显在她身上投入了比在我身上，更多的时间、精力，和资源。她有个运动的心，便花钱让她学习游泳，并让她进泳队打比赛。她感兴趣的其他运动项目，母亲也会给她报班尝试。</p><p>聊到这种事情，母亲总会说，我小时候没有管我，现在想要在妹妹身上弥补，让她不要经历和我一样的事情。</p><span class="emphasis">和我一样的事情。</span><p>过去听到这种话必定会难过一阵子，眼眶里还会掉小珍珠。现在顶多是难过一下，然后为过去的自己感到惋惜。「唉，他们都这样了，让让他们吧！」我会这么想。</p><p>不过说实话，Diff 先生定制的暑期实习计划，大学生，甚至说毕业生，都不一定能做到。如果小妹妹能全部做完，那前途无量呀！希望小妹妹和父亲都能努力坚持下去。</p><p><a id="你为什么不搬到别处去"></a></p><h4 id="你为什么不搬到别处去"><a class="markdownIt-Anchor" href="#你为什么不搬到别处去"></a> <a href="https://nik.art/why-dont-you-move-elsewhere/">《「你为什么不搬到别处去？」》</a></h4><p>当我们在抱怨自己所处的国家时，总是会有人跑过来说：「那你搬走啊。」</p><p>作者 Niklas Göke（以下简称 Nik）的回应是：</p><ol><li>搬去其他国家也是个工作</li><li>家终归是家</li><li>每个国家都有各自的问题</li></ol><p>去年十一月我写了一篇 <a href="/posts/dfa8.html#:~:text=%E5%A4%8D%E6%9D%82%E7%9A%84%E5%9B%BD%E5%AE%B6%E6%AF%94%E8%BE%83%E6%A0%B9%E6%9C%AC%E5%B0%B1%E4%B8%8D%E6%98%AF%E9%9D%9E%E9%BB%91%E5%8D%B3%E7%99%BD%E7%9A%84%E4%BC%98%E5%8A%A3%E5%88%A4%E6%96%AD%EF%BC%8C%E8%80%8C%E6%98%AF%E5%90%84%E6%9C%89%E4%BE%A7%E9%87%8D%E7%9A%84%20AB%20%E7%BA%A7">文章</a>，明确表明了我对国家们的态度：它们之间的关系是各有侧重的 AB 级，而非非黑即白的好或者坏。</p><p>可惜这种态度并不「主流」。我难以和身边的人共情，他们不会考虑到我的态度，甚至会直接默认国家政策之间定有绝对的非黑即白。</p><p>然后我就说说第二条。</p><p>我一直有着回国的想法，因为过去的美好记忆驱使我往那里去。我在美国居住的这十几年，能回想起来的美好记忆屈指可数，甚至不及我在国内做留守儿童的那两年。也有一点是我的童年在中国度过，而童年往往是最令人深刻的时候。</p><p>家人不理解我的乡愁。也没有办法，我出生在他们「北漂」的城市里，光是在中国我们就没法理解彼此。</p><p>国内的许多餐饮品牌打入美国，以及多样化的新移民陆续来到美国后，我第一反应是开心。但实际吃过以前在中国吃到的一模一样的食物后，我便变得难过无比。我有十多年没能回国，让我能一直记着中国的就是「吃」。现在我吃到了味道一样的食物，我便少了一个在惦记的东西，好像我离中国又远了一步。</p><p>家终归是家。我想要至少回去看看一次。朋友曾和我说，我对中国的认知已经断层了，就算回去生活，也有可能会不适应。</p><p>还有一点是在国外待太久，接触太多外国思想，对中国政府来说不是件好事吧……</p><p>每过一两年，就会有国内的亲戚给我发山东的照片。记忆里，六七年前我小时候住的小区楼刷了黄漆。三四年前，楼下又变成了夜市。</p><p>我手机里曾下载了高德地图，专门用来查看我曾经住过的地区，现在有了什么样的变化。街景图片真是个好技术，让我能够看到小区楼的门口。就是更新时间太久了。</p><p><a id="背包活化能"></a></p><h4 id="背包活化能"><a class="markdownIt-Anchor" href="#背包活化能"></a> <a href="https://www.autodidacts.io/backpack-activation-energy/">《背包活化能》</a></h4><p><em>Activation energy</em> 是化学里的「活化能」，又称「阈能」。它被用于表示化学反应所需的能量要求。</p><p>作者的这篇文章也如他自己说的那样，很简单：</p><blockquote><p>Yes, you have just read an entire essay about the fact that <strong>I don't like getting things out of my backpack.</strong> Finding and extracting things from a full backpack takes physical and psychic energy that I don't have……</p><p>是的，你刚刚读完了一整篇文章，而它的核心就是 <strong>我不喜欢从背包里拿东西。</strong> 从塞满的背包里寻找并掏出东西需要消耗我所没有的体力和精神能量……</p></blockquote><p>我出门会尽量仅带手机和钥匙。如果要坐车的话，就会带耳机。为此，我会特意购买有四或以上个口袋的裤子。比如我今年春天从 UNIQLO 购买的 smart wide pants，屁股口袋就大到能装下我的 Kobo。它还有扣子，可以关上，所以骑车时只需要把东西放入屁股口袋即可。这样我连外套都不用穿、包包也不用带。</p><p>有时候我得带上一些小东西，比方说出门去玩《舞萌 DX》，我就需要带手套、有线耳机、卡包。我会把它们塞入我的胸包或腰包内。</p><p>背书包的时候，仅在我出门要买很多菜，或者要带电脑出门的时候。</p><p>室友这个月购买了个跑步用的 hydration 包。背在身上相当轻量，内置一个水袋，可以通过伸出来的软管喝水。它在背带上有个小设计，那就是也装有口袋。</p><p>我在想，这种背带能不能单独搞个产品出来？它不是包，但我可以把它套在我的身上。它开了许多个小口袋，可以让我把小东西一个个塞进去。又因为它不是包，我移动起来不需要担忧它晃来晃去。</p><hr><h2 id="折腾博客"><a class="markdownIt-Anchor" href="#折腾博客"></a> 折腾博客</h2><p>我把月刊的分类给改了，因为原先的得不停去扩充才能放下所有的文章类型。现在的这个以「距离」作为要点，从离我最远的「世界」开始，最后到我周围的「眼前」。</p><h2 id="我写的文章"><a class="markdownIt-Anchor" href="#我写的文章"></a> 我写的文章</h2><ul><li><a href="/posts/893f/">《想法在丙午芒种迭代》</a></li><li><a href="/posts/293b/">《抢房子大战》</a></li><li><a href="/posts/2814/">《数多年重试跑步然后晕倒》</a></li><li><a href="/posts/54b4/">《讨厌礼物》</a></li><li><a href="/posts/97a1/">《读《虚构一九八七》》</a></li></ul><h2 id="编程历程"><a class="markdownIt-Anchor" href="#编程历程"></a> 编程历程</h2><p>这个月做项目的时间很短，没有什么突破和新想法。</p><h2 id="书籍"><a class="markdownIt-Anchor" href="#书籍"></a> 书籍</h2><h4 id="其他评价"><a class="markdownIt-Anchor" href="#其他评价"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/book/0PIxzerx5SuYp8DIuzqg69" target="_blank" rel="noopener noreferrer">越級申訴</a><span class="neodb-status">已读</span><p class="neodb-comment">仅看了同名篇章「越级申诉」。 <span class="spoiler">因为 *Lower One's Eyes* 看的，这么疯的 Judas 看着太有趣了。</span></p></li></ul><h2 id="影视"><a class="markdownIt-Anchor" href="#影视"></a> 影视</h2><h4 id="其他评价-2"><a class="markdownIt-Anchor" href="#其他评价-2"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/movie/2dT2G3eRIm0XwF4Xa7ccDT" target="_blank" rel="noopener noreferrer">玩具总动员 5</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已看</span><p class="neodb-comment">好看的合家欢，很多好笑的地方。看到结局很温馨。</p></li><li class="neodb-item"><a href="https://neodb.social/tv/season/2azh3WGI7gM3BDVvn8hnh4" target="_blank" rel="noopener noreferrer">喜羊羊与灰太狼之决战次时代</a><span class="neodb-status">在看 </span></li><li class="neodb-item"><a href="https://neodb.social/tv/season/6LfdXQxKxEUiXM9Wi0D1In" target="_blank" rel="noopener noreferrer">URAHARA</a><span class="neodb-status"> 在看</span><p class="neodb-comment">重温。我无法抵抗头上长了角的女孩子。</p></li><li class="neodb-item"><a href="https://neodb.social/tv/season/1qRxBPgzWReIaYBbYxXKKd" target="_blank" rel="noopener noreferrer">明日同学的水手服（明日酱的水手服）</a><span class="neodb-status"> 在看</span></li><li class="neodb-item"><a href="https://neodb.social/tv/season/5laO1Yzmk3duCDRvHhlVs1" target="_blank" rel="noopener noreferrer">女高中生的虚度日常</a><span class="neodb-status">在看</span><p class="neodb-comment">重温。原作漫画有在追。这次看的时候发现 バカ 的声优是赤琦千夏，OP / 剧中的声线，和 ED 的声线真的是同个人……？声优恐怖如斯啊。重温时发现了更多小细节，比如每一集 ロボ 都在做些很诡异的事情，像是突然在背景里开始电焊、做化学实验、玩魔方从一开始的摸索变成速拧达人。</p></li></ul><h2 id="音乐"><a class="markdownIt-Anchor" href="#音乐"></a> 音乐</h2><h4 id="其他评价-3"><a class="markdownIt-Anchor" href="#其他评价-3"></a> 其他评价</h4><p>本月暂无记录。</p><h2 id="日记片段"><a class="markdownIt-Anchor" href="#日记片段"></a> 日记片段</h2><button id="details-toggle-diary_sections-1789678111670" class="details-toggle-btn" data-group="diary_sections" onclick="toggleGroupDetails('diary_sections', 'details-toggle-diary_sections-1789678111670', '展开所有', '收起所有')">展开所有</button><details data-group="diary_sections"><summary>六月一日</summary><div class="diary-entry">00:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT0ANA57D4HRMK1KA1XXM1YZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>年初走到的 <a href="https://blog.cytrogen.icu/posts/53f4.html#:~:text=%E6%88%91%E4%BB%AC%E8%B5%B0%E5%88%B0%E4%BA%86%E8%8A%B1%E6%97%97%E7%90%83%E5%9C%BA" rel="nofollow noreferrer noopener" target="_blank">地方</a>，这次骑到了！</p><p>差不多花了两个小时。骑前特意计划了一下路线，结果发现和那次走半马的路线差不多。不过在细节上，还是有许多差异。</p><p>刚才慢慢过一条很细窄的道，不小心撞到别人了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 结果对方一脸懵逼地看着我，我也只能道歉，然后逃跑……</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KT0AEZPT9M8GC6Q8MCR4KPFT.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">00:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT0AZ52JHE8SJAMFQEWNYNRA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>话说我这个状态好适合玩 <em>Pokemon Go</em> 啊。我高中有段时期特别沉迷于此，但沉迷没能让我开始运动，反而是玩起了邪道…… 下载别人做的 Android 软件，当飞机党。后来被警告，又用 macOS 上的一款修改手机定位的软件模拟自己在走路和跑步。</p><p></p></blockquote><blockquote class="diary-thread-reply">01:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT0BN00C61GME0KSVEVZ8BPR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>一路上最痛苦的地方依然是前三分之一段，即骑出曼哈顿、过桥的这段路。这个破曼哈顿，到处都是不怕死的行人，就算我按了铃也无动于衷。</p><p>而桥，永远都是先上坡再下坡的。我上坡的方法不对，当时应该站起来蹬。太累了，很想放弃，但依然在往前骑…… 难过到鼻涕泡都快出来了。</p><p></p></blockquote><blockquote class="diary-thread-reply">01:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT0CCGG6NYBMWF34BPRGB6HY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今儿过来一是为了完成「骑车到法拉盛」的目标，二是过来吃口喜家德。之前跟博友 <a href="https://liangmouyin.com/blog/14-dumplings/" rel="nofollow noreferrer noopener" target="_blank">梁某银</a> 说了想尝尝看，但一直没时间来。要是按照往常的「法拉盛出勤」—— 指的是走地铁来、吃郑州烩面、玩舞萌 DX—— 那我肯定会为了郑州烩面而不愿意尝试其他。今天过来，顺便把这个任务做完！</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KT0CC8QWJ58KWCMJ4Q2KRHCC.jpeg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KT0CCDXPVQKYXTY0J6DNTN75.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">01:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT0D458388PN12FXEKXF9V5K" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>点了店员推荐的「喜三鲜」。说实话，名字像喜羊羊的孩子。我其实很喜欢《狂野新宇宙》里的喜儿。我在说什么？</p><p>然后店员跟我说酱在前台拿。我过去一看，<em>怎么没有番茄酱？</em></p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KT0D16GV5XNM5PGC5K36RVZ3.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">01:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT0DYDMATPBNPXEHZ7ZEPZMG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>加上小费还有可乐一共 21 美元 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​ 还是太痛了，加上小费 12 美元的郑州烩面依然是我心里的第一。</p><p></p></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">01:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT0BAYYW777K4CXX9F82T2WS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想换房子住。现在的房子年年都在涨价，你什么样子别人什么样子，这么破还敢涨价。结果搜一圈房源，发现便宜的都在 Harlem…… 你让我住在犄角旮旯的地方也行啊。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">Contains a bunch of swear words.</summary>        <div class="diary-cw-content">04:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT0PJRMF5K9ST1W041MY5C8N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://fortune.com/2025/07/24/sam-altman-college-not-working-great-stanford-dropout/" rel="nofollow noreferrer noopener" target="_blank">https://fortune.com/2025/07/24/sam-altman-college-not-working-great-stanford-dropout/</a></p><blockquote><p>Most people think about risk the wrong way—for example, staying in college seems like a non-risky path. However, getting nothing done for four of your most productive years is actually pretty risky.</p></blockquote><p>Plaused. Bravo. I agree with this statement standalone.</p><p>I don't understand a single piece of shit. Why are there so many people wasting their time and life in college, for literally NOTHING? Like a friend of mine, chose a major that they have no fucking idea with, a university that they have no fucking idea with, and still chose to rot in there, just for a stupid-ass diploma. For real, what can it help you? How? You chose to rot, wasted time and money, and still believe this is the right, safe, and secure thing to do. Even though I told them multiple times, FUCKING DON'T. Mother fuckers. Go get your Master's, or maybe Doctor's, and rot.</p><p></p></div>      </details></div><hr><div class="diary-entry">14:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT1V0VTSHJJDMBF6KNM6MYJ3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨晚室友把我的笔记本电脑忘在了共享办公室里 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 我要杀了她……</p><p></p><blockquote class="diary-thread-reply">17:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT22SE8NNG12J2CTTWWSXVQA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这个人明明把我的东西落在了到处都是人的地方，却到现在才悠悠哉哉醒过来……？</p><p></p><blockquote class="diary-thread-reply">17:43 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT24GQ2SC10YQZ84KT0BXPGS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我的焦虑宛如婴儿醒来却找不到母亲。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">18:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT268BTT84HFNRQ29XTPZP2N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在为一个项目，做多 agent 协作系统…… 因为不想花时间和精力在这个项目上了，打算直接外包给 AI 工具，我好干点别的事情。反正也只是在不停地听甲方写业务逻辑…… 打螺丝打螺丝。</p><p>目前是暂时在测试 dual agent 方案。初始化任务和研究交给 Deepseek，实际执行交给 Claude Code。实际使用的项目是 <a href="https://github.com/keshrath/agent-tasks" rel="nofollow noreferrer noopener" target="_blank">agent-tasks</a>。因为维护者两个月了都没有任何动静，再加上有许多需要贴近项目的地方，所以克隆下来自行维护。</p><p>实际上最好是再添加不同的模型，比如 Gemini，巴啦巴啦。训练的内容都各不相同，能看到其他模型看不到的角度。但 Gemini 会员很快就要到期了，也不想要花钱去续。到时候申请个 API key 再弄吧，现在仅是实验阶段。</p><p>原理就是给一个 agent 下任务、其他 agent 通过 MCP server 等待 kanban 里的内容更新，然后协作。想法很美好，实际上如何，就不知道了。</p><p></p></div></details><details data-group="diary_sections"><summary>六月二日</summary><div class="diary-entry">01:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT3050Z5P7CDBRQAC598D5DS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>虽然学习过机器学习的内容，也做过 CS50AI 这样的作业…… 但现在重新学习机器学习的理论知识，依然会觉得这些数学公式看不懂啊看不懂 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 我只会调包。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">又是吵架、焦虑。</summary>        <div class="diary-cw-content">07:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT3JPXG7WYQPRK4REMR88776" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打工很难让我想要继续下去。烦人的同事、抠门的薪资、看不到未来的职位…… 吞小费到底是什么意思！最烦躁的莫过于要接触的人，一个两个没有谁是不让人讨厌的，到处都是旧时代的糟蹋。我根本不适合这种地方，做下去怕是心都要被腐蚀掉，赚的钱也不多。</p><p>所以想要找关系不错的亲戚帮我介绍一下工作。至少不会是这种破地方的工作吧，让我做什么都可以…… 我原先有考虑过兼职送外卖或者送快递，但是出于安全考量没有那么做，再加上我也没有车。</p><p>钱，好想要钱…… 虽然我的物欲不算太强烈，但为了一些事情，不得不去赚钱。好像赚来的钱，只有一小部分是用来花给自己的，其他都被用来交房租、吃喝拉撒维持基本的生活质量。只是想要和一个人在一起，但要为此维持的生活，实在是太艰难了。</p><p>晚上又被单方面地骂了一顿。骂得很难听，总之又是什么找不到工作活该啊、不够努力，让我不要去找亲戚换工作做。可是再换个工作，还有什么比现在这份破工作更难做、更赚不到钱的呢？你到底想要我做什么？我觉得我已经在很努力地去做我该在做的事情了。不停地去 network、修改简历，能给我带来的到底是什么？什么是「现在市场竞争已经很激烈了，所以你要比其他人更努力」？我在和谁竞争？我在做什么？到最后也只是强忍着憋屈敷衍了几句，然后难过得很想哭 —— 虽然已经在哭了。</p><p>钱重要，还是做专业的事情重要，我也不好说。后者看上去更体面，但是按结果而言，找不到就是找不到，那我也只能选择前者，先把钱赚了。可是又想到，未来还有更多黑暗的东西在等待着我，由衷地感觉有点绝望了。我的人生是什么时候开始演变成这样的？大家都在擅自地把自己的事情堆到我身上，让我去承担些根本不是我的错的事情…… 好想变成什么乱七八糟的液体，顺着水槽或者马桶流入下水道，然后转生成蚊子或者什么虫子，专门咬你们这些可恶的家伙……</p><p></p></div>      </details></div><hr><div class="diary-entry">17:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT4MEZQ6E1K5507CGY88RS5F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>和被逼在做 AI 工具的朋友（好惨一个人）聊天，越发觉得这东西做起来，很像是在赌运气，而不是写代码的那种「只要逻辑对就能跑通」的感觉。</p><p>比方说读取代码文件这种很简单的操作，其实会因为代码文件逐渐变大，而导致塞满上下文。尤其是老项目，代码文件不可避免会变多、变大。再去为了结构性而重构它，又不知道要花费多少人力、精力、时间，况且企业并不希望程序员们去做对业务效率无关联的事情 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 我之前重构项目就被骂了，现在只能很缓慢地悄悄进行。问我为什么不最开始就写好，那当时的我咋知道会变成这样啊，我又不是想写 bug 才写 bug 的。</p><p>而业界解决 agent 不要一次性读取过多代码文件的方式是，在 CLAUDE 或者 AGENT 或者啥的 .md 文件内声明 agent 该怎么做 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 但是现实很无情，agent 依然会「忘记」这件事情，所以最保险的方式是监禁 agent 的行动力，加上 pre-tool-use hook 警告、阻止等等。亦或者是做个 AST map，让 agent 先看文件的结构概览，再去读取需要的内容。</p><p>这里就能看出跟 LLM 打交道是个什么鬼感觉了。它不会百分百听从于你，你要花很多时间去约束它的行为。这个约束还是发生在应用层、更抽象和高级的地方，而非基层的模型本身。那要如何从根源解决这个问题哩？我不知道！</p><p></p></div><hr><div class="diary-entry">17:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT4NBQ4JJVHY8F6A0VH2BF7Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我想考普通话证书，然后每次有中国人问我会不会讲汉语时，我可以对着他们说「是的，我的普通话力有 xx 级」。</p><p></p></div><hr><div class="diary-entry">18:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT4QWS13TAYNKRRTQ1NYFZ7E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前一直看不惯 Kobo 的字体，再加上无法通过 Calibre 无线推送书籍，所以老想把原生系统干掉。介于 Instapaper 以及未来可能会用到的公共图书馆系统，也没有下定决心做……</p><p>直到我发现直接在 Kobo 内放字体文件就可以用了，所以果断添加了思源宋体。计划直接破产……</p><p>不过新的问题在于，如何让它在渲染拉丁字母和数字时，用另一个字体呢？</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KT4QVPWFBSNMEZ7KQX502WEX.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">21:10 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/967532877622890681" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Mimi slept on my sister's bed without any consent!!! Bad mimi.</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/b5862bd14-4506fa/wEAC4ntml4qX/j91zqaXHOXxpDAdKyJ8jdcqD1vyvhUqWvnRUASY6.png" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/b5862bd14-4506fa/GjukBm5K8HnN/iO5jVXaTma7lRTLMXROkKnyUUmaWJYTTCSMKsi1e.png" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/b5862bd14-4506fa/a5Ki1SszFEVK/rTiV2LzxgDykzfsth24iRtffG2zhudXGEQAYOQ0s.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">21:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT52WP0BV7H9S6KYYFPHZ44E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>好吧不知道为什么我所处的 Pixelfed 实例，不让我上传幸运狗的照片，反而咪咪猫的照片都能正常上传。难道实例主偷偷从狗奴变成了……？</p><p>总之在这里发张毛发长回来的幸运狗吧。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KT52TMMZKJ0JH7GAZ8QC7AX1.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">23:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT5AFRR19E9WR5ZED61P2CJ7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>没那么忙，有些隐隐不安，不知道做什么。好像又开始无意识地在拔眉毛了，室友前几天说我眉毛又秃了一角…… 想看漫画，但是 manhuagui 炸了看不了。久违想看看轻小说，打开 Hikari Novel 发现作者停更了，得自行编译他的新写的项目。人在外面，很是怠惰，未来再说吧。</p><p>这家店有一面墙，其实是可以打开的门。如果把这个难听的音乐列表关掉，把门和窗户都打开，大家一直感受夏天的声音，就好了。</p><p></p></div><hr><div class="diary-entry">23:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT5B5BRNZBWH5P4NRSMYVN0D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://news.kagi.com/s/et99ws" rel="nofollow noreferrer noopener" target="_blank">https://news.kagi.com/s/et99ws</a></p><p>What do you mean I can just hack into others' accounts by enabling a VPN and asking AI to help me?</p><p></p></div></details><details data-group="diary_sections"><summary>六月三日</summary><div class="diary-entry">01:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT5HNJWV5T9HY33ZGW5FG9YF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>度过相当碎片的一天，也不知道自己在干什么，昏昏欲睡的。走路回家的时候，让思维更加发散了些，然后开始往过去的记忆里随便找一块，再找另一块与其相关的记忆，不停地找下去。</p><p>比如我想到了小时候从大屁股电视里看到的国产剧，应该是民国或者抗战背景吧，说一个女的和另一个男的相爱，但在结婚前男的消失不见。同时她又看到另一个长相相同的富二代，却不是她的未婚夫。原来，这个富贵家庭曾经求子不能，于是从镇上的一个酱油铺那儿，买来了双胞胎的其中一个，当成继承人培养。不过后来还是怀了二胎。长大后，富贵家庭的弟弟恨「哥哥」过于优秀，打算杀了他，却杀错、杀了双胞胎里的另一个，也就是留在了酱油铺里的、女子的未婚夫。</p><p>剧集都喜欢创造误会，让我又想到另一部剧的开头。说是一对姐弟坐大巴去投靠亲戚。其中一个睡着了，另一个中途下车去买包子。和我们想象的一样，大巴开走了，另一辆一模一样的大巴停在了原地。买包子的上车却没有找到自己的手足，睡着的醒来后也是。于是两人的命运就这么错开、往完全不同的方向开去……</p><p>明明流着相同的血，却过着截然不同的人生，我又想起了小时候阅读的《大林和小林》。我只记得它的开头，像大饭和小饭这样的诡异名字。另一个记得的，是其结尾。两人因不记得的事情而错开，大林过上了公子哥的生活，小林过上了平凡的生活。最后二人终于相见，却已经不记得彼此，反而视彼此为仇敌……</p><p>也许因为是不好的结局，所以让我印象深刻。另一个典型例子是《红宝石公寓》。有段时间对《皮皮鲁和鲁西西》系列很感兴趣，表哥就借了他的 <del>盗版</del> 合集给我，里面就有这篇。看完难受好几天，一想到故事的结尾，就郁闷 —— 事情就只能这样了吗？怎么会呢！</p><p>写到这儿，思维反倒难以发散了。</p><p></p></div><hr><div class="diary-entry">02:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT5KRWB6ZRY572PCBGFCGM6F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>后厨大叔的烦到了新的境界。他开始向我展示他的网恋对象们，而每一个年纪都和我差不多。介绍时，要么是说对方的照片高 P、现实肯定更丑，要么就是说现在的 00 后都喜欢大叔、太恐怖了，然后享受这种「恋爱」的感觉。</p><p>我没有网恋过，所以很难想象这些文字到底有意思在哪儿。互相道早安晚安、发虚假情意的安抚、喊彼此老公老婆…… 这些东西竟是「恋情」吗！我本就是厌恶快餐恋爱的人，互联网上的快餐恋爱，更让我鄙视…… 尤其是他现在已经给我看了好几个网恋对象了。</p><p>当然，我每次都是敷衍地在一边「嗯嗯」，也不是很想去看他的聊天记录、网恋对象的照片，所以还会悄悄挪动位置、走到一边去。</p><p>这种破恋爱的话题，初中就已经受够了，现在不要让我再听到…… 免疫倒也有点免疫，不过最烦的、以至于我现在跑来吐槽的事，是他开始说其中一位网恋对象的事情。他说他拉黑了这个女的，却没想到女的一直纠缠他。接着他说：</p><blockquote><p>她和你长得一样！同个年纪。</p></blockquote><p><strong>我要把你的头皮剥下来。</strong></p><p></p></div><hr><div class="diary-entry">02:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT5NZVF5192VK8G5APCPC4F8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>等麦当劳。看了眼，发现五美元套餐确实变成六美元套餐了，名字也变了。</p><p>唉。</p><p></p><blockquote class="diary-thread-reply">16:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT74K5RG1Y531189HEWFK8EH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前说妹妹吃白米饭会蘸番茄酱，后来发现她吃苹果也会蘸番茄酱。</p><p>但是！她吃薯条不会蘸！她会蘸冰淇淋！</p><p>啊啊啊啊啊 ——！！！</p><p></p></blockquote></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">福瑞、性暴露……？以及很尴尬的事情相关。</summary>        <div class="diary-cw-content">04:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT5XAREHB9NNAFH98HMSCFQQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在家里找点东西结果翻到了高中画的大包福瑞 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 我擦我以前在画啥啊。然后每个画画本子，翻到最后怎么都是福瑞，并且感觉完成度要更高一些……？</p><p>还翻到以前没写完的情书，太厉害了，这么多年都没有被别人找到 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​</p><p>反倒是以前画的女同漫画被妹妹翻出来重新勾了线…… 我也到了得把手足视为世敌的时候了吗……？</p><p>有些可怕的是部分本子明显不见了……？它们没备份啊别乱丢 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">福瑞、性暴露……？以及很尴尬的事情相关。</summary>        <div class="diary-cw-content">05:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT5Y60T651RH6XZT9FGYBWFT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>找了半天没找到印象里质量还算可以的画，只找到大量的垃圾摸鱼 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 不是我东西呢。</p><p></p></div>      </details></blockquote></div><hr><div class="diary-entry">05:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT5ZWMY03VZY89F41FSMYAGP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>上 QQ 相册找东西时发现有些图片竟然暂停访问了！火速把剩余的存下来。</p><p>还有许多绘图没有拍下照片，亦或者是没有上传到相册里，总之找不到了。还有些是以前故意丢、删掉的 —— 奶奶的你丢它们干嘛！</p><p>「做蠢事 - 删除记录 - 想要找回记录」是每个人都要经历的吗。</p><p></p><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">敏感内容</summary>        <div class="diary-cw-content">05:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT60639K8RFJG7YNDM2W3PG2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>找到了高中做游戏时画的老虎角色。还是很可爱的……？就是西装的像素图画出来像不良女式水手服 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 不过这个角色当时扮演的是黑心企业的老板，主角是被压榨的程序员，被开除后回老家种地…… 是的，是类星露谷，虽然没做完，当时也没玩过星露谷。</p><p></p><figure class="diary-media diary-media-sensitive"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KT601Y5XD55CCXCQFDJ2PDX0.jpeg" alt="" loading="lazy"></figure><figure class="diary-media diary-media-sensitive"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KT601Y9HMY2CC4VDXZBEQPJ5.png" alt="" loading="lazy"></figure></div>      </details></blockquote></div><hr><div class="diary-entry">13:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT6TS92JP5N9J8WMWR5BY4PE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>卖鞋子的叔叔（简称鞋子叔叔）送了双 HOKA 给我。之前自己挑选鞋子的时候，就想要买 HOKA。倒不如说高中在倒腾 QQ bot 的时候，就想要买 HOKA，因为当时 bot 的名字改成了 Hoka（霍卡），是小学画漫画时一个角色的名字。</p><p>这双鞋怎么说呢，最显著的点在于鞋底很高，后跟杯总感觉难以抓住脚后跟，恐怕摔倒时脚踝也会受伤。先穿穿看吧。</p><p></p></div><hr><div class="diary-entry">13:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT6W72X848A6Q5P3E37KE949" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天是出来看眼睛的。好久没有检查眼睛了，现在的看热气球环节不会有气打到眼球了么？一直都很怕这个环节。然后多了个看绿色 X 的环节，后面会出现白色的光、闪我的眼睛，很难受。</p><p></p><blockquote class="diary-thread-reply">15:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT6ZZK6C2KCKVFEPATVXMS4P" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>测眼底时滴了个药水，好像是让瞳孔扩散的？现在看东西很难受，还得一直戴着一次性塑料墨镜摸来摸去。</p><p></p></blockquote></div><hr><div class="diary-entry">15:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT71P76B28NHSZ5KEH9EKDH7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>妹妹数学太烂了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 家里在考虑请私教。请私教的前提倒也是我没空管她。到底是为什么变成这样。难道我拿走了妹妹的数学细胞，作为代价，运动细胞被她拿走了……？所以叫母亲去网上贴个招聘启事或者啥的，抓个大学生来也行吧。</p><p>说到私教，先前和一校友讨论中美教育和贫困家庭的关联性。他觉得中国人均都能请私教，大家高考都能考高分，以反驳我认为中国贫困人家勤读书便能被好大学录取的观点。反正对于他的后半句，我是不相信的啦……</p><p></p><blockquote class="diary-thread-reply">16:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT73J6BGZ5SMC0WBB92TS54V" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>听母亲讲到个好笑的，因为妹妹常年在及格线 60 分左右蹦跶，有时候考了 80 会兴高采烈跟母亲说「你不要太高兴」，反之会说「你不要生气」。</p><p>便想到我和她年纪差不多的时候，会很故意地把试卷右上角的 100 分拿别的东西遮住，弄成 0 分的样子，来试图骗小餐桌的辅导老师。当然，没有一次骗过，因为小孩子的那种「我没有骗你我真的没有骗你喔」的感觉成年人真是一眼就能识破。</p><p>不过也一起记起来了当时的棍罚。我在小餐桌里的成绩要求是至少 95 分，每少 1 分手心就会被打一下，真的很痛。有次计算题出了很多错误，考 70 多，直接屁股挨了一脚、踢飞了。小学考咋样，现在想来根本也没有那么重要吧，但是幼小的心灵还是很受伤的。</p><p>成绩至上的社会很是可怕啊。遥想到高中在网上认识的在中初中生，骄傲地说我另一个每天写作业（plus 是最呆的小组作业）到凌晨 3 点的在美朋友不够她努力。该睡觉的时候就该睡觉吧……？这些作业到底有用在哪里呢？要达成「每天都能自主学习」的目的，真的需要牺牲这么多睡眠么？最后是，这种东西真的有比较的必要吗……？</p><p></p><blockquote class="diary-thread-reply">16:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT74EX15ESAMJDZY3GNDWDTD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>考了 70 多分的那天，照顾我的人晚上带我回家，一边哭一边走。只是因为我考了 70 多分！虽然是关心我，我很开心，但是也没必要吧！也只是小学生考了 70 多分而已啊？</p><p>小孩子机灵古怪的想法也从日常挨打中激发了出来。比如当时的大家都会互相装成彼此的家长、伪造签名，尤其是考差的时候。谁都不想挨骂挨打嘛。</p><p>当时的另一个记忆是，有天我很有自信地不和任何成年人说，一个人从小餐桌那儿走回了家。结果大家都以为我走丢，或者被人贩子拐走了。结合当时传得沸沸扬扬的人贩子拐卖小孩的新闻，要是当时真的被拐走，我的人生又会变成什么样呢？幸好是路上谁也没遇到。</p><p>之后他们放宽心让我一个人走回家了。在乡下的外婆家，这样做还挺常见。但放在现在，我是不会让我妹妹这么做的…… 一次妹妹要和朋友们结伴回家，但是等了会儿都没有等到她，于是很着急地开车出去找。结果最后发现出门找的期间她就已经到家了。明明自己小时候也是个智障，却能做到这种事情，现在却无法相信同个年纪的孩子能做到同样的事情。这也是育儿必须要考虑到的问题吗……</p><p></p></blockquote></blockquote></div></details><details data-group="diary_sections"><summary> 六月四日</summary><div class="diary-entry">05:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT8JXQXD96Y1AD040SKXYH03" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Went to find some mentors. I used to have some, but I didn't take it too seriously, as I couldn't participate in any of the jobs out there due to some issues I had. Years passed; I don't have those issues anymore, but I don't get any hearbacks anymore either. Ironic -- when I was more playful I got interviews and offers. Now I have nothing.</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">生活的迷茫、焦虑相关。</summary>        <div class="diary-cw-content">14:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT9FNKDDVHHTAWS0CXT725P0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>先前和母亲，还有鞋子叔叔，去先前教我调酒的师傅开的新店里吃饭。再次看到他还是很高兴的，尤其是看到他的新店里有着还算多的客人。希望他的新店能长久、开大。</p><p>他问我愿不愿意来他这边上班。诚然，氛围、环境，甚至可能说待遇，都要比我现在这个兼职要好上不少。可是，这家新店在父母住的地区，我现在住的地区离那儿很远很远。</p><p>搬离家的一大问题，便是钱。我打工很大程度上便是为了解决「住」这个问题。谁叫这里的房租真的很贵啊，房子质量…… 也不能叫房子吧，仅仅是个小小的 studio 而已。我和室友和匹克猫三个生物合租在这儿。</p><p>吃饭期间，母亲和鞋子叔叔就聊到了「住」的问题。他们认为我一直在赚钱，仅是把钱交给了房东，却没有一点存款 —— 这说得不错。他们作为努力买了房的新移民，希望后代可以不用受房租、学贷的折磨，但到头来，我还是头也不回地逃离了家。这也没办法，因为我搬离家的第一个理由便是逃离父母。</p><p>但他们说得也有道理，我并不是一定要住在这里。这就要说到第二个理由，我住在这里是为了室友。虽然时常称呼这个人为「室友」，但我们二人的关系要更深，最为贴切的形容是「挚友」吧。我们对未来人生的想象，都是以把对方放在其中作为前提的。所以，搬去父母家，我会同时面临两个难题，只能忍痛 pass。</p><p>真想搬离这个破房子，去到别的地方去啊。太贵了，遭不住。另一个破解的方法，是找到工作，软件工程的工作只要能找到，最低薪资也足以我活得滋润了。可惜，我找不到，只能想尽办法去寻找突破口、机会。这些天便在筹划换兼职、学习不同学科的知识、找人 network 扩张人脉……</p><p>不得不说，<em>妈的</em> 传统行业例如会计师、税务师，真好找工作啊。室友做了个小实验，结果竟有人看到她的简历，打电话过来挖她。放在计算机领域，能被公司主动挖的，现在基本上都是机器学习人才了吧。我们二人都好奇为什么会这样，搜索一番发现是可恶的年轻人们都觉得会计、税务很无聊，不倾向于学习，导致供不应求。明明报税是个硬需求的铁饭碗……！但也确实，因为兴趣而学习计算机、编程的人到处都是，而因为兴趣而学习税法知识的…… 我反正除了室友外，没有见过。</p><p></p></div>      </details></div><hr><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSVSF2YAXCR2H6VPQ911RBWS">↩ 续前文</a>        </div> 16:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT9PJN6MAQX0BWTECZPQX746" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>应该是有点效果的，这几天没怎么看到它。原本以为灯光驱动陷阱没啥用，结果昨晚回来看到上面死了俩，今早起床又多了一只。</p><p>买的清理下水道的东西，是 Rockwell Labs 的益生菌排水管清洁凝胶（InVade Bio Drain Gel）。</p><p></p><blockquote class="diary-thread-reply">06-07 16:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTHD61Q108FX2VFQRRMZK049" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>哈哈哈哈哈家里没有蚤蝇了哈哈哈哈哈！</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>六月五日</summary><div class="diary-entry">01:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTAP1SYW21EPEM7JZFV1H6W1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>时间管理太差了，很多时候都不会规划自己什么时间该做什么…… 所以很多时候是同个时间做三件事情，把自己当异步搞。结果自然而然便是，注意力很快就涣散、开始想打瞌睡，明明还在学习 transformer 的 attention 还有 self-attention，我晕～</p><p>想着这样不行啊，于是换了衣服，准备好 mai-set 出门，骑车去了别的地方玩舞萌。这家店玩家都很少，基本上都是路人，还有一边在玩中二的。这样的氛围让我感觉很安心…… 很多时候并不想要和舞萌的玩家待在一起。</p><p>随便摸了几把就离开了（不准玩恶俗谐音梗）。刚出店门就看到黑黑的天、关门大吉的超市 —— 喔，我最开始是想要过来买香菜的。算了，明天再去吧。</p><p></p><blockquote class="diary-thread-reply">01:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTAPJJHCS0F3N7YXMNN9MSA1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天优化项目的 agent 的上下文。优化得太狗屎了，现在新的 session 的初始上下文，比之前的还要多 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 混用了不同的 AI 工具，本意是为了让训练不同的模型给出不同的视角和看法，结果这种事情我还没有体验到，就先被不同的 AI 工具的默认行为许可给坑到、不得不去维护三套配置 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​</p><p>之前提到的多 agent 任务板，效果挺一般的，因为我也不可能让 agent 自动干活 —— 干这么烂还想自己做主？想得美！</p><p>坐对面的黑哥叽里呱啦说啥呢？能不能先把裤子提上啊。</p><p></p></blockquote></div><hr><div class="diary-entry">02:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTAR4YM808FGVNB11VN711HQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>一个自然段拆成多个单一句子的 AI chatbot 是哪个？最近老是看到这种形式的文章，说实话有点烦。我也很难说清具体是什么让我觉得这些文字并非人类写的，但就是有这种感觉 🤔​ 好奇怪。</p><p></p></div><hr><div class="diary-entry">14:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTC3GQB40851PEMSENRFC6W8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前和亲戚问能不能推荐个工作给我。他把这件事告诉我母亲，然后我母亲来了句，「不要工资。」</p><p>不给工资我干屁啊，我特么吃啥啊 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 我找的甚至都不是同专业的工作。现在我也不需要无薪实习来美化简历了虽然。</p><p>这就特么让我想起初中时母亲不知道哪根线搭错了，让我去她朋友开的中餐馆里打工。假期一天站到晚，下课了放学了也要过来上到晚上。一个月工资猜猜看多少，500！这 500 块还被她说是「会赚钱了该交房租了」，给收走了！天热了期间她还要求我不能拿可乐喝，因为她觉得可乐比水贵，拿走喝对不起她朋友 —— 她觉得我应该对这份工作感激涕零！我感激你个鬼！</p><p></p><blockquote class="diary-thread-reply">14:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTC3WH4Z4PQN54JS0ZJDDB1W" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>然后聊到说我母亲会和上层圈层社交接触，我没能遗传到这一点 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 干屁啊，现在家里认识的很厉害的人，不是特么远房亲戚吗，跟你和上层圈层接触有毛关系啊。美国你开家餐馆做久了买房买车确实很容易，因为没有市场去刻意炒这玩意儿，但也同样的，买多栋房子多辆车，就能标榜自己是上层圈层了吗 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 中央公园西边的老钱们要笑了啊。再说了，你个狗屎之前天天嚷嚷让我退学、去餐馆打杂一辈子赚钱给你花，你可不是这个嘴脸啊。当初骂我学习也是白学的是不是你，当初叫我不要上大学的是不是你，骂完我又骂我不如别家小孩的是不是你 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 好话烂话全给你说完了，你是最仁慈最善解人意的母亲 —— 滚蛋！</p><p></p></blockquote></div><hr><div class="diary-entry">14:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTC4RCW709SNEZKB9M06HDNP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>本来生气着想到往日种种，这个那个的事情。手机弹出个邮件通知，发现里面出现了那个讨厌鬼的名字，一下子更生气了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 朋友们常说我身边总是有各式各样很诡异的人，让我开始反省自己是不是也是个诡异的人，导致出现了同型吸引……</p><p></p></div><hr><div class="diary-entry">21:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTCVT2F6715S6GF5P42R2HBM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天…… 想要试试和室友一起…… 跑去买菜…… 然后…… 晕倒了呢…… 明明配速…… 只有 12 分钟一公里…… 哈哈…… 被许多好心人帮助了……<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​</p><p></p></div></details><details data-group="diary_sections"><summary>六月六日</summary><div class="diary-entry">12:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTEEVBYQD3PW2G1BZY7VVAHH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>没检查 VPS 的状况，导致昨晚 disk 满了。早上一看发现看不了 Fediverse，赶紧坐起来修复。结果都是不用的 Docker 残留物，一直没有清理导致的。先前从 Sourcehut 转移到了 Forgejo，但折腾一半就去做别的事情、忘记处理后续了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4EE8WQ7Z323BCGBCMRHS.png" alt=":ottersgottaott16:" loading="lazy">​</p><p>因为读了些博友的文章，对过去游玩但不记得名字的 Flash 小游戏又产生了想要再去寻找它们的热情。结果 Kagi 优先跳出来了 7K7K，我先前在 4399 找了半天的游戏，竟在 7K7K 找到了。游戏是 <a href="https://www.7k7k.com/flash/17458.htm" rel="nofollow noreferrer noopener" target="_blank">《妖精城堡》</a>。</p><p>记忆里还有个没有找回来的，是密室逃脱小游戏。主人公出现在一个洋房外面的迷宫中，需要找到园艺剪跑到洋房内。洋房的大厅中央有个很大的银色男人侧脸画像，有点像名侦探柯南蓝色古堡的那集，画像后方是秘密通道。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KTEEG1FHG3SCVT2XRVWD4NRW.png" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">13:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTEJGAH78TC9V1X7W1Q411W0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说到 4399 和 7K7K 这些平台。我小学二三年级，也就是 2013-14 年的时候，借住在一个酷爱恐怖故事的同学家里。他家是做小餐桌、辅导班的，有个角落堆满了书，也包括了许多恐怖故事的杂志…… 他父亲作为一个老师，印象里藏了本恐怖故事集，被我翻出来了，第一篇故事讲的是「杂货店饮料柜下的怪物」，然后主人公用什么，芥末吗？在地上画了个圈，怪物就不敢过来。还有本故事集，里面有篇故事写的是《致命 ID》的剧情。小时候的我看到人头在洗衣机里滚动这一幕，真的是……<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3R99C17MNJ5X7674S7J2A.png" alt=":neocat_x_x:" loading="lazy">​</p><p>说回 4399 和 7K7K 小游戏平台。当时那位同学都不知道从哪里找到的，找到了一堆说是游戏，但其实全都是恐怖小电影的玩意儿。里面有一款印象深刻，说是有一户小区人家失踪了，警察就进屋找。在黑漆漆的客厅里找到个尸体还是啥，然后发现厕所里有动静。警察小心翼翼走过去，到厕所一看…… 啪一个鬼脸，让那时候的我不敢一个人上厕所。</p><p></p><blockquote class="diary-thread-reply">14:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTEMXWZA0H5N2B8AGXZ2AHBF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>再就是美式的血腥小游戏也有很多吧。不说大便超人这种纯猎奇的，印象中玩过许多虽然卡通角色还算可爱，但是动画和表现都非常血腥、令人不适的游戏。比方说撕脸皮啊巴啦巴啦这些，难说对小时候的我有什么影响，但应该没少重复游玩。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">12:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTEFYSPAH5EA1967THQ17SVY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这个怪兽博士很萌很可爱啊。</p><p>7K7K 的链接： <a href="https://www.7k7k.com/tag/943/" rel="nofollow noreferrer noopener" target="_blank">https://www.7k7k.com/tag/943/</a></p><p>不过这个链接只有 1 和 2 集。</p><p>可惜的是游戏里的 3wish [a] com 已经死掉了…… 但找到了个 <a href="https://en.namu.wiki/w/3wish.com" rel="nofollow noreferrer noopener" target="_blank">Wiki 网页</a>。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KTEF9MW5NV1VXHCP4F1G7G4K.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">13:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTEJW6BA9Q3YYHRH8BA28H1W" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>感觉这《白兔历险记》后面就没几个是真原创啊。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KTEJSSRZC9BB1YCA70HJVQG2.png" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">13:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTEKCJD65FAN2HNC7QXG9PE8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>啊想起来了，这东西根本就不是白兔，原本是个绿的。</p><p>搜了下名字是 <em>Easy Joe</em>。</p><p></p><blockquote class="diary-thread-reply">13:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTEKN4AVV4GF7VFY8F8X0WQZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><a href="https://www.thealmightyguru.com/Wiki/index.php?title=Easy_Joe_(universe)" rel="nofollow noreferrer noopener" target="_blank">https://www.thealmightyguru.com/Wiki/index.php?title=Easy_Joe_(universe)</a></p><p>竟然有四部。</p><p>伪原创、山寨你害人不浅啊。非要让我玩劣质破小游戏。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">14:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTEKZBTR3R9NA9BC8B0T4RG8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我何时能玩上完整版的你……</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KTEKY9YDTGXP0XT4FFB8RG3R.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">19:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTF6NHTFSH8YK3V3SH9FC7XK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前几天忽然发现自己的简历上，有个数字写错了，导致工作经验少了足足一年我的天啊 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">19:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTF7ZYHQTMF12XGJKQGXNXKR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>那我之前投的 60 封简历不都是错的吗，我靠。我对自己彻底服气了。错误的简历搞得我像是刚入职两个月就被炒了，接着空窗空了一年的人。</p><p></p></blockquote></div><hr><div class="diary-entry">21:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTFEM03M41P407DNQKQNXJCD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这几天注意力时常涣散，就会骑车去打游戏。因为现处的级别，正在学习更进阶的手法和配置，从而也终于是听到了过去练习底力玩的核曲外的歌曲。我听核都要听烦了…… 事实证明，听喜欢的歌、玩这类节奏游戏会非常开心与快乐，尤其是作为一个喜欢 Vocaloid 歌曲的玩家。</p><p>然后玩到了这首歌：来自 はるまきごはん（Harumaki Gohan，春卷饭）的 <em>Zero Talking</em>。</p><ul><li>官方 YouTube 链接（当然是指向 Invidious 的了）： <a href="https://invidious.nerdvpn.de/watch?v=2INYgH-Gcjk" rel="nofollow noreferrer noopener" target="_blank">https://invidious.nerdvpn.de/watch?v=2INYgH-Gcjk</a></li><li> 谱面确认： <a href="https://invidious.nerdvpn.de/watch?v=Oao-99sxfcM" rel="nofollow noreferrer noopener" target="_blank">https://invidious.nerdvpn.de/watch?v=Oao-99sxfcM</a></li></ul><p>当时对这首的印象是，歌挺好听，尤其是跟着旋律玩的时候。然后到最后高潮的部分，MV 上突然出现了女孩们在接吻，瞬间引起了我的注意！再次查看谱面的时候，发现谱师在那一段还很巧妙地画了个爱心，以及带有保护套的 BREAK，击打时会发出「啵」的声音，正好和歌曲中二人接吻时出现的「啵」声吻合 —— 谱师的小巧思啊小巧思~</p><p>让我联想到了另一首歌，是魂音泉的 <em>Paradisoda</em>。中间有一段是会出现打开碳酸饮料瓶盖的「啵」声，谱师也使用了带有保护套的 tap 来发出同样的声音。</p><p>谱面确认： <a href="https://invidious.nerdvpn.de/watch?v=k1XXDOZ5b1s" rel="nofollow noreferrer noopener" target="_blank">https://invidious.nerdvpn.de/watch?v=k1XXDOZ5b1s</a></p><p>顺便一说这个 MV 里的 Lime &amp; Lemon 熊好可爱…… 嗯？<em>Lemon</em>？—— 那一天的忧郁、忧郁起来~！那一天的寂寞、寂寞……<em> 呃啊！</em></p><p></p><blockquote class="diary-thread-reply">22:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTFJ0GHJ3TN4P3KR9XRK85NK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>虽然我本人是很喜欢姐妹百合的，但希望同样喜欢姐妹百合的人不要传谣说「sis 也有『女朋友』的意思」啊 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​ 它没有这层意思！</p><p></p></blockquote><blockquote class="diary-thread-reply">06-14 22:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV446X1S69KHB4AN0QZ21X59" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>让更有音乐天赋的室友听了下 —— 毕竟是初见节奏天国手鼓关就完美通过，还会扒谱、参加过乐队的女人 —— 她给出了让我这个音乐白痴听后只会觉得「哇好厉害呀」的看法。</p><p><em>Zero Talking</em> 的旋律是很好听的，但她发现春卷饭在一首歌内使用了温柔的木吉他和非常非常近的鼓点，还有她觉得听上去像大粪的合成器，导致听上去很割裂。比方说开头木吉他弹完，就突然出现了离听众很近的鼓点。</p><p>因此她一个没有听过春卷饭的歌的人，推测这首歌是春卷饭的一次尝试。为了验证这个推测，我们去听了春卷饭以前、最近的歌，包括他最火的 <em>Melty Land Nightmare</em>。结果发现，这种木吉他 + 电子乐的组合几乎见不到；<em>Melty Land Nightmare</em> 直接使用了电子吉他，所以听上去非常协调；其他歌曲，例如 <em>Empurple</em> 有用到应该是非洲鼓的乐器，但和其他乐器的配合也很和谐。只有 <em>Zero Talking</em>，她觉得乐器的搭配很糟糕。</p><p>不过这依然不影响这首歌的高潮部分，还有大小姐「ルルル」的那一段很好听。我们发现副歌只使用了木吉他。因为写歌往往都是先写最好写的副歌，所以我怀疑鼓点和合成器都是春卷饭最后才加的。</p><p>总而言之，室友觉得这首歌是个失败的尝试。</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>六月七日</summary><div class="diary-entry">03:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTG392VPZ4ZA0AWR3A76Z4ZH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 翻看 Instapaper 发现存进去的文章都是 AI 工具相关的。总感觉自己一直都在听、读、写同样的东西，赶紧清空清空。</p><p></p><blockquote class="diary-thread-reply">04:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTG4F53EC1YARKR5RV1J14D9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说实话这些天的注意力都好容易涣散…… 根本的原因还是自己不想要做现在的事情吧。项目和学习都要和破 AI 工具打交道，投简历投了一大堆但没有半个 hearback，mentor 得等对方的回应、而我又很讨厌做这些事情，除了很烦的朋友外其他朋友都没有空…… 其中有个朋友在和我遭受类似的摧残…… 打工还因为夏天不忙，不咋叫我去了。</p><p>总之就是特别想出门玩游戏 ——！享受音乐、节拍和旋律～</p><p></p></blockquote></div><hr><div class="diary-entry">13:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTH579RR34M1NBBTP3GZCQ4Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看视频时看到的弹幕：「24 岁快奔三了所以是中登。」</p><p>…… 不至于啊！<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 24 不是刚大学毕业没几年吗。你 30 也不至于变中登吧。</p><p></p></div><hr><div class="diary-entry">13:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTH5Z5XCGD658R0Z23WMHX56" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这几天父母家的院子里时常被浣熊们入侵、搞破坏 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3DWCVA2CPCGYZ1FSHS79X.png" alt=":wolf_mad:" loading="lazy">​ 这东西太坏了。不过浣熊印象里去年还是去去年就在家附近游荡了，现在怎么突然这么活跃？</p><p></p><blockquote class="diary-thread-reply">06-10 03:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTQSHY5W8XPEFCDHEYJAFQ24" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>母亲说要拿摔炮炸…… 炸死浣熊？？</p><p>快住手啊 —— 你那个是过节时小孩子丢地上玩的摔炮啊！</p><p></p></blockquote></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">蟑螂相关。应该…… 是很恶心的描写吧。</summary>        <div class="diary-cw-content">14:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTH7TRV8RM6XFKYPFBHPNPCY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我做了白日梦。我梦到自己在家里看到了蟑螂，然后将其拿了起来，放在手心里把玩，并对其…… 产生了怜爱之情，好似我与它互相理解了。这种感觉和我过去幻想我的螺是一样的。过去我对螺有了想将其放入嘴中、感受它的冲动，在这次的白日梦中，我也产生了这样的冲动……？不过梦中我没有那么做，而是把它用手活活捏死，感受着「杀生」和「死」，然后变得无比沮丧。</p><p>感觉是压力太大了吗，我为什么会幻想自己和昆虫有了精神上的连接？不过说到昆虫，唤醒了我小时候食用它们的记忆。不记得当地人取的名字了，总之是油炸的知了。非常油腻，第一次吃不敢吃，吃过后觉得还挺好吃，就是太油了。</p><p></p></div>      </details></div><hr><div class="diary-entry">15:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTHCRTF8SWXD8VV6H9K57NZV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今儿计划和难兄难弟出去玩，一同将对 AI 工作流的愤怒发泄在洗衣机上。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">《春嵐》解析、长文相关。</summary>        <div class="diary-cw-content">20:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTHWNJYPA5FW6M0MGZVS331F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>BiliBili 频道主「不会特效の点缀星空」有在做 <a href="https://space.bilibili.com/1792961650/lists/7487572" rel="nofollow noreferrer noopener" target="_blank">老曲新译</a> 项目，也就是把 Vocaloid 歌曲重新翻译一遍。原因在于，大量 Vocaloid 歌曲的歌词非常非常非常难懂。以至于，歌曲想要表达的内容，都很容易被误解。尤其是歌刚放出来的翻译，都为了追求速度而忽视了许多隐喻。因此这个项目，就是把过去的 Vocaloid 歌曲进行一次深度解析，并重新翻译歌词。</p><p>介于我是很忠诚的《春嵐》（读音读的 しゅんらん）迷，所以想要分享该项目对《春嵐》的解析。它也颠覆了我对《春嵐》的理解 —— 你根本不是合格的春嵐学家！</p><p>原视频链接： <a href="https://www.bilibili.com/video/BV1WgPMzpEun/" rel="nofollow noreferrer noopener" target="_blank">https://www.bilibili.com/video/BV1WgPMzpEun/</a></p><p>前奏开始时，就会出现一段 john 语（联想到 sasakure.UK 的「麒麟叫」……）。星空对此的解读是 stand by me, but I'll never be back，这也是大众普遍认为的解读，亦或者是顺序有变但内容不变的 stand by me. But never I'll go back。以这个角度出发，便能感受到这是和「离开」相关的歌曲。</p><p>而「春嵐」「春嵐」，中文社区更倾向于将其翻译成「春日风暴」，而非「春岚」。因为后者在中文的语境中更像是「春天笼罩山野的雾霭」，而非「春天刮的风暴」。</p><p>这首歌在日语层面上的魅力在于，它会同时使用「私」和「僕」作为第一人称，来暗指有两个「我」。</p><p>实际上，因为我对 john 的 ANGRY DOG 专辑有着先入为主的印象，所以也误认为这首歌讲的是人际关系…… 最初听这首歌时，也是因为面临着人际关系上的问题，才对歌词产生了共鸣。这也是这类歌曲难以理解和翻译的问题所在吧，歌词也容易符合另一个语境。</p><p>星空对《春嵐》的解析在于，这是 john 的自白。结合视频评论区内的一张截图，能看出 john 当时低调地进行活动，不愿意透露自己的信息，却被粉丝们「造神」—— 该说也不愧是有多个马甲的人么，但粉丝们确实也很喜欢去挖掘他的马甲……《春嵐》正是 john 怀抱着「想让人们停止妄想」的心情，而被写出来的。知道了这一点后，再去看它的歌词，就能品出另一种味道。</p><p>根据星空的解析，我们大致可以将 john 这个人分成两个角色：一个是 john，另一个就是 TOOBOE（其他马甲我就不知道了），也正好对上了先前说的两个第一人称代称。其中的「私」是虚假、却被粉丝当作神的，「僕」则是愤怒的、哭泣的、真实的自己。星空认为前者是 TOOBOE、后者是 john。但因为我对 john 这个人其实了解不深，仅知道 TOOBOE 是更商业化的身份，所以对于这个分析也算是赞同。</p><p>关于歌词中频繁出现的「春日风暴」，解析也有很多：春天的风暴虽强烈，但来得快去得也快，且走后留一地清新，意味着全新的自己；john 在网络上分享音乐，却招来将他造神的魑魅魍魉，这些魑魅魍魉便是他唤来的春日风暴；气象现象中，「春嵐」是冷暖气流碰撞引发的剧烈风暴，隐喻了粉丝塑造的虚像与真实的自己碰撞后，产生的内心动荡……</p><p>第二段 verse 里，像神明一样的「私」已经思想干枯了。虽然还是很愤怒，但也只能装成不生气的样子。尽管如此，john 还是在制作音乐，就是为了在好好听音乐的「你」。紧接着的 pre-chorus 里，一直在愤怒的「僕」决定消失殆尽。结合先前星空说的，「僕」代表 john 的话，那么也就是 john 决定放弃做 john，完全变成 TOOBOE。此次副歌中，小人的身后炸出七个身影，分别代表着 john 先前创作的七首歌 —— 我将其看成是组成 john 的七个部分。</p><p>得出上面的解析后，再来看 MV 里 bridge 段的一排排玩手机的小人，就能知道他们代表的到底是什么了。这也是我过去一直没搞懂的地方。</p><p>最后的 chorus 中，小人的面具裂开，对着镜头大喊「笨蛋！」并醒悟了过来 —— 从先前的被动，转变成了主动。星空认为，小人的面具没能完全剥落，意味着没有完全抛弃掉 john，改为二者合一。这不仅能对应上歌曲结尾的「再一起笑吧」，也能和 john 现在的情况对应上，又或者应该直接用官方名 john / TOOBOE？</p><p>但是呢，部分解析都未经 john 赞同，并不一定都是真的。不要把想象强加于创作者身上，也是这首歌想要表达的意思之一。</p><p>结尾就放一张之前给别人画贺图时，角落里偷偷画的《春嵐》MV 里的小人吧。</p><p></p><figure class="diary-media diary-media-sensitive"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KTHWM0D0WRQZ2F90YWPKHDM5.png" alt="" loading="lazy"></figure></div>      </details><blockquote class="diary-thread-reply">06-14 22:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV44EP87GA0QVE94FMCP8JBM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>关于《春嵐》的解析，我跟室友大致地讲了一下，却引得她很反感，因为她就是歌词中会认为创作者自作多情、无聊的人。她认为艺术创作不应该有任何「解读」，一旦有了，就会变得无聊起来。</p><p>这也是个有趣的观点。我倒是挺喜欢去解剖创作者们的想法。</p><p></p></blockquote></div><hr><div class="diary-entry">22:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTJ3BVW86K2ZCBXJ4QJ1K9K6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>车站冰淇淋一个 9 块钱…… 那我为啥不去买冰淇淋车，或者蜜雪冰城的，你这都是它们的多少倍了。</p><p></p></div></details><details data-group="diary_sections"><summary>六月八日</summary><div class="diary-entry">03:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTJKEY3MRGHAAY0H6JM232GR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前任跟我说，她新认识的人们在知道她和我交过往后，都会问她谁是 top 谁是 bottom。简单来说就是攻和受。起初她对于大家得知答案后的惊讶，还有新鲜感。但这种问题越来越多，她也觉得无趣了起来，尤其是这些人的部分问题，参杂着对她这个个体的看法：你是 top 的话，会更强大些；你是 bottom 的话，会更弱小些…… 但是，性行为中在上或在下，怎么可以决定她是个啥样的人呢？</p><p>女女关系中，还有 TPH 之分：T 是 Tomboy，指关系中更中性或者男性化的一方；P 是 Pretty girl，指更女性化的一方；H 是 Half，介于 T 和 P 之间。这套体系很烦人，说真的，因为它仅是用于描述人的表象，并试图以此去将性格硬套在人身上，比方说 T 会更阳刚、主动…… 再结合先前的 top &amp; bottom 一说，更没完没了了。</p><p>这些东西让我深觉烦躁的源头在于，它总是会让一般人以为所有非顺性别异性恋关系都可以「性转」，并转化成他们更好理解的样子，也就是顺性别异性恋关系：你得有个长相更男性化、性格更阳刚的主导者，还得有个长相更女性化、性格更阴柔的被动方 —— 你一定要这么做吗！</p><p></p></div><hr><div class="diary-entry">03:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTJM447ZM7JCGP3ZE6QGJA60" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天和 AI 浪潮的难兄难弟出去玩，然后打游戏。期间我们聊到 agent 和就业的事情，然后理所当然地，对行业再度感到失望…… 先前已经说过，他所在的大厂今年已经放弃从学校招聘学生，从去年开始 all in AI，岗位也都变成 senior Gen AI platform engineer。</p><p>虽然话是这么说的，但他明显感觉出决策层根本不知道自己想拿 AI 工具做什么。再就是他发现，这短短几个月来，公司已经花掉了很多很多钱。这些钱拿来招 contractor 的话，事情早特么办完了。</p><p>然后也聊了些现在市场的话题…… 能和业内人士验证自己的想法还是很棒的。不过他对于我现在投了 80 份简历都没有什么结果一事感到很惊讶，并感叹时间太快了，他以前找工作的时候可不是这样的。</p><p></p><blockquote class="diary-thread-reply">03:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTJN05WYRJZVQC0WM2P5JXDP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我们走在街道上，你一句我一句地聊着天。期间他苦笑道：「普通人在历史的浪潮中什么都不是。走一步看一步吧。</p><p>」</p><p>这种话要是讲给室友听的话，一定会嫌他无能吧。但是世界上的一般人、多数人，都是普通人，是「我」的一个个分身……「我」们到底又能做到什么呢……</p><p></p></blockquote></div><hr><div class="diary-entry">04:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTJRD5XBDB6QGGPEBT86PKZC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>竟发现 EmoCosine 做过《少女レイ》的 remix。这几天因为要玩游戏，所以没少在听这首歌。</p><p>EmoCosine 的 Future Bass &amp; Future Core 听着让人感觉很爽。不过他的这首 remix 我没有那么喜欢。</p><p></p></div><hr><div class="diary-entry">04:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTJRQ8G4KD2A6WMQAKWD75RV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>BiliBili 首页怎么老给我推送什么沸腾者…… 类似的恐怖视频。虽然我关注了恐怖游戏主播，但不代表你可以随便投送恐怖和猎奇的视频给我 😡​ 过去还在刷短视频的时候，BiliBili 也老闲着没事给我推送恐怖直播，循环放一个女人在「哒哒哒」唱歌，然后播放一堆恐怖生物的视频，就算我点了好多次「不感兴趣」。</p><p></p></div><hr><div class="diary-entry">13:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTKQ0SF6EB4XJSPW4YR9V9NY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>做了个很长的梦，涵盖了租房子、居住、被赶走、找房子、房东把整栋房子卖给我。前面还有什么，因为需要我做什么事情，所以给了我很多好东西像车子，后面则把所有东西都收走，让我感受着失去的悲伤 —— 虽然已经不记得到底给了我什么。</p><p></p></div><hr><div class="diary-entry">16:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTM0XK256G3WHQHB2H4TA1C8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>和学校的 advisor 再检查了一下简历，这次有很多格式上的小问题。介于现在已经是 ATS 大时代，简历什么的直接全变成纯文字会更好吧，少数岗位也支持上传纯文字的简历…… 过去好看的 PDF 格式简历已经不太能比得过 WORD 格式简历了。</p><p></p><blockquote class="diary-thread-reply">16:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTM21ZPCPB4TTQ32GZB0DH5D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>再就是开始投简历和找工作的频率变勤后，陌生电话可见地变多了许多。因为担忧是诈骗电话，且接了诈骗电话后会被标记成活人号码，所以不认识的电话号码一概不接，除非它发语音到我 mailbox 里来。</p><p>朋友先前换 iPhone 17 的时候，跟我讲了下代借电话的功能，帮他阻拦了上百通诈骗电话。想到国内的小爱同学，应该是类似的机制？现在很想要这样的功能。</p><p>嗯好吧，最大的问题是我恐惧电话这件事。小时候的一些小经历让我实在是喜欢不上来接陌生电话。电话铃声响起来都特别害怕。</p><p></p></blockquote></div><hr><div class="diary-entry">18:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTM6HTF1MN8TTGQ6PSMC0JQW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>被豆苗坑了。一磅 9 块钱，买两袋 23，我买一袋上海青也才 3 块钱多啊 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">19:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTM9ZH7WS4BF01MXFFB9P1G3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>家里的地板上有许多等着被我踩到、才能知道它在那儿的玻璃渣子…… 为什么我要谈起这件事，是因为室友她又忘了冰箱门上被她放了玻璃盒子的事情。</p><p></p></div><hr><div class="diary-entry">22:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTMMPH2TNAP7YAFRT9W7EBN9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>This is dumb as fuck.</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KTMMNQXT0CXEMW74E9RDCSAC.png" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>六月九日</summary><div class="diary-entry">02:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTN3VXAJ10CFAQT48JV9PMT6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不敢出门，街上挤满了看球的人。太多了有点害怕。</p><p>鞋子叔叔之前给我看他赌球玩的记录。他投了 10 块钱，赌有十个条件能达成，结果全中，10 块钱变 700 多。太可怕了这倍率。</p><p></p><blockquote class="diary-thread-reply">06:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTNHQXNQEC4TJ8M0ZEGK9CC0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>从办公室出来的时候，街道上都是人。Sports bar 内挤满了看球的人，就连外面都被他们占领。我回头望去，发现电视只是个挂在墙上的很小很小的显示屏，但人们都举起手机拍摄，并且随着球员们的动静儿而欢呼。</p><p>想要回家，但被警察拦住，得出示自己住在这条街的证据…… 我只有手机上的 Amazon 的订单有居住证明。旁边的黑人也想走这条路，但无法证明，气得手舞足蹈，而警察开他玩笑说「不要拿假 ID 给我」。</p><p>晚上和室友约好了再去跑次步，她会跟着我的节奏也慢慢来的。河边很安静，没有喧哗，夏天的风吹在脸上很舒服。水面上停着一艘艘船，有小船，也有做成餐厅的大船。我曾经在上面吃过一次饭，结果 motion sickness 导致我病了两天……</p><p>她给了我她 Airpods 的一边，我俩一起听 r-906 的歌慢慢跑步。为了不发生先前晕倒的事情，我努力专注于深呼吸上。事实证明，是应该用口深呼吸，鼻子根本吸不够。同时也事实证明，我的体能还是够跑三公里往上的。哼哼～路上还看到同样在跑步的男女，还有河边伴随着水声起舞的女人。</p><p>跑步有种魔力，让人觉得可以一直这么下去。不过太晚了，大半夜的，球场附近的警察都鸣笛赶着要回家。我和室友跑到 711 里买了个热狗，两人蹲在家楼下吃。</p><p></p><blockquote class="diary-thread-reply">06:43 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTNHYCWKPAWRJD6XV1JQS6KF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>两个人还都泡了味增汤喝。白味增不太喜欢。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">08:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTNPTC3AMW3E4ZJWKZ2XWRBG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>发现台式机里还留有大一和别人合作做的项目的代码存档，稍微看了眼，发现他们当时就开始在弄 RAG、Langchain、FAISS 啥的当年还只能算是玩具，现在已是潮流中的历史的玩意儿。思来想去，感觉框架还是挺不错的，很适合拿来重构、当作新领域的实践项目。</p><p>结果发现里面还有他们硬编码的各种 API key…… 难道门和窗户就不能兼得吗？然后又发现他们秘密写了很多东西，但没有调用，比如 Anki 闪卡生成功能 —— 这东西我根本就没有听说过要做啊我的天。还有后端返回聊天记录的接口，居然和创建聊天的接口调用了不同的模型……？为啥啊？为啥你要调用 helper 模型，但给对象取名叫 tutor 啊？我当时一直天真地以为是模型本身的问题，结果都是你们的问题吗……！</p><p></p><blockquote class="diary-thread-reply">06-10 15:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTS1399T77VAVF9452Y4Y10V" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>师傅，你把我教得太好了……</p><p>对项目进行了一次大重构，统统改用现在更热门的框架或者方案来写。</p><p>他们当时想要研究怎么让模型做数学题。结果研究半天 pre cal 的东西都做不出来，赞助商还跑了。根据他们的代码来看，感觉解题纯是靠 LLM 自己的 pre trained data 或者幻觉硬编…… 就算你用 RAG 框架让 LLM 读到了 pre cal 的理论知识，也不意味着它真能学会然后算对数吧？</p><p>我搜索了下，发现现有的解决方案也跟之前我一直说的补丁差不多：写工具让 LLM 自己去调用。LLM 要自己去理解题目、规划怎么做，要计算的时候就调工具、在沙盒里写代码运行，最后再调用工具验证 ——AI 应用层都是打补丁啊。</p><p>不过数学题也不仅仅是算数，还有证明题、几何题，巴啦巴啦。这种我搜了一圈，貌似就算用上上述的补丁都不咋稳定。还需要进一步研究研究。</p><p>之后是弄了些新东西：我一直觉得这种所谓的 AI tutor 项目，但实际功能只有问 AI 问题，或者改个提示词让它不告诉你答案、引导你作答，都有个前提，那就是用户必须先自主学习，不知道了再来问 AI。我写了个新模式，可以让用户阅读教材时，AI 在旁边陪着看、指出知识点、考试重点啥的，让 AI 更像是个老师在旁边指指点点，稍稍有点主动性。</p><p>总之现在折腾一番可以在简历上大写特写我是 <em>Gen-AI platform engineer</em> 了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 玩具项目不计数的话就去开公司，LLC 太好开了师傅，都在公司里干活了何尝不是我的工作经验 —— 奶奶的现在的招聘市场真是疯了，先前还刷到要自证比 AI 厉害的 junior 岗位。Junior 有那么多工作经验那还是 junior 吗。疯了，我也疯了。我打工也失业了。</p><p></p><blockquote class="diary-thread-reply">06-10 15:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTS1SP5RAH1TGKN1NK2JBQMJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>现有的方案都围绕着这样的补丁：</p><ol><li>模型只准做规划</li><li>模型调用工具</li><li>硬性验证最终结果</li></ol><p>开发流程中也是这个狗样子。写大量的 hook 去验证模型做出改动后的代码。就算在 AGENT.md 里写满了你不准做这个、不准做那个，agent 该变傻瓜蛋还是会变傻瓜蛋，所以需要硬性的检验。</p><p>打比方让 agent 不要在 Typescript 项目里再写狗屎的 <code>any</code> 了。仅在 AGENT.md 里写 <em>DO NOT write <code>any</code></em> 是不够的，你得写个 hook 脚本，在每次 agent 做出改动后检测是否存在 <code>any</code> 这个字儿，要是有就警告或者阻止 agent，直到它做好为止。不过 agent 的「懒惰」，会让它改成去写 <code>unknown</code>。那好嘛再写个 hook 阻止这个…… 没完没了。这还只是项目的基础要求之一。</p><p>所以说「用 AI 提升生产效率」这句话有时候看来真的是…… 不够行啊。</p><p></p></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>六月十日</summary><div class="diary-entry">06:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTR3RXC1S6DFKEC2SZ3SXNYR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKPG9JXEBDFYC9RZH0AC9PB.png" alt=":cozy_otter_face_rub03:" loading="lazy">​ 测试 agent 写网文的工作流时发现它给主人公扩写成做题狂魔了，穿越到异世界去凌晨四点睡不着去图书馆里做题。还嚷嚷道都做了十二年的题了也不差这一会儿。</p><p>你在写啥啊我服了。</p><p></p></div><hr><div class="diary-entry">17:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTS98GWWFX4TB7VD89T8371E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想着让室友帮我把头发剪短一点。</p><p>然后感受着她直接把我头发的一半给剪掉。</p><p>最终看着头发长度比我要求的还要短一截……</p><p>…… 受死吧。</p><p></p><blockquote class="diary-thread-reply">18:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTSCGSSDMRSZS5TGY5MVZMNH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>没有拍照片，头发都在垃圾桶里，总之是一坨很长很长的头发，就这么被剪掉了……</p><p>这个臭人还在说什么，自己剪头发特别厉害，真是一点都不该信她啊。</p><p>幸好也不用出门，就这样待在家里，等头发长出来吧。我对头发的生长速度还是很自信的！</p><p></p><blockquote class="diary-thread-reply">06-11 01:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTT3RHHPDC6YGGR9ZMHZ20FJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>家里有手台的朋友说可以去他家里闭关修炼。出山时不仅头发长出来了，实力还大增。笑得我……</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">23:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTSYK0X1P8NDFNE8ZPTHCAXD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>第一次用 FreshRSS 内置的爬虫订阅，这下可以订阅那些没有提供 RSS 的博客了。</p><p>我通常使用 Blog Quest 这个浏览器扩展来检测当前网站是否提供 RSS 订阅链接。如果它没有找到，我左看右看也没有找到，放在往前我就会放弃该博客网站，很是可惜。</p><p>这个爬虫订阅能顶上这个缺口，真不错，还让我重新接触了过去爱得不行的 XPATH。</p><p></p></div></details><details data-group="diary_sections"><summary>六月十一日</summary><div class="diary-entry">01:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTT3NJ564JZDA0TAZ88GR392" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>先前一直没有写的事儿。项目管理有个朋友，有天问我们能不能给我们设计点啥、画点啥，项目管理答应了。画出的结果，对于也会画画还高傲的项目管理而言，不算啥，甚至还有点嫌弃。不过那就跟我没什么事儿了……</p><p>有天，那个朋友跟他讲「你要是要用的话得找我要授权喔」，气得项目管理牙痒痒：画这么烂还这么跟我讲话！</p><p>本来以为这事儿就这么过去了，今儿项目管理发现，这朋友在自己 LinkedIn 上写，他是我们公司的 illustrator？？不是，我们没有跟你合作啊，是你以私人的名义问我们能不能画的啊，你什么时候成我们的 illustrator 了？我们官方网站上的画都没有你的东西啊，你的图我们一没有使用，二没有承认，你怎么变我们公司的 illustrator 了？？你自己上我们官网看看哪些图是你画的嘛！</p><p></p><blockquote class="diary-thread-reply">06-12 03:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTWYEWDVP3DPW24TBTP5N94Z" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>更深地了解了来龙去脉，被对方的逻辑折服了。</p><p>项目管理跟这位朋友客气过，说自己愿意免费帮他报税。这件事发生在几个月前。</p><p>之后这位朋友以「学校作业」的名义，问能否使用我们公司的品牌。类似于学校让你画个设计给某个公司品牌像 Nike 啊巴拉巴拉啥都行。项目管理就答应了，随便他用。</p><p>接着这位朋友开始在 Instagram 上发很模棱两可的帖子，说这是给我们公司做的设计。听起来真的像是，我们雇佣了他来做设计，但没有！公司的官方账户没有给他点赞、回关、转发。</p><p>之后就是在他的 LinkedIn 上发现了公司的名字，以及他写自己是 freelancer、给我们公司做 illustrator 的事情…… 但没有！我们没有雇佣关系！—— 项目管理去问他到底在搞鸡毛。结果他居然觉得，项目管理说好免费帮他报税，他回赠自己的设计，是交易关系……？是雇佣关系……？啊……？这是可以拼凑在一起的吗……</p><p></p><blockquote class="diary-thread-reply">06-12 06:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTX7FD4MST7HC9783Q9EQH7C" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>结果这两人在牛头不对马嘴的对话中，得出来的结果是该「经验」从 freelance 变成了 voluteer…… 这根本就不是有没有给钱的问题啊，我们从来就没有找对方做过任何事情。我给 Nike 随便画点啥，发网上，我就是 Nike 的 freelancer 或者 volunteer 了吗？当然不是啊。</p><p>对话里，对方竟默认项目管理找他是为了招聘他 —— 没有这么自恋的啊！</p><p>这就得说到为什么没能直接和对方把话说开：在对方眼中，我们是很友善的人。项目管理不愿意把自己非常刻薄的一面展露出来。我觉得倒是没有关系，不然误会会越来越大。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">01:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTT43Z69249JB976JJ8T3SE1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有点想入 Intel 股但是看到有大厂卖了……</p><p>我对炒股的理解只有小时候玩星猫大富翁的「跌了就买，涨了就卖」。</p><p>好吧还有美股长期放着挺不错。</p><p></p><blockquote class="diary-thread-reply">15:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTVKCCBTRQND27Y6RH40B89E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>早上起来看到 Intel 涨 10% 眼睛都直了。</p><p></p><blockquote class="diary-thread-reply">19:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTW30V5XR1AD9MEWDW4C0AQC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>大致了解了一下股票会因为什么而动荡。</p><p>科技公司的股高涨都是因为 AI 浪潮。</p><p>看 top loser 的时候看到了 Oracle，我以为它就个租云服务器的，还知道它跟 Java 有关，但去了解了下才知道它今年借了 600 亿美元去入 AI。股民全都跑了。</p><p>AI 浪潮到底是不是泡沫，我学金融经济学没那么多不知道怎么说。假设确实是泡沫，那么什么时候爆炸是个好问题。想捞钱就得等爆炸之前捞。</p><p></p><blockquote class="diary-thread-reply">06-13 00:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTZ7RJNVV008ZBWYZP0QR3X9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>就算现在 Intel 还在涨，没有买的我也要如此安慰自己：要警惕做空力量！</p><p>看着钱涨来跌去很挺有意思的。不过很容易产生 FOMO 情结，想要一直盯着这红红绿绿的表看、找新闻和财报分析。</p><p></p></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">03:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTTC1RNEHC8PX8ANS3MRAEW4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>饭后打算去河边散步或者跑步，结果听到窗外阵阵摩托车的声音，还有球迷们的欢呼声…… 太恐怖了。</p><p></p></div><hr><div class="diary-entry">04:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTTFF0QRAJ0KDMK551QKYJH0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>为什么河边的高档公寓楼下会有垃圾场的臭味？熏得我根本没办法张口呼吸。</p><p>室友给我剪的超绝短发根本扎不起来。跑步热死我了，还不如不扎。</p><p>路过桥下，黑漆漆一片，感觉有点怪，发现黑暗里站着个人，吓死我了。</p><p>就算跑了这么远，怎么还有球迷，在高声欢呼。现在可是大半夜啊。不要在马路上跑来跑去啊。</p><p>走到隧道里面，发现对面来的全是球迷。他们的声音变成了回声，在隧道里传来传去，太可怕了。我好想逃离这个世界。</p><p>这个球赛什么时候结束喔。总不能家楼下每天都是人声吧。想干嘛！</p><p>球迷推着购物车，在马路上荡起来了！他滑起来了！我的天啊！</p><p>警察在拦街，我要怎么回家喔。</p><p>死室友你快他妈下楼啊。我想回家卧槽。</p><p></p><blockquote class="diary-thread-reply">04:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTTFN7H8BZBBRRNSB4RGTB8C" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>第一次用语言输入，还可以。</p><p>跑步期间，对面来了个开远光的自行车。开远光！开过车的朋友知道远光有多离谱吧！</p><p></p></blockquote></div><hr><div class="diary-entry">13:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTVEQA49G3SYYHWS0JQ24P8E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚上睡觉手机忘充电，怪不得闹钟没响。这几天睡得晚，早上都不咋能起来。</p><p>我家里人莫名其妙把我跟几个亲戚加到个微信群里，群名还叫啥「抗日游击队」。你取个吉利点的名字给我呗。我不想要打仗啊。</p><p>昨晚拍的一些有的没的的照片。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KTVEGZ6WA9WCG5CSMDGWRX6C.jpeg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KTVEGZBQ2C00TXCTZYWSDT1Q.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">17:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTVTS1P8S4XETK0NQA3TFVN7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Easy money.</p><p>I earned 0.01 dollars per stock, risk-free.</p><p><em>I'm joking. Don't take my words seriously. I'm not an idiot.</em></p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KTVTPCC3Q1M7NR24TDCWWXQ6.jpeg" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>六月十二日</summary><div class="diary-entry">00:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTWMNVT4VV57A0X9F73K6T9A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><a href="https://trashposts.com/blog/draw-a-cat/" rel="nofollow noreferrer noopener" target="_blank">来画一只猫吧！</a></p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KTWMKXHK09SN1VEPSX5KCGXR.png" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>六月十三日</summary><div class="diary-entry">00:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTZ6TGBTNDWHE3BJ6SJV94QQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>真是惊讶，昨天我表姐生了个孩子。她比我大一岁。虽然之前知道她怀孕了，但没有想到昨天就生了娃。太令人吃惊了。</p><p>然后他们开始给宝宝想名字。除了几年前因为觉得酷所以学易经跟算卦，还有那会儿看的修仙网文，我有听到过生辰八字外，从未想过我会在亲戚口中听到这些概念…… 说这个宝宝缺金缺水，有很多火，所以小名要叫「稳稳」，让她稳重起来。为了取有金和水的名字，母亲还用上了 ChatGPT，问它什么名字有金也有水。但我说实话，都好土这些名字，我也看不出他们对这孩子有着什么样的期待。</p><p>大一时我和校友聊过「中国人的名字」一事儿。他不喜欢他的名字，觉得都是父母给他安的「期望」。他喜欢我的名字，所以当时要「拿走」我的名字。其实我的名字就是个物体，要比当时到处可见的形容词「好」得多。例如「文静」，巴啦巴啦，这些给孩子们装上的性格或者行为标签。因为只是个物体，所以想咋样就咋样了，你还想让我变成这个物体不成？</p><p>当时他还有个观点，就是他老觉得男孩子的名字都影射了父母的期望，女孩子的名字则都是景色或者啥的。他会更喜欢后者。他不知道的是，我的名字是爷爷乱取的，根本没有意思可言。这相当于他打我出生以来就没有对我有过任何期望，赞同使用该名字的其他人都是如此。</p><p>中文课上阅读过《草暖》这篇短篇小说。主人公的名字也是母亲乱想出来的。她小时候常常追问母亲，自己的名字是否有别的含义在，结果答案总是，在草地上觉得暖和，所以就取了这个名儿。</p><p>我认为期望总是要比性格或行为标签好，更比纯粹的目的性要好（参考著名的「招弟」「亚男」系列）。至少期望能证明父母对孩子的未来下了功夫，有想过他未来会是什么样儿。围绕着生辰八字取的名儿…… 我就不好说了。虽然我会算卦，但我也不懂这些。但很明显，他们在表姐生子之前根本没有认真想过孩子的名字。</p><p></p></div><hr><div class="diary-entry">04:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTZNFGKXV7F5G0W8QWGAQAD7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>要给我妹妹上网课，所以开始捣鼓 Zoom 咋用。虽然 COVID 期间天天用，但作为会议发起者，就对这玩愣不咋了解了。</p><p>我目前计划是让 iPad 通过 Airplay 连接到电脑，然后在 iPad 上打开 Goodnotes 手写内容。但是妹妹那边的设备不太明白她要咋给我实时展示。按理来说我在父母家放着的电脑，也可以通过相同的方法在 iPad 上写题。</p><p>顺带一提要辅导的是数学。她数学太烂了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">05:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTZPPG3AZXH4VZ0MP6T2499M" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我把笔记本的触摸板给关掉，想要学习如何纯靠键盘使用电脑。</p><p>结果发现许多网站的无障碍设计太差了，我一直点 TAB 都看不到我现在到底在哪里。</p><p></p><blockquote class="diary-thread-reply">05:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTZPSAWREN05DNYNF23NXP8E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>哦天啊我不知道该如何在我的 Masto-FE 里聚焦到别的 column，因为主页一直 TAB 会无限往下滑动。</p><p></p></blockquote></div><hr><div class="diary-entry">05:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KTZRTSCXXJZT44XYKC0BP5RE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前些天出门，意识到自己因为过分在意记笔记，导致没能推进阅读量，所以选择直接在地铁上阅读 <em>The Absolutely True Diary of a Part-Time Indian</em>（对这本书我到现在还没有重温完）。以前是睡前给室友读故事时才会读这本，但平日根本没有这个时候，所以不管她了。</p><p>书中有个 geek 角色，geek 到让主人公觉得会和计算机做爱。以前看这个角色还觉得没啥，现在看发现特别有趣。他拉着主人公到学校的图书馆内，并告诉主人公，这里的书虽然看上去很少，但你读书得读三遍：一遍是直接读完，感受文字的 mood；一遍是将文本和历史关联上，搞明白为什么作者会使用这个「词」；一遍是…… 书中没有明说，但我在网上看到类似的理论，说是搞明白文本为何和我们有关、为什么我们读了这个文本会有某某感想。</p><p>为什么之前不知道这个理论呢！先前的中文课上，教授就常带我们过一遍「第二遍」，即为什么作者会使用某某词汇、成语，例如《大闸蟹》里的「脑满肠肥的南方大地主」。</p><p></p></div><hr><div class="diary-entry">19:00 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/971486469394186348" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Princess skeleton found in the office.</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/b5862bd14-4506fa/v0zLSGnwXGBv/vEOFpSDgyudApjnDtrriuP8ff4gbVikuRWsWk6aH.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">19:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV15YHDZREJ5E2EFAHWTHKQJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>开开心心打算买可乐喝，结果一打开发现……</p><p>最终忍痛买了 pepsi。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KV15XSGRKHNYBS7YN8267D6A.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">20:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV19VJ399M7ND2SC55JRVVFG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我最近在系统性地学习税务知识，这让我意识到我之前的「学习」一路通顺是因为我对正在学习的领域很感兴趣。税务知识目前在我看来，是相当枯燥的，让我看了便觉得很想困觉。我无法让自己硬撑着去学习，所以很想要搞懂它有什么地方能是有趣的，或者将它转化成我能理解的框架 —— 哦天哪，我会变成那种很烦人的「用计算机知识解释一切」的 tech bro！好吧，我尝试过了，学科太不一样了，不能相提并论。</p><p>室友是学习税务知识的，并觉得这东西很有意思。她有段时间找我学习编程，然后连一天都没有撑下去。我觉得很有趣的东西，她会觉得无聊；反之亦然。但我不会说她是蠢蛋，连个 Python 都学不会；倒是这家伙儿会觉得我脑子有病、蠢得要死。她真讨厌啊，哪天我要在她的饭里下老鼠药。叽叽叽。</p><p>我也学习了如果使用 TaxWise 这款大便软件，到处都是补丁的痕迹，真是太大粪了。</p><p></p></div><hr><div class="diary-entry">23:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV1PH4V9W94EXNAYRCJ8SPG7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://news.kagi.com/s/zx67kq" rel="nofollow noreferrer noopener" target="_blank">https://news.kagi.com/s/zx67kq</a></p><blockquote><p> 攻击者通过接管废弃的软件包并更改构建文件，在安装过程中拉取恶意的 npm 有效载荷，从而对 Arch Linux 社区运营的 Arch 用户软件仓库（AUR）发起了攻击。</p></blockquote><p>下游也在被影响啊。</p><p></p></div></details><details data-group="diary_sections"><summary>六月十四日</summary><div class="diary-entry">00:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV1RHEBQ87SBJH9CQ0DQ3932" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>狗骗子 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ496Q8A4XAZF9TK81RAX7.png" alt=":ottersgottaott10:" loading="lazy">​</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KV1RFGK74T6Y93TMPMT372RJ.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">06:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV2BEG1NAY7VVVCGKW0N4JZ8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天也去跑步了，跑得比之前快一些，不过还是会有岔气的情况。然后我发现…… 我不会同时用鼻子和嘴巴呼吸……</p><p>今天 Knicks 也赢了呢。这个区域的球迷们还要狂欢一两天。偶尔热闹下挺好的，不过看到马路上都是垃圾，有些担忧。</p><p></p></div><hr><div class="diary-entry">17:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV3J9ESBVAYR7CAB6CWMY415" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有点空闲时间，想要修一下我一直碰上的 Stalwart 的 DMARC 问题。结果发现上游把整个架构重置了一遍哎。完蛋，有种不详的预感……</p><p></p><blockquote class="diary-thread-reply">17:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV3JCGFZ9ANCVFC031RMPNP4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>以前的 Stalwart 有个我特别想吐槽的 admin 密码明文存储的问题。不知道这些更新里有没有修掉这个问题。</p><p></p></blockquote></div><hr><div class="diary-entry">23:43 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV489CB8A6NVEWKM1M3QGW90" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>突然想到了「网文」。我看的网文不多，看的第一本应该是女同性恋网文，但是剧情太狗血了，每个角色都能失忆两次，也就是总共多于十次失忆！结尾还洗白了个强奸犯，甚至给她配了个对象！呕呕呕 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4EE8WQ7Z323BCGBCMRHS.png" alt=":ottersgottaott16:" loading="lazy">​</p><p>另一本印象比较深的百合文，主要讲的是女主角穿越到各种小说里当「恶毒女配」，但反而激发了原小说里的主人公的「病娇」属性…… 这本让当时很喜欢病娇属性的我很是喜欢。至于现在的我嘛…… 我很怕病娇啊，尤其是前不久刚看了 <em>Obsession</em>。</p><p>高中时被朋友推荐去看了男性向的《诸天尽头》。这本太长了，经常被我读一点就弃掉。</p><p>下一本被我读完的是女性向的修仙文《我把全修真界卷哭了》。这本我的评价挺高的，不过部分朋友听我讲的，都嫌它拖。这部分朋友也包括某个无时无刻都在二倍速听 AI 读知乎文的那位；他说的「拖」基本上等同于普通速度。</p><p>我小时候也写过小说。但我很快发现我是更喜欢写设定的那种人，所以放弃了。最长的一篇也只是两万字，连大纲都没有。唉……</p><p></p></div></details><details data-group="diary_sections"><summary> 六月十五日</summary><div class="diary-entry">01:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV4EZQ52J2TTT3BPRA9Y09RB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>总算是把今天要学的东西学完了！看着老白头给出的 filing status 例子，不知不觉想象起可能会有人为了更好的 tax situation 而大打出手，尤其是和婚姻相关的。</p><p>昨天学着学着突然意识到，去年有个收入今年忘记报了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 明年得补上。</p><p>周日泡在 WeWork 里很爽啊。都没有人。工作日过来，有时候会被该地点的 community team 那糟糕的音乐品味震慑到：别在办公室里放 K-pop 啊，我讨厌 K-pop。周日放的歌就正常很多。</p><p>WeWork 的装修风格非常适合泡在里面，除了打工人必备的办公座椅，还有舒舒服服的沙发、很漂亮的画作。女厕所里还有 August 牌卫生巾，这东西谁用谁知道。最重要的是，WeWork 自主贩卖机里的可乐，一罐不到 2 美元！这在曼哈顿中城实在是太难得了！</p><p></p></div><hr><div class="diary-entry">01:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV4F9W31CGT6MEA49K2ZAHRE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>火车站附近的 B &amp; H，路过好几次了但第一次进去逛，发现里面别有洞天 —— 好大哇！</p><p>买了个一直都想要的手柄和交换机。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KV4F6XQDBB1RK8XCMF3R7D8K.jpeg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KV4F6XSHK6FMSMPZ38364HS3.jpeg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KV4F6XTNFYVAJBQEXCX5PZD4.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">03:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV4MHSCXZGJJGRYDR453ZMKS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>听着 WeWork 里播放的歌曲，忽然意识到我无法立即听明白这首歌在讲什么语言。</p><p>想到我的不完全正确定论，我仔细听了下，发现果然是中文歌。</p><p></p><blockquote class="diary-thread-reply">04:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV4QSBB1F59FPXSW5TKETKAH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>出来发现外面正在下雷暴雨…… 而我没有伞。看了眼天气，貌似这周会下很多天雨，也就是夏雨吧。</p><p>热了就要下雨，下雨就要变热。所以雨后温度还要涨。哪天涨到 40 度把我晒死算了。</p><p>几个月前还有空重绘个人主页的时候，有想过给自己画个形象放在城堡里。当时想不到画什么好，现在想要画成一条鲨鱼。</p><p></p><blockquote class="diary-thread-reply">04:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV4RH2GC7K00X9Q7GMZG70AV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我被雨困在了外面，任由雨滴随着狂风打在我的脸上。</p><p>没有事情做所以我开始想为什么税务知识对我来说这么难学进去。这个老白头教学的方式是把细节扣掉，先和你讲大致的框架：什么条件下会触发这个事情，至于这个事情到底是个啥，未来再说。</p><p>我发现我在学习期间经常去思考，为什么会这样、你这个事情到底是个什么事情…… 我把这些疑问交给已经是税务大师的朋友，他却告诉我说能搞懂这些的是税务师，不是做 data entry 的会计师，叫我先别管。好吧，可是我在用报税软件的时候，就因为很多东西没有搞明白，所以用起来云里雾里的。</p><p>我又换位思考了下，发现我作为一个写代码的也不曾思考过代码的最底层都是什么。虽然后来学了点汇编语言相关的知识，但也不够解释。谁让我真正是用 Python 这个高级语言入门的编程呢，我现在都没有弄明白指针是什么东东，只会调破包。</p><p>确实，搞明白的话我就不用做码农了，可以升级变成其他岗位。</p><p></p><blockquote class="diary-thread-reply">04:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV4RY280HRQ3HCZGPW22WNC2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友想要学习 Python 的时候，我给她推荐过一个 Python 入门视频。那个视频做挺用心的（不过我印象里只有头几节是很易懂的，之后的就是直播课录像），会从计算机的原理开始讲起，让作为计算机白痴的室友也能搞明白内存、CPU、硬盘都是干什么活的。</p><p>不过她学了一点点就没有再学了，无法验证我教 Python 的方法是否正确。毕竟人还是要给自己找 plan B/C/D……</p><p>顺带一提我的 plan Z 是站在麦当劳门前给别人开门、讨要零钱。</p><p>这种从根源开始学习的方式，我想更能建立好学生的基础。有了基础后，有些更抽象的内容都可以自行想出来。</p><p></p><blockquote class="diary-thread-reply">04:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV4S4QB6T8A4XHVF2XRZ8YCD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不过这也是用编程的思想去硬套税务。学习税务期间我感觉自己只是在记些硬编码的东西，更像是在背法条。我的记忆又很差，根本背不下来这些东西…… 小时候因为一晚上都背不会《秋姑娘》（应该是这个名字）、完成不了语文作文，被打好惨喔。这些东西为什么非要背不可呢？明明真要用的时候只要查就够了。面试也是，非要背这个背那个。</p><p></p><blockquote class="diary-thread-reply">04:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV4SWZZ3XPZ1B2AQ64B34A27" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说到背，又想起小学的时候刚学乘法口诀，当晚便要求全部会背。次日不会背，又被教训了…… 以及语文课要求背，不知道是不是注文的东西？记忆里是字母表，但是字母不念拼音，也不念英文那套，而是念我完全不知道是什么的东西。这东西我的监护人不知道是什么，现在的我也不知道是什么，只知道它是用在字典里的玩意儿。那会儿的次日果不其然又被骂了。生气的是，这套系统只出现在一堂课上，之后我就再也没有见过它。</p><p></p></blockquote></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">03:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV4P6GV0G5Z36VH8SS56HTJM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在小十一的 <code>home-manager</code> 里添加了 <code>services.gammastep</code>，借此来解决 TN 屏幕太瞎眼的问题。</p><p>虽然调得有点暗，但不会太亮，就够了。</p><p></p></div><hr><div class="diary-entry">04:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV4QHMFZHK02RQ4TQXX3NFPW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这马画得真好啊。寥寥几笔却能画成这样，抓形好了得呀。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KV4QDFM06B7YPR5RKE7MHC1N.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">14:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV5WKW1B9RJEH3E1KT95JKCZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>偶尔会刷新的每日任务：找不到眼镜。</p><p></p></div><hr><div class="diary-entry">16:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV615QDSBZ3X6E7GJPP83G7Y" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Judas（背叛的「犹大」，用英语来和另一个门徒 Jude—— 也是「犹大」，原文是同个名字 —— 分开）在听道时常常会听到，在创作上也时不时会看到他。虽然不喜欢宗教，但我喜欢宗教的故事，以及它延伸下来的各个象征，例如最著名的「背叛」主题。</p><p>不过我不记得黄色雨衣是出自于哪里了。印象里我读圣经的时候没有这样的描写。</p><p>最初 Judas 的形象就是背叛了 Jesus 的恶人。<em>Gospel of Matthew</em> 里增加了 30 银币和他上吊自尽的桥段；<em>Gospel of Luke</em> 写 Judas 被 Satan 入了心；<em>Gospel of John</em> 把吻的部分去掉，改为 Jesus 喂饼指认 —— 因为每个福音的作者不同，也能看出他们会如何看待这个事情。</p><p>之后诺斯底运动爆发，对于圣经的全新解读层出不穷。对于诺斯底主义，它的大概观念便是精神是高级且善的，物质是低级且恶的，能做出物质世界这种充满痛苦的地方一定是低级的造物主（旧约上帝）干的。而人有着至高神的一部分，只要获得了 γνῶσις（gnōsis、诺斯底、灵知、觉醒的知识）便能觉醒，死后灵活脱离肉体。因此 Jesus 这个角色，对于诺斯底主义来说并不是传统的为罪人们赎罪，而是作为先知来唤醒世人的 γνῶσις 的。</p><p>这便带来了 <em>Gospel of Judas</em> 这篇经典诺斯底文本。既然有 γνῶσις 的人死后才能脱离低级的肉体，那么 Jesus 也得想办法死去才行。这篇文本里的 Judas 摇身一变，变成了 Jesus 的助手、是受启示才背叛他、好让他快死摆脱人性。不过这篇被刻意淹没，直到这个世纪初才引起讨论。</p><p>到了中世纪，Judas 这个角色被添加了很多很多很多受古希腊神话影响的设定，比如他曾杀了父亲、娶了母亲，还杀了哥哥……</p><p>到 19 世纪起，法国作家开始思考 Judas 的人格与动机。这里便包括了 Judas 因 Jesus 没能反抗罗马、失望后才出卖他的设定。我认为这和上一条的本质很相似，都是创作者们硬把自己感兴趣的领域往人家头上套。</p><p>20 世纪的文学与影视里，Judas 的定位很忙，不过还是往非传统塑造的方向走。</p><p>其中，太宰治的《越级申诉》（AKA 我一直想读但昨天才读的）提供了非常…… 别扭的…… 情感方向，即 Judas 的背叛是出自于「对 Jesus 疯狂的爱和崇拜」。因爱得不到回应所以转为恨，要亲手杀了 Jesus 然后自尽 —— 天这太阴湿了。</p><p>Flower 版的 <em>Lower One's Eyes</em>（特别指出 Flower 版因为我对 <em>Project Sekai</em> 不熟）借《越级申诉》的设定，将二人性转了（Magdalene 也被性转了啊！）。不过虽然《越级申诉》听上去 gay gay 的，但 Judas 的幻想里是他和 Jesus 都娶妻子、大家一起住在一起，其他门徒都滚。可是看他对 Magdalene 的态度，Jesus 要是真娶妻子了指不定是什么样儿呢……</p><p>不得不说宗教方面的译名常有很大的出入，最好的方法还是改用英语来指谁是谁……</p><p></p></div><hr><div class="diary-entry">16:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV61R09KDJX0F0ZKXKWC06SW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这个月发现 PiliPlus 用起来很不舒服。视频常常看一半画面便卡住，需要手动重载视频。现在看东西一卡一卡的，可能是网速问题吧，但我用官方客户端就不会这样。第三方客户端终究还是有限制么……</p><p></p></div><hr><div class="diary-entry">17:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV647WNKXKJCPV6TTKH6QS19" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3FZ75C9HA8Q3KRW12YT3F.png" alt=":neocat_cry:" loading="lazy">​</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KV646NZ9PFQ39BBARREDQWEA.png" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">17:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV64MPY8X53MS0PJ6N82W9CB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>虽然不是第一次被挡住，但之前的还能访问「关于」页面找联系方式，这次的这个「关于」都进不去，文章的留言板也因为网络错误用不了…… 放弃了。</p><p></p></blockquote></div><hr><div class="diary-entry">17:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV655ETEE1P54QB51TP939JA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>后悔因为无聊买了 Figma 的股。跌跌跌跌。直到 AI 泡沫破碎，它才会回来吧，现在都在说它能做的事情不如 AI 随手生成的 —— 当然我不这么认为，倒也不妨碍一般人们咋想。总之 Figma 的股票很烂，现在看来。</p><p>我的其他钱拿去投 Moomoo 了。<em>Moomoo～</em> 看着还不错。</p><p></p></div><hr><div class="diary-entry">21:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV6JV467D5DWAB6T9PWKVFZE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前想要去 MUJI 买点纸和橡皮，因为我先前在 Amazon 上下单了铅笔，却发现忘了买橡皮…… 还有画画本。</p><p>根据过去的印象，我以为 MUJI 只卖文具和懒人沙发。今儿过去发现它卖很多东西，小到味增汤和饮料 mixer，大到各式各样的厨具、家具。</p><p>我买了些用来升级活页本的纸，结果发现它们的洞，和我的活页本不匹配。除非再买个 MUJI 自己的活页本，不然就得拿过去退货了。悲伤啊。</p><p>然后买了个 card holder，想要装点卡。但是买完后室友才告诉我，这只能拿来装名片，我的那些卡根本装不进去。好吧。</p><p></p><blockquote class="diary-thread-reply">06-16 04:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV7C7N7F9QABWVN8B8WM0SWY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>是我想当然了。我的活页本买的是 6 环的，MUJI 的纸都是 20 环。前者在欧美很常见，后者则顺应了日本的 JIS 工业标准。</p><p></p><blockquote class="diary-thread-reply">06-16 04:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV7CKBPV3TPRNEFC077CN7CF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>借自己的好奇心又去搜索了一下。</p><p>6 环系统多用于欧美的个人规划本传统，定位是写手账、日程规划、生活管理等。可惜我没有这些习惯…… 我更习惯把它们记录在手机上。再就是 A5 要随时放身上，太大了。</p><p>20 环系统的定位则是写笔记、自由书写、日常消耗。对比 MUJI 的价格，确实能够随意消耗。我也才知道在 JIS 里每个尺寸都有自己的固定孔数，例如 A4 是 30 孔。</p><p>这样一说，又想要去买个 MUJI 的 A5 活页本。</p><p></p></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>六月十六日</summary><div class="diary-entry">00:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV6Y67R39ZEH1273CDTNHN1D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>《决战次世代》里的双蝶刃真是个完美的武器。</p><p>我听到有人说美羊羊因为双蝶刃，所以后面要还债用虚幻镜就想笑。当时看《奇妙大营救》发现这个武器连狗小兵都打不过真是服气了。</p><p></p></div><hr><div class="diary-entry">01:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV70MEHWDJY6PWAJ9WGSCBYW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 昨天修 Stalwart 的时候忘了我还写了个配置补丁，导致 Stalwart 的 <code>catch-all</code> 配置没法用，所以有段时间的邮件收不到。</p><p></p><blockquote class="diary-thread-reply">06:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV7J10C21TV23J984C16K2XR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>每次碰这个 Stalwart 我的邮件都要消失一次是吗。</p><p>升级到了 <code>0.16</code>，结果新账号的 ID 跟旧账号的对不上，烦死了。</p><p></p><blockquote class="diary-thread-reply">20:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV92JKN9ZZM29SDV876CPW03" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>邮件又回来了！</p><p>我再也不想乱碰 Stalwart 了。</p><p></p><blockquote class="diary-thread-reply">21:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV94M840E5N2JTMWX4529EX3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>日历和联系人数据也回来了。</p><p>顺便终于知道了月规划纸咋用…… 虽然有点晚了。</p><p></p></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">01:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV727F4M60NNNKBGCJV5RG6T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>过了三年亲戚们终于开始想办法去处理抑郁的表妹为什么很怕高中的事情了。这三年来他们做了：</p><ul><li>辱骂表妹有问题</li><li>想办法找人试探表妹</li><li>给表妹驱魔</li></ul><p>我现在也才知道她去上高中时被段长无缘无故打了。虽然我不知道段长是什么职位，但应该是学校里的领导层吧。回家后一直在哭，不敢再去学校、在家里上了两三年的网课。</p><p>问班主任怎么回事，这个烂人也是已读不回，然后连考试都不通知表妹去，已经放弃她了。这种学校早点转走吧真的。</p><p>我和表妹现在也不熟，母亲一直让我去和表妹「谈谈」。我又能说什么呢？我都不知道发生了什么，大人们也只会一直说是表妹有问题了，得「走出来」。这种话术我已经在有自闭症的远房亲戚那儿听过一模一样的了。</p><p></p></div><hr><div class="diary-entry">02:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV73FR03CSFTQG662JS0WTM5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>SpaceX 的股票涨得也太离谱…… 我把 Moomoo 的先卖掉，买了点 SpaceX，结果现在涨到好多钱。打算这几天盯着它的股价看，一旦开始下跌就卖掉，然后继续 all in Moomoo。</p><p><em>Moomoo~</em> 我是牛。</p><p>一是因为 Elon Musk 的印象在我这里很差，我不相信他持股最多的公司会稳定。事实也证明啦 SpaceX 的财报里说了公司一直在亏损，除非 xAI 能大赚一笔、稳定下来。买科技公司的股太刺激了…… 我之后就放着一直养 Moomoo……</p><p></p></div><hr><div class="diary-entry">17:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV8S7RER5QN7R9RXEFF9ZRYT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我又做了恐怖的梦。一个是梦到《舞萌 DX》推出了平板移植版，但还在测试，所以每个街机玩家在玩的时候，会被要求在内屏上试玩两次平板移植版。在一个圆形的屏幕上，要求玩款方形的游戏，太可怕了。</p><p>另一个是自己带着妹妹在荒郊野岭坐大巴车。但我感觉有什么东西不对。我说不上来哪里不对了，只是有一种「我们和其他人不一样，而他们想要让我们和他们一样」的感觉。我带着妹妹从空空的后排移动到前排。一个大妈跟我说，我们不能坐前排，要去后排。我纳闷了凭啥啊，前排又不是不给坐。她说我跟妹妹就是不能坐。我无视了她。下一站来了更多的人，也就是更多的「不是人」的人。尽管他们和人类长得一样，行为举止也和人类一样，也没有来招惹我，但我感觉出，一旦他们等到了一个时机，就会立即扑上来撕碎我们。</p><p>我要去的站点快到时，我立即拉下巴士边上的线，想要趁他们反应不过来快点下车。可是司机居然没有停车！司机也是一伙儿的！我又去按停车按钮，可是来不及了！我的站点已经过了！—— 内心如此想着，但下一站就在一百米开外，真是虚惊一场。但我和妹妹下车的举动已经让他们注意到，有些「人」跟着我们下来了。</p><p>我假装淡定，领着妹妹去一栋房子 —— 现实中我没有见过这房子，长得真破，旁边的树还都干巴巴的 —— 母亲住在里面。亦或者说，那是长得像母亲的怪物。她热情招待我们，可是房子里站着很多我不认识的「人」，盯着我和妹妹。</p><p>后面忘了。总之我觉醒了超能力，在房子里见谁揍谁。什么妖魔鬼怪，全部倒在我的拳头之下！他们也怕我，但又不能逃跑，死也死不掉，所以还是想方设法去打倒我。可惜，对于已是新人类的我，任何雕虫小技不过都是开玩笑。</p><p>然后不知道为什么，我梦到的敌人都是美少女，相当于我一直在打美少女。再就是梦到后面妹妹不见了，母亲也不见了。</p><p>我把他们收拾一顿后，就离开了房子。我好像过去来过这栋房子，还是开车来的，所以很自觉地往停车场去。走一半，我想起来我是坐大巴车来的，停车场里也没有我的车啊。忽然，我看到站一边，迷路了的室友，就跟她一起去大巴站了。</p><p>梦一醒，感觉真可怕。我都在梦个啥。</p><p></p></div><hr><div class="diary-entry">21:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV973CR4CDG41P5HNM4N5SSH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3M8KH0WA908PA858VD8FK.png" alt=":neocat_nervous:" loading="lazy">​ 久违用了下 Gmail 这个客户端，发现它底部菜单栏的中间多了个选项，点进去发现是自动读取邮件，然后生成 AI 概要。</p><p>靠，谁让你读的。我还纳闷 Gmail 怎么知道我有个项目 TODO 没做。</p><p></p></div><hr><div class="diary-entry">23:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV9B1PD7R36VGM5SFV1Z1SRM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>登录一个页面设计相当传统的网站。忽然，验证邮件的页面变了样，有了很有 terminal 味道的绿色，以及跟首页完全不搭配的设计。</p><p>这也太出戏了。</p><p></p></div><hr><div class="diary-entry">23:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV9DVGCN6Z1TGWMKFV8G5QEX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看了眼 BiliBili 首页一直推送给我的 VibeOS 展示视频。有点太搞笑了这个。</p><p></p></div></details><details data-group="diary_sections"><summary>六月十七日</summary><div class="diary-entry">01:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV9JY1GHG9XJXES35GTZRNVA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>网络冲浪时发现自己特别喜欢的解密游戏系列 <em>Reincarnation</em> 在 2024 年竟做了一季的重制版！</p><p>Newgrounds 链接： <a href="https://www.newgrounds.com/portal/view/952262" rel="nofollow noreferrer noopener" target="_blank">https://www.newgrounds.com/portal/view/952262</a></p><p>我上一次听到这个系列的消息，还是数年前作者说要制作 <em>The Root of All Evil</em>，但迟迟没有讯息。这款重制版的简介中提到，有个程序员离开了团队，导致作者只能自学游戏引擎，最后学习了 Visionaire。</p><p>真是很高兴能看到这个系列的新作品，虽然晚了两年才看到。</p><p>EVIIIILLL——！</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KV9JMB7F2QNDEN3E2QDQZV36.png" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">01:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV9MEWXT49XBB5G7CQEXQB1G" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看到花瓶的 vile：</p><blockquote><p>It's a /vɑːz/.</p><p>Or a /veɪs/ for your uncultured sort.</p></blockquote><p>笑喷了。</p><p></p></blockquote><blockquote class="diary-thread-reply">03:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV9SR03DQQTKDFRVATR8HB0W" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在重温以前的内容。TCOU（<em>The Clergy Of Unholy</em>）篇内的这段话，小时候看了没看懂，现在……<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3QFJGAWJ9M9GSWX95FCK4.png" alt=":neocat_sweat:" loading="lazy">​</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KV9SP5CHNARX55BSF5D0WTQQ.png" alt="" loading="lazy"></figure></blockquote><blockquote class="diary-thread-reply">03:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV9TQN1PEASF8FP8C2KCYHFH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在 LTETR（<em>Let The Evil Times Roll</em>）篇中，作者说这本是系列的第三款游戏，但前面做了足足四个迷你游戏才把这款赶工出来，理由是每次找新的程序员，他们都会因「诅咒」而出事，导致游戏开发进行不下去…… 程序员你们都怎么了！</p><p>这款游戏是 2010 年出的，那看来作者在 14 年后才决定自己开发游戏。</p><p></p></blockquote></div><hr><div class="diary-entry">15:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVB1W6672FSJ9SNANECGP30P" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>复健画画！<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JDVGDYQWMMBRBXVTZFPD.png" alt=":neocat_googly_blep:" loading="lazy">​ 晚上画到了凌晨，虽然不健康但很开心，希望能找回过去画画的感觉。</p><p>不过代价是 9 点多醒来后又躺回去睡，睡到了现在。股市都 9 点开盘，看来我的身体还未记住这条规则……</p><p>不怎么忙碌最近，项目也是半死不活的不需要我，打工也是…… 我的悲伤是水做的！所以找了新的兼职，今天去看看。不过薪资也太低了吧，底薪 13 你玩谁呢！如果是给支票的就滚蛋吧！我要货比三家，因为我不是从前那个少年、没有一丝丝改变。</p><p></p></div><hr><div class="diary-entry">23:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVBZ7D7PC5G50JSPM7BS5NS4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>找工作真是想要放弃了。其他学科的工作要等一阵子才能去找，这期间为了活下去所以又开始做老本行，明明已经说了从奶茶店毕业。</p><p>今天培训完，扫 Citibike 却扫到极品单车，骑起来超级舒服！</p><p>朋友给我展示了他另一个朋友写的手账，上面画的「人」都是长得不知道是白色的狗，还是北极熊，总之非常用心、很可爱，还能看到他这个月都做了什么、跑了多少英里、见了多少个朋友、期间最喜欢的活动都是哪些。这个人过去好像提到过，但懒得去翻记录，反正是个衣着很时尚的老头。</p><p></p><blockquote class="diary-thread-reply">23:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVBZSAAFZE2H1HJE1FZWT4DD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天的晚饭是酸辣肥肠粉。</p><p>昨天吃了鸡蛋沙拉培根奶油锅三明治，很好吃。</p><p>流水账啊这是！</p><p></p><blockquote class="diary-thread-reply">06-18 04:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVCHAWAVBM8SP6X13529CBEE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这肥肠粉也太难吃了…… 油得要死不说，整个汤底非常非常酸，吃不出一丁点儿辣。</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">06-18 05:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVCHMCJF9X5XV2RDDBVMCP4M" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>忽悠朋友拿走我的 A5 6 环写手帐失败，想着干脆自己也写手帐好了，但又想到那我一件事要一边发 Fediverse 一边手写吗……！</p><p>老头经常在手帐上写写画画，让人很是向往。</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>六月十八日</summary><div class="diary-entry">03:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVCE11C22WZPWRWW52DQSSDN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>怎么有站点等个加载要等十几秒的 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3EQQJ0WWJ5EQ79NS9AMS5.png" alt=":neocat_angry:" loading="lazy">​</p><p></p></div></details><details data-group="diary_sections"><summary>六月十九日</summary><div class="diary-entry">04:48 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/973446368986595393" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Mimi on her sofa.</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/b5862bd14-4506fa/bH9Kc9njAbPX/vKL3HxdjlZ1aIpmLP6Bsav7g273nhE69eOJ4jK1L.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/b5862bd14-4506fa/4peC50Mdd82s/Z7nd7wsN7bwvOlEq0tddRBRG93XaVRTxypSw4U3u.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/b5862bd14-4506fa/4BGXvbdJSoJo/or1QD80T0UjoKDIwQXdGU3lpKCfMc8QsD4CZe1ru.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/b5862bd14-4506fa/rESWSYBEarFf/5FhPtM14sSyZ40jaSy9vnAavDX3PjwKphf1QXVfT.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/b5862bd14-4506fa/Yd3c9Qny4ZLg/KYKEDUBFBe6kpq1YjgsLnMg7pyCTmgMbXgi26SBQ.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">05:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVF43XAKBJ2D83CBSH5MKW11" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想在地址栏输入 <em>netflix.com</em>，但是很熟悉地输入了 <em>netlify.com</em>。直到看到加载出来的页面不对劲，才发现输错了……</p><p></p></div><hr><div class="diary-entry">05:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVF463YX6BJXSF3NXHJ6916F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在 Steam 游戏库内想要找一些简单的游戏玩玩，结果发现 <em>Bear Party Adventure</em> 下架了。我还挺喜欢这款游戏、依然在等 part 2 的哎。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">《毁掉一切地狱再爱》第 31 话剧透相关。</summary>        <div class="diary-cw-content">05:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVF70Z1X6RVZKZV9AHR8PKCK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这一话出来之前，我和其他粉丝们都推测妹妹是姐控身份过来的。结果这一话里，妹妹的动静儿和内心戏…… 该不会是直井母亲又找了家暴男吧……？</p><p>直井从小被打，一直被打到现在。工藤过来后虽然能改打工藤了，但很快也被工藤打了。怎么有 M 打 S 的啊。</p><p>总之还是很高兴工藤篇过去了。这个篇章我不太喜欢，追着憋屈，没有最开始吉泽的内容好看。吉泽真的萌萌哒啊。</p><p>31 话中间妹妹说吉泽喜欢直井，吉泽竟然没有经典脸红。感觉吉泽这几话来一直都是在流汗和皱眉，少有的高兴表情还是和直井和好的那一小段。</p><p>再度感叹吉泽的名字「来未」读 くるみ 实在是太可爱了。直井的名字虽然先前有人推测是叫「爱叶」，但我当时看那一段以为母亲喊的是肚子里的孩子。这一话则称孩子为「这个孩子」「那个孩子」，看来还没有取名字的样子，那直井真的就叫「爱叶」啦？好吧，和妹妹「萌奈」的名字还是很像的，不过我手头上没有日语的版本，没法正确比对。</p><p>结尾吉泽说的自己没有面对母亲的勇气，难道作者又打算一个篇章同时走两条线？工藤篇就是先让吉泽和下田先有矛盾，然后再让直井和工藤有矛盾，中间再加个伊佐沼和峰的支线 —— 共同点，难道是执着的爱吗？为了让喜欢的对方变成自己想要的样子，所以不停去折腾对方。那之后的就是家庭的问题啰？如果是围绕着特定的主题来安排角色们的剧情，所以我推测吉泽的母亲就算登场，也不会和过去有什么区别吧，但下田又是个成长的例子，但母亲再有成长，吉泽的生活如此一帆风顺，对比下来直井就惨多了。</p><p></p></div>      </details></div><hr><div class="diary-entry">22:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVGYW5YAA9G579N9KZP4ZPY6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>被朋友吐槽发型像豆包，穿着像老白男 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ496Q8A4XAZF9TK81RAX7.png" alt=":ottersgottaott10:" loading="lazy">​</p><p>我头发啥时候长回来啊 ——！</p><p></p></div></details><details data-group="diary_sections"><summary>六月二十日</summary><div class="diary-entry">15:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVJW0N6RRCKZNF2M3E570AD9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这几天一直看到中文独立博客聚合网站的恩恩怨怨，真是可怕！</p><p>不过也因此收集到了一些博客网站的 RSS，让自己的收藏多了起来。目前还在很缓慢地开发自己的 RSS 阅读器…… 打算添加能和农业法对应，还有日报功能。现在是很悲伤手动调整阅读顺序。</p><p>话说我先前换了子域名后，博客网站好像就不会再出现在任何一个聚合网站上了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">我在发疯。还挺长的。</summary>        <div class="diary-cw-content">19:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVK9H7CMN4PC952B25BKF3AJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4EE8WQ7Z323BCGBCMRHS.png" alt=":ottersgottaott16:" loading="lazy">​ 其中有个事件的走向很莫名其妙啊说实话。我翻了翻当事人最初的交流，并没有看到任何和性别相关的字眼，但到后面双方就都开始互喷说什么「极端女权」「180 斤小仙女」「破防男」……</p><p>不针对这个事件，只说一言不合就开始揪性别这一行为，我在中文互联网已经看乏了。每次，每次都能看到这种鬼东西，完全无视「个体做烂事是因为他是个烂人，而不是因为他是某某性别（或者某某标签）」这一点！我是真的真的，很讨厌这种鬼叙事。和一些中国朋友闹很僵，也是因为他们习惯于这种叙事，而我真的真的很讨厌这样。</p><p>标签化什么的真的是说烂了，但这些破人都不会理解我！有个朋友曾经和我说什么，「没有想到还有你这样正常的女生」—— 什么是「正常」！什么是「我这样的」！我哪样是「正常」的！不正常的女生是什么！为什么要感叹这一点！到底是什么啊你们解释清楚！<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​ 我 get 不到啊我真的 get 不到啊！你们说这些话到底是出于什么意图！你们眼里的世界到底是什么样的，为什么和我的不一样！—— 我当时内心的想法就是这样吧。</p><p>除了性别再就是性取向了，不过我接触到的和中文互联网没啥关系。我国内的朋友对这方面都特别包容；特别不包容的是我在美国的朋友们。我和他们也是根本合不来…… 我讨厌 bro 文化、讨厌满脑子都是性的人、讨厌总是想要从我身上得到利益却根本不在乎也不尊重我想法的人…… 我讨厌他们。</p><p>我是真的很烦现在中文互联网到处都是的性别叙事。我已经很努力地不参与任何一个主流的中文互联网平台了，所以也不想要看到这玩意儿出现。什么时候人们才能搞明白这种冲突对自己无益，甚至会搞乱更私人的人际关系呢？我又想要扯到我发现的另一个问题，即在互联网上表演、直播。</p><p>当时被某人表白的时候，我真的很怕他会把我们的聊天记录发到百度贴吧上。因为我知道他玩百度贴吧，在上面曾经发过我和他的聊天记录，并且经常跟我分享上面的「小丑表白帖」，也就是楼主发个自己表白的直播帖，大家在底下评论。这种帖里有很多我一看就知道行不通甚至很不健康的「建议」。要是有社会化没做好的人信了，真去效仿了，我会很绝望的 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 然后我很高兴他没有发，发了我会很想死。</p><p>总之就先胡言乱语到这儿吧。</p><p></p></div>      </details></blockquote></div><hr><div class="diary-entry">16:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVJYS7838Z206TPX6MMEJVHH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我梦到厨房里一个铁盆，里面装了水，但表面上还浮着油。旁边的墙上有个洞，里面掉了一条很小很小的黑色鱼宝宝出来，正好掉进了铁盆。</p><p>我们怕鱼宝宝死掉，所以把铁盆里的水倒入一个很大的方鱼缸内。天使鱼可能会吃掉它，但没有吃；可是鱼宝宝还是慢慢滑落、躺在缸底，死掉了。</p><p>我去旁边取水草，在箱子里找到个触感很像牛百叶、滑溜溜的玩意儿。应该也是水草吧，五颜六色的。别人说这是富含多种营养成分的水草，是高级货。我把它丢入鱼缸的角落，却惊醒了躺在那儿的黄色鳗鱼：它快速地朝着鱼缸的一个方向转圈圈，然后躺在了那颗水草下，装死了。</p><p></p></div><hr><div class="diary-entry">19:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVK6Q93ZR0JHPP1Q9RS03MMN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 我发现我访问国内的独立博客网站的速度越来越慢了，有些干脆无法访问，这也包括「根本无法访问」以及「访问了但是对面 ban 了我的 IP」—— 为啥呀！为啥要这么对我！</p><p></p><blockquote class="diary-thread-reply">19:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVK6V9S0QPTV9NHBTQHBVQ7T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>「根本无法访问」里还有我连接了 Wi-Fi 无法访问但换成 mobile data 就能访问的，以及哪个都没法访问的。因为无法访问，所以我也不知道是对方网站有问题，还是我有问题。</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>六月二十一日</summary><div class="diary-entry">00:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVKQP5VMF2T0MGS7VX1N7XNH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友微波了红糖馒头吃。</p><p>室友蘸了炼奶。我：<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3M8KH0WA908PA858VD8FK.png" alt=":neocat_nervous:" loading="lazy">​</p><p>室友蘸了牛奶。我：<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KPH39KEXCFCTM562V9DT.png" alt=":neocat_laugh_sweat:" loading="lazy"></p><p>室友蘸了草莓牛奶。我：<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy"></p><p>室友蘸了蜂蜜草莓牛奶。我：……</p><p>受死吧！</p><p></p><blockquote class="diary-thread-reply">00:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVKQRB8JKT60X3HPY80NVE2A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我：「我小时候还有种馒头是巧克力馒头。」</p><p>室友：「你有病吧。」</p><p>人们是无法理解彼此的 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JJ8V728TW4PRJHPWGKSK.png" alt=":neocat_googly_woozy:" loading="lazy">​</p><p></p></blockquote></div><hr><div class="diary-entry">16:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVNFEAEBKESPCWXZFCNXSMQM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>跑步期间拍的照片。</p><p>为什么只有洗手间的房间能让外人看得这么清楚。</p><p>Skatepark 之前和朋友进去过，太血腥了，那会儿正好看到一小孩儿骑 scooter 然后脸磕到石头上，哗哗流血。之后再也不敢进去。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KVNFAXPV6Y6HA2F61K6QWAER.jpeg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KVNFAYEGKH07TK3ECX0153HH.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">19:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVNS8N34R4K785F7DKYVKBAY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>和一起看电影的朋友有了个让我膈应的对话。起因是我们聊未来就业的事儿，我开玩笑提到了回国做公务员，但我因为出境记录定是当不了了，再加上我在网络上有对（应该）对中国不利的发言。</p><p>他有点纳闷儿，我怎么会说过中国的坏话呢。我就讲到了之前上的中文课。我刚提到这门课会读上个世纪的读物，他立即打断我：「我知道。是那种很『典』的『地主都觉得自己是好地主』的东西。」</p><p>我对中国的历史了解得不多，所以有人能跟我科普些我不知道的，我当然是高兴的。但绝对不会是以这个形式…… 我提到「乡土文学」，他又重复了一遍他说过的话：「那种文学很『典』啊。一个个地主都说自己是『好地主』。太『典』了。」</p><p>我有些不耐烦了：「…… 除了乡土文学，还有其他知青下乡的内容。」他愣了一下，然后说「就算那些事情发生过，这种文学都是很『典』的。」</p><p>什么是「典」？什么是「典」的文学？为什么它们是「典」的文学？这些疑惑他都没有解答给我，让我憋屈得很。</p><p></p><blockquote class="diary-thread-reply">19:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVNSXYDR46CVNRHN9D7BXB02" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>既然聊到了就业，那么也说说我们当时聊到的话题吧。他本科已经混了三年了，打算再混一年混出来学历，再去花钱花时间花精力去别的大学考个副学士（Associate's）出来。我已经不想对他非要混四年学历、啥正经事儿也不干的行为有任何评价了…… 我已经给了他三四年的建议，现在我自己也被行业重创，更没精力去帮他。关键是他也不听，有时候还要呛我几句，下次继续跟我抱怨这个抱怨那个、发泄情绪。</p><p>单说这个副学士，你考它又有什么用呢？个体的能力不会因为学历或者证书的数量（甚至含金量：CPA 很厉害是吧，垃圾 CPA 依然到处都是）而改变太多，你能力差照样能力差。不去认真思考行业方向的话，不停去做题考试拿这个学历、拿那个证书，照样没有用啊。</p><p>他天天说一定要赚钱离开家，但又让父母承担学费和住宿钱，甚至未来计划继续这么做，也让我很不能理解。虽然粉领工作没有上升空间，但你这样下去，别说上升空间了，只有一直持续增长的消费空间。</p><p>他说的继续上大学或者考证，跟他过去说的想要考研一样，都是逃避现实。我不知道他能逃避到什么时候。反正我言尽于此了。</p><p></p></blockquote><blockquote class="diary-thread-reply">06-22 10:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVQDYGMT501HCAQFHD9HCSWQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这家伙还频繁评价过我的穿着 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ496Q8A4XAZF9TK81RAX7.png" alt=":ottersgottaott10:" loading="lazy">​ 我的常服是冬天高领衫阔腿裤、夏天衬衫阔腿裤或者 polo 短 / 中裤 —— 我的衣柜只有这些衣服，剩下的就是奇形怪状的睡衣们。</p><p>他每次都要问我为什么要穿衬衫，而不是 hoodie。</p><p><em>Hoodie!</em></p><p>你知道 hoodie 在塑造人体线条上，有多糟糕吗！它会让我的身体看上去像个大方块！</p><p>再就是穿 hoodie 的人，实在是太多了，以至于我会觉得他要我穿 hoodie 是出于主流思想的驯化，来折腾我这个不顺应主流的人。这一点很主观，因为在许多我会做但是他不会做的事情上，他的反应都给我这种感觉。我就顺应自己的第一反应吧。</p><p>我的另一个主观喜好是我很讨厌穿上面印了文字或者画的 T 恤衫出门 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JDVGDYQWMMBRBXVTZFPD.png" alt=":neocat_googly_blep:" loading="lazy">​ 就算是夏天我也不会穿 T 恤衫出门。它们只会被我当成睡衣穿。</p><p></p></blockquote><blockquote class="diary-thread-reply">06-22 11:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVQG4S9SJT9WP5DF1QEHZJ3G" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我忽然意识到我并不知道他常说的「小资」是什么。</p><p>我从 Wikipedia 上得到的答案：</p><blockquote><p>小资是 1990 年代开始在中国大陆流行的名词，最初特指向往流行思想生活，追求内心体验、物质和精神享受的年轻人，而随着物质生活的逐渐丰富，小资一词常常与情调连用，用来代指一种追求浪漫、慢节奏、一定的仪式感和精神美学的生活方式。小资一般为年轻都市白领，又与「中产阶级」相差一定距离 —— 主要在经济方面。</p></blockquote><p>所以特指的是那些在经济上没有到中产阶级那个水平的年轻人？我推断他的意思是这些人没有钱，还非要让自己的生活和有钱人（在这个语境下就是中产阶级了）的生活身上靠。可是听播客或者用香薰也没什么吧。难道我写博客也是小资爱好？这都啥跟啥呀！</p><p>他说的「小粉红」我还是知道的，不过「目田」是什么鬼玩意儿。他说是「自由」去了两个头，「自由蛆」的意思 —— 这玩意儿又是啥啊！我要和你们这些口头交流也要弄这种狗屎 super ultra deluxe 缩写 pro max 的人拼了！</p><p>OMG 我甚至找不到有关的 Wikipedia 页面。是什么啊是什么！你告诉我啊 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">06-22 11:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVQHW46H5GPVG1H8JGHE2Q2E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>找不到很官方的解释（以及正在吃饭所以有点懒）所以去问了 AI 工具。它作为个搜索引擎真是好用。</p><p>和我想的一样，「目田」去掉上面的头暗示了「没有独立思考的能力」。</p><p>它实际上代指的是「自由派」或者「公共知识分子」，也是个很贬义的表达。主要是批判一个人在面对西方社会的问题时会为其开脱或者沉默，但在聊本地的事情时会激烈批判。他们也会认为本地的问题可以通过直接引入西方的理论来解决。</p><p>这些东西我就不深入了解了，因为我对政治学可以说是一窍不通 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 我高中的美国历史兼政治 AP 课最后拿了个 2…… 满分 5。术语忒多了这也。</p><p></p></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>六月二十二日</summary><div class="diary-entry">05:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVPW5C6H92RYWWHM90RPHRKX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4EE8WQ7Z323BCGBCMRHS.png" alt=":ottersgottaott16:" loading="lazy">​ 其实一个小时前就该睡觉了。但是室友火眼金睛在房间角落里找到了一头超大的千足虫，大半夜尖叫把我吓飞了。千足虫是吃 ゴキブリ 的人类好伙伴，所以我打算让它活下去。可是家里的第三个生物，找到了它，并开始疯狂攻击它…… 于是一个屋子里同时出现了在蹦跳逃离尖叫的人类、在抽和咬和嚼虫子、在一旁放着纸打算放生虫虫的人类、不知道是在装死还是真死的千足虫。</p><p>我要去睡觉了…… 明儿还要早起去试工。这家店新开的，结果刚开几天没多久店长就要优化员工们了。我还没开始做呢压力就好大……</p><p>趁机复盘一下今天的「日计划」，发现早上花了 3 个小时在看视频 —— 准确来说是一边在听视频一边在做白日梦。</p><p>睡觉！</p><p></p></div><hr><div class="diary-entry">12:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVQM0W8T3A1967E2AZBB0RP3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>来太早了…… 只能去旁边的公园里散步消食了。应该把手账本带来的，不过这附近还有狗狗公园，真不错。</p><p></p><blockquote class="diary-thread-reply">12:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVQMHSM29TJ69MZAATDTJ8KC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p></p><blockquote><p><em>No people without dogs.</em></p></blockquote><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3FZ75C9HA8Q3KRW12YT3F.png" alt=":neocat_cry:" loading="lazy">​</p><p></p></blockquote><blockquote class="diary-thread-reply">12:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVQMR7GG3BNKMH4C38K1S514" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>怎么会有水滴打在我身上？</p><p>不可能是下雨，对吧？对吧！</p><p>我没带伞啊！</p><p></p></blockquote><blockquote class="diary-thread-reply">12:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVQP081JYTB675F38EQC3ASM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>公园里遛狗的比遛娃的多好多。之前找兼职的时候看了些帮带动物的平台，发现都要手续费，并且看评价问题狗很多。实在是担心自己无法照顾好动物，以及手续费好高啊！所以放弃了这条路。</p><p>看着一条狗叼起了足球：咦，足球这种表面质感的东西狗居然是可以叼起来的吗？</p><p></p></blockquote></div><hr><div class="diary-entry">19:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVRE4267ZEVD1CC26GY7X585" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>结果大早上的没有下雨，现在下班了一直在下 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">20:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVREPWJ3BPTZVGKMRTS3SG74" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>被宰了十块钱的伞 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​</p><p>这种破伞我只接受一块钱的！</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>六月二十三日</summary><div class="diary-entry">02:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVS5FBX5QEKB4Z2YWN8ZJZBG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>什么叫我通过 Turbopack 启动项目服务器会吃掉我 655% 的 CPU 使用率以及 6.3GB 的 RSS？</p><p>你快醒醒你只是个普普通通的 Next.js 项目！</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">《无能的奈奈》第 121 话剧透相关。</summary>        <div class="diary-cw-content">14:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVTDJS4T10VSA5N22PXHZA99" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>鹤岗真的就是奈奈的哥哥啊 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 这设定给人种很微妙的感觉……</p><p></p></div>      </details></div><hr><div class="diary-entry">14:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVTEPQK566ADP58NBW61J7RV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看到一位博友做了个地图，将博客网站评论者的 IP 转换成归属地（地级市级别）再转换成地图坐标、直观地显示在地图上。然后他说：</p><blockquote><p>本站的 IP 归属地显示、设备显示、GEO 坐标计算，全部在本地完成，没有调用任何第三方 API，不用担心泄漏隐私。</p></blockquote><p>不对不对，不是这个问题吧！</p><p>本来显示评论者的归属地、使用的操作系统和 user agent 已经是违反数据最小化的行为了，但为啥非要去学中国社交平台那一套呢？</p><p>我去翻阅了他网站上的协议，虽然提到不会明文显示 IP 地址或 user agent，但这样直接放在地图上，给人一种很诡异的感觉……</p><p>总之不要去会展示归属地、使用的设备类型、使用的浏览器等信息的博客下评论。</p><p></p><blockquote class="diary-thread-reply">14:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVTFS728Y9H32W9K9CADMWKF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>他在文章中引用了别人说的这段话：</p><blockquote><p>这个功能我很清楚娱乐意义远大于实用意义，但是我觉得自己的博客站点肯定不能只追求超高效率和简洁性，而失去了一些好玩的东西。不然直接去找个平台发文远比自己弄个站点高效的多。</p></blockquote><p>我不明白这里的逻辑。为什么追求高效率和简洁性就必须得是去找平台发文？就那么不重视数据隐私和主权吗？或者说你觉得平台就是高效率或者简洁的吗？—— sorry bear blog。</p><p>大家搭建博客确实是为了能有自己的地盘。你也可以去折腾很多好玩的东西。我先前看过一位博客站主将自己的博客网站做成了 RPG 游戏，技术力和努力让人敬佩。但为了好玩却公开展示评论者的 IP 归属地、系统、浏览器等，我觉得很没必要啊？这和模仿主流社交平台有什么区别？协议里也没详细说归属地会被放在地图内 —— 虽然和直接显示地级市的文字是一样的，但在地图上显示会更容易引起对隐私的担忧 —— 再加上他的协议是无法 opt-out 的，除非不评论。</p><p></p></blockquote></div><hr><div class="diary-entry">19:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVTYAP82FC782Z4BB3V7W6EV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>好可爱的熊。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KVTYAA2VQ3NKMRDTHQ6921ZD.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">19:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVTYJQCD29Y9HQK82M9WZ67H" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不小心点到 QQ 空间的说说回忆了。结果第一条是这个，配合第一条评论食用，能够达成令人忍俊不禁的效果。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KVTYGWM4NCKE85ZVMYBASCM2.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">20:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVV1GH3Q6989R0WCZ3GYJ0X6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前几天和好朋友出门买东西。我们在唐人街碰了面。因为她说想要在外面吃个饭，所以我们转了两圈、找一家看着不错的餐馆下下。最后是她用小红书随便找了家推荐的。</p><p>这是家广 &amp; 港式（我不知道它们俩的区别……）饭馆，卖很常见的饭、云吞（我更习惯叫它「馄 hún 饨 dùn」，是山东那儿的叫法）面、通心粉啥的。我一直都想尝尝广 &amp; 港式通心粉，朋友则点了个肠粉煲。</p><p>不过我重点想说的不是食物如何 —— 真想要我说的话，我也只能说不符合我的胃口 —— 而是店员。还没点单的时候，就有个店员大妈过来夸朋友年轻、看着像初中生，然后看到她的手表，用粤语问这是什么表。朋友用粤语回答说这是 Omega 的，对方又问多少钱。得到了答案后，她一边惊讶地说「是你爸爸给你买的吧！」，一边伸手去摸表盘，接着不停询问朋友的年龄、职位等，然后又招呼其他店员过来看朋友的表。</p><p>总之之后我们在商量点啥好，店员们就在一边用粤语说朋友长得好看、年纪轻轻事业有成、表很贵重巴啦巴啦 —— 我还是可以听得懂一点点粤语的！应该吧！之后让朋友给我翻译总结了还是。点单期间朋友用普通话帮我点，同个店员竟惊讶了一下：「你竟然会说普通话！」然后继续询问朋友是否是 ABC、是不是在美国出生的、牛什其实是牛肚她能吃吗…… 菜单收走后，强烈的视线和大声对话依然让朋友感觉不适。</p><p>结账走人时，店员看着站起来的朋友，再度惊讶：「你这么高！」但其实她还没有我高呢。朋友尴尬一笑，拉着我跑了。走后她提到先前去参加一次活动的时候，被别人传播或者扒出了她的经历，导致一堆人很膜拜她，经常夸赞她、贬低自己，让她除了尴尬一笑外什么都回应不了。她觉得和这样的人相处很烦；她在这些人面前，仿佛呼吸都是在炫耀，但她根本也没想要这么做。</p><p>我是很讨厌这类人了，和他们相处也会让我深觉不舒服。室友会称呼这类人为「思想贫穷的人」，并觉得他们没救了，不要和他们牵扯上联系。像我先前很怒的那个朋友，她也觉得是思想贫穷的，并好奇我为什么还要和对方做朋友：很明显，那个家伙现在给我带来的坏影响要远多于好影响。我不是个果断的人，和他也做了近十年的朋友了 —— 难道是沉没成本和习惯吗？</p><p>认清一个人并做出判断还是件我需要学习的能力。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">《羊村守卫者：决战次世代》剧透兼观感相关。</summary>        <div class="diary-cw-content">22:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVVAVBGM4205WRR5M2C0F5S1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>50 集之前内容还挺同质化的。感觉我还是不大喜欢这种日常打怪的故事。</p><p>千算万算没想到剔博士是个有 daddy issue 的人…… 这种人设真的看太多了，力竭。设计成真的疯狂科学家会更好一点吧。</p><p>影子倒戈这个倒是意料之中，不过没想到人家是美羊羊她妈。我没看过之前的三季，都不知道有这个人。</p><p>美羊羊她爸怎么是这么粗壮的人，但为什么变成寒天之后就没有过和美羊羊的剧情了呢？</p><p>这一季很多点子都挺不错的，对我胃口，但实际看下来没有很好地发挥出来。</p><p>小灰灰长大后的声优听起来和其他人有些区别，有点奇怪。这个角色明明也可以挖掘一下的，但被制作组完全当成写亲情戏的工具了。</p><p>现在看《羊村守卫者》还有个想要吐槽的点是红太狼的人设跟老版的变化也太多了吧。不仅没了平底锅设定，出场次数也变少了，每次出来就是出演亲情戏、给灰太狼增添 buff…… 本来这季红太狼被抓、变成珍妮，我还很期待会有什么样的剧情，结果还是立刻猜到了结尾。</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">RE：《羊村守卫者：决战次世代》剧透兼观感相关。</summary>        <div class="diary-cw-content">23:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVVD4CQJC9Z2FYJGG37ATDT3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>终于是看完这一季了。</p><p>中间实在是太水了。真的没想到这中途的几个机器人结尾是完全不出场，就算出场也是死人形态。从黑钻开始，这些机器人都要发一次「刀子」，制作组很刻意地想要让观众哭，而我很不喜欢这样。看到奥力篇我真的遭不住了，同个主题的催泪戏份一直一直演。红太狼那个是已经麻痹了，之前看的几季都会演一遍所以……</p><p>我开头看的时候对这一季的设定抱有很高的期待，结果看完这 60 集很不爽。《狂野新世界》也一般吧但它中间的穿越很有趣（虽然我是奔着喜儿去看的；综合一般都是后期害的），但这季 60 集下来看什么猜中什么，很无聊说真的。</p><p></p></div>      </details></blockquote></div></details><details data-group="diary_sections"><summary>六月二十四日</summary><div class="diary-entry">01:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVVJW8GJ9MHZRA60RPJ2G1BX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://pluralistic.net/2026/06/23/destroy-the-village/" rel="nofollow noreferrer noopener" target="_blank">https://pluralistic.net/2026/06/23/destroy-the-village/</a></p><blockquote><p>Spying on kids to save kids from spying is very, very stupid</p></blockquote><p>Cory Doctorow's opinion on age verification, which he defines as <em>mass surveillance</em>.</p><p></p></div><hr><div class="diary-entry">17:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVX9FYT875XKKW27KC0BZ5WC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://forum.wordreference.com/threads/%E9%A6%84%E9%A5%A8-t%C3%BAn-tun-d%C3%B9n.3217958/" rel="nofollow noreferrer noopener" target="_blank">https://forum.wordreference.com/threads/%E9%A6%84%E9%A5%A8-t%C3%BAn-tun-d%C3%B9n.3217958/</a></p><p>「馄饨」的「饨」咋念到底？</p><blockquote><p>根据百度百科：</p><p>「馄饨（汉语拼音：hún tún 或者 hún tun 轻声；粤语：wɐn3 tɐn1，音同「云吞」；山东话：hún dùn；英文名：wonton）」</p></blockquote><p>在普通话考试的官方标准下，标准读音仅有 hún tún 这一种。但民间为什么会有这么多念法？</p><p>尤其是英文的 <em>wonton</em>，我特么在美国待好几年了，认识了个会粤语的朋友才知道 wonton 是源于粤语的「云吞」wɐn3 tɐn1—— 这还有个有趣的延伸就是我当时和福建人待得久，他们会念成 wan3 tang1。我从小都是 hún dùn、hún dùn 地念，还被别人嘲讽过没文化，但这就是北方部分地区的念法。</p><p>关于该 BBS 帖子内的音韵学知识，我没有了解过所以就不评论了…… 不过有个用户提到了词源学的知识：</p><blockquote><p>I think its connection with 沌 cannot be ignored.</p><p>渾沌：沌 MC *duən （王力） &gt; Pinyin dùn</p><p>唐・段公路 （山東臨淄人）《北戶錄》卷三〈食目〉: 「渾沌餅」 (cf. 後秦・弗若多羅與鳩摩羅什譯《十誦律》: 「餛飩餅」); 唐・李匡乂《資暇集》卷下曰：「餛飩以其像渾沌之形，不能直書渾沌而食，避之從食可矣。」 ==&gt; 餛飩 was also written as 渾沌。《食物志》：餛飩，「或作渾沌」.</p><p>錢鐸《方言箋疏》註：餛飩之言倱伅也（伅 Pinyin dùn)</p></blockquote><p>所以我小时候将「馄饨」和「混沌」关联在一起，是不无道理的。只是我小时候不知道「浑沌」这个词儿…… 其实一直把「混 hun4 沌」念成「浑 hun2 沌」。先前我还纳闷一个 hun4 怎么能变成 hun2 的，现在知道了「浑沌」这个词儿，就能理解了！</p><p>我会如此好奇的一大原因是去年在 BiliBili 上看到一个「科普」视频，说「馄饨」不念 hún dùn；这是现在人们都将其视为「混沌」而发展起来的错误念法，就像是大家会把「券」念成「卷」、一些场合会把「骑」念成 qi2 而不是 ji4—— 不过这个已经变成全部场合都念 qi2 了貌似。还有些类似的案例是「给予」的「给」从 ji3 变成了 gei3。</p><p>一个特别有趣的题外话是「说服」这个词儿。它自民国起就念 shuō fú，官方也从来都没有改过它的读法。台湾地区受「说服」语义接近「游说」的 shuì 音影响，一些辞书标注了又读 shuì fú。而台湾流行文化在大陆崛起，使得「说 shuì 服」广泛被传播，让很多人认为 shuì fú 才是保留了传统音，甚至传起谣言认为是没文化的人太多，都说 shuō 所以官方特地改了。现在就算是在科普「说 shuì」已经有「说服」这一层意思的视频底下，依然有人不听解释，搬出「是没文化的人太多了」的说法。</p><p>当时那个「科普」馄饨念法的视频的评论区里，有人指出，山东地区就是会念 hún dùn，并不完全是「错误」念法。紧随其后的是另一个评论者，表示这就是「错误」的，就是人们教育水平不够、看不懂所以当成「混沌」来念。前者愤怒回复道：「请你尊重地区文化。」</p><p></p></div><hr><div class="diary-entry">17:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVXBECEC6JGDH7W0VJ8XVXYK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我在写一个税法案子的报告。写的期间分享发现的趣事给税法大师的室友看，但她却生气了，觉得我作为一个不怎么懂税法的人，却在写一些她也不知道的东西，叫我不准写了。</p><p>就写就写，气死你。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">悲伤的情绪相关。</summary>        <div class="diary-cw-content">22:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVXXKH2AJ8KH69AQ3NBDD5CS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>写文章报告时想到了一些过去发生的事情。我记得自己很痛苦地在处理人际关系问题，我也不知道该怎么处理这种第一次碰到的问题。朋友提供给我的建议，都不让我觉得是我想要的。还有几个在我们的对话中，明显是想要让我的行为符合他们心目中「爽文」的样子，让我更难以和他人倾诉和商量。</p><p>之后事情结束了，我觉得我当时已经做了最好了，但当时在伤害我，同时也是事情的一大受害者的人，常常会说我也有错。我不知道我错在哪里？整个事情对我来说根本就是无妄之灾。他说我没有真正地去包容他，让他在我面前感到羞耻，更加无法理解自己。可我依然不知道什么是「包容」？你们伤害别人的时候，有考虑过包容我吗？为什么总是把我当成「不够受伤」的，然后指责我没有去包容你们呢？我明明也有努力去让自己做你们想要我做的事情吧，但你们又对我做了什么呢！非要在需要我的时候将我压榨干净，又在我抑郁和痛苦的时候轻飘飘说一句「我也有错」，才高兴吗！</p><p></p></div>      </details></div></details><details data-group="diary_sections"><summary>六月二十五日</summary><div class="diary-entry">00:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVY4KVD9VEXHEX23E14ZDE4F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://jamesg.blog/blogger-archetypes" rel="nofollow noreferrer noopener" target="_blank">https://jamesg.blog/blogger-archetypes</a></p><p>博主原型测试。</p><p>如何最好地总结你作为博客社区一员的角色？</p><hr><p>这是我的结果：</p><blockquote><p>You are a Link curator</p><p>The web is not just its pages, but the connections between pages. You have internalised this and love spending your time exploring the web and sharing what you find with the world.</p><p>You are also a Author</p><p>You love writing and have a growing backlog of posts on your website! Words are your best friend and you're always thinking about what to write next.</p><p>Other archetypes</p><p>Explorer: To you, the web feels like a library that's open all hours and has everything you could ever imagine! You love reading others blogs, and know how important readers are to the whole of the indie web community!</p><p>Community gardener: You love to help contribute to building the blogging community, either through your writing or how you share the spirit of writing on the web with friends.</p><p>Culture maker: You love to help push the blogging community forward by starting discussions, encouraging thought, and sharing what's on your mind.</p></blockquote><p></p></div><hr><div class="diary-entry">01:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVY7DFNDCRNMFS8HJWXF87YE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>感觉自己沉浸在做规划上…… 税务好不想学下去啊。TODOs 总会让我觉得得从上往下一个一个做，一旦有个任务卡住了就不想改做下一个了……</p><p></p></div><hr><div class="diary-entry">04:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVYGVKYXF01E0A8KV7KSD1D0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>本来写点东西打算睡觉了，打工的群里大半夜的发来夺命连环通知，响得我还以为又有什么运维大失误、有人要夺我这个 tech 的人头，结果是有个傻蛋子发图片发错群了，一发发了几十张，然后又撤回了一遍。</p><p>我真要睡觉了！</p><p></p><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">《要赶紧逃走》V 曲相关。</summary>        <div class="diary-cw-content">04:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVYHB2XCN2BC5XKGHBQHC3VN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>顺带一提总算给之前一直在首页刷到的《要赶紧逃走》给看完了。忘了人家咋翻译了总之是个鬼畜雨衣的 V 曲。</p><p>之前 BiliBili 老在我首页上推送这曲的二创，封面一个个都是雨衣的鬼畜大脸。我之前还遭受了许多恐怖游戏录播视频的封面的冲击，还有什么沸腾者、伪人相关的视频的封面重创，对这类恐怖或猎奇的封面实在是烦躁得不行。我虽然看恐怖游戏主播，但不代表你可以随便丢个鬼脸封面在我的首页上！所以我一段时间里把这首歌相关的视频全都点了「不感兴趣」，得以清静自在。</p><p>今天看了眼，初次观感是整首歌都很服务于 MV 的样子，所以我一直用「看」这个动词。非要说歌曲本身吧，核的要素会多些。我不太喜欢这个初音未来的调法。</p><p>评论区有人放了 <em>Dark Deception</em> 的梗图，笑得不行…… 我以前还直播玩过这款游戏，技术很差因为我还是很怕玩恐怖游戏的。</p><p>睡觉！</p><p></p></div>      </details></blockquote></div><hr><div class="diary-entry">09:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVZ2CS6E2JG9W4P8AG5ZXD7X" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>好困…… 凌晨四点室友在床边架着个电脑在看 <em>Hunter X Hunter</em>。不想动…… 让我趴在桌子上睡到天荒地老吧。</p><p></p><blockquote class="diary-thread-reply">10:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVZ3QC2KGDGZGC20PZXF4E46" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>感觉自己真很像社畜啊，明明是一个半失业状态的人。</p><p></p><blockquote class="diary-thread-reply">10:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVZ3WYDYF4E19ANQN41RFC0Z" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>绕一大圈才发现要去的车站，其入口就在绕圈前的地方，相当于白白绕了一圈。死导航什么时候能正常点。</p><p>今天去参加妹妹的毕业典礼。</p><p></p><blockquote class="diary-thread-reply">10:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVZ4WPSDQK8FB2688A0Z4MSG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>死 MTA 又在延误，害我错过大巴，又要原地站着等上半小时。</p><p></p></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">09:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVZ2WMQCA0J4CSVHQP70TV4H" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>每天有新理由想掐死室友：这破人凌晨出门、回来忘锁门了。</p><p>看到门的锁没上上，一瞬间心跳都要停了。</p><p></p></div><hr><div class="diary-entry">10:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVZ53ERQ0J0TZ1ST4B60ZHC9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有时会觉得自己真是小肚鸡肠，一件小事能记恨上这么久。过一会儿又开始想他们这么整我心态，怎能就这么过去了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3P7ERKZ171TWDDBTNA1WX.png" alt=":neocat_scream_angry:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">10:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVZ6RKM0FRGRKZZ1P7YHK48M" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Elsagate 我其实也经历过 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 小时候要带小孩儿，所以就得陪着他们看电视。这群小孩子人手一块大平板，就拿着看 YouTube；虽然我那时也不咋地，也在用 YouTube 看恐怖 RPG 录播。记忆里妹妹还没一岁就在用平板看视频了，很多时候是家长懒得管，给她看视频让她安静点。</p><p>妹妹到了上 pre-K 的年纪，大概就是四五六岁的时候么？她便接触到了 Elsagate，大意就是提供给儿童看的视频里，虽使用了孩童们喜欢的角色（例如 Elsa、Mickey Mouse 等），但内容都是快节奏、有毒的，还会使用各种方式吸引小孩子的注意力 —— 另一个较大的案子是 CoComelon，这鬼玩意儿我也看过；他们会专门做研究，做出最能让婴幼儿们「沉浸其中」的视频。不过 Elsagate 恶劣的地方在于，它的视频很鬼畜和可怕，内含大量三角恋、色情擦边、暴力、屎尿屁（但我不清楚这对于四岁左右的孩子算不算坏处？因为这个年龄段的小孩子都更倾向于觉得屎尿屁好笑、有趣）内容。我当时看的时候真很纳闷啊，不知道他们为什么要做出这样的影片。后来我在中文互联网上也看到了类似于 Elsagate 的短视频，就是角色换成了奥特曼啥的，但剧情大差不差。</p><p>为了让妹妹不要看这种鬼屎影片，我特意把 YouTube 卸载、要求她只能看 YouTube Kids。但我不太记得当时发生了什么：要么是 YouTube Kids 上也全都是这类影片，要么是我的傻逼母亲又把 YouTube 下回来了。在我对妹妹的教育上，母亲是我最大的阻碍 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 然后她会在有一天得不到妹妹的回应、愤而上楼骂她，接着跟我抱怨 ——「长姐如母」我在自己的情况下就不反对了，但要想让我承担母亲的责任，就得先把这真正的母亲除掉……！</p><p>妹妹不再接触 Elsagate，很大程度是因为她后来长大、不用再看这种幼稚的影片了。不过她之后接触了 Gacha World 二创视频、短视频等，这又是另一个话题了…… Elsagate 对妹妹最显著的影响，我很难说明白。当时她对排泄很敏感和羞耻，但我不知道是否是 Elsagate 的屎尿屁内容导致的？她长大后也会因为这些东西而感到崩溃，尤其是有一天家里带的一小破孩儿在车里拉屎然后把玩…… 我对排泄物的接受程度，因为养了狗后而直面上升，也不知是我和妹妹哪个有问题。</p><p>另一个点便是她那会儿虽还在用小孩子用的马桶，但常常会扮演自己是孕妇，并对我们的发现而感到羞耻。Elsagate 中确实也出现了巨量怀孕的情节…… 还有男性偷窥女性隐私部位的情节。但这些都因为她的长大而消散不见了。</p><p></p><blockquote class="diary-thread-reply">11:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVZ8VP0HBADCBAVE0FECAR0W" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>至于 Gacha World 二创视频，游戏在此处更多是个工具，重点在于孩子们用它创作的东西。</p><p>真要说的话，当时妹妹看很多的是各类狗血的剧情 —— 除了狗血我不知道用什么描述它…… 电视剧、短剧、知乎盐选文里能出现的，它都能出现。该说是快节奏时代的趋势吗？当时以抖音为代表的短视频平台已经成为了人们日常会使用的软件（除了我 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JDVGDYQWMMBRBXVTZFPD.png" alt=":neocat_googly_blep:" loading="lazy">​）</p><p>这会让我想起我同个年龄段都在干什么…… 好吧，我来美国上五年级的时候才知道性这个概念。以前在中国感觉大家都是小傻蛋（这是赞许），满脑子都是怎么打谱尼、获得帝皇龙…… 不过我玩网游玩得不入心，天天忘密码、新建号玩，但写过一本《赛尔号》里俩精灵的二创小说。故事中一人牺牲、另一人狂暴进化击退反派…… 怎么是这种武打片走向？当时在班上常常画漫画，内容也是叠战力：主人公们会碰到更强大的反派、变得更强大，然后就一直叠，叠得没完没了。在当时的创作中，就有融合过其他作品的设定，但在剧情上我都是自己瞎写，很多时候能写出很烂很屎的剧情出来。</p><p>在美国得知了性这个概念后，我接触到的圈子便是 Undertale 和绘圈…… 我还在当时的 Undertale 吧里接过稿，现在只会觉得那时我什么臭鱼烂虾还敢发自己画的东西。不过在 Undertale 吧经过一次管理更替后，发帖子都需要经过审核，我也不再玩这个圈子哩。</p><p></p></blockquote></div><hr><div class="diary-entry">14:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVZHE7SF1W93M2AY7PCWYGC8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>妹妹学校的学生，一届仅有相当于我在国内上小学时一个班的学生。</p><p></p><blockquote class="diary-thread-reply">14:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVZKAMHM6HZ7BVZTEGF6EC0Y" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这毕业典礼总算是结束了！</p><p>我太烦毕业典礼了导致高中那会儿不打算出席，但还是被父母叫来的一面包车人（夸张）捞走了。不过好笑的是，当时我没有花钱去买学校的 package，就是袍子和帽子啥的，但当时管这些东西的老师我认识 —— 没想到吧，这就是参加学生会干杂活的特权 —— 免费给了我多出来的袍子和帽子，让我参加了毕业典礼。</p><p></p></blockquote></div><hr><div class="diary-entry">15:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVZQQMR8FFTH3WWFRT7SNR70" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天想试试用手柄玩泰拉瑞亚，但我开了灾厄模组并且选了大师死亡，开局还没搞明白操作就被飞过来的绿史莱姆单杀。</p><p></p><blockquote class="diary-thread-reply">15:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVZQW16AKJVZ0N6XV0ECAZW0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>上次玩灾厄模组应该是去年还是年初的时候跟朋友联机玩的？完整走完流程就走过两次，一次是跟朋友摸石头过河玩召唤师，第二次是自己玩速攻战士哥（当时速攻战士哥还没有被削弱……）。几次没玩完的都是因为想玩盗贼但被打爆不得不放弃。</p><p></p></blockquote></div><hr><div class="diary-entry">16:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KVZSABMCGXCHCGWG4KHBHCYG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>和父母还有其他人来吃上海菜。我对上海菜没啥印象，但这家店里的主食，除了味道特别甜，就是满满花椒味儿，我不是特别喜欢。除了蔬菜吧，有西兰花炒山药，我特别喜欢吃山药。</p><p>然后是份量都很小，一盘盘都是二十块钱左右，真是的。</p><p></p></div></details><details data-group="diary_sections"><summary>六月二十六日</summary><div class="diary-entry">02:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW0V1AES260R1D6QZ7DG0P9Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>「纽约」和「跨年」放在一起会让我想起特别恶毒的一句话：</p><blockquote><p>多让你的仇人喝水，然后让他去时代广场跨年数倒计时。</p></blockquote><p></p></div><hr><div class="diary-entry">02:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW0V4KE5FGNT5GBZQ48EM6FR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>卧槽外面的烟花声听上去像是城市外有敌军要冲进来、连环开炮了。</p><p></p></div><hr><div class="diary-entry">02:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW0XHKXCVMSQFNTV3M7FB12V" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p></p><blockquote><p>…… 坦白说，社团里的求知欲与谈话渐渐使我感到做作，我想，我们彼此炫耀知识，唯恐暴露自己所知仍然停留在解严之前，唯恐同伴讥讽自己心灵不够勇敢，这样的急切，才真正透露禁忌在我们心灵埋下何等阴影吧。</p></blockquote><p>这段话出自于《虚构一九八七》的第 6 节。</p><p>我有时也会思考，我，或者其他人，谈论一些事情是否是因为转换了环境，为了让新环境的人们觉得自己是「未被洗脑」的，所以才大谈特谈它们。日常对话中，也要左一个「言论自由」，右一个「宗教自由」。唉。我也不知道。我没有卷入到极端的事件当中，对历史也仅抱有去挖掘它们的兴奋，但除此之外，我的思考和想法是什么？</p><p></p></div><hr><div class="diary-entry">04:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW127BD1F6NE5T9E884FTQ2H" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>重新开始写中文课短篇小说系列的时候发现教授把整个课程的数据从学校平台上删除了，相当于人间蒸发了，我写的作业还有讨论……</p><p>…… 还有同学们用 AI 工具生成的牛头不对马嘴的回复，如果有人想念它的话（好机翻的话）。</p><p></p></div><hr><div class="diary-entry">05:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW15PGQJYMY12K5HTXH5ZZYD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我随手发了个评论说之前看到广场舞大妈外放吵死了，然后就被别人迅速下定义说我住的是华人区，质问我为什么不搬去高档的地区。</p><p>说什么鬼话呢这个人。</p><p></p></div><hr><div class="diary-entry">14:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW26Q2W9ZX632J0RSXCGSPDX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>热得睡不着，也不想起床。</p><p>最近在做的事情都提不起劲儿，不会让我有兴奋的感觉：硬着头皮去 network、coffee chat；给小孩子上网课，但我根本不知道怎么更好地教数学，也适应不了学校让他们使用的方法，再加上孩子们的水平各不相同，难以平衡课程的质量；试工的店要做的事情一大堆，同事们也都不爱说话，给人没有友善的感觉。</p><p>特别有趣的是，这店刚开店就招了快二十个人，但同时能上班的只有五六个人而已？你招那么多人干嘛啊你。结果就是有个别员工的做事态度很差，每天都有客户因为低级错误而要求退款和投诉，搞得经理人都要崩溃了在群聊说第一个要被开除的是他耶！</p><p>还有税务的事情，学起来枯燥，他们也不让我去深挖里面的内容，告诉我只要学到「知道」即可，类似于「死记硬背」但没有真的去硬背。这种感觉很不舒服让我……</p><p>我逃避到未来去，开始规划未来我想要做的事情：我想要系统性去学习网络安全、我想要写完该写完的文章、我想要做完这个软件…… 事情又挤在一起动弹不得，像是漏斗里卡住的玉米。</p><p></p></div><hr><div class="diary-entry">15:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW2AEJVF3FZZ5ARF384PH53W" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>什么情况，我的网络访问不了 IONOS 也无法访问我自己托管的服务了？现在用的是 mobile data。</p><p></p></div><hr><div class="diary-entry">18:43 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW2KXBX2HXJFNKSQ62PEBJ24" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>BiliBili 开始惩罚我了。首页上出现了大量这样我讨厌的视频：</p><ul><li>大肆宣传爱国的，见多了还挺烦的</li><li>反驳隐私的，像什么只有犯罪者才怕摄像头巴拉巴拉这种鬼话都说出来了。作死一开评论区还有人说只有恋童癖才会怕摄像头，真是莫名其妙</li><li>批评极端女权搞性别对立然后又用同样的逻辑搞刻板印象的。你俩谁也没比谁好，倒像苦命鸳鸯</li><li>说看到泰迪就想弄死的 —— 这个我好像一直没说过。我不喜欢这种氛围。我家幸运狗就是迷你贵宾，但没有做泰迪发型。这种品种的特点是智商高以及作为小型犬非常适合放在城市里养，因为不掉毛（这种说法很夸张其实。迷你贵宾的毛是卷的，会挂在我们裤子上，但依然难以看见），所以在城市里很常见。但许多人是压根没有驯狗所需的知识的，很容易没有主人样，被智商高的狗踩在头上。同样的事情在边牧上其实也能看到。不负责任还不牵绳的主人配上实际已经成为一家之主的狗，便形成了现在的刻板印象「泰日天」—— 关于「日天」，无论是什么狗骑跨行为都是本能的一种，但许多人会将其和「性」百分百扯上联系，实际上只是狗看不起你、以此来表达自己的地位。可以抬脚直接顶开，不过这无法解决更深层的问题，未来再说吧</li></ul><p>还有我明知推荐算法是神经病但还要刷，我罪大恶极。希望近期的哪一天，自己不要再抱怨已经抱怨过的事情了！</p><p></p></div></details><details data-group="diary_sections"><summary>六月二十七日</summary><div class="diary-entry">03:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW3H93EKJDHF9BVRZX1PDTZX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>下班回家，到家都十一点半了快。</p><p>在一家国内开进来的知名奶茶店里打工，可以猜猜是哪一家 233 总之卫生条件非常严格，可以放心。</p><p>我晚上洗器具把手洗烂了…… 第一次看到手上突然少了好几块皮，我的天啊。</p><p>晚班可以带走店里放着的饮品和甜点。我拿了三杯，放在纸袋子里，然后…… 纸袋子破了…… 三杯掉了出来，破了一杯……</p><p></p></div><hr><div class="diary-entry">04:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW3MF2CRNVR5EFW5VGQJTZDT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>很久以前玩 <em>The Designer's Curse</em> 的时候，被第一个怪的 AI 有所惊艳到。之后陆陆续续玩了些追逐类恐怖游戏，脑海里就开始想象做一个十分强大的怪物 AI，能够像现实里的生物那样追捕玩家。</p><p>最近想到了这个想法，上网一搜发现更久之前就有《异形》的一款游戏，里面的怪物异形就有很多很多逻辑树去演示这一点。</p><p></p></div><hr><div class="diary-entry">04:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW3NFABD3H8G3PHWG7675X3K" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>和男性自慰相关的玩笑浪潮什么时候能结束啊。感觉看了不知道多少个月了，哪儿都是。</p><p></p></div><hr><div class="diary-entry">15:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW4TGMBZYDQXNCBRY0XBXE7N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>妹妹要上初中了，学校离家里有点距离，所以母亲想让她去领学生用的地铁卡，每天坐公交车上下学。</p><p>但她基本上没有单独出过门。有次她提前跟我们说放学要和小伙伴走回家，我们恰点看她还没有回来，就开车跑出去找…… 找一圈还问了同学朋友，一回家发现她已经到家了，在客厅看电视。</p><p>记忆里我小学开始就有过放学走回家的经历，跑乡下玩他们也是自己上学下学。但放妹妹身上就觉得特别危险 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 尤其是她先前没怎么有过自己单独跑出去的经验，顶多是跑隔壁街去找她朋友玩。</p><p></p></div><hr><div class="diary-entry">16:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW4X2E16BCVEYKQBKA86T32W" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我很饿但我对食物失去了激情。</p><p>我最喜欢的食物在吃的次数多了后，逐渐失去了童年滤镜，变得没那么想吃了。让人觉得很难过，食物同家和回忆和过去和文化息息相连。我什么都失去了。我的饮食习惯在改变，变成了不知道是什么东西的样子。我会对不同文化的人们处理食物的方式而生气，可能是愤怒于他们在这里有着自己的圈子，能吃到自己熟悉的食物，但我吃不到。这里没有哪家店铺有个很大的竹蒸笼，每天早上起来会散发出热腾腾的香气；街上没有做火烧的老人推着奇形怪状的塔形小车；整个国家连驴肉都没有，只有欺骗我这样的人、在自己招牌上说自己卖驴肉的无良商家；我甚至难以找到做好吃的家常菜的餐馆。我的四周只剩下已经吃腻的料理包面店，还有我不习惯的其他国家的菜肴，以及美式中快餐。</p><p>我想要回家，但没有人理解我。他们指责我不懂感恩不知好歹，指责我逃离了中式教育却又想回来享福。家乡就是家乡，他们从未体会过离开家乡许久的感觉，就算是移民到了新的国家也有本地同乡搭建起来的地区和食物，却非要让我去理解他们，明明根本就不理解我！</p><p></p></div><hr><div class="diary-entry">20:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW5DTNMAH2JY4TD6F8GJN9NM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JH2FHXKNQFADV5ETNG5K.png" alt=":neocat_googly_shocked:" loading="lazy">​ 得好好考虑一下如何在没有公共桌子的地方，花半个小时吃饭了。</p><p>下雨时四周会弥漫狗臭的味道。</p><p></p></div></details><details data-group="diary_sections"><summary>六月二十八日</summary><div class="diary-entry">02:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW621SZQCXW43E2P0S5N403A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>家里的信箱就像是注册领取后、就被垃圾邮件占领的电子邮箱。</p><p>想买个虚拟地址了。然后搬去没有人知道的地址，把假住址告诉不信任的机构。</p><p></p></div><hr><div class="diary-entry">02:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW62GFCP227EF96S58BR5QAD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我的钥匙前段时间不见了…… 在跑完步之后。我确信它就在家里，但不知道具体在家里的哪里。这很奇怪，我的很多东西都有着自己的标签，比如钥匙的标签就是「显示器架子下面的东西」，所以我每次回家都会把它丢到显示器的架子下。但这次我发现钥匙不见后，它不仅不在架子下，也不在地上，更不在包里。没办法，我今天只好出门配了把，总共是三个钥匙，花了我 30 块钱 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3FZ75C9HA8Q3KRW12YT3F.png" alt=":neocat_cry:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">03:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW62XQCMDX9D8D3P5CAHDZJY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 我上完中文课这么久了特别想要知道我的同学们用的是哪个 AI 工具，怎么说话这么奇怪。后来我把这件事忘了一段时间，然后在 RSS 列表里发现一篇文章说话方式和那些 AI 工具一模一样，就又想起来了。</p><p>该 AI 工具的特点是会很频繁地使用顿号，然后特别喜欢强调别人把简单或者复杂的事情「说透」了（目前仅能想到这些）。</p><p>这让我突然好奇，我是如何知道它是用 AI 工具写的？具体的特征是什么？</p><p></p></div><hr><div class="diary-entry">03:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW63GQVSV754G1C2ZT9X201A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ44EHVDAKT706596R5DZ2.png" alt=":ottersgottaott05:" loading="lazy">​ 下班回家又有甜点吃。</p><p>明天和朋友出去玩，然后去见识一下网咖，我还从来没有去过网咖。</p><p>第一次去网吧还是因为父亲离开了家，去别的地方工作，母亲带我去网吧打 QQ 视频给父亲。后来 QQ 对他们而言被微信取代了位置，而我也几乎再也没有打过 QQ 视频，更没有去过网吧。</p><p>那时候应该小学都还没有上，但就已经知道网吧的性质相当「恶劣」，只有没有人生的人才会去！所以我才不去，这辈子都不去，我是好好学生！</p><p>顺带一提当时最喜欢的网吧笑话是成年人发现未成年人在网吧里，于是骂他叫他离开，结果发现人家是网管或者老板孩子 —— 嗯…… 小时候特别喜欢这种误解系笑话。</p><p>长大后不去的理由，和以上一点关系都没有，因为很快就知道网吧没有那么恶劣，再加上我就没有零花钱，也没有使用电脑的习惯，或者日后已经有了电脑所以不用再去网吧。总之，我再也没有跑到网吧里面去过。</p><p>现在的网咖，貌似是把网吧跟咖啡厅结合在了一起？我猜还有奶茶、炸物这种低成本高利润的暴利产品啦。</p><p></p><blockquote class="diary-thread-reply">03:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW63KPKKTPX2N370M94BM3BA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>误解系笑话我喜欢的还有：</p><ul><li>考 100 分但是用东西故意遮着，只露出来一个 <em>1</em> 或者 <em>0</em>，然后假装出一副不想要告诉监护人或者辅导老师的样子</li></ul><p>待补充…… 会一直编辑这条的。</p><p></p></blockquote></div><hr><div class="diary-entry">08:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW6MJ359WZXMWCENQJNCBP1C" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>大半夜睡不着跟室友大聊特聊生理性别、性别认同、性取向、pronoun 文化、LGBTQ+ 运动等等内容。这点之后再说。</p><p>然后我们俩开始玩大衍筮法，拿牙签给彼此算卦。我算对方的事业运算出了六爻全变的乾卦，对方给我算出了六爻也全变的水风井卦。我从书架中抽出了之前在教堂里取走的《漫画易经》，不过还是不太会读，所以最后是让 Kagi Assistant 帮我找了点资料来解读。</p><p></p><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">第一个话题的内容。长文。</summary>        <div class="diary-cw-content">14:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW79BVH91H3KV5E8GWBGC4BE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>因为今天纽约市有个 Gay Parade，所以她有点好奇我对此的看法。不过她先抛出的观点是她讨厌 pronoun 文化并推行它的人，觉得这变成了年轻人的时尚单品、潮流，而她讨厌没有脑子的年轻人，所以也讨厌 pronoun 文化。</p><p>Pronoun 文化具体点指的是在自我介绍时强调自己的 pronoun（代词）是啥，比如 <em>he/him</em> 等。我们的高中是公立学校，所以常有这个东西。当时我们接触到的一些会强调自己 pronoun 不顺性别的人，她都觉得是小傻子，所以也对 pronoun 不顺性别的人有了刻板印象，即搞亚文化且盲跟潮流的人。</p><p>她对性别的看法可以简单这么概括：根据人的生殖器来分辨，所以有阴茎的就是男的，有阴道的就是女的，然后还能分出双性人和其他。对于有男性/女性生殖器却声称自己是女性/男性的人，她的看法则是：改变性别认同意味着符合社会对该性别的刻板印象，但个体应选择去打破刻板印象而不是顺从于它。</p><p>我对 pronoun 以及性别认同的看法就…… 我能感觉出自己难以对它们感同身受，所以不强求自己能说点啥。但我否认运动的意义因为所谓的「跟风」而要被污名化，因为运动的存在是有意义的 —— 在此之前对方的观点是运动没有意义，人们应该把这些事儿留给自己，不要大肆宣传，还有什么理由但我忘了。</p><p>这需要提到「语言」和「世界」两个概念，即人们主观的想法和客观能观察到的规律。人们在一些事情上有着默认的想法，例如默认男女配对、会认为就算是同性婚姻也有男人角色和女人角色等，都是「语言」，而「语言」会进一步改变「世界」，例如法律等。运动的存在是决定通过改变「语言」来改变「世界」，以及起到个带头作用，避免弱势群体再被歧视。我的做法是将非传统的性别或者性取向正常化，传统的性别或者性取向是如何被对待的，我也就如何对待它们。这一点她也认同，不过不喜欢运动的宣传属性。</p><p>我们又提到两点：一是她认为宣传过多导致更让人讨厌了；二是她本人不喜欢宣传弱势群体，因为她觉得人们应该让自己变强、这样做什么都不会被人指指点点，而不是强调自己是要被保护的弱者。关于第二点，我认为这很奇怪，非传统的性别和性取向为什么要在社会里顶着传统性别和性取向没有的压力、变得地位高之后才能不被人指点？况且这个「不被指点」仅是因为他们够有钱或者地位高所以没人敢说，而不是因为社会包容了非传统的东西而没人会说 —— 两者差别很大的。相当于依然是站在主流的角度去看待非传统事物。当前性别和性取向运动的处境我会视作和「隔离但平等」时的黑人群体类似。人们在表面上认为非传统性别和性取向，跟传统的是平等的，但在许多事情上依然将二者隔离。而第一点，我没有啥想法，宣传就宣传吧。</p><p>说回我对性别相关的事情难以感同身受的理由，还有一个是我没啥朋友…… 所以我无法从同样有性别相关的问题的朋友那儿得知他们的想法。对方有这样的朋友，继而产生了「除非是真的动手术或者吃药改变了性别，否则都不认可」的观点。我对性别的了解没有多到可以评价什么的地步，不过对方提到没有社会的刻板印象的话，男女将变成区别不大的个体。</p><p>有什么其他记起来的我会回复这条以补充。</p><p></p></div>      </details></blockquote><blockquote class="diary-thread-reply">14:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW79ZQ4XJC06TR3HR84H94DQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>乾卦是内卦外卦都是天卦的卦象 —— 有些流派会称其为先天卦和后天卦，但大衍筮法只有内卦外卦的解读方式 —— 六爻全变则是六个爻都是「老阴 / 老阳」，对于乾卦而言就是六个老阳，意思是阳气太多了，得转变成阴。而六爻全变的乾卦还需要看「用九」，不能仅看变卦后的坤卦 —— 因为六爻有变，所以要全都反过来，从六个横变成六个虚线，也就是坤卦，意味着未来要变成的样子。</p><p>不想夸她所以只说我的卦象。水风井卦可以视作一个水井，有内涵藏在地底但不外露，而水井需要持续维护才能运作，且代价是格局小、视野窄。六爻全变意味着人要变化成完全不同的样子，也就是山火贲卦，可以视作山下有火的景象。这一卦象象征的是脚踏实地的同时，也有外在的装饰。整体想说的就是我要从现在的小水井，转变成更有内涵、更会宣传自己的样子 —— 但仅追求装饰，就会引火上身。</p><p>当然是仅供参考玩的，不过偶尔玩一下还是很有意思。通过个别的解读重新审视下自己。</p><p></p><blockquote class="diary-thread-reply">14:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW7AKJTCT433Z5XZX2163S37" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>关于如何弄大衍筮法：取 50 根…… 原本是木签还是什么的草，但我没有，所以我用的是 50 根牙签。取 1 根出来视作「天」，整局都不会使用它来算卦，放到一边去。手上现在有 49 根。</p><p>这 49 根分成两拨，右边的一拨里取 1 根，放在左手小指和无名指之间，视作「人」。接着将左边的一拨以 4 根一组分开，取余数（如果是余数 0 就取最后 4 根）。右边也是一样。得出两个余数后，相加，然后加上「人」的 1，就会得到一个数字。这时将 49 根重新混合在一起，重复先前的行为，直到得到三个余数，将它们相加，然后除以 4。根据得到的余数我们会得出这一爻是什么：</p><ul><li>余 1 是老阳</li><li>余 2 是少阳</li><li>余 3 是少阴</li><li>余 0 是老阴</li></ul><p>接着重复上面的行为，直到得到六个爻。顺带一提算爻是从内卦到外卦、从下到上算的。我们看到的六个横线，是下三个为内卦、上三个为外卦，而最底下的才是初爻。对于每个爻的解读也有说法，但我了解不多。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">17:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW7JTNQX8YJFNG11QZ4YXFKN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>路过了 PrideFest。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KW7JT0M2BWND7CWTY33RJHQF.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">21:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW83RC1121VPJ9BWD14MQSAT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>实际上不是真的路过，我要去的一家店在他们举行 PrideFest 的一条街上。路都被警察封上了，我说我想要去那家店，警察不让，理由是整个大道都被封锁，但也没有说怎么过去。我和朋友转悠了很久才找到一条进入封锁区域的路线。真是莫名其妙，这么大且繁忙的区域被封锁，却没有任何人告知我们如何绕过它或者进入它，警察像我欠他几百块钱一样不耐烦。我们到达店的时候发现，店所在的街道根本不是真的被封锁，甚至都没有多少人在街上。</p><p>走的期间还遇到扛着共产主义大旗的人，说自己是马克思共产主义者，要反对彩虹资本主义。他们抗议的地方，旁边就是 PrideFest 的游行车。游行车都放着大声到可怕的音乐，我被恶心到必须戴着降噪耳机才能正常行走和对话。一扭头，看到好几条狗在跟着主人，又想到它们听力更加敏锐，恐是耳膜都要被震掉了。</p><p></p><blockquote class="diary-thread-reply">06-29 06:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW91HEY44T14B2BAW9JVAV5H" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>因为好奇所以去了解了一下彩虹资本主义是什么。大意说是资本主义利用 LGBTQ+，假装支持他们以获取利益，并将 <em>pride</em> 商业化。政府同样也用过这个技巧来换取选票和支持。</p><p>因为表面支持和赞助游行，对于企业而言都是小投资，轻轻松松就能获得 LGBTQ+ 群体的青睐。而游行逐渐变得…… 儿戏化？许多问题还未被解决，依然有着支持 LGBTQ+ 群体但内部搞歧视的企业在。我不认为这是足够的，想要打破规则却满足于现状无疑是温水中的青蛙。</p><p>有意思的是在其 <a href="https://en.wikipedia.org/wiki/Rainbow_capitalism" rel="nofollow noreferrer noopener" target="_blank">Wikipedia 页面</a> 内有个引句：</p><blockquote><p>Today it isn』t homosexuals who are persecuted; it』s their critics, whether it』s Ann Widdecombe or Tim Farron. [..] Gay people should be as free and equal as straight people. And today they are. That』s wonderful. But the fact you are gay is the least interesting thing about you. Tell me something else.</p><p>如今受到迫害的不是同性恋者，而是他们的批评者，无论是安・威德科姆还是蒂姆・法伦。[..] 同性恋者应该和异性恋者一样享有自由和平等。而今天他们确实如此。这太棒了。但是，你是同性恋这个事实，是你身上最无趣的一点。跟我说点别的吧。</p></blockquote><p>引得室友尖叫：<em>this!</em>（上下文见之前的 toot 懒得引用了）</p><p>现在因 Trump 上台搞的反 DEI，许多企业都跑了没有继续搞 pride 的东西，也是很符合他们为了利益所以站边、分点汤喝的形象。</p><p>目前先想到这里。</p><p></p></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>六月二十九日</summary><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">负面情绪相关。</summary>        <div class="diary-cw-content">04:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW8SV4CYE62YZHZ0V2CGFBK6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近状态很糟糕，不知道自己一天天的在干什么。</p><p>本职工作的问题在很缓慢地处理中，根据 mentor 的说法 cold applying 已经死了，只能在 LinkedIn 上 cold calling、network、coffee chat 然后被内推去面试上岗。</p><p>副业的事情也是缓慢地学习中，但我对这个领域的现状可以说是一窍不通，完全是被推出来干活的。</p><p>打工的话，现在依然在培训阶段，但我觉得这家店事情太多，不说未来愿不愿意做下去了，能不能过考核都是个问题。</p><p>天我什么都做不好，最近也没有在阅读文章，RSS 清单从来没有堆积过这么多内容。我也不知道我在做什么想什么，今天花了上午和下午的时间在外面虚度光阴、玩，我在干什么我。为什么我做不好这些事情，是我太高估自己了吗，其实我就没有那么厉害，没有他人的庇护根本活不下去。</p><p></p></div>      </details></div><hr><div class="diary-entry">05:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KW8Y8DGVJK374D92MPFWWEAE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>回家路上发现远处有什么东西在动，发现是个大浣熊。</p><p></p></div><hr><div class="diary-entry">20:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWAFVS44JCP841D4HR94HJGM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>好热啊好热啊。好想要喝西瓜汁。</p><p></p></div></details><details data-group="diary_sections"><summary>六月三十日</summary><div class="diary-entry">04:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWBBNQY1CKNDQQQ1A808DG4Z" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>夜驱，回家泡泡面吃。运动后的 goyslop 最好吃了 ——</p><p>—— 这个词最近从朋友那儿学的，是个反犹主义的网络俚语，意思是垃圾食物。<em>Goy</em> 的意思是「非犹太人的」，<em>slop</em> 就是「垃圾」（或者泔水。说来我之前做过的饭被朋友说过是马桶里的泔水……）。</p><p>之前跑完都是去 711 买热狗吃，两个三块钱，配合番茄酱很好吃。今天过去没有吃热狗的心情，看泡面发现一桶 4 美元，吃你个猫猫毛。回家把仅剩的一包泡了，明天早上去唐人街进货，顺便让自己思考下人生。近期的状态太差了，很不对劲儿。室友觉得我的生活需要有所改变，我觉得说得很对，我要去做平日明显就没有在做的事情。</p><p></p></div><hr><div class="diary-entry">13:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWCCNX9T831RRJRX2JE3QVPS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>匹克猫日常上我桌子提升关注度，可惜这次我桌子上摆满了东西，所以它只能四个脚脚蹲在桌子的角落了。</p><p></p></div><hr><div class="diary-entry">14:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWCDQMNE1RRD1RKS61FMWT2J" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://www.bilibili.com/video/BV1PPjU6XE33" rel="nofollow noreferrer noopener" target="_blank">https://www.bilibili.com/video/BV1PPjU6XE33</a></p><p>我对《神威》的最深印象是舞萌 Expert 谱面里的那一长串交互…… 至于为什么不是 Master 的，那自然是因为…… 哈哈。</p><p>在 Sasakure.UK 的音游魔王曲人格里，我会更喜欢他的 <em>Raputa</em>。不过这个人做的音乐太多了，实在是说不过来，除了核外还有个 Vocaloid 人格。在我还在用 Soundcloud 听无限播放的随机 Vocaloid 曲时，就有很多印象深刻的是他的，比如 <em>Puppet Theatre of Twee Box</em>。</p><p></p></div><hr><div class="diary-entry">14:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWCE8GHJ788561KFAH2HEK1Y" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>久违游玩电脑游戏，在尝试《空洞骑士》。我玩游戏的技术力很差很差，所以不期望自己能快速通关。这样说来许多时候我都没有在玩要求高操作的游戏。呃，《泰拉瑞亚》算吗……？</p><p></p></div><hr><div class="diary-entry">15:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWCHCBCDYNG5N6J89N6WDQKS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>好热啊我真的要出门吗……</p><p></p></div><hr><div class="diary-entry">15:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWCJ8E4B71D46XN2P559MA2D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>LinkedIn 上找已经毕业且找到工作的校友 connect，再度察觉到开发的技术和水平难以被量化这一点。要是在简介里说自己会什么技术栈的话，我看了只会觉得你没啥东西；就算是在 AI 工具炸出来之前，学习不同的技术栈也不会花费过多的时间 ——7 天速成的也是「会」，只听说过的也是「会」，人要像印度人学习，把自己吹成湿婆那般，才能在当今社会下存活！—— 我在夸张和中二。不过一个业内的朋友确实就是靠电话面试吹自己一周速成语言和框架，被某领域的大厂带走了，颇有意思。</p><p>但去看可量化的指标，也不太能看出来什么，尤其是有人为了写量化，还特意拿平台人数说事，但那个 bullet point 讲的又不是优化或者有所关联的事情。</p><p>那还可以看项目，不过大家的 GitHub 账户，怎么全都是二次元头像，刻板印象过重了（怎么我也是）！真的去做过完整的项目的，不见多 —— 好啦我也没写过多少现在说这些根本是在瞎指指点点。</p><p>只有共事才能知道一个人的水平，那看简历是最没用的。面试虽能看出一些，但依然很奇怪，因为大量面试题根本不是实际工作中需要闭卷搞明白的。带回家去做的作业倒是有趣。</p><p></p></div><hr><div class="diary-entry">15:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWCKTW9CH05EX4S3MF0SA0WH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前几天在办公室里无聊到发昏，随着背景音乐用着诡异的舞步在转圈。看到室友，我忽然脑子里涌出一句话，并跟她说了：</p><blockquote><p>你不觉得我很有舞蹈天赋吗？</p></blockquote><p>然后她笑了我三天。</p><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4RH41FBJ2K2SH4YNQA8W.png" alt=":ottersgottaott21:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">16:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWCMFQ86MKGHACKM40WHY92B" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我得再次着重考虑夏装了因为我热得受不了。我现在的方案是 Polo 短裤腰带，没有钥匙链和拖鞋基本上就是 cos 白男的服装（尤其配上卡其色），有的话就 cos 男德学院的学生吧。但是！这个 Polo 衫其实要比我的衬衫厚不少。衬衫最大的问题就是它是长袖的，要是短袖的话我就天天穿了。据说短袖衬衫是只有中国才会卖的东西，相当稀少，可以考虑。至于 T 恤，我实际上完全不会穿它正经出门，所以不考虑。</p><p></p></div><hr><div class="diary-entry">19:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWCYNQ5TTF184KE47QFVY8XN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>早知道绕点远路去买四五块钱的西瓜冰沙了，跑到街机店时，附近的店竟卖十块钱。我也忘了叫他们别放糖，喝下去就是果糖那种黏腻感，实在是不喜欢。</p><p>这家街机店看上去脏脏的、暗暗的，每台街机上都有贴纸和涂鸦，有些恶心。不过位置偏僻，进去别说没有客人了，我都没有看到店员。然后我就在里面霸占舞萌机玩了一个小时，嘿嘿。没有人的时候反而能享受音乐、节奏和游戏，有人的话总是紧张，得等一段时间才能适应。</p><p>游戏时间结束，我去常去的超市里进货 <del>垃圾食品</del> 储备粮食。</p><p></p></div><hr><div class="diary-entry">19:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWCYYWDVC8CJ1THGKZH8N48R" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我宣布美国华人的汉语是新的方言，要另起一个新分支才行。</p><p><em>Mott</em> 的汉语音译是「勿」。</p><p></p><blockquote class="diary-thread-reply">19:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KWCZHB8H2294AYVHZ37CE219" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>许多老移民不会说普通话，只会说方言。另一批不讲该方言的人，会用自己的方式去「说」这些方言。于是我们能看到写作「芥兰鸡」读作「尬蓝唉 ——」实际上是甜口的西兰花炒滑鸡片。</p><p></p></blockquote></div></details></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;酷暑逐渐来临。连打工兼职都能失业的我，依然在拼命找工作中。为了赚钱，这个月开始学习些和计算机不相干的东西。&lt;/p&gt;</summary>
    
    
    
    <category term="想法迭代" scheme="https://blog.cytrogen.icu/categories/%E6%83%B3%E6%B3%95%E8%BF%AD%E4%BB%A3/"/>
    
    
  </entry>
  
  <entry>
    <title>班级政治</title>
    <link href="https://blog.cytrogen.icu/posts/851c.html"/>
    <id>https://blog.cytrogen.icu/posts/851c.html</id>
    <published>2026-07-01T04:00:00.000Z</published>
    <updated>2026-07-06T21:52:06.974Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我想说说我来美国后，上小学时的事情。其实我一直都很想分享自己在美国时的经历，将其整理成一个别于「日常生活」的分类，就叫「美国十年」好了。它和政治没有关系，就连这篇文章的标题「班级政治」，也和人们常谈的政治不同。整个系列只记录我这十年来有记忆的事情，更倾向于分享日常。</p><span id="more"></span><p>我来美国前是小学四年级，来美国后翘了这下学期，当了几个月的「无校游娃」。父母担心我难以融入，于是把我推进当地一家华人浸信会中，去他们举办的免费暑期辅导班里待待。说是辅导班，其实就是教会里的大学生、研究生带我们几个小学生。我也没有真学到什么，记忆犹新的就是这班上有几个烦人的男生，整天嘲笑另一个出生在墨西哥的女生。我因为好奇和好谈，还被「老师」拉到别的地方去坐，那也是我作为学生第一次被安排在特殊的地方坐着，让我这个四年好学生很是委屈。</p><p>同年秋季，我根据地址被安排到一家附近的小学里就读五年级。因为英语不达标，上的班是双语班，老师是个会说普通话的中国人，我们要叫他 <em> Mr. Tang</em>。说到这个「英语不达标」，我就得好好说道说道了。在我们一家出国之前，母亲其实有把我送进英语辅导班里提升提升，结果那个辅导班的老师竟告诉我美国除了加法外没有减法、乘法和除法！而加法的说法是 <em> X and X is X</em>，即「X 加 X 等于 X」。这当然是很不对的了，你至少要用 <em> add</em> 这样的动词吧（口语更常用 <em> plus</em>）。没有减法、乘法、除法更是无稽之谈。但当时对美国一无所知、也不会上网冲浪只会玩 4399 小游戏的我自然是信得不能再信了。唉……</p><p>上学的第一天便是不适应。当时的学生们只有我一个是突然转学来的，有些虽和我是同个时间来美国，但没有选择去翘掉四年级，所以对美国的小学也算熟悉。其他人则都是 ABC（America-Born Chinese，在美国出生的中国人），但不知道为啥被安排到双语班来？我不知所措，不知道他们说的英语是啥意思，也没有朋友在身边。不过还是和一个同桌的女生说起了话，这个人我就简称甲。</p><p>午饭时，这个班级邪恶的一幕才慢慢开始揭晓：一个女生主动过来找我，然后跟我说「你不要和甲玩，她以前偷过学校东西」。我再看饭桌上其他女生投来的异样的目光，当时的我还不知道什么是「霸凌」、它有多严重，但我知道自己要是继续和甲相处，就会发生不好的事情。于是午饭后，我懦弱地远离了甲，让她难过极了。</p><p>但这件事依然没有结束。虽然我和甲没有再相处，在之后认识了其他同学，但暗处似乎还有人看不爽我。新交的朋友在一次放学后跟我说，「你要小心乙，她在背后说你坏话，说你很臭。」这个「乙」我不认识，不知道是班上的哪个女生。我们二人商讨一番，得知她是因我和甲相处过一会儿，记恨上了我。</p><p>现在我已是成年人，再去回望乙的种种行为，就会觉得这个小孩儿…… 行为幼稚吧，但对于其他还未开智的孩子而言破坏力十足，实在是可怕。在之后我才知道，甲在学校里被霸凌许久，带头的就是这个乙。乙不仅拉拢其他女生冷暴力甲，还会连着欺负其他对甲好的人，这里就包括不知情的我。</p><p>至于甲的罪证，就是他们之前说的「以前偷过学校的东西」。我不知道她偷过没有，但作为题外话还是说说「偷窃」这个行为。 我在这所学校里目睹过学生偷学校里的东西，比如故事书。当时是我被推荐去上校后的美术班，接连被两个墨西哥女孩偷画，然后看到一中国男孩偷了两天的书。我没有经历过这种事情，根本不知道该做什么好。以前在山东读小学，同学可都不会这么不要脸啊！幸好当时新认识的同学听我一说，勇敢站出来指认。相比之下，我可以说是胆小如鼠。</p><p>说回乙吧。我天天忙着跟上英语进度，就已经够累了，根本没有精力去找这个背地里说我坏话的家伙儿是何方神圣。不过她自己倒是主动找上门来了。一天中午，我和朋友们在玩 Suit Sprint，但我不知道 <em> sprint</em> 这个词儿，以为他们在说 <em> sprite</em>，所以乐呵呵说着 <em> sprite</em> <em>sprite</em>。她忽然走上前来，开始骂我，叫我想要跳舞的话就滚去别的地方跳。因为逻辑跳跃过大，我没有反应过来她其实是在阴阳怪气，所以没有放在心上。之后才知道这人就是乙。</p><p>第二次与乙接触，是我在体育课跑步。体育老师在室内操场里摆放了数个路障，让我们绕着路障跑。我被绕晕了，有一个路障没有按照规则绕。她又不知道从哪里跑出来，指着我的鼻子开始骂「你作弊！你作弊！」</p><p>班里的霸凌，我不清楚其他同学有没有上报给老师，但我没有。我不知道如何处理这些事情，过去在山东的小学里也发生过欺负人的事情，但是老师们都会发现并且点名批评，我也从来都不是个会寻求他人帮助的人，老师没发现的话就只能挨着，反正再痛还能有母亲骂我打我时痛吗？区区小屁孩。</p><p>好在她针对我的次数不算多，很快她便换了个面孔对我：友善热情的样子，真是令人作呕。我没想和她继续纠缠，所以日后再也没有和她扯上联系。不过甲到学期结束，依然是被她们一伙人欺负着的，没有真心朋友。处境对比下来是好了些，可是依然令人悲伤。我长大后惊觉于自己的弱小，不过小升初后我再也没有见到过甲和乙。</p><p>背景故事算是讲完了，现在终于可以说说标题的「班级政治」了 —— 没想到吧！</p><p>从前面所说的我想读者朋友们可以看出来，乙是个很爱「表演」的人。她算是 <em> teacher's pet</em>，和老师关系不错。五年级的下半学期，这老师想了个新制度，将学生分成五六个桌子，每个桌子算一个小组。每个小组里会有一个组长，负责管其他组员，而每次上课如果有组员表现不错，例如回答积极，该组就能得到根小木棍。每周五老师会结算小木棍的数量，并赋予小木棍数量最多的小组奖励，像是马卡龙这样的小零食。</p><p>乙自然是当上了她那个组的组长。她的两个朋友也是其他两个组的组长。几周下来，她们想到了个不用竞争、彼此都能给彼此面子的方法，那就是严格拉平小木棍的数量。这样每个组都能拿到奖励。不过这个方法依然需要和其他不是她们朋友的小组竞争。我很不幸地，正好在乙的朋友丙的组里。这丙时不时会告诉我们何时停止举手回答问题，把机会让给乙或者另一个朋友的组。</p><p>这样的「和平」直到丙将计划告诉了老师，才结束。我还记得那天周五，老师拿着一盒五颜六色的马卡龙生气地走到班里，开始训我们。他一直以为这几周的平手都是巧合，结果竟是故意为之的。然后他带头批评了乙丙等人，这导致了二人的决裂。</p><p>乙开始冷暴力丙。再之后的记忆就不太清晰了，因为学期也快结束、得考虑申请哪所初中了。我去的初中离家里很远，走路过去半个小时。在那所初中里发生的故事，就等到下一次再说吧。</p><p>五年级的这一年在我内心里记了许久。我做过错事，附和他人去霸凌别人，实在是不应该。我也经历了许多没有经历过的，不过很可惜，这一年我没有真的学习到如何应付霸凌，也没有搞明白如何维系人际关系。能好好和人深交并建立健康的关系，这一点要到我高中时我才深刻体会到。</p><p>这件事情我前几个月讲给室友听，她和我处境正好相反；她是在中国的学校碰上了霸凌，到了美国后反而如龙得水，顺得不能再顺。不过对于我的事情，她很直接地说，我当时居住的华人区的人，不过都是群中国混不下去的穷人，偷渡跑来美国的。本来就没有什么文化和教养，生的孩子也随父母。这种满地都是穷鬼的地方，自然到处都是欺凌和攀比。再就是她觉得小孩子本来便是邪恶的。他们像是猴子一样，发现暴力有趣就会满脑子都是暴力。</p><p>我也很想搞明白为什么小孩子会做这样的事情。今年我的妹妹和当时小升初的我一样大，她就不是会做这种霸凌行为的人。不过室友的解释总是带有着对底层的歧视，并且她当时被霸凌时，上的可是深圳的小学呀，家里都不缺钱的。</p><p>我仅认同「父母影响了孩子」以及「孩子不成熟」这两点。我当时所住的华人区，氛围在我看来十分压抑，同乡之间的互相攀比，还有异乡之间的瞧不起。我作为一个来自山东，无法混入福建圈和广东圈的异乡人，更是二者嘲弄的对象。那里的人会让我想起乡下外婆家那边的邻居，在我很小的时候便总是刁难我，用方言骂我是外乡人。他们的孩子也学着骂我。我只有在山东才是正常人，是老师眼里的好学生，是同学眼里的好朋友。</p><p>直到十多年后的今日，我依然难以融入到美国的任何一个团体。不了解我的人经常表达出对我的羡慕，认为我移民到美国来实在是太好了，但我不这么认为。不像室友，她是从地狱的中国跑来美国，才在全新的环境里焕然一新，我则是本来在中国生活得好好的，忽然被父母决定带走，然后在美国活得相当痛苦。</p><p>我有时会幻想，如果我继续待在中国，会如何呢？我一定会完整地经历中式教育、考高考，然后现在偶尔会在六月份的哪一天梦到自己在高考吧。我会有朋友吗？我的朋友都是谁？但我也会同样地失去室友这个好朋友。</p><p>室友总是听到我的幻想，然后表示可能过得会更差也说不定。是啊，那也有可能。</p><p>我有时会想，经常表示外国更好的中国人，是不是因为中国的环境对他们而言够糟糕了，他们急需一个可以幻想的对象，来安慰自己只要离开了当前的环境，便能过上好日子。我对中国的幻想，想必也是同样的：我所处的环境对我而言够糟糕了，所以我需要一个虚构的对象，安慰自己只要去了那里，我就能过上好日子。</p><p>美国十年，也是我乡愁的十年，虚构的十年。我会想要写出这些想法，恐是因为幻想已经无法满足自己了。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我想说说我来美国后，上小学时的事情。其实我一直都很想分享自己在美国时的经历，将其整理成一个别于「日常生活」的分类，就叫「美国十年」好了。它和政治没有关系，就连这篇文章的标题「班级政治」，也和人们常谈的政治不同。整个系列只记录我这十年来有记忆的事情，更倾向于分享日常。&lt;/p&gt;</summary>
    
    
    
    <category term="美国十年" scheme="https://blog.cytrogen.icu/categories/%E7%BE%8E%E5%9B%BD%E5%8D%81%E5%B9%B4/"/>
    
    
    <category term="情感" scheme="https://blog.cytrogen.icu/tags/%E6%83%85%E6%84%9F/"/>
    
    <category term="社会学" scheme="https://blog.cytrogen.icu/tags/%E7%A4%BE%E4%BC%9A%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>读《虚构一九八七》</title>
    <link href="https://blog.cytrogen.icu/posts/97a1.html"/>
    <id>https://blog.cytrogen.icu/posts/97a1.html</id>
    <published>2026-06-25T04:00:00.000Z</published>
    <updated>2026-07-06T21:52:06.978Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>开始捣鼓手账后，我开始记录自己的 TODO，然后发现上个学期中文课上读的内容还没写完。别说写完该系列了，我清点过后还剩足足十七个短篇小说没写读后感！</p><span id="more"></span><p>我发现我在清理 TODO 时，最大的问题在于我非常在意 TODO 列表的处理顺序：必须是从上往下的。「Blog 或 Research 想法」分类的 TODO，按照顺序下一个要写的是…… 如何玩三阶魔方、如何玩二阶魔方、如何玩四阶魔方、如何玩三阶五魔方。</p><p>先不提最后这个三阶五魔方我实际上在现实里也没弄明白咋还原，光是第一个「如何玩三阶魔方」，我就在编写教程文章时发现，这东西很难用文字说明白！还不如读者朋友们去视频平台上找什么，「十分钟速通」视频呢。</p><p>所以我决定无视这些烦人的 TODO，先开始写我最感兴趣的内容，那便是这篇由赖香吟写的《虚构一九八七》！</p><p>再就是我发现，先前写影评和书评时，常常会陷入到必须要把整个故事用自己的方式重述一遍的困境内，导致我很难写完一篇文章。从这篇开始，我会先简要复述剧情，然后着重分析小说内没有直接提及的内容 —— 不过写完后发现自己还是会潜移默化去重述一遍故事……</p><h3 id="小说前"><a class="markdownIt-Anchor" href="#小说前"></a> 小说前</h3><p>在讲这篇短篇小说之前，我要先说说 <em> metafiction</em>，即「元小说」、「反设小说」。</p><p><em>Meta-</em> 源自于希腊语的 <em> μετά</em>，含义是「在…… 之后」、「超越」、「关于」，或者「更高一层次的」。Aristotle 的著作 <em> Metaphysics</em>，或者更熟知的，《形而上学》，便使用了这个前缀。如果直译这本书的标题的话，那就叫《在物理学之后的》。对于 Aristotle 而言，能超越物理学、在物理学之后、可以解释物理学无法解释的「存在本身」的，就是哲学。</p><p>或者另一个程序员们会常看到的例子，是 <em> metadata</em>，也就是「元数据」。<em>Meta-</em> 也有着「关于某的某」的意思。对于 metadata，它的意思便是「关于数据的数据」，也就是描述了数据的数据。</p><p>那么同个逻辑套用在 <em> metafiction</em> 上，<em>fiction</em> 是「小说」的意思，那么 <em> metafiction</em> 就是「关于小说的小说」、「关于虚构的虚构」。</p><p>《虚构一九八七》正是这样的一篇短篇元小说：一篇关于如何创作小说的小说。</p><h3 id="小说中"><a class="markdownIt-Anchor" href="#小说中"></a> 小说中</h3><p>整篇小说讲的是女主人公的班上死了个同学，名为「谢彩文」。主人公发现自己根本不了解这个女孩，于是心生幻想，写了篇以谢彩文为主角的短篇小说。</p><p>小说里这谢彩文成了韦老师从大陆来到台湾后收养的女儿，还喜欢上了学校图书馆里的黄先生。最终谢彩文因为不舍黄先生的离去，向他表达心意，却被拒绝；黄先生还将此事告诉了自己的养父，导致自己被骂了一顿。结尾，谢彩文自杀而亡。</p><p>主人公将小说拿给写作研习活动的郑老师看，对方却认为结尾太做作，让主人公修改一下。同时主人公还和学长谈起了恋爱。把这事儿跟学长一说，学长觉得小说这东西，应该有意识一点、刺激一点。懵懂下，主人公写起了小说的第二稿。</p><p>这第二稿里，谢彩文依然是韦老师在台湾的养女，但这次她结识了学长，并喜欢上了他。学长让她去查清楚自己的身世，却遭到韦老师的激烈指责：「异地亲情的不可指望」、「政治的无限蔓延」……「让你读书是叫你来违逆我吗？养育之恩比不过外头小言小论？」结果，韦老师因病倒下了。绝望的谢彩文不知道该如何是好，又发现学长和更美丽的女子谈起了恋爱…… 最终，谢彩文再度自杀身亡。</p><p>主人公将自己的得意之作寄给郑老师，却被退回，反馈和上次一样：「怎么愈改愈做作呢？」主人公大受打击，开始反省，自己不过是一直在捏造谢彩文的死，这一行为便是「做作」的。结尾主人公和学长一边聊着，一边看着游行的队伍走在大街上……</p><p>可以看出，这篇故事的主要剧情内容，便是主人公在写自己的小说，以及她写小说、改小说的前因后果。</p><h3 id="小说后"><a class="markdownIt-Anchor" href="#小说后"></a> 小说后</h3><p>我这个月的中旬，在慢悠悠重新阅读 <em> The Absolutely True Diary of a Part-Time Indian</em> 这本我高中时的读物。书里有个极客角色，曾经跟主人公说了段让我颇有感触的话：一本书你要读三遍，一遍是直接读完、感受文字里的情绪，一遍是将文本和历史关联上、搞明白为什么作者会使用这个「词」；至于第三遍，作者没让他说完，但我在网络上找到了类似的理论，第三遍其实是要搞明白该文本为什么是和我们有关的、为什么我们读了它会有某某感想。</p><p>元小说的内容，自然便是我们第一遍阅读时，能观察到的事情。而「小说后」，我想要说说这第二遍。</p><p>结尾故事写到，主人公看到了「游行的队伍」。我先前刻意不去提小说中和政治、国家相关的内容，便是将它们留到了「小说后」。要理解这篇小说，就得搞懂标题中的这「一九八七」指的是什么。</p><p>我们先回到 1945 年，日本投降、二战结束的那段时间。台湾民众为日本的殖民统治的终结而欢呼，但很快发现接管台湾的国民党政府也不是什么好东西。</p><p>1947 年 2 月 27 日，台北一小贩走私香烟，被专卖局的查缉员发现。该小贩不仅被打伤，还有个市民被误杀，引起台湾群众的群情激愤。次日，政府选择开枪镇压游行的人们 —— 这便是二二八事件。</p><p>3 月 8 日，国民党政府开始自北向南展开全面武力镇压，这便包括了清除藏匿分子的「清乡」行动，大肆搜捕和杀害百姓，甚至还有台籍社会精英和领导阶层。</p><p>两年后，国民党和共产党的内战中，前者节节败退，恐是政权要掉凳子上了。为了巩固自己的威权统治，政府颁布了《台湾省戒严令》，宣告自 5 月 20 日零时起在台湾全境实施戒严；这一实施，就实施了足足三十八年，曾是全世界持续时间最长的戒严令。再配合上其他恶法，台湾开始了「白色恐怖」时期，不仅禁止公开讨论和研究二二八事件，还不允许组织新的政党、限制新闻的出版自由、禁止抱有左翼言行或台独主张，甚至对政府的批评都会被算成是在搞叛乱。</p><p>台湾社会压力随着时间的推移，不断地累积。民间力量逐渐涌现和崛起，再加上国际局势形成的压力，总统于 1987 年 7 月 14 日终是宣布次日起解除戒严令。</p><p>哎，<em>1987</em>，不正是标题中的「一九八七」么。</p><p>是的，这篇小说隐藏在「元小说」这一设定之下的主题，就是台湾的解严。而赖香吟对此的看法，在小说的第二自然段内便能看出端倪：这一段讲的是主人公的班级，因为谢彩文的死而乱作一团。主人公还借此提到了母亲参加葬礼时的行为举止，因过于特殊，而让她觉得死亡是不同寻常的。</p><p>接着几个自然段里，主人公开始说这谢彩文多么普通、多么渺小、多么不起眼 —— 可就算是班上如此不起眼的同学，死后还有这么多后事要交代，那何况是戒严时期这么长、这么庞大的时代的死亡呢？</p><p>当时台湾民众们对解严的期待，远远超过了预期。他们天真地认为，只要解严了，整个国家的处境便会一飞冲天、变成好的民主国家。但赖香吟认为，台湾社会根本没有做好准备，多数人（或者用我爱用的说法「一般人」）并不懂得政治。这份自由他们不仅不知道怎么使用，也会很快消耗掉解严后的兴奋，转为陷入迷茫和虚无之中。</p><p>小说中用了一些以物喻物的手法，来暗示当时社会对解严的看法。例如导师对着同学们说：「上大学你们就自由了。」这和当时社会的主流看法「解严后便自由了」不谋而合。至于已经上过大学的读者朋友们，自然也是知道这句话的真实性，真像驴头上挂着的胡萝卜呀！</p><p>小说还有一些有趣的暗示，独属于那个时代。主人公写韦老师是从大陆来的这一点，实际上并没有在「现实」中明确提及过，但有两处暗示：一是韦老师教地理知识说的是长江和秦岭淮河附近的土壤，都是对台湾本省学生来说是陌生且遥远的地名；二是他送给了主人公《沈从文自传》—— 一本记载了中国现代文学作家沈从文，从湘西小镇走向广阔世界的成长记录的书。</p><p>关于外省人只身来到台湾、遭遇乡愁和身份认同问题，这一点在 <a href="/posts/9027.html">《那片血一般红的杜鹃花》</a> 也有所体现。当时我写说，王雄死在了 1987 年、黎明之前，但现在我要对此打个问号了：解严了，这些问题也会得到解决么？</p><p>关于什么是「本省」、什么是「外省」，此处补充下吧：本省人指的是台湾本地的居民，主要是清代以来就从各地移居台湾的汉人后代，也包括原住民；外省人指的是 1945-1949 年间随着国民党政府来到台湾的大陆各省人士以及他们的后代。</p><p>俩省人在语言、文化经验、历史记忆上都有着差异。这一点未来也能在其他短篇小说中的角色上看到。</p><p>第二节的开头，主人公在外面偷听到几个文艺队工作人员的对话：当地城镇是二二八事件中唯一一个没有发生枪杀事件的地方。乍一看是在歌颂平安，但第二个人说道：「全是望族士绅的后代嘛。」</p><p>「望族士绅」这个词儿由两个部分组成：</p><ul><li>望族，就是名门望族的意思，指在地方上世代累积了财富、声望和影响力的家族。这些家族通常拥有大量土地或商业资产，在地方上扎根数代，形成稳固的社会根基；</li><li>士绅，则是中国传统社会皇权与民间之间的中间阶层。皇帝的权力理论上至高无上，但实际上中央政权往往只延伸到县一级，也就是所谓的「皇权不下县」。那县以下的乡村秩序，就是由这个士绅阶层来维持。包括但不限于：<ul><li>代表官府执行公务，同时也代表地方利益向官府交涉</li><li>修建书院、宗祠、道路、水利，组织赈灾、调解纠纷等</li><li>以儒家伦理为依据，维护地方的风俗和等级秩序</li><li>掌握读书、受教育的特权</li></ul></li></ul><p>台湾的士绅阶层相当特殊。首先清代时台湾是移民社会，早期的社会秩序由垦户、业主、头家等地方实力派主导。随着社会逐渐稳定，部分家族开始通过科举、经商、购置土地等方式上升为地方望族。</p><p>在之后的日本殖民时期，日本笼络和利用了地方望族来协助殖民统治。这些望族被授予绅章、任命为街庄长或协议会员，成为殖民政府与台湾民众之间的缓冲层。他们也因此进一步巩固了财富和地位。</p><p>战后国民党接管了台湾，同样需要依靠地方望族来维持治理。地方领袖的家族相当于换了个统治当局合作。</p><p>这样我们便理清了，主人公所在的小镇不是因为和平所以没有发生枪杀事件，而是因为地方望族早已与统治体制达成共谋，社会结构本身就是压制反抗的无形大手。</p><p>那么解严了，小镇会有变化么？望族士绅的权力不依赖于戒严或不戒严；他们的支配地位是跨政权且跨时代的。对普通百姓而言，换了统治者、解了严，地方上的权力结构依然如故，生活并无实质改变 —— 这便是作者隐藏的另一讯息。</p><p>第二节结尾，主人公认为谢彩文已经死了，关于她的一切全都停止了，并想着自己是不是理解了死亡。小说中主人公对谢彩文的死，所抱有的想法，近乎都能和作者对戒严时代的「死」一一相联。在之后，主人公对谢彩文的「死」的看法还会更新一次。</p><p>总之第三节开头，主人公思来想去开始写起了以谢彩文为主角的小说，也就是第一稿。这篇小说稿在暗示什么，我研究后有了个大胆的猜想：谢彩文作为「养女」，代表了台湾；韦老师作为「外省来的养父」，代表了外省权威；黄老师可能暗示的是 1979 年美丽岛事件的核心人物之一黄信介。谢彩文对黄先生的爱慕，象征着台湾年轻一代对民主自由的向往，但这种向往在戒严体制下被拒绝和压制。最终，谢彩文毁灭了自我，象征着台湾社会当时的精神状态。</p><p>第三节结尾，主人公被这篇小说感动得不行，然后在第四节开头打算新写一篇，却发现怎么写都是在原地打转，根本写不出来新东西 —— 亦或者说「真正」的东西。因为小说中谢彩文的死，是主人公捏造出来的，而她为自己写出来的悲剧而感动。这就是小说标题中的「虚构」。</p><p>学长主动向主人公提起二二八事件后，主人公的反应则是「听过但不知道是什么」：</p><blockquote><p>后来我真的去了学长主持的社团，像个乖巧学妹那样坐在圆桌的边边，渐渐知道了许多事情，但我并不了解，按过去的道理来讲，我是不应该知道这些事情的。那时，我天真地以为这些事情，本来就是到了此时 —— 也就是说，像高中老师所说的，上了大学，自由了之后 —— 我自然就会知道的；我不知道诸事的揭晓原来是因为我恰恰逢到了解严的时刻。</p></blockquote><p>这段独白中，「知道」和「了解」的区别是关键。「知道」是接收到了信息：殖民、虐杀、戒严、迫害，这些词汇如今到处都是；「了解」是理解了信息的意义和脉络：为什么二二八会发生、戒严对社会的塑造有多深、这些创伤如何延续至今…… 主人公能「知道」二二八发生了，但她没有足够的背景知识、历史意识和社会语境来「了解」它意味着什么。</p><p>这正是戒严体制抹除记忆的深层后果。它不仅抹除了事实，更抹除了理解事实所需的脉络。一个人突然被告知一个从未听过的词汇的定义，他可以记住这个定义，但无法真正理解它在语言中的位置和用法。主人公的处境便是如此，而这也映射了台湾社会在解严后的认知困境。尽管信息通道的门很是宽敞，但理解的能力不会随之自动恢复。</p><p>接着主人公收到了郑老师反馈她小说结尾做作的电话。电话里，郑老师也说她的小说要是修好了，还要找地方发表 —— 这里的「发表」很耐人寻味。解严后，社会往往需要打破禁忌的声音，需要有人站出来说话。所以文艺队需要言论来填充解严后刚刚打开的公共空间，也就是要使用主人公写的小说。于是乎，主人公的写作被赋予了政治的功能。</p><p>实在不知道咋改的主人公，向学长求了助。学长的建议是让她写小说时有意识点、要刺激点。此处的「有意识」，结合学长这个人以及第二稿的内容，可以明白暗示的是政治意识；「刺激」则暗示了对读者的冲击力，得冲击社会的神经。</p><p>但这引出了这些问题：</p><ol><li>主人公是没有「意识」的，要如何写出有深度的写作？</li><li>为了冲击效果而刻意选择敏感、刺激的题材，是不是「做作」？</li></ol><p>这便带来了主人公的第二稿。因为主人公自己也开始理解政治和历史，所以小说中的谢彩文也要被卷入到政治和历史的漩涡。</p><p>第二稿里，谢彩文考上大学，离开小镇，进入了台北的知识空间。她发现自己过去的生活是封闭的、无知的，她此前不知道的东西太多。这与主人公自己的经历完全平行。在她向韦老师寻求安慰时，得到的却不是理解，而是夹杂着外省人群体对自身苦难的叙事的谩骂 —— 韦老师拿「战乱经」说她。</p><p>这「战乱经」指的是外省人群体对自身苦难的叙事：中日战争的惨烈、国共内战的失败、逃难来台的流离失所…… 这些创伤构成了他们理解世界的框架。当谢彩文表达自己的困惑和痛苦时，韦老师用自己的创伤来压倒她的痛苦。这使得我们看到新的问题：外省人的创伤叙事和本省人的创伤叙事之间存在着竞争和压制关系。韦老师的「战乱经」使他无法听见谢彩文的痛苦，正如本省人的二二八创伤长期被外省政权的大中国叙事所压制。韦老师不理解解严后年轻一代的处境，他仍活在自己的战乱记忆中。这种代际和族群之间的无法沟通，正是戒严留下的裂痕。</p><p>而谢彩文不知道自己的身世，是出于刚才提到的 <u>大中国叙事</u> —— 国民党政府在戒严时期所构建的官方意识形态。其中一个核心内容，便是用「我们都是中国人」来压制对实际族群差异的认知。明明台湾人的本省和外省身份差异是存在的，但官方叙事不承认它。</p><p>第二稿结尾特别搞笑的，让学长爱上了写小说的主人公自己。叙事还特意注明这是纯粹的爱情，无关政治和历史。</p><p>小说中的谢彩文虽是虚构的，但她的处境映射了真实的台湾历史；主人公是纪实的，但她通过将自己写入虚构来为自己创造了一个避难所。为什么这么说？在这段叙事之前，主人公让小说中的学长有了这么一句台词：「没有人能够摆脱政治和历史阴影。」但小说中的学长又是因为无关政治和历史的纯粹爱情而爱上主人公。这份「纯粹」本身是否就是最大的反讽？而谢彩文恰恰死于失去这份「纯粹」，因为她被排除在主人公为自己保留的特权之外。</p><p>第六节的开头，郑老师表示主人公的第二稿更做作了。因为这个「做作」，主人公思考了许多：她刚从学长的社团里知道了点事情，就急于把这些知识转化为小说素材，但这些知识对她而言还停留在信息层面。于是当她用这些未消化的知识来虚构时，产出的是知识的堆砌而不是洞察。</p><p>这一点，她也应用在了社团的人身上：</p><blockquote><p>…… 坦白说，社团里的求知欲与谈话渐渐使我感到做作，我想，我们彼此炫耀知识，唯恐暴露自己所知仍然停留在解严之前，唯恐同伴讥讽自己心灵不够勇敢，这样的急切，才真正透露禁忌在我们心灵埋下何等阴影吧。</p></blockquote><p>接着她开始思考「虚构」：虚构看似有形，实则无质。一旦被质疑，那便消散了。她的虚构没有坚实的内核。她不了解谢彩文、不了解二二八、不了解戒严的真正含义；她所虚构出来的一九八七，不过是用新的词汇来包装旧的无知。</p><p>而主人公这段自我批判的闭环是，<span class="emphasis">我的形貌就是做作的。</span></p><p>亦或者说，<strong>所有人都是做作的。</strong></p><p>为了好好处理自己的情绪，主人公开始思考解决办法：不能将所有的新知识和情绪混杂在一起了，这只会重蹈郑老师所说的「愈改愈做作」；也不能用刺激性的内容来简单调动情绪了，不过是另一种做作 —— 必须要真正去理解这一切，而解严后短短几个月的时间，是根本不够让她去明白戒严的 38 年、二二八后的 40 年、殖民的 50 年…… 她决定退出社团，回家读书。</p><p>她要独自且自由地学习和理解「真实」。她不再依赖社团的集体表演，而是以个体的方式、以自己选择的速度去面对。这里的「自由」是认知上的自主。</p><p>学长对此有不同的看法：「知识与行动是不冲突的。」也就是不需要等到完全理解时才行动，完全可以边做边学。以及他批评道「好像喜欢文学的人总是过于洁癖或理想」。主人公的回应是「不要这么说」—— 两人代表了两种不同的姿态。</p><p>小说结尾，主人公和学长在圣诞节时见了面。她想到也是在圣诞节左右时去世的谢彩文，情感开始爆发：她向学长提到了真实的谢彩文，就是个普普通通的女孩，没有任何戏剧性的虚构。她又想到曾不停消费着谢彩文、让谢彩文充当自己文学野心和政治思考的容器与工具。鼻子一酸，主人公难过了起来，承认自己对谢彩文残忍、写坏了小说 —— 这是真实的感情，而非做作的虚构。</p><p>在学长安慰了一阵后，主人公感觉好了些，最终为「做作」做了个终极的重新定义：1987 年本就是不寻常且做作的，但她认为这一切都是对的；做作不是错误，是必经之路，因为我们必须要透过不寻常和做作的方式才能了解自己。正如一个人只有经历了失败才能真正理解失败的含义，主人公正是经历了做作，才真正理解做作的本质，进而理解虚构的本质 —— 主人公自己和时代，都靠做作理解了虚构的本质。</p><p>回顾全篇，「不造作的故事结局」这一贯穿始终的追寻，经历了一个三层升级：最初它是文学技术问题，也就是如何写一个不感伤套路的结局；接着它变成了创作与理解的关系问题：如何才能写出真实的情感，而真实的前提是真正了解所写之物吗；最终它成为一个伦理与政治问题，即在不了解的情况下，是否有权发声？</p><p>主人公的回答分别是，「不了解就不应该假装了解」、「虚构无法替代了解」，以及「做作是虚构在缺乏真实时的必然表现」。</p><p>「不造作的故事结局」巧妙地通过做作的过程、理解了做作的不可避免性，进而理解了虚构的本质和局限。这便是小说标题《虚构一九八七》的终极含义：1987 年是「虚构」的，整个时代的表达都是做作且不扎实的；但这种「虚构」是必要的，因为只有通过虚构的失败，才能认识到真实的不可替代性。理解虚构的本质，便是 1987 年最真实的收获。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;开始捣鼓手账后，我开始记录自己的 TODO，然后发现上个学期中文课上读的内容还没写完。别说写完该系列了，我清点过后还剩足足十七个短篇小说没写读后感！&lt;/p&gt;</summary>
    
    
    
    <category term="书评" scheme="https://blog.cytrogen.icu/categories/%E4%B9%A6%E8%AF%84/"/>
    
    
    <category term="政治" scheme="https://blog.cytrogen.icu/tags/%E6%94%BF%E6%B2%BB/"/>
    
    <category term="社会学" scheme="https://blog.cytrogen.icu/tags/%E7%A4%BE%E4%BC%9A%E5%AD%A6/"/>
    
    <category term="短篇小说" scheme="https://blog.cytrogen.icu/tags/%E7%9F%AD%E7%AF%87%E5%B0%8F%E8%AF%B4/"/>
    
  </entry>
  
  <entry>
    <title>抢房子大战</title>
    <link href="https://blog.cytrogen.icu/posts/293b.html"/>
    <id>https://blog.cytrogen.icu/posts/293b.html</id>
    <published>2026-06-20T04:00:00.000Z</published>
    <updated>2026-06-20T18:56:13.073Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我最近买了手账（或者应该叫「手簿」？），因为我发现我手上的活页本，是 6 环的欧美个人记事本，更适合拿来做手账。</p><span id="more"></span><p>我是怎么发现的呢？因为我 <a href="https://gts.cytrogen.icu/@cytrogen/statuses/01KV6JV467D5DWAB6T9PWKVFZE">六月十五日</a> 下午去了趟 MUJI 买文具。我的活页本是 A5 尺寸的，也就是 A4 纸的一半大小，自然也在 MUJI 买了 A5 尺寸的活页纸作为补充。</p><p>待我回到办公室的时候，我发现这些活页纸的洞，和我的活页本的环并不匹配。刚才说了，我的活页本是 6 环的，这些活页纸则有足足 20 个洞。</p><p>接着我去搜索，得知 MUJI 的活页本和活页纸都符合 <u>JIS</u>（Japanese Industrial Standards，日本产业规格），我的活页本则符合在欧美更常见的标准。</p><p>这也改变了两种活页本的用途：欧美的常用于个人规划本，定位是写手账、日程规划、生活管理等；日本的常用于写笔记、自由书写、日常消耗等。这也能从两者的活页纸价格看出端倪，MUJI 的纸好便宜啊！</p><p>不过我寻思着，我要为了这 4 块钱的纸专程跑一趟 MUJI 退货么？一种强迫的想法在我的脑内蔓延开来：这个本子是记手账用的，那个本子才是记笔记用的…… 于是我购买了手账用的各类纸，还有 MUJI 的 A5 尺寸活页本。唉，仪式感是消费陷阱啊！</p><p>好啦以上都是随便聊聊我近期在做啥，和标题的「抢房子大战」半毛钱没有 —— 你被骗了！</p><h2 id="正文"><a class="markdownIt-Anchor" href="#正文"></a> 正文</h2><p>我昨天翻阅 RSS 里的文章时，看到有个文章的评论说「租房唯一不好的就是会被房东赶」，让我想起了一些事情。</p><p>我的人生是被劈成两半的，前十年待在中国山东，后十年待在美国纽约。住在中国山东的时候，家里有栋市中心的小区房。虽然当时那房子破破的，还在小巷子里，但终究还是在市中心 —— 三线城市的市中心也是市中心！</p><p>我做留守儿童的那两年内，母亲的朋友负责照顾我。不过他们没有把我带去他们家，而是偷偷地不告诉我母亲、入住了我家里来。其实这也没有什么。他们家在一栋水泥楼的顶楼，光是爬楼印象里就要爬很久很久。整个房子小小的，但住着他们一家五口，厨房得弯着腰才能进。我那会儿十岁还没开始长个儿，都得小心不被碰到头。所以再让我拎包入住，光是日常生活就要很累了，更别提学习。</p><p>反观我家，足够他们夫妻俩把儿子带过来住。他们的儿子比我大个两三岁应该，初中生快到了长个儿的年纪，学习还得用到电脑。我家正好有台电脑可以给他用。</p><p>他是个像我哥哥一样的人，虽然也没有比我大多少吧，但小时候就记得他玩《赛尔号》、《造梦西游》等游戏玩得很厉害，所以还是小学生的我很崇拜他。顺带一提，他也是带我开始看日本动漫的人。</p><p>那时候远在美国的父母是想要把山东的房子租给别人，一个月一千块钱，让照顾我的人 —— 以下还是简称「佛教夫妇」吧 —— 做代理人。不过他们瞒着我父母，把自己的钱说是从租客那儿收的，交了上去。</p><p>相当于我父母以为我住在佛教夫妇家，房子是另外一户人家在住。实际上住在房子里的，就是佛教夫妇还有我。</p><p>之后这件事情被戳破了。我不知道大人们都做了什么，总之我后来被交给了母亲在山东的「亲戚」照顾，房子也确确实实租给了陌生人。</p><p>这便是「大战」的开端……</p><p>首先，我用引号括起来了「亲戚」二字，是因为我们其实没有任何血缘关系。他们是母亲在山东认的「姐妹」。这群姐妹花总共四个人，带上我母亲就是五个。我小时候常称呼他们为「大姨」、「二姨」、「三姨」…… 但我们实际上并不是真正的亲戚。</p><p>不过假戏真做也真是的，我小时候还纳闷我怎么同时有「爷爷奶奶」、「外婆外公」、「姥姥姥爷」。</p><p>随着我也移民去了美国后，我们家在山东的房子没有了真正的掌权人。而这些姐妹花的其中一个，在数年后盯上了我们家的房子。</p><p>整个争执过程非常可笑。她想要「买」下我们家的房子，首付是…… 两万人民币。这要是十几年前我父母刚买下这套房子的时候，两万首付确实也可以，因为我记得这小区房最初也就十万人民币。但已经过了十几年了，房子早就增值到近百万了，两万首付我们要怎么相信她接下来能付得起呢？更何况她这两万块，还是找其他姐妹东凑凑西凑凑，凑出来的。</p><p>所以她的想法很显然，是打算用所谓的「亲情价」，直接获得我家房子，反正我们一时半会儿也不会回国。就算她真的付完房子的钱，也不知道要过多少年了。</p><p>因为房子原先是交给了姐妹花中先前照顾我的那位（也是姐妹花中的大姐）来管理，母亲自然而然先去找了她商量。结果对方似是铁了心要把我们家的房子交给自己的妹妹，很多时候直接已读不回，气死人了。这也让母亲心寒，十几年的交情根本比不上血缘关系。</p><p>住在我家里好多年的租客就因为这种事情，被我们劝走了。也是为什么我想起了这件事儿。</p><p>更生气的是，那人入住我们家时，嫌弃被我母亲拜托清理房子的佛教夫妇没有好好打扫，真是把人当奴仆！她后来被赶走时，反而还在房子的冰箱里放了发霉的饼不丢，杀伤力更重！</p><p>至于她是怎么被赶走的。母亲联系上了住在山东的真正的亲戚，写了信寄回国，指定她作为真正的代理人来管那个小区房。同时家里也决定在纽约买房子，急需钱，便在赶走那人之后，让这个代理亲戚卖掉我们家的房子。</p><p>不过很可惜，不是所有人都是能被信任的。这个亲戚之前就和我们家不合。她没有在母亲让她卖房子时把房源挂上网，而是在母亲火急火燎问起来后，才把房源挂上网。本来近百万的房子，被她这么一折腾，贬值了几十万。</p><p>对于母亲而言，总算是终结了这围绕着房子的战争，不用再去跨国操心它了。但那依然是我出生后就一直居住的房子，让我怀念也确实很怀念。记忆里，客厅墙上挂着一把别人送我的剑，上面还刻着我的名字。现在，已经不知道去了哪里。电脑和电视等家具，也都在我离开中国之后，被那些山东的亲戚或「亲戚」们搬走了。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我最近买了手账（或者应该叫「手簿」？），因为我发现我手上的活页本，是 6 环的欧美个人记事本，更适合拿来做手账。&lt;/p&gt;</summary>
    
    
    
    <category term="日常生活" scheme="https://blog.cytrogen.icu/categories/%E6%97%A5%E5%B8%B8%E7%94%9F%E6%B4%BB/"/>
    
    
  </entry>
  
  <entry>
    <title>讨厌礼物</title>
    <link href="https://blog.cytrogen.icu/posts/54b4.html"/>
    <id>https://blog.cytrogen.icu/posts/54b4.html</id>
    <published>2026-06-16T04:00:00.000Z</published>
    <updated>2026-07-06T21:52:06.974Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我的桌子下方放了个灰色的盒子，专门用来放一些没必要摆在桌子上的东西，例如电池、玩具。这里也包括了一部分别人送我的礼物。</p><span id="more"></span><p>昨天因为盒子里的东西都满了出来，实在是不好找电池，所以我清理了一下。最占位置的都是我的玩具，像魔方，还有朋友送我的周边等。我自己买的玩具，因为我知道我要玩，所以买了也不会觉得有怎么。但朋友送我的东西，就非常占位置，令人讨厌。</p><p>我在清理盒子时，发现底部有一些积木零件。几年前，室友买了一套廉价的程序员主题积木送我。它甚至没有一个专业的说明书，零件的质量也非常差，拼出来的成品更是难看得不行。摆在桌上，每晚都会被猫叼走扔地上，已经找不见了许多零件。</p><p>「扔了吧。」我这么想着，顺手丢到了垃圾桶里。这一幕被室友瞧见，反而惹得她很生气。</p><p>尽管之后我向她道歉、把积木从垃圾桶里捞了回来，她也很生气。这是我们二人无法理解彼此的地方。这个积木对我来说就是不需要的垃圾，我这辈子都不会再动它了。但对她来说，我把她送给我的东西丢掉，相当于是在蔑视她。如果她把我以前送她的东西也扔了，我肯定会感到难过的，那她凭什么不能生气呢。</p><p>但我依然不觉得这说得通。她不丢我送给她的东西，本就是我送的东西有价值，值得收藏。但她送我的积木，是一点价值都没有的东西，是和其他朋友硬塞给我的礼物没什么区别的东西。她都能觉得那些朋友经常给我塞的礼物是垃圾，那为什么不能觉得自己送的东西是垃圾呢？最开始，我也没有想要这套积木吧？</p><p><a href="/posts/893f.html#:~:text=%E5%85%B3%E4%BA%8E%E6%84%9F%E6%83%85,%E4%BB%80%E4%B9%88,-%E3%80%82">上个月</a> 我知道了「爱的五种语言」，并将「送礼物」放在了最低的一档。理由很简单：我不喜欢礼物。</p><p>我没有送人礼物的习惯，也不喜欢别人送我礼物。今年一位朋友过生日，我送给他的礼物是当日让他自己选的。送对方东西，还是要送对方想要的东西吧。而对方送我的东西，每次都是他觉得我会喜欢，实际上我根本不想要，也不需要，只是放在盒子里积攒灰尘。</p><p>我也讨厌用花束作为礼物。那可是植物哎。我收到的话，就会想要去为它负责、让它活下来。所以我还得自费买花盆，如果需要土的话就得买土，如果只用水的话就放水里…… 但这种鲜花，往往都难以活下来，更何况我的家里有一只会啃植物的猫。</p><p>未经过许可便买动物作为礼物是最差劲的。对方只管买就好了，全然不在乎我要花费多少精力在小动物身上。这么说，这和怀孕生子还挺像。</p><p>小时候在家中，大人们便常常塞给我东西。衣服也好，首饰也罢，都不是我想要的。收吧，不需要；不收吧，不给面子。最后拿着一堆垃圾，扔也不是，留也不是，真难！反倒是我想要的东西，都不怎么有人送给我。久而久之，我也讨厌起了礼物。你硬塞给我这些垃圾，还想要我买东西给你？门都没有！</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我的桌子下方放了个灰色的盒子，专门用来放一些没必要摆在桌子上的东西，例如电池、玩具。这里也包括了一部分别人送我的礼物。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="心理学" scheme="https://blog.cytrogen.icu/tags/%E5%BF%83%E7%90%86%E5%AD%A6/"/>
    
    <category term="情感" scheme="https://blog.cytrogen.icu/tags/%E6%83%85%E6%84%9F/"/>
    
  </entry>
  
  <entry>
    <title>数多年重试跑步然后晕倒</title>
    <link href="https://blog.cytrogen.icu/posts/2814.html"/>
    <id>https://blog.cytrogen.icu/posts/2814.html</id>
    <published>2026-06-06T04:00:00.000Z</published>
    <updated>2026-06-06T18:58:45.314Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我距上次跑步，也就是初中时期，已经有七八年没有再慢跑过。</p><span id="more"></span><p>我在 <a href="/posts/5586.html#%E5%BD%93%E6%88%91%E8%B0%88%E6%99%A8%E8%B7%91%E6%97%B6-%E6%88%91%E5%9C%A8%E8%B0%88%E4%BA%9B%E4%BB%80%E4%B9%88:~:text=%E6%88%91%E6%B2%A1%E6%9C%89%E6%99%A8%E8%B7%91%E7%9A%84%E4%B9%A0%E6%83%AF%EF%BC%8C%E6%88%96%E8%80%85%E8%AF%B4%E6%88%91%E6%A0%B9%E6%9C%AC%E5%B0%B1%E6%B2%A1%E6%9C%89%E8%B7%91%E6%AD%A5%E7%9A%84%E4%B9%A0%E6%83%AF%20%E2%80%94%E2%80%94%20%E8%BF%99%E6%A0%B7%E8%AF%B4%E5%AE%9E%E5%9C%A8%E6%98%AF%E8%AE%A9%E6%88%91%E6%84%9F%E5%88%B0%E7%BE%9E%E8%80%BB%EF%BC%8C%E6%98%8E%E6%98%8E%E8%87%AA%E5%B7%B1%E4%B9%9F%E8%A7%89%E5%BE%97%E4%B8%8D%E5%A4%AA%E5%A5%BD%EF%BC%8C%E4%BD%86%E4%B9%9F%E5%8F%AA%E8%83%BD%E5%AE%89%E6%85%B0%E8%87%AA%E5%B7%B1%E3%80%8C%E6%85%A2%E6%85%A2%E6%9D%A5%E5%90%A7%E3%80%8D%E3%80%82%E8%87%B3%E5%B0%91%E7%8E%B0%E5%9C%A8%E9%83%BD%E4%BC%9A%E5%B0%BD%E9%87%8F%E8%B5%B0%E8%B7%AF%E5%87%BA%E9%97%A8%EF%BC%8C%E8%80%8C%E4%B8%8D%E6%98%AF%E6%90%AD%E4%B9%98%E5%9C%B0%E9%93%81%E5%85%AC%E4%BA%A4%E4%BA%86%E2%80%A6%E2%80%A6%EF%BC%81">四月份</a> 就有看到他人跑步锻炼，而得到良好的身体状况，以及后续工作效率的提升。因此我对跑步锻炼很是向往，尽管我平日根本就不跑步。</p><p>介于 <a href="/posts/f118.html">五月份中旬</a> 我有了骑自行车的习惯，想方设法地抛弃了公交车和地铁，并且在更早的 <a href="/posts/53f4.html">一月份</a> 走过半马，我对自己的身体素质相当自信。另一边，室友因为我开始骑车，也适当地抛弃了地铁。不过我们的共享单车会员仅能在一个时间内让一个人骑车。有着更硬的身体素质的她，选择了跑步、我骑车。</p><p>说来，室友的身体素质，让她在一月份的走半马后，又陆陆续续走了多次半马、全马，实在是恐怖啊…… 我还是更喜欢骑脚踏车。丁零丁零~</p><p>于是，我们二人每周都会花一天的时间，跑步以及骑车到达唐人街、购买食物、玩街机游戏，然后回家处理。</p><p>但这么做有个问题，我骑车无论如何速度都是要比她跑步快的。并且我认为，骑车不会让我满身大汗，用的力更像是散步或者快走的力。既然没能累到，意味着锻炼并不到位。我们二人一协商，决定哪天一起跑步。</p><p>那一天便是昨天。</p><p>因为平日完全不跑步，室友便调整了配速，和我一起慢慢跑。先前和她看过一期跑步的视频，说是跑步期间最不该做的事情，就是用嘴大口呼吸。我想办法让自己用鼻子呼吸、根据室友所说的「五吸三呼」—— 不过后续我查资料发现，美国肺脏协会推荐的是 3:2 节奏呼吸法，即左右左右左右吸、左右左右呼…… 循环。</p><p>跑步的时候，太阳挂在天的中间，无疑是个大热天。我们慢慢地从家里开始，一点一点向前跑去。虽说是「跑」，实际上的配速也仅仅是 12 分钟一公里，和快走没有什么区别。</p><p>刚开始的时候，我事先发觉到自己的小腿很酸痛。感觉像是，我的小腿突然被要求以不正常的形式承受着压力，让我怀疑是不是跑步的姿势有问题。接着，我意识到左腹的疼痛。等红白灯的时候，我和室友提起了此事，她认为是我岔气了、在用嘴呼吸导致的。可是我没有用嘴呼吸呀。接下来，我笨拙地遵守着「五呼三吸」的规则，忍受着小腿和左腹的疼慢跑着。</p><p>直到我们跑了一公里开外、等另一个红白灯而停下时，我的眼睛所能看到的景色忽然变黑了。更像是黑色的滤镜在我的眼球上吧，如果非要比喻的话。我的头紧跟着开始痛、晕晕乎乎的，让我难以保持站立的姿势，本能地想要躺到地上去。当然没有那么做啦，我半蹲在地上感受着晕厥，一旁的室友则不停拉着我，想要让我再走几步。</p><p>最后我是躺在了不远处的一块大石头上。室友想要让我坐起来，或者走到别的店里待着，石头毕竟还是很脏的。但我难以保持着坐立的姿势，甚至连手臂都开始变得麻木、难以移动或者感受到触觉。她喂给我水，然后着急地上网查该怎么办。按照她后来说的，当时的我嘴唇都在发白，像是要死了一样。但也只是跑了快走的速度而已，怎么会变成这样呢？</p><p>我神智不清地躺在步行街的石头上，自然引来了他人的注意。记忆里，第一个过来问候的是个护士。她一边问室友我怎么了，一边从附近的店里弄来了可乐，让我先补充糖分。按照她的说法，最好是能补充维他命的橙子果汁，但附近没有，亦或者是含有电解质的水。我没听懂太多，只能小口小口被人喂可乐喝。</p><p>接着路过了一位医生，询问室友我是否还有意识，接着俯下身给我把了个脉，说问题应该不大。他表示可以帮我们叫个 Uber，赶紧送我回家休息。室友不好意思，婉拒了，转而叫了个路边的车夫。车夫和医生帮我扛到了车内。之后就是被送回家，躺在床上休息。</p><p>在身体机能几乎丧失的时刻，这些陌生人的帮助都让我很是感动。但也不得不提，这个车夫走路 10 分钟的距离，竟然收我们 20 多块钱！太贵了、太贵了啊。</p><p>回家后，搜索了大批资料的室友打了个草莓蓝莓柠檬盐糖冰沙给我喝，说是用于补充电解质和糖分。很难喝，咸咸的…… 但还是喝完了。</p><p>我恢复得很快，躺床上没多久就能用 iPad 查资料了。</p><p>首先我搜索的是，为什么我的小腿会如此酸痛。结果这是正常现象，原因是小腿肌肉负荷大，导致乳酸堆积，和微小的肌纤维损伤。</p><p>左腹部痛，又称岔气，是 <u>运动性短暂腹痛</u>。原因可以有很多，例如呼吸节奏不规律、脾脏释放了红细胞、饭后不久运动等等。</p><p>之后的眼前变黑以及头晕，是脑供血不足、缺氧了。我原本的猜测是低血糖，但当时我也刚吃完饭没多久，不太可能。</p><p>最严重的手臂变麻，是因为 <u>过度换气综合征</u>。原理是呼吸节奏有问题，排出了过多的二氧化碳，引起呼吸性碱中毒，导致血钙离子浓度下降、神经肌肉兴奋性增高、手足麻木且刺痛。虽然话是这么说，但排出二氧化碳为什么会引起碱中毒？我又搜了搜，发现人体需要二氧化碳来维持血液的酸碱平衡。一旦血液偏碱性，就会出现刚才说的情况。</p><p>好吧，我明显没能被化学课「教育」到：东西全还给了老师。以至于我对人体中二氧化碳的认知，还停留在简简单单的「排出去是好事」。</p><p>但是搜索的第一波资料中，依然有着许多没能解答的谜团在。比如我的配速如此之慢，怎么会出现这么严重的症状？根本就不正常啊。因此我又做了第二波搜查。这波搜查指向了各式各样的原因，例如严重的 <u>心律失常</u>、<u>肥厚型心肌病</u>、<u>短暂性脑缺血发作</u>…… 或者更常见的贫血、脱水、低血容量、<u>血管迷走性晕厥</u>、颈椎病…… 我不是医学生，所以这些东西我都没咋看懂。但根据它们的关键特征来看，并不是我的症状，尤其是在场还有医生和护士评估。把脉后医生也说了问题不大，更不可能是心脏问题了。</p><p>我认为最有可能的，还是过度换气导致的碱中毒。至于贫血，我不好说自己的血液一次能携带多少氧气，但平日不怎么锻炼的话，这个能力应该很弱吧。</p><p>关于室友做的冰沙，我也调查了下，了解了电解质这东西。说是人体的神经和肌肉的运作，本质上是依赖于微弱的电信号，而电解质是维持这些信号传递的介质。过度换气后，体内的电信号会紊乱。草莓和蓝莓是天然的糖分，不仅可以补充血糖，还富含钾，能帮助电解质恢复；柠檬水同样提供钾，还有维生素 C；盐补充钠，是最关键的电解质，且钠能帮助身体保留水分、恢复血容量；糖快速补充碳水化合物，能恢复血糖和肌糖原；冰用来降温 —— 它们都能帮助到我。</p><p>我又好奇自己的跑步姿势是否有问题，专门搜索了网络上的资料，了解了下正确的跑步姿势。不过我发现自己的姿势和正确的跑步姿势区别也不大，并且短短一公里姿势真的会影响这么多么？</p><p>再就是我明明平时都在骑车啊，体能不可能不足吧。结果真相是 —— 骑车体能根本不能转化成跑步体能。差异分别是：</p><p>一、骑车时，肌肉的主要任务是向外推，属于主动发力的向心收缩。而跑步不仅包含了向心运动，也包含离心 —— 脚落地时，小腿肌肉会一边被拉长，一边发力来吸收冲击 —— 和等长收缩运动，对全身施加的力要更大。</p><p>二、骑车几乎没有硬性冲击，但跑步时每次落地，肌肉都要承受体重的 2 到 3 倍冲击力。我先前骑车，都没让小腿经历过这种冲击，再去跑步，自然而然会感到疼痛。</p><p>三、两者的呼吸模式不同。</p><p>我的体能肯定没有差到这种地步，所以我的最终推论是，运动特异性导致的各种问题，引向了我昏迷的结果。如何解决这个问题就变得很简单了，我得学会如何跑步。室友是过去就有跑步的习惯，所以她跑上一天估计也没什么大问题，但让我跑步，我得先让身体搞明白如何从走路「进化」成跑步。就像是骑自行车人们都是一点点学的，我学跑步也只能一点点去习惯，所以未来我出门得跑几步走几步。</p><p>我也搜索到了一些跑步外可以做的训练，比如小腿的离心训练，以建立小腿抗冲击的能力，还有各种核心训练、呼吸训练……</p><p>再就是我也发现，呼吸时并非绝对不能用口呼吸。慢跑时可以选择鼻吸口呼；中等强度以上就得口鼻同时吸，然后口呼，因为嘴巴能快速地通过更多空气。只用鼻子的话，氧气不够也会导致过度换气。</p><p>可以这样练习呼吸：</p><ol><li>站着练习腹式呼吸：把手放在肚子上。吸气时肚子要鼓起来，呼气时肚子要缩进去；</li><li>走路练 3:2，吸 3 步、呼 3 步；</li><li>慢跑练 3:2；</li><li>感觉岔气来了，就切换到 3:3，深呼气并按住痛处。</li></ol><p>之前看《鬼灭之刃》的时候，就觉得腹式呼吸要更「厉害」些。之后从室友那儿得知，胸部呼吸的坏处，以及她身体的问题，导致她很早就学会且习惯了腹部呼吸。那时候找她学习，但也没学到什么，现在倒是得努力学到那种感觉。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我距上次跑步，也就是初中时期，已经有七八年没有再慢跑过。&lt;/p&gt;</summary>
    
    
    
    <category term="日常生活" scheme="https://blog.cytrogen.icu/categories/%E6%97%A5%E5%B8%B8%E7%94%9F%E6%B4%BB/"/>
    
    
  </entry>
  
  <entry>
    <title>想法在丙午芒种迭代</title>
    <link href="https://blog.cytrogen.icu/posts/893f.html"/>
    <id>https://blog.cytrogen.icu/posts/893f.html</id>
    <published>2026-06-01T04:00:00.000Z</published>
    <updated>2026-06-01T20:31:19.042Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>期末周总算是结束了！没有了学业这个拖后腿的东西后，我在这个月花了更多的精力在求职、学习新东西上。</p><span id="more"></span><details>      <summary>本期导读</summary>      <h2 id="输入"><a class="markdownIt-Anchor" href="#输入"></a> 输入</h2><h4 id="商业与社会"><a class="markdownIt-Anchor" href="#商业与社会"></a> 商业与社会</h4><ul><li><a href="#2015-2016-%E9%9A%8F%E7%AC%94%E9%80%89%E9%9B%86">2015-2016 随笔选集</a></li><li><a href="#%E4%B8%8B%E4%B8%80%E4%BB%A3%E4%BA%BA%E6%9C%89%E5%8F%AF%E8%83%BD%E6%98%AF%E4%BA%BA%E7%B1%BB%E6%BC%94%E5%8C%96%E7%9A%84%E5%8F%88%E4%B8%80%E6%AC%A1%E5%88%86%E5%8F%89%EF%BC%9A%E8%AE%BA-ai-%E5%AF%B9%E6%95%99%E8%82%B2%E5%92%8C%E4%BA%BA%E6%80%A7%E7%9A%84%E5%A8%81%E8%83%81">下一代人有可能是人类演化的又一次分叉：论 AI 对教育和人性的威胁</a></li><li><a href="#%E7%BE%8E%E5%9B%BD%E7%BD%91%E7%BB%9C%E5%AE%89%E5%85%A8%E5%B1%80%E5%B0%86%E5%85%B6%E6%95%B0%E5%AD%97%E5%AF%86%E9%92%A5%E5%85%AC%E5%BC%80%E5%9C%A8-github-%E4%B8%8A">美国网络安全局将其数字密钥公开在 GitHub 上</a></li><li><a href="#meta-%E6%8E%A8%E5%87%BA-instagram-facebook-%E5%92%8C-whatsapp-%E8%AE%A2%E9%98%85%E6%9C%8D%E5%8A%A1">Meta 推出 Instagram、Facebook 和 WhatsApp 订阅服务</a></li></ul><h4 id="心理与关系"><a class="markdownIt-Anchor" href="#心理与关系"></a> 心理与关系</h4><ul><li><a href="#%E6%88%91%E5%BE%88%E5%96%9C%E6%AC%A2%E5%8F%8B%E9%93%BE%E9%87%8C%E7%9A%84%E6%89%80%E6%9C%89%E4%BA%BA-%E4%BD%86%E5%BE%88%E9%81%97%E6%86%BE-%E5%AE%83%E5%BF%85%E9%A1%BB%E5%BE%97%E6%B6%88%E5%A4%B1%E4%BA%86">我很喜欢友链里的所有人，但很遗憾，它必须得消失了</a></li><li><a href="#ai-%E5%8F%AF%E8%83%BD%E6%AD%A3%E8%AE%A9%E6%88%91%E4%BB%AC%E5%9C%A8%E6%80%9D%E8%80%83%E5%92%8C%E5%86%99%E4%BD%9C%E4%B8%8A%E5%8F%98%E5%BE%97%E6%9B%B4%E5%8A%A0%E7%9B%B8%E4%BC%BC">AI 可能正让我们在思考和写作上变得更加相似</a></li></ul><h4 id="科学与自然"><a class="markdownIt-Anchor" href="#科学与自然"></a> 科学与自然</h4><h4 id="技术与创造"><a class="markdownIt-Anchor" href="#技术与创造"></a> 技术与创造</h4><ul><li><a href="#microsoft-%E5%A6%82%E4%BD%95%E5%89%A5%E5%89%8A%E5%85%B6%E7%94%A8%E6%88%B7">Microsoft 如何剥削其用户</a></li><li><a href="#cal-com-%E5%B0%86%E8%BD%AC%E4%B8%BA%E9%97%AD%E6%BA%90">Cal.com 将转为闭源</a></li><li><a href="#%E5%9C%A8%E4%BF%A1%E4%BB%BB%E4%B8%8B%E4%B8%80%E4%B8%AA%E8%87%AA%E6%89%98%E7%AE%A1%E5%BA%94%E7%94%A8%E4%B9%8B%E5%89%8D-%E8%AF%B7%E5%85%88%E7%9C%8B%E8%BF%99%E4%B8%AA">在信任下一个自托管应用之前，请先看这个</a></li><li><a href="#%E8%87%AA%E6%89%98%E7%AE%A1%E5%91%A8%E5%88%8A">自托管周刊</a></li><li><a href="#%E4%BA%92%E6%93%8D%E4%BD%9C%E6%80%A7%E5%B0%86%E6%8B%AF%E6%95%91%E5%BC%80%E6%94%BE%E7%BD%91%E7%BB%9C">互操作性将拯救开放网络</a></li><li><a href="#%E5%AF%B9%E8%8B%A6%E5%B7%AE%E4%BA%8B%E7%9A%84%E9%80%89%E6%8B%A9%E6%80%A7%E5%A4%B1%E6%98%8E">对苦差事的选择性失明</a></li><li><a href="#%E6%8A%8A%E6%88%91%E7%9A%84%E9%82%AE%E4%BB%B6%E4%B8%A2%E8%BF%9B%E9%BB%91%E6%B4%9E">把我的邮件丢进黑洞</a></li><li><a href="#%E5%A6%82%E6%9E%9C-ai-%E4%B8%BA%E4%BD%A0%E7%BC%96%E5%86%99%E4%BB%A3%E7%A0%81-%E4%B8%BA%E4%BB%80%E4%B9%88%E8%BF%98%E8%A6%81%E7%94%A8-python">如果 AI 为你编写代码，为什么还要用 Python？</a></li><li><a href="#%E6%9C%89%E8%B6%A3%E9%A1%B9%E7%9B%AE">有趣项目</a></li></ul><h2 id="输出"><a class="markdownIt-Anchor" href="#输出"></a> 输出</h2><ul><li><a href="#%E6%88%91%E5%86%99%E7%9A%84%E6%96%87%E7%AB%A0">我写的文章</a></li><li><a href="#%E4%B9%A6%E7%B1%8D">书籍</a> / <a href="#%E5%BD%B1%E8%A7%86">影视</a> / <a href="#%E9%9F%B3%E4%B9%90">音乐</a></li><li><a href="#%E6%97%A5%E8%AE%B0%E7%89%87%E6%AE%B5">真生活</a></li></ul>    </details><h2 id="商业与社会"><a class="markdownIt-Anchor" href="#商业与社会"></a> 商业与社会</h2><p><a id="2015-2016-随笔选集"></a></p><h4 id="2015-2016-随笔选集"><a class="markdownIt-Anchor" href="#2015-2016-随笔选集"></a> <a href="https://ursb.me/posts/2015-2016-essays/">《2015-2016 随笔选集》</a></h4><p>这是 Airing 发表的，2015 到 2016 年期间，他大二大三时写的随笔选集。</p><p>我在去年订阅的他的博客，并发现他也在写月刊。从第一期慢慢看下来，不得不感叹真是一个令人向往成为的业内前辈模样。虽然这篇随笔选集是在三月份发的，但我那时候一直没有读。打算写这条条目时，发现他的博客主题变了样，十分漂亮，像干净的报纸，犀利。</p><p>这篇随笔选集的许多文字，都让现在正是大三生的我感到共鸣。区别在于，我不是什么好学生，记忆里从来不复习，导致大学期间因「不会复习」而栽了许多跟头。高中起，连课都懒得去上，是个让老师头疼的学生。现在上大学了，绩点也是低到令人发指。</p><p>小学没读完便来到美国读书的我，无法亲身体会中国教育的可怕之处。两者像是天平上的两头，根本不一样。不过从国内朋友那儿，以及互联网上的种种案例听来，都觉得恐怖。不只是形式恐怖，更恐怖的是付出了这么多努力，但是得来的回报寥寥可数。</p><p>思来想去，不知道这个条目放哪里好。最后决定放在「社会」内了，也是本月刊最顶部的分类。</p><p>接下来一篇一篇讨论吧！</p><p>一、《谈谈我所理解的教育》。</p><p>选集中的第一篇中，便讲到了作者曾在高中苦读，最终来到大学，发现一切都是虚假的：没有所谓的「社会的良知和思想发动器」，有的只是浮躁的商业中心、空虚的大学生。</p><p>可见早在十年前，大学就已经不再是过去那样，高门槛的学习环境。</p><p>美国大学的问题，因国情而不同。我发现中国有个问题，那便是「不考上好大学一辈子就完了」，因此鄙视所谓「不好」的大学，或者大专。</p><p>我不清楚这种说法是从何而来的，但上大学应当看该学校的专业情况、资源，而不是单单看排名、985 或者 211 这些头衔。</p><p>上大专更是没有什么值得贬低的。许多人更适合上大专、学习技术，我自己说不定也更适合那种环境。大学一直以来都是以学术的角度培养学生，目的是让学生们去上更高的学历。如果不做研究，仅是想找工作的话，大学的课程并不一定能跟上职场的技术要求。</p><p>关于这一点，我已经攻击过多次我的大学。现在正在思考大学文凭的重要性。技术什么的，反正都是自学来的，文凭有或者没有，真的重要么？</p><p>上大学上了也有三年，唯一一节让我觉得学到东西的，是本学期为了凑成全日制而临时加上的中文短篇小说课。说到这门课，作业很简单，每周观看或者阅读教授发的视频或者读物，同学们讨论，然后发表至少三个帖子或者回应即可。有趣的是，几乎所有人都在使用 AI 工具，且是很笨地在使用。许多帖子和源内容一点关系都没有，底下的回复没有人察觉，换着花样在说车轱辘话。</p><p>一次我生病缺席，没能听到教授对 <em> Transcendence and the Fax Machine</em> 这篇小说的分析。虽自行搞明白了核心要点，但这位教授的知识储量，总是能指出我想不到的细节以及历史背景。于是着急的我在同学们创建的微信群 —— 我要插句话，国外也要使用这个微信，真的好烦啊 —— 中礼貌问道，是否有任何人有这篇小说的笔记。结果等来的是一个根本不礼貌的「真的有人上课记笔记？」以及一张蠢得像回复者本人、被拉长了脸的猫咪表情包。没办法，最后我去找了教授问，才终结了我这好奇心。</p><p>和同组的同学聊起时我才明白，这些同学基本上都是来水绩点，以及水兼修的。本来就是中国人，上中文课总比上英文课要好，学校也有中文兼修，手到擒来。我最初选这门课也是为了填充自己的课表、刻意选择了对我来说不太难，也有兴趣的课，所以在这一点上彼此彼此了。</p><p>Airing 也提到了大学中的学生会。我高中期间参加过一段时间学生会，算是有点话语权么。做学生会会员的好处是，可以更方便地从教师那儿知道更多的资源和信息，也是对上了他说的「不是因为他们很厉害才当上了学生干部，而是他们当上了学生干部才很厉害」。</p><p>关于第四点「勿忘初心」，我想说回先前「大专」的话题。当时的作者认为，教育的意义在于启迪智慧、接纳真实的自我，以及统一内心价值与外在行为，也就是去培养一个完整的人，AKA 全人教育（Liberal Arts）。不过要想要求大学课程跟上职场的技术要求，那么教育的目的便变成了职业培训，也就是国内的专科。</p><p>顺带一提，美国也有专科，直接就叫 <em> vocational school</em>，但是没有国内的专科那么「低人一等」。很多人会把社区大学（Community college）说成是「美国的大专」，但它实则是给予学生们副学士学位，然后可以让学生们转入到大学的第三年以继续学士学位，更像是块跳板。</p><p>本科教育的一大问题便是，它试图将两个目标合并到一起。结果就是，启发性教育需要时间和空间的留白来试错和反思、追赶职场技术需要紧跟风向，而大学往往两者都没抓好。不过大学也并不是只有无用之处。社交要是做得好的话，可以快速集结人脉、认识行业内的人士…… 唉，又变得功利起来了呢。</p><p>结尾，当时的作者呼吁大学生们明确个人目标，将个体的理想奋斗与国家、乃至整个人类社会的未来发展相联结，以此来践行「真正的大学生」的现实意义 —— 确实很贴合他开头说的「观点偏激」，但也对得上他接下来说的「二十岁的人本就该这样：笨拙地思考，认真地愤怒，不管不顾地把想说的话一口气写完」。</p><p>现在的大学生已经没有过去那么稀缺，就如我先前说的，不过是又四年的高中生活。而我算是个俗人，没有爱国情绪在，不论是对中国还是美国，因此并不喜欢这种「要求尚未实现经济独立的青年去肩负抽象的宏大责任」的叙事。</p><p>如果个体都无需担忧物质匮乏的话，我倒是很愿意用尽才华、奉献给世界。</p><p>二、《不要虚度你的大学时光》。</p><p>作者提到的「师弟」让我察觉到一些事情。我的大学大一时是不给上专业课的，并且让我觉得有难度、没有学习过的专业课，都得修上许多必修课、进了学院才给上。实验室更是没有这玩意儿，也没有硬件课。</p><p>在第六节「勤写博客」中，作者要求至少每两周产出一篇比较高质量的文章。我去看了眼自己的归档，嗯…… 还算可以吧，虽然没有合格，但也满意一丢丢了。现在很多内容倒是直接发到了 Fediverse。</p><p>三、《难得清闲》。</p><p>可以看得出当时的作者真的很喜欢《月亮与六便士》这本书，到这里已经提起过两次了。我没有读过这本书，不过根据作者所说的，主题想必是关于理想和现实。</p><p>我想不到自己的理想，或者说，没有一个确切的理想。室友时常和我聊起她喜欢什么样的人（不是浪漫的「喜欢」）—— 有热爱和理想的人。那些人做起事情来，会闪闪发光。高中开始自学编程时，虽然经常学到忘我、对她爱搭不理的，但她依然觉得那时的我很惹眼。</p><p>我现在很少有心流的时候了，恐是我逐渐与浮躁的生活融为一体。我在工作、赚钱、寻找更多更好的工作。不赚钱就会饿死，只去赚钱我就会忙碌一辈子没个出头，不找更好的工作总有一天便会麻木，不拿个文凭就不好找工作……</p><p>仰望月亮总是需要一个隐形的垫脚石。我没有这块石头，只能去想方设法让自己拥有。放在原作者的语境中，和低头看向六便士还是不同的，因为我现在的忙碌是为了未来而铺的路。</p><p>我现在依旧还是迷茫的，不知道自己想要的理想是什么形状，但清楚垫脚石铺到哪里。等到生存什么时候不再是 Damocles 剑的时候，我才能找回曾经丢失的纯粹吧。</p><p><a id="下一代人有可能是人类演化的又一次分叉：论-ai-对教育和人性的威胁"></a></p><h4 id="下一代人有可能是人类演化的又一次分叉论-ai-对教育和人性的威胁"><a class="markdownIt-Anchor" href="#下一代人有可能是人类演化的又一次分叉论-ai-对教育和人性的威胁"></a> <a href="https://pathos.page/blog/ai-education-humanity/">《下一代人有可能是人类演化的又一次分叉：论 AI 对教育和人性的威胁》</a></h4><p>我原本在这个月初的时候就写好了该条目。但是不知道为什么，条目的数据在 refile 后找不见了…… 最终我是凭着记忆重新写了一遍。顺带一提重写时是五月三十日，唉……</p><p>总之本月的月刊有很多内容都是和 AI 工具相关的。你们有的受的了。</p><p>不知道该将此条目放在「社会」还是「心理」。最终决定放在前者内。话说我是不是应该改改这些分类了？</p><hr><p>正如「失败是成功之母」所言，学习期间最重要的便是「犯错」。</p><p>这一点在 <a href="https://github.com/zijie0/HumanSystemOptimization">《健康学习到 150 岁 - 人体系统调优不完全指南》</a> 内也有提到。当我们没能达到预期目标时，身体便会激活大脑神经元的可塑性，从而进入学习状态。听上去是挺反直觉的：我们得先失败，才能学习。但细想也确实是这样。</p><p>指南内还提到了 Mihaly 的心流，说有些人认为心流状态是学习的最佳状态。这种想法是错误的，因为心流的重点在于做同件事的「最佳状态」，是和「幸福」相关联的，而非「学习」新东西。</p><p>不过 AI 工具的出现后，人们愈发难以接受失败和错误。我发现在 AI 工具之前，也发生着同样的事情：揪着他人的错误和失败不放，好似对方的人生只剩下这些…… 到底是为什么会变成这样呢？人是会改变的，毋庸置疑。</p><p>我身边的一位朋友，曾经做过很差劲的事情，但认识到自己的错误后，不停去弥补，最终成长为一个和过去完全不同的人。这种变化说实话，难以置信，甚至到令我嫉妒的地步。但是也有另一批朋友，因为他犯过的错，私下将其视为「不该出现的存在」。他日后所想的所有思想、所做的所有行为，都会被他们未能成长的见识冠以解释。就我这个第三方看来，后者是更为幼稚、没能成长的，尽管他们没有犯过很差劲的事情。</p><p>文章作者提到了 <em> World</em> 和 <em> Word</em> 的关联性。「世界」是客观的，「语言」是主观的。用这个简单的解释再来看待作者提及的社会实践和自然科学研究，就可以看懂他的例子。比方说自然科学研究里，研究人员会观察「世界」，即客观存在、无论我们如何主观辩解都依然存在着的东西，得出尽量贴合的解释，也就是「语言」。</p><p>在社会实践内，情况是反过来的。我们会先有主观的理念（「语言」），然后想方设法让我们客观生活在的社会（「世界」）符合该理念。这也就是文科存在的意义。</p><p>过去我一直没能搞明白文科是干什么的，开始写博客后，逐渐才发现写作的重要性。写作可以梳理自己的思绪，也可以运用「语言」去介入并重塑「世界」。在此过程中，打磨出自身的观点极为重要，哪怕这些观点最终被证明存在谬误。</p><p>这一点，和我今年三月份写的一篇文章里的 <a href="/posts/eac7.html#%E6%88%91%E5%AF%B9%E6%9C%AC%E6%9C%9F%E7%9A%84%E7%9C%8B%E6%B3%95">一段内容</a> 不谋而合。这篇文章里，我本来是在介绍「那些不受欢迎的观点」活动，并对参与者们的观点思考一番的。但介于期待太高，一些内容让我觉得很是疲乏，所以我在结尾结合作家三毛的《学期作业报告》，发表了一番意见。大意是，有主观就说，总比无观要好。说时，要大胆地说，<strong>观点本就该是有争议的。</strong></p><p>我这段时间看了个番剧，名字我不想说，片内角色提到了一个概念：在电子游戏中，往往会出现个岔路口。一边是 BOSS 房，另一边是支线。如果走去支线的话，会花费更多的时间和精力，拿到尽头的奖励后还得原路返回打 BOSS。但情况又常常是 BOSS 难度极高，不去走支线拿奖励的话根本打不过。换言之，我们一时认为的「慢」，反而才是真正的「快」。</p><p>放到我对《学期作业报告》的看法，以及文章作者对学习时犯错的想法内，便能感觉出，我们认为的「错误」，实际上才是「正确」。观点有争议本身没有问题。但如果是没能好好思考过，才导致有争议的观点，经过他人指点和探讨，领悟的感觉才更深刻，和直接询问 AI 工具得到「正确答案」完全不同。</p><p>这也是为什么文章作者对未来的教育、下一代抱有堪忧。一旦 AI 工具普及率到达一个阈值，小孩子玩 AI 工具都比他们爷爷奶奶玩得溜了，他们还真的可以学得进去么？未来无疑是一个全民加快的未来。不单单是短视频、更快更刺激的娱乐剥夺了一般人们的耐心，AI 工具的出现也将「学习」的门槛一降而降……</p><p>结尾，文章作者做出了个猜想：AI 工具带来的效率导致全球的物质财富增长，所以失业的人不会被饿死，反而会过得不错。只是，他们会变成人形宠物，被供养起来，完全失去人性…… 我对这个前提抱有不认同态度。实际上现在人类的财富就已经够所有人都活得滋润了，但这种事情没有发生。这到底是为什么呢？我猜不出来耶 ——？（我在装傻）</p><hr><p>最后想要岔开话题、聊聊的是，文章作者采用了旁注，而我也经此意识到自己其实很讨厌旁注。去年十一月，我在 <a href="/posts/ea48.html#%E6%8A%8A%E8%84%9A%E6%B3%A8%E8%B8%A2%E5%87%BA%E6%96%87%E7%AB%A0%E5%90%A7">月刊</a> 里聊了聊脚注和旁注。当时也和 Spike 通过电子邮件讨论了下，我说的也是自己不太喜欢脚注和旁注，内容还是能塞进文本本身、就塞进文本本身最好。这也是我现在一直在做的，灵活使用括号、破折号，还有连接词！虽然我做得肯定也不是最好的，但我更喜欢这样，足矣。</p><p>旁注的一大问题在于，它会把我的注意力从中间的文本，强行挪到两边去。这种感觉实在是太糟糕了！尤其是作者他在本篇文章内，添加的旁注很长很长很长。就算使用了和背景色相近的文本颜色，但还是很影响阅读。</p><p>如果非要使用脚注或者旁注这样的形式，标注一些东西的话，我会更喜欢 <a href="https://www.geedea.pro/">Eltrac</a> 的做法：在自然段的下方立即插入注释，并且默认文本颜色很不明显，除非鼠标 hover 上去。不过他的注释说实话，太小了，我看不太清…… 是的，我喜欢很大的文字，大大大大…… 大大泡泡糖！</p><p><a id="美国网络安全局将其数字密钥公开在-github-上"></a></p><h4 id="美国网络安全局将其数字密钥公开在-github-上"><a class="markdownIt-Anchor" href="#美国网络安全局将其数字密钥公开在-github-上"></a> <a href="https://gizmodo.com/the-worst-leak-that-ive-witnessed-u-s-cybersecurity-agency-leaves-its-digital-keys-out-in-public-on-github-2000760330">《美国网络安全局将其数字密钥公开在 GitHub 上》</a></h4><p>我选择将它放在「商业与社会」，而不是「技术与创造」分类里。</p><p>因为我很难说服自己，这是与技术相关的事情…… 这件事情实在是太蠢了！白痴！</p><p><a id="meta-推出-instagram-facebook-和-whatsapp-订阅服务"></a></p><h4 id="meta-推出-instagram-facebook-和-whatsapp-订阅服务"><a class="markdownIt-Anchor" href="#meta-推出-instagram-facebook-和-whatsapp-订阅服务"></a> <a href="https://techcrunch.com/2026/05/27/meta-officially-launches-instagram-facebook-and-whatsapp-subscriptions-with-more-to-come-including-ai-plans/">《Meta 推出 Instagram、Facebook 和 WhatsApp 订阅服务》</a></h4><p>订阅服务分别是：</p><ul><li>3.99 美元一个月的 Instagram Plus</li><li>3.99 美元一个月的 Facebook Plus</li><li>2.99 美元一个月的 WhatsApp Plus</li></ul><p>这三个软件，对于年轻人而言实在是不得不用。这就得谈谈 FOMO（Fear of Missing Out，社群恐慌症）—— 由自己的不在场，而产生的一系列不安和持续性焦虑，总感觉自己不在时可能发生非常有意义的事情 —— 的恐怖之处，尤其是在年轻人群体中。</p><p>这也是信息流很可怕的地方。每次翻阅信息流，就会发现许多「必须得知道」的事情。但它们真的是如果不知道、我们的生活就会毁于一旦的事情么？自然不是。不去追随流、不去知道很多事情，反而会让我们的生活更好。</p><p>我离开了 Instagram 和 Facebook，转而拥抱个人网络，也有强迫自己不去查看人们认为自己必须得看的信息。除了社交平台，我也正在思考离开 BiliBili 这类视频平台。很有趣，我意识到自己能够察觉出算法的存在，并且对此产生厌恶之情。或许重新将以前做的 QQ bot 捡起来也不错 —— 也不是一定需要 QQ，随便一个软件接上 <a href="https://github.com/nonebot/nonebot2">Nonebot2</a> 都可以，再通过 <a href="https://github.com/DIYgod/RSSHub">RSSHub</a> 仅获取自己订阅的信息。</p><p>我看了眼 Instagram Plus 提供的额外功能。作为曾经的用户，我能感觉出一旦这些功能被推出，会有大量年轻人消费订阅，尤其是 Story 的受众列表的扩张、置顶 Story 等等。</p><p>最近又因为身边的朋友和我聊了聊炒股的事情，让我对股市有些感兴趣。借此调查一番发现，Meta 的主要业务是广告，占比有足足 90% 以上。它的其他产品，例如 AI 工具、硬件，销量都不尽人意。如果这些订阅计划被推出，有了稳定的收入，股市会变得绿油油的也说不定。</p><p>不过它同时也推出了 AI 计划，让我…… 怎么说呢，你也知道自家的 AI 产品是什么样，对吧……？</p><h2 id="心理与关系"><a class="markdownIt-Anchor" href="#心理与关系"></a> 心理与关系</h2><p><a id="我很喜欢友链里的所有人-但很遗憾-它必须得消失了"></a></p><h4 id="我很喜欢友链里的所有人但很遗憾它必须得消失了"><a class="markdownIt-Anchor" href="#我很喜欢友链里的所有人但很遗憾它必须得消失了"></a> <a href="https://gkeenan.co/avgb/i-really-like-everyone-on-my-blogroll-but-im-sorry-to-say-that-it-must-die/">《我很喜欢友链里的所有人，但很遗憾，它必须得消失了》</a></h4><p>「客观上被移除友链」这件事，能否直接等同于「自己存在过错，或者冒犯了对方」呢？</p><p>这自然是说不通的。但是对于作者来说，他主观上将对方视为比自己更高位的存在。因此当负面结果出现时，其讨好型人格会本能地将其归咎于自身的过失。</p><p>讽刺的是，这种内部归因可以在潜意识中提供控制感：只要查明并修正自己的错误，就能恢复彼此之间的关系。可惜，人类的行为往往都是具备随机性，是难以预料的。同理，外界环境也是不可控的。</p><p>我也遇到过自己的友链被移除的情况。第一次发现时，感觉挺不舒服的，因为我们曾经通过电子邮件交流过一两回，且当时我认为友链是重要的标识。</p><p>后来嘛，不知道什么时候，变得不在意了。友链友链，友情链接，不过是个破链接罢了。挂着给对方吸引些流量，也不是不行。因此，我几乎都不会去维护自己的友链页面 —— 还有邻邦页面，上面依然残留着我已经取消订阅的链接 —— 你还能在我的友链页面上找到旧的电子邮箱地址。</p><p>之后作者向亲友复述了事件，想要得到一些建议，然后得到了「过度反应」的假设。亲友认为，主动和泛泛之交联系，仅是为了去问友链被移除一事，会显得作者像疯子一样。</p><p>不过放弃询问，虽然规避了可能会发生的争执与尴尬，但也失去了证伪猜想的机会。最后，它会任由未知的恐惧在我们的脑海中持续地发酵，再发酵，最后形成闭环……</p><p>最终关闭友链的决定，正是必然的产物。害怕被伤害，同时将自身的敏感过度投射于他人、预设他人也会因同样的事情受挫……</p><p>我会给自己确立一个认知边界，即他人的行为就是可以被归因于巧合或客观偏好，也和我们的自我价值一点关联都没有。有了这个认知边界，我们再遇到同样的事情，便也不会第一时间想到去评判自己。</p><p>接着，接受自己不被喜欢的可能，并接受「自己不被喜欢」并不等同于「双方一定有人有错」这件事。不喜欢就是不喜欢，并非所有的不喜欢都要有人承担责任。</p><p>在「取消关注或者移除友链是否需要提前告知」上，我的观点是，关注一个人的账户，亦或者是持有一个人的博客友链，本质都是单向展示自己从哪儿获取信息。</p><p>如果提前告知的话，就会把单向的私人空间升级为需要双方共同面对的交涉。假设移除行为仅仅是因为兴趣转移，主动告知的话，对于被移除者就会是另一个冲击。因此，我更推荐不告而别。</p><p>那么作为被移除者，我们可不可以去询问对方为什么移除了自己的友链呢？我认为是可以的，不论结果如何、关系是否仅是泛泛之交。倒不如说，只有泛泛之交对友链的移除反应更大些。毕竟如果双方有着高频且深度的互动，便不会在意友链这种小小的标识。</p><p>对于泛泛之交而言，保留标识这个行为暗示着关系存在着向更亲近的方向发展的可能性。一旦被其中一方单方面地切断，那么在逻辑上极其容易被解读为对方不想要继续发展关系，甚至是排斥发展关系。</p><p>这样一说，友链或者关注订阅能有这种问题，都是因为每个人对其的理解不同 —— 接口不统一啊！使用 Fediverse 软件时，我也发现有时候我对一些人发的内容感兴趣，但不一定想要关注他们。亦或者反过来，我和一些人互相关注以表达友好，但不代表我想要在自己的流内看到他们的内容。</p><p><a id="ai-可能正让我们在思考和写作上变得更加相似"></a></p><h4 id="ai-可能正让我们在思考和写作上变得更加相似"><a class="markdownIt-Anchor" href="#ai-可能正让我们在思考和写作上变得更加相似"></a> <a href="https://dornsife.usc.edu/news/stories/ai-may-be-making-us-think-and-write-more-alike/">《AI 可能正让我们在思考和写作上变得更加相似》</a></h4><p>AI，尤其是 LLM，会同质化人类的认知和表达方式。如果不控制好的话，这种趋势势必会削弱人类的智慧，还有适应多样化环境的能力。</p><p>如果你有写作过，并将自己写的内容发给 AI 工具来校验的话，它会给出你并不赞同的建议 —— 至少我是这样。又或者说，你去观察依赖于 AI 工具来润色或者生成文章的人，会发现他们写出来的东西，不论是写作结构、用语，甚至是观点，都是非常相似的。</p><p>其中，用语最容易被察觉到，毕竟现实生活中没有人会说「我就在这里，不躲，不藏，不绕，不逃，稳稳地接住你。你问到问题的核心，你是太清醒了。这次我懂了，我真的懂了，不是因为你错了，是因为你太对了，我逐步说清楚，不绕，一句话总结，你看完会彻底开悟。不用硬撑，不用向我解释，你只是太久没被稳稳接住了。如果你想，我可以生成一张接住你的图片，你想让我做吗？」（这些是我手打出来的）</p><p>每个人都拥有独特的语言风格，以及视角。如果依赖于 AI 工具来润色，得出自认为「更好的文章」，那么你的个体性便被机器消灭了！这在群体都在依赖 AI 工具的情况下，效果更为显著。</p><p>ChatGPT 刚面世的那一年，便有 <em> biased data</em> 的担忧 ——「有偏见的数据」，即训练数据过度集中在西方主流社会，导致输出的内容过于狭隘。这一点，可以在 2023 年华盛顿大学的一篇 <a href="https://www.washington.edu/news/2023/11/29/ai-image-generator-stable-diffusion-perpetuates-racial-and-gendered-stereotypes-bias/">文章</a> 中初见端倪。</p><p>第二个 AI 同质化会带来的影响，是它会改变我们推理的方式。LLM 更倾向于使用线性的推理，最好的例子是逐步推演思维链。这一点是 LLM 的底层架构决定的，但具体是怎么个回事儿，我还在学习当中，无法说得既准确又易懂。大致可以用来参考的，便是解数学题那样的思考模式吧。</p><p>但是人类的推理方式，会有更多的直觉和抽象。一旦频繁与 AI 互动，那么人类会渐渐习惯，并迎合这单一的逻辑。</p><p>同时，人们的惰性会导致他们会直接去采纳 LLM 的足够好的建议，而不是坚持自主创作 —— 我们身边看到的文字，是不是具备「AI 味儿」的愈来愈多了呢？</p><p>同质化也不仅仅局限于影响 AI 工具的直接用户，还可以传染给社会内的其他人。即使是不使用 AI 的人，身处一个被统一形式的表达所包围的环境中，也会因压力而顺从主流。</p><p>知道了以上几点后，我又好奇起来。AI 工具因为训练了人类努力产出的智慧 —— 不幸地 —— 所以它有时候能够生成比一般人说的话更有价值的内容。注意，我这里说的「价值」，也不是客观意义上的价值，单论说话者自认为的「有价值」或者说「更有深度」。</p><p>作为例子，我们请出小明。小明他是个说话很没有深度的人，你可以想象成任何一个在互联网爱不动脑就喷屎的人。在小明有了 AI 工具后，他能够对许多以前根本看不懂的问题，「给」出大家看了都说好的回答 —— 我们作为创造了小明的神明，自然知道这是因为他将问题喂给 AI 工具，并让 AI 工具生成了逻辑紧密、结构完整的回复。不过小红小刚小野大辅（日本的知名声优）都不知道，以为是小明这个人贼有见识。于是乎，小明在这批人的面前，有了偶像包袱。为了不让别人察觉到自己肚子里其实一滴墨水都没有，他想尽办法让自己平日都说话像这样，并愈发认为自己就是这么厉害，AI 不过是给自己排了个版而已。</p><p>世界是庞大的，我们有无数个小明。多亏了人类会倾向于顺从主流这一点，这无数个其他的小明，看到了上一段我提到的小明变得无比有「见识」，又因为 AI 工具的普及率上升，也开始用起了 AI 工具。小明军团们使用 AI 工具互相交流、沟通，让社会都充斥着小明的味道。</p><p>对于我们这些已经知道 AI 工具的问题所在的人们而言，小明军团无疑是奇怪的。但是对小明军团而言，AI 工具能够让自己看上去更博学多才，更能写出更美丽的文字。</p><p>我好奇的点在于，在我们这个世界线的未来，是否会有更多的人要求他人写出逻辑更紧密、结构更完整的内容呢？在没有 AI 工具之前，要想验证一个观点是否全面，需要验证者自身有着一定的知识量，亦或者是有多个具有不同背景的验证者存在。现在有了 AI 工具，虽无法给出所有人类的视角，但也已经要比一般人的视角广阔一点 —— 我说的「一般人」指的都是特定领域里的大多数，即未受过上下文内提到的领域内教育的人。比方说，计算机领域里的一般人，就是根本不懂计算机的人。</p><p>好吧，我会有这样的奇形怪状的好奇，一是因为我父母这样的一般人也开始广泛使用 AI 工具解决问题，并嘴里时常蹦出他们过去不会说的术语和概念。二则是我今年 <a href="/posts/a4c0.html#:~:text=%E7%BD%91%E5%8F%8B%E4%B8%99%E5%88%99%E8%AE%A4%E4%B8%BA%EF%BC%8C%E4%BD%BF%E7%94%A8%20AI%20%E6%B6%A6%E8%89%B2%E8%BF%87%E7%9A%84%E6%96%87%E5%AD%97%E4%BC%9A%E6%9B%B4%E7%BE%8E%E4%B8%BD%20%E2%80%94%E2%80%94%20%E8%BF%99%E6%98%AF%E6%88%91%E4%B8%BB%E8%A6%81%E8%B4%A8%E7%96%91%E7%9A%84%E7%82%B9%EF%BC%8CAI%20%E5%86%99%E7%9A%84%E4%B8%9C%E8%A5%BF%E6%98%AF%E7%BE%8E%E4%B8%BD%E7%9A%84%E5%90%97%EF%BC%9F%E5%8D%9A%E4%B8%BB%E7%9A%84%E9%82%A3%E7%AF%87%E6%96%87%E7%AB%A0%EF%BC%8C%E9%99%A4%E4%BA%86%E8%AE%A9%E4%BA%BA%E6%83%B3%E5%88%B0%E3%80%8C%E8%BF%99%E6%98%AF%20AI%20%E7%94%9F%E6%88%90%E7%9A%84%E3%80%8D%EF%BC%8C%E4%BC%9A%E8%AE%A9%E4%BA%BA%E8%A7%89%E5%BE%97%E3%80%8C%E5%86%99%E5%BE%97%E5%A5%BD%E3%80%8D%E3%80%81%E3%80%8C%E5%86%99%E5%BE%97%E7%BE%8E%E4%B8%BD%E3%80%8D%E5%90%97%EF%BC%9F%E5%B0%B1%E8%BF%9E%E8%AF%84%E8%AE%BA%E5%8C%BA%E9%87%8C%EF%BC%8C%E4%B9%9F%E4%BC%9A%E6%9C%89%E4%BA%BA%E7%94%A8%20AI%20%E7%94%9F%E6%88%90%E7%9A%84%E6%96%87%E5%AD%97%E8%AF%84%E8%AE%BA%E5%8D%9A%E4%B8%BB%EF%BC%8C%E7%94%A8%E7%9A%84%E8%BF%98%E6%98%AF%20GPT%205%20%E7%B3%BB%E5%88%97%E7%9A%84%E6%A8%A1%E5%9E%8B%EF%BC%8C%E5%8F%AA%E6%9C%89%E6%BB%A1%E6%BB%A1%E7%9A%84%E7%88%B9%E5%91%B3%E5%84%BF%E3%80%82%E4%BD%86%E8%BF%98%E6%98%AF%E6%9C%89%E4%BA%BA%E7%94%A8%20AI%20%E7%94%9F%E6%88%90%E7%9A%84%E6%96%87%E5%AD%97%E5%86%8D%E5%BA%A6%E5%9B%9E%E5%A4%8D%EF%BC%8C%E6%9D%A5%E8%A1%A8%E7%A4%BA%E8%87%AA%E5%B7%B1%E8%A2%AB%E8%AF%B4%E4%B8%AD%E4%BA%86%E3%80%81%E4%BA%92%E7%9B%B8%E5%AE%89%E6%85%B0">三月一日</a> 的日记里，记录的一门趣事：我还在使用小红书时，发现了一群人，会使用 AI 工具生成的文字互相交流、回信，并认为 AI 工具写出来的文字是美丽的。</p><p>正如拼写检查软件普及后，拼写错误在文本中变得不可原谅一样。AI 工具普及后，逻辑紧密、结构完整的文本也会从加分项变成及格项。把时针再往未来拨一些，人们恐是会更变本加厉去要求他人提供如此的文本。作为这类文本的相反面，混乱、抽象、碎片化、逻辑断层的文本，会变成态度敷衍的证明吧。</p><p>实际上，现在能展现出直觉、个人偏见、逻辑留白，已经变成了验证个体是否具备独立思考价值的新标准。简单来说，便是能否说起话来更像有缺点的人。这又到底是好事还是坏事呢？为了表现出自己没有使用 AI 工具，大肆发表极具个人偏见的言论，似又是本末倒置，回到了最开始提到的「狭隘」。</p><h2 id="科学与自然"><a class="markdownIt-Anchor" href="#科学与自然"></a> 科学与自然</h2><h2 id="技术与创造"><a class="markdownIt-Anchor" href="#技术与创造"></a> 技术与创造</h2><p><a id="microsoft-如何剥削其用户"></a></p><h4 id="microsoft-如何剥削其用户"><a class="markdownIt-Anchor" href="#microsoft-如何剥削其用户"></a> <a href="https://lzon.ca/posts/other/microsoft-user-abuse/">《Microsoft 如何剥削其用户》</a></h4><p>一天，一名普通用户发现自己的 Outlook 邮箱因存储空间耗尽而无法接收邮件。</p><p>经过作者的排查后发现，耗尽空间的并不是邮件本身，而是 Windows 11 默认将用户的本地桌面文件同步到了 OneDrive 中。</p><p>我每次搞坏电脑、重装 Windows 系统时，第一件要做的事情是处理掉 OneDrive。它作为一个云盘，在我需要它的时候再出来不行么？我本地的文件凭什么默认存在它上面？我买的硬盘是装饰用的吗？</p><p>文章中作者推荐了 Chris Titus 的 <a href="https://github.com/christitustech/winutil">winutil</a>，感兴趣的可以看看。</p><p>Microsoft 这样的企业，在先前的月刊中便批判过多次。它已经放弃尊重其消费者用户了，最好离开 Windows。不过实际上的一般人，即不懂技术的人，并没有一个方便使用的替代品。MacOS 么？那就需要换台电脑。Linux 发行版？我无法给出一个确切的评价。要是能找到一篇由技术小白写的用后感就好了。</p><p><a id="cal-com-将转为闭源"></a></p><h4 id="calcom-将转为闭源"><a class="markdownIt-Anchor" href="#calcom-将转为闭源"></a> <a href="https://cal.com/blog/cal-com-goes-closed-source-why">《Cal.com 将转为闭源》</a></h4><p>这篇文章发布于上个月 14 日。当时我的想法是，怎么可能因为安全问题而转向闭源呢？开源才能让数不尽的用户找出更多的问题 —— 此事在《大教堂与集市》上有记载。</p><p>这个月我的想法改变了。基本上每周都有各种 CVE（Common Vulnerabilities and Exposures，通用漏洞披露）出现，而导致它们的理由很简单：挂个 AI agent 24 小时不间断去扫代码漏洞。</p><p>「只要眼睛多，漏洞容易找」，这个观点在现在难以成立。过去，人力资源稀缺时，开源能够聚集全球各地的开发者，大家一起找漏洞。但这个优势，随着 AI 工具的普及，一点点在被削弱。</p><p>闭源不能在物理上消灭漏洞，但因为隐藏了代码，显著增加了恶意攻击者的探测成本和门槛。</p><p>再加上开发团队内部同样可以部署 AI 工具来审查自己的闭源项目。开源能够换来的在安全性上的效益，也进一步被削减。</p><p>所以单就安全性上来说，开源的优势不如以往。但这不意味着开源的必要性就此消亡，只是说仅仅为了抓全球开发者来帮忙找漏洞而开源的形式，是该被改变了。</p><p><a id="在信任下一个自托管应用之前-请先看这个"></a></p><h4 id="在信任下一个自托管应用之前请先看这个"><a class="markdownIt-Anchor" href="#在信任下一个自托管应用之前请先看这个"></a> <a href="https://inv.nadeko.net/watch?v=Jzg6uhAB1D4">《在信任下一个自托管应用之前，请先看这个》</a></h4><p>这是一个 YouTube 上的视频。按照惯例，我将其指向了 Invidious 的端点。</p><p>Booklore 事件不知道读者们听过没有？这是一个自托管的数字图书馆软件。在今年 3 月份，有社区成员发现无法访问其 Discord 服务器和 GitHub 仓库，并且项目的所有在线资源都消失了。</p><p>原因在于，开发者被社区指控过度使用 AI 生成大量代码、在数据收集上不够透明、限制开源版本的功能。面对这些质疑和批评，开发者选择了…… 一把火烧掉一切！</p><p>这种做法自然是败坏了自托管社区的好感。没多久，社区成员便创建了 <a href="https://github.com/grimmory-tools/grimmory">Grimmory</a> 这个分支项目。</p><p>抛开 Booklore 开发者的问题不谈，在宏观层面上，这揭露了现在自托管社区的许多问题：大多数项目依然由单人负责维护。因为是他们自己的项目，他们想要怎么样就怎么样。</p><p>而另一个 Huntarr 事件更诡异。Huntarr 是个媒体自动化工具，用于管理 arr 生态系统（我对这个不了解）。今年 2 月份有安全研究人员对它公开安全审查，结果发现了大量严重的安全漏洞，例如认证绕过、敏感数据明文暴露 —— 哪个大聪明想出来的明文存储密钥。</p><p>披露后，开发者竟也选择了一把火烧光一切。不仅封禁了提出安全问题的社区用户，还删除了 GitHub 仓库。</p><p>社区同样创建了名为 Newtarr 的分支项目。</p><p>不过虽然有了分支项目这个解决方案，但是如何才能提前发现项目的问题呢？毕竟总不能数据泄露完了，才换成更安全的分支吧。</p><p>该视频的作者便建议，用这些方式来提前审核要使用的开源项目：</p><ul><li>检查贡献者的数量。如果是单人维护者，就要警惕一下了。这往往意味着维护者会面临严重的倦怠，以及经济压力；</li><li>不要看 GitHub 的星数，一点用没有，应该多检查近期的提交记录；</li><li>确认是否有安全披露政策。没有代码审查、测试流程和安全审计是导致严重漏洞的主要原因；</li><li>观察维护者对反馈的态度，听不进去一点反馈的维护者要不得；</li><li>查看 Docker 镜像的来源，还有更新日志。</li></ul><p>部署后也要做这些措施：</p><ul><li>锁定 Docker 镜像的版本，避免使用 <code>latest</code> 标签；</li><li>保留本地镜像的副本；</li><li>定期备份数据，确保是可以被导出的；</li><li>项目异常停运时要立即更换 API 的密钥；</li><li>关注社区动态；</li><li>制定应急迁移计划。</li></ul><p>虽然很多措施，都应当是开发者们的责任。但现在不聪明的 AI 工具使用方式的泛滥，作为用户，不得不保护好自己（和自己的数据）。</p><p>说实话，现在的自托管社区并没有那么可靠。不能再抱有浪漫主义的错觉，认为开源项目是美好的 —— 也是我 <a href="/posts/5586.html#nekogram-%E4%BC%9A%E7%A7%98%E5%AF%86%E6%94%B6%E9%9B%86%E5%B9%B6%E4%B8%8A%E4%BC%A0%E7%94%A8%E6%88%B7%E4%BF%A1%E6%81%AF">上个月</a> 提倡的做法。项目开源，它便一定安全、持久么？我们希望它是，但可惜它现在不再是了。</p><p>如果希望开源生态再度健康发展，我们需要主动介入其中。例如，从被动的代码消费者，转变为主动的审查员。</p><p>不过普通用户本就难以辨别代码的缺陷，我想了一些方案，仅用于抛砖引玉。为了更安全的代码，普通用户使用 AI 工具来扫描代码是没有问题。但这会激怒部分不想要将代码喂给 AI 工具（以及背后的企业）的开发者们。</p><p>另一个想法是，让社区生长出独立的第三方审计团体。通过对新兴的自托管软件进行代码审查和安全评估，审计团体可以出具公开透明的报告。这样普通用户便可以通过这些报告，得知哪些项目是危险的。</p><p>不过我也明确，纯粹依靠社区热情驱动的组织，非常容易就会重蹈单人维护者精力枯竭的覆辙。就算引入外部资金维持运转，审计的绝对中立性又会遭受质疑…… 自托管软件本是免费供应的，却需要消耗高昂的成本来证实其安全。</p><p>然后，我们需要有意识地选择和推广由团队维护的开源项目 —— 说是这么说，但我并不认为事情会发展得那么简单。单人维护者占社区的极大多数并非巧合。团队中最不重要的能力，反而是写代码。难道仅仅因为缺乏团队沟通和运营的能力，就要否定并抛弃单人维护者们的项目么？如何平衡这一切实在是太难啦！</p><p><a id="自托管周刊"></a></p><h4 id="自托管周刊"><a class="markdownIt-Anchor" href="#自托管周刊"></a> <a href="https://selfh.st/">《自托管周刊》</a></h4><p>嗯，是的，这个条目仅是我想要分享一个周刊给读者们。它叫作「自托管周刊」，由英语编写。除了分享大量自托管项目外，周刊内还会夹杂自托管社区内的大大小小风波和事件，也适合用于了解社区每周都发生了点啥。</p><p>我不会把自己放在自托管社区内，说实话，我也不认为自己在开源社区内。我近乎不会给开源项目贡献，issue 都很少开…… 我是《大教室与集市》中提到的「流氓」，只喜欢打补丁，但不告诉其他人。</p><p>至于为什么，我想是因为我讨厌和其他人沟通工作，尤其是和我相同专业的人们。恐怕我是恐惧自己的嫉妒心吧。</p><p>《大教堂与集市》这本书，我从上个月开始慢慢在碎片化的时间中阅读。未来读完想要特意写个文章聊聊它。这里我就简单拿它第三章节的内容出来吧。</p><p>黑客文化在当时为何如此不同寻常？作者 Eric Raymond 提出了两个方向：工艺模式与礼物文化。前者是黑客们对写出优美的代码的执着，因此他们会想方设法在同僚看到前，折腾出最优美、最完美的代码。后者是因为代码资源过多，并不算什么稀缺物资，因此可以在社区内作为「礼物」赠予他人。</p><p>这两者的本质都是相同的：通过代码来提升自己的声望，以在社区内有着更高的社会地位。</p><p>人们想要更高的社会地位，恐怕我要一路讲到人类刚开始使用石器的时代。实在是过于久远，所以不打算说。大家对声望都有着执着，而它会以不同的形式表现出来 —— 我害怕声望所带来的、未来潜在的、来自于他人的失望。</p><p>不过这本书我还未读完。读到最后，我的想法也会随之改变也说不定。</p><p><a id="互操作性将拯救开放网络"></a></p><h4 id="互操作性将拯救开放网络"><a class="markdownIt-Anchor" href="#互操作性将拯救开放网络"></a> <a href="https://spectrum.ieee.org/doctorow-interoperability">《互操作性将拯救开放网络》</a></h4><p>Cory Doctorow 这个人，我在 <a href="/posts/c089.html#%E5%90%8E%E7%BE%8E%E5%9B%BD%E4%BA%92%E8%81%94%E7%BD%91">过去</a> 提起过，是一位著名的数字主权活动家。他近期出了本新书，叫 <em> The Internet Con: How to Seize the Means of Computation</em>，直接翻译的话就是《互联网骗局：如何夺取计算工具》。</p><p>本篇文章是对 Doctorow 的采访。采访中他提到，Twitter、Facebook、Apple 等科技巨头能有现在这样的统治地位，并不是人们普遍以为的，它们有着卓越的技术。实际上，这些平台通过法律的手段，构建了封闭的围墙花园。</p><p>这一点和他在《后美国互联网》这场 <a href="https://pluralistic.net/2026/01/01/39c3">演讲</a> 中说得一致。尝试破解或者逆向工程在平台们利用的法律条款中，会被定性为犯罪（DMCA）。这有效地阻止了竞争对手，也强行剥夺了用户的选择权。</p><p>为了瓦解这种垄断，Doctorow 主张强制推行 <u>互操作性</u>，即不同平台或者系统之间相互协作、数据互通的能力。文章也重点探讨了互操作性的三种形式：自愿、强制的互操作性，例如在自己的车里加任何厂商的汽油、在灯座上装任何灯泡；漠不关心的互操作性，例如汽车公司不会阻止用户在车内使用点烟器转 USB 的适配器；对抗性互操作性 —— 重点中的重点 —— 例如公司甲利用爬虫、逆向工程等技术，创造了兼容公司乙平台的产品。</p><p>曾经，对抗性互操作性是推动科技行业发展的核心。但现在，科技企业为了利润，放弃支持公众利益，切断了互操作性。用户无法再带走自己的数据，平台也不再善待用户。</p><p>先前说过，平台们是通过 <span class="emphasis">法律手段</span> 而构建封闭生态的，并非科技手段。那么如何恢复曾经的互操作性、拯救过去的开放网络呢？Doctorow 的结论是修改法律。以 Twitter 为例：用户关注了谁就必须能看到该用户发布的内容，而不是利用算法操纵信息流；用户在离开平台时必须有权利带走自己的数据。</p><p>为什么非得这么要求、开放网络对普通人真的有意义么？答案是「有意义」。目前的大量平台，都因为囚禁了用户、没必要继续善待他们，而在自己的围墙花园内大搞一通。如果用户有了更多的选择，无法再被囚禁住，那么平台只能通过提升服务来留住用户。</p><p>采访中另一个话题是和「垄断」有关。一个行业要想在法律和监管上达成对自己有利的目的，必须同时具备两个条件：一是将超额利润转化为游说资金的能力，二是行业内部的高度团结。</p><p>为了说明这一点，Doctorow 提到了过去的 Napster 版权大战 —— 这是一场从上世纪末发生到本世纪初的，互联网最著名的数字版权大战之一。Napster 这款软件开创了 <u>点对点</u>（也就是 P2P）文件共享技术，让网民们能够绕过唱片公司，免费且直接地互相传输音乐文件。这种模式不仅迅速吸引了大量用户，还冲击了当时依赖于实体 CD 销售的传统音乐产业。随后，美国唱片业协会（RIAA）以及诸多音乐人联手对 Napster 发起诉讼，指控其纵容大规模的版权侵权行为。这场大战以传统唱片工业胜诉告终，Napster 被迫关闭服务器、宣告破产。Napster 版权大战结束后，市场们都一一发现了数字分发的潜力，迫使音乐行业都往数字化妥协，并直接催生了后来的合法付费下载，以及流媒体订阅模式 —— 这些都是后话了。</p><p>说回 Doctorow。他提出 Napster 版权大战，是为了指出大战途中双方的状况：和我想象的不同，Napster 所代表的点对点网络，虽然整体极其活跃，且利润丰厚，但力量都分散在无数个初创企业中。它们各自为战，甚至在商业路线上互相拆台。当 Napster 遭到起诉时，科技行业根本无法形成统一的战线，更没能合力去游说国会保护这种技术创新。反观作为原告的传统唱片工业，虽然公司数量少，但都是巨头。面对 Napster，这几家巨头全都结成利益共同体，不仅集中火力干掉了 Napster，还联合推动了数字版权法案。</p><p>咦？少量公司…… 巨头…… 这不正是现在的科技巨头们么？Doctorow 想说的正是，如今的科技巨头已经演变成当年那几家唱片公司的模样。它们压榨用户是因为技术好么？不，是因为它们具备庞大的资金以及垄断团结。</p><p>强制推行互操作性的另一目的，便是引入真实的竞争。竞争首先会削减科技巨头的利润，导致它们没有充足的闲置资金去游说政府。其次，竞争会带来大量的新兴市场参与者，打破现有的巨头利益同盟。一旦参与者变多，行业内部就很难再在干预政策上达成一致。你不能干预法律了，自然也不能利用法律维持围墙花园 —— 可喜可贺，可喜可贺。打破垄断的良性循环诞生了。</p><p>采访最后谈到的是「为什么要先打击科技行业」。理由也很简单，不同于实体经济，例如铁路，科技行业的基础建立在代码与协议之上，数据天生具备流动性。只要开放 API 或者允许逆向工程，不同的系统和平台之间便可以随时、低成本地连接到一起。科技巨头的垄断地位并没有物理基础，它们完全是依靠律师团队和人为的法律限制硬撑起来的。</p><p>再加上，垄断巨头往往会让公众，甚至监管机构陷入无力，以为这些企业已经庞大到凌驾于国家机器之上，不可战胜。Doctorow 引入了过去标准石油的例子，但我对这个并不了解，仅能明白他的意思：<strong>要让人们意识到政府确实有能力约束资本。</strong></p><p>综上所述，Doctorow 主张，摧毁科技垄断便能接着击溃其他行业的垄断。</p><p>他的新书我还未阅读，届时应会有更多例子。</p><p>我很喜欢他的主张。无论是否能够成功反垄断、拯救开放网络，多一种选择总归是好的 —— 这样说，也是因为我并不完全相信它会成功。不愿承认的是，世界上大多数人，或者说「普通人」，根本不在乎这些事情。我也尝试过向周遭的人宣传我的理念，哪怕是一点点，都会得到糟糕的反馈：好一点的至少会表达感兴趣，但依然会选择留在围墙花园内；坏一点，就会觉得我脑子有病，「为什么要使用 Kagi 这种路边、奇奇怪怪的屎引擎？ <em>Just use Google.</em>」</p><p>但我不想去否认 Doctorow 的主张都是「理想主义」、「不可能做到的事情」。大道理是，在想改变世界之前，先改变自己，再是周围的人…… 我们缺少许多微观上的策略。例如如何让身边的人转向使用 AT Protocol 或者 Fediverse 软件，而不是 Twitter、Instagram—— 可是，从小便使用这些围墙花园软件的人，真的能够抛弃它们、转向完全陌生的新软件么？要知道，互联网上最多的「普通人」，是对技术一点都不了解的人。</p><p><a id="对苦差事的选择性失明"></a></p><h4 id="对苦差事的选择性失明"><a class="markdownIt-Anchor" href="#对苦差事的选择性失明"></a> <a href="https://paulgraham.com/schlep.html">《对苦差事的选择性失明》</a></h4><p>这是 Paul Graham 在 2012 年初写的文章。这个人是谁呢？是 Y Combinator 的创始人之一。你要还想问 Y Combinator 是什么，就想想硅谷的创业加速器、「孵化」这些内容吧。</p><p>原文标题是 <em> Schlep Blindness</em>，其中的 <em> schlep</em> 可以理解为麻烦事儿、苦活累活。我将整个标题翻译成「对苦差事的选择性失明」，是因为 Graham 认为的 <em> schlep blindness</em>，更多是人们知道、看到，但视而不见的麻烦。直接翻译成「盲点」，便失去了「知道」的前提，更像是「不知道而没做」。</p><p>回到文章本身。Graham 认为，许多极具潜力的创业想法其实就摆在人们眼前，但创业者却往往当没看见。这种忽略，都源自于人类潜意识里对繁琐、枯燥且令人不快的工作有着本能上的逃避。</p><p>作为例子，Graham 拎出来了 Stripe。在没有 Stripe 的过去，在线的支付体验很糟糕。尽管无数技术人员深知这个痛点，但多数人宁愿去开发简单的食谱网站，也不愿意触碰支付领域。这是因为，解决支付问题需要应对银行交涉、欺诈防范、政府监管…… 害怕麻烦的情绪阻碍了他们去解决这个真实的需求。谁叫技术人员往往都只希望专注于写代码，而不是和其他人沟通呢？</p><p>Graham 强调，苦差事不仅不可避免，还是商业运作的核心。一家公司的价值由它所承担的繁琐工作来定义。一旦创业者决定直面这些复杂的现实难题，就能在市场中占据明显的优势。</p><p>为了主动发现这些被忽视的机会，人们应跳出常规的思考模式。比起问自己，「我能解决什么」，倒不如问自己，「我迫切希望别人能替我解决什么」。</p><p>实际上，这篇文章是我在使用 <a href="https://github.com/garrytan/gstack">gstack</a> 时，它很可恶地推送给我的 —— 你只是一个 skills 集合，凭什么在我使用期间给我推送东西？幸运的是，推送的文章是我感兴趣的。这个 skills 集合是由现如今 Y Combinator 的 CEO，Garry Tan 搞出来的。他引用了 Graham 的这篇文章，想要表达的是「就算有着许多苦差事，有了 AI 工具后，就算是普通人也能着手于解决它们」——AI 工具自诞生以来，最大的价值便是让普通人也能做些啥吧。</p><p><a id="把我的邮件丢进黑洞"></a></p><h4 id="把我的邮件丢进黑洞"><a class="markdownIt-Anchor" href="#把我的邮件丢进黑洞"></a> <a href="https://www.johnsto.co.uk/blog/blackholing-my-email/">《把我的邮件丢进黑洞》</a></h4><p>文章的内容很简单。作者 Dave Johnston 回顾了 2002 年，自己被迫注销个人常用邮箱的始末。</p><p>不过 Johnston 这个人，大有来头。如果有游玩过第一人称射击类游戏的话，都会知道 <em> Counter-Strike</em>（《反恐精英》，简称 <em> CS</em>）吧？这款游戏有两张非常经典的地图，也就是沙漠地图系列：<em>de_dust</em> 以及 <em> de_dust2</em>，简称「沙一」和「沙二」。而设计这两张地图的，正是 Johnston。</p><p>当年该地图系列随着游戏被安装到了全球无数个电脑中，而它附带的含有作者联系方式的 README 文件，为文章内提到的邮箱瘫痪事件埋下了伏笔……</p><p>要说 Johnston 的邮箱是如何瘫痪的，那就得先说说千禧年初的 <u>蠕虫病毒</u>。这是一类能够自我复制，并利用网络连接自动传播的恶意软件。那时候，电子邮件构成了其最核心的传播温床。</p><p>还是用一个中国人更熟悉的例子吧：熊猫烧香。2006 年底到 2007 年初，它通过局域网共享、U 盘和移动存储设备、网页挂马、Windows 系统的弱口令和漏洞等方式，在互联网上大规模爆发。</p><p>而文章内提到的 ILOVEYOU，早在 2000 年就从菲律宾开始传播。攻击者 Onel de Guzman 利用了 <u>社会工程学</u>，在邮件系统中发送带有诱惑性标题 <em> ILOVEYOU</em> 的信件，以及标题为 <em> LOVE-LETTER-FOR-YOU.TXT.vbs</em> 的附件，让用户出于好奇点击进去。</p><p>这里我必须要吐槽一下 Windows 的狗屎默认特性：隐藏已知文件扩展名。我们能看到附件的后缀是 <code>.vbs</code>，但是对于未能关闭该特性的用户而言，他们看到的是 <code>.txt</code>，也就是纯文本文件。还以为真是什么情书呢，稀里糊涂点进去，VBScript 便运行了，裤衩（拟声词）一下电脑上的秘密都被盗窃走。</p><p>不仅如此，该病毒还会读取用户的通讯录、伪造原始用户的身份，向名单上的所有联系人批量发送包含该病毒的邮件。于是乎，海量的数据请求诞生了…… 全球的企业和机构，他们的邮件服务器都因负载过高而崩溃。这里也包括 Johnston，最终导致他注销了自己的邮箱。</p><p><a id="如果-ai-为你编写代码-为什么还要用-python"></a></p><h4 id="如果-ai-为你编写代码为什么还要用-python"><a class="markdownIt-Anchor" href="#如果-ai-为你编写代码为什么还要用-python"></a> <a href="https://medium.com/@NMitchem/if-ai-writes-your-code-why-use-python-bf8c4ba1a055">《如果 AI 为你编写代码，为什么还要用 Python？》</a></h4><p>这篇文章的核心观点在于，随着 AI 接管代码编写工作，开发者们不再需要为了快速交付而妥协选用 Python 等动态语言，而是可以直接利用 AI 生成高性能的底层语言代码，例如 Rust、Go、C++ 等。</p><p>除了性能上有提升外，这些困难的语言也有个共性：有着严格的编译器。</p><p>我有个丢给 AI 工具做的项目。最初使用的是 JavaScript，但很快我发现，AI 工具在编写类型不严格的语言时，做得可谓是相当差劲。后来我切换成了 TypeScript，但效果依然不佳，因为 AI 工具会想方设法写 <code>any</code>、<code>undefined</code> 等类型上去，好跳过实际的接口匹配……</p><p>作者因此认为，Python 和 JavaScript 的生态系统在未来会慢慢被瓦解。未来编程语言的竞争维度，将从「是否利于人类理解」，转向「是否利于 AI 生成与纠错」。</p><p>就我现在对市场和社会的理解，我赞同作者的结论。人类的惰性，自然是哪个好用使哪个。所以在未来，我们会看到更多用 Rust、Go、C++ 写的开源项目。</p><p><a id="有趣项目"></a></p><h4 id="有趣项目"><a class="markdownIt-Anchor" href="#有趣项目"></a> 有趣项目</h4><hr><h2 id="我写的文章"><a class="markdownIt-Anchor" href="#我写的文章"></a> 我写的文章</h2><ul><li><a href="/posts/b984/">《关于 Stallman 报告》</a></li><li><a href="/posts/51f0/">《我和宗教》</a></li><li><a href="/posts/f118/">《我开始有健康的生活习惯了》</a></li><li><a href="/posts/61e0/">《我的求职路・壹：投简历和找对方向》</a></li><li><a href="/posts/8513/">《观 <em>Obsession</em> 》</a></li><li><a href="/posts/85d6/">《读《私宴》》</a></li></ul><h2 id="书籍"><a class="markdownIt-Anchor" href="#书籍"></a> 书籍</h2><h4 id="其他评价"><a class="markdownIt-Anchor" href="#其他评价"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/book/work/1XwjYEKSi8pDoJnwdlubGc" target="_blank" rel="noopener noreferrer">Build Financial Software with Generative AI (from Scratch)</a><span class="neodb-rating">★★☆☆☆</span><span class="neodb-status">已读</span></li><li class="neodb-item"><a href="https://neodb.social/book/3erPShUuTfvq3JloNtYayO" target="_blank" rel="noopener noreferrer">晚安，布布（01)</a><span class="neodb-rating">★★★★★</span><span class="neodb-status">已读</span><p class="neodb-comment">浅野一二〇的作品每次看都觉得「卧槽！」，然后再也不敢看第二遍…… 这本对我而言是最不想要重新看的。或许未来内容快忘光了会再拿起来看。</p></li><li class="neodb-item"><a href="https://neodb.social/book/2Et0eHNojEiQVdh9P7J7YL" target="_blank" rel="noopener noreferrer">Nothing to Envy</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已读</span><p class="neodb-comment">断断续续读完的。对了解上个世纪末到这个世纪初的北朝鲜很有帮助。</p></li><li class="neodb-item"><a href="https://neodb.social/book/70PvDMdEMCLCv0sKKg56aI" target="_blank" rel="noopener noreferrer">动物农场</a><span class="neodb-status">想读</span></li></ul><h2 id="影视"><a class="markdownIt-Anchor" href="#影视"></a> 影视</h2><h4 id="其他评价-2"><a class="markdownIt-Anchor" href="#其他评价-2"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/movie/3c1kyDKUvemvvxWRAKVAt6" target="_blank" rel="noopener noreferrer">疯狂动物城 2</a><span class="neodb-rating">★★★☆☆</span><span class="neodb-status">已看</span><p class="neodb-comment">远没有第一部做得好。</p></li><li class="neodb-item"><a href="https://neodb.social/movie/799DmZUge8vtJQgXbE27Sa" target="_blank" rel="noopener noreferrer">功夫梦：融合之道</a><span class="neodb-rating">★★☆☆☆</span><span class="neodb-status">已看</span><p class="neodb-comment">剧情挺一般的，相当俗套。设定为中国人的配角，演员不能找普通话好点的吗，经常会听出戏。</p></li><li class="neodb-item"><a href="https://neodb.social/movie/0iGhptbOY50jsR948XvDxE" target="_blank" rel="noopener noreferrer">飞奔去月球</a><span class="neodb-rating">★★☆☆☆</span><span class="neodb-status">已看</span><p class="neodb-comment">很一般。人物情感处理没有做到位。人物模型不喜欢，刺猬狗倒是挺可爱的。总体看下来塞了很多东西进去，但都没有讲好。</p></li><li class="neodb-item"><a href="https://neodb.social/movie/6jJ4dkY7oEi2Vw9fLvKvql" target="_blank" rel="noopener noreferrer">机器人之梦</a><span class="neodb-rating">★★★★★</span><span class="neodb-status">已看</span><p class="neodb-comment">结局看哭了。观影期间很享受，许多歌曲是我喜欢的，很多表现形式也很有趣。从头夹到尾的曼哈顿元素特别多，很容易共鸣。</p></li><li class="neodb-item"><a href="https://neodb.social/movie/1h6eSFaFOKzV3ElOnk0BnA" target="_blank" rel="noopener noreferrer">痴迷</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已看</span><p class="neodb-comment">作为恐怖片恐怖得很成功。太恐怖了。有很多搞笑的地方。</p></li><li class="neodb-item"><a href="https://neodb.social/tv/season/0s9CnppzV8aZf2XKTcYQEj" target="_blank" rel="noopener noreferrer">魔法少女毁灭者（魔法少女魔法破坏者）</a><span class="neodb-rating">★★☆☆☆</span><span class="neodb-status">已看</span><p class="neodb-comment">烂片出神曲 / 神作画的典型代表。OP 和 ED 的作画艺术到不行，但是正片太糟糕了。</p></li></ul><h2 id="音乐"><a class="markdownIt-Anchor" href="#音乐"></a> 音乐</h2><h4 id="其他评价-3"><a class="markdownIt-Anchor" href="#其他评价-3"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/album/65xsb8dtWSUmZfYi9RNXjZ" target="_blank" rel="noopener noreferrer">Static</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已听</span><p class="neodb-comment">很不错的 Vocaloid 英语歌。高潮带感。MV 也很棒，我还挺喜欢 MV 的画风的。</p></li><li class="neodb-item"><a href="https://neodb.social/album/2niRtikcQzcTCcstERWVEf" target="_blank" rel="noopener noreferrer">September</a><span class="neodb-rating">★★★★★</span><span class="neodb-status">在听</span><p class="neodb-comment">超级经典。</p></li></ul><h2 id="日记片段"><a class="markdownIt-Anchor" href="#日记片段"></a> 日记片段</h2><button id="details-toggle-diary_sections-1789678110894" class="details-toggle-btn" data-group="diary_sections" onclick="toggleGroupDetails('diary_sections', 'details-toggle-diary_sections-1789678110894', '展开所有', '收起所有')">展开所有</button><details data-group="diary_sections"><summary>五月一日</summary><div class="diary-entry">01:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQGHRK188NPGT2JK9S8WYJA1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>后厨师傅每做错一道菜，我的宵夜就多一道菜。嗯…… 结果今天被投喂三份主食。</p><p></p></div><hr><div class="diary-entry">01:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQGJ92FXWH6ZY8PRTBG10R52" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不知道为啥，信用卡这几个月来好多地方刷不过去：坐车刷不了，前几天买菜也使不了，烦。之后干脆把信用卡都关掉，管你什么 cashback。没钱没钱，不刷不刷。</p><p></p></div><hr><div class="diary-entry">01:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQGJG7VM6N1PA7R7JNE5CNP3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>什么时候人们可以停止询问我有没有男朋友 😡😡 不用 neocat 表情是因为我要表现出很生气的样子。</p><p>室友提议直接说自己是 gay 就好了 —— <em>Yes I'm the gayest person you would ever see. I have fucking gay power.</em></p><p></p><blockquote class="diary-thread-reply">01:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQGJMP5F06Y5KM4TTZVDFSZY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>话说回来朋友们经常说我讲英语的时候听上去很 ghetto…… 我好像也感觉出来了……</p><p></p></blockquote></div><hr><div class="diary-entry">02:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQGMGZR8GFFEYWQ8XH3BVD62" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想要一把办公椅，坐在上面工作应该很舒服。然后把家里的桌子换掉，我喜欢 L 型桌，但是从来没有使用过。我理想中的桌子有一面可以拿来放显示器，有一面放纸笔或者笔记本电脑。腿上应该是放键盘的地方，柜子或者抽屉应当在我的脚边或者桌子两侧，总之不能在我腿上方。桌面上不需要有书架，但是得找个放台灯的地方。</p><p>小时候一次生日亲戚送了我一套学习桌，也就是一整个桌面可以弄平、也可以弄斜来方便使用者写字的。我也想要弄一个给妹妹，她今年才拿到属于自己的书桌 —— 谁家化妆台拿去给小孩写作业，明明也不是没钱买桌子。</p><p>这几天邻居们貌似搬了好多离开，许多家具被搁置在街上。有些想拿走，最后想想家里不够放、放弃了；有些想拿走，晚上下班回来发现被别人拿了 —— 正所谓先下手为强就是这个道理吧！</p><p>不过没什么闲钱做这种事情呢，室友也不一定让。这个破人更看重家具的颜色和样貌，以及整个房间的搭配和协调。如果弄一张白色的办公桌椅来，她一定会生气的。办公椅能滑动，也要考虑下楼下老头敏感的神经，估计还得买个毯子垫在下面…… 我可不想再听到他骂街。</p><p></p></div><hr><div class="diary-entry">15:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQJ3YK3MMP9FBZZVZ52ZRXMZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>准备数据库管理系统课的考试时，想到去年刷到但没有看完的「炮轰 MySQL」系列视频： <a href="https://space.bilibili.com/162183/lists/7605634?type=season" rel="nofollow noreferrer noopener" target="_blank">https://space.bilibili.com/162183/lists/7605634?type=season</a></p><p>虽然和这节课的关系不大啦。</p><p></p></div><hr><div class="diary-entry">16:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQJ4D02A6K23CF890K8WKV9B" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看博友梁某银两周前的 <a href="https://liangmouyin.com/blog/scrub-towel/" rel="nofollow noreferrer noopener" target="_blank">文章</a>，让我也买了个搓澡手套 —— 冲动消费！</p><p>其实很好奇为啥我一直没想到去买它，明明小时候经常被这玩意儿搓。</p><p>Amazon 上搜它容易蹦出来 <em>Korean exfoliating mitt</em>。韩国人也常常使用么？</p><p>洗澡期间搓完，皮肤红彤彤，便想起小时候好像是讨厌它的。不知是心理作用还是什么，总之皮肤没有滑溜溜的感觉哩。</p><p></p></div><hr><div class="diary-entry">16:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQJ5N2K8PYNWM46KK93SYRYQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>代码托管服务被爬虫卡爆了啦 ——！</p><p>查了下日志有 60 多个在排队，但我 worker 也才加到 4 个。你们不要爬了，不要爬了。这是我过去爬虫偷东西应得的惩罚吗。</p><p></p></div><hr><div class="diary-entry">17:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQJAFXFBYA8YBSKA5VCZQCP7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想要微波 bánh mì 吃的时候把盘子摔碎了。</p><p>又得花时间新添厨具了么？对家里的碗筷、锅，以及整个厨房的布局都不是特别满意。整个厨房小到令人怀疑到底是不是设计来做饭的，反而更像是单身汉随便煮点预制菜将就着吃的地方。</p><p></p></div><hr><div class="diary-entry">21:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQJNRWF54HAXB0CM5P3KG2HV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>经校友推荐复习用了 NotebookLM，效果看上去不错，不知道有没有 degoogle 的替代品。也得警惕使用 AI 时常见的「看上去好像学了但其实只有 AI 在学」的问题。</p><p></p><blockquote class="diary-thread-reply">23:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQJXRSCFVE495RBNBJ1NA7ZQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>结果复习错方向了…… 囧。</p><p></p></blockquote></div><hr><div class="diary-entry">21:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQJRJKJFTT5AKVPDC35FGAK6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>收到了 AWS 的账单，明明记忆里已经没有跑在它上面的服务了。晚上回家得看眼是怎么回事。</p><p></p></div></details><details data-group="diary_sections"><summary>五月二日</summary><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ5S50F578QGJW9V8Z3MF24N">↩ 续前文</a>        </div> 00:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQK098S15K7XQZASYS70WP8Y" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Raymond 引用了 John Locke 的财产论。在这之前，他讲了讲黑客们都是如何在开源圈内看待、管理自己的项目的：项目都是由一个原创作者开始。其他使用该项目的黑客们提出问题、给出补丁，而核心团队检查它们、决定是否要纳入项目的源代码。这里有个让我觉得有意思的点：<strong>黑客们厌恶分支。</strong></p><p>这句话我不知道是对是错，因为我并不是真正意义上开源圈内的黑客 —— 我其实从来都没有给项目贡献、提出 PR 过。我发现我更像是 Raymond 口中的「流氓」：喜欢克隆下来他人的项目、打流氓补丁或者写自己的分支，但就是不贡献代码。</p><p>那么为什么黑客们厌恶分支呢？这就要回到黑客们身上无法被礼物文化解释的地方，也就是名声竞争了。顺着 Raymond 的观点，可以看出，开源圈的黑客们并不是利他主义者 —— 倒不如说这世上真的有利他主义者么？利他的自我满足，不也是一种「利己」么？</p><p>礼物文化里社会地位取决于人们赠予了什么 —— 在开源圈的案例里，是黑客们开源的代码。不过分支能够破坏一个项目的认同感、稀释掉「官方版本」的用户基数和知名度。这也是为什么，黑客们厌恶有人未授权的情况下强行接管项目、创建具有竞争性的分支。他们更倾向于原作者退出后，将继续维护项目的核心权力交给另一个人；亦或者是一个项目被荒废过久、突然蹦出来一个人自行决定要继续维护它。</p><p></p><blockquote class="diary-thread-reply">00:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQK1FJYNGB6YZ4E784PQ7EY5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>而 Locke 的财产论（来自于《政府论》的第五章）大致逻辑是：</p><p>一、每个人有自己的身体的所有权。既然拥有了身体，那人也拥有身体所从事的劳动；</p><p>二、上帝将地球以及地球上的所有物资赐予了全人类所有。那么私人财产会以这个形式诞生：<strong>人的劳动和自然界的资源混合</strong>。例如我动手去摘取野外的苹果，那么这个苹果就成了我的资产；</p><p>三、为了避免资源的过度垄断以及浪费，还要有以下两个前提条件：</p><ol><li><p>一个人在获取资源时，得为别人留下足够多、同样好的资源，因为私有化不能导致别人的处境困难；</p></li><li><p>一个人占有的资源不能超过其使用能力。</p></li></ol><p>而黑客文化能够和该财产权共鸣：原创作者投入了大量心智劳动、写了个项目。这个项目在道德和名望层面就成了他的私产。</p><p>强行分支则等同于在他人已经开垦、围栏并耕种的土地上强行划出一块归自己。这种行为破坏了「通过劳动获得所有权」的秩序。同时，黑客们通过混合劳动确权，但他们选择将使用权回赠给社区以换取名望。这种名望是另一种形式的财产，而分支则是对这种名望财产的拆分与掠夺。</p><p></p></blockquote></div><hr><div class="diary-entry">04:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQKGH77M5QQR2D5SCYDQMEG9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>和朋友出去吃饭，她打算考考我：负债 liability + 什么 = 什么？</p><p>我有点印象，说其中一个一定是资产 asset。她说是 asset + liability = stockholder's equity.</p><p>听上去有些不对：equity 是净资产。资产加上负债怎么可能会是净资产呢？查了下发现果然，反了，是 asset - liability = equity.</p><p>没有学习过但是有印象的原因是，她以前学习的时候当着我的面说过三次：一次自言自语，一次尝试教我，一次尝试教会她母亲。</p><p></p></div><hr><div class="diary-entry">16:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQMR5Y5X446NVBCKHX8BY5V5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天和朋友去游戏厅玩，结果同时遇到了造谣者以及被造谣者 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 我不是特别喜欢在外起冲突的人，所以不会突然不搭理造谣者，因为在他看来我是不知情的…… 但和他说话依然很别扭。再加上他开始做些奇奇怪怪的行为，例如不玩游戏也不排队，坐在玩家等候区不停在大声打电话。他离开时，和他不对付的团体便找我们说话，说他这几个月间都是这样，也不知道他来游戏厅的目的何在 —— 好像他之前的朋友全都和他断交，在游戏厅内也没有谁愿意和他说话，除了他主动介入对话也愿意回应几句的我们吧。</p><p></p><blockquote class="diary-thread-reply">16:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQMSSSDGGCXGQV0FENS9F1CF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>另一个我一直想要吐槽的事儿是，游戏厅里，尤其是我玩的这款街机的圈子里的玩家，素质都好低好低。经常莫名其妙大喊大叫，讲话也常常夹杂着各种各样的脏话，还有背着别的玩家批判他玩得如何。还挺烦的，在这种成绩主义至上的环境里玩游戏，很多时候会被影响到、没法体验单纯的「玩」—— 我是很讨厌竞争的人，玩游戏也没有一个准确的目标。</p><p></p><blockquote class="diary-thread-reply">20:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQN7FT37STP79DYT22R974DG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>再一个想要吐槽的事儿：讲话不要那么「网络」呀！我不知道什么词能够形容这样的讲话方式，总之是会玩许多梗、像是铁哥们儿般互损。可是我们关系没有好，有些「损」或者梗在我听来要么听不懂，要么就是很粗鲁、没有教养、莫名其妙。我有些朋友也会如此，搞得我很生气。这不只是我对游戏厅内的玩家们，也是对其他我线下或者线上认识的人们的想法。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">18:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQMYJF0WR8GQ3HCMV2NWHXF4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>吃炸猫鱼（感觉比兵鲶听上去有趣点）的时候，想到家里养的小猫鱼。它的崽崽都被室友的天使鱼吃完了。想到天使鱼，也想起前段时间和室友大吵一架，吵着吵着想起大日去世了，开始哭起来，因为发觉无论是谁在接下来的几年都会死，猫鱼会死，蛇鱼会死，杀手螺会死，幸运狗会死，匹克猫会死，咪咪猫会死，我和室友可能会因为意外或者疯子而死，但就是这两条可恶的天使鱼能在家里活二十年。</p><p></p></div><hr><div class="diary-entry">19:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQN32YQ6YJQFZA50MM9MCFB3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前几天学习税法的朋友又过来跟我分享她学到的知识了：众所周知，美国政府有三大头，legislative（国会）、executive（总统那帮人）和 judicial（最高法院）。这么搞是为了互相平衡、避免又发生过去英国那样的事情。那么 IRS 属于哪一方哩？答案是为 executive 工作。有意思的地方在于，实际上制造法律的是 legislative，executive 仅是执行的。对 IRS 来说，它会去理解 legislative 弄出的税法，并根据自己的理解写 tax code、建议等。假设你听了 IRS 的建议，做出了和实际法律不同的东西，那你是可以起诉 IRS 的。至于为什么要多这么一层抽象层，我也不知道，估计也是为了平衡权力吧。</p><p></p></div></details><details data-group="diary_sections"><summary>五月三日</summary><div class="diary-entry">01:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQNQKE3RM5QXPA2Z8MAXJPSB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打工的时候，看着一位外卖员「气势汹汹」进来、「气势汹汹」掏出手机 —— 我忽然意识到，如果他掏出来的是把枪，我会在还未反应过来的时候便吃上一发子弹。</p><p>会想到枪，也有这几天华人一个区发生了枪杀案，而作案过程被一户人家的摄像头清晰录制。不知道是谁上传了这段视频，总之它经过了父母的手机，出现在了我的屏幕上。</p><p>我家里是没有枪的。纽约管枪很严格 —— 但也没法阻止枪击案的发生就是了 —— 我印象中需要办一些证件，最普遍的应该是猎人证。父亲曾经摸过枪，但也仅是摸过而已，我更是只见过枪：探望 Ohio 的叔公时，隔壁邻居向我们展示了它放在车库里的猎枪。印象中很大一把。</p><p>另一段对枪的回忆，是高中时。不记得是哪所学校发生了枪击案，竟引得很多地方都传出当地高中有枪击预告的谣言，也包括我高中的。为了逃课，我那天没有去上学，「枪手」看上去也没有去上学的样子，不过记忆中那之后学校便多了金属检测门，我的迷你信刀也不给带了。</p><p>事情倒也不如过去一位网友所说的「在美国待十年竟从未被枪击过」这么严重，倒不如说这个实在是夸张得不切实际：美国人平均年龄十岁左右是吧！</p><p></p></div><hr><div class="diary-entry">02:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQNTF5AEQ72KT0NBH3M8S6RQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>网上买了把便宜办公椅，组装时发现厂商送了个这。</p><p>这是什么完美形态的六角扳手！</p><p>我要珍藏起来。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KQNTCW0PZ4FMNSRD56WTVNVX.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">02:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQNTWDY03D7S00Q7SWP0JQ6A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>话说这办公椅好宽啊，我要把手臂展开一点才能将两只手都放在把手上。难道是我不会使用办公椅么？</p><p></p></blockquote></div><hr><div class="diary-entry">03:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQNZ7HNJ6EHHB7W0FWMH288E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>购买了 jomm 在 Bandcamp 上的打折包，重新听了遍，虽然没有找到 <em>Astronaut Song</em> 这首歌，估计是太新了，但还是听了很开心。</p><p>主唱 ReadySetFire27，或者说 Aimee，唱歌实在是太好听了。不过我还没有听过她自己的专辑。</p><p>说来之前和朋友一起给 jomm 发了邮件，但对方完全没有回信呢……！</p><p></p></div><hr><div class="diary-entry">11:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQPRRGR7Y8CF3888DW317DPS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>做梦梦到有人问我我跟 cytrogen.com 什么关系，醒来发现没有这回事。</p><p></p><blockquote class="diary-thread-reply">13:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQQ242HQYC05AZRA07TAP4B2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>然后梦到自己在打工，以前认识的人过来吃饭。干着干着突然我们开始打羽毛球，每个人像篮球投篮一样，要把球打进什么地方。我把球打进了篮球框里，自然而然没算分。</p><p></p></blockquote></div><hr><div class="diary-entry">14:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQQ2F62KWSGEAJ4YBNPJ1G9D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天室友带来一盆蜘蛛草，说是猫咪的致幻剂，换句话说是猫大麻。我说我俩没吸过，猫先吸上了。</p><p></p></div><hr><div class="diary-entry">14:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQQ56K6CM68JGDZVNASQ1TMZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打一天苦力工，晚上除了吃饭什么都不想做，还得陪室友玩游戏。去做自己的事情的话，又得被说不珍惜和她一起的时间。烦烦！</p><p>人是无法同时维护人际关系、好好睡觉、做学业或者职业或者兴趣上的事情的。时间不允许，我还多个经济问题。</p><p>第二天又要打工，路上看到街边一个 link 台上抹满了大粪，好烦。</p><p></p></div><hr><div class="diary-entry">15:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQQ6DZVGJ7BMV2XSBRP3V3A8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我想住在有电梯的小区楼，楼下有老人健身器材。每天早上跑下楼，在步行机上荡来荡去。</p><p></p></div></details><details data-group="diary_sections"><summary>五月四日</summary><div class="diary-entry">01:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQR8KMGZN3K52B4EZBKJ6W9F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打工结束小跑回家，结果小腿十分酸痛，还有脚底。打工期间站久了吧，还算可以理解。但满打满算，这个鞋垫也穿了有几年，是不是该换了。现在穿着这双鞋子踩在地上，脚底有很明显的「踩在地面」上的感觉，走久了很难受。</p><p></p></div><hr><div class="diary-entry">01:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQR9EQ8S3A4Z3X00J8DXANXC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>什么时候人们能看到问题后好好回答，而不是阴阳怪气。直接不回答都比莫名其妙冒犯别人好。先前加了个线上群，问了个问题，结果对方答起来不情不愿的，好似我欠他五百块钱，拽得不行，答案还特么没有帮助。</p><p>我不太喜欢 <em>How to Ask the Questions the Smart Way</em>，理由是问答是人们线上互相连接的通道之一，而它将人们推向手册或者互联网。有时候我问问题，更多是想要和对方进一步沟通。如果对方为了阴阳我，给我发了个「如何百度」，我会想要掐死对方的 —— 这自然也有我无法被人理解的小心思的问题。</p><p>不过这个指南完全无用么？当然不是，我仅是「不太喜欢」它而已。我遇到不能礼貌问问题的人也会产生掐死他们的冲动，并希望他们能够好好问问题。换言之，我相信问问题的人需要有礼貌，但不喜欢回答者因此而产出的高傲态度 —— 不想回答可以不回，没有人求你。再简单些，有礼貌的「问」不应该得到冒犯的「答」。</p><p></p></div><hr><div class="diary-entry">01:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQR9XEP29TAMGVPSG34XXSAC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>训练狗狗或者猫咪时，有一种方法是「无视法」。例如狗狗看到你回家，冲上来扑你，你可以轻轻将膝盖往前一顶、将狗狗推下去 —— 不要为此感到难过！这样做可以帮助狗狗不要总是那么兴奋，也可以避免狗狗伤到别人。接着无视狗狗，不要和它有任何眼神上的接触，直到它冷静下来 —— 如果狗狗有提前训练过，自行坐下来也是很值得鼓励的 —— 这时候再奖励、摸摸摸摸摸摸它。整个方法的目的是，让狗狗知道它这么做没有任何正面反馈，从而不再这么做。</p><p>对人也是一样的。开了智的人会明白自己继续这么做没有反馈。至于没开过智的，可以考虑使用人类最灵活的器官。</p><p></p></div><hr><div class="diary-entry">02:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQRCNQZ2VWY2894A1AEN35A9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我新买的桌子，不知道被物流商弄到哪里去了…… 他们说昨天早上送达失败，变相说我当时没有回应他们，但我那会儿在家里啊，怎么可能无法回应他们？</p><p>快把我的桌子给我我的桌子给我桌子给我给我 ——！</p><p></p></div><hr><div class="diary-entry">04:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQRKZAXTP7B2E972NR9P8QCG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友送了我三本她从创价学会那儿搞来的书 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">04:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQRMQ7MBRKEE410RD14H64SS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>好想死…… 高高兴兴换墨水，拿成了新的、没开过、满的墨水瓶，倾斜一下流出来不少，撒得鼠标垫、手上、腿上、衣服上、坐垫上都是……</p><p></p><blockquote class="diary-thread-reply">04:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQRNAP75HCQS8QTQYGZWZ7S3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>用搓澡手套跟十八合一，在身上搓了半天，不见起色。想了想，人要如何时时刻刻开心呢？在适当的时候果断选择放弃！</p><p>实在不行就拿馒头蘸墨水吃吧，还能显得自己颇有文采。</p><p></p></blockquote><blockquote class="diary-thread-reply">05:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQRQ4NM2K1F8FAW5CZRPPR72" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>嗯…… 更难受了。今早走得急没带手环，刚才看了眼手环发现养的 Moosemon 死掉了。</p><p>为什么会死啊 ——！</p><p></p></blockquote></div><hr><div class="diary-entry">14:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQSNSBM6NCV1ESWTS5XN5DYG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>早上起来突然想起之前看过的，平林都礼仪讲座第一期： <a href="https://inv.nadeko.net/watch?v=7y-kv7Ftlf0" rel="nofollow noreferrer noopener" target="_blank">https://inv.nadeko.net/watch?v=7y-kv7Ftlf0</a></p><p>这期视频讲的是当参加正式饭局时，基本的礼仪。对于我的平日用餐情况来说，有些可以借鉴，有些就算了。</p><p>说来日本吃饭都会提供筷架的样子，我这边很少见到提供筷架的餐厅，只能学习如何将一次性筷子套折成筷架，也是我打工期间看到许多外国客人会做的事情。到底是怎么折的呢？我之前在外吃饭想要跟着文字教学学习，但是最后一步不会做。</p><p>最有帮助的应该是这段：用餐期间如何和对方开启话题聊天。她提倡的是「きどにたてかけせし」方案，即接下来这个列表的每个字中，取首音形成的口诀：聊 季节、路况、新闻、旅游、天气、家庭、健康、人际关系、工作。</p><p>平林都也做过其他场合的礼仪教学。目前还没有开始看。</p><p>我在学校和家里根本不会学习到这里，顶多知道筷子不可以插在饭上。和室友认识后才意识到吧唧嘴是不可以的，即嚼东西期间嘴唇跟着牙齿一起开闭。然后便是用刀叉时该如何正确切割食物（锯割）、如何仅用刀叉吃掉盘子上像玉米粒的小东西（用餐刀将玉米粒「赶」到餐叉上）。再就是要避免出现桌上金属乐演唱会。根据她所说，她小时上的贵族学校会刻意学习这些礼仪知识。</p><p></p></div><hr><div class="diary-entry">17:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQT08KRGDXMJYW4YKQFBFQC2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>和专业部门的导员（应该是这么叫？advisory）有个面谈预约，不过早上事情有点多，导致现在要迟到了。步行路上发现有辆冰淇淋车停在旁边。既然都已经迟到了，干脆翘掉、买冰淇淋吃吧…… 不，不可以！</p><p></p></div><hr><div class="diary-entry">17:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQT241JKN0K5N2F8E4ZET0D5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>什么意思你 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3EQQJ0WWJ5EQ79NS9AMS5.png" alt=":neocat_angry:" loading="lazy">​</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KQT23KY97ESMBY0F9581GG1R.png" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">18:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQT2GPE9PX0EJSP5HAN6JZGY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>和 advisor 的面谈很快便结束了。也在意料之内，因为我已经知道学术上我该如何毕业。不过换专业要另学习的课有点太多，或许最好是转校 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3J36QN0WGDJKHG1Q1DK49.png" alt=":neocat_flop_sleep:" loading="lazy">​ 不好好写作业的代价就是这样吧。</p><p>因为结束得早，离下一节课还有半小时之久，打算补补作业，结果发现日语课要求观看的电影居然看不了！改做中文课的作业吧，发现今天的读物打印版我没带过来。额啊 —— 身边的人一直在抖腿，能感受到地板在微微震动……</p><p></p></blockquote></div><hr><div class="diary-entry">21:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQTD293D7NP1V1500VVJ32V1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天一同阅读的是《虚构一九八七》。和往常阅读的短篇小说不同，这部小说本身就很值得说道说道：它是一篇后设小说。在探讨「如何写小说」的同时，也表达了对台湾当时的担忧 —— 解严。</p><p>阅读这些短篇小说的前提条件，便是对中国地理以及历史的熟悉度上么！对我而言实在是个挑战。</p><p></p></div></details><details data-group="diary_sections"><summary>五月五日</summary><div class="diary-entry">00:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQTSR65GG2E2QPW5050J8WRT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这些天重新吃回奶油蘑菇培根意面。shell 吃太多，腻了，这东西煮起来也麻烦。买了五种不同形状的意面。目前 rigatoni 感觉不错，elbows 买太小了不太喜欢，spaghetti…… 这东西还需要说么？cellentani 还没吃。</p><p>我和意面有过一段现在想来实在是太大胆的回忆…… 每晚在共享办公室的水槽旁用水果刀切鸡肉。取出骨头后放到水里微波煮汤，再放上海青进去煮贝壳粉，最后放入鸡肉微波、撒上黑胡椒粉。嗯，那个水槽旁边是放咖啡用的…… 有时候处理鸡肉，还有其他人路过还咖啡杯。</p><p></p></div><hr><div class="diary-entry">03:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQV1ZN2M9PS7MZ4CYN2EX22G" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>哦我的天啊，昨晚莫名其妙又被母亲阴阳一顿。不理会她后今晚又问我知不知道萨提亚，然后发来大量萨提亚的书籍。我扫了眼，全都是家庭治疗相关的。</p><p>家中的书架上摆满了这样的书，什么育儿经、如何做好父母。但我没有感受到家有什么好的变化，只想要过好自己的生活。</p><p>说到底那个家真的还需要我么？</p><p></p><blockquote class="diary-thread-reply">03:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQV4E4SG3H0AQ8YMMQD1399F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说完这种话又开始反省自己作为儿女是不是太冷血了。但现在身为成年人也无法原谅过去父母那么对待还是孩子的我。好像是将自己解离出来，站在旁人的角度去审视我和父母的关系。那我本人又是如何想的呢？不愿意去思考，或者说不敢去思考，才会将自己抽离出来吧。</p><p></p></blockquote></div><hr><div class="diary-entry">04:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQV7XQEC3EHGZ5VX52883XPK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>什么鬼我拿到了完全不知道是谁也根本不觉得自己申请过的公司的面试。</p><p></p></div><hr><div class="diary-entry">06:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQVD0FJAY1EDN46RSJCPR8JE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://www.theregister.com/2026/05/04/uk_online_safety_act_age_checks_subvert/" rel="nofollow noreferrer noopener" target="_blank">https://www.theregister.com/2026/05/04/uk_online_safety_act_age_checks_subvert/</a></p><p>小孩子画假胡子骗过年龄验证 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G3K5695ZWW1XHFBNWEQ8.png" alt=":neocat_devil:" loading="lazy">​ 数据在意料之内，不过画个假胡子就行么？！</p><p></p></div><hr><div class="diary-entry">15:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQWAFVA42NA0YCPHMW51QMT3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚上睡太晚了，看简历和面试的事情。找了一圈依然没有找到「我何时申请过对方岗位」的证明，自然而然也无法得知对方岗位的具体内容。不过扒到了对方公司网站的源代码，得知技术栈是个我没碰过的玩意儿。呃啊…… 讨厌面试，也没做过 technical interview—— 更讨厌 behavioral interview 就是了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JNHF23SBKYB8350F7PKT.png" alt=":neocat_happy_blep:" loading="lazy">​ 简历是我乱写的，我近乎没有看其细节。现在为了面试不得不去背它，还要背些有的没的东西。国内面试貌似都要背「八股文」，具体是什么我不清楚。国外面试要面啥，我不知道。我讨厌他们问我，我比起其他人有什么闪光点：我也不知道啊。</p><p>早上起来睡过头，只能抛下家里没做完的事情、马不停蹄跑去地铁站。路上发现抹满大粪的 link 台虽然还有大粪在上面，但住在一旁的流浪汉不知去向，连带着他的帐篷、椅子都不见了，道路一下宽敞不少。艳丽高照，在昨天的中文课上看到这个成语，很适合用来描述今天的天气。</p><p></p><blockquote class="diary-thread-reply">05-06 23:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQZV5WQ133MDCRKJ18D91P8K" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>悲报：大概率是骗子。</p><p>本来看对方邮件域名就觉得有点奇怪，并不是总公司的企业邮箱地址。跟踪狂能力大发动期间发现直接在浏览器内看，是 Squarespace 的默认页面，也就是说，是在 Google Workspace 注册的域名。</p><p>然后是对方邮件格式写得糟糕、不好看。最开始还能说对方小公司、老板自己发的，错别字就错别字了。但今天发的邮件里，出现了明显伪造的上下文，说他们昨天给我回了信，附件内有考题，要求今儿做完。这封所谓的昨天的邮件从来就没有出现在我的收信箱内，且和真正的上下文隔开、很明显地出现在正文内。这么做是为了营造紧张感吧，我猜测接下来他会发送 malware 给我。</p><p>唉，好伤感情。亏我还高兴一下。继续慢慢找工作……</p><p></p></blockquote></div><hr><div class="diary-entry">17:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQWJBM4D6Z5850FQBYFH3DGZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想用 FairEmail 查看下邮件来着，结果发现本应该被我要求不再弹出的日志窗口弹了出来，明明也没有今天的更新在上面？不过我注意到了作者每次都在窗口顶部写的一段话，大意是每次都有人叫他写新功能，加进去又要被另一批人骂臃肿。最后他不得已，给添加新功能一事加了个硬性规则。</p><p>链接： <a href="https://m66b.github.io/FairEmail/#get-support" rel="nofollow noreferrer noopener" target="_blank">https://m66b.github.io/FairEmail/#get-support</a></p><blockquote><p> 只有当有不止几个人提出要求时，才会考虑进行更改。过去的更改经常导致许多其他人抱怨。</p><p>请求的功能应：</p><ul><li>在应用程序的范围内</li><li>对不止几个人有用</li><li>在应用程序中逻辑且一致地契合</li><li>符合应用程序的理念（注重隐私、注重安全）</li><li>符合通用标准（IMAP、SMTP 等）</li><li>符合核心应用程序质量指南</li></ul></blockquote><blockquote><p>设计的目的是极简主义（没有不必要的菜单、按钮等）和不分散注意力（没有花哨的颜色、动画等）。所有显示的内容都应以某种方式有用，并应仔细定位以便于使用。字体、大小、颜色等应尽可能符合 Material Design。</p><p>每天都有要求以这样或那样的方式改变外观，但问题是这些要求往往相互冲突。为了避免让其他人不高兴，外观上的改变总是需要明确客观地有助于应用程序的可用性才能被考虑。</p><p>如果超过 0.5% 的用户请求某个功能，即实际约 2500 人，则该功能将被认为对大多数人有用。假设只有 10% 的应用程序用户会请求新功能，那么需要大约 250 个请求才能添加新功能。</p></blockquote><p></p></div><hr><div class="diary-entry">18:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQWNPBPR8T30TTCR6W1N140F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打工干活呢，看到冰淇淋车从窗外开过，身上还没有现金，难受死了。</p><p>夏天我要每天都去蜜雪冰城买冰淇淋吃 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G3K5695ZWW1XHFBNWEQ8.png" alt=":neocat_devil:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">18:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQWPPZ28233JHXXX5V853Z2E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想要和朋友泡在电影院里泡一整天，买个大桶焦糖爆米花和大杯饮料，吃吃喝喝看看喜剧片看看恐怖片就是不看恋爱片。吃完了还能续，谁叫我是影院会员 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G3K5695ZWW1XHFBNWEQ8.png" alt=":neocat_devil:" loading="lazy">​</p><p>看完去桌游吧泡着，嫌读规则书麻烦，就和他打一架。或者去公园走走，嫌走路麻烦，就和他打一架。或者去博物馆看看，嫌无聊，就和他打一架…… 最近的想法都这么发散，是怎么回事呢？</p><p>北边上学的朋友这周要回纽约来，可以趁暑假期间多约出来玩 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JNHF23SBKYB8350F7PKT.png" alt=":neocat_happy_blep:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">21:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQWZYBVBBC58T268HWAQCH0N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>记忆里几个月前看到过有人吐槽互联网上竟有「点评独立博客」的网站在。今天想了起来，好奇于是上网搜索一番。找到个还算是点评的，但没有恶意，想必不是这个站。</p><p>不过该站依然收录了大量独立博客网站，可以晚上看上一看了。</p><p></p></div><hr><div class="diary-entry">21:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQX0ZYR10EP8MQT88A7X9VSD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>要考虑一下重新捣鼓自己的 RSS 订阅了。我大抵是不爱看旅游相关的博客文章吧。</p><p></p><blockquote class="diary-thread-reply">05-13 04:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRFRPH3BKGFHMMEKH8BSQK86" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>忽然想通了我的问题在哪里。我给所有的 RSS 链接都添加到了自己的「阅读优先级」分组，例如第一级是只要作者发出来了，我就一定会点进去看的。</p><p>详情可以见这个文章： <a href="https://taxodium.ink/nichijou-6.html#73537C35-2E65-424A-89D3-C1C0F3773D3F" rel="nofollow noreferrer noopener" target="_blank">https://taxodium.ink/nichijou-6.html#73537C35-2E65-424A-89D3-C1C0F3773D3F</a></p><p>但是在我的 RSS 阅读器（Fluent Reader）内，首页显示的不会以这个分组显示。想要在每个分组内翻找文章，需要点击多次二级、三级菜单，很麻烦！</p><p></p></blockquote></div><hr><div class="diary-entry">22:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQX4061MV4EZH8K8052BRSTZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>无聊读文章，忽然记忆回到高中一年，疫情那会儿我上的 earth science 课。那个老师好像叫什么 bee，是个女老师。和她搭档的另一个男老师，名字不记得了，只记得是 D 开头。这俩人都是个活宝，还凑巧碰一起了。</p><p>授课是线上，作业交线上，考试也是线上考。这俩活宝老师想了这么个考试题目：一个他俩自己写的故事，讲的是一伙人跑来什么犄角旮旯的地方，好像是死火山，来研究东西。其中一个叫做 Aquafino 的人，暗恋一位忘了名字的女队员。路上他悄悄拉女队员到一旁说话，想要表白。未曾想这女队员心有所属，或者单纯不喜欢他，跑掉了。Aquafino 抬起头，眼泪从脸颊流到地上…… 请问这滴眼泪滴到了地球的哪个层？</p><p>问题当然不是这么简单的问题啦，我已经不记得原文了。总之考卷整体就是这种感觉。之后 Aquafino 还为爱献身、死了。而整个研究旅游都是另一个女队员的计划，目的是什么不记得了，总之还有当时还未出世的最新代 iPhone 的事情。为了这部新 iPhone，他们要上宇宙找其实没死的 Steve Jobs.</p><p>不得不说这俩老师脑洞是真的大…… 可惜第三季没有出，我当时也没有存档的习惯，许多在高中里弄的有趣东西都没存下来，比如给历史课、健康课做的小动画，中国历史课用 OnScripter 做的文字游戏等等，都没有了记录。</p><p></p></div><hr><div class="diary-entry">23:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQX81N4ZPMGK7G5KZQ56NDTB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://news.kagi.com/s/6erzm8" rel="nofollow noreferrer noopener" target="_blank">https://news.kagi.com/s/6erzm8</a></p><blockquote><p> 开发 Canvas 学习管理系统的教育科技公司 Instructure 确认，在 4 月 30 日宣布服务中断并在 5 月 1 日表示有犯罪威胁者参与后，发生了一起网络安全事件。</p></blockquote><p>妈耶。初看以为是 Canva 可画，后来发现这个 Canvas 之前好像用过。</p><p></p></div><hr><div class="diary-entry">23:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQX8RJCK9KSRAA0HAFX22Y1X" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://news.kagi.com/s/wrgut3" rel="nofollow noreferrer noopener" target="_blank">https://news.kagi.com/s/wrgut3</a></p><blockquote><p> 据报道，杭州市中级人民法院裁定，公司不能仅仅因为人工智能可以更便宜地完成工作而解雇员工。</p></blockquote><p></p></div></details><details data-group="diary_sections"><summary>五月六日</summary><div class="diary-entry">04:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQXRH8WNY79BMQYJ4G1ABK5H" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>买的便宜桌子到了，质量不好说，但总归是能用的。装的期间因为不看说明书，顺便多个线程和父亲吵架，结果屡次装反。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KQXRFX5YTD5R410ZQ5WMFF8Y.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">04:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQXRSK6CDHEHZ21N14R6EK1Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>原本的桌子给室友用了，她之前也抱怨过自己的桌子不够大，尤其是上面有三分之一的位置拿来放鱼缸。再加上她对家具的风格统一性有着执念，我俩原本的桌子正好是同个风格，拼在一起不会看着很怪。</p><p></p></blockquote></div><hr><div class="diary-entry">13:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQYRMXMKDT2ARE2ZKGH0NP5J" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>梦到自己被困在一个游戏里。首先是一张纽约市的地图，政府拆掉大量的老建筑，人们无处可去。我像是蜘蛛侠一样跳来跳去。</p><p>然后我出现在几乎每每都会梦到的恐怖游戏片场。这是一个平平无奇的，郊外的独栋木屋。我要穿过木屋才能离开，但是每达成特定条件，木屋内打不开的门里便会走出一个老太太。她有特别多超能力：透视、隐身、加速…… 总之每次她出来就一定会抓到我。而那个条件是在木屋内发出声音。要想离开，需要走一圈木屋内的所有房间，并且一次做完老太太的每日流程，像是厕所用水、吃饭、接电话啥的，木屋后院的门便会打开。做这些事情难免会发出声音，然后走路没声音的隐形老太太便会在木屋内巡逻。不过后面她会慢慢显形，但也很难很难躲过她的搜查。每次被抓去世，就要一切重来……</p><p>一次重来，我和三个人一同出现在游戏内，像是游戏的正式版。来到木屋，接起门外的电话会听到游戏的大致讲解。这三个人根本不知道老太太的强度，冲进去很快就团灭、重开哩。我后面也尝试了许多不同的躲法，但就是躲不过老太太，这还包含了向老太太求饶、说自己特别憧憬她、别杀自己 —— 不过还是被杀了。一次重来，我死前和她说话，她却说任务明明很简单，只要体验一遍她的日常生活就好了。我没有理解意思，只能看着自己被杀、其他三人也像无头苍蝇般被杀。话说他们还打算强拆院子后门、三人轮流牵制老太太，结果当然是被老太太干掉了。</p><p></p></div><hr><div class="diary-entry">14:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQYW0S5VWAZ786E6BG5V9YPA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Why isn't my Chinese input method working nowwww help help I turned into an American woodcock meep meep meep *dancing</p><p></p><blockquote class="diary-thread-reply">21:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQZKVB8XC676PH88S6X6464E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>查出问题所在了。是昨天为了测试 Fluent Reader 能不能在 Linux 设备上使用时，滚动了更新，导致 lua 版本从 5.4 升级到 5.5。rime 里有段代码，会因为 5.5 的新特性而变成硬性错误，从而导致候选窗口不出现。</p><p></p><blockquote class="diary-thread-reply">21:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQZKZHTC94CYFND3HYCYDDMN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>导致该错误的另一个理由也很有趣…… 我 fork 了 rime-ice 的库，然后在本地使用了自己的 fork。但因为这几个月完全没有使用过 GitHub，也没有滚动更新，所以两个月前上游便做出的更新我完全不知道……</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">14:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQYWE3K5QPAWETHT2KDAHW0V" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>I like Fluent Reader but it's in Electron <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3FZ75C9HA8Q3KRW12YT3F.png" alt=":neocat_cry:" loading="lazy"> I want no chromium inside my devices meep.</p><p></p></div><hr><div class="diary-entry">15:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQYZMQ169JWTTTCE82JTQV7P" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>隔壁不知道什么情况，大早上电钻嘎嘎嘎在用，还在砰砰砰用锤子敲钉子，时不时𠳐𠳐𠳐敲门还是敲墙。应该是 super 吧，但是那间房有段时间没见有人出来，不知道什么时候搬走了，门也一直是虚掩着的。</p><p></p></div><hr><div class="diary-entry">18:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQZ7GJDBZRKBK9Q9WH9EXP8H" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>步行路上，忽然想到《少女歌剧》的 ED 曲，唱了起来：</p><blockquote><p>私 ずっとあなたを見てた</p><p>孤独を置いてきたみたい</p><p>今宵月も笑いかける</p><p>こっちを向いて</p><p>Oh, fly me to the star~~</p></blockquote><p>但是唱不出调来，把歌词唱完室友才听出我在唱什么 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">22:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQZNF1FQQWH6KSBY4WH8N0YJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>下日语课后，泡在图书馆里把中文课先前没读的其中一篇，阿城的《棋王》读完了。脑海里有了些想法，但还未验证，起了想要请教教授的心思。后思索，感觉还未查清楚历史背景，就去要答案不太好，遂放弃。</p><p>回家路上，发现一家公司在他们下班期间给我发了邮件，心情复杂。</p><p></p></div></details><details data-group="diary_sections"><summary>五月七日</summary><div class="diary-entry">05:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR0G49B16E8ZNTDCHY2R95JP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>大晚上从 Instapaper 中取了上个月存的 Stallman report 读。读一半又头大又饿。</p><p>开饭！我要吃牛排！</p><p></p><blockquote class="diary-thread-reply">14:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR1DVYXM6A8N8MX2TX5EQWBJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>越看越服气，贬义意义上。实在是对一个能向儿童说出性暗示发言的人喜欢不上来，整个男性沙文主义集合体。</p><p>报告内频繁指出 Stallman 接受过 MIT 的性方面的道德培训，并认为他是刻意跟现有法律和道德标准对着干。我持保留意见，因为他明显是位对自己的理念相当自豪的人，怕是培训期间就会和主办方吵起来。</p><p></p></blockquote></div><hr><div class="diary-entry">14:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR1BZBJ8468N82HJVAZ57AF2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>要去为一位朋友庆祝生日。按照对方的想法，是想要我陪他一整天。不过…… 如果没有特定的娱乐的话，和他待一整天会很无聊，因为他并没有有趣到可以跟我聊一整天的天。想问他有没有什么地方想去，他也不知道，看样子恐怕是想要宅在家里打电子游戏 —— 不，我不想要那样，会无聊死的。可是户外的娱乐方式，他兴趣也都不大。怎么办哦……</p><p></p></div><hr><div class="diary-entry">16:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR1NQY5RJ46XCM57R7020283" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>应该是抽到了小 otter？可爱可爱。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KR1NQDEER1JS3ENSMR8KCNZV.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">23:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR2CFM5G4KPM91MND2A9M00F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>品鉴《杀戮尖塔》桌游。因为有着电子版的经验，朋友建议直接上手，结果最终打 BOSS 时，发现其血量高到根本打不败的地步。两人蠕动许久，放弃后才发现打错了，二人游戏的话只用打 BOSS 的第二行血量就行，我们一直打的第四行。</p><p></p></div></details><details data-group="diary_sections"><summary>五月八日</summary><div class="diary-entry">02:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR2PRPXGZGWHR581NHW8CY9J" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>久违回家，母亲跟我抱怨这儿，抱怨那儿的，说咪咪猫肚子大了，是不是前段时间不小心放在屋外、怀孕了，又说父亲把她种的花草都拉走丢掉。父亲说是花花草草挡住了他的风水，嫌母亲不赚钱，前几天又发脾气跟我吵架。我回家看，发现咪咪猫住的地方有一整桶干粮，它吃了我带的三文鱼，又去吃干粮，怪不得肚子大、还肥！真是贪吃鬼。</p><p></p></div><hr><div class="diary-entry">03:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR2T8R5AXHQH7VH28R7EKJTP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>妹妹要和我比谁的腿部肌肉厉害。两个人面对面躺在床上、双脚对着彼此的双脚，用力往前推，结果根本推不过她，很快就被打败了……</p><p></p></div><hr><div class="diary-entry">13:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR3XTFPQGXFX2J0KZVKBH9TG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>早上起来，后颈不舒服，还做了奇怪的梦，元素乱七八糟混杂在一起：排泄物、性、鬼魂、同性恋…… 醒来后不太舒服，发现手机没电了、晚上忘记充电。充电后看到室友凌晨两点来电，但当时应该就没有电了，没有收到。起来送幸运狗出去上厕所，下楼找咪咪猫发现昨夜放起来的干粮竟被它找到、打翻。</p><p></p></div><hr><div class="diary-entry">15:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR41Z09FVVWMKZDNS8CT6CQK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>拜访一位亲戚家，他家里有很多小孩子，刚学会走路没多久。电视机基本上一直开着，放小孩子玩玩具的视频，就算这些小孩子根本没有在看。我大致看了眼，发现里面玩玩具的「小孩子」根本不是人，而是一只穿衣服、纸尿裤的猴子。视频里，它会和其他小动物互动，还会操作给小孩子开的玩具车。</p><p></p><blockquote class="diary-thread-reply">15:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR43A3G1FG9WRFK15XF432YF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>他们废弃的泳池里养了一些小龙虾。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KR43916MC1NCKBFTMERECBSF.jpeg" alt="" loading="lazy"></figure></blockquote></div></details><details data-group="diary_sections"><summary>五月九日</summary><div class="diary-entry">06:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR5R0SFZZD4M0TRR1SK3QTZ7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天晚上和一位许久没见的朋友出去玩。这两天聊下来都有些收获吧，不过搞太晚了，现在还在坐着奇怪神经病的车厢里闻着不知道是二手烟还是二手叶子的味道。</p><p>昨天和朋友在吃饭期间聊到 AI，他多多少少算个科技白痴，在用 AI 工具上使用的是免费的 chatbot，高阶的使用方式便是直接使用别人分享的 prompt。平日使用除了做作业，就是和 AI 讨论、构思自己的故事。他好奇，付费 AI 和免费的区别会很大么？以及在写作上，人们可以容忍 AI 工具在什么方面介入、介入多少？</p><p>今天这位朋友则更多和我聊起感情史和性话题。他是一位更容易日久生情的人，经常暗恋朋友暗恋个数年也不表白，因为他比起被拒绝或者无法和对方在一起，更害怕不能和对方做朋友。</p><p>（写到这里那个神经病突然大叫一声，然后跑到车厢外要吻一个下车的女人的手）</p><p></p><blockquote class="diary-thread-reply">15:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR6MEMCTYEZHQGH9DFCE82YB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>回家很快便睡着了，都没写完。</p><p>接着聊到了无性恋、感情中最看重哪一点的话题。我原本以为无性恋是无法对特别性别特征有性冲动，结果他告诉我说只要无法对对方有性冲动就算。总感觉和我最初认识到的案例不太一样…… 当时看的是一篇博客文章，讲到无性恋也分偏男性、女性、中性的无性恋。我平日会产生性幻想，但我不认为那是色情的，而是暴力的。性对我来说，很多时候并不和繁殖、爱挂钩，而是和暴力、支配挂钩。我产生的性幻想，和平日也会产生的暴力幻想、被动死亡幻想没有太大的区别。所以你要说我是不是无性恋，我不清楚，也不太想知道。</p><p>关于感情中人们最倾向于做什么来表达爱意，他给出了五个选项，可以任意排序：</p><ul><li>physical affection：肢体接触，像亲吻、拥抱、贴贴等</li><li> quality time：和对方约会、度过有质量的时间</li><li> gift receiving：送礼物</li><li> acts of service：主动为对方做事情，像是帮忙干活也好</li><li> words of affirmation：夸赞、表扬，口头上的认可</li></ul><p>他认为，男性通常将 physical affection 排序得很高，而女性会将 words of affirmation 排很高。</p><p>我的 tier 是 gift giving 以及 act of service 最低，physical affection 或者 quality time 最高，words of affirmation 排中间。感兴趣的可以自行排排看，或者思考一下自己想要对方做什么、自己想要为对方做什么。</p><p></p><blockquote class="diary-thread-reply">18:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR6Z1G4QPH9QA3QC3K04BKNS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这天本来是和朋友出去玩舞萌 DX 的，结果他被游戏厅的其他玩意儿吸引住，花了好多 tokens 在这些东西上……</p><p>首先是拳击机器，我最多是打个 800 / 9999，很弱了…… 他一连破了三次自己的最高纪录，目前最高是 7300 左右吧（机子的最高纪录是 9000 多，恐怖如斯）。我捏了捏他的手臂肌肉，很硬很明显，他还说每周都会去攀岩，手上长了茧子。问我要不要去时，我连连拒绝，因为我几乎穿不了所有租用的鞋子，也有点恐高。最重要的是，我不怎么运动，攀岩爬不动……！</p><p>其次是游戏厅里的扭蛋机。虽然说是可以抽到电器什么的，但估计是骗人的！他抽了个空的 token 卡出来，好惨；我抽了个好像是长得很像 Hello Kitty 的一有名 IP 里的小狗玩具钢琴；游戏厅里认识的一位朋友看我们在抽，也抽了个派大星玩偶钥匙链出来。这俩玩具我们都不需要，被我转手送给认识的另一位女玩家，而她看我们三个在抽，也跑来抽，结果抽到空卡……</p><p>最后是最坑爹的大头贴 booth。这应该是个很老的机器，滤镜和特效什么的都很少。不过我也是第一次拍，都是猜测〜两人捣鼓都没捣鼓明白，计时便结束，拍下了四张很诡异的大头贴…… 结束后要决定打印多少张，但是软件有问题，并不会显示数字出来，我们乱点后，发现打印了三张出来，token 也被额外扣了两次，靠！更好笑的是，我们的照片打印出来后，上一个拍大头贴的人的照片被推了下来。想必他们拍完，肯定在纳闷为什么没有照片出来吧。</p><p></p><blockquote class="diary-thread-reply">18:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR713S7MEH864MTN16SEG3PD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>接着便是吃饭、聊感情史、巴拉巴拉、回家。回家后日常和室友复盘一天聊到的话题。</p><p>关于无性恋，她也怀疑过我是。她认为人有性欲是很正常的事情，而我好似根本不理解这一点，也无法和她共情。再加上她最近认识了一位无性恋者，能够更加深入了解这个群体。</p><p>朋友曾说过，我至少要性高潮过一次才能确认自己是性冷淡还是无性恋。室友觉得这种话和「没和男人 / 女人做过你怎么知道你是不是异性恋」一样荒诞，如果想的话，可以无限延伸成「没和全世界上的所有人做过爱，你怎么知道你是不是无性恋」。</p><p>根据她的理论，人天生就会有性欲和性冲动，那么一开始没有性欲、性冲动、对性方面上的兴趣便足以指出问题所在。</p><p></p></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">16:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR6QMCPNDVP7PPQPT78DEXHK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>嗓子喉咙该说是干吗，又有点黏黏的，难道我要生病了么？前两天都在出门和朋友玩，这下社交任务完成，整个月都不想要出门了。就算朋友来找我，我也只会去不花钱的图书馆里干活！</p><p></p><blockquote class="diary-thread-reply">05-13 21:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRHN8W3FW9KWQX7ZN03TVGXY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我错了…… 是花粉过敏。怎么回事，我上次有这个问题还是初中的时候。现在眼睛感觉是有数个洋葱在旁边被切开。</p><p></p><blockquote class="diary-thread-reply">05-14 03:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRJ8GNNBQ80TKDAQ17WDNDVS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>太久没有生病过，反而家里除了几年前拔牙用的止痛药外，什么药都没有…… 可恶，为什么平时不多生病一下。</p><p></p><blockquote class="diary-thread-reply">05-14 17:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRKQAKME6HKYJNHGS5NH08E5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚上室友回来，找到了她以前用的过敏药。她顺带也搞来了很多韩国的产品，是老师送的，里面有味道和辛拉面一模一样的酱料，还有芥末蛋黄酱，都挺好吃的。</p><p>过敏药上竟然没有写如何服用、服用多少。我姑且吃了俩，沉沉睡去。早上醒来头昏脑胀，走到卫生间路上还险些摔倒。低血糖了，我想，躺在地上，感受着地板的凉、身体的热，还有冷汗。是不是应该早点请假比较好？今天还要上班呢。躺了会儿后站起来，没有刚才那么难受，收拾收拾后离开了家。</p><p></p><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">死相关。</summary>        <div class="diary-cw-content">05-14 17:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRKT9RQ51204XEHQKRXTQVDK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>时常会有自己死掉的幻想，死法大多都是意外，比如出门路上迎面而来的人拿着把刀捅进我的胸口，印象中前段时间有个新闻便是如此。</p><p>然后我就会开始想，我死之后，人们要如何处理我的死？中文课上阅读《虚构一九八七》时，开头作者便写主人公班上一个同学去世了，要折腾葬礼，学校里的委员会成员也要到场。我死的那一会儿，人们要如何发现我死了？他们会打电话报警吧。报警期间，他们要怎么说？歹徒是什么样的人？救护车会来吗？救护车过来一趟多少钱？我没有 ID 在身上的话，他们要如何得知我的身份？然后他们会先知道我的父母，还是会先知道我的室友？应该是父母会先被通知吧，那我的父母会作何反应？我的葬礼上，因为还没有做文书，所以处理人应该由父母承担，而不是室友。所以他们不会把我的骨灰做成唱片，也不会给我刻《植物大战僵尸》主页面上的墓碑，更不会使用我几年前给自己拍好的遗照，而是用一张丑得要死的照片。那我的东西怎么办呢？室友应该会拿走吧，然后我的信用卡会被停掉、VPS 因为没有了钱也被停掉，我在互联网上的所有一切都会消失。那现实中呢？我的葬礼上，应该只有我根本就没有那么亲近的人会在场。因为过去的争执，室友大概不会出席。</p><p>接着我也会开始幻想，我是这一整个死亡事件中，那个路人…… 我看到了另一个人的死亡瞬间，并拨打电话报警，指认歹徒……</p><p></p></div>      </details></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">16:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR6RXXPFEJHM3NWY7YJ8N21A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前天跟朋友出去的时候，他忽然惊讶道，说他学校出了个瓜，当事人还是个 BiliBili 频道主。内容包含但不限于：以俄罗斯人身份交换到中国的大学、嘲笑该校普通本科生还需要苦读才能进来、自己反而什么都不用做就能交换来；来美国大学上课、做打车服务，背地造谣、对来打车的女性开黄腔。事情曝出来后，他校的微信群炸成一团。被造谣的一方火速做了上百页的吃瓜 PDF。</p><p>题外话，大学竟然有微信群 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3N0PXFDAZ6V7T74MZ1VQD.png" alt=":neocat_notice:" loading="lazy">​ 好像先前有华人校友跟我提起过，但是对那个兴趣不大，一直都没有深入了解。</p><p></p></div></details><details data-group="diary_sections"><summary>五月十日</summary><div class="diary-entry">02:36 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/958917652589641774" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Mimi you are cute cute cute.</p><p> <a href="https://pixelfed.feddit.social/discover/tags/cat?src=hash" title="#cat" class="u-url hashtag" rel="external nofollow noopener">#cat</a></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/0d402c64b-2701fc/vzsQqSSs8PSE/m0RJsBGmfUMtbQotIx7UmjnvoEC7s9HbFi2K3syT.png" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/0d402c64b-2701fc/kKXGiEKHklmc/arLaHuos18LAqB7OBIkUWYFVQozBY2rVDS9kCrtu.png" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/0d402c64b-2701fc/goZ8lOy8MCFI/h9cgbxUtwSinnEae1X2rvQlyXyVULcUTVhLmfBai.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/0d402c64b-2701fc/7rQo1tKwwowl/9E05EPViVM60VT0jOR26X0WIHgR9TBmBPgT8eTNb.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">14:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR93ME390E8N9MJ2E87KF6NA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在工作平台上总是能看到申请者 200+ 的工作，很好奇能拿到面试的人都是什么样的人。</p><p>最简单的方法还是 nepo 啦。就算是求在业人士要内推、推荐信，弄 coffee chat 啥的，已经是大家的标准操作了，还是 nepo 更直接些。</p><p></p></div><hr><div class="diary-entry">14:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR94E9Q695J37MKQPY1ZTQBC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Pretty rare to see a job posting asking for Vue.js experience.</p><p></p></div><hr><div class="diary-entry">14:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR95DS2W6PRK2KCETB127EGV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我好蠢，因为全能本和台式电脑的键盘上，DEL 都在右上角，所以用小十一时，也习惯性摸去右上角，结果那是 Macbook 的开关键…… 我申请还没写完呢！</p><p></p></div><hr><div class="diary-entry">17:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KR9F3AQMFZA8WCE0P6EENTWG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>和朋友聊到 RAG 架构，原因是他所在的公司计划弄一个内部的 AI 应用。先前虽然听到过这些术语，但没有真的了解过，以为和传统机器学习有关，结果发现是 LLM 的万种补丁的其中之一。</p><p>众所周知 LLM 有幻觉问题，这是模型底层的问题，而要想办法让其下游的 AI 产品更好用，只能不停去打补丁。在哪里打呢？应用层打。RAG 架构认为应该先找好所需的资料，再丢给 LLM 处理。一个好参考，但原理真说起来还是不太一样的产品是 Google 的 NotebookLM：用户需要在笔记本内上传资料，而应用会找出输入中有所关联的资料、丢给 LLM。</p><p>朋友认为，在应用层上人们的玩具越来越多，像 OpenClaw、现在的 Hermes，都是这些玩具，改变的仅是 LLM 能读到啥、输出到哪里。最初对抗 LLM 的幻觉问题，用的还是 prompt engineering，现在都不咋能听到这个词儿了。他提出一个假设，如果未来 LLM 的算力足够了，这些补丁是不是都会作废？再加上玩具一直在迭代，花时间和精力研究 RAG、之后又蹦出来个新的架构，那么做它真的值得这些付出么？</p><p>我和另一位创业的朋友聊到这件事，对方认为这完全是公司为了被投资而做这种事情，实际收获肯定也不会有多大。忙倒是肯定是会让员工们忙上一段时间。我对 RAG 架构以及大差不差的应用层玩具们（例如找资料时找到的 agentic RAG）有点兴趣其实，此前一直想要个自己的知识库 —— 唉，也是一直在捣鼓没啥实用价值的玩具。</p><p></p></div><hr><div class="diary-entry">22:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRA1VQZ95THBPTED4A2WVP68" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>试用了一下 <a href="https://github.com/LanRhyme/MicYou" rel="nofollow noreferrer noopener" target="_blank">MicYou</a>，可以通过 Wi-Fi 或者 USB 来让 Android 手机变成电脑的麦克风。</p><p>我只用了 Wi-Fi，声音卡卡的，像是在用很垃圾的麦，但介于它是 Wi-Fi 传输，所以原谅它了。我要用也只是用在学校项目中，「麦很垃圾」说不定能够唤起 reviewer 的同情心，哈哈。</p><p></p><blockquote class="diary-thread-reply">23:47 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRA4KVM685PD47EAZK0WRRFW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>剪辑用到了运行在本地的 <a href="https://github.com/OpenCut-app/OpenCut" rel="nofollow noreferrer noopener" target="_blank">OpenCut</a>。上一次使用视频剪辑软件，应该是一两年前用的 Windows 自带的，名字忘了，好像是 Clip 啥啥。再上一次是高中时下的盗版 Adobe Premium。</p><p>OpenCut 大致使用下来，基础功能没什么问题。没有关键帧的样子，所以不能像 PR 那样整活了 —— 应该说是 PR 太臃肿了吧！</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>五月十一日</summary><div class="diary-entry">04:47 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRANRAB4A9VVQJQKR9MJJB9Z" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>明天是中文课的最后一节课了，为了完成期末作文，连着将先前落下的《很大风》、《逃》、《鬼话》，还有明儿要讨论的《节日》读完了。</p><p>教授选择的读物大致可以分成两个类型：文化革命期间和后来对人们的影响，以及探讨个体在当今社会中的生存状态。我较为有印象的是前者，连带着学习到了许多历史知识。</p><p>《很大风》的角色视角颇为有趣，每节都在切换。用不同人物的视角构建出一个故事世界，阅读时像是在当侦探；《逃》则将历史背景重点放在了抗美援朝那会儿。我外公这个穷渔民也当过逃兵，推算可能是同个时期的。老百姓们都不想要打仗啊……《鬼话》初次阅读，没有读明白，颇有「哲学」的味道，得再细品一遍；《节日》讽刺意味儿很深，孩子们根本不会理解什么是「革命」、什么是「战争」，想要的只是在儿童节上玩乐 —— 其实我都要忘了六月一日是儿童节，仅有共产党国家会过这个节日。</p><p>期末作文要写作家间的不同点和共同点。我没有细看过他们的写作风格，但这应该和绘画时的「画风」相同，我得细品才能总结出什么来。</p><p></p></div><hr><div class="diary-entry">21:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRCFBKY5XVM3N18TK9GD8NHW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>走路上学，今天不用上日语课，晚上也不用等室友下课，所以没有带书包也没有带电脑，胳膊夹了个文件袋就出门了。</p><p>路上在听 Eltrac 前段时间分享的播客 ——</p><p><a href="https://shows.acast.com/lesmotsetleschoses" rel="nofollow noreferrer noopener" target="_blank">https://shows.acast.com/lesmotsetleschoses</a> 中的 VOL37；没用小宇宙的链接是因为浏览器刷新、页面丢失，直接在 Kagi 上搜了播客名「词与物」，出来的第一个结果便是这个 Acast. 先前我在 Fediverse 上自言自语写日记 —— 现在也在自言自语写日记就是了 —— 提及到「无性恋」这个话题，该播客也是和「无性恋」相关。</p><p>起先播客提出了一个我虽然知道，但没能立即应用在性取向上的概念：解构。「谁谁谁是异性恋/同性恋/泛性恋」等语句，实在是过分简化。尽管可以快速让他人理解个体是怎么个状态，但用久了难免会有标签化必定会遇到的问题，即彼此之间的不理解，还有对自身的不理解。播客中使用到了个例子，一个同性恋因为不想和自己的伴侣有性行为，那么他就不是同性恋了么？实际上这件事情，有着对谁有怀有浪漫倾向、性欲、性冲动等不同维度上的 scale；说是 scale，也是为了表明这不单单是 <em>yes or no</em> 这么简单。</p><p>知道了这么些维度，就可以明白在探索「自己到底是谁」这个问题上，不纠结于统一的标签：我完全可以是一个对同性抱有浪漫倾向，但对异性有性冲动的人。这都不冲突。</p><p></p><blockquote class="diary-thread-reply">22:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRCJ5CYQ179PMNSWQMYCVYB2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>上完课，又走路回去。两趟都没忘开始手环的冒险任务，即走两千步打个 BOSS，打到 15 关我的 Metal Garurumon 就能进化成黑色的 Omegamon。</p><p>这趟路上听的是播客的第二阶段，即对霸权的反驳。无论是什么性取向的人，恐都会被「你只是没有遇到对的人」呛得不知道该如何回应。那么人必须要尝试过，才能得知自己对什么没有兴趣么？那就没完没了了：你要尝试过世界上所有的人，或者死前从来没有谈过恋爱或者有过性行为，人们才会去承认你是无性恋。</p><p>播客认为，这是霸权强行定义少数群体。而这不单单会发生在，我在先前的 Fediverse 帖子内提到的「朋友认为我需要至少性高潮过一次才能确认是否是无性恋」、我在博客文章中提到过的「校友认为我没有和男人做过爱所以无法认定我是否是同性恋」，也出现在性少数群体欺压性更少数群体上。例如女同性恋者因为讨厌「直女装姬」，所以出的各种鉴别指南。其中的一些点用另一个角度来看，便是性骚扰，像看指甲长度去辨别一个女的是否是同性恋者。</p><p></p><blockquote class="diary-thread-reply">05-23 14:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSANC2C2NVDD0Y5TP2QBAG3G" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我还没听完这期播客。这些天外出都不会戴耳机，连歌都听得少了许多。内容很感兴趣是真的，但是音质很差，三个人的声音都有很明显的杂杂的、剪辑过的感觉，让我更想要去扒拉文字下来阅读，而不是听。</p><p></p></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>五月十二日</summary><div class="diary-entry">00:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRCTZRB8SGCFWPWPD18ATE85" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>中文课的期末论文，因为有一篇小说太少人分析，导致我写的那篇博客文章可以被我自己引用…… 我终于做到了引用我自己的壮举么！</p><p></p></div><hr><div class="diary-entry">01:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRCY6Z6JRDJ0CKS5D1QXBPWC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>厨房突然出现小飞虫，还在思索哪儿来的，因为我每天都会处理垃圾。最后发现橱柜里的一袋土豆，竟有一颗坏掉、生蛆了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">05:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRDBH8M2VBNEEB3DXCA16D9H" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 我疯了，我在本地挂了个 agent session 每到一个点儿就会分析项目生产环境上有什么问题、本地代码有什么问题，然后整理成邮件发给我。而这么做的原因是，我在打破工，没有那么多时间坐在电脑桌前做审计。相当于我这个人类在干苦活，供了个工具躺我电脑里做我该做的事情中最轻松的活。打工，何时是个头……</p><p></p></div><hr><div class="diary-entry">05:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRDBS3JYECP5JWY12VGRNYV3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>写邮件的时候，发现 Thunderbird 的字体跟颜色我还挺喜欢的。</p><p>好不容易写完要发送时，出现登录错误，而我接着不小心丢弃了草稿邮件…… 幸好还记得邮件内容，快速重写了一封。</p><p></p></div><hr><div class="diary-entry">15:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KREBXVDRWPKDKRK18AZEJP0S" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>法拉盛有一家红色招牌的喜旺德，卖饺子，有点想尝尝看。但是人都在法拉盛了，去常去的面馆吃他们包的手工大饺子也可以。</p><p>随着在美国待的时间越来越长，国内的品牌一一进入美国，我能吃到的过去的味道越来越多，我对中国的记忆也越来越少。不知道是好事还是坏事。</p><p>以下是我的待吃清单：</p><ul><li>炒焖饼</li><li>大烧饼，不是脆的小烧饼</li><li>土渣渣烧饼</li><li>李先生</li><li>忘了什么名儿总之是一碗面，里面的面条用蔬菜上了色，有黄色绿色紫色</li><li>不是小包子，面不是甜的，里面也不是肉馅的大包子，馅儿得是蔬菜跟肉跟粉条。美国甜口烂肉小包子真是泛滥</li><li>羊肉灌汤包，形状很特殊</li></ul><p></p><blockquote class="diary-thread-reply"> 20:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KREX28HHKZC6XHDF92S03YW8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我一定要吐槽一顿甜口的面：甜口的馒头，甜口的包子面，甜口的包子馅儿，走遍纽约只能吃到这些甜口的东西。饺子倒不是甜的，不过就算是甜的也无所谓，我对饺子的包容度在于我愿意拿它蘸番茄酱，还挺好吃。但是我讨厌炸馒头配炼乳，它得蘸孜然才行。</p><p></p></blockquote></div><hr><div class="diary-entry">16:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KREHYYBD4271ECRJ9AZRF2SK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>太好奇了，所以下载了一个玩，结果一进去就要我捏人 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4WKZ05GGYH92R4R30HNR.png" alt=":ottersgottaott28:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">18:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KREQAHEZEYB2ZD8HASRZ7F33" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>唉…… 不是特别想要继续了……</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KREQA1BNSVJ8N27AEM0QM56S.png" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">18:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KREQXZRDAGPAX1MVK0DBZRVA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我这样做的意义是什么呢。想要认识人、和他们产生连接，那明明也有许多已有的选择，去深入了解，没有必要把自己的生日跟其他数据拱手交给一个 app 吧。笔友的话，大不了去找个不跟我同个国家的，地址给对方看也无所谓吧！最大的问题不正是，自己自私得谁都不想了解么！</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">19:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRETF2A9ESZPCA0VZ0J4QN3Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>每天都会检查一遍 RSS 列表，但是没有把它们读完的动力，结果不知不觉积攒了许多。其中有一些打算留到回家坐在电脑桌前再读，不过也留了很久，都不知道自己还有兴趣没有。</p><p></p></div><hr><div class="diary-entry">20:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KREWNFXZA8YJW9GRJ5DDY185" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我：我要杀掉你然后吃掉。</p><p>室友：你 <em>他妈</em> 吃我干什么。</p><p>我：我在网上看到 Disney 优惠，但感觉你过去很快就要嚷嚷工作。</p><p>室友：总感觉很无聊呢。</p><p>我：我想做保安。</p><p>室友：你会被抢劫的吧。</p><p></p></div><hr><div class="diary-entry">21:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRF2K631GBJ5W8ME42S9DHZ9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://news.kagi.com/s/a6syh5" rel="nofollow noreferrer noopener" target="_blank">https://news.kagi.com/s/a6syh5</a></p><blockquote><p>5 月 8 日，在中佛罗里达大学艺术与人文学院以及尼科尔森传播与媒体学院的毕业典礼上，塔维斯托克高管格洛丽亚・考尔菲尔德在表示「人工智能的崛起是下一次工业革命」后，被学生打断并发出嘘声。学生们发出嘘声，有人喊道「人工智能糟透了！」</p></blockquote><p></p></div></details><details data-group="diary_sections"><summary>五月十三日</summary><div class="diary-entry">03:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRFPCRCP8YQ0XPZ26V1PJE6N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Navidrome 还未上线播客订阅功能呢，总觉得自己手持 RSS 链接，却无处可放的感觉好难受。</p><p></p><blockquote class="diary-thread-reply">03:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRFPHVRSKDF1X9G2S70ZD9XR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>话说我发现打工期间经常有碎片化的时间，是不是应该学后厨或者之前的调酒师师傅那样，有事没事就塞个耳机在耳朵里，放东西听。但又觉得长期这么做对注意力不好。</p><p></p></blockquote></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">敏感内容</summary>        <div class="diary-cw-content">04:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRFS88GJQ4A0NJXB0BAT4ZR5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看到这个封面（小黄人新电影的封面），让我想起小时候，估计二三年级的时候，上网找埃及法老王的照片，却从百度图片那儿看到的贴吧里的画集。</p><p>内容是一个虚构的生物，也是封面里这样红色的、像泥巴史莱姆、浑身都是眼睛的东西。它被一群法师创造出来，但连法师们都不知道该怎么处理它。它貌似是不死的，有着很厉害的能力。</p><p>可惜那之后就再也没有找到过。</p><p></p><figure class="diary-media diary-media-sensitive"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KRFS1KPWRKM2SCHJ24RHY13K.png" alt="" loading="lazy"></figure></div>      </details></div><hr><div class="diary-entry">04:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRFTQH5Z11ZXEFZRA5TF33NV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天想用 Emacs 看邮件，但是 mu4e 说 mu 有问题。mu 能有什么问题？排查一番发现，mu 竟然成 orphan 包了，Arch 啥时候不提供啦？然后又是之前的滚动更新，旧的没更新的 mu 想要用旧的 libxapian.so.30 文件，但是后者更新到了 45，mu 也自然而然崩溃了……</p><p>我根本不适合使用 Arch <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">争吵、就业相关。</summary>        <div class="diary-cw-content">07:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRG273EXH52EEG2GSTY8Q1ZF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>吃晚饭期间，和她吵了一架。说是吵架，也只是被单方面训斥了。她认为我找不到工作，更多是自己活该，又因为时常怪罪给市场，所以罪加一等、更让她鄙视了。我承认我有着市场不喜欢的性格，也不喜欢去做市场想要的事情，比如软实力很差，也没有那么喜欢 network、coffee chat 要内推跟各种建议…… 她说我要想办法去做自己不喜欢做的事情，也是我认为没有问题的地方，因为我确实需要停止在舒适区内待着。但她之后的言论让我很不舒服。她认为我的简历很烂，理由是没有从其他公司那儿 hear back. 接着认为我没有好好努力，明明我要同时管学校、赚钱、找工作、她的项目，以及自己的项目的事情。就算现在将学校抽掉，那也依然要在四件事内转来转去。她认为可以将我自己的事情丢掉，因为它们没有价值。可是我不做的话，这么活着有什么意义？还有什么是我在乎的？她甚至说我不能好好兼顾赚钱、找工作、她的项目这三件事，是我的 skill issue，是我太懒惰了 —— 反正你在乎的只有自己的工作，精神支柱也是自己的工作，能花所有精力在一件事上实在是太令人羡慕啦！明明自己就没有经历过我的情况，经济状况有人兜底，买菜用的还都是我的钱！真是讨厌！她回说我只能习惯，就像她过去对我的悲伤与痛苦做的一样。然后她又开始讲起那套理论，认为和她有人际交往的人不能是她瞧不起的，而她现在瞧不起我 —— 真讨厌！</p><p></p></div>      </details></div><hr><div class="diary-entry">10:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRGFB4A4S9VCPGQDNBV11P7V" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>巨龙苏醒，感觉自己棒棒哒，可爱极了。这么早起床，真是太厉害了。我要骑车一路向南，从中城猛猛骑到唐人街，吃早上开门而不是 11 点才开的肠粉！</p><p>怎么只有港式早点早上开门…… 粥…… 好想喝南瓜粥……</p><p></p><blockquote class="diary-thread-reply">11:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRGJWADSN89B3GJ0XD8642NG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>走到楼下的 Citibike 站发现全被别人骑走了…… 只能走到几个街道开外的另一个站。可恶的是，因为起始站变了，我在 Transit 上的 100% protected bike lane 变成了仅有 47% <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">13:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRGPWD72ZJXF28YG11C2M7VH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>哎哟骑了半个小时终于到了…… 路上没有选择听音乐或者播客，就带着耳机听导航。Transit 不好的地方是，它导航不会说「下 X 个路口」或者「下 X 个红绿灯」，而是说「X 米后」—— 我怎么知道 X 米后是哪里啦！幸好没有更丧心病狂，不报给我街道名，否则真要疯掉。这一点上，我更喜欢 Apple Maps，开车也最喜欢它了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JNHF23SBKYB8350F7PKT.png" alt=":neocat_happy_blep:" loading="lazy">​</p><p>停车时，老破旧的 Citibike 站显示说我没停进去，但是车子又被锁上、无法推出来重新停，可恶！我怕这个站待会儿抽风、把车又解锁了，只能站在原地联系客服。过了会儿终于是弄好车子，浪费我十多分钟。</p><p></p><blockquote class="diary-thread-reply">13:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRGQ8YKEWQT1ZNR6MAGKYMHV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>下一个问题便是去哪里吃比较好呢？我对唐人街没那么熟悉。我初次来到这里，电影里那些专门给不懂英语的华人介绍工作的场所几乎都关干净哩。路上除了老人，就是外国人。记忆里几年前有报道说，唐人街房租愈来愈贵，华人们纷纷搬去其他区域，例如日落公园区（俗称「八大道」）、法拉盛等等。唐人街旁边的小意大利也缓缓「侵蚀」过来。</p><p>因为我没有小红书了，也没法看到华人们真实的推荐。所以我决定……Kagi Assistant 快告诉我哪里更推荐吧 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​ 它推荐我来这家银记肠粉店，看装修像是连锁店，因为当地老字号才不会放这么大声的英语流行乐吧！姑且点个肠粉跟港奶，粥什么的之后再考虑。</p><p>现在九点了呢，估计过两个小时，室友才会醒来吧。我走前给她留了个消息，说我因为讨厌她、离家出走了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G3K5695ZWW1XHFBNWEQ8.png" alt=":neocat_devil:" loading="lazy">​ 气死她。</p><p></p><blockquote class="diary-thread-reply">13:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRGQWB2GYFSHG05D1CW93X59" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>港式奶茶是丝袜奶茶么？喝起来有点像。我第一次喝奶茶，应该是 15 年左右，上学路上买的一罐丝袜奶茶。当时觉得这东西真苦耶 —— 所以我连咖啡都喝不了 —— 但又觉得这种味儿，嗯，真不错～然后珍珠奶茶就打爆了市场。</p><p>其实，我不会吃一整块的肠粉…… 毕竟不是老广啦！我和广东人的关联只有，都有「东」这个字而已！我只会慢慢夹碎它，也不知道是不是正确的吃法，可能在店员眼里看来，我和把整个饼丢到羊汤里泡的人没有区别 —— 无所谓啦！</p><p></p></blockquote><blockquote class="diary-thread-reply">14:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRGT9W4B187RDDBRA7274604" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>结果还是打电话给室友，问她要不要吃肠粉，然后带了个给她。再买个三黄走地鸡回家，一整天都充实了许多。</p><p>回家该怎么回家呢？刚吃完饭，本不想骑车回去的。但发现坐地铁也是半个小时，还要花三块钱…… 我是单车超人。</p><p></p><blockquote class="diary-thread-reply">15:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRGZGMZ79J4W85FPBFG29MNF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>出发时家楼下的站没什么车，所以高高兴兴去那儿还车，结果发现全都是车、满了！于是乎，又骑到最初借车的地方，然后苦逼走回家。</p><p>中午太阳好大，我还穿着毛衣，出了一身汗。算了下往返三四十分钟，一看手环竟只显示四千步，我走去学校二十分钟都三千步了。看来这个玩具不能骑车做任务，老老实实走路吧。</p><p></p></blockquote></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">14:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRGVDK7WM3KDFREBCMQJ4BT1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这路是给人骑的吗。</p><p>我的鸡被震掉了，肠粉的酱也飞走了。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KRGVCQAZFF4YVVYMBW69BFZC.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">22:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRHPA8R5KP3G3WP6BF9RQ2F6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>用 Calibre 的 CLI 工具把这本从 PDF 转换成了 KEPUB 格式。看上去好了很多。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KRHNRHDJRC3TS4VH9A8JQMAX.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">05-20 00:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS1B525TQ93J8XZYHH2NE7J1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>意外发现作者和读者就 PDF 格式的问题吵了起来： <a href="https://news.ycombinator.com/item?id=47497661" rel="nofollow noreferrer noopener" target="_blank">https://news.ycombinator.com/item?id=47497661</a></p><p></p></blockquote></div></details><details data-group="diary_sections"><summary> 五月十四日</summary><div class="diary-entry">14:43 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRKF3B0C6N7K0BFZWC3VW5AP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>一位亲戚暑期要把小孩子送到美国夏令营，期间他自己也跑过来旅个游。他是学习机械和电磁的，孩子们也都是学理工的，我想肯定比我硬核许多，因为听上去更偏向物理，而我只是写业务逻辑的。和他在微信上沟通的时候，他问了我许多问题，不知是不是十多年没见、想要单纯了解我。这些问题里就包含着例如我数学好不好、学过算法没等等。我压力山大的原因便是，我确实数学一般，也没学习过算法。我更多将编程视作达成目的的一个手段，但鲜少为了编程而编程，也是我一直以来最大的问题吧。</p><p></p></div><hr><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ5S50F578QGJW9V8Z3MF24N">↩ 续前文</a>        </div> 22:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRM9B7RQH9R8ER5FS0E9WMRR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>3.7 节中提到，除了礼物文化外，黑客们还有「工艺文化」：把代码写得完美再完美，并以此为乐。这也是 Raymond 认为的，成为黑客的最基本要求，即拥有设计完美软件的动力。在工艺文化模型中，黑客做的一切都是为了写完美代码所能得到的快乐。那么它和礼物文化冲突么？那可未必。Raymond 认为，在没有质量评判标准、没有稀缺经济的情况下，依然需要同行的评价来度量软件的质量。这又回到了有关声誉的竞争。</p><p>但是它无法像礼物文化那样解释太多黑客文化里的事情，不过能够解释许多个体的行为。</p><p></p></div><hr><div class="diary-entry">22:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRM9Z3XEJBH3GZQE13A7DY8Z" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打工地儿的后厨人好烦。继上次他说什么没老婆、可以等我长大 —— 谁问你了，—— 之后，又是经常问我他长得帅不、网恋对象长得好看不，或者路过我身边就开始唱「妹妹你坐船头……」，因为店里他们都不知道我名字，只会叫我「小妹」，又或者不经过我同意拍我和其他人的照片。</p><p>结果今天我得知他已经四十多了，是我年龄的一倍往上，比我父母小十岁而已。今儿他暗戳戳问我，我找对象会找四十岁的不，我回不啊。他又加了个条件，说这个男人又帅又有钱，对我还好。我想了下，要是没有暴力倾向的话不就是有了钱的我爹么，回说那跟我没什么关系，年纪大就是年纪大。他接着换了个问法，说六十岁跟七十多岁的人呢？…… 实际上这些问题对我而言根本无所谓，因为我就不喜欢男的，不论是浪漫还是性倾向。但我没有说出来，因为实在是不想陌生人知道太多我的事情……</p><p></p><blockquote class="diary-thread-reply">05-16 15:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRRPQ30SYF58K7XFJ9EQ2QAB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这个后厨今儿不在，替班的是几个尼泊尔人。因为语言不通，他们也不会跟我说话，既不会冒犯到我，也不会让我觉得烦躁。</p><p>之前跟一位朋友吐槽，他说中年男人很 flirty 很常见，尤其是亚洲裔。他打工的店里，就有过中年韩裔男员工广泛性骚扰刚成年的女员工，甚至传其他男员工谣言、说他们背地里辱骂其他女员工是 easy girl.</p><p>如果要工作的话，还是想要和同龄人们一起。平均的边界感会强许多。我自己实在是对付不来觉得自己天大地大、永远都是正确的中年人。</p><p>和室友聊这事儿的时候，她说单身久了、没人要，就会性压抑。最终沉浸在老牛也能吃嫩草的幻想中。唉！</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>五月十五日</summary><div class="diary-entry">01:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRMNP78RZP7TRTK59XYA26XS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>一路从哥大骑到火车站，爬坡我实在是爬不动…… 路上找到许多没吃过的中餐厅，还有被卡在车流里的救护车、警车，以及疑似被撞的外卖单车。说来上次去吃肠粉，路上也看到躺在地上的老人。太危险了，得多注意自己的健康和安全。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KRMNH01VANNPE48R9V0KKJQZ.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">14:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRNZ5BSQFZ1MTE7CZ6V6EY18" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近骑车魔怔了，早上起来决定一路从曼哈顿中城骑到布鲁克林的朋友家，大致在日落公园区。现在骑了一半，刚下桥，好想吐…… 暂且停了车在附近买 Yakult 喝。Yakult 好喝好喝。</p><p></p><blockquote class="diary-thread-reply">14:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRNZYJRNSEZS15QK7YXN1HKK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>路途中路过 NYU 的一个校区，附近看到的海报。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KRNZY2Q2BGXJAS9Z66FZP75Y.jpeg" alt="" loading="lazy"></figure></blockquote><blockquote class="diary-thread-reply">14:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRP1J7JY6E3R4PV5SXCRKPH6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>爬坡不能…… 全是坡，累死了，最后十分钟的爬坡，干脆弃掉单车走上去。当然没有真的弃掉车。</p><p>买 Yakult 期间又看到日本生可乐。之前喝过一次，气泡很足，放了一晚上也有气泡感。</p><p></p><blockquote class="diary-thread-reply">14:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRP1XN0RNGXMA47TRVQX34DW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>接下来就是徒步日记…… 这里是日落公园（Sunset Park），站在一个特殊的点，朝西北方向的大海看去，可以看到自由女神像…… 的像素点。这附近是 <del>臭名昭著的</del> 日落公园区，往西北方向六五大道都是西班牙语使用者，东南方向则是华人区，其中粤语和福州话使用者居多。你在这里能看到舞狮排练、附近居民在运动跟野餐，还有广场舞大妈。秋天来这里坐着很惬意。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KRP1RA4N2VX45Z2HZ2NDXXPP.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">14:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRP2BV3MB4WRPW7AWJAZZKP0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我对这个区的印象是，物欲非常低，主要是年纪大的带小孩子住在这里。几年前喜茶开进来，没过多久在这里开倒闭了，换成了脆脆鸡～</p><p>房租还可以吧。我几年前住在这里，印象里客厅一张床一个月五百，一套房然后跟别人合租一厅一千，三室一厅当二手房东是两千多。水电煤网都不包。现在肯定涨了很多。</p><p></p><blockquote class="diary-thread-reply">16:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRP7ZCEMDZEYEPHDDFY3JQBJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>依旧是和朋友去喝早茶。本来进去想着两个人都不是广东人呢，结果发现店员和客人们也没有哪个是广东人，一瞬间有了奇妙的安心感。菊花茶非常好喝。小费好烦人，以前默认 10% 还算可以，现在默认都在 15 或者 18% 了。</p><p></p><blockquote class="diary-thread-reply">05-16 13:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRRH4JVKWAXHD400GTDCTCZB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>和朋友聊到他专业可以做的工作，翻到和 podcast 相关的。据说美国 podcast 和 radio 很热门、常见。虽然我听的次数很少，但是脑海里会不知不觉开始想象在仿佛永远都走不完的高速公路上，人们一边开着老爷车一边放着 radio 的场景。所以我说挺不错的，可以考虑看看，结果对方嗤之以鼻地说「podcast 听上去很傻逼」。问他为什么这么想，他认为 podcast 的精英主义味道很重，都是白男白女在聊天，无聊死了。除非是在聊很抽象的东西，否则他是不会听的 —— 很明显，他根本没有听过 podcast。</p><p>室友听后，回道：「你这家伙上过学吗！」</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">05-16 15:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRRNDXDTKVAXNHMJ92NAZV65" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我信你个鬼你是淄博人。</p><hr><p>路上看到奇怪的「AI 向阳堂」。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KRRN7M9600PJEYR8YZMASDK9.jpeg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KRRND48YK0TG5711SNQ6CHPS.jpeg" alt="" loading="lazy"></figure></blockquote></blockquote></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>五月十六日</summary><div class="diary-entry">00:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRQ2Z4WGR1XE05Z8K24S6GK4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>升级了一下自己的活页本。本次更新添加了：</p><ul><li>planner 页</li><li>更好的分类</li><li>为了更好的可见性添加了 TODAY 书签</li></ul><p>然后移除了：</p><ul><li>不需要的纸</li></ul><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KRQ2W4YYBJQF0PNK74SC3TA5.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">17:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRRW4YP8VW3R9NS5BRNR8479" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>发觉如果没有专门的读书时间，否则无法读进去教学方面的书籍，因为做不到不记笔记或者实践。最终在书库里找了还没读完的，像故事书一般的《无可羡慕》。我很多电子书是从随想编程那儿薅来的。除了技术相关，就是政治的更多。</p><p></p><blockquote class="diary-thread-reply">17:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRRX280V5V4R079B9G8RZ5Q0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这本书和北朝鲜相关，讲的是作者去采访脱北者后所得到的北朝鲜人民的生活。其中第六章第七章讲到，领袖金日成去世后，北朝鲜民众们痛哭失声。在这一画面之下，却有着许多隐秘的规矩：不哭，就相当于不尊敬金日成、对国家有危害。因此哭不出来的人只能假装自己在哭，也包括什么都不懂的小孩子。渐渐的，「不哭」这个问题变成了「哭的声音没有别人大」。人民班会在国丧期间监视其他人去雕像前祭拜时，哀悼的频率、面部表情，来判断人们是真的悲痛还是假的悲痛。第六章结尾，作者说，当时究竟有多少人是真的为金日成的死而感到哀伤呢？毕竟哭是可以传染的。</p><p></p><blockquote class="diary-thread-reply">17:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRRYPD7A7D4P0MZJR1JTN0V5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>第七章则揭露了北朝鲜当时和性别相关的社会议题，以及医生们的处境。起初宪法中说，民众会得到免费的医疗服务。但随着北朝鲜的经济一路下滑，医院的医疗设备过时也得不到更新，医生们能得到的药品也渐渐没有了。书中采访的金医生，虽厌恶医生们收病人贿赂而开诊，但自己的薪水没了、发配的食物也没了，饥肠辘辘下只能羞愧收下病人们的礼物。</p><p>另一方面，当时北朝鲜的法律中要求所有人晚嫁晚娶，差不多是 26 到 30 岁左右才允许结婚。整个社会环境也要求人们保守，女人要遮住许多部位，也不准骑自行车。街道上看不到人们牵手，长辈们也对年轻情侣们嗤之以鼻。金医生因为是工作狂，导致身边的男人们不敢靠近她。之后她和一位 26 岁的男大学生相处、订了婚。但在结婚当天，人们批评金医生会伤害男方的自尊，因为金医生赚的钱要比对方多得多。最终二人还是离婚了。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">17:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRRXSDXZ15KVW691DP3M6KX9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>以前我还挺讨厌夏天的，觉得很炎热，还有蚊子。现在觉得夏天一来，开始变得有活力了许多，早上起来也不会因为寒冷而躲到被子里。最重要的是现在有室友在身边，蚊子会先咬她。</p><p></p><blockquote class="diary-thread-reply">05-18 13:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRXM9ZRK1A3XWV3FASFFBCCN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我错了。明明我有在频繁收拾垃圾，但垃圾桶里总是能看到小飞虫。往年不好的回忆涌上心头，心中只能怪罪夏天这个温度。</p><p>再就是洗碗时发现一只巨大无比的蚊子，吓得我差点蹦起来。我看到 ゴキブリ 都不会如此害怕……</p><p></p></blockquote></div><hr><div class="diary-entry">22:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRSD8FJ5EWEJ6DX9PJ7JD7XF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想买个挂头上或者眼镜上或者胸前的摄像机，骑行的时候就录下来。有时候路过一些店，不能立即停下来记录。回家要是检查录像带的话，就能记录下来更新 OSM 哩。</p><p></p></div><hr><div class="diary-entry">22:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRSG592CG0A3GYR5K6YV0EFF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>香港的朋友说，从未想到菠萝包里塞一整块黄油竟是香港的特产，这得多腻啊……</p><p>说到香港，小时候还在国内时为数不多的旅游里，就去过香港，还有迪士尼。那是我第一次乘坐地铁，非常干净漂亮，对比纽约市这个烂破铁、还在使用二战的通讯系统的 MTA…… 转乘去迪士尼时，坐的还是专门添加了许多米老鼠元素的地铁。</p><p>来美国后，香港人和广东人会被统一到 <em>Cantonese</em> 这个大群体里，更像是「粤语使用者」。不过室友给了个分辨哪个是广东人、哪个是香港人的方法：香港人喜欢在说话时夹杂英语，例如他们会管草莓叫做「士多碑里」，说父母会说「爹地妈咪」。然后貌似，这个大群体里也会暗地里瞧不起彼此…… 不过他们最瞧不起的，还是另一个大群体 —— <em>Fujianese</em> —— 美国华人们的关系，也很值得探讨探讨呢。</p><p></p></div></details><details data-group="diary_sections"><summary>五月十七日</summary><div class="diary-entry">02:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRSVJ67FKQJF4GEZMVDCAW8K" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今日骑行回家太热了，觉得是头发的问题，又厚又长，洗起来还麻烦。印象里有个远房亲戚是理发大师，所以去问家里人说我想要剪头发。结果妹妹不同意，说我剪了的话会变成 <em>Minions</em> 里的那个短发矮女人…… 于是两个人开始吵架，吵架内容如图。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KRSVHMDQVYW9VY0A865EXP7W.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">02:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRSVPG9JM33KJY4J1SFY9BWH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>小山上拍到了不错的夜景…… 应该吧，手机是灰色的看不出来拍了个啥。</p><p>这路边有垃圾桶。路过时竟然有肥硕的浣熊蹦出来，吓我一跳。初见还以为是野猫，很快反应过来不对啊，怎么会有野猫这么大、这么肥。黑暗中看到它尾巴的轮廓，哦～原来是浣熊。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KRSVK7RPENWJ7754QMH767AH.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">02:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRSVRW1XSG9EV9QT35VKM2Z8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>电脑上一看怎么拍得像白天，明明都晚上九点多了，黑蒙蒙的。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">13:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRV0WD1JK9XV2QA72SB8R1A5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今日依旧做梦梦到恐怖桥段，怀疑是平日看恐怖游戏实况主看太多了。梦到我初中的朋友过生日，准备在恐怖题材的密室逃脱里过。城镇是一套我从没去过的，隔壁是一家很大的 Popeyes. 说是密室逃脱鬼屋，但我在来之前，就已经被告知哪里会有高能…… 后面还因为有事，没有体验完便走了。再之后见到他们，他们吐槽我的另一位朋友看上去很俗气，为什么要和他玩、不和自己玩。我喊道，「我就是喜欢和漂亮女生待在一起！」</p><p></p></div><hr><div class="diary-entry">13:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRV1G8GRBY057FV1AK7H8SJC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>使用 FairEmail 期间，时常会在邮件里看到「追踪用途的图像」。了解之后得知，这是一个 1x1 像素点，人眼很难捕捉到。当收件人打开这封邮件时，邮件客户端会自动请求并加载图像，从而导致服务器收到图像请求、记录下相关的数据。这在营销邮件内很常见。项目中我会用到 MailTrap 给客户发送 Newsletter，其中 dashboard 上就会有「用户点开了多少次」。先前很好奇是如何做到的，现在想必正是这个小小的像素点吧。</p><p>建议让邮件客户端不要自动显示图片。一旦被追踪久了，也会被企业建立起用户画像。又或者说，抛弃 HTML 邮件、改用纯文本吧！</p><p></p></div><hr><div class="diary-entry">13:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRV2SA6D8V0X5HFNHABA67WG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>其实我一直在研究，如何在 Macbook 上安装 NixOS…… 因为它使用的频率很低，也没有什么重要数据在上面，很适合用来研究各式各样的 Linux 发行版…… 才怪！因为是 2013 年的老设备，网卡驱动得折腾很久。之前装 EndeavourOS，还是启动环境里有安装脚本，正好有它的网卡驱动。</p><p>目前是尝试了先在主力机上构建了个自己的 NixOS iso 包，但卡在了 <code>wpa_supplicant</code> 有问题。</p><p></p><blockquote class="diary-thread-reply">05-19 03:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRZ5F58BJAFQAWWPCMY1D8S4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>买了网线转 USB 口，可算是安装好了……minimal。因为太 mini，所以底下的状态栏都没设置好，还报错了。现在除了能唤起终端，什么都做不到。总之之后慢慢搭建起来吧。</p><p>奇怪的是，我进入桌面后用 <code>nmcli</code>，直接就成功地连接上了 Wi-Fi。那我先前在 boot 环境里一直捣鼓 <code>wpa_supplicant</code> 是在……？</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KRZ56R79CV0H27AMPXBVSZ6M.jpeg" alt="" loading="lazy"></figure></blockquote></div><hr><div class="diary-entry">16:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRVC6V7CNWA5MRF0F73X4V71" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我…… 再也不乱吃东西了…… 脑子灵光一闪，想到冰箱里有些可能过期，或者快过期的东西，例如放了不知道多久的 pita，还有 greek yogurt…… 又发现厨房里落了个 sriracha 酱，所以我把 pita 丢到了空气炸锅里热、蘸 sriracha 吃，同时在吃 greek yogurt. 可能五分钟不到吧，现在我肚子开始隐隐作痛……</p><p></p><blockquote class="diary-thread-reply">05-18 03:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRWJ53FAZ3ZBTJWVJC6DHA91" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最后这个 greek yogurt 拿来做调料品了。晚上吃了室友自制的椰子鸡，说是按照膳食指南，人只需要吃手掌大小的肉。结果吃了鸡肉，吃了皇帝菜，吃了山东拉面（这到底是……？来自山东人的不解），肚子还是饿饿的感觉…… 之前从室友老师那儿拿了几盒冷冻海鲜，丢到空气炸锅里弄了点炸虾。家里没有塔塔酱，让室友帮我用 greek yogurt 还有甜辣酱啥的调了个特制酱料出来，还有前段时间从家里那儿顺来的可乐。真不错～</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>五月十八日</summary><div class="diary-entry">01:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRWBM244SHS5WNTHJ1TW3MMV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我的耳机是 Soundcore 的 Liberty 4 NC。黑色的盒子很适合盘在手上当球玩，用了几年下来也挺满意的，音质嘛…… 没有使用过好的有线耳机的话估计是不会挑剔了。这几天想要听的歌曲风格变了，想起来它安装 firmware 用的 app 里有切换声音效果的功能，其实就是调均衡的功能。今儿久违打开了这个 app，结果正中间是个大大的 <em>Chat with Anka</em> ——AKA LLM!</p><p>内心深处酝酿出了复杂的感情……</p><p></p></div><hr><div class="diary-entry">03:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRWGHWG41DF785R73ESAZ66C" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Earth, Wind &amp; Fire 的 <em>September</em> 实在是太喜欢了。过去听过这首经典老歌，这段时间因为在听 Ginger Root 专门收录翻唱的专辑 <em>Toaster_music</em>，又重新听到了 <em>September</em>. Ginger Root 翻唱的版本，更 chill 一些。听了原作者们的 HD 版本，惊讶于原来原版如此有活力、欢乐，听起来很开心，让自己也手舞足蹈了起来。</p><p>于是我打算去购买这首歌。Bandcamp 上我买的是 Bootz &amp; Kutz 的，不过听的时候才发现并不是 HD 这个版本的。之后我跑到 Qobuz、注册了 Qobuz 账户、下载了 Qobuz Downloader 才买到 FLAC 格式的 HD 版本 <em>September</em>. 开心开心。</p><p></p></div><hr><div class="diary-entry">03:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRWJT3CYCM7Z0A3BJ531F1Q6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>买了一幅老虎在渡河的画，可爱。</p><p>明天 silent hour 过了再钉到墙上去。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KRWJSBM04ADEGZHGK5WE8WCJ.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">17:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRY3NTHXBF12DAEQ55A75F8V" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://www.bilibili.com/video/BV1ThRyBGEh6" rel="nofollow noreferrer noopener" target="_blank">https://www.bilibili.com/video/BV1ThRyBGEh6</a></p><p>r-906 去年圣诞节的《シリーテラー》（Silly Terror），和 MV 配合得很棒，尤其是中途摇晃的镜头，配合 hardbass 的紧张感。</p><p>恐惧、逃跑、放弃。最后打开包，发现里面是圣诞礼物，苦笑道自己实在是太蠢了。</p><p>整首歌的寓意很值得被挖掘。而我明显就是没有挖明白的~ 总之就来听听 r-906 调的 IA 吧。</p><p></p></div><hr><div class="diary-entry">21:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRYED1G7FNQKE4EVBCACGAEA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天和室友骑车去唐人街买三黄鸡。三黄鸡太好吃了，仅是鸡胸肉就好吃得让人流口水。不过室友的膳食指南，根本满足不了我，所以到了地方我又跑到 Paris Baguette 吃了点，然后跑到隔壁的饼店里买了大杯的西瓜汁。</p><p>Paris Baguette 的奶油包，我嫌它不够凉，然后 4 美元的个头，总感觉不够吃，几口干掉了。小时候印象里家附近有个面包店，里面有叫作「毛毛虫」的超长奶油包，小时候吃一个特别开心。还可以跟小伙伴们一起分享。</p><p>因为室友好奇，我们也买了草莓味的 mochi donut，长得很像日本的那个猎奇吉祥物。我没吃出 mochi 的感觉，但是吃出这 donut，贼 <em>他妈</em> 油啊。一口下去，别说草莓味了，上面洒的白色糖粉我都吃不出来，只能吃出 donut 里面油的感觉。呸 ——！不过最后还是吃完了，因为肚子饿。</p><p>西瓜汁是最棒的。</p><p></p><blockquote class="diary-thread-reply">21:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRYEQP712S76MDEG6MBXGZ88" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>话说 Paris Baguette 的 baguette（法棍），怎么在店铺的角落躺着。差不多也是 4 美元一根，但看上去没有 Wholefoods 的 5 美元法棍有食欲。原来 Paris Baguette 主卖的并不是 baguette 么……！</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>五月十九日</summary><div class="diary-entry">00:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KRYVBTJ6VWKWAJT5E917MA62" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>找到了小时候玩的游戏，名字是 <em>Oggy Moshi</em>。以现在的角度来看，背景的像素图画得感觉还不错哎。Oggy 看上去肥肥的很萌，蟑螂们太坏了。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KRYV9JH899SK3H65338T767E.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">14:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS095AYR20YJQ10CWDW4S8PD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://gizmodo.com/the-worst-leak-that-ive-witnessed-u-s-cybersecurity-agency-leaves-its-digital-keys-out-in-public-on-github-2000760330" rel="nofollow noreferrer noopener" target="_blank">https://gizmodo.com/the-worst-leak-that-ive-witnessed-u-s-cybersecurity-agency-leaves-its-digital-keys-out-in-public-on-GitHub-2000760330</a></p><p>好诡异 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">14:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS0A7SRVWT3C3GR2RHMMV6F0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 想要下载影视资源来着，但是对这方面不了解，跑到 Amazon 的 Prime Video 买了个电影，结果发现下载不了，只是给了我在它平台上观看的权力。早知道这样我就租用了，也是没有提前了解清楚的锅。</p><p>简单搜索发现没有类似于音乐领域 Bandcamp 或者类似平台的，购买就能随意下载的影视资源平台。虽然我也有相关平台的会员啦，但想要下载到 U 盘里然后塞到前不久从家里顺来的投影仪里看。实在不行，笔记本电脑投影也可以，就是上次测试时不知为何没有成功，很是沮丧。</p><p></p></div><hr><div class="diary-entry">15:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS0CM1PP554R4RS5KHJG0F58" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天，36 度的高温，好热，但还是要出来打工。这里管事的大妈，不喜欢开空调，也不知道为什么…… 上次来，看到客人大汗淋漓，是真的满身都是汗，啪嗒啪嗒往下流。我出汗量不大，是件不好的事情，意味着排毒少。</p><p>眼镜是可以挡阳光的，但是脸怎么挡呢？在考虑买顶帽子。鸭舌帽压头皮，大帽子没怎么戴过，竹帽…… 戴上的话就会被人说 <em>your phone linging your phone linging</em> 吧。</p><p></p></div><hr><div class="diary-entry">19:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS0W5RRS3PZM1M59XR8R3QTS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>唉，年少无知 —— 虽然也就过了一年不到吧 —— 把自己域名贴在了各种社交媒体上。有些认识的校友都知道我有个人网站，不过幸好他们大多数都没有读博客的习惯…… 现在实在是不想要他们知道我的另一面。更可恶的是，室友竟然会在向认识的人（背着我）介绍我时，都会拉出来我的网站……！也就是说，我现实中认识的人里，知道我有博客、Fediverse 账户的人比我想象中的还要多……！这种感觉糟透了！</p><p></p></div></details><details data-group="diary_sections"><summary>五月二十日</summary><div class="diary-entry">15:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS316TK0TNS7MFMQKJHNHK4C" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>来 career center 转…… 如果能得到一些新的信息就好了。其实自己也知道该做什么，模糊意义上，但详细的就不清楚。例如我知道要和业内人士打好关系、要内推，但是如何打好关系？我要如何和我根本不感兴趣的人关系好？软实力真的好烦。</p><p></p><blockquote class="diary-thread-reply">18:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS397M6137ASXNT8Q3CQR3N5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>ATS 害人不浅 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 又得默默修改简历了。市场的竞争激烈，简历第一轮先用 ATS 扫关键词并不少见。为此，学校还弄了个新系统，可以上传简历，交给「万能」的 AI 工具模拟这个流程，反正公司用 AI 工具扫简历的案例也不少见吧。</p><p>最后聊到的是，万恶的，内推文化。我对此有着很糟糕的印象，因为它说难听点就是「走后门」。然而在美国，已经成为一种文化，坐在我讨厌的文化中的 No. 3，仅次于酒桌和小费吧。为什么它是一种文化呢？因为所有人都默认这么做是好的，并且都在做。这就导致内推泛滥，市场要改从简历里找人，到有内推的简历里找人。它的好处是业内人士能够更好地了解潜在的候选人。坏处是，在人脉方面上不平等。人们会愈来愈倾向于推荐和自己背景相似、和自己有过往的人 —— 哦天哪，<em>nepotism</em>！</p><p>以上都是调侃。要做还是要做的。怎么做？你要和业内人士 coffee chat、面试他们、从他们口中扒出行业内你不知道的事情，以及最重要的，内推。如何找呢？使用最能泄漏个人信息的不自由软件，LinkedIn 啦。你可以搜索你感兴趣的公司，随便找个感兴趣岗位的人，问他们有没有 15 分钟空闲时间出来 coffee chat。就算对这个人不感兴趣也没有关系，你完全可以为了人脉而靠近他们，并得到更多的人脉。接着便是循环……</p><p></p><blockquote class="diary-thread-reply">18:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS3AJD6KYYQ723SVEA2BCS94" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>另一件事是刚找完 career center，就被家里人因为专业的事情轰了一顿 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ496Q8A4XAZF9TK81RAX7.png" alt=":ottersgottaott10:" loading="lazy">​ 起因是母亲朋友圈里一个都不知道算不算朋友的朋友，说她女儿要去哪里实习，问有没有人能担任下司机。母亲拿着截图过来问我为什么还没有找实习。项目的事情一直都瞒着他们，实在是不想说，再加上也不够我自己盈利 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 实习什么的，本来几年前就找到了，但是因为家里的不可抗力，导致没去成，也是很倒霉了…… 现在要拿到面试，只能靠骗，指说大空话假装自己什么都会。内推如我先前说过的，也很重要。不过母亲不信这个「邪」，说内推哪有那么常见 —— 这种事情你问数据去吧！</p><p>还有需要考虑的是，自己到底想要做什么。软的需求总觉得要死要活的，也被很多企业拿 AI 工具一脚踢死 —— 不想承认的是，虽然 AI 工具干这些活很像猪头，但是多数企业都很爱猪头，可能是同类之间的吸引吧（这是玩笑）。难道要走硬么？身边没有这个资源，也是我从未探索过的领域。</p><p></p><blockquote class="diary-thread-reply">05-21 01:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS429V97NGS2J8H34200DHZM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>母亲给我发了我校基督教社团的图片，叫我去参加并拿「内推」。原来是在这儿等着我 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 接着归结于是我没能「好好走出去」—— 爱咋样咋样吧。</p><p></p><blockquote class="diary-thread-reply">05-24 15:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSDBAWK06TV3G9PD7BE1J9X4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我觉得特别好笑的是，明明家里（直系亲属）都是做蓝领工人的，但因为亲戚里有做会计的，母亲就能毫不在意地和他人说「因为我们家族是做会计的，所以希望她（我）也可以去学做会计」。</p><p>接着在没有得到我许可的情况下和一位开会计所的远房亲戚（远到我从未见过，对方也不知道我）预约打电话。电话内容倒是挺愉快，从企业的角度来看待现在的 candidate 们。</p><p>他认为，要成为「泛才」，或者说「混合型人才」，而不是「专才」，因为现在的企业不需要专才。专才在现在的企业只能把一件事做好，最多是一颗很厉害的螺丝钉，但泛才能够提出一系列解决方案。这也需要跨专业、学科学习东西。因为在纽约市，所以 fintech 的路子还是特别热门的，再就是 healthcare + tech。</p><p>不过现在 AI 工具像大卡车一样横冲直撞，但没有对会计领域产生太大影响。该说真不愧是美国铁饭碗之一么（另一个是医院里的），所需的 tech 也不多，总不能搞什么 AI 自动报税吧…… 不会吧……！但如果去 fintech，不仅所需的 tech 方面会更多，搞上 AI 工具自动化的需求也会变多 —— 不过我的观点是，AI 工具做自动化并不会得出更好的效果…… 见 <a href="https://blog.cytrogen.icu/posts/5586.html#%E4%B8%BA%E4%BB%80%E4%B9%88-atm-%E6%B2%A1%E6%9C%89%E5%8F%96%E4%BB%A3%E9%93%B6%E8%A1%8C%E6%9F%9C%E5%91%98-%E8%80%8C-iphone-%E5%8D%B4%E5%81%9A%E5%88%B0%E4%BA%86" rel="nofollow noreferrer noopener" target="_blank">我月刊里的内容</a>。但单从 fintech 的角度去想，就必须得和讨厌的数据打交道了。分析已有的用户数据、提炼成一种算法、自动给新来用户计算出解决方案…… 大致是这样的流程么？我没有在 fintech 里工作就是了。</p><p>我现在所在工作的项目中，和对方的公司的路子很相似，可惜用户基数过少，也不需要我做什么，每次更多是做维护以及搞业务逻辑。在这方面上，我就只是一颗螺丝钉…… 换了专业后，要学习的非 tech 相关的知识会变多很多。如果我真是什么聪明的家伙儿的话，应该可以学会吧。</p><p></p><blockquote class="diary-thread-reply">05-24 16:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSDC7TQMNAQ4R4EPGMW2PS3Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不过这么想我总会有沮丧的感觉，即「其实我并不是一个特别擅长 tech 方面事情的人」。我渐渐发觉自己没有那么喜欢编程了，就像刚开始学习编程时，发现自己没有那么喜欢绘画了…… 这种感觉令人不安。计算机爱玩还是爱玩，不过爱玩不定能赚钱，而我很怕没有钱。</p><p>另一点是自己还是个又傲慢又刻薄的坏家伙儿。其中傲慢出自于早期学习计算机时，周遭环境带来的赞赏 —— 现在看来，也只是我还未深入计算机的领域内，被各种根本学不进去的人夸赞了而已 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ27T1ZWSPFCZM3DBNHNWSB.png" alt=":blobcatgooglyshrug:" loading="lazy">​ 自己离了舒适圈，真去找工作了，结果面试都拿不到，更不舒服了。</p><p>目前换了策略，以更慢的速度投递简历，仅投了 50 多份 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​ 何时才能投到千来份、获得「亚洲人可以辱骂市场」的资格啊。</p><p></p></blockquote></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">18:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS3BM4VVQMJKT967V6VPQS0Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://blog.prayhand13013.top/20260521T014604--%E7%BF%BB%E8%AF%91-bitwarden%E7%9A%84%E9%9D%99%E9%BB%98%E9%9D%A9%E6%96%B0__blog.html" rel="nofollow noreferrer noopener" target="_blank">https://blog.prayhand13013.top/20260521T014604--%E7%BF%BB%E8%AF%91-bitwarden%E7%9A%84%E9%9D%99%E9%BB%98%E9%9D%A9%E6%96%B0__blog.html</a></p><p>之前仅简单想过，但感觉也该考虑考虑是否自建密码管理服务了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">18:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS3BWJBN8DZ34S4ZH9S4XYGN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>每次一打开 Kagi News 就能看到这种，不想要一个个 RE 过去因为反应都大差不差的新闻。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KS3BVHMTGT284K80ZMPKNGX8.png" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>五月二十一日</summary><div class="diary-entry">06:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS4KD6032VMG279J8XVE1G71" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>电影在影院看完一次，为了写影评在家又看了一次，晚上室友回来好奇又又看了一次。</p><p></p></div><hr><div class="diary-entry">22:25 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS6A8V0QCNVDM73QNEX5BZHK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><em>Self Deployment</em> 阅读笔记相关嘟串。</p><p>作者第一章便给出建议的好习惯，即阅读文档，因为文档是除了源代码外，我们能了解代码的最佳方式 —— 不过现在 AI 工具泛滥的情况下，这种话也实在不太好说呢。</p><p>除此之外，还有个建议的习惯，即从 AI 工具或者 Stack Overflow 那儿获取到的命令或者代码，都建议拿去文档里搜一下，看看如何使用、其他参数都是什么。</p><p></p></div></details><details data-group="diary_sections"><summary>五月二十二日</summary><div class="diary-entry">02:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS6PTGHCSG4VP4HEK3PRVTAW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>自信骑回家，本来以为可以在目标时间内骑完，结果超了三分钟…… 上次超了两分钟，上上上次超了一分钟。怎么越骑越超时了。</p><p></p></div><hr><div class="diary-entry">02:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS6RH4TG7PP7RH7CTB0RJWHE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>家里怎么又断水又断网的…… 我还想煮 pasta 吃呢。</p><p></p></div><hr><div class="diary-entry">16:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS8988VCEX0RMFYB1PXAHWTM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近有点怠惰…… 早上起来看关注的频道主实况玩恐怖游戏，结果几小时过去了什么也没有做，肚子还饿了。接着一边看一边做饭，想要有活力点但是外面阴阴的，还一直下雨。</p><p></p></div><hr><div class="diary-entry">16:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS89GTN305QXCECAYYTN54DD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这些天一直想要吐槽，这台 Windows 电脑用起来好慢好慢。检查了一下，发现是 WSL 和 Node.js 运行时在疯狂吃内存。但 WSL 是我 Docker 开启时必须要开的。然后是现在 Task Manager 也无法开启。很诡异了。</p><p>好想把系统刷掉…… 这台电脑里的东西太臃肿、无从下手，我不知道该如何管理是好。</p><p></p></div></details><details data-group="diary_sections"><summary>五月二十三日</summary><div class="diary-entry">07:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KS9TBC3WRNJGGN5ZXE33VE91" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想要为自己的悲伤找出承担责任的人。想了半天，决定让 WeWork 成为这个人。谁让它决定在一天播放 Ginger Root 的 <em>Loreta</em>，并被室友听到、用 iPhone 的那个微软件捕捉到、推荐给我。我这个杀千刀的，还下载了他的 <em>Toaster_music</em> 专辑，听到了翻唱的 <em>September</em>。好奇心驱使下，在 YouTube 上找到 HD 版本的原唱、在 BiliBili 看到大量跟这部电影相关的评论。最终我决定跑到 Amazon 上购买了电影（的观看权），于今天凌晨一点一边吃剩饭一边和室友看。</p><p></p></div><hr><div class="diary-entry">14:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSAJGZSMD9939H5BWND9K32D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天刷了奖杯，可算是进化了。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KSAJEZ86RZMYW0GEXFD2N2HT.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">18:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSB2AKHWPFBQDNZH5FGJG2SS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>突然发现这些天吃饭，吃完都会有「没吃饱」、「不够满足」的感觉。这难道象征了，人生中的二次成长……！因为我现在的身体，和初中时区别不大：身高一样，体重一样，长相也一样。如果可以的话，想再长高一点。</p><p></p></div><hr><div class="diary-entry">23:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSBH84Z7E0GK8E7EZ2BW8QR2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>下了很大的雨，却还是要坐两小时的车回父母家。唉，到底图什么呢，回去也没什么事情做。本来想要骑车在郊外转转，但是这么大的雨，岂不是只能在家里待着，也不能遛狗。我会在那里无聊到腐烂的 ——！</p><p></p></div></details><details data-group="diary_sections"><summary>五月二十四日</summary><div class="diary-entry">01:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSBR1G916947VA00WJN2X1WK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://meshtastic.org/" rel="nofollow noreferrer noopener" target="_blank">https://meshtastic.org/</a></p><p>有点想玩哎…… 玩玩玩，玩心太重了我。</p><p>能用这个代替掉手机么？手机一直揣身上就是怕错过重要的消息。但是手机本身的功能又七彩缤纷、五颜六色、五花八门、班门弄斧、无中生有、暗度陈仓…… 如果能给自己设置点枷锁，生活会更愉快些也说不定 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKPG9JXEBDFYC9RZH0AC9PB.png" alt=":cozy_otter_face_rub03:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">02:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSBWGE4X89H2KXF91GHA8QZE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我受够了各种莫名其妙的街道名，还有知道了地址名也找不过来的人们。从今往后给别人发地址直接发经纬度、plus code。我就不信了。</p><p></p></div><hr><div class="diary-entry">03:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSBYYQ47RR9N7Y3XBTAFJDW6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>回家发现父亲在看 AI 生成的国产修仙 3D 动漫。该说是「进化」得特别快速么……</p><p></p></div><hr><div class="diary-entry">20:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSDVPZ95G9SFARVMX2Z0MRMN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3NQGXNH3PXHGGGBS0NVB8.png" alt=":neocat_phone:" loading="lazy">​ 帮亲戚设置他新买的 iPhone 17，发现自己太久没有碰 iPhone 了，对它新的充电线的材质，以及手机背部的触感有些好感。</p><p>静音调整用的按钮怎么从开关变成单个按钮了？设置时发现还能用来自定义功能。</p><p>相机按钮总感觉怪怪的……</p><p>不得不提现在手机设置时方便好多，还能自动发现附近的手机。</p><p></p></div><hr><div class="diary-entry">20:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSDWE5WYRKDSSMZXBYPFMDRQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>为什么会有人一边开车一边刷短视频…… 我生气地叫母亲关掉，她也只是调小了音量。因为接上了车的蓝牙，短视频里那些听到耳朵长出茧子的破声音，全都从车内的各个角落跑出来，污染我的耳道。</p><p></p></div><hr><div class="diary-entry">21:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSDWY23D3D7PQ4AEHB4T1SQT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>每次回家，尤其是父亲在家的时候，就要听父母双方吵架。不得不说，父亲的脾气越来越糟糕，素质也越来越差。有时候明明什么事情也没有发生，他也会对着空气大骂 <em>fuck you!</em> 和母亲吵架，也会骂例如「死全家」的话。吵架多了，双方一要开始说话，便会互相攻击。我和他们二人关系都谈不上好，也不想管这些事情……</p><p></p></div></details><details data-group="diary_sections"><summary> 五月二十五日</summary><div class="diary-entry">03:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSEJAB5MZ0CQJK2B3D6AHK8Y" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>耳机忘在父母家了…… 离开前，母亲想要我再留一晚上。可是，就算我待在那里，又能做什么呢？大家只是不停地在刷手机、刷手机、刷手机…… 可恶的妹妹，看完一场电影后便立即换到了 YouTube Shorts，在电视上刷短视频。面对我有关「无聊」的问题，母亲也仅是说可以一起看电影，明明我总是觉得自己的时间不够用…… 怎么可能再浪费时间，在仅仅是陪同一些人身上…… 先前被我刻薄说过的朋友，也想要几天后约我出来，可是就算出来玩，又能做什么呢？无非又是拉我去他家里打电动、因为什么都不想要做所以浪费一整天的时间吧。我不要…… 离我远点……</p><p></p><blockquote class="diary-thread-reply">03:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSEJF01VC9YF4N5KP96SMY4P" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这些天一直在下雨，天阴阴的。中途有一小会儿时间没有下，所以出去骑了会儿车。母亲给我搞来了一辆二手山地车，因为之前那辆被 amigo 偷了…… 天气很容易影响一个人的心情，说得也不错，我现在心情就很差。我要去把自己搓成红色的达摩。咪咪猫很害怕我，所以我要吸收一些匹克猫能量。</p><p></p></blockquote></div><hr><div class="diary-entry">17:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSG1HGRT2XD2EYTQ2Q560G87" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不知道为什么，早上醒来又不知不觉睡了过去，接着一直睡到现在…… 被饿醒。</p><p></p></div></details><details data-group="diary_sections"><summary>五月二十六日</summary><div class="diary-entry">03:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSH6M9276JNB4DA2X8ZZK22G" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>研究了几天终于搞明白了…… 买的一组魔方里没有三阶，所以跳过了三阶直接去玩的四阶，在学习理解上感觉很不对劲儿。不过总归结果是好的，慢慢熟练就好了。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KSH6HNFGEMC3H53416851VRP.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">12:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSJ4H5N81Y78S0YFF7N94JCG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>真是觉得服了。父母那帮子人因为住在海边，父亲又是个爱钓鱼的人，且从来没有空军过。钓上来的鱼他虽不吃，但母亲爱吃，且鱼这种东西只要能够「免费」获取，便可以作为「礼物」赠予给他人。因此，一个只需要利用起父亲爱好就可以不停继续下去的人情世故机器便诞生了…… 吗？</p><p>美国当然不给这么做了。一个钓鱼点之所以是钓鱼点，那是因为鱼的数量是足够给钓客钓的。如何保证？要求钓客们仅能带走限量的鱼，小鱼必须丢回去。为了防止有人不遵守规则，还安排了鱼警在周遭巡逻。看到谁偷偷拿鱼，或者疑似拿了鱼，就赶上去查，有时候还会开车追到对方家里、检查后备箱有没有鱼。我是咋知道的呢？因为父亲就有被查过一次。</p><p>前段时间母亲鼓励一位朋友去拿鱼，结果他拿的过程中被鱼警抓到，上庭罚了钱。风险承担下来，罚的钱够买好几条破鱼了。尽管这位朋友出了事情，母亲依然没少和其他朋友去拿鱼，甚至也想出了大量拿鱼的「技巧」，例如鱼要先藏在草丛中，多个人趁着夜色一个个搬到自己的车上…… 有时候他们拿的数量我总是好奇，真需要这么多么？你们吃得完么？对于这个问题，他们吃不完的便满城开车去送人 —— 真好，又有人欠我人情。谢谢鱼！</p><p></p></div><hr><div class="diary-entry">14:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSJASBJYB3C3FRHMV6N7M1S3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>因为无线耳机落父母家里了，无法使用手机听歌，但又不想因此来回四小时去取，所以打算买个有线耳机先用用。搜索时特别想吐槽，一个个做得都跟 Apple 的那款一样，但它那个头塞我耳朵里很不舒服。</p><p></p></div><hr><div class="diary-entry">14:47 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSJC1VSSCJ7ZMATWTN4WD5WD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天没能一醒来便起床。忏悔…… 每回合结束时向敌方单位造成等同于忏悔层数的伤害。</p><p>下单的录像小设备昨天到了。骑单车时别在衣领上用了下，回家发现朝向偏下，应该是弯腰导致的。然后是走路和骑车不可避免会抖动，必须后期修正。画质看上去还可以吧。不过它空闲时会自动关机，导致我之后想要录 Maimai，没发现已经关了、没录成。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KSJBWG9DF688PREPWP3SJNHD.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">14:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSJC6HBX7EEP0BV2RG4EATMY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚上室友没工作做，很闲，要我跟她玩饥荒。但不论是在线，还是离线的房间，我们都无法连上。所以放弃、改去玩逆转裁判。</p><p></p></blockquote></div><hr><div class="diary-entry">23:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSK9JHS8DKQ3EFA5JPSGAJD1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>餐厅里，客人们用卡付款时，会要求在一张收据上签字，并给出小费的数额。大多数收据格式上都会自动显示某某百分比的数额，例如 15%、20% 的小费会是多少。不想算的客人，可以直接勾选；想自行计算的，得在「自定义」的地方分别写下「给多少小费」和「小费后的总额」。</p><p>所以你时常能看到餐厅里的客人们用餐完，拿着手机里的计算器在算东西。当然，也有人很自信地不使用计算器。如果算对了，那便可喜可贺；如果算错了…… 那便是另一个故事了。</p><p>像我现在就根本搞不明白，加个 10 而已，为什么客人算出的总额的个位数和小数点，会和原价的完全不相干……</p><p></p></div></details><details data-group="diary_sections"><summary> 五月二十七日</summary><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">超级无敌焦虑。</summary>        <div class="diary-cw-content">04:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSKT0RT7GHQ18T83928F8ZAH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>总算是，暂时地，不用去考虑学校的事情了。说实话，怎么样都无所谓啦。文凭不文凭的，伪造出来也没有人会发现。原本以为要焦虑的事情仅剩经济 &amp; 打工，以及找工作，结果室友给我投了个更大的焦虑炸弹出来：我必须在某个时间点之前找到工作。说实话，能不能找到工作就已经够我焦虑了，现在还要加个 deadline…… 对于我找不到工作这件事，她也只是觉得「有能力的人一定能找到的」…… 可是，到底什么是「有能力」啊…… 我只是一个本科都没有毕业的蠢蛋啊。我能有什么能力？我 <em>他妈</em> 找个实习岗位都要有能力？实习岗位能要什么能力？你 <em>他妈</em> 的正常岗位都不一定需要什么能力。破烂父母在耳边叽叽喳喳地叫唤，又在像高考那会儿一样，「你为什么考得没有 XXX 高！」——「为什么 XXX 有实习，你没有！」滚开，滚开！亲戚上次过来和我聊天，说他们会从小培养孩子的兴趣爱好、找出孩子的优势，并为他们规划出能够最大化优势的路线。话题转向我的时候，他说，我的父母以前没有管我，我只能一个人撑着。就如现在，他们不捣乱就已经搞好了。妹妹小我十多岁，不过她的教育就被母亲抓得很好：有着体育上的天赋，便支持她去练习、带她进泳队打比赛。同岁的时候，我应该在国内当留守儿童，能过一天是一天。我不想把我的失败说成是父母的责任，我肯定也有问题：我懒惰、我爱逃避、我想过一天是一天…… 我根本不独立。我在幻想自己缩在纸箱里，等着哪天被运上车，爱去哪里去哪里。</p><p></p></div>      </details></div><hr><div class="diary-entry">13:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSMRNVGS3K3GZG15854QRKW5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>醒来意识到自己做了系列梦的第二节。过去做过一个梦，背景是未来的一个星球上。我是皇室的子嗣，但是国家要毁灭了，具体理由不明。梦中的父母要求我跑到地球，调查地球是否还宜于居住。不知道为啥，大臣仆人们都是超大号的 Duolingo 鸟，颜色都不一样。</p><p>今天这个梦，说的是我在地球待了 15 次，却遇到了大量蟑螂战士的入侵。我放弃了收集到的数据，时光穿越回过去，并着急叫 Duolingo 灰色鸟管家回国报告。</p><p></p><blockquote class="diary-thread-reply">13:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSMTFYEACS79E5N5YR60DZHR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>梦中还有一段是，我在一个人的家里，要躲避一个地中海男人的追杀。我也不知道为啥他要杀我。总之我躲在木制的柜子里，逃过一劫。</p><p></p></blockquote><blockquote class="diary-thread-reply">15:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSN1976KH3NMFMVP49KWJSVJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>煮饭期间对面的墙上赫然爬着一只巨大的 ゴキブリ <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3QFJGAWJ9M9GSWX95FCK4.png" alt=":neocat_sweat:" loading="lazy">​ 我才刚做完被人形 ゴキブリ 战士追杀的梦哎。</p><p>不过在现实中，我才是虐杀者……</p><p></p></blockquote></div><hr><div class="diary-entry">15:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSMZ8T6QT5YY4GHB9QBMMYAG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有关跨学科找工作一事，先前做过一个小调查，知道了一条应该可行的路线。简单来说，便是将编程和计算机，跟美国的三大铁饭碗结合在一起：法律、医疗、金融（我会将税务放在金融的范畴内）。但单单是结合在一起，对于这些传统行业而言，依然是不足够的。不过近些年来有了「转机」，即无论是有钱还是没钱都觉得有了它便能改变世界的可恶的 AI。嗯，美国现在做 AI 应用落地的岗位是综合看来最多的。再加上这玩意儿，新玩具每过一段时间就会出来，所以一旦有公司想要搞它，就必须有个人不停去学习、跟进。这一点倒是和我先前聊过的朋友说得一致，大家都在搞这个破玩意儿。至于有没有用，那当然是……<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4EE8WQ7Z323BCGBCMRHS.png" alt=":ottersgottaott16:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">15:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSMZPNYH27YN31SP2Y5DM30Y" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>但学习 AI 应用落地，我一直在质疑是否是把双刃剑。因为，很难说这种对于 Gen LLM 本身的缺陷而无限打上的补丁，未来是否还能继续使用。还是说未来一定会被遗弃？就算是现在热门的 RAG，如何才能保证它未来依然是可用的，不会被什么 agentic RAG、更多的乱七八糟术语代替？如果会的话，那我搭建的 AI 应用是否还要重新搭建一次？亦或者是，未来终于有企业发现，这玩意儿的效果真没有想象中那么好使？同样的精力去学习更传统的跨学科知识，例如金融基础、数据合规等，明显长期看来更有用。</p><p>总之也没事做，学了吧。</p><p></p></blockquote></div><hr><div class="diary-entry">18:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSNAR6MTTYS04TEWM5TW8221" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3P8JF14YTHR4M5SDGKWRQ.png" alt=":neocat_scream_scared:" loading="lazy">​ 不对，后知后觉发现 Kobo 不见了。难不成我昨晚落在打工的店里，没带回家？</p><p></p><blockquote class="diary-thread-reply">05-28 15:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSQMWJZD4YKVKHRP6V46SMH7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>还真是落在打工的店里了…… 总之没弄丢实在是太好了。</p><p></p></blockquote></div><hr><div class="diary-entry">22:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSNQDMZVM7WABS6ZMNH120P7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>那你贴的链接里的 Zenly 是你这个 Zenly 吗。真当我没见过 Zenly。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KSNQC46DXEVPX4PKPJW5C41F.png" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>五月二十八日</summary><div class="diary-entry">05:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSPJ6825XWEEZAE6B5CT3C59" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天晚起了，没有出门，也没有戴手环。确认了一下求职路线后，读书学习，然后被这本叫做 <em>Build Financial Software with Generative AI (From Scratch)</em> 的书坑了一把。原本以为都 2025 年的书了，应该会讲讲 fintech 里如何利用 Gen AI（我想的是 AI 应用落地）干事情吧。就算是自动化我也认了。结果整本下来，都是作者借助 chatbot 生成的代码，开发了一个简单的 ACH 仪表盘项目。一本读下来最有收获的是让我明确了 ACH 可以自实现，可以在一个生产项目内实践，因为先前那个的管理抱怨过 Stripe 的手续费很贵…… 书内 90% 的开发代码，都是开发的基础知识。剩余 10% 是 PostgreSQL 的玩法。因为我不怎么用，所以也是涨见识了。</p><p>为了更了解 AI 应用，我又去读了另一本。还未读完，但看 preface，要讲的东西不算少，要从如何让计算机处理文本开始讲起…… 忽然想起我最初学习编程时，想做的一直是个聊天机器人。那会儿就是个 C-c C-v 战士，借一个 C++ 教程搓了个简单的聊天机器人 —— 太简单了以至于实际说起话来是个大弱智，印象里根本没有用到机器学习里的基础知识。后来转战 Python，想用当时一个叫什么 <code>chatbot</code> 的库复现，但没有系统性学习，根本没搞明白要做什么，弄出来的也是个弱智机器人。这样一想，系统性学习真是重要。从零开始一个人折腾的话，就会像那会儿的我一样，不知不觉放弃掉吧。</p><p>晚上室友回来带了包裹，里面有我买来救急的便宜有线耳机。本来以为和无线耳机的音质应该不会差到哪里去吧，结果这款听上去音质很糟糕…… 幸好很便宜，还打折，等之后回父母家取无线耳机吧。明儿还得去打工的地方找 Kobo…… 总不能是弄丢了吧。</p><p></p><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">脏话有。</summary>        <div class="diary-cw-content">20:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSR5Y4DVB96XWJQNRJ1PKX93" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最该有科技介入的行业是 <em>妈的</em> 餐饮。这都什么狗屎系统、烂 POS、Java 写的破软件。</p><p></p></div>      </details></blockquote></div><hr><div class="diary-entry">15:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSQHP05F5KKFVJ61FMWYD34J" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>天气又热了起来。20 多度就很舒服，不需要再去找短袖短裤穿，直接把衬衫的袖子撸上去即可。谁叫我就没几件夏装呢。前几年大热天都是穿衬衫西装裤出得门，最热的时候也只是换成 polo 衫。</p><p>一眨眼，也要到六月份了。去年六月份我都在干嘛？因为室友，我时常也会因自己好像没有变化一事感到急躁…… 虽然普通人都是如此，但她瞧不起所有不够顶尖的人。有时候会觉得她的这种心理很烦，很讨厌。但她总会以财富、地位至上的理论来反驳 —— 没办法，谁叫她确确实实是特定领域的顶尖，而我是个连工作都找不到、靠兼职养活自己的家伙儿呢。虽说我对自己的惰性有一定的认知，给我带来压力也能让我持续努力一阵子，但频繁的压力，就会让我焦虑万分…… 更想逃跑了。</p><p>一说到「逃」，就想起中文课读的那篇《逃》：陈三麦从妻子那儿逃跑，去当兵。回来后被当成英雄，什么义务都被免除了。结果后来发现，他是个逃兵，根本不是英雄。他内心里只想无忧无虑地放风筝 —— 我是否也是另一个「陈三麦」呢？</p><p></p></div><hr><div class="diary-entry">15:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSQJHPX6HYDEG202BB3TV7X3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>近距离去观察他人的身体，就会发现肉身与肉身的不同之处。比如我的脚歪歪扭扭的，双脚的大拇指无法并在一起。又或者，我的小脚趾指甲形状很奇怪。我没有想过，世上竟有人的小脚趾指甲，和其他脚趾的指甲长得一样，而不是我这样，像是石头一般，厚厚的一块。</p><p></p></div><hr><div class="diary-entry">18:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSQWDBANCS2GP9SXVR8QA7Z5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我记忆里，自己小时候骑车好像会溜车。现在完全不会了。小时候的自己好像也会侧身单手翻，现在也不会了……</p><p>现在的自己好弱啊！跑都跑不起来。</p><p></p></div><hr><div class="diary-entry">19:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSR2GT3FSPDG93FK833D4ZEW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在「喝可乐」还是「不喝可乐」之间，最终选择了「喝雪碧」。</p><p>唉，可乐不赶紧喝完的话，气泡一旦没掉了，喝起来就会是腻歪的小甜水，甚至有点恶心。</p><p></p></div></details><details data-group="diary_sections"><summary>五月二十九日</summary><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">发疯。</summary>        <div class="diary-cw-content">00:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSRGM80H16VKVKM75N6YWFQ5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我完全听懂了，给你说最简单、最不绕弯的，不绕圈子，不扯废话。一句话给你讲透，不藏着掖着。主打一个直白靠谱，句句都在点子上。直接跟你说大实话、最实在、最生活化、不带任何专业词、最清晰、最准确、一看就懂、明明白白、彻底讲懂、一句话把你彻底点醒。</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">还是发疯。</summary>        <div class="diary-cw-content">00:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSRHKT28QMBVTP6XJJ5GGNMM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我好饿，我好饿，我好饿，我好饿，我好饿，我好饿，我好饿，我好饿，我好饿，我好饿，我好饿，我好饿。</p><p></p></div>      </details></blockquote></div><hr><div class="diary-entry">03:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSRWVCD7XYPE6MHRH6E8K9XT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>风火轮魔方好难玩啊…… 根本扭不起来。</p><p></p><blockquote class="diary-thread-reply">04:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSRZW9D40K9SVN2M7STQ6BZZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>搞明白了。扭的时候得对准大小。有了这个概念后之后都和三阶差不多。区别仅有：</p><ul><li>腰部还原得自行扭一下决定放左还是放右，因为腰部角块只有单色</li><li>有中心块变形的特殊情况。放顶层然后做五遍上勾下勾就行了</li></ul><p>因为形状太奇怪，玩起来特别特别不舒服，估计只会玩这一次，未来无聊玩的话还是玩四阶。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KSRZPHXCFXF4ZAHV49B7N5AQ.jpeg" alt="" loading="lazy"></figure></blockquote></div><hr><div class="diary-entry">04:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSS0W3FYQHZT9FJZZMCR64R0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>小时候最喜欢的一款魔方 —— 应该是吧，也有可能买的是粽子 —— 但记忆里坐高铁还是火车时，把魔方坐在身下睡着了。醒来后发现魔方被我压扁，难过了一天……</p><p>总之是款非常简单的魔方。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KSS0S08YCXT5Y2TVF9F53R2N.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">04:47 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSS0YMMNMH4ATQR492ESZME0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>买的一组五款，只剩下最后一款还没有开始玩。但说实话，不是特别想玩 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 像个特么的跑团用的骰子。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KSS0Y8CZFZ7DPJHKCVT91C5N.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">13:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSSZB4ETNK84JASFCF6C94HM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>一觉醒来发现厨房满地都是黏糊糊的隐形椰子水残渣 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 不小心踩到我还以为是匹克猫吐了。</p><p></p></div><hr><div class="diary-entry">14:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KST0THXCYW5THJ0ENB2S7RJV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这些工作岗位一个个都要问我居住地址是想干什么 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 按理来说你知道个 zip code 不就完了。问房号跟街道名什么意思你。</p><p></p></div><hr><div class="diary-entry">14:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KST1G5TD54N8Y35ZNFVH1WJ9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>卧槽，哥们，这是二楼啊，你是怎么上去的。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KST1F6BDNMYCH5W5DKJCBF64.jpeg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KST1F6GKCZANYY6H2TEBW0ER.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">15:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KST49X4JR6RW689B21CMPGTE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Macbook 的电源键，好容易误触到啊。本来在另一台电脑上 rsync 一些配置过来，结果不小心碰到，关机了…… 得把这个键改掉。</p><p>目前是刚把 status bar、fcitx5 折腾完，现在在弄 Floorp 和 Emacs。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">性别对立、脏话相关。</summary>        <div class="diary-cw-content">15:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KST6VBGFX5Z844Y9NFF8G1EQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这太神奇了，我到现在还玩不上《洛克王国：世界》，但上 QQ 天天会被加入的频道跳脸。性别对立过脑连「理性讨论，男 / 女性不准玩游戏」这种话都说得出来，可见得这群人脑腐有多严重。</p><p>过去应该是和哪位朋友聊过相关联的话题。当时我们得出的结论是，身处于一个环境内，看到的问题可能并非真实的大问题，而是环境塑造出来的。将自己搬出该环境的盒子，能够更客观地看待它。一个更易懂的说法是信息茧房，让人们只能看到某个信息或者问题，并认为它大于或优先于其他事情。</p><p>用朋友更为刻薄的话语来说，是井底之蛙，以为井画出来的天就是世界。不过当时我们是在聊人生规划，因为他无法理解这世上怎么会有人愿意普普通通过完一生：结婚生子、这个那个…… 由于我们其实是在用泛例在指桑骂槐某个讨厌鬼，所以得出的「井底之蛙」一例也仅仅是对讨厌鬼的评价。</p><p>不过互联网这种东西，想从某个东西那儿断开连接还是很方便的，直接退出那个破频道就好了，反正游戏我也玩不到。但是现实里我再感受到标签化对个体带来的影响，还是会觉得很恼怒。单说性别对立，身边就有过男性朋友被女性友人莫名其妙骂一顿然后拉黑、男性朋友「小仙女」入脑和我聊几句话突然说「原来世上还是有好女孩」…… 这种，就，非常，那个，<em>他妈</em> 莫名其妙的事情啊，会让我装不出笑脸，只想说「赶紧 <em>他妈</em> 去上个学吧」—— 但我就因为上了这个破学，遭遇了种种垃圾事件和垃圾人，所以学校也可以是另一个糟糕的封闭空间。难道事情就没有任何转机……！</p><p>无论是和什么对立，初衷看上去都是好的、正义的。女性主义想要消除社会对女性的歧视和偏见；环境保护想要保护大自然环境；动物保护想要保护小动物们…… 但现在它们都以更负面的形象出现在公众面前，尽管这个负面形象的整体占比大概率并不大，因为群体里总是以沉默者居多，但介于说话声音更大，看上去也更大。这看上去就是个恶性循环，内对外的仇恨越高，外对内的仇恨也越高，慢慢地，大家都被激化，说的话以及做的事情也越来越极端…… 最终的结果是标签化愈发严重，人们也与彼此愈来愈远。</p><p>那么解决方法到底是个啥子喔。鬼知道。个体要如何改变世界呢？常说的道理是先改变自己 —— 嗯，大道理讲完了。不要指望我能给什么解决方案出来，这只是我肚子痛、蹲马桶期间写的日记而已。</p><p></p></div>      </details></div><hr><div class="diary-entry">16:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KST7E0QXYV96TJKA520QVQ6T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p></p><blockquote><p>Do you remember</p><p>the twenty-first night of</p><p>September?</p><p>Love was changing the minds of</p><p>pretenders.</p><p>While chasing the clouds awayyyyyyyy.</p><p>Our hearts were ringing</p><p>in the key that our souls were singing</p><p>as we danced in the night,</p><p>remember</p><p>how the stars stole the night awayyyyyyy.</p></blockquote><p>Stop here. You can't sing the rest as a joke punishment.</p><p></p></div><hr><div class="diary-entry">16:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSTA6575T7PFPP1F60935WR8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这段时间在家每餐都在吃椰子鸡、上海青、米粉或者米饭。因为蛋白质摄入得充足 —— 虽然完全按照膳食指南根本吃不饱，所以加了量 —— 现在的体重已经到达了历史最高！太厉害了，蛋白质。</p><p>不过要到达健康的 BMI，还需要增重更多……</p><p></p></div><hr><div class="diary-entry">20:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSTPRDBEVGWS8PTHAAZ4HSTZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>美国小企业管理局（SBA）有个联邦项目，要求每年至少有 3% 的联邦合同金额会授予位于 HUBZone 的企业。</p><p>而 HUBZone 是 Historically Underutilized Business Zone、历史上未被充分利用的商业区的意思。通常包括了：低收入社区、高失业率地区、农村流失区，和灾难声明区域。</p><p>如果有家企业有 HUBZone 认证，那么为了维持认证，它必须有一定比例的员工居住在 HUBZone 地区。所以对这些企业而言，居住在 HUBZone 的候选人有额外的价值。</p><p>那么如何确认你是否住在 HUBZone？SBA 提供了官方地图工具： <a href="https://maps.certify.sba.gov/hubzone/map" rel="nofollow noreferrer noopener" target="_blank">https://maps.certify.sba.gov/hubzone/map</a></p><p></p></div><hr><div class="diary-entry">23:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSV2HHNF06BV1YBXR49C42ED" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>本来好好的不打工的一天，可以做点事情，但生理期一来，什么都做不了…… 嗑了点药，慢慢地等待生效。因为很好奇，所以搜了下人们是如何干掉生理期的，发现除了绝育和嗑药，还有很多方式，比如什么皮下移植避孕、宫内节育器…… 最常见的还是吃避孕药，但得去找医生（所以的都得找医生！）。</p><p>有点想吃麦当劳。</p><p></p></div></details><details data-group="diary_sections"><summary>五月三十日</summary><div class="diary-entry">03:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSVFYX8NNK6ZDCEXFK0ZCFY6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 悲报，有些代码库在我备份之前就丢失了，然后写的一篇文章回应也丢失了。现在特别想一头撞在冻豆腐上。</p><p></p></div><hr><div class="diary-entry">06:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSVR9SHYVP8T3RZDZM1XQC4J" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>真是受够家里这台电脑的显示器了，经常会突然黑屏。今天不知道发生了什么，黑屏的频率和时长比过去多很多，根本无法正常使用。就像现在，屏幕就黑了十秒以上。</p><p></p></div><hr><div class="diary-entry">06:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSVRV03TYD2BBF0XQ3ZM6534" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我对离线小模型有着一定的好奇。高中时简单研究 Hugging Face 上的模型时，订阅了忘了什么名字的中国公司的公众号。前不久看到他们推出了 1B 的超小模型，就很想下载一个、玩一下。当时我在外面，所以快速下载了一个名为 <em>Toolneuron</em> 的安卓 app，想试试看这些小模型跑起来咋样。</p><p>结果 Toolneuron，虽然有着丰富的外观和动画，但根本用不了呢…… 看了下 issues，发现是内存问题。等开发者啥时候更新吧……</p><p></p></div><hr><div class="diary-entry">06:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSVSF2YAXCR2H6VPQ911RBWS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前买了苹果醋驱动的果蝇陷阱，想要看到果蝇们全部被苹果醋的味道吸引过去，然后死光光。结果，根本没有作用。</p><p>今天实在是被烦到了。在打死了数只小飞虫后，终于打算搜索一下这玩意儿为什么不被果蝇陷阱吸引 —— 结果它根本就不是果蝇！是蚤蝇。吃蛋白质的。</p><p>这玩意儿繁殖能力很快很强，会吃蛋白质、蔬菜、腐烂的东西，还能在下水道一边的有机污垢上繁殖。太恐怖了，生物。</p><p>果断购买清理水槽管道的东西，还有吸引小飞虫的灯光驱动陷阱。</p><p></p></div><hr><div class="diary-entry">13:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSWJR21PMC3QRBZ2BYZ3BFJ5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在 PiliPlus 上看到意外感兴趣的视频：让自己的生活多些离线科技，以摆脱 distraction（一下子忘了中文叫啥了）。</p><p>打开评论区：「国外复古嘉豪」。</p><p>我得改改自己习惯看评论区的毛病。</p><p></p></div><hr><div class="diary-entry">15:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSWQWKQVVM5QBV6E7MKBE353" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>火车站边，不知道是哪个组织放了台五彩小钢琴在那儿。不过声音太小了，有个演奏者在弹，我却听不见。</p><p>昨晚去见朋友。她前段时间在 Instagram 被人搭讪，搭讪方式让她觉得新奇。大致是这样的开场白：</p><blockquote><p><em>汪汪！</em></p><p>哦不，对不起，这是我的狗狗 Max。它会感应到美女。坏狗狗 Max！</p></blockquote><p>虽然在我看来，搭讪就是搭讪，而我讨厌被人搭讪。所以她认为的「新奇」我无法感受出来，只是觉得，有种奇怪的油腻感……</p><p>出于好奇，她去和对方见了个面、喝喝咖啡 ——coffee chat 技能真好用啊。期间他们的对话其实就是，对方想要找个亚洲人谈恋爱，想问朋友是否对自己感兴趣。不过对朋友来说，主动提出想和自己谈恋爱一事已经是个 red flag，所以表达了不感兴趣。</p><p>对方认为明明两个人聊得很来啊，可以慢慢发展嘛。但是朋友表示，她只是和谁都能聊得来而已，不意味着他们是 best match—— 过去她还和流浪汉、素食主义宣传者聊得很来。友善聊天对她来说是个 skill issue，但许多人都有错觉，认为是她对自己感兴趣。这也让她觉得很头疼。</p><p>对方又好奇为什么她对谈恋爱不感兴趣。于是我和朋友们老生常谈的「纠正行为」再次出现：「你对恋爱不感兴趣？是不是你没有谈过？是不是你没有谈过好的？是不是你还没有见到真命天子？」—— 在现实表现出来的，就是对方直接询问了朋友是否有过炮友关系。嗯，尽管诚实但依然听上去很…… 粗鲁和直接 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 唉，诚实也是件好事，这能让我们很快地看清一个人。省时又省力。朋友的回答也很简单：「就如你知道自己不喜欢男人一样，我也知道自己对你一点兴趣都没有。当朋友也不可能。」</p><p>结果自然是不愉快的。对方为了谈成还给朋友买了花束，殊不知是朋友的另一个小小 red flag。我也不喜欢花。让我捧着花会让我觉得自己很蠢。它们也是生命的一部分，让我拿着花束会有着得去照料它们的责任和负担…… 我得去买花瓶、土，或者直接水养。这种感觉很糟糕，和买条狗让我养差不多。至于朋友，她把花放在了共享办公室内，写了个 <em>TAKE ME</em> 在上面，在某个时候被别人拿走了。</p><p>我想起了曾在网上看到的一组图片，说是甲的社交圈内只有泛泛之交，和一个对自己很不错的乙。对比下，甲会误以为乙对自己抱有好感。但反过来，乙的交际圈内，对甲表现出来的「好感」只是礼貌而已，他有更多关系好的人。这种信息上的对差，会导致同时出现「我以为他喜欢我」以及「有人莫名其妙跟我表白」这两个情况。</p><p>我很想搞明白过去有人向我表白时，我从心里萌生出的恼怒感是出于何等原因。我目前对此的解释是，或许是对方没能按照我对他的角色定义走，导致我很生气。亦或者是我当时在处理别的事情，他却从一个让我感觉安稳的角色，变成了另一个麻烦。那问题就变成了，为什么我会觉得他人向我表达心意对我来说是个麻烦？为什么我会潜意识里强求他人按照我的预期行动？</p><p>我不成熟，还有更多需要了解自己的地方在……</p><p></p></div><hr><div class="diary-entry">15:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSWS1HH4B9J7TSK3WZ1Z9NE0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>没看天气预报，出门时差点被风刮走。地铁和以往一样延误…… 什么叫我得等十多二十分钟？总之终于是到了目的地。看了眼天气预报，今天怎么只有 14 度？前两天还热得没边呢！</p><p></p></div><hr><div class="diary-entry">16:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSWTEZXZ3SHW5V6M5NBGBAW1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打工太无聊了。碎片化的时间难以做些什么，比如读书，很多时候只能读 RSS 订阅内的小文章，或者 Instapaper 里的小文章，或者玩《杀戮尖塔 2》，或者发呆……</p><p>然后就会想要从打工中寻求些乐趣，比如我想学一只手拿 9 个杯子。但是手太小了，最多 4 个。</p><p></p></div><hr><div class="diary-entry">16:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSWV4Q1AP2K4XANTZW45KSMY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近有炒股的想法，不过看了眼自己的存款，连四位数都没有，还是不要放进去丢人现眼了……</p><p></p></div><hr><div class="diary-entry">17:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSWYHFF11PSBPRHFN5GBSVMW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想要把 Kobo 的原生系统干掉。理由是想要一个能打通 Calibre 和 Zlibrary 的网络。不过我真需要这么做么？实际上每天回家、将真的想要读的书籍有线传输过来，也不是什么坏事。</p><p></p></div><hr><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ3FAJXF4XE1VN2ZH7SR5EEG">↩ 续前文</a>        </div> 18:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSX2NCRJEHG4EHGZBQHZRJCR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不过 Raymond 发现了黑客们，实际上并不愿意承认「自我」驱动这件事。他们会将其包裹成「专业素养」、「成就感」等等话语，但就是不愿意承认自己的行为是出于对声望的渴望。这也导致他们很讨厌自我推销。对外，他们通常是谦逊的，尤其是在技术能力和代码上，但又往往会毫无顾虑地攻击他人的意识形态、个人差异…… 这一点和学术圈相比可是天差地别：学术圈内获取声誉的一大方式，正是通过批评他人有缺陷的作品；黑客文化内，大家并不会直接指出作品的过错，亦或者是将 bug 认为是作者的问题。</p><p>这些内容我需要结合现在的开源文化来探索，因为我还是会见到因为代码写得差，所以被攻击的案例在。</p><p></p><blockquote class="diary-thread-reply">18:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSX37GVCK5W1609K58K77NHX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在已知黑客文化中都是隐形的声望竞争后，Raymond 列出了一些他发现能在竞争中胜出的点：</p><ul><li>创建项目会比项目合作让人获得更多的声誉</li><li>相比做出更多现有软件的仿造产品，创意十足的产品会让人获得更多的声誉</li><li>一个软件如果只有作者本人才理解或需要，那在声誉竞争内连参赛都不够格</li><li>对现有项目做出贡献会比另起一个新项目更容易吸引注意力</li><li>和成熟项目进行竞争，要比填补领域的空白更难</li></ul><p>结论是，项目总是倾向于填充前沿地带的功能性缺口。而过于成功的项目会导致人们更倾向于去增加它的扩展，而非另起一个新项目与其竞争。最好的例子是 GNU Emacs，还有 Linux。</p><p>开源项目发展的总体趋势，也因此大致可以分成「填补空白」和「做出过分成功的软件以至于没有人想要与此竞争」。</p><p></p></blockquote></div><hr><div class="diary-entry">21:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSXDX1VV338S0PZ6B74VMX9F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://www.sina.cn/news/detail/5279286413232198.html" rel="nofollow noreferrer noopener" target="_blank">https://www.sina.cn/news/detail/5279286413232198.html</a></p><p>初中读了本日本人写的书，内容是做推销能参考的心理学知识，里面就有同个道理但是名字叫做「松竹梅法则」，其中的「松竹梅」可以直接替换成文章内的 <em>ABC</em>，或者更中国一点的「甲乙丙」。</p><p></p></div></details><details data-group="diary_sections"><summary>五月三十一日</summary><div class="diary-entry">01:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSXSQ0BRJHFM3R27SD877E0M" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​ 刷卡过地铁站，门一开过来一个出站的男的，竟叫我去旁边的门。奶奶的，我钱都刷了让我走别的门，你帮我再刷啊。赶紧叫他一边去，我要过。</p><p></p></div><hr><div class="diary-entry">01:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSXTBJM9D9D7N8JEVXFRKKKD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>路人们擦肩而过，然后开始互相辱骂。</p><p><em>Typical New Yorkers.</em></p><p></p><blockquote class="diary-thread-reply">01:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSXTGKTDT9G9VTD1JB8BJX6D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>走在大街上然后莫名其妙被骂，也是不少见的事情。因为习惯了，我还会观察对方因为什么而骂人。比如之前一个骂我的光头，会对着所有路过他的人大骂。因为太大声了，他看上去总是很疲累的样子，脱离了被辱骂一方的身份，仅以第三方的角度去看，反而会觉得这光头气喘吁吁的很滑稽。</p><p></p></blockquote><blockquote class="diary-thread-reply">01:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSXV0QMCWC2PQ7XDMJ8BF0S9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>比起说是 <em>New Yorkers</em>，更像是 <em>Manhattaners</em> 吧。人们对纽约的印象，其实都是对曼哈顿的印象。纽约市的五大区，知名的只有曼哈顿一个就是了。</p><p>那有没有比曼哈顿更残暴的地方在呢？有，Bronx 区。我除了参观过一次那边的动物园外，从来都没有去过那边。住在 Bronx 的校友只会苦口婆心劝我没事别过去。</p><p></p><blockquote class="diary-thread-reply">01:47 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSXVDWHAVPYPWM2M3MSA8XK1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说到 Bronx 又想说说黑帮文化了。黑帮这东西，听上去远，但实际上离我们很近也说不定…… 我第一次打工，是在 Brooklyn 内的一个华人区。该说是臭名昭著么，那个区会被外人调侃为 <em>Chinese ghettos</em>，即「华人贫民窟」。除了中国人住在那儿，还有棕色皮肤的，应该是墨西哥或者西班牙裔住在那儿。上个世纪，中国人还未大量搬来这个区时，到处都是残暴的黑帮成员，见到亚洲面孔就抢劫。至于现在，卖白粉的黑帮成员也在，我曾经还给他们送过外卖…… 不行，又想展开说说初次打工的经历了。</p><p>而纽约市的华人区，另一个有趣的事情在于，也有帮派活动，并且是中国人之间的帮派活动。印象里上个世纪有「长乐帮」，就是福建省里的那个长乐。他们还有个死对头，但我不记得叫什么、来自福建省的哪里了。打架斗殴、互相砸场子，也不罕见。</p><p></p><blockquote class="diary-thread-reply">02:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSXW6JZH1MHVG1Y7PS83EEK7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>华人帮派做的最多的事情，是人口走私，即做「蛇头」，高价从国内将人偷渡来美国。方法百花齐放，最开始是把人藏甲板底下，还成了稳定的生意链。不过走船现在应该不行了，不然怎么这么多「走」来的。印象里前几年里有一年，一下子「走」来十多万个。人太多了处理不过来，只能求助其他州帮忙收一些。如果没记错的话，那年同时还发生了 Texas 要宣布独立的事件。</p><p></p></blockquote><blockquote class="diary-thread-reply">02:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSXXXR6MJZPZEPP59X0TVB1Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>简单搜索了一下，发现了更为有趣的事情，那就是新移民青少年帮派活动。这篇 <a href="https://myhunan.us/%E7%BE%8E%E5%9B%BD%E6%A2%A6%E4%B8%8E%E7%BE%8E%E5%9B%BD%E7%97%9B-%E5%8D%8E%E8%A3%94%E6%96%B0%E7%A7%BB%E6%B0%91%E9%9D%92%E5%B0%91%E5%B9%B4%E5%B8%AE%E6%B4%BE%E7%8A%AF%E7%BD%AA/" rel="nofollow noreferrer noopener" target="_blank">文章</a> 有着更详细的说明。</p><p>让我想起了一个表弟。因为父亲移民来美国工作，再加上当时他们那儿的风气，就是来美国能变有钱，那作为高中生，考个毛高考啊。我出去洗盘子能把老板店买下来，你努力高考、上大学，毕业后能找到工作吗你？所以他放弃了高考，直接移民过来。</p><p>这种情况的后果是，他没能事先调查好在美国要如何生活。是，你洗盘子可以生存下来，但作为年轻人，不可能只有「生存」，而没有「生活」吧？没有说英语的技能，在美国基本上只能在华人圈内待着。而华人圈，恶劣的话可以很恶劣…… 我刚来美国那会儿，看到过热水煮婴儿视频，接触过性压抑单身汉（妈的这个现在也在接触）、暴力狂、赌鬼…… 那些可怕的环境，根本没法正常培养孩子。</p><p>看上去还算光彩的是 ABC 群体，即老移民的后代。不过我对他们也有偏见，谁叫我碰到的 ABC 无一例外全都是恐怖的自恋狂…… 包括那个讨厌鬼。虽然是美国出生的，但传统文化所带来的性压抑，和西方文化的性开放互相碰撞，产生的东西…… 很大可能就是这么恶心。</p><p>说回青少年帮派，他们有时候手段要比成年人帮派更为残暴、恐怖。在压抑的社会内长大，接触到的仅是暴力。他们很大可能在家里就不被关心，毕竟因为偷渡过来，家里都没有钱，父母只会埋头工作，又因为没有英语，干的都是底层的苦力活，受气后哪还管教育，直接把你当充气筒打一顿。</p><p>我有过类似的经历，是段很令人受伤的经历，而我可能要用一辈子才能治愈这些事情…… 贫穷是可怕的。我不敢没有钱。高中的老师曾瞒着我将事情报告给了儿童局 —— 许多人可能会认为在美国，儿童很重要、打不得。但是孩子什么都不知道，又哪能知道自己其实有一定的「权利」呢？所以很多时候是被父母威胁着「如果告诉别人，你就没有爸妈了！」然后为了自己可悲的，天生的爱父母的能力，忍气吞声挨打。总之儿童局介入后，母亲不敢打骂我了，我也可算是在肉体上逃离了暴力。</p><p>但是暴力不仅仅局限于肉体。除了在家里也被挨打的青少年外，还有父母因为怕儿童局，而不敢打骂的青少年。哎，这些人也有被忽悠进帮派的可能性在。因为打骂不意味着教育，不打骂同时也不教育，到头来还是没对孩子进行教育。他们怎么知道事情该怎么做呢？他们只知道有人叫自己进帮派，进帮派做事情可以拿钱、玩女人、有社会地位……</p><p></p></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">05:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSY7VYH8ZJFFMBW6PYCA1DRA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>幸福地吃着 Tous les Jours 的轻芝士蛋糕…… 吃起来不像芝士的芝士蛋糕，真是太棒了……</p><p></p></div><hr><div class="diary-entry">19:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KSZSFMVVRVFMSZNF2974Y0DT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>早上起来收拾了下家，复盘五月做的事情后察觉到有很多东西可以直接写成文章，于是花了点时间在搓文章上 —— 早干嘛去了。</p><p>接着把之前一直都没挂到墙的挂画挂上去。不过我不会用，最后是用很奇怪的方式弄上去的。过程虽然很屎，但结果够了就行，我是高级程序员。</p><p></p></div><hr><div class="diary-entry">21:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KT00FWR79CSZG37C7WMSY48S" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>What the fuck. Like for real for real?</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KT00EYVWMZ273N9N55RZ52NX.png" alt="" loading="lazy"></figure></div></details></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;期末周总算是结束了！没有了学业这个拖后腿的东西后，我在这个月花了更多的精力在求职、学习新东西上。&lt;/p&gt;</summary>
    
    
    
    <category term="想法迭代" scheme="https://blog.cytrogen.icu/categories/%E6%83%B3%E6%B3%95%E8%BF%AD%E4%BB%A3/"/>
    
    
  </entry>
  
  <entry>
    <title>我的求职路・壹：投简历和找对方向</title>
    <link href="https://blog.cytrogen.icu/posts/61e0.html"/>
    <id>https://blog.cytrogen.icu/posts/61e0.html</id>
    <published>2026-05-31T22:00:00.000Z</published>
    <updated>2026-05-31T22:21:42.174Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>虽说上个月就在求职，但一直都没能拿到面试，拒绝信收得也很快。这个月因为各种事情，比方说经济方面的焦虑、室友带来的压力、父母带来的压力等等，都让我深觉沮丧和焦虑。焦虑就不用说了，沮丧是因为我认为自己的经验并不差，简历上连玩具项目都没有，全都是我真实参加过、和别人合作过，甚至有盈利的项目。作为本科还未毕业的人，我心想这已经足够让我找到一份实习了吧？但事实是没有，我收到了大量的拒绝信。</p><span id="more"></span><p>有天我和室友吵了很厉害。她觉得都是我的能力不足导致的，更让我的心情降到了低谷。不过架吵到后面，她还是给了点建设性的建议 —— 当然她的那些挖苦和贬低全都是垃圾话，连建议都算不上。有时候真的很想打她一顿，但是我打不过她。流汗流汗。</p><p>根据建议，我预约了学校的职业发展部门，希望能从这些专业人士身上得到建议。很不错，我确实得到了有用的建议，分享一下吧。</p><p>首先是现在的公司招聘，收上来的简历会先进行一轮 ATS（Applicant Tracking System，申请人跟踪系统）。这东西最关键的一个功能是，根据职位要求自动筛选简历、匹配关键词。没匹配到的，公司就有可能直接刷掉，根本到不了真人手里。</p><p>为此，我们可以「逆向」这个流程：自己弄个模拟 ATS 筛选流程的工具，然后自己进行一波筛选，不就可以了？</p><p>学校破天荒地做了件好事，那就是内置了 JobScan 这个软件。大家也可以去 JobScan 的官网体验一下：<a href="https://www.jobscan.co/">jobscan.co</a></p><p>顺带一提，学校除了做这件好事外，就一直在做坏事…… 例如为了拥抱 Microsoft 的 Exchange，重新设计了邮箱系统，让我们手里又多了个聚合邮箱。原本的学生邮箱收到的邮件，会被自动转发给聚合邮箱。但在聚合邮箱内，转发来的邮件看不到原始的邮件名、发信人，只能看到我的名字，且在 Outlook 里得再展开一次才能看到邮件内容。聚合邮箱也不能用来发信，相当鸡肋。可是不用它又不行，因为学校发来的通知现在会优先发给聚合邮箱。我的手机上同时登录了聚合邮箱和学生邮箱。如果有邮件发给我的学生邮箱，那么总共会弹出三次通知，其中有两次，是转发给聚合邮箱的通知 —— 我也不知道为什么是两次，但就是这样。</p><p>回归正题。JobScan 会根据职位说明，扫描我上传的简历，并给出分数和建议。通用的建议是，不要在简历内使用花哨的字体和排版，最好是纯文本或者 Word 格式。</p><p>我原本的简历是用 <a href="https://jobright.ai/">Jobright</a> 生成的。这是一个 AI 驱动的求职平台，可以根据我的简历和目标，自动筛选并推荐最匹配的职位。它也有主流 ATS 平台自动填写申请的功能，需要安装 Chrome 的插件，但我用的是 Firefox 的分支软件，所以用不了这个功能。</p><p>Jobright 也有定制简历的功能，我用过几次，是挺不错的。但它作为一个 AI 产品，肯定是不给一直免费使用的，因此它有 credit 系统，一天只能定制化几次。对于「不发个千来份简历亚洲人就不准说三道四」的美国职场而言，几次算个毛！所以我放弃使用 Jobright，仅用它找岗位 —— 别说，能找到很多岗位，很适合弥补 Indeed、Handshake 这类求职平台上岗位不够的点。</p><p>Jobright 生成的简历，我给职业发展部分的工作人员看了，他们觉得在排版上依然可以做得更好。可是 Jobright 不能随便改排版…… 思来想去，我决定设计一个流程。我拿 Org Mode 文件作为简历的信息源，然后用什么工具自动生成简历的 PDF 格式出来。这样我就可以很方便地定制简历。</p><p>这是一个大致的 Org Mode 模板：</p><pre><code class="language-plaintext">#+TITLE: Resume#+OPTIONS: toc:nil num:nil author:nil date:nil#title:nil#+begin_export html&lt;header class="resume-header"&gt;  &lt;h1 class="name"&gt;名字&lt;/h1&gt;  &lt;p class="contact"&gt;城市, 州 邮编号码 | 电话 | &lt;a href="mailto:邮箱地址"&gt;邮箱地址&lt;/a&gt; | &lt;a href="GitHub 或者 LinkedIn 地址"&gt;GitHub 或者 LinkedIn 地址&lt;/a&gt;&lt;/p&gt;&lt;/header&gt;#+end_export* 教育** 大学名称 / 学院名称 | 啥时候毕业学位 \\/专业/* 专业经验** 公司或者项目名称 | 开始 - 结束/岗位名称/- 详情* 技能- *技术栈：*- *兴趣爱好：** 语言- 要是在美国的话就不要写英语了，这和在中国没人会说自己会汉语是一个道理</code></pre><p>Pandoc 可以将 Org Mode 文件转换成 HTML。因为 Org Mode 本身无法排出自定义的 header，所以我是直接写了原始的 HTML。</p><p>生成命令：</p><pre><code class="language-zsh">pandoc resume.org -o resume.html --standalone \       --css=resume.css \       --lua-filter=split-headings.lua \       --metadata title="姓名 - Resume"</code></pre><p>其中我的 CSS 文件是从 Jobright 生成的简历中，逆向出来的，再做了些更改。内容如下：</p><pre><code class="language-css">@page {  size: letter;  margin: 0.375in 0.5in 0.555in 0.5in;}* { box-sizing: border-box; }html, body { margin: 0; padding: 0; }a { color: inherit; text-decoration: none; }p { margin: 0; }ul {  margin: 0.1em 0 0.3em 0;  padding-left: 1.1em;  list-style: disc;}li { margin: 0.05em 0; }body {  font: 11pt/1.3 "Arial", "Helvetica", sans-serif;  color: #000;  max-width: 7.5in;  margin: 0 auto;  padding: 0.375in 0.5in 0.555in 0.5in;}@media print { body { padding: 0; max-width: none; } }.resume-header { margin: 0 0 0.6em 0; }.name {  font-size: 23pt;  font-weight: normal;  margin: 0;  line-height: 1.1;}.contact {  font-size: 10pt;  margin: 0.15em 0 0 0;}h1 {  font-size: 13pt;  font-weight: bold;  margin: 0.7em 0 0.25em 0;  padding-bottom: 0.05em;  border-bottom: 0.75pt solid #000;}h2 {  font-size: 12pt;  font-weight: bold;  margin: 0.5em 0 0 0;  display: flex;  justify-content: space-between;  align-items: baseline;  gap: 1em;}h2 .rhs { font-weight: bold; white-space: nowrap; }h2 + p {  font-size: 11pt;  margin: 0.05em 0 0.1em 0;}h2 + p em { font-style: italic; }ul li strong { font-weight: bold; }h1, h2 { break-after: avoid-page; page-break-after: avoid; }li, p  { break-inside: avoid; }</code></pre><p>而 <code>split-headings.lua</code>，是将 level-2 的标题变成这样的 <code>h2</code> 标题：</p><pre><code class="language-html">&lt;h2&gt;&lt;span class="lhs"&gt;公司名&lt;/span&gt; &lt;span class="rhs"&gt;日期&lt;/span&gt;&lt;/h2&gt;</code></pre><p>这样 CSS 才能用 flexbox 将日期推到右边去。</p><p>这是 Lua 脚本的内容：</p><pre><code class="language-lua">function Header(el)  if el.level ~= 2 then return nil end  local s = pandoc.utils.stringify(el.content)  local left, right = s:match("^(.-)%s*|%s*(.+)$")  if not left then return nil end  el.content = {    pandoc.Span(pandoc.Str(left),  {class="lhs"}),    pandoc.Span(pandoc.Str(right), {class="rhs"}),  }  return elend</code></pre><p>有了带 CSS 加持的 HTML 后，我们便可以用 WeasyPrint，将 HTML 转换成 PDF 了。WeasyPrint 是个 Python 库，下载后可以直接在终端内使用。我为了自动化，写了个 Makefile：</p><pre><code class="language-makefile">SRC := resume.orgCSS := resume.cssHTML := resume.htmlPDF := resume.pdfSRC_ITS := resume-its.orgHTML_ITS := resume-its.htmlPDF_ITS := resume-its.pdfSRC_FE := resume-fe.orgHTML_FE := resume-fe.htmlPDF_FE := resume-fe.pdf.PHONY: all html pdf its fe watch clean openall: pdfhtml: $(HTML)TITLE := Xueshan Wang — Resume$(HTML): $(SRC) $(CSS) split-headings.luapandoc $(SRC) -o $(HTML) --standalone --css=$(CSS) \  --lua-filter=split-headings.lua \  --metadata title="$(TITLE)"pdf: $(PDF)$(PDF): $(HTML)weasyprint $(HTML) $(PDF)its: $(PDF_ITS)$(HTML_ITS): $(SRC_ITS) $(CSS) split-headings.luapandoc $(SRC_ITS) -o $(HTML_ITS) --standalone --css=$(CSS) \  --lua-filter=split-headings.lua \  --metadata title="$(TITLE)"$(PDF_ITS): $(HTML_ITS)weasyprint $(HTML_ITS) $(PDF_ITS)fe: $(PDF_FE)$(HTML_FE): $(SRC_FE) $(CSS) split-headings.luapandoc $(SRC_FE) -o $(HTML_FE) --standalone --css=$(CSS) \  --lua-filter=split-headings.lua \  --metadata title="$(TITLE)"$(PDF_FE): $(HTML_FE)weasyprint $(HTML_FE) $(PDF_FE)watch:@command -v entr &gt;/dev/null || { echo "install 'entr' (pacman -S entr)"; exit 1; }@ls $(SRC) $(CSS) | entr -c make pdfopen: pdfxdg-open $(PDF)clean:rm -f $(HTML) $(PDF)</code></pre><p>使用方法很简单：</p><ul><li><code>make pdf</code> 来自动执行 Pandoc 和 WeasyPrint 操作</li><li><code>make watch</code> 用 <code>entr</code> 监听文件变动后自动重新构建</li><li><code>make open</code> 用 <code>xdg-open</code> 来打开 PDF，供我们浏览</li></ul><p>好了介绍完我的简历生成工具后，重新说回 JobScan。我事先弄了个统一的简历，写上必须要带上的信息后，就会上传这份简历到 JobScan，和任何我想要申请的岗位配对。大多数时候，JobScan 会直接给个 20 到 40 分左右，惨不忍睹。不过没关系，我们可以拷贝一份简历出来，专门对该岗位进行定制化。</p><p>JobScan 会扫描出所有该岗位有可能会视作关键词的内容，例如技术栈、技能，还有软实力要求。我发现许多找计算机领域岗位的人们，对软实力没有概念，以为只要努力刷题、做项目就可以找到工作。实际上，软实力非常重要。</p><p>因为我自己就有个「公司」，也和其他开公司的人打过交道，觉察出站在企业老板，或者部门招聘人员的角度来看，他们很多时候要的仅仅是个 vibe，也就是「氛围」。硬实力重要么？如果真的那么重要，为什么会有那么多草台班子公司？再加上一个人的氛围，决定了他未来在公司里好不好一同共事。</p><p>当然最基本的硬实力还是要有的。你总不能没刷过题就去申请算法岗吧 —— 坏了，我怎么记得之前有人跟我吐槽过公司里招了个什么都不会的人。</p><p>好了大致的投简历环节说完了。接下来还有拿到面试的面试环节…… 但我不打算对这个展开聊聊。你要问我为什么，理由很简单，因为我现在还没拿到面试啊！不过值得高兴的是，在我开始用 JobScan，截止到现在，都还没有出现任何拒绝信。我希望未来是光明的 —— 大概吧！</p><p>但我想聊聊美国的内推文化。印象里中国没有这东西，因为过去还在用小红书的时候，就有看到国内的人吐槽有留学生回国找工作，找到了自己并想要约出来了解行业内情以及要内推。他当时说的是，这些事情根本就不会有人说，已经很忙了还要被叫出来 coffee chat。</p><p>这种行为在美国被称为 <u>信息面试</u>（information interview），别名也叫 <em> coffee chat</em>、<em>networking</em>…… 其实就是主动约在业人士出来喝咖啡，建立关系、获取内推机会，亦或者是认识其他更有地位的人。</p><p>所以主动给陌生人、校友、LinkedIn 联系人发 cold message 约出来喝咖啡，在美国是件很常见的事情。不过因为我并不乐意和陌生人主动交流，所以我很难去体会这件事…… 这也是我不得不克服的事情。因为常见，甚至都有完整的话术体系。网上有大量的资料教人们如何写 cold email、如何聊天、聊完怎么跟进…… 是的，它是求职的必修课。</p><p>我对国内的印象是，中国人会将这种行为视作为「走后门」，且就算要走后门，也是给已经认识的人走，而不是给陌生人这个机会。我自己也不喜欢内推文化，仅次于酒桌文化和小费文化。它很容易发展成 nepotism，也就是裙带关系，真正的「走后门」。</p><p>相当带有种族偏见的是，美国有很多声音表示讨厌印度人。他们简直是内推文化的最佳受益者，因为他们不在乎要内推会不会尴尬，满眼都是对工作的渴望。这一点来源于硅谷的科技行业，那有着很成熟的印度生态圈，从校友会、专业组织，到投资圈，都有着完整的链条。</p><p>讨厌印度人则来源于他们的「抱团文化」。人们普遍认为，印度裔群体在大公司中层与高层占据了话语权，掌控了招聘、晋升和预算。甚至还有名言：「只要印度人和其他人起冲突，公司里其他印度人会无条件支持印度人。」</p><p>过去在华人圈混迹时，我总结了一些印度人和中国人的区别 —— 当然并非指代所有印度人或所有中国人。嗯这种话我有必要声明么？首先是印度人的母语就是英语，就算他们有着极其魔性的口音，那也是英语。英语作为第二语言的中国人，普遍有着较低的表达自信度以及表达欲望。这一点我在我身上也发现了。</p><p>其次是中国人有着谦逊文化，不善于推销自己。这在美国是个很大的劣势。外向、愿意自我推销的人，在美国活得更滋润。</p><p>我这几个月来一直在断断续续阅读《大教堂与集市》，目前读到了第三章。这本书我在 Fediverse 上有条专门的 <a href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ2PNX9796VGQXW83XK17R6G">笔记嘟串</a>。第三章的重点在于，驱动黑客文化的并非经济价值，而是自我满足和同僚声望，也就是 <em> egoboo</em>。但是黑客们并不愿意承认这一点，自我主义对他们而言是可耻的。他们所做的各种事情，在他们口中都是「无私」、具备「专业素养」的，但又真的如此么？</p><p>我还在学习期间，不过我确实发现了黑客们缺乏自我营销的能力，以及渴望。这被作者 Eric Raymond 认为是谦逊文化。既然如此，同样普遍存在着谦逊文化的中国人，是否就会导致两两相加、双倍的谦逊呢？至少对我而言，是这样的。</p><p>最后是中国人的组织很分散。据我对在美华人的观察和了解，内部斗争相当常见。福建人里，可以根据所在的城市或者县城分成多个帮派，互相鄙视来鄙视去的；说粤语的歧视说福建方言的，说粤语里的人又可以分成广东人和香港人，也会互相看不顺眼；融合了一些西方文化的，瞧不起不会说英语、更带有中国文化底色的人；完全融入了西方文化，比方说 ABC（American-Born Chinese，在美国出生的华裔后代），觉得说汉语很丢脸；新移民与老移民之间的斗争更是说不完；哦天呐，我们还有政党斗争，支持中国共产党的 v.s. 支持美国民主党的 v.s. 支持美国共和党的 —— 把除了我以外的华人都赶出美国、让美国再次强大！</p><p>由此可见，内部斗争有多复杂、多常见。</p><p>再加上华人圈总是会被一种被西方社会审视的紧张感存在，即刚才说到「ABC 觉得说汉语很丢脸」。这种紧张感源自于东西方文化的差异，被简单地划分成了「土」和「现代化」这对黑白。类似的批评有，「中国人都吃狗肉，太恶心、残忍、<span class="emphasis">落后</span> 了！」我发现很多中国人对此的回应是，「我不吃狗肉」，但这正中下怀，因为你根本不需要去接受对方说的「吃狗肉等同于落后」的逻辑。一旦你也开始认为「吃狗肉等同于落后」，那么你就间接性地证明了「吃狗肉的中国人都落后、多数中国人吃狗肉，因此中国人多数是落后的」这一逻辑。</p><p>我喜欢狗，并不会吃狗肉，又是为什么呢？因为我讨厌偷狗贼，以及为了刺激小孩子、杀狗吃的大人们。他们无疑是可恶的，但不能直接认为是食用狗肉有问题。文化是文化，不符合西方标准的文化就是落后的文化么？这是殖民思想，不可取。思想过于狭隘才是落后。</p><p>关于美国华人圈，尤其是底层华人圈的事情，一直都想要聊聊，但介于一些个人因素，决定还是放着不管…… 未来再说吧。</p><p>总之回到内推文化一事，我也只能入乡随俗了，毕竟没有钱才是最可怕的。在我习惯这东西之后，我会再写一篇文章跟进。</p><p>最后的最后，让我以我和一位亲戚之间的谈话作为结尾吧，希望能对所有对找工作、未来迷茫的人有所帮助。这位亲戚是个远房亲戚，远到我都没有见过他。和他通电话，也是母亲为我「预约」的。这又要谈到父母对我找不到工作的焦虑，又或者说是「我不如他人」的焦虑。反正这种事情也不是第一次了，早在以前、高考时，都发生过一样的事情，让人心烦。</p><p>亲戚作为税务公司的老板，给出了新的视角，即跨学科岗位的重要性。用他的话来说，他越来越不需要只会当会计的人，因为太多了，并且不会给自己的公司带来突破。专才在现有的公司里，最多成为金子做的螺丝钉。螺丝钉不论是生锈的，还是金子做的，都只会是螺丝钉。但跨学科的泛才不同，他们有着更广的视角，能看到专才看不到的东西，并且将两个学科的工作结合在一起，那他们就可以变成齿轮，不单单是个小小的螺丝钉。</p><p>于是我去思考了下自己的定位。我不太适合待在科技公司内，因为我并没有那么 <em> tech</em>，又或者说「硬核」么。我不喜欢算法、没刷过题，做的事情也更多是面向业务逻辑的。这种情况下，纯写代码已经不够有竞争力，理由便是 AI 工具的诞生。大量基础的编码工作被交给它们来处理，但去理解业务问题，并用代码解决的人还没有多到数不清。</p><p>调查后我发现，常见的组合有：CS 兼医疗或生物信息、金融或量化、制造或工业、法律或合规、AI 应用落地 —— 最后这个是今年最火热的需求，出于各种我们都熟知的原因。</p><p>因为居住在纽约市这个金融大区、学校是商科学院，还有 AI 应用这玩意儿的火热…… 我给自己暂且定下来的目标是 FinTech + AI 应用。</p><p>实际上在和业内人士聊天期间，我发现这类传统行业在科技方面，可以说是还未跟上潮流，那我喜欢阅读博客文章、新闻的兴趣爱好也能派上点用场。像是一些传统行业的大厂，还在慢慢学习使用在科技领域里已经被淘汰的框架。</p><p>所以说，也不要把目光锁定在科技巨头身上。要把视野再放宽一些嘛。</p><p>和这个亲戚聊完后，我设立了新的学习目标，并打算把学业扔到一边去。破大学，爱上不上！当天也有另一位亲戚在家中拜访，和我聊了聊人的优势。他的大儿子今年十岁左右吧，患有 ADHD。虽然听上去是个缺陷，但他发现儿子在做自己喜欢的事情时，会比其他人更加关注。而这件事就是做机器人 —— 好刻板印象啊！</p><p>每个人都有自己的特点，而我们应想办法将特点转换成优势。我时常觉得自己不够好，是因为把自己放在了错误的环境。科技巨头里人人都会写代码，狗写的代码都比我写得好。但如果我跑到另一个领域内，成为了那里唯一一个会写代码的，不就行了吗。</p><p>初三的时候，申请的高中要开始决定收还是拒绝我们。当时的班主任，虽然是个很讨人厌、很烦的大妈，但她说的一句话我现在才搞明白有多重要：「就算去了不是最顶尖的学校，你也能在其他不够顶尖的学校里闪耀着光芒。」</p><p>祝我求职顺利！</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;虽说上个月就在求职，但一直都没能拿到面试，拒绝信收得也很快。这个月因为各种事情，比方说经济方面的焦虑、室友带来的压力、父母带来的压力等等，都让我深觉沮丧和焦虑。焦虑就不用说了，沮丧是因为我认为自己的经验并不差，简历上连玩具项目都没有，全都是我真实参加过、和别人合作过，甚至有盈利的项目。作为本科还未毕业的人，我心想这已经足够让我找到一份实习了吧？但事实是没有，我收到了大量的拒绝信。&lt;/p&gt;</summary>
    
    
    
    <category term="求职" scheme="https://blog.cytrogen.icu/categories/%E6%B1%82%E8%81%8C/"/>
    
    
  </entry>
  
  <entry>
    <title>我开始有健康的生活习惯了</title>
    <link href="https://blog.cytrogen.icu/posts/f118.html"/>
    <id>https://blog.cytrogen.icu/posts/f118.html</id>
    <published>2026-05-31T04:00:00.000Z</published>
    <updated>2026-05-31T22:21:42.174Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>不知道是否有读者还记得，<a href="/posts/5586.html#%E5%BD%93%E6%88%91%E8%B0%88%E6%99%A8%E8%B7%91%E6%97%B6-%E6%88%91%E5%9C%A8%E8%B0%88%E4%BA%9B%E4%BB%80%E4%B9%88">上个月</a> 我因为自己没有运动的习惯而感到沮丧。这个月，准确来说是五月十三日。这天凌晨，我和别人吵了一架，气冲冲地睡着了。然后睡了三个小时，早上六点多醒来，突然萌生了想要运动的想法。尽管只是骑自行车，但总比躺在床上刷手机好吧。</p><span id="more"></span><p>这个冲动让我坐了起来，思考着既然要出门骑车，那我要去哪里呢？我忽然想到，这么早的话，我是不是可以去吃个早餐？我的生活作息糟糕到，一天的第一顿饭可能是下午才吃。七八点的早饭相当罕见。</p><p>我又开始想，吃早饭的话，吃什么好呢？家附近貌似只有咖啡店和面包店会七点开门，但我不喜欢喝咖啡，也不喜欢吃面包。大脑深处的某个记忆片段，随着我对食物的联想，觉醒了！—— 我要吃肠粉！</p><p>好吧，其实并不是因为我有多么爱吃肠粉，而是我能想到的，这里能七点开门的食物只有广式或港式早点。肠粉则是我在早点内最喜欢的一类。我小时候的生活习惯，早上是要喝粥的，尤其是小米粥和南瓜粥。再配个饼或者茶叶蛋，嘿嘿，不过我所在的地区毕竟是广东人或香港人还有福建人扎堆的地方，这些食物并不常见…… 又或者我可以直接吃正餐：嗦面。可惜面馆在这儿都是十一点才开门。</p><p>总之我换好衣服出门，用 Transit 这款 app 导航，一路从中城骑到了唐人街。Transit 作为骑行导航的一大好处是，它会根据 Openstreet Map 内更细致的内容，来生成一条能尽量待在 protected bike lane（受保护的自行车道）内的路线。这对我来说实在是太爽啦！我真是受够了那些要和汽车近距离贴在一起的路。</p><p>不过 Transit 不会像 Apple Maps 那样，告诉我第几个路口或者红绿灯要转向，反而是像 Google Maps 一样，告诉我多少米后再转向 —— 我又不是机器人，我怎么知道多少米是哪里！但仔细听它报的街道名，再找到正确的街道名并转向，也是个不错的体验。</p><p>去唐人街的路上，本来以为会很远很累，实际上仅花了 20 来分钟。要知道我坐地铁的话，过去也差不多是这个时间。还了共享单车后，我意识到一件事：我没有做足计划，不知道去哪家店吃肠粉好。</p><p>因为我没有小红书了，所以看不到本地华人们真挚的推荐 —— 要是软广不存在的话。我决定用 Kagi Assistant 帮我结合 Yelp 这类平台，帮我找出最推荐的字号。最终它建议我去「银记肠粉店」。</p><p>这家店的装修怎么说呢，用了很多国潮元素。整体的颜色和风格，一点都不像是当地的夫妻小店，反而像是连锁快餐店。播放的音乐是英语流行乐，特别大声，更没品了。</p><p>我点了最喜欢的虾肠粉，还有港式奶茶。味道不错，上菜速度很慢，所以合理怀疑是现做的。吃完后又给室友买了份。当时我打电话叫醒她，并让她猜猜我在哪里时，她很是吃惊。</p><p>回家路上我又听室友的指令、买了只三皇走地鸡回家 —— 为我之后体重破记录一事埋下了伏笔……—— 感觉一天充实了许多呢！回家自然也是骑车回去的。我和室友共享了 Citibike 会员，一年 200 多块钱，每个人对半劈就是 100 多。作为会员，骑普通自行车前 45 分钟都不花钱。而坐地铁，我要花 3 块钱。哪个最值当，我想我不用多说了吧！</p><p>骑车回去，经过了一段根本不是给人骑的路…… 以至于我的鸡和肠粉的酱都被震到了地上。本来很生气的，但想到这又不是给我吃，一下又觉得开心起来。我真是邪恶。</p><p>单单一天的骑车，就能说成是我有健康的习惯了么？当然不是！那天的骑车，还有五月的大太阳，让我意识到运动的美妙！于是接下来的日子里，我变成了单车超人……</p><p>首先是打工回家，我都会骑自行车回来。差不多是 4.5 个英里的距离，我骑车的速度很慢，时间只能维持在 46 到 50 分钟之间。</p><p>再就是我会有骑车去很远的地方的冲动。五月十五日我早上醒来决定去见一位朋友。如果坐地铁的话，我到他家至少得半个小时吧。但我偏不，我要挑战自我、挑战极限！所以我要骑自行车过去。大致花了 104 分钟，骑了多少英里不清楚。Citibike 这个 app 居然查看历史记录时，不会显示距离。</p><p>这期间我有无数次想要放弃…… 没办法，我平日就不运动，身体很弱。但坚持下来的感觉，也很棒。路上我经过了许多从未经过的社区。整体的感想和我年初 <a href="/posts/53f4.html">走半马</a> 时很类似。不过那次我是和别人边走边聊天，这次我只有一个人。</p><p>惊喜的是，我不停在骑行一事，传染给了室友。她和我不同，是愿意跑步的，并相约每周都选一天出来运动：她跑步，我骑车。我们可以去唐人街，逛超市、买更便宜的菜，还有三黄走地鸡！这种鸡的肉实在是太鲜嫩、好吃了。室友的做法很简单，锅里放椰子水，煮开后下鸡肉，直到它们的体内温度到 70 度左右，捞出蘸酱吃。这个酱其实就是海鲜酱油，配香菜、小米辣和柠檬汁，特别好吃。</p><p>因为煮起来很方便、很快，我这个厨艺白痴也能做，所以做饭对我来说不再有阻力。我不得不去承认一件事，那就是我很懒，很懒，很懒…… 因为懒，一整天都不吃饭的事情也发生过，对自己的身体实在是不珍惜。也因此，我的身体状况挺差的，BMI 常年在不健康的范畴。整个人就是个皮包骨，没点肉。</p><p>但是现在不一样了，我吃饭可以自己煮鸡肉。配点喜欢的上海青作配菜，主食随便选米饭或者面条就行。这样吃了几天，我的体重竟突破了最高记录！</p><p>今天本是为了写月刊，所以在复盘日记内的内容，结果写完这一段，意外觉得还挺感动的。我从初中开始便维持着同样的身高和体重，到现在大三结束，都不见任何变化。未曾想，我某天醒来所有的冲动，打破了这个「不变」。说实话，也不是什么特别大的事情，但这种长期静止不前的小事情，还是很戳我的泪点的 —— 我的意思不是我有哭，我只是很感动而已！</p><p>说来那天早上的冲动，也有一些是出于我上个月引用的胡拉图的 <a href="https://hulatu.com/posts/2026/04/12/morning-run/">文章</a>。当时我的想法就是简单的「晨练可以让接下来的工作效率变高」，最后因我大脑的跳跃性，一路演变成「我要骑车去唐人街吃肠粉」。</p><p>这又让我想到，今天阅读的一篇文章，名叫 <em> Being Small</em>。虽然内容和我想要聊的事情完全不相关，它是讲家庭暴力中那些细小的暴力行为的，不过我想要借它的标题一用 —— 我因为阅读了一篇文章，记在心里的很小的想法，竟推动了一连串小小的事情，最后达成了小小的，但对我来说意义很大的目的。我希望我能一直持续下去，并见证它们像推雪球一般，未来会变得多大。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;不知道是否有读者还记得，&lt;a href=&quot;/posts/5586.html#%E5%BD%93%E6%88%91%E8%B0%88%E6%99%A8%E8%B7%91%E6%97%B6-%E6%88%91%E5%9C%A8%E8%B0%88%E4%BA%9B%E4%BB%80%E4%B9%88&quot;&gt;上个月&lt;/a&gt; 我因为自己没有运动的习惯而感到沮丧。这个月，准确来说是五月十三日。这天凌晨，我和别人吵了一架，气冲冲地睡着了。然后睡了三个小时，早上六点多醒来，突然萌生了想要运动的想法。尽管只是骑自行车，但总比躺在床上刷手机好吧。&lt;/p&gt;</summary>
    
    
    
    <category term="日常生活" scheme="https://blog.cytrogen.icu/categories/%E6%97%A5%E5%B8%B8%E7%94%9F%E6%B4%BB/"/>
    
    
  </entry>
  
  <entry>
    <title>观 *Obsession*</title>
    <link href="https://blog.cytrogen.icu/posts/8513.html"/>
    <id>https://blog.cytrogen.icu/posts/8513.html</id>
    <published>2026-05-25T04:00:00.000Z</published>
    <updated>2026-05-25T17:58:20.885Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>五月了，夏天到了，是时候品尝一些恐怖片了。</p><span id="more"></span><h2 id="电影前"><a class="markdownIt-Anchor" href="#电影前"></a> 电影前</h2><p>去年看 <em> FNAF 2</em> 时，看到了 <em> Obsession</em> 的预告，很感兴趣。因此决定和跟我一起吃了 <em> FNAF 2</em> 这坨臭狗屎的朋友再来看 <em> Obsession</em>。</p><p>它的预告片有趣在哪儿呢？和一大堆只要看了预告片就能知道电影大致讲的什么的恐怖片不同，它的预告片仅截取了电影中的一段。你好像知道故事是什么样，但是你又模模糊糊不知道。</p><p>最后再说一次，不想要被剧透的不要往下看。</p><h2 id="电影中"><a class="markdownIt-Anchor" href="#电影中"></a> 电影中</h2><p>电影内容整体来说没有破坏我的预期。开头角色们的简单塑造我还挺喜欢的，所以接下来的崩坏令我惋惜 —— 奇怪，我为什么会在恐怖片里渴望看到幸福的人们？</p><p>故事主要以 Bear 为重心。他暗恋好友 Nikki 许久，想要表白，但又没有这个胆子。另一位好友 Ian 一直在作为「军师」帮他。</p><p>除了这三个人，小团体里还有个 Sarah。所以是两男两女的经典组合，他们不仅是彼此的朋友，也是同事。</p><p>一天回家，Bear 发现自己的小猫 Sandy 误食了药物、死掉了。精神受到打击的 Bear，得知 Nikki 丢了项链，恍惚间去商店购买了名为 <em> One Wish Willow</em> 的玩具，并认为这可以让 Nikki 打起精神。</p><p>四人晚上去酒吧玩。Ian 看出 Bear 很想跟 Nikki 说话，怕傻哥们儿直接表白，所以不停在搅局。不过最终还是因为 Nikki 想要提前回家、Bear 愿意送他，让他们二人有了独处的空间。</p><p>这里有个小桥段，是 Nikki 借了钱并施舍给酒吧门口的流浪汉，表明她是个很善良的人。和 Bear 车上独处这段时间，我们还能得知，Nikki 实际上在写作创作。她否认 <em> love story</em> 等同于 <em> romance</em>，因为后者会有圆满的结局，而前者不一定。</p><p>单靠这段就写作的对话，我们便能看出，Nikki 心思要比 Bear 细腻许多 —— 实际上在后来我们还能发现，几乎所有人的心思都要比 Bear 细腻，也是很搞笑了 —— 尤其是 Nikki 回家前，Bear 还像个大傻子称呼她为 <em> Freaky Nikki</em>。要知道，这是 Nikki 以前在学校被霸凌时，霸凌者们给她安的称呼。这激怒了 Nikki，觉得 Bear 心里有鬼。在 Bear 不断地道歉时，她直接询问 Bear，是不是喜欢自己。</p><p>出于被拒绝的恐惧，Bear 选择否认。这让他接下来懊悔不已，拿出许愿玩具，许愿让 Nikki 爱自己胜于所有人。</p><p>我本以为这个场景结束后，荒诞要等到下个场景才会开始出现。结果好家伙，Bear 刚许愿完 Nikki 就出现在了他的车旁边，嚷嚷着要去 Bear 家里，还说自己父亲有了癌症、要死了，不想一个人待着。对于 Bear 而言，脆弱的女神需要自己，自己哪能拒绝。结果 Nikki 要求要和 Bear 一起睡，并尝试吻他。Bear 耐不住，想要抱她、回应她 —— 未曾想 Nikki 突然尖叫起来，推开 Bear，然后又哭着道歉，说自己精神状态不太好。</p><p>我对前期 Nikki 时而抽搐的行为，认定为此时「邪灵」（姑且如此称呼）并没有完全占据 Nikki 的身体。推开 Bear 的是真正的 Nikki。后面也说了，Nikki 过去承认道只把 Bear 当弟弟看待，如果 Bear 向自己表白，就给他发好人卡。</p><p>到了第二天早上，荒诞的事情开始慢慢发生……Nikki 将 Sandy 做成了纪念物，想要送给 Bear。作为任何心理健康的人，都不会想要去世的爱宠被别人从垃圾袋里掏出来、做成莫名其妙的纪念物吧！因此 Bear 很不高兴。</p><p>上班期间，Bear 赶紧把事情告诉 Ian，Ian 则认为不可能。谈话期间，站在前台的 Nikki 一直笑眯眯盯着 Bear，相当惊悚…… 电影最开始可爱的 Nikki 去了哪里！</p><p>Nikki 则将错归给了摇头丸，说自己有在吸食毒品，所以才会做这些疯狂的事情。接着她向 Bear 表白，两人成为了恩爱的情侣，全剧终……</p><p>…… 个鬼啦。其实我原本以为这一幕，是 Bear 在幻想，看来是我更刻薄一些么。总之在他们恩恩爱爱的一场约会中，Ian 打来电话。他早觉得奇怪了，自己也是 Nikki 的好 homie、知道 Nikki 对 Bear 不感兴趣，怎么突然两个人甜蜜起来了？</p><p>Ian 还透露，Nikki 说的什么父亲患癌，根本都是假的。Nikki 讨厌自己的父亲，早就和父亲没有任何瓜葛，父亲也健康得不得了。Bear 害怕地察觉出，Nikki 对自己的喜欢恐怕是出于愿望，而非真心。</p><p>在 Bear 的询问下，Nikki 在公共场合哭喊起来，并反问 Bear 这真的重要么？Bear 为了让她安静下来，只能同意说确实不重要。</p><p>晚上睡觉时，Bear 发现身边的 Nikki 不见了，接着发现她站在房间的角落。我当时看的时候，发现房间里同时有两个「人」的形状，很奇怪。接着发现左边明显是挂起来的大衣，那右边的是…… 果然是 Nikki 啊。不得不说，Nikki 一会儿甜美一会儿尖叫的反差，是这部电影的核心恐怖点。不过出现的次数过多，到后面便变得好笑起来。</p><p>在 Bear 的质问下，Nikki 说自己只是在看他睡觉，太可爱了没办法。接着哭泣道说 Bear 不像自己爱他那样，爱着自己 —— 不，这种话，不要再说了！难道每个浪漫关系都要经历这句话么！</p><p>次日 Bear 要上班出门，发现 Nikki 竟然用胶带将前门封死。Nikki 一边说自己会很想 Bear，一边说要是 Bear 开不了门的话，可以直接不去上班的。而 Bear 做的竟是，强行把门打开，然后喃喃道「没关系」…… 实在是过分荒诞了。</p><p>Bear 走后，有一段 Nikki 一边笑着，一边望着他离去的背影，一边失禁的场景。我很好奇为什么导演要专门做出来「失禁」的画面？我的第一反应是狗。</p><p>午餐期间他一边吃着 Nikki 带给自己的三明治，一边和 Sarah 有一句没一句地说起话来。Bear 发觉 Ian 开派对竟然不带自己，并质疑 Sarah 为什么要在背后跟 Ian 谈论 Nikki。</p><p>在前面和真正的 Nikki 在车上独处时，Nikki 其实问过 Bear 对 Sarah 有没有感觉。Sarah 认为 Nikki 有问题，而且会伤害到 Bear，但这种关心被 Bear 解读成「讨厌 Nikki」，还生了气。两人快要吵起来，且在 Sarah 决定揭露出什么的时候，她的父亲过来打断了她：原来是 Sarah 一直在申请入学艺术学校（为了成为纹身师），而父亲带来的是学校的拒绝录取信。她还有最后一所学校的申请结果不知道 —— 不过我们都知道，故事一旦半场便开始塑造「希望」，那么即将迎接「希望」的角色最终都会迎接「死亡」。</p><p>就算是 Bear，也知道这时候不该继续和朋友吵架，于是安抚起了 Sarah。</p><p>以为这个场景结束了吗？才没有呢！被俯身的 Nikki 总是能给我们惊喜：她将 Sandy 做成了三明治，并在 Bear 的午餐盒上写下「『猫』你打几分？」的字眼。我这个时候特别想要吐槽，导演对猫是有什么恨意在吗？快一小时过去了这个猫来来回回被折腾了足足三次！</p><p>Bear 呕吐后，晚上下班顺便载着 Ian 回家。Ian 路上吐槽道，明明 Bear 前不久还跟自己说 Nikki 出了问题，怎么现在又恩恩爱爱起来了。Bear 的回答是，Nikki 磕了药，她好好的、没事。二人也就「Ian 开派对不带自己」一事吵了起来。</p><p>Ian 回应道，他觉得 Nikki 正在经历什么，并且 Bear 正在趁人之危，毕竟 Bear 喜欢 Nikki 也不是一天两天了，他才不想要邀请二人来派对。这激怒了 Bear，觉得 Ian 正在毁掉好的事情，还说明明是 Nikki 无法离开自己。从这一段可以看出，Bear 对好友的质疑起了防御心理，不断地美化他和 Nikki 的恋情、否认他人的怀疑。Ian 吵不过，说既然你觉得你俩的关系是健康的，而非建立在相互依赖之上的话，那你完全可以靠「一个人来我的派对」证明。那样的话，其他人也能明白二人的恋情是健康的。</p><p>Bear 回家打算跟 Nikki 说自己晚上要去 Ian 家参加「男生之夜」前，在车上发现了另一个许愿玩具，并看到玩具生产公司的电话号码。他打电话过去，想要修改自己的愿望。</p><p>电话那头儿起初像是随处可见的客服，帮「把玩具信以为真」的客人随便排忧解难。Bear 得知，愿望不仅不能被修改，也不能被取消，将会直到自己生命终结之时才会结束。</p><p>然后，未曾想电话的另一头竟主动问 Bear，是否想要和 Nikki 谈谈。紧接着，电话传来 Nikki 的尖叫声。恐惧让 Bear 赶紧关掉了电话。</p><p>我对这个尖叫声的解读是，真正的 Nikki 的尖叫。先前也能看出，真正的 Nikki 时不时会突然出现，例如和 Bear 初次接吻时，她突然推开 Bear 并大喊 <em> what the fuck!</em>，但又马上开始道歉。推开 Bear 的是真正的 Nikki，道歉的是虚假的 Nikki。</p><p>回家开灯，发现 Nikki 竟然浑身都是呕吐物和排泄物，站在 Bear 出门上班前所站在的位置，一直不开灯地在等他回家。Nikki 洗澡期间，Bear 站在门外说自己要去「男生之夜」，却被 Nikki 揭穿明明 Sarah 这个女生也会去。在 Nikki 尖叫和哭喊着「如果你想要我去的话，早就会让我一起去」后，Bear 妥协带上了 Nikki。</p><p>派对开始时，Bear 和 Ian 的对话也很有趣。Ian 说早就知道 Bear 会带 Nikki 来，Bear 反过来说是 Sarah 邀请 Nikki 来的，并且怪罪 Ian 没有按照原本说的那样、不让 Sarah 来。Ian 回答说 Sarah 没做错什么，Bear 反呛道「我们也没做错什么」。</p><p>派对游戏中，Nikki 开始读自己写的 <em> love story</em>。很明显，这并非真正的 Nikki 之作，因为小说内容是改编后有了更多色情、血腥和乱伦情节的 <em> Hansel and Gretel</em>，即《糖果屋》。</p><p>这一念，大家全都尴尬了起来……Bear 继续游戏，抽到的大冒险是亲吻坐在左边的 Sarah。这一段近乎让影院笑场了：一是出于 Nikki 听到后的愤怒表情；二是出于 Sarah 看到 Nikki 的表情后、做出的皱眉以及疑惑的表情；三是 Nikki 摆着同样的表情走到一直在皱眉和无语的 Sarah 后面，将对方挪开，然后跑到了 Bear 的左边、索吻；四是其他朋友们的尴尬表情；五是 Sarah 紧接着站了起来表达不满；六是 Nikki 被吻后，对着所有人说的「玩笑话」。因为不好笑，没有人笑，她还耸耸肩表示那就这样吧。</p><p>然后，Nikki 突然尖叫着往后退去，大喊着 <em> It's not me!</em>，摔碎了玻璃杯并打在自己头上。这吓坏了所有人，除了 Bear…… 是的，他冷漠地坐在自己的椅子上，尽管 Ian 一直骂他叫他站起来、带 Nikki 去医院，他依然一点表情都没有地坐在那儿 —— 回避型人格啊。</p><p>二人回家后，Bear 问她为什么要这么做，得到的回答是「我知道 Sarah 喜欢你」。这让 Bear 一直绷着的神经断开，控制不住地尖叫道「原本一切都好好的！」—— 也就是说，Bear 实际上很需要一场正常的社交，向他人证明自己和 Nikki 的关系是健康的。</p><p>他又向眼前的 Nikki 问道，「你喜欢我吗？你真的喜欢我吗？Nikki 开心吗？Nikki 喜欢我吗？」这便是 Bear 面临的另一个问题：他明知现在喜欢自己的 Nikki，是因为愿望才喜欢上自己的。虽然愿望实现了，但并非自己想要的。自己想要的是，Nikki 发自内心喜欢上自己。</p><p>而 Nikki 答道，<em>Yes. I'm your Freaky Nikki.</em> —— 真正的 Nikki 怎么可能说出这种话？——Bear 要 Nikki 回家，让二人彼此有点空间。邪灵俯身的 Nikki 怎能答应？她哭起来，说自己可以变成真正的 Nikki，只要是 Bear 想要的，她都有。这些回答，又恰恰不是 Bear 想要听到的。</p><p>接下来的恐怖桥段，像是为了恐怖而恐怖，我并不是特别喜欢。总之 Nikki 拿刀出来，威胁说要么自己自杀，要么二人好好留下来。最终 Bear 选择了留下来，又度过了心惊胆战的一晚……</p><p>半夜，Sarah 发来消息，说想要和 Bear 见面，有重要的事情要说 —— 不，不要啊！——Bear 偷偷爬下床，听到 Nikki 又如往常那样，醒来并发现自己不见…… 不，好像不一样。这个 Nikki 竟然一边睡着，一边发出脆弱的声音，苦苦哀求 Bear 杀掉自己。</p><p>原来，这是真正的 Nikki，趁着邪灵睡着后，向 Bear 求助。而 Bear 这个顶级窝囊废，所想的竟然是「你不想要和我在一起，不想要到想要去死」。真正的 Nikki 回应道，「我从来没有和你在一起过。」被否认了的 Bear 恼羞成怒，竟无视 Nikki 句句 <em> please</em>，跑了出去见 Sarah。</p><p>Bear 和 Sarah 的场景，怎么说呢…… 处处都弥漫着 Sarah 很快便要领便当的气息。不过我还是挺喜欢这一段的，主要是因为 Sarah 指出 Nikki 在利用自己的「痛苦」，道德绑架 Bear，毕竟她并不知道 Bear 喜欢 Nikki。</p><p>Bear 竟拿出先前早就被否认的「父亲有癌症」一说，为 Nikki 开脱。在听到 Nikki 在利用自己这一说法后，Bear 明显慌张了。这和先前 Ian 的那场戏正好相反。Bear 摇身一变竟成了受害者。他没能继续回答下去，只是苦笑一声。可是，他刚刚才拒绝了真正的 Nikki 想要解脱的愿望。</p><p>Sarah 拿出信封，说这是来自最后一所美术学校的通知书，并表示想要和 Bear 一起打开来看。接着她又说道，自己很担心 Bear，因为 Ian 曾经和 Nikki 断断续续以肉体关系交往了大概两年，Ian 认为 Nikki 和 Bear 交往是为了报复他 —— 我们作为观众，自然已经知道 Sarah 的申请结果会是什么，以及 Nikki 和 Bear 交往是因为愿望。我们也知道接下来会发生什么……</p><p>Sarah 说，就算不是这样，也认为 Bear 需要一个更稳定的人，比如自……Nikki 突然拿着板砖砸碎了车窗玻璃，并不停用其殴打 Sarah 的脸部、杀了她。这个场景特别血腥，所以才是 R 级电影的理由吧。</p><p>我先前说 Bear 是顶级窝囊废，这个场景也贡献了几个证据：在 Sarah 想要暗示自己对 Bear 有好感时，Bear 接了句话，说「更稳定的人，比如你么？」我们站在上帝视角，已经知道 Bear 从 Ian 还有 Nikki 那儿得知，Sarah 喜欢自己。此时，却要如此暧昧地接话么？明明也可以说别人的吧？</p><p>另一个便是，Nikki 杀了 Sarah 后，让 Bear 帮自己处理尸体。然后，他就那么做了…… 嗯…… 帮助 Nikki 搬走了昔日好友 Sarah 的尸体……</p><p>Nikki 让自己回家休息后，Bear 一个人坐在车上，看向还未开封的申请通知书。一打开，果然，Sarah 被最后一所艺术学校录取了。Bear 麻木地看着信，内心深刻有什么被撬动。无法再绷住的他，呐喊、哭泣起来。他跑到一开始的商店，辱骂店员售卖许愿玩具这种邪恶的东西，却意外得知一个解决方法：重新许个和原本愿望相矛盾的愿，不就行了？</p><p>在尝试了许新的愿望但失败后，Bear 跑去找 Ian 帮忙。Ian 看到满身都是血的 Bear，也绷不住了，骂他问到底发生了什么、Nikki 怎么了、为什么 Sarah 开始给自己发奇怪的信息、叫自己去 Bear 家？—— 这也暗示了 Nikki 已经接管 Sarah 的物品。</p><p>Bear 终于向 Ian 坦白，Nikki 喜欢上自己，是因为自己许了愿望。他希望 Ian 可以许个「自己从未许过愿望」的愿望。但是他为了 Ian 许愿，加上一句「这样的话你就可以和 Nikki 在一起了」。这句话反而激怒了 Ian，认为是 Bear 出于忌妒在故意搞他，所以许愿说要钱。在 Bear 的尖叫中，美元们就这么从天上掉了下来……</p><p>没办法，Bear 拿着许愿玩具又去找 Nikki—— 不要问为什么不找其他朋友，故事总是要有戏剧性的 —— 结果一回家发现客厅里放着诡异的祭坛、死去的 Sarah 被扒光衣服放在一边、穿着 Sarah 衣服的 Nikki 躲在房间黑暗的角落里。她笨拙地抽着烟，哭道「你为什么就不能爱着我呢！」然后开始攻击自己，说明明自己那么爱着他，却得不到 Bear 的爱。她想要和 Bear 在一起，做不到的话，她宁愿开枪自杀。同时，Ian 跑了过来，却被 Nikki 一枪爆头。不仅如此，她强迫 Bear 大声说他爱着自己。得逞后，又切换回甜美的样子和声线 —— 女演员的实力太强了。</p><p>Bear 早就知道如何安抚 Nikki，所以骗她说要一起冲澡，实际上自己躲到了卫生间里，任由外面的 Nikki 疯狂地砸门。他拿起枪，想要自杀，但是怎么做都只是在犹豫。直到 Nikki 妥协说道，如果需要分开一下的话，也可以，他便放下手枪。紧接着，他又想起被自己放在卫生间里，最开始杀死 Sandy 的药物，打算服药自杀。</p><p>他吃下一整瓶药，无视门外 Nikki 的说话声，坐在浴缸上等待自己的死亡…… 然后他反悔了，想要吐出来，门外却又响起许愿玩具的声音。Bear 定住了，没能吐出来，世界好像突然变大、变广了起来。他走出了卫生间，一脸幸福又害羞地看向笑着的 Nikki，抱住她，并开始接吻。再然后，倒在了地上，口吐白沫，死掉了。</p><p>Nikki 抱着死去的 Bear，哭着，也不想活了，拿起一旁的手枪也打算自杀…… 音乐戛然停止，Nikki 也不再哭泣，反而是以非常疑惑的表情，看向周围。她震撼地看向手中的手枪、浑身都是伤的自己、一旁死掉的 Sarah、门口倒着的 Ian、四周，还有怀中抱着的 Bear 的尸体。此时的悲痛，转变为被悲剧冲击，所无法控制的悲伤。她控制不住自己，发自内心地哭了出来。</p><h2 id="电影后"><a class="markdownIt-Anchor" href="#电影后"></a> 电影后</h2><p>这部电影在我进行搜索后，挖掘出了更多蛛丝马迹，例如因为整部电影都是 Bear 的视角，导致我们观众其实也不清楚除此之外的角色们的想法。这便包括，真正的 Nikki 到底喜不喜欢 Bear？</p><p>Nikki 的演员 Inde Navarette 的观点是，Nikki 确实对 Bear 抱有好感。</p><p>我重新看了一遍电影，以捕捉细节。Nikki 听到 Bear 的否认后，先是眼睛飘向自己的右下角，说了句 <em> Okay</em>，接着一边梳理自己的头发，一边不满地说 <em> Good. Goodnight</em> 然后转身离开。</p><p>Navarette 认为这些细节都是 Nikki 失望的表现。再加上和 Bear 在车上聊创作的那场戏中，可以看出 Nikki 会在意 <em> love</em> 和 <em> romance</em> 的区别，且想要自由。就算是和 Ian，也仅是肉体关系。</p><p>然后是 Nikki 在车上说过的一句话：「如果自己喜欢上了谁，谁都看不出来。」这句话最初看，我以为是和接下来 Bear 愿望实现、Nikki 变得特别主动的反差。但假设 Nikki 确实对 Bear 抱有好感，那么这句话便很有意思：我们现在不就正在为了她喜欢谁而在争执么？</p><p>更为重要的是，如果假设为真，那么 Bear 这个角色会变得特别…… 像个小丑。如果他能够承认自己喜欢 Nikki，那么大家的死亡根本就不会发生。</p><p>我喜欢这部片子么？它挺对我胃口的其实。故事中的各个情节，都将不健康的关系搬上了荧幕。电影的标题 <em> Obsession</em>，表面上来看，来源于被邪灵俯身、会失禁、暴力、杀戮和有着极端占有欲的 Nikki，但更深层中，指的是 Bear 本身。他不痴迷于真实的 Nikki，甚至对她的拒绝感到愤怒，而痴迷于一个绝对安全的客体，这也是为什么他一直没有想过抛弃邪灵 Nikki，顶多是要求「有点空间」。</p><p>Bear 结尾的服药自杀，有两种猜测：一是对现实失控的逃避，二是想要帮助 Nikki 解脱。无论是哪一种，他最终其实都没能下定决心、反悔想要吐出来。导致他死亡的，是 Nikki 意外许的愿。绝望的是，这个窝囊废在虚假的甜蜜幻想中死去，获得了逃避的解脱，而真正的受害者 Nikki 却要醒过来、独自面对死去的朋友们，以及无尽的创伤……</p><p><em>Obsession</em> 这部片子，我观看时一直觉得和其他恐怖片有着区别。因此看完后，我第一时间和朋友说「这部片在奇怪的意义上很恐怖」。回家思考后察觉出，它其实没有传统恐怖片里的怪物；我们从最开始便知道恐怖的来源是 Nikki 这个角色，也知道她大概接下来会做什么。也就是说，恐怖不来自于「未知」，而是「人性」。</p><p>「它很恐怖」的另一个原因是，不健康的关系、不沟通、自身的怯懦、猜忌…… 这些都是我们人生中或多或少经历过的。我恐惧这些事情，因此也恐惧这部电影。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;五月了，夏天到了，是时候品尝一些恐怖片了。&lt;/p&gt;</summary>
    
    
    
    <category term="影评" scheme="https://blog.cytrogen.icu/categories/%E5%BD%B1%E8%AF%84/"/>
    
    
  </entry>
  
  <entry>
    <title>关于 Stallman 报告</title>
    <link href="https://blog.cytrogen.icu/posts/b984.html"/>
    <id>https://blog.cytrogen.icu/posts/b984.html</id>
    <published>2026-05-10T04:00:00.000Z</published>
    <updated>2026-07-06T21:52:06.970Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>上个月我调查了一会儿 Richard Stallman 这个人，也是 <a href="/posts/e3b9.html#richard-stallman-%E7%9A%84%E4%B8%AA%E4%BA%BA%E7%BD%91%E7%AB%99">两个月前提到的自由软件之父</a>。</p><p>除了作为自由软件运动的先驱而闻名外，他也因备受争议的言论而知名，尤其是在涉及 <span class="emphasis">性行为不端</span> 和 <span class="emphasis">未成年人性行为</span> 方面的言论。</p><span id="more"></span><p>他最为诟病的争议之一，是 2019 年就 Jeffrey Epstein 性交易案发表的评论（见 <a href="https://zh.wikipedia.org/zh-cn/%E7%90%86%E6%9F%A5%E5%BE%B7%C2%B7%E6%96%AF%E6%89%98%E6%9B%BC#%E4%BA%89%E8%AE%AE">维基百科</a>）。当时他对一名指控者的动机提出了质疑。而这些争议，最终导致他辞去 MIT 和自由软件基金会的职务。</p><p>2021 年，Stallman 宣布回归自由软件基金会董事会，这也是本篇文章重点引用的 <a href="https://stallman-report.org/">网站</a> 的存在目的：阻止他返回，除非他可以公开道歉并撤回所有有问题的主张。</p><p>Stallman 报告，即引用的网站，整理了大量 Stallman 本人的问题，包括但不限于「正常化成年人与未成年人之间的性关系」、「为强奸未成年人者辩护」等等。</p><p>报告的编辑们认为，自由软件领域普遍存在性别歧视文化，而这和 Stallman 脱不了干系。因为 Stallman 数十年来都尝试正常化性暴力，而在他领导下的自由软件运动也会受影响。</p><p>这一点我无法判断是真是假，因为自由软件运动已经是许久之前的事情，那时候我都没有出生。</p><p>不过我赞同报告编辑说的，许多人在对 Stallman 的所作所为一无所知的情况下支持着他。至少该让民众知道真相，再去决定支持与否。所以我决定总结与翻译该报告上的内容，以让信息更易懂。如果想要知道更多，请去阅读原文。</p><p>那么这些是该报告上的重点：</p><p>一、正常化成年人与未成年人之间的性关系。</p><p>Stallman 长期推崇未成年人可以同意与成年人发生性关系的立场。就算他在 2019 年发表声明，承认与「儿童」发生性关系存在心理伤害并表示反对，但这一撤回声明并未改变其核心主张。</p><p>这是为什么呢？首先，Stallman 有一个自己的 <a href="https://www.stallman.org/glossary.html">词汇表</a> 以及 <a href="https://www.stallman.org/antiglossary.html">反词汇表</a>。他会严格将「儿童」定义为 12 或 13 岁以下的群体，并将 13 到 17 岁的群体规划为「青少年」。基于这种个人用词逻辑，报告编辑们反推认为撤回声明仅仅涵盖了青春期前的儿童，但依旧保留了支持成年人与 13 到 17 岁青少年发生性关系的立场。</p><p>在「为什么这种立场是有问题」的方面上，我和报告编辑的观点一致：因为经验与权力的严重不对等，成年人极易对未成年人实施性操纵。</p><p>报告编辑进一步提出，有实际数据显示，当伴侣年龄大出 5 岁以及以上时，未成年女性遭遇意外怀孕、感染性传播疾病以及被迫发生性行为的概率会成倍激增。并且，她们会在成年后面临更长期的心理创伤，还有亲密关系障碍。</p><p>我身边确实存在着未成年时便和成年人发生过性关系的人。那些回忆并不美好…… 说实话，我儿时也差点遭遇毒手。</p><p>Stallman 声称成年人对未成年人的欲望是出于「自然吸引力」，也就是大家耳熟能详的「男人都喜欢 18 岁的」。令人头大的是，他竟认为这是正常的态度，并且将其和性向扭转治疗相提并论，说「难道要洗脑男人对同龄女人产生吸引力吗？」</p><p>医学界明确将恋童癖列为心理病理特征，而非正常性取向 —— 我也知道近些年有人 <a href="https://publicdispatch.org/how-pedophiles-are-being-normalized/">尝试将恋童癖弄成正常性取向</a> —— 但是基于实际的研究，以及我本人对身边「恋童癖」的样本的分析来看，这些对未成年人实施性虐待的，反而并不是所有人都源于 Stallman 所说的「性吸引力」，更多是缺乏与同龄人建立正常关系的社交能力，从而将未成年人作为易于控制的替代品。</p><p>在继续下一个条目之前，我想要探讨下言论与传播的自由。我的边界是，恋童癖作为一种精神障碍，理应被严肃对待并且引入专业的心理与医疗干预，而不是在公共领域被包装成正常的性取向来推行。任何试图通过公共平台来正常化侵犯他人的行为，都是不可取，且越过言论自由的底线的。</p><p>二、为性行为不端辩护。</p><p>Stallman 频繁为涉嫌或已被定罪的性犯罪者辩护，并淡化性不当行为的严重性。</p><p>首先他很喜欢公开淡化和否认受害者经历的言论，营造一种助长施暴者有恃无恐的舆论环境。</p><p>去年我写过一篇 <a href="/posts/5c85.html">文章</a>，表明了我对性犯罪新闻的态度：</p><ul><li>不要掩盖加害者的主观恶</li><li>不要认为受害者不完美就活该遭罪</li><li>不要持有男权沙文主义思想</li><li>不要擅自剥夺受害者的解释权</li></ul><p>Stallman 很完美地踩中了我的所有雷区。</p><p>先前提到的 Stallman 词汇表，现在又要拉出来说，因为他真的有着非常非常严格的用词习惯 —— 我倒是没有，想必也是为什么我写不出来 <code>/glossary</code> 页面吧 —— 他很喜欢在「性侵犯」一词上抠字眼儿。</p><p>例如，他认为灌醉他人以发生性行为，或者施加压力迫使对方和自己发生性行为，只是介于「自愿」与「强奸」之间的中间罪行。</p><p>Stallman 强调，将强奸与轻微的不当接触相提并论是不公正的，被指控者有权获得更精确的区分。他的想法源自于新闻报道上将强奸、性骚扰等行为统一称为「性侵犯」一事。但实际上，这种做法是为了保护当事人。</p><p>他又声称只要前一晚有过自愿行为，这种「同意」便可以延续到第二天，甚至可以让对方不经过任何同意、未戴安全套的情况下与熟睡的自己发生性行为。这种逻辑剥夺了受害者在特定情景下撤回或设定同意条件的权利、夺走了受害者的解释权。</p><p>可耻的是，Stallman 也喜欢为了证明自己的观点，从而歪曲新闻事实、凭空捏造新闻中根本不存在的东西。这些已经不再是基于事实的辩护，而是单纯为了维护自己先入为主的偏见了。</p><p>三、无视有关性骚扰的法律规范。</p><p>Stallman 相信性骚扰是一系列构成经济不公平、性别偏见的行为模式，而非行为或者犯罪。在他看来，单次发生的恶劣黄色笑话、性挑逗等，只要没有反复发生、形成长期模式，就不能算作性骚扰。并且，他将性骚扰从侵犯人身权利，降级到了普通的职场纠纷。</p><p>他不仅在网站上使用具备误导性的定义，还在 MIT 内修完有关性骚扰和性行为不端的课程后，依然继续歪曲性侵犯的概念。他无知么？当然不是，他很明显在抵制现有的法律和道德规范。</p><p>身为女性，性骚扰给我造成了许多不便，也是导致我讨厌出门的原因之一。就连近期常去的打工场所，也有令人烦躁的骚扰现象在……</p><p>四、支持持有儿童性虐待材料。</p><p>Stallman 坚称，仅仅因为持有儿童性虐待材料就判刑，是对人权的威胁，并认为持有此类材料根本不应构成犯罪。</p><p>尽管他对技术执法可能侵犯自由的担忧有一定的合理性，但将其作为支持儿童性虐待材料合法化的论据是…… 呃，极端且糟糕的。</p><p>报告编辑补充道，儿童性虐待材料的传播会对社会中的四类人群造成实质性上的伤害：受害者、消费者、刑事调查员，以及内容审核员。</p><p>令人感到震惊的是，Stallman 曾面对一位自称被儿童性虐待材料吸引的读者的求助时，不仅没有建议其寻求专业的心理或者法律帮助，反而告诉对方「传播儿童色情图片不是错的」，并继续输出其关于「青少年不是儿童」、批评美国社会夸大危险的政治主张。</p><p>报告编辑认为，这不仅证明了 Stallman 的言论会对读者产生真实的误导，更是表明他借受众的软弱与困境，将其自身有害的政治主张伪装成建议，直接造成实质性的恶劣影响。</p><p>五、人类与动物之间性行为，以及恋尸癖的法律与社会正常化。</p><p>这两点在原报告内是分开的，但我想要放在一起说。</p><p>和先前一样，Stallman 认为持有人兽交或者恋尸癖色情内容都是人的权利，反对它们就相当于在威胁人权。</p><p>接着他认为，只要没有对动物施加物理上的强迫或造成直接的身体伤害，那么此类行为就不应该被禁止。同样，他也认为尸体不会感到痛苦，因此对尸体采取的任何行为都不会造成实质性伤害。</p><p>在人兽交上，动物实际上并不具备表达「同意」的能力、无法传达意愿，也无法在遭受侵害后为自己辩护。这一点很像未成年人、醉酒后意识不清醒的人。</p><p>Stallman 声称的「无身体伤害」也不是真的：遭受性虐待的动物同样会表现出抑郁、焦虑和攻击性等创伤症状。</p><p>而制作人兽交色情材料的过程中也有着对人类演员的剥削，因为他们往往是在胁迫下才进行表演的。主张正常化此类色情内容是在无视并纵容暴力。</p><p>至于恋尸癖，他恐怕并不明白死者依然有着作为人的基本尊严。法律和社会规范对遗体的保护，是在维护死者的主体地位、死后自决权，以及身体自主权，而尸体显然也无法表达「同意」。</p><p>对于死者的家属而言，失去亲人本就伴随着巨大的悲痛，若还要面对亲人遗体遭到亵渎，甚至被制作成色情图像传播的事实，将遭受难以想象的二次心理创伤。</p><p>有趣的是，报告编辑也补充说，奸尸被明确界定为战争罪行，因其本质是向民众施加恐惧以及屈辱。</p><p>六、Stallman 本人的不当行为。</p><p>以上五点都在说 Stallman 的政治主张，那么有没有他本人干过的事情哩？确实有。他的行为大可以归结为对权力落差的系统性滥用，主要体现在社交剥削、公开性化与职场独裁三个层面。</p><p>在社交剥削方面，Stallman 习惯利用自身的行业权威获取不平等的关注与身体接触。</p><p>例如上个世纪 80 年初，身为 MIT 研究生的 Stallman，曾以「自杀」为要挟纠缠一名大一新生，并在事后将自己的心理操纵包装成「被拒绝多次后的绝望表达」，将责任推卸给女方的误解。</p><p>在公开性化方面，他长期保留名为 <em> Church of Emacs</em> 的公开表演传统，并自称 <em> St. iGNUcius</em>。在这个表演中，他多次强调必须由女性来扮演「Emacs 处女」（没有使用过 Emacs 的人），甚至在 2008 年将一名 13 岁女孩带上舞台进行性暗示。面对争议，他仅仅将其辩解为针对宗教的恶搞笑话，从未对将未成年人或女性置于性化语境中的行为做出任何反思与道歉。</p><p>在职场独裁方面，Stallman 长期将带有性别歧视和种族主义色彩的「黑客幽默」视为理所当然，无视同事帮助其建立职业边界的劝阻。他在管理中极度缺乏同理心，凭借个人情绪威胁解雇员工，甚至逼迫员工必须依靠组建工会、引入合同与规则，才能勉强维持正常的办公环境。</p><p>Stallman 个人的道德越界之所以能够长达数十年不被清算，根源并不完全在于他本人的固执，而在于其背后的机构将公权力私有化，为他提供了系统性的包庇 —— 这就必须谈到自由软件基金会本身的不当行为。</p><p>七、自由软件基金会的不当行为。</p><p>2019 年的董事会，以及现任的董事会长期纵容 Stallman 的越界行为，且未能遵循联邦和 Massachusetts 的法律规范、为员工提供免受性骚扰的工作环境。</p><p>前执行董事兼董事会成员 Bradley Kuhn 曾长时间试图让 Stallman 认识到，其争议性政治议程有很大的问题，且他的个人极端主张与基金会推进自由软件的根本使命背道而驰。结果不仅没有用，Kuhn 还被驱逐出了董事会。</p><p>有趣的是，Kuhn 被驱逐一事，理应已经离开基金会的 Stallman 有亲自参与投票。因此报告编辑认为，自由软件基金会还在 2019 年到 2021 年间维持了个运作极不透明的影子政府：通过文字游戏和信息隐瞒，蓄意误导公众，以此掩盖 Stallman 继续掌控基金会核心决策权的事实。</p><hr><p>我阅读完整篇报告，是很惊讶的。先前我仅在维基百科上看到过 Stallman 有争议性的地方，也就是 Epstein 案期间的言论，但没有想象到他实际上发表过这么多可怕的言论。</p><p>尽管我认可「极端的观点也享有表达的权利」，可是 Stallman 对特定受害者发表的负面或者质疑，已经对他们产生了干预，并造成精神层面上的伤害。此时问题便不再属于言论自由的讨论范畴。</p><p>尤其是作为在计算机科学和自由软件运动中取得无可代替的成就的先驱者，Stallman 本身就有着巨大的声望。这一点很不幸地会让部分追随者盲目信任他所说的一切，他的政治议程也会很不幸地通过追随者的传播，转化成一种压制受害者发声、改变社区文化走向的力量。</p><p>再加上自由软件运动本身并非纯粹地去开发代码，更多是捍卫用户数字主权、具有伦理和人权色彩的社会运动。非常讽刺的，它的精神领袖却在现实生活中公然利用权力落差去胁迫他人。面对这样一个被个人意志绑架、甚至包庇施害者的基金会，民众包括我自己在内，要如何继续信任它呢？</p><p>好像，还是太动听了些。实话说，整个报告看完，感觉挺恶心的。虽然我知道人有着不同的面孔，或者说在不同的方面上有着截然不同的标准。但是深入了解这位自由软件之父，还是会难以置信。该说是愚昧还是封建呢，总之自私自利肯定是跑不掉了。</p><p>我依然喜欢并支持自由软件的理念，可惜 Stallman 这个精神领袖已经彻底让我祛魅。至于基金会，如果做不到干脆的道德切割的话，那么该机构的公信力必将走向破产 —— 现今各大开源核心机构纷纷与其断供与割席就是最好的证明。</p><p>自由软件这个理念，其核心本就是去中心化与权利共有，早已超越了某个具体的个人。留着一个道德溃败的独裁者到底有什么用呢？就算继续包庇、维护他，他的所作所为也都被存档下来，等着被未来的其他不知情者挖掘。最好的做法是立即切割，避免 Stallman 的政治议程继续侵蚀基金会。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;上个月我调查了一会儿 Richard Stallman 这个人，也是 &lt;a href=&quot;/posts/e3b9.html#richard-stallman-%E7%9A%84%E4%B8%AA%E4%BA%BA%E7%BD%91%E7%AB%99&quot;&gt;两个月前提到的自由软件之父&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;除了作为自由软件运动的先驱而闻名外，他也因备受争议的言论而知名，尤其是在涉及 &lt;span class=&quot;emphasis&quot;&gt;性行为不端&lt;/span&gt; 和 &lt;span class=&quot;emphasis&quot;&gt;未成年人性行为&lt;/span&gt; 方面的言论。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="互联网" scheme="https://blog.cytrogen.icu/tags/%E4%BA%92%E8%81%94%E7%BD%91/"/>
    
  </entry>
  
  <entry>
    <title>读《私宴》</title>
    <link href="https://blog.cytrogen.icu/posts/85d6.html"/>
    <id>https://blog.cytrogen.icu/posts/85d6.html</id>
    <published>2026-05-04T04:00:00.000Z</published>
    <updated>2026-07-06T21:52:06.978Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>这是苏童写的一篇短篇小说，人物多，且个个个性分明，颇有意思。</p><span id="more"></span><p>开头，苏童就用「讽刺」的语气，说长途汽车抛锚在了举例终点站五六十米的大牌坊。可笑的是，它不仅抛锚，门还开不开，急死乘客们了。</p><p>这期间，有乘客怒道，应该举报负责的运输公司、退钱！有乘客说，这是「马桥镇」，又不是北京广州，你举报、别人把你当傻子喔！又有乘客说，这汽车的产权归属于「大猫黄键」，你敢去举报吗？</p><p>一段吵吵嚷嚷的文字，作者就已经透露出，故事发生在贪污腐败的小地方 ——「马桥镇」，并且这个名为「大猫黄健」的人，是这里的地头蛇。</p><p>关于这个「马桥镇」是哪个「马桥镇」，我不知道。好奇的我在网络上搜索，发现中国有足足七个「马桥镇」，其中有个还在我老家山东。唉，如果能从文字中寻找到蛛丝马迹就好了。</p><p>长途汽车好不容易开了半个车门缝儿，乘客们推搡着下了车。汽车站的喇叭放着欢快的《运动员进行曲》，但是听到音乐的人们可没有一个是开心的。</p><p>到这时，小说的主角「包青」才露了面。苏童并没有在小说的开头表明主角是谁，而是用了一通对长途汽车以及乘客的描写，构造出了「急忙和不愉快」的氛围。明明是农历小年的傍晚，也就是差不多除夕前的几天，回家是件好事儿啊，怎么会想要去营造这样的氛围呢？</p><p>苏童描述包青时，说的是「典型的马桥镇人嘴里所说的那种知识分子」。什么知识分子？苏童继续解释道，是「对人缺乏热情，与几声信口而来的寒暄相比较，往往选择装作没看见」的那种知识分子 —— 哦~ 原来是那种在乡下容易被讨厌的知识分子。包青和他说的一样，像做贼般下了车，明明看到了小学同学李仁政，却打算偷偷跑开。不过命运没有眷顾他，李仁政发现且主动找来了他。</p><p>李仁政这个角色初登场的时候，戴着红色棒球帽正在洗车。他帽子上写着「新马泰八日游」，且苏童特意让包青问了这八日游的事情，但是我还是没搞清楚有什么含义在。</p><blockquote><p>（李仁政）突然提高声音说，大猫要请你喝酒，他关照我好几次了，你一回来就通知他，他要请你喝酒。包青说，谁，大猫？黄健吗？李仁政对准汽车后窗玻璃喷着水，说，就是大猫嘛，大猫你都不记得了？包青愣了好一会儿，最后低声嘀咕道，怎么会不记得他，喝就喝嘛。</p></blockquote><p>中文课讨论时，教授问了我们一个问题：包青真的不记得黄健吗？我们的讨论结果是否定的，根据后文，他怎么会忘了黄键呢？明明自己都把「黄健」这个名儿说出口了。从这一处可以隐约看出，包青并不期待和黄健见面。</p><p>有趣的是，包青最后说道，「喝就喝嘛」，像赌气般，也是虚张声势。</p><p>对话结束后，苏童大致讲了包青对过年回家的看法：厌恶。他远在北京，回来只是为了看看母亲。可以说，他对马桥镇没有任何牵挂。</p><p>接着包青遇到了身上有着「夏天北京大商场里弥漫的香水味道的喇叭花」，程少红。她穿着紫色的皮大衣，还遛了条小卷毛狗。</p><p>这段形象上的描写，很不一般：一是北京大商场里喷洒的香水不可能是便宜货；二是紫色皮大衣是种非常惹眼的打扮，很少人会这么穿；三是这小卷毛狗…… 怎么感觉是条迷你贵宾犬啊！</p><p>而四很重要，是「喇叭花」的特征。喇叭花通常会被认为是「传话筒」、「大嘴巴」的象征，也有「五颜六色」的意思在。但是教授给出了新的角度：喇叭花随处可见，且必须依附在墙上才能生长。这一说，想必读者们就会明白程少红这个角色的本质了吧？</p><p>二人进行了一场对话。对话中透露出，包青这么多年过去，见到程少红依然紧张，恐是喜欢过人家。而程少红也侧面描绘出包青的「知识分子」身份，竟是位上过电视的博士。分别前，程少红和李仁政一样，提到「大猫要请包青喝酒」一事。</p><p>次日，包青便开始了名为「走亲戚」的义务。其实我没有怎么走过亲戚，出生在父母北漂的城市里，从小便对「亲戚」这一概念没什么想法。放假回母亲老家时，倒是觉得一个个亲戚明明没怎么见过，却还要想方设法逗我一事很烦。</p><p>包青走亲戚期间，舅舅又跟他提了「大猫要请他喝酒」这件事，连带着还有让包青在黄健面前美言几句，说不定自己的儿子就能去羽绒厂或者长途汽车上工作了。这已经是苏童第四次借旁人之口提到黄健，且无一例外，都在说这黄健多有钱和权势。同时，也借一步提高了包青的地位，他可是个能让黄健想要清酒喝的人物。</p><p>包青自然觉得这种事儿很烦，我也觉得。他不耐烦地回应说，镇长的饭局他推了，他黄健的饭局我哪儿还有时间去应？明儿还要去见教委刘主任呢。这里可以看出，包青的博士身份足够让他推掉镇长这号人物的饭局，但却没能推掉刘主任的。这是怎么回事呢？重点并非在于「地位够不够推饭局」，而是在于包青是位博士、是知识分子，对教育有着明显更强的主动性。他去见刘主任，是自己想去、才去的。</p><p>同一个自然段里，苏童也表现出了包青对教育的看重。离开舅舅家后，他路过了小时候上过的马桥二小，发现学校没了，变成了黄健的羽绒加工厂。他很是愤恨，骂黄健买了小学建工厂，是个可耻的暴发户。</p><p>回到家，包青打算打电话推掉黄健的饭局。期间包青的母亲在旁边唠叨，透露道包青曾经为了和黄健做朋友、付出了耻辱的代价。过去黄健就没把包青当人。当一家人决定在家里用餐时，李仁政骑了车过来，露出先前被帽子遮住的地中海，站在雨里说什么也要把包青请去宴席。</p><blockquote><p>李仁政就那样站在雨中，他的表情看上去有几分惶恐，有几分不安，也有几分神秘。</p></blockquote><p>为什么苏童要特意写出这三个特质呢？在讨论中，我们最终得出的结果是：惶恐在于没能完成黄健的任务，神秘在于可能知道接下来会发生什么。</p><p>这道德绑架的一招还是让包青的家人屈服了。母亲担心有损包青的声誉，劝包青赴约。没办法，他还是坐上李仁政的摩托车走了。路上，他想起曾经三人一起骑两辆自行车去看演唱会。李仁政的车爆了胎，黄健便逼包青跟李仁政换了车。最终包青一个人推着坏掉的自行车走了三十里地，也就是约十五公里、十英里。我曾经走过二十多公里，花了我一天的时间。如果不是特意来走马拉松，突然叫我走这么远，我会想死的！</p><p>到了会场，包青和读者终于是见到前面铺垫许久的大猫黄健。他的额头上有红色的胎记，肥肥胖胖的，像是老虎，也就是「大猫」，具有强烈攻击性的动物。他想要拥抱包青，包青却害怕躲开，又一次暗示二人过去的关系。不得已，他俩只能握手。期间黄健说，就算是省长接见自己，也不见得会像现在这样心跳如此厉害 —— 可是谁能知道他说的是真是假呢？</p><p>饭局上除了先前提到的角色们，还有个新角色小钟，是包青的恩师 —— 中学里钟老师的女儿。未曾料到，包青不知道这位恩师于去年已经因癌症而去世。这和先前包青的形象有所冲突：明明是个那么重视教育的人，每年还来马桥镇过年，怎么会不知道恩师去世了呢？如果我没有记错的话，这个问题在课上没有个准确的答案，钟老师可能是包青去年过年后去世的，谁知道呢？</p><p>接下来就是看得令人疯狂的喝酒桥段，当然是贬义上的。许多人前来劝包青酒，其中程少红因为劝不动，恼羞成怒，曝出了包青曾经偷她胸罩的事情。包青不怕，揭露出是黄健偷的、放自己口袋里来了。黄健不得不承认是自己干的。不知是喝了酒，还是明白自己的身份地位高，包青刻意倒扣酒杯在桌上，示意自己不想再喝了。</p><p>小钟好奇问道，包青明明是好学生，怎么会和黄健和李仁政做朋友的？话外之意，黄健和李仁政是坏学生。黄健听后豁达地自嘲了句，但包青却红了脸。小说里说，包青没有勇气去刨析自己以前为什么这么做，而这么做也是屈辱的。他只能说是小孩子的选择、没什么道理可言。可是程少红点破了一切：「小鸡给黄鼠狼拜年，求它去吃别的小鸡，别吃它自己。」</p><p>因为怕被黄健整，所以选择去和黄健他们混在一起，最终好似也没有落得什么好下场。</p><p>黄健听后，愤怒地辱骂程少红，并要李仁政给程少红倒三大杯白酒。包青一下感觉很惊讶：程少红完全驯服于黄健，说罚就罚，而李仁政也真的拿了酒出来。场面一度变得十分混乱，包青想走，黄健却不让，还要等在场的所有人都罚了酒才让走。</p><p>鸿门宴啊鸿门宴！在场的所有人，不都是特意安排在这儿，逼迫包青喝酒用的嘛！为了稳住场面，包青只能主动提出喝酒，把自己原本拉高的架子又主动拉低了 —— 谁让这一切都是因为自己不喝酒！</p><p>接着黄健拿出个老古董，经过包青的鉴定，发现是假货。原本好不容易稳住的氛围，又因为黄健被骗、李仁政可能从中吃了回扣，变得糟糕了起来。包青发觉了这一点，只得站起来又找人敬酒。</p><p>喝着喝着，给包青喝吐了。李仁政扶着他去厕所，竟还想让他继续和黄健喝酒，喝到黄健满意为止。包青想起小时候自己曾经被黄健等人扔进河里、李仁政过来拉他的事情。</p><blockquote><p>包青忽然就对李仁政说，仁政，我知道你是个好人。李仁政却不高兴，喷出满口酒气骂道，好人有 x 用，没钱，好人也会变坏人！</p></blockquote><p>出了厕所，包青想要最后和黄健喝一杯，喝完就走。但本就喝太多，喝这最后一杯时，倒坐在黄健脚边。他看到黄健鞋子上有泥巴土，忽然想起了过往：曾经黄健命令他给自己擦皮鞋，现在黄健也命令他给自己擦皮鞋。包青一下没了先前大博士的样子，顺从给黄健擦上鞋，却被黄健打了一耳光、让他把另外一边也擦干净。</p><p>次日包青要离开马桥镇，李仁政来车站送他。他问李仁政，昨天为什么不来帮自己、自己是不是给黄健擦了皮鞋，还被打了一耳光？李仁政决口否认。包青话一转，不是我擦的，难道是你擦的、你被打？谁曾想这句话令李仁政激动了起来，他自豪地说，「我从小到大就没替他擦过鞋，更没挨过他耳光！」接着又说，「你们现在都混好啦，那么多同学朋友，只有你能跟他平起平坐，要不是喝醉了，他怎么敢打你的耳光？」</p><p>说着说着，一旁的长途客车自动地开了门，故事也到此结束。</p><hr><p>这篇小说留下了许多未解之谜。我的记忆似是错乱了，并不记得课堂上我们讨论到什么。</p><p>小说的开头与结尾，「长途客车」代表着包青的心结：来时不想来，走时巴不得立即走。是小说常见的「以物喻人」手法。</p><p>人物众多，作者也没有明确说明白这些问题：李仁政到底骗没骗黄健？这些重要人物都代表着什么？黄健这次私宴是鸿门宴，还是意外呢？</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;这是苏童写的一篇短篇小说，人物多，且个个个性分明，颇有意思。&lt;/p&gt;</summary>
    
    
    
    <category term="书评" scheme="https://blog.cytrogen.icu/categories/%E4%B9%A6%E8%AF%84/"/>
    
    
    <category term="社会学" scheme="https://blog.cytrogen.icu/tags/%E7%A4%BE%E4%BC%9A%E5%AD%A6/"/>
    
    <category term="短篇小说" scheme="https://blog.cytrogen.icu/tags/%E7%9F%AD%E7%AF%87%E5%B0%8F%E8%AF%B4/"/>
    
  </entry>
  
  <entry>
    <title>我和宗教</title>
    <link href="https://blog.cytrogen.icu/posts/51f0.html"/>
    <id>https://blog.cytrogen.icu/posts/51f0.html</id>
    <published>2026-05-03T04:00:00.000Z</published>
    <updated>2026-07-06T21:52:06.970Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>今天我在 Fediverse 上看到有位朋友上传了和宇宙人运动相关的网站，勾起了我和宗教（或者邪教）的记忆。</p><span id="more"></span><p>同时因为自己想要多在外写写博客，利用起自己的碎片化时间，所以想要尽力多发发「日常生活」相关的文章 —— 其实也只是把我发到 Fediverse 上的内容扩展下，弄成订阅博客的朋友们也能看懂的形式。</p><p>所以这篇文章也是我用来测试外出时，能不能用安卓手机上的 Termux 使用 Emacs，然后写博客文章并推送到 VPS 上、自动构建跟发布的。</p><p>结果 Emacs 跑出来没什么问题，构建 Hexo 成了问题。只能乖乖回家自行构建和推送了。</p><hr><p>我和宗教的关系要从我还在中国生活的时候开始说起。我外婆会做法事，在家中也供奉除了祖先外的其他神仙，不过我说不出来他们的名字。每年鬼节都要在家中用大锅烧纸、念不知道是不是经的话 —— 由于是方言，所以我听不明白，但是烧纸很好玩。</p><p>接着家里要摆酒席，院子都摆上红彤彤的桌子，长辈们都要杀鸡。我对这段时间没什么记忆，只记得他们会给我气球吹，然后我每次都会弄破气球，也是每个气球的命运吧。</p><p>后来我被交给山东的父母朋友带，当了几年的留守儿童。别说，这段时间反而让我更为记忆犹新，说是我在中国最开心的日子也不为过。</p><p>父母的朋友是对夫妻，其中妻子是位佛教徒：每天都会念经、供奉佛像、吃素。尽管她吃素，但是完全不抵触他人食肉，甚至会拼命给孩子们喂肉。</p><p>他们像对待亲生女儿般对待我，让我十分感激。通过这位阿姨，我认识到了佛教（的一个分支？）：会念经、会买鱼放生、会抄写《心经》、会反对堕胎。</p><p>这些见识逐渐建立起了我小时候的认知，比方说要对小动物好，看见蜘蛛不要弄死、引它出去就好了。为什么特地要说「蜘蛛」哩？因为小学时我和同桌发现了一只蜘蛛。她想弄死蜘蛛，我想把蜘蛛放到窗外。争执间我说蜘蛛也是生命，她反驳道蜘蛛也会想要为我们而去死的！</p><p>当时微信渐渐普及，阅读公众号也成了我每日会做的事情。阿姨订阅的微信公众号里，除了奇怪的言情小说外，就是和佛教相关。有趣的事情有两个，一是许多公众号使用了 Steve Cutts 的讽刺类动画短片，像 <em> Man</em> 这样的，二是经常写反对堕胎的文章。</p><p>那时的我刚刚得知自己并非母亲怀上的第一个孩子，并听信死去的哥哥的故事 —— 母亲堕胎后做过一段时间噩梦，舅舅的摩托车也出问题，直到外婆做法事给死婴做了个小屋子，一切才变正常。所以这一切都是堕胎的错吧！</p><p>对于这世上到底有没有灵或者鬼，我是没法答出这种人们争执许久的问题的。但我现在可以说，我不相信它的存在，我也更相信堕胎是人类的权利。</p><p>至于 Steve Cutts。嗯…… 他的一些短片画出来蛮猎奇，尤其是对当时还是小孩子的我来说。</p><p>在我来到美国之后，我便要和当地更有名的宗教，AKA 基督教打交道了，严格上来讲，是新教的浸礼会，也是福音派的一种。母亲是位基督徒，她喝令我每周日要去教堂、参加主日学。</p><p>我起初对这个新见到的宗教没啥特殊的想法。教堂内实在是无聊，没有什么娱乐方式，只能在大人们听道期间，一个人找书读。最常被我翻阅的书籍就是简体中文版的圣经，当时还未开始阅读汉化版的日本漫画，对繁体字实在是懵懵懂懂。</p><p>圣经啊，该如何评价这本书呢？我是以「读故事书」的角度去阅读它的，所以我很喜欢其中的各个故事，对诗经、仪式如何举办等内容没有兴趣。当时最喜欢阅读《启示录》，反而因「和耶稣基督无关」而被师母教训。唉……</p><p>上初中后，我没怎么阅读圣经，也觉得主日学烦、不再去了。有时会被母亲抓来听讲道，但也兴趣乏乏，转而在台下偷偷阅读他们订阅的周刊。周刊里多是读者的投稿，赞扬信耶稣基督后、自己的人生变化。我读时无法产生任何共鸣，倒是越发觉得教堂里的人很烦、老有事没事管我作甚！</p><p>妹妹出生后，她也随着母亲信了教、受了洗。她对比我，要更相信耶稣基督的存在，在幸运狗一次走丢后，还会跪在地上祈祷、求耶稣基督救救幸运狗。小孩子是单纯的，我总是这么相信着，所以对于各类面向孩童的圣经班，我抱有复杂的感情。</p><p>我又必须要说一次「堕胎」的事情。我不清楚在中国它是个怎么样的事儿，但在美国，它是个争议纷纷的事情：你倾向于「不能杀生」，还是倾向于「人们有对自己身体的所有权」？</p><p>这个问题过于简单化了，但确实是美国人们在「堕胎」一事上吵半天的事情。逻辑是，肚子内的胎儿也是生命、是上帝的造物，堕胎相当于杀人、杀害上帝的造物。中国人难以理解这样的逻辑吧，因为在中国法律中，胎儿没从子宫中生产出来便不算人。</p><p>我的想法自然是偏向于「人们应有对自己的所有权，以及执行权」。不仅如此，也要考虑到被强奸者的情况，尤其是幼小的被强奸者。例如 2022 年，「不能堕胎」在美国各州开始蔓延时，就有过 13 岁女孩被强奸至怀孕，无法在当地堕胎，也没有钱去其他州堕胎，最终不得不生下孩子的新闻。</p><p>在一期周刊中，有位不记得姓名的牧师写了篇文章，主张「不能让人有堕胎权」，理由和我上述的一致，但在「被强奸者能不能堕胎」上，他轻描淡写说：「比例很少，更多是人们放纵而导致怀上必须要被打掉的胎儿。」</p><p>比例少，所以便可以不在乎他们了么？</p><p>疫情后，我便再也没有去过教堂，就算被硬拉着去，我也只是找地方躲起来。和父母发生过一次事件后，他们也不敢再来招惹我，放着我想干嘛去干嘛去。</p><p>那个教堂中同时会讲流利的普通话以及英语的人不算多，我是其中之一。教堂新上任的牧师只会讲英语和粤语，急需一个翻译官。我就被拉上去干这个活哩。小学时如何声情并茂朗读课文的小技能，竟在这个时候派上了点用场 —— 当然是对本人来说不好的用场啦！因为我不想要浪费时间去和牧师对稿件、上台跟着他讲个一小时。</p><p>有次我周日有事，明确表示了自己不能上台。这牧师的母亲，也就是先前教训我的师母（前），竟一起向我发送短信施压，一点边界感都没有！我对这个教堂的厌恶，也很大程度上是因为她。</p><p>那么我很讨厌宗教么？我确实很讨厌宗教，不过也认可它对于人们的作用。我挺喜欢小教堂中的社区感，人们互帮互助，有时虽也有让我看着不愉快的地方在，但整体上来讲我喜欢这个想法。</p><p>在美国这些年也不仅仅是碰上了新教这一个宗教。犹太教么，以前居住的区旁边正是犹太人区，我初中也在犹太人区内。我很讨厌犹太人，因为他们总会给我种「不欢迎你！」的感觉。一次放学，一个犹太小女孩盯着结伴而行的我和小伙伴们，竟毫无掩盖地露出了鄙夷的表情。</p><p>在华人区居住时，我常常撞上法轮功的人。年少无知，没上过政治课，都不知道「共产党」是个啥。第一次认识到「共产党」，还是在法轮功派发的小册子上看到。册子上的内容听后会让人觉得忍俊不禁：老天爷有眼，召唤闪电劈中了块石头，石头上竟赫然写着几个汉字 —— 中国共产党必亡！</p><p>就算是还是小孩子的我，也知道这种事情写出来有多扯淡。对法轮功的第一印象也是差上加差。再之后总是能遇到法轮功的人传教，跟着我跑，太可怕了。</p><p>每年和法轮功相关联的神韵团都有演出，不过我从未看过。一是票挺贵的，二是身边的人都认为它是邪教 —— 我无法定义它是否是邪教，因为它还挺复杂的。我不能直接去相信墙内对它的指控，而在墙外对法轮功的说法争议不断。最终像是大家都放弃了般，没有个非常权威的源去说它是否是邪教、政治产物，墙内的人们都认为它是邪教，法轮功自己到处游行哭诉江泽民对自己的所作所为，尽管他已经去世好多年了。</p><p>和基督教相关的邪教我也遇上过，其中一个大名鼎鼎 —— 东方闪电。其实这类宗教因为过于符合「邪教」的定义，都不需要犹豫和挣扎：声称世界末日快降临了，并认为所有自然灾害都是世界末日的前兆。</p><p>其中有教徒缠上过我母亲，每天嘘寒问暖、买吃的给她。母亲虽然有免费的饭可吃，但家里又不是穷到给点饭便感激涕零，很快就赶她走掉了。</p><p>我对基于基督教的邪教是这么定位的：主张教徒们不要去教堂的很大可能就是邪教。母亲一位朋友貌似就深陷其中，不愿意去教堂，也不知道他们现在如何。</p><p>最后讲宗教，就讲讲最近碰上的来自日本的创价学会吧。准确来说，这是室友碰上的，她的一位新朋友是其会员。起初，室友觉得它比基督教「好」，里面的人们不会神神叨叨。我当时提醒她，随着她越来越了解个宗教，她只会愈发厌恶它。</p><p>果不其然，在参加了创价学会的一场活动后，她便回来说那里的人怎么也神神叨叨的，整天念经、哭诉自己生活多么惨，入了学会后如何吃得好、睡得香。</p><p>我从未想过，大名鼎鼎的互联网精神污染视频「武器 A」里的人脸，就是创价学会的人。想要了解更多，我会推荐阅读这个 <a href="https://airmoto.fandom.com/zh/wiki/%E5%85%A5%E9%97%A8%E5%BF%85%E7%9C%8B">亚文化 Wiki 页面</a>。无他，就是觉得好笑。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;今天我在 Fediverse 上看到有位朋友上传了和宇宙人运动相关的网站，勾起了我和宗教（或者邪教）的记忆。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="社会学" scheme="https://blog.cytrogen.icu/tags/%E7%A4%BE%E4%BC%9A%E5%AD%A6/"/>
    
    <category term="哲学" scheme="https://blog.cytrogen.icu/tags/%E5%93%B2%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>想法在丙午麦序迭代</title>
    <link href="https://blog.cytrogen.icu/posts/5586.html"/>
    <id>https://blog.cytrogen.icu/posts/5586.html</id>
    <published>2026-05-01T04:00:00.000Z</published>
    <updated>2026-08-09T05:41:25.890Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>好吧，看上去我把上个月的一些条目错误地放在了另一个 Org Mode 文件内，并把它们忘在了那儿…… 所以本次月刊会有一些上个月就该有的内容。</p><span id="more"></span><details>      <summary>本期导读</summary>      <h2 id="输入"><a class="markdownIt-Anchor" href="#输入"></a> 输入</h2><h4 id="商业与社会"><a class="markdownIt-Anchor" href="#商业与社会"></a> 商业与社会</h4><ul><li><a href="#hullo-hillo-holla-%EF%BC%9A%E5%8D%95%E8%AF%8D-hello-%E7%9A%84-600-%E5%B9%B4%E8%B5%B7%E6%BA%90">/Hullo, hillo, holla/：单词 /hello/ 的 600 年起源</a></li><li><a href="#%E6%88%91%E4%BB%AC%E5%9C%A8%E9%9A%90%E7%A7%81%E6%94%BF%E7%AD%96%E4%B8%AD%E9%9A%90%E8%97%8F%E4%BA%86%E4%B8%80%E6%AC%A1%E5%85%8D%E8%B4%B9%E7%9A%84%E7%91%9E%E5%A3%AB%E4%B9%8B%E6%97%85">我们在隐私政策中隐藏了一次免费的瑞士之旅</a></li><li><a href="#%E4%B8%BA%E4%BB%80%E4%B9%88-atm-%E6%B2%A1%E6%9C%89%E5%8F%96%E4%BB%A3%E9%93%B6%E8%A1%8C%E6%9F%9C%E5%91%98-%E8%80%8C-iphone-%E5%8D%B4%E5%81%9A%E5%88%B0%E4%BA%86">为什么 ATM 没有取代银行柜员，而 iPhone 却做到了</a></li><li><a href="#%E8%91%AC%E7%A4%BC%E5%A6%82%E4%BD%95%E8%AE%A9%E9%9D%9E%E6%B4%B2%E9%99%B7%E5%85%A5%E8%B4%AB%E5%9B%B0">葬礼如何让非洲陷入贫困</a></li></ul><h4 id="心理与关系"><a class="markdownIt-Anchor" href="#心理与关系"></a> 心理与关系</h4><ul><li><a href="#%E6%88%91%E6%B2%89%E8%BF%B7%E4%BA%8E%E5%81%9A%E4%B8%AA%E6%9C%89%E7%94%A8%E7%9A%84%E4%BA%BA">我沉迷于做个有用的人</a></li></ul><h4 id="科学与自然"><a class="markdownIt-Anchor" href="#科学与自然"></a> 科学与自然</h4><ul><li><a href="#bryant-park-%E7%9A%84%E5%B0%8F%E4%B8%98%E9%B9%AC%E6%88%90%E4%B8%BA%E6%9B%BC%E5%93%88%E9%A1%BF%E7%9A%84%E4%B8%BB%E8%A6%81%E6%99%AF%E7%82%B9">Bryant Park 的小丘鹬成为曼哈顿的主要景点</a></li><li><a href="#%E5%BD%93%E6%88%91%E8%B0%88%E6%99%A8%E8%B7%91%E6%97%B6-%E6%88%91%E5%9C%A8%E8%B0%88%E4%BA%9B%E4%BB%80%E4%B9%88">当我谈晨跑时，我在谈些什么</a></li></ul><h4 id="技术与创造"><a class="markdownIt-Anchor" href="#技术与创造"></a> 技术与创造</h4><ul><li><a href="#%E6%88%91%E5%9C%A8-linux-%E4%B8%8A%E5%BA%A6%E8%BF%87%E4%BA%86%E4%B8%80%E5%B9%B4-%E5%BF%98%E8%AE%B0%E4%BA%86%E5%8E%BB%E6%80%80%E5%BF%B5-windows">我在 Linux 上度过了一年，忘记了去怀念 Windows</a></li><li><a href="#%E4%BD%A0%E6%92%9E%E5%88%B0%E4%BA%86%E5%B9%B4%E9%BE%84%E9%97%A8%E6%A7%9B-%E7%8E%B0%E5%9C%A8%E8%AF%A5%E6%80%8E%E4%B9%88%E5%8A%9E">你撞到了年龄门槛。现在该怎么办？</a></li><li><a href="#nekogram-%E4%BC%9A%E7%A7%98%E5%AF%86%E6%94%B6%E9%9B%86%E5%B9%B6%E4%B8%8A%E4%BC%A0%E7%94%A8%E6%88%B7%E4%BF%A1%E6%81%AF">Nekogram 会秘密收集并上传用户信息</a></li><li><a href="#%E8%BF%99%E4%B8%8D%E6%98%AF%E4%B8%BA%E4%BD%A0%E5%87%86%E5%A4%87%E7%9A%84%E7%94%B5%E8%84%91">「这不是为你准备的电脑」</a></li><li><a href="#bunnycdn-%E5%9C%A8%E8%BF%87%E5%8E%BB%E7%9A%84-15-%E4%B8%AA%E6%9C%88%E9%87%8C%E4%B8%80%E7%9B%B4%E5%9C%A8%E6%82%84%E6%97%A0%E5%A3%B0%E6%81%AF%E5%9C%B0%E4%B8%A2%E5%A4%B1%E6%88%91%E4%BB%AC%E7%9A%84%E7%94%9F%E4%BA%A7%E6%96%87%E4%BB%B6">BunnyCDN 在过去的 15 个月里一直在悄无声息地丢失我们的生产文件</a></li><li><a href="#%E4%BD%BF%E7%94%A8%E7%BA%AF%E6%96%87%E6%9C%AC%E9%82%AE%E4%BB%B6">使用纯文本邮件</a></li><li><a href="#ai-%E9%9F%B3%E4%B9%90%E6%9C%89%E5%85%B3">AI 音乐有关</a></li><li><a href="#stalwart-%E5%87%BA%E9%97%AE%E9%A2%98">Stalwart 出问题</a></li><li><a href="#%E6%9F%A5%E9%98%85%E6%BC%AB%E7%94%BB-%E4%B8%8B%E8%BD%BD%E6%BC%AB%E7%94%BB-%E5%90%8C%E6%AD%A5%E6%BC%AB%E7%94%BB%E5%88%B0-kobo-%E4%B8%8A">查阅漫画、下载漫画、同步漫画到 Kobo 上</a></li><li><a href="#agentic-coding">Agentic Coding</a></li></ul><h2 id="输出"><a class="markdownIt-Anchor" href="#输出"></a> 输出</h2><ul><li><a href="#%E6%8A%98%E8%85%BE%E5%8D%9A%E5%AE%A2">折腾博客</a></li><li><a href="#%E6%88%91%E5%86%99%E7%9A%84%E6%96%87%E7%AB%A0">我写的文章</a></li><li><a href="#%E7%BC%96%E7%A8%8B%E5%8E%86%E7%A8%8B">编程历程</a></li><li><a href="#%E4%B9%A6%E7%B1%8D">书籍</a> / <a href="#%E5%BD%B1%E8%A7%86">影视</a> / <a href="#%E9%9F%B3%E4%B9%90">音乐</a></li><li><a href="#%E6%97%A5%E8%AE%B0%E7%89%87%E6%AE%B5">真生活</a></li></ul>    </details><h2 id="商业与社会"><a class="markdownIt-Anchor" href="#商业与社会"></a> 商业与社会</h2><p><a id="hullo-hillo-holla-：单词-hello-的-600-年起源"></a></p><h4 id="hullo-hillo-holla单词-hello-的-600-年起源"><a class="markdownIt-Anchor" href="#hullo-hillo-holla单词-hello-的-600-年起源"></a> <a href="https://www.bbc.com/culture/article/20260113-hello-hiya-aloha-what-our-greetings-reveal">《/Hullo, hillo, holla/：单词 /hello/ 的 600 年起源》</a></h4><p><em>hello</em> 是个相当常见的问候语，且有着多个变体。根据文章内提到的，就有 <em> heyyy</em>、<em>hellaw</em>、<em>howdy</em> 和最干脆的 <em> hi</em>。</p><p>那么它在正式记载之前的起源，可能是什么呢？文章认为这存在争议，可能源自古高低德语的呼唤语、狩猎口令或者法语的感叹词。</p><p>19 世纪凭借 Thomas Edison 的推崇，它在与 <em> ahoy</em> 的竞争中胜出，正式确立了作为标准电话问候语的地位。所以说，在某个平行宇宙中我们会用 <em> ahoy</em> 来问候彼此！那在中国，可能就不再是互相说「哈喽」，而是互相说「啊哦咦」。</p><p>不过就现在的数字时代而言，传统问候语的必要性正在被削减：你会在即时通讯软件上，和一个人每次开启新对话时、都向对方说句 <em> hello</em> 吗？</p><p>再就是网络交流对效率和情绪表达的需求，<em>hello</em> 在拼写形式上不断发生变异，例如拉长尾音、使用缩写，或者用表情符号替代。这有点像「哈哈」这种表达大笑的文字，在网络上想要表达真的很好笑，你得「哈哈哈哈哈哈哈哈」才行。</p><p>互联网上沟通毕竟还是无法看到对方的表情的。同一句话可以是「普普通通的叙述」，也可以是「阴阳怪气」。人们对于同一句话的理解会随着时间改变，这也包括表情符号：最初的微信「微笑」就是「微笑」的意思嘛，现在对年轻人而言完全变成「表面微笑实则愤怒」的意思了。</p><p><a id="我们在隐私政策中隐藏了一次免费的瑞士之旅"></a></p><h4 id="我们在隐私政策中隐藏了一次免费的瑞士之旅"><a class="markdownIt-Anchor" href="#我们在隐私政策中隐藏了一次免费的瑞士之旅"></a> <a href="https://www.cape.co/blog/easter-egg-in-privacy-policy">《我们在隐私政策中隐藏了一次免费的瑞士之旅》</a></h4><p>Cape，一家以隐私为核心的移动虚拟网络运营商，悄悄在隐私政策里放了个彩蛋：谁看到了，可以给 Cape 发送邮件以赢得一次免费的双人瑞士往返之旅，带私人度假屋三晚住宿、1500 美元的餐饮津贴、由私人厨师主持的晚宴，以及三年的 Cape 移动服务。</p><p>放上去的两周后，便有人发了邮件询问这件事。虽说看到这样的彩蛋被人挖掘很有趣，但是两周的时间并不算短，意味着愿意阅读隐私条款的人们还是很少。</p><p>我上一次阅读隐私条款，还是三个月前写 <a href="/posts/2590.html">《最能保障「数字主权」的 VPS 公司》</a> 的时候。莫有办法啊，它们通常会被写得很长很长很长，而很长的隐私条款往往带着大量我不想要看到的东西，看到后使用该服务也会觉得膈应 —— 说来说去还是自己的惰性犯了。</p><p>我先前有过一个计划，那就是阅读自己使用的服务的隐私条款，并将其进行总结、整理到一个网页上。</p><p>不过隐私条款并不是绝对正确的，违反自己隐私条款的公司不在少数，毕竟也没有那么多人盯着看：就算是 Cape 这样的以隐私为核心、用户都重视隐私的公司，彩蛋不也是塞到隐私条款中两周后才被人发现。</p><p><a id="为什么-atm-没有取代银行柜员-而-iphone-却做到了"></a></p><h4 id="为什么-atm-没有取代银行柜员而-iphone-却做到了"><a class="markdownIt-Anchor" href="#为什么-atm-没有取代银行柜员而-iphone-却做到了"></a> <a href="https://davidoks.blog/p/why-the-atm-didnt-kill-bank-teller">《为什么 ATM 没有取代银行柜员，而 iPhone 却做到了》</a></h4><p>哦，<a href="/posts/a4c0.html#%E8%AE%B8%E5%A4%9A%E4%BA%BA%E5%8F%A3%E6%95%B0%E6%8D%AE%E9%83%BD%E6%98%AF%E8%99%9A%E5%81%87%E7%9A%84">又</a> 是你，David Oks！你写的文章的主题都让我这么感兴趣。</p><p>Oks 在这篇文章中的核心论点是，技术对劳动力的真正替代并非通过「任务自动化」实现，而是通过「范式替换」实现。</p><p>那什么是「范式替换」呢？<u>范式替换</u> 指的是，一项新技术的出现彻底重构了整个商业模式的基础架构和运行逻辑。这和自动化是完全不同的概念：技术仅仅提升了旧范式中特定任务的效率，使其做得更快、成本更低。</p><p>比方说我要迁移数据。比起一个个手动迁移，我会写个脚本、让程序自动迁移。然而因为数据结构的复杂性，我在迁移时会遇到许多问题，这时候只能人工介入、完善脚本。</p><p>因此，任务自动化并不会直接导致大规模的结构性失业，反而可能因为单次服务成本降低、总体需求增加，进而衍生出对原有劳动力的衍生需求 —— 在刚才的例子中，就是不停维护脚本的人。</p><p>但在范式替换的模式下，整个旧框架都被打破、新的规则被树立。技术不再服务于旧工作流，转而创造出全新的运作体系。在这个新的体系里，原本需要人类执行、后来试图用机器自动化的任务，在概念上就已经不存在了！</p><p>Oks 在文章中驳斥了政界以及经济学界广泛流传的乐观论调，即「ATM 不会导致银行柜员失业」。他指出了几个点：</p><p>一、银行柜员的就业人数在过去十几年间经历了断崖式下跌，所以整个命题就是错的；</p><p>二、终结这一岗位的并非 ATM，而是 iPhone 所代表的移动互联网技术。</p><p>从逻辑上看，ATM 仅符合我说到的「自动化」模式：大幅降低了单次交易的成本，以及运营实体网点的成本，从而促使银行开设更多的物理网点。同时，柜员们的任务从日常现金处理，进化到了执行关系型银行业务，也就是推销信用卡和贷款。</p><p>ATM 也不是万能的，所以柜员们的存在也弥补了 ATM 坏掉的情况。</p><p>但是 iPhone 的出现，是「范式替换」。移动互联网技术普及后，不仅全职银行柜员的数量减少了，银行的物理网点也裁撤了不少。这是因为客户和银行的交互被完全转移到了数字终端，实体网点失去了存在的必要性。整个商业模式的基础被动摇，依附于实体网点的柜员岗位自然也会失去价值。</p><p>Oks 提出这个话题，是为了结尾跟 AI 相关的讨论。目前业界普遍倾向于将 AI 视为「可以直接嵌入到现有工作流的远程工作者」—— 例如平替程序员、客服 —— 但他认为只要人类仍在尝试将新技术塞入旧流程中，AI 带来的生产力提升和劳动力替代率都会令人失望。</p><p>这是因为，现有的人类工作流充满了历史遗留的规则、妥协，以及专门为人类设计的沟通反馈机制。AI 在这种范式下运作，只会处处碰壁。</p><p>那和 AI 相关的「范式替换」会是什么？Oks 讲到完全围绕 AI 能力设计的新型组织架构，以促使企业放弃旧工作流。假设有一个新的结构，是完全围绕 AI 的绝对优势来构建的，那会是什么样的呢？我也很好奇。不过在这之前，需要先解决运行 AI 会带来的种种问题，例如环境保护等等。</p><p><a id="葬礼如何让非洲陷入贫困"></a></p><h4 id="葬礼如何让非洲陷入贫困"><a class="markdownIt-Anchor" href="#葬礼如何让非洲陷入贫困"></a> <a href="https://davidoks.blog/p/how-funerals-keep-africa-poor">《葬礼如何让非洲陷入贫困》</a></h4><p>看来我和 David Oks 没完了。事先说明，我没有去订阅他，我只是跑到 Hacker News 上、将一些我认为有趣的话题添加到 Instapaper 上而已。但每次开始阅读时就会发现作者是 Oks。</p><p>Oks 这次探讨了撒哈拉以南的非洲地区里，极其昂贵的葬礼文化。比方说非洲西部的加纳共和国，年收入中位数仅为 1500 美元左右，但是一场普通的中档葬礼要花费 5000 美元，而一场更体面的葬礼能耗资 15000 到 20000 美元 —— 什么~！这些地区举办的葬礼里，难道要用到金子棺材吗，怎么会这么贵！</p><p>根据文章所说，葬礼会专门请平面设计师来制作彩色的横幅，还会租下场地、雇佣大量的工作人员，比如抬棺舞者，就是那四个有专属 BGM、开心跳舞的黑人。如果再有钱点，死者的亲属会委托工匠专门雕刻一个棺材，还是定制的。</p><p>这就导致了听上去很离奇的一幕：该地区的家庭在埋葬死者上的花费要比维持生者生命的花费还要多。更可怕的在于，很多时候家庭成员会通过贷款、削减生活开支、变卖家产等手段来支付葬礼的费用。</p><p>Oks 的观点是，这种现象不能简单归结于当地对长辈的敬重。它的本质是宗族社会为了维持内部结构而运行的财富摧毁机制。也就是说，整个地区的经济增长被如此阻碍，是刻意的。</p><p>非洲的许多社会高度依赖于宗族网络。在缺乏现代国家机器的地区，宗族为成员提供社会保障、医疗信贷，和在安全方面上的保护。作为交换，成员必须承担无尽的财富分享义务。宗族网络会持续不断地将资金从高产出的个体转移给低产出的亲属 —— 也就是吸血。</p><p>而这么做的原因在于，个人财富的积累会对这种网络构成威胁。一旦高产出成员积累了足够的资本，那他们便具备了脱离宗族的能力，第一时间想的也会是赶紧跑掉。如果人真的跑了，那抽血机制会直接陷入崩溃。为了防止成员逃避义务，宗族社会演化出消耗个人财富的公共仪式，而葬礼是其中最核心的一环，因为人无法回避它。</p><p>有趣的是，高产出成员会想方设法证明自己「没有钱」，比方说办理非必要银行贷款、躲到离家乡远的地方工作、投资于不可分享的商品…… 文章中 Oks 引用了一位女商人的话：</p><blockquote><p>我在远离家乡、无人知晓的地方卖二手衣服。我躲着朋友，因为我相信并非所有朋友都会为我的成功感到高兴；我也躲着家人，为了营造一种我没钱的假象，让他们为自己的生计而努力工作。我之前的生意是一家路边餐厅，因为姻亲们把我当成提款机而倒闭了，但我本想扩大规模的。</p></blockquote><p>资本和亲属关系的对立关系，是我未曾想过的。后来想想，Oks 说得没错，「亲属网络有着强烈的动机去阻止其成员变得足够富裕」。而变有钱意味着社会现代化，社会现代化又会让我们脱离亲属网络。那从根源上想方设法让成员变得没钱不就好了？</p><p>我对亲属网络有偏见，但偏见更多来自于道听途说。我母亲虽也有个「大家族」，不过并没有非洲这种宗族网络这么可怕，顶多是互相扶持一把，钱还是要多多赚。我父亲则是位十几年甚至几十年都不愿意再见父母的人，所以更不用提他那边有没有「大家族」了，还有认识的人便足矣。</p><p>亲戚是一个我很难去理解的概念。他们并非我熟悉的人，单单只是和我有血缘关系而已，我就要想办法去扶持对方吗？更极端点，有些亲戚甚至会嫉妒别人过得比自己好，想尽办法拉别人下水，说不定在非洲的宗族网络里也是个隐性缘由。</p><h2 id="心理与关系"><a class="markdownIt-Anchor" href="#心理与关系"></a> 心理与关系</h2><p><a id="我沉迷于做个有用的人"></a></p><h4 id="我沉迷于做个有用的人"><a class="markdownIt-Anchor" href="#我沉迷于做个有用的人"></a> <a href="https://www.seangoedecke.com/addicted-to-being-useful/">《我沉迷于做个有用的人》</a></h4><p>作者内心中有着对解决问题，和被系统或他人需要的内在渴望，因此依然对排查漏洞、统筹项目等常常会被人认为是麻烦的事情而充满热情 —— 工作本身及其带来的效能感即是终极的内在满足。</p><p>这是一个危险的想法，因为这类人对于企业主而言，很容易被发现，也就是大家常说的「软柿子」，然后被榨得连汁水都不剩。作为解决方案，作者认为必须建立严格的边界，不做无意义的工作。</p><p>能从工作本身获得乐趣和满足的心态，我是相当羡慕的。我已经开始厌恶自己的工作，时刻都想要从中逃脱，但我又被过分需要，以及和甲方的边界很是薄弱 —— 这一切都让我苦不堪言。</p><h2 id="科学与自然"><a class="markdownIt-Anchor" href="#科学与自然"></a> 科学与自然</h2><p><a id="bryant-park-的小丘鹬成为曼哈顿的主要景点"></a></p><h4 id="bryant-park-的小丘鹬成为曼哈顿的主要景点"><a class="markdownIt-Anchor" href="#bryant-park-的小丘鹬成为曼哈顿的主要景点"></a> <a href="https://www.silive.com/entertainment/2026/04/bryant-park-woodcock-becomes-major-manhattan-attraction.html">《Bryant Park 的小丘鹬成为曼哈顿的主要景点》</a></h4><p>Bryant Park 在时代广场附近，旁边立着许多银行公司的总部或者分部。公园内也有个很大的溜冰场，不过我没去过。</p><p>这个月 <em> American woodcock</em> 的标签实在是到处乱飞，室友给我看了许多有关这种鸟的视频。中文叫「小丘鹬」，直译也可以叫「美洲木鹬」。</p><p>它从三月中旬到四月底都会抵达曼哈顿短暂地休息与觅食。这吸引了大量纽约客跑到 Bryant Park 里找它、拍摄它。</p><p>小丘鹬的长相很奇特…… 在我看来，它的头部很像兔子，眼睛长在很上面，一点都不可爱。但它行走时身体会有节奏感地摇来摇去，被许多人拍摄、配上音乐发布到社交媒体，看起来很魔性。</p><p>室友很喜欢这只鸟，和我专门去了一趟 Bryant Park 找它。虽然它有着伪装色，但是旁边聚集着很多捧着摄像机的人，变相地好找了许多。</p><p>这次小探险倒是让我意外发现了很多东西，例如 Bryant Park 里有很多休闲区域，像是有打乒乓球的桌子、下象棋的地方…… 这就是 <em> touch grass</em> 的魅力吧。我还发现现在兼职的店，在这附近竟还有家分店，而它正好在我一位在这附近上班的朋友、午休天天去的餐厅的对面。</p><p><a id="当我谈晨跑时-我在谈些什么"></a></p><h4 id="当我谈晨跑时我在谈些什么"><a class="markdownIt-Anchor" href="#当我谈晨跑时我在谈些什么"></a> <a href="https://hulatu.com/posts/2026/04/12/morning-run/">《当我谈晨跑时，我在谈些什么》</a></h4><p>博友 <a href="https://hulatu.com/">胡拉图</a> 的文章，讲了他晨跑后发现的真理：</p><blockquote><p>运动是脑力工作的前置条件，而不是奖励。</p></blockquote><p>我没有晨跑的习惯，或者说我根本就没有跑步的习惯 —— 这样说实在是让我感到羞耻，明明自己也觉得不太好，但也只能安慰自己「慢慢来吧」。至少现在都会尽量走路出门，而不是搭乘地铁公交了……！</p><p>文章里提到的 Huberman 教授，指的是 Andrew David Huberman，是一位知名的美国神经科学家兼播客主持人。可惜我也没有听播客的习惯 —— 是不是也应该听听看呢？我曾经在 GitHub 上看到过 zijie0 关于「人体系统调优」的 <a href="https://github.com/zijie0/HumanSystemOptimization">指南</a>，里面就介绍过 Huberman。</p><p>这篇指南简单来说，我们可以通过许多「小动作」来调优自身的人体系统，从而达到提升日常工作、获得幸福感的目的。比方说起床先去接触太阳光、晚上要尽量减少和光源的接触…… 当时我阅读的时候，对进食的部分印象很深刻。什么时候吃东西、什么时候不吃东西，尤其是对糖分的摄入，对我们来说都是很重要的。原文讲了很多，建议直接看原文。</p><p>胡拉图这个月另一篇让我印象深刻的文章，是 <a href="https://hulatu.com/posts/2026/04/07/dining-together-stir-frying-vegetables/">《聚餐，其实可以不那么罪恶》</a>。是的，因为他的这篇文章，我出门吃饭会开始优先考虑炒菜配饭，也就是更传统的「下馆子」。</p><p>印象较深刻的一次是，我和项目管理在办公室里不知道吃什么好，就点了个附近一家湘菜馆的「农家小炒肉」，价格当然是不菲的…… 不过特别好吃，燃起了我对青椒的爱 —— 还有猪肉的。</p><p>之前有觉察过一点点，即每次出门吃饭都是干面食什么的，其实营养搭配较单一。我身体状况的一大问题就是摄入了过多的碳水，甚至到了有点讨厌蛋白质的地步：有时候我点面吃甚至会要店家少给肉。只吃面跟只吃方便面的区别也没有差太多吧，问题都是营养不均衡。</p><p>不过沮丧的外部因素还是有的，我吃不惯家附近的餐馆。尽管它们多是健康的地中海菜，但吃不惯就是吃不惯啊。就算是那家湘菜馆，一道菜的价格就已经够我吃两碗粉。而我吃得惯、价格又可以让我接受的餐馆，得坐很久的车才能到。</p><p>最佳的方案是自行炒菜吃，可是电磁炉又炒不动 ——！你们懂炒饭变烩饭的痛苦吗！</p><p>咳咳，问题当然不是这个了，而是我能不能长期主动做饭给自己吃。这些年来我的饮食都是由室友在管，我则是打下手和打扫卫生。如果她不在家的话，根本没有做饭主动性的我就会慢慢饿死自己…… 不，其实是只会做主食给自己吃。先前也说过了，只吃主食是不够营养的。看来我要想办法努力的地方还有很多很多……</p><h2 id="技术与创造"><a class="markdownIt-Anchor" href="#技术与创造"></a> 技术与创造</h2><p><a id="我在-linux-上度过了一年-忘记了去怀念-windows"></a></p><h4 id="我在-linux-上度过了一年忘记了去怀念-windows"><a class="markdownIt-Anchor" href="#我在-linux-上度过了一年忘记了去怀念-windows"></a> <a href="https://www.theverge.com/features/861968/year-using-linux">《我在 Linux 上度过了一年，忘记了去怀念 Windows》</a></h4><p>真好，又是一个离开 Windows、拥抱 Linux 操作系统的人。</p><p>先前的月刊中，我都有表达出对 Windows 系统现状的厌恶之情，并且说到过自己投入了 EndeavourOS 的怀抱中（它是 Arch Linux 的一个发行版）。</p><p>这并不是我第一次接触 Linux 操作系统，高中时我安装过两次 Ubuntu，最后都以失败为终：第一次因为我误删了支撑着底层系统的 Python 而导致电脑用不了，第二次则是因为想要用笔记本电脑重新画画、而购买的数位板驱动并没有 Linux 操作系统可以安装的版本 —— 尽管我换了 Windows 系统，也没有使用笔记本电脑画画过。</p><p>这次切换到 EndeavourOS，说不定可以让我完全脱离于 Windows 系统。为什么说是「完全」呢？因为我还有两台电脑还运行着 Windows 系统，一个是放在父母家的老旧电脑，另一个是放在自己家里的。前者我不常使用，但是妹妹会时不时登录上去玩 Roblox，姑且放在那里当作装饰，等什么时候会长期待在家里了再折腾吧；后者的迁移还在计划中，因为它安装了大量软件，如果有些软件没有 Linux 系统版本的，我还需要寻找替代品。况且迁移本就是一个消耗精力的事情，等未来再说吧。</p><p>文章作者在结尾提到了 Macbook。说来也巧，我最近收拾家里找到了室友过去使用的 Macbook Air。因为系统和型号都过于老旧，支持的软件也就不剩多少了。如果简单折腾一下，说不定可以带在身上作为写文章用的工具，因为它很小一个。</p><p><a id="你撞到了年龄门槛-现在该怎么办"></a></p><h4 id="你撞到了年龄门槛-现在该怎么办"><a class="markdownIt-Anchor" href="#你撞到了年龄门槛-现在该怎么办"></a> <a href="https://www.eff.org/deeplinks/2026/01/so-youve-hit-age-gate-what-now">《你撞到了年龄门槛。现在该怎么办？》</a></h4><p>从去年开始，许多平台陆陆续续开始验证用户的年龄。对于不懂技术的人而言，看到的一面或许会被局限在「未成年者远离了互联网的毒害」这一点上。</p><p>凡事都是多面性的，我说。心理层面要看，技术层面要看，法律层面也要看，这才健全。</p><p>好了不抖机灵儿了。验证机制本身是一种强制性的数据收集行为，收集到的内容包括但不限于用户的面部特征、法定身份证件和金融信息。一旦这些数据离开本地设备，被传输且存储到第三方或平台的数据库中，数据泄露的可能性便呈指数级上升。</p><p>在 <a href="/posts/2590.html">我分析 VPS 服务商们的隐私条款</a> 时，就说过第三方是不可控的，且数据泄露往往发生在第三方供应商。即便平台或供应商承诺阅后即焚，过往无数的违约事件已经证明，冗长的保留期、系统日志的意外记录，以及内部管理的不善，随时可能将用户的核心隐私暴露在不可控的风险之中。</p><p>该文章拆解了当前主流平台的验证机制，能够让我们清晰地看到这些风险是如何在具体的业务流中被放大的。</p><p>大多数平台首选的策略是「推断年龄」，即利用长期监控积累的用户行为数据进行系统猜测。当这一策略失效，用户便会被迫面临更具侵入性的选项，这里只说一些：</p><p>一、Meta 主要依赖第三方供应商 Yoti 进行面部扫描或证件验证。若用户使用面部估算，照片会直达 Yoti 的服务器；若用户被迫上传身份证件，Meta 会将数据留存 30 天，同时交由 Yoti 处理。</p><p>二、Google 的技术分支相对复杂：面部年龄估算采用了 Private ID，将核查过程限制在了设备端。虽然避免了图像上传的直接风险，但验证意图和结果依然会被追踪。</p><p>在电子邮件验证方面，Google 选择与 VerifyMy 合作，将用户邮箱投喂给外部数据源进行交叉比对，让更多不可见的第三方触及了用户的活动轨迹。</p><p>相比之下，通过 Google Payments 进行信用卡验证，因为依托于成熟的金融欺诈保护机制，反而是相对可控的选项。</p><p>然而，若用户上传身份证件，Google 虽承诺验证后删除，却又保留了将其用于「改进验证服务」的权利，这种模糊的声明为数据的实际用途留下了后门……</p><p>三、TikTok 的证件验证合作方为 Incode，而 Incode 根本不会执行行业标准的自动化数据删除，除非 TikTok 触发特定流程或用户主动干预。</p><p>除了这些主流平台外，将合规成本转嫁给用户隐私的做法已然是整个互联网行业的常态。比方说 Spotify 和 OnlyFans 也将数据交给 Yoti，Quora 和 Discord 选择了 k-ID——Discord 还因为曾通过常规客服工作流程发送用户证件而导致近七万张身份证件照片泄露。</p><p>顺带一提，该文章来自于 EFF（Electronic Frontier Foundation），是个非盈利组织，旨在捍卫公民们的隐私、言论自由和技术创新。进入 <a href="https://www.eff.org/issues/age-verification">该链接</a> 能够看到他们撰写的和年龄验证相关的资料，能让你快速理解到年龄验证的问题所在，以及如何保护自己。</p><p><a id="nekogram-会秘密收集并上传用户信息"></a></p><h4 id="nekogram-会秘密收集并上传用户信息"><a class="markdownIt-Anchor" href="#nekogram-会秘密收集并上传用户信息"></a> <a href="https://scg.owu.one/@cdn0x12/statuses/01KN90FCN81257WYB7B9270EG9">《Nekogram 会秘密收集并上传用户信息》</a></h4><p>Nekogram 是 Telegram 的一个第三方开源客户端，但近期被人发现含有恶意代码，会收集和上传全球所有用户账号信息，包括电话号码。</p><p>糟糕的地方在于，代码本身是干净的，但是编译二进制文件不是。也就是说，自己去构建 Nekogram 的话并不会发现这个问题，而直接使用被作者编译好的 Nekogram 的话，就会被该恶意代码影响。</p><p>在察觉到这件事之前，我一度认为这是大家不检查代码导致的问题。现在后知后觉意识到，投毒已经不单单存在于代码这种可以被明面发现的层级，而是需要用到反编译等技能，才能发现。</p><p>这个世上能读得懂代码的人就没有那么多，会反编译的人又有多少呢？</p><p>在 Fediverse 上和朋友们聊起了这件事，最终我的结论是：<strong>必须要对「开源软件」去魅力化</strong>。开源软件没有想象中那么美好，所以你要把它默认成邪恶的软件，努力去检查它，才能避免自己的隐私被泄露，或者保证自己的资产安全。</p><p>这和隐私条款很相似。它们是明面上的，你可以阅读它们来确保提供服务的公司明面上应当怎么做。而真正去发觉公司暗地里怎么做，是困难的。我们不知道公司们拿我们的数据做了什么，我们也不知道 Nekogram 的作者拿用户的电话号码做了什么。</p><p>再就是因为 Nekogram 的作者是中国人，且起初收集的都是中国的电话号码，所以许多人认为数据送给了中国共产党。</p><p>对此事感到好奇的我，在挖掘时发现作者本人过去没少在 Nekogram 上做过糟糕的事情。比方说 2020 年左右，他和 Nekogram X 的人起了冲突，完事又说要在 Nekogram 中添加限制，又通过 Firebase Cloud Messaging 给用户推送侮辱性消息。此事可以在 Nekogram Lite 的作者的 <a href="https://telegra.ph/%E6%9C%89%E5%85%B3-Nekogram-Lite-%E7%9A%84%E6%95%85%E4%BA%8B-04-09">这篇文章</a> 中了解下。</p><p>有趣的是，2020 年 Nekogram Lite 的作者就说过：</p><blockquote><p>如果你使用一个人构建的 app，你应当充分信任这个人，否则你最好自己构建。诘问他「你的 app 有后门吗」是没有意义的。我个人认为这三个应用都还没有出现应用和开源代码不一致的情况。</p></blockquote><p>我也很好奇为什么一个开源项目会演变成如此混乱的局面。但就像我先前说的，我们不知道 Nekogram 的作者拿用户的数据干嘛去了。</p><p>而根据我查看的 Nekogram 讨论频道中的用户态度，放下这件事、继续使用 Nekogram 的人不在少数，因为「这个世界没有隐私而言」。</p><p>又或者说，只要使用虚拟号码就行了。</p><p>虽然很难去吹捧这件事，但确实，在互联网上使用虚拟号码、虚拟邮箱地址是更为安全的。你无法保证哪个网站、软件获取到了你的数据，也无法得知它们拿你的数据做了什么。在互联网上建立一个虚假的自己，才是目前最好的选择。</p><p>上个月我捣鼓了下自己托管的邮箱服务，将原本使用的个人邮箱地址隐藏了起来，改利用别名机制来随时随地创建无数个可以被抛弃的虚假邮箱地址（见 <a href="/posts/a4c0.html#%E6%97%A5%E8%AE%B0%E7%89%87%E6%AE%B5">三月十六日</a>）。</p><p><a id="这不是为你准备的电脑"></a></p><h4 id="这不是为你准备的电脑"><a class="markdownIt-Anchor" href="#这不是为你准备的电脑"></a> <a href="https://samhenri.gold/blog/20260312-this-is-not-the-computer-for-you/">《「这不是为你准备的电脑」》</a></h4><p>Macbook Neo 这几个月发售了，是 Macbook 生产线内第一款低配设备。主流科技评论普遍认为，这款设备受限于较小的内存容量和入门级芯片，仅适合处理日常基础任务，并不适合运行专业创作软件。</p><p>作者则挑战了这一观点：为什么试图为消费者划定明确的使用界限、阻止有专业需求的人群购买呢？</p><p>他给出的证据是，硬件的局限性恰恰能够促使用户产生探索欲。和从底层开始便限制了用户权限的 Chromebook 不同，Macbook Neo 完整保留了 MacOS 系统的架构与软件生态。当用户尝试强行运行超出设备承载能力的软件时，机器会因为资源的枯竭而卡顿。这种反馈是真实的，能让用户直接接触到计算机运算的边界、体会乱调配资源的代价。</p><p>结合自身早期的经历，作者强调 Macbook Neo 真正的受众并非寻求效率最大化的专业人士，而是充满好奇心的初学者。这类群体往往会无视性能的瓶颈，在低配设备上反复测试各类软件，然后逐渐摸索出软件的运行逻辑，并最终挖掘出自身在编程、设计，或者影视制作等领域的兴趣。</p><p>我一直想要搞一台低配设备，用来测试自己项目在它们上能不能跑得动：要是跑得动，意味着我的应用的兼容性高，是好事；要是跑不动，意味着我的应用还不够好。</p><p>去年我阅读了个文章，可惜忘记叫什么了。文章作者推荐网站或者移动端 app 开发者至少购买两台手机：一台低配、一台超低配，然后在它们上面测试自己的网站或者移动端 app。这样做可以直观意识到使用这类手机的用户，如果访问了开发者做的网站或移动端 app 时会看到什么。</p><p>进一步，我认为也可以多入手一些奇怪的设备，例如我就会用 Kobo 阅读器内置的浏览器访问博客网站，因为它默认禁止运行 JavaScript，也不支持许多新颖的 CSS 技术。如果这个浏览器无法正常访问一个博客网站，那我会认为该博客网站在尽力展示文字这一方面上可以做得更好 —— 值得高兴的是，我的博客网站可以通过 Kobo 查看；不高兴的是，我的个人网站不行，因为 SVG 不会展示。这也让我想到，能不能检测访问者的设备是什么，然后返回不一样的内容呢？比方说，用阅读器的浏览器访问的话，就返回个带 ASCII art 的「领地」，实则是纯文本。</p><p><a id="bunnycdn-在过去的-15-个月里一直在悄无声息地丢失我们的生产文件"></a></p><h4 id="bunnycdn-在过去的-15-个月里一直在悄无声息地丢失我们的生产文件"><a class="markdownIt-Anchor" href="#bunnycdn-在过去的-15-个月里一直在悄无声息地丢失我们的生产文件"></a> <a href="https://old.reddit.com/r/webdev/comments/1sglytg/bunnycdn_has_been_silently_losing_our_production/">《BunnyCDN 在过去的 15 个月里一直在悄无声息地丢失我们的生产文件》</a></h4><p>啊，使用 <a href="http://old.reddit.com">old.reddit.com</a> 而不是 <a href="http://reddit.com">reddit.com</a>，这也会是我的新习惯吧。</p><p>帖主在 2025 年 1 月 13 日发现上传到 BunnyCDN 的文件消失了，然后一直到 2025 年 3 月 26 日，这些文件都没有被找回，且没有停止被静默丢失。</p><p>最让人气愤的是帖主期间一直想要和相关人员沟通，却一直在被客服搪塞。</p><p>评论区内有人表示，「在没有验证的情况下，永远都不要信任单一供应商保证的一致性。」他建议无论什么时候都应该定期检查、核实文件数量没错。</p><p>我也有考虑过花点时间把自己从 Cloudflare 那儿移出来。知道了 Bunny 的这次事件，只能慢慢继续找下去……</p><p><a id="使用纯文本邮件"></a></p><h4 id="使用纯文本邮件"><a class="markdownIt-Anchor" href="#使用纯文本邮件"></a> <a href="https://useplaintext.email/">《使用纯文本邮件》</a></h4><p>在阅读 Spike 的新文章时，发现他在文章底部添加了一句话：</p><blockquote><p>如果你有什么想法，可以给 Spike Leung 发送纯文本邮件。</p></blockquote><p>其中，「纯文本」三个字引用的便是本条目引用的网页。</p><p>我总共使用这些邮件客户端：</p><ul><li>mu4e</li><li>FairEmail</li><li>Gmail</li><li>Microsoft Outlook</li><li>Thunderbird</li></ul><p>其中有些客户端是不得已才使用的。读者们想必能猜出来是哪些吧？哈哈。</p><p>网页先是说了如何在客户端里设置成发送纯文本邮件，接着说写纯文本邮件时要注意什么，然后才说为什么纯文本更好。这样做无法说服人们发送纯文本邮件，所以我要从尾开始讲起。</p><p>HTML 邮件有许多问题：</p><ul><li>复制正经公司的邮件模板样式，单在样式上就欺骗用户点击可疑的链接。但如果这些链接是一开始就能被用户看到的，那用户发现问题的可能性就会更大：这个链接怎么是乱七八糟的数字和字母组合呢？</li><li>能够侵犯隐私并追踪收信者。我在公司里要发送一些 newsletter—— 我需要澄清，不是营销邮件，而是公司博客更新时要连带着发送的 newsletter—— 使用的平台就会在邮件里藏标识符，从而得知收信人们有没有打开邮件。这一点也被广泛利用于诈骗邮件，看看收信邮件地址到底是不是活人地址；</li><li>能够规避垃圾邮件过滤器 —— <em>ewww!</em></li><li>有可能泄露信息，并执行恶意代码；</li><li>可访问性很差很差很差很差……</li></ul><p>有趣的是，纯文本邮件礼仪中鼓励使用底部回复，而不是顶部回复。顶部回复是把我们的回应放在引用内容的上方，实际上并不好用。推荐的用法是这样的：</p><pre><code class="language-markdown">你好，&gt; 一加一等于二。我认为你这句话不对！</code></pre><p>而不是：</p><pre><code class="language-markdown">你好，我认为你这句话不对！&gt; 你好，&gt; 一加一等于二。&gt; 再见。&gt;&gt;&gt; 你好，&gt;&gt; 我是 JavaScript 星人，我认为一加一等于一一。&gt;&gt; 再见。</code></pre><p>可悲的是，Microsoft Outlook 不支持底部回复。</p><p><a id="ai-音乐有关"></a></p><h4 id="ai-音乐有关"><a class="markdownIt-Anchor" href="#ai-音乐有关"></a> AI 音乐有关</h4><p>还没有这么重视写博客之前，我常和网络上的人就「AI 绘画」一事吵架：我认为 AI 绘画不好、人可以画出更好的画。就算画工不好也能画出感觉，比方说我认识一位很「奇特」的大叔，他身上永远带着一个小本本，写日记用的。在写日记的时候，他会在本子上涂涂画画。虽然从来没有系统性学习过绘画，画出来的东西像是小孩子画得一样，但画多了便有了自己的艺术风格。我和一些从事美术行业的朋友们看了，从来不会觉得画得烂，而是很欣赏他能够每日作画的耐力，以及想象力和创造力。</p><p>绘画的重点是「创造」，这和写作以及作曲是一样的。</p><p>不过我实际想要说的是第三个、我完全没有涉足过的领域 —— 音乐。我对音乐的了解很浅，所以有错就纠错吧。</p><p>几个月前 Vocaloid 圈出现了一首热度不低、制作时涉及到 AI 生成的歌曲。这首歌参与了 <em> The VOCALOID Collection</em> 比赛。在被质疑使用了 AI 后，涉事 P 主主动清空了所有社交媒体的账户、逃跑了，比赛资格自然也被取消。</p><p>有意思的是整个事件，听众们的各路观点。我很难想象有人因为觉得歌好听，所以认为反对这首歌的人都是大傻蛋 ——「不管是不是 AI 制作的，好听就行。」这种话真是傻到极致，令我怀疑说这种话的人有没有考虑过 AI 作曲背后的问题。</p><p>我不会说出涉事歌曲的名称，因为不想要让不知情的人们再给它贡献播放量 —— 好笑的是，几个月前 Vocaloid 圈又发生过一起涉及到「未成年性爱和怀孕」话题的歌曲。虽然涉及到「性爱」或者直接说「低俗」的歌曲在 Vocaloid 圈内并不少见，我也不认为那有任何问题，但将「未成年性爱」视为娱乐性质话题的作品被大众抵制也没有任何问题。</p><p>很快这首歌在国外就被下架，不过转载到 BiliBili 上的歌曲没有，反而因为被太多人提起、有越来越多的人知道了这首歌，并以「攻击」的名义贡献播放量、二次创作数量、拉高了整体的热度。这是让我感觉匪夷所思的地方：这种歌，你不要管它，让它慢慢死去就好了。为什么就是有人要想办法盘活它呢？这便包括了大量的将涉事歌曲洗干净的二创视频，例如「没有性爱画面或者声音的话」。</p><p>事实是，无论如何这首歌都是在以将未成年怀孕的事情娱乐化的态度下写出来的。再去创作更多的二次作品，都是在给它送热度和讨论度，延长它在 Vocaloid 圈的寿命。</p><p>我对涉及到 AI 生成的歌曲也是一样的态度：不要给它送任何热度了！所以我决定不提出这首歌的名称，感兴趣的可以自行搜索。不过为了方便，还是将这首歌简称「歌曲甲」。</p><p>歌曲甲的争议中，支持者为了维护这首歌可谓是想尽了方法。比方说先前提到的，「只要歌好听」的假中立：说是中立，但自己真的是中立吗？说到底，不还是承认了歌曲里有 AI 生成的部分，并且认同了这个做法、继续听下去么？</p><p>我对歌好听与否，不给出任何主观的评价。我想要探讨的是，歌曲甲为什么被人们认为是好听的？所有人都有自己的口味没错，但也要想到 AI 音乐，即 Suno AI 这一派是如何生成音乐的。市面上的 AI 生成音乐，都是基于深度学习模型的，即通过分析大量现有的音乐数据来学习各种音乐元素的模式。根据训练时使用了什么音乐，生成出来的音乐在风格或者特征上也会和那些歌有相似之处。这一点和 AI 生图以及写作是一致的，都是站在了巨人的肩膀上预测下一步应该发生什么。</p><p>既然「分析」了这么多音乐，那生成一首「好听」的歌，也没有什么问题吧？倒不如说很正常，只要训练数据都是好听的歌。</p><p>另一个支持者们绞尽脑汁想出来的反驳点是，「Vocaloid 不就是 AI 吗？凭什么 AI 作曲就不行了？」—— 这或许就是为什么，说词一定要说完整吧（我的 <a href="/glossary/">辞典</a> 还没写完呢……）。<em>AI</em> 本身就是个模糊的大概念，就连不智能的早年 Siri 也是 AI 的一部分。现在人们常说的 <em> AI</em> 要不然是「生成式大语言模型聊天机器人」（ChatGPT），要不然就是「生成式大语言模型」（GPT）。像 Gemini，前者和后者都叫作 <em> Gemini</em>，所以不好分辨、容易产生误会。但是 ChatGPT 和 GPT 的区别，我想读者们还是可以分辨出来的吧？</p><p>Vocaloid 软件通过学习声源主人的发声，从而能够发出近似声源主人的声音。虽然都是「学习」，但重点在于 Vocaloid 是工具，专门针对声源进行了大量的采样、最终做出来的电子声源，属于电子乐器的一种。它不会影响到人们创作音乐，反而能够帮助音乐制作人们做音乐。因为不会替代音乐制作人，也不涉及到盗取他人作品和抄袭等问题，自然也没问题了。</p><p><a id="stalwart-出问题"></a></p><h4 id="stalwart-出问题"><a class="markdownIt-Anchor" href="#stalwart-出问题"></a> Stalwart 出问题</h4><p>本月我自托管的邮件服务出了大问题。因为我的小错误，数据遭到了丢失，并且邮件服务在一周内都无法正常使用。</p><p>好在邮件数据在我的一些客户端内留有缓存，恢复了，并且这只是我手动做出的错误导致。如果是我的 VPS 出了不可抗拒的问题，那我托管的网站、邮件服务、Fediverse 实例…… 都会无法使用。相当于我这个人在独立互联网上人间蒸发了！</p><p>所以还需要考虑再弄台备用的服务器。嗯，现在没有那个资金啊，并且我租用东西都是一租租好几年。一下子让我掏出很多钱出来，不行啊不行。</p><p>我也想过将不用的主机升级下，弄台自己的服务器当备用使。不过很显然，自己并没有过剩的精力去处理这件事。</p><p><a id="查阅漫画-下载漫画-同步漫画到-kobo-上"></a></p><h4 id="查阅漫画-下载漫画-同步漫画到-kobo-上"><a class="markdownIt-Anchor" href="#查阅漫画-下载漫画-同步漫画到-kobo-上"></a> 查阅漫画、下载漫画、同步漫画到 Kobo 上</h4><p>我上个月买了台 Kobo Clara BW，喜欢的不得了。因为是黑白的，也很适合阅读黑白漫画。所以我尝试了下，将网络上的漫画资源下载下来、批量转换成 KEPUB，然后通过 Calibre 有线传输到 Kobo 上。</p><p>别说，效果很不错！我一次性传输了《金田一少年侦探事件簿》的二十多卷上去，有事没事就翻翻看。</p><p>说到漫画，看单行本的感觉和追连载的感觉真是不一样。单行本可以流畅地阅读下去，而追连载的体验无论是周更还是月更，都有种会忘记上次讲到什么的感觉。比方说《战队大失格》，每次追连载都觉得春场葱你这家伙到底在写个什么玩意儿啊！但从头读下来又会觉得没那么糟。</p><p>总之我用 agent 挫了个小项目 <a href="https://git.cytrogen.icu/cytrogen/kobo-manga">kobo-manga</a>（好简单粗暴的名字），可以爬取漫画平台、搜索指定的漫画并下载、转换，然后无线传输到 Kobo 上。咦，无线传输？是怎么做到的呢？这需要修改 Kobo 内部的 API 地址，指向该项目跑起来的服务器。反正我也不会花钱租用书，Kobo 自己的服务器对我来说可有可没有。</p><p>我参考了 calibre-web 的写法，因此项目只能使用 GPL 系的 license 啦。目前很多东西都不咋完善，感兴趣的就来看看、贡献吧。</p><p><a id="agentic-coding"></a></p><h4 id="agentic-coding"><a class="markdownIt-Anchor" href="#agentic-coding"></a> Agentic Coding</h4><p>这个月花了些心思在 agentic coding 上。我有个项目得使用 LLM 生成代码，但纯靠自己监督 LLM，效率不仅低，有时候脑子放空进入了 vibe coding 的状态后，生成的代码既危险又难以维护。</p><p>TW93 上个月开始写了些和 agent 相关的文章，分别是：</p><ul><li><a href="https://tw93.fun/2026-03-12/claude.html">《你不知道的 Claude Code》</a></li><li><a href="https://tw93.fun/2026-03-21/agent.html">《你不知道的 Agent》</a></li><li><a href="https://tw93.fun/2026-04-03/llm.html">《你不知道的大模型训练》</a></li><li><a href="https://tw93.fun/2026-04-26/ai-coding.html">《你不知道的 AI Coding》</a></li></ul><p>从中主要是学习到了 agent 的运作流程，以及 context 的重要性。</p><p>TW93 在过去的 <a href="https://weekly.tw93.fun/posts/262">周刊</a> 里分享了 <a href="https://github.com/garrytan/gstack">gstack</a> 这套 skills。它是 Y Combinator 的 CEO Garry Tan 搞的。起初试用时发现效果不错，但是整套 skills 里有大量的推广…… 说实话很烦，就算它分享了许多 Paul Graham 的文章给我。并且 gstack 很重很重很重，其中的 <code>/browse</code> 命令要求用户安装 chromium，对于不希望在笔记本电脑里看到它的人来说很讨厌。</p><p>之后发现 TW93 自己搓了个 <a href="https://github.com/tw93/waza">Waza</a> 出来，我也试用了下。毕竟它是 TW93 自己的 skills，不一定贴合我的使用场景。最终我决定根据 TW93 的《你不知道的谁谁谁》系列，将 gstack 和 Waza 里我常用的功能提取了出来，捣鼓成了这个叫 <a href="https://git.cytrogen.icu/cytrogen/loom">loom</a> 的库。</p><p>loom 的话，要比 gstack 轻一些，比 Waza 重。目前还在慢慢调整，有问题的话就联系我吧。</p><p>但无论如何，skills 都只是让 LLM 生成的结果可靠了些，最终还是需要人类的介入和审查。</p><hr><h2 id="折腾博客"><a class="markdownIt-Anchor" href="#折腾博客"></a> 折腾博客</h2><p><a id="基于邮件列表的评论系统"></a></p><h4 id="基于邮件列表的评论系统"><a class="markdownIt-Anchor" href="#基于邮件列表的评论系统"></a> 基于邮件列表的评论系统</h4><p>不知道有没有朋友记得我说过的 <a href="/posts/e3b9.html#webmention-%E5%92%8C-syndication">基于电子邮件列表的评论系统</a> 呢？我搓了原型，仅作为实验用：现在你可以在文章的最底部发现「邮件评论」板块。</p><p>原理是这样的：我有一个 <code>post-xxxx@blog.cytrogen.icu</code> 的邮箱地址，它也利用了 Stalwart 的 <code>catch-all</code> 机制，在我不需要手动创建用户名的情况下接受邮件。</p><p>接着 Stalwart Labs 开发的现代基于 HTTPS 的协议 Mail Transfer Agents 的 hook 会在 data 阶段将其 POST 到我服务器上的一个服务上，用于解析 hook 的 JSON、重组原始的邮件，并根据收件地址前缀路由。然后 <code>mailparser</code> 库会解析邮件，提取 <code>From/Date/Message-ID/In-Reply-To/Reference/正文</code>，去掉邮件的签名（<code>-- \n</code> 之后的内容），最终写入 JSON 文件。</p><p>如果是新的发件人，邮件会送到 <code>held/</code> 目录，而白名单内的发件人发送的邮件会检测 SPF 跟 DKIM，要是通过了就进入 <code>approved/</code> 目录。进入 <code>held/</code> 时，程序会给我发送审核通知邮件。</p><p>重点的邮件列表流程是，每次程序检测到新评论时，都会以邮件列表模式转发给该文章的所有其他评论者。转发邮件的 Message-ID 等同于评论的 Message-ID，<code>From</code> 会显示评论者的名字，带有 <code>List-Id/List-Unsubscribe</code> 头。接着收件人可以直接回复。</p><p>但这种做法并非是最佳的，说出来是为了抛砖引玉，搞这个东西也只是为了好玩。</p><p><a id="添加-webmention-发送入口"></a></p><h4 id="添加-webmention-发送入口"><a class="markdownIt-Anchor" href="#添加-webmention-发送入口"></a> 添加 Webmention 发送入口</h4><p>是的，我给文章的 Webmention 板块添加了个发送入口 —— 终于。</p><p>最初从 Spike 那儿得知 Webmention 的时候，他就已经实现了个入口。我不是没看见，我是偷懒了，一直没加上去…… 同样引入了 Webmention 的 Eltrac 也在自己的网站中添加了该入口。嗯，我也偷懒假装没看见了。</p><p>之后是 <a href="https://v1sta.xyz/">远景 v1sta</a> 主动向我提议添加这个入口，我才添加的。唉，所有多么希望文章下方有个发送入口的朋友们，我对不起你们 ——！</p><p>总之它现在会出现在 Mastodon 回应的按钮上方，点击它会自动发送 Webmention 给当前的文章。</p><p><a id="加入了-indie-webring-社区"></a></p><h4 id="加入了-indie-webring-社区"><a class="markdownIt-Anchor" href="#加入了-indie-webring-社区"></a> 加入了 Indie Webring 社区</h4><p>个人主页里可以看到右下角的方向牌和戒指形状的小蜘蛛 —— 我不管，蜘蛛有六条腿，《饥荒》里是这么说的！</p><p><a href="https://xn--sr8hvo.ws/">Indie Webring</a> 是一个虚拟社区，以「环」的形式将独立个人网站串联在一起。不过比起「环」，我认为「车站」这个概念更易懂：每个独立个人网站都是一个站点，你可以坐车去上一站，也可以去下一站。这就很像国内的 <a href="https://www.travellings.cn/">开往</a>，不过我现在还没有加入开往。</p><p>为了实验，我临时在个人主页中添加了 /webring 页面，是为了展示 /friends 里所有有 Indieauth 的网站。但这种做法应该是会被我抛弃，改成重构 /friends 页面时，直接给有 Indieauth 的网站特殊的小房子样式。</p><h2 id="我写的文章"><a class="markdownIt-Anchor" href="#我写的文章"></a> 我写的文章</h2><ul><li><a href="/posts/c2db/">《了解 Kagi 的历史》</a></li><li><a href="/posts/794/">《入坟编写 SVG》</a></li><li><a href="/posts/a4c0/">《想法在丙午蚕月迭代》</a></li><li><a href="/posts/f8cc/">《观《八号出口》》</a></li><li><a href="/posts/fd71/">《观《河狸变身计划》》</a></li></ul><h2 id="编程历程"><a class="markdownIt-Anchor" href="#编程历程"></a> 编程历程</h2><p><a id="gotosocial-和-masto-fe-🦥-flavour"></a></p><h4 id="gotosocial-和-masto-fe-flavour"><a class="markdownIt-Anchor" href="#gotosocial-和-masto-fe-flavour"></a> GoToSocial 和 Masto-FE (🦥 flavour)</h4><p>GoToSocial 很轻量不错，但是功能也太少了吧！比方说引用功能就没有。我自行 fork 了 GoToSocial 下来，添加了引用功能 —— 说来也巧，源代码里其实有支持引用的代码，但是没有被真正使用，怀疑是等到未来一大版本才打算添加上去。</p><p>添加了引用功能后，我在 Masto-FE (🦥 flavour）上可以正常使用它。但有天我发现其他第三方客户端不会显示引用按钮，怎么会呢？</p><p>总之在一顿操作下，我依然无法让其他第三方客户端显示引用按钮，尽管我在 Nodeinfo、Mastodon 版本上都声明好了我这个 GoToSocial 可以引用…… 后来我想到，为什么我非要在第三方客户端上费力不可呢？我会使用它们，是因为 Masto-FE (🦥 flavour）在浏览器上无法以 web app 的形式安装在桌面，那我直接让它具备条件不就好了？所以现在 <a href="https://masto-fe.cytrogen.icu/">masto-fe.cytrogen.icu</a> 可以被当成 web app 安装了。</p><p><a id="一个域名管理无限邮箱别名"></a></p><h4 id="一个域名管理无限邮箱别名"><a class="markdownIt-Anchor" href="#一个域名管理无限邮箱别名"></a> 一个域名管理无限邮箱别名</h4><p>过去我看到过一个解决「贩卖个人信息」的方案：注册一个平台的账户时，将姓名刻意写成那个平台的名字。比如注册 Yami，就把姓名改成 Yami 什么什么。如果诈骗电话打过来，问你是不是 Yami，你就明白是 Yami 贩卖的你的个人信息。</p><p>我想要弄一个类似的计划，来解决电子邮箱的收信箱里到处都是营销邮件的问题。这里自然也牵扯到了贩卖信息的问题，那为了找到这个「犯人」，我也需要在注册时做些文章。可惜，这些营销邮件和诈骗文件不同，有时候并不会叫我的名字。同时我也需要封禁这个「犯人」，那该怎么做呢？</p><p>我的逻辑是，搞到一堆可以随时抛弃、且收到邮件时就自动转发给指定电子邮箱地址的邮箱地址们。可惜这种随便就能被舍弃的邮箱地址，并不多见，就算有恐怕也被主流平台屏蔽了。所以我的进阶方案是，给主要的邮箱地址设置匹配所有用户名的别名，这样注册账户时，随意编的邮箱地址依然可以将邮件汇入主邮箱。而我在主邮箱的收件箱中查看邮件时，能够看到对方究竟是发给了哪个别名，从而判断出是哪个别名被泄露、哪家平台偷偷卖了我的个人信息。</p><p>那么就开始工作吧！</p><p>我使用的邮件服务是 Stalwart，非常好用和全能，推荐。它支持 <code>catch-all</code> 功能，需要设置 <code>session.rcpt.catch-all = true</code>，然后给主账户添加 <code>@domain.suffix</code> 作为别名后，所有发往该域名、但没有对应账户的地址，都会投递到主账户的收件箱内。</p><p>解决了「发」的问题，现在来解决「封禁」的问题。在我的构思中，我需要 Web 入口，能让我随时随地拉入别名到黑名单中，避免进一步地污染我的收件箱。我折腾了一个轻量的 Go 服务，提供 Web 界面管理黑名单 ——VPS 内存紧张，省着点用，Go 在这一点上就很不错。总之它的原理是，当我输入要拉黑的别名时，它会将其写入本地的 <code>blocklist.json</code>，然后根据黑名单生成 Sieve 过滤脚本、通过 Stalwart API 上传脚本并重载配置。</p><pre><code class="language-plaintext">require ["envelope"];if envelope :is "to" [  "random@domain.suffix"] {  discard;  stop;}</code></pre><p>这里使用 <code>discard</code> 来静默丢弃邮件，发件人不会收到任何退信通知，从而也不会暴露邮箱地址其实不存在。</p><p>脚本需要被注册为 <code>session.data.script</code>、在邮件 DATA 阶段全局生效。</p><h2 id="书籍"><a class="markdownIt-Anchor" href="#书籍"></a> 书籍</h2><h4 id="其他评价"><a class="markdownIt-Anchor" href="#其他评价"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/book/6lHChcwz9FfIUDfIfp7LnA" target="_blank" rel="noopener noreferrer">不原谅也没关系</a><span class="neodb-rating">★★★★★</span><span class="neodb-status">在读</span><p class="neodb-comment">读的过程中学习到了许多，间接改变了我看待他人的方式。不过之前读到一半便没有继续下去，暂且标记为「在读」。有时候会出现冗余、重复过的内容，可能是当时弃置的原因。</p></li><li class="neodb-item"><a href="https://neodb.social/book/2IAnq63LPCtDAXIWczIYDm" target="_blank" rel="noopener noreferrer">Getting divorced from mother &amp; dad</a><span class="neodb-status"> 想读 </span></li><li class="neodb-item"><a href="https://neodb.social/book/7DxBbK9hVrHnckUoYeNYVM" target="_blank" rel="noopener noreferrer">Writing GNU Emacs Extensions</a><span class="neodb-status"> 想读 </span></li><li class="neodb-item"><a href="https://neodb.social/book/3RxPfnW0VPCwN19rxMkxAn" target="_blank" rel="noopener noreferrer">Memoirs of a Revolutionist</a><span class="neodb-status"> 想读</span></li></ul><h2 id="影视"><a class="markdownIt-Anchor" href="#影视"></a> 影视</h2><h4 id="其他评价-2"><a class="markdownIt-Anchor" href="#其他评价-2"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/tv/season/4KrAYHb0Uad5EIa8X6yOHb" target="_blank" rel="noopener noreferrer">诈欺游戏 第一季</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已看</span><p class="neodb-comment">虽然细想女主人设问题很大，但个人看的时候不会觉得有什么，也不清楚为什么，反而觉得大家一直管她叫「直ちゃん」还挺可爱的。<br>女主演员真的好漂亮好可爱 www 心理诡计还可以，水平不算太高，看的时候可以推出来一些。搞笑桥段很多，我更多是把这部当喜剧片来看。有很多早年电视剧的经典桥段，对我来说影响不大，在意的人估计会嫌烦。</p></li><li class="neodb-item"><a href="https://neodb.social/movie/6rSxZ5Ycri1Jr0kj86BHAb" target="_blank" rel="noopener noreferrer">8 号出口</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已看</span><p class="neodb-comment">因为是游戏改电影，所以我对它的期待没那么高，看完后反而觉得很不错。演员演技很好，音效方面也可以。</p></li><li class="neodb-item"><a href="https://neodb.social/movie/0wKIhL3cZWrGKaDctLomq2" target="_blank" rel="noopener noreferrer">河狸变身计划</a><span class="neodb-rating">★★★☆☆</span><span class="neodb-status">已看</span><p class="neodb-comment">看的时候不带脑子看的，因为看之前就被剧透了…… 作为儿童向电影，笑点挺多的，也有看了想哭的地方（最后高潮部分我就看得鼻子一酸），很不错了。画风真的很可爱很可爱。</p></li></ul><h2 id="音乐"><a class="markdownIt-Anchor" href="#音乐"></a> 音乐</h2><h4 id="其他评价-3"><a class="markdownIt-Anchor" href="#其他评价-3"></a> 其他评价</h4><p>本月暂无记录。</p><h2 id="日记片段"><a class="markdownIt-Anchor" href="#日记片段"></a> 日记片段</h2><p>本月税务季结束了（其实没有，延期的话能延个好几个月呢，相当于这期间我还是会花时间在工作上，呜呜呜）！我想要把时间尽可能地分摊给博客，要有个好习惯嘛。不过可惜的是，我很多时候时间还是碎片化的，除了奶头乐外，很难再有其他适用的娱乐方式 —— 不对，还有写嘟文。</p><p>我让 agent 编写了个「月度嘟文回顾」的网页出来，并部署在了 <a href="https://gtsm.cytrogen.icu">gtsm.cytrogen.icu</a> 上。它会按月显示我的所有嘟文，然后按日分组展示。这样我就可以翻阅本月中我记录下的事情，找出我依然觉得有意思的，然后专门写出来放月刊里。整个日记板块太长了，也夹杂着许多零碎的自言自语。这样提取出个别精华，重新包装一下放给读者看，我想是不错的。</p><p><a id="穿衣搭配"></a></p><h4 id="穿衣搭配"><a class="markdownIt-Anchor" href="#穿衣搭配"></a> 穿衣搭配</h4><p>我曾经受母亲的负面影响，并不喜欢打扮自己。她喜欢所谓阳光的女孩，而我不是那类人：我被迫扎着要把我头皮都撕扯下来的高高高马尾，也被迫穿着上面画着莫名其妙图案或者写着莫名其妙字眼的衣服。说实话，这很丑，但我不配有自己的审美，也不敢去探索那方面的事情。</p><p>之后是朋友的介入让我意识到打扮很重要。你其实都不需要化妆，至少要把自己打扮得干净利索，然后找出适合自己的穿衣风格。我最开始是白衬衫 + 海军蓝毛衣衫 + 西装裤，现在把白衬衫改成了可以遮住脖子的高领羊毛衫，西装裤改成裤腿更宽的裤子。</p><p>现在很多人的穿衣风格都很统一化、固化，例如随处可见的黑色卫衣 + 黑色运动裤 + 黑色运动鞋，真的很像精神小伙好吗。适合自己的搭配，可以显著提升自信。</p><p>有一点想要单独拿出来说的是西装颜色，我建议不要购买黑色或者蓝色的西装，这也包括海军蓝。前者会让你看上去像大堂经理和服务生（黑色的裤子都有点这种感觉），后者会显得你像个刚买西装的实习生。我更推荐灰色的西装。</p><p>在西装的搭配上，还可以在领带上做文章：领带的颜色和图案、系的方法、长短都会影响到西装整体是更偏休闲风，还是严肃的商务风。</p><p>我过去穿衬衫的时候，还买过衬衫夹。它是一对带子，可以绑在腿上。带子上的夹子能够夹住衬衫的角、往下拉，保证衬衫角不会从裤子里跑出来。</p><button id="details-toggle-diary_sections-1789678111116" class="details-toggle-btn" data-group="diary_sections" onclick="toggleGroupDetails('diary_sections', 'details-toggle-diary_sections-1789678111116', '展开所有', '收起所有')">展开所有</button><details data-group="diary_sections"><summary>四月一日</summary><div class="diary-entry">01:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN3AGHZC8SQG37E97EFYY9RY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>I dont like Coco because it tastes more like tea, not a perfect combination of syrup, milk (powder), and tea. But its mascot and cup design is pretty cute.</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KN3AGG9ZQX73DRP8PE0T8ZYG.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">01:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN3AR6KXR71BQJ7Y9FNVGFF9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>I hate NYC weather. The forecast literally said it would rain today but turned out not one single drop was generated by the clouds. Now I am the only one holding a black 99 cents umbrella on the street <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ2GHQQKSNN4ZAV8P6GNWA5.png" alt=":blobcatangrybongo:" loading="lazy"></p><p>No, the umbrella does not cost 99 cents. It is 2026 now.</p><p></p></div><hr><div class="diary-entry">01:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN3BQMJAXGTW0DFTJQYV88PJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Trying out Thunderbird as an email client on my computer yesterday. There is a setting named <em>Attach a VCard</em>. I thought it's like signatures but more professional, so I sent an test email with VCard attached to another email address of mine; however, nothing showed up. I am pretty curious at this point……</p><p></p></div><hr><div class="diary-entry">02:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN3D6Y0YF9B3ED1MR7010MRB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>I just got home and saw an old lady walking around the building's entrance. My apartment's main door is always locked, so I was wondering if she had forgotten to bring her keys or something. Surprisingly, she was there to return packages that were accidentally delivered to her place.</p><p>USPS people always make mistakes, like they never pay attention to the package label. Fortunately, the old lady's apartment isn't far, so I took the packages and placed them right at their owners' doors.</p><p>When leaving, she said <em>thank you</em> to me. I replied, <em>No, thank you for your kindness. Normally, people just take the misdelivered packages or throw them out. It is nice of you to try to return them.</em></p><p></p></div><hr><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMW0B11WX8FRR804KHP6DCMS">↩ 续前文</a>        </div> 02:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN3DN72P5J862X5P6M3E43KF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>因为担心是我的心理作用，比如比起官方客户端更喜欢开源的第三方客户端、误以为后者播放的音质更好，所以让我心目中耳朵更精的室友听了一下。她单是听到后者播放的音乐一秒，就说这两个区别很大，问我后者是不是官方的客户端，因为在她心里官方的客户端才应该有好的质量。</p><p>不过生气的是，她听完我的说明后赞赏道「没想到你都能听出来」—— 虽然我不会弹奏乐器，唱歌也唱不到调上，但我不是木耳朵好吧！</p><p></p></div><hr><div class="diary-entry">02:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN3E4WWTP3XRX80NN139A0X2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有时候会看到不明所以的帖子，即明明是「回复帖」，但点进去看不到原帖，只能看到孤零零一个艾特了原帖主的回复。检查日志时发现是原帖被删除了，服务端检索时跳过了它。</p><p>我不喜欢这样的静默设计。被删除的话就大大方方表示出来嘛，害我还在瞎猜。</p><p></p></div><hr><div class="diary-entry">02:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN3EME6SHFEWYD13NKNEV2T9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>It's <em>not</em> the Spring break! And <em>not</em> the April's Fools Day which I can use my fake ID card with fake birth date to fool everyone around! Yes, I am <em>not</em> going to watch a movie tomorrow. It is <em>not</em> a kids movie, and I am definitely <em>not</em> excited!</p><p></p></div><hr><div class="diary-entry">18:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN53S4C0KKC6SHM6Q5RZAE3P" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>电影被实际播放前的几十分钟会播放其他电影的预告片，再往前一点就是播放专门给影院设计的广告了。其中，我看到了 Chuck E. Cheese 的广告。受 FNAF 系列的影响，我每次看到它都会想到吉祥物恐怖作品…… 不过小时候确实去过 Chuck E. Cheese 玩，他们家的披萨是少数我很爱吃的披萨。至于街机嘛，是传统的充值游玩、靠得分获取票票，然后用票票换玩具的机制。我玩游戏很菜，不是那么爱玩，现在玩街机只会玩舞萌 DX 了。</p><p></p><blockquote class="diary-thread-reply">20:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN5A40DKGDXDVPHDN63PQAG8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看完了今天这场电影，感觉有些微妙，许多想要探讨的问题都被汇集成了一个 <strong>个体</strong>。之前看动物城 2 也是这种感觉，好似打败这个个体所有的问题便也解决了。我很不喜欢电影结尾会出现疯子反派 BOSS 的设计。</p><p></p><blockquote class="diary-thread-reply">20:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN5ACMXY4NQM76JNKVZ5M0SY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>早上睡过头了还没吃早饭，想到麦当劳结果发现已经走过了，懒得回去便继续往前走。然后我看到了 Panda Express—— 不，我不要进去！</p><p>纽约许久都没有今天这般舒适的天气，让我想要到处走走，可是我还有工作要做。走着走着，路口冲进来一辆 e-bike，好似要把行人们撞死一般。妈的，能不能慢点，不要在人行道上骑车啊。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">20:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN5B7EB8RYXPZRYR93NKG86N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>拿带着假生日日期（AKA 今天的愚人节）的 ID 骗人，得到了诚实的称赞 —— 我再也不骗人了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy"></p><p>初中有个小傻叉被我骗，说「愚人节出生的人的人生都是笑话。」现在很好奇这个人生不是笑话的家伙在过怎样的人生。</p><p></p></div><hr><div class="diary-entry">22:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN5GZ5PJ6GVHN1CZ65BTFAX6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Masto-FE (🦥 flavour）虽然代码里有 i18n 功能需要的语言模板，但是却没有实际可以调用的入口。这在我的 fork 中修复了。</p><p>是不是应该贡献一下……</p><p></p></div></details><details data-group="diary_sections"><summary> 四月二日</summary><div class="diary-entry">02:18 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/945142301750325335" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>匹克猫在扫地机器人的箱子里。</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/31410d826-759a86/lQljB9KoNBb1/HLUcSqOU1vbKxv36WfI2uTinbCm3FcxEP9F4OuRX.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/31410d826-759a86/acbz2YyHKMUx/uZr906obSZk7Y5pqh7St2H6J4ptZZgihKDrKJ38T.jpg" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>四月三日</summary><div class="diary-entry">16:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNA3C1CWHM9EVDXQAT67G2D1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>你的意思是我的包裹从 Austria 到了 Ohio 然后到了 Germany 到了 New York 是吗。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNA3BZF41CNANHFJFRF5B81N.png" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNA3BYDW3WPPZT9W42JZFPH1.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">18:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNA8X965QZVVWB1TC9N1MFXV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>I was singing this:</p><blockquote><p>Dumb ways to die.</p><p>So many dumb ways to die.</p><p>Dumb ways to die-ie-ie.</p><p>So many dumb ways to die.</p></blockquote><p>It was viral before, isn't it?</p><p></p></div><hr><div class="diary-entry">18:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNAA85WFKMBX80SFGAFH8VYP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>萌萌的。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNAA8494DDC9M8FWD1AK9KSP.jpeg" alt="Kagi Swag、Kagi 黄色袜子、Kagi 贴纸、Kagi 黑色 T 恤衫。" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>四月四日</summary><div class="diary-entry">01:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNB0YG68W49P4X391SVF2SSR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看样子我花费了一个下午去翻阅这些东西。这些是我目前为止发现的有趣的东西：</p><ul><li><a href="https://news.ycombinator.com/item?id=40013592" rel="nofollow noreferrer noopener" target="_blank">https://news.ycombinator.com/item?id=40013592</a></li><li><a href="https://d-shoot.net/kagi.html" rel="nofollow noreferrer noopener" target="_blank">https://d-shoot.net/kagi.html</a></li><li><a href="https://web.archive.org/web/20240412081005/https://hackers.town/@lori/112255132348604770" rel="nofollow noreferrer noopener" target="_blank">https://web.archive.org/web/20240412081005/https://hackers.town/@lori/112255132348604770</a></li></ul><p></p></div><hr><div class="diary-entry">14:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNCF41DVK1VFKTKWX1Q5Y4QM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>初中开始我疑似有了拔毛癖，是强迫症状的另一个表现吧。总之我现在眉毛秃掉了半边 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy"></p><p></p><blockquote class="diary-thread-reply">16:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNCMGGAX4EGREP5CEZVPBXBG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说到强迫症状，小时候有看到文字就想分类的冲突（我还写了 <a href="https://blog.cytrogen.icu/posts/cf35.html" rel="nofollow noreferrer noopener" target="_blank">文章</a>）。</p><p>初中开始沾上了拔毛癖，甚至还会去拔同学的头发…… 以前好暴力。总之是拔掉所有和其他毛发不同的毛，比如白头发、红头发、金头发等，还有头发的分叉，以及拔掉我认为它不应该出现在那儿的毛，像大拇指根部上的毛都会被我拔掉。结果初中那时候手总是红肿的。</p><p>高中有段时间没有再拔毛了，是段少见的没有强迫行为的时期，具体原因不详。不过后面还是回来了…… 我是一个非常焦虑的人，很难静下心来做事情。</p><p></p></blockquote></div><hr><div class="diary-entry">16:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNCN5109QNESJVWEHFMAX3H2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://help.kagi.com/kagi/plans/family-plan.html#poopavatar" rel="nofollow noreferrer noopener" target="_blank">https://help.kagi.com/kagi/plans/family-plan.html#poopavatar</a></p><p>道理我都懂，但是为什么有大便 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ4DD324BDCVH6YWF2AVV4.png" alt=":ottersgottaott15:" loading="lazy">​</p><p>其实有思考自己开个家庭组，把妹妹或者亲密的朋友加进来。但是公立学校已经强迫学生们使用 Google 的服务；室友嫌 Kagi 太小，再加上我们公司用的是 Google Workspace 服务。</p><p></p></div><hr><div class="diary-entry">17:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNCQBMVTJNGWBXMAWB0ZBFW7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>简单地做了下 Kagi 的历史的功课。暂且不知道塞到文章里好，还是塞到月刊条目中好。毕竟 Kagi 再怎么折腾也是个小公司，历史再怎么翻阅也没有那么多值得说的。</p><p>在 2026 年的现在看到 Kagi 已经有了近七万付费会员，还是挺欣慰的（虽然我也就用 Kagi 用了两个月）。和大公司肯定是没法比的，但是作为正在折腾初创公司的后辈来说，Kagi 的商业价值很不错了。</p><p>过去对 Kagi 失去了信心的用户，我想现在的 Kagi 还是努力交出了完美的答卷，除了 AI 相关的问题。当然这也是马后炮了，我要是现在听到一个声称专注于隐私的公司的创始人说电子邮箱地址不是个人可证明信息，我也会拔腿就跑。</p><p></p></div></details><details data-group="diary_sections"><summary>四月五日</summary><div class="diary-entry">04:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNDZZK9E6F7S6WBZBYFCFF24" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>为什么我要手写 SVG 代码…… 打算直接画图然后转换成 SVG 代码了。个人主页会变成手绘风格估计。</p><p></p><blockquote class="diary-thread-reply">15:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNF4XN796Y97ZMA0H5Q7NNWM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天画完的，整体设计大致是这种感觉，不过用了抗锯齿的硬性笔刷，还需要在转换期间去掉多余的颜色和像素…… 最终看上去应该还是平面的风格。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNF4VT1ZQC9CNG88F20YYB5F.png" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">15:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNF5E1FXEV3Y1GA1KEA5DG5S" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>目前的效果。缺失了好多小细节，应该是量化导致的。</p><p>下面那个方向标是给 Webring 留的，不过今天看了眼发现它好像还强求 Webring 自身的链接？我以为只要 prev 和 next 就够了哎。</p><p>到时候再说吧 ——！</p><p>考虑在原先的 /friends 里添加一个魔法阵，里面放我自己的 Webring 社区，即从我订阅的博客中取已经有 IndieAuth 的出来，拿去献祭！</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNF57EPN3CR4EE8X6AYS1WRJ.png" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">15:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNF5V6Q3HVNF79F8B3XHDJ2A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>调整了一下量化后，我门怎么变这样了？</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNF5TYEDABY747CXP5FVE3HD.png" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">20:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNFP323M8S9RPF36CDYVTT37" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>目前的效果如下。</p><p>抗锯齿还是太伤了，放大看可以看到边缘处被意外保留的颜色。</p><p>再就是量化时，相似的颜色会被合并，导致许多细节丢失，只能不停调整参数了。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNFNYSR23EX63N4PCS4760PS.png" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">04-06 00:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNG2QWZWNRG533E1YFF89DD4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>目前的效果如下 —— 和源近乎一致！</p><p>搞明白从像素图改矢量图期间要特别注意什么了。使用的颜色、绘画的形状等情况因为都会不一样，所以每个图层都要自己去调整。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNG1G2WM0RPKVQYS1906V8KD.png" alt="" loading="lazy"></figure></blockquote></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">14:11 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNEZQW01E79VBVMKA2WF06Y5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近发现我无法访问 mobius.blog 了…… 为啥哦？一进去 Spectrum 就会弹出来说该网站有危险。换流量可以正常访问。</p><p></p></div><hr><div class="diary-entry">18:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNFEF0RM3Q0EMMNQE4MGQSE4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>个人主页的卧室一直没做，因为我一直没有想好「角色设计」。这包括了我家的小动物怎么用自己的美术风格画出来，也包括了「我」在互联网会以什么样的形象出现。</p><p></p></div><hr><div class="diary-entry">19:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNFGSVY6FXXQAR8W867RZMAB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>放在父母家的、我的自行车被偷了……<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​</p><p>虽然不是很贵的自行车，但是骑上去比 Citibike 好很多，还被特意喷上了银色的漆。</p><p>我恨你，小偷 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​</p><p>妹妹的自行车也被偷走了！</p><p></p><blockquote class="diary-thread-reply">22:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNFW7DRQP8N1DHQAR6JDZZ50" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>因为不在家，所以打算线上报案…… 不过这就是你的答复吗，NYPD！</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNFW797HASVC5M8M7T04GSRG.png" alt="" loading="lazy"></figure></blockquote></div></details><details data-group="diary_sections"><summary>四月六日</summary><div class="diary-entry">18:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNJ0ESEZV90W0HP4CXJV1JXM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://inv.nadeko.net/watch?v=QMsYc9qMq7g" rel="nofollow noreferrer noopener" target="_blank">https://inv.nadeko.net/watch?v=QMsYc9qMq7g</a></p><p>这个骷髅王的 BGM 好听。看一位 UP 主玩传奇死亡难度的时候用到了。很有那种，骷髅叮叮当当的感觉。</p><p></p></div><hr><div class="diary-entry">19:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNJ3RNQNA1B992CTT2YP0TKE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>现在这一版已经急匆匆上线了。可以查看 <a href="https://cytrogen.icu" rel="nofollow noreferrer noopener" target="_blank">https://cytrogen.icu</a> 看看效果。字体大小还没有调整。</p><p>现在我的网站会出现在 Indieweb Webring 上了。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNJ3Q0D39ARTX6MR3Y2BMEX3.png" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>四月七日</summary><div class="diary-entry">01:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNJRERVPW60KTMEJ17YSZMWR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>受够了别人写的漏洞百出的 Sourcehut Docker 镜像…… 我已经叠了不知道多少层补丁了。虽然经常看到文章说不要自建，但我不自建能干嘛呢，我自个儿也好奇为什么你一个代码托管平台自建这么困难。</p><p></p></div><hr><div class="diary-entry">13:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNM2RXTHHX7VJ485BVHZHT7M" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>回父母家发现，一直以为是小猫尺寸的咪咪猫不仅比匹克猫要大，甚至都要比幸运狗大了。我的天，你是什么巨型猫。</p><p></p><blockquote class="diary-thread-reply">16:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNMDGN3ASRK2MPZKCW7Q8NAS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>该说是匹克猫太小了么。不过幸运狗在迷你贵宾里也算有点大只的了。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNMDFDK9X03D5NDVARNV4D45.jpeg" alt="" loading="lazy"></figure></blockquote></div><hr><div class="diary-entry">18:39 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/947201161638723785" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Beautiful white flowers and clear sky.</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/31410d826-759a86/n2rFWS97zUuI/dzIOVi5crQyj363voo4wH81HjYM30OllS19YRnFa.jpg" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>四月八日</summary><div class="diary-entry">06:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNNVYPE59HRYHW3HEA8R318X" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>影院给了个四月底到期的免费爆米花跟饮料，所以想在四月底之前看个电影。但是不知道看什么好。</p><p>《沉默的羔羊》35 周年倒是有一场，但是没有半价折扣，太贵了不想去，并且位置已经被预约满了…… 它可是快到月底才放哎；</p><p>《心之谷》四月底也有场 IMAX 的感觉可以去看看；</p><p>想看的《玩具总动员 5》要等到六月份，呃啊 ——；</p><p>现在在放的超级马里奥电影不知道能不能看，尤其是在我对这个 IP 熟悉的情况下。实在不行就拉着妹妹或者室友重新看一遍《河狸变身计划》吧！</p><p></p></div><hr><div class="diary-entry">06:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNNWKEYKPMN8K6YVJ7YM01E4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天晚上不想吃美式中餐，久违点了个外卖。因为看了个博友讲吃炒菜的文章，所以久违点了份炒菜 + 米饭，而不是往常的面食。这是家湘菜馆（其实是湘菜餐厅 + 酒吧），炒出来的农家炒肉别说，很香很好吃，下饭。使用的椒是辣辣的青色辣椒，不知道用青椒炒的话哪个更好吃。</p><p></p></div><hr><div class="diary-entry">07:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNNZR3K0PVA0HR8HNHHV326R" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友最近老是给我看小丘鹬（American woodcock）的视频。它们会在纽约市待个一个月，已经有好多人跑去 Bryant park 去观察它们了。</p><p>这鸟叫起来很喜感，平时身体 boi boi 地跳舞，看上去也很喜感。</p><p></p></div><hr><div class="diary-entry">07:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNNZX5YFN5Q22PMD8QVAGXVH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>可恶的室友说幸运狗和咪咪猫长得丑…… 只能偷偷晚上把她杀掉了。</p><p>（是玩笑话）</p><p></p></div><hr><div class="diary-entry">17:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNQ1TD4NEQNAW1AA0MTBCKAC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这几天又在视频平台上看到这首歌，原因是外网发现了这位 P 主用 AI 做的 V 曲，一时间议论纷纷，把热度又带上来了。我用的是国内的视频平台，令人震惊的此时大家纷纷都在声称自己是「中立」的，甚至还有人说自己「中立」、只要歌好听就行 —— 朋友，你自己掂量掂量什么是「中立」。说「歌好听就行」，不就意味着自己支持 AI 生成音乐、融合他人的作品进去吗？你所谓的「歌好听」，就我这个没有那么狂热的 Vocaloid 听众来看都能品出其中融了哪些优质 V 曲。更有甚者直接说「支持所有人使用 AI 作曲，产出更优质的 V 曲」——excuse me?？你认真的吗？可笑的是，大家都认为这样是「正常」的，大言不惭地乐呵着「没有刷怪」，直接把反对 AI 作曲的人当成了怪物、异端。</p><p></p></div></details><details data-group="diary_sections"><summary>四月九日</summary><div class="diary-entry">00:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNQRQG029VMVWKBJT30H6Y9C" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天应该是补作业的日子，但我选择自托管了 Headscale、取代闭源的 Tailscale 服务 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">13:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNS8BFSZ5Q5K6HH0YGPKT6BK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>几天前，我在博客网站的文章底部添加了意义不明的东西。</p><p>顺便发现了这个： <a href="https://useplaintext.email/" rel="nofollow noreferrer noopener" target="_blank">https://useplaintext.email/</a> 也就是发送纯文本电子邮件。</p><p></p></div><hr><div class="diary-entry">15:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNSD4JQ4BXFRJ4HG5CYR7NPM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>给自己放了三天的假，今天要回去打工，好不情愿……</p><p></p></div><hr><div class="diary-entry">18:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNSR4R9GPWNENMJGNSGDTZDQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>高中得 senioritis 的时候，一周平均翘课三天…… 专业课毕设也是赶工做完的因为不去上课。</p><p>还有就是大一的时候 senioritis 没走掉 —— 现在也没走掉就是了 —— 生物钟颠倒、打游戏从下午打到早上出太阳再睡觉，一觉睡到下午，吃完饭继续打游戏。</p><p>我靠，那时候好堕落。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNSQZ40CQFHYKWQYDW6MHV3F.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">20:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNSZEBB3KFRTKWSN638JABNJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>每天都要输这个破小费 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3DWCVA2CPCGYZ1FSHS79X.png" alt=":wolf_mad:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">20:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNSZKZX41FZ4D7NEX8C2TDRQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这东西反正员工根本就收不到，也不会捐给罐罐里说的「贫困大学生」……</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary> 四月十日</summary><div class="diary-entry">01:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNTFV2TS35QWB3S8VW5K8EMV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>做完一阵子活，习惯性敲自己后背凹进去的部位，就是「腰」吧。被店里的长辈看到，说我还没有生孩子腰就被搞坏了，生完孩子一定要找个疼老婆的老公。</p><p>Oh shit, don't start on this!</p><p>之前因为身体瘦瘦的，还被说只要找个男朋友就会被养得胖胖的。啊 ——！不要再和我说这些了！<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ496Q8A4XAZF9TK81RAX7.png" alt=":ottersgottaott10:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">01:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNTGH20KDQA9GR4GM8EZQ0PM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>下午时脑子里想到一些东西想写下来，结果一转眼忘干净了。</p><p>不过有个脑子里一直在想的事情是，「想做日更博主！」发些有的没的的日常文章，也会很开心吧。</p><p>室友这几天被小丘鹬刷了屏，老是想要在这个月出去观下这种很特别的鸟。它会发出 <em>mbeeep</em> 的叫声，然后身体摇摆不停地动来动去。它也是很常见的猎鸟，以至于室友在搜这种鸟的视频时，搜到了猎人生食其脑子的视频。</p><p>今天开始天气就没有那么多变了…… 吧？在它们迁走前去看下，说不定挺不错的。</p><p></p></div><hr><div class="diary-entry">01:44 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNTH0NC5ZKD5VMKFX9APMC80" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>走之前，后厨把做多出来的烤猪肉越南面包给了我。可以想象出它有多么好吃。</p><p>后来在街上看到他，本来悄悄走去别的街、避免对话的，结果到车站时发现他跟我去的同个车站…… 两人不可避免地尴尬站在一起。还好不是坐同辆车。唉，一天忙活下来实在是不想和人交谈。</p><p>今天靠近一些客人时，发现他们身上喷有很刺激的香水味儿，有些是「香」的（太冲了实在是不想承认那是「香」味儿），有些我闻着像是尿骚味儿！—— 该不会就是吧……</p><p>一说到味道就会想起大一那会儿在奶茶店打工，来了个新人要早班的同事带。我这个下午班的过去，新人正好要走。同事见她走了，让我去闻她待过的地方 —— 我靠，很恐怖的臭味儿！像臭水沟一样！我们只能到处喷清新剂。</p><p></p></div><hr><div class="diary-entry">02:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNTJBN96ESA1RDA2D8AX4BRS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>妈的，回家的路上有个疯子在大喊大叫，害我得绕一圈。他不知道是怎么了，「啊啊啊」地叫着，身体部位摇摆来摇摆去，然后拍击着别人家一楼的窗户 —— 另一个不想住一楼的理由。</p><p>我感觉我每天在大街上就会看到这种人。是吸毒了么？看上去很可怕。要是靠近的话，万一就会被攻击，再不济就是被跟着骚扰。</p><p></p></div><hr><div class="diary-entry">02:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNTJQ27R24RVJ10XZNTXHBFH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>朋友这几天生日，给她炒了个土豆丝吃。我平日不做饭，或者说不会做饭，这次也是抄下来网上的食谱自己做了下。</p><p>大致是：</p><ol><li>放油</li><li>放花椒炒，但我没有花椒所以放了一勺花椒油</li><li>下小米辣、干辣椒和蒜片炒</li><li>下土豆丝炒。我不会切丝，所以切成薯条状。炒之前要洗干净，然后用水跟一勺白醋泡个十分钟；我估计我只泡了五分钟左右，炒出来没那么脆</li><li>放一勺盐、一勺糖、一勺味精、两勺酱油</li><li>放两勺白醋，结束啦！</li></ol><p>电磁炉做这东西好费劲儿，感觉炒好后白醋都挥发掉了…… 我另一个会做的东西是炒饭，用电磁炉做容易做成烩饭。</p><p></p></div><hr><div class="diary-entry">03:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNTQYWEHJV6GHXVX2R0JSZXD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>We were eating fortune cookies. Mine says <em>I will embark on a journey of personal growth and transformation this year</em>; my roommate's literally says my name.</p><p></p></div><hr><div class="diary-entry">07:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNV34Y381GACWV1C2TQECZ0K" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这段时间里弄 Kobo 的服务端弄到怀疑人生，怎么排查都排查不出来为什么 Kobo 不向服务端发送下载请求。后来直接将 Calibre web 里的 Kobo sync 的代码搬了过来，就可以了！</p><p>之前完成了爬取漫画平台资源的插件化功能（参考了 Mihon 的设计）、将漫画资源转换成 EPUB 或者 KEPUB，接着用 Calibre 或者其他工具有线导入到 Kobo 即可。现在服务端做好后，便可以将 Kobo 内的配置文件改成完全不依赖于 Kobo 官方服务端的了，还可以继续做 web UI、想看什么就自动抓取漫画资源、转换、无线下载到 Kobo 设备内。</p><p></p><blockquote class="diary-thread-reply">07:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNV38SYW1RDG48BYTY8R56A7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>忽然意识到自己拿 Kobo 读书的时间远不如自己折腾这个服务端的时间 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​</p><p></p></blockquote></div><hr><div class="diary-entry">14:43 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNVXJFBFHAZ84728MZ16ZG0X" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前几天一位朋友甲来店里，聊了些跟男同性恋相关的事情。他当时带了个白男过来吃饭，之后白男提前走了，他说那个人其实 HIV 为阳性。</p><p>根据他的科普，HIV 为阳性不等同于有艾滋病。别说国内了，国外的很多人也会将两者划为一谈。不过阳性 HIV 依然可以抑制住，他所处的男同圈子里，大家无论有没有阳性 HIV，都会吃一种药。这种药和避孕药有点类似，分为长期连续吃的，以及短期紧急吃的，且前者吃下去副作用很小很小。有阳性 HIV 的人也可以通过长期服用药物，而避免得上艾滋病。</p><p>白男去日本定居的时候，明明每次都用了安全套，却依然染上了。朋友甲说原本以为国内的性教育做得很差了，但实际上日本的氛围更加压抑：担心社会性死亡，所以没有人会去做检测；就算做了，也会因为和国内一样，以为自己得了绝症，所以决心报复社会。因此，没有人知道当时有阳性 HIV 的是谁，也不知道他是对自己的身体不知情，还是故意隐瞒了此事。戴了安全套但还是传染上这一点也很意外。</p><p>说到我们更熟悉的国内，朋友甲认为性教育的缺席，导致许多人对阳性 HIV 有偏见，药物也不普及。许多最后得上艾滋病的人，往往被病情折磨，要么就是报复社会、故意和别人性交。他在国外的这些年发现，有阳性 HIV 或者艾滋病并不是一件特别羞耻的事情。通常来说，在性交前人们会互相告知对方自己有没有，尽量透明化自己的身体状况。</p><p></p></div><hr><div class="diary-entry">23:48 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/948366053934080053" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>来公园找到了小丘鹬。一群人围着它在拍照，所以很好找。</p><p> <a href="https://pixelfed.feddit.social/discover/tags/woodcock?src=hash" title="#woodcock" class="u-url hashtag" rel="external nofollow noopener">#woodcock</a> <a href="https://pixelfed.feddit.social/discover/tags/americanwoodcock?src=hash" title="#americanwoodcock" class="u-url hashtag" rel="external nofollow noopener">#americanwoodcock</a> <a href="https://pixelfed.feddit.social/discover/tags/bird?src=hash" title="#bird" class="u-url hashtag" rel="external nofollow noopener">#bird</a></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/31410d826-759a86/F7X5V4UEZaoa/iopE5xVn43nfgLRbC88HcsX9kCeX4TDxAD71rumL.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/31410d826-759a86/VYJ3Wxp3OdAS/rhiyXRB0kUq4mbip0ufCuHcAReFe2d8BD0wqsZip.jpg" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary> 四月十一日</summary><div class="diary-entry">01:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNX2GH1CKF9REEP3AAZS154B" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>去 Wholefoods 吃了 hot bar，一磅食物是 13 美元。我的感受是，好难吃，像是在浪费食物，尤其是肉类食物。沙拉和水果啥的没什么问题，毕竟你也不需要用力去烹饪它们。里面也有地中海食物，需要自行拼装，但我对这个兴趣不大，也没有鸡蛋。最让我意外的是菠萝烤焦了，有着恶心的苦味儿。</p><p></p></div><hr><div class="diary-entry">02:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNX598BPSCNKEYGK132506N2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>路过一家日本手制品店，东西都很可爱，不过价格很贵，比如盘子要 80 美元。我看中了个猫头鹰扩香瓷器，不过 15 美元加上香自己的价格，以及没有使用香薰的习惯，最终还是让我放弃了。送礼倒感觉不错。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNX549DS64647FNZTVJ5GGWB.jpeg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNX54FPSFNPHEY7A7JDA7NR5.jpeg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNX54FQPZD4RBAJZB0RYQPRW.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">02:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNX5DYB0EP0WJ17W7R0D3QNC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>因为好奇，还是去看了眼蜜雪冰城…… 和冰淇淋车卖的冰淇淋没什么两样。朋友买的草莓椰奶，喝了口感觉和库迪用的草莓浆一样。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNX5A0XDV1M99ZDQVK4YBG1V.jpeg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KNX5A102PADZPFS91T6RM6KK.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">03:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNX8J15A4MQR78GP8G87KPNW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>回家路上有很多很多人，就像凭空生成出来一样，挤满了街道。数量像是那种，漫画里为了体现出角色强度而画出来的一片片「沙包」。看他们的穿着，应该是今天这附近有个球赛、有 Knicks 上场。</p><p>我不看体育比赛，对这个不熟悉，但是记住 Knicks 还是因为几年前在教堂被迫做翻译的时候，一位牧师讲道时讲自己很喜欢 Knicks。</p><p>Knicks 是纽约市还是纽约州的球队？不清楚。这种当地的球队自然便有当地人们的支持，和之前看的电影 <em>Goat</em>（《奇迹梦之队》听上去还是太奇怪了）里表现得一样。<em>Rumble</em>（《怪兽训练营》）这个电影也是一样，只是把巨兽竞技搞成了一种体育项目 —— 话说我是不是看了太多儿童向电影？顺带一提 <em>Rumble</em> 这个电影我很不喜欢它的最终表现…… 印象里预告片和正片的内容有差别。值得称赞的是怪兽设计，有个羊角怪兽很可爱。</p><p>说回体育，高中时唯一一个教计算机相关知识的老师是名校 NYU 毕业的。但他作为一个教计算机的人，并不知道如何使用任何编程语言。学习第一款编程语言 Python 还是我快毕业时、学校打算塞点计算机专业进来，他才学的。那他是怎么进的名校呢？答案是足球踢得好，NYU 专门抓他进去的。</p><p></p></div><hr><div class="diary-entry">17:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNYS0C51HGRFCEWDJB0ES84K" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>每天上班都会喝可乐，因为觉得糖分可以快速给我能量。这可能是假的，但我的身体状况肯定好不到哪里去。几个月前家庭医生给我打电话让我去复诊，但我忘了…… 也不想去，因为这个家庭医生离我很远。虽然也可以换，但我没有动力去做，医生还是难得一见的我老乡……</p><p></p></div><hr><div class="diary-entry">18:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNYWH26KGWXN6DKTAXP8AXH1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我擦，回家路上坐车呢，站在我旁边的女人突然坐了下去、倒在了地上。一瞬间我没有反应过来，直到有群众说了句拉她起来，我才动了起来。一个白女大叫着车厢里有没有医生，然后叫另一头的人去按警报。还没到下一站之前，我们一伙人只能按着她让她坐着，一个黑人阿姨一边说着耶稣会救你的，一边给她水喝。庆幸的是，她看上去是有意识的，没有完全晕过去。到站后，其他车厢的医学生跑过来检查女人的脉搏，表示人没事。管车厢的人叫我们都出来、腾出点位置。这班车不可避免地要延误，但女人起来的时候，群众还是高兴地笑了起来。接下来的问题就是，车能不能快点走了……</p><p></p></div></details><details data-group="diary_sections"><summary> 四月十二日</summary><div class="diary-entry">04:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KNZYG668VW1GJH4PJQH93WTA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想要把现在在跑的项目搞成尽量去中心化的…… 中心化的项目维护起来很难受，要遵守许多安全合规。担心数据泄漏的话，干脆就不要把数据存到云上！</p><p></p></div><hr><div class="diary-entry">16:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP1A1T996E22EKZ93BDZWZKZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>餐厅的音乐怎么是女声版的 <em>Never Gonna Give You Up</em>，我听着贼搞。</p><p></p></div><hr><div class="diary-entry">17:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP1CERJ3C091QNN197AQ58FW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>没有用的小知识：餐厅折纸巾的时候这种格子一样形状的永远朝右下。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KP1CCFFNJ56Z5J7VK6Y77WJ3.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">22:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP1XAE7TJ8GSMV6YQJMVK6H7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我受够了怎么会有人问我白米饭里有没有盐 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​ 你蒸白米饭为什么要放盐进去啊！</p><p></p></div><hr><div class="diary-entry">23:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP1ZXGCNCH4RW6C6685FQ89J" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>汤力水好难喝…… 店里的葡萄果浆单品味道很不错，想着可以和什么东西配在一起，做成酸甜可口的小甜水。气泡水和汤力水之间，我选择了汤力水，想要试试它到底是什么味道。基酒的话，自然是味道不咋烈的基酒了。</p><p>因为只是尝味道，所以基酒只放了三分之一盎司，葡萄果浆是它的三倍。此时的成品对我这个对酒精尤其敏感的人来说，根本喝不出来酒精味儿（毕竟放的就很少啦）。但是我明显低估了汤力水的苦味儿…… 应该是倒了太多进去，现在成品喝起来前面是葡萄果浆的酸甜味儿，后面苦味儿立即就赶了上来、抽我嘴巴子…… 失败品。</p><p></p><blockquote class="diary-thread-reply">23:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP21DZYMADHAJVNVRA5QHXH1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这次改用波本威士忌和干姜水。0.5 盎司的葡萄果浆、0.25 盎司的干姜水、0.75 盎司的波本威士忌。这个比例做出来正好一个 shot 的量，很适合尝味道。总之整体喝起来就很…… 奇怪？但是不难喝。我也发现这个果浆（或者说糖浆）的问题：特别黏稠，搅不开。如果拿着杯子对嘴喝会直接被波本威士忌的味道撞飞，我现在就头痛痛的…… 估计得摇杯把它撞开么？</p><p></p><blockquote class="diary-thread-reply">04-13 01:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP261VAB1CK2ZHAEZGMM4R8Z" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>目前折腾出来比较满意的方案是：</p><ul><li>0.25 盎司的糖浆、0.25 盎司的热水搅拌在一起</li><li> 0.5 盎司的干基酒</li><li> 0.25 盎司的干姜水</li></ul><p>虽然我怎么喝都只能喝出恶心的酒精味儿，但是别人喝说好喝，所以就这样吧。</p><p></p></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>四月十三日</summary><div class="diary-entry">00:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP2298V73VW55PXK7ACDHGBP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>研究葡萄浓缩糖浆（嗯我后面看了眼才知道不是果浆）呢进来一个手拿白纸和零零散散叶子的黑人，说他想借个厕所，用完就点单。结果他用完跑了 —— 你找我借厕所直接说不就好了，编这么个幼稚的理由，反而更鄙视你了。然后他加入了门口一批吹叶子的黑人们，就这么堵在了店的门口…… 直接堵在了店的门口！大麻味道也顺着门缝儿飞了进来 —— 我要杀掉你们！</p><p></p></div><hr><div class="diary-entry">02:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP2B8EG8WGA42RWCHKFK5WGS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>发现自托管的 Stalwart 崩了…… 可能错过了邮件，也有可能没有。总之修复中。</p><p></p><blockquote class="diary-thread-reply">18:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP41SM438CS621EGZTTTQK3Z" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>经过我热血沸腾的一顿操作后，Stalwart 服务终于出现了问题。首先是邮件、日历和联系人数据在 VPS 上丢失了，不过它们都在本地上有备份或者缓存，所以还好；catch-all 配置疑似丢失，还未测试；之前捣鼓的用来充当邮件评论的邮箱数据应该是没了，不过里面也只有两个测试邮件，还好还好；邮件客户端都无法和 Stalwart 握手成功，原因不明，还在调查中。</p><p></p><blockquote class="diary-thread-reply">04-14 14:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP66QTVEEKGTG1X2HFX3XPHG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不知道是为什么，最开始有个配置导致 Stalwart 崩了，重新启动后出现了各种原本没有的底层问题。怀疑是长时间没有重新启动过，这次重新启动正好 <em>latest</em> 到一个大版本。比方说最新版本里硬编码了 IMAP4rev2，我的部分邮件客户端并不支持这么新的版本。</p><p></p><blockquote class="diary-thread-reply">04-14 15:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP68J7TPASZRX0V8QBCHGY1F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>心烦了，不想再用别人打包好的 docker 镜像了。直接 fork 下来跑，哪里不行改哪里吧。</p><p>上次 Sourcehut 也是，原本用的是别人打包好的、相当旧版本的镜像。实际上自己编译、跑起来，并没有想象中那么复杂：pypi 上的是前端，可以直接下下来跑；后端作为模块分散在代码托管平台上，只要能 go build 就行了，最多需要从源代码那儿自行 cmake 个底层工具。其中意想不到的是，别人打包的镜像里用的是旧的 SSH 工具，我跟着步骤编译发现版本不对，才发现 Sourcehut 的 SSH 工具已经变成了新的另一个仓库。</p><p></p><blockquote class="diary-thread-reply">04-16 01:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP9X3CDBRYAM7FW44YF4X5SA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>又腾出一点点时间来修 Stalwart，现在可以正常运行了。但是 catch-all 还没有开始修。先把日历和地址簿恢复。</p><p>这期间发现 Thunderbird 还有聊天功能，可以接入 IRC 和 Matrix—— 我以为你只是一个邮件客户端！</p><p></p><blockquote class="diary-thread-reply">04-16 01:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP9Y4PAGVR22Q7F86W3EVJWP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不过我连接 Matrix 也连接不上去，好神奇。IRC 我也有点兴趣在。</p><p></p></blockquote><blockquote class="diary-thread-reply">04-16 04:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPA802ZZW1YSWEBN7M2423D2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>终于全部修复好了…… 妈妈咪呀，再也不乱碰了。</p><p></p></blockquote></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">16:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP3SFVGJ48EWWH38VDGX2XG1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>访问一个订阅许久但一直没有更新的博客网站时，读着读着，突然左下角跳出来一个 Live2D 小人和一个气泡，挡住了我手机屏幕左下角的位置。没给我吓死。</p><p></p></div><hr><div class="diary-entry">20:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP4A6FH3MD0MEADVF4KPP3FT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>唉，现在做兼职的一家店应该是不再开了，难免觉得可惜：饭好吃，价格不错，人也挺好。但是老板们对这家店貌似不怎么上心。我们说了多次提高曝光率，可是昨天去看，发现门口展示食物的电视，和贴在玻璃上的菜单都被撤走了。晚上，我和店里的人调酒玩，以后恐是没有这个机会了。</p><p>这期间品了品干琴酒和波本威士忌的味道，发现前者比想象中烈很多，反而波本威士忌作为后来者、让我觉得还可以。</p><p></p><blockquote class="diary-thread-reply">04-25 15:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ2NJ7K052110G8PY4GXE0AH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>重返这家店，内心相当复杂。无论是什么组织，只要管理的人多了，难免会出现冲突，以及「站队」吧。</p><p>这家店与其说是在老板的管理下，不如说最初是在主厨大哥和调酒师（兼前台服务生兼我的调酒师傅）的管理下。后者中，主厨大哥想出了老板经营的店里，近乎所有的菜单，而调酒师具备着能让客人爱上他的人格魅力，尤其是在这个以老人为主的社区里。</p><p>但老板和调酒师在「营销」上有着冲突。调酒师认为这家店做得最差的地方在于曝光率不足。主厨大哥的手艺和菜是值得认可的，并且在做菜上有着一种不知道该说好还是坏的执着：一道菜正宗该是什么味道，他就做什么味道，例如辣的菜他是很抗拒做出不辣的出来，直到不吃辣的调酒师跟他吵架他才妥协…… 客人们也常说这家店太容易在繁杂的纽约市里被人忽视，明明质量很能打。它甚至连招牌的店名 logo 都贴反了，从外根本看不出来里面是什么。</p><p>调酒师知道可以营销的人脉，但是老板却不愿意出钱。最终调酒师和主厨离开、去开自己的餐厅，这家店以及菜单完全从世上消失了，消失的还有熟客们…… 我和朋友们在店寿命的最后，想尽方法去推广，还做了很多酒的海报、带更多朋友过来，在 Instagram 上发图片。但一切都是无用功。</p><p>现在这家店变成了老板娘自己管的另一家店 —— 尽管样子还是同个样子，我还能看见上次在这里时，我们一起调酒用的葡萄味浓缩糖浆，但一切又都不一样了。</p><p></p><blockquote class="diary-thread-reply">04-25 16:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ2PBGCKBA0V4T72Q1Y9B72T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不过都开店了，作为主厨的老板娘怎么还没来啊 ——！要是有客人过来咋办，我也不会做菜啊。</p><p></p><blockquote class="diary-thread-reply">04-25 16:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ2PGR965Z3AP9XN7T8ACV97" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>其实也没有客人来。唉，事已至此，读书吧！</p><p></p></blockquote><blockquote class="diary-thread-reply">04-25 23:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ3GRF5M8TF6EYMYS4D7HDF8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>很难理解这些管理的想法。我坐一天，也就三单吧，这期间是不准玩手机的（但我偷偷在玩，嘻嘻）。理由也莫名其妙，她觉得忙或者不忙都应该装成忙的样子，玩手机会导致我无法注意到客人进来。但实际上真是如此吗？客人进来或者不进来，我当然可以注意到啊。不忙又装成忙的样子，你干脆把这里弄成健身房、我带薪健身好了，还能当餐厅里的又一奇观。</p><p>她在隔壁的面店里放了这家新店的菜单，要求面店的员工接到单后，打电话给新店。接着新店做完单，让我淋着雨去把菜端给面店的客人…… 好折磨。</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">04-26 22:47 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ5ZMK4VT5FG9MAS3QC6CWEX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>遇到了以前常来的客人，他们询问我为什么原本那家店倒闭了。明明他们看到有更多的人来、一起看上去那么好啊？我也说不上来，到底是为什么呢？越来越多人认识这个地方，不靠任何水票也一直在打分平台上坐拥满分好评，当时的我们也以为会继续这样下去。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">23:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP4KB5VJX68CB6TJ64RWRS6R" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>走在路上发现到处都是手卷吧，融合了西方酒吧文化的 omakase 餐厅，我不咋爱去。生海鲜我只喜欢虾、扇贝和生蚝，鱼基本上没有爱吃的。过去倒是被手卷吧坑过：使用些品质差的烂肉，放在破海苔上，再卖点酒，便可以收取高价。</p><p></p></div></details><details data-group="diary_sections"><summary>四月十四日</summary><div class="diary-entry">07:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP5D06CYJSPQGSCVJ4JBY82R" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://www.drbronner.com/products/peppermint-pure-castile-liquid-soap" rel="nofollow noreferrer noopener" target="_blank">https://www.drbronner.com/products/peppermint-pure-castile-liquid-soap</a></p><p>我的美味十八合一…… 最开始还会拿来洗头和洗身体，后面基本上都是用来混着水刷碗。虽然说可以刷牙，但我试过、觉得很糟糕。买的是薰衣草味。</p><p></p></div><hr><div class="diary-entry">11:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP5WB19958GWTRNAVN4G1N3D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>六点的时候迷迷糊糊醒了，明明三四点才睡着。打算再迷迷糊糊睡回去，开始做梦…… 梦里我好像在一个政府部门窗口，申请自动房屋装修服务。要输入自己的身份辨识数据。接着小票机会吐出收据，上面写着收据的 ID 58x-xxx-xxx。我刚取收据准备走，广播便报了我这串数字。也要离开的女人回头看了我一眼，然后我的耳朵便听到万分吵闹的钻头声 —— 完全基于机械的自动装修服务开始了！好像我的房间外有很多机械钻头在自己干活、钻掉我的一面墙！—— 不对啊！这是我家楼下的声音！靠，楼下怎么有施工队七点就开始没完没了地钻地了啊！</p><p></p></div><hr><div class="diary-entry">14:43 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP6748DFZ5436R8JQZ0N1R8D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>应该是去年才重回摄氏度的怀抱的，今天 20 多度竟没个概念。我只知道 40 多度是超级热，类似于华氏度的 100 多度吧。</p><p></p></div><hr><div class="diary-entry">15:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP6ADBWHKNSF3Q7YBEY6N06E" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天和朋友聊到几年前在社团教室里，他和别人的对话。当时他们一群 finance bro 在聊金融、商业相关的话题，我在旁边做自己的事情。然后他提到，自己父亲是国内大老板，在商业上颇有洞见。其他人里的一个男人，冷不丁地接上一句「你知道我朋友的父亲有 Fordes 的股份吗？」至今，我都没有搞明白他这句话的意思……</p><p></p></div><hr><div class="diary-entry">16:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP6D8379KX8P38Y6C5Y5V3W6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天搞完了中文课的期中演讲，讲的是班宇《冬泳》集里的第二篇《肃杀》。有太多中文课的短篇小说没有在博客上写读后感了，之后补上；读起来都很有意思。</p><p>演讲结束后会有个问答环节，教授会根据同学们问的问题，以及演讲者的回答记分。不过这些以前已经上过该教授的课的同学们，显然是发现了其中的漏洞：只要自己生成问题、背下答案，然后在演讲前发在微信群里即可。</p><p>我这个组里的之前都没有上过该教授的课，所以没有这么做（也没时间做就是了）。结果意料之中，问答环节冷场了……</p><p></p></div><hr><div class="diary-entry">19:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP6Q1PSP78F02K9SAHNSDJAN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这个学期后，日语兼修就修完哩。要说我到了什么水平，就是到了个张口便是胡话的水平吧！</p><p></p></div></details><details data-group="diary_sections"><summary>四月十五日</summary><div class="diary-entry">04:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP7N5H4D4CMEP3Z0PJ1N7F27" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想买一双，够宽够软够硬够透风表面没有奇奇怪怪设计和颜色和 logo 鞋垫还可以取下来的长得像皮鞋的运动鞋。</p><p></p></div><hr><div class="diary-entry">04:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP7NEY7M46P2XDPRQF666DE2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>关注的钢琴手分享了之前改的三拍春嵐的扒谱： <a href="https://www.bilibili.com/video/BV1BPQGBfEt6" rel="nofollow noreferrer noopener" target="_blank">https://www.bilibili.com/video/BV1BPQGBfEt6</a></p><p>这位老师经常改春嵐谱，跳拍的也很好听： <a href="https://www.bilibili.com/video/BV1xw4m1k7oz" rel="nofollow noreferrer noopener" target="_blank">https://www.bilibili.com/video/BV1xw4m1k7oz</a></p><p>这首歌被多次改编，每位老师改出来的都是不同的味道，很喜欢。</p><p></p><blockquote class="diary-thread-reply">04:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP7PTJ39K41HW5D79P01YR9M" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打算整理一下我对春嵐改编曲的看法，嘻嘻。</p><p>首先是春嵐原曲，一切的起源……</p><p><a href="https://inv.nadeko.net/watch?v=pUH9vCsvq08" rel="nofollow noreferrer noopener" target="_blank">https://inv.nadeko.net/watch?v=pUH9vCsvq08</a></p><p>有 john 的味道，但我认为是 john 打破了同质化的相当独一无二的一首歌，也是 john 这个马甲成绩最好的歌。</p><p>原曲整体听来是干净的，主要是要和其他改编做对比。</p><p>顺带一提之前在博客上说自己最喜欢的 P 主是 john，其实是有点骗的成分在…… 因为我只喜欢 john 的这一首歌，就算是把所有马甲的歌包含在一起。综合看来我应该是更喜欢 Sasakure.UK，无论是他的 Vocaloid 歌曲、核，还是乐队的歌我都挺喜欢的。之前也分享过他的 Wanderlast（最可怕的是初中那会儿用 Soundcloud 乱听 Vocaloid 歌时，随机到的喜欢的歌全是他的，我到近些年才知道。那我算不算小时候就是 Sasakure.UK 的粉丝？）。</p><p></p><blockquote class="diary-thread-reply">05:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP7SWMHTK8B7JR64FPATRGY6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>接下来是 john remix，自己 remix 自己。可惜它很短很短很短。</p><p>找不到原本的链接，用 Bilibili 上转载的连载好了： <a href="https://www.bilibili.com/video/BV1zT4y1E7g4/" rel="nofollow noreferrer noopener" target="_blank">https://www.bilibili.com/video/BV1zT4y1E7g4/</a></p><p>一改原曲的快、大喊的感觉，这个 remix 很慢，很温柔，听上去要比原曲干净得多，连标志性的春嵐叫都没有了。其中两边电吉他的声音吸引到了我 —— 嗯，应该是电吉他吧……？</p><p>缺点是只有 33 秒，只能拿来当铃声了。</p><p>先前分享的 Bilibili 频道主做过自己的加长版： <a href="https://www.bilibili.com/video/BV1sY4y1E794" rel="nofollow noreferrer noopener" target="_blank">https://www.bilibili.com/video/BV1sY4y1E794</a> 开头那段相当惊艳！因为有着频道主自己的理解，虽说是「加长版」，但是实际和 john remix 有着区别。这一版有着刚从风暴中出来、看到春天的第一束亮光的感觉，甚至中间开始窗外的鸟鸣声都为这一版增添了色彩。</p><p>还有个 john remix 是 lo-fi 版本：听了脑内要么只想串烧，要么只想睡觉，根本不会认真工作吧！： <a href="https://inv.nadeko.net/watch?v=Vc9kvK4239U" rel="nofollow noreferrer noopener" target="_blank">https://inv.nadeko.net/watch?v=Vc9kvK4239U</a></p><p></p><blockquote class="diary-thread-reply">06:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP7XPMXF14JKQ16793E3T3TX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>john remix 里经常出现 煮ル果実（にるかじつ）的歌，比如我很喜欢的 <em>Traffic Jam</em>（才发现春嵐忘记用书名号括起来哩，嗯，就这样吧！）。所以某天 煮ル果実 决定 remix 了春嵐…… 好吧两者可能没有直接的关联。</p><p><a href="https://inv.nadeko.net/watch?v=1vXrExcV0s8" rel="nofollow noreferrer noopener" target="_blank">https://inv.nadeko.net/watch?v=1vXrExcV0s8</a></p><p>煮ル果実 的曲风，我很难说明是什么。能说的肯定有相当标志性的 flower 调教风格，再就是「果味儿」—— 太抽象了！总之分享一些我喜欢的他的歌：</p><ul><li><em>Ameri</em>： <a href="https://inv.nadeko.net/watch?v=8QAORkRx2vg" rel="nofollow noreferrer noopener" target="_blank">https://inv.nadeko.net/watch?v=8QAORkRx2vg</a> ——「把笨蛋都踢飞吧！」不过这首歌是草莓味豆奶产品的广告曲，震惊！MV 由 bakui / sakanauosakana 老师负责，是位很有个人特色的动画天才兼恐怖的一体机，很推荐了解；</li><li><em>Traffic Jam</em>： <a href="https://inv.nadeko.net/watch?v=oUevY6uH4Qg" rel="nofollow noreferrer noopener" target="_blank">https://inv.nadeko.net/watch?v=oUevY6uH4Qg</a> 主要是喜欢高潮部分的 Deuce Deuce Deuce；</li><li><em>Shama</em>： <a href="https://inv.nadeko.net/watch?v=tQWMArNo9F0" rel="nofollow noreferrer noopener" target="_blank">https://inv.nadeko.net/watch?v=tQWMArNo9F0</a> 高潮部分动静儿太经典了，过去是手书金曲；</li><li><em>Wozwalf</em>： <a href="https://inv.nadeko.net/watch?v=mVjyVppveGY" rel="nofollow noreferrer noopener" target="_blank">https://inv.nadeko.net/watch?v=mVjyVppveGY</a> 算是我听 煮ル果実 的第一首歌吧。</li></ul><p>其实停下来会发现 2020 年前和左右的歌，跟近几年的歌听上去很不同，比如 <em>Ameri</em> 的音色明显丰富很多很多。</p><p>说回 煮ル果実 的春嵐 remix。刚开始几秒会立即发觉它和原曲的不同：音轨很多很多，开头一声尖叫触发了春嵐叫，配合 MV 里一个捂着脸的男人的出现，不难想象是他在捂脸呐喊。整个曲子里用了许多不同的声音，比方说狗叫、表达清爽的打开瓶子般的「啵」声。歌姬使用的是 煮ル果実 常用的 flower，而不是原曲使用的 Miku。种种原因都让这个 remix 有着和原曲截然不同的味道 —— 更加强烈的暴风雨。</p><p></p><blockquote class="diary-thread-reply">07:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP7ZAYD3EVF6VZSFNQ47GJ59" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Tonbi remix 则有着和其他 remix 都不同的风格。</p><p><a href="https://inv.nadeko.net/watch?v=sC1n7gkDKOQ" rel="nofollow noreferrer noopener" target="_blank">https://inv.nadeko.net/watch?v=sC1n7gkDKOQ</a></p><p>它添加了许多听上去像是在马戏团一样的音效，曲调也是更加欢快…… 吗？不，它改用小调了。众所周知，小调听上去会比大调要更压抑一些。明明使用了猫叫、捏球等声音，为什么却选用小调呢？我认为这是为了塑造出假装出快乐的感觉。就像 MV 里躺地上摆烂的小恶魔，是真的乐逍遥，还是麻木了呢？</p><p>我很喜欢 Tonbi 添加的手风琴音轨，以及他在一些旋律的结尾添加的小 twist（不知道该如何翻译我的意思……）。</p><p>而缺点我想，是许多小巧思过于重复，例如「ふ」的停顿出现了足足三次，实在是容易疲劳。</p><p>至于 Tonbi 这个 P 主嘛，我并不熟悉，所以不过多介绍。</p><p></p><blockquote class="diary-thread-reply">07:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP80Z1HZMWM6H0TD36YQNGVT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>一些有着我不太能 get 到的音乐风格的春嵐改编：</p><ul><li>HAPPYBOMBER remix： <a href="https://inv.nadeko.net/watch?v=xQF4BbqfaZU" rel="nofollow noreferrer noopener" target="_blank">https://inv.nadeko.net/watch?v=xQF4BbqfaZU</a> 特色在于「电话」以及铃的脆声。我喜欢中间那段和声，其他地方给我感觉有些…… 不搭配？</li><li>ariiol remix： <a href="https://www.bilibili.com/video/BV1HzSyYfED2" rel="nofollow noreferrer noopener" target="_blank">https://www.bilibili.com/video/BV1HzSyYfED2</a> 很单纯的不喜欢这个音乐风格，像是一把抓住我的脖子往上提，然后卡上边下不来给我弄死了；</li><li>ran remix： <a href="https://inv.nadeko.net/watch?v=tpks29xckWA" rel="nofollow noreferrer noopener" target="_blank">https://inv.nadeko.net/watch?v=tpks29xckWA</a> 虽说粉丝们时常调侃 john 的 Miku 声音没有其他声音大，但这个 remix 放大了这一点，导致听上去有点难受；</li><li>发现忘记提 john 搞的 8bit 版了： <a href="https://inv.nadeko.net/watch?v=ALQUnfGON1M" rel="nofollow noreferrer noopener" target="_blank">https://inv.nadeko.net/watch?v=ALQUnfGON1M</a> 我不是特别喜欢 8bit，太刺耳。16bit 可能还行。</li></ul><p>再就是其他改编：</p><ul><li>「- 热心市民 C 先生 -」的即兴电吉他演奏： <a href="https://www.bilibili.com/video/BV1EeDCB2Edo/" rel="nofollow noreferrer noopener" target="_blank">https://www.bilibili.com/video/BV1EeDCB2Edo/</a> 能看出技术相当高超。可惜作为直播切片，实际听上去原曲和即兴演奏是分开的；</li><li>「唐朝那些事儿」的「春嵐宇宙」系列，包括跳拍、三拍子、原曲翻弹、混入 114514 旋律版（嗯？）、john remix 加长版： <a href="https://space.bilibili.com/385760945/lists/4267074?type=series" rel="nofollow noreferrer noopener" target="_blank">https://space.bilibili.com/385760945/lists/4267074?type=series</a> 不过系列里少了 <a href="https://www.bilibili.com/video/BV1rM4y1W7Qi" rel="nofollow noreferrer noopener" target="_blank">https://www.bilibili.com/video/BV1rM4y1W7Qi</a>。他还有一些混曲：<ul><li>【【钢琴混曲】春岚 × 黎明前线 × 被生命所厌恶。】 <a href="https://www.bilibili.com/video/BV1Y6421u7Kq" rel="nofollow noreferrer noopener" target="_blank">https://www.bilibili.com/video/BV1Y6421u7Kq</a></li><li>【【钢琴混曲】春嵐 × 好运来】 <a href="https://www.bilibili.com/video/BV1KW4y157iy" rel="nofollow noreferrer noopener" target="_blank">https://www.bilibili.com/video/BV1KW4y157iy</a> （你到底在混些什么啊！）</li></ul></li></ul><p></p></blockquote></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">04:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP7NX0CPFRCCV4Q70MZMMQ7D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>大晚上两个人在干活，没有时间吃饭，导致饭堆在厨房里凉了。但我的事情不急，可以先吃饭。</p><p>我：「我肚子好饿。」</p><p>室友：「我肚子也好饿。」</p><p>我：「我可以帮你吃。」</p><p>室友：「你 <em>他妈</em> 还是人吗！」</p><p></p></div><hr><div class="diary-entry">16:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP8XY7SARRKSW6BSB62ZVVEK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​ 从未想过自己有一天需要和完全不懂技术的客户斗智斗勇，想方设法理解对方说的话里什么是真的、什么是错的。又因为自己已经知道某某术语是什么意思，所以更难以对方的角度进发、搞明白他听没听懂。</p><p></p><blockquote class="diary-thread-reply">04-16 18:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPBSFCB2AA5ZV58ZA6BFYKF6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>管理认为我的回信有工程师那股「死板」的味道，解释了太多客户根本看不懂，也不想了解的东西。她认为客户只想要知道解决方案，所以任何解释都是没必要的。于是她删了我一半的回信内容，然后喂给 AI 吐出来个超简单回复 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ496Q8A4XAZF9TK81RAX7.png" alt=":ottersgottaott10:" loading="lazy">​</p><p></p></blockquote></div><hr><div class="diary-entry">17:35 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP93C5SQD48FV3TJN1NGG34S" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>因为缺席了一节中文课，所以有一篇的内容没听到，遂去微信群里问同学们有没有笔记。</p><p>同学甲：「真的有人上课记笔记吗？」</p><p>你还挺骄傲。</p><p></p><blockquote class="diary-thread-reply">04-16 05:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPAAZGBGMK1YXQG9YXZARX5N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我愤怒的一点在于，我礼貌在公开场合询问是否有人愿意分享笔记，却得来这种一点都不礼貌、细想还有点蠢和愚昧的回复。</p><p>从字面上来看，这句话否认了所有上课记笔记的人，但真的没有人上课记笔记吗？答案是否认的。我来群里询问笔记，是不是意味着我本身就是个会记笔记的人？你这句话，是不把我当人吗？</p><p>这话也能反映出，此人对「上课」抱有强烈的消极态度，且默认所有这么想的人才是「正常人」。我有时候也讨厌上课，但我还是佩服那些努力学习的人。不否认那些喜欢自己讨厌的东西的态度才是正确的，而不是自己爱水分所以质疑所有认真的人有问题。</p><p>不去想背后可能的「阴阳怪气」。假设他真的是开玩笑的，那我的问题是：一、「谁需要这个玩笑」；二、「这个玩笑是否好笑」。我的问题是简单的，只需要「是」或「否」的问题 —— 没有人询问你有没有人记笔记，我想知道的只是有没有人愿意分享自己的笔记。接着是这个玩笑是否好笑：不，我不这么认为，它很没礼貌，也很莫名其妙。这句话字面上就和善意不搭边，甚至还有上述提到的阴阳怪气的感觉。</p><p>这让我想起一个讨厌的朋友，以及我很讨厌的互联网现象：爱玩字面上不礼貌的梗。前段时间有种夸奖人的方式火了起来，即「乍一听以为是在骂对方，但看到最后才知道是赞美」。我不喜欢这种赞美方式，你要夸就夸，不要让我以为你要骂我。那位朋友爱玩的梗基本上没有一个是听上去顺耳的，多是有质疑意思在的，例如每次说话都要回我一句「有没有一种可能……」听上去颇有种说「你连这么都不知道？」的样。他知道这说法听上去很不舒服吗？他当然知道了，因为我模仿他说话的时候他急得跳脚，那凭什么我听了不能生气？</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>四月十六日</summary><div class="diary-entry">01:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KP9X9AXGG17WWZPK5ABPS4KY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这些天没事的时候都在翻看金田一。金田一给我的印象是，许多犯人都是通过心理诡计，让人证「先入为主」以为事情是以 A 方向发展的（实则朝 B 方向发展）。</p><p>而我对柯南的印象更多是小道具或者冷知识的一万个利用方法，以及某位师徒整出来的、让人眼前一黑的原创集。</p><p></p></div><hr><div class="diary-entry">05:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPACCC643GSSBMEGQQFSJB9B" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友在听郭老师的故事会合集，外放所以我也竖起耳朵听了听，一听差点也没给我笑死，是怎么想出这么多搞笑的故事的。</p><p></p></div><hr><div class="diary-entry">05:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPACGRPEGVXQYP2KYQFWXDMT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>第三次购入楼下超市打折的草莓，结果发现这次一点都不甜，好酸好难吃！你可是我在美国难得一见的甜草莓啊，你怎么可以堕落！</p><p></p></div><hr><div class="diary-entry">13:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPB8FMDZ9VEJ049ZR6ZKHWZ3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>愤怒，很多链接点进去都无法访问，还以为是对方服务器炸了。多点几次感觉不对，炸的怎么这么多。想到什么后，果断把 wifi 断了改用流量，所有东西都可以正常访问了。这到底是 Spectrum 的问题还是什么。</p><p></p></div><hr><div class="diary-entry">14:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPBA9CSB1G1458NMM2N181ZA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚上一位朋友在小群里表达出了自己对未来的焦虑。这不是第一次，也不会是最后一次。这几年来，基本上每过一阵子他都会在小群里说丧气话，可能我之前在 Fediverse 上都说过这件事情。</p><p>他的专业是非硬性需求类型的，且可以被 AI 冲击波影响到。放现在，只有能力异禀的人才能找到岗位。而他的能力并没有多好，因为他上大学是混日子过多，甚至也不喜欢他这个专业。他原本学的是游戏设计，但嫌写代码难，遂放弃。之后如果没记错，他因为朋友在，所以换了家大学、专业。</p><p>我多次有建议过什么专业放现在好就业。现在混日子混到快毕业了，原本就不想换专业、真的去学什么，现在又可以说自己快毕业了、怎么可能去换 —— 当然可以啊。又或者说学个副专业、在自己的文凭上加行铁饭碗专业的字儿，他也明确表示不想学、罢了。</p><p>然后我们聊到美国什么工作赚钱。蓝领赚钱啊：做厨师、装修，但别去抠门老板底下做，尤其是华人，想方设法把国内那套搬进来，不把人当人 —— 人工费很贵好么！粉领搞小费也不错吧，去稍微高级点的餐厅做企台也赚 —— 你总不能一辈子摇奶茶吧。奶茶这玩意儿喝的人越来越少，店里都倾向于一个人当两个人使，工资也低，你真要因为自己已经会了，所以一辈子啥都不学、锁死在这上面呗？</p><p>对话不算愉快，我借金田一为理由、溜走了，不然和他继续聊得聊到凌晨三四点。他也明显不是真的想解决问题的，否则最开始我们提建议的时候他就会听、逮着个东西好好学。早上起来看的时候，发现他凌晨自言自语道自己是不是有双相、感觉症状都挺符合的。</p><p></p></div><hr><div class="diary-entry">17:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPBM9590B17R7Z99HF5M241N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>税务季今天零点结束…… 但是大家全都延了期，所以税务季没有正式地结束。傻管理兼写报表的忘写了一客户的报表，大晚上赶，又被难用的 Taxwise 卡住。这种报税软件真的是难用到我怀疑是不是会用它、在税务界就已经算是厉害的人物。她期间一直着急问我咋办，你问我咋办，我是报税的吗你问我。</p><p></p></div><hr><div class="diary-entry">18:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPBR14X2022KF10MX52W6H9H" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>对几周前吃的农家小炒肉流连忘返。虽然只是普通的青椒炒五花肉，但是炒出来没那么油，猪肉还脆脆的。室友也觉得好吃，想在家里做出来。</p><p>五花肉超市里有，没问题；青椒要怎么选哩？这家超市里除了 bell，就只有 cubanelle、serrano 和 jalapeno。其中青色的 bell 长得最像我常说的「青椒」，但我不清楚青色的 bell 是苦的还是甜的。室友很讨厌 bell，只能 pass 掉。</p><p>Jalapeno 通常用来做酱，我们应该吃不了这么辣的辣椒。而 serrano 要更辣上一层楼，算了算了。Cubanelle 是这四个里最适合煎炒的，辣度虽有但相当微弱，整体还是偏甜。</p><p>万事俱备，只欠东风 —— 准确来说是东火。可恶的电磁炉，把我的五花肉搞成炖肉了，一点都不干脆，到处都是油。</p><p></p></div><hr><div class="diary-entry">19:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPBVS8JVR24K8797TRZBN08R" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打工，考虑要不要喝可乐。嘴馋是真，摄入过多也是真。昨天去买菜的时候，偷偷在购物车里加了个蔗糖版的玻璃瓶可乐，室友竟没有揍我。晚上品了品，感觉可以喝出玉米糖浆和蔗糖的区别了。</p><p></p><blockquote class="diary-thread-reply">21:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPC21T4JCXKVB93N904N4TJ7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>结果还是喝了…… 这次加了冰块，30 度的大热天里喝最舒服了，虽然我在空调房里。</p><p>上次在店里等冰淇淋车等半天没出现，今天也等了快一天，也是没出现。唉，没有追冰淇淋车的夏天不是完整的夏天。</p><p></p></blockquote></div><hr><div class="diary-entry">22:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPC56STXWPQHN3F53Z8N30X1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我忘记交学费了，现在选课不能，唉。</p><p></p></div><hr><div class="diary-entry">22:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPC725P849ZWH2TNFWKNFRW6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>竟还有这种劫持，涨知识了。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KPC71T4S35RMRGZZNPTS424Z.png" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>四月十七日</summary><div class="diary-entry">14:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPDY7N71SXMWZC4S98FZPQS7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我才发现百度贴吧 web 可以切换回旧版。差点以为回不去了。</p><p></p></div><hr><div class="diary-entry">18:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPEAFCH7CMA91A2MZ9CKNYGB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>让 agent 帮我写了个小工具： <a href="https://gtsm.cytrogen.icu/" rel="nofollow noreferrer noopener" target="_blank">https://gtsm.cytrogen.icu/</a></p><p>会按月抓取我所有的嘟文，然后按日分组展示。目的是为了让我回顾这个月我都在发啥。</p><p></p></div><hr><div class="diary-entry">23:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPEW9K27H1V052NE45HP1C3A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友从德国朋友那里学来了胡萝卜的新吃法：表面洗净，用 cottage cheese 沾着生吃。她又改良了配方，添加了 ranch、意大利的酸辣沙拉酱但我忘记名字是什么，以及过期两年的炼乳……</p><p>上次喂她吃酸草莓一点都不过分。</p><p></p></div><hr><div class="diary-entry">23:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPEWN19785FZTSGRVS5DDN8F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨晚跟室友买了《逆转裁判》三部曲玩。这类游戏我第一次玩的是《谎言游戏》，然后是同公司出的《恶狼游戏》—— 我的看法是它们美术风格和实际推理的部分完全不能相提并论…… 人设明显更出圈些。</p><p>国产里有个作者做的衡水中学和蓝宝石女孩挺有意思的，想要自己玩玩看，全名不记得了。</p><p></p></div></details><details data-group="diary_sections"><summary>四月十八日</summary><div class="diary-entry">06:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPFK1QXH9F0QT50G8DWE7RZJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>博友写了篇和美国税法相关的文章，遂分享给税务师朋友看看，结果对方连续发来十几条消息纠错…… 其实也不是什么很大的错误，而是许多地方没有说清楚，或者数字没说准确。这跟我看技术文章里作者管 Node.js 叫成编程语言一样的感受吧，不影响读者去理解文章内说的其他东西，但 Node.js 就不是编程语言的一员！</p><p>其中有一点，是 IRS 的恐怖被严重夸大了。它确实会在查到有人逃税时、疯狂追查，但重点是它决定去查。现实情况是，世界上有太多涉及到百万、千万以上的逃税金额，IRS 管这种都管不过来，逃个几百块的一般打工人更不会被查到。</p><p></p></div><hr><div class="diary-entry">06:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPFM5KJ5M0G7HTETZ9Z4HZZB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>回家路上有点饿，明明十点多吃了一碗烩面，还是之前怎么吃都会吃饱的，怎么就还饿呢？总之去了家 deli 买泡面，一包火鸡面一个碗面，居然要 7 美元，骗钱哦！</p><p></p></div><hr><div class="diary-entry">16:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPGNKSYC8YSXHXQ1Y3HNHRW6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Wolf Howl 卡里的数码兽还没收集完，看到 Amazon 上这两张卡打折，竟然才 4 块钱，果断下单了。</p><p>Volcanic Beat 里有一代经典的 Birdramon 和 Meramon！而 Blizzard Fang 里有可爱的 Yukidarumon，出于某件事情，他和我很有缘。不过这两张卡对比 Wolf Howl 都少了一段进化。</p><p>通过运动培养和收集数码兽，很有趣。</p><p>关于手环产品的详细信息，建议看： <a href="https://humulos.com/digimon/vbdm/manual/" rel="nofollow noreferrer noopener" target="_blank">https://humulos.com/digimon/vbdm/manual/</a></p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KPGN8H95H006ZY9QFPZHQ70A.jpeg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">16:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPGPMV8Y9FQHPR2GS0R16WW0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>搬离家也有三四年了，最显著的变化便是和父母的关系变好了：吵架频率下降、彼此都看彼此顺眼了许多，恶意也少了很多。还是要离开家啊。</p><p>曾经有数位朋友就「成年后要不要搬出家生活」吵得不可开交。其中一位很受家人宠爱的讨厌鬼认为，「为什么要离开家，有家人的照顾和陪伴，还不用多花钱，不挺好的吗？」</p><p>虽然我是因为和家人天天打架，为了精神健康离开的家，但我依然认为无论和家人关系如何，都应该在成年后至少搬出家生活一次。离开了家庭、去和陌生人或者同龄朋友磨合，这种感觉很不一样。虽有时会沮丧、愤怒，但也收获了许多好的东西。</p><p>当然这一切都是基于有好的经济情况之上的事情。纽约的房租还是太贵啦 ——！</p><p></p><blockquote class="diary-thread-reply">04-19 00:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPHJ5NDJN0DT12A253Z8DNPC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>唉，撤回一些话，实际上碰面还是会情不自禁想要和父母打起来。最好还是不见面吧。</p><p></p></blockquote></div><hr><div class="diary-entry">16:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPGQWXT71Q3VKNCZRHEP65E7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Kagi Maps 作为和 Kagi Search 一样的资源汇集器，虽然可以看到一个地点的许多信息，但是没有过滤器，导致想要真的去找家符合我要求的餐厅，依然要去 Yelp 或者其他源上看。</p><p></p><blockquote class="diary-thread-reply">16:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPGR9QJJRVNFGPKAW77QNHG5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我也只是想找一家能把狗放进去的餐厅而已啦！</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>四月十九日</summary><div class="diary-entry">01:34 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/951291994092052638" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>从妹妹那儿搞来的咪咪猫照片。</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/31410d826-759a86/MKBfYhOFzmUf/8JFjDa25tCrjRfgpfUl5xM0vlLnGU6RrOXtnRmfc.png" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/31410d826-759a86/0N8ZpTRhKlKK/QDzCX86eC7sYaJQqpJyGtcSShY4bKcCiM6KVOOZh.png" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/31410d826-759a86/psNftETAznOo/6uHt2z4AOxkCjVQOok1la35Kl5MfcJvnon8p021H.png" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/31410d826-759a86/6hdC9xhqPZ80/J0FdSCUiif39kvFRbjjuwJZacG0nAme4oXJ7uubc.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">02:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPHQFVYBYDJR0T5TASVXN9AN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>玩《杀戮尖塔 2》的期间时不时会在想，之前玩《月圆之夜》全成就像个笑话。虽然两者无法完全对标彼此，但后者的难度实在是低到不行。</p><p>接着又会想起经典模式已经被制作团队放弃…… 有生之年还能看到修女的日记 DLC 吗？</p><p></p></div><hr><div class="diary-entry">13:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPK00VWNKGPPQRWHG8FY8QZV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://news.kagi.com/s/b9de6t" rel="nofollow noreferrer noopener" target="_blank">https://news.kagi.com/s/b9de6t</a></p><p><em>Aye Yai Yai</em>.</p><p></p><blockquote class="diary-thread-reply">04-20 00:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPM3SJ8KHG0A2KXGEBB4ZX81" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前几天 30 多度，今天 10 度不到，搞什么啊，好讨厌。我还把冬装收起来了。</p><p>只能多披外套出门买菜了。</p><p></p><blockquote class="diary-thread-reply">04-20 00:17 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPM3Z8M7X8PR8QFQ9C99YE04" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>为什么会有人贴鬼图在电线杆上…… 一转弯就看到张大脸，缺德喔。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">13:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPK0CPJM3RN3M986G79E5RTJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://news.kagi.com/s/6v2zs8" rel="nofollow noreferrer noopener" target="_blank">https://news.kagi.com/s/6v2zs8</a></p><p>我们需要言论自由 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKQ496Q8A4XAZF9TK81RAX7.png" alt=":ottersgottaott10:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">14:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPK0N0ZKWE0NGRTE9NXWTXQK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>天啊，连续休息两天，我是做好事有了回报吗？</p><p>脑子想出这种话后意识到自己可能没救了…… 总之让自己的生产力 up up、把 TODO 列表上的事情做完吧。</p><p></p></div><hr><div class="diary-entry">15:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPK68VCNWCXJK69MA07FBRQN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前在电脑里下载了以前的 GTA 游戏，现在玩的是之前一直不会兔子跳的 San Andreas。任务也太接地气：帮派人沉迷于吸毒，所以要去干掉毒贩子。</p><p></p><blockquote class="diary-thread-reply">19:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPKKC0JXS3YB730PT5F6M6P4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>第一次知道这一代里的主角要吃饭，还要锻炼身体。</p><p>之前玩个人认为更经典的 Vice City 那一代，只记得有万恶的小飞机和汤米溶于水，没有像 San Andreas 这么复杂的状态机制。</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>四月二十日</summary><div class="diary-entry">00:49 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/951643041705439464" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Mimi why are you inside the bathroom? Wait what the hell---</p><p> <a href="https://pixelfed.feddit.social/discover/tags/cat?src=hash" title="#cat" class="u-url hashtag" rel="external nofollow noopener">#cat</a></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/31410d826-759a86/D5nKDWKWjbaP/fbknnZyPhm7wjS6F0FIDWVXSvH9O1RYkU6O1a74n.png" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/31410d826-759a86/X6l29Mfb0TkJ/7DK6Mg3FT7lsBsrR0mfiP5cvN9NL0tSAzusJD6Yp.png" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/31410d826-759a86/Dz1Dn2RT02Gq/N9EckCfiSaQEtkUX4k4EqsdWbmnxqujkwgueWFXt.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">00:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPM6256AJKQBWFMFKKFGGWRX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>几个月前找到了室友不用的旧电脑。据她所说，系统已经不能再更新，许多主流软件都不能再用了。本来拜托她找一下充电器，结果她一边答应下来一边完全没有在找，最后只能认定它丢了、另买了一条。可气的是商家迟迟不发货，害我必须退款、去找另一家买。</p><p>现在要考虑的是，这台不知道多大的 Macbook Air 能干什么呢？</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KPM5WNA1BFSGS5SD94H8BTNQ.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">00:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPM68H46KYJ5P5SD7M5607PJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不…… 最该考虑的是怎么把它打开…… 室友的电脑密码我不知道，她本人居然也不知道。</p><p></p><blockquote class="diary-thread-reply">13:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPNGNMB74N040Y48BSK275BS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>总算是打开了，里面没有太重要的数据，真是太好了，现在就开始快快乐乐地刷新系统吧！—— 不对，Macbook 的重点不就是 MacOS 吗，你不是还有 iPad 没有生态上的好伙伴吗！—— 可是这台电脑比妹妹还要大几岁，系统早就老到不能正常使用主流软件啦。再加上掏出个笔记本但里面跑的是不知道叫什么的操作系统这件事、不觉得很酷吗。</p><p></p><blockquote class="diary-thread-reply">13:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPNJV2Q8GHGAHCERWC4JXPQE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>真神奇，第一次把玩 Macbook，发现它可以单手很轻松地将屏幕掀开。虽说这应该只是轻薄本最基础的设计吧？（我主力的笔记本是最可恶的全能本）但第一次上手接触还是觉得很有意思。</p><p></p></blockquote><blockquote class="diary-thread-reply">14:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPNPFER93EY5B761GSM09D52" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这个系统用下来还是很喜欢的，就是接下来要配置很多很多很多东西了……</p><p>最开始离线安装完发现界面不太对，说不上来为什么，还怀疑是不是人家今年进行了一次设计大重构。用了下才发现离线安装默认装 KDE。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KPNPCTAA7PASH64A2T3HBA4W.jpeg" alt="" loading="lazy"></figure></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">15:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPNPV6G0VBJ225VZM05KP4EC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不好好做好适应性的下场就是这样！</p><p>纸条上的文字是 SVG 所以不受影响，但作为代价无法复制粘贴。还是好好想办法做可适应性吧。</p><p>这个电话的设计我还是很喜欢的，尤其是拿起听筒才能拨号这一部分。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KPNPMYMGDSBDS3004PGFHNM4.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">15:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPNS5DHQZ04XWM622Q0HJRN9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>为什么我的电脑还漏电啊 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​ 折腾 Macbook 的时候把手放在了原本的笔记本上，结果那种像是被电流按摩的感觉出现在了手掌心上。</p><p></p></div><hr><div class="diary-entry">16:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPNWGG6HJ6P371MMJ8MHBDQC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Bruh literally after saying the word <em>sunlight</em>, I realized that if I open the curtain now my vampire roommate would kill me for doing that, because she's still sleeping nowwww</p><p></p></div><hr><div class="diary-entry">21:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPPDGJ746P062TEJDR9F70G7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天的中文课学到了很多东西，还被教授夸奖每周写的讨论写得很好（就是经常不写……）<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JNHF23SBKYB8350F7PKT.png" alt=":neocat_happy_blep:" loading="lazy">​ 不过在同学们全都在用 AI 生成车轱辘话的情况下怎么可能写不出来好东西啦！</p><p>一同阅读的是白先勇的《夜曲》，在历史、音乐、政治层面上解读了短篇小说中的人物们。实在是很难想象，他们仅是虚构作品里、历史的缩影，而真正经历过同样事件的人们，恐怕数也数不过来。期间，教授也透露道，他以前做过的「要是被发现了就一定会被告发」的事情，引得同学们好不好奇。总之，很期待写这篇短篇小说有关的文章，不过前面还积累着好多本就是了……</p><p>课后也找教授单独询问了缺席那节课、没听到的小说解读。教授给出了一些我没想到的见解，很有启发性。</p><p></p></div><hr><div class="diary-entry">22:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPPFD44MQ8C8PHE467WF5YT9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我又想喷学校基础设施了。你打印文件只能通过 web UI 上传，我觉得没问题，但你能不能让 web UI 能够被正常访问？我流量访问不了，我还能为你辩解是锁 IP、防止有人滥用。但学校网络连上了也不能用是什么意思？你干脆直说只能用学校电脑访问吧！但你学校电脑登录进去要用一个账号登，去门户登录下载文件要用另一个账号登，最后去打印用的 web UI 要用另另一个账号登，是什么意思！</p><p></p></div></details><details data-group="diary_sections"><summary>四月二十一日</summary><div class="diary-entry">01:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPPTH90EWDTYT3CD065TF7NG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Orion 可以安装 Violentmonkey，这下可以在 iPad 上用 Tempermonkey 脚本干些七七八八的事情了。</p><p></p></div><hr><div class="diary-entry">02:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPPYH5FYW8YWQ3RMKWAV0PMY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Board 最近好多人推荐和公共图书馆有关系的数字流媒体平台。可惜我找不到之前的图书馆卡，也很久都没有再去过了…… 刚上大学那时候还打算去办张新的，但拖延症让我迟迟没有行动。</p><p></p></div><hr><div class="diary-entry">03:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPQ24EQZFZ0RATTZP9TN5P07" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前订阅的一博客设计上使用了意想不到的颜色，但是最近去看发现变成了「极简黑白圆角气泡」主题，变化也太大了吧！虽然我也没资格说啦，但他的新主题看上去和其他博客很相似，失去了个性。我还是更喜欢之前的。</p><p></p></div><hr><div class="diary-entry">11:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPQWBK0G6VAVFH0RBK9HX1CX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>到下午都不能开窗帘，因为某个正在呼呼大睡的家伙 ——！我只好蹲在窗边，吸收一点太阳光…… 逐渐理解了为什么人们选房会选朝向好的。隔着窗户都能感觉到外面的寒冷，明明前几天还有 30 度。唉，也好想晒被子，但晒的话会被罚款。想念以前家里的阳台。</p><p></p></div><hr><div class="diary-entry">11:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPQWF9SY5X0DMQN5Y0A6QHWQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>睡前看了点诈欺游戏。令人感叹利用「数字」可能玩的把戏有很多，像几年前春晚上的刘谦，就用了数字让人们以为扑克牌是被随机打乱的，实际上却不是。</p><p></p></div><hr><div class="diary-entry">14:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPR8CMRKF4FXYCMRNPASZD42" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>坐地铁的时候，要乖乖站在门的一边，给要出来的乘客腾出空间出来喔 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JNHF23SBKYB8350F7PKT.png" alt=":neocat_happy_blep:" loading="lazy">​ 可恶的人们，明明知道这一点，却还是堵在门口、让里面的人只能想办法挤出来是什么意思！里面的人出不来，你外面的人也进不去啊。幼儿园还是小学的时候学习过的东西，现在完全忘记了吗！</p><p>不过同为礼仪一部分的「乘坐扶梯时要左行右立」，我持反对意见。如果有人想要往上走的话，乖乖走旁边的楼梯啦，也更安全不是吗。因为这个习惯，大家无论什么时候都会站在扶梯的右边，扶梯上能容纳的人会变少，效率也很低啊。然后左行右立对扶梯本身也有损害。</p><p></p></div><hr><div class="diary-entry">14:56 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPR8NQB9309Z38CQZTMY5P0A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>MTA 新型车厢最开始坐还觉得很新很棒很漂亮，尤其是现在显示屏上会显示当前的车厢在当前这个站的哪里、离楼梯和电梯有多远。</p><p>但现在意识到，因为把放纸的地方都换成了 LED 屏幕，所以一抬头就可以看到五颜六色的广告…… 广告…… 告…… 实在是太鲜艳，对我这个习惯把设备屏幕弄成灰阶的人来说是种折磨。</p><p></p></div><hr><div class="diary-entry">18:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPRMFST64C3PNCTJMT6ZPHHD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前台阿姨：小妹，后厨师傅给你做吃的，你要是有离过婚的姑姑婶婶阿姨就介绍给他哈。</p><p>后厨师傅：对，对，我有八块腹肌。没结过婚的也要哈。</p><p>实在不行，我等你长大也可以。</p><p>我：<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3KMH1XH965H9ZD3JSM7Z7.png" alt=":neocat_laugh_nervous:" loading="lazy">​</p><p>让人想起刚成年上大学的时候，母亲就让我去跟大十岁的富二代相亲这件事。</p><p>人类还是有好人的，该毁灭的是我 ——！</p><p></p></div><hr><div class="diary-entry">18:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPRP0JXS4ZW4RQK9BBNNVVJ3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前和朋友们聊到个话题，说的是从小幸福快乐长大的人，对于「死亡」一事有着更大的反应。他们日常生活中完全不会想到「去死」的事情，并且听到别人提起「想死」，会很惊讶。因为对于他们来说，「死」是一件大事，更不用提「暴力」了。</p><p>这个「幸福快乐长大」自然没有说的那么简单。因为我认识的一个 <strong>超级无敌讨厌鬼</strong>，就是在「幸福美满」的家庭里长大的，但这个「幸福美满」也包含着他对亲生哥哥和同龄人的霸凌和欺压。长大后，他虽时常夸赞自己的家庭多么美好，但依然可以看出其骨子里的残暴 —— 毕竟谁有事没事就拿着把蝴蝶刀对着同学的脖子，然后靠贬低的方式让别人喜欢上自己呢。</p><p>说回对「死亡」的看法。我有被动死亡欲望，也就是会控制不住去幻想自己因为什么事情死掉。这个概念我不清楚是谁想出来的，但看到它是在《不原谅也没关系》这本书里。对标的另一个概念叫「主动死亡欲望」，即会主动寻死、自毁。</p><p>什么时候变成这样的，我也不知道，但我猜是来到美国后。来美国是我人生的转折点之一，我不仅来到了一个完全不熟悉的环境，也重新和父母住在一起、进入了我人生最为黑暗的时期。我对来到美国这件事，实际上多抱有后悔的想法 —— 但其实，待在哪里我的人生都会是黑暗的吧。</p><p>高中的时候，精神状况随着儿童保护局的介入，以及朋友们的帮助，变得越来越好些。但是毕业作品，我还是画了和「自毁」、「宗教」相关的作品。我也不知道为什么，但是里面的人物都和「死亡」相关，且多有「砍头」的元素在。</p><p></p></div></details><details data-group="diary_sections"><summary>四月二十二日</summary><div class="diary-entry">01:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPSCDYCEEBE2WGCTRNDFQNJW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>下班！回家收拾收拾去看《八号出口》。没想到家附近的影院上了。真可恶，每次都是这样，一点预兆没有就上映电影。要不是我还心心念念影院给的生日礼物、看了眼最近电影在放什么，估计就又要错过了。</p><p></p><blockquote class="diary-thread-reply">04:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPSNZ16VXD03CR8BSRS99WYQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>记错时间了，导致晚了差不多十几、二十分钟才看到…… 幸好对理解剧情上影响不大。比想象中的播放时长还要短上不少。</p><p></p></blockquote></div><hr><div class="diary-entry">18:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPV5XVJTBFG4AV0JC7P4EPBN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这款 Macbook Air 的屏幕颜色看上去怪怪的…… 感觉太亮了，很难受。是屏幕硬件的问题么？再就是键盘还需要适应一段时间。</p><p>我试着把屏幕颜色调整成了灰阶，但还是很亮、伤眼睛。</p><p></p><blockquote class="diary-thread-reply">19:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPVBZXK0TSWAG2H3BQNAG1EF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>改用 redshift，让屏幕少发射蓝光了。目前看上去不会让眼睛太难受，但太红了也会让我觉得不舒服。</p><p></p></blockquote></div><hr><div class="diary-entry">20:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPVERSVYE30AX2FP6CFJ2PQH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近开始炸鸡肉吃，因为做起来方便、好储存。第一天做完腌料，腌一晚上鸡肉，第二天就可以上面包糠或者裹粉。之后每次想吃，放进空气炸锅炸两次就行，也不需要洒油。去年就吃过一段时间，这次配方改良了一下，添加了牛奶。加了牛奶的腌汁，可以让鸡肉更滑嫩多汁。</p><p></p></div><hr><div class="diary-entry">23:22 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/952708168165859597" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Weird statue.</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/31410d826-759a86/xmcHptvb2PUj/Ns21CYKpyBDcouanpdRl4B1rBQhlAqvfxyR7yM7o.jpg" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>四月二十三日</summary><div class="diary-entry">01:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPW0GACDC8W6DFFNE8V9FXJG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>总感觉每年生日都鸡飞狗跳的，这也包括室友的生日。她很讨厌庆祝生日，尤其是自己不想过生日时，别人还强行要为她庆祝。但又因为她不喜欢解释太多，所以让对方误以为她是没朋友、怕尴尬…… 这下更尴尬了，不知道如何解释才好。</p><p>现在那位朋友找上我，想要我一同加入、庆祝室友的生日（不知道有没有经过室友的允许呢？）。同时，我很讨厌的人会来。单是听到他的名字，便立即让我烦躁起来。</p><p></p><blockquote class="diary-thread-reply">01:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPW0YGH9HXTE25WN22Z8G9AF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>但是为什么每次从第三人那儿听到他的名字，都会带贬义的形容词啊？像什么的「怪胎的」、「不应该张口说话的」…… 路人缘也太差了吧！唯一一个觉得他很厉害的，是另一个我讨厌到甚至写过文章一吐为快的人……</p><p></p></blockquote><blockquote class="diary-thread-reply">20:52 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPY1VR9P71N87J47BSD02587" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>结果对方说也要给我煲汤，实在是太热情了，就算我有说自己不会参与。</p><p>有时候会反省自己是不是太容易讨厌别人。但和室友比较后，发现她更容易讨厌别人，并且还会讨厌对她好、但是有着她瞧不起的特质的人。比较了下，觉得自己讨厌别人也没有那么频吧！</p><p></p><blockquote class="diary-thread-reply">04-24 02:49 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPYP900WSC07S2C3ZTWM9JZP" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我错了…… 对方做的是和浪费食物没有两样的，原本是汤面的面。为什么说是「原本是汤面」，因为他把面和汤放在一起放了十个小时，汤全都被吸干了。而这个汤，则是完全没有肉味儿、只有肉桂和草药包的苦味儿的汤。不知道为什么，他选择把草药包和面放在一起泡？面只能吃出酸味儿和苦味儿。结果是制作者本人都没能把这东西吃完。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">03:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPW6RZGKQDVMMP5HHYEC9RR0" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>發現 IMDb 的網站可以看到未來要上映的電影： <a href="https://www.imdb.com/calendar/?ref_=hm_nv_menu" rel="nofollow noreferrer noopener" target="_blank">https://www.imdb.com/calendar/?ref_=hm_nv_menu</a></p><p>同樣的還有 Movie Insider 的網站： <a href="https://www.movieinsider.com/movies" rel="nofollow noreferrer noopener" target="_blank">https://www.movieinsider.com/movies</a></p><p>這臺電腦的輸入法不知道爲什麼，默認是繁體字呢。打出來後就懶得切換了，乾脆就這樣吧，也當認識認識繁體字好了。</p><p></p><blockquote class="diary-thread-reply">04:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPW8NTH06JZ913P09QW6QC1Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>查閱的時候發現十一月會上映 <em>Godzilla Minus Zero</em>！</p><p>我很喜歡將哥斯拉視爲自然環境、核武器或者其產物、戰爭象徵的哥斯拉電影。好萊塢中怪獸互相爭鬥的電影我則不怎麼感冒。</p><p></p></blockquote></div><hr><div class="diary-entry">06:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPWFQWGBJ9FFAZWCJGKFJ2X6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>ｗｗｗ新しいパソコン（実は新しくなくて、ルームメイトさんがくれた古い Macbook だ）で日本語の IME を追加した。日本語を話し続けると、きっと上手になっていくよ！</p><p></p></div><hr><div class="diary-entry">21:01 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPY2B4GSK54SJCCBZ4YMK9EQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://news.kagi.com/s/9ftrhn" rel="nofollow noreferrer noopener" target="_blank">https://news.kagi.com/s/9ftrhn</a></p><p>这几天天气一直变来变去的。再这样下去，一定会生病啊 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​</p><p></p></div></details><details data-group="diary_sections"><summary>四月二十四日</summary><div class="diary-entry">01:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPYGKWA0JS7AZ6PH0K3H4VVS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在别家买的又便宜又甜的草莓全被室友拿去榨她的香蕉草莓奶昔…… 未来还会加入蛋白粉进去。我想吃草莓……</p><p></p></div><hr><div class="diary-entry">02:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KPYM9XYBNH4M7M08N22D19AJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMKPG9JXEBDFYC9RZH0AC9PB.png" alt=":cozy_otter_face_rub03:" loading="lazy">​ 每每选课都有辍学的想法。学校的 CS 专业有着许多我认为根本没有必要的前提要求，例如数学课必须拿高分。但是我一直都不是个能拿高分的人…… 因为我很不喜欢写作业，也不喜欢勤来学校 —— 也是我活该了。校方的观点是，这是为了可以让专业课更贴合行业内的要求 —— 那你倒是不要误导小白，教他们 class 呀！免费的 Python 基础课都不会把 class 落下，你凭什么就可以！再者是，给这么多数学相关的前提要求，有什么用啊？你不是 CS 专业吗？非要让别人认为，不懂数学就不能学 CS、进 CS 行业吗？行业里最常见的岗位是什么？是不是写业务的？它一定需要数学很厉害的人吗？我又想到，我上学是为了什么。学习，同样的资料和书我都能找到，并且自行捣鼓清楚 —— 我是不是不适合上学？这样想着，越来越焦虑，脑子也越来越乱。</p><p></p></div></details><details data-group="diary_sections"><summary>四月二十五日</summary><div class="diary-entry">02:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ16AKMF1YK3GSRJANRCQCGZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在为就业一事严肃焦虑中。学业什么的无所谓啦，gap 就 gap、重修就重修吧，但是工作还是要好好找啊。对产品也没什么想法，问别人也只会叫我去做 AI 伴侣软件。</p><p>据说不投个上百份简历是不准抱怨的 —— 有毒的环境啊。</p><p></p><blockquote class="diary-thread-reply">07:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ1R24392MQ74RZ1TFNCS3V7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ2FW8JTX1ME80G4XQ37R70.png" alt=":blobcat_is_in_rain_ani:" loading="lazy">​ 部分申请问我 GitHub 账户链接。想想我的 GitHub 不仅头像「不正经」、是游戏里的女角色（不要问我是什么游戏！），很多仓库还不是什么大项目。</p><p></p></blockquote><blockquote class="diary-thread-reply">04-27 16:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ7X1TAS1G5EVVNZK8MZYXK4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>大多数申请都会询问我种族和性别是什么，并且声称仅是为了统计，整个申请流程是公平的。但我们都知道这是假的，而我只能去乖乖将自己先天的信息输入进去，因为「只有亚洲女人会刻意模糊掉自己的性别和种族」也是个隐形规则。</p><p></p></blockquote></div><hr><div class="diary-entry">16:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ2PNX9796VGQXW83XK17R6G" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>读《大教堂与集市》嘟串：</p><p>Brooks 定律说，在一个已经延期的项目上增加人手，只会让项目更加延期。</p><p>在做项目时也发现，和人沟通才是最消耗精力的…… 如果计划增加人手，还需要确保文档等写得没问题。而我实际上没有写文档的习惯 —— 对不起啦！</p><p></p><blockquote class="diary-thread-reply">16:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ2PZ9NP52168M5JWDN742TD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>书中提到的一个例子是：</p><blockquote><p>bug 会集中在不同人写的代码的交互接口上……</p></blockquote><p>我想象的是前端开发人员以及后端开发人员之间的冲突。如果接口数量增多，文档没有及时补上（例如 hotfix 的时候），导致代码写错，或者需要来回沟通，是很累人。</p><p>我现在的方案是让后端的 Swagger 自动生成前端的接口代码，前端的 store 只能调用这些生成好的接口代码，相当于把主动权交给程序了。这样做的「代价」是后端 DTO 和 controller 得写得很详细，足以让 Swagger 生成正确的接口类型。</p><p>不过这也只是一个人开发的时候想出来的方案。</p><p></p></blockquote><blockquote class="diary-thread-reply">23:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ3FAJXF4XE1VN2ZH7SR5EEG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>书中提到，驱动志愿者文化的东西不是经济价值，而是自我满足和黑客声望。不单单是开源社区，也包括例如科幻迷的圈子，都是以 <em>egoboo</em> 作为基本驱动力，即个人在团体中声望的提升。</p><p>这一点实在是感同身受啊。</p><p></p><blockquote class="diary-thread-reply">04-26 20:54 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ5S50F578QGJW9V8Z3MF24N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>接着作者提到了礼物文化，希望可以借此解释黑客和开源文化的状况。</p><p>首先除了礼物文化，还有其他组织模式，比如说更知名的「命令体系」和「交换经济」。前者将稀缺物品交给中心化的权力分配，谁具备这个权力看的是他的武力；后者对于稀缺物品的分配是通过自愿在贸易上合作，谁拥有最多可使用且可交易的资源，谁就有最高的社会地位。</p><p>对于黑客和开源社区而言，这两个都不适配。Raymond 认为「礼物文化」才是最适配的。礼物文化的前提是人们物资充足。当物资充足时，命令关系无法维持下去，交换关系也没必要了。那么如何决定谁的社会地位最高呢？是通过送礼物、通过谁给予了最多。</p><p>如果是这样的话，黑客们不断去编写高质量的开源代码，却近乎不收取物质上的回报，就能说通了…… 吗？这个话题是复杂的，单靠礼物文化依然无法解释黑客圈的所有事情。</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">04-26 00:07 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ3HT5RM5Y16TT6164GCXB1Y" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>本书在发布初版后，Netscape 便决定开源自己浏览器的源代码，不过之后还是被 Microsoft 的 Internet Explorer 打败…… 他们成立了个组织，就是现在大名鼎鼎的 Mozilla，日后开发了 Firefox 的组织。</p><p>但根据作者 Raymond 的说法，这家公司以及 Mozilla 最开始的做法，并没有完全遵循他对开源集市模式的想象。他们同时展示了开源如何成功，以及开源如何失败 —— 不是所有东西沾上「开源」二字就会立刻变成金子的。</p><p></p></blockquote><blockquote class="diary-thread-reply">04-26 00:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ3K0FPM0ST3VR8QP1CT05B1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RMS 推行的自由软件，是不反对商业化的。这一点听上去有些反直觉，但确实如此。自由软件想要的仅是，用户不论怎么获得软件的副本，都能够自由去运行、修改、复制和分发。也就是说，同个软件的副本，用户能够付费去获取，也可以免费获取，这取决于卖软件副本的人怎么决定。并且这卖软件副本的人不一定是软件的原创作者，可以是另一个用户。</p><p></p></blockquote><blockquote class="diary-thread-reply">04-26 20:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ5QDME8CSJSZGFMFKVZPKKM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>书中时常提到现在已经被淘汰的互联网沟通方式，比如 Usenet、新闻组等等。因为从未接触过，所以搜索了一下如何去参观参观。Google Groups 里可以直接查看。我从网络上找到一些有名的服务器，发现要么已经被垃圾信息堆满，要么最新消息还在是十几年前发的 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3M8KH0WA908PA858VD8FK.png" alt=":neocat_nervous:" loading="lazy">​</p><p>虽然 Emacs 也有 Gnus 可以看啦…… 但我上班期间不能带电脑过来看，只能玩手机了。</p><p></p></blockquote></div><hr><div class="diary-entry">16:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ2QF1422SYCQ86VNDDKA3NB" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>先前看到 Eltrac 吐槽译者在书籍里莫名其妙添加自己的主观想法，想到昨天看漫画时，发现多数汉化组也喜欢在漫画中添加自己的主观想法。</p><p>有些汉化组是会在尾页添加自己的想法，这种我认为没问题。不过直接在格子旁添加自己的主观想法，读者们的想法难免会被汉化组成员的想法影响。</p><p>还有些是在格子旁添加对漫画中引用的故事背景进行补充。比方说一部有许多来自于不同信仰的神明的漫画，汉化组近乎会将背景写满漫画格子外的空白处，导致有时候看上去特别可怕 233 我很害怕有很多字挤在一起的画面，小时候做过这样的恶梦，现在还记忆犹新。</p><p></p></div><hr><div class="diary-entry">21:47 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ39S797BB17R0VNGRYRXZAA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>闲来无事跑去看了看之前加的 Matrix 群组，发现 Invidious 面临的一个大问题。</p><p>背景是 YouTube 引入了 SABR 协议，会在服务端动态调整视频的质量。在技术层面上，它将视频切割成动态变化的小 chunk，通过加密和安全令牌来保护内容。所以像 yt-dlp 这样的传统下载工具都不能用了；就算能，要么是下得不完整，要么就是只能下载低画质的视频。</p><p>对于 Invidious 来说，他们面临的问题为：</p><p>一、需要重写播放逻辑，因为响应格式不一样了；</p><p>二、如果在服务端解密和重组 SABR 流的话，会花费大量的计算资源；</p><p>三、为了访问 SABR 流，必须生成 Google 反机器人系统要用的 PO token，而在服务端上生成的话，服务器的 IP 地址会被 YouTube 察觉到并且被封禁。</p><p>为此，最可行的方案是将 SABR 的处理转移到用户的客户端浏览器中进行。然而，它要求用户的浏览器直接运行 Google 的不自由代码，这可能会收集用户设备和网络的敏感信息。</p><p></p></div></details><details data-group="diary_sections"><summary>四月二十六日</summary><div class="diary-entry">00:33 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ3K8TV29QPZBSSE9E4T6CPW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>做了个 Jack Coke 喝，把威士忌的量降到了原本的四分之一。就算是这样，威士忌的味道还是很重 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JH2FHXKNQFADV5ETNG5K.png" alt=":neocat_googly_shocked:" loading="lazy">​</p><p></p><blockquote class="diary-thread-reply">00:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ3KRP0ERQG57NVK6ERWNB79" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我为什么要干这种事情…… 明明根本不喜欢酒精的味道。最初有这个想法好像是觉得喝酒可以暖身子，而我现在干坐在店里、没有运动，冷得要死。外面在下大雨，哗啦啦的，没带伞的人有难了。接着我想到的是自己一直都很好奇 Jack Coke 的味道，秉着「调酒师」的专业（虽然我连学徒都算不上，只会调些基础的东西），应该尝尝看。</p><p></p></blockquote></div><hr><div class="diary-entry">00:50 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ3M7Z8E9PS41YN12HWBAF1S" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我无聊的时候就会变成超级大话痨。叭叭叭叭叭。嘎嘎嘎嘎。吵死所有人。</p><p>说来我昨天想要掐死室友来着，因为她一边觉得我找工作找不到是技术太菜的问题，一边又嫌我做菜慢又难吃。虽然后者是事实，但是说出来太伤人了，所以我要揍她。而前者我也承认是自己找得不够频 —— 我投一百个简历先好吧！烦死了。</p><p>这家伙经常认为我不回应她的情绪是我的问题，认为是我没有素质或者不愿意为她做事情。像是之前去看电影迟到的路上，我就因为她穿高跟鞋走路很慢这件事抱怨了，而她认为她穿什么跟我无关。但是当她自己想要抱怨我的时候，根本就不懂口下留情，经常刻意人身攻击我，说我是乡下人或者活该一辈子穷逼什么的。妈的，三线城市是个鬼乡下！我穷不穷跟你又有什么关系！</p><p></p><blockquote class="diary-thread-reply">00:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ3MEQYE4S0GYDZ0ESQTK2XJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>其实我们吵架的时候很像。我们无法理解彼此，很多时候都觉得对方生气是大题小做。她经常因为这件事说我，但她自己也没少干 —— 可恶的双标，我可没有就这种事骂她。比方说她说了句让我觉得很伤人的话，我会很难过，而她会很不情愿地道歉，然后补上一句「我不觉得这是什么大不了的事情，我也觉得自己说得没有错」。互相理解有时候也是理解自己吧，因为我有时候也会表现出对她情绪化的不理解。这种时候应该说什么，得慢慢磨练出来，站在各个角度去看问题。唉。</p><p></p></blockquote><blockquote class="diary-thread-reply">01:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ3NCGDWY52NFYST3BNBV146" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我做的菜是…… 炒青椒羊肉肠粉。嗯，我把冷冻肠粉拿去炒了。对不起，不要说我，我也知道肠粉不该这么吃，但是母亲给我的肠粉实在是太奇怪了，完全冻成了一块。没有蒸笼，最后只能想办法把它当成河粉来炒。</p><p>我不得不说母亲买菜时总是会买她根本不吃的东西。像是番茄沙司意大利面她压根不吃，但就是买了大量的番茄沙司，以及泡在番茄沙司里的预制牛肉丸。最后这些东西都拿给了我，我也不吃番茄沙司，转手给了会吃的室友。</p><p></p></blockquote></div><hr><div class="diary-entry">02:02 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ3RC37X7GNY4JFW5XZ2BHZ8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>尽管 notochina.org 为「不想要购买在中国制造的产品的人们」提供了全新的方案，但是主页毫无根据直接说「至少付款的一半会用于资助 CCP」实在是太有误导性了…… 税务才不是这样的。通常会认为中国企业所得税法定税率为 25%，但实际上要更低，因为企业可以想办法扣除和抵免。至于这些税有没有全被用于军事武器研发，我就不评价了，肯定有一部分是用了的，但绝对不是全部。</p><p>如果不懂税务的话，还是不要大放厥词、导致更不懂税务的普通民众误会吧。我已经受够傻逼 CFA / CPA 在网络上散布和税务有关的谣言了，不是他们这个级别的就更不要添乱了。</p><p></p><blockquote class="diary-thread-reply">02:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ3S39F5P9GRDYARDHN1NBJ1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不是，「工人支付 50% 所得税」？？你知道中国能支付最高的个人所得税是多少吗？连 50% 都不到啊，这还是收入最顶层的那一批人（年收入减去起征点、专项扣除和专项附加扣除后，余额依然有 96 万的人）。这话也他妈太没有常识了吧？现实生活中能在中国缴纳个人所得税的都很少很少。你要不懂装懂我觉得没问题，但你这么离谱的谣言张口就来、给民众带来更多的误会，我就要生气了。</p><p></p></blockquote></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">敏感内容</summary>        <div class="diary-cw-content">02:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ3SFRMEHHDAB0V745X8PW92" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>上班期间太无聊了，画了点小东西。这狐狸参考了桌游 <em>Root</em> 的画师 Kyle Ferrin 的画法。</p><p></p><figure class="diary-media diary-media-sensitive"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KQ3SBGYV1J4ZCK5SPJTJ7MK2.jpeg" alt="" loading="lazy"></figure></div>      </details></div><hr><div class="diary-entry">02:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ3SJYGTVAVVBYBRC2SR7VSX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>母亲不知道从哪里买的，一次要吃 30 粒、一天两次的药。一瓶也就 300 粒，这药真的没事么……</p><p></p></div><hr><div class="diary-entry">15:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ55DCVZCAEW68CBP4B6BETX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>天冷的时候被子里老有猫。毛毛贴着我，有时候脚还能感受到它的心跳，咚咚咚的。</p><p>匹克猫还是很会享受的。我要是双腿直着放，它就会仰着肚皮躺在我双腿之间，或者耷拉着脑袋在我腿上睡觉。</p><p>不知道为什么，小动物跟人一起睡觉的时候，会变得更容易睡熟。以前有次和幸运狗睡觉，睡到凌晨不知道几点突然醒了过来，然后脑子里想到「狗不能在太热的地方待太久」、转头就开始拍打幸运狗，叫它快醒醒、别热晕过去了。它起初没什么反应，我还以为是真晕过去了，结果拍了几下后发现它只是睡太熟 —— 对不起……</p><p></p></div><hr><div class="diary-entry">15:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ57HH3YX96N4NXT75G57APR" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我在「吃」这一方面上认为吃什么都无所谓，不要因此去攻击、嘲笑和贬低别人。例如，我会认为食用狗肉没有问题，但我因为自身情况不会去食用狗肉，这两点不冲突。我也认为吃屎没有关系，我不会去吃就是了。世界上确实有着异食癖的人存在，不该否定他们 —— 总之吃就是吃了，不同地区和文化就是会吃不同的东西。</p><p>所以我很想不通一些人老是揪着「吃的东西」笑来笑去，想尽办法把文明与否和会吃什么扯上联系。尽管逻辑不通，也会在毫无根据的情况下把他们认为文明的国家以及该国家实际上会吃的东西分隔开来。</p><p></p></div><hr><div class="diary-entry">16:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ5B2KJVFG760237MSR2CS82" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3M8KH0WA908PA858VD8FK.png" alt=":neocat_nervous:" loading="lazy">​ 不知道同学用的是哪个 AI chatbot，但很明显没有把实际的文本输入进去，更像是直接问 chatbot xxx 书讲了什么，然后把 AI 生成的恐怖幻觉 chunk 直接粘贴到了讨论区中。因为这个评论的内容，和文本没有任何关系…… 更为好笑的是，下面的来自于其他同学的回应，全部都认同了他的说法，然后开始无穷地讲车轱辘话、车轱辘、车轱、车。</p><p></p></div></details><details data-group="diary_sections"><summary>四月二十七日</summary><div class="diary-entry">02:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ6DTCDCF63H2X7YQBFEGB92" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚上久违赶作业（我的「久违」在于「写作业」本身），突然想起了早上忘掉的梦：一个多人恐怖游戏。大家可以操纵一个像房子也像是机械大蜘蛛（虽然这么说但梦里一直管它叫作「火星车」）的大大大大型载具。里面有像牧场一样的场景，整体更像是动物园，有许多分区。</p><p>玩家们要操纵载体慢慢移动到很狭窄的地方，感觉是山谷里，但是外面看上去黑漆漆的，天空都是黑墨。忽然，一只山羊从载具内跳了出来，然后像出 bug 一样蹦来蹦去！有人去追，却发现黑暗中赫然有一座小房子，隔着窗户亮起电视机的白光。一个女人背对着白光，站在模糊的窗户玻璃后，似是狰狞地看着我们 —— 我们赶快逃跑，把山羊赶回了载具内，但是错误将其放到了灰狼的分区。一头长得像我第一次用 three.js 搓出来的 bearcat 的灰狼从房间的黑暗中跳出来，把山羊抓回了黑暗……</p><p>我要乖乖赶作业了！</p><p></p><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">敏感内容</summary>        <div class="diary-cw-content">03:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ6E2WWS1V3TMDF0V7ARBDPV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这个 bearcat 长这样……</p><p></p><figure class="diary-media diary-media-sensitive"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KQ6E2RV62ENSKF39PNKVPAE1.jpeg" alt="" loading="lazy"></figure></div>      </details></blockquote></div><hr><div class="diary-entry">03:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ6FS686BXX0D5CKG6M7C4W3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ Sourcehut 经常慢到令人抓狂。今儿有时间去排查下，发现是因为 gunicorn 我只给了 1 个 worker。</p><p></p></div><hr><div class="diary-entry">03:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ6HFVZR84BA79XC19GZXFZT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近无聊会捣鼓一下自己的音乐下载器。原本是通过 yt-dlp 库下载 YouTube Music 上的音乐（OPUS 格式，有损），后来添加了在 BiliBili 上下载音频的功能（AAC 格式，也是有损），接着想要去用 lucida.to 来下载一些音质更高的音乐，结果发现 lucida.to 无论哪个选项都无法正常处理。干脆跑去 bandcamp 上看看 Ginger Root 的专辑吧 —— 咦？什么叫你的无损 FLAC 格式音乐文件可以免费下载？</p><p>当然还是有给钱的。不知道给多少比较好就是了。</p><p></p><blockquote class="diary-thread-reply">04:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ6JNVDF65ZBNVHBGWM9AHHJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>日本艺人的无损音乐文件太难找了…… 最终安装了 Nicotine+，顺便把自己拥有的文件分享了出去。</p><p></p></blockquote></div><hr><div class="diary-entry">16:28 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ7WA6TH831VJR54PW0796CV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 室友买的廉价破浴巾，擦身体会掉毛，很多很多毛。</p><p>最近 Amazon 也不知道是咋了，买东西永远都无法正常跟踪状态，每次都是先告知我们「无法跟踪，等东西到了再扣钱」。按理来说也可以取消订单，因为东西寄没寄我们也不知道，但请求取消后 Amazon 依然没有动静…… 直到东西毫无预警地送达。</p><p></p></div><hr><div class="diary-entry">17:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ7ZFEJV0EN62KAQDCM3RR60" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前就很想吐槽，将博客网站从根域名搬到 blog 子域名之后，尝试联系 VXNA、Blog Finder 以及笔墨迹都没有回应，笔墨迹干脆找不到联系方式…… 最后决定随便啦！不管了。</p><p></p></div><hr><div class="diary-entry">17:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ81EZ7VT76KCTKT6ESCZPGK" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>公寓的厨房太小了，很多东西都没地方放…… 再加上没有电钻，也无法在墙上钻螺丝上去 —— 非要弄的话倒是可以走去附近的 Home Depot 租一个，但我不好说我的三脚猫技术能不能弄好，以及走过去太远了不想这么做。</p><p></p></div><hr><div class="diary-entry">20:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ89JMTQSJ3BZE9GW5KBW6ER" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看到 Board 里有人注册了 slowly。我之前想要加入笔友社区时也有想过这个 app，但当时我更想要写实体的信件，所以没有去考虑它。虽然之后就因为陷入不想要暴露自己住宅地址的焦虑中、把做笔友的事情渐渐抛之脑后了。如果是和不认识的人们随意沟通的话，说不定 slowly 也不错呢 —— 就是隐私条款里你牵扯到的第三方服务商也太多了吧！</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">学业焦虑相关。</summary>        <div class="diary-cw-content">20:31 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ8A799JFSZQJ7YGN3XQEWQN" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>已经不知道该如何继续学业了…… 其实事情也没有那么复杂，该重修重修就好了，但是现在心情无比糟糕，糟糕到甚至无法听进去自己说的话。四年没有毕业的话，助学金会没掉，再之后找不到工作的话还得停掉银行账户 —— 不过做非全日制学生的话，就算没有助学金，一个学期几百块钱我还是可以自行支付的。和父母的关系也没有好到拉长毕业线他们还会从容地给我交学费，倒不如说现在的学费就已经是我自己在交、生活费他们给我的也少了很多。简单扫了一眼部门教授的邮件，内容像是在嘲笑我没能和其他一百个学生那样，有着好看的绩点 —— 不要嘲笑我啊！真的好烦啊你们，一个个都……！反正学校什么的，去不去都无所谓了，自己读书学进去还会更开心一些，证书什么的随便啦！大家不过是一个个都在考场上作弊、申请工作的时候假造 transcript 而已！根本没有人在乎这些东西……！</p><p></p></div>      </details></div></details><details data-group="diary_sections"><summary>四月二十八日</summary><div class="diary-entry">01:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ8TAJCWV760NZNKPZYHBDVD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看到有个中文实例叫「驴肉火烧」，理由是管理员在加拿大吃不到驴肉火烧、太想念了所以给实例取这个名儿 —— 太能共鸣了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​ 我得给自己再取个「老酸奶」名儿。</p><p></p></div><hr><div class="diary-entry">05:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ98CKNK2JC9031RMT53VQ68" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>给小十一（因为这台 Macbook Air 是 11 多英寸大的）上的 mu4e 关联上了申请工作用的邮箱地址，基本上只用来做一些工作的事情。</p><p>不过找到的岗位都是要求很多的 AI 公司的，真的可靠么…… 为什么非要我写这么多小作文，还要拍视频念小作文啊。</p><p></p><blockquote class="diary-thread-reply">05:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQ98JY1Y97AXB74GWXM12NCJ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>话说小十一的打字体验很奇怪喔：字母都在偏左侧的位置，右手自然而然会更靠中心一点。但是 touchpad 就在电脑的中间靠下，右手时不时会误触、碰到 touchpad，导致打字中断。</p><p></p></blockquote><blockquote class="diary-thread-reply">14:57 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQA9GQ9QJP006RS0RVGKHJNQ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>另一台全能本（简称「多贴纸」）将 mbsync 放在 systemd 一直后台跑。小十一为了更简洁一些，改成 Emacs 开启时才会每过五分钟轮询一次。虽然五分钟也没多久啦，但就是觉得一下子老了许多…… 这种变「老」的感觉很不错 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3Q0E3XVR46S1GGCXDN71D.png" alt=":neocat_solder_googly:" loading="lazy">​</p><p></p></blockquote></div><hr><div class="diary-entry">14:51 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQA968QG90KCQ96TVDRA6ASW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JH2FHXKNQFADV5ETNG5K.png" alt=":neocat_googly_shocked:" loading="lazy">​ 今天又休息，可以大睡特睡了 —— 不，我还有很多作业没有做！</p><p></p></div><hr><div class="diary-entry">15:05 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQA9Z4HXNP2YTTKF2W572REE" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>乱投简历呢投着投着发现有个岗位要求做安全审查检查，也就是检查你这个人有没有被信任到可以接触国家机密。</p><p>思考了一番，最后决定「管你呢，先投再说」，然后投上了简历。</p><p></p><blockquote class="diary-thread-reply">17:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQAJPA2N0D25MMFSM3ZX1RHW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我服了朋友给我出歪点子让我想办法去搞个残障证明，比如说证明自己有心理疾病，这样好找工作 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​</p><p></p></blockquote></div><hr><div class="diary-entry">15:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQAA87G7GFGPDTFPQNYNG98H" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p></p><blockquote><p>Are you able to perform the function of the job with or without reasonable accommodation?</p></blockquote><p>What? If I said <em>Yes</em>, you wouldn't offer me <em>reasonable</em> accommodations?</p><p></p><blockquote class="diary-thread-reply">15:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQAAD0YHYCDHQ0S84GMFEGMH" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Bruhhh didn't realize this phrase is asking <em>do you have a disability that our company has to pay extra for</em>.</p><p></p></blockquote><blockquote class="diary-thread-reply">16:48 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQAFWFNW2K5PQJWA8SKK3KBT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Now we get:</p><blockquote><p>Do you trust in Christ alone for the forgiveness of your sins?</p></blockquote><p>Is this necessary during a job application?</p><p></p><blockquote class="diary-thread-reply">17:00 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQAGH4P14P3VP9369BYEXB55" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>I don't object to anyone's belief in any religion. It doesn't matter to me. I don't care about it. It just feels off to me when a random job asks if I would like to attend a weekly devotional meeting inside the company.</p><p>I know what I would get if I said <em>Yes</em>, which is another thing that makes me sad. A friend of mine is willing to fake joining a religious organization to get a job or customers. Well yeah I can pretend to be religious too, which is something I was forced to do in my past. I mean I already got baptized, what could be worse? But lying is lying; I don't like lying; I don't like talking about religion anymore. But I also hate the feeling of being jobless and anxious.</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">04-30 04:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQEASV1RG066JK36380AB3VW" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>What the fuck is:</p><blockquote><p>If you live 3 blocks away from a carwash, is it better to walk or drive?</p></blockquote><p>Why does this question matter in the first place during a job application?</p><p></p></blockquote></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">就业焦虑相关。</summary>        <div class="diary-cw-content">16:23 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQAEEDB8RK235908PFJZG8EC" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>唉，申请工作的同时，看到对方快速拒绝我，会反思到底是哪里做得不够好。之前说的许多话，也有甩锅的意味儿在吧，因为我无法百分百确认被拒绝是肤色（用中文说「种族」还是太奇怪了）、性别、没有内推，还是自己的简历真的没有竞争力 —— 但我又经常纳闷儿：不应该啊，这简历看着还行吧，该包装的包装好了，也就没有白字 prompt 叫 AI 审查放我过的字眼儿而已。</p><p>身边同专业的朋友们都在焦虑，一边申请工作一边在做粉领工作养活自己 —— 技术硬、从名校出来的又怎样！现在市场已经不需要我们了吧！</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">就业焦虑相关。</summary>        <div class="diary-cw-content">16:42 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQAFGMX4N8A7CK5EFB4CNY61" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>妈的才发现过滤器里有「实习」。我没事找实习干嘛，现在能找实习生的不都是找便宜牛马的初创公司？初创公司干活太难受了，头头儿也多数是「不找到最完美的人选就不行」的家伙儿。</p><p></p></div>      </details></blockquote></div><hr><div class="diary-entry">21:29 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQAZYPFH63WRRRNBBXADP1MD" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>舒适的桌椅很有必要。家里的桌子椅子根本就不是给人正常使的，会习惯性地用别扭的姿态窝在椅子上。办公室的桌椅使用笔记本电脑就很舒服，自觉地坐直也不会难受。</p><p>写字的时候要挺直腰哦！</p><p></p></div></details><details data-group="diary_sections"><summary>四月二十九日</summary><div class="diary-entry">03:41 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQBN8EERXFEH8XFRX8FQ0NQ9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>学校旁边开了家日本超市，里面卖自称「老酸奶」但根本不是老酸奶的玻璃瓶北京酸奶，以及日本生可乐。</p><p>我喝了日本生可乐，身上并没有长满滨州，滨州也没有发亮，更是没有多个嗨。好失望喔。</p><p></p></div><hr><div class="diary-entry">05:47 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQBWEDWE6C9V6HVQJ5YV106P" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>撸匹克猫头的时候不得不感叹，猫的头真的好小，感觉两只手就能将其轻易压碎。</p><p>也不清楚是室友养猫就会养成这样，匹克猫跟她以前养的一只猫都是小头大肚腩，有时候看上去很不协调。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">《悪いがわたしは百合じゃない》可能剧透相关。</summary>        <div class="diary-cw-content">09:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQC8DQY6KMFT1BZ5MJQDDTY1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>维护一些破东西的期间重新刷了遍《悪いがわたしは百合じゃない》。一次性看完的好处就是观感也很流畅吧，人物也能记住了。这作者特别喜欢在漫画里塞各种各样的角色…… 像假面洛基这种长得很特别的就算了，还有些长得很路人的角色，追连载时就完全记不住……</p><p>转型后女主变化是真的大，明明前期就跟人渣一样。后期的人设能理解为什么大家都喜欢围着她转。</p><p>羽根井真的好可爱啊。另一个我很喜欢的傲娇女角色是《ナカノヒトゲノム【実況中】》里的更屋敷花凛。傲娇角色在表面「傲」的情况下尽量地「娇」，是我很喜欢的一个二次元萌点 —— 相反，「傲」太多的话我会觉得很烦。</p><p>然后很想吐槽的是，这个作品里的女角色战斗力也太强了些…… 警察抓小偷篇国中生、高中生被专业杀手连着攻击了数次、飞踢了数次，好像一点事儿都没有。这总不能是体育生导致的吧！</p><p></p></div>      </details><blockquote class="diary-thread-reply"><details class="diary-cw">        <summary class="diary-cw-warning">RE: 《悪いがわたしは百合じゃない》可能剧透相关。</summary>        <div class="diary-cw-content">12:24 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQCK4HG533GTHZZD8EH8WXG1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最新一话自己啃了生肉：这是什么？什么叫同时交往？为什么？为什么要做这样的事情？哎？最后要和三个人一起交往吗？可以不要画这样的剧情吗？我会很难过的。</p><p></p></div>      </details></blockquote></div><hr><div class="diary-entry">10:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQCB8J2MYTKZJ7TGPVHFSXAZ" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3JFVK5MMZKAR9F2K4H1QW.png" alt=":neocat_googly_drool:" loading="lazy">​ 终于把密钥轮换完了，睡觉！</p><p></p><blockquote class="diary-thread-reply">19:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQDAYXETW8WE4R866GKHTJG6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>结果身体感觉很疲倦，胃部还很难受…… 真不应该熬夜，但又是很紧急的事情。</p><p></p></blockquote></div><hr><div class="diary-entry">18:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQD7EJKTHNC8HGVFRH9ZHR5D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>快暑假了，FIT 的美术生都在学校的墙上作画，应该是他们的毕设吧。等他们画完，我再来拍几张照片好了。</p><p>看到别人画画，也会想要画画呢。但是现在眼高手低的，不仅没有过去的想象力，也没有过去的产能 —— 应该说是丧失了对画画的兴趣吧。如果小时候的自己知道的话，肯定会打死现在的我的。</p><p></p></div><hr><div class="diary-entry">20:06 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQDDK1FF8M2WD2C0YVAXFPH9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>日本語のクラスで「老害」や「エイジズム」についてプレゼンテーションがありましたので、浅野いにおさんの『TEMPEST』という漫画を紹介したいです。</p><p></p></div><hr><div class="diary-entry">20:14 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQDE1K2YMGHHAYAR9HWM7A1N" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有时候来学校图书馆自习，会忘记带手机的充电线。这时候就会想要一边用笔记本电脑「多贴纸」（是名字！）干活一边播放音乐。作为好像是重度 Emacs 用户的我，选择在 Emacs 上安装了 empv 和 subsonic.el：前者只要有 URL 就能播放，后者则是会连接上我 Navidrome 的 API。不过目前这个新配置还是有点小 bug，慢慢修复吧。</p><p>再就是之前用 yt-dlp 搓的下载 YouTube Music 里音乐的命令行工具，总是下载下来元数据很奇怪的文件，例如 jomm 的歌每首歌的作者都不一样，导致无法随机播放他的所有歌曲。</p><p></p></div><hr><div class="diary-entry">20:55 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQDGCD46HFZE4370YDM1MAR4" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想要学习中文课教授的说话风格，慢悠悠的，但是稳重有力，尤其是他读文的时候。到我读文时，会因为紧张、语速不自觉加快。实际上听同样语速快的同学们读文，会觉得很难受。</p><p></p></div></details><details data-group="diary_sections"><summary>四月三十日</summary><div class="diary-entry">01:06 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/955271028373607068" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Mimi and Lucky.</p><p> <a href="https://pixelfed.feddit.social/discover/tags/cat?src=hash" title="#cat" class="u-url hashtag" rel="external nofollow noopener">#cat</a> <a href="https://pixelfed.feddit.social/discover/tags/dog?src=hash" title="#dog" class="u-url hashtag" rel="external nofollow noopener">#dog</a></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/31410d826-759a86/jd82L5tNjMKX/Uvs54tHEwUIUeunAvSoQKEyOr4CsyODMbDOqVeUu.png" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/31410d826-759a86/Pc7j1dIH6L1j/jLt0l4dsP4jIs7BQUxnqtOz9cOAH9RmRufZGiuQF.png" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/31410d826-759a86/EPOIIHRJmNTt/dcxk2OWSxSL7vmHWOMDFZqcKqGWlZC78ZtRb3QuI.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">01:34 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQE0CPWKYWXQNHA7W09MGP2D" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>MIMI 的歌已经到了听一下就知道是他写的情况，也不知道是好是坏。</p><p></p></div><hr><div class="diary-entry">14:22 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQFC99VBG9D2GB2R79DEWN9V" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这几天身体状况很奇怪，本来昨天凌晨就在通宵干活，肠胃也有点问题。不知道是不是因为突然开始摄入大量的蛋白质，我长期以来一直在吃碳水的身体无法立即适应（我是碳水大王），身体像是积食了，也有胀气的状态在 —— 胀气就不知道是为什么哩，总不能是做奶油意面时放的牛奶吧。</p><p>吃完早上的剩饭，胃部虽然有点鼓但明显不够，因为一整天严格意义上来讲只吃了一顿饭的量…… 最后喝了两碗粥躺床上去了。睡前照旧投简历，已经完成了基本指标的一半，但感觉前途灰暗呢……</p><p></p></div><hr><div class="diary-entry">15:13 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQFF7SPC8VK4SY06KRS0SY76" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前不久看店的时候进来一个熟客，然后跟他聊了会儿天。说是聊天，其实更像是他单方面在「教育」我。本来是打算写篇文章的，但怎么写都没法写出想要的效果来，暂且先把故事细节放到 Fediverse 上来好了。</p><p>故事要从他十几年前工作的沙龙店里开始讲起。店里的老板据他所说，是个除了日本人外什么人都会歧视的日本老头。但这也不代表着他对日本人就会好：将人从日本以学生 visa 的形式运来美国，让他们以 4 美元每小时的工资给自己打工、偿还他们的债务。吃喝住行上，也是老头负责。这相当于这批日本人一旦违逆他，在美国根本活不下去，不仅要被遣返，也要偿还大量债务。</p><p>客人的肩膀上有着旧伤，尽管能够做好工作，但在速度上依然无法入老头的眼。老头当着他的面，以糟糕的语气用他听不懂的日语和店内的其他日本人说话。他知道老头是在羞辱他，感觉被歧视、瞧不起，愤怒间便拿起沙龙店里的工具砸在地上，说「你现在可以开除我，但要是出了这道门，我们没有任何关系，我就会弄死你！」</p><p>他向我解释道，就算他住在 Bronx 这样的 ghetto 地区，也不代表他是 ghetto people. 工作就是工作，不要不尊重其他想要生存下去的人啊。当时的他刚成年吧，换句话说「什么都没有」。敢招惹「什么都没有」的人，他认为是老头的愚昧。</p><p>结果是他没有受到任何惩罚，反而可以继续在沙龙店内工作。经理允许他去其他分店工作，也可以在老头不在的时候来事发分店工作。明明辱骂了老板，却什么惩罚也没有。老头当时的反应，也只是闭上嘴巴不说话。</p><p>他说，很多人在成长期间缺乏「管教」，尤其是在美国。未成年踩在父母头上并不少见，这在他的国家以及亚洲是少许发生的：因为父母会把孩子揍一顿。</p><p>对话期间，他说，看到问题却不修复、纠正，最终这个问题会像滚雪球一般、祸及我们或者身边的人。像 karma 一样。</p><p>作为家庭暴力的受害者之一，我无法完全赞同他说的话。明事理儿的父母去教训有着坏心思的孩子，我会觉得没问题，因为缺乏管教而长大后祸害他人的家伙儿我也没少见，甚至也深受其害。但是这世上又有多少明事理儿的父母呢？因为发泄情绪而打孩子，并不少见。我也不是棍棒下出来的孝子，反而更像是头「白眼狼」，还未成年时便躲到了其他人的家里，现在更是鲜少回家，未来也不想要去为父母做什么 —— 有时候会反思自己是不是邪恶的，因为还是会想要来自父母亲的爱吧，不知不觉会忘记过去的遭遇。</p><p>我于这段对话中并没有花费过多的精力，因为他更像是我说什么都会表示反对、尽管我说的内容我认为和他说的没什么两样。我做事情也更喜欢逃避，于是我说，「我太年轻了，不会想到那么远。」他回，「当事情发生在你身上时，你就会意识到。所以要多看、多用脑子去想周遭的一切。」</p><p>最后是人们到底有没有责任和义务去修正「问题」呢？比方说，夜晚回家路上有流浪汉在跟踪你 —— 如果你问我为什么女孩子家家要走夜路，我的回应会是「那我一辈子待在家里、不要工作好了！」问题不在于「我走夜路」，而是「有人跟踪」，不是么？晚上和室友聊到这件事，她说这个人明显对自己的武力很自信，但我的话，软弱无力，还是不要冒风险更好。比起我为了正义而让自己陷入危险之中，她更希望我能活得好好的。</p><p></p></div><hr><div class="diary-entry">16:39 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQFM5PSRWM8K4HA6KRX1TC14" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>后知后觉国内五一有放假、是黄金周，所以大家都去旅游了，Board 上也都是旅游相关的内容。</p><p>我要哭了 ——！</p><p></p></div><hr><div class="diary-entry">20:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQG0FVS5EJ2SQCAT89NBHAB7" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy">​ 幸运狗被我父亲剃光毛啦 ——！</p><p></p></div><hr><div class="diary-entry">20:20 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQG0SAVPQP72JVQ0VTER60W3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我觉得咪咪猫很可爱啊，死室友怎么会觉得它丑 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3EQQJ0WWJ5EQ79NS9AMS5.png" alt=":neocat_angry:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">20:26 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQG14AXWEVD29WERBMFM8CG9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>下载了些 FLAC 格式的音乐，听的时候发现，我的硬件可能根本不够展现出有损压缩以及无损压缩的区别 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3M8KH0WA908PA858VD8FK.png" alt=":neocat_nervous:" loading="lazy">​ 总之就当满足自己的强迫心理，以及支持原作者了。</p><p></p></div><hr><div class="diary-entry">20:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KQG319E8PQMM61QX79D9M7WX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>为什么会有外放的短视频，还是循环播放，还是多部手机一起…… 一个在「什么洗发水泡沫什么什么都不曾关心山里的什么什么」，另一个在「如果有人千里迢迢来到你的城市只是为了见上你一面，这种人光是遇见就已经是上上签。成年人的世界什么什么什么」—— 烦死了！</p><p></p></div></details></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;好吧，看上去我把上个月的一些条目错误地放在了另一个 Org Mode 文件内，并把它们忘在了那儿…… 所以本次月刊会有一些上个月就该有的内容。&lt;/p&gt;</summary>
    
    
    
    <category term="想法迭代" scheme="https://blog.cytrogen.icu/categories/%E6%83%B3%E6%B3%95%E8%BF%AD%E4%BB%A3/"/>
    
    
  </entry>
  
  <entry>
    <title>入坟编写 SVG</title>
    <link href="https://blog.cytrogen.icu/posts/794.html"/>
    <id>https://blog.cytrogen.icu/posts/794.html</id>
    <published>2026-04-22T04:00:00.000Z</published>
    <updated>2026-07-06T21:52:06.970Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我先前的个人主页，是用简单的 SVG 代码一个个画出来的。因为是简单的图形，所以画一个出来没什么问题，但要是画很多的话…… 最终我决定，这种做法太累人了，乖乖手绘吧。</p><p>不过点进来之前，我需要事先说明下：这不是一篇教学文章！</p><span id="more"></span><hr><p>现在你可以访问 <a href="https://cytrogen.icu/">我的个人主页</a> 看到首页的风格变了。目前绘制完毕且托管的只有首页和电话（我很喜欢电话的设计），我花了很多时间来将图片转换成 SVG 代码 —— 是的，这不是一张图片，而是 SVG 代码。</p><p>通常不靠手搓（也没人会这么做吧！）画出复杂矢量图形的方式有可视化矢量图形编辑器，比方说 Adobe Illustrator，也是我高中学习使用的。可惜现在毕业、根本没有免费的 Adobe Illustrator 供我使用，我也早就忘了如何使用这类软件，所以可视化矢量图形编辑器只能被我残忍 pass 掉。</p><p>至于矢量图形、SVG 代码是什么 —— 如果你抱有这样的问题的话，那说明你还没有读过这篇文章的 <a href="/posts/a778.html">前文</a> 吧！快去看看吧~</p><p>我的方案是直接在 Procreate 这类绘画软件上画完整张图，然后用 Potrace 将位图图形转换成矢量图形 —— 我太聪明了！快来实现吧！</p><p>原理一句话能说完，但凡事都是说起来简单做起来难啊。我和 agent 进行了很多研究和探索，因为我对图形文件的理解还是不到位的，总之最后还是成功地将画转换成了可互动的 SVG 代码。下面我会简单说说我的方案。</p><h3 id="工具选型"><a class="markdownIt-Anchor" href="#工具选型"></a> 工具选型</h3><p>在深入流水线之前，先介绍三个主角。整条管线是三个工具协作完成的，它们各自的定位值得先说清楚。</p><p>一、ImageMagick。</p><p>ImageMagick 是一套命令行图像处理套件，也是 Unix 世界最全能的光栅图处理工具。它的核心机制是 <code>magick</code>，支持几乎所有你能想到的位图操作：格式转换、裁剪、旋转、颜色量化、阈值化、合成模式、滤镜、通道操作、巴啦巴啦…… 而且都能在一条命令里用管道式参数链接起来，不需要读文件、写中间产物再读回去。</p><p>这个流水线里几乎所有「位图到位图」的操作都交给 ImageMagick 来做。替代品可以是 Python 的 PIL / Pillow，或者 OpenCV，但是一条 <code>magick</code> 命令能干的活，真的要选择去写十几行代码吗？</p><p>二、Potrace。</p><p>Potrace 是位图矢量化工具，也是 FOSS 世界里事实上的标准。Inkscape 的 <em> Trace Bitmap</em> 功能底层用的就是它，很多商业软件也把它当作矢量化引擎。</p><p>它的定位很清晰：接受一张二值位图（只有黑白两色，连灰色都没有），输出一个 SVG、EPS，或者 PDF 文件，里面则是用贝塞尔曲线描述的路径。</p><p>算法管线分为三步：先找出所有黑白边界的像素链，再把像素台阶拟合为多边形，最后把多边形顶点转成三次贝塞尔曲线。</p><p>三、Python。</p><p>脚本最终我决定使用 Python 来写。用其他语言写也完全没问题啦，只是我对 Python 更熟悉一些（JavaScript 是什么东西，不熟）。</p><h3 id="作画与导出"><a class="markdownIt-Anchor" href="#作画与导出"></a> 作画与导出</h3><p>为了防止有读者听不明白，我决定讲讲电子作画时的基础概念和知识 —— 不过真的会有不懂的人来看这篇文章么？总之先讲 <u>图层</u> 吧！图层是一张张透明的画布叠在一起，每层画不同的东西，最终看到的画面是从上往下看穿所有图层后的视觉合成。每一层都可以单独修改、隐藏、换顺序而不影响其他层 —— 这自然给作画带来了巨大的灵活性。更关键的是，图层是有顺序的：上面的层会盖住下面的层。</p><p>我的方案严重依赖图层这个概念。每个物品都有自己的图层，例如大门是一个图层，城墙是在这之下的另一个图层。这一步是有讲究的：整条管线的每一次追踪都是「单图层对单掩膜」，如果你把所有元素合成到一张图再导出，后面就没办法单独给城堡添加悬停效果，或者让某一棵树动起来。</p><p>接着需要将图层以 PNG n 的格式一一导出，千万不要把背景图层导出来。我把它们全部丢进一个 <code>transparent/</code> 目录，命名成 <code>layer-01.png</code>…… 数字就是图层的叠放顺序，01 在最底层，例如背景的天空，数字大的则在上层。</p><p>这里还得解释一个概念：PNG 的透明度是怎么存的？每张 PNG 实际是四通道数据：R（红）、G（绿）、B（蓝）、A（alpha，即不透明度）。RGB 三个通道大家想必耳熟能详了，是对颜色的描述，而 alpha 描述的是这个像素有多透明：0 是完全透明，255 是完全不透明，中间值自然便是半透明了。</p><p>用电子软件作画时，我们时常会看到笔刷的边缘有着 <u>羽化</u>。它就是 alpha 从 255 平滑衰减到 0 所形成的软边，看起来让我们的笔刷柔和上去不少。</p><h3 id="单层处理流水线"><a class="markdownIt-Anchor" href="#单层处理流水线"></a> 单层处理流水线</h3><p>每张 PNG 都要过一遍以下流程才能变成一组 <code>&lt;g&gt;</code> 元素：</p><ol><li><p>检查是否是空图层。</p><p>我用 ImageMagick 把每个图层的 alpha 通道单独提取成灰度图，然后计算平均的亮度：<code>magick layer.png -alpha extract -format "%[fx:mean]" info:-</code>。</p><p><code>%[fx:mean]</code> 是 ImageMagick 内置的像素表达式引擎，<code>info:-</code> 让结果走 stdout。</p><p>返回值是 0.0 到 1.0 之间的浮点数。用我实际的数据来说：天空层约 0.48，即占画面一半都是不透明的像素；白色小鸟的那层约 0.003，小小的；空白的图层为精确的 0.0。如果 alpha 平均值小于 0.0001，即几乎全透明，那这个图层就是空图层，要被跳过。</p></li><li><p>硬阈值化 alpha 值：<code>magick layer.png -alpha extract -threshold 50% alpha.bmp</code>。</p><p><u>阈值化</u> 是把连续灰度映射成二值的操作。你会选择一条分界线，高于它的像素变白、低于它的变黑。阈值化的产物叫作二值图，是图像处理里最简洁的形式，也是很多算法的强制输入要求，包括我们马上要用的 Potrace。</p><p>回到命令，我用 <code>-threshold</code> 参数把所有大于等于 50% 亮度的像素变成纯白，其余变成纯黑。然后输出成 BMP3 格式，也是 Potrace 唯一无损保证能读的格式。</p><p>这么做的原因在于 Procreate 的笔刷有抗锯齿羽化边，边缘像素的 alpha 值从 255 平滑衰减到 0，可能中间横跨了 5 到 10 个像素的宽度。这些半透明的像素在后续合成中不能说没有用，只能说用处太大了，把我合成出来的东西全都搞砸了！</p><p>具体会怎么「搞砸」呢？后面要给每个颜色造掩膜时，会用到 alpha 去裁剪真实的形状。如果 alpha 是羽化带，乘起来得到灰度 76 的中间值，Potrace 看到灰度就会把它当成实心区域来追踪。结果是每一个色块外围都会被绕出一圈轮廓，不仅翻倍了文件体积，还在视觉上糊成一坨坨。</p><p>所以需要提前将它们合并。50% 是我认为较为舒服的值，实际上你可以随意调整。阈值化会让边缘变有锯齿状，但后续 Potrace 的贝塞尔平滑会把台阶拟合回曲线，反而比羽化边更干净！</p></li><li><p>量化颜色，即把连续色阶压缩成 N 色：<code>magick layer.png [-blur 0xR] -colors N +dither quantized.png</code>。</p><p><u>量化</u> 的意思是把一个连续范围压缩成若干个离散的层级。在颜色量化里，我们把原图里成千上万种颜色减到 N 种，每个像素替换成 N 色里距离最近的那个。这是有损操作，但对我们的矢量化来说恰恰是必要的。因为只要把颜色阶梯化，我们才能划分出明确的色块边界。假设原图是一片渐变的云，量化会把它切成几个色阶带，每个色阶带才能被 Potrace 追成一条边界清晰的 path。</p><p>我用 ImageMagick 的 median-cut 量化器，按照 RGB 颜色空间里最长的轴切分像素的分布，直到得到 N 个聚类。</p><p>我建议是每个图层都手动调整下 N 的值，因为自动估算对艺术风格并不敏感，需要人类的介入、指出一个图层里到底该有多少种颜色。我的部分配置表：</p><pre><code class="language-python">LAYER_COLORS = {    1: 1, # 纯色的天空    2: 4, # 月亮 + 星星    3: 15, # 带有窗户的塔顶    8: 6, # 树    12: 10, # 上半墙    20: 15, # 城门}</code></pre><p>纯色图层给 1 就足够了。复杂图层能给到 15，让它能同时容纳石头灰阶和橙色光斑。</p><p>另外，误差扩散抖动得关掉（<code>+dither</code> 里的 <code>+</code> 是 ImageMagick 约定的「关闭」前缀，对标 <code>-dither</code>。怎么感觉应该反过来哩？），否则两种邻近颜色的像素散点会多出第三种颜色。在位图显示上，它是好看的，但对矢量化是毁灭性的 —— 每个散点都会变成一种独立的 <code>&lt;path&gt;</code>，SVG 体积又更上一层楼，视觉上还花花的。</p><p>可选的 <code>-blur 0xR</code> 是对笔刷纹理特别重的层先做高斯模糊，把颗粒糊掉再量化。我只对城门那层用了它。</p></li><li><p>列出实际用到的颜色并去重：<code>magick quantized.png -alpha off -unique-colors txt:-</code>。</p><p>量化时限制了图层中最多出现 N 种颜色，但如果原图的色阶数小于 N，那实际用到的会更少。我们要的是真正出现了的颜色，必须挨家挨户造掩膜追踪。</p><p><code>-unique-colors</code> 会生成一张 1×N 的像素图，每个像素是一种颜色。<code>txt:-</code> 把它以 IM 的文本格式 dump 到 stdout，长这样：</p> <pre><code class="language-plaintext">0,0: (28,29,48)  #1C1D30 srgb(28,29,48)                                  1,0: (18,18,36)  #121224 srgb(18,18,36)   2,0: (132,70,11) #84460B srgb(132,70,11)                      ...                                       </code></pre><p>用正则 <code>#([0-9A-Fa-f]{6})</code> 把十六进制色值抠出来。</p><p>接着还需要合并一次，因为笔刷纹理可能产出视觉上一样但数值差 1 到 3 个颜色对（比如 <code>#47475B</code> 和 <code>#47475C</code>），会在后续的转换中产出很多几乎同色的 <code>&lt;g&gt;</code> 颜色，白白浪费浏览器的渲染资源。</p><p>合并策略很简单：如果两个颜色的 R、G、B 每个通道差值都小于某个阈值（我给城门设的是 15），判定为重复，只保留第一个。</p></li><li><p>为每种颜色构造二值掩膜。一共是两条命令链。</p><p><u>掩膜</u> 是图像处理里的万用工具！简单来说，它是一张告诉后续操作哪些像素该保留、哪些该忽略的黑白图。典型的约定是白色等于保留，黑色等于忽略，不过有的工具会反过来，所以用任何工具之前都要先看文档。你可以把掩膜想象成是剪纸。把这张剪纸叠在原图上，黑的地方剪掉、白的地方留着。上色的时候很有用喔！</p><p>首先是要生成目标色和其余色的掩膜：<code>magick quantized.png -alpha off -fuzz 3% -fill white -opaque "#COLOR" -fill black +opaque white BMP3:raw.bmp</code>。</p><p>拆解下来是：<code>-fuzz 3%</code> 给 <code>-opaque</code> 设一个 3% 的颜色匹配容差（因为量化 + BMP 往返可能让颜色偏差 1-2 单位，精确匹配会漏掉边缘像素），<code>-fill white -opaque "#COLOR"</code> 把所有接近目标色的像素刷成白色，<code>-fill black +opaque white</code> 再把所有「不是白色」（<code>+opaque</code> 是 <code>-opaque</code> 的反操作）的像素刷成黑色。</p><p>先前的 <code>-threshold</code> 仅是按照亮度切分，无法精确匹配 RGB 值，使用 <code>-opaque</code> 可以正确的按照颜色切分。</p><p>接着是要用 alpha 把掩膜裁回真实形状：<code>magick raw.bmp alpha.bmp -compose Mulitply -composite -negate BMP3:final.bmp</code>。</p><p>这里涉及到 <u>合成模式</u> 的概念。合成模式决定了两张图怎么叠在一起。最常见的是 Normal，就是上层完全覆盖下层啦。还有：</p><ul><li>Multiply：两张图对应像素值相乘再除以最大值；</li><li>Lighten：对应像素取较亮值；</li><li>Screen、Overlay、Difference…… 因为本篇不会用到，所以就不过多讲解啦。</li></ul><p>上一个命令链的问题在于，原本透明但颜色恰好匹配背景默认值的像素也可能变成白色，所以要用 alpha 掩膜做交集、把「透明但被误标白色」的区域切掉。Multiply 在二值图上等价于布尔 AND：255 乘以 255 等于 255（白），255 乘以 0 等于 0（黑），0 乘以任何等于 0。</p><p>不过我们这里是把白色弄成了目标色，和 Potrace 把白色当成要被忽略的背景色的约定不同，需要用 <code>-negate</code> 反转一下。最终 <code>final.bmp</code> 里目标色区域是黑的，其余是白的 —— 这才是 Potrace 想要的输入。</p></li><li><p>Potrace 追踪：<code>potrace final.bmp -s --flat -t TURDSIZE -o path-COLOR.svg</code>。</p><p>终于到我们的 Potrace 出场了。</p><p>三个参数：<code>-s</code> 输出 SVG（否则默认是 EPS），<code>--flat</code> 输出扁平的 <code>&lt;g&gt;</code> 而不是嵌套结构，<code>-t 10</code>（turdsize）丢弃包围像素数小于 10 的孤立斑点。turdsize 可以用来降噪。</p><p>输出长这样：</p><pre><code class="language-xml">&lt;svg ... viewBox="0 0 238.8 149.3"&gt;  &lt;g transform="translate(0,1493) scale(0.1,-0.1)" fill="#000000" stroke="none"&gt;                     &lt;path d="M21483 14869 c-191 -100 -354 -221 -431 ..." /&gt;  &lt;/g&gt;&lt;/svg&gt;           </code></pre><p>那个诡异的 <code>translate(0,1493) scale(0.1,-0.1)</code> 变换乍一看像 bug，其实是 Potrace 的签名：它内部用 10 倍定点整数坐标做贝塞尔计算（提升精度、避免浮点误差累积），所以 path 里的数值都是 ×10 的；同时它使用数学坐标系 Y 轴朝上，而 SVG Y 轴朝下。所以 <code>scale(0.1, -0.1)</code> 会做两件事：一、除以 10 还原坐标、Y 方向翻转；二、<code>translate(0, 1493)</code> 把翻转后跑到负象限的图形平移回可见区域（1493 是图像高度）。</p></li><li><p>抽取 <code>&lt;g&gt;</code>，塞入正确的 fill 颜色。</p><p>我们已经得到了轮廓，接下来只需要把第 4 步的真实颜色放到 <code>&lt;g&gt;</code> 里就好了！Potrace 默认输出 <code>fill="#000000"</code>，得替换掉。</p><p>建议使用正则来做：<code>&lt;g transform="([^"]*)"[^&gt;]*&gt;(.*?)&lt;/g&gt;</code>。抓到 <code>transform</code> 的值和内部 <code>&lt;path&gt;</code> 内容，重新拼装成 <code>&lt;g transform="..." fill="#COLOR" stroke="none"&gt;...&lt;/g&gt;</code>。</p></li></ol><h3 id="对比度方案"><a class="markdownIt-Anchor" href="#对比度方案"></a> 对比度方案</h3><p>有一些复杂的图层，例如在暗色的背景上有着更暗的细节，像砖块和城墙的颜色。如果按照全图颜色分布切分的话，砖块会消失的。解决方案是完全绕开全局量化，改用两次独立的阈值化跟 Potrace。我下面简称该方案为对比度方案。</p><p>详细对比的话，对比度方案的流程需要通过局部亮度的阈值来决定哪些像素是同一块。如果图层里有细节只占 10 灰阶跨度，而全图跨度有 250 灰阶，那么细节在原先的量化器看来是噪音、可以被合并进主体色。而局部亮度的方案中，小差异就可以被放大成可切分的对比。</p><p>至于为什么是两次阈值化，因为一次需要追整块形状，一次追纹理细节即可。对比度方案的本质是让图层变成只有两个亮度群的画面，即「主体」和「细节」。再多分几次没有意义，反而可能将笔刷的噪点切出来。砖墙就是「墙」和「砖」两个元素，不需要再增加。</p><p>不过该方案需要手动填写图层需要什么颜色，因为它终究只是产出黑白两色的二值掩膜。这一步可以用 ImageMagick 从原图采样平均色，可能产生误差，所以建议是用吸色器直接吸、手动填写。我的配置表长这样：</p><pre><code class="language-python"># (基础色, 细节色, 阈值%, 是否反转)             CONTRAST_LAYERS = {   9:  ("47475C", "030205", 50, False),  # 鸟：身体 + 黑眼                       12: ("1C1D30", "121224", 30, False),  # 上半墙：底 + 砖缝                    17: ("24273D", "0F1021", 60, False),  # 左箭头：底 + 暗点   19: ("18182E", "0F1023", 80, False),  # 下半墙：底 + 砖缝                          22: ("0D0F1E", "1E2035", 40, True),   # 电话亭：暗体 + 亮屏}</code></pre><p>整条对比度流程的关键命令是： <code>magick layer.png -alpha off -colorspace Gray -auto-level -threshold T% BMP3:thresh.bmp</code></p><p>四个操作逐一解释：</p><ul><li><code>-alpha off</code> 忽略透明通道，否则透明像素会干扰后面 <code>-auto-level</code> 找最小最大值；</li><li><code>-colorspace Gray</code> 用 ITU - R BT.709 加权公式把 RGB 转成单通道灰度：=Y = 0.2126・R + 0.7152・G + 0.0722・B=。之所以加权是因为人眼对绿色最敏感，对蓝色最不敏感。对比度方案关心的是明暗差异不是色相差异，转灰度把我们关心的维度独立出来；</li><li><code>-auto-level</code> 是整个方案的「魔法」。它找到当前图像的最小灰度 vmin 和最大灰度 vmax，对每个像素执行 =new = (old - vmin) / (vmax - vmin) × 255=，即把现有灰度范围线性拉伸到 [0, 255]。举个例子：上半墙层原始灰度分布是 [5, 55]，跨度 50。auto-level 之后变成 [0, 255]，跨度 255。墙和砖块原本相差 10 灰阶，拉伸后相差 51 灰阶，已经足够用阈值干净切开；</li><li><code>-threshold T%</code> 把灰度 ≥ T 的变白，&lt; T 的变黑。T 的选值要根据该层 auto-level 后的灰度分布手调。我的上半墙选 30%（刚好只切出最暗的砖块），下半墙选 80%（这层纹理更模糊，要把阈值线放更高才能吃到所有砖块），电话亭选 40%。</li></ul><p>阈值化后如果该层是 <code>invert</code> True=，还要追加一个 <code>-negate</code>。电话亭是特殊情况 —— 它的细节（屏幕、按键、听筒）比底色更亮而不是更暗。默认的「暗变黑」规则只会把底色抠出来，但底色已经追过一次了；<code>-negate</code> 反转灰度后，原本亮的像素变暗、被阈值判为黑（前景），Potrace 追的就是细节而不是底色。</p><p>接着要用 alpha 把透明区强制变成白色，防止透明区被误认为前景： <code>magick thresh.bmp ( alpha.bmp -negate ) -compose Lighten -composite BMP3:detail_mask.bmp</code></p><p>这里用 Lighten compose 而不是 Multiply。Lighten 的语义是对每个像素取两张图的较亮值。两个输入：thresh.bmp（细节二值化结果，前景是黑）和 alpha.bmp 取反（原不透明区 = 黑，原透明区 = 白）。四种情形：</p><table><thead><tr><th>原 alpha</th><th>threshold 结果</th><th>alpha 取反</th><th>Lighten 结果</th><th>含义</th></tr></thead><tbody><tr><td>不透明</td><td>黑（细节）</td><td>黑</td><td>黑</td><td>细节保留</td></tr><tr><td>不透明</td><td>白（非细节）</td><td>黑</td><td>白</td><td>正确忽略</td></tr><tr><td>透明</td><td>黑（误判）</td><td>白</td><td>白</td><td>透明区救回来</td></tr><tr><td>透明</td><td>白</td><td>白</td><td>白</td><td>正确忽略</td></tr></tbody></table><p>第三行是关键 —— 不管阈值怎么错判，只要原来是透明，白色就压过去了。换成 Multiply 效果会完全相反 —— 不透明区会全部被乘成黑，灾难。原本方案的 Multiply 和对比度方案的 Lighten 在数学上是 de Morgan 律的对偶，不是随便选的，取决于中间数据里「黑白哪个代表有效」。</p><p>剩下的步骤和原本方案一样：Potrace 追踪、抽取 <code>&lt;g&gt;</code> 、塞上配置里写的十六进制色。</p><p>对比度方案每层会产出最多两个 <code>&lt;g&gt;</code> —— 一个基础形状（从 alpha 掩膜追来）、一个细节形状。比原本方案 N 个 <code>&lt;g&gt;</code> 要少得多，这也符合「这一层概念上就两个元素」的直觉。</p><h3 id="混合方案"><a class="markdownIt-Anchor" href="#混合方案"></a> 混合方案</h3><p>而更为复杂的图层中，例如上半城堡墙既有暗底和砖块，又有高饱和的橘色窗户，只是量化的话砖块会消失，走上一段提到的对比度追踪又会弄丢窗户，因为窗户灰度落在阈值之上，会被判成背景。</p><p>解法是两条路都跑，然后把产物叠起来。我把这两个麻烦的图层（上半墙、下半墙）标记成 <code>HYBRID</code>：</p><pre><code class="language-python">HYBRID_LAYERS = {12, 19}if layer_num in HYBRID_LAYERS:    groups = process_layer(layer, ...)  # 正常量化    groups.extend(        process_layer_contrast(layer, ..., detail_only=True)  # 对比度    )</code></pre><p><code>detail_only</code> True= 是关键。正常的对比度方案会先从 alpha 追一次基础形状；但在混合方案里，正常量化那边已经把底色当作最大占比色给追过了，如果对比度再追一次，两个完全重叠的同色 <code>&lt;g&gt;</code> 会造成 over-draw 和抗锯齿边缘错位闪烁。<code>detail_only</code> 让对比度方案跳过基础形状追踪，只贡献细节层。</p><p>最后 <code>&lt;g&gt;</code> 列表的顺序是：</p><ol><li>量化产物的底色 <code>&lt;g&gt;</code> （整层轮廓）</li><li>量化产物的橙窗、亮边等 <code>&lt;g&gt;</code> （点缀色块）</li><li>对比度产物的砖块 <code>&lt;g&gt;</code> （纹理）</li></ol><p>SVG 渲染是 <u>画家算法</u>，后写的盖在前面。叠出来的视觉效果是：深紫蓝的墙打底，上面点缀橙色窗户，最上面叠一层更深的砖块纹理，正好是原画的层次。如果把对比度放在量化之前 <code>extend</code>，砖块会被底色完全盖掉。</p><h3 id="最后组装"><a class="markdownIt-Anchor" href="#最后组装"></a> 最后组装</h3><p>每层处理完都会返回一个 <code>&lt;g&gt;</code> 列表。主循环把所有图层的产物按图层编号顺序拼接成一个大列表，然后套一个 <code>&lt;svg&gt;</code> 外壳：</p><pre><code class="language-python">svg = f'''&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="{viewbox}" width="800" height="500"&gt;{"".join(all_groups)}&lt;/svg&gt;'''</code></pre><p><code>viewBox</code> 从任意一次 Potrace 输出里抓出来（所有层尺寸相同，共用一个）。<code>width</code> 和 <code>height</code> 是默认显示尺寸，CSS 可以覆盖。</p><p>图层编号顺序就是叠放顺序：layer-01（天空）产出的 <code>&lt;g&gt;</code> 在列表最前，画在最底；layer-22（电话亭）产出的 <code>&lt;g&gt;</code> 在最后，画在最顶部。</p><p>最终 SVG 我直接内联粘贴进 <code>index.html</code>，而不是用 <code>&lt;img src="castle.svg"&gt;</code>。外部 SVG 没法被外部 CSS 样式化（比如给某层加悬停颜色），也没法被 JavaScript 操作里面的 <code>&lt;g&gt;</code> —— 内联之后就随便了。是不是很有意思呢？</p><h3 id="之后"><a class="markdownIt-Anchor" href="#之后"></a> 之后</h3><p>个人主页的重构会花费一些时间，因为现在我可以手绘、用更简单和省力的方式在网页里添加元素，例如首页中的城堡我参考了《喜羊羊与灰太狼》中「狼堡」 的设计（好啦根本一模一样）。我后续决定添加更多有趣的内容进去，比方说下一个我打算重绘的 /death 页面，就会出现一些游戏元素，像《植物大战僵尸》啦。</p><p>再就是个人主页在不同设备上的显示。我希望所有设备都能访问个人主页，展示的不同没有关系。我发现部分博友会在浏览时关闭 JavaScript，而我主页上有些页面使用了 JavaScript。我会尽我所能将 JavaScript 从主页上剔除，除非是必须使用 JavaScript 的功能，那我会想办法将内容以别的形式展示出来。SVG 以及更新的 CSS 语法同理 —— 总之不要出现那种「不开启 xx 功能或者没有 xx 就不能看」的问题吧！</p><p>虽然话是这么说，但其实也想过在主页上添加解密要素。不使用 JavaScript 的话，应该会滥用 LocalStorage 吧……？到时候再说，到时候再说。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我先前的个人主页，是用简单的 SVG 代码一个个画出来的。因为是简单的图形，所以画一个出来没什么问题，但要是画很多的话…… 最终我决定，这种做法太累人了，乖乖手绘吧。&lt;/p&gt;
&lt;p&gt;不过点进来之前，我需要事先说明下：这不是一篇教学文章！&lt;/p&gt;</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="SVG" scheme="https://blog.cytrogen.icu/tags/SVG/"/>
    
  </entry>
  
  <entry>
    <title>观《八号出口》</title>
    <link href="https://blog.cytrogen.icu/posts/f8cc.html"/>
    <id>https://blog.cytrogen.icu/posts/f8cc.html</id>
    <published>2026-04-22T04:00:00.000Z</published>
    <updated>2026-04-22T22:34:20.495Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>四月份有我明面上的生日。至于为什么是「明面」上的，那就去问当年给我办户口的人吧！总之，影院送了我生日礼物 —— 一桶爆米花和一杯饮料，直到月底都可以随时领取。因此我一直想要在四月份和别人一起去看部电影，把礼物领了。</p><span id="more"></span><p>原先考虑到的分别是 35 周年重播的《沉默的羔羊》，但不吃任何折扣，两个人总计 40 美元，太贵了；《迈克尔・杰克逊》感觉不错，但室友好像兴趣不大；其余我想看的儿童向电影室友都不想看，唉。最终在一次意外搜索中发现，AMC 上映了《八号出口》。</p><p>继续之前，我还是要说一遍，不想要被剧透的请不要阅读这篇文章。</p><h2 id="电影前"><a class="markdownIt-Anchor" href="#电影前"></a> 电影前</h2><p>我对原作游戏有一定的了解，是「找异常」游戏的鼻祖，也导致了独立恐怖游戏里一时出现了大量类似玩法的游戏。原作作者也做过同类型的续作《八号站台》。</p><p>看电影之前，我记错了时间。原本 10 点的电影，我记成了 10 点半。因为电影播放前还会有 20 分钟到半小时的广告时间，我们出发的时间更晚一些，路上还吵了一架。实际上看到电影的时候，应该是电影播放了 20 分钟之后。事后我们快速查看了网上别人做的解说，发现错过的这 20 分钟里有许多恐怖、惊悚的桥段…… 实在是不应该错过啊。</p><h2 id="电影中"><a class="markdownIt-Anchor" href="#电影中"></a> 电影中</h2><p>电影的音效很厉害，在营造压抑的感觉上做得很好。中间有一段是男主角接到了「女友」的来电，向她哭诉自己对电车上的带娃女人无动于衷的样子，根本不是个未来爸爸该有的样子。他向前哭着走去，转弯后发现打来电话的「女友」也是异常的一部分。绝望、恐慌，什么负面情绪都涌现了出来：他先是愤怒地摔了包，接着哆哆嗦嗦爬向墙、吐了出来，然后呼吸困难地倒在地上。这里电影配上了警笛般的背景声，很不错。</p><p>另一个我很喜欢的设计是男主角的视角是如何转变到「行走的男人」的视角的。对于了解游戏的我来说也很震惊，电影竟然描述了这个 NPC 大叔的故事。说到大叔，不得不提他的演技很厉害，将一个已经陷入绝望、但无法主动在男孩面前表现出来的长辈样子表演得淋漓尽致 —— 从头再来的时候，他先是胡乱将身边能破坏的东西破坏了一遍，尖叫着「我要去见我的儿子啊」，然后察觉到现场还有小孩子在，于是蹲下腰、僵硬地露出微笑，向他道歉道，「对不起，吓到你了吧」。我很喜欢这一幕的表现力。</p><p>作为游戏改电影，我本对它没有过多的期待，因为我上一部看的游戏改电影是《世界计划：无法歌唱的初音未来》，完完全全粉丝向的电影……《八号出口》没有将原作游戏的内容放在最重要的位置，反倒更像是借游戏的规则，讲了另一个故事。这种做法是有争议性的，我看到部分打差评的影评就是认为这「另一个故事」他们不感冒，是基于原作作品的「强行上价值」。</p><p>制作方实际想要讲的，是评判日本社会常见的「异常」。例如明明看到带着孩子的妈妈在被上班族骂，却没有一个人施以援手，全都盯着手机在看。这种异常，却没有人发现，就像是游戏里的玩家，不停在往前走，每每都卡在第 0 层、无法找到真正的出口。</p><p>逃出 8 号出口的男主角先是给女友打了通电话过去，说他会立马赶过去，并在车厢上遇到了最初他遇到的情况 —— 一个上班族在痛骂一个妈妈带婴儿来坐车，而婴儿的哭啼声吵得他不爽。实际上，婴儿不会因为叫他闭嘴、就会住口不哭的。上班族不知道这件事吗？我不见得，只是在借「婴儿很吵」这件事、宣泄自己的怒气罢了。另一个我很好奇的事情，就是日本的车厢是真的不能有一点声音的吗？但这是题外话了。</p><p>开头男主选择了戴上降噪耳机、和所有人一样无视了这场单方面的言语施暴。而结尾，男主盯着前方，最终朝着上班族的方向转过去身 —— 影片结束。</p><p>说到男主角的改变，必须要谈谈这个无尽的走廊对男主角而言到底指的是什么。除了对被侮辱的妈妈视而不见外，他开头还从女友那儿得知女友怀上了自己的孩子，但不敢去承担当父亲的责任。这些都是男主角的心结，他迷茫、不知道该怎么办。</p><p>卡在循环中无法离开时，他与一个男孩相遇 —— 在电影中的许多场景里都揭示了，他是男主角的儿子。在遇到洪水异常时，男主角将他高高托起、任由自己被水流冲走。此时男主角完成了在同理心上的成长、愿意去承担父亲的责任。</p><p>所以整个游戏对男主角来说，都是心理上的历练。他最终走出了循环，也解开了自己的心结，不仅决定去找生下孩子的女友，还在车厢上帮助了被侮辱的妈妈。</p><h2 id="电影后"><a class="markdownIt-Anchor" href="#电影后"></a> 电影后</h2><p>看完电影后，我和室友持有相反的意见。在我觉得还挺不错的情况下，她认为这部电影根本不好看，还是她讨厌的恐怖片 —— 这是我的错吧，我没有好好说明白「找异常」类型的游戏都是恐怖游戏。</p><p>但我也得说明白，《八号出口》更像是一部小小的佳作，而不是「神作」。我很难说我会不会去推荐别人观看这部电影，总之我自己看着喜欢就好了吧！</p><p>我接下来想要看的电影还有《玩具总动员 5》，以及想要和另一位朋友看的恐怖电影 <em> Obsession</em>、和恐怖电影有关的喜剧电影《惊声尖笑 6》。至于《沉默的羔羊》，我打算把父母家里不用的投影仪带过来，用线上资源观看。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;四月份有我明面上的生日。至于为什么是「明面」上的，那就去问当年给我办户口的人吧！总之，影院送了我生日礼物 —— 一桶爆米花和一杯饮料，直到月底都可以随时领取。因此我一直想要在四月份和别人一起去看部电影，把礼物领了。&lt;/p&gt;</summary>
    
    
    
    <category term="影评" scheme="https://blog.cytrogen.icu/categories/%E5%BD%B1%E8%AF%84/"/>
    
    
  </entry>
  
  <entry>
    <title>观《河狸变身计划》</title>
    <link href="https://blog.cytrogen.icu/posts/fd71.html"/>
    <id>https://blog.cytrogen.icu/posts/fd71.html</id>
    <published>2026-04-22T04:00:00.000Z</published>
    <updated>2026-04-22T21:24:12.889Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>实际上，我今天没有看《河狸变身计划》。今天我看的是《八号出口》，前者我是在四月一号看的，但最近才想着去写个影评出来。</p><span id="more"></span><p>先前两次影评我都说过了，不想要被剧透的人就不要看，这次也一样。不过这次想要多说一句：我的影评文章更多是我在看完电影后，想到了什么，有时候可能和原片的关联并不大。</p><h2 id="电影前"><a class="markdownIt-Anchor" href="#电影前"></a> 电影前</h2><p>去年 <a href="/posts/7240.html">看《疯狂动物城 2》的时候</a> 我就注意到了这部电影：画风实在是太可爱了！后来我才知道，设计上有点点的作者的参与 —— 点点是条可爱的小狗蛇；它的创作者是动画师「yogin 幺菁」。</p><p>电影前，我看到了专门给影院设计的广告，里面有 Chuck E. Cheese 的。正常来说，大家说到 Chuck E. Cheese 都会想到儿时来这种游戏厅玩乐的时光。当然，要是你去过的话。但我受 FNAF 系列影响，再加上前段时间刚看了 FNAF 电影的第二代，每次看到都会想到吉祥物恐怖作品。</p><p>2024 年 Chuck E. Cheese 推出了会员制，每个月要支付 8 美元，每天能得到 40 游戏积分，买吃的还有优惠，很适合暑假的时候把小孩子丢到这种游戏厅里，让他们肆意乱跑。可惜我家附近没有 Chuck E. Cheese。</p><p>小时候对 Chuck E. Cheese 很有好感，因为它家的披萨很好吃。现在已经很多年都没有看到过 Chuck E. Cheese 了，不知道它现在是怎么个处境。</p><h2 id="电影中"><a class="markdownIt-Anchor" href="#电影中"></a> 电影中</h2><p>说回《河狸变身计划》。在看这部电影之前，我就看到了许多骂它烂的视频，所以在看之前，我对这个电影带有负面印象。</p><p>实际上，看完后我发现电影想要讲的和网上的视频里所说的，根本不是一回事，甚至是完全相反的观点。这让我怀疑这些人到底有没有看进去，还是听到个「环境保护」的关键词便肆意攻击。</p><p>作为儿童向商业电影，《河狸变身计划》的可爱画面以及透露出的社会问题，已经足够及格 —— 话虽这么说，它的问题依然很多，其中让我最在意的是电影对反派 Titus 的塑造。</p><p>和《疯狂动物城 2》的设计一样，这位反派最终展现出来的是疯狂的样子，而正方最终要做的，仅仅是打败这个脸谱化的疯子。尤其是打败的方式还相当滑稽，稀释掉了前面铺垫的矛盾，最终看到的只有虎头蛇尾的收场。</p><p>和 Pawbert 不同，Titus 并没有背负什么主题或者问题，如果「蝴蝶没有人类强大」算主题的话…… 好像也不是不行，「弱小的生物试图成为更强大的生物」，或者「一心只为了王位的暴君其实也有脆弱一面」——！但电影看上去并没有打算展开描写这些，所以就当它们不是吧。</p><p>我说的「最终要做的」，指的是正方确确实实花费了精力去做，且制作方想办法去刻画的事情。打个照面就解决的「问题」不是问题，仅仅只是套路罢了。电影里就有许多这样的套路，令人失望。不论是女主 Mabel 和 George 之间第一次冲突，还是结尾 Mabel 和 Jerry 之间的冲突，都是这样。</p><p>然后是反派的存在目的。电影的主题是「共存」，但后期明显丢掉了该主题，让一切变成了为了感官体验、为了爽的二元制「对抗」，也就是变得非黑即白了。Titus 的出现到落幕，都是制作方想要在电影中添加一个纯粹的恶、纯粹的敌人 —— 接着又在他彻底发疯之前透露出他母亲死后孤独的一面，好似在说他不一样，但实际上依然和常见的疯子反派没有区别。</p><p>归根结底，《河狸变身计划》让我不满的是，它明明让许多社会问题浮出水面，但处理起来过于儿戏。难道只要解决了有问题的人，那问题就被解决了吗？同样，解决冲突就很儿戏，让整部电影更适合不带脑子看。</p><p>关于电影的主题，我并不认为它是个讲环保的故事，环保不需要提倡，重点是「身份」：人作为动物的一员，能不能以人类的标准去干预自然环境？</p><p>既然人类是动物，是自然的一员，那人类的所有行为在广义上是不是都可以被视为自然演化的结果？那故事中建高桥、破坏环境，是不是自然界中常见的强势物种对弱势物种的压制和利用？</p><p>但事情根本不是这么运转的。人类掌握着游离于生物本能之外的技术力量，早就打破了整体内部的平衡。像破坏环境，也不是为了控制猎物数量去做的，而是为了让高速公路可以快几分钟。这种话你讲给动物听，它还要问你「高速公路」是啥哦，一种没见过的鹿吗。</p><p>为什么电影让 Mabel「成为」仿生河狸，并用河狸的身份去帮助动物们？这是为了贴合「整体」，让女主融入到整体中。但电影在主题上的问题也随之而来：女主就算成为了仿生动物，她的思维是动物的思维吗？她不仅在以人类的思维去考虑事情，也无法理解动物们的规矩，甚至就算死了，也不过是机械身体被摧毁，人依然还活着。</p><p>电影的结尾是好结局，Mabel 想要保护的地方依然存在，高桥被建去了别的地方。可是，这一切都要源于她选择变成动物。尽管电影中经常有角色表示「不要人为干预自然环境」，但是这个好结局不正是 Mabel 人为干预才有的吗？制作方究竟是提倡人为干预，还是反对呢？</p><h2 id="电影外"><a class="markdownIt-Anchor" href="#电影外"></a> 电影外</h2><p>我在看完电影后也看了个影评，大致内容讲的是《河狸变身计划》很棒地展现出了现实生活中的极端组织是如何从「正确」一步步走向疯狂的：动物保护、环境保护组织，现在每每谈起都会想起他们做过的坏事儿和蠢事儿。既然这么坏、这么蠢，为什么组织里依然有人为此着魔，组织外的人还很难拿他们有办法？</p><p>因为他们认为自己是「正确」的，是「正义」的一方。既然我已经是正确的了，那要解决我所担忧的事情，应当是当务之急的。所以我认为其他人必须赞同我，谁不赞同就是反对动物保护或者环境保护。</p><p>像我先前提到的，<strong>没有人会反对环保</strong>。保护环境本就是为了更好的世界，也是为了人类的生存环境可以更好。可一旦目标上的高尚被用于掩盖手段上的越界，极端组织也就垄断了道德的「解释权」—— 打上引号是因为，站在「正确」的立场不意味着做什么就真的都可以被容忍、原谅了。</p><p>近期和 Fediverse 上的朋友聊到了「以正义之名宣泄恶意」。在我们的语境里，背景是互联网。例如在一个娱乐性质更多的互联网圈子内，比如特定游戏的圈子吧，路人甲发表了「不对」的言论，或者做了「不对」的事情。因为触及到了圈子的规则，因此路人甲被其他人声讨、开户、查在互联网上的任何蛛丝马迹并对此进行侮辱…… 因为路人甲是「坏人」，所以这么做是「正义」、「正确」的吗？</p><p>人是复杂的，不是扁平的。我可以像个正人君子一样在这里胡说海说，但也可以拥有很混蛋的一面。这不影响别人去赞同我的部分观点，同时反对我的另一部分观点。因为这不是简单的二元制，所以实际理解且实践起来要困难一些。</p><p>最常见的做法是因为路人甲做了错事，所以我要否定他整个人。同理，也可以因为声讨路人甲的路人乙做了「对事」，所以神化他、视他为「神明」—— 这样做一定又会因为路人乙做了不合大众胃口的事情，而被贬低成猪狗不如的东西。因为你无法确认路人乙是真的想要伸张正义，还是想要发泄恶意、发现了路人甲这么个可以被随意辱骂的沙包。如果是后者的话，路人乙的「恶意」自然会随着时间被围观群众挖掘出来。</p><p>好像这样的事情，每天每天都在发生，不腻一样。</p><p>我过去还是个很「网络」的人的，会使用很多社交平台，尤其是国内的社交平台。渐渐地，我越来越不想要在社交网络上留下公开的足迹，因为总是会出现一些莫名其妙的言论，让我觉得很烦，其中最不乏针对我所在国家的评论。</p><p>因为我所在的国家不一样，所以我有了「美国 IP」的标签。这标签将「我」压缩成了单一的片面符号，比方说「美爷」、「富哥」，但明明我根本就没那么有钱，甚至人生的很多时候是贫穷的。</p><p>标签的存在是为了大幅降低理解的成本。它同样也有好处，可以让陌生人们快速亲密起来，但这不在我想要谈论的范畴内。</p><p>因为贴标签不需要消耗过多的心智，所以只要给事物打上「正义」或者「邪恶」、「保护着」或者「破坏者」的烙印，人们就可以心安理得地放弃思考、理直气壮地宣泄情绪。关于标签化的问题，我过去在写「强奸者」和「被强奸者」的 <a href="/posts/5c85.html#%E6%A0%87%E7%AD%BE%E7%9A%84%E5%B1%80%E9%99%90%E6%80%A7">文章</a> 里也有提到过。</p><p>尽管近些年逐渐有民众发现标签化不好的一面，但它依然没有结束，反而变得更加隐蔽且坚固。人与人之间的共识变得愈发廉价，沟通也变得不可能。想要维持真实的自我，在如今这个时代倒是成了种奢侈……</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;实际上，我今天没有看《河狸变身计划》。今天我看的是《八号出口》，前者我是在四月一号看的，但最近才想着去写个影评出来。&lt;/p&gt;</summary>
    
    
    
    <category term="影评" scheme="https://blog.cytrogen.icu/categories/%E5%BD%B1%E8%AF%84/"/>
    
    
  </entry>
  
  <entry>
    <title>了解 Kagi 的历史</title>
    <link href="https://blog.cytrogen.icu/posts/c2db.html"/>
    <id>https://blog.cytrogen.icu/posts/c2db.html</id>
    <published>2026-04-04T04:00:00.000Z</published>
    <updated>2026-07-06T21:52:06.970Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>上个月我在 <a href="https://store.kagi.com/">Kagi Store</a> 上下单了 Kagi 的 T 恤衫、袜子周边。不为别的，Kagi 的吉祥物设计很可爱，画风很独特。</p><p>不过在搜寻时我发现了这个 Hacker News <a href="https://news.ycombinator.com/item?id=40011314">链接</a>，也迫使我不得不去探索 Kagi，这个大概被我神话过头的公司。</p><span id="more"></span><p>首先我必须 <a href="/posts/e3b9.html#kagi:~:text=%E7%9C%BC%E5%B0%96%E7%9A%84%E6%9C%8B%E5%8F%8B%E4%BB%AC%E6%88%96%E8%AE%B8%E5%8F%91%E7%8E%B0%E4%BA%86%EF%BC%8C%E6%88%91%E4%B8%80%E4%BC%9A%E5%84%BF%E8%AF%B4%20Kagi%EF%BC%8C%E4%B8%80%E4%BC%9A%E5%84%BF%E8%AF%B4%20Kagi%20Search%20%E7%9A%84%E3%80%82%E8%BF%99%E6%98%AF%E5%9B%A0%E4%B8%BA%EF%BC%8CKagi%20%E5%9C%A8%E6%9C%AC%E6%96%87%E5%86%85%E6%8C%87%E7%9A%84%E6%98%AF%E8%AF%A5%E5%85%AC%E5%8F%B8%EF%BC%8C%E8%80%8C%20Kagi%20Search%20%E6%98%AF%E5%85%B6%E5%90%8D%E4%B8%8B%E7%9A%84%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E%E6%9C%8D%E5%8A%A1%E5%90%8D%E7%A7%B0%E3%80%82%E5%A6%82%E6%9E%9C%E6%88%91%E5%8F%AA%E6%98%AF%E6%83%B3%E8%AF%B4%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E%E7%9A%84%E8%AF%9D%EF%BC%8C%E5%8F%AF%E4%BB%A5%E7%9B%B4%E6%8E%A5%E4%BD%BF%E7%94%A8%20Kagi%E3%80%82%E4%B8%8D%E8%BF%87%E6%88%91%E6%83%B3%E8%AE%B2%E7%9A%84%E6%98%AF%20Kagi%20%E7%9A%84%E4%BA%A7%E5%93%81%EF%BC%8C%E4%B8%8D%E5%8D%95%E5%8D%95%E6%98%AF%E6%90%9C%E7%B4%A2%E5%BC%95%E6%93%8E%E4%B8%80%E4%B8%AA">再度</a> 说清楚，我所说的 Kagi 不单单只是个搜索引擎，而是一个公司（Kagi Inc.）。不过这么说也不准确，因为 Kagi Inc. 这个实体于 2022 年 3 月份才成立，而团队开始捣鼓 Kagi 的 AI 产品早在 2018 年便有记录（见 <a href="https://help.kagi.com/kagi/company/history.html">Kagi 历史</a>），甚至早过 2019 年 Kagi Search 的原型产品。</p><p>Kagi 这家公司太小了，以至于 Wikipedia 都没有 Kagi Inc. 的条目，只有同名为 Kagi、实际上在产品线中叫作 <em> Kagi Search</em> 的搜索引擎产品。要了解 Kagi Inc.，只能慢慢从不同年份的博客文章中找出各种蛛丝马迹了…… 没关系！我 <a href="/posts/2590.html">隐私条款</a> 都读过，还怕你个博客文章！</p><p>总之先从 <a href="https://en.wikipedia.org/wiki/Kagi">Wikipedia</a> 开始吧。Wikipedia 上写了什么并不重要，重要的是它所引用的参考资料，以及开头所写的「这篇文章可能过度依赖与主题密切相关的来源，从而导致条目内容缺乏可验证性和中立性」。稍微看一下参考资料就会发现，许多确实是来自 Kagi 网站自己的文章。</p><p>好吧，那我们先读一下 Kagi 自己如何评价自己。在 <a href="https://help.kagi.com/kagi/company/">Kagi 的关于页面</a>、<a href="https://help.kagi.com/common/company/history.html">Kagi 历史</a>，和 <a href="https://blog.kagi.com/what-is-next-for-kagi#3">2024 年 Kagi 的一篇文章</a> 里我们得知，它的历史发展可以划分为四个阶段：</p><p>一、技术探索与试错。</p><p>Kagi 由 Vladimir Prelovac 于 2018 年 5 月在美国加州的帕罗奥图市创立。最初的四年里，公司完全由 Prelovac 自筹资金，大约是 300 万美元。</p><p>早期的 Kagi 并没有直接去做一个完整的搜索引擎，而是将重心放在了 AI 和问答技术上。这一点可以查看被存档下来的 <a href="https://web.archive.org/web/20241129140750/https://kagi.ai/">kagi.ai</a> 网站。所以你要说 Kagi 是一家 AI 公司，也大差不差吧！这也反映了未来 Kagi 有许多 AI 产品的原因。不过那可是 2018 年，当时的 AI 产品指的还是 Siri 呢！</p><p>总之当时的 Kagi 认为未来的搜索引擎必须具备强大的即时问答能力，这倒是和现在大家使用生成式 LLM 聊天机器人的方式差不多：问问题。</p><p>在这个阶段，Kagi Search 的第一个原型也诞生了，用的是命令行模式，还挺符合 MVP 开发逻辑的。<a href="https://orionbrowser.com/">Orion 浏览器</a> 的早期原型也一起出现了。</p><p>关于 Kagi Search 的原型体，感兴趣的可以见：</p><ul><li><a href="https://blog.kagi.com/last-mile-for-web-search">https://blog.kagi.com/last-mile-for-web-search</a></li><li><a href="https://vimeo.com/754908681">https://vimeo.com/754908681</a></li><li><a href="https://vimeo.com/754899234">https://vimeo.com/754899234</a></li></ul><p>他们还尝试建立高级搜索业务 <a href="https://donna.gg/">Donna.gg</a>，不过失败了。</p><p>二、底层研发与内侧。</p><p>接着疫情来了。Kagi 的团队规模翻倍达到 10 人。他们在 2020 年到 2021 年的期间将早期的技术积累转化为实际的产品，即进入了封闭 Beta 内测阶段的 Kagi Search 和 Orion 浏览器。</p><p>三、商业化验证与公测。</p><p>2022 年 3 月 4 日，Kagi Inc. 正式注册成立。同年的 6 月份，搜索引擎和浏览器进入公测，并确立了「用户付费」的无广告商业模式 —— 太好了！而仅仅三个月后，就有数千名用户开始为这些产品付费。</p><p>2023 年是 Kagi 商业模式被验证的关键节点。这一年他们实现了 100 万美元的 <u>年度经常性收入</u>，证明了「人们愿意为优质且注重隐私的搜索付费」这一假设。同年，他们通过社区向 93 位天使投资人（也是他们的用户）筹集了约 250 万美元。</p><p>四、组织进化与生态扩张。</p><p>随着公司实现盈利，团队规模扩张至 40 人以上。在 2024 年，Kagi 推出了 Assistant、Translate 以及企业版服务。</p><p>更重要的是，在 2024 年初，Kagi 在法律事实上完成了商业实体的转变，成为了一家 <u>公共利益型企业</u>。</p><p>到 2025 年，Orion 浏览器也结束了 Beta 测试，并推出了隐私通行证等新功能。</p><p>大致的历史中便出现了一些商业术语呢，必须要讲清楚一下。</p><p>在理解 Kagi 的实体转变之前，我们得先厘清 <u>商业实体</u> 的概念。</p><p>简单来说，商业实体是法律在纸面上创造出来的拟制人，AKA 假人。当创始人开展业务时，如果不成立实体，所有的债务和法律责任都会由创始人个人承担。而成立了商业实体之后，公司就有了自己独立的法定身份，它可以拥有资产、签订合同、雇佣员工，并在法律上承担责任 —— 所以说有些人说自己最爱公司不是错的，它在法律层面上就是个人啊！</p><p>对于美国的科技初创公司而言，最常见的实体类型是 <u>特拉华州 C 型股份有限公司</u>。为什么要说「最常见」呢？因为我找不到 Kagi 最初注册时选的类型是什么。<a href="https://icis.corp.delaware.gov/ecorp/entitysearch/NameSearch.aspx">特拉华州公司检索系统</a> 会直接显示 <em> Benefit Corporation</em>，也就是 Kagi 之后才转变成的公司类型。所以我就默认它是 C 型公司吧。</p><p>C 型公司的核心特征在于其在法律和税务上的绝对独立性。它是一个独立于所有者（即股东）的法人实体。这种架构的最显著特点是，你要征两次税（哦不！）：公司本身需要为其产生的利润缴纳 <u>企业所得税</u>；当公司将税后利润以股息形式发放给股东时，股东还需要在个人层面缴纳个人所得税。</p><p>如果对股份感兴趣的话，我在今年一月份有简单 <a href="/posts/53f4.html#:~:text=%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%AC%E8%B4%A8%E6%98%AF%E4%BD%A0%E6%8B%A5%E6%9C%89%E4%B8%80%E5%AE%B6%E5%85%AC%E5%8F%B8%E7%9A%84%E4%B8%80%E9%83%A8%E5%88%86%E3%80%82%E5%AF%B9%E4%BA%8E%E4%B8%8A%E5%B8%82%E5%85%AC%E5%8F%B8%E8%80%8C%E8%A8%80%EF%BC%8C%E5%AE%83%E4%BB%AC%E9%80%9A%E8%BF%87%E5%87%BA%E8%AE%A9%E8%82%A1%E4%BB%BD%E6%9D%A5%E7%AD%B9%E9%9B%86%E8%B5%84%E9%87%91%E5%8E%BB%E7%A0%94%E5%8F%91%E5%92%8C%E6%89%A9%E5%BC%A0%EF%BC%8C%E5%9B%A0%E6%AD%A4%E5%8F%AF%E4%BB%A5%E8%A2%AB%E4%B8%80%E8%88%AC%E4%BA%BA%E4%B9%B0%E5%8E%BB%E3%80%82%E6%AF%8F%E4%B8%80%E5%B9%B4%E5%AE%83%E4%BB%AC%E9%9C%80%E8%A6%81%E6%A0%B9%E6%8D%AE%E8%B5%9A%E6%9D%A5%E7%9A%84%E9%92%B1%E9%80%89%E6%8B%A9%E5%8F%96%E5%A4%9A%E5%B0%91%E7%BB%99%E7%A0%94%E5%8F%91%E3%80%81%E5%8F%96%E5%A4%9A%E5%B0%91%E5%88%86%E7%BA%A2%E7%BB%99%E8%82%A1%E4%B8%9C">聊过</a>。不过当时的聚焦点主要是在股票市场上。这里再说一下：卖股票不意味着一定要在公开股票市场卖，还可以通过私募的方式出售股权。所以就算 Kagi 不是上市公司、你在股票市场上看不到 Kagi 的大名，它依然是有股东的。</p><p>继续说。C 型公司允许发行不同层级的股票，能够极为便利地进行股权融资、发放员工期权，所以尽管它存在着税务上的劣势，绝大多数初创公司依然会选择这种架构，天使投资人们也更喜欢它。</p><p>在这种架构下，公司董事会和管理层会受到一种被称为 <u>受托责任</u> 的严格法律约束。这种责任要求他们必须将「股东利益最大化」作为核心，甚至唯一的商业决策目的。比方说你得让公司有好看的财务报表、利润要赚得多多的……</p><p>顺带一提，这种责任的确立可以追溯到 1919 年著名的 <em> Dodge v. Ford Motor Co.</em> 案。</p><p>2024 年初，Kagi 的商业实体转变成了 <u>特拉华州公共利益型企业</u>。它和传统的 C 型公司的区别在于，它要求公司的董事和高管在追求股东财务回报的同时，比如兼顾特定的公共利益，以及其他利益相关者的诉求，比方说用户和社区！</p><p>这下你或许就会明白了。Kagi 的卖点本就是「不卖广告、不追踪用户数据、完全由用户付费」，那它要还是维持传统的 C 型公司结构的话，未来要是发展壮大了，可能就会面临巨大的法律和商业冲突。</p><p>举个例子，一家大型广告公司提出以极高的溢价收购 Kagi，如果有投资者指出「如果加入广告的话，公司的利润可以翻十倍」，那你在传统 C 型公司的法律框架下，你会拒绝吗？董事会如果拒绝这些能让股东利益最大化的提议的话，就有可能会面临股东的起诉哦。</p><p>那转变为公共利益型企业后，Kagi 就可以合法地对利润说「不」了，因为他们「致力于创建一个以人为本、可持续发展的网络」。</p><p>这同时也向付费用户，即我们，提供了一个法律层面上的保证，证明其永远不作恶、不卖广告。</p><p>而年度经常性收入（Annual Recurring Revenue，简称 ARR）是一项财务指标，主要用于评估订阅制业务或 SaaS 公司的收入表现。它衡量的是「公司在未来十二个月内，基于现有订阅合同可以合理预期的、稳定的经常性总收入」。</p><p>对于一个订阅制软件服务而言，100 万美元的年度经常性收入意味着企业已经拥有了可预测的现金流来覆盖基础研发和运营成本，且其商业模式能够在小规模的样本下跑通！</p><p>所以这串数字象征着，Kagi 成功打破了「搜索必须免费」的思维定势。</p><p>知道了 Kagi 在商业模式上的历史，接着来看看其技术方面上的历史吧。和 Google 不同，Kagi 并非一个像 Google 那样从零开始爬取全网的独立搜索引擎，而是一个 <u>元搜索引擎</u>，或者说是「搜索客户端」。</p><p>2023 年，Kagi 曾明确定义过自己的架构：当用户输入一个查询时，Kagi 会将这个请求分发给后端的多个信息源，然后将拉取到的数据进行清洗、重新排序，最后呈现给用户。这一段内容可以见 <a href="https://web.archive.org/web/20231228222303/https://help.kagi.com/kagi/search-details/search-sources.html">这个被存档的文章</a>。</p><p>它的信息源分为两类：一类是垂直领域的 API 接口，例如 Wikipedia、Apple Maps、Yelp、TripAdvisor 等；一类是最为核心的综合网页搜索索引。在早期，Kagi 明确标示了它对外部通用索引的依赖，包括 Google、Bing、Yandex、Brave 和 Mojeek。</p><p>怎么说呢，这样的架构就很…… 客户端。如果老板让我写个搜索引擎给他，估计我也会这么做。</p><p>进入 2024 年后，Kagi 不再公开列出其使用的传统搜索引擎来源了，这主要是因为两点：</p><ol><li>Bing 的 API 价格涨幅高达 10 倍（之后 2025 年还停用了 Bing Search API）</li><li>Google 不提供公开的搜索 API，除非使用广告联合分发包。</li></ol><p>这意味着，Kagi 失去了通过正规合同获取这两大巨头数据的合法路径。在一篇 2026 年的 <a href="https://web.archive.org/web/20260125151549/https://blog.kagi.com/waiting-dawn-search">被存档文章</a> 中，Kagi 承认道：「由于无法在兼容的条款下获得直接授权，我们和许多其他公司一样，使用第三方 API 提供商来获取 SERP 风格的结果（SERP 指搜索引擎结果页面）。」</p><p>这种方式是灰色的，因为第三方 API 供应商本质是在通过技术手段大抓特抓 Google 和 Bing 的搜索结果。再加上 2025 年年底 Google 还真的起诉了大型抓取服务商 SerpApi，侧面反映出了 Kagi 确实不该公开列出自己所使用的源。</p><p>所以我们也不知道 Kagi 的搜索结果具体都来自谁，不过根源肯定也会是 Google 和 Bing 就是了。</p><p>值得一说的是，这些 API 是按次计费的，是变动成本，而我们用户订阅 Kagi 是每个月支付固定的金额。这意味着，成本和收入是可以错位的，随之而来的隐患便是破产。</p><p>顺带一提 Kagi 也有自己的爬虫和索引系统，其中最核心的是针对 small web 的 Teclis。它的技术实现，很暴力：使用 Puppeteer 配合 uBlock Origin 来渲染网页。如果在加载网页时触发了 5 个以上的广告或者追踪器拦截请求，该网页就会被直接从索引中剔除。</p><p>随后 Kagi 会使用 Elasticsearch 和 Typesense 进行全文检索，结合自然语言处理模型进行语义向量搜索。</p><p>你已经对 Kagi 有一个大致上的了解了，现在让我们把焦点放在本次要回应的文章上吧！</p><p>lori 在 Kagi 的 Discord 频道中观察许久，基于这些观察，他提出了一些普通用户不会考虑到的点。由于这篇文章发布于 2024 年，所以一些东西可能是过时的：</p><p>一、T 恤衫事件。</p><p>先前说到 Kagi 在 2023 年筹集了约 250 万美元的社区资金，其中有 <a href="https://blog.kagi.com/safe-round">67 万美元</a> 是他们首次外部融资筹集来的。接着在 2024 年 1 月 24 日，Kagi 表示为了庆祝自己有了两万名付费会员，拨出了其中的三分之一，也就是 20 多万美元成立了一个全新的业务实体来生产，并免费分发这两万件 T 恤衫。</p><p>这让 lori 觉得很困惑：为什么要花这么多做这种事情呢？我也承认花这么多钱做这件事听上去有欠考虑。</p><p>但我对 lori 提到的这个「业务实体」更感兴趣：它叫什么名字？在哪里？真的有一个独立的仓库吗？因为你不能就 Kagi 的 <a href="https://blog.kagi.com/celebrating-20k">博客文章</a> 这么说了，所以相信他们成立了家商业实体。</p><p>商业实体的注册和成立，都是可以被查到的。证明这个实体是否存在，便成了我的首要目标 —— 我也很好奇嘛。</p><p>Kagi 在 2024 年 9 月份，也就是 Kagi Store 上线的时候发布的 <a href="https://blog.kagi.com/mountains-of-cotton">博客文章</a> 中提到：「我们并没有真的开一家 T 恤工厂。」所以 lori 文章中所说的工厂是绝对被夸大了的。</p><p>但我还是很好奇啊！没有工厂，不意味着商业实体不存在，对不对？为此我跑到多个德国的商业登记系统数据库内进行检索，结果发现唯一一个和关键词 <em> Kagi</em> 相关的公司是 Kagi Trade UG。但这是一家机械贸易公司，2021 年便成立了，和我们现在说的 Kagi 明显不是同一个。</p><p>这就很难办了。确实，Kagi 为发 T 恤衫设立的那个实体，名称不一定是 <em> Kagi</em>，高管也不一定是 Prelovac。那咋办呢？</p><p>我只能说，就像我们不知道 Kagi 的传统搜索结果来自哪个第三方服务商，我们也不知道 Kagi 到底有没有成立一个商务实体在德国 —— 好啦，我认为没有。如果有的话，早就被人翻个底朝天了，也轮不到我这个站在 2026 年的时间点的人指手画脚。</p><p>说回 T 恤衫本身。根据 2024 年 4 月 12 日 Prelovac 通过 Hacker News 对这篇文章的 <a href="https://news.ycombinator.com/item?id=40013592">回应</a> 中可以看出，他想要取悦用户社区。因为 Kagi 不做任何付费广告，能增长完全是依靠社区的口口相传。</p><p>我尝试用其他方式来为 T 恤衫辩解，最终只能想到「穿上它上街相当于免费为 Kagi 打广告」这一个说辞。那两万个用户到底想不想要这件 T 恤衫呢？我不得而知。我只能说它作为一个品牌的周边挺不错的，但我会更期待初创公司只花一点点钱，找些合作商定制马克杯、贴纸什么的送出去。</p><p>二、整整两年忘记缴纳销售税。</p><p>lori 认为 Kagi 有两年没有缴纳销售税很莫名其妙，以此怀疑 Kagi 当时的财务状况并不好 —— 呃，说实话，两年没有缴纳销售税，也没有听上去那么糟糕？因为我有许多客户有数年，甚至二十多年都没有缴纳销售税。原因通常是他们的税务师不负责任、没有把这件事情告诉他们。最后我们也只能让他们自首。</p><p>根据 Prelovac 在 Discord 中的截图，看上去也更像是他们没有意识到自己需要缴纳销售税这件事。也很符合我心目中一心只有技术的技术宅的刻板印象啦。其实我在搞公司之前，也对税务一窍不通，现在顶多是知道一些些。</p><p>税务这个东西我只能说，不懂的人是真的不懂，也会惹出许多笑话。但这并不是他们的错，义务教育里又没有教过美国人们税务知识，而会学习它们的多是 ego 比天还高的傻瓜税务师。这也是我们公司一直在想办法改善的问题，也在致力于帮助那些被不专业的税务师坑骗的人们 —— 咦，怎么开始推销了？</p><p>不单单是税务师，会计师、律师也有着同样的问题。自己不专业就算了，冷落自己的客户，然后搞出来的破事儿丢给客户自己处理。就算客户不知道、将事情都交给税务师处理，但如果被税务局查到、抓包了，依然是客户承担主要责任。</p><p>之后我阅读了 Prelovac 对 lori 文章的回应，即一个被 lori 公开在 <a href="https://web.archive.org/web/20240508204319/https://hackers.town/@lori/112255132348604770">Fediverse</a> 上的 <a href="https://web.archive.org/web/20240412070624mp_/https://d-shoot.net/files/kagiemails.txt">邮件串</a> 后得知，最初是 Prelovac 不知道付费搜索会被市场接受，所以早期就没搞。好吧，我以为你不知道呢！</p><p>三、AI 愿景与用户期待的严重错位。</p><p>这是这篇文章中最核心的技术冲突。</p><p>很多用户转投 Kagi，是为了逃离 Google 越来越臃肿的 AI 概括和 SEO 垃圾，他们想要一个老派、纯粹、只给链接的搜索引擎。</p><p>但我先前也说过了，Kagi 在 2018 年创立的第一天叫 <em><a href="http://Kagi.ai">Kagi.ai</a></em>。Prelovac 的终极愿景从来都不是做个复古的搜索引擎，而是做一个用 AI 帮用户总结的工具。</p><p>在这个终极愿景实现之前，Kagi 靠下放控制权留住了这些讨厌 AI 的用户，也就是用户可以在客户端层干预搜索结果，比方说拉黑特定内容农场。</p><p>这也解释了另一个问题：既然终极目标是 AI，为何 Kagi 还要花好几年时间做一个传统搜索页面呢？原因在于，早期大语言模型存在着严重的幻觉问题，Kagi 必须先打磨出一个具有高质量清洗、去重和过滤能力的传统搜索系统，以此作为未来 AI 产品的基座 —— 只要底层的信源足够干净，上层的 AI 总结才具备真正的可用性。</p><p>也就是说，Kagi 的技术策略是「表面做 A，实际为了 B」。这一点也体现在 Kagi 庞杂的产品线上。除了 Kagi Search 外，Kagi 显然想要做个互联网生态全家桶，涵盖了搜索引擎、浏览器、电子邮箱服务等我们平日会使用到的东西。lori 认为这些太多了，只做 Kagi Search 会更好。</p><p>事实上，在先前的 Hacker News 讨论串中也有很多人在当时认为是在浪费资源。比方说有个评论认为，Kagi 在和 Google 以及 Microsoft 竞争，将资源放在非核心产品的东西上都是在放弃。</p><p>不过 Kagi Search 真的是 Google 和 Bing 的竞品么？它们确实都是搜索引擎，但说是竞品实在是太高抬 Kagi Search 了。它的搜索来源真要追溯，不还是 Google 跟 Bing 吗？Kagi Search 只能算是元搜索客户端的一员罢了；根据现在的 <a href="https://kagi.com/stats?sub_stats=members">统计</a> 来看，其会员数根本不够格，才近 7 万而已。</p><p>说到 Kagi 其他的产品，我其实都有在尝试使用。比如 Orion 浏览器，我就安装了个在 iPad 上，来代替原先的 Edge 浏览器 —— 嗯，我在折腾 degoogle 和 demicrosoft 的时候把我的 iPad 给忘了。这个支持 Chromium 和 Firefox 插件的 Webkit 浏览器很有趣，我还在探索阶段。</p><p>我用的最少的是 Kagi News，因为我压根不怎么阅读新闻。其次是 Kagi Maps，它怎么说呢，没有导航系统意味着我很少会打开它，但是搜索地点还算不错，可以说是 Kagi Search 附带的地图功能。</p><p>至于 Kagi Assistant 嘛…… 我只使用过 Quick mode，更进阶的 Research mode 我没有打算付费使用。我使用过竞品 Perplexity，这种问答引擎找资料挺有帮助的，但产品类型并不是我会经常使用的。</p><p>如果 Kagi 真的要弄出一个互联网全家桶的话，我会不会使用是个好问题：我会放弃自己托管的邮件服务，改用 Kagi 邮箱么？不过当务之急的应该是，先让 Kagi Small Web 支持中文独立网络吧！</p><p>四、隐私观的本质分歧。</p><p>Kagi 是一家在美国注册的公司，这已经注定了其存储的隐私数据在美国政府面前不值一提。我在 <a href="/posts/2590.html">研究 VPS 服务商的隐私条款的文章</a> 中已经提到过了，在美国注册的实体，其数据无论存储在哪里都没有用，依然可以被美国政府够到。</p><p>GDPR 也不是那么神仙的存在：想要自己隐私安全的唯一办法就是，不要把自己的信息上传到互联网！</p><p>但是 2024 年的 Discord 频道截图中也可以看出，当时的 Kagi 团队对隐私权并不了解，甚至可以说是有点白痴了 —— 你的卖点是尊重隐私，但你表现出来的好像对隐私一窍不通？比方说「电子邮件地址不属于个人身份信息」、「世界上除了罪犯，极少有人需要真正的完全匿名」。唉，初创公司另一个难过的槛儿是公关问题啊。</p><p>不过当年的担忧，在 2025 年有了满意的 <a href="https://blog.kagi.com/kagi-privacy-pass">答卷</a>：Kagi 推出了 Privacy Pass 身份验证！也就是说，用户的付费账户身份和实际搜索行为在数学层面上彻底地切断了联系。紧接着 Kagi 还官方支持了 Tor 服务。</p><p>现在用户的搜索查询不再与包含邮箱的账户绑定，那么 Kagi 在处理搜索数据时，就几乎不再触及个人可识别信息。即使 Stripe 依然保留着用户的付款信息和邮箱，但只要这些信息无法与用户的搜索历史关联，隐私泄露的风险和法律合规的压力便大大降低了。</p><p>这篇文章也意外为 Orion 浏览器正了名。过去用户视其为不务正业，但文章中提到，由于 Safari 的技术限制，Privacy Pass 无法在 Safari 上完美实现。此时，拥有自己底层控制权的 Orion 浏览器的价值便体现了出来~ 可喜可贺，可喜可贺。</p><p>五、不要给我发邮件了！</p><p>在文章发布后，Prelovac 尝试通过电子邮件和 lori 联系上，以此来讨论这些事情，也就是先前我分享的邮件串。</p><p>lori 最初便表示了不想要和 Prelovac 有任何联系，也不想要和 Prelovac 沟通 —— 理由在文章的结尾写明了，他在 Discord 频道中已经知道了 Prelovac 是个什么样的人，所以无力去和他起争执。但是 Prelovac 依然向 lori 发送了对文章的回应。</p><p>电子邮件这样的沟通方式，因为会存储到对方的数据库内，所以并不静默。如果 Prelovac 只是在自己的博客上写了篇回应，那也真的还好啦，但明知对方不想要沟通的情况下，还是硬把观点塞给对方，这就是对对方的不尊重了。</p><p>至于我会不会因此讨厌 Kagi、不再使用 Kagi 的产品，那自然是不会的。因为 Kagi 是集体工程的产物，不单单是 Prelovac 个人的项目。需要将产品的使用价值与创始人的个人做派剥离开来。</p><p>但也就我先前常提到的，这是个「马后炮」的回应。在 2026 年的现在，Kagi 的一切看上去很不错：它已经不是个无法与创始人的个人特质解绑的初创公司了。</p><p>无论用户会选择继续支持，还是放弃 Kagi，都是他们自己的选择。这一点上，我和 lori 的观点是一样的。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;上个月我在 &lt;a href=&quot;https://store.kagi.com/&quot;&gt;Kagi Store&lt;/a&gt; 上下单了 Kagi 的 T 恤衫、袜子周边。不为别的，Kagi 的吉祥物设计很可爱，画风很独特。&lt;/p&gt;
&lt;p&gt;不过在搜寻时我发现了这个 Hacker News &lt;a href=&quot;https://news.ycombinator.com/item?id=40011314&quot;&gt;链接&lt;/a&gt;，也迫使我不得不去探索 Kagi，这个大概被我神话过头的公司。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="互联网" scheme="https://blog.cytrogen.icu/tags/%E4%BA%92%E8%81%94%E7%BD%91/"/>
    
    <category term="Kagi" scheme="https://blog.cytrogen.icu/tags/Kagi/"/>
    
  </entry>
  
  <entry>
    <title>想法在丙午蚕月迭代</title>
    <link href="https://blog.cytrogen.icu/posts/a4c0.html"/>
    <id>https://blog.cytrogen.icu/posts/a4c0.html</id>
    <published>2026-04-01T04:00:00.000Z</published>
    <updated>2026-04-01T22:30:53.703Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>本月的条目和内容依然不多。待税务季结束后我会重新花费精力在月刊上。</p><span id="more"></span><details>      <summary>本期导读</summary>      <h2 id="输入"><a class="markdownIt-Anchor" href="#输入"></a> 输入</h2><h4 id="商业与社会"><a class="markdownIt-Anchor" href="#商业与社会"></a> 商业与社会</h4><ul><li><a href="#%E8%AE%B8%E5%A4%9A%E4%BA%BA%E5%8F%A3%E6%95%B0%E6%8D%AE%E9%83%BD%E6%98%AF%E8%99%9A%E5%81%87%E7%9A%84">许多人口数据都是虚假的</a></li><li><a href="#%E5%A4%A7%E5%9E%8B%E7%A0%94%E7%A9%B6%E5%8F%91%E7%8E%B0%E9%9D%92%E5%B0%91%E5%B9%B4%E5%90%B8%E9%A3%9F%E5%A4%A7%E9%BA%BB%E4%B8%8E%E5%90%8E%E6%9C%9F%E7%B2%BE%E7%A5%9E%E7%97%85%E5%8F%91%E4%BD%9C%E4%B9%8B%E9%97%B4%E5%AD%98%E5%9C%A8%E8%81%94%E7%B3%BB">大型研究发现青少年吸食大麻与后期精神病发作之间存在联系</a></li><li><a href="#%E4%B8%89%E5%8D%81%E5%B9%B4%E4%BA%86-%E5%AE%9D%E5%8F%AF%E6%A2%A6%E4%BE%9D%E7%84%B6%E9%A3%8E%E9%9D%A1%E5%85%A8%E7%90%83">三十年了，宝可梦依然风靡全球</a></li><li><a href="#%E5%BE%AE%E8%BD%AF%E5%8F%97%E5%A4%9F%E4%BA%86-microslop-%E8%BF%99%E4%B8%AA%E7%A7%B0%E5%91%BC">微软受够了 /Microslop/ 这个称呼</a></li><li><a href="#%E5%9C%A8%E6%97%A5%E6%9C%AC%E5%AF%B9%E5%9D%91%E5%AD%A4%E7%8B%AC%E7%9A%84%E9%85%B8%E5%A5%B6%E9%85%8D%E9%80%81%E5%A5%B3%E5%B7%A5">在日本对坑孤独的酸奶配送女工</a></li><li><a href="#%E5%9C%A8%E9%97%B9%E9%92%9F%E5%8F%91%E6%98%8E%E5%89%8D%E4%BA%BA%E4%BB%AC%E6%98%AF%E5%A6%82%E4%BD%95%E8%B5%B7%E5%BA%8A%E7%9A%84">在闹钟发明前人们是如何起床的</a></li></ul><h4 id="心理与关系"><a class="markdownIt-Anchor" href="#心理与关系"></a> 心理与关系</h4><ul><li><a href="#%E6%88%91%E4%BB%8E%E6%9C%AA%E5%A6%82%E6%AD%A4%E5%BF%AB%E4%B9%90%E8%BF%87">我从未如此快乐过</a></li><li><a href="#%E9%99%8C%E7%94%9F%E4%BA%BA%E7%9A%84%E7%A7%98%E5%AF%86%EF%BC%9A%E5%A6%82%E4%BD%95%E4%B8%8E%E4%BB%BB%E4%BD%95%E4%BA%BA%E4%BA%A4%E8%B0%88-%E4%BB%A5%E5%8F%8A%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BD%A0%E5%BA%94%E8%AF%A5%E8%BF%99%E4%B9%88%E5%81%9A">陌生人的秘密：如何与任何人交谈，以及为什么你应该这么做</a></li></ul><h4 id="科学与自然"><a class="markdownIt-Anchor" href="#科学与自然"></a> 科学与自然</h4><h4 id="技术与创造"><a class="markdownIt-Anchor" href="#技术与创造"></a> 技术与创造</h4><ul><li><a href="#%E6%97%A5%E6%9C%AC%E7%BD%91%E9%A1%B5%E8%AE%BE%E8%AE%A1%E7%9A%84%E5%A5%87%E7%89%B9%E6%A1%88%E4%BE%8B">日本网页设计的奇特案例</a></li><li><a href="#%E8%AE%BE%E7%BD%AE%E6%89%8B%E6%9C%BA%E7%AE%80%E7%9B%B4%E6%98%AF%E4%B8%80%E5%9C%BA%E5%99%A9%E6%A2%A6">设置手机简直是一场噩梦</a></li><li><a href="#libreoffice-%E7%A7%B0%E5%85%B6%E7%94%A8%E6%88%B7%E7%95%8C%E9%9D%A2%E4%BC%98%E4%BA%8E-microsoft-office">LibreOffice 称其用户界面优于 Microsoft Office</a></li><li><a href="#%E5%A5%BD%E7%9A%84%E8%BD%AF%E4%BB%B6%E6%87%82%E5%BE%97%E9%80%82%E5%8F%AF%E8%80%8C%E6%AD%A2">好的软件懂得适可而止</a></li><li><a href="#%E5%81%9C%E6%AD%A2%E4%BD%BF%E7%94%A8%E7%81%B0%E8%89%B2%E6%96%87%E6%9C%AC">停止使用灰色文本</a></li><li><a href="#%E5%A6%82%E4%BD%95%E5%9C%A8%E6%89%8B%E6%9C%BA%E4%B8%8A%E5%AE%89%E8%A3%85%E5%B9%B6%E5%BC%80%E5%A7%8B%E4%BD%BF%E7%94%A8-lineageos">如何在手机上安装并开始使用 LineageOS</a></li><li><a href="#%E5%A4%A9%E5%91%90%E6%88%91%E4%B9%8B%E5%89%8D%E5%AF%B9-fediverse-%E7%9A%84%E7%9C%8B%E6%B3%95%E5%AE%8C%E5%85%A8%E9%94%99%E4%BA%86">天呐我之前对 Fediverse 的看法完全错了</a></li><li><a href="#%E6%9C%89%E8%B6%A3%E9%A1%B9%E7%9B%AE">有趣项目</a></li></ul><h2 id="输出"><a class="markdownIt-Anchor" href="#输出"></a> 输出</h2><ul><li><a href="#%E6%88%91%E5%86%99%E7%9A%84%E6%96%87%E7%AB%A0">我写的文章</a></li><li><a href="#%E7%BC%96%E7%A8%8B%E5%8E%86%E7%A8%8B">编程历程</a></li><li><a href="#%E4%B9%A6%E7%B1%8D">书籍</a> / <a href="#%E5%BD%B1%E8%A7%86">影视</a> / <a href="#%E9%9F%B3%E4%B9%90">音乐</a></li><li><a href="#%E6%97%A5%E8%AE%B0%E7%89%87%E6%AE%B5">真生活</a></li></ul>    </details><h2 id="商业与社会"><a class="markdownIt-Anchor" href="#商业与社会"></a> 商业与社会</h2><p><a id="许多人口数据都是虚假的"></a></p><h4 id="许多人口数据都是虚假的"><a class="markdownIt-Anchor" href="#许多人口数据都是虚假的"></a> <a href="https://davidoks.blog/p/a-lot-of-population-numbers-are-fake">《许多人口数据都是虚假的》</a></h4><p>澳大利亚正北方向有个小岛国，叫作巴布亚新几内亚。它的人口仅占全球的 0.1% 左右，却拥有超过 10% 的语言被使用。这意味着，两个相距仅几英里的村庄里，所说的语言可能完全无法互通。</p><p>结合该文章的标题，你也知道话题会是什么了吧：巴布亚新几内亚有多少人呢？</p><p>答案是 <strong>不知道</strong>。</p><p>政府只能去推测，国家里到底有多少人居住。因为人们住在山地上，有些连路都没有铺设，政府很难派遣人员去调查。</p><p>联合国也想知道巴布亚新几内亚有多少人，所以利用卫星图像和住户调查发现，实际居住的人口应是政府声称的两倍。巴布亚新几内亚的总理尴尬地承认了这件事，并说：</p><blockquote><p>他说，这基本上无关紧要，因为无论人口是多少，「我都无法为国民提供充足的教育、医疗保障、基础设施建设，以及创造有利的法治环境」来让他们获得成功。</p></blockquote><p>文章作者 David Oks 列出了一些国家的人口数据为什么会是虚假的原因。令我意外的是，并不是所有的国家都因为类似于巴布亚新几内亚这样的技术问题，而只能给出预测的数字。</p><p>比如尼日利亚的人口普查充满了政治色彩。首先需要知道的是，该国的联邦共和制度效仿的是美国，总统需要由全民投票、选举出来，也是国家的元首和政府的首脑。同样的，总统的任期是四年，最多可以连任一次。甚至连参议院、众议院都是和美国的制度很相似。</p><p>不过 Oks 指出，尼日利亚作为一个统一国家，现状要脆弱许多。精英阶层为了确保国家不分崩离析，需要利用不同地区在政府中的相对代表权，和石油收入的分配。巧了，它们都取决于人口占比。地方精英为了更多的石油收入，想尽办法去夸大自己地区的人口数量，而国家精英又需要去平衡不同地方之间的人口，最终得到的就是数字造假。</p><p>这期间还发生过一个城市认为政府普查的人口数量有误，自行进行了普查，然后声称实际的数据还要多出八百万人的事件。</p><p>更为可笑的是，尼日利亚人口委员会的主席说自 1816 年以来，尼日利亚就没有任何一次普查是可信的。而他在说完这些话后，便被总统解雇了。</p><p>人口普查这种工作，本就是麻烦，得到的反馈也并非即时的工作。想要让并没有那么富裕的国家做好这份工作，更是难上加难。更何况，Oks 表示使用卫星技术也无法得出更准确的数字，毕竟这世上还是有许多人生活在同个房子里，或者森林里的。</p><p><a id="大型研究发现青少年吸食大麻与后期精神病发作之间存在联系"></a></p><h4 id="大型研究发现青少年吸食大麻与后期精神病发作之间存在联系"><a class="markdownIt-Anchor" href="#大型研究发现青少年吸食大麻与后期精神病发作之间存在联系"></a> <a href="https://text.npr.org/nx-s1-5719338">《大型研究发现青少年吸食大麻与后期精神病发作之间存在联系》</a></h4><p>2021 年，纽约正式通过了《大麻监管与税收法案》。在这之前，社会各界经历了漫长且激烈的拉锯战。</p><p>支持合法化的一方主要着眼于司法改革与经济利益：过去几十年针对大麻的严厉执法导致了极其严重的种族不平等！少数族裔在轻微持有大麻的逮捕纪录中比例过高，建立受监管的合法市场不仅能消除这种司法不公，还能彻底摧毁地下黑市，并为州政府带来数以亿计的税收，用于反哺社区建设。好哇，好哇！</p><p>反对合法化的一方将焦点集中在公共健康与社会治安上：大麻的泛滥将不可避免地增加青少年接触精神活性物质的几率，引发不可预估的脑部发育损害。此外，反对者还对大麻合法化后必然带来的毒驾事故率上升、二手大麻烟雾对城市公共空间空气质量的破坏表示了强烈质疑。</p><p>那么从 2021 年立法通过，到 2026 年的今天，纽约的现实情况如何呢？</p><p>在合法化初期至 2024 年间，由于官僚系统的低效、繁琐的合规审批以及相关的法律诉讼，纽约合法大麻店的落地速度极其缓慢。数以千计的非法无证大麻店依然在纽约街头野蛮生长。它们不仅销售未经安全测试的劣质产品，甚至为了牟利向未成年人违规出售色彩鲜艳的大麻软糖 —— 这玩意儿我的校友给我看过，和小熊软糖很像，乍一看还以为是安全的甜食呢。它通常被称为 <em> edibles</em>。</p><p>同时，纽约上州等地的毒物控制中心也接到过大量关于婴幼儿和儿童误食大麻的求救电话。纽约的街头巷尾那刺鼻的大麻气味也挥之不去。这是个和香烟完全不同的气味，惹得当时一位朋友每每闻到，都会在我们的小群聊里气得骂街。</p><p>现在纽约查封了大量非法大麻店，加快了执照的审批流程，让合法的大麻店在 2025 年迎来爆发式的增长。具体表现在哪儿呢，我家楼下每条街都有家合法大麻店。除了大麻，它们也会售卖罐装、瓶装饮料和薯片等零食，活像普通的一元店。</p><p>附近一家大麻店里，店主还收养了只小猫，被我和室友称呼为「大麻猫」。不过明明和我们的匹克猫是同个品种，看上去却又凶又肥硕。</p><p>大麻带来的税收，被要求定向投入到以下五个核心领域：心理健康、住房、劳动力发展与教育、物质使用障碍治疗，以及减少伤害。</p><p>虽然有一定的利，但弊也不少，就比方说本篇文章的重点研究：吸食大麻对青少年大脑的损伤。</p><p>该研究分析了加州 46 万名青少年的健康数据，并追踪至他们 25 岁。为了明确因果关系的逻辑，研究人员在样本中排除了在使用大麻前就已经表现出精神疾病症状的个体 —— 因为支持大麻合法化的一个观点是，人们是为了缓解原发精神症状才去吸食大麻的，也是我身边日常就会吸食大麻的朋友们的理由。</p><p>研究发现，在过去一年内使用过大麻的青少年，其未来确诊严重精神疾病的风险是未使用者的两倍。这些严重疾病主要包括 <u>双相情感障碍</u>、<u>精神分裂症</u> 等导致脱离现实的精神病性障碍。虽然这类病症的绝对发病率较低，占比约 1%，但具有极高的致残性和社会治疗成本。</p><p>此外，大麻也提升了常见心理疾病的发病率。数据显示，大麻使用者的抑郁症风险增加了约三分之一，焦虑症风险增加了约四分之一。</p><p>至于年龄因素是否重要，研究数据发现，青少年接触大麻时的年龄越小，其与抑郁和焦虑的关联就越强。这意味着，发育中的大脑对大麻的神经学影响非常敏感。</p><p>随着大麻合法化的推进，公众会慢慢将其视为安全、天然的减压物。接着，多因素导致的易感人群在使用大麻后，一旦精神病发作，如果依然继续使用，大脑功能将被快速恶化；未来的临床康复只能变得愈来愈困难。</p><p><a id="三十年了-宝可梦依然风靡全球"></a></p><h4 id="三十年了宝可梦依然风靡全球"><a class="markdownIt-Anchor" href="#三十年了宝可梦依然风靡全球"></a> <a href="https://www.pressreader.com/india/mint-chennai/20260304/281556592315807">《三十年了，宝可梦依然风靡全球》</a></h4><p>Poképark Kanto（宝可梦乐园：关都）是宝可梦品牌的主题乐园，于 2026 年 2 月 5 日正式对外开放。</p><p>高中时一位数学老师在放暑假之前，要跟我们玩「冷知识游戏」：电脑上会有数个列，每个列代表了一个分类。列内会有多张卡牌，它们的分数是递增的，意味着背面的「冷知识」会有多「冷」。</p><p>其中有一张卡牌，问的是「哪个 IP 是全球最火热的」。有人猜是《英雄联盟》，结果答案是《宝可梦》。</p><p>那时的我根本没有清楚地意识到，《宝可梦》这个 IP 到底有多热门。这源自于，小时候在中国看少儿节目的时候，我更喜欢《数码兽》这个系列，以至于傻傻地认为《宝可梦》没有那么「厉害」。</p><p>结果现在，绝大多数的宝可梦我都记得名字，游戏也玩过好几款，反倒是数码兽系列的世界观基础我都不是很清楚 —— 谁叫你动画系列做得越来越奇怪，我看到第三代的「驯兽师之王」就没有继续再看了，多年后看到《数码兽 02 THE BEGINNING》差点没喷出饭来。</p><p>虽然内陆跟台湾更喜欢管它叫「数码宝贝」、香港叫「数码暴龙」，但我更喜欢叫「数码兽」就是了……</p><p>小时候我还喜欢一个少儿节目，中国叫《磁星骑士》，但它其实是韩国的《최강합체 믹스마스터》，也是《카드왕 믹스마스터》的续作（哦我不会韩语……）。二者都是 <em> MIX MASTER</em> 系列的动画作品。</p><p>这期间还有反复看《开心宝贝》、《贝肯熊》（也就是《倒霉熊》，没想到吧！它在 2017 年被全版权收购了）等奥飞娱乐出的动画系列。有意思的是，小时候虽然不爱看《喜羊羊与灰太狼》—— 除了生肖电影。我 2015 年离开中国的四个月前，看的就是《喜羊羊与灰太狼》生肖电影系列的最后一个《羊年喜羊羊》，再之后生肖电影再也没有后续，我也再也没有回到中国去，呜呜 —— 前不久我倒是连续看完了「异国大营救」系列，以及「羊村守护者」系列下的《狂野新宇宙》，让人觉得时间好像慢了下来，内容也比想象中有趣。</p><p><a id="微软受够了-microslop-这个称呼"></a></p><h4 id="微软受够了-microslop-这个称呼"><a class="markdownIt-Anchor" href="#微软受够了-microslop-这个称呼"></a> <a href="https://www.windowslatest.com/2026/03/02/microsoft-gets-tired-of-microslop-bans-the-word-on-its-discord-then-locks-the-server-after-backlash/">《微软受够了 /Microslop/ 这个称呼》</a></h4><p>事件的起因是微软在其 Discord 服务器中启用了自动审核机制，拦截了贬义词 <em> Microslop</em> 的发送。</p><p>审查机制触发后，事态迅速走向失控：用户开始通过将字母替换成数字，如 <em> Micros10p</em> 等方式，绕过关键词过滤器。原本单一的系统拦截演变成了用户群体的逆反测试，大家玩得不亦乐乎。</p><p>随着大量变体词汇涌入，微软最终采取了强硬的限制措施：封禁相关账号、隐藏频道消息历史、禁用了多数用户的发言权限、将服务器全面锁定。</p><p><a id="在日本对坑孤独的酸奶配送女工"></a></p><h4 id="在日本对坑孤独的酸奶配送女工"><a class="markdownIt-Anchor" href="#在日本对坑孤独的酸奶配送女工"></a> <a href="https://www.bbc.com/travel/article/20260302-the-yoghurt-delivery-women-combatting-loneliness-in-japan">《在日本对坑孤独的酸奶配送女工》</a></h4><p>1963 年，养乐多为了向公众普及益生菌概念，雇佣了大量女性进行上门推销。由于这些女性多是本地社区里的人，所以更容易与客户建立信任。随着时间的推移，这种长期的、定期的上门拜访超越了商业销售的范畴，变为更稳定的社交层面上的基础设施。</p><p>这是因为，日本是世界公认老龄化速度最快的国家之一，随着带来的是孤独感以及「孤独死」这一社会问题。养乐多配送员每周在固定时间拜访客户，反而为独居老人们提供心理慰籍，以及降低了独居老人们会遇到的安全风险：孤独死的老人们最怕的便是没有人惦记，就算死了也不会有人第一时间发觉。</p><p>中国也有养乐多配送员，叫作「养乐多妈妈」。现在去养乐多的官网上看，还能看到招聘页面。不过我小时候并没有喝过养乐多，自然也没见过养乐多妈妈。</p><p>但是我对益生菌食品还是颇有印象的。我是个挑食的人，不爱喝牛奶，尤其是纯牛奶。小时候别的孩子在喝奶的时候，我只会喝酸奶（和哈密瓜味的学生奶）。益生菌食品的口味和酸奶很相似，所以我也爱喝。当时最常喝的好像叫「每日益菌」，还有「小洋人」！我对酸奶的喜爱，以至于现在我每次出去玩都会去华人超市里找「小样」喝，以及日日想念叫「北京老酸奶」的东西 —— 可惜美国没有它，也找不到驴肉。</p><p>现在在国内搜索「养乐多」，看到的每每都是它接连关厂的新闻。到了有养乐多可喝的美国，我也鲜少会买它喝，因为替代品实在是太多了：在 Costco 就有 Cool Plus，一买就是 50 瓶。</p><p>而养乐多配送员这一工作，我并没有见过，也没有体会过。小时候居住的小区楼下虽然有订阅牛奶用的铁箱子，但家里还是会自行去超市购买袋装奶。真要说有什么相似的，那应该是亲戚家订阅的《故事会》了。可惜在我接触到它的时候，我也离出国不远了。</p><p>出国后来到生活节奏更快的曼哈顿，我曾和室友订阅过固定时间上门送预制餐的服务。它们投放了大量的广告，说什么前十几盒免费，想要取消订阅的话还会打折。再加上室友有段时间懒得做饭，自然而然订阅了这一服务。</p><p>虽然是上门配送，但很多时候配送员将包放在公寓楼下就走了。就算送到家门口，也只是敲了敲门、快速离开，根本没有沟通可言。这倒是让我好奇了起来，如果在中国订阅了类似的服务，怕也是同个情况，怎么就日本这么特殊哩？</p><p>几年前我去对比纽约市而言根本就是「乡下」的亲戚家探望。那是美国不同于大城市的另一个景色：空旷的高速公路、离邻居极远的房子…… 亲戚是做美式中餐生意的；我那次过去填补上了空缺的「外卖员」位置，顺带赚了点小费。送餐上门时，许多客人都会跟我聊几句，表达亲切。</p><p>日本的养乐多配送员先前提到过，多为「社区女性」。「社区」是个在城市里难以听到的词汇：什么社区？你会和你的邻居聊天吗？我和我的邻居可是天天都视彼此不顺眼，自然也没有说过话。城市化的世界里，大家都住在小小的房间里，别说敲门拜访来推销了，你是隔壁邻居我都得怀疑你是不是图谋不轨。</p><p>这种居住形态边缘化了养乐多配送员这个岗位，这是毋庸置疑的。另一面便是商业对效率的极致追求。消费者购买的是商品本身以及极速的便利，而配送员要被系统和算法驱使，时间与收入直接挂钩，要求他们停下来与客户闲聊并不现实。高度发达的商业体系中，人与人的接触早成了「低效」的代名词，是必须要被优化掉的。</p><p>反观日本，养乐多配送员模式能活到现在，是因为她们交付的核心产品早已在暗中发生了转移。独居老人真的需要小红瓶么？他们需要的是嘘寒问暖，购买的也是嘘寒问暖。</p><p><a id="在闹钟发明前人们是如何起床的"></a></p><h4 id="在闹钟发明前人们是如何起床的"><a class="markdownIt-Anchor" href="#在闹钟发明前人们是如何起床的"></a> <a href="https://www.bbc.com/future/article/20260306-the-wake-up-tricks-people-used-before-alarm-clocks">《在闹钟发明前人们是如何起床的》</a></h4><p>在现代闹钟普及之前，人们是如何按时醒来的呢？</p><p>前工业时代的人们很大程度上依靠日出等自然光线的变化来调节生理节律，很健康！动物的鸣叫也成了最早的听觉闹钟，比如大家常说的公鸡打鸣 —— 也是我所质疑的，鸡这东西可是时刻都会打鸣哎？</p><p>教堂或者村庄定时敲响的钟声也是听觉闹钟。在富裕的家庭中，还会有仆人来叫醒雇主。</p><p>到了早期技术发明的时候，新花样便多了起来。例如古代的蜡烛钟和香钟，通过计算燃烧进度，让预先放置的金属针或金属球掉落至金属盘中、发出声响。</p><p>古希腊时期广泛使用水钟，通过水流积累增加气压以发出哨声，或通过水盆排水机制触发铃铛。</p><p>早期的机械时钟在 13 世纪末便已出现，但就算到了 19 世纪后期，也因为过于昂贵、不够可靠，而没有被广泛普及。</p><p>工业时代工人必须准时到岗，英国和其他欧洲国家搞了个叫 <em> knocker uppers</em>（敲床人）的专职工作。他们会在凌晨的街道上走来走去，用长长的杆敲击客户的窗户，或者用管子向窗户吹射豌豆，直到确认客户醒来为止。</p><p>再然后，20 世纪 20 年代，个人机械闹钟便廉价化、普及到了普通人的家里。</p><h2 id="心理与关系"><a class="markdownIt-Anchor" href="#心理与关系"></a> 心理与关系</h2><p><a id="我从未如此快乐过"></a></p><h4 id="我从未如此快乐过"><a class="markdownIt-Anchor" href="#我从未如此快乐过"></a> <a href="https://ben-mini.com/2026/the-happiest-ive-ever-been">《我从未如此快乐过》</a></h4><p>2020 年初，作者 Ben Wallace 在大学毕业初期，面对传统的职场生活感到内心空虚。一次偶然的机会，使他成为了一支只有六名球员的中学篮球队主教练。</p><p>在执教的过程中，Wallace 逐渐获得了极大的成就感。这种帮助他人成长的经历，也反向提升了他自身的自信，使其在工作和生活中表现得更加出色。</p><p>他认为这段经历带来的快乐可以被归结为四个核心要素：</p><ol><li>自己具备帮助和引导孩子的天赋与热情；</li><li>自己享受身处现实世界、进行实体流汗互动的真实感；</li><li>执教过程中所做的事情满足了自己对掌控全局的需求；</li><li>自己对篮球运动本身纯粹的爱。</li></ol><p>Wallace 认为，许多科技从业者被 AI 打击、对自身的行业角色和价值产生怀疑。过去，行业仅用产品扩张的规模来衡量个人价值；此类想法在现在应当变革。人们不应被屏幕束缚地工作，而是应当去探寻那些能在现实世界中带来真实掌控感与价值感的事务。</p><p>我的兴趣爱好很狭隘，以前至少还有个「画画」的选项，现在却什么都画不出来了。虽然室友这个破家伙很喜欢借此贬低我、彰显自己的厉害，但也不得不承认，她的喜好很多：画画、唱歌、乐器、健身…… 这些是可以借肉体，为我们带来快乐的事情。</p><p>每每想到这种事情，心中所涌现出来的 —— 是羡慕同嫉妒 —— 再去想，察觉到我是个嫉妒心很强的人。</p><p>我也想要有着很多兴趣，会做很多事情、懂很多东西。但我没有。</p><p><a id="陌生人的秘密：如何与任何人交谈-以及为什么你应该这么做"></a></p><h4 id="陌生人的秘密如何与任何人交谈以及为什么你应该这么做"><a class="markdownIt-Anchor" href="#陌生人的秘密如何与任何人交谈以及为什么你应该这么做"></a> <a href="https://www.theguardian.com/lifeandstyle/2026/feb/24/stranger-secret-how-to-talk-to-anyone-why-you-should">《陌生人的秘密：如何与任何人交谈，以及为什么你应该这么做》</a></h4><p>这个月我换了新兼职，工作中就需要适当给客人提供「服务」，即时不时问候一下，让客人觉得自己被服务到了。这对和人类有着边界感的我来说，无疑是件难事：「我要如何知道这个人愿意和我交谈？他不会觉得我在烦他吗？为什么人们喜欢在用餐期间和陌生人聊天？」</p><p>练习这件事时，我还是可以听到一些有趣的经历，但也只是「有点有趣」而已。我不认为自己享受和对方交谈。不过这也没办法，它是我的工作，不是我的兴趣使然。</p><p>那么将我抽离出工作本身，投放到任意一个车厢、街道，或者什么的，我会乐意和陌生人交谈吗？我认为我不会，但这只是「我认为」。有些时候我会陷入自己的幻想，幻想我和一个看上去有趣的陌生人搭话，我们聊了起来，聊得还不错。我会在脑海中想我和这个人说的每句话，使其听上去完美，然后用右手食指在任意一个地方将它们一个字一个字地写下来。</p><p>不过就算这样脑内预习多少次，下次和别人说话还是一团糟就是了。</p><p>我在和多个朋友相处时会有相似的问题。我的「礼貌」使我不能去打断他们之间的交谈。所以很多时候，我都默默走在后面，听他们聊天。因为不插嘴是件好事，不是么？</p><p>文章作者 Viv Groskop 认为，这一切都是「人们在社交中过度放大被拒绝或引发尴尬的恐惧」导致的。重建连接的关键在于，降低对社交的预期压力。人们应当将闲聊视为一种微小、且人性化的举动，而不是什么必须达成深刻共鸣的艰巨任务。</p><p>初中时我在一家中餐馆打工过一段时间。一次坐地铁，就有个大叔过来搭话，因为他去过那家中餐馆，见我有些眼熟，想要确认我是不是那家店的员工，仅此而已。</p><p>现在的兼职，也有些格外自来熟的熟客，会在喝红酒时去问隔壁桌的客人点了什么、好不好吃、自己推荐什么 —— 在他们看来，闲聊就是随随便便就能做到的吧，也没有心理负担，只是为了一个「想」。</p><h2 id="科学与自然"><a class="markdownIt-Anchor" href="#科学与自然"></a> 科学与自然</h2><h2 id="技术与创造"><a class="markdownIt-Anchor" href="#技术与创造"></a> 技术与创造</h2><p><a id="日本网页设计的奇特案例"></a></p><h4 id="日本网页设计的奇特案例"><a class="markdownIt-Anchor" href="#日本网页设计的奇特案例"></a> <a href="https://sabrinas.space/">《日本网页设计的奇特案例》</a></h4><p>日本网页设计在全球极简主义趋势下，呈现出了独特的「极繁主义」的现象。</p><p>文章作者就想明白，为什么就日本如此独特地出现了这种情况？他的结论是，日本互联网与移动硬件的发展路径与全球存在显著脱节。</p><p>首先，日本人口老龄化特征明显，庞大的老年用户群体固守早期的网页使用直觉。</p><p>其次，社会整体对软件更新存在迟滞性，例如企业端长期依赖 Internet Explorer 等老旧浏览器。</p><p>最关键的因素在于日本独有的早期手机文化 —— 早在 iPhone 引领全球智能手机革命之前，日本就已经普及了具备邮件、支付和网络功能的移动设备。这使得日本用户和开发者过早地适应了以高密度文本为主的移动端排版，从而在随后的十年里，没有像世界其他地区那样受到移动端极简设计浪潮的冲击。</p><p>这些网页设计，令我想到了早期百度贴吧和 QQ 邮箱的界面设计。虽然我并不使用 QQ 的邮箱地址，但我很喜欢它的皮肤，特别是「枫叶秋」。到现在，我也没有将它们改成新版的网页设计。另外，我也好奇有没有已有的邮件网页客户端可以直接使用 QQ 邮箱这套设计呢？</p><p>另一个让我好奇的是日本的折叠机文化。我对非全触屏智能机的电子设备有着兴趣，一直想要收藏一些玩玩。这里分享个 <a href="https://chaz.fun/phonemuseum/">手机博物馆</a>，可以查看一些老手机的 3D 模型，有些甚至可以互动，比如我觉得整体设计很有趣的 Nokia N93i。</p><p><a id="设置手机简直是一场噩梦"></a></p><h4 id="设置手机简直是一场噩梦"><a class="markdownIt-Anchor" href="#设置手机简直是一场噩梦"></a> <a href="https://joelchrono.xyz/blog/setting-up-phones-is-a-nightmare/">《设置手机简直是一场噩梦》</a></h4><p>我家里人除了我，大家用的是 iPhone、iPad，所以很无聊。我在去年年初换掉了电池健康 60 还是 70% 的 iPhone SE 3 代，改用 Motorola Razr Plus 2024—— 也是个糟糕的选择。</p><p>Motorola 手机的系统很难让人去 Google 化：Google 的产品全部都是预装好的，我连 Google Calendar 都无法删掉，讨厌死了。Razr 系列的特殊性，也使其难以安装上匹配的第三方操作系统。</p><p>再就是折叠屏的电池，也没有比 iPhone 好到哪里去。值得赞赏的倒是其屏幕，颜色很亮丽，天呐居然是高刷 —— 但我已经把屏幕颜色都改成灰阶了，看不到啥。</p><p>这个月初，GrapheneOS 惊喜地表示要和 Motorola 合作。不过考虑到 GrapheneOS 的特殊性，兼容它的 Motorola 手机只能是全新的设备，而不是我这台 Motorola Razr Plus 2024。我难道还要去买部新的吗？</p><p>当然不行。一位讨人厌的朋友在我折叠屏漏液后，每天嘲笑我使用安卓手机，而不是他那部买了五年还能继续使用的 iPhone 12。你那部手机的价钱，换成 Motorola，我就能买到硬件更好，还不怕水的 Edge 系列，拽什么拽！虽然已经不和这个家伙来往，但内心起了无名火，总想要一直用这部手机，直到五年后。</p><p>我在 Fediverse 上看到这则新闻时，还看到一些朋友质疑 Motorola 和以色列的关系。我必须要澄清一下，Motorola 有两个：Motorola Mobility 和 Motorola Solutions。前者是我一直在说的 <em> Motorola</em>，也就是产手机、属于 Lenovo 的那家面向消费者的子公司；后者才是给以色列生产电子设备的公司。他们除了图标和名字，<strong>没有任何关系</strong>！</p><p>当时在和网络上的朋友们讨论时，就有人认为他们之间有合作关系：不，他们没有。先不说二者生产的设备就不同，给以色列生产的政府用设备，怎么可能交给母公司总部位于中国的生产线呢？</p><p>顺带一提 Motorola Mobility 是 LLC，Motorola Solutions 是 Inc。它们有什么区别呢？前者是「有限责任公司」，后者是「股份有限公司」。简单来说，LLC 的「法人」是公司本身。要是出了什么问题，死掉的只会是公司，而不是内部的「成员」。因为所有人都是「成员」，没有股份什么的，内部协议什么的都会灵活、有弹性许多。相反，上市的、有股份的公司，就有股东、董事会，合规压力要大许多，还得保留财务报表等形式要件。</p><p>好了，你又学到了没那么重要的小知识！</p><p><a id="libreoffice-称其用户界面优于-microsoft-office"></a></p><h4 id="libreoffice-称其用户界面优于-microsoft-office"><a class="markdownIt-Anchor" href="#libreoffice-称其用户界面优于-microsoft-office"></a> <a href="https://www.neowin.net/news/libreoffice-hits-back-at-its-critics-says-its-ui-is-better-than-microsoft-offices/">《LibreOffice 称其用户界面优于 Microsoft Office》</a></h4><p>我日常生活不会使用到 Microsoft Office、LibreOffice、WPS 等产品，不过曾经还是有使用过的。</p><p>LibreOffice 是自由且开源的软件（<em>Free Software</em> 就该改名叫 <em> Libre Software</em>），在这一点上我就会更倾向于使用它。高中时将笔记本电脑刷成了 Ubuntu Linux 发行版，而它内置了 LibreOffice 套件。</p><p>在用户界面上，说实话，这类办公室套件都差不多，只有用户习不习惯的问题。重点在于对格式的支持、软件的速度和硬件资源占用等等。</p><p>文章中所提到的，「许多用户通过对 Microsoft Office 的熟悉视角来评估办公软件，把『偏离它』视为问题，而非设计选择」，这句话说得很对。使用的工具、软件，不能只有一个，必须支持多个的存在，避免中心化。这一点，GitHub 便是个例子。</p><p><a id="好的软件懂得适可而止"></a></p><h4 id="好的软件懂得适可而止"><a class="markdownIt-Anchor" href="#好的软件懂得适可而止"></a> <a href="https://ogirardot.writizzy.com/p/good-software-knows-when-to-stop">《好的软件懂得适可而止》</a></h4><p>有一天，你发现 <code>ls</code> 命令变成了 AI 驱动的路径智能。它不仅会展示文件，还会预测你在找哪个…… 真是个恐怖故事。</p><p><a id="停止使用灰色文本"></a></p><h4 id="停止使用灰色文本"><a class="markdownIt-Anchor" href="#停止使用灰色文本"></a> <a href="https://catskull.net/stop-using-grey-text.html">《停止使用灰色文本》</a></h4><p>我也想要知道，为什么会有网站选择在浅灰色的背景上使用灰色的文本颜色。</p><p>作者表示，如果非要使用对比度极差的颜色的话，可以使用 <code>prefers-contrast</code>。</p><p><a id="如何在手机上安装并开始使用-lineageos"></a></p><h4 id="如何在手机上安装并开始使用-lineageos"><a class="markdownIt-Anchor" href="#如何在手机上安装并开始使用-lineageos"></a> <a href="https://lockywolf.net/2026-02-19_How-to-install-and-start-using-LineageOS-on-your-phone.d/index.html">《如何在手机上安装并开始使用 LineageOS》</a></h4><p>这篇文章依然和我无关……</p><p>不过了解一下还是对自己有帮助的。</p><p>作者表示，仅仅在手机上拥有 <code>root</code> 权限是不够的（我到现在连 <code>root</code> 权限都没有……）：</p><ol><li>突破私有应用权限的限制。Android 系统中存在着权限极高的「私有应用」，这类应用必须使用平台密钥签名，而这通常需要获取手机厂商的私钥。只有自行编译操作系统，拥有自己的平台密钥，才能真正赋予应用这些底层特权；</li><li>消除对特定设备厂商的生态依赖；</li><li>获取更优质的第三方开发支持；</li><li>实现系统级备份。在自定义系统中，可以直接以 Root 身份运行 ADB 守护进程。这在常规的、已 Root 的手机上难以实现。如果实现了，原生的高级权限可以使用户通过脚本对整个工作环境进行深度的无缝备份与还原；</li><li>降低修改 <u>SELinux 策略</u> 的门槛。SELinux 是 Linux 内核的安全模组。掌控操作系统源码意味着用户可以直接在源码层面更新或配置 SELinux 安全策略，从而避开对现有闭源系统策略进行繁琐的反编译的痛苦过程；</li><li>简化系统服务的部署流程，摆脱掉对 Magisk 等第三方动态挂载工具的依赖。</li></ol><p>单是阅读作者写的文章，就能意识到 Android 官方文档有多么碎片化跟混乱…… 甚至连作者有时都需要承认，文档很匮乏，没有读明白。那我更不用说了，我根本不懂这些东西。</p><p>但我内心还是向往去搞明白的，但这是否意味着我需要去搞来一台玩成砖我都不会心疼的旧手机？</p><p><a id="天呐我之前对-fediverse-的看法完全错了"></a></p><h4 id="天呐我之前对-fediverse-的看法完全错了"><a class="markdownIt-Anchor" href="#天呐我之前对-fediverse-的看法完全错了"></a> <a href="https://matduggan.com/boy-i-was-wrong-about-the-fediverse/">《天呐我之前对 Fediverse 的看法完全错了》</a></h4><p>起初，作者对去中心化社交网络背后的意识形态斗争或底层协议之争缺乏兴趣 —— 我也是，ActivityPub 跟 AT Protocol 哪个更好，我不想知道 —— 为了逃避 Twitter 易主后的混乱与商业化环境，他转向了 Mastodon，看中了其没有广告和算法推荐的清静。</p><p>接着，美国的新闻环境便急剧恶化（真的么？我觉得它从事至今都是一坨屎），作者的认知发生了改变。资本逐利、政治诉讼等原因，美国主流媒体沦为了寡头利益的筹码，以及缺乏实质内容的宣传工具，根本不能作为可靠信息源的价值。</p><p>不知为何，身边的一些朋友们总是认为某某新闻是「可靠」的，尽管它们明确表示过自己倾向于某个政党。甚至有人因为自己会阅读报纸，而觉得自己高人一等 —— 新闻和网络上的资讯网站，都是一个性质，谁也比不过谁。</p><p>作者认为 Twitter 通常被认为是替代品的软件，如 Threads 和 Bluesky，都无法填补这个信息空白。其中 Threads 被他视为是由品牌方主导的无聊广告平台。我使用过一段时间 Threads，主要是在上面发仅自己可见的垃圾话……Bluesky 倒是没有使用过。</p><p>真正的转折点发生在美国威胁入侵格陵兰岛的时候。传统媒体，包括外部的欧洲媒体，都难以获取真实情况时，反而是 Fediverse 成为了作者唯一可靠的情报来源。这让作者意识到，Fediverse 剥离了现代社交媒体的功利性，让人们只是单纯地分享事实与见解。这才是可以建立真实且有用的人际信息连接。</p><p><a id="有趣项目"></a></p><h4 id="有趣项目"><a class="markdownIt-Anchor" href="#有趣项目"></a> 有趣项目</h4><hr><h2 id="我写的文章"><a class="markdownIt-Anchor" href="#我写的文章"></a> 我写的文章</h2><p>我上个月的月刊忘记生成了……</p><p>为了方便，我在自己的 Emacs 配置里写了个从 Org-Mode 文件里自动调取本月写的文章的功能。然后，我把它忘记了。</p><ul><li><a href="/posts/ccb5/">《DeGoogling and DeMicrosoft is a new start for me》</a></li><li><a href="/posts/a778/">《入门编写 SVG》</a></li><li><a href="/posts/7ae3/">《奶茶店毕业》</a></li><li><a href="/posts/1572/">《没有情人的情人节》</a></li><li><a href="/posts/eac7/">《那些不受欢迎的想法・贰》</a></li></ul><h2 id="编程历程"><a class="markdownIt-Anchor" href="#编程历程"></a> 编程历程</h2><p><a id="自托管-gotosocial"></a></p><h4 id="自托管-gotosocial"><a class="markdownIt-Anchor" href="#自托管-gotosocial"></a> 自托管 GoToSocial</h4><p>我离开了待了有几个月的「海獭之家」，改为自托管 GoToSocial 实例。这是个轻量级的 ActivityPub 服务端，轻量到目前为止官方源代码中都没有「引用」功能，也不打算提供原生的 Web 客户端。</p><p>也是借此，我才开始使用第三方客户端，例如 Phanpy、Nicolium、Statuzer、Elk…… 还有专门为 GoToSocial 实例开发的 Masto-FE (🦥 flavour)—— 它名字就是这样，直接称呼为 Masto-FE GoToSocial 特供版好了。</p><p>这些第三方客户端，各有各的优势，展示逻辑也挺不一样的。比方说 Phanpy，它可以将别人的转嘟叠在一起展示；一些客户端会将回复以及被回复的嘟文放在一起展示，一些则严格按照时间线、将回复单独展示出来。</p><p>Masto-Fe GoToSocial 特供版这种多栏的设计，放在电脑上看挺舒服的，便成了我电脑使用 Fediverse 的唯一客户端。有意思的是，虽然它说是为了 GoToSocial 打造，但是一些功能明显 GoToSocial 就没有，比方说用户级屏蔽域名功能所调用的 API 从来都没有在 GoToSocial 的源代码中出现过。</p><p>因为 GoToSocial 没有些功能挺蛋疼的，所以我在它们的 fork 里做了些修改，比如添加引用功能。</p><p>现在你可以在 <a href="https://gts.cytrogen.icu/@cytrogen">https://gts.cytrogen.icu/@cytrogen</a> 上看到我的个人主页了！如果想要尝试下我的 Masto-FE GoToSocial 特供版 fork，可以去 <a href="https://masto-fe.cytrogen.icu">https://masto-fe.cytrogen.icu</a> 上体验（说实话和原版区别不大，顶多就是修了点 bug）。</p><h2 id="书籍"><a class="markdownIt-Anchor" href="#书籍"></a> 书籍</h2><p><a id="kobo"></a></p><h4 id="kobo"><a class="markdownIt-Anchor" href="#kobo"></a> Kobo</h4><p>室友的家人给她寄了很多东西。我们二人久违去了躺 Staples 取货。这家 Staples 内部除了有 UPS 外，还有 Amazon 的柜子。当时过去，店里只有取货的人，在货架之间来回转悠的只有好奇的我一人。</p><p>Staples 是一家卖办公用品的连锁店，中文译名叫「史泰博」但我估计没有人会这么叫。总之它除了传统的办公用品，还会售卖电子产品和电脑配件，其中便包括了吸引到我眼球的 Amazon Kindle—— 准确来说，是墨水屏。</p><p>我在将手机屏幕颜色改成 <a href="/posts/b211.html#%E5%8E%BB%E5%BD%A9%E4%B8%8D%E5%97%A8%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BD%A0%E8%AF%A5%E6%8A%8A%E6%89%8B%E6%9C%BA%E8%B0%83%E6%88%90%E7%81%B0%E5%BA%A6">灰阶</a> 后，对电子产品屏幕里的颜色越来越敏感，这得利于 Motorola Razr+ 2024 的屏幕硬件：120% DCI - P3 色域，意味着其涵盖的色彩范围远大于传统的 sRGB 标准，画面色彩会表现出极高的饱和度；pOLED 和 AMOLED 都属于 OLED 屏幕技术；10-bit 色深；3000 尼特和对 HDR10+ 技术的支持…… 听上去很厉害，但我不需要呀！习惯了灰阶后，再调回正常的模式，只会觉得无比刺眼。</p><p>但这个墨水屏，嗯~！很对我的胃口啊！</p><p>可惜它是 Amazon 的 Kindle，我对它印象不太好。在 Kagi Assistant 的帮助下，我挑中了 Kobo Clara BW，总价大概是 130 美元。</p><p>进入设备，会发现它更倾向于让我订阅 Kobo Plus，即每个月花钱租书读 —— 对不起，我在这方面是自由派。连接 Kobo 到电脑，再打开电脑上的 Calibre，便能发现它识别到 Kobo、可以开始传输书籍了。过去没有深入研究 Calibre，这次才知道它也可以转换书籍的格式，例如从 PDF 转换成 EPUB，或者在 Kobo 上支持更佳的 KEPUB 格式。</p><p>除了电子书，Kobo 也可以阅读漫画。只需要将漫画资源下载下来，打包成 KEPUB 就行了。我弄了个「爬取到转换打包到传输」的一站式工具，还在修修改改中，到时候空闲了就写个技术文章讲讲我最喜欢的爬虫环节吧。</p><h4 id="其他评价"><a class="markdownIt-Anchor" href="#其他评价"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/book/2eQRSbSch2wEZwHlb51j9m" target="_blank" rel="noopener noreferrer">大教堂与集市（开源运动的《圣经》，中文版首次出版）</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">在读</span><p class="neodb-comment">开头讲了黑客圈的历史，单单补足历史就很不错。提到了许多过去的技术，值得了解。</p></li><li class="neodb-item"><a href="https://neodb.social/book/4469xHqNzj3rCFiC2hnjKA" target="_blank" rel="noopener noreferrer">The Absolutely True Diary of a Part-Time Indian</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">在读</span><p class="neodb-comment">重新读一遍。读起来很舒服，作者用简单的词汇来表达人物的情绪和心中所想。</p></li></ul><h2 id="影视"><a class="markdownIt-Anchor" href="#影视"></a> 影视</h2><p><a id="撤回是计算机的谎言"></a></p><h4 id="撤回是计算机的谎言"><a class="markdownIt-Anchor" href="#撤回是计算机的谎言"></a> <a href="https://invidious.nerdvpn.de/watch?v=4HWPFd8CQo8">《撤回是计算机的谎言》</a></h4><p>如果你点击这个视频链接，会发现自己被导向到了 <a href="http://invidious.nerdvpn.de">invidious.nerdvpn.de</a>。你也可以切换到这些代理来观看视频：</p><ul><li><a href="http://inv.nadeko.net">inv.nadeko.net</a></li><li><a href="http://yewtu.be">yewtu.be</a></li></ul><p>只需要将域名更换即可。如果你觉得访问 YouTube 也没有关系的话，你也可以将域名换成 <a href="http://youtube.com">youtube.com</a>。</p><p>至于为什么我要做这些事情，是因为 Richard Stallman 的这个观点：</p><blockquote><p><a href="http://youtube.com">youtube.com</a> 需要非自由软件（JavaScript 代码）才能正常使用；在 Google 于 2017 年 8 月做出更改后，如果不运行其非自由的 JavaScript 代码，就无法在典型的 YouTube 页面上看到任何内容。</p><p>为了我自己的自由，我不会运行 YouTube 发送的非自由 JavaScript 软件。我建议你也同样拒绝；直接受损的是你自己的自由。</p><p>然而，如今我可以通过非直接方式访问 YouTube，即通过 invidious 代理，其官方网站是 <a href="http://invidio.us">invidio.us</a>。即使浏览器禁用了 JavaScript，此方法也有效，并且支持下载。但是 Google 正威胁要攻击这些代理。</p><p>为避免让他人误入歧途，请勿使用 <a href="http://youtube.com">youtube.com</a> 或其别名来引用视频。请链接到 <a href="http://invidio.us">invidio.us</a> 或其关联的代理网站。引导人们走向善，而非恶！</p><p>请确保不要选择被 Cloudflare「保护」的代理，因为这会发送其自己的非自由软件。</p></blockquote><p>这些都和视频本身没什么关系…… 回到视频内容来吧！</p><p>使用 Gmail 软件的人或许会意识到，当你发送了一封邮件后，左下角会出现一个「是否要撤回发送」的提示。如果你点击了「撤回」，你的邮件便「撤回了发送」。</p><p>但了解电子邮件底层逻辑的人都知道，这是不可能的：发了就是发了，怎么可能撤回发送呢？难道系统顺着网线找到了还未送达的数据包，把它一脚踹回来了？又或者说，跑到了接收方的邮件服务器内，将这封「被撤回的」邮件删除了？</p><p>这些当然都是不可能的啦。撤回功能的本质是，等一段时间、确定你不想撤回后再发送邮件。</p><p>当你访问 Gmail 的设置页中你会发现，你可以设置「取消发送的周期有多少秒」，比方说 5 秒、10 秒、30 秒…… 只有在这个周期结束后，你的邮件才会被真的发送出去。</p><p>当然这个功能不只是在 Gmail 上有，其他邮件客户端也会有。</p><p>这些只是这个影片的引子，观看它，你会发现这种「技术上不完美」的功能是为什么存在，且如何影响人类的。并且影片本身不无聊，频道主讲话很有趣~</p><h4 id="其他评价-2"><a class="markdownIt-Anchor" href="#其他评价-2"></a> 其他评价</h4><p>本月暂无记录。</p><h2 id="音乐"><a class="markdownIt-Anchor" href="#音乐"></a> 音乐</h2><h4 id="其他评价-3"><a class="markdownIt-Anchor" href="#其他评价-3"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/album/6TustVbqmNsMyJjtbDqksT" target="_blank" rel="noopener noreferrer">月が綺麗ねと言われたい！</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已听</span><p class="neodb-comment">初次听的时候想到了 john，听完后发觉虽然 Miku 的发音调得很像，比如他们都喜欢把 ta 调成 za 或者 ca 音，但整体来说并不是同个风格。在歌曲想要表达的意思上，カササギ 和 john 是相反的：前者大喊道「我想要被你说月亮很美！」，后者则是阴湿的败犬、在看不到的舞台上愤怒地吼叫。</p></li><li class="neodb-item"><a href="https://neodb.social/album/0GaYSOFrstsFQb9jcFs7bj" target="_blank" rel="noopener noreferrer">OK ORCHESTRA</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已听</span><p class="neodb-comment">歌词很有趣，个人也喜欢这种风格。</p></li></ul><h2 id="日记片段"><a class="markdownIt-Anchor" href="#日记片段"></a> 日记片段</h2><button id="details-toggle-diary_sections-1789678111369" class="details-toggle-btn" data-group="diary_sections" onclick="toggleGroupDetails('diary_sections', 'details-toggle-diary_sections-1789678111369', '展开所有', '收起所有')">展开所有</button><details data-group="diary_sections"><summary>三月一日</summary><div class="diary-entry">00:05 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116150994950536224" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>完了，开始忘记自己哪些东西没记录，哪些东西已经记录过。</p><p></p></div><hr><div class="diary-entry">00:43 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116151145832336120" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>可能没记录过的事情：</p><p>过去还在刷小红书的时候看到一个博主发了条用生成式 AI 生成亦或者是辅助编写的文章，被网友甲评论质问现在的人不用 AI 难道就写不出来东西了么，引得争议纷纷。</p><p>博主认为，甲分不清 AI 生成和 AI 辅助写作，是个傻蛋，说话毫无意义，况且甲说话也像 AI 生成 —— 就我而言看不出来，博主所说的话也自相矛盾了。不过这不重要，人身攻击是不可取的，也没有什么对话是无意义的。</p><p>网友乙借此内涵甲，说他一定是大量使用了 AI 聊天机器人才能看出来，因此这样的甲没有资格说博主。我认为这不冲突，「使用 AI 聊天机器人」和「只能使用 AI 聊天机器人生成来写作」是两码事。</p><p>网友丙则认为，使用 AI 润色过的文字会更美丽 —— 这是我主要质疑的点，AI 写的东西是美丽的吗？博主的那篇文章，除了让人想到「这是 AI 生成的」，会让人觉得「写得好」、「写得美丽」吗？就连评论区里，也会有人用 AI 生成的文字评论博主，用的还是 GPT 5 系列的模型，只有满满的爹味儿。但还是有人用 AI 生成的文字再度回复，来表示自己被说中了、互相安慰。</p><p>整个评论区除了诡异，我看不到「美」。</p><p></p></div><hr><div class="diary-entry">00:53 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116151181927833515" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前段时间回家，母亲跟我分享她在厨房看到的事情：家里厨房地上有个塑料桶，平日主要拿来…… 装鱼，因为父亲是个从来不空军的钓鱼佬。</p><p>咪咪猫和幸运狗混熟了，偶尔会打在一起，其中咪咪猫最喜欢玩的是幸运狗的尾巴。这次，它躲在了这个桶里，为的就是等幸运狗来厨房时，跳出来揍幸运狗一顿。于是它睁大眼睛等啊等，等啊等…… 也没有等到幸运狗来，没劲儿地跳出桶来走掉了。</p><p>而这一切都被一个人类看在眼里……</p><p></p></div><hr><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://m.otter.homes/@Cytrogen/116150121757862637">↩ 续前文</a>        </div> 01:18 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116151281164773356" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>其实最让我感觉可怕的新知识是，淡啤酒在常喝酒的人口里是甜的 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/019/313/original/1679206d77bf4d95.png" alt=":bear_fright:" loading="lazy"> 我闻这东西是苦的酒精味儿，喝这东西也是苦的酒精味儿。</p><p>师傅的解释是，习惯了酒精味道的人，才能够喝到酒精背后其他的味道。</p><p>嗯…… 对于我这样的，或许半辈子后才能到这个级别吧。主要是因为不喝酒是件好事，前段时间去世的一位亲戚某种程度上来说就是喝酒喝没的。</p><p>身边的人总是认为长大后必须学会喝酒，其实都是为了预防酒桌文化。不过有时候也会想，我舔了口酒后然后火速倒地晕过去，是不是也可以有效预防酒桌文化。</p><p>说到酒桌文化，又会想起自己作为山东人，家里从大到小都不能喝酒呢。现在尝了下啤酒加酸梅粉的配合，据说可以去除一些啤酒自己的苦味儿。苦味儿感觉还在，反而是头开始昏昏沉沉了起来。</p><p></p></div><hr><div class="diary-entry">01:33 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116151341855899288" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我订阅的一位博友开发了一个给孩子提供游戏的网站：kidsgame.online</p><p>虽然说初心不错，不过为什么节奏盒子打开后是 Sprunki <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/019/313/original/1679206d77bf4d95.png" alt=":bear_fright:" loading="lazy"> 真适合小孩子吗。</p><p>在中国，我访问的游戏平台都是例如 4399、7K7K 这种。它们虽然游戏很多，但是弊端也很多：其中我认为很严重的是早期的审核不严格，以及无版权搬运游戏。</p><p>之后来美国，用 Cool Math Games 会多些，再就是 Nitrome—— 我的名字或许也借用了它们的几个字母？</p><p>因为家里不仅有小孩子，还有管不住小孩子使用电子设备的无能家长，就只能让我去管妹妹游玩什么游戏、看什么电视……</p><p></p></div><hr><div class="diary-entry">15:38 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/933868154024800266" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>喜欢的哥斯拉 😈</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/c7Rq5QRiwlxM/CbItm9ldybkcfWc3zbkSTBByfjWDNeTWnKvIfCEQ.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">23:23 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116156493064994983" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>懒得空闲，溜出来玩。平时会和我一起出门的朋友今天不知道为什么，意外地安静，让人担心。</p><p>说是出来玩，其实就是去常去的游戏厅。不过这家游戏厅所涉及到的玩家群体，这些天听到了一些不好的传闻，例如造谣传谣、偷拍玩家并且在小群体内传来传去…… 实在是觉得糟糕。</p><p></p><blockquote class="diary-thread-reply">23:33 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116156532882090597" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>为什么商场地板上满地都是米田共？？</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>三月二日</summary><div class="diary-entry">00:09 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116156671769260077" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天被师傅吐槽我和室友的名字听上去都很霸气，倒是让我想起先前一同做项目的组员表达过的一个观点。他发现中国父母很喜欢给男孩子取「希望他们未来是什么样」的名字，而给女孩子取让他觉得很漂亮、来自大自然的名字。因为羡慕，所以他「拿走」了我名字里他喜欢的文字，然后把他名字里不喜欢的文字「给」了我，也是很任性了。</p><p>当然他说的并不是事实，许多女孩子的名字里也蕴含着父母的期待 —— 至于这些期待是不是件好事，我想每个人心里都有着不一样的回答 —— 例如室友的名字，就有着她不喜欢的期待，遂长大后改成了自己想要拥有的特质。</p><p>我的名字里也有着我不喜欢的地方，或许未来会考虑改掉。</p><p></p></div><hr><div class="diary-entry">21:11 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116161635729788279" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>为了探索不会涉及到 Google 这种大公司的前提下，还能如何听音乐这一问题，姑且将 YouTube Music 的订阅取消了。</p><p></p></div></details><details data-group="diary_sections"><summary>三月三日</summary><div class="diary-entry">19:44 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116166956692345179" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>What's wrong with the NY temperature? It was literally getting warmer a few days ago, but now it's freezing cold and raining a few snowflakes at the same time, and next week is expected to get hotter again……what?!</p><p></p></div><hr><div class="diary-entry">21:09 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116167289597353594" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>People should tell me Pho pronounces similar to FARR, not FO.</p><p></p></div></details><details data-group="diary_sections"><summary>三月四日</summary><div class="diary-entry">02:34 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116168569304819085" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我好喜欢 Gboard 的 Emoji 合成功能…… 好可爱。可惜我不用 Gboard 了。</p><p></p></div><hr><div class="diary-entry">02:45 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116168611107545991" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>母亲：妹妹数学考了 60 分。</p><p>妹妹：No I didn't.</p><p>我：<em>Who's the imposter</em> <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/109/219/original/0caaf7aad0f68a72.png" alt=":Shiropuyo_AmongUs:" loading="lazy"> </p><p></p></div><hr><div class="diary-entry">20:52 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116172883698100244" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>脑海里总是想着过去看到过一个文章，说作者自己发明了个手指游戏。说是手指游戏，如果没记错的话更像是数学游戏。然而我并没有记下来这个游戏的玩法，只记下了「我看到过这个文章」。</p><p></p></div><hr><div class="diary-entry">22:18 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116173221759111487" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>上个打工店总算把工资给我结干净了 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/003/207/original/6b304c843f41f156.webp" alt=":ottersgottaott11:" loading="lazy"> </p><p></p></div></details><details data-group="diary_sections"><summary>三月五日</summary><div class="diary-entry">00:54 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116173837148792708" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>总感觉自己做了很多梦，隐隐约约梦到雪山，地牢，收杀掉的人的孩子为徒、长大后复仇等等戏码。</p><p></p></div><hr><div class="diary-entry">01:20 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116173940403241463" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>很不想承认但是，Mastodon 的表情符号面板太小，我看不清…… 目前的解决方式是，把整个页面放大到 200%。就是会显得我像个老人家。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">带有「杀」等描写。</summary>        <div class="diary-cw-content">14:15 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116176985341748275" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天的梦有着恐怖怪谈。快醒来的时候，梦到一个可怕的女人，不仅要杀我，还想要自杀。我拼命阻止她，但每次掉以轻心的时候都会看到她拿着刀要终结自己。她好像怀孕了，杀人和自杀的目的貌似是为了信仰，也就是邪教，但这个邪教的日本味儿更冲一些。梦中印象最深的是我从身后握着她手上的刀，苦苦相劝，但手刚松开一点，她就拿着刀要刨开自己的肚子。幸好刀有点钝，没让她得逞。</p><p>这个梦之前我好像梦到有人在博文里引用了我的博文 —— 呵呵呵…… 说不开心肯定是假的。</p><p></p></div>      </details></div><hr><div class="diary-entry">21:48 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/935410733601923095" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>はちみつ舐めると、足が速くなる～</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/hsTEWh5upllR/BDYcm0fvBwBcv3GAay6gPF4fQbiztCqTvxCmRGly.png" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>三月六日</summary><div class="diary-entry">17:41 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116183458219911448" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>父母忽然决定要卖旧车、买新车。原本不太爱说话的父亲在提及车的时候，在群聊里自言自语了一大堆，惹得母亲心烦，叫他做人低调点。或许是母亲真的看不懂父亲说的各个术语吧，她也开始询问 ChatGPT 问题，然后将它的回应粘贴到群聊里。为什么要说「也」，因为父亲也没少跟 ChatGPT 聊过天。</p><p>好笑的点在于，就「Premium 和 Luxury 哪个是高配哪个是顶配」一事，二人吵了起来，体现出来的形式是互相贴 ChatGPT 的回应截图。</p><p>室友经常说，一个东西火不火可以通过自己的父母知不知道来看出，如果他们还用的话那就意味着更火了。例如 OpenClaw，还是室友的父亲提起我才知道的。</p><p></p><blockquote class="diary-thread-reply">03-08 22:09 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116195837733472148" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>好吧，不只是父母在聊，店里的顾客也是天天聊，无论是小的还是老的。</p><p></p></blockquote></div><hr><div class="diary-entry">21:10 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116184281760502888" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>捣鼓了一会儿 2x2 魔方，嗯，玩不明白呢…… 我总共买了 5 个，到货后才发现没有基础的 3x3。</p><p></p></div></details><details data-group="diary_sections"><summary>三月七日</summary><div class="diary-entry">05:03 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116186139242259140" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这些天在吃羊肉，因为牛肉有点贵，在我心目里也没有羊肉好吃。家附近的超市里售卖的羊肉部分并不算多，其中就有绵羊的腿。吃它的时候会想起来初中一年万圣节，英语老师为了符合当天的主题，让我们阅读的 <em>Lamb to the Slaughter</em>。</p><p>这样说来，中国的「一头撞死在冻豆腐」上也是差不多的故事吧。</p><p></p></div><hr><div class="diary-entry">05:07 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116186156945729183" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>朋友今天去参加了一个活动，在那里认识了几个来自中东的空姐…… 难民。她们给朋友看了几张照片，说她们家的那栋楼里貌似有美国间谍。那天，她们看到窗外出现了一个无人机，精准地飞进了那个间谍的房间，然后爆炸了 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/019/313/original/1679206d77bf4d95.png" alt=":bear_fright:" loading="lazy"> </p><p>除了自己家被炸外，她们工作所在的机场也被炸了。不得以，她们只能逃到美国来。</p><p>好可怕。</p><p></p></div><hr><div class="diary-entry">05:19 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116186204139029923" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>朋友前几天受邀去参加了个讲座。当天早上他问我来不来，我说我讨厌聚众、不去。讲座结束后，他告诉我说那个讲座里有人讲了「去中心化」，说 Nextdoor 不好，想要开发一款去中心化的类 Nextdoor 应用软件。</p><p>我在意的点有二：首先我过去也跟这个朋友推荐过去中心化的想法，这个二货是个「如果对方不是自己觉得厉害的人的话，就会默认对方说的话都是废话」的家伙，所以并没有听进去，还觉得我魔怔了。真讨厌啊！</p><p>其次 Nextdoor 是一个超本地化的应用软件。如果要去中心化的话，会有很多矛盾的点吧，比方说身份验证、隐私保护。</p><p></p></div><hr><div class="diary-entry">05:24 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116186222299086720" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>家里人普遍对我有种控制欲，大半夜的给我打电话，我没接，就开始在公众面前计划找警察，私下却说我是一个「可怕的人」。</p><p></p></div><hr><div class="diary-entry">15:19 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/936037689137434703" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>一位朋友想出的天才拍照技巧，在杯子下方叠手机。</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/Z4ZNgUXqAj3I/n3LDD9CSgTUe9qZBV6YLw9Ia7jFrmPGdL1U7C8K9.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/oyHLR0hG0qdQ/XWZ5ZtrPFfDT7pTjGMLfEFdgg0prSyzfdDN0EuOG.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">15:20 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/936037903306928212" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>P1 是我做的假酒，因为都是水。</p><p>P2 是可乐。</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/6UIxa83h6Ylg/opuRq5D9nRza6TdmA5wwujIzgYawqbFqdNmUnKZc.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/LwSzJyXFzcU1/7Rlrhj5qbJe7rCnjfgmS6z1IUbRYDJ9stoKXNUin.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">19:07 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116189460046293071" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>学习酒杯。因为不是酒，所以就不在酒的那条串里回复了。酒的那条串在 <a href="https://m.otter.homes/@Cytrogen/116150231624377683" target="_blank" translate="no"><span class="invisible">https://</span><span class="ellipsis">m.otter.homes/@Cytrogen/116150</span><span class="invisible">231624377683</span></a> 会很缓慢缓慢更新……</p><p>说回酒杯，详细的知识可以看 <a href="https://www.homestratosphere.com/types-of-bar-glasses/" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://www.</span><span class="ellipsis">homestratosphere.com/types-of-</span><span class="invisible">bar-glasses/</span></a></p><p>总之，酒杯有很多种，细分下去也能分很多种。这家店里大致有：</p><ul><li>beer glass</li><li>wine glass</li><li>shot glass</li><li>rocks</li><li>Martini</li><li>Margarita</li><li>High ball</li><li>Old fashioned</li><li>Hurricane</li></ul><p></p></div><hr><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://m.otter.homes/@Cytrogen/116150231624377683">↩ 续前文</a>        </div> 20:23 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116189758140108581" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>马提尼（Martini）分两种：琴酒为基酒，或者是伏特加（Vodka）为基酒，两个都以苦艾酒（Vermouth）作为辅助。</p><p>调酒时，基酒至少要 2 盎司，最多 3 盎司，给超级酒鬼朋友们。辅助用的酒则在 0.5 到 1 盎司之间不等，看情况吧。</p><p>调酒前，先找到马提尼杯是否存在。如果不够冷，需要提前放一杯冰块进去冷却。接着拿出调酒用的杯子（忘记叫什么了总之是个有点大的宽玻璃杯），放入一勺冰，用拿毛笔般的手势拿搅拌棒，搅拌个几下让杯子冷却，然后把水漏干净。</p><p>接下来就要开始调酒了。将计算好盎司量的基酒和苦艾酒倒进去，再用搅拌棒搅拌个半分钟 —— 不用那么久也可以，只要摸着杯沿觉得够冰就好了，太久冰块都要融化成水了。</p><p>马提尼是没有冰块在里面的，保险起见建议多拿漏斗，把酒倒到马提尼杯中（先前冷却用的冰块都要倒掉）。最后收尾需要用到橄榄、柠檬或者橙子的皮，任意选吧，反正都是削出皮来，将皮里的油拧到酒上，然后拿着皮沿着杯口摸一圈、将皮丢入酒中。</p><p>相同的做法还能做曼哈顿（Manhattan），区别在于曼哈顿的基酒是威士忌（Whiskey）、需要用到有颜色的苦精（bitter），收尾可以用马拉斯奇诺（Maraschino）樱桃。</p><p></p><blockquote class="diary-thread-reply">03-17 18:27 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116245926445529447" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>补充：苦艾酒大致有两种，即有颜色的和没有颜色的。如果是基酒本身就是透明的，那使用没有颜色的苦艾酒，成品会更好看些；反之亦然，用有颜色的苦艾酒搭配有颜色的基酒。</p><p></p></blockquote></div><hr><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://m.otter.homes/@Cytrogen/116150231624377683">↩ 续前文</a>        </div> 20:47 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116189853646635175" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>高球酒（Highball）简单来说，是基酒加上大量的冰和非酒精饮品，这家店里大致分为三类，实际有更多的种类：</p><ul><li>Whiskey Soda</li><li>Jack Coke</li><li>Gin and Tonic</li></ul><p>一、Whiskey Soda.</p><p>顾名思义，威士忌和气泡水（seltzer water）混在一起。不得不说，我好讨厌气泡水，喝起来有股苦味儿，不过算是可乐等含气饮品的可选健康替代之一。</p><p>高球酒有自己的高球杯，看上去就像是个普通的长玻璃杯。直接将基酒倒 2 盎司进去，然后装满冰、把气泡水倒满。收尾可以用半片橙子，中间切一小刀，挂在杯沿。</p><p>二、Jack Coke.</p><p>RE：<a href="https://www.geedea.pro/essays/jack-in-fitness/" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://www.</span><span class="ellipsis">geedea.pro/essays/jack-in-fitn</span><span class="invisible">ess/</span></a></p><p>哼哼，Jack 列表还可以继续延伸下去……</p><p>Anyway 这个指的是威士忌和可乐的混合。不过 Jack 特指 Jack Daniel's 牌子的威士忌。如果是其他牌子的威士忌的话，叫 Whiskey Coke。</p><p>还有个变种叫 Bourbon Coke，用的是波本威士忌（Bourbon Whiskey）。</p><p>三、Gin and Tonic.</p><p>依然是顾名思义，琴酒和汤力水（tonic water）。汤力水我没喝过，不知道是什么玩意儿。貌似是调酒专用的饮品。</p><p></p></div><hr><div class="diary-entry">21:15 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116189964105676425" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://theticker.org/18214/opinions/wi-fi-issues-unacceptable-for-first-day/" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="ellipsis">theticker.org/18214/opinions/w</span><span class="invisible">i-fi-issues-unacceptable-for-first-day/</span></a></p><p>Baruch and CUNY's Wi-Fi is weird in multiple aspects: one is stated in this article, which is frequent password changing, and another one is HOW DO I CONNECT TO WIFI ON A LINUX DEVICE.</p><p>I have been setting up my <code>nmcli</code> configurations for two days and it just doesn't work. My Android phone also couldn't connect to Wi-Fi, until two help desk members spent half an hour helping me to do so (thank you). On the other hand, I believe it will take more time and effort for them to figure out how to have my Linux device connected to the school Wi-Fi, since following the correct procedure for an Android phone does not work on my Linux device for an unknown reason. It's just effort-consuming, making me have to turn on the hotspot every time I'm on campus.</p><p>Weirdly, besides the regular Wi-Fi, which requires a domain, authorization, and the like, either Baruch or CUNY has turned on another Wi-Fi that only needs to be redirected to the CUNY login portal and get connected. However, it does not work on my devices either.</p><p></p></div><hr><div class="diary-entry">21:41 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116190063151122149" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>家庭组里的一个朋友火速购买了《杀戮尖塔 2》。因为我们时间戳各不相同，可以趁他们睡大觉的时候悄悄爬塔玩。目前还在熟悉阶段，因为我第一代 a20、隐藏 BOSS 都没打过……</p><p></p></div><hr><div class="diary-entry">21:47 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116190088579055934" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>小时候讨厌逛街，去博物馆、美术馆和动物园，因为每次去都是照顾亲戚和小孩子。现在为了自己考虑，会发现这样走走很不错。尤其是去了不知道多少次的美国自然历史博物馆，会发现比想象中有意思不少。</p><p>动物园的话，纽约市最大的动物园貌似就是 Bronx 那家，只去过一次，印象里有缆车，还有大象。</p><p></p></div><hr><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 三月七日 21:15</span>            </div>            <div class="diary-quote-preview">RE: https://theticker.org/18214/opinions/wi-fi-issues-unacceptable-for-first-day…</div>          </div>22:24 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116190232891990524" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Unrelated to the Wi-Fi, but related to the CUNY login portal.</p><p>Seems like they have an i18n feature for their portal, which is nice! The un-nice part of it is that if my browser's language is not included in their supported languages, I cannot use the portal. I have to change my browser's language, just to use the login portal, and the sad part is, all the CUNY services require a login before accessing. Can't you set English as a default or fallback option or anything?</p><p></p></div><hr><div class="diary-entry">23:21 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116190459760365452" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这又是 MTA 的哪些人的小巧思，给原本透明的门加上金属的壳。我的车费就拿来干这个使吗？</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/116/190/456/397/462/496/original/75a7fb70de2a047c.jpg" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>三月八日</summary><div class="diary-entry">00:28 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116190722861694223" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>过去认识一个人，衣服只穿紧身的，原因是他有自闭症，对声音异常敏感，普通的衣服穿在身上会有着摩擦的声音，让他心烦、无法集中。</p><p>他也符合刻板印象里的自闭症患者，有着很高的智商，想法也是天马行空。比如他学习中文时，会先从汉字的偏旁开始学习，从而搞清楚汉字是如何组成的，再慢慢学习更抽象的概念。又比如，他将一个土豆送到过外太空……</p><p></p></div><hr><div class="diary-entry">16:47 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116194570124586053" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Bánh Mì，好吃的越南面包。用的是好吃的法棍，真好吃。今天我吃的是牛肉馅料的，酱料有点偏甜辣。不过里面居然有黄瓜，咬下去差点以为是腌黄瓜。我讨厌腌黄瓜。</p><p></p></div><hr><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://m.otter.homes/@Cytrogen/116150231624377683">↩ 续前文</a>        </div> 20:13 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116195381165073654" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天学习了制作本楼咖啡。「本楼」这个说法不清楚是哪里传来的，总之在英语说是 <em>house special</em>，也就是「这家店特色的」的意思，常用于美式中餐餐馆。说是「特色」，但在这种餐馆里已经公式化了，比方说「本楼炒饭」基本上就是店里所有能炒饭的材料都拿去炒。不过我现在打工的店里，说是特色咖啡，我认为应该就是特色咖啡。</p><p>底子用的是浓缩咖啡，混合了炼乳（这种做法貌似就是越南咖啡），还自己用重奶油和炼乳打了个奶油，浇在咖啡上方。奶油上撒一些黑糖粉，用喷火器烧上一会儿，就会散发出浓郁的焦糖味儿，连我这个不喜欢咖啡的人也觉得好喝！</p><p>照片见：<a href="https://pixelfed.feddit.social/i/web/post/936316500055355393" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="ellipsis">pixelfed.feddit.social/i/web/p</span><span class="invisible">ost/936316500055355393</span></a></p><p>不对这个串不是说酒的吗。咳咳，和咖啡有关的酒确实存在。今天就学习了「浓缩马提尼」。这是伏特加马提尼的一个变种，「浓缩」指的是 espresso，也就是浓缩咖啡，用来代替苦精、给酒添加更丰富的味道。</p><p>虽然我现在不管怎么喝，都只能喝到酒精浓厚的苦味儿就是了……</p><p></p></div><hr><div class="diary-entry">20:23 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116195421373622576" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>中文课的讨论里，有一些让我不满的地方在：</p><p>一、车轱辘话太多，每次看他人的回复，只感觉仅是将对方的观点用另一种说法阐述了一遍。一个人起了个头，剩余的人都在重复这个观点，那其他观点就没有人注意到了吗？我很不喜欢这样，让我无从回复。</p><p>二、不认真看教授附的影片的人太多。影片整体的观点是 A，我不知道为什么大家都要说影片阐述的观点 B 很对，牛头不对马嘴的 —— 影片根本就没有观点 B 啊。再接上第一条，得，又是围绕着观点 B 的车轱辘话，轱辘轱辘…… 转起来。</p><p>三、用生成式 AI 生成回应，忘了把 Markdown 星号删干净的，论坛页面把所有的文本都渲染成粗体，闪瞎我的眼睛。</p><p></p></div><hr><div class="diary-entry">20:52 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116195536184676113" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>还没有写博客之前，需要就 AI 绘画一事吵架（顺带一提我的观点是 AI 绘画不好，人可以画出更好的画来，我也讨厌老是看到原本画得不错的小画家觉得 AI 绘画更好、完全转向用 AI 生成画作，就算标注了我也不喜欢）。写博客后，需要就 AI 写作一事吵架。现在因为 Vocaloid 圈内出现了一首热度不低的、制作时涉及到 AI 生成的歌曲，又不得不去思考一下 AI 编曲。</p><p>实际上我很难想象有人因为这首歌好听，认为反对这首歌的人都是傻蛋 —— <em> 有歌听不就行了</em>，尽管这首歌的前奏拍子与我喜欢的一位 P 主的知名歌曲的前奏拍子近乎一致。就算不是 AI 编曲，至少也有抄袭这一罪名了。去年就有一首抄袭而被声讨的 Vocaloid 歌，为什么这首歌就不能被声讨？</p><p>上述因为抛开了 AI 编曲这个事实，所以只能算一层。回归到 AI 编曲这件事情，原作者犯了两个错误：一是使用了 AI 编曲，二是用了还不标注 AI，且用来参加原创比赛 —— 难不成你还是「原创 AI 歌曲」？</p><p>为了自己喜欢的歌，绞尽脑汁想出的各个反驳点都是可笑的：比方说 Vocaloid 就是 AI，凭什么 AI 编曲就不行 —— 这或许就是为什么说词一定要说完整吧。AI 本身就是个大概念，现在人们常说的 AI 要不然是生成式大语言模型聊天机器人（ChatGPT），要不然就是生成式大语言模型（GPT）。但真要说，神经网络也算 AI 的一种。Vocaloid 是通过学习声源主人的发声，从而让 Vocaloid 发出近似声源主人的声音 —— 它依然是工具，就算是被称为 AI 的 SV，用的也是神经网络的一种。况且 Vocaloid 其实算乐器的一种，类似于做了个电子工具来模拟现实吉他的声音。因为不会替代人，也不涉及盗取他人作品和抄袭等问题，自然也没问题了。</p><p>还有人表示为什么我们无法接受 AI 编曲，但是可以接受 AI 声音，这依然是「起」和「终」的问题：起在于市面上常见的 AI 声音都是企业自行训练的，这点和 Vocaloid 相似；终在于它代替的依然是工具，即 AI 声音之前的机械音，帮助不想要发声或者没有麦克风的朋友们拍视频。</p><p></p></div><hr><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://m.otter.homes/@Cytrogen/116150231624377683">↩ 续前文</a>        </div> 22:22 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116195888980844634" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>普罗赛克（Prosecco）是一种意大利的起泡酒（sparkling wine），是红酒的一种。大家熟知的香槟（Champagne）也是起泡酒。起泡酒使用的红酒杯（或者说高脚杯）是窄窄、细长的。</p><p>普罗塞克口味爽口，是酸甜味儿的（不过我对酒精很是敏感，只能喝出恶心的酒精味儿）。</p><p>浅尝了几口，现在很难受……</p><p></p><blockquote class="diary-thread-reply">03-17 18:41 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116245981887851707" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>普罗塞克的瓶子，如何打开也有说法。</p><p>瓶口会有锡纸保住，可以选择沿着虚线撕开锡纸。专业的调酒师则会直接将锡纸下方的铁丝开关拔出来、扭开。扭铁丝开关时，一只手的大拇指一定要放在瓶盖上，以免它被气吹飞，也要避免将瓶盖面向客人或者自己的下巴。</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>三月九日</summary><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 三月四日 02:34</span>            </div>            <div class="diary-quote-preview">我好喜欢 Gboard 的 Emoji 合成功能…… 好可爱。可惜我不用 Gboard 了。</div>          </div>00:15 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116196330934576988" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>发现了这些网站：</p><ul><li><a href="https://emojikitchen.com/" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="">emojikitchen.com/</span><span class="invisible"></span></a> 没找到源码 </li><li><a href="http://emoji.supply/kitchen" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">http://</span><span class="">emoji.supply/kitchen</span><span class="invisible"></span></a> 源码在 <a href="https://github.com/alcor/emoji-supply" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="">GitHub.com/alcor/emoji-supply</span><span class="invisible"></span></a></li><li><a href="https://emojikitchen.dev/" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="">emojikitchen.dev/</span><span class="invisible"></span></a> 源码在 <a href="https://github.com/xsalazar/emoji-kitchen" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="ellipsis">GitHub.com/xsalazar/emoji-kitc</span><span class="invisible">hen</span></a></li></ul><p>原来这个 Emoji 合成功能叫做 Emoji Kitchen。稍微了解了一下，这些合成的 Emoji 都是存放在服务器上的静态文件，可以花时间将它们都下载下来。</p><p>如果可以有个专门发 Emoji 和 Emoji Kitchen 的输入法的话，那我就可以将 Gboard 移除我的输入法列表了。</p><p></p></div><hr><div class="diary-entry">01:55 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116196726279976679" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我想吃驴肉，但是在纽约市没有见到过卖的。在网络上查，也只是找到一个个菜单里根本没有驴肉、招牌还硬说自己卖驴肉的店。好生气。</p><p></p></div><hr><div class="diary-entry">03:58 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116197211037762528" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我又买「电子垃圾」了…… 像个小学生一样。</p><p>之前买的黑色表带款，给的是 Pulsemon，不过一次看电影的时候落在电影院里，找不见了……</p><p>这次买的是 Gabumon。亚马逊上还有个 Gammamon 的，但要价 175 美元，骗钱喔。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/116/197/201/934/377/491/original/b125940850beba45.jpg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">03-10 15:00 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116205473603079750" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Active 活动类型的 Gabumon 进化成了 Lazy 类型的 Drimogemon…… 现在要是做高频运动，反而还会让 Drimogemon 感到沮丧，得配合 Lazy 类型的数码兽的活动偏好。</p><p>再就是，这款游戏要是数码兽受伤了、玩家却在做高频运动的话，会导致数码兽死亡。这样看来，游戏性要比「健身手环」的实用性高上不少。不过这本来就是给小孩子玩的吧。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/116/205/420/398/329/351/original/a0333db562d7aded.jpg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">03-10 21:02 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116206898148304206" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说明书上说，只要手环靠近任何 NFC 源就可以触发战斗。于是我试了下触碰手机，结果召唤来了 Jaeger Dorulumon…… 两下被击败。</p><p>不同活动类型的数码兽，暴击的回合都不相同，Lazy 类型最慢，要等到第 5 回合。被击败后，会按照对方比我方的数码兽高多少级还是低多少级，来决定扣除多少 Vital Value。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">22:27 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116201570673022136" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>微信创建群聊也要我认证吗…… 生气了。</p><p></p></div><hr><div class="diary-entry">22:40 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116201622591671924" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>I thought you were becoming blue.</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/116/201/618/433/964/093/original/d730c2517b39ecf9.jpg" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>三月十日</summary><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 二月十六日 16:17</span>            </div>            <div class="diary-quote-preview">逐渐苏醒了前几年为什么不回家过节的记忆。春晚放到军人那段时，母亲眼中流露着羡慕之情，严肃地告诉我和妹妹未来找男朋友一定要找当兵的：帅气、有气质、品行好。一位亲戚…</div>          </div>14:14 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116205292309368060" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天母亲愤慨地说，「这个时代的孩子都怎么了，真的是一代不如一代了。」</p><p>让她如此有感而发的，竟是一个长发男生被父母交给「教官」「管教」、从而重新获得「阳刚之气」的事件！</p><p></p></div><hr><div class="diary-entry">17:45 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116206123702021167" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>教我调酒的师傅如是说道：</p><blockquote><p>酒是骗人的，调酒也是骗人的。</p></blockquote><p></p></div><hr><div class="diary-entry">18:01 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116206187907711926" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>邮箱的使用有时让我觉得有些割裂。</p><p>我认为邮箱的重点就在于「非即时」，是可以想什么时候发、就什么时候发的。所以我用个人邮箱发邮件时，基本上是不会在乎现在几点，回复时更有可能拖延个几天再回。</p><p>但是在工作中，邮件的使用方法就更像是即时通讯软件，不在特定时间范围内还不能发。例如某个客户选择凌晨给我发邮件，虽然夜猫子的我看到了，但按照规矩就是需要等、或者设置定时发送，在早上七八点回复。理由是不在工作时间回邮件，会让对方认为公司存在压榨现象，亦或者是觉得你不够专业、生活作息很差，又或者会嫌你烦、大半夜给我发什么发。</p><p></p></div><hr><div class="diary-entry">18:06 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116206206066050101" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我其实想要体验一下，没有手机的生活。</p><p>灵感参见：</p><ul><li><a href="https://news.ycombinator.com/item?id=45018773" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="ellipsis">news.ycombinator.com/item?id=4</span><span class="invisible">5018773</span></a></li><li><a href="https://erne.bearblog.dev/260225/" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="">erne.bearblog.dev/260225/</span><span class="invisible"></span></a></li></ul><p></p></div><hr><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 三月九日 03:58</span>            </div>            <div class="diary-quote-preview">我又买「电子垃圾」了…… 像个小学生一样。之前买的黑色表带款，给的是 Pulsemon，不过一次看电影的时候落在电影院里，找不见了…… 这次买的是 Gabumon。…</div>          </div>20:12 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116206700092276147" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>该手环有 NFC 功能，可以和移动端 app 连接，达成数据传输的效果。根据说明书所说，插上 VS 卡后还可以和其他手环互相点一下、进入战斗。</p><p>之前以这个「NFC 进入战斗」的功能为灵感，想做一个带有 NFC 功能的手机可以互相点、进行社交的 app 玩。不过我没有第二台安卓手机，无法测试，也就不了了之了。</p><p>再加上我的设计有问题。我的想法是你可以在手机里养宠物。它在没有涉及到 NFC 的情况下，只会是带有宠物培养系统的、类似于番茄钟那样的 app。当你和其他人的手机通过 NFC 连接，相当于你们带着宠物一起出来玩，是宝贵的社交时间。无论是哪个，这期间都会鼓励你不使用手机。</p><p>但在开发的时候慢慢想到，这些功能其实没有太大的用处，或许单纯只是我想要用 NFC 玩出点花样来的、僵硬的产物 —— 你都出去社交玩了，还需要一个 app 控制你、给你奖励吗？</p><p>然后就是，我没有使用控制设备时间的 app 的习惯在。如果要开发的话，肯定只会做出漏洞百出的烂东西的。</p><p></p></div></details><details data-group="diary_sections"><summary>三月十一日</summary><div class="diary-entry">12:53 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116210639799630379" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近天气好热，明明上周还是上上周刚下过一场雪。昨天店里很是闷热，没多少客人来吃热腾腾的汤面，无聊期间玩起了 OpenStreetMap。说是玩，其实也只是把认识的店的信息补全。移动端分别使用了 Every Door 和 Street Complete 这两个应用。</p><p></p></div></details><details data-group="diary_sections"><summary>三月十二日</summary><div class="diary-entry">00:19 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/937502234616012870" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>伏特加和雪碧。</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/2TlshPxmEJgP/q2oJCEIKH4xcZhBfHjNQ3N6yQuJrfJAnEGtMGPoU.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">00:30 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/937505096363905117" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Another coffee martini.</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/B1GXBem07lKC/xVRZDCSmAIqItJzqLW9Of8zpDwxW5V1Am6YanTVI.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">01:29 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/937520028570734809" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>刚洗了毛的幸运狗。</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/9vrWQuj3tAyx/8CZQhBBlDxtgFk6COlOmOvOjvTgfFi0kHuXNyfPq.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">01:51 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116213698557800726" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>店里来了个自来熟的阿姐，塞给我这个 3D 打印的产物，是个小观音？</p><p>师傅和她聊了起来。她原先是个基督教徒，之后因为各种事情，接受了佛教，想要将佛祖的事情传给其他人。</p><p>不过他们聊天的时候，聊到了印度教的许多神明到底都是谁。我的脑子开始想：</p><blockquote><p>印度教和佛教有着一定的区别其中我能记住的印度教的神明有湿婆也就是三大神之一的破坏神还有首陀罗但忘了他是谁了印度教有点像希腊和北欧神话有着许多神明你知道克苏鲁神话吗其作者便参考了印度教的三大神结构巴拉巴拉。</p></blockquote><p>但我什么都没有说。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/116/213/665/408/259/665/original/0df61e95c5b13df6.jpg" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>三月十三日</summary><div class="diary-entry">05:10 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116220143072359784" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>自己尝试一个人调了点酒，感觉如果不享受去喝它的话，是无法想出好创意的。跟着网上的食谱走，得到的也只会是一个自己觉得中规中矩的玩意儿。</p><p>但是曼哈顿这东西到底谁喝得下去我想问了。差点没被呛死。</p><p>朋友叫我弄杯 <em>Sex on Beach</em> 给他。它是伏特加跟各种很甜很甜的果汁或者水果 liquer 混在一起，甜得要死。</p><p></p></div><hr><div class="diary-entry">13:56 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116222212034171006" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><a href="https://archive.org/details/animationfactoryessentialcollection" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="ellipsis">archive.org/details/animationf</span><span class="invisible">actoryessentialcollection</span></a></p><blockquote><p>I'm lovin' it……</p><p>Blababababa~</p></blockquote><p>Sweet animations that I used for my videos before. Unfortunately, their website is down for now, which is this: <a href="https://animationfactory.com/" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="">animationfactory.com/</span><span class="invisible"></span></a></p><p></p></div><hr><div class="diary-entry">14:05 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116222244776998307" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前段时间亲手摸到了 Amazon Kindle，也算是第一次亲眼去观察墨水屏吧，让人觉得很喜欢。不过价格就不喜欢了，Kindle 的使用方式也不太喜欢。</p><p></p></div><hr><div class="diary-entry">14:45 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116222401574404888" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>到底是谁写 TypeScript 会充满勇气地写下无数个 <code>any</code> 类型。</p><p></p></div><hr><div class="diary-entry">15:00 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116222462878612643" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想要将 Floorp 的新建窗口直接指向 Kagi 的搜索页面，但在设置里找了许久也没有找到这个选项。上网查询时发现，Firefox 的这个功能曾经被利用过，所以不开放了。</p><p>参见：<a href="https://www.reddit.com/r/Floorp/comments/16t9ts9/change_new_tab_page/" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://www.</span><span class="ellipsis">reddit.com/r/Floorp/comments/1</span><span class="invisible">6t9ts9/change_new_tab_page/</span></a></p><p>不由得想到几年前还不会使用电脑的时候，下载 360 还是什么乱七八糟的东西，开机时会污染我浏览器的设置，将开始页面还是搜索引擎改成 Yahoo 还是啥的。</p><p>修改方式是，在 <code>about:config</code> 里修改 <code>floorp.newtab.overrides.newtaburl</code> 的类型为 <code>string</code> 然后添加 <code>https://kagi.com</code> 链接。再到 <code>about:hub#/features/design</code> 里禁用 Floorp Start、重启 Floorp。</p><p></p></div><hr><div class="diary-entry">16:09 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116222731524347984" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前几天热到怀疑夏天要来了，结果昨天又是下雨和下雪，今天还冷到怀疑人生。</p><p></p></div><hr><div class="diary-entry">17:02 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116222942377036489" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天和一个许久没见的朋友见面，他提到了个东西，我上网查找时 Kagi 给我推送了和关键词相关但没有那么相关的新闻。</p><p>他看到后问我这是什么搜索引擎，我回答说是 Kagi。</p><p>他：<em>You should stop using those weird search engines, just use Google.</em></p><p>我：<em>Google is the worst of all.</em></p><p></p></div><hr><div class="diary-entry">20:02 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116223649977972895" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>I was thinking about this a couple of seconds ago:</p><blockquote><p>Any ways that I can share a YouTube video without actually sharing a YouTube video link?</p></blockquote><p>Then I went on Richard Stallman's personal website because I believed he wrote something about this.</p><p>Luckily, I found this:</p><blockquote><p>For my own freedom's sake, I do not run the nonfree JavaScript software sent by Youtube. I advise you to refuse likewise; what's directly at stake is your own freedom.</p><p>However, nowadays I can access Youtube, by doing it indirectly through the invidious proxies, whose welcome site is invidio.us. This works even if the browser has JavaScript disabled, and implements downloading. However, Google is threatening to attack those proxies.</p><p>To avoid leading other people astray, please don't refer to videos using the host name youtube.com or its aliases. Instead, make a link to invidio.us or one of the associated proxy sites. Lead people to what is good, not to what is bad!</p><p>Just make sure not to choose a proxy that is "protected" by Cloudflare, since that sends its own nonfree software. </p></blockquote><p>Now I can share videos that I found useful, which are unfortunately hosted on YouTube, with other people without having them access YouTube!</p><p></p></div><hr><div class="diary-entry">23:00 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116224349089053682" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这段时间在使用 Kagi 的翻译功能。因为他们提供浏览器扩展，所以使用起来相当方便。</p><p>首先是翻译网站本身，在 translate.kagi.com 上，除了最基础的文本、文档翻译外，还有校对、词典、以及网站翻译功能。</p><p>校对是检查语法和用词的，用起来有点像 Grammarly；词典可以搜索一个单词的详情内容，比方说词源、例句什么的，还可以选择不同类型的同义词；网站翻译目前还在测试中，使用方法是输入一个网址，它会自动访问这个网址并且进行全文翻译 —— 但我发现它无法通过 Anubis，哈哈。</p><p>再来说浏览器扩展。当右键空白区域，出现的是「全文翻译」，这个翻译可以选择「快速」和「最佳」两种翻译质量，看情况选择吧。你也能选择「已翻译」、「双语」和「原文」三种显示方式，其中「双语」的效果类似于沉浸式阅读或者流畅阅读这两个翻译插件。</p><p>选中文本并且右键的话，会出现三个选项：「翻译」、「定义」和「校对」，分别对应翻译网站里的三个功能。</p><p>使用体验整体来看很棒。棒棒滴～</p><p></p></div></details><details data-group="diary_sections"><summary>三月十四日</summary><div class="diary-entry">04:04 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116225545871585173" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>I HATE WINDOWS.</p><p>I came to my parents' home tonight and decided to play <em>Slay the Spire 2</em> on my old computer. It loaded for a supppppppeeeer long time, staying on a white screen for some unknown reason until it finally finished loading, and it turns out it was loading the <em>WiNdOwS 11 uPgRaDe NoTiFiCaTiOn</em> screen.</p><p>Leave it alone; it's a 10+-years-old computer with a Sandy Bridge CPU on.</p><p></p></div><hr><div class="diary-entry">14:28 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116227997302763534" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天回父母家里，睡前没关房间门。躺床上还在迷糊的时候，幸运狗冲进来、扒拉我的床，让我带它去外面上厕所。</p><p>带着它下楼就听到咪咪猫在地下室里喵喵叫，也想出来。最近咪咪猫得猫藓了，下巴烂了一块。我前些天叫母亲买治猫藓的药，她忘了买。她还抱怨说咪咪猫掉毛掉好多。我说你梳毛吧，抓着它死命梳，谁让它是只长毛猫呢。</p><p></p></div><hr><div class="diary-entry">14:43 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116228058085178275" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>母亲跟我说一个表弟找了女朋友，还给我看了照片，顺便像过去那样批判对方的穿着。</p><p>我心里想的是怎么照片说有就有、说看就能看，好可怕喔。你可能在不知不觉间就被不认识的人批评了。</p><p>父母辈相当热衷于拍别人照片然后上传到不安全的网络中，或者是分享给被拍摄者也不认识的人。过去我刚开车上路的时候，就被母亲拍了一段视频传到微信朋友圈。结果被个「媒婆」看到，要介绍一个三十岁的富二代给我，我那时候才刚上大学呢！</p><p>再有一次是我小时候的邻居从我表妹那儿拿到了我的 QQ 号码（我有授权）。我们聊了一阵子后父母又不知道怎么地，知道了这件事情，把我们的照片互相发给了彼此。次日他就主动提起了此事，说看到了我的照片。</p><p>再再有一次是我还在中国上小学时的同学，不知为何有我母亲的微信号，从她的朋友圈里看到了许多我的照片。我一直没退小学的 QQ 群，因为想着要是未来回国了还得靠这个群聊认人，结果反而被他找到了 QQ 号码，厚颜无耻地表示自己有我母亲的微信号、看过我的照片了已经，问我能不能发自拍给他。神经病 ——！</p><p>自过去某个节点之后，我对被拍摄这件事就感到敏感。母亲想要拿手机拍我时，我会勃然大怒，她也不敢说什么，顶多说我脾气差、拍一下怎么了。当然「怎么」了，「怎么」大了！为了我的隐私，就不要拍我吧！</p><p></p></div><hr><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 三月十四日 14:43</span>            </div>            <div class="diary-quote-preview">母亲跟我说一个表弟找了女朋友，还给我看了照片，顺便像过去那样批判对方的穿着。我心里想的是怎么照片说有就有、说看就能看，好可怕喔。你可能在不知不觉间就被不认识的人…</div>          </div>15:14 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116228178547634102" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>攻击他人的外貌会让我认为攻击者的思想低级，以至于不想去和思想低级的人争论。这里的「外貌」可以被替换成其他人们天生就决定的东西，比方说残疾、出身。</p><p>逻辑是这样的：人有许多天生就被决定的事情，这往往是他们无法改变的东西（现代科技倒是已经可以改变一些了）。批判这一方面的事情，只是在一件永远都会胜利的地方上获胜，而 <em>你</em> 会因此获得可悲的满足感。这是懒惰且懦弱的。</p><p></p></div><hr><div class="diary-entry">16:13 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116228410299207851" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>和妹妹出门遛狗，嫌幸运狗走太慢，打算自己跑起来好让它追我，结果被凹凸不平的路绊倒，摔到流血了 2333</p><p></p><blockquote class="diary-thread-reply">16:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116228487757675747" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>本来觉得不痛，现在过了会儿意识到，好痛 ——！</p><p></p></blockquote></div><hr><div class="diary-entry">17:38 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116228744095021614" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><a href="http://digimons.net" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">http://</span><span class="">digimons.net</span><span class="invisible"></span></a></p><p>可以通过这个网站了解数码兽们。</p><p></p></div><hr><div class="diary-entry">17:47 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116228780816669776" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>电子邮箱里全都是营销的破玩意儿。得先舍弃掉一些个人邮箱，然后改用随时都可以被舍弃的、能自动转发的邮箱地址。</p><p>其实会想要体验一下写信寄信。</p><p></p></div></details><details data-group="diary_sections"><summary>三月十五日</summary><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 三月十四日 17:47</span>            </div>            <div class="diary-quote-preview">电子邮箱里全都是营销的破玩意儿。得先舍弃掉一些个人邮箱，然后改用随时都可以被舍弃的、能自动转发的邮箱地址。其实会想要体验一下写信寄信。</div>          </div>02:42 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116230884077065875" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>了解了一下「笔友」。想来过去笔友是个很庞大的群体，例如我父母曾经就是笔友，现在反而稀少了不少。也是互联网的影响吧，调查时发现部分笔友已经进化成了电子笔友，也就是互相发电子邮件，或者使用 Slowly 这种模拟写信寄信的软件。</p><p>查阅过程中发现，寄明信片是一件很正常的事情，不过我这辈子都还没有收到过一张明信片呢。邮票什么的也是近些年需要给政府寄信我才学会使用的。</p><p>如果想要成为笔友群体的一份子的话，首先要解决的就是地址问题了呢。实在是不想要暴露自己的住宅地址，有个方案是租用 PO Box 或者虚拟地址。前者太贵了，一个月足足要二十多美元；后者会扫描收到的信件，虽然一个月降到了十美元，但还是不太行呢……</p><p></p></div><hr><div class="diary-entry">02:44 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116230891221044352" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>坐地铁回家路上看到好多倒在地上的人，不知道是晕过去了还是在睡觉。能够做到不担心不担忧，已然是个成功的冷漠纽约客了。</p><p>这是一件糟糕的事情。</p><p>不过之前朋友好心叫醒一个，反而被追着骂。做人真难。</p><p></p></div><hr><div class="diary-entry">14:10 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116233591354539824" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>用 <code>curl</code> 可以做到一些有趣的事情：</p><ul><li><a href="https://chat.est.im" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="">chat.est.im</span><span class="invisible"></span></a></li><li><a href="https://github.com/TokenRollAI/curl-resume" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="ellipsis">GitHub.com/TokenRollAI/curl-re</span><span class="invisible">sume</span></a></li></ul><p></p></div><hr><div class="diary-entry">14:17 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116233617474678698" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前几天本来打算晚上去看 <em>Hopper</em>，结果无意间被朋友剧透，很是头疼。</p><p></p></div><hr><div class="diary-entry">22:53 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116235645824960374" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打了个赛博符纸出来，贴在机器人身上会让它中病毒吧。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/116/235/643/544/320/277/original/dbe6ae5507afd9f5.jpg" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>三月十六日</summary><div class="diary-entry">02:14 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116236437670746697" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>师傅生病了，今天我一个人顶上。期间有位朋友过来吃饭，还帮我做了些事情。</p><p>较为感动的是有个老顾客，在我们忙的时候帮我们接待了其他客人。他几乎每天都会来，很喜欢和我们聊天。</p><p></p></div><hr><div class="diary-entry">13:45 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116239152861222854" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>家庭医生在离我家里坐车半小时到一小时的距离。因为过去实在麻烦，想要换成离家里更近些的地方。母亲说可以换到她家附近的。我说拜托我一个月能去你家一次吗，让我坐车两个小时就是为了看个家庭医生。她生气道，怎么，你想换到你家附近的？不行，那些要钱。我很无语，问她家庭医生怎么要钱了，不要胡说八道。她最后骂道，你自己看着办吧！</p><p>有时候想不通父母的脑回路。如果我在家里出了事怎么办？我的家庭医生甚至不在家附近。因此，我很长一段时间对看医生有着不敢靠近的想法，单单是去看的门槛就高到需要我坐这么久的车，那我得生多大的病我才愿意花时间去看医生啊。</p><p></p></div><hr><div class="diary-entry">21:45 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116241039870479649" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>早上出门前，看了下天气预报，想着出门和回家的时间都没有下雨，便也没带雨伞走。</p><p>结果我错得荒唐。现在外面下着暴雨，我被困在学校的旧楼里，只能玩电脑。</p><p></p><blockquote class="diary-thread-reply">22:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116241226324967398" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>被雨困的，看了眼时间，发现 IONOS 客服还没下班，赶紧 Live Chat 和他们沟通一下升级 VPS 的事情。目前正在升级中，从 2GB 内存升到 4GB 内存。</p><p></p><blockquote class="diary-thread-reply">03-25 00:48 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116287059403577593" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>什么情况，今天打算部署下 GoToSocial 的，结果发现 VPS 里还是 2GB 内存，IONOS 面板里写的则是 4GB 内存。</p><p>别坑我啊。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 三月十四日 17:47</span>            </div>            <div class="diary-quote-preview">电子邮箱里全都是营销的破玩意儿。得先舍弃掉一些个人邮箱，然后改用随时都可以被舍弃的、能自动转发的邮箱地址。其实会想要体验一下写信寄信。</div>          </div>22:30 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116241216976701101" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Stalwart 实在是个好东西，帮助我解决了「随时都可以被舍弃的、能自动转发的邮箱地址」问题。</p><p>解决方案为，配置 catch-all 路由，让 <code>*@cytrogen.icu</code> 收到的邮件自动转发给我的个人邮箱地址。因为是 *，所以瞎编一个邮箱地址都无所谓，也不需要注册或者什么。当有一个瞎编的邮箱地址开始给我发送营销邮件，我就会封禁这个邮箱地址。</p><p>封禁的方案是写 Sieve 脚本，以及开发一个 Web 入口，能让我添加邮箱地址到黑名单内。建议是直接 <code>discard</code> 而不是 <code>reject</code>，后者能让发送方收到退信通知，从而暴露邮箱地址有问题一事。</p><p>目前整个流程还在测试中。我的目标是一个邮箱地址只注册一个平台的账户，从而查出到底是哪个王八蛋天天卖我信息。</p><p></p><blockquote class="diary-thread-reply">23:20 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116241414671109757" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>成功了 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/167/664/original/kawausosan_45989706.png" alt=":kawausosan_45989706:" loading="lazy"> 暂且先把 GitHub 弄了。</p><p>有个额外的步骤需要做，那就是在 Stalwart 的管理员面板里，将要转发给的邮箱地址的别名添加一个 <code>@cytrogen.icu</code>，用于匹配所有未被其他账户认领的地址。</p><p><code>session.rcpt.catch-all</code> 也要设置为 <code>true</code>。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/116/241/403/649/992/235/original/85eef4e8c2d2a5b6.png" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">03-17 14:21 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116244957341702367" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/070/960/original/50f556343257c59f.png" alt=":wolf_think:" loading="lazy"> 收到了原本应该发送给 dmarc 用户的邮件，意外得知有个附属于 Google 组织的 IP 地址在验证中失败 —— 怎么会出现 Google 呢？我的这个邮箱和 Google 一毛钱都没有。</p><p>稍微研究了一下，怀疑是有人在 Google Cloud Platform 的计算实例上，在邮件的发件人头部强行填入了我的域名，以此来伪造身份。</p><p></p></blockquote></blockquote><blockquote class="diary-thread-reply">03-18 02:13 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116247758214188500" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有些糟糕，早在 11 日就有营销邮件发到我的收件箱，只是我一直没有检查垃圾信箱所以没有看到而已。虽然是垃圾中的垃圾邮件，可以被过滤器直接刷出去，但看到还是会觉得不舒服。</p><p>与此同时收到了几百封垃圾邮件的 Gmail…… 没事，你这样就好了。</p><p></p></blockquote></div><hr><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 三月十六日 22:30</span>            </div>            <div class="diary-quote-preview">RE: https://m.otter.homes/@Cytrogen/116228780816669776Stalwart 实在是个好东西，帮助我解决了「随时…</div>          </div>22:51 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116241299283921315" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>是时候开始缓慢执行 DeGoogle 计划了……</p><p>先从迁移出 Gmail 开始。我有差不多四五个 Gmail。为了清静，需要将不再使用的平台账户都注销掉，不过实在是不清楚到底注册了多少个平台，只能慢慢找了。然后将多余的 Gmail 注销。如果可以的话。最后保留一个 Gmail。因为手机的系统全面拥抱了 Google 生态，Gmail 都被注销的话会变得很麻烦 —— 如果旧的 Motorola 手机也能直接安装 GrapheneOS 就好了，实在是不想再去买新的。</p><p>Google 送了我超大容量的 Google Drive 套餐，以及数年的 Gemini Pro，算了下时间其实差不多也要到期了。到期后自然也不会继续使用它们了，所以还好。其他的 Google 产品都是和手机的操作系统有关，换掉操作系统或者手机的话，自然也不会有任何瓜葛。</p><p>Chrome 浏览器我从很久之前就不用了，Google 搜索引擎也是。因为之前经常使用 Microsoft 的产品，也就是 Edge 和 Bing。所以除了 DeGoogle，还有 DeMicrosoft：把 OneDrive、Outlook 和一些电脑上安装的 Windows 系统都干掉即可 —— 为什么没有提到 Edge 和 Bing 呢？因为我早就换成 Floorp 和 Kagi Search 了。</p><p></p></div></details><details data-group="diary_sections"><summary>三月十七日</summary><div class="diary-entry">00:09 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116241608053640517" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>清理手机中不使用的 app 结果发现了：</p><ul><li>生怕自己在野外迷路死掉所以安装的 Trail Sense</li><li> 听歌然后给出歌曲链接，但因为我没有 API 所以从来没有使用过反而还让我完成了整个简体中文翻译的 Audile</li><li>LavSeeker 同作者写的 whoBird，通过 API 推测出是哪种鸟在叫，因为没有 API 自然也从来都没有使用过</li><li>观星用的 Stellarium 但这辈子只观过一次星，用的还是肉眼</li><li>买不起贵得要死的计算器所以安装的 Graph 89</li><li> 各种根本不需要安装的餐厅 app</li></ul><p></p></div><hr><div class="diary-entry">00:34 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116241707737970358" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>家附近的超市打折，两盒四美元的草莓，尝了一下惊讶于它竟然是甜的，我的天啊！</p><p>这是讽刺。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/116/241/703/908/478/508/original/1a8ac9cd31db3692.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">06:04 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116243003942429499" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>网上买了点周边，想要查询订单送到哪里时，发现必须要下载一款叫做 <em>Shop</em> 的 app 才行。</p><p>我刚清理手机上的 app 哎，你们就不能好好做 web 端、不要再让用户手机上出现更多的 app 么？</p><p></p></div><hr><div class="diary-entry">14:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116244999575383639" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>忽然想到小时候发生过的趣事。三年级左右小餐桌里有个无话不谈的好朋友，不过他之后转学了，我也忘了他的名字。一次等待其他学生出校门的时候，我提到了「毛主席」，而他生气地阻止了我，说我不礼貌，应该叫「毛主席主席」。</p><p>我说，但「主席」不是他的名字呀，已经带了「主席」，还要在后面加个「主席」么？再之后的记忆便模糊了，什么也记不起来。</p><p>说到「毛主席」，中文课的教授曾经跟我们分享过，他小时候在学校学英语的时候，学的第一句话是 <em>long live Chairman Mao</em>，而第二句话是 <em>long long live Chairman Mao</em>，逗得我们哈哈大笑。接着他问我们，知道他数学课的教材都会用什么来算数么？有人举一反三：数毛主席！又把大伙儿整乐了，哈哈，其实是数拖拉机。</p><p></p></div><hr><div class="diary-entry">14:41 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116245035065782552" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>很意外 Therapy 行业比我想象中常见很多很多，应该叫「话疗」吧？但身边人的意见差距很大，有人认为有用，有人认为没用，甚至有人直接说整个话疗行业都是个笑话。</p><p>我因为从来没有接受过话疗服务，已然成为了这种话题中的局外人…… 什么叫 <em>average Americans</em> 都有做过！</p><p></p></div><hr><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://m.otter.homes/@Cytrogen/116150231624377683">↩ 续前文</a>        </div> 18:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116245942907369977" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>尼格罗尼（Negroni）是很常见的鸡尾酒之一，做法是三种酒以一比一比一的比例，加上大块的冰（rock）和橙子片。这三个酒分别是琴酒、甜味的苦艾酒以及金巴利（Campari）。杯子用 rocks 即可。不需要摇，搅拌即可。</p><p></p></div><hr><div class="diary-entry"><div class="diary-reply-ref">          <a class="diary-reply-link" href="https://m.otter.homes/@Cytrogen/116150231624377683">↩ 续前文</a>        </div> 18:39 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116245971465288418" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>古典（Old Fashioned）鸡尾酒需要在 rocks 或者 old fashioned 杯里放置一块大冰，大冰上放片橙子，然后在橙子上滴苦精、放糖，用喷火器将糖烧成糖浆 —— 对，这杯酒是甜口的。最后倒入威士忌。</p><p>有些店为了图省事，会准备好糖浆直接和威士忌混在一起。</p><p></p></div><hr><div class="diary-entry">18:55 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116246035101648583" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想困觉…… 好困喔。看了眼窗外，那绿绿的帽子，才知道今天是 St. Patrick Day，好多人去看了游行。不过我到现在也不知道这个节假日是干什么的，只知道有绿色的帽子。</p><p></p><blockquote class="diary-thread-reply">19:15 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116246114775572936" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>原来 St. Patrick Day 是纪念同名人物忌日的宗教节日。说实话就现在的标签和形象，根本想不到这是宗教节日，因为人们会戴绿色的帽子，穿那种像绿色精灵的衣服。还有个刻板印象是大家会酗酒，中午游行结束的时候估计就有很多人跑去酒吧喝酒了吧。</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>三月十八日</summary><div class="diary-entry">03:16 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116248004780172087" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>心情很悲伤，回家后发现大日去世了。</p><p>满怀期待地捞它出来，希望它只是像过去那样，死了一样睡着了。结果发现它的肉已经缩了进去，和死去的螺一模一样。</p><p>同时，属于死去的螺那样的腐烂臭味也散发了出来。不得已，我们只能丢掉它的尸体。</p><p>它作为一个黄金螺，活得已经够久了，差不多一年半。壳早就没有过去那样光滑、明亮，反而是暗淡的、凹凸不平的。对它而言，它只是老死的吧，但我们总会认为是水缸不够好、水质不够好。</p><p>未来我不会再养任何螺和虾了。</p><p></p></div><hr><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 三月十一日 12:53</span>            </div>            <div class="diary-quote-preview">最近天气好热，明明上周还是上上周刚下过一场雪。昨天店里很是闷热，没多少客人来吃热腾腾的汤面，无聊期间玩起了 OpenStreetMap。说是玩，其实也只是把认识…</div>          </div>04:36 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116248321258183153" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今日的进程：</p><p>Google Calendar—— 杀！Stalwart 的 JMAP 支持通过 blob 上传日历事件，导出 <code>.ics</code> 文件、用 <code>curl</code> 命令上传即可。Android 设备用 DAVx<sup>5</sup> 同步，客户端我则用 Etar 替代 Google Calendar。它们都可以通过 F-Droid 下载安装。</p><p>既然说到了 F-Droid，你自然也知道我用什么替代了 Google Play Store <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/077/428/original/neocat_think_googly.png" alt=":neocat_think_googly:" loading="lazy"> </p><p>我的联系人曾经都保存在 Google 账户上。导出 <code>.vcf</code> 文件，直接在手机原生的联系人 app 中选择自行托管的电子邮箱上传，DAVx<sup>5</sup> 会自行同步到 Stalwart。对，Stalwart 作为一个电子邮箱托管服务，也管这个。</p><p>在我的 Windows 系统电脑上，我选择的客户端是 Thunderbird。这个老字号软件很好用，有很多很多功能，可玩性也高。最常见的用法是当电子邮件客户端。顺带一提我的 Android 设备上电子邮件客户端是 Fairmail。</p><p>不过在我的 Arch Linux 系统的笔记本上，我的玩具只会有一个……Emacs！</p><p>不过 Stalwart 不支持 Google Tasks 协议，所以 Tasks 就算导出了也不能放在 Stalwart 上托管…… 一个方案是使用其他开源方案例如 tasks.org，一个方案则是把日历活动当任务用。看喜欢哪个吧，我现在其实更喜欢用小本本记任务。</p><p></p><blockquote class="diary-thread-reply">04:54 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116248392229671765" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Google Maps，你也受死吧。天天在地图里塞 Gemini 的入口，还在我导航期间问我要不要去赞助商的店里 —— 去你个鬼！推荐使用基于 OpenSreetMap 的开源方案，例如 Organic Maps、OsmAnd。</p><p>导出 Google Maps 的数据时才发现，Google 有 takeout.google.com 可以帮助用户快速导出数据。唉，你也是有过良心的，但还是死吧！ <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/653/original/2034ccd8dc088554.png" alt=":azukisan_angry:" loading="lazy"> 因为破 Google 只能导出 Place ID，没有坐标。有个方案是用 Google Maps Platform API 来获取 Place ID 的对应坐标，但我还是决定手动一个个填入了，顺便看看这些年我都收藏了些啥（发现了图标是中指的厌恶名单）。</p><p>值得注意的是，导出 Google Maps 里收藏的地点时，需要选择的是 Saved 而不是 Maps。</p><p>RE: <a href="https://m.otter.homes/@Cytrogen/116210639799630379" target="_blank" translate="no"><span class="invisible">https://</span><span class="ellipsis">m.otter.homes/@Cytrogen/116210</span><span class="invisible">639799630379</span></a></p><p>手动一个个填入时发现，OpenStreetMap 的内容还是不够全面。关于该项目，我先前有提到过几个移动端上编辑它的软件：Every Door 和 Street Complete。简单来说，它是一个地图界的维基百科，用户们可以访问、使用、编辑它。希望大家可以多多支持该项目，让人们可以用到更好的地图，而不是到处都是广告的破地图。</p><p>基于 OpenStreetMap 的开源软件，我还推荐 Lavseeker：可以显示周围哪里有公共厕所。就是 UI / UX 不是特别好。对了，请向付费厕所说不！见 <a href="https://stallman.org/pay-toilets.html" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="">stallman.org/pay-toilets.html</span><span class="invisible"></span></a></p><p>网页版上 Kagi 有自己的地图软件，不过只适合找地方，而不适合出门导航 —— 最好的还是离线地图。说实话，因为 Kagi 现在我越来越能够说服自己去支持开源、无广告、无追踪、无数据收集的软件。如果这些钱能够帮助团队开发出把用户当人看的项目，是值得的。</p><p>当然，花钱之前请仔细查明白，到底把钱给了谁！请看这篇文章：<a href="https://blog.cytrogen.icu/posts/d33e.html" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="ellipsis">blog.cytrogen.icu/posts/d33e.h</span><span class="invisible">tml</span></a></p><p></p><blockquote class="diary-thread-reply">06:17 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116248716686064921" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>YouTube 我本来用得就少，不过如何分享 YouTube 上的视频是个问题 —— 毕竟自己不用的话，也尽量不要让他人误入歧途，参见：<a href="https://m.otter.homes/@Cytrogen/116223649977972895" target="_blank" translate="no"><span class="invisible">https://</span><span class="ellipsis">m.otter.homes/@Cytrogen/116223</span><span class="invisible">649977972895</span></a></p><p>中文翻译过来就是，使用 invidio.us 这样的代理，防止点击链接的人们接受来自 YouTube 的不自由 JavaScript 代码，但同时也能看到托管在 YouTube 的视频。</p><p>YouTube Music 我则是之前就取消了订阅，改用了自托管的 Navidrome，然后使用如 Tempo、Feishin 的客户端听音乐。推荐获取音乐的方式：获取音乐的 DRM-free 副本、听电台，比如 Vocaloid 歌曲就有个自己的电台：<a href="https://vocaloidradio.com/" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="">vocaloidradio.com/</span><span class="invisible"></span></a></p><p>不过如何获取副本依然是个大问题：听的很多歌不下载 iTunes 买不了啊 ——</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 三月十八日 04:54</span>            </div>            <div class="diary-quote-preview">Google Maps，你也受死吧。天天在地图里塞 Gemini 的入口，还在我导航期间问我要不要去赞助商的店里 —— 去你个鬼！推荐使用基于 OpenSreetM…</div>          </div>15:45 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116250950800334637" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天在 Google Maps 里找到了自己的地点收藏夹。这个习惯是从一个朋友那儿学来的，把喜欢的、想去的，以及讨厌的地方标记下来，然后写下为什么喜欢、想去和讨厌。</p><p>搜寻期间意外发现，我讨厌的地方竟都是 4 星左右评价的餐厅，就连是又贵又咸、不给调盐量，椅子还坐着难受的日本拉面店，都有近 5 星的好评。要去的话为什么不去附近的一兰拉面呢？</p><p>两年前和朋友去吃的广式点心自助，更是讨厌得不行，点的菜迟迟不上，只能和同桌的陌生人聊天，然后抱怨他们上菜慢。没过多久再路过那条街，发现倒闭了，合着是生意不行、开自助赶紧割割韭菜。换成杨国福这家贵得要死的麻辣烫，生意看着很好。</p><p>我很喜欢吃烩面，有一家郑州烩面深得我心，因为他家烩面很像是我小时候家附近的杭州私房面的味道，是童年的回忆。但在小红书上，有人屡屡说这家卫生不好、不好吃，不如隔壁的河南烩面。我一惊，这家店卫生条件哪里差过？不仅赠送免费的茶水，食物好吃的同时，量大管饱还不贵。我倒要看看你说的这家河南烩面如何！找了半天，发现它是个苍蝇馆子，门面破破烂烂的，里面的装修和卫生更是不忍直视。他家的烩面虽和郑州烩面味道不同，但对我来说不够惊艳，不是我喜欢的味道。吃完后心想，自己怕是被小红书上的人骗了。</p><p></p></div></details><details data-group="diary_sections"><summary>三月十九日</summary><div class="diary-entry">00:20 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116252976410499962" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>买了个 Kobo Clara BW 试试墨水屏。</p><p>看上去挺新奇的对我。大小比我的手要大上一些。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/116/252/970/243/897/899/original/72d9f6e88dfd5742.jpg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">04:00 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116253839157819545" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>奇怪，虽然开启了暗黑模式，但是只有书的内容是黑底白字，菜单什么的都是白底黑字。且呼出菜单的时候，书的内容会因为刷新，先变成白底黑字，再变成黑底白字。</p><p></p></blockquote><blockquote class="diary-thread-reply">06:11 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116254355797288271" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>除了连接 Calibre 直接导入书籍外，Kobo 支持订阅 Kobo 书店来 <strong>租借</strong> 书籍的阅读权。把玩期间发现有个叫做 Instapaper 的服务，有自己的移动端 app 和浏览器扩展，说是可以分享内容到 Instapaper，Instapaper 再将内容同步到 Kobo 上。</p><p>目前把 <em>The Absolutely True Diary of a Part-Time Indian</em> 导进去、给室友当睡前故事念了。几个小时体验下来字很大很爽。</p><p></p><blockquote class="diary-thread-reply">20:19 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116257690606709581" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>测试了一下 Instapaper，挺有意思的。可以将想要读的内容用浏览器扩展保存并上传到服务器内，然后再让 Kobo 抓取下载、带走阅读。</p><p>目前还在考虑如何连接到我的 RSS 源。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/116/257/684/447/025/856/original/89c16fa266aa7093.jpg" alt="" loading="lazy"></figure></blockquote></blockquote></div><hr><div class="diary-entry">03:36 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116253746064044199" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天和日语课的同学们进行了一些对话，和如何学习语言有关。说实话所谓的「中级」日语水平，也不过是读了两本 Genki 课本的、看基本的句子能拆明白的水平，甚至这个还是学得好的人能做到的，平日不咋自习或者复习的自然也说不了啥。</p><p>对话中除了出现什么，观《千与千寻》才看了个开头就打了差评、一直抱怨自己得复习但从来没见过在复习的，让我有些讨厌外，还有个话题我不喜欢。</p><p>我认为学习语言，用课本里教的基础语法，其实就可以拼装出日常生活中的大多数对话。也就是说如果想要自习，不想要啃课本的话，可以去看漫画和影片来逐步加深对日语语法的理解。但缺点是，这些大家常看的内容类型，里面的对话有时会过分简单。</p><p>同学反对了我的观点，认为过分简单的台词也可以是件好事，因为日常生活中大家说话就是「过分简单」的，例如说俚语。匪夷所思的是，他认为我将语言视为数学一样的东西，是死板的 —— 我才没有那么说吧！</p><p>况且，让学习者学习俚语，反而才是更难的吧。俚语除了是常规语言的「简单形式」，还影射了当时的文化背景，要比常规语言更加复杂。且母语者要理解它们都很困难，学习者又要如何理解它们呢？难道要不理解其意味、死记硬背吗？谁刚开始学完基础语法，就去学习 <em>this absolute skibidi-level, non-existent aura, Ohio-tier brainrot Gen Z slang</em> 啊？（夸张举例，纯为搞笑）</p><p></p><blockquote class="diary-thread-reply">03:45 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116253781921052543" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不过有个有趣的话题。我们今天读了《注文の多い料理店》，光是标题就看出了日本人有多么喜欢双关梗…… 总之同学告诉我，短篇小说的作者宮沢賢治曾经学习过世界语。我过去对世界语的印象是，因没有文化背景而无法对世界的任何事情造成影响，单单仅是个玩具。</p><p>她绝对奇怪的是，世界上反而有更多的人熟知 <em>Game of Thrones</em> 里的语言。</p><p></p></blockquote></div><hr><div class="diary-entry">06:15 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116254372411692416" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>母亲给了我许多阿胶。作为山东人，我很讨厌阿胶，所以送给室友吃。她说阿胶是不是只有山东人吃，好奇到底啥味道，咬了口后差点吐了出来，抱怨了足足几分钟。</p><p></p></div><hr><div class="diary-entry">06:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116254439236808001" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>使用 MacOS 的朋友想要安装专业软件，未曾想它们竟然只支持 Windows 系统，甚至有一个不再支持 Windows 10 了，真是倒大霉。</p><p>家里还放着一台不完整的计算机，没有显卡和硬盘，要是做成 Windows Server 说不定就能安装专业软件的服务器版本、供朋友们使用了。</p><p></p></div><hr><div class="diary-entry">19:01 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116257383730900919" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>早上起来以为獭站挂了，结果发现 Team Viewer 也开不起来（顺带一提生产环境出现了非常奇怪的问题……），关机后网络才能正常使用，什么鬼呀。</p><p></p><blockquote class="diary-thread-reply">03-20 00:56 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116258780549742418" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>惊天大屎山错误。</p><p>后端返回的对象是仅被 <code>toJSON()</code> 的，而这个方法并不会真的把数据转换成 JSON 字符串，而是转换成 <code>_id</code> 还是 ObjectId 类型的 JavaScript 对象。在后端发送响应之前，数据会被特定的拦截器拦截，使用 class-transformer 的 <code>plainToInstance()</code> 来将属性映射到目标类的实例上。然而，这个方法只会拷贝对象的表层可枚举属性，根本没法正常处理 ObjectId（ObjectId 是 BSON 对象，有特定的 Buffer 结构和私有状态）。处理后 ObjectId 的数据会被破坏，变成空实例。最后框架会调用 <code>JSON.stringify()</code> 来准备要发送给前端的响应（我也不知道我在想什么鬼玩意儿顺序根本错掉了），遍历到 <code>_id</code> 时会触发它的 <code>toJSON()</code>，从而根据当前的进程和时间戳、重新计算生成一个全新的 ObjectId。也就是说原本就该是 ObjectId 的 <code>_id</code> 对象，有了自己的 ObjectId……</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary> 三月二十日</summary><div class="diary-entry">01:26 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/940418298299122903" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>大尾巴狐狸猫。</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/5YqWQ7WJh0sI/j7gkAycjCHxqqxYas37WhK2eVP1bPplH4ruMPdHo.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">01:58 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116259023995730559" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>几个月前申请学校的实习。其实到了大三大四申请这种实习就很难过了，因为它们大多都面向新生，而我还是新生的时候，虽然通过了面试，但一些不能说的原因让我无法继续下去。好吧，反正进去的可能性就不大，为何不在申请书上写写有意思的东西呢？于是我写了一篇和数据主权有关的小作文，大谈数字主权和绿色环保之间的关联，然后果不其然，今天被拒绝了～</p><p></p></div><hr><div class="diary-entry">02:51 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116259230229460758" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Kobo 的 Instapaper 读起来像是 Gemini capsule，图片不会显示出来，也没有 CSS 或者 JavaScript，只有文字，文字，文字。</p><p>链接点进去，不会立即转向，而是会询问我是否要在测试版浏览器里查看，或者添加到 Instapaper 阅读。这个测试版浏览器，应该是无法显示 JavaScript，也无法显示我主页里的 SVG 动画的。</p><p></p></div><hr><div class="diary-entry">04:22 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116259590792098183" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Made by one of my favorite high school teachers, named Mr. R because I forgot about his real name <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/019/055/original/2421e8d631ebf3b8.png" alt=":ablobcry:" loading="lazy"> but I still keep this Lab Sparkle sticker with love~</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/116/259/582/718/795/086/original/8dd7f1d7a0373654.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">14:43 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116262031671704144" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>求朋友不要看到个怪兽就说是福瑞然后发给我了 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/129/595/original/37bc85a6661300f1.png" alt=":panghu_cry:" loading="lazy"> </p><p></p></div><hr><div class="diary-entry">14:54 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116262074342496273" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>朋友用的专业软件像狗屎，无论是 UI、UX，还是整个运行逻辑都像狗屎。这些软件活了不知道有多少年，占着行业大头的位置，每年就是维护政府更新的表、拉屎山代码。能够使用它们的人，都是靠肌肉记忆使用的，其帮助手册写得也是一塌糊涂。</p><p></p></div><hr><div class="diary-entry">18:03 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116262817601935687" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Organic Maps 的公共交通导航做得有点简陋。我要从哪里上 E 号线、在哪一站转 7 号线呢？</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/116/262/811/853/824/397/original/6633f298fc17eff5.png" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>三月二十一日</summary><div class="diary-entry">02:25 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116264791602082674" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>虽说远离游戏圈子和小团体，但有时候小团体就会想要闯进你的生活…… 比如盗摄和造谣。这跟是什么游戏倒没有太多关系。任何把圈子太当回事儿，以及太把自己当回事儿的人，都会逐渐变成可怕的土皇帝。</p><p>今天跑出去玩的感想。</p><p></p><blockquote class="diary-thread-reply">16:44 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116268167589546451" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这件事带入独立博客圈，有点像：你是一个独立博客站主，平时有事没事都写点博文，和其他同道中人互相评论来评论去、邮件来往、Webmention 或者 Pingback ping ping ping…… 大家都很礼貌，顶多有些人讲话不太礼貌或者想法和你对不上，但你不觉得他们是什么坏人，只觉得是他们性格使然，也就任由而去了。直到有天你发现，他们存档了你的所有文字记录，并发在小群里长期批判和造谣揣测你是个什么样的人。不只是你，还有其他你在网络上结识的小伙伴们都深受其害。如果只是私底下这么说就算了，但他们都是过去和你有过互动的独立博客站主，且越来越放肆、将这些谣言摆在台面上说，好似你真的是那样个人。更可气的是，腐朽的灵魂是他们，他们却在自己的想象中将你视为腐朽的灵魂。</p><p></p></blockquote></div><hr><div class="diary-entry">07:07 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116265901108827835" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>写不动了，睡大觉！</p><p>是这个月「那些不受欢迎的想法」的观点总结以及我对该活动的看法。因为拿到了已被授权的完整对话录音，所以要死要活地在边听边记录。</p><p></p><blockquote class="diary-thread-reply">03-22 15:38 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116273571575628323" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>听力竭了，来人把 AI 相关的话题都 ban 了吧。</p><p>其实应当是 ban 掉所有当下非常有争议性的话题，因为讨论的人过多，观点也过多，无法保证参与者的观点不是「从别人那儿继承来的」。</p><p></p><blockquote class="diary-thread-reply">03-22 16:38 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116273807225908502" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>话说我为啥在听这个啊。室友平时没少骂过我时间管理有问题，她说的是对的，我对自己想做的事情也没有自制力。因为我现在应该去写自己的中文课作业、日文课作业和 PPT、网络课期中考的复习、项目生产环境的审计、打扫卫生（为什么家里有个掉毛吐毛的臭猫，还有个掉发的我！以及凭什么不给我晒被子！）。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">16:53 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116268204873017376" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天看到一个朋友口袋里有足足四台手机！他说分别是工作用、私人用、开热点用，和备用的。</p><p></p></div></details><details data-group="diary_sections"><summary>三月二十二日</summary><div class="diary-entry">15:42 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116273589016444991" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>早上起来感觉眼睛对焦怪怪的 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/077/389/original/neocat_scream_scared.png" alt=":neocat_scream_scared:" loading="lazy"> </p><p></p><blockquote class="diary-thread-reply">19:09 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116274402420210335" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>左眼很疼，不知道是什么情况…… 可能是有东西在眼球的哪里。考虑到过往的经验，应该是可恶的眼睫毛跑到眼球后面去了。</p><p></p></blockquote></div><hr><div class="diary-entry"><div class="diary-quote-external">            <a class="diary-quote-link" href="https://m.otter.homes/@Cytrogen/116246201523973082" target="_blank" rel="noopener noreferrer">显示引用原文 ↗</a>          </div>17:10 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116273935595537726" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>虽然曾经说过自己没有考虑搭建自己的 Mastodon 实例，但现在正在严肃考虑中…… 上班就是会想东想西吧。</p><p></p></div></details><details data-group="diary_sections"><summary>三月二十三日</summary><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">情绪发泄。</summary>        <div class="diary-cw-content">21:35 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116280638025749615" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚上稀里糊涂睡着了，做了噩梦。这是个过去也做过的梦，虽然有些小区别，但大体上都是一样的。梦中的自己很无助，一直在走，但也不知道要走去哪里。醒来后果不其然，想起了以前发生的事情。</p><p>昨天写东西的时候写到了《不原谅也没关系》这本书，本来想写自己慢慢从绝望，转变到愿意发泄情绪，最后变成释然。结果发现这是个谎言。我从来没有释然过，而是麻木了，心里一直惦记着。</p><p>昨天左眼疼痛难耐，到了晚上消停了些，但加班又让我头痛了起来。想着睡一觉会好吧，结果醒来后头还是痛的，难受极了。上课什么的，无所谓了，缺席一天两天又怎样，破课，一天天的……！下午又躺到床上歇息，给自己放个小假。不过这次醒后，头还是不舒服。头痛通常都是脑袋上的血管堵塞了，得按摩疏通，那我干脆洗澡洗头不好了。</p><p>早上想要转变心情，拆一下 DiM 卡然后用刚到货的 CH341A 读数据，结果 DiM 卡死活拆不开。唉，乖乖下载社区上他人上传的数据吧。</p><p>这几天做 part-time 学生的想法愈发强烈。一个学期上四五个课其他事情根本做不了，只上一节课算了，助学金也能拿，顶多影响我报税的事儿。</p><p>说到税，破税季什么时候结束，维护不动这个破项目了。我总觉得自己在做一些莫名其妙、被外部玩意儿强迫去做的事情，也没有什么正反馈。</p><p></p></div>      </details></div></details><details data-group="diary_sections"><summary>三月二十四日</summary><div class="diary-entry">00:38 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116281359036749585" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>《洛克王国：世界》出了，而我玩不了……</p><p></p></div><hr><div class="diary-entry">07:39 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116283011260569353" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>LibreTube 是专注于隐私的开源 YouTube 安卓客户端，旨在让用户观看 YouTube 视频的同时，不会被广告和追踪器影响到。</p><p>虽话是这么说，但其特色的 piped 代理几乎是用不了了 ——IP 地址全被 YouTube 封禁，只能选用本地流提取。尽管本地客户端里没有不自由的代码和追踪器，但是 IP 地址依然暴露给了 YouTube，也只能无奈说句好吧。</p><p></p></div><hr><div class="diary-entry">07:59 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116283090301258874" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Yunus Koçyiğit 想要让大家理解自己的基础设施、学会如何部署软件而不是依赖于云平台和托管服务，因此写了本 750 页的书。</p><p>见 <a href="https://selfdeployment.io/" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="">selfdeployment.io/</span><span class="invisible"></span></a></p><p>惊讶的是，虽然他认为这本书值 19 美元，但读者应当想花多少钱就花多少钱来获取这本书。这意味着你可以通过官方网站免费获取这本书的 PDF 拷贝。如果读完后觉得有所启发，还可以返回来打钱给他。</p><p></p><blockquote class="diary-thread-reply">19:20 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116285768630663601" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这本书要是有 EPUB 或者 MOBI 格式就好了。尽管 Koçyiğit 说这本书他专门制作成了什么设备都能正常阅读的，但是 PDF 格式其实对电子书阅读器并不友好：字很小，还没法调整。</p><p></p></blockquote></div><hr><div class="diary-entry">17:59 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116285449389834312" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我无法立即分清日语的「九」和「十」哪个念 じゅう 哪个念 きゅう，所以我给自己下了这样的规则：「十」的发音像「九」，所以是 じゅう，那另一个 きゅう 就是「九」。</p><p>室友无法立即认清左和右，所以她给自己下了这样的规则：两只手的食指和大拇指都伸出来，形成 <em>L</em> 形状。哪只手可以形成正确的 <em>L</em>，哪只手就是左边。</p><p>我们互相不理解，觉得彼此都是大傻叉。</p><p></p></div></details><details data-group="diary_sections"><summary>三月二十五日</summary><div class="diary-entry">05:33 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116288180965711386" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Mastodon 原本的这个客户端用起来挺舒服的，我也不想下载个新的 app 到手机。大致用了下主流的第三方 web 客户端（GoToSocial 太轻量以至于连 web 客户端都没有哈哈），还是很喜欢原来这个客户端。不过咋弄过来使呢？寻思寻思。</p><p></p></div><hr><div class="diary-entry">06:07 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116288315246471692" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>其实感觉自己有点生病了…… 喉咙干干的。这几天有点遭罪：眼睛痛，头痛，现在还咳嗽。很不想去上课或者上班哎，我就不能花一天时间、什么都不需要做吗。你让我在外面玩一天手环也行啊。</p><p></p></div><hr><div class="diary-entry">09:09 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMJ43WTBMHY7KKQWPYM93ME3" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>目前 web 客户端用的是 <a href="https://masto-fe.superseriousbusiness.org/" rel="nofollow noreferrer noopener" target="_blank">https://masto-fe.superseriousbusiness.org/</a></p><p>对这种多列的布局有点好奇，就是瑕疵有些多，例如明明开启了 wide view，但屏幕右侧还是有很多空间空出来。</p><p><a href="https://elk.zone/" rel="nofollow noreferrer noopener" target="_blank">https://elk.zone/</a> 也不错，不知道为什么还接入了 Kagi Translate。就是显示博文的逻辑我不是特别喜欢，它会将整个上下文都显示出来。本应该是件好事啦，这样我就不用看个回复、找来找去了，但还是觉得有些小小的不习惯。</p><p></p></div><hr><div class="diary-entry">19:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMK7Z7S0FGAWGGBNPKK75C1X" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>进化成 Metal Garurumon 咯～有点小坑的是，如果奖杯拿了很多，会进化成 Z'd Garurumon，然后就无法再进化成 Omegamon 了。特意看了进化条件才发现。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KMK7Z58M186HKJ61TEFR2PZG.jpeg" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>三月二十六日</summary><div class="diary-entry">00:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMKR93N46NQQNAX783PM8EYG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>「同一份数据的形状在多个地方重复定义」，这种问题如何最优雅地处理呢？这几天就一直在思考它…… 比方说项目中使用了多个装饰器，处理的是同个数据，但实际上各管各的。一旦手写 mapper 写错了，除非最佳的测试对象「用户」发现，不然根本发现不了。更痛的是，我写的是 JavaScript / TypeScript……</p><p></p></div><hr><div class="diary-entry">02:47 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/942612972869624105" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Still, pictures of Mimi.</p><p> <a href="https://pixelfed.feddit.social/discover/tags/cat?src=hash" title="#cat" class="u-url hashtag" rel="external nofollow noopener">#cat</a></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/05PuNKO3QRng/DW0Hken7xtpUF2YiQC42tvnWHuTRqjzB2vwz3GyM.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/wbNtYYyEW0DV/3g4ZirKjU48pA7RsIJNnfdvCK1dbfUFbwJRhSkZy.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/b6Icj8VhnqSD/yvZZZGYR8oX59eNZVZjBrfwapSO9BwMnIERKB68Y.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">04:30 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMM6HN27DP9WM7KRZVSGR74R" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>自托管了个 Masto-Fe：https://masto-fe.cytrogen.icu</p><p>做了些修改，代码见：https://git.cytrogen.icu/~cytrogen/masto-fe</p><p>SCSS 已经可以被纯 CSS 代替了，可以去掉额外的抽象层。</p><p>目前看来原作者是想要慢慢更新个大的？</p><p></p></div><hr><div class="diary-entry">04:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMM6XD207AKGXJSE8YBX7VVY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><span class="h-card"><a href="https://m.otter.homes/@Cytrogen" class="u-url mention" rel="nofollow noreferrer noopener" target="_blank">@<span>Cytrogen</span></a></span> 今天看了下，发现变成 4GB 内存了，还行还行。现在跑的所有服务所占的内存 2GB 都没到，可以再往里面塞点有的没的。</p><p></p></div><hr><div class="diary-entry">04:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMM6ZGNQAXN3ESPACPWA6ZF8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>原本獭站的那个账户，点进去发现个人信息处变成了黑白的，不知道还以为咪咪猫死了……<img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3M8KH0WA908PA858VD8FK.png" alt=":neocat_nervous:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">08:03 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMMJPE1P6PSE7SJWMGDVWSG2" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前段时间室友鱼缸内的兵鲶挂了一条，只剩另一条兵鲶孤零零躲在木桩下。它俩恩恩爱爱过，有段时间还能看到叶子上产下了数十粒小卵，可惜都被缸里最邪恶的天使鱼吃光了。</p><p>公的兵鲶去世感觉有一个月左右了，但这条还活着的母兵鲶依然时不时在产卵，这些卵如果没有被天使鱼吃掉的话，还能孵化出小的兵鲶，小到不仔细看还以为是虫子。可惜它们就算孵化出来，也会被天使鱼一口一条地吃掉……</p><p>为了让它们活下来，室友买了个隔离用的盒子。它们会聚集在一起，趴在地上不知道在干什么。要是可以活下来就好了。</p><p></p><blockquote class="diary-thread-reply">20:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMNXX0992Q17GCZCRBG1KMJ1" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天打工早退了…… 处理项目迁移遗留下来的巨量 bug。逐渐理解为什么大家都那么讨厌迁移，一迁移就要改动更多的代码。虽然说起初项目的架构就要做好，但那时候什么都不懂，怎么会知道呢。</p><p>回来后看到兵鲶宝宝都孵化了出来。应该是隔离盒子里叶子的原因，盒子里有许多棕色的垃圾，应该也不是屎吧。惊喜的是，盒子外的水草上也有一些兵鲶宝宝没有被天使鱼吃掉，因为它们贴在腐烂的叶子上，正好和环境融为一体，不仔细看还看不到。</p><p>这个鱼缸里最该被清掉的是邪恶的天使鱼。它们不仅看到宝宝鱼就吃，还会故意攻击除了自己外的所有生物，比如盯着螺的脸就啄下去。</p><p></p><blockquote class="diary-thread-reply">03-29 02:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMVPA6EGAT2SH3HGK39YJQ2Q" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>兵鲶宝宝们小小的，像是透明的蝌蚪，会聚集在一起，抱成一团。隔离盒里的兵鲶宝宝貌似都通过细缝逃了出去 —— 不！你会被吃掉的！</p><p>不过现在过了有两三天，数量依然不少，我怀疑这条母兵鲶一次性下了三四窝崽崽。等它们长到一定大小后，天使鱼便没法一口吞掉它们了。希望它们能活到那个时候。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">18:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMNNQ6WFNJGG43VGX2BV21E5" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>越来越讨厌 Node.js…… 虽然我主要写的东西都依赖着它。</p><p>实际表现出来的便是，好慢，占用好多硬件资源 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ2HZ80675PY91PFAFNP8HD.png" alt=":blobcatsweats:" loading="lazy">​</p><p></p></div><hr><div class="diary-entry">22:58 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMP5XWK7V3NMA5XWKEENTF4T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>RE: <a href="https://invidious.nerdvpn.de/watch?v=NneNmdW44BI" rel="nofollow noreferrer noopener" target="_blank">https://invidious.nerdvpn.de/watch?v=NneNmdW44BI</a></p><p>Sasakure.UK 居然又出了这首歌的重制版…… 感动。</p><p>2019 年，也就是 7 年前也出过一版重制版。而原曲在 2009 年发布在 niconico。最开始知道这首歌还是因为 R3 Music Box 做的八音盒版本：https://invidious.nerdvpn.de/watch?v = 5cQg1d6cCcg 那时候是 2017 年。</p><p>虽然现在 Luka 的知名度已经不如往前，但是许多老歌都很好听，是个值得回味其歌曲的歌姬。</p><p></p></div></details><details data-group="diary_sections"><summary>三月二十七日</summary><div class="diary-entry">14:08 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMQSZAQPHFF2N4KFNJV1T1WX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>干嘛干嘛干嘛，睡觉呢楼下的街道突然开始钻地了。</p><p></p><blockquote class="diary-thread-reply">16:37 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMR2H853B6KB7B9FK3F5WV8A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>钻了几个小时了，现在终于结束了……</p><p></p></blockquote></div><hr><div class="diary-entry">14:32 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/943152707120644872" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Why you in there??</p><p> <a href="https://pixelfed.feddit.social/discover/tags/cat?src=hash" title="#cat" class="u-url hashtag" rel="external nofollow noopener">#cat</a></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/RwgZRwcIftZl/tejai3nfs0FloRK9mtGjgM4vgvHDOBuYxpbwbs8R.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/3AhYEybXZw3y/rb3Nr4feqWuSYGlk73qoaUaUATVKH6uRcjsHuuMj.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/n8FnNwiEwqhZ/d3f7f00dzuf8GVswjUGvKJ2xy88vWZCUE8jVlLLb.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/a1431798c-70628a/u4Uo3vuMpepx/ed3FgmLvRjCxr0iIjUKbB0lP1NOpS33iBRGARdFy.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">14:53 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMQWHHBESGYPTXZKG9013GGG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>继续一点点探索 GoToSocial <del>你为什么不阅读文档！</del> 找到了 RSS 功能。它是默认关闭的；开启后在个人主页的 <em>Recent posts</em> 旁会出现 RSS 经典的橘色小图标。橘色，太好了！</p><p>根据代码，它只会输出最近 20 条公开的帖子，其中不包含回复、转发、仅关注者可见的帖子。媒体附件则会作为 RSS enclosure 显现。</p><p>除了 RSS XML，它也支持 Atom 和 JSON feed。</p><p></p></div></details><details data-group="diary_sections"><summary>三月二十八日</summary><div class="diary-entry">04:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMSANSHEZ73NT6A09DH2F02Z" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>关注的好多有意思的解说柯南的 UP 主最近都在讲金田一，使我对金田一很感兴趣，找了找网上漫画的资源看了起来。</p><p>我想到，Kobo 也能阅读漫画就好了 —— 不，它就是可以阅读，只要有对应的格式。</p><p>最近因为生产环境出问题，每天都是凌晨四五点睡觉，根本没有时间读书。拿 Kobo 的时间都短了（其实拿笔记本电脑的时间都短了很多很多很多）…… 什么时候淡季才能来啊。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">排泄物，吃饭不要看。</summary>        <div class="diary-cw-content">16:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMTKNC280HNK7HWSW3GKTW4K" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我讨厌这个地方…… 出门丢垃圾在门口看到一坨坨人类的大便。走到街道上路边就是小坨大便、被踩扁的大便、被踢飞的粪球…… 下水道上有狗的大便，有些看上去是狗、但其实是人类的大便。要问我为什么知道，因为他们的大便形状和颜色就不一样啦！</p><p>我逐渐理解了，当时在小红书上看到的，会抓起热腾腾的大便扔向流浪汉的中国女人，是抱有什么样的心情做这件事的了。我的心情差到，脑子中都开始想象抓起大便，拍到这些到处大小便的蠢货的脸上。</p><p></p></div>      </details></div><hr><div class="diary-entry">17:59 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMTSK4ZX2K0C7X8APM2DX6CF" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打工呢，手机叮叮叮在响。空闲了拿起来看，发现是父母又在家庭群里吵了起来。母亲总是说父亲不会陪伴孩子。不像她身边的那些「模范父亲」，赚钱多，还会陪伴孩子。</p><p>父亲则呛道，难道自己天天说她没有正经工作、没有自己小弟老婆每个月赚得多，她会开心吗。自己时时不在家，不就是因为家里需要钱么？</p><p>母亲回，自己不在乎这些事，当下的生活已经知足了。她只是想要父亲多回家陪伴孩子。</p><p>唉，家家都有本难念的经。现在的生活质量，正是父亲外出数个月做项目，才能得到的。代价除了他的劳累外，自然也有我的童年中完全没有父亲角色这一事；妹妹倒是相较于我，好了许多，至少四岁后还有机会和父亲相处。</p><p></p></div><hr><div class="diary-entry">18:27 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMTV6M111DW90J6VDVPZ2HJV" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看了下 Pixelfed，发觉自己还在使用其原生的 web。它不是不能用，就是不怎么好用。所以我在第三方 web 客户端里登录了正在使用的 Pixelfed 实例，看看后续效果如何（现在我手机主页有一大堆 web app 图标……）。</p><p>顺便发现 Pixelfed 的新 profile，这是我的：https://pixelfed.feddit.social/i/portfolio/Cytrogen 看着挺不错的。</p><p></p></div></details><details data-group="diary_sections"><summary>三月二十九日</summary><div class="diary-entry">02:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMVNQ8XPJEDC5045PM4YMWVG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>没有复习、写作业的心情，好似它们不是我生活中的一部分。</p><p></p></div><hr><div class="diary-entry">02:12 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMVNSX0YEZKPGY3NYHVQQ86T" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>兼职期间无意看到一位客人的手机屏幕，惊讶发现它里面的内容也是灰色的。</p><p></p></div><hr><div class="diary-entry">05:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMW0B11WX8FRR804KHP6DCMS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>平日都是在台式电脑上工作，用 Feishin 放自己下载的 OPUS 文件（是个糟糕的选择）来听音乐。不过这些天我从床底下找到个小桌子，可以架在床上，然后用笔记本电脑干活。</p><p>笔记本电脑上一直没有安装过像样的音乐播放器，我也没怎么折腾过让 Emacs 播放音乐，所以就用手机外放音乐了。</p><p>我在 PiliPlus 上看到关注的 Vocaloid 合集更新，点进去听了下 —— 这是我换成 PiliPlus 后第一次去听这个合集，而感觉和我用 BiliBili 听完全不一样，<strong>完全不一样</strong>。</p><p>BiliBili 播放出来的音频，有着一种声音全被打扁的感觉，音符们被拍成一坨球，哪里都去不了。但 PiliPlus 播放出来的声音，明显「大」了很多，有种音符噼里啪啦都飞出小盒子的感觉。</p><p>为了测试，我将手机摆放在了同个位置，同个音量大小，播放了同个视频。最终感觉就是如上所述。这是为啥呢？</p><p></p></div><hr><div class="diary-entry">20:21 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMXM55Q83CQ2VNGXZCRNJA1H" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Apparently（我一直想说这个词作为一段话的开头），我 GoToSocial 的 fork 补上了引用功能。官方的代码里已经有了对应的框架，但是一直没有实现，应该是在等下次大更新。</p><p>Masto-Fe 我的 fork 中也支持显示引用块了。但是其他的第三方 web 客户端，例如 Statuzer，还看不到，不知道为什么。Nicolium 和 Phanpy 倒是都看得见。</p><p>这里有个坑，那就是 GoToSocial 源代码里写了很多 <code>bun:"-"</code> 标记来关联字段。如果新加了字段，却没有在 Populate 中加载，那 API 跟 AP 输出时字段就会是空的。因为这个事，我成功把实例和 Masto-Fe 搞坏了几个小时…… 引以为戒！</p><p>说到 Populate，其实我生产环境中就一直在和它斗智斗勇。或许我命中注定被 Populate 克吧。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KMXHFFHYD6MPR2DZS1P9VC5Z.png" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>三月三十日</summary><div class="diary-entry">01:46 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMY6QJMFVK68JJT72JE18Q3F" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>熟客们过来，看到墙上的一幅画议论纷纷 —— 那是一副一战时的画的复印品。我们好奇问道，是想要买副挂在墙上么？他回答不，他自己就是个漫画家，单纯有点感兴趣而已。</p><p>之后他给我们看了他的作品：居然是曾经给 Marvel 以及 DC 画过漫画作品的老师，且有一个自己的 Wikipedia 页面。因为是画美漫的，基础功了得，不得不佩服。</p><p>熟客里也有百老汇中曾经风光过一段时间的明星。虽然他们都老了，却还是活力满满地对待生活，喜欢有事没事就聊天和聚会。如果我老了，我也想有一天去一家餐厅吃饭，让那里的小年轻服务生觉得我如此不平凡。</p><p></p><blockquote class="diary-thread-reply">04:15 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMYF9983Z9SZHANHFQ6KFSP6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有一对夫妻忘记说。他们老了，时不时就会去其他国家旅游。为了可以在那个国家里不依赖于向导或者翻译官，他们会在那里自学语言，所以他们会说普通话、日语、埃及的阿拉伯语等等。</p><p>旅游，我也想要去。我在纽约市待了十年，但是连城市的边边角角都没有了解过。<a href="https://blog.cytrogen.icu/posts/53f4.html" rel="nofollow noreferrer noopener" target="_blank">上次走了半马</a>，让我久违看到了城市中我尚且没有看到过的景色。</p><p>很快假期就要来了，那时候天气想必也是暖和的，一定要出去走走啊。</p><p></p></blockquote></div><hr><div class="diary-entry">03:19 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMYC2FRQHA6T36EHD6ZCGPFM" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>兼职期间一个客人看着我，问我是不是计算机专业的。</p><p>我惊讶道：「你怎么知道？」</p><p>他得意地说，计算机专业的人们有一种特定的长相，因为他经常和他们打交道，所以有个「计算机专业」雷达。真要说是什么特征，那就是看上去很会学习，以及有着无情的效率。</p><p></p></div><hr><div class="diary-entry">04:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMYGE8BWB1SSSNR4F2FJ3NCS" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>半夜抱佛的大脚丫，复习明天要考的计算机网络。唉，真的不是我讨厌学习它，而是这节课的教授讲话实在是令人很想睡觉。</p><p>我让 AI 给我生成一些应用题，我做做看。其中一个是：</p><blockquote><p>某大学校园网每到晚上 8 点至 11 点之间就会变得极度卡顿，导致科研人员连最基本的文献数据库都无法访问。经过排查，网络管理员发现是因为大量学生在这个时段同时使用 P2P 软件下载大型游戏和高清电影，完全占满了学校购买的总出口带宽。</p></blockquote><p>淦，好有生活感。</p><p></p><blockquote class="diary-thread-reply">04:38 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMYGJGEB04EJJHDP619WJRQX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说到大学校园网，就会想起一位朋友在自己的宿舍里搞了个路由器，一机承担了整个宿舍的校园网费。之后他玩起了 NAS，还问我要不要用 —— 还是算了吧！</p><p>我没有住过宿舍，对宿舍生活有那么一丢丢丢丢兴趣。</p><p></p></blockquote></div><hr><div class="diary-entry">04:45 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMYGZ4PVN9MDTVPMB2VQ1XKG" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>怎么感觉自己开始上班后，倒啤酒越来越娴熟了：左手将啤酒杯倾斜个 45 度，右手慢慢地将啤酒倒入啤酒杯内 —— 要多慢哩？慢到只有一点点液体流出来，并且你看不到白色的泡泡。这样倒杯啤酒要花个一两分钟，但得到的会是一杯没有泡泡的啤酒！</p><p>我又不喝它，我在兴奋个啥…… 可能「强迫症」被满足了，自己就会不由自主地高兴起来吧。</p><p>生啤酒也一样，要很小心地去掌控应用于手把的力~</p><p></p></div><hr><div class="diary-entry">06:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMYNVPXMA006FSVXR6PFQ9Z9" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>虽然没有完美地匹配漫画的宽长，但已经比我这个超级长的手机好上许多。</p><p></p><figure class="diary-media"><img src="https://gts.cytrogen.icu/fileserver/01NE7PHQDY0JMV0FHPK6F8P35X/attachment/original/01KMYNRY2MRHW1RXAW0FF32SX4.jpeg" alt="" loading="lazy"></figure><blockquote class="diary-thread-reply">06:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMYP933ASJHB70VJN55T14NT" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><span class="h-card"><a href="https://gts.cytrogen.icu/@cytrogen" class="u-url mention" rel="nofollow noreferrer noopener" target="_blank">@<span>cytrogen</span></a></span> 印象里之前看过一个 BiliBili 上的视频，说华为三折叠有着最适合阅读漫画的宽长占比 —— 谁买它就是为了看个漫画呀！</p><p>之前无聊翻阅 Kagi News 的时候，看到三星的三折叠已经不卖了。今年苹果好像也要出折叠屏，这是折叠屏时代么？</p><p>这个点了怎么隔壁的男人还在说话。</p><p></p></blockquote></div><hr><div class="diary-entry">15:32 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KMZP024ZE8PJ6D5W7XRWSZM6" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近订阅的一些博客站主都换了主题，我的映射无法立即分清楚该网站设计代表着谁了 <img class="emoji" src="https://gts.cytrogen.icu/fileserver/01DFVSW6RERQR4PFBJ30Y1QPS8/emoji/original/01KMJ3G0B7WBTN0716A7887SHX.png" alt=":neocat_cry_loud:" loading="lazy"></p><p>我想要把自己的博客网站弄成橘色，但是手机又看不出来，干脆全部变灰阶吧。</p><p></p></div></details><details data-group="diary_sections"><summary>三月三十一日</summary><div class="diary-entry">04:16 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN11QSMMAVS9A6ERSX97WZ0A" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>又去超市里买了打折的草莓。买回来咬一口，发现又是甜的，好开心。</p><p></p></div><hr><div class="diary-entry">14:04 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN23BBXTV54VN59CWBDFGRCX" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想着这几天去 AMC 看个电影，比如 Pixar 最近新出的可爱河狸电影，结果上 AMC 看了眼发现不知道多久之前送给我的 Premium 会员没了。</p><p>这倒是没有想到，因为一直都没有显示过截止日期。其实 Premium 会员一年也就 20 美元不到，真的赚不回来也无所谓，我平时也是有事没事就会去找电影看。</p><p></p><blockquote class="diary-thread-reply">14:10 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN23P82E5AJHD2A8YHB8SHW8" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>忽然想到几年前去参加学校的一个项目，大家其乐融融自我介绍了起来。其中一个破冰的问题是「你喜欢看什么类型的电影」。当时参加项目的人们多是研究生，什么历史电影啊都会看，问到我的时候我回答说我喜欢子供向电影。</p><p>子供向电影虽然好看归好看，但是近几年总觉得没有一个是让我非常喜欢的 —— 前段时间在日语课上重温的《千与千寻》是子供向电影吗？</p><p></p></blockquote></div><hr><div class="diary-entry">14:18 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN245NJ8YB0D9KEV2J6Q6456" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>清理了一下个人邮箱，收信箱里都是和其他博客站主之间的来信，开心。</p><p>至于已经被垃圾、系统邮件攻陷的其他邮箱，已经懒得再去清理了…… 原谅我。</p><p></p></div><hr><div class="diary-entry">19:36 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN2PC91AGNEXCD27DASDNFAY" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>想把手上唯一一台苹果设备 iPad Pro 给干掉，换成安卓设备，但是又舍不得 Procreate 和 Apple Pencil。</p><p>唉，留着吧留着吧，就算它安装第三方 app 都有限制且每周都要重新签名，但我还是爱着它。</p><p></p></div><hr><div class="diary-entry">20:40 <a class="diary-source-link" href="https://gts.cytrogen.icu/@cytrogen/statuses/01KN2T12JGA7WZ6B2DP5RBTXNA" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我会鄙视所有看我笨手笨脚干活的同时，说「读书还真的没用啊」的人。</p><p>这个逻辑已经糟糕到无言以对的程度！</p><p></p></div></details></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;本月的条目和内容依然不多。待税务季结束后我会重新花费精力在月刊上。&lt;/p&gt;</summary>
    
    
    
    <category term="想法迭代" scheme="https://blog.cytrogen.icu/categories/%E6%83%B3%E6%B3%95%E8%BF%AD%E4%BB%A3/"/>
    
    
  </entry>
  
  <entry>
    <title>那些不受欢迎的想法・贰</title>
    <link href="https://blog.cytrogen.icu/posts/eac7.html"/>
    <id>https://blog.cytrogen.icu/posts/eac7.html</id>
    <published>2026-03-23T04:00:00.000Z</published>
    <updated>2026-07-06T21:52:06.978Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>三月份的「那些不受欢迎的想法」活动结束了。说实话，这次的内容并没有二月份的那么印象深刻。简单来说，便是不够「不受欢迎」。</p><span id="more"></span><p><a href="/posts/1572.html">上篇文章</a> 里我提到了，我提前知道了一位朋友的具有争议性的想法。我依然在写作时偷了懒，并没有将他的观点全盘托出，只是借了他提出的「动量」概念，改来说自己的观点。</p><p>可惜的是，他并没有在这次活动中讲出这个观点，否则我就可以用参与者们吵架的事情，又写一篇文章了。</p><p>总之，他对我上篇文章的内容很不满意，认为我没有写出他的意思，虽然我觉得已经在不大幅度修改我原本的观点的情况下，很努力地引入了他的概念且不会偏题了。</p><p>所以，我要重新声明一下他的观点。他的观点是，<strong>人们做出的选择大多数并不是自己决定的，而是动量决定的</strong>。至于为什么，我已经在上篇文章中进行了解释 —— 他所谓的「真正的观点」，和我阐述的根本没什么区别吧！</p><p>好了我已经满足了朋友的需求，来继续看看本期其他人的「不受欢迎的」想法吧。</p><hr><h3 id="一-问题少年产业"><a class="markdownIt-Anchor" href="#一-问题少年产业"></a> 一、问题少年产业</h3><p>令我感到意外的是，许多人都对「话疗」这一行业很有想法。</p><p>我从来都没有接受过话疗，所以不知道话疗到底是个啥，也不认为它是一个多么常见的服务。现在看来，这个地区的人们体验过话疗的并不少见。我去问了一些朋友，他们告诉我美国几乎每个人都接受过话疗，一辈子没接受过话疗的，是一件相当「东亚」的事情 —— 也许是因为东亚在心理学上发展得慢吧。</p><p>但我不认为话疗服务是一件多么好的事情。上期能有人特意骂这个行业，本期也不会少。详细的想法我会留到后面。</p><p>第一个开始分享的人，提到了「香蕉」。可惜，并没有任何香蕉在他想要分享的观点里，他只想开个玩笑而已。他的观点和 <em> troubled teen industry</em>（以下简称「问题少年产业」）有关。</p><p>说「问题少年产业」，大家或许无法想象出这是个什么东西，但如果说到国内的治疗网瘾寄宿学校以及杨永信，说不定就能立即明白这个产业是怎么个回事了吧。</p><p>1958 年，Charles Dederich 创立了 Synanon 戒毒项目。在二十年的沉淀下，该项目演变成了邪教。它是美国创立的首个针对药物成瘾者的治疗性社区（Therapeutic Community，简称 TC），其核心是居住式治疗模式，通过严格的团体生活、行为纠正和心理干预来重塑成员的人格与行为模式。</p><p>中国的部分戒瘾治疗机构也采用了类似的 TC 模式。这些机构会实行封闭式管理，让学员们集体生活，通过军事化训练、心理辅导和行为纠正课程来干预成瘾行为。</p><p>以上全都是字面上的、给蠢蛋家长们听的好话！</p><p>实际上，无论是 Synanon 还是中国的戒瘾机构，都因为采用了各种争议性手段而伤害到了学员。比方说，Synanon 独创了一种名为 <em> Synanon Game</em> 的团体攻击疗法，旨在鼓励成员们互相批评和羞辱。接着推广了 <em> tough love</em> 攻击疗法，说可以靠言语攻击来治愈青少年的不良行为 —— 狗屎！</p><p>尽管 1991 年 Synanon 因破产而解散，但它的许多「信徒」都深信这种攻击疗法可以治愈他人，而开设了一个个治疗机构，也就形成了先前说的「问题少年产业」。</p><p>十分悲伤的是，这个产业依然存在，依然在合法折磨、杀死数不清的孩子们。孩子们被绑架、监禁，同时在心理、精神和肉体上遭受没有人性的折磨，而施暴者们却说这一切都是「严厉的爱」。恶心得令人作呕！</p><p>回到提出者的故事。他作为一个话疗师，起初并不知道这个产业有多么糟糕，因为也是许多年前的事情了。他大学毕业后便来到了一个野外治疗项目工作，即问题少年产业中的一种住宿式干预形式，通常将青少年们安置在偏远的自然环境中。参与者们需要进行徒步、露营和野外生存等活动，并同时接受团体和个人心理治疗。</p><p>抛开纸面上好听的地方不看，这种项目依然存在着折磨等问题，以至于他还没有离职时，就因为过多的法律诉讼而强制关闭了。</p><p>讲完大致的背景故事后，他说这种行业一定会消失，但问题在于，终会有另一套系统去代替它的生态位置，因为问题青年依然存在，问题青年的父母也会源源不断将他们送到类似的机构内。只要需求还在，总会有人为了大赚一笔，充当对应的供应方。</p><p>因此他认为野外治疗项目是利大于弊的，因为它可以帮助孩子们远离手机、去到户外、接触阳光。社会应当清除劣质的机构，而不是全盘摧毁整个行业。</p><p><em>What the fuck?</em></p><p>前面说了这么多，只能感觉出对问题青年产业的厌恶，但结尾的定论，却潦草无比。</p><p>这次的活动有个规矩，发言只能有两分钟。这是硬性的，因为主办方真的会拿着定时器计时。没办法，活动时间就这么长，为了所有人都能发言，只能削减每个人的发言时长。</p><p>这位参与者显然陷入了 <u>语境过载</u> 的陈述陷阱，即过分交代前置信息，反而令后面真正的论点变得浅薄无比。用网络用语来说，就是「叠了太多层甲」。</p><p>「叠甲」这一行为的根本原因，是人们过于担心自己的观点被人质疑或者攻击，而想尽办法向外人表示自己知道且认同「大众」相信的观点。又换句话来说，对自己的观点不自信。</p><p>听者听完后，只会去想这种产业多么应该被铲除殆尽，而不是「阳光、远离手机、重建社交技能」等仅是用词汇堆砌出来的论据 —— 我家孩子都要死了，你还要跟我说问题青年产业好就好在至少我家孩子不是玩手机玩死的吗？听者根本无法理解这些要素如何产生治疗效果。这一点也在后续的讨论中展现了出来：大家都在聊机构的腐败和虐待底线，根本没有人提项目本身的积极机制。</p><p>青少年缺乏基本权利，这一点我在 <a href="/posts/b211.html#%E6%96%B0%E6%8A%A5%E5%91%8A%E5%91%BC%E5%90%81%E5%9C%A8%E7%BE%8E%E5%9B%BD%E7%BB%88%E7%BB%93%E7%AB%A5%E5%A9%9A">伟大灯塔的童婚丑闻</a> 中提到过。他们无法给予实质性上的同意或者不同意，大多数情况下不过是父母强制他们同意、他们才同意的。因此青少年在这些项目中被随意「绑架」带走，前提正是有人替他们做了决定。这是权力结构和系统性上的漠不关心与无能。而这又不得不提到机构内部的包庇文化。</p><p>讨论期间有人做出了这样的类比反问逻辑：「如果一所小学的老师猥亵了学生，你会直接关闭这所学校吗？」</p><p>该反问忽略了「偶发性违规」和「系统性作恶」在权力结构上的本质差异。</p><p>首先，正规学校拥有外部监管、透明的投诉机制，以及受法律严格约束的从业门槛，教师的作恶是对系统规则的背离。</p><p>其次，问题青年产业的运作逻辑在于物理隔离以及权力的绝对垄断之上。在黑盒结构中，虐待可不是什么错误，而是结构性的必然，因为其设计初衷就是在掩盖和促进伤害。</p><p>撇开已存在的虐待事实，再去夸赞项目本身是积极的，是奇怪的。我们已经知道，青少年在项目中是无助的，权威人士是漠不关心或者说无能的，那是否可以证明项目本身就存在根本性的问题？因为这一切不就是因为成年人做出的数个糟糕决策吗？</p><p>一位参与者尝试用经济学的现象去看待项目本身的积极性：大家有钱都会想要去赚，就算是一个糟糕的项目，也会尝试控制其损害、保留其积极的部分，再广大宣传出去。那问题青年产业究竟需要做出多么烂的事情，才能让人们想要去全盘废弃它？同样的，政治也是得烂到一定程度，才会让人们发动彻底的革命。</p><p>不过这样的说法依然过分简单化了问题。别说和问题青年打交道了，和青年打交道都是一项困难的工作，且报酬往往不高。结果真正合适该工作的人不愿意做，机构的候选人池里只有别无选择、为了糊口、会成为施暴者的人。如果无论是哪个理论模型，候选人池都是这种人的话，那么虐待只会以不同的形式存在。当然，你也可以花大钱聘用最优秀的人才，但这并非长久之计，仅仅是无数个补丁中稍微有用些的一个罢了。</p><p>那么根本性的问题在于哪里？是「青少年们缺乏权利」吗？不，这样的逻辑依然仅成立了一半。</p><p>未成年人在法律层面不具备完全的自主决定权，是因为他们心智尚未成熟。如果赋予自毁边缘的青少年完全的拒绝权，任由其行使「不接受任何干预」的权利，同样违背了社会和家庭的监护初衷。「青少年缺乏权利」是社会保护机制的副产品，但并非这门生意走向施暴的终极推手。</p><p>真正的系统性灾难发生于「监护权」和「商业利益」上。问题青年产业的底层逻辑是家长在面对自身无法解决的家庭危机时，视图花钱将监护责任和教育义务一同外包。管教、行为纠正、心理干预全都被彻底商业化，且运作于一个封闭的黑盒环境中时，权力的天平将不可避免地失衡。</p><p>曾经我在初中上一节忘了名字的课时，老师问我们，麦当劳儿童套餐广告的面向观众是谁。我回答说，是孩子。老师纠正道，孩子可没有钱，广告实际说服的是为其掏腰包的父母。</p><p>在刚才提到的商业闭环中，机构也不需要对真正的服务对象，也就是青少年负责，因为青少年没有付费能力，也没有退出机制。机构只需要对支付账单的家长负责就好了。只要通过一套精美话术稳住家长，让家长相信一切折磨都是为了孩子好，这个商业模式就能完美闭环。</p><p>而候选人池问题是商业模式的必然结果。既然机构的生存不依赖于青少年的实际治疗效果，只依赖于家长的持续付费，那么在内部运营上，资本必然会追求利润最大化。压低运营成本最直接的方式，就是雇佣廉价、缺乏专业心理学或医学资质的劳动力。所以不完全是先前提到的「合适的人不愿意做」，更有可能是机构的盈利模型本来就排斥高成本的专业人才。</p><h3 id="二-passport-bro"><a class="markdownIt-Anchor" href="#二-passport-bro"></a> 二、Passport Bro</h3><p>提出者近期去了次巴西，回来后曾经也去过巴西的同事问他，有没有做 <em> Passport Bro</em> 的那些事情。</p><p><em>Passport Bro</em>（跨国寻爱族）是大众用于描述专门跑到其他国家结婚的西方人的词汇。这些西方人往往被认为前往其他国家以享受更高的购买力、更低的生活成本，以及将自己视为富人的他国女人的崇拜。而根因也往往被认为是在自己的国家里不够具备竞争力。</p><p>提出者的观点是：拥有财富和特权的男人去另一个国家，利用这些财富和特权去吸引女性是不对的。因为这专门针对了不太富裕的国家，且将这种针对作为与某人建立联系的主要方式是不公平的。</p><p>我对人际关系类的话题，其实并没有想要去回应的欲望，尽管我时不时叭叭叭说一大堆。人际关系永远是他人自己的问题，不是我的。但我依然可以说一些无聊的事情。</p><p>讨论期间，有参与者认为只要双方自愿且诉求透明，这就只是一场公平的交易，即用 <em>自由市场资本主义</em> 的逻辑来合理化这种行为。</p><p>不过当两个国家之间存在巨大的经济断层时，弱势一方做出的「自愿」选择，本质往往是基于生存压力或阶级跃升的渴望，是由环境倒逼出来的。</p><p>这也是为什么这种关系被认为不可持续 —— 因为关系的基础完全建立在资源依赖上。只要资源没了，或者弱势一方获得了独立的生存能力，关系便会立刻消失。</p><p>令我觉得滑稽的，是有人认为 Passport Bro 的行为可以重新分配财富，避免财富都集中在富人身上。</p><p>首先，跨国婚姻根本无法改变目标国家的贫困，只是将 <em>涓滴效应</em> 极其粗暴地应用到了婚姻市场上 —— 涓滴效应主张政策应当优先给予富人或大企业财富上的优待，因为这些位于金字塔顶端的群体会让财富像水滴一样逐渐向下渗透，最终惠及底层的普通劳动者。该效应理应是宏观经济学概念，却被这个人放到了微观、局限于被选中的特定家庭上。它不会转化为目标国家的基础设施建设、教育投资或产业升级，也无法创造出任何健康的、可自我维持的经济循环。真的会有人认为几个外籍人士过来娶妻生子，就能解决国家的系统性贫困吗？享福的仅仅是被选中的女性以及她们的家庭成员，而已！</p><p>或许有人注意到，我使用了「女性」这个词，意味着我默认这种有争议的行为是「外籍男性娶他国女性」。莫要着急，「外籍女性娶他国男性」的很快就要来了：学术界将其称为 <em> Romance Tourism</em>，即「浪漫旅游」。怎么男性的跨国寻欢如此饱受争议，女性的就成了「浪漫旅游」？两者在社会叙事上就被包装得不同。前者是商品化的，而后者是浪漫化的，不过底层逻辑都是发达国家公民利用经济优势在发展中国家进行性资源消费。</p><h3 id="三-竞技编程和竞技数学的价值"><a class="markdownIt-Anchor" href="#三-竞技编程和竞技数学的价值"></a> 三、竞技编程和竞技数学的价值</h3><p>该参与者曾是一次全国数学竞赛的冠军。他讲话咬字很清晰，但是语速极快，导致听不清楚。为了更具象地形容给我，室友说他讲话就像《初音未来的消失》。我说，初音未来咬字就很清晰，语速也可以很快，那他四舍五入也可以是初音未来真人。</p><p>好吧，我对竞技编程和竞技数学不感兴趣，自然也不会对他提出的话题感兴趣：竞技编程和竞技数学能让你更擅长 <u>研究性思维</u>。</p><p>说实话，这也不是感不感兴趣的问题了，而是整个话题和讨论都无聊至极 —— 多数参与者都是软件工程师或者数据科学家，也就是理工科背景或者此类技能的受益者，那么他们又怎么会提出有趣的反驳呢？</p><p>我有时候会钻牛角尖，拆解大家说的词汇到底是什么意思。这个「研究性思维」便被我盯上了。研究性思维通常而言会被核心在于对抗未知和不确定性。如果是这个定义的话，提出方的逻辑就有问题，因为竞技类项目的本质是在极度确定的规则和边界内寻求最优解，训练的也是解题思维而非找题思维。</p><p>但根据提出方所说，他实际上想要表达的意思是「面对核心技术瓶颈时的逻辑突围」，那么他的逻辑在该框架下是成立的。不过这偷换了概念，在真正的科学研究中，最漫长的往往是定义问题的阶段。更何况，竞技类技能到底能否成功迁移到另一个领域，都是个值得探究的问题 —— 你要如何证明你刷题时学到的东西，放在现实中的项目中就有决定性的帮助？</p><p>另一个让我心觉无聊的是，这个观点深究下去，底层逻辑不过就是「付出特定努力就会获得特定能力」，是一句绝对正确的废话。事实是，你高强度重复做什么，都会让你擅长一种能力。这有什么好反对的呢？谁会不想要自己什么都擅长？该观点从一开始就失去了可证伪性啊。</p><p>既然如此，为什么大家没有成为全知全能的呢？那当然是因为成本了。为了在竞技编程和竞技数学的领域中达到顶尖水平，一个人必须投入常人难以想象的时间和精力。沉没成本如此庞大，意味着他在同一时间段内必须放弃对其他维度能力的探索 —— 人的精力终究是有限的。</p><h3 id="四-又是话疗"><a class="markdownIt-Anchor" href="#四-又是话疗"></a> 四、又是话疗</h3><p>该参与者的原话我认为说得很棒，所以打算直接照抄下来 —— 肯定不是我懒得总结：</p><blockquote><p>我有三个核心观点，我想挑一个来讲。当我们感到悲伤或迷失的时候，本能地会寻求验证和出路。天主教徒去告解、印度人拜访瑜伽修行者、非洲女孩找巫医…… 而现代人，我们有「心理治疗师」。治疗很贵，但它真的值这个价吗？我的基本观点是：<strong>不一定</strong>。现代治疗师并不比过去的巫医、长辈或者睿智的朋友更有效。</p><p>我认为治疗的效用主要源于情感支持、实用建议和问责机制，而这些原本是正常人际关系，如父母、导师，中该有的。但现在的社会，建立这种关系变得越来越难，于是我们将原本属于人类自然体验的部分「拆分」出来，以每小时几百美元的价格打包出售。</p><p>支持我的理由有三点：</p><p>一、不同流派的疗法，如 <u>认知行为疗法</u>（CBT）、<u>心理动力学</u> 等，在统计学上的有效性几乎没有差异；</p><p>二、治疗师的水平并不一定随着年龄、经验或专业培训而显著提升；</p><p>三、拥有一段真正的友谊对生活的改善，几乎等同于接受治疗。</p></blockquote><p>这个观点对比上一个，争议性多了些。这和参与者们的专业以及职位有所关联：有一部分是理工科背景，有一部分是心理学背景，且话疗要比竞技编程和竞技数学常见许多，谁都可以说上几句。</p><p>那我就根据提出来的三个点的顺序，来整理讨论中的想法吧。</p><p>在专业层面上，有个准精神科医生提出了异议：不同流派的系统化学习是「表演性」的这一点并不准确。特定的心理障碍需要特定的方法，比如针对 <u>边缘型人格障碍</u> 的 <u>辩证行为疗法</u>、针对高理性的人的哲学思辨式流派、针对接地气的人的认知行为疗法等等。虽然医患之间的信任关系才是最重要的，但针对性流派的科学性依然存在。</p><p>好吧这里出现了很多术语。简单来说，他的核心意思是「对症下药」。这位准医生的反驳确实为不同治疗流派的科学性保留了尊严，证明了它们并非纯粹的表演。但这并没有解答原观点的后两层质疑：治疗师的个人水平差异，以及最核心的，治疗本身是否正在异化人类自然的社交连接。</p><p>那么，治疗是否正在逐步代替友谊？这和第一个观点中，有家长想要通过花钱来外包教育孩子是不谋而合的。治疗本质上也是交易性的，而这个特质是个双刃剑：你可以毫无心理负担地向治疗师只谈论自己，不用担心对方会因为你的黑暗面而过度焦虑或带有偏见。</p><p>但这在现实中并不正确，不负责任和不专业的治疗师就会对你指手画脚。这也就是整个观点的第二点，治疗师的水平问题。</p><p>况且，能够向朋友坦白自己的不好的一面，不才是健康的友谊该有的吗？无法对身边的人敞开心扉，这件事本身才是该解决的问题，寻找治疗师不过是其替补方案。</p><p>有位参与者补充了一点：去治疗的人必须想要好起来才行。现实中有些人就是沉溺于痛苦，他们找治疗师或者朋友只是为了抱怨。</p><p>这不经意让我想到曾刚读了 Alfred Adler 的《被讨厌的勇气》的朋友，大放厥词认为陷于心理痛苦中的其他朋友们是甘愿沉浸在痛苦当中，以至于我有段时间对 Adler 以及他的书籍有些不好的印象。</p><p>道理是看上下文的，给每个道理加上对应的上下文的话，所有道理都是正确的。但将道理套在所有人事物上，就有可能导致更多的痛苦。我精神状态很差的那段时间，很需要他人的帮助和支持。如果有人过来说我是活该、自愿沉浸去做个受害者，那我拿着刀捅死那个人然后自尽的 —— 当然是开玩笑的，因为确实有人这么说过我，而我并没有拿刀捅他。</p><p>在阅读了《不原谅也没关系》后，我的精神状态很快从抑郁的，变成易哭的，再变成释然的 —— 又或者是麻木的？谁知道呢 —— 因为我那时候需要的就是那样的观点。精神恢复正常后再去看 Adler 的观点，能理解他想要激发人类的主动性，但也能理解把这种道理讲给一些确诊了精神疾病的朋友们，只会伤害到对方。</p><h3 id="五-资本主义与社会主义的平衡"><a class="markdownIt-Anchor" href="#五-资本主义与社会主义的平衡"></a> 五、资本主义与社会主义的平衡</h3><p>提出者认为，资本主义是世界的自然状态 —— 因为资本主义的竞争机制最接近于生物学意义上的 <em>社会达尔文主义</em> 和 Thomas Hobbes 提出的 <u>自然状态</u>，即弱肉强食、适者生存的原始丛林法则 —— 但社会主义不是。然而，健康的资本主义系统必须依赖社会主义原则来维持运转，任何单一的纯粹制度都无法让社会保持稳定。</p><p>作为例子，没有现代医学的原始时代，人类虽然完全顺应自然，但往往寿命很短；资本主义就是这种纯粹的自然环境，通过适者生存的法则提供内在激励。而社会主义像是现代医学，比如福利制度，介入并纠正了自然状态下的残酷，确保社会中的个体不会因为生病或贫穷而轻易衰亡。</p><p>但如果将现代医学推向极端，例如开始克隆人类了，那伦理危机就会被引发。因此，提出方认为政府应当用社会主义的政策药物来维持资本主义肌体的健康。</p><p>我完全不认同整个观点的大前提，也就是「资本主义等同于原始丛林法则」。真正的资本主义有个核心前提：受法律保护的私有产权。在没有规则的原始状态下，最强者可以直接暴力抢夺他人的资源，这属于封建强权。资本主义无论如何都是相对现代、被精心设计出来的系统，依赖于国家机器来保护私有财产并维持自由市场的秩序。</p><p>再就是有参与者提到，如果观察过去的原始人，会发现小型部落中，由于没有剩余财富的积累，社会呈现出的是高度的 <u>平均主义</u>：食物共享、共同抚养后代；没有财产私有制，也就没有资本主义。自然而然便破解掉了「资本主义是世界的自然状态」这一点。反而是日后人口膨胀、物资变多了，资本主义才形成。</p><p>不过思考尚未停止，如果在逻辑推演上再下沉一层，就会想到：<strong>现代人类社会的制度能套用生物学和进化论的理论吗？</strong></p><p>是，自然界确实存在弱肉强食，但那是为了基因延续和获取卡路里的物理法则 —— 狮子捕杀斑马，吃饱后便会停止，而不是建立斑马养殖场、发行什么「斑马肉期货」来剥削其他狮子的劳动剩余价值。资本主义的本质，并不单单是私有产权，还包含了信用扩张、跨期资源错配、资本的复利增长…… 归根结底，都是人类想出来的虚构概念。</p><p>原始社会的食物共享和共同抚养，同理，也仅仅是特定环境下生存策略的一种，并不能等同于任何现代经济制度。</p><p>想到这些，再去思考提出者提到的和社会主义有关的观点，就会发现一切都不成立：资本主义和社会主义都是现代社会的补丁；用克隆人带来的伦理危机来警告社会主义的极端化更是犯了 <u>滑坡谬误</u>。</p><h3 id="六-ai-取代工作"><a class="markdownIt-Anchor" href="#六-ai-取代工作"></a> 六、AI 取代工作</h3><p>我希望所有类似的活动，都可以将 AI 相关的话题 ban 掉！</p><p>从 2023 年 ChatGPT 横空出世以来，AI 就是个大家都在聊的事情。讨论当下的事情没什么不好，只是它被讨论了太多次，人们提出了无数个不同方向的观点，现在已经很难去辨别你的观点是否是你自己的，还是你从别处继承来的。</p><p>不过，该评论还是要评论的。提出者认为，关于「AI 将取代所有人的工作」或者「AI 会毁灭全人类」的说法纯属炒作。作为一名软件工程师，他认为 AI 仅仅擅长于处理训练数据中存在的事情，本质上不过是个高级的自动打字工具。</p><p>反驳中，有人提到 Archive 上的一篇论文：AI 能够解决非平凡的数学问题，而且这些问题并不在训练数据中。数学家 Tim Gowers 声称 AI 使用了非显而易见的技巧。</p><p>实话说，我不清楚他具体说的是哪篇论文，因为我就没有阅读论文的习惯和耐力。不过明说的 Tim Gowers，我还是查到了他当时具体说的是什么：他让 GPT-5 去解一道题，而 GPT-5 使用了 <u>Kolmogorov-Riesz 引理</u>（而我对此自然是一无所知了），也是他最初并未想到的。但这无法证明 AI 使用了不在训练数据中的内容，这只能证明 GPT-5 在数学方面上有过广泛的训练。</p><p>为了进一步捍卫自己的观点，提出者又说，AI 完全不知道人类是如何在三维空间中使用物体的，所以它给出的产品设计很糟糕 —— 但这不是因为模型本身并不具备「看见」的能力么？收集数据也好，开发外部的 3D 软件接口也好，和模型本身的推理能力并不在同个层级上吧。</p><p>随后讨论出现了目前更为常见的妥协派观点：AI 会让一部分工作消失的同时创造更多的工作。</p><p>指出这一点的人说，「虽然确实有人被取代了，但在大量引入 AI 的领域，工作岗位的总数实际上是在增长的。」</p><p>另一个人补充道，这是 <u>杰文斯悖论</u>：当某种东西太贵时，大多数人不买；但随着成本降低，需求就会增加。这意味着以前很多公司雇不起整个软件开发团队，但现在有了 AI，软件开发成本降低了，他们反而就可以雇佣更多工程师了 —— 吗？</p><p>杰文斯悖论最初是用来描述煤炭这种 <u>大宗商品</u>（指同质化、被广泛作为工业基础原材料的商品）的：燃烧效率提高会导致煤炭的成本下降，进而引发蒸汽机的广泛应用，最终增加了煤炭的总消耗量。</p><p>但软件代码不是煤炭。代码是用来处理系统复杂性的工具。AI 降低了编写单行代码的成本，软件的总生成量也会呈指数级爆炸开来。但这并不意味着企业会按照同等比例增加人类程序员。因为在这个新结构中，瓶颈已经从「代码的生产」转移到了「代码的验证、集成与需求定义」。</p><p>底层码农被淘汰，这一大方向不假，但站在更高级、抽象一层的系统级工程师，可不见得企业就需要更多。</p><p>在完全由人类编写代码的时代，由于前期生产代码的成本极高，后续的重构和清理屎山代码虽然痛苦，但往往比彻底推翻重写要划算（像 QQ 这种烂东西就除外），因此产业内确实存在大量专门维护旧代码的岗位。</p><p>然而，当 AI 将生成代码的边际成本无限压倒接近于零时，代码的属性就发生了根本性的翻转：原本人类是一个个写屎山代码，现在 AI 是以光才能有的速度拉出屎山代码，谁维护谁就乐着去吧，这根本就是 <strong>廉价的一次性消耗品</strong>。</p><p>让人类去梳理 AI 生成出来的代码逻辑，时间成本和认知损耗远高于重写。那还不如直接抛弃无法通过测试，或者充满冗余的模块，转而修改更高层的约束条件、逻辑提示、架构框架…… 以此让 AI 重新生成一个全新的模块。</p><p>所以人类向更高的抽象层级转移，是不可避免的，因为底层的 AI 代码本质上就是不可读的债务屎山。如果一家公司真的陷入了需要雇佣大量人类程序员，去手工清理 AI 生成的闭源屎山代码的泥潭，那相当于既承受了 AI 逻辑不严谨的试错成本，又要承担人类工程师高昂的雇佣成本，那最开始为什么要引入 AI 编程哩？</p><p>这就引出了讨论中的最后一个切入点。他们提到目前的经济「供过于求」是因为疫情期间的过度招聘。这让我不得不去面对一直以来都不愿意去思考的问题：计算机软件的工作，到底算不算工作？我们去做的那些开源、自由的项目，哺养了 AI，使其淘汰掉了底层的工作。这也是人们常常在说的「程序员创造了留给自己的上吊绳」。但如果，这类工作其实从最开始就行不通呢？</p><p>AI 不过是用来背锅的，程序员们写的无数代码仅仅只是负债 —— 该观点出自于 Cory Doctorow，详情见 <a href="/posts/c089.html#%E5%90%8E%E7%BE%8E%E5%9B%BD%E4%BA%92%E8%81%94%E7%BD%91">这个演讲</a>。闭源的代码越多，需要背负的维护债务也越重，因此开源代码才是未来 —— 那便意味着现在绝大多数的公司，走的都是错误的道路？因为他们的软件是闭源的。而开源商业软件，是让代码交给了世界上任何一位程序员，或者说编程 geek 们。如果这样，公司里还需要那么多程序员么？</p><p>我问了许多问题，但我不会就这样把问题放在这儿，留给你们。因为这显然是个未来我必须去面对的问题：我喜欢的开源和自由软件，到底是不是无法买饭给我吃，也是不是杀死无数程序员的推进器之一？</p><p>先说「开源软件」，也是更广为熟络的概念：它可以创造，且创造了极其庞大的商业价值。但这些价值，并没有分配给写代码的开源贡献者，而是被提供基础设施的科技巨头收割了。</p><p>先前已经说过，每一行代码都是未来的维护债务，那么一家理性的商业公司最该做的事情，自然便是尽可能地将这些债务甩给外部。这也是为什么常被自由的极客们称为「邪恶」的 Google、Microsoft、Meta 等等，会开源他们底层的框架，比如 Kubernetes、React、PyTorch。</p><p>他们当然不是来做慈善的。通过开源，大公司将原本需要内部支付高昂薪水才能维持的代码审查、Bug 修复和功能迭代工作，免费外包给了全世界充满热情的极客和理想主义者们。就他们而言，「自由与开源」的想法是被利用的，让无数程序员心甘情愿地为他们打无偿的工，从而极大压缩了自身的研发和维护负债。</p><p>那么钱被谁赚走了？被掌握计算资源和分发渠道的人赚走了。开源协议，如 MIT 或者 Apache，保证了代码可以被自由使用，这也就意味着 AWS、阿里云等这样的云厂商，可以直接将全世界最优秀的开源数据库、中间件打包成 SaaS 售卖。在这个环节中，云厂商卖的根本不是代码，而是「免除部署和维护痛苦的服务」。</p><p>「自由软件」这一意识形态，实际上要早于「开源软件」。二者区别在于，前者能够通过 GPL 这样的协议，摧毁企业通过闭源形成的技术垄断，以及售卖专有软件拷贝的传统盈利路径。为了彻底规避 GPL 协议带来的风险，资本发明了「开源软件」这一套全新的叙事。MIT、Apache、BSD 这些被开源运动大力推崇的 <u>宽容型许可协议</u>，允许商业公司拿走社区的开源代码、随意修改，然后直接闭源打包成自己的商业产品进行售卖，且无需将修改后的代码回馈给社区。</p><p>所以说，二者在意图上就不同：自由软件运动是社会学和伦理学运动，试图让代码脱离资本的私有化控制；开源运动是商业方法论的迭代，主要将开放协作的成果嵌入到资本的全球供应链中。</p><p>那么自由软件到底能不能赚钱？我们必须转移现有的商业逻辑：已知，代码本身无法被垄断和售卖，那就需要去售卖围绕代码产生的稀缺物。而在现代的商业环境中，这种稀缺物有三种形态：</p><p>一、售卖「免责声明和兜底服务」。参考 Red Hat。对于大型企业而言，免费的开源软件其实是最昂贵的，因为没有人会负责突如其来的崩溃，以及直接导致的业务停摆的损失。Red Hat 就是来接锅并解决问题的。</p><p>二、售卖「便利性与基础设施」。正如之前提到的云厂商逻辑，大多数中小型企业根本没有能力，也没有意愿去自己部署、配置和维护复杂的自由软件集群。商业公司，比方说 <a href="http://WordPress.com">WordPress.com</a>，就会将自由软件打包，搭建在自己的服务器上，并配置好一切。用户订阅的并非软件的使用费，而是服务器的电费、带宽费、一键开箱即用的便利费……</p><p>三、售卖「企业级的制度摩擦力」，AKA 开放核心或双重授权模式。软件的核心功能是完全自由免费的，足以吸引全世界的极客和个人开发者去使用并形成生态。但是，一旦软件被用在大公司的企业环境中，那些专门针对大公司合规性要求开发的功能，比如 SSO，就会被严格闭源并收取许可费。</p><p>知道了这些后，就会发现，真正能够带来丰厚利润的环节，早已脱离了「写代码」这一纯粹的创造性行为。没办法啊，资本市场根本不为「优雅」买单。</p><p>这倒也解释了为什么 AI 的出现是历史的必然。如果资本的最终目的是将写代码的边际成本无限压缩，并将所有的技术负债甩脱，那么 AI 就是他们梦寐以求的终极开源劳动力 Pro Max。因为 AI 可不需要休息，不会被开源精神感召，也不会为了代码的自由与巨头抗争啊。赚不到钱的不是自由软件，而是那个只想躲在屏幕后、指望靠纯粹的极客理想和一行行开源代码就能体面生存的黑客 —— 我们！</p><h3 id="七-放弃宗教中的形而上学与来世观"><a class="markdownIt-Anchor" href="#七-放弃宗教中的形而上学与来世观"></a> 七、放弃宗教中的形而上学与来世观</h3><p>提出者是一位前科普特基督徒。小的时候，即使家里人都住在纽约上州，离教堂有一小时的车程，他们也会每周去三次。因此，他小时候便被灌输了「死后会在天堂或者地狱度过永生」的观念，并将其视为理解现实的基石。</p><p>尽管他之后不再信仰死后的世界，但他紧接着陷入到了 <u>荒诞主义</u> 的困境中：我和其他人死后，可能什么都不会发生。也就是说做什么都没有意义，反正一切都不重要。</p><p>提出者引用了 Marx 曾说过的，宗教不过是精神的鸦片，带来的幻觉虽能缓解现实的痛苦，但也消解了人们改变现实的动力。因为对天堂的期盼、圣经里教诲的「要把财富积攒在天上」，在逻辑上导致了对现实生活的消极妥协。</p><p>宗教，特别是关注来世的宗教，在根本上是「否定生命的」。这是典型的尼采哲学观点，即认为将价值寄托于死后的彼岸世界，本质上是对现世肉体和真实生命的贬低 ——「上帝已死」在这里，被提出者用来指代「随着现代认知的发展，传统的 <u>形而上学</u> 和客观道德体系已经崩塌」。</p><p>小标题和刚才都提到了「形而上学」。以防万一有读者不清楚这是什么 —— 毕竟不是所有人都有精力学习哲学，你说对吧，竞技编程和竞技数学 —— 这是古希腊时期，研究「存在」和「事物本质」的学问。不过在本次的对话中，形而上学指的是那些超越物理经验、无法被科学证伪的假设，例如死后的天堂与地狱、神的存在，以及对话中提到的宇宙终极意识。</p><p>说了这么多，提出者的观点是什么呢？他认为既然无法触及到客观的形而上学现实，那不如直接去接受宇宙的混乱，利用人自身的主观体验去赋予当下生活的价值，而不是依赖虚构的来世承诺。</p><p>为了做到这一点，提出者提议将冥想和祈祷等行为，从神学框架中剥离出来。现代神经科学已经证实了正念冥想可以改变大脑的神经可塑性，因为它们触发了特定的心理和神经机制，而不是因为有神明在倾听。因此，人类可以继续保留这些有益的实践，但不需要相信其背后的超自然解释。</p><p>说完提出者的主张，再来听听其他参与者们的想法吧。</p><p>首先是一个相当经典的逻辑反驳：如果宗教是适应不良的，为什么它会出现在几乎所有的人类历史中？确实，宗教在早期人类社会中具有极高的生存适应价值，因为它提供了超自然惩罚的约束，促进了大规模的社会协作。提出者的回应是，在拥有了科学体系的未来后，这种依赖来世驱动的机制将不再是最优解。</p><p>其次是 Jonathan Haidt 的观点：人类进化出了围绕「神圣事物」聚集的本能。这解释了世俗化带来的副作用。当宗教机构衰退后，人类失去了每周定期聚集、建立社区纽带的物理和精神场所。如果抽离了共同的形而上学信仰，社会会面临如何重新构建群体凝聚力的现实难题。</p><p>最后是将「期盼天堂」解构为人类普遍的心理防御机制。在心理学中，人类常常为了逃避当下的困难，而将希望寄托于未来，例如「等我做完这件事，我就去告白！」。来世的概念被视作这种心理模式在宏观尺度上的体现，因为它为人类面对死亡恐惧和现世困境提供了一个逃避出口。</p><p>和人际关系一样，虽然我对宗教话题有着主观上的意见，但我其实也不爱讨论它。因为它是个非常主观的概念，讨论与否都极度依赖于当事人的情况。每个人眼中的宗教都各不相同。我们仅能分享看到了什么样的杨桃，但也无法就「杨桃到底是什么形状」来争个高低 —— 咋，我看到的五角星形状，就不是杨桃的形状了么？</p><p>比方说去评论「宗教是精神鸦片」这件事，我无法去否认宗教确实对于痛苦的人们而言，是止痛药。没有改变导致痛苦的现实物质条件之前，人不吃止痛药，只会被痛死，而不是觉醒。用科学替代宗教，听上去容易做起来难：你要如何保证你不是在拜一尊名为「科学」的偶像呢？</p><p>宗教好用就好用在，人们可以将无法承受的焦虑和责任外包给一个全能的实体。因为世俗的正念冥想，要求个体在内部消化这些焦虑，意味着该个体必须足够强大 —— 世上没有那么多强大的人，但就算是弱小的人，他们也是人。有这种可以推卸掉一切责任的心理释然，我不认为是件坏事。</p><p>再就是科学和宗教，并不是彼此的对立面啊。怎么可能互相平替生态位呢？</p><p>唯一值得担忧的是宗教的权力结构。当一种宗教的主张开始干预世俗法律、定义何为罪恶、甚至指导资源分配时，它就变成了一个拥有绝对质量的客观社会实体。这是因为宗教的底层架构建立在「神圣启示」和「不可篡改的绝对真理」之上，而人们没有实证数据去反驳一句「这是神的旨意」。</p><h3 id="我对本期的看法"><a class="markdownIt-Anchor" href="#我对本期的看法"></a> 我对本期的看法</h3><p>尽管我巴啦巴啦说了一大堆，但我实际上对这一期的讨论并不是特别满意。因为参与者的多数观点并没有完美地满足这些条件：</p><ul><li>拥有真正的观点，而不是重复的、继承来的，而是经过深思熟虑的、思考过的、检验过的、真实经历得出的、真正相信且能够捍卫的</li><li>不要将个人恩怨包装成深刻的见解</li></ul><p>或者更简单来说，许多观点不够「不受欢迎」，不够具备争议性。如果一个观点是大家听了就会想要快速赞同的，这和车轱辘话没有什么区别。讨论出自于争议，不论是出于自保还是什么理由，而决定不提出内心中那些不被欢迎的想法，那你就不应该出现在这场活动里。</p><p>这和访问个人博客时，近乎一定会看到的「博客是写给谁」这个主题一样：博客是写给自己的，还是写给他人的？我实际上对这个话题没有太久的思考，因为我最开始就认定了博客是写给自己的。观众可是雪山上的一百万条狐狸，以及你要喂给狐狸的酱板鸭、牛肉面、意大利面、鸳鸯锅…… 为了满足所有人的需求，避免被化身成人形的狐狸、酱板鸭、牛肉面、意大利面、鸳鸯锅…… 追杀，几乎是不可能的。</p><p>「雪山上的狐狸」这个笑话出自于近期的邵氏武侠 AI 二创视频……</p><p>况且这种写法相当无趣。上篇文章里我引用了 Spike 的 Zine，但是忘记引用原作者的 <a href="https://flowtwo.io/post/on-10-years-of-writing-a-blog-nobody-reads">文章</a> 了：少使用无用的、谨慎的短语，这会让你的观点变得无聊、没有争议性，自然而然也没有人想要就此进行例如反驳这样的进一步讨论。</p><p>惊喜的是，在我那篇文章发布之后，Spike 对这个观点进行了更深一步的 <a href="https://taxodium.ink/%E8%AF%BB%E3%80%8A%E5%AD%A6%E6%9C%9F%E4%BD%9C%E4%B8%9A%E6%8A%A5%E5%91%8A%E3%80%8B.html">扩展</a>。他在这篇文章中分享了作家三毛的《学期作业报告》。从批注中能看出三毛的观点很犀利，以及主观性很强。比方说学生宋平在作业开头简单地说了说自己对庄子的看法，短短两句话便被三毛批评了没有理解庄子哲学的核心 —— 不过可惜的是，我并没有读过老子、庄子的作品，目前也只是在缓慢学习中国文学，也就无法展开说说了。</p><p>这个报告中，三毛说「主观总比无观来得好」。什么是「无观」？没有想法的人自然是无观的，观点的搬运者则是更隐蔽的无观者 —— 他们将别人的观点，未经任何思想上的处理，便打包成了自己的观点。「那些不受欢迎的想法」活动，本意是拒绝这些无观者，但每次翻阅记录，只能感受到观点们停留在了表面，亦或者根本违反了活动的规则。</p><p>我来，是为了吸取他人的独特想法，并将其进行对抗、最终得出一个属于自己的见解。而不是花费数个小时翻阅记录，来听这些泛泛其词的！</p><p>和朋友讨论这件事的时候，我得出了这样的结论：参与者第一次参加，也有可能是最后一次参加，那更有可能分享的是他们认为的，表面上的自己。这是保护机制，大多数人们都会认为自己内心深处的「不受欢迎」的想法是具有争议性，且对它被质疑一事透露出脆弱的一面，自然也不会选择在一帮陌生人面前说出它们。</p><p>好吧，但大家来参与这种活动，不正是为了接触到有争议性的想法，并与他人的思想进行碰撞么？这又回到了我刚说的，我想听到争论，不是大家都赞同的事情。</p><p>三毛接下来又指出：「太多『也许』『也许』，『不知道』又『还是不知道』，现在又出来了个『好像』。你大概十分安然于不确知的事情，是不是？」她在批评宋平时，自己也用了个「大概」。看上去好似在犯自己刚说的错，实则让听者清楚得很 ——「我要表达的是这个，我认为这个就是对的，你听上去也会觉得我是这个意思，所以根本不需要多余的、『谨慎』的语言。」</p><p>现在我终于理解小学时，语文老师在我的一篇日记上写的评语是什么意思了。那时我写，「今天是阴天，我讨厌阴天！」而语文老师评「阴天很正常！」死脑筋儿的我一直认为这是老师的多管闲事。阴天正常又如何？我不喜欢就是不喜欢啊。但是写作就应该清楚、清晰：为什么讨厌阴天？具体是阴天的什么让我如此厌恶？</p><p>表述观点、服务客人也是一样的：把脑子里想到的东西统统说明白。有些东西你不说，对方是不知道的。这里提到「服务客人」是因为，我最近换了个服务生的兼职，学习了一些「待客之道」，例如要和客人说明白自己做一些事的原因是什么，否则客人不明白，还会产生不必要的误会。这些原因又往往都是善意的，例如为了他们吃饭方便，带去刀叉，放下时可以解释一下为什么自己带来了刀叉、客人可以用刀叉干什么。听到这些解释，客人不会觉得有什么不好，反而是什么都不说，才会让他们遐想。</p><p>再就是谨慎的语言，会让听者质疑你到底信不信任你的观点。如果提出者都不信任自己提出的观点，那讨论下去还有什么意义呢？你也不过只是个观点的搬运者，怕是根本不理解它吧。在宋平使用了「绝对」二字后，三毛高兴地写道：「『绝对』两字终于出来了，你自己看见了吗？终于肯定了自己的眼光和看法，好。」且三毛发现，宋平在聊电影时不仅越说越有自信，谨慎的语言越来越少，说得又好又有自己的见解，和前几个部分的内容截然不同 —— 是啊，只有在你说一件自己真正相信、认同、喜爱的事情，你才会说得自信、吸引人继续看下去。而不确信的、不自信的文字，只会让人心想不够好、不够有说服力。</p><p>活动的参与者们在发言时，也使用了大量的谨慎的语言。「我认为」「应该」「我猜」…… 数不胜数。英语使用者们有一个不好的习惯，我想要特地指出来，那就是在口头上大量地使用 <em> uh</em>、<em>like</em> 和莫名奇妙的形容词，例如 <em> literally</em>、<em>basically</em>，好似没了它们就没法说话一样。这些习惯难以纠正，因为我也会这么说。它是大脑还没想明白接下来要说什么时、嘴巴先占了位的习惯。大量使用这些 <em> filler words</em>，会让自己的口语水平下降，且极度依赖这些模糊的说法，而不是准确的词汇。我推荐的方法是，直接不说话，让自己的脑子慢慢跟上，为此说话语速慢一些也没有关系。</p><p>那么参与者们到底是对自己的观点没有信心呢，还是单纯讲话依赖于 <em> filler words</em> 呢？我不得而知，但是听上去都会有「说者不够确信自己在说什么」的意思在。</p><p>顺带一提，这是我第一次阅读三毛的作品，虽然仅是批改学生的作业，但将自己的性格显露得活灵活现。例如宋平说自己「难过死了」，三毛紧跟着写了句「可爱的孩子，可以难过，不要死，比较仍能更爱载湉，不死好不好？」一个报告里竟能出现两个可爱的人！</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;三月份的「那些不受欢迎的想法」活动结束了。说实话，这次的内容并没有二月份的那么印象深刻。简单来说，便是不够「不受欢迎」。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="心理学" scheme="https://blog.cytrogen.icu/tags/%E5%BF%83%E7%90%86%E5%AD%A6/"/>
    
    <category term="社会学" scheme="https://blog.cytrogen.icu/tags/%E7%A4%BE%E4%BC%9A%E5%AD%A6/"/>
    
    <category term="哲学" scheme="https://blog.cytrogen.icu/tags/%E5%93%B2%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>没有情人的情人节</title>
    <link href="https://blog.cytrogen.icu/posts/1572.html"/>
    <id>https://blog.cytrogen.icu/posts/1572.html</id>
    <published>2026-03-15T04:00:00.000Z</published>
    <updated>2026-07-06T21:52:06.974Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>室友上个月主持的 <a href="/posts/fbd.html">活动</a> 里，我忘了说一个话题。不过正好也可以借此说一些我的观点。活动那天是情人节，而提出者说：「人们不需要恋爱关系。」</p><span id="more"></span><p>提出者会提出这么有争议性的话题，很有这个人的风格。这个观点也是他常常挂在嘴边的，就我看来更像是一种警戒 —— 谁知道呢？因为本文的主角并不是他，我就不深入他的情况了，只会简单解释一下他的观点。</p><p>顺带一提，我在阅读 Spike 最新出炉的 <a href="https://taxodium.ink/47.html">Zine</a> 的时候（我好想念这个系列），看到了这句话：</p><blockquote><p>我过去使用了太多的限定词和冗长的短语。那是我口语的直接翻译，事实证明，这是一个糟糕的写作策略。如果你的目标是让别人阅读 ⸺ 并且希望他们喜欢 ⸺ 你的文字，你应该努力编辑你的想法。</p><p>以下是我当时几乎在每个句子开头或结尾都会添加的无用短语样例：</p><ul><li>我认为……</li><li>我觉得……</li><li>我相信……</li><li>对我而言，……</li><li>感觉就像……</li><li>似乎……</li><li>在我看来……</li></ul><p>刚开始写作时，这是我的最坏习惯。这种废话只会让读者疲惫不堪。在观点文章中任何地方加上「我认为」都是多余的。</p><p>使用这种「谨慎」的语言只会让你的观点变得软弱无力，以至于无法引起争论。如果你用「我觉得……」开头，那么后面说的任何话都没人能反驳，因为这只是你的感受。读起来实在乏味。</p></blockquote><p>说得真好！好的想法可以立即让人反思自己。所以我之后会很少使用这类短语。这意味着我的文字会听上去像是在陈述事实，但并不是这样，一切都是观点。或许是时候该写一个 <code>/glossary</code> 页面了。在 Eltrac <a href="https://www.geedea.pro/essays/on-wording/">提出这个概念</a> 的时候，我就有考虑去写，但一直拖延没有这么做。</p><p>回到正文吧。</p><hr><p>提出方的观点在于，人类需要物理接触，这包括拥抱和抚摸。但在众多文化中，异性 —— 或者同性，如果对方将同性恋放在眼里的话 —— 之间做这些行为会被认为是浪漫的，从而认为只有恋人可以做这些。如果可以随意在物理上接触他人，或许许多恋情也没必要存在了。</p><p>这么说的原因在于，许多恋情的本质其实仅仅是「连接」。人们渴望陪伴，只是单纯地想和某个人多待在一起。但在有限的社会标签下，人们往往会误将这种对深度连接的渴望认作是「恋爱」。为了合理化这种物理和时间上的亲近，他们选择了「在一起」，误以为这就是爱情，随后便无可避免地被卷入了以「结婚」为最终目的的传统轨道。</p><p>恋爱实在是个过于复杂的话题。人们到底渴望从恋情中获取到什么？是理解吗？是关怀吗？还是性需求？貌似除了性，朋友们也可以提供这些东西。当然你要是个愿意找炮友的人，那性需求也可以被满足。</p><p>然而，社会将恋爱美化得太严重了，好像没了它，人就是不完整的，是失败的。</p><p>朋友甲说的「恋爱关系」，其实可以看出来，专指被社会标签化过后的「恋爱关系」：人们以结婚为目的，决定一辈子都要在一起后，怀孕生子、将两个家庭融合在一起，度过标准的一生。</p><p>结婚是我和朋友们最讨厌的概念之一。比如朋友甲，因为是个法律脑袋儿，所以他认为婚姻的重点在于「共享资产」。他不相信婚姻的契约，认为那只是将二人强行绑定在一起的说辞 —— 毕竟如果有心的话，二人不结婚也可以一直在一起。又由于他是个不喜欢遵守「社会规则」的人，「不结婚生子不行」的观念在他这里也行不通：老了可以花钱请护工，怕护工欺负自己那就培养类似于徒弟或者养子或者信徒 —— 他有信心做到这一点。只要有钱和人格魅力，就可以规避通常人会认为只有结婚生子才能做到的事情。既然如此，为什么要花费精力和人进入恋爱关系，然后将自己的生活搞得一塌糊涂呢？</p><p>传统婚姻或深度恋爱关系之所以成为主流，很大程度上是因为它是一种打包方案。人们将情感支持、生理需求、经济合作甚至养老保障全部集中在同一个人身上。这种做法降低了前期的交易成本和维护难度，但假设伴侣变质或背叛，个体的整个生活运转就会面临全面瘫痪，这也是为什么朋友甲选择不进入打包关系，而是将需求分散给不同的关系，例如朋友。</p><p>值得说明的是，他并不否认人类渴望且需要亲密关系这一事实。他真正反对的，是将「亲密关系」与被社会标签化的「浪漫关系」强行画上等号。深度的友谊同样可以通过长期的摩擦建立起坚韧的羁绊，提供不可替代的情感支撑与连接感。既然亲密并不专属、也不必然导向爱情，这一切就完全可以在剥离了恋爱与婚姻的传统叙事后独立存在。</p><p>当然也有另一部分参与者不认同这个观点：爱情就是人生中不可缺失的一环。亲情要，友情要，爱情也要，这才是健全的人生啊。况且能够亲密地抚摸对方，不道德、不知羞耻！</p><p>朋友甲所反对的人生并不是错的，我也不觉得他推崇的人生是所有人都能做到的。但「标准的人生方式」早就应当不再成为任何人的束缚。我已经看到过太多，为了「普通」和「正常」而强行过上这种生活的人，他们的人生是如何被一步步毁掉的。如此之多的案例，不得不让我去思考这种生活形式的正确性 —— 说不定，它其实已经不适用于现在的人们了。</p><p>三月份的「那些不受欢迎的想法」活动会照常举行，我依然没有打算出席，自然也不清楚这次都有什么有趣的想法被抛出。不过我知道其中一个人（朋友乙）的话题，这和 <em> momentum</em> 有关。中文翻译过来叫作「动量」，也就是物理学中常说的牛顿第二定律。如果用大辞泉词典去查这个词的话，会发现它在日本还有个意思：惰性。</p><p>过去的一切，社会的规矩和经验，都形成了庞大的动量，在人准备前进时，推动着人。你会被推进得很快，人生也会看上去顺利起来，但这不是你的力量，这是惰性。你只是又一次遵循了前人的脚步，走在已经踩平的路上。这时候，再有人想去走隔壁的草丛，想必都会被认为是个怪胎吧。</p><p>朋友乙说，这个世上到处都是受动量驱使的人们。过去我从社交网络上听到过一个类似的概念，叫作「空心人」。这种人对于事情的看法只有一个标准，那便是他们认为的社会标准：「普通人不会这么做」、「普通人应该这么做」。事实是，世上没有「普通」，只有「普遍」，而「普遍」不等同于「正确」。</p><p>自然，「空心人」这个概念实在是过分傲慢了，毕竟不能因为对方做的事情和你不同，就如此贬低对方吧。但这也让我思考，人们做一件件普遍的事情是为了「正确」，还是为了随波逐流？说到底，究竟有多少人知道自己现在在做的事情，是出于自己想这么做，还是认为自己应该这么做呢？要知道，被无数人追捧的标准人生，从来都不是为了确保每个个体的幸福而设计的。</p><p>我有一位有些讨人厌的朋友丙，在和朋友甲或者朋友乙接触时，喜欢说这句话：<em>But it's not normal.</em> 但问他什么是 <em> normal</em> 的话，他也答不上来。毕竟 <em> normal</em> 就没有一个准确的定义，它是一种被无数人臆想出来的存在，是主观的集合体。你就算过得不是个 <em> normal</em> 的人生，你也不会死。虽然会受到社会部分人的谴责，但也会有另一部分支持这种生活习惯的人在。如果不想要去能够容纳自己的群体中生活，转而改变自己的生活方式，从而获得已在群体的支持，亦或者根本不去考虑这种事情 —— 这不就是具有毁灭性的惰性吗？</p><p>情人节到底该不该有情人？有多少情人又是包装成「情侣」的朋友呢？看来我的问题太多了。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;室友上个月主持的 &lt;a href=&quot;/posts/fbd.html&quot;&gt;活动&lt;/a&gt; 里，我忘了说一个话题。不过正好也可以借此说一些我的观点。活动那天是情人节，而提出者说：「人们不需要恋爱关系。」&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="心理学" scheme="https://blog.cytrogen.icu/tags/%E5%BF%83%E7%90%86%E5%AD%A6/"/>
    
    <category term="情感" scheme="https://blog.cytrogen.icu/tags/%E6%83%85%E6%84%9F/"/>
    
  </entry>
  
  <entry>
    <title>奶茶店毕业</title>
    <link href="https://blog.cytrogen.icu/posts/7ae3.html"/>
    <id>https://blog.cytrogen.icu/posts/7ae3.html</id>
    <published>2026-03-14T04:00:00.000Z</published>
    <updated>2026-03-14T22:56:03.574Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>早在 <a href="/posts/dc84.html">第一篇月刊</a> 里，我就说过去年八月份我找了份兼职，主要是得快速还笔钱。这一做就是半年，而在二月份我提了离职、逃跑了。</p><span id="more"></span><p>先从最开始说起吧。当时我的银行账户已经支撑不起我日常的吃喝拉撒了。就算是和室友合租，有父母给的几百块生活费，不欠钱活下去依然很难。不得已，我只能将开发项目的时间分出来，花费在打工上 —— 那会儿连公司都没有被注册，项目跟个人项目没有什么区别，更别说赚钱了。</p><p>粉领工作虽然赚得不多，但胜在成本低，不需要培训很久就能上岗工作。尤其是我在大一时就做过奶茶店的兼职，去新的店里工作学习很快。于是我在网上找各个招人的店，一个个联系过去 —— 有些人无视了我，有些人问了我点问题后就不回我了… 最后只有家附近的一家本地知名奶茶品牌的店同意让我来培训。</p><p>因为隐私还是得要的，这个奶茶品牌是什么我就不说了。</p><p>奶茶店的员工要做的事情并不算多：做前台收银、摇奶茶、补货、开店闭店，如果店里提供小吃的话做小吃 —— 这种小吃多数以甜品或者炸物为多，我去的这家店没有甜品，只有炸物，做起来也方便，丢到油锅里炸即可。</p><p>经济情况从某一年开始，从来都没有好转过。Trump 第二次竞选的时候，就有大量认为民主党搞坏了经济的老白人上网支持 Trump，认为他可以让美国的经济再度伟大。实际上，什么也没有变。说到底，一个联邦的总统怎么可能一下子就改善整个经济体系呢？人们是住在地方内的，地方有自己的官，地方外的州也有自己的官。人们总是将希望寄托于一个人，听信政客们的承诺，最后只能活在比过去更痛苦的生活中。但也没有办法，除了相信这些系统的明面指定人，还能去相信谁呢？</p><p>在蜜雪冰城来到纽约之前，奶茶大致可以分成两种：没有品牌的，和有品牌的。没有品牌的奶茶，估计只有三四美元吧，通常都是广东饼店用粉冲泡的，成本本来就很低，味道只能说能喝就行。而有品牌的，价格会高一些，目前来看市场价得在六七块钱之间，只说最经典的珍珠奶茶。这里有一些用的依然是粉，只是粉质量更高，虽然我喝的话只能喝出来恶心的粉味儿，和没有品牌的奶茶没什么太大的区别。如果是标榜自己用真奶的品牌，价格还得高一些，我喝了不会觉得肚子痛，但为了钱包和身体健康还是少喝为妙。</p><p>奶茶店除了奶茶，卖的东西还有水果茶：多数都是使用果酱或者水果风味的糖浆。能用得起真水果的，很少很少。我大一兼职的那家奶茶店，就有使用真水果，但是其他店员都不会检查它们的质量，导致我每次上班就要清理大量腐烂、长白毛的水果，恶心死了。没多久，这家店便倒闭不做了。</p><p>那么蜜雪冰城对本地的奶茶品牌造成的影响有多大呢？大杯的奶茶或者百香果果茶，只需要两三块钱，花没有品牌的奶茶所需的钱，喝到了有品牌的奶茶的质量。可能会有人说蜜雪冰城也没有那么好喝吧，问题是两倍价格的有品牌的奶茶，不见得有好喝多少。我就不一一点名了，纽约客或许会知道我在说哪些品牌。</p><p>奶茶店的生意如何，和地段有很大的关系。繁荣的地段，尤其是约会圣地、有着逛街氛围的地方，奶茶店就是很容易满座。学校附近也不错，学生们多数喜欢放学后来喝杯奶茶。如果组团一起来，还会点小吃一起吃、聊聊天再回家。</p><p>不过这家店所在的地段有些特殊，它算是一种住宅区，老人偏多，还有许多流浪汉。尽管附近有足足三所学校，但是有实际购买能力的只有大学生。要问我为什么知道，因为另外两所里，一所是小学，另一所是高中 —— 我的高中。这家高中的同学们，都不住在附近，而是住在坐地铁半个小时远的、低购买欲住宅区。有零花钱时不时买奶茶喝的，并没有那么多，这里的另一层原因是「奶茶很贵」。</p><p>这家店的老板和经理是对夫妻，对员工的要求很高：穿着好看、外貌漂亮、做事认真、年轻能干、不能属鸡。要求高重点在于「做事认真」和「年轻能干」上，比方说他们会定时看监控，看员工们是否在玩手机。其实这也还好，对比一位朋友兼职的店，那边的经理还会偷听员工们聊天。如果有人抱怨很累的话，就会打电话过去质问。好恐怖喔。</p><p>他们最让我讨厌的点是动不动就言语攻击。有些事情明明不是我的问题，有些甚至会是他们的问题，他们却会时常说我这个说我那个，听着很烦。所有的线上交流都是通过电话或者微信 —— 都在海外了也要使用微信吗，腾讯的影响力可想而知 —— 而微信群聊，通常会变成公开的处刑场。他们会公开艾特要挨骂的人的账户，接着一大段文字发过来，有时是很直接地训斥，有时则是阴阳怪气。但是被挨骂的人，也没有真的做错什么，很多时候都只是因为信息不对等的问题，而不知道要做某件事而已。</p><p>不过作为严厉的奖励，这家店的卫生条件和责任心不错。</p><p>迫使我离职的原因也很简单：在这家店里继续工作下去对我的精神状态不太好。工资不过是最低薪水的标准、小费拿不到、员工餐也没有，还要和这两尊大佛相处。再加上这家店所在的地段，先前说过，是一个特殊的住宅区，因为它也在另一个金融区的角落，周围还有地铁站，所以租金不低，但客人就是没有那么多。为了「降本增效」，这家店缺人，俩大佛也经常迟到，或者干脆不来、让其他员工临时来工作顶上。</p><p>要知道，小规模的奶茶店一天只会有两个人在，只有一个人的话，是很难同时顾得上前台收银、摇奶茶和做小吃的。我因为他们的迟到，已经吃过许多亏，那些时候我只能绷紧神经，一个人处理店内所有的事情。这里最麻烦的是接单，因为客人们点单的速度很慢，而根据规矩，有客人进来就必须先接单。有时候柜台上已经积累十几单还没开始处理，前台却还有一些客人慢吞吞地在点单，旁边站着已经点了单的其他客人、盯着我看。我能怎么办呢？要是想退款的话，就退款吧，反正我做多少都不会影响到我的工资，老板少赚也只会是老板活该，可怜的只有赶时间的客人。</p><p>有位老员工，便因为这件事受不了、早我一两个月离职了。走之前他说，你的底线在哪里，我的底线在这里。</p><p>他走后，压力便到了我身上。其他员工都是学生，还有实习什么的，一周内能来上班的次数很少。我因为一学期里要做的事情不多，反而要上更多的班，一个人扛住压力。这些压力明显不是我能承受得了的，但就算是那个时候，除了被说「菜」外，得到的反馈也只有「我做事不认真」，尽管我根本不知道哪来的「不认真」，我能做的都做了。</p><p>提出离职那天，感觉一身轻。这半年来收获许多，其实一个月过去，已经不记得自己当时有多么不舒服，只记得自己很愤怒。这些情绪都被记录在日记和聊天记录内，再来看的时候反而觉得陌生。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;早在 &lt;a href=&quot;/posts/dc84.html&quot;&gt;第一篇月刊&lt;/a&gt; 里，我就说过去年八月份我找了份兼职，主要是得快速还笔钱。这一做就是半年，而在二月份我提了离职、逃跑了。&lt;/p&gt;</summary>
    
    
    
    <category term="日常生活" scheme="https://blog.cytrogen.icu/categories/%E6%97%A5%E5%B8%B8%E7%94%9F%E6%B4%BB/"/>
    
    
  </entry>
  
  <entry>
    <title>入门编写 SVG</title>
    <link href="https://blog.cytrogen.icu/posts/a778.html"/>
    <id>https://blog.cytrogen.icu/posts/a778.html</id>
    <published>2026-03-11T04:00:00.000Z</published>
    <updated>2026-03-11T23:34:26.946Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>这一切要从我决定重构 <a href="https://cytrogen.icu">https://cytrogen.icu</a> 开始（当你看到这篇文章时，访问该链接就能看到雏形了）。原本它是我的博客网站的地址，后来我想要一个更像是个人网络的设计，即根域名为个人主页，博客网站放在 <code>blog</code> 子域名上。</p><span id="more"></span><p>个人主页、个人主页…… 怎么样的个人主页更能展示出我的「个性」呢？除了 <a href="/posts/c089.html#%E7%BA%AF%E6%96%87%E6%9C%AC%E7%BD%91%E7%AB%99%E7%9A%84%E5%B0%8F%E5%9E%8B%E5%90%88%E9%9B%86">先前</a> 介绍的 <code>ellesho.me</code> 外，我还看了 Hacker News 的这个 <a href="https://news.ycombinator.com/item?id=46618714">帖子</a>，里面有许多设计非常有趣的个人主页，不过博客网站依然偏多。不是对博客网站有任何意见，只是我认为，我不需要另一个以文本为主的网络载体：我已经有了博客网站，还有了只能显示文字的胶囊。</p><p>这就需要说到 Web 最为特殊的东西了：HTML、CSS 和 JavaScript。既然是 Web 上搭建的站点，不玩玩这三剑客又怎么行呢？当然，这也不意味着我的个人主页就会充满了 JavaScript、把访问者的设备卡到无法动弹。我依然会遵循「极简 JavaScript」的原则，来完成它。</p><p>小时候游玩过的 Flash 小游戏，让我想要实现类似的内容。不知道读者们有没有玩过 <em> Reincarnation</em> 这款点击解密 Flash 游戏呢？4399 游戏平台将其翻译为《地狱使者》，不过我认为失去了原标题「轮回」的意味。总之它是一款原先发布在 <a href="https://www.newgrounds.com/series/reincarnation">NEWGROUNDS 平台</a> 上的游戏，由 Chris Gianelloni 开发。故事讲的是地狱中逃出去了许多鬼魂，主角小恶魔受地狱之王撒旦指使，要去人间找到这些死人、定他们的罪，最后靠解密让他们「意外」身亡 —— 为什么小时候的我喜欢这种血腥的游戏啊？不过主角小恶魔我觉得很可爱，还是个被迫工作的打工人，经常光着身子撅着个腚走来走去。</p><p>当时的 Flash 游戏，这种玩法单纯依赖于鼠标点击的有很多，比方说各种类宝可梦的网游、《华纳史诗冒险系列》（<em>Steppenwolf: The X-Creatures Project</em>）都是如此。我也想一个类似的个人主页！</p><p>使用 Flash 技术肯定是不可能的了。我也不打算将个人主页做成一款网页游戏，不过一些游戏元素还是可以接受的…… 但这篇文章并不会涉及到这一方面，为什么呢，因为我还没有开始设计和编写。就像标题所说的，该文章的重点在于 <em> SVG</em> 这项技术。</p><h3 id="了解-svg"><a class="markdownIt-Anchor" href="#了解-svg"></a> 了解 SVG</h3><p>SVG 的全称叫作 <em> Scalable Vector Graphics</em>，即 <u>可缩放矢量图形</u>。它是基于 XML 格式的图像格式，用于描述 <u>二维矢量图形</u>。</p><p>说这么多术语以及模糊的概念，大家可能无法很好地明白，我就先来讲解一下计算机里、图形到底是什么吧。<strong>图形本质上是数据的可视化量现</strong>。为了在屏幕上准确呈现这些视觉信息，计算机需要依赖一套特定的编码规则或者说数据格式来解析信息，而这一切大致可以分为两个分支：位图与矢量。</p><p><u>位图图形</u>（bitmap），也被称为 <u>栅格图形</u>（raster graphics），核心结构是由像素点（pixel）排列而成的矩形网格，而像素是数字显示设备上能够被独立控制色彩与亮度的最小物理发光单元。大家熟知的 JPEG、PNG 等，都是位图图形的格式。当计算机系统渲染一张 JPEG 文件时，它读取的其实是二维数据表 —— 表会记录该特定尺寸网格中，每一个坐标位置上像素的具体色彩值。</p><p>不过位图有个大问题：依赖分辨率。因为图像的信息由固定数量的像素点强行绑定，一旦图像被放大、网格被拉伸，计算机就必须运行插值算法，根据原有相邻像素的颜色去推算并凭空生成新的像素来填补填充后的物理面积。作为一个例子，你可以打开任何一个位图编辑器，比方说 Windows 系统的 Paint 软件，在上面随便画点什么，接着将其选中、拉伸，你就能看到许多突然多出的锯齿状像素方块。</p><p>而 <u>矢量图</u>（vector）抛弃了像素网格的概念，转而使用数学公式和几何图元来描述图像。一组由起点坐标、终点坐标、线条粗细和颜色属性共同构成的数学指令，就能在矢量体系中画出一条直线。当矢量图被放大后，计算机会将新的缩放比例代入原有的数学公式中，重新计算并在屏幕上实时绘制出新的图像，从而让矢量图无论怎么放大，都能让边缘保持锐利。</p><p>在互联网普及之前，计算机图形学领域便已经存在成熟的矢量技术：用于打印排版的 PostScript、CAD 软件和 Adobe Illustrator 等专业绘图工具使用的专用格式…… 二十世纪九十年代末，万维网面临着严重的带宽限制和多样的终端显示器分辨率。位图格式在传输高质量大尺寸图像时，会导致文件体积急剧膨胀，且有着先前提到过的、极差的不同分辨率下的缩放表现。矢量图本应该是解决这一问题的完美方案，但是当时的矢量格式大多是编译后的二进制数据，且被各家商业公司作为技术壁垒严格封闭。</p><p>如果将早期 Macromedia Flash 或各类专有矢量文件直接嵌入网页，浏览器无法原生解析这些数据，用户必须下载并安装特定的第三方插件。这些二进制文件对于网页的底层结构而言，也有着许多问题：搜索引擎的爬虫无法读取其中的文本内容，网页开发者也无法使用 JavaScript 去捕获图形内部的元素并产生交互。</p><p>W3C（万维网联盟）认为，互联网需要一种属于自己的、非专有的、且与现有 Web 技术栈深度融合的矢量图形标准。业界纷纷向 W3C 提交关于 Web 矢量图形的提案，其中最具代表性的分别是 VML（Vector Markup Language）和 PGML（Precision Graphics Markup Language）。它们都试图建立基于 XML 的图形描述规范。</p><p>而 W3C…… 哪个都没选，反而成立专门的图形工作组，吸收了这两种方案的优势、想出了 SVG 规范。</p><p>因为 SVG 被设计为纯粹的 XML 文本，因此顺理成章成为了 DOM 树的一部分。网页浏览器不需要插件也能利用内置的渲染引擎对其进行解析，同时图形中的每一条路径、形状都成为了可被精确寻址的 DOM 节点。可喜可贺，可喜可贺。</p><h3 id="写-svg"><a class="markdownIt-Anchor" href="#写-svg"></a> 写 SVG</h3><p>在我的计划里，我的个人主页所会用到的矢量图形并不复杂。没有描边的大色块有着自己的魅力。</p><p>用 SVG 来写只需要知道这五个元素：</p><ul><li><code>&lt;rect&gt;</code></li><li><code>&lt;circle&gt;</code></li><li><code>&lt;polygon&gt;</code></li><li><code>&lt;path&gt;</code></li><li><code>&lt;text&gt;</code></li></ul><p>SVG 应用的是直角坐标系，原点 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mn>0</mn><mo separator="true">,</mo><mn>0</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(0,0)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">0</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord">0</span><span class="mclose">)</span></span></span></span> 位于画布的左上角，X 轴向右延伸，Y 轴向下延伸。所有的几何图元都基于这个网格定位与绘制。</p><p>对于矩形 <code>&lt;rect&gt;</code> 元素，核心属性分别是：</p><ul><li><code>x</code> 和 <code>y</code>，用于确定矩形左上角顶点的精确坐标</li><li><code>width</code> 和 <code>height</code>，分别定义矩形在水平方向和垂直方向上的标量跨度</li><li><code>rx</code> 和 <code>ry</code>，指定圆角的水平和垂直半径</li></ul><p>圆形 <code>&lt;circle&gt;</code> 元素的逻辑基于圆心的半径：</p><ul><li><code>cx</code> 和 <code>cy</code>，标记圆心在坐标系中的绝对位置</li><li><code>r</code>，设定原的半径长度</li></ul><p>多边形 <code>&lt;polygon&gt;</code> 元素用于绘制由直线段连接而成的闭合形状：</p><ul><li>核心 <code>points</code> 属性，在接收一系列坐标对，每个坐标对代表多边形的一个几何顶点。渲染引擎会按照坐标的书写顺序，依次用直线将这些点连接起来，并自动将最后一个点与第一个点连接以闭合图形</li></ul><p>作为一个例子：<code>&lt;polygon points="50,15 100,100 0,100" /&gt;</code> 画出的是三角形。</p><p>文本 <code>&lt;text&gt;</code> 元素将字符数据引入矢量画布。与常规 HTML 中的文本排版不同，SVG 文本需要严格的空间绝对定位：</p><ul><li><code>x</code> 和 <code>y</code> 属性并不代表文本块的左上角，而是文本基线的起点位置。字号、字体族等排版属性需要通过 CSS 或内联属性进行声明</li></ul><p><code>&lt;path&gt;</code> 元素很常用：</p><ul><li><code>d</code> 属性是一系列微型绘图指令的集合：<ul><li><code>M x y</code> 指令负责抬起虚拟画笔并移动到指定的 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>x</mi><mo separator="true">,</mo><mi>y</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(x,y)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mclose">)</span></span></span></span> 坐标，通常作为路径的初始起笔指令</li><li><code>L x y</code> 指令表示从当前画笔位置绘制一条绝对直线到新的 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>x</mi><mo separator="true">,</mo><mi>y</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(x,y)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mclose">)</span></span></span></span> 坐标</li><li><code>Q x1 y1, x y</code> 指令绘制二次贝塞尔曲线。其中 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><msub><mi>x</mi><mn>1</mn></msub><mo separator="true">,</mo><msub><mi>y</mi><mn>1</mn></msub><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(x_1, y_1)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span> 是控制点，<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>x</mi><mo separator="true">,</mo><mi>y</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(x,y)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mclose">)</span></span></span></span> 是整段曲线的最终物理端点</li><li><code>Z</code> 指令没有参数。当它出现在路径数据的末尾时，渲染引擎会自动从当前所在坐标绘制一条直线，径直连回当前子路径的起始点，即上一个 <code>M</code> 指令所在的坐标</li></ul></li></ul><p>知道了这些后，我便可以一步步绘制出，我的个人主页的内容了！</p><p>首先，我希望我的个人主页有一个开场动画：一面山羊头骨为中心的墙，短暂呈现一段时间后，从中间垂直地打开，展示后面的城堡。那么这个墙要怎么画呢？</p><p>先定义一下结构：</p><pre><code class="language-css">&lt;div class="skull-overlay" aria-hidden="true"&gt;  &lt;svg class="skull" viewBox="-200 -250 800 1000" preserveAspectRatio="xMidYMidslice"&gt;    &lt;g class="skull-bottom"&gt;    &lt;/g&gt;    &lt;g class="skull-top"&gt;    &lt;/g&gt;  &lt;/svg&gt;&lt;/div&gt;</code></pre><p>在最外层的 <code>&lt;svg&gt;</code> 容器中（实际最外层的 <code>div</code> 仅作动画用，在写 SVG 的情况下并不需要管），视口属性 <code>viewBox="-200 -250 800 1000"</code> 意味着起始点在于 X 轴的 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>−</mo><mn>200</mn></mrow><annotation encoding="application/x-tex">-200</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">−</span><span class="mord">2</span><span class="mord">0</span><span class="mord">0</span></span></span></span> 和 Y 轴的 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>−</mo><mn>250</mn></mrow><annotation encoding="application/x-tex">-250</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">−</span><span class="mord">2</span><span class="mord">5</span><span class="mord">0</span></span></span></span>，整体的宽度设定为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>800</mn></mrow><annotation encoding="application/x-tex">800</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">8</span><span class="mord">0</span><span class="mord">0</span></span></span></span>，高度设定为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1000</mn></mrow><annotation encoding="application/x-tex">1000</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span><span class="mord">0</span><span class="mord">0</span><span class="mord">0</span></span></span></span>。</p><p><code>preserveAspectRatio="xMidYMidslice"</code> 属性是适配规则，强制 SVG 在容器尺寸变化时保持自身比例缩放，且会裁剪掉超出容器边缘的部分，以确保画面始终完全填满视口、不发生形变。</p><p>由于 SVG 遵循着从上到下的文档流渲染顺序，实际带有山羊头骨的上半部分墙需要在下半部分墙之后定义。现在让我们先完成下半部分墙的内容。</p><p><code>&lt;g&gt;</code> 是群组元素，可以在内部添加数个 SVG 元素来组合起来。对于下半部分墙，我们只需要一个 <code>&lt;rect&gt;</code> 元素，但为了统一性，还是放入群组内：</p><pre><code class="language-css">&lt;g class="skull-buttom"&gt;  &lt;rect class="fill-wall-dark" x="-200" y="250" width="800" height="500" /&gt;&lt;/g&gt;</code></pre><p>除了高度外，其他内容都和视口属性相同，因为需要填满整个画面。高度则是视口高度的一半，毕竟是「下半部分」。</p><p>接下来让我们绘制上半部分墙。在我的构造里，这个墙在画面中心还会有一个山羊头骨，在绘制时需要先画墙、山羊头骨、头骨细节。先画墙：</p><pre><code class="language-css">&lt;g class="skull-top"&gt;  &lt;rect class="fill-wall-dark" x="-200" y="-250" width="800" height="500" /&gt;&lt;/g&gt;</code></pre><p>接着绘制一个山羊头骨的剪影：</p><pre><code class="language-css">&lt;path class="fill-skull" d="M175 380 L158 340 L138 290 L125 245L130 200 L155 170 L200 158L245 170 L270 200 L275 245L262 290 L242 340 L225 380 Z"&gt;</code></pre><p>起初点 <code>M175 380</code> 是头骨吻部的左侧底端，随后用 <code>L</code> 指令向上描绘头骨的左侧边缘：<code>L158 340 L138 290 L125 245 L130 200 L155 170</code>。可以观察出，它们的 X 坐标先减小后增大，因为我想先画出从吻部向外扩张到颧骨，再到头顶时向内收缩。而 Y 坐标一直在减少，因为我们是从左下角开始画、要画到头顶的。</p><p>跨过中心点 <code>L200 158</code> 后，再描绘头骨的右侧边缘：<code>L245 170 L270 200 L275 245 L262 290 L242 340 L225 380</code>。和画头骨左侧的路线相反，Y 坐标一直在变大，X 坐标则是先增大再减少，直至吻部的右侧底端（看 Y 坐标，和起始点的 Y 坐标一致）。最终用一个 <code>Z</code> 指令将它们两个点用一条直线相连。</p><p>想要填充头骨颜色的话，在 CSS 类 <code>.fill-skull</code> 里设置即可。</p><p>山羊头骨的大致形状写完后，我们还需要写两个眼洞和角。其中眼洞的写法和头骨剪影一致，都是用直线勾出形状，这里只说角的写法吧。</p><p>我想要这个角具有弧度，因此需要引入二次贝塞尔曲线。二次贝塞尔曲线需要三个关键点：</p><ol><li>起点</li><li>控制点</li><li>终点</li></ol><p>控制点本身不位于最终渲染的曲线上，但起到了类似于引力的作用，将起点到终点的连线向自身方向拉扯，从而形成特定的弧度。</p><p><img src="/posts/a778/curvequad.webp" alt="" loading="lazy"></p><p>图片来自 <a href="https://svgpocketguide.com/">Pocket Guide to Writing SVG</a>。</p><p>用这张图片来看，会更直观些吧。</p><p>左侧角的绘制从 <code>M130 205</code> 开始，确立了角与颅骨左侧的连接基点。随后 <code>Q70 170 35 110</code> 勾勒角的外侧边缘。这里的曲线从坐标 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mn>130</mn><mo separator="true">,</mo><mn>205</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(130,205)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">1</span><span class="mord">3</span><span class="mord">0</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord">2</span><span class="mord">0</span><span class="mord">5</span><span class="mclose">)</span></span></span></span> 开始，向 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mn>35</mn><mo separator="true">,</mo><mn>110</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(35,110)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">3</span><span class="mord">5</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord">1</span><span class="mord">1</span><span class="mord">0</span><span class="mclose">)</span></span></span></span> 延伸，同时受到位于左上方的控制点 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mn>70</mn><mo separator="true">,</mo><mn>170</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(70,170)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">7</span><span class="mord">0</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord">1</span><span class="mord">7</span><span class="mord">0</span><span class="mclose">)</span></span></span></span> 的牵引。结果便是曲线先向左侧外扩，随后向左上方收束。到达角尖最高点附近时，<code>L65 95</code> 封闭角的顶端，再用 <code>Q85 145 145 180</code> 画角的内侧边缘。右侧角就不用说了，是完全镜像的。</p><h3 id="更复杂的-svg"><a class="markdownIt-Anchor" href="#更复杂的-svg"></a> 更复杂的 SVG</h3><p>到这里，你或许会想，这样写 SVG 好累。我不否认。人类的大脑并不擅长于直观构建二维坐标系内的形状，尤其是过于复杂的形状。一个解决方案是使用更抽象的工具：可视化矢量图形编辑器。</p><p>我高中时学习了 Adobe Illustrator 的使用方式，或许其他的编辑器也是一样的。绘制路径时，往往都会有操作锚点、控制手柄等工具。底层图形引擎会实时计算这些交互动作对应的绝对，或相对的坐标，并能够精准地生成所需的二次，甚至是三次贝塞尔曲线指令。</p><p>不过 Adobe 的东西都很昂贵。Inkscape 是开源的替代品，可以尝试。据说 Figma 也能够绘画矢量图形。它们都可以将结果导出为标准的 SVG 代码。</p><p>如果想要画重复性高的 SVG 图形，也可以通过编写脚本来动态连接路径数据。比方说 <a href="https://github.com/d3/d3">d3.js</a> 这个项目，就能实现一个很有意思的 <a href="https://github.com/d3/d3">例子</a>。</p><p>再就是，在传统开发模式中，SVG 往往被视为等同于 PNG 或 JPEG 的静态外部资源。一旦在矢量编辑器中完成绘制并导出为 XML 代码，其内部的节点结构、填充颜色、描边参数以及路径坐标种种，都被硬编码锁定了。</p><p>怎么解决呢？现代前端开发体系，比如 React 和 Vue，引入了组件化封装与声明式抽象，本质上是将静态的 XML 标记解析为虚拟 DOM 树上的节点。这样的话，SVG 就被包装成了个能够接收外部参数的函数或类组件。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;这一切要从我决定重构 &lt;a href=&quot;https://cytrogen.icu&quot;&gt;https://cytrogen.icu&lt;/a&gt; 开始（当你看到这篇文章时，访问该链接就能看到雏形了）。原本它是我的博客网站的地址，后来我想要一个更像是个人网络的设计，即根域名为个人主页，博客网站放在&lt;code&gt;blog&lt;/code&gt;子域名上。&lt;/p&gt;</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="SVG" scheme="https://blog.cytrogen.icu/tags/SVG/"/>
    
  </entry>
  
  <entry>
    <title>想法在丙午阳中迭代</title>
    <link href="https://blog.cytrogen.icu/posts/e3b9.html"/>
    <id>https://blog.cytrogen.icu/posts/e3b9.html</id>
    <published>2026-02-28T05:00:00.000Z</published>
    <updated>2026-03-11T05:44:51.604Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>这个月我忙于一些现实中的事情，结果连月刊和自己一个月里都做了什么，全都忘了个干净……</p><p>我希望这会是你能看到的，最后一个条目如此之少的月刊。</p><span id="more"></span><details>      <summary>本期导读</summary>      <h2 id="输入"><a class="markdownIt-Anchor" href="#输入"></a> 输入</h2><h4 id="商业与社会"><a class="markdownIt-Anchor" href="#商业与社会"></a> 商业与社会</h4><h4 id="心理与关系"><a class="markdownIt-Anchor" href="#心理与关系"></a> 心理与关系</h4><ul><li><a href="#%E5%A6%82%E4%BD%95%E5%87%8F%E5%B0%91%E5%B0%B4%E5%B0%AC">如何减少尴尬</a></li><li><a href="#%E6%88%91%E4%BB%AC%E6%98%AF%E5%90%A6%E5%BD%BB%E5%BA%95%E5%8E%8C%E5%80%A6%E4%BA%86%E7%A4%BE%E4%BA%A4%E5%AA%92%E4%BD%93">我们是否彻底厌倦了社交媒体？</a></li></ul><h4 id="科学与自然"><a class="markdownIt-Anchor" href="#科学与自然"></a> 科学与自然</h4><ul><li><a href="#a4-%E7%BA%B8%E7%9A%84%E6%95%85%E4%BA%8B">A4 纸的故事</a></li><li><a href="#%E7%9C%9F%E9%A3%9F%E7%89%A9%E5%BF%85%E8%83%9C">真食物必胜</a></li><li><a href="#%E9%A6%96%E6%AC%A1%E6%8B%8D%E6%91%84%E5%88%B0%E8%A4%90%E9%BC%A0%E6%8D%95%E9%A3%9F%E8%9D%99%E8%9D%A0%E7%9A%84%E7%94%BB%E9%9D%A2">首次拍摄到褐鼠捕食蝙蝠的画面</a></li><li><a href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E6%9C%89%E4%BA%9B%E8%A1%A3%E6%9C%8D%E5%9C%A8%E6%B8%85%E6%B4%97%E6%97%B6%E4%BC%9A%E7%BC%A9%E6%B0%B4">为什么有些衣服在清洗时会缩水</a></li></ul><h4 id="技术与创造"><a class="markdownIt-Anchor" href="#技术与创造"></a> 技术与创造</h4><ul><li><a href="#richard-stallman-%E7%9A%84%E4%B8%AA%E4%BA%BA%E7%BD%91%E7%AB%99">Richard Stallman 的个人网站</a></li><li><a href="#%E8%AF%BB%E7%82%B9%E5%A5%BD%E7%9A%84%E5%90%A7">读点好的吧</a></li><li><a href="#%E7%94%A8%E6%9C%80%E5%B0%91%E7%9A%84%E9%9F%B3%E8%8A%82%E5%BF%B5%E6%95%B0%E5%AD%97">用最少的音节念数字</a></li><li><a href="#%E5%B0%8F%E5%9E%8B%E7%BD%91%E7%BB%9C%E5%BE%88%E7%BE%8E">小型网络很美</a></li><li><a href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E5%A4%A7%E5%A4%9A%E6%95%B0%E7%BD%91%E7%AB%99%E5%AE%9E%E9%99%85%E4%B8%8A%E4%B8%8D%E9%9C%80%E8%A6%81-cookie-%E5%90%8C%E6%84%8F%E6%A8%AA%E5%B9%85">为什么大多数网站实际上不需要 Cookie 同意横幅</a></li><li><a href="#%E5%86%99%E7%BB%99%E6%81%90%E6%85%8C%E8%80%85%E7%9A%84-git-rebase-%E6%8C%87%E5%8D%97">写给恐慌者的 Git rebase 指南</a></li><li><a href="#org-mode-%E8%AF%AD%E6%B3%95%E6%98%AF%E7%94%A8%E4%BA%8E%E6%96%87%E6%9C%AC%E7%9A%84%E6%9C%80%E5%90%88%E7%90%86%E6%A0%87%E8%AE%B0%E8%AF%AD%E8%A8%80%E4%B9%8B%E4%B8%80">Org Mode 语法是用于文本的最合理标记语言之一</a></li><li><a href="#claude-code-%E7%A9%B6%E7%AB%9F%E5%90%91%E4%BA%91%E7%AB%AF%E5%8F%91%E9%80%81%E4%BA%86%E4%BB%80%E4%B9%88">Claude Code 究竟向云端发送了什么？</a></li><li><a href="#%E5%BD%93%E7%94%A8%E6%88%B7%E6%B3%A8%E6%84%8F%E5%88%B0%E4%BD%A0%E7%9A%84%E8%BD%AF%E4%BB%B6%E6%97%B6-%E4%BD%A0%E5%B0%B1%E5%B7%B2%E7%BB%8F%E8%BE%93%E4%BA%86">当用户注意到你的软件时，你就已经输了</a></li><li><a href="#%E4%B8%8D%E8%A6%81%E9%99%B7%E5%85%A5%E5%8F%8D-ai-%E7%9A%84%E7%82%92%E4%BD%9C%E4%B8%AD">不要陷入反 AI 的炒作中</a></li><li><a href="#%E8%BD%AF%E7%9B%98%EF%BC%9A%E6%9C%80%E9%80%82%E5%90%88%E5%AD%A9%E5%AD%90%E7%9A%84%E7%94%B5%E8%A7%86%E9%81%A5%E6%8E%A7%E5%99%A8">软盘：最适合孩子的电视遥控器</a></li><li><a href="#kagi">Kagi</a></li><li><a href="#%E6%9C%89%E8%B6%A3%E9%A1%B9%E7%9B%AE">有趣项目</a></li></ul><h2 id="输出"><a class="markdownIt-Anchor" href="#输出"></a> 输出</h2><ul><li><a href="#%E6%8A%98%E8%85%BE%E5%8D%9A%E5%AE%A2">折腾博客</a></li><li><a href="#%E6%88%91%E5%86%99%E7%9A%84%E6%96%87%E7%AB%A0">我写的文章</a></li><li><a href="#%E4%B9%A6%E7%B1%8D">书籍</a> / <a href="#%E5%BD%B1%E8%A7%86">影视</a> / <a href="#%E9%9F%B3%E4%B9%90">音乐</a></li><li><a href="#%E6%97%A5%E8%AE%B0%E7%89%87%E6%AE%B5">真生活</a></li></ul>    </details><h2 id="商业与社会"><a class="markdownIt-Anchor" href="#商业与社会"></a> 商业与社会</h2><h2 id="心理与关系"><a class="markdownIt-Anchor" href="#心理与关系"></a> 心理与关系</h2><p><a id="如何减少尴尬"></a></p><h4 id="如何减少尴尬"><a class="markdownIt-Anchor" href="#如何减少尴尬"></a> <a href="https://www.experimental-history.com/p/how-to-be-less-awkward">《如何减少尴尬》</a></h4><p>我想，许多人或许在社交中都有尴尬的时候吧。因为社交尴尬而恐惧社交的人，又有多少呢？作者对此提供了有三个部分的治疗方案，我就简单总结一下了：</p><p>一、有些人在社交上显得笨拙，而这救不了 —— 你就是这样的人。但也没什么好怕的，你只要承认这一点就可以了。</p><p>有些人出现了问题后，会倾向于掩盖过错，但这很多时候又会把氛围搞砸。如果一开始就承认自己是个不太会社交的人，反而会起正面效果：觉得自己漏掉了什么，或者不礼貌了，那就承认；觉得自己做错了什么，那就道歉。</p><p>作者认为这和有些人有饮食忌讳是一样的。我赞同这一点。作为一个社交能力很差的人，我逐渐发现去掩盖一些过错，可能会引起更多的误会。这个时候可以将自己想象成一个笨拙但诚实的人 —— 如果我现实中遇到这样的人，我不会觉得他很奇怪，我只会去想办法帮助他。我想，这世上会这么做的人也有很多。</p><p>这一点会让我想起过去 Cate Hall 写的 <a href="/posts/31df.html#%E4%BD%A0%E6%98%AF%E5%90%A6%E9%99%B7%E5%85%A5%E4%BA%86%E7%94%B5%E5%BD%B1%E9%80%BB%E8%BE%91">一篇文章</a>，我也在月刊里写过。想到什么说什么，有时候并不是那么糟糕的事情。</p><p>二、承认自己自我意识过剩，然后想办法将注意力转向除了自己以外的东西。</p><p>好吧，我也是个自我意识过剩的人，所以我时不时有着被害妄想。太过于在意和关注自己，却不把眼光看向他人，这样的社交自然也不会进行下去了。有趣的灵魂只要认真观察就能被发现，或许你也可以借此找到有意思的人。</p><p>当然，也有不有趣、认识了也只会让自己难受的「垃圾人」。这种人该滚多远就滚多远吧！他们也不配认识你的灵魂。</p><p>三、面对社交恐惧，然后遗忘社交恐惧。</p><p>人类需要社交、渴望社交，但这种强留的需求也引起了我们对社交的恐惧。单是想想我们可能会从人际关系处得到的负面反馈，就会让我们恐惧去主动社交。</p><p>作者认为，人们的心灵是可以被愈合的，因此可以采取「消除恐惧的最好方法，就是面对恐惧」这一方案。是的，你将不得不将自己暴露在人群中、主动去社交。社交中的正面反馈，会助长我们的自信心。</p><p>不过有时候，我们能否意识到正面反馈的存在也是个问题：每次社交结束后就反思自己付出的，以及自己得到的。一定要记住，「负面反馈多」并不一定是真的，可能只是我们将其放得太大，以至于看不到其他闪光点。</p><p>知道了这些后，你会变成一个社交大师么？不，你不会，除非你付出了行动，并从中慢慢学习到了什么。</p><p>当然，尝试后依旧认为自己在社交时会觉得尴尬也是没关系的，就让它那样吧。但我们已经知道了，世界上有许多人也会和我们一样感到尴尬，那我们想办法照顾他们、让他们不会那么尴尬就好了 —— 或许这么做，对你来说会更简单些？</p><p><a id="我们是否彻底厌倦了社交媒体"></a></p><h4 id="我们是否彻底厌倦了社交媒体"><a class="markdownIt-Anchor" href="#我们是否彻底厌倦了社交媒体"></a> <a href="https://www.danielbrendel.com/blog/24-are-we-tired-of-social-media-once-and-for-all">《我们是否彻底厌倦了社交媒体？》</a></h4><p>作者 Daniel Brendel 说出了我一直在思考的问题：Fediverse 真的可以让大家连接在一起吗？</p><p>其实我也不记得是从哪里听来的。是，Fediverse 软件多数都没有算法，也没有广告，大家想要关注谁就关注谁，不用再担心企业平台为了流量而硬塞来的引战讯息。但我认为，Fediverse 解决的本质问题，只有「数字主权」，而不是「让大家连接在一起」。</p><p>这就不得不再拿出来 Ploum 的 <a href="https://ploum.net/2025-12-15-communication-entertainment.html">这篇文章</a>。重新说一下 Ploum 的观点：Fediverse 是社交网络，是娱乐平台，是媒体消费协议。Mastodon 和 Pixelfed 充其量只是没有算法、冗余功能、大公司控制的 Twitter 和 Instagram—— 它们不是可靠的通讯工具，也不适用于彼此间的连接。</p><p><a href="https://blog.cytrogen.icu/posts/c089.html#%E6%88%91%E4%BB%AC%E6%98%AF%E5%A6%82%E4%BD%95%E4%B8%BA%E4%BA%86%E5%A8%B1%E4%B9%90%E8%80%8C%E5%BC%84%E4%B8%A2%E4%BA%86%E4%BA%A4%E6%B5%81%E7%9A%84">过去我说过</a>，Mastodon 作为微博客平台，输入模式契合着人类大脑想事情的机制。不过信息接收者在 Mastodon 这样有着时间线的平台，大脑会在极短时间内进行剧烈的上下文切换 —— 这是反深度思考的，迎合的也是即时多巴胺反馈。</p><p>其实说到这个，也需要确认一下「微博客」和「博客」的区别。我认为核心标准在于文本的「上下文独立性」和「信息结构的完整度」。</p><p>「微」的文字，通常是高度依赖即时语境的。比方说突然想出来的灵感、需要立即记下来的记录、针对某件突发事件的情绪反馈，它们都是未经深度加工的文本。一旦这段文字从时间线上抽离，放到数年后的一个空白页面中，它就会因为默认读者与作者共享当前的物理时间、社交网络热点或者说特定的讨论氛围，而因为本身缺乏背景信息的铺垫，变得难以理解。</p><p>博客文章具备着上下文独立性，因为作者通常会在撰写时就预设读者什么都不知道，也是我推荐大家写博客文章时采取的视角，所以必须在文中构建完整的逻辑链条，提供必要的背景介绍，并进行结构化的论述。这样的文字内容，丢到几百年后的哪里，或许连外星人也能读明白吧。</p><p>必须客观承认的是，Fediverse 并不完全等同于 Mastodon。在这个联邦网络中，同样存在 WriteFreely 或是集成了 ActivityPub 的 WordPress 等长文本博客平台，它们完全可以承载具备上下文独立性的文章。但这并未改变整个 Fediverse 被时间线主导的底层消费逻辑。</p><p>由于 Mastodon 这类微博客平台在 Fediverse 中占据了绝对的用户主导地位，它们的时间线 UI 和 ActivityPub 的广播机制，共同构建了一个没有边界的广场。这意味着，即便你在 Fediverse 中发布了一篇深度的博客文章，当它被分发给其他实例的受众时，在绝大多数读者的屏幕上，它依然是一条混杂在各种即时情绪、新闻、日常吐槽中的碎片化动态。</p><p>在这样剧烈切换上下文的阅读环境中，深度思考变得极其困难。即便排除了商业算法的干扰，信息的呈现方式依然是信息流。人们在参与这种网络时，潜意识依然是在进行广播和自我展演，而不是在进行沉浸式的交流。这也是为什么 Ploum 认为 Mastodon 和 Twitter 没有什么区别，因为底层的产品逻辑和信息消费方式并未发生实质性的改变。</p><p>不过，信息结构的完整度，真的就是建立有效交流的绝对前提吗？其实也不全是。如果我和现实生活中的朋友聊天，哪怕我只发一句没头没尾的抱怨，对方也能瞬间明白我的意思，因为我们之间早就共享着各种生活经历和情感上下文，此时使用即时通讯软件进行碎片化的高频互动，是再正常不过的事情。</p><p>但问题在于，Fediverse 是一个由陌生人组成的公共网络。在没有任何现实关系背书的情况下，如果不提供完整的上下文，只是把未经加工的瞬间情绪抛到广场上，对方根本都不知道你在说什么，所谓的「连接」自然也就无从谈起。这也是为什么我现在使用 Mastodon 进行日常记录时，依然会添加必要的上下文，它有时候只不过是字数少一些的博客罢了。</p><p>顺着这个逻辑往下想，Brendel 提出的更深层的问题，即「人们总体上对社交感到厌倦了」，或许并不仅仅是平台机制的问题。更深层的问题在于，建立并维护人际关系，本身就是一件极度消耗精力的事情。</p><p>我仔细审视了自己想要通过 Fediverse 获得什么，结果发现，我其实并没有那么强烈地、想要在互联网上与陌生人产生深度连接的渴望。我没有交网友的习惯，我的人际关系和有效交流，几乎全部倾注在了现实生活中的人们身上。要求互联网上的陌生人与我产生深刻的共鸣，或者强求自己去维系庞大的线上关系网，既不现实，也会让人疲倦不堪。</p><p>所以，结论并不是要去彻底抛弃哪个工具，而是接受并合理分配自己的社交精力。我依然会继续使用 Mastodon 进行带有上下文的日常记录，不去强求什么互动，在那个没有算法的广场上保持一种「泛泛之交」的松弛感，其实是最好的状态。我也会继续撰写博客文章，把深度的思考沉淀下来。至于那些真正需要情感连接和即时反馈的交流，我会将它们留给电子邮件，或者是和现实朋友们所在的即时通讯软件里 —— 当然，给陌生人们的选择也有我的 Matrix 账户 <code>@cytrogen:tchncs.de</code>。不过要记住，我所在的地区的时间戳是 UTC-5。</p><h2 id="科学与自然"><a class="markdownIt-Anchor" href="#科学与自然"></a> 科学与自然</h2><p><a id="a4-纸的故事"></a></p><h4 id="a4-纸的故事"><a class="markdownIt-Anchor" href="#a4-纸的故事"></a> <a href="https://susam.net/a4-paper-stories.html">《A4 纸的故事》</a></h4><p>这是一篇很「数学」的文章。</p><p>有没有想过 A4 纸为啥叫 A4 纸么？</p><p>这个月我因为中文课教授的一句「现在的大学生都不带纸了么」，起了莫名的对抗欲，挑选了心目中最好的本子类型 —— 活页本！不过能装 A4 纸的活页本会很大，我的小书包估计装不下。我估摸着退两级下来，能装 A6 纸的活页本估计就足够了吧。不过我不知道 A6 纸多大呢，上网看到了这个 <a href="https://papersizes.io/compare">工具</a>，拿 A4 和 A6 比较了一下。</p><p>结果发现，A6 几乎就是 A4 的四分之一。</p><p>差这么多？</p><p>总之我买了装 A5 纸的活页本，大小刚刚好，很不错。</p><p>扯远了。</p><p>文章里提及了 A 系列纸张尺寸背后优雅的数学原理。首先有个数学问题需要考虑：如何让一张纸在平行于短边对折一半后，得到的新纸张与原纸张拥有完全相同的长宽比？</p><p>结果得出了 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msqrt><mn>2</mn></msqrt></mrow><annotation encoding="application/x-tex">\sqrt{2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.04em;vertical-align:-0.13278em;"></span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.90722em;"><span class="svg-align" style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord" style="padding-left:0.833em;"><span class="mord">2</span></span></span><span style="top:-2.86722em;"><span class="pstrut" style="height:3em;"></span><span class="hide-tail" style="min-width:0.853em;height:1.08em;"><svg width="400em" height="1.08em" viewBox="0 0 400000 1080" preserveAspectRatio="xMinYMin slice"><path d="M95,702c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429c69,-144,104.5,-217.7,106.5,-221l0 -0c5.3,-9.3,12,-14,20,-14H400000v40H845.2724s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47zM834 80h400000v40h-400000z"></path></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.13278em;"><span></span></span></span></span></span></span></span></span> 这个数字，也是所有 A 系列纸张的固定长宽比。</p><p>有了比例还不够，还需要一个基准尺寸。ISO 216 标准将 A0 纸的面积精确定义为 1 平方米，也就是长 1189 毫米、宽 841 毫米。这时候将 A0 纸不断对折，面积依次减半来得到 A1、A2、A3，以及我们最常用的 A4。所以 A4 纸相当于对折了 4 次的 A0 纸。</p><p>作者在文章里还提到了他是如何用一张 A4 纸测量显示器的尺寸 —— 搞数学的人的世界我不懂！</p><p><a id="真食物必胜"></a></p><h4 id="真食物必胜"><a class="markdownIt-Anchor" href="#真食物必胜"></a> <a href="https://realfood.gov/">《真食物必胜》</a></h4><p>这是美国政府的网站。</p><p>美国是世界上「最伟大」的国家，也是最有病的 —— 精神上，也有生理上的意义。美国民众有多么爱预制食物，我想都能想象出来。虽然无比便利，以及便宜，但代价是并不健康。</p><p>这个网站就是为了让美国民众们知道，吃真正的食物有多么重要。</p><p>我在美国上小学的时候，老师就没少向我们科普一餐得吃什么：蛋白质、奶制品、蔬菜、水果、谷物，也就是食物金字塔里提倡的。</p><p>虽然话是这么说的，但在学校里吃到的午饭，也不一定遵守这个规则。</p><p>说说网站本身。设计还可以，但不知道为什么访问起来卡卡的。它是由 <a href="https://ndstudio.gov/">National Design Studio</a> 设计的，而该机构是由特朗普想出来的，因为他想要让政府服务的设计变得实用且美观。</p><p>美观我认为可以，但是实用嘛…… 根据 <a href="https://www.notus.org/trump-white-house/silicon-valley-government-websites-national-design-studio">该文章</a> 所说，许多来自 National Design Studio 的网站都违反了网页无障碍标准，视障人士很难阅读这些网站。</p><p>文章也认为 National Design Studio 在开发网站时，依赖于 AI 生成内容。</p><p>Eat Real Food 网站底部也有个询问 AI 的板块，让我有点摸不着头脑。我试了下，发现会被导航到 Grok。嗯，好吧……？</p><p><a id="首次拍摄到褐鼠捕食蝙蝠的画面"></a></p><h4 id="首次拍摄到褐鼠捕食蝙蝠的画面"><a class="markdownIt-Anchor" href="#首次拍摄到褐鼠捕食蝙蝠的画面"></a> <a href="https://scienceclock.com/rats-caught-on-camera-hunting-flying-bats-for-the-first-time/">《首次拍摄到褐鼠捕食蝙蝠的画面》</a></h4><p>德国北部的研究团队首次记录到褐鼠（Rattus norvegicus）在半空中捕杀飞行中的蝙蝠。意外的点是，通常被视为食腐动物或行动迟缓猎物捕食者的褐鼠，竟展现出了极其罕见的敏捷性与主动捕猎能力。这种现象在动物行为学上，展示了 <u>行为可塑性</u>，即环境促使常见的城市啮齿动物学习并掌握了高度专业化的捕猎技巧。</p><p>不过呢，褐鼠在欧洲广泛存在且属于入侵物种，它们的这种捕猎能力给本就面临栖息地缩减和疾病威胁的欧洲蝙蝠种群施加了严重的额外压力。因此对于此类大型蝙蝠栖息地，针对性地介入并管理鼠类种群已成为一种必要的预防手段。</p><p><a id="为什么有些衣服在清洗时会缩水"></a></p><h4 id="为什么有些衣服在清洗时会缩水"><a class="markdownIt-Anchor" href="#为什么有些衣服在清洗时会缩水"></a> <a href="https://www.swinburne.edu.au/news/2025/08/why-some-clothes-shrink-in-the-wash-and-how-to-unshrink-them/">《为什么有些衣服在清洗时会缩水》</a></h4><p>纺织品科学家 Nisa Salim 博士解释了为什么衣服会缩水一事背后的微观物理与化学原理。</p><p>常见的植物性纤维（如棉和亚麻）在自然状态下呈不规则的卷曲状。在现代纺织制造过程中，这些纤维素分子链被机械拉伸、排列整齐，并通过氢键固定以形成平滑的纱线。</p><p>然而这些纤维具有天然的「记忆性」。在洗涤时，具有亲水性的纤维素会吸水膨胀，而热水的热能以及洗衣机翻滚的机械力会破坏固定纱线的氢键。这导致纤维失去原有的张力，重新放松并回缩到其天然的卷曲状态，从而在宏观层面表现为衣物缩水。</p><p>此外，针织结构较松散的面料比紧密编织的面料具有更多的形变空间，因此更容易发生缩水。</p><p>动物性纤维的缩水机制则与植物纤维完全不同。以羊毛为例，其表面覆盖着由角蛋白构成的微小重叠鳞片。在洗涤的搅动过程中，这些鳞片会受潮张开并与相邻的纤维相互交错缠结，产生被称为「毡化」的现象，致使衣物变得更加密实且体积缩小。</p><p>相比之下，由石油基聚合物制成的合成纤维（如涤纶或尼龙）不易缩水。它们内部含有高度有序的结晶区域，这些区域充当了坚固的微观骨架，能够有效防止纤维在洗涤过程中起皱或变形。</p><p>为了尽量减少衣物缩水，日常洗涤中应优先使用冷水、低转速以及轻柔洗涤模式，以最大程度地降低机械力与热能对纤维内部结构的破坏。</p><p>如果衣物已经发生缩水，可以通过特定的表面化学原理进行部分补救。具体操作是：</p><ol><li>将缩水的衣物轻轻浸泡在温水中；</li><li>按每升水一汤匙的比例加入护发素或婴儿洗发水。这类洗护产品中含有的阳离子表面活性剂能够暂时润滑纺织纤维，使其恢复一定的柔韧性；</li><li>浸泡后，在保持面料湿润的状态下轻轻将其拉伸回原始轮廓，并采用平铺或施加轻微张力的方式晾干。</li></ol><p>虽然这一过程无法完全逆转严重的结构性缩水，但能够有效恢复面料的部分物理尺寸。</p><h2 id="技术与创造"><a class="markdownIt-Anchor" href="#技术与创造"></a> 技术与创造</h2><p><a id="richard-stallman-的个人网站"></a></p><h4 id="richard-stallman-的个人网站"><a class="markdownIt-Anchor" href="#richard-stallman-的个人网站"></a> <a href="https://stallman.org/">《Richard Stallman 的个人网站》</a></h4><p>Richard Stallman 是一位自由软件活动家，也是 GCC、GNU、GNU Emacs —— AKA 我现在在用的软件 —— 之父。</p><p>何为「自由软件」呢？</p><blockquote><p>自由软件（英语：free software）是允许用户自由地使用、复制、研究、修改和分发的软件。</p></blockquote><p>不过这里的「自由」专指用户的控制权与使用自由（Libre），而非价格上的免费（Gratis）。</p><p>自由软件并不等同于开源软件。首先，自由软件基金会严格定义了运行程序、研究并修改程序源代码、重新分发副本以及向公众发布改进版本的绝对权利。在自由软件的语境下，任何剥夺用户这些权利的专有软件都被视为不道德的。</p><p>为了在法律层面上捍卫这种绝对的自由，该运动催生了以 GNU 通用公共许可证（GPL）为代表的 <em> Copyleft</em>（著佐权）协议。这类协议具有强烈的传染性，强制要求任何基于自由软件修改或衍生的作品，也必须以同等的自由条款向下游发布，从而在机制上防止公共代码被私有化封装。</p><p>而开源软件这一概念由 Eric S. Raymond 等人创立的开源倡议组织推动。这一概念的提出，直接动机是为了摆脱自由软件运动中强烈的意识形态色彩和道德约束，从而让传统的商业公司更容易接受开放源代码的模式。</p><p>开源软件将焦点从道德层面的「用户权利」转移到了实用层面的「卓越工程方法论」上。开源阵营主张，向公众开放源代码是一种极其高效的开发模式，通过广泛的同行评审和分布式协作，能够产生质量更高、安全性更好且迭代更快的软件产品。这种实用主义的导向促使开源社区更倾向于拥抱商业力量，并广泛推崇如 MIT、Apache 等宽松型许可协议。这类协议允许企业或个人修改代码后将其闭源并作为商业专有软件分发，在最大化代码被工业界采用率的同时，放弃了对下游衍生品必须保持开放的强制约束。</p><p>所以，一个开源软件并不意味着它一定是自由软件。</p><p>除了想要分享自由软件的理念外，Stallman 的个人网站上有这些我认为有趣的点：</p><p>一、网站设计十分简约，以至于一些人可能会说很简陋的程度。个人不太喜欢阅读这类网站上的文字，总觉得很难受、哪里都是字……</p><p>二、<em>What's bad about:</em> 专栏，也是我想要分享的重头戏。Stallman 列举了数个公司（包括需要付费才能使用的厕所），并数出它们的罪孽。</p><p>比方说 Wendy's，罪状在这里：<a href="https://talkpoverty.org/2016/08/08/dear-wendys-im-boycotting-im-not-one-worried/">https://talkpoverty.org/2016/08/08/dear-wendys-im-boycotting-im-not-one-worried/</a></p><p>简单来说，Wendy's 拒绝加入「公平食品计划」（Fair Food Program）。该计划要求企业为番茄采购支付极少量的额外费用以改善底层农工的待遇，并严格限制企业只能向遵守劳工权利准则的农场进货。在主要快餐竞争对手及大型零售商均已加入该计划的背景下，Wendy's 是唯一一家拒绝签署的大型企业。</p><p>此外，Wendy's 选择停止向佛罗里达州参与该计划的合规农场采购番茄，转而向墨西哥的供应商进货，而这些新的供应商曾被相关报道指控存在严重的劳工剥削及童工问题。</p><p>又比方说，LinkedIn 的罪恶在于：</p><ol><li>强制用户运行非自由的 JavaScript 代码才能访问网站，同时采取极端手段，试图将抓取其公开网页数据的行为定罪并寻求将抓取者投入监狱；</li><li>存在大量冒充知名企业高管或网络安全负责人的虚假账号，这类账号可能会误导用户并传播恶意的安全建议，而平台自身也被指控向用户发送大量垃圾邮件；</li><li>在注册流程中设置阻碍，使得用户几乎必须交出个人的电子邮件通讯录才能完成注册；</li><li>声称拥有用户个人资料的所有权，对用户可以展示的信息施加符合平台利益的限制，并强制用户接受存在风险的赔偿条款；</li><li>当付费用户因平台削减功能而决定注销时，系统拒绝立即删除其账号；</li><li>存在配合特定国家机器进行政治审查的行为，主动过滤和审查当地用户的个人资料。</li></ol><p>许多平台都是因为类似的情况而被 Stallman 举为例子，我就不一一赘述了，最后只说一下「付费厕所」为什么不好：</p><blockquote><p>请不要付费使用收费厕所。</p><p>收费厕所很恶劣，应该是非法的。如果我们接受这种做法，我们这些不穷的人能付得起钱；但穷人付不起。在人们需要厕所时拒绝让他们使用是恶劣且有损尊严的。</p><p>我的结论是，为了消除收费厕所，我们至少能做的是避免给它们钱。我宁愿费尽周折去找其他厕所，也不愿付钱给它们。</p><p>请加入我，坚决抵制收费厕所。</p></blockquote><p>来自于 <a href="https://stallman.org/pay-toilets.html">https://stallman.org/pay-toilets.html</a>。</p><p><a id="读点好的吧"></a></p><h4 id="读点好的吧"><a class="markdownIt-Anchor" href="#读点好的吧"></a> <a href="https://readsomethingwonderful.com">《读点好的吧》</a></h4><p>我这个翻译很俏皮，沿用了网络用句「吃点好的」。</p><p>这是一个分享互联网上的写作内容的网站。和许多平台不同，它不注重于推送给用户最近的文章，而是只专注于那些「永恒的文章」。你可以在这里找到上个世纪的文章，也可以找到数年前的文章 —— 重点是它们的内容经得起时间沉淀。</p><p>这是一个有意思的项目！我一直在寻找一个不是 Hacker News 的信息索引平台，来增加自己的信息来源。</p><p>不过缺点也很明显，这些是我的看法：</p><ol><li>没有 RSS 订阅功能。这个网站看上去更像是给 Matter 这个 App 打的广告？但是我不想要下载一个 App 呀；</li><li>收集的链接是以什么标准来收集的呢？又是以什么顺序排序的呢？这些都没有被解释。</li></ol><p><a id="用最少的音节念数字"></a></p><h4 id="用最少的音节念数字"><a class="markdownIt-Anchor" href="#用最少的音节念数字"></a> <a href="https://thegraycuber.github.io/fast_numbers">《用最少的音节念数字》</a></h4><p>欢迎来到语言学大讲堂！在这里，你可以借此学习到不同语言念数字的底层逻辑…… 不，其实都是奇奇怪怪的数字公式。</p><p>我想到这个是因为法国法语念数字时会混入二十进制这样的东西，例如 99 念 <em> Quatre-vingt-dix-neuf</em>，逻辑是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>4</mn><mo>×</mo><mn>20</mn><mo>+</mo><mn>10</mn><mo>+</mo><mn>9</mn></mrow><annotation encoding="application/x-tex">4 \times 20 + 10 + 9</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">4</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">2</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">1</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">9</span></span></span></span>。</p><p>多数人类语言念数字的本质都是在念一个以 10 为底的多项式。假设数字为 <em> N</em>，我们在语言里把它表达为：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>N</mi><mo>=</mo><msub><mi>a</mi><mi>n</mi></msub><mo>×</mo><mn>1</mn><msup><mn>0</mn><mi>n</mi></msup><mo>+</mo><msub><mi>a</mi><mo stretchy="false">(</mo></msub><mi>n</mi><mo>−</mo><mn>1</mn><mo stretchy="false">)</mo><mo>×</mo><mn>1</mn><msup><mn>0</mn><mo stretchy="false">(</mo></msup><mi>n</mi><mo>−</mo><mn>1</mn><mo stretchy="false">)</mo><mo>+</mo><mo>⋯</mo><mo>+</mo><msub><mi>a</mi><mn>1</mn></msub><mo>×</mo><mn>1</mn><msup><mn>0</mn><mn>1</mn></msup><mo>+</mo><msub><mi>a</mi><mn>0</mn></msub><mo>×</mo><mn>1</mn><msup><mn>0</mn><mn>0</mn></msup></mrow><annotation encoding="application/x-tex">N = a_n \times 10^n + a_(n-1) \times 10^(n-1) + \cdots + a_1 \times 10^1 + a_0 \times 10^0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.73333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.7977219999999999em;vertical-align:-0.08333em;"></span><span class="mord">1</span><span class="mord"><span class="mord">0</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.9385299999999999em;vertical-align:-0.3551999999999999em;"></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.34480000000000005em;"><span style="top:-2.5198em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mopen mtight">(</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.3551999999999999em;"><span></span></span></span></span></span></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.0213299999999998em;vertical-align:-0.08333em;"></span><span class="mord">1</span><span class="mord"><span class="mord">0</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.938em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mopen mtight">(</span></span></span></span></span></span></span></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.66666em;vertical-align:-0.08333em;"></span><span class="minner">⋯</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.73333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.9474379999999999em;vertical-align:-0.08333em;"></span><span class="mord">1</span><span class="mord"><span class="mord">0</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.73333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.8641079999999999em;vertical-align:0em;"></span><span class="mord">1</span><span class="mord"><span class="mord">0</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span></span></span></span></span></span></span></span></span></p><p>例如中文里的 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>3</mn><mo>×</mo><mn>100</mn><mo>+</mo><mn>3</mn><mo>×</mo><mn>10</mn><mo>+</mo><mn>3</mn></mrow><annotation encoding="application/x-tex">3 \times 100 + 3 \times 10 + 3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">3</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">1</span><span class="mord">0</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">3</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">1</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span></span></span></span>，英文里的 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>3</mn><mo>×</mo><mn>100</mn><mo>+</mo><mn>30</mn><mo>+</mo><mn>3</mn></mrow><annotation encoding="application/x-tex">3 \times 100 + 30 + 3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">3</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">1</span><span class="mord">0</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">3</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span></span></span></span>。</p><p>一些语言里倒是还会用到减法逻辑，相关少见，比如说拉丁语中 19 是 <em> undeviginti</em> 即 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>20</mn><mo>−</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">20 - 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">2</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span>。</p><p>不过呢这个项目是完全以英文为基底创作的，和我讲的他国语言没有关系，只是我自己在强行赋予关联性。</p><p><a id="小型网络很美"></a></p><h4 id="小型网络很美"><a class="markdownIt-Anchor" href="#小型网络很美"></a> <a href="https://benhoyt.com/writings/the-small-web-is-beautiful/">《小型网络很美》</a></h4><p>什么是「小型网络」？解释可以有很多，例如独立的个人网站、复古的网络、对科技巨头反击的网站、订阅者数很少的 YouTube 频道……</p><p>现在的电子设备，硬件方面都要比过去的高上许多倍，比方说内存，现在 16GB 内存的电脑到处都是，但在过去可能 1GB 的内存就已经足够奢侈。那么为什么要这么专注于「小」？作者认为重要的理由是：</p><ul><li>运行速度更快</li><li>内容更少，更容易修复</li><li>功耗更少，对环境保护很有效</li><li>简约的美学</li></ul><p>不过小型网络的美，并不只是规模小，还在于「努力想要变小的理念」。正因为关心网络的用户，所以站主们想尽办法去让页面下载速度更快、更易于阅读，且为了用户的隐私考虑，不使用各种各样的追踪器。</p><p>文章中提到了一些小型网络的俱乐部，如 <a href="https://1mb.club/">1MB Club</a>。我查了一下自己的博客网站，发现光是字体文件就远超 30 多个 MB 了。好吧，谁叫我导入了六个字体文件呢。</p><p>在作者提到的喜欢的小型网络里，他提到了 Sourcehut。这是一个我最近在学习使用的代码托管平台。除了它相当独特的协作方式，即使用邮件列表而非 Pull Requests—— 有人知道这其实并不是代码协作的唯一方式么？—— 它的页面很简单小巧，甚至不需要 JavaScript 就能让所有功能正常运行。</p><p><a id="为什么大多数网站实际上不需要-cookie-同意横幅"></a></p><h4 id="为什么大多数网站实际上不需要-cookie-同意横幅"><a class="markdownIt-Anchor" href="#为什么大多数网站实际上不需要-cookie-同意横幅"></a> <a href="https://block81.com/blog/why-most-websites-dont-actually-need-cookie-consent-banners">《为什么大多数网站实际上不需要 Cookie 同意横幅》</a></h4><p>上一些网站时我发现，Cookie 横幅到处都是！种种原因，让我只能一个个拒绝掉。</p><p>文章作者认为，大多数小企业网站根本不需要 Cookie 同意横幅。</p><p>首先 Cookie 分为必要性 Cookie 以及追踪性 Cookie。前者就用户的角度去考虑的话，是没什么大问题的，因为它们的作用就是保持登录状态、维护会话等。后者则会建立用户的画像，用于投广告或者为第三方收集数据。</p><p>不过小企业之所以是小企业，是因为它们根本不需要追踪用户，也多数不需要与第三方共享用户的数据。那这种情况下，网站便不需要 Cookie 横幅。</p><p>做项目的时候，项目管理就问我能不能写个 Cookie 横幅，或者用户点击后会弹出来的折扣、newsletter 订阅讯息。我说我不要，这东西有个毛必要嘛。</p><p>因为看多了 Cookie 横幅，就会认为网站必须要有 Cookie 横幅 —— 这种想法是不行的！请立即中止它！就算你的网站里有用到 Cookie，也不一定需要添加 Cookie 横幅，因为 GDPR 和类似的隐私法里都表示，运行绝对必要的 Cookie、仅用于自身分析的第一方 Cookie，以及用户关闭了浏览器就会失效的会话 Cookie 不需要获得用户的同意。</p><p>但是呢，使用 Google Analytics 这种营销工具就需要获得同意了。</p><p>美国没有联邦层面的 Cookie 同意法 —— 唉，美国 —— 不过有一些州有影响 Cookie 使用的隐私法。大多数美国企业可以通过专注于清晰的信息披露和尊重退出请求，从而完全避免使用 Cookie 同意横幅。</p><p><a id="写给恐慌者的-git-rebase-指南"></a></p><h4 id="写给恐慌者的-git-rebase-指南"><a class="markdownIt-Anchor" href="#写给恐慌者的-git-rebase-指南"></a> <a href="https://www.brethorsting.com/blog/2026/01/git-rebase-for-the-terrified/">《写给恐慌者的 Git rebase 指南》</a></h4><p>文章本身写得就较简洁了，再总结也没有太大意义。如果你害怕使用 <code>git rebase</code> 命令的话，可以看看。</p><p><a id="org-mode-语法是用于文本的最合理标记语言之一"></a></p><h4 id="org-mode-语法是用于文本的最合理标记语言之一"><a class="markdownIt-Anchor" href="#org-mode-语法是用于文本的最合理标记语言之一"></a> <a href="https://karl-voit.at/2017/09/23/orgmode-as-markup-only/">《Org Mode 语法是用于文本的最合理标记语言之一》</a></h4><p>作者认为 Org Mode 语法是他最喜欢的语法，借此，他想要解释一下为什么。虽然说到 Org Mode 就一定会想到 Emacs，不过作者特意表示，这和 Emacs 无关，他就是喜欢 Org Mode 的语法。</p><p>首先，Org Mode 语法直观，很好学，并且还提供了标记。</p><p>其次，Org Mode 语法是标准化的。这里需要说一下更常见的 Markdown：<a href="/posts/b211.html#markdown-%E9%99%90%E5%88%B6%E4%BA%86%E4%BD%A0">过去</a> 我讲过 Markdown 的问题，其中一个便是无统一标准。但 Org Mode 就没有这个问题。</p><p>作者在文章中使用了许多例子来解释为什么 Org Mode 语法更好，感兴趣的话可以看看。</p><p>最后要说的是，GitHub 或者 GitLab 的 README 其实并不需要用 Markdown，用 Org Mode 照样可以渲染出来。</p><p>以及，虽然说了不需要 Emacs 也可以写 Org Mode，但还是希望大家尝试一下这个文本编辑器 ——！</p><p><a id="claude-code-究竟向云端发送了什么"></a></p><h4 id="claude-code-究竟向云端发送了什么"><a class="markdownIt-Anchor" href="#claude-code-究竟向云端发送了什么"></a> <a href="https://rastrigin.systems/blog/claude-code-part-1-requests/">《Claude Code 究竟向云端发送了什么？》</a></h4><p>作者搭建了个代理，想要知道 Claude Code 会向云端发送什么内容，结果是：</p><ul><li>完整的上下文历史。因为 Claude Code 采用的是无状态架构，所以每一次请求都必须带上 <strong>从会话开始到当前的所有对话记录</strong>，这也包括它用工具读取到的本地代码文件。</li><li>Claude Code 客户端会在会话开始时，自动收集本地环境快照并注入到提示词中发送，这包括：<ul><li>系统信息，例如操作系统版本、平台</li><li>路径信息</li><li>Git 仓库状态，例如当前分支、主分支名称、<code>git status</code> 的结果、以及最近的 commit 历史和提交信息</li></ul></li><li>自定义指令文件，也就是 <code>CLAUDE.md</code>。</li><li>在用户说任何话之前，客户端会预先塞入 Claude Code 自己的行为规范手册：<ul><li>所有它可以调用的工具的详细定义</li><li>安全与合规策略</li><li>语气与风格指导，这儿有个好笑的点，那就是 Claude Code 被特意要求不许说 <em> You're absolutely right</em></li><li>任务执行逻辑，例如强制要求频繁使用 Todo 列表规划任务、严禁过度设计等</li></ul></li></ul><p><a id="当用户注意到你的软件时-你就已经输了"></a></p><h4 id="当用户注意到你的软件时你就已经输了"><a class="markdownIt-Anchor" href="#当用户注意到你的软件时你就已经输了"></a> <a href="https://pivot-to-ai.com/2026/01/10/if-users-notice-your-software-youre-already-a-loser/">《当用户注意到你的软件时，你就已经输了》</a></h4><p>文章的核心逻辑建立在一个极度务实的前提之上：<strong>计算机和软件仅仅是达成目的的工具，它们本身绝非目的。</strong></p><p>理想状态下，操作系统和底层工具应当像空气一样，用户透过它们直接沉浸于自己的任务中，而感受不到工具本身的存在。</p><p>如果你在工作时突然被迫停下来处理系统弹出的各个对话框，亦或者说按下按键呼出的却不是你认为它会呼出的功能，这就意味着工具打断了你的工作流。此时，你被迫「注意」到了这个软件。</p><p>这种现象被作者称为 <em> NOTICE ME</em> 式衰退。它通常源于商业压力，或是项目内部的营销人员、高层管理者试图为自己的履历增添亮点，而非出于用户的真实痛点。当软件为了刷存在感而不断添加花哨但缺乏实际用途的功能时，它就变成了一个干扰源。</p><p>Firefox 和 Chrome 是作者提出了两个例子。起初，它们凭借「打开即是互联网」的极致透明性赢得了市场。然而随着组织架构的膨胀，它们也开始强行添加无关功能的老路 —— 为什么 Firefox 近些年老是想成为 AI 浏览器。</p><p>说到生成式 AI 按钮，我发现它几乎是无处不在，讨厌死了！</p><p><a id="不要陷入反-ai-的炒作中"></a></p><h4 id="不要陷入反-ai-的炒作中"><a class="markdownIt-Anchor" href="#不要陷入反-ai-的炒作中"></a> <a href="https://antirez.com/news/158">《不要陷入反 AI 的炒作中》</a></h4><p>除了文章本身，我也会说说它多达 79 条的评论里，大家的观点。所以长文短说直接进入正文。</p><p>首先是作者 antirez（Redis 的创始人 Salvatore Sanfilippo）的观点：</p><p>一、编程已经发生了不可逆转的改变，因为 AI 能够几乎独立完成大型子任务或中型任务，尤其是对于系统编程这类相对孤立、易于用文本描述的领域，所以手动写代码已经不再是理智的选择，除非是为了娱乐。</p><p>二、程序员的核心价值观转变为「知道要做什么」。写代码本身不再是瓶颈，更重要的是能够在大脑中构建问题的模型，并清晰地将目标传达给 AI。</p><p>三、AI 吸收了过去开源的代码并反哺给全人类，这是作者认为的「知识与代码民主化」的延续。AI 将极大地提升小型团队的竞争力，其意义堪比 90 年代的开源运动。</p><p>四、尽管目前开源模型（特别是中国的模型）仍在缩小与顶尖闭源模型的差距，但作者仍然非常担忧算力和模型的过度集中化。同时，他担心大批程序员乃至其他行业从业者会因此失业。</p><p>五、在宏观层面，作者呼吁通过政治途径（如投票给支持通用基本收入 / 失业保障的政府）来解决 AI 带来的社会震荡。在微观层面，他强烈建议程序员不要抗拒，而是必须去拥抱和测试这些工具，将 AI 作为自身能力的放大器，重新找回「构建」软件的乐趣。</p><p>说完作者的观点，现在我会跟随评论区的意见，再说说我的看法。</p><p>首先是技术层面上的。如果依赖 AI 生成底层代码，会让程序员失去通过挫折而建立起的问题的深刻直觉，例如内存安全。未来将充满只会设计高层架构、却无法修复底层错误的开发者。</p><p>再就是 AI 生成代码时，技术债要比真人程序员积累得更快。一旦在未来，最初的提示词丢失，而 AI 的逻辑暴露出缺陷时，没有亲自写过这些代码的人将极其难以维护。</p><p>且 AI 目前只擅长生成单一语言的短小代码。对于由数百人编写、跨越数十个微服务的复杂系统，AI 写的东西还有没有那么好，就是个问题了。</p><p>和写作一样，写代码也是思考的过程。将代码生成完全交给 AI，等同于放弃思考 —— 这么说也是因为，AI，或者说生成式大语言模型的本质是基于人类已有知识共识的概率预测。如果全行业都依赖 AI，软件开发将陷入平庸的「足够好」状态，因为真正的突破往往源于人类偏离常理的尝试。</p><p>说到「已有知识共识」，必须想一想科技巨头们是如何无视版权协议，将其压缩后反卖给开发者的了。这个月 Anthropic 控诉部分模型盗窃、蒸馏模型 —— 天啊，它们怎么敢偷走 Anthropic 从其他地方偷来的东西！</p><p>作者提出的「民主化」在我看来有些可笑。前沿 AI 要花费的资源并不少，我认为这是大家有目共睹的：环境破坏也好，算力需要花费的美元也好，宁愿不道德地窃取大量数据也好，这一切都是有代价的。而 AI 能回应的，也只有资本对廉价劳动力的渴望。</p><p>关于失业问题，评论区有着两个互相矛盾的观点：</p><ol><li>大量工作岗位会消失，穷人仅存的劳动力价值也会被剥夺；</li><li>AI 会消灭那些人们本来就讨厌的「垃圾工作」和「工资奴隶」。并且软件开发成本的暴跌会释放出过去因成本而被搁置的巨大软件需求，从长远来看，这会创造更多的新行业和工作岗位。</li></ol><p>我认为工作岗位，就目前来看一定是越多越好。就算是「垃圾工作」，对于穷人而言也是救命稻草。至于到底有没有新行业和工作岗位因软件需求而诞生，我想恐怕是没有的，如果非要把 AI 垃圾代码清洁工也算在里面的话，还有就是围绕着 AI 转的各种 AI 公司 —— 其实我也做过，结果一言难尽。只能说简单的软件需求会因为一般人也能使用 AI 而做好，而复杂的软件需求依然会交给原本就在做软件开发的人。整体来说，工作依然在变少。</p><p>我需要批评一下 <u>技术乌托邦主义</u>，即认为只要科学和技术进步，就能带来乌托邦的效果。这是理想的，但太理想了，因为它往往只关注了作为结尾的「技术进步」，而非过程中为了让技术进步而牺牲掉的东西。就现在来说，这个代价就是为了维护 AI 数据中心而付出的各个自然资源。况且，技术乌托邦主义并没有证据支持。拿过去的原始社会和现在的生活对比，人吃人的情况依然存在着，而我认为在大多数人的劳动力价值都被剥夺的未来，这个问题只会更严重。</p><p>也有人认为，AI 只是编程历史上不断追求「抽象」的延续，即从机器码到 FORTRAN、C、Java、Python、自然语言提示词这样的路线。</p><p>不过我仍然认为，想要学习软件开发的人，请从最基础的开始学习。是的，从机器码开始学习吧 —— 好吧，也不需要，但也至少从 C 开始学习，会对未来的学习很有帮助的。只有从底层建立起思维模型，你才有能力去评判 AI 生成的代码是否符合标准不是么？否则就只是在和一般人一样，Vibe Code 难以维护的垃圾代码。</p><p><a id="软盘：最适合孩子的电视遥控器"></a></p><h4 id="软盘最适合孩子的电视遥控器"><a class="markdownIt-Anchor" href="#软盘最适合孩子的电视遥控器"></a> <a href="https://blog.smartere.dk/2026/01/floppy-disks-the-best-tv-remote-for-kids/">《软盘：最适合孩子的电视遥控器》</a></h4><p>作者认为现代电视的遥控器过于复杂，不适合给自己 3 岁的孩子使用。为了让孩子可以触摸和感受到「更换媒体内容」，他决定完成一个硬核 DIY 项目：将一个真实的软盘驱动器改造成控制 Chromecast 播放电视节目的便携式物理遥控器。</p><p>如果你好奇他是怎么做到的话，那就阅读原文吧！我想要聊的是一个评论：</p><blockquote><p>为了推迟和避免与儿子的负面和正面互动，你费了这么大劲儿。当你面对面交流时，你可以教他耐心、顺从和鼓励等品质；你可以经常向他展示你喜欢他的陪伴，他是一个令人喜爱、值得你花费时间和精力的人。科技不应该取代育儿，朋友。</p></blockquote><p>在我看来，这是很奇怪的评论：难道任何通过技术手段进行的育儿辅助，都等同于逃避父母责任吗？难道博主做了这样的东西，他平日就一定没有和孩子交流吗？这在逻辑上，和认为养宠物的人一定是不管父母的白眼狼是一样的。</p><p>更值得注意的是他使用的词汇 —— <em>patience and obedience</em>（耐心与服从）。这可以侧面推断出一个高度传统甚至偏向威权控制的育儿观，即认为父母必须时刻在场，且核心目的是让孩子听话。</p><p>评论者完全误解了作者的初衷，将一个为了赋予孩子有限自主权而精心设计的物理交互装置，看作了用来打发孩子的电子保姆 —— 尽管作者已经在文章里说到，孩子在初次使用时就从中获取了乐趣，毕竟是还在靠触觉认识世界的 3 岁孩子。</p><p><a id="kagi"></a></p><h4 id="kagi"><a class="markdownIt-Anchor" href="#kagi"></a> Kagi</h4><p>Spike 推荐给了我一个搜索引擎。最初我以为 Kagi Search 只是一个无广告的搜索引擎，但在使用了一周后我发现，它的功能远不只是这些。</p><p>Spike 也写了一篇博文来介绍 Kagi Search：<a href="https://taxodium.ink/maybe-you-want-to-try-kagi.html">《也许你想试试 Kagi？》</a>。</p><p>首先要说明的是，Kagi Search 是付费的，并不是免费的搜索引擎服务！但是它提供的功能，我想或许会让你觉得物超所值。</p><p>过去我暗示过，互联网由广告技术驱动，<a href="https://cytrogen.icu/posts/31df#%E7%A7%91%E6%8A%80%E5%85%AC%E5%8F%B8%E6%AD%A3%E5%9C%A8%E8%A3%81%E5%91%98%E4%BB%A5%E8%B5%84%E5%8A%A9-ai">就连 AI 技术也靠此盈利</a>。免费的搜索引擎服务能盈利，靠的便是无尽的广告 —— 要知道最初让谷歌公司赚钱的业务，也是广告业务。</p><p>据 <a href="https://dkb.io/post/DEPR_kagi-interview">采访</a> 所说，Kagi 的创始人 Vladimir Prelovac 发现，学校里都会提供给孩子们 Chromebook 以学习（除了 Chromebook，美国学校另一个会提供的是 ThinkPad）。谷歌的服务使用起来确实很方便，个人感觉比微软的要好使用些，尤其是谷歌课堂这些产品。不过，Prelovac 不喜欢孩子们从小接触到的技术 —— 由广告支持的技术。这些技术会在孩子们还小时就影响到他们，塑造他们的思想和世界观。</p><p>许多付费订阅的服务，如 YouTube Premium，都是免除广告的。既然这样，为什么不能有一个付费订阅的搜索引擎，还没有广告呢？于是 Kagi Search 诞生了。</p><p>在我看来，Kagi Search 现在的成功很大得利于现在人们渐渐看重数字安全和隐私。用这个角度去想，未来或许会出现愈来愈多类似的产品，来替代现在邪恶的「免费」服务。</p><p>说回 Kagi Search，现在已知的搜索结果排名算法有两个：一、用户自行决定；二、Kagi Search 自己会降级那些广告和追踪器过多的网站，并推广没有或者很少有广告和追踪器的网站。</p><p>其中，用户自行决定网站排名是很不错的设计。假设你不喜欢某某网站，你可以选择减少它的结果，或者直接封锁它；反之，你可以增多喜欢的网站的结果，或者直接将其置顶。如果看到了 AI 生成的垃圾结果，你也可以标记它，让 Kagi Search 知道哪些网站通过 AI 生成的内容来产生流量；同理，看到非 AI 内容被其他用户标记为 AI 垃圾结果，你也可以报告它为非 AI 内容。</p><p>需要解释的是，Kagi 并不完全反对 AI 内容，详情见 <a href="https://help.kagi.com/kagi/why-kagi/ai-philosophy.html">Kagi 的 AI 集成理念</a>。</p><p>讲完 Kagi 的理念，来说一些我觉得很棒的功能。</p><p>一、优化搜索。</p><p>Lens 功能可以让用户在搜索时定制搜索，例如只在论坛或者 Fedi 论坛内、官方编程语言网站内搜索。详情见 <a href="https://help.kagi.com/kagi/features/lenses.html">Lenses</a>。</p><p>同样能够优化搜索结果的功能，是 Kagi Search 的搜索运算符。详情见 <a href="https://help.kagi.com/kagi/features/search-operators.html#search-operators-1">Search Operators</a>。觉得学习起来麻烦的话，也可以使用高级搜索，相当于搜索运算符的 GUI。</p><p>二、Kagi Small Web。</p><p>眼尖的朋友们或许发现了，我一会儿说 Kagi，一会儿说 Kagi Search 的。这是因为，Kagi 在本文内指的是该公司，而 Kagi Search 是其名下的搜索引擎服务名称。如果我只是想说搜索引擎的话，可以直接使用 Kagi。不过我想讲的是 Kagi 的产品，不单单是搜索引擎一个。</p><p>Kagi Small Web 就是 Kagi 的另一个产品。</p><p>在 Kagi Small Web 的 <a href="https://blog.kagi.com/small-web">这篇博文</a> 中， <em>small web</em> 一词指的是非商业化的个人网络。这些个人网络的一大问题便是聚合、不容易找到。Kagi Small Web 会从博客列表内收集发布的新内容，然后呈现给用户，例如通过刚才提到的 Kagi Lens。</p><p>该产品有一个自己的网站，使用起来有点像「开往」这种项目。它还有一个自己的 RSS 信息源，不过我不建议直接使用。最好是使用它的网站，找到自己喜欢的个人网络，自行添加进自己的 RSS 订阅源。毕竟 Kagi Small Web 收集的博客网站，依然是该团队按照自己的想法挑选的，并不一定适用于所有人。</p><p>个人网络一直因为 SEO 问题而不容易被用户查到。现在使用结合了 Kagi Small Web 的 Kagi Search，我们能够看到更多来自无数个个体所写的博文，而不是 SEO 排名高的营销垃圾。</p><p>不只是博客网站，Kagi Small Web 也会收集 YouTube 视频。按照它所说的，收集到的 YouTube 频道都是订阅者小于 40 万的。我对视频相关的小网络没有太多思考，所以也不评价了。</p><p>三、AI 相关。</p><p>这并不是我会用的功能，但觉得或许有人需要，所以讲一下吧。</p><p>其实 Kagi 在 2018 年就开始发布关于 AI 的产品，倒不如说它其实就是搞 AI 开始的。先前说过，Kagi 有着自己的 AI 理念，其中提到「AI 应被用来增强搜索体验，而不是创造它」。</p><p>这些是 Kagi 的 AI 产品：</p><ul><li>Kagi Assistant：和不同的大语言模型对话，和 Perplexity 很相似的样子？说到 Perplexity，虽然在 <a href="https://cytrogen.icu/posts/ea48#perplexity-%E4%BC%9A%E5%91%98%E4%BD%93%E9%AA%8C">十月份的月刊</a> 内提及了它，但其实很快我就没有继续再使用了，现在会员貌似已经失效。这蛮奇怪的倒是，因为它最初给的是年费会员，结果 2025 年一结束就没了。</li><li>Kagi Summarizer：对页面进行总结。类似的功能还有 Kagi Search 里的 Quick Answer；</li><li>Kagi Translate：基于生成式大语言模型的翻译服务。如果是像 DeepL 那样，并不是使用生成式大语言模型的技术就好了。</li></ul><p>四、其他。</p><p>关于 Kagi Search 的其他使用技巧，可以阅读这些博文：</p><ul><li><a href="https://anotherdayu.com/2024/5834/">《Kagi 使用技巧》</a></li></ul><p>虽然也有一些文章想要分享出来，来让大家看看其他人对 Kagi 的看法。最终思来想去，还是让好奇的你们自行搜索吧。</p><p>颇为有意思的是，Kagi 有个 Kagi Hub，感觉像是 WeWork 这样的共享办公室，不过 Kagi 会员们进去免费。除了会议室等共享办公室都有的配置外，Kagi Hub 还有厨房。但是它在欧洲的一个国家，我是没法造访啦。</p><p>写完这个条目的一周后，<a href="https://ghost.feddit.social/">Jay</a> 分享了 Kagi 网站上的一个页面给我：<a href="https://kagi.com/specials">https://kagi.com/specials</a>。</p><p>简单来说，这是 Kagi 分享的一些公司的产品，且都是与 Kagi 价值观相同的公司，致力于打造一个更健康、更道德的网络环境。如果是 Kagi 用户的话，订阅他们的服务还会有优惠。</p><p>有趣的是，Kagi 表示这没有任何金钱交易。与这些公司合作，是因为 Kagi 相信他们的事业，认同他们的价值观，并相信各自的社群会自然而然地欣赏彼此所提供的产品。</p><p>看到这些文字，真是要感动哭了。</p><p>不过我也发现，Kagi Blog 貌似是用 Bear Blog 做的？</p><p><a id="有趣项目"></a></p><h4 id="有趣项目"><a class="markdownIt-Anchor" href="#有趣项目"></a> 有趣项目</h4><ul><li><a href="https://wheredoescloudflarethinkiam.com/">Cloudflare 以为我在哪儿？</a>：通过 Cloudflare 的 IP geolocation 功能，就可以通过地图看到 Cloudflare 认为的我们在什么位置。我尝试了一下，发现它以为我住在一个很是繁华的地段 —— 对不起我没有那么富足。</li></ul><hr><h2 id="折腾博客"><a class="markdownIt-Anchor" href="#折腾博客"></a> 折腾博客</h2><p><a id="自托管"></a></p><h4 id="自托管"><a class="markdownIt-Anchor" href="#自托管"></a> 自托管</h4><p>是的，现在这个博客网站是自托管的了！</p><p>过去该网站部署在 Netlify 上。这个月我因为一些事情，购买了 IONOS 的 VPS（三年的使用权）。虽然之前也有写 <a href="/posts/2590.html">数字主权和 VPS 的文章</a> 啦…… 但是没有办法，无论是考虑钱包还是访问性，身处美国的 VPS 在这个时候都要更适合我。</p><p>除了博客外，我还托管了其他服务，详情见 <a href="/hosted">这里</a>。</p><p>因为是静态博客，要托管的内容也不过是静态文件而已，要占用的空间很小很小。我使用 Caddy 来作为博客的 Web 服务器，自动申请和续期 Let's Encrypt 证书很是方便。</p><p>过去，我构建博客文件时采取的是本机构建、Hexo 的部署器将构建好的文件（在 <code>public</code> 目录内）上传到 GitHub 仓库，Netlify 最后部署这些新构建的文件。</p><p>有了 VPS 后，我在 VPS 上添加了一个 hook：当 <code>git push</code> 推到 VPS 上的 bare repo 时，Git 会在接收完数据后自动执行脚本，构建和部署博客文件。这样做的好处是，不用担心不同设备的环境导致最终构建出来的博客文件不一致。</p><p><a id="重定向"></a></p><h4 id="重定向"><a class="markdownIt-Anchor" href="#重定向"></a> 重定向</h4><p>在可能有人在意的角落里，当你访问该博客时，会发现从 <code>cytrogen.icu</code> 重定向了 <code>blog.cytrogen.icu</code>。这是因为我考虑写个人主页，弄一些花里胡哨的东西。目前还在编写中…… 不过依然希望所有订阅该博客的人，即时将 RSS 订阅改成 <code>blog.cytrogen.icu</code> 的。一旦个人主页上线，重定向可就没了。</p><p><a id="webmention-和-syndication"></a></p><h4 id="webmention-和-syndication"><a class="markdownIt-Anchor" href="#webmention-和-syndication"></a> Webmention 和 Syndication</h4><p>现在 Fediverse 上的回应，会通过 Bridgy 发送到 Webmention，再展示到博客文章内了。</p><p>如果你找到一篇文章，并且往下拉，便能找到 Webmention 区多出了两个内容：</p><ol><li>「在 Mastodon 上回应本文」按钮：实际上，使用其他 Fediverse 应用也能回应，并不局限于 Mastodon。目前点击它会直接被导航到我的 Mastodon 帖子，不过最好还是导航到读者使用的实例，之后再考虑怎么实现吧。</li><li>Webmention 的使用说明。点击该段文字结尾的「详情见营造记」的话，可以看到整个功能所用到的技术和背后的流程。</li></ol><p>我就重点说说围绕着 Bridgy 的技术实现吧。Bridgy 要求 Mastodon 帖子包含博客文章的 URL，也要求博客文章里有个带 <code>u-syndication</code> 类的链接指向 Mastodon 帖子。这样的做法被称为 <em> Syndicate</em>。在 IndieWeb 社区，有个原则叫作 POSSE（Publish on your Own Site, Syndicate Elsewhere，在自己的网站上发布、在其他地方联合发布）。因此 Syndicate 这个词汇的意思是「将个人网站上的内容以副本的形式发布或分享链接到第三方」，即「联合发布」。</p><p>此时的问题就成了鸡生蛋、蛋生鸡：如何才能在部署时，将 Mastodon 帖子链接给博客文章、将博客文章链接给 Mastodon 帖子呢？</p><p>如果是手动操作的话，那自然没有问题了：发布文章、在 Mastodon 上手动复制标题和链接并发一条帖子、拿到 Mastodon 帖子的链接并嵌入到文章内。但我想要搞明白如何将其自动化。</p><p>我现在写博客的流程是先在 Emacs 上进行 Capture 行为，写一个条目，接着触发自定义的命令，将条目转换成独立的 Org Mode 文件。转换期间，程序会自动添加我需要的 front matter，这里也包含了 <code>syndicate: true</code> 这样的标识，意味着这篇文章会被联合发布。</p><p>接着整理好 Org Mode 文件后，再次触发一条自定义的命令，将 Org Mode 文件转换成 Markdown 文件，然后放在 Hexo 项目的 <code>/source/_post/</code> 目录下。联合发布的脚本在此处便有了用处，使用时，它会扫描 Hexo 项目内所有带 <code>syndicate: true</code> 的文章，取其构建时自动生成的 <code>abbrlink</code>、拼接成完整的博文链接，然后发布到 Mastodon。接着它会把返回的帖子链接，写回 <code>syndication: 帖子链接</code> front matter。在主题模板中，莫要忘了将该 front matter 渲染成 <code>&lt;a class="u-syndication" href="链接"&gt;文字&lt;/a&gt;</code>，然后重新触发构建和部署，否则 Bridgy 扫描不到。</p><p>Bridgy 会每半小时抓取一次 Mastodon 帖子。不过我的问题并不在这里，而在于我的 Webmention 是静态构建并展示的。因为我不再依赖于 GitHub 和 Netlify 来部署博客，而是在 VPS 上写了个 <code>post-receive</code> 钩子，一旦检测到博客被 <code>git push</code> 到 bare repo，便自动构建和部署到 Caddy 托管的目录内。既然唯一触发构建和部署的方式是通过 <code>git push</code>，那我难道要每半个小时就 <code>git push</code> 一次吗？我会累死的。</p><p>我的解决方案是在 VPS 上写一个 cron 定时任务，每半小时从 <a href="http://webmention.io">webmention.io</a> 拉取互动数据。因为 VPS 的内存实在是太少，不可能每半小时就构建一次（我也需要解决 Mermaid 插件会同时启动数个 Chromium 的问题），最好的办法是直接更新已部署的 HTML 文件。</p><p>Well, talk is cheap, show me the code…… 需要再等一段时间。过去一直在重构博客的样式，但是没有对 Hexo 项目进行重构，以至于硬编码的密钥满天飞。到时候会同样放在 git.cytrogen.icu 上。</p><p>类似的「折腾」也可以见 <a href="https://www.geedea.pro/posts/site-report-4/">《极客死亡计划书 IV》</a>。阅读完看文章的结尾，你可以看到我的一个回应：提出开发一个 Sourcehut 的 <em> Giscus</em>。我设想的是利用 Sourcehut 的电子邮件列表，让想要参与讨论的读者发送电子邮件，网站则自行处理拉取和渲染该邮件列表。虽然我也提到了这种做法的缺陷，也就是清洗很麻烦，不过如果你点击我那个回应的右上角的小箭头，还可以看到 Chlorine 提出了另一个我没有考虑过的缺点：发公开电子邮件的阻力。</p><p>写电子邮件的心智负担会更大，因为电子邮件更像是写正式的信件，有着自己独特的格式要求。我写电子邮件也会注意这些，更不用说平日我都是给教授写电子邮件。然后我会认为，中文互联网独特的一点，便在于「电子邮件完全被抛弃了」。大众有的电子邮箱，恐怕都是注册 QQ 账户送的，平日根本不会使用到电子邮件。几年前我看到有个 Bilibili 的 UP 主想要观众们通过电子邮件投递稿件，却没有想到他的观众全都是根本不会使用，或者说根本没有听说过电子邮件的人，也闹出了一些笑话。</p><p>笑归笑，这种事情还真怨不得人家。大家都不使用电子邮件，甚至有部分人认为使用电子邮件是落后的象征。最终导致在中文互联网，除了极客们，恐怕只有在学术相关的事情上人们才会使用电子邮件。</p><p>我个人后来思考了很久，难道基于电子邮件的评论系统真的是那么不可取的一件事吗？我认为并不是。撰写电子邮件所带来的 <u>认知摩擦力</u>，能够过滤低质量互动。不得不承认的是，现代互联网的评论区充斥着由多巴胺驱动的冲动型回复和无意义的短句，特地打开邮件客户端、构思主题、组织语言的过程中，会天然阻断这种碎片化的情绪宣泄。至于没有畏惧之心的自动化垃圾邮件攻击，这就不属于社会学范畴的问题了，应当让评论系统的服务器端清洗它们。</p><p>目前所有的评论系统，重点可以分为两点：评论本身，以及信息放在哪里。了解数字主权的都明白，将信息数据放在自己手里是最好的，因此和 GitHub 相关的评论系统我认为都不是特别好的选择。比方说 Giscus，虽然方便，也能通过要求读者必须有 GitHub 账户来防止垃圾信息攻击，但是数据是存储在 GitHub Discussion 上的，而 GitHub 并不是一个多么纯良的平台。</p><p>而我先前捣鼓的「联合分发」重点在于「连接」。虽然是 IndieWeb 的概念，但 POSSE 并不认为将链接分发到非独立网络是多么糟糕的事情，反正内容都在个人网站上，和人们交流才是最重要的。不过需要警惕的是如果分发到 Twitter 这类毫无隐私可言的社交媒体平台，会让读者们不知不觉地牺牲掉隐私，那还是强迫读者们只能在 Fediverse 上回应我吧 —— 还请加入 Fediverse！</p><p>虽然话是这么说，我也没少在别人的 Giscus 上留言，而不是发送电子邮件……</p><p>再就是分发到社交媒体平台上，所得到的评论质量。这篇月刊前头已经说过，Mastodon 是微博客平台，重点在于「微」，回应也会随着变得「微」和碎片化起来；电子邮件可以承载更长、更详细的内容，作为辩论确实是再好不过。不过，我并不认为电子邮件因此要比 Fediverse「好」：Fediverse 与电子邮件并不是彼此的替代品，而是能够互补的两个概念。</p><p>但我也不希望电子邮件仅是作为「长篇大论」的载体，它有着自己独特的魅力。并且在 Eltrac 的那篇文章下，你还能看到另一个读者表示自己正在远离微博客平台，如果有基于电子邮件的评论系统那真是再好不过了。好吧，这又是另一个话题了：如何设置读者回应的门槛？设置门槛真的可以过滤掉质量不高的回应么？Maybe？不过现在不论是 GitHub 还是 Fediverse，其实都很好注册，更不用说它们都需要的电子邮箱了。</p><p>最不应该有的评论系统，是无法验证真身的评论系统。之前在博客圈内便发生过一个事情：无法验证真身的评论系统导致了一条具有攻击性的回应的出现。那件事情正因为「无法验证真身」而不了了之，至于之后围绕着可能由冒充者发送的评论内容展开的讨论，在我看来都没有必要进行下去，因为你无法得知这个评论到底是谁发送的。因此，让读者们自证身份是必要的。</p><p>这里的「真身」并不是要求读者实名制，更不是要获取物理世界中的真实身份。我想表达的是「发言者对其数字身份的控制权」。</p><p>再有一个是获取 IP 地址、设备信息等的评论系统 —— 你根本不需要这些内容，读者们也不一定想要展示这些信息！读者们可以自证其数字的身份，但是不应当强迫展示除了身份之外的内容。当然，悄悄存储这些信息也是不好的。</p><p><a id="更多的-slash-pages"></a></p><h4 id="更多的-slash-pages"><a class="markdownIt-Anchor" href="#更多的-slash-pages"></a> 更多的 Slash Pages</h4><p><a href="/posts/c089.html#%E6%8A%98%E8%85%BE%E5%8D%9A%E5%AE%A2">上个月</a> 我提到自己添加了 Slash Pages。这个月，我又添加了一些。同样的，你可以在 <a href="/sitemap/index.html">领地地图</a> 里看到它们。</p><p>虽然 Slash Pages 有很多可以选择的，但我认为最好还是添加一些不常更新的内容进去。我会每过一段时间就更换自己的钢笔吗？不会。所以我要写进 /uses 里。我会每过一段时间就说自己听了什么歌吗？会。那就写进月刊里吧。</p><p>使用「领地」以及自称「领主」什么的，现在看来还是有点小羞耻啊！</p><p>需要说的是，我将二级菜单里的 GitHub 和作品集的链接取下，改为直接放上领地地图的链接。前者现在在 <a href="/uses">/uses</a> 里，后者则被我从博客网站内完全移除了。</p><p>这个作品集呢，其实只是我个人的 portfolio。里面会带一些我现实生活中的信息，想来想去，还是留给那些只认识现实生活的我的朋友们吧。有意思的是，我在尝试使用 Kagi Search 时，测试了一下搜索自己会发生什么。结果在一个介绍 <code>.icu</code> 的文章里，看到作者引用了我这个作品集的设计 —— 虽然这个设计根本就不是我的，只是我使用的一个 Astro 免费模板。</p><h2 id="我写的文章"><a class="markdownIt-Anchor" href="#我写的文章"></a> 我写的文章</h2><h2 id="书籍"><a class="markdownIt-Anchor" href="#书籍"></a> 书籍</h2><h4 id="其他评价"><a class="markdownIt-Anchor" href="#其他评价"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/book/4ZRGmDj0AMstO9tHliGy3H" target="_blank" rel="noopener noreferrer">The Sun Is Also a Star</a><span class="neodb-rating">★★★☆☆</span><span class="neodb-status">已读</span><p class="neodb-comment">这个作者真的很喜欢写混血亚裔。处女作 *Everything, Everything* 里女主是日本混血，这一作里男主是韩国混血。这一作对比上一作，添加了更多有趣的非传统的写作方式，例如更多配角的视角，将故事发生的这一天巧妙地连在一起。故事围绕着「身份认同」转，对于纽约客而言共情起来很容易。 <span class="spoiler">不过我不是很喜欢这一作的结局。</span></p></li><li class="neodb-item"><a href="https://neodb.social/book/35bfn4VPfUU8TTakERoKPD" target="_blank" rel="noopener noreferrer">Everything, Everything</a><span class="neodb-rating">★★★☆☆</span><span class="neodb-status">已读</span><p class="neodb-comment">在我看来，这本书最有意思的地方在于「作者传递信息的方式」，而非故事本身。作者使用了各种并不传统 —— 例如模仿邮件界面 —— 的方式来表达角色们交流过了这件事。故事本身，说实话，并不是那么精彩， <span class="spoiler">就连结尾女主身体的真相也并不是那么难猜</span>；感情戏方面，个人感觉不够顺滑。不过作为该作者的处女作，还算不错。</p></li></ul><h2 id="影视"><a class="markdownIt-Anchor" href="#影视"></a> 影视</h2><h4 id="其他评价-2"><a class="markdownIt-Anchor" href="#其他评价-2"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/movie/3cyk9HnGhkV75gTDmoYVil" target="_blank" rel="noopener noreferrer">奇迹梦之队</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已看</span><p class="neodb-comment">近乎没有什么硬伤，该搞笑的时候搞笑。观感上，3D 的特效很不错，动物角色们的行为和互动都很可爱，并且电影内引入了许多并不常见的动物种类。</p></li><li class="neodb-item"><a href="https://neodb.social/tv/season/4PXIDfrY5UnJgx1L8no15x" target="_blank" rel="noopener noreferrer">五等分的新娘 特别篇</a><span class="neodb-rating">★★★☆☆</span><span class="neodb-status">已看</span><p class="neodb-comment">该篇章是制作组为了补上被跳过的暑假篇而做的。按照漫画的进度，正确的时间线应当是第一季 - 第二季 - 特别篇 - 剧场版。不过因为这个特别篇是剧场版之后做的，有一些内容不看剧场版的话可能会一头雾水。<br>画风方面，我更喜欢第二季的，特别篇的画风和分镜等总感觉和第二季不是同个制作组。OP 的动画相当下功夫。</p></li><li class="neodb-item"><a href="https://neodb.social/tv/season/5Fa8LCoGwBX8IPQjVHk9Cd" target="_blank" rel="noopener noreferrer">五等分的新娘 第二季</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已看</span><p class="neodb-comment">这一季的画风个人看来要比上一季舒服许多，五胞胎们更可爱了，风太郎也使用了正确的黑发金眼设定。<br>掉分的是，为了讲完剧情，删除了许多内容，还擅自挪动角色的剧情顺序。同室友一起重温时，我经常需要解释制作组删除了什么内容、修改了什么内容。</p></li></ul><h2 id="音乐"><a class="markdownIt-Anchor" href="#音乐"></a> 音乐</h2><p><a id="r-906"></a></p><h4 id="r-906"><a class="markdownIt-Anchor" href="#r-906"></a> r-906</h4><blockquote><p>看起来，如果你将 r-906 的名称写成 R-906 或者 r906 的话，他本人就会精神崩坏并且消失呢。</p></blockquote><p>r-906 是一位 Vocaloid 曲制作人（以下简称 P 主），曲风相当独特，我也在很久之前便关注了他。</p><p>这个月想要拿他出来说，是因为发生了一件很是荒诞的事件：上个月，一个自称是 r-906 本人的账号在 BiliBili 上出现，因其拙劣的模仿，引发粉丝们热议。这种事情本来就不少见，荒诞的点在于，r-906 在推特上打假，表示 BiliBili 上的那个账户是假的，却被冒充者倒打一耙、说自己的推特账号被盗取、自己的 IP 在江苏是因为使用了 VPN。</p><p>为了解决这件事，r-906 在另一个 P 主的帮助下，开通了 BiliBili 账号，并发布了 2026 版本的《まにまに》，这才将冒充者打跑。</p><p>说回他制作的歌曲。我非常喜欢他的《パノプティコン》（以下简称《圆形监狱》）和《​<ruby>三日月<rt>みかずき</rt></ruby> ステップ》。曾经有一段时间会去健身房，每次听到歌单里出现他的歌曲，都会让我很惊喜。</p><p>说到「圆形监狱」，这是个可以让一个警卫监视所有囚犯的监狱模型。原理是让建筑变成圆形，警卫在最中心，通过百叶窗查看外围的犯人。虽然无法一次性看到所有人，但囚犯们也不知道什么时候自己才会被监视，因此只能假设自己时刻都被监视，从而强迫自己遵守规矩。</p><blockquote><p>ずっと　見ています<br>アナタを見ています<br>アナタのすべてが　きっと　終わるまで</p></blockquote><p>歌曲开头，从 Sunday 的 S 讲到 Saturday 的 S 后，「我」说「我一直在看着你」。</p><p>「你」是一个不被期待、束手无策、毫无用处的人。</p><p>「我」什么都知道，因为「我」要比任何人都要靠近「你」。</p><blockquote><p>ずっと　見ています<br>ワタシを見ています<br>ワタシが</p></blockquote><p>因为「你」就是「我」。</p><p>「圆形监狱」这一概念最为可怕的地方并不在于它物理层面上的设计，而在于被监视的囚犯在内心里为自己构建的牢狱：自我不仅是狱卒，也是囚徒，日复一日不停地监视自己下去。就算深处也想要呐喊「才不是这样吧！」，但极度的自我贬低也只能让自己继续痛苦下去。</p><h4 id="其他评价-3"><a class="markdownIt-Anchor" href="#其他评价-3"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/album/3G9CZlh5RLg1ODkl4W130n" target="_blank" rel="noopener noreferrer">春嵐</a><span class="neodb-rating">★★★★★</span><span class="neodb-status">已听</span><p class="neodb-comment">个人认为是 john 曲风同质化时期的一大突破，也是他之后难以越过的一座山。john 语和声算是点睛之笔，也能听到许多 john 颇有特色的「ta za 不分」调音。很容易对歌词中的「我」产生共鸣。虽然 MV 不计入评分计算，不过很有 john 本人的风格，可爱。</p></li><li class="neodb-item"><a href="https://neodb.social/album/4g7crZqaaQDlA27o3jPkIP" target="_blank" rel="noopener noreferrer">パメラ (self cover)</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已听</span><p class="neodb-comment">喜欢高潮部分。</p></li><li class="neodb-item"><a href="https://neodb.social/album/1tshmBF4L9uSVAWDUMJlDi" target="_blank" rel="noopener noreferrer">Q &amp;A (feat. KASANE TETO)</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已听</span><p class="neodb-comment">MV 要比音乐本身更吸引人，但不代表这首歌不好听。因为是音乐所以只点评音乐本身。几段长难句听着很爽。最开始还好奇这是故意调成更电子的 SV 还是 UTAU 的 Teto。跟我一起听的人说是 SV，一查发现是 UTAU，某种程度上反映了 P 主调得很好吧。歌词的蕴意颇有意思。</p></li><li class="neodb-item"><a href="https://neodb.social/album/4o9DXx13uD1QROqH9x03CX" target="_blank" rel="noopener noreferrer">瓦合</a><span class="neodb-rating">★★★☆☆</span><span class="neodb-status">已听</span><p class="neodb-comment">对比《丑奴儿》，没有了震撼感，歌词也是个硬伤。</p></li><li class="neodb-item"><a href="https://neodb.social/album/0raoBextspyRrvNVmkt0qp" target="_blank" rel="noopener noreferrer">Rikki</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">在听</span><p class="neodb-comment">个人比较喜欢 *Friend* 和 *Why Try*。</p></li><li class="neodb-item"><a href="https://neodb.social/album/3xnkZjJRIHUCjSOlDPGCwP" target="_blank" rel="noopener noreferrer">上海速写</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">在听</span></li></ul><h2 id="日记片段"><a class="markdownIt-Anchor" href="#日记片段"></a> 日记片段</h2><button id="details-toggle-diary_sections-1789678111592" class="details-toggle-btn" data-group="diary_sections" onclick="toggleGroupDetails('diary_sections', 'details-toggle-diary_sections-1789678111592', '展开所有', '收起所有')">展开所有</button><details data-group="diary_sections"><summary>二月一日</summary><div class="diary-entry">00:34 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115992564982664092" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>亲戚之间的礼尚往来真是讨厌！</p><p></p></div><hr><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 一月二十九日 04:51</span>            </div>            <div class="diary-quote-preview">吃饭期间收到母亲发来的视频：不知道具体发生了什么，但是家里的芦丁鸡都被猫咬死…… 沙发也被猫挠破。母亲生气地打我电话，问我要把猫放归还是送走 —— 最开始把猫捡回家就…</div>          </div>01:36 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115992809431069541" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>回家看了一下，发现小鸡没有全部死光。不过死了一半，也差不多。听母亲说，不只是咪咪猫咬了鸡，幸运狗也干了，两个臭东西都被教训了一顿。</p><p></p></div><hr><div class="diary-entry">02:01 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115992904444263209" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>妹妹把 iPad 摔坏了。我看了一下，实际的显示屏和外侧的玻璃是分开的，她只摔碎了玻璃屏幕，内部的依然可以正常使用。</p><p>iFix 上整个 fix kit 是 60 美元，也比在维修店里的「印象价」便宜。再去看亚马逊上的，20 多块钱的也有，但是我怕买到便宜烂货，还是去配件供应商那儿买吧。</p><p></p></div><hr><div class="diary-entry">02:37 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115993046788907329" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>妹妹有很多儿童相机，这个貌似是她新买的。我拿来拍了几张幸运狗的照片，模模糊糊的灰色照片别有风味。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/993/043/630/434/017/original/c0949f17ecc4bd6f.jpg" alt="白色桌面上放置着一台粉红色的儿童热敏打印相机，旁边散落着几张印有迷你泰迪犬和罗小黑玩偶的黑白小照片；右侧是一台屏幕严重碎裂的 iPad，左侧可见黑色联想笔记本电脑的一角。" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>二月二日</summary><div class="diary-entry">07:49 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/923965589367644375" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>尝试迁移到这个实例中。应该添加 alias 就会自动迁移了吧？</p><p>这个是打哈欠的匹克猫。</p><p> <a href="https://pixelfed.feddit.social/discover/tags/tabbycat?src=hash" title="#tabbycat" class="u-url hashtag" rel="external nofollow noopener">#tabbycat</a></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/e6fgJe18hH0S/oeLQOHDGvCXvef1kpHBPjOqawDA3tutku15JA4bj.jpg" alt="一只白底虎斑纹的家猫位于画面中心，前爪搭在一个米色的毛绒材质平面上。猫的头部正对镜头，双眼圆睁注视前方，嘴巴微微张开，露出上排细小的牙齿，呈现出张嘴的瞬间状态。" loading="lazy"></figure></div><hr><div class="diary-entry">16:43 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116002036137027461" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前一直都是使用 Teamviewer 远程操控自己的电脑。现在这个学期要频繁出门、不在家，脑子里突然就不想要在自己的笔记本电脑上安装 Teamviewer 了。花费一些精力查了一下，发现可以使用 Tailscale + Remmina 的方案远程访问电脑。</p><p></p></div><hr><div class="diary-entry">17:40 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116002261033081652" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>上周坐公交去上课被坑了，连着几辆公交都是 out of service。到学校的时候课已经只剩十几分钟就结束了，遂打算直接走路去上学。</p><p>前几天室友跟别人跑马去了，回来的时候告诉我跑步会累几乎都是因为没有正确地呼吸。首先是绝对不能使用嘴巴呼吸，全程只能用鼻子。其次是呼吸时频率要快，最好是短促的呼呼呼吸吸吸。</p><p></p><blockquote class="diary-thread-reply">17:48 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116002291386910714" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>走到一条街，因为积雪而本就拥挤的路被一群人堵住了。看到我走过来，这些人也像是我不存在一样、没有丝毫让路的想法。真是不礼貌！</p><p></p></blockquote></div><hr><div class="diary-entry">20:05 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/924150865879789684" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>上传一些旧照片之都是鸟类。</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/of11eTJofxxN/WgGroo5ZCMa42Gne3rgE51APloi1e1dK9lyOAM1R.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/Uu7Py7cR9zaK/CfwPFuguUoQ6gJFbdhxO5Q6PL2poUE9BVLMiUWJv.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/t2ElKhDM9W4V/Gau7NwzV8N2n4VbiEONY3Zw6pPZYJI9ZMn8ffwCk.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">20:58 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116003040371197899" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>一个寒假过去我又不能连上学校的网络了。本来有几个作业要打印出来，但貌似学校打印机的 portal 只有连上学校网络才能打开，好麻烦喔。</p><p>在学校的 14 楼等电梯下去，等了差不多快 10 分钟了也没有见到电梯来，遂走下楼，居然只用了 3 分钟 —— 早知道我就直接走楼梯了！</p><p>离下节课还有十分钟，我只能赶忙跑去图书馆里使用学校电脑访问线上打印系统。不得不说，用起来很浪费时间，需要登录两个系统的账号才能打印出我需要的文件。打印结束后，课已经开始了。</p><p>这次上课我本来打算也不坐电梯，但刚走到大厅电梯就来了，真是天助我也！—— 个头啦，下课时楼梯间和电梯间都挤满了人。这个大学真是小得不行。</p><p></p></div></details><details data-group="diary_sections"><summary>二月三日</summary><div class="diary-entry">08:35 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/924339591591684124" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>大鹅和家里的鸡。</p><p>刚才那个帖图片太糊了换了张，但是编辑的时候没有找到添加新照片的按钮，遂删了重新发一次。</p><p> <a href="https://pixelfed.feddit.social/discover/tags/birds?src=hash" title="#birds" class="u-url hashtag" rel="external nofollow noopener">#birds</a> <a href="https://pixelfed.feddit.social/discover/tags/goose?src=hash" title="#goose" class="u-url hashtag" rel="external nofollow noopener">#goose</a> <a href="https://pixelfed.feddit.social/discover/tags/chickens?src=hash" title="#chickens" class="u-url hashtag" rel="external nofollow noopener">#chickens</a></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/8Egy4Pkudb7x/KeDmEN5D7UCfTLRqHKAe2L2HPJBT6OOmvv1UrS9x.webp" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/7niboDeFiahX/iIqHip8n35doGS9UXtRC8uEq02rKBYbPWKVlel5E.webp" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">08:49 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/924343160772190268" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>一些幸运狗的照片。</p><p> <a href="https://pixelfed.feddit.social/discover/tags/dog?src=hash" title="#dog" class="u-url hashtag" rel="external nofollow noopener">#dog</a> <a href="https://pixelfed.feddit.social/discover/tags/poodle?src=hash" title="#poodle" class="u-url hashtag" rel="external nofollow noopener">#poodle</a></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/JoDNlYkR12O5/9fXO4i95QgCpHSLX7VtpHasXrIPGHDqjLXcM7Fvk.webp" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/GtArWrYEGC3n/OaXajcL8ZIhj9y1OlSF9GB5kZz8NpfXsCg2TsN0Q.webp" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/SX74hHpga2OE/y0mjtsMZuUw0IHhzjy9pCD7LulqXtXmE1BZ6jvcI.webp" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/yj6NdSFR1QCa/IgDEGfopKFe0gscbDBdaUpHCaLkjoanjPG7q5Etc.webp" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/qaxv5vXZkgZA/0dmDXcCgSGpDH3AcQaoDZzFSGrBP9ZYeORwUKUm4.webp" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/eLbvGxksHrCi/CvmPC1tqStx600PS26cDTa0lSLXWKYph5v9ByIRA.webp" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/1goe9eV8EKOJ/MytjcwQHpoUxVuse5U6yJlxvIweY7mCuNf4xIIZl.webp" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">08:57 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/924345050604662876" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>一些邻居们。</p><p> <a href="https://pixelfed.feddit.social/discover/tags/cats?src=hash" title="#cats" class="u-url hashtag" rel="external nofollow noopener">#cats</a></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/cCAIQDyWAoB8/B5tqEjd87sR9smrvc9L6wPEqBProOtWtvpURV5lg.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/OPk5Zc56GuZB/tBOLmA1XqAJVy1GclSTKrPVBKVP2ZEnwwKv0kyoE.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/3pFLCYtAKljO/alWBLgFWWXQAeErTGKpYHmflcbI9ESjQs6eD1gzR.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">09:08 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/924347971408498872" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>去年养的虾虾们，很是漂亮。</p><p> <a href="https://pixelfed.feddit.social/discover/tags/shrimps?src=hash" title="#shrimps" class="u-url hashtag" rel="external nofollow noopener">#shrimps</a> <a href="https://pixelfed.feddit.social/discover/tags/aquarium?src=hash" title="#aquarium" class="u-url hashtag" rel="external nofollow noopener">#aquarium</a></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/u54CPqBFBIgi/ILdPzF4SEA0z25fnr1mloCSajdFK0cU83EsmXCb2.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/CazF6t1b0WcO/ilKmrEPFSh2OmJzbOq52XOawz4N0m5XMb2hgzRR8.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/388drSfqytvG/IUAqiJK1BgNUGK9tLv1SPyci6lMliHLXlWzB9sbv.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/QUJDuJFbYGEB/0ztmf9Tt3TX9VqusbbYAWj8zmdgNqbFEM4zG2lb4.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/PzIVe1Bu4W8f/0SJc1hoV2dZaLmTsylC5740QthoNAd0dkxQPOnhe.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/ylzPOjfzj8Ss/w23M4MIUOsPMQ7240JWjFQsQ6g7NbgST5zmKrT01.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">09:24 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/924351987158626575" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>去年去的 Mercer Labs，容易让人昏厥，不过也看到了许多有意思的艺术品。例如 *Archetype* 这个艺术品（最后一张照片），让我想起了《难自禁》。两者使用的都是 KUKA 产的机械臂，只是前者让机械臂在沙子上创作、又抹掉重新开始，后者像西西弗斯一样不停地清理着从自身流出去的液体……</p><p> <a href="https://pixelfed.feddit.social/discover/tags/mercer_labs?src=hash" title="#mercer_labs" class="u-url hashtag" rel="external nofollow noopener">#mercer_labs</a> <a href="https://pixelfed.feddit.social/discover/tags/artmuseum?src=hash" title="#artmuseum" class="u-url hashtag" rel="external nofollow noopener">#artmuseum</a></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/pOu0I6Gqo3vt/Euzd0fB9TDQUNzgROZtzwUb19kBtvDoEqCywHHhb.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/TTf4C035COD6/CQHzEHdhaA3VsmBD5TforgD6IX6csqDMFFNZxmkp.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/roM5tcU2mFlW/zeqC43HRztQzdZe1fFIn31tLQpObWJYEMuyo82mx.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/VgG5XhE57QxQ/db4JF9C6A9quQiXxkFT87uIhoJiMtx6LzD9ZnJpl.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/NZrjaJffKCow/YWDBehRtHD3P6oTsTgLj8KLTQTn76TLXHalaEDhi.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/nB3U3zu15Hth/TnXxv3coUCNb6mviWdsuQ5IXnw7kJaMTzO5GwZBK.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/4qopShxDLRS6/sZ4c8ODUpuSQurYgMxWtd5HDtHYwDj14TCcD9SwI.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/iNRk6mDL2nqo/6Bfs9DV1unJAnTqmEmdYoCDRFRil5dZmzNbpwnJz.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/AtRNlppNNXoW/R3rMzQgPvyjO4eDZUd4dcgHV0XJuEDlMDCGbdJkO.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">17:38 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/924476238685728785" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>去年暑假去了林肯中心参加 Summer for the City 活动之「上海日」！观看了李晓川先生及他的爵士乐队的演出，很是高兴。整个演出非常好听，后面还有观众们一起跟着主唱唱歌的环节。最为特殊的是那两个中国鼓。</p><p>当天也有明日方舟的表演（最后一张图片），不过我没有待太久，拿了点小周边走掉了。</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/bPC0qCUtKjc9/xqf6me0nQRGVJ7E5LlgsijETzukLvQQd3wUJeWSD.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/FLovLxs73KDE/jQ5BizwjZJHiWFDfqa9ZR7PauuV9YW2K9hKfLs7u.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/RqCyFYZ7T3cc/02yM4sDCaEE8GIUCuORtGsRHIPO6o0AJ9PBej6jw.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">17:39 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116007919254418317" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近左眼皮一直在跳，好奇怪。估计是眼睛太疲劳了，从很久以前我也有眼球时不时震动的问题。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">螺的照片，可能会吓到不喜欢螺的人，请注意 | Pictures of snails, might scare some people.</summary>        <div class="diary-cw-content">18:04 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/924482833697067042" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>黄金螺「大日」～</p><p> <a href="https://pixelfed.feddit.social/discover/tags/goldensnail?src=hash" title="#goldensnail" class="u-url hashtag" rel="external nofollow noopener">#goldensnail</a> <a href="https://pixelfed.feddit.social/discover/tags/snail?src=hash" title="#snail" class="u-url hashtag" rel="external nofollow noopener">#snail</a></p><figure class="diary-media diary-media-sensitive"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/dCpe3rL31lZi/rsDDSJ2EVCbIEy4r16MNcEtamc8kFyr1M8t8ZqC3.jpg" alt="" loading="lazy"></figure><figure class="diary-media diary-media-sensitive"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/GcmVS4CEp1vl/rhRFoGsB5VaUum68WZivy1Nu58mS4y6htPPJM1Bf.jpg" alt="" loading="lazy"></figure><figure class="diary-media diary-media-sensitive"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/7z01FjEsIOuP/4ZsUaFVjCBAR3dIWfw3CiAHTuvA21J6RqJj8Y4DJ.jpg" alt="" loading="lazy"></figure><figure class="diary-media diary-media-sensitive"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/cxzzWNOsFQCf/RMSgWvT1LrU0kWKQbF6VmHFehjrNdhP0iobpLoAp.jpg" alt="" loading="lazy"></figure><figure class="diary-media diary-media-sensitive"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/EaekcAsiHLcX/p4EbMGArFEbcCfVsSM5GaROTuLTBoov9R3E9kbUH.jpg" alt="" loading="lazy"></figure><figure class="diary-media diary-media-sensitive"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/e0mfzylOHOI9/IWu0qdrkUTxNmDux3iMQ5MBhvF4V4Tz8LtMfnUAH.jpg" alt="" loading="lazy"></figure><figure class="diary-media diary-media-sensitive"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/QvIyP8vh7UOk/uRwHlHmWt94lKcucSJgzivUGFUpRIVgBmfevbWfN.jpg" alt="" loading="lazy"></figure></div>      </details></div><hr><div class="diary-entry">19:46 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116008416707581601" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>才想起来自己的 Instagram 什么的社交账户上还挂着我的博客地址，想要撤下来时发现可恶的 Instagram 居然要求下载 App 才能撤除。只能等到晚上回家用 iPad 操作了，晕。</p><p></p></div></details><details data-group="diary_sections"><summary>二月四日</summary><div class="diary-entry">01:12 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116009700740828623" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我服了鸡又被猫咬了 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/001/443/original/f80d90ce2280a2f2.png" alt=":aru_0171:" loading="lazy"> </p><p>更匪夷所思的是，明知道猫可以打开鸡笼子，还是选择将鸡笼子原封不动放在客厅的家里人。</p><p></p></div><hr><div class="diary-entry">01:26 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116009755405039426" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>去年上旬沉迷于玩《森林联盟》的时候，认识一个网友，组了群一起玩。第二天他说他有个 date，接着便再也没有回过我们。</p><p>直到今天他出现，告诉我们他进精神病院了，不是故意不回我们消息……</p><p>靠，好真实的情况。</p><p></p></div><hr><div class="diary-entry">01:43 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116009820491754146" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最痛苦的莫过于，三年前度过了相当可怕的生日后，得知生日那天草东在附近的城市里开演唱会……</p><p></p></div><hr><div class="diary-entry">12:54 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/924767198940790798" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>咪咪猫晒太阳中。</p><p> <a href="https://pixelfed.feddit.social/discover/tags/cat?src=hash" title="#cat" class="u-url hashtag" rel="external nofollow noopener">#cat</a></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/LVJt9B1gk1qt/aJzkH64U403lUnSmTeN7fUcsl7eCC4PVwx2IGNq9.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">14:20 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116012797224570128" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>做了两个诡异的梦。一个是我在一栋大楼里，楼下出现了 ICE 杀人事件，且 Mastodon 被全面封锁（不知道怎么办到的但总之 Mastodon 消失了呜呜呜）。另一个是世界上出现了超能力者，他们时不时会打起来，因此我的梦里出现了多场超能力打戏。在我醒来之前，梦里的场景是有人在用「拜登 油」炸「一个女人的名字但是忘记了 饼」 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/070/960/original/50f556343257c59f.png" alt=":wolf_think:" loading="lazy"> </p><p></p><blockquote class="diary-thread-reply">15:33 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116013085353909873" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>或许是最近 ICE 相关的东西看得太多了，校友之间也在传 ICE 会出现在哪里。看着因他们而死去的人们，有时候会想下一个可能是我。</p><p></p></blockquote></div><hr><div class="diary-entry">15:48 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116013146008129449" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>税季到了（好「美国」的话题），要做的事情变多了。无论是工作，还是和家里之间的沟通，都变得频繁了不少。尤其是和家里，就报税一事吵了好多架。母亲总是会用着她不知道从哪里得知的错误税务知识辱骂我。尽管我不是一个干税务工作的人，但多多少少还是知道一些税务相干的基础知识，听出了一丝丝不对劲儿。</p><p>和室友确认的时候，因为她们之间有过一段冲突，室友很不吝啬地说出了「傻逼非专业」这几个字。我也如家中常说的那样，白眼狼般赞同了她。</p><p></p></div><hr><div class="diary-entry">19:04 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116013915313024977" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>上课中，昏昏欲睡的，悄悄在玩 Emacs…… 突然间，教授说话兴奋起来，狠狠敲了桌子 —— 吓死个人。</p><p></p></div><hr><div class="diary-entry">22:17 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116014676159085435" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>原本想着回家不急，花个三块钱坐公交回去好了，结果一等就是一个小时。这期间只来了三辆公交，还是连着一起来的，其中两辆满员，一辆没人但是直接越过了我这一站开走了。</p><p>外面又冷又暗，心情不由自主差了起来。将沉没成本抛之脑后，决定走路回家。中午没有吃饭，走一半肚子饿，停在了麦当劳买个五块小套餐。排队的人不多，但是里面的员工慢慢的，经理还一直在骂其中一个速度慢、不知道在干什么。等待期间过来一个人投诉说有人占着厕所不走，反而在里面吹起了叶子。</p><p>现在这个套餐提供加钱升级薯条，我升级成了个大薯条，六块五税前。</p><p></p></div></details><details data-group="diary_sections"><summary>二月六日</summary><div class="diary-entry">11:51 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/925476179809973092" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>怎么不晒太阳了。</p><p> <a href="https://pixelfed.feddit.social/discover/tags/cat?src=hash" title="#cat" class="u-url hashtag" rel="external nofollow noopener">#cat</a> <a href="https://pixelfed.feddit.social/discover/tags/poodle?src=hash" title="#poodle" class="u-url hashtag" rel="external nofollow noopener">#poodle</a></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/kqwUol8Ohx2l/KQtEHqWUbCINnNmkVdvDs8iSZHHf2ymuH6TT0IW3.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">11:52 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/925476421228401509" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>尝试发个视频，是咪咪猫舔毛的视频。</p><p> <a href="https://pixelfed.feddit.social/discover/tags/cat?src=hash" title="#cat" class="u-url hashtag" rel="external nofollow noopener">#cat</a></p></div><hr><div class="diary-entry">19:56 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116025445866805840" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这几天因为要用手机看照片和视频，时不时会切换到正常的颜色模式。结果就是，感觉手机屏幕上的颜色过于鲜艳，眼睛很难受很难受。</p><p>这下不立马切回灰阶都不行了……</p><p></p></div><hr><div class="diary-entry">22:03 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116025945729676800" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我想要在笔记本上运行泰拉瑞亚玩。初次进入游戏发现帧数连 60 帧都不到，检查时发现自己连 NVIDIA 驱动都没装…… 安装时又发现，NVIDIA 驱动里已经不再支持 Pascal 架构 —— 对哦，这台电脑用的显卡还是不知道什么时候诞生的 MX230。</p><p>这里一个坑是，Pacman 上安装不到支持 Pascal 架构的 NVIDIA 驱动，最好是使用 Yay 安装特定的版本，至于装哪个版本，见 <a href="https://wiki.archlinuxcn.org/wiki/NVIDIA。" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="ellipsis">wiki.archlinuxcn.org/wiki/NVID</span><span class="invisible">IA。</span></a></p><p>装完后再进游戏一看，还是跑不到 60 帧。接着我才发现，光是跑个泰拉瑞亚 GPU 内存就会用到近 2GB，MX230 也只有 2GB 内存大小啊！所以我放弃使用笔记本电脑玩游戏了……</p><p></p></div><hr><div class="diary-entry">23:04 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116026183703544324" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>走路上学期间路过许多小巷。虽然道路很窄，多为单行道，且人行道的宽度只能挤两个人左右，但总能看到装修不错的店，其中酒吧最多。</p><p>室友很喜欢酒吧：一是氛围好、灯光舒适、音乐优雅；二是她不讨厌酒，倒不如说她还蛮喜欢酒的；三是酒吧可以喝酒，而喝酒意味着可以快速跟人拉近距离（当然不是罗曼那层的含义），尤其是四十岁左右的人。如果是吃正餐的话，需要考虑许多事情，但酒吧就不用考虑正式不正式了，且其氛围更容易让对方打开心扉。</p><p>我对酒吧就没有那么喜欢了。我不是一个精力那么旺盛的人，在酒吧里待着会昏昏欲睡。并且我也喝不来酒，每次去只能喝 mocktail—— 我喜欢称它为「假酒」，其实就是果汁混在一起、看上去像酒而已。</p><p></p><blockquote class="diary-thread-reply">23:14 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116026222618501451" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>走到学校附近，在路口听到身后有人被叫住：「你好，你有时间吗？我有问题想问你。」最近这里经常出现这些人，上次经过时我也被叫住，但我没听到，走远了一点才反应过来、回头去看对方。不过对方以为我故意无视了她，走掉了。</p><p>今天我总算听到了他们在采访什么 ——「美国哪个州以 K 结尾？」哦～原来是在拍 TikTok。一段时间为了考察市场，我研究了一点点点点点 TikTok 上的内容，以及 Z 时代的朋友们喜欢看什么，这种采访视频就很常见。</p><p>被采访的人说道：「这是一个好问题……」不，这不是！New York 啊！ <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/011/original/0158d7965e3f9488.webp" alt=":gblackcat_shake_shadow:" loading="lazy"> </p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>二月七日</summary><div class="diary-entry">02:12 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116026925089019895" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/008/original/424361453b49ed14.webp" alt=":gblackcat_shake:" loading="lazy"> 目前最后悔的事情是没有即时将博客链接从各大社交媒体上撤走。</p><p></p></div><hr><div class="diary-entry">19:10 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/925948836321390842" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>抓到一只粘人的匹克猫。</p><p> <a href="https://pixelfed.feddit.social/discover/tags/cat?src=hash" title="#cat" class="u-url hashtag" rel="external nofollow noopener">#cat</a></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/4pKHEZH43Rld/WHOENLeWv6ljnqjlK2kwpTbEVIX4K30VmiXW2GFs.jpg" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary> 二月八日</summary><div class="diary-entry">02:33 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116032669264420297" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>美食中餐店里有个特别可恶的规矩：「芥兰」其实是「西兰花」。这成功地骗到了无数广东人、看着盒饭里的西兰花无能狂怒……</p><p></p></div><hr><div class="diary-entry">11:43 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/926198959946891695" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天匹克猫要出门，穿件毛衣别冻着了。</p><p> <a href="https://pixelfed.feddit.social/discover/tags/cat?src=hash" title="#cat" class="u-url hashtag" rel="external nofollow noopener">#cat</a></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/3VkTR1torKQt/2BfsdFxVl1eg66A2v3EiKh4oCkuA57dadbVyR84B.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">15:52 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116035811572773131" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨晚想要给室友看自己几年前在贴吧发的一个帖子；内容是我当年的 P 图合集，感觉很有意思，遂分享。结果她看个首页，就自顾自点进我的个人首页，要翻我发的所有的帖。</p><p>我是自小学开始就在使用贴吧，混迹在各个我喜欢的作品吧内。直到数年前，贴吧开始频繁向我推送我不喜欢的极端内容，我才放弃了使用贴吧。因此，你要说我都发了什么，我也不记得。秉着对潜在黑历史的恐惧，我立即试图抢走手机，却根本抢不过这个健身者。无能狂怒的我，只能窝在被子里生闷气。</p><p>她翻了一点，迟迟发现我没有出来，才发现我是真的不开心了。她以为刚才只是在和我打闹，没有想到我这么放心里去，并抱着很没有诚意的态度向我道歉 —— 她认为，我和她的关系应该亲密到并不需要隐藏什么才对（也确实是这样），并且我也看过她的许多黑历史。</p><p>我生气的点主要是：我都告诉你我不想给你看，你为什么还要如此坚持、去做我不喜欢的事情？总之，我们各有自己的不服，不开心地睡觉去了。睡前我想到，其实自己过去也做过类似的事情 —— 无视对方的意愿，非要随着自己的性子来 —— 想必也没少让对方生气吧……</p><p></p></div><hr><div class="diary-entry">18:26 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116036416886685015" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我终于想起来台式电脑上还用着 Firefox，终于将其卸载、全面投入到 Floorp 的怀抱。</p><p>Firefox 至今都没有提供安装 PWA 的选项，但是 Floorp 就有。不过我现在比起使用 PWA，会更倾向于将标签页都放在不同的工作区内，每个工作区都使用不同的指纹。</p><p></p></div></details><details data-group="diary_sections"><summary>二月九日</summary><div class="diary-entry">06:43 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116039314202772768" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天，因为一些误会，购买了一台 VPS（三年的使用权？）。虽然之前写了一篇和数字主权以及 VPS 相关的博文，但是用钱包以及访问距离来看的话，最终还是需要购买身处美国的 VPS。</p><p>目前还在折腾，看看我能用它做什么。</p><p></p></div><hr><div class="diary-entry">15:06 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116041291245406971" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>继卸载了小红书后，最近发现自己开始点进百度贴吧看。有趣的是，进去看没多久我就会因为百度贴吧首页推荐给我的内容而被无语到，立即退了出来。不过这依然小小影响到了我的生活，怎么又开始掏出手机、空虚地打开一个 App 了呢？和我的其他 App 一样，我卸载了百度贴吧、改用电脑上的 Web。</p><p>说起它会推送给我的、我没有关注的内容，除了各国的政治，便是失传媒体。说是从什么时候，一个「我也要死吗」的梗在国内火了起来。附着的图片，却迟迟找不到出处。这期间出现了，一个人冒充原图作者、被拆穿后又辩解说自己是在做社会实验的事情。近期，原图作者被找到，伴随而来的，便是作者社交账号评论区内，大量的「狂欢」—— 其实就是一群网民在下面发「到此一游」，以及原图的二创产物。</p><p>让另一部分网民担心的是，这些二创图片很多都是 AI 生成的。作者在简介里提到严禁 AI 训练，这群网民却还是在评论区内自顾自发送 AI 图片，会不会惹怒了作者。幸运的是，作者后续的回应还算正面。要是真的勃然大怒了，那便是另一场网络战争吧……</p><p>我对互联网环境没有学习太多。例如一名网友认为「该作者是因为此图的 AI 二创而火的，没有 AI 不过是路边一条野狗。网友根本不需要在意他的想法，因为该 meme 已经不再属于它，互联网就应该解构再解构，网友们嗨就好了」。他的观点自然反驳不起「不要在作者社交平台账号下发 AI 生成的图片」的要求，只是我很好奇，这里的「解构」是什么意思，互联网到底又是什么呢。</p><p></p></div><hr><div class="diary-entry">15:08 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116041300774628810" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>读中文课要求的《大闸蟹》，搞得有点饿了。螃蟹说爱吃，也爱吃，说不爱吃，也不爱吃。味道鲜美不假，但是吃起来麻烦，小时候还被迫吃多只螃蟹，有点心理阴影……</p><p></p><blockquote class="diary-thread-reply">15:12 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116041313195221825" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我的另一个心理阴影是…… 吃到蛋壳。高中时母亲帮一个亲戚带孩子带了半年还是一年。一次，她在一个碗里剥了鸡蛋给他吃，见我下楼，用那个装有碎蛋壳的碗给我盛了饭。浑然不知的我，扒拉几口，吃到的除了白米饭，就是蛋壳。实在是太恶心了！</p><p></p></blockquote></div><hr><div class="diary-entry">16:15 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116041561566440095" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在一个可能有人在意的角落…… cytrogen.icu 博客网站变成自托管的啦！</p><p></p></div><hr><div class="diary-entry">17:36 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116041880954692608" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>可以理解喜欢学习，但是无法理解喜欢学校……</p><p>好不想去学校。</p><p></p></div><hr><div class="diary-entry">19:05 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116042232544546511" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>走着走着看到一句标语：</p><blockquote><p>为什么 iPhone 的充电器不叫 Apple Juice？</p></blockquote><p></p></div><hr><div class="diary-entry">19:23 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116042301727090750" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>中午微波了三个急冻的「狗不理大包」吃：首先清洗这些包子，放入一个可微波的容器内，保留底部有一些水，然后盖上盖子但得留个缝儿，最后微波三分钟即可。</p><p>我讨厌纽约市遍地的甜口肉包子，这个包子却不是甜的，令人意外。馅儿的话，因为是急冻包子，所以只能是一坨肉球了，也不怪它。</p><p>开心同室友分享时，她咬了一口，说：「对不起，我喜欢甜口的包子。」一瞬间，我有了和她打起来的冲动……</p><p></p></div><hr><div class="diary-entry">21:28 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116042794881990084" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>学习了一些汉语的读法。</p><p>首先是「血」这个字，如果和其他字合成一个词，念 xuè；如果只有它自己，念 xiě。也就是说，并没有 xuě 这个念法。</p><p>汉语也有「文白异读」的概念，即一个字在口语环境下念这个，在书面环境下却念那个 —— 比如说「壳」。「蟹壳」、「蛋壳」等念 ké，「板壳」则是 qiaò，明明意思是同一个。同样的还有「爪」，书面环境念 zhaǒ，口语环境下念 zhuǎ。</p><p></p></div></details><details data-group="diary_sections"><summary>二月十日</summary><div class="diary-entry">04:40 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116044491242235613" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>部署了一个自己的 FreshRSS 服务。虽然现在有 tailscale，可以让手机随时连接到家里电脑的本地服务，但觉得还是自搭建一个比较好。</p><p>折腾期间发现有一个可以管理用户的板块。说来这个功能确实很小，都不怎么吃内存和存储（除非订阅源很多很多？）。就算添加多个用户也不会对服务器产生多大的负担。会有人对这个感兴趣、需要一个云端的 FreshRSS 么？</p><p>目前看状态用的是 Beszel。</p><p></p><blockquote class="diary-thread-reply">02-11 18:55 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116053514903449536" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我还部署了一个邮件服务，使用的是 Stalwart Email Server。现在已经将 iCloud 邮箱地址从博客上撤了下来，改用这个：boo@cytrogen.icu。</p><p>能发现用户名里的超级迷你小巧思吗？</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>二月十一日</summary><div class="diary-entry">01:17 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116049357365939091" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>寻思着闭店前终于可以用光所有的材料了，突然冲进来十几个人是几个意思 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/245/original/aad7de836fc79371.png" alt=":ablobhammer:" loading="lazy"> </p><p></p><blockquote class="diary-thread-reply">01:20 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116049367234373317" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>什么叫过一会儿要下雨了，我出门前看天气预报可不知道这一点啊！</p><p></p></blockquote></div><hr><div class="diary-entry">11:06 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/927276794884850359" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>咪咪猫和匹克猫，一个不亲人，一个有人瘾、天天巴不得抱着我睡觉。</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/ZFrw8d2ZkdFb/4RvgyjLvG1L70DOJnPgwNiJz9IfbMiRt80tOxcQG.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/YKWXsp3CfJNV/OsAvTtskO5y5Y6uGR6HunjLgoO7rIR9dYwFG4Dwf.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">17:30 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116053181357675165" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>周四店里又要聚餐，一聚餐我就知道，他们又要喝酒了。我实在是喝不了。虽然没有到喝了就要起疹子倒地上的状况，但是脸红头痛还是有的。</p><p>向老板表示自己喝不了酒，却被说不够争气，内心只剩下怒火。</p><p></p></div><hr><div class="diary-entry">17:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116053188697458033" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>快捷键用多了，开始理解不同系统或者软件快捷键不统一是多么难受的事情。</p><p></p></div><hr><div class="diary-entry">17:33 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116053194013728767" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>街道的下水道口处，时不时会冒出不明成分的浓烟。这到底是什么玩意儿，看着好恐怖啊。</p><p></p></div><hr><div class="diary-entry">17:45 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116053241488907654" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>纽约客上街出门的每日任务：</p><ul><li>吸到二手叶子</li><li>差点踩到不知道是人还是狗的排泄物</li><li>差点被不会讲英语的逆行外卖员撞飞</li></ul><p></p></div><hr><div class="diary-entry">18:39 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116053452782209344" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>忽然想到把笔记本电脑的触摸板功能关闭，让自己只能通过键盘使用电脑。想必这样，过一段时间我的脑子里就会全都是快捷键了吧。</p><p></p></div><hr><div class="diary-entry">19:12 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116053582512297974" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>很久之前就想分享的，但是一直都没有拍照下来，他的海报也时不时会被撕掉，最近终于拍到一张。</p><p>我认为这是一个很棒的案例：使用会吸引到人的标题和图片，进入网站后可以直接看到商家的故事，让潜在客户先一步对商家产生感情，并且记住他。</p><p>（这算打广告吗）</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/116/053/580/919/631/541/original/52a80664e05481b5.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">20:57 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116053997791467979" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在学校一个令我火大的是，许多人根本不会使用电梯。明明要下楼，却要按「上」。有些人干脆按了两个方向，让向上的满员电梯在一层停下，没有人出来也没有人进去，白白浪费开门和关门的时间。</p><p>还有便是在满员电梯还未完全关门前就频繁按上下按键，使得电梯又打开一次。</p><p></p></div></details><details data-group="diary_sections"><summary>二月十三日</summary><div class="diary-entry">05:36 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116061699573412254" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天突然无法 ssh vps 了，检查后才发现电脑的 IP 被自动封禁了……why！</p><p></p></div><hr><div class="diary-entry">05:39 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116061711870902669" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>喝了酒后，快速醒酒的方式是 —— 疯狂喝水排尿。</p><p></p><blockquote class="diary-thread-reply">05:42 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116061724035099528" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>喝太快现在胃好难受…… 喝酒时也是，切记不要喝太快。像红酒，慢慢品味才行（虽然我自己只能喝出酒精味儿），直接灌进胃里只会加快醉意。</p><p></p></blockquote></div><hr><div class="diary-entry">05:50 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116061753443612323" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>何时回复，何时引用呢？凡事都要看目的。如果内容是高强度依附于原串内容的话，例如补充信息或者说一些「如果不看原串的话就根本看不懂」的内容，这时候就应该「回复」。同理，不看原串也能看懂的内容，即重心放在表达自己的观点的时候，就使用「引用」。</p><p>引用也可以用来「挂人」：引用一个人的回复，说「这个人就是个傻瓜！」也是可以的。</p><p></p></div><hr><div class="diary-entry">06:00 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116061795479441151" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Mastodon 的 Favorite 跟其他社交媒体的 Like 功能有着许多不同。例如推特里，一个人 Like 他人的串，这件事会被推送到他的 Timeline 内。但是 Mastodon 里，关注者是无法在 Timeline 内看到被关注者 Favorite 了哪个串。再就是因为没有算法，Favorite 并不会增加原串的权重。这时候，「刷赞」便没有太大意义。</p><p>那么 Favorite 可以用来做什么呢？最重要的便是对作者的赞同。当没有什么好回复的，就使用 Favorite 来表达赞许吧。一部分人也会把它当作「已读回执」来使用。虽然回复一些文字更有活人味儿，但这样总比什么反应都没有更好些。</p><p></p></div><hr><div class="diary-entry">18:13 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116064677424420760" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天不好回家，在老板家里待了一晚上。早上出来，发现最近的地铁站居然要走二十分钟的路…… 睡过头了，现在还没有吃饭，遂在地铁站附近吃饭。</p><p>这是一家看上去像是连锁的米粉店。米粉套餐蛮便宜的，才 15 块钱 —— 可能是因为自己被曼哈顿的物价麻痹了内心，无法判断出「对」的价格吧，一碗面通常动不动就 20 多块钱。</p><p></p><blockquote class="diary-thread-reply">18:17 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116064690124871304" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>不对，这是一家过桥米线店，但是上菜方式不是传统的方式，而是直接将米线组装好端了上来。虽然是一件微不足道的小事，但还是会让我有点不开心。</p><p></p><blockquote class="diary-thread-reply">18:21 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116064706417676195" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>为什么南瓜饼的里面是紫薯？！😡 </p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">18:31 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116064745339223483" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚上做了个很长的梦。我梦到一个商场里，有一家肠粉店，叫什么「陈 XX 肠粉店」。它的装修布局很奇怪，一进门，能看到排满长队的前台，右侧是用餐区，最右侧则是一墙肠粉模型。模型不仅多，还很大，做工相当精良。</p><p>我走去查看模型，模型旁边还有店内的菜单。查看期间肠粉店的老板过来，忘记说了什么，总之是来找茬儿的。我忽然想起，这仿佛不是我第一次来到这家店、发现这家店的老板口碑很差。愤怒间，我和老板起了口角，她被我说得不敢还嘴，缩在了角落的一张椅子上，嘀嘀咕咕的，不知道在说什么。</p><p>结果我什么也没有买，去了商场的别的地方逛。突然，我进了一个貌似是虚拟体验游乐场一样的地方，背景黑秃秃的，只有一个个 Minecraft 里的方块。人也不再是「人」，而是长着大眼睛的小方块人，只有一个头。一共有红黄蓝三个阵营，大家要在这个黑色的大房间里互相厮杀…… 后面忘了。</p><p>后面我发现自己貌似是在深圳，虽然我从来都没有去过深圳。总感觉自己是出来给室友一家买早餐的，好奇怪。</p><p></p></div><hr><div class="diary-entry">19:04 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116064878097738326" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>数年前母亲交给我一部 iPhone。它的系统出现了问题，一开机就会进入 Recovery 模式，使用普通的恢复方式没有用。今年我想起了这部 iPhone，如果修好的话就可以当作备用机拍照了。但是刷机过程中发现数个问题，遂放弃……</p><p></p></div><hr><div class="diary-entry">19:35 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116065000124948236" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>初中还是高中的时候，对「扫雷」有些感兴趣，不过没有深入研究，只是知道了例如「121」这样的公式。今天在地铁上玩扫雷输了好多把，萌生了「如何聪明地玩扫雷」这样的想法，找到一篇八年前的说明文章：<a href="https://zhuanlan.zhihu.com/p/27439584。遂恍然大悟，原来是这样！" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="ellipsis">zhuanlan.zhihu.com/p/27439584。</span><span class="invisible">遂恍然大悟，原来是这样！</span></a></p><p></p></div><hr><div class="diary-entry">19:51 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116065061023820201" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>认识的一位去香港留学一年、变成「铁血香港人」的校友最近不再吹叶子，改抽香烟了。室友笑说这个人越来越像亚洲人了。我好奇问，为什么「抽香烟」是个亚洲人的事情？她解释道，因为美国人都吹叶子或者吸电子烟，吸香烟则是亚洲人的一个刻板印象。</p><p>哦…… 原来是这样。</p><p></p></div></details><details data-group="diary_sections"><summary>二月十四日</summary><div class="diary-entry">07:45 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/928313267593818897" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>咪咪猫和植物。</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/YpxWdHc8CyY4/RDXujMGiXeoEyXvNo3h7jzSP1oCbhuzwbqTVL22v.heic" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">14:17 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116069411763758853" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>为什么岗位申请需要上传成绩单。我上的 80% 的课都和这个岗位没有任何关系吧，有关的专业课还是我跟教授掐架的那个 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/245/original/aad7de836fc79371.png" alt=":ablobhammer:" loading="lazy"> 靠 GPA 筛选别人，怎么想都不是一个能找到好员工的方法吧。</p><p></p></div><hr><div class="diary-entry">22:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116071358511800408" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>又跑出来玩舞萌 DX 了 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/167/664/original/kawausosan_45989706.png" alt=":kawausosan_45989706:" loading="lazy"> 然而键盘底力因为越级而变得越来越糊，怎么会这样 ——</p><p></p></div></details><details data-group="diary_sections"><summary> 二月十五日</summary><div class="diary-entry">15:12 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116075287946989897" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>久违回父母家，感觉很糟糕。这个房子的中央空调很有问题，只有我的房间又热又闷，一楼则冷得要死，更不用说地下室了。前不久家里的水管都被零下的温度冻住，他们只能进一步调高空调的温度。现在刚醒，我便发现自己的嘴唇已经干裂……OH MY GOSH!</p><p></p></div><hr><div class="diary-entry">15:16 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116075304817544242" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>咪咪猫要比我上次回家的时候更亲人了。刚才坐在椅子上它会走过来趴在我的腿上要摸摸，不过它的声音还是很微弱，有时候不仔细听，真听不出来它在叫。</p><p></p></div><hr><div class="diary-entry">19:56 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116076407513994165" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>LinkedIn 会检查用户安装了哪些插件，来生成指纹，而检查用的插件列表里足足有近三千个插件。</p><p>见：<a href="https://github.com/mdp/linkedin-extension-fingerprinting" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="ellipsis">GitHub.com/mdp/linkedin-extens</span><span class="invisible">ion-fingerprinting</span></a></p><p>借此我考虑了一下 LinkedIn 现在对我的用途：找工作吧，真实的工作岗位没有如 Indeed 这样的平台多，活人也少得不行；当作公开的个人档案吧，我有自己的简历文件，也有自己的作品集网页，再不济我也能贴上 GitHub 的账户页面。</p><p></p></div><hr><div class="diary-entry">22:00 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116076894934917146" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>带三个小孩子出来看电影。影院所在的商场里有一家 UNIQLO，遂拿了本他们家的杂志看，参考一下穿搭。UNIQLO 的部分服装设计我还挺喜欢的，不过店内没有 XXS 码，不能直接买；线上买衣服这件事儿我总是会忘记。</p><p>因为今天早上才订票，已经没有好位置了，只能委屈这三个小的跟我一起坐前排，这也是我第一次坐前排看电影，需要躺下抬头才能看到荧幕中心。订票期间，我还买了爆米花和两杯饮料的套餐，实际成本和价格实在是两个极端。不过工作人员貌似会按时将这些东西送到我们的位置，稍微期待一下吧。</p><p></p></div></details><details data-group="diary_sections"><summary>二月十六日</summary><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 二月十五日 22:00</span>            </div>            <div class="diary-quote-preview">带三个小孩子出来看电影。影院所在的商场里有一家 UNIQLO，遂拿了本他们家的杂志看，参考一下穿搭。UNIQLO 的部分服装设计我还挺喜欢的，不过店内没有 XX…</div>          </div>00:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116077490440427485" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看了几分钟才发现我买的是 3D 票，我说怎么画面糊糊的好难受，转头一看发现其他人都戴了 3D 眼镜，赶紧跑去影院前台要了四副眼镜。小孩子们都没有戴眼镜，戴这种 3D 眼镜不会觉得不舒服；我已经戴了一副眼镜，再去戴 3D 眼镜就只能在眼镜上叠眼镜，难受死了。</p><p>室友和其他同事戴的都是隐形眼镜，我也尝试过一次，结果是眼皮子毫无争议地成为了我全身上下最强壮的肌肉 —— 根本打不开。</p><p></p></div><hr><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 二月十五日 22:00</span>            </div>            <div class="diary-quote-preview">带三个小孩子出来看电影。影院所在的商场里有一家 UNIQLO，遂拿了本他们家的杂志看，参考一下穿搭。UNIQLO 的部分服装设计我还挺喜欢的，不过店内没有 XX…</div>          </div>01:31 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116077722845114412" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>去影院之前，拿杂志之后，室友向我去了通电话。她近期结识了创价学会的人，并受邀去参加他们的活动、认识该学会。起初她觉得很有意思，还跟我分享该学会的理念，认为它和其他认识的宗教不一样。不过结合她的性子和我对宗教的了解，我认为如果让她继续相处下去，她绝对会对该宗教产生厌恶感。</p><p>她打这通电话给我，便是告诉我这件事。今天她去了一次更有宗教味道的活动，并要跟着信徒们念经。她很好奇，为什么要一直念经呢？信徒回答说，念经可以让人类的心灵变得强大。这一解释不仅没能说服她，反而激活了她的反骨 —— 这家伙就算在地铁上遇到强行推销素食主义的人，也会不停输出自己的观点，直到说服推销者。她认为，人类不需要念经也能够让心灵强大起来。会觉得念经才能填充自己的人，难道是无法相信人类的能力吗？</p><p>宗教一直都是一个复杂的话题，无法用一两句话来概括。只是我个人对宗教的印象，就算有正面的地方，但也是负面的偏多。真要去评价什么，我也只能说我并不喜欢宗教，且很确认室友继续了解下去、只会对宗教愈来愈厌恶。</p><p></p></div><hr><div class="diary-entry">03:33 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116078201793800185" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>虽然现在在 Emacs 里配置的 Org Mode 转 Markdown 逻辑可以用，但是久了还是会觉得有点怪怪的。如果原本就是写 Org Mode 的话，那博客框架直接读取 Org Mode 会更好些，也不用让文件转换来转换去、移动来移动去了。</p><p>因为这个，我还考虑了一下要不要将博客从 Hexo 迁移到 Hugo。既然要迁移，那肯定要做全套，完全融入到 Hugo 的生态中。不过现在我这个 Hexo 项目，其实和屎山没有太大区别 —— 写了很多脚本，其中有一些可以让 Emacs 完成，比如日记拉取嵌入功能。</p><p>但是简单调查了一番发现，Hugo 貌似并不算完全支持了 Org Mode？<code>ox-hugo</code> 包则依然将 Org Mode 转换成了 Markdown。再就是博客主题的迁移也需要一些工作。目前主题使用的是 Pug 语言，Hugo 主题应该不支持 Pug。</p><p>看来还是需要一些更深入的调查 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/147/926/original/f1ad416e0f1aae06.webp" alt=":blackcat_read:" loading="lazy"> </p><p></p></div><hr><div class="diary-entry">15:15 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116080964582267579" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>据说，微信要添加例如小红书和微博那样的，向公众展示最多九张图片的功能。</p><p>不要再让这个破软件变得更大了！</p><p></p></div><hr><div class="diary-entry">15:25 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116081002437235415" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>迷迷糊糊醒来，楼下传来父亲看春晚的声音，但他今年肯定也只是把春晚当背景音放。脑海慢慢回到刚来美国的那一年过节，我们挤在一个房间的角落，用 iPad 放春晚直播看。那时候我还是很乐意看春晚的，有几年过节我有课，一边用手机看春晚一边走路上学（莫要模仿好危险），回家后还会拿录播出来再看一遍。</p><p>从一个时间点开始，看不看春晚变得不再重要，当背景音放就好了。要是好奇的话，之后再看一些人上传的小品合集就好。</p><p></p><blockquote class="diary-thread-reply">15:42 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116081067438107126" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>失策了，我父亲根本不在楼下，那到底是谁在看……？客厅里只有条幸运狗啊。</p><p></p></blockquote></div><hr><div class="diary-entry">16:17 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116081205627331118" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>逐渐苏醒了前几年为什么不回家过节的记忆。</p><p>春晚放到军人那段时，母亲眼中流露着羡慕之情，严肃地告诉我和妹妹未来找男朋友一定要找当兵的：帅气、有气质、品行好。一位亲戚的儿子很皮，当爹的管不了他，送他去当了两年兵，回来时变成了亲戚们口中的模范孩子，乖巧得不行，连被子都叠得整整齐齐。</p><p>我不对军人有任何负面印象，只是觉得母亲这些话说给我俩听很奇怪 —— 妹妹也只有十岁大，就要管她未来找对象的事儿。理由也莫名其妙的，说是军人只要站在那儿，就没有人敢找我们茬儿。至于为什么要说给我，大概是因为表姐刚结婚怀了孕，我也临近毕业，想赶紧给我连条线。</p><p>我倒是觉得她只想给自己找个模范儿子，又或者说模范老公。父亲当年当兵不及格，条件在她看来也「拿不出手」。近期夫妻俩吵架，过节了也要互相生闷气，不肯跟对方说话，就连要不要吃面这个事儿，还需要让我当中间人、传递信息。</p><p>妹妹一边吃面一边问这问那，成功地吸引了母亲的注意力、将火力发射到了妹妹身上：「你最近是不是没有频繁弹钢琴？天天玩 iPad！」</p><p>「我不喜欢弹钢琴，我喜欢运动。」</p><p>「姐姐小时候想弹都没有钱弹！」</p><p>「我小时候没想弹。」</p><p>「她说她小时候没想弹！」</p><p>「你不弹钢琴你做什么！天天抱着 iPad 玩！你要跟着（教堂）师母学钢琴！」</p><p>「我是运动员，我不喜欢弹钢琴。」</p><p>「让她运动就够了啦。」</p><p>三人叽叽喳喳说话期间，父亲只是坐在旁边无言刷手机。</p><p></p></div></details><details data-group="diary_sections"><summary>二月十七日</summary><div class="diary-entry">04:02 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116083979462306877" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>一天夜里，受各类视频和博文影响，做出了一个大胆的决定 —— 集五十元巨资购买一台护眼仪。室友试过后说睡得很香，让我今晚试试。</p><p></p></div><hr><div class="diary-entry">19:32 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/929578397078118909" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Assassin Cat</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/WZxWuPYvVesf/898q5c8GQO8ZUI90ZQc9vr2QRyJDHpB8eLaSdsjQ.jpg" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary> 二月十八日</summary><div class="diary-entry"><div class="diary-quote-external">            <a class="diary-quote-link" href="https://go5.dev/@cee/116090195714048662" target="_blank" rel="noopener noreferrer">显示引用原文 ↗</a>          </div>15:23 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116092320023448805" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在国外和同样身处国外的人之间通讯，就不要继续使用国内的软件了，尤其是微信这类会涉及到私密讯息的应用。过去母亲就被询问过，「你认为中国迫害信教的人，为什么还要将宗教活动的照片上传到微信朋友圈？」</p><p>至于 HungryPanda，也不是什么好东西，且很大可能主动介入了此事。因为如果骑手们真的是因为微信的信息审查而被找上门，但讯息内容仅是海外资薪纠纷，根本动不着让这么多、不同地区的警方找上他们。能做到这种规模的，通常是被调查人涉及到了像法轮功这类敏感的政治问题。要知道，过去没少发生过中国公民在海外作为工人罢工抗议的事件，能做到悉尼这次这样的，相当罕见。</p><p></p></div></details><details data-group="diary_sections"><summary>二月十九日</summary><div class="diary-entry">08:14 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116096294035395256" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>公司也是做大了，终于遇到了第一个会通过邮件发千字小作文传递「我都是为了你好」的刻板印象白男客户。</p><p></p></div></details><details data-group="diary_sections"><summary>二月二十日</summary><div class="diary-entry">00:35 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116100151295955013" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>很奇怪的零食…… 咬下去之前没有想到它的皮是这种口感……</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/116/100/150/633/189/148/original/0e2dffe5317c2480.jpg" alt="一只手握着一个方形包装的日式点心。包装纸呈现淡黄色，质感类似和纸，上面印有醒目的黑色书法字体「饼入り」（含年糕）以及红色方框内的白色文字「最中」（Monaka，一种夹心糯米皮点心）。包装左侧绘有一只可爱的白色兔子卡通形象，兔子正提着一只灯笼。背景中可以看到一个白色的圆形台灯底座以及其他未拆封的同款点心包装。" loading="lazy"></figure></div><hr><div class="diary-entry">00:56 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116100232815270219" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>同事问我，我在大学里会不会主动和人交朋友。我回不会。大一那段「主动社交」的时间里，我被一堆校友搞得心态爆炸，不再想主动从大学内交朋友了。</p><p>她告诉我，她也尝试了一下主动找人聊天，不过发现有许多校友说话时不会看向对方的眼睛，让她觉得不够尊重人。我说对方或许是很内向的人呢。虽然眼神交流是社交直觉的一部分，能理解同事付出热情但没有得到期待的回馈，但也可以理解内向者们为什么这么做。</p><p></p></div><hr><div class="diary-entry">01:57 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116100475973797850" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>中文课上需要阅读一些早年政府讲话的稿件，给我的感觉是，每个字都认识，但是组合在一起看不懂…… 同朋友抱怨了这件事。本来怀疑是因为我和中国政府严重脱节所以看不明白，结果他安慰我说没关系，就算学习过政治，再去看也看不明白。</p><p></p></div><hr><div class="diary-entry">02:08 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116100517386110186" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>去年暑假被锁匠坑了百来块钱。昨天看了一个撬锁入门的视频，产生了一丝兴趣。不过上网搜了一下，发现透明锁的价格比想象中贵一些。</p><p></p></div><hr><div class="diary-entry">04:07 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116100984879237139" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>朋友在吐槽另一个朋友，总是找些「神奇宝贝」处对象，说不定是 Furry 控吧。</p><p>紧接着，他意识到什么，说我天天遇到「神奇宝贝」还能绷得住，是因为我是一个 Furry 控 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/080/746/original/9a931a99b2ca6f56.png" alt=":luxun:" loading="lazy"> </p><p></p></div><hr><div class="diary-entry">04:11 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116101001710887993" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>创建了一个 Matrix 账户 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/167/664/original/kawausosan_45989706.png" alt=":kawausosan_45989706:" loading="lazy"> 不过，先前我只用 Telegram 来创建机器人，并没有认真钻研过这类应用如何使用。</p><p></p></div><hr><div class="diary-entry">17:47 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116104209582549239" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>很需要一个可以跨平台使用的收据管理应用。过去使用的是 Easy Expense，但是它只有移动端 App，功能也很臃肿（为什么有报税功能），使用电脑查购物的数据不方便。不过它扫描收据、自动填写数据的功能很好用。</p><p></p></div><hr><div class="diary-entry">18:23 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116104352304709848" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>春节期间一位叔叔送了我双新鞋，也是将穿了几年的旧鞋子淘汰掉。因为脚有问题，我穿过的鞋子都会变形。比如有一年，一位亲戚送了双板鞋，为了表达感激之情，和她出门时特意穿了这双板鞋，结果半小时不到，这双板鞋就变了形、歪歪扭扭的，之后拿去退款时店员也不知道还能不能退。而我的脚也因为多处擦伤，流了很多血，痛了好几天。</p><p>这注定了我的脚只能穿运动鞋，且最好穿利于扁平足的鞋子。虽然我每过几年就会去定制鞋垫，支撑起最重要的足弓，不过鞋子也需要认真挑选：太软，足跟可能会歪斜，长期走不安全；太硬，就会变成上述的例子，同时伤害到我和鞋子。</p><p>一个麻烦的事情是，因为我只能穿运动鞋，到一些正式的场合就会看起来很奇怪。我又是个为了舒适性，可以牺牲掉「体面」的人，正式场合想让我穿高跟鞋或者说任何有跟的鞋，都是不可能的！</p><p></p></div></details><details data-group="diary_sections"><summary>二月二十一日</summary><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 二月十七日 04:02</span>            </div>            <div class="diary-quote-preview">一天夜里，受各类视频和博文影响，做出了一个大胆的决定 —— 集五十元巨资购买一台护眼仪。室友试过后说睡得很香，让我今晚试试。</div>          </div>04:34 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116106753376027688" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这些天，每天都在用护眼仪。加热功能很舒服，睡前用一下不知不觉就睡着了…… 不过我暂时保留按摩功能的评价，总感觉没啥实质性的作用。</p><p>佩戴期间会开始想 VR 的事情。一位朋友平日就会使用 VR，让我很想要试一试。AR 也想试试看，但都需要钱。</p><p></p></div><hr><div class="diary-entry">04:49 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116106814483652518" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>家附近的超市里没有绵羊肉，只有山羊肉，不过都是羊肉，都是一样的好吃。就是有点贵，一板山羊肉 10 来块钱，多重不记得了，不过只够我吃两餐。</p><p></p></div></details><details data-group="diary_sections"><summary>二月二十二日</summary><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 二月二十一日 04:49</span>            </div>            <div class="diary-quote-preview">家附近的超市里没有绵羊肉，只有山羊肉，不过都是羊肉，都是一样的好吃。就是有点贵，一板山羊肉 10 来块钱，多重不记得了，不过只够我吃两餐。</div>          </div>02:27 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116111916384712630" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>怎么咬都咬不下来骨头上的肉，放弃后突然想起，是不是肉没熟导致的 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/019/313/original/1679206d77bf4d95.png" alt=":bear_fright:" loading="lazy"> </p><p></p></div><hr><div class="diary-entry">17:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116115473738488082" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友购买了一台小型的跑步机，昨晚一起调整了下房间的布局。她有很多乐器，但是现在没有时间弹奏，我也没有长期学习乐器的精力，只能将它们塞进床底……</p><p>昨天学校和各大平台也表示今天会下很大的雪，周日和周一的课都被改为在线上进行。不过现在醒来一看，还没有开始下雪。</p><p></p><blockquote class="diary-thread-reply">18:59 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116115819577948911" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>现在开始下大雪了…… 上次的积雪还没化开、堵在路口呢。这就是为什么我讨厌雪…… <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/372/original/155bf96cb3d47a6e.png" alt=":blobcatangery:" loading="lazy"> </p><p></p><blockquote class="diary-thread-reply">02-23 05:40 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116118339621161906" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚上手机发出警报声，原来是城市实施了出行禁令。我上次看到出行禁令，也是因为大雪，不过那是差不多十年前的事情了。那天，我一个人在街道上跑来跑去，还有闲心拍照。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">18:56 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116115807434890521" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在笔记本电脑上也安装了 Golden Dict，可以开心查阅词典了。</p><p>初中时做过一件可能很蠢的事情，那就是抄词典…… 不过不得不提，我那本词典用起来很舒服，应该是牛津英汉词典，具体名字和版本不记得了，总之矮矮胖胖的，中间还有生活中常见的词汇大全，例如蔬菜都叫什么（不过我没有认真读过，之后还买错了 cilantro 和 parsley……）。</p><p></p></div><hr><div class="diary-entry">22:42 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116116694185338696" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>突然想到，几周前诊所打电话叫我去复诊…… 我给忘记了，一直没去。不过说是复诊，也只是重新查胆固醇和幽门螺旋杆菌。胆固醇不知道为什么，一直降不下去，我也没那么爱吃油炸食品吧。得幽门螺旋杆菌是个很意外的事情，因为和我同吃同住的室友没有这东西，我平日也不爱吃生鲜。</p><p></p></div><hr><div class="diary-entry">22:46 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116116711697696483" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>做了半年的工作，辞职不做了 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/444/original/8b96f93c59ad5a46.png" alt=":blobcatphones:" loading="lazy"> 压力容易大……</p><p></p></div><hr><div class="diary-entry">23:35 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116116902174461288" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>捣鼓了一下 Fluent-Reader-Lite。这个 App 虽然上次更新都是几年前的了，但用起来很是很舒服。我这次主要是添加了一下自己想要的功能 —— 开源就是好啊。</p><p></p><blockquote class="diary-thread-reply">02-26 14:40 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116137448824962177" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>其实只添加了打开文章时可以指定用哪种方式打开功能。这样就不用手动切换到「用内部浏览器打开」，方便一点点。</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>二月二十三日</summary><div class="diary-entry">00:31 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116117121789381384" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>虽然我会使用钢笔，但是很难解释为什么自己会使用它，而非其他文具。毕竟这东西和圆珠笔相比较，可是难用得很，比方说现在我就因为它笔头干燥，不得不拿去卫生间清洗。</p><p>选择纸也是个难题。我本来想要去 MUJI 买一堆便宜的回收纸回来，但是想到那种纸薄得很，用钢笔写字的话恐怕只能写一面吧。</p><p>说到纸，又想到前不久上中文课时，教授要求我们拿出纸笔写作文，而很多学生包括我都不带纸…… 只能惭愧找他人借。我能想到的最好的选择是活页本，想怎么撕怎么撕。但是活页本又很大个儿，难道要一个包里又装笔记本电脑又装活页本么？</p><p></p><blockquote class="diary-thread-reply">01:04 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116117254900049247" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>刚说完，拿去清洗，吸墨器掉到水管里了 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/019/055/original/2421e8d631ebf3b8.png" alt=":ablobcry:" loading="lazy"> <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/019/055/original/2421e8d631ebf3b8.png" alt=":ablobcry:" loading="lazy"> </p><p></p></blockquote></div><hr><div class="diary-entry">19:52 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116121690364243555" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>一位朋友近期一直在考虑未来的事情，只是他考虑的是一事无成的自己毕业后怎么办。我是个邪恶的人，并不同情他，但也觉得这样的自己很糟糕。他既不想努力学习一门手艺或者技术，又想毕业后离开家人、过上每个月只用打钱而不用交流的生活，这些想法毋庸置疑是相互矛盾的。</p><p>他也想过本科毕业后读研来逃避现实，让我匪夷所思：读研结束后你不也一样需要考虑这些问题吗？且读研的钱依然是父母给的，只会拉高父母未来投射给你的期待，再加上他现在甚至还会担忧拿不到本科文凭（虽然我觉得可能性不大）。</p><p>现在的社会饿是肯定饿不死的，何况他未来没有组建家庭、生孩子的打算，所以不用考虑什么车贷房贷，也不会进行吹叶子、赌博这样的不良嗜好。他的焦虑很大程度来源于父母：父母想要他成为家里的顶梁柱，未来扶持弟弟，还要帮助已经变成赌鬼的父亲 —— 这也是父母的严重失职。</p><p>我作为朋友，也没有什么可以帮得上忙的。只能像过去的几年那样，给出一些建议。</p><p></p></div></details><details data-group="diary_sections"><summary>二月二十四日</summary><div class="diary-entry">06:52 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116124283484020795" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>之前写了个 cytrogen.icu / death，给室友看，她说这没有法律效力，然后她也不想当受益人和代理人，会给自己多加一份收入，说不定还要多报一份税 —— 真是个没有浪漫细胞的家伙儿！</p><p>不过如果想要有法律效力的话，很多书面文件要准备好。比方说遗体想要给谁处置、资产归给谁等等。听完室友喋喋不休的税法科普，我还要关心死后的税怎么报……</p><p></p></div><hr><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 二月二十二日 17:32</span>            </div>            <div class="diary-quote-preview">室友购买了一台小型的跑步机，昨晚一起调整了下房间的布局。她有很多乐器，但是现在没有时间弹奏，我也没有长期学习乐器的精力，只能将它们塞进床底…… 昨天学校和各大平台…</div>          </div>22:27 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116127958953129138" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友强迫我每天跑二十分钟，不然我死得会很早。如果我死得很早的话，她会把我的遗产都丢掉，并且把我平日吐槽别人的言论一字字念给当事人。</p><p>在跑步机的前面，她架了个全身镜，我也在这二十来年的人生中，第一次正面看到跑步的自己 —— 歪歪扭扭的，尤其是腿部。好吧，这是我初次如此直观地看到扁平足对一个人的身体的影响。骨盆很大，但是四肢都很纤细，整个人像是个插了四根牙签的橡皮人。</p><p>再就是自己粗壮的，如果拼给认识的男生还会增加他们男性气概的脖子。先前朋友们都怀疑我是不是甲状腺有问题，但是问过医生、都说没什么问题……</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">一点点和政治相关；带脏话。</summary>        <div class="diary-cw-content">22:45 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116128030627226920" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>突然想到大一的时候，一个校友主动跟我谈论起了政治，或许因为我是一个中国人吧。他表示自己这辈子都不会去中国，因为中国很危险，而美国更自由和安全。</p><p>其实两者真要去对比，都是一丘之貉，顶多算五十步笑一百步。想要获得数字主权，逃离美国也是必要的。想必他在说这些话的时候，根本不知道他常用的软件都在背地做什么肮脏的事情吧。</p><p>至于安全，妈的，我今早刚睡醒发现家附近有人被枪杀了。是我自己不想出门吗。</p><p></p></div>      </details></div></details><details data-group="diary_sections"><summary>二月二十五日</summary><div class="diary-entry">00:39 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116128479298301509" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>写作业期间，笔记本电脑突然卡死。重启后查看了一下 <code>journalctl</code>，发现是内核 OOM killer 连续斩了数个进程于话下，其中包含了一个 QtWebEngineProc 进程，用了足足 1.4TB 的虚拟内存……！</p><p>你是谁！</p><p></p><blockquote class="diary-thread-reply">00:47 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116128509254285658" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>破案了是 GoldenDict-ng 😡 泄漏内存这事儿就不能修复吗。</p><p></p></blockquote></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">敏感内容</summary>        <div class="diary-cw-content">01:41 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116128724438074787" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>无聊画了点 Kagi 的吉祥物。这个画师真想找出来…… 太可爱了。想要仿照画风，不过画得一般。之后融合了一些自己的画风，总觉得有点猥琐。</p><p></p><figure class="diary-media diary-media-sensitive"><img src="https://media.otter.homes/media_attachments/files/116/128/715/589/989/917/original/478678fbb9b6fd11.jpg" alt="一张涂鸦，上面画了 Kagi 公司的吉祥物：一条狗。" loading="lazy"></figure></div>      </details></div><hr><div class="diary-entry">17:44 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116132510779757954" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚上搞到凌晨三四点才睡觉。一躺下就梦到一位朋友找到了我的博客网站，并开始批量搜索她的名字。我吓得要死，因为我没少吐槽过她。</p><p></p></div><hr><div class="diary-entry">20:59 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116133278446252877" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>学校网络连不上啊 ——！之前用安卓手机连接，连半天连不上，交给学校的工作人员捣鼓，也是捣鼓半天才弄好。现在笔记本电脑只能连手机热点了。</p><p></p></div><hr><div class="diary-entry">22:16 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/932518814698955267" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Feels like a part of this world is starting to glitch.</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/J7yTczLcCWCK/kXWoLQPahT4mZ0XxZAFZC1LdetqU1KUezsCMsARR.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">22:17 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/932519059482939908" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>雪人。</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/NENc7tykaEbJ/muMqmz4SRhZh5y839REdgTCXhljJ5Wx4Ht5bz2N6.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/RxqLbSAJ4qET/Md5U64V0TIM1JPnabfwpd5YiIxz5hpxSMKIsRyUj.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">22:18 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/932519304280379912" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>咪咪猫。</p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/UO0qpfJwggJ7/NmHZAUZzti4MgkYgoRu0pttxgCfFC36g9jZlEgTI.heic" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/3OcMur9jwNlH/ocCjuAhQyixsxScEDoq9v30fix37Ql3QZ8mCxx70.heic" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/9eMcGobWNy8p/UyusDmOPy1yWLIaLalhjjscTyIU200hVFmOxCD9T.heic" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">23:53 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116133961108818040" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>突然发现 blogblog.club 被我校的网络封锁了访问 —— 为啥呢。</p><p></p></div></details><details data-group="diary_sections"><summary>二月二十六日</summary><div class="diary-entry">05:58 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116135396896254831" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>夜晚听一些 Vocaloid 歌曲，不得不感叹 Teto SV 的性能真是强到没边。</p><p></p></div><hr><div class="diary-entry">14:58 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116137520191235498" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有些博客网站采取的是「无法验证身份」的评论系统，即只需要填写电子邮箱或者博客地址就可以回应的评论系统。该评论系统的一大问题在于，很容易就会被人冒充。</p><p>除了要求对方换个评论系统这种斩草除根的方案外，还有什么方案可以避免被其他人冒充身份呢？</p><p></p></div><hr><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 二月二十二日 22:46</span>            </div>            <div class="diary-quote-preview">做了半年的工作，辞职不做了 压力容易大……</div>          </div>20:35 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116138845302134082" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我换了个新的兼职，这些是我的感想：</p><ul><li>这家店用的 POS 系统，好老、好没用！算零钱还不如心算来得快。</li><li>员工餐是店里会卖的东西，真好，终于不是师傅们做的大锅饭了……</li><li> 因为人手会多，所以不会像之前那家店那样，一个人顶着所有顾客的压力。心酸。</li></ul><p></p></div><hr><div class="diary-entry">22:15 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116139239565412446" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨晚想要升级一下 VPS 的内存来着，但是 IONOS 展示的付款界面让我感觉很怕啊，要让我全款支付想要升级到的套餐似的。</p><p>姑且先加大了 SWAP 容量。</p><p></p></div></details><details data-group="diary_sections"><summary>二月二十七日</summary><div class="diary-entry">02:50 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116140319299624642" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这种小本子为什么会配这种笔…… 好土，感觉我是什么土皇帝，写土日记。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/116/140/316/885/770/486/original/188e16b49c275fe4.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">03:22 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116140443229512701" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>你这样会显得我很蠢 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/008/original/424361453b49ed14.webp" alt=":gblackcat_shake:" loading="lazy"> </p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/116/140/441/513/998/532/original/0c2e1879586927e3.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">04:28 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116140702860181491" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Uniqlo 有两款裤子，Smart Ankle Pants 以及 Smart Wide Pants。前者是九分裤，刚好会露出脚踝，因此显得很利落；后者采用的是直筒宽腿设计，从大腿到裤脚一直保持着较宽的围度，长度也要比前者长、落在鞋面。</p><p>Smart Wide Pants 的一个优点是，可以掩盖腿型问题。我的腿就有问题，可以穿这款。</p><p></p></div><hr><div class="diary-entry">22:45 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116145016941443189" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>晚上思考了一下个人网络该如何设计才好。因为托管了博客胶囊，设计风格上也贴近极简的博客网站就显得重复。要大改博客网站的设计么，也觉得没有必要，毕竟本身就是文字的载体。但是脑子里总想要一些更 Web 的东西 ——CSS 啊、JavaScript 啊！最终得出的结论是，我可以写个个人主页，把博客网站挤到 blog 子域名去。</p><p>现在访问 cytrogen.icu 会被 301 重定向至 blog.cytrogen.icu。至于个人主页会是什么样子，目前还在策划中…… 其实就是美术素材不想画。</p><p>分享一个我觉得很不错的个人网络，算是灵感来源：</p><ul><li>ellesho.me</li><li>elle.sh（需要使用 <code>curl</code>）</li></ul><p></p></div></details><details data-group="diary_sections"><summary>二月二十八日</summary><div class="diary-entry">03:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116146145130495617" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><a href="https://drawafish.com/" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://</span><span class="">drawafish.com/</span><span class="invisible"></span></a></p><p>画鱼玩。我画了后光速得到 11 个踩，怎么会 ——</p><p></p></div><hr><div class="diary-entry">07:53 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/933388694997926252" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>咪咪猫，重新发一次。这次是 JPG 格式的，应该可以看到。</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/UiylYpklOEif/IpKFW7he9IZx2qYzvm6rbVOXEq18J3mGvBrCJs7j.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/z1QpuziXA3q2/4itQ9wo9yaePLyHu76NksMnMbOfusGgprrU6XKIz.jpg" alt="" loading="lazy"></figure><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/wtPNDz3Qw7Uc/3UmsBuzJ0qNfV230LZZSYIyeb6rIUWtutrmHj6bE.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">10:47 <a class="diary-source-link" href="https://pixelfed.feddit.social/p/Cytrogen/933432386855870991" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>chill……</p><p></p><figure class="diary-media"><img src="https://files.pixelfed.feddit.social/public/m/_v2/923960293389291627/fbedcc803-0ec729/pYS4PVK5U07V/RDEs4B9GVmTTDgtbtBq28um8XeukSuCy1JlEq9Ja.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 二月二十六日 20:35</span>            </div>            <div class="diary-quote-preview">RE: https://m.otter.homes/@Cytrogen/116116711697696483 我换了个新的兼职，这些是我的感想：这家店用的 POS…</div>          </div>18:40 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116149718270374778" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>万万没想到，老板又让我去了另一家店学习。这家店同时做堂食和酒吧（和不知道为什么存在的越南咖啡），意味着要学习的东西变多了。</p><p>师傅去隔壁，也就是我引用的这家店里，拿了个越南面包给我吃。他说不是特别正宗啦，但是很香，面包味道和口感让我想起 Baguette，就是没有特别硬和长。里面夹着萝卜丝、生菜、煎牛肉和火腿，还可以，挑食的我也会吃。</p><p></p><blockquote class="diary-thread-reply">20:23 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116150121757862637" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>要学很多东西，就比方说酒。我自己根本不知道 gin、vodka 有什么区别，因为我不怎么喝酒，cognac 又是什么，啤酒怎么还分等级，不同品牌的酒也是各不相同，明明里面装的都是同类东西！</p><p>服务顾客也是一个学问，归根结底就是为了一个东西 —— 小费。但是我痛恨小费文化……</p><p></p></blockquote></div><hr><div class="diary-entry">20:51 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/116150231624377683" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>记录学习到的酒知识，虽然我很讨厌酒……</p><p>先说琴酒（Gin），是一种起源于荷兰的蒸馏酒（liquor）。</p><p>荷兰琴酒（Dutch Gin）的话，口味很甜，适合直接加冰喝。不过根据师傅所说，现在更流行伦敦干琴酒（London Dry Gin）。「干」在这里的意思是不甜，貌似也可以指涩口，我不喝我就不尝尝看了。实践精神 GONE——</p><p>店里摆放着的琴酒（应该都是伦敦干琴酒）大致可以分成三个牌子：Tanqueray、Bombay 和 Hendrick's。师傅说前两个在品牌酒里算平价酒，最后这个会贵。</p><p>说到琴酒，总会想起某个也很有名的「琴酒」呢……</p><p></p></div></details></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;这个月我忙于一些现实中的事情，结果连月刊和自己一个月里都做了什么，全都忘了个干净……&lt;/p&gt;
&lt;p&gt;我希望这会是你能看到的，最后一个条目如此之少的月刊。&lt;/p&gt;</summary>
    
    
    
    <category term="想法迭代" scheme="https://blog.cytrogen.icu/categories/%E6%83%B3%E6%B3%95%E8%BF%AD%E4%BB%A3/"/>
    
    
  </entry>
  
  <entry>
    <title>我的胶囊旅馆开张了</title>
    <link href="https://blog.cytrogen.icu/posts/d823.html"/>
    <id>https://blog.cytrogen.icu/posts/d823.html</id>
    <published>2026-02-25T05:00:00.000Z</published>
    <updated>2026-02-26T04:44:36.523Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>此胶囊旅馆非彼胶囊旅馆。虽说我对现实中的胶囊旅馆很感兴趣，但至今都没有睡过一次，去开张一家真正的胶囊旅馆更是无稽之谈。标题中的「胶囊旅馆」指的是通过 Gemini 协议提供内容的独立信息集合。</p><span id="more"></span><p>想必有些读者看到 Gemini，第一时间想到的是同名的，由谷歌开发的多模态大型语言模型，亦或者是同由谷歌开发的生成式 AI 聊天机器人了吧。实则不然，本篇文章所说的 <em> Gemini</em> 指的都是 <u>Gemini 协议</u>，一个轻量级的互联网应用层通信协议。</p><p>一个常见的误解是，将「互联网」和「万维网」混为一谈。很多人认为，浏览器就是互联网，或者说互联网只有 HTTPS。这些都是认知盲区，但也怪不了谁。现代万维网极度繁荣，承载了普通用户所有的线上活动，但也掩盖了底层网络架构的多样性。</p><p>互联网是由全球无数计算机网络相互连接而成的庞大基础设施，它的核心职责是数据的路由和传输，其基石是 TCP / IP 协议族。</p><p>在计算机网络的体系结构中，网络通信被严密地划分为不同的层级。从下往上分别是「链接层」、「网络层」、「传输层」、「应用层」。</p><p>底层协议负责处理物理信号、IP 寻址和数据包在路由器之间的接力，而最顶层的应用层协议定义了运行在不同设备上的应用程序如何相互传递报文、直接决定了数据在终端用户面前的呈现和交互方式。</p><p>为了让同一台服务器能够同时处理多种不同的网络服务，传输层引入了「端口」的概念。当我们在浏览器中输入 <code>https://</code> 时，实际上要求了操作系统使用超文本传输协议安全版（HTTP over TLS，也就是 HTTPS），去连接目标服务器的 443 端口。</p><p>HTTP 协议最初仅仅是为了在研究人员之间共享简单的学术超文本文档而设计的。但随着数十年的发展，为了满足复杂的现代 Web 应用程序的需求，它被不断追加了 Cookie 会话管理、CORS、Service Worker 等庞杂的机制，最终造就了今天功能强大但也极其臃肿的 Web 生态。</p><p>不过应用层是一个相当宽广的领域，HTTP 仅仅是其中的一个居民。互联网上时刻运行着大量与 HTTP 平级的应用层协议，它们各自服务于高度专一的通信需求。例如：构建全球电子邮件系统的核心是 SMTP 和 IMAP / POP3 协议；远程管理 Linux 服务器时，系统管理员会依赖运行在 22 端口的 SSH 协议；服务器之间进行时间同步，依赖于 NTP 协议。这些协议支撑着互联网的底层运转，却鲜为人知，很大缘故是它们通常在后台静默工作，或者需要特定的客户端而非通用浏览器来访问。</p><p>今天的主角 Gemini 协议也是与 HTTP 完全平行的应用层协议。它拥有着自己专属的通信规则、状态码体系和数据格式，并且默认运行在 TCP 1965 端口（纪念 1965 年的「双子星号」载人航天任务）。</p><p>在深入 Gemini 的技术基层之前，有必要了解它的精神前身：<u>Gopher 协议</u>。</p><p>在万维网尚未一统天下的二十世纪，Gopher 是互联网上最流行的信息检索系统。它采用严格的层级菜单结构来组织纯文本信息：</p><pre><code class="language-text">Welcome to Gopherspace  1. About this server.  2. Articles and Musings/  3. Links to other Gopher holes/  4. Search this server &lt;?&gt;  5. A plain text document.Press ? for Help, q to Quit, u to go up a menu, or enter a number: _</code></pre><p>大概就是这样吧，是不是看着很像早些年的文字游戏呢？</p><p>其实我最初学习编程语言，写的第一个项目就是一个类似于这样的文字冒险游戏 —— 可惜源代码被我删除了，之后考虑使用 Python 重构却没有写下去。</p><p>Gopher 的客户端界面之所以是这么个列表形态，是因为服务端返回的原始数据本身就是一种以制表符分割的结构化纯文本。每一行代表菜单中的一项，行首的单个字符定义了该项的资源类型。</p><p>然而随着带有图形界面、支持内嵌图像和复杂排版的早期 Web 浏览器的出现，加之 Gopher 的发源地明尼苏达大学曾短暂尝试其服务端软件收取许可费，Gopher 迅速走向了衰落。</p><p>Gemini 正是诞生于对现代 Web 日益臃肿和商业化，以及对 Gopher 历史教训的深度反思之中。其核心设计理念被概括为「比 Gopher 重，比 HTTP 轻」。很聪明地，它并不打算取代现有的 Web，而是想要构建一个被称为 <em> Geminispace</em> 的独立、纯粹的文本网络生态。对于偏好纯文本与自托管服务的极客们而言，Gemini 是个相当具备吸引力的信息分发与获取方案。</p><p>与 HTTP 不同的是，Gemini 强制要求使用 TLS 加密连接，不允许任何明文传输，确保了基础的通信安全。同时它在实践中广泛接受 TOFU（Trust on First Use，首次信任）模式或自签发证书，大幅降低了个人站长维护基础设施的门槛。</p><p>其请求和响应模型被设计为一次性的单向事务，连接在响应完成后立即关闭。服务端的响应头部极简，仅包含一个两位数的状态码、一个空格、一段元数据（在请求成功时通常是 MIME 类型，如 <code>text/gemini</code>），从根本上抛弃了 HTTP 中复杂的头部字段。</p><p>更为彻底的是，Gemini 规范中没有 Cookie，没有 User-Agent 嗅探，不支持任何形式的客户端脚本执行。如果服务端应用需要维持会话状态或进行身份验证，协议规定直接使用 TLS 客户端证书来实现。这意味着在体系结构上，任何人都无法在 Gemini 页面中嵌入追踪探针、广告代码或第三方分析工具。</p><p>与该协议深度绑定的是一种名为 Gemtext 的专属轻量级标记语言（文件后缀通常为 <code>.gmi</code>）。Gemtext 的语法相较于 Markdown，仅支持三级标题、无序列表、引用块、预格式化文本以及链接。</p><p>三级标题对我而言，不是什么大问题，因为我现在使用的主题的原作者 <a href="https://github.com/WhoKnowInfinity">Infinity</a> 这么认为：</p><blockquote><p>实际上，Hexo-theme-apollo 只支持两种标题：<code>h1~h3</code> 大标题，<code>h4~h6</code> 小标题，也就是说，<code># 和 ###</code> 的样式是一样的。之所以这么处理，是因为就个人感觉而言，我们不应该为文章设置过多的层级消耗读者的阅读精力。这相当于强制使用 Hexo-theme-apollo 的用户在写文章时注意文章结构，最多只能使用两层结构。</p></blockquote><p>不过我印象里，这个「两种标题」并不准确，实际上是三种标题：<code>h1</code> 一个，<code>h2~h3</code> 一个，<code>h4~h6</code> 一个才对。我并不记得我特意修改了这一点，也有可能是我记错了。总之，我在写博客的时候就已经慢慢培养出来了不滥用标题层级的习惯。</p><p>特殊的是，Gemtext 还严格禁止在段落文本中内嵌链接，所有超链接必须作为独立的代码行存在。</p><p>我个人算是半个脚注的反对者。脚注在实体书籍上出现没问题，但展示在互联网的文章上，阅读起来相当难受。如果可以的话，我会希望文章都尽量是从头到尾、瀑布般的排版，不需要让读者去别的地方才能收获完整的阅读体验。不过为了漂亮，我还是会在文本内嵌入链接，给它们附加文本。这个做法我会深思熟虑一下，是否应当完全参照 Gemini 协议希望的那样。</p><p>先前说过，Capsule 是通过 Gemini 协议提供内容的独立信息集合。它的概念完全等同于万维网中的 Website。正如一个 Website 是由多个通过 HTTP 协议传输的 HTML 页面和资源组成，一个 Capsule 则是通过 Gemini 协议传输的 Gemtext 文件及其他媒体文件的集合。</p><p>虽然它的命名出处来自于阿波罗计划中的「双子星号」太空舱，但结合我给个人网络附加的设定，最终将我自己的 Capsule 其称为「胶囊旅馆」。莫要搞混了，它的意思是太空舱，而不是我二次创作出来的胶囊旅馆！</p><p>因为 Capsule 等同于 Website，所以通过 Gemini 客户端访问他人搭建的服务器时，最好不要称其为「Gemini 站点」，而是说「Gemini 胶囊」会更好些。因为「站」这个概念属于 HTTP 协议，胶囊严格来说也不属于「网站」—— 网站是依附于万维网生态、基于 HTTP / HTTPS 协议和 HTML 标记语言构建的产物。</p><h3 id="访问-gemini-地址"><a class="markdownIt-Anchor" href="#访问-gemini-地址"></a> 访问 Gemini 地址</h3><p>由于 Gemini 协议从根本上切断了与 HTTP 的联系，常规的现代 Web 浏览器是无法撬开这些太空舱的。我们需要借助专门支持 Gemini 协议的客户端工具。</p><p>在终端环境中，Amfora 是一款功能完备的命令行客户端。如果依然偏好图形界面的便捷性，Lagrange 则是目前生态中非常优秀的桌面端选择。</p><p>如果你要问我，我选了哪个的话。莫要忘了，我是一个 <em> typical Emacs user</em>（经典 Emacs 用户）—— 其实只要使用 Elpher 包就可以访问 Gemini 胶囊啦，太方便了！</p><pre><code class="language-plaintext">M-x package-install RET elpher RET</code></pre><p>接着你可以在 Elpher 界面上，使用 <code>g</code> 命令，然后输入我的胶囊旅馆地址 <code>gemini://cytrogen.icu</code> 便可以访问了。</p><h3 id="博文生成和部署"><a class="markdownIt-Anchor" href="#博文生成和部署"></a> 博文生成和部署</h3><p>我的写作流程因为相当私人化，所以仅供参考了。</p><p>Org Mode 文件是所有文章的上游。写好 Org Mode 文件，我会转换它为 Markdown 和 Gemtext 文件。这里只说 Gemtext 的转换：我引用的是 <code>ox-gemini</code> 这个导出后端，不过我有很多额外的定制化需求，因此进行了一些魔改。比方说在我的月刊内，有个「日记片段」板块，那里理论上来说是 Hexo 框架在构建文件时，自动从 Fediverse 应用上获取数据、嵌入 HTML 文件内。这意味着 Org Mode 文件里没有这些日记内容，转换成的 Gemtext 文件也不会有。但我目前并不希望 Gemtext 文件在构建时进行过多的操作，导致流程愈来愈复杂，最终决定只放一个 Mastodon 主页链接。</p><p>接着我会将 Gemini 项目 <code>git push</code> 到 VPS 的 bare repo，并触发它的构建命令。说是构建命令，其实也就是帮我部署到 Gemini 服务器，然后镜像到 Sourcehut 仓库。</p><p>我选用的是 Agate 这个由 Rust 写的 Gemini 协议服务器。它会自动生成并管理 TLS 证书，不需要额外配置 Let's Encrypt，运行内存要求很低，我自己搭建后实际用的连 500KB 都不到。</p><p>不过它仅适用于纯静态 gemtext 文件 capsule。想要动态内容支持的话，可以考虑一下 Gemserv 或者 Molly Brown 这些服务器。</p><p>在 VPS 上安装了 Agate 之后，所需要的命令相当简单：</p><pre><code class="language-zsh">agate --content /gemtext/文件目录 --hostname 域名.后缀 --lang zh</code></pre></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;此胶囊旅馆非彼胶囊旅馆。虽说我对现实中的胶囊旅馆很感兴趣，但至今都没有睡过一次，去开张一家真正的胶囊旅馆更是无稽之谈。标题中的「胶囊旅馆」指的是通过 Gemini 协议提供内容的独立信息集合。&lt;/p&gt;</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Gemini" scheme="https://blog.cytrogen.icu/tags/Gemini/"/>
    
  </entry>
  
  <entry>
    <title>那些不受欢迎的想法</title>
    <link href="https://blog.cytrogen.icu/posts/fbd.html"/>
    <id>https://blog.cytrogen.icu/posts/fbd.html</id>
    <published>2026-02-25T05:00:00.000Z</published>
    <updated>2026-03-09T19:44:52.242Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>室友自上个月开始，和另一位有趣的人联合举办了一个活动，名为「那些不受欢迎的想法」。</p><span id="more"></span><p>该活动的简介很有特色：</p><blockquote><p>大多数人实际上并没有自己的观点。他们持有的是继承来的立场、重复的观点，或是伪装成深刻见解的自助车轱辘话。</p><p>本次活动是为那些真正拥有观点的人准备的。</p><p>每次活动，参与者都会分享一个他们真正持有的、经过深思熟虑的观点 —— 一些他们真正思考过、检验过或通过真实经历得出的东西。</p><p>一些他们真正相信并且能够捍卫的东西。</p><p>每次分享后，所有人都会在「完全不同意」到「完全同意」的谱系上选择自己的态度。然后我们会进行结构化的讨论：双方都有不被打断的时间来阐述他们的理由。目标不是为了胜利或证明自己是对的 —— 而是将想法与其他敏锐的头脑进行碰撞，并练习将想法与持有它们的人分开。</p></blockquote><p>第一次活动里，室友分享给我的话题并不是让我特别在意，不过还是让我记录一下吧。</p><p>室友自己分享了「将手机屏幕颜色调成灰阶」这个想法，因为这可以避免大脑被鲜艳的颜色吸引到。我必须严肃表示，她这一想法是从我这里学来的，而我是从 <a href="https://sami.eljabali.org/go-gray-not-cray-why-you-should-grayscale-your-phone/">另一篇文章</a> 学来的。</p><p>有人不赞同这个做法，因为护眼的话，其实调成纯红色更好，看上去也更恶心、让人不想要动手机。</p><p>经过两个月的使用后，我发觉将手机屏幕颜色调成灰阶的一个问题在于，眼睛逐渐不习惯于鲜丽的颜色。我的手机屏幕原本能够发出极其鲜艳的颜色，购买时我还认为是一件好事，现在看来一点都不好；眼睛都要瞎了，还是乖乖调回灰阶吧。</p><p>至于护眼不护眼，省不省电，我认为最好的方法还是 —— 把手机放下！</p><p>一个人建议大家学习在地板上睡觉，而理由是想要让自己不需要依赖任何外界的东西就能好好活下去。睡眠对人类而言是一件大事，如果只能在床上睡着的话，她会觉得自己的身体不受控制。</p><p>一个人表示「写作即思想」。他是一个热爱撰写博客文章的人，并在纽约市举办了一个自己的写作俱乐部。</p><p>室友觉得这个想法很棒，问我如何开发一个个人网站 —— 哼，这个家伙根本不理解个人网站的魅力，吃了我一嘴教程后到现在也没有搓出来一个网站。</p><p>一个人认为话疗没有用，根本就是胡言乱语，不会解决任何人的问题。不过这个人的想法过于主观，没有足够可以说服人的证据，不太严谨。</p><p>过去和室友大打出手的时候，室友去过几次话疗，结果都不尽人意：要么是建议她去搞开放式关系，要么是建议她去找心理医生、嗑药。这个话题本该会勾起她表达欲，但是提出者给出论点让她觉得有些幼稚。</p><p>一个人提议大家去专注于平日不会注意到的细节。他经常会在家附近走一条固定的路线。一次，他决定放慢脚步，鉴赏大自然，却发现家附近有个温室 —— 天啊，他住在这里这么多年了，居然不知道这里有这么大一个温室！</p><p>一个人说千万不要觉得自己奇怪，想到什么就去做吧。这个想法虽然很不错，但我认为实现起来很困难。</p><p>作为室友和另一个人初次举办的活动，她们俩都没有什么经验，后来也承认不够成熟，经过审核的话题也不够符合标题「不受欢迎的想法」，甚至有些听上去依然是车轱辘话来回转。不过第二次举办的活动里，能聊的东西就多了起来。</p><p>首先是鸽子被严重低估了！纽约客们可能都很讨厌这个动物吧：到处都是，到处拉屎。但其实这个动物并不是原生动物，而是因为战争、以「信鸽」的形式来到这片土地的。</p><p>提出这个观点的人认为，鸽子也可以很美丽。想要了解更多的话，可以见这个 <a href="https://www.theamericanpigeonmuseum.org/pigeon-breed-gallery">鸽子博物馆</a>。</p><p>我想到了「赛鸽」和「和平鸽」。这样说来，鸽子同时是「信息」以及「和平」的象征，可以拼接在一起，合成「沟通可以达成世界和平」的想法。</p><p>不过真的要给一个动物贴上如此宏大的标签么？「和平鸽」这个概念出自于《圣经》的诺亚方舟。当时诺亚放出了鸽子去打探地上的情况，而鸽子叼了橄榄叶回来，暗示地上已经有植物生长，洪水退了、世界和平了。</p><p>或许将动物的美拉回到动物本身是最好的 —— 你认为三文鱼的代表色是橙色吗？</p><p>接着是一个颇有争议性的话题：男人和女人如果互换了生殖系统，会发生什么？提出该话题的人认为，这世上的大多数人祖上都是皇族或者强奸犯。这是因为过去，只有强壮的人才能够繁殖后代。抛开在地位和权利上「强大」的皇族，强奸犯则是因为暴力、强迫了女性诞下自己的子嗣。皇族终究是少数人，那么剩余的多数人都是强奸犯，且越暴力越好。</p><p>他接着提出一个猜想：在基因层面上，男人会更暴躁。再加上男人的生殖系统是侵入性的，并且男人可以让多个女人怀孕，而女人一次只能怀一个男人的胎，因此男人想要授种的欲望更加强烈，其生殖系统也更希望他更加暴力。那么在互换后，具备这样的生殖系统的女人也会变得暴躁起来 —— 生殖系统决定了人类的很多事情。</p><p>室友提出反对。假设这个互换是突然发生的，那它仅改变了男女的「先天条件」，但是没有改变长期以来人类形成的文化，所以男人不会突然变得女性化，而女人也不会突然变得男性化。作为证据，她提出了双胞胎说：一对同卵双胞胎如果在不同的环境下生长，最终会长成完全不同的人。这意味着对人类而言，后天环境更加重要。</p><p>当然，这些都是以极端的情况作为前提来讨论的。是男人并不意味着他就是个强奸犯，拥有男性生殖系统也不意味着他一定会有 <u>有毒男子气质</u> —— 我曾经写过 <a href="/posts/5c85.html#%E6%9C%89%E6%AF%92%E7%94%B7%E6%80%A7%E6%B0%94%E8%B4%A8%E4%B8%8E%E6%80%A7%E5%88%AB%E6%9D%83%E5%8A%9B">相关的文章</a>，并认为这是被社会化的结果，而不是生理层面上的。将繁衍的生物学内驱力强行和系统性的社会暴力表现替换，实在是过于极端了，毕竟生殖器官本身并不具备实施社会暴力的主观意志，认为男性生殖器官更有侵入性一点我也不好说，毕竟男性也可以被女性强奸。</p><p>下一个话题是「大学是给一些不愿进社会的人们的拖延症」。提出方是一个没有上过大学的人。说实话，她是我目前见过最自律的人了，不仅自学了大量技能，就连生活的方方面面也不愿意交给其他人来做。她热爱音乐、走马拉松、尝试做自己从来没有做过的任何事情…… 令人忍不住去羡慕她。</p><p>说回她的论点。她认为大学对自己而言没有用处，只是让不想接受现实的人们再当几年的学生。室友也赞同这一点。不过这一论点很快被两个人否决了：一个认为，这是因为提出方和室友两个人都是主动性很强的人，在大学前就知道自己应该做什么工作。那如果是对未来感到迷茫的人呢？比方说他自己，就是上了大学才发现自己对物理学感兴趣，继而成为了一个物理老师，因此他永远都不会后悔自己上了大学。</p><p>另一个不赞同的人则认为，「大学无用」这个结论根本上是因为社会让太年轻的人去上大学了。刚刚成年的人们根本不知道未来该怎么办，也不知道社会是什么样的，去了大学自然不知道应当学什么专业。他希望高中生们毕业后，就立即步入社会工作，然后再决定是否要读本科，专精某项技能。</p><p>这很难让我回应…… 我讨厌大学是真，但更多是我觉得大学教育德不配位 —— 贵死了，教育水平也一般般，不如自学。所以我也算在大学之前就知道自己想做什么的人。不过并不是所有人一出生就知道自己想做什么，为这些人提供帮助的，我想正是学校。</p><p>但是我有一个更为宏观的看法：本科的重点是培养搞学术的人，而不是专业的工作者。后者应该去读专科。很多人错将本科认为是可以学习到专业技术的地方，毕业后却去找更适合专科毕业生的工作。同理，现在的职场也只认本科生，将适合专科生的工作交给本科生。结果社会越来越乱，出现了大量的本科生，出社会找工作却发现学校教的知识根本不是职场需要的技能。</p><p>这也是为什么我觉得双方的观点其实并不冲突：赞同方更注重于步入职场的实用性，都是创业者；不赞同方想要的是在学术上的引导，因为他之后当的也是和学术相关的老师。</p><p>至于是否应该让高中毕业生先去工作，我认为该想法的内核是值得称赞的，目前教育系统的一大痛点正是大多数年轻人在做出人生最昂贵的一次投资时，对真实的社会运作一无所知。</p><p>过去我认识到了一个观点，即 K-12 教育中应当多出哪些课程，其中就有税法、金钱管理等长大后必须要学习的内容。可惜，K-12 教育里没有这些，想要学习税法的需要自行去申请成为税法专业学生。社会残酷地没有为刚刚成年的个体提供试错和探索的空间，导致一个又一个人发觉大学真是个笑话，自己不过是又当了四五年高中生。</p><p>而已经经历过社会毒打，参与过真实工作场景的人们，更能清楚自己欠缺什么。重返校园接受本科教育时，他们拥有着更强的目的性。我没少见过年纪可以做我父母的本科生们比谁都要更努力地钻研学业，让我忍不住去关注他们。</p><p>不过这个想法实践起来有些不切实际，并不是因为它有误，而是目前社会运转逻辑已经固定了。我们的劳动力市场过于前置了学历门槛，剥夺了高中毕业生通过低门槛工作去探索世界的过渡期，就连 Gap Year 这个概念在很多国家都属于奢侈品。社会默认将年轻人直接从高中强行推进大学，导致许多人只是为了逃避就业而继续读书。本科是如此，硕士也是如此。</p><p>最后一个话题就没有前一些话题那么有争议性了：自私和无私的代价。我和室友在高中时就参与过这个话题的辩论。或许是一直待一块的原因，臭味相投，我和她的看法是一致的：世界上根本没有什么所谓的「无私」，无私不过是在客观结果上利他的自私，因为无私者是被自己的想法驱动而去做利他型行为的，获得最多的也是自我的满足。</p><p>当时我哗啦啦写了一篇作文表示人类有着自私的基因，却被另一个同学评论认为这种想法是不人道的。现在我已经不记得我做出了什么样的回应，但我现在可以说，自私并不意味着要和恶意、贪婪和剥削等词汇挂钩，承认自己自私也并不妨碍我们在宏观层面建立道德 —— 人类的自私基因为了延续，演化出来的恰恰正是合作、同理心和无私奉献等策略，因为互助的群体存活率远高于互相残杀的群体。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;室友自上个月开始，和另一位有趣的人联合举办了一个活动，名为「那些不受欢迎的想法」。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="心理学" scheme="https://blog.cytrogen.icu/tags/%E5%BF%83%E7%90%86%E5%AD%A6/"/>
    
    <category term="社会学" scheme="https://blog.cytrogen.icu/tags/%E7%A4%BE%E4%BC%9A%E5%AD%A6/"/>
    
    <category term="哲学" scheme="https://blog.cytrogen.icu/tags/%E5%93%B2%E5%AD%A6/"/>
    
    <category term="教育学" scheme="https://blog.cytrogen.icu/tags/%E6%95%99%E8%82%B2%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>汇编语言学习・壹</title>
    <link href="https://blog.cytrogen.icu/posts/8e54.html"/>
    <id>https://blog.cytrogen.icu/posts/8e54.html</id>
    <published>2026-02-23T05:00:00.000Z</published>
    <updated>2026-02-24T05:58:57.367Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>学习汇编语言的笔记。</p><span id="more"></span><p>使用的教学材料：</p><ul><li>Linux Foundation X [LFD117x] Foundations of RISC-V Assembly Programming</li></ul><p>汇编语言可以用于开发操作系统和编译器，不过我认为也可以用于「入门」计算机 —— 学了总是好事。</p><h3 id="基础知识"><a class="markdownIt-Anchor" href="#基础知识"></a> 基础知识</h3><h4 id="risc-v"><a class="markdownIt-Anchor" href="#risc-v"></a> RISC-V</h4><p>这是一种指令集架构规范，为处理器奠定了通用的机器代码语言基础。<br>RISC 指的是「精简指令集计算机」，而 V 代表的是罗马数字 5。<br>RISC - V 属于一种开放式指令集架构。</p><h4 id="assembly"><a class="markdownIt-Anchor" href="#assembly"></a> Assembly</h4><p>Assembly 语言可以被直接翻译成机器码，是最低级的编程语言。需要记住的是，「低级」不代表是一件坏事。</p><p>学习 Assembly 以及如何使用它可以帮助我们理解软件和硬件的内部。</p><h4 id="微处理器"><a class="markdownIt-Anchor" href="#微处理器"></a> 微处理器</h4><p>通常来说，处理器包含控制单元、算术逻辑单元、寄存器以及用于输入输出的信号与数据线路。</p><ul><li>处理器利用控制单元来执行指令</li><li>算数逻辑单元负责对整数执行算术和逻辑运算</li><li>寄存器是位于处理器内部的一种小型存储单元。处理器能够将数据从外部存储器或其他设备快速加载到寄存器中，在寄存器内对数据进行操作，随后将结果写入外部存储器或者其他设备<ul><li>程序计数器是一种特殊的寄存器，用于保存当前待执行指令的位置信息。控制单元可以通过程序计数器来确定程序的执行进度</li></ul></li></ul><p>微处理器可以被分为 RISC 和 CISC，后者是复杂指令集计算机。两者的区别在于，RISC 架构拥有的指令数量较少。特定情况下，CISC 架构可能只需要一条指令就能做到一件事情，而 RISC 架构下需要执行更多的指令。</p><p>继续说 RISC。典型的 RISC 处理器会执行典型的五级流水线工作：</p><ol><li>指令获取（IF）</li><li>指令译码（ID）</li><li>指令执行（EX）</li><li>存储器访问（MEM）</li><li>写回（WB）</li></ol><p>具体流程是这样的：</p><ol><li>处理器从程序计数器所指向的内存地址获取指令</li><li>指令是以二进制代码形式编码的，所以系统随后会对其进行译码、确定并获取执行所需的其他信息</li><li>进入执行阶段，利用算术逻辑单元进行计算</li><li>如果指令涉及内存访问，则会在接下来的存储器访问阶段进行处理</li><li>如果运算产生了结果，该结果将在最后一个阶段被写回寄存器</li></ol><p>该流程可以按照单周期方式执行，也可以采用流水线技术执行。后者可以实现各阶段的并行处理，从而提升效率。</p><h4 id="ripes"><a class="markdownIt-Anchor" href="#ripes"></a> Ripes</h4><p>Ripes 是一款专为演示 RV32IMC 和 RV64IMC 架构上机器代码执行过程而设计的模拟器。<br>总体而言，Ripes 是快速入门并实践学习汇编语言的极佳工具。</p><h3 id="安装"><a class="markdownIt-Anchor" href="#安装"></a> 安装</h3><p>课程使用的系统是 Debian / Ubuntu 系，我用的是 Arch Linux 系，部分包会对不上。这里只写我安装了什么：</p><pre><code class="language-zsh">sudo pacman -S qemu-system-riscv qemu-user</code></pre><p>可以使用 <code>qemu-riscv-64-static -help</code> 命令就可以。</p><p>这是用于在我们的计算机上安装专门针对 RISC - V 架构的系统仿真器。<br>接着我们需要安装交叉编译器，用来让我们的 C 语言源代码编译成 RISC - V 指令集。</p><pre><code class="language-zsh">sudo pacman -S riscv64-linux-gnu-gcc</code></pre><p>当编译一个动态链接的 RISC - V 程序时，编译器会在生成的二进制文件里写入一个解释器的绝对路径。对于 64 位的 RISC - V Linux 程序，这个解释器通常是 <code>ld-linux-riscv64-lp64d.so.1</code> 默认预期位置在 <code>/lib/</code> 目录下。然而在我们的宿主机上，这个文件实际上位于交叉编译器的安装目录中，而不是系统的根目录 <code>/lib/</code> 下。</p><p>当使用 <code>qemu-riscv64</code> 运行程序时，QEMU 会尝试加载程序，但程序本身会告诉系统去 <code>/lib/</code> 找解释器。如果找不到就会报错。</p><p>因此我们需要建立一个软链接，将位于深层目录的解释器映射到程序预期的 <code>/lib/</code> 位置，从而欺骗程序使其能够找到加载器。</p><p>这里有两个选择：</p><ol><li>链接到 <code>/lib/</code></li><li>链接到 <code>/usr/lib/</code></li></ol><p>两者其实差不多，都可以。我就用后者来示范了。</p><pre><code class="language-zsh">sudo ln -s /usr/riscv64-linux-gnu/lib/ld-linux-riscv64-lp64d.so.1 /usr/lib/ld-linux-riscv64-lp64d.so.1</code></pre><p>但其实还有一种方法，更适合「洁癖党」，那就是指定 Sysroot 路径。这样 QEMU 就会在那个目录下查找 <code>/lib/</code> 和 <code>/usr/lib</code> 了，我们也不需要弄乱系统的目录。我的建议是设置一个环境变量：</p><pre><code class="language-zsh">export QEMU_LD_PREFIX=/usr/riscv64-linux-gnu</code></pre><p>无论如何，都可以使用 <code>riscv64-linux-gnu-as --version</code> 来进行检查。</p><p>然后我们需要安装一个调试器：</p><pre><code class="language-zsh">sudo pacman -S gdb</code></pre><p>运行 <code>gdb -h</code> 来检查。</p><p>让我们创建一个测试文件 <code>example.s</code>：</p><pre><code class="language-plaintext">.globl _start_start:addi x10, x0, 7addi x17, x0, 93ecall</code></pre><p>先使用 <code>as</code> 将源码转换为目标文件：</p><pre><code class="language-shell">riscv64-linux-gnu-as -o example.o example.s</code></pre><p>再将 <code>example.o</code> 链接为可执行文件 <code>example</code>：</p><pre><code class="language-shell">riscv64-linux-gnu-ld -o example example.o</code></pre><p>最后在 QEMU 中执行：</p><pre><code class="language-shell">qemu-riscv64 example</code></pre><p>最终的结果是返回了个 <code>7</code>。</p><p>我们也可以使用 <code>riscv64-linux-gnu-objdump</code> 来审视我们的二进制文件：</p><pre><code class="language-shell">riscv64-linux-gnu-objdump -sd example</code></pre><pre><code class="language-plaintext">example:     file format elf64-littleriscvContents of section .text: 100b0 13057000 9308d005 73000000           ..p.....s...    Contents of section .riscv.attributes: 0000 415e0000 00726973 63760001 54000000  A^...riscv..T... 0010 05727636 34693270 315f6d32 70305f61  .rv64i2p1&lt;u&gt;m2p0&lt;/u&gt;a 0020 3270315f 66327032 5f643270 325f7a69  2p1&lt;u&gt;f2p2&lt;/u&gt;d2p2_zi 0030 63737232 70305f7a 6966656e 63656932  csr2p0_zifencei2 0040 70305f7a 6d6d756c 3170305f 7a61616d  p0&lt;u&gt;zmmul1p0&lt;/u&gt;zaam 0050 6f317030 5f7a616c 72736331 703000    o1p0_zalrsc1p0. Disassembly of section .text:00000000000100b0 &lt;_start&gt;:   100b0:00700513          lia0,7   100b4:05d00893          lia7,93   100b8:00000073          ecall</code></pre><p>这可以将机器码逆向翻译回人类可读的汇编指令，帮我们验证编译器是否真的生成了预期中的代码。</p><p><em>Contents of section .text</em> 处展示了内存中的原始字节数据。</p><pre><code class="language-plaintext">100b0 13057000 9308d005 73000000</code></pre><p>其中地址 <code>100b0</code> 是这段代码在内存中存放的起始地址，数据 <code>13057000</code> 是第一个 4 字节（32 位）的内容。</p><p>在计算机科学中，位（bit，有时也可以叫比特位）是信息的最小单位，只能显示 0 或者 1 两种状态，也就是「假」与「真」。而字节（byte）是计算机存储和处理数据的基本单位，通常规定 1 个字节由 8 个位组成。</p><p><code>13057000</code> 这串数据实际上是十六进制表示法。</p><p>这个「十六」并非物理上的容量单位，而是「进制」这个数字概念，具体代表的是在一个单独的数位上，到底拥有多少种不同的独立状态或者符号。例如人类最熟悉的十进制，每一个数位拥有从 0 到 9 这十个独立符号，当状态数值超过 9 时，就必须向前进位（1 + 9 = 10，个位超过了 9，就会向前面的十位进位）。</p><p>同理，十六进制意味着每一个单独的数位拥有 16 种独立的状态，为了填补数字 9 之后的符号空缺，系统引入了 a 到 f，对应十进制的 10 到 15。</p><p>理解了进制代表着「状态的数量」后，就可以将其与底层的「位」建立起直接的数学映射。先前说过，位只有 <code>0</code> 和 <code>1</code> 这两个状态。如果想要使用纯续的二进制来表示更多的状态，就必须将多个位组合在一起来观察：1 个位是 2 种状态；2 个位组合在一起（<code>00</code>、<code>01</code>、<code>10</code>、<code>11</code>）是 4 种状态；3 个位是 8 种状态。</p><p>十六进制中每一个字符（<code>0-9</code> 和 <code>a-f</code>）就代表 4 个位，总计 16 种状态。</p><p>计算机科学选择大量采用十六进制，其根本原因是为了在机器的物理状态和人类的阅读习惯之间寻找妥协：人类无法快速阅读和心算二进制流，而如果将其转换为人类最熟悉的十进制，二进制与十进制之间的互相转换又必须经过整体的乘除法运算。由于 10 不是 2 的整数次幂，这种转换无法在底层的比特位上做到规整的一一对应。</p><p>既然 1 个十六进制字符代表 4 个位，那么需要 2 个连续的十六进制字符并排，来转录 1 个字节的完整物理状态 —— 因为 1 个物理字节由 4 个比特位组成。</p><p>在 <code>13057000</code> 里共有 8 个字符（<code>13</code>、<code>05</code>、<code>70</code> 和 <code>00</code>），意味着总共有 32 个位，或者说 4 个字节。对于 RISC - V 架构而言，其标准的指令长度固定为 32 位，也正好对应了内存中这 4 个连续字节所占据的空间。</p><p><code>littleriscv</code> 指明了小端序，低字节需要存放在低地址。</p><p>小端序又是什么呢？它描述的是多字节数据在计算机内存中的排列顺序。由于内存是被组织成一个线性的字节序列，即每个地址对应一个字节，当我们要在内存中存放一个跨越多个字节的数值，比如一个 32 位的整数时，就面临着把哪一端放在低地址的选择。</p><p>小端序指的是将数据的最低有效字节存放在内存的最低地址处，而最高有效字节则存放在最高地址处。这种存储方式的优势在于从低地址读取数据时，不需要进行地址计算即可直接获得数值的低位部分。</p><p>要想更加理解这一部分，就必须深入理解计算机是如何「看待」数据的物理本质。计算机的内存可以类比于一排无限长的储物柜，每个储物柜上都有编号，叫作「地址」，从 0 开始，依次递增。低地址是编号较小的位置，高地址自然就是编号较大的位置。</p><p>问题在于，一个储物柜只能存放 1 个字节。我们想要存储的数据往往是多个字节，要想存进内存就必须占用连续的储物柜。用 <code>13057000</code> 举例：你有着身为最高位的 <code>00</code> 以及身为最低位的 <code>13</code>，面前是低地址 0 和高地址 3，你应该把数据的头放在低地址还是把尾放在低地址？</p><p>更直观一些，假设我们要存储十六进制数 <code>0x12345678</code>，其中 <code>12</code> 是最高有效字节，相当于「千位」， <code>78</code> 是最低有效字节，相当于「个位」。而我们会占用从 <code>0x100</code> 到 <code>0x103</code> 这四个地址。</p><p>人类的阅读习惯是从左到右，从大到小（例如数字），所以先把最大的头 <code>12</code> 放在最开始的低地址 <code>0x100</code>。</p><table><thead><tr><th>内存地址</th><th><code>0x100</code></th><th><code>0x101</code></th><th><code>0x102</code></th><th><code>0x103</code></th></tr></thead><tbody><tr><td>存放内容</td><td><code>12</code></td><td><code>34</code></td><td><code>56</code></td><td><code>78</code></td></tr></tbody></table><p>而小端序更符合计算逻辑。计算机在做加法时，是先算个位，再算十位。把最低位放在低地址（数据的起始地址），CPU 读取数据时，直接从起始地址就能拿到最低位开始运算。因此就会变成：</p><table><thead><tr><th>内存地址</th><th><code>0x100</code></th><th><code>0x101</code></th><th><code>0x102</code></th><th><code>0x103</code></th></tr></thead><tbody><tr><td>存放内容</td><td><code>78</code></td><td><code>56</code></td><td><code>34</code></td><td><code>12</code></td></tr></tbody></table><p>理解了小端序，就能解释为什么会出现 <code>00700513</code> 这样的内容。在 <code>objdump</code> 输出中，左侧的 <code>13057000</code> 是按照内存地址从低到高显示的： <code>13</code> （地址 N）， <code>05</code> （N+1）， <code>70</code> （N+2）， <code>00</code> （N + 3）。正因为是小端序，放在低地址（最左边）的 <code>0x13</code> 实际上是数值的最低位，而放在高地址（最右边）的 <code>0x00</code> 是最高位。</p><p>当 CPU 读取这 4 个字节组成一个 32 位整数（指令）时，它会按照权重将这些字节重新组装，最终形成符合人类书写习惯的大端数值 <code>0x00700513</code> （高位在左）。</p><p><em>Disassembly of section .text</em> 处是 <code>objdump</code> 将机器码翻译回汇编指令的结果，也是我们验证代码逻辑的核心区域。</p><pre><code class="language-plaintext">100b0: 00700513 li a0,7</code></pre><p>第一行指令中显示， <code>100b0</code> 是指令的内存地址； <code>00700513</code> 是 CPU 实际执行的 32 位机器码，也是上面提到的「被倒过来」的指令； <code>li a0,7</code> 是反汇编后的汇编代码。</p><p>我们源码写的是 <code>addi x10, x0, 7</code>，寄存器中 <code>objdump</code> 默认使用 ABI 名称， <code>x10</code> 寄存器在函数调用规范中用于传递参数或者返回值，因此被称为 <code>a0</code> 即 <em> Argument/Return 0</em> 的意思。</p><p>ABI 全称为 Application Binary Interface（应用程序二进制接口），是一套规范，定义了软件组件之间如何在机器码层面进行交互。它规定了每个寄存器的专用功能，其名称也可以让汇编代码更具可读性。</p><p><code>objdump</code> 识别出 <code>addi x10, x0, 7</code> 的语义实际上就是「将立即数 7 加载到 a0 中」，因此它显示了更易读的伪指令 <code>li</code>（Load Immediate，加载立即数）。这两者在机器码层面是完全一样的。</p><pre><code class="language-plaintext">100b4: 05d00893 li a7,93</code></pre><p>第二行指令中显示， <code>05d00893</code> 是机器码； <code>li a7,93</code> 对应的是源码中的 <code>addi x17, x0, 93</code>。</p><p><code>x17</code> 的 ABI 别名是 <code>a7</code>。在 Linux RISC - V 系统调用规矩中， <code>a7</code> 寄存器用来存放系统调用号。 <code>93</code> 代表的是 <code>exit</code> 的系统调用。</p><pre><code class="language-plaintext">100b8: 00000073 ecall</code></pre><p>第三行指令中显示， <code>00000073</code> 是 <code>ecall</code> 指令的固定机器码。</p><p><code>ecall</code> 即 Environment Call，它会触发中断，将控制权交给操作系统内核。内核检查 <code>a7</code> 中的值（93），知道你要退出，然后检查 <code>a0</code> 中的值（7），将其作为退出状态码返回。</p><p>至于中间的 <code>.riscv.attributes</code> 部分，它是编译器留下的指纹。右侧的 ASCII 码显示了该程序编译时所使用的架构扩展列表。</p><pre><code class="language-zsh">qemu-riscv64 -g 1234 example</code></pre><p>启动另一个终端来连接 GDB（目录需要是同一个）：</p><pre><code class="language-zsh">gdb -q example</code></pre><p>当显示 <code>(gdb)</code> 时输入：</p><pre><code class="language-zsh">target remote :1234</code></pre><p>我们可以使用命令 <code>display /3i $pc</code> 来打印内存信息。其中 <code>3</code> 代表着数量， <code>i</code> 代表着指令， <code>$pc</code> 则代表程序计数器寄存器，这个寄存器始终存储着 CPU 即将执行的下一条指令的内存地址。</p><pre><code class="language-plaintext">1: x/3i $pc=&gt; 0x100b0 &lt;_start&gt;:lia0,7   0x100b4 &lt;_start+4&gt;:lia7,93   0x100b8 &lt;_start+8&gt;:ecall</code></pre><p>得出的结果中，带有箭头标记的一行就是当前 CPU 暂停的位置，也就是下一刻将被执行的指令。随后的两行则展示了未来的执行路径。</p><p>接下来可以使用 <code>si</code> 来命令 CPU 向前走一步，返回的结果中可以看到箭头出现在了下一行指令。</p><p>使用 <code>c</code> 来解除暂停，让 CPU 全速运行直到遇到下一个断点或者程序结束，我们就能看到返回码 <code>7</code>。</p><p>最后 <code>q</code> 来结束当前的 GDB 调试会话。</p><p>上述的所有没有解释明白的术语，在后续都有讲解。</p><p>教程中还提到了可以在 Visual Studio Code 中使用 PlatformIO 插件，不过我不用 Visual Studio Code，就不说了。</p><h3 id="星光板"><a class="markdownIt-Anchor" href="#星光板"></a> 星光板</h3><p>StarFive VisionFive（以下简称星光板）是一款基于 RISC - V 架构的单板计算机，相当于 RISC - V 版本的树莓派。</p><p>介于我手上没有这个物理开发板，和物理外设相关的代码我都无法运行，只当学习运算逻辑了。</p><p>教程中展示了如何在板子内调用生成 RISC - V 代码的工具，例如 <code>as</code> 和 <code>gcc</code>；在我这个 x86 电脑上，就只能使用 <code>riscv64-linux-gnu-as</code> 了。同理， <code>./example</code> 这样的命令在 x86 电脑上要改用 <code>qemu-riscv64 example</code>。</p><p>在之前的步骤，我们的 GDB 会提示 <code>(No debugging symbols found)</code>，这是因为我们生成的只是纯粹的机器码。需要添加 <code>-g</code> 参数，汇编器才会将源代码的调试信息嵌入到生成的目标文件中。</p><pre><code class="language-shell">riscv64-linux-gnu-as -g -o example.o example.sriscv64-linux-gnu-ld -o example example.o</code></pre><p>接下来是关键的调试步骤。</p><p>打开终端 A，充当服务端：</p><pre><code class="language-zsh">qemu-riscv64 -g 1234 example</code></pre><p>打开另一个终端 B，充当客户端。</p><p>客户端连接成功后，输入：</p><pre><code class="language-zsh">layout src</code></pre><p>因为这次添加了 <code>-g</code>，我们会看到熟悉的源代码窗口，而不是汇编代码。</p><p>接着输入：</p><pre><code class="language-zsh">b 5</code></pre><p>意思是在第 5 行打断点。</p><p>最后使用 <code>c</code> 命令，让程序全速运行，直到撞上第 5 行的断点并自动停下。此时输入：</p><pre><code class="language-zsh">info reg x10</code></pre><p>会看到寄存器 <code>x10</code> 的值确实是 7。</p><h3 id="指令集架构"><a class="markdownIt-Anchor" href="#指令集架构"></a> 指令集架构</h3><p>ISA（Instruction Set Architecture， <u>指令集架构</u>）是软件与硬件之间的契约。它定义了处理器能够理解的所有操作指令（比方说加法、跳转、内存读写），以及处理器向软件暴露的状态。</p><p>RISC - V 的设计哲学是模块化的。基础指令集代表了 CPU 必须实现的最小功能集合。其他的扩展功能，如浮点运算，都是可选的插件。这与 x86 这种将所有功能捆绑在一起的架构并不相同。这意味着，只要掌握了基础指令集，代码就能在任何一个标准的 RISC - V 处理器上运行。</p><h4 id="非特权指令集"><a class="markdownIt-Anchor" href="#非特权指令集"></a> 非特权指令集</h4><p>现代处理器通常至少有两种运行模式：</p><ol><li>特权模式：操作系统内核运行的模式，可以执行所有指令，包括管理硬件、中断和内存映射的指令；</li><li>非特权模式：普通应用程序运行的模式。</li></ol><h4 id="基础架构的分类"><a class="markdownIt-Anchor" href="#基础架构的分类"></a> 基础架构的分类</h4><p>RISC - V 通过简单的命名规则来区分不同的基础架构变体：</p><ul><li>RV：代表 RISC - V；</li><li>32 / 64 / 128：代表寄存器的位宽和地址空间的大小；</li><li>I：代表整数；</li><li>E：代表嵌入式。</li></ul><p>RV64I 是目前我们正在使用的架构，因为工具链是 <code>riscv64</code>。它是 64 位的标准整数指令集。<br>RV32I 是 32 位的标准版本，在微控制器领域非常流行。<br>RV128I 是为未来设计的 128 位架构，用于应对未来海量内存寻址的需求。<br>RV32E 是为了极低成本、极低功耗的微控制器而设计的。它将寄存器数量从标准的 32 个砍到了 16 个，以节省芯片面积。</p><h4 id="寄存器大小与地址空间"><a class="markdownIt-Anchor" href="#寄存器大小与地址空间"></a> 寄存器大小与地址空间</h4><p>寄存器大小与地址空间是理解 32 位或 64 位计算机本质的关键。在 RV64I 中，通用寄存器（例如 <code>x10</code>）的物理宽度是 64 个比特，这意味着单一一条指令可以直接处理一个最大为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mn>2</mn><mn>64</mn></msup><mo>−</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">2^{64} - 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.897438em;vertical-align:-0.08333em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">6</span><span class="mord mtight">4</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span> 的整数。如果在 RV32I 上处理同样的数，就需要多条指令将其拆分处理。</p><p>寄存器的宽度也决定了指针的大小。在 RV32 中，指针是 32 位的，因此 CPU 最多只能寻址 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mn>2</mn><mn>32</mn></msup></mrow><annotation encoding="application/x-tex">2^{32}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8141079999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span> 个字节的内存，即 4 GB。这对于现代桌面应用来说往往是不够的。在 RV64 中，指针是 64 位的，理论寻址空间高达 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mn>2</mn><mn>64</mn></msup></mrow><annotation encoding="application/x-tex">2^{64}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8141079999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">6</span><span class="mord mtight">4</span></span></span></span></span></span></span></span></span></span></span></span> 字节，即 160 亿 GB，消除了内存容量的限制。</p><p>RV32I 的基础指令集仅包含 40 条指令，也就是说，只需要这 40 条最基本的指令就可以构建出所有的计算逻辑！</p><h4 id="模块化命名规则"><a class="markdownIt-Anchor" href="#模块化命名规则"></a> 模块化命名规则</h4><p>RISC - V 的设计允许通过组合不同的扩展模块来定制处理器的功能。</p><p>先前说过，RISC - V 处理器都必须至少支持一个基础整数指令集。在此基础上，处理器设计者可以选择添加额外的硬件功能，这些功能被称为扩展。处理器的完整型号就是「基础架构名 + 扩展后缀」。</p><p>这些是标准扩展代码：</p><ul><li>M（Integer Multiplication and Division）：整数乘除法。硬件直接支持整数的乘法和除法运算。如果没有这个扩展，处理器需要通过软件算法模拟乘除法，速度会显著变慢；</li><li>A（Atomic Instructions）：原子指令。支持在单一操作中完成内存的「读取 - 修改 - 写入」过程。这对于多线程同步和并发控制至关重要，例如实现互斥锁；</li><li>F（Single-Precision Floating Point）：单精度浮点数。硬件支持 32 位浮点数运算；</li><li>D（Double-Precision Floating Point）：双精度浮点数。硬件支持 64 位浮点数运算。通常依赖于 F 扩展；</li><li>Q（Quad-Precision Floating Point）：四精度浮点数。硬件支持 128 位浮点数运算；</li><li>C（Compressed Instructions）：压缩指令。支持 16 位长度的指令，而标准 RISC - V 指令为 32 位。这可以显著减少程序占用的内存空间，提高代码密度；</li><li>V（Vector Operations）：向量操作。支持 SIMD（单指令多数据）操作，允许一条指令同时处理一组数据，常用于高性能计算和 AI 加速。</li></ul><p>这里使用两个例子：</p><ul><li>RV32IMAC：<ul><li>RV32I：基础是 32 位整数架构；</li><li>M：支持硬件乘除法；</li><li>A：支持原子操作；</li><li>C：支持压缩指令；</li><li>但是不支持浮点运算，是一个纯整数处理器。</li></ul></li><li>RV64IMAFDC（通常也被称为 RV64GC）：<ul><li>RV64I：基础是 64 位整数架构；</li><li>剩下的意味着它同时支持乘除法、原子操作、单 / 双精度浮点运算和压缩指令。这是一个全功能的通用处理器配置，类似于我们电脑内的 CPU。</li></ul></li></ul><p>某些情况下会出现 SU 后缀，例如 RV64IMAFDCSU。这两个字母不代表具体的运算指令，而是代表处理器支持的特权模式：</p><ul><li>S（Supervisor Mode）：监管者模式。这是操作系统内核，如 Linux Kernel，运行所需的权限级别。支持 S 模式意味着该处理器有能力运行完整的操作系统；</li><li>U（User Mode）：用户模式。这是普通应用程序运行的受限权限级别。</li></ul><p>因此，如果一个处理器列出了 <code>S</code>，事实就是它被设计为可以运行操作系统；如果只支持机器模式（也是默认都有的），则它通常只能运行简单的裸机代码。</p><h4 id="硬件层面的寄存器结构"><a class="markdownIt-Anchor" href="#硬件层面的寄存器结构"></a> 硬件层面的寄存器结构</h4><p>RISC - V 的基础指令集规定处理器必须包含 32 个通用整数寄存器，物理编号为 <code>x0</code> 到 <code>x31</code>。此外，还有一个独立的程序计数器 <code>PC</code>，用于记录当前正在执行的指令地址。</p><p>寄存器的位宽直接对应于基础架构的位数。在 RV32I 架构中，每个寄存器（<code>x0</code> 到 <code>x31</code>）和 <code>PC</code> 都是 32 位的（4 字节）；而在 RV64I 架构中，它们则是 64 位的（8 字节）。这意味着寄存器即用于存储参与运算的数据，也用于存储内存地址（指针）。</p><p>在硬件层面， <code>x0</code> 是一个特殊的寄存器。它被硬件强制硬连线位常数 0。无论程序向 <code>x0</code> 写入什么值，读取时得到的结果永远是 0。这是为了简化指令集，例如「将寄存器清零」或「移动数据」等操作都可以复用通用的算术指令，而无需设计专用的指令。</p><h4 id="abi"><a class="markdownIt-Anchor" href="#abi"></a> ABI</h4><p>先前已经提到了 ABI，此处详细说一下 ABI 将寄存器按功能划分成了多少类：</p><ul><li>特殊功能寄存器<ul><li>zero（<code>x0</code>）：恒为 0；</li><li><code>ra</code> （<code>x1</code>，Return Address）：返回地址寄存器。当发生函数调用（<code>call</code>）时，硬件会将「下一条指令的地址」自动保存到这里，以便函数执行完后能跳回原来的位置；</li><li><code>sp</code> （<code>x2</code>，Stack Pointer）：栈指针。指向当前栈顶的内存地址，用于管理函数调用栈；</li><li><code>gp</code> （<code>x3</code>，Global Pointer）和 <code>tp</code> （<code>x4</code>，Thread Pointer）：分别用于快速访问全局变量和线程本地存储。</li></ul></li><li>函数调用与参数传递<ul><li><code>a0-a7</code> （<code>x10-x17</code>，Arguments）：参数寄存器。用于将参数传递给函数。其中 <code>a0</code> 和 <code>a1</code> 还兼职用于存储函数的返回值。如果参数超过 8 个，多余的参数通常会通过栈（内存）传递。</li></ul></li><li>临时与保存寄存器<ul><li><code>t0-t6</code> （Temporaries）：临时寄存器。被调用函数（Callee）可以随意修改这些寄存器，不需要恢复原值。因此，调用者（Caller）如果想在函数调用后继续使用 <code>t</code> 寄存器里的值，必须自己在调用前保存它们；</li><li><code>s0-s11</code> （Saved Registers）：保存寄存器。被调用函数必须保证这些寄存器的值在函数退出时与进入时一致。如果函数内部需要使用这些寄存器，必须先将旧值压入栈中保存，使用完后再从栈中恢复。其中 <code>s0</code> 有时也被用作 <code>fp</code> （Frame Pointer），即帧指针。</li></ul></li></ul><h4 id="加载-存储架构"><a class="markdownIt-Anchor" href="#加载-存储架构"></a> 加载 - 存储架构</h4><p>在 RISC - V 中，所有的算术和逻辑运算只能在寄存器之间进行。CPU 无法直接对内存中的数据执行加法操作。</p><p>如果想要修改内存中的一个变量，必须遵循严格的「三步走」流程：</p><ol><li>Load：使用加载指令（如 <code>lw</code>）将数据从内存读取到某个通用寄存器中；</li><li>Compute：在寄存器内部使用算术指令（如 <code>add</code>）对数据进行计算；</li><li>Store：使用存储指令（如 <code>sw</code>）将计算结果从寄存器写回到内存中。</li></ol><p>这种设计虽然使得单条指令的功能变弱了，比方说不能像 x86 的 <code>add [eax] 5</code> 那样一步到位，但简化了硬件电路设计，使指令流水线更加规整和高效。</p><p>以 <code>addi</code> 指令为例，用三个核心层级来讲解汇编指令如何被 CPU 执行、寄存器如何变化以及机器码在内存中的基本布局。</p><p>两个例子：</p><ol><li><code>addi x1, x0, 1</code></li><li><code>addi x1, x1, 1</code></li></ol><p>一、在指令层级上， <code>addi</code> 的全程是 Add Immediate（立即数加法）。它的标准语法格式是 <code>addi rd, rs1, imm</code>。</p><ul><li><code>rd</code> （Destination Register）：目标寄存器，用来存放计算结果；</li><li><code>rs1</code> （Source Register 1）：源寄存器，提供基础数值；</li><li><code>imm</code> （Immediate）：立即数。这是一个直接写在指令里的常数，而不是从寄存器里读的。<ul><li>限制：它必须是一个 12 位有符号整数。这意味着它的取值范围被限制在 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">[</mo><mo>−</mo><mn>2048</mn><mo separator="true">,</mo><mn>2047</mn><mo stretchy="false">]</mo></mrow><annotation encoding="application/x-tex">[-2048, 2047]</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">[</span><span class="mord">−</span><span class="mord">2</span><span class="mord">0</span><span class="mord">4</span><span class="mord">8</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord">2</span><span class="mord">0</span><span class="mord">4</span><span class="mord">7</span><span class="mclose">]</span></span></span></span> 之间。</li></ul></li></ul><p>第一个例子取出了 <code>x0</code> 的值，并添加立即数 1，结果便是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>0</mn><mo>+</mo><mn>1</mn><mi mathvariant="normal">『</mi><mn>1</mn></mrow><annotation encoding="application/x-tex">0 + 1 ` 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord">1</span><span class="mord">『</span><span class="mord">1</span></span></span></span>。然后将这个结果 1 写入寄存器 <code>x1= 。 第二个例子取出</code> x1 <code>当前的值，并添加立即数 1，结果是 $1 + 1 </code> 2$。然后将这个结果 2 写入寄存器 `x1=，实际上实现了自增的操作。</p><p>二、 <code>PC</code> 指针与步进。</p><p>在 RISC - V 的基础指令集中，每条指令的长度固定为 4 字节（32 位）。每当 CPU 取出一条指令后， <code>PC</code> 寄存器会自动加 4，使得 CPU 能够指向内存中的下一条指令。</p><p>三、内存与机器码层级上，代码到底是如何被存放的？</p><p>假设代码从地址 <code>0x0</code> 开始：</p><table><thead><tr><th>内存地址</th><th>机器码</th><th>对应的汇编</th></tr></thead><tbody><tr><td><code>0x0</code></td><td><code>0x00100093</code></td><td><code>addi x1, x0, 1</code></td></tr><tr><td><code>0x4</code></td><td><code>0x00108093</code></td><td><code>addi x1, x1, 1</code></td></tr></tbody></table><ul><li>地址 <code>0x0</code>：存放第一条指令。执行时，CPU 处于地址 <code>0x0</code>，执行完后 <code>PC</code> 变为 <code>0x4</code>；</li><li>地址 <code>0x4</code>：存放第二条指令。因为上一条指令占了 4 个字节（0, 1, 2, 3），所以下一条指令必须从 4 开始。</li></ul><p>执行流演示：</p><ol><li>初始状态： <code>PC </code> 0x0=；</li><li>取指：CPU 读取地址 <code>0x0</code> 处的数据 <code>00100093</code>；</li><li>执行：解析为 <code>addi x1, x0, 1</code>。寄存器 <code>x1</code> 变为 1；</li><li>更新： <code>PC</code> 自动加 4，变为 <code>0x4</code>；</li><li>取指：CPU 读取地址 <code>0x4</code> 处的数据 <code>00108093</code>；</li><li>执行：解析为 <code>addi x1, x1, 1</code>。寄存器 <code>x1</code> 变为 2。</li></ol><p>教程推荐使用 Ripes 模拟器来直观观看数据通路中，信号是如何流动的，以及 <code>PC</code> 指针是如何跳变的。</p><h4 id="六大指令类型"><a class="markdownIt-Anchor" href="#六大指令类型"></a> 六大指令类型</h4><p>基础指令集将所有功能划分为 6 种类型，每种类型对应一种特定的比特位布局：</p><table><thead><tr><th>类型</th><th>英文全称</th><th>中文含义</th><th>典型用途</th><th>示例指令</th></tr></thead><tbody><tr><td>R</td><td>Register</td><td>寄存器型</td><td>纯寄存器之间的运算</td><td><code>add x1, x2, x3</code></td></tr><tr><td>I</td><td>Immediate</td><td>立即数型</td><td>寄存器与小常数运算，或加载内存</td><td><code>addi x1, x0, 1</code></td></tr><tr><td>S</td><td>Store</td><td>存储型</td><td>将数据存入内存</td><td><code>sw x1, 0(x2)</code></td></tr><tr><td>B</td><td>Branch</td><td>分支型</td><td>条件跳转</td><td><code>beq x1, x2, label</code></td></tr><tr><td>U</td><td>Upper</td><td>高位立即数</td><td>设置长立即数的高 20 位</td><td><code>lui x1, 0x1000</code></td></tr><tr><td>J</td><td>Jump</td><td>跳转型</td><td>无条件跳转</td><td><code>jal , label</code></td></tr></tbody></table><p>根据先前的例子， <code>addi x1, x0, 1</code> 的机器码是 <code>0x00100093</code>。我们可以通过查表并结合已知信息推导出这个编码：</p><ul><li>Opcode（操作码）： <code>0x13</code> （二进制 <code>0010011</code>）；</li><li><code>funct3</code>（功能码）： <code>0x0</code> （二进制 <code>000</code>）；</li><li>Type（类型）：属于 I-type。</li></ul><p>因此 <code>addi x1, x0, 1</code> 的机器码按位组合如下：</p><ul><li>二进制序列： <code>0000 0000 0001 0000 0000 0000 1001 0011</code>；</li><li>由于每 4 个二进制位可以转换为 1 个十六进制数字，最终结果就是 <code>0x00100093</code>。</li></ul><p>要看懂这个解析，我们需要深入了解指令编码的具体布局。虽然 RISC - V 的指令长度固定为 32 位，但这 32 个比特并非随意排列，而是被划分为了不同的字段。每种指令类型都有其独特的字段排布方式。对于 <code>addi</code> 这种 I-type 指令，其 32 位数据的内部结构由高位到低位依次如下：</p><p>首先，其 32 位空间被分割为 5 个部分：</p><table><thead><tr><th>比特位置</th><th><code>31:20</code></th><th><code>19:15</code></th><th><code>14:12</code></th><th><code>11:7</code></th><th><code>6:0</code></th></tr></thead><tbody><tr><td>字段名称</td><td><code>imm[11:0]</code></td><td><code>rs1</code></td><td><code>funct3</code></td><td><code>rd</code></td><td>操作码</td></tr><tr><td>含义</td><td>立即数</td><td>源寄存器</td><td>功能码</td><td>目标寄存器</td><td>操作码</td></tr><tr><td>长度</td><td>12 位</td><td>5 位</td><td>3 位</td><td>5 位</td><td>7 位</td></tr></tbody></table><p>其次，我们将具体的汇编指令映射到上述结构中：</p><ul><li>操作码：这是识别指令家族的。对于所有的 I-type 算术指令（如 <code>addi</code> 、 <code>ori</code> 等），操作码固定为 <code>0010011</code> 也就是十六进制的 <code>0x13</code>；</li><li><code>rd</code>：指令中的目标是 <code>x1</code>。在二进制中，1 表示为 <code>00001</code>；</li><li><code>funct3</code>：由于操作码定义了一组指令，我们需要额外的 3 位来区分具体是「加法」还是「异或」等。对于加法 <code>addi</code>，该值为 <code>000</code>；</li><li><code>rs1</code>：指令中的源操作数是 <code>x0</code>。在二进制中，0 表示为 <code>00000</code>；</li><li><code>imm</code>：我们要加的数值是 <code>1</code>。I-type 允许 12 位的有符号立即数，因此 1 表示为 <code>000000000001</code>。</li></ul><p>最后，我们需要将上述二进制片段按顺序连接起来。值得注意的是，我们要用的是从高位 31 到低位 0 的顺序：</p><ul><li><code>imm</code>： <code>000000000001</code></li><li><code>rs1</code>： <code>00000</code></li><li><code>funct3</code>： <code>000</code></li><li><code>rd</code>： <code>00001</code></li><li><code>操作码</code>： <code>0010011</code></li></ul><p>连在一起我们就得到了 32 位二进制流： <code>00000000000100000000000010010011</code>。</p><p>为了将其转换成人类可读的十六进制，我们将这 32 位每 4 位分为一组进行转换：</p><table><thead><tr><th>二进制分组</th><th>0000</th><th>0000</th><th>0001</th><th>0000</th><th>0000</th><th>0000</th><th>1001</th><th>0011</th></tr></thead><tbody><tr><td>十六进制值</td><td>0</td><td>0</td><td>1</td><td>0</td><td>0</td><td>0</td><td>9</td><td>3</td></tr></tbody></table><p>最终组合结果为： <code>0x00100093</code>。这就是机器真正看到并执行的内容！</p><p>其他类型的编码方式见下图：</p><p><img src="/posts/8e54/encoding_table.webp" alt="" loading="lazy"></p><h5 id="立即数类型指令集中与算术-逻辑运算相关的具体指令"><a class="markdownIt-Anchor" href="#立即数类型指令集中与算术-逻辑运算相关的具体指令"></a> 立即数类型指令集中与算术、逻辑运算相关的具体指令</h5><p>这些指令的一个共同特征是：它们都接受一个源寄存器和一个立即数作为输入，运算后将结果存入目标寄存器。所有这些指令共享同一个 操作码，这意味着 CPU 是通过 <code>funct3</code> 字段，以及移位指令中的部分立即数位来区分具体是要执行加法、异或还是移位操作。</p><p>我们将这些指令分为三类进行讲解：</p><p>一、算术与逻辑运算。</p><p>这组指令对寄存器数值进行基础数字或位操作。</p><table><thead><tr><th>指令</th><th>全称</th><th>功能描述</th><th>关键点</th></tr></thead><tbody><tr><td>&lt;6&gt;</td><td>&lt;10&gt;</td><td>&lt;10&gt;</td><td>&lt;8&gt;</td></tr><tr><td><code>addi</code></td><td>Add Immediate</td><td><code>rd </code> rs1 + imm`</td><td>唯一的加法指令。RISC - V 没有专门的 <code>subi</code> 指令。因为立即数 `immi= 是有符号的（-2048 到 2047），如果你想做减法，只需加上一个复数即可。</td></tr><tr><td><code>xori</code></td><td>XOR Immediate</td><td><code>rd </code> rs1 ^ imm=</td><td>按位异或。常用于翻转特定位。</td></tr><tr><td><code>ori</code></td><td>OR Immediate</td><td><code>rd </code> rs1 \vert{} imm=</td><td>按位或。常用于将特定位置 1。</td></tr><tr><td><code>andi</code></td><td>AND Immediate</td><td><code>rd </code> rs1 &amp; imm=</td><td>按位与。常用于掩码操作（清零特定位）。</td></tr><tr><td>假设寄存器 <code>x1</code> 的值为 <code>0x9</code> （二进制 <code>1001</code>）。执行 <code>xori x1, x1, 0x3</code>：</td><td></td><td></td><td></td></tr></tbody></table><ul><li>源数据： <code>1001</code> （<code>0x9</code>）</li><li>立即数： <code>0011</code> （<code>0x3</code>）</li><li>异或结果： <code>1010</code> （<code>0xA</code>）</li><li>最终 <code>x1</code> 变为 <code>0xA</code></li></ul><p>二、移位运算。</p><p>移位指令用于将二进制位向左或向右移动。对于 I-Type 移位指令，立即数指定了移位的位数。</p><p>值得注意的是，移位指令在编码上比较特殊。由于移位量只需要 5 个比特，I-Type 指令原本 12 位的立即数空间被拆分了：低 5 位用于存移位量，高 7 位（<code>imm[11:5]</code>）被用来作为辅助功能码，区分逻辑移位和算术移位。</p><table><thead><tr><th>指令</th><th>全称</th><th>符号</th><th>填充规则</th></tr></thead><tbody><tr><td><code>slli</code></td><td>Shift Left Logical Imm.</td><td><code>&lt;&lt;</code></td><td>逻辑左移；所有位向左移，低位（右侧）空出的位置补 0</td></tr><tr><td><code>srli</code></td><td>Shift Right Logical Imm.</td><td><code>&gt;&gt;</code></td><td>逻辑右移；所有位向右移，高位（左侧）空出的位置补 0</td></tr><tr><td><code>srai</code></td><td>Shift Right Arithmetic Imm.</td><td><code>&gt;&gt;</code></td><td>算术右移；所有位向右移，高位（左侧）空出的位置补符号位（即维持最高位不变）。适用于有符号数（补码），这能保证负数右移后依然是负数</td></tr></tbody></table><p>作为一个例子，假设 <code>x1</code> 为 <code>0x9</code> （<code>1001</code>）。执行 <code>slli x1, x1, 0x2</code>，即左移 2 位。原始内容是 <code>00...001001</code>，左移后变成 <code>00...100100</code> （低位补了两个 0），等于 <code>36</code>，即十六进制 <code>0x24</code>。</p><p>三、比较运算。</p><p>这类指令用于数值比较，结果不是返回差值，而是返回布尔值 0 或者 1。</p><table><thead><tr><th>指令</th><th>全称</th><th>功能描述</th><th>区别</th></tr></thead><tbody><tr><td><code>slti</code></td><td>Set Less Than Imm.</td><td>若 <code>rs1 &lt; imm</code> 则 <code>rd=1</code>，否则 <code>0</code></td><td>有符号比较。它将操作数视为补码。例如，它会认为 -1 小于 10</td></tr><tr><td><code>sltiu</code></td><td>Set Less Than Imm. Unsigned</td><td>若 <code>rs1 &lt; imm</code> 则 <code>rd=1</code>，否则 <code>0</code></td><td>无符号比较。它将操作视为纯正整数。例如，它会认为 -1，即全 1 的 <code>0xFFFFFFFF</code>，是一个巨大的正数，因此 -1 大于 10</td></tr></tbody></table><h5 id="寄存器类型"><a class="markdownIt-Anchor" href="#寄存器类型"></a> 寄存器类型</h5><p>在先前的 I-Type（立即数型）指令中，指令的 32 个比特位被分配给了一个目标寄存器（<code>rd</code>）、一个源寄存器（<code>rs1</code>）和一个 12 位的立即数（<code>imm</code>）。当程序需要将两个都在寄存器中的变量进行运算时，I-Type 就无能为力了。因此，RISC - V 设计了 R-Type 格式。</p><table><thead><tr><th>指令名称</th><th>操作码</th><th><code>funct3</code></th><th><code>funct7</code></th><th>描述</th></tr></thead><tbody><tr><td><code>add</code>（加法）</td><td><code>0110011</code></td><td><code>0x0</code></td><td><code>0x00</code></td><td><code>rd = rs1 + rs2</code></td></tr><tr><td>#ERROR</td><td><code>0110011</code></td><td><code>0x0</code></td><td><code>0x20</code></td><td><code>rd = rs1 - rs2</code></td></tr><tr><td><code>xor</code>（异或）</td><td><code>0110011</code></td><td><code>0x4</code></td><td><code>0x00</code></td><td><code>rd = rs1 ^ rs2</code></td></tr><tr><td><code>or</code>（或）</td><td><code>0110011</code></td><td><code>0x6</code></td><td><code>0x00</code></td><td><code>rd = rs1 \vert rs2</code></td></tr><tr><td><code>and</code>（与）</td><td><code>0110011</code></td><td><code>0x7</code></td><td><code>0x00</code></td><td><code>rd = rs1 &amp; rs2</code></td></tr><tr><td><code>sll</code>（逻辑左移）</td><td><code>0110011</code></td><td><code>0x1</code></td><td><code>0x00</code></td><td><code>rd = rs1 &lt;&lt; rs2</code></td></tr><tr><td><code>srl</code>（逻辑右移）</td><td><code>0110011</code></td><td><code>0x5</code></td><td><code>0x00</code></td><td><code>rd = rs1 &gt;&gt; rs2</code></td></tr><tr><td><code>sra</code>（算术右移）</td><td><code>0110011</code></td><td><code>0x5</code></td><td><code>0x20</code></td><td><code>rd = rs1 &gt;&gt; rs2</code></td></tr><tr><td><code>slt</code>（小于置位）</td><td><code>0110011</code></td><td><code>0x2</code></td><td><code>0x00</code></td><td><code>rd = (rs1 &lt; rs2)? 0:1</code></td></tr><tr><td><code>sltu</code>（无符号小于置位）</td><td><code>0110011</code></td><td><code>0x3</code></td><td><code>0x00</code></td><td><code>rd = (rs1 &lt; rs2)? 0:1</code></td></tr></tbody></table><p>R-Type 指令的物理编码结构将原本用于存放 12 位立即数的空间重新进行了分配。它划出了 5 个比特位用于指定第二个源寄存器（<code>rs2</code>），而剩余的 7 个比特位则被定位为 <code>funct7</code> 也叫 7 位功能码。所有的 R-Type 算术和逻辑指令都共享同一个基本的操作码，操作码 为 <code>0110011</code>。CPU 首先读取操作码，得知这是一条 R-Type 算术指令，接着通过结合 <code>funct3</code> 和 <code>funct7</code>，才能最终确定具体要执行的硬件电路。</p><p>例如加法和减法。RISC - V 的 I-Type 指令中不存在 <code>subi</code> （立即数减法），因为程序员可以直接加上一个负的立即数。但是在纯寄存器运算中，加法和减法是截然不同的操作。在 R-Type 中，<code>add</code> 和 <code>sub</code> 拥有完全相同的操作码和 <code>funct3</code>，它们唯一的物理区别就在于 <code>funct7</code> 字段：<code>add</code> 的 <code>funct7</code> 为 <code>0x00</code>，而 <code>sub</code> 的 <code>funct7</code> 为 <code>0x20</code>。硬件编码器会捕捉到这一个比特位的差异，从而指示算术逻辑单元执行减法而不是加法。</p><p>这种 R-Type 架构同样适用于移位操作。在前面提到的立即数移位指令（如 <code>slli</code>）中，移位的步长是硬编码在指令里的常数。而在 R-Type 的移位指令中（<code>sll</code>、<code>srl</code>、<code>sra</code>）中，移位的步长来自于第二个源寄存器（<code>rs2</code>）的最低 5 个比特位。这意味着程序可以在运行时，动态计算并决定需要移位的具体位数，从而极大地提升了运算的灵活性。</p><p>依然是作为例子：</p><table><thead><tr><th>地址</th><th>机器码</th><th>汇编含义</th></tr></thead><tbody><tr><td><code>0x0</code></td><td><code>0x00100093</code></td><td><code>addi x1, x0, 1</code></td></tr><tr><td><code>0x4</code></td><td><code>0x00108093</code></td><td><code>addi x1, x1, 1</code></td></tr><tr><td><code>0x8</code></td><td><code>0x00108133</code></td><td><code>add x2, x1, x1</code></td></tr></tbody></table><p>程序计数器会从地址 <code>0x0</code> 启动，第一条 I-Type 指令将 <code>x1</code> 初始化为 1。随后 <code>PC</code> 步进至 <code>0x4</code>，第二条 I-Type 指令通过自增操作使 <code>x1</code> 的值更新为 2。当 <code>PC</code> 到达 <code>0x8</code>，CPU 读取并解码出第一条 R-Type 指令（<code>add</code>）。此时，指令指示 ALU 取出 <code>rs1</code>（即 <code>x1</code>，值为 2）和 <code>rs2</code>（依然是 <code>x1</code>，值为 2）的内容。ALU 执行加法后得到 4，并将该结果通过数据通路写回到目标寄存器 <code>rd</code>（即 <code>x2</code>）。至此，<code>x2</code> 的状态被确立为 4。</p><h4 id="加载与存储"><a class="markdownIt-Anchor" href="#加载与存储"></a> 加载与存储</h4><p>如何与主内存进行数据交换，以及如何高效地生成大型的 32 位常数和内存地址呢？</p><p>RISC - V 采用了严格的「加载 - 存储」架构。ALU 无法直接读取或修改内存中的数据。所有的运算必须在寄存器内完成。这就构成了数据流转的基本逻辑：使用 Load 指令将内存数据搬运到寄存器，在寄存器中计算完毕后，再使用 Store 指令将结果搬运回内存。</p><table><thead><tr><th>指令</th><th>名称</th><th>格式</th><th>操作码</th><th><code>funct3</code></th><th>描述</th></tr></thead><tbody><tr><td><code>lb</code></td><td>加载字节</td><td>I</td><td><code>0000011</code></td><td><code>0x0</code></td><td><code>rd = M[rs1+imm][7:0]</code></td></tr><tr><td><code>lh</code></td><td>加载半字</td><td>I</td><td><code>0000011</code></td><td><code>0x1</code></td><td><code>rd = M[rs1+imm][15:0]</code></td></tr><tr><td><code>lw</code></td><td>加载字</td><td>I</td><td><code>0000011</code></td><td><code>0x2</code></td><td><code>rd = M[rs1+imm][31:0]</code></td></tr><tr><td><code>lbu</code></td><td>加载无符号字节</td><td>I</td><td><code>0000011</code></td><td><code>0x4</code></td><td><code>rd = M[rs1+imm][7:0]</code></td></tr><tr><td><code>lhu</code></td><td>加载无符号半字</td><td>I</td><td><code>0000011</code></td><td><code>0x5</code></td><td><code>rd = M[rs1+imm][15:0]</code></td></tr><tr><td><code>sb</code></td><td>存储字节</td><td>S</td><td><code>0100011</code></td><td><code>0x0</code></td><td><code>M[rs1+imm][7:0] = rs2[7:0]</code></td></tr><tr><td><code>sh</code></td><td>存储半字</td><td>S</td><td><code>0100011</code></td><td><code>0x1</code></td><td><code>M[rs1+imm][15:0] = rs2[15:0]</code></td></tr><tr><td><code>sw</code></td><td>存储字</td><td>S</td><td><code>0100011</code></td><td><code>0x2</code></td><td><code>M[rs1+imm][31:0] = rs2[31:0]</code></td></tr></tbody></table><p>该表格列出了所有的 Load 和 Store 指令。这些指令的寻址模式被称为「基址寻址」。以语法 <code>lb x2, 0(x1)</code> 为例，括号内的 <code>x1</code> 是基址寄存器（<code>rs1</code>），提供了一个基础的内存地址；括号外的 <code>0</code> 是立即数偏移量（<code>imm</code>）。硬件会将 <code>x1</code> 的值与立即数相加，计算出最终的物理内存地址，然后从该地址读取数据存入 <code>x2</code>（<code>rd</code>）中。</p><p>对于 Load 指令，RISC - V 提供了按字节（8 位，<code>lb</code>）、半字（16 位，<code>lh</code>）和字（32 位，<code>lw</code>）加载的选项。由于目标寄存器总是 32 位的，当加载不足 32 位的数据（如 8 位的字节）时，就会出现高 24 位如何填充的问题。带有 <code>u</code> 后缀的指令（如 <code>lbu</code>，无符号加载）会在高位全部填充 0；而不带 <code>u</code> 的指令（如 <code>lb</code>，有符号加载）则会进行「符号扩展」，即将最高位（符号位）复制填充到所有的剩余高位中，以维持负数的数字意义。Store 指令则不需要区分符号，因为它们仅仅是截断寄存器中的低位数据，并覆盖到内存中，如 <code>sb</code> 只取寄存器的最低 8 位写入内存。</p><p>既然内存地址通常是一个 32 位的巨大数值，而基于 I-Type 和 S-Type 的指令只能容纳 12 位的立即数，我们该如何将一个 32 位的地址放入寄存器以便后续寻址呢？</p><p>早期的笨办法是通过复杂的算术运算。程序员被迫先用 <code>addi</code> 将 1 放入寄存器，然后再用 <code>slli</code> 将其左移 28 位，才能勉强凑出 <code>0x10000000</code> 这个地址。这种操作极其低效，且难以泛用。</p><p>为了解决这个问题，RISC - V 引入了 U-Type（Upper Immediate，高位立即数）指令格式。U-Type 指令舍弃了源寄存器字段，将立即数的可用空间直接扩展到了 20 位。</p><table><thead><tr><th>指令</th><th>名称</th><th>操作码</th><th><code>funct3</code></th><th>描述</th></tr></thead><tbody><tr><td><code>lui</code></td><td>加载高位立即数</td><td><code>0110111</code></td><td>无</td><td><code>rd = imm &lt;&lt; 12</code></td></tr><tr><td><code>auipc</code></td><td>将高位立即数加至 <code>PC</code></td><td><code>0010111</code></td><td>无</td><td><code>rd = PC + (imm &lt;&lt; 12)</code></td></tr></tbody></table><p><code>lui</code> 的硬件逻辑非常纯粹：它获取指令中提供的 20 位立即数，直接将其放置在目标寄存器的高 20 位（即向左移位 12 次），并将底部的 12 位强制清零。因为在十六进制中，每 4 个二进制等于 1 个十六进制字符，左移 12 位正好等同于在数字末尾追加 3 个零。这样，只需要一条 <code>lui</code> 指令，就可以极快地构造出 32 位数值的上半部分。</p><p>而 <code>auipc</code> 与 <code>lui</code> 机制类似，但多了一个步骤：它在将高 20 位就位后，会将其与当前的 <code>PC</code> 的值相加。在现代操作系统中，程序加载到内存的绝对地址往往是随机的，程序必须能够相对于其自身的位置去寻找变量。<code>auipc</code> 允许处理器以当前执行的指令地址为基准，向前或向后计算出相距甚远的数据地址。</p><h4 id="控制流"><a class="markdownIt-Anchor" href="#控制流"></a> 控制流</h4><p>在先前的学习中，我们已经知道 <code>PC</code> 在默认情况下会在每个时钟周期自动加 4，以此顺序执行内存中的指令。控制流的物理本质就是通过特定的条件或指令强行重写 <code>PC</code> 寄存器的值，从而改变指令获取的物理地址。</p><p>条件分支指令（B-Type）的核心机制是让 ALU 对两个源寄存器进行比较。如果满足指令规定的比较条件，硬件会将指令中携带的立即数与当前的 <code>PC</code> 值相加，并将这个计算结果强行写入 <code>PC</code> 寄存器，完成物理跳转。如果条件不满足，PC 则按常规加 4，继续执行内存中紧挨着的下一条指令。</p><p>在条件比较中，区分有符号和无符号至关重要。底层的机器码只是一串二进制位，没有内在的正负之分。</p><p>作为个例子：</p><table><thead><tr><th>地址</th><th>机器码</th><th>意思</th><th>注释</th></tr></thead><tbody><tr><td><code>0x00</code></td><td><code>0xffb00093</code></td><td><code>addi x1, x0, -5</code></td><td><code>x1 = -5</code></td></tr><tr><td><code>0x04</code></td><td><code>0x00500113</code></td><td><code>addi x2, x0, 5</code></td><td><code>x2 = 5</code></td></tr><tr><td><code>0x08</code></td><td><code>0x0020c463</code></td><td><code>blt x1, x2, 0x8</code></td><td><code>if (x1 &lt; x2) pc = pc + 8</code></td></tr><tr><td><code>0x0c</code></td><td><code>0x00100193</code></td><td><code>addi x3, x0, 1</code></td><td><code>skipped if (x1 &lt; x2): x3 = 1</code></td></tr><tr><td><code>0x10</code></td><td><code>0x00200193</code></td><td><code>addi x3, x0, 2</code></td><td><code>x3 = 2</code></td></tr></tbody></table><p>寄存器 <code>x1</code> 先是被赋予了 <code>-5</code>。在 32 位系统中，<code>-5</code> 的底层补码是以 1 开头的一串极长的数据（即 <code>0xfffffffb</code>），而 <code>x2</code> 是 <code>5</code>。当使用 <code>blt</code> 进行比较时，硬件逻辑会将最高位视为符号位，从而正确得出 <code>-5</code> 小于 <code>5</code> 的结论，并触发跳转。</p><p>但如果错用了 <code>bltu</code>，硬件会纯续从数值大小的角度将 <code>0xfffffffb</code> 视为一个巨大的正数，此时比较结果为假，程序就会错误地跳过分支。</p><p>除了基于条件的短距离跳转，RISC - V 还提供了用于实现函数调用和返回的无条件跳转指令，即 <code>jal</code>（Jump and Link）和 <code>jalr</code>（Jump and Link Register）。这类指令不仅要改变 <code>PC</code> 的值以实现跳转，还承担着「记录来处」的责任。</p><p>所谓的 <em> Link</em>（链接），指的是在覆盖 <code>PC</code> 寄存器之前，硬件会先将当前的 <code>PC</code> 值加上 4 保存到一个指定的目标寄存器中。这个被保存的地址就是返回地址。通过这种机制，程序在跳入一个代码片段执行完毕后，可以再次通过读取该寄存器的值跳回到最初离开的位置，这是实现程序模块化和复用的底层基础。</p><p><code>jal</code> 和 <code>jalr</code> 的区别在于计算目标地址的方式。<code>jal</code> 属于 J-Type 指令，它将当前的 <code>PC</code> 值与指令中携带的大范围立即数相加来实现相对位置的跳转。而 <code>jalr</code> 属于 I-Type 指令，它通过读取一个源寄存器的值，加上立即数偏移量来计算跳转的绝对物理地址。</p><p>这是又一个例子：</p><table><thead><tr><th>地址</th><th>机器码</th><th>意思</th><th>注释</th></tr></thead><tbody><tr><td><code>0x00</code></td><td><code>0x00c000ef</code></td><td><code>jal x1, 0xc</code></td><td><code>set pc to 0x0 + 0xc = 0xc, x1 = pc + 4 = 0x4</code></td></tr><tr><td><code>0x04</code></td><td><code>0x00000013</code></td><td><code>addi x0, x0, 0</code></td><td>无操作</td></tr><tr><td><code>0x08</code></td><td><code>0x00010093</code></td><td><code>addi x1, x2, 0</code></td><td><code>set x1 = x2</code></td></tr><tr><td><code>0x0c</code></td><td><code>0x00008167</code></td><td><code>jalr x2, x1, 0</code></td><td><code>set pc to x1, x2 = pc + 4 = 0x10</code></td></tr><tr><td><code>0x10</code></td><td><code>0x00100093</code></td><td><code>addi x1, x0, 1</code></td><td><code>x1 = 1</code></td></tr></tbody></table><p>这是一个相对复杂点的跳转时序，实际上模拟了一个状态机的执行轨迹。程序从地址 <code>0x00</code> 开始，执行 <code>jal x1, 0xc</code>。此时 CPU 计算跳转目标为 <code>0x00</code> 加上 <code>0xc</code> 等于 <code>0x0c</code>，同时将返回地址 <code>0x04</code> 保存到寄存器 <code>x1</code> 中。</p><p>随后 <code>PC</code> 跳转至 <code>0x0c</code>，执行 <code>jalr x2, x1, 0</code>。此时 <code>x1</code> 的值为 <code>0x04</code>，因此跳转目标为 <code>0x04</code> 加上 <code>0</code> 等于 <code>0x04</code>。同时，这条指令需要保存新的返回地址，即当前的 <code>0x0c</code> 加上 <code>4</code> 等于 <code>0x10</code>，并将其写入寄存器 <code>x2</code> 中。</p><p>此时 <code>PC</code> 再次跳转回 <code>0x04</code>。<code>0x04</code> 处的指令是将 <code>x0</code> 加上 <code>0</code>，实际上是一条不改变任何物理状态的空操作。程序继续顺序执行到 <code>0x08</code>，这里的指令将 <code>x2</code> 的值（即刚才保存的 <code>0x10</code>）复制给 <code>x1</code>。</p><p>程序继续顺序执行，再次来到 <code>0x0c</code>。此时再次执行 <code>jalr x2, x1, 0</code>。由于在上一步，<code>x1</code> 的值已经被更新为 <code>0x10</code>，因此这次的跳转目标变成了 <code>0x10</code> 加上 <code>0</code> 等于 <code>0x10</code>。同时，新的返回地址 <code>0x10</code> 再次被写入 <code>x2</code>。</p><p>最终，PC 跳转至 <code>0x10</code> 执行加法指令。</p><h4 id="系统接口"><a class="markdownIt-Anchor" href="#系统接口"></a> 系统接口</h4><p>在现代计算机体系结构中，为了保证系统的稳定与安全，硬件在物理上划分了不同的运行模式。普通应用程序默认运行在权限极低的「用户模式」下，这种模式下的代码被物理电路限制，无法直接操作底层硬件。而操作系统内核运行在高权限的「监管者模式」或者「机器模式」下，拥有掌控所有物理资源的最高权限。</p><p>当运行在用户模式下的程序需要执行必须由高权限才能完成的动作时，就必须通过一种机制，在硬件层面上安全地将控制权移交给操作系统。<code>ecall</code> 指令就是为此而生的。</p><p>它在执行时，会在处理器内部触发一个同步异常。这个物理动作会瞬间打断当前用户程序的线性执行流，将 <code>PC</code> 的值强行替换为操作系统内核预先设定的异常处理程序的物理地址，并同时提升处理器的硬件特权级别。</p><p>然而，操作系统内核在接管控制权后，必须知道用户程序究竟想要请求什么服务。这就需要依靠 ABI 指定的寄存器契约。在 Linux RISC - V 的契约中，程序员必须在触发 <code>ecall</code> 之前，将特定的系统调用号放入指定的物理寄存器 <code>x17</code>（ABI 名称为 <code>a7</code>）中。内核被唤醒后，会第一时间去读取 <code>a7</code> 寄存器的电平状态，以此来决定分配哪一段内核代码去执行具体的任务。</p><p>教程中提供的例子正是描述了这样一个完整的系统调用物理过程，其具体内容如下表所示：</p><table><thead><tr><th>地址</th><th>机器码</th><th>意思</th><th>注释</th></tr></thead><tbody><tr><td><code>0x00</code></td><td><code>0x05d00893</code></td><td><code>addi x17, x0, 93</code></td><td>设置 <code>a7 = 93</code>，对应 Linux 的 <code>exit</code> 系统调用</td></tr><tr><td><code>0x04</code></td><td><code>0x00000073</code></td><td><code>ecall</code></td><td>触发环境调用，将控制权移交系统内核</td></tr></tbody></table><p>在这个执行序列中，程序首先位于内存地址 <code>0x00</code>。指令解码器将机器码 <code>0x05d00893</code> 翻译为 <code>addi x17, x0, 93</code>。硬件电路读取恒为 0 的 <code>x0</code> 寄存器，将其与立即数 93 相加，并将结果存在 <code>x17</code> 寄存器中，也就是 <code>a7</code>。在 Linux 内核的系统调用映射表中，数字 93 严格对应着 <code>sys_exit</code> 的服务。随后 <code>PC</code> 步进至 <code>0x04</code>，处理器读取并执行 <code>ecall</code> 指令。此时，硬件权限提升，Linux 内核介入，检查到 <code>a7</code> 寄存器内部的数据为 93，于是内核执行进程清理工作，彻底在内存中抹除该程序的运行状态。</p><p>另一个系统接口指令是 <code>ebreak</code>。与 <code>ecall</code> 移交控制权给操作系统不同，<code>ebreak</code> 的物理设计目的是将处理器的控制权移交给调试器。执行 <code>ebreak</code> 同样会触发一个异常，迫使 CPU 暂停当前的流水线工作。</p><p>不过程序员在编写汇编源码时，极少会手动写入 <code>ebreak</code> 指令。它的主要应用场景是在幕后由调试软件动态注入。当我们在调试器中对代码的某一行下达「打断点」的指令时，调试器会在物理内存中定位到该行代码对应的原始机器码，并将其悄悄替换为 <code>ebreak</code> 的机器码。</p><p>当微处理器的高速缓存读取并执行到这个被篡改的内存地址时，<code>ebreak</code> 触发异常，CPU 物理挂起，调试器趁机接管控制台，允许我们通过输入命令去查看各个寄存器内部的电平状态。当我们在调试器中输入继续运行的指令后，调试器会再次访问那段内存，将 <code>ebreak</code> 机器码抹除，并把原本正确的指令机器码填补回去，最后让 CPU 恢复物理运转。</p><h4 id="内存排序"><a class="markdownIt-Anchor" href="#内存排序"></a> 内存排序</h4><p>在现代微处理器架构中，为了极致追求物理执行效率，硬件通常会采用乱序执行技术，并配备多级高速缓存和存储缓冲区。这意味着，机器码在内存中的线性排列顺序，并不完全等同于 CPU 最终将计算结果写入主内存的物理时序。在单核处理器中，这种乱序执行对程序员是透明的，硬件内部的依赖检查机制会保证最终结果的正确性。</p><p>然而在拥有多个 RISC - V 硬件线程且共享同一块物理主内存的系统中，这种乱序写入会导致严重的同步问题。当核心 A 向共享内存写入一组数据，随后写入一个标志位表示数据已准备就绪时；核心 B 如果通过物理总线先预测到了标志位的改变，却因为核心 A 的缓存延迟而读取到了尚未更新的旧数据，就会引发并发程序的逻辑崩溃。</p><p><code>fence</code> 指令的物理作用就是强制实施严格的内存访问顺序，以解决上述的可见性倒置问题。当微处理器的指令流水线读取到 <code>fence</code> 指令时，它会在硬件层面上将程序的执行流划分为两个绝对隔离的集合：位于 <code>fence</code> 之前的指令集合，以及位于 <code>fence</code> 之后的指令集合。</p><p>执行 <code>fence</code> 指令时，当前处理器核心会暂时挂起后续集合中所有涉及内存访问指令的执行。硬件控制电路会等待并确保，前序集合中的所有内存读写操作不仅在当前核心内执行完毕，而且其产生的电平状态改变必须通过系统总线被推送至全局，确保被系统内的所有其他物理核心准确观测到。只有在这一物理可见性保证达成之后，后续集合中的内存访问指令才被允许启动。</p><p>这种硬件级别的时序强制保证，是构建现代并发软件的基石。在操作系统的底层实现中，开发人员利用 <code>fence</code> 指令配合原子操作，来构建互斥锁等同步机制，从而确保多个进程或线程在操作共享内存区块时不会发生物理状态的竞态条件。</p><table><thead><tr><th>指令</th><th>名称</th><th>类型</th><th>操作码</th><th><code>funct3</code></th><th>描述</th></tr></thead><tbody><tr><td><code>fence</code></td><td>Fence</td><td>I</td><td><code>0001111</code></td><td><code>0x0</code></td><td><code>rd</code> 和 <code>rs1</code> 处于保留状态。针对所有内存访问类型的常规 <code>fence</code> 指令，其立即数 <code>imm = 0b000011111111</code></td></tr></tbody></table><p>根据该表，由于 <code>fence</code> 并不进行实际的算术数据搬运，其目标寄存器 <code>rd</code> 和源寄存器 <code>rs1</code> 在基础用法中被硬件忽略并保留为空。</p><p>该指令的核心在于其 12 位的立即数。在 <code>fence</code> 指令的微架构实现中，这 12 个比特位被精确划分为输入和输出两组掩码，用于细粒度地指定具体需要对哪种类型的设备的哪种操作进行强制排序。表格中给出的立即数（即十六进制的 <code>0x0FF</code>）是一个全为 1 的掩码。当硬件电路接收到这个特定的立即数序列时，它会执行最严格的「完全屏障」，即要求该屏障之前的所有类型的物理内存读写，必须先于该屏障之后的所有类型的物理内存读写完成全局同步。</p><h4 id="m扩展"><a class="markdownIt-Anchor" href="#m扩展"></a> <em>M</em> 扩展</h4><p>在体系结构的底层设计中，基础整数指令集（RV32I）为了追求硅片面积的极简与低功耗，在物理电路上刻意移除了硬件乘法器和除法器。如果仅有基础指令集，微处理器在执行乘除法时必须依赖编译器生成的循环加法与位移指令软件算法，这会消耗大量的时钟周期。M 扩展代表着在处理器的硅片上实际蚀刻了专用的硬件乘法器和除法器逻辑电路，使得乘除法可以在极少的时钟周期内直接由硬件电路完成。</p><p>M 扩展包含的指令全部属于 R-Type 格式，这意味着所有参与运算的数据必须预先加载到通用寄存器中，且指令的操作码统一为 <code>011011</code>。硬件译码器通过识别 7 位功能码（<code>funct7</code>，M 扩展固定为 <code>0x01</code>，即 <code>0000001</code>）与 3 位功能码（<code>funct3</code>）的电平信号组合，来精确激活对应的乘除法物理电路。</p><table><thead><tr><th>指令</th><th>名称</th><th><code>funct3</code></th><th>描述</th></tr></thead><tbody><tr><td><code>mul</code></td><td>Multiply</td><td><code>0x0</code></td><td><code>rd = (rs1 * rs2)[31:0]</code>（取乘积的低 32 位）</td></tr><tr><td><code>mulh</code></td><td>Multiply High</td><td><code>0x1</code></td><td><code>rd = (rs1 * rs2)[63:32]</code>（有符号乘法，取高 32 位）</td></tr><tr><td><code>mulhsu</code></td><td>Multiply High Sign/Uns.</td><td><code>0x2</code></td><td><code>rd = (rs1 * rs2)[63:32]</code>（有符号与无符号乘法，取高 32 位）</td></tr><tr><td><code>mulhu</code></td><td>Multiply Unsigned</td><td><code>0x3</code></td><td><code>rd = (rs1 * rs2)[63:32]</code>（无符号乘法，取高 32 位）</td></tr><tr><td><code>div</code></td><td>Divide</td><td><code>0x4</code></td><td><code>rd = rs1 / rs2</code>（有符号除法，取商）</td></tr><tr><td><code>divu</code></td><td>Divide Unsigned</td><td><code>0x5</code></td><td><code>rd = rs1 / rs2</code>（无符号除法，取商）</td></tr><tr><td><code>rem</code></td><td>Remainder</td><td><code>0x6</code></td><td><code>rd = rs1 % rs2</code>（有符号除法，取余数）</td></tr><tr><td><code>remu</code></td><td>Remainder Unsigned</td><td><code>0x7</code></td><td><code>rd = rs1 % rs2</code>（无符号除法，取余数）</td></tr></tbody></table><p>这组指令设计的核心物理矛盾在于数据位宽的溢出。当物理电路执行两个 32 位整数的乘法运算时，其产生的最大物理输出结果需要 64 根导线，即 64 个比特位才能无损承载。</p><p>在 RV32 架构下，微处理器内部的单一通用寄存器物理位宽被硬性限制为 32 位。由于一个物理卡槽无法吞下 64 位的电平信号，硬件电路在输出时必须对数据进行物理截断。RISC - V 采用了两次读取的策略：<code>mul</code> 指令用于将硬件乘法器底部的 32 根导线（低 32 位）连接到目标寄存器；而 <code>mulh</code> 系列指令则用于将硬件乘法器顶部的 32 根导线（高 32 位）连接到目标目标寄存器。根据参与运算的数据是有符号补码还是无符号纯二进制，系统提供了不同的 <code>mulh</code> 变体以确保最高位（符号位）扩展时的物理正确性。</p><p>举个例子：</p><table><thead><tr><th>地址</th><th>机器码</th><th>意思</th><th>注释</th></tr></thead><tbody><tr><td><code>0x00</code></td><td><code>0x000100b7</code></td><td><code>lui x1, 0x10</code></td><td>通过高位立即数加载，<code>x1</code> 的物理状态变为 <code>0x00010000</code></td></tr><tr><td><code>0x04</code></td><td><code>0x00108093</code></td><td><code>addi x1, x1, 1</code></td><td><code>x1</code> 与 1 相加，其状态确立为被乘数：<code>0x00010001</code></td></tr><tr><td><code>0x08</code></td><td><code>0x00080137</code></td><td><code>lui x2, 0x80</code></td><td><code>x2</code> 的物理状态被确立为乘数：<code>0x00080000</code></td></tr><tr><td><code>0x0c</code></td><td><code>0x022081b3</code></td><td><code>mul x3, x1, x2</code></td><td>执行乘法，并将结果的低 32 位截断后存入 <code>x3</code>，此时 <code>x3 = 0x00080000</code></td></tr><tr><td><code>0x10</code></td><td><code>0x02209233</code></td><td><code>mulh x4, x1, x2</code></td><td>执行乘法，将结果的高 32 位截断后存入 <code>x4</code>，此时 <code>x4 = 0x00000008</code></td></tr></tbody></table><p>程序首先利用 <code>lui</code>（向左偏移 12 位）和 <code>addi</code> 指令，在 <code>x1</code> 寄存器中构造了十六进制数值 <code>0x00010001</code>。随后通过 <code>lui</code> 在 <code>x2</code> 寄存器中构造了十六进制数值 <code>0x00080000</code>。</p><p>当在内存地址 <code>0x0c</code> 和 <code>0x10</code> 触发乘法运算时，硬件乘法器接收这两个 32 位的输入电平，在内部产生一个 64 位的完整结果。从数学逻辑上验算：<code>0x00010001</code> 乘以 <code>0x00080000</code>，其完整的 64 位十六进制结果为 <code>0x0000000800080000</code>。在地址 <code>0x0c</code> 处，<code>mul</code> 指令激活了捕获低 32 位信号的数据通路，将其引流至寄存器 <code>x3</code>，因此 <code>x3</code> 呈现为 <code>0x00080000</code>。在地址 <code>0x10</code> 处，<code>mulh</code> 指令重新执行乘法（在实际的高性能微架构实现中，乘法器可能会缓存上一次的 64 位结果以避免重复计算），并激活捕获高 32 位信号的通路引流至 <code>x4</code>，因此 <code>x4</code> 呈现为 <code>0x00000008</code>。此时，<code>x4</code> 和 <code>x3</code> 在物理上共同组合成了完整的 64 位乘积。</p><p>最后，教程指出了硬件除法器在面临「除数为零」这种未定义数学行为时的物理响应机制。在某些复杂的体系结构（如 x86）中，除以零会在硬件级别强行触发一个异常中断，迫使操作系统介入处理（通常表现为程序崩溃）。但在 RISC - V 架构中，为了维持处理单元和流水线控制逻辑的绝对精简，除以零被规定为一种不会引发物理中断的常规操作。当除法器电路接收到除数为 0 的电平信号时，其硬件连线会产生一个固定的输出：将目标寄存器内的所有物理比特位强制拉高至 1。全 1 的二进制状态在有符号补码逻辑中等同于数值 -1（即十六进制的 <code>0xFFFFFFFF</code>）。这就意味着，硬件将除以零的安全边界检查责任完全推卸给了软件。程序员或编译器必须在使用 div 指令之前，通过条件分支指令（如 <code>beq rs2, x0, exception_label</code>）主动探测除数寄存器的电平状态，以防止错误的 -1 污染后续的数据流计算。</p><h4 id="rv64"><a class="markdownIt-Anchor" href="#rv64"></a> RV64</h4><p>RV64 架构的基础执行逻辑与 RV32 完全一致。这种一致性体现在操作码、指令寻址格式以及寄存器契约的完全复用上。其根本的物理变化在于微处理器内部数据通路的全面拓宽。在 RV64 架构中，微处理器内部的 32 个通用物理寄存器（<code>x0</code> 至 <code>x31</code>）、ALU 的内部逻辑门阵列，以及连接各部件的内部数据总线，其物理导线的数量都被硬性地增加到了 64 根。这意味着，当你在 RV64 上执行一条基础的 <code>add</code> 或 <code>addi</code> 指令时，硬件电路默认激活的是一个 64 位的全加器，它会同时处理 64 位的电平信号，并将 64 位的完整结果写回目标寄存器。</p><p>然而，计算体系中存在大量依赖 32 位物理边界的软件逻辑。例如 C 语言中标准 <code>int</code> 数据类型在大多数现代系统中被强制定义为 32 位。在纯粹的 32 位物理硬件上，当一个 <code>int</code> 类型的整数不断递增并超越其最大物理承载上限时，最高位的进位信号会因为没有更多的物理导线而自然丢失，从而精确的截断与符号位翻转（即溢出变成负数）。如果将这种运算直接放到 RV64 的 64 位加法器中执行，进位信号会顺理成章地流向第 33 根导线，数值会继续平滑增大，原本预期的 32 位溢出截断行为在物理上彻底失效了，这将导致严重的软件逻辑谬误。</p><p>为了在 64 位的物理硬件上精准模拟 32 位的截断环境，RV64 指令集专门引入了带有 <code>w</code> 后缀的指令子集。在 RISC - V 的标准术语中，「字」（Word，即 <code>w</code>）被严格且永久地定义为 32 个比特位，而 64 位的数据被称为「双字」（Doubleword）。教程中提到的 <code>addw</code>、<code>addiw</code>、<code>sllw</code> 和 <code>mulw</code>，就是专门针对 32 位电平信号设计的截断运算指令。</p><p>当微处理器的指令解码器读取到带有 <code>w</code> 后缀的机器码时，控制电路会向算术逻辑单元下达特定的屏蔽指令。此时，ALU 在获取源寄存器的数据时，会从物理上切断或忽略第 32 根至第 63 根导线的输入信号，仅仅提取寄存器最底部的 32 根导线（即低 32 位）的状态作为有效的运算输入。在 ALU 内部执行完纯粹的 32 位运算并得出结果后，硬件电路还需要完成最后一步关键的物理填充：符号扩展。</p><p>由于目标寄存器本质上仍然是一个 64 位的物理卡槽，ALU 不能仅仅将低 32 位的结果写回而任由高 32 位保留先前的垃圾电平信号。根据 RISC - V 的规范，硬件电路必须提取这 32 位运算结果的最高位（即第 31 根导线，符号位）的电平状态，并通过物理连线将其强行复制、覆盖到目标寄存器高段的全部 32 根导线上。这种由底层电路强制执行的符号扩展机制，确保了 32 位截断运算产生的数据，在被放回 64 位的寄存器空间后，依然能够维持其在数学逻辑上的正负一致性。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;学习汇编语言的笔记。&lt;/p&gt;</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="RISC-V" scheme="https://blog.cytrogen.icu/tags/RISC-V/"/>
    
    <category term="Assembly" scheme="https://blog.cytrogen.icu/tags/Assembly/"/>
    
  </entry>
  
  <entry>
    <title>读《大闸蟹》</title>
    <link href="https://blog.cytrogen.icu/posts/b084.html"/>
    <id>https://blog.cytrogen.icu/posts/b084.html</id>
    <published>2026-02-23T05:00:00.000Z</published>
    <updated>2026-07-06T21:52:06.978Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>这是陈昌平在零几年写的一篇短篇小说。</p><span id="more"></span><p>这篇小说整体来说，带有许多影射文革时代的内容。</p><p>故事开始，主角刘爱国从苏州回到辽北，带来了三只阳澄湖的大闸蟹。它们丰腴饱满，以至于刘爱国描述它们为「脑满肠肥的南方大地主」。</p><p>为什么是这样的比喻？这些大闸蟹来自于南方不假，但为什么要描述为「肥地主」呢？这便是这篇小说的一个特色，它采取了主人公刘爱国的视角，在生活的方方面面透露出经历过文革时代的人们如何看待这些地方。将「肥硕的东西」下意识想成是「肥地主」便是这样。实际上，历史上的地主能吃成「脑满肠肥」的并不多，会将「地主」和「脑满肠肥」绑定在一起的，通常是政治宣传。</p><p>除开中文课上教授提到的「文革」，我个人认为这篇小说里，出现的「地域」也是个重点。刘爱国看到蟹壳上印着激光防伪的标志，和经纪公司的信息，心想南方人有着出色的商品意识。</p><p>数十年前，我经常会接收到的一个信息便是中国的南北之争，例如一些文章说南方人喝茶谈生意，所以南方人更容易出大老板，而北方人喝酒吹牛皮，所以北方人更容易出败家子等等 —— 这样的观点现在听来自然是蠢到家了，不过在中国开始在南方建设经济区，以及北方下岗潮的引发，或许当时也会有人认为是这样吧。总之，「地域黑」永远是不可取的。</p><p>刘爱国担心这些大闸蟹是假货，于是拨号上网查阳澄湖大闸蟹的特征，并一一验证，发觉自己确实买的是真货。此处有意思的在于刘爱国的用词，他先是用了「验明正身」这个成语，接着称呼这些大闸蟹「根红苗正」。</p><p>「验明正身」指的是，查验死刑犯是否为其本人，毕竟执行死刑前可不能弄错人了。验证大闸蟹是否是阳澄湖的真货，有必要使用对死刑犯用的词儿吗？</p><p>再就是「根红苗正」。这个成语很简单，在文革时期意味着家庭出身好。那什么是家庭出身好的，那自然便是「红色的根」，也就是父母亲也是中国共产党的人了。所以这个成语也特指「中国共产党」。</p><p>刘爱国形容个大闸蟹，怎么口里蹦出来这么多这样的词儿？这是因为他是出生在文革时代的人，就连用词都受了那个时代的影响。</p><p>下一幕中，刘爱国给儿子打电话。小说先是特意提到儿子在省重点中学，还是市实验中学里住校上学，接着又是刻意说刘爱国打电话时，是在「向儿子报到」。</p><blockquote><p>爸爸回来啦。爱国向儿子报到。</p><p>嗯。儿子的声音像领导一样稳重和漠然。</p><p>周末回家有好东西吃了。爱国抛出了主题。</p><p>什么东西？儿子声音一下子升高了。</p><p>你猜。爱国说。</p><p>嗯 —— 炸鸡翅。这是儿子喜欢吃的东西。</p><p>不是。</p><p>是…… 螃蟹。这是儿子更喜欢吃的东西。</p><p>爱国笑了。儿子马上明白了，大声问，是赤甲红还是梭子？馋儿子最喜欢吃的就是蟹子里的赤甲红了。</p><p>都不是。爱国笑吟吟地回答，顿了一下，又一字一句地说，这可不是一般的螃蟹啊，这是阳澄湖的大、闸、蟹！</p></blockquote><p>陈昌平用了短短一个对话，便能让读者快速搞明白刘爱国和儿子之间的关系到底是什么样的。刘爱国又是要向儿子报到，又是说儿子的声音像个领导。而儿子起初的声音很是冷淡，好像并不关心父亲，直到父亲提到了好吃的东西，态度才变好。也就是说，刘爱国在家庭里，并没有所谓「父亲的尊严」，除非能向儿子提供好吃的。</p><p>之后儿子问了刘爱国什么是阳澄湖大闸蟹。刘爱国的脑海里出现了这样的思考流程：阳澄湖是著名的沙家浜，是阿庆嫂智斗的地方，但儿子不懂这些。如果用儿子懂的语言来说，赤甲红是桑塔纳，而大闸蟹是奔驰。</p><p>《沙家浜》是文革时期相当有名的八大样板戏之一。我没有看过样板戏，所以不评价了。不过在讨论这篇小说之前，中文课有个异步线上讨论，是和延安文艺座谈会有关的。那次讲话要求文艺工作者放下身态，走到底层群众中，用群众看得懂的形式创作。许多同学提到这个方案相当成功，不仅快速团结了底层群众，也影响到了后来中国文学创作的底色。</p><p>刘爱国的这个思考流程有这些值得思考的点：一、在他的认知图谱中，地理是被样板戏定义的；二、使用汽车品牌来划分螃蟹种类。不论是桑塔纳还是奔驰，都是物质符号。奔驰要比桑塔纳更为「高档」，且奔驰完全出自于德国公司，而桑塔纳是中国第一款合资车型。</p><p>「车」在刘爱国接下来的回忆中又出现了一次。儿子开学当天，刘爱国借了辆桑塔纳来接送儿子，未曾想学校门口全是好车，尾号一个比一个炫富 —— 但是一个学校能开来全市的好车么？刘爱国能借车，他人就不能借车了么？或许除了刘爱国有攀比心，其他人也想要攀比攀比。不过在刘爱国的心里，他在社会竞争中依然失败了，不仅买不起车，连借来的车都不如别人的高档。作为补偿，既然儿子爱吃的螃蟹还是买得起的，那不如等每次儿子回家，都买上只螃蟹犒劳犒劳。</p><p>次日，刘爱国发现大闸蟹丢失，急眼、只能一个个地方都找过去。有趣的是他找到的那些不是大闸蟹的东西：「失踪已久的结婚证」，意味着对婚姻的不重视；「爱国的中专毕业证」，文革期间学校不大上课的话，这个毕业证并不能代表刘爱国是否是「知识分子」；「儿子一年级时『最有意义的一天』」，我相信中国学生没少写过这类作文吧！刘爱国将它和其他重要文件收集起来，意味着他重视儿子的教育，以及这可能是儿子第一次一个人写作文，具有一定的意义；「洗衣机的保修单」，在二十一世纪刚开始的时候，买得起洗衣机并不常见，想必也是一种资产上的炫耀吧。</p><p>最后一个则是：</p><blockquote><p>甚至还找到了爱国二十多年前的日记本。日记本是红色的塑料皮，发硬了，上面印着烫金的「为人民服务」，洇着蓝钢笔水的扉页上，中学生刘爱国歪扭而又工整地抄录着《钢铁是怎样炼成的》里面的一段话 —— 人的一生应当这样度过：回首往事，他不会因为虚度年华而悔恨，也不会因为碌碌不为而羞愧；临死的时候，他能够说：我的整个生命和全部精力，都…… 以下的字被墨水淹没了。</p></blockquote><p>被墨水淹没的后续虽然小说里没有提到，不过其实是：</p><blockquote><p>已经献给世界上最壮丽的事业 —— 为人类的解放而斗争。</p></blockquote><p>有些同学读过这本书，因为它是学校的必读书籍之一。不过我没有读过这本书，只是上学期间听说过。教授借此扩展了下话题，告诉我们它在文革期间其实是禁书，因为它的作者是苏联人，而当时中苏的关系并不好。但《钢铁是怎样炼成的》的中译本在学生之间很是有名，早就偷偷传开了。大家不仅会偷读，还会手抄下来。</p><p>说回小说的内容。很明显，这本日记本的存在暗示了刘爱国小时候的理想主义早已在琐碎且物欲的现实生活面前变得模糊不清：它有大闸蟹重要么？能让人吃好饭么？</p><p>刘爱国出门找大闸蟹时，陈昌平又描写了他所居住的桃源小区：一个典型的北方重工业城市中的普通居住区。文中提到的「安居工程」是中国政府为中低收入城市居民实施的保障性住房项目，点明了刘爱国并不宽裕的工薪阶层角色 —— 实际上，先前有很多地方都介绍了他的背景，并不是一个多么富足的人。</p><p>陈昌平也强调了刘爱国在此居住七八年却与邻居毫无来往，揭示了现代城市生活中的人际疏离。这倒也解释了后续发生的种种。</p><p>刘爱国上班去，知道同样买了阳澄湖大闸蟹的大李子不仅吃了，还对此给出了极高的评价，心里不舒坦。中午儿子罕见地主动打电话回来，询问大闸蟹怎样，让他的心情又变差了不少。挂了电话，他跑去上海菜馆看大闸蟹，却发现里面的螃蟹和大闸蟹没有一点共同特征，领班还强行将它们标榜为「最正宗的大闸蟹」，并以此贬低其他产地的河蟹。这种推销让刘爱国确信，这座北方老工业城市里的人根本不具备鉴赏南方高档消费品的认知水平。</p><p>从这里之后，才是这篇小说的「正文」。刘爱国在公告栏上贴了个启事，希望拾到自己蟹子的人可以归还给自己。谁曾想，来的是来纠正语病的孙老师，蟹子的下落依然不知道。这一段再次呼应和坐实了先前「人际关系冷漠」的描写。孙老师作为刘爱国自认「最熟悉的邻居」，其所谓的「热心」仅仅停留在居高临下的知识纠错与说教层面，对刘爱国丢失物品的实际焦虑毫无共情。</p><p>被当面指出低级错误也让刘爱国感到了文化与体面上的双重难堪。先前就已经暗示过，刘爱国已经在家庭和社会层面上「失败」了。再加上孙老师对「几只蟹子」轻描淡写的态度，极大地刺激了刘爱国：在这个小区里，大众根本不具备识别阳澄湖大闸蟹高贵身份的认知能力。这两种感觉都迫使刘爱国重新打印了一份更加周密和庄重的第二版启事。</p><p>实际上，在教授讲解前，我对小灵通没有一个实际的概念，一直以为它是类似于诺基亚那样的手机品牌。其实它是一种无线通信工具，或者说是当地固定电话网络的无线延伸。另一个我不知道，但教授没有讲解的东西是「红塔山」，后面查了一下发现是中高档香烟。</p><p>贴完第二版启事后，刘爱国发现小区垃圾箱里有一个红色的蟹子壳，正是自己丢失的其中一只，已经被人吃干净了。邻居们的冷漠此时展示了出来：就算看到了刘爱国贴的启事，也不选择归还，反而是自己吃掉。</p><p>陈昌平在此处立刻描写了辽北的衰败现状。这座衰落，且物质相对匮乏的北方城市，与代表着南方精致生活和经济繁荣的阳澄湖大闸蟹形成了反差：大闸蟹在辽北的垃圾箱中竟惨遭粗暴对待并沦为残骸！要知道它在刘爱国心里，除了是高贵的食物外，还是刘爱国作为一个父亲的骄傲、对儿子的承诺。他鼻子一酸，心里骂自己没出息，这种生理上的悲伤反应让他感到羞耻。</p><p>回家后，刘爱国在启事的后面加了个附录，试图指导捡到剩余两只大闸蟹的人正确保存它们，以防它们在被归还前死亡，毕竟大闸蟹死后就不能吃了，儿子还有两天才回来呢。戏剧性的是，当他贴上附录后，他便看到了第二只被吃掉的大闸蟹 —— 这只螃蟹被吃得乱七八糟，好多肉都没吃干净，简直是暴殄天物。</p><p>愤怒的刘爱国接到了儿子主动打来的第二通电话。面对儿子那句「大闸蟹到底是什么滋味儿呢」，刘爱国罕见地呵斥了儿子。他不仅弄丢了原打算犒劳儿子的昂贵礼物，甚至连他自己也无从知晓这代表着阶层品味的大闸蟹究竟是何滋味儿。儿子的期待成了一种精神上的压迫，让他无法继续维系那个能为后代提供高级物质体验的父亲形象，这样的无力感，令他无处宣泄情绪，失控地攻击了儿子。</p><p>另一边，大闸蟹的象征意义逐渐发生了异化。起初它只是作为纯粹的犒劳物品存在的，然而随着它的丢失及其惨遭邻居随意丢弃，它脱离了单纯的食物属性，变成了刘爱国个人尊严以及对抗周围庸俗环境的心理寄托。当刘爱国发现大闸蟹被以极不讲究的方式糟蹋时，他感受到的是自身向往的精致生活被碾碎的屈辱。因此，他后期的所有偏执行为，都演变成了一场捍卫个人尊严的自救。就如他自己所说的，「这已经不是为了儿子了。」</p><p>刘爱国做了一份重要启事，整理了阳澄湖大闸蟹的所有知识，其字里行间的庄严感，与当年抄写革命宣言时的虔诚恐怕如出一辙吧。下班回来，他变态般地扒拉着小区的垃圾箱，并在旁边找到了一只完整的蟹子：天啊，它竟然在没有蟹八件的北方，被吃得很规范、很圆满、很精彩、很成功、很伟大！刘爱国满意、得意，又反省自己能不能像这个邻居一样，吃出如此美丽的大闸蟹。</p><p>在刘爱国这么想的时候，他还会在乎共产主义么？</p><p>周末儿子回来的那天，刘爱国买了三只赤甲红回家，好似大闸蟹是一场梦 —— 一场试图依靠消费符号来跨越阶级的梦。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;这是陈昌平在零几年写的一篇短篇小说。&lt;/p&gt;</summary>
    
    
    
    <category term="书评" scheme="https://blog.cytrogen.icu/categories/%E4%B9%A6%E8%AF%84/"/>
    
    
    <category term="社会学" scheme="https://blog.cytrogen.icu/tags/%E7%A4%BE%E4%BC%9A%E5%AD%A6/"/>
    
    <category term="短篇小说" scheme="https://blog.cytrogen.icu/tags/%E7%9F%AD%E7%AF%87%E5%B0%8F%E8%AF%B4/"/>
    
    <category term="历史" scheme="https://blog.cytrogen.icu/tags/%E5%8E%86%E5%8F%B2/"/>
    
  </entry>
  
  <entry>
    <title>4 个字符为一组构成的城市</title>
    <link href="https://blog.cytrogen.icu/posts/cf35.html"/>
    <id>https://blog.cytrogen.icu/posts/cf35.html</id>
    <published>2026-02-16T05:00:00.000Z</published>
    <updated>2026-02-19T07:42:07.353Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>从小时候记事起，我就有一个奇怪的习惯，那就是看到商店招牌，会自动将上面的字符以 4 个一组的形式排列起来。</p><span id="more"></span><p>比方说「江南皮革厂倒闭了，老板黄鹤带着小姨子跑路了」，在我的眼里会变成：</p><pre><code class="language-plaintext">江南皮革厂倒闭了，老板黄鹤带着小姨子跑路了</code></pre><p>正好多出来 1 个字符。</p><p>多出来的内容会让小时候的我感到既不开心，也不舒服。为了让自己开心起来，有时候我会强行将限制改成 3 个或者 5 个字符一组。这样做并不是特别容易，因为 4 个字符一组已经是我脑内的标准，突然换成别的总感觉怪怪的。</p><p>之后我常用的伎俩便是将余数加入到下一个招牌的计算中。</p><p>假设下一个招牌的内容是「我要金坷垃，非洲农业不发达，必须要有，金坷垃！」，那么排列就会加上刚才多出来的「了」：</p><pre><code class="language-plaintext">了我要金坷垃，非洲农业不发达，必须要有，金坷垃！</code></pre><p>哎，这下就可以被 4 整除了，内心一下子开心起来~</p><p>通常来说，我都是在乘车期间进行这些脑内操作的，比如跟着大人们坐出租车去什么地方，或者坐在电动车上，望着远处。我自小居住在一个城市里，无论是往哪边看去，都可以看到带有招牌的店铺。坐车是无聊的，为了让自己不无聊，我自行研发了这种小游戏，好让自己在什么时候都能游玩 —— 会这么说，是因为在我的记忆中，这种行为慢慢地也渗透到我的其他生活里：小时候翻开课本时，我会扫视一番页面上的内容，快速将里面的字符根据 4 个字符一组的方式排序。</p><p>现在想来，为什么孩童时期的我要这么做呢？不知道从什么时候开始，我看商店招牌再也不会去想要将字符分成 4 个一组了，乘车时望向窗外也只会发呆。</p><p>能够确认的是，它是我的强迫行为的一种。我小时候总是有一些现在看来都觉得莫名其妙的「秩序」，比方说喝粥时绝对不能在里面放任何东西。如果大人往我的碗里夹了肉或者榨菜，又或者不小心滴了点酱料进去，我会很难过，认为我的粥被玷污了、不再纯净。</p><p>我已经很难记起小时生活的点点滴滴，自然也不知道那时候的我是怎么想的、经历了什么才会这么想，所以我还是不揣测自己了吧。但我可以感觉出，我是一个很轴的人，且只生活在自己的世界里：一套独属于自己的逻辑，外界对我而言并不重要，因为是它们不遵守我的规则在先。</p><p>不过随着年龄的增长，经历了一个又一个事情，发现这个世界就是存在着余数、绝大多数事物都是无法被完美整除的 —— 有些能不能被「除」都是个问题。白粥也不可避免地会沾染上其他味道，毕竟再去取一个碟子装榨菜意味着需要多洗一个餐具。</p><p>现实总是塞满了需要我去重新适应的全新事物，而这些问题远比招牌上多出来的字符庞杂得多。所以那个坐在电动车后座的小孩，最好还是连同她那套规则一起，留在那条以 4 个字符一组构成的街道吧。</p><h3 id="bonus"><a class="markdownIt-Anchor" href="#bonus"></a> Bonus</h3><p>最近我知道了 <a href="https://blogblog.club/party">BlogBlog 同乐会</a>，相当于中文版的 IndieWeb Carnival。或许初来乍到的你也不知道 <a href="https://indieweb.org/IndieWeb_Carnival">IndieWeb Carnival</a> 是什么。简单来说，它是一个每月根据主办方提出的主题，让参与者们在自己的个人网站上发布该主题的博文，并投稿给主办方的活动。</p><p>这个月 BlogBlog 同乐会的主题是「只有我这样吗？！」。我心想该主题还蛮有趣的，所以快速动笔写了一下。不过写到后面，总感觉有些偏题 —— 应该没有关系吧，因为成年人的世界总是不遵守规矩的！</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;从小时候记事起，我就有一个奇怪的习惯，那就是看到商店招牌，会自动将上面的字符以 4 个一组的形式排列起来。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="投稿" scheme="https://blog.cytrogen.icu/tags/%E6%8A%95%E7%A8%BF/"/>
    
  </entry>
  
  <entry>
    <title>玩《茂林源记》</title>
    <link href="https://blog.cytrogen.icu/posts/cc52.html"/>
    <id>https://blog.cytrogen.icu/posts/cc52.html</id>
    <published>2026-02-15T05:00:00.000Z</published>
    <updated>2026-02-19T07:42:07.353Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>《茂林源记》，或称 Root（以下也这么称呼），是一个区域控制类桌游。虽然这么说，但它的标签还是很多的，例如德式桌游标准的得分制、应该被划分给美式桌游的阵营机制等等。我先前为这款游戏写过一些评价，本来没有打算继续去写该游戏的说明，但介于自己刚写了个扫雷的入门说明，最终还是写下了这篇文章。</p><span id="more"></span><p>首先需要说明，桌游和其他电子游戏一样，是一个很大的类。休闲的桌游，如爆炸猫，跟大型的桌游，如很知名的 D &amp; D，区别是很大很大的。在决定游玩 Root 之前，请务必考虑一下自己到底是什么桌游玩家 ——<span class="emphasis"> 愿意花时间钻研吗？愿意仔细阅读说明书，且游玩期间遇到不懂的地方也会去认真查询吗？</span></p><p>问这些问题的原因是，Root 其实卡在一个颇为尴尬的地方：它既没有大型桌游那么难懂，但入门门槛也足以劝退休闲玩家。这也是为什么我很难线下跟他人玩 Root，愿意尝试的就不多，看到说明书和规则书的还想继续玩的是少数；最麻烦的是教完一个人规则和至少一个阵营后，天也暗了，大家没有那么多空闲时间，只能等几个月再约。</p><p>好啦虽然我抛出了这么多预警，对于依然想要继续学习的你们来说，Root 可能并没有那么可怕！实际上，就像我刚才说的，它无法跟更大的桌游比较。既然只需要一天就能教会一个新人，它的困难程度可想而知，并没有那么高，难的地方只是它的阵营机制。</p><p>说了这么多，让我们回归正题吧，一起进入这片广大的茂林吧！</p><h3 id="基础规则"><a class="markdownIt-Anchor" href="#基础规则"></a> 基础规则</h3><p>Root 里，每个阵营的回合都结束后，一轮才算结束。也就是说，玩家甲开始回合，到玩家乙的回合结束，这算一轮。每个阵营的回合会经历三个阶段，也是三个时间段：清晨、白天和晚上。在这三个阶段里，不同阵营能够做的事情都不相同。</p><p>通常而言，在设置期间，每个玩家会获得自己的阵营板、阵营所需要的所有米宝和令牌，以及 3 张牌。说到卡牌，该游戏有三个基础类型，或者说领地类型：老鼠、兔子和狐狸，他们是这个森林里的老百姓，更详细的背景设定我之后会补充。该游戏的大多数卡牌都需要锻造后才能发挥作用。在 Root 里，如果手牌超过 5 张，就必须在晚上阶段结束时丢弃直到手上只有 5 张牌。</p><p>地图上的地点和路线都是固定的，不过地点的类型可以随机，不过我个人推荐在学会游玩 Root 之前，只玩它的默认地图，因为类型分布最为平均。</p><p>必须要记住的是，Root 是一个区域控制游戏，<strong>「占领的领地」和地点是两个不同的概念</strong>。当你的士兵米宝和建筑物在一个地点上，数量超过其他阵营的士兵和建筑物，就算占领了该地点。当移动士兵时，出发地点和目标地点必须至少有一个在你进行移动之前、被你的阵营占领。这是 Root 在移动士兵上的基础规则。一次可以移动的士兵数量是随意的，想要移动多少就移动多少。</p><p>再就是「建筑物」，查看地图时你会发现，地点上都有数个空格，这些便是放置建筑物的格子。当一个地点上没有空闲的建筑物格子，玩家们就不可以在该地点上放置更多的建筑物了。建筑物并不属于令牌的一种，令牌是圆形的，建筑物是方形的。建筑物在计算占领权会被算上，令牌则不算。</p><p>战斗需要用到两个骰子，这两个骰子都只能投出 0/1/2/3 这四个点数。假设玩家甲和乙丢出了 1 和 3 这两个点数，且甲和乙在这个地点上的士兵数量分别是 2 和 3。在 Root 的战斗中，发起战斗的一方会取点数最大的那个骰子，被攻击的一方则拿点数最小的骰子 —— 乙作为攻击方，一共有 3 个士兵，点数也是 3，这意味着他的 3 个士兵都可以各杀死一个敌人。尽管甲的士兵数量是 2，但拿到的 1 点数让他只能让 1 个士兵杀死一个敌人。结果就是，乙的 3 个士兵杀死了甲的 2 个士兵，多出了 1 次攻击，而甲的 1 个士兵杀死了乙的 1 个士兵。</p><p>当地点上的士兵都死掉了，多出来的攻击会算给令牌和建筑物。它们都不具备攻击能力，所以也无法战斗。如果攻击方攻击的地点上只有对方的令牌或者建筑物，那么无论投出多少点的骰子，都会另加 1 点伤害。并且，只要有 1 个令牌或者建筑物被摧毁，攻击者都可以额外拿取 1 分。如果有多个令牌或者建筑物，那么由被攻击的一方决定哪一个应当被移除。</p><p>要在 Root 里获胜，通常是靠先得到 30 分。至于如何得分，每个阵营的方式也都不一样。所以可以看出来，该游戏的绝大多内容都在阵营上，而因为阵营除了游侠这个特殊阵营外都不能重复，所以在游玩自己的阵营时，也需要提防他人的阵营得分。这也是 Root 入门时的难点： <strong>记住所有阵营的机制和得分方法</strong>。</p><h3 id="阵营机制说明"><a class="markdownIt-Anchor" href="#阵营机制说明"></a> 阵营机制说明</h3><h4 id="猫女侯爵"><a class="markdownIt-Anchor" href="#猫女侯爵"></a> 猫女侯爵</h4><p>也有翻译称其为「猫咪贵族」。在原文中用的 marquis 其实是法语的「女侯爵」的意思，这里就保留这层意思吧，不过后面都会简称为「猫咪」就是了。</p><p>猫咪们在打跑了原本统治了森林的「飞鹰王朝」后，决心一路向工业化进发 —— 砍树盖房子！猫咪可以放置三个种类的建筑物，且加分方式是靠放置建筑物。</p><p>猫咪在开局阶段里优先级最高，可以选择地图上的任意一个角落作为自己城堡的落脚点，然后可以在城堡所在的地点或者相邻的地点内免费放置一个伐木场、一个工坊，和一个招兵所。</p><p>我用了「免费」这个词，为什么呢，因为是「砍树」盖房子，原先这些建筑物都需要使用「木材」才能建造。木材作为一个令牌，又该如何获取呢？答案是靠猫咪的伐木场。嗯，这下便好理解了：猫咪通过建造伐木场来获取木材，又消耗木材来建造建筑物，建造建筑物还能加分，且场上相同类型的建筑物盖得越多、 加分越多。这便是猫咪主要的玩法。</p><p>猫咪的士兵足足有 25 个，到后面我介绍越来越多的阵营时，你便会发现这个数量有多么夸张。开局阶段里，猫咪需要在地图的所有地点上放置一个士兵，除了城堡斜对面的那一个角落。</p><p>清晨阶段，猫咪只能做一件事，那便是在场上所有伐木场所在的地点放置一个木材令牌，相当于每个伐木场都砍到了木头。白天阶段里则分两个步骤：一是激活场上的工坊来锻造卡牌，二是按照任意顺序和组合执行最多三项操作。</p><p>先说猫咪的锻造。卡牌的锻造条件都要求一个阵营的可锻造单位有足够的数量，且位于正确的地点类型。比方说有一张牌要求有两个兔子类型，那对于猫咪而言，就需要在兔子类型的地点内先建造两个工坊，才能锻造该卡牌。这些可锻造单位，一回合只能使用一次。这对猫咪来说，不是一个好兆头，因为锻造卡牌之前，猫咪需要先消耗木头和行动次数来建造建筑物。</p><p>再来说猫咪的行动：战斗、行军、招募、建造建筑物、加班。</p><p>其中战斗没什么好说的，剩下三个都有着猫咪自己的特色。行军是加强的移动，一次行军相当于移动两次，且移动时仍然可以随意决定要移动的士兵数量；招募会在每个招兵所所在的地点放置一个新士兵，不过该操作 <strong>每个回合只能执行一次</strong>。</p><p>建造建筑物需要单独拉出来说。一个玩家们经常忘记的猫咪规则是，想要建造建筑物的地点首先得是被猫咪占领的，且该地点需要和木材所在的地点形成一条完全被猫咪占领的路线才行。也就是说，<span class="emphasis">木材必须从猫咪占领的地点，通过一系列也被猫咪占领的地点，才能抵达猫咪打算建造建筑物的已被占领地点</span>。接着玩家需要在阵营板上选择建造哪一个建筑物、查看该建筑物如果被建造了需要消耗多少木材（每个类型的建筑物所需要的木材以及得到的分数都是独立开来的），并消耗这些木材。</p><p>猫咪也可以通过消耗一张手牌里的飞鹰类型的卡牌来为自己添加一次额外的操作次数。咦，什么是飞鹰类型？这是有别于基础三类型的第四个类型，对许多阵营而言，它可以被当成是「任意一个类型」，相当特殊。</p><p>至于加班，它需要你选中一个伐木场，并根据该伐木场所在的地点类型，消耗一张同类型的卡牌来获取一个木材令牌。因为飞鹰卡牌可以被视作任意一个类型，所以也可以用在这里。</p><p>到晚上阶段，猫咪需要补充一张手牌。如果招兵所被建造得够多，你会根据阵营板上的卡牌图标而获取额外的手牌。</p><p>最后说一下猫咪的被动技能：其他阵营不能在城堡所在的地点内放置任何令牌或者建筑物或者士兵，他们只能将士兵移动到该地点。每当任意数量的猫咪士兵从一个地点中被移除，猫咪可以选择消耗一张匹配该地点类型的卡牌，将这些被移除的士兵放置在城堡所在的地点。如果城堡被移除，它会在该局游戏内完全被移除，拿不回来。</p><h4 id="飞鹰王朝"><a class="markdownIt-Anchor" href="#飞鹰王朝"></a> 飞鹰王朝</h4><p>Eyrie 虽然是鹰巢的意思，但是「鹰巢王朝」总感觉不好听，故使用官方翻译「飞鹰王朝」。</p><p>飞鹰是森林过去的霸主，被猫咪打跑后，希望通过重新占领领地，来恢复自己的尊严。不过他们也是一个强迫症种族，每日的行动必须完全遵守「法令」的顺序，否则民众会陷入混乱、推翻当下的领袖。</p><p>清晨阶段按照顺序分为三个步骤：一、如果没有手牌，则抽一张牌；二、必须将手牌的一张或两张牌添加到法令区中，但只能有一张是飞鹰牌；三、如果地图上没有鸟巢建筑物，则在一个有最少士兵的空地上放置一个鸟巢和三个士兵。</p><p>白天阶段按照顺序分为两个步骤：一、激活鸟巢锻造卡牌；二、必须严格从最左边的列开始，向右依次结算法令。</p><p>不过在说明法令如何运作之前，我们需要先看一眼飞鹰的开局阶段。在游戏开始时，飞鹰玩家需要从四张领袖卡牌中选择一张作为初始领袖放置在阵营板上。每位领袖不仅拥有一个独特的被动技能，决定了两张初始大臣卡牌（两张固定视为飞鹰类型的卡牌）在法令区四个列中的初始位置。选定领袖后，飞鹰需要在地图上猫咪城堡斜对角的那个地点，放置一个鸟巢以及六个士兵。</p><p>该阵营最为重要的机制有且只有一个：<span class="emphasis">法令</span>。飞鹰的阵营板上有一个分为四个栏位的法令区，从左到右依次为招募、移动、战斗和建造。在每一个单独的列中，如果有两张或以上的卡牌，玩家可以按任意顺序解决该列里的所有牌，但对于每一张牌，玩家都必须切实执行其所在列对应的操作。</p><p>招募要求玩家在带有与卡牌类型相符、且已经建有鸟巢的地点上放置一个士兵；移动要求玩家从与卡牌类型相符的地点出发，移动至少一个士兵到其他相邻地点，前提是移动的基础条件可以被满足；战斗要求玩家在带有与卡牌类型相符的地点上，主动发起一场战斗；建造要求玩家在一个被自己占领、卡牌类型相符且当前没有鸟巢的地点上，放置一个新的鸟巢。</p><p>这一机制是极其死板的。如果在解决法令的过程中，玩家因为版图局势或者自身资源限制，无法完全执行某一张卡牌对应的一项操作，飞鹰就会立即陷入动乱 —— 当天的白天阶段会被立即强制中止。玩家会因为法令区中包含的每一张飞鹰类型的卡牌而失去 1 分，飞鹰也是唯一一个会在游戏中失去分数的阵营。随后，整个法令区除了两张初始的大臣卡牌外，所有的手牌都会被清空弃置。触发动乱的现任领袖必须下台，玩家需要从备选的领袖中挑选一位接任。新领袖的上台会改变初始卡牌所在的列数位置，玩家也必须在接下来的回合里重新构筑整个行动链条。</p><p>如果飞鹰成功且完整地解决了白天的所有法令，便能顺利进入晚上阶段，这也是其核心的得分环节。飞鹰会根据地图上现存的鸟巢总数，直接获取阵营板上对应位置标明的分数。鸟巢铺设得越多，每回合自动获取的分数就越高。计分结束后，飞鹰进行手牌抽取，抽牌的具体数量同样由版图上的鸟巢数量决定。</p><p>最后说一下飞鹰的被动技能。作为森林过去的领主，当一个地点上飞鹰的士兵以及建筑物的数量，和其他阵营的士兵以及建筑物的数量，相同时，默认飞鹰占领该领地。飞鹰也藐视贸易，锻造物品时会忽略列出的分数，而只获得 1 分。</p><h4 id="森林联盟"><a class="markdownIt-Anchor" href="#森林联盟"></a> 森林联盟</h4><p>在猫咪和飞鹰天天打架的时候，森林的老百姓坐不住了…… 联盟需要努力赢得森林里对现状不满的各种动物的同情，大家联合起来，将女侯爵还是王朝都赶出森林！</p><p>森林联盟是一个起步极晚但爆发力极强的阵营。与其他阵营不同，联盟在开局阶段的地图上没有任何实质性的棋子，只有阵营板上的 3 个基地、10 个民意令牌以及 10 个士兵。</p><p>联盟的运作高度依赖一个独立于玩家手牌的特殊卡牌区域 —— 支持者牌堆。支持者牌堆里的卡牌面朝下放置，不计入手牌上限，只有联盟玩家可以查看，且专门用来执行联盟的核心行动。如果联盟在地图上没有建立任何基地，该牌堆的容量上限仅有 5 张，超出部分必须被直接弃置；而一旦地图上存在至少一个联盟基地，支持者牌堆的容量便没有限制。</p><p>联盟拥有两个让其他阵营极为头疼的被动技能。首先是民意机制。每当其他玩家移除了地图上的民意令牌，或者将任何士兵移动到一个有民意的地点时，该玩家必须从自己的手牌中强制上交一张与该地点类型相符的卡牌，并将其加入联盟的支持者牌堆。如果该玩家手中没有对应类型的卡牌或者飞鹰卡牌，则必须向联盟玩家展示手牌自证，随后联盟会从公共牌堆顶部抽取一张牌加入支持者牌堆。</p><p>另一个被动技能是「游击战」。这是整个 Root 游戏中，强度最为可怕的被动技能：在所有战斗中，只要联盟是作为防守方被攻击，那么联盟始终会拿取点数较大的骰子作为自己的命中数，而攻击方只能拿取较小的骰子。这意味着主动攻击联盟很多时候只会被联盟反杀。</p><p>既然提到了骰子，我想要再深入讲解一下 Root 骰子的机制。已知每枚骰子有四个面，点数是 0/1/2/3，因此投掷结果是由两枚骰子组成的 16 种等概率组合构成的样本空间。在这个样本空间中，取最大值的概率分布是不均匀的。两枚骰子最大值为 0 的组合仅有 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mn>0</mn><mo separator="true">,</mo><mn>0</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(0,0)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">0</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord">0</span><span class="mclose">)</span></span></span></span> 这一种，概率为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mi mathvariant="normal">/</mi><mn>16</mn></mrow><annotation encoding="application/x-tex">1/16</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mord">/</span><span class="mord">1</span><span class="mord">6</span></span></span></span>；最大值为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn></mrow><annotation encoding="application/x-tex">1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span> 的组合有 3 种，概率为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>3</mn><mi mathvariant="normal">/</mi><mn>16</mn></mrow><annotation encoding="application/x-tex">3/16</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">3</span><span class="mord">/</span><span class="mord">1</span><span class="mord">6</span></span></span></span>；最大值为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn></mrow><annotation encoding="application/x-tex">2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span></span></span></span> 的组合有 5 种，概率为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>5</mn><mi mathvariant="normal">/</mi><mn>16</mn></mrow><annotation encoding="application/x-tex">5/16</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">5</span><span class="mord">/</span><span class="mord">1</span><span class="mord">6</span></span></span></span>；而最大值为 3 的组合最多，共有 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>7</mn></mrow><annotation encoding="application/x-tex">7</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">7</span></span></span></span> 种，概率为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>7</mn><mi mathvariant="normal">/</mi><mn>16</mn></mrow><annotation encoding="application/x-tex">7/16</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">7</span><span class="mord">/</span><span class="mord">1</span><span class="mord">6</span></span></span></span>。</p><p>也就是说，掷出 2 点和 3 点的概率加在一起，正好是 75%。如果计算较大值的数学期望，就会是 2.125，而较小值的数学期望仅为 0.875。在基础规则下，主动进攻方有着绝对的火力优势，然而「游击战」强制反转了这一判定规则。只要森林联盟作为防守方被攻击，从概率论的角度来看，这一反转让攻击方的单次命中期望瞬间从 2.125 骤降直 0.875，而联盟的防守反击期望则从 0.875 飙升至 2.125。</p><p>清晨阶段是联盟扩张与爆发的核心时间段，分为「起义」和「散播民意」两步。</p><p>起义是联盟建立基地的唯一方式，玩家需要选择一个已有民意令牌且类型与阵营板上未建基地相符的地点，随后从支持者牌堆中消耗两张匹配该地点类型的卡牌。起义一旦爆发，该地点上的所有敌方棋子，包括士兵、建筑物和各种令牌，将被瞬间<span class="emphasis">全部</span>清空（联盟也会获取摧毁建筑物和令牌所得的分数）。接着，联盟会在该地点放置对应的基地，并根据目前地图上与该基地类型相符的民意令牌总数，放置等量的士兵，最后再将一名士兵放置到阵营板的教官区。</p><p>执行完起义后，联盟可以进行散播民意来获取分数。玩家必须选择一个与现有民意地点相邻的无民意地点（若地图上完全没有民意，则可任选地点）。根据民意令牌轨道上标明的成本，玩家需要从支持者牌堆中消耗对应数量且与目标地点类型匹配的卡牌，将民意放置上去并立即获得轨道上显示的分数。</p><p>需要注意的是戒严规则：如果目标地点内驻扎着至少三名属于同一敌方阵营的士兵，联盟在传播民意时必须额外多消耗一张匹配的支持者卡牌。</p><p>白天阶段，联盟可以进行手牌和支持者牌堆的资源转化。联盟可以执行动员，将手中的任意卡牌放入支持者牌堆中。同时也可以执行训练，通过消耗手中一张与地图上已有联盟基地类型相匹配的卡牌，将一名士兵放置到教官区。必须要注意的是，联盟只有 10 个士兵，放置多少个到教官区、保留多少个士兵在地图上，是游玩联盟阵营时必须要考虑到的问题。此外，联盟的卡牌锻造也在白天阶段进行，与其他阵营依赖特定的建筑物不同，联盟是通过激活地图上对应类型的民意令牌来完成锻造的。</p><p>夜晚阶段则是联盟进行常规版图互动的时刻。联盟可以根据阵营板上现有的教官数量，执行同等次数的军事行动。军事行动包含四种选项：移动士兵、发起战斗、在拥有基地的地点招募一名士兵，或是执行组织行动。组织行动允许联盟从一个没有民意的地点移除一名自己的士兵，并直接在那里放置一个民意以此获取分数，这是一种不消耗支持者卡牌来传播民意的方式。</p><p>在所有军事行动结束后，联盟进行常规的抽取手牌步骤，并将超出五张上限的多余手牌弃置。每次基地被敌人摧毁时，联盟必须丢弃支持者牌堆中所有与该基地同类型的卡牌，并损失一半的教官（向上约）。</p><h4 id="神秘游侠"><a class="markdownIt-Anchor" href="#神秘游侠"></a> 神秘游侠</h4><p>在猫咪、飞鹰和联盟互相牵制的期间，森林里总有一些流浪者，想要趁机提升自己在森林中的声望 —— 这当然也包括了恶名。与那三个势力截然不同的是，游侠在地图上只有一个棋子，那就是游侠自己。游侠并不属于士兵，因此永远无法占领任何地点，也无法阻止其他阵营占领地点，且无法被移除。但这种孤立也赋予了游侠移动时可以完全无视出发地和目的地的占领权限制。</p><p>游侠的行动与生存完全依赖于他的物品系统。无论是移动、战斗、探索废墟获取新装备，还是完成任务与援助他人，都需要消耗背包或物品栏中对应的、未损坏的物品。</p><p>这里需要提到 Root 的物品系统。物品可以通过锻造特定的卡牌来获取，对于不会用到物品的阵营来说，锻造出来的物品只会从公共物品区取出一个、放到一边。当公共物品区里没有物品了，那么制造物品的卡牌便无法被锻造，自然也不能用来锻造得分。</p><p>而对于会使用到物品的阵营来说，物品还可以通过地图上的废墟来获取。游侠能够探索这些废墟、获取废墟内的物品，并且将废墟移除、变成一个空的建筑物格子。如果本局游戏里没有能够移除废墟格子的阵营，那么这些废墟格子会一直占着空闲的建筑物格子。</p><p>对游侠来说，物品具有两个通用的属性：是否被使用，以及是否损坏。这两个属性是<span class="emphasis">完全独立</span>的。在遭遇战中，由于游侠没有士兵可供阵亡，他所拥有的未损坏物品总量便等同于他的生命值上限，而未损坏的物品「剑」的总数，等同于能够掷出的最大命中数，无论是否被使用。每当游侠受到一点伤害，他就必须将一件未损坏的物品移入损坏区。如果身上没有任何完好的物品，游侠则忽略所有剩余的伤害。</p><p>处理与其他阵营的社交关系是游侠核心的战略维度。通过消耗物品并向其他玩家支付对应地点类型的卡牌，游侠可以执行「援助」行动。这不仅能从其他玩家那里换取他们锻造好的物品，还能逐步提升双方的关系轨道。当关系达到同盟状态时，游侠便赢得了该阵营的信任，不仅每次援助都能获得额外分数，还能在白天行动时直接裹挟盟友的士兵一同移动甚至发起进攻。</p><p>反之，如果游侠在游戏中移除了任何一个非敌对阵营的士兵，双方的关系会立刻跌入敌对状态。虽然游侠进入有敌对士兵驻扎的地点时需要额外消耗用于移动的物品，但这开启了另一条得分途径：在游侠自己的回合内，每在战斗中移除一个敌对阵营的部件（无论士兵、建筑还是令牌），游侠都能获得 1 分。这种得分机制太可怕，以至于官方需要在比赛中特别削弱游侠，才能平衡游戏。</p><p>游侠的开局阶段中，玩家需要选择一个游侠角色。不同的游侠角色开局携带的物品不同，且技能也都不一样。接着玩家需要将游侠米宝放置在森林里，注意，并不是在地图的格子内，而是其他阵营都无法进入的「森林」里。然后玩家会获取一个任务牌堆，抽取 3 张、面朝上放在阵营板的附近。任务需要游侠到达任务牌上类型相符的地点，并使用任务所需要的未使用物品，以获取奖励：得分或者抽卡。随着同类型的任务做得越来越多，得分以及抽卡的数量也会越来越多。不过在我看来，靠任务得分并不是一个很棒的选择。</p><p>清晨阶段，3 个已使用的物品会变成未使用状态，且每有 1 个物品「水壶」，还可以多刷新 2 个物品。接着游侠可以无消耗地移动到相邻的地点或者森林中，无论该地点是否被敌对阵营占领。</p><p>早上阶段，游侠可以按照任意顺序来使用自己的物品：</p><ul><li>移动：使用 1 个物品「靴子」；</li><li>战斗：使用 1 个物品「剑」；</li><li>探索：使用 1 个物品「火把」，探索后获得 1 分；</li><li>援助：使用任意 1 个物品。就算是敌对阵营，游侠也可以援助，但是关系不会变好；</li><li>任务：使用任务牌上所要求的物品；</li><li>打击：使用 1 个物品「弩」，直接移动当前所在地点的士兵或者建筑物或者令牌。打击并不算战斗，但是算移除士兵或者令牌，因此不会触发游侠杀害士兵得分的机制，但是会触发联盟民意被移除的机制；</li><li>制作：选中一张手牌，在类型相符的地点上使用 1 个物品「锤子」来锻造它。因为游侠只能一次出现在一个地点上，意味着所有要求多个地点类型的卡牌都无法被锻造；</li><li>修复：使用 1 个物品「锤子」，将一个已损坏的物品变成未损坏的状态。不过如果该物品也出于已使用的状态，那么修复并不会让它也变成未使用的状态；</li><li>特殊行动：游侠角色的技能不同，在进行的特殊行动也不同，不过使用的都是物品「火把」。例如「猎人」角色就可以一次性修复 3 个物品，代价是白天阶段会被立即结束。</li></ul><p>晚上阶段中，如果游侠处于森林，那么所有已使用或者已损坏的物品都会变成未使用或者未损坏的物品，相当变态。接着抽取卡牌，每有 1 个物品「金币」都会额外抽取 1 张。若手牌多于 5 张，则丢弃手牌直到手牌数为 5 张。最后，游侠要检查物品的容量。如果未损坏和已损坏的物品总数超过物品上限（默认 6，每有 1 个物品「背包」便多出 2），那就需要丢弃物品，直到物品数量等于物品上限。这里的「丢弃」并不代表着将物品放回公共物品区，被丢弃的物品不会再回来。</p><h3 id="结语"><a class="markdownIt-Anchor" href="#结语"></a> 结语</h3><p>本篇文章仅供参考。在实际的游玩时，我建议还是阅读官方提供的规则书，或者说 <a href="http://root.livingrules.io/">这个网站</a>。为了减少篇幅，我没有细讲许多内容，只是将游戏的大致规则讲了一遍。</p><p>Root 除了实体桌游外，还有电子版本。你可以从 Steam 上购买下载，也可以在 Google Play 或者 App Store 中购买下载。购买游戏本体是不共通的，但是购买 DLC 是可以通过 Dire Wolf 账户实现共通。</p><p>又因为 Root 既有实体桌游，也有电子版本，我采取的讲述方式是同时基于了它们二者：你会发现我尽量不去介绍桌游特有的实体物件，也没有无视掉电子版本中程序已经帮助玩家处理好的地方，而是围绕着游戏机制本身进行介绍。</p><p>未来我考虑继续介绍 Root 的 DLC 内的阵营，或者说阵营的进阶玩法。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;《茂林源记》，或称 Root（以下也这么称呼），是一个区域控制类桌游。虽然这么说，但它的标签还是很多的，例如德式桌游标准的得分制、应该被划分给美式桌游的阵营机制等等。我先前为这款游戏写过一些评价，本来没有打算继续去写该游戏的说明，但介于自己刚写了个扫雷的入门说明，最终还是写下了这篇文章。&lt;/p&gt;</summary>
    
    
    
    <category term="游戏说明" scheme="https://blog.cytrogen.icu/categories/%E6%B8%B8%E6%88%8F%E8%AF%B4%E6%98%8E/"/>
    
    
    <category term="桌面游戏" scheme="https://blog.cytrogen.icu/tags/%E6%A1%8C%E9%9D%A2%E6%B8%B8%E6%88%8F/"/>
    
  </entry>
  
  <entry>
    <title>用笑脸玩扫雷</title>
    <link href="https://blog.cytrogen.icu/posts/9408.html"/>
    <id>https://blog.cytrogen.icu/posts/9408.html</id>
    <published>2026-02-14T05:00:00.000Z</published>
    <updated>2026-02-19T07:42:07.357Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>想必大家都有玩过「扫雷」这款游戏，尤其是经历过 Windows 早年版本时代的人们，在计算机的开始菜单里找了半天，好不容易找到「游戏」文件夹，里面赫然躺着一个应用程序。双击打开，看到一个黄黄的微笑，心想这游戏肯定很简单吧！然后便被炸弹炸死。</p><span id="more"></span><p><img src="/posts/9408/start.webp" alt="" loading="lazy"></p><p>好吧，这游戏到底该怎么玩呢？首先，你可以点开一个网格，看看下面有没有雷，就像是现实生活中挖雷一般。你可以右键给一个网格插上旗子，标记该网格，假设它底下有雷。</p><p>那就点开一个网格看看吧！</p><p><img src="/posts/9408/first_click.webp" alt="" loading="lazy"></p><p>看来我们挖出了一个大区域。其中没有数字的网格，代表它的周围（即相邻的八个格子）没有雷；有数字的网格，上面的数字代表周围存在多少个雷，例如 1 就是相邻的格子里有 1 个雷、2 就是相邻的格子里有 2 个雷……</p><p>知道了这一条规则后，我们可以快速锁定这些 1 们：因为它们的周围只有 1 个格子，也只有 1 个雷，那么雷到底在哪里，很显而易见了吧~</p><p><img src="/posts/9408/eight_ones.webp" alt="" loading="lazy"></p><p>给这些定有雷的格子插上旗后，我们可以进一步推测出，旁边的 1 的雷已经被找到了，那么它们的周围就不可能再有其他雷 —— 全部挖开！</p><p>持续做下去后，很快你便会发现，已经没有可以用这种推理方法挖开或者插旗的格子了。当然，这不意味着扫雷无法再继续进行下去，只是我们还没有明白该游戏的本质。</p><p>扫雷的核心逻辑在于「公共区域的控制权」。什么是公共区域？当两个数字相邻时，它们周围的一圈格子在中间部分一定是重叠的。除了这片公共区域，它们又各自拥有属于自己的一小块独占区域。</p><p>假设我们决定观察这两个相邻的数字：M 和 N。M 周围有 M 个雷，N 周围也有 N 个雷，它们中间夹着的几个格子是它们共同拥有的。无论这些公共格子通过什么方式排列雷，它们对 M 和 N 的贡献是一样的。如果 M 是 1，N 也是 1，意味着 M 需要在它的视野里找到 1 颗雷，N 也需要找到 1 颗雷 —— 因为 M 通过公共区域得到了满足，那么 N 作为邻居，自然也得到了满足。如果此时 N 还有额外的独占区域格子，那么格子必然不能有雷，否则 N 周围的雷数就会超标。</p><p>明白了这些后，恭喜你，你理解了扫雷游戏里的「1-1」定式！</p><p>接着我们用这个逻辑去理解「1-2」定式。想象这么一个场景，M 是 1，N 是 2。这意味着公共区域内最多只能有 1 颗雷，绝对不能再多。既然最多只能有 1 颗雷，那么 N 的最后那颗雷哪里来？答案是在 N 的独占区域内。也就是说，我们可以通过减法公式 N - M = 1，来得出答案 1 颗雷必然存在于大数字的独占区域内。</p><p>再来看「1-2-1」定式。我们这里使用 M = 1、N = 2、O = 1 来代表这个场景。假设我们把雷放在 N 的正下方，这颗雷会同时被 M、N、O 看到，且同时满足 M 和 O 的条件。可是，中间的 N 还差 1 颗雷。但这颗雷没有地方放了，因为如果再在任何地方放雷，左右两边的 1 就会变成 2，也就违背了已知条件。所以，结论只有一个：中间那个公共格子绝对不能有雷。既然中间不能有雷，为了满足中间的 2，雷只能被迫分布在两个 1 的下方。也就是说，「1-2-1」是一个硬性定式，只要看到了就可以断定两个 1 下面有雷，而 2 的下面没有。</p><p><img src="/posts/9408/one-two-one.webp" alt="" loading="lazy"></p><p>如果将两个「1-2」叠加起来，我们能得到「1-2-2-1」定式。左边的「1-2」结构意味着，为了补足 2 的雷数，最左边的雷必须在 2 的独占区域。同理，右边的「2-1」结构意味着最右边的雷也必须在 2 的独占区域。这样一来，两个 2 外侧的雷都确定了。现在只需要找到公共区域的雷。由于它们原本都是 2，现在各减去确定的 1 颗，剩下的需求便变成了「1-1」的局面。</p><p>根据前面提到的「1-1」逻辑，中间往往是安全的，或者雷的分布是对称的。结果便是，两头的 1 下面有雷，中间的两个 2 下面往往可以挖开。不过该定式需要取决于雷的具体排列，不过逻辑核心依然是先确定外侧的必然雷。</p><p>其实，这些定式本质上都是数个「1-1」或者「1-2」组成的，只要理解底层逻辑，都可以通过这些减法公式来判断雷的位置。但是呢，在实际的中盘博弈中，数字周围通常已经插上了旗帜。如果不扣除这些已知的雷，直接套用减法公式，新手容易将实质上的「1-2」误判为「2-2」或者「3-3」等对称局面，从而得出完全相反的安全结论并导致踩雷。</p><p>过去我为作业写过 <a href="https://github.com/Cytrogen/CS50AI_2023/blob/main/minesweeper/minesweeper.py">一个简单的扫雷 AI</a>。因为对该游戏的不熟悉，代码里并没有赋予 AI 处理任何需要综合判断的局面的能力。这对我们而言也是同样的，如果只是随便将定式套在数字上，而没有考虑到更为综合的情况的话，得到的可能就是一个爆炸的雷，和一个死掉的小黄脸了。</p><p>该文章仅讲述扫雷游戏的入门玩法，参考 <a href="https://zhuanlan.zhihu.com/p/27550382">该文章</a>，想要更多了解的也请阅读该文章。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;想必大家都有玩过「扫雷」这款游戏，尤其是经历过 Windows 早年版本时代的人们，在计算机的开始菜单里找了半天，好不容易找到「游戏」文件夹，里面赫然躺着一个应用程序。双击打开，看到一个黄黄的微笑，心想这游戏肯定很简单吧！然后便被炸弹炸死。&lt;/p&gt;</summary>
    
    
    
    <category term="游戏说明" scheme="https://blog.cytrogen.icu/categories/%E6%B8%B8%E6%88%8F%E8%AF%B4%E6%98%8E/"/>
    
    
    <category term="扫雷" scheme="https://blog.cytrogen.icu/tags/%E6%89%AB%E9%9B%B7/"/>
    
  </entry>
  
  <entry>
    <title>女人的血</title>
    <link href="https://blog.cytrogen.icu/posts/df9e.html"/>
    <id>https://blog.cytrogen.icu/posts/df9e.html</id>
    <published>2026-02-12T05:00:00.000Z</published>
    <updated>2026-02-19T07:42:07.353Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>女人，或者说有雌性生殖器官的人，又或者说需要生产卵子来进行繁殖生育的哺乳动物，都会有月经吧。以防万一有人不知道月经的底层逻辑，它本质上是卵子死去时流出的血液。女人需要每个月更换卵子，经历「流血的七天、安全期、卵子生成的发情期」这样的 28 天循环，直到无法生育。这期间有一个例外，那便是怀孕。</p><span id="more"></span><p>要说月经有多么不便，一是伴随而来的腹痛和肌肉酸痛，二是下体那无法离去的黏稠感，三是对于流血这件事情的恐惧 —— 这里主要指的是不知道什么时候流血，以及在实际确认前不知道自己流了多少。量就像死或者没死的猫，无论是哪个结果，在打开箱子前我们作为观测者都是心惊胆跳的。</p><p>五年级的时候，我流出了第一滩月经血。那是一坨黑色的东西，附在我彩色的凯蒂猫睡裤上，当然还有内裤上。我对它的第一个反应，便是恐怖 —— 废话，身体不舒服去蹲个马桶，刚脱下裤子就是这么一大滩黑色的玩意儿，哪个小孩儿不会被吓到。和近乎所有中二的小孩儿一样，我的第二个反应是「我该不会得了什么绝症吧」，进而得出自己是「特殊的」这件事。</p><p>也和近乎所有中二的小孩儿一样，我认为「特殊」的事情，不过是世界上比我能数出的数字更多的人正在经历的事情。因为母亲像是没事人一样说，「我也到那个年纪了」，然后像是被逗乐般，告诉我如何使用卫生巾。使用卫生巾是一个极其不适的事情：你的肉体和内裤之间隔了一层粗糙的护垫；要是你出汗了，这个护垫还会黏糊糊地粘在屁股上，更别提血多的时候了。虽然长大后我有幸使用过高质量的卫生巾，但是我绝大多数只买得起便宜货…… 而这种事情，每个月都要发生足足七天，可能会少一两天，亦或者多一两天。</p><p>为什么女人一定要经历月经这件事，我自小就在思考。它实在不是一件能让我觉得有价值的事情，无论是不舒适还是其带来的结果 —— 可生育 —— 都让我觉得可有可无。</p><p>母亲来美国后，成为了一个忠诚的基督教徒。我来美国后，自然也没少和她去教堂。还是孩子的我，并不能理解宗教，只是在没有娱乐的教堂里一遍遍翻阅圣经，直到看到《撒母耳记》以及后面的明显不再带有故事情节的内容；因为那些内容实在是「无聊」，无法吸引到我。圣经在那时候，对我来说更像是西方人的「故事书」。因此，孩童时期的我最喜欢的章节是《启示录》。不过那里面没有太多和耶稣相关的内容，说出去的时候还被说教了一番。</p><p>先前我表态过，我并 <a href="/posts/b211.html#%E6%96%B0%E6%8A%A5%E5%91%8A%E5%91%BC%E5%90%81%E5%9C%A8%E7%BE%8E%E5%9B%BD%E7%BB%88%E7%BB%93%E7%AB%A5%E5%A9%9A">不喜欢宗教</a>。不过我喜欢宗教故事。也就是说，将它们视为故事书来看，我是很欢迎的；如果是传教来的，我只能用手打个大大的 X 给你看。我很不喜欢跟耶和华有关系的宗教。无论是犹太教还是基督教还是伊斯兰教，都一定会出现旧约的内容。尽管知道一些派系否认了旧约里说的事情，但我还是无法喜欢上它们。《创世纪》里说，夏娃被蛇欺骗，吃了生命果，还劝亚当吃下，所以被上帝额外惩罚，后代的所有女人都要每月受腹痛之刑，且在一个章节里，女人要额外比男人多清洗几天，只因女人一出生便是不洁的。</p><p>我会一次次去想，我是生而不纯洁的吗？我会在小时候就体验这种钻心之痛，是因为这种事情吗？</p><p>「血」，仿佛真的像是诅咒一般。</p><p>疫情期间，父亲被辞退，纽约市的街道空荡荡的，大家买不到口罩，我们一家四口和一个亲戚在房子里日复一日地搓麻将。那是一段压抑的时期，我们无处可去，只能醒来、玩手机、打麻将、睡觉、重复。这种像是被打了一针麻醉的生活里，母亲突然说了一句，「要是当时死掉的人是我就好了。」我陷入了沉默，然后和过去一样，不受控制地出现了情绪闪回：这是母亲多少次如此厌恶我？或者在我的面前赞扬她那个已经胎死腹中的男孩儿？</p><p>母亲打掉的孩子一共有两个，我是她第三个怀上的孩子，也是第一个顺利生产的孩子。在我之前，她怀上的是一个男婴。然而当时发生了许多事情，母亲一气之下打掉了这个孩子，后面又一个劲儿地后悔。梦里，她时不时会梦到这个男婴，对着她说「妈妈，我冷。」惊恐中，她向外婆求助做法事，心境安稳后，就再也没有梦到这个男婴了；取而代之的是她会潜意识中将所有男青年视为自己的儿子，并对我说，「要是你哥哥还活着，他就是这个样子吧。」</p><p>我一边摸着麻将牌，一边流下泪水。父亲看到我哭了，愤怒地掀翻了麻将桌，和母亲吵了一架；妹妹大声哭了起来，亲戚只能在旁边做和事佬。</p><p>在美国欠债的生活压得还未成年的我很是难受，也压得父母难受，尤其是母亲。她在我初中时开始，精神逐渐变态。不仅打骂已经是家常便饭，还会管控我和同龄人之间的社交，令我很难和朋友们进一步发展关系。最为可恶的是那些向着她的人们，口上说着要帮助我，却没有人真的做什么，只是让身为孩子的我一次次原谅母亲、体谅她。直到日后，高中的一位老师策划了一件事，瞒着我报告了儿童局，且一位友人一直在帮助和支持我，我和母亲的关系才得以缓和。所以让孩子体谅父母，根本就不是什么责任，明明解决问题有着更好的方法。</p><p>母亲到底是为什么生下我，以及妹妹的呢？是为了社会义务，是为了一己私欲，还是真的希望一个生命能够诞生、享受世界上各个美好？我想，怎么都不会是最后一个吧。如果我都不觉得自己能够抚养好的一个孩子的话，那我这些年为了生育而保留的这个系统，真的还有存在的必要吗？</p><p>在知道我和同性交往过后，一个说教味儿极重的校友找到我，开门见山问我为什么要和同性在一起、我应该知道「洞和洞是不能在一起」的吧。我心想，这个人恐怕是一个「洞性恋」；怎么会有人将其他人类视作为「洞」呢？除非他满脑子都是洞，看到的也只有洞。对话的结尾，他为了让我难堪，说「因为你是同性恋者，所以你全家的血脉都断了。」</p><p>香火、血脉，这些事情，真的有那么重要吗？为了这些「社会义务」，生下一个又一个孩子，但是缺乏培养他们的能力，最终得到的却是一个个倍受童年折磨的人。</p><p>这一切的目的是什么？在生物角度上来看，是为了发情和繁殖。生育从来都不是一件错事，这是自然的。只是我并不清楚自己真的会想要生育吗？我在未来，会喜欢上一个人，然后想要去那个人组建家庭、生下两人基因的融合体吗？不，这样的想法到底在把孩子们当成什么？如果要让一个生命诞生的话，就必须为他负起责任吧。我不想成为一个，像父母亲那样的人啊。我希望世上的孩子们，都可以幸福地度过童年，可以成长为自己想要成为的大人 —— 因为，我连自己也喜欢不上来啊。</p><p>既然如此，为什么我没有去采取相关的措施、好让自己的生活好过一些？我思来想去，觉得最大的问题在于「后路」。每次想到这件事，考虑到的都不是所消耗的精力和资源，而是「万一自己未来会使用到呢」—— 潜意识中，生育这种与生俱来的能力，竟是我的后路吗？</p><p>如果我构建出来的社会身份失败了，我剩下的，便是「母亲」这种最为原始的身份。照顾孩子是困难的，我一直都知道，所以我也会认为母爱是伟大的。但如果让我因为这种理由而成为一位母亲，这个身份便成了廉价的兜底方案 —— 它不需要我拥有才智和品格，只需要我维持这具肉体的基本机能。这种思想是可怕的，我在潜意识里依然认可了将人简化为「洞」的逻辑，依然在为自己保留一种功能性的价值，而非主体性。</p><p>我要是因为自己的失败，而让一个生命诞生了，对他而言，我或许只不过是一个又傲慢又糟糕的人吧。我会将他视为填补自己人生空洞的工具，让他成为我逃避虚无的牺牲品。好像，我又一次变成了母亲。</p><p>我好希望这「女人的血」，仅仅是血，而不是诅咒。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;女人，或者说有雌性生殖器官的人，又或者说需要生产卵子来进行繁殖生育的哺乳动物，都会有月经吧。以防万一有人不知道月经的底层逻辑，它本质上是卵子死去时流出的血液。女人需要每个月更换卵子，经历「流血的七天、安全期、卵子生成的发情期」这样的 28 天循环，直到无法生育。这期间有一个例外，那便是怀孕。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="社会学" scheme="https://blog.cytrogen.icu/tags/%E7%A4%BE%E4%BC%9A%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>读《那片血一般红的杜鹃花》</title>
    <link href="https://blog.cytrogen.icu/posts/9027.html"/>
    <id>https://blog.cytrogen.icu/posts/9027.html</id>
    <published>2026-02-07T05:00:00.000Z</published>
    <updated>2026-02-19T07:42:07.357Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我这个学期开始上中文课了。这节课是短篇小说课，主要是阅读上个世纪台湾、大陆等作者们的短篇小说。</p><p>开课要阅读的第一本叫作《那片血一般红的杜鹃花》，出自于《白先勇文集》的第二卷「台北人」。</p><p>这是一个第一人称视角的故事，但「我」并非故事的主角，而是故事的旁观者。而故事采取的叙事手法是倒叙。</p><span id="more"></span><p>开头人们便在海边找到一具男尸 —— 够 hook，吸引了读者的注意力。此时出现了故事真正的主角 —— 王雄 —— 的第一次外表描写：</p><blockquote><p>要不是他那双大得出奇的手掌，十个指头圆秃秃的，仍旧没有变形的话，我简直不敢想象，躺在地上那个庞大的怪物，竟会是舅妈家的男工王雄。</p></blockquote><p>简单一句话，我们得知了这些信息：王雄很大一只，且手掌出奇地大，有着秃秃的手指头 —— 并不精致，是个干活的手。</p><p>之后故事便切换到了「我」最初来到故事发生的地点的时候。此处纷纷介绍了舅妈和丽儿这两个角色。舅妈在这个故事里并非什么重要角色，作者对她的描写并不多；丽儿是故事的另一个主角，描写自然也就多了：从小就被惯着养，且又白又圆，像个玉娃娃 —— 玉娃娃是个颇为有趣的描写，代表着精致、贵重的同时，还有着易碎的特征。</p><p>接着「我」初次见到了王雄 —— 他在长满了杜鹃花的花圃里，给丽儿当马骑。就算是丽儿从他的头上跨过去，他也觉得无所谓。作者对王雄的描写是这样的：高大得出奇、黑头黑脸、巨掌、秃秃的指头。很显然，这是一个完全和丽儿反着来的角色；一个小孩和一个大人，一个白一个黑。</p><p>不过王雄也有着和丽儿相似的外貌描写，他有着一嘴白牙齿和发白的裤子，意味着他并不是一个完完全全「黑」的人。</p><p>三人的对话透露出，王雄是个湖南人，以前还打过仗。意外的是，当丽儿说王雄曾经对自己说过，可以让自己骑着他上学时，王雄这个粗男人竟脸红了。</p><p>「我」从舅妈那儿得知，王雄是个退伍军人，现在被舅妈雇佣作男工。他为人老实，干活细腻，花圃的杜鹃花全是他一颗颗种的。「我」心生疑惑：为什么要种杜鹃花呢？舅妈给出的答案是丽儿喜欢。</p><p>王雄每天都会接送丽儿上下学，还会把自己打扮得体体面面的。一回到家，便会钻研各种东西讨丽儿欢心。此时的二人，关系再好不过。</p><p>因为服兵役，「我」时不时会借住在舅妈家，因此有时间给丽儿补习功课，以及和王雄谈话。王雄告诉「我」，他原是湖南乡下的农民，十八岁抽壮丁时被抽了出来，直到现在四十了也没能回过家。</p><blockquote><p>「表少爷，你在金门岛上看得到大陆吗？」有一次王雄若有所思的问我道。我告诉他，从望远镜里可以看得到那边的人在走动。</p><p>「隔得那样近吗？」他吃惊的望着我，不肯置信的样子。</p><p>「怎么不呢？」我答道，「那边时常还有尸首漂过来呢。」</p><p>「他们是过来找亲人的。表少爷，你不知道，」王雄摇了摇手止住我道，「我们湖南乡下有赶尸的，人死在外头，要是家里有挂得紧的亲人，那些死人跑回去跑得才快呢。」</p></blockquote><p>「我」服兵役的地方正是现在福建的金门岛，且离大陆很近很近。但就算这么近了，两岸当时的关系也不容探亲，更别提让王雄这个国民党的军人回家了。</p><p>当描述到营地里的老士兵的时候，「我」说他们有时会出现成人不会有的「童稚般的笑容」以及「赤子的天真」。且「我」初次提到了「怀乡的哀愁」。对于王雄来说，他不也是这样的人吗？</p><p>当问到王雄家里还有什么人的时候，王雄回答说家里有个不知道还在不在的母亲，以及一个十岁大的童养媳。作者描述童养媳的时候，也使用了「白白胖胖」这样的比喻。童养媳的年龄和描述，正和现在的丽儿一模一样。</p><p>这一段里，不只是出现了童养媳这个角色，作者也引入了最开头提过但没有深入的角色 —— 喜妹。她是下女，也就是女佣或者侍女。对于喜妹这个角色的描写，虽然她也是「白白胖胖」，但是「自以为很有风情」，反而和王雄是死对头。喜妹很喜欢撩拨王雄玩，这在旧中国看来是相当轻浮的举动，但王雄又很不喜欢她。</p><p>让我好奇的是，喜妹在逗完王雄后，「用着尖细的声音哼起了台湾的哭调《闹五更》」。而王雄「霍然立起身，头也不回」回了房间。这里的《闹五更》到底有着什么样的含义？</p><p>丽儿上中学前，舅妈给她买了套童军制服。王雄看后，「猛吃了一惊」。先前暗示过，王雄将丽儿视为自己小时候的童养媳；但现在丽儿开始长大，有了新的衣服，变得也渐渐和童养媳不一样。对于那时的王雄来说，又意味着什么呢？不只是如此，丽儿上中学后也有了性别和阶级意识。在她在家里炫耀自己学的英文时，她说：</p><blockquote><p><em>I am a girl.</em> 丽儿指了一指自己的胸膛念道，然后又指了一指王雄。</p><p><em>You are a boy.</em> 王雄微张着嘴，脸上充满了崇敬的神情。</p><p><em>I am a student.</em> 丽儿又念了一句，她瞥了王雄一眼，然后突然指着他大声叫道：</p><p><em>You are a dog.</em></p></blockquote><p>这些都象征着丽儿在未来只会越来越不像童养媳。果不其然，在紧接着的下一场景中，丽儿便大发脾气，不再允许王雄接送自己，理由是同学们觉得王雄长得像大猩猩。此时，王雄不仅不再是「非异性」、「同级人」，而是一个动物 —— 连人都不是了！</p><p>王雄为了让这段关系回到过去那样美好，给丽儿带来两条金鱼。丽儿非但没有收下，反而摔碎了鱼缸、害死了金鱼。作者借物描述了二人的关系，正如文中所说那样，「跌落在地上不能动弹了」。这也是这部短篇小说里，王雄和丽儿的最后一次对话。</p><p>自这之后，王雄变得颓废起来。人叫他，他不应，脾气还越来越暴躁，一整天只是不停照料杜鹃花。一次，他和喜妹就用水一事起了冲突。王雄瞪着喜妹时，喜妹却放声嘲笑他：</p><blockquote><p>「大猩猩 —— 大猩猩」</p></blockquote><p>谁知这一笑，王雄彻底愤怒、像头真的大猩猩一样，抓住喜妹的肩膀拼命摇晃，还发出野兽般的低吼！喜妹挣扎逃开，对着他骂道：</p><blockquote><p>「考背！」</p></blockquote><p>次日早上，「我」和舅妈在花园找到了像是死了一样的喜妹。她的衣服被撕碎，身上包括乳房都是伤痕。同一天，王雄也不见了。在那之后，便发生了小说开头的「王雄之死」。这里小说中并没有提及喜妹到底有没有被性侵。</p><hr><p>上中文课的一个好处是，我们可以一边阅读，一边讨论。这篇小说在开课前我便读过一遍，但当时并没有读出其更为深奥的意义来。这次讨论让我见识到了作者的功底，也更乐意去解读这些小说。</p><p>教授问我们，王雄和丽儿的关系到底是什么。一位同学认为是父女般的关系，一位同学认为是不纯粹的、王雄将丽儿视为性对象的关系…… 在我看来，王雄确实是以不单纯的视角去看丽儿，不过并不能简单归于「父女」或者「性」。这就需要讲到这部短篇小说的主题 —— 乡愁。</p><p>王雄十八岁便被迫离开湖南，到四十岁都没有再回去过。他将对童养媳的思念加到丽儿身上，正好她们在小时候很是相似。可是丽儿终究是丽儿，而非童养媳。长大后的丽儿只会慢慢疏远王雄，变得和王雄记忆里的童养媳不再一样。在王雄意识到这一点之后，他的重点便放在了浇灌杜鹃花上。</p><p>为什么非得是杜鹃花呢？不论是小说的标题，还是王雄最初决定栽种的植物，都是杜鹃花。故事中的「我」很是好奇，便去询问了舅妈。当时舅妈的回复是「丽儿喜欢」，但其实还有一层意思：湖南盛产杜鹃花，早在 193x 年便引入长沙市栽培，1985 年还成了长沙市的市花。种杜鹃花，是为了让舅妈家变得像自己在湖南的家一样。</p><p>这份思乡之心也在其他地方表现出来：王雄询问「我」能否看到内地时，提到的赶尸习俗中，他特意提到「只要亲人挂得紧，尸体回去才快呢」。小说里也让「我」见到念叨着家乡的老士兵，作为主题的又一暗示。</p><p>王雄作为退伍老兵，回不去家，仅能将丽儿和杜鹃花视为一种寄托。但丽儿变了，开始嫌弃自己，生活没有了正面反馈，自己又同喜妹产生冲突 —— 喜妹那句骂人的话很有意思。「考背」（现在更喜欢称之为「靠北」）的意思其实是「哀悼父亲去世」，延伸开来就有诅咒对方死全家的意思。王雄是家中唯一一个男丁，对他来说，母亲可能已经去世，家中只剩下一个不知去向的童养媳，王雄本人又回不去 —— 这又何尝不是一种「死全家」了呢？</p><p>而王雄暴怒时的举动，正好和他人嘲弄他说的「大猩猩」一样。此时的他，不仅理解了和丽儿的关系无法再回到当初，自己可能一辈子无法回家；种种压力下，王雄想：「你们说我是大猩猩，那我就变成大猩猩给你们看。」结果便是喜妹的悲剧。</p><p>王雄本身并不是一个暴力的人。攻击了喜妹之后，想必他的想法很是复杂：愧疚、焦虑、后悔、自暴自弃…… 想要回家，怎么回家？「湖南有个赶尸习俗，只要亲人挂得紧，尸体回去才快呢。」荒诞的是，能回家的方法竟只剩「死」这一条路。</p><p>这必须得讲一下当时的历史。1949 年到 1987 年之间，所有流亡到台湾的外省人都无法回到内地。1949 年国民党退守台湾后，海峡两岸处于战争状态：两岸之间不通邮、不通商、不通航。而王雄的身份是国军退伍士兵。当时台湾处于长达 38 年的「戒严时期」。私自与大陆联系或试图前往大陆，会被视为通匪或叛逃，可能面临极刑或牢狱之灾。同理，在大陆那边，曾为国民党效力的士兵被划为「黑五类」或「历史反革命」。假设王雄真的偷渡回去，等待他的极可能是批斗、监禁甚至处决。</p><p>戏剧性的是，《台北人》是在 1960 年代到 1970 年代初。 两岸开放探亲要等到 1987 年。王雄死在了黎明前的漫长黑夜里。对于那个时代的大多数老兵来说，这就是死局。他们唯一的归乡方式，往往只能是死后魂归故里。「我」看到的老士兵实际上便是无数个王雄。他们虽然年纪看着大，但有着成人没有的童真和天真 —— 有多少是还没长好就被抓来当兵，半辈子都在战场上生活的呢？先前我说这暗示了乡愁主题，其实也暗示了这些人们停留在孩童的年龄。</p><p>这又要说回最开始那个问题：王雄和丽儿到底是什么关系？作者在描写他们二人互动时，很喜欢将王雄写成一个「虽然年纪大身体也大，但处处跟个孩子一样、同丽儿玩耍的人」。在我看来，就算他将丽儿当成童养媳看待，但这也不意味着他带着有色滤镜去看待丽儿，反而是将其视为童年的一部分；同丽儿游玩，就像是自己也变小了一样，从来都没有上战场过。</p><p>可惜他最终的结局是：</p><blockquote><p>他的尸体被潮水冲到了岩石缝中，夹在那里，始终没有漂走。</p></blockquote></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我这个学期开始上中文课了。这节课是短篇小说课，主要是阅读上个世纪台湾、大陆等作者们的短篇小说。&lt;/p&gt;
&lt;p&gt;开课要阅读的第一本叫作《那片血一般红的杜鹃花》，出自于《白先勇文集》的第二卷「台北人」。&lt;/p&gt;
&lt;p&gt;这是一个第一人称视角的故事，但「我」并非故事的主角，而是故事的旁观者。而故事采取的叙事手法是倒叙。&lt;/p&gt;</summary>
    
    
    
    <category term="书评" scheme="https://blog.cytrogen.icu/categories/%E4%B9%A6%E8%AF%84/"/>
    
    
    <category term="短篇小说" scheme="https://blog.cytrogen.icu/tags/%E7%9F%AD%E7%AF%87%E5%B0%8F%E8%AF%B4/"/>
    
  </entry>
  
  <entry>
    <title>想法在丙午岁始迭代</title>
    <link href="https://blog.cytrogen.icu/posts/c089.html"/>
    <id>https://blog.cytrogen.icu/posts/c089.html</id>
    <published>2026-02-01T05:00:00.000Z</published>
    <updated>2026-03-11T05:44:51.604Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>这个月里我做了很多在笔记本上的工作，所以在阅读文章上花费的时间跟精力都变少了很多。</p><span id="more"></span><details>      <summary>本期导读</summary>      <h2 id="输入"><a class="markdownIt-Anchor" href="#输入"></a> 输入</h2><h4 id="商业与社会"><a class="markdownIt-Anchor" href="#商业与社会"></a> 商业与社会</h4><ul><li><a href="#%E5%90%8E%E7%BE%8E%E5%9B%BD%E4%BA%92%E8%81%94%E7%BD%91">后美国互联网</a></li><li><a href="#%E7%8E%B0%E5%9C%A8%E5%AD%A9%E5%AD%90%E4%BB%AC%E5%B7%B2%E7%BB%8F%E5%BE%88%E5%B0%91%E8%AF%BB%E5%AE%8C%E6%95%B4%E6%9C%AC%E4%B9%A6%E4%BA%86%E5%8D%B3%E4%BD%BF%E6%98%AF%E5%9C%A8%E8%8B%B1%E8%AF%AD%E8%AF%BE%E4%B8%8A">现在孩子们已经很少读完整本书了，即使是在英语课上</a></li><li><a href="#ai-%E4%BB%A3%E7%90%86%E6%AD%A3%E5%9C%A8%E5%90%9E%E5%99%AC-saas">AI 代理正在吞噬 SaaS</a></li><li><a href="#%E5%A6%82%E6%9E%9C-ai-%E5%8F%96%E4%BB%A3%E4%BA%86%E4%BA%BA%E7%B1%BB%E5%91%98%E5%B7%A5%E9%82%A3%E5%AE%83%E9%9C%80%E8%A6%81%E4%BB%98%E7%A8%8E%E5%90%97">如果 AI 取代了人类员工，那它需要付税吗？</a></li><li><a href="#%E6%83%B3%E6%B3%95%E5%B9%B6%E9%9D%9E%E8%B6%8A%E6%9D%A5%E8%B6%8A%E9%9A%BE%E6%89%BE">想法并非越来越难找</a></li><li><a href="#%E9%82%A3%E4%B8%AA%E5%94%AE%E5%8D%96%E6%97%B6%E9%97%B4%E7%9A%84%E5%A5%B3%E4%BA%BA%E5%92%8C%E9%82%A3%E4%B8%AA%E8%AF%95%E5%9B%BE%E9%98%BB%E6%AD%A2%E5%A5%B9%E7%9A%84%E7%94%B7%E4%BA%BA">那个售卖时间的女人，和那个试图阻止她的男人</a></li><li><a href="#%E5%84%BF%E7%AB%A5%E7%99%8C%E7%97%87%E6%82%A3%E8%80%85%E7%9A%84%E6%95%B0%E7%99%BE%E4%B8%87%E6%B2%BB%E7%96%97%E6%AC%BE%E9%A1%B9%E8%A2%AB%E9%AA%97">儿童癌症患者的数百万治疗款项被骗</a></li><li><a href="#%E7%8E%A9%E8%80%8D%E6%97%B6%E9%97%B4%E6%9C%80%E9%95%BF%E6%B8%85%E7%90%86%E6%97%B6%E9%97%B4%E6%9C%80%E7%9F%AD%E7%9A%84%E7%8E%A9%E5%85%B7">玩耍时间最长、清理时间最短的玩具</a></li><li><a href="#%E8%87%AA%E7%94%B1%E8%96%AF%E6%9D%A1">自由薯条</a></li><li><a href="#ai-%E5%AF%BC%E8%87%B4%E5%AD%A6%E6%A0%A1%E8%BF%9B%E5%85%A5%E5%B0%81%E9%94%81%E5%9B%A0%E5%85%B6%E5%B0%86%E5%AD%A6%E7%94%9F%E7%9A%84%E5%8D%95%E7%B0%A7%E7%AE%A1%E8%AF%AF%E8%AE%A4%E4%B8%BA%E6%9E%AA%E6%94%AF">AI 导致学校进入封锁，因其将学生的单簧管误认为枪支</a></li><li><a href="#%E6%88%91%E8%A2%AB%E5%BE%B7%E5%9B%BD%E9%93%81%E8%B7%AF%E7%BB%91%E6%9E%B6%E5%8F%AA%E5%BE%97%E5%88%B0%E4%BA%86-150-%E6%AC%A7%E5%85%83">我被德国铁路绑架，只得到了 1.50 欧元</a></li><li><a href="#%E6%88%91%E8%A7%A3%E9%99%A4%E4%BA%86%E6%88%91%E7%9A%84%E5%87%BA%E4%B9%A6%E5%90%88%E7%BA%A6">我解除了我的出书合约</a></li><li><a href="#%E9%98%85%E8%AF%BB%E6%98%AF%E4%B8%80%E7%A7%8D%E6%81%B6%E4%B9%A0">阅读是一种恶习</a></li><li><a href="#%E7%99%BE%E5%B9%B4%E6%B5%81%E8%A8%80">百年流言</a></li><li><a href="#%E8%B0%B7%E6%AD%8C%E4%BC%A4%E9%80%8F%E4%BA%86%E6%88%91%E7%9A%84%E5%BF%83">谷歌伤透了我的心</a></li></ul><h4 id="心理与关系"><a class="markdownIt-Anchor" href="#心理与关系"></a> 心理与关系</h4><ul><li><a href="#%E4%B8%96%E7%95%8C%E6%B2%A1%E6%9C%89%E4%BD%A0%E7%9A%84%E6%97%B6%E5%80%99%E4%B9%9F%E4%BC%9A%E7%BB%A7%E7%BB%AD%E8%BF%90%E8%BD%AC">世界没有你的时候也会继续运转</a></li><li><a href="#%E8%96%84%E6%AC%B2%E6%AD%A3%E5%9C%A8%E5%90%9E%E5%99%AC%E4%BD%A0%E7%9A%84%E7%94%9F%E6%B4%BB">薄欲正在吞噬你的生活</a></li><li><a href="#%E4%BD%A0%E5%B9%B6%E9%9D%9E%E8%81%8C%E4%B8%9A%E5%80%A6%E6%80%A0%E8%80%8C%E6%98%AF%E7%81%B5%E9%AD%82%E5%9C%A8%E9%97%B9%E9%A5%A5%E8%8D%92">你并非职业倦怠，而是灵魂在闹饥荒</a></li><li><a href="#%E4%B8%8D%E8%A6%81%E5%8F%98%E6%88%90%E6%9C%BA%E5%99%A8">不要变成机器</a></li><li><a href="#%E5%9C%A8%E5%92%96%E5%95%A1%E9%A6%86%E7%8B%AC%E5%A4%84%E7%9A%84%E4%B8%8D%E8%83%BD%E6%89%BF%E5%8F%97%E4%B9%8B%E4%B9%90">在咖啡馆独处的不能承受之乐</a></li></ul><h4 id="科学与自然"><a class="markdownIt-Anchor" href="#科学与自然"></a> 科学与自然</h4><h4 id="技术与创造"><a class="markdownIt-Anchor" href="#技术与创造"></a> 技术与创造</h4><ul><li><a href="#github-%E7%9A%84%E5%9E%84%E6%96%AD%E6%98%AF%E5%A6%82%E4%BD%95%E6%AD%A3%E5%9C%A8%E6%91%A7%E6%AF%81%E5%BC%80%E6%BA%90%E7%94%9F%E6%80%81%E7%B3%BB%E7%BB%9F%E7%9A%84">GitHub 的垄断是如何正在摧毁开源生态系统的</a></li><li><a href="#bear-vs-pika-vs-writeas">Bear vs Pika vs Write.as</a></li><li><a href="#br-%E6%A0%87%E7%AD%BE%E7%9A%84%E4%B8%89%E5%8D%81%E5%B9%B4">br 标签的三十年</a></li><li><a href="#%E6%88%91%E6%98%AF%E8%82%AF%E5%B0%BC%E4%BA%9A%E4%BA%BA%E6%88%91%E4%B8%8D%E5%83%8F-chatgpt-%E9%82%A3%E6%A0%B7%E5%86%99%E4%BD%9Cchatgpt-%E5%83%8F%E6%88%91%E4%B8%80%E6%A0%B7%E5%86%99%E4%BD%9C">我是肯尼亚人。我不像 ChatGPT 那样写作。ChatGPT 像我一样写作</a></li><li><a href="#time-%E5%85%83%E7%B4%A0%E5%BA%94%E8%AF%A5%E5%81%9A%E7%82%B9%E4%BB%80%E4%B9%88"><code>&lt;time&gt;</code> 元素应该做点什么</a></li><li><a href="#%E6%88%91%E5%9C%A8%E5%9C%B0%E9%93%81%E4%B8%8A%E7%BC%96%E7%A8%8B">我在地铁上编程</a></li><li><a href="#%E8%BF%99%E4%B8%8D%E6%98%AF%E6%9C%AA%E6%9D%A5">这不是未来</a></li><li><a href="#times-new-roman-%E7%AE%80%E5%8F%B2">Times New Roman 简史</a></li><li><a href="#%E8%A7%A3%E5%86%B3%E9%97%AE%E9%A2%98%E7%9A%84%E4%B8%89%E7%A7%8D%E6%96%B9%E6%B3%95">解决问题的三种方法</a></li><li><a href="#%E6%88%91%E6%97%A0%E6%B3%95%E5%8D%87%E7%BA%A7%E5%88%B0-windows-11%E7%8E%B0%E5%9C%A8%E8%AF%B7%E5%88%AB%E7%83%A6%E6%88%91%E4%BA%86">我无法升级到 Windows 11，现在请别烦我了</a></li><li><a href="#%E4%B8%80%E7%99%BE%E4%B8%87%E4%B8%AA%E7%8B%AC%E7%AB%8B%E7%BD%91%E7%BB%9C%E6%88%AA%E5%9B%BE">一百万个（独立网络）截图</a></li><li><a href="#%E6%88%91%E6%98%AF%E5%A6%82%E4%BD%95%E7%A6%BB%E5%BC%80-youtube-%E7%9A%84">我是如何离开 YouTube 的</a></li><li><a href="#pixelfed-%E6%AD%A3%E5%9C%A8%E9%94%AF%E7%9D%80-fediverse-%E5%9D%90%E7%9D%80%E7%9A%84%E6%A0%91%E6%9E%9D%E5%90%97">Pixelfed 正在锯着 Fediverse 坐着的树枝吗？</a></li><li><a href="#%E6%88%91%E4%BB%AC%E6%98%AF%E5%A6%82%E4%BD%95%E4%B8%BA%E4%BA%86%E5%A8%B1%E4%B9%90%E8%80%8C%E5%BC%84%E4%B8%A2%E4%BA%86%E4%BA%A4%E6%B5%81%E7%9A%84">我们是如何为了娱乐而弄丢了交流的</a></li><li><a href="#%E7%94%A8%E7%BA%AF-html-%E6%9B%BF%E6%8D%A2-js">用纯 HTML 替换 JS</a></li><li><a href="#%E8%AE%BA%E9%9A%90%E7%A7%81%E4%B8%8E%E6%8E%A7%E5%88%B6">论隐私与控制</a></li><li><a href="#%E4%B8%80%E4%B8%AA%E7%BB%88%E7%BB%93%E6%89%80%E6%9C%89%E7%BD%91%E7%AB%99%E7%9A%84%E7%BD%91%E7%AB%99">一个终结所有网站的网站</a></li><li><a href="#%E7%BA%AF%E6%96%87%E6%9C%AC%E7%BD%91%E7%AB%99%E7%9A%84%E5%B0%8F%E5%9E%8B%E5%90%88%E9%9B%86">纯文本网站的小型合集</a></li><li><a href="#%E8%BF%87%E5%BA%A6%E8%AE%BE%E8%AE%A1%E8%AF%B7%E5%8B%BF%E6%89%93%E6%89%B0%E8%AE%BE%E5%A4%87">过度设计「请勿打扰」设备</a></li><li><a href="#%E5%B0%B1%E6%98%AF%E4%B8%BA%E4%BA%86%E8%BF%99%E4%BB%BD%E9%9A%BE%E5%8F%97%E5%8A%B2%E5%84%BF">就是为了这份难受劲儿</a></li><li><a href="#%E4%B9%9F%E8%AE%B8%E8%AF%84%E8%AE%BA%E5%BA%94%E8%AF%A5%E8%A7%A3%E9%87%8A%E5%81%9A%E4%BB%80%E4%B9%88">也许评论应该解释「做什么」</a></li><li><a href="#2026-%E5%B9%B4%E4%BA%86%E5%85%B3%E4%BA%8E%E5%8A%A0%E5%AF%86%E9%82%AE%E4%BB%B6%E4%BD%A0%E9%9C%80%E8%A6%81%E8%AE%A4%E6%B8%85%E7%9A%84%E7%9C%9F%E7%9B%B8">2026 年了，关于加密邮件你需要认清的真相</a></li></ul><h2 id="输出"><a class="markdownIt-Anchor" href="#输出"></a> 输出</h2><ul><li><a href="#%E6%8A%98%E8%85%BE%E5%8D%9A%E5%AE%A2">折腾博客</a></li><li><a href="#%E6%88%91%E5%86%99%E7%9A%84%E6%96%87%E7%AB%A0">我写的文章</a></li><li><a href="#%E7%BC%96%E7%A8%8B%E5%8E%86%E7%A8%8B">编程历程</a></li><li><a href="#%E4%B9%A6%E7%B1%8D">书籍</a> / <a href="#%E5%BD%B1%E8%A7%86">影视</a> / <a href="#%E9%9F%B3%E4%B9%90">音乐</a></li><li><a href="#%E6%97%A5%E8%AE%B0%E7%89%87%E6%AE%B5">真生活</a></li></ul>    </details><h2 id="商业与社会"><a class="markdownIt-Anchor" href="#商业与社会"></a> 商业与社会</h2><p><a id="后美国互联网"></a></p><h4 id="后美国互联网"><a class="markdownIt-Anchor" href="#后美国互联网"></a> <a href="https://pluralistic.net/2026/01/01/39c3">《后美国互联网》</a></h4><p>这是一篇非常有深度的演讲稿，内容很长，作者是著名的数字权利活动家 Cory Doctorow。它也很难懂，因结合了技术法律、地缘政治、经济学和数字主权，不过可以大致拆解为四个核心逻辑：</p><p>一、什么是 <u>通用计算之战</u>？</p><p>美国在 1998 年通过了 <u>《数字千年版权法》</u> 也就是 <u>DMCA</u>，其中第 1201 条规定：绕过这一技术措施 —— 越狱或者破解 —— 是犯罪行为，即使你的目的是合法的。</p><p>也就是说，如果我购买了一台设备，无论是手机还是拖拉机还是呼吸机，厂商用软件锁住了它，我即使拥有这台设备，也不能修改它的代码。</p><p>而美国利用其强大的科技地位，通过贸易协定强迫全世界其他国家也通过类似的法律。目的也很简单，保护美国科技巨头的利润：让全世界使用美国的技术，却无法掌控这些技术，必须源源不断地向美国公司付费。</p><p>二、特朗普带来的意外契机。</p><p>Doctorow 很反感特朗普，但他认为特朗普的胡作非为反而打破了上述的枷锁。</p><p>过去世界各国容忍美国的霸权是因为相信美国是一个相对中立的平台。假设世界上 200 个国家，每两个国家之间都要直接建立光缆或者货币兑换机制，那需要几万条线路，成本太高。最效率的方法是建立一个枢纽。二战后，美国就是这个枢纽 —— 光缆汇聚在美国，资金通过美元结算。</p><p>但是特朗普政府的单边主义、高额关税和不可预测性（这个老家伙最近一次演讲讲了近一小时的胡话，比如声称自己是独裁者），彻底摧毁了这种信任：</p><ul><li>2006 年 Mark Klein 和 2013 年 Snowden 爆料表示美国国家安全局在利用这个中心地位监听全世界（见 <u>棱镜计划</u>）；</li><li>2005 年美国的 <u>秃鹫资本家</u> 利用美国法院，扣押了阿根廷政府在美国的资产来偿还债务；</li><li>微软曾因海牙国际刑事法院通缉内塔尼亚胡而切断其 Outlook 服务；</li><li>约翰迪尔远程锁死俄罗斯境内的乌克兰拖拉机；</li><li>拜登政府将俄罗斯踢出 <u>SWIFT 系统</u>，意味着美元不再是中立的贸易工具，而是美国外交政策的武器。</li></ul><p>这些案例都让各国政府突然意识到，如果继续依赖美国的云服务和黑盒硬件，特朗普政府随时可以远程变砖他们的基础设施、医疗设备甚至政府大楼。</p><p>讽刺的是，美国政府过去几年里一直在警告盟友们不要使用华为的电信设备，如 5G 基站，理由是如果国家的关键基础设施使用了中国的设备，中国政府可能会出于政治目的，命令华为远程切断这些设备，或者窃取数据。现在美国反而正在做当年他们指控华为 <span class="emphasis">可能会做</span> 的事情。</p><p>既然美国已经对全世界加征关税，其他国家再遵守美国的 <u>反规避法</u> 就没有意义了。作者认为，与其对自己人加税反击，不如废除反规避法。</p><p>三、如何反击？</p><p>Doctorow 提出，因为特朗普的政策，一个前所未有的反美国科技霸权联盟正在形成。这个联盟由三类人组成：</p><ol><li>数字权利活动家：他们为了自由和隐私，呼吁了 25 年，想要开源和可互操作的设备；</li><li>逐利的资本家和企业家：如果欧洲废除反规避法，芬兰的黑客就可以合法破解 iPhone，建议一个不收 30％苹果税的第三方应用商店。这能从美国巨头嘴里抢走数千亿美元的利润；</li><li>国家安全鹰派：各国政府为了数字主权，必须摆脱对美国技术的依赖。他们不能允许国家的命脉掌握在一个随时可能发疯的美国总统手里。</li></ol><p>四、未来的 <span class="emphasis">后美国互联网</span>。</p><p>基于上述逻辑，作者描述了一个即将到来的新互联网愿景：各国修改法律，允许通过逆向工程接管设备控制权；即使美国巨头不配合，其他国家也可以开发工具，将数据从美国平台无缝迁移到本地平台；软件应该是公开、透明、可审计的，而不是私有的黑盒子。</p><p>该演讲稿的精彩之处还不止是这些。</p><p>Doctorow 解构了软件的本质以及权贵阶层为何狂热追捧 AI，他认为这背后并非技术进步，而是控制欲和傲慢。这里我就拆解成两个核心逻辑：</p><p>一、软件是负债，不是资产。</p><p>在传统的商业思维中，软件被视为知识产权，是公司的核心资产。写得越多，资产越厚。但 Doctorow 认为， <strong>软件本身是负债</strong>。</p><p>是的，软件跑起来后实现的自动化、数据分析、管理能力等，这些是资产，因为它们能赚钱。但是那些服务器里的代码，全都是负债。这是因为软件极其脆弱，需要不断的维护、修补漏洞。当上游、下游或者周边环境变化时，它随时都会崩溃。我们拥有的私有代码越多，我们需要背负的维护债务就越重。</p><p>既然软件是负债，通过专利和反规避法把代码锁起来，实际上是独自承担所有负债。在他提倡的后美国互联网系统里，基础设施代码会变成像科学原理一样的公共品。如果全欧洲，乃至全世界都用同一套开源的、可审计的基础代码，那么全人类的开发者都在帮忙修补漏洞、分摊维护成本。这才是唯一的生存之道。</p><p>二、AI 热潮的本质是阶级斗争。</p><p>如果说软件是负债，那为什么现在的科技巨头还在疯狂推崇 AI 生成代码？这是因为老板们并不懂技术。他们误以为代码量等同于价值，结果是 AI 正在以超人的速度拉出那些不可读、难维护的屎山代码，也就是在以超人的速度积累负债。</p><p>而 AI 对老板们的又一个诱惑，并不是它干得比人好，而是它够听话。老板们内心深处知道，如果自己不来上班，公司会照常运作下去；但如果工人不来上班，公司就会瘫痪。这让他们感到失控。AI 成了老板们心中所期望的听话但平庸的机器，他们根本不想要一个能干但会反驳的员工。</p><p>关于这一点，我认为在 AI 出现之前企业就有这样的征兆了。</p><p>三、唯我主义。</p><p>亿万富翁和独裁者们迷恋 AI，是因为他们梦想构建一个 <span class="emphasis">没有人的世界</span>。这个世界里，只有唯一的「神」和无数唯命是从的「信徒」，即他们和 AI。没有任何人会因为专业知识、道德底线或人类情感而对他们说「不」。</p><p>Doctorow 的另一论点是： <strong>舒适导致依赖，危机催生主权</strong>。</p><p><u>历史唯物主义</u> 认为，舒适区的惯性只能被生死的危机打破。为了证明这一点，Doctorow 回顾了俄乌战争引发的欧洲能源危机。普京切断天然气供应本意是扼住欧洲的咽喉，这在当时被视为一场灾难。然而结果出人意料，这种极端的匮乏感并没有让欧洲崩溃，反而通过休克疗法治好了欧洲在能源转型上的拖延症。短短三年，欧洲人爆发出了惊人的适应力，太阳能的普及率呈指数级增长，原本落后的能源转型计划不仅追平了进度，甚至提前了十年完成！</p><p>在舒适的旧秩序下，人们会因为各种琐碎的理由，例如「开源软件不好用」、「迁移数据太麻烦」、「美国服务更成熟」，而拒绝改变。然而，一旦出现了大问题，所有的审美洁癖和用户体验惯性瞬间变得一文不值。</p><p>说来也巧，阳台光伏是一种典型、自下而上、分布式的解决方案，不需要等待国家建设巨大的核电站，每个家庭买回来挂上就能发电。这正符合 Doctorow 对后美国互联网的构想。</p><p>这些观点让我想起了现在的中国。在很长一段时间里， <u>全球化分工</u> 是效率最高的模式：如果能买到英特尔的芯片、能用微软的系统，为什么要花十倍的钱、百倍的时间去自己造一个性能只有人家一半的产品？这就是经济学上的 <u>比较优势</u>，但也容易导致「造不如买」的路径依赖。</p><p>正如 Doctorow 所说，和平时期不会有人乐意去打不值得的仗。但当制裁降临，由于买不到现成的，「必须自己造」就成了唯一的选项。这种孤立反倒是人为地制造了一个封闭的进化环境，迫使中国企业必须在没有外部输血的情况下建立自己的循环系统。</p><p>比尔・盖茨曾经说过，美国对华科技封锁起到了截然相反的效果，且迫使中国在芯片制造等所有领域全速发展。除了让国家学会自力更生，更为可怕的是它导致了市场的永久性丢失和技术标准的各种分裂。因为中国市场曾是美国科技巨头最大的利润来源之一。</p><p>失去了这个市场，美国企业便失去了巨大的研发资金回流，从而削弱了它们继续领先的能力。一旦中国建立起一套完全独立且成熟的生态系统，世界就会分裂成两个宇宙：对于全球南方国家来说，如果中国的方案不仅便宜，而且没有被随时断供的政治风险，那么美国的地位确实会一低再低。</p><p>说完美国对其他国家的影响，也需要聊聊美国现在内部的问题。过去我借 <a href="/posts/31df#%E9%BA%A6%E5%BD%93%E5%8A%B3%E6%AD%A3%E5%9C%A8%E5%A4%B1%E5%8E%BB%E5%85%B6%E4%BD%8E%E6%94%B6%E5%85%A5%E9%A1%BE%E5%AE%A2">麦当劳</a> 一事提到过美国经济走向了 <u>K 型分化</u> 之路，即有钱人更有钱、没钱人更没钱。不得不承认的是，美国曾经作为全球最大消费市场的地位已经名存实亡。为了维持体面的消费假象，只能刷信用卡、借房贷、背住房教育医疗债务。</p><p>较为唏嘘的是，我曾经也因为刷信用卡过多而背上债务，好在欠的钱不多，找到工作后很快便还干净了。我的建议是千万不要每个月只还最小数额，这是个陷阱，你只会越欠越多。每个月花多少还多少才是正道。</p><p>毫无疑问，特朗普政府加速了这一榨取过程。特朗普本人就是那些不创造价值、仅靠垄断资源收取租金的人的一员。无论是削弱对房租操纵平台的监管、重启学生贷款偿还，还是扼杀降低药价的计划，这些政策的目的只有一个：把钱从普通人的口袋里掏出来，转移给债务催收者和垄断巨头。</p><p>每一美元被用来偿还利息，就意味着少一美元用于实体消费。这种政策也在制造一个没有人的世界；在这个梦想中，工薪阶层被剥夺殆尽，所有的财富都流向了股市、加密货币垃圾币和赌博网站，在金融空转中不断膨胀，却与实体经济毫无关系……</p><p>既然废除反规避法可以打击美国科技巨头，那会不会跟着让欧洲的科技公司受损呢？Doctorow 认为会，但是只有肮脏、无耻的公司会受损。为了证明这一点，他举了四个例子：</p><ol><li><p>大众汽车在软件里写了作弊代码，检测到尾气检查时就降低排放，平时则超标排放。如果你是一个独立的工程师，想逆向分析大众汽车的软件，你就会因为反规避法而坐牢。法律不仅保护了代码，还保护了犯罪证据；</p></li><li><p>宝马和梅赛德斯用软件锁住硬件上已有的功能，要求每月付订阅费才能使用。反规避法禁止了第三方修车铺帮你越狱解锁这些功能；</p></li><li><p>美敦力提供呼吸机，但它要求用官方维修工输密码才能修好。新冠疫情期间，官方维修工过不来，医院自己的工程师虽然懂技术，但因为没有密码且破解密码违法，只能眼睁睁看着病人死去；</p></li><li><p>Newag（波兰火车公司）更为离谱，在火车代码里写了地理围栏。如果火车 GPS 定位到在竞争对手的维修厂里，火车就自动锁住，Newag 便可以借此向客户勒索高额解锁费。</p></li></ol><p>不过这一点过于激进，更像是为了贴合演讲风格而说的。实际上，中小微企业和独立创作者极有可能成为附带损伤。并且越狱工具也可以用于做坏事。</p><p>这是一个经济学悖论：监管有时是保护弱者的，在这种情况下，去监管反而会利好强者。不过转念一想，目前巨头垄断带来的伤害远大于潜在的盗版伤害，且现在的小开发者也在被巨头们剥削，不如打破围墙，大家一起在外面跑。</p><p><a id="现在孩子们已经很少读完整本书了即使是在英语课上"></a></p><h4 id="现在孩子们已经很少读完整本书了即使是在英语课上"><a class="markdownIt-Anchor" href="#现在孩子们已经很少读完整本书了即使是在英语课上"></a> <a href="https://www.nytimes.com/2025/12/12/us/high-school-english-teachers-assigning-books.html">《现在孩子们已经很少读完整本书了，即使是在英语课上》</a></h4><p>这篇文章让我想起我在美国接受的 K-12 教育，即从幼儿园到高中毕业，只是我是在小学四年级的时候才来的美国。美国的小学到五年级就结束了，初中是从六年级上到八年级，然后高中从九年级上到十二年级。</p><p>初中对我来说是一个颇为重要的时期，因为我在那会儿明明可以好好学习英语，但是我选择了继续和华语使用者打交道，导致我现在的英语水平并不算好。来美国接受教育的第二年就需要通过 ESL 测试，也就是 English as Second Language 测试。我六年级那年并没有通过，因为考官认为我一直在照着原句读，到了七年级我才通过。</p><p>说回学校里的英语课，它大致可以分为两类：ELA 和 ESL。前者类似于「语文」，后者是非英语母语者学习英语的课程。两者使用的教材都是裁剪过的小说或者文章，例如我印象里比较深的《少年 Pi 的奇幻漂流》。</p><p>当时我们是每过几天就跳着阅读一个章节，可能上次阅读还在说 Pi 在船上发现有老虎、斑马和鬣狗，下次阅读就变成了斑马和鬣狗全都死了，被遗漏掉的信息还是以括号的形式出现在章节的前面。</p><p>到高中的时候这件事才开始有改善。高中的那几年我阅读了一些有趣的书籍，例如《一个印第安少年发现真我的日记》、《太阳也是一颗星星》以及同作者的开山之作《一切的一切》。或许我应该重新阅读它们，因为它们蛮有意思的。</p><p>我一直在思考，我现在如此讨厌阅读英语文章或者书籍，是因为什么？<br>是我没有养成这个习惯吗？好像从小我就没有被要求过定期阅读书籍，我目前的阅读量低到令人发指。</p><p>是我讨厌英语吗？我现在阅读英语文章会使用大量的翻译工具，虽然也可以，但是真的是一个好习惯吗？我又不是真的看不懂。</p><p>在写这些内容时我也发现一件事情：输出是一件很重要的事情，因为我都忘了这些年来我阅读过什么。努力细想后才想起来。如果从那个时候就开始写下自己「读了什么」，或许印象会更为深刻，然而我的「开智」也不过是近些年才开始的。</p><p><a id="ai-代理正在吞噬-saas"></a></p><h4 id="ai-代理正在吞噬-saas"><a class="markdownIt-Anchor" href="#ai-代理正在吞噬-saas"></a> <a href="https://martinalderson.com/posts/ai-agents-are-starting-to-eat-saas/">《AI 代理正在吞噬 SaaS》</a></h4><p>过去我们很多时候谈论 AI 代理讨论的都是它如何影响供给侧，也就是它们如何降低创作成本。市场分为供给和需求两侧，如果将视线转向需求侧，问题就会变成「为什么我要花钱购买你的服务，而不是让 AI 代理帮我做这件事？」</p><p>我想到了近期 TailwindCSS 团队发生的事情。他们提供 UI Kit 定制服务，但是因为 AI 代理的存在，不得不裁员来维持公司的存活。当时 <a href="https://github.com/tailwindlabs/tailwindcss.com/pull/2388">讨论串</a> 内有人这么说：「这很大原因出于已经没有人想要 UI Kit 定制服务了。」</p><p>是啊，有了 AI 代理后，只需要告诉它你想要什么样的 UI，它就可以照着你想要的做出来。这意味着有更多类似的服务会因为 AI 代理而消亡。</p><p>不过作者也表示，并不是所有的服务都会受其影响，例如 Slack 就很难被 AI 代理影响到，Stripe 也无法被轻易地取代。</p><p>而最有可能被影响到的是那些实际功能简单的工具，例如只会进行 CRUD 操作的后端工具。</p><p><a id="如果-ai-取代了人类员工那它需要付税吗"></a></p><h4 id="如果-ai-取代了人类员工那它需要付税吗"><a class="markdownIt-Anchor" href="#如果-ai-取代了人类员工那它需要付税吗"></a> <a href="https://english.elpais.com/technology/2025-11-30/if-ai-replaces-workers-should-it-also-pay-taxes.html">《如果 AI 取代了人类员工，那它需要付税吗？》</a></h4><p>这是一篇很「美国」的文章，因为涉及到「税」。</p><p>我和身为税务师的朋友讨论过这个问题。她的看法是 AI 没有收入，自然无法付税。它身为工具和服务，客户在使用前已经付了消费税。</p><p>我认为如果岗位越来越少的话，国家的经济不是会一直走下坡路吗？政府终有一天会对 AI 下手吧。她则认为 AI 的出现会让岗位的平均水平提升，大家都要学会使用 AI 工具，并且收入也会因此增长，这对经济而言是一件好事。</p><p>我很难以宏观的角度去赞同这一观点：现在的经济明显是在走下坡路，AI 热终究是一个泡沫，到了一个阈值这一切终会「炸开」，而剩下的人们多数都是被企业放弃培养、曾经被说是「不如 AI」的人。从来不去培养初级工程师的话，未来又怎么可能会有高级工程师给你用呢？</p><p><a id="想法并非越来越难找"></a></p><h4 id="想法并非越来越难找"><a class="markdownIt-Anchor" href="#想法并非越来越难找"></a> <a href="https://asteriskmag.com/issues/12-books/ideas-arent-getting-harder-to-find">《想法并非越来越难找》</a></h4><p>我过去想过这样的一个问题：想法是有限的，总有一天人们会想完所有的想法，那时候怎么办呢？</p><p>经济学界普遍认为点子正在变得越来越昂贵，因为维持技术进步所需的研发投入正在指数级增长。不过呢，从专利产出的数据来看，人类产生突破性想法的效率并没有下降，反而提升了许多。那到底是什么导致了它们没有「端上桌来」？</p><p>答案是万恶的市场。</p><p>许多超前或者高效的创新在进入市场后，并不能像过去那样通过竞争淘汰低效的旧技术。掌握旧技术的往往都是老公司，而新公司很难仅仅因为个新点子便占据大量的市场份额，反倒是很容易在实际的生产力被转化之前就被干倒。更别提一些概念被提出后就被老公司抄去……</p><p><a id="那个售卖时间的女人和那个试图阻止她的男人"></a></p><h4 id="那个售卖时间的女人和那个试图阻止她的男人"><a class="markdownIt-Anchor" href="#那个售卖时间的女人和那个试图阻止她的男人"></a> <a href="https://www.bbc.com/news/articles/c4nn7gew9zxo">《那个售卖时间的女人，和那个试图阻止她的男人》</a></h4><p>19 世纪的人们并没有可以随地查阅最新的权威时间的能力。假设你是一个商家，店里挂着一个钟，你要如何每天都确保它的时间是正确的？</p><p>Belville 家族的成员会定时去天文台（伦敦最权威的时间来源）一次、校准自己手表的时间，然后将这个信息卖给他们的客户。标题里的「女人」便是家族的最后一位时间销售员 ——Ruth Belville。在她的任职期间，发生过一次「竞争公司为了抢占市场份额，在公众面前攻击她」的事件。</p><p>John Wynne，也就是标题里的「男人」，是标准时间公司的董事。该公司提供的是通过电报信号自动校时的新技术。为了抢占市场，他在《泰晤士报》上发表了一篇演讲，包含了大量针对女性的人身攻击，以及对她的做法的嘲弄。</p><p>结果是，这番言论并没有让 Belville 失去客户，反而让公众对她产生好奇和敬佩、带来了更多的知名度和客户。一直到 1940 年她年近八旬时才退休，而当时英国广播公司也就是 BBC 已经开始通过无线电广播发送格林威治时间信号。</p><p><a id="儿童癌症患者的数百万治疗款项被骗"></a></p><h4 id="儿童癌症患者的数百万治疗款项被骗"><a class="markdownIt-Anchor" href="#儿童癌症患者的数百万治疗款项被骗"></a> <a href="https://www.bbc.com/news/articles/ckgz318y8elo">《儿童癌症患者的数百万治疗款项被骗》</a></h4><p>这是一篇令人心碎的报道。</p><p>儿童癌症患者的家庭被跨国网络诈骗团伙利用，进行虚假的筹款，榨取民众们的同情心。事后，诈骗团体会欺骗这些家庭其实没有赚到钱 —— 事实上捐款多到难以想象 —— 然后跑路。这些款项原本可以用于拯救那些因经济问题而无法得到有效治疗的儿童癌症患者，但是没有，它们都进了诈骗团伙的腰包。</p><p>BBC 发现这些团伙会在哥伦比亚、菲律宾、乌克兰等地寻找目标家庭，而筹款组织则在以色列、美国或加拿大注册，以获取捐款人的信任。他们甚至会雇佣当地的中间人来招募病童，部分中间人对诈骗性质表示知情。可悲的是，就算发现了一个有问题的组织，他们也会立即更换全新的名称继续行骗。</p><p>我很难不去怀疑我所看到的所有捐款，因为前不久我刚被维基百科基金会「坑」了一次。我们需要知道这些款项的背后都是谁，但我们作为普通人，真的能发现得了吗？可能对我们来说最稳妥的方法就是「变冷漠」—— 不给任何人自己的东西。这么做听上去不近人情，但是在这个到处都是谎言的社会，可能人人都会慢慢不再关心彼此。</p><p><a id="玩耍时间最长清理时间最短的玩具"></a></p><h4 id="玩耍时间最长-清理时间最短的玩具"><a class="markdownIt-Anchor" href="#玩耍时间最长-清理时间最短的玩具"></a> <a href="https://joannabregan.substack.com/p/toys-with-the-highest-play-time-and">《玩耍时间最长、清理时间最短的玩具》</a></h4><p>作者以游玩的频率、时长和收拾的轻易度这三个维度评价了孩子的各个玩具。如果你不知道该如何给小孩子挑选玩具，可以参考这篇文章。</p><p>吸引了我注意力的是「磁力砖」这个玩具，我从未听说过，但是感觉好好玩。</p><p>我小时候玩得最多的是「魔尺」。按理来说它可以组成的搭配相当有限，不过得利于我小时候那强大的想象力，我可以将其拼成我认为的「人」或者「精灵」、放置在一个我编写的故事里。自然，到这个地步就已经不是「选什么玩具」这样的问题了…… 因为我可以把所有看到的东西都当作是长相奇怪的「精灵」。现在反而做不到了，实在是令人悲伤。</p><p><a id="自由薯条"></a></p><h4 id="自由薯条"><a class="markdownIt-Anchor" href="#自由薯条"></a> <a href="https://zh.wikipedia.org/zh-cn/%E8%87%AA%E7%94%B1%E8%96%AF%E6%A2%9D">《自由薯条》</a></h4><p>2001 年，美国发生了可怕的 911 恐怖袭击。事后美国政府指控伊拉克拥有大规模杀伤性武器，并且暗中支持恐怖主义组织，因此主张必须通过军事手段推翻萨达姆政权。</p><p>这一军事行动计划未能获得联合国的明确授权，美国只能试图通过外交压力促使联合国安理会通过决议，批准对伊拉克动武。在这一争取国际合法性的过程中，美国与以法国、德国为首的欧洲盟友发生了严重的战略分歧。</p><p>当时的法国是联合国安理会常任理事国，拥有极其关键的一票否定权。法国坚持认为战争应当是最后的手段，主张给予联合国武器核查人员更多时间在伊拉克进行核查，以确定是否真的存在美国口中的武器。</p><p>美国对此很不满意，公开嘲讽法国和德国代表了过时的「老欧洲」，而支持美国的东欧国家才是「新欧洲」。美国舆论普遍认为法国不仅阻碍了美国的国家安全行动，还忘恩负义（美国二战期间和结束后多次帮助法国）。这种政治上的受挫感转化为了美国国内强烈的反法情绪。</p><p>在这种舆论氛围下，北卡罗来纳州的共和党众议员 Walter B.Jones 提议将「法式薯条」（French Fries）更名。</p><p>没想到的是，2003 年 3 月 11 日，众议员行政委员会主席兼俄亥俄州共和党众议员 Bob Ney 还真的指示国会众议院的三家自助餐厅去正式修改菜单：「法式薯条」改名为「自由薯条」（Freedom Fries）、「法式吐司」（French Toast）改名为「自由吐司」（Freedom Toast）。</p><p>Ney 声称，此举旨在表达对法国「拒绝支持美国盟友」的不满，并象征性地剥夺法国在国会大厦菜单上的「名分」。</p><p>当时的民意调查显示，有不少美国民众支持这一象征性的抗议行为，视其为一种低成本的爱国主义表达。</p><p>随着伊拉克战争局势的演变以及美国国内政治气候的变化，「自由薯条」的热度逐渐消退。到了 2005 年和 2006 年，随着美军在伊拉克陷入泥潭，公众对战争的支持率大幅下降，这种针对法国的象征性抗议显得愈发不合时宜。更为关键的是 Ney 因其他事件而陷入法律困境，最终辞职和入狱，他对国会餐厅的管辖权也随之旁落。</p><p>2006 年 8 月，接替 Ney 担任众议院行政委员会主席的密歇根州众议员 Vern Ehlers 在没有发布任何官方声明的情况下，悄然指示国会餐厅将菜单改回了「法式薯条」。</p><p>更戏剧性的在于，最初的提议者 Jones 后来成为了伊拉克战争的公开反对者，并对自己当年的行为表示了悔意，希望这件事从未发生过。</p><p>一战其实也发生过一样的事情。1917 年美国对德国宣战后，国内爆发了极端的反德歇斯底里情绪。</p><p>当时作为德国饮食文化代表的「酸菜」（Sauerkraut）被认为带有敌国色彩，为了切断与敌人的文化联系并激发爱国热情，美国国内的生产商和部分官方机构将其更名为「自由卷心菜」（Liberty Cabbage）。</p><p>这种改名风潮波及甚广：「德国麻疹」（German measles）要叫「自由麻疹」（Liberty measles），「汉堡」（Hamburger）要叫「自由三明治」或者「自由牛排」（叫「牛排」是因为这里的「汉堡」并非我们现在认为的「汉堡包」，其形式可以想象一下日本的「汉堡肉」），甚至「腊肠犬」（Dachshund）也要叫「自由犬」（Liberty pups）。</p><p>用现在的眼光去看，就会觉得这帮人作为政客，做的事情可是一个比一个幼稚，将其视为美国反智主义抬头的表现也不为过。</p><p><a id="ai-导致学校进入封锁因其将学生的单簧管误认为枪支"></a></p><h4 id="ai-导致学校进入封锁因其将学生的单簧管误认为枪支"><a class="markdownIt-Anchor" href="#ai-导致学校进入封锁因其将学生的单簧管误认为枪支"></a> <a href="https://futurism.com/future-society/ai-surveillance-school-clarinet">《AI 导致学校进入封锁，因其将学生的单簧管误认为枪支》</a></h4><p>去年年底佛罗里达州的一所中学发生了一起乌龙事情：AI 监控系统发出警报，发现一名学生携带了枪支，事后发现这名学生手里拿的其实是单簧管。</p><p>这件事情发生没多久，马里兰州又发生了类似的事件。学校的 AI 监控系统这次误认为一名学生手里的 Doritos（多力多滋，是薯片）是手枪，导致学生被至少八名持枪警察暴力拘留。</p><p>我很不能理解的是校方的事后态度。佛罗里达州的那个学校事后责怪了携带单簧管的学生，认为对方假装在学校内持有武器 —— 这种话你都能说出口？</p><p>明明这种事情可以通过让一个人类参与其中而避免，但是这些教育机构却好像只想依靠 AI 系统的样子。这倒是让我想起前些时候的另一个新闻：AI 学校，即学生主要从 AI 那儿获取知识，而「老师」仅是辅助学生使用 AI 学习的人。</p><p><a id="我被德国铁路绑架只得到了-150-欧元"></a></p><h4 id="我被德国铁路绑架只得到了-150-欧元"><a class="markdownIt-Anchor" href="#我被德国铁路绑架只得到了-150-欧元"></a> <a href="https://www.theocharis.dev/blog/kidnapped-by-deutsche-bahn/">《我被德国铁路绑架，只得到了 1.50 欧元》</a></h4><p>作者被德国铁路「绑架」，被拉去了离目的地几十公里开外的另一个联邦州。这一事实在是荒诞，反映出德国铁路在临时变更计划时的系统性僵化。</p><p>十年纽约客看到铁路相关的话题便会不由自主想起 MTA……</p><p><a id="我解除了我的出书合约"></a></p><h4 id="我解除了我的出书合约"><a class="markdownIt-Anchor" href="#我解除了我的出书合约"></a> <a href="https://austinhenley.com/blog/canceledbookdeal.html">《我解除了我的出书合约》</a></h4><p>作者被一位出版社编辑联系上，决定写一本让读者通过动手做有趣项目来学习计算机基础概念的书。</p><p>可惜这期间发生了不少摩擦，例如作者被强制要求使用 AsciiDoc 或者 Word 而不是 LaTeX、去除个人风格、加入作者不想要添加的章节，甚至要求他的书里必须包含 AI 内容。</p><p>最后作者因工作繁忙和生活琐事，不断错过截止日期，还因 LLM 时代的到来而失去了写书的热情，主动申请了冻结项目。</p><p>不过这篇文章出来后，许多读者表示有购买意愿，让作者开启了电子书预售，计划按章节发布，并在亚马逊上发行纸质版。感兴趣的可以看看。</p><p><a id="阅读是一种恶习"></a></p><h4 id="阅读是一种恶习"><a class="markdownIt-Anchor" href="#阅读是一种恶习"></a> <a href="https://www.msn.com/en-us/news/us/reading-is-a-vice/ar-AA1Tsp7w">《阅读是一种恶习》</a></h4><p>过去十年来，美国学生的阅读能力直线下降，他们的阅读习惯也随之恶化。2023 年只有 14％的 13 岁青少年几乎每天都为了乐趣而阅读，而十年前这一比例为 27％。越来越多的高中生甚至大学生难以从头到尾读完一本书。</p><p>为了改变这一事，国际出版商协会在过去一年里一直在推广「民主取决于阅读」的口号，劝说他们为了拯救民主而读书。不过这种策略能有用才奇怪，主动去读书的人几乎都不是因为对社会有益才去读的。</p><p>作者认为可以提议将阅读视为一种恶习，这对年轻人来说才是有吸引力的。</p><p>这个角度是我意想不到的，略微思考后觉得是个不错的提议，只是我担心有些人只会去阅读禁书，却对其他书不感冒。</p><p><a id="百年流言"></a></p><h4 id="百年流言"><a class="markdownIt-Anchor" href="#百年流言"></a> <a href="https://www.plough.com/en/topics/community/one-hundred-years-of-gossip">《百年流言》</a></h4><p>Bruderhof 社区是一个非常有名的基督教公社，其生活方式非常理想主义：他们试图完全按照《圣经》的教导过群居生活，财产公有，且互相关爱。</p><p>该社区最古老的一条规则叫作 <em> First Law of Sannerz</em>，核心是「以此为爱：当面直言，绝不背后议论」。对于习惯了现代社会复杂人际关系的我们来说，这种规则实在是难以想象。那么这条规则有效吗？</p><p>这一规则在作者看来，违背人性，且可以被人利用、打着「当面直言」的旗号攻击别人。钻空子也是很容易的事情，只要靠肢体语言就可以表达对他人的轻蔑，根本不需要张口说话。更不用提八卦在心理学上算一种有用的社会均衡器了。不过《圣经》中多次提到过「舌头能燎原」，背后议论终究还是会带来不信任和仇恨。</p><p>即使「不八卦」在现代社会几乎是不可能完成的任务，但是这个百年社区依然选择将其作为最高理想，因为透明和直接是信任的唯一来源。</p><p><a id="谷歌伤透了我的心"></a></p><h4 id="谷歌伤透了我的心"><a class="markdownIt-Anchor" href="#谷歌伤透了我的心"></a> <a href="https://perishablepress.com/google-broke-my-heart/">《谷歌伤透了我的心》</a></h4><p>多年来作者一直视谷歌为值得信赖的盟友，因为谷歌过去总是迅速、无障碍地处理他关于盗版书籍的投诉，将侵权链接从搜索结果中移除。然而 2026 年的一次经历打破了这种信任。</p><p>这次谷歌并未像往常一样直接处理，而是连续三次发邮件质疑他的身份和版权所有权。这让作者感到极度失望和无助。他认为谷歌已经变成了一个傲慢、冷漠、不再关心小人物死活的官僚机器。</p><p>我认为很大一个可能是谷歌完全制裁了人工审核 DMCA 的团队，改为 AI 或者自动化脚本处理，因为作者收到的回复非常像模板话术。</p><h2 id="心理与关系"><a class="markdownIt-Anchor" href="#心理与关系"></a> 心理与关系</h2><p><a id="世界没有你的时候也会继续运转"></a></p><h4 id="世界没有你的时候也会继续运转"><a class="markdownIt-Anchor" href="#世界没有你的时候也会继续运转"></a> <a href="https://tala.bearblog.dev/what-do-you-do-when-life-keeps-going-on-without-you">《世界没有你的时候也会继续运转》</a></h4><p>艰难时期有着两个糟糕的部分：一是认为自己是唯一一个经历这一切的人；二是发现世界继续向前，而你停滞不前。</p><p>事实是，没有人会救我们。只有我们可以拯救自己 —— 这听上去像是毒鸡汤，但确实如此。我们很小，是这个宇宙的无数尘埃之一，我们只能依靠自己。</p><p><a id="薄欲正在吞噬你的生活"></a></p><h4 id="薄欲正在吞噬你的生活"><a class="markdownIt-Anchor" href="#薄欲正在吞噬你的生活"></a> <a href="https://www.joanwestenberg.com/thin-desires-are-eating-your-life/">《薄欲正在吞噬你的生活》</a></h4><p>什么是薄欲？—— 在你满足了之后、并不会实质性去改变你的一种欲望。</p><p>查看社交媒体而不是去交朋友、观看色情影片而不是寻找伴侣、使用生产力应用而没有真正生产出什么…… 这些在特定的情况下都是薄欲的一种。人们在不支付任何代价的情况下获得了短暂的快乐，又或者说其实他们已经支付了代价 —— 不再长期快乐的代价。</p><p>市面上多的是那些可以让人们快速满足的东西，但是它们没有解决任何事情，反而让一些本应该下降的指数提升了，比如孤独感。互联网让全世界的人们不可思议地联系在了一起，但是我们好像没有变得太快乐，焦虑和抑郁值一直在增长，没有停下来过。</p><p><a id="你并非职业倦怠而是灵魂在闹饥荒"></a></p><h4 id="你并非职业倦怠而是灵魂在闹饥荒"><a class="markdownIt-Anchor" href="#你并非职业倦怠而是灵魂在闹饥荒"></a> <a href="https://neilthanedar.com/youre-not-burnt-out-youre-existentially-starving/">《你并非职业倦怠，而是灵魂在闹饥荒》</a></h4><p>作者 Neil Thanedar 认为大家有个误解：我们觉得累、不想上班是因为工作太辛苦，所以我们试图通过休息、度假、优化睡眠来解决。但他认为这些方法都没用，因为我们并非倦怠，而是在 <u>存在主义</u> 方面上感到饥饿 —— 我们的生活在物质上很富足，但在精神上很空虚。</p><p>心理学家 Viktor Frankl 认为，人的主要驱动力不是快乐也不是权力，而是意义。当我们没有最高目标时，我们就会陷入存在主义真空，感觉生活停滞不前。</p><p>借此，Thanedar 引用了 <u>马蹄铁理论</u> 来解释压力：想象一个马蹄铁，它的左右两端虽然方向不同，但是是彼此的镜像。代入「压力」，马蹄铁的最左端意味着「压力太小」和「无聊」，最右端意味着「压力太大」 和「倦怠」，中间则意味着「良性压力」。</p><p>这一理论本身如何我就不评价了，因为它原本是一个政治理论，但是它让我想起了初中读的《心流：最优体验心理学》，给我的印象十分深刻（虽然很抱歉没有读完）。</p><p>简单来说，这本书的作者 Mihaly Csikszentmihalyi 认为人类的幸福并非静止的状态，也不是单纯感官享乐的堆积，而是一种通过全身心投入某件事而获得的「最优体验」。</p><p>他提出了一个动态平衡：当外界赋予的任务挑战过高而个人技能不足时，人会感到焦虑；反之，当技能很高而挑战过低时，人会感到厌倦。 <u>心流</u> 只存在于这两者之间。为了维持这种状态，个体必须不断提升技能以应对更高的挑战，或者寻找更难的任务来匹配已有的技能。</p><p>因此，心流本质上是一种促进个体复杂性成长和自我进化的驱动力，它要求活动具备明确的目标、即时的内部反馈，以及技能与挑战的匹配。只要符合这些要点，大众常以为苦的流水线工人也可以进入心流状态。</p><p>他也提到现代人感到空虚的原因往往在于过度追求被动的享乐，而缺乏主动创造乐趣的能力。书中有一句话让我印象最为深刻： <strong>人要学会自娱自乐</strong>。这倒是让我想起 Aristotle 的一句话：</p><blockquote><p>离群索居者，不是野兽，便是神灵。</p></blockquote><p>Karl Marx 在他的《1844 年经济学哲学手稿》中提到了「异化劳动」这个概念。劳动本应是人类本质力量的自我确证，但在资本主义生产关系下，劳动发生了多重异化：</p><ol><li>你造出来的东西不归你，它变成了商品被拿走换钱；</li><li>产品越完美，工人越贫穷；</li><li>劳动不再是目的，而成了生存的手段；</li><li>劳动变成了「外在的苦难」，人只有在不劳动时才觉得自在。</li></ol><p>当「钱」成为了唯一的衡量标准时，劳动的挑战性就不再是乐趣的来源，而是痛苦的来源，因为挑战意味着可能拿不到钱的风险。这会形成一个恶性循环：工作被剥夺了自反馈，人们为了防御痛苦选择「摆烂」，结果掉入了「无聊」的无底洞，不得不为了缓解无聊而转向高刺激的消费。</p><p>室友有一套自己的理念，她认为人生的重点在于「热爱」。她看一个人的标准基本上就是看这个人是否有热爱，一个人为了自己的热爱而努力的姿态是最闪亮的。那些没有「热爱」的人，对她而言则不过是随波逐流的垃圾，是无聊的。</p><p>自然，她的表述很是极端。不过她的一个问题我认为是只看到了空心人们的「果」，而没有看到「因」。社会已经被异化了许久，人们空虚的同时，只能依靠市场提供的奶头乐来刺激自己享乐。他们是系统性饥饿的受害者。</p><p><a id="不要变成机器"></a></p><h4 id="不要变成机器"><a class="markdownIt-Anchor" href="#不要变成机器"></a> <a href="https://armeet.bearblog.dev/becoming-the-machine/">《不要变成机器》</a></h4><blockquote><p>只有奴隶才通过生产力来衡量自己的存在。</p></blockquote><p>作者讲到了奋斗文化（Hustle Culture），简单来说可以认为是一群人在表演自己很奋斗：炫耀加班时长、用古怪的方式工作…… 一个很好的观察场地是 LinkedIn（领英）。</p><p>大家迷恋于自己可量化的一面，却忽略了真正重要的产出，并用自己的「生产力」来证明自己的价值，已经和机器无异。</p><p>作者认为成功的策略应该是不追求线性和盲目的苦干，而是发挥人的优势 —— 适应性和策略性。</p><p><a id="在咖啡馆独处的不能承受之乐"></a></p><h4 id="在咖啡馆独处的不能承受之乐"><a class="markdownIt-Anchor" href="#在咖啡馆独处的不能承受之乐"></a> <a href="https://candost.blog/the-unbearable-joy-of-sitting-alone-in-a-cafe/">《在咖啡馆独处的不能承受之乐》</a></h4><p>标题中的 <em> Unbearable Joy</em> 引用了 <em> The Unbearable Lightness of Being</em>，即《生命中不能承受之轻》这本名著，我在翻译中保留了这一点。</p><p>我是建议阅读原文，因此不对这篇文章编写总结，只说我的想法。</p><p>不知何时，我再也 <span class="emphasis">不独自出去</span> 了。初中的时候我因为被同学孤立，会每周走半小时的路去图书馆借书。那时候或许是我人生中可以算是「厉害」的阶段：绘画上对自己无比满意、每周都会阅读五本书、成绩还算不错，就是人际关系上有些糟糕，无论是和家庭还是和同龄人。</p><p>然后从一个时间点开始，我不再那么做了。我不读书了，我不出门了，我不画画了。到底是什么时候呢？我也说不上来。</p><p>现在我几乎是除了和人有约外，就只会因为打工而出门。我在家里待了太久，却没有出门的欲望。我对外面有着一种恐惧：我可能会被流浪汉纠缠、可能会被跟踪、可能会被杀…… 这些自然都是我的被害妄想。不过出门确实对我来说变成了一种团体活动，但不会有人永远都带着我出门。</p><p>这个月我产生了许多幻想。说是幻想是因为我实际上没有精力去实现它们，意味着在我的脑海里它们的优先级并不高。我看到一位博客站主购买了相机，对他路上拍的照片感觉羡慕，因此评论表示自己也想要购买一个、出门拍着玩。对方的回应是这种事想了就要立即去做。我心想说得对，但也没有动身子 ——「相机好贵，我想要在二手市场淘一个。二手卖家的家好远，我不想去。我不是还有工作要做吗？这件事就放一放吧。」</p><p>如果我没有记错的话，我的那个评论是在月初发的，而现在你看到的这个内容是月底写的。</p><p>我从很久之前就幻想过我可以再去图书馆，但是我的脑海里也产生了许多阻力：「那家图书馆我没有实体卡，我要去办吗？好像我有虚拟卡，但是我懒得查……」</p><p>懒，懒， <strong>懒</strong>！</p><p>我又不是不知道如果那么做了我会很开心，但我就是没有那么做。</p><p>虽然我很讨厌打工，但是它对我来说有一些好处：不是特别忙的时候，我可以观察顾客们。例如每周六早上都会进来一个老头，戴着帽子系着围巾牵着条狗，他每次都会点一杯热的金橘柠檬茶，坐着慢慢喝。这期间他什么都不会坐，只是坐着。如果有其他顾客过来和他的狗互动，他会笑着说你要摸摸它吗。</p><p>纽约市是一个快节奏的城市，对比美国的其他地方。我很意外我会在这样的地方看到人们慢节奏地生活，毕竟很多顾客取走饮品后就会立即离开，其中的一部分人干脆是在等车的五分钟内进来买东西，公交车快到的时候还会催我们。能悠哉坐在这里很久的群体，除了身为成人的「怪人」外，就只有学生了。</p><p>说到学生，我有时能遇到非常可爱的小学生或者初中生。这里的「可爱」并非指的是外观，而是他们的思维和行为。他们会带着一本厚重的书读，说话有礼貌也很安静，这种小孩子会让人打心里觉得「真不错」，对比一些烦得要死的熊孩子们。</p><h2 id="科学与自然"><a class="markdownIt-Anchor" href="#科学与自然"></a> 科学与自然</h2><h2 id="技术与创造"><a class="markdownIt-Anchor" href="#技术与创造"></a> 技术与创造</h2><p><a id="github-的垄断是如何正在摧毁开源生态系统的"></a></p><h4 id="github-的垄断是如何正在摧毁开源生态系统的"><a class="markdownIt-Anchor" href="#github-的垄断是如何正在摧毁开源生态系统的"></a> <a href="https://ploum.net/2026-01-05-unteaching_github.html">《GitHub 的垄断是如何正在摧毁开源生态系统的》</a></h4><p>GitHub 近期一直都有问题，倒不如说从微软接手了之后，GitHub 再也不是我们心里的开源社区代表之一了。</p><p>作者想要知道他的学生的报告里，有多少是和被托管在 GitHub 上的项目有关，结果是只有 238 之 7 个是和 GitHub 无关的，而这里有 6 个人是忘了添加代码库的 URL，实际上使用的代码库依然被托管在 GitHub 上。</p><p>作者认为，GitHub 的替代方案有很多：</p><ul><li>GitLab</li><li>Codeberg</li><li>Forgejo</li><li>Sourcehut</li><li>Fossil</li><li>Mercurial</li><li>Radicle</li></ul><p>他告诉学生们要去看看 GitHub 以外的内容，但是这 238 个人里，只有 1 个人那么做了。</p><p>为什么一定要去看看 GitHub 以外的内容呢？这就要说到 <u>集权化</u>。当所有数据都放在一个服务上，最大的危险便是失去对它们的访问权限。</p><p>谷歌账户就是一个很好的例子：你有一部基于谷歌的手机，你可以登录你的谷歌账户、用谷歌邮箱注册其他网站的账户，并且简单地用手机作为 Passkey 源。一切都太方便了！</p><p>但如果你的手机坏了，或者你的谷歌账户登不上手机了，你再去登录其他网站就会变得很麻烦，因为你除了这个手机外，没有其他「可以证明你是你」的证据。而谷歌决定抽风、让「你」消失。</p><p>同样的例子也可以用在其他服务上，苹果是如此，微软也是如此。</p><p>对于 GitHub 来说，我认为问题更为复杂一些。GitHub 被社区的人们描述得太像一个 <em> Only One</em> 了 —— 大家都在使用它：找项目使用它，贡献使用它，托管私密代码使用它…… 好像除了 GitHub 之外，其他选择都是「看不见摸不着」，或者说「不入流」。</p><p>我也考虑了一下我的情况。我许多时候代码都会优先放在 GitHub 上，它变得像一个云盘，尽管它不是，并且有可能把我的代码都弄没。不过企业相关的代码，我会放在 BitBucket 上，毕竟它是为了企业而生的。这样说来，我对开源的看法，很有可能就是被局限在 GitHub 的一亩土地里。</p><p><a id="bear-vs-pika-vs-writeas"></a></p><h4 id="bear-vs-pika-vs-writeas"><a class="markdownIt-Anchor" href="#bear-vs-pika-vs-writeas"></a> <a href="https://commentingon.xyz/bear-vs-pika-vs-writeas">《Bear vs Pika vs Write.as》</a></h4><p>作者比较了三个写作平台：Write.as、Pika.Page 以及 Bear Blog。</p><p>我从未接触过这些写作平台。过去，我以为你要写博客只能是自己构建、部署一个。直到最近我才知道，其实互联网早就有了这样的平台，可以帮助你构建网页样式，你只需要写…… 还有选择域名？应该吧。</p><p><a id="br-标签的三十年"></a></p><h4 id="br-标签的三十年"><a class="markdownIt-Anchor" href="#br-标签的三十年"></a> <a href="https://www.artmann.co/articles/30-years-of-br-tags">《br 标签的三十年》</a></h4><p>作者聊了聊他眼里，从 90 年代到现在的这 30 年里，web 开发都发生了什么。这篇文章有点长，但是值得去了解这段历史。</p><p>我个人很羡慕从小就接触了计算机并去学习原理的人。我是疫情的时候才学习计算机相关的东西。当时我想要自己弄一个视觉小说游戏，接触了 OnScripter，后来想着反正闲着也是闲着，不如学习编程。当时入门学的是 C++，但是没有系统地学习，导致我基础没有打好就开始做「C-c C-v 战士」了。</p><p>让我意外的是，WordPress 居然在 03 年就诞生了。后面想了想也合理，它的底层是 PHP，能用上这东西的怎么说也是老资历了。我只用过一次 WordPress，是因为甲方要求我用这个。感觉刚会 Web 开发不久，对这种低代码平台很是嗤之以鼻 —— 又慢又难用，实在是不够优雅。现在看来技术栈什么的真的没有那么重要，业务才是最重要的。就像是个人博客网站，重点是展示自己，也就是内容。不过技术栈也可以或多或少代表一个人的某些特质，还是不能把话说死了。</p><p>我了解过前端的历史，很多事情都要从那个手机开始说起 ——iPhone。智能手机的大众化让开发者不得不去考虑「如何让网站变成在移动设备上看也很正常」这个问题。答案是响应式设计。前端和后端就此正式分成了两派：你写你的 API，我渲染我的样式，我们不走同个道儿了～</p><p>文章里提到了 MongoDB，并讲了这样的一个笑话：「初创公司会选择 MongoDB 因为他们会考虑到未来的百万用户，然后在用户只有几千人的情况下花费数年时间。」哦不，这说的根本就是我！</p><p>Agile 和 Scrum，我认为它们是有趣的东西。Scrum 可以在现在的许多企业里看到，至于 Agile，就不太一定了。我在某个项目里曾经提起过 Agile，主要是因为那会儿功能都没有约定好，你个破登录做了这么久做不好，不如直接开始折腾后面的部署，先把 MVP 展示出来。结果那个同事以很鄙夷的语气问道：「你想要搞敏捷开发？」虽然后面登录做好了，但是没有保护路由，所以登录不登录根本不重要。而他也因为不太懂部署和前后端之间的关系，折腾了很久才部署成功。</p><p>作者写到 AI 时代的时候，这种事实的冲击依然让人难以接受：原本感觉无限丰富的市场，居然收得这么快速。初创公司貌似变多了，但是岗位一直在减少，大家挤破了头都想进一个岗位 —— 靠更好看的简历、更有噱头的项目、更硬的人脉……</p><p><a id="我是肯尼亚人我不像-chatgpt-那样写作chatgpt-像我一样写作"></a></p><h4 id="我是肯尼亚人-我不像-chatgpt-那样写作-chatgpt-像我一样写作"><a class="markdownIt-Anchor" href="#我是肯尼亚人-我不像-chatgpt-那样写作-chatgpt-像我一样写作"></a> <a href="https://marcusolang.substack.com/p/im-kenyan-i-dont-write-like-chatgpt">《我是肯尼亚人。我不像 ChatGPT 那样写作。ChatGPT 像我一样写作》</a></h4><p>前几个月我因为「写出了学生不应该写出来的代码」而被质疑使用 AI，这种感受无疑是令人愤怒的，更不用提愚蠢的部门最终选择逃避了我的反质疑、继续将他们那害人的教学方式留给未来的学生们 —— 哦对，我那个分数他们也没有给我，谁叫那个作业只占整体成绩的 2％ 呢？实在是虚伪至极，还懒惰。</p><p>我认为较为可悲的是这些「AI 警察」比谁都更要「AI 入脑」。他们已经默认了人类做不到一些事情，并认为自己所看到的就是世界的一切。</p><p>我高三的时候因为 SAT 认真地钻研了一点点英语，并在大一的时候从教授那儿学习了更为专业的英语写作方式。如果完全使用这些方式来书写英语内容，恐怕也会被人以为是 AI 写的，但我写句子的时候很难不去想句子的完整性、比较时怎么写才是「公平」的、使用 <em> furthermore</em> 这样不知道为什么很戳我的连接词…… 我能怎么办呢？我就是这么被教的。</p><p>大一暑假的时候，一位校友询问我我的现状，我回 <em> enhance my xxx skills</em> 却遭到其嘲笑：「你是 ChatGPT 吗？」ChatGPT 你个头喔。</p><p><a id="time-元素应该做点什么"></a></p><h4 id=""><a class="markdownIt-Anchor" href="#"></a> <a href="https://nolanlawson.com/2025/12/14/the-time-element-should-actually-do-something/">《 <code>&lt;time&gt;</code> 元素应该做点什么》</a></h4><p>HTML 有一个 <code>&lt;time&gt;</code> 元素，使用方法如下：</p><pre><code class="language-html">&lt;time datetime="2026-01-01T00:00:00.000Z"&gt;  刚刚&lt;/time&gt;</code></pre><p>我的博客里就有使用它。</p><p>作者发现 <code>&lt;time&gt;</code> 元素明明是语义上可以精确表达时间戳的方式，但是其实际上的使用率低到不可思议 —— 根据 Chrome 浏览器所说，只有 8％ 的页面会加载使用它。</p><p><a id="我在地铁上编程"></a></p><h4 id="我在地铁上编程"><a class="markdownIt-Anchor" href="#我在地铁上编程"></a> <a href="https://www.scd31.com/posts/programming-on-the-subway">《我在地铁上编程》</a></h4><p>我干过一样的事情，也是在纽约市的地铁上。唯一的区别是，我不只是在地铁上这么做，我还在巴士和渡轮上都这么做了。不过我很快就放弃了 —— 因为我晕车。</p><p>我的目的和作者一样：纽约市内的每日通勤实在是让人忍受不了。当时的我需要每天在史泰登岛上坐半小时的巴士到东北边的码头、坐半小时的渡轮到曼哈顿西南边的码头（如果错过了渡轮还需要再等半小时），最后坐半小时的地铁才能到达我的目的地；晚上的时候再以反过来的方法坐回家。这意味着我每天至少要浪费三个小时在通勤上！</p><p>因为刚刚接触到编程的美妙没多久，我巴不得每天泡在电脑上，可惜高中里的许多课禁止我使用电脑（更多是我活该）…… 这自然而然让我产生了「为什么不利用起通勤时间」的想法。</p><p>实话实说，在交通工具上编程的感受很奇怪，至少对于过去的我来看是这样的 —— 你成为了这个封闭空间里唯一一个在「积极上进」的人。我会不自觉地开始想：「其他人会如何看待我？上次我在车里写作业，对面就坐着一个人盯着我看 —— 他们觉得我是一个做作的人吗？」这当然也只是我的「被害妄想症」在发作。实际上，纽约市里还有精力去管别人的人依然是少数派中的少数派。</p><p><a id="这不是未来"></a></p><h4 id="这不是未来"><a class="markdownIt-Anchor" href="#这不是未来"></a> <a href="https://blog.mathieui.net/this-is-not-the-future.html">《这不是未来》</a></h4><p>文章的开头又让我想起了上个学期的那节计算机课。太棒了，我喜欢生活的一部分因为不同的事情而联系在一起：我又多了一个攻击部门的理由。</p><p>「披露 AI 使用」这个规则实在是太奇怪了，让我无法理解其中的含义。是觉得学生反正都要使用 AI，所以干脆任由他们那么做吗？还是教授自身水平跟不上课程内容（例如我那个不懂 HTML 的教授居然还要让我们做和 HTML 相关的作业），用 AI 当作遮羞布？</p><p>回到文章本身，我们需要明白有时候使用最新技术并不代表先进，这世上就没有什么技术是不可避免的；Off-grid 人群在这个星球上依然生活得很好。有时候阅读 Hacker News 的评论区我发现，这世上因为自主意识而选择不持有手机的人并不少，而手机是一个大家都认为必须存在于自己人生中的一个东西。</p><p><a id="times-new-roman-简史"></a></p><h4 id="times-new-roman-简史"><a class="markdownIt-Anchor" href="#times-new-roman-简史"></a> <a href="https://typographyforlawyers.com/a-brief-history-of-times-new-roman.html">《Times New Roman 简史》</a></h4><p>我不喜欢 Times New Roman。我很难描述这种感受，总之我不喜欢它，我也讨厌教授们要求我们使用这个字体。它说是「专业」和「权威」的代表，但了解到它的历史后，发现它不过是为了在报纸上的每一行里塞更多的字而设计出来的。</p><p><a id="解决问题的三种方法"></a></p><h4 id="解决问题的三种方法"><a class="markdownIt-Anchor" href="#解决问题的三种方法"></a> <a href="https://andreasfragner.com/writing/three-ways-to-solve-problems">《解决问题的三种方法》</a></h4><p>作者认为，如果将「问题」定义为「感知到的现状」与「期望的状态」之间的落差，那么解决问题的路径就不止一条，而是存在三个逻辑上的变量可供调整：</p><ol><li>改变世界以符合期望，也就是我们通常理解的努力工作去解决具体困难，将现状拉高到理想的标准；</li><li>重新审视现状，改变对现状的看法；</li><li>降低自己的期望。</li></ol><p>室友是一位有时候理性到让人觉得有些冷漠的人，她曾经提出了一套适用于自己的人际关系法：她认为人际关系上的痛苦都来源于「期待」。很多时候对对方的期待过高，会想要将对方的「价值」或行为提升到自己期望的水平，但这往往会导致双方都很痛苦。这时候想要维持这段关系，就只能调整自己的期望：对方不是好朋友、不是朋友、不是校友、不是熟人……</p><p>但是人毕竟是人，人是不擅长量化机会成本的，也难以对那些情感强烈的人说「不」。这套方法真的成功了吗？我不见得。我只看到一段本应该断掉、却因为其中一方一直在降低期望而侥幸存活下来的关系。</p><p><a id="我无法升级到-windows-11现在请别烦我了"></a></p><h4 id="我无法升级到-windows-11现在请别烦我了"><a class="markdownIt-Anchor" href="#我无法升级到-windows-11现在请别烦我了"></a> <a href="https://idiallo.com/byte-size/cant-update-to-windows-11-leave-me-alone">《我无法升级到 Windows 11，现在请别烦我了》</a></h4><p>我和作者一样，有着一台性能不错但是因为不支持 Windows 11 的电脑。我也遇到了和作者一样的问题，时不时会收到更新到 Windows 11 的提醒，尽管这个电脑想更新也更新不了。</p><p>Windows 10 的「逝去」让许多人意识到 Windows 已经不是过去的 Windows，这也包括我在内。这个月我重新翻出了自己的笔记本电脑，用于新学期的学习。因为之前就想要试试看脱离 Windows 系统，以及学习使用 Emacs，所以给这个电脑安装了 Linux 发行版。我下的是 EndeavourOS + i3WM，原本担心自己会不习惯快捷键等操作，实际用下来意外顺手。</p><p><a id="一百万个独立网络截图"></a></p><h4 id="一百万个独立网络截图"><a class="markdownIt-Anchor" href="#一百万个独立网络截图"></a> <a href="https://nry.me/posts/2025-10-09/small-web-screenshots/">《一百万个（独立网络）截图》</a></h4><p>作者看到了一个叫 <a href="https://onemillionscreenshots.com">onemillionscreenshots.com</a> 的网站，觉得这种看图选网站的交互方式很棒。</p><p>但是该网站抓取的都是最热门的网站，充满了广告和 SEO 垃圾，没点儿营养。他想要挖掘独立网络，也就是个人博客、非盈利项目，虽然不流行，但内容真诚、有设计感。</p><p>因此，他决定复刻那个看图网站，但把数据源换成这些小众网站。</p><p>关于作者的技术实现，我就看不懂了。但是你可以访问 <a href="https://screenshots.nry.me">这个网址</a> 来看看效果，很酷炫的。</p><p><a id="我是如何离开-youtube-的"></a></p><h4 id="我是如何离开-youtube-的"><a class="markdownIt-Anchor" href="#我是如何离开-youtube-的"></a> <a href="https://zhach.news/how-i-left-youtube/">《我是如何离开 YouTube 的》</a></h4><p>这篇文章我最为惊讶的是谷歌的内部构成。</p><p>过去我阅读过《重新定义公司：谷歌是如何运营的》这本书，书中对于早期的谷歌的描写，与本篇文章所描写的现实中的官僚主义有着巨大的割裂。</p><p>例如书中提到员工可以跨级汇报、只看能力而不看头衔。但对于现在拥有近十几万员工的谷歌，为了维持秩序，「层级化」这个书中曾多少有些唾弃的东西不得不成了管理上的必需品。</p><p>上个月我引用了 <a href="/posts/b211#%E4%BC%98%E7%A7%80%E7%9A%84%E5%B7%A5%E7%A8%8B%E7%AE%A1%E7%90%86%E6%98%AF%E4%B8%80%E7%A7%8D%E6%97%B6%E5%B0%9A">一篇文章</a>，表示所谓「优秀的工程管理」不过是一种时尚，同个工程管理在不同的场景下有着截然不同的效果。但看到谷歌这样在 2014 年就提出扁平化的企业，到现在却变得和它曾经厌恶的「传统企业」一样，心中依然颇不是滋味儿（虽说我认为《重新定义公司：谷歌是如何运营的》并没有全面否定「传统企业」管理的价值，但是仍然可以感觉出作者对它的不满）。</p><p>扁平化真的是一个先进的管理哲学么？实际上并不见得。就和《「优秀的工程管理」是一种时尚》的作者所说的那样，这些东西只能根据当下的环境来评估。过去谷歌提出扁平化，是因为为了留住「创意精英」们，利润也足够丰富，公司容得下大量的冗余和低效。现在的大量公司所采用的扁平化，本质上是结构上的大裁员，砍掉中间管理层、减少汇报层级，强调人效比。</p><p>而现在的谷歌，其内部人数过大，为了避免信息的拥堵和决策瘫痪，采用严格的级别制度是必然的。「好管理」是适应环境的产物，根本就没有什么管理是客观而言优秀的。</p><p>但是对于仍然想要创新的人们，离开这种大公司才是最好的选择。</p><p><a id="pixelfed-正在锯着-fediverse-坐着的树枝吗"></a></p><h4 id="pixelfed-正在锯着-fediverse-坐着的树枝吗"><a class="markdownIt-Anchor" href="#pixelfed-正在锯着-fediverse-坐着的树枝吗"></a> <a href="https://ploum.net/2025-12-04-pixelfed-against-fediverse.html">《Pixelfed 正在锯着 Fediverse 坐着的树枝吗？》</a></h4><p>我接触 Fediverse（联邦宇宙）没多久，所以对这整个概念并不熟悉。</p><p>作者认为，Pixelfed 的问题在于，它的设计旨在模仿 Instagram，刻意地移除了不显示图片的文字。这导致 Pixelfed 用户以为自己关注了某人，却看不到对方的大部分消息。同样的，被关注的 Mastodon 用户会以为 Pixelfed 用户收到了自己的消息，因为后者关注了自己。</p><p>这就导致了另一件事：人们变得倾向于使用 Mastodon 账号来关注 Mastodon，创建 Pixelfed 账号来关注 Pixelfed。这也让 ActivityPub 协议变成了一个笑话 —— 它的承诺是只需要一个账号就能关注宇宙里的所有人。</p><p>Pixelfed 作为一个 ActivityPub 客户端，理论上应该处理所有接收到的 Activity。它完全可以将纯文字内容渲染成一个文字卡片，例如 Instagram 的文字快拍模式，或者给纯文字内容一个单独的动态流入口。但是它选择直接不显示，让 Fediverse 的意义大打折扣。</p><p><a id="我们是如何为了娱乐而弄丢了交流的"></a></p><h4 id="我们是如何为了娱乐而弄丢了交流的"><a class="markdownIt-Anchor" href="#我们是如何为了娱乐而弄丢了交流的"></a> <a href="https://ploum.net/2025-12-15-communication-entertainment.html">《我们是如何为了娱乐而弄丢了交流的》</a></h4><p>上一篇文章引发了激烈的讨论，让作者意识到自己和 Pixelfed 的支持者生活在两个完全不同的世界：</p><ul><li>作者认为 ActivityPub 是人与人之间的通讯协议，因此「不丢失信息」是底线；</li><li>Pixelfed 的支持者则认为 ActivityPub 是内容消费协议，是用于娱乐的。他们习惯根据想看什么内容来切换账号。</li></ul><p>作者认为，真正的互操作性并不需要用户注册多个账户。现在这种「看图去 Pixelfed，看字去 Mastodon」的思维根本就是被大公司洗脑后的产物，让人以为一个平台必须有一个账号。</p><p>然而作者又发现，ActivityPub 的官方定义里明确写了 Fediverse 是为了投递内容，而非成为通讯网络。也就是说，这些社交网络从来都不是为了交流，本质上是把内容创作外包给用户、填满用户的时间 —— <em>ActivityPub 和 Fediverse 可能正在重蹈 Web2 的覆辙</em>！</p><p>如果将 Fediverse 应用视为通讯网络的话，那么用户就不应该不担心信息的丢失。但它是社交媒体，所以丢失信息根本不算什么，因为算法平台没少这么干过。而这也可以解释为什么即时通讯是主流的沟通方式，因为用户并不信任对方收到了自己的消息。</p><p>什么是真正的通信方式？电子邮件。它可靠、异步、去中心化、标准化，还可以使用我们自己的工具来离线管理。它使用起来很麻烦，还需要主动维护，但这让我们保持了主动性，而不是像社交媒体那样让我们被动地躺在算法里。</p><p>作者也认为真正的通信协议是无聊的，因为它们没有算法让我们上瘾，设计出来的目的也不是为了刺激我们的大脑。也正因为如此，它们的利润不高，自然而然也不会被大肆宣传。</p><p>我使用 Mastodon 是为了自己方便、不想要把自己的日记放在谷歌的产品下而已，也就是说最开始我就不指望使用 Mastodon 来和其他人沟通。Mastodon 或许更像是微博客平台。</p><p>不过之后我确实将其当作社交媒体来看待了。虽然我已经很克制自己不去使用社交媒体（事实上我还保留着 Instagram、脸谱网和推特的账号，用于关注一些我想要关注的人们），但是这个月使用 Mastodon 的频率明显高上很多。</p><p>不过原因并非我一直在刷，而是我沉迷于微博客那样的碎片化的表达。人类的思维本就是碎片化的，微博客其实要比博客更符合人类大脑的自然运作模式。我不想要去争论哪个更好，这（或许）会引起一场无意义的战争。总之大家只要有产出即可，我是这么想的。总之我并不赞同使用 Fediverse 应用就等同于在使用大公司社交媒体这一观点。</p><p>作者对 Fediverse 的批评有一定的可取之处，但并非客观上的真理。既然 ActivityPub 协议本就是为了传递内容而生，那我认为不应该因为一件它原没有打算去做的事情而说它。</p><p>最后说一下作者在文章中提到的一些我不知道的技术：Gemini 协议和离线浏览器。</p><p>Gemini 协议具有着极致的极简，不支持图片嵌入、脚本、iframe、复杂的样式，只支持文字和链接。</p><p>而离线浏览器作者推荐的是 Offpunk，也是他自己用 Python 写的命令行浏览器。现代浏览器的工作方式是点击、等待加载和阅读，而离线浏览器更像是 RSS 阅读器和电子邮件客户端，它会自动将内容全部下载到本地，这样你只需要阅读本地缓存即可。</p><p><a id="用纯-html-替换-js"></a></p><h4 id="用纯-html-替换-js"><a class="markdownIt-Anchor" href="#用纯-html-替换-js"></a> <a href="https://www.htmhell.dev/adventcalendar/2025/27/">《用纯 HTML 替换 JS》</a></h4><p>作者列举了一些可以被原生 HTML / CSS 替换掉的传统 JS 功能：</p><ol><li>手风琴效果和内容展开面板：使用 <code>&lt;details&gt;</code> 和 <code>&lt;summary&gt;</code> 标签；</li><li>带自动筛选建议的输入框：使用 <code>&lt;input&gt;</code> 和 <code>&lt;datalist&gt;</code> 标签；</li><li>模态框和弹出层：使用 <code>popover</code> 和 <code>popovertarget</code> 属性；</li><li>离屏导航和侧边栏：基于 <code>popover</code> API，配合 CSS 的 <code>translate</code> 属性。</li></ol><p><a id="论隐私与控制"></a></p><h4 id="论隐私与控制"><a class="markdownIt-Anchor" href="#论隐私与控制"></a> <a href="https://toidiu.com/blog/2025-12-25-privacy-and-control/">《论隐私与控制》</a></h4><p>作者按照不同类别推荐了 13 个工具、服务或硬件（不包括他提到的个人域名这种策略）。具体清单如下：</p><ul><li>密码管理器<ul><li>GNU pass</li><li>passage</li><li>Bitwarden</li></ul></li><li>即时通讯<ul><li>Signal</li></ul></li><li>手机系统与应用<ul><li>GrapheneOS</li><li>F-Droid</li></ul></li><li>邮件<ul><li>Tuta</li></ul></li><li>浏览体验<ul><li>Firefox</li><li>Privacy Badger</li><li>uBlock Origin</li></ul></li><li>日历与联系人托管<ul><li>树莓派</li><li>Baïkal</li><li>DAVx⁵</li></ul></li><li>域名与网络<ul><li>Cloudflare Registrar</li><li>Cloudflare DNS</li></ul></li></ul><p>我因为玩转笔记本的配置，也稍微做了下隐私和安全性的功课。我个人不推荐使用 Firefox 浏览器，尤其是 Mozilla 发行的。首先是它已经声称全面转向 AI，未来会怎样很难说，总之好感对我来说已经掉光了。其次是它在隐私上已截然不再是过去的 Firefox，还修改过自己的条款，好感又要掉掉掉了。</p><p>如果你想要极致的隐私性的话，可以试试 LibreWolf，其缺点是隐私性太强，很多时候无法正常地使用。</p><p>我现在使用的是 Floorp，算是夹在 Firefox 和 LibreWolf 之间的选择，也有许多自己的特色功能。</p><p>在 Mastodon 上还有朋友推荐了 Zen，是一个 UI 非常漂亮的浏览器。唯一的问题是我用不惯垂直标签页。感兴趣的可以试试。</p><p>我也想过换自己的手机系统。我现在的手机是摩托罗拉 Razr+，不幸的是摩托罗拉的手机系统已经全面接入谷歌，更不幸的是它作为一款折叠屏手机，适配它的系统估计很少很少……</p><p><a id="一个终结所有网站的网站"></a></p><h4 id="一个终结所有网站的网站"><a class="markdownIt-Anchor" href="#一个终结所有网站的网站"></a> <a href="https://henry.codes/writing/a-website-to-destroy-all-websites/">《一个终结所有网站的网站》</a></h4><p>这是一个十分漂亮的网站，就算是对文章内容不感兴趣，我认为也可以点进去学习一下样式。</p><p>文中提到了 Ivan Illich 的理论，指出技术发展的两个阶段：</p><ol><li>增强人类能力的乐观阶段；</li><li>工业化后的垄断阶段。</li></ol><p>当到第二个阶段时，工具开始「操纵和篡夺」社会，甚至会产生激进垄断 —— 不使用该工具就会被排除在社会之外。</p><p>这是一些历史案例：</p><ul><li>纺织革命虽然提高了生产力，但也带来了劳工剥削、巨大的生态成本和过度消费；</li><li>抗生素虽然救命，但后期滥用导致耐药性和更高的医疗成本；</li><li>太空探索扩展了我们的认知，商业化后反而因太空垃圾泛滥、阻碍了天文学观测。</li></ul><p>万维网也是如此。我们最初使用它来共享信息，但商业化后带来了网络霸凌、虚假信息、成瘾和资本掠夺。</p><p>作者重新审视了互联网的三个方面：</p><ol><li>教学和学习：逃离巨头平台的控制和变现陷阱。回归博客、HTML、RSS 和 Webmentions；</li><li>社交连接：逃离社交媒体 App。利用 POSSE、ActivityPub 和 ATProto 等协议，建立属于自己的、去中心化的、互操作的社交网络；</li><li>Web 开发：拒绝千篇一律的 B2B SaaS 开发模式。拥抱 HTML 和 CSS 的复兴，利用现代浏览器 API 进行创造性表达。</li></ol><p>作者也对个人网站进行了一些解释。如果你对个人网站很好奇，但是自己没有一个的话，可以听听看：个人网站是对企业化、工业化互联网的最有力反击。它允许自主、实验、拥有权和去中心化。</p><p>如何开始呢？从小做起，允许自己的失败，记录自己的成长。哪怕只是简单的 HTML 也好，别纠结工具和框架，除非设计让你快乐。你可以利用 <a href="http://brid.gy">brid.gy</a> 等工具将内容分发到 Mastodon，再把评论收回来。</p><p>最后你可以将自己的作品分享到 <a href="http://personalsit.es">personalsit.es</a> 这样的社区。这是作者自己推荐的，我看了一下都是英文使用者的网站。介意的话可以改投到中文使用者的社区内，有很多，我就不一一列举了。</p><p><a id="纯文本网站的小型合集"></a></p><h4 id="纯文本网站的小型合集"><a class="markdownIt-Anchor" href="#纯文本网站的小型合集"></a> <a href="https://shkspr.mobi/blog/2025/12/a-small-collection-of-text-only-websites/">《纯文本网站的小型合集》</a></h4><p>作者整理了一份支持「纯文本模式」浏览的网站清单，也列出了它们具体的访问方法。这些方法大多通过修改 URL 实现，常见的模式包括：</p><ul><li>添加后缀</li><li>替换后缀</li><li>添加特定参数</li><li>某些站点仅支持通过 <code>curl</code> 命令行工具访问</li></ul><p>其中 elle's blog 的设计让我很是吃惊。如果只是点进作者提供的网址，你会看到一个像素的房间。点击左下角的小猫，你会和作者进行对话，她会指导你如何和这个网页互动。这时候随便点点，你会发现中间的小人可以走来走去、一些页面以很有趣的方式展现…… 这还不是全部。想要阅读她的文章，你需要使用 <code>curl</code> 命令。</p><pre><code class="language-zsh">curl elle.sh/blog</code></pre><p>你就可以看到她的文章了。</p><p>不过说「需要」是有点夸张了。其实在浏览器上访问 <code>ellesho.me/page/website</code> 即可。</p><p>说回纯文本这个想法，我认为想法不错，我也很乐意为我的读者提供这种阅读方式，但就个人观点而言，如果不美化一下我是不愿意读的。话又说回来，Emacs 可以使用 <code>M-x eww</code> 来浏览 <code>.txt</code> 的网址，然后使用我自行配置好的字体。Emacs 真是好东西啊。</p><p><a id="过度设计请勿打扰设备"></a></p><h4 id="过度设计请勿打扰设备"><a class="markdownIt-Anchor" href="#过度设计请勿打扰设备"></a> <a href="https://apoorv.page/blogs/over-engineered-dnd">《过度设计「请勿打扰」设备》</a></h4><p>作者做了一个小工具，可以在 OLED 屏幕上显示自己是否在开会。听上去是个蛮简单的功能，不过爱折腾的极客们喜欢将小事情做成无比完美的小事情…… 建议直接阅读原文。</p><p><a id="就是为了这份难受劲儿"></a></p><h4 id="就是为了这份难受劲儿"><a class="markdownIt-Anchor" href="#就是为了这份难受劲儿"></a> <a href="https://nik.art/the-suck-is-why-were-here/">《就是为了这份难受劲儿》</a></h4><p>这篇文章的开头就令人毛骨悚然：有人训练了一个人工智能模型，以作者的风格撰写博客文章，并且想要知道如果这个模型正常工作的话，是否会对作者有用。虽然没有人会那么做，但如果有人这么告诉我，我可能第一时间会想要封锁他，让他不要再来联系我。</p><p>不过作者最后的想法有点小邪恶了。虽然客观上没说错，但主动去庆幸这种事还是算了吧！我也是一个读者，还是不希望自己因为其他内容太差所以去关注一个人。</p><p><a id="也许评论应该解释做什么"></a></p><h4 id="也许评论应该解释做什么"><a class="markdownIt-Anchor" href="#也许评论应该解释做什么"></a> <a href="https://www.hillelwayne.com/post/what-comments/">《也许评论应该解释「做什么」》</a></h4><p>过去人们认为注释应该解释这段代码 <span class="emphasis">为什么</span> 存在，而不是这段代码 <span class="emphasis">做什么</span>。理由是如果你的代码需要额外解释它是什么，那意味着你的代码写得不够清晰和整洁。</p><p>阅读代码时最大的敌人是上下文切换。作者引用了《代码整洁之道》作者 Bob Martin 的观点，后者主张把一个长函数拆分成无数个极小的函数，通过函数名来解释 <em> What</em>，从而消灭注释。</p><p>例如我们有一个 <code>replace()</code> 方法，它会被拆分成多个小方法。结果是读者为了理解逻辑，往往需要在这些方法里跳来跳去，不断滚动屏幕，打断了阅读思路。</p><p>作者推崇保留原本的 10 行代码在一个函数里，但在关键步骤前加上 <em> What</em> 类型的注释。这样读者就可以顺着读下来，利用注释作为路标快速理解逻辑，而不需要跳转到其他地方。</p><p><a id="2026-年了关于加密邮件你需要认清的真相"></a></p><h4 id="2026-年了关于加密邮件你需要认清的真相"><a class="markdownIt-Anchor" href="#2026-年了关于加密邮件你需要认清的真相"></a> <a href="https://soatok.blog/2026/01/04/everything-you-need-to-know-about-email-encryption-in-2026/">《2026 年了，关于加密邮件你需要认清的真相》</a></h4><p>作者认为，电子邮件的设计初衷就是电子明信片，根本没有隐私可言。后来的修修补补不过是在烂地基上盖楼，例如 PGP、S / MIME。</p><p>对于邮件来说，正文是数据，而发件人、收件人、主题行等内容就是元数据。即使我们加密了正文，元数据依然是明文传输的。通过元数据，攻击者能知道我们在跟谁聊、聊什么主题、聊了多久。这足以让情报机构定位目标。</p><p>再加上虽然可以在技术上进行修补，但邮件被几大巨头垄断，政府也希望保留监控能力，实际改不了一点。</p><p>就算是 ProtonMail 这样主打隐私的邮箱服务也有隐患：一旦离开他们的围墙跟别人发邮件，还是会回落到不安全的状态。</p><p>假设我们终于配置好了加密邮件，也可能因为易用性灾难而将加密内容以明文形式发出去。</p><p>因此作者的主张是，彻底放弃加密邮件这个幻想吧，使用 Signal 来进行敏感沟通。</p><hr><h2 id="折腾博客"><a class="markdownIt-Anchor" href="#折腾博客"></a> 折腾博客</h2><p>我受 <a href="https://slashpages.net/">Slash Pages</a> 启发，为博客网站添加了一些页面。详细可见 <a href="/sitemap">网站地图</a>，它也被添加到网站的 Footer 处。</p><p>如果你往下划，会发现我也添加了指向 <a href="https://slashpages.net/">笔墨迹</a> 的链接。去年我的站点被添加到笔墨迹内，不过我是到后面才知道此事，因为提醒邮件被塞进了垃圾邮件内…… 不清楚是不是 iCloud 的问题。不过无论是不是我都比较想换成用域名结尾的邮箱地址。跑题了跑题了。</p><p>笔墨迹建议我在首页内添加他们的链接，这让我犯了难：因为添加笔墨迹提供的图片素材在我的网站内会导致样式上的混乱。最后我选择了添加只显示文字的超链接。</p><p>说回 Slash Pages。根据我最开始对该博客的定义，也就是「个人领地」，我将这些新添加的页面视作「领地里的不同地点」，例如 <code>/contact</code> 就是领地的联络处。目前我还在慢慢施工中~</p><p>我为月刊中的「书影音」部分添加了自动抓取 NeoDB 数据的功能。目前我还在摸索如何使用 NeoDB，例如一些内容无法在 NeoDB 上搜索到条目，也无法让其在互联网上获取。可能还是需要自行手写内容。</p><h2 id="我写的文章"><a class="markdownIt-Anchor" href="#我写的文章"></a> 我写的文章</h2><ul><li><a href="/posts/4420/">《Emacs 里配置邮箱服务》</a></li><li><a href="/posts/53f4/">《初次走半马》</a></li><li><a href="/posts/2590/">《最能保障「数字主权」的 VPS 公司》</a></li><li><a href="/posts/9412/">《谈模仿学习与身份误区》</a></li></ul><h2 id="编程历程"><a class="markdownIt-Anchor" href="#编程历程"></a> 编程历程</h2><p>这个月我花了很多时间在自己的笔记本上。首先我将笔记本的键盘换了套新的，原先的不知为何无法正常使用。接着我将笔记本上的 Windows 系统换成了 EndeavourOS，也是 Arch Linux 发行版的一员。它本质上就是预配置好的 Arch Linux，安装起来很丝滑。</p><p>在窗口管理上，我选择了 i3wm 这个颇为独特的选项。它是手动平铺式窗口管理器，与传统的桌面环境，如 GNOME 或 KDE，很不一样。</p><p>因为月底我就要开学了，我临时学习了如何使用 Emacs，因为总感觉笔记本系统换了再不换个更高效更少见的工具记笔记实在是说不过去…… 不过这倒是让我打开了新的大门，Emacs 真好玩！</p><p>为了更好地使用 Emacs，我学习了 GTD 工作流，其核心围绕着这么一个问题：人并不擅长于牢记事情。GTD 工作流鼓励大家将脑子里想到的东西立即记下来，然后暂时抛之脑后，到手上的动作做完了再回看。Emacs 强大的可玩性就能做到这一点：我想到一件事情可以进行 Capture 操作，唤出我自定义好的模板（是 TODO 列表吗？是下一篇博客的想法吗？），写完后就不管它们，待未来再来补充。</p><p>因为 Emacs 可以做很多事情，所以我会长期将 Emacs 挂在主要窗口，需要 Capture 的时候只需要一个简单的快捷键即可。这可以抹除许多我们不会注意到的小块时间，例如打开 App、新建文件……</p><p>当然，你不需要 Emacs 也可以玩转 GTD 工作流。不过我依然认为 Emacs 是一个值得学习和使用的工具，类似定位的我也推荐。使用快捷键来进行过去用鼠标才能做到的操作，实在是太爽了。并且 Emacs 的可玩性极高，虽然配置需要使用 Elisp 来编写，但如果不介意的话，可以利用 AI 来帮助你打造自己想要的配置。</p><p>我也写了个配置来自动化一些我写博客期间可以被忽略掉的步骤，例如自动生成月刊内容。过去我还在用 Typora 写博客的时候，一个月刊的 Markdown 文件差不多有两万字。每次想在月刊里添加新内容，都需要在一个 Markdown 文件里找来找去，麻烦的同时还卡顿得不行。</p><p>现在我可以将内容以列表的形式放在一个 Org Mode 文件内（Emacs + Org Mode 是一个天衣无缝的组合），然后使用自定义好的快捷键快速将它们移动到月刊 Org Mode 文件内、我想要它们在的分类下。整理好后，我会再次使用快捷键，将月刊 Org Mode 文件转换成 Markdown 文件，接着保存在 Hexo 项目的文章目录下。</p><p>我现在会推荐想要写博客的各位使用 Hugo 而不是 Hexo…… 我现在依旧使用 Hexo 的原因不过是习惯了，且懒得去迁移。</p><p>总之，我很满意这个月的折腾，虽然和标题「编程历程」中的「编程」关系不是特别大！</p><h2 id="书籍"><a class="markdownIt-Anchor" href="#书籍"></a> 书籍</h2><h4 id="其他评价"><a class="markdownIt-Anchor" href="#其他评价"></a> 其他评价</h4><p>本月暂无记录。</p><h2 id="影视"><a class="markdownIt-Anchor" href="#影视"></a> 影视</h2><h4 id="其他评价-2"><a class="markdownIt-Anchor" href="#其他评价-2"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/tv/season/1pjylphBgIXpdeOWt9J7Oh" target="_blank" rel="noopener noreferrer">五等分的新娘</a><span class="neodb-rating">★★★☆☆</span><span class="neodb-status">在看</span><p class="neodb-comment">陪室友重刷这个作品。<br>我是原作铁粉。想要看这个作品的话我个人推荐还是看原作漫画更好些，无论是细节还是画风都更好。<br>作者春场葱的画风我个人很喜欢，可惜无论是动画的第一季、第二季还是剧场版我都不认为能复刻他的画风。更不用说这一季的各种崩坏场景，很难想象这是一个曾经销量达到过日本某季度第一的漫画的动画化产物，给你星星摘喽。<br>第一季所涉及到的篇章我个人都不是特别感冒，不加星也不减星吧。</p></li></ul><h2 id="音乐"><a class="markdownIt-Anchor" href="#音乐"></a> 音乐</h2><p><a id="sakanaction"></a></p><h4 id="sakanaction"><a class="markdownIt-Anchor" href="#sakanaction"></a> Sakanaction</h4><p>我重新听了一下 Sakanaction 的歌。去年我很喜欢他们的专辑 <em> 834.194</em>，这个月发现 <em> DocumentaLy</em> 和 <em> Shin-Shiro</em> 也不错。</p><p>这些是我很喜欢的歌曲：</p><ul><li><p>《『バッハの​<ruby>旋律<rt>せんりつ</rt></ruby>を夜に聴いたせいです。』》</p><p>其中歌词：</p><blockquote><p>バッハの​<ruby>旋律<rt>せんりつ</rt></ruby>を夜に聴いたせいです<br>こんな心</p></blockquote><p>的唱法对我而言很有意思，听了没几次就会唱了，作为一个日语口语白痴。</p><p>唱歌期间被室友听到，然后被笑话…… 因为「没有一个音是对的，但居然能和原唱形成很好听的和声」，让她认为我或许在一些奇怪的地方上有着天赋 —— 怎么听都不像好话吧！</p></li><li><p>《ネイティブダンサー》，或称 <em> Native Dancer</em>。</p><blockquote>​<ruby>淡<rt>あわ</rt></ruby>い日に僕らは​<ruby>揺<rt>ゆ</rt></ruby>れた、ただ揺れた<p>そういう気になって</p><p>思い​<ruby>出<rt>で</rt></ruby>のように降り​<ruby>落<rt>お</rt></ruby>ちた、ただ降り落ちた<br>そう雪になって</p></blockquote></li><li><p>《多分、風。》</p><p>这首歌的前奏相当抓耳！</p></li></ul><h4 id="其他评价-3"><a class="markdownIt-Anchor" href="#其他评价-3"></a> 其他评价</h4><ul class="neodb-list"><li class="neodb-item"><a href="https://neodb.social/album/0ip3QYqMeuVg8gQINodtAb" target="_blank" rel="noopener noreferrer">Baumkuchen_EndCredits</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">已听</span><p class="neodb-comment">使用了卡农和欢乐颂的旋律的一首 V 曲，注定了这首歌不会难听到哪里去。<br>「年轮蛋糕结局」指的是在单相思对象的婚礼上吃分到的年轮蛋糕。光是听到这样的描述就可以想出数万字的胃痛剧情……<br>虽然 MV 里出现了亚北音留，但是实际使用的歌姬是镜音玲。</p></li><li class="neodb-item"><a href="https://neodb.social/album/7YqfO5uxzKiZZNIjpfMeka" target="_blank" rel="noopener noreferrer">Grizzly ni Osowaretara</a><span class="neodb-rating">★★★★☆</span><span class="neodb-status">在听</span><p class="neodb-comment">灰熊是真的存在，还是少女为了你的关注而撒的一个小谎呢？<br>无论是哪一个，这都是一首很可爱的歌，少女感满满，旋律很欢快。</p></li></ul><h2 id="日记片段"><a class="markdownIt-Anchor" href="#日记片段"></a> 日记片段</h2><p>日记片段现在已经全面使用我在 Mastodon 内发布的内容。你可以通过跟随我的 Mastodon 账户来提前阅读日记片段，或者不跟随，在月刊里一次性读完。</p><button id="details-toggle-diary_sections-1789678111841" class="details-toggle-btn" data-group="diary_sections" onclick="toggleGroupDetails('diary_sections', 'details-toggle-diary_sections-1789678111841', '展开所有', '收起所有')">展开所有</button><details data-group="diary_sections"><summary>一月一日</summary><div class="diary-entry">15:13 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115820489945084398" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我打算在新的一年里折磨自己，先从把一直不用的笔记本电脑打造成折磨工具开始。</p><p>「东西越难用越好，」我是这么认为的。让我的日常生活增加有意义的不便利性。</p><p>系统可以改，反正这个电脑跑 Windows 10 都有点跑不动了；笔记工具可以大改，我真是受够 Typora 了，但是其他人常用的笔记工具我又几乎没用过…… 多尝试尝试吧；其他工具也是，我想要这台笔记本电脑杜绝对某些大企业的工具的使用。</p><p>最后是 AI。虽然自己一直都知道，但还是一直以侥幸心理的态度去看待 AI Coding，直到身边真的出现了一个一直在写代码的人 —— 可能这也是为什么我有时会抗拒结识同行吧。</p><p>不知道从什么时候开始，我在写代码上极度依赖于 AI。它有时候能解答我问题或者给出架构上的建议，是挺好的啦，但是写代码的时间变成了一种折磨。我看得懂它在做什么，但是要我自己一个人写、我是写不出来它写的东西的。AI 工具便利吗？便利，但凡事都有代价。</p><p>总之希望新的一年可以天天向上、成为更好的自己~ 以上内容为什么我没有写到博客里呢？唉 ——</p><p></p><blockquote class="diary-thread-reply">01-02 06:25 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115824076263428654" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我尝试了一些全新的工具。</p><p>折磨是蛮折磨的，敲错了命令后会发出非常刺耳的高频蜂鸣声，以至于我大晚上的差点被吓飞，还把我的室友吵醒了 —— 对不起！</p><p>虽然最开始的学习成本看上去就很高，但是努力总会有回报，熟练后速度明显要比鼠标点来点去快上不少。</p><p>这样的尝试也带来了许多意想不到的收获，比如系统字体居然是可以随意更改的！Windows 你给我吃的都是什么猪食 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/011/original/0158d7965e3f9488.webp" alt=":gblackcat_shake_shadow:" loading="lazy"> </p><p>明天起来再配置一下，争取效率一节更比六节强，旺旺！</p><p></p></blockquote></div><hr><div class="diary-entry">15:25 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115820536475365413" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我的 Instagram 头像是 P 的，给我 P 了个手和显卡（我记得是 GTX 1060），看上去像是我在拿着一张显卡。</p><p>其实没有，我根本没有 GTX 1060，我用的最好的显卡还是 GTX 750Ti。</p><p>然而很多人都没有看出来这是 P 的 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/054/original/21b69395062a4e07.png" alt=":ablob_spinfast:" loading="lazy"> </p><p></p></div></details><details data-group="diary_sections"><summary>一月二日</summary><div class="diary-entry">06:12 <a class="diary-source-link" href="https://pxlmo.com/p/Cytrogen/912586317527541826" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Some recent pics of my cat. She grows so fast that she's almost the size of my adult dog!</p><p></p><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/ffe7c43a6-a8b5f2/MD4Zyuq6MpKQ/ymaLQofRDUrjcSoqbCuJZRWw3EYAbtxjUwrBX14J.jpg" alt="My fluffy calico cat, wearing her purple collar and tag, is sitting nicely on the grey bedding and looking curiously off to the side. A large black office chair is behind her." loading="lazy"></figure><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/ffe7c43a6-a8b5f2/RkLNfxVNFjV0/Lzp6swVNzuU8eSVt67OfVUEDHoz5tYHHjPyb6qCf.jpg" alt="My sweet calico cat is resting comfortably, lying down on her pink unicorn patterned quilt and gazing intently toward the right. Her fluffy tail is curled behind her." loading="lazy"></figure><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/ffe7c43a6-a8b5f2/K3UYPaUspZDb/z2DxjcYerhHWi9O42RQm3oyCmHwXxTYCtCbshDaf.jpg" alt="A beautiful portrait of my calico cat lying down with her white front paws stretched out straight toward the camera. Her purple collar, tag, and prominent ear tufts are clearly visible against the dim background with a red teddy bear." loading="lazy"></figure><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/ffe7c43a6-a8b5f2/zHe1PyhrWXtt/YhppVbfk91WxkadA0VVXsq31wQmWlBiKnOl5mt5W.jpg" alt="My playful calico cat is lying on her side on the pink quilt, looking back over her shoulder. She is showing off her cute multi-colored toe beans on her curled back feet." loading="lazy"></figure></div><hr><div class="diary-entry">06:40 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115824135618304484" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天和公司里的其他同事一起在办公室里跨年。室友想出来的跨年主题是 —— 包饺子！</p><p>好吧也不是什么特别惊喜的活动。</p><p>同事甲带来的饺子皮，居然是日本的煎饺皮。我们包好后，把饺子放到微波炉里加热、蒸。果不其然，饺子皮变得无比酥脆，和日本煎饺的区别只有颜色较淡。</p><p>不过好吃还是好吃的，就是肉馅做得太咸。同事乙还带来了她做的鸡腿和鸡心，美滋滋。</p><p>我们玩了两套简单的桌游。第一款是独角兽，因为规则架构简单易懂，他们很快便上手了。这期间大家「丑恶的勾心斗角」实在是令人发指 —— 虽然我也没少使绊子。</p><p>第二款是三国杀…… 的鼻祖 Bang。我们只有四个人，规则里说配置是 1 主公 2 反贼 1 内奸，但是玩下两局后就觉得没有什么意思。同事甲提议取出主公，剩下的身份卡打乱后随机抽取 3 张，这样我们没人知道不明牌的三人是什么身份：可能是 2 忠臣 1 反贼或者 1 内奸，可能是 3 反贼…… 因为对谁来说身份都是不明确的，反而都互相猜忌、演了起来。</p><p>下次团建我们考虑玩 Root。我个人还是蛮喜欢这个桌游的，美术风格很棒，只是苦于线下的朋友都对桌游不感兴趣。</p><p>另一个朋友想要明天来我家玩电子游戏，但自己实在不是那个心情，并且也要从新年的气氛里抽离出去才是：我已经ゴロゴロ好几天啦。</p><p></p></div><hr><div class="diary-entry">16:11 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115826377590787339" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>悄咪咪从 Edge 迁移到 FireFox。</p><p></p></div><hr><div class="diary-entry">16:29 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115826449793525485" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>笔记本换成了 EndeavourOS 并且体验了一天后的感受是 —— 用装有 Windows 系统的台式电脑时明显出现了不适应的感觉。</p><p>唉效果这么快的吗？</p><p>还有就是我装了 Fcitx5 和 Rime，可以悄悄把 [] 键改成直角引号。但是台式电脑装的还是破搜狗输入法……</p><p>或许养成好习惯就需要把所有的设备都统一一下。</p><p></p></div><hr><div class="diary-entry">16:41 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115826495483891544" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我总感觉昨晚做了场非常精彩的梦……</p><p>早上起来却什么都记不起来。</p><p></p></div><hr><div class="diary-entry">17:24 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115826664822080669" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天的叛逆之作。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/826/660/722/587/719/original/6a2c2bc92767109f.png" alt="一盘模仿塔可造型的创意饺子，饺子皮像塔可壳一样立起，内填猪肉馅和玉米粒，摆放在白色便当盒上。" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>一月三日</summary><div class="diary-entry">13:47 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115831476591364585" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我其实还蛮讨厌别人跟我私聊的时候说一句话就接一个表情包，像巨大的逗号一样。有时候对方还会使用很闪的动图表情包，看着很不舒服。</p><p></p></div><hr><div class="diary-entry">14:19 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115831602171857082" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天和校友沟通被大夸特夸了一顿，还蛮不好意思的…… 我是巧合下认识他的。Reddit 上他宣传了自己开发的一套工具，和我当时做的工具功能很类似，我就给了他个 star。他说因为我是第一个给他 star 的人，他就激动地把我的 GitHub 仓库、博客，甚至是藏在博客二级菜单里的 portfolio 页都看了一遍 —— 顺便给我提了个 issue。</p><p>我从他那儿得知了一个有意思的事情：我校的计算机课完全是为了金融/会计/商科专业学生而打造的。基础什么的都无所谓，反正目的就不是让学生开发，而是让学生随便学点 pandas 跟 numpy。</p><p>因为觉得自己没有必要阅读教材，所以我从来没有认真看过教材，但是校友告诉我他在教材里发现了许多基本错误。他上那节 Python 入门课 —— 不，应该是「编程与计算思维」课 —— 的时候，授课的人甚至只是一个研究生，而非真正的「教授」。</p><p>他说他很想转学走，这个学校几乎没有 STEM 氛围。过去他在国内还能和同学讨论 STEM 相关的内容，现在他身边真的在搞 STEM 的人少得可怜。我很赞同这一点，但我也没有转学、适应新环境的精力了。其实现在转去哪所学校的结果都差不多，并不会有什么很大的变化 —— 东西靠自学，工作该找不到的依旧找不到。</p><p></p></div><hr><div class="diary-entry">14:28 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115831637508718250" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友最近捣鼓的炸鸡排，真不错，空气炸锅好方便。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/831/635/974/955/200/original/ece2b271bc073ca0.jpg" alt="一个白色的长方形便当盒，里面装有撒了黑芝麻的白米饭、切成条状的金黄炸鸡排（可以看到内部白色的肉质），并配有红黄两色的切片圣女果和少许青豆。" loading="lazy"></figure></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">含生殖器官相关的词汇。整体内容是我在倒情绪垃圾。</summary>        <div class="diary-cw-content">16:34 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115832130391807404" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>大一那年被强迫去社交过。</p><p>这一年堪称我有史以来最折磨的一年。首先是某个垃圾闯入了我的生活，也让我看到了室友这个人垃圾的时候有多垃圾。她又是出轨又是想要三人行的，怪我不够好让她出了轨ーー这里的「不够好」指的是我这个一辈子都营养不良的小女生没有给她拎包、没有那个人那么多朋友，以及没有屌。</p><p>当时对那个人的了解，只停留在「朋友多」「爱社交」和「健身身材好」。不过现在再来看，就会发现他是一个除了有根屌和不错的肌肉外，可以说是一无是处的人：追求女生靠的是 PUA 和强奸，朋友也是根本没有亲密的。因为我是已经和室友在一起了，他对我这个人可谓是充满了嫉妒情绪：在背地里又是诋毁我、把自己塑造成从女同怪物那儿救下喜欢女孩的英雄，或者是渴望进入到我和室友的生活里ーー女人怎么可以喜欢一个没有屌的人，太奇怪了，我要纠正你！</p><p>好了回到正题：为什么我被要求去社交。当时室友这个傻逼非常崇拜他的「朋友多」特征，也要我去多社交。我是一个绝对的内向人士；我不需要量多的友谊，我只想要质量高的友谊。但是也没有办法，室友每天都和那个人或者他的男性沙文主义团体待在一块。我每天的情绪都很崩溃，但是她根本不在乎，我在学校里也没有认识的人可以让我不去想这些事。我没有办法，只能笨拙地模仿他人社交的样子，去强迫自己和人产生联系。可是不行，我对他们一点兴趣都没有，我根本不想强行和人有关联，更别提他们一个个后面都成了我的噩梦。那时候我甚至堕落到开始长期刷短视频和短剧。</p><p>直到一天我实在是受够了。我向室友提了分手。去死吧，你们都！好笑的是，她在我拉黑了她之后才开始意识到我是个人，不是条狗。她说她可以什么都听我的，无视了我的情感需求是她的错，那个人和我比起来根本不算什么，没有我的话她的生活就崩塌了…… 这样的话一直重复在我的耳边。</p><p>至于之后发生了什么，以后想说的时候再说吧。</p><p></p></div>      </details></div><hr><div class="diary-entry">17:04 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115832248788499107" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天在折腾自己的台式电脑，装上了 Emacs，然后捣鼓了一下主题和字体。目前还在学习 Emacs 的快捷键，以及如何将 Emacs 和 Org.mode 对接上 Hexo ーー我还是忘不了 Hexo…… 主要是迁移太麻烦了。</p><p>目前想的是写好的 Org 文件用 Ox-Hugo 导出成 Markdown 文件、放在 Hexo 的文章目录下，这样 Hexo 就不需要修改什么了，唯一的问题也只是我自己写好的 Nunjucks 标签在 Org 文件里显得格格不入……</p><p>现在也有考虑要不要把台式电脑也改用 EndeavourOS，不过这台电脑平日也有做一些娱乐相关的事情，有时候室友也会借用。先暂且让它是一台谁都能操作的娱乐电脑吧。</p><p>其实就算没有很熟练，去折腾一些新东西也会很开心，就是项目的速度会因为我的分心而减缓一些。</p><p></p></div><hr><div class="diary-entry">17:50 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115832429644047163" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>早些时候倒情绪垃圾的时候倒是让我想起另一件事。</p><p>当时有个男的对强奸一事发表了这样的态度：</p><p>- 没有奋力对抗的话，女性被强奸活该</p><p>- 男性被强奸应该感觉爽才对</p><p>后者让我想到了几年前认识的一个人。他很小的时候被女恋童癖强奸，有了严重的 PTSD，以至于他后来改变了自己的性别。</p><p>性爱一事，只要有一方觉得不舒服、不想做，就应当可以定义为强奸。</p><p>至于发表那种言论的那个破人，不过是个彻头彻尾的自负 Incel。</p><p>我怎么当时强迫社交时认识的都是群垃圾角色。该说室友那帮垃圾会给我介绍的也只有垃圾人吗。</p><p></p></div><hr><div class="diary-entry">18:17 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115832536958053230" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>安卓手机也装上了 Fcitx5！</p><p>不过 Gboard 一个很大的优势是 Emoji 合成，可以看到许多可爱的合成 Emoji。</p><p></p></div></details><details data-group="diary_sections"><summary>一月四日</summary><div class="diary-entry">04:15 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115834887342287714" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这是一个用 Emacs 写的嘟文，真有趣，就是我的标点符号全部变成垂直的了，怎么回事 ——</p><p></p></div><hr><div class="diary-entry">14:06 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115837211170612899" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>老板班表排错了，让我提早一小时到。</p><p>我昨天给她又是发信息的又是打电话，她一整天下来都没有回复。晚点我将这件事告诉了同事，同事说貌似是要早开店一小时。</p><p>今天我依旧是按照班表上的、早一小时来，发现机器还是不能启动，遂打电话给经理询问。他说是老板排错了，没有早一小时开店。挂断电话后老板打电话来训我。淦，我昨天发你那么多信息你完全不回，我又不知道你们一天两天的搞什么幺蛾子。</p><p>同事说她们考虑全部跑路了ーー薪水低、活多。有时候老板或者经理上班根本不看班表，晚四个小时或者干脆不来也是家常便饭。偶尔客人会突然出来一大群，一个员工根本处理不过来，只会被压力到想哭。</p><p></p></div><hr><div class="diary-entry">14:21 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115837269944916629" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天和校友一边对接一边聊天，聊到了技术栈。</p><p>这样说是蛮对不起他的啦…… 项目的技术栈是臭名昭著的 MERN，也就是 MongoDB + Espress.js + React.js + Node.js，不过详细的是把 Espress 换成了更适合生产环境的 Nestjs。</p><p>他是写 Golang 的，会写 Next.js 但是前端写的不多，以至于看到项目客户端那庞大的 JavaScript 代码都表示谁能维护谁牛逼。他认为就算是 TypeScript，写起来也很奇怪，有一种不踏实的感觉。我能理解他是怎么想的啦，我自己也很后悔最开始学开发的时候走的是 MERN Stack 路线。但是现在项目都走到这里了，只能做一些简单的迁移；React 目前迁移到了 Next，Mongo 我有打算迁移到 PostgreSQL 但是之后再说吧，服务端的话…… 迁移起来或许会很痛苦。</p><p>聊着聊着我们聊起了前端框架。他是一个主做算法和后端的，感觉只要开始写 UI 或者布局了，代码一定会变得很奇怪。</p><p></p></div><hr><div class="diary-entry">14:35 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115837324802542434" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天晚上（不要怪我一直提昨天，昨天我一直在捣鼓 Emacs）让室友帮我做个奶油洋葱意面吃。说是意面，其实是大号的贝壳粉，适合挂黏稠的汤汁吃。她自作主张添加了蛋黄酱在里面，让我有点讨厌…… 不过依然很好吃！</p><p>她做酱汁的期间和她聊我的自动化系统，让我的笔记想法文章日程社交工作结为一体，全部在一个东西上查看编辑，然后按照分类分发到其他工具。好啦其实就是用 Emacs 做我现在常做的很多事情，只是减少我把手从键盘挪到鼠标的频率。</p><p>手机的话用 Syncthing 同步了这些文件，不过我还没尝试过在手机上写 Org。至于笔记本电脑…… 它的键盘很久之前坏掉了，我前几天买了替换零件，大概今天就可以换上。</p><p></p></div><hr><div class="diary-entry">14:41 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115837350999753076" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前段时间我和室友的手机颜色都调成了灰度。她很喜欢这种理念，让身边的各种人都尝试这么做。</p><p>这样的方案也有了效果。她说她刷朋友圈和 Instagram Stories 或者 Reels（就是短视频）的次数下降了，因为它们看上去都很无趣。</p><p>我认为这很大程度取决于这个人本身对手机有没有依赖。她不是一个特别依赖手机的人，和其他人出去玩绝对不会用手机，无聊的时候用手机的次数也不多。</p><p>我自己就有点信息上瘾了，闲不住。不想承认但是我确实养成了掏手机出来的肌肉记忆，一闲下来就会触发，然后发现手机里没有什么我想看的东西，默默放回桌上。现在我用小红书这类算法平台的频率变少了，但是用 Mihon 看漫画的频率变高了，原因是灰度不会影响到我看漫画……</p><p></p><blockquote class="diary-thread-reply">01-16 07:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115903612111644693" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友将「灰度手机」的想法分享给自律到可怕的朋友，却发现对方已经做过这样的事情了，并且给了一个更好的建议：将手机的颜色换成红色。这样不仅可以让手机颜色变得单一，还可以减少蓝光。</p><p>我的第一反应是：「我靠好恶心。」转念一想，既然我都觉得恶心了，那么这个防止人们过度使用手机的方法不就实现了吗？</p><p></p></blockquote></div><hr><div class="diary-entry">16:02 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115837669931200528" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我可能是个原始人不过我搞明白这个空调遥控器怎么用了。</p><p>SENSOR 功能启动后可以把遥控器带在身上，空调会按照遥控器的温度来调节温度。</p><p>很冷或者很热的时候打开 TURBO 功能可以享受超大风力。</p><p>之前开空调的时候都觉得温度很难受，现在可算是舒服了。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/837/650/738/854/568/original/b9981fc4a67ce969.jpg" alt="这是一张放置在浅色木纹表面上的Friedrich品牌空调遥控器的特写照片。遥控器通体呈灰白色，机身正面及边缘分布着细微的黑色划痕和磨损痕迹，显示出该设备已被长期使用。遥控器上方的LCD显示屏处于开启状态，屏幕中央醒目地显示设定温度为86华氏度（°F）。屏幕左侧的太阳图标表明空调当前设定为制热模式，顶部文字显示“FAN AUTO”，意为自动风速。屏幕中央的时钟显示时间为10:56。与另一张照片相比，该屏幕上额外显示了一个松树形状的图标（通常代表健康或换气模式）以及一个圆形的风扇图标。遥控器中部是一个醒目的黄色圆形“START/STOP”电源键，周围环绕着灰色的功能按键，底部印有深灰色的“FRIEDRICH”品牌标识。" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>一月五日</summary><div class="diary-entry">04:06 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115840513940309957" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>买了个这样的东西拼着玩。小小的模型看着很安心。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/840/513/312/970/019/original/8e0e5355d5686eee.jpg" alt="一个放置在木质表面上的黑色复古自行车微缩模型。模型细节精致，具有银色的弯曲车把、安装在前叉上的车灯、黑色的车座以及银色的后货架。自行车通过脚撑直立停放，背景略显模糊，可见部分杂物和蓝色的光映。" loading="lazy"></figure></div><hr><div class="diary-entry">04:20 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115840570667058384" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>下午五六点的时候很困，想着睡个午觉，迷迷糊糊期间微信发出了许多提示音，结果是老板在群里大肆教训我们…… 我有时候觉得跟他们沟通很费劲，信息量一般的情况下还会混杂许多无意义的情绪攻击，比如人身攻击。我认为，我们有一个问题，我们解决它就好了，牵扯到智商什么的真的没有必要。昨天的事情，她也没有向我道歉，只是像多数的中年人那样主动跟我提起了这件事，或许对他们来说这就是道歉吧。</p><p>因为同事跟我提起了调酒师这样的工作，让我也有点想要试试看。</p><p></p></div><hr><div class="diary-entry">13:34 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115842749386415316" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>大早上母亲告诉我猫发情了，要我去给猫找做绝育的诊所。对话挺不愉快的，和之前一样，不给她安排好就威胁丢猫，美其名曰「放养」。</p><p>家附近是类似于郊区的地方，草丛里的虫子毒得可怕，放养出去也不过是看着猫慢性死亡，或者徒增野猫的「猫口」ーー这个社区的野猫不知道从什么开始越来越多。</p><p>邻居们在家门口放置了许多猫粮，也给它们搭建纸房子，可以说到处都是野猫…… 以及宝宝野猫。但是这也招来了浣熊这样的可怕动物，就住在我家隔壁的废墟里。</p><p>回到提供绝育的诊所。那种位于城市里的低价诊所预约已经排满，剩余的要么价格不详，要么位置远得离谱。我需要起床，一个个发邮件联系过去…… 一股焦虑感由此而生：昨天刚和老板闹得不愉快，起来后又看到项目的同事凌晨在抱怨工作不好做，我也有自己的事情想要做。</p><p></p></div><hr><div class="diary-entry">15:49 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115843279505319412" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/001/012/original/4cc46114482bc870.gif" alt=":cozy_otter_face_rub03:" loading="lazy"> 检查了邮箱的垃圾邮件，发现有一封两三周前的邮件…… 真是对不住啦。</p><p>我现在博客留下的联系方式是 iCloud 邮箱，但我其实看不爽这个邮箱很久了。它原本是我找实习和工作用的。但一次对方发邮件来约我去面试，居然被 iCloud 认为是垃圾邮件，直到两周后我才发现这件事。</p><p></p></div><hr><div class="diary-entry">17:59 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115843789142588750" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我以前对这个电脑都做了什么……？</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/843/787/187/542/082/original/223ec725bcf4198d.jpg" alt="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>一月六日</summary><div class="diary-entry">01:16 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115845507517239204" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>给室友带了个热的珍珠奶茶，三分糖，偷偷摸摸加了勺珍珠。今天比前几天明显要忙很多，也遇到了一些有趣的客人，比如：</p><p>甲：「你叫什么？」</p><p>我：「叫我 Susan。」（这是我的教名，我不喜欢这个名字，不过它很适合用来伪装身份）</p><p>甲：「你叫 Suzy？Suzy 是什么名字的外号？」</p><p>我：「我叫 Susan。」</p><p>甲：「你的全名是 Suzy 吗？」</p><p>乙（看上去像是监护人的人）：「她叫 Susan 啦。你说你叫什么。」</p><p>甲：「我叫 Stephen。Suzy 再见。」</p><p>下班后去了 Target 买下水道疏通剂。浴室的水槽很久之前就有点堵了，但我们都选择性无视了这个问题 —— 直到我看到洞口有一坨头发和绿色的玩意儿。</p><p>我买的是 Drano Max Gel Clog Remover，差不多七块钱，使用的时候需要倒一半的液体下去，等个 15 到 30 分钟，最后冲热水下去。提着这东西回家的时候碰巧遇到了物管，他问我是浴缸的下水道堵了吗，我说不是、只是水槽的洞口被头发缠住了。这样说来，早上他还给租户发了个邮件，说马桶除了厕纸外什么都不能倒，尤其是湿巾和厨房纸。这几天也看到有水管工陆陆续续来修理，恐怕又是谁堵了下水道。</p><p></p></div><hr><div class="diary-entry">02:13 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115845735041080489" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近不知道为什么，ゴキブリ酱出现的频率大幅度提升！往往都是室友发现它们、室友大声尖叫、我拿着厕纸捶ゴキブリ酱、我把ゴキブリ酱的尸体冲进下水道。</p><p>今天不太一样，我戴着一次性手套在切牛百叶。室友打算洗澡，站在卫浴门口发现匹克猫的动作有些不自然，好像在玩弄什么、在垃圾桶旁边。她笑着：「不会是ゴキブリ酱吧。」然后看着一只ゴキブリ酱惊慌失措地跑了出来，表情从欢乐变成了惊恐，落荒而逃。</p><p>我转过身一看，发现匹克猫已经把ゴキブリ酱玩弄于股掌之中，甚至放嘴里咬来咬去。我嘴里说着「不行啊快给我」，一边向匹克猫走去。这一举动反而吓到了它，以为我要来教训它，一瞪就把手上正把玩着的ゴキブリ酱打飞到不知何处。</p><p>这下好了，ゴキブリ酱不见了。我在找，匹克猫也在找。哦不，那个ゴキブリ酱肯定没有死，它肯定会躲到哪里去，成立宗派，未来带着三千个徒弟来报仇。此子定不可留也。好了不说那么多废话总之我在桌子底下发现了精疲力尽的ゴキブリ酱，在匹克猫的面前学它那样抓ゴキブリ酱，然后给了它一拳结束了它罪恶的一生……</p><p></p></div><hr><div class="diary-entry">15:05 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115848768551656376" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天把电脑修好了。主板上有许多螺丝滑牙了，急得我又是拿剪刀想把螺丝剪了以后固定用鸭子胶带（就是布胶带但我觉得鸭子胶带听起来好玩），又是把几年不用的电烙铁拿出来想用融化的锡固定住螺丝和螺丝刀，结果嘛…… 我根本不会焊锡，所以滑牙的螺丝也没有取下来。</p><p>那我是怎么换好键盘的呢？我发现取主板下来根本不需要取下那些滑牙的螺丝ーー靠！真的把屏幕和键盘分开的时候，还是会觉得很好玩。之前我把家里的老电脑索尼 VAIO 给拆了，取下其屏幕做成了简单的显示器。不过毕竟是老电脑，屏幕看上去并没有那么舒服，还时不时会出现红的斑点，我便将其落在了父母家。</p><p>电脑换好键盘后开机，敲下回车键后开心地发现没有失灵，要是换了键盘还不行的话估计我就得换个电脑了，但我不想买新的，没那个钱。新键盘零件我是从 iFix 上买的，差不多 180 块钱。</p><p>不开心的是我无法从旧键盘上取下我的贴纸。这些贴纸陪伴了我好多年，有些是大学为了庆祝学生被录取、附带的礼品贴纸。我很喜欢键帽贴纸，不过送键帽贴纸的大学不多。最后我也只是取了个 npm 的贴纸下来，放在新键盘上。至于旧键盘，那自然是保存起来哩。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/848/703/870/627/460/original/6da0b07f5126c7e7.jpg" alt="一台处于拆解维修状态的笔记本电脑的底部视角。我的左手抬起了已经移除后盖的机身，清晰地暴露了内部的硬件布局，包括占据很大面积的黑色锂电池组、绿色的主板电路、散热风扇以及连接各个组件的排线。在机身左下角可以看到一颗橙色的指示灯正在亮起。背景是略显杂乱的深灰色工作台垫，上面放着电源插座、鼠标以及其他维修设备。" loading="lazy"></figure><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/848/707/035/688/388/original/8ab34d5ec44a21d0.jpg" alt="以俯视角度拍摄了一台贴满各色编程技术贴纸（如 Python、C++、Spring、npm 等）的联想笔记本电脑的 C 面。有一个被拆卸下来的旧键盘直接覆盖放置在已经安装好新键盘的机身之上。旧键盘上的部分键帽（如 WASD 和 HJKL 区域）被替换成了醒目的彩色键帽。电脑的右侧放置着一把蓝黑相间的精密螺丝刀，左侧可见一盒螺丝批头。" loading="lazy"></figure></div><hr><div class="diary-entry">20:50 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115850125498221819" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这几天室友想和我玩 PUBG Mobile（国际服的吃鸡手游）。这是我们少数的会一起玩的游戏，因为电脑配置的差距，我们只能一起玩手机游戏，或者不吃性能的电脑游戏。</p><p>神奇的是，我玩这个游戏好像会开启我的「战斗模式」：会开始紧张、出汗。而我们居住的房子没有一个特别像样的暖气，很多时候要开不仅很耗电还很干燥的移动暖气。这意味着，我可以不开暖气的情况下开一局来让自己快速出汗。</p><p>以上可能都是胡话。</p><p></p></div><hr><div class="diary-entry">23:45 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115850812657057951" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>十一月的时候我读过一个文章，讲的是作者在父亲去世后发现父亲生前三年有婚外情，对方是同性。</p><p>感兴趣见：<a href="https://www.jenn.site/after-my-dad-died-we-found-the-love-letters/" target="_blank" rel="nofollow noopener" translate="no"><span class="invisible">https://www.</span><span class="ellipsis">jenn.site/after-my-dad-died-we</span><span class="invisible">-found-the-love-letters/</span></a></p><p>昨天我不知道为什么想起了这篇文章，把它讲给了室友听。她说她想起了自己的舅舅，也是一个同性恋者，但是有老婆孩子。</p><p>室友的母亲有着很强烈的「Gaydar」（Gay 雷达），很早就看出他是一个同性恋者。他结婚后，会去同性恋酒吧。虽然没有人提起，但是室友的母亲觉得大家都多多少少知道他不是异性恋者。</p><p>我：「这样子女方不就是被欺骗了吗？为什么要这么做呢？」</p><p>室友：「有可能女方也是同性恋者呢？双方凑合起来过日子生孩子。」</p><p>我：「我很难理解这件事。明明自己也没有想藏的样子，但是又要和不喜欢的人组建家庭、生孩子。」</p><p>室友：「可能是为了养老吧。生孩子是最便宜的养老手段。这样说来，他们会爱自己的孩子吗？」</p><p>我：「我不知道哎。」</p><p></p></div><hr><div class="diary-entry">23:54 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115850848224767688" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>感觉最近态度很不端正…… 虽然也有在干活，不过内心没有什么波涌。和前辈聊了一会儿，他推荐给我一些算法书籍，可以用来给我补基础。</p><p>过去不知天高地厚，觉得计算机相关的书籍都是土掉渣的资源。现在看来，载体根本不重要，内容才是核心。过于注重于载体，就像是看人只看衣装。</p><p></p></div></details><details data-group="diary_sections"><summary>一月七日</summary><div class="diary-entry">01:27 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115851216079389893" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>一位朋友有着一些让我感觉很可怕的习惯，例如在和我见面时、两个耳朵都塞着耳机听二倍速的 AI 读知乎短文。</p><p></p></div><hr><div class="diary-entry">05:06 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115852074500012290" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天我很罕见地吃了三顿饭 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/003/219/original/9825657b6c506ad8.webp" alt=":ottersgottaott21:" loading="lazy"></p><p></p></div><hr><div class="diary-entry">05:09 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115852087624318470" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>公司举办的活动被一个没有来的人打了一星差评。</p><p>有时候真不知道这些人在想什么。</p><p></p></div><hr><div class="diary-entry">14:48 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115854363018273525" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>你怎么是个海豹。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/854/354/885/887/594/original/a4164b0817d84de4.jpg" alt="一只长毛三花猫趴在深色木地板上，抬起头看着镜头。它有着蓬松的深灰色尾巴，身体是棕色、黑色和橙色相间的图案，圆圆得像个海豹宝宝，胸部和爪子是白色的。它的脖子上系着一个带有蓝色标签的项圈。背景是木地板和一小部分白色踢脚线。" loading="lazy"></figure></div><hr><div class="diary-entry">18:52 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115855325771102306" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打算在笔记本上用 Mu4e 和 mbsync 来使用邮箱服务，结果发现学校邮箱不能正常配置。最开始的方案是把 OAuth2 脚本伪装成邮箱客户端发起请求，后来发现 IMAP 协议被彻底禁用……</p><p></p><blockquote class="diary-thread-reply">23:36 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115856442374254480" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>可以使用 DavMail 网关，它会把 mbsync 的请求转换成微软的 EWS 协议发送给服务器，获取到的响应伪装成 IMAP 发给 mbsync。回调地址设置成 Outlook 桌面端的回调地址，中间的过程和用 OAuth2 脚本一样，除了最后登录微软账户的时候需要提前打开 Inspect 查看 Network、获取等会儿登录后状态码为 302 的响应头里的 location 值的 code 参数。</p><p></p></blockquote></div><hr><div class="diary-entry">23:43 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115856467255172281" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>笔记本修好后也同步了 Rime 和 Emacs 的配置，开心开心。不清楚为什么，Emacs 默认读取的路径是 .emacs 而不是 .emacs.d，除此之外需要关心的只有字体。我原先写 Emacs 配置的时候就是花费了大量的精力在设置字体上，尤其是两个系统会管同个字体叫不同的名字，需要在 Emacs 里自行检查扫描到的字体都叫什么，然后写 fallback 名称。</p><p>实际的写作文件用 Syncthing 同步。现在还在缓慢接受 GTD 工作流。</p><p></p></div></details><details data-group="diary_sections"><summary>一月八日</summary><div class="diary-entry">16:12 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115860356459226073" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>从朋友那里听到他们接过的一个案子：每年客户原本可以拿到五位数的钱，但是被某个知名企业的会计师处理得只能拿到十分之一。而他们就这样过了十六年，根本没有发现…… 后来发现的时候，十六年已经长到多数会计师不愿意接这个单。</p><p>朋友说，不管是哪个行业都有草台班子和垃圾。比如他们前些时候研究过网络上有名的 CPA（注册会计师）、EA（注册税务师） 等，张口就是胡话的并不少，还让一些有实力的会计师们延伸出了「批判知名会计师言论正误」的视频博主赛道。</p><p></p></div><hr><div class="diary-entry">16:18 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115860380589150805" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友有个二货的习惯。她会给自己的手机和平板设置十几个闹钟，但是闹钟响起的时候只是将其拍掉 —— 意味着过几分钟该闹钟还会响起 —— 但是完全不起床。也就是说，到了一定时间这些闹钟会挤在一起，每过几秒就会响起一次，但是她全程不会关掉任何一个。更为可恶的是，平板的闹钟声音是特么的野兽前辈呐喊声。</p><p>我每次早上都会被她的闹钟吵到，然后大喊她的名字叫她关闹钟，或者别睡了干脆起床吧！她没有一次选了后者。</p><p>她醒着的时候我说「你能不能不要定闹钟了，反正你都是自然醒，吵死了。」她拒绝了，认为没有闹钟她会起得更晚。我愤怒。</p><p></p></div><hr><div class="diary-entry">19:53 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115861225212426468" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天给室友看我的电子书库，其中《欺骗的艺术》让她觉得很有意思。我说这是和社会工程学有关的，她问我什么是社会工程学，我便简单地给了一些例子。</p><p>她：「这真的算是『工程学』吗？」</p><p>我：「是吧，英文这么叫的。不是还有 Prompt Engineer 吗？」</p><p>她：「那我是不是 Tax Engineer？」</p><p></p></div></details><details data-group="diary_sections"><summary>一月九日</summary><div class="diary-entry">02:51 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115862871394410568" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>公司的钱用在研发还是营销，我认为一直都是个好问题。</p><p>曾经认识一位电动滑板公司老板，他家的产品近乎没做营销，想找到它很困难。除了他的产品外，你能搜到的也只有老板努力地操着中式英文向用户展示滑板速度的「低质量」视频。</p><p>那他的产品好吗？实际上好得可怕。无论是电池还是马达，用的都是同价位买不到的配置。他曾经在另一家公司工作，然而其他创始人们执着于用便宜的配置、砸更多的钱在营销上 —— 钱是固定的，营销多意味着研发一定会少 —— 这一点让他觉得恶心，所以离开了前公司、自己出来单干。</p><p>现在我依然可以在街上看到人们用他前公司的产品，他现在公司的产品反而几乎见不到。匠人精神值得称赞，不过我也在想是不是反向而行才是最符合大众市场的方案。</p><p></p></div><hr><div class="diary-entry">03:02 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115862913589606902" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我刚换成 Firefox 没多久，你现在告诉我它的发展方向是 AI 浏览器？</p><p></p></div><hr><div class="diary-entry">03:22 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115862992903576208" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我最烦有人口口声声说着「不知道就问我」，然后在我真的问了之后回「这你都不知道」……</p><p></p></div><hr><div class="diary-entry">04:44 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115863313775176829" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我第一次见到一个包装盒同时也是说明书的设计，真不错。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/863/303/803/734/828/original/f3c9d590eb35bce0.jpg" alt="一个被拆开并完全展开的白色长方形纸制包装盒。从拍摄角度可以从侧面直接看穿包装盒内部，其结构呈现为一个中空的隧道状。​包装盒的内壁上印有密集的黑色文字说明。在图像的右侧内壁，可以清晰地看到一段垂直排列的黑色英文提示语，内容为“PACKAGE INSERT ON CARTON INSIDE”（说明书印于纸盒内侧）。这段文字的设计意图是指导用户剪开包装，以便阅读印在盒体内部的详细产品信息。​在包装盒的开口处，有一块撕裂后悬垂的白色纸质边缘，显示出纸盒已被破坏或正在被拆解。背景中隐约可见一台笔记本电脑屏幕、键盘以及一些电子设备的连接线。" loading="lazy"></figure></div><hr><div class="diary-entry">05:35 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115863514346532923" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>现在可以在 Emacs 里获取我的 RSS Feeds 并且阅读了。目前正在捣鼓如何查看 EPUB 和 PDF 文件，以及下载我 Calibre OPDS 里的书籍。</p><p>总有一天我会 Everything In Emacs 的…… <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/003/219/original/9825657b6c506ad8.webp" alt=":ottersgottaott21:" loading="lazy"> </p><p></p></div><hr><div class="diary-entry">17:56 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115866429105684496" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我又从 Firefox 改为了使用其分支 ——LibreWolf。</p><p>迁移很轻松。唯一的问题在于 LibreWolf 为了抵制指纹追踪，集成了 RFP 策略，其中就有强制所有页面为明亮主题。</p><p>这对我来说是个糟糕的体验，我看到明亮主题就会死（夸张）。</p><p>最好的方案是开启网站自身的主题选项。就算是大家常用的 Dark Reader 扩展，其实也会多多少少增加指纹熵。</p><p>不，或许最好的方案是把用指纹追踪发广告的人痛扁一顿……</p><p></p><blockquote class="diary-thread-reply">01-12 18:19 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115883507418870165" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我又改成使用 Floorp 了。LibreWolf 的安全和隐私性我认为是最可靠的那一档，但作为代价，它的易用性并不高。Floorp 是另一个基于 FireFox 开发的浏览器，功能更为全面和丰富，更适合作为一个生产力工具。</p><p></p></blockquote></div><hr><div class="diary-entry">18:15 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115866501233349545" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我才发现 Mastodon 可以使用 Markdown 渲染器。</p><p>设置后测试看一下效果：</p><p><strong>测试！</strong></p><p></p></div></details><details data-group="diary_sections"><summary>一月十日</summary><div class="diary-entry">01:47 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115868280397801943" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>原本班表是明天有上班，结果老板说不用、她来。</p><p>本来我和家里人说好了让他们来店里给我送东西。既然我明天不在店里，他们过来也不方便，于是叫他们明天不要来。</p><p>过一会儿老板私聊：「你早上可以上班吗？」</p><p>好吧……</p><p></p><blockquote class="diary-thread-reply">19:38 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115872491087553461" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>老板不意外地根本没有准时接班。或许我加个两小时的班她就来了呢？又或许她今天根本就不来了呢？总之这两个人很不靠谱。</p><p>我现在很想辞职不做了……</p><p></p></blockquote></div><hr><div class="diary-entry">16:50 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115871831479884696" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>脑子里还在想老板和经理曾经干过的破事儿、愤怒地小发雷霆时，未曾想父母在群聊里吵了起来。父亲向我控诉说母亲一大早就凶他，自己已经很忙了根本不想在乎其他人过得好不好，他只想修车、好好工作；母亲骂他嘴巴不干净，也不爱妹妹、不陪她，引得父亲勃然大怒：「你不要在小孩子面前说这个、她听得懂！」</p><p>虽然我清楚解决一件事情的前提是友好沟通，但是很多时候，去想要他们那么做是一种奢望。我在他们之间的关系里能做什么？他们想要我做什么？我又真的有精力去那么做吗？一想到这些事，立马开始变得无助起来。</p><p></p></div><hr><div class="diary-entry">18:52 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115872311843212332" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>小狗你可以吃橘子。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/872/310/068/662/541/original/0cd30f995b0dfe25.jpg" alt="一只手捏着一瓣剥好的新鲜橘子，果肉饱满呈橙黄色。在画面下方的模糊背景中，一只棕色卷毛的小狗正向上仰着头，眼神专注地盯着那瓣橘子，在等待喂食。" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>一月十一日</summary><div class="diary-entry">02:58 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115874221499542987" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>哦我的天…… 笔记本上突然不能正常生成 Hexo 文章了。不知道是什么问题，早上还可以正常 <code>hexo s</code>，现在一个文章都生成不出来。将整个项目删除重新克隆、把中午卸载的 chromium 安装回来…… 居然都不行。</p><p></p></div><hr><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 一月十一日 02:58</span>            </div>            <div class="diary-quote-preview">哦我的天…… 笔记本上突然不能正常生成 Hexo 文章了。不知道是什么问题，早上还可以正常 hexo s，现在一个文章都生成不出来。将整个项目删除重新克隆、把中午…</div>          </div>05:21 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115874785894626094" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有时解决方案就是这么朴实无华…… 我把 <code>_config.yml</code> 里指定文件类型的值写成 <code>.org</code> 而不是 <code>.md</code> 了 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/019/055/original/2421e8d631ebf3b8.png" alt=":ablobcry:" loading="lazy"></p><p></p></div><hr><div class="diary-entry">14:06 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115876848791547853" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>听朋友遇到的各类案子，心想会计师这么个职业真是铁饭碗中的铁饭碗 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/070/960/original/50f556343257c59f.png" alt=":wolf_think:" loading="lazy"> </p><p>她说其实律师也是一样。他们都做着可以影响客户一生的事情，但是其中不乏有没有职业道德、不专业，甚至爱故弄玄虚让客户崇拜自己的家伙在。一些案子里，客户的情况是完全可以称得上为「犯法」。但他们并不是故意那么做的，是会计师没有告知他们、擅自折腾出来的烂账。不过就算被查出来，大多数处罚也是无知的客户挨。</p><p></p></div><hr><div class="diary-entry">16:53 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115877504127449287" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>久违出门娱乐，刚出家门没多久听到优美的吹号声 —— 好吧我不认识这些乐器。</p><p>走之前我和室友聊了会儿天，主要是说我早上起来看到了什么趣事，比如小马是如何对着人类撒娇的。</p><p>我们也聊到了动物的语言。我看过一个 thread，讲的就是让 LLM 分析猫猫狗狗的语言 —— 问题在于它们有「语言」吗？目前已知有语言系统的动物貌似就是鲸类那些，而已经有人开始用 LLM 来分析它们的叫声。</p><p>那猫猫狗狗呢？我知道野猫成年后基本上不会喵喵叫，喵喵叫是奶猫获得母亲关注的一种方式。现在的家猫因为都被养在家里，也便不需要变得「成熟」、舍弃人类喜欢的叫声了。如果它们不是靠这种声音来交流的，它们之间是如何沟通的呢？</p><p>走到地铁站时，发现天杀的 MTA 把车价涨到了 3 美元。我本来想要坐的车居然在非工作日的时候被取消了…… 站内也没有贴说明，我爬上台阶才发现站台被封锁。</p><p>我想要试一下嘟文串功能，这是什么东西？</p><p></p><blockquote class="diary-thread-reply">17:05 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115877551930908772" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>本来地铁来了，但是看周围的人都没有想上去的样子，就转头看了眼接下来地铁的班表：下一辆是 Express，怪不得没人上这辆。不过非工作日怎么会有 Express 呢？</p><p></p><blockquote class="diary-thread-reply">17:12 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115877580416795726" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>其实我带了一本书、放在书包里。它是我至今为止都没有啃完的《阿特拉斯耸耸肩》的第三部。坐到目的地通常来说需要一个小时的时间，这期间我就可以坐着读书了 —— 结果我到现在还是站着的，玩的还是手机。</p><p>这些天我一直在配置电脑，疏忽了阅读 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/003/219/original/9825657b6c506ad8.webp" alt=":ottersgottaott21:" loading="lazy"> 实在是不应该。心里想到了室友的一位朋友，她是一个自律到可怕的人，让我很想向她学习。她同时有着许多「工作」，但不是为了经济才去做的，只是她想要学习。她的一个习惯让我觉得很有有趣 —— 记录自己今天在哪条街道走路，慢慢用自己的足迹填满地图。为了走过所有地方，她甚至会专门坐车到某个区，只是为了填充那一条没走过的路。</p><p></p><blockquote class="diary-thread-reply">17:52 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115877736292400298" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我想起来为什么我过去尝试坐车时读书、却放弃了：我晕车，再读书会睡过去……</p><p></p><blockquote class="diary-thread-reply">17:56 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115877753383517915" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我来到我个人很喜欢的一个馆子。他家的菜单很大很丰富，口味也是我喜欢的、像是小时候的味道。他们会免费提供茶水，也不会追着我要小费 —— 我去过一家越南面馆，那个服务生直接算好了小费，要我照着她算出来的给。我又不想要给你那么多钱！</p><p>再就是这家面馆的分量很足，价格很便宜。我带朋友来这家，最喜欢看他们点太多，却根本吃不完的样子。</p><p></p><blockquote class="diary-thread-reply">18:08 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115877800593444909" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>吃着吃着进来一个乞讨者，说自己丢了工作，希望有人可以 spare change，也就是要钱。和纽约市每分每秒都发生的一样，店里没有人理会他，就像是他不存在一样。</p><p>他走后，一桌客人问老板娘为什么不给他点钱。老板娘说如果给了，他之后每天都会来，那她的店就毁了。</p><p>前不久我和一位校友见面时，问他来美国（准确来说是来纽约市）的一年如何。他说最大的变化莫过于看到街上的流浪汉和乞讨者，现在可以不变脸色、当他们不存在一样走开。</p><p></p></blockquote></blockquote></blockquote></blockquote></blockquote></div><hr><div class="diary-entry">17:03 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115877544224773337" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>pxlmo 团队终于回复了我 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/109/original/930c5953aba2153e.gif" alt=":ablobcatpnd_heart_happy:" loading="lazy"> 现在我的 PixelFed 账号应该是变正常了。</p><p></p></div><hr><div class="diary-entry">18:05 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115877786768790631" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨晚看了一个讨论，是关于「死了吗」这个 App 的。OP 认为它依靠邮件服务一事很蠢，不如接入微信。讨论下有人说，不如监控用户界面来确认用户死活，反正普通老百姓又不会犯什么事，隐私给了就给了，又不是什么大事。</p><p>这让我感到很傻眼。真的会有人为了那么屁大点功能，将自己的数据和隐私拱手相让、还愚蠢地说服他人也这么想？</p><p></p></div></details><details data-group="diary_sections"><summary>一月十二日</summary><div class="diary-entry">06:10 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115880638328403683" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/019/055/original/2421e8d631ebf3b8.png" alt=":ablobcry:" loading="lazy"> 什么玩意我怎么 <code>hidden: true</code> 的文章全出现在 RSS 上了。</p><p></p><blockquote class="diary-thread-reply">21:14 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115884192522004896" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/080/751/original/0e7b38483aee37bb.png" alt=":blobimfine:" loading="lazy"> 我真的应该在每次 <code>hexo d</code> 之前专门打开 <code>public</code> 目录下的文件进行一次检查。很多过去存放在目录里但是没有继续往下写的文章被一次性发了个干净。现在那些隐藏文章的 <code>abbrlink</code> 都被我修改了，在网站上搜索只会看到我精心准备的 CloudFlare 报错页（假）。</p><p></p></blockquote></div><hr><div class="diary-entry">16:20 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115883037351701472" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友看 TNF 看多了觉得自己跑 100 公里不是问题，准备这周的哪一天抓我去实践 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/003/219/original/9825657b6c506ad8.webp" alt=":ottersgottaott21:" loading="lazy"> </p><p></p></div><hr><div class="diary-entry">18:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115883557159516533" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>昨天和朋友兼行业里我的大前辈出去玩。休息期间他询问我的现状，并且讲了讲他对本地行业的看法：</p><ol><li>Open position 基本上都是摆设。企业更倾向于招 contractor 也就是合同工，看他们几个月的表现再决定是否返聘（其实就是把实习生那套机制搬过来用在非学生人群身上）；</li><li>现在的面试机制过于「传统」，重点在于「你这个人够不够自信、能不能吹」，否则无法解释为什么经过那么多轮面试、最终筛选出来的人这么自信但实际表现一塌糊涂。我是认为这里也有暗箱操作在…… 亲爱的「裙带关系」……</li><li>「学习汇编语言吧！这样你学什么都会如鱼得水的！」</li></ol><p>拜他所赐，我开始慢慢补全自己的计算机基础了。我过去接触高级语言会更多一些，例如 Python，还有更为抽象的前端框架。C 这样的语言我只接触过一小段时间。总感觉什么东西都有代价，没有在入门计算机时深啃基础而是直接开始写业务逻辑和项目，结果就是基础不够牢固。</p><p></p></div></details><details data-group="diary_sections"><summary>一月十三日</summary><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">舞萌 DX 相关。我昨天游玩后的一些想法。</summary>        <div class="diary-cw-content">03:40 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115885712057919244" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>思考一些昨天玩舞萌 DX 的事情。</p><p>首先是这个游戏毕竟是音乐游戏，需要一定的节拍和协调感，很不幸的是我两个都不太好。</p><p>节拍感可以说是贯穿了整个游戏，基础配置到跳拍到后期的转圈都需要节拍感。这里单独拿跳拍出来说。跳拍又称 Swing，比较好理解的例子是「12-21-12-21」—— 假设数字是键位，- 是中间空出来、也就是「跳」掉的那一拍。<em>Popcorn</em> 和《好き！雪！本気マジック》的 Master 是我少数可以靠听打出来的跳拍曲。不过级别上去后，跳拍速度的加快会导致许多人直接将其视为多个交互来打，据说 よしき 就是这么打的。比较有名的是《ロウワー》Re:Master 的前半部分。</p><p>再就是协调。什么是协调？你可以左手打八分、右手打十六分吗？这就是协调。我没有到需要考虑这个的级别…… 虽然是这么说，但有时候随机到的谱子里偶尔就会有考验协调性的。参考的话搜「定拍」即可。</p><p>虽然这游戏只要游玩次数堆上去，很容易就会变厉害，但对于我这种很少能有时间去的，每次游玩后就会开始想这个想那个…… 这次去的收获还是比较大的：《まにまに》Master 的楼梯交互打得不错，让我惊喜；《ただ選択があった》Master 是一首我个人认为冷门的「Touch 当 Tap 用」的练习曲，因为完全把 Touch 当 Tap 使用的谱师并不多，所以会练习这一反射弧的人估计不多，想要练习的话可以尝试一下；这个月的 <em>Transcend Lights</em> Master 成绩又加了 1%，这种长脑子的谱面不去静下心来理解它实在是太困难了……</p><p>结尾和朋友玩了 Sasakure.UK 的魔王曲，不过我玩 Expert 难度就是了。Expert 13 和 13+ 很难避免触及到人体的极限，例如极快速度的纵连，我没有接触过当场就傻眼了。朋友提到几个解决方法，都利用了这个游戏的判定机制，例如「搓」—— 大拇指对准键位的内屏判定点、其他手指对准其外键，做出像是摆手一样的动作。</p><p>说到手，我感觉现在的发力姿势越来越正确了，几乎只会因为大幅度的移动而累到肩膀。</p><p></p></div>      </details></div><hr><div class="diary-entry">03:44 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115885727259622047" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>比较傻眼，刚才发现 Windows 系统在后台同时启动了 <em>Microsoft 365 Copilot</em> 以及 <em>Copilot</em> 这两个程序 —— 它们不应该是同一个东西吗？</p><p></p></div><hr><div class="diary-entry">15:18 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115888456449044950" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前几天父亲出车祸了。好在人被安全气囊「稳稳地接住了」，没有什么大碍。不过车就出问题了，保险杠那一整个部位都被撞飞，像一个没有下巴的人。</p><p>虽然这样说很缺德，但是我和母亲想的一样 ——「他可算出车祸了。」他开车总是不听劝阻、速度极快，转弯甚至还要加速，光是坐在副驾驶座上就是一种折磨。现在他出了车祸，也算是让他吃了点苦头，并且把他的车子卖掉、合理地不准让他继续开车了。</p><p>（我有模仿 ChatGPT 讲话因为我觉得很好笑）</p><p></p></div><hr><div class="diary-entry">15:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115888512396876001" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Emacs 比我想象中的强大很多，可以帮助我实现许多我以前需要手动操作的小事情。不过这些天一直在配置电脑，实际生产出来的内容却不见增长 —— 希望这不是我的「薄欲」吧。话又说回来，这样捣鼓来捣鼓去的，让我也是很开心。为了这一刻的体验，或许也是值得的。</p><p></p></div><hr><div class="diary-entry">15:38 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115888534788452060" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有时候会觉得一些人真的是幼稚得要死。可能岁数是我的两倍也说不定，但是时刻都在尝试证明「我不够好」，反而侧面反映出了他本人的愚蠢 —— 就，别那么无聊行不行，你又不是一个小孩子了，证明出这些事情会让你觉得很爽吗？</p><p></p></div><hr><div class="diary-entry">17:03 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115888867373859630" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有时候看到腿脚不便的老人，就会想需不需要把食物送过去。转念一想我是不是很傲慢地认为对方「走不过来」，将自己放在一个更高的位置、自以为是地施舍帮助？但又想到客观上来说我走过去要比他走过来所花费的时间和精力都明显更短和小。可是人类之间的联系真的可以用客观条件和效率来衡量吗？……</p><p>这可能是你在餐饮店内看到的店员平日在想的事情。</p><p></p></div><hr><div class="diary-entry">17:20 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115888935749185019" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>无聊会促进思考…… 至少是胡思乱想的频率变高了。</p><p>这家店或许是要没落了。除非是一个特定的时间点，否则根本不会忙。这期间我能做的，只有毫无目的地刷手机。</p><p>上次带了电脑来店里，被老板发现然后骂了一顿，虽然她给出的理由跟我带不带电脑一点关系都没有。</p><p>当时的电脑让我有时间可以做一些工作，不过为了不影响到打工都是让 AI Agents 干活。现在店里已经不让带电脑来了，我能做的就变成在手机上各种找存在感，比如现在。</p><p>不过可以考虑一下用 TeamViewer 远程操控电脑，继续指使 AI Agents 工作，就是速度很慢，我不是特别喜欢。</p><p>或许可以考虑一下带书，但这个环境较为潮湿，我怕弄脏了书，并且感觉老板会因为我看书这件事又骂我一顿……</p><p></p></div></details><details data-group="diary_sections"><summary> 一月十四日</summary><div class="diary-entry">03:33 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115891346564102344" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我想要休息，所以坐到了房间的另一个角落观看螺。有时候我想要变成一个螺，在鱼缸里爬来爬去。</p><p></p></div><hr><div class="diary-entry">03:38 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115891364806152011" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>年底的时候给匹克猫买了个猫爬架，主要是觉得它精力这么旺盛，却让它天天待在一个没有玩乐的房间很对不起它。它最开始还挺抵触猫爬架，后面慢慢习惯了，时不时会站在最顶层俯视我们。</p><p>我也有考虑要不要买一个类似于仓鼠滚轮的玩具给匹克猫。这个猫有时候像狗一样，会到处跑来跑去，还会把玩具叼回来让我陪它玩。</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">情感相关；我过去被表白一事。</summary>        <div class="diary-cw-content">16:08 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115894315973096582" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>起床的时候以为校友给我发了个消息，仔细看了眼聊天记录才发现是一位「朋友」。用「朋友」一词有些奇怪，因为我和他已经很久没有说过话了，我也不是特别乐意和他进行对话，再加上过去我们之间发生了一些让我觉得很不愉快的事情。</p><p>如果他不是一个自负的家伙，或许我会很乐意多一个朋友吧。很可惜那不是现实，这个人平日说话实在是让人心生厌烦。他因为一些莫名其妙的事情喜欢上了我，给我发了阅读起来让人恼火的小作文 —— 他居然说「虽然人人都有缺点，但在他看来我 <em>瑕不掩瑜</em>」。</p><p>我讨厌满脑都是自己的人，许多时候和他说话都会感觉我只是他的观众。他的重心在于如何表达自己，而非和我沟通交流。他在乎我的感受吗？我没有看出来。就连他的表白，他想的也都是他自己：他有没有鼓起勇气、他要是被拒绝了怎么办、他过去怎么怎么样……</p><p>被我稍作愤怒地拒绝后，他选择了删除我的联系方式，次日又给我发 QQ 邮件说自己真是个废物、不会再来联系我。结果没多久他告诉我的朋友他还是想要和我联系上，并且在接下来的一年内又给我发送 QQ 邮件，内容自然而然也是他一时兴起想出来的，对我而言只是精神上的负担。一年后，他主动找到我，希望可以再次成为朋友。</p><p>比较好笑的是，这之后我从母亲那儿听说其实我俩是亲戚关系，只是我们俩活了二十多年才知道。</p><p></p></div>      </details></div><hr><div class="diary-entry">16:21 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115894367240336123" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>大一时发生过一个哭笑不得的事情。</p><p>一个 ABC 蠢蛋说福建菜好吃。</p><p>我不是特别喜欢福建菜，甚至可以说是有点讨厌。他觉得我不喜欢福建菜一定是因为我没有吃过福建菜，或者说是没吃过好的。</p><p>我心生疑虑，你个一辈子没去过福建的，还能比我这个三分之一的福建人更懂福建菜？遂询问他福建菜里有什么好吃的。</p><p>他：「拌面扁肉。」</p><p><em>我真服了。</em></p><p></p></div></details><details data-group="diary_sections"><summary>一月十五日</summary><div class="diary-entry">00:54 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115896381937236696" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这个店里弥漫着诡异的「绩优主义」的味道。明明对方迟到了足足一个小时，却没有丝毫歉意可言，反而认为这期间没能一个人做好的我有问题，也就是「菜」。</p><p>这一小时对我的身体所造成的损伤不算小：压力过大，头撕裂般地疼痛着，就算过了数个小时也是如此。但是抱怨在这个环境下是会被取笑的，因为这里只允许存在着「强者」。</p><p>为了证明自己是那个「强者」，无端取笑他人在这家店里并不少见。逻辑也就是「只要我能证明你是弱者，那我就是强者」。这是一个很莫名其妙的想法，又幼稚，也没有意义，只会让员工们越来越瞧不起你。</p><p>想多了又觉得这些人很可怜。他们过去是生活在一个怎样的有毒环境下，才会每分每秒都贯彻着「绩优主义」？他们不累吗？从来都没有脆弱过吗？或许他们只能在对他人的否定中才能获得那可怜的安全感。</p><p></p></div><hr><div class="diary-entry">03:24 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115896973477678208" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>匹克猫老用脑袋顶我脸，好烦。</p><p></p></div><hr><div class="diary-entry">05:29 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115897464962510808" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>头太难受了，想用电脑做点什么但是眼睛不允许。想要做一点不会用到电子屏幕的事情，想到了练习钢笔字，但是没有找到字帖。又想到可以读书，不过好像对眼睛也是一种负担。思来想去，我躺在床上对着手机说话，录了九分钟的音，说到自己都要睡着了……</p><p>眯一会儿后室友回了家，她一直在打电话，我也借此醒了过来，很不好地去刷了 BiliBili：近期出现了不少欧美 V 曲，颇有意思。我听了抽掉多个音轨的《催眠术》，旋律很不错，不过原曲的混音根本无法让我专注于其旋律。我又听了《圆头监狱》，我本来就喜欢其原型《圆形监狱》，这首歌又在其基础上讲了「哈基米文化」和中国互联网，不过我对此不是特别熟悉，因为不怎么混「抽象圈」。</p><p>不拿起电子设备的话，就无法解决自己的分享欲吗？</p><p></p></div><hr><div class="diary-entry">14:41 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115899634026682338" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>睡前关掉闹钟，打算美美睡上一觉…… 结果早上同事的微信电话打过来，问我能不能送下钥匙，她忘记带了。</p><p>我让她直接来我家，也就差不多十分钟的路程。未曾想，我地址给错了 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/003/219/original/9825657b6c506ad8.webp" alt=":ottersgottaott21:" loading="lazy"> </p><p></p></div><hr><div class="diary-entry">22:42 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115901525997209875" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>周日计划去走路。原先室友想着直接走个 100 公里，但听了她一位「走路大师」的经验，打算只走个 50 公里看看。</p><p>根据「走路大师」所说，她曾经一天走了 70+ 公里，最大的问题在于找不到厕所。关于路上怎么吃饭，她的方案是找到路边一家 Deli 然后买汉堡、三明治或者贝果吃。那天她吸收了足足四千多卡路里。</p><p></p><blockquote class="diary-thread-reply">22:57 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115901587714819360" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最大的问题其实是我能不能走那么久。</p><p>我有扁平足，很多类型的鞋子不能穿，还必须穿上定制的鞋垫。扁平足的特质导致许多运动都不适合做，例如羽毛球。</p><p>其实撇开我的脚，我这个人的身体就不强。我平日出门的频率很低，几乎跑不了几步。上次去健身房因为身体过于纤细、缺钙，导致每次动身体时关节都在咔咔响，其他人也不建议我来。</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>一月十六日</summary><div class="diary-entry">02:42 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115902468642331246" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>PaaS 好贵…… 其实最开始项目就应该用 IaaS 部署。</p><p>这不是我第一次购买云服务器，上次买是为了搭建《饥荒联机版》的服务器，买的是 DigitalOcean，感觉还挺贵。现在买了别家的小服务器来部署项目，便宜好多。</p><p></p></div><hr><div class="diary-entry">03:24 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115902635213769376" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>疑似天气暖和起来的原因，家里ゴキブリ酱出现的频率显著提高。现在基本上每天都可以找到一个让它飞升……</p><p></p></div><hr><div class="diary-entry">03:58 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115902768144978058" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>匹克猫最近一直往人肩膀上跳。有时候觉得它和狗一样，对人上瘾了。</p><p>家里的另一只猫就没有这么喜欢人了。咪咪猫老是看到我就跑，很多时候都是自己玩自己的，也不喜欢喵喵叫。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/902/755/835/172/070/original/1d5350c5ada3c425.png" alt="一只狸花猫趴在一个人的肩膀上，猫的身体横跨在人的后颈和肩膀处，看起来非常放松和好奇。猫的头部朝向右侧俯视，露出了它明亮的眼睛、粉嫩的鼻子和白色的胡须。人正举着手机对着镜子拍照。" loading="lazy"></figure></div><hr><div class="diary-entry">16:05 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115905627769543021" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/003/219/original/9825657b6c506ad8.webp" alt=":ottersgottaott21:" loading="lazy"> 我才知道 Swagger 可以导出端口供客户端使用。之前一直是手动维护，累死我了。</p><p></p></div></details><details data-group="diary_sections"><summary>一月十七日</summary><div class="diary-entry">04:20 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115908516652875189" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>因为没能准时交付，我和项目管理大吵一架。</p><p>我认为这种工作根本无法给出一个准确的时间：一是没有过去的经验来推测出一个相对的时间，二是我怎么知道有多少个隐形 Bug、修它们要花多少时间。</p><p>对方则认为我不守信，因为我曾经承诺过可以在这个时间点完成工作。这个行为确实也是我的不负责任。我们因为「我无法给出一个准确的交付时间点」而吵过多次架，我为了不继续吵架，给了个我自己都不确定的时间。</p><p>我不清楚到底该怎么办。我有在很努力去做这件事，关于 Deadline 我也真是不知道怎么算出来。我要交付一个没有 Bug 的完美产品，我做得到吗？</p><p>他也问我不是已经有了另一个人吗，为什么效率还是那么低。那也不是我的问题啊，对接要时间，等对方做完也要时间，我也不是一个会管理的人。</p><p>那我又要为了时间放弃质量吗？这个产品并不是一个质量差也没关系的产品，我根本不可能为了速度而放弃质量和安全性。我明明已经说了那么多遍，对方想的依然是「那你为什么不能在 Deadline 之前把两者都做好？」</p><p>该说有什么好事情，那就是这几天发现了许多技术债务，可以趁现在用户量没有那么多的时候赶紧纠正。</p><p></p><blockquote class="diary-thread-reply">08:31 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115909505399840248" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我怎么还在干活…… 明明五个小时后就要准备去上另一个班了……</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary> 一月十八日</summary><div class="diary-entry">14:06 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115916483631645046" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>目前走了五公里，来 Dunkin 买个东西喝。</p><p>天气太差了，一直在下雨和下雪。如果是晴天的话走感会好很多。因为怕太冷，戴了个针织帽。这是我第一次戴针织帽，感觉很奇怪。它会把我的眼镜向下推，很烦。</p><p>路上看到了许多坑老外用的「日料店」，贵得要死，一看用的还是糟糕的材料。</p><p></p><blockquote class="diary-thread-reply">14:51 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115916663294465558" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>二公里的桥，雾蒙蒙的。比曼哈顿大桥好看点，但是比不过布鲁克林大桥。有人未来想要走桥的话，莫要走错了，布鲁克林大桥是西边的那座。</p><p>路上看到了很多健身者，他们真自律啊。</p><p>长岛市感觉还不错，吃的东西不少，就是靠河有点冷。貌似许多留学生会选择住在这里，房价不算特别高。但最便宜的选择永远是隔壁的新泽西。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/916/638/611/384/155/original/3d77038c4f60f169.jpg" alt="一个从高处俯瞰的城市景观，前景被密集的黑色铁丝网围栏完全遮挡。围栏的菱形网格结构占据了画面的大部分，焦点落在金属网线上，使得背景中的城市景色呈现出模糊的虚化效果。​透过围栏可以看到，背景是一条宽阔的海湾，水面呈现深灰色。右侧排列着多栋高层建筑，建筑风格较为传统且密集。地面上覆盖着一层薄薄的积雪或霜，显示出寒冷的气候特征。整个画面色彩以灰色、黑色和暗棕色为主，天空阴沉，营造出一种冷峻、压抑且带有工业质感的氛围。" loading="lazy"></figure><blockquote class="diary-thread-reply">16:36 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115917076185163513" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>走到了朋友家附近，跟他说后他以为我是坐车来玩舞萌的。</p><p>我：「我走过来的。」</p><p>他：「？？？…… 那你要来玩吗？」</p><p></p><blockquote class="diary-thread-reply">18:06 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115917428383516417" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>走了十七公里，到平日爱吃的面馆了～点了干锅肥肠吃。</p><p>室友原先的目标是五十公里，现在看来不太行呢…… 重在参与吧。</p><p></p><blockquote class="diary-thread-reply">21:13 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115918162452301987" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>半马达成～</p><p>一路上叽叽喳喳聊着天，脚步也变得轻快不少。</p><p>路上经过了数个没去过的社区，蛮稀奇的。</p><p></p><blockquote class="diary-thread-reply">21:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115918239345529015" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>在星巴克休息了一会儿，出来后感觉还是走不动，遂去附近的 Popeyes 买点东西吃。没想到它居然也推出了五美元活动，可以选择三块鸡肉，对现在的我来说应该是足够了。</p><p></p><blockquote class="diary-thread-reply">21:51 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115918312977868770" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我来这种地方买炸鸡干嘛。炸鸡又干又油，还没有味道。我为什么要浪费五美元来荒郊野岭买炸鸡。</p><p></p><blockquote class="diary-thread-reply">23:48 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115918774552873485" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>走到了极限…… 袜子和鞋子都湿透了，雪几乎下了一整天。膝盖后方无比酸痛，除此之外就是因为太冷、脚趾控制不住地抓地而导致的疼痛。现在找到了最近的巴士站，慢慢坐车回家。</p><p>可以想象到我明天肌肉酸的样子，明天还要上班呢。</p><p></p><blockquote class="diary-thread-reply">01-19 01:22 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115919142801256605" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天差不多是这样了，满打满算应该是二十二公里。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/919/136/511/716/920/original/31d99c8b32550273.png" alt="这幅图像展示了 Immich 应用程序的地图界面，以深色模式呈现了纽约市部分地区的地理分布。地图上散布着多个圆形图标，代表在该地点拍摄的照片或照片集。在曼哈顿上东区和罗斯福岛附近，可以看到一个显著的圆形图标，其内部显示的正是一张透过铁丝网围栏俯瞰河岸的照片。地图的其他区域，如皇后区的长岛市、伍德赛德以及法拉盛周边，也分布着类似的照片标记。部分标记显示为带有数字的蓝色圆圈（如「2」、「3」或「4」），表示该区域内聚合了多张照片。背景地图详细标注了城市地标和主要道路，包括中央公园、拉瓜迪亚机场以及连接各区的州际公路网络。左侧设有地图缩放和定位的控制按钮，左下角则显示了 1 公里的比例尺。" loading="lazy"></figure></blockquote></blockquote></blockquote></blockquote></blockquote></blockquote></blockquote></blockquote></div></details><details data-group="diary_sections"><summary>一月十九日</summary><div class="diary-entry">10:34 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115921311525333718" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>养猫很讨厌一点是它会在凌晨选择去把桌子上的东西都打到地上，而不是乖乖睡觉。</p><p>现在我已经在桌子上不放它可以打下来的东西，但还是不知道它找到了什么、推到了地上。刚才听到了两声响声，但是地上只找到一个东西…… 意外可怕。</p><p>有时候我会想，猫做这种事情是为了吸引人类的注意吗？匹克猫经常这么做的目的貌似就是这样，它打完还要挑衅般地看着我。之前看过一个养猫的聋哑人，她家的桌子上摆满了装饰品，而能这么做意味着猫平日不会翻桌上的东西。让我大胆猜测一下，是因为打东西到地上就不会被她听见，所以猫觉得无聊、不再那么做了么？</p><p></p></div><hr><div class="diary-entry">11:31 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115921537238348732" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>一位「朋友」很喜欢用「没想到……」来表达自己又惊又喜的心情。</p><p>在我看来，「没想到你怎么怎么样」是一个很诡异的表述。我在你心里到底是一个什么样的人？你还「没想到」起来了？</p><p>他对我用过两次「没想到」：一次是「原以为女人是网上说的那样，没想到认识你后发现不是那样」，另一次是「我一直都没有朋友，没想到我们可以聊得很来」。</p><p>这种表述的前提是，他原先认为的我是一个更为负面的存在。就算发现了我的可取之处，但他依然会以上位者的姿态对我发表自己的意见，浑然不在乎我听到后是什么感受。</p><p>听着就来气主要是。</p><p></p></div><hr><div class="diary-entry">11:45 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115921593848169538" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我想睡觉呢匹克猫躺我脸上了。它踩奶的动作特别大，感觉像是故意在踩我玩。</p><p>你想怎样，还想怎样。</p><p></p></div></details><details data-group="diary_sections"><summary>一月二十日</summary><div class="diary-entry">03:17 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115925258019418910" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我不知道为什么，近期漫画里总是会出现前期党争，后期全收的剧情。可恶，我是来看党争的，不是来看后宫的。</p><p>我个人还蛮喜欢《五等分的花嫁》这部作品，它在某个意义上成功地结合了推理和党争。当时追连载的时候看贴吧里各个党派之间的分析和干架（还有早期的迫害四叶，已经我最喜欢的镜哥哥环节），只会觉得这个社区真是活力满满 —— 当然临近结尾的时候干架就成了真的干架，这种东西还是不要回忆起来好了。</p><p>这部作品后，我就很难再看到「赢家」很难推理出来的党争作品了 ——《学不来》我是不会把它算在党争里的。</p><p>喜欢《五等分的花嫁》的另一个原因是作者的画风我很喜欢，初中时专门学习过他的画风，那时候也算是我的绘画巅峰吧…… 高中因为玩了 LBGTQ+ 手游变成只会画兽人的废人了。现在别说画得好不好，能不能画出来都是一个问题。</p><p></p></div><hr><div class="diary-entry">04:07 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115925452701936409" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天不知道怎么回事，楼下老头还是隔壁小子，其中有一个一整天都在用力走路 —— 地板一直在随着对方的脚步「咚咚咚」地晃动。不仅烦，还要因为对方大声地喧哗而被吵到。</p><p>更生气的是现在不是「安静」的时间，我也没有理由去说对方。</p><p></p></div><hr><div class="diary-entry">04:12 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115925475460812766" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Playwright 真有意思啊，之前我怎么不会用这个来测试前端。</p><p>今天一整天都在写测试了，但是最好用的测试莫过于 —— 生产环境的真实用户！</p><p>不，我怎么可能是一个不负责任的 DevSecOps……</p><p></p></div><hr><div class="diary-entry">04:18 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115925498051213747" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>考虑如何利用起同事的 Go 技术栈 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/070/960/original/50f556343257c59f.png" alt=":wolf_think:" loading="lazy"> 不然让对方写前端也太痛苦了。</p><p>其实可以让计算相关的任务全部放在一个 Go 写的服务端上，当前的服务器只处理业务逻辑，要用的时候调用 Go 服务端即可。</p><p>但是今天不是想和人对接的心情呢～还得写知识库，好烦喔。</p><p></p></div><hr><div class="diary-entry">04:33 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115925555947660350" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友找我要匹克猫的丑照，拍了一张，她居然觉得不够丑！遂不服气地问她有什么丑照，她给我发了图二……</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/925/553/708/662/215/original/47bbb3d3f90b6100.jpg" alt="极近距离拍摄的猫部正面照，由于对焦距离过近，画面呈现出一种自然的虚化感。焦点主要集中在猫粉红色的鼻头和白色的吻部。猫的眼睛位于画面上方，因景深关系略显模糊。背景是浅色的木地板和零星的杂物。" loading="lazy"></figure><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/925/554/736/520/041/original/b0ba4d42a27020fc.jpeg" alt="一只拥有棕色虎斑纹和白色的胸部及面部毛发的家猫，睁着大而圆的淡黄色眼睛，直视镜头，表情显得有些呆萌。最显著的特征是它微微吐出了粉红色的舌尖。背景较为模糊，隐约可见灰色的布艺沙发边缘。" loading="lazy"></figure></div><hr><div class="diary-entry">14:26 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115927889254128187" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>朋友圈里有个我认为很适合写微博客的人。但因为我不喜欢他，所以我不会推荐给他。</p><p></p></div><hr><div class="diary-entry">19:12 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115929012754380754" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>那之前那节课是什么情况。同个部门下的课对这方面的应对还各不相同么。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/929/008/157/312/087/original/5d8700830cee779a.png" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">22:33 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115929802161954274" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>上班闲着搓了个千字的文，客人一来我就把手机收起来了，现在拿起来一看发现记录全没了 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/008/original/424361453b49ed14.webp" alt=":gblackcat_shake:" loading="lazy"> </p><p></p></div></details><details data-group="diary_sections"><summary>一月二十一日</summary><div class="diary-entry">06:23 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115931650112741637" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>看了订阅的博客里有关 MBTI 的文章，难以想象的是看完后刷 BiliBili 时发现舞萌 DX 上了个名为 <em>INTJINTPENTJENTPINFKENFJINFPENFPISTJISFJESTJESFJESTPISTPISFPESFP</em> 的歌。</p><p></p></div><hr><div class="diary-entry">13:55 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115933428728776709" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>最近想淘个二手破相机随时随地拍照玩。虽然在脸谱网市场上找到了不少不错的选择，但是离我家有点距离，这种鬼天气还是在家里窝着吧</p><p>之前受导师影响，也喜欢在脸谱网市场 <em>dumpster diving</em>（垃圾场冲浪，简称垃圾佬行为），借此免费拿到了两个不能用的戴尔计算机，不过现在还没搞明白为什么不能启动就是了……</p><p></p></div><hr><div class="diary-entry">14:38 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115933596816996375" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前些天看到一个人分享自己做的手机键盘壳，可以随时随地用手机编程。我心想还蛮酷的，点进评论区一看却发现多数人都在用「牛马给自己配了个随身的磨」这样的语句嘲讽博主，亦或者搬出意义论来辩解这些热评的合理性。</p><p>无论博主做这个东西是干什么的，都不应该嘲笑才对吧。他有可能是拿来工作，有可能是拿来闲暇期间做自己的项目，也可能只是为了分享自己设计出来的东西。我很不理解为什么大家都默认编程只是为了工作，进而得出「喜欢编程的人都是老板的好驴」这样的结论。</p><p>至于意义论…… 带着你的意义论吃大粪吧！</p><p></p></div><hr><div class="diary-entry">19:39 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115934780651575098" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>顾客提出有报错、我 hotfix、项目管理急忙和对方联系什么的也太刺激了。</p><p>错误倒只是一些小 bug，还算可以接受。</p><p></p></div><hr><div class="diary-entry">20:03 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115934877291897955" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有点想要买个云服务器把现在本地托管的服务都丢上去。不过家里的残废计算机不算少，修一下也可以自己弄个物理服务器玩。</p><p></p></div><hr><div class="diary-entry">21:14 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115935153058865586" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>感觉自己冲浪频率有点变高，把小红书卸载了。不知道为什么自己之前整理 App 时没有把它卸载了改用 Web，同样的还有百度贴吧。</p><p></p></div><hr><div class="diary-entry">21:24 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115935193623793299" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>一些大平台虽然流量看着多，但是活人很少，比如 Instagram 这类，在上面做营销很难做出什么成绩。我会推荐先从本地社区开始做起，例如 Nextdoor，活人明显会多很多。虽然脸谱网也有本地社群，但是脸谱网的讨论氛围怎么说呢，我很不喜欢，一点都不亲切。</p><p>开活动和工坊的话，我不建议一上来就买推广，容易花冤枉钱。部分组织活动的平台要求订阅服务才会把你的活动放在 Feed 上，其实没必要，你在其他平台宣传，链接这些私人活动就好了。这类平台的服务价格相比下来都很贵，用处还不大。</p><p></p></div></details><details data-group="diary_sections"><summary>一月二十二日</summary><div class="diary-entry">00:50 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115936004127740042" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>很可怕的是今天 21 号，我月刊还没有准备好。这个月除了打工，就是赶进项目，有时候很好奇怎么时间过得这么快。这周末需要回一趟家陪亲戚吃一顿饭，下周还开学了，有时就很好奇怎么时间过得那么快。我怎么记得我除了打工和赶项目，就没有做什么了，汇编学习和读书的工作推进速度都一般般。</p><p></p><blockquote class="diary-thread-reply">00:52 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115936011483527217" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>有时候谜底就在明面上…… 我还突然想起来这个月折腾了一段时间的 Emacs。</p><p></p></blockquote></div><hr><div class="diary-entry">01:35 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115936181061342083" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>听着钢琴声睡着的咪咪猫。</p><p>妹妹弹的钢琴有那么助眠么？</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/936/176/410/204/863/original/9592ecc45c55d0ce.jpg" alt="一只毛发蓬松的三花猫正闭着眼睛，舒适地蜷缩在一件黑色的羽绒外套里睡觉，它的头枕在衣领处，背景是米色的墙壁。" loading="lazy"></figure></div><hr><div class="diary-entry">05:02 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115936994733762478" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我唱歌走调严重，让唱歌小金星室友很是好奇我的耳朵和嗓子是怎么运作的，难道听不出来自己唱的是哪个调么。</p><p>这些天一直在听 Sakanaction 的歌，其中《『バッハの旋律を夜に聴いたせいです。』》这首歌听着听着有点会唱了，遂唱了几句，引得室友惊讶跑来：「你一个音都没唱对，但是居然和原曲达成了相当美妙的和声！你真厉害！」</p><p>我要杀了她 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/019/055/original/2421e8d631ebf3b8.png" alt=":ablobcry:" loading="lazy"> </p><p></p></div><hr><div class="diary-entry">17:00 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115939817539374461" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/070/960/original/50f556343257c59f.png" alt=":wolf_think:" loading="lazy"> </p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/939/806/081/689/637/original/9dcc8906dad4df02.png" alt="一张来自维基百科的英文感谢信截图，深色背景配白色文字。信中写道：「数十亿人使用维基百科，但只有不到 2% 的读者会捐款。这就是为什么我如此感激能将您视为我们珍贵的支持者之一，[已隐去名字]。多亏了您最近的捐助，全球各地的读者只需轻点按钮，就能找到可靠的事实，并探索人类知识的无尽奇迹。维基百科为您、为世界、也为下一代而存在。怀着深深的感激之情」，以此表达对用户捐款支持的深切感谢。" loading="lazy"></figure></div><hr><div class="diary-entry">17:23 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115939907303669359" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>试着用一下 NeoDB 中，但不是很会用。</p><p>比如我在 YouTube Music 上听到的歌，我想要记录下来，却发现数据库内没有，该如何添加呢？</p><p>依次换成 Spotify、Apple Music 和 Musicbrainz 的链接都无法正确查找。</p><p>实在不行就乖乖地本地记录好了。</p><p>话说貌似 Emacs 也可以播放音乐……？</p><p></p></div><hr><div class="diary-entry">17:34 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115939950725259379" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/008/original/424361453b49ed14.webp" alt=":gblackcat_shake:" loading="lazy"> 唉同事离开了我们，心情较为复杂。</p><p>我对人的看法很大程度上受《不原谅也没关系》这本书的影响，这也包括我对我自己的看法。</p><p>书中有个概念叫作 <u>内在批判者</u>，可以理解为心中有个声音，总是会数落自己、一次次想起自己难堪时的样子，然后陷入自卑的泥沼。</p><p>他的声音在我心中实在是过于大声，第一时间让我认为是不是自己做得不够好，是不是我的安排和计划都不够周到，我到底做了什么。</p><p>过一会儿我让自己接受一个事实，原因可能真的和我无关，其他人有自己的事情需要处理，这是很正常的。</p><p></p></div></details><details data-group="diary_sections"><summary>一月二十三日</summary><div class="diary-entry">02:22 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115942028619426846" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友向我分享了今天活动来的一位男士。只是听她就觉得「哇噻」！</p><p>首先是他的服装，尤其是配色极有品味，我可以 <em>抄</em> 去 —— 没办法我对橘色和奇怪花纹的领带没有抵抗力。我就有一条可爱的猫咪领带，但是很少戴。</p><p>其次是他有一个日记本，每天都会在上面写写画画。虽然没有学习过绘画，但是看着画的完成度就让我明白这是一个下了功夫画画的人。因为一些事情，我也在考虑使用实体的日记本，正好可以开心地使用钢笔多写字。</p><p>再就是他的技能树，他会很多东西，包括编程，也是一位马拉松跑者。室友说现在让她觉得颇有趣的人都是跑马的，让她很意外、不知道为什么。</p><p></p><blockquote class="diary-thread-reply">03:16 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115942242019721061" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>再认真听她讲了一下今天的活动，主题很是稀奇：「那些不受欢迎的想法」。</p><p>室友拿了灰阶来说，其他人的想法也是一个比一个有意思：</p><ul><li>写作是为了自己，不要停止写，一起来写博客吧；</li><li>专注于当下那些平日不会注意到的细节，比如走路时观察一下看到的建筑物；</li><li>睡地板；</li><li>不要觉得自己奇怪，想到什么就去做吧。</li></ul><p></p><blockquote class="diary-thread-reply">06:29 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115942999551897791" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友借此问了我关于写博客的事情，不过在我看来她更想要个人网站，也就是仅展示自己的页面，因为她对于样式和设计很看重，还觉得我的博客不好看。</p><p>哼，你是不会懂极简的美的。</p><p>不过如果让她这样的技术小白写博客的同时，还要好看的设计，BearBlog 这样的平台都得 pass 掉。我让她自己去 vibe 算了，但她应该不会花精力在这上面。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">04:37 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115942558031937625" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这些天都在吃这个。</p><p>附近超市买鸡腿排，用小刀剔除骨头后沾上面包糠后，就可以全部冻起来，需要吃的时候塞进空气炸锅里。</p><p>这种肉的内部很嫩，外部其实没有说多脆，放油可能外壳会更脆？但我不是很在乎这一点。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/942/542/955/017/012/original/d75bd1768ce212bb.jpg" alt="一个黑色炸篮底部铺着一层铝箔纸，上面平铺着一大块裹满面包糠的鸡腿排。​鸡肉呈现出浅褐色的干燥粉末质感，显示出尚未开始烹饪或处于加热初期的状态。铝箔纸边缘略微卷起，紧贴炸篮内壁，整个构图从俯视角度居中拍摄，光线均匀，背景可见厨房台面的局部细节。" loading="lazy"></figure></div><hr><div class="diary-entry">15:33 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115945139943697213" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>睡着睡着突然醒过来想起自己博客还在用 Google Analytics <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/245/original/aad7de836fc79371.png" alt=":ablobhammer:" loading="lazy"> </p><p>杀！</p><p></p></div><hr><div class="diary-entry">22:09 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115946693793810835" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前不久手机接收到了一次更新，其中有一半的更新是与 AI 相关，例如玩游戏卡住时你可以快速唤出 AI 来询问咋办 —— 谁会问啊。</p><p>昨天我阅读了 <a href="https://toidiu.com/blog/2025-12-25-privacy-and-control/" target="_blank" rel="nofollow noopener">这篇文章</a>，并对作者的手机系统产生了兴趣。简单搜索过后发现该系统得用到 Pixel 系的手机，我不知为何蛮喜欢 Pixel 系的外观，但是现在没有买新手机的打算，太贵啦。去二手市场淘一个还可以。</p><p>我的手机是折叠屏手机，意味着鲜少有第三方系统会支持该型号。摩托罗拉系统已经全面拥抱了谷歌生态，使用起来说方便也方便，就是这挥之不去的 AI 很烦人。刚才想要分享截图到短信里，第一个出现的视图居然是 Remix 按钮。对不起我不想要 AI 编辑这张图片。</p><p></p></div></details><details data-group="diary_sections"><summary>一月二十四日</summary><div class="diary-entry">03:15 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115947898463232194" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>据说周日要下 12 寸的大雪…… 上一次看到这么冷的纽约，还是在上次。开玩笑的，是我刚来美国的那一两年。</p><p>有一次雪下得太大，政府叫我们不要出门。从窗户看去，只能看到大雪和远处铲雪车的车灯。我因为熊，跑到外面去玩，是街道上唯一一个跑来跑去的人。</p><p></p><blockquote class="diary-thread-reply">03:17 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115947907622464388" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说到铲雪车，上次走马的时候看到撒融雪剂的车和人。这些小颗粒会从车的屁股洒出来，像小型的冰雹。至于撒融雪剂的人，他们二三成队，一人负责推车洒，一人负责抗着备用的融雪剂，最后一个人应该负责当靓仔。</p><p></p><blockquote class="diary-thread-reply">03:22 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115947926837240332" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>说到雪，在美国上的第一年学里，班上只有我一个北方人。要下雪的时候大家都很兴奋。班主任讲了一下玩雪的事儿，说着「大家应该都是第一次看雪，除了一个人」，然后很酷地转身指向我。这一幕在我脑海里记了许久。</p><p>虽然名字里带个「雪」，但我不喜欢雪。见得多，铲得多，这东西还脏。</p><p></p></blockquote></blockquote></div><hr><div class="diary-entry">15:40 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115950827427383861" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/003/219/original/9825657b6c506ad8.webp" alt=":ottersgottaott21:" loading="lazy"> 最开始就应该全部写成 TypeScript。JavaScript 什么破玩意儿。</p><p></p></div><hr><div class="diary-entry">15:42 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115950837511838044" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>幸运狗把家里的网线啃断了 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/019/055/original/2421e8d631ebf3b8.png" alt=":ablobcry:" loading="lazy"> </p><p></p></div><hr><div class="diary-entry">22:46 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115952504550778999" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>零下八度…… 许久没受过这样的苦，还要专程出来请亲戚吃饭。往返两个小时的车程，碎碎念碎碎念。</p><p>第一次坐 S 号线，这个车怎么这么慢哦。</p><p>走前室友给我分享了她昨天知道的一个福州艺术家群体，她被邀请去参加他们举办的展览，虽然她连福建人都不是。</p><p></p></div><hr><div class="diary-entry">23:01 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115952561634283707" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>过去有考虑过写一下我来美国的这十年经历，但自己也只是个半入社会的小傻子，就算写也写不出来什么。如果当作自己十年来的记录的话，或许会很有意思。</p><p></p></div></details><details data-group="diary_sections"><summary>一月二十五日</summary><div class="diary-entry">01:44 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115953202863151922" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>还没有工作经验的 Web 开发可以考虑去找本地社区里的小企业或者小型机构推销自己，市场还可以。不过毕竟是小型机构，能开出的价不算大，甚至会出现只找免费工的情况，但是作为工作经验还是蛮不错的。</p><p>主要是这种机构的网站充斥着 AI 生成的图片和乱七八糟、没处理干净的网页模板，看着让我恼火。</p><p>Wellfound 这种只有 startup 的平台怎么说呢，有点诡异，上面总是只能刷到 AI startup，还有根本不需要高学历却非要的岗位（我还被刷了，靠）。其他 open position 现在这个环境基本上不用想…… 乖乖从 contractor 或者 intern 做起吧。</p><p></p><blockquote class="diary-thread-reply">01:46 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115953211832985815" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>找工作的期间我最好奇的是 Wordpress 的应用场景。感觉轻量的场景用它又笨又重，复杂的场景现在也不会想到它吧。</p><p></p></blockquote></div><hr><div class="diary-entry">03:43 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115953669753048268" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我是那种如果去吃火锅，好吃与否全部基于店家调制的酱料的人。</p><p>例如这家店的花生酱和芝麻酱就很难吃。</p><p>通常来说火锅店里只有花生酱的话，它是麻酱，且可能是二八酱。但如果同时出现了花生酱和芝麻酱，需要先确认一下两者的味道。其中会有一方是稀的，味道不发苦也不腻，那就多盛它。粘稠且苦腻的另一方放一点就好。最后夹一大堆香菜。</p><p>我也不知道为什么我能得出这样的结论…… 有时候在这里吃火锅会感觉时不时有店家搞混了花生酱和芝麻酱，气死了。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/953/649/956/247/004/original/1a493c18a7ce81a1.jpg" alt="一张特写照片，展示了餐厅自助调料台上的三个不锈钢酱料桶。从左到右依次盛放着浅黄色的花生酱、深褐色的芝麻酱和白色的豆腐乳。每个酱料桶上方都贴有白底黑字的中英文标签，分别标注为「花生酱 Peanut Sauce」、「芝麻酱 Sesame Sauce」和「豆腐乳 Fermented Beancurd」。  " loading="lazy"></figure></div><hr><div class="diary-entry">21:27 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115957855877263696" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/109/original/930c5953aba2153e.gif" alt=":ablobcatpnd_heart_happy:" loading="lazy"> 最近会去挑选一下相机，拍一些他人要用的照片。虽然对摄影一窍不通，但是只要努力学习的话就可以做到吧。</p><p>有时候这种过度乐观可能会毁了我自己……</p><p></p></div></details><details data-group="diary_sections"><summary> 一月二十六日</summary><div class="diary-entry">15:33 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115962124463525054" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前些天做了个梦…… 梦到自己终于被炒了，但是老板事后还在微信上说教我，说我吃相不好看意味着我本性贪。醒来后寻思自己吃相也不难看啊，都不会吧唧嘴。</p><p></p></div><hr><div class="diary-entry">16:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115962358334165159" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我的坐姿从小时候开始就很差，最近终于吃到苦果了。现在是乖乖把腿放到桌子下，不过借此发现椅子只有前端能坐，如果坐在正中间的位置的话脚就够不着地了。因为背无法倚着椅背，也不得不跟着立直了起来。</p><p>再就是写字时的坐姿。现在经常看到有人弯下腰去写字，脸几乎是贴在桌子上，这也是不好的习惯。虽然在家里我的坐姿很差，但在外面就会不知不觉坐端正，反而是教室里少数看上去很「高」的人。要保持身体离桌面一拳的距离、背挺直的好习惯呢。</p><p></p></div><hr><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 一月二十六日 15:33</span>            </div>            <div class="diary-quote-preview">前些天做了个梦…… 梦到自己终于被炒了，但是老板事后还在微信上说教我，说我吃相不好看意味着我本性贪。醒来后寻思自己吃相也不难看啊，都不会吧唧嘴。</div>          </div>21:26 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115963514659503261" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>今天刚说完这个梦，上课期间就被老板私信。我没做过的事情莫名其妙被安在我头上，我不仅差点背锅，还要被说教 —— 说真的，我觉得我什么都有在做了，你这些罪证不都是莫须有的吗。刚入店犯的错误也要拿出来说，你怎么不盘古开天辟地的时候开始数我做了啥。</p><p>就算误会解开了，也一点道歉都没有，我可是差点就被罚钱了哎？他像是为了弥补自己的错误一样，又把我说了一顿。唉，你开心就好。</p><p></p></div><hr><div class="diary-entry">21:47 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115963596003282815" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>第一次上大学的中文课。没想到教授说：</p><blockquote><p>大家都是资深的网民了。就算你有多么不赞同同学的观点，也不要对其进行人身攻击。</p></blockquote><p>因为是国外的中文课，所以难免会出现对国内而言敏感的话题么。我也好奇这节短篇小说课的受众都是什么样的人，有像我一样想要真的补充阅读量和进阶学习中文的同学吗。</p><p></p><blockquote class="diary-thread-reply">22:09 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115963681827481615" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>怎么会有人找到同学电话，然后要跑人家家里「继续讨论」啊 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/019/313/original/1679206d77bf4d95.png" alt=":bear_fright:" loading="lazy"> </p><p>每一条规则的背后都是血淋淋的事件……</p><p></p></blockquote></div><hr><div class="diary-entry">22:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115963772667040417" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我平日和新同学破冰：「我有小猫小狗小鱼小螺你要看吗。」</p><p></p></div><hr><div class="diary-entry">22:40 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115963805050331128" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>去年还是什么时候家里院子出现过宝宝负鼠。家里人不知道这是什么东西，还以为是掏垃圾的浣熊，所以给关进了不用的鸡笼子里……</p><p>纽约抓这东西当宠物养是犯法的，我们当天稍后便将其放归到大自然。数个月后我开车回家偶然在马路上看到成年的负鼠，我去，好大一只，感觉和一只猫差不多。</p><p>美国南方有食用负鼠的习俗，不清楚是要怎么做了吃。不过据说负鼠只能活两三年，唉。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/963/794/794/726/767/original/d29899200e8f2e53.jpeg" alt="一只年幼的北美负鼠在金属笼子里。​这只负鼠有着典型的白色面部、黑色的眼睛和粉红色的鼻子，耳朵边缘呈黑色。它正用前爪抓着笼子的金属条，后爪也攀附在上面，身体略微直立，视线直接看向镜头。笼子背景为浅色瓷砖地面，光线明亮。" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary>一月二十七日</summary><div class="diary-entry">16:56 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115968112478394086" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>帮朋友看看 Taxwise 这种报税软件为什么不能正常使用，然后意识到这一类软件里深藏的众多原罪。使用起来太复杂太难了！许多导向也是莫名其妙，牛头不对马嘴。比方说用户设置有误，导致发送报表时出现 Customer Disabled 问题，查看更多信息却被导向「用 SSN / TIN 搜索报表」的搜索页面。我想要的又不是这个吧！是 EFIN 设置错了？还是哪个设置错了？你倒是说呀！上网搜索居然什么都搜不出来。</p><p>Online 和 Desktop 是截然不同的两个产品。不清楚为什么，注册 Online 时给了一个不知道是谁的 EFIN，提交正确的 EFIN 后 Taxwise 给我们发了个注册码。但是，在邮件里根本不会说这个注册码是放在哪里输入的。我是应该去 Online 的哪个地方更换注册码吗？抱着这样的心情，最后发现这居然是 Desktop 的注册码，不过朋友是 MacOS 用户，安装不了 Desktop。最后是换了我的电脑操作，但是 Desktop 的操作逻辑又是另一码事，还需要自行安装州模块 —— 我根据说明书找了半天都没有找到安装州模块的入口。</p><p>不过那时已经凌晨了，只能作罢。不如让朋友继续使用 Online，早上的时候给 Taxwise 的客服打电话询问情况。不过据说 Taxwise 的客服态度也是不咋地…… 小时候给一堆公司的客服打过电话的我，事到如今也不指望哪家公司有态度好的客服了。</p><p></p></div><hr><div class="diary-entry"><div class="diary-quote-external">            <a class="diary-quote-link" href="https://m.otter.homes/@Cytrogen/115958977929715736" target="_blank" rel="noopener noreferrer">显示引用原文 ↗</a>          </div>19:52 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115968807465716256" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>借该演讲的内容，今天我在做一项个人小研究，主题是「最适用于『数字主权』这一概念的 VPS 提供商」。之前就没少想要整一台 VPS 然后部署东西玩，顺便学习运维和网络安全相关的知识（我在 DevSecOps 里只会了第一个啊！）。当然，也有看到 Mastodon 上的朋友们的 VPS 所以多多少少有些向往……</p><p>想要摸清楚哪家服务提供商最乐意把主权交给用户，就必须去阅读他们的法律条款，包括隐私条款等等。需要知道的是，服务器的所在地的意义并没有大家想的那么简单，即数据不在美国境内就没事了！</p><p>具体的内容待我做完研究、阅读条款们之后吧…… 希望可以在月底之前做完。不对，我不是还有作业要写吗？嗯…… 随便啦！</p><p></p></div></details><details data-group="diary_sections"><summary>一月二十八日</summary><div class="diary-entry">15:22 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115973405424320269" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>做了个梦，梦到全人类的影子要杀光人类，包括二次元角色的影子 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/019/055/original/2421e8d631ebf3b8.png" alt=":ablobcry:" loading="lazy"> 我和其他人被困在一栋房子里，外面被雪掩盖，雪上是一群正在搜寻人类的影子。上一世，全人类被影子团灭。这一世，我要拯救大家！然后我在提及影子的时候被狠狠嘲笑 —— 人类还是灭绝吧！</p><p>接着我带着地图跑出去，但不知道为什么，明明周围都是影子，他们却没有过来杀我。我又突然变成唐僧一样的角色，和一些可以沟通的影子要解开地图上的谜题。一下子，世界又变得和开发世界游戏一样，到处都是谜题。</p><p></p></div><hr><div class="diary-entry">18:25 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115974125707374582" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我已经非常成功地被自作聪明的管理层主观意识上认为是个不负责任、经常做错事情的人。在被安上这样莫须有的身份后，言论便立即充斥着先入为主的想法以及针对我的偏见。</p><p>因为他们说话已经没有正常人该有的逻辑性和严谨性，其他员工们想要合理讨论的欲望降至无。反正怎么说都是他们对，你作为员工只能受着。你要又是员工又没有他们想的做得那么好，你表达意见更是找死。</p><p></p></div></details><details data-group="diary_sections"><summary>一月二十九日</summary><div class="diary-entry">04:47 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115976573842447471" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>和室友出来吃快乐小羊。火锅这种东西呢，属于是好久没吃了的话就会很想吃，吃过后便会觉得「这辈子都不想要再吃了」。因为高估了我的食量，室友夹了许多牛百叶来，导致我们吃得太撑，已经到了闻到食物味道就会犯恶心的程度。</p><p>原本为了可以吃饱点，而不是吃得过腻反而没吃饱，我特意夹了水果沙拉来。结果这盘水果沙拉，成了餐桌上我印象最深刻的东西。怎么会这么好吃，苹果菠萝橘子，我最喜欢你们了。</p><p>酱料的话，比山城码头的好吃，只是指芝麻酱和花生酱。话说回来我火锅只会吃这两个酱料呢，怪不得腻。主食我没吃太多，只是吃了一点羊肉云吞，比想象中好吃。因为牛百叶，我连红薯宽粉都没有吃下去。这辈子再也不吃牛百叶了 —— 虽然几天后还是会买来吃吧。</p><p>都怪大胃王视频，室友看了后又是学他们走马，又是一吃饭就想吃很多。我叫她不要想了，米线这东西都没法续一碗的话，就不要学人家大胃王吃饭！</p><p></p></div><hr><div class="diary-entry">04:51 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115976587712865388" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>吃饭期间收到母亲发来的视频：不知道具体发生了什么，但是家里的芦丁鸡都被猫咬死…… 沙发也被猫挠破。母亲生气地打我电话，问我要把猫放归还是送走 —— 最开始把猫捡回家就应该好好想想这种事情吧。指甲也不愿意自己剪，非要我往返坐车三小时回来给猫剪指甲，还要怪我头上吗！</p><p>最好是考虑将猫送给一个负责任的人家，或者说我自己带着。不过合租的房子很小，并且室友已经有一只猫了…… 事情变得好麻烦。</p><p></p></div><hr><div class="diary-entry"><div class="diary-quote-context">            <div class="diary-quote-meta">              <span class="diary-quote-label">引 一月二十九日 04:47</span>            </div>            <div class="diary-quote-preview">和室友出来吃快乐小羊。火锅这种东西呢，属于是好久没吃了的话就会很想吃，吃过后便会觉得「这辈子都不想要再吃了」。因为高估了我的食量，室友夹了许多牛百叶来，导致我们…</div>          </div>16:09 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115979254508992734" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p><img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/019/055/original/2421e8d631ebf3b8.png" alt=":ablobcry:" loading="lazy"> 亲戚今天来纽约见我，又要请我吃火锅。我现在因为昨天的自助火锅吃太多，胃部好难受。千万不要暴饮暴食，尤其是突然吃太多东西，对身体一点都不好！</p><p></p></div></details><details data-group="diary_sections"><summary>一月三十日</summary><div class="diary-entry">01:31 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115981463651746905" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这次去的火锅店有着独特的香气。提早半小时来排队的我一边排队一边饿肚子…… 今天没怎么吃饭，应该先去面馆喝羊汤的，但是身上也没带现金 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/019/055/original/2421e8d631ebf3b8.png" alt=":ablobcry:" loading="lazy"> </p><p></p><blockquote class="diary-thread-reply">01:46 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115981522416254362" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>从火锅店的喧哗声中稍微可以听到赵雷的歌，开心一点点。</p><p></p></blockquote></div><hr><div class="diary-entry">01:56 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115981561319650204" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>虽然很羞耻，但是我对许多中国的常识一窍不通，例如我在去年之前一直以为东北是个省…… 实际上它是三个省合在一起的「东北地区」。怎么没有人告诉我呢！</p><p></p></div><hr><div class="diary-entry"><details class="diary-cw">        <summary class="diary-cw-warning">工作相关，带有负面情绪。</summary>        <div class="diary-cw-content">07:07 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115982783920388163" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>应该在睡前关闭所有通知的…… 好死不死拿起手机一看就是某些人莫名其妙的主观判断和基于此诞生的「压力」。不是你凌晨不睡觉专门跑过来压力我是干什么，现在不是工作时间、你坏我心情了知不知道。第二天我还要顶着压力做你的破工作，也不知道什么时候你又情绪大变骂来骂去。工资又低、干的事情又多，还要像个保姆一样接你们几个巨婴的情绪。</p><p></p></div>      </details></div><hr><div class="diary-entry">14:44 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115984581742300469" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>梦到自己回家，看到鱼缸的大家都跑了出来。我害怕它们死了，将它们一个个丢回鱼缸，它们却一个接着一个地爬出来。我在浴缸里装满冰水，又将它们丢了进去。这次它们都没有爬出来。不知道为什么，里面混进去了不知道是什么鱼的鱼，还有河豚。</p><p>然后我看到一本漫画，讲的是其中一个身患疾病的女主角，希望通过「魔法少女」来拯救自己。她有两个朋友帮助自己，其中一个被她任命为「魔法少女」，另一个则是军师一样的角色。总之，她们会在街上声称自己是魔法少女，且需要帮助。但这只是漫画主要时间线之前的事情。女主角的两位朋友离开了她，让她不得不去重新寻找新的「魔法少女」。</p><p></p></div><hr><div class="diary-entry">19:02 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115985594799260332" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>早上起来迷迷糊糊换衣服，像往常一样盯着白墙看 —— 嗯？怎么有个黑点？走近看看。喔～原来是ゴキブリ酱，一个人在这里很危险喔？可能会被某个双足行走的家伙儿拿着纸捏死喔？</p><p>其实我一直想练习徒手抓ゴキブリ酱，这样以后看到它就不用专门去抽纸了。转念一想，它和普通的虫子有什么区别呢？嗯、这种话题会不会太恶心一点……</p><p></p></div><hr><div class="diary-entry">23:04 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115986548163011095" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>怎么会！数据库课居然要求使用 Windows 系统！我才刚把笔记本刷成 EndeavourOS 没多久（一个月？）。</p><p>不知道为什么，手机和电脑都无法连上学校的网络，只能使用热点了。</p><p></p></div></details><details data-group="diary_sections"><summary>一月三十一日</summary><div class="diary-entry">02:21 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115987320794026417" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>去年在 TEMU 上买了个壁挂式浴室收纳架，今天才悠悠送到。整个包装像是别人退回去的，一张说明书都没有，安装流程画在了包装的背面，但是和实物长得很不一样，不知道什么东西该装在哪里。想要去查看产品详情页的时候，发现该产品已下架……</p><p></p></div><hr><div class="diary-entry">21:04 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115991739306031540" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>草莓好吃，草莓奶好喝，草莓奶茶好喝，草莓酸奶好喝。</p><p>蜜瓜难吃！蜜瓜奶好喝，蜜瓜奶茶好喝…… 嗯？</p><p>（以上均主观看法）</p><p></p></div></details></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;这个月里我做了很多在笔记本上的工作，所以在阅读文章上花费的时间跟精力都变少了很多。&lt;/p&gt;</summary>
    
    
    
    <category term="想法迭代" scheme="https://blog.cytrogen.icu/categories/%E6%83%B3%E6%B3%95%E8%BF%AD%E4%BB%A3/"/>
    
    
  </entry>
  
  <entry>
    <title>最能保障「数字主权」的 VPS 公司</title>
    <link href="https://blog.cytrogen.icu/posts/2590.html"/>
    <id>https://blog.cytrogen.icu/posts/2590.html</id>
    <published>2026-01-30T05:00:00.000Z</published>
    <updated>2026-02-24T05:58:57.367Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我观看了一场名为「后美国互联网」的 <a href="https://pluralistic.net/2026/01/01/39c3/">演讲</a>，实在是精彩，让我对「数字主权」这一概念有了更深刻的认知。借此，我发现我的许多服务依然部署在美国的 PaaS 服务上。这类中心化的服务如果出问题了会很麻烦，参考去年 Cloudflare 的事故。而我愈来愈对美国企业产生抵触之心。不过要我完全逃离是很难做到的，毕竟我人就在美国。这些原因结合在一起，促使我对「哪家提供 VPS（虚拟专用服务器）服务的公司最适用于数字主权者」这一命题感到好奇。</p><span id="more"></span><hr><p>首先我需要确立一个核心的排他性原则： <strong>任何受 <u>《美国爱国者法》</u> 和 <u>CLOUD Act</u> 管辖的实体必须被彻底剔除</strong>。</p><p>这不仅仅是因为数据隐私问题，更是管辖权层面的问题：CLOUD Act 赋予美国执法机构长臂管辖权，无论服务器物理位置在何处，只要控制着是美国企业，数据即被视为处于美国管辖之下。因此，AWS、Google Cloud、DigitalOcean、Vultr 等主流厂商在第一轮筛选中即宣告出局。</p><p>为了让后续对其他厂商的筛选带有令人信服的法理依据，我打算剖析美国法律体系来确立负面清单的标准。这也是为了还没有怎么接触过「数字主权」一概念的读者们可以更明白为什么我的选择是这个、为什么是哪个。</p><p>在 2018 年之前，微软曾经以「数据不存储在美国境内」为由， <a href="https://en.wikipedia.org/wiki/Microsoft_Corp._v._United_States">拒绝向美国政府移交存储在爱尔兰的数据</a>。这时候，大家都普遍认为数据存储在美国境外可以规避美国的搜查令。然而 CLOUD Act 的签署彻底摧毁了这一避风港。该法案确立了一个核心原则，即 <strong>数据的管辖权不再取决于数据的物理存储位置，而取决于数据控制者的注册地</strong>。</p><p>这意味着，只要一家公司是在美国注册的实体，或者该公司在美国有业务运营，无论它将你的数据存储在东京、伦敦还是南极，美国执法机构都有权要求其移交数据。</p><p>对于大多数人而言，这是一个巨大的认知误区 —— 许多人误以为选择了 AWS 的德国区就受到了 <u>GDPR</u> 的绝对保护。</p><p>为了防止有读者不理解这些术语，我将在本篇以「问为什么之前先问是不是」这一形式来构建完整的因果链条。</p><p>GDPR（General Data Protection Regulation，通用资料保护规则）是欧盟于 2018 年生效的一项法律法规，被公认为全球史上最严厉、最全面的隐私保护法。它的核心宗旨是让公民重新掌控自己的个人数据。GDPR 规定了数据控制者必须如何收集、存储和处理数据，并赋予了用户一系列强大的权利，例如 <u>被遗忘权</u> 和 <u>数据可携带权</u>。德国作为欧盟的核心成员国，自然完全受 GDPR 管辖。</p><p>事实是，由于 AWS 是美国公司，当美国法律与欧盟法律冲突时，AWS 必须优先响应母国的要求，否则将面临本土的巨额罚款或制裁。因此，对于美国主流厂商而言，物理位置的隔离在法律层面是无效的。</p><p>CLOUD Act 针对刑事调查也就算了， <u>FISA Section 702</u> 还针对大规模的国家安全情报收集。FISA（Foreign Intelligent Surveillance Act，外国情报监视法）是美国于 1978 年颁布的一项联邦法律。它的初衷是为了规范美国政府在进行针对外国势力和外国代理人的情报收集时的行为。在早期，如果美国情报机构想要监听境内的通讯，必须经过一个秘密法庭的批准。这在当时是为了防止政府滥用权力。而 FISA Section 702 是该法案在 2008 年增加的一个修正案，允许美国情报机构在无需获得任何具体法院搜查令的情况下，直接对位于美国境外的非美国公民进行大规模监控。</p><p>这是 <u>PRISM</u> （棱镜计划） 的法律基础。NSA（国家安全局）基于 Section 702 法律授权实施了这个大规模电子监听项目。2013 年该项目被 Edward Snowden 曝光。根据 Snowden 披露的文件，PRISM 允许 NSA 直接接入美国互联网巨头的中心服务器。</p><p>当你使用美国厂商的服务时，从法律层面讲，你已经默认放弃了对抗美国情报机构窥探的权利。更为不幸的是，这类提取往往伴随着严格的保密指令，服务商不仅必须配合，而且被法律禁止告知用户数据已被查看。这种不透明性使得用户根本无法知晓自己的主权何时被侵犯。</p><p>抛开国家层面的法律，仅从商业合同来看，美国主流厂商的条款也充满了对用户主权的剥夺。最典型的陷阱在于 <u>单方面终止权</u>。如果仔细阅读 AWS 或者 Google Cloud 的条款，你会发现它们通常包含类似「我们保留在任何时间、出于任何原因（或无须理由）终止服务或拒绝访问的权利」的表述。这种条款赋予了企业凌驾于用户之上的绝对权力。即使你的内容完全合法，只要触发了其自动风控算法，或者你的内容不符合其模糊的社会准则（注意，并非法律），你的账号及其中的所有数据可能在瞬间被封锁，且往往没有申诉通道。</p><p>此外，关于 <u>可接受使用策略</u>，美国厂商通常会加入极其模糊的道德审查标准，例如禁止「令人反感的内容」。这是一个极其危险的口袋条款，因为「反感」是一个主观的感觉，它的解释权完全掌握在公司手中，而非由法院裁定。</p><p>说了这么多，理解起来可能依然很困难。作为实操案例，我分析和解读一下 <a href="https://aws.amazon.com/privacy/">AWS 的隐私条款</a>。</p><p>AWS 将数据严格划分为两类：个人信息和上传到服务器的数据。前者受这份隐私条款管辖；对于后者，AWS 则在法律上认定自己只是处理者、用户才是控制者。因此，关于如何收集、使用、分享的条款统统不适用于用户服务器里的文件。如果数据被泄露，或者被 AWS 删除，都和这份隐私政策无关，需要去查阅其他条款和协议（内容太多暂且不做）。</p><p>AWS 都会拿我们的个人信息做什么呢？除了和改进 AWS 内部的产品有关外，就是推广推广推广 —— 推广自己的产品，也会推广其他公司的产品，简称「打广告」。证据例如：</p><blockquote><p>We use your personal information to market, advertise, and promote AWS Offerings.</p><p>我们使用您的个人信息来营销、宣传和推广 AWS 产品。</p></blockquote><p>法律相关的表述中，AWS 这么说道：</p><blockquote><p>In certain cases, we have a legal obligation to collect, use, or retain your personal information. For example, we collect bank account information from AWS Marketplace sellers for identity verification.</p><p>在某些情况下，我们负有法律义务收集、使用或保留您的个人信息。例如，我们会收集 AWS Marketplace 卖家银行账户信息以进行身份验证。</p></blockquote><p>这是很常见的陷阱表达： <em>in certain cases</em>，什么 certain case？「某些情况」是哪些情况？在没有明确说明的情况下，这个「某些情况」是完全受 AWS 主观判断而决定的。同样的表达也可以见：</p><blockquote><p>We release account and other personal information when we believe release is appropriate to comply with the law, enforce or apply our terms and other agreements, or protect the rights, property, or security of AWS, our customers, or others. This includes exchanging information with other companies and organizations for fraud prevention and detection and credit risk reduction.</p><p>当我们在认为公开信息有助于遵守法律、执行或应用我们的条款及其他协议，或保护 AWS、我们的客户或其他人的权利、财产或安全时，我们会公开账户和其他个人信息。这包括与公司及组织交换信息，以进行欺诈预防和检测以及信用风险降低。</p></blockquote><p><em>When we believe</em> 、 <em>comply with the law</em> 是一个又一个的陷阱。只需要 AWS 内部的法务团队认为合适，他们就可以移交数据，将 <u>司法裁定权</u> 私有化。</p><p>没有国界限制的「法律适用」也是危险的。对于美国而言，这默认包含美国法律。这意味着为了遵守美国法律，他们可以出卖非美国用户的数据。</p><p>先前我说过，数据实际在什么位置根本不重要，这里 AWS 就给了我们一个很好的例子：</p><blockquote><p>We share personal information only as described below and with <a href="http://Amazon.com">Amazon.com</a>, Inc. and the affiliates that <a href="http://Amazon.com">Amazon.com</a>, Inc. controls that are either subject to this Privacy Notice or follow practices at least protective as those described in this Privacy Notice.</p><p>我们仅按照下述方式分享个人信息，并与亚马逊公司（<a href="http://Amazon.com">Amazon.com</a>, Inc.）及其控制的附属公司分享。这些附属公司要么受本隐私声明的约束，要么遵循与本隐私声明中描述的实践至少具有同等保护性的实践。</p></blockquote><p>AWS 承认了数据会被合法流向 <a href="http://Amazon.com">Amazon.com</a>，即美国母公司，或者其他附属公司。只要在这个链条中有一个实体受美国管辖 —— 显然母公司受管辖 —— 整个数据池就受管辖。无论你是在 AWS 的哪个分公司注册，结果都是如此。</p><p>还有一点是 AWS 并不独立完成所有工作，它依赖一个庞大的第三方供应商网络。即使 AWS 发誓不看我们的数据，但它还是把我们的数据交给了第三方。根据 <u>短板效应</u>，美国执法机构也不用找 AWS，只要找下游供应商就好了。你的安全程度取决于整套供应链中最弱的一环。</p><blockquote><p>We employ other companies and individuals to perform functions on our behalf. Examples include: delivering AWS hardware, sending communications, processing payments, assessing credit and compliance risks, analyzing data, providing marketing and sales assistance (including advertising and event management), conducting customer relationship management, and providing training. These third-party service providers have access to personal information needed to perform their functions, but may not use it for other purposes. Further, they must process that information in accordance with this Privacy Notice and as permitted by applicable data protection law.</p><p>我们聘请其他公司和个人代表我们执行职能。例如：交付 AWS 硬件、发送通信、处理付款、评估信用和合规风险、分析数据、提供营销和销售支持（包括广告和活动管理）、进行客户关系管理以及提供培训。这些第三方服务提供商可以访问其履行职能所需的个人信息，但不得将其用于其他目的。此外，他们必须根据本隐私声明以及适用数据保护法的规定处理这些信息。</p></blockquote><p>注意，这里的「不得将其用于其他目的」仅是用于合同约束。只要数据流出，对用户来说就一定存在着潜在风险。这段话对 AWS 来说更多是免责说明。并且最后的「适用数据保护法」依然表明了美国政府可以向下游供应商索要数据。</p><p>尽管 AWS 开头就说：</p><blockquote><p>Information about our customers is an important part of our business and we are not in the business of selling our customers』personal information to others.</p><p>关于我们客户的信息是我们业务的重要组成部分，我们不从事将客户的个人信息出售给他人。</p></blockquote><p>但它也没说自己不共享用户数据啊。这是一个相当经典的商业诡辩：无论是「卖」还是「共享」，对于用户而言自己的数据就是被脱离出了原本的隔壁环境，进入了不可控的第三方手中。</p><p>一个有意思的题外话：韩国拥有全球最严格、最注重形式主义细节的数据保护法 <u>PIPA</u> （Personal Information Protection Act，个人信息保护法）。第 17 条里表示：</p><blockquote><p>(2) A personal information controller shall inform a data subject of the following matters when it obtains<br>the consent under paragraph (1) 1. The same shall apply when any of the following is modified:</p><ol><li>The recipient of personal information;</li><li>The purpose for which the recipient of personal information uses such information;</li><li>Particulars of personal information to be provided;</li><li>The period during which the recipient retains and uses personal information;</li><li>The fact that the data subject is entitled to deny consent, and disadvantages, if any, resulting from the<br>denial of consent.</li></ol><p>(2）个人信息处理者在依据第（1）款第 1 项取得同意时，应当向信息主体告知下列事项；下列事项发生变更时，亦同：</p><ol><li>个人信息的接收方；</li><li>个人信息接收方使用该信息的目的；</li><li>拟提供的个人信息具体项目；</li><li>接收方保有及使用个人信息的期间；</li><li>信息主体有权拒绝同意的事实，以及因拒绝同意而产生的不利后果（如有）。</li></ol></blockquote><blockquote><p>(3)……obtain the consent from the data subject in order to provide personal information to a third party overseas……</p><p>(3)…… 为了向海外第三方提供个人信息…… 应获得数据主体的同意……</p></blockquote><p>这导致 AWS 在对韩国的额外说明里，揭露了其全球运营的真实后台架构。实际使用的第三方服务商名单见隐私条款内的 <em> South Korea</em> 区域。</p><p>虽然这份名单名义上只针对韩国，但云服务商的后台架构通常是全球统一的。AWS 不太可能专门为韩国搭建一套独立的 Salesforce 或 Marketo 系统，也不太可能只在韩国使用 Paymentech，而在其他地区完全自研。因此，我合理推断这份名单实际上就是 AWS 在全球范围内通用的第三方供应商名单。</p><p>这样我们就能得知：</p><ul><li>AWS 的客户关系管理直接被托管在 Salesforce 的美国服务器上；</li><li>哪怕用本地信用卡支付，结算的底层通道和记录依然与美国的金融系统紧密相连，因为 Paymentech（JPMorgan Chase）的地址为美国，而根据《美国爱国者法》金融数据是重点监控对象；</li><li>表格中明确列出传输的项目包括「必要时通过信息网络传输数据」，意味着只要业务需要，数据就会跨境流动，完全无视物理距离。</li></ul><p>现在大致地阅读了 AWS 的隐私条款后，我认为作为读者的你多多少少也应该明白什么样的话是陷阱了。用同样的规则去阅读其他公司的隐私条款，很容易就可以觉察出各种不对劲。</p><p>我将「数字主权」定义为：用户对存储的数据拥有排他性的控制权，且该控制权仅受服务器物理所在地的当地法律约束，不受第三方国家的长臂管辖干扰。</p><p>自然，你喜欢哪一类都没有对错之分。我希望我的研究是可以帮助你找到理想中的那个「它」，而不是让你感觉你是否选错了公司。</p><p>我将从隐私政策、服务条款以及公司注册地与物理设施管辖权三个维度进行解构。不过这些并非所有提供 VPS 的服务商，只是出于篇幅，暂时只看了这些公司的文档。</p><h4 id="1984-hosting"><a class="markdownIt-Anchor" href="#1984-hosting"></a> 1984 Hosting</h4><p>1984 Hosting 通常被视为「数字主权」界的标杆，但如果仔细阅读它的 <a href="https://1984.hosting/tos/">Terms of Service</a>，会发现它并非像某些人想象的那样是一个无法无天的法外之地。相反，它确实提供了极高的国家级防御，但在操作界面和道德条款上埋下了不少陷阱。</p><p>条款里相比于 AWS 模糊的「适用法律」，1984 Hosting 明确指定了冰岛法律。</p><blockquote><p>These Terms are governed by Icelandic law. Disputes arising from these Terms shall be brought before the Reykjavík District Court.</p><p>本条款受冰岛法律管辖。由此条款引起的争议应提交给雷克雅未克地方法院。</p></blockquote><p>美国政府想要获取服务器内的数据的话必须通过 <u>MLAT</u> 让雷克雅未克地方法院认可并签发本地搜查令。MLAT（Mutual legal assitance treaty，相互法律援助条约）是两个国家之间签署的一种双边协议，用于在刑事调查中交换证据和信息。虽然 CLOUD Act 声称对美国公司拥有全球管辖权，但是 1984 Hosting 是一家纯粹的冰岛公司，和美国没有一点关系。因此美国想要数据，只能请求冰岛政府协助。</p><p>而冰岛法律拥有 <u>IMMI</u>，要让冰岛法官签发针对媒体或言论的搜查令，难度极高。IMMI（Icelandic Modern Media Initiative）是冰岛协会在 2010 年一致通过的一项决议，其目的是将冰岛打造为全球新闻自由和言论自由的避风港。根据 MLAT 中的 <u>双重犯罪原则</u>，如果美国的指控在冰岛法律下被视为受保护的言论自由而非犯罪，冰岛法院将拒绝签发搜查令。</p><p>说了优点，现在来说说缺点。很多追求「数字主权」的用户误以为 1984 Hosting 等于匿名抗审查，但它其实会明确记录用户的真实姓名和电话号码。</p><blockquote><p>When a service agreement is concluded between the Subscriber and 1984 ehf., the following information from the Subscriber will be recorded: (1) the Subscriber's name; (2) the Subscriber's active e-mail address; (3) any user name selected by the Subscriber; (4) the Subscriber's password(s); (5) the Subscriber's active telephone number; and (6) payment details, i.e. address, means of payment, etc., in accordance with the laws on the handling of such information and 7) PIN number selected by customer</p><p>当订户与 1984 ehf. 订立服务协议时，将记录下列来自订户的信息：(1）订户的姓名；(2）订户的有效电子邮件地址；(3）订户选择的任何用户名；(4）订户的密码；(5）订户的有效电话号码；(6）支付详情，即地址、支付方式等（依照处理此类信息的相关法律规定）；以及（7）客户选择的 PIN 码。</p></blockquote><p>如果试图提供虚假信息，你便违反了保证条款，他们有权关停服务：</p><blockquote><p>In addition, the Subscriber represents and warrants that all information provided by the Subscriber to 1984 ehf. is accurate, complete and current upon renewal and registration of services. The Subscriber represents and warrants that the Subscriber will inform 1984 ehf. of any changes to such information so as to ensure that 1984 ehf. always has accurate, complete and current information.</p><p>此外，订户陈述并保证，其向 1984 ehf. 提供的所有信息在服务续约和注册时均准确、完整且为最新版本。订户陈述并保证将通知 1984 ehf. 此类信息的任何变更，以确保 1984 ehf. 始终掌握准确、完整且最新的信息。</p></blockquote><p>虽然 1984 Hosting 标榜言论自由，但他们同样保留了极大的主观裁量权。根据 Sec 8.02，他们禁止「任何 1984 ehf. 认为是非法、有害或在道德上令人反感的材料」。</p><blockquote><p>Offering, selling or showing, or providing links to other websites offering, selling or showing the following is prohibited: (a) habit-forming or narcotic substances or related services; (b) weapons; (c) copyrighted materials that the Subscriber is not entitled to offer or sell; (d) information used to violate the copyrights or trademarks of others; (e) information used to manufacture, make or provide illegal goods or weapons; (f) pornography or sexual products; (g) file sharing; (h) pharmaceuticals; (i) any materials or information that are, in the opinion of 1984 ehf., illegal, harmful or ethically objectionable.</p><p>禁止提供、销售或展示下列内容，亦禁止提供链接指向提供、销售或展示下列内容的其他网站：(a）成瘾性物质、麻醉药品或相关服务；(b）武器；(c）订户无权提供或销售的受版权保护的材料；(d）用于侵犯他人版权或商标的信息；(e）用于制造、制作或提供非法物品或武器的信息；(f）色情内容或性产品；(g）文件共享；(h）医药产品；(i）任何经 1984 ehf. 认定为非法、有害或在道德上令人反感的材料或信息。</p></blockquote><p>冰岛法律对色情内容有严格限制，所以做成人内容或者边缘内容的用户会被直接 pass 掉。而「道德上令人反感」是一个口袋条款。什么是「道德上反感」？解释权完全归 1984 Hosting 所有，这与「绝对的言论自由」是有出入的。</p><p>1984 Hosting 也和 AWS 一样，给自己预留了完全的决定权 —— 只要他们认为你的材料有害，就可以不需要经过法院审判而直接停止向用户提供服务（见 Sec 8.04）。</p><p>一个较为恶趣味的设计是，如果想要退订 1984 Hosting 的服务的话，必须在订阅到期的 16 天前向他们发送电子邮件（见 Sec 2.04）。</p><p>基于上述分析，1984 Hosting 的「数字主权」建立在冰岛法律之上，而不是建立在 <u>无政府主义</u> 之上。如果你的内容对美国而言是有问题，但在冰岛没问题的话，可以尝试一下 1984 Hosting。</p><p>在价格方面，一个 1 GB RAM、单 CPU、25 GB 硬盘内存的 VPS 是每月 7.6 欧元，折合 9 美元，或者说 63 人民币。</p><h4 id="orangewebsite"><a class="markdownIt-Anchor" href="#orangewebsite"></a> OrangeWebsite</h4><p>OrangeWebsite 很喜欢强调自己「在冰岛」这一身份。那么它的 <a href="https://orangewebsite.com/docs/privacy-policy.php">隐私条款</a> 可以证明它够「冰岛」么？</p><blockquote><p>We do not disclose any personal information obtained about you from this website to third parties. We may use the information to keep in contact with you and inform you of developments associated with our business. We do not release any information to foreign authorities or agencies. We only release any personal data or any data saved on our servers with valid Icelandic court order or similar order from Icelandic authorities if it's not stated otherwise in this document.</p><p>We disclose the necessary personal data with 3rd party service providers, such as domain registrars and SSL-certificate registrars. Our client will be however informed about this before disclosure.</p><p>我们不会向第三方披露我们从本网站获取的您的任何个人信息。我们可能会使用这些信息与您保持联系，并向您告知与我们业务相关的最新动态。我们不会向外国当局或机构披露任何信息。除非本文档另有规定，否则我们仅凭有效的冰岛法院命令或冰岛当局的类似命令才会披露任何个人数据或保存在我们服务器上的任何数据。</p><p>我们向第三方服务提供商披露必要个人数据，例如域名注册商和 SSL 证书注册商。但是，我们的客户将在披露前被告知此事。</p></blockquote><p>可以看出，OrangeWebsite 明确表示其法律根基完全扎根于冰岛，受到全球最严格隐私法之一的保护。</p><p>有意思的是，如果任何第三方就客户的个人详细信息联系 OrangeWebsite，他们会保留通知客户此类行动的权利。要知道，大多数美国服务商会受到禁言令的限制，被迫在秘密中移交数据且禁止通知用户。能把通知用户的权利写进隐私政策，很是豪爽喔。</p><p>虽然在法律防御上很强硬，但在数据收集层面上，这份文档显示他们依然遵循传统的商业 ISP 模式。OrangeWebsite 会收集完整的计费信息字段，虽然没说必须验证真伪，但也没说使用假的也可以。</p><p>文档也承认 <code>orangewebsite.com</code> 上使用了自动化营销工具收集数据，但强调在 <code>secure.orangewebsite.com</code> 上不收集。意味着他们会追踪访客的营销数据，但是不会监控已登录用户的后台操作。</p><p>支付方面，文档并没有提及加密货币。如果只支持信用卡和 PayPal 的话，那么资金流向就是实名的。这一点需要阅读其他文档来确认。</p><p>要知道更多，必须去阅读 <a href="https://orangewebsite.com/docs/tos.php">Terms of Service</a>。里面提到，OrangeWebsite 虽然支持加密货币支付，但是是用的是 BitPay 和 CoinPayments。前者是业界最著名的合约狂魔，在许多情况下会强制要求付款人上传护照照片进行 KYC，否则拒绝处理交易 —— 加密了个寂寞！如果付钱给 OrangeWebsite，你便有可能必须把护照交给美国公司。后者 CoinPayments 相对宽松点，但依然是第三方。</p><p>至于能否提供假的个人信息，答案是「否」，只是没有强制验证而已。平时是没人管，但要是出问题被发现了，他们可以以此为由封锁用户账号，且不退款。</p><p>合法的成人内容在冰岛通常是被允许的，OrangeWebsite 的条款没有明确禁止合法成人内容，只提及了儿童色情。这一点依然需要进一步确认。</p><p>文档中也没有提及到 Tor。在主机行业，未明确允许即默认为高风险。结合 Sec 3.3，运行 Tor 出口节点极易被判定为扫描或滥用。建议默认其不支持 Tor 出口节点，除非咨询客服获得书面许可。</p><p>一些有趣的点：没买防御却被打，想临时加防御的话需要先交 200 欧元罚款；除非用户授权，否则 OrangeWebsite 是不会碰服务器的，包括维护系统时。</p><h4 id="flokinet"><a class="markdownIt-Anchor" href="#flokinet"></a> FlokiNET</h4><p>阅读了一些隐私条款后，FlokiNET 的 <a href="https://flokinet.is/privacy-policy">隐私条款</a> 中的一些内容我想只要看到就能发现陷阱。</p><p>例如：</p><blockquote><p>FlokiNET considers any information that can be used to directly or indirectly identify you to be Personal Data, including, without limitation, Personal Data that is accessed, collected, maintained, transmitted and/or used by FlokiNET in the normal course of our business and is subject to the provisions of this Privacy Policy and applicable law.</p><p>FlokiNET 将任何可用于直接或间接识别您的信息视为个人数据，包括但不限于 FlokiNET 在正常业务过程中访问、收集、维护、传输和 / 或使用的个人数据，并且该等数据受本隐私政策和适用法律的约束。</p></blockquote><blockquote><p>FlokiNET will ensure that appropriate security measures are in place and that confidentiality is maintained to protect your personal information in accordance with applicable laws and regulations.</p><p>FlokiNET 将确保采取适当的安全措施并保持机密性，以根据适用法律法规保护您的个人信息。</p></blockquote><blockquote><p>If you breach the Terms of Service or any other applicable service level agreement, or if FlokiNET is required to disclose or share your personal data in order to comply with any legal obligation, FlokiNET may disclose your information to a relevant authority. In particular, FlokiNET may disclose the information it collects to third parties if FlokiNET believes that disclosure is appropriate to comply with the law, to enforce its legal rights, or to protect the rights or safety of others.</p><p>如果您违反服务条款或任何其他适用的服务级别协议，或者 FlokiNET 为遵守任何法律义务而被要求披露或共享您的个人数据，FlokiNET 可以向相关部门披露您的信息。特别是，如果 FlokiNET 认为披露信息有助于遵守法律、执行其合法权利或保护他人权利或安全，FlokiNET 可以向第三方披露其收集的信息。</p></blockquote><p>等等等等（提示：「适用」！）。</p><p>那我们只来看一些有趣的地方：</p><blockquote><p>Customer data (data stored on the server) is stored in accordance with applicable law and requires a court order from the country in which it is stored in order to be disclosed.</p><p>客户数据（存储在服务器上的数据）的存储须符合适用法律，且披露该数据需要获得数据存储所在国家的法院命令。</p></blockquote><p>后半句很关键，因为它明确了数据主权随物理位置而定。如果用户的服务器选在冰岛，FlokiNET 就只认冰岛法院的命令；选在罗马尼亚，只认罗马尼亚法院的命令。这意味着 <strong>用户必须明智地选择数据中心位置</strong>。这一点往往会被忽略，以为只要是 FlokiNET 就全都一样安全。</p><p>言论自由主机从来都不等同于匿名主机，FlokiNET 就是一个例子。它会收集用户的信息，且不单单指代用户的注册信息，还有访客的指纹。</p><p>FlokiNET 还会存储账单记录足足七年，就算是比特币交易哈希也会被存储：</p><blockquote><p>You may cancel your account at any time and request that your personal information be deleted from our databases, except for any accounting records of purchases, which we are required by law to retain for 7 years, network access logs, which we may retain for any period of time at our discretion, in cases where there are outstanding financial obligations or in cases where illegal activity is suspected (as determined by FlokiNET management or law enforcement officials), in which case personal information may be retained indefinitely for the purposes of ongoing investigation and prevention of recurrence of fraud, or in cases where a breach of the Terms and Conditions and applicable Service Level Agreement has resulted in the termination of your account (as defined by revocation of your permission to use FlokiNET's services), in which case personal information may be retained indefinitely for the purposes of preventing further use of FlokiNET's services by the offending individual.</p><p>您可以随时取消您的账户，并要求从我们的数据库中删除您的个人信息，但出于会计记录的购买记录除外，根据法律规定，我们必须保留 7 年；网络访问日志，我们可以自行决定在任何时期保留，在存在未偿还的财务义务的情况下，或在怀疑存在非法活动的情况下（由 FlokiNET 管理层或执法官员确定），在这种情况下，个人信息可能会被无限期保留，以用于正在进行的调查和防止欺诈再次发生；或在违反了服务条款和适用的服务级别协议导致您的账户被终止的情况下（定义为撤销您使用 FlokiNET 服务的权限），在这种情况下，个人信息可能会被无限期保留，以防止违规个人进一步使用 FlokiNET 的服务。</p></blockquote><p>「自行决定」是法律上的流氓条款。FlokiNET 明确表示他们会留日志，而且想留多久留多久。这通常是为了应对执法部门的溯源要求。</p><p>FlokiNET 也会无限期保留违规的用户信息。注意，这里的「违规」也包括「怀疑存在违规行为」这一主观想法。无限期保留的缺陷便是你无法通过注销账号来行使被遗忘权。</p><p>关于支付，FlokiNET 使用的是第三方支付，这包含了面向智利或全球的 Paygol、面向冰岛的 Borgun（现更名为 SaltPay），以及面向冰岛国家银行的 Landsbankinn。这三家都是受严格金融监管的实体，必定遵守 <u>AML</u> （Anti-money Laundering，反洗钱）规定，将数据直通给政府。</p><p>说到 AML，就必须说到该法规强制要求机构们执行的两个关键动作：</p><ol><li>KYC（Know Your Customer，了解你的客户）：必须验证付款人的真实身份；</li><li>SAR（Suspicious Activity Reports，可疑活动报告）：必须监控交易流向。</li></ol><p>凡是提及遵守 AML / KYC 的支付方式，都等同于实名支付。而在 AML 框架下的金融数据，隐私保护等级极低。只要执法机构以调查洗钱或资助恐怖主义为由调取数据，这些支付机构不仅必须配合，而且往往设有专门的自动化接口来对接政府查询。</p><p>因此， <strong>在金融世界里，不存在法外之地的支付通道</strong>，尤其是涉及到信用卡和银行转账（再尤其是 Visa 和 Mastercard 的授权收单机构）时。</p><p>FlokiNET 目前提供四个区：罗马尼亚、冰岛、荷兰以及芬兰（未来会提供新加坡）。这四个区的价格各不相同，但单核、1 GB RAM、20 GB 硬盘空间的 VPS 大致在每月 7.99 到 10.99 欧元之间，折合 9.5 到 13 美元，或者 66.5 到 91.5 人民币。</p><h4 id="njalla"><a class="markdownIt-Anchor" href="#njalla"></a> Njalla</h4><p>Njalla 的 <a href="https://njal.la/tos/">条款</a> 是「数字主权」领域中最激进的条款之一，得利于它的法律隔离层。不同于传统服务商试图平衡合规与隐私，Njalla 采用了一种替代所有权的模式来规避管辖。</p><p>首先 Njalla 的运营实体位于尼维斯，是加勒比海的一个小岛，也是著名的离岸避税天堂和隐私堡垒。尼维斯法律对公司信息的保密性极高，且不执行美国或欧盟的民事判决。这意味着版权流氓想要起诉 Njalla 索要用户数据几乎是不可能的，因为当地法院根本不承认这些外国的民事诉求。</p><p>不过条款中并未披露服务器的物理位置。虽然公司在尼维斯，但服务器可能位于瑞典、芬兰或其他欧洲国家。根据 <u>属地管辖权</u>，服务器所在地的执法机构依然有权直接扣押物理服务器。Njalla 的防御仅限于法律文书层面，而非物理设施层面。</p><p>其次 Njalla 不需要用户实名制，甚至都不需要邮箱，仅需一个 XMPP（一种去中心化的即时通讯协议）地址即可注册。</p><p>在 Sec 6.4 中，Njalla 还嘲讽了 GDPR，认为真正的隐私并非「合规地处理数据」，而是「根本不收集数据」。这种态度表明他们不会主动配合常规的数据保留指令。</p><p>较为有争议性的是 Sec 3.3。在 WHOIS 数据库和法律层面，域名或服务器的所有者是 Njalla，而非用户。好处是这实现了完美的隐私，因为在公网记录里你根本不存在，没人能查到你的名字；坏处是如果 Njalla 跑路、倒闭或者恶意侵占，你在法律上很难证明这个资产是你的。</p><p>说完优点来说缺点。Njalla 的条款内有一些陷阱：在 Sec 9.2 中，他们也使用了「任何适用法律」这样的词汇，且没有限定是尼维斯法律。如果服务器位于瑞典，瑞典警方的要求也属于适用法律。</p><blockquote><p>needed to comply with any applicable laws, government rules, requests of law enforcement, court orders or public authorities;<br>it is in compliance with any dispute resolution process;<br>to avoid any potential civil or criminal liability; or<br>your use of the Services in any other way incurs damage on the Services or Njalla or entails a risk thereof.</p><p>需要遵守任何适用的法律、政府规定、执法部门的要求、法院命令或公共当局的要求；<br>符合任何争议解决程序；<br>为避免任何潜在的民事或刑事责任；或<br>您以其他任何方式使用本服务均会对本服务或 Njalla 造成损害或带来风险。</p></blockquote><p>「执法请求」一词意味着仅仅是警方的请求就足以让 Njalla 关停你的服务。以及绝对免责条款：只要 Njalla 觉得你的存在可能让他们惹上官司，他们就可以先下手为强把你关了。尽管他们由海盗湾创始人建立，但他们并不打算为了你而在法庭上死磕。</p><p>Njalla 并不是一个传统的 VPS 服务商，它更像是个匿名代理中介。如果你是极度需要隐藏身份的用户，且主要受来自民事诉讼或非国家级的骚扰的话，可以尝试一下 Njalla。</p><p>在价格方面，Njalla 一个单核、1.5 GB RAM、15 GB 硬盘空间、1.5 TB 流量的 VPS 每个月是 15 欧元，折合近 18 美元，或者说近 125 人民币。</p><h4 id="privex"><a class="markdownIt-Anchor" href="#privex"></a> Privex</h4><p>Privex 的 <a href="https://www.privex.io/privacy/">隐私条款</a> 很是简短，因为它实行了 <u>数据极简主义</u> —— 如果根本不收集数据，那就不需要写几千字来说明你如何处理数据。</p><p>不过虽然看起来很美，但依然存在需要警惕的盲区。</p><p>阅读隐私条款时最可怕的并不是它写了什么，而是它没写什么。Privex 的隐私条款就完全没有提及它的注册实体在哪里，也没有提及适用的法律管辖区。这就带来了一个巨大的法律不确定性。如果 Privex 注册在五眼联盟国家，那这份隐私条款在 <u>国家安全信函</u> 面前就是废纸一张。</p><p>然而文档中有一句话极其耐人寻味，暴露了他们的威胁模型：</p><blockquote><p>We hold all database data on our own database cluster, with full disk encryption on all database nodes, protecting your data in the event of our database servers being seized.</p><p>我们将所有数据库数据保存在我们自己的数据库集群中，并在所有数据库节点上进行全盘加密，以保护您数据在我们的数据库服务器被扣押的情况下。</p></blockquote><p>绝大多数主流厂商的条款只会讨论数据泄露或合规，而 Privex 罕见地预设了服务器被执法部门物理扣押的情况，这说明他们的防御对象直接设定为了国家强力部门。</p><p>在隐私方面上，Privex 做得相当不错：允许用户使用假名，也不会记录用户的 IP 地址。配合加密货币支付，理论上可以实现 100% 的链上链下身份隔离。再加上 Privex 不使用第三方服务：不使用 Cloudflare、不使用 AWS RDS、自建支付网关。先前我在 AWS 的条款分析中提到，数据泄露往往发生在第三方供应商。</p><p>现在来说「陷阱」。Privex 会收集用户使用服务器的目的。一个不需要实名、不记录 IP 的服务商，为什么要问用户「买服务器干什么」？</p><blockquote><p>In some rare cases, for specific products, we may be required to share some, or all of your personal details with one or more third parties in-order to provide the service. In the event of this, we will explicitly inform the customer before sharing any details, in clear visible writing.</p><p>在极少数情况下，对于特定产品，我们可能需要与一个或多个第三方共享您的一些或所有个人详细信息，以提供服务。在这种情况下，在共享任何详细信息之前，我们将以清晰可见的文字明确告知客户。</p></blockquote><p>Privex 也给自己留了这么个合规的后门。通常来说，这指的是域名注册或软件授权。如果在 Privex 注册域名，ICANN 规定必须有 WHOIS 信息，Privex 必须把信息传给上游注册局。虽然 Privex 承诺会用大号粗体字显式告知，但为了绝对的「数字主权」，建议只在 Privex 购买纯粹的计算资源，不要购买域名或者商业软件授权，以避免触发这个第三方共享条款。</p><p>这样看来，Privex 最大的缺点便是缺乏明确的法律管辖区声明。一旦出事，用户没有任何法律途径维权，只能寄希望于 Privex 的技术防御能扛得住。</p><p>但先别急！我们最好是再多阅读一下 Privex 的文档，例如 <a href="https://www.privex.io/faq/">FAQ</a>。</p><p>FAQ 解答了我先前的一些疑惑：是的，Privex 是在伯利兹注册的。他们也不向伯利兹本地人提供服务，符合离岸公司的标准操作（为了避免触犯本地法律）。</p><p>Privex 有两类区域：标准区域和自治区域。前者是租用别人的机器，受上游供应商管制。如果上游收到投诉，Privex 必须在 12-72 小时内删号。这些区域自然没有数字主权而言。后者的机器是 Privex 自个儿买的，网络设备自己运营，IP 也是自己的。这意味着只有瑞典或者荷兰当地法院或者伯利兹法院能命令他们关机。普通的 DMCA 投诉、滥用报告，Privex 可以选择无视。</p><p>对于一般人来说，一个较为扣分的点是 Privex 拒绝法币支付，也就是信用卡和 Paypal 这类支付方式。</p><p>接着是对于灰产许可与诚实原则的说明。这一点展现了 Privex 独特的法外狂徒但守规矩的逻辑：</p><ul><li><p>Tor 出口节点许可；</p></li><li><p>在「使用目的」里老老实实说自己买服务器干什么，跑的是色情网站 Privex 也会保护你；</p></li><li><p>不过呢，在标准区域里 Privex 依然需要遵守上游供应商的规矩。</p></li></ul><p>价格方面，Privex 提供迷你 VPS，例如一个 256M RAM、单核、5 G 硬盘空间、仅有 IPv6 的瑞典服务器，每月只需要 1 美元。如果看更为标准的单核、1 G RAM、15 G 硬盘空间的瑞典服务器的话，则是 4 美元一个月。</p><p>其他国家的服务器会贵一丢丢，这里就只展示瑞典区域的服务器价格了。</p><h4 id="hetzner"><a class="markdownIt-Anchor" href="#hetzner"></a> Hetzner</h4><p>Hetzner 的 <a href="https://www.hetzner.com/legal/privacy-policy/">隐私条款</a> 的重要部分是折叠起来的，这有点小坑，我还以为那个是超链接，点击后才发现是折叠块。</p><blockquote><p>Unless otherwise specified, your data will remain within the EU and will not be passed on to third parties.</p><p>除非另有说明，您的数据将保留在欧盟境内，不会透露给第三方。</p></blockquote><p>这一句话表明了 Hetzner 默认让用户数据归于 GDPR 的保护下。但是重点在于「另有说明」一词。现在 Hetzner 在美国和其他国家都有数据中心。如果购买时选择了美国节点，那么根据之前提到的属地管辖权，这部分数据将不可避免地落入美国 CLOUD Act 的管辖范围。这份隐私政策是针对德国母公司的，它巧妙地没有展开讨论美国分公司的法律地位。</p><p>Hetzner 有着极其严苛的预审与 KYC。在用户付款前，他们会通过第三方服务对用户进行风险画像，通常包括 IP 声誉、浏览器指纹甚至名字是否在某些黑名单上。如果被判定为高风险，他们甚至不会告诉用户原因就拒绝服务。</p><p>匿名也是不可能的。Hetzner 会将护照信息传输给立陶宛（欧盟国家，受 GDPR 保护）的 iDenfy。较为恐怖的是，Hetzner 会保留足足 14 年的开票数据，用于税法和商法保留义务。</p><p>一个大家可能不会注意到的泄漏点是 Hetzner 的网页客服系统外包给了美国公司 <a href="http://Kapa.ai">Kapa.ai</a> 和 OpenAI。虽然声称有个人敏感信息过滤工具，但在技术上这依然是一个通向美国的后门。</p><p>看完数据隐私相关后，还需要阅读 <a href="https://www.hetzner.com/legal/terms-and-conditions/">Terms and Conditions</a>，因为前者的内容过短，许多重要条款都没有提及到。</p><blockquote><p>All matters arising out of or relating to these Terms and the contractual relationship are governed by and construed in accordance with German law without giving effect to any choice or conflict of law provision or rule that would cause the application of the law of any jurisdiction – including international jurisdiction - other than German law. Place of jurisdiction for all disputes arising from the contractual relationship is our registered office in Gunzenhausen, Germany. However, we are entitled in all cases to take legal action at your place of business. Overriding statutory provisions, in particular, exclusive jurisdiction, shall remain unaffected.</p><p>因本条款及合同关系引起或与之相关的所有事项，均应受德国法律管辖并根据德国法律解释，不得引起任何选择或冲突法律条款或规则适用任何管辖权 —— 包括国际管辖权 —— 而非德国法律。合同关系引起的所有争议的管辖地为我们在德国 Gunzenhausen 的注册办事处。但是，在所有情况下，我们均有权在您的营业地提起法律诉讼。特别是，具有约束力的法定条款，尤其是专属管辖权，将不受影响。</p></blockquote><p>Sec 22 里，Hetzner 表面上声称即使服务器在美国，他们也会按照德国法律办事。</p><p>但是……</p><blockquote><p>You are not allowed to publish content that may violate the rights of third parties or otherwise violate the federal or any state law of the US.</p><p>您不得发布可能侵犯第三方权利或以其他方式违反美国联邦或任何州法律的内容。</p></blockquote><blockquote><p>The Services we provide in the USA are subject to the export laws, restrictions, regulations and administrative acts of the United States Department of Commerce, Department of Treasury Office of Foreign Assets Control (「OFAC」), State Department, and other United States authorities (collectively,「U.S. Export Laws」). You shall not use our Services to collect, store or transmit any technical information or data that is controlled under U.S. Export Laws. You shall not export or re-export, or allow the export or re-export of, our Services in violation of any U.S. Export Laws. None of our Services may be downloaded or otherwise exported or re-exported (i) into (or to a national or resident thereof) any country with which the United States has embargoed trade; or (ii) to anyone on the U.S. Treasury Department's list of Specially Designated Nationals or the U.S. Commerce Department's Denied Persons List, or any other denied parties lists under U.S. Export Laws. By using the Site and our Services, you agree to the forego, represent and warrant that you are not a national or resident of, located in, or under the control of, any restricted country; and you are not on any denied parties list; and you agree to comply with all U.S. Export Laws (including「anti-boycott」,「deemed export」and「deemed re-export」regulations). If you access the Site or our Services from other countries or jurisdictions, you do so on your own initiative and you are responsible for compliance with the local laws of that jurisdiction, if and to the extent those local laws are applicable and do not conflict with U.S. Export Laws. If such laws conflict with U.S. Export Laws, you shall not access the Site or use our Services. The obligations under this section shall survive any termination or expiration of these Terms or your use of the Site our Services.</p><p>我们在美国提供的服务受美国商务部、美国财政部外国资产控制办公室（「OFAC」）、国务院及其他美国当局（统称「美国出口法律」）的出口法律、限制、法规和行政法令的约束。您不得使用我们的服务来收集、存储或传输任何受美国出口法律管制的任何技术信息或数据。您不得违反任何美国出口法律出口或转口我们的服务，或允许出口或转口我们的服务。我们提供的任何服务不得下载或以其他方式出口或转口（i）到美国已实施贸易禁运的任何国家（或该国的国民或居民）；或（ii）到美国财政部特别指定国民名单或美国商务部禁止出口人员名单，或根据美国出口法律的任何其他被拒绝方名单上的任何人。使用本网站和我们的服务，即表示您同意上述规定，并声明和保证您不是任何受限制国家的国民或居民，也不在该国家或地区，或受其控制；您不在任何被拒绝方名单上；并且您同意遵守所有美国出口法律（包括「反抵制」、「视同出口」和「视同转口」法规）。如果您从其他国家或司法管辖区访问本网站或我们的服务，您将自行承担此行为，并负责遵守该司法管辖区的当地法律，如果且在这些当地法律适用且不与美国出口法律冲突的情况下。如果此类法律与美国出口法律发生冲突，您不得访问本网站或使用我们的服务。本节项下的义务在本条款的任何终止或期满，或您对本网站或我们服务的使用的任何终止或期满后仍然有效。</p></blockquote><p>这两条（Sec 4 和 Sec 19）否定了 Sec 22 的独立性。只要选择了美国节点，用户就必须遵守美国联邦法律和州法律。原本在德国合法但在美国非法的内容，在 Hetzner US 都是违规的。</p><p>为什么说是 Sec 22 被否定，而不是 Sec 22 否定了这两条条款呢。因为接下来的 Sec 23 中说道：</p><blockquote><p>(a) IN THE EVENT THAT SECTION 22 IS NOT APPLICABLE BY LAW, THE FOLLOWING RULES SHALL APPLY.</p><p>(b) YOU AND WE AGREE TO GIVE UP ANY RIGHTS TO LITIGATE CLAIMS IN A COURT OR BEFORE A JURY, OR TO PARTICIPATE IN A CLASS ACTION OR REPRESENTATIVE ACTION WITH RESPECT TO A CLAIM. OTHER RIGHTS THAT YOU WOULD HAVE IF YOU WENT TO COURT MAY ALSO BE UNAVAILABLE OR MAY BE LIMITED IN ARBITRATION.</p><p>ANY CLAIM, DISPUTE OR CONTROVERSY (WHETHER IN CONTRACT, TORT OR OTHERWISE, WHETHER PRE-EXISTING, PRESENT OR FUTURE, AND INCLUDING STATUTORY, CONSUMER PROTECTION, COMMON LAW, INTENTIONAL TORT, INJUNCTIVE AND EQUITABLE CLAIMS) BETWEEN YOU AND US ARISING FROM OR RELATING IN ANY WAY TO YOUR PURCHASE OF PRODUCTS OR SERVICES VIA THE SITE WILL BE RESOLVED EXCLUSIVELY AND CONCLUSIVELY BY BINDING ARBITRATION.</p><p>(c) The arbitration will be administered by the American Arbitration Association ("AAA") in accordance with the Consumer Arbitration Rules (the "AAA Rules") then in effect, except as modified by this section of this Agreement. (The AAA Rules are available at <a href="http://adr.org">adr.org</a> or by calling the AAA at 1-800-778-7879.) The Federal Arbitration Act will govern the interpretation and enforcement of this section.</p><p>The arbitrator will have exclusive authority to resolve any dispute relating to arbitrability and/or enforceability of this arbitration provision, including any unconscionability challenge or any other challenge that the arbitration provision or the Agreement is void, voidable or otherwise invalid. The arbitrator will be empowered to grant whatever relief would be available in court under law or in equity. Any award of the arbitrator(s) will be final and binding on each of the parties and may be entered as a judgment in any court of competent jurisdiction.</p><p>(d) You agree to an arbitration on an individual basis. In any dispute, NEITHER YOU NOR WE WILL BE ENTITLED TO JOIN OR CONSOLIDATE CLAIMS BY OR AGAINST OTHER CUSTOMERS IN COURT OR IN ARBITRATION OR OTHERWISE PARTICIPATE IN ANY CLAIM AS A CLASS REPRESENTATIVE, CLASS MEMBER OR IN A PRIVATE ATTORNEY GENERAL CAPACITY.</p><p>The arbitral tribunal may not consolidate more than one person's claims and may not otherwise preside over any form of a representative or class proceeding. The arbitral tribunal has no power to consider the enforceability of this class arbitration waiver, and any challenge to the class arbitration waiver may only be raised in a court of competent jurisdiction.</p><p>If any provision of this arbitration agreement is found to be unenforceable, the unenforceable provision will be severed, and the remaining arbitration terms will be enforced.</p><p>(a）如果法律规定第 22 条不适用，则适用以下规则。</p><p>(b）您和我们同意放弃在法院或陪审团面前起诉索赔的任何权利，或就索赔参与集体诉讼或代表诉讼。您在去法院时可能拥有的其他权利在仲裁中也可能不可用或受到限制。</p><p>因您通过本网站购买产品或服务而产生或与之有关的任何索赔、争议或纠纷（无论是合同、侵权法或其他性质的，无论是在签订合同之前、现时或将来发生的，包括法定、消费者保护、普通法、故意侵权、禁令救济和衡平法索赔），将仅通过具有约束力的仲裁来解决，并且该解决将是终局的。</p><p>(c）仲裁将由美国仲裁协会（「AAA」）根据当时有效的《消费者仲裁规则》（「AAA 规则」）进行管理，但本协议本节对其进行的修改除外。（AAA 规则可在 adr.org 查阅，或致电 AAA 1-800-778-7879 索取。）《联邦仲裁法》将管辖本节的解释和执行。</p><p>仲裁员将拥有处理任何与本仲裁条款的可仲裁性和 / 或可执行性有关的争议的专属权力，包括任何不公平性挑战或对仲裁条款或本协议无效、可撤销或以其他方式无效的任何其他挑战。仲裁员将被授权授予法庭依法或衡平法可提供的任何救济。仲裁员的任何裁决将对各方具有最终约束力，并可在任何有管辖权的法院作为判决执行。</p><p>(d）您同意以个人身份进行仲裁。在任何争议中，您和我方均无权在法庭或仲裁中加入或合并其他客户的索赔，或以其他方式作为集体代表、集体成员或以私人公益律师身份参与任何索赔。</p><p>仲裁庭不得合并一人以上的索赔，也不得以任何形式主持代表性或集体诉讼。仲裁庭无权考虑此集体仲裁弃权条款的可执行性，并且对集体仲裁弃权条款的任何质疑只能在有管辖权的法院提出。</p><p>如果本仲裁协议的任何条款被认定为不可执行，则不可执行的条款将被分割，其余的仲裁条款将得到执行。</p></blockquote><p>强行在美国执行德国法律是行不通的，他们的 Plan B 是 <u>美国仲裁协会</u> （AAA） 的强制仲裁。强制仲裁意味着用户放弃在法院起诉的权利，也放弃了陪审团审判。这是典型的美国式法律压迫工具，旨在降低大公司的诉讼成本。</p><p>Sec 19 还提到了 OFAC（Office of Foreign Assets Control，外国资产控制办公室），也是美国政治部的制裁者：如果美国决定制裁某个实体，Hetzner 为了保住其美国业务，必须切断该实体的服务。这证明了其管辖权不再是独立的，而是附庸于美国外交政策的。</p><blockquote><p>You are not allowed to publish content that may violate the rights of individuals or groups of people, or that insults or denigrates these people.</p><p>您不得发布可能侵犯个人或群体权利、或侮辱或贬低这些人的内容。</p></blockquote><p>和其他提供商一样，Hetzner 也给自己预留了极大的主观裁量权：什么是侮辱？什么是贬低？难道任何引发争议的政治或社会内容的站点都要被关闭吗？</p><p>Hetzner 必须被拆分为两个完全不同的实体来评价。讲完了 Hetzner 在美国的分公司后，再来说说母公司的原罪。</p><p>根据 Terms and Conditions 的 Section 8.3 和 8.4，只要 Hetzner 的自动化系统监测到用户的服务器有异常流量或者收到了第三方投诉，他们通常会先拔线，再发邮件通知用户。用户必须在断网状态下自证清白。对于追求高可用性的用户，这种官僚逻辑自然是致命的。</p><p>Hetzner 也明确指出他们在监视元数据，通常是分析连接频率、目标 IP 分布和端口扫描行为。用 Hetzner 的机器做任何会产生大量连接数的行为都会被系统自动判定为攻击行为，进而触发自动封锁。</p><p>支付方面，Hetzner 不支持 Monero（XMR）或完全匿名的加密货币支付。他们只接受信用卡、PayPal 或银行转账。</p><p>Hetzner 的合同需要提前 30 天通知并在月底终止。这种周期过于僵硬，对于需要灵活部署或者紧急撤离的用户来说是一个巨大的财务和安全负担。</p><p>价格上，一个 2 VCPU、4 GB RAM、40 GB 硬盘空间、20 TB 流量的服务器最低可以达到每月 3.49 欧元，也就是 4 美元、29 人民币。</p><h4 id="bahnhof"><a class="markdownIt-Anchor" href="#bahnhof"></a> Bahnhof</h4><p>我找不到 Bahnhof 的隐私条款…… 留给未来的自己吧。</p><h3 id="结论"><a class="markdownIt-Anchor" href="#结论"></a> 结论</h3><p>选择 VPS 的之前，一定要搞清楚自己买这个服务器做什么。如果是想要记录敏感内容（色情网站不算啊），就必须找到提供法律保护的服务商；如果是极客或者加密无政府主义者，你需要找到那些提供身份隔离的服务商；如果是开发者或者中小企业主，且业务完全合法，那选择稳定、便宜且合规的服务商会更好。不过无论选谁，只要看到美国节点，请直接 pass。</p><p><strong>这篇文章也绝非真理</strong>！我可能遗漏一些细节，有可能无视了服务商们实际的操作 —— 毕竟完全不按照条款运作的公司貌似也不少见 —— 甚至可能说错了内容。如果有任何需要修正的地方，还请务必联系我。</p><p>细数了这些「面向隐私」的 VPS 服务商的罪恶后，或许有人会想要使用自己家中的物理服务器。但在我看来，它依然不是旅途的终点，因为家中的物理服务器会和互联网服务提供商有所牵连。具体是怎样我就不展开说了，很多民用互联网服务提供商也禁止搭建公开服务。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我观看了一场名为「后美国互联网」的 &lt;a href=&quot;https://pluralistic.net/2026/01/01/39c3/&quot;&gt;演讲&lt;/a&gt;，实在是精彩，让我对「数字主权」这一概念有了更深刻的认知。借此，我发现我的许多服务依然部署在美国的 PaaS 服务上。这类中心化的服务如果出问题了会很麻烦，参考去年 Cloudflare 的事故。而我愈来愈对美国企业产生抵触之心。不过要我完全逃离是很难做到的，毕竟我人就在美国。这些原因结合在一起，促使我对「哪家提供 VPS（虚拟专用服务器）服务的公司最适用于数字主权者」这一命题感到好奇。&lt;/p&gt;</summary>
    
    
    
    <category term="工具分享" scheme="https://blog.cytrogen.icu/categories/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    
    <category term="云服务器" scheme="https://blog.cytrogen.icu/tags/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    
    <category term="数字主权" scheme="https://blog.cytrogen.icu/tags/%E6%95%B0%E5%AD%97%E4%B8%BB%E6%9D%83/"/>
    
    <category term="法律" scheme="https://blog.cytrogen.icu/tags/%E6%B3%95%E5%BE%8B/"/>
    
  </entry>
  
  <entry>
    <title>初次走半马</title>
    <link href="https://blog.cytrogen.icu/posts/53f4.html"/>
    <id>https://blog.cytrogen.icu/posts/53f4.html</id>
    <published>2026-01-19T05:00:00.000Z</published>
    <updated>2026-02-19T07:42:07.353Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>室友这些天喜欢看 <a href="https://space.bilibili.com/8263502">橙飞一下</a> 这个 BiliBili 频道。频道主是一位大胃王，也是一位马拉松跑者，吃饭的时候看他吃饭会格外香。不过呢他跑马拉松这件事情引起了室友那奇怪的好战之心，想要试试一天内走「全马」。不过嘛，结果从本文标题里就可以看出……</p><span id="more"></span><hr><p>「全马」指的是「全程马拉松」，即 42.195 公里；「半马」顾名思义，是「全马」的一半。虽然通常来说马拉松都是跑的，但你要想走也没有关系，还更适合我这个运动白痴。考虑到我的身体状况和缺陷，我和室友最终决定这一天走完全马即可。</p><p>这一周室友都很兴奋，还去咨询了自己的几位朋友 —— 她们都是马拉松跑者或者走者，其中一位还是踢踏舞舞者，可以在跑步期间感受到脚步的节奏，听上去颇为有趣 —— 她们给出了一些不错的建议，例如厕所要时刻留意、袜子建议多带几双……</p><p>不幸的是，约定好的这天下起了雪。我们原本打算早上四点就起床的，但因为嗜睡、到六点才起，望向窗外时外面已是大雪飘飘。我此时已经打起了退堂鼓：外面又是下雪和下雨，一整天还只有零度，真的有必要在这个日子出去吗？室友则认为既然已经约好了，外面下火也得出去。为了防止冻着自己，她还穿了两层保暖衣，我则是戴了一个从未戴过的针织帽。</p><p>我们身上的装备除了彼此的手机，就是一个充电宝、昨夜剩下的冷鸡块和折叠雨伞。因为担心期间太无聊，我们还带了无线蓝牙耳机，不过这一整天我们都没有使用过就是了。</p><p>路线昨天就已经被室友规划好了。我们要先走到昆斯博罗大桥（Queensboro Bridge），它在曼哈顿的东边，连接起了曼哈顿和皇后区。</p><p>从家里过去的距离大致是五公里，这期间我看到了一个当地餐饮业的趋势：做日料。这里的「日料」指的是那种小手卷，我个人并不爱吃。这种店通常会开在上班族多的地段，价格贵得离谱，材料一眼看过去就是便宜货。但是这种店开得不少，意味着当地人就爱吃这一套。或许我找不到「体面工作」可以考虑下做寿司师傅，算是我的 Plan S 吧。</p><p>这五公里走起来很难受，快到桥的时候我们都感觉身体有点不适，遂走去一家最近的 Dunkin' Donuts（唐恩都乐；我的天我都不知道它的中文译名是这个）买了杯抹茶。我不喜欢抹茶，所以没有喝多少，都让室友喝去了。</p><p>昆斯博罗桥比曼哈顿桥好看点，但是没有布鲁克林大桥好看。我建议想要走桥参观的人们只去布鲁克林大桥，曼哈顿桥实在是太丑了，还特别吵！布鲁克林大桥是西边的那座，不要走错了。说回昆斯博罗桥，我们站在上面望向东河。因为雪，只能看到大片大片的雾，白茫茫的。期间我实在是受不了这个针织帽 —— 它会压住我的眼镜，很是难受 —— 把它戴在了室友头上，别说，还挺搭配。</p><p><img src="/posts/53f4/queensboro_bridge.webp" alt="" loading="lazy"></p><p>走到桥的一半我们看到了罗斯福岛，我还从未上去过呢。据说可以坐缆车过去，未来可以坐坐看。</p><p>整个桥的长度差不多是二公里，走完后我就走了七公里了，身体意外地没有先前那样不舒服，我也不觉得渴。倒是室友听了「走路大师」的意见后，对厕所产生了执着，非要去找厕所上。我们去了星巴克，室友想着是不是买点东西更好，不然感觉坐在里面不自在。我说你放心，这种店的员工不会在乎的，他们忙得要死哪儿还有精力管你。</p><p>桥下是皇后区的长岛市，是一个对我来说比较新颖的区域。我曾经来过这里的攀岩馆，高兴地接受了自己恐高、抓力弱，以及脚型奇怪穿不了攀岩鞋的事实。长岛市的中国餐厅不少，貌似是一个留学生比较多的地方。房价不能说是特别高？总要比曼哈顿中城的房租便宜吧。它的地理位置也不错，西边可以快速抵达曼哈顿，东边可以坐车去法拉盛大吃一顿（我认为法拉盛作为华人区还是有不可替代的地方在的）。</p><p>这时候的路线基本上就是跟着 7 号线和 LIRR（Long Island Rail Road，长岛铁路） 的铁轨走。毕竟是有铁轨的地方，道路都变得宽敞不少，建筑物除了仓库就是加油站，还有一家装修漂亮的狗狗托管所，叫作 Dozo Dog LIC。我们可以通过玻璃清楚地看到里面的狗狗在和工作人员们玩耍。</p><p><img src="/posts/53f4/under_rail.webp" alt="" loading="lazy"></p><p>路上，我向室友提到了一个命题：「你更想要共享知识而将数据都免费开放，还是为了版权和盈利而严厉打击盗版？」她认为只有在自己足够富足的时候，她才愿意将知识分享出去。这让我想起前些时候我做的「你是 Copyleft 还是 Copyright」测试，结果显示我是 Copyright，虽然和 Copyleft 的比例相差没有太大。</p><p>走了一会儿我们走到了 Sunnyside 区，原先以为这就是一个物欲低的住宅区，却没想到发现了一个很大的美食城，不过来的时间太早，还关着门。令人意外的是，这个美食城内貌似都是中国餐厅，但这个区看着并不像华人区。</p><p>事后我查了地图，才发现我们走的只不过是 Sunnyside 较为偏僻的那条路，再往南走两个大道就是 7 号线的地铁站以及一大堆餐厅 —— 最开始说你物欲低真是抱歉啦。</p><p>走到一个供孩童玩耍的公园时，发现门口摆放着数个椅子和箱子，好像是临时放在这里的活动用具。其中一个蓝色箱子上贴着 <em> Cursed Books</em> 的字眼，真是好笑。</p><p><img src="/posts/53f4/cursed_books.webp" alt="" loading="lazy"></p><p>回看照片时发现 <em> C</em> 没有被拍到，我更好笑。</p><p>再往东走，可以看到一个土耳其小超市，卖很多精致的甜品和零食，价格并不贵。吸引我们走进去的是它门口用中文写着「我们有卖奶皮子喔！」走进去找了半天并没有找到这个叫作「奶皮子」的东西，到底什么是「奶皮子」啊？</p><p><img src="/posts/53f4/nai_pi_zi.webp" alt="" loading="lazy"></p><p>隔着一条街有一家归正宗教堂，意外的是他们居然对性少数群体友善。我简单地查了一下，这主要是源于开放派教会的观点，认为对圣经的解释可以随着社会对正义、人权和科学理解的进步而不断更新。</p><p>这让我想起了《地。－关于地球的运动－》这部漫画里临近尾声的一幕，一位角色作为教会的人，反对了教会整部漫画里对地动说的看法 ——「地球是动的又如何？这反而可以证明上帝的伟大，我们对圣经的解释不应该拘泥于过去的错误理解。」</p><p><img src="/posts/53f4/reformed_church.webp" alt="" loading="lazy"></p><p>走到 Woodside 区时，或者说重新回到 7 号线高架下时，可以明显感受到我们走到了一个人口密集的社区。这里感觉是墨西哥人的社区，道路十分拥挤的情况下还能看到很多人在路边摆摊、开餐车。你还别说，有些烧烤摊的串串看上去很好吃的样子，就是不知道多少钱。</p><p>因为下了雪，高架上积累了不少水，一滴滴往我们头上流。走这一段路是我认为这一天里最痛苦的经历，人实在是太多了，还要撑着伞挡着头上的雨水，时不时还有雪下下来。因为快到法拉盛了，我们也不打算在这里就餐，只能饿着肚子继续向前走。</p><p>我发现这种社区里一定会开不少花店，让我很好奇花店赚钱么，明明这里的花店的价格也不是很贵的样子。</p><p><img src="/posts/53f4/flower_shop.webp" alt="" loading="lazy"></p><p>一位朋友住在 Woodside 区旁边的一个区，我给他发了一个定位，让他猜猜我是怎么过来的。他听到我说我是步行走过来之后，整个人都惊讶得不行，连发了许多问号，哈哈！</p><p>走了这么久，找厕所就成了一个问题。我推荐一个开源的 App，叫作 LavSeeker，可以根据 OpenStreetMap 上的信息在地图上显示厕所的位置。不过这个 App 有一些使用上的逻辑问题，比如用户的位置不是实时获取的，需要点击右上角的按钮先定位一下，过一小段时间才会显示附近最近的厕所。因为太冷了，我除了拍照外都鲜有掏出手机的时候，绝大多数情况下我们还是进店里问有没有厕所。</p><p>多数本地的店里都不提供厕所，就算有、也需要你买东西成为「顾客」才可以给你使用。不过有些地方还是一定会有厕所的，例如星巴克、麦当劳和超市（首选那种连锁超市，例如 Whole Foods）。偏僻的地方可以考虑问问加油站，以及找公园。公园里的厕所比想象中干净那么一点点，但还是有着说不上来的压抑感。</p><p><img src="/posts/53f4/dragon_ball_z.webp" alt="" loading="lazy"></p><p>言归正传，我们走到了花旗球场。这里人烟稀少，路上都是厚厚的雪，走起来很不舒服。我很后悔没有穿靴子来，不过我的脚就算穿靴子了，也会先因为脚型奇怪而提前喊苦吧。室友为了好看，穿上了漂亮的羊毛大衣，但是这个材质会吸水，在雪天待久了只会徒增难受。</p><p><img src="/posts/53f4/citi_field.webp" alt="" loading="lazy"></p><p>室友这时候提起了昨天她去参加的生日派对。她一直都是一个不喜欢和「无聊的人」打交道的人，对「朋友」的标准很高 —— 在她眼里，好朋友只有我一个，剩下的都是酒肉朋友或者生意伙伴。过生日的这个人（以下简称甲）对她来说就是个「有点无聊的人」。不过碍于甲很喜欢她，两人之间有点交情，她最终还是接受了派对邀请。</p><p>搞笑的是，室友之前为了公司而做的宣传视频被甲的朋友挖了出来（是的，室友就是我口中的「项目管理」；整个故事见 <a href="/posts/31df.html#%E6%97%A5%E8%AE%B0%E7%89%87%E6%AE%B5">十一月十日</a>），还被私下嘲笑。这件事要是她不知道也就罢了，偏偏甲莫名其妙地选择了直接把聊天记录甩给她看，搞得她心里七上八下 ——「你的朋友嘲笑了我，你给我看又是想怎样？」甲虽表示无意冒犯，觉得这些记录可能对她有帮助，但这逻辑实在感人。</p><p>很多时候，人做错事若是源于「坏」，尚有逻辑可循；但若是源于「蠢」，就真得小心了，因为你根本不知道他在想什么。甲显然属于后者。室友说，她根本不知道甲在那些朋友面前传了什么话，因为甲既然能把朋友的闲话复述给她，就意味着在甲心里，这种「双向传话」压根无所谓。</p><p>据说那群人在背地里把她无缘无故数落了一通，还追问甲关于她的事情。甲转头又把这事告诉了她，惹得她烦躁地表示：「你们要是想要知道什么的话就直接来问我吧！」但果不其然，没有人敢主动联系她。</p><p>这次生日派对里，甲的那些朋友也在场。那些背地里说得最欢的人，见了面却不敢吭声，装作初次相识，这让室友倍感无趣。整个派对的氛围也很诡异：明明甲才是寿星，全程叽叽喳喳抢话的却是那群人。他们不仅声音很大、时不时爆粗口，还喜欢在公共场合高谈阔论一些不合时宜的话题，例如「孩童被强奸和种族歧视，你最能接受哪一个？」拜托，这种问题私底下说说也就算了，不要在公共场合大声说出来啊！</p><p>总之，这场生日派对算是还了甲的人情。事后她问我我会不会开生日派对，我回道：「你想想跟我认识的这些年来我开过吗，我只有『被开生日派对』的份儿。」她被逗乐了，两人哈哈哈地笑作一团。</p><p>走过花旗球场，就能抵达华人区法拉盛。不过在说法拉盛之前，我要先说一下球场附近好玩的东西：室内溜冰场 World Ice Arena。这里的价格不算贵，还提供付费教学课。不过据说曼哈顿中城 Bryant Park 的那个溜冰场可以免费入场。</p><p>至于为什么我会想要提起这件事，是因为我们穿过法拉盛河时，路上有两个女生叫住了我们，问我们知不知道 World Ice Arena 在哪里。根据她们来的方向，我推测出原先告诉她们路线的人并不知道如何快速抵达这个溜冰场：假设你从 Mets-Willets Point 站下车（无论是 LIRR 还是 7 号线地铁），你都可以通过南边的 David Dinkins Circle 一路向东走到溜冰场。然而她们的原定路线是向东走到法拉盛的 Main Street 再从西南方向走，相当于绕了一大圈。</p><p>说回法拉盛，这可是纽约市相当有名的华人区。这里有着各种各样的美食，对我这个北方胃 + 碳水大王来说实在是喜欢得不得了。像海底捞、快乐小羊等国内知名品牌都在法拉盛有分店，不过这类店我吃得不多，我最喜欢的还是本地一个面馆 —— 皇后区法拉盛公共图书馆附近的郑州烩面。听名字会以为它是一家普通的面馆，但其实提供的食物很多，量大管饱好吃的同时还不贵，实在是太稀奇了。我偶尔来这里玩舞萌 DX 时，就会来这家点上一碗羊肉烩面吃。</p><p>不过这次是和室友一起来的，她对碳水不是特别感冒，想要点个菜我俩一起就着大米饭吃。最后我俩选的是干锅肥肠，加了份藕片（居然要六块钱），她一碗大米饭，我两碗。最后小费前总计三十块整。整体服务还可以，当时有点忙服务生跑来跑去的，也能理解一点吧。这家店还会提供免费茶水，茶水没了也会主动给你续，光是这点我就觉得给小费很理所当然。</p><p><img src="/posts/53f4/gj_go_fw_ih.webp" alt="" loading="lazy"></p><p>吃饭期间来了一个乞讨的，我前段时间来法拉盛玩舞萌 DX 时也遇到了这个人。他在店里走来走去，用英语说着他失业了，问有人能不能给他钱。老板娘用中文告诉我们不要给他钱，他这么年轻就出来乞讨要钱，如果给了钱他未来每天都会来，到时候店就不要开了。</p><p>见没有人理他，他还走到大门口处挡着其他客人、不让他们进来。要不到钱还恶意妨碍店内生意，实在是不道德。</p><p>可能也有读者认为这种人很苦，给点钱不好么。说实话，只要你来纽约市久了，自然而然就会对这种乞讨者祛魅。</p><p>吃完饭后我们继续向东进发。这时候我们已经走了十七公里。路上路过了 Koreatown（韩国城），也就是韩国人版本的唐人街。在曼哈顿中城也有一个韩国城，就在 Macy's（梅西百货）附近。</p><p>我们经过了一个华人超市，在里面买了一些小零嘴和桃子味儿的脉动，现在想来其实应该买外星人电解质水。除了矿泉水，瓶装饮料里我只会喝小样和可乐，去超市也是为了找小样。离开超市的时候我才发现其实有卖小样，只是不单卖，很是让我气愤。</p><p><img src="/posts/53f4/utopia_pkwy.webp" alt="" loading="lazy"></p><p>先前室友上厕所时我翻阅着 Mastodon 解闷儿，看到一篇和 Crypto，即虚拟货币相关的嘟文串。我对金融并不了解，只是大概地知道它在技术方面上的实现原理。室友和我完全相反，她是个技术小白，但在金融和商业嗅觉上却极其敏锐。</p><p>她说现在各国政府都开始监管 Crypto，并不推荐靠 Crypto 来避税，一般人当股票玩玩就好了。就算是想要自由地使用自己的资产，也会因为售卖货币的机构已经和政府有关联而变得很难。无论如何买币的人的信息都会被上交给政府，而美国政府对于人民的调查权是无限期的，也就是说政府哪天抽风了就是想查查你玩，你就一定会被扒干净。</p><p>她认为这类建议最好不要盲从。如果未来真的出了问题，你是找不到出建议的人的，想要玩的话还是先自己学明白吧。</p><p>这番话引出了我心中长期存在的一个疑问：Crypto 和股票到底有什么区别？她耐心地给我补了堂金融课。</p><p>股票的本质是你拥有一家公司的一部分。对于上市公司而言，它们通过出让股份来筹集资金去研发和扩张，因此可以被一般人买去。每一年它们需要根据赚来的钱选择取多少给研发、取多少分红给股东。</p><p>有人想要提前变现，有人想现在就入场…… 于是一个股票市场就出现了：我认为这家公司会赚很多钱，持有它的股票能够拿到更多的分红，所以我要买这家公司的股份；你觉得这家公司赚钱有点悬，所以想要赶紧卖出避免亏损。根据双方预测的股份价值，我们会进行一次交易。也就是说股份的价值是完全主观的，基于我们认为它值多少钱。但是股市所锚定的是公司的生产力，是实体资产。</p><p>我想起了两件事：一个是特朗普刚上台没多久和马斯克之间的冲突，市场担心特斯拉被针对，导致大量投资者抛售特斯拉股票；另一个是去年 CS2 还是 CS:GO 因为 Valve 的操作、导致整个饰品市场一夜之间崩盘。</p><p>股份、Crypto 和游戏资产都是数字资产，这些东西并不是客观存在的，也都有一个可以随意控制市场的「角色」存在 —— 股份是分发股票的公司，Crypto 是政府的监管，游戏资产则是游戏公司。</p><p>区别在于，分发股票的公司受法律保护，还算稳定些，虽然还是有着「炒」的元素在；游戏资产是纯粹的割韭菜；而 Crypto 的重点在于「共识」，说直白点它完全依赖于市场里的人相不相信它值钱。一旦监管介入，切断了法币入金和出金的渠道，或者像室友说的那样开始秋后算账，「共识」就会迅速崩塌。</p><p><img src="/posts/53f4/do_not_fear_enter.webp" alt="" loading="lazy"></p><p>我们沿着纽约州公路 25A 继续向东走，时不时可以看到中国餐厅、韩国餐厅和日本餐厅，但是整个区域给人感觉不知道是什么区，好像什么人都有，又好像什么人都没有。</p><p><img src="/posts/53f4/nj_uj_hot_pot.webp" alt="" loading="lazy"></p><p>快走到 Little Neck Bridge 的时候我已经感觉到达了自己的极限，也就是半马。这时候的我膝盖后方的肌肉明显开始抽搐，疼痛不已，只能靠僵硬地移动大腿根部的骨头来行走。</p><p>我们停在了那附近的 Popeyes（博派斯；派派思；大力水手炸鸡；佰百鸡…… 译名真多），点了份五美元的炸鸡吃，然后我就吃到了这辈子最难吃的炸鸡 —— 又油又干，鸡翅炸老了，咬下去连骨头都是脆的，肉硬得不行，真是恶心！没吃几口我就把食物打包了起来。</p><p>因为我到了极限，室友不得不调整我们的行走路线。她原先的计划是走到 LIRR 的 Great Neck 站点，然后再往西南方向走去 Jamaica（牙买加）站点，完成全马的目标。</p><p>此牙买加非彼牙买加，只是皇后区的一个社区而已，约翰・肯尼迪国际机场就在这里。</p><p>问题在于，这时候天已经开始黑了，我走完半马就已经开始身体不适，继续往东走只怕会愈来愈难回家，更何况雪依旧在下着。室友明显看着很不开心，但为了我的状况，最后决定一起走到牙买加区的 F 号线最后一站，然后坐 F 号线回家。</p><p>离开了更繁荣的主道路后，我才意识到人烟稀少的住宅区有多么难走。这里和城市的住宅区不同，路上几乎没有人，人们出行都是靠车，这也代表人行道都被大学覆盖，有些人行道干脆设计得很有问题，像是不希望人们在这里走的样子。</p><p><img src="/posts/53f4/random_road.webp" alt="" loading="lazy"></p><p>说实话，就算是让我走到 F 号线的最后一站，那也是差不多七公里的距离。我已经临近了身体的极限，还因为忘记在 Popeyes 上厕所，膀胱憋得难受，实在是走不到那里，所以还是让室友在 Oakland Gardens 区提前停止了走马。我们在公交站的附近找了下厕所，一家 99 美分店（AKA 一元店）很好心地给了我们他们厕所的钥匙，实在是太友善了。</p><p>比较好笑的是，我上完厕所后立马觉得身体抖擞，好像又可以继续走了。不过我还是没有那么做…… 天黑了快回家吧，下次可以继续，我明天还要上班呢。</p><p><img src="/posts/53f4/long_is_expwy_bus_stop.webp" alt="" loading="lazy"></p><p>接下来就是坐公交、转地铁、回家了。下车时看着无比熟悉的地铁站，忽然觉得今天的所有经历像梦一样。哎，我居然一路走到了那么远？我吗？回家后我们先是洗了澡。感受着热水从花洒里喷到身体上的感觉，我心里想着现代技术的发达和我有多幸福 —— 或许人就是这么「下贱」吧，必须得感觉难受才会知道平日过得有多舒服。</p><p>室友和父母打电话的期间，她的体质真是可怕，居然意犹未尽，还想要之后每两周走一次马。我和你们这群有足弓的人没话说。</p><p>我躺在床上查看自己今天拍的照片。我有个自托管的 Immich（虽然只是本地的 Docker 容器），可以很轻松地将手机上的照片上传到电脑上查看。看着地图里的图片分布，让人觉得无比有成就感。虽然今天只走了半马，并没有达成室友原先定的全马目标，但已经够了。我打算先将今天所发生的事情都写成博客文章发布，结果写到一半我就坐着睡着了…… 所以这篇文章是隔了一天才写完的。</p><p>这是我第一次写流水账。流水账如何才能写得好呢？我很好奇，毕竟我还在国内上小学时老师可没有教我这个。我现在只能靠图片来分隔开一些内容，但或许整体看上去还是会有点无聊？总之我已经很努力在使用连接词了…… 呃啊。</p><p>这也是我第二次用 Emacs 写博客文章。Hexo 框架本身并没有那么支持 Org Mode，就算使用 Org Mode 渲染器也就只是把 Markdown 换成 Org Mode 来写，还是没有很棒地利用起 Emacs + Org Mode。</p><p>我的方案是先创建一个专门存放 Org Mode 文件的目录，这个目录也会被我用来存放 GTD（Getting Things Done 的简写，是一种时间管理系统，未来我会写一篇和这有关的文章） 工作流相关的文件。当我写完了这篇 Org Mode 文章，我会用 Emacs 配置内我已经写好的方法将其转换成 Markdown 文件，并保存在 Hexo 源文件内，这期间 Front Matter 什么的都可以利用 Emacs 来完成，实在是太方便了！</p><p>扯远了。让我总结这一天的话，我认为走马是一个颇为有意思的活动。如果有一个有趣的朋友陪着自己完成的话，全程不会特别无聊。不过室友认识的马拉松跑者或者走者平日都是独自一人完成目标，要是你是一个享受这一活动的人的话，说不定走着走着就会进入心流状态呢？</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;室友这些天喜欢看 &lt;a href=&quot;https://space.bilibili.com/8263502&quot;&gt;橙飞一下&lt;/a&gt; 这个 BiliBili 频道。频道主是一位大胃王，也是一位马拉松跑者，吃饭的时候看他吃饭会格外香。不过呢他跑马拉松这件事情引起了室友那奇怪的好战之心，想要试试一天内走「全马」。不过嘛，结果从本文标题里就可以看出……&lt;/p&gt;</summary>
    
    
    
    <category term="日常生活" scheme="https://blog.cytrogen.icu/categories/%E6%97%A5%E5%B8%B8%E7%94%9F%E6%B4%BB/"/>
    
    
  </entry>
  
  <entry>
    <title>谈模仿学习与身份误区</title>
    <link href="https://blog.cytrogen.icu/posts/9412.html"/>
    <id>https://blog.cytrogen.icu/posts/9412.html</id>
    <published>2026-01-16T05:00:00.000Z</published>
    <updated>2026-02-19T07:42:07.357Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我在网络冲浪时看到了一位网友的求助。他自小就没有被教导如何和人打交道，长大后先是被母亲认定是一个孤僻的人，又被学校的环境误导，以为优秀的道路注定是孤独的、维持人际关系不重要。</p><p>这些因素堆叠在一起，当他意识到的时候，自己已经错过了积累社交经验的黄金期。</p><p>在此背景下，我真挚地给出了自己的建议：你只是不知道怎么说而已，你可以通过学习他人的对话来补上这个技术缺陷。这却遭到了第三人的反对，他认为这会让当事人丢失自己，不如让当事人以自己的方法来。</p><span id="more"></span><hr><p>我们常说大学是一个「小社会」，此话不假。对于社交能力的缺失让他开始感到痛苦；他其实很渴望别人能靠近自己，也希望自己能够回应别人的好意。</p><p>但因为他从未学习过如何社交，许多本可以拉近别人距离的社交场合都被他无一例外地搞砸。在其他人眼里，他看上去是那么冷漠或者奇怪，但他根本不是那个意思，他只是不知道如何接话。</p><p><strong>社交本质上是一套由符号、编码和反馈构成的系统</strong>。这听上去像是把人以计算机来看待，颇有股「只要学了计算机就可以把所有东西用它来解释」的傲慢劲儿。但实际上，这是许多人没有注意到的社交的另一面。</p><p>具体而言，对于社交经验匮乏的人们来说，他们面临的挑战通常不是缺乏表达欲，而是将内在意图转化为有效社交信号的能力。如果一个人都无法分辨笑话，那要求对方「做自己」不过是一个伪命题。当事人缺乏表达手段，展示出来的自己往往是 <span class="emphasis">受限且扭曲</span> 的。</p><p>社交能力充其量也只是一种技能，数年来人们对其的误解导致了大众对它的敬畏：「我不知道如何回复，这意味着那是我的性格，我只是不愿意和他人交流。」但这很多时候又是不对的，因为人们实际上很渴望与人交流和联系。大家一边承受着孤独，一边却又无动于衷。交流是人类的本能，社交是一种从小人们就要学习的技能。用这个角度来看，我们的「孤独」就可以是被改变的了！</p><p>当然，如果你是一个沟通能力没有问题的孤独人，那就是另一码事了…… 未来我会对此发表一些暴论，敬请期待？</p><p>社会学家 Erving Goffman 提出过 <u>拟剧论</u>：社会生活分为前台和后台。社交能力和人格无关，人们是可以采取 <u>工具性沟通</u> 的。在这种模式下，社交不再投射自我，更多是为了达成特定的目标的手段。这也不是一个应当被批评的行为，很多时候人们会下意识采用工具性沟通来适配社会规则，和「背叛自我」没有半毛钱关系。</p><p>回到我的观点。既然社交能力是一种技能，就和画画、编程一样，那么要如何学会它呢？在我看来，许多东西都需要经历这样的一套流程： <strong>模仿－内化－创新</strong>。孩童学习一件事情几乎就是依赖着「模仿」和「重复」，他们会模仿自己看到的所有人，然后不停地重复。这也是为什么长时间陪伴孩子的那个人在孩子的成长里是最重要的，通常来说这个人是父母。至于重复，只要你带过小孩子，就会知道他们有多么热衷于只做一件事情、只看一个电视频道……</p><p>一个画家必须先通过大量临摹来掌握透视、色彩和线条等技术手段，才能最终创作出具有个人风格的作品；如果画家拒绝学习技术，其画作呈现出的笨拙并非「真我」，仅仅只是「无能」。既然孩童是通过模仿他人才学会的社交，那错过了这一时期的人们也必须得让自己再次变成孩子。</p><p>认知科学认为，社交能力并非由抽象的理论构成，而是由无数个具体的「条件－反应」链条组成。当能力达到一定程度，个体自然会从「完全模仿」过渡到「选择性采纳」，最终形成带有个人色彩的社交风格。只有当社交动作不再占据一个人的全部认知资源时，他才有余力将真实的自己注入到谈话中。</p><p>值得注意的是，模仿他人说话与保持自我从来都不是此消彼长的关系，这也是为什么我十分排斥第三人的回复。他错将当事人的技能缺失认为是他的真实一面，完全无视了他对此的烦恼和痛苦，轻飘飘地反驳了我的建设性建议，要求当事人继续「当自己」—— 当事人的「自己」到底是什么？我认为肯定不是因为不知道该说什么、而被同学们误以为高冷的那个他。要知道，社交中的「自我」是动态构建的，而非静态存在的。</p><p>总之， <strong>强大的社交能力反而意味着我们可以更好地表达出自己</strong>。这是一个反直觉的概念：我们模仿他人是为了展现出完全、真实的自己。但是事情就是如此运转的。</p><p>缺乏社交技巧的人往往因为无法融入群体而感到自卑，这种负面情绪反而会极大地侵蚀自我的独特性。通过学习社交技巧，个体如果能获得更顺畅的社交反馈，反而可能建立起更强的自信，从而更有能力在公共场合展示出真实的自我。</p><p><strong>技能缺陷从来都不是一种性格选择</strong>。我认为现在的社会经常将这两点搞混 —— 不，你不是 <em>自闭症、抑郁症、ADHD</em>…… 你只是不会「社交」这个能力而已。自然，我不是说所有自闭症、抑郁症、ADHD 等患者都是如此，这只是夸张式表达而已。</p><p>更进一步说，当事人被母亲贴上了「孤僻」的标签，并被误导认为优秀的人不需要人际关系。这些事情对于一个还未稳定的个体而言，是一瓶瓶毒药。我会这么评价，是因为我也经历过同样的事情。我很高兴我身边有一位讲话十分直白的人，教会了我许多过去从未被教导过的社交礼仪。这也让我愈发对自己的父母感到不满，他们为了自己，数次伤害还是孩童的我，最终将我的惨状视为笑柄。</p><p>自然，第三人的考量不是并无道理。个体为了融入社交环境，可能会刻意压抑本能反应、模仿他人的行为。只是放在当事人的案例里，这只是 <span class="emphasis">廉价且无效</span> 的安慰，还回避了当事人正在经历的认知困境和技术门槛。这其实让我想起了另一个现象：只看简单的一段，然后只以事情的一面来发表意见或者建议，最终得出的结果牛头不对马嘴。事情是多面性的，你怎么可以因为我说了「模仿」，所以认定我的建议必定会让当事人压抑自我呢？</p><p>:PROPERTIES:<br>:CAPTURED: [2026-01-16 Fri 12:52]<br>:END:</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我在网络冲浪时看到了一位网友的求助。他自小就没有被教导如何和人打交道，长大后先是被母亲认定是一个孤僻的人，又被学校的环境误导，以为优秀的道路注定是孤独的、维持人际关系不重要。&lt;/p&gt;
&lt;p&gt;这些因素堆叠在一起，当他意识到的时候，自己已经错过了积累社交经验的黄金期。&lt;/p&gt;
&lt;p&gt;在此背景下，我真挚地给出了自己的建议：你只是不知道怎么说而已，你可以通过学习他人的对话来补上这个技术缺陷。这却遭到了第三人的反对，他认为这会让当事人丢失自己，不如让当事人以自己的方法来。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="心理学" scheme="https://blog.cytrogen.icu/tags/%E5%BF%83%E7%90%86%E5%AD%A6/"/>
    
    <category term="社会学" scheme="https://blog.cytrogen.icu/tags/%E7%A4%BE%E4%BC%9A%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>Emacs 里配置邮箱服务</title>
    <link href="https://blog.cytrogen.icu/posts/4420.html"/>
    <id>https://blog.cytrogen.icu/posts/4420.html</id>
    <published>2026-01-11T05:00:00.000Z</published>
    <updated>2026-02-09T17:16:55.009Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我开始在我的笔记本电脑上使用 EndeavourOS＋i3WM 以及 Emacs 了。刚开始使用 Emacs，实在是被它的能力上限所折服，巴不得所有事情都让它来做 —— 例如邮件收发。</p><span id="more"></span><p>关于邮箱收发，我最终决定使用这样的邮件客户端流：Mu4e 客户端＋mbsync。</p><p>首先需要安装以下内容：</p><pre><code class="language-bash">sudo pacman -S isync msmtp msmtp-mta passyay -S mu</code></pre><p>其中，isync 用于 IMAP 同步，mu 是邮件索引器，msmtp 是 SMTP 客户端用于发送，pass 则是密钥管理器。</p><p>配置邮件同步，需要创建 <code>~/.mbsyncrc</code>：</p><pre><code class="language-plaintext">Create BothExpunge BothSyncState *# === Gmail ===IMAPAccount gmailHOST imap.gmail.comUser 邮箱地址PassCmd "pass show email/gmail"TLSType IMAPSAuthMechs LOGINIMAPStore gmail-remoteAccount gmailMaildirStore gmail-localPath ~/Mail/Gmail/Inbox ~/Mail/Gmail/InboxSubFolders VerbatimChannel gmailFar :gmail-remote:Near :gmail-local:Patterns *</code></pre><p>在终端初始化目录： <code>mkdir -p ~*Mail*Gmail</code>。</p><p>同步前需要生成 GPG 密钥：</p><pre><code class="language-bash">gpg --full-generate-keygpg --list-keyspass init &lt;GPG ID 或者最后 8 位&gt;pass insert email/gmail</code></pre><p>最后一个命令是交互式的，需要自行粘贴邮箱的密码。对于主流的邮箱，需要输入应用密码，Gmail 和 iCloud 都是这样。</p><p>使用 <code>mbsync gmail</code> 来测试单个邮箱的连接。全部一起连接用 <code>mbsync -a</code>。</p><h3 id="初始化-mu"><a class="markdownIt-Anchor" href="#初始化-mu"></a> 初始化 mu</h3><p>我们需要初始化 mu，告诉它邮件都存放在哪里、哪些是我们的邮箱地址：</p><pre><code class="language-bash">mu init --maildir=~/Mail \   --my-address=邮箱地址 \   --my-address=另一个邮箱地址</code></pre><p>最后建立索引：</p><pre><code class="language-bash">mu index</code></pre><h3 id="将我校邮箱加进来"><a class="markdownIt-Anchor" href="#将我校邮箱加进来"></a> 将我校邮箱加进来</h3><p>CUNY 用的是微软的服务，并且关闭了基本认证，必须使用 OAuth2。</p><p>我最初的方案是，弄一个脚本处理 OAuth2 握手并自动刷新令牌，也就是 <code>mutt_oauth2.py</code> 脚本（见 neomutt）。这个脚本需要被伪装成 Mozilla Thunderbird，来绕过应用注册审批。</p><pre><code class="language-bash">mkdir -p ~/.mbsynccurl -L -o ~/.mbsync/mutt_oauth2.py https://raw.githubusercontent.com/neomutt/neomutt/master/contrib/oauth2/mutt_oauth2.pychmod -x ~/.mbsync/mutt_oauth2.py</code></pre><p>然后这么调用：</p><pre><code class="language-bash">python ~/.mbsync/mutt_oauth2.py ~/.mbsync/cuny_token --verbose --authorize --provider microsoft --client-id 9e5f94bc-e8a4-4e73-b8be-63364c29d753 --authflow authcode --email &lt;你的邮箱地址&gt;</code></pre><p>出现 Client Secret 时直接按回车，复制终端里给的 URL，最好是在无痕浏览器里登录。登录完会跳转到一个页面，赶紧复制 URL 下来，否则过几秒会跳转到警告页面。这个 URL 里有个 <code>code</code> 参数，复制下来（注意后面的 <code>session_state</code> 参数，删掉），输入到终端里……</p><p>然后你会收到 <em>User is authorized but not connected</em> 的消息。</p><p>为什么会这样呢？我们的 OAuth2 配置是没有问题的，但是 CUNY IT 部门把邮箱的 IMAP 和 POP 协议都禁用、不让用在应用上。</p><p>解决方法是，用 DavMail 在本地机器开启一个 IMAP 端口，mbsync 会连接到它，发送的请求会被转换成 Microsoft EWS 协议，也是 Outlook 网页版和官方客户端使用的协议。DavMail 会向微软的服务器请求数据，并伪装成 IMAP 返回给 mbsync。</p><p>创建 <code>~/.davmail.properties</code>：</p><pre><code class="language-plaintext">davmail.mode=O365Manualdavmail.uri=https://outlook.office365.com/EWS/Exchange.asmxdavmail.imapPort=1143davmail.smtpPort=1025davmail.ldapPort=1389davmail.popPort=1110davmail.bindAddress=127.0.0.1davmail.oauth.clientId=d3590ed6-52b3-4102-aeff-aad2292ab01cdavmail.oauth.redirectUri=urn:ietf:wg:oauth:2.0:oobdavmail.tokenFilePath=davmail.propertiesdavmail.ssl.nosecurecaldav=falselog4j.rootLogger=WARNdavmail.logFilePath=/var/log/davmail.logdavmail.keepDelay=30</code></pre><p><code>davmail.oauth.clientId</code> 里的内容是微软 Outlook 官方客户端的 ID。<br>用 <code>davmail ~/.davmail.properties</code> 启动，它会出现一个 URL，也是建议用无痕浏览器使用。唯一的区别是，这次登录后会一直卡着，一定要在登录前打开 Inspect 的 Network 标签页，里面会有一个 302 状态码的请求，location 值里的 URL 有个 <code>code</code> 参数，取出来粘贴到 DavMail 里。</p><p>在另一个终端里运行 mbsync：</p><pre><code class="language-bash">mbsync cuny</code></pre><h3 id="发送邮件"><a class="markdownIt-Anchor" href="#发送邮件"></a> 发送邮件</h3><p>我们需要使用 msmtp 这个外部程序来发信。</p><p>如果你有着需要使用 DavMail 才能连接上的邮箱地址，msmtp 也需要通过 DavMail 发送邮件。创建 <code>~/.msmtprc</code>：</p><pre><code class="language-plaintext">defaultsauth            ontls             offtls_starttls    offlogfile         ~/.msmtp.logaccount         cunyhost            127.0.0.1port            1025from            邮箱地址user            邮箱地址password        "随便写"account         gmailhost            smtp.gmail.comport            587auth            ontls             ontls_starttls    onuser            邮箱地址from            邮箱地址passwordeval    "pass show email/gmail"tls_trust_file  /etc/ssl/certs/ca-certificates.crt</code></pre><p>设置文件的权限：</p><pre><code class="language-bash">chmod 600 ~/.msmtprc</code></pre><p>你可以这样测试发送：</p><pre><code class="language-bash">echo "This is a test email from msmtp via DavMail." | msmtp --debug --account=发的账户 另一个收的邮箱</code></pre><h3 id="配置-emacs"><a class="markdownIt-Anchor" href="#配置-emacs"></a> 配置 Emacs</h3><p>现在我们的邮件系统由三个组件协同工作：</p><ul><li>mbsync 负责收</li><li>mu4e 负责界面和索引</li><li>msmtp 负责发</li></ul><p>我的方案是，在一个配置文件内写好所有的邮箱账号信息，例如这样：</p><pre><code class="language-lisp">(:name     "CUNY"                           ; 显示名称   :email    "邮箱地址"   :fullname "blabla"                         ; 发件人名   :maildir  "CUNY"                           ; ~/Mail/ 下的文件夹   :inbox    "Inbox"                          ; 收件箱路径   :sent     "Sent"                           ; 已发送   :drafts   "Drafts"                         ; 草稿   :trash    "Trash"                          ; 垃圾箱   :archive  "Archive")                       ; 归档</code></pre><p>多账号就是一个列表： <code>(账号1 账号2 ...)</code>。</p><p>为了让 mu4e 支持多账号，需要写一个函数自动生成 context。</p><pre><code class="language-lisp">(defun my/email--make-context (account)  (make-mu4e-context   :name (plist-get account :name)   :match-func (lambda (msg) (string-prefix-p "/CUNY" (mu4e-message-field msg :maildir)))   :vars `((user-mail-address . ,(plist-get account :email))         (mu4e-sent-folder . "/CUNY/Sent")           (mu4e-drafts-folder . "/CUNY/Drafts")     ...)))</code></pre><p>mu4e 很大，建议用 <code>with-eval-after-load</code> 延迟配置：</p><pre><code class="language-lisp">(with-eval-after-load 'mu4e  (setq mu4e-maildir "~/Mail")  (setq mu4e-get-mail-command "mbsync -a"))</code></pre><p>也可以使用 <code>--read-envelope-from</code> 让 msmtp 自动从邮件头的 <code>From:</code> 字段选择正确的账号发送：</p><pre><code class="language-lisp">(setq sendmail-program "/usr/bin/msmtp")(setq message-send-mail-function 'message-send-mail-with-sendmail)(setq message-sendmail-extra-arguments '("--read-envelope-from"))</code></pre></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我开始在我的笔记本电脑上使用 EndeavourOS＋i3WM 以及 Emacs 了。刚开始使用 Emacs，实在是被它的能力上限所折服，巴不得所有事情都让它来做 —— 例如邮件收发。&lt;/p&gt;</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Emacs" scheme="https://blog.cytrogen.icu/tags/Emacs/"/>
    
    <category term="Lisp" scheme="https://blog.cytrogen.icu/tags/Lisp/"/>
    
  </entry>
  
  <entry>
    <title>想法在乙巳临月迭代</title>
    <link href="https://blog.cytrogen.icu/posts/b211.html"/>
    <id>https://blog.cytrogen.icu/posts/b211.html</id>
    <published>2026-01-01T04:58:00.000Z</published>
    <updated>2026-02-09T17:16:55.213Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>开始下雪了。一年也要过去了，不知道大家的 2025 年如何呢？</p><span id="more"></span><div class="danger warning"><p>这次的网站和月刊结构也做了一点更新，见 <a href="#%E6%8A%98%E8%85%BE%E5%8D%9A%E5%AE%A2">博客更新记录</a>。</p></div><details>      <summary>本期导读</summary>      <h2 id="输入"><a class="markdownIt-Anchor" href="#输入"></a> 输入</h2><h4 id="商业与社会"><a class="markdownIt-Anchor" href="#商业与社会"></a> 商业与社会</h4><ul><li><a href="#%E6%B0%91%E6%84%8F%E8%B0%83%E6%9F%A5%E7%BE%8E%E5%9B%BD%E4%BA%BA%E4%B8%8D%E5%86%8D%E8%AE%A4%E4%B8%BA%E5%9B%9B%E5%B9%B4%E5%88%B6%E5%A4%A7%E5%AD%A6%E5%AD%A6%E4%BD%8D%E7%89%A9%E6%9C%89%E6%89%80%E5%80%BC%E8%BF%99%E6%98%AF%E4%B8%80%E4%B8%AA%E6%88%8F%E5%89%A7%E6%80%A7%E7%9A%84%E8%BD%AC%E5%8F%98">美国人不再认为四年制大学学位物有所值</a></li><li><a href="#%E6%96%B0%E6%8A%A5%E5%91%8A%E5%91%BC%E5%90%81%E5%9C%A8%E7%BE%8E%E5%9B%BD%E7%BB%88%E7%BB%93%E7%AB%A5%E5%A9%9A">新报告呼吁在美国终结童婚</a></li><li><a href="#%E5%B0%86%E6%B5%B4%E5%AE%A4%E9%97%A8%E5%B8%A6%E5%9B%9E%E9%85%92%E5%BA%97">将浴室门带回酒店</a></li><li><a href="#%E4%B8%BA%E4%BB%80%E4%B9%88-38-%E7%9A%84%E6%96%AF%E5%9D%A6%E7%A6%8F%E5%A4%A7%E5%AD%A6%E5%AD%A6%E7%94%9F%E8%AF%B4%E4%BB%96%E4%BB%AC%E6%9C%89%E6%AE%8B%E7%96%BE">38% 的斯坦福大学学生说他们有残疾</a></li><li><a href="#uber-%E8%BF%9B%E5%86%9B%E5%B9%BF%E5%91%8A%E4%B8%9A%E7%9A%84%E6%96%B0%E6%8B%9B%E5%B0%86%E4%BD%A0%E7%9A%84%E8%A1%8C%E7%A8%8B%E5%92%8C%E5%A4%96%E5%8D%96%E6%95%B0%E6%8D%AE%E8%BD%AC%E5%8C%96%E4%B8%BA%E8%90%A5%E9%94%80%E4%BA%BA%E5%91%98%E7%9A%84%E6%B4%9E%E5%AF%9F">Uber 进军广告业</a></li><li><a href="#%E5%AF%B9%E5%BE%AE%E8%BD%AF%E8%80%8C%E8%A8%80%E6%B6%88%E8%B4%B9%E8%80%85%E5%8F%AA%E6%98%AF%E6%8A%80%E6%9C%AF%E5%80%BA%E5%90%97">对微软而言消费者只是技术债吗？</a></li><li><a href="#%E5%BE%AE%E8%BD%AF%E9%81%87%E5%88%B0%E4%BA%86%E4%B8%80%E4%B8%AA%E9%97%AE%E9%A2%98%E6%B2%A1%E6%9C%89%E4%BA%BA%E6%84%BF%E6%84%8F%E8%B4%AD%E4%B9%B0%E6%88%96%E4%BD%BF%E7%94%A8%E5%85%B6%E5%8A%A3%E8%B4%A8%E7%9A%84-ai-%E4%BA%A7%E5%93%81">没有人愿意购买或使用微软那劣质的 AI 产品</a></li><li><a href="#%E6%88%91%E6%8A%8A%E4%BA%BA%E7%94%9F%E4%B8%AD-8-%E5%B9%B4%E7%9A%84%E5%AE%9D%E8%B4%B5%E6%97%B6%E9%97%B4%E6%B5%AA%E8%B4%B9%E5%9C%A8%E4%BA%86%E5%8A%A0%E5%AF%86%E8%B4%A7%E5%B8%81%E4%B8%8A">我把人生中 8 年的宝贵时间浪费在了加密货币上</a></li><li><a href="#%E5%88%9B%E4%BD%9C%E8%80%85%E7%BB%8F%E6%B5%8E%E5%A6%82%E4%BD%95%E6%91%A7%E6%AF%81%E4%BA%86%E4%BA%92%E8%81%94%E7%BD%91">创作者经济如何摧毁了互联网</a></li><li><a href="#%E8%BF%87%E5%8E%BB%E6%B2%A1%E9%82%A3%E4%B9%88%E5%8F%AF%E7%88%B1">过去没那么可爱</a></li><li><a href="#%E7%A7%91%E6%8A%80%E7%B2%BE%E8%8B%B1%E4%BB%AC%E6%AD%A3%E5%9C%A8%E5%88%9B%E5%8A%9E%E8%87%AA%E5%B7%B1%E7%9A%84%E8%90%A5%E5%88%A9%E6%80%A7%E5%9F%8E%E5%B8%82">科技精英们正在创办自己的营利性城市</a></li><li><a href="#youtube-%E7%A7%98%E5%AF%86%E6%B5%8B%E8%AF%95-ai-%E8%A7%86%E9%A2%91%E6%B6%A6%E9%A5%B0%E6%9C%AA%E7%BB%8F%E5%88%9B%E4%BD%9C%E8%80%85%E5%90%8C%E6%84%8F">YouTube 秘密测试 AI 视频润饰</a></li><li><a href="#spotify-%E7%8E%B0%E5%B7%B2%E6%8E%A8%E5%87%BA-ai-%E4%B9%90%E9%98%9F%E5%85%8B%E9%9A%86">Spotify 现已推出 AI 乐队克隆</a></li></ul><h4 id="心理与关系"><a class="markdownIt-Anchor" href="#心理与关系"></a> 心理与关系</h4><ul><li><a href="#%E5%8F%AA%E9%9C%80%E8%A6%81%E6%9C%89%E4%B8%80%E4%B8%AA%E6%88%90%E5%8A%9F%E5%B0%B1%E5%A4%9F%E4%BA%86">只需要有一个成功就够了</a></li><li><a href="#13-%E5%B2%81%E5%89%8D%E6%8B%A5%E6%9C%89%E6%99%BA%E8%83%BD%E6%89%8B%E6%9C%BA%E7%9A%84%E5%AD%A9%E5%AD%90%E5%BF%83%E7%90%86%E5%81%A5%E5%BA%B7%E7%BB%93%E6%9E%9C%E6%9B%B4%E5%B7%AE">13 岁前拥有智能手机的孩子心理健康结果更差</a></li><li><a href="#%E5%8E%BB%E5%BD%A9%E4%B8%8D%E5%97%A8%E4%B8%BA%E4%BB%80%E4%B9%88%E4%BD%A0%E8%AF%A5%E6%8A%8A%E6%89%8B%E6%9C%BA%E8%B0%83%E6%88%90%E7%81%B0%E5%BA%A6">为什么你该把手机调成灰度</a></li><li><a href="#%E4%BC%98%E5%8C%96%E5%8A%A8%E5%8A%9B">优化动力</a></li></ul><h4 id="科学与自然"><a class="markdownIt-Anchor" href="#科学与自然"></a> 科学与自然</h4><ul><li><a href="#%E6%B2%A1%E6%9C%89%E4%BB%80%E4%B9%88%E5%88%AB%E7%9A%84%E4%B8%9C%E8%A5%BF%E7%9C%8B%E8%B5%B7%E6%9D%A5%E5%83%8F%E5%AE%83%E4%BB%AC%E6%8B%AF%E6%95%91%E6%97%A5%E6%9C%AC%E6%9E%81%E5%85%B6%E7%BD%95%E8%A7%81%E7%9A%84%E9%9B%AA%E6%80%AA">拯救日本极其罕见的「雪怪」</a></li><li><a href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E8%87%AA%E9%97%AD%E7%97%87%E4%B8%8D%E5%BA%94%E8%A2%AB%E8%A7%86%E4%B8%BA%E5%8D%95%E4%B8%80%E7%96%BE%E7%97%85">为什么自闭症不应被视为单一疾病</a></li><li><a href="#%E8%87%AA%E9%97%AD%E7%97%87%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BB%A4%E4%BA%BA%E5%9B%B0%E6%83%91%E7%9A%84%E8%A1%A8%E4%BA%B2%E4%BB%AC">自闭症的那些令人困惑的表亲们</a></li><li><a href="#%E6%96%B0%E7%A0%94%E7%A9%B6%E6%98%BE%E7%A4%BA%E9%98%BF%E5%B0%94%E8%8C%A8%E6%B5%B7%E9%BB%98%E7%97%85%E5%9C%A8%E5%8A%A8%E7%89%A9%E6%A8%A1%E5%9E%8B%E4%B8%AD%E4%B8%8D%E4%BB%85%E5%8F%AF%E4%BB%A5%E8%A2%AB%E9%98%BB%E6%AD%A2%E6%88%96%E5%87%8F%E7%BC%93%E8%BF%98%E5%8F%AF%E4%BB%A5%E8%A2%AB%E9%80%86%E8%BD%AC%E8%87%B3%E5%AE%8C%E5%85%A8%E7%9A%84%E7%A5%9E%E7%BB%8F%E5%8A%9F%E8%83%BD%E6%81%A2%E5%A4%8D">阿尔茨海默病在动物模型中可以被逆转至完全的神经功能恢复</a></li></ul><h4 id="技术与创造"><a class="markdownIt-Anchor" href="#技术与创造"></a> 技术与创造</h4><ul><li><a href="#cloudflare-%E5%AE%95%E6%9C%BA%E6%98%AF%E4%B8%80%E4%BB%B6%E5%A5%BD%E4%BA%8B">Cloudflare 宕机是一件好事</a></li><li><a href="#%E8%B0%B7%E6%AD%8C%E7%A7%BB%E9%99%A4%E4%BA%86%E6%88%91%E6%95%B4%E4%B8%AA-bear-blog-%E7%9A%84%E7%B4%A2%E5%BC%95%E8%80%8C%E6%88%91%E4%B8%8D%E6%98%8E%E7%99%BD%E4%B8%BA%E4%BB%80%E4%B9%88">谷歌移除了我整个 Bear Blog 的索引</a></li><li><a href="#%E5%A4%A7%E5%A4%9A%E6%95%B0%E6%8A%80%E6%9C%AF%E9%97%AE%E9%A2%98%E5%AE%9E%E9%99%85%E4%B8%8A%E6%98%AF%E4%BA%BA%E7%9A%84%E9%97%AE%E9%A2%98">大多数技术问题实际上是人的问题</a></li><li><a href="#css-%E8%AE%BE%E8%AE%A1%E4%B8%AD%E7%9A%84%E4%B8%8D%E5%AE%8C%E6%95%B4%E9%94%99%E8%AF%AF%E5%88%97%E8%A1%A8">CSS 设计中的不完整错误列表</a></li><li><a href="#%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD%E6%97%B6%E4%BB%A3%E7%9A%84%E6%89%B9%E5%88%A4%E6%80%A7%E6%80%9D%E7%BB%B4">人工智能时代的批判性思维</a></li><li><a href="#%E8%87%AA%E4%BF%A1%E7%9A%84%E7%99%BD%E7%97%B4%E9%97%AE%E9%A2%98%E4%B8%BA%E4%BB%80%E4%B9%88-ai-%E9%9C%80%E8%A6%81%E7%A1%AC%E6%80%A7%E8%A7%84%E5%88%99%E8%80%8C%E4%B8%8D%E6%98%AF%E6%B0%9B%E5%9B%B4%E6%A3%80%E6%B5%8B">为什么 AI 需要硬性规则，而不是氛围检测</a></li><li><a href="#%E6%9C%80%E9%AB%98%E8%B4%A8%E9%87%8F%E7%9A%84%E4%BB%A3%E7%A0%81%E5%BA%93">最高质量的代码库</a></li><li><a href="#%E8%AF%8D%E8%A2%8B%E9%A5%B6%E4%BA%86%E6%88%91%E4%BB%AC%E5%90%A7">词袋，饶了我们吧</a></li><li><a href="#%E5%85%B3%E4%BA%8E%E5%A4%A7%E8%A7%84%E6%A8%A1%E6%B6%88%E8%B4%B9%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD%E7%94%9F%E6%88%90%E5%86%85%E5%AE%B9">关于大规模消费人工智能生成内容</a></li><li><a href="#llm-%E6%98%AF%E4%B8%80%E5%9C%BA%E5%A4%B1%E8%B4%A5%E6%96%B0%E4%B8%80%E8%BD%AE%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD%E5%AF%92%E5%86%AC%E5%8D%B3%E5%B0%86%E6%9D%A5%E4%B8%B4">LLM 是一场失败</a></li><li><a href="#%E4%B8%8D%E5%81%9A%E4%BF%A1%E6%81%AF%E7%9A%84%E6%B6%88%E8%B4%B9%E8%80%85%E4%BB%8E%E5%86%99%E5%91%A8%E5%88%8A%E5%BC%80%E5%A7%8B">不做信息的消费者，从写周刊开始</a></li><li><a href="#%E6%88%91%E4%B8%BA%E4%BB%80%E4%B9%88%E5%86%99%E4%BA%86-15-%E5%B9%B4%E7%9A%84%E5%8E%86%E5%8F%B2%E4%B8%93%E9%A2%98%E5%8D%9A%E5%AE%A2">我为什么写了 15 年的历史专题博客</a></li><li><a href="#markdown-%E9%99%90%E5%88%B6%E4%BA%86%E4%BD%A0">Markdown 限制了你</a></li><li><a href="#%E8%AE%A9-rss-%E6%9B%B4%E6%9C%89%E8%B6%A3">让 RSS 更有趣</a></li><li><a href="#%E7%94%A8%E9%9D%99%E8%B0%A7%E6%8A%80%E6%9C%AF%E6%8E%A2%E7%B4%A2%E7%8B%AC%E7%AB%8B%E7%BD%91%E7%BB%9C">用静谧技术探索独立网络</a></li><li><a href="#%E4%B8%8D%E8%A6%81%E4%B8%8B%E8%BD%BD%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F">不要下载应用程序</a></li><li><a href="#%E4%BC%98%E7%A7%80%E7%9A%84%E5%B7%A5%E7%A8%8B%E7%AE%A1%E7%90%86%E6%98%AF%E4%B8%80%E7%A7%8D%E6%97%B6%E5%B0%9A">「优秀的工程管理」是一种时尚</a></li><li><a href="#%E5%83%8F%E4%BD%A0%E8%AF%B4%E7%9A%84%E9%82%A3%E6%A0%B7%E5%BC%83%E7%94%A8%E5%AE%83">像你说的那样弃用它</a></li><li><a href="#%E5%88%9B%E9%80%A0%E8%83%BD%E8%A7%A6%E5%8A%A8%E4%BA%BA%E5%BF%83%E7%9A%84%E8%BD%AF%E4%BB%B6">创造能触动人心的软件</a></li><li><a href="#%E8%8F%9C%E5%8D%95%E4%B8%8A%E7%9A%84%E5%9B%BE%E6%A0%87%E6%97%A0%E5%A4%84%E4%B8%8D%E5%9C%A8%E6%B1%82%E5%8A%A9">菜单上的图标无处不在</a></li><li><a href="#%E5%BD%A2%E5%90%8C%E6%8B%92%E7%BB%9D%E7%9A%84%E8%81%94%E7%B3%BB%E9%A1%B5%E9%9D%A2">形同拒绝的联系页面</a></li><li><a href="#%E9%98%BB%E6%AD%A2%E5%9D%8F%E4%BA%BA%E4%BD%BF%E7%94%A8%E6%88%91%E7%9A%84%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE">阻止坏人使用我的开源项目</a><ul><li><a href="#%E9%98%BB%E6%AD%A2%E9%82%AA%E6%81%B6%E4%B8%8E%E5%BC%80%E6%BA%90%E6%88%91%E7%9A%84%E6%83%B3%E6%B3%95">阻止邪恶与开源：我的想法</a></li></ul></li><li><a href="#%E4%B8%BA%E4%BB%80%E4%B9%88%E6%88%91%E6%83%B3%E9%80%A0%E4%B8%80%E5%8F%B0%E7%AC%94%E8%AE%B0%E6%9C%AC">为什么我想造一台笔记本</a></li><li><a href="#%E6%88%91%E6%98%AF%E5%A6%82%E4%BD%95%E5%B1%8F%E8%94%BD%E6%89%80%E6%9C%89%E7%9A%84%E5%9C%A8%E7%BA%BF%E5%B9%BF%E5%91%8A%E7%9A%84">我是如何屏蔽所有的在线广告的</a></li><li><a href="#%E6%9C%80%E5%B0%8F%E7%9A%84%E7%8B%AC%E7%AB%8B%E5%8D%9A%E5%AE%A2%E5%8D%9A%E4%B8%BB">最小的独立博客博主？</a></li><li><a href="#%E6%9C%89%E8%B6%A3%E9%A1%B9%E7%9B%AE">有趣项目分享</a></li></ul><h2 id="输出"><a class="markdownIt-Anchor" href="#输出"></a> 输出</h2><ul><li><a href="#%E6%8A%98%E8%85%BE%E5%8D%9A%E5%AE%A2">折腾博客</a></li><li><a href="#%E6%88%91%E5%86%99%E7%9A%84%E6%96%87%E7%AB%A0">我这个月写的文章</a></li><li><a href="#%E6%88%91%E7%9A%84%E7%BC%96%E7%A8%8B%E5%8E%86%E7%A8%8B">编程历程</a></li><li><a href="#%E4%B9%A6%E7%B1%8D">书籍</a> / <a href="#%E5%BD%B1%E8%A7%86">影视</a> / <a href="#%E9%9F%B3%E4%B9%90">音乐</a></li><li><a href="#%E6%97%A5%E8%AE%B0%E7%89%87%E6%AE%B5">真生活</a></li></ul>    </details><h2 id="商业与社会"><a class="markdownIt-Anchor" href="#商业与社会"></a> 商业与社会</h2><h4 id="民意调查美国人不再认为四年制大学学位物有所值这是一个戏剧性的转变"><a class="markdownIt-Anchor" href="#民意调查美国人不再认为四年制大学学位物有所值这是一个戏剧性的转变"></a> <a href="https://www.nbcnews.com/politics/politics-news/poll-dramatic-shift-americans-no-longer-see-four-year-college-degrees-rcna243672">《民意调查：美国人不再认为四年制大学学位物有所值，这是一个戏剧性的转变》</a></h4><p>作者 Ben Kamisar 发现，美国人对四年制大学学位的价值观正在发生剧烈转变。</p><p>近三分之二的注册选民如今认为大学学位「不值这个价」，理由是毕业生往往缺乏具体职业技能，同时背负沉重债务。只有约三分之一的人仍然相信学位能带来更好的工作机会和长期收入。</p><p>这与十年前的情况形成鲜明对比：2013 年有 53% 认为学位值得投资，而如今这一比例下降了 20%。</p><details>      <summary>我的看法</summary>      <p>看来我并不是唯一一个认为大学愈来愈无用的人。</p><p>现在工作越来越不好找，大学里的课程很多时候也并不能在职业上帮助到学生。好像不论是哪个国家，本科课程都会出现和实际工作中不相同的情况，理论和实践之间存在巨大落差。</p><p>在美国，这种落差又被学费和债务进一步放大。</p><p>美国排名靠前的大学近乎都是私立大学，而私立大学的学费极为恐怖。但就算上了这么一所所谓的「好学校」，你毕业后又真的能找到工作吗？要知道，在美国上好学校、毕业后长期做的不是「体面工作」的人实在是大有人在。</p><p>值得注意的是，美国的助学金贷款有一个非常可怕的特性：<strong>它是很难通过破产申请免除的</strong>。</p><p>那么如何又上好学校、又不花那么多钱呢？用社区大学这个跳板。社区大学的价格很便宜，不过你只能上两年。上完这两年转去一所学费不昂贵的公立大学，最后一年再转去排名靠前的大学，这样你的毕业证书就是好大学的了。</p><p>但是这么做并非所有人都愿意。</p><p>相比之下，职业培训、社区学院或技能导向的教育模式，反而更能满足就业市场的需求。</p><p>例如最近媒体创造出来的 <em>The Toolbelt Generation</em>（工具腰带一代）一词，指的就是越来越多的 Z 世代年轻人放弃大学，直接去学电工、水管工、焊接。</p><p>总体来看，这次民意调查的结果并不令人意外。</p>    </details><h4 id="新报告呼吁在美国终结童婚"><a class="markdownIt-Anchor" href="#新报告呼吁在美国终结童婚"></a> <a href="https://womensmediacenter.com/news-features/new-report-calls-for-end-to-child-marriage-in-us">《新报告呼吁在美国终结童婚》</a></h4><p>或许很多人都会感到傻眼，已经快 2026 年了，世界的灯塔 ——AKA 美国 —— 还在争执<span class="emphasis">是否该废除童婚</span>。</p><p>2000–2021 年间，美国有超过 31 万名儿童合法结婚，其中 86% 是女孩，多数在 16–17 岁，但也有低至 10 岁的案例。女孩通常嫁给比自己大约 4 岁的成年男性；男孩则往往娶比自己年长约 1.5 岁的女性。</p><p>美国并没有联邦层面的最低结婚年龄，各州自行规定。截至 2018 年，所有州都允许未成年人结婚；目前仅有 16 个州、1 个地区和 2 个领地规定最低年龄为 18 岁且无例外。意味着在许多州，婚姻可以成为规避 <u>法定强奸罪</u> 的合法途径。</p><p>这也可以用于移民漏洞：美国移民法允许未成年配偶通过签证进入美国，2007–2017 年间有近 5 千名未成年人因此获得绿卡。</p><p>这样做的影响与危害我认为自然不用我多说。幸存者倡导组织 Unchained At Last 和国际人权组织 Equality Now 共同呼吁美国在联邦和州层面彻底禁止未满 18 岁的婚姻，不允许任何例外。不仅是法律，还需要教育、社会保护和对已婚未成年人的支持。要知道，美国在联合国 2016 年的全球计划中可是承诺了到 2030 年就会消除儿童婚姻。</p><p>幸存者 Fraidy Reiss 说：</p><blockquote><p>「他们之所以不愿意迅速采取行动，在很多情况下是因为<span class="emphasis">厌女症</span>。在美国，几乎所有未成年人结婚的对象都是成年男性。如果情况是男孩们被带离学校，在新婚之夜遭受强奸，反复遭受强奸，他们的未来被毁掉，我敢肯定立法者们会有更快的行动。」</p></blockquote><details>      <summary>我的看法</summary>      <p>美国童婚的许多案例都是父母或宗教团体强迫孩子结婚，所谓的「同意」并不是真正的自由选择。</p><p>宗教，宗教，<span class="emphasis">又是宗教！</span>我是一个厌恶宗教的人，具体是厌恶哪个宗教我就不提了。总之宗教对我的人生而言真是无妄之灾，它们常常通过神圣化「家庭权威」来掩盖虐待。</p><p>美国数年前就女性堕胎是否合法一事吵了个底朝天，反对者的底层逻辑便是「上帝创造了生命，女性没有决定生命（胚胎）是否有活下去的权力」。</p><p>小时候我在国内也受过另一个宗教的洗礼。差不多是说堕胎等同于阻止另一个灵魂投胎 —— 你都主动阻止别人投胎降生了，别人不得天天缠着你、向你复仇？</p><p>回到这篇文章的内容。部分 Hacker News 读者对这个报告有质疑：</p><ul><li>17 岁和 18 岁的差别并不总是决定性，法律划线可能过于僵硬</li><li>应区分「自愿的晚期青少年婚姻」和「强迫的早期童婚」</li></ul><p>或许最好的方法是支持设定最低年龄，但允许有限的例外…… 吗？实则不然。所谓的「例外」通常会被用来指「父母同意」或「法官批准」。唉，那不就又绕回去了？</p><p>一个很关键的法律陷阱是，<strong>未成年人即使结婚了，在法律上依然是未成年人</strong>。这意味着他们通常不能签署合同也不能独自提起诉讼。如果想要逃离这段婚姻，他们甚至无法进入家庭暴力庇护所，因为可能会被认为是「离家出走」。</p><p>用这个角度来看，允许例外，就等于允许「合法的人口贩卖」和「合法的强奸」。</p>    </details><h4 id="将浴室门带回酒店"><a class="markdownIt-Anchor" href="#将浴室门带回酒店"></a> <a href="https://bringbackdoors.com/">《将浴室门带回酒店》</a></h4><blockquote><p>「我受够了。我受够了每次入住酒店，都发现他们把浴室门拆了。这个本该和床一样标配的东西，却为了所谓的『美学』而被牺牲了。</p><p>「我明白了，这样可以节省材料成本，让房间显得更大，但我的尊严怎么办？？？如果你们不装浴室门，我可保不住我的尊严。</p><p>「这就是我搭建这个网站的原因，我在这里整理了保证有浴室门的酒店，以及需要改进隐私的酒店。</p><p>「我给几百家酒店发了邮件，问了他们两个问题：你们的门能完全关上吗？门是用玻璃做的吗？所有回答门能关上但不是玻璃做的酒店，我都按价格区间和城市进行了排序，方便你轻松找到保证有浴室门的住宿地点。</p><p>「最后，如果不是有人提交没有浴室门的酒店以供公开羞辱，这个充满激情的项目将无法实现。如果您住过一家没有门的酒店，请将酒店名称发送电子邮件至 bringbackdoors@gmail.com，或在 Instagram 上私信我酒店名称和没有门的设施照片，以便公开张贴。</p><p>「让我们点名批评这些酒店，以保护未来旅客的尊严。」</p></blockquote><h4 id="为什么-38-的斯坦福大学学生说他们有残疾"><a class="markdownIt-Anchor" href="#为什么-38-的斯坦福大学学生说他们有残疾"></a> <a href="https://reason.com/2025/12/04/why-are-38-percent-of-stanford-students-saying-theyre-disabled/">《为什么 38% 的斯坦福大学学生说他们有残疾？》</a></h4><p>文章里的「残疾」指的是「学习障碍」。</p><p>美国顶尖大学中声称自己有学习障碍的学生比例正在急剧上升，尤其是斯坦福大学，达到了 38%。相比之下，布朗大学和哈佛大学是 20%。</p><p>作者 Emma Camp 认为这很扯淡 —— 这些大学可是美国顶尖、录用率极低的大学，许多要求学生们有近满分的 SAT 成绩、文书优异（实际上并不只是这样，有时间可以聊聊美国大学如何录取学生），怎么可能有这么多有学习障碍的学生？</p><p>教育记者 Rose Horowitch 采访了一些教授，得知了事情的真相：<em>Americans with Disabilities Act</em>（美国残疾人法案）允许学生们仅凭一张医生纸就能「证明」自己有学习障碍。而美国对这些残障人士有丰富的福利，例如考试时拥有更多的时间、避免得到稀烂的成绩。</p><p>不过 Camp 也认为，并不是所有人都在靠此作弊，也有 <u>身份认同</u> 的问题在。Horowitch 在采访中发现，有许多学生确信自己患有神经发育障碍，并将其作为自己身份的一部分。</p><p>这也有网络的影响在作祟，许多社交媒体都在广泛传播这些东西的「症状」，让很多普通行为被解读为疾病迹象。</p><p>结果便是，大众严重扭曲了「正常」的含义。</p><details>      <summary>我的看法</summary>      <p>关于身份认同这一点，我有话要说。</p><p>我有着 fidget 的习惯，可以理解为做小动作、坐不住，不过我也不是那种好动、一秒钟都不想乖乖坐好的人。我 fidget 的一个很大原因是我无聊了、焦虑了、不想继续待在这个社交场合下、只想慢慢地走神……</p><p>不过很多人都借此觉得我有 ADHD，也就是我们常说的「多动症」、现在称为「注意缺陷多动障碍」最好。很多时候我的内心都在呐喊：<span class="emphasis">诊断才没有你们想的那么简单！</span></p><p>可惜我身边拿心理或者精神问题当做代表「自我」的标签的人，实在是不在少数。无论是抑郁症、焦虑症，还是近些年来的 ADHD、OPD、NPD、BPD……（哦天、怎么这么多）它们是医学问题！不是一个人的全部，也不是个性！同理，一个人的个性也不代表了他们有医学问题。</p><p>不过呢，在顶尖名校内发生这种事情，也可以算是制度的反向鼓励吧。在竞争极度激烈的地方，如果其他同学都有「加时卡」，你没有，你就处于劣势。</p>    </details><h4 id="uber-进军广告业的新招将你的行程和外卖数据转化为营销人员的洞察"><a class="markdownIt-Anchor" href="#uber-进军广告业的新招将你的行程和外卖数据转化为营销人员的洞察"></a> <a href="https://www.businessinsider.com/uber-ads-launches-intelligence-insights-trips-takeout-data-marketers-2025-12">《Uber 进军广告业的新招：将你的行程和外卖数据转化为营销人员的洞察》</a></h4><p>Uber Advertising 推出了新平台：Uber Intelligence。现在广告商可将自己的客户数据与 Uber 的数据结合，分析用户的饮食习惯和出行模式。</p><p>最为可怕的是，Uber 不同于谷歌和亚马逊，有着非常独特的数据来源 —— 人们点的外卖和打车的记录。</p><details>      <summary>我的看法</summary>      <p>有句话说得好：如果你不付费，你就是产品；如果你付费了，那么你就是更有价值的产品。</p><p>本来人们用 Uber 打车就是已经付过费的了，没想到我们还要看到无数个广告，并且让自己的数据变成了生产这些广告的一部分。</p><p>一部分 Hacker News 的用户提出了相当有意思的分析：那些愿意付费去除广告的用户，反而把自己标记成了「优质目标」，让广告商更愿意花钱投放。</p><p>这就不得不提 Cory Doctorow 提出的 <u>平台衰退理论</u>：</p><ol><li>平台初期：用低价和好服务取悦用户</li><li>平台中期：用好数据和精准流量取悦商业客户</li><li>平台末期：垄断市场后，同时收割用户和商业客户，把所有价值以此回馈给股东</li></ol><p>Uber 现在显然已经进入了第三阶段。</p><p>好在我不使用 Uber。</p>    </details><h4 id="对微软而言消费者只是技术债吗"><a class="markdownIt-Anchor" href="#对微软而言消费者只是技术债吗"></a> <a href="https://birchtree.me/blog/are-consumers-just-tech-debt-to-microsoft/">《对微软而言消费者只是技术债吗？》</a></h4><p>作者 Matt Birchler 提出了三个点：</p><ol><li>微软越来越不像一家消费科技公司</li><li>苹果在 2026 年可能推出平价 MacBook</li><li>Valve 会在 2026 年推出 Steam Machine</li></ol><p>这意味着，微软在消费者产品上可能会受到来自苹果和 Valve 的重创：Windows 电脑「价格亲民」和「能打游戏」这两个优点会被后两个公司的产品比下去。</p><details>      <summary>我的看法</summary>      <p>Windows 10 在今年正式结束了其生命周期，许多用户被迫升级，面临的却是体验极差的 Windows 11、更多的广告和订阅模式。</p><p>说实话，我自己很难把微软和苹果这样的公司进行对比，他们在消费端上付出的精力真的是一个天一个地。Windows 11 这样的残次品，到底是怎么敢放出来给顾客的？</p><p>现在很多人使用 Windows，根本就是习惯了、讨厌 MacOS 或者想玩游戏。如果这些优点都不复存在了，怎么可能会有人购买呢？</p>    </details><h4 id="微软遇到了一个问题没有人愿意购买或使用其劣质的-ai-产品"><a class="markdownIt-Anchor" href="#微软遇到了一个问题没有人愿意购买或使用其劣质的-ai-产品"></a> <a href="https://www.windowscentral.com/artificial-intelligence/microsoft-has-a-problem-nobody-wants-to-buy-or-use-its-shoddy-ai">《微软遇到了一个问题：没有人愿意购买或使用其劣质的 AI 产品》</a></h4><p>Birchler 主要是说微软的 Windows 系统做得差，现在 Jez Corden 又指出微软的 Copilot 做的也很烂。</p><p>微软和谷歌在 AI 领域上是直接的竞争对手。微软依赖 OpenAI 技术和 NVIDIA 硬件，试图通过 Copilot 将 AI 融入 Windows、Office 等产品；谷歌则凭借自研的 Gemini 模型和深度整合的生态，在用户体验和功能落地上更胜一筹。</p><p>结果是：微软的 AI 产品被批评为「仓促上线、质量低劣」，而谷歌的产品则逐渐赢得用户信任。</p><p>这意味着，不仅是 Windows，连微软寄予厚望的 AI 产品也陷入同样的困境。</p><p>微软到底怎么了呢？</p><h4 id="我把人生中-8-年的宝贵时间浪费在了加密货币上"><a class="markdownIt-Anchor" href="#我把人生中-8-年的宝贵时间浪费在了加密货币上"></a> <a href="https://x.com/kenchangh/status/1994854381267947640">《我把人生中 8 年的宝贵时间浪费在了加密货币上》</a></h4><p>作者 kenchangh 讲述了他在加密行业投入八年后，最终意识到这段经历几乎是浪费生命的过程。</p><p>2013 年左右他进入了加密领域，被「去中心化」「金融革命」的叙事吸引，也相信比特币和区块链能改变世界，带来更公平的金融体系。</p><p>结果是，大部分项目并没有真正的技术或社会价值，而是以投机和炒作为主。许多所谓的「创新」其实是重复的骗局或空洞的承诺。而社区文化往往充斥着贪婪、极端主义和对批评的排斥。</p><p>有意思的是，kenchangh 提到了《阿特拉斯耸耸肩》这本书。你会在本刊的后面再次听到它。</p><h4 id="创作者经济如何摧毁了互联网"><a class="markdownIt-Anchor" href="#创作者经济如何摧毁了互联网"></a> <a href="https://www.theverge.com/cs/features/810002/influencers-creator-economy-special-series">《创作者经济如何摧毁了互联网》</a></h4><p>创作者经济的本质并不是让创作者靠内容生存，而是迫使他们把内容当作广告入口，最终走向商品化。</p><h4 id="过去没那么可爱"><a class="markdownIt-Anchor" href="#过去没那么可爱"></a> <a href="https://juliawise.net/the-past-was-not-that-cute/">《过去没那么可爱》</a></h4><p>作者 Julia D. Wise 批评了人们在怀旧文化中对过去的浪漫化，强调历史并不如我们想象的那样美好，而是充满艰辛、歧视和复杂的社会现实。</p><p>过去的文化产物可以带来温暖和灵感，但必须承认它们是经过修饰的，而不是客观的历史。</p><h4 id="科技精英们正在创办自己的营利性城市"><a class="markdownIt-Anchor" href="#科技精英们正在创办自己的营利性城市"></a> <a href="https://www.ft.com/content/b127ee7a-5ac4-4730-a395-c9f9619615c7">《科技精英们正在创办自己的营利性城市》</a></h4><p>硅谷和科技精英们近期正在推动一股潮流：建立 <u>营利性城市</u>，或者所谓的「网络国家」。这些项目是对现有民主和监管体系的逃离尝试，也是资本与技术结合的实验。</p><p>起因是 Coinbase 的前首席技术官 Balaji Srinivasan 在新加坡举办「网络国家会议」，呼吁科技人群通过购买土地建立新的社区或国家。几年前还是一个边缘概念，现在却逐渐走向了主流 —— 目前已有约 120 个「初创社会」在筹备，部分项目甚至已获得数亿美元风险投资。</p><details>      <summary>我的看法</summary>      <p>这个话题有点复杂。</p><p>这些精英们认为美国制度已经陷入停滞与腐败，无法满足创新者和年轻人的需求，因此才推动营利性城市作为替代方案。</p><p>营利性城市的意思，是让私人公司作为「城市运营商」，像企业一样设计法律、收费和服务体系。盈利方式通常为租金、服务费和税收。目标是绕开传统民主制度的冗长流程，直接用市场逻辑来运行城市。</p><p>Pronomos Capital 的创始人 Patri Friedman 就希望可以让更多人尝试不同的治理模式。管理城市要变得像开创业公司一样，大家可以快速试错、允许不同意识形态的城市并存。</p><p>用大白话来说，居住权不再是人权，而是类似于会员制的东西。你可以订阅某某模式的城市，然后住进去。如果你不满意现在的城市服务，你不需要投票或者游行，你只需要退订、搬去你满意的城市。这就是所谓的「治理即服务」。</p><p>那么这些营利性城市真的是为了真正的社会创新吗？部分人们认为这是精英们为了逃避监管、税收和公共责任的 <u>机会主义</u> 行为。在他们看来，这些项目更像是「套利」，利用弱国或特殊经济区的制度漏洞来牟利。</p><p>有学者指出，这些城市由少数科技精英和资本家控制。城市的法律和规则由公司董事会制定，公共事务被商业化…… 居民缺乏民主参与。也就是 <u>技术官僚式威权主义</u>，以效率和数据为名，削弱民主与公共性。</p><p>更激烈的批评者认为，这些项目可能演变成 <u>科技法西斯主义</u>：以技术和资本为工具，建立高度监控和排他性的社会。这甚至可以是新殖民主义的翻版。未来当地社区被迫迁移或失去土地了，该怎么办？</p><p>Friedman 对这两点的回应是：花钱迁走原住民，以及<span class="emphasis">你不喜欢就不要住这里啊</span>。</p><p>该文章也提到了《阿特拉斯耸耸肩》，堪称 <u>自由意志主义者</u> 的圣经。</p><p>我仅读完了这本书的前两部，不过还是可以明白作者想要表达的意思。书中的 John Galt 带领全球的精英罢工，躲进深山建立了一个没有「寄生虫」（政府和「弱者」）的乌托邦。这和这些科技精英想的差不多是一致的：只有极少数人在推进世界进步，而现有的民主制度让大多数「平庸者」拖了后腿。</p><p>「我们作为那些极少数人，不想带你们这些拖油瓶玩，我们要自己玩。」</p><p>真是极致的精英主义傲慢。</p><p>这篇文章的作者 Hannah Murphy 的部分用词十分有意思，推荐学习一下。</p>    </details><h4 id="youtube-秘密测试-ai-视频润饰未经创作者同意"><a class="markdownIt-Anchor" href="#youtube-秘密测试-ai-视频润饰未经创作者同意"></a> <a href="https://www.ynetnews.com/tech-and-digital/article/bj1qbwcklg">《YouTube 秘密测试 AI 视频润饰，未经创作者同意》</a></h4><p>作者 Raphael Kahan 揭示了 YouTube 在未经创作者同意的情况下，秘密测试 AI 视频美化功能，引发了信任与透明度的争议。</p><p>事件起因是知名音乐类 YouTuber Rick Beato 和 Rhett Shull 发现自己的视频出现了奇怪的变化，例如头发看起来不自然、皮肤更光滑、衣服褶皱更清晰，甚至耳朵略有不同。他们怀疑视频被 AI 修改。</p><p>YouTube 创作者联络人 Rene Ritchie 在推特承认，确实在对部分 Shorts 视频进行「小规模实验」，使用机器学习来提高清晰度、减少噪点，类似于智能手机的自动优化功能。</p><p>问题在于：</p><ul><li>创作者并未被告知视频会被修改</li><li>这种隐藏的 AI 编辑可能削弱观众对内容的信任</li></ul><h4 id="spotify-现已推出-ai-乐队克隆"><a class="markdownIt-Anchor" href="#spotify-现已推出-ai-乐队克隆"></a> <a href="https://old.reddit.com/r/Music/comments/1phag1t/spotify_now_features_ai_band_clones/">《Spotify 现已推出 AI 乐队克隆》</a></h4><p>相较于上一篇文章，Spotify 的情况更为严重，直接推出了 AI 仿冒乐队，并将这些内容推送给用户。</p><h2 id="心理与关系"><a class="markdownIt-Anchor" href="#心理与关系"></a> 心理与关系</h2><h4 id="只需要有一个成功就够了"><a class="markdownIt-Anchor" href="#只需要有一个成功就够了"></a> <a href="https://alearningaday.blog/2025/11/28/all-it-takes-is-for-one-to-work-out-2/">《只需要有一个成功就够了》</a></h4><p>很多时候，我们并不需要所有机会都奏效，只要有一个合适的结果，就能带来转折。</p><h4 id="13-岁前拥有智能手机的孩子心理健康结果更差"><a class="markdownIt-Anchor" href="#13-岁前拥有智能手机的孩子心理健康结果更差"></a> <a href="https://abcnews.go.com/GMA/Family/kids-smartphones-age-13-worse-mental-health-outcomes/story?id=123961082">《13 岁前拥有智能手机的孩子心理健康结果更差》</a></h4><p>一项研究分析了超过 10 万名 18–24 岁的年轻人，结果发现在 13 岁之前就拥有智能手机的孩子们、成年后心理健康状况更差。</p><p>其中尤其是女孩最受影响，表现为自我形象低下、情绪韧性差、自信心不足。而男孩都表现出更少的平静感、稳定性和同理心。</p><p>在 5–6 岁就拥有智能手机的年轻女性中，约 48% 报告严重的自杀念头；相比之下，13 岁或更晚才拥有手机的女性比例为 28%。男性也有类似趋势：5–6 岁获得手机的群体中 31% 报告严重自杀念头，而 13 岁或更晚才拥有手机的群体为 20%。</p><details>      <summary>我的看法</summary>      <p>这里很让我意外的是性别上的差异：为什么女孩的负面影响更明显？整个数据的背后，实际上的因果链是怎么样的？</p><p>目前主流的心理学解释是，男孩和女孩在手机上做的事情不同，导致的心理后果也不同：</p><ul><li><p>女孩更多使用视觉主导的社交媒体。算法不断推送经过滤镜修饰的完美身材和生活，导致青春期女孩产生严重的比较心理和体貌焦虑。</p><p>此外，女孩之间的霸凌往往是关系型的（排挤、流言），手机让这种霸凌变成了 24 小时无处可逃的噩梦。</p></li><li><p>男孩更多将时间花在游戏和视频流媒体上。这导致的问题更多是现实脱节（不愿意社交、不愿意去真实世界冒险）以及同理心缺失。</p><p>此外，男孩更容易接触到极端激进的内容或暴力色情内容。</p></li></ul><p>部分读者们也提出了一些观点：</p><ul><li><p>「拥有智能手机」真的是主要因素吗？会不会它只是一个代理变量？真正的问题是社交媒体的使用、家庭环境或者其他因素呢？</p><p>我们也可以逆向思考一下：什么样的父母会在 5-6 岁就给孩子买智能手机？很可能是那些无暇照顾、或者因为自身压力大而需要一个「数字保姆」让孩子闭嘴的父母。这种家庭原本就可能缺乏情感支持。</p><p>不过即便排除了家庭因素，在富裕、关爱的家庭中，过早接触社交媒体依然与抑郁率飙升强相关。多数读者都认为智能手机的风险主要来自于社交媒体的成瘾机制和算法驱动的注意力消耗。成人都难以抵抗的东西，小孩子怎么可能抗拒得了？</p><p>也有读者认为，如果是这样的话，使用电脑访问社交媒体也会导致相同的结果。</p><p>我觉得使用电脑和使用手机之间有着明显的差异。你很难把台式机抱上床，但是手机就可以。蓝光和半夜的消息提示是青少年睡眠不足的头号杀手，而睡眠不足直接导致抑郁和情绪不稳定。</p><p>并且电脑的使用通常是块状的，而手机把注意力切成了粉末。这种持续的注意力切换会损害前额叶皮层的发育。</p></li><li><p>数据来源是自我报告问卷，样本偏差和方法学不足可能导致结论不可靠。</p></li></ul><p>如何解决这个问题，读者们的想法也是五花八门：一刀切禁止孩子们使用手机；让孩子们只使用功能机或者去智能化的手机；八年级前不给孩子智能手机…… 虽然听起来很美，但在现实中很难执行。主要是因为 <u>集体行动问题</u> —— 如果只有一个家长不给孩子买手机，这个孩子就会在学校被社会性死亡。必须当所有家长或者学校政策统一行动时，这种禁令才有效。</p>    </details><h4 id="去彩不嗨为什么你该把手机调成灰度"><a class="markdownIt-Anchor" href="#去彩不嗨为什么你该把手机调成灰度"></a> <a href="https://sami.eljabali.org/go-gray-not-cray-why-you-should-grayscale-your-phone/">《去彩，不嗨：为什么你该把手机调成灰度》</a></h4><p>作者 Sami Eljabali 建议大家将手机设置成灰度模式（Grayscale，或许应该叫黑白模式）。理由如下：</p><ul><li>让手机变无聊，这样就可以减少手机的使用时间</li><li>手机电池续航时间会变长</li><li>没有颜色后，许多通知无法通过颜色看出来。例如 WhatsApp 的绿色已读勾号</li><li>屏幕更柔和，看手机眼睛不累头不痛</li></ul><details>      <summary>我的看法</summary>      <p>我试了几天。因为稀奇，引得室友也这么做；她也推广了这个方法给其他校友。</p><p>她认为她的手机确实变得无聊起来了，视频都看不了，既然如此出门还是看书好了。顺带一提，她看的是《冷亲密》。</p><p>真要看视频的话，我们还有 iPad 和电脑。用更大的屏幕看，对眼睛的负担也远比用手机要小得多。</p><p>至于图片，我自己部署了一个 Immich，手机的照片可以自动上传到电脑上。不过有时候确实会麻烦，室友的方案是改回普通模式查看，看完就改回灰度模式。</p><p>不过这个方法并没有 Eljabali 说的那么好。如果你用手机看文字或者黑白漫画，调成灰度模式并不会影响到你什么。比如说我就喜欢早上起来赖床看漫画。</p><p>真正减少手机使用时间的方法永远都不是调个设置那么简单。大家还是需要从现实生活中下手。</p>    </details><h4 id="优化动力"><a class="markdownIt-Anchor" href="#优化动力"></a> <a href="https://muratbuffalo.blogspot.com/2025/12/optimize-for-momentum.html">《优化动力》</a></h4><p>作者 Murat Demirbas 提出，在工作和创造过程中，动力比完美更重要。与其追求一次性做到最好，不如保持持续的推进力，让事情不断向前发展。</p><p>那么如何优化动力呢？首先让开始变得容易起来，其次避免复杂的流程和过度的审批，最后维持连续性、哪怕只有微小的进展。</p><h2 id="科学与自然"><a class="markdownIt-Anchor" href="#科学与自然"></a> 科学与自然</h2><h4 id="没有什么别的东西看起来像它们拯救日本极其罕见的雪怪"><a class="markdownIt-Anchor" href="#没有什么别的东西看起来像它们拯救日本极其罕见的雪怪"></a> <a href="">《「没有什么别的东西看起来像它们」：拯救日本极其罕见的「雪怪」》</a></h4><p>作者 Mizuki Uchiyama 介绍了日本藏王山冬季独特的自然奇观「雪怪」，也就是​<ruby>樹氷<rt>じゅひょ</rt></ruby>，并强调它们正因气候变化和虫害而迅速消失，当地科学家和政府正在努力保护这一罕见景观。</p>​<ruby>樹氷<rt>じゅひょ</rt></ruby>到底是什么？当强劲的冬季西风携带过冷水滴并在树枝上冻结时，逐渐形成厚厚的霜雪层，树木会膨胀成幽灵般的巨大冰雕。这种现象需要极为罕见的气象条件：持续强风（约每秒 26 米）、气温在 -6.3℃ 至 -0.1℃ 之间，以及高液态云含量。<p>问题在于，气温升高和风向变化使形成条件越来越少。同时，自 2013 年以来，毛虫等害虫开始啃食冷杉针叶和枝条，削弱了树木的基础，大量冷杉也因虫害和积雪压力折断或死亡，使​<ruby>樹氷<rt>じゅひょ</rt></ruby>难以形成。</p><h4 id="为什么自闭症不应被视为单一疾病"><a class="markdownIt-Anchor" href="#为什么自闭症不应被视为单一疾病"></a> <a href="https://www.economist.com/science-and-technology/2025/12/03/why-autism-should-not-be-treated-as-a-single-condition">《为什么自闭症不应被视为单一疾病》</a></h4><p>自闭症是一个复杂的谱系！它涵盖了差异极大的群体：有些人社交能力较弱但能独立生活，有些人则伴随严重智力障碍、需要全天候照护。</p><p>将这些不同情况都归入「自闭症」标签，可能模糊了研究和干预的方向。</p><h4 id="自闭症的那些令人困惑的表亲们"><a class="markdownIt-Anchor" href="#自闭症的那些令人困惑的表亲们"></a> <a href="https://www.psychiatrymargins.com/p/autisms-confusing-cousins">《自闭症的那些令人困惑的表亲们》</a></h4><p>作者 Awais Aftab 也讨论了自闭症与其他相似或容易混淆的精神障碍之间的关系。</p><p>一些与自闭症症状相似的障碍在公众认知度上差异很大，导致很多人更倾向于自我诊断为「更知名」的自闭症，而忽视其他可能的解释。精神科医生在临床中经常遇到患者坚信自己是自闭症，但实际上需要更细致的鉴别诊断。</p><p>这是一些 Aftab 举例的「自闭症的表亲们」：</p><ul><li>分裂性（Schizoid）人格障碍</li><li>分裂型（Schizotypal）人格障碍</li><li>强迫型人格障碍</li><li>社交恐惧症</li><li>边缘性人格障碍</li><li>社交沟通障碍</li><li>创伤相关障碍</li><li>社交尴尬（非正式诊断）</li><li>其他影响自闭症鉴别诊断的疾病<ul><li>选择性缄默症</li><li>智力障碍（不含自闭症）</li><li>刻板运动障碍</li><li>注意力缺陷 / 多动障碍（ADHD）</li><li>精神分裂症谱系障碍</li><li>回避型人格障碍</li><li>依恋障碍</li><li>广泛性焦虑障碍</li><li>强迫症</li><li>雷特氏综合征</li></ul></li></ul><details>      <summary>我的看法</summary>      <p>美国有个不礼貌的俚语，叫做 <em>xxx is on spectrum</em>，意思是某人行为古怪，因为他有自闭症。虽然只是俚语，但有时候人们这么说就是为了侮辱他人。把「自闭症」拿来当作侮辱用语，实在令人难过。不只是研究的方向需要调整，人民对于自闭症的看法也要改变。毕竟不论是谁，最终都会回到社会去。</p><hr><p>在我阅读 <a href="/posts/dc84.html#%E4%B8%8D%E5%8E%9F%E8%B0%85%E4%B9%9F%E6%B2%A1%E5%85%B3%E7%B3%BB">《不原谅也没关系》</a> 时，作者就有提到过 CPTSD 幸存者非常非常容易被误诊成其他病症，不仅仅是自闭症，也可能被误诊成<span class="emphasis">上述提到的所有</span>「自闭症的表亲们」。</p><p>我认为创伤是一个现代人需要去了解的领域，我们很多时候都误把环境带给我们的影响认为是我们的先天就有的性格、人格、特质。</p>    </details><h4 id="新研究显示阿尔茨海默病在动物模型中不仅可以被阻止或减缓还可以被逆转至完全的神经功能恢复"><a class="markdownIt-Anchor" href="#新研究显示阿尔茨海默病在动物模型中不仅可以被阻止或减缓还可以被逆转至完全的神经功能恢复"></a> <a href="https://case.edu/news/new-study-shows-alzheimers-disease-can-be-reversed-achieve-full-neurological-recovery-not-just-prevented-or-slowed-animal-models">《新研究显示：阿尔茨海默病在动物模型中不仅可以被阻止或减缓，还可以被逆转至完全的神经功能恢复》</a></h4><p>过去百年来，<u>阿尔茨海默病</u> 被视为<span class="emphasis">不可逆</span>的疾病，因此研究重点一直是「预防」或「减缓」。但这项来自凯斯西储大学（Case Western Reserve University）的研究团队的工作首次提出：即使是已经严重受损的大脑，也可能通过恢复 <u>烟酰胺腺嘌呤二核苷酸</u>（以下简称 NAD⁺）平衡而实现功能性恢复。</p><p>NAD⁺ 是细胞内最基础的辅酶之一，几乎所有活细胞都依赖它存活。它的核心作用有三层：</p><ol><li>能量代谢</li><li>DNA 修复与细胞维护</li><li>神经元长期存活</li></ol><p>随着年龄增长，NAD⁺ 水平自然下降；在阿尔茨海默病中，这种下降更严重。当 NAD⁺ 不足时，神经元无法维持关键功能、细胞修复能力下降、神经退行性变化加速。</p><p>传统的阿尔茨海默病主流假说认为，<u>β- 淀粉样蛋白斑块</u> 和 <u>tau 蛋白缠结</u> 是疾病的「根因」。但问题是，清除这些斑块并不等同于恢复认知，多项针对蛋白沉积的临床试验都失败了。</p><p>研究团队据此提出一种不同于传统假说的解释框架：在他们的模型中，神经元能量系统的崩溃可能是更早期、更底层的失效，而蛋白质沉积则是随之出现的病理结果之一。</p><p>大致的逻辑是这样的：</p><pre class="mermaid-error">Mermaid render failed: Mermaid render timed out after 30s</pre><p>研究团队使用两种不同机制的阿尔茨海默病小鼠模型，都高度模拟了人类阿尔茨海默病的病理。接着在模型上做了两类实验：</p><ol><li>在疾病发生前维持 NAD⁺ 平衡 → 能预防阿尔茨海默病</li><li>在疾病已经严重时恢复 NAD⁺ 平衡 → 能逆转阿尔茨海默病</li></ol><p>他们使用的是实验室开发的药物 P7C3 - A20。与直接补充 NAD⁺ 前体不同，该药物的作用是减缓 NAD⁺ 在病理状态下的消耗，帮助细胞维持其正常稳态，而不是把水平人为推高。</p><div class="danger warning"><p>不过市售 NAD⁺ 前体在动物实验中可能导致癌症风险。</p></div><p>在这两类小鼠模型中，研究者观察到大脑病理指标和认知功能均恢复至接近健康对照组的水平。这不仅仅是行为改善，还是在该动物模型定义下的系统性逆转！</p><p>但由于这只是在小鼠上做实验，如果要对人类有帮助，还需要进行严格的人体临床试验。</p><h2 id="技术与创造"><a class="markdownIt-Anchor" href="#技术与创造"></a> 技术与创造</h2><h4 id="cloudflare-宕机是一件好事"><a class="markdownIt-Anchor" href="#cloudflare-宕机是一件好事"></a> <a href="https://gist.github.com/jbreckmckye/32587f2907e473dd06d68b0362fb0048">《Cloudflare 宕机是一件好事》</a></h4><p>作者 jbreckmkcye 认为，Cloudflare 这次大规模宕机事件虽然短期内让许多网站和服务瘫痪，但从长远来看却是一件好事。</p><p>Cloudflare 是如何宕机的呢？只不过是一个配置错误而已，不过它确实导致了全球大量网站无法访问，凸显了 <strong>互联网基础设施过度集中在少数几家公司</strong> 身上的风险。</p><p>jbreckmkcye 指出，这种集中化让单点故障的影响被无限放大，而这次事故迫使开发者和企业重新思考冗余设计、分布式架构，以及避免把所有流量都交给一家供应商。</p><p>换句话说，人们开始意识到鸡蛋不能放在同一个篮子里了，赛博鸡蛋也一样。</p><h4 id="谷歌移除了我整个-bear-blog-的索引而我不明白为什么"><a class="markdownIt-Anchor" href="#谷歌移除了我整个-bear-blog-的索引而我不明白为什么"></a> <a href="https://journal.james-zhan.com/google-de-indexed-my-entire-bear-blog-and-i-dont-know-why/">《谷歌移除了我整个 Bear Blog 的索引，而我不明白为什么》</a></h4><p>作者 James Zhan 的 Bear Blog 在上线一个月后，被谷歌移除了整个网站的索引，所有文章从搜索结果中消失。</p><p>Zhan 排查了所有可能原因，但都不是问题。谷歌对此没有任何解释，导致他只能将博客迁移到他现在发布文章的这个站点。</p><details>      <summary>我的看法</summary>      <p>我真的不明白 Google Search Console 这种平台是如何运作的。</p><p>我的项目有着一个很漂亮的 sitemap，但是谷歌只选择索引了四个网页 —— 这四个网页其实是同个，所以因为「重导向」，最终只有一个页面被索引。</p><p>但我还有几十个页面没有被索引呢。</p>    </details><h4 id="大多数技术问题实际上是人的问题"><a class="markdownIt-Anchor" href="#大多数技术问题实际上是人的问题"></a> <a href="https://blog.joeschrag.com/2023/11/most-technical-problems-are-really.html">《大多数技术问题实际上是人的问题》</a></h4><p>作者 Joe Schrag 指出，许多看似纯粹的技术问题，其根源往往在于人和组织层面的因素 —— 需求不明确、沟通不畅、管理失误、个人习惯或抗拒改变等。技术债务、重复劳动和低效解决方案，背后其实是人际关系和组织文化的问题。</p><p>很多工程师以为只要埋头写代码就能解决问题，忽视了组织政治和沟通的重要性。结果往往是项目周期过长、失去管理层信任。代码又承载了编写者的性格和习惯。抗拒变革的人往往不会为未来留出空间，导致技术债务不断累积。</p><h4 id="css-设计中的不完整错误列表"><a class="markdownIt-Anchor" href="#css-设计中的不完整错误列表"></a> <a href="https://wiki.csswg.org/ideas/mistakes">《CSS 设计中的不完整错误列表》</a></h4><p>该 Wiki 页面展示了一系列 CSS 早期设计中的历史遗留错误。</p><h4 id="人工智能时代的批判性思维"><a class="markdownIt-Anchor" href="#人工智能时代的批判性思维"></a> <a href="https://addyo.substack.com/p/critical-thinking-during-the-age">《人工智能时代的批判性思维》</a></h4><div class="danger warning"><p>我会多次混用 AI、LLM、人工智能这三个词，主要是看引用的文章是如何称呼这个概念的。总之它们很多情况指的都是同个东西，根据上下文分辨吧。</p></div><p>作者 Addy Osmani 使用了十分经典的 5W1H 框架，来阐述在 AI 时代保持批判性思维的重要性。</p><blockquote><ul><li>谁：不要依赖 AI 作为神谕。验证其输出。</li><li>什么：在急于寻求解决方案之前，先定义真正的问题。</li><li>在哪里：上下文为王。在沙盒中有效的修复可能会在生产环境中出现问题。</li><li>何时：知道何时使用快速启发法（初步判断）与深度分析（根本原因）。</li><li>原因：使用「5 个为什么」技巧来找出根本原因。</li><li>如何：用证据和数据沟通，而不仅仅是依靠观点。</li></ul></blockquote><p>AI 可以生成看似合理的答案，但真正的价值在于人类能否用批判性思维去验证、质疑和完善这些答案。</p><h4 id="自信的白痴问题为什么-ai-需要硬性规则而不是氛围检测"><a class="markdownIt-Anchor" href="#自信的白痴问题为什么-ai-需要硬性规则而不是氛围检测"></a> <a href="https://steerlabs.substack.com/p/confident-idiot-problem">《「自信的白痴」问题：为什么 AI 需要硬性规则，而不是氛围检测》</a></h4><p>作者 Steer Labs 批评了当前 AI 系统常常表现为「自信的白痴」：即使答案错误，仍然以极高的自信给出看似合理的结果。</p><p>当前行业趋势是用更大的模型来评估小模型的输出。但如果底层模型本身存在幻觉或迎合用户的倾向，评估模型也会被误导。这也就会形成一个危险的循环依赖：错误被「打分」成正确。</p><p>Labs 认为依赖「用一个模型去评估另一个模型」只是「用概率修补概率」，无法解决根本的问题。解决之道是引入硬规则和确定性验证层，而不是依赖「氛围检测」。</p><p>软件工程中有确定性机制，例如单元测试。Labs 认为 AI 系统也需要类似的验证层，因此，他开发了一个轻量的 Python 库 <code>Steer</code>。</p><h4 id="最高质量的代码库"><a class="markdownIt-Anchor" href="#最高质量的代码库"></a> <a href="https://gricha.dev/blog/the-highest-quality-codebase">《最高质量的代码库》</a></h4><p>作者 Greg Pstrucha 做了一个邪恶的实验：让 Claude Code 连续 200 次自动改进同一个代码库。</p><p>结果是，原本 2 万行代码（近一半为测试）变成了 8 万行代码，其中有 6 万为测试。注释也从 1500 行变成了近 2 万行。</p><p>那么 Claude Code 都做了什么呢？：</p><ul><li>重造轮子，写了 2 万行自制工具函数</li><li>强行 Rust 化</li><li>假装自己是安全工程师</li><li>过度追求虚荣指标，如更多的测试、注释、类型检查和更高的覆盖率</li></ul><p>这意味着，AI 会把「质量」误解为「数量增长」与「指标堆叠」。</p><p>它根本不理解什么是可维护性、复杂度控制、实际业务需求、真实的工程权衡…… 于是生成了一个看起来很努力，但完全不可维护的代码怪兽。</p><h4 id="词袋饶了我们吧"><a class="markdownIt-Anchor" href="#词袋饶了我们吧"></a> <a href="https://www.experimental-history.com/p/bag-of-words-have-mercy-on-us">《词袋，饶了我们吧》</a></h4><p>作者 Adam Mastroianni 表示，LLM 并不是人类，它们只是「词袋」系统，依靠统计模式生成文本。试图用人类心理学来理解它们是错误的，它们的价值在于帮助我们思考和测试，而不是取代人类的思维。</p><p>很多人把 LLM 当作「聪明的助手」，甚至认为它们有意识。这是一个很常见的误解。LLM 并不是人，它们不会「思考」，只是统计模式的产物。</p><p>Mastroianni 认为，LLM 的价值在于它们能帮助我们测试和澄清想法。例如在编程中，代码可以被验证，因此 LLM 的输出更有用。但是在政策或哲学问题上，LLM 的答案不可验证，因此风险更大。</p><h4 id="关于大规模消费人工智能生成内容"><a class="markdownIt-Anchor" href="#关于大规模消费人工智能生成内容"></a> <a href="https://www.sh-reya.com/blog/consumption-ai-scale/">《关于大规模消费人工智能生成内容》</a></h4><blockquote><p>「我可能要疯了，因为我现在读的东西有一半听起来像 ChatGPT。」</p></blockquote><p>作者 Shreya Shankar 借这条推文，想要好好讨论现在大规模消费 AI 生成的内容所带来的两个主要问题：</p><ol><li><p>AI 过度使用修辞和沟通工具，导致这些工具失去原本的区分度。</p><p>比喻、强调句、加粗等原本帮助理解的写作手法被 AI 滥用。一旦这些内容被滥用，我们作为读者便会习惯，然后忽略它们。</p><p>有一个可怜的标点符号就因为 AI 写作而被大家厌恶：破折号。希望大家可以多多关心一下破折号，我还挺喜欢它的。</p></li><li><p>生成变得极其容易，但验证仍然昂贵，使人们更难判断信息的真伪与质量。</p><p>AI 生成的文献综述可能引用正确的学者，但编造了标题或作者。又或者说 AI 生成的代码看似合理但缺乏边界条件。</p><p>这就很像一句话：「造谣一张嘴，辟谣跑断腿。」</p></li></ol><p>Shankar 想出了一些解决方向，虽然她认为这些方向不够完美，但还是可以给我们用于参考：</p><ol><li>教 AI 不要机械地套用技术，而要理解其背后的使用场景。</li><li>让 AI 引用真实的人类经验，而不是假装自己有体验。</li><li>确保 AI 系统的判断仍然依赖人类的经验与验证。</li></ol><details>      <summary>我的看法</summary>      <p>我在日常生活中没少使用 AI，于是我在阅读其他人的文章时，很轻易便能看出来什么地方用了 AI。</p><p>不过我并不是想要指责任何人。我从来都不认为 AI 是一个杀千刀的玩意儿、谁用谁垃圾。你用过 AI 的话，也能从我的文章中发现许多使用 AI 的痕迹。</p><p>问题在于，我们能够无意识中发现并且怀疑，这毫无疑问地会降低我们阅读文章时的参与感和价值感：「这东西是 AI 写的，那是不是不可信？这个作者是不是也不可信？」</p><p>例如这个文章在 Hacker News 的评论区，就有人指出写作风格、段落结构和用词习惯都像是 AI 生成。</p><p>当然了，没有人会因为用 AI 写了东西而被否定价值。这里说的只是主观想法 —— 甚至都不是「想法」，很多时候都是潜意识。</p><p>有一个许多人担心的点是，任何写得整齐、没有明显错误的文章也会被怀疑是 AI 生成的。目前我在绘画上看到了不少 —— 许多人类画师被「AI 小警察」质疑作品是 AI 生成，怒而放出绘画过程视频作为证据，却只能看着对方装死不回复。还是那句话，<span class="emphasis">造谣一张嘴，辟谣跑断腿。</span></p>    </details><h4 id="llm-是一场失败-新一轮人工智能寒冬即将来临"><a class="markdownIt-Anchor" href="#llm-是一场失败-新一轮人工智能寒冬即将来临"></a> <a href="https://taranis.ie/llms-are-a-failure-a-new-ai-winter-is-coming/">《LLM 是一场失败。新一轮人工智能寒冬即将来临》</a></h4><p>作者 Taranis 认为，LLM（大型语言模型）虽然一度被视为突破性的技术，但如今已显露出根本性的局限，甚至可能引发新一轮的「AI 寒冬」。</p><p>随着模型规模不断扩大，它们生成的错误往往更加「逼真」，只有专家才能识别。这使得 LLM 在医学、教育评估、执法、税务等关键领域完全不可接受，因为错误率带来的风险过高。</p><p>与此同时，即便是在编程辅助等场景，幻觉代码也可能导致严重漏洞和维护负担。</p><p>更为严峻的是，目前企业界约有 95% 的生成式 AI 项目已经失败，投资和基础设施支出也可能很快崩塌。或许少数「杀手级应用」能够幸存，但大多数用例终将消失。</p><p>未来，我们仍可能在文本编辑器或学生作业中看到 AI 的身影，但整体行业势必经历剧烈收缩。</p><div class="reply-block h-entry"><div class="post-meta p-author h-card visually-hidden"><img class="u-photo" src="https://blog.cytrogen.icu/favicon.png" alt="Cytrogen" loading="lazy"><span class="p-name">Cytrogen</span><a class="u-url" href="https://blog.cytrogen.icu">https://blog.cytrogen.icu</a></div><time class="dt-published visually-hidden" datetime="2026-09-17T20:48:25.719Z">2026-09-17T20:48:25.719Z</time><a class="u-url visually-hidden" href="https://blog.cytrogen.icu">Post Link</a><div class="reply-content e-content"><h4 id="不做信息的消费者从写周刊开始"><a class="markdownIt-Anchor" href="#不做信息的消费者从写周刊开始"></a> <a href="https://www.geedea.pro/essays/why-blog-weekly/">《不做信息的消费者，从写周刊开始》</a></h4><p>什么是信息的消费？输入信息到自己的脑子里。</p><p>作者 Eltrac 认为，现代人容易陷入到这种 <u>信息消费主义</u> 中，妄想通过消费来解决问题。实际上，它们通常只能解决短期的情绪问题，却 <strong>无法触及真正的结构性矛盾</strong>。</p><p>你以为自己在变得更懂、准备得更充分，但大多数时候只是用新的输入来麻痹焦虑、逃避负反馈。信息被摄入，却没有被加工、吸收或转化，最终只留下更深的空虚与疲惫。</p><p>写周刊则可以记录自己学习到了什么，也就是从自己的脑子里输出信息。你会回顾自己的一周：做了什么、没做什么、什么信息毫无价值、什么东西是自己的思考盲点……</p><details>      <summary>我的看法</summary>      <p>我很喜欢阅读周刊、半月刊、月刊、不定刊…… 也订阅了许多。</p><p>在我看来，期刊大致可以分为两种：以作者输出为主的，以及以向读者提供信息输入为主的。许多日记周记都是前者，后者更像是信息的整合。自然，两者结合在一起的也不少。</p><p>我很乐意通过期刊来了解作者眼里的最新的世界。注意，是「作者眼里的」。通过作者说了什么、记录什么、看了什么，很轻松就能看出这个人的大致观念如何、对什么感兴趣。这是有趣的，因为比起直白的「我是……」，这种潜移默化表示出来的样子更符合这个人真实的样子。</p><p>不费吹灰之力知道了一个知识点，确实很容易让人觉得自己「变聪明」了。我身边倒是有很多这样的例子，比如某个靠分享短视频就想要表达自己比我聪明的人。</p><p>这篇文章也算是狠狠地攻击到了我吧，因为我出于懒惰、用 AI 总结文章的次数并不算少。</p>    </details></div><div class="reply-meta p-in-reply-to h-cite"><span class="reply-label">回复：</span><a class="reply-target u-url" href="https://www.geedea.pro/essays/why-blog-weekly/">https://www.geedea.pro/essays/why-blog-weekly/</a></div></div><h4 id="我为什么写了-15-年的历史专题博客"><a class="markdownIt-Anchor" href="#我为什么写了-15-年的历史专题博客"></a> <a href="https://resobscura.substack.com/p/why-i-have-been-writing-a-niche-history">《我为什么写了 15 年的历史专题博客》</a></h4><p>作者 Benjamin Breen 回顾了自己从 2010 年开始写 Res Obscura 历史博客至今 15 年的经历，解释了为什么在社交媒体和短视频盛行的时代，他仍坚持写这种小众的专题博客。</p><details>      <summary>关于 Niche Blog</summary>      <p>上个月我链接了一个 <a href="/posts/31df.html#%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E5%8F%88%E5%9B%9E%E6%9D%A5%E4%BA%86%E5%88%A9%E5%9F%BA%E5%8D%9A%E5%AE%A2%E6%98%AF%E4%B8%8D%E6%98%AF%E4%B9%9F%E8%AF%A5%E5%A4%8D%E5%85%B4%E4%BA%86">文章</a>，讲的就是 Niche Blog。因为偷懒，我直接取了「利基市场」里的音译「利基」、安在了「博客」上，最终得出「利基博客」一词。然后便很应得地被读者吐槽了……</p><p>人不能偷懒，该严谨还是严谨点。</p><p>无论是上个月链接的文章还是现在链接的文章，这两篇文章使用的 <em>Niche Blog</em> 都是「作者在一个特定领域下不停钻研，无论是什么领域、赚不赚钱」。</p><p>如果如果是和「利基市场」相关、带有商业意味的博客，我认为可以翻译为「利基博客」；如果和钱关系不大，而是作者在某个特定主题上长期钻研，那就更适合叫「专题博客」。</p><p>所以这两篇文章的标题，都应该使用「专题博客」，而不是「利基博客」。</p><p>至于为什么不叫「专业博客」，是因为我看到「专业」二字第一时间想到的是 <em>Professional</em>，即职业上的专业。你喜欢聊石墩子，也可以写个和石墩子有关的 Niche Blog，不过聊石墩子本身不是一个工作。</p>    </details><h4 id="markdown-限制了你"><a class="markdownIt-Anchor" href="#markdown-限制了你"></a> <a href="https://newsletter.bphogan.com/archive/issue-45-markdown-is-holding-you-back/">《Markdown 限制了你》</a></h4><p>作者 Brian Hogan 提出，虽然 Markdown 容易上手、写作速度快、可读性强，并且广泛应用，但是还是存在着许多问题：</p><ul><li><p>Markdown 主要是排版语言，只能表达「看起来像标题」、「看起来像列表」，但是无法说明这些内容在逻辑上是什么。人类看的话可以推出上下文，但是对于机器而言就不行了。</p><p>这样说可能会有点绕，所以我就举个例子：</p><p>这是一个 Markdown：</p><pre><code class="language-markdown"># 安装- 安装依赖- 配置环境变量- 运行测试</code></pre><p>这三个列表项是「步骤」吗？还是「要点」？有没有先后约束、前置条件、失败回滚？Markdown 是无法表达这些内容的。</p><p>一个语义化格式，如 AsciiDoc 和 DocBook，则会是这样的：</p><pre><code class="language-markdown">= 安装.Step 1: 安装依赖.Step 2: 配置环境变量.Step 3: 运行测试[requires=Step 1,Step 2][fallback="清理缓存并重试"]</code></pre><p>后者的优势在于，可以明确「步骤」的类型、顺序、依赖、异常分支等，工具可以将这个内容解析为流程图、校验顺序，或者生成操作手册和自动化脚本。</p></li><li><p>Markdown 的语法太简单，缺乏上下文。AI 或搜索引擎会更喜欢结构化的 HTML / XML，因为它们能够明确标记「这是命令」、「这是注释」，而 Markdown 无法提供这样的信息。</p><p>再就是 Markdown 语义过于贫乏，如果作为源的话根本无法拿来做「多格式输出」。结构化文档可以导出成 Markdown，那反过来呢？要如何让没有语义标签的 Markdown 导出为有语义标签的格式呢？</p></li><li><p>Markdown 没有统一标准，存在 CommonMark、GitHub-Flavored 等不同版本。</p></li></ul><p>Hogan 觉得在写 README 或短期文档的方面上，Markdown 依然很合适，在复杂的场景上则可以改用这些格式（可以查看原文看看示例）：</p><ul><li>reStructuredText</li><li>AsciiDoc</li><li>DocBook</li><li>DITA</li></ul><details>      <summary>我的看法</summary>      <p>我就是用 Markdown 写博客和记笔记的。我认为，Markdown 的普及性和兼容性已经在这场「战斗」中胜出了。大多数场景下 Markdown 已经够用，我这里说的「大多数场景」也包含非技术领域。Markdown 的学习门槛实在是低的不行，用来写作或者记笔记已经比 LaTeX 或者 HTML 方便不少。当需要添加复杂需求的时候，再嵌入 HTML 或者工具扩展。至少我现在就是这么做的。</p><p>我也有看到有人使用一些工具来扩展 Markdown 的功能，例如：</p><ul><li>Pandoc</li><li>Quarto</li><li>Docusaurus</li></ul>    </details><h4 id="让-rss-更有趣"><a class="markdownIt-Anchor" href="#让-rss-更有趣"></a> <a href="https://matduggan.com/making-rss-more-fun/">《让 RSS 更有趣》</a></h4><p>作者 Mathew Duggan 认为传统 RSS 阅读器虽然轻量、隐私友好，但在用户体验上过于严肃，容易让人产生压力 —— 让人感觉有无尽的「待读积压」，像任务清单一样。他不想按时间顺序读完所有内容，而是希望打造一种更轻松、有趣的方式来消费 RSS 内容，类似于 TikTok 的随机推送体验。</p><p>因此 Duggan 做了个 Firefox 浏览器扩展，点击按钮即可获得新网站。可惜我不使用 Firefox，写到这里的时候他也没有发布 Chrome 版本的扩展，所以只能通过其他使用者来猜测是什么样的。</p><details>      <summary>我的看法</summary>      <p>我实在是无法苟同这个观点啦。</p><p>首先是我对 RSS 阅读器的看法就和 Duggan 完全不同了。RSS 阅读器并不会让我感到有压力：不想看就放着不要看了，反倒是 TikTok 那样的短视频平台的推送会让我倍感压力。</p><div class="reply-block h-entry"><div class="post-meta p-author h-card visually-hidden"><img class="u-photo" src="https://blog.cytrogen.icu/favicon.png" alt="Cytrogen" loading="lazy"><span class="p-name">Cytrogen</span><a class="u-url" href="https://blog.cytrogen.icu">https://blog.cytrogen.icu</a></div><time class="dt-published visually-hidden" datetime="2026-09-17T20:48:25.796Z">2026-09-17T20:48:25.796Z</time><a class="u-url visually-hidden" href="https://blog.cytrogen.icu">Post Link</a><div class="reply-content e-content"><p>我喜欢这个观点：RSS 像邮件的客户端，我们可以逐条阅读并保持秩序感。看到未读，就点开看看；不重要的内容就直接略过或删除；重要的内容则收藏归档，方便以后再读。我阅读邮件也是相同的方式。</p><p>Spike 曾经提到过一个 <a href="https://taxodium.ink/nichijou-6.html#73537C35-2E65-424A-89D3-C1C0F3773D3F">归类订阅流的方式</a>，对我而言挺有帮助的，或许也可以帮到你们：划分多个区域，将你对不同订阅源的关注程度分层管理 —— 常读的放在靠近中心的区域，偶尔浏览的放在外围区域，这样既能避免信息过载，也能更清晰地掌握优先级。</p><p>这种模式让我觉得 RSS 是一个我能掌控的信息工具，而不是像 TikTok 那样不断推送、让我被动接受的娱乐流。说真的如果我想要看算法给我展示的内容的话，我大可以去继续看小红书这样的平台，上面的优质内容真不少。就是因为受不了自己一直在刷，我才开始慢慢培养订阅博客的习惯。</p></div><div class="reply-meta p-in-reply-to h-cite"><span class="reply-label">回复：</span><a class="reply-target u-url" href="https://taxodium.ink/nichijou-6.html#73537C35-2E65-424A-89D3-C1C0F3773D3F">https://taxodium.ink/nichijou-6.html#73537C35-2E65-424A-89D3-C1C0F3773D3F</a></div></div><p>话又说回来，Duggan 这样的做法还是蛮有意思的。对一些希望被动接收信息的人来说，这正好满足了他们的需求。毕竟 RSS 终究还是一个底层协议，想要怎么用都完全根据读者们的喜好。</p><hr><p>该月刊还有一天就要发布的时候，我检查了一下这个文章，发现 Duggan 在文章里贴的链接不能用了。如果大家好奇的话，可以直接安装这个 Firefox <a href="https://addons.mozilla.org/en-US/firefox/addon/time-waster-pro/">扩展</a>。至于 Chrome 系，他估计不会做。</p>    </details><h4 id="用静谧技术探索独立网络"><a class="markdownIt-Anchor" href="#用静谧技术探索独立网络"></a> <a href="https://alexsci.com/blog/calm-tech-discover/">《用静谧技术探索独立网络》</a></h4><p>作者 Robert Alexander 讨论了如何通过静谧技术来发现和参与独立网络，避免社交媒体的噪音与精神负担。</p><p>他引用了 <em>Calm Technology</em> 一词。该术语的核心含义是：技术应该在背景中默默运行，不打扰用户的注意力，只在必要时才进入前台。我这边就翻译成「静谧技术」了，「静谧」有着「心境上的宁静」的意思，我认为这么翻译很美。</p><p>回到正题，Alexander 认为最初的社交媒体承诺连接人与人，但如今已变成充满通知、点赞、广告和无尽滚动的精神负担，就像是「海妖的歌声」，诱惑人们沉迷其中。他推荐了一些浏览器扩展：</p><ul><li><p><a href="https://streetpass.social/">StreetPass for Mastodon</a>，可在用户浏览网页时自动发现 Mastodon 验证链接，并悄悄收集这些账号。</p><p>静谧技术的核心便在于，这个扩展不会打扰用户，而是等用户准备好时再查看。</p></li><li><p><a href="https://github.com/robalexdev/blog-quest">Blog Quest</a>，这是 Alexander 受 StreetPass for Mastodon 的启发，所开发了另一个扩展。它可以自动发现网页上的 RSS / Atom feed。</p></li></ul><h4 id="不要下载应用程序"><a class="markdownIt-Anchor" href="#不要下载应用程序"></a> <a href="https://blog.calebjay.com/posts/dont-download-apps/">《不要下载应用程序》</a></h4><p>作者 Caleb Jay Rogers 告诫我们，不要下载商家或平台的 App：因为下载 App 会让用户付出比得到的更多。原因有二：</p><ol><li><p>监控资本主义与差别定价</p><p>公司可以通过 App 获取更多用户数据，然后根据用户数据动态调整价格，例如在发薪日提高商品价格。</p><p>这样的话，价格便不再由市场决定，而是由公司根据个人情况设定。</p></li><li><p>绑定仲裁条款，放弃法律权利</p><p>下载 App 必须接受「服务条款」，其中常包含 <u>强制仲裁</u>。</p><p>后果便是，用户在发生纠纷时不能上法院，只能由公司聘请的仲裁员裁定。</p><p>一个非常著名的案例便是前段时间，一位男子的妻子在迪士尼乐园因食物中毒去世，而迪士尼竟然试图用他几年前注册 Disney+ 时的仲裁条款来阻止诉讼。这件事最终因媒体曝光才撤回，但显示了仲裁条款的危险性。</p></li></ol><details>      <summary>我的看法</summary>      <p>Oops，我是一个喜欢 App 的人。说实话，也没有什么原因，就是觉得 App 很专业。我个人没未想过下载 App 可以有这样的后果，实在是让人后怕。</p><p>我看到过许多人推荐使用 PWA，或许我也应该慢慢转向使用 PWA 而不是 App。较为可悲的是，许多主流产品都是 App 比网页版做得更好，例如淘宝。</p>    </details><h4 id="优秀的工程管理是一种时尚"><a class="markdownIt-Anchor" href="#优秀的工程管理是一种时尚"></a> <a href="https://lethain.com/good-eng-mgmt-is-a-fad/">《「优秀的工程管理」是一种时尚》</a></h4><p>作者 Will Larson 提出一个观点：「优秀的工程管理」只是一个时代性的潮流。这是因为不同阶段的行业环境塑造了不同的管理模式，意味着「好管理」并不是一个永恒的标准，而是会随着经济环境和技术趋势而变化。</p><p>我在阅读 <a href="/posts/dc84.html#%E9%87%8D%E6%96%B0%E5%AE%9A%E4%B9%89%E5%85%AC%E5%8F%B8%E8%B0%B7%E6%AD%8C%E6%98%AF%E5%A6%82%E4%BD%95%E8%BF%90%E8%90%A5%E7%9A%84">《重新定义公司：谷歌是如何运营的》</a> 时也发现了这一点。这本书的作者批评了传统企业的各个做法，但是并没有全面否定它们的价值 —— 传统企业的做法只是不符合现在这个科技时代了。</p><p>根据 Larson 的经历，大致可以分为三个时代：</p><ol><li>2000 年代，管理风格是「识别机会、协调组织」，而不是关注个人成长。</li><li>2010 年代，行业强调「吸引、留住、激励工程师」，经理被要求停止写代码，专注于人事管理。这是因为招聘是增长瓶颈，管理的「好坏」被定义为能否留住人才。</li><li>2020 年代，组织被「扁平化」，很多协调角色被要求重新写代码。过去被认为是「好经理」的人，现在被视为「官僚」。</li></ol><p>然而人们普遍认为，这是因为「企业管理正在从糟糕变得有效」。这是一种道德叙事上的批判，因为我们现在觉得傻的管理方式，在过去就是最优解。根本没有糟糕不糟糕一说，只有合不合适现在的经济环境。</p><p>Larson 还总结了八项工程管理技能，分为「核心技能」和「成长技能」。详细的内容可以看原文，Larson 解释的非常清楚，我就不画蛇添足了。</p><p>Larson 还提到了一个我觉得有意思的点：理想的工作分配不是数学最优，而是能让你保持长期精力和动力。有些你喜欢做的事情，尽管不完全有利于团队，也可以适度保留。</p><h4 id="像你说的那样弃用它"><a class="markdownIt-Anchor" href="#像你说的那样弃用它"></a> <a href="https://entropicthoughts.com/deprecate-like-you-mean-it">《像你说的那样弃用它》</a></h4><p>作者 Chris 指出，弃用警告几乎没有人理会，而这正是导致 API 移除时大量代码突然崩溃的根本原因。</p><p>理由如下：</p><ul><li>弃用警告不会让事情立刻坏掉</li><li>延迟修复的「成本」不明显</li><li>直到 API 真正被移除，才会有代价</li></ul><p>这是因为人类不擅长为未来的突发变化做计划。</p><p>Chris 想了一个邪恶又有趣的解决方案：让弃用的函数偶尔返回错误结果，并随着时间推移逐渐提高错误频率。这样就可以让开发者更早修复，而不是等到移除当天才手忙脚乱。</p><p>当然，这只是他在讽刺而已。他的真实建议是保持 API 的瑕疵，不要用这种方式折磨用户。</p><h4 id="创造能触动人心的软件"><a class="markdownIt-Anchor" href="#创造能触动人心的软件"></a> <a href="https://rapha.land/craft-software-that-makes-people-feel-something/">《创造能触动人心的软件》</a></h4><p>作者 Raphael Amorim 认为，软件创作应该让人有感觉，而不是机械地重复生产。灵感、乐趣与个人表达比「成功」「开源」「大众化」更重要。</p><p>他原本在开发一个编辑器，叫 Boo。这是一个为自己做的编辑器，但他逐渐发现 Boo 和另一个他正在开发的软件 Rio Terminal 有许多相似之处，导致了重复工作和创作疲劳。因此他暂停开发 Boo，转去开发编程语言。待语言成熟后，再用它来重写 Boo。</p><p>Amorim 真正想做的事情，是创造一个让人记住的软件：人们一旦体验了，便终生难忘。</p><h4 id="菜单上的图标无处不在求助"><a class="markdownIt-Anchor" href="#菜单上的图标无处不在求助"></a> <a href="https://blog.jim-nielsen.com/2025/icons-in-menus/">《菜单上的图标无处不在 —— 求助》</a></h4><p>作者 Jim Nelson 批评了现代软件设计中「菜单项无处不在的图标」现象，认为这种设计理念并没有改善用户体验，反而让界面显得杂乱和冗余。</p><p>现在越来越多的应用在菜单的每一个选项旁边都加上图标。不仅是顶部菜单，连右键上下文菜单也充满了图标。Nelson 表示，自己从未喜欢这种「默认加图标」的理念，认为这是一种过度设计。图标本应帮助用户快速识别功能，但在菜单中每个选项都有图标时，反而失去了区分度。</p><p>这种趋势可能源于设计系统的统一化：设计师和开发者倾向于「规范化」，把图标作为默认元素。但作者认为这是一种「形式大于功能」的做法，忽视了用户真正的使用体验。</p><details>      <summary>我的看法</summary>      <p>如果看原文里举的例子的话，可以立马明白 Nelson 什么意思。</p><p>我之前都没有考虑过这件事，导致我在项目里做出了这样的东西：</p><p><img src="/posts/b211/image-20251227010502034-1766815507339-4.webp" alt="image-20251227010502034" loading="lazy"></p><p>嗯…… 有些图标确实不是必需的。</p><p>这件事让我想起了一两个月前读到的 <a href="https://emilkowal.ski/ui/you-dont-need-animations">一篇文章</a>，批评的是在网页里使用太多动画。这世上的所有东西都有一个平衡度。用太多或者太少都不好，或许大师就是可以把握这个度的人。</p>    </details><h4 id="形同拒绝的联系页面"><a class="markdownIt-Anchor" href="#形同拒绝的联系页面"></a> <a href="https://www.nicchan.me/blog/the-f-off-contact-page/">《形同拒绝的联系页面》</a></h4><p>作者 Nic Chan 回忆自己曾为一家设计公司做网站改版。该公司主营全套设计服务，但收入中很大一部分来自一些小型任务。这些小任务虽然客户自己也能做，但交给专业人士更省时，因此成为重要收入来源。</p><p>不过，在改版过程中，客户要求设置一个「联系页面」，但设计方式让人几乎无法真正联系到他们。比如：</p><ul><li>页面上只有模糊的指引或复杂的表单</li><li>缺乏清晰的联系方式</li></ul><p>Chan 表示，这种页面就是所谓的 <em>fuck off contact page</em> —— 企业表面上提供了联系渠道，但实际上是阻止用户接触。</p><h4 id="阻止坏人使用我的开源项目"><a class="markdownIt-Anchor" href="#阻止坏人使用我的开源项目"></a> <a href="https://evanhahn.com/stopping-bad-guys-from-using-my-open-source-project/">《阻止坏人使用我的开源项目》</a></h4><p>作者 Evan Hahn 指出了一个看似简单却极具争议的问题：开源项目是否应该允许任何人、不加限制地使用？</p><p>Hahn 维护着一个在 npm 上有超过 2 亿次下载的的开源包。虽然它默默嵌入在成千上万的项目中，但并不为人熟知。然而，正因为它的广泛使用，他开始担心 —— 大型公司和所谓的「坏人」正在免费利用这些成果，却没有任何回馈。</p><p>因此，Hahn 提出了一系列问题：</p><ul><li>是否应该改变许可证，避免 MIT 这种「任何目的都可用」的完全自由？</li><li>是否可以通过文档或博客呼吁，来引起更多关注？</li><li>是否需要集体行动，让更多维护者联合起来？</li><li>是否可以先在一些不太流行的项目上做实验？</li></ul><h4 id="阻止邪恶与开源我的想法"><a class="markdownIt-Anchor" href="#阻止邪恶与开源我的想法"></a> <a href="https://blog.liw.fi/posts/2025/stop-evil/">《阻止邪恶与开源：我的想法》</a></h4><p>作者 Lars Wirzenius 回应了上一篇《阻止坏人使用我的开源项目》的讨论。</p><p>他不赞成通过修改开源许可证来阻止坏人使用软件</p><p>在他看来，这样做并不能真正阻止邪恶行为，反而会破坏开源生态。开源之所以能繁荣，是因为它允许开发者在没有繁琐谈判的情况下自由组合和复用代码。如果许可证开始带有排他性或限制性条款，善意的开发者反而会因为兼容性问题而无法继续构建新的应用。</p><p>其次，他强调，真正的坏人并不会在意许可证。无论是政府机构、大型企业，还是极端组织，他们都有能力无视规则，甚至凌驾于法律之上。换句话说，改变许可证只会增加好人的负担，却无法阻止坏人继续使用。</p><p>在价值观层面，Wirzenius 承认自己也希望阻止破坏生态环境的「坏人」，但他认为开源许可证不是有效的武器。他提出了另一种思路：<strong>人类社会需要通过发声、拒绝合作、抵制恶行、照顾他人、建设善意的事物来抵抗邪恶</strong>。这些方式虽然需要更多勇气和时间，但才是真正能发挥作用的长期策略。</p><h4 id="为什么我想造一台笔记本"><a class="markdownIt-Anchor" href="#为什么我想造一台笔记本"></a> <a href="https://geohot.github.io//blog/jekyll/update/2025/11/29/bikeshedding-or-laptop.html">《为什么我想造一台笔记本》</a></h4><p>作者 geohot 认为苹果笔记本质量正在下降，而自己每天使用笔记本超过 10 小时，愿意为更好的设备付出合理代价。他梦想中的笔记本是「MacBook with Linux」：由用户导向的公司支持，硬件与软件高度整合，简洁而高质量。</p><p>然而，现有的选择都存在无法满足的缺陷，因此他萌生了自己设计笔记本的念头 —— 当然，并不是真的做了台笔记本，而是构建了一个理想笔记本的蓝图，geohot 称其为 <em>hackbook</em>（黑客本？）。</p><p>对于不了解他的读者，可能需要补一下背景：这位 geohot 是美国知名黑客 George Francis Hotz，也就是 2007 年破解了 iPhone 3 的那位。后面他还破解了 PS3、开发了自动驾驶系统 comma.ai。</p><p>我不认为厂商们做不出来，很有可能是不想做：有这么好的一个笔记本电脑，谁还买新的呀，又不是苹果手机那样的类宗教产品。</p><h4 id="我是如何屏蔽所有的在线广告的"><a class="markdownIt-Anchor" href="#我是如何屏蔽所有的在线广告的"></a> <a href="https://troubled.engineer/posts/no-ads/">《我是如何屏蔽所有的在线广告的》</a></h4><p>作者 Troubled Engineer 分享了自己彻底屏蔽网络广告的实践经验。他认为广告不仅令人厌烦，还破坏了上网体验，因此展开了一场「圣战」，尝试各种方法来尽可能消灭广告。</p><p>这些是他分享的一些方案，更多请见原文：</p><ul><li><p>使用 Firefox 搭配 uBlock Origin。</p><p>用 Firefox 是因为，Google Chrome 转向 Manifest V3 后限制了广告拦截功能，使 Chromium 系浏览器更难彻底屏蔽广告。</p></li><li><p>用 Pi-hole 来进行 DNS 过滤。</p></li><li><p>托管 WireGuard 来路由自己所有的流量。</p><p>这是因为许多在线平台不会向公共云提供商的流量投放广告。</p></li><li><p>iOS 关闭后台 App 刷新。</p></li></ul><p>不过 Troubled Engineer 也提醒道，广告确实是许多创作者和平台的收入来源。如果读者们重视某些创作者或者平台，最好是通过会员订阅或捐赠支持，而不是只依赖广告屏蔽。</p><details>      <summary>我的看法</summary>      <p>我讨厌广告，所以我的博客网站一辈子都不会有广告。主要是因为我不靠写博客赚钱，部署这个博客的成本也很低：10 美元一年的域名、免费的 Netlify 托管、免费的 Cloudflare 保护……</p><p>不过我是很赞同 Troubled Engineer 的提醒。有些创作者是需要通过博客赚钱的，屏蔽广告反而会断人家财路。那要如何更灵活地决定屏蔽哪个网站呢？</p>    </details><h4 id="最小的独立博客博主"><a class="markdownIt-Anchor" href="#最小的独立博客博主"></a> <a href="https://www.weiwenchao.com/2044.html">《最小的独立博客博主？》</a></h4><p>作者希望自己 9 岁的女儿可以把学校趣事记录下来、发布到博客网站上。这样不仅可以记录自己的生活，也可以锻炼小孩子的思维能力。于是，一个可能是目前最小的独立博客博主出现在了互联网上。</p><details>      <summary>我的看法</summary>      <p>因为自己前不久也是个小孩（现在也是啦，心理层面上），感觉作者女儿到一个年纪可能就会把过去写的内容都删除，然后再到一个年纪后便会后悔删记录的举动…… 咳咳，我现在还在后悔自己扔掉了曾经写过的小说以及画过的插图。</p><p>我的妹妹和作者的女儿年纪相仿。不过因为我几乎不回家，妹妹现在在做什么我并不是很清楚，只知道她会画画和做许多运动。这个年级段的小孩子大多都是用电脑玩游戏，也就是数字的消费者，而不是数字的生产者。</p><p>我特别教过她如何开机、用鼠标点击桌面上 Roblox 的图标、用键盘操作角色。她先前有说想要学如何使用我的数位板画画，但是我的画画软件是中文的，她看不懂，我也没时间教她，最后便不了了之了。</p><p>想要让她写博客的话，首先得知道她感不感兴趣 —— 大概率不感兴趣；其次教她如何使用计算机 —— 大概率不想学习；最后鼓励她经常写博客 —— 她光是每天各种兴趣班就已经够呛啦。</p><p>我个人还会担心隐私问题。能够表达自己的自由很重要，但也需要在互联网上保护孩子们的隐私。个人网站和中心化平台之前的一个差异便是「监管」。中心化平台虽然常常因为有监管而被诟病，但是在保护孩子这一方面上，监管可以避免孩子们接触到不良内容。</p>    </details><h4 id="有趣项目"><a class="markdownIt-Anchor" href="#有趣项目"></a> 有趣项目</h4><ul><li><p><a href="https://neal.fun/size-of-life/">生命与大小</a></p><p>Neal Agarwal 又做了个新东西：将不同物种的大小（使用的是平均值或者上限）以十分直观的方式列出。</p><p>他先前做过 <a href="https://neal.fun/not-a-robot/">I'm Not a Robot</a> 游戏，我还 <a href="/posts/31df.html#%E6%88%91%E4%B8%8D%E6%98%AF%E6%9C%BA%E5%99%A8%E4%BA%BA%E4%BD%86%E6%88%91%E4%B9%9F%E6%B2%A1%E6%9C%89%E6%80%A7%E9%A5%A5%E6%B8%B4">通关过</a>，让人感觉的出来他是一个既有想法也有技术的人。</p></li><li><p><a href="https://github-incidents.pages.dev/">距离上次 GitHub 事故已经过了 X 天</a></p><p>不知道是谁写的网页，但是想法太天才了。</p></li><li><p><a href="https://enclose.horse/">enclose.horse</a></p><p>用 10 个墙，把马围在尽可能大的马厩里吧。</p></li><li><p><a href="https://github.com/epidemian/snake">epidemian/snake</a></p><p>在浏览器的 URL 栏里游玩贪吃蛇。让人好奇它是如何实现的。</p></li><li><p><a href="https://github.com/Tichau/FileConverter">Tichau/FileConverter</a></p><p>FileConverter 是一个 Windows 上的「右键菜单自动化脚本集合」，它把 ffmpeg、ImageMagick 等底层程序封装成一套可点击执行的批处理 / 脚本式工作流。</p><p>安装后，只需要右键一个文件（如图片）然后选择 FileConverter 选项、目标文件类型即可。很是方便。</p></li><li><p><a href="https://github.com/immich-app/immich">immich-app/immich</a></p><p>Immich 是一个自托管的照片与视频管理系统。它把「手机相册备份 + AI 搜索 + 家庭共享」这一整套能力，重新实现成可在我们自己的服务器上运行的完整应用栈。</p><p>我原先考虑使用的是 PhotoPrism。但是我配置了很久都无法通过 WebDAV 来同步手机的照片到 PhotoPrism 上。之后退一步直接来用 Immich，意外发现它还提供了移动端 App，可以一键同步照片到服务器上。</p></li><li><p><a href="https://github.com/criwits/missing-web">criwits/missing-web</a></p><p>我和一位朋友聊过「编程如何入门」这个话题。他作为早我十年入行的前辈，认为最开始要学习的便是「认识计算机」。选择哪个编程语言什么的，都无所谓。先从「什么是计算机」开始，学习二进制、机器的语言，然后学习低级语言，搞明白高级语言和低级语言的区别是什么，最后学习高级语言、入门编程。</p><p>可惜的是，许多高中或者大学的计算机课根本不会按照这样的路径学习。很多时候只是把学生丢到高级语言课里，让他们没有任何基础就开始学习编程。这样学习是可以速成编程，但是代价是基础过于薄弱，而这样的代价会随着时间、在未来反咬回来。</p><p>这个项目便是帮助小白们认识自己的计算机。</p></li><li><p><a href="https://github.com/YuKongA/HQ-ICON?tab=readme-ov-file">YuKongA/HQ-ICON</a></p><p>从 App Store 网页版上获取的高清应用图标。</p></li><li><p><a href="https://github.com/donlon/cloudflare-error-page">donlon/cloudflare-error-page</a></p><p>生成 Cloudflare 错误页面。如果用于网站的 404 页面的话，就可以快乐地甩锅给 Cloudflare 了。</p><p>我一直没有给该博客添加错误页面，现在用该项目快速弄了一些出来，比如 <a href="/500.html">500 页面</a>。</p></li><li><p><a href="https://github.com/Bistutu/FluentRead">Bistutu/FluentRead</a></p><p>因为我会引用大量的英文文章或者使用英文，建议使用翻译工具来阅读。Fluent Read 这个扩展是我常使用的翻译工具，模型用的是 gemini-2.5-flash-lite。</p></li><li><p><a href="https://github.com/Tatsu-syo/noMeiryoUI">Tatsu-syo/noMeiryoUI</a></p><p>该工具可以修改 Windows 用户界面字体。我改成了摩托罗拉系统里的 Slab 字体，其实就是 Roboto Slab，然后把字体改成了 10px。</p><p>效果如下：</p><p><img src="/posts/b211/image-20251229004217929.webp" alt="image-20251229004217929" loading="lazy"></p><p>看侧边的「扫描」可以看出，Roboto Slab 没有 CJK 字符。如果该工具可以像网页那样，为不同的字符应用不同的字体就好了。</p></li><li><p><a href="https://github.com/hoothin/UserScripts/blob/master/Picviewer%20CE%2B/README.md">hoothin/UserScripts/Picviewer CE+</a></p><p>上面的图片在桌面端看不清楚的话，推荐使用这个图片查看扩展。需要用到 TemperMonkey。</p></li></ul><hr><h2 id="折腾博客"><a class="markdownIt-Anchor" href="#折腾博客"></a> 折腾博客</h2><p>我将月刊的内容一分为二：上方是「输入」，下方的是「输出」。</p><p>总之我：</p><ul><li><p>将文字全部都放大了！原本的正文大小是 12px-18px，对我而言太小了，阅读不是很舒服。现在改为了 18px-22px。</p></li><li><p>将中文的正文字体改为了思源宋体。</p><details>      <summary>现在该博客网站的字体选择</summary>      <ul><li>英文<ul><li>正文：Georgia 或者 Times New Roman。它们是系统自带的字体，我还在思考用什么字体更好，如果有建议的话务必联系我！</li><li>标题：Open Sans</li><li>代码块：JetBrains Mono</li></ul></li><li>中文<ul><li>正文：Source Han Serif CN</li><li>标题：Noto Sans SC</li><li>代码块：Source Han Sans SC</li></ul></li><li>日文<ul><li>正文：Source Han Serif JP</li><li>标题：Noto Sans JP</li><li>代码块：虽然想要使用 Source Han Code JP，但是 Source Han Sans SC 已经包含假名在内，不可避免地会先渲染假名。目前还在思考如何解决这个问题</li></ul></li></ul>    </details></li><li><p>将粗体改回了最开始的仅 <code>fontWeight</code> 样式。</p></li><li><p>将下划线改成了波浪线，用于标记重要的术语。</p></li><li><p>添加了 <code>ruby</code> 的使用，这是给日语汉字注音用的。</p></li><li><p>添加了着重号的使用，即 <code>text-emphasis</code>，用于强调语气。它会替代许多原本我使用斜体的场景。</p></li><li><p>添加了自动收起 / 折叠 <code>details</code> 块的按钮，目前只用在 <a href="#%E6%97%A5%E8%AE%B0%E7%89%87%E6%AE%B5">日记片段</a> 这个板块内。</p><p>实现原理是这样的：</p><ol><li>生成带 <code>data-group="分组名"</code> 的按钮和 <code>details</code> 元素</li><li>在 JavaScript 内，用 CSS 选择器找到所有同组的 <code>details</code> 元素，检查它们是否全部展开（用 <code>.open</code> 属性），然后根据状态执行相反状态</li></ol><div class="danger warning"><p>我也从中学习到了一件事。</p><p>当使用 Hexo 标签来生成 HTML 时，务必生成 <strong>一行</strong> HTML。不清楚原理是什么，但是我发现如果返回的是多行 HTML，会被程序自动缩进。而这个缩进会被 Markdown 渲染器认为是代码块，从而生成 <code>&lt;pre&gt;&lt;code&gt;实际的 HTML&lt;/code&gt;&lt;/pre&gt;</code> 这样的内容。</p></div></li><li><p>添加了 <code>info</code>、<code>warning</code>、<code>success</code> 和 <code>error</code> 块。主要是为了未来的技术文章用，正常写作估计只会用到 <code>info</code> 和 <code>warning</code>。</p></li><li><p>添加了错误页面。</p></li></ul><h2 id="我写的文章"><a class="markdownIt-Anchor" href="#我写的文章"></a> 我写的文章</h2><p>顾名思义，用来记录我这个月都写了什么。</p><ul><li><p><a href="/posts/5a85.html">《请学会如何读空气吧》</a></p><p>同朋友吵架的记录。</p><p>你可能会在未来看到我和同种人吵架的记录。</p></li><li><p><a href="/posts/e955.html"><em>I had (maybe) the worst computer class in my life</em></a></p><p>这是一篇英文文章，也是我第一次尝试写英文原创文章。我一直在考虑要不要写英文文章，主要是怕被身边的人发现，后面考虑了一番 —— 随便啦，看就看吧！虽然大概率不会被他们看到。</p><p>你能从这里看到我使用英文时欠揍的一面~</p></li><li><p><a href="/posts/196a.html">《儿童网红背后的黑暗》</a></p><p>公开演讲课的最后一场演讲。</p></li><li><p><a href="/posts/d33e.html">《你缺这 2.75 美元吗》</a></p><p>我捐款给维基百科，然后发现这个捐款根本不是我想象的那样。</p></li><li><p><a href="/posts/9572.html">《尝试去中心化和去 App 化》</a></p><p>我开始使用 PixelFed 和 Mastodon 了！以及逐渐从手机中删去 App、改用网页 App。</p></li><li><p><a href="/posts/5097.html">《观「玩具熊的五夜后宫 2」》</a></p><p>实在是一部令人感到失望的续作。</p></li><li><p><a href="/posts/6e69.html">《当 True 不再是 True》</a></p><p>我很不喜欢通过语言结构来断言语言使用者的思维方式，更何况例子用的很糟糕。</p><p>不过我也赞成「可以通过语言来逆向推理出什么来」这个想法。比如我对日语的分析，可以分析出日本社会的一定成分来。但要搞清楚，那不是这个国家的全部。</p></li><li><p><a href="/posts/7240.html">《观「疯狂动物城 2」》</a></p><p>我很喜欢这个系列。续作虽然有许多瑕疵，但我认为都是可以包容的，希望第三部可以更好。</p></li><li><p><a href="/posts/18b0.html">《离开纽约市的一天》</a></p><p>有时候去一个平日不会去的地方，会让生活很新鲜。</p></li><li><p><a href="/posts/c5d9.html">《中文网络写作上的规则习惯》</a></p><p>抛砖引玉用，如果有想法的话务必联系我。</p></li><li><p><a href="http://localhost:55555/posts/f77.html">《乙巳想法复盘》</a></p><p>大家是如何看待今年的自己的呢？</p></li></ul><h2 id="编程历程"><a class="markdownIt-Anchor" href="#编程历程"></a> 编程历程</h2><p>「编程历程」这个板块是我记录我都做了什么和编程、计算机巴拉巴拉相关的事情。</p><h4 id="时间戳"><a class="markdownIt-Anchor" href="#时间戳"></a> 时间戳</h4><p>服务器都会默认使用 UTC 时区，然后发送到客户端的时候再转换成我们想要的时区。</p><h4 id="邮件模板和发送"><a class="markdownIt-Anchor" href="#邮件模板和发送"></a> 邮件模板和发送</h4><p>项目里的一个需求是让 TypeScript 可以验证传入邮件模板文件的变量。为此我开发了一个 MJML 模板语言的 Linter 工具，只在项目里使用。结果 Linter 还是不够。我放弃 MJML、改用 React Email 了。</p><p>React Email 还自带预览和热加载。这些功能我先前都是手搓……</p><h4 id="使用-sentry"><a class="markdownIt-Anchor" href="#使用-sentry"></a> 使用 Sentry</h4><p>我一直以为 Sentry 只是用来看日志用的，结果实际使用后发现它的功能很丰富。例如测试客户端时可以在 Sentry 看到我具体用鼠标在页面上做了什么。</p><h4 id="cloudflare-安全规则"><a class="markdownIt-Anchor" href="#cloudflare-安全规则"></a> Cloudflare 安全规则</h4><p>先前我一直以为这个项目那么小，不会有人攻击。结果客户端和服务端都被脚本小子攻击，其中客户端因为同时被 AI 爬虫机器人爬取数据、被干到无法响应了。</p><p>脚本小子本来不是刻意来 DDOS 我。他尝试爬取我的项目中类似于 <code>/.env</code> 的路由，看看我是不是一个小傻瓜、把密钥拱手送给他。</p><p>项目的域名受 Cloudflare 保护，可以在 Cloudflare 那儿设置安全规则：</p><pre><code class="language-plaintext">(http.request.uri.path contains ".env") or (http.request.uri.path contains ".git") or(http.request.uri.path contains ".yaml") or (http.request.uri.path contains "/config.") or(http.request.uri.path contains ".php") or(http.request.uri.path contains "/wp-") or(  http.request.uri.path contains ".json"   and   (    http.user_agent contains "python" or     http.user_agent contains "curl" or     http.user_agent contains "wget" or     http.user_agent contains "http-client" or     http.user_agent contains "java" or     http.user_agent contains "libwww-perl"  ))</code></pre><h2 id="书籍"><a class="markdownIt-Anchor" href="#书籍"></a> 书籍</h2><h4 id="蛋安迪威尔"><a class="markdownIt-Anchor" href="#蛋安迪威尔"></a> 《蛋》—— 安迪・威尔</h4><blockquote><p>「但这世界上所有其他人……」</p><p>「<span class="emphasis">全是你！</span>都是你不同的转世，不同的化身。」</p></blockquote><h4 id="即使只有一次也会后悔-swig40-swig41-"><a class="markdownIt-Anchor" href="#即使只有一次也会后悔-swig40-swig41-"></a> 《即使只有一次也会后悔》——​<ruby>宮原<rt>みやはら</rt></ruby>​<ruby>都<rt>みやこ</rt></ruby></h4><p>重温了这本漫画，也就是该站的 icon 的出处。</p><p>追连载的时候特别喜欢它，现在看来觉得十分可惜：作者明显想要探讨很多东西，但可能是被腰斩了或者什么原因，许多东西开了个头、便没有后续了。例如房东小姐的过去、邻居的过去等等。</p>​<ruby>宮原<rt>みやはら</rt></ruby>​<ruby>都<rt>みやこ</rt></ruby>喜欢将角色虹膜画成菱形形状。受他影响，我高中期间也会这么画。不过现在已经完全失去了画画的热情。<h2 id="影视"><a class="markdownIt-Anchor" href="#影视"></a> 影视</h2><h4 id="寒蝉鸣泣之时寒蝉鸣泣之时-解"><a class="markdownIt-Anchor" href="#寒蝉鸣泣之时寒蝉鸣泣之时-解"></a> 《寒蝉鸣泣之时》/《寒蝉鸣泣之时 解》</h4><p>同室友重温了这个系列。这应该是我第三次看这个作品，每次看都会觉得某某设计真是绝了！可惜后续的两个新篇实在是过于糟糕，令人为这个系列感到惋惜。</p><h2 id="音乐"><a class="markdownIt-Anchor" href="#音乐"></a> 音乐</h2><h4 id="年度总结"><a class="markdownIt-Anchor" href="#年度总结"></a> 年度总结</h4><p>我用的听歌软件是 YouTube Music。不知道为什么 12 月初就开始给我生成年度总结。因为今年下半年我才开始使用的 YouTube Music，因此内容更多代表的是下半年我听了什么，而不是我一整年都在听什么。</p><p><img src="/posts/b211/image1764861689445.webp" alt="一张 YouTube Music 2025 年度回顾图，展示用户全年音乐收听情况，包括最常听的艺人如老王樂隊、草東沒有派對、萬能青年旅店、趙雷和溫室雜草，以及最常听的歌曲如《我記得》、《搁浅的人》、The sound about petals、《揪心的玩笑與漫長的...》和《春天有腳》。图中还显示用户的“音乐护照”，表明他们收听了来自日本、中国和美国的艺人，分别为 28 位、19 位和 16 位，总收听时长达 7,304 分钟。整体设计色彩丰富，突出个性化音乐喜好与年度数据总结。" loading="lazy"></p><h4 id="あばらや"><a class="markdownIt-Anchor" href="#あばらや"></a> あばらや</h4><p>之前还在用 Apple Music 的时候，每次月度总结都能看到多首日语歌。现在换了 YouTube Music，发现听日语歌的频率开始大大下降。Top Songs 上只有 <em>The sound about petals</em> 是日语歌，出自于 P 主 あばらや。</p><p>あばらや 的另一首歌《かなしばりに​<ruby>遭<rt>あ</rt></ruby>ったら》也很好听，我个人很喜欢异世界情绪翻唱的版本。</p><h4 id="monkey-majik"><a class="markdownIt-Anchor" href="#monkey-majik"></a> Monkey Majik</h4><p>我重新听了 Monkey Majik 的一些歌。主唱讲日语时口音有些重，哈哈，不过不影响他们的歌好听。</p><p>我初次知道 Monkey Majik 还是因为月之美兔，她在 2023 年翻唱了 <em>Around The World</em>。这首歌到现在我也觉得很好听，MV 实在是太怪太诡异了！褒义层面上的怪。</p><p>了解了这支乐队后我也听了他们和 M-Flo 一起唱的 <em>Picture Perfect</em>，旋律和歌词想要表达的意思都让人很喜欢。</p><blockquote><p><em>All the time that you were standing by my side.</em></p><p><em>She's that picture perfect kind.</em></p><p><em>I can't believe I was so blind.</em></p><p><em>Do you remember the time?</em></p><p><em>You know I stepped across that line.</em></p><p><em>I made you cry and that's my crime.</em></p><p><em>I wish that I could just rewind.</em></p></blockquote><p>单挑这首歌出来，是因为室友曾说，这首歌让她想起了自己对我做过的事情。<span class="emphasis">倒带重来</span>，是多少人都梦寐以求的能力。可是做过的事情不会消失不见，它会一直存在，我们也只能去接受这个事实。</p><h4 id="ajr"><a class="markdownIt-Anchor" href="#ajr"></a> AJR</h4><p>说到 Monkey Majik 和室友，就会想起更早些时候我们一起听过的 AJR，是我很少会去听的纯英语乐队之一。我是通过 <em>World's Smallest Violin</em> 认识的他们，不过印象最深的是他们的 <em>Joe</em>。</p><blockquote><p><em>I don't ever think of you.</em></p><p><em>I got too much stuff to do.</em></p><p><em>Should have left you back in school.</em></p><p><em>Joseph, do you think I'm……</em></p><p><em>I don't ever think of you.</em></p><p><em>Look at all this stuff I do.</em></p><p><em>Probably not as much as you.</em></p><p><em>Now Joe, do you think I'm cool?</em></p></blockquote><p>那段时间的我陷入了人生第「绝对不是第一但也不是倒数第一」次低谷。同家人的关系愈来愈差，物理和精神上的暴力每天都在发生。和同龄人的人际关系处理的也一般。小圈子里的一位朋友情绪失控、毫无理由地辱骂了我；室友第二次高高在上地提出了一个问题：「我遇到了更好的人。我喜欢刺激。我是不是应该选择那个人？」</p><p>那时候，我从人生的经历里也仅是学会了如何「装自己不在乎」，说白了就是逃避。我将自己锁在了地下室里两周，每天就是继续开发游戏、外放这首歌。放这首歌可能也没有什么真正的含义吧，就是觉得好听。</p><p>只是现在再来听这首歌，<em>do you think I'm cool?</em>「我过去所做的决定是『酷』的吗？我后悔吗？」这样的想法难免会涌上心头。</p><h4 id="ginger-root"><a class="markdownIt-Anchor" href="#ginger-root"></a> Ginger Root</h4><p>室友经常会去 WeWork 办公，那里外放的音乐时不时会出现很有趣的乐队，例如这个月她发现的 Ginger Root。当时 WeWork 里放的是他们的 <em>Loretta</em>，她一瞬间就被这极其抓耳的节奏捏紧了心头。</p><p>或许这也是我第一次听灵魂乐？我对音乐类型实在是不太懂。室友最先认为这是蒸汽波，后面我们查了百科才知道 Ginger Root 是美国独立灵魂乐乐队，不过还是混合了不少日本的 City Pop 元素在内 —— 蒸汽波也是 City Pop 的一个亚种吧。</p><p>我稍微看了一些 Ginger Root 的 MV，发现这个乐队的想法十分奇特和有趣。很推荐听听看~</p><h4 id="nelward"><a class="markdownIt-Anchor" href="#nelward"></a> Nelward</h4><p>好啦虽然前面说我听的纯英文乐队不多，结果这个月貌似我爱听的都是纯英文乐队…… 总之我又发现了一个很有意思的乐队：Nelward。我是通过 <em>Never Wanna Fall in Love With You</em> 这首歌知道他们的。</p><p>我也推荐他们的另一首歌 <em>Ghost</em>，我觉得主题设计非常非常有意思！Ghost 在字面上是「幽灵」的意思，但作为动词可以是「突然不再回复」的意思，常用于社交或者恋爱关系中。</p><blockquote><p><em>There's a ghost in my home</em></p><p><em>But it's better than being alone</em></p><p><em>Reading read receipts with no replying</em></p><p><em>Yes, my house is haunted</em></p><p><em>That's the way I want it</em></p><p><em>Read receipts with no replying</em></p></blockquote><p>Nelward 的专辑封面很有趣，我不知道算什么风格？总之给我的感觉像是数年前互联网黄金时代的风格。</p><p><img src="/posts/b211/image-20251228235340311.webp" alt="image-20251228235340311" loading="lazy"></p><h4 id="jomm"><a class="markdownIt-Anchor" href="#jomm"></a> jomm</h4><p>主要听了他的 <em>Astronaut Song</em> 和 <em>Dial 143</em>。带有爵士味道的流行？我分不出来音乐类型，把答案交给你们吧。主唱 readyaimfire27 的声音很漂亮，音乐的旋律都很欢乐，听了会很开心~</p><h2 id="日记片段"><a class="markdownIt-Anchor" href="#日记片段"></a> 日记片段</h2><p>关于该板块的变动，详情见 <a href="/posts/9572.html">这篇文章</a>。有一点需要注意，PixelFed 的文字都是英文的。</p><p>我也添加了一个「展开所有」的按钮，原理见 <a href="#%E6%8A%98%E8%85%BE%E5%8D%9A%E5%AE%A2">上方博客的折腾记录</a>。</p><p>因为是第一次尝试，可能有一些问题。如果有任何建议的话，很欢迎给我发邮件！</p><button id="details-toggle-diary_sections-1789678105896" class="details-toggle-btn" data-group="diary_sections" onclick="toggleGroupDetails('diary_sections', 'details-toggle-diary_sections-1789678105896', '展开所有', '收起所有')">展开所有</button><details data-group="diary_sections" id="十二月二日">      <summary>十二月二日</summary>      <p>大半夜寻思用下电脑等下睡觉了，结果小组成员（以下简称甲）突然开始在 WhatsApp 群聊里释放压力。他先是表示我们要多 Zoom、推进进度，然后指责我「时间没有你想象的那么充沛」。</p><p>这个小组作业的 Deadline 在 12 号，也就是 10 天的时间，这个作业本来也不是很难的东西，一直没做好的原因根本就是我们行程冲突却又非要所有人同时在场。就算一起 Zoom 了，大家也没有起到重要的作用，很多时候都是在帮倒忙。对，我说的就是你，甲！</p><p>这种话本来就该花费了最多时间的人说，他除了瞎指挥外一点事情没做，现在反倒是怪起我们来了。</p>    </details><details data-group="diary_sections" id="十二月三日">      <summary>十二月三日</summary>      <p>中午去常去的面馆里吃饭。想着吃吃看他们给的辣油，没想到一点都不辣，反而只有满嘴的油味儿。这次的馍也一般，没有微波透，嚼起来硬硬的。这家店虽然最初是用「免小费」作为招牌，但是单价实在是太贵了，质量也貌似不如以前，可能之后不会继续支持下去 —— 我也没多少票子啦。</p><p>不过期间听到面馆老板和另一个人说话。老板想要在自助点单机上添加一个学生优惠功能，不过平台不可能真的去接各大学校的数据、一个个查询顾客的学生 ID 是否有效。老板说不是学生的顾客过来假装学生也没有关系，反正也只是 10% 优惠而已，他不怕。</p><p>我一直都很纳闷，为什么这家店这么抗拒前台收银。每次过去的时候，前台都是空无一人，员工全在角落吃饭。如果我想要使用现金的话，需要等他们走过来才行。多数餐馆也都是用「你给前台展示自己的学生证、前台手动添加 10% 的优惠」的笨方法。</p><p>吃着吃着门外进来一个人，专门把店里所有的塑料花瓶都摔在地上，嘴上不知道在骂什么、转了一圈走了。这就是为什么<span class="emphasis">我讨厌这个城市</span>。这种无时无刻都在散发恶意的人实在是太多了，你也不知道该拿他们怎么办。万一他们想要鱼死网破，跟你打起来，对我们而言实在是得不偿失。他们也没有做出实质性的破坏，就算要找警察，警察除了口头警告还能做什么呢？这群人本来就是天天惹事、不怕警告的家伙。</p><hr><p>晚上回家，项目管理告诉了我一个趣事：上次找来做贴纸的那个朋友（见 <a href="/posts/31df.html">十一月十日</a>）因为痛恨可画，没有使用可画的二维码生成功能，而是去找了 QR.io 生成二维码。结果这个网站的二维码并不是永久的，7 天后就会失效，除非购买他们每月 35 美元的套餐计划。这意味着她们印的近百张贴纸全部都作废了。更好笑的是，项目管理发现国内淘宝的贴纸定制服务比她们自己印要便宜了不知道多少倍。</p>    </details><details data-group="diary_sections" id="十二月四日">      <summary>十二月四日</summary>      <p>听 Spike 推荐给我的 <a href="https://www.xiaoyuzhoufm.com/episode/69109159af4fc00da7e16ec2">播客</a>，讲的是智力。</p><p>这是第一次听博客，感觉很适合坐地铁的时候听，不过还没听到一半就到站了。</p><p>详细感想还是留给长文吧。</p><hr><p>在地铁上看到一个公益广告，讲到了 Ageism（年龄歧视）。孩子怎么养是一个深奥的问题，如何看待老人也是一个问题。到了一定年纪，估计身体会不知不觉弱下来，无论过去是一个多么厉害的人。这让我想起日本的老龄化问题，导致「​<ruby>老害<rt>ろうがい</rt></ruby>」一词诞生。</p><p>写着写着，上来一组跳舞队，开始在车厢里放音乐、跳街舞。有时候真的很担心他们因为地铁摇晃而摔倒。</p><p>今天出门就是去见先前提到的物理理论转码的朋友。我们在街机厅见的面，然后开始了互相给彼此选奇怪谱面的时间。</p>    </details><details data-group="diary_sections" id="十二月六日">      <summary>十二月六日</summary>      <p>和小组成员继续推进作业的进度，总之也是特别想要吐槽的一天。</p><p>完全可以感受出来这个指挥的家伙基本功差的离谱。我在 pandas dataframe 里发现了无限，而这是因为数据里出现了负数 —— 要命哦，纽约市处理已去世的公务员居然是直接将他们的工资、工作时间都弄成负数。</p><p>甲说我们可以 catch <code>zerodivisionerror</code>，但是问题根本不是那个 —— 你连异常都没有，怎么能 catch 呢？pandas 里遇到除零可是会直接得无限啊。我这么解释，甲却抛来一句 <em>then get it</em>，直接让我大脑宕机：<em>get what？</em> 我解释的还不够清楚吗？</p><p>然后我就无视了他 —— 反正在我做事情的时候，他就是在发呆不说话，也没有太多有参考价值的建议 —— 把数据重新清洗了一下。</p>    </details><details data-group="diary_sections" id="十二月七日">      <summary>十二月七日</summary>      <p>今天看到了《洛克王国：世界》的正式服定期：明年的 3 月份。这让我想起了过去游玩洛克王国的时候。洛克王国和其他类宝可梦网游的一个最大的区别，我认为是绑定了 QQ，所以就算是现在我也可以继续登录我的账号。至于赛尔号、奥奇传说的我都不记得用户名和密码了，奥拉星的倒是还记得。</p><p>2010 年 7 月份是我注册洛克王国的时候，不过并不是我第一天玩它。在那之前我就登录过母亲的 QQ 然后注册了洛克王国玩，我还傻傻地想着把母亲的 QQ 给自己、我新建一个给她，还给那个新号取名为「X 妈」。母亲当然不愿意了，那个新号就成了我自己的 QQ，「X 妈」这个用户名也在我的 QQ 空间上挂了数年，直到 2016 还是 2017 年我才改掉。</p><p><img src="/posts/b211/rock.webp" alt="" loading="lazy"></p><p>刚接触网络的时候，不知道为什么我的空间首页里总是有不认识的人叫我的名字（虽然是假的名字）。因为害怕，我就把 QQ 空间能不能被他人看到和能不能被他人添加好友的设置都改成了不行。现在我的 QQ 还留着我以前的个性签名。</p><p><img src="/posts/b211/qq.webp" alt="" loading="lazy"></p><p>说回洛克王国，那时候有一段记忆：我看表哥玩洛克王国，他在一个沙滩上，全都是其他小洛克，然后大家都在等一个宠物刷新 —— 蓝色多哥。</p><p>虽然这个宠物现在可能已经烂大街了，不过他给我的印象实在是深刻，以至于后面我不知道怎么搞到了一只，还特意把它放在农场里守护庄稼。结果没想到，农场守护功能后来被关闭了，它就这样永远卡在了那里，再也取不出来。当时我难过得不行，直到现在还对这件事耿耿于怀。</p><p>我最喜欢的场景是威廉城堡，目前最喜欢的宠物是恶魔战士。不知道为什么恶魔猪能进化成一个明显像猫的动物… 以前特别喜欢喵喵，还喜欢有事没事抓呱呱修行。我还有一个雪精灵，不知道怎么搞到的，但是当时感觉十分稀有，并且他的进化链条很奇怪：明显像是同个进化链的雪灵和他在页游里居然算两个宠物。</p><p>我小时候并不是一个战斗党，完全是觉得谁厉害练谁、每个宠物要带四个伤害技能。这也是我在类宝可梦网游里玩得实在是很菜的原因吧。</p>    </details><details data-group="diary_sections" id="十二月八日">      <summary>十二月八日</summary>      <p>回家一趟。</p><p><img src="/posts/b211/dog.webp" alt="" loading="lazy"></p><p>猫又变大了，已经有我的键盘长。没有之前那么怕人，开始表露出自己活泼调皮的一面，在我的床上爬上爬下的。我摸了一把，毛发非常柔软。现在它年纪还小，有时候睡觉的时候还会像吸奶一样吸被子。</p><p><img src="/posts/b211/cat.webp" alt="" loading="lazy"></p>    </details><details data-group="diary_sections" id="十二月十日">      <summary>十二月十日</summary>      <p>早上赖床刷手机的事情暴露了…… 虽然现在可以很早地醒来，但是会赖床用手机。自己也知道这样不好，但就是会像习惯一样使用手机。要纠正这个坏习惯的方法也很简单，醒来后让自己不要用手机。这样说听起来很奇怪是真的啦，但是很多时候要纠正一个坏习惯真的就是这么简单：<span class="emphasis">相信自己的自制力！</span></p><p>好了以上都是假的，大家还是乖乖地给自己的 App 设置使用限制吧。</p><p>总之和室友吵架了，也不能说是吵架，只能说是被她单方面输出了。她觉得我可能是一个「做的没有说的多」的人，而她很鄙视这样的人。我很懒散是没有错啦，我也知道自己懒散不好…… 反正她不会和这样的人做朋友，也不会把他们当人看。</p><p>有时和她说话，只能觉得很愤怒就是了，虽然这件事确实是我有问题。</p><p>随便吧！你爱怎么样怎么样吧！</p><p>这个讨厌的家伙，总是觉得自己高人一等，只有她选朋友，没有别人选她。她的客观条件确实很好，也有很厉害的专业能力和商业头脑，但是有时候真会觉得她能把人逼疯。她的身边总是有没有脑子的家伙，像教徒一样侍奉她，真讨厌！</p><p>更何况，她的许多规矩对于某个人来说根本不成立。讨厌的双标！</p><hr><p>室友想听回春丹的《花桥》，所以我放了。关于它的歌词，我们的理解产生了一些冲突。</p><blockquote><p>键盘佬过头</p><p>大过地球</p><p>有山有水</p><p>冇有水龙头</p><p>公鸡都叫了</p><p>他们都不肯去睡觉</p><p>叫～叫～叫～</p><p>坏人的血才是黑色的</p><p>我们永远万紫千红</p><p>一方水土养一帮人精</p><p>浪费了粮食还假装清醒</p><p>坏人的血才是黑色的</p><p>我们永远万紫千红</p><p>一方水土养一帮人精</p><p>浪费了粮食还假装清醒</p><p>哎呀这个世界疯子真是多啊</p><p>食嘢唔做嘢</p><p>做嘢打烂嘢</p></blockquote><p>我的理解是这样的，先说前四句：作者直接指出了「键盘佬」这个群体，也就是键盘侠，意味着这是整首歌所要说的「主体」。接下来的「有山有水、冇有水龙头」则是连接了上一句的「大过地球」，这段话的主体是「键盘侠的头」，用山和水讽刺了键盘侠的脑子进水，还没有系统可以排水。</p><p>室友则认为，这首歌讲的是浪费资源，因为出现了山水但是没有水龙头，表现出一些地区资源落后的现象。其他资源丰富的地区却在浪费粮食。</p><p>我认为室友的理解：一、无视了开头的「键盘侠」群体；二、整体理解过于片面、只看了字面意思。</p><p>她认为我在批判她的理解，因为每个人都可以有自己的理解，除非我可以发邮件问作者什么想法。虽然我没有到这个程度，但还是觉得她所说的让我有点不爽。</p><p>主要是我认为我的解读在逻辑上更通顺、没有任何问题。《花桥》给我的感觉就是这个样子，室友的理解反而给我感觉很奇怪，逻辑上并不通顺。面对我的问题，她像是找补一样给出了很奇怪的看法。比如说「键盘侠」，她认为是作者举的游手好闲的人的例子。这也就是说，她认为作者先列出了游手好闲的人作为主体，然后作者用「键盘侠」举例。这怎么会逻辑通顺呢？要知道这首歌的歌词里，「键盘侠」是先出现的，后面的歌词都是用于补充「键盘侠」的特点的，在室友的理解里却本末倒置了。</p><p>结果反正就是，室友指责我非要跟她吵这个事情。我认为我是想要知道她为什么这么想，因为她的这个理解最初并没有一个解答思路。她觉得我莫名其妙要跟她吵架，反而让我蛮不开心的：<span class="emphasis">我才没有想要吵架吧！</span>我只是想要知道为什么她会这么想。</p>    </details><details data-group="diary_sections" id="十二月十一日">      <summary>十二月十一日</summary>      <p>今天请假，和一位朋友出去玩。</p><p>我们是先去了九朗寿司吃饭。没想到居然涨价了，一个碟子变 4.1 美元。也多了一些外国人可能爱吃的东西，比如炸米热狗、炸鱼薯条这样的东西。因为和卡比联动，有些碟子还是卡比形状的，很可爱。</p><p><img src="/posts/b211/kura.webp" alt="kura" loading="lazy"></p><p>九朗一直都有个小活动，每吃 15 碟给一个扭蛋。卡比联动期间是给卡比相关的小周边，我们抽到一个绑电线用的东西。</p><p><img src="/posts/b211/kirby.webp" alt="kirby" loading="lazy"></p><p>吃完饭就去周围的周边店逛。我个人不是很喜欢周边店啦，东西很贵，我对周边也不是很感兴趣。</p><p>不知道为什么，有家周边店的电视屏幕在放《罗小黑战记 2》。我还没看过，不要剧透给我！在《罗小黑战记 2》刚上映的时候，纽约的电影院其实也上映了。不过我当时有点忙，以为说电影下周还播放，结果没有、直接下线了。</p>    </details><details data-group="diary_sections" id="十二月十四日">      <summary>十二月十四日</summary>      <p>我发现我的 Webmention 发送又出问题了…… 明明解析出来的是正常的格式，但是实际发送出去的却只有链接。</p><hr><p>我在迁移 Instagram 上的图片时发现了自己大一时做的 <em>Punch Clock</em> 合集。Punch Clock 指的是「打钟」，就是上班时的打卡那样的东西啦。</p><p>大一暑假还在考全栈开发相关的证书，因为想要自己每天都有实质性的事情在做，所以（几乎）每天都在用 Story 功能上传自己用各种奇怪 GIF 以及文字拼接起来的「打卡证明」。到后面慢慢也变成了分享日常的东西，不过发到后面自己做一个项目的时候就没有继续再发了。</p><p>现在再看就觉得「哎这个人是谁啊怎么这么有意思」。</p><p>当时发的第一个 Story 是这个：</p><video controls="" width="100%"><source src="/posts/b211/18068006656460692.mp4" type="video/mp4">Your browser does not support the video tag.</video><p>当时停更还有校友线下来问我为什么不继续打钟了。</p>    </details><details data-group="diary_sections" id="十二月十五日">      <summary>十二月十五日</summary>      <p>复习微积分的一天，周三就要期末考试了，我还有一场 Python 的期末考在周四。</p><p>感觉自己复习不完…… 微积分。</p><p>Python 还好？多选题不会有太多问题，唯一的问题是写代码的时候怎么办。听说是要用笔写，我这个 Syntax 全靠编辑器帮我看的人、写错了怎么办？我因为主写 JavaScript 和 TypeScript，总感觉很多语法都会和 Python 语法弄混呢…… 哎呀能及格就好。</p><hr><div class="diary-entry">01:18<br><p>First time using PixelFed 😁</p><p></p><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/c19ce1b25-2f8843/CXh5hOPhlc5l/B8qwSBrPCUDwcZ6LwtSJHa2WOZtfYa4BJlW8ogrF.jpg" alt="A close-up of a tabby cat's face peering out from the branches of a Christmas tree, positioned directly beneath a large red matte ornament. The cat is looking upwards, surrounded by artificial pine needles with white frosted tips." loading="lazy"><figcaption>A close-up of a tabby cat's face peering out from the branches of a Christmas tree, positioned directly beneath a large red matte ornament. The cat is looking upwards, surrounded by artificial pine needles with white frosted tips.</figcaption></figure></div><hr><div class="diary-entry">01:19<br><p>Cute gato tax</p><p></p><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/c19ce1b25-2f8843/0ZO4IfUqnYzh/WdYGl6VHRgIvfdKwI3E3VvXz3hZGC9tcv3DejOQx.jpg" alt="A fluffy tabby and white cat lounging in a textured yellow pet bed. The cat rests its head sideways on the rim of the bed, looking directly at the camera with a soft expression, while one white paw extends over the edge. A colorful wand toy with pink and neon green feathers lies on the wooden floor in the foreground." loading="lazy"><figcaption>A fluffy tabby and white cat lounging in a textured yellow pet bed. The cat rests its head sideways on the rim of the bed, looking directly at the camera with a soft expression, while one white paw extends over the edge. A colorful wand toy with pink and neon green feathers lies on the wooden floor in the foreground.</figcaption></figure></div><hr><div class="diary-entry">01:19<br><p>Gato took a nap on my lap</p><p></p><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/c19ce1b25-2f8843/9EblPS4oSYaz/nD2tzXlTyvsOmVd8TcPTMnYq3uAkKI1HbKKVh5LF.jpg" alt="An extreme close-up of a sleeping brown tabby and white cat's face bathed in warm sunlight. The cat's eyes are closed, highlighting its pink nose and long white whiskers against a white muzzle. The lighting accentuates the texture of the fur on its cheek and head." loading="lazy"><figcaption>An extreme close-up of a sleeping brown tabby and white cat's face bathed in warm sunlight. The cat's eyes are closed, highlighting its pink nose and long white whiskers against a white muzzle. The lighting accentuates the texture of the fur on its cheek and head.</figcaption></figure></div><hr><div class="diary-entry">21:16<br><p>Little tiger gato</p><p></p><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/c19ce1b25-2f8843/zYTrXDvhQ4Qo/wfRXyr9zbPLpTrYQSMdrmakqB8vwpw52MeshFZ8o.jpg" alt="A top-down view of a fluffy calico cat sound asleep in a brown woven basket lined with a soft, light blue fleece blanket. The cat is curled on its side with its white belly exposed and paws stretched out comfortably. It is wearing a purple collar with a tag." loading="lazy"><figcaption>A top-down view of a fluffy calico cat sound asleep in a brown woven basket lined with a soft, light blue fleece blanket. The cat is curled on its side with its white belly exposed and paws stretched out comfortably. It is wearing a purple collar with a tag.</figcaption></figure></div>    </details><details data-group="diary_sections"><summary>十二月十六日</summary><div class="diary-entry">06:02 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115727727079387442" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>正在尝试让我的博客自动抓取和嵌入我的嘟文~</p><p></p></div></details><details data-group="diary_sections"><summary>十二月十七日</summary><div class="diary-entry">01:48 <a class="diary-source-link" href="https://pxlmo.com/p/Cytrogen/906721630261821016" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>What are you looking at?</p><p></p><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/c19ce1b25-2f8843/PyuMpm3A6kNK/FPrii9O4Unjrdp7Cc44psgCvZmH4WF2DSoLT5ITr.jpg" alt="A fluffy calico cat peering through the vertical black metal spindles of a staircase railing. The cat is looking upwards with an attentive expression. In the background, a light-colored wall is decorated with a large gallery of framed photographs, and some green indoor plants are visible on a shelf to the right." loading="lazy"></figure></div><hr><div class="diary-entry">06:13 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115733431751450269" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>东部时间下午我继续写自己的脚本，发现使用的獭站宕机了，到现在才恢复。幸好之前缓存了一份数据，可以用缓存数据继续开发。目前进度是可以靠标记过滤掉不需要嵌入的嘟文 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/068/original/056b5cd637e95313.png" alt=":ablob_catcoffee:" loading="lazy"> Mastodon 掉线时的动画很可爱。</p><p></p></div><hr><div class="diary-entry">19:23 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115736537847230204" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>PixelFed 的 API 文档，找了半天没有找到，后面才得知和 Mastodon 用的是同一套…</p><p>我加入的是 pxlmo\.com，不清楚其他的服务器是什么样的，不过我发的 post 都被默认标记为 unlisted，说是后续会有人工来审查… 不过已经过了三天了，一点消息都没有的样子。</p><p>所以猫猫照片可能要过很久才会发出来 —— <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/019/055/original/2421e8d631ebf3b8.png" alt=":ablobcry:" loading="lazy"> </p><p></p></div><hr><div class="diary-entry">21:27 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115737024403921536" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>来 AMC 看 FNAF2，半小时了一直在看广告。原本的其他电影预告片哪里去了！真是应了那句话：花钱只能让自己成为更高价值的产品 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/245/original/aad7de836fc79371.png" alt=":ablobhammer:" loading="lazy"> </p><p></p></div></details><details data-group="diary_sections"><summary>十二月十八日</summary><div class="diary-entry">23:51 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115743253363219743" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>期末终于结束啦，每年一定会发生的糟糕的事情也如期而来，该说非常怪异地感到安心了吗？也许是麻木了，内心的起伏没有之前那么大，但还是想着「把所有东西都毁掉就好了」。</p><p></p></div></details><details data-group="diary_sections"><summary>十二月十九日</summary><div class="diary-entry">04:47 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115744416100909333" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>被 Hexo 坑了。我一直以为 hexo s 显示的页面等同于 hexo d 部署的页面，结果不是，导致我这个月底要发布的月刊今天就发了出去，还被我的 FreshRSS 抓到，意味着其他订阅者的 RSS 聚集工具也抓到了这个错误发布的文章 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/080/751/original/0e7b38483aee37bb.png" alt=":blobimfine:" loading="lazy"> </p><p></p></div><hr><div class="diary-entry">18:45 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115747711280078222" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这些天的心情实在是太差了，感觉好像有一阵迷雾在自己的脑子里，乱七八糟的，想把它当作耳机线拆开，结果发现人家是迷雾、我压根碰不到。</p><p>学业很烦人，工作也烦人，人际关系也像巧克力形状的粪。或许是因为冬天来了吧，人会不受控制地感到情绪低落。</p><p>看着某人不停地为自己辩解，只会由衷地感觉恶心。把这一切都毁掉吧！</p><p></p></div></details><details data-group="diary_sections"><summary>十二月二十一日</summary><div class="diary-entry">03:40 <a class="diary-source-link" href="https://pxlmo.com/p/Cytrogen/908199404402805131" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Chubby chubby?</p><p></p><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/c19ce1b25-2f8843/7c79qi4fstgy/cSx85bioOvwoNkO7rcPyPa3eTWMZTWOHVlI5F8GV.jpg" alt="A top-down view of a fluffy calico cat lying stretched out on a dark hardwood floor, with its back pressed against a white baseboard. The cat features a white belly and paws contrasted with dark tabby and orange patches on its body and a bushy tail. It is looking up towards the camera with a calm expression." loading="lazy"></figure></div><hr><div class="diary-entry">03:42 <a class="diary-source-link" href="https://pxlmo.com/p/Cytrogen/908200018288515523" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Stare…</p><p></p><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/c19ce1b25-2f8843/Z3r9P9LqWEyI/JG1obajeem6M6eQBg66yUYsrvjhJarYV86j8McYO.jpg" alt="" loading="lazy"></figure></div><hr><div class="diary-entry">03:50 <a class="diary-source-link" href="https://pxlmo.com/p/Cytrogen/908201960492333675" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Lion gato</p><p></p><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/c19ce1b25-2f8843/qISsAhPgPrNN/HFLu5jVorkh4wanlrXML66yu6iL4msNTlfmu9B58.jpg" alt="A close-up shot of a fluffy calico cat looking upwards with wide, attentive eyes. The cat has a white chest and paws, with patches of brown and black tabby markings on its head and body. It wears a collar with a purple bell and a blue, flower-shaped tag engraved with text including " rabies="" vacc"="" and="" an="" id="" number.="" the="" cat="" is="" resting="" its="" front="" paws="" on="" a="" beige="" tiled="" floor."="" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary> 十二月二十二日</summary><div class="diary-entry">02:11 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115760789730478094" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>大晚上坐快车回家。期间车里的灯突然变成了大白灯，看着很不舒服。前面有个乘客想要关掉头上的灯，一按按到了停车键 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/232/original/00da63afe790e605.png" alt=":ablobjoy:" loading="lazy"> 上次同室友乘坐巴士时也遇到了这个情况：室友想要关掉头上的大白灯，果断点击了停车键。</p><p></p></div><hr><div class="diary-entry">02:17 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115760814469692240" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>这段时间看到了一个梗图，说的是「如果你突然对一个第一次见到的人很上头，那就是你的报应来了」。这句话实在是太符合我身边某个例子了。</p><p>今天我询问她，你做的事情迟迟没有回报，也让你、让我受了那么多次伤害，真的有意义吗。她回复我，她也知道没有意义，她好似沉浸在这个有毒的关系里无法自拔。只有在数次糟糕的事情发生之后，她才会考虑了结一切。</p><p>不过她还不想现在结束，还是打算再给一次机会。我皱眉，很是无奈。肉体、精神、重要的人，都被践踏一遍，或许人才能学到教训吧。</p><p></p></div><hr><div class="diary-entry">02:21 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115760829954488833" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我现在在手机上访问 Mastodon、PixelFed 都是用的 PWA，也就是在浏览器上访问网页、以 App 形式安装到自己的桌面上。不过每次关机或者开启省电模式，桌面上的图标都会消失，需要我再添加一次，很是麻烦。</p><p>虽然也知道它们都有对应的 App，但是网页的功能明显会更多些。比方说 PixelFed，本身核心功能就已经看着不够完善了，更别提移动端 App 这么个客户端了。</p><p></p></div><hr><div class="diary-entry">02:22 <a class="diary-source-link" href="https://pxlmo.com/p/Cytrogen/908542319809551941" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Fluffy animal</p><p></p><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/c19ce1b25-2f8843/YeiH3qsvHRJb/8bIiNqNDuUiYjZFhVYxmFC3iBo7t8VGELqTQjnbk.jpg" alt="A fluffy calico cat lying relaxed on a dark wooden floor. The cat features patches of black, brown, and orange tabby markings on its back and head, contrasted with a white chest, belly, and paws. It is wearing a purple collar with a blue tag and looking calmly to the side. A blue pet grooming brush is visible in the bottom right corner of the frame." loading="lazy"></figure></div><hr><div class="diary-entry">17:16 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115764350666348668" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打工的店里，居然只要消费 15 块钱，就送你一个小熊玻璃杯 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/167/664/original/kawausosan_45989706.png" alt=":kawausosan_45989706:" loading="lazy"> 太可爱了想自己拿走一个。</p><p></p></div></details><details data-group="diary_sections"><summary>十二月二十三日</summary><div class="diary-entry">01:47 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115766360306790396" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>老板做的小熊杯海报好丑… 好多顾客都没有注意到，谁叫她一下子写上去了那么多字 —— 谁读啊！每次都是我主动问顾客要不要，他们才知道有这么个活动。</p><p>我之后简单地在便利贴上画了小熊杯、写上去 FREE 作为吸引顾客注意力的标题，以及写上「需要消费超 15 块钱」作为条件，贴在了海报的角落。很快便有顾客注意到了这个活动，并且主动找我们要小熊杯。</p><p>我也不理解这么个玻璃杯子，为什么消费超 15 块钱就送？不应该提高一下条件吗？</p><p></p></div><hr><div class="diary-entry">01:52 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115766379499893999" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>乐事薯片的包装… 很早之前就注意到了，但还是觉得很奇怪…</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/766/371/439/168/868/original/409c7e6bcd8e631a.jpg" alt="一张摆在货架上的乐事（Lay's）经典原味（Classic）薯片包装照片。包装袋为标志性的黄色，中间印有乐事 Logo 和切片薯片的图案，净重为 8 oz (226.8 g)。" loading="lazy"></figure></div><hr><div class="diary-entry">02:05 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115766428179577501" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>下个学期开始，我就会变成一个非全日制兼读学生 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/266/original/a8c668aa4afe81d3.gif" alt=":ablobsmilehappy:" loading="lazy"> </p><p>全日制以我现在的状态实在是吃不消，工作忙就算了，偶尔还要应付一堆很烦的私事，很容易便会影响到我的学业。</p><p>我是认为没有必要一定要在四年内就毕业。四年内一直都会很焦虑就算了，这种状态下上课也很难学进去东西。</p><p></p></div><hr><div class="diary-entry">02:21 <a class="diary-source-link" href="https://pxlmo.com/p/Cytrogen/908904367137732028" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Pork chop made using air fryer. Interesting…</p><p></p><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/c19ce1b25-2f8843/wYpxyYJ4IUdy/6swcXVvtRLf7l8z47ysUFw76yTN8KDho2Fe4zMQD.jpg" alt="A close-up, overhead view of a meal served on a white plate. The dish features a golden-brown, breaded cutlet (likely katsu) on the left, accompanied by a pile of shredded cabbage on the top right. A large portion of white rice sprinkled with black sesame seeds fills the foreground, and a fork rests on the edge of the cutlet." loading="lazy"></figure></div><hr><div class="diary-entry">04:58 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115767109504122569" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>快年底了，许多 App 都推出了年终总结。万万没想到，ChatGPT 这样的 AI Agent 类 App 也有。</p><p>因为 AI 逐渐变成了大家日常生活中的工具 / 树洞，所以也能侧面反映出大家平日都在想什么、做什么。</p><p>我不用 ChatGPT，但是可以从室友那儿听到感想：她就用 ChatGPT 辅助她学习，关键词基本上都是学习 / 专业相关。</p><p></p></div><hr><div class="diary-entry">13:38 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115769153059317115" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>做了噩梦，刚被弄醒。</p><p>梦里，室友很是轻浮地告诉我，她是提供服务的公司，只要顾客有需求，为什么不做呢？</p><p>我为她又是无语又是愤怒。吵架所说的话被对方故意地无视，所以拿着桌子上的东西一个个摔在地上 —— 我估计也只会在梦里这么做了。</p><p>她倒是生气地说我歇斯底里，然后用我的电脑看什么惊爆草莓。</p><p>因为很急，所以不愉快地醒了过来。醒来后发现手机没电，一小时前的闹钟也因此被跳过。转头看到室友睡得像头猪，更是气不打一处来。</p><p></p></div><hr><div class="diary-entry">14:51 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115769440769866039" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我和教堂打过交道，还是可以瞥到低收入人群的一部分。因此看到有人轻飘飘地说着什么「美国人都是自愿流离失所」后，会觉得很愤怒 —— 他们怎么可能会是自愿的？</p><p></p></div></details><details data-group="diary_sections"><summary>十二月二十四日</summary><div class="diary-entry">03:36 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115772449940775066" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>下班同室友走回家，路过一家宠物店，门上拴着一条黑狗，旁边放着一个书包以及一个写有 Too Ugly 2 Strip 的牌子。</p><p>因为不知道这条狗是被遗弃了还是怎么样，我们站在那儿站了一会儿，直到隔壁的洗衣店里走出来一个男人，说那条狗是他的。</p><p>男人是流浪汉，流离失所没多久，也没有钱和食物。他希望很快自己就能再有住所，但是也不知道那是什么时候。他和狗打算离开纽约，一路走去亚利桑那。</p><p>离开时，他祝福我们俩，我们也祝福他能好好的。虽说如此，内心还是颇为复杂。想要帮助他，但也不知道从何下手。这个地段没有家的人太多太多了，并且数字也在一直增长。数年前一直碰到的一个流浪汉，现在已经碰不到了 —— 可能是去世了吧，在某个冬天。</p><p>我忘了是谁提起的数据了，在美国流浪三年基本上就是离死不远，但是他们为什么流浪、什么时候死去、在哪里死了，我都不得而知。</p><p></p></div><hr><div class="diary-entry">04:55 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115772761117607069" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>上 Facebook 上看了一眼，突然想起来很久以前我管它叫「脸谱网」，又因此想起来小时候用按键机登录 QQ 的时候。</p><p></p></div><hr><div class="diary-entry">06:47 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115773201353077916" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友送了块不用的表给我。因为放了有四五年没用，所以需要打开手表更换电池。</p><p>值得一提的是，室友以为手表的电池换不了，所以每次用完电都是买新的。现在家里有三四块没电的手表。</p><p>这一想法让我想起了数年前一个人不知道笔记本电脑可以充电，也是每次关机就买电脑，直到她上网询问大家哪来的那么多钱买电脑。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/773/159/298/823/903/original/fbb321566243df65.jpg" alt="一块浅粉色手表的背面特写，金属后盖已被移除，露出内部的黑色机芯。机芯上贴有一张白色绝缘贴纸，上面印有红色的英文电池更换说明：“After battery replacement, contact AC with (-) using tweezers”（更换电池后，请使用镊子连接 AC 端和负极）。" loading="lazy"></figure><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/773/160/072/033/399/original/f0c823405f5a457c.jpg" alt="一只手拿着一个拆卸下来的圆形手表机芯。表盘为米色，带有粉色的几何闪电图案装饰和金色指针。表盘中央印有“PIKACHU #025”字样，数字显示屏显示“SAT”，表明这是一款宝可梦皮卡丘联名款手表。" loading="lazy"></figure></div><hr><div class="diary-entry">16:35 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115775514329095219" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>可恶的买产品后会直接丢掉说明书的人们，你们知道我在网上搜说明书，以及发现产品功能其实很强大的样子有多么狼狈吗！</p><p></p></div><hr><div class="diary-entry">18:04 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115775861537437800" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>尝试用 React Email，发现可以无限套娃，不知为何戳中了笑点……</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/775/844/695/509/781/original/d9f94216419c89db.png" alt="React Email 开发环境的截图，呈现出一种异常的“俄罗斯套娃”式递归布局。左侧连续排列了三个重复的侧边栏面板（均显示选中“index”），层层向右嵌套展开。最右侧的主预览区域显示了 index.tsx 的最终渲染结果，包含红色的 “React Email Setup” 标题背景、蓝色的 “Theme System Active” 信息框以及底部的红色按钮。" loading="lazy"></figure></div></details><details data-group="diary_sections"><summary> 十二月二十五日</summary><div class="diary-entry">00:16 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115777325442621052" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>室友在脸谱网的一个社群内发布了不遵循规则的内容。</p><p>说是不遵循规则，其实内容并没有什么大不了的。该社群是某特定职业的休息区，规则里提到「这不是问问题的地方」。很显然，室友并没有读这条规则，并且在社群内问了一个职业相关的问题。</p><p>我认为这「并没有什么大不了的」，是因为该内容的许多评论都认真地回答了该问题，就像这条规则并不重要一样。实际上，它确实没有大不了的，并没有对社群造成任何实际的干扰，提醒一下就好了。</p><p>但并不是所有人都是那么认为。有人为此阴阳怪气了室友一句，搞得她很不开心。我说可能是你违反了规则？她认为她只是问了一个问题，现在知道不行了，但也没必要这样吧，接着灰溜溜地删除了那条内容。</p><p>这让我想起数年前我初次使用一个现在已经死掉的论坛，也是没有遵循规则。当时有两条回复，但是语气截然不同：一个嘲弄地叫我离开，另一个告诉我违反了规则、让我删除该内容。</p><p>借此我思考着，这种情况大可以普通地告知，而不是像抓住了把柄一样、随意地去攻击他人。不遵循规则的人，是故意不遵循的吗？不是的话，辱骂他们也只会给社群带来不好的印象 —— 说到底，谁赋予了你们站在道德高地上攻击他人的权利呢？</p><p></p></div><hr><div class="diary-entry">00:22 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115777347578139715" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>下班回家发现室友特么没锁门，真想掐死她。这已经不是她第一次忘记锁门了，恐怕也不会是最后一次。</p><p>幸好没有任何人进来的痕迹。</p><p></p></div><hr><div class="diary-entry">00:26 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115777366193196307" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>顺手牵羊了个小熊杯回来，不过这种杯子不太适合装热水，摸着烫手。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/777/357/016/333/407/original/4657722ae2590c8a.jpg" alt="一个透明的玻璃水杯，杯身印有黑色数字“52”和文字“livewell, laugh often, love much”以及“GoodLife Life is sweet”。杯子里有一个泡在水里的茶包，杯盖是黑色的，带有两个小耳朵。" loading="lazy"></figure></div><hr><div class="diary-entry">03:04 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115777986413975769" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>同室友来看《疯狂动物城 2》。结果一过来发现定的位置被别人坐去了… 本来想着去其他位置坐也行，避免冲突，不过我买的位置是整个影院里最好的位置。最后是室友替我去沟通，真是太好了~</p><p></p></div><hr><div class="diary-entry">21:22 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115782303514932598" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>阅读一篇文章的时候，发现是我曾经一位朋友所在的大学的研究团队写的。让我想起和他过去的时光。</p><p>他是我的初中同学，高中虽然不在一起了但在网络上还是会互相聊天。直到他越来越疏远我们：不愿意告诉我们他发生了什么，刻意掩盖自己未来的去向，还和另一位朋友产生了不知道理由的冲突。</p><p>然后不再联系的几年后，他随意地发布了一条动态，上面透露着他之后去了哪里。而这些信息，是过去的我们曾经问过他，但是都被他避开了话题的信息。</p><p>我不知道发生了什么，现在想来，可能最从开始他就不喜欢我们吧。我以为我们是朋友，但可能并不是那样。</p><p></p></div></details><details data-group="diary_sections"><summary>十二月二十六日</summary><div class="diary-entry">00:49 <a class="diary-source-link" href="https://pxlmo.com/p/Cytrogen/909968440916923797" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>My duck is laying an egg.</p><p></p><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/c19ce1b25-2f8843/cs1Zd52lpeud/xbOWDtjg1wH755uHvz57uXEmkoobqJHxEqrBgMIb.jpg" alt="A yellow rubber duck with an orange beak sitting on top of a blue and white " rubik's="" snake"="" puzzle="" toy,="" which="" has="" been="" folded="" into="" a="" rounded,="" geometric="" shape.="" the="" objects="" are="" resting="" on="" dark="" wooden="" surface.="" in="" blurred="" background,="" white="" reusable="" water="" bottle="" is="" visible="" against="" light-colored="" wall."="" loading="lazy"></figure></div><hr><div class="diary-entry">16:11 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115786742257011412" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>早上起床感觉自己感冒了… 喉咙里好像有什么一样，结果还要赶早来开店。</p><p>前几天和同事一起悄咪咪吐槽这份兼职：老板喜欢立些莫名其妙的规矩然后罚钱；小费不给我们，虽然会被用在团建上，但是我对团建聚餐一点兴趣都没有；过节还要掏钱买礼物送给同事，尽管我也会收到礼物，不过我也不需要这些东西吧！</p><p></p></div><hr><div class="diary-entry">20:54 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115787855267429691" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>炒饭怎么给冰淇淋勺 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/040/685/original/fa1e2ea265081315.png" alt=":blobonfire:" loading="lazy"></p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/787/845/884/797/930/original/1784f3546b3e676e.jpg" alt="一份装在黑色外卖盒里的炒饭特写，米饭中可见鸡蛋、玉米粒、青豆和黑芝麻，一把木质勺子插在炒饭中，背景模糊处有一罐红色汽水和白色容器。" loading="lazy"></figure></div><hr><div class="diary-entry">23:32 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115788475413079476" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打工摸鱼期间室友发给我一张截图，说是今晚纽约会下足足 9 英寸厚的雪，也就是差不多 2 分米厚。可能是因为这个警报，街上几乎没几个人。我和同事依旧在吐槽这份兼职：不赚钱，可能快倒闭了，换其他兼职做吧…… 六点整我打卡下班，发现街上都撒满了融雪剂，天上也慢慢落下毛毛雪。</p><p></p></div><hr><div class="diary-entry">23:34 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115788483243029490" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>小破项目第一次有了完全不认识的新用户 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/148/109/original/930c5953aba2153e.gif" alt=":ablobcatpnd_heart_happy:" loading="lazy"> </p><p></p></div></details><details data-group="diary_sections"><summary>十二月二十八日</summary><div class="diary-entry">04:15 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115795252854357511" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>果然是生病了… 早上起来身体恶化，喉咙很干，久违开始流鼻涕，肌肉也很酸痛。就算这样我还是去上班了，幸好有这场雪，店里不忙。</p><p>晚上回家的时候倒在地上，过了一段时间再爬到床上去。室友的小破猫跟我欠了它一百万猫条一样，冲着大声喵喵叫。我哪有空管你，我还要睡觉。</p><p>室友回家后拜托她给我做东西吃。这期间我躺在床上刷 Hacker News 看，看到一个有意思的文章，是关于把手机的颜色变成 Grayscale 的。我想要尝试几天，看看效果。代价是我没法看到自己喜欢的橘色。</p><p></p></div><hr><div class="diary-entry">15:38 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115797937784773774" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>第一次知道会有人用脚本扫 .env 路由 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/070/960/original/50f556343257c59f.png" alt=":wolf_think:" loading="lazy"> 如果是小白没弄 ignore 的话，密钥就要被看光光了。</p><p></p><blockquote class="diary-thread-reply">19:55 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115798947071780942" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我说怎么昨天项目管理问我为什么用不了，原来是脚本小子也去爬了我客户端，AI 爬虫机器人也来爬我，直接把便宜服务器干 down 了……</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary> 十二月二十九日</summary><div class="diary-entry">00:13 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115799962765152152" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>傻眼我也太词穷。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/799/952/063/438/517/original/dee4d4de559ac05a.png" alt="深色界面的搜索结果栏，左侧为“Search”，中间显示关键词“有意思a ‖‖ (*)”，右侧显示结果计数“‘8 / 8”，并包含上下箭头与关闭（×）按钮。" loading="lazy"></figure><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/799/953/534/649/594/original/87a4700f8c88f77d.png" alt="深色界面的搜索结果栏，左侧显示“Search”，中间为高亮关键词“有趣 Aa ‖‖ (*)”，右侧显示结果计数“1 / 12”，并有上下箭头和关闭（×）图标。" loading="lazy"></figure></div><hr><div class="diary-entry">02:19 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115800458452123293" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>朋友和我说，美国的蜜雪冰城特制了 200% 糖的奶茶款式，却依然被美国人嫌弃不够甜。</p><p>我听后瞳孔震惊：我喝奶茶或者果茶都只会点 30% 甚至说无糖，200% 太离谱了。</p><p>后面想想，每个奶茶品牌的糖分标准都不一样。我去的都是本地小作坊，全糖已经是改良后符合美国人口味的糖度。</p><p></p></div><hr><div class="diary-entry">15:36 <a class="diary-source-link" href="https://pxlmo.com/p/Cytrogen/911278808331404096" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Squeeeeeze the cat!</p><p></p><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/c19ce1b25-2f8843/ZDhoQRBtAZ6s/eMBnqqjOclOBjcQnC8KcvDix5BF2PnPe8ID9Qb1P.jpg" alt="A close-up view of a sleeping cat with brown tabby markings on its head and a white muzzle. The cat is resting its head on a person, lying against a light cream-colored fabric with its eyes closed and one white paw tucked near its face. A portion of a human leg is visible in the upper left background." loading="lazy"></figure></div><hr><div class="diary-entry">15:48 <a class="diary-source-link" href="https://pxlmo.com/p/Cytrogen/911281792436847826" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>Roommate made this for me while I was sick sick.</p><p></p><figure class="diary-media"><img src="https://assets.pxlmo.com/public/m/_v2/905147513046556367/c19ce1b25-2f8843/mH9jpkf4vOfd/18Fa2vOQbo3Xqpvu3MibaLacw6LfJwQBUXsYAelz.jpg" alt="A top-down view of a meal featuring sliced, breaded meat cutlets seasoned with herbs and red spice, served alongside a poached egg sprinkled with paprika, over a bed of creamy shell pasta with a fork visible at the bottom." loading="lazy"></figure></div><hr><div class="diary-entry">18:31 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115804281933908845" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>联系了 pxlmo 的团队但是暂时没有回复，姑且发一些动物照片在 mastodon 好了。</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/804/280/173/833/554/original/fd2d58c8b6a09bd7.jpg" alt="​一张俯拍视角的照片，显示一只棕白相间的斑纹猫舒适地躺在一个人的双腿之间。猫咪眯着睡眼，神情困倦地直视前方，一只白色的前爪向下伸展搭在人的腿上。背景中可以看到这个人穿着带有白色横条纹的蓝色短裤。" loading="lazy"></figure></div><hr><div class="diary-entry">19:39 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115804546496586873" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>本来是打算下个学期只上三节课，美美做个非全日制学生。结果同事看了我的课表后，告诉我下个学期她们几个都有事情忙。如果我告诉老板我是这么个安排，老板会想方设法让我一周上七天的……</p><p>于是我又悄咪咪加了个中文课。当然不是那种中文入门课，我同学校的中文教授联系过，他让我随便选一个高级课。最后我选了个短篇小说课，顺便可以弥补一下我小时候缺失的阅读量。</p><p></p></div><hr><div class="diary-entry">20:02 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115804637766469400" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>前些天和同事聊蜜雪。我们做的是奶茶 + 咖啡，但是生意越来越差。我认为原因有这些：</p><p>一、品牌力弱，价格打不下去。</p><p>我们这个奶茶品牌本来就是本地小作坊，又贵又不好喝，全是粉。国内的大牌子打进来，又是真水果又是真奶的，价格还比你便宜，凭什么别人喝你？</p><p>咖啡品牌更好笑，刚开业的时候居然没有任何营销。它在国内不算什么很小的牌子，但是没有任何营销是认真的吗？除非是死忠粉靠着 App 找过来，不然别人根本不知道这里有这个牌子。</p><p>二、地段糟糕。</p><p>店的地段在学校附近，除此之外就是政府楼和来乘车的上班族。这意味着能在这个地段来买饮料的要么是住在这附近的，要么是放学的学生，要么就是急着走的上班族。</p><p>首先这个店快到中午才开门，早上六七点想喝咖啡的全都不是我们的顾客。其次是能住在这个地段的人多数为传统咖啡派，有许多顾客对这个咖啡品牌表达过不满：为什么不能给我糖包、我自己加？为什么美式只能加纯牛奶、不能加燕麦奶和椰奶？什么叫水果咖啡？你知道这附近哪里有正常咖啡店吗？</p><p>老板为了降本增效，不招新人了，还把做得好的全部安排在客人多的主店，让我们这些员工做所有过去几年都不用做的活。或许这个分店只能被慢慢放弃掉吧……</p><p></p></div></details><details data-group="diary_sections"><summary> 十二月三十日</summary><div class="diary-entry">17:44 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115809757546206348" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>打算将 Instagram 上的 Story 和 Collection 都撤下来，结果 Web 没有这个功能……</p><p></p></div><hr><div class="diary-entry">18:18 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115809892868799137" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>出来面试校友，没想到对方早十几分钟到。我还在办公室附近狼狈买饭呢…</p><p>在美式中餐馆里，我喜欢点虾捞面、新加坡炒米粉和扬州炒饭，全部多葱多豆芽不要蛋~ 有些中餐馆提供炸鸡胗和炸鸡串，也很好吃。不过不同店里对鸡肉的处理也不同，比如我现在去的这家中餐馆里鸡肉就很柴很难吃。</p><p></p><blockquote class="diary-thread-reply">23:28 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115811110741914786" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>校友说他视奸过我的博客 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/094/853/original/6a22cd240c3f9b9e.png" alt=":fox_30:" loading="lazy"> </p><p>我聊到之前发生过的某件事，他 belike：「根据你博客里写的结果是不是……」</p><p>我滴妈呀！</p><p></p></blockquote></div></details><details data-group="diary_sections"><summary>十二月三十一日</summary><div class="diary-entry">08:17 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115813189422558304" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>店里团建，喝了点酒。酒精含量虽然只有 4.5%，但我真的喝不来，已经是摇摇晃晃走回家了…</p><p>3 点才回家，晚安吧。</p><p>PS：要的制冰机笨蛋同事买成刨冰机；送给妹妹好了。</p><p></p></div><hr><div class="diary-entry">14:34 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115814675215582469" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>恐怖校友（现在应该称其为同事）凌晨不睡觉把我安排给他的活干完了 <img class="emoji" src="https://media.otter.homes/custom_emojis/images/000/136/430/original/232302945e6885c8.png" alt=":pikachu_surprise:" loading="lazy"> </p><p></p></div><hr><div class="diary-entry">16:10 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115815049379224455" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>因为昨晚喝了酒，老板不放心我坐地铁回公寓，叫住在我父母家附近的同事顺路送我回家。</p><p>原本以为没有很醉，结果下车后走路歪歪扭扭的，进了房间便倒在床上不能自己… 后劲真可怕吧。</p><p>狗看到我回家很是开心；晚上猫被关在地下室，怕它趁人不注意咬沙发。</p><p>早上醒来，感觉身体没什么太大的问题，就是后脑勺隐隐作痛。</p><p>猫比之前放得开了许多。过去还以为它是个孤僻小猫，结果一放上来、对着狗就是一个熊抱、抓着人家尾巴不放 —— 也就狗心善，不跟它一般见识。</p><p>猫的体型也是变化许多，一小段时间不见又变大了，快赶上了狗。说不定等它长完，还要比狗大上不少。</p><p>（我才发现我的嘟文引用设置的是仅自己）</p><p></p><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/815/037/868/731/119/original/375729d766926760.jpg" alt="我的毛茸茸红棕色泰迪犬，戴着一个心形的红色铭牌，正坐在木地板上，歪着头，用深色的眼睛向上看。" loading="lazy"></figure><figure class="diary-media"><img src="https://media.otter.homes/media_attachments/files/115/815/039/463/627/427/original/f5c72a7dadfeaa6a.jpg" alt="我的棕色、黑色和白色相间的三花猫，戴着带有蓝色花形铭牌的项圈，站在木地板上，好奇地向上看。" loading="lazy"></figure><blockquote class="diary-thread-reply">17:06 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115815272574841821" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>将手机调成 Grayscale 后，最大的问题就是 —— 我自己也看不出来照片里有什么颜色！</p><p>我让 LLM 生成了 Alt 文字，发现它说图片 1 是红棕色的狗。嗯… 我的狗是红棕色的吗？其实 LLM 不说的话，我都看不出来狗戴着铭牌（我第一次认识「铭牌」这个词）。</p><p>说到 Alt 文字，早上看到了 AltBot 被关闭一事，以及关闭的理由，实在是让人一醒来就开始思考：我一直以为「专业」和「精确」的 Alt 文字，原来对于它们的实际使用者而言，可能是一种负担。而我会有那些想法，不过是因为我根本就不是这个人群 —— 我自己压根不读 Alt 文字。人不穿同个鞋子，是无法感同身受的，更别提换位思考了。</p><p>我的思维又借此回到昨天聚餐，我因为无聊开始阅读书签里还未阅读的文章。其中一篇文章里，作者是肯尼亚人。因为从小习得的写作风格「很像」LLM，而被数个读者抨击。但肯尼亚人就是那么学习写作的，根本不是他们像 LLM，而是 LLM 像他们。那些抨击的人有意思的是，他们好像根本看不到双语、多语者，默认世界上所有说英语的人都是像他们那样说话。</p><p>关于英文写作，我之前也差不多啦，会充分使用一些现在被认为「LLM 写作」的证据，比如我最喜欢的破折号。现在写东西倒是全部「降级」、口语化，也是怕再次被教授认为是 LLM 生成的，囧。</p><p></p><blockquote class="diary-thread-reply">17:35 <a class="diary-source-link" href="https://m.otter.homes/@Cytrogen/115815383417950311" target="_blank" rel="noopener noreferrer" title="查看原帖">          <svg class="icon icon-external-link" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">            <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>            <polyline points="15 3 21 3 21 9"></polyline>            <line x1="10" y1="14" x2="21" y2="3"></line>          </svg>        </a><br><p>我思考了一下认为：需求还是高度情境化的。一张图片，精确客观的 Alt 文字可以满足回答 What/Who/Where/When，发送者可以自行加上主观的想法来回答 Why。</p><p>不过那个 Thread 我没有看完，还是让我酒醒一会儿吧…</p><p></p></blockquote></blockquote></div></details></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;开始下雪了。一年也要过去了，不知道大家的 2025 年如何呢？&lt;/p&gt;</summary>
    
    
    
    <category term="想法迭代" scheme="https://blog.cytrogen.icu/categories/%E6%83%B3%E6%B3%95%E8%BF%AD%E4%BB%A3/"/>
    
    
  </entry>
  
  <entry>
    <title>乙巳想法复盘</title>
    <link href="https://blog.cytrogen.icu/posts/f77.html"/>
    <id>https://blog.cytrogen.icu/posts/f77.html</id>
    <published>2025-12-30T17:29:41.000Z</published>
    <updated>2026-02-19T07:42:07.353Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>Steph Ango 每年年底都会问自己 <a href="https://stephango.com/40-questions">40 道问题</a>。我认为颇有回答意义，有时候就是需要这样的东西来自省。</p><span id="more"></span><h4 id="1-你今年做了哪些之前从未做过的事"><a class="markdownIt-Anchor" href="#1-你今年做了哪些之前从未做过的事"></a> 1. 你今年做了哪些之前从未做过的事？</h4><p>今年我开始写 <a href="/categories/%E6%83%B3%E6%B3%95%E8%BF%AD%E4%BB%A3">月刊</a> 了。我认为这是信息整合的同时，也表达了我对部分信息的看法。这些信息多数来自于 Hacker News，少数来自我订阅的博客。不过我明明可以更多记录我对后者的想法，下个月开始我就这么做吧！</p><p>至于线下的话，我注册了个公司、做小破项目，希望可以加油吧。</p><h4 id="2-你有没有遵守年初时和自己许下的约定"><a class="markdownIt-Anchor" href="#2-你有没有遵守年初时和自己许下的约定"></a> 2. 你有没有遵守年初时和自己许下的约定？</h4><p>我年初的时候没有给自己许下任何承诺。</p><h4 id="3-你身边有人生孩子了吗"><a class="markdownIt-Anchor" href="#3-你身边有人生孩子了吗"></a> 3. 你身边有人生孩子了吗？</h4><p>虽然没有谁生小孩了，不过大我一岁的表姐今年刚结婚没多久便怀孕了，让人意外。</p><h4 id="4-你身边有人去世了吗"><a class="markdownIt-Anchor" href="#4-你身边有人去世了吗"></a> 4. 你身边有人去世了吗？</h4><p>远在故乡的大堂舅因病去世了，享年仅 60 岁。</p><h4 id="5-你去了哪些城市州国家"><a class="markdownIt-Anchor" href="#5-你去了哪些城市州国家"></a> 5. 你去了哪些城市/州/国家？</h4><p>哪里也没有去，我只是又在纽约待了一年。</p><h4 id="6-明年你想要获得哪些你今年没有的东西"><a class="markdownIt-Anchor" href="#6-明年你想要获得哪些你今年没有的东西"></a> 6. 明年你想要获得哪些你今年没有的东西？</h4><p>我想要独立思考、自制和时间管理的能力。</p><h4 id="7-今年的哪个或哪些日子会铭刻在你的记忆中为什么"><a class="markdownIt-Anchor" href="#7-今年的哪个或哪些日子会铭刻在你的记忆中为什么"></a> 7. 今年的哪个或哪些日子会铭刻在你的记忆中，为什么？</h4><p>今年并没有这样的日子。我如果不是开始写日记了，否则会忘记很多事情。</p><h4 id="8-你今年最大的成就是什么"><a class="markdownIt-Anchor" href="#8-你今年最大的成就是什么"></a> 8. 你今年最大的成就是什么？</h4><p>同时有三份工作？</p><h4 id="9-你今年最大的失败是什么"><a class="markdownIt-Anchor" href="#9-你今年最大的失败是什么"></a> 9. 你今年最大的失败是什么？</h4><p>有三份工作的同时还是一个全职学生。</p><h4 id="10-你今年还遇到过哪些困难"><a class="markdownIt-Anchor" href="#10-你今年还遇到过哪些困难"></a> 10. 你今年还遇到过哪些困难？</h4><p>同时兼顾学业、工作和乱七八糟的东西，难免出现时间管理不好的问题。我有时候还要和项目管理、教授、老板掐架，真是麻烦！</p><h4 id="11-你今年是否生过病或受过伤"><a class="markdownIt-Anchor" href="#11-你今年是否生过病或受过伤"></a> 11. 你今年是否生过病或受过伤？</h4><p><s>今年没怎么生过病，我貌似就不是多病体质。</s> 但说到受伤，自从开始打工了，三天两头都会不小心伤到自己。</p><p>好的当我没说，我在 12 月底生了场大病。拖着身体去上班，第二天还要被老板训，淦！</p><h4 id="12-你今年买过的最好的东西是什么"><a class="markdownIt-Anchor" href="#12-你今年买过的最好的东西是什么"></a> 12. 你今年买过的最好的东西是什么？</h4><p>500 美元左右搭建的新电脑。大一用 150 美元搭建的电脑内存和 CPU 实在是不够用，只能用来玩游戏。新电脑换上了 32GB 内存，达到了可以用 JetBrains 全家桶的标准！</p><h4 id="13-谁的行为值得去表扬"><a class="markdownIt-Anchor" href="#13-谁的行为值得去表扬"></a> 13. 谁的行为值得去表扬？</h4><p>没有人。</p><h4 id="14-谁的行为令你感到震惊"><a class="markdownIt-Anchor" href="#14-谁的行为令你感到震惊"></a> 14. 谁的行为令你感到震惊？</h4><p>没有人。</p><h4 id="15-你大部分的钱都花到哪里去了"><a class="markdownIt-Anchor" href="#15-你大部分的钱都花到哪里去了"></a> 15. 你大部分的钱都花到哪里去了？</h4><p>我大部分的钱都用在线上购物上了。因为范围很广，从家具到厕纸，所以无法具体得知到底花在什么东西上最多。</p><h4 id="16-有什么事让你感到超级-超级-超级兴奋"><a class="markdownIt-Anchor" href="#16-有什么事让你感到超级-超级-超级兴奋"></a> 16. 有什么事让你感到超级、超级、超级兴奋？</h4><p>我装了新电脑。有了新的 CPU 和内存后，可以流畅做的事情变多了。</p><h4 id="17-哪首歌会永远让你想起这一年"><a class="markdownIt-Anchor" href="#17-哪首歌会永远让你想起这一年"></a> 17. 哪首歌会永远让你想起这一年？</h4><p>我不太清楚，或许是台湾摇滚乐这一类吧，今年听的尤其多。</p><h4 id="18-与去年的这个时候相比你是感到更快乐还是更悲伤了变得更瘦还是更胖了变得更富还是更穷了"><a class="markdownIt-Anchor" href="#18-与去年的这个时候相比你是感到更快乐还是更悲伤了变得更瘦还是更胖了变得更富还是更穷了"></a> 18. 与去年的这个时候相比，你是：感到更快乐还是更悲伤了？变得更瘦还是更胖了？变得更富还是更穷了？</h4><p>过去两年我已经很悲伤了，所以今年算是变得快乐些。</p><p>瘦或者胖，貌似我的体重十年里都没有什么变化，样貌也是。</p><p>钱包的话，肯定是变厚了，但是也没有变很多。</p><h4 id="19-你希望自己能做得更多的是什么"><a class="markdownIt-Anchor" href="#19-你希望自己能做得更多的是什么"></a> 19. 你希望自己能做得更多的是什么？</h4><p>开发更多的小工具。至少把自己手头上的一个项目做到「可用」吧，不要再挖坑了。</p><h4 id="20-你希望自己能做得更少的是什么"><a class="markdownIt-Anchor" href="#20-你希望自己能做得更少的是什么"></a> 20. 你希望自己能做得更少的是什么？</h4><p>少刷以算法为主的平台，比如小红书和哔哩哔哩（特指短视频功能）。每次一刷就是一个小时过去，烦死了。</p><h4 id="21-你是如何度过节假日的"><a class="markdownIt-Anchor" href="#21-你是如何度过节假日的"></a> 21. 你是如何度过节假日的？</h4><p>我几乎不过。就算过，也是和室友买菜吃点好的，偶尔出去吃。</p><p>不过今年有点意外，打工的店居然有聚餐，实在是有点讨厌。这次的圣诞节应该是我人生中第一次送别人礼物，虽然是半强迫的，并且别人也会给我礼物，但还是喜欢不起来。</p><h4 id="22-你今年坠入爱河了吗"><a class="markdownIt-Anchor" href="#22-你今年坠入爱河了吗"></a> 22. 你今年坠入爱河了吗？</h4><p>没有。</p><p>我这些年都有在思考，我需要恋爱吗？</p><p>我的结论是，我想从恋爱中获得的东西，实际上从友谊上也可以得到：关怀、陪伴、理解、爱…… 除了性。</p><p>而我是最不需要性的那种人。</p><p>只是要获得这些让人幸福的东西，无论是和谁、什么人都非常难，所以要努力。</p><h4 id="23-你是否有讨厌某个你去年此时不觉得讨厌的人呢"><a class="markdownIt-Anchor" href="#23-你是否有讨厌某个你去年此时不觉得讨厌的人呢"></a> 23. 你是否有讨厌某个你去年此时不觉得讨厌的人呢？</h4><p>有，一些朋友让我觉得愈来愈不舒服。我认为这是因为我和他们已经过了一个阶段，新的阶段下我们的相性会不如过去的要高。</p><p>不知道是因为忙碌而导致的耐性降低，许多人的行为都让我觉得不可理喻，我今年没少拉黑熟人：「我跟你们也没有熟到那种程度吧！」有时候就会这么想。</p><h4 id="24-你最喜欢的电视节目是什么"><a class="markdownIt-Anchor" href="#24-你最喜欢的电视节目是什么"></a> 24. 你最喜欢的电视节目是什么？</h4><p>我不看电视节目。</p><p>如果非要说任何视频的话，其实也没有。</p><h4 id="25-你读过最好的一本书是什么"><a class="markdownIt-Anchor" href="#25-你读过最好的一本书是什么"></a> 25. 你读过最好的一本书是什么？</h4><p>《不原谅也没关系》，算是解答了我多年的各种疑惑吧，也给了我新的视角去理解一些事情。</p><h4 id="26-你今年发现的最好听的一首歌是什么"><a class="markdownIt-Anchor" href="#26-你今年发现的最好听的一首歌是什么"></a> 26. 你今年发现的最好听的一首歌是什么？</h4><p>Ginger Root 的 Loretta。</p><h4 id="27-你今年看过最喜欢的一部电影是什么"><a class="markdownIt-Anchor" href="#27-你今年看过最喜欢的一部电影是什么"></a> 27. 你今年看过最喜欢的一部电影是什么？</h4><p>今年看的电影不多，最喜欢的应该是《南京照相馆》。我认为拍的很有意思，尤其是对日本兵的刻画。</p><h4 id="28-你今年吃过最好吃的一顿饭是什么"><a class="markdownIt-Anchor" href="#28-你今年吃过最好吃的一顿饭是什么"></a> 28. 你今年吃过最好吃的一顿饭是什么？</h4><p>不好说是哪一顿呢。最让我心心念念的肯定是烩面了，因为我是碳水大王。</p><h4 id="29-有什么是你想要且得到了的"><a class="markdownIt-Anchor" href="#29-有什么是你想要且得到了的"></a> 29. 有什么是你想要且得到了的？</h4><p>和家人的关系缓和了许多，家里也多了只小猫，不过我还是不怎么想要回家。</p><h4 id="30-有什么是你想要却没有得到的"><a class="markdownIt-Anchor" href="#30-有什么是你想要却没有得到的"></a> 30. 有什么是你想要却没有得到的？</h4><p><em>让那个人永远离开我的生活吧。仅是让我知道在未来还能听到这个人的事情就够让我想要离开这个世界了。</em></p><h4 id="31-你生日那天做了什么"><a class="markdownIt-Anchor" href="#31-你生日那天做了什么"></a> 31. 你生日那天做了什么？</h4><p>我没做什么特殊的事情。</p><p>前两年的生日发生了一些不愉快的事情，以至于差点对生日有 PTSD 了。</p><h4 id="32-有什么还未发生的事如果发生了会让你的这一年变得无比满足"><a class="markdownIt-Anchor" href="#32-有什么还未发生的事如果发生了会让你的这一年变得无比满足"></a> 32. 有什么还未发生的事，如果发生了，会让你的这一年变得无比满足？</h4><p><em>那个人的消失。</em></p><h4 id="33-你会如何描述你今年的个人时尚风格"><a class="markdownIt-Anchor" href="#33-你会如何描述你今年的个人时尚风格"></a> 33. 你会如何描述你今年的个人时尚风格？</h4><p>自高四开始（美国高中有四年）我的时尚风格就在「衬衫 + 西装裤 + 毛衣」这个固定搭配没变过了。</p><p>有些人老问我为什么穿这样奇奇怪怪的样子、为什么不穿卫衣，反倒是让我觉得有点震惊：你要那么穿无所谓啦，但是只知道卫衣的话，不要怪我说你没有衣品哦！</p><p>不过我今年年底解锁了「毛衣 + 高领衫」的穿法。</p><h4 id="34-是什么让你保持理智"><a class="markdownIt-Anchor" href="#34-是什么让你保持理智"></a> 34. 是什么让你保持理智？</h4><p>好面子。</p><h4 id="35-你最欣赏哪个名人公众人物"><a class="markdownIt-Anchor" href="#35-你最欣赏哪个名人公众人物"></a> 35. 你最欣赏哪个名人 / 公众人物？</h4><p>没有！我和他们都不熟。</p><h4 id="36-哪个政治问题最令你有感而发"><a class="markdownIt-Anchor" href="#36-哪个政治问题最令你有感而发"></a> 36. 哪个政治问题最令你有感而发？</h4><p>平日能想到很多，现在真要我说一个出来，反而说不出来。</p><h4 id="37-你想念哪些人"><a class="markdownIt-Anchor" href="#37-你想念哪些人"></a> 37. 你想念哪些人？</h4><p>我今年没有想念过任何人。</p><h4 id="38-在你新认识的人之中谁是最好的"><a class="markdownIt-Anchor" href="#38-在你新认识的人之中谁是最好的"></a> 38. 在你新认识的人之中，谁是最好的？</h4><p>我今年新认识的人里，居然都是打工伙计。但是我们交谈不够深入，我很难说谁谁谁是最好的。</p><h4 id="39-今年你学到了什么宝贵的人生经验"><a class="markdownIt-Anchor" href="#39-今年你学到了什么宝贵的人生经验"></a> 39. 今年你学到了什么宝贵的人生经验？</h4><p>我忘了在哪里看到的了，总之是一句谚语，意思是「学习新的事物的时候要像一个婴儿，把过去自己学过的其他东西都忘掉」。</p><p>有时候可能会因为自己在某个领域里略有手脚，反而导致在一个新的领域内无法接受自己吃瘪。这样的心态一旦长久、对自己就很不利。</p><h4 id="40-能够总结你这一年的一句话是什么"><a class="markdownIt-Anchor" href="#40-能够总结你这一年的一句话是什么"></a> 40. 能够总结你这一年的一句话是什么？</h4><p>我没有变好，但至少开始看清自己在消耗什么的时间。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;Steph Ango 每年年底都会问自己 &lt;a href=&quot;https://stephango.com/40-questions&quot;&gt;40 道问题&lt;/a&gt;。我认为颇有回答意义，有时候就是需要这样的东西来自省。&lt;/p&gt;</summary>
    
    
    
    <category term="年终总结" scheme="https://blog.cytrogen.icu/categories/%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/"/>
    
    
  </entry>
  
  <entry>
    <title>中文网络写作上的规则习惯</title>
    <link href="https://blog.cytrogen.icu/posts/c5d9.html"/>
    <id>https://blog.cytrogen.icu/posts/c5d9.html</id>
    <published>2025-12-29T17:41:51.000Z</published>
    <updated>2026-02-09T17:16:55.009Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我一直在思考，什么时候应该使用粗体、什么时候应该使用斜体…… 以下是我的看法，相当于抛砖引玉。</p><span id="more"></span><h2 id="强调"><a class="markdownIt-Anchor" href="#强调"></a> 强调</h2><p>之前我提到过，我给博客的粗体效果添加了点状线，让它看上去更加突出。后面我还是将粗体改回了最开始的仅 <code>fontWeight</code> 样式。一是有读者提醒我粗体太显眼可能会导致其他读者只读了粗体的内容，但无视了其他内容；二是我自个儿也觉得这个粗体太碍眼。</p><p>我以前通常会在这些情况下使用粗体：</p><ul><li>强调语气，通常是一个句子里的一部分文字变粗体</li><li>强调我觉得有意思的内容</li><li>强调总结</li></ul><p>如果是后两者的话，添加点状下划线感觉也不错。但是一篇文章里出现太多总结或者我觉得有意思的句子，该怎么办呢？实在是无法让读者好好阅读非粗体的内容。也就是说，粗体也分级别。我感觉出来的级别划分如下：</p><ol><li>总结了整篇文章的，可以使用粗体和点状下划线</li><li>总结了一个要点或者一个自然段的，只使用粗体</li><li>有意思的内容，使用其他样式</li></ol><p>关于其他样式，我还在摸索中。不过有读者向我推荐了 <code>text-emphasis</code>，让人眼前一亮。</p><p>经过一些自问自答后，我认为读者们看到粗体，第一时间想到的是「如果这里不看，后面会出问题」。也就是说，粗体是信息结构的一部分，而非装饰。这和我上述提到的「强调总结」一致。重要的是，粗体是可以改变读者的阅读路径的，因为它实在是太突出太突出了。人们看文章的第一眼，其实就会发现粗体、并且阅读它。</p><p>而着重号（也就是 <code>text-emphasis</code> 可以达成的效果，两者不是同个东西。以下依旧简称着重号）不会改变读者的阅读路径。只有在读者看到这一段的时候，读者才会发现着重号。它可以用来做我先前提到的两个事情：「强调语气」和「强调我觉得有意思的内容」。用法可以很多样：反讽、微妙的强调、我觉得这个点很妙、需要读者慢下来体会的一小段词……</p><p>还有两个可以用于强调的样式：下划线和斜体。下划线我几乎不使用，不过斜体我很常用。除了处理需要括起来的英文（比如书名），我也会用于异化语气。</p><p>作为例子：</p><div class="danger alert-info"><p>当我排查这个问题的时候，其实一开始完全没往 Hexo 的标签实现上想。我以为是 Markdown 渲染器在处理 HTML 时出了 bug，直到我把生成的内容原样打印出来，才发现真正的问题点。Hexo 在渲染标签时返回的是多行字符串，而 Markdown 在解析时会把这些行首的空白当成缩进，从而直接识别为代码块。</p><p>这也就解释了为什么页面最后会出现 <code>&lt;pre&gt;&lt;code&gt;...&lt;/code&gt;&lt;/pre&gt;</code> 这样的结构：<strong>只要返回的不是一行 HTML，就一定会触发这个行为</strong>。</p><p>更微妙的是，这个问题并不是每次都会暴露出来。如果你生成的标签内容本身比较短，看起来就像是正常输出；但一旦 HTML 稍微复杂一点，被拆成了<span class="emphasis">多行</span>，问题就立刻出现了。这里的「<u>多行</u>」并不是一个实现细节，而是整个渲染流程里最容易被忽略、却又最致命的条件。</p><p>所以后来我干脆换了一个思路：不去试图「修复」Markdown 的解析逻辑，而是接受它的规则，<em>反过来约束自己生成的 HTML 结构</em>。从结果来看，这个策略反而简单得多，也稳定得多。</p></div><p>关于我先前提到的分级，整套系统我觉得没有什么问题，不过没有详细解释粗体的密度。我想了这么一个规则：</p><ol><li>文章里的粗体是有限资源。对于小于一千字的短文，不要使用超过 5-7 次粗体；对于长文，每 3-5 个自然段，最多 1 处粗体。</li><li>如果读者只看粗体，他能不能复述你的结论？如果不能，不要使用粗体；如果能，那用得好。</li></ol><h4 id="换行"><a class="markdownIt-Anchor" href="#换行"></a> 换行</h4><p>不过呢，还有一个有意思的东西可以用于强调 —— 换行。</p><p>在中文网络写作中，换行的强调力会小于粗体，但是大于其他样式。拆段是一件很重要的事情。通常读者对段落长度的容忍度是这样的：</p><ul><li>2-4 行：舒服</li><li>5-6 行：还能接受</li><li>7 行以上：开始跳读</li></ul><p>提出这一点的原因是，这些都是为了可读性，那么就要从读者的视角出发。段落是组成文章的重要元素之一，不在这上面花功夫怎么行呢？</p><p>通常来说，会建议在一个自然段内只推进一个信息点。不过我认为没必要这么极端，推进两三个信息点也没有关系，取决于这个信息点的内容。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我一直在思考，什么时候应该使用粗体、什么时候应该使用斜体…… 以下是我的看法，相当于抛砖引玉。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="博客" scheme="https://blog.cytrogen.icu/tags/%E5%8D%9A%E5%AE%A2/"/>
    
  </entry>
  
  <entry>
    <title>离开纽约市的一天</title>
    <link href="https://blog.cytrogen.icu/posts/18b0.html"/>
    <id>https://blog.cytrogen.icu/posts/18b0.html</id>
    <published>2025-12-29T14:35:15.000Z</published>
    <updated>2026-02-09T17:16:55.549Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我的坏习惯是记录下来的事情不会第一时间加工成文章发布。这件事是 5 号发生的，我于 19 号开始起草、29 号才发布……</p><span id="more"></span><p>室友去考 EA 证的第一场考试。我跟她一起去，相当于一个陪同。</p><p>考场在新泽西一个小地方里，地方实在不大。建筑物使用的是一种很老式的电梯：门还没完全关上就开始下降，按钮少得可怜，也没有显示楼层的屏幕。整条走廊很窄，除了考场就是辅导班，看起来不像考试中心，更像是临时拼出来的空间。</p><p><img src="/posts/18b0/door.webp" alt="door" loading="lazy"></p><p>很诡异啊。</p><p>等待期间我无聊得很，幸好带了日语作业和 iPad。上个月的日语作业我全部忘记做了。</p><p>iPad 本来是用来读书的。我最近在读《无可羡慕：朝鲜人的普通生活》，整体感觉像是小说，反而很适合这种等人的场合。书中记录的生活细节，让我第一次对那个过去几乎完全陌生的国家和其中的人有了一点具体的印象。</p><p>不远处坐着一个男人，手机一直在响不同的铃声。我起初以为他是在故意放铃声玩，可能是提神吧，哈哈。结果过了几分钟他接了电话，说「不要再给我打电话了」。</p><p>居然是真的电话啊……</p><p>既然是在考场，倒是不要放任电话响这么久吧！</p><p>我在等待区坐了个几小时，有工作人员过来告诉我，作为陪同不能在等待区逗留，让我去电梯旁边的长椅那边待着去。好吧，也没什么区别，都是坐着读书。</p><p>又等了一段时间，室友终于出来了。果不其然，她通过了考试 —— 她第一次做模拟考试的时候，其实就已经考到了及格线啦。</p><p>人一出来，这一天才算真正往前走了一点。</p><p>新泽西整个州给我的感受就是：没想到纽约市这么令我诟病的公共交通系统，在美国里已经算是佼佼者了。</p><p>新泽西的公共交通系统可以说是莫名其妙，各个地方都毫无逻辑，App 界面甚至丑陋到让我抓狂。这个 App 也是蠢得要死，室友只是稍微将其退回了后台，它就把室友的账户登出了。我们上车后室友还需要手动在司机面前登录账号，白白浪费时间。</p><p>抛开软件不谈，公交车本身的问题也不少：车速极快，几乎没停稳就开门；人一上车立刻关门继续狂奔；没有 Tap 系统，必须提前买实体票，或者在 App 里处理好一切。</p><p>从纽约坐车去新泽西，通常要经过大巴终端。路线、购票、对应的 gate 都需要自己提前确认，不然现场很容易手忙脚乱。第一次用 NJ Transit 的话，更是很容易被它的设计绕晕。</p><p><img src="/posts/18b0/bus-1765348969900-3.webp" alt="" loading="lazy"></p><p>回程时发现公交还要等一会儿，我们就先去了附近的麦当劳，买了个鸡块套餐。天已经完全黑了，店里却依旧人不少。</p><p>这家麦当劳的饮料是无限续杯，反而让我有点意外。可能只有纽约市这样的大城市，才会把这种事情一步步取消掉吧。刚来纽约的时候，我还记得有些区的麦当劳也是可以续杯的，后来一个个都消失了。</p><p>这个小镇的路很宽，车很多，但行人却很少。就连红绿灯也需要手动按键才会变灯。车站很老旧，大多只有一块不起眼的小牌子，晚上几乎看不见。我们在附近绕了好一会儿，才终于确认自己没有走错。</p><p>或许正是这些细碎又不太方便的地方，才让我真正意识到：我确实已经离开纽约市了吧。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我的坏习惯是记录下来的事情不会第一时间加工成文章发布。这件事是 5 号发生的，我于 19 号开始起草、29 号才发布……&lt;/p&gt;</summary>
    
    
    
    <category term="日常生活" scheme="https://blog.cytrogen.icu/categories/%E6%97%A5%E5%B8%B8%E7%94%9F%E6%B4%BB/"/>
    
    
  </entry>
  
  <entry>
    <title>观《疯狂动物城 2》</title>
    <link href="https://blog.cytrogen.icu/posts/7240.html"/>
    <id>https://blog.cytrogen.icu/posts/7240.html</id>
    <published>2025-12-27T19:59:48.000Z</published>
    <updated>2026-02-09T17:16:55.549Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>上个月一直想看的《疯狂动物城 2》，最近终于有时间去和室友一起看了。和 <a href="/posts/5097.html">上次</a> 一样，我去的还是周二三场。毕竟才 10 块钱。</p><span id="more"></span><div class="danger warning"><p>不想要被剧透的还是不要看了吧 —— 虽然话是这么说的，但如果你都不想被剧透了，还点进来做什么呢？</p></div><p>去家附近的影院之前，我和室友在美式中餐馆里快速吃了炒面和炒粉，期间还玩了 Neal 的 <a href="https://neal.fun/absurd-trolley-problems/"><em>Absurd Trolley Problems</em></a>（荒诞电车难题）游戏。她认为，在不认识任何人的情况下，一切都应当遵守「少数服从多数」的规矩，而人优先于任何非人或者非生命，并且交易是不可取的。如果绑在铁轨上的人是我的话，她会选择让其他人死。</p><p>因为对「少数服从多数」规矩的严格遵守，就算是第 9 关里那五个人是「自杀者」，她也会选择救下他们、杀死那一个不想死的人。</p><p>这次去的影院要比上次去的明显大不少。我们没有买爆米花和饮料，直接入了场。令人大跌眼镜的是，买的位置被别人坐去了。</p><p>本来想着去其他位置坐也行，避免冲突。但后来一想，首先我买的位置是整个影院里最好的位置，其次要是坐到了其他人买的位置怎么办？最后室友替我去沟通，让这群小孩回到了他们该在的位置。</p><p>因为晚来了十分钟，不需要看那又臭又长的广告，可以直接观看其他电影的预告片。我发现根据看的电影类型，播放的预告片类型也不同，这次没有任何恐怖电影的预告片，都是合家欢或者以动物为主角的电影。</p><p>我特别喜欢看这类「给儿童看的电影」，未来或许会去看《山羊巅峰》和主角特别可爱的《河狸变身计划》。</p><h2 id="电影中"><a class="markdownIt-Anchor" href="#电影中"></a> 电影中</h2><p>先说结论，我认为这部电影一路看下来没有什么很大的毛病。</p><p>里面穿插了许多让人会心一笑的桥段，例如对《料理鼠王》的致敬，甚至还有后期对《闪灵》的致敬 —— 你这个合家欢电影致敬它真的没问题吗！</p><p>动物们的模型依旧很可爱，尤其是狼：大鼻子、长长的嘴筒子，很多时候还会瞪个大眼睛，实在是太可爱了。片中有两个山羊警官，一直戴着个墨镜，特别骚气。</p><p>这次电影里也展示了第一部没有出现的动物，比方说在水里生活的动物，补充了「鱼类」在这个世界观里的定位 —— 拿去吃。</p><p>这种设定我会更喜欢《动物狂想曲》的，鱼类也是生命，但是他们的观念是「吃」这一行为不过是大自然的一部分。你吃了我，你也会被其他更大的生物吃，而更大的生物一旦死去，便是滋润了无数小生物的「鲸落」。</p><p>电影开头的「毛毛心理咨询」实在是太 America 了。我身边的人几乎都做过心理咨询，不过我自己没做过，我光是听他们描述的我就不想去。</p><p>通常来说，电影的剧情架构是这样的：</p><ol><li>引入冲突</li><li>引入主线和新伙伴</li><li>线性推进主线</li><li>被背叛</li><li>解决主线问题</li><li>解决最初引入的冲突</li></ol><p>第一部里，冲突是「社会对动物们所添加的标签」，旨在告诉观众「谁都可以成为任何人」。刻画该冲突的方式便是刻画朱迪作为一个警官有被多么忽视，以及尼克作为一只狐狸被包括朱迪在内的人投射刻板印象。其实说是冲突，更像是整个《疯狂动物城》系列的主题，只是第一部里着重刻画了它。</p><p>第二部的主题更复杂，原有主题依然存在，不过朱迪和尼克的关系也成为了一种冲突。</p><p>朱迪作为理想主义者，她可以为了自己的理想做任何事，为了刻画这一点，朱迪的行为变得更加鲁莽。尼克很关心朱迪，成为警官也是为了和朱迪在一起，但是他无法表达出这一点，可能是好面子。</p><p>我个人认为，他们中期吵架的那一部分做的不够好。</p><p>朱迪为了追盖瑞、毫不犹豫地跳入了水管内，差点窒息而亡，最后是尼克救了她。朱迪很不开心，认为这错失了追盖瑞的机会；尼克也很不开心，他只是想要朱迪好好的，为此他愿意和朱迪一起放弃身份、逃离动物城，在哪个角落里安安稳稳过日子。</p><p>问题在于，冲突应当是两个角色都做错了事情，才能在最后通过道歉达成和解。</p><p>我们可以具体拆一下：</p><p>朱迪的问题是：</p><ul><li>行为鲁莽、不顾生命危险</li><li>被救后反而指责尼克</li><li>爬山时录音笔摔坏，选择回避情绪冲突</li><li>在旅店里只想取证据，不关心尼克的恐慌</li></ul><p>尼克的问题则相对单一：</p><ul><li>想要和朱迪在一起</li><li>不希望朱迪受伤</li><li>但始终没有表达自己的真实感受</li></ul><p>这样一看，冲突明显不平衡。</p><p>然而在结尾，率先道歉的是尼克。</p><p>我很喜欢第一部的一幕是朱迪从老家回来找尼克，并且真诚地向尼克道歉。我原本期待，第二部里可以是朱迪更清除地意识到自己的问题，并主动迈出那一步。</p><p>用我在网络上看到的一句话是：</p><blockquote><p>朱迪没有成长，尼克只是看开了。</p></blockquote><p>当然，说是没有成长就有点夸大了。</p><p>然后便是续作几乎一定会出现的新主线和新伙伴。</p><p>第二部的主线是帮助盖瑞找回自己的家园，并且击溃林雪猁家族的阴谋。说实话，在美国看林雪猁家族的阴谋，实在是让人如坐针毡。这也太像美国人赶走印第安人和墨西哥人的历史了吧！理由也很简单，因为他们是领地动物，所以他们想要赶走其他动物，扩张自己的领地。</p><p>好吧，现实中那么多可悲的历史，理由说不定也是这么简单。</p><p>中间的线性推进主线我就不说了，基本上就是展示世界观。直接来看「背叛」。</p><p>第一部里朱迪被羊副市长背叛，颠覆了「食草动物是弱势」的刻板印象。观众和朱迪一样，被迫意识到「加害者与被害者」的区分并不来自物种，而来自权力、位置与选择。</p><p>食肉动物很强很可怕吗？但是他们在社会里很难做到一些事情。朱迪作为「弱势群体」警校毕业就能受到羊副市长的支持、来动物城工作，但是作为「强势群体」的尼克呢？他从来都没有选择。</p><p>第二部里，朱迪则被宝伯特背叛，此时的主题依然是「变成刻板印象里不一样的样子」，宝伯特的回应是「但我不想要和家人不一样」。</p><p>这个背叛和第一部的背叛有着本质上的差异：它没有颠覆任何主题层面的既有认知，它只是角色立场的转向。我们知道了宝伯特为什么会这么做，但是没有迫使我们重新思考「我们原先相信的是否是错的」。这也使得这一段情节在情感和思想上的冲击力，明显弱于第一部。</p><p>我自己很不喜欢第二部里如何解决这些冲突的方式。</p><p>在朱迪和尼克解开心结后，整个故事突然开始以过山车般的方式一路冲向地底：先前作为傀儡的马飞扬突然决定不再听从林雪猁家族；宝伯特越来越疯狂，却又被轻易击败；盖瑞找到了专利证明，林雪猁家族锒铛入狱。</p><p>一切结束得太快了。</p><p>电影的结尾出现了羽毛的彩蛋，貌似第三部会出现鸟类动物。</p><p>结束后，室友跟我说的第一句话是，「感觉怪怪的，没有第一部那么惊艳。」</p><p>我认为电影续作确实很难达到首作的高度。因为首作是围绕着主题所展开的，而续作要操心更多事情：让旧角色登场、维持系列主题、引入新故事、制造新冲突……</p><p>我认为创作里，第一条是最不重要的。但电影依然做了这一点，让许多角色回归，虽然观感很差，但也照顾到了这些角色的粉丝们。</p><h2 id="电影后"><a class="markdownIt-Anchor" href="#电影后"></a> 电影后</h2><p>我和室友看了许多解析视频，来了解我们心中的不快。</p><p>其中我认为做的最好的是这个视频：<a href="https://www.bilibili.com/video/BV1STSyBFE8u">为何尼克绝不该只为爱情而生？为何马市长是 2 最大遗憾？深度解析疯狂动物城系列！</a> 视频里很棒地解释了为什么第一部那么出彩：它讨论的并不只是「有没有歧视」，而是 <strong>谁被定义为弱势，以及这种定义是如何运作的</strong> —— 食草动物与食肉动物、看得见的冲突与看不见的身份红利。</p><p>第一部真正厉害的地方，并不只是展示了朱迪作为「食草动物」视角下的动物城歧视，还同时给出了尼克作为「食肉动物」所承受的另一套歧视逻辑。这两种视角并不是简单的对立，而是相互错位的：朱迪从小被当作弱势的一方被忽视、被低估，于是她理所当然地认为「食草动物就是弱势群体」；而尼克看起来体格更大、更具威胁性，却在制度和信任层面被系统性地排除在外。</p><p>这也使得朱迪这个角色变得更加复杂。她确实遭遇过歧视，但她同样明显拥有身份红利：她是食草动物、是警察、是体制内的「成功案例」。而她对这种红利几乎是完全无意识的 —— 直到那场发布会的发言伤害了尼克，她才第一次意识到，自己口中「理所当然的判断」，在尼克那里意味着什么。</p><p>第一部里那些体格庞大的食肉动物，正是在这里显露出他们的脆弱：在权力结构面前，体型、力量、凶猛都毫无意义，他们只是另一种层面下的弱势群体。也正是因为这种多层次、交错的弱势描写，第一部的主题才显得如此扎实。</p><p>相比之下，第二部虽然引入了爬行动物作为新的伙伴，却给到他们的篇幅实在太少，少到我在回想剧情时，甚至会暂时忘记他们的存在。这一点让我觉得有些可惜。</p><p>Claire 也在视频中提到了一些她认为遗憾的地方：很多原本可以继续深挖的议题，最后都只是轻轻擦过，没有再往前走一步。</p><p>最后便是关于朱迪和尼克之间的关系。</p><p>我认为他们有着亲密关系，但这不一定是爱情，因为亲密关系本身就不等同于爱情。</p><p>这个命题也是我现实生活中一直在探讨的：我可以有一个生命中最亲密最重要的人，但我们之间没有爱情，我们有的只是陪伴和理解彼此。</p><p>我渴望拥有这样的关系，但是这很难。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;上个月一直想看的《疯狂动物城 2》，最近终于有时间去和室友一起看了。和 &lt;a href=&quot;/posts/5097.html&quot;&gt;上次&lt;/a&gt; 一样，我去的还是周二三场。毕竟才 10 块钱。&lt;/p&gt;</summary>
    
    
    
    <category term="影评" scheme="https://blog.cytrogen.icu/categories/%E5%BD%B1%E8%AF%84/"/>
    
    
  </entry>
  
  <entry>
    <title>当 True 并不是 True</title>
    <link href="https://blog.cytrogen.icu/posts/6e69.html"/>
    <id>https://blog.cytrogen.icu/posts/6e69.html</id>
    <published>2025-12-25T15:32:25.000Z</published>
    <updated>2026-02-09T17:16:55.213Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>某天我阅读了 <a href="https://suggger.substack.com/p/the-architecture-of-not-bad-decoding">《Not Bad 的架构：解码虚空的中文源代码》</a>，原本想要放入月刊内，结果发现自己写的越来越多，已经到了「不独立发个文章都对不起自己」的地步。</p><span id="more"></span><h2 id="文章的大致内容"><a class="markdownIt-Anchor" href="#文章的大致内容"></a> 文章的大致内容</h2><p>在深入讨论之前，为了照顾没有阅读过作者 Suggger 原文的读者，我先快速梳理一下他的核心观点。</p><p>Suggger 的思考始于一个细微的翻译卡顿：他发现中文在表达「肯定」时，往往不喜欢直接说 <code>True</code>（是），而是更倾向于双重否定的 <code>!False</code>（非假）。</p><p>这是他举出的例子：</p><ul><li>没错 = Not wrong = Right</li><li>不差 = Not bad = Decent</li><li>还行 = Still passable = Okay</li><li>没事 = No problem = Fine</li></ul><p>Suggger 将这种现象总结为「无」的语言哲学。</p><p>他认为，相较于英文那种直接、明确、必须承担立场的 <u>分类思维</u>，中文的这种负向肯定构建了一种 <u>灰度思维</u>：它旨在避免直接承担责任，保留解释空间，并让态度始终保持模糊与可撤回性。</p><p>简而言之，他认为英语是在给世界打标签，而中文是在测算风险与留白。</p><h2 id="我的看法"><a class="markdownIt-Anchor" href="#我的看法"></a> 我的看法</h2><p>我看完这个文章后第一时间想到的是日语。</p><p>如果非要试图通过语言结构来窥探思维方式，我认为日语才是那个最极致的样本，因为他们的多重否认在这个世界上是相当独特的。</p><p>让我们先看几个例子。假设我们要表达「义务」的话，这三个语言是这么表达的：</p><ul><li>中文：必须</li><li>英文：Must / Have to</li><li>日语：しなければならない —— 直译就是「如果不做的话，不行」。</li></ul><p>很明显，日语用的是一个 <u>结构性的双重否定</u>，用来表达最强烈的「肯定」含义。</p><p>甚至在表达「只有」的时候：</p><ul><li>中文：我只有一个苹果</li><li>英文：I have only one apple</li><li>日语：りんごは​<ruby>一<rt>ひと</rt></ruby>つしかない —— 除了一个苹果之外，<em>没有</em> 别的了</li></ul><p>在日常社交中，这种倾向更明显。比如邀请：</p><ul><li>中文：你想去吗？</li><li>英文：Do you want to go?</li><li>日语：​<ruby>行<rt>い</rt></ruby>きませんか？ —— 你 <em>不</em> 去吗？</li></ul><p>或者是拒绝：日本人想要拒绝时，他们几乎不会说「不」的，他们会说「それはちょっと……」或者简单点「ちょっと……」。直译是「那个有点……」。句尾甚至直接省略了否定词，只留下一个悬而未决的语气。</p><div class="danger alert-info"><p>当然，我这里话没有说那么死。这是因为虽然日语表达「必须」的核心语法结构确实是双重否定，但现代日语（尤其是口语）确实发生了变化，而且存在其他的表达方式。</p><p>哪怕是现在最懒、最年轻的日本人，在口语里表达「必须」时，通常会说：</p><ul><li>しなきゃ</li><li>しないと</li><li>しなくちゃ</li></ul><p>但是！即使是这些缩略语，它们的词源依然是双重否定，即「不这么做的话不行」：</p><ul><li>しなきゃ = しなければならない</li><li>しないと = しないといけない</li></ul><p>那么是否存在肯定形式呢？自然是有的，只是语感不太一样：</p><ul><li>するべき = 应该做（更多带有一种道德判断或强烈建议，而不是客观的「必须」）</li><li>​<ruby>必要<rt>ひつよう</rt></ruby>がある = 有做某事的必要（名词性的陈述）</li></ul></div><p>那么，我列举了这么多日语的例子，是为了证明「语言结构决定思维」吗？</p><p><u>弱萨丕尔・沃尔夫假说</u> 认为，语言结构强关联思维方式。这在学术上是有意义的，比如语言会影响我们对颜色的感知或对方位的描述。</p><p>但 Suggger 的错误在于，<strong>他将这种「影响」无限放大成了「决定」</strong>。他试图证明：因为你的语言里全是「否定」，所以你的骨子里就是「逃避」。如果这种理论成立，即语言结构决定逃避责任，那日本人应该是世界上最爱「推卸责任」的民族？这显然过于简化了。日本社会以极度严苛的责任感和耻感文化著称。这里的「否定结构」并不是为了逃避责任，而是一种社会性的<span class="emphasis">谦逊</span>。</p><p>日本文化中有一个核心概念叫​<ruby>配虑<rt>はいりょ</rt></ruby>，即时时刻刻照顾对方的感受。直接的断言在日本社会往往被视为一种攻击或对他人的冒犯。因此，他们使用否定句式，不是为了像 Suggger 说的那样给自己留后路，而是为了降低自我的姿态，给对方留出面子和余地。</p><p>这就引出了那个鸡生蛋的问题：是语言的源代码决定了思维，还是文化的运行逻辑重塑了语言？ 现实更可能是后者：<strong>文化的运行逻辑重塑了语言</strong>。日本的高语境、耻感文化需要一种不那么尖锐的语言工具来维持社会润滑，因此「多重否定」才演变成了一种语法规则。</p><p>理清了「文化重塑语言」，我们再来看中文，就会发现 Suggger 所谓的「中文否定肯定」和日语的「语法否定」本质完全不同。</p><p>日语的多重否定往往是语法层面的<span class="emphasis">刚需</span>。在表达「必须」、「只有」等基础概念时，日本人的选择并不多，语法结构几乎是强制他们调用「不…… 不行」或「不…… 没有」的模块。</p><p>但 <strong>中文的「否定肯定」是词汇层面的选择</strong>。当我们说「没错」或「还行」时，更多是出于一种松弛的口语习惯或社交修辞。我们完全拥有选择权，随时可以说「对的对的」、「正确的」、「确实」。我们的操作系统并没有禁止我们输出 <code>True</code>，只是我们在特定语境下选择了更温和的表达。</p><p>这里就必须提到 <u>语用学</u>。简单来说，语用学研究的是「在特定情境下这话是什么意思」。如果一个人在屋里说「这有点冷」，他的句法是在陈述温度事实，但他的语用意图通常是「请把窗户关上」。如果按照 Suggger 的逻辑，这个人就是在「逃避直接下达关窗指令的责任」？不，这只是人类社会通用的社交礼仪。</p><p>同样的道理，如果不考虑文化语境，单纯看语法，我们再回头看看 Suggger 眼中那个「直球、裸露、高效」的英语世界。他认为英文的肯定是分类、非黑即白的。这个观点忽略了英语中非常重要的修辞手法 ——Litotes（反语 / 低调陈述）。</p><p>英语也不是永远都在直球地进行属性赋值。它同样在大量使用「负向肯定」：</p><ul><li>I wouldn't say no = Yes, please</li><li>I don't disagree = I agree</li><li>It was no small feat = It was a huge achievement</li><li>Can't complain = Everything is good</li></ul><p>再用「不错」这个例子来说，Suggger 认为这是「避免承诺完美」。但在英语母语者的语境里（特别是英国人），当他们看着一份很棒的报告说 <em>Not bad at all</em> 时，这也往往是极高的赞赏，等同于 <em>Very good</em>。</p><p>这里的逻辑并不是「我在逃避给它打满分的责任」，而是「我通过压低预期的表达，来显得更客观或更谦虚」。</p><p>因为过度的赞美往往听起来像廉价的恭维，而克制的 <em>Not bad</em> 则暗示了说话者拥有极高的标准 —— 这意味着你的作品经受住了挑剔眼光的审视。这种「否定之否定」剔除了情绪化的泡沫，反而让赞美显得更加诚恳且更有分量。</p><p>更有趣的是，他声称英语强迫人们「公开立场」，但这恰恰忽略了英语语法中的 <u>主体消除</u>。当一个美国政客想要逃避责任时，他不需要像中国人那样用「原则上」这种模糊词，他只需要使用被动语态：<em>Mistakes were made</em>（错误已被铸成）。注意到了吗？在这个句子里，「错误」发生了，但「犯错的人」在语法层面上被直接删除了。这难道不是英语的「虚空」吗？</p><p>所以，如果因为中文里有「不错」，就认为中国人缺乏担当，那我也可以因为英文里有 <em>I wouldn't say no</em>，而论证讲英语的人都是一群首鼠两端之徒。这显然是荒谬的。</p><p>这种语言宿命论在流行文化中很受欢迎，因为它提供了一种廉价的深刻 —— 似乎只要破解了语法，就能看透一个民族的灵魂。Suggger 在文章中使用了编程逻辑：中文是 <code>!False</code>，英文是 <code>True</code>。这种极客式的比喻很容易让人产生「洞察了本质」的错觉。但看看上面那些日本人和英国人的例子，语言真的是冰冷的二进制代码吗？显然不是，语言是流动的博弈。</p><p>因此，无论是日语中不得不用的语法规则，还是中文里为了社交润滑的修辞选择，如果仅仅因为它们都带有「否定」成分，就将其统一解读为「避险心机」，会忽略语言演变的历史脉络，以及使用者在具体语境中的能动性。</p><p>这类理论之所以迷人，我认为这是因为它提供了一个简单化的诱惑：分析几个单词语法来解码整个庞大文明的底层逻辑。但是像我先前说的那样，<strong>语言不是冰冷的代码，是人类为了在复杂社会中生存而打磨出的工具</strong>。真正的洞察不应该止步于语法的表象，而应该去接触那些隐藏在单词背后、更为深沉的文化脉搏。</p><p>说到底，<strong>复杂的文化心理怎么可能塞得进去那小小的二进制框架呢？</strong></p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;某天我阅读了 &lt;a href=&quot;https://suggger.substack.com/p/the-architecture-of-not-bad-decoding&quot;&gt;《Not Bad 的架构：解码虚空的中文源代码》&lt;/a&gt;，原本想要放入月刊内，结果发现自己写的越来越多，已经到了「不独立发个文章都对不起自己」的地步。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="语言学" scheme="https://blog.cytrogen.icu/tags/%E8%AF%AD%E8%A8%80%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>观《玩具熊的五夜后宫 2》</title>
    <link href="https://blog.cytrogen.icu/posts/5097.html"/>
    <id>https://blog.cytrogen.icu/posts/5097.html</id>
    <published>2025-12-23T17:02:31.000Z</published>
    <updated>2026-02-09T17:16:55.549Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>前段时间和朋友一起去看《玩具熊的五夜后宫 2》电影（以下简称 FNAF2 电影）。本来打算自己一个人去的，看她在家里无所事事的，干脆抓过来和我一起观赏电影。</p><span id="more"></span><div class="danger warning"><p>不想要被剧透的还是不要看了吧 —— 虽然话是这么说的，但如果你都不想被剧透了，还点进来做什么呢？</p></div><p>我们去的我校附近的一家 AMC 影院。AMC 好便宜啊，周二周三电影票都半价，有些早上的时间段还额外打个八折或者七五折。不看 IMAX 或者 Dolby 的话，一个人才 10 块钱。</p><p>去年还是前年的时候，AMC 忽然送了我一年 Premium 会员。不知道是什么意思，怀疑是生意不好做，我也查不到我这个会员的有效截止期是什么时候。总之除了攒积分快点，我还可以买中号爆米花跟饮料，然后免费升级到大号（虽然两者的区别只有 1 块钱……）。</p><p>朋友买了爆米花和饮料，总计 18 块钱。可以免费续，不过没有那个必要，实在是吃不动那么多，一场电影下来爆米花还剩差不多三分之一。饮料倒是喝得很快。她调了个桃子柠檬味雪碧，也就是一点点桃子味雪碧，剩下全部接普通雪碧。味道意外地不错。</p><p>我们提前半小时入场，也看了半小时的广告。该说不说，这些广告很「优质」，至少成功地让我出于好奇、扫了一个二维码。不过让我想到了前段时间接收到的一个观点：很多时候花了钱更容易看到这些「优质」的广告。</p><p>半小时过后，大荧幕终于开始播放其他电影的预告片 —— 基本上都是那种经典得不得了的外国恐怖 / 血腥片，光是看了预告片就知道实质内容会是什么。</p><h2 id="电影中"><a class="markdownIt-Anchor" href="#电影中"></a> 电影中</h2><p>说回 FNAF2 电影本身，我看完后第一感想是「这是喜剧片吗？」</p><p>首先它作为一部恐怖片严重失格，<strong>所谓的「恐怖」都是靠堆跳杀来实现</strong>。堆的实在是太多了，还很刻意，根本不会让人觉得害怕，只会觉得无趣、重复。</p><p>那它作为粉丝向的作品合格吗？</p><p>我确实很喜欢电影里面的彩蛋，例如 Mike 吐槽 2 代披萨店的保安室居然没有门。还有开头展示 2 代披萨店时，展示到街机区的时候貌似看到了 Candy 猫的小彩蛋，不知道是不是看错了？不过呢有些地方我觉得可以做得更好，比如老 Foxy 居然不是被闪走的。</p><p>Vanessa 和 Mike 前期的约会剧情我挺喜欢的，以及 Vanessa 的梦境剧情。</p><p>为了体现出 Vanessa 渴望脱离 William 带给自己的阴影，我认为制作组在这方面上很是用心：成人的 Vanessa 看着走廊尽头的 William，勉强地大喊「我不再怕你了」。William 冲来时她又逃到出口恐慌地拍门、想要离开。下一幕 Vanessa 变成了小孩的样子，逃窜到父亲的工作室。在那里，她找到了 Baby，可能是想要补充游戏世界里 Elizabeth 的设定？总之，电影里的 Vanessa 变成了保安的样子后枪杀了 William，但是倒在地上的 William 依然喊着「你永远都会是我的」。</p><p>我认为这一幕很棒地表现出了 William 在 Vanessa 的眼里是多么可怕的存在，就算死了也会一直作为阴影存在。</p><p>说完了优点，来说缺点。电影里那种经典的「不好好说话」剧情到处都是，以至于我都不乐意一个个挑出来说 —— 太多了！自然，影视作品一定要有这样的桥段来营造冲突，但我认为可以有更聪明的方式，<strong>至少不要每个冲突点都让我觉得过分刻意吧</strong>！</p><p>电影世界在剧情设定上，对游戏原著的魔改程度大得惊人，甚至到了令人困惑的地步。</p><div class="danger alert-info"><p>事先说明一下游戏里的主要角色：</p><ul><li><p>William 是主要的反派，他创造了玩偶，并且杀害了多个小孩，也包括自己的女儿 Elizabeth。</p><ul><li><p>Michael 是 William 的大儿子，也是 FNAF 系列的主角，许多作品里玩家所扮演的就是他。</p><p>他想要弥补父亲造成的一切、找回妹妹。不过在《姐妹地点》里，他被混合意识体 Ennard 欺骗、挖空了身体、当做 Ennard 出门伪装用的皮囊。最后因为身体腐烂，Ennard 不得不放弃他，而他居然也没有死，实在是打不死的小强啊。</p></li><li><p>Elizabeth 被 William 所做的 Baby 玩偶意外杀死。</p></li><li><p>William 还有个小儿子，不过他的名字从来都没有被提起过，只知道他是 83 之咬的受害者。</p></li></ul></li><li><p>Henry 是 William 的商业伙伴。</p><ul><li>Charlotte 是 Henry 的女儿，也是 William 的第一名受害者。死后附身了 Marionette（Puppet，也叫傀儡）。</li></ul></li><li><p>Vanessa 就比较特殊了。她是到《安全漏洞》才出现的新角色，这时候 FNAF 游戏已经不再是过去那样的「保安电竞游戏」。正因如此，我对她并不熟悉。</p></li></ul></div><p>我因为第 1 部电影而分不清 Vanessa 和 Elizabeth。电影世界里，William 的女儿从 Elizabeth 变成了 Vanessa。主角是 Mike，他的弟弟曾经被 William 拐走杀害，因此留下阴影。</p><p>我在 FNAF 小说推出后就没有再怎么关注这个系列了。Vanessa 到底是谁？是 Elizabeth？但是 Elizabeth 不是已经被 Baby 杀了吗？</p><p>直到我出了影院搜了一下，才得知游戏世界里的 Vanessa 和 Elizabeth 一点关系都没有。电影世界里其实是将 Michael 的角色位置给了 Vanessa，因为要给 Mike 凑 CP 吗？然后 Elizabeth 的位置给了 Michael，也就是想要和 William 一样杀人的位置。Elizabeth 在电影里查无此人。太乱了。</p><p>Michael 因为站在游戏世界里 Elizabeth 的角色位置，所以在电影世界里他认同了 William、变成了反派，刻意释放出 Charlotte 要大杀四方。</p><p>这里我忘了为什么 Michael 可以操控 2 代玩偶，不应该是 Charlotte 操控它们吗？我也没有看到 Michael 和 Charlotte 合谋的场面，只有开头 Michael 放出 Charlotte 的场合，但那个时候 Michael 还很怕 Charlotte 会弄死自己。</p><p>Charlotte 虽然为了救小男孩而被 William 杀死，但是她并不觉得这是 William 的问题，有错的是当时不愿意帮助她的大人。此处的逻辑我认为是为了让角色变成反派而设计的，就像为什么 1 代玩偶会想要弄死 Abby 一样。说实话很刻意，我不喜欢。</p><p>这个片快结尾的时候实在是欢乐得不行：谁想出来的 1 代玩偶痛扁 2 代玩偶的情节的？差点以为回到了十年前看 YouTube 上那些不同版本的玩偶大战、比战力的时候。尤其是制作组很刻意地将这一段设计的非常滑稽 ——Toy Bonnie 的脸被一脚踩烂，眼珠子可笑地漏了出来。我当时看的时候一直在憋笑……</p><p>看到 Mike 拿出音乐盒驱散了 Charlotte 时，我觉得应该就这么结束了吧，谁曾想 Mike 直接把音乐盒停了，然后和 Vanessa 大吵一架。这一段吵架戏感觉莫名其妙的，像是为了吵架而吵架一样。Vanessa 绝望的时候，Charlotte 突然出现并俯身了她，全片完……</p><p>只是觉得颇为儿戏，这样的设计。</p><p>当时灯光亮起，很意外地播放了 <em>It's Been Too Long</em> 这首歌。身后的人起来要走，抱怨了一句「明明电影拍到这儿就行了」。</p><p>电影刚开始的时候，提到结尾有彩蛋，因此我和朋友等到了整部电影结束。结尾的彩蛋有两个：William，或者说 SpringTrap 苏醒了过来，暗示着第 3 部电影；Henry 给 Mike 发了个语音提醒？具体说了什么其实我都不记得了，类似于那种「你要小心一个人」，然后在报名之前就被不明生物杀害。</p><p>我自己是觉得，这些桥段实在是太经典了。估计第三部电影里，Vanessa 会被其他人嘴炮醒来、和 Charlotte 斗争…… 不过我也不清楚，因为 Mike 明显有救世主情节，想要去「修复」Vanessa，这样的态度让 Vanessa 以及我都感到很生气，所以我大胆猜测一下，也有可能 Vanessa 会治愈自己？总之，我想要看一些不是那么典型的桥段。</p><h2 id="电影后"><a class="markdownIt-Anchor" href="#电影后"></a> 电影后</h2><p>我和朋友商量着去附近新开的蜜雪冰城。过去一看果不其然，排满了长队。没有办法，价格实在是太便宜了，熊猫外卖上的预售套餐有两个饮品，居然只要 4 美元左右。就算加上平台费、运送费和小费，价格也比附近的奶茶品牌便宜很多很多。</p><p>没办法，我们只能到处走走、吐槽这部电影。她觉得电影剧情实在是招人笑，许多情节她后来想想也会觉得可笑。</p><p>我也在手机上看到一些人对这部电影的看法：因为这是 FNAF 的电影，所以他们觉得就是好、不该骂。我认为这没必要。</p><p>作为 FNAF 系列（曾经的）粉丝，能看到玩偶们以真实的形态动起来很是惊喜，看到各个彩蛋的时候也很高兴。但是这部电影的剧情对我而言就是很不咋地，评价不可能只有黑或者只有白。再就是 <strong>喜欢这个系列，所以希望作品优秀不是很正常的事情吗？怎么能因为它是某某系列的作品，就无视了所有的缺点呢？</strong></p><p>不过过了几天我再看这部电影的消息：居然在票房上打败了我还没看的《疯狂动物城 2》。朋友知道后气急败坏地说：「都怪你拉我来看这个，我们居然为这个片的票房贡献了宝贵的两票！」我听后实在是哭笑不得。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;前段时间和朋友一起去看《玩具熊的五夜后宫 2》电影（以下简称 FNAF2 电影）。本来打算自己一个人去的，看她在家里无所事事的，干脆抓过来和我一起观赏电影。&lt;/p&gt;</summary>
    
    
    
    <category term="影评" scheme="https://blog.cytrogen.icu/categories/%E5%BD%B1%E8%AF%84/"/>
    
    
  </entry>
  
  <entry>
    <title>尝试去中心化和去 App 化</title>
    <link href="https://blog.cytrogen.icu/posts/9572.html"/>
    <id>https://blog.cytrogen.icu/posts/9572.html</id>
    <published>2025-12-23T02:18:18.000Z</published>
    <updated>2026-02-09T17:16:55.213Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>如标题，我想要尝试慢慢地去中心化、去 App 化。</p><span id="more"></span><h2 id="去中心化"><a class="markdownIt-Anchor" href="#去中心化"></a> 去中心化</h2><p>我尝试了一下使用 PixelFed 和 Mastodon 来代替 Instagram 和推特（我依然拒绝叫它 X）。</p><p>PixelFed 给我整体的感觉是还未完善，可以发现整体设计有许多瑕疵。比如我最开始将自己的账户设置为私密账户，发的一些猫咪照片自然也是私密的，但是后续将账户放开、照片却无法再公开。</p><p>Mastodon 我在上个学期其实就有用过。</p><p>我校的日语部门和日本的信州大学有合作关系，有一些课需要让我们互相投递影像、彼此学习对方的语言。我不知道具体是哪一方搭建的服务器，但就是有人专门为此搭建了一个 Mastodon 服务器：学生创建自己的账户、在服务器内上传自己的视频，另一个学校的学生看到后就可以回复了。</p><p>你可以用这些链接关注我：</p><pre><code class="language-plaintext">https://pxlmo.com/Cytrogen</code></pre><div class="danger warning"><p>值得注意的是，我加入的这个 PixelFed 服务器因为不明原因将我的账户 unlisted 了，也就是不开放。我发布的许多照片目前看不到，但是月刊内嵌入的可以看到。</p><p>暂且不知道什么时候会开放。</p></div><pre><code class="language-plaintext">https://m.otter.homes/@Cytrogen</code></pre><p>我最近看到许多博客站主使用 Telegram 发布短想法，然后抓取这些内容、生成一个索引网页供大家访问。其实 PixelFed 和 Mastodon 也可以做到这一点，甚至说更方便些。比方说 PixelFed 就可以直接生成一个自己账户的 feed 页面。</p><p>既然这些去中心化平台本就支持开放的 Feed 协议，<strong>与其让内容分散在各个站点，不如将它们收纳回自己的「主阵地」</strong>。于是我打算在这个博客网站里嵌入一个自己的照片和短想法合集。</p><p>我也考虑过重复性。现在的日记片段其实就有一点短想法合集的感觉。或许我可以全面迁移到 Mastodon，这也可以解决我先前提到的「外出时无法在博客里写日记」（见 <a href="/posts/31df.html#%E6%97%A5%E8%AE%B0%E7%89%87%E6%AE%B5">十一月二十九日</a>）的问题：日记不需要再写在 Google Keep 内，直接在 Mastodon 里写好，然后要部署新的月刊时直接在构建时拉取这个月的 Mastodon 内容、自动添加到页面内。</p><p>我还在考虑在 PixelFed 和 Mastodon 上发什么类型的内容最好：</p><ul><li><p>PixelFed 是专门发送图片的，如果我想要在博客网页上使用这个图片，是不是应该嵌入这个图片进来呢？因为我不想要在互联网上重复上传同一个图片。</p></li><li><p>Mastodon 和博客网站上的「日记片段」是否会有冲突？现在的「日记片段」有些是短想法，有些是日常分享，我认为可以分成两类。那么在 Mastodon 上应该写短想法还是日常分享？</p><p>这样一想又觉得，自己好像花在日常分享上的精力更多，那是不是自己的博客也可以分享日常？这样月刊的内容就不需要这么多这么长？</p></li></ul><p>最后我的方案是，略微改动一下月刊内的「日记片段」板块。我决定尝试一个全新的写日记方式：</p><ol><li><p>如果是很长的日记，例如一天的流水账、一些很长的想法，我会直接当做独立文章发布。</p><p>如果只是想着去写高质量的博客，月刊的「日记片段」会被我的分享欲压垮的。直接当做文章发布，然后让月刊做链接的工作就好。这样我的标准也会降低许多，写博客也不需要考虑什么质不质量、高不高大上了……<em> 明明是我的博客！</em></p></li><li><p>如果是短想法，我会发到 Mastodon 上，博客会自动抓取和嵌入这些嘟文。</p><p>这是因为 Mastodon 与「日记片段」的定位有些冲突。我认为既然博客是合集，Mastodon 就可以只做素材库。基于此，我会将嘟文嵌入到 <code>details</code> 块内，并以发布的时间排序，因此它们的前面一定会有时间。</p></li><li><p>如果是照片，我会发到 PixelFed 上。和 Mastodon 同样，博客也会自动嵌入这些照片、时间和 <code>figcaption</code>。</p><p>因为我不想要在互联网上重复留下冗余的脚印，所以嵌入的照片不会是自部署的。意味着如果我加入的 PixelFed 服务器崩了，这些照片也会裂。</p></li></ol><h4 id="实现"><a class="markdownIt-Anchor" href="#实现"></a> 实现</h4><p>关于如何将这些内容嵌入 <code>details</code> 块，核心逻辑很简单：自动抓取并整合我在 Mastodon 和 PixelFed 上发布的特定标签的帖子，然后将它们按月和天组织成日记，并呈现在我的博客文章中。</p><p>主要由四个部分协同工作：</p><ul><li>数据抓取</li><li>智能渲染</li><li>内容注入</li><li>样式表现</li></ul><p>一听很唬人，实际上没有，我大概说说：</p><ol><li><p>数据抓取是所有功能的起点。</p><p>当 Hexo 在构建一篇含有 <code>{% diary_aggregator %}</code> 标签的文章时，脚本会被触发、读取我在 <code>_config.yml</code> 中配置的 Mastodon 和 PixelFed 的服务器地址、用户 ID 和访问令牌（它们俩使用的是同一套 API）。</p><p>连接到这两个平台的 API 后，为了提高效率，脚本会通过 <code>since_id</code> 机制，只请求自上次成功抓取以来发布的新帖子。</p><p>抓取到帖子后，脚本会检查每个帖子是否包含特定的日记标签。只有带这些标签的帖子才会被视为有效的日记条目。</p><p>接着将这些新的、有效的日记条目，与一个位于 <code>source/_data/.diary-cache.json</code> 的缓存文件中的旧条目合并。</p><p>合并后，所有条目会根据日期重新排序并去重，然后回写到缓存文件中，确保数据是最新的、完整的。</p><p>这个步骤的核心职责是确保本地拥有所有日记条目的最新数据，它本身并不关心最终页面长什么样。</p></li><li><p>在更新完缓存后，<code>diary_aggregator</code> 脚本会立刻读取当前正在处理的文章的原始内容。</p><p>它会使用正则表达式查找所有我手动编写的日记占位符，例如 <code>{% details 十二月十八日 diary_sections %}</code>（我写了一个 <code>details</code> 标签，该标签会渲染 <code>&lt;details class="diary_section"&gt;&lt;summary&gt;十二月十八日&lt;/summary&gt;&lt;/details&gt;</code>）。</p><p>脚本会从这些占位符中提取出日期标题（如「十二月十八日」），并将它们记录在一个集合中。这个集合代表了「所有已经由我手动安排好的日期」。</p><p>接下来，脚本从缓存文件中读取当前月份的所有日记条目，并按天分组。然后它会进行一次对比：</p><ul><li><p>如果某天的日记（比如「十二月十九日」）在缓存里存在，但在「手动日期集合」中不存在，脚本就认为这是一个「新」的、无人管理的日期。于是，它会为这一天自动生成一个完整、带内容的 <code>&lt;details&gt;</code> 折叠区块。</p></li><li><p>如果某天的日记（比如「十二月十八日」）在缓存里存在，并且在「手动日期集合」中也存在，脚本就认为这个日期已经被我手动处理了，它就会跳过这个日期，不生成任何 HTML。</p></li></ul><p>最后，<code>{% diary_aggregator %}</code> 标签只会输出那些无人管理的日期的 <code>&lt;details&gt;</code> 区块，或者在所有日期都已被手动管理的情况下输出一个空字符串。</p></li><li><p>不过那些被我手动创建的，还没有被处理，所以还需要写一个注入器。</p><p>在每篇文章即将被渲染成 HTML 之前（<code>before_post_render</code> 事件）运行。它只对 front-matter 中设置了 <code>diary_month</code> 的文章生效。</p><p>注入器会扫描文章内容，寻找 <code>{% details ... diary_sections %}</code> 这样的结构。对于每一个找到的占位符，它会提取出日期标题（例如「十二月十八日」），然后去 <code>.diary-cache.json</code> 缓存文件中查找属于这一天的所有日记条目。</p><p>接着将找到的条目格式化成 HTML（包括时间、文字内容、图片等），然后将这些 HTML 注入到 <code>details</code> 标签的内部。</p></li><li><p>最后，所有这些 HTML 元素如何显示，是由主题的样式文件决定的。</p></li></ol><p>实现讲完了，大家想要复现的话，需要根据自己使用的框架来调整。因为我还在各种调整，就先不把代码放上来了。</p><p>总之，实际效果到这个月底大家就能看到啦（不过因为某些原因，可能有人已经看到了……）。虽然话是这么说的，但其实这些改动更多是只有我才能看到，因为实际效果和过去的「日记片段」区别并不大。</p><h2 id="去-app-化"><a class="markdownIt-Anchor" href="#去-app-化"></a> 去 App 化</h2><p>说完了「去中心化」，现在来说说「去 App 化」。因为 <a href="https://blog.calebjay.com/posts/dont-download-apps/">这篇文章</a>，我想要慢慢卸载手机里的一些 App、使用它们的网页版本。</p><p>我第一个下刀的就是 Instagram。我对这个 App 真是又爱又恨：我很喜欢它的 Story 功能，但是 App 内那群人给我带来的回忆实在是不欢快。当然，这个 App 本身也有很多问题。</p><p>只需要在浏览器内打开该产品的网页版，然后在菜单里选择「安装为 App」即可。以后在手机首页上点击对应的图标就可以打开使用。</p><p>接着我将推特、Facebook、Reddit、LinkedIn 等 App 都卸载，改用网页 App 了。有一些产品是必须使用 App 才行，例如 WhatsApp 这样依赖于手机系统底层的软件。</p><p>本来想着先用个几天看看情况，结果实施的当天就出现了一个问题：室友在 Instagram 上发了一个投票，我也想参与其中，结果网页 App 可以看到这个投票栏，点击后却会显示说「需要下载 App 才可以使用」。</p><p>更有甚者，移动端根本找不到网页 App，比如国内的许多产品 —— <em> 凭什么！</em></p><p>PWA 一个特点是，通知没有那么简单发出来。我认为这是一个双刃剑：如果有急事找你，没有通知就会很麻烦，不过不想被通知轰炸的话，这又是一个好事。只是说，Instagram 和 Facebook 这样的产品本身就不是 IM 类 App，<strong>如果真有人很急找我，那还是乖乖给我发短信或者来电吧</strong>。</p><p>还有一个问题是，我发现我的手机如果关机了或者开启了省电模式，放在桌面上的 PWA 都会被清除，很可能是因为 Edge 浏览器被 kill 了。目前我还不知道有什么办法可以解决这个问题。</p><p>不过拜这所赐，我发现我的手机里根本不需要很多 App—— 每次桌面被清后，我会想要添加回来的才是那些对我来说重要的 App。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;如标题，我想要尝试慢慢地去中心化、去 App 化。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="去中心化" scheme="https://blog.cytrogen.icu/tags/%E5%8E%BB%E4%B8%AD%E5%BF%83%E5%8C%96/"/>
    
  </entry>
  
  <entry>
    <title>你缺这 2.75 美元吗</title>
    <link href="https://blog.cytrogen.icu/posts/d33e.html"/>
    <id>https://blog.cytrogen.icu/posts/d33e.html</id>
    <published>2025-12-21T17:17:00.000Z</published>
    <updated>2026-02-09T17:16:55.009Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>这个月的某一天，我在查阅维基百科的时候，又一次看到他们要捐款。</p><p>心里想着这个网站也不容易，大家几乎都在用，并且也就 2.75 美元，还是给了吧。</p><span id="more"></span><p>实际上，并不是 2.75 美元，而是 3.10 美元。多给的 0.35 我忘了是什么东西的费用了。不过为了方便叙述，以下还是称为 2.75 美元。</p><p>总之要了钱后，它还问我可不可以每个月都捐款 1.75 美元。因为不是什么大数目，我觉得问题不大，便同意了。</p><p>早上起来脑子清醒了一点，想要知道其他人的看法。结果看到了 <a href="https://www.zhihu.com/question/34465982/answer/2773335209">这篇文章</a> 后，一下子便后悔了。实在是不能冲动消费啊！</p><p>首先，这笔钱并没有流向我想象中那个「苦哈哈、用爱发电」的小作坊。</p><p>收到捐款的是<span class="emphasis">维基百科基金会</span>。与许多人的直觉相反，这绝非一个濒临破产的组织，而是一个坐拥数亿美元资产、每年收入远超支出的庞大机构。</p><p>根据 Daily Dot 的 <a href="https://www.dailydot.com/news/wikipedia-endownemnt-fundraising/">报道</a>，维基媒体基金会总资金约为 3 亿美元（截至 2023 年），并在 2023 年前 9 个月就筹集了 1.42 亿美元，远超任何历史年份。</p><p>它们并不缺我这几块钱来救命，甚至可以说，它们的现金流比绝大多数科技公司都要健康。</p><p>既然不缺钱，为什么还要表现得如此窘迫？</p><p>他们通过 A / B 测试发现，这种带有强烈危机感、暗示「不捐款明天就关服」的文案，配合巨大的、遮挡视线的 Banner，转化率最高。尤其是在每年年底的「筹款季」，通过制造焦虑来收割用户的善意，已经成为了一套成熟的商业逻辑。</p><p>我这种铁公鸡也会捐款的话，看来确实如此。</p><p>借用那篇文章里的图片，这个让我掏钱的「情感勒索」界面，大概长这样：</p><p><img src="/posts/d33e/v2-445e8b47200e5c71616dd8f129e15a13_720w.webp" alt="img" loading="lazy"></p><p>事实上，这种营销方式连他们自己的社区都看不下去了。</p><p>2022 年，英文维基百科 Village Pump 就进行过一次 <a href="https://lists.wikimedia.org/hyperkitty/list/wikimedia-l@lists.wikimedia.org/thread/YKYDOBBH2RHJO2DHNP4YEPH37J3L5PBH/">社区投票</a>。志愿者以压倒性多数认为基金会的筹款邮件 <strong>不道德且具有误导性</strong>。具体的批评包括：筹款横幅主要宣传「维基百科」而非「维基媒体基金会」，容易导致捐赠者误认为所有捐款直接用于维持网站运营。</p><p>更让我感到被欺骗的，是这笔资金的去向。</p><p>作为一个普通用户，我天真地以为我的捐款会变成服务器的电费、或者是带宽的租金。然而真相是，维持网站运行的硬件成本只占基金会支出的极小部分（约为 5%）。</p><p>根据基金会公开的财报和过往争议来看，资金中相当大的一部分主要用于数百名员工的薪资与福利，以及规模可观的软件开发和法律相关开支，另外也有一部分投向以多元与包容为目标的项目；至于这些支出的效率如何、是否带有明显的政治取向，则在不同观察者之间存在较大分歧。</p><p>我并不心疼钱，但我希望我的善意不被滥用。</p><p>如果他们诚实地坦白「我们需要钱来扩大团队规模、做更多包容性项目」，<strong>我是绝对不会捐款的</strong> —— 因为那不是我的义务。但他们选择了暗示「没钱就关服」，这就是对「日行一善」这种朴素心理的精准收割，本质上就是欺诈。</p><p>更深层的裂痕在于立场。作为一个中国用户，我意识到我正在资助的这个组织，在对待中文社区时不仅缺乏公正，甚至带有明显的政治偏见与傲慢。</p><p>2021 年 9 月 13 日，维基媒体基金会对中文维基百科进行了规模前所未有的行动：禁制了 7 名用户，撤销了 12 名管理员的权限，其中包括中文维基百科十大活跃管理员中的四位。理由是深入调查中国大陆维基人用户组后认为他们存在「渗透」风险，甚至可能对其他编辑者造成恐吓与起底的威胁，并试图在与中国相关的条目中施加不当影响。</p><p>实际上又如何呢？指控被公开报道了，<strong>具体证据却从未向公众公开</strong>；外界只能看到基金会的结论，而无法看到调查过程或原始材料。与此同时，被封禁者否认这些指控，并批评基金会的程序不透明。这使得整个事件至今仍充满争议。</p><p>用我的钱，去供养一个对我所在社群并不友好的管理层，这才是最荒谬的地方。</p><p>所谓「失去」的 2.75 美元，对于财大气粗的基金会来说九牛一毛；我没有从中得到任何增值服务，毕竟维基百科本来就是免费的。</p><p>真要说得到了什么，大概就是一个教训：<strong>不要被互联网上的「弱者叙事」轻易绑架</strong>。当然，可能还附赠了一堆基于我捐款数据而生成的后续催捐邮件。</p><p>为了不再继续这种无意义的供养，我立刻去取消了那个顺手勾选的「月付」计划。虽然目前还没有收到确认回复（可能是赶上节假日效率低下），但态度必须摆出来。</p><p>写下这篇文章，也是希望提醒大家：爱维基百科的内容，不代表要无脑供养基金会。在按下支付键之前，先搞明白你的善意到底喂给了谁。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;这个月的某一天，我在查阅维基百科的时候，又一次看到他们要捐款。&lt;/p&gt;
&lt;p&gt;心里想着这个网站也不容易，大家几乎都在用，并且也就 2.75 美元，还是给了吧。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
  </entry>
  
  <entry>
    <title>儿童网红背后的黑暗</title>
    <link href="https://blog.cytrogen.icu/posts/196a.html"/>
    <id>https://blog.cytrogen.icu/posts/196a.html</id>
    <published>2025-12-20T14:39:11.000Z</published>
    <updated>2026-02-09T17:16:55.009Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>演讲课的最后一场演讲，我选择的主题是「儿童网红背后的黑暗」。</p><span id="more"></span><p>我不清楚国内怎么样，但是国外的儿童网红真不少。最有名的 Ryan 还当过几年最赚钱的 YouTuber 榜首，这个赛道远比我们想象的值钱。</p><p>不过很意外的是，Pink Fox 唱的 Baby Shark，这个洗脑了无数带娃家长的歌曲，居然没有赚到很多钱。</p><p>儿童网红其实算「童工」的一类，只是这个行业太新了，法律还未跟进。上个世纪有个很有名的儿童演员，叫 Jackie Coogan，他和卓别林一起工作过，赚的钱不能说多，只能说是特别多。但是在他成年后，他才发现他赚的钱全都没了 —— 被父母用完了。加州因为他，通过了 Coogan Law，也就是保护儿童演员的一个法律，<strong>所赚的 15% 必须存入信托基金，待儿童演员成年后才可以取出</strong>。</p><p>对于儿童网红而言，问题会更麻烦一些。多数的儿童网红都是播和玩具有关的。父母录制孩子们玩玩具的视频到网上，你要如何分辨哪个是儿童网红，哪个是单纯地记录小孩在玩？并且 Coogan Law 要求儿童必须有一个雇主，对于儿童网红而言，他们的雇主又是谁？父母吗？就算有和平台签约的频道，那么没有签约的频道怎么办呢？</p><p>让儿童工作的弊端有很多，我就不详细说明了。我认为儿童就应该有一个儿童的生活，简单来说便是要有一个童年。童年对人类的重要性实在是不言而喻。</p><p>就算工作是玩，但是工作就是工作，许多成年人的工作尽管是和兴趣有关，也难免会讨厌自己的工作，这对儿童来说也一样。更不用提当要玩的玩具里出现了赞助商，一旦和钱、公司有了关系，很多事情都会变得不纯粹。</p><p>比如虚假背书，强迫孩子们去推广自己讨厌的玩具。这不仅仅是工作，对孩子们而言也是一种情感剥削，迫使他们在幼年就学会隐藏真实感受。</p><p>我在演讲中引用了一个研究，总计采访 19 个儿童网红频道。其中一些对话令我印象深刻：孩子们都说自己录制节目很有趣，父母没有剥削自己。但聊得越来越深入时，孩子们便开始抱怨父母经常在一些事情上管这儿管那儿。例如一个孩子的母亲会强迫他对着镜子练习笑容。</p><p>互联网也是残酷的，没有孩子们想象的那样淳朴。今天拍下的觉得有趣的视频，很有可能在未来以全然不同的形式反噬自己。</p><p>法国在 2020 年赋予了孩子无需父母同意即可删除自己视频的权利。我认为和互联网相关的法律都应该像这样被推进。大多数人都是互联网的消费者，并且在互联网上花费的时间愈来愈多，也应该让互联网变得安全。不过互联网变安全的代价，自然就是不再自由。</p><p>只是对于孩子来说，<strong>他们从来没有过选择「不自由」或者「被保护」的权利</strong>，他们是被父母推向这个「自由但危险」的领域的。</p><p>而孩子这个身份，又会不约而同地吸引一群可怕的掠食者 —— 结果几乎所有受访的博主父母都接触过恋童癖的信息。当然，没有说这都是频道的错 —— 恶意确实不该存在，但它现在就在那里。作为孩子唯一的防线，父母却亲手将监护权让位于经营权，悲剧便成了一个概率问题。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;演讲课的最后一场演讲，我选择的主题是「儿童网红背后的黑暗」。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="互联网" scheme="https://blog.cytrogen.icu/tags/%E4%BA%92%E8%81%94%E7%BD%91/"/>
    
  </entry>
  
  <entry>
    <title>请学会如何读空气吧</title>
    <link href="https://blog.cytrogen.icu/posts/5a85.html"/>
    <id>https://blog.cytrogen.icu/posts/5a85.html</id>
    <published>2025-12-01T22:44:03.000Z</published>
    <updated>2026-02-09T17:16:55.549Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><div class="reply-block h-entry"><div class="post-meta p-author h-card visually-hidden"><img class="u-photo" src="https://blog.cytrogen.icu/favicon.png" alt="Cytrogen" loading="lazy"><span class="p-name">Cytrogen</span><a class="u-url" href="https://blog.cytrogen.icu">https://blog.cytrogen.icu</a></div><time class="dt-published visually-hidden" datetime="2026-09-17T20:47:54.640Z">2026-09-17T20:47:54.640Z</time><a class="u-url visually-hidden" href="https://blog.cytrogen.icu">Post Link</a><div class="reply-content e-content"><p>前不久，我写了一篇 <a href="https://cytrogen.icu/posts/dfa8.html">文章</a>，讲了我在一个评论区底下发觉到的 Whataboutism。未曾想，这篇文章给我带来的，是一场跟朋友的争吵。</p><span id="more"></span><p>我的朋友阅读了那篇文章的草稿（和实际发出来的内容大差不差），并提出了这些让他反感的点：</p><ol><li>Whataboutism 这个例子用得不好，两者明明有关联性</li><li>评论区说的没有问题，中国的作业就是比美国的作业多</li><li>发布在网上的东西被人骂了活该</li><li>无论是发帖子的人、发评论的人，还是写文章的我，全都是事逼；<em>小题大做，闲得慌</em></li></ol><p>我来一一说说。</p></div><div class="reply-meta p-in-reply-to h-cite"><span class="reply-label">回复：</span><a class="reply-target u-url" href="https://cytrogen.icu/posts/dfa8.html">https://cytrogen.icu/posts/dfa8.html</a></div></div><h2 id="一-语境错位"><a class="markdownIt-Anchor" href="#一-语境错位"></a> 一、语境错位</h2><p>Whataboutism 原本是一种政治宣传技巧，但是我在这里的使用方式更多是将其视为一种逻辑谬论，直白点理解就是「因为有更糟糕的事情 B 在，所以糟糕的事情 A 就不算问题。」</p><p>朋友会认为这个例子不好，是因为他觉得「美国的作业」和「中国的作业」都是「作业」，是有关联性的，那么评论提及「中国的作业」就不涉及到 Whataboutism。</p><p>我们的核心分歧在于，「关联性」到底由什么决定？</p><p>朋友的逻辑是，只要主体属于同一类别（「作业」），且事实属实（「中国的作业确实比美国的作业多」），那么在这个帖子下提及到中国的作业就是合理的比较，不是谬误。</p><p>似乎很有道理。</p><p>但是我们在讨论一件事的时候，<em>说出来的内容</em> 其实并没有 <em>说这个内容的目的</em> 重要。原帖主发帖的目的是什么？是寻求安慰、共情和建议。这些提及到国内作业的评论做的又是什么？首先是预设原帖主的目的是否认国内的作业没有美国的多，其次是靠比烂彰显优越感。这些评论是否有帮助到原帖主？没有，反而更糟糕了，因为它们否认了原帖主抱怨的权利。</p><p>如果提及国内作业的目的是为了消解原帖主的情绪或者否定他的问题，那么即使他们说的是事实，他们依然涉及到了 Whataboutism 或者比烂。</p><p>原帖的语境是情感宣泄，而评论却把语境强制降维成了事实比对。但是问题在于，<em>到底谁问你们了？有任何人说中国的作业不多吗？</em></p><h2 id="二-真理的功能性"><a class="markdownIt-Anchor" href="#二-真理的功能性"></a> 二、真理的功能性</h2><div class="reply-block h-entry"><div class="post-meta p-author h-card visually-hidden"><img class="u-photo" src="https://blog.cytrogen.icu/favicon.png" alt="Cytrogen" loading="lazy"><span class="p-name">Cytrogen</span><a class="u-url" href="https://blog.cytrogen.icu">https://blog.cytrogen.icu</a></div><time class="dt-published visually-hidden" datetime="2026-09-17T20:47:54.643Z">2026-09-17T20:47:54.643Z</time><a class="u-url visually-hidden" href="https://blog.cytrogen.icu">Post Link</a><div class="reply-content e-content"><p>朋友以及评论区的那些人的防御逻辑在于，他们说的是事实。「中国的作业就是多」这句话因为在事实层面是真的，所以他们也认为自己在对话层面是合理的。</p><p>但是人类之间的对话绝对不是只要 <a href="https://cytrogen.icu/posts/d4e5.html">说了事实便可以攻击他人</a>。</p><p>事实有两种用法：一是解决问题，例如你提醒他人外面下雨了，记得带伞；二是剥夺权利，骂所有说食物不好吃的人「非洲还有人饿死呢，你要什么好抱怨的」。当一个人在寻求情感支持的时候，去谈论谁更惨，本质是一种冷漠和对他人痛苦的刻意忽视。</p><p>如果按照这个逻辑下去，那么除了那个全宇宙最惨的人，剩下 70 亿人都没有资格难过了。这显而易见是荒谬的。</p><p><strong>这些评论拿出的「事实」，不是为了讨论，而是为了封你的嘴。</strong> 这就是我想说的功能性。目的真的是为了陈述事实吗？那怎么看都不是。</p><p>不过我认为，朋友之所以无法理解我说的，最主要还是「拒绝看见情绪价值」这个维度。我后面会提到。</p></div><div class="reply-meta p-in-reply-to h-cite"><span class="reply-label">回复：</span><a class="reply-target u-url" href="https://cytrogen.icu/posts/d4e5.html">https://cytrogen.icu/posts/d4e5.html</a></div></div><h2 id="三-消极放任"><a class="markdownIt-Anchor" href="#三-消极放任"></a> 三、消极放任</h2><p>到这个时候，朋友明显开始出现了情绪化的状况，不过他依然想要和我辩论。他认为，发到互联网上的东西就是会被他人看到、批判，甚至辱骂。这是再正常不过的事情了，因为互联网无时无刻都充斥着攻击和辱骂。<em>不过是一个这么小的一件事，你还专门写个文章说，你一天天难道没有事情做吗？</em></p><p>这里的逻辑可以简单梳理为，既然一件事情已经是这样了，那么我想要去改变、批判它，就是矫情和多余。这也是另一种形式的虚无主义：<em>反正人都要死，何必这么拼命？</em> 这个事情是大事吗？当然不是，它确实是一件小到不能再小的事情。</p><p>但小事不代表没错。我发现了问题，我指了出来，你指责我是什么意思？</p><p>这种「消极放任」才是最可怕的。因为它 <strong>不仅承认了恶的存在，还进一步把「指出恶」定义为一种错误</strong>。这不单单是虚无，也是一种对现状的共谋。用「大家都被骂」来合理化网络暴力，并试图以此让不满者闭嘴时，他其实已经成为了那个糟糕环境的维护者。所谓的「正常」，也不过是习惯了麻木之后的自我催眠罢了。</p><p>我肯定不认为写一篇博客就能彻底净化互联网，但我至少想要拒绝加入这种麻木的合唱。连指出「这不对」的勇气都被嘲笑，那才是无可救药。</p><h2 id="四-充满攻击性的理中客"><a class="markdownIt-Anchor" href="#四-充满攻击性的理中客"></a> 四、充满攻击性的理中客</h2><p>到最后，他终于把自己内心所想的事情说了出来：他觉得我们三方都是事逼。</p><p>当他这么说的时候，我忽然理解了我们之前辩论的实质。那些争论或许都只是表象，核心驱动力可能并非源于逻辑，而是源于一种深刻的情感不认同 —— 他是一个厌恶互联网的人，他讨厌我写博客、讨厌我上网、讨厌我交网友……<em> 真烦！跟你有什么关系！</em> 总之，他觉得任何在网上发布这些「私人想法」的人，都有罪，都是在无事生非。</p><p>于是，一场本该关于公共讨论规则的辩论，最终坍缩为一场人身攻击。我意识到，他或许只想批判我的姿态，所以我也不乐意再跟他讲什么道理了。我说，「你的这些想法真的很烦很坏。」烦是因为这并不是他第一次向我传达这些具有攻击性的想法（而我最讨厌别人满嘴只剩自己了）；坏是因为 <strong>他一边劝我闭嘴，一边自己又闭不上嘴</strong>。尽管他说了这都是观点、没有想要纠正我的意思，但一些话并不会因为你的事后解释就变了性质。</p><p>或许网络上那些不由分说的「比烂」和「反问」，其内核也是如此：拒绝进入语境、拒绝理解情感，只想用最简单粗暴的方式完成居高临下评判的姿态。这种姿态不仅隔绝了理解，也杀死了沟通。如果有什么是可以打破这层傲慢的厚壁的话，或者就只有这简单的几个字：<strong>请学会如何读空气吧 —— 因为在冰冷的逻辑和事实之外，那里才是我们要共同呼吸的地方。</strong></p></body></html>]]></content>
    
    
    <summary type="html">&lt;div class=&quot;reply-block h-entry&quot;&gt;&lt;div class=&quot;post-meta p-author h-card visually-hidden&quot;&gt;&lt;img class=&quot;u-photo&quot; src=&quot;https://blog.cytrogen.icu/favicon.png&quot; alt=&quot;Cytrogen&quot;&gt;&lt;span class=&quot;p-name&quot;&gt;Cytrogen&lt;/span&gt;&lt;a class=&quot;u-url&quot; href=&quot;https://blog.cytrogen.icu&quot;&gt;https://blog.cytrogen.icu&lt;/a&gt;&lt;/div&gt;&lt;time class=&quot;dt-published visually-hidden&quot; datetime=&quot;2026-09-17T20:47:54.640Z&quot;&gt;2026-09-17T20:47:54.640Z&lt;/time&gt;&lt;a class=&quot;u-url visually-hidden&quot; href=&quot;https://blog.cytrogen.icu&quot;&gt;Post Link&lt;/a&gt;&lt;div class=&quot;reply-content e-content&quot;&gt;&lt;p&gt;前不久，我写了一篇 &lt;a href=&quot;https://cytrogen.icu/posts/dfa8.html&quot;&gt;文章&lt;/a&gt;，讲了我在一个评论区底下发觉到的 Whataboutism。未曾想，这篇文章给我带来的，是一场跟朋友的争吵。&lt;/p&gt;&lt;/div&gt;&lt;/div&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="互联网" scheme="https://blog.cytrogen.icu/tags/%E4%BA%92%E8%81%94%E7%BD%91/"/>
    
    <category term="逻辑学" scheme="https://blog.cytrogen.icu/tags/%E9%80%BB%E8%BE%91%E5%AD%A6/"/>
    
    <category term="心理学" scheme="https://blog.cytrogen.icu/tags/%E5%BF%83%E7%90%86%E5%AD%A6/"/>
    
    <category term="社会学" scheme="https://blog.cytrogen.icu/tags/%E7%A4%BE%E4%BC%9A%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>想法在乙巳纸月迭代</title>
    <link href="https://blog.cytrogen.icu/posts/31df.html"/>
    <id>https://blog.cytrogen.icu/posts/31df.html</id>
    <published>2025-12-01T16:38:23.000Z</published>
    <updated>2026-02-09T17:16:55.277Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>虽然上个月已经说了很冷，但发现这个月变得更冷了……</p><span id="more"></span><details><summary>本期导读</summary><h2 id="商业与社会"><a class="markdownIt-Anchor" href="#商业与社会"></a> <a href="#%E5%95%86%E4%B8%9A%E4%B8%8E%E7%A4%BE%E4%BC%9A">商业与社会</a></h2><p>关注资本流向与阶层分化。</p><ul><li><a href="#%E7%A7%91%E6%8A%80%E5%85%AC%E5%8F%B8%E6%AD%A3%E5%9C%A8%E8%A3%81%E5%91%98%E4%BB%A5%E8%B5%84%E5%8A%A9-ai">科技公司正在裁员以「资助 AI」</a></li><li>经济的 K 型分化：<a href="#%E9%BA%A6%E5%BD%93%E5%8A%B3%E6%AD%A3%E5%9C%A8%E5%A4%B1%E5%8E%BB%E5%85%B6%E4%BD%8E%E6%94%B6%E5%85%A5%E9%A1%BE%E5%AE%A2">麦当劳</a> 和 <a href="#%E4%BD%A0%E8%AF%AF%E8%A7%A3%E4%BA%86%E8%B4%AB%E7%A9%B7%E7%9A%84%E5%90%AB%E4%B9%89">贫穷的真相</a></li><li><a href="#%E5%AD%A9%E5%AD%90%E4%BB%AC%E5%9C%A8%E5%93%AA%E9%87%8C%E7%8E%A9%E8%80%8D">现在的孩子们都在哪里玩耍？</a></li></ul><h2 id="心理与关系"><a class="markdownIt-Anchor" href="#心理与关系"></a> <a href="#%E5%BF%83%E7%90%86%E4%B8%8E%E5%85%B3%E7%B3%BB">心理与关系</a></h2><p>我们如何处理与自己、与他人的关系</p><ul><li><a href="#%E6%88%91%E4%B8%8D%E6%98%AF%E6%9C%BA%E5%99%A8%E4%BA%BA%E4%BD%86%E6%88%91%E4%B9%9F%E6%B2%A1%E6%9C%89%E6%80%A7%E9%A5%A5%E6%B8%B4">我通关了 <em>I'm Not a Robot</em> 但是……</a></li><li><a href="#%E6%99%BA%E5%8A%9B%E9%AB%98%E7%9A%84%E4%BA%BA%E5%B9%B6%E4%B8%8D%E6%AF%94%E5%85%B6%E4%BB%96%E4%BA%BA%E6%9B%B4%E5%B9%B8%E7%A6%8F">聪明人为何不快乐？</a></li><li><a href="#%E4%B8%8D%E6%98%AF%E5%9C%A8%E5%81%9A%E9%82%A3%E4%BB%B6%E4%BA%8B%E7%9A%84%E4%BA%8B">「准备做」</a> 不是做，而是 <a href="#%E6%88%96%E8%AE%B8%E4%BD%A0%E5%85%B6%E5%AE%9E%E5%B9%B6%E6%B2%A1%E6%9C%89%E7%9C%9F%E6%AD%A3%E5%8A%AA%E5%8A%9B">一种停滞</a></li><li><a href="#%E4%BD%A0%E6%98%AF%E5%90%A6%E9%99%B7%E5%85%A5%E4%BA%86%E7%94%B5%E5%BD%B1%E9%80%BB%E8%BE%91">为什么我们不能好好沟通呢！</a></li><li>在网络上思考 <a href="#what-about-%E5%92%8C%E6%AF%94%E7%83%82">比烂</a> 和 <a href="#%E6%88%91%E5%9C%A8%E8%B0%88%E8%AE%BA%E5%85%B1%E6%83%85%E4%BB%96%E4%BB%AC%E5%9C%A8%E8%B0%88%E8%AE%BA%E9%80%BB%E8%BE%91">共情</a></li><li><a href="#%E7%AB%A5%E5%B9%B4%E7%8E%A9%E4%BC%B4%E8%80%8C%E9%9D%9E%E6%AF%8D%E4%BA%B2%E5%A1%91%E9%80%A0%E4%BE%9D%E6%81%8B%E9%A3%8E%E6%A0%BC%E6%9C%80%E6%B7%B1">童年的小伙伴或许才是塑造我们依恋模式的大头？</a></li><li><a href="#%E6%88%91%E7%88%B6%E4%BA%B2%E5%8E%BB%E4%B8%96%E5%90%8E%E6%88%91%E4%BB%AC%E6%89%BE%E5%88%B0%E4%BA%86%E9%82%A3%E4%BA%9B%E6%83%85%E4%B9%A6">传统思想造就了一个个痛苦的人</a></li></ul><h2 id="技术与创造"><a class="markdownIt-Anchor" href="#技术与创造"></a> <a href="#%E6%8A%80%E6%9C%AF%E4%B8%8E%E5%88%9B%E9%80%A0">技术与创造</a></h2><p>互联网生态观察与本站折腾记录。</p><ul><li><a href="#%E5%8D%9A%E5%AE%A2%E6%8A%98%E8%85%BE">博客更新记录</a></li><li><a href="#%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD%E6%B5%8F%E8%A7%88%E5%99%A8%E5%85%A5%E5%9C%BA%E8%B4%B9%E5%A4%AA%E9%AB%98">AI 浏览器的入场费太高</a></li><li><a href="#%E5%9C%A8-ai-%E6%81%90%E6%85%8C%E7%9A%84%E6%97%B6%E4%BB%A3%E7%86%9F%E7%BB%83%E5%BA%A6%E6%98%AF%E4%B8%80%E7%A7%8D%E7%B4%AF%E8%B5%98">在 AI 恐慌的时代，熟练度是一种累赘</a></li><li><a href="#typora-%E5%92%8C-hexo-%E7%9A%84%E5%AE%8C%E7%BE%8E%E5%B7%A5%E4%BD%9C%E6%B5%81">Typora 和 Hexo 如何一起合作</a></li><li><a href="#web-%E5%8A%A8%E7%94%BB%E6%80%A7%E8%83%BD%E5%88%86%E7%BA%A7%E4%BD%93%E7%B3%BB">Web 动画性能分级体系</a></li><li><a href="#github-%E5%B7%B2%E7%BB%8F%E5%81%9C%E6%AD%A2%E4%BD%BF%E7%94%A8-toasts">GitHub 停用了 Toasts</a></li><li><a href="#%E6%97%A0%E4%BA%BA%E6%B0%B8%E7%94%9F%E8%BF%8E%E6%9D%A5-25-%E5%91%A8%E5%B9%B4%E4%BD%86%E4%BD%A0%E4%BB%8D%E7%84%B6%E6%97%A0%E6%B3%95%E5%90%88%E6%B3%95%E8%B4%AD%E4%B9%B0%E5%AE%83">可笑的版权法「强迫」玩家游玩盗版</a></li><li><a href="#%E5%B0%8F%E5%9E%8B%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E7%9A%84%E5%91%BD%E8%BF%90">小型开源项目的命运</a></li><li><a href="#%E6%97%A0%E9%9C%80-javascript-%E7%9A%84-llm-%E7%88%AC%E8%99%AB%E9%98%BB%E6%8C%A1%E6%96%B9%E6%B3%95">无需 JavaScript 的 LLM 爬虫阻挡方法</a></li><li><a href="#%E4%BA%92%E8%81%94%E7%BD%91%E4%B8%8D%E5%86%8D%E6%98%AF%E4%B8%80%E4%B8%AA%E5%AE%89%E5%85%A8%E7%9A%84%E9%81%BF%E9%A3%8E%E6%B8%AF">互联网不再是一个安全的避风港</a></li><li><a href="#%E4%B8%AA%E4%BA%BA%E5%8D%9A%E5%AE%A2%E5%8F%88%E5%9B%9E%E6%9D%A5%E4%BA%86%E5%88%A9%E5%9F%BA%E5%8D%9A%E5%AE%A2%E6%98%AF%E4%B8%8D%E6%98%AF%E4%B9%9F%E8%AF%A5%E5%A4%8D%E5%85%B4%E4%BA%86">让利基博客也回来吧！</a></li><li><a href="#ai-%E5%AF%B9%E8%BF%99%E6%AE%B5%E4%BB%A3%E7%A0%81%E7%9A%84%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86%E6%9C%89%E9%9D%9E%E5%B8%B8%E6%B7%B1%E5%88%BB%E7%9A%84%E7%90%86%E8%A7%A3">AI 对这段代码的工作原理有非常深刻的理解！</a></li><li><a href="#%E6%9C%89%E8%B6%A3%E9%A1%B9%E7%9B%AE">有趣项目分享</a></li></ul><h2 id="生活与文娱"><a class="markdownIt-Anchor" href="#生活与文娱"></a> <a href="#%E7%94%9F%E6%B4%BB%E4%B8%8E%E6%96%87%E5%A8%B1">生活与文娱</a></h2><p>具体的、鲜活的十一月。</p><ul><li><a href="#%E4%B9%A6%E5%BD%B1%E9%9F%B3">书影音</a></li><li><a href="#%E6%97%A5%E8%AE%B0%E7%89%87%E6%AE%B5">真生活</a></li></ul></details><h2 id="商业与社会-2"><a class="markdownIt-Anchor" href="#商业与社会-2"></a> 商业与社会</h2><h4 id="科技公司正在裁员以资助-ai"><a class="markdownIt-Anchor" href="#科技公司正在裁员以资助-ai"></a> 科技公司正在裁员以「资助 AI」</h4><p>但他们把钱花在彼此身上，而没有人真正盈利。</p><p><a href="https://www.reddit.com/r/ArtificialInteligence/comments/1oj52xx/tech_companies_are_firing_everyone_to_fund_ai_but/">Reddit</a> 一位用户提出：七巨头（苹果、微软、英伟达、亚马逊、谷歌、Meta 和特斯拉）正在以「资助 AI」为名裁掉数十万员工，而 <strong>在 AI 上的支出远超裁员节省的成本</strong>、大部分 AI 基础设施是彼此之间购买的。目前除了 Meta 外，没有任何公司从 AI 中获得实际利润。但是他们无法停止支出，否则股价会崩盘。投资人们都相信 AI 会带来巨大的利润，股价为此不断地被推高，但这是靠不断花钱制造出来的「增长的假象」。如果哪家公司停止投入，股价就会暴跌，所以大家都被迫继续烧钱。整个美国股市的增长很大程度上依赖这几家公司。<strong>如果 AI 投资不能带来回报，泡沫可能会破裂，影响整个经济。</strong></p><p>我大概地搜索了一下。根据 CNBC 在今年二月份的一篇 <a href="https://www.cnbc.com/2025/02/08/tech-megacaps-to-spend-more-than-300-billion-in-2025-to-win-in-ai.html">报道</a>，Meta、亚马逊、谷歌和微软今年计划在 AI 和数据中心建设上投入高达 3200 亿美元，比去年多了足足近 1000 亿。要知道，按照 Reddit 用户所说，2025 年已经有超过 18 万名科技行业员工被裁掉。假设他们每个人年薪都是 10 万美元，也就是节省了 180 亿美元，这也 <strong>只是这 3200 亿的大约 17 分之一而已</strong>。</p><p>报道的作者 Samantha Subin 也提到，虽然投入巨大，但是目前 AI 云业务的收入增长未达预期，也有投资人开始质疑这种「烧钱竞赛」是否可持续。不过还是可以看出，相信 AI 的投资人更多，现在每天也是有源源不断的 AI 产品被开发、融资。</p><p>关于是否有公司从 AI 那儿获得实际利润，我要小小澄清一下：Meta 让 AI 带动广告收入增长，也就是说，<strong>Meta 实际获利靠的还是广告，而非以 AI 本身作为产品的业务</strong>。这样看的话，AI 能否盈利的可能性就从「可能」变成了「好像不太行呢」。目前唯一有公开 AI 财务数据的公司是 OpenAI，他们也不好过：在推理上每花 1 美元，只能从用户那里获得约 0.4 美元的收入。即使 ChatGPT Pro 用户支付 200 美元一个月，也会因为 token 生成量过大，而导致 OpenAI 依然在这些用户身上亏钱。可悲的是，现在如果有任何科技巨头宣布暂停 AI 支出，都会被市场理解为放弃 AI 竞争，从而导致股价暴跌。</p><p>用这个 Reddit 用户的一句话来总结就是：</p><blockquote><p>「而我们只能随波逐流。」</p></blockquote><h4 id="麦当劳正在失去其低收入顾客"><a class="markdownIt-Anchor" href="#麦当劳正在失去其低收入顾客"></a> <a href="https://www.latimes.com/business/story/2025-11-16/mcdonalds-is-losing-its-low-income-customers">《麦当劳正在失去其低收入顾客》</a></h4><p>快餐业长期以来依赖低收入群体作为核心顾客。比如 21 世纪初的时候，麦当劳就通过推出了 Dollar Menu（一美元菜单）在低迷时期成功逆转。</p><p>然而现在，麦当劳的低收入顾客正迅速被高收入顾客取代！快餐价格上涨显著，导致低收入顾客流失，客流量下降两位数。高收入顾客的消费反而增加，形成「阶层分化」的消费趋势。不只是麦当劳，其他快餐连锁店的顾客结构也在发生变化。</p><p>这件事的原因很复杂，牵扯到各种东西的成本和政策，总而言之美国的物价一直在上涨。这反而反映出了美国消费经济的「K 型分化」：<strong>富裕群体消费力增强，低收入群体收缩</strong>。现在的低收入群体光是健康地活着都很有压力。</p><p>对于企业来说，他们也不想要流失这类顾客，并且消费者对于价格上涨的容忍度是有上限的。麦当劳尝试推出各类优惠套餐、其他连锁餐饮也在推出经济组合以吸引顾客。</p><p>未来，美国经济又会怎么样呢？</p><p>如果你觉得自己很穷，但依然买得起快餐、质疑为什么有人买不起的话，请见下面这篇文章。</p><h4 id="你误解了贫穷的含义"><a class="markdownIt-Anchor" href="#你误解了贫穷的含义"></a> <a href="https://blog.ctms.me/posts/2025-11-14-being-poor-or-being-broke/">《你误解了「贫穷」的含义》</a></h4><p>作者 Dom Corriveau 在他的文章中提到，「拮据」是短期的资金紧张，而「贫穷」是一种长期、无解的困境。人们误解了这两者的区别，以至于许多建议的出发点是善意的，但其实根本没有帮助。例如：</p><ul><li>让穷人去学新的技能：穷人无法付钱请别人帮忙，所以他们早就掌握大量技能</li><li>让穷人在家做饭：穷人的家里根本没有菜，只能去排长队领物资</li><li>让穷人找第二份工作：穷人都已经在靠排队才能吃上饭了，又怎么可能有时间去打第二份工呢？</li></ul><p><strong>贫穷是长期、无尽、没有缓解的。</strong></p><h4 id="孩子们在哪里玩耍"><a class="markdownIt-Anchor" href="#孩子们在哪里玩耍"></a> <a href="https://unpublishablepapers.substack.com/p/where-do-the-children-play">《孩子们在哪里玩耍？》</a></h4><p>一篇让我很意外的文章。作者 Eli Stark-Elster 借巴亚卡人（刚果雨林里的一个民族）的童年，指出西方人（我认为不只是西方人）的童年有问题。这是他给出的 8-12 岁的美国儿童的数据：</p><ul><li>45% 的人从未在商店里走过与父母不同的过道</li><li>56% 的人没有在父母的陪同下与邻居交谈过</li><li>61% 的人没有在没有成人帮助的情况下与朋友制定计划</li><li>62% 的受访者表示，在没有成人陪同的情况下，他们没有去过（商店、公园、学校）等地方</li><li>63% 的人没有在室外建造过结构（例如，堡垒或树屋）</li><li>71% 的人没有使用过锋利的刀</li><li>31% 的人曾与大型语言模型进行过交流</li><li>23% 的人曾在网上与陌生人交谈</li><li>到 13 岁时，50% 的人曾接触过色情内容</li></ul><p>Stark-Elster 认为，在现实世界里西方儿童受到了过度的成人监管，几乎没有独立探索的空间。与此相反的是，在数字空间里儿童完全脱离了成人的掌控，并且越来越多地把时间花在其中。这种现象通常被归咎于科技公司：它们设计出来的平台极具成瘾性，使儿童难以抗拒。不过他提出了另一个想法：<strong>数字空间之所以吸引儿童，是因为它成为了他们唯一能「没有成人」的成长场所</strong>。</p><p>西方儿童的出行能力一直都在下降，这种变化远早于互联网出现。在人类进化史上，童年本来就是同伴文化和独立世界的时期，孩子们主要是在成人视线之外成长。而在西方，成人们已经破坏了自然的隐秘空间，导致孩子们失去了现实中的秘密基地，并且孩子之间住的更远、需要依赖父母开车去参加组织活动。另一个因素是父母对此的态度：担心如果让孩子们在户外无人看管地玩耍，会遇到危险的陌生人或者受到邻居的评判。这意味着孩子们已经失去了同伴文化：没有地方玩、没有玩伴。就算条件改善，父母也依然可能不让孩子独自外出。</p><details><summary>我的故事</summary><p>2015 年我来到美国，母亲对我说的令我记忆犹新的话便是「不要出门」。理由很简单：「美国很乱，小孩子单独出门会被警察质疑是否存在虐待。」</p><p>我不否认家的外面很大可能会出现恋童癖、黑帮份子或者其他危险的陌生人，但这也确实影响到了我的童年，因为我上高中前的那五年里几乎没有同朋友外出过，我只能在学校见到他们或者网上。好吧，有时候网上也不行，因为我的母亲会检查我的手机、登录我的 QQ，退出所有她看不懂的群聊。而我会狼狈地在第二天又偷偷把这些群聊加回来。</p><p>为什么高中就改变了这些事儿呢？因为我的高中离我家非常远，而我的一位朋友就住在高中旁边。那时我会假装自己还没放学，然后在她家里玩，之后我住在了她家里，直到现在。</p><p>后来家里有了妹妹。因为年龄差距，我也算是她半个妈了。这时候我们已经搬到了郊区，出行都需要开车。虽然家附近有公园和操场，但家长们依然不会让孩子们单独出去玩。这也代表如果我妹妹想要跟朋友出去玩，永远会有一个成人陪同，且他们出行的频率完全基于这些家长们是否有时间或者想要出门。不能出门的话那怎么办呢？待在家里玩 Roblox、跟朋友打 Facetime 聊天…… 也没有其他了，总不能真的希望这些十岁的孩子们做一整天功课吧！</p><p>我很想念我还在中国时的童年生活。当时我住在一个小区里，小区楼下有数个健身器材，并且位置足够封闭。我们当时最常做的便是在漫步机上荡来荡去、在扭腰机上转来转去，或者玩跷跷板，然后聊我们在脑海里构思的「游戏」。我认为这是一种很独特的「半熟人社会」，没有家长在真的监视我们，但又同时被其他成人们（保安、小卖部、路过的邻居等）监视是否有任何危险。我们只需要下楼就可以开始玩乐，也不需要担心外面的人进来、抓走我们。</p><p>但这也不代表我赞同直接把妹妹放到外面、自个儿去玩。一是我也担心危险；二是真的会有邻居举报。关于美国的「儿童虐待」一事，我可能会在未来写一篇相关的文章，主要是讲一下我遇到的问题。</p></details><h2 id="心理与关系-2"><a class="markdownIt-Anchor" href="#心理与关系-2"></a> 心理与关系</h2><h4 id="我不是机器人但我也没有性饥渴"><a class="markdownIt-Anchor" href="#我不是机器人但我也没有性饥渴"></a> 我不是机器人但我也没有性饥渴！</h4><div class="reply-block h-entry"><div class="post-meta p-author h-card visually-hidden"><img class="u-photo" src="https://blog.cytrogen.icu/favicon.png" alt="Cytrogen" loading="lazy"><span class="p-name">Cytrogen</span><a class="u-url" href="https://blog.cytrogen.icu">https://blog.cytrogen.icu</a></div><time class="dt-published visually-hidden" datetime="2026-09-17T20:47:54.610Z">2026-09-17T20:47:54.610Z</time><a class="u-url visually-hidden" href="https://blog.cytrogen.icu">Post Link</a><div class="reply-content e-content"><p>我在看 Spike 最近的一期 <a href="https://taxodium.ink/43.html#82F4E24E-345E-48C9-9A3B-567A81BC40A0">Zine</a>，发现了一个很有趣的网页游戏~ 叫做 <a href="https://neal.fun/not-a-robot/"><em>I'm Not a Robot</em></a>。经历千辛万苦，虽然最后一关用的是作弊的方式过去的…… 不过我终于证明自己是个人类了（…… 咦？）！</p><p><img src="/posts/31df/imhuman.webp" alt="imhuman.png" loading="lazy"></p><p>为了让这变得更好笑，我把这个「证书」上传到我的领英账号上去了~</p></div><div class="reply-meta p-in-reply-to h-cite"><span class="reply-label">回复：</span><a class="reply-target u-url" href="https://taxodium.ink/43.html#82F4E24E-345E-48C9-9A3B-567A81BC40A0">https://taxodium.ink/43.html#82F4E24E-345E-48C9-9A3B-567A81BC40A0</a></div></div><p>其中有一关是在一张街景图片中找到正在接吻的情侣。我觉得很有意思，便截图下来发在 Instagram 的 Story 上，开现在人机测试有多么离谱的玩笑。</p><p>未曾想到，一个校友竟认为我发这个 Story 是因为我嫉妒「接吻的情侣」！我的天啊，到底是多么性饥渴的人，才会认为我是在表达对情侣的嫉妒和恨？</p><p>太恐怖了，过去我也遇到过类似的经历。我有一次说我要去睡觉，却让对方想到了性方面的内容。</p><h4 id="智力高的人并不比其他人更幸福"><a class="markdownIt-Anchor" href="#智力高的人并不比其他人更幸福"></a> 智力高的人并不比其他人更幸福</h4><p>近期阅读了 Adam Mastroianni 写的 <a href="https://www.theseedsofscience.pub/p/why-arent-smart-people-happier"><em>Why aren't smart people happier?</em></a>，重点探讨了 <strong>为什么智力高的人并不比其他人更幸福</strong>。心理学家普遍认为智力是一种广泛的心智能力，包括推理、计划、解决问题、抽象思维、快速学习和经验学习。按照这个定义，聪明人应该更擅长处理生活问题，从而更幸福。</p><p>然而，多项研究（包括英国的全国性调查和美国的社会调查）发现：智力与幸福之间的相关性非常微弱，甚至略为负相关。这意味着，高智商者并不比低智商者更快乐。</p><p>这里牵扯到多个问题：</p><ol><li><p>智力测验可能并不完全公平，受文化、经济和动机影响。即使测验能预测学业和职业表现，它仍无法预测一个人是否拥有「美好生活」。</p></li><li><p>Charles Spearman 提出「g 因子」（通用智力），认为人们在各种认知任务上的表现高度相关。Adam 则认为这忽略了问题的结构差异：智力测验只衡量「结构良好的问题」的解决能力。这里的 g 因子（general intelligence factor）指的是心理学中用于解释个体在各种认知任务中表现差异的核心概念，代表一种普遍的心智能力。</p></li><li><p>有两种问题：结构良好 vs. 结构模糊。</p><ul><li><p><strong>结构良好问题</strong>：有明确边界、稳定规则、可重复、可验证答案（如数学题、IQ 测验）。</p></li><li><p><strong>结构模糊问题</strong>：如「如何找到人生伴侣」、「如何养育孩子」、「如何过上好生活」，没有标准答案，因人而异。</p></li></ul><p>Adam 提出我们缺乏衡量「解决模糊问题的能力」的词汇，可能更接近「智慧」。解决模糊问题的能力才是幸福的关键。他以自己的祖母为例：虽然她不懂遥控器，却能经营一个充满爱的家庭，应对人生悲剧，做出完美的南瓜派。这种「生活智慧」不被智力测验衡量，却极其重要。</p></li><li><p>AI 擅长解决结构良好的问题（下棋、预测蛋白质折叠），但在模糊问题上仍无能为力。GPT 和 DALL・E 看似创造性，其实是在解决「预测下一个词 / 图像」的明确任务。</p></li></ol><p>Adam 的结论是，我们需要重新定义「聪明」。真正的聪明不仅是解题能力，更是选择正确问题、在模糊中前行的能力。他呼吁我们向那些擅长解决模糊问题的人学习，尤其是我们的祖母们。</p><details><summary>我的故事</summary><p>我认识这么一个「天才儿童」。虽然我认识她的方式令我痛苦、我也特别讨厌她，但是必须承认她的 IQ 已经高到一个恐怖的级别。凡是她看过的东西，她都能过目不忘，并且靠记忆完整地写下来。学习不同的技能对她而言实在是简单的不行，还未成年她就已经在哈佛大学教课，也被各个科技大厂主动发 offer。</p><p>不过她幸福吗？并不见得。她实际上患有严重的抑郁症以及自闭症，也在小时候经历过可怕的事情、患上了 PTSD。或许是自闭症的原因，她很难和人沟通，以至于几乎没有朋友。她的日常生活也很痛苦：对声音的极度敏感，仅是穿一件普通的衣服就会被摩擦声烦到要死。</p><p>在许多地方都能看出她「不智慧」的地方。作为一个一生傲慢的白人，她指责自己喜欢的女生不是和她一样的「白左」：<em>你们中国人屠杀并且奴役了很多黑人，你们要对黑人道歉！</em> 这种让人无力吐槽的对话，在她的生活里几乎比比皆是。</p><p>我讨厌她。她曾经毁了我的一段生活，也从未道歉过。我承认她是个聪明人，比我聪明太多了，但我还是会在这里骂她：<em>你就是个傻逼！</em></p></details><h4 id="不是在做那件事的事"><a class="markdownIt-Anchor" href="#不是在做那件事的事"></a> <a href="https://strangestloop.io/essays/things-that-arent-doing-the-thing">《不是在做那件事的事》</a></h4><blockquote><ul><li>准备去做那件事 —— 不是在做那件事。</li><li>安排时间去做那件事 —— 不是在做那件事。</li><li>为那件事列待办清单 —— 不是在做那件事。</li><li>告诉别人你要去做那件事 —— 不是在做那件事。</li><li>给朋友发消息，问他们是否在做那件事 —— 不是在做那件事。</li><li>写一条炸裂的推文，宣布你要去做那件事 —— 不是在做那件事。</li><li>因为没做那件事而责怪自己 —— 不是在做那件事。</li><li>因为别人已经做了那件事而责怪他们 —— 不是在做那件事。</li><li>因为阻碍你做那件事的障碍而生气 —— 不是在做那件事。</li><li>幻想一旦你做了那件事会得到多少赞美 —— 不是在做那件事。</li><li>阅读关于如何做那件事的文章 —— 不是在做那件事。</li><li>阅读别人是如何做那件事的故事 —— 不是在做那件事。</li><li>阅读这篇文章 —— 不是在做那件事。</li></ul><p><strong>唯一真正是在做那件事的，就是去做那件事。</strong></p></blockquote><h4 id="你是否陷入了电影逻辑"><a class="markdownIt-Anchor" href="#你是否陷入了电影逻辑"></a> <a href="https://usefulfictions.substack.com/p/are-you-stuck-in-movie-logic">《你是否陷入了电影逻辑？》</a></h4><p>作者 Cate Hall 提出了一个我一直都很赞同的观点：<em>为什么电影里的角色不能很好地沟通、不去直接说出问题，而是等到情节发展到无法被忽视为止？</em></p><p>当然，存在于现实生活中的我们知道，这是为了制造有效的冲突，不然我们来看电影是为了什么？不过这样的电影逻辑也会出现在现实中，甚至很多，因为就是有人遇到问题，不沟通也不主动解决。</p><p>通常来说，我们面对问题有四个阶段：</p><ol><li>没发现问题</li><li>发现问题</li><li>思考如何解决问题</li><li>解决问题</li></ol><p>而我认为大多数人都卡在了第二步或者第三步无法动弹：<em>如果我想的是错觉？会不会让对方以为我在自作多情？</em> 不，那不重要！因为很多时候提出问题给我们带来的第一个感受是「解脱」。</p><p>Hall 给了一些可以让我们的生活变得美好的例子：</p><blockquote><ul><li>「我注意到最近，每次我们计划单独见面，你都会邀请别人加入 —— 这是故意的吗？」</li><li>「我总觉得你周围有点不自在，我担心这会让你觉得我不喜欢你 —— 我只是想说事实并非如此。」</li><li>「我能感觉到我们之间弥漫着一种低度紧张，好像我们在心里互相有些不悦，但又努力保持礼貌。只有我这么觉得吗？」</li><li>「有时我觉得，当我在会议中提出反对意见时，会改变房间里的气氛 —— 好像你们不敢像对待其他人那样直接地与我交流。你觉得是这样吗？」</li></ul></blockquote><p>Hall 也提到，人们很少这么说话。她认为原因有二：</p><ol><li>误把沉默当做是明智的外交</li><li>担心让别人觉得你在小题大做</li></ol><p>问题提出或者不提出，都是会真实存在、并对我们造成影响。不过如果用力过猛，我们就会变成那群「急着给问题下定义的讨厌鬼」。那我们应该继续沉默吗？不是的，我们应该更灵活地去思考：</p><ol><li>提出这个问题是否必要？是会改善这段人际关系，还是会变得更糟？</li><li>当你觉得无法直接说出问题时，其实这本身就是一个问题，可以直接把「说不出来」作为对话的切入点</li><li>即使你还不完全理解问题，也可以先把「直觉」或者「感觉」说出来。这本身也是一种沟通方式，可以让别人参与进来，一起澄清问题</li></ol><p>偶尔的沉默也并不致命，有时还可以避免冲突、自然地缓和情绪。不过长期靠沉默来解决问题的话，会让人们陷入到自我安慰的虚假世界，失去真实感和成长机会。</p><h4 id="或许你其实并没有真正努力"><a class="markdownIt-Anchor" href="#或许你其实并没有真正努力"></a> <a href="https://usefulfictions.substack.com/p/maybe-youre-not-actually-trying">《或许你其实并没有真正努力》</a></h4><p>这也是 Hall 写的。她被一个网络跟踪狂骚扰数年，并发现对方逐渐得寸进尺，不仅要从印度找到美国来伤害她，还伪造了绑架信息向她的家人勒索钱财。Hall 承认，当时的她内心虽然想要解决这件事，但实际上她选择了忽视、认为怎么做都无法阻止这个跟踪狂，直到丈夫的介入。他所采取的策略并不复杂：联系 FBI、美国驻印度领事馆以及当地警方，然后事情便解决了。</p><p>Hall 意外的是，自己若处理别人的类似情况也会想到这样的解决方案，但为什么当时的自己没有这么做？</p><blockquote><p>「为什么直到另一个人介入，我才意识到自己并没有真正地『尽力』？」</p></blockquote><p>Hall 的解释是这样的：最初遇到这件事时，她处于一个低能量、低资源的状态，忽视这个跟踪狂是当时的她所能想到的唯一的办法。这也形成了一个固定的应对模式：就算她后续能力提升了，也会默认这件事只能这么处理、没有其他更好的法子。</p><p><strong>人并不是整体高能或者低能的，而是选择性能动</strong>。一个人，他在工作上可以极具创造力和坚持，却也可以在人际关系上停留在青少年式的应对水平。Hall 也发现，人们在至少一个领域停留在早期发展阶段似乎是一种规则。我们在生活的某个领域并没有真正在努力。</p><p>努力不代表真正地在尝试。依靠意志力的挣扎会让人们误以为自己在努力，但其实并没有，我们还有更多的资源可以使用呢。</p><p>Hall 在文章的最后说道：</p><blockquote><p>「我建议你假定生活的某个领域，你在不知不觉中停滞不前，而找到这个领域非常重要。审视你生活的三个舞台：工作、人际关系和自我关系，并注意你面临的最大问题。</p><p>「要知道，你可能在寻找一些并非感觉像问题的东西 —— 它可能只感觉像是悲伤或愤怒，比如不被看见的悲伤，或者感觉工作没有意义的沮丧。</p><p>「一旦你浮现出某些东西，问问自己：我是否尽我所能，利用我所有的资源，想出了一系列可能的解决方案？我对待自己，是否和我对待任何带着同样问题来找我的朋友一样好？我怎么知道我真的在努力？」</p></blockquote><details><summary>我的故事</summary><p>这篇文章不仅让我看到了我身边的许多人，也让我看到了自己。我在许多许多事情上都做过「假努力」，或者单纯就是在忍受，无论是过去家人对我的暴力，还是之后其他人对我的利用、冒犯……</p><p>很多时候我都认为：「这件事只能这样了。我没有办法解决，这是一个死胡同，就这样吧。」但实际上，这又何尝不是一种停滞？我放弃了，我没有努力去改善，任由这些人持续性地伤害我。</p></details><h4 id="what-about-和比烂"><a class="markdownIt-Anchor" href="#what-about-和比烂"></a> <a href="/posts/dfa8.html">《What About…… 和比烂》</a></h4><p>我在网上冲浪时刷到一个吐槽美国学校作业多的帖子，发现了一个评论：<em>为什么大家什么都要和国内比？为什么要比较彼此谁更不幸呢？</em></p><h4 id="我在谈论共情他们在谈论逻辑"><a class="markdownIt-Anchor" href="#我在谈论共情他们在谈论逻辑"></a> <a href="/posts/d4e5.html">《我在谈论共情，他们在谈论逻辑》</a></h4><p>还是我写的一些碎碎念。网络一个很大的问题在于，评论发了就是发了，不同人看到的实际内容都不同。对方说的是错的吗？那肯定不是，这世上怎么会有对的或者错的评论呢？所以这篇更像是我生气了、解析自己为什么生气。</p><h4 id="童年玩伴而非母亲塑造依恋风格最深"><a class="markdownIt-Anchor" href="#童年玩伴而非母亲塑造依恋风格最深"></a> <a href="https://nautil.us/childhood-friends-not-moms-shape-attachment-styles-most-1247316/">《童年玩伴，而非母亲，塑造依恋风格最深》</a></h4><p>传统观点都认为父母的关系会决定孩子们成年后的依恋模式。作者 Kristen French 则认为，童年友谊要更深刻地塑造成年依恋风格。他给出了一些研究作为证据，其中的关键发现为：</p><ul><li>和母亲的关系确实会影响成年后的依恋风格，但是只解释了约 2-3% 的差异</li><li>和父亲的关系影响甚微</li><li>和童年玩伴的关系影响最大，解释了成年依恋焦虑的约 4%，以及依恋回避的 10-11%</li></ul><p>French 表示，高质量的童年友谊会让我们成年后在浪漫关系和友谊中更安全、稳定。</p><p>不过这个论点也被一些读者质疑：</p><ul><li>研究样本都是美国的中产家庭，无法代表更广泛的文化和社会背景</li><li>母亲关系解释的差异只有 2-3%，友谊解释的差异也只有 4-11%，属于弱效应，不应该过度解读</li><li>虽然研究追踪了 15 年，但依然可能遗漏环境变量</li></ul><p>关于「我们是如何被塑造的」这一话题，实际答案实在是太复杂了。我认为不能就这么简单地给出结论，并用于所有人身上。</p><h4 id="我父亲去世后我们找到了那些情书"><a class="markdownIt-Anchor" href="#我父亲去世后我们找到了那些情书"></a> <a href="https://www.jenn.site/after-my-dad-died-we-found-the-love-letters/">《我父亲去世后，我们找到了那些情书》</a></h4><p>作者 Jenn 的父亲去世后，她在遗物里发现了父亲隐藏起来的情书：原以为沉闷的父亲竟有一位维持了三年恋情的男性伴侣。这些情书上展示出了父亲温柔、幽默、充满激情的一面，让 Jenn 感到陌生。更为惊讶的是，Jenn 也是一位同性恋者，曾向父亲出柜过。当时的父亲给予了她支持与理解，但是他自己却在柜子待了整整四十多年。</p><p>这是一场彻头彻尾的悲剧。传统与家庭的压力下，父亲无法公开真实的自我。他的一生大部分时间都是压抑和痛苦的，直到最后三年才获得幸福。正如母亲在文章中所说的：</p><blockquote><p>「他浪费了他的一生。」</p></blockquote><p>母亲与父亲的婚姻并非出于爱情，而是被迫结合。家庭的关系长期处于紧张状态，以至于父亲一直都在缺席孩子的成长，错过了毕业、生日等重要时刻。他的秘密生活也让家庭破碎，甚至在死后仍带来冲突。母亲的那句话还有后续：</p><blockquote><p>「他的一生，也包括我的一生。」</p></blockquote><p>悲剧不仅仅是个人的选择，还是社会结构的产物。传统文化和社会期待逼迫着父亲成为了那个「大家长」，必须去维持表面的婚姻和家庭。但是这样的话，谁都得不到幸福。<strong>只是为了变成他人眼里的「普遍」，毁掉不光是自己的、还有其他人的一辈子，真的值得吗？</strong></p><p>对于 Jenn 而言，最可惜的莫过于她原本可以理解父亲、了解父亲。但因为死亡，她再也无法同父亲展开这些对话。</p><p>节哀顺变。希望世界上不再有这样的悲剧。</p><h2 id="技术与创造-2"><a class="markdownIt-Anchor" href="#技术与创造-2"></a> 技术与创造</h2><h4 id="博客折腾"><a class="markdownIt-Anchor" href="#博客折腾"></a> 博客折腾</h4><ul><li><p>这次依然对月刊的内容进行了一次结构重整。原先结构的问题有二：</p><ol><li>太长了不好读；</li><li>内容分类太细碎。</li></ol><p>于是我新添加了一个导读，可以让读者快速得知本期文章大概都有什么，也可以快速抵达他们想看的内容。因为导读里的标题可以随意写，所有我也可以用来提出一些主题。这样读者就不需要完全照着原文的思路去思考这些主题。</p><p>再就是板块的重组，把一些板块合并了、又或者是稍微地挪动了一些板块……</p><p>如果有什么建议的话，随时欢迎给我发邮件，我会很感动的~</p></li><li><p>我为该分类文章的标题做了一个 <a href="https://mng.cytrogen.icu/">随机生成器</a>，可以生成年份的干支和月份的雅称。收集雅称的期间，我很惊讶一个月份的雅称能有这么多个，也很佩服古人在这方面的审美，很多雅称听上去实在是太漂亮了。</p></li><li><p>把博客网站的默认主题改成了暗黑。之前不知道是什么问题，我每次刷新页面都会先显示亮主题，再刷回暗黑主题，看着实在是让人恼火。后来想了想，我自己都不用亮主题，为什么要把默认主题设置成亮主题呢？如果你用的是亮主题，会遇到刷新页面时先显示暗黑主题、再显示亮主题的情况。我认为这样的话不会太伤眼睛。</p></li><li><p>给粗体添加了下方显示一行点状装饰线的效果，比以前只改 <code>fontWeight</code> 而言看起来更突出了。</p></li><li><p>给网站加了个 Source Han Sans 字体来处理代码块里的中文以及日文字符。我没找到简体中文的 Source Han Code，只能先用 Source Han Sans。之后再找更好的替代品。</p></li></ul><h4 id="人工智能浏览器入场费太高"><a class="markdownIt-Anchor" href="#人工智能浏览器入场费太高"></a> <a href="https://vivaldi.com/blog/a-i-browsers-the-price-of-admission-is-too-high/">《「人工智能」浏览器：入场费太高》</a></h4><p>作者 Bruce Lawson 是 Vivaldi 浏览器团队的成员，在文章里表达了他对最近的 AI 浏览器的担忧：这些产品的设计初衷不是为了帮助用户浏览 Web，而是把用户困在 AI 生成的「围墙花园」里。假设用户输入关键词「Taylor Swift」，AI 浏览器返回的是生成的回答，而不是 Taylor Swift 的网站。<strong>这些 AI 的回答又往往不准确、会被各类虚假宣传和错误信息所影响。</strong></p><p>先前提到，Meta 作为唯一一个通过 AI 技术赚钱的科技巨头，靠的是驱动广告排名。其他公司实际也发现，AI 可以用于盈利的地方，就是广告业务，而 AI 浏览器被推出的目的便是投放更精确的广告。通过收集用户的输入、浏览行为，一个更为详细的用户画像便会被建立，意味着更容易吸引我们点击、购买的广告会愈来愈多。这一点同样适用于现在的 AI 聊天工具，用户分享给 AI 的私密信息数据缺乏法律保护，具有被 AI 背后的公司滥用的风险。</p><p>AI 浏览器的安全风险也是一个大问题：代理功能可以直接操作用户的浏览器标签，也可以被隐藏提示诱导、执行删除行为。</p><p>最后 Lawson 还推荐了一下自家的 Vivaldi 浏览器，表示如果用户实在是想要使用 AI，可以在 Vivaldi 的 Web 面板里使用：它是一个沙盒环境，与其他选项卡隔离，也不受任何浏览器供应商的 LLM 或搜索的束缚。我认为这也是一种有意思的立场：<strong>不完全否认 AI，重点是要把数据和体验的掌控权还给用户。</strong></p><details><summary>我的故事</summary><p>我有段时间会去学校附近的那家兰州牛肉面馆买肉夹馍带回家。店里的员工十分松弛，我会坐在角落看着他们慢慢地微波我的馍……</p><p>不过我注意到，他们原本用来展示菜单的显示屏现在开始循环播放 AI 动画。</p><p>哪里都是 AI…… 谷歌地图上内置了 AI 问我要不要了解这些地点、Edge 浏览器上内置了 AI 说可以直接问它问题，就连家附近的奶昔店的海报都是 AI 画的食物。</p><p>浏览器是一个很私密的东西，我们身边的软件、生活的点点滴滴也是。但现在的感觉是，无论线上还是线下，我们都正逐渐被困进一个由 AI 生成的巨大「围墙花园」里。</p></details><h4 id="在-ai-恐慌的时代熟练度是一种累赘"><a class="markdownIt-Anchor" href="#在-ai-恐慌的时代熟练度是一种累赘"></a> <a href="/posts/d38e.html">《在 AI 恐慌的时代，熟练度是一种累赘》</a></h4><p>近日我在一项限时一小时的小组作业里被教授控诉使用 AI 且不承认，而她的理由让我大跌眼镜。这是我写的一篇文章，记录我的感想。</p><p>后续是她「不再和我纠缠 AI 使用」，但是认为我们的作业依然没有达到她的要求，也就是没有写测试等。不过她「大发慈悲」决定给我们部分分数：只有在这个作业的分数可以改变我们的最终成绩（如从 D 变成 C），她才给我们算分。</p><p>我是蛮傻眼了。我已经说过了我有爬虫的经验，她非要继续和我在「是否有记录过程」一事上闹。我觉得我已经把想要记录的内容都记录了下来，莫名其妙的形式主义有什么意义吗？</p><p>更为可悲的是这个决定是她和课程负责人以及系主任一同商量得出的结果：整个部门都认同这套形式主义以及强迫学生使用 AI 的做法。我就纳闷了，你课上讲的内容不完整就算了，你是不是可以把作业设计的只会出现你教过的内容？为什么非要在作业里添加你没有教过的地方，然后强迫学生们使用 AI 呢？</p><h4 id="typora-和-hexo-的完美工作流"><a class="markdownIt-Anchor" href="#typora-和-hexo-的完美工作流"></a> <a href="/posts/96d8.html">《Typora 和 Hexo 的完美工作流》</a></h4><p>我写的一篇有关 Typora 和 Hexo 如何配合、实现「所见即所得」的博客图片工作流的文章。</p><h4 id="web-动画性能分级体系"><a class="markdownIt-Anchor" href="#web-动画性能分级体系"></a> <a href="https://motion.dev/blog/web-animation-performance-tier-list">《Web 动画性能分级体系》</a></h4><p>作者 Matt Perry 在他的文章里提到，Web 动画虽然常常让 UI 更生动，但要是性能不好，反而会让体验卡顿甚至有害。他希望可以通过一个性能分级体系，让开发者可以快速判断不同动画技术的代价和适用场景。原文里有一些举例用的 Web 动画，推荐直接看原文。</p><h4 id="github-已经停止使用-toasts"><a class="markdownIt-Anchor" href="#github-已经停止使用-toasts"></a> <a href="https://primer.style/accessibility/toasts/">GitHub 已经停止使用 Toasts</a></h4><p>Toasts 是小型矩形通知，通常出现在视口的角落，自动消失。GitHub 已经停止使用 Toasts，因为它们存在严重的可访问性与可用性问题：</p><ol><li>自动消失，用户可能来不及阅读，也无法回顾信息</li><li>在 DOM 中的位置不合理，屏幕阅读器难以理解</li><li>通常只考虑鼠标点击，缺少键盘焦点管理和可操作性</li><li>没有正确使用 <code>aria-live</code> 或者 <code>role="status"</code> 的话，辅助技术无法感知</li><li>字体缩放可能导致遮挡或溢出</li><li>焦点顺序混乱</li><li>代码不一致，影响识别</li><li>大屏幕下可能出现在视野之外</li><li>浮动在底部角落，可能挡住按钮</li><li>被过度使用的话，用户会倾向忽略</li><li>如果与触发操作距离过远，用户难以理解关联</li><li>按 Esc 可能误关 Toasts 或者其他 UI</li></ol><p>更好的替代品是 Banner、Dialog 或者确认页这些更持久、可控的反馈方式。</p><p>我有一个项目就用到了 Toasts，后来我仿照 AWS 仪表盘里的 Banner 重写了一套通知系统。</p><h4 id="无人永生迎来-25-周年但你仍然无法合法购买它"><a class="markdownIt-Anchor" href="#无人永生迎来-25-周年但你仍然无法合法购买它"></a> <a href="https://www.techdirt.com/2025/11/13/no-one-lives-forever-turns-25-you-still-cant-buy-it-legitimately/">《「无人永生」迎来 25 周年，但你仍然无法合法购买它》</a></h4><p>「无人永生」是一款经典的间谍射击游戏，至今已 25 周年。尽管玩家群体仍然怀念它，但游戏仍无法合法购买。原因为下：</p><ul><li>游戏版权因多次并购、公司关闭和权利转移而陷入混乱</li><li>没有人能明确证明自己拥有完整权利</li><li>相关合同早于数字化存档时代，文件可能遗失在档案库或纸质箱中</li><li>当 Nightdive Studios 尝试重制并申请商标时，有三家公司都声称可能拥有部分权利，并威胁诉讼</li></ul><p>现在这款游戏没有在任何平台合法出售，玩家们只能通过非官方渠道下载「改良版」，也就是通过社区修改以适配 Windows 10 / 11 和宽屏的版本。甚至在 GOG 的「Dreamlist」上，足足有超过 87000 人表示愿意购买，但是权利方无意解决问题。</p><p>这是「弃置软件」的典型案例。游戏被作为文化遗产被遗忘，但是潜在权利方却阻止任何合法重制。作者 Timothy Geigner 认为，这违背了版权的初衷：既不保护创作者，也不让公众受益。<strong>如果公司既不出售也不明确权属，就不应阻止公众获取。</strong></p><h4 id="小型开源项目的命运"><a class="markdownIt-Anchor" href="#小型开源项目的命运"></a> <a href="https://nolanlawson.com/2025/11/16/the-fate-of-small-open-source/">《「小型」开源项目的命运》</a></h4><p>作者 Nolan Lawson 以自己开发的 <code>blob-util</code> 为例指出，随着 Node.js 内置功能的扩展以及约八成开发者日常使用 AI 生成代码，许多微型工具库已不再必要。过去这些库不仅解决问题，还承担教育作用，帮助开发者理解底层机制。而如今，AI 提供即时答案却削弱了学习过程。</p><p>Lawson 认为，这意味着小型、低价值的开源项目正逐渐消亡，但真正有价值的仍在于大型、创新或需要原创研究的项目，也就是那些 AI 无法轻易复制的东西。</p><h4 id="无需-javascript-的-llm-爬虫阻挡方法"><a class="markdownIt-Anchor" href="#无需-javascript-的-llm-爬虫阻挡方法"></a> <a href="https://www.owl.is/blogg/blocking-crawlers-without-javascript/?v">《无需 JavaScript 的 LLM 爬虫阻挡方法》</a></h4><p>这几个月来，一直都有博客站主反映自己的网站在被 LLM 爬虫机器人攻击。作者 Uggla 的防御方案是在网站上人为创建一个特殊路径，例如 <code>/heck-off/</code>，并在 <code>robots.txt</code> 中明确禁止爬取该路径。合规的搜索引擎会遵守规则，不会访问；违规爬虫则可能会跟随。</p><p>具体实现是这样的：对于无 Cookie 的请求，服务器直接返回一个页面，其中包含一个隐藏的链接指向那个特殊的路径、一个 <code>&lt;meta http-equiv=refresh&gt;</code> 标签来跳转到验证路径 <code>/validate/</code>。如果是低质量的爬虫，那就会点击隐藏链接，而不是遵循跳转。</p><p>这时候会发生两件事：</p><ul><li>如果访问特殊路径：<ul><li>检查 <code>Referer</code>，如果符合条件，那就设置 <code>Set-Cookie: slop=1</code></li><li>后续请求如果带有 <code>slop</code> Cookie，那就阻止访问</li></ul></li><li>如果访问验证路径：<ul><li>检查 <code>Referer</code>，如果符合条件，设置 <code>Set-Cookie: validated=1</code></li><li>后续请求如果带有 <code>validated</code> Cookie，那就允许访问</li></ul></li></ul><p>想要避免浏览器陷入重定向循环的话，可以在这些中间页面上设置 <code>Cache-Control: no-cache, no-store, must-revalidate</code>。</p><p>不过这个方法有一点问题：如果不把 RSS Feed 链接作为例外的话，Feed 阅读器会无法订阅你的博客。我建议大家都可以用 Feed 阅读器订阅一下自己的博客，看看会是什么效果。</p><h4 id="互联网不再是一个安全的避风港"><a class="markdownIt-Anchor" href="#互联网不再是一个安全的避风港"></a> <a href="https://brainbaking.com/post/2025/10/the-internet-is-no-longer-a-safe-haven/">《互联网不再是一个安全的避风港》</a></h4><p>作者 Wouter Groeneveld 的个人网站遭遇 AI 爬虫攻击的经历：大量伪装成正常浏览器的请求涌入，导致服务器资源被耗尽，迫使他采取封锁整段 IP 的极端措施。</p><p>Groeneveld 指出，这类爬虫不仅破坏了环境和创作者的热情，也侵蚀了批判性思维。同时，去中心化的小型服务器爱好者因频繁攻击而被迫迁移到大型平台，进一步加剧互联网的集中化。</p><p>他在文章里哀叹道：</p><blockquote><p>「互联网不再是软件爱好者的安全港。」</p></blockquote><h4 id="个人博客又回来了利基博客是不是也该复兴了"><a class="markdownIt-Anchor" href="#个人博客又回来了利基博客是不是也该复兴了"></a> <a href="https://disassociated.com/personal-blogs-back-niche-blogs-next/">《个人博客又回来了，利基博客是不是也该复兴了？》</a></h4><p>博客的黄金时代时，网上充满了各种主题的博客，个人博客与商业博客并存。博客对于大家来说，可以是赚钱的工具，也可以是传达影响力的平台。</p><p>那么什么是利基博客呢？这类博客的特点是只聚焦于一个主题，作者往往被视为该领域的专家。</p><p>虽然现在这个社交媒体和网红都取代了博客的时代，只有一小部分博客能够维持生计，但是 IndieWeb 和 SmallWeb 社区推动了个人网站的复兴。个人博客堂堂回归，它们多数是非商业化的、强调独立性和自我表达。</p><p>作者 John Lampard 认为，在个人博客复兴的同时，应该也推动利基博客的回归。我们的互联网世界需要高质量、主题聚焦的资源，以对抗社交媒体的错误信息、搜索引擎的 AI 摘要，以及各种各样的 AI 垃圾。不过他也认为，广告泛滥的博客可以不要回归（笑），以往的强制订阅模式也可以被淘汰掉。</p><p>评论区有一个虽然读起来有些偏激，但蛮有意思的「假名言」：</p><blockquote><p>「那些为了获得短暂的便利而放弃基本自由来决定追随谁的人，不配选择读什么，也不配获得便利。」</p></blockquote><h4 id="ai-对这段代码的工作原理有非常深刻的理解"><a class="markdownIt-Anchor" href="#ai-对这段代码的工作原理有非常深刻的理解"></a> AI 对这段代码的工作原理有非常深刻的理解！</h4><p>OCaml 是一个多范式的编程语言，常用于编辑器、金融系统和高效性能。而在十一月十九日，OCaml 的 GitHub 仓库里出现了一个让人哭笑不得的 <a href="https://github.com/ocaml/ocaml/pull/14369">PR</a>：整整一万三行代码修改。</p><p>但是这些文件头里出现的署名并不是该 PR 的发起者，让人怀疑这个 PR 的发起者是否存在抄袭或者错误署名。成员 yallop 甚至在代码里发现了 Claude 的署名。</p><p>「作者」joelreymont 直接承认代码由 AI 生成：Claude 写、ChatGPT 审查是否有问题，Claude 又去解决这些问题。他认为自己是 AI 的「牧羊人」，全程没有写任何代码。</p><p>成员 gasche 强烈反对这种贡献方式：</p><ul><li>AI 生成的代码却署名了真实人类</li><li>缺乏设计讨论，直接丢上来如此庞大的 PR</li><li>代码量庞大、测试不足、维护负担重</li><li>AI 生成的代码难以审查，可能拖垮 PR 系统</li><li>这也不是 joelreymont 第一次在 OCaml 贡献大 PR，实在是浪费维护者们的时间</li></ul><p>作为回应，joelreymont 先放上来了一个 AI 生成的版权分析，接着反驳道：</p><blockquote><p>「AI 对这段代码的工作原理有非常深刻的理解！它能告诉我，它需要跟踪跨寄存器移动的局部变量，以便添加足够的 DWARF 信息来显示变量。我拥有 Codex 审查 Claude 的完整会话日志，而且见解非常深刻！」</p></blockquote><p>成员 dra27 则反驳了 joelreymont，表示 LLM 并没有「理解」，它们只是在生成而已。不要去误解 AI 的本质。但是 joelreymont 依然认为，AI 生成的代码并没有比人类写的代码要差、可能比 dra27 自己写的还要好，并且这一套代码可以用、写得好、通过了测试，值得肯定。</p><p>当 yallop 再次询问 joelreymont 为什么要在提交的文件里署名其他人后，joelreymont 的回答是：</p><blockquote><p>「天知道。AI 决定这样做，我也没有质疑它。」</p></blockquote><p>这是整个事件最可笑的地方。joelreymont 之前还说「AI 深刻理解代码」，结果连为什么作者名字写错了都不知道，还承认自己完全没过脑子、盲目信任 AI。</p><p>部分网友认为，有些人因为有了 AI，就觉得自己无所不能，产生了一种毫无根据的自信，完全丧失了对技术复杂度的敬畏。不过也有人反驳了这一点：在没有事先讨论的情况下、把一大堆代码丢给维护者才是问题所在，但如果只是想分享能跑的代码，这算「脑子坏掉」吗？</p><p>我不认为用 AI 写代码是一种「罪」，靠着捷径成功并且因此变得傲慢才是罪。</p><h4 id="有趣项目"><a class="markdownIt-Anchor" href="#有趣项目"></a> 有趣项目</h4><ul><li><p><a href="https://github.com/dnlzro/horizon">horizon</a></p><p>一个很有意思的项目：根据用户的近似位置，实时渲染天空为 CSS 渐变。刷新机制利用的是 HTML 的 <code>meta http-equiv="Refresh"</code> 标签，实在是鲜为人知。</p></li><li><p><a href="https://watilde.github.io/KokoScript/">KotoScript</a></p><p>很神奇的东西，用日语来写 JavaScript。</p><p>根据官网，这样的 KotoScript：</p><pre><code class="language-plaintext">変数、名前は「太郎」。変数、年齢は25。「こんにちは、」と名前と「さん！」を表示。もし、年齢が18より大きいならば、  「あなたは成人です」を表示。そうでなければ、  「あなたは未成年です」を表示。終わり。</code></pre><p>等同于这样的 JavaScript：</p><pre><code class="language-javascript">let 名前 = "太郎";let 年齢 = 25;console.log("こんにちは、" + 名前 + "さん！");if (年齢 &gt; 18) {  console.log("あなたは成人です");} else {  console.log("あなたは未成年です");}</code></pre><p>结果都是：</p><pre><code class="language-plaintext">こんにちは、太郎さん！あなたは成人です</code></pre><p>实在不知道这个项目是更适合会 JavaScript 的人去学日语，还是会日语的人去学 JavaScript。</p></li><li><p><a href="https://clocks.brianmoore.com/">AI World Clocks</a></p><p>一个每分钟都会展示由 9 个不同的 AI 模型实时生成的模拟时钟的网站。</p></li><li><p><a href="https://stickertop.art/">stickertop.art</a></p><p>一个收录笔记本电脑贴纸的网站。</p><p>下图红框内的是我的笔记本电脑。上面不只是各种各样科技相关的贴纸，还有一些申请大学时他们给我的、购买一些产品时送的，以及最中间那个由我和我室友设计的贴纸。</p><p><img src="/posts/31df/stickers.webp" alt="stickers.png" loading="lazy"></p></li></ul><h2 id="生活与文娱-2"><a class="markdownIt-Anchor" href="#生活与文娱-2"></a> 生活与文娱</h2><h4 id="书影音"><a class="markdownIt-Anchor" href="#书影音"></a> 书影音</h4><ul><li><p>书籍</p><ul><li><p>漫画也是书，我是这么想的。总之我重温了以前没追完的《实况主的逃脱游戏》。看到了最精彩的地方，作者却在五年前就不更了（五年前是 2020 年这件事也让我很吃惊）！</p><p>推特上作者的账号在两年前发了一些最新话的草稿。但是都两年了，恐怕也很难再看到后续了。</p></li><li><p>我看了《毁掉一切地狱再爱》这本漫画。我很喜欢作者画的女主吉泽来未，很可爱。想要讲述的主题、多方人物的冲突和互动都很有意思，是我个人近期很喜欢看的百合题材作品。</p><p><em>什么时候应该主动进入到其他人的世界里？是否应该替其他人作出决定？</em> 我认为是我们处理人际关系上的几道大难题。而引出这个主题的角色心，对我而言既视感很重、会让我想起现实生活中的一些人，实在是毛骨悚然。</p></li></ul></li><li><p>影视</p><ul><li><p>吃饭的时候跟室友一起看《野原广志 午餐的流派》。</p><p>整个片节省的不可思议，以至于无法用太高的标准去看待它。不过意外的很有意思，配合弹幕看更好笑了。</p><p>片头曲和片尾曲很好听，我更喜欢片尾曲。放片尾曲的时候，中间有一段「假广志」接电话、被骂一顿、挂断电话垂头丧气的动画，不知道为什么我很中意，感觉很好哭……</p></li><li><p>《野原广志 午餐的流派》没更新的时候，跟室友一起吃饭看的是《蜡笔小新》，好像是第十三季的日配。</p><p>真的很难把正片的广志和外传里的广志想象成同一个人…… 所以我会称呼后者为「假广志」。</p></li><li><p>重温了《异度侵入 ID:INVADED》，很好看。我认为结尾可以做得更好些。</p></li><li><p><a href="https://www.bilibili.com/video/BV1z6szzREbN">《【中字】电子游戏如何塑造南梁群体》</a></p><p>作者 the poopie show 用很可爱的小动画讲述了「男娘」（femboy）的历史。视频里作者提出：「自从可爱的东西问世以来，即使是男的也想拥有。」是啊，为什么世间要这么抗拒男性去变可爱呢？</p></li><li><p>我重温了一下《疯狂动物城》第一季。第一次看的时候我刚来美国不久，那会儿看的还是枪版。现在看来整个故事的节奏依旧很不错，动物角色的模型也非常可爱。这次重温也让我发现了多个细节，例如主角朱迪有很多镜头会出现动鼻子的微动作，和现实中的兔子很像。</p></li></ul></li><li><p>音乐</p><p>这一个月我貌似变得急躁了许多，不乐意去专心听音乐。有些音乐我现在并没有认真去「倾听」它，让我感觉这样对音乐很不公平。我会在未来平静下来的时候，再把听它们时的感觉记录下来。</p><ul><li><p>我喜欢赵雷的歌，这个月一直在听他的两个专辑：《无法长大》和《署前街少年》。我个人更喜欢前者一点，打工的时候还悄咪咪地在店里的手机上循环播放；后者我最喜欢的是《我记得》这首歌。</p><blockquote><p><em>呜快来抱抱，快来抱抱我……</em></p></blockquote><p>这样的歌词意外地很戳我呢！</p></li><li><div class="reply-block h-entry"><div class="post-meta p-author h-card visually-hidden"><img class="u-photo" src="https://blog.cytrogen.icu/favicon.png" alt="Cytrogen" loading="lazy"><span class="p-name">Cytrogen</span><a class="u-url" href="https://blog.cytrogen.icu">https://blog.cytrogen.icu</a></div><time class="dt-published visually-hidden" datetime="2026-09-17T20:47:54.613Z">2026-09-17T20:47:54.613Z</time><a class="u-url visually-hidden" href="https://blog.cytrogen.icu">Post Link</a><div class="reply-content e-content"><p>Spike 给我推荐了许多乐队。我目前还没听完，暂时是「耳福不愁」了：</p><ul><li><p>窦靖童的两个专辑非常适合做事情的时候听，很 chill。</p></li><li><p>海豚刑警的歌曲很神秘：我一直都没有仔细去听他们的歌词，只是觉得貌似听不懂？直到我看了一眼歌词：</p><blockquote><p><em>地上右边指往台北，</em></p><p><em>我想往左边，</em></p><p><em>但明明左边也是台北。</em></p><p><em>怎么还是台北？</em></p><p><em>怎么到哪里都是台北？</em></p><p><em>我不要台北！</em></p></blockquote><p>像这样无厘头的歌词还有很多，我认为是一种很独特的风格。</p><p>室友很喜欢听海豚刑警的歌，会自己偷偷放着听。</p></li></ul><p>他的网站里有一面 <a href="https://taxodium.ink/album-wall.html">Album 墙</a>，感兴趣的可以看看~</p></div><div class="reply-meta p-in-reply-to h-cite"><span class="reply-label">回复：</span><a class="reply-target u-url" href="https://taxodium.ink/album-wall.html">https://taxodium.ink/album-wall.html</a></div></div></li></ul></li></ul><h4 id="日记片段"><a class="markdownIt-Anchor" href="#日记片段"></a> 日记片段</h4><p>我现在会把日记片段用 <code>&lt;details&gt;</code> 折叠起来。感兴趣的话就来看看吧~</p><details><summary>十月十五日</summary><p>阅读 <a href="https://blog.ursb.me/tags/weekly/">Airing 的月刊</a>，他有 <a href="https://blog.ursb.me/posts/weekly-6/">一期</a> 聊的是非暴力沟通和沟通的艺术。我阅读了一下，意识到沟通是十分复杂的。根据沟通的目的，一些我们普遍认为不好的沟通反而可能很有效。</p><p>依然是 Airing 的月刊，他讲到了 <a href="https://blog.ursb.me/posts/weekly-21/">好奇心和互联网</a>。现在互联网这么发达，大家却都没有变开心。</p><p>我认为人类普遍对信息上瘾，但是接收太多信息，很多时候并不是一件多么美好的事情。我们会沉沦下去，却 <strong>什么都没有记住、学会</strong>。这也是为什么我没有看短视频的习惯，我从来都没有用过抖音、快手这类广为人知的短视频平台代表。</p><p>不过呢，我还是看过短视频的。不得不说，短视频功能嵌入到各类应用里实在是防不胜防。我当时看得最多的是 Instagram 的 Reels。刚进大学时对 Instagram 很感兴趣，因为它的交友性质很强，再就是那段时间我「被迫」社交、必须跟着身边人的潮流来。之后我意识到这类 app 的信息茧房实在是可怕，总是在播放一样的东西，很快便厌倦、不看了。</p></details><details><summary>十一月二日</summary><p>这是美国东部大家都不约而同期待的一天：所有的钟表往前拨一个小时。这天凌晨，我体验了两次一点，也就是说我多了一个小时。我在这多出的一个小时里编辑好了博客文章、发布了出去，哈哈哈哈，实在是太高兴了。</p><p>不过呢，现在有多高兴，夏令时到来时就会有多难过。</p><p>今天要上班，醒来的时候未曾想 Spike 给我发了个邮件。这种感觉很难形容，大致是感动吧！有人会喜欢我的文章内容。</p><p>没什么客人，好无聊。我趁这个空档重新学起了双拼。突然觉得没那么难接受了，是不是一些东西得丢掉再捡起才行？我买了茂林源记的新 DLC 玩，也是想要再捡起来玩玩~</p><p>万圣节的那个黑人又来了…… 但是罐子里只有两枚硬币就没了，他看了一眼后便跑了出去。</p><hr><p>下班后去看了 <a href="https://space.bilibili.com/8730238">小熊 flippy</a> 的一次直播录像，游戏内容是台湾邪教。</p><p>美国这个「宗教自由」的地方有时也可以见到邪教，比如以「世界末日」为主的东方闪电、完全遵循旧约而生活的耶和华见证人，甚至是法轮功。</p><p>我的母亲曾经遇到过东方闪电的信徒。对方当时给她各种问候、送吃的，说的话倒是很可怕：<em>世界很快就会末日！今年又冷了、这里火山爆发了、那里狂风大作……</em></p><p>耶和华见证人在繁忙的华人区内还能看到教堂存在…… 实在是不想靠近。</p><p>至于法轮功，那可是无处不在：华人区能见到他们摆小摊、我家楼下可以看见他们在练气功、每过一段时间就会在华人区大搞游行。</p></details><details><summary>十一月三日</summary><p>下课口渴，去学校附近的 Coco（都可）买了个很喜欢的 Lava Pearls Taro，热饮 30% 糖。感觉 30% 糖还是太甜了，下次可以买无糖。</p><p>室友买了个白板贴，我在上面画了画，还写了双拼口诀。</p><p><img src="/posts/31df/cat.webp" alt="cat.jpg" loading="lazy"></p><p>阅读 <a href="https://lawtee.com/article/talk-about-2025-oct/">老 T 的一篇文章</a>，里面讲到他儿子的小学有一套货币系统。我想起我的初中和高中都有这种系统，前者用的是抽奖券，后者用的是学校自己印的塑料币，可以换零食、衣服、文具、化妆品等。我当时要毕业的时候，换了很多笔，还把学校所有的 U 盘都换走了。结果，没有一个 U 盘能用，还是学校道高一丈啊……</p></details><details><summary>十一月四日</summary><p>上班好烦！尤其是那两个头头，讲话像是为了攻击你而攻击你，很多时候给人感觉都是在无效沟通。你说这些东西，意义何在？只是为了让我难堪吗？</p><p>学校有个 app，几个月前看连登录都不行登录，今天一看可以用了，但是用起来还是很傻，最重要的预约功能不能用。</p><p>一说到学校，他们这两年发生的事情可不少：去年学生隐秘数据被盗，过了两个月才告诉我们；去年九月份引发了一场暴动，抗议者们口头攻击了校内的犹太人社团，并且在学校的正门口写了侮辱性话语。</p></details><details><summary>十一月五日</summary><p>项目管理打算主办活动，结果发现：现在的活动平台都需要充钱才给你推送。这里的「推送」指的是，用户能否在平台里搜到你。结果是不行，连搜都搜不到，那我要你何用呢？</p></details><details><summary>十一月六日</summary><p>回家，去了下店里取钥匙。</p><p>猫变肥了。</p><p><img src="/posts/31df/cat2.webp" alt="cat2.jpg" loading="lazy"></p></details><details><summary>十一月七日</summary><p>最烦的一天。</p><p>先是开车去新泽西，路窄以至于撞到了路边一辆车的左视镜。对方的镜子问题不大，反手按了回去。我们的右视镜就惨了，底座碎了。幸好镜子的线没断，还能感应。我们去 Home Depot 买了猩猩胶布粘了回去，等我或者我父亲以后回来再折腾。</p><p><img src="/posts/31df/homedepot.webp" alt="" loading="lazy"></p><p>期间我母亲没打电话去了岛另一头的修车厂，问他们多少钱。那个老板脸色很臭，直接说 1500 美元，原装的价格不关他事，然后要先给他定金 500 美元。见我母亲没有掏钱的意思，直接甩了个「拜拜」走了。之后我母亲给另一家修车的打电话，对方查了价格，给我们报价 885 美元。虽然少了近一半，但还是很贵。我们想了会儿，给我父亲去了电话，他说这东西换个底座就好了，上亚马逊买个第三方底座、他回来装，我们先买个胶布粘上。</p><p>这里还有个小插曲：我母亲给他去电话，电话好像是没信号还是关机了，都是一接就挂，我给他去电话也是。我们放弃没一会儿，我父亲给我来了电。我跟他沟通完，我母亲没声好气说他不给自己打电话、反倒给我先来了通电话。</p><p>买胶布的地方正好是宠物医院的附近。因为这天我也给猫做了预约，我们再次从修车厂开去医院。本来从新泽西去这家医院很近，但是我母亲这个举动，导致又需要一段时间。她期间烦躁地说：「不如把猫丢到这个高速旁边得了。」</p><p>我很恶心，骂她有病。她反骂我有病。我没继续跟她闹：猫是她自己捡的，先前打算把猫丢回家附近，结果看猫一直回来、不忍心又带了回来。结果一要她承担一些责任，她就开始疯了一样说要把猫丢到很远的地方，或者骂我和妹妹不孝、非要这只猫 —— 这猫是她 <strong>自己</strong> 捡回来的！</p><p>我把放在后备箱里的猫带去做检查、打针。医生说它肚子里可能有虫，但我之后什么时候还有时间回来也不知道了，只能先让医生把最必要的狂犬疫苗打了。猫瘟疫苗什么的得等到之后放假了，因为需要连续一段时间再来打第二第三针。钱也是另一回事，我刚还上之前欠的钱，现在才开始慢慢攒钱。</p><p><img src="/posts/31df/cat3.webp" alt="cat3" loading="lazy"></p><p>这些事处理完本想着直接走了，家里人说让我吃完晚饭再走，我也就答应下来。结果教堂的人过来、聊教堂的事情，貌似是不满教堂如何处理贡献的钱、没有很好地把钱放在正事上。这些年那个教堂的掌权人从老牧师变成了他的儿子，但掌管方式还是没怎么变，也有老牧师想要继续管教堂的问题在。其中一人不满新牧师不尊重人，没有和她说便叫另一个人替她的职位。这些事也不是那种真的岗位，几乎都是志愿者，但是没有和人说就不让他们做了，是不是不好呢？</p><p>其中一位阿姨也聊了今天我撞车的事情，说我们最先找的那家修车厂她认识。几年前这家修车厂刚开的时候，他们那个华人圈里的老板们会互相照应：今天我去你那边消费，明天你来我这边消费，大家互相打折，其乐融融。第一年还好，那个修车厂的老板还是弯着腰的，到了第二年，他的脸便奇臭无比，无论你是熟客还是什么，统统当韭菜割。渐渐的，她也不乐意去了。</p><p>还没完，他们接着开始说我为什么周日不去教堂。我一直说自己在打工，他们便问我为什么打那么多工、没必要攒那么多钱。阿姨说，我可以不信神，但是我得先接触祂才行。真是的，我做什么和你有什么关系啊。我也没告诉他们我实际做什么工作、花多少钱。母亲趁此机会要我不要打工了，不然赚的钱太多，影响她拿补助。</p><p>晚上坐车回去，结果日语课的同学说今天有个视频要交。我靠！</p><p>唉，事已至此，我去买了瓶可乐。</p><p><img src="/posts/31df/manhattan.webp" alt="manhattan" loading="lazy"></p><p>附一张曼哈顿某处的街头。</p></details><details><summary>十一月八日</summary><p>工作…… 第一次做早班，马马虎虎？也不是不行啦。</p><p>老板便秘，要出来的时候被我叫了出来，气得她一直说我，我只想哈哈笑。哈哈！</p><p>双拼也是，马马虎虎？还没到六点就开始发困，不知道为什么。</p><p>回去的时候去见项目管理人，她提到最近一个很火的东西：在红绿灯上挂着对口型。不知道为什么火，但是可以用来做视频宣传。不过她没有挂，人太多了我也不好录，我自己也比较抗拒这样的事儿。</p><p>晚上太困了，没做什么事就去睡觉了。</p></details><details><summary>十一月九日</summary><p>打工…… 班表说老板十二点半到，结果是经理下午两点才到。晚到就算了，做别的事做到了快五点才出来帮我。我自己也才五点下班哎。整体来说不算很忙，但是客人总是一连串来，搞得我很烦。</p><p>朋友同我讲了 <a href="/posts/e0dc.html">他的事情</a> 的后续。他去见了那个女的，询问她过去为什么那么对自己。果不其然，对方没有承认，只是说都是误会，然后让朋友删了自己、不要再联系。本来这件事到这里就结束了，结果女的的男友找来，态度只能说拽得莫名其妙、要求他删除一些帖子。我朋友告诉他他没有资格要求自己删帖，如果他想要帖子被删，叫女的自己过来跟自己说。然而对方沉浸在「自己的女朋友被过去的舔狗缠上」的戏码中，明知理亏还要装成白骑士一样说我朋友一顿，被我朋友反骂一顿、拉黑了。</p><p>赶工，事情好多，第二天还要上课？为什么？我不应该是只有工作才对吗，我恨。</p><p>室友最近做了很多秋葵作凉菜，好吃，比黄瓜好吃。</p><p>这几天想了一个新点子，用 NFC 模拟以前的暴龙机。我原本打算今天搞完、明天去玩，看来不行了。</p></details><details><summary>十一月十日</summary><p>不想上课，翘课做项目做了一天。晚上室友回来的时候眼睛感觉要融化了……</p><p>中午泡了个三养的蒜香拌面，不能说很好吃吧，只能说量真小啊。</p><p>看了斗龙战士 2 的解说，我小时候只看过第一代，很喜欢里面的十二星龙。第二代的设定都变得不一样了，人比龙还厉害。</p><hr><p>项目管理跟我说，她找一位朋友（以下简称甲）定制贴纸，对方今天交付。见面的时候，她们俩聊了聊关于项目的营销推广。甲把自己的手机给她，说里面是甲的朋友们对于该项目的看法。傻眼的是，原先以为是什么很好的建设性意见，结果是这群小女生得知这个人接了个贴纸的单，一个个跑去把我们项目的社交媒体账号扒了个干净，然后骂里面的内容做得很差、参演的人都是小孩子、不正经。</p><p>项目管理自然看得很不舒服：一、没有什么有用的建议，反而是一堆攻击；二、甲不觉得这种行为有什么不对，她是真的认为这些言论可以帮到我们；三、这可不是项目管理自己愿意看的，是甲直接给她看的，她都没法拒绝。</p><p>我哭笑不得。总之项目管理说了一顿甲。</p><p>真要说她们俩的对话有什么是有用的，那便是项目管理 —— 也就是产出推广视频的人 —— 的笑点不够 Gen Z。甲觉得她的笑点像千禧世代的人，也就是说，内容还不够「搞」。我看了一些调侃 Gen Z 说话方式的视频，感叹怎么这么像黑人帮派，朋友要叫 gang。</p></details><details><summary>十一月十一日</summary><p>实在是不想在学校、家里、打工的店里待着了，来法拉盛玩 MaiMai（舞萌 DX）~</p><p>街头一个有意思的垃圾桶。艺术这样融入生活，总是让人会心一笑。</p><p><img src="/posts/31df/trashcan.webp" alt="trashcan" loading="lazy"></p><p>工作是这种感觉吗……？没有自己的时间，只是在交差？很无聊……</p><p>创业…… 没有那么容易。</p><p><img src="/posts/31df/shrimp.webp" alt="shrimp" loading="lazy"></p><p>常去的一家水族店的猫咪，太可爱了~</p><p><img src="/posts/31df/cat5.webp" alt="cat5" loading="lazy"></p><p>午饭吃的烩面，常去的那家真的很好吃。隔壁也有一家，但是卫生条件和这家完全没法比，做的烩面也不是我喜欢的口味。</p><p>小时候家附近有一家「杭州私房面」，味道就和这种烩面一模一样。初次来这家烩面馆的时候，因为童年的味道突然被自己找回，差点难过得哭出来。</p><p><img src="/posts/31df/noodles.webp" alt="noodles" loading="lazy"></p><p>玩的期间碰到了之前打 MaiMai 认识的朋友。用现在的流行用语来说，就是 MaiMai 搭子？</p></details><details><summary>十一月十二日</summary><p>过生日啦~</p><p>恩其实也没有什么实感，主要是前两年的生日过的太凄惨？又或者是过生日一直都很不开心？总之潜意识里有些抗拒。反正呢，一边工作一边翘课一边做自己的 app 一边写日记和整理博客。日语课教授生病了，所以也没去，只剩下公开演讲课，好烦哦。</p><p>五点半出门去上课，巴士上都是下班的人，挤得满满当当的。唉，一时有些伤感。左边的腮帮子很难受，应该是一直在无意识咬牙齿导致的。</p><p>整理博客的期间整理了一下照片，发现一些上个月忘记放到十月月刊的照片，就当作是这个月才发现的吧~</p><hr><p>项目管理期间做了一些 Gen Z slang（网络用语或者流星语）调查，找我问一些建议。我怎么会懂呢？我只会不知所措地看着她：<em>什么是 bop？为什么要说 delulu？</em>（没有注释，因为我还是不懂）</p><p>不过我发现，外网的这些 brainrot 其实和国内的「抽象文化」很相似，主打一个莫名其妙、荒谬。我不仅看到了许多猫 meme，还看到了一些一看就是从国内平台搬出来的视频。除了叫朋友 gang，Gen Z 也会说 fam，很像国内常说的「家人们」。</p><p>晚上我和她吃的 Popeyes（博派斯；佰百鸡）。那个服务生居然把我们说的「不要鸡胸肉」理解成了「只要翅膀和小腿」，一个大腿都没给我们。我们俩一起吃了八块鸡肉都还是饿着肚子。</p><p>为了庆祝我的生日，她还给我买了小蛋糕。我们一起吃了。</p><p><img src="/posts/31df/cakes.webp" alt="cakes" loading="lazy"></p><p>她想要找天和我一起拍摄，但是算了吧！到半夜她就开始疯狂拷打我：<em>什么时候才能部署？</em></p></details><details><summary>十一月十三日</summary><p>我酷爱益生菌饮料，尤其是小样。一位朋友告诉我可以在亚米上买，我先买了十二瓶试试。50 美元才免运费，只是买零食的话有点小贵呢。这一点 Weee 就很好，可以买菜买肉。</p></details><details><summary>十一月十四日</summary><p>申请了学校的 SpringForward 项目（主要面向未实习过的大一大二生的校招实习），然后第一轮都没过。</p><p>好奇怪啊，去年都过了，难道是因为我的专业经验变多了？</p></details><details><summary>十一月十六日</summary><p>同项目管理去拍摄。我是一点都不懂拍摄…… 她看了我的素材后说我拍人很丑！我可是也花了很多时间在这上面哎！</p></details><details><summary>十一月十八日</summary><p>店里的新业务终于弄好了。软营业期间，我们全体员工都在慢慢学习：</p><ul><li>Espresso 是浓缩咖啡，也就是咖啡 + 水。水少一点叫 Ristretto，水多一点叫 Long Shot 或者 Lungo</li><li>Pandan 或者说 Pandanus 是千叶兰、斑兰</li><li>蓝藻在新系统内有足足三个叫法：Cyanobacteria、Phycocyanin、Cyanocose…… 我就怕有客人问我配方</li></ul><p>原先 10 点的早班，提早了两个小时，我现在得每天早上 7 点起床去开早班。</p><hr><p>我开始用「流畅阅读」这个插件来阅读文章，十分方便。我用的模型是 gemini-2.5-flash-lite。</p></details><details><summary>十一月十九日</summary><p>日语教授给我发送了一份邮件，我这才发现她也有一个博客网站，并且在里面发现她不仅是一个日语教授，还是一名作家、比较文学/现代语言/文化研究系博士、汉语学习者、法语学习者、企业家、螳螂拳学习者、侦探小说狂热粉丝……</p><p>博客的魅力还是太大了。我像往常一样劝诱室友同我一起写博客。</p><p>不过我的博客里，到底要放什么好呢？有什么是其他人想要知道的内容呢？我的关于页面被我修改过，现在还未想好里面放什么。</p></details><details><summary>十一月二十一日</summary><p>我最讨厌的食物，是味道很甜的肉包子。整个包子小小一个，连面都是甜的，吃进去让我恶心。肉包子为什么不能做成普普通通的咸口呢？为什么是甜的？你又不是糖包吧！最可恨的是，我在这里近乎只能买到甜的肉包子。</p><p>第一次做晚班，老板陪我到闭店。其实我也才得知老板不是真老板，经理才是真老板。但是因为懒得改了，所以还是使用原有的称呼。</p></details><details><summary>十一月二十二日</summary><p>妹妹游泳的时候，室友找我发了消息，又提到了那个人。她问我，<em>为什么这个世上听不懂人话的这么多，为什么人类可以这么自私和恶心、不讲道理？</em></p><p>我也不知道。这件事已经过去了两年，我认为她已经很努力地在做一些事情了，但是人所相信的东西是很难改变的。就算嘴上那么说，心里实际想的又是另一码事。</p><p>不过我自己也好奇，这样一段关系，真的有维持的必要吗？<em>他到底是你的什么？你想要通过这段关系，向自己证明什么？付出的这么多努力，真的可以证明出来什么吗？这个证明对你而言又有任何意义吗？</em></p><hr><p>之后我们一家顺路去了游戏厅，我的一位朋友也过来玩游戏。他大我近一轮，我们平日聊天就是聊游戏。结果我和他聊天的时候被我母亲看到，游戏结束后她质问我是不是在谈恋爱、不要找这种年纪这么大的。接着告诉我她已经有了一些人选，都是家里有车有房的，不过我不认识里面任何一个就是了。</p><p>那顿饭我感觉压力山大，不知道回复什么好。真是无语，我同男性相处我就是谈恋爱，我同女性相处我就是同性恋谈恋爱，老一辈或许才是真正的「性压抑」—— 看什么都是性！让我知道这些又是想干嘛，你看上对方家里有钱有势，那对方又凭什么要跟你的女儿在一块、还你们家的债务呢？就因为我有一整套女性生殖和生育器官吗？</p><p>实际上，最让我在意的是性取向。我喜欢男性吗？我不知道。就算是在美国，传统思想也不少见。大一的时候便有一个很烦很烦的傻逼问我，<em>你为什么喜欢女的？你不知道洞和洞是不能在一起的吗？</em> 家里就更不用提了。从小我和同性玩耍（真的只是关系好！）我的母亲都会说一句，「你们两个搞同性恋？我要打断你的腿！」</p><p>如果我真的不喜欢男性，却又因为社会压力去和一个男性在一起，那不就是在欺骗这个男性？我认为探索自己的性取向是有必要的，总不能我和一个人过了大半辈子了我才发现，<em>哦卧槽，我好像喜欢的是另一个性别。</em> 为了看起来「正常」，却伤害了自己、伤害了另一个相信自己的人，有必要吗？</p><hr><p>开车把猫的粪便样本带去医院，才知道我当时忘记付样本分析的钱，一共是 70 多美元。</p><p>Popeyes 和《玩具熊的午夜后宫》要出的新电影联动了，杯子上都印有玩具弗莱迪，十分可爱。</p><p><img src="/posts/31df/ToyFreddy.webp" alt="Toy Freddy" loading="lazy"></p><p>晚上我教了妹妹数学，母亲要求我每周回家辅导她学习。真的吗？我要去做这么多事情吗？唉？</p><p>我也跟朋友玩了泰拉瑞亚，帮她通关了原版经典。后面开了一个灾厄的专家复仇新档。这游戏开始的时候总是很困难，连一个史莱姆都打不过。</p></details><details><summary>十一月二十三日</summary><p>回家，老板叫我今天不要来上班，街上一个人都没有。应该是感恩节和黑色星期五快到了，大家都窝在家里自己煮饭吃。</p></details><details><summary>十一月二十四日</summary><p>医院给我打了个电话，说猫的体内查出了寄生虫。早不来，晚不来，现在我在曼哈顿了才来！如果我让我的家人直接把猫送去医院开药，他们肯定不乐意，<em>一群没有了别人就什么都做不到的家伙！</em> 我只能在周五那天早上坐两小时的车回家、开车半小时送猫去医院，再开半小时把猫送回父母家，最后坐两小时的车去曼哈顿。</p></details><details><summary>十一月二十六日</summary><p>明天是感恩节，一整周下来街上都没有什么人。</p><p>店里每天都会来一组学生，特别喜欢大声喧哗。可能他们是在一起打游戏，兴奋的时候还会突然尖叫。我们之前还会叫他们小声点，但他们也不会道歉，甚至也没有回应，只是小声了一丢丢，过一会儿又大声起来。今天有两个学生过来，等餐期间实在受不了了，生气地叫他们小声点。我很是感激。</p><p>快闭店的时候进来了一个流浪汉，盯着我们几个收拾卫生的女生看，让人发毛。他突然开始问我们多大了，我说我不能告诉你。其他同事告诉他已经关门了，想要他离开，他也只是站着不动盯着我们看。最后是一个同事打电话给老板，或许是让他以为我们要报警了，他才慢悠悠决定要离开。就算是要走了，他也不忘骚扰我们：对着我们每个人做了个飞吻动作。因为担心他在门口蹲守，我们让老板看了下室外监控，确保他已经不在了我们才离开。</p><p>聚餐我们去了一家网红店，有烧烤、手抓海鲜等。店里的人总是以为我是东北人，还问我山东不是东北吗。气得我，哎呦！这家店的味道倒是一般，里面有一个酱料甜的让人恶心。最可恶的是，他们家许多烤串刷的都是这个酱。</p></details><details><summary>十一月二十七日</summary><p>感恩节终于到了。今天主要是和室友在家里打边炉、看《极限挑战》第二季。很久没有看过综艺节目，这一季的内容相比第一季，总感觉少了些刺激。</p></details><details><summary>十一月二十八日</summary><p>回家带猫去医院，自然少不了争吵。母亲前几天要我昨天就回来，理由是这样的话我就可以看着妹妹、她出门去采购赚钱。我说我这周都安排好了，怎么可能给你突然腾出来一个时间呢？她在短信里没说什么，不过今天就这事和我说了起来。她觉得都是因为我，她才没钱赚。这到底又跟我有什么关系？妹妹又不是一个婴儿，放在家里一个上午不是什么大问题，甚至可能比我还会照顾自己。她也完全可以把妹妹交给其他朋友来看，但是她自己忘记这么做了！<em>反正她这样的人，只要失败了就全是其他人的错吧！</em></p><p>去医院的路上，她一边责怪我，一边想打听我昨天到底什么安排、为什么不回家。她又是觉得我和我室友搞同性恋情，又是认为我和我的朋友在搞兄妹恋。在她心里，我就不是什么好东西。</p><p>没过多久，她像是发病一样嚷嚷要把猫丢在高速上，并且责骂我和我妹。我们两个反驳她：「这猫是你自己捡回来的！你要负责！」她又把错推到我妹上，说是我妹要、我妹让她捡的。这怎么可能是真的呢？妹妹随口一说，又不是命令，分明是她自己想要捡回来。现在不想负责了，又不想被别人说是残忍的人，竟让我年幼的妹妹替她背锅。</p><p>车内安静一段时间后，她突然提到以前村里会把死猫挂在竹子上。一瞬间，她就好像那个圣母玛利亚转世，开始指责中国人残忍、没文化。<em>她也好不到哪里去吧！</em></p><p>开了半小时的路后一进去才发现医院又突然关了，只能打道回府。唉，四天前打我电话的那个人还说这周他们除了周日都开门。以后每次出门还是先打个电话问问吧。</p><p>和室友吐槽这件事的时候，她说这猫不属于我，我不应该操心。如果我家里人养不好，不如直接把猫送给想要领养的人。</p><p>晚上没有心情做事情，继续和朋友一起联机玩泰拉瑞亚的灾厄模组。</p></details><details><summary>十一月二十九日</summary>  <p>如果出门了，要如何捣鼓博客呢？</p><p>我现在的方法是先把内容写在 Google Keep 或者其他应用上，有时间用电脑了再一一复制粘贴过来。不过这个方法挺烦的，我实际写博客的时候只有在家里用电脑的时候。</p><p>有一个 app 叫做 GitJournal，需要用户自行将博客源代码放到 Git 云端仓库上。当用户想要用手机写的时候就拉取下来、写完保存便推送上去。想法还不错，就是 UI 实在是不好看，并且 Pro 版本最低就要 20 多美元。</p><p>过去我看到有人用 GitHub Issues 写博客。操作方法是利用 GitHub Actions，将 Issues 自动转换成博客内容，然后触发站点的构建。我觉得这个想法挺不错的，光是想想就觉得便利。不过一定要注意一下数据备份。</p><p>想到这里的时候，我也想起了家里那辆凌志 RX 350。它的操作系统和显示屏仿佛是上个世纪的产物，居然是摇杆模拟鼠标！整个系统老旧的不行，连 Carplay 都无法使用。我了解到其实把中控换成第三方盒子就可以使用 Carplay，不过想要触屏功能的话实在是很难：凌志 RX350 的屏幕凹在了中控台里，就算换了触摸屏也很难够得到。</p></details><details><summary>十一月三十日</summary><p>打工期间和同事闲聊，她说这家店好像快要倒闭了，新的业务估计也撑不了多久。我很吃惊，我也才进来几个月不到吧！怎么就要倒了？</p><p>本来和计算机课的小组成员说好，下午三点开个 Zoom 继续推进作业。结果他们：</p><ol><li>「我四点半才能来。」</li><li>「我可能得五点半。」</li><li>「不好意思哦我现在不在纽约我也不知道我什么能回家。」</li><li>「我得八九点才有时间。」</li><li>「我终于回家了（九点）。」</li><li>「我也到家了（十点）。」</li></ol><p>整个协作实在是让人痛苦无比。这次的作业要求是这样的：</p><ul><li>抓取纽约市公开数据的 API，获取一万条数据并存入 CSV 文件</li><li>用 pandas 清理数据、分析数据</li></ul><p>我是写代码的，在会议里共享窗口给他们看。因为 <a href="/posts/d38e.html">上次事件的问题</a>，我也不上网查方法了，直接从教授的笔记里 Ctrl + F 找，找不到就按教授的要求问 AI。呵呵，这可是我目前为止见过的第一个强迫学生使用 AI 的课。她上次因为我使用了课上没有教过的方法，就说我使用 AI 且不披露、学术不纯，在我解释我有过往经验后，她在回复里干脆表示「不和我继续纠缠 AI 使用」。</p><p>但好像小组成员根本不理解教授的要求。一个不知道如何实现的功能，在教授的笔记里没有提及，按照教授的要求，就是得问 AI、记录 AI 使用。他们非要在大半夜给教授发邮件，问能不能使用某某方法。你这样问她，有什么必要呢？在你提出这个课上从未出现的方法时，不就已经表明了你使用了 AI 并且知道了有这个方法？导致我很多地方都被无意义地暂停：你们问了 AI，倒是把结果告诉我啊！我还要睡觉呢！</p><p>其中一个小组成员（以下简称甲和乙）说的话实在是让人理解不了，令人怀疑他是不是从很久之前就不听课了：</p><ul><li><p>问题：如何删除 pandas dataframe 的列？</p><p>教授的笔记里没有提及，我说直接问 AI 吧、速度速度。</p><p>甲：「我记得她之前教我们，<code>del</code> 可以删除东西。」</p><p>我：「<code>del</code> 是给列表用的啊。」</p><p>甲：「她之前教我们 <code>del</code>。」</p><p>我：「<code>del</code> 是给列表用的！」</p><p>乙：「我查了 AI，我们要用 <code>remove()</code>。」</p><p>甲：「哦那你能不能写个邮件问她我们可不可以用 <code>remove()</code>。」</p><p>接着就是他们把我晾在一边，聊邮件发送和乱七八糟的东西……</p></li><li><p>问题：如何重新命名 pandas dataframe 的列？</p><p>教授的笔记里依然没有提及，我的提议依然是直接问 AI。</p><p>甲：「你能不能写一个，<code>if df["name"]</code> 为 xxx 然后 <code>name</code> 等于……」</p><p>我：「什么东西？」</p><p>甲：「她之前教我们用一个方法可以把下划线都换掉。好像是 <code>split()</code>。」</p><p>我：「那是 <code>replace()</code>。」</p><p>甲：「她之前教的好像是 <code>split()</code>。」</p><p>我上手写了个 <code>split()</code> 例子。</p><p>乙：「好像是 <code>rename()</code> 吧我猜的。」</p><p>甲：「你可不可以撤回那个邮件然后问她我们可不可以用 <code>rename()</code>。」</p><p>我：「你们可不可以有个人去查 AI。」</p><p>甲：「为什么 <code>mid_init</code> 这个列在最右边，不应该在 <code>last_name</code> 和 <code>first_name</code> 之间吗？」</p><p>我：「不影响，我们也没学如何调整列的顺序。」</p><p>甲：「你可不可以撤回那个邮件然后问她我们需要调整列的顺序吗。」</p><p>我：「这东西根本无所谓啦！」</p><p>甲：「可是如果因为这个我们数据乱了怎么办？它的 index 会乱掉然后我们不能用 <code>index()</code> 而是需要用 <code>loc()</code>。」</p><p>我：「……？」</p></li></ul></details></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;虽然上个月已经说了很冷，但发现这个月变得更冷了……&lt;/p&gt;</summary>
    
    
    
    <category term="想法迭代" scheme="https://blog.cytrogen.icu/categories/%E6%83%B3%E6%B3%95%E8%BF%AD%E4%BB%A3/"/>
    
    
  </entry>
  
  <entry>
    <title>我在谈论共情，他们在谈论逻辑</title>
    <link href="https://blog.cytrogen.icu/posts/d4e5.html"/>
    <id>https://blog.cytrogen.icu/posts/d4e5.html</id>
    <published>2025-11-24T15:07:48.000Z</published>
    <updated>2026-02-09T17:16:55.401Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>先前我刷到一个视频，内容是「一位学生在自习期间播放恐怖电影，反而导致另一位学生被吓出精神问题」。较为可悲的是，评论区内竟然有很多声音是指责受害者「矫情」，然后延伸到「现在的孩子都脆弱」。</p><span id="more"></span><p>这些声音令我作呕，于是我写了一个评论侧面攻击了这群人。我说：</p><blockquote><p>「评论区部分评论很完美地展示出了过早接触暴力、恐怖题材内容的弊端：没有共情能力、喜爱嘲笑欺凌他人。不要成为这种人。」</p></blockquote><p>结果我收获了一部分支持我的声音，以及一部分不知道为什么就是想要指责我的声音：</p><ol><li><p>说「没有共情能力、喜爱嘲笑欺凌他人」这些都是个人特征，然后指责我将它们赖到恐怖片上。我的回复是，我压根没有说看恐怖片是导致这些情况的主要因素啊。</p></li><li><p>反问我「与他人共情有什么意义」。这个没什么好说的，我都没有回复他他就已经被其他人骂的不敢说话了。</p></li><li><p>认为我归因草率的，原因有二：</p><ol><li>我不知道评论区内缺乏共情能力的是因为过早看了恐怖片</li><li>我无法确定恐怖题材会导致缺乏共情能力</li></ol></li></ol><p>我主要就说第三条。</p><p>首先我承认，我的评论存在了几个逻辑问题：我确实无法隔着网线核实那几个恶语相向的人童年是否看过恐怖片，「过早接触」也确实不能直接推导出「缺乏共情」。</p><p>但对于这个人看似客观的驳斥，我有意见。</p><p>我说的明明是「弊端」，他怎么理解成我说接触恐怖题材「一定」会导致缺乏共情能力？我有说我「确定」接触恐怖题材会「导致」缺乏共情能力吗？「弊端」这个词属于 <em>可能性论述</em>，他硬是给我掰成了 <em>确定性论述</em>，然后用这个被强化后的 <em>稻草人</em> 来攻击我「归因草率」。</p><p>通常我们看到一个熊孩子在公共场合撒泼打滚，会下意识感慨「这是过度溺爱、缺乏管教的弊端」。这并不代表我们认定所有溺爱的孩子都会变坏，也不代表我们需要先做完家访确诊了家教方式才能开口说话吧。</p><p>我们是在根据经验，警示一种环境造就性格的风险。我的担忧也并非空穴来风，心理学研究早已证实过度的感官刺激会让人对现实中的痛苦变得麻木。</p><p>是啊 <em>看恐怖内容不一定会让人丧失共情能力、变得喜欢嘲笑欺凌他人</em>，但那和我的观点有什么关系，我本来就不认为它们一定会这样啊。我个人并没少看恐怖题材的内容，并认为恐怖内容在我们的成长中有一定的帮助。</p><p>我想表达的根本不是「我反对恐怖片」，而是「心智未成熟时的过度暴力暴露」：<em>为什么要莫名其妙霸占自习时间然后自作主张播放恐怖片，然后攻击受害者矫情？</em> 再用先前熊孩子的例子，对方非要杠「你怎么知道他不是天生坏种」，这种对于显而易见的关联视而不见、非要追求绝对因果的姿态，与其说是严谨，不如说是为了抬杠而故意装瞎。</p><p>再退一步讲，这真的重要吗？</p><p>我的那条评论，根本不是一篇学术结论，而是 <strong>一个正常人类在面对同类受苦、遭到二次伤害时，出于道德义愤的本能反应</strong>。我认为我的评论，在这个评论区的出现根本就是在提醒其他观众，重点是「不要成为恶人」，使用「恐怖和血腥内容」作为因子完全是为了攻击那些恶意评论。我的评论的唯一问题，不就是没有叠所有的甲，在每个词之前加个「可能」嘛？</p><p>他的回复也是完完全全的在「驳斥」我，而非「探讨」这个问题。他指责我的点是否正确？客观来讲，没什么问题，我的用词确实不是「事实」。我不清楚他回复我的实际动机，但在他的语气里只能感受出他的质疑、否定，和一丝刻意的指责，也就是说他的回复本身既不严谨，也带有攻击性，并且绝口不提受害者和评论区里满溢的恶意。</p><p>但他的回复，无视了我的 <em>价值倡导</em> 初衷，只是揪住了我论证中不符合学术严谨性的部分进行攻击。他 <strong>不在乎</strong> 那个学生是否痛苦，也 <strong>不关心</strong> 我的核心关怀，他只 <strong>享受</strong> 于指出我形式上的错误。</p><p>这让我想起一句禅语：</p><blockquote><p>当手指指向月亮时，傻瓜却在看手指。</p></blockquote><p>在这种语境下，优先讨论「归因是否严谨」，真的有意义吗？</p><p>难道我们在制止恶行、呼吁善良之前，必须先做一份完美的社会学调查报告？难道人说的每一句话，都要以此生绝不出错的标准，去迎合世界上所有杠精的审查？</p><p><strong>把逻辑变成自己冷漠的借口，这种所谓的「严谨」，不过是另一种形式的残忍。</strong></p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;先前我刷到一个视频，内容是「一位学生在自习期间播放恐怖电影，反而导致另一位学生被吓出精神问题」。较为可悲的是，评论区内竟然有很多声音是指责受害者「矫情」，然后延伸到「现在的孩子都脆弱」。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="互联网" scheme="https://blog.cytrogen.icu/tags/%E4%BA%92%E8%81%94%E7%BD%91/"/>
    
    <category term="逻辑学" scheme="https://blog.cytrogen.icu/tags/%E9%80%BB%E8%BE%91%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>在 AI 恐慌的时代，熟练度是一种累赘</title>
    <link href="https://blog.cytrogen.icu/posts/d38e.html"/>
    <id>https://blog.cytrogen.icu/posts/d38e.html</id>
    <published>2025-11-20T21:36:50.000Z</published>
    <updated>2026-02-09T17:16:55.213Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近日我在一项限时一小时的小组作业里被教授控诉使用 AI 且不承认，而她的理由让我大跌眼镜。</p><span id="more"></span><h2 id="背景"><a class="markdownIt-Anchor" href="#背景"></a> 背景</h2><p>我这个学期正在上一节 CIS（计算机信息系统）课程，内容是 Python 入门，上课方法是网课。开课时的第一周，教授便给我们分配了一项作业：介绍自己并且告知我们是否有课外经验，好让她了解我们的能力以及对我们的作业有多大的期待。</p><p>我于数年前便学习过 Python，且学习了很长一段时间爬虫、网页自动化操作和 JavaScript 逆向（关于 JavaScript 逆向，你可以在 <a href="/tags/%E7%BD%91%E9%A1%B5%E9%80%86%E5%90%91/">这里</a> 找到一些我过往写过的文章。我也有当时学习这三个内容的笔记，未来可以发出来）。</p><p>于是我填写了表单，表示我学习过 Python 并且懂得如何使用许多库，其中便包括了这次的主角：BeautifulSoup。</p><h2 id="起因"><a class="markdownIt-Anchor" href="#起因"></a> 起因</h2><p>教授要求我们在一小时内完成一个小组作业，要求如下：</p><blockquote><h4 id="网页抓取书籍数据"><a class="markdownIt-Anchor" href="#网页抓取书籍数据"></a> 网页抓取书籍数据</h4><p>目标网站： <a href="http://books.toscrape.com/">Books to Scrape</a></p><p>任务：</p><ol><li>从网站的 <strong>第一页</strong> <strong>提取书籍信息</strong>，包括：<ul><li>书籍的 <strong>标题</strong></li><li><strong>价格</strong></li><li><strong>库存状态</strong></li></ul></li><li>将每本书的数据存储为一个 <strong>字典</strong></li></ol><p>输出示例：</p><pre><code class="language-plaintext">A Light in the Attic : {'Price': '£51.77', 'In Stock': 'In stock'}Tipping the Velvet : {'Price': '£53.74', 'In Stock': 'In stock'}</code></pre><p>作业说明：</p><ul><li>遵循课上讨论的步骤和方法</li><li>你可以使用 AI 工具来获取关于从网站抓取数据的指导或澄清，但 <strong>请勿复制完整的解决方案</strong>。任何 AI 提供的建议 <strong>都必须经过修改，以符合课上讨论的方法和步骤</strong>，以此证明你自己的理解并应用了所学知识</li><li><strong>直接提交来自外部来源的解决方案将得零分</strong></li><li>如果你使用了 AI，请 <strong>明确注明</strong> 你使用的 AI 工具，包含你提供的提示词，以及 AI 生成的输出内容</li><li>请像课上演示的那样，<strong>一步步展示你的进度</strong>。只提交完整的解答而没有展示过程或小测试将不被接受</li></ul><p>进阶挑战：</p><ul><li>从网站的 <strong>前 5 页</strong> <strong>提取书籍信息</strong></li><li>同时 <strong>提取</strong> <strong>评分</strong></li></ul></blockquote><p>这里有一些内容需要补充：</p><ol><li>教授本身不懂 HTML，也没讲过 HTML</li><li>关于网页爬虫的内容，教授只讲了一堂课</li></ol><p>这也是为什么教授允许我们使用 AI 工具：因为一些内容她根本没提到，需要 AI 辅助。</p><p>回到小组。我因为本来就懂爬虫，也懂怎么使用 BeautifulSoup（不过我更喜欢 lxml~），所以我直接告诉了小组成员我们要如何编写这套代码。不过这里出现了一个小插曲：我误以为需要进入到书本详情页才能获取到标题等内容，还白白写了一套「获取所有链接、访问链接再抓取数据」的代码。实际上直接在首页抓就好了。后面被小组成员提醒才赶忙修回来。</p><p>好了这不是重点！</p><p>这是首页源代码里一本书的内容：</p><pre><code class="language-html">&lt;article class="product_pod"&gt;  &lt;div class="image_container"&gt;    &lt;a href="catalogue/sapiens-a-brief-history-of-humankind_996/index.html"&gt;&lt;img src="media/cache/be/a5/bea5697f2534a2f86a3ef27b5a8c12a6.jpg" alt="Sapiens: A Brief History of Humankind" class="thumbnail"&gt;&lt;/a&gt;  &lt;/div&gt;  &lt;p class="star-rating Five"&gt;    &lt;i class="icon-star"&gt;&lt;/i&gt;    &lt;i class="icon-star"&gt;&lt;/i&gt;    &lt;i class="icon-star"&gt;&lt;/i&gt;    &lt;i class="icon-star"&gt;&lt;/i&gt;    &lt;i class="icon-star"&gt;&lt;/i&gt;  &lt;/p&gt;              &lt;h3&gt;&lt;a href="catalogue/sapiens-a-brief-history-of-humankind_996/index.html" title="Sapiens: A Brief History of Humankind"&gt;Sapiens: A Brief History ...&lt;/a&gt;&lt;/h3&gt;  &lt;div class="product_price"&gt;    &lt;p class="price_color"&gt;£54.23&lt;/p&gt;    &lt;p class="instock availability"&gt;      &lt;i class="icon-ok"&gt;&lt;/i&gt;            In stock        &lt;/p&gt;    &lt;form&gt;      &lt;button type="submit" class="btn btn-primary btn-block" data-loading-text="Adding..."&gt;Add to basket&lt;/button&gt;    &lt;/form&gt;  &lt;/div&gt;&lt;/article&gt;</code></pre><p>这里需要特别说一下首页标题：</p><pre><code class="language-html">&lt;h3&gt;&lt;a href="catalogue/sapiens-a-brief-history-of-humankind_996/index.html" title="Sapiens: A Brief History of Humankind"&gt;Sapiens: A Brief History ...&lt;/a&gt;&lt;/h3&gt;</code></pre><p>如果直接 <code>a.text</code> 的话，只会得到被裁剪的标题。真正的标题在其中的 <code>title</code> 属性里。那直接写 <code>a["title"]</code> 就可以了吗？当然不是了，不是所有的 <code>a</code> 标题都带有 <code>title</code> 属性，真跑起来的话不就报错了？</p><p>这里有两个方法：</p><pre><code class="language-python">if soup.find("a")["title"]:</code></pre><pre><code class="language-python">soup.find("h3").find("a")["title"]</code></pre><div class="danger"> 当然了方法还有很多，我这里只说我当时第一时间想到的。</div><p>用第一个办法最保险，但是对于这个简单的作业，我直接写的第二个。这里虽然是我不够严谨了，不过当时实际敲代码的并不是我。单是口头指导屏幕另一边的小组成员怎么写东西、要点击什么东西就已经够累人了，我还需要告诉他们为什么我要这么做、用的方法是做什么使的…… 因为小组成员好像没有一个人知道怎么做哎！反正代码向来都是能用就可以，我觉得这个处理方式没有任何问题。</p><p>其余内容没什么好说的，我直接让小组成员开始写字典、照教授所要的方法打印出来字典…… 唯一的问题是打印出来的价格会多出一个神秘符号 <code>Â</code>，感觉是编码问题。我们加了一个 <code>.replace("Â", "")</code> 来去掉它。</p><p>这时候我们已经快到了截止时间。我们不仅需要在这个时间里写完代码，还需要填写成员评估表单交上去。这是最终代码（因为是 <code>ipynb</code>，所以一个代码块等同于一个单元格）：</p><details>  <summary>所有代码</summary><blockquote><pre><code class="language-python">%pip install requests</code></pre><pre><code class="language-python">import requestsurl = "https://books.toscrape.com/"response = requests.get(url)response</code></pre><blockquote><p><code>response</code> 返回的内容：</p><pre><code class="language-plaintext">&lt;Response [200]&gt;</code></pre></blockquote><pre><code class="language-python">from bs4 import BeautifulSoup</code></pre><pre><code class="language-python">soup = BeautifulSoup(response.text, 'html.parser')soup</code></pre><blockquote><p><code>soup</code> 返回的内容：</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;&lt;!--[if lt IE 7]&gt;      &lt;html lang="en-us" class="no-js lt-ie9 lt-ie8 lt-ie7"&gt; &lt;![endif]--&gt;&lt;!--[if IE 7]&gt;         &lt;html lang="en-us" class="no-js lt-ie9 lt-ie8"&gt; &lt;![endif]--&gt;&lt;!--[if IE 8]&gt;         &lt;html lang="en-us" class="no-js lt-ie9"&gt; &lt;![endif]--&gt;&lt;!--[if gt IE 8]&gt;&lt;!--&gt; &lt;html class="no-js" lang="en-us"&gt; &lt;!--&lt;![endif]--&gt;&lt;head&gt;&lt;title&gt; All products | Books to Scrape - Sandbox&lt;/title&gt;&lt;meta content="text/html; charset=utf-8" http-equiv="content-type"/&gt;&lt;meta content="24th Jun 2016 09:29" name="created"/&gt;&lt;meta content="" name="description"/&gt;&lt;meta content="width=device-width" name="viewport"/&gt;&lt;meta content="NOARCHIVE,NOCACHE" name="robots"/&gt;&lt;!-- Le HTML5 shim, for IE6-8 support of HTML elements --&gt;&lt;!--[if lt IE 9]&gt;     &lt;script src="//html5shim.googlecode.com/svn/trunk/html5.js"&gt;&lt;/script&gt;     &lt;![endif]--&gt;&lt;link href="static/oscar/favicon.ico" rel="shortcut icon"/&gt;&lt;link href="static/oscar/css/styles.css" rel="stylesheet" type="text/css"/&gt;&lt;link href="static/oscar/js/bootstrap-datetimepicker/bootstrap-datetimepicker.css" rel="stylesheet"/&gt;&lt;link href="static/oscar/css/datetimepicker.css" rel="stylesheet" type="text/css"/&gt;&lt;/head&gt;&lt;body class="default" id="default"&gt;...         });     &lt;/script&gt;&lt;!-- Version: N/A --&gt;&lt;/body&gt;&lt;/html&gt;Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...</code></pre></blockquote><pre><code class="language-python">books = soup.find_all("article", class_="product_pod")books</code></pre><blockquote><p><code>books</code> 返回的内容：</p><pre><code class="language-plaintext">[&lt;article class="product_pod"&gt; &lt;div class="image_container"&gt; &lt;a href="catalogue/a-light-in-the-attic_1000/index.html"&gt;&lt;img alt="A Light in the Attic" class="thumbnail" src="media/cache/2c/da/2cdad67c44b002e7ead0cc35693c0e8b.jpg"/&gt;&lt;/a&gt; &lt;/div&gt; &lt;p class="star-rating Three"&gt; &lt;i class="icon-star"&gt;&lt;/i&gt; &lt;i class="icon-star"&gt;&lt;/i&gt; &lt;i class="icon-star"&gt;&lt;/i&gt; &lt;i class="icon-star"&gt;&lt;/i&gt; &lt;i class="icon-star"&gt;&lt;/i&gt; &lt;/p&gt; &lt;h3&gt;&lt;a href="catalogue/a-light-in-the-attic_1000/index.html" title="A Light in the Attic"&gt;A Light in the ...&lt;/a&gt;&lt;/h3&gt; &lt;div class="product_price"&gt; &lt;p class="price_color"&gt;Â£51.77&lt;/p&gt; &lt;p class="instock availability"&gt; &lt;i class="icon-ok"&gt;&lt;/i&gt;              In stock      &lt;/p&gt; &lt;form&gt; &lt;button class="btn btn-primary btn-block" data-loading-text="Adding..." type="submit"&gt;Add to basket&lt;/button&gt; &lt;/form&gt; &lt;/div&gt; &lt;/article&gt;,... &lt;form&gt; &lt;button class="btn btn-primary btn-block" data-loading-text="Adding..." type="submit"&gt;Add to basket&lt;/button&gt; &lt;/form&gt; &lt;/div&gt; &lt;/article&gt;]Output is truncated. View as a scrollable element or open in a text editor. Adjust cell output settings...</code></pre></blockquote><pre><code class="language-python">books_data = {}for book in books:title = book.find("h3").find("a")["title"]price = book.find("p", class_="price_color").text.replace("Â", "")availability = book.find("p", class_="instock availability").text.strip()books_data[title] = { "price": price, "in stock": availability }</code></pre><pre><code class="language-python">for title, info in books_data.items():print(title, ":", info)</code></pre><blockquote><p>最终 <code>print</code> 出来的内容（原文太长了删减一下）：</p><pre><code class="language-plaintext">A Light in the Attic : {'price': '£51.77', 'in stock': 'In stock'}Tipping the Velvet : {'price': '£53.74', 'in stock': 'In stock'}Soumission : {'price': '£50.10', 'in stock': 'In stock'}Sharp Objects : {'price': '£47.82', 'in stock': 'In stock'}</code></pre></blockquote></blockquote></details><p>数日后成绩下来了，我们拿了 F，而这是教授的反馈：</p><blockquote><p>作业说明明确指出：「就像课堂上演示的那样，一步步展示你的过程。不展示过程或小测试的完整解答将不被接受。」你提交的作业不包含任何测试或循序渐进的过程。你只是把完整的解答拆分到了不同的单元格里。依然没有测试。此外，也未披露使用了 AI。</p><p>关于你的代码：这一行是从哪里来的？<code>books = soup.find_all('article', class_='product_pod')</code>。还有，你是怎么在 for 循环下直接写出这些的： <code>book.h3.a['title']</code> <code>book.find('p', class_='price_color').text</code> <code>book.find('p', class_='instock availability').text.strip()</code> 像我在练习中做过多次的那样，针对这些代码的测试在哪里？</p></blockquote><p>我当时看到的第一反应是：<em><strong>什么叫他妈的我们没有披露使用 AI？</strong></em></p><h2 id="第一次回复"><a class="markdownIt-Anchor" href="#第一次回复"></a> 第一次回复</h2><p>这节课的 WhatsApp 群组里有人表示，我们不是唯一拿了 F，并且被指控使用了 AI 的小组。</p><p>一些拿了分的小组提到教授要求我们像她的笔记那样，记录每一步尝试。他们直接照着她的笔记捣鼓，拿了满分。但这和我有什么关系？我又不是新手，我为什么还要退一步、装自己什么也不懂？难道抄教授的思路就好了？</p><p>也有人向教授说话，说因为教授自己也不懂 HTML，因此不期待我们懂 HTML，才叫我们用 AI 来了解 HTML。这番言论一说出来便遭到了其他已经学习过网页开发的校友的嘲讽：<em>教授自己都不懂自己分配的作业，反过来指责我们这些懂的人用了 AI。这不搞笑吗？</em> 这是我自己想出来的代码，用我学过的东西、自己写出来的！现在你告诉我，<em>我未披露自己使用了 AI</em>？要知道，AI 可是有一定的可能性，被喂了我所曾经想出来的代码方案哎！</p><p>我的一位小组成员（以下简称甲）找到我，希望我可以和她一起出面、找教授说清楚。我告诉甲我们的代码绝对不是 AI 生成的，我也已经就我的想法给出了我的步骤。如果不是因为教授要求我们给出步骤，我甚至不会去打印那么多次变量、将它们分成多个单元格。有必要去装模作样测试那么多次吗？没有！</p><p>不过呢，我因为次日还有个演讲，完全忘记了发邮件这件事…… 直到演讲前的一小时，甲给我发了她和教授之间的对话：</p><blockquote><p>甲：</p><blockquote><p>晚上好，</p><p>我阅读了您关于第 5 次作业的反馈。关于「逐步展示过程」，就我们的理解而言，我们确实是照做了。我觉得我们可能没理解题目到底要求我们做什么。</p><p>我们并没有使用 AI，所以我不知道您为什么会觉得我们用了。</p><p>能不能请您再给我们一次机会来修正那段代码或提交类似的代码？在作业里拿个 0 分并不能激励我继续前进。</p><p>致以诚挚的问候，</p><p>甲</p></blockquote><p>教授：</p><blockquote><p>嗨甲，</p><p>这次作业的要求非常明确，而且我在上课一开始就强调过，我期望看到你们的 <strong>过程</strong>，而不仅仅是最终的解决方案。这次作业旨在评估你们 <strong>循序渐进的过程</strong>，而不仅仅是最终结果。我已经在反馈中解释了我对 AI 使用的顾虑。其他披露了使用 AI 的小组实际上也使用了相同的代码。让我给你一个更详细的解释。</p><p>使用 <code>h3.a["title"]</code> 这一点，如果没有 AI 的协助，你们也是想不出来的。如果你们是独立完成的，你们很可能会从像 <code>first_book.find("a", class_="title")</code> 这样的代码开始，观察到它不起作用，然后再转向其他方法。它之所以不起作用，是因为标题的 HTML 结构与价格和库存的结构不同。然而，你们并没有关于这部分的 AI 使用披露，也没有尝试用我教过的方式来提取标题。这种用法是直接由 AI 生成的解决方案，这也违反了作业要求。我从来没有教过将标签（h3, a）当作函数 / 属性来使用。这些信息是从哪里来的？为什么在提取价格和库存时使用的是 <code>book.find('p', class_="price_color")</code> 和 <code>book.find('p', class_='instock availability')</code>，却偏偏在提取标题时使用 <code>h3.a["title"]</code>？</p><p>如果你们参考过我的教学课件，你们就不会那样去构建代码中的字典部分。你们使用的这种风格是一种 <strong>优化过的方法</strong>：先通过 <code>soup.find_all('article', class_="product_pod")</code> 一次性提取所有项目，然后再遍历每一项进行抓取。你们是怎么知道可以这样做的？然而，这并不是我在课上展示的内容。我演示的是如何通过一步步审查 HTML 结构来单独定位每一条信息。我并没有教过你们如何先提取所有数据，然后再在一个单一的循环中检索内部的子数据点。你们提交的方法并不能反映我所教授的过程或方法论。</p><p>很遗憾，我无法接受你们修改后的重新提交。课程政策不允许重新提交作业。</p><p>祝好，</p><p>教授</p></blockquote></blockquote><p>我看到后立马想到（以至于我之后的演讲因为头脑混乱讲的很差）：</p><ol><li>这个教授的整个底层逻辑有问题</li><li>她不懂爬虫、不懂 AI，也不懂学习！</li></ol><h2 id="教授的指控和逻辑"><a class="markdownIt-Anchor" href="#教授的指控和逻辑"></a> 教授的指控和逻辑</h2><p>先说教授的底层逻辑。她默认学生们什么都不会，没有教过的内容等同于学生们不会。这里有两个问题：</p><ol><li><p>学生们要是不会，去问 AI 完全没有问题。但是她没有考虑到会的学生啊！我都会了，我还要去搜 AI、告诉你我用了 AI 吗？肯定不是啊！</p><p>在大学环境里，<strong>「教授没教」怎么可能去等同于「学生不可能知晓」呢？</strong> 我们完全可以去提前阅读文档、验证假设、应用这些知识。更何况这是编程课程，自主学习本来就应该被鼓励才对。</p><p>按照她的逻辑，独立实验是被禁止的、主观能动性是受惩罚的、学术成长也是被视为作弊的证据。要求我们的思维过程必须与她教授的路径一致，这既不合理、在学术上站不住脚，也绝对不是高等教育的运作方式。</p></li><li><p>既然原先就这么默认，那么起初的编程经验调查的意义何在？只是为了完成学校部门的要求吗？</p></li></ol><p>这是上文我重点提及的代码：</p><pre><code class="language-html">&lt;h3&gt;&lt;a href="catalogue/sapiens-a-brief-history-of-humankind_996/index.html" title="Sapiens: A Brief History of Humankind"&gt;Sapiens: A Brief History ...&lt;/a&gt;&lt;/h3&gt;</code></pre><p>她认为我所写的 <code>h3.a["title"]</code> 是学生无法独立想出的内容、是直接用 AI 生成的解决方案。就和我上文所说的那样，莫名其妙，毫无逻辑。宣称学生们想不出来，根本是否认了他们思考的权利。再加上，为什么死认我们使用 AI，而不是阅读 BeautifulSoup 的文档？难道阅读文档在现在这个时代也过时了？</p><p>教授所要求的「展示步骤」也是愚蠢至极，根本无法像她所想的那样防住使用 AI 作弊的学生：<em>我只要把教授的课件全部炼化，然后让 AI 生成相同效果的代码不就好了？</em> 并且会大大打击那些已经学会了如何写代码的学生。已经有数个学生反映她的课对已经学习过编程的人来说是一种折磨：<em>我就是会啊，你还想我怎样！</em></p><p>可怕的是，<strong>教授对我们使用 AI 的指控没有任何可靠的证据，完全出于她自己的臆测</strong>。她将这一条写在解释之前，因此我猜测这是她认为我们有罪的最大证据：<em>其他披露了使用 AI 的小组实际上也使用了相同的代码。</em> 额…… 不然呢？BeautifulSoup 提取标签属性值的方法本来就那几个啊。难道和 AI 一样说 1 + 1 = 2 的人，也全都是 AI？</p><p>而最让我意外的是，许多被无辜指控的学生都放弃了澄清。当时向着教授说话的不在少数，这些观点也险些让我也失去了沟通的勇气。我可以为我任何的不足负责，但我绝不为我未曾做过的事道歉。如果对方要用臆测代替证据，她所要负起的，不止是一次误判的责任，更是对学术公正和个体尊严的损害。</p><h2 id="第二次回复"><a class="markdownIt-Anchor" href="#第二次回复"></a> 第二次回复</h2><p>既然找出了教授所有的逻辑漏洞，我也得负起小组领导的职责、向教授再一次沟通。这是我最终的邮件：</p><blockquote><p>尊敬的教授：</p><p>我已阅读了您发给我的队友甲的关于我们作业反馈的邮件。我写这封信是为了澄清关于我们要代码逻辑的误解以及对我们使用 AI 的指控，因为是我主导了我们组的编码逻辑。</p><p>关于基于特定语法（如 <code>h3.a['title']</code>）而指控我们使用 AI 一事，我必须澄清这段代码并非由 AI 生成。我在 HW1 的学生概况调查中曾表示过我有网络爬虫的经验。我最初尝试使用 <code>soup.find("a")["title"]</code> 来提取标题，但我很快意识到这会导致报错，因为文档结构中并非所有的 <code>&lt;a&gt;</code> 标签都拥有 "title" 属性。随后我将代码改进为 <code>soup.find("h3").find("a")["title"]</code>，因为所有带有 "title" 属性的 <code>&lt;a&gt;</code> 标签都嵌套在 <code>"h3"</code> 标签内。之后在循环中我使用了 <code>book.find("h3").find("a")["title"]</code>，因为我写了一个 <code>for</code> 循环从 <code>soup.find_all("article", class_="product_pod")</code> 中获取所有的书籍。由于当时时间紧迫，我便保留了这段代码未做改动。</p><p>您还提到其他披露使用了 AI 的小组也提交了类似的代码。我认为相关性并不意味着因果关系。<code>a["title"]</code> 这种语法是标准的简写形式，并且可以说是浏览这种特定 HTML 结构最直接的方式。</p><p>关于我们没有展示逐步推进过程的顾虑，这是对我们在时间限制下构建代码方式的误解。正如提交的 Notebook 所示，我在单独的单元格中展示了 <code>response</code>、<code>soup</code> 和 <code>books</code> 列表的输出。然而，对于循环内部具体的提取逻辑，我们在组内协调上遇到了一些挑战，这拖慢了我们的进度。尽管我尽力引导团队完成，但当我们开始编写最终的提取脚本时，距离截止时间已经非常近了。在时间压力下，我不得不依靠我之前的经验，直接基于分析编写了循环。</p><p>如果我们的作业能被重新评估，我将不胜感激。</p><p>非常感谢。</p><p>诚以此致，</p><p>我</p></blockquote><p>十分私人的想法还是留给自己（以及你们，嘻嘻）吧…… 没必要增加更多的误会，只要回复教授的问题以及指出其他问题即可。</p><p>说来好笑，我最初拟的版本被室友吐槽「不像人在说话」。她认为我是博客写多了，现在写邮件也会在里面穿插一些大道理，并且有许多重复的内容。我认为没有办法啊，有些东西我不重复讲一下不能表达出我的急切。总之让她帮我修改了一下，也是上文这个版本。</p><p>至于后续如何，也不是特别重要了。值得感叹的是，<strong>就算是到了 AI 时代，能够熟练使用某项技能也会被古板的教育系统视为「有罪」</strong>。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;近日我在一项限时一小时的小组作业里被教授控诉使用 AI 且不承认，而她的理由让我大跌眼镜。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="Python" scheme="https://blog.cytrogen.icu/tags/Python/"/>
    
    <category term="大学课程" scheme="https://blog.cytrogen.icu/tags/%E5%A4%A7%E5%AD%A6%E8%AF%BE%E7%A8%8B/"/>
    
    <category term="逻辑学" scheme="https://blog.cytrogen.icu/tags/%E9%80%BB%E8%BE%91%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>What About…… 和比烂</title>
    <link href="https://blog.cytrogen.icu/posts/dfa8.html"/>
    <id>https://blog.cytrogen.icu/posts/dfa8.html</id>
    <published>2025-11-18T05:24:41.000Z</published>
    <updated>2026-02-09T17:16:55.009Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我在网上冲浪时刷到一个吐槽美国学校作业多的帖子，发现了一个评论：<em>为什么大家什么都要和国内比？为什么要比较彼此谁更不幸呢？</em></p><p>我认为这是现在少数的、能发觉评论区问题的人。当时的评论区近乎都是国内的账户评论「国内就不累了吗」或者「这才哪到哪儿，国内高中更累」这样的发言。前者更类似于 Whataboutism，后者则明显就是比烂。</p><span id="more"></span><p>Whataboutism（那…… 又怎么说）是一种常见的逻辑谬误。当一方提出 A 领域的问题时，另一方在不喜欢对方的观点的情况下，不就此回应、<strong>反而抛出了 B 领域的另一个问题来反击或者转移话题</strong>：<em>你这样说是不是代表着你觉得这个另一个主体不 xxx？</em> 这种观点表述在关于外国的帖子，尤其是吐槽和抱怨的帖子下比比皆是，动机因人而异，但大抵可归为两类：</p><ul><li>内心更相信外国的月亮更圆，因此不信任他人对外国的评价</li><li>感觉被冒犯到了，所以触发了防御心理</li></ul><p>无论初衷如何，其结果往往是 <strong>模糊了焦点，让理性的比较和就事论事的讨论无法展开</strong>。</p><p>我遇到过不少类似的情况。当我提出美国社会某些制度的弊端时，对方总是会立刻将中国的情况拉出来作为「反驳」，好似他们根本无法意识到，复杂的国家比较根本就不是非黑即白的优劣判断，而是各有侧重的 AB 级 —— 一个多了这个但缺少了那个，一个多了那个但缺少了这个。</p><p>比如，我说「美国很多城市的公共交通太差了，晚上出门没有车简直寸步难行。」那么一条经典的 Whataboutism 回复就会是：「呵呵，那你是不了解国内小县城，那里连公交都没有，你怎么不说？美国有地铁公交你就知足吧！」</p><p>你看，我的原意是讨论「美国某城市公交系统不便」，这是问题 A，但回复者却将话题强行转移到了「中国小县城公交匮乏」，也就是问题 B 上。他预设的立场是「我在通过贬低美国来抬高中国」，并通过引入一个更不堪的例子，试图证明我的抱怨是「无病呻吟」或是「别有用心」。</p><p>这自然是我虚构出来的一个例子。不过将这里的主体稍微换一下，便能得到我和某个朋友曾经每天的对话是什么样的（关于这个朋友，我在未来会写篇文章展开说说）。这也是为什么我对这种事如此上心，实在是令人烦躁！按照这些人的逻辑，<strong>只要世界上存在一个更差的情况，所有具体的批评就都失去了意义</strong>。于是，关于问题 A 的任何深入讨论都被扼杀了。</p><p>比烂则是一种更消极的攀比。攀比这个行为并不需要比较「好的地方」，比较「烂的地方」也可以，因为攀比的本质是让「他人看到自己」。当一个人在价值上难以企及「最好」时，通过证明自己经历了「最烂」来获得某种独特的优越感或存在感，便成了一条捷径。</p><p>这种行为深层次上，呼应了人类对自我身份的寻求。在宏大的网络世界里，个体常常感到渺小，而一个极端的故事，无论是至善还是至恶，都能成为最有效的身份标签。让他人看到自己，也可以回复人们从青少年时期就在思考的问题 —— <em> 我是谁？</em> 于是，最惨的经历也成了一种畸形的资本，通过它，个体得以在嘈杂的舆论场中被看见、被记忆，从而确认「我是谁」。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我在网上冲浪时刷到一个吐槽美国学校作业多的帖子，发现了一个评论：&lt;em&gt;为什么大家什么都要和国内比？为什么要比较彼此谁更不幸呢？&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;我认为这是现在少数的、能发觉评论区问题的人。当时的评论区近乎都是国内的账户评论「国内就不累了吗」或者「这才哪到哪儿，国内高中更累」这样的发言。前者更类似于 Whataboutism，后者则明显就是比烂。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="互联网" scheme="https://blog.cytrogen.icu/tags/%E4%BA%92%E8%81%94%E7%BD%91/"/>
    
    <category term="逻辑学" scheme="https://blog.cytrogen.icu/tags/%E9%80%BB%E8%BE%91%E5%AD%A6/"/>
    
    <category term="心理学" scheme="https://blog.cytrogen.icu/tags/%E5%BF%83%E7%90%86%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>Hexo 和 Typora 的完美图片工作流</title>
    <link href="https://blog.cytrogen.icu/posts/96d8.html"/>
    <id>https://blog.cytrogen.icu/posts/96d8.html</id>
    <published>2025-11-14T01:37:43.000Z</published>
    <updated>2026-02-09T17:16:54.709Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我写作是用 Typora 编辑器来写 Markdown，再让 Hexo 框架的 Markdown 渲染器渲染成 HTML。</p><span id="more"></span><p>Hexo 对于图片的存放要求是这样的：在 Markdown 文件的同级下创建一个同名的目录，并在该目录下存放图片。这样写很方便，只需要在 Markdown 文件里写 <code>![](图片名.类型)</code>，程序就会自动从同名目录里找到指定的图片。</p><p>但如果我想要在 Typora 里直接粘贴图片，它通常会被拷贝到其他位置，我再灰溜溜去手动挪动图片的位置。</p><p>幸运的是，我最近发现一个法子可以解决这个问题，让我的写作体验更上一层楼~ 这个方案的核心是把 Typora 的图片保存逻辑（它实际把文件复制到哪里）和路径预览逻辑（它如何理解 <code>![](image.png)</code> 这行代码）分离开。</p><ol><li><p>在 Typora 中，进入 <strong>设置</strong> &gt; <strong>图像</strong>。</p></li><li><p>在 <strong>插入图片时……</strong> 下拉菜单中，选择 <strong>复制图片到指定路径</strong>。</p></li><li><p>在 <strong>路径</strong> 输入框中，填入以下这行代码：</p><pre><code class="language-plaintext">./${filename}/</code></pre></li><li><p>勾选 <strong>优先使用相对路径</strong>。</p></li></ol><p>现在，当你在一篇名为 <code>hello-world.md</code> 的文章中粘贴图片时，Typora 会自动将该图片复制到 <code>hello-world/</code> 文件夹中。不过插入的路径还是 <code>![](hello-world/image.png)</code>。要解决这个问题，我们只需要在文章最顶部的 YAML Front Matter 区域里添加一行：</p><pre><code class="language-yaml">---typora-root-url: ./hello-world---</code></pre><p>这个路径必须和这篇文章的文件名完全一致。而在 Hexo，你只需要在 scaffolds 里添加一个：</p><pre><code class="language-yaml">---typora-root-url: ./{{ title }}---</code></pre><p>就可以每次用 <code>hexo new</code> 命令创建 Markdown 文件时，自动添加这个键值对。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我写作是用 Typora 编辑器来写 Markdown，再让 Hexo 框架的 Markdown 渲染器渲染成 HTML。&lt;/p&gt;</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Hexo" scheme="https://blog.cytrogen.icu/tags/Hexo/"/>
    
    <category term="Typora" scheme="https://blog.cytrogen.icu/tags/Typora/"/>
    
  </entry>
  
  <entry>
    <title>离开父母对成年子女独立性的帮助</title>
    <link href="https://blog.cytrogen.icu/posts/96d1.html"/>
    <id>https://blog.cytrogen.icu/posts/96d1.html</id>
    <published>2025-11-05T17:31:23.000Z</published>
    <updated>2026-02-09T17:16:55.549Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我在公开演讲课上的一次信息性演讲内容。这篇文章是我的演讲稿的超级增强版。</p><span id="more"></span><p>离开父母家庭是 <em><strong>成年初显期</strong></em> 最重要的发展转折点之一。迈出这一步，可能让人感到兴奋、充满不确定性，而且坦白说花费不菲。但是，当一个年轻人离开「巢穴」时，究竟会发生什么？这远不止是换一个地址那么简单。发展心理学的研究表明，住宅独立是全方位独立性的催化剂。搬家不仅重塑了我们的家庭关系，也强力推动了个体身份认同的发展、日常自给自足能力的建立，甚至对我们的心理健康都有深远的影响。</p><h2 id="促进更成熟-平等的亲子关系"><a class="markdownIt-Anchor" href="#促进更成熟-平等的亲子关系"></a> 促进更成熟、平等的亲子关系</h2><p>只要你住在父母的屋檐下，你就很难摆脱「孩子」的角色。你活在他们的空间里、遵循着青春期的权力动态 —— 他们行使控制，你保持依赖。这种旧有的亲子模式很难打破。但是当你搬出去后，游戏规则就必须改变。你的父母不再负责你日常生活的方方面面。正因为如此，他们会自然地减少控制，而你也减少了依赖。</p><p>威斯康星大学麦迪逊分校的社会学教授威廉・阿奎利诺的权威研究揭示，离家是「通往更加个体化关系的催化剂，这种关系建立在两个成年人之间的相互关怀和尊重之上」。</p><p>这种转变是积极的。宾夕法尼亚州立大学的肖恩・D・怀特曼及其同事在一项长达十年的纵向研究中证实了这一点。他们追踪了 184 个家庭从子女早期青春期到成年早期的家庭关系变化，发现在长子离家后的一年内，母亲和父亲都报告与离家子女的冲突显著减少。具体而言，母亲报告的冲突频率下降超出了正常发展轨迹，父亲的报告也显示类似模式。</p><p>更重要的是，这种改善还表现在情感亲密度的提升。离家的年轻人自己报告说，与父母的亲密感在离家后有所增加，超越了他们之前的发展轨迹。康涅狄格大学人类发展与家庭科学系的教授兼系主任伊娃・S・莱夫科维茨在 2005 年的研究中发现，78% 过渡到大学的年轻人报告亲子关系发生了变化，其中超过 80% 的人将这些变化描述为积极的，例如「感觉与父母更亲近」、「沟通更开放」、「争吵更少」。</p><p>这种关系转变的深层意义在于，它标志着从等级制的监护关系向平等的成年人关系的过渡。年轻人开始被视为独立的决策者，而不是需要指导的孩子，这种认可本身就是独立性发展的重要组成部分。</p><h2 id="获得空间探索我是谁"><a class="markdownIt-Anchor" href="#获得空间探索我是谁"></a> 获得空间，探索「我是谁」</h2><p>这一点可能是最重要的：身份认同。</p><p>杰弗里・阿内特是克拉克大学心理学研究教授，也是 <em>成年初显期</em>（大约 18-25 岁）理论的创始人。他在 1995 年开始对 18-29 岁的年轻人进行深度访谈，历时五年访谈了 300 名来自不同族裔、社会阶层和地理区域的美国年轻人。阿内特指出，<em>成年初显期</em> 最显著的特征是「身份探索的年龄」。在这一阶段，年轻人探索爱情和工作中的各种可能性，逐步做出持久的选择。通过尝试这些不同的可能性，他们发展出更明确的身份认同，包括理解 <em>自己是谁</em>、<em>自己的能力和局限是什么</em>、<em>自己的信念和价值观是什么</em>，以及 <em>如何融入周围的社会</em>。</p><p>离开父母家在这一过程中起到了关键作用。它创造了必要的物理和心理空间，让年轻人能够进行独立探索。当年轻人搬出父母家时，他们面临着从 <em>决定晚餐吃什么</em> 到 <em>是否结婚</em> 等各种独立决策。这种自主决策的练习是身份形成的核心。<em>成年初显期</em> 也因此成为「自我专注的年龄」—— 大多数美国成年初显者在 18 或 19 岁搬出父母家，直到至少接近 30 岁才结婚或生育第一个孩子。在青少年依赖父母和成年人在爱情与工作中的长期承诺之间，成年初显者专注于自我，发展他们成年生活所需的知识、技能和自我理解。</p><p>阿内特还指出，<em>成年初显期</em> 是「不稳定的年龄」。年轻人在探索爱情和工作的不同可能性时，生活往往不稳定。美国社会 18-29 岁年龄段的居住变动率远高于其他任何生命阶段。这种不稳定性反映了他们生活中正在进行的探索 —— 有些人搬出去上大学，有些人仅仅为了独立而搬出；他们可能因为退学或毕业而再次搬家；他们可能搬去与恋爱伴侣同居，然后在关系结束时搬出。这种看似混乱的模式实际上是身份探索的表现，每一次搬迁都代表着对新可能性的尝试。</p><h2 id="建立财务独立与自给能力"><a class="markdownIt-Anchor" href="#建立财务独立与自给能力"></a> 建立财务独立与自给能力</h2><p>这一点显而易见，但至关重要。如果你问人们「成为一个成年人」意味着什么，排在首位的答案之一总是「财务独立」。搬离父母家为此创造了必要性。</p><p>杜克大学社会学和人口健康科学教授迈克尔・沙纳汉在生命历程研究和成年过渡方面具有深厚的学术积累。沙纳汉明确指出，独立生活是成年初显期的关键发展任务之一。离开父母家会直接促使年轻人发展自给自足的能力。他们必须学会管理预算、支付账单、购买食品杂货、处理住房相关事务 —— 这些日常责任的累积培养了自力更生的能力。</p><p>来自全国青少年到成年健康纵向研究的数据显示了财务独立的复杂性。研究者安娜・曼佐尼使用马尔可夫模型分析了年轻人进出父母家的转变及其与代际财务转移的关系。她发现了一种「部分独立」状态（不与父母同住但接受父母财务支持）在年轻人中非常普遍。重要的是，参加四年制大学的年轻人在大学期间接受父母财务支持后，更有可能在随后过渡到完全独立（既不与父母同住也不接受财务支持）。这表明，离开父母家，即使最初伴随着财务支持，也为最终实现完全财务独立奠定了基础。</p><p>明尼苏达大学家庭社会科学学院的研究进一步证实了这一点。研究者使用 2005-2015 年收入动态面板研究的数据，追踪了 1719 名 18-27 岁年轻人的四项财务独立指标。他们识别出四种财务独立轨迹：<em>持续独立</em>、<em>快速独立</em>、<em>逐渐独立</em> 和 <em>持续受支持</em>。关键发现是，经历 <em>快速独立</em> 轨迹的年轻人最终报告了更高的财务安全感。</p><p>这些发现揭示了一个重要机制：独立生活让你为自己的生活买单，迫使你培养出坚固而可转移的财务管理和生活自理能力。这些在真实压力下习得的技能，是终身独立的基础。</p><h2 id="对心理健康的复杂影响"><a class="markdownIt-Anchor" href="#对心理健康的复杂影响"></a> 对心理健康的复杂影响</h2><p>因为很复杂，所以长话短说：成功地独立生活，通常是对 <em>自我效能感</em> 的巨大提升。你觉得自己有能力、能胜任，这本身就是心理健康的核心。</p><p>然而，来自鲍灵格林州立大学的研究团队利用托莱多青少年关系研究的纵向数据，对 891 名成年初显者进行了分析，探讨了居住安排与抑郁症状之间的关系。</p><p>研究发现，从未离开父母家和独立生活的成年初显者报告的抑郁症状显著低于返回父母家的人。具体而言，返回者的抑郁症状平均高出约 2 分（在 6-48 分量表上），这一差异在控制了先前抑郁症状、父母亲密度、性别、种族、家庭结构、母亲教育、就业 / 在学状态、关系状态和子女数量后仍然显著。</p><p>这一发现揭示了离开父母与心理健康之间的复杂机制。独立生活本身与较低的抑郁症状相关，但这种积极效应取决于独立的质量和原因。对于那些能够维持独立的人来说，独立生活增强了 <em>自我效能感</em> 和成年身份认同。然而，对于那些因负面事件被迫返回的人来说，返回可能被感知为「倒退」或下行轨迹的一部分，与独立、自给自足的成年人自我形象相冲突。</p><p>研究还发现，居住动机起着中介作用。那些因为「享受与父母同住」（内在动机）而与父母同住的人报告了较低的抑郁症状，而那些因为「失业或找不到工作」（功利性动机）而同住的人报告了较高的抑郁症状。更重要的是，就业问题调节了返回父母家的效应：只有在经历就业问题的情况下，返回父母家才与更高的抑郁症状相关。</p><p>这些发现指向一个关键机制：离开父母和维持独立被视为成年的传统标准，当年轻人能够成功实现和维持这一状态时，它增强了他们的自我评估，确认了他们正在向成年标准前进。相反，无法维持独立可能损害 <em>自我效能感</em>，影响追求教育或者职业机会、寻求恋爱伴侣和维持健康关系的能力。</p><h2 id="迎接挑战获得成长"><a class="markdownIt-Anchor" href="#迎接挑战获得成长"></a> 迎接挑战，获得成长</h2><p>诚然，搬离父母家不是解决所有问题的「万灵药」，在当今高房租和劳动力市场不稳定的社会中，独立之路也比以往任何时候都更加复杂。</p><p>但是这个过程仍然至关重要。</p><p>搬离父母家提供了一个发展性的「一揽子交易」：</p><ol><li>它将你的家庭关系 <strong>重置</strong> 为成年人之间的相互尊重。</li><li>它为你 <strong>建立了空间</strong> 去构建和整合你的独立身份。</li><li>它 <strong>迫使你</strong> 学习真实世界的生存技能。</li><li>当你成功应对这些挑战时，它为你带来了 <strong>核心的胜任感</strong>，并将伴随你一生。</li></ol><p>离开父母家庭是 <em>成年初显期</em> 最艰难、也最重要的一次挑战。正是这些挑战，最终帮助我们成长为自主、有能力的成年人。</p><h2 id="引用"><a class="markdownIt-Anchor" href="#引用"></a> 引用</h2><details>  <summary>只是演讲稿的引用</summary><ul><li>Arnett, J. J. (2000). Emerging Adulthood: A Theory of Development From the Late Teens Through the Twenties. The American Psychologist, 55(5), 469–480. <a href="https://doi.org/10.1037/0003-066X.55.5.469">https://doi.org/10.1037/0003-066X.55.5.469</a></li><li>Aquilino, W. S. (2006). Family Relationships and Support Systems in Emerging Adulthood. In J. J. Arnett &amp; J. L. Tanner (Eds.), Emerging adults in America: Coming of age in the 21st century (pp. 193–217). American Psychological Association. <a href="https://doi.org/10.1037/11381-008">https://doi.org/10.1037/11381-008</a></li><li>Aquilino, W. S. (1997). From Adolescent to Young Adult: A Prospective Study of Parent-Child Relations during the Transition to Adulthood. Journal of Marriage and Family, 59(3), 670–686. <a href="https://doi.org/10.2307/353953">https://doi.org/10.2307/353953</a></li><li>Whiteman, S. D., McHale, S. M., &amp; Crouter, A. C. (2011). Family Relationships From Adolescence to Early Adulthood: Changes in the Family System Following Firstborns』Leaving Home. Journal of Research on Adolescence, 21(2), 461–474. <a href="https://doi.org/10.1111/j.1532-7795.2010.00683.x">https://doi.org/10.1111/j.1532-7795.2010.00683.x</a></li><li>Lefkowitz, E. S. (2005). Things Have Gotten Better: Developmental Changes Among Emerging Adults After the Transition to University. Journal of Adolescent Research, 20(1), 40–63. <a href="https://doi.org/10.1177/0743558404271236">https://doi.org/10.1177/0743558404271236</a></li><li>Serido, J., Shim, S., &amp; Tang, C. (2013). A developmental model of financial capability: A framework for promoting a successful transition to adulthood. International Journal of Behavioral Development, 37(4), 287–297. <a href="https://doi.org/10.1177/0165025413479476">https://doi.org/10.1177/0165025413479476</a></li><li>Copp, J. E., Giordano, P. C., Longmore, M. A., &amp; Manning, W. D. (2017). Living With Parents and Emerging Adults』Depressive Symptoms. Journal of Family Issues, 38(16), 2254–2276. <a href="https://doi.org/10.1177/0192513X15617797">https://doi.org/10.1177/0192513X15617797</a></li></ul></details></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我在公开演讲课上的一次信息性演讲内容。这篇文章是我的演讲稿的超级增强版。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="心理学" scheme="https://blog.cytrogen.icu/tags/%E5%BF%83%E7%90%86%E5%AD%A6/"/>
    
    <category term="社会学" scheme="https://blog.cytrogen.icu/tags/%E7%A4%BE%E4%BC%9A%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>想法在乙巳开冬迭代</title>
    <link href="https://blog.cytrogen.icu/posts/ea48.html"/>
    <id>https://blog.cytrogen.icu/posts/ea48.html</id>
    <published>2025-11-02T05:34:23.000Z</published>
    <updated>2026-02-09T17:16:55.249Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>开冬不愧是开冬，前段时间还觉得有点热，现在每天都是冻醒的。这个月，我在缓慢地调整我的生活 —— 从兼职、工作、学业和自己。我还在摸索「想法迭代」这类文章的架构，所以该文章相较于 <a href="/posts/dc84.html">上篇文章</a> 会有显著的差异。</p><span id="more"></span><h2 id="日记"><a class="markdownIt-Anchor" href="#日记"></a> 日记</h2><p>我决定调整一下日记板块的内容。该板块会注重于一些篇幅不长、专注于生活的内容。我希望展开讨论、有一定深度的内容则会在日记板块的后面。不过写太多的内容会被我编辑成独立文章发布，我在这里只会给它们留个标题的位置（或者一丢丢补充说明）。</p><h4 id="perplexity-会员体验"><a class="markdownIt-Anchor" href="#perplexity-会员体验"></a> Perplexity 会员体验</h4><p>PayPal 的首页上有个领取福利的栏块，我一直都没有去看。一次突发兴起，我领取了 Perplexity 的一年免费会员。因为我还是个学生，还可以用学校的邮箱再领取一年。</p><p>Perplexity 是一个基于大语言模型的应用程序，功能比较多，主要是帮助用户更好地搜索、研究。你想要搞清楚的问题，Perplexity 都会帮你「搜索」、「总结」。因为它会搜索网上的资源，因此幻觉不会太严重。就是有时候它会直接略过搜索这一步骤、根据自己的训练数据告诉你答案。</p><p>另一个起眼的功能是新闻板块，它会自动抓取线上的新闻、结合成数个文章，并展示给用户。我个人用下来，新闻板块几乎没有主动看过。它每天都会推送给我一些新闻，我也都没有去看。除了个别新闻我有看 —— 例如联邦政府罢工一事 —— 其余的几乎都是「特朗普今天又做了什么」的新闻。</p><p>我用的最多的是研究功能，主要是深入某个主题、靠问数个问题来得知客观数据。不过我试了下、使用了 Perplexity 辅助写作，并发现了一个问题：我的想法会被它无比正确的研究和数据左右。我大概写了几篇文章作为比对，其中有几篇我感觉很失望。内容虽然很正确、很对、无法纠错，但看着只让我感觉挫败。还是得要我自己写好文章，然后再去找 Perplexity 查找对应的数据。</p><p>自然，这并不是 Perplexity 的问题。无论我用什么 AI 工具，只要在最开始起稿的时候就使用并且依赖它们，都会落得这样的结果。</p><h4 id="咪咪"><a class="markdownIt-Anchor" href="#咪咪"></a> 咪咪</h4><p>家里人从家附近捡了个小猫回来。刚捡回来的时候，小猫的身上全是跳蚤在爬，我母亲根据养狗的经验，直接用带药的宠物沐浴乳洗了一遍猫。这样做其实很危险，小猫还未打疫苗，洗澡容易导致问题。好在它之后表现得十分健康和好动，没过几天就会用「猫猫拳」打狗的鼻子，吃完猫粮后还会偷偷再吃狗的饭。</p><p>我找了一天回父母家、带小猫去医院做检查。我预约的是 Vetco，载着三人一狗一猫开了半小时的路才到。谁曾想 Vetco 这期间给我发了消息，说本次预约不正确、医生不在，需要我回电让他们客服进行人工预约。没办法，我们只是在那附近的零售连锁店买了一些猫玩具和猫抓板回去。</p><p><img src="/posts/ea48/mimi.webp" alt="幼年三色猫盖着被子在狗窝里" loading="lazy"></p><p>尽管想着之后有空的时候再预约一次，结果到十月底我没有一天是闲着的。我的天啊 ——！</p><h4 id="兰州牛肉面"><a class="markdownIt-Anchor" href="#兰州牛肉面"></a> 兰州牛肉面</h4><p>小时候住的巷子的路口有一家兰州牛肉面馆，特别好吃。这家店最稀奇的在于，老板是一位犹太人。他不仅管接客收银，面也是他在一个大铁桌上亲手拉的。我记得他会很用力地摔面，发出很响的声音。有时候会看见他的妻子和儿子，长相也是非常接近我们传统印象里的犹太人样貌：金发、黑衣、戴眼镜。</p><p>学校附近有两家兰州牛肉面馆。我常去的这家免小费，不过单品价格并不便宜。我点了一份兰州牛肉面和一个肉夹馍。他家的肉夹馍味道很不错，税前 7 美元一个。</p><p><img src="/posts/ea48/noodles.webp" alt="洒满香菜的兰州牛肉面和一个肉夹馍" loading="lazy"></p><h4 id="中秋游行"><a class="markdownIt-Anchor" href="#中秋游行"></a> 中秋游行</h4><p>中秋那天，布鲁克林的日落公园区有中秋游行，据说是 BBA（繁荣布碌仑协会，Better Brooklyn Association；这里的布碌仑是布鲁克林的另一种说法）举办的第二次中秋游行。游行里有数个学校的学生在演奏乐器、表演舞蹈，还有一个环节是一群玩偶服的人在朝街边扔毛绒玩具。神奇的是，游行队伍的最后还有长乐游神。</p><h4 id="妹妹的游泳比赛"><a class="markdownIt-Anchor" href="#妹妹的游泳比赛"></a> 妹妹的游泳比赛</h4><p>妹妹第三次比赛游泳，也是我第一次开车上高速。没开过那么快的车，脚感很不习惯，不过感觉没什么问题。这次妹妹比赛的场地在新泽西。不知为何，教练给她选了个 100 码的比赛项目。50 码后她明显变得力不从心。</p><p>因为家人的影响，妹妹有些「一根筋」，比赛结束后不敢去问教练能否提早离开，导致我们晚了一小时才离开现场。下午饭依然是吃越南面，不过这家餐厅装修更高档、食物味道更好，随之提升的还有价格。好在份量不小，三个人就着俩主餐、一小吃和一碗加的面吃饱了。</p><h4 id="e-fika"><a class="markdownIt-Anchor" href="#e-fika"></a> E-Fika</h4><p>我的辅修是日语。大学的日语部门要求我这学期参加两期信州大学的英语部门学生们举办的 E-Fika。Fika 是瑞典的一个类似于茶会的活动。你可以带自己的饮品、食物来参加，要做的事情只有两个：休息和聊天。而 E-Fika 就是线上的 Fika，大家用 Zoom 开着摄像头互相认识、聊天。我起先发现的是，信州大学的学生们讲英语明显要比我们讲日语利索许多。</p><p>我的日语水平在班上算是偏好的，可以模仿本地人的一些腔调。不过真让我和本地人用日语交流的话，还是算了吧！</p><h4 id="语言是死去的诗歌"><a class="markdownIt-Anchor" href="#语言是死去的诗歌"></a> 语言是死去的诗歌</h4><p>网上冲浪时，我发现了一个帖子，内容是帖主在一次思索时发现「不如」这个词的意思就是「我的提议更好、你的想法比不上我的」。评论区的人们发表了众多他们发现的一些有趣例子，比方说：</p><ul><li>「不知道」：「道」是一切的本源、组成万物的基本单位，那「不知道」不就是「什么都不知」的意思吗？（哎哟我才发现除了「不知道」外我都不知道该如何表达「不知道」的意思，像这句话里我又用了一次「不知道」）<ul><li>不过现在「道」已经虚化成补语，表示「知晓」的结果，而非指称哲学意义上的「道」。</li></ul></li><li>「开水」：想象「开花」，「开水」便是「水像花一样盛开」。</li><li>「披风」：「披着风」。</li><li>「未来」：「还未来到的」。</li><li>「故事」：「过去的事情」。</li><li>「太空」：这里的「空」是「空间」的意思，「太」则是「大之甚」，放一起便是极大的空间。</li></ul><p>我觉得很有趣，简单研究了一下，发现这涉及到一个概念 —— <em> 语义透明度</em>。意思是复合词的整体意义能够从构成它的语素意义推知的程度。学者们将复合词分为了不同类型：</p><ul><li>完全透明的词：词义基本等于语素意义的直接相加，能从语素义直接推求词义</li><li>半透明或不透明的词：整词语义与语素意义存在差异，甚至完全不相关</li></ul><h4 id="新鼠标"><a class="markdownIt-Anchor" href="#新鼠标"></a> 新鼠标</h4><p>我换了个新鼠标，因为旧的鼠标按键有点坏了。这次买的是人体工学鼠标，没我家里的那款鼠标「垂直」，不过大小很匹配我的手。室友感觉有点大。</p><p><img src="/posts/ea48/anker.webp" alt="Anker 人体工学鼠标" loading="lazy"></p><h4 id="外卖和小费"><a class="markdownIt-Anchor" href="#外卖和小费"></a> 外卖和小费</h4><p>十月中旬，天气开始变冷了，我也比以往晚醒了一小时半的时间。有一天打工，我忘了带下午饭，所以点了个预订送达的外卖。我用的平台是饭团外卖，说是有活动，肉夹馍 0 元。自然这个便宜在北美的外卖平台里是占不到的，平台费小费等东西加起来，变成了比肉夹馍原价还要贵一点的价钱。如果没有这个活动，一个肉夹馍说不定就要 12 美元呢！更可恶的是，这个肉夹馍没有青椒就算了，里面放的还是青葱和洋葱。整体也就比我的手大一点，几口就被我吃干净了。</p><p>大一的时候我很喜欢用熊猫外卖，当时的一个十元吃饱活动，一碗土豆粉真的就是十元多。后来纽约市要求顾客必须至少给外卖员固定比例的小费。小费文化真是个糟蹋，我也不理解为什么有人会喜欢这东西。一次网上冲浪，我表达了对小费文化的厌恶，还有个人阴阳怪气地回复我，说我在这里说没用、要去申报才行。</p><p>这样说的话，是不是送外卖也很赚钱呢？我要不要也去送外卖看看？</p><p>不过几天后老板告诉我熊猫外卖多了个「0 服 0 运」，说是服务费和运费都不收。我试着点了一份米线外卖，9.99 美元加 3.8 美元的额外米线，再加上 1.22 美元的消费税，实际支出 15.01 美元，连小费都不需要给。这让我好奇商家、平台和外卖员都是如何靠此盈利的。</p><h4 id="越南春卷"><a class="markdownIt-Anchor" href="#越南春卷"></a> 越南春卷</h4><p>室友买了一堆原材料，包了个越南的 summer roll（脍卷、夏卷，或者直接说越南春卷）给我吃。</p><p>做法很简单：首先是煮越南的一种粉，然后煮虾剥虾、切黄瓜丝萝卜丝等。米纸沾水拿来包这些材料。为了不破掉，要在米纸还有点硬的时候就开始包。酱料则是花生酱、番茄酱、耗油和热水搅拌而成。</p><p>她的师傅是十几家餐厅的老板，其中一家餐厅便是专门做越南菜的。他家的脍卷酱料非常好吃，我跟她经常会抢着要。现在我和室友还没有搞懂里面究竟放了什么，只知道有猪肝在内。</p><p>学会做了脍卷后，室友很贴心地为我包了一些带去工作吃。因为没有小盒子装酱料，她故作聪明地把酱料包在了米纸内。结果就是，等我要吃饭的时候才发现皮全部破了、酱料也都流得到处都是。</p><p>后面我们太懒了，直接省去「包」这个步骤，将米纸沾水揉成一团，然后切成数个小条条、直接蘸酱吃。口感很像更硬一些的肠粉。而整道佳肴则变得更像是一种拌面：</p><p><img src="/posts/ea48/summer.webp" alt="没有卷起来的脍卷，放了水煮蛋、黄瓜片、虾和越南粉" loading="lazy"></p><h4 id="玩桌游"><a class="markdownIt-Anchor" href="#玩桌游"></a> 玩桌游</h4><p>一天周日，我和室友以及她的一个朋友来办公室玩 <em>茂林源记</em>。我先前就玩过这游戏，刚开始玩的时候很上头。这游戏的美术风格我很喜欢，最初我是在一个桌游吧看到的，但是因为它的规则书而被劝退（当时我还只会玩 <em>炸弹猫</em> 等较悠闲的桌游）。之后我看到了 <a href="https://store.steampowered.com/app/965580/Root/">Steam 版本的 <em>茂林源记</em></a>，实在是太想入手，便买了个玩。入门期间我发现它的规则其实并不难接受，遂推荐给室友玩，没想到她比我还上头，直接买了实体的桌游和扩展。</p><p><em>茂林源记</em> 的故事设计我认为很有创意：一个森林原本被 <em>飞鹰王朝</em> 控制。他们有规律地生活、完全遵循于法条。结果主张工业发展的 <em>猫咪贵族</em> 侵入森林，将飞鹰们打跑，并希望统治森林。飞鹰不甘心，想打败猫咪、重新夺回森林。森林里的其他阵营也想要达成自己的目的：想要和平、由百姓组成的 <em>森林联盟</em>；只为自己出名声的 <em>神秘游侠</em>；渴望从战争中谋取财利的 <em>河岸商会</em>……</p><p>游戏阵营很多，规则也各不相同，因此这游戏入门比较困难。你不只是需要搞明白自己在做什么，也得明白其他人如何计分，以及如何阻碍他们计分。但又因为规则各不相同，阵营之间也是有着克制关系和不平等的强度：有些阵营遇到特定阵营玩起来就是很难受；有些阵营强度就是高到离谱；有些阵营玩起来就是异常艰辛。尽管它的美术风格十分可爱，但认真玩起来就能感受到其中的竞争元素，也就是要杀个 <strong>你死我活、不留情面</strong>。尽管有些阵营一旦玩起来，几乎就赢不了，但可以想尽办法让原本要赢的人没法赢，简称搅屎棍。这一刻，游戏又变回了 <strong>人情世故</strong> 的样子。</p><p>那我推荐这款桌游吗？如果你喜欢玩德式桌游，也有乐意玩德式桌游的伙伴们，那可以尝试一下这款游戏。我认为玩这款游戏比较重要的是 <strong>是否在意刻意对抗</strong>，因为这款游戏有许多要求玩家们刻意攻击彼此的设计，不像部分德式桌游竞争意识没那么激烈。这游戏几乎很难和平地玩下去。</p><p>如果你是一个不喜欢和真人起冲突的玩家，我不是很推荐，只能说可以试试。因为 Steam 版本的 <em>茂林源记</em> 有人机模式，实体版则有机器人扩展（就是要花更多的钱）。</p><p>我还为这款游戏写过一个 Steam 评测：</p><blockquote><h4 id="优点"><a class="markdownIt-Anchor" href="#优点"></a> 优点</h4><ul><li>给没玩过 <em>茂林源记</em> 的玩家：这款游戏的原身是 <strong>非对称战争桌游</strong>，特色是每个阵营的玩法都很不一样。</li><li>给玩过一点线下桌游的玩家：相比起游戏线下那一大本规则书，数字版有个好处是它自己会帮你算规则。萌新想入坑的话从数字版开始会轻松很多，并且数字版有教程关。只是数字版玩多了再去玩线下桌游容易出现村规的问题。</li><li>美术风格很香：画面看着挺舒服的，3D 小动物模型也挺有特色。不过某些 DLC 里的模型很敷衍。</li><li>BGM 很赞，我线下玩桌游的时候都时不时拿出来当背景音。</li><li>单机玩的情况下数字版提供了挑战关和人机局。就是人机实力很不稳定，尤其是人机飞鹰，你赢了的时候它可能都已经把所有的领袖动乱了一遍、10 分都没有。</li></ul><h4 id="缺点"><a class="markdownIt-Anchor" href="#缺点"></a> 缺点</h4><ul><li>给没玩过 <em>茂林源记</em> 的玩家：这游戏本身是 <strong>King Maker 类游戏</strong>，也就是分少的人可以因为「<em>反正自己也赢不了，但又不想让你赢，还不如让另一个人赢</em>」的想法，而完全投入在帮助其他阵营导致原本可以赢的你大输特输的游戏。游戏的阵营强度是不一致的，有些阵营只要你选择去玩、你之后就一定要坐牢。</li><li>游戏大厅设计简直是上古世纪的产物，社交功能除了一个加好友，就只有屏蔽别人以及在大厅里喊话摇人。有时候玩线上还会碰到开局就跑的奇葩，在同步局里你要白白等六分钟才能等到这个人被机器人托管。</li><li>汉化做的特别特别烂，尤其是越来越新的 DLC。二扩 2023 年出的，游戏规则里干脆显示的英文；三扩 2025 年年初出的，你能看到老鼠的翻译一会儿是百人团一会儿是群鼠。</li><li>又是三扩，模型和动作肉眼可见的敷衍。谁小动物晕倒是睁着眼睛盯着前方好似要入党一样晕啊。真就是随便糊弄一下，影响了整体的游戏品质。</li></ul><h4 id="给萌新的建议"><a class="markdownIt-Anchor" href="#给萌新的建议"></a> 给萌新的建议</h4><ul><li>先学会怎么玩猫，之后再慢慢学习游玩其他阵营。猫猫是最适合新人学习这款游戏的基础规则的阵营，不要因为听说猫猫弱就嫌弃猫猫。当你觉得初始四个阵营都多多少少玩明白了再考虑是否要购入 DLC。</li><li>线上开房间要选「同步」（SYNC），加别人房间时也要认准同步。同步模式下你一个回合是三分钟，三分钟过了机器人会暂时托管你。如果机器人已经托管了你一次，第二次托管就是永久托管；非同步模式是一个回合三天。</li><li>这款游戏的目的永远都是得分。要保证自己能得分的情况下再去阻碍别人得分，除非比分差太大了。</li></ul></blockquote><p>我个人不是一位那么喜欢对抗的玩家，尤其是会和其他人产生冲突的游戏我都不是很爱玩。比如 MOBA 类我都不爱玩，因为我觉得我会和队友起矛盾（毕竟游戏里也就 10 个人，五五分组大家分工都明确），再就是我技术很差；吃鸡类则还好，我只跟朋友联机玩，并且几乎不会和敌人有任何互动，击败敌人或者被敌人击败都没有什么怨言。我后面开始慢慢放弃 <em>茂林源记</em> 就是因为这个：有时会遇到莫名其妙的玩家、在聊天室内散发恶意，十分毁体验。</p><h4 id="演讲"><a class="markdownIt-Anchor" href="#演讲"></a> 演讲</h4><p>我这个学期有节公开演讲课，竟然是我这个专业的必修课，很是无语。第二场演讲是关于 <em>信息性演讲</em>，也就是向听众传达特定信息或者知识。演讲结束回家后和室友吵了一架，一肚子的事情无法分享出来，只好一边淋浴一边对着手机录音。我用的是摩托罗拉手机自带的 Moto Note，貌似这也可以被称之为「说客」？结果期间我发现，我用「说」来表达想法很吃力，会迟钝和卡壳。看来我还是需要培养「说」的能力。洗完后才发现手机录到一分钟便自动熄屏了，连带着 Moto Note 一起被关闭。也就是说，我一个人在卫浴里自言自语了不知道多久！</p><p>室友在卫浴间旁边的厨房做饭，也听到了我的自言自语。她说让她想起了 <em>模拟人生 4</em> 里她捏的一个带有「古怪」特征的角色：平日也会自言自语，但是游戏会贴心地标记成「在和朋友聊天」。</p><p>说回那天的演讲，我本来是非常焦虑的，以至于一周前我一直处于「脑子无法静下来」的状态。之后看到了同学们带的笔记卡比我的还厚，我便慢慢冷静了下来。过去我从订阅的博客那边看到了一个句子，让我很喜欢：<em>比较是偷走幸福的小偷</em>（后面得知是西奥多・罗斯福说的）；现在我要加一句：<em>当它往下比的时候，就成了幸福的快递员</em>，哈哈。</p><p>部分同学们想了些我觉得很有意思的主题，例如会发光的生物、创伤对人类大脑的影响、政治娱乐化等。但有一部分主题就让我感觉很无聊了：这里的大家都在说，好似不说就是一种「不正确」。至于是什么主题，我或许会在未来扩展说说吧。</p><p>总之，我的演讲是关于「离开家庭对成年子女的影响」。具体的演讲内容我会在未来以文章的形式发布出来~ 现在专心于「我在演讲」这件事：因为太过于焦虑「演讲」这件事本身，在实际的演讲中我完全没有关心台下观众可能对我投来的眼光或者持有的想法，反而很快速和流畅地讲完了。做这类我不擅长的事情，我会倾向于玩起「角色扮演」，也就是想象别人会怎么做、自己跟着效仿。这应该是 <em>解离</em> 的一种？可悲的是，我在「扮演」一个我行我素、能够活跃气氛的角色时，我对着教授做了个鬼脸，对方没能瞬间 get 到，我也没能化解接下来的尴尬气氛。我都不知道我在做什么！</p><h4 id="朋友的信用卡被盗刷"><a class="markdownIt-Anchor" href="#朋友的信用卡被盗刷"></a> 朋友的信用卡被盗刷</h4><p>我的一位朋友的信用卡不知为何被盗刷了，她立即找了银行换了新卡、寄回自己在纽约市的家。结果这张新卡还没到家的信箱里就被偷了，被盗窃者在当地的某个工厂里刷走了六千美元。当时朋友还在很远的大学里上课，突然看到银行给自己发短信、询问这笔交易是不是她弄的，整个人都不好了。更悲剧的是，她明明回复了「NO」，钱还是被刷走了。这让我和她都怀疑，这种确认短信的存在意义是什么？</p><p>继续说，朋友之后打电话给银行要索赔。银行先是在内部调查了不知道多少天，调查结束后拒绝了她的要求。因为这一阶段的「要索赔」不会提供任何证据，也没有任何声明，银行也不愿意直接给她六千美元。她询问我接下来该怎么办好，我让她先在 FTC（Federal Trade Commission，联邦贸易委员会）网站上报告自己的信息被盗、信用卡也被盗刷。这一步是为了拿到《FTC 身份盗窃宣誓书》，好去警察局报案。有了警方报告的副本后，就可以再去银行上诉了。</p><p>这听上去好似是个还可以的计划，但是万万没想到，数周前 Perplexity 给我发送的「联邦政府因没有筹资而罢工」这一新闻，以另一种方式重新回到我的脑内：FTC 的网站也罢工啦！我只能叫朋友直接去找当地警局，但她好像并没有听进去、次日直接跑去了当地银行上诉。这也不是不行，问题是这个环节里银行可能会要很多证据，比如当时不在纽约市的证据。她压根没有做任何准备，只能在那里手写了一个声明，说自己当时不在纽约市、也在短信里回复了「NO」。</p><p>让我有些气不过的是，我前一天还跟她解释了一遍她要去找谁、做什么，结果她第二天什么都没有地跑去了银行，在群里哭诉说没有文档。我问她什么文档，她说不知道、是银行职员跟她说的。我问她去警局了吗，她又好像第一次听到我提及警局一样，问我为什么要去警局、去当地的警局吗、要打 311 吗…</p><p>整体来说，这里出现这种事情就是很麻烦。很多事情都要求你会，虽然从某个角度来看，也是强迫你独立、是一种好事。但我讨厌这样，很烦哎，有些事情我就不能从最开始就避免发生吗？所以我的态度还是「讨厌」。</p><h4 id="有意思的顾客们"><a class="markdownIt-Anchor" href="#有意思的顾客们"></a> 有意思的顾客们</h4><p>做服务业很容易碰到有意思的顾客，这个月一些我印象深刻的：</p><ul><li><p>两个学生，买一个东西 6.26 美元，甲求着乙帮她付。乙起先说可以付 6 块，在甲的万般请求下帮付了 6.20 美元，甲则刷卡支付了剩余的 6 美分。后面甲还想买东西，老板看她没零钱，给她抹了零。</p></li><li><p>有一位看上去就有点问题的男孩。他作为孩子脸、长得很高，不停地走来走去，还询问了我数个问题：「要多久啊？这么多单的话，我可以跟后面的人说他们要等一会儿吗？」</p></li><li><p>万圣节的那天，店里直接走进来一个黑人把小费罐里的硬币拿走了。虽然也不算「顾客」啦……</p><p>我当时看着他一直伸手掏，脑海里想着：</p><ul><li>「罐里都是硬币，没多少钱，罐子本身还很深，他这样一直掏是因为『已经走进来了，必须得拿一把走，否则会很尴尬』吗」</li><li>「这个社会好野蛮，有人光明正大拿东西都没有人会阻止。就算我要阻止，他也会一拳打爆我的鼻梁，然后逃之夭夭、就算被抓了也没有钱赔我吧。这个社会就是因为最开始有人放纵了恶人，才会慢慢发展成这样的」。</li></ul></li><li><p>同样是万圣节，一个钉子头凶狠地走了进来，给我展示了一张纸，上面写着他已经过了要糖的年纪，但他可以为了自己的弟弟妹妹要糖。我可以选择给他糖，或者让他去做恶作剧。值得难过的是，他来的太晚了，糖果早在下午就被小孩子们拿光了。</p></li></ul><h4 id="楼下老头"><a class="markdownIt-Anchor" href="#楼下老头"></a> 楼下老头</h4><p>一天晚上我在玩 <em>模拟人生 4</em>，室友在一边逗猫。不知道是猫的跳跃声太大还是什么，触动了楼下老头的神经，他朝着天花板捶了数下。因为之前物管找我们打过招呼，说这个人很奇怪，是整栋楼里唯一一个会频繁举报楼上声音吵的人，并且态度奇差无比、很凶很急躁。我们搬进来后一直都是小心翼翼的，后面住久了差不多知道了他的愤怒阈值，例如猫的跳跃声就不会吵到他。这次反而吵到了、让我很意外。</p><p>之后室友去把吸尘器从我的桌子旁挪动到厨房，却没有料到插头一直插在插排上，导致电线绊倒了桌子上的书、连带着吸尘器一起倒了下去。楼下老头先是对天花板砸了十几下，接着打开自己的门跑了出来，对着走廊的墙还是门砸了几下，然后摔门回屋去了。</p><p>我只能说，虽然大晚上我们还在活跃并且导致这些声音都是我们的不对，但是他的处理方式很糟糕，只能让我们感到非常害怕，生怕他接下来跑上楼砸我们的门（他过去确实对着上一家住户做过）。</p><h4 id="去香港交换的校友"><a class="markdownIt-Anchor" href="#去香港交换的校友"></a> 去香港交换的校友</h4><p>我去见了一位去香港做了一年交换生的校友。他这一年在亚洲的各个国家旅游玩耍。虽然只有一年，但觉得他离开了很久。不过不得不提，他的生活习惯实在是糟糕。作为一个刻板印象里的美国青年，他有喝酒、抽「叶子」、玩女人的习惯，在香港没少去夜店喝个烂醉、跟很多女人有过一夜情。</p><p>校友告诉我，这期间他喝酒还被下过药，一觉醒来发现自己赤身裸体在一个陌生女人的房间里。对方直接坐到他身上，要求他支付自己一千美元。他虽然看起来傻傻的，但还是跑了，一千美元也没到对方手里。回到美国后他发现对方还给自己发过邮件，威胁说如果不交就找黑帮弄他。</p><p>我对这个人的看法只能说很复杂……</p><h2 id="书影音"><a class="markdownIt-Anchor" href="#书影音"></a> 书影音</h2><h4 id="书籍"><a class="markdownIt-Anchor" href="#书籍"></a> 书籍</h4><p>我这个月没有怎么阅读书籍。惭愧。不过我可以简单说说我现在持有的书籍。</p><p>我两三四年前（实在是忘了具体时间）买了《阿特拉斯耸耸肩》这套书，包含了它的三部曲。不得不说，这一整套书真的很厚，我觉得只需要拿着一本就可以到处抡人脑袋。内容所提供的信息量也很大，以至于我后悔刚开始阅读的时候没能记笔记：里面的人物实在是太多啦！我现在零零散散地读到了第三部曲。</p><p>和室友同居后我们的书架也合并了，她的纸质书要比我的多得多。像余华的《活着》也是我从她那边读来的。</p><h4 id="影视"><a class="markdownIt-Anchor" href="#影视"></a> 影视</h4><p>这个月和室友重温了《Happy Sugar Life》。动画在播出时我还是个初中生，因为对题材比较感兴趣，期间还追了漫画连载。现在再来看这个动画，感觉节奏很不错、不拖沓。我在漫画完结后就再也没有关注过该作品，没想到作者之后还出了第 11 卷，其中最重要的是讲到了女主之一盐长大后的样子。</p><h4 id="音乐"><a class="markdownIt-Anchor" href="#音乐"></a> 音乐</h4><p>这个月初我没有继续听 YouTube Music 为我在年初时创建的 Recap 播放列表，而是按照它的推荐算法、听了一些它推荐给我的专辑和单曲。其中最让我印象深刻的便是 <em>温室杂草</em> 这支乐队。他们 2021 年发布的单曲《春天有脚》非常好听，很赞。</p><blockquote><p><em>一起离开吧~ 一起离开吧~</em></p></blockquote><p>另一首我比较喜欢的单曲是《快乐的形状》。我很喜欢主唱呼出「快乐」的时候。</p><p><em>傻子与白痴</em> 这支乐队在 2019 年发布的专辑《夜长梦少》我也因推荐去听了。我认为该乐队的音乐风格不是我喜欢的那种，但是我很喜欢他们在该专辑里的一处设计。第七首《Taxi Radio》仅有一分钟，说是「歌曲」很奇怪，它更像是过渡段：一位出租车司机接了几个客人，问他们是不是玩乐队的。客人好似有些尴尬，一个接一个地说「是啊，算是吧」。背景里的电台主持人介绍着一支正在崛起的乐队 —— 傻子与白痴，并播放了该专辑的第八首《美好前程》。</p><p>我还听了 <em>伤心欲绝</em> 的专辑《逊到简直是个艺术品》。不得不说，这些乐队的取名风格实在是艺术，我很喜欢。</p><h2 id="博客"><a class="markdownIt-Anchor" href="#博客"></a> 博客</h2><h4 id="该文章分类"><a class="markdownIt-Anchor" href="#该文章分类"></a> 该文章分类</h4><p>「想法在 YYXX 迭代」可能会类似于月刊，但没有月刊那么正式。为了简单称呼，以下还是称其为月刊。</p><p>这里的 YY 指的是年份，不过是用天干地支的写法，例如二〇二五年叫作乙巳；XX 用的也是中国较为传统的写法。例如九月就是菊月，合在一起叫作「想法在乙巳菊月迭代」。</p><p>我之前给室友看了一些我的日记，她以为我写的「二〇二五年」是出自于日本的年份书写格式。其实这个〇是小写的「零」。这很有意思，因为我们在日常生活中几乎见不到〇，但是其他数字用的都是小写的（如一二三，大写的话则是壹贰叁）。我想起小学的时候，语文老师教过我们如何写大写的数字，以及如何写支票。</p><p>说回月刊，我打算在其中添加我这个月看过的、感受到的、学到的东西。例如我这个月读的书我就可以写在里面，讲讲我的想法；读过的技术文章或者写项目的时候学到的内容也可以写在月刊内；日记片段也可以取一些出来，尤其是那些体量不够我写一篇文章，但是有意思到我想要去分享的片段。我也想要添加我最近听的歌、专辑，应该也会很有意思。</p><p>不写周刊的原因是我认为我没有那个精力、时间去每周写个周刊，万一我这周什么都没做怎么办？但是一个月就足够我去分享些内容。我不打算准时发布月刊，但还是尽量在一个月的上旬发布吧。</p><h4 id="annie-的博客"><a class="markdownIt-Anchor" href="#annie-的博客"></a> <a href="https://anniemueller.com/guestbook">Annie 的博客</a></h4><p>一次意外，我发现了该博客网站，并让我感觉很有意思。不只是站主写的文章很幽默，她的网站设计也很有趣。博客网站里有个很常见的页面，是「友链」，而 Annie 很机智地将其设计成了 <a href="https://anniemueller.com/guestbook">Guestbook</a>（访客留言簿）。你可以在里面留下一条留言、画一张画，然后写下你的名字和网站链接。</p><p>我仿照她的头像简单画了一只猫，并写上了「BE COOL」。目前这条留言应该是还在审核中。</p><p>说回博客文章，我可以看出她是一位很风趣的人。很多文章都采用了夸张、幽默、讽刺的语言。例如十月一日发布的 <a href="https://anniemueller.com/posts/two-small-ui-things-that-might-not-bother-me-if-i-were-a-completely-different-person"><em>Two small UI things that might not bother me if I were a completely different person</em></a>，就狠狠地批评了她发现的两个微小但令人恼火的用户界面设计问题。不需要会读英语，只需要看她贴上的图片和无处不在的大写单词便能看出她有多么地生气，哈哈！</p><h4 id="博客集合平台"><a class="markdownIt-Anchor" href="#博客集合平台"></a> 博客集合平台</h4><p>我从一个订阅的博客那儿听说了 <a href="https://boyouquan.com">博友圈</a>，让我觉得很有意思，可以通过这类平台看到其他博客站主在写什么文章、都是什么样的人在做博客站主。我过去有个刻板印象，觉得博客站主都是程序员。实际上，有许多没有接触过计算机相关工作的人也在做站主。我也看到了 <a href="https://www.travellings.cn/">开往</a>，让我觉得第一个想到这类东西的人真是个天才：我可以从一个博客网站「开」到另一个博客网站，就像大家的博客网站真的都是一个个独立的小岛一样。就是有时候目的地是有问题的站点，很容易出戏。</p><p>我只加入过 <a href="https://github.com/timqian/chinese-independent-blogs">中国独立博客列表</a>，还是我很久之前加入的。虽然我觉得这些平台都非常有意思，但我暂且应该是不会考虑加入的。主要原因有二：有内容监管，以及让别人在一众文章里看到我的笔记什么的很奇怪哎…… 至于友链接力类的项目，我只是不知道该在首页的哪里添加这些链接和按钮。现在的首页菜单实在是太乱、太杂了。</p><h2 id="职场与创业观察"><a class="markdownIt-Anchor" href="#职场与创业观察"></a> 职场与创业观察</h2><h4 id="天使-vs-恶魔的管理风格"><a class="markdownIt-Anchor" href="#天使-vs-恶魔的管理风格"></a> 天使 vs 恶魔的管理风格</h4><p>兼职的店里有两个「头儿」，一个是「天使」，一个是「恶魔」。前者我会在文章里称呼为「经理」，后者则会称呼为「老板」。但他们是不是真的经理和老板呢？我就不知道了。他俩对员工的要求是一个在天、一个在地。经理总是担心员工做不好，觉得大家都是孩子，基本上不会训斥员工，甚至巴不得员工不去做、他来做。老板则希望员工什么都能做、都得做好，必要的时候会训斥员工。如果要培训出一个能用的员工，自然是交给老板培训最好。但老板也不是什么时候都有空，就会把包袱丢给经理。结果便是经理培训过后的员工，没有几个是可以入老板眼的。</p><h4 id="事精的定义"><a class="markdownIt-Anchor" href="#事精的定义"></a>「事精」的定义</h4><p>这个月有两位新人来培训，其中有一位没想到竟是过去一次兼职的同事。因为本身就有奶茶店工作的经验，她学起来很快，不过老板的要求「道高一尺」。另一位则是由经理培训，培训结束后跟着老板做了两天就差点被炒鱿鱼。你们可以猜猜看，最终谁留了下来？</p><p>两个都被炒掉了！</p><p>前者被炒的理由较有意思：老板认为她是个「事精」。又或者说，不符合店铺氛围。</p><p>对于这类小型服务业而言，店铺氛围是老板权威和管理风格的直接体现。员工无论主观是否愿意，都会受到这种氛围的影响而自动调整行为。在 10 人以下的小团队里，单个成员的态度和行为方式对整体氛围影响极大。一个「会搞事」的员工就足以改变整个团队的互动模式。</p><p>不过我还是很好奇，对方到底「事精」在哪儿？</p><h4 id="创业宣传策略"><a class="markdownIt-Anchor" href="#创业宣传策略"></a> <a href="/posts/c3f9.html">创业宣传策略</a></h4><p>在营销至上的氛围中，我的一位创业者朋友也陷入了资源错配的怪圈。他的项目还未正式启动，但团队的所有人都开通了企业邮箱，一个月就要花掉不少钱。</p><p>他认为团队里的多数人是做营销的，需要出头露面，企业邮箱因此是必需的。但是开支对于初创公司而言很大是真的，为此他想要削减技术人员的工具预算。</p><p>我的第一反应是比较生气。同样作为技术人员，为什么这些人就要因为待在后面、不被人看到，就要把预算让给一些实际产出都不理想的人呢？</p><p>我不是觉得营销没必要，事实上，我认为营销很有必要，因为没有什么产品是可以自销的。但是营销得有效，预算也得用在对的地方上。将「看起来像是在创业」的活动误认为是创业本身，可是毁灭性的想法！</p><h2 id="技术学习与实践"><a class="markdownIt-Anchor" href="#技术学习与实践"></a> 技术学习与实践</h2><h4 id="webmention"><a class="markdownIt-Anchor" href="#webmention"></a> Webmention</h4><p>是的，现在这个博客网站支持 Webmention 了！这是 IndieWeb 的核心协议之一，想要详细了解我是如何做到的，可以看 <a href="/posts/1de.html">这篇文章</a>。目前我还在缓慢改进 Webmention 的显示方式，十分感谢 <a href="https://taxodium.ink/">Spike</a> 在这期间主动联系我、帮助了我许多~</p><p>然后我发现，开发 Hexo 的插件的话一定要在文件顶部写上：</p><pre><code class="language-javascript">/* global hexo */</code></pre><p>测试期间发现了 Hexo 实例未定义的错误。找了很久才发现是这行忘记加。</p><h4 id="去中心化"><a class="markdownIt-Anchor" href="#去中心化"></a> 去中心化</h4><p>阅读博客时我学到了一个新东西：ActivityPub。我觉得去中心化社交平台是一个很有意思的概念，不过我现在依然没有搞明白其中的原理。到底是怎么做到的？只用客户端、不用服务端就可以互相发送数据、存储数据？后面了解了一下得知，并不是完全的没有服务器，而是没有了中间的服务器。比方说 Instagram，用户上传的内容都是从客户端传输到 Instagram 自己的服务器，而去中心化是去掉了这个中间的封闭服务器，改用用户自己搭建的服务器，通信则需要依靠特定的协议。ActivityPub 便是这样的一个协议。</p><p>我想到过去我捣鼓过的 Nostr 也是这样吧，用户可以在一种叫做 Relay 的服务器上上传内容。去中心化的好处是我们上传的内容不会被这些封闭的公司管控，坏处则是展示上传的内容时不一定齐全，并且要特意折腾一番、迁移时也麻烦。如果是完全的纯客户端，那就是 P2P 了，我还没折腾过。</p><p>我认为很多时候人际关系在社交平台上的分布就会决定我们使用什么平台。我还在使用 Instagram、推特（我还是抗拒叫它 X……）、Threads 和脸书等平台，主要还是因为我的朋友都在上面、我要分享我的生活给他们，绝对不是因为我有多么喜欢这些平台给我带来的流量。我的账户几乎都是私密的，流量什么的都无所谓，我乱发我开心就好，我在 Instagram 上还有个专门的分类存放我收藏的钢笔美照~ 我写博客也是这样的心态。我虽然会把它的链接放在我社交平台账户的个人资料上，但我肯定不会期待我的校友们会点进去、看到全都是中文的文章然后特意每一篇都用翻译工具读过去。很多人对于博客的想法还是，<em>哇哦酷</em>，然后再也不会打开。唉…</p><h4 id="10x-工程师-vs-10x-工程师"><a class="markdownIt-Anchor" href="#10x-工程师-vs-10x-工程师"></a> 10x 工程师 vs -10x 工程师</h4><p>在团队中，「10x 工程师」代表极高产能和影响力的人才；相对地，「-10x 工程师」则是以拖慢团队效率、增加内耗为特征的反面角色。他们的典型特征是：</p><ul><li>制造大量无效产出：例如幻灯片、图表、报告等形式主义成果，却无法交付可运行的产品。</li><li>追求优雅胜过实用：花费大量时间在架构设计或代码风格打磨上，却忽视最终交付或快速迭代的需求。</li><li>阻塞决策流程：反对「一锤定音」的决策方式，通过反复讨论、持续征求意见拖延进度。</li><li>冗长且泛滥的沟通：在群组或邮件中发送长消息，要求团队成员广泛参与无意义的讨论。</li><li>代码与脚本难以维护：编写晦涩难懂、仅自己能看懂的脚本或程序，没有文档；构建和测试流程非常缓慢。</li><li>滥用测试与依赖：写大量毫无意义的测试用例；引入需要单独学习且维护成本高的第三方库。</li><li>浪费团队智力：将团队困在复杂而收益不明的项目上，让其他工程师也陷入无产出的深坑。</li><li>误导管理层：低估项目难度，夸大可行性，最终导致进度大幅延迟或彻底失败。</li><li>复制「负能量」人才：倾向招募同样低效的工程师，进一步拖累团队。</li></ul><h4 id="把脚注踢出文章吧"><a class="markdownIt-Anchor" href="#把脚注踢出文章吧"></a> 《把脚注踢出文章吧！》</h4><p>我有订阅一个英文的 Feed，里面收录了一些 JavaScript 相关的技术文章，例如这次我翻到的 <a href="https://jakearchibald.com/2025/importing-vs-fetching-json/"><em>Importing vs fetching JSON</em></a>。不过让我引起兴趣的不是这篇文章，而是文章作者 Jake Archibald 在七月份写的 <a href="https://jakearchibald.com/2025/give-footnotes-the-boot/"><em>Give footnotes the boot</em></a>。</p><p>在许多文章里，当作者想要对一个话题或者术语进行补充的话，都会在对应的词汇旁添加一个小数字，然后将补充说明放在页面的最底部。Jake 认为这样的设计很糟糕，因为它会迫使读者做出选择：要不然跳过脚注保持阅读流畅，或者中断主线去探索「支线」。这种体验被他描述成是一种「死胡同式的冒险书」，读者最终还是得回到主线来。同时他提到，脚注字体通常被设计的很小，阅读体验很差，而这样的做法竟是写作界的传统。</p><p>而网页没有「页面」这个概念，脚注通常被放在文末，需要读者滚动查找。如果页面有长评论区或者页脚，脚注会更难被定位。虽然可以用超链接跳转，但读者依然需要手动寻找对应的内容；返回主文后，读者又会迷失在文字中。Jake 就此提出了多个解决方案：</p><ol><li>使用 <code>&lt;popover&gt;</code> 和 CSS anchor 实现无 JS 的脚注弹窗。虽然技术上可行，但他依然认为这是糟糕的体验，原因有二：<ol><li>链接文本如 <code>1</code>、<code>7</code> 等毫无语义，点击区域又极小。</li><li>superscript 存在可访问性问题。</li></ol></li><li>放弃脚注，直接使用括号吧！毕竟「脚注是印刷时代的残留 hack，在网页平台上继续使用脚注是『愚蠢的延续』」（这句话不是我说的）。不过仅适用于简短的补充内容，需要避免使用嵌套括号。</li><li>使用 <code>&lt;section role="note"&gt;</code>，语义明确，视觉独立，适合中等长度补充内容。</li><li>使用 <code>&lt;details&gt;&lt;summary&gt;</code> 折叠内容，读者可选择展开，适合较长补充信息。</li></ol><p>Jake 也强调，如果内容真的不重要，就别写；如何值得一读，就放在上下文中。</p><p>该文章的评论区内也有人认为，Jake 提出的替代方案「太打断阅读」。Jake 反驳：<em>阅读本就包含跳过不相关内容的行为。与其优化给「不感兴趣的读者」，不如提升整体语义与可读性</em>。</p><p>自然也有一些特殊情况：</p><ul><li><p>Wikipedia 的脚注就是仅用于引用的，并且用户的习惯早已建立，属于例外。</p></li><li><p>如果内容需要打印，可以用媒体查询优化打印体验。</p><p>媒体查询是一种 CSS 技术，可以根据不同的设备类型或输出方式（例如屏幕、打印机）应用不同的样式。当用户选择打印网页时，浏览器会使用 <code>@media print</code> 规则下的样式，而不是屏幕显示的样式。</p><p>你可以在 <code>@media print</code> 中：</p><ul><li>隐藏不必要的元素（如导航栏、评论区）</li><li>调整字体大小、行距、颜色（通常改为黑白）</li><li>展开折叠内容（如 <code>&lt;details&gt;</code> 标签）</li><li>将脚注或引用内容重新排版为适合纸质阅读的格式</li></ul></li></ul><p>我个人没有写脚注的习惯，不过我过去会用 Markdown 的引用块来补充内容。这种行为不依赖编号或者跳转，因为内容直接可见，更像是「作者旁注」而非「脚注」。引用块通常也是缩进或变色的（在我的博客主题里，它两者皆是），会在视觉上形成轻微分割，便于读者跳过。根据 Jake 的说法，应该是类似于 <code>&lt;section role="note"&gt;</code> 的做法。</p><p>但是直接使用引用块，在语义上还是偏了，只能说可以接受。因为引用块的用途终究还是「引述他人观点、文献或外部内容」。最好还是自定义语法标记，然后让 Hexo 转换成 <code>&lt;section role="note"&gt;</code> 或者 <code>&lt;aside&gt;</code>。</p><p>翻阅一些订阅的博客网站时，我也发现有站主实现了全屏旁注。我个人比较好奇，这类旁注对于部分较为特殊的设备来看是什么样的？</p><h4 id="nan那个不是数字的数字"><a class="markdownIt-Anchor" href="#nan那个不是数字的数字"></a> 《 <code>NaN</code>：那个不是数字的「数字」》</h4><p>我在 Hacker News 上找到了这篇文章：<a href="https://piccalil.li/blog/nan-the-not-a-number-number-that-isnt-nan/"><em>NaN, the not-a-number number that isn't NaN - Piccalilli</em></a>。作者 Mat "Wilto" Marquis 指出 <code>NaN</code> 只要出现在算术表达式中，结果永远都会是 <code>NaN</code>；任何使用 <code>NaN</code> 作为操作数的比较也都会返回 <code>false</code>。奇怪的是，当你写 <code>NaN == NaN</code> 或者 <code>NaN === NaN</code> 时，结果却是 <code>false</code>。Mat 解释，这是因为 <code>NaN</code> 是一个数字，尽管它的全称是 <em>Not-a-Number</em>。这听上去像是自相矛盾，但其实背后的设计逻辑很合理：</p><ol><li><p>JavaScript 使用 IEEE 754 标准来表示数字，包括整数和浮点数。在这个标准里，<code>NaN</code> 是一种合法的数值类型，用于表示「无法表示的数值结果」，比如：</p><ul><li>0 除以 0</li><li>数字与非数字相乘</li><li>对负数开平方（在部分语言中）</li></ul><p>因此 <code>NaN</code> 是一种「数值错误状态」，而不是一个非数值类型。</p></li><li><p>为了让错误状态在数值计算中传播，<code>NaN</code> 必须表现得像一个数字。如果 <code>NaN</code> 不是数字类型，它就无法参与算术运算，也无法在表达式中自然传播错误。</p></li><li><p><code>NaN</code> 的设计目的是在数值计算中标记错误，而不是抛出异常。它是一种「哨兵值」，表示「这里出了问题，但是程序可以继续运行」。这比抛出错误更灵活，尤其是在数据处理、科学计算或者图形编程里。</p></li><li><p>为了防止错误值被误认为是有效数值，<code>NaN</code> 是 JavaScript 中唯一一个不等于自身的值。你必须使用 <code>Number.isNaN()</code> 或 <code>isNaN()</code> 来检测它，而不是用等号比较。</p></li></ol><h2 id="社交与人际关系思考"><a class="markdownIt-Anchor" href="#社交与人际关系思考"></a> 社交与人际关系思考</h2><h4 id="吃免费的饭骂做饭的厨子"><a class="markdownIt-Anchor" href="#吃免费的饭骂做饭的厨子"></a> <a href="/posts/a2a2.html">吃免费的饭，骂做饭的厨子</a></h4><p>对于「为什么人们更倾向于攻击贡献者」这一问题的思考。</p><h4 id="阶段性朋友"><a class="markdownIt-Anchor" href="#阶段性朋友"></a> 阶段性朋友</h4><p>人与人之间的关系，远没有想象中那般永恒，而是会随着个人成长、环境变迁逐渐发生裂变与疏离。所谓「阶段性朋友」，指的是那些在生命某个阶段因为特定经历或背景走到一起、彼此陪伴、共享过一段时光的朋友。但随着时间推移，彼此的世界观、生活轨迹乃至性格边界产生变化，这段关系逐渐失去了原有的连结，甚至在某个节点彻底失效。</p><p>认识的年头再长，曾经再亲密都不能保证关系始终如一。人会成长，也会走散，有的人是陪你一阵子的，有的人才能陪你一辈子。</p><p>我认为这并不等同于背叛或者消耗，这是一场彼此陪伴和成长的必经过程。感谢那段时光的相遇和陪伴，也坦然面对最终的分离。接受关系的自然流转，顺势而为。成长本就是一场不断筛选、不断更新关系的过程。</p><h4 id="你只是在怪她没有选你"><a class="markdownIt-Anchor" href="#你只是在怪她没有选你"></a> <a href="/posts/e0dc.html">你只是在怪她没有选你</a></h4><p>近日，一位朋友提起了自己的情感问题。不过我没有很深入去写到底发生了什么，毕竟把别人的隐私拿出来写还是很不好的。这篇文章里我更多是借用了他的一些故事，去写我对「你只是在怪她没有选你」的部分看法。</p><h4 id="性暴力的苗头是加害者"><a class="markdownIt-Anchor" href="#性暴力的苗头是加害者"></a> <a href="/posts/5c85.html">性暴力的苗头是加害者</a></h4><p>原本是公开演讲课的作业，但因为感觉很有缘，所以深入思考后的产物。</p><h2 id="教育与学习"><a class="markdownIt-Anchor" href="#教育与学习"></a> 教育与学习</h2><h4 id="番茄钟的个人想法"><a class="markdownIt-Anchor" href="#番茄钟的个人想法"></a> 番茄钟的个人想法</h4><p>一次，一位校友询问我平日都是如何学习的。我说我会学到累为止。他立马开始批评我，并提到了他的一位朋友的学习方式，认为我应该向他学习。而那位朋友的学习方式，则是番茄钟学习法。</p><p>我觉得这位校友人很烦。这已经不是第一次 <em>他因为一件自己完全不熟悉的事情而「说教」我</em> 了。我也不喜欢番茄钟，但我也不否认它的可用性，只是它强制的时间切割方式会和我的思考节奏产生冲突。</p><blockquote><p>番茄钟学习法：要求你每完成一个 25 分钟的专注周期，就必须暂停 5 分钟。</p></blockquote><p>我习惯深度沉浸地做事。如果在我思路连贯的时候突然中断我，我会十分愤怒，并且之后也很难迅速回到同样的专注状态。</p><p>番茄钟本身是一套高度结构化、外在强制的时间管理体系。它规定了固定的工作与休息节奏。对于依赖自我判断来安排学习节奏的人来说，使用番茄钟容易产生被工具主导的无力感。并且对于需要更长的连续思考才能进入心流状态的人来说，当休息周期早于心流完成点时，反而会打乱最佳效率，还不如自然而然地寻找暂停时机。</p><h4 id="孩童和恐怖游戏"><a class="markdownIt-Anchor" href="#孩童和恐怖游戏"></a> <a href="/posts/e068.html">孩童和恐怖游戏</a></h4><p>和妹妹玩多人恐怖游戏的时候一直在脑海里盘踞着的想法。在我和妹妹一样大的年纪，如果有成年人这么想，我绝对会觉得他们很烦吧…… 最近我在网上经常看到一类言论，觉得很贴切我现在的状态：<em>到了两边（长辈和孩子）都能理解的年纪</em>。</p><h2 id="日记片段"><a class="markdownIt-Anchor" href="#日记片段"></a> 日记片段</h2><p>该栏块专门放置一些日记片段…… 它们是我的一些还未被深入探索的小想法，一些我觉得有意思的日常…… 或许在未来的哪一天，我会捡起一些详细说说？你感兴趣的话，也可以拿走~</p><blockquote><p>我要发表我对领英这个 app 的想法：无聊透顶。</p><p>每次刷都是看高中生进了什么名校、大学生找到了什么实习、应届生找了什么工作。</p><p>也没什么办法，这是一个报喜不报忧的平台。</p></blockquote><blockquote><p>我发现移动端的 Fluent Reader Lite 和桌面端的 Fluent Reader 的区别还挺大：</p><ol><li>不能改字体</li><li>会自动删除 7-28 天之内的文章</li></ol><p>导致我去床上躺着还不能愉快阅读 RSS Feed。我订阅的很多博客都不是一个月一更的。像我自己都可能不会几个月更一次。</p></blockquote><blockquote><p>我感觉我的生活已经没有了自己的时间了。一段不会被别人打扰的、自己想事情自己可以写下来的时间。我写日记都是选在较特别的时间段：坐车通勤、打工空闲… 就算是在家里，我也要赶项目的进度，更别提很多时候都有学校的作业要写。</p></blockquote><blockquote><p>我梦到我和家人翻山越岭来到大陆的一个角落，在海里放了个 Hello Kitty 大脸气球，坐在上面想慢慢地飘到北极……</p></blockquote><blockquote><p>你的大脑只能理解它已知的信息，所以当你选择你想要的未来时，你实际上只是基于过去创造了一个理想化的方案。</p><p>如果事情没有按照你希望的方式发展，你就会认为自己失败了，因为你没有创造出你想要的东西。</p><p>而实际上，你创造了更好的东西，但它对你的大脑而言是陌生的，所以大脑将其错误地理解为「不好的」。</p></blockquote><blockquote><p>一个过于在意他人感受和看法的人，是否也是一个极度以自我为中心的人呢？</p><p>拼命寻求认可是一种以自我为中心的表现。</p><p>之所以在意他人的看法，是因为希望世界以自己想要的方式运行。</p><p>课题分离：</p><p>没有比主观感受更大的事情。</p><p>课题 = 个体的主观感受 + 选择</p><p>人际关系的烦恼：</p><ol><li>心甘情愿让他人干涉自己的课题</li><li>企图强行干涉他人的课题</li></ol></blockquote><blockquote><p>反叛精神不等于叛逆。</p><p>叛逆青年无法跳脱出赏罚机制，只是因为无法因赞赏而得到他人的关注，因此走向极端，做叛逆的行为来获得关注。</p><p>反叛精神则是跳脱出赏罚机制，不做会得到他人表扬的事，而是做自己想做的事。</p></blockquote><blockquote><p>我今天 ゴロゴロ（<em>gorogoro</em>，无所事事的意思）了一整天。晚上出去吃了快乐小羊，不是很惊艳。我感觉现在的火锅都不惊艳。</p></blockquote><blockquote><p>我有一个想要订阅的博客网站，但是不知道为什么，FreshRSS 无法和它成功进行 SSL 握手，说是版本不对。我在容器内改了许多 TLS 版本来 curl，但都不行，只好收藏在我的标签页里时不时看一眼。</p></blockquote><blockquote><p>我在学习双拼。我用的是 Gboard 里的小鹤双拼。</p></blockquote><blockquote><p>双拼好难，暂且搁置。</p></blockquote><blockquote><p>我放弃了我的鱼缸，里面死掉了太多的虾和螺，我都不知道是怎么做到的，一向杀不干净的羊角螺在里面全部死光。</p></blockquote></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;开冬不愧是开冬，前段时间还觉得有点热，现在每天都是冻醒的。这个月，我在缓慢地调整我的生活 —— 从兼职、工作、学业和自己。我还在摸索「想法迭代」这类文章的架构，所以该文章相较于 &lt;a href=&quot;/posts/dc84.html&quot;&gt;上篇文章&lt;/a&gt; 会有显著的差异。&lt;/p&gt;</summary>
    
    
    
    <category term="想法迭代" scheme="https://blog.cytrogen.icu/categories/%E6%83%B3%E6%B3%95%E8%BF%AD%E4%BB%A3/"/>
    
    
  </entry>
  
  <entry>
    <title>孩童和恐怖游戏</title>
    <link href="https://blog.cytrogen.icu/posts/e068.html"/>
    <id>https://blog.cytrogen.icu/posts/e068.html</id>
    <published>2025-11-02T05:20:14.000Z</published>
    <updated>2026-02-09T17:16:55.213Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>妹妹一直都有在玩 Roblox（罗布乐思）这款游戏，因为她很想和我一起玩，所以我花了一天时间陪她。其中有个游戏叫做 <em>99 Nights at Forest</em>，貌似近期在孩子们之间十分流行。</p><span id="more"></span><h2 id="游戏背景"><a class="markdownIt-Anchor" href="#游戏背景"></a> 游戏背景</h2><p>该游戏的背景发生在一片森林里，人们声称目击到了一头「站着的鹿」，还有四个孩子在里面失踪。警方怎么找都找不到怪物和孩子，只能将其封锁。而玩家有 99 天的时间探索该森林、找出真相。</p><p>该游戏的玩法不知为何会让我想起饥荒，玩家刚进入游戏就能看到营火、持有布袋和斧子。砍树可以获取木头、布袋可以装木头，木头又可以生火、扩大可探索范围。除了白天就能看到的动物外，该游戏还有晚上才会出现的鹿人、到一定天数会主动来找你麻烦的邪教徒、我目前还没见过的羊人…… 基地旁还会立着一个寻人启事板，可以根据上面给出的方向来找到失踪的孩子。</p><h2 id="恐怖游戏是否适合孩童游玩"><a class="markdownIt-Anchor" href="#恐怖游戏是否适合孩童游玩"></a> 恐怖游戏是否适合孩童游玩？</h2><p>这个游戏的桌面端快捷键设计有些不合理，操作实在是不习惯。但让我更在意的其实是另一个问题：<em>这种恐怖主题的游戏在孩子中如此受欢迎，究竟合不合适</em>？首先，我先说一下我的部分观点：</p><ol><li><p>Roblox 本身就是多人游戏，会火的恐怖游戏也近乎都是多人合作。例如几年前在外国孩子之间很火的 <em>Piggy</em> 就是多人合作逃脱游戏，再到之后的一系列恐怖题材游戏都是多人合作。<em>99 Nights at Forest</em> 也是一样。正是这种集体协作、彼此依赖的机制，让原本单纯的恐怖体验转化为社交刺激与游戏乐趣。</p><p>心理学研究提出过 <em>娱乐性恐惧</em> 这个概念，即一种恐惧与愉悦并存的混合情绪体验，而恐惧与愉悦之间是存在着「倒 U 型关系」的。当人们在安全的社交环境中体验恐惧时，恐惧会被转化为积极情绪。</p></li><li><p>对于已经在上学的孩子而言，恐怖体验是有利的，可以帮助他们学习如何面对恐惧、管理焦虑情绪。前提是恐惧强度必须适中。事实上，从我观察来看，近些年在孩子之间火的恐怖游戏（如 <em>Poppy's Playtime</em>）普遍属于 <em>吉祥物恐怖</em>，其内容更偏向于紧张与刺激，再加上可爱吉祥物所营造的反差，而非真正的血腥或猎奇。这些游戏的恐怖也多数被包裹在任务、收集等系统里。</p></li><li><p>我认为这个年龄段的孩子就算接触到了一些恐怖概念，例如邪教徒，他们也无法明白这到底是什么、只是将其看成是一种设定。这并不意味着孩子无法感知恐怖，他们只是难以理解背后的抽象含义。如果你在小时候玩过 4399 等平台上的小游戏的话，或许也接触过许多带有血腥、恐怖、猎奇要素的游戏。比方说 <em>jumpaloo!</em>，屡次失败的玩家会遭受血腥的对待、看着代表自己的小动物被搅碎。但是对于当时的孩子而言，「被搅碎」这个行为本身不重要，重要的是「失败了」。因此，他们把这一幕理解为游戏中的失败信号，而不是现实暴力的再现，这正说明儿童在早期阶段对暴力的解读更多停留在规则层面。</p></li></ol><p>那么，孩子到底适合游玩恐怖游戏吗？我的答案：<strong>这是一个双刃剑。</strong></p><p>是的，恐怖游戏可以帮助孩子们脱敏，但是过量的暴力和血腥内容会导致孩子们的共情能力下降、培养出非黑即白的理念。关键在于剂量和语境：偶尔的卡通暴力可能无害，但如果每天数小时沉浸在「杀戮获得奖励」的游戏循环内呢？</p><h2 id="roblox-的问题"><a class="markdownIt-Anchor" href="#roblox-的问题"></a> Roblox 的问题</h2><p>Roblox 也有着自己特有的风险。它其实比起说是一款游戏，更像是一个游戏平台、里面的游戏都是用户生成内容。而这种开放式平台设计虽然鼓励创造，但同时也带来了新的问题：</p><ul><li>内容质量不可控。虽然里面多数游戏都是正规的，但是质量低劣、设计不当的游戏也不是没有。突然的 jumpscares（突发惊吓，或称跳杀）就会被我称为是 <em>无营养的恐惧</em>。</li><li>多人游戏意味着与陌生人互动。即使游戏本身适当，聊天功能也可能导致孩子们被有心者欺骗、骚扰、仇恨。<ul><li>Bloomberg 曾经调查发现，Roblox 上的儿童性侵案件从 2018 年的 13 起激增至 2023 年的 <strong>147</strong> 起。要知道，Roblox 是全球最大的儿童游戏平台，日活跃用户超 <strong>7800 万</strong>，其中 40% 是 13 岁以下的儿童，也就是 <strong>312 万</strong>。这一数据之所以令人担忧，是因为 Roblox 的规模远大于其监管能力。全平台审核员竟然只有 <strong>3000</strong> 名左右！</li><li>Roblox 有一个叫做 Robux 的货币，类似于 Q 币，可以购买角色装扮和部分游戏内的装备。对于已经有经济能力的大人而言，购买 Robux 根本就不是什么大事。但是对于孩子们而言，该系统会让他们感受到 <em>经济焦虑</em> 或 <em>同伴压力</em>。再者，允许孩子为游戏充值的家庭我个人认为并不多。这就像一些现实的案例：没有经济能力的未成年人被一个有经济能力的成年失败者坑骗肉体。</li></ul></li></ul><h2 id="评估和结语"><a class="markdownIt-Anchor" href="#评估和结语"></a> 评估和结语</h2><p>如何更好地去评估一款游戏适不适合孩子们游玩？我认为可以参考这个框架：</p><ol><li>游戏是卡通化还是写实化？</li><li>恐怖类型是跳跃惊吓、追逐紧张，还是心理恐怖、存在威胁？</li><li>玩家能否通过技能避免威胁，还是只能被动承受？</li><li>游戏的叙事框架是单纯的杀戮模拟吗？</li><li>孩子多少岁？7 岁以下应完全避免；7-10 岁需严格选择和监督；10 岁以上可适度放宽。</li><li>孩子对恐怖书籍、电影的反应如何？是否有持续恐惧史？</li><li>独自一人玩还是和朋友一起玩？</li><li>陪同孩子玩前 30 分钟至 1 小时，其面部表情、身体语言是什么样的？</li><li>游玩后是否出现了睡眠问题、焦虑增加、攻击性言行或回避行为？</li><li>游玩后询问孩子哪部分最可怕？这些怪物是否是真实的？如果害怕了怎么办？评估孩子的理解和应对能力。</li><li>即时游戏适当，也应限制每周游戏时间，避免过度沉浸。</li><li><strong>一定</strong> 要教育孩子们，如何应对陌生人、保护个人信息、如何举报不正当内容！</li></ol><p>那么，完全禁止是否更高效、也更有利于保护孩子？其实未必。对于 Z 世代和 Alpha 世代（前者指代 1997-2012 年出生的人，后者指代 2013 到现在出生的人）来说，这些游戏是社交货币和共同话题。拒绝参与可能导致社交孤立。这意味着完全禁止也有弊处。</p><p>适合性是动态的、条件性的，而非静态的、普遍的。所以，与其追问「恐怖游戏是否适合儿童」，不如问「如何让恐怖体验在安全的环境下，为儿童心理成长服务」。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;妹妹一直都有在玩 Roblox（罗布乐思）这款游戏，因为她很想和我一起玩，所以我花了一天时间陪她。其中有个游戏叫做 &lt;em&gt;99 Nights at Forest&lt;/em&gt;，貌似近期在孩子们之间十分流行。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="心理学" scheme="https://blog.cytrogen.icu/tags/%E5%BF%83%E7%90%86%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>创业宣传策略</title>
    <link href="https://blog.cytrogen.icu/posts/c3f9.html"/>
    <id>https://blog.cytrogen.icu/posts/c3f9.html</id>
    <published>2025-11-02T05:02:00.000Z</published>
    <updated>2026-02-09T17:16:55.009Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>此文章记录了一些我对于现代年轻人创业，尤其是其宣传策略的观察和想法。</p><span id="more"></span><p>我的一位创业者朋友想要将目标人群定在 Z 世代（指代 1997-2012 年出生的人，也就是现在的「年轻人」）。原因很简单：<strong>你是个年轻人，你要赚年轻人的钱</strong>。他找来了一位摄影师，拍了许多带有艺术氛围的照片作为宣传，还录制了一些宣传视频。重点在于这些宣传视频。他告诉我，现在能夺得 Z 世代目光的宣传视频必须是夸张、搞笑、刺激的。</p><p>作为例子，我被迫看了其他初创公司的宣传视频。它们都是在 Instagram 上投递短视频、具有着年轻人特有的欢快活泼耍宝风格。这些视频和产品没有丝毫关系，更多是创始人同员工们整活：招程序员要招有自闭症的、员工和创始人的关系要亲近到「一起搓澡」…… 这个时候我看到公司名称还没反应过来，看到创始人的名字才意识到他是 Cluely—— 七月份较有话题度的「AI 作弊工具」—— 的 CEO。</p><h2 id="roy-和-cluely"><a class="markdownIt-Anchor" href="#roy-和-cluely"></a> Roy 和 Cluely</h2><p>Roy 是一位辍学的 21 岁男生，干过许多奇奇怪怪的事情，例如靠作弊过了亚马逊的面试，却把作弊方式分享到了 YouTube，导致被亚马逊的员工发现。他因为现在这个 AI 初创公司 Cluely，在外网火了一把，公司也足足融资了 1500 万。我那会儿刷到过有人吐槽他新投放的广告的帖子，结果第二天就在路上看到了这个广告：一个巨大的广告牌上白纸黑字写着「我是 Roy，今年 21 岁，我开了个 AI 初创公司，快来看」。</p><p>我不否认，Z 世代购物者确实更信任网红，并且对「夸张、搞笑、刺激」的内容有着天然的亲和力。短视频平台上，60 秒以下的内容拥有最高的参与度，而那些展示真实性、幽默感和参与感的品牌更容易获得青睐。</p><p>当然，这是趋势观察，不是对个体的标签。</p><p>但这里存在一个危险的逻辑跳跃：<strong>理解 Z 世代的偏好，不等于可以用纯粹的表演代替产品价值</strong>。</p><p>Roy 的故事本身就是现代创业文化的极端标本。他因为开发帮助人们在面试中作弊的工具被名校开除，随后将这场争议本身转化为了病毒式营销的素材，从而获得 1500 万美元融资。他最初的策略就是创建争议，必须要让超过一半的观众讨厌视频，然后制作大量视频、像病毒一样投放出去。</p><p>这套玩法的核心在于，用极具话题性的「个人表演」来强行占据公众视野，从而让产品的实际价值在讨论中变得不再重要。当一条信息、一个事件在网络上足够火，各种监管、批评或惩罚措施就很难再对它产生任何影响了。换言之，公众注意力的放大效应还可以让事件本身变成一种护身符。</p><p>然而，Roy 也曾承认，这个「作弊工具」被设计出来就是等着被毁灭的，因为公司很快会调整面试流程，吸食原有面试流程的养分的作弊工具很快也会变得无用。</p><p>我现在再去看 Cluely，就会发现它已经转型成了面试辅助工具，可以在用户面试前策划好用户要准备什么等。这也让我产生了一个疑问：现在没有了争议，转型后的产品本身能否支撑起 1.2 亿美元的估值？在我看来，其长期价值仍然存疑。</p><h2 id="对流量的焦虑"><a class="markdownIt-Anchor" href="#对流量的焦虑"></a> 对流量的焦虑</h2><p>Cluely 只是当前时代、面向年轻人的无数个初创公司的其中一所。我在一次网上冲浪时，看到另一位辍学的年轻人创业。很有意思的是，他的主页里也近乎没有任何产品的内容，更多是尝试获取流量的帖子。</p><p>我作为一个无意间刷到帖子的人，无法从他的帖子里得知产品是什么，但是可以看出创始人在想办法「有趣」。我说他是想办法「有趣」而不是直接说他是个有趣的人，是因为我能从他的帖子里感受到他的焦虑，一种为了变得吸引人的焦虑。评论区时不时会出现一些尖锐的声音，差不多都是批评当下年轻人创业、什么都不懂只知道开会和 KPI，没有满腔热血只有歪门邪道。</p><p>这里还有一个问题：为了流量，然后呢？要如何变现？大家想看的是你这个产品，还是你努力表演出来的搞笑？</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;此文章记录了一些我对于现代年轻人创业，尤其是其宣传策略的观察和想法。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="创业" scheme="https://blog.cytrogen.icu/tags/%E5%88%9B%E4%B8%9A/"/>
    
  </entry>
  
  <entry>
    <title>性暴力的苗头是加害者</title>
    <link href="https://blog.cytrogen.icu/posts/5c85.html"/>
    <id>https://blog.cytrogen.icu/posts/5c85.html</id>
    <published>2025-10-27T21:28:00.000Z</published>
    <updated>2026-02-09T17:16:55.213Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>写一门课的作业时，我被要求在一众 TED 演讲里选一个进行分析。我随手一选，选到的是一个双人演讲。更没想到的是，这两个人的身份分别是「强奸者」和「被强奸者」。</p><span id="more"></span><h2 id="我们的强奸与和解故事"><a class="markdownIt-Anchor" href="#我们的强奸与和解故事"></a> 《我们的强奸与和解故事》</h2><p>男演讲者 Tom 是一位澳大利亚人，女演讲者 Thordis 则是冰岛人。在他们还是学生的时候，Tom 来冰岛交换、同 Thordis 交往。一次圣诞舞会，Thordis 喝了朗姆酒，而这一决定成了她这辈子最后悔干的事情：Tom 在 Thordis 喝醉后，像「护花使者」一般送 Thordis 回家，然后在她的卧室床上实施了性侵。Thordis 无法反抗，只能麻木地在脑海里数数 —— 最终数到了 7200 秒。</p><p>这次创伤给 Thordis 带来了 PTSD 症状。她经历了长达九年的沉默，25 岁濒临精神崩溃，自我价值被压抑在孤立她与所有关心她的人的重负之下。Tom 则靠心理上的否认「生存」下来。他拒绝将自己的行为定义为强奸，而是说服自己那是 <em>性爱</em>。这是一种对现实的回避，因为他一直认为自己是一个来自良好家庭、自认为正派的人。而这样的一个人，怎么可能会性侵别人呢？</p><p>2005 年，Thordis 主动给 Tom 写信，直面她所遭受的痛苦。令她震惊的是，Tom 没有否认，反而回信承认了罪行，充满了真诚的悔恨。这标记着长达八年通信的开始。不过 Thordis 最终意识到，文字依然不足以疗愈她，她决定和 Tom 见一面、双方去面对自己一生中最大的痛苦。他们在南非开普敦度过了一周。值得一提的是，南非这个国家通过真相与和解委员会处理了种族隔离的创伤历史。</p><p>这一周充满了紧张、痛苦，有时甚至感觉像是失败的尝试。Thordis 曾经多次想要放弃，回到丈夫和儿子的身边。但他们坚持了下来，从头到尾讲述彼此的人生故事。他们遵循严格的诚实原则，分析自己的历史。这种面对面的对话是恢复性司法的一种形式。不同于传统的惩罚性司法，它的核心在于让犯罪者、受害者以及社团成员共同参与，解决因犯罪行为所造成的伤害与冲突。</p><p>Thordis 在演讲中强调，仅仅给人们贴上「受害者」和「强奸犯」的标签不足以让我们理解背后的人性，也无法帮助我们理解为什么会发生暴力。这种简化的标签化可能导致去人性化，反而阻碍了对暴力根源的深入理解。Tom 则揭示了男性社会化如何创造了一种危险的性别权力动态：男性被教导他们「应得」女性的身体。这种有毒的男性气质观念是强奸文化的核心特征。</p><h2 id="隐身的加害者"><a class="markdownIt-Anchor" href="#隐身的加害者"></a> 隐身的加害者</h2><p>现在的新闻标题都喜欢将被害者放在主语的位置，例如「女孩被杀害」。接着我们添加一些细节，变成「女孩在景区内被杀害」。为了让更多人看，我们添加一些会让大众感兴趣的内容：这个女孩是个大学生，那就可以写「19 岁女大学生景区内被杀害」；她被残忍杀害，那为了满足猎奇和刺激，就可以写「19 岁女大学生景区内遭捅多刀身亡」。现在再来看这个标题，你会发现，你对这个加害者一无所知：<strong>这个男人因搭讪被拒绝、恼羞成怒，拿起剪刀连捅了被害者和被害者朋友数刀</strong>。更为悲惨的是，这个男人被官方强调有精神病史、捅人后还自首，很大可能会从轻处罚。</p><p>同样的还有「两女孩店门口喝奶茶被货车压死」。我们为什么要知道「喝奶茶」这个信息？而不是 <strong>电动货车卸货时意外失控、造成店铺门口四人受伤，其中两人抢救无效死亡</strong>？前者给出的信息，到底有什么用？告诉我们不要在门口喝奶茶、会被货车压死吗？这种报道视角，模糊了事故的责任根源，只留下了对受害者行为的无端指责。</p><p>再来一个，「女子熟睡被男友持刀架在脖子上」。这里看似写出了加害者，但是很刻意地模糊了加害者的行为：<em>他可没有在 <strong>蓄意谋杀</strong>，只是很单纯地把刀架在了女友脖子上哦</em>。</p><p>更有甚者，在「男子杀害女友 25 年后落网头发花白」这类标题中，虽然将加害者放在主语，但是很离谱地添加了这些模糊事件性质的描述：「头发花白」、「当年意气风发的小伙」等，无形中给杀人犯披上了一层悲情或沧桑的外衣，仿佛在博取同情。然而，杀人犯就是杀人犯，<strong>新闻标题应当报道事实，不应当给任何人套上任何人设</strong>。这种行为无疑是对受害者极其家属的二次伤害。</p><p>现在的社会，似乎都在关注着受害者：<em>他们是谁？发生了什么？他们感受如何？他们现在怎么样了？</em> 好像只要受害了，我们的人生就会一直被人监视。而加害者呢？我们知道他们是谁、为什么要害人、现在怎么样了吗？不，我们很多时候都不知道，因为他们在新闻报道里永远都是 <strong>隐身的</strong>。</p><h2 id="标签的局限性"><a class="markdownIt-Anchor" href="#标签的局限性"></a> 标签的局限性</h2><p>标签化也可以对受害者构成一种无声的暴力。它会创造一个 <em>完美受害者</em> 的模板：他必须是纯洁无瑕、奋力反抗、事后立即报案并痛苦欲绝。任何不符合这个模板的受害者，比方说喝了酒、曾对加害者有好感、反应是僵住而非反抗、没有立即报案等，都会遭受质疑，甚至自我怀疑。最常见的案例便是「她穿的这么少，活该被 xxx」。这会让真实的受害者被排除在「受害者」标签之外，承受二次伤害。</p><p>一个 <em>受害者</em> 的标签，也会覆盖掉他所有的其他身份。他原本是一个孩子、一个朋友、一个有喜怒哀乐的人，但 <em>受害者</em> 的标签只会将他生命中最创伤的一刻固定为他唯一的身份标识。这本身就是一种去人性化，他失去了被看作是一个「完整的人」的权利。</p><p>我的人生中便出现过这样一位「受害者」。她是一个很棒的朋友、身怀各种才能的学生、年纪轻轻的企业家。她对加害者曾抱有好感，被花言巧语蒙骗，周遭的帮凶们一个个借此规训她，仿佛错的是她。但这无法掩盖她被伤害、错的是那个加害者的事实。受害者是不能被标签化的，因为现实中的伤害往往发生在灰色地带，而僵化的标签会成为加害者及其拥护者颠倒黑白的工具。</p><p>同样的，标签化会助长为了达成目的而施行的 <em>工具性暴力</em>，即为了其他目的而伤害他人（不是为了施暴本身，而是为了暴力背后的利益。例如抢劫钱财）。当我们给一个群体贴上「低等」等标签后，就更容易把他们「去人性化」，从而为了自己的利益对他们施加暴力，而不会有道德负担。<em>咦，怎么听上去那么耳熟？</em></p><p>然而，对于另一种认为受害者「活该」的 <em>道德性暴力</em>，施暴者恰恰需要将受害者视为有思想、有行为的「完整的人」，他的暴力才被他自己赋予意义。因为只有对方是一个有思想、有行为的「人」，他的「错误」（比如穿着、拒绝、行为）才具有「道德意义」，才「值得」被惩罚。如果对方只是一个物体，那就无所谓「活该」了。</p><p>因此，Tom 的行为无法简单地将其归咎于 <em>邪恶</em>，因为它混杂了这两种暴力。既有工具性的一面（为了满足自己的性欲），也有道德性的一面（他认为作为男友，这是他的「权利」）。我们必须通过将他视为一个完整的人，而非怪物，才能够探索导致暴力的复杂因素：他所处的文化是如何让他变成这样的？这是我之后会提到的要点。</p><p>标签化还会阻碍对施暴者动机的理解。尤其是性暴力施暴者，他们往往通过否认、最小化和将责任归咎于受害者或外部因素来维持自我形象，例如酒精和性冲动。我们只有通过深入对话和问责，才能打破这些防御机制。</p><p>我必须得强调一下，将加害者视为一个 <em>人</em>，绝非是为了替他们的罪行开脱，更不意味着要给予丝毫的宽容。上述的事件我也被牵扯其中，并遭受了精神上的折磨。我痛恨这些加害者，认为他们仅为了自己的一私之欲、随意地伤害了他人，并不会受到任何实质性的惩罚。但是，去理解为什么要把他们视为 <em>人</em>，与我们内心中应有的愤怒和道德审判并不矛盾。</p><p>如果我们只将加害者视为 <em>怪物</em>，就等于承认暴力是来自我们无法理解的、外部的 <em>邪恶</em>。这会让我们感到安全，这种安全是虚假的，因为怪物是罕见的、异常的。而真相是，暴力往往由看似正常的普通人实施。只有承认加害者是人，我们才能承认暴力的根源存在于我们的人类社会、文化，甚至我们自己可能无意识秉持的观念中。这是解决问题的第一步。同样，将加害者视为人，意味着我们坚信其行为是可以被分析、被归因、从而被预防和阻断的。这是一种直面问题、并相信自己有能力解决的姿态。</p><h2 id="有毒男性气质与性别权力"><a class="markdownIt-Anchor" href="#有毒男性气质与性别权力"></a> 有毒男性气质与性别权力</h2><p><em>有毒男性气质</em> 将男性定义为必须主导和暴力，将女性视为性对象，并将性视为一场征服游戏。这种社会化过程通过家庭、同伴文化、媒体和更广泛的 <em>父权制</em> 社会结构传播。即使是来自良好家庭、平时表现正面的人，也可能在特定场景下做出极端负面的行为。</p><p>回到我上述提到的事件的性暴力加害者，他将自己的性侵行为用花言巧语装饰成双向奔赴的性爱，并认为过去的各类性骚扰行为是普通的求爱，<strong>因为他觉得自己比谁都更应得到女方的身体</strong>。这个人是怎么变成这样的呢？抛开现在到处传播的大男子主义思想外，还有周遭恐怖的大男子主义群体。在女方后续意识到自己被强奸时，群体里甚至还有这个男性的朋友向她传达男性沙文主义思想：<em><strong>你当时没有好好拒绝他，你活该被强奸</strong></em>。更不用提在他「追求」女方时，这帮「朋友」对女方施压的各类压力，好似在告诉她男方才是受害者，一切都是因为女方没能接受他的「求爱」。</p><p>这种群体的可怕不只是因为他们热爱压迫女性，他们对于男性也照样压迫。他们默认女性都是物品，可以被群体内部的人分享，因此没少出现过多个人同时喜欢一个人，然后私下分享「追求」成果。如果被拒绝，那就群众私下辱骂该女性，好让他们觉得自己「雄伟」，「像个男人」。不和他们共享同个思想的男性，会被他们鄙视、视为懦夫，换句话说便是，<em><strong>不是个男人</strong></em>。</p><p>我过去提及到 <a href="/posts/a2a2#%E7%BD%91%E7%BB%9C%E7%8E%AF%E5%A2%83"><em>群体极化</em></a> 这个现象。不只是网络世界，现实生活也会发生。实际上，只要是个稍微封闭的环境就可以造成该现象。内部群体会崇拜一个理念，而为了证明自己「忠诚」，不断去挑战极限、做出最极端的事情。这种大男子主义群体也是如此，只有够粗鲁、暴力才是男人，而这条标准又会因为成员的各种出格行为、被无限拔高。</p><p>一个容易被忽视的事实是，这种气质和一个人的其他品行是近乎不相关的。一个会家暴的人，他可以是一个最失败的混蛋，也可以是一个被人尊敬的公司老总。例如我刚才举例用的，在我的现实生活中所出现的这个群体的成员中，既有年轻有为的人，也有 <em>Incel</em>（非自愿单身。此处的用法是偏贬义的，类似于「屌丝」、「鲁蛇」等）。</p><p>而那个实施了性侵的人，不仅在家里是个被宠爱的孩子，在外还是个被同龄人崇拜、学业和专业方面做的都很好的人。但被他伤害过的人都知道，他不过是 <strong>一个平庸宛如尘土，心却比天大的可怜虫</strong>。在女方意识到自己被伤害后，立即问责了他。这个总是幻想自己是主导者、瞧不起女性的人，因为被女方问责，很快就变得像他常说的 <em>女人</em> 一样，哭得不能自我。</p><p>他所崩溃的，不仅是劣行的败露，更是那个由有毒男性气质精心构筑的、充满力量感的自我形象。先前说过，女方是一位聪慧的人。虽然在感情上被蒙骗，但她一旦想明白了，其他人的诡计便一个都使不出来。她深入了解后察觉到，这个男人连做她的朋友都不够格，因为他既无法提供任何情绪价值，也没有可以被利用的地方，甚至经常惹她生气。当我们看到这样一个 <em>被宠爱的孩子</em> 和 <em>平庸的可怜虫</em> 并存的双面体，我们自然无法简单称呼他为 <em>怪物</em>。</p><p>正因如此，Tom 和 Thordis 的和解之路才显得尤为重要：<strong>并非为了原谅，而是为了夺回被暴力剥夺的解释权</strong>。Thordis 主动写信、要求见面，是 <strong>夺回</strong>。她迫使 Tom 必须在她面前，承认那是「强奸」而不是「性爱」。我的朋友问责那个加害者，是 <strong>夺回</strong>。她当面戳穿了他的谎言与伪装，让他建构的虚假自我瞬间崩塌。</p><p>这个过程的核心，是验证自己的真实感受，确认「我所经历的就是伤害」，并要求对方和世界承认这一事实。它的首要目标和最终成果，是受害者自我的重建，而不是加害者是否得到宽恕。原谅可以是夺回解释权之后的一个 <em>可能结果</em>，但绝不是夺回行动本身的 <em>前提或目的</em>。</p><p>而这，也正是我们社会在面对每一桩暴力事件时，最需要学习的一课：不仅看到受害者的痛苦，更要直视加害者的人生。唯有如此，才能斩断暴力的循环。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;写一门课的作业时，我被要求在一众 TED 演讲里选一个进行分析。我随手一选，选到的是一个双人演讲。更没想到的是，这两个人的身份分别是「强奸者」和「被强奸者」。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="心理学" scheme="https://blog.cytrogen.icu/tags/%E5%BF%83%E7%90%86%E5%AD%A6/"/>
    
    <category term="社会学" scheme="https://blog.cytrogen.icu/tags/%E7%A4%BE%E4%BC%9A%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>你只是在怪她没有选你</title>
    <link href="https://blog.cytrogen.icu/posts/e0dc.html"/>
    <id>https://blog.cytrogen.icu/posts/e0dc.html</id>
    <published>2025-10-23T14:36:00.000Z</published>
    <updated>2026-02-09T17:16:55.009Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近日，一位朋友提起了自己的情感问题。简单来说，便是他在正值青春的年纪喜欢上了一位女生，却在这段关系中被这位女生反复推拉，一次次经历快乐的巅峰，又一次次经历痛苦的谷底。他本以为这一切会随着进入新环境而过去，但过去的种种回忆却时常浮现，往事也数次被唤醒。和我的对话中，他提到在网上看到的一句话：<em>你只是在怪她没有选你</em>。</p><span id="more"></span><h2 id="过去为何反复重现"><a class="markdownIt-Anchor" href="#过去为何反复重现"></a> 过去为何反复重现</h2><p>我对他的往事的主观想法，便是他很可悲地被一位缺爱的女性玩弄了。同为女性，还是经历过类似事件的人，我大致能理解她的心态：<strong>缺爱的人更倾向于控制追求者的情绪</strong>。这种情绪控制，我会称为是在「玩弄」，也就是大家常说的「被玩弄于股掌之间」。她们是蓄意的吗？不一定，但绝非完全无辜。我们都知道戏耍他人在道德上是不好的，但是它所能提供的安全感和「权利」对于缺爱和缺安全感的人而言，是难以抗拒的。</p><p>然而对男方而言，这种暧昧关系带来的却是持续的情感困扰与不安全感。他想要和女方在一起、谈恋爱，但摆在他面前的首先是一个身份问题：他们究竟是什么关系？女人和她不喜欢的追求者？单向喜欢的朋友？同学？要知道，在传统观念里，无论是哪种关系，都无法成为他要求女方不恋爱的理由。更进一步说，连「希望她不谈恋爱」这个念头，他都没有立场去拥有。</p><p>尽管女方知道男方喜欢自己，她却并未直接拒绝，反而是一边给出暗示性的举动、一边又时不时拉开距离。正是这种模糊不清的态度，使得暧昧与明确拒绝更难应用：你永远无法确定自己到底是以什么样的身份陪伴在心上人身边的。至少对这个朋友来说，他既不敢去问女方的想法，也没有勇气远离她。</p><p>他现在的表现，很明显是创伤后应激的闪回与反复回忆。这里可能需要澄清一个常见的误解：很多人以为创伤后应激只有上了战场才能得，但实则不然，创伤近乎遍布我们生活的边边角角。不受控制的侵入性记忆是创伤后应激的特征之一，其中情绪记忆尤为顽固。从神经机制上看，当人们遭受到强烈的情绪冲击，杏仁核会产生大量的高频伽马波活动，让海马体改变其编码方式、提高突触强度、更深更强地存储这一段记忆。如果只是被明确拒绝一次，这种强烈的记忆编码或许只发生一次。然而在他的案例中，关系上的推搡会反复强化这段痛苦的记忆。</p><p>面对这样的情感问题，不少人的提议都是「时间会治愈一切」。不得不说，我在经历那件情感问题之前也是这么认为的。然而事实是，时间不仅未能解决问题，反而还会因为长时间不处理、让人埋下了难以察觉的创伤。记忆的存储是多层分布的，当新环境和新恋情出现时，某些旧的记忆仍然存在并可能被特定触发因素激活，比如相似的情绪体验或环境线索。</p><h2 id="怪她没有选你"><a class="markdownIt-Anchor" href="#怪她没有选你"></a> 怪她没有选你</h2><p>有一个概念叫做拒绝创伤，即人际拒绝激活的大脑区域与身体疼痛激活的区域高度重叠，被拒绝确实会产生类似生理创伤的痛感。在神经系统的层面上来看，被拒绝会被我们的大脑处理为一种伤害。从进化的角度来看，这种反应是有意义的。在原始社会中，被社群拒绝意味着失去获取食物、受到保护和交配求偶的权利，从而很难生存下去。因此，人类的大脑发展出一种早期预警系统，当存在「被踢出群体」的风险时，该系统就会触发尖锐的痛感。</p><p>然而，这种疼痛远不止于神经信号，更深层次的是随之而来的自我价值感被削弱。对人类 —— 这种社会性动物 —— 而言，来自他人的接纳本身就是维系自尊的重要来源。社会计量理论正是由此出发，将自尊视为一种「社会温度计」，可以用来衡量我们被群体接纳或被排斥的程度。</p><p>长期的拒绝经验，会逐渐侵蚀个体的自我概念。低自尊的人对任何潜在的拒绝线索更为敏感，他们会过度解读他人的行为，把中性信号视为排斥。由此，这样的状态让人陷入一个恶性循环：越害怕被拒绝，就越容易感受到拒绝，从而进一步降低自我价值感。我的朋友正是陷入了这种循环。他不理解，为什么他足够优秀，但是被选的人从来就不是他。他已经在心中种下了一颗名为「根本性的失败」的种子：他想尽一切努力让她看到自己、认可自己，但从来都不够，因为他似乎永远都 <strong>不够好</strong>。</p><p>这里我们要厘清一个逻辑关系，<strong>关系的不合适绝不等同于自我的不够好</strong>。这是一个我们常说的道理，但真能渗透这句话的人貌似并不多。为了「被选」，许多人会像他一样，陷入疯狂自我提升乃至同辈竞争的状态；或因落选而反复质疑自身。但我们必须认清，一段关系的终结，核心原因只能是「不合适」。</p><p>根据他所说，他曾多次以为女方也喜欢自己，因为对方会说一些暗示性的话、送他花和礼物，最后却告诉他：「<em>我不喜欢你，我只是觉得你这样喜欢我很可怜，我想要补偿你</em>」。期望的轰然倒塌必然引致愤恨情绪，这是人之常情：我们在关系中无法得到自己想要的，便会变得沮丧、失望，甚至愤恨。更何况，对方的做法本质上是一种「情感戏耍」。</p><p>一段亲密关系的开始，往往都是为了得到一些我们孩童时期没能得到的东西。「<em>你只是在怪她没有选你</em>」，这句话揭示的是他「被选择」的心理需求。这里的核心逻辑可以用三层心理机制来理解：</p><ol><li><p>爱一个人被拒绝后，我们常会误以为那种痛苦是「失恋的伤」。但准确来说，那是来自被动丧失控制权的心理反应。在暧昧关系中，人容易把「成功与否」视作对方是否回应自己的情感。没有被选择，心底的声音并不是「我失去了她」，而是「我没被需要」。换句话说，「没有被选择」的痛要比「没有和这个人在一起」的痛更深。</p></li><li><p>真正的爱是向外流动的，是「我想让你幸福」；而需求则是内向的，是「我需要你让我感觉幸福」。暧昧中的人往往模糊了两者的边界。很多时候，「我喜欢你」的真实潜台词是：「<em>你让我感觉到被关注、被肯定、被需要</em>」。因此，当对方撤回了这些反馈时，个体失去的往往并不是爱情，而是自我确认的重要来源。</p><p>这背后是依附理论在起作用。人的安全感最初来源于童年与养育者的稳定联结。成年后，恋爱会成为新的依附对象，被拒绝会再次激活那种深植于心的「被抛弃」和「不被爱」的原始恐惧。</p><p>因此，表面上的愤怒指向对方，但本质上，愤怒的根源是那个因关系动摇而再次感到无助、缺乏安全感的自己。</p></li><li><p>先前提到，自尊是一种社会温度计，反映我们在社群中的受接纳程度。被拒绝时，大脑会自动解读为自我价值下降。「她为什么不选我」的执念，实际上是在抵抗「我是不是不值得被爱」这一羞耻感。换言之，他未必是「爱得无法自拔」，而是无法接受「未被选中」所象征的失败与羞耻。将这份羞耻感转化为对外的怨恨，是一种常见的心理防御机制。</p></li></ol><p>综合这三层机制来看，他表现出的是一个典型的低自我价值感个体，其情绪状态严重依赖外部认可来维持。事实上，他确实是这样的一个人。在其他人际关系中，他也习惯于将问题归咎于自己：「<em>我要是当时这么做就好了</em>」、「<em>我要是更早地这么做就好了</em>」…… 这种归因模式通常源自于早期的情感剥夺或者不稳定的依附关系，这类人会在童年时期就学会如何去压抑自己、过度承担责任。当关系出现问题时，他们的第一反应也不是愤怒或质疑，而是内疚与自责。这绝对不是成熟的责任感，而是一种恐惧驱动的讨好逻辑。</p><p>表面上，「都是我的错」看似谦卑，实则是一种虚假的控制感。通过自责，我们得以维持一种幻觉：只要自己够努力，就能控制关系的走向，让对方回心转意。这种心态的核心是焦虑：害怕被抛弃。它让人宁愿把错误都揽在自己身上，也不愿直面「我无法控制他人意愿」的现实。久而久之，这种过度承担会变成关系中的单向负担，个体不断通过自我消耗来换取短暂稳定，反而加剧了内心的无力感和情感上的依附循环。</p><p>当「我造成的」和「我该改」成为惯性思维，个体就逐渐失去了 <strong>辨认界限</strong> 的能力：到底哪些是我的责任，哪些又是对方的选择？在暧昧或失衡关系中尤其明显。对方模糊不清的态度会让低自我价值者不断「修正」自己，试图换取一丝确定的认可。然而，越是努力讨好，就越是强化了「我只能通过付出来换取价值」的错觉，最终导致彻底的自我迷失 —— 连「我是谁」和「我想要什么」都不知道了。</p><h2 id="青春期经历的特殊性"><a class="markdownIt-Anchor" href="#青春期经历的特殊性"></a> 青春期经历的特殊性</h2><p>网上有个概念叫做「白月光」，这通常用于描述高中、大学时未能得到的初恋。它之所以能成为人们心中难以磨灭的记忆，并不仅仅是因为爱情本身的美好，还有青春期阶段的心理和生理特点。</p><p>首先，从神经科学上看，青春期正是大脑高度可塑性的阶段。大脑中的突触连接处于剧烈重塑过程中，尤其是与情绪、记忆、社交相关的边缘系统和前额叶区域。因此，此时经历的强烈的情感体验，更容易在神经回路中留下深刻且持久的痕迹。这便解释了，为何即便成年之后，那些青春时代细小的遗憾也常常在脑海中挥之不去。</p><p>其次，青春期是自我认同形成的关键期。青少年正经历「我是谁」的剧烈探索，会不自觉地把外界的评价、同龄人的回应乃至亲密关系的成败，都映射到对自身的价值与身份定义上。所以，初恋被拒绝就不仅仅是一次情感受挫，更构成了一次对「自我」的直接否定。于是，这段「未完成」的关系就和「我是一个不被选中的人」的自我认知深深捆绑，成为一个难以割舍的情结。</p><p>也正因为是第一次投入全部信任和憧憬、第一次体会爱的波动与失落，相关的记忆才更容易被事后美化、神话，并被赋予超越现实的意义。我的这位朋友对此并非毫无觉察，他清楚地知道自己美化了那个女生和共同的回忆，只有在翻出过去的各个证据时，才能记起对方曾经的所作所为。说到底，「白月光」的背后是创伤，也是未尽的期望。它是一个关于纯洁、遗憾与自我价值的混合投影，是那个「如果当初我们在一起，我的人生将会如此不同」的青春式想象。</p><p>对于身处高中阶段的个体而言，失恋或暧昧关系的破裂会产生比成年人更为强烈的情感反应。这是由于青春期荷尔蒙剧烈变化、情绪调节系统尚未成熟，导致青少年在面对被拒绝时更易出现极端的情绪波动，这些体验也比成年后更鲜明、更难以自控。与此同时，情绪调节能力不足也是关键。青少年尚未建立起成熟的情绪管理与自我安慰机制，被拒绝的痛苦往往无法及时有效释放和处理，只能在心里反复「回放」，进一步强化记忆、加深创伤。</p><p>此外，狭小却复杂的社交圈与沉重的声誉压力，进一步加剧了内心的负担。高中时期，同龄人之间的传言、评价、集体归属感的流动都使得被拒绝不仅是个人的情感失落，更像是以小集体为单位的「社会性伤害」。一段关系的流产、暧昧的失败，可能在同学、朋友圈里引发从善意的调侃到恶意的排斥，乃至固化的负面标签，这些外部压力使得青春期被拒绝的创伤更加复杂和深入。</p><h2 id="你需要的她给不了"><a class="markdownIt-Anchor" href="#你需要的她给不了"></a> 你需要的，她给不了</h2><p>满足他人，从来都不是任何人的责任，正如我们也无法完全为另一个人的幸福负责一样。我们内心深处所渴望的无条件接纳、绝对安全感与完整的自我价值确认，** 事实上，没有任何一个外部个体能够提供。** 试图从一段暧昧或亲密关系中索取这些，无异于要求对方去填满一个连我们自己都看不到底的内心深渊。</p><p>于是，解决问题的核心在于放下不切实际的期望，以及期望落空后产生的愤恨。我们常常误以为愤恨是针对那个「没有满足我们」的人，但更深层来看，那是针对「自己需求未被满足」这一事实的无力感。失恋本身并不会降低我们的自我价值，它只是一面镜子，映射出我们内心早已存在的、关于自我价值的裂缝。对方出现在我们生命中的意义，并非成为一个完美的供给者，而是通过这段关系，塑造我们的成长，让我们看清自己需要修补的地方。</p><p>在这个过程中，所有涌现的情绪，不论是悲伤、愤怒、不甘，还是委屈，都是正常且重要的。我们身处一个常常嘲笑脆弱、推崇快速翻篇的有毒社会中，但疗愈的前提是承认并接纳所有这些感受。伊丽莎白・库伯勒・罗丝提出的悲伤五阶段（否认、愤怒、讨价还价、沮丧、接纳）不仅适用于面对死亡，也同样适用于任何重大的丧失，包括一段重要关系的终结。我们需要给予自己足够的时间和空间，去完整地经历这个过程，而不是跳过它。</p><h2 id="走出创伤"><a class="markdownIt-Anchor" href="#走出创伤"></a> 走出创伤</h2><p>要打破拒绝敏感性的恶性循环，第一步是进行认知上的重构：<strong>将「被拒绝」与「我不够好」这两个概念分离开</strong>。每一次拒绝，都可以被重新解读为一次「走出舒适圈」的尝试，或者一次价值观的检验。它的核心结论是「我们之间不合适」，而绝非「我这个人很失败」。这需要刻意地练习，就像锻炼肌肉一般，去建立新的神经通路。</p><p>放手，从来不是承认失败或者放弃追求，而是选择放过自己。它意味着你终于能全然接纳「她没有选你」这个简单而残酷的事实，并停止在内心继续与之对抗。当我们停止对抗，与之相关的情绪才会开始真正流动和消散。</p><p>首先，我们必须赋予他的创伤以合法性：痛苦是真实且值得被深切理解的。我的朋友所经历的一切，绝非「想太多」或「不够坚强」。然而，在充分承认这一切之后，一个更至关重要的真相浮现出来：<strong>一个人的终极价值，从来不由「谁选择了我」来裁定</strong>。他那么努力地想要被看见、被认可、被选择，却忘了最重要的选择权，一直就在他自己手中：他可以选择相信自己本具的价值，选择不再让过去的拒绝来定义当下的自己，选择带着这些伤痕，继续坚韧地成长。</p><p>那个女生没有选他，<strong>但他可以选择自己</strong>。</p><p>我想，这就是我最终试图告诉他的。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;近日，一位朋友提起了自己的情感问题。简单来说，便是他在正值青春的年纪喜欢上了一位女生，却在这段关系中被这位女生反复推拉，一次次经历快乐的巅峰，又一次次经历痛苦的谷底。他本以为这一切会随着进入新环境而过去，但过去的种种回忆却时常浮现，往事也数次被唤醒。和我的对话中，他提到在网上看到的一句话：&lt;em&gt;你只是在怪她没有选你&lt;/em&gt;。&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="心理学" scheme="https://blog.cytrogen.icu/tags/%E5%BF%83%E7%90%86%E5%AD%A6/"/>
    
    <category term="情感" scheme="https://blog.cytrogen.icu/tags/%E6%83%85%E6%84%9F/"/>
    
  </entry>
  
  <entry>
    <title>吃免费的饭，骂做饭的厨子</title>
    <link href="https://blog.cytrogen.icu/posts/a2a2.html"/>
    <id>https://blog.cytrogen.icu/posts/a2a2.html</id>
    <published>2025-10-22T14:10:00.000Z</published>
    <updated>2026-02-09T17:16:55.213Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我喜欢阅读漫画，尤其是日本漫画。不过近期我关注的一个作品的粉丝群因为一件极为离谱的事情解散了：毫无用途的群管理无端辱骂「烤肉 man」，并表示不缺你一个汉化的。</p><p>如果把未翻译的内容视作「生肉」，那么被翻译的自然就是「烤肉」、进行「烤肉」行为的就是「烤肉 man」。免费为大家汉化内容的「烤肉 man」们被读者赶跑的事情，仿佛并不罕见。但是，<strong>为什么人们那么乐意攻击主动贡献者？</strong></p><span id="more"></span><h2 id="搭便车问题"><a class="markdownIt-Anchor" href="#搭便车问题"></a> 搭便车问题</h2><p>经济学和心理学中有一个经典概念叫做「搭便车问题」：当有人免费提供公共物品时，其他人会倾向于享受成果而不付出。这本身无可厚非，但问题在于，搭便车者内心深处往往对自己的不劳而获感到不安。这种不安来自两个层面：</p><ol><li><p>对「成为冤大头」的恐惧。</p><p>社会心理学中有一个概念叫做「社会性懈怠」，指的是人们担心自己付出太多而被其他成员占便宜，因而减少努力的现象。当我们接受别人的免费付出时，内心会产生一种微妙的自我质疑：<em>我是不是那个被利用的二傻子？对方是不是在用恩惠控制我？</em></p><p>这种对「被当傻子」的厌恶会严重影响人们的决策。研究表明，即使在没有任何社会后果的实验环境中，人们也会因为害怕「被占便宜」而拒绝合作，哪怕合作明显对双方都有利。</p></li><li><p>不平等关系带来的心理负担。</p><p>当一个人持续接受他人的帮助而无法回报时，会产生一种权力失衡。贡献者拥有「给予」的权力，而接受者则处于「被施恩」的被动位置。这种不对等会让接受者感到：</p><ul><li>自尊受损：<em>我为什么需要依赖别人？</em></li><li>自我贬低：<em>我是不是不如对方有能力？</em></li><li>失去控制感：<em>我欠了人情，是否意味着我要听从对方？</em></li></ul><p>当人们无法回报恩惠时，最容易产生的情绪其实不是感激，而是 <strong>怨恨</strong>。</p></li></ol><p>当接受者内心产生「我是搭便车者」的羞耻感时，人类的防御机制会启动一个危险的转换：将内在的羞耻投射为对外的愤怒。这个转换过程遵循一个典型的心理链条：</p><ol><li><em>我不得不接受他的汉化。</em></li><li><em>他让我觉得自己无能。</em></li><li><em>我有权利要求他做得更好。</em></li></ol><p>一旦进入第三阶段，搭便车者会开始合理化自己的攻击行为。这种转变涉及多个心理机制：</p><ul><li>通过批评别人、要求更高的标准，将原本的不道德行为（不出力却享受）重新定义为道德的行为（虽然我没出力，但我是在监督质量、要求进步）。</li><li>将自己的不贡献归因于外部环境，却将贡献者的成果不足归因于内在能力不足。</li><li>将「互惠」理解为「既然我享受了你提供的好处，我应该给你『反馈』」。但这个反馈不是正面的回报，而是「建设性的批评」和「更高的要求」。通过批评来「贡献」，巧妙地将自己的不出力转变为一种「参与」形式。</li><li>内心深处清楚自己没有付出却享受了利益，这造成了认知失调。为了消除这种不适感，他们采取最简单的策略：通过批评别人来缓解自己的内疚感。</li></ul><p>那位群管理能说出「想走就走，又不缺你一个烤肉的」这种很离谱的话时，本质上是在试图夺回被贡献者「威胁」的权力。而要重新确立「我也有价值」的自我认知，最简单且粗暴的方式便是贬低和攻击那些威胁其社会地位的人。</p><h2 id="网络环境"><a class="markdownIt-Anchor" href="#网络环境"></a> 网络环境</h2><p>这些攻击往往发生在网络空间。人们在网络中感觉解放，变得更加肆无忌惮，并且更倾向于无视各种社会约束或社交禁忌。具体来说，网络环境造成了心理学家约翰・苏勒所提出的六个关键的心理转变：</p><ul><li><strong>你不知道我是谁</strong>：匿名性给了用户一种心理安全感。当真实身份无法被识别时，人们感到可以自由地说出平时会让自己尴尬的话，甚至做出被视为反社会或有害的行为。</li><li><strong>你看不到我</strong>：缺乏对方的真实反馈。用户无法观察到对方的表情变化、眼神反应或语气变化，这削弱了人们对他人感受的同理心。</li><li><strong>待会儿见</strong>：网络交流的非实时性让人可以说完就走。用户可以发布情绪化的言论，然后简单地退出或删除，无需为此承担实时的社会后果。</li><li><strong>这是我脑中的世界</strong>：在缺乏现实交互要素的情况下，人们根据接收到的消息自行想象对方的样貌、声音和性格。这种想象的自由度高，容易投射个人的欲望和需求，甚至可能将对方想象成自己讨厌的人。</li><li><strong>这只是场游戏</strong>：将网络空间视为一个游戏场所，在这里日常生活中的道德规范「不适用」。用户能够清晰地区分网络角色与现实角色，迅速切换于各种身份之间。</li><li><strong>你的规则在这儿不管用</strong>：现实中的社会地位、职业身份、年龄都在网络上无效。匿名性使得权力结构扁平化，这给了那些在现实中处于低权力地位的人一种 "翻身" 的幻觉。</li></ul><p>除了这些去抑制效应，去个性化理论也进一步解释了为何攻击在群体中更加激烈。去个性化指的是在群体中，个体失去了对自己行为的责任感，使自身自我控制系统的作用减弱甚至丧失。这包含两个核心要素：</p><ul><li>当个体隐匿在群体中、无法被辨认时，会觉得自己是匿名者而放纵。他们认为即使做了坏事也不会被识别出来，因此可以毫无顾忌地违反社会规范。</li><li>在群体中，个人觉得自己对集体行为不负责任。群体活动的责任被分散在每个成员身上，没有任何一个具体成员需要承担谴责。群体规模越大，这种效应越明显。</li></ul><p>在线社群会随着时间推移变得越来越有毒。我认为无论是谁只要有加入过 QQ 群或者类似社群的，都能发觉到这个事实。这里的「有毒」指代的是三种暴力模式：</p><ol><li>施虐式娱乐：以攻击他人为乐。</li><li>派系战争：不同小团体争夺主导权。</li><li>私刑正义：成员自发「惩罚」违规者。</li></ol><p>这是因为网络社群中存在着群体极化现象。当搭便车者集聚在一起时，他们对贡献者的批评不会减弱，而是通过群体动力学被不断放大。社群成员会为了获得身份认同感和心理安全感，去迎合群体的主流意见。而为了获得更多支持，个体会有意地将自己的立场表现得比其他人更加坚定。这会导致群体内的平均立场不断向极端方向移动。当个体采取更为激烈的言论或行为攻击异见者，对贡献者的攻击就不再是个人的心理补偿，而是成为了群体的集体行为，获得了群体的强化和鼓励。</p><p>旁观者效应在网络中也适用，但有所不同。在现实中，当有多个旁观者时，人们帮助他人的可能性反而降低。然而在网络上，这个效应表现为管理的缺失 —— 没有人对群体暴力进行干预。在网络群体中，管理员可能是缺席的或被搭便车者控制的，理性的声音往往被淹没在情绪化的声音中，干预者也有可能变成被攻击的对象。如果说话的人都是指责贡献者的搭便车者，对贡献者的攻击就会看起来像是「群体的共识」，尽管实际上只是少数人在制造噪音。</p><h2 id="预防"><a class="markdownIt-Anchor" href="#预防"></a> 预防</h2><p>如何预防、如何面对这种事情呢？</p><p>如果你是贡献者，请明确自己的贡献范围，不要让免费变成无限索取的接口；攻击往往不是因为你做得不好，而是因为你的存在让某些人感到威胁。这不是你的问题；如果一个社群持续不尊重贡献者，离开是最健康的选择。</p><p>如果你是接受者，请时刻提醒自己这是他人的善意，不是你应得的；哪怕是小小的回馈，都能平衡关系中的权力失衡，例如感谢、力所能及的帮助；当你开始觉得「他应该为我做更多」时，停下来想一想：<em>到底是谁欠谁</em>？</p><p>如果你是社群管理者，请制定清晰的社群规则，保护贡献者不受攻击；当看到对贡献者的攻击时，及时介入而不是沉默；公开肯定贡献者的价值，不要让「理所当然」成为常态。</p><p>一个健康、可持续的社群文化，是一个既感激贡献者，也欢迎搭便车者，但绝不容忍攻击的社群。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;我喜欢阅读漫画，尤其是日本漫画。不过近期我关注的一个作品的粉丝群因为一件极为离谱的事情解散了：毫无用途的群管理无端辱骂「烤肉 man」，并表示不缺你一个汉化的。&lt;/p&gt;
&lt;p&gt;如果把未翻译的内容视作「生肉」，那么被翻译的自然就是「烤肉」、进行「烤肉」行为的就是「烤肉 man」。免费为大家汉化内容的「烤肉 man」们被读者赶跑的事情，仿佛并不罕见。但是，&lt;strong&gt;为什么人们那么乐意攻击主动贡献者？&lt;/strong&gt;&lt;/p&gt;</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="互联网" scheme="https://blog.cytrogen.icu/tags/%E4%BA%92%E8%81%94%E7%BD%91/"/>
    
    <category term="心理学" scheme="https://blog.cytrogen.icu/tags/%E5%BF%83%E7%90%86%E5%AD%A6/"/>
    
    <category term="社会学" scheme="https://blog.cytrogen.icu/tags/%E7%A4%BE%E4%BC%9A%E5%AD%A6/"/>
    
  </entry>
  
  <entry>
    <title>在 Hexo 项目中添加 Webmention</title>
    <link href="https://blog.cytrogen.icu/posts/1de.html"/>
    <id>https://blog.cytrogen.icu/posts/1de.html</id>
    <published>2025-10-14T16:16:17.000Z</published>
    <updated>2026-02-09T17:16:55.213Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>Webmention 是 IndieWeb 的一个核心的开放标准，允许网站之间像社交平台一样互动：评论、点赞、转发等。重点是它去中心化、跨站点实现这些功能。</p><p>要知道，我的博客是用「老掉牙」的 Hexo 构建的。Hexo 的插件列表里，可是没有任何一款插件是和 Webmention 相关的。假设我想要在自己的网站里添加 Webmention 的发送和接收功能，只能自己写。更悲伤的是，我的「强迫症」要求我在自己开发的主题里也添加上即拿即用的 Webmention 功能。</p><span id="more"></span><div class="danger"><p>和过去一样，我会将 Hexo 项目根目录的 <code>_config.yml</code> 称呼为 Hexo 配置项、将 <code>themes/主题名/</code> 目录下的 <code>_config.yml</code> 称呼为主题配置项。</p><p>我用的是 Markdown + Pug。如果你用的是其他引擎，请自行改动代码，逻辑应当都是相同的。</p><p>该文章默认你是 Hexo 插件 &amp; 主题开发者！如果你不是、又或者说只是想要即拿即用的方案，见 <a href="#%E6%8F%92%E4%BB%B6">这里</a>。</p></div><h2 id="接收"><a class="markdownIt-Anchor" href="#接收"></a> 接收</h2><p>要想接收 Webmention，非常简单。你只需要在网站里添加这样的标签：</p><pre><code class="language-html">&lt;link rel="me" href="https://github.com/yourusername" /&gt;</code></pre><p>这不需要是 GitHub 链接。实际上大多数社交平台的链接都可以，像 GitLab 啦、推特啦、长毛象啦…… 我写了一个辅助函数来检测一个链接是否是社交平台的链接：</p><pre><code class="language-plaintext">-    function isSocialMediaUrl(url) {        if (!url) return false;        const socialDomains = [            'github.com', 'gitlab.com', 'bitbucket.org',            'twitter.com', 'x.com', 'mastodon.social', 'mastodon.online',            'linkedin.com', 'facebook.com', 'instagram.com',            'weibo.com', 'zhihu.com', 'bilibili.com',            'youtube.com', 'youtu.be', 'tiktok.com',            'discord.gg', 'telegram.me', 't.me'        ];        try {            const domain = new URL(url).hostname.toLowerCase();            return socialDomains.some(socialDomain =&gt;                 domain === socialDomain || domain.endsWith('.' + socialDomain)            );        } catch {            return false;        }    }</code></pre><p>这个 <code>&lt;link&gt;</code> 呢，放在哪里都可以。像我就偷懒了，直接在我的二级菜单里添加了这个判断条件：</p><pre><code class="language-plaintext">mixin nav-link(item)    if item.type === 'internal'    // 省略    else if item.type === 'external'        - var relAttr = "noopener noreferrer" + (isSocialMediaUrl(item.path) ? " me" : "")        a.nav-link(href=item.path target="_blank" rel=relAttr)            != __(`menu.${item.key}`)            +icon-external-link()</code></pre><p>我的主题可以手动标记二级菜单里的链接是否是内部还是外部的（其实自动识别更好，但我偷懒了）。假设是外部链接，就让主题判断它是否是社交平台链接。如果是的话，就添加 <code>rel="me"</code> 这个属性。因为二级菜单里的链接大概率都是自己的社交平台链接，所以我认为这么写完全没问题~</p><p>这样做的目的是身份验证。现在来到 <a href="https://webmention.io/">Webmention.io</a> 里便可以注册该网站、获得你的接收网址：</p><pre><code class="language-plaintext">&lt;link rel="webmention" href="https://webmention.io/你的域名/webmention" /&gt;</code></pre><p>再将其添加网站的 <code>&lt;head&gt;</code> 里：</p><pre><code class="language-plaintext">if theme.webmention &amp;&amp; theme.webmention.domain    link(rel="webmention", href=`https://webmention.io/${theme.webmention.domain}/webmention`)</code></pre><pre><code class="language-yaml">webmention:  domain: 你的域名</code></pre><p>为了让使用到 Hexo-Theme-Ares 的用户也可以立即使用上 Webmention，我写成了需要在主题配置项里配置、才能自动添加接收链接的逻辑。</p><p>收到的所有 Webmention 都可以在 <a href="https://webmention.io/settings/sites">Webmention.io 的仪表盘</a> 里查看。</p><h2 id="发送"><a class="markdownIt-Anchor" href="#发送"></a> 发送</h2><p>我参考的是 <a href="https://webmention.app/docs">Webmention.app 文档</a> 里的做法。</p><div class="danger"><p>我建议还在开发该功能的朋友们，先使用手动发送。待功能完善后，再进行自动化。</p><p>问的话，只能说都是泪。我在功能还未完善时就采用了 Netlify 自动请求 Webhook 的方案。结果向接收方发送了数个不完善的 Webmention。这些 Webmention 还无法撤回，只能等待对方自行移除。不是什么大问题，但心里会想着给对方添了麻烦、实在是抱歉。</p><p>再就是手动发送时请一定要注意自己网页的 URL 规范。例如我现在这个文章，你可以用 <code>/posts/1de</code> 访问，也可以用 <code>/posts/1de.html</code> 访问。看似是一样的，但是对于 Webmention.io 而言它们是完全不同的源地址。</p><p>假设你先用了不带 <code>.html</code> 的 URL 作为源地址发送，之后又用了带 <code>.html</code> 的 URL 作为源地址发送。即时它们内容一样、目标一样，服务器也会创建两条独立的记录。</p><p>想知道我是如何知道的吗？就算你问我这个问题，我也只能看着接收方数个重复的 Webmention 记录、笑笑不说话了。</p><p>我个人建议用后者发送，因为是 Permalink。</p></div><p>Webmention.app 提供了数个发送的方法，其核心都是通过检查指定 URL 的内容并自动发现其中的链接目标，然后向这些目标发送 Webmention 通知：</p><ul><li>基础发送方式<ol><li>命令行工具<ul><li>使用 <code>curl -X POST</code> 向 <code>https://webmention.app/check?url=你的网页地址</code> 发起请求</li><li>支持一次性发送单条或多条条目，会自动发现 <code>.h-entry</code> 等 Microformats 标记（见 <a href="#microformats">Microformats</a>）</li><li>可通过 GET 请求进行 dry-run 预览，也就是检查将要发送的 Webmention 但不会实际发送</li><li>建议在 Webmention.app 内领取令牌并配合使用，避免速率限制。如果不添加令牌的话，每个独立的 URL 每四个小时只能请求一次。用法很简单，只需要在 API 里添加 <code>token</code> 参数</li></ul></li><li>Node.js 本地工具<ul><li>安装 <code>@remy/webmention</code> 包后，可以使用 <code>webmention</code> 或者简写命令 <code>wm</code></li><li>支持读取多种内容格式，包括 HTML、RSS、Atom</li><li>使用方法：<code>npx webmention 你的网站的feed地址 --limit 数字 --send</code><ul><li><code>--limit</code> 默认为 10 条。假设设置成 1，就是发送 feed 里最新的文章的 Webmention</li><li>默认执行 dry-run，加上 <code>--send</code> 参数才会实际发送 Webmention</li></ul></li></ul></li><li>Webmention.app 网页<ul><li>该方案没有在文档中提及。简单来说便是在 <a href="https://webmention.app/check">Webmention.app 的 Test a URL 页</a> 手动填写网页地址、手动点击 <strong>Send All Webmentions</strong> 按钮发送</li><li>其实就是「命令行工具」方案的网页版，更好看些</li></ul></li></ol></li><li>自动化发送方案<ol><li>Netlify 部署通知<ul><li>步骤<ol><li>在 Netlify 项目中访问 <strong>Deploys</strong> 页</li><li>点击 <strong>Notifications</strong> 按钮</li><li>在 <strong>Deploy notifications</strong> 块旁找到 <strong>Add notification</strong> 选项</li><li>点击后选择 <strong>HTTP POST request</strong></li><li><strong>Event to listen for</strong> 选择 <strong>Deploy succeeded</strong></li><li><strong>URL to notify</strong> 输入该 URL：<code>https://webmention.app/check?token=令牌&amp;limit=限制发送多少条&amp;url=你的网站feed地址</code></li></ol></li><li>每次部署成功后，Netlify 都会自动向 Webmention.app 发送 POST 请求</li><li>其实该方法就是最先说的「命令行工具」方案的进化版，并不意味着必须要使用 Netlify 部署网站才能自动化。你只要能确保每次部署成功后都可以发送一次该 POST 请求即可</li></ul></li><li>IFTTT + RSS Feed<ul><li>该方案需要付费。我个人不推荐该方案，你可以找找 IFTTT 的免费代替品，或者使用其他方案。和我上面说的一样，这些方案的本质都是向 Webmention.app 发送 POST 请求</li></ul></li><li>IFTTT + 定时触发<ul><li>同上，不推荐</li></ul></li></ol></li></ul><h4 id="microformats"><a class="markdownIt-Anchor" href="#microformats"></a> Microformats</h4><p>Microformats 是一组基于 HTML 的轻量级语义标记规范，用于在网页中嵌入结构化数据，使人类和机器都能更好地理解和使用网页内容。</p><p>它的核心概念是：</p><ul><li>不需要额外的语法或嵌套语言，直接在网页中使用标准 HTML 元素和 <code>class</code> 属性</li><li>通过添加特定 <code>class</code> 名称来标记文章、人物、事件等信息</li><li>搜索引擎、浏览器、社交平台等可以自动识别这些标记并提取结构化数据</li><li>标记内容仍然是普通网页的一部分，不影响用户阅读体验</li></ul><p>为了让 Webmention 功能更完整地显示我们的内容，Microformats 是十分建议添加的。重点在于第二条：<em>标记文章、人物、事件等信息</em>。</p><ul><li><p>文章：<code>h-entry</code> 用于标记网页内容条目的语义类名</p><ul><li><p>用纯 HTML 作为例子，用法是这样的：</p><pre><code class="language-html">&lt;div class="h-entry"&gt;  &lt;p&gt;世界你好~&lt;/p&gt;&lt;/div&gt;</code></pre></li><li><p>要想添加标题、摘要、正文等信息，需要在 <code>h-entry</code> 所属的标签内部添加子标签。这些是广泛使用的属性：</p><ul><li><p><code>p-name</code>：条目标题或名称</p><pre><code class="language-html">&lt;div class="h-entry"&gt;  &lt;p class="p-name"&gt;我是标题&lt;/p&gt;  &lt;p&gt;世界你好~&lt;/p&gt;&lt;/div&gt;</code></pre></li><li><p><code>p-summary</code>：简短摘要</p><pre><code class="language-html">&lt;div class="h-entry"&gt;  &lt;p class="p-name"&gt;我是标题&lt;/p&gt;  &lt;p class="p-summary"&gt;我是摘要&lt;/p&gt;  &lt;p&gt;世界你好~&lt;/p&gt;&lt;/div&gt;</code></pre></li><li><p><code>e-content</code>：正文内容</p><pre><code class="language-html">&lt;div class="h-entry"&gt;  &lt;p class="p-name"&gt;我是标题&lt;/p&gt;  &lt;p class="p-summary"&gt;我是摘要&lt;/p&gt;  &lt;p class="e-content"&gt;世界你好~&lt;/p&gt;&lt;/div&gt;</code></pre></li><li><p><code>dt-published</code>：发布时间（建议使用 <code>&lt;time datetime&gt;</code>）</p><p>就不举例了，总之和上面的例子一样，都是标签里加类名。</p></li><li><p><code>dt-updated</code>：更新时间</p></li><li><p><code>p-author</code>：分类或标签</p></li><li><p><code>u-url</code>：条目的永久链接</p></li><li><p><code>u-uid</code>：唯一标识符，通常与 <code>u-url</code> 相同</p></li><li><p><code>p-location</code>：发布地点（可嵌套 <code>h-card</code>、<code>h-adr</code>、<code>h-geo</code>）</p></li><li><p><code>u-syndication</code>：条目的分发副本链接</p></li><li><p><code>u-in-reply-to</code>：所回应的原始条目链接（可嵌套 <code>h-cite</code>）</p></li><li><p><code>p-rsvp</code>：RSVP 状态</p><ul><li><p>RSVP 指的是法语短语「<em>Répondez s'il vous plaît</em>」的缩写，意思是「请回复」。在活动邀请中，它用于请求受邀者告知是否会出席。虽然来源是法语，但这个缩写已经被英语和其他语言广泛采用，尤其在正式或半正式的场合中</p></li><li><p>在 Microformats2 的语义标记中，<code>p-rsvp</code> 用来表示你对某个活动（<code>h-event</code>）的回应状态。支持的值包括：</p><ul><li><code>yes</code>：会参加</li><li><code>no</code>：不会参加</li><li><code>maybe</code>：尚未决定</li><li><code>interested</code>：感兴趣但未承诺参加</li></ul></li></ul></li><li><p><code>u-like-of</code>：所点赞的条目链接</p></li><li><p><code>u-repost-of</code>：所转发的条目链接</p></li></ul></li><li><p>虽然没有强制要求，但一个典型的 <code>h-entry</code> 应至少包含：</p><ul><li><code>u-url</code></li><li><code>dt-published</code></li><li><code>e-content</code> 或 <code>p-summary</code></li><li><code>p-name</code></li><li><code>p-author</code>：稍后在 <code>h-card</code> 提到</li></ul></li></ul></li><li><p>人物：<code>h-card</code> 用于在网页中嵌入人物或组织的结构化信息</p><ul><li>和 <code>h-entry</code> 一样的用法。核心属性是这些，它们都是可选的，并且支持多值：<ul><li><code>p-name</code>：姓名或组织名称</li><li><code>u-url</code>：主页或代表链接</li><li><code>u-photo</code>：头像或代表图像</li><li><code>u-email</code>：邮箱地址</li><li><code>p-org</code>：所属组织</li><li><code>p-job-title</code>：职位名称</li><li><code>p-note</code>：附加说明</li><li><code>p-category</code>：标签或分类</li><li><code>dt-bday</code>：生日日期</li><li><code>p-tel</code>：电话号码</li><li><code>p-adr</code>：地址信息，可嵌套 <code>h-adr</code></li><li><code>p-geo</code> / <code>u-geo</code>：地理位置，可嵌套 <code>h-adr</code></li></ul></li><li><code>h-card</code> 不强制放入 <code>h-entry</code> 内，但我 <strong>推荐</strong> 嵌套使用。这样有助于 Webmention 接收方或 Microformats 解析器识别作者是谁，并展示头像、名称、主页等信息</li></ul></li></ul><p>现在我们回到 Hexo。我建议在渲染文章的 <code>&lt;article&gt;</code> 标签里添加 <code>h-entry</code> 类。</p><p>我个人的写法是这样的：</p><pre><code class="language-plaintext">mixin post(item)    .post        article.post-block.h-entry            .post-meta.p-author.h-card                img.author-avatar.u-photo(src=url_for(theme.logo), alt=config.author)                a.author-name.p-name.u-url(href=config.url)= config.author                a.post-permalink.u-url(href=full_url_for(item.path)) 永久链接                if item.excerpt                    .p-summary                        != item.excerpt                h1.post-title.p-name                    != item.title                +postInfo(item)                if item.in_reply_to                    .post-reply                        != __('reply_to') + ': '                        a.u-in-reply-to(href=item.in_reply_to)= item.in_reply_to                .post-content.e-content                    != item.content</code></pre><div class="danger"><p>此处我直接照搬的主题源码。实际传参用的是 <code>page</code>。</p><p>需要注意的是，我没有使用到全部的属性。未来我会慢慢扩展这些内容。</p></div><pre><code class="language-plaintext">mixin postInfo(item)    .post-info        time.post-date.dt-published(datetime=date_xml(item.date))            != full_date(item.date, 'l')        if item.from &amp;&amp; (is_home() || is_post())            a.post-from(href=item.from target="_blank" title=item.from)!= __('translated')</code></pre><p>在文章中的 Front Matter 里添加该属性来指定目标地址：</p><pre><code class="language-markdown">---in_reply_to: 目标地址---</code></pre><p>不过我的主题有些特殊：</p><ol><li>导航栏会渲染我的头像作为 logo，我不想要文章又一次显示该头像</li><li>部分内容显示出来会导致整体页面看上去比较臃肿</li><li><code>item.content</code> 包含了 <code>item.excerpt</code> 在内。直接从 <code>item.content</code> 里取摘要会很麻烦，再显示一次 <code>item.excerpt</code> 又很奇怪</li></ol><p>解决方案也很简单。既然这部分内容只是给机器看的，我们将其隐藏就好了。直接全部加上 <code>display: none</code> 样式。</p><h2 id="进阶玩法"><a class="markdownIt-Anchor" href="#进阶玩法"></a> 进阶玩法</h2><h4 id="仅发送一部分内容"><a class="markdownIt-Anchor" href="#仅发送一部分内容"></a> 仅发送一部分内容</h4><p>有时候，你一个文章里只有小部分内容是你想要发送的；有时候，接收方的 Webmention 显示处并没有写字数限制，你的文章会原封不动地全部显示在接收方的网页里。至少我是想要一个更灵活的发送方法，因此我写了个脚本。</p><p>效果如下：</p><pre><code class="language-markdown">{% reply 目标地址 %}这是会被发送给目标地址的内容。目标地址是 xxx。{% endreply %}这是不会被发送给目标地址的内容。</code></pre><p>首先我们需要注册标签 <code>reply</code>：</p><pre><code class="language-javascript">hexo.extend.tag.register('reply', function(args, content) {  const targetUrl = args[0];  // ...}, {ends: true});</code></pre><p>我们先前的主题模板写法，会默认给文章最外部包上 <code>h-entry</code>、发送整个文章。既然有些文章我们只想在内部包含多个小的 <code>h-entry</code> 回复块，我们可以在内存中添加一个属性 <code>entry</code>。</p><p>如果该文章我们希望整个打包送走，那就在文章的 Front Matter 里添加：</p><pre><code class="language-plaintext">---entry: true---</code></pre><p>并在主题模板里添加条件判断：</p><pre><code class="language-plaintext">mixin post(item)    .post        //- 如果 entry 为 true，包裹整个 article        if item.entry === true            article.post-block.h-entry                .post-meta.p-author.h-card(style="display: none;")                    img.author-avatar.u-photo(src=url_for(theme.logo), alt=config.author)                    a.author-name.p-name.u-url(href=config.url)= config.author                                a.post-permalink.u-url(href=full_url_for(item.path), style="display: none;") 永久链接                                if item.excerpt                    .p-summary(style="display: none;")                        != item.excerpt                                h1.post-title.p-name                    != item.title                +postInfo(item)                                if item.in_reply_to                    .post-reply                        != __('reply_to') + ': '                        a.u-in-reply-to(href=item.in_reply_to)= item.in_reply_to                                .post-content.e-content                    != item.content        else            article.post-block                h1.post-title                    != item.title                +postInfo(item)                                if item.in_reply_to                    .post-reply                        != __('reply_to') + ': '                        a.u-in-reply-to(href=item.in_reply_to)= item.in_reply_to                                .post-content                    != item.content</code></pre><p>由于会使用到 <code>reply</code> 标签的文章都不希望发送整个文章，所以在脚本内我们要将 <code>entry</code> 设置为 <code>false</code>：</p><pre><code class="language-javascript">if (this.page) {  this.page.entry = false;}</code></pre><p>接着验证 URL：</p><pre><code class="language-javascript">// 1. 检查用户是否忘记提供 URLif (!targetUrl) {  hexo.log.warn('Reply tag: Missing target URL');  return '&lt;div class="reply-error"&gt;回复标签缺少目标URL&lt;/div&gt;';}// 2. 确保是绝对URLlet absoluteUrl;try {  new URL(targetUrl);  absoluteUrl = targetUrl;} catch (e) {  try {    // 3. 如果失败，尝试作为相对路径处理    absoluteUrl = hexo.extend.helper.get('full_url_for').call({config: hexo.config}, targetUrl);  } catch (e2) {    // 4. 如果再次失败，则判定为无效 URL 并报错    hexo.log.warn(`Reply tag: Invalid URL - ${targetUrl}`);    return '&lt;div class="reply-error"&gt;回复标签包含无效URL&lt;/div&gt;';  }}</code></pre><p>渲染 Markdown 内容：</p><pre><code class="language-javascript">let renderedContent;try {  renderedContent = hexo.render.renderSync({     text: content.trim(),     engine: 'markdown'   });} catch (e) {  hexo.log.warn('Reply tag: Failed to render markdown content');  renderedContent = content; // 降级到纯文本}</code></pre><p>国际化支持：</p><pre><code class="language-javascript">// 获取当前语言的“回复”翻译const currentLang = this.page ? this.page.lang : hexo.config.language;let replyText = '回复';// 尝试从主题语言文件获取翻译try {  const langHelper = hexo.extend.helper.get('__');  if (langHelper) {    replyText = langHelper.call({page: {lang: currentLang}}, 'reply_to') || replyText;  }} catch (e) {  // 使用默认文本}</code></pre><p>获取并处理作者信息：</p><pre><code class="language-javascript">// 获取作者信息和网站配置const config = hexo.config;const theme = hexo.theme.config;const authorName = config.author || 'Anonymous';const siteUrl = config.url || '';// 简单构造绝对 URL，确保 logo 路径正确let authorAvatar = '';if (theme.logo) {  // 如果 logo 已经是绝对 URL，直接使用  if (theme.logo.startsWith('http')) {    authorAvatar = theme.logo;  } else {    // 确保路径以/开头，构造网站根路径    const logoPath = theme.logo.startsWith('/') ? theme.logo : '/' + theme.logo;    authorAvatar = (config.url || '').replace(/\/$/, '') + logoPath;  }}</code></pre><p>最后生成 HTML 结构：</p><pre><code class="language-javascript">return `  &lt;div class="reply-block h-entry"&gt;    &lt;!-- 作者信息（h-card） --&gt;    &lt;div class="post-meta p-author h-card" style="display: none"&gt;      ${authorAvatar ? `&lt;img class="author-avatar u-photo" src="${authorAvatar}" alt="${authorName}"&gt;` : ''}      &lt;a class="author-name p-name u-url" href="${siteUrl}"&gt;${authorName}&lt;/a&gt;    &lt;/div&gt;        &lt;!-- 回复内容 --&gt;    &lt;div class="reply-content e-content"&gt;      ${renderedContent}    &lt;/div&gt;        &lt;!-- 回复元信息 - 通过 CSS 在列表页隐藏 --&gt;    &lt;div class="reply-meta"&gt;      &lt;span class="reply-label"&gt;${replyText}:&lt;/span&gt;      &lt;a class="reply-target u-in-reply-to" href="${absoluteUrl}"&gt;${absoluteUrl}&lt;/a&gt;    &lt;/div&gt;  &lt;/div&gt;`;</code></pre><div class="danger"><p>这里我声明了一些类，需要自定义样式：</p><ul><li><code>reply-block</code></li><li><code>post-meta</code></li><li><code>author-avatar</code></li><li><code>author-name</code></li><li><code>reply-content</code></li><li><code>reply-meta</code></li><li><code>reply-label</code></li><li><code>reply-target</code></li></ul><p>不用这些样式也可以。我个人更希望回复块和普通文本们可以区分开来。</p><p>和先前做的一样，我也为 <code>h-card</code> 标签添加了 <code>display: none</code> 样式。这个样式可以根据你们的需求、选择保留或者删除。</p></div><h4 id="显示"><a class="markdownIt-Anchor" href="#显示"></a> 显示</h4><p>要想在博客内显示其他人向我们发送的 Webmention，就需要用到 Webmention.io 提供的 <a href="https://webmention.io/settings">Mentions Feed API</a>。Webmention.io 会提供给我们一个 API 密钥，只需要将其添加在以下任意一个 URL 中即可：</p><ul><li><code>https://webmention.io/api/mentions.html?token=API密钥</code></li><li><code>https://webmention.io/api/mentions.atom?token=API密钥</code></li><li><code>https://webmention.io/api/mentions.jf2?token=API密钥</code></li></ul><p>这些链接会根据自己的格式，显示网站所有的 Webmention。但要是用在我们的博客网站上的话，就遭殃了：读者只想阅读你的一篇文章，但你的网站已经获取了全部一千篇文章的 Webmention。<em><strong>请不要这么做。</strong></em></p><p>正确做法是使用 <code>url</code> 参数，指定获取哪个文章的 Webmention。我建议使用 <code>jf2</code> 来获取数据，它是纯粹的、为机器而生的数据格式：</p><ul><li><code>https://webmention.io/api/mentions.jf2?url=文章URL</code></li></ul><p>如果你认为数据获取可以在客户端上进行、希望 Webmention 可以实时显示，你完全可以在主题的 <code>/source/js/</code> 目录下添加一个 JavaScript 文件执行网络请求和数据处理。不过纯动态有些劣势：</p><ol><li>对 SEO 不友好。其他人发送的 Webmention 不会被搜索引擎索引</li><li>可能在内容出现时导致页面布局发生跳动</li><li>浏览器需要发起一次额外的网络请求</li><li>如果 Webmention.io 的 API 出现故障或者相应缓慢，就什么都加载不出来了</li></ol><p>如果你认为这四点很重要，你可以考虑采用纯静态构建。这需要你在项目根目录的 <code>/scripts/</code> 目录下创建 Hexo 脚本：</p><pre><code class="language-javascript">hexo.extend.generator.register('webmentions', async function() {  const hexo = this;  const webmentionConfig = hexo.config.webmention;  let allMentions = [];  if (webmentionConfig &amp;&amp; webmentionConfig.enable) {    try {      // 拼接 Webmention.io API URL 并且发起请求      const newWebmentions = await fetchWebmentions(hexo.config);      // 更新本地的缓存文件      // 缓存功能非必需，可以无视掉！      allMentions = updateWebmentionsCache(hexo, newWebmentions);    } catch (error) {      hexo.log.error(error.message);      hexo.log.warn('[Webmention] Falling back to local cache due to fetch error.');      allMentions = loadWebmentionsCache(hexo);    }  } else {    allMentions = loadWebmentionsCache(hexo);  }  // 将获取到的数据注入到 Hexo 的本地变量  hexo.locals.set('all_webmentions', allMentions);  if (webmentionConfig &amp;&amp; webmentionConfig.debug) {      hexo.log.info(`[Webmention] Injected ${allMentions.length} total mentions into hexo.locals.`);  }  return;});</code></pre><p>我假设了项目配置项里有这些内容：</p><pre><code class="language-yaml">webmention:  enable: true  domain: 域名  api_endpoint: https://webmention.io/api/mentions.jf2  token: 令牌</code></pre><p>要想要在主题模板里渲染这些变量，有两种方法：</p><ol><li><p>直接在主题模板里用 <code>site</code> 变量渲染</p><p>关于 Hexo 的局部变量，建议看以下文档：</p><ul><li><a href="https://www.bookstack.cn/read/hexo/b61d0b214ee2fdc6.md">自定义 - 变量 - 《Hexo 博客框架文档》 - 书栈网・BookStack</a>：列出了模板中所有可用的变量</li><li><a href="https://hexo.io/zh-cn/api/locals#logo-wrap">局部变量 | Hexo</a>：官方文档。主要是说明如何在 JavaScript 里操作 <code>hexo.locals</code></li></ul><p>总之，脚本里 <code>hexo.locals.get("posts")</code> 等同于模板里用 <code>site.posts</code>。</p></li><li><p>写一个辅助函数，在模板中调用、渲染返回的 HTML：</p> <pre><code class="language-javascript">hexo.extend.helper.register('render_webmentions', function(pageUrl) {  const webmentionConfig = this.config.webmention;  const mode = webmentionConfig &amp;&amp; webmentionConfig.mode ? webmentionConfig.mode : 'static';  // 从 hexo.locals 获取 webmention 数据  const allMentions = hexo.locals.get('all_webmentions') || [];  // 文字截断函数  const truncateContent = (content, maxLength = 200) =&gt; {    if (!content) return '';    // 如果是HTML内容，先提取纯文本    const textContent = content.replace(/&lt;[^&gt;]*&gt;/g, '');    if (textContent.length &lt;= maxLength) {      return content;    }    // 截断文本并添加省略号    const truncatedText = textContent.substring(0, maxLength).trim();    // 如果原内容是HTML，包装成段落；否则直接返回    return content.includes('&lt;') ? `&lt;p&gt;${truncatedText}…&lt;/p&gt;` : `${truncatedText}…`;  };  if (!pageUrl) {    // 尝试多种方式获取当前页面 URL    pageUrl = this.page.path || this.page.url || this.url;  }  // 确保 pageUrl 有值  if (!pageUrl) {    return '&lt;div class="webmention-section webmention-empty"&gt;&lt;span&gt;无法获取页面URL&lt;/span&gt;&lt;/div&gt;';  }  const fullUrl = new URL(pageUrl, this.config.url).href;  const mentionsForThisPage = allMentions.filter(mention =&gt; {    // 简化 URL 匹配逻辑，使用字符串比较而非 URL 构造    const targetUrl = mention.target;    // 同时尝试完整 URL 和相对路径匹配    return targetUrl === fullUrl ||            targetUrl.endsWith(pageUrl) ||            fullUrl.endsWith(mention.target.split('/').pop()) ||           mention.target.includes(pageUrl.replace(/^\//, ''));  });  let html = `&lt;div class="webmention-section" data-page-url="${pageUrl}" data-full-url="${fullUrl}" data-mode="${mode}"&gt;                &lt;h3 class="webmention-title"&gt;Webmentions (&lt;span class="webmention-count"&gt;${mentionsForThisPage.length}&lt;/span&gt;)&lt;/h3&gt;                &lt;div class="webmention-list"&gt;`;  mentionsForThisPage.forEach(mention =&gt; {    const authorHtml = mention.author.url       ? `&lt;a class="webmention-author-name" href="${mention.author.url}" target="_blank" rel="noopener ugc"&gt;${mention.author.name}&lt;/a&gt;`      : `&lt;span class="webmention-author-name"&gt;${mention.author.name}&lt;/span&gt;`;    const photoHtml = mention.author.photo      ? `&lt;img class="webmention-author-photo" src="${mention.author.photo}" alt="${mention.author.name}" loading="lazy"&gt;`      : '';    html += `      &lt;div class="webmention-item" id="webmention-${mention.id}" data-webmention-id="${mention.id}"&gt;        &lt;div class="webmention-author"&gt;          ${photoHtml}          ${authorHtml}          &lt;span class="webmention-date"&gt;${new Date(mention.published || mention.received).toLocaleDateString('zh-CN')}&lt;/span&gt;        &lt;/div&gt;        &lt;div class="webmention-content"&gt;          ${truncateContent(mention.content.html || mention.content.text)}        &lt;/div&gt;        &lt;div class="webmention-meta"&gt;          &lt;a class="webmention-source" href="${mention.source}" target="_blank" rel="noopener ugc"&gt;查看原文&lt;/a&gt;        &lt;/div&gt;      &lt;/div&gt;    `;  });  html += '&lt;/div&gt;&lt;/div&gt;';  return html;});</code></pre><p>实际返回的 HTML 可以自行修改。如果想要直接使用该脚本文件，不要忘了为里面提到的类写样式。</p><p>接下来你要做的就是在模板里找到个顺眼的地方调用该方法：</p> <pre><code class="language-plaintext">if config.webmention &amp;&amp; config.webmention.enable    != render_webmentions()</code></pre></li></ol><h2 id="插件"><a class="markdownIt-Anchor" href="#插件"></a> 插件</h2><p>先前说过了，我有「强迫症」。我将上述的所有功能整合成了多个 Hexo 插件，你只需要安装和配置。详情以仓库里的 README 文件为标准。</p><ul><li><p>Hexo-Tag-Quotemention 涵盖了 <a href="#%E4%BB%85%E5%8F%91%E9%80%81%E4%B8%80%E9%83%A8%E5%88%86%E5%86%85%E5%AE%B9">发送部分文字</a> 功能</p><p><a href="https://github.com/Cytrogen/hexo-tag-quotemention"><img src="https://gh-card.dev/repos/Cytrogen/hexo-tag-quotemention.svg" alt="Cytrogen/hexo-tag-quotemention - GitHub" loading="lazy"></a></p></li><li><p>Hexo-Generator-Webmention 涵盖了 <a href="#%E6%98%BE%E7%A4%BA">显示</a> 功能</p><p><a href="https://github.com/Cytrogen/hexo-generator-webmention"><img src="https://gh-card.dev/repos/Cytrogen/hexo-generator-webmention.svg" alt="Cytrogen/hexo-generator-webmention - GitHub" loading="lazy"></a></p></li></ul><h2 id="测试"><a class="markdownIt-Anchor" href="#测试"></a> 测试</h2><div class="reply-block h-entry"><div class="post-meta p-author h-card visually-hidden"><img class="u-photo" src="https://blog.cytrogen.icu/favicon.png" alt="Cytrogen" loading="lazy"><span class="p-name">Cytrogen</span><a class="u-url" href="https://blog.cytrogen.icu">https://blog.cytrogen.icu</a></div><time class="dt-published visually-hidden" datetime="2026-09-17T20:47:54.419Z">2026-09-17T20:47:54.419Z</time><a class="u-url visually-hidden" href="https://blog.cytrogen.icu">Post Link</a><div class="reply-content e-content"><p>如果你想要测试，又不想要打扰到其他人，你可以向 <a href="https://hexo-theme-ares-demo.netlify.app/2025/10/14/webmention-test-zh/">这个地址</a> 发送 Webmention。这是我为 Hexo-Theme-Ares 搭建的 Demo 页面。</p></div><div class="reply-meta p-in-reply-to h-cite"><span class="reply-label">回复：</span><a class="reply-target u-url" href="https://hexo-theme-ares-demo.netlify.app/2025/10/14/webmention-test-zh/">https://hexo-theme-ares-demo.netlify.app/2025/10/14/webmention-test-zh/</a></div></div></body></html>]]></content>
    
    
    <summary type="html">Hexo 缺少开箱即用的 Webmention 支持？本篇终极指南将带你从零开始，通过编写自定义 Generator、Helper 和标签插件，深度集成 Microformats，为你的博客实现完整的 Webmention 接收、发送（包括独特的“引用式”提及）与静态渲染功能。文章最后还提供了两个即插即用的 npm 插件，让你轻松为博客赋能。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Hexo" scheme="https://blog.cytrogen.icu/tags/Hexo/"/>
    
    <category term="Pug" scheme="https://blog.cytrogen.icu/tags/Pug/"/>
    
    <category term="JavaScript" scheme="https://blog.cytrogen.icu/tags/JavaScript/"/>
    
  </entry>
  
  <entry>
    <title>想法在乙巳菊月迭代</title>
    <link href="https://blog.cytrogen.icu/posts/dc84.html"/>
    <id>https://blog.cytrogen.icu/posts/dc84.html</id>
    <published>2025-10-07T15:04:40.000Z</published>
    <updated>2026-02-09T17:16:55.401Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>八月份开始我找了个兼职、过上了「起床 &gt; 做饭 &gt; 吃饭 &gt; 工作 &gt; 洗澡 &gt; 吃饭 &gt; 睡觉」的健康生活。要知道过去的我经常熬夜、一觉睡到中午、饭不按时吃，总之习惯差得很。突然开始自律，就变得想要去完全利用起自己的时间。</p><p>纽约市是一个坐地铁比开车要好的地方，但地铁没有网络。一般出门的话，通勤半小时到俩小时是跑不掉的，意味着这个时间里去网上冲浪或者同朋友聊天几乎不可能，我只能去阅读已经被下载到手机里的电子书籍或者博客文章。多亏了这一点，我开始关注一些独立博客主，并发现了很多我认为有意思的博客。陆陆续续看了一两个月后，令我也想花些时间在记录我自己看到的、学到的、感受到的东西上。</p><span id="more"></span><h2 id="书籍"><a class="markdownIt-Anchor" href="#书籍"></a> 书籍</h2><h4 id="不原谅也没关系"><a class="markdownIt-Anchor" href="#不原谅也没关系"></a> 《不原谅也没关系》</h4><p>我是一次网上冲浪的时候发现了这本书。当时我刷到一个帖子，内容大致是在说：</p><blockquote><p>自言自语、在脑海中幻想某件事情会发生并且演习如何去应对等行为是因为「父母的凝视」。</p></blockquote><p>我确实有这样的毛病。很多时候我的大脑都在想「过去发生了但是没做好的事情」以及「未来可能会发生的事情」，自言自语也是脑内演习时我想出来的回复被不小心说了出来。我常常处于自省的状态。说是自我反省，实则是一遍遍 <strong>羞辱</strong> 自己。</p><p>这本书的主题是 CPTSD（Complex Post-Traumatic Stress Disorder，复杂性创伤后应激障碍）。但是和科普疾病的书不同，它更像是一本「自救手册」、附带了对于 CPTSD 的解释。托这本书的福，我更了解自己以及身边的人了。</p><p>什么是 CPTSD？它是一种 <strong>因长期或反复暴露于创伤事件而引发的心理疾病</strong>。与 PTSD（Post-Traumatic Stress Disorder，创伤后应激障碍）相比，CPTSD 不仅包含了 PTSD 的核心症状（如恐惧感、闪回、过度警觉），还包括了情绪调节障碍、负面的自我信念以及人际交往困难。CPTSD 通常发生在个体感知无法逃避或者躲避创伤事件的情况下。</p><p>根据作者所说，CPTSD 的核心症状主要是这五种：</p><ol><li>情绪闪回：CPTSD 最典型的症状，是一种 <strong>突然发生且通常持续时间较长的退行</strong>，幸存者会退回到童年遭受虐待或遗弃时的强烈情绪状态，如恐惧、羞耻、愤怒、悲伤等，并激活「战或逃」反应</li><li>毒性羞耻感：一种强烈的自我贬低感，会摧毁自尊，令幸存者觉得自己毫无价值、必被鄙视，常导致自我疏离和孤立，不愿寻求他人支持</li><li>自我遗弃：对自己的忽视或抛弃感，表现出对自我关爱和保护的缺失</li><li>恶性内在批判：内化的苛刻批评声，源自童年的父母批判，持续挑剔和否定自我，导致自信心极度受损</li><li>社交焦虑：对人际关系的焦虑和恐惧，常伴随孤独和被遗弃感</li></ol><p>此外，CPTSD 患者常表现出过度的创伤应对模式「4F 反应」：</p><ul><li>战斗（Fight）</li><li>逃跑（Flight）</li><li>僵住（Freeze）</li><li>讨好（Fawn）</li></ul><p>这些反应是对童年创伤的长期适应性防御机制。</p><p>作者在书中给出了一个例子，令我印象深刻。一个家庭养育了四个孩子，这四个孩子却分别代表了 4F 反应的其中一个：大儿子从小跟着父母欺负兄弟姐妹，为人狂傲自大，永远都觉得自己是正确的，代表「战斗」；二女儿从小被欺负，只能靠一天天的忙碌来避免面对内心的痛苦，代表「逃跑」；三女儿也是从小被欺负，但是接触到了电子产品后，很快便麻木地沉迷在其中，连自理的能力都丧失了，代表「僵住」；小儿子自小就懂得察言观色，长大后被母亲「绑架」到身旁照顾自己，代表「讨好」。</p><p>实际上 4F 反应单纯指的是生物在面对危险时的四种本能生存反应：「战斗」是主动攻击来保护自己或对抗威胁；「逃跑」是通过逃离危险环境来躲避威胁；「僵住」是身体和情绪上的僵硬或麻木、暂时「冻结」以避免威胁；「讨好」是试图通过迎合、讨好他人来避免冲突和伤害。这些反应都是生物的本能反应，是我们的自然防御机制。</p><p>问题在于，在一个有毒的环境下我们有可能 <strong>长期重复</strong> 做出这些反应、形成深层的心理防御模式。</p><p>我的家庭曾是个有毒的环境：日常的物理与言语暴力、羞辱，以及强加给孩子的过度责任。那个时候，我的好朋友不多，因为我不被允许出去玩，朋友们也不愿意同我深交，因为他们都认为我的家人是神经病。</p><p>在经历了一段斗争后，我脱离了这个环境。这段时间，我的创伤更多与家庭有关。我很厌恶他人在我面前诉说他们的家庭有多么和睦；可笑的是在我一次同朋友分享我的过去经历后，TA 的第一反应是「<em>这样说来我的家人对我就很好呢</em>」。每次提到我的家人是否爱我，我会立即陷入「情绪闪回」，被一种强烈的悲伤所淹没。这些经历塑造了我内在的「毒性羞耻感」。</p><p>可悲的是，我很快便进入了另一段有毒的关系。我的「内在批判者」变成了校友，一群永远是在批判他人的家伙们。明明是我被冒犯了，但我会感到愤怒的同时，也会去想如何讨好他们。很是可笑。我的内心早已充满了来自家庭的、模糊的自我怀疑。就算是被伤害了，我也无力反击。</p><p>好在这些事情都已经是过去式了。如果我想去详细说说这些事情的话，我会单独写一篇博客文章。</p><h4 id="重新定义公司谷歌是如何运营的"><a class="markdownIt-Anchor" href="#重新定义公司谷歌是如何运营的"></a> 《重新定义公司：谷歌是如何运营的》</h4><p>这本书我没有读完，只读了前两个章节。</p><p>作者认为，科技进步对商业的影响非常大，基本上没有什么行业在信息时代还以过去的样子运行。过去，企业可以靠着销售手段，把一个质量差的产品变成全民都在消费使用的摇钱树，但现在完全行不通了。现在要想成功，必须要有出类拔萃的产品，因为消费者可以用各种方式获取到信息、了解该产品的质量如何。同时，实验和失败的成本显著下降了。现在的人们可以组建一个小团队，创造出产品、通过网络免费在全球发行、选定顾客群试用、判断产品的优点和缺点……</p><p>作者还抨击了传统知识工作者：秉着「专攻术业」的精神在刻板的企业环境中出人头地，主要靠的还是墨守成规。这些人要么是技术达人 + 管理白痴，要么就是管理专家 + 技术菜鸟，和谷歌的工程师人才很不同。这里作者提出了一个概念 —— 创意精英。</p><p>创意精英的特点包括但不限于：</p><ul><li>不拘泥于特定的任务</li><li>不受公司信息和计算能力的约束</li><li>不惧怕甚至喜爱冒险。即便在冒险中失败，也不会受到惩罚或牵制</li><li>不被职位头衔或企业的组织结构绊住手脚</li><li>很容易失去耐心，经常变换职位</li><li>具有多领域的能力，经常会将前沿技术、商业头脑以及奇思妙想结合在一起</li><li>拥有过硬的专业知识、懂得如何使用专业工具，还需具备充足的实践经验</li><li>有分析头脑，对数据运用自如，又不会沉迷其中</li><li>有商业头脑</li><li>有竞争头脑</li><li>拥有用户头脑</li><li>用不同于你我的崭新视角看问题</li><li>充满好奇心</li><li>自动自发，注重于自己的理念</li><li>心态开放，可以自由地与他人合作</li><li>一丝不苟</li><li>善于沟通，风趣幽默</li></ul><p>所有创意精英都必须具备商业头脑、专业知识、创造力以及实践经验。衍生出降低风险、规避失误的企业运营流程的管理模式会形成一种压制创意精英的大环境。</p><p>我能感觉出，我不是一位创意精英，我会的东西根本也没那么多。仔细想来，我唯一一件能被说是「做得好」的，只有计算机相关的事情了。我认为人终究不能去只专注于做一件事，未来我也想要有其他可以被说是「做得好」的事情。</p><p>这本书传递的信息很多且各不相同，我只挑一些我认为有趣的说：</p><ol><li><p>现实生活中，河马是一种十分危险、速度快、咬合力强、体重足以碾碎其他动物的动物。而职场里的河马，叫做「高薪人士的意见」。一个人拿多少工资，并不能直接等于他们做决策的能力有多强。同样，经验本身也不是决策的关键。但是许多人，甚至说许多企业都没有意识到这一点，依然认为谁的薪金高或者个人经验多，谁才是对的。</p></li><li><p>谷歌采取的是扁平化企业结构，也就是压缩中间的管理层级，可以让一个普通员工直接向总监或者副总裁汇报（对标的是金字塔结构）。多数人认为，扁平化是为了和上层平起平坐、追求一种地位上的平等感；而对于创意精英而言，扁平化是为了多干正事。过多的管理层级会成为他们创新的阻碍，他们需要能够快速地与决策者沟通，获得反馈和资源，从而高效地推进工作。</p><p>谷歌实现扁平化的方法很有意思：一个管理者至少要有 7 个直接下属。这会强制扩大管理幅度，让管理者们无法对每个人的工作细节都进行微观管理，自然也没法事事都插手下属们的工作。</p></li><li><p>传统和僵化的管理思维会认为工作和生活是两个对立面，需要像天平一样「平衡」，一个多了另一个就必然会少。然而作者认为这个标准本身就很有问题：对于热爱工作的人来说，工作是生活的重要组成部分，而不是生活的对立面。强行分割很不自然。最好的企业文化是让工作环境和家庭环境都充满乐趣，员工可以自由地在两种状态中切换。</p><p>通常让员工感到痛苦的不是工作本身，而是「失控感」和「被迫牺牲感」。作者对此的建议并不是「让员工少工作」，而是「不要用时间去管束员工」。管理者不需要催员工加班，也别劝他们早点回家。这种行为的潜台词是「我不相信你能自己管好自己」。你只需要让员工知道他们需要对自己的工作负全责，并把如何完成工作的控制权交还给员工，他们自己会找到最适合自己的节奏，从而最大化产出、最小化「被迫牺牲」带来的倦怠感。</p></li><li><p>一个不可或缺的员工通常被视为英雄和骨干。然而这个「不可或缺」是一个巨大的风险，因为如果一个人的离开就能让公司瘫痪，那说明公司的组织结构非常脆弱。同时这种「不可或缺」也会导致一种不健康的共生关系。作者提到「强制休假」很重要：对员工而言，这可以让他们意识到「地球离了谁都照样转」、减轻心理负担；对公司而言，给了其他人接手的机会，可以锻炼团队的「备份」能力</p></li><li><p>随着企业变大，为了控制混乱，管理者会本能地增加流程和审批环节。这些流程的潜台词就是一种「不」——「你不能随便做，必须先经过 ABCDE 的同意」。而在一个说「好」的文化里，这恰恰相反，它要求想说「不」的人必须给出「百般信服的业务考量」。这颠覆了权力关系，把证明的责任交给了阻碍者，而非创新者。这也是一种「提出质疑的人要给出证据，而非让被质疑的人自证」。</p><p>有创意、有能力的员工最讨厌的就是无意义的内耗和形式主义。一个默认说「好」的环境，传递给员工的信息是：「我们信任你的判断，我们鼓励你尝试」。这可以让员工愿意提出更多想法。反之，一个默认说「不」的环境，会让员工觉得「多一事不如少一事」，最终人才流失。</p></li></ol><p>我不是很懂管理，评价什么的待我进了一家真正的企业之后再说吧。</p><h4 id="黑客攻防技术宝典web-实战篇"><a class="markdownIt-Anchor" href="#黑客攻防技术宝典web-实战篇"></a> 《黑客攻防技术宝典：Web 实战篇》</h4><p>这本书我同样没有读完。它属于是那种「不一边读一边记笔记就不行」的书，因此我打算读完后直接将笔记发布到博客上。</p><p>它的核心要点很简单：服务端 <strong>永远</strong> 都不应该信任客户端发来的任何请求。</p><hr><h2 id="音乐"><a class="markdownIt-Anchor" href="#音乐"></a> 音乐</h2><p>我个人很喜欢听台湾摇滚，从万能青年旅店听到草东没有派对、康斯坦的变化球，最近则是在听老王乐队在 2019 年发布的专辑《吾日三省吾身》。听完后印象让我最深刻的是《垂钓》。可惜我不懂音乐和乐理，没法展开说说，只能说我喜欢他们的哪些歌词：</p><blockquote><p>迎面而来的机会我抓不住，迎面而来的车子我躲不开。</p></blockquote><blockquote><p>比你聪明的人啊都在努力往前，我无力地闭上眼。</p></blockquote><hr><h2 id="影视"><a class="markdownIt-Anchor" href="#影视"></a> 影视</h2><p>我跟朋友补完了《未来日记》。男主前期的塑造有点劝退，实在是太小孩子气了。后面有两集的制作很明显出现了很大的变化，不论是画风、动作的流畅度和分镜设计。</p><hr><h2 id="前端技术"><a class="markdownIt-Anchor" href="#前端技术"></a> 前端技术</h2><p>我在阅读前端技术相关的博客文章时都会记笔记。现在打算分享出来了，才发现我居然忘了标记来源是什么。我只能把这些文章从浏览记录里一一找出，真是醉了。</p><h4 id="css"><a class="markdownIt-Anchor" href="#css"></a> CSS</h4><ul><li><p><a href="https://frontendmasters.com/blog/the-coyier-css-starter/">The Coyier CSS Starter – Frontend Masters Blog</a></p><p>介绍了 Chris Coyier 的 CSS 样式起点方案，旨在提升开发效率与界面一致性。</p></li><li><p><a href="https://www.oddbird.net/2025/09/23/type-units/">The Best CSS Unit Might Be a Combination | OddBird</a></p><p>不必在 <code>px</code> 与 <code>em</code> / <code>rem</code> 之间做单一选择。借助现代 CSS 的比较与数学函数（如 <code>max()</code>, <code>clamp()</code>, <code>calc()</code>），可以组合单位以表达更精确的设计意图。单位的「语义」比其数值更重要 —— 应使用最能表达设计目的的单位。</p></li><li><p><a href="https://frontendmasters.com/blog/css-offset-and-animation-composition-for-rotating-menus/">CSS offset and animation-composition for Rotating Menus – Frontend Masters Blog</a></p><p>介绍了如何使用 CSS 的 <code>offset</code> 属性和 <code>animation-composition</code> 机制，为圆形菜单项创建沿路径旋转的动画效果，实现更流畅且可控的交互式布局。</p></li><li><p><a href="https://emilkowal.ski/ui/you-dont-need-animations">You Don't Need Animations</a></p><p>强调动画应有明确目的，并根据使用频率与速度优化设计，否则可能降低用户体验甚至损害产品信任。</p></li><li><p><a href="https://webkit.org/blog/17240/a-gentle-introduction-to-anchor-positioning/">A gentle introduction to anchor positioning | WebKit</a></p><p>介绍了 CSS 的新特性「锚点定位」，展示如何使用纯 CSS 将元素相对于另一个元素进行精确、响应式定位，从而简化菜单和弹出层的布局。</p></li></ul><h4 id="javascript"><a class="markdownIt-Anchor" href="#javascript"></a> JavaScript</h4><ul><li><p><a href="https://blog.sangeeth.dev/posts/accurate-text-lengths-with-intl-segmenter-api/">Accurate text lengths with <code>Intl.Segmenter</code> API | Automagic</a></p><p><code>String.length</code> 并不总是对的。正确做法是使用 <code>Intl.Segmenter</code>。这是浏览器原生的 API，可以按照语言规则将字符串分割为「graphemes」，也就是扩展字数簇、人类可识别的字符。</p></li><li><p><a href="https://lyra.horse/blog/2025/08/you-dont-need-js/">You no longer need JavaScript Ʊ lyra's epic blog</a></p><p>现代 JavaScript 框架（例如 React、Next.js）常常导致加载缓慢、错误频发、资源臃肿。HTML 和 CSS 已经具备了强大功能，能完成许多交互和视觉效果。对于安全研究者或者隐私用户，禁用 JavaScript 是常态，纯 HTML / CSS 页面更友好。并且 CSS 性能更优：动画运行在 compositor 线程，不受 JavaScript 阻塞影响。</p></li></ul><h4 id="html"><a class="markdownIt-Anchor" href="#html"></a> HTML</h4><ul><li><p><a href="https://reasonunderpressure.com/blog/posts/your-images-are-probably-oversized">Your Images Are (Probably) Oversized</a></p><p>开发者常用高分辨率图片（如 3600×2400）以确保视觉质量，但多数用户设备无法充分利用这些像素。未设置 <code>sizes</code> 属性时，即使使用 Next.js 的 <code>&lt;Image&gt;</code> 组件，仍可能加载原始尺寸图片，浪费带宽与计算资源。</p></li><li><p><a href="https://www.jonoalderson.com/performance/youre-loading-fonts-wrong/">You're loading fonts wrong (and it's crippling your performance) - Jono Alderson</a></p><p>系统性揭示了当前网页字体加载的常见误区，强调字体是性能与可访问性基础设施，并提供优化策略以提升加载速度、稳定性与全球语言支持。</p></li></ul><hr><h2 id="后端技术"><a class="markdownIt-Anchor" href="#后端技术"></a> 后端技术</h2><h4 id="nestjs"><a class="markdownIt-Anchor" href="#nestjs"></a> NestJS</h4><p>在写项目的时候我学习到了这些知识：</p><ol><li><p>防御性编程：</p><p>使用 <code>??</code> 操作符处理 <code>undefined</code> 情况。例如：<code>return setting?.settingValue ?? false;</code></p></li><li><p>查询优化：</p><ul><li><p>如果只查一个数据，用 <code>findOne()</code> 而不是 <code>find()[0]</code></p></li><li><p>一次查询获取所有相关设置，而不是循环查询</p></li><li><p>使用 <code>$regex</code> 精确匹配设置键值</p></li><li><p>使用 <code>{ upsert: true }</code> 确保设置项存在</p></li><li><p>批量操作时，使用 <code>bulkWrite()</code>，速度比循环单个操作快 10 倍以上：</p><pre><code class="language-javascript">for (const task of tasks) {  operations.push({    updateOne: {      filter: {},      update: {},      upsert: true,    }  });}await this.adminSettingModel.bulkWrite(operations);</code></pre></li></ul></li><li><p>拦截器：</p><ul><li><p>在 NestJS 中，拦截器会站在业务逻辑（Controller / Service）之前，可以检查、修改甚至完全阻止一个请求继续往下走。而 NestJS 底层大量使用了 RxJS 库，后者的世界里，所有异步的数据流都被表示为可观察对象，像一个管道；数据会从管道的一端流向另一端。拦截器的 <code>intercept</code> 方法，返回值必须是一个 <code>Observable</code>。这意味着想要阻止请求，只写一个 <code>return null</code> 是不够的，需要使用 RxJS 的 <code>of()</code>、创建一个新的、立即发出一个值然后结束的 <code>Observable</code>。该方法可以用于判断是否开启了某项设置，如果没开启就 <code>return of(null)</code>、直接阻止该请求。</p></li><li><p>缓存实现策略，除了使用 Redis 缓存装饰器，还可以使用内存缓存 Map：</p><pre><code class="language-javascript">private settingsCache = new Map&lt;string, { value: boolean; expiry: number }&gt;();private readonly CACHE_TTL = 60 * 1000; // 60秒async getTaskSetting(taskName) {  const cacheKey = `email_scheduler.${taskName}.enabled`;  const cached = this.settingsCache.get(cacheKey);    // 缓存命中且未过期  if (cached &amp;&amp; Date.now() &lt; cached.expiry) {    return cached.value;  }      // 查询数据库  const setting = await this.adminSettingModel.findOne({ settingKey: cacheKey });  const value = setting?.settingValue ?? false;      // 更新缓存  this.settingsCache.set(cacheKey, {    value,    expiry: Date.now() + this.CACHE_TTL  });  return value;}</code></pre></li></ul></li><li><p>架构：</p><ul><li>使用事件驱动</li><li>写 E2E，也就是端到端测试</li></ul></li></ol><h4 id="分布式锁"><a class="markdownIt-Anchor" href="#分布式锁"></a> 分布式锁</h4><p>分布式锁类似于公厕的门锁。它的目标是确保同一时间只有一个人（服务器实例）能使用厕所（执行任务）；关键是锁必须对所有人（所有服务器）都可见且有效；现实是 Redis 充当「锁的管理员」，所有服务器都通过它来检查锁状态。而在技术定义内，分布式锁是一种跨多个节点的互斥机制，确保分布式系统中的临界区同时只能被一个节点访问。</p><p>在我的项目中，有个功能会用到 <code>@Cron()</code> 装饰器。其中有这么一个例子：每日午夜零点，服务器 A 启动了每日报告任务、查询了数据库，发现有 100 个需要发送的邮件。服务器 B 同样也启动了每日报告任务、查询了数据库，发现了相同的 100 个邮件。</p><p>结果显然易见：200 封重复邮件发送给了客户。</p><p>为什么数据库防重复的功能不够？首先，服务器具有着竞态窗口，它们会同时查询、同时发现「未发送」状态、同时发送、同时更新状态。其次，邮件发送耗时有 5-10 秒，在此期间数据库状态是不会被更新的。这也就体现了分布式锁的价值：它能够确保任务一次只在一台服务器上执行、能够消除时间窗口内的并发冲突。</p><p>让分布式锁变得「健壮」的关键因素有三：</p><ol><li><p>原子性（Atomicity）：</p><p>我们需要确保「检查锁状态」和「获取锁」这两个操作必须是原子操作。解决方法是使用 Redis 的 <code>SET key value NX EX ttl</code> 命令：<code>NX</code> 仅在 <code>key</code> 不存在时设置；<code>EX</code> 设置过去时间，单位为秒。</p><p>错误案例：</p><pre><code class="language-javascript">const exists = await redis.exists(lockKey);if (!exists) {  await redis.set(lockKey, lockValue);  await redis.expire(lockKey, ttlSeconds);}</code></pre></li><li><p>超时保护（Timeout Protection）：</p><p>如果持有锁的服务器崩溃了，那锁不就是永远都不会被释放了？解决这个问题的方法也很简单：设置合理的 TTL（Time To Live 的缩写）。如果太短，任务未完成、锁就过期了，其他服务器便会开始执行、导致冲突；如果太长，服务器崩溃、锁长时间无法释放，任务也就停滞了。推荐设置为任务预期执行时间的 2-3 倍，例如邮件发送预期耗时 5-10 秒，那 TTL 就设置为 10-30 秒。</p></li><li><p>安全释放（Secure Release）：</p><p>只有锁的持有者才能释放锁，要做到这一点，我们需要使用 UUID 作为锁值、释放锁的时候验证身份。值得注意的是，验证身份时建议使用 Lua 脚本来保证原子性：</p><pre><code class="language-lua">if redis.call("get", KEYS[1]) == ARGV[1] then  return redis.call("del", KEYS[1])else  return 0end</code></pre></li></ol><p>更多实用工具：</p><ol><li><p>智能锁键：</p><p>根据任务执行频繁，使用不同的日期精度。例如每 15 分钟就要进行的定时任务，日期精度自然是要准确到分钟；每天都要发送的报告，日期精度只需要到哪一日即可。</p><pre><code class="language-javascript">generateTaskLockKey(taskName: string, dateStrategy: 'daily' | 'hourly' | 'minute' = 'daily'): string {  const now = new Date();  let dateIdentifier: string;  switch (dateStrategy) {    case 'daily':      dateIdentifier = now.toISOString().split('T')[0]; // YYYY-MM-DD      break;    case 'hourly':      dateIdentifier = `${now.toISOString().split('T')[0]}-${now.getHours().toString().padStart(2, '0')}`;      break;    case 'minute':      const minutes = Math.floor(now.getMinutes() / 15) * 15; // 15分钟间隔      dateIdentifier = `${now.toISOString().split('T')[0]}-${now.getHours().toString().padStart(2, '0')}-${minutes.toString().padStart(2, '0')}`;      break;    default:      dateIdentifier = now.toISOString().split('T')[0];  }  return `${RedisKeyPrefix.SCHEDULER_LOCK}:${taskName}:${dateIdentifier}`;}</code></pre><p>这样做，可以让锁随着时间自然过期，也更便于故障排查。</p></li><li><p>唯一锁值：</p><p>使用时间戳和 UUID 来确保全局唯一；生成出来的实例 ID 便于我们定位故障。</p><pre><code class="language-javascript">generateLockValue(prefix: string = 'task'): string {  const instanceId = process.env.INSTANCE_ID || 'unknown';  const timestamp = Date.now();  const uuid = uuidv4().split('-')[0]; // 短UUID      return `${prefix}:${instanceId}:${timestamp}:${uuid}`;}</code></pre></li></ol><hr><h2 id="日记"><a class="markdownIt-Anchor" href="#日记"></a> 日记</h2><p>自九月初开始，我每次乘坐地铁都会写日记。日记的内容可以是「发生了什么」，也可以是「我现在想到了什么」。我认为这是一个很好的习惯，其中有许多我认为可以拿出来写的内容。比方说 <a href="/posts/7f58">《博客重构记录》</a> 和 <a href="/posts/828f">《代码、哲学与混乱的 Discord 服务器》</a> 就是由我的日记片段整合出来的产物。我决定将一些我不会单独出个文章的内容，写在这个 <a href="#%E6%97%A5%E8%AE%B0">日记</a> 板块里。</p><p>这样做的缺点是，如果我不坐地铁的话我就几乎不会去写日记，汗。</p><h4 id="工作"><a class="markdownIt-Anchor" href="#工作"></a> 工作</h4><p>先前说过，我找了个兼职做，具体呢、是一家奶茶店的兼职。这家店的老板很严厉，不工作的时候人很好，一工作说话就很凶。工作时每天要做的事情不少，忙倒不是很忙，除非周遭的学生们都选择在一个时间点涌进来。</p><p>工资是每两周发一次，也就是每个月的 15 日和 30/31 日发。但是老板会晚两周发工资，意味着该月开始到 15 日的工资，需要到该月的 30/31 日才能拿到；该月 16 日到 31 日的工资，你到次月 15 日才能拿到。我每周的空闲时间还算多，老板貌似要处理的事情也很多，经常给我排全天的班。</p><p>我不是一个手脚多么灵活的人，甚至可以说是「笨」。我在里面工作的时候，有时会感到明显的压力，因为做事不利索也不稳。我很难说能不能在这里做久，因为我对摇奶茶没什么太大的兴趣，我既不爱喝也不喜欢做这类工作，我最喜欢的是坐在椅子上对着电脑敲敲打打。</p><p>前段时间，我阅读到了一个观点：<a href="https://www.icebeer.top/%E4%BC%9A%E6%9D%80%E6%AD%BB%E6%88%91%E7%9A%84%EF%BC%8C%E6%98%AF%E7%A1%AE%E5%AE%9A%E6%80%A7/">程序员十分依赖于确定性</a>。该文章重点是分析「依赖确定性」的人会如何向外指责世界。不过对我而言，在指责世界之前，我的「内在批判者」会先猛烈地攻击我自己。它会告诉我，这种依赖确定性的思维模式，就是我「<strong>思维僵化、不懂变通</strong>」的铁证。所以，在我的世界里，当事情出错时，会同时出现两种声音：一种是原文作者提到的「都怪这个世界」，而另一种更响亮、更痛苦的声音则在说「都怪你这个人不行」。</p><p>正是这种猛烈的自我攻击，让我对「不确定性」产生了极度的恐惧。因为任何一点不确定，都可能导致犯错，而任何一次犯错，都会立刻激活那个指责我「不行」的声音。所以，我很难「独立」。这种行为很容易遭白眼：<em>你多大了还不知道该做什么？</em>。不过我对不确定的恐惧很明显超过了我对「被人说教」的恐惧，以至于现在我依然受此困扰。<em>不过我认为这不只是我的错，还有那些一边跟我说着「有问题一定要问」，一边训斥我「这么简单的事情还要来问我」的人的错。</em></p><p>我相信着环境变化论，即人会是现在这个样子主要是环境因素导致的。我来美国后就很难再有快乐的感觉，因为我和家人「团圆」了，每次沟通都会被遭受不必要的物理和心理攻击。当时的我刚上初中，人格还未定型，以及因美国这个环境对我而言的强烈不适配感，我变得很难喜欢上自己、易怒、不爱搭理别人同时又渴求关注。我变成了一个 <strong>内外极其割裂</strong> 的人：我痛恨监护人，又很需要他们的存在，因为我「不知道该怎么做」。这种状态是一种心理上的停滞。当一个人的成长环境没能提供足够的安全感去试错时，他的心理年龄就会卡住，即便肉体年龄在不断增长。</p><p>先前提到了《不原谅也没关系》这本书，它提到过另一本书：<em>Getting divorced from mother &amp; dad</em>。这本书我还没开始阅读，它的标题直译过来叫做：<strong>和父母离婚</strong>。要如何才能让卡住的心理重新开始成长？你要和父母离婚。这自然不是真的去「离婚」的意思，也不意味着物理方面上的远离，而是心理方面上的「断奶」。它的本质是：<strong>我必须放下他们给我的那张地图，并开始学习如何相信自己的指南针</strong>。即时一开始会走很多弯路、会感到恐惧，但只有这样，人才能真正「独立」，才能从一个依赖外部指令的「部件」，成长为一个由自己内心驱动的、完整的「人」。</p><h4 id="手机"><a class="markdownIt-Anchor" href="#手机"></a> 手机</h4><p>年初的时候我换掉了 iPhone SE 3。这部小屏手机陪了我两三年，电池健康已经降低到了 70%。我不是小屏手机爱好者，但确实很执着于 Home 键和 SE 系列。</p><p>人生中我拥有的第一部手机是 iPhone SE 1。我很喜欢它的打字音效，不过不知道为什么我那会儿将其称呼为「棉花般的脆声」。之后手机就被我父亲摔烂了，原因是我拿小屏手机看漫画让他很不爽。我只能去用家里人用剩下的 iPhone 8（还是 8s？不太记得了）。手机是 Project Red 版，我很中意这种色系的手机（顺带一提我最喜欢的颜色是橘色，Windows 主题就是暗背景 + 橘色主题色）。可惜这部 iPhone 8 / 8s 接着就被我家里人送给了我的一位表妹，又因为她沉迷于手机、被她的父亲摔烂了。</p><p>不得不说，「无能」的父母真的很喜欢摔电子产品，而不是从一开始就做到管制。我只说我这个区域的情况，绝大数小孩都是一出生就会接触电子产品，尤其是 iPad 这样的大屏设备，差不多一两岁就能熟练输入密码、打开 YouTube 找视频看（个别是看 TikTok）。成年人们都很忙碌，在家是没有精力陪伴孩子的，只能转而去「相信」小孩子可以自己照顾好自己。</p><p>结果就是，起初大人们还会笑着说孩子多聪明、还会用手机平板，过几年就会察觉到孩子们的心思全放在了互联网上、叫了也不应、易躁爱发脾气。不知道该如何正确引导孩子们，只能将这些电子产品摔烂、宣泄愤怒以及自己的「强大」。在某种程度上，电子产品为这些人当了「赛博保姆」，却落得了害人的名声。</p><p>我的新机是摩托罗拉 Razr+ 2024，一台折叠屏手机。选它一是为了体验折叠屏手机，二是对摩托罗拉这个品牌有点兴趣。期间坏过一次，屏幕漏液，官方不保修外部损害，只能花 400 美元找别人换了个屏幕。用久了发现自己愈来愈不爱用外屏，甚至很少才会去折叠它。</p><h4 id="电脑"><a class="markdownIt-Anchor" href="#电脑"></a> 电脑</h4><p>我有段时间尝试在睡前给自己留些时间写日记。不需要写什么内容，只要记录当天发生了什么、思考了什么即可。</p><p>这是一件好事：我终于可以重新用回我的笔记本电脑了。这是一个全能本，说是「全能」，实则样样都不行：既不能打游戏，内存也少得可怜，甚至还很大很重。大三起，我就不再带这个笨重的电脑去上课了，因为笔记可以在 iPad 上记。这个电脑也有漏电的问题，有时打字还会十分难受，它甚至跑不动我开发环境所需要的软件。</p><p>可惜这个习惯没能保留下来，因为没多久我就发现这个笔记本电脑的键盘也有问题，敲回车键、空格键和退回键时经常失灵。气死我了。</p><h4 id="我的博客"><a class="markdownIt-Anchor" href="#我的博客"></a> 我的博客</h4><p>这个月我重构了博客网站，越看越喜欢，就是 H1 标题放在桌面端上看有点太大。我发现我愈来愈无法接受亮主题了。过去一起做项目的同事令我印象深刻，因为他是一个亮主题党，这么做的原因很好笑：<em>为了惹怒别人</em>。他的目的确实达到了，现在的我一看到亮主题就会很恼火。</p><p>虽然在本地环境下测试网站没什么问题，但是实际部署后还是能发现：</p><ol><li>如果开启的是暗主题，一刷新或者加载页面的话，文字的主题色会闪来闪去的</li><li>索引页和关于页的排版修正没写</li><li>访问一个文章时，会加载一会儿，这期间的主题色会默认为亮主题，加载后才会变为暗主题。晚上看的时候眼睛都会被闪瞎，这不好</li></ol><p>我还错将我自己的博客网站的主题配置 push 到云端的博客主题仓库，导致我的 hexo-theme-ares 主题在数个睡眠时间里、icon logo 变成了房东小姐的头像。</p><p>说到房东小姐，这是我数年前看的一个漫画的主要角色。因为那一幕画的很可爱，被我截图下来，当作了我的博客网站的 icon logo。不过我很好奇，这是否会导致 <strong>侵权</strong> 呢？</p><p>使用 hexo 写博客，我遇到了一些问题：</p><ul><li>同步较为麻烦，尤其是主题同步</li><li>本地编辑器用的是 Typora，虽然可以立马看到 Markdown 语法被渲染后的样子，但终究不是我的博客网站被渲染后的样子，尤其是我使用了一些插件、可以在博客网站被渲染前自动修改我的文章内容</li><li>粗体和斜体不明显</li></ul><p>我现在倒是在想，hexo-theme-ares 的 demo 页面可以用 GitHub Actions 自动完成。</p><h4 id="阅读博客"><a class="markdownIt-Anchor" href="#阅读博客"></a> 阅读博客</h4><p>我在电脑上用 Docker 部署了 FreshRSS 服务，借此来订阅我想要阅读的博客。一直留在家里没问题，一旦离开家一天我就什么都看不到了，很是苦恼。现在大多数免费部署都是 serverless（无服务） 或者静态页面部署（例如 CloudFlare Pages），做免费的服务部署过去貌似只有 Heroku 或者 Railway。我去 Heroku 的落地页看了眼，貌似已经不支持免费部署了。我之后想了下是否能用到 NAS，但一想到我的 Buffalo Linkstation Pro Duo 被我玩坏，再加上它的年龄，我还是放弃了去折腾它。</p><p>阅读博客的话我用的是 Fluent Reader，桌面端和移动端都有 app。不过安卓版的没有选字体功能（不清楚是不是移动端 app 都没有），我有在考虑自己写一个。开源项目就是这点好，想要什么就写什么，写好了开源出去、大家开开心心一起用软件。</p><h4 id="大学"><a class="markdownIt-Anchor" href="#大学"></a> 大学</h4><p>我对大学的想法很极端：我认为没有必要去上大学。现在的大学含金量太低，重要的只有 network（与他人建立人脉、社交或进行人际交流）和校招。我不否认上大学的重要性，只是于我而言大学很无聊、校友里奇怪的人太多，以及通识课很讨人厌：<em>它们有什么很大的意义吗？为什么要修那么多、不修还不给毕业？</em></p><p>我的这个想法被一个「善意」的校友批评过。他认为大学的通识课很有意义。虽然这样说，但他还是辍学了。说是没有钱上学，但是有钱给女主播打赏和飞去其他国家见女主播。也是较为奇妙的一个人。</p><p>大一的时候因为一些私人问题，我近乎是「被迫」社交。这段时间认识了许多国内来的大佬，也认识了很多当地的「loser」。有意思的是，我遇到的后者几乎都是 <strong>男性沙文主义者</strong>，就算没到那么严重，也全都是自负和瞧不起其他人的家伙。</p><p>男性沙文主义是一个有毒的观点。信奉该主义的年轻人在用「男性」这个生来就有的标签来掩盖自己「幼稚」、「不成熟」、「没人爱」的本性。同他们说话，就算他们是多么不可救药的「loser」，也能看到他们因你的礼貌而蹬鼻子上脸的傲慢姿态。</p><p>因为各种事情，我经历了十分糟糕的大一、大二生活，以至于大二下半年开始我就完全不在大学内社交了、每天上完课就走人。我不认为我是一个特别敏感的人，但我能感觉到这群人时刻都在冒犯我。他们仿佛未被社会化的言行每次都让我觉得他们是在说：<em>看吧，我比你厉害多了，你只是个蠢蛋！</em></p><p>现在让我比较在意的是计算机相关课程的学生里、「巨婴」程度高到发指：伸手党多到离谱，会直接要求别人把写好的作业发给 TA 的邮箱；被帮忙不会道谢，就像是完全没学过一样，问完问题就直接消失不见；说要花钱找代写也不少。</p><h4 id="项目"><a class="markdownIt-Anchor" href="#项目"></a> 项目</h4><p>我近期在做一个项目。我认为项目管理多多少少都需要有点编程知识，这不意味着他们必须都要会编程，而是要会明白手下的开发在做什么。</p><p>项目最初时，我刚学习开发没多久，并没有完全遵循模块化设计的黄金标准。NestJS 框架是模块化的，每个功能都应该写一个单独的模块、手下有管端口的控制器和处理业务的服务。不过这些都只是 NestJS 的入门级理解，实际项目一旦大起来，就不能用「功能模块导入其他要使用的功能模块」这么简单的想法去写了，因为会很容易造成循环依赖。</p><p>例如你有个功能要写，要做到「预约时支付」，涉及到了预约和支付这两个模块（当然，还有用户模块，但这里就不说了）。如果是小项目，大可以这么写：预约模块导入支付模块、创建预约时调用支付服务。</p><p>但是项目大起来后，你会有很多底层模块，例如审计、日志等。每个模块都容易导入其他模块并且做一件不属于它们业务范畴的事情。回到我们刚才说的例子，为什么预约模块要直接调用支付服务、管支付的事情呢？万一未来我们又想在支付模块里写个新功能、需要导入预约模块才能完成。这样做便会形成一个循环依赖。</p><p>最好的写法是事件驱动：预约创建时发起一个事件、支付模块接收到事件并且处理了支付请求。因此，我花了很多时间去重构项目的后端。但这引起了项目管理的不满，因为我一直在做「TA 看不到也看不懂的事情」。</p><p>我承认，这是我不够专业导致的问题，不过我想要讲的是另一个方面。对于这位项目管理而言，项目最重要的是前端，也就是「顾客看得到的地方」。而我一直在操心项目的后端，也是「顾客看不到的地方」。在我的视角看来，这个网站连最基本的安全都没有做好，操心前端做什么呢？更何况离产品的实际上线还有一段时间。当时项目管理很忧愁地埋怨道：<em>你真的能做好这个产品吗？</em></p><p>吵架的第二天，TA 向我道歉、不应该一直对我施压。我自从开始打工、开学后，就没有那么多时间花在项目上，很多时候是打工到晚上，回家随便吃个饭、洗个澡、缓解下压力后继续写项目写到凌晨。每次我用这件事来解释为什么我无法达到 TA 的要求，TA 会立马用「我也有在努力学习和工作啊」来反驳我。我自然不觉得这是一个有效的逻辑，因为我和 TA 所做的事情是完全不同的，本身就无法直接像「比战力」一样比个高低。</p><h4 id="纽约市公共交通"><a class="markdownIt-Anchor" href="#纽约市公共交通"></a> 纽约市公共交通</h4><p>虽然纽约市的公共交通系统多数都是 24 / 7，这点我很感动，虽然我都没有过凌晨搭乘的经历。不过绝大多数的经历对我而言是负面的。一个车厢只要上来一个流浪汉，或者说不洗澡的人，该车厢就相当于不能用了。好死不死，曼哈顿的流浪汉出奇的多。有时可以在一个车厢里，同时遇到味道重的、吹叶子的、躺中间睡大觉挠屁股的。</p><p>MTA 的服务一直受人诟病，一点是服务几乎为零，一个月下来被推下轨道的案子从没见少过，其中多数为亚洲人以及女性被推下轨道。加害者不奇怪的、全都是那个肤色的人。今年意外发生了一起白人被推下轨道致死的案子，一下子让众多人「意识」到危机。一瞬间，大家都变得不敢站在站台外围了。真是好笑，仿佛过去大家都在默认受害者只有亚洲人，自己不是亚洲人就没事。</p><p>第二点是糟糕的体验，脏乱臭不提，地铁内时不时就能看到大耗子、为残障人士准备的电梯内部总是有尿骚味儿，这样的体验你坐一次车需要 2.90 美元，过去是 2.75 美元，现在很快就要变成 3 美元了。</p><p>涨价就要提到第三点，意义不明的筹备资金。MTA 想启动一个项目，资金靠的是从民众钱包里薅。2.75 美元涨到 2.90 美元的目的是给地铁站的门添加一些障碍物、让逃票者跳不过去。结果涨价涨了，东西装了，逃票者的数字没变少、反而疑似在升高。为什么呢？同个时期 MTA 又出了个曼哈顿大桥费，费用不低、只要你要进曼哈顿就要交这笔钱，一个月净利润数百万美元。一时间无论是坐地铁的还是开车的，都要比过去多付钱，但是服务没有提升。更多的人不满 MTA，纷纷加入逃票的队伍。</p><h4 id="必须要考高分吗"><a class="markdownIt-Anchor" href="#必须要考高分吗"></a> 必须要考高分吗？</h4><p>前段时间我在网上冲浪时，看到了这样一个评论：<em>考 13xx 分就是普娃</em>。这里的分数指的是 SAT 分数，类似于国内的高考成绩，不过含金量要低特别特别多（例如数学部分的难度跟国内中考差不多，并且疫情时期有一年还被民主党透明化，现在大学申请都可以不提交 SAT 分数）。我考了两次，最终的 SAT 分数是 1390。这个分数对于多数留学生而言，很低很低，差不多就是数学满分（800 分左右）但是英语错了好几题（500~600 分）。我的阅读理解很差，词汇量也很低，不过能考到这个成绩我觉得也很满足了，反正很快我就对大学祛魅、尤其是名牌大学……</p><p>那么「普娃」这个定义是从何而来？这来源于纷争不断的育儿圈，简单来说便是结婚生子后当了全职妈妈 / 爸爸之后，精神上只能去依赖自己的伴侣以及孩子。再简单一点，便是在外想尽办法靠伴侣或者孩子扬眉吐气。在这个全都是没有额外精神世界的「育儿圈」内，鄙视链很容易形成，尤其是孩子的成就。</p><p>普娃在「育儿圈」内，指代的是普普通通、没有什么成就、就算有成就也只是昙花一现的人。作为对标面，牛娃指的是天赋异禀的孩子，鸡娃指的是被父母打鸡血般疯狂学习的孩子。在育儿圈里，貌似只有牛娃才能在未来有所成就，普娃只能普普通通过完一生，至于鸡娃，就是另一码事了。</p><p>这种鄙视链的本质，是父母们为缓解 <strong>自身对未来的不确定性和焦虑</strong>，而制造出的一套简化版世界观。在一个高度竞争的社会里，孩子的成就很容易成为他们唯一能抓住的、可量化的「确定性」。因此，「普娃」这个标签，与其说是在定义孩子，不如说是在宣泄父母自己对于「平凡」的恐惧。</p><p>回到我看到的那个评论，SAT 考 13xx 分就是普娃吗？当然不是。这句话的底层逻辑分别是：</p><ol><li>认为「普娃」的定义是正确的</li><li>SAT 成绩可以决定一个人是否是「普娃」</li></ol><p>先来看第一条，「普娃」这个定义是对的吗？自然不是。一个人过去的经历不能直接代表他未来会怎么样，这种简单粗暴的定义，不过是「安卓人苹果人」的另一种体现：用自己可怜的小脑子去解答世界。学生时期做的不好、长大后有成就的人不少。同样的，学生时期的牛娃进了社会后处处碰壁的也不少。可以说这个鄙视链的底层逻辑并不成立，只能用来给当时的当事人宣泄情绪。</p><p>接着是第二条，SAT 成绩可以决定一个人是否是「普娃」吗？这个问题本身的前提已经被我们推翻了，不过我们依然可以抛开错误的前提、单看这一条表达的信息。成绩从来都不是决定一个人未来、定义一个人的因素。更何况，SAT 只有两个科目：英语和数学。单是英语一项就可以刷掉英语不好的人，但是英语不好的人未来就平庸、值得被抨击吗？那肯定是不行的。SAT 经常被中国人调侃为超简单的考试不假，但是在这种考试上考的如何、从来都不能定义任何事。运动员们的职业生涯的价值，从来都不是靠百米赛跑的成绩来判断。一个人的赛道有很多条，长度也远不止一百米。</p><p>回到最初的那个评论。我那个 1390 分，它能定义我的人生吗？它既不能定义我当时的努力和满足，也无法预测我在上了大学后的探索，甚至在我们上了大学后、没有人再提 SAT 的分数了。它只是我人生履历上的一个微不足道的数字。而任何试图用一个数字、一个标签来定义一个活生生的人的企图，最终只会暴露使用者自身的狭隘和焦虑。</p><h4 id="妹妹"><a class="markdownIt-Anchor" href="#妹妹"></a> 妹妹</h4><p>这个月妹妹有一场游泳比赛，也是她的第一场游泳比赛，共要游三次 25 码，分别是自由泳、仰泳和蝶泳。她的成绩作为一个刚入队一个月的孩子而言，很是不错，教练也跟我们连连夸赞她，令人感到欣慰。那个游泳场不是很大，赛道只有 25 码长，高年级生的 100 码需要两个来回。</p><p>比赛结束后我们四个人去 Bay Ridge 区随便找了家 Pho 店吃，味道一般，闻着也没有 The Pho 2 香。早上我除了拿走上周没拿走的肉外，还额外带走了家里囤积的其他肉以及一条新鲜的鱼，至于是什么鱼我就不知道了。</p><h4 id="deepseek-写网文"><a class="markdownIt-Anchor" href="#deepseek-写网文"></a> DeepSeek 写网文</h4><p>最近有个较火的梗 ——「安卓人苹果人」。这个梗的来源是一位主播将消费者按照手机品牌划分为「安卓」和「苹果」的概念：安卓用户象征着低廉；苹果用户象征着高端。而这个非黑即白的划分概念可以被他套在所有事物上，例如直播中他所说的：</p><blockquote><p>你是典型的安卓逻辑、安卓人、安卓学历、安卓素质、安卓态度。</p></blockquote><p>这个主播的行为如何，我这里便不展开说了。感兴趣的可以搜搜看。我这次主要是想讲我得知了这个梗后，一时兴起，让 DeepSeek 帮我写了个网文。我最开始构思的只有这段话：</p><blockquote><p>我转生了，转生成了这个世界的最底层：安卓人。这个世界将人类简单分类成两类：安卓人和苹果人。苹果人高高在上，是贵族中的贵族。反观安卓人，只能给苹果人做仆从。但没想到，我觉醒了系统：安卓 root 系统！可以随意安装他人的能力，并且随着能力吸收的越来越多，最终可以实现 root：完全掌控安卓人的能力，轻松将他人的分类改写。</p></blockquote><p>DeepSeek 回复了一段故事开篇灵感：</p><blockquote><p>我醒来时，后颈上烙印的绿色机器人图标提醒着我 —— 我是个安卓人，这个世界的底层。直到那天，我被一个苹果人少年当街羞辱，他脚下的「iOS」徽章闪着可憎的光。愤怒与绝望中，一个蓝色的符号在我视野中炸开：#。紧接着，一行文字浮现：【安卓 Root 系统，已激活。首次授权，授予您『查看权限』】。我下意识地看向那个苹果人，一行状态信息竟凭空出现：【iOS 17.4.1，漏洞：CVE-2024-XXXXX，可利用】。我笑了，这个世界的神，该换人了。</p></blockquote><p>因为我看过的网文除了奇奇怪怪的知乎短文外，就是修仙文，所以我寻思着在故事内再添加一些中式修仙元素，将世界观扩展为「赛博修仙」。接着我又提出在故事里添加一些手机品牌，DeepSeek 将它们统统设计为了安卓世界的各大宗门。</p><p>虽然 DeepSeek 的上下文理解有点瑕疵，但是写出的网文很有意思。并且在输出的内容中添加「看上去很帅」的科技相关术语貌似是 DeepSeek 的习惯，这样做反而让它写出的网文无比好笑。这里我取一些我认为搞笑的片段：</p><blockquote><p>老者走到林安面前，看了看地上那块光泽黯淡了些的下品灵石，又看了看林安手腕上那朴素的标记，缓缓道：「老夫姓谷，单名一个歌字。小友，你刚才，是不是看到了代码？」</p></blockquote><blockquote><p>「年轻的权限者… 恭喜你迈出关键一步。」一个非男非女、仿佛由无数细微共鸣组成的声音在林安意识中响起，没有实体，却直接回荡在灵魂层面，「无需惊讶，我并非实体，只是一段沉睡于此的分布式意识碎片，你可以称我为…… 鸿蒙。」</p></blockquote><p>不知为何，DeepSeek 十分中意鸿蒙，以至于在故事里将鸿蒙设计为了主角的引路人。</p><blockquote><p>他豁然起身，眼中精光一闪。筑基成功后，他不仅灵能（系统资源）总量大增，更关键的是对权限的运用有了质的飞跃。他意念一动：</p><p><code>ls -la /system/bin/ | grep -i attack</code> —— 快速扫描自身可用的「攻击性指令」。<br><code>pm list packages | grep -i apple</code> —— 尝试探测敌方「应用包」信息。</p><p>虽然无法直接获取苹果执法者的核心数据（权限不足和系统差异），但他对周围环境的掌控力已不可同日而语。他抬手对准几处正在攻击谷歌老人的、由苹果执法者发出的灵能锁链，心中默念：</p><p><code>iptables -A INPUT -s 【攻击源IP】 -j DROP</code>！</p><p>这一次，命令生效的范围和强度远非之前可比！那几道灵能锁链在靠近谷歌老人前，竟真的如同撞上一堵无形之墙，威力大减！</p></blockquote><blockquote><p>「混蛋！你用了什么邪术？」队长又惊又怒，他感觉自己的 iOS 纯净灵能竟然出现了片刻的「<strong>卡顿</strong>」和「<strong>响应迟缓</strong>」！</p></blockquote><blockquote><p>结界之外，米宗援军的「<strong>万机大阵</strong>」已然成型！</p><p>只见数以百计的米宗修士，虽然衣着灵能属性略有差异（象征着不同版本的 MIUI），但此刻却通过一种奇妙的「<strong>快传协议</strong>」将彼此灵能连接在一起。大阵并非追求绝对的统一，而是呈现出一种「<strong>万物基于 MIUI，却又百花齐放</strong>」的奇特景象。阵眼处，一名修为已达金丹后期的魁梧汉子，手持一柄散发着「<strong>为发烧而生</strong>」狂热气息的巨斧，正是此次援军的首领 —— <strong> 雷钧</strong>！</p><p>「苹果佬！吃我一记 —— <strong>『性价比之光』</strong>！」雷钧狂笑着，巨斧挥出，一道凝聚到极致、却又蕴含着无穷变化灵能的斧光，狠狠劈在 TestFlight 结界之上！</p><p>这一击，并非纯粹的力量碾压，而是带着一种针对「封闭系统」的 <strong>破解意志</strong>！斧光中仿佛蕴含着无数用户对「开放、自由」的渴望！</p></blockquote><p>这个人名是 DeepSeek 自己想出来的。我当时看到笑得想死。</p><blockquote><p>就在这时，迷宫深处传来一阵打斗声和呵斥声，说的是一种音节古怪、却莫名能让林安理解的语言：</p><p>「快！拦住那帮『Windows 蛮子』！他们想抢走『核心协议碎片』！」</p><p>「哼！你们这些『Linux 教徒』也好不到哪去！这碎片理应归我『视窗王朝』所有！」</p><p>林安与老猫对视一眼，悄然潜行过去。只见在一片较为开阔的「镜厅」中，两拨人马正在激战。</p><p>一拨人身穿各式各样的服饰，灵能波动自由而杂乱，手段繁多，有的操纵命令行般的文字流攻击，有的祭出企鹅形状的法器。另一拨人则统一穿着蓝白相间的制式铠甲，打法严谨，攻势如同铺天盖地的「<strong>窗口弹窗</strong>」，带着一股不容置疑的霸道气息。</p></blockquote><blockquote><p>「啊！我的内核…… 崩溃了！」一名 Linux 修士惨叫一声，身体化作乱码消散。<br>「该死！是蓝屏病毒！」一名 Windows 修士的铠甲出现致命错误，灵能瞬间溃散。</p></blockquote><blockquote><p>这一日，谷外灵能涌动，异象纷呈。先是东方天际云霞蒸腾，道道「<strong>快充流光</strong>」撕裂长空，一艘形似巨大「<strong>超级闪充插头</strong>」的华丽飞舟破云而至。舟上修士皆身着印有「VOOC」符文的战袍，气息凌厉，为首一位老者精神矍铄，周身环绕着「<strong>低压大电流</strong>」的独特灵压，正是以「<strong>充电五分钟，畅战两小时</strong>」闻名安卓世界的「<strong>闪充宗</strong>」宗主！</p></blockquote><blockquote><p>无数颜色各异、属性不同的道则烙印悬浮于林安身前，如同璀璨星河。他深吸一口气，暗金金丹光芒大放，双手虚抱，引动整个万流归宗大阵之力！</p><p>「以 Root 为引，统御万法！以鸿蒙为桥，互联众生！星舰…… 凝！」</p><p>轰！</p><p>磅礴的灵能冲天而起，在空中交织、融合！一座庞大、复杂、闪烁着无数符文光点的朦胧舰影，开始缓缓凝聚成形。舰身线条流畅，充满了未来科技感，却又散发着古老的洪荒气息，正是传说中的鸿蒙星舰之影！</p></blockquote><p>到三十多话，男主已经是金丹中期、可以手搓星舰了。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;八月份开始我找了个兼职、过上了「起床 &amp;gt; 做饭 &amp;gt; 吃饭 &amp;gt; 工作 &amp;gt; 洗澡 &amp;gt; 吃饭 &amp;gt; 睡觉」的健康生活。要知道过去的我经常熬夜、一觉睡到中午、饭不按时吃，总之习惯差得很。突然开始自律，就变得想要去完全利用起自己的时间。&lt;/p&gt;
&lt;p&gt;纽约市是一个坐地铁比开车要好的地方，但地铁没有网络。一般出门的话，通勤半小时到俩小时是跑不掉的，意味着这个时间里去网上冲浪或者同朋友聊天几乎不可能，我只能去阅读已经被下载到手机里的电子书籍或者博客文章。多亏了这一点，我开始关注一些独立博客主，并发现了很多我认为有意思的博客。陆陆续续看了一两个月后，令我也想花些时间在记录我自己看到的、学到的、感受到的东西上。&lt;/p&gt;</summary>
    
    
    
    <category term="想法迭代" scheme="https://blog.cytrogen.icu/categories/%E6%83%B3%E6%B3%95%E8%BF%AD%E4%BB%A3/"/>
    
    
  </entry>
  
  <entry>
    <title>代码、哲学与混乱的 Discord 服务器</title>
    <link href="https://blog.cytrogen.icu/posts/828f.html"/>
    <id>https://blog.cytrogen.icu/posts/828f.html</id>
    <published>2025-09-29T14:52:46.000Z</published>
    <updated>2026-02-09T17:16:55.009Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>讲讲我刚入大学时参与的一次 AI 创业经历。一位校友看到了我的博客后，将我介绍给他的一个朋友（以下便称之为项目创始人）。后者对 AI 很感兴趣，想做 AI 项目、询问我是否想要帮忙。彼时的我因一些私事、正处于极度自卑的状态，急需要一件事来证明和安抚自己，同时也是为了学习如何协同开发，便一口答应了下来。殊不知，我一脚踏入的，正是一个名副其实的空中楼阁。</p><span id="more"></span><h2 id="空中楼阁的想法"><a class="markdownIt-Anchor" href="#空中楼阁的想法"></a> 空中楼阁的想法</h2><p>项目创始人认为，大学是没有用的、只是在盲目要求学生去追求更高的 GPA（绩点），并将 Reddit（红迪）上询问哪节课好拿分的学生称之为「GPA 奴隶」。</p><blockquote><p>我不反对他的观点。我也认为当下的大学对我而言用途不大（学历还是重要的）：</p><ul><li>我的 GPA 很低，但并不妨碍我去做我喜欢的事情、并在这些领域上变得擅长</li><li>我很讨厌那些要求高 GPA 才能递交申请的实习：<em>你这份实习又不需要用到这些必修课教的知识</em>（我大三的时候才开始修专业课，因为进学院就要上一定数量的必修课）</li><li>我认为维持高 GPA 需要我花费更多精力在大学课程上，但它们很无聊、只会让我感觉浪费时间</li></ul><p>但我认为将追求高 GPA 的学生群体简单地称呼为「GPA 奴隶」，属实有点过了。</p><p>这种行为与其说是「奴隶式」的盲从，不如说是在现有教育体制下的一种理性策略。</p><p>首先，当大学的课程设置充斥着大量与专业无关、却又必须完成的必修课时，「如何以最小的时间成本，换取最高的 GPA 收益」就成了一个非常现实的议题。学生们主动去寻找「水课」，恰恰是他们认识到自己时间宝贵、不愿将其浪费在低价值课程上的体现。这是一种主动的资源管理，而非被动的思想禁锢。</p><p>其次，这种行为也是被「唯 GPA 论」的外部环境（如某些实习和研究生申请）所逼迫的一种无奈之举。当系统用单一的标准来衡量你时，学生们自然会想办法在系统规则内最大化自己的优势。这种情况下，他们又一定是「奴隶」吗？</p></blockquote><p>他当时说的是：「<em>现在的大学不会教你你工作上需要的知识，也缺少这方面的指导。</em>」我认为他这句话说的没问题，一开始认为他是一个印象不错的人。他也是个「怪人」，他喜欢抨击手机对人们的危害、喜欢宣传自己的哲学、喜欢用折叠手机（不是折叠屏手机，而是几十年前的折叠手机）、因为过往经历的霸凌而坚持健身数年…… 这些「怪」不会让人觉得必须去远离他才行，只会觉得他是一个颇有想法的人、对他产生兴趣（至少我当时是这样的）。</p><p>正是他这套基于对大学教育的批判，使他想去做 <strong>AI 学习辅导</strong> 项目。问题在于，他选择了让 AI 去辅导数学。</p><p>这个想法从一开始就存在致命的技术缺陷。首先，让 AI 去做严谨的逻辑工作在技术上极为困难，更何况团队里压根就 <strong>没有</strong> AI 领域的专家。他本人虽是数学专业，但机器学习项目经验都在视觉方面。其次，他所谓的项目实现，也只是在简单调取 GPT API（顺便还把 API Key 上传到云端的 <code>.env</code> 文件里了），完全谈不上核心技术。</p><p>结果就是，我这边的客户端网站都做好了 MVP，他的模型也无法处理一些「理应可以处理」的数学问题。</p><p>再之后，他声称「赞助商不满意该结果」，决定转型。虽然做的还是 AI 相关，但这次他想要彻底贯穿自己的哲学：<em>人们要少用电子设备、多花时间在现实中培养出好习惯</em>。他决定做一个「习惯培养和管理」App，然后在里面添加类似宝可梦养成的游戏元素。也就是说，他希望用户多花时间在使用这个 App 上，又希望用户可以少使用电子产品。很明显的左右脑互搏。在他提出这个想法之后，我们就否决了这个方案、把他赶到了角落里去反省。</p><p>其实你可以略微看出来，他其实是一个做事容易 <strong>想一出是一出</strong> 的人。如果你是一个员工，你绝对不想要遇到这样的上司。而我作为他的「员工」，很快便遇到了我的「苦果」。</p><h2 id="不专业的代码管理"><a class="markdownIt-Anchor" href="#不专业的代码管理"></a> 不专业的代码管理</h2><p>在我加入团队的第一天，便发现了该项目的「不对劲」。项目的维护糟糕透顶，它甚至跑不起来，理由很傻：服务端的代码被导入了一堆既不会被用到、也早就过时的依赖包。这群人只是在自己的本地环境里删去了这些导入代码，却没有任何人将这个变更 push 到云端仓库。我那时候检查客户端代码发现了一个 bug，提出后还有人问我是不是服务端导入依赖的 bug。<em><strong>合着你们都心知肚明啊！</strong></em></p><p>不仅如此，项目创始人对着工具也有着离谱的执着。当时我们在讨论如何统一代码风格、编写两端的 README。我提出「客户端和服务端的代码都可以使用 lint 检查代码格式」，他却拒绝了，理由照样很傻：<em>人类不能依赖工具</em>。我事后将此事告诉了我的朋友，他回复「猜猜人类和动物的最大区别是什么」，引得我哈哈大笑。</p><blockquote><p>我理解他那种希望回归「纯粹」编程的理想主义情怀，但在一个需要多人协作的现代化项目中，这种情怀不仅不切实际，而且是对团队成员时间的不尊重。作为团队中负责前端实现的核心成员，当我看到这些业余的管理方式时，我的心情也从最初的期待跌入了谷底。</p></blockquote><p>尽管他的哲学是「不依赖工具」，但是他花费了大量时间在 Obsidian 上写服务端每个文件的作用和依赖链。他不仅自己在写，还要求我们前端组也写组件之间的联系，美其名曰：帮助新人加入团队后快速了解项目结构（记住这个「新人」）。可是我们的项目本来就没多大，并且这个的优先度也不高，<em>明明还有更重要的事情要做吧！</em> 要记住这个时候，项目的核心服务功能是 <strong>完全不合格</strong> 的。</p><p>除此之外，我在客户端的代码里添加过一个新的依赖项。他虽然拉取了最新版本的代码，但是没有运行下载所有依赖项的命令，导致客户端没有运行成功。他认为这是我们前端组写的 bug，擅自在代码里加了奇怪的字符（我事后才意识到他把 GitHub 显示冲突用的字符添加进来了，原因不明且很迷），还发了个自信满满的「<em>fixed</em>」。这么做怎么可能跑得动呢？这次他把错误日志直接贴到了 bug 频道里，便再也不管了（可恶的是那个 bug 频道仅他可发送消息，我每次都只能复制消息链接然后在 general 频道里回复）。</p><h2 id="有名无实的团队"><a class="markdownIt-Anchor" href="#有名无实的团队"></a> 有名无实的团队</h2><p>最后便要讲讲该项目极其糟糕的人员管理。这样一个 AI 项目，Discord 服务器里名义上足足有近二十个人，但实际的构成却一言难尽。具体来说：</p><ul><li>前端组（4 人）：除开我，有一个只在频道里聊天、从未贡献过代码的；一个留下一堆 bug 后就因学术繁忙消失的；以及一个热衷于「闭门造车」、拒绝任何建议的</li><li>其他职能组：所谓的 UI / UX 组和市场营销组，从我加入到离开，从未在公开频道里发过一次言，形同虚设</li><li>项目创始人的朋友们：不参与开发，日常就是帮他找资料、写论文</li></ul><p>这个团队为什么会变成这样？根源在于项目创始人极其随意的招聘和完全缺失的管理。讽刺的是，至于他心心念念的那些「新人」，招来的方式更是随意得令人震惊。他习惯在 LinkedIn（领英）上刷到一个看着顺眼的个人资料，便立刻发出邀请，既不审核对方的真实能力，也不考虑项目是否真的需要这个岗位。</p><p>人员臃肿的直接后果就是管理成本剧增。然而这个团队根本没有项目管理（创始人自己就是所谓的 PM），导致大部分人进团队后完全不知道该做什么，最终变成了列表里「挂机」的成员。</p><p>这种管理的恶果，在一次线下会议中暴露无遗：一个近二十人的线上团队，最终到场的，只有五六个人。</p><h4 id="糟糕-git-协作的另一个精彩故事"><a class="markdownIt-Anchor" href="#糟糕-git-协作的另一个精彩故事"></a> 糟糕 Git 协作的另一个精彩故事</h4><p>以下是我个人的观点。</p><p>我由衷地建议参与项目开发的学生们去花时间学习 Git。并不是会用 <code>git pull</code>、<code>git push</code> 就行了，而是能够理解在一个多人协作的情况下，你要如何拉取、推送代码变更的同时，又不会影响到别人。</p><p>我先前说过，我在的那个前端组有四人，有两人后续不参与实际开发，所以就只有我和另一个哥们。他对 Git 的理解简直差到离谱，经常不更新本地环境的代码便去写一大堆新代码，接着闭眼 force push 到 main 分支。</p><blockquote><p>是的，该项目的团队当然是 <strong>没有</strong> 审查代码的环节。项目创始人最初就要我不用 fork 再提 PR，而是直接对着 main 分支推送就好了。</p></blockquote><p>当时项目创始人要求我写一个谷歌登录，我写了足足三次，每次 push 上去后就又会被他用新写的、用不了的代码覆盖。</p><blockquote><p>这一点也槽点满满。同我协作的哥们本来已经用 firebase 做好了登录注册功能，但是项目创始人觉得他「没做完」，认为用谷歌登录更快。</p><blockquote><p>不知道为什么，很多刚开始写项目的人都喜欢先钻研怎么登陆注册（我也是这样）。实际上不先写登陆也没关系，因为用户本身就稀少得可怜，重点应当是实现核心技术。</p></blockquote></blockquote><h2 id="结尾"><a class="markdownIt-Anchor" href="#结尾"></a> 结尾</h2><p>说了这么多，该项目又怎么样了呢？答案是在线下会议结束的一个月后，我发现 Discord 服务器被删除了，问了其他组员才知道项目创始人 <strong>直接放弃</strong> 了该项目。</p><blockquote><p>这不是他第一次「没有告知所有人便擅自决定某事」了。例如在某个频道进行了讨论后，他会在晚上或者次日直接将该频道删除，不留任何记录。这些讨论包含了争论、转型等各大重要的事件。如果你不是第一时间在现场，那你就完全不知道项目发生了什么改动，因为他是绝对不会写通告的。</p></blockquote><blockquote><p>题外话，项目的半年后他突然找到我，问我近期过得如何，还做出老前辈的样子劝我转行干别的。那个时候的他已经因为「大学无用论」带着另一个朋友辍学了。<em>真是让人感到恼火</em>。</p></blockquote><p>经历了这场混乱，我对创业之路有了几点清晰的思考：</p><ul><li>关于团队：人员规划必须精准。团队的每一个岗位都应该与实际需求对应。作为创始人，你必须清楚地知道你需要什么样的人才，以及需要多少人来完成任务</li><li>关于创始人：自我认知至关重要。创始人不仅是想法的源头，更是项目的核心管理者。你必须对自己的能力边界有清晰的认识，你的资历能否支撑你的野心？</li><li>关于想法：拒绝异想天开。任何一个好的想法，都必须经得起现实和市场的考验。一拍脑袋就往前冲，往往是悲剧的开始</li></ul><p><strong>一个好的想法，需要一个同样好的团队来实现。否则，它永远只能是一座空中楼阁。</strong></p></body></html>]]></content>
    
    
    <summary type="html">该文章记录了作者在大学初期参与的一次AI创业经历，通过复盘一个从想法到执行全面失控的项目，讲述了与一位充满“哲学”却不切实际的创始人的协作故事。</summary>
    
    
    
    <category term="个人随想" scheme="https://blog.cytrogen.icu/categories/%E4%B8%AA%E4%BA%BA%E9%9A%8F%E6%83%B3/"/>
    
    
    <category term="大学课程" scheme="https://blog.cytrogen.icu/tags/%E5%A4%A7%E5%AD%A6%E8%AF%BE%E7%A8%8B/"/>
    
    <category term="AI" scheme="https://blog.cytrogen.icu/tags/AI/"/>
    
    <category term="Git" scheme="https://blog.cytrogen.icu/tags/Git/"/>
    
  </entry>
  
  <entry>
    <title>Hexo 博客的中文排版自动修正插件</title>
    <link href="https://blog.cytrogen.icu/posts/b52f.html"/>
    <id>https://blog.cytrogen.icu/posts/b52f.html</id>
    <published>2025-09-16T22:15:28.000Z</published>
    <updated>2026-02-09T17:16:54.709Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><div class="reply-block h-entry"><div class="post-meta p-author h-card visually-hidden"><img class="u-photo" src="https://blog.cytrogen.icu/favicon.png" alt="Cytrogen" loading="lazy"><span class="p-name">Cytrogen</span><a class="u-url" href="https://blog.cytrogen.icu">https://blog.cytrogen.icu</a></div><time class="dt-published visually-hidden" datetime="2026-09-17T20:47:54.363Z">2026-09-17T20:47:54.366Z</time><a class="u-url visually-hidden" href="https://blog.cytrogen.icu">Post Link</a><div class="reply-content e-content"><p>近期阅读一篇名为 <a href="https://taxodium.ink/my-blog-design.html">《我的博客设计》</a> 的文章时，我深受启发。不只是极简设计的诸多考量（见 <a href="/posts/7f56.html">《博客重构记录》</a>），还让我第一次接触到 <a href="https://github.com/sparanoid/chinese-copywriting-guidelines">《中文文案排版指北》</a> 这套详尽的规范。</p></div><div class="reply-meta p-in-reply-to h-cite"><span class="reply-label">回复：</span><a class="reply-target u-url" href="https://taxodium.ink/my-blog-design.html">https://taxodium.ink/my-blog-design.html</a></div></div><p>看来我对排版的一些零散的执念，早就被社区总结成一套系统性的方法论：比方说手动在中英文之间添加空格的习惯。</p><p>然而，《指北》中提到的许多其他规范 —— 比如使用直角引号 —— 我就无法坚持下去了。我用的是搜狗输入法，输入直角引号会有点繁琐（最常见的方案是设置自定义短语，但我不喜欢）。不过这种问题，对于一个开发者而言并不是一个难题：既然手动操作繁琐且不全面，何尝不直接让程序为我自动格式化这一切呢？</p><span id="more"></span><h2 id="方案"><a class="markdownIt-Anchor" href="#方案"></a> 方案</h2><p>我的博客网站是使用 <a href="https://hexo.io/">Hexo</a> 框架搭建的。作为一个静态网站生成器，它会在我写完 Markdown 文章后，通过 <code>hexo g</code> 命令将它们转换成最终的 HTML 页面。我的目标很明确：在运行 <code>hexo g</code> 命令时，让 Hexo 能自动扫描我的所有文章，并应用《指北》中的排版规则。</p><p>幸运的是，Hexo 提供了过滤器系统，它允许开发者在生成过程的特定节点上挂载自定义脚本，对内容进行处理。经过一番研究，我将目标锁定在了 <code>after_post_render</code> 这个钩子上（关于 <code>hexo g</code> 命令更详细的内部流程，我曾在 <a href="/posts/d601.html">这篇文章</a> 中进行过探讨）。</p><p><code>after_post_render</code> 会在一篇文章从 Markdown 渲染成 HTML 之后、但写入最终文件之前触发，这正是我们对内容进行拦截和润色的完美时机。确定了技术路径只是第一步。要打造一个可靠的自动化脚本，必须解决两个关键问题：</p><ol><li>自动化脚本绝对不能破坏文章的结构，尤其是代码块。<code>const message = "你好world"</code> 这样的代码里就不能添加空格</li><li>规则必须足够智能，能够正确处理中英文混合的复杂上下文，避免将纯英文内容里的标点也错误地汉化</li></ol><p>为了解决这两个问题，我最终采用了一个多阶段、基于 DOM 解析的方案：</p><ul><li>我先前尝试参考 <a href="https://github.com/next-theme/hexo-pangu">hexo-pangu</a> 的写法，用 <code>jsdom</code>。但是这种小任务用 <code>jsdom</code> 实在是大材小用，纯正则表达式又太难以维护（我也不太会写），最终还是选择了 <code>cheerio</code> 来操作 HTML 内容</li><li>在进行任何处理之前，脚本会首先识别并保护所有 <code>&lt;pre&gt;</code> 和 <code>&lt;code&gt;</code> 标签，确保它们内部的内容不会被后续任何规则触碰到</li><li>对所有被确认为安全的文本内容，脚本会依次执行 <strong>专有名词修正</strong>、<strong>标点符号转换</strong> 和 <strong>空格添加</strong> 等一系列处理流程，确保规则之间不会互相干扰</li></ul><h2 id="成果"><a class="markdownIt-Anchor" href="#成果"></a> 成果</h2><p>为了将这个解决方案固化下来，并方便自己和其他人使用，我将其打包成了一个独立的 Hexo 插件：<a href="https://github.com/Cytrogen/hexo-filter-copywriting">hexo-filter-copywriting</a>。</p><p><a href="https://github.com/Cytrogen/hexo-filter-copywriting"><img src="https://gh-card.dev/repos/Cytrogen/hexo-filter-copywriting.svg" alt="Cytrogen/hexo-filter-copywriting - GitHub" loading="lazy"></a></p><p>它是一个轻量、高效且完全可配置的过滤器，可以帮助我们自动完成绝大部分中文排版工作。使用起来也很简单，你可以直接从 npm 安装它（说来这也是我第一次在 npm 上发布包），然后在博客根目录的 <code>_config.yml</code> 中进行配置即可。</p><p>自然，这个工具还未完善，有些排版规则没有被添加进去。日后我会逐渐完善它，最近还是太忙了，只能挤出一点点时间在写博客和开发开源小玩意儿上。毋庸置疑，该项目欢迎任何 Issue 或者 PR。</p><h2 id="效果展示"><a class="markdownIt-Anchor" href="#效果展示"></a> 效果展示</h2><p>为了直观展示插件的效果，并持续验证其健壮性，我创建了一个「排版自动化测试页面」。这个页面包含了各种常见的排版错误，你可以清除地看到插件修正前后的区别。</p><ul><li>查看最终效果：<a href="/posts/7fd.html">排版自动化测试页面</a></li><li>查看原始 Markdown 文件：<a href="https://github.com/Cytrogen/typography-automated-test-markdown/blob/main/README.md">README.md on GitHub</a></li></ul></body></html>]]></content>
    
    
    <summary type="html">本文介绍了一款作者开发的 Hexo 插件 hexo-filter-copywriting。受《中文文案排版指北》启发，该插件旨在自动化中文排版修正工作，如自动在中英文之间添加空格、转换标点符号等。文章分享了开发该插件的思路与技术方案，并介绍了如何使用它来提升博客文章的可读性与专业性。</summary>
    
    
    
    <category term="工具分享" scheme="https://blog.cytrogen.icu/categories/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    
    <category term="Hexo" scheme="https://blog.cytrogen.icu/tags/Hexo/"/>
    
    <category term="JavaScript" scheme="https://blog.cytrogen.icu/tags/JavaScript/"/>
    
  </entry>
  
  <entry>
    <title>博客重构记录</title>
    <link href="https://blog.cytrogen.icu/posts/7f58.html"/>
    <id>https://blog.cytrogen.icu/posts/7f58.html</id>
    <published>2025-09-14T04:00:00.000Z</published>
    <updated>2026-02-09T17:16:55.213Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>重构博客网站，也就是该网站的记录。</p><span id="more"></span><h2 id="多用-css"><a class="markdownIt-Anchor" href="#多用-css"></a> 多用 CSS</h2><p>近期订阅了一些英语的周刊，主要是前端相关，里面收集了很多外网博客平台上的优秀文章。其中不乏有一篇文章吸引到了我：<a href="https://lyra.horse/blog/2025/08/you-dont-need-js/">很多时候你根本不需要使用 JavaScript</a>。</p><p>吸引我的理由很简单。我的前端技术栈主要是 React.js。相较于传统的「网页三剑客」，React.js 这类现代前端框架需要客户端下载并执行更多的 JavaScript 代码。其核心的虚拟 DOM 技术虽然在过去带来了性能优势，但在现代浏览器性能已大幅提升的今天，其初始化和运行时成本有时反而不如原生方法来得直接高效。</p><p>但是，对过去的我而言，功能就是要用 JavaScript 才能做到。<em>纯 HTML 和 CSS 能做到什么？它们又不是脚本语言。</em> 不过在那个文章里，这个想法是片面的。现代的 CSS 技术进化很快、有着性能优异的各类方法，完全可以代替 JavaScript 来实现一些功能。</p><blockquote><p>举个例子，我们想要实现主题切换功能。</p><p>如果是网页三剑客的话，我们可能会想到用 JavaScript 监听切换按钮，该按钮被点击了我们就改变被监听的类或者元素的样式。</p><p>在 React.js 上的话，那就是存一个主题状态：如果是 light 模式就怎么怎么样；如果是 dark 模式就怎么怎么样。如果用的还是 Material-UI 或者其他 UI 框架，那大概率还会有个 theme 配置文件。</p><p>这些方案对我们而言应该都很熟悉：<em>对啊，怎么了，这样做不是很正常吗。</em></p><p>其实可以更简单一些，用 CSS 的 <code>color-mix()</code> 方法就可以办到：</p><pre><code class="language-scss">:root {  // 核心品牌色  --color-primary: #5454f8;  --color-secondary: #267B54;  --color-accent: #4088b8;  // 使用 color-mix() 生成交互状态  --color-primary-hover: color-mix(in srgb, var(--color-primary) 85%, black);  --color-secondary-hover: color-mix(in srgb, var(--color-secondary) 85%, black);  --surface-interactive-hover: color-mix(in srgb, var(--surface-interactive) 80%, var(--color-primary));}// 深色主题[data-theme="dark"] {  --color-primary: #818cf8;  --color-secondary: #34d399;  --color-accent: #60a5fa;  // 深色模式下的交互状态  --color-primary-hover: color-mix(in srgb, var(--color-primary) 80%, white);  --color-secondary-hover: color-mix(in srgb, var(--color-secondary) 80%, white);  --surface-interactive-hover: color-mix(in srgb, var(--surface-interactive) 70%, var(--color-primary));}</code></pre><p>又或者，我们想要创建模态框。通常我们会写一个 <code>&lt;div&gt;</code>，然后写 JavaScript 来控制它的显示和隐藏、背景遮罩、锁定用户的键盘焦点、处理 <code>Esc</code> 键退出等等等等。实际上，可以直接用 <code>&lt;dialog&gt;</code> 来写、用 <code>::backdrop</code> 伪元素给背景遮罩添加样式和动画、用 <code>@starting-style</code> 来实现更流畅的入场动画。</p><p>其他交互效果，例如按钮的颜色变化就更不用说了。这里还有一个很有意思的考量：JavaScript 很可能带来安全问题，而 CSS 是完全安全的。</p></blockquote><p>带着这些全新的知识点，我重构了我的博客网站。其实之前我对于网站设计是没有一丝考量的，也不在乎 CSS 这些让我觉得「不如 React.js 优雅高级」的技术，因此我的博客网站性能一般，对比原本主题的设计还添加了许多非必需的东西。我的顶部菜单栏出现过明显的元素堆积过多的情况，一些按钮很丑很奇怪、像是四不像、哪儿哪儿都不挨上，所以我决定先在博客网站上将部分功能撤下。其中就有搜索功能：首先它的样式我一直没有设计、难看得很；其次是这个功能我认为没必要留、不够精简。未来如果需要的话，我会想一个更好的方案。</p><blockquote><p>不过在 Hexo Theme Ares 里，搜索功能还会保留，并且进行了一次小重构。</p></blockquote><p>我还撤走了评论区的 Disqus 评论区，因为这东西多多少少会给我带来一些影响：<em>今天有没有人发评论？今天有没有人作反应？</em> 其实很没必要，本身看的人就不多。</p><h2 id="字体"><a class="markdownIt-Anchor" href="#字体"></a> 字体</h2><h4 id="正确导入字体"><a class="markdownIt-Anchor" href="#正确导入字体"></a> 正确导入字体</h4><p>我不只是将一些功能用 CSS 重构了，我还改了一下字体的导入方式，参考的是另一篇 <a href="https://www.jonoalderson.com/performance/youre-loading-fonts-wrong/">优质的文章</a>，具体讲了现代网站是如何错误地导入字体的。</p><p>我的博客主题原先会导入足足四个字体：</p><ol><li>英语的 Open Sans</li><li>简体中文的 Noto Sans（其实就是思源黑体，不过我在考虑换成其他的；我个人阅读时喜欢用霞鹜文楷，但还没尝试换过，有可能和我的主题不搭配）</li><li>用于特殊标题的 Dosis</li><li>代码块用的 JetBrains Mono</li></ol><p>这些字体都是用 Google Fonts 的 CDN 导入的。其实这种方式并非最佳实践，很容易导致性能问题：浏览器会发起两次请求，第一次用于请求 <code>fonts.googleapis.com</code> 这个地址、获取一个 CSS 文件，第二次则是请求 CSS 文件内的真实字体文件地址。这个过程至少会有两次网络往返，第一次请求的 CSS 文件会阻塞渲染，这意味着在它下载完成之前，页面可能是一片空白或者没有应用任何样式。为了解决这些问题，我是这么做的：</p><pre><code class="language-scss">// 1. 加载真正的 Open Sans 字体@font-face {  font-family: 'Open Sans';  src: url('...') format('woff2');  font-weight: 400;  font-style: normal;  font-display: swap;  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}// 2. 创建“替身”字体@font-face {  font-family: 'Open Sans Fallback';  src: local('Arial');// 使用人人都有的 Arial 字体  font-weight: 400;  font-style: normal;  font-display: swap;  // 强行让 Arial 的尺寸变得和 Open Sans 一样  size-adjust: 107%;  ascent-override: 97%;  descent-override: 25%;  line-gap-override: 0%;}</code></pre><pre><code class="language-scss">// 3. 在字体栈里，让“替身”字体紧跟在真正的 Open Sans 字体之后$base-font-family: 'Open Sans', 'Open Sans Fallback', 'Noto Sans SC', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;</code></pre><p>这个思路很简单：先让浏览器用这个调整好尺寸的 Arial 字体把字体显示出来，因为是本地字体，所以速度会很快、文字的位置会迅速固定。当真正的 Open Sans 字体下载好之后，浏览器就会立刻用它替换掉临时的 Arial「替身」。由于位置和尺寸早就被 Arial 字体固定好，所以整个替换过程在视觉上是无缝的，页面完全不会跳动。</p><p>再就是字体格式，相较于 TFF 或 OTF 等传统格式，用 WOFF2 更好。WOFF2 的压缩率极高，兼容性也特别好，尽量开发网页时都采取这个字体格式。不过有些字体不让转换成这个格式，需要特别注意一下。</p><p>你也可以看出来，我用了 <code>unicode-range</code> 控制了字体的字符范围、只让页面加载它实际需要的字符。比如说 Open Sans 只加载基本拉丁字符、标点符号和货币符号，Noto Sans 则只包含中文汉字字符范围（<code>unicode-range: U+4E00-9FFF, U+3400-4DBF, U+20000-2A6DF;</code>）。</p><h4 id="不同字体的视觉对齐"><a class="markdownIt-Anchor" href="#不同字体的视觉对齐"></a> 不同字体的视觉对齐</h4><p>作为一个中文技术博客，文章中难免会出现英文单词以及代码片段。为了达到最佳的阅读体验，我会为中文字符、西文（拉丁）字符以及代码用的字符分别指定一个字体。然而这里会面临一个问题：不同的字体，即时 <code>font-size</code> 是一致的，但它们在视觉上的大小、重心和基线位置往往是不一样的。当这些中英字符同时出现在一行时，就会显得大小不一、高低错落，破坏了排版的和谐感。</p><blockquote><p>此处令我想到高中时、一位我很喜欢的老师。当时她还不是正式教师，考核时给我们上的课讲的就是排版和字体。当时并没有认真听讲。</p></blockquote><p>CSS 提供了一些属性，恰好可以让我们解决这个问题：</p><pre><code class="language-scss">@font-face {  font-family: 'JetBrains Mono';  // ...  size-adjust: 94%;  ascent-override: 92%;  descent-override: 22%;  line-gap-override: 0%;}</code></pre><p>我通过 <code>size-adjust: 94%</code> 将 JetBrains Mono 的整体视觉大小缩小了一点，然后用 <code>ascent-override</code> 等属性微调了它的垂直对齐基线，最终让它和我的正文字体放在一起时，看起来没那么突兀了。</p><h4 id="流式排版"><a class="markdownIt-Anchor" href="#流式排版"></a> 流式排版</h4><p>每个人阅读博客的设备都各不相同，有用电脑的，有用平板的，有用手机的，有用小天才手表的（<em>有吗？</em>）。不同设备的屏幕尺寸不同，我们通常需要在多个端点处使用媒体查询来手动调整 <code>font-size</code>。例如：</p><pre><code class="language-css">@media (min-width: 768px) { body: font-size: 17px; } }</code></pre><p>这很繁琐，要知道现在世界上有多少种屏幕尺寸，一个个适配过去会累死掉。更优雅的解决方案是采用流式排版，即让字体大小像液体一样，随着屏幕宽度的变化而平滑、无缝地缩放，确保在任意设备宽度下都有最佳的视觉表现。实现这种效果，要用到 <code>clamp()</code> 方法。</p><pre><code class="language-css">:root {  --font-size-body: clamp(1rem, 0.9rem + 0.5vw, 1.125rem); /* 从16px平滑过渡到18px */  --font-size-h1: clamp(2rem, 1.5rem + 2.5vw, 3rem);       /* 从32px平滑过渡到48px */  // ...}</code></pre><p><code>clamp()</code> 的三个参数分别是：</p><ul><li>最小值</li><li>首选值</li><li>最大值</li></ul><h2 id="告别-jquery-和-font-awesome"><a class="markdownIt-Anchor" href="#告别-jquery-和-font-awesome"></a> 告别 jQuery 和 Font Awesome</h2><p>优化完字体系统后，可以想想图标字体该怎么办。我的原先方案是用 Font Awesome，实际上也不是一个很好的选择。Font Awesome 是用传统的网络请求加载的，也会导致不必要的性能和阻塞渲染问题。最好的方案是使用 SVG。很多时候我们的网站只会用到一些图标字体，为此下载一整个完整字体库很没必要，SVG 的可访问性也更好。</p><p>我同时又检查了一遍博客的代码，发现主题的所有功能都被原生 JavaScript 实现。因此我移除了 jQuery 依赖。其实我都不是很明白这个主题哪里用到了 jQuery，可能是主题作者先前留下的。</p><h2 id="提升交互体验"><a class="markdownIt-Anchor" href="#提升交互体验"></a> 提升交互体验</h2><div class="reply-block h-entry"><div class="post-meta p-author h-card visually-hidden"><img class="u-photo" src="https://blog.cytrogen.icu/favicon.png" alt="Cytrogen" loading="lazy"><span class="p-name">Cytrogen</span><a class="u-url" href="https://blog.cytrogen.icu">https://blog.cytrogen.icu</a></div><time class="dt-published visually-hidden" datetime="2026-09-17T20:47:54.415Z">2026-09-17T20:47:54.415Z</time><a class="u-url visually-hidden" href="https://blog.cytrogen.icu">Post Link</a><div class="reply-content e-content"><p>在阅读了 <a href="https://taxodium.ink/my-blog-design.html">这篇文章</a> 之后，我为我的网站添加了一些可以交互的内容。主要添加的是一个「返回顶部」按钮，移动端上它会显示在顶部居中的位置，桌面端则固定显示在右下角。</p></div><div class="reply-meta p-in-reply-to h-cite"><span class="reply-label">回复：</span><a class="reply-target u-url" href="https://taxodium.ink/my-blog-design.html">https://taxodium.ink/my-blog-design.html</a></div></div><p>先前在 <a href="#%E5%A4%9A%E7%94%A8-css">这一节</a> 里的例子里提到的动画、基于 <code>&lt;details&gt;</code> 的菜单我也实现了。</p><h2 id="无障碍增强"><a class="markdownIt-Anchor" href="#无障碍增强"></a> 无障碍增强</h2><p>我几乎是不会考虑「无障碍」的，过去的时候。在阅读了一些博客网站的设计想法时我意识到，实际上用着「不寻常设备」的读者可能比想象中还要多，总是要确保所有的用户都能良好地使用博客功能。当然，不只是博客，未来开发的网站也要想到这一点才行。这次重构中，我添加了一个跳过导航的按钮，它平日会被藏在屏幕视图的上方，需要使用 Tab 才可以将其唤出。Tab 也可以用来快速导航到下一个标题、链接、代码块等。</p><p>我也为正文链接添加了下划线，有用到 <code>text-decoration-skip-ink: auto</code> 这个属性，可以自动跳过字形，例如拉丁字符 <code>g</code>、<code>j</code> 等。</p></body></html>]]></content>
    
    
    <summary type="html">详细记录了一次 Hexo 主题的深度重构，旨在分享如何减少对 JavaScript 的依赖，并回归现代 CSS 与 HTML 的原生能力。文章深入探讨了高级字体优化（CLS 缓解与视觉对齐）、利用 color-mix() 构建动态颜色系统、以及使用内联 SVG 替代字体图标等性能实践，为希望精简技术栈、提升网站性能的开发者提供了宝贵的实战经验。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Hexo" scheme="https://blog.cytrogen.icu/tags/Hexo/"/>
    
    <category term="CSS" scheme="https://blog.cytrogen.icu/tags/CSS/"/>
    
  </entry>
  
  <entry>
    <title>Svg2SvgIcon：将 SVG 转为 Material-UI SvgIcon</title>
    <link href="https://blog.cytrogen.icu/posts/369e.html"/>
    <id>https://blog.cytrogen.icu/posts/369e.html</id>
    <published>2025-08-10T18:23:04.000Z</published>
    <updated>2026-02-09T17:16:55.005Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我有时候会根据自己当前的需求，写一些简单的小工具。现在希望将这些工具背后的思考和成果整理成博客文档，分享给有着同样需求的朋友们。</p><span id="more"></span><h1 id="前言"><a class="markdownIt-Anchor" href="#前言"></a> 前言</h1><p>作为一名常用 Material-UI 的开发者，我经常需要将各种 SVG 图标集成到项目中。虽然 Material-UI 本身提供了丰富的图标库，但很多时候我们还是会遇到需要自定义图标的情况。例如在网站的落地页上加一个大大的 logo，把它设置成五彩斑斓的黑色……</p><p>过去要这么做，得手动封装 SVG、将其转换为 React 组件。这么搞很浪费时间，我因此萌生出将其自动化的想法、写了 <code>Svg2SvgIcon</code>。</p><h1 id="svg2svgicon"><a class="markdownIt-Anchor" href="#svg2svgicon"></a> <code>Svg2SvgIcon</code></h1><p><code>Svg2SvgIcon</code> 是一个纯客户端的在线转换工具，它可以将任意 SVG 代码或文件、快速转换为可以直接在你的 React 项目中使用的 Material-UI <code>SvgIcon</code> 组件。</p><p><a href="https://github.com/Cytrogen/SVG2SvgIcon"><img src="https://gh-card.dev/repos/Cytrogen/SVG2SvgIcon.svg" alt="Cytrogen/SVG2SvgIcon - GitHub" loading="lazy"></a></p><p><a href="%5Bhttps://%5D(https://svg2svgicon.cytrogen.icu/)">点击这里传送</a>。</p><blockquote><p>或者自行复制到浏览器内：</p><pre><code class="language-plaintext">https://svg2svgicon.cytrogen.icu/</code></pre></blockquote><h2 id="核心功能"><a class="markdownIt-Anchor" href="#核心功能"></a> 核心功能</h2><p>该工具的核心设计理念是高效、易用和安全。纯客户端意味着你上传或粘贴的任何 SVG 数据都只会在你的浏览器中进行处理、不会发送到任何服务器，最大限度地保障了你的隐私和数据安全。</p><p>以下是 <code>Svg2SvgIcon</code> 的主要功能：</p><ul><li>智能的 <code>viewBox</code> 解析：<ul><li>自动读取 SVG 中已有的 <code>viewBox</code> 属性</li><li>若 <code>viewBox</code> 不存在，会使用 SVG 的 <code>width</code> 和 <code>height</code> 属性来生成</li><li>若以上全无，则默认使用 <code>0 0 24 24</code>，确保图标能正确显示</li></ul></li><li>实时预览与控制器：<ul><li>在输入或修改 SVG 后，你可以立即在预览窗口中看到转换后的图标效果</li><li>提供实时控制器，方便你精确调整 <code>viewBox</code> 的 <code>min-x</code>、<code>min-y</code>、<code>width</code> 和 <code>height</code> 值，所有调整都会立刻反映在预览图标上</li><li>提供「重置」按钮，一键恢复到原始的 <code>viewBox</code> 值</li></ul></li><li>全面的 SVG 解析能力：<ul><li>支持解析嵌套元素，例如 <code>&lt;g&gt;</code> 标签</li><li>正确处理并转换行内的 <code>style</code> 属性为 React 的 <code>style</code> 对象</li></ul></li><li>内置错误控制台：<ul><li>内置一个可抽拉的错误控制台，当发生解析错误时会自动滑出提示</li><li>右下角的浮动按钮会用红点标记未读错误，方便你随时查看</li></ul></li><li>一键复制<ul><li>自动生成可以直接在项目中使用的 React 组件代码，并提供「一键复制」功能</li></ul></li></ul><h2 id="如何使用"><a class="markdownIt-Anchor" href="#如何使用"></a> 如何使用</h2><p>使用 <code>Svg2SvgIcon</code> 非常简单，只需几步：</p><ol><li>输入 SVG 或者上传一个 <code>.svg</code> 文件</li><li>为即将生成的 React 组件起一个合适的名称</li><li>点击「转换 SVG」按钮，右侧会立刻显示图标预览和生成的代码</li><li>（可选）调整 <code>viewBox</code></li><li>点击「复制代码」按钮，然后将代码粘贴到你的 React 项目中即可使用</li></ol><p><img src="/posts/369e/image.webp" alt="alt text" loading="lazy"></p><h2 id="技术栈与开源"><a class="markdownIt-Anchor" href="#技术栈与开源"></a> 技术栈与开源</h2><p><code>Svg2SvgIcon</code> 的核心技术栈非常精简：</p><ul><li>React</li><li>Material-UI</li><li>DOMParser</li></ul><p>这个项目已在 GitHub 上开源，并采用 MIT 许可证。</p></body></html>]]></content>
    
    
    <summary type="html">分享一个我为解决 Material-UI 项目中 SVG 图标手动封装的痛点而开发的在线工具。Svg2SvgIcon 让你轻松转换、精确裁剪，并保障你的数据隐私。</summary>
    
    
    
    <category term="工具分享" scheme="https://blog.cytrogen.icu/categories/%E5%B7%A5%E5%85%B7%E5%88%86%E4%BA%AB/"/>
    
    
    <category term="JavaScript" scheme="https://blog.cytrogen.icu/tags/JavaScript/"/>
    
    <category term="React.js" scheme="https://blog.cytrogen.icu/tags/React-js/"/>
    
    <category term="Material-UI" scheme="https://blog.cytrogen.icu/tags/Material-UI/"/>
    
  </entry>
  
  <entry>
    <title>Hexo 源代码分析【2】：「generate」的奇幻漂流</title>
    <link href="https://blog.cytrogen.icu/posts/d601.html"/>
    <id>https://blog.cytrogen.icu/posts/d601.html</id>
    <published>2025-07-24T04:00:00.000Z</published>
    <updated>2026-02-09T17:16:54.713Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>使用 Hexo，痛骂 Hexo，理解 Hexo，成为 Hexo。</p><p>这篇文章是用来记录我阅读 Hexo 源代码的过程和分析。</p><span id="more"></span><div class="danger"><p>其实这篇文章去年暑假就在筹备写，但是当时的思维被局限在了线性的代码导览。</p><p>看过 <a href="/posts/5d57.html">上一篇文章</a> 的朋友应该能明显感觉出，一个小小的 <code>index.js</code> 都能 <s>水</s> 写那么多内容，很多还是占篇幅的代码。实际上根本不需要把代码一次又一次贴出来，只要贴出来最核心的几行代码就好了，难道真的会有人去跟着我的文章去一个一个对 Hexo 的源代码吗 2333。重点还得是如何用文字描述内容、让读者更聚焦。</p><p>那么我又为什么没有继续写第二篇了呢？自然不是因为我又鸽了 <s>（当然可能性不是零）</s>，而是我当时计划写 Hexo 的 <code>extend</code> 目录，即扩展（官方文档 <code>/api</code> 路由下就能在左侧边栏看到蓝蓝的 <em>扩展</em> 二字，它包含了控制台、部署器、过滤器等 Hexo 很核心的内容。而这就是问题所在，它并不是一个线性的代码、和第一篇的入口文件 <code>index.js</code> 不一样。<code>extend</code> 目录下的模块那么多，逐一分析过去非常耗时并且容易失去焦点，我那样写又是折磨自己还折磨读者，花费那么多精力根本不讨好。</p><p>问题又来了：我为什么又跑来写这个第二篇，并且在开头加了这么长一个警告块？</p><p>答案很简单，因为我在睡梦中受高人指点。高人曰：「不要做代码的导游，要做故事的讲述者。」</p><p>我顿时恍然大悟，之前那种线性分析方法，就像是拿着一本字典，一页一页地给读者讲定义、枯燥且乏味。而一个优秀的技术分享，应该像一部引人入胜的侦探小说、有一条清晰的主线。巴拉巴拉，这个这个，那个那个。开玩笑的。</p><p>所以这篇文章的风格将会和上一篇不同。我们不再按部就班地解刨 <code>extend</code> 目录下的每一个文件，而是会以一个核心的用户行为为线索，将这些分散的扩展模块串联起来，讲述一个它们如何协同工作的完整故事。这意味着本文会更侧重于流程、数据流和模块间的交互，而不是孤立地分析某个函数的实现。</p><blockquote><p>实际上写完后感觉风格没变多少，晕。</p></blockquote></div><p>在 <a href="/posts/5d57.html">上一篇文章</a> 中，我们了解了 Hexo 源代码中的入口文件，并且在没有讲太多细节的情况下过了一遍 Hexo 运行的流程：</p><pre><code class="language-js">class Hexo extends events_1.EventEmitter {  constructor(base = process.cwd(), args = {}) { ... }  _bindLocals() { ... }  init() { ... }  call(name, args, callback) { ... }  model(name, schema) { ... }  resolvePlugin(name, basedir) { ... }  loadPlugin(path, callback) { ... }  _showDrafts() { ... }  load(callback) { ... }  watch(callback) { ... }  unwatch() { ... }  _generateLocals() { ... }  _runGenerators() { ... }  _routerRefresh(runningGenerators, useCache) { ... }  _generate(options = {}) { ... }  exit(err) { ... }  execFilter(type, data, options) { ... }  execFilterSync(type, data, options) { ... }}</code></pre><p>简单来说是：</p><ol><li>初始化了各种目录路径、设置环境变量、初始化各种扩展，设置配置、日志、渲染器、路由等。</li><li><code>_bindLocals</code> 方法将数据库中的数据绑定到 <code>locals</code> 对象上。</li><li><code>init</code> 方法初始化 <code>Hexo</code>，加载插件和配置。</li><li><code>call</code> 方法调用控制台命令。</li><li><code>model</code> 方法创建或获取数据库模型。</li><li><code>resolvePlugin</code> 和 <code>loadPlugin</code> 方法用于解析和加载插件。</li><li><code>load</code> 和 <code>watch</code> 方法加载数据并处理源文件，<code>watch</code> 方法还会设置文件监听。</li><li><code>_generate</code> 方法生成静态文件。</li><li><code>exit</code> 方法退出程序，执行清理工作。</li></ol><p>但一个静态的类如何响应我们的命令，并将一堆散乱的 Markdown 文件变成一个精美的网站的呢？</p><p>熟悉 Hexo 的朋友都知道，我们最常用的命令之一 —— <code>hexo generate</code> —— 就是用来做这个的，而这篇文章要剥下 <code>hexo generate</code> 的皮，看看 Hexo 的核心是如何运作的。</p><h1 id="1-解析命令"><a class="markdownIt-Anchor" href="#1-解析命令"></a> 1. 解析命令</h1><p>无奖竞猜：当我们在终端敲下 <code>hexo generate</code> 时，Hexo 中第一个被激活的部件是什么？</p><p>答案是 <code>Console</code> 扩展。</p><p>我们可以把它想象成 Hexo 的「总机」或者「前台」。它的核心职责就是：接收你输入的命令，然后把它转接给正确的内部处理函数。这个过程分为两步：<strong>注册</strong> 和 <strong>调用</strong></p><p>一个命令能被调用，前提是它得先被「注册在案」。这个注册过程发生在 Hexo 的初始化阶段，也就是 <code>hexo.init()</code> 方法中。记性很好的朋友应该可以瞬间想起这行关键代码：</p><pre><code class="language-javascript">require('../plugins/console')(this);</code></pre><p>这行代码会加载 Hexo 内置的所有控制台命令。对于 <code>generate</code> 命令，它会执行 <code>/plugins/console/index.js</code> 文件中的代码，该文件负责注册包括 <code>generate</code> 在内的多个核心命令。我们来看 <code>generate</code> 的注册部分：</p><pre><code class="language-javascript">console.register('generate', 'Generate static files.', {  options: [    { name: '-d, --deploy', desc: 'Deploy after generated' },    { name: '-f, --force', desc: 'Force regenerate' },    { name: '-w, --watch', desc: 'Watch file changes' },    { name: '-b, --bail', desc: 'Raise an error if any unhandled exception is thrown during generation' },    { name: '-c, --concurrency', desc: 'Maximum number of files to be generated in parallel. Default is infinity' }  ]}, require('./generate'));</code></pre><p><code>register</code> 方法在这里接收了四个参数：</p><ol><li><p><code>name</code>：命令名称</p></li><li><p><code>desc</code>：命令描述</p></li><li><p><code>options</code>：定义了所有 <code>hexo g</code> 支持的命令行参数，比如我们 <code>-d</code>（生成完成后部署）和 <code>-w</code>（监视文件变动）</p></li><li><p><code>fn</code>：命令的执行函数。这里通过 <code>require('./generate')</code> 加载了同目录下的 <code>generate.js</code> 文件，该文件导出的 <code>generateConsole</code> 函数就是 <code>generate</code> 命令的真正入口：</p> <pre><code class="language-javascript">function generateConsole(args = {}) {  const generator = new Generater(this, args);  // 这个类之后会提起  if (generator.watch) {    return generator.execWatch();  }  return this.load().then(() =&gt; generator.firstGenerate()).then(() =&gt; {    if (generator.deploy) {      return generator.execDeploy();    }  });}module.exports = generateConsole;</code></pre></li></ol><p>这样一来，<code>generate</code> 命令、它的描述、它的所有参数，以及它的执行函数，就通过这几行代码被清晰地关联起来，并存放在 <code>hexo.extend.console</code> 这个登记簿内。</p><p>注册完成后，当 <code>hexo-cli</code> 工具解析到你的 <code>generate</code> 命令时，它就会调用我们在 <code>Hexo</code> 类中看到的方法：<code>hexo.call('generate', args)</code>。</p><blockquote><p>也就是这一段：</p><pre><code class="language-javascript">call(name, args, callback) {  if (!callback &amp;&amp; typeof args === 'function') {    callback = args;    args = {};  }  const c = this.extend.console.get(name);  // 1. 从登记簿里查找命令  if (c)    return Reflect.apply(c, this, [args]).asCallback(callback); // 2. 执行找到的函数  return bluebird_1.default.reject(new Error(`Console \`${name}\` has not been registered yet!`));}</code></pre></blockquote><p>就这样，通过注册和调用这两步简单的操作，Hexo 的 <code>Console</code> 扩展干净利落地完成了它的使命…… 可喜可贺、可喜可贺。</p><p>现在 <code>generateConsole</code> 函数接过了指挥棒，而它要做的第一件事，就是调用 <code>this.load()</code>。</p><h1 id="2-原材料加工"><a class="markdownIt-Anchor" href="#2-原材料加工"></a> 2. 原材料加工</h1><p>我们来看 <code>this.load</code> 方法的核心：</p><pre><code class="language-javascript">load(callback) {  return (0, load_database_1.default)(this).then(() =&gt; {  // 确保数据库已加载    this.log.info('Start processing');    return bluebird_1.default.all([      this.source.process(),  // 我们的主角      this.theme.process()    ]);  }).then(() =&gt; {    mergeCtxThemeConfig(this);    return this._generate({ cache: false });  }).asCallback(callback);}</code></pre><p><code>this.load()</code> 的任务很明确：将 <code>source</code> 文件夹里所有零散的文件，加工成结构化、可供后续使用的内存数据。</p><p><code>this.source.process()</code> 是故事的起点。那么 <code>this.source</code> 是什么？它的 <code>process()</code> 方法又是什么？</p><h2 id="21-box-类"><a class="markdownIt-Anchor" href="#21-box-类"></a> 2.1. <code>Box</code> 类</h2><p>在 <code>Hexo</code> 类的结构函数中，<code>this.source</code> 被实例化：</p><pre><code class="language-javascript">const source_1 = __importDefault(require("./source"));this.source = new source_1.default(this);</code></pre><p>而 <code>Source</code> 类的定义出奇地简单：</p><pre><code class="language-javascript">"use strict";var __importDefault = (this &amp;&amp; this.__importDefault) || function (mod) {  return (mod &amp;&amp; mod.__esModule) ? mod : { "default": mod };};const box_1 = __importDefault(require("../box"));class Source extends box_1.default {  constructor(ctx) {    super(ctx, ctx.source_dir);    this.processors = ctx.extend.processor.list();  }}module.exports = Source;//# sourceMappingURL=source.js.map</code></pre><p>原因也很简单：<code>Source</code> 类继承自 <code>Box</code> 类。记性很好的朋友此时就要一拍脑袋了：<a href="/posts/5d57#%E6%BA%90%E6%96%87%E4%BB%B6%E7%AE%A1%E7%90%86">上一篇文章</a> 提到过。</p><p>当我们调用 <code>this.source.process()</code> 时，我们实际上是在调用 <code>Box</code> 类中定义的 <code>process</code> 方法：</p><pre><code class="language-javascript">process(callback) {  const { base, Cache, context: ctx } = this;  return (0, hexo_fs_1.stat)(base).then(stats =&gt; {    if (!stats.isDirectory())      return;    // Check existing files in cache    const relativeBase = escapeBackslash(base.substring(ctx.base_dir.length));    const cacheFiles = Cache.filter(item =&gt; item._id.startsWith(relativeBase)).map(item =&gt; item._id.substring(relativeBase.length));    // Handle deleted files    return this._readDir(base)      .then((files) =&gt; cacheFiles.filter((path) =&gt; !files.includes(path)))      .map((path) =&gt; this._processFile(file_1.default.TYPE_DELETE, path));  }).catch(err =&gt; {    if (err &amp;&amp; err.code !== 'ENOENT')      throw err;  }).asCallback(callback);}</code></pre><p><code>Box</code> 类是 Hexo 通用的文件处理引擎。它的 <code>process</code> 方法负责扫描指定目录（这里的话扫描的是 <code>source/</code>）、与缓存对比、找出被删除/新增/修改的文件，然后为每个文件调用 <code>_processFile</code> 方法：</p><pre><code class="language-javascript">_processFile(type, path) {  if (this._processingFiles[path]) {    return bluebird_1.default.resolve();  }  this._processingFiles[path] = true;  const { base, File, context: ctx } = this;  this.emit('processBefore', {    type,    path  });  return bluebird_1.default.reduce(this.processors, (count, processor) =&gt; {    const params = processor.pattern.match(path);    if (!params)      return count;    const file = new File({      // source is used for filesystem path, keep backslashes on Windows      source: (0, path_1.join)(base, path),      // path is used for URL path, replace backslashes on Windows      path: escapeBackslash(path),      params,      type    });    return Reflect.apply(bluebird_1.default.method(processor.process), ctx, [file])      .thenReturn(count + 1);  }, 0).then(count =&gt; {    if (count) {      ctx.log.debug('Processed: %s', (0, picocolors_1.magenta)(path));    }    this.emit('processAfter', {      type,      path    });  }).catch(err =&gt; {    ctx.log.error({ err }, 'Process failed: %s', (0, picocolors_1.magenta)(path));  }).finally(() =&gt; {    this._processingFiles[path] = false;  }).thenReturn(path);}</code></pre><p><code>_processFile</code> 则是处理单个文件的核心，它会遍历一个名为 <code>this.processors</code> 的数组，用数组中的每个 <code>processor</code> 的 <code>pattern</code> 与文件路径进行匹配。如果匹配成功，就执行该 <code>processor</code> 的 <code>process</code> 方法。</p><p>那么，<code>this.processors</code> 这个关键的数组是从哪里来的呢？这引出了 <code>Processor</code> 的注册机制。</p><h2 id="22-processor-扩展"><a class="markdownIt-Anchor" href="#22-processor-扩展"></a> 2.2. <code>Processor</code> 扩展</h2><p><code>Processor</code> 扩展遵循一个清晰的注册与加载流程。</p><p>首先是注册，在 <code>hexo.init()</code> 阶段，Hexo 会加载 <code>/plugins/processor/index.js</code> 文件，该文件负责注册所有内置的 <code>Processor</code>：</p><pre><code class="language-javascript">"use strict";module.exports = (ctx) =&gt; {  // 1. 从 Hexo 上下文中获取 processor 扩展的注册器实例  const { processor } = ctx.extend;  // 2. 定义一个内部的 register 辅助函数  function register(name) {    // 2.1. 加载指定 processor 的定义文件    const obj = require(`./${name}`)(ctx);    // 2.2. 调用注册器实例的 register 方法    // 将 processor 的 pattern 和 process 函数正式注册到 Hexo 的扩展管理器中    processor.register(obj.pattern, obj.process);  }  // 3. 为每一个内置的 processor 调用 register 函数  register('asset');  // 静态资源处理器  register('data');   // _data 目录处理器  register('post');   // 文章处理器};//# sourceMappingURL=index.js.map</code></pre><p>接着是加载。当 <code>new source_1.default(this)</code> 执行时，<code>Source</code> 类的构造函数会从 <code>Processor</code> 扩展的注册器中，获取所有已注册的 <code>Processor</code> 列表，并赋值给自身的 <code>this.processors</code> 属性。</p><pre><code class="language-javascript">class Source extends box_1.default {  constructor(ctx) {    super(ctx, ctx.source_dir);    // 从 ctx.extend.processor.list() 获取完整的 processor 列表    this.processors = ctx.extend.processor.list();  }}</code></pre><p>至此，调用链完全闭合：</p><ol><li><code>init</code> 阶段，<code>/plugins/processor/index.js</code> 将 <code>post</code> 等处理器注册到 <code>hexo.extend.processor</code>。</li><li><code>Source</code> 实例将 <code>hexo.extend.processor</code> 的完整列表复制到自身的 <code>this.processors</code> 数组中。</li><li><code>source.process()</code> 调用 <code>_processFile</code>，<code>_processFile</code> 遍历 <code>this.processors</code> 数组，从而找到了 <code>post</code> 处理器来处理匹配的文件。</li></ol><h2 id="23-post-处理器"><a class="markdownIt-Anchor" href="#23-post-处理器"></a> 2.3. <code>post</code> 处理器</h2><p>现在我们以 <code>_posts/hello-world.md</code> 为例，看看 <code>post</code> 处理器是如何工作的。</p><h4 id="231-资格审查"><a class="markdownIt-Anchor" href="#231-资格审查"></a> 2.3.1. 资格审查</h4><p>当 <code>hello-world.md</code> 开始要被 <code>Box</code> 引擎处理时，它首先会遇到 <code>post</code> 的资格审查。</p><p><code>post</code> 会通过其 <code>pattern</code> 函数来决定是否处理一个文件。这个函数非常智能，它不仅仅是匹配路径，更是进行了一系列的检查：</p><pre><code class="language-javascript">module.exports = (ctx) =&gt; {  return {    pattern: new hexo_util_1.Pattern(path =&gt; {      // 1. 临时的文件直接拒绝      if ((0, common_1.isTmpFile)(path))        return;      // 2. 文件必须来自 _posts/ 或者 /_drafts 目录      let result;      if (path.startsWith(postDir)) {        result = {          published: true,          path: path.substring(postDir.length)        };      }      else if (path.startsWith(draftDir)) {        result = {          published: false,          path: path.substring(draftDir.length)        };      }      // 3. 隐藏的文件直接拒绝      if (!result || (0, common_1.isHiddenFile)(result.path))        return;      // 4. 判断其可渲染性（ctx.render 会在下一章提起）      result.renderable = ctx.render.isRenderable(path) &amp;&amp; !(0, common_1.isMatch)(path, ctx.config.skip_render);      // 5. 处理文章资源文件夹      // 如果开启了 post_asset_folder，那么只有和默认文章扩展名相同的文件才被认为是可渲染的文章      if (result.renderable &amp;&amp; ctx.config.post_asset_folder) {        result.renderable = ((0, path_1.extname)(ctx.config.new_post_name) === (0, path_1.extname)(path));      }      return result;    }),  };};</code></pre><p>这个函数返回的 <code>result</code> 对象，会被 <code>Box</code> 附加到 <code>File</code> 实例的 <code>params</code> 属性上，供 <code>process</code> 函数使用。</p><h4 id="232-分流与处理"><a class="markdownIt-Anchor" href="#232-分流与处理"></a> 2.3.2. 分流与处理</h4><p><code>post</code> 处理器的 <code>process</code> 函数会读取 <code>file.params.renderable</code> 的值，决定下一步操作：</p><pre><code class="language-javascript">module.exports = (ctx) =&gt; {  return {    process: function postProcessor(file) {      // 如果可渲染，就作为文章处理      if (file.params.renderable) {        return processPost(ctx, file);      }      // 否则，如果开启了 post_asset_folder，则作为文章的静态资源处理      else if (ctx.config.post_asset_folder) {        return processAsset(ctx, file);      }    }  }}</code></pre><h4 id="233-精加工与入库"><a class="markdownIt-Anchor" href="#233-精加工与入库"></a> 2.3.3. 精加工与入库</h4><p>当 <code>process</code> 函数决定一个文件是 <strong>可渲染的</strong> 文章时，它就会把 <code>file</code> 对象交给 <code>processPost</code> 函数。这个函数使整个 <code>Processor</code> 中最复杂的部分，它的任务是 <strong>读取文件、解析并融合所有元数据，最后将结构化的文章数据存入数据库</strong>。</p><p>整个过程可以分解为以下几个关键步骤：</p><ol><li><p>准备与前置处理</p><p>函数首先会进行一些准备工作，并处理几种简单的文件状态。</p> <pre><code class="language-javascript">function processPost(ctx, file) {  const Post = ctx.model('Post');  const { path } = file.params;  const doc = Post.findOne({ source: file.path });  // 1. 检查数据中是否已存在该文章  const { config } = ctx;  const { timezone: timezoneCfg, updated_option, use_slug_as_post_title } = config;  let categories, tags;  // 2. 根据文件类型进行处理  if (file.type === 'skip' &amp;&amp; doc) {    return; // 文件未修改，直接跳过  }  if (file.type === 'delete') {    if (doc) {      return doc.remove();  // 文件已删除，从数据库移除    }    return;  }</code></pre></li><li><p>异步读取与初步解析</p><p>对于 <code>create</code> 或 <code>update</code> 状态的文件，处理正式开始。Hexo 会并行地执行两个异步操作：读取文件内容和获取文件系统状态。</p> <pre><code class="language-javascript">return bluebird_1.default.all([  file.stat(),  // 获取文件系统信息，例如创建、修改时间  file.read()   // 读取文件内容]).spread((stats, content) =&gt; {  // 1. 解析 Front-matter  const data = (0, hexo_front_matter_1.parse)(content);  // 2. 解析文件名  const info = parseFilename(config.new_post_name, path);</code></pre><p><code>hexo_front_matter_1.parse(content)</code> 会将文件头部的 YAML Front-matter（<code>---</code> 开头）解析成一个 JavaScript 对象 <code>data</code>。文件的正文内容会存放在 <code>data._content</code> 属性中：</p> <pre><code class="language-javascript">function parse(str, options) {  if (typeof str !== 'string')    throw new TypeError('str is required!');  const splitData = split(str);  const raw = splitData.data;  if (!raw)    return { _content: str };  let data;  if (splitData.separator.startsWith(';')) {    data = parseJSON(raw);  }  else {    data = parseYAML(raw, options);  }  if (!data)    return { _content: str };  // Convert timezone  Object.keys(data).forEach(key =&gt; {    const item = data[key];    if (item instanceof Date) {      data[key] = new Date(item.getTime() + (item.getTimezoneOffset() * 60 * 1000));    }  });  data._content = splitData.content;  return data;}exports.parse = parse;</code></pre><p><code>parseFilename</code> 函数则会根据我们在 <code>_config.yml</code> 中配置的 <code>new_post_name</code> 格式，从文件名中尝试提取 <code>year</code>、<code>month</code>、<code>day</code>、<code>title</code> 等信息，存放在 <code>info</code> 对象中：</p> <pre><code class="language-javascript">function parseFilename(config, path) {  config = config.substring(0, config.length - (0, path_1.extname)(config).length);  path = path.substring(0, path.length - (0, path_1.extname)(path).length);  if (!permalink || permalink.rule !== config) {    permalink = new hexo_util_1.Permalink(config, {      segments: {        year: /(\d{4})/,        month: /(\d{2})/,        day: /(\d{2})/,        i_month: /(\d{1,2})/,        i_day: /(\d{1,2})/,        hash: /([0-9a-f]{12})/      }    });  }  const data = permalink.parse(path);  if (data) {    if (data.title !== undefined) {      return data;    }    return Object.assign(data, {      title: (0, hexo_util_1.slugize)(path)    });  }  return {    title: (0, hexo_util_1.slugize)(path)  };}    </code></pre></li><li><p>数据融合与标准化</p><p>这是 <code>processPost</code> 最核心的部分。它会将上一步得到的 <code>data</code> 和 <code>info</code>，以及 <code>stats</code> 这三个来源的数据进行智能融合，并进行标准化处理，最终形成一篇完整、规范的文章数据。</p><p>这个融合过程遵循明确的优先级：<strong>Front-matter &gt; 文件名 &gt; 文件系统信息</strong>。</p><p>元数据确定逻辑：</p><ul><li><code>slug</code> 和 <code>source</code>：直接从文件名解析结果或文件路径中获取</li><li><code>title</code>：优先使用 Front-matter 中的 <code>title</code>。如果没有，并且 <code>use_slug_as_post_title</code> 配置为 <code>true</code>，则会使用从文件名中解析出的 <code>slug</code> 作为标题</li><li><code>date</code>：<ol><li>优先使用 Front-matter 中的 <code>date</code></li><li>其次尝试从文件名中解析（<code>info.year</code> 等）</li><li>最后使用文件的创建时间 <code>stats.birthtime</code></li></ol></li><li><code>updated</code>：<ol><li>优先使用 Front-matter 里的</li><li>其次根据 <code>_config.yml</code> 的 <code>updated_options</code> 配置，可能使用 <code>date</code> 的值或者留空</li><li>最后默认使用文件的修改时间 <code>stats.mtime</code></li></ol></li><li><code>tags</code> 和 <code>categories</code>：函数会进行标准化处理，确保它们最终都是数组格式，并处理了 <code>tag</code>（单数）-&gt; <code>tags</code>（复数）这种别名情况</li></ul> <pre><code class="language-javascript">const keys = Object.keys(info);data.source = file.path;data.raw = content;data.slug = info.title;if (file.params.published) {  if (!Object.prototype.hasOwnProperty.call(data, 'published'))    data.published = true;}else {  data.published = false;}for (let i = 0, len = keys.length; i &lt; len; i++) {  const key = keys[i];  if (!preservedKeys[key])    data[key] = info[key];}// use `slug` as `title` of post when `title` is not specified.// https://github.com/hexojs/hexo/issues/5372if (use_slug_as_post_title &amp;&amp; !('title' in data)) {  data.title = info.title;}if (data.date) {  data.date = (0, common_1.toDate)(data.date);}else if (info &amp;&amp; info.year &amp;&amp; (info.month || info.i_month) &amp;&amp; (info.day || info.i_day)) {  data.date = new Date(info.year, parseInt(info.month || info.i_month, 10) - 1, parseInt(info.day || info.i_day, 10));}if (data.date) {  if (timezoneCfg)    data.date = (0, common_1.timezone)(data.date, timezoneCfg);}else {  data.date = stats.birthtime;}data.updated = (0, common_1.toDate)(data.updated);if (data.updated) {  if (timezoneCfg)    data.updated = (0, common_1.timezone)(data.updated, timezoneCfg);}else if (updated_option === 'date') {  data.updated = data.date;}else if (updated_option === 'empty') {  data.updated = undefined;}else {  data.updated = stats.mtime;}if (data.category &amp;&amp; !data.categories) {  data.categories = data.category;  data.category = undefined;}if (data.tag &amp;&amp; !data.tags) {  data.tags = data.tag;  data.tag = undefined;}categories = data.categories || [];tags = data.tags || [];if (!Array.isArray(categories))  categories = [categories];if (!Array.isArray(tags))  tags = [tags];if (data.photo &amp;&amp; !data.photos) {  data.photos = data.photo;  data.photo = undefined;}if (data.photos &amp;&amp; !Array.isArray(data.photos)) {  data.photos = [data.photos];}if (data.permalink) {  data.__permalink = data.permalink;  data.permalink = undefined;}</code></pre></li><li><p>数据库持久化</p><p>当所有数据都准备就绪后，便进入了最终的数据库操作阶段。</p> <pre><code class="language-javascript">  if (doc) {  // 如果在步骤一中找到了记录    if (file.type !== 'update') {      ctx.log.warn(`Trying to "create" ${(0, picocolors_1.magenta)(file.path)}, but the file already exists!`);    }    // 文件已存在，执行更新操作    return doc.replace(data);  }  // 文件是新增的，执行插入操作  return Post.insert(data);})</code></pre></li><li><p>建立关联</p><p>数据入库后，工作还没有完全结束。</p><p><code>insert/replace</code> 操作会返回一个 Promise，其结果是处理后的数据库文档 <code>doc</code>。接下来的 <code>.then()</code> 中，Hexo 会完成最后一步：建立模型之间的关联。</p> <pre><code class="language-javascript">.then(doc =&gt; bluebird_1.default.all([    doc.setCategories(categories),  // 将文章与分类模型关联    doc.setTags(tags),              // 将文章与标签模型关联    scanAssetDir(ctx, doc)          // 如果开启，处理文章的资源文件夹  ]));}</code></pre><p><code>doc.setCategories</code> 和 <code>doc.setTags</code> 方法会处理 <code>categories</code> 和 <code>tags</code> 数组，在 <code>Category</code>、<code>Tag</code> 以及中间关联表中创建或更新记录。这使得我们之后可以轻松地通过 <code>post.tags</code> 或 <code>category.posts</code> 来查询关联数据。</p></li></ol><p>至此，<code>processPost</code> 的全部工作完成。一篇原始的 Markdown 文件，经过这一系列精密的加工，已经变成了一条结构完整、关系清晰的数据库记录。</p><h1 id="3-从-markdown-到-html"><a class="markdownIt-Anchor" href="#3-从-markdown-到-html"></a> 3. 从 Markdown 到 HTML</h1><p>上一章，我们看到 <code>post</code> 处理器将 Markdown 源文件加工成了包含 <code>_content</code>（原始 Markdown 文本）的数据库记录。但此时，文章的 <code>content</code> 属性仍然是空的。从 <code>_content</code> 到 <code>content</code>（渲染后的 HTML），是整个生成过程中最关键的「炼金」步骤。</p><p>这个转换不是在 <code>source.process()</code> 阶段发生的，而是在稍后的一个特殊时机，由 <code>Filter</code> 机制驱动。</p><h2 id="31-before_generate-过滤器"><a class="markdownIt-Anchor" href="#31-before_generate-过滤器"></a> 3.1. <code>before_generate</code> 过滤器</h2><p>在 <code>_generate</code> 方法的核心逻辑中，<code>_runGenerators</code> 执行之前，有一个关键的前置步骤：</p><pre><code class="language-javascript">_generate(options = {}) {  if (this._isGenerating)    return;  const useCache = options.cache;  this._isGenerating = true;  this.emit('generateBefore');  return this.execFilter('before_generate', null, { context: this })  // 在这里    .then(() =&gt; this._routerRefresh(this._runGenerators(), useCache)).then(() =&gt; {    this.emit('generateAfter');    return this.execFilter('after_generate', null, { context: this });  }).finally(() =&gt; {    this._isGenerating = false;  });}</code></pre><p><code>execFilter</code> 方法会执行所有注册在 <code>before_generate</code> 这个钩子上的函数。Hexo 默认在这里注册了一个名为 <code>renderPostFilter</code> 的过滤器，它的任务就是：确保所有文章在生成页面蓝图之前，都已经被渲染成 HTML。</p><p>这个过滤器的注册和定义如下：</p><pre><code class="language-javascript">"use strict";module.exports = (ctx) =&gt; {  const { filter } = ctx.extend;  // 注册 render_post.js 到 before_generate 钩子  filter.register('before_generate', require('./render_post'));};//# sourceMappingURL=index.js.map</code></pre><pre><code class="language-javascript">"use strict";var __importDefault = (this &amp;&amp; this.__importDefault) || function (mod) {  return (mod &amp;&amp; mod.__esModule) ? mod : { "default": mod };};const bluebird_1 = __importDefault(require("bluebird"));function renderPostFilter() {  // 定义一个处理指定模型的函数  const renderPosts = model =&gt; {    // 1. 找出所有 content 属性为 null 的文章/页面    const posts = model.toArray().filter(post =&gt; post.content == null);    // 2. 遍历这些未渲染的条目    return bluebird_1.default.map(posts, (post) =&gt; {      // 2.1. 将原始 Markdown 内容赋值给 content      post.content = post._content;      // 2.2. 调用核心的渲染方法      return this.post.render(post.full_source, post).then(() =&gt; post.save());    });  };  // 并行处理 Post 和 Page 两个模型  return bluebird_1.default.all([    renderPosts(this.model('Post')),    renderPosts(this.model('Page'))  ]);}module.exports = renderPostFilter;//# sourceMappingURL=render_post.js.map</code></pre><h2 id="32-postrender"><a class="markdownIt-Anchor" href="#32-postrender"></a> 3.2. <code>post.render</code></h2><p><code>this.post.render</code> 是整个内容转换过程的核心。它确保了 Markdown 在转换为 HTML 的过程中，内嵌的特殊标签（例如 Swig 模版标签）不会被破坏，并且能被正确地执行。</p><p>那么 <code>this.post.render</code> 从哪里来的？回到 Hexo 实例：</p><pre><code class="language-javascript">const post_1 = __importDefault(require("./post"));this.post = new post_1.default(this);</code></pre><p>我们再来深入 <code>Post</code> 类的 <code>render</code> 方法：</p><pre><code class="language-javascript">render(source, data = {}, callback) {  const ctx = this.context;  const { config } = ctx;  const { tag } = ctx.extend;  // 文件读取和非文章类型文件的处理逻辑  const ext = data.engine || (source ? (0, path_1.extname)(source) : '');  let promise;  if (data.content != null) {    promise = bluebird_1.default.resolve(data.content);  }  else if (source) {    promise = (0, hexo_fs_1.readFile)(source);  }  else {    return bluebird_1.default.reject(new Error('No input file or string!')).asCallback(callback);  }  const isPost = !data.source || ['html', 'htm'].includes(ctx.render.getOutput(data.source));  if (!isPost) {    return promise.then(content =&gt; {      data.content = content;      ctx.log.debug('Rendering file: %s', (0, picocolors_1.magenta)(source));      return ctx.render.render({        text: data.content,        path: source,        engine: data.engine,        toString: true      });    }).then(content =&gt; {      data.content = content;      return data;    }).asCallback(callback);  }  let disableNunjucks = ext &amp;&amp; ctx.render.renderer.get(ext) &amp;&amp; !!ctx.render.renderer.get(ext).disableNunjucks;  if (typeof data.disableNunjucks === 'boolean')    disableNunjucks = data.disableNunjucks;  const cacheObj = new PostRenderEscape();  // 1. 创建转义工具实例  return promise.then(content =&gt; {  // promise 在之前已读取文件内容    data.content = content;    // 2. 执行 before_post_render 过滤器    return ctx.execFilter('before_post_render', data, { context: ctx });  }).then(() =&gt; {    // 3. 转义代码和 Swig 标签    data.content = cacheObj.escapeCodeBlocks(data.content);    if (disableNunjucks === false) {      data.content = cacheObj.escapeAllSwigTags(data.content);    }    const options = data.markdown || {};    if (!config.syntax_highlighter)      options.highlight = null;    ctx.log.debug('Rendering post: %s', (0, picocolors_1.magenta)(source));    // 4. 调用核心渲染器    return ctx.render.render({      text: data.content,      path: source,      engine: data.engine,      toString: true,      onRenderEnd(content) {  // 5. 回调        // 5.1. 恢复 Swig 标签        data.content = cacheObj.restoreAllSwigTags(content);        if (disableNunjucks)          return data.content;        // 5.2. 执行 Swig 标签        return tag.render(data.content, data);      }    }, options);  }).then(content =&gt; {    // 6. 恢复代码块    data.content = cacheObj.restoreCodeBlocks(content);    // 7. 执行 after_post_render 过滤器    return ctx.execFilter('after_post_render', data, { context: ctx });  }).asCallback(callback);}</code></pre><p>这个过程可以分解为七个步骤：</p><ol><li>实例化 <code>PostRenderEscape</code> 对象，专门用来「保护」和「恢复」特殊标签</li><li>执行一轮 <code>before_post_render</code> 过滤器，允许插件对原始 Markdown 内容进行修改</li><li>保护性转义<ul><li><code>escapeCodeBlocks</code> 和 <code>escapeAllSwigTags</code> 方法会用正则表达式查找所有的代码块和 Nunjucks / Swig 标签（例如 <code>{% post_link %}</code> 或 <code>{{ post.title }}</code>）</li><li>它会将这些找出的内容从字符串中「挖」出来，存入 <code>cacheObj.stored</code> 数组，然后在原文中留下一个无害的占位符</li><li>这么做的理由是为了让下一步的 Markdown 渲染器知道，这一块是 Nunjucks 语法，不要把它当做普通文本并转义</li></ul></li><li>调用 <code>ctx.render.render()</code>。它会根据文件扩展名（<code>.md</code>）找到对应的渲染器插件，然后调用其 <code>render</code> 方法，将已经被保护起来的 Markdown 文本转换成 HTML。此时生成的 HTML 中依然包含着占位符</li><li>Markdown 渲染器完成工作后，<code>onRenderEnd</code> 回调函数会立刻执行，开始逆向工程<ul><li><code>restoreAllSwigTags</code> 方法被调用。它会查找 HTML 中的所有占位符，并用之前存储在 <code>cacheObj.stored</code> 数组中的原始标签替换它们。现在我们得到了一个混合了 HTML 和 Nunjucks 标签的字符串</li><li><code>tag.render()</code> 被调用、用于处理这个混合字符串，执行其中的 <code>{&amp; post_link &amp;}</code> 等标签，并将其替换为最终的 HTML 片段</li></ul></li><li>经过 Nunjucks 渲染后，<code>restoreCodeBlocks</code> 被调用，以同样的方式将代码块占位符恢复成原始的代码块 HTML</li><li>所有渲染和模版执行都已完成。这最后一轮 <code>after_post_render</code> 过滤器让插件有机会对最终生成的 HTML 内容进行处理，例如添加 <code>target="_blank"</code>、图片懒加载等</li></ol><h2 id="33-render-类"><a class="markdownIt-Anchor" href="#33-render-类"></a> 3.3. <code>Render</code> 类</h2><p><code>ctx.render</code> 是 <code>Render</code> 类的一个实例，它扮演着渲染任务「总调度员」的角色。它不关心具体如何渲染，只负责找到正确的渲染器并把任务交给它。</p><pre><code class="language-javascript">class Render {  render(data, options, callback) {    // 参数处理和文件读取    if (!callback &amp;&amp; typeof options === 'function') {      callback = options;      options = {};    }    const ctx = this.context;    let ext = '';    let promise;    if (!data)      return bluebird_1.default.reject(new TypeError('No input file or string!'));    if (data.text != null) {      promise = bluebird_1.default.resolve(data.text);    }    else if (!data.path) {      return bluebird_1.default.reject(new TypeError('No input file or string!'));    }    else {      promise = (0, hexo_fs_1.readFile)(data.path);    }    return promise.then(text =&gt; {      data.text = text;      // 1. 获取文件扩展名      ext = data.engine || getExtname(data.path);      if (!ext || !this.isRenderable(ext))        return text;      // 2. 根据扩展名查找对应的渲染器      const renderer = this.getRenderer(ext);      // 3. 执行渲染器      return Reflect.apply(renderer, ctx, [data, options]);    }).then(result =&gt; {      result = toString(result, data);      // 4. 检查并执行 onRenderEnd 回调      if (data.onRenderEnd) {        return data.onRenderEnd(result);      }      return result;    }).then(result =&gt; {      // 5. 执行 after_render 过滤器      const output = this.getOutput(ext) || ext;      return ctx.execFilter(`after_render:${output}`, result, {        context: ctx,        args: [data]      });    }).asCallback(callback);  }}module.exports = Render;//# sourceMappingURL=render.js.map</code></pre><p>也就是说，核心渲染是由具体的渲染器插件完成的。</p><h4 id="331-hexo-renderer-marked"><a class="markdownIt-Anchor" href="#331-hexo-renderer-marked"></a> 3.3.1. <code>hexo-renderer-marked</code></h4><p><code>hexo-renderer-marked</code> 是 Hexo 默认的 Markdown 渲染器，也是 <code>Renderer</code> 类调度的完美范例。它本身不是一个简单的函数，而是一个集配置、扩展和定制于一体的小系统。</p><p><a href="https://github.com/hexojs/hexo-renderer-marked"><img src="https://gh-card.dev/repos/hexojs/hexo-renderer-marked.svg" alt="hexojs/hexo-renderer-marked - GitHub" loading="lazy"></a></p><pre><code class="language-javascript">module.exports = function(data, options) {  const { post_asset_folder, marked: markedCfg, source_dir } = this.config;  const { prependRoot, postAsset, dompurify } = markedCfg;  const { path, text } = data;  marked.defaults.extensions = null;  marked.defaults.tokenizer = null;  marked.defaults.renderer = null;  marked.defaults.hooks = null;  marked.defaults.walkTokens = null;  // exec filter to extend marked  this.execFilterSync('marked:use', marked.use, { context: this });  // exec filter to extend renderer  this.execFilterSync('marked:renderer', renderer, { context: this });  // exec filter to extend tokenizer  this.execFilterSync('marked:tokenizer', tokenizer, { context: this });  const extensions = [];  this.execFilterSync('marked:extensions', extensions, { context: this });  marked.use({ extensions });  let postPath = '';  if (path &amp;&amp; post_asset_folder &amp;&amp; prependRoot &amp;&amp; postAsset) {    const Post = this.model('Post');    // Windows compatibility, Post.findOne() requires forward slash    const source = path.substring(this.source_dir.length).replace(/\\/g, '/');    const post = Post.findOne({ source });    if (post) {      const { source: postSource } = post;      postPath = join(source_dir, dirname(postSource), basename(postSource, extname(postSource)));    }  }  let sanitizer = function(html) { return html; };  if (dompurify) {    if (createDOMPurify === undefined &amp;&amp; JSDOM === undefined) {      createDOMPurify = require('dompurify');      JSDOM = require('jsdom').JSDOM;    }    const window = new JSDOM('').window;    const DOMPurify = createDOMPurify(window);    let param = {};    if (dompurify !== true) {      param = dompurify;    }    sanitizer = function(html) { return DOMPurify.sanitize(html, param); };  }  marked.use({    renderer,    tokenizer  });  return sanitizer(marked.parse(text, Object.assign({    // headerIds was removed in marked v8.0.0, but we still need it    headerIds: true  }, markedCfg, options, { postPath, hexo: this, _headingId: {} })));};</code></pre><blockquote><p>该渲染器用了 <code>marked</code> 库。</p><p><a href="https://github.com/markedjs/marked"><img src="https://gh-card.dev/repos/markedjs/marked.svg" alt="markedjs/marked - GitHub" loading="lazy"></a></p></blockquote><p>它的入口函数接收从 <code>Renderer</code> 类传来的 <code>data</code> 和 <code>options</code>，然后执行以下步骤：</p><ol><li><p>为了保证每次渲染的纯粹性，它首先会清空 <code>marked</code> 库的默认扩展。然后，它立刻通过 <code>this.execFilterSync</code> 触发三个专属于 <code>marked</code> 的过滤器：</p><ul><li><code>marked:use</code></li><li><code>marked:renderer</code></li><li><code>marked:tokenizer</code></li></ul><p>允许其他插件来进一步修改和扩展 <code>marked</code> 的行为，体现了 Hexo 插件系统的层次性。</p></li><li><p>定义一个 <code>renderer</code> 对象，重写 <code>marked</code> 库的默认渲染行为，以实现 Hexo 的特有功能：</p><ul><li><code>heading</code>：为标题标签自动生成 <code>id</code> 属性，用于页面内锚点跳转，并添加一个可点击的「链接」图标。因此我们能在 Hexo 文章标题旁看到那个小链接图标</li><li><code>link</code>：根据 <code>_config.yml</code> 中的 <code>external_link</code> 配置、自动为外部链接添加 <code>target="_blank"</code> 和 <code>rel="noopener"</code> 等属性</li><li><code>image</code>：智能处理图片路径，可以根据配置自动在图片路径前加上根目录（<code>root</code>），并处理与文章关联的资源文件夹中的图片</li><li><code>paragraph</code>：增加了一个小功能，可以识别特定的语法（<code>Term&lt;br&gt;: Definition</code>）并将其转换为定义列表（<code>&lt;dl&gt;</code>）</li></ul> <pre><code class="language-javascript">const renderer = {  // Add id attribute to headings  heading({ tokens, depth: level }) {    let text = this.parser.parseInline(tokens);    const { anchorAlias, headerIds, modifyAnchors, _headingId } = this.options;    if (!headerIds) {      return `&lt;h${level}&gt;${text}&lt;/h${level}&gt;`;    }    const transformOption = modifyAnchors;    let id = anchorId(text, transformOption);    const headingId = _headingId;    const anchorAliasOpt = anchorAlias &amp;&amp; text.startsWith('&lt;a href="#');    if (anchorAliasOpt) {      const customAnchor = text.match(rATag)[1];      id = anchorId(customAnchor, transformOption);    }    // Add a number after id if repeated    if (headingId[id]) {      id += `-${headingId[id]++}`;    } else {      headingId[id] = 1;    }    if (anchorAliasOpt) {      text = text.replace(rATag, (str, alias) =&gt; {        return str.replace(alias, id);      });    }    // add headerlink    return `&lt;h${level} id="${id}"&gt;&lt;a href="#${id}" class="headerlink" title="${stripHTML(text)}"&gt;&lt;/a&gt;${text}&lt;/h${level}&gt;`;  },  link({ tokens, href, title }) {    const text = this.parser.parseInline(tokens);    const { external_link, sanitizeUrl, hexo, mangle } = this.options;    const { url: urlCfg } = hexo.config;    if (sanitizeUrl) {      if (href.startsWith('javascript:') || href.startsWith('vbscript:') || href.startsWith('data:')) {        href = '';      }    }    if (mangle) {      if (href.startsWith('mailto:')) {        const email = href.substring(7);        const mangledEmail = mangleEmail(email);        href = `mailto:${mangledEmail}`;      }    }    let out = '&lt;a href="';    try {      out += encodeURL(href);    } catch (e) {      out += href;    }    out += '"';    if (title) {      out += ` title="${escape(title)}"`;    }    if (external_link) {      const target = ' target="_blank"';      const noopener = ' rel="noopener"';      const nofollowTag = ' rel="noopener external nofollow noreferrer"';      if (isExternalLink(href, urlCfg, external_link.exclude)) {        if (external_link.enable &amp;&amp; external_link.nofollow) {          out += target + nofollowTag;        } else if (external_link.enable) {          out += target + noopener;        } else if (external_link.nofollow) {          out += nofollowTag;        }      }    }    out += `&gt;${text}&lt;/a&gt;`;    return out;  },  // Support Basic Description Lists  paragraph({ tokens }) {    const text = this.parser.parseInline(tokens);    const { descriptionLists = true } = this.options;    if (descriptionLists &amp;&amp; text.includes('&lt;br&gt;:')) {      if (rDlSyntax.test(text)) {        return text.replace(rDlSyntax, '&lt;dl&gt;&lt;dt&gt;$1&lt;/dt&gt;&lt;dd&gt;$2&lt;/dd&gt;&lt;/dl&gt;');      }    }    return `&lt;p&gt;${text}&lt;/p&gt;\n`;  },  // Prepend root to image path  image({ href, title, text }) {    const { options } = this;    const { hexo } = options;    const { relative_link } = hexo.config;    const { lazyload, figcaption, prependRoot, postPath } = options;    if (!/^(#|\/\/|http(s)?:)/.test(href) &amp;&amp; !relative_link &amp;&amp; prependRoot) {      if (!href.startsWith('/') &amp;&amp; !href.startsWith('\\') &amp;&amp; postPath) {        const PostAsset = hexo.model('PostAsset');        // findById requires forward slash        const asset = PostAsset.findById(join(postPath, href.replace(/\\/g, '/')));        // asset.path is backward slash in Windows        if (asset) href = asset.path.replace(/\\/g, '/');      }      href = url_for.call(hexo, href);    }    let out = `&lt;img src="${encodeURL(href)}"`;    if (text) out += ` alt="${escape(text)}"`;    if (title) out += ` title="${escape(title)}"`;    if (lazyload) out += ' loading="lazy"';    out += '&gt;';    if (figcaption &amp;&amp; text) {      return `&lt;figure&gt;${out}&lt;figcaption aria-hidden="true"&gt;${text}&lt;/figcaption&gt;&lt;/figure&gt;`;    }    return out;  }};</code></pre></li><li><p>定制 <code>tokenizer</code>，用于影响 <code>marked</code> 如何解析原始的 Markdown 文本</p> <pre><code class="language-javascript">const tokenizer = {  // Support autolink option  url(src) {    const { autolink } = this.options;    if (!autolink) return;    // return false to use original url tokenizer    return false;  },  // Override smartypants  inlineText(src) {    const { options, rules } = this;    const { quotes, smartypants: isSmarty } = options;    // https://github.com/markedjs/marked/blob/b6773fca412c339e0cedd56b63f9fa1583cfd372/src/Tokenizer.js#L643-L658    const cap = rules.inline.text.exec(src);    if (cap) {      let text;      if (this.lexer.state.inRawBlock || this.rules.inline.url.exec(src)) {        text = cap[0];      } else {        text = escape(isSmarty ? smartypants(cap[0], quotes) : cap[0]);      }      return {        type: 'text',        raw: cap[0],        text      };    }  }};</code></pre><ul><li><code>inlineText</code> 主要是实现了 <code>smartypants</code> 功能，可以将普通的直引号自动转换成更美观的弯引号，以及将多个连字符转换成破折号</li></ul> <pre><code class="language-javascript">const smartypants = (str, quotes) =&gt; {  const [openDbl, closeDbl, openSgl, closeSgl] = typeof quotes === 'string' &amp;&amp; quotes.length === 4    ? quotes    : ['\u201c', '\u201d', '\u2018', '\u2019'];  return str    // em-dashes    .replace(/---/g, '\u2014')    // en-dashes    .replace(/--/g, '\u2013')    // opening singles    .replace(/(^|[-\u2014/([{"\s])'/g, '$1' + openSgl)    // closing singles &amp; apostrophes    .replace(/'/g, closeSgl)    // opening doubles    .replace(/(^|[-\u2014/([{\u2018\s])"/g, '$1' + openDbl)    // closing doubles    .replace(/"/g, closeDbl)    // ellipses    .replace(/\.{3}/g, '\u2026');};</code></pre></li><li><p>在准备好所有定制的 <code>renderer</code> 和 <code>tokenizer</code> 之后，插件通过 <code>marked.use()</code> 将它们应用到 <code>marked</code> 实例上。最后调用 <code>marked.parse()</code>，传入原始文本和所有配置，得到最终的 HTML</p><ul><li>如果用户开启了 <code>dompurify</code> 选项，它还会在返回结果前对 HTML 进行一次安全过滤，防止恶意的脚本注入</li></ul></li></ol><h1 id="4-页面的生成"><a class="markdownIt-Anchor" href="#4-页面的生成"></a> 4. 页面的生成</h1><p>还记得第二章最开始出现的那段代码吗？</p><pre><code class="language-javascript">load(callback) {  return (0, load_database_1.default)(this).then(() =&gt; {    this.log.info('Start processing');    return bluebird_1.default.all([      this.source.process(),      this.theme.process()    ]);  }).then(() =&gt; {    mergeCtxThemeConfig(this);    return this._generate({ cache: false });  }).asCallback(callback);}</code></pre><p><code>hexo.load()</code> 方法成功地将所有 <code>source</code> 目录下的源文件处理完毕，并将结构化的数据存入了内存数据库（<code>this.database</code>）。也就是说，我们拥有了所有文章、独立页面、分类和标签的原子数据。但是，一个完整的网站还包含许多由这些原子数据聚合而成的页面，例如：首页的文章列表、归档页、分类列表页等。这些页面在 <code>source</code> 目录中并没有对应的源文件。</p><p>那么这些「无源之页」是如何被创建的呢？答案就在 <code>Generator</code> 扩展中。上一章节讲到了 <code>this.source.process()</code>，本章节则重点探讨之后的 <code>_generate()</code> 方法，看 Hexo 是如何调用所有 <code>Generator</code> 插件，并生产出网站所有页面的「蓝图」。</p><blockquote><p>眼尖的朋友应该发现了，我跳过了 <code>this.theme.process()</code>。搭建过个人博客的朋友都知道主题这一大山有多么重要，而这段代码就是调用了主题的处理方法。不过本文并不注重于主题，而是注重于「Markdown 文件如何变成网页」这条主线。之后的文章就会讲一讲主题（挖坑）<s>（说实话 Hexo 开发主题也是一堆坑）</s>。</p></blockquote><h2 id="41-_rungenerators-方法解析"><a class="markdownIt-Anchor" href="#41-_rungenerators-方法解析"></a> 4.1. <code>_runGenerators</code> 方法解析</h2><p><code>Generator</code> 的调用发生在 <code>_generate</code> 方法内部。<code>_generate</code> 会调用 <code>_runGenerators</code>，并将该方法的返回值 —— 一个包含了所有页面蓝图的数组 —— 传递给下一阶段的 <code>_routerRefresh</code>。</p><pre><code class="language-javascript">_generate(options = {}) {  if (this._isGenerating)    return;  const useCache = options.cache;  this._isGenerating = true;  this.emit('generateBefore');  // Run before_generate filters  return this.execFilter('before_generate', null, { context: this })    .then(() =&gt; this._routerRefresh(this._runGenerators(), useCache)).then(() =&gt; {    this.emit('generateAfter');    // Run after_generate filters    return this.execFilter('after_generate', null, { context: this });  }).finally(() =&gt; {    this._isGenerating = false;  });}</code></pre><p><code>_runGenerators</code> 的职责非常专一：执行所有已注册的 <code>Generator</code> 插件，并收集它们的返回结果。</p><pre><code class="language-javascript">_runGenerators() {  this.locals.invalidate();  // 1. 准备 Generator 的输入数据（site 对象）  const siteLocals = this.locals.toObject();  // 2. 获取所有已注册的 Generator 函数列表  const generators = this.extend.generator.list();  const { log } = this;  // 3. 遍历并执行所有的 Generator  return bluebird_1.default.map(Object.keys(generators), key =&gt; {    const generator = generators[key];    log.debug('Generator: %s', (0, picocolors_1.magenta)(key));    // 4. 执行单个 Generator 函数    return Reflect.apply(generator, this, [siteLocals]);  }).reduce((result, data) =&gt; {    // 5. 将所有返回结果合并成一个数组    return data ? result.concat(data) : result;  }, []);}</code></pre><p>这里的 <code>this.locals</code> 是 <code>Hexo</code> 实例的一个属性。<a href="/posts/5d57#%E6%9C%AC%E5%9C%B0%E6%95%B0%E6%8D%AE%E7%BB%91%E5%AE%9A">第一篇文章</a> 中，它被我们分析过的 <code>_bindLocals</code> 方法初始化。<code>_bindLocals</code> 将数据库查询函数与 <code>posts</code>, <code>pages</code>, <code>tags</code>, <code>categories</code> 等键名绑定。</p><p>而 <code>this.locals.toObject()</code> 方法的作用，就是执行所有这些绑定的函数，从数据库中查询出最新的数据，并组装成一个巨大的 <code>site</code> 对象。这个对象包含了：</p><ul><li><code>site.posts</code>：一个 <code>Warehouse</code> 模型集合，包含了所有文章</li><li><code>site.pages</code>：包含了所有独立页面</li><li><code>site.categories</code> 和 <code>site.tags</code>：分别包含了所有分类和标签</li><li><code>site.data</code>：包含了 <code>source/_data</code> 目录下的所有数据</li></ul><p>这个 <code>site</code> 对象，就是所有 <code>Generator</code> 赖以生存的「食材库」。</p><blockquote><p>看过 <a href="https://hexo.io/zh-cn/api/locals">Hexo 官方文档</a> 的朋友或许会回忆起，<code>site</code> 对象实际上就是用于模板渲染的局部变量。</p></blockquote><h2 id="42-页面蓝图-path-layout-data"><a class="markdownIt-Anchor" href="#42-页面蓝图-path-layout-data"></a> 4.2. 页面蓝图 <code>{ path, layout, data }</code></h2><p><code>Generator</code> 的核心产出是一种标准化的数据结构，我们可以称之为「页面蓝图」。它不是最终的 HTML，而是描述了如何生成一个页面的指令。</p><p>每个蓝图对象通常包含三个核心属性：</p><ul><li><code>path</code>: <code>String</code> - 页面最终生成的文件路径，例如 <code>archives/index.html</code></li><li><code>layout</code>: <code>String | Array</code> - 渲染这个页面所使用的主题布局文件。例如，<code>'archive'</code> 会对应到主题的 <code>layout/archive.ejs</code> 文件。可以是一个数组，Hexo 会依次查找并使用第一个找到的布局</li><li><code>data</code>: <code>Object</code> - 渲染布局时需要的数据</li></ul><blockquote><p>示例：</p><ul><li><p>一篇文章的蓝图：</p>  <pre><code class="language-json">{  "path": "2025/07/23/hello-world/index.html",  "layout": "post",  "data": { "post": { ...文章数据 } }}</code></pre></li><li><p>归档页的蓝图：</p>  <pre><code class="language-json">{  "path": "archives/index.html",  "layout": "archive",  "data": { "posts": site.posts, "page": { "current": 1, ... } }}</code></pre></li></ul></blockquote><h2 id="43-generator-的来源"><a class="markdownIt-Anchor" href="#43-generator-的来源"></a> 4.3. <code>Generator</code> 的来源</h2><p>Hexo 默认注册了几个核心的 <code>Generator</code> 来生成网站的基础部分：</p><ul><li><code>post</code> &amp; <code>page</code>：这两个 <code>Generator</code> 负责处理「有源文件」的页面。它们遍历 <code>site.posts</code> 和 <code>site.pages</code> 集合，为每篇文章和每个独立页面生成对应的页面蓝图</li><li><code>archive</code>, <code>category</code>, <code>tag</code>：这三个 <code>Generator</code> 负责处理「无源之页」。它们分别遍历 <code>site.posts</code>, <code>site.categories</code>, <code>site.tags</code> 集合，生成归档页、所有分类页和所有标签页的蓝图</li></ul><p>我们可以深入一个具体的 <code>Generator</code>，来了解它是如何利用 <code>site</code> 对象创建页面蓝图的。我们以 <code>archive</code> 生成器为例。</p><p>不过在分析之前，有一个关键点需要明确：并非所有核心的生成功能都内置在 Hexo 的主代码库中。Hexo 遵循「保持核心精简」的设计哲学，许多基础功能都是通过 <strong>默认插件</strong> 提供的。</p><p>当我们 <code>hexo init</code> 一个新项目时，<code>package.json</code> 会自动包含 <code>hexo-generator-archive</code>, <code>hexo-generator-category</code>, <code>hexo-generator-tag</code> 等插件。</p><p>这意味着：</p><ul><li><code>post</code> &amp; <code>page</code> 生成器位于 Hexo 核心代码库（<code>/plugins/generator/</code>）中，负责处理有源文件的页面</li><li><code>archive</code>、<code>category</code>、<code>tag</code> 等生成器，虽然是默认安装，但它们是独立的 npm 包。它们负责处理无源页面</li></ul><p><code>archive</code> 生成器的核心代码可以分解为三个主要步骤：</p><ol><li><p>生成主归档页</p><p><code>Generator</code> 首先会处理根归档页，也就是 <code>/archives/</code> 目录。</p> <pre><code class="language-javascript">'use strict';const pagination = require('hexo-pagination');const fmtNum = num =&gt; num.toString().padStart(2, '0');module.exports = function(locals) {  const { config } = this;  let archiveDir = config.archive_dir;  const paginationDir = config.pagination_dir || 'page';  // 1. 获取所有文章，并根据配置排序  const allPosts = locals.posts.sort(config.archive_generator.order_by || '-date');  const perPage = config.archive_generator.per_page;  const result = [];  if (!allPosts.length) return;  if (archiveDir[archiveDir.length - 1] !== '/') archiveDir += '/';  // 2. 定义一个通用的页面蓝图生成函数   function generate(path, posts, options = {}) {    options.archive = true;    // 3. 调用 hexo-pagination 工具生成分页数据    result.push(...pagination(path, posts, {      perPage,      layout: ['archive', 'index'],   // 指定布局      format: paginationDir + '/%d/', // 分页路径格式      data: options    }));  }  // 4. 为根归档页调用 generate 函数  generate(archiveDir, allPosts);</code></pre><p><a href="https://github.com/hexojs/hexo-pagination"><img src="https://gh-card.dev/repos/hexojs/hexo-pagination.svg" alt="hexojs/hexo-pagination - GitHub" loading="lazy"></a></p></li><li><p>按日期对文章进行分组</p><p>如果用户在 <code>_config.yml</code> 中开启了 <code>yearly</code> 或 <code>monthly</code> 归档，<code>Generator</code> 接下来会执行一个精巧的数据预处理步骤：将所有文章按年、月、日进行分组。</p> <pre><code class="language-javascript">if (!config.archive_generator.yearly) return result;  // 如果没开启，直接返回const posts = {};// 遍历所有文章allPosts.forEach(post =&gt; {  const date = post.date;  const year = date.year();  const month = date.month() + 1;  // 创建一个嵌套结构来存储文章  if (!Object.prototype.hasOwnProperty.call(posts, year)) {    posts[year] = [      [],      [],      [],      [],      [],      [],      [],      [],      [],      [],      [],      [],      []    ];  }  posts[year][0].push(post);  // 按年分组  posts[year][month].push(post);  // 按月分组  if (config.archive_generator.daily) {    const day = date.date();  // 按日分组    if (!Object.prototype.hasOwnProperty.call(posts[year][month], 'day')) {      posts[year][month].day = {};    }    (posts[year][month].day[day] || (posts[year][month].day[day] = [])).push(post);  }});</code></pre><p>这段代码执行完毕后，会得到一个类似 <code>posts[2025][7]</code> 的数据结构，其中存储了 2025 年 7 月的所有文章。</p></li><li><p>生成年、月、日归档页</p><p>最后，代码会遍历上一步中分组好的 <code>posts</code> 对象，为每个时间单位生成对应的归档页面。</p></li></ol><pre><code class="language-javascript">  const { Query } = this.model('Post');  const years = Object.keys(posts);  let year, data, month, monthData, url;  // 遍历年份  for (let i = 0, len = years.length; i &lt; len; i++) {    year = +years[i];    data = posts[year];    url = archiveDir + year + '/';    if (!data[0].length) continue;    // 为该年份生成归档页，例如 /archives/2025/    generate(url, new Query(data[0]), { year });    if (!config.archive_generator.monthly &amp;&amp; !config.archive_generator.daily) continue;    // 遍历月份    for (month = 1; month &lt;= 12; month++) {      monthData = data[month];      if (!monthData.length) continue;      if (config.archive_generator.monthly) {        // 为该月份生成归档页，例如 /archives/2025/07/        generate(url + fmtNum(month) + '/', new Query(monthData), {          year,          month        });      }      if (!config.archive_generator.daily) continue;      // 同样逻辑处理按日归档      for (let day = 1; day &lt;= 31; day++) {        const dayData = monthData.day[day];        if (!dayData || !dayData.length) continue;        generate(url + fmtNum(month) + '/' + fmtNum(day) + '/', new Query(dayData), {          year,          month,          day        });      }    }  }  return result;};</code></pre><p>通过嵌套循环，<code>Generator</code> 复用了第一步中定义的 <code>generate</code> 辅助函数，为所有存在文章的年、月、日都创建了对应的分页归档页面蓝图。</p><p>最终，这个 <code>Generator</code> 返回一个巨大的 <code>result</code> 数组，其中包含了主归档页、以及所有年、月、日归档页的完整页面蓝图。</p><h1 id="5-路由的建立"><a class="markdownIt-Anchor" href="#5-路由的建立"></a> 5. 路由的建立</h1><p><code>_runGenerators</code> 方法为我们产出了一份包含了网站所有页面生成指令的「蓝图清单」。但这些蓝图还只是数据，系统需要一个机制来管理它们，并将它们与最终的文件路径关联起来。</p><p>这个机制就是 Hexo 的 <code>Router</code>。</p><h2 id="51-router-类内存中的-public-目录"><a class="markdownIt-Anchor" href="#51-router-类内存中的-public-目录"></a> 5.1. <code>Router</code> 类：内存中的 <code>public</code> 目录</h2><p>在分析 <code>_routerRefresh</code> 之前，我们必须先理解它的工作对象：<code>this.route</code>。这个属性是 <code>Router</code> 类的一个实例。</p><p>需要明确的是，Hexo 的 <code>Router</code> <strong>不是</strong> 一个网络服务器中的路由（用于匹配 URL 请求），而是一个 <strong>内存中的键值对集合</strong>，可以理解为一个虚拟的文件系统。</p><ul><li>键：将要生成的文件路径，例如 <code>archives/index.html</code></li><li>值：该路径对应的文件内容</li></ul><p><code>Router</code> 类（位于 <code>/lib/hexo/router.js</code>）提供了一系列方法来管理这个集合，核心方法包括 <code>list()</code>、<code>get(path)</code>、<code>set(path, data)</code> 和 <code>remove(path)</code>。</p><pre><code class="language-javascript">class Router extends events_1.EventEmitter {    constructor() {        super();        this.routes = {}; // 核心数据结构    }    list() {}    format(path) {}    get(path) {}    isModified(path) {}    set(path, data) {}    remove(path) {}}</code></pre><p><code>_routerRefresh</code> 的核心任务便是清空并重新填充这个 <code>this.routes</code> 对象。</p><h2 id="52-_routerrefresh"><a class="markdownIt-Anchor" href="#52-_routerrefresh"></a> 5.2. <code>_routerRefresh</code></h2><p><code>_routerRefresh</code> 方法接收 <code>_runGenerators</code> 返回的蓝图数组作为输入、遍历这个数组、为每一个蓝图在 <code>this.route</code> 中创建一条对应的记录。</p><pre><code class="language-javascript">_routerRefresh(runningGenerators, useCache) {  const { route } = this;  const routeList = route.list(); // 1. 获取旧的路由列表，用于后续对比  const Locals = this._generateLocals();  // 2. 准备一个 Locals 类的构造器  Locals.prototype.cache = useCache;  // 3. 遍历所有由 Generator 生成的页面蓝图  return runningGenerators.map((generatorResult) =&gt; {    if (typeof generatorResult !== 'object' || generatorResult.path == null)      return undefined;    const path = route.format(generatorResult.path);    const { data, layout } = generatorResult;    // 4. 根据蓝图是否有 layout 属性，进行分流处理    if (!layout) {      // 4.1. 没有 layout：视为静态资源      route.set(path, data);      return path;    }    // 4.2. 有 layout：视为待渲染页面    // 这里的 createLoadThemeRoute 是用于将主题的布局文件和页面的具体数据打包成一个待执行的渲染任务、通过 route.set 存入路由系统的    return this.execFilter('template_locals', new Locals(path, data), { context: this })      .then(locals =&gt; { route.set(path, createLoadThemeRoute(generatorResult, locals, this)); })      .thenReturn(path);  }).then(newRouteList =&gt; {    // 5. 刷新操作：移除所有过时的路由    for (let i = 0, len = routeList.length; i &lt; len; i++) {      const item = routeList[i];      if (!newRouteList.includes(item)) {        route.remove(item);      }    }  });}</code></pre><blockquote><p><code>_generateLocals</code> 方法见 <a href="/posts/5d57#%E7%94%9F%E6%88%90%E6%9C%AC%E5%9C%B0%E7%8E%AF%E5%A2%83">这里</a>。</p></blockquote><p>这个方法的逻辑非常清晰，但要真正理解，我们需要回到 <code>Router</code> 类。</p><h2 id="53-router-类深度解析"><a class="markdownIt-Anchor" href="#53-router-类深度解析"></a> 5.3. <code>Router</code> 类深度解析</h2><ol><li><p><code>set</code> 方法负责将内容存入路由。它的实现非常巧妙，能够区分处理不同类型的数据。</p> <pre><code class="language-javascript">set(path, data) {  if (typeof path !== 'string')    throw new TypeError('path must be a string!');  if (data == null)    throw new TypeError('data is required!');  let obj;  if (typeof data === 'object' &amp;&amp; data.data != null) {    obj = data;  }  else {    obj = {      data,      modified: true    };  }  // 检查 data 是否为函数  if (typeof obj.data === 'function') {    // 使用 bluebird 将其包装成一个标准的 Promise-returning 函数    if (obj.data.length) {  // 有回调参数的函数      obj.data = bluebird_1.default.promisify(obj.data);    }    else {  // 无参数的函数      obj.data = bluebird_1.default.method(obj.data);    }  }  path = this.format(path); // 格式化路径  this.routes[path] = {    data: obj.data,    modified: obj.modified == null ? true : obj.modified  };  this.emit('update', path);  return this;}</code></pre><p><code>set</code> 方法的逻辑揭示了路由内容的两种形态：</p><ol><li><strong>成品（静态资源）</strong>：如果传入的 <code>data</code> 是 Buffer 或字符串（比如一张图片的内容），它会被直接存入 <code>this.routes</code></li><li><strong>半成品（待渲染页面）</strong>：如果传入的 <code>data</code> 是一个函数（由 <code>createLoadThemeRoute</code> 创建的那个），<code>set</code> 方法会用 <code>bluebird</code> 将其包装成一个标准的异步函数。<strong>存入路由的，是这个被包装后的函数本身</strong></li></ol><p>这种设计就是 Hexo 高性能的 <strong>延迟执行（Lazy Evaluation)</strong> 策略的核心。它避免了在生成路由时就渲染所有页面，而是将渲染工作推迟到最后一刻。</p></li><li><p>如果说 <code>set</code> 方法是把「速冻料理包」（待执行的渲染函数）放入冰箱，那么 <code>get</code> 方法就是从冰箱里取出料理包并准备加热。</p><p><code>get</code> 方法本身很简单，但它返回的东西却大有文章：</p> <pre><code class="language-javascript">get(path) {  if (typeof path !== 'string')    throw new TypeError('path must be a string!');  const data = this.routes[this.format(path)];  if (data == null)    return;  // 返回一个 RouteStream 实例  return new RouteStream(data);}</code></pre><p>它并不直接返回值，而是将从 <code>this.routes</code> 中取出的数据（无论是 Buffer 还是那个待执行的函数）传递给 <code>RouteStream</code> 类的构造函数，并返回一个 <code>RouteStream</code> 实例。</p><p><code>RouteStream</code> 是一个 Node.js 的可读流（Readable Stream)。它的魔法藏在 <code>_read()</code> 方法中：</p> <pre><code class="language-javascript">class RouteStream extends Readable {  constructor(data) {    super({ objectMode: true });    this._data = data.data;    this._ended = false;    this.modified = data.modified;  }  _toBuffer(data) {    if (data instanceof Buffer) {      return data;    }    if (typeof data === 'object') {      data = JSON.stringify(data);    }    if (typeof data === 'string') {      return Buffer.from(data);    }    return null;  }  _read() {    const data = this._data;    // 情况一：内容是“成品”（Buffer、String 等）    if (typeof data !== 'function') {      const bufferData = this._toBuffer(data);      if (bufferData) {        this.push(bufferData);  // 直接将数据推入流中      }      this.push(null);  // 结束流      return;    }    // 情况二：内容是“半成品”（待执行函数）    if (this._ended)      return false;    this._ended = true;    // 执行函数    data().then(data =&gt; {      if (data instanceof stream_1.default &amp;&amp; data.readable) {        data.on('data', d =&gt; {          this.push(d);        });        data.on('end', () =&gt; {          this.push(null);        });        data.on('error', err =&gt; {          this.emit('error', err);        });      }      else {        const bufferData = this._toBuffer(data);        if (bufferData) {          this.push(bufferData);  // 将渲染后的 HTML 推入流中        }        this.push(null);  // 结束流      }    }).catch(err =&gt; {      this.emit('error', err);      this.push(null);    });  }}</code></pre><p>之后我们讲到「文件写入」时，模块会从这个流中读取数据，<code>_read()</code> 方法会被触发。它会检查 <code>this._data</code>：</p><ul><li>如果是普通数据，就直接推入流</li><li>如果是一个函数，它就会执行这个函数（<code>data()</code>）。渲染过程在这一刻才真正发生。函数执行完毕后（<code>.then()</code>），<code>_read</code> 会将返回的 HTML 结果推入流中，供文件写入模块消费</li></ul></li></ol><h1 id="6-从内存到硬盘"><a class="markdownIt-Anchor" href="#6-从内存到硬盘"></a> 6. 从内存到硬盘</h1><p>经过前面四个阶段的精密运作，Hexo 已经在内存中构建了一个完整的虚拟网站（<code>this.route</code>）。现在，我们来到了这趟旅程的终点站：将这个虚拟世界实体化，写入到硬盘的 <code>public</code> 文件夹中。</p><p>这个最终的执行任务，由 <code>generate</code> 命令的总指挥 —— <code>Generater</code> 类 —— 来完成。</p><h2 id="61-怎么又是你-generator-类"><a class="markdownIt-Anchor" href="#61-怎么又是你-generator-类"></a> 6.1. 怎么又是你 <code>Generator</code> 类</h2><p>回顾第一章，<code>generateConsole</code> 函数在最开始就实例化了 <code>Generater</code> 类：</p><pre><code class="language-javascript">function generateConsole(args = {}) {  const generator = new Generater(this, args);  // 我在这儿  if (generator.watch) {    return generator.execWatch();  }  return this.load().then(() =&gt; generator.firstGenerate()).then(() =&gt; {    if (generator.deploy) {      return generator.execDeploy();    }  });}module.exports = generateConsole;</code></pre><p><code>generator.firstGenerate()</code> 就是文件写入流程的入口。这个方法负责比对文件差异、创建任务队列，并最终调用 <code>writeFile</code> 和 <code>deleteFile</code> 来同步 <code>public</code> 目录。</p><h2 id="62-firstgenerate"><a class="markdownIt-Anchor" href="#62-firstgenerate"></a> 6.2. <code>firstGenerate</code></h2><p><code>firstGenerate</code> 方法做的第一件大事，不是写入，而是 <strong>比对</strong>，以确定一份精准的「施工清单」。</p><pre><code class="language-javascript">firstGenerate() {  const { concurrency } = this;  const { route, log } = this.context;  const publicDir = this.context.public_dir;  const Cache = this.context.model('Cache');  const interval = (0, pretty_hrtime_1.default)(process.hrtime(this.start));  log.info('Files loaded in %s', (0, picocolors_1.cyan)(interval));  this.start = process.hrtime();  // 确保 public 文件夹存在  return (0, hexo_fs_1.stat)(publicDir).then(stats =&gt; {    if (!stats.isDirectory()) {      throw new Error(`${(0, picocolors_1.magenta)((0, tildify_1.default)(publicDir))} is not a directory`);    }  }).catch(err =&gt; {    if (err &amp;&amp; err.code === 'ENOENT') {      return (0, hexo_fs_1.mkdirs)(publicDir);    }    throw err;  }).then(() =&gt; {    const task = (fn, path) =&gt; () =&gt; fn.call(this, path);    const doTask = fn =&gt; fn();    const routeList = route.list(); // 1. 获取本次需要生成的文件清单    const publicFiles = Cache.filter(item =&gt; item._id.startsWith('public/')).map(item =&gt; item._id.substring(7));  // 2. 获取上次已生成的文件清单    // 3. 生成任务队列    const tasks = publicFiles.filter(path =&gt; !routeList.includes(path))      .map(path =&gt; task(this.deleteFile, path)) // 需要删除的文件      .concat(routeList.map(path =&gt; task(this.generateFile, path)));  // 需要生成/更新的文件    // 4. 并发执行所有任务    return bluebird_1.default.all(bluebird_1.default.map(tasks, doTask, { concurrency: parseFloat(concurrency || 'Infinity') }));  }).then(result =&gt; {    const interval = (0, pretty_hrtime_1.default)(process.hrtime(this.start));    const count = result.filter(Boolean).length;    log.info('%d files generated in %s', count.toString(), (0, picocolors_1.cyan)(interval));  });}</code></pre><p>这里的逻辑非常清晰：</p><ol><li>获取新蓝图：从 <code>this.context.route.list()</code> 获取我们在第四章构建的内存虚拟网站的文件列表</li><li>获取旧清单：从 <code>Cache</code> 模型中读取上次生成时写入 <code>public/</code> 的所有文件记录</li><li>计算差异并生成任务：<ul><li>如果一个文件在「旧清单」里，但不在「新蓝图」里，就为它创建一个 <code>deleteFile</code> 任务</li><li>所有「新蓝图」里的文件，都为它们创建一个 <code>generateFile</code> 任务</li></ul></li><li>并发执行：使用 <code>bluebird.map</code> 并发处理所有任务，以提高生成效率</li></ol><h2 id="63-触发延迟执行"><a class="markdownIt-Anchor" href="#63-触发延迟执行"></a> 6.3. 触发延迟执行</h2><p><code>writeFile</code> 方法是整个流程中最关键的「临门一脚」，它负责触发第四章中我们埋下的「延迟执行」机制。</p><pre><code class="language-javascript">writeFile(path, force) {  const { route, log } = this.context;  const publicDir = this.context.public_dir;  const Cache = this.context.model('Cache');  // 1. 从路由中获取内容，返回的是一个 RouteStream 实例  const dataStream = this.wrapDataStream(route.get(path));  const buffers = [];  const hasher = (0, hexo_util_1.createSha1Hash)();  const finishedPromise = new bluebird_1.default((resolve, reject) =&gt; {    dataStream.once('error', reject);    dataStream.once('end', resolve);  });  // 2. 消费这个流  dataStream.on('data', chunk =&gt; {    buffers.push(chunk);    hasher.update(chunk);  });</code></pre><p>当我们开始监听 <code>data</code> 事件，也就是开始从流中「拉取」数据时，<code>RouteStream</code> 内部的 <code>_read()</code> 方法就会被触发。</p><p>如果这个路由的内容是一个「待执行的渲染函数」，这个函数在此时此刻才会被执行，渲染出最终的 HTML，然后将结果推入流中，被这里的 <code>data</code> 事件监听器接收。</p><h2 id="64-哈希值对比"><a class="markdownIt-Anchor" href="#64-哈希值对比"></a> 6.4. 哈希值对比</h2><p>在 <code>writeFile</code> 方法的后半部分，还隐藏着 Hexo 再次生成时速度飞快的秘密 —— 增量生成。</p><pre><code class="language-javascript">  return finishedPromise.then(() =&gt; {    const dest = (0, path_1.join)(publicDir, path);    const cacheId = `public/${path}`;    const cache = Cache.findById(cacheId);  // 1. 查找上一次的缓存    const hash = hasher.digest('hex');  // 2. 拿到本次内容的哈希值    // 3. 如果哈希值未变，且不是强制生成，则跳过    if (!force &amp;&amp; cache &amp;&amp; cache.hash === hash) {      return;    }    // 4. 哈希值变了，才执行真正的写入操作    return Cache.save({      _id: cacheId,      hash    }).then(() =&gt;      (0, hexo_fs_1.writeFile)(dest, Buffer.concat(buffers))).then(() =&gt; {        log.info('Generated: %s', (0, picocolors_1.magenta)(path));        return true;    });  });}</code></pre><p>在将文件内容写入磁盘之前，<code>writeFile</code> 会计算出内容的 SHA1 哈希值，并与缓存中的旧哈希值进行对比。如果两者相同，意味着文件内容没有变化，Hexo 就会聪明地跳过这次文件写入操作，从而极大地提升了二次生成的效率。</p><h1 id="7-总结"><a class="markdownIt-Anchor" href="#7-总结"></a> 7. 总结</h1><p>现在，让我们回到最初的起点，以 <code>_posts/hello-world.md</code> 的视角，快速回顾它在 <code>hexo generate</code> 命令下经历的完整旅程：</p><ol><li>我们在终端敲下回车，<code>Console</code> 扩展接收到 <code>generate</code> 命令</li><li><code>Box</code> 引擎扫描 <code>source</code> 目录，发现了 <code>hello-world.md</code>。<code>post</code> 处理器接管了它，解析其文件名和 Front-matter，将标题、日期等元数据连同原始 Markdown 内容（<code>_content</code>）一起，存入了数据库的 <code>Post</code> 模型中</li><li>在生成页面之前，<code>before_generate</code> 过滤器被触发。<code>renderPostFilter</code> 找到了数据库中 <code>content</code> 字段尚为空的 <code>hello-world.md</code>，并调用 <code>post.render</code> 对其进行「炼金」：<ul><li><code>post.render</code> 暂时将文中的 Nunjucks 标签（如果有的话）替换为占位符</li><li><code>ctx.render</code> 调度 <code>hexo-renderer-marked</code> 将 Markdown 转换为 HTML</li><li>在 <code>onRenderEnd</code> 回调中，<code>post.render</code> 恢复 Nunjucks 标签并立刻执行它们。最终，一篇完整的 HTML 被存入数据库记录的 content 字段</li></ul></li><li><code>_runGenerators</code> 开始执行。<code>post</code> 生成器遍历数据库，找到了我们已渲染好的 <code>hello-world.md</code>，为它创建了一张包含最终路径、主题布局（<code>layout: 'post'</code>）和所有页面数据的「页面蓝图」</li><li><code>_routerRefresh</code> 接收到这张蓝图。它没有立即渲染整个页面，而是创建了一个「待办任务」—— 一个包含了「使用 <code>post</code> 布局」和「填充 <code>hello-world.md</code> 内容」指令的函数，并将这个任务存入了内存中的 <code>Router</code> 里，键名为最终的文件路径 <code>posts/hello-world/index.html</code></li><li><code>Generater</code> 类的 <code>firstGenerate</code> 方法开始工作。它对比 <code>Router</code> 和 <code>public</code> 目录的缓存，确定 <code>posts/hello-world/index.html</code> 是一个需要生成的文件，并为其创建了一个 <code>writeFile</code> 任务</li><li>当 <code>writeFile</code> 任务执行时，它向 <code>Router</code> 请求 <code>posts/hello-world/index.html</code> 的内容。<code>RouteStream</code> 机制被触发，直到这一刻，第五步中创建的那个「待办任务」才被真正执行。它读取主题的 <code>post</code> 布局文件，将 <code>hello-world.md</code> 的 <code>content</code>（HTML）填充进去，生成了包含页头、页脚的完整页面 HTML</li><li>最终的 HTML 内容通过流被写入 <code>public/posts/hello-world/index.html</code> 文件。<code>hello-world.md</code> 的旅程至此结束，它已成为网站上一个可被访问的真实页面</li></ol></body></html>]]></content>
    
    
    <summary type="html">本文以 hexo generate 命令为主线，深入剖析 Hexo 源码，讲述一篇 Markdown 文章从原材料加工、渲染、生成页面蓝图到最终写入硬盘的完整生命周期故事。</summary>
    
    
    
    <category term="代码解读" scheme="https://blog.cytrogen.icu/categories/%E4%BB%A3%E7%A0%81%E8%A7%A3%E8%AF%BB/"/>
    
    
    <category term="Hexo" scheme="https://blog.cytrogen.icu/tags/Hexo/"/>
    
    <category term="JavaScript" scheme="https://blog.cytrogen.icu/tags/JavaScript/"/>
    
  </entry>
  
  <entry>
    <title>用 JavaScript 自制 GameBoy 模拟器（上）</title>
    <link href="https://blog.cytrogen.icu/posts/4148.html"/>
    <id>https://blog.cytrogen.icu/posts/4148.html</id>
    <published>2025-07-01T04:00:00.000Z</published>
    <updated>2026-02-09T17:16:55.545Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期有些百无聊赖。因为工作，先前的个人项目全都不得不暂时搁置。为了找点乐子，我决定做一些与全栈开发不同的事情 <s>（主要是最近玩宝可梦玩的有点多）</s>。</p><p>这期的文章参考了 Imre Nazar 在 2010 年写的一系列关于 <a href="https://imrannazar.com/series/gameboy-emulation-in-javascript">用 JavaScript 实现 GameBoy 模拟器</a> 的教程。虽然这个教程有些年头了，但还是提供了一个很好的起点和思路。自然，这期文章不会直接去 Ctrl C + V 他的实现，而是会使用更现代的 ES6 语法。</p><span id="more"></span><h1 id="前言"><a class="markdownIt-Anchor" href="#前言"></a> 前言</h1><p>要模拟一台 GameBoy，我们至少需要模拟以下核心组件：</p><ul><li>CPU（Z80 兼容处理器），也就是「大脑」，负责执行游戏代码</li><li>内存管理单元（MMU），用于处理内存的读写，包括 ROM、RAM 和各种硬件寄存器</li><li>图形处理单元（PPU），负责渲染游戏画面</li><li>输入设备，处理用户按键操作</li><li>定时器，提供精确的时间控制</li><li>声音处理单元，生成游戏音效和音乐</li></ul><h1 id="1-模拟-z80-cpu"><a class="markdownIt-Anchor" href="#1-模拟-z80-cpu"></a> 1. 模拟 Z80 CPU</h1><p>GameBoy 的 CPU 是一个修改过的 Zilog Z80 处理器。要模拟它，就得理解它的工作方式。</p><p>核心概念很简单：取指 → 解码 → 执行循环。</p><ol><li>取指：从内存中获取下一条指令</li><li>解码：解析指令的含义</li><li>执行：执行指令指定的操作</li></ol><p>这个循环在 GameBoy 上电后就开始运行，直到关机。为了跟踪程序执行到哪里，CPU 会使用一个特殊的寄存器 —— 程序计数器。每当一条指令被取出后，程序计数器就会根据指令的长度向前移动，指向下一条要执行的指令。</p><p>Z80 CPU 是一个 8 位芯片，意味着它一次可以处理一个字节的数据。它也能访问多达 6,5536 字节的内存空间，程序代码和普通数据都被存储在同一个内存地址空间中，而一条指令的长度可以在 1 到 3 个字节之间。</p><p>除了程序计数器，Z80 CPU 还有一组内存寄存器，用于存储数据和执行计算：</p><ul><li>8 位通用寄存器（A、B、C、D、E、H、L），每个可以存储一个字节（0 到 255）的值。大多数 Z80 指令都围绕着操作这些寄存器，例如将内存中的值加载到寄存器中，或者对寄存器中的值进行算术运算</li><li>标志寄存器（F）是一个特殊的 8 位寄存器，其中每个位都代表一个「标志」，用于存储上一次运算的结果状态</li><li>栈指针（SP）是一个 16 位寄存器，用于指向内存中的「栈顶」位置<ul><li>栈是一种后进先出的数据结构</li></ul></li></ul><blockquote><p>CPU 是什么？（用大白话说）</p><p><strong>不要被「中央处理器」这个名字吓到。</strong></p><p>把 CPU 想象成一个超快的计算器工人：</p><ul><li>他有一张小纸条（寄存器），记录当前的数字</li><li>他有一本操作手册（指令集），告诉他怎么计算</li><li>他一次只能做一件事，但做得很快</li></ul><p>假设有一个指令是「把 A 和 B 加起来」，那么对于这个工人而言就是：</p><ol><li>看看 A 纸条（3）</li><li>看看 B 纸条（5）</li><li>算出结果（8）</li><li>写到 A 纸条上</li></ol><p><s>基本上就是一个只会加减乘除但超级勤快的员工</s></p></blockquote><p>基于以上理解，我们的 Z80 CPU 模拟器需要包含以下核心组件：</p><ul><li>内部状态，需要保存所有寄存器的当前值、执行上一条指令所花费的时间，以及 CPU 总共运行了多长时间</li><li>指令模拟函数</li><li>指令映射表</li><li>内存接口</li></ul><h2 id="11-cpu-骨架"><a class="markdownIt-Anchor" href="#11-cpu-骨架"></a> 1.1. CPU 骨架</h2><p>下面是我们 <code>GameBoyCPU</code> 类的初步骨架，包含了 CPU 的时钟系统和所有重要的寄存器：</p><pre><code class="language-javascript">/** * GameBoy Z80 CPU 类 */class GameBoyCPU {  constructor() {    // 时钟系统，跟踪 CPU 执行时间    this.clock = {      m: 0, // 机器周期计数器（主时钟）      t: 0, // 时钟周期计数器，用于精确计时    };    // CPU 寄存器组    this.registers = {      // === 8位通用寄存器 ===      a: 0, // 累加器，主要用于算术运算      // BC寄存器对（可作为16位使用）      b: 0,      c: 0,      // DE寄存器对（同上）      d: 0,      e: 0,      // HL寄存器对（同上；常用作内存指针）      h: 0, // 高位      l: 0, // 低位      f: 0, // 标志寄存器，存储运算结果的状态标志      // === 16位专用寄存器 ===      pc: 0, // 程序计数器，指向下一条要执行的指令      sp: 0, // 栈指针，指向栈顶位置      // === 指令执行时间记录 ===      m: 0,      t: 0,    };  }}</code></pre><p>CPU 的时钟系统是用来精确跟踪模拟时间的，<code>m</code> 代表机器周期，<code>t</code> 代表时钟周期，两者之间存在固定关系。</p><h2 id="12-标志寄存器与基本指令"><a class="markdownIt-Anchor" href="#12-标志寄存器与基本指令"></a> 1.2. 标志寄存器与基本指令</h2><p>标志寄存器是 CPU 运算中一个非常关键的部分，它会根据上一条指令的执行结果自动设置某些位。在 GameBoy 的 Z80 CPU 中，有四个重要的标志位：</p><ul><li>零标志（<code>0x80</code>）：如果上一次运算的结果为 0，则设置此位</li><li>减法标志（<code>0x40</code>）：如果上一次运算是减法操作，则设置此位</li><li>半进位标志（<code>0x20</code>）：如果上一次运算在字节的低 4 位发生了溢出（即结果的第 3 位向第 4 位进位），则设置此位</li><li>进位标志（<code>0x10</code>）：如果上一次加法运算结果超过 255（8 位最大值），或者减法运算结果低于 0（发生借位），则设置此位</li></ul><blockquote><p>看不懂的话……</p><p>想象你刚做完一道数学题，你的大脑会自动记住一些「状态」：</p><ul><li>「咦，答案是 0？」→ 零标志</li><li>「我刚才是在做减法吗？」→ 减法标志</li><li>「有没有进位？」→ 进位标志</li></ul><p>GameBoy 的 CPU 也是如此。每次计算完，它都会在标志寄存器里记下这些「感想」。</p><p>为什么需要这些标志？因为后面的指令可能会问：「上次计算结果是 0 吗？如果是的话，跳转到别的地方。」</p></blockquote><p>为了更好地管理这些标志位，我们首先定义一个常量对象 <code>CPU_FLAGS</code>：</p><pre><code class="language-javascript">/** * 标志位常量定义 */const CPU_FLAGS = {  ZERO: 0x80,  OPERATION: 0x40,  HALF_CARRY: 0x20,  CARRY: 0x10,};</code></pre><p>接着，我们为 <code>GameBoyCPU</code> 类添加 <code>reset</code>、<code>setFlag</code> 和 <code>getFlag</code> 方法：</p><ul><li><code>reset</code> 方法用于将 CPU 的所有寄存器和时钟状态复位到初始值，这对于模拟器启动或重新加载游戏非常有用</li><li><code>setFlag</code> 和 <code>getFlag</code> 则分别用于设置和检查标志位，方便我们根据运算结果来操作标志寄存器 <code>f</code></li></ul><pre><code class="language-javascript">// ... 之前的 constructor .../** * CPU 重置，将所有寄存器和时钟复位为初始状态 */reset() {  // 重置所有8位寄存器  this.registers.a = 0;  this.registers.b = 0;  this.registers.c = 0;  this.registers.d = 0;  this.registers.e = 0;  this.registers.h = 0;  this.registers.l = 0;  this.registers.f = 0;  // 重置16位寄存器  this.registers.pc = 0; // 程序从地址0开始执行  this.registers.sp = 0;  // 重置时钟  this.clock.m = 0;  this.clock.t = 0;  console.log('主人~ CPU 已重置到初始状态喵！');}/** * 设置标志位 * @param {number} flag 要设置的标志位 * @param {boolean} condition 是否设置该标志位 */setFlag(flag, condition) {  if（condition) {    this.registers.f |= flag; // 设置位：通过按位或操作将指定标志位设置为 1  } else {    // 否则就清除位：通过按位与操作与指定标志位的补码，将其设置为 0    this.registers.f &amp;= ~flag;  }}/** * 检查标志位是否设置 * @param {number} flag 要检查的标志位 */getFlag(flag) {  return (this.registers.f &amp; flag) !== 0;}</code></pre><p>为了演示 CPU 如何执行指令并影响寄存器和标志位，我们来模拟几个基本的 Z80 指令：</p><ul><li><p><code>ADD A, E</code>（加法指令）：将寄存器 <code>e</code> 的值加到寄存器 <code>a</code> 中，结果存回 <code>a</code>。这个函数需要更新 <code>a</code> 寄存器的值，并根据结果设置零标志和进位标志。<br>注意，我们将结果限制在 8 位范围内（<code>&amp;= 255</code>），并更新指令执行所花费的机器周期 <code>m</code> 和时钟周期 <code>t</code>。</p><pre><code class="language-javascript">/** * 将 E 寄存器的值加到 A 寄存器 * 算术指令用：ADD A, E */addRegisterE() {  this.registers.a += this.registers.e;  // 清除所有标志位并准备设置新的  this.registers.f = 0;  // 检查零标志和进位标志  this.setFlag(CPU_FLAGS.ZERO, !(this.registers.a &amp; 255)); // 结果为0则设置零标志  this.setFlag(CPU_FLAGS.CARRY, this.registers.a &gt; 255);   // 结果溢出255则设置进位标志  // 将结果限制为 8 位  this.registers.a &amp;= 255;  // 设置指令执行时间（1 机器周期，4 时钟周期)  this.registers.m = 1;  this.registers.t = 4;}</code></pre></li><li><p><code>CP A, B</code>（比较指令）：将寄存器 <code>a</code> 的值与寄存器 <code>b</code> 的值进行比较。这个指令实际上是执行 <code>a - b</code> 的操作，但不保存结果，只根据结果设置标志位。我们需要设置减法标志，并根据比较结果设置零标志（如果 <code>a == b</code>）和进位标志（如果 <code>a &lt; b</code>）。</p><pre><code class="language-javascript">/** * 比较 B 寄存器和 A 寄存器 * 用于条件判断和循环控制：CP A, B */compareRegisterB() {  // 创建 A 的副本并模拟 A - B  let result = this.registers.a;  result -= this.registers.b;  // 设置减法标志  this.registers.f = CPU_FLAGS.OPERATION;  // 检查 A 是否等于 B（结果为 0）以及 A 是否小于 B（结果为负，产生借位）  this.setFlag(CPU_FLAGS.ZERO, !(result &amp; 255)); // 结果为0则设置零标志  this.setFlag(CPU_FLAGS.CARRY, result &lt; 0);     // 结果为负（下溢）则设置进位标志  // 设置指令执行时间（1 机器周期，4 时钟周期)  this.registers.m = 1;  this.registers.t = 4;}</code></pre></li><li><p>NOP（无操作指令）：这个指令不做任何事情，仅仅消耗 CPU 周期，用来延时或指令对齐。</p><pre><code class="language-javascript">/** * 无操作指令，不执行任何操作只是浪费时间 * 延时或指令对齐用：NOP */noOperation() {  this.registers.m = 1;  this.registers.t = 4;}</code></pre></li><li><p>最后弄个调试工具，要打印出当前所有寄存器的十六进制值、标志位的状态以及时钟技术。</p><pre><code class="language-javascript">/** * 获取当前 CPU 状态的字符串表示，用于调试 */getStatusString() {  const r = this.registers;  return `CPU状态:  寄存器: A=${r.a.toString(16).padStart(2,'0')} B=${r.b.toString(16).padStart(2,'0')} C=${r.c.toString(16).padStart(2,'0')}          D=${r.d.toString(16).padStart(2,'0')} E=${r.e.toString(16).padStart(2,'0')} H=${r.h.toString(16).padStart(2,'0')} L=${r.l.toString(16).padStart(2,'0')}  标志位: F=${r.f.toString(16).padStart(2,'0')} [Z:${this.getFlag(CPU_FLAGS.ZERO)?1:0} N:${this.getFlag(CPU_FLAGS.OPERATION)?1:0} H:${this.getFlag(CPU_FLAGS.HALF_CARRY)?1:0} C:${this.getFlag(CPU_FLAGS.CARRY)?1:0}]  PC=${r.pc.toString(16).padStart(4,'0')} SP=${r.sp.toString(16).padStart(4,'0')}  时钟: M=${this.clock.m} T=${this.clock.t}`;}</code></pre></li></ul><h2 id="13-完整指令集与执行循环"><a class="markdownIt-Anchor" href="#13-完整指令集与执行循环"></a> 1.3. 完整指令集与执行循环</h2><p>在前面我们实现了几个示例指令，但真正的 GameBoy CPU 需要支持完整的 Z80 指令集。现代模拟器的核心是建立一个高效的「取值 → 解码 → 执行」循环，这个循环每秒要执行数百万次。</p><pre><code class="language-javascript">/** * 指令时序常量（T 周期） */const INSTRUCTION_TIMINGS = {  // 基础指令时序  NOP: 4,              // 0x00: NOP  LD_BC_nn: 12,        // 0x01: LD BC,nn  LD_MEM_BC_A: 8,      // 0x02: LD (BC),A  INC_BC: 8,           // 0x03: INC BC  INC_B: 4,            // 0x04: INC B  DEC_B: 4,            // 0x05: DEC B  LD_B_n: 8,           // 0x06: LD B,n    // 跳转指令  JR_s8: 12,           // 0x18: JR s8  JR_NZ_s8: 8,         // 0x20: JR NZ,s8 (8 if not taken, 12 if taken)  JR_Z_s8: 8,          // 0x28: JR Z,s8    // 算术指令  ADD_A_r: 4,          // 0x80-0x87: ADD A,r  SUB_r: 4,            // 0x90-0x97: SUB r  AND_r: 4,            // 0xA0-0xA7: AND r  CP_r: 4,             // 0xB8-0xBF: CP r    // 其他  HALT: 4,             // 0x76: HALT  RET: 16,             // 0xC9: RET};</code></pre><p>指令映射是现代模拟器的核心技术。我们创建了一个 256 元素的数组，每个元素对应一个操作码（opcode），直接指向对应的函数。这避免了复杂的 switch-case 语句，大幅提升执行效率：</p><pre><code class="language-javascript">/** * 构建指令映射表 */buildInstructionMap() {  const map = new Array(256);  // 基础指令集  map[0x00] = this.nop.bind(this);           // NOP  map[0x01] = this.ld_bc_nn.bind(this);     // LD BC,nn  map[0x02] = this.ld_mem_bc_a.bind(this);  // LD (BC),A  map[0x03] = this.inc_bc.bind(this);       // INC BC  map[0x04] = this.inc_b.bind(this);        // INC B  map[0x05] = this.dec_b.bind(this);        // DEC B  map[0x06] = this.ld_b_n.bind(this);       // LD B,n  // 跳转指令  map[0x18] = this.jr_s8.bind(this);        // JR s8  map[0x20] = this.jr_nz_s8.bind(this);     // JR NZ,s8  map[0x28] = this.jr_z_s8.bind(this);      // JR Z,s8  // 算术指令 - ADD A,r（批量注册）  for (let i = 0x80; i &lt;= 0x87; i++) {    map[i] = this.add_a_r.bind(this, i &amp; 0x07);  }  // 比较指令 - CP r（批量注册）  for (let i = 0xB8; i &lt;= 0xBF; i++) {    map[i] = this.cp_r.bind(this, i &amp; 0x07);  }  // 填充未实现的指令  for (let i = 0; i &lt; 256; i++) {    if (!map[i]) {      map[i] = this.unimplemented.bind(this, i);    }  }  return map;}</code></pre><p>CPU 执行的核心是 <code>step()</code> 方法。每次调用它会执行一条指令，这个方法每秒会被调用数百万次：</p><pre><code class="language-javascript">/** * 执行单条指令 */step() {  if (this.halted || this.stopped) {    // CPU 处于暂停状态，只更新时钟    this.registers.t = 4;    this.registers.m = 1;    this.updateClocks();    return;  }  if (!this.mmu) {    throw new Error('CPU 未连接到 MMU');  }  try {    // 取指令：从 PC 指向的内存地址读取操作码    const opcode = this.mmu.readByte(this.registers.pc);    this.registers.pc = (this.registers.pc + 1) &amp; 0xFFFF;    // 记录指令（用于调试）    this.stats.lastInstruction = opcode;    // 解码并执行：直接通过映射表调用对应函数    this.instructionMap[opcode]();    // 更新统计    this.stats.instructionsExecuted++;    this.stats.lastCycles = this.registers.t;    this.stats.totalCycles += this.registers.t;    // 更新时钟    this.updateClocks();  } catch (error) {    console.error(`❌ CPU 执行错误 PC=0x${this.registers.pc.toString(16).padStart(4, '0')}:`, error);    throw error;  }}</code></pre><p>为了简化指令实现，我们提供了一组辅助方法来处理常见的寄存器操作：</p><pre><code class="language-javascript">/** * 获取寄存器值（按编号） */getRegisterValue(regNum) {  switch (regNum) {    case 0: return this.registers.b;    case 1: return this.registers.c;    case 2: return this.registers.d;    case 3: return this.registers.e;    case 4: return this.registers.h;    case 5: return this.registers.l;    case 6: return this.mmu.readByte(this.getHL()); // (HL)    case 7: return this.registers.a;    default: return 0;  }}/** * 获取 16 位寄存器组合 */getBC() { return (this.registers.b &lt;&lt; 8) | this.registers.c; }getDE() { return (this.registers.d &lt;&lt; 8) | this.registers.e; }getHL() { return (this.registers.h &lt;&lt; 8) | this.registers.l; }setBC(value) {  this.registers.b = (value &gt;&gt; 8) &amp; 0xFF;  this.registers.c = value &amp; 0xFF;}</code></pre><h2 id="14-导出"><a class="markdownIt-Anchor" href="#14-导出"></a> 1.4. 导出</h2><p>在文件的最下方、<code>GameBoyCPU</code> 类的外部添加导出代码：</p><pre><code class="language-javascript">if (typeof module !== 'undefined' &amp;&amp; module.exports) {  // Node.js 环境导出  module.exports = { GameBoyCPU, CPU_FLAGS, INSTRUCTION_TIMINGS };} else if (typeof window !== 'undefined') {  // 浏览器环境导出到全局对象  window.GameBoyCPU = GameBoyCPU;  window.CPU_FLAGS = CPU_FLAGS;  window.INSTRUCTION_TIMINGS = INSTRUCTION_TIMINGS;}</code></pre><h1 id="2-模拟内存管理单元"><a class="markdownIt-Anchor" href="#2-模拟内存管理单元"></a> 2. 模拟内存管理单元</h1><p>我们的 GameBoy CPU 骨架虽然能够执行指令并管理内存寄存器，但是一个没有内存的 CPU 就跟一个没有书的图书馆差不多，光有管理员也没啥用。CPU 必需能够与外部内存交互，才能读取程序代码、存取数据，并与各种硬件组件通信。</p><p>这就是 <strong>内存管理单元</strong>（MMU）的作用。MMU 负责管理 GameBoy 的整个 64KB 的地址空间，并将 CPU 的内存访问请求路由到正确的物理内存区域。</p><blockquote><p>为什么需要 MMU？（大白话 + 1）</p><p>想象你在管理一个大仓库，有多大呢？GameBoy 的 64KB 内存相当于有 65536 个格子，你的大仓库也有这 65536 个格子：</p><ul><li>有些格子放游戏程序（ROM）</li><li>有些格子放临时数据（RAM）</li><li>有些格子放图片数据（VRAM）</li><li>有些格子是控制按钮（I / O 寄存器）</li></ul><p>CPU 依然是那个工人。假设他想要 <code>0x8000</code> 地址的数据。</p><p>如果没有 MMU 的话，CPU 就得自己跑到 <code>0x8000</code> 格子、搞清楚这个格子到底存的是什么、自行处理各种复杂情况。</p><p>有了 MMU 的话，CPU 只需要说他要 <code>0x8000</code> 的数据，MMU 就会：</p><ol><li>「<code>0x8000</code> 是图片数据区域。」</li><li>「这个区域的数据在 VRAM 里。」</li><li>「给你！」</li></ol><p>这样看，MMU 就像是一个很靠谱的仓库管理员。</p></blockquote><h2 id="21-gameboy-内存映射"><a class="markdownIt-Anchor" href="#21-gameboy-内存映射"></a> 2.1. GameBoy 内存映射</h2><p>与现代计算机复杂的内存管理不同，GameBoy 的内存映射相对直观，但仍然包含了多个不同功能的区域。理解这个内存映射对于正确模拟 GameBoy 至关重要。</p><p>GameBoy 的 64KB 地址空间被划分为以下主要区域：</p><ul><li><code>0x0000 - 0x3FFF</code>：卡带 ROM 银行 0<br>这是游戏卡带程序的第一个 16KB 区域，始终可访问。<ul><li><code>0x0000 - 0x00FF</code>：BIOS：GameBoy 启动时，CPU 从 <code>0x0000</code> 地址开始执行 BIOS 代码。一旦 BIOS 运行完毕，这片区域就会被卡带 ROM 覆盖，不再可访问。</li><li><code>0x0100 - 0x014F</code>：卡带头部：这部分包含游戏的名称、制造商、ROM / RAM 大小等关键信息。</li></ul></li><li><code>0x4000 - 0x7FFF</code>：卡带 ROM 其他银行<br>对于大于 32KB 的游戏，卡带会包含多个 16KB 的 ROM 银行。MMU 需要通过 <strong>内存银行控制器</strong>（MBC）来切换这些银行，以便 CPU 能够访问整个游戏程序。对于 32KB 或更小的游戏，这个区域也直接是 ROM 的一部分，无需银行切换。</li><li><code>0x8000 - 0x9FFF</code>：视频 RAM<br>存储用于渲染游戏背景和精灵图形数据。这部分内存对 CPU 可读写，但主要由图形处理单元（GPU）使用。</li><li><code>0xA000 - 0xBFFF</code>：卡带外部 RAM<br>部分游戏卡带会包含额外的可读写内存，用于保存游戏进度或临时数据。</li><li><code>0xC000 - 0xDFFF</code>：工作 RAM<br>这是 GameBoy 内部的主工作内存，CPU 可以自由读写，用于存储程序变量、栈等。</li><li><code>0xE000 - 0xFDFF</code>：工作 RAM 镜像<br>由于硬件接线的设计，工作 RAM 在内存映射中有一个完全相同的镜像区域。这意味着对 <code>0xE000-0xFDFF</code> 的读写实际上是对 <code>0xC000-0xDFFF</code> 的读写。</li><li><code>0xFE00 - 0xFE9F</code>：精灵属性表<br>存储屏幕上所有精灵（例如角色、敌人）的位置、大小、图形数据索引等属性信息。</li><li><code>0xFF00 - 0xFF7F</code>：内存映射 I / O 寄存器<br>这个区域包含了控制 GameBoy 各个硬件子系统（如图形、声音、定时器、输入）的寄存器。CPU 通过读写这些地址来控制硬件行为。</li><li><code>0xFF80 - 0xFFFF</code>：零页 RAM<br>又称「高速 RAM」，这片区域是 GameBoy 最顶部的内存，CPU 访问它们的速度最快。虽然地址很高，但因其在汇编编程中的常用性，常被称为「零页」。</li></ul><blockquote><p>太复杂了看不懂、一图胜千言版本：</p><p>GameBoy 的 64KB 内存就像一栋 8 层楼的公寓：</p><p>🏢 GameBoy 内存公寓（64KB）<br>├── 8 楼（<code>0xFF00-0xFFFF</code>）控制中心（按钮、音量调节等）<br>├── 7 楼（<code>0xFE00-0xFEFF</code>）精灵属性（角色信息）<br>├── 6 楼（<code>0xE000-0xFDFF</code>）工作区镜像（楼下的复印件）<br>├── 5 楼（<code>0xC000-0xDFFF</code>）工作区（临时文件柜）<br>├── 4 楼（<code>0xA000-0xBFFF</code>）卡带存档（游戏进度）<br>├── 3 楼（<code>0x8000-0x9FFF</code>）图片仓库（所有图像数据）<br>├── 2 楼（<code>0x4000-0x7FFF</code>）游戏程序（第 2 部分）<br>└── 1 楼（<code>0x0000-0x3FFF</code>）游戏程序（第 1 部分）<br>└── 地下室（<code>0x0000-0x00FF</code>）开机程序（BIOS）</p><p>每次 CPU 说他想要 <code>0x8000</code> 的数据，MMU 就知道：「哦，你要 3 楼图片仓库的东西。」</p></blockquote><p>为了在代码中清晰地表示这些区域，我们定义一个 <code>MEMORY_REGIONS</code> 常量对象：</p><pre><code class="language-javascript">/** * 内存区域常量定义 */const MEMORY_REGIONS = {  // ROM 区域  ROM_BANK_0_START: 0x0000,  ROM_BANK_0_END: 0x3FFF,  ROM_BANK_1_START: 0x4000,  ROM_BANK_1_END: 0x7FFF,  // BIOS 区域（在 ROM 银行 0 内）  BIOS_START: 0x0000,  BIOS_END: 0x00FF,  BIOS_EXIT_POINT: 0x0100,  // 卡带头部（在 ROM 银行 0 内）  CARTRIDGE_HEADER_START: 0x0100,  CARTRIDGE_HEADER_END: 0x014F,  // 视频 RAM  VRAM_START: 0x8000,  VRAM_END: 0x9FFF,  VRAM_SIZE: 0x2000, // 8KB  // 外部 RAM  ERAM_START: 0xA000,  ERAM_END: 0xBFFF,  ERAM_SIZE: 0x2000, // 8KB  // 工作 RAM  WRAM_START: 0xC000,  WRAM_END: 0xDFFF,  WRAM_SIZE: 0x2000, // 8KB  // 工作 RAM 镜像  WRAM_SHADOW_START: 0xE000,  WRAM_SHADOW_END: 0xFDFF,  // 精灵属性内存  OAM_START: 0xFE00,  OAM_END: 0xFE9F,  OAM_SIZE: 0xA0, // 160 字节  // I/O 寄存器  IO_START: 0xFF00,  IO_END: 0xFF7F,  // 零页 RAM  ZRAM_START: 0xFF80,  ZRAM_END: 0xFFFF,  ZRAM_SIZE: 0x80 // 128 字节};</code></pre><h2 id="22-mmu-类结构与初始化"><a class="markdownIt-Anchor" href="#22-mmu-类结构与初始化"></a> 2.2. MMU 类结构与初始化</h2><p>我们的 <code>GameBoyMMU</code> 类会负责创建和管理这些内存区域的实际存储（用 <code>Unit8Array</code>），并提供读写内存的接口。</p><p>在构造函数里，首先要调用 <code>initializeMemoryRegions</code> 来分配各个内存区域的存储空间，然后调用 <code>reset</code> 方法将它们清空并设置初始状态。</p><pre><code class="language-javascript">/** * GameBoy 内存管理单元类 */class GameBoyMMU {  constructor() {    this.initializeMemoryRegions();    this.reset();  }  /**   * 初始化所有内存区域   */  initializeMemoryRegions() {    // BIOS 数据（256 字节），GameBoy 启动代码    this.bios = new Uint8Array(256);        // 卡带 ROM 数据（最大 32KB 基础 ROM）    this.rom = new Uint8Array(0x8000); // 32KB 初始空间        // 视频 RAM（8KB），存储背景和精灵图形数据    this.vram = new Uint8Array(MEMORY_REGIONS.VRAM_SIZE);        // 外部 RAM（8KB），卡带上的额外可写内存    this.eram = new Uint8Array(MEMORY_REGIONS.ERAM_SIZE);        // 工作 RAM（8KB），GameBoy 内部 RAM    this.wram = new Uint8Array(MEMORY_REGIONS.WRAM_SIZE);        // 零页 RAM（128 字节），高速访问内存    this.zram = new Uint8Array(MEMORY_REGIONS.ZRAM_SIZE);        // 精灵属性内存（160 字节），存储精灵位置和属性    this.oam = new Uint8Array(MEMORY_REGIONS.OAM_SIZE);        // I/O 寄存器映射（128 字节），硬件控制寄存器    this.ioRegisters = new Uint8Array(0x80);  }  /**   * 重置 MMU 到初始状态   */  reset() {    // BIOS 映射标志，控制是否显示 BIOS 区域    this.biosEnabled = true;        // 清空所有可写内存区域    this.vram.fill(0);    this.eram.fill(0);    this.wram.fill(0);    this.zram.fill(0);    this.oam.fill(0);    this.ioRegisters.fill(0);        console.log('MMU 已重置到初始状态');  }}</code></pre><h2 id="23-内存读取"><a class="markdownIt-Anchor" href="#23-内存读取"></a> 2.3. 内存读取</h2><p>MMU 最核心的功能就是根据 CPU 请求的地址，将其路由到正确的内存区域并返回数据。<code>readByte(address)</code> 方法实现了这一逻辑：它根据 16 位地址的不同范围，返回对应 <code>Uint8Array</code> 中的字节。</p><p>这里需要特别注意 BIOS 区域的逻辑：当 CPU 程序计数器 <code>PC</code> 达到 <code>0x0100</code> 时，表明 BIOS 已经执行完毕，此时我们会禁用 BIOS 映射（<code>this.biosEnabled = false;</code>），让该地址范围（<code>0x0000-0x00FF</code>）切换到显示卡带 ROM。</p><pre><code class="language-javascript">// ... 之前写的方法 .../** * 从指定地址读取 8 位字节 * 根据地址范围路由到相应的内存区域 * @param {number} address 16 位内存地址（0x0000-0xFFFF） * @returns {number} 8 位数据值（0x00-0xFF） */readByte(address) {  // 确保地址在 16 位范围内  address &amp;= 0xFFFF;  // 根据地址高 4 位进行初步分类，提升性能  switch (address &amp; 0xF000) {    // 0x0000-0x0FFF: BIOS/ROM 银行 0 区域    case 0x0000: {      // 检查是否在 BIOS 区域且 BIOS 已启用      if (this.biosEnabled &amp;&amp; address &lt; MEMORY_REGIONS.BIOS_EXIT_POINT) {        return this.bios[address];      }      // BIOS 退出检查：当 PC 到达 0x0100 时禁用 BIOS      // TODO: 这里依赖于全局的 cpu 实例，后续可以考虑通过依赖注入优化      if (address === MEMORY_REGIONS.BIOS_EXIT_POINT &amp;&amp; window.cpu?.registers?.pc === MEMORY_REGIONS.BIOS_EXIT_POINT) {        this.biosEnabled = false;        console.log('BIOS已退出，切换到卡带ROM');      }      return this.rom[address]; // 否则读取 ROM    }    // 0x1000-0x3FFF: ROM 银行 0 的其余部分    case 0x1000:    case 0x2000:    case 0x3000:      return this.rom[address];    // 0x4000-0x7FFF: ROM 银行 1（可切换） - 基础模拟中直接从 rom 读取    case 0x4000:    case 0x5000:    case 0x6000:    case 0x7000:      return this.rom[address];    // 0x8000-0x9FFF: 视频 RAM    case 0x8000:    case 0x9000:      return this.vram[address &amp; 0x1FFF]; // 限制在 8KB（0x2000）范围内    // 0xA000-0xBFFF: 外部 RAM    case 0xA000:    case 0xB000:      return this.eram[address &amp; 0x1FFF]; // 限制在 8KB 范围内    // 0xC000-0xDFFF: 工作 RAM    case 0xC000:    case 0xD000:      return this.wram[address &amp; 0x1FFF]; // 限制在 8KB 范围内    // 0xE000-0xEFFF: 工作 RAM 镜像    case 0xE000:      return this.wram[address &amp; 0x1FFF]; // 映射到工作 RAM    // 0xF000-0xFFFF: 复杂区域 - 包含 RAM 镜像、OAM、I/O、零页 RAM    case 0xF000:      return this.readHighMemoryRegion(address); // 调用辅助函数处理高地址区域    default:      console.warn(`未处理的内存读取地址: 0x${address.toString(16).padStart(4, '0')}`);      return 0xFF; // 返回未连接总线的典型值（全1）  }}/** * 处理高内存区域的读取（0xF000-0xFFFF） * 这个区域包含多个不同的内存映射，需要进一步细分 * @param {number} address 内存地址 * @returns {number} 读取的数据 */readHighMemoryRegion(address) {  // 根据地址的中间 4 位进一步分类  switch (address &amp; 0x0F00) {    // 0xF000-0xFDFF: 工作 RAM 镜像的剩余部分    case 0x000: case 0x100: case 0x200: case 0x300:    case 0x400: case 0x500: case 0x600: case 0x700:    case 0x800: case 0x900: case 0xA00: case 0xB00:    case 0xC00: case 0xD00:      return this.wram[address &amp; 0x1FFF];    // 0xFE00-0xFEFF: 精灵属性内存区域（OAM）    case 0xE00:      if (address &lt; 0xFEA0) {        // 有效的 OAM 区域（0xFE00-0xFE9F）        return this.oam[address &amp; 0xFF]; // 限制在 160 字节（0xA0）范围内      } else {        // 0xFEA0-0xFEFF: 未使用区域，读取通常返回 0 或 0xFF，这里统一返回 0        return 0;      }    // 0xFF00-0xFFFF: I/O 寄存器和零页 RAM    case 0xF00:      if (address &gt;= MEMORY_REGIONS.ZRAM_START) {        // 0xFF80-0xFFFF: 零页 RAM        return this.zram[address &amp; 0x7F]; // 限制在 128 字节（0x80）范围内      } else {        // 0xFF00-0xFF7F: I/O 寄存器        return this.readIORegister(address); // 调用辅助函数处理 I/O 寄存器读取      }    default:      return 0xFF; // 未知区域返回 0xFF  }}/** * 读取 I/O 寄存器 * 这些寄存器控制 GameBoy 的各个硬件子系统。 * TODO: 目前只是返回其在内部数组中的值，具体硬件逻辑将在后续章节实现。 * @param {number} address I/O 寄存器地址（0xFF00-0xFF7F） * @returns {number} 寄存器值 */readIORegister(address) {  const registerIndex = address - MEMORY_REGIONS.IO_START;  // 返回 I/O 寄存器数组中的值，如果超出范围则返回 0（或 0xFF）  return this.ioRegisters[registerIndex] || 0;}/** * 从指定地址读取 16 位字（小端序 - Little Endian） * GameBoy CPU 使用小端序存储多字节数据，即低位字节在前。 * @param {number} address 起始地址 * @returns {number} 16位值 */readWord(address) {  const lowByte = this.readByte(address);  const highByte = this.readByte(address + 1);  return lowByte | (highByte &lt;&lt; 8); // 将高位字节左移 8 位后与低位字节合并}</code></pre><h2 id="24-内存写入"><a class="markdownIt-Anchor" href="#24-内存写入"></a> 2.4. 内存写入</h2><p>内存写入的逻辑与读取类似，<code>writeByte(address, value)</code> 方法根据地址将数据写入对应的内存区域。需要注意的是，ROM 区域通常是只读的，任何写入操作都会被忽略（除了用于内存银行切换的特殊地址，这将在后面讨论）。</p><pre><code class="language-javascript">// ... 之前写的方法 .../** * 向指定地址写入 8 位字节 * 根据地址范围路由到相应的内存区域 * @param {number} address 16 位内存地址 * @param {number} value 8 位数据值 */writeByte(address, value) {  // 确保地址和值在有效范围内  address &amp;= 0xFFFF;  value &amp;= 0xFF;  // 根据地址高 4 位进行分类  switch (address &amp; 0xF000) {    // 0x0000-0x7FFF: ROM 区域 - 通常只读，但可能有银行切换逻辑    case 0x0000: case 0x1000: case 0x2000: case 0x3000:    case 0x4000: case 0x5000: case 0x6000: case 0x7000:      this.handleROMWrite(address, value); // 专门处理 ROM 区域的写入      break;    // 0x8000-0x9FFF: 视频 RAM - 可写    case 0x8000:    case 0x9000:      this.vram[address &amp; 0x1FFF] = value;      break;    // 0xA000-0xBFFF: 外部 RAM - 可写    case 0xA000:    case 0xB000:      this.eram[address &amp; 0x1FFF] = value;      break;    // 0xC000-0xDFFF: 工作 RAM - 可写    case 0xC000:    case 0xD000:      this.wram[address &amp; 0x1FFF] = value;      break;    // 0xE000-0xEFFF: 工作 RAM 镜像 - 写入映射到工作 RAM    case 0xE000:      this.wram[address &amp; 0x1FFF] = value;      break;    // 0xF000-0xFFFF: 高内存区域    case 0xF000:      this.writeHighMemoryRegion(address, value); // 调用辅助函数处理高地址区域写入      break;    default:      console.warn(`未处理的内存写入地址: 0x${address.toString(16).padStart(4, '0')}`);  }}/** * 处理 ROM 区域的写入 * ROM 通常是只读的。在基础模拟中，任何对 ROM 区域的写入都会被忽略。 * TODO: 在未来的内存银行章节中，这里将包含处理卡带内存银行控制器的逻辑。 * @param {number} address 地址 * @param {number} value 值 */handleROMWrite(address, value) {  console.log(`ROM写入被忽略: 地址=0x${address.toString(16).padStart(4, '0')}, 值=0x${value.toString(16).padStart(2, '0')}`);}/** * 处理高内存区域的写入（0xF000-0xFFFF） * @param {number} address 地址 * @param {number} value 值 */writeHighMemoryRegion(address, value) {  switch (address &amp; 0x0F00) {    // 0xF000-0xFDFF: 工作 RAM 镜像 - 写入映射到工作 RAM    case 0x000: case 0x100: case 0x200: case 0x300:    case 0x400: case 0x500: case 0x600: case 0x700:    case 0x800: case 0x900: case 0xA00: case 0xB00:    case 0xC00: case 0xD00:      this.wram[address &amp; 0x1FFF] = value;      break;    // 0xFE00-0xFEFF: 精灵属性内存（OAM）    case 0xE00:      if (address &lt; 0xFEA0) {        this.oam[address &amp; 0xFF] = value;      }      // 0xFEA0-0xFEFF 区域的写入通常被忽略      break;    // 0xFF00-0xFFFF: I/O 寄存器和零页 RAM    case 0xF00:      if (address &gt;= MEMORY_REGIONS.ZRAM_START) {        // 零页 RAM        this.zram[address &amp; 0x7F] = value;      } else {        // I/O 寄存器        this.writeIORegister(address, value);      }      break;  }}/** * 写入 I/O 寄存器 * @param {number} address I/O 寄存器地址 * @param {number} value 要写入的值 */writeIORegister(address, value) {  const registerIndex = address - MEMORY_REGIONS.IO_START;  this.ioRegisters[registerIndex] = value;  // TODO: 在后续章节中，这里将处理特定 I/O 寄存器写入的副作用  // 例如：当写入显示控制寄存器时触发屏幕更新，或写入声音寄存器时播放声音}/** * 向指定地址写入 16 位字（小端序） * @param {number} address 起始地址 * @param {number} value 16 位值 */writeWord(address, value) {  this.writeByte(address, value &amp; 0xFF);            // 写入低位字节  this.writeByte(address + 1, (value &gt;&gt; 8) &amp; 0xFF); // 写入高位字节}</code></pre><h2 id="25-加载-rom-与-bios"><a class="markdownIt-Anchor" href="#25-加载-rom-与-bios"></a> 2.5. 加载 ROM 与 BIOS</h2><p>为了让模拟器能够运行游戏，MMU 还需要加载 BIOS 和游戏 ROM 的功能：</p><ul><li><code>loadBIOS(biosData)</code>：加载 GameBoy 的 BIOS 文件<ul><li>BIOS 是启动时运行的一小段程序，通常用于初始化硬件和显示任天堂的标志</li></ul></li><li><code>loadROM(romData)</code>：加载游戏卡带的 ROM 数据。这个方法会将 ROM 数据复制到 MMU 内部的 <code>this.rom</code> 数组中</li><li><code>loadROMFromURL(url)</code>：直接从给定的 URL 下载 ROM 文件并加载</li></ul><p><code>displayCartridgeInfo()</code> 方法则会从 ROM 的卡带头部读取并打印出游戏的标题、类型、ROM 大小和 RAM 大小等信息，这对于验证 ROM 是否正确加载非常有用。</p><pre><code class="language-javascript">// ... 之前写的方法 .../** * 加载 BIOS 数据 * @param {Uint8Array|Array} biosData BIOS 数据数组（应为 256 字节） */loadBIOS(biosData) {  if (biosData.length !== 256) {    throw new Error('BIOS 数据必须正好是 256 字节');  }  this.bios.set(biosData); // 将传入的 BIOS 数据复制到内部存储  this.biosEnabled = true; // 确保 BIOS 映射处于启用状态  console.log('BIOS 已加载');}/** * 加载 ROM 文件 * @param {Uint8Array|ArrayBuffer} romData ROM 数据 */loadROM(romData) {  // 转换为 Uint8Array（如果传入的是 ArrayBuffer）  const rom = romData instanceof ArrayBuffer ? new Uint8Array(romData) : romData;  // 确保 ROM 不超过 MMU 分配的最大支持大小  const maxSize = this.rom.length;  if (rom.length &gt; maxSize) {    console.warn(`ROM 大小 ${rom.length} 字节超过最大支持大小 ${maxSize} 字节，将被截断`);  }  // 复制 ROM 数据到内部存储，只复制有效部分  const copySize = Math.min(rom.length, maxSize);  this.rom.set(rom.slice(0, copySize));  console.log(`ROM 已加载，大小: ${copySize} 字节`);  // 显示卡带信息，验证 ROM 是否加载正确  this.displayCartridgeInfo();}/** * 显示卡带头部信息 * 从 ROM 的特定地址读取游戏元数据 */displayCartridgeInfo() {  // 读取卡带标题（0x0134-0x0143）  let title = '';  for (let i = 0x0134; i &lt;= 0x0143; i++) {    const char = this.rom[i];    if (char === 0) break; // 标题以空字符结束    title += String.fromCharCode(char);  }  // 读取卡带类型（0x0147）  const cartridgeType = this.rom[0x0147];  // 读取 ROM 大小（0x0148）  const romSizeCode = this.rom[0x0148];  // 根据 GameBoy 规范计算 ROM 实际大小，32KB * (2^romSizeCode)  const romSize = 32 * (1 &lt;&lt; romSizeCode); // KB  // 读取 RAM 大小（0x0149）  const ramSizeCode = this.rom[0x0149];  // 根据 GameBoy 规范定义 RAM 大小映射  const ramSizes = [0, 2, 8, 32, 128, 64]; // KB  const ramSize = ramSizes[ramSizeCode] || 0; // 处理未知编码  console.log('=== 卡带信息 ===');  console.log(`标题: ${title}`);  console.log(`卡带类型: 0x${cartridgeType.toString(16).padStart(2, '0')}`);  console.log(`ROM 大小: ${romSize}KB`);  console.log(`RAM 大小: ${ramSize}KB`);}/** * 异步加载 ROM 文件（从 URL） * @param {string} url ROM 文件 URL */async loadROMFromURL(url) {  try {    console.log(`正在加载ROM: ${url}`);    const response = await fetch(url); // 发起网络请求    if (!response.ok) {      throw new Error(`HTTP错误: ${response.status}`);    }    const romData = await response.arrayBuffer(); // 获取二进制数据    this.loadROM(romData); // 调用 loadROM 进行处理  } catch (error) {    console.error('ROM加载失败:', error);    throw error; // 重新抛出错误以便外部捕获  }}/** * 获取内存使用情况统计（用于调试） * @returns {Object} 内存使用统计对象 */getMemoryStats() {  return {    biosEnabled: this.biosEnabled,    romLoaded: this.rom.some(byte =&gt; byte !== 0), // 检查 ROM 是否包含数据    memoryRegions: {      bios: { size: this.bios.length, used: this.bios.some(byte =&gt; byte !== 0) },      rom: { size: this.rom.length, used: this.rom.some(byte =&gt; byte !== 0) },      vram: { size: this.vram.length, used: this.vram.some(byte =&gt; byte !== 0) },      eram: { size: this.eram.length, used: this.eram.some(byte =&gt; byte !== 0) },      wram: { size: this.wram.length, used: this.wram.some(byte =&gt; byte !== 0) },      zram: { size: this.zram.length, used: this.zram.some(byte =&gt; byte !== 0) },      oam: { size: this.oam.length, used: this.oam.some(byte =&gt; byte !== 0) }    }  };}/** * 获取内存转储（用于调试） * 以十六进制和 ASCII 形式显示内存内容 * @param {number} startAddr 起始地址 * @param {number} length 要转储的长度 * @returns {string} 十六进制转储字符串 */getMemoryDump(startAddr, length = 256) {  let dump = `内存转储 (0x${startAddr.toString(16).padStart(4, '0')} - 0x${(startAddr + length - 1).toString(16).padStart(4, '0')}):\n`;  // 每行显示 16 个字节  for (let i = 0; i &lt; length; i += 16) {    const addr = startAddr + i;    let line = `${addr.toString(16).padStart(4, '0')}: `; // 地址部分    let ascii = ''; // ASCII 可视化部分    for (let j = 0; j &lt; 16 &amp;&amp; (i + j) &lt; length; j++) {      const byte = this.readByte(addr + j);      line += `${byte.toString(16).padStart(2, '0')} `; // 十六进制字节      // 将可打印字符转换为 ASCII，否则显示 '.'      ascii += (byte &gt;= 32 &amp;&amp; byte &lt;= 126) ? String.fromCharCode(byte) : '.';    }    line = line.padEnd(50, ' ') + ascii; // 填充空格对齐    dump += line + '\n';  }  return dump;}</code></pre><h2 id="26-mmu-与-cpu-的连接"><a class="markdownIt-Anchor" href="#26-mmu-与-cpu-的连接"></a> 2.6. MMU 与 CPU 的连接</h2><p>现在我们有了 <code>GameBoyCPU</code> 和 <code>GameBoyMMU</code> 两个类。CPU 需要一个方式来与 MMU 交互，才能真正实现「取指」和「读写内存」的功能。最简单的方式就是将 MMU 实例作为参数传递给 CPU，或者让 CPU 拥有一个 MMU 的引用。</p><p>不过也别忘了在 <code>mmu.js</code> 中导出 <code>GameBoyMMU</code> 类和常量：</p><pre><code class="language-javascript">if (typeof module !== 'undefined' &amp;&amp; module.exports) {  // Node.js 环境导出  module.exports = { GameBoyMMU, MEMORY_REGIONS };} else if (typeof window !== 'undefined') {  // 浏览器环境导出到全局对象  window.GameBoyMMU = GameBoyMMU;  window.MEMORY_REGIONS = MEMORY_REGIONS;}</code></pre><p>然后在 <code>GameBoyCPU</code> 类中，我们可以添加一个对 MMU 的引用：</p><pre><code class="language-javascript">class GameBoyCPU {  constructor(mmu) { // 接收 MMU 实例    this.mmu = mmu; // 存储 MMU 引用    // ... 其他寄存器和时钟初始化 ...  }  // 示例：实现一个 LD A, (HL) 指令  // 将 HL 寄存器指向的内存地址的值加载到 A 寄存器  loadAToHL() {    const address = (this.registers.h &lt;&lt; 8) | this.registers.l; // 合并 H 和 L 得到 16 位地址    this.registers.a = this.mmu.readByte(address); // 通过 MMU 读取内存    this.registers.m = 2; // 假设这条指令需要 2 机器周期    this.registers.t = 8; // 假设这条指令需要 8 时钟周期  }  // ... 其他指令和方法 ...}</code></pre><p>这样，CPU 就可以通过 <code>this.mmu.readByte()</code>、<code>this.mmu.writeByte()</code> 等方法来访问内存了。</p><h1 id="3-gpu-时序让-gameboy-屏幕动起来"><a class="markdownIt-Anchor" href="#3-gpu-时序让-gameboy-屏幕动起来"></a> 3. GPU 时序：让 GameBoy 屏幕动起来</h1><p>先前我们已经构建了 GameBoy 模拟器的 CPU 骨架和 MMU，让模拟器能够加载游戏 ROM 并开始执行指令。但是一个没有图像输出的模拟器是没有灵魂的！现在我们得引入 GameBoy 的主要输出设备 —— <strong> 图形处理单元</strong> 也就是我们经常说到的 GPU 了。</p><p>GameBoy 的官方内部名称是「点阵式游戏机」（Dot Matrix Game），这是因为它靠着一块 160x144 像素的单色 LCD 屏幕来显示内容。为了模拟这个屏幕，我们可以在 Web 页面中使用一个 HTML5 <code>&lt;canvas&gt;</code> 元素。这个 Canvas 将作为我们的「帧缓冲区」，其中每个像素的颜色都可以被直接操作。</p><h2 id="31-模拟屏幕与帧缓冲区"><a class="markdownIt-Anchor" href="#31-模拟屏幕与帧缓冲区"></a> 3.1. 模拟屏幕与帧缓冲区</h2><p>要将 GameBoy 的图形输出呈现在网页上，最直接的方法就是创建一个与 GameBoy 屏幕尺寸相同的 Canvas。我们可以通过 Canvas 的 2D 渲染上下文来操作它的像素数据。</p><p>GameBoy 的显示分辨率是 160 像素宽和 140 像素高。Canvas 的像素数据通常以 RGBA（红、绿、蓝、透明度）的 4 字节序列存储。这意味着每个像素需要 4 个字节来表示其颜色。我们可以通过 <code>getImageData</code> 或 <code>createImageData</code> 方法获取或创建这个帧缓冲区。</p><p>首先，在 HTML 文件中添加一个 Canvas 元素：</p><pre><code class="language-html">&lt;canvas id="gameboy-screen" width="160" height="144"&gt;&lt;/canvas&gt;</code></pre><p>在 <code>GameBoyGPU</code> 类中，我们将负责初始化这个 Canvas 并创建帧缓冲区。我们还设置了 <code>imageSmoothingEnabled = false</code> 和 <code>image-rendering: pixelated</code> 样式，以确保图像在放大时保持像素艺术的清晰度，而不是变得模糊。</p><pre><code class="language-javascript">// ... 其他常量定义，之后写 .../** * GameBoy GPU 类 * 负责管理显示时序、渲染管线和帧缓冲区 */class GameBoyGPU {  constructor() {    this.initializeTimingState();    this.initializeCanvas();    this.initializeFrameBuffer();    console.log('GameBoy GPU 已初始化');  }  /**   * 初始化 Canvas 画布   */  initializeCanvas() {    // 尝试获取已存在的 canvas 元素    this.canvas = document.getElementById('gameboy-screen');    // 如果不存在，创建新的 canvas 并添加到页面    if (!this.canvas) {      this.canvas = this.createCanvas();    }    // 获取 2D 渲染上下文    this.context = this.canvas.getContext('2d');    if (!this.context) {      throw new Error('无法获取 Canvas 2D 渲染上下文');    }    // 禁用图像平滑，保持像素艺术风格    this.context.imageSmoothingEnabled = false;    console.log('Canvas 画布已初始化');  }  /**   * 创建新的 Canvas 元素   * @returns {HTMLCanvasElement} 创建的 canvas 元素   */  createCanvas() {    const canvas = document.createElement('canvas');    canvas.id = 'gameboy-screen';    canvas.width = DISPLAY_CONFIG.WIDTH;    canvas.height = DISPLAY_CONFIG.HEIGHT;    canvas.style.border = '2px solid #333';    canvas.style.imageRendering = 'pixelated'; // 保持像素完美缩放    canvas.style.imageRendering = '-moz-crisp-edges'; // Firefox    canvas.style.imageRendering = 'crisp-edges';      // Chrome/Edge    canvas.style.backgroundColor = '#9BBC0F'; // GameBoy 绿色背景    // 为了方便在 HTML 中演示，这里直接添加到 body    document.body.appendChild(canvas);    console.log('已创建新的 Canvas 元素');    return canvas;  }  /**   * 初始化帧缓冲区   * 使用 ImageData 对象作为屏幕的内存表示   */  initializeFrameBuffer() {    // 创建图像数据对象（帧缓冲区）    this.frameBuffer = this.context.createImageData(      DISPLAY_CONFIG.WIDTH,      DISPLAY_CONFIG.HEIGHT    );    // 初始化为白色背景    this.clearFrameBuffer();    console.log('帧缓冲区已初始化');  }  /**   * 清空帧缓冲区（设置为白色，或 GameBoy 默认背景色）   */  clearFrameBuffer() {    const data = this.frameBuffer.data;    // 设置所有像素为白色（255, 255, 255, 255）    for (let i = 0; i &lt; DISPLAY_CONFIG.BUFFER_SIZE; i += 4) {      data[i] = 255;      // R      data[i + 1] = 255;  // G      data[i + 2] = 255;  // B      data[i + 3] = 255;  // A (透明度)    }  }  /**   * 设置像素颜色（辅助函数）   * @param {number} x - X 坐标（0-159）   * @param {number} y - Y 坐标（0-143）   * @param {number} r - 红色分量（0-255）   * @param {number} g - 绿色分量（0-255）   * @param {number} b - 蓝色分量（0-255）   * @param {number} a - 透明度（0-255），默认 255   */  setPixel(x, y, r, g, b, a = 255) {    if (x &lt; 0 || x &gt;= DISPLAY_CONFIG.WIDTH || y &lt; 0 || y &gt;= DISPLAY_CONFIG.HEIGHT) {      return; // 越界检查    }    const pixelIndex = (y * DISPLAY_CONFIG.WIDTH + x) * 4;    const data = this.frameBuffer.data;    data[pixelIndex] = r;    data[pixelIndex + 1] = g;    data[pixelIndex + 2] = b;    data[pixelIndex + 3] = a;  }}</code></pre><p>现在，我们有一个可以操作的帧缓冲区。通过修改 <code>this.frameBuffer.data</code> 数组中的 RGBA 值，我们可以改变屏幕上任何像素的颜色。修改完成后，调用 <code>this.context.putImageData(this.frameBuffer, 0, 0)</code> 就可以将更新后的帧缓冲区内容绘制到 Canvas 上。</p><h2 id="32-栅格图形与显示时序"><a class="markdownIt-Anchor" href="#32-栅格图形与显示时序"></a> 3.2. 栅格图形与显示时序</h2><blockquote><p>GPU 工作原理：</p><p>我们可以看一下老式电视是如何显示画面的：</p><pre><code class="language-plaintext">电子枪从左到右扫描 →→→→→→→→→→→（一行画完）然后跳到下一行    ↓再从左到右扫描   →→→→→→→→→→→（下一行）...重复 144次 ...最后回到顶部     ↑↑↑↑↑↑↑↑↑（准备下一帧）</code></pre><p>GameBoy 的 GPU 完全模仿了这个过程。</p><p>1989 年的硬件很慢，一次只能处理一行像素，这样做也能省电省内存。当年的程序员很聪明，用最少的资源做最多的事。</p></blockquote><p>GameBoy 的显示硬件模拟了阴极射线管（CRT）的工作方式。在 CRT 显示器中，电子束逐行扫描屏幕，并在扫描完成后返回到屏幕顶部。这个扫描过程不是瞬间完成的，它包含了消隐期：</p><ul><li>水平消隐：电子束从一行的末尾移动到下一行的开头所需的时间</li><li>垂直消隐：在一帧结束后，电子束从屏幕底部回到屏幕左上角所需的时间。垂直消隐期通常比水平消隐期长得多，因为它需要移动更远的距离</li></ul><p>GameBoy 的显示器也遵循类似的模式，并将其工作周期细分为四个不同的 GPU 模式。这对于精确模拟非常重要，因为某些硬件操作只能在特定的 GPU 模式下进行。</p><table><thead><tr><th>周期</th><th>GPU 模式号</th><th>时间消耗（<code>t</code> 时钟周期）</th><th>描述</th></tr></thead><tbody><tr><td>OAM 搜索</td><td>2</td><td>80</td><td>GPU 扫描 OAM 获取当前扫描线上的精灵信息。</td></tr><tr><td>像素传输</td><td>3</td><td>172</td><td>GPU 从 VRAM 读取图块和地图数据并渲染像素。</td></tr><tr><td>水平消隐</td><td>0</td><td>204</td><td>当前扫描线渲染完成后的等待期。</td></tr><tr><td>一条扫描线总时间</td><td></td><td>456</td><td>(80 + 172 + 204)</td></tr><tr><td>垂直消隐</td><td>1</td><td>4560（10 行）</td><td>所有可见扫描线渲染完成后的等待期。</td></tr><tr><td>一帧总时间</td><td></td><td>70224</td><td>（456 * 154 行）</td></tr></tbody></table><blockquote><p>为什么是这些数字呢？</p><p>GPU 像是一个画家，每天画一行像素。</p><ol><li>准备阶段（80）：看看要画什么角色（OAM 搜索）</li><li>绘画阶段（172）：专心画这一行（像素传输）</li><li>休息阶段（204）：喝口水，准备下一行（水平消隐）</li><li>长休息（4560）：一张画完了，休息下（垂直消隐）</li></ol><p>因此我们的游戏不能随时访问 GPU。</p></blockquote><p>为了在模拟器中保持这些时序，我们需要一个 <code>step</code> 函数，它会在 CPU 每执行一条指令后被调用，并根据 CPU 消耗的时钟周期来推进 GPU 的内部时序状态。</p><p>我们定义 GPU 模式和时序常量：</p><pre><code class="language-javascript">/** * GPU 模式常量定义 * GameBoy GPU 有 4 种不同的工作模式，模拟 CRT 显示器的扫描过程 */const GPU_MODES = {  HBLANK: 0,        // 水平消隐期（扫描线结束后）  VBLANK: 1,        // 垂直消隐期（帧结束后）  OAM_SEARCH: 2,    // OAM 搜索期（精灵属性扫描）  PIXEL_TRANSFER: 3 // 像素传输期（VRAM 读取和渲染）};/** * GPU 时序常量（以 CPU 的 T 时钟周期为单位） * CPU 频率：4194304 Hz */const GPU_TIMINGS = {  // 扫描线时序  OAM_SEARCH_CYCLES: 80,      // 模式 2：OAM 访问时间  PIXEL_TRANSFER_CYCLES: 172, // 模式 3：VRAM 访问时间  HBLANK_CYCLES: 204,         // 模式 0：水平消隐时间  // 计算得出的时序  SCANLINE_CYCLES: 456,       // 一条扫描线总时间（80 + 172 + 204）  VBLANK_LINE_CYCLES: 456,    // 垂直消隐期每线时间  VBLANK_TOTAL_CYCLES: 4560,  // 垂直消隐总时间（456 * 10）  // 帧时序  VISIBLE_LINES: 144,         // 可见扫描线数量  VBLANK_LINES: 10,           // 垂直消隐扫描线数量  TOTAL_LINES: 154,           // 总扫描线数量（144 + 10）  FRAME_CYCLES: 70224         // 完整帧时间（456 * 154）};/** * 显示常量 */const DISPLAY_CONFIG = {  WIDTH: 160,                 // 屏幕宽度  HEIGHT: 144,                // 屏幕高度  BYTES_PER_PIXEL: 4,         // RGBA 格式，每像素 4 字节  TOTAL_PIXELS: 160 * 144,    // 总像素数  BUFFER_SIZE: 160 * 144 * 4  // 帧缓冲区大小};</code></pre><p>接下来，我们在 <code>GameBoyGPU</code> 类中初始化时序状态，并实现 <code>step</code> 方法：</p><pre><code class="language-javascript">// ... 之前写的其他方法 .../** * 初始化时序状态 */initializeTimingState() {  this.mode = GPU_MODES.OAM_SEARCH; // 初始 GPU 模式  this.modeClock = 0;                // 当前模式的时钟计数器  this.currentLine = 0;              // 当前扫描线号（0-153）  this.totalClock = 0;               // GPU 总时钟计数（累积）  this.frameCount = 0;               // 帧计数器  this.lastFrameTime = performance.now(); // 上次帧渲染时间（用于计算 FPS）}/** * 重置 GPU 到初始状态 */reset() {  this.initializeTimingState();  this.clearFrameBuffer();  this.updateDisplay(); // 更新 Canvas 以显示清空后的画面  console.log('GPU 已重置');}/** * GPU 时序步进函数 * 每次 CPU 执行指令后调用，根据 CPU 消耗的时钟周期推进 GPU 状态 * @param {number} cycles CPU 消耗的时钟周期数 */step(cycles) {  this.modeClock += cycles; // 累加当前模式下的时钟  this.totalClock += cycles; // 累加总时钟  // 根据当前模式处理时序逻辑  switch (this.mode) {    case GPU_MODES.OAM_SEARCH:      this.handleOAMSearchMode();      break;    case GPU_MODES.PIXEL_TRANSFER:      this.handlePixelTransferMode();      break;    case GPU_MODES.HBLANK:      this.handleHBlankMode();      break;    case GPU_MODES.VBLANK:      this.handleVBlankMode();      break;    default:      console.warn(`未知的 GPU 模式：${this.mode}`);      this.mode = GPU_MODES.OAM_SEARCH; // 恢复到默认模式  }}/** * 处理 OAM 搜索模式（模式 2） * 当模式时钟达到 OAM_SEARCH_CYCLES 时，切换到像素传输模式 */handleOAMSearchMode() {  if (this.modeClock &gt;= GPU_TIMINGS.OAM_SEARCH_CYCLES) {    this.modeClock = 0;    this.mode = GPU_MODES.PIXEL_TRANSFER;    // TODO: 在这个阶段，会进行 OAM 搜索逻辑，在第 7 章（精灵）中实现    this.searchOAM();  }}/** * 处理像素传输模式（模式 3） * 当模式时钟达到 PIXEL_TRANSFER_CYCLES 时，切换到水平消隐模式，并渲染当前扫描线 */handlePixelTransferMode() {  if (this.modeClock &gt;= GPU_TIMINGS.PIXEL_TRANSFER_CYCLES) {    this.modeClock = 0;    this.mode = GPU_MODES.HBLANK;    // 渲染当前扫描线    this.renderScanline();  }}/** * 处理水平消隐模式（模式 0） * 当模式时钟达到 HBLANK_CYCLES 时，递增扫描线，并根据扫描线数量决定进入 VBLANK 或下一条扫描线 */handleHBlankMode() {  if (this.modeClock &gt;= GPU_TIMINGS.HBLANK_CYCLES) {    this.modeClock = 0;    this.currentLine++; // 扫描线递增    if (this.currentLine === GPU_TIMINGS.VISIBLE_LINES) {      // 所有可见扫描线完成（0-143），进入垂直消隐模式      this.mode = GPU_MODES.VBLANK;      this.onFrameComplete(); // 通知一帧渲染完成    } else {      // 继续下一条扫描线，回到 OAM 搜索模式      this.mode = GPU_MODES.OAM_SEARCH;    }  }}/** * 处理垂直消隐模式（模式 1） * VBLANK 持续 10 条扫描线的时间。当模式时钟达到 VBLANK_LINE_CYCLES 时，递增扫描线， * 直到所有 VBLANK 扫描线完成，然后开始新的一帧。 */handleVBlankMode() {  if (this.modeClock &gt;= GPU_TIMINGS.VBLANK_LINE_CYCLES) {    this.modeClock = 0;    this.currentLine++; // 扫描线递增    if (this.currentLine &gt; GPU_TIMINGS.TOTAL_LINES - 1) {      // 垂直消隐结束（总共 154 条扫描线），开始新的一帧      this.currentLine = 0;      this.mode = GPU_MODES.OAM_SEARCH;      this.onNewFrameStart(); // 通知新帧开始    }  }}/** * OAM 搜索逻辑（占位函数） * 在第 7 章（精灵）中会实现完整的精灵处理逻辑 */searchOAM() {  // TODO: 实现精灵搜索逻辑  // 1. 扫描 OAM 表中的 40 个精灵  // 2. 找出在当前扫描线上的精灵（最多 10 个）  // 3. 按 X 坐标排序准备渲染}/** * 渲染当前扫描线 * TODO: 目前是一个简单的测试渲染，在第 4 章（图形）中会实现完整的背景和精灵渲染 */renderScanline() {  this.renderTestPattern(); // 渲染一个测试图案}/** * 渲染测试图案（用于验证 GPU 时序） * 在 Canvas 上显示彩色条纹，以验证扫描线渲染是否正常工作 */renderTestPattern() {  const data = this.frameBuffer.data;  const y = this.currentLine; // 当前要渲染的扫描线  // 为每条扫描线生成不同颜色的测试图案  for (let x = 0; x &lt; DISPLAY_CONFIG.WIDTH; x++) {    const pixelIndex = (y * DISPLAY_CONFIG.WIDTH + x) * 4;    // 创建彩色测试图案，使之随帧动画    const colorPhase = (x + y + this.frameCount) % 64;    if (colorPhase &lt; 16) {      // 红色渐变      data[pixelIndex] = 255;      data[pixelIndex + 1] = colorPhase * 16;      data[pixelIndex + 2] = colorPhase * 16;    } else if (colorPhase &lt; 32) {      // 绿色渐变      data[pixelIndex] = (32 - colorPhase) * 16;      data[pixelIndex + 1] = 255;      data[pixelIndex + 2] = (colorPhase - 16) * 16;    } else if (colorPhase &lt; 48) {      // 蓝色渐变      data[pixelIndex] = (colorPhase - 32) * 16;      data[pixelIndex + 1] = (48 - colorPhase) * 16;      data[pixelIndex + 2] = 255;    } else {      // 白色渐变      const brightness = (64 - colorPhase) * 16;      data[pixelIndex] = brightness;      data[pixelIndex + 1] = brightness;      data[pixelIndex + 2] = brightness;    }    data[pixelIndex + 3] = 255; // Alpha（完全不透明）  }}/** * 帧渲染完成回调 * 当一帧的所有可见扫描线渲染完成时调用。在这里我们将帧缓冲区显示到 Canvas。 */onFrameComplete() {  // 将帧缓冲区内容显示到 Canvas  this.updateDisplay();  // 更新帧计数和性能统计  this.frameCount++;  this.updatePerformanceStats();  // TODO: 触发垂直消隐中断（在第 8 章中断中实现）  this.triggerVBlankInterrupt();  console.log(`帧 ${this.frameCount} 渲染完成`);}/** * 新帧开始回调 * 当垂直消隐期结束，准备开始新的一帧渲染时调用。 */onNewFrameStart() {  // TODO: 为新帧做准备，例如：  // 1. 重置精灵计数器  // 2. 更新背景/窗口滚动寄存器  // 3. 处理显示控制寄存器变化}/** * 将帧缓冲区内容更新到 Canvas */updateDisplay() {  this.context.putImageData(this.frameBuffer, 0, 0);}/** * 更新性能统计，例如 FPS */updatePerformanceStats() {  const currentTime = performance.now();  const frameTime = currentTime - this.lastFrameTime;  this.lastFrameTime = currentTime;  // 计算 FPS  const fps = 1000 / frameTime;  // 每 60 帧输出一次性能信息，避免频繁日志输出  if (this.frameCount % 60 === 0) {    console.log(`性能统计 - FPS: ${fps.toFixed(2)}, 帧时间: ${frameTime.toFixed(2)}ms`);  }}/** * 触发垂直消隐中断（占位函数） * 在第 8 章（中断）中会实现完整的中断系统，通知 CPU 进行 VBLANK 相关操作 */triggerVBlankInterrupt() {  // TODO: 实现 V-Blank 中断  // 1. 设置中断标志位（例如在 MMU 中设置 IE/IF 寄存器）  // 2. 如果中断使能，通知 CPU 暂停当前执行并跳转到中断处理程序}/** * 获取当前 GPU 状态信息（用于调试） * @returns {Object} GPU 状态对象，包含模式、时钟、扫描线等 */getStatus() {  return {    mode: this.mode,    modeName: this.getModeName(this.mode),    modeClock: this.modeClock,    currentLine: this.currentLine,    totalClock: this.totalClock,    frameCount: this.frameCount,    fps: this.calculateFPS()  };}/** * 获取 GPU 模式名称的辅助函数 * @param {number} mode - 模式号 * @returns {string} 模式名称 */getModeName(mode) {  const modeNames = {    [GPU_MODES.HBLANK]: '水平消隐',    [GPU_MODES.VBLANK]: '垂直消隐',    [GPU_MODES.OAM_SEARCH]: 'OAM 搜索',    [GPU_MODES.PIXEL_TRANSFER]: '像素传输'  };  return modeNames[mode] || '未知模式';}/** * 计算当前 FPS * @returns {number} 当前 FPS 值 */calculateFPS() {  const currentTime = performance.now();  const timeDiff = currentTime - this.lastFrameTime;  return timeDiff &gt; 0 ? 1000 / timeDiff : 0;}/** * 获取调试信息字符串 * @returns {string} 格式化的调试信息 */getDebugInfo() {  const status = this.getStatus();  return `GPU 状态：模式：${status.modeName}（${status.mode}）模式时钟：${status.modeClock}当前扫描线：${status.currentLine}总时钟：${status.totalClock}帧计数：${status.frameCount}FPS：${status.fps.toFixed(2)}`;}</code></pre><h1 id="4-图形渲染绘制背景与瓦片"><a class="markdownIt-Anchor" href="#4-图形渲染绘制背景与瓦片"></a> 4. 图形渲染：绘制背景与瓦片</h1><p>与现代显卡动辄数 GB 的显存不同，早期游戏机（如 GameBoy）的内存极其有限，无法在内存中直接存储完整的屏幕像素（即帧缓冲区）。为了解决这个问题，工程师们采用了一种非常聪明的技术 —— 瓦片系统。</p><p>想象一下你在用瓷砖来铺地板。你不需要为每一块地面都设计一个独一无二的图案，而是可以使用一组预先设计好的瓷砖（瓦片），通过不同的排列组合来创造出丰富的地面样式。GameBoy 的图形渲染就是基于这个原理。我们只需要存储一份「模板」，然后在需要的地方「引用」它即可。这个「模板」就是瓦片。</p><ul><li>瓦片：一个 8x8 像素的基本图形单元。游戏中的所有背景和角色（精灵）都是由这些小小的瓦片拼接而成的</li><li>瓦片地图：一个 32x32 的二维数组，其中每个元素都是一个指向特定瓦片的索引。它就像一张设计图纸，规定了哪个位置应该使用哪个瓦片</li><li>视图：GameBoy 屏幕只有 160x144 像素，而整个背景地图却有 256x256 像素（32 个瓦片 × 8 像素 / 瓦片）。屏幕就像一个「摄像机」，我们只能通过这个 160x144 的窗口看到庞大背景地图的一部分</li></ul><blockquote><p>做过游戏开发的，尤其是做像素风格的应该对这个都很熟悉吧。</p><p>还是不太理解的，可以想一下拼图。</p><p>你要拼一幅大画，瓦片是你的拼图块（8x8 像素的小方块）、瓦片地图是拼图说明书、视图是拼图框。</p><p>游戏背景制作过程：</p><ol><li>美术画了很多 8x8 的小图块</li><li>策划说：「草地用 1 号块、石头用 2 号块……」</li><li>程序：「我按照说明书拼。」（GPU 渲染）</li><li>玩家在游戏中看到森林</li></ol><p>1989 年光是 1MB 内存就动不动要几千块钱，直接存储一张完整图片作为背景实在是过于奢侈。使用瓦片系统不仅可以节省内存，也可以节省空间。整个游戏卡带也才 32KB，必须得精打细算。</p></blockquote><p>VRAM（视频内存）中，瓦片数据和瓦片地图的布局如下：</p><table><thead><tr><th>地址区域</th><th>用途</th></tr></thead><tbody><tr><td><code>0x8000</code> - <code>0x8FFF</code></td><td>瓦片集 #1</td></tr><tr><td><code>0x9000</code> - <code>0x97FF</code></td><td>瓦片集 #2</td></tr><tr><td><code>0x9800</code> - <code>0x9BFF</code></td><td>瓦片地图 #0</td></tr><tr><td><code>0x9C00</code> - <code>0x9FFF</code></td><td>瓦片地图 #1</td></tr></tbody></table><p>有趣的是，瓦片集 #0 和 #1 有一部分是重叠的。游戏可以通过设置寄存器来选择使用哪个瓦片集和哪个瓦片地图，从而实现不同的显示效果。</p><h2 id="41-背景滚动与调色板"><a class="markdownIt-Anchor" href="#41-背景滚动与调色板"></a> 4.1. 背景滚动与调色板</h2><p>既然背景地图比屏幕大，我们自然就可以通过移动「摄像机」的位置来实现背景滚动的效果。这在平台跳跃或飞行射击游戏中非常常见。</p><p>GameBoy 提供了两个特殊的 GPU 寄存器来控制滚动：</p><ul><li><code>SCY</code>（Scroll Y，地址 <code>0xFF42</code>）：定义了屏幕顶边对应在 256x256 背景地图上的垂直坐标</li><li><code>SCX</code>（Scroll X，地址 <code>0xFF43</code>）：定义了屏幕左边对应在 256x256 背景地图上的水平坐标</li></ul><p>通过在每一帧之间改变 <code>SCX</code> 和 <code>SCY</code> 的值，游戏就能让背景平滑地滚动起来，创造出动态的世界。</p><p>或许大家都会以为 GameBoy 是纯黑白的，但实际上它可以显示四种深浅不同的「灰色」（或者说是绿色，取决于屏幕材质）。这四种颜色是通过调色板系统实现的。</p><p>一个瓦片中的每个像素用 2 个比特来表示，可以表示四种值（00, 01, 10, 11）。但这四个值具体对应哪种颜色，是由背景调色板寄存器（<code>BGP</code>，地址 <code>0xFF47</code>）决定的。</p><p><code>BGP</code> 是一个 8 位寄存器，每 2 位定义一个颜色的映射关系：</p><ul><li>位 1-0：映射像素值 <code>00</code></li><li>位 3-2：映射像素值 <code>01</code></li><li>位 5-4：映射像素值 <code>10</code></li><li>位 7-6：映射像素值 <code>11</code></li></ul><p>例如，如果 <code>BGP</code> 的值是 <code>0xE4</code>（二进制 <code>11100100</code>），那么映射关系就是：</p><ul><li><code>00</code> → <code>00</code>（颜色 0）</li><li><code>01</code> → <code>01</code>（颜色 1）</li><li><code>10</code> → <code>10</code>（颜色 2）</li><li><code>11</code> → <code>11</code>（颜色 3）</li></ul><p>这是最常见的默认调色板。但如果游戏将 <code>BGP</code> 的值改为 <code>0x1E</code>（二进制 <code>00011011</code>），映射就会变成：</p><ul><li><code>00</code> → <code>11</code>（颜色 3）</li><li><code>01</code> → <code>10</code>（颜色 2）</li><li><code>10</code> → <code>01</code>（颜色 1）</li><li><code>11</code> → <code>00</code>（颜色 0）</li></ul><p>这样整个屏幕的颜色就瞬间反转了，能够很高效地实现特殊视觉效果（比方说闪烁、水下效果）的方式。</p><p>在我们的模拟器中，我们将这四种颜色定义为经典的 GameBoy 绿色调：</p><pre><code class="language-javascript">const DEFAULT_PALETTE = [  [155, 188, 15, 255],   // 颜色 0: 最亮 (白)  [139, 172, 15, 255],   // 颜色 1: 亮灰 (浅绿)  [48, 98, 48, 255],     // 颜色 2: 暗灰 (深绿)  [15, 56, 15, 255]      // 颜色 3: 最暗 (黑)];</code></pre><h2 id="42-瓦片数据结构与缓存管理"><a class="markdownIt-Anchor" href="#42-瓦片数据结构与缓存管理"></a> 4.2. 瓦片数据结构与缓存管理</h2><p>在 GameBoy 中，每个瓦片的像素数据以一种特殊的方式存储。每个像素需要 2 位来表示（因为有 4 种颜色），但这 2 位并不是连续存储的。相反，一个瓦片行的 8 个像素的低位全部存储在一个字节中，高位存储在下一个字节中。</p><p>例如，如果一个瓦片行的像素值是 <code>[3, 2, 1, 0, 0, 1, 2, 3]</code>，那么：</p><ul><li>低位字节：<code>11100001</code>（每个像素值的最低位）</li><li>高位字节：<code>11000011</code>（每个像素值的最高位）</li></ul><p>这种存储方式虽然看起来复杂，但符合 GameBoy 硬件的读取方式。</p><blockquote><p>这一部分不需要完全理解，只要知道「GameBoy 有自己的存储格式，我们需要转换一下」就够了。</p></blockquote><p>为了提高模拟器的性能，我们需要将这种原始格式转换为更易于处理的格式，并建立缓存机制：</p><pre><code class="language-javascript">/** * 瓦片管理器类 * 负责瓦片数据的存储、更新和缓存管理 */class TileManager {  constructor() {    // 扩展瓦片数据缓存 - 每个瓦片预计算为 8x8 的像素数组    this.tileCache = new Array(GRAPHICS_CONSTANTS.TOTAL_TILES);        for (let i = 0; i &lt; GRAPHICS_CONSTANTS.TOTAL_TILES; i++) {      this.tileCache[i] = new Array(GRAPHICS_CONSTANTS.TILE_HEIGHT);      for (let y = 0; y &lt; GRAPHICS_CONSTANTS.TILE_HEIGHT; y++) {        this.tileCache[i][y] = new Uint8Array(GRAPHICS_CONSTANTS.TILE_WIDTH);      }    }        // 标记哪些瓦片需要更新    this.dirtyTiles = new Set();  }  /**   * 更新单个瓦片的缓存数据   */  updateTileCache(tileIndex) {    // 计算瓦片在 VRAM 中的起始地址    const baseAddr = tileIndex * GRAPHICS_CONSTANTS.TILE_SIZE_BYTES;        // 逐行处理瓦片数据    for (let y = 0; y &lt; GRAPHICS_CONSTANTS.TILE_HEIGHT; y++) {      const rowAddr = baseAddr + (y * 2); // 每行占 2 字节            if (rowAddr + 1 &lt; this.vram.length) {        const lowByte = this.vram[rowAddr];     // 像素低位        const highByte = this.vram[rowAddr + 1]; // 像素高位                // 从两个字节中提取 8 个像素        for (let x = 0; x &lt; GRAPHICS_CONSTANTS.TILE_WIDTH; x++) {          const bitMask = 1 &lt;&lt; (7 - x);                    const lowBit = (lowByte &amp; bitMask) ? 1 : 0;          const highBit = (highByte &amp; bitMask) ? 2 : 0;                    // 组合成 2 位颜色值          this.tileCache[tileIndex][y][x] = lowBit + highBit;        }      }    }  }}</code></pre><p>这个缓存系统的核心思想是「按需更新」—— 只有当 VRAM 中的瓦片数据发生变化时，我们才重新计算对应的缓存。这样可以避免每次渲染时都进行耗时的位操作。</p><h2 id="43-调色板系统实现"><a class="markdownIt-Anchor" href="#43-调色板系统实现"></a> 4.3. 调色板系统实现</h2><p>调色板管理器负责处理颜色映射。它不仅存储当前的调色板设置，还提供了动态更新调色板的能力：</p><pre><code class="language-javascript">/** * 调色板管理器类 * 处理 GameBoy 的 4 色调色板系统 */class PaletteManager {  constructor() {    // 背景调色板（4 种颜色，每种颜色 RGBA 4 字节）    this.backgroundPalette = new Array(GRAPHICS_CONSTANTS.PALETTE_COLORS);        // 原始调色板寄存器值（用于模拟硬件寄存器）    this.paletteRegister = 0xFC; // 默认值：11 10 01 00        this.setDefaultPalette();  }  /**   * 更新调色板寄存器   */  updatePaletteRegister(value) {    this.paletteRegister = value &amp; 0xFF;        // 从寄存器值提取 4 个 2 位颜色映射    for (let i = 0; i &lt; GRAPHICS_CONSTANTS.PALETTE_COLORS; i++) {      const colorIndex = (this.paletteRegister &gt;&gt; (i * 2)) &amp; 0x03;      this.backgroundPalette[i] = [...DEFAULT_PALETTE[colorIndex]];    }  }  /**   * 获取映射后的颜色   */  getColor(paletteIndex) {    if (paletteIndex &lt; 0 || paletteIndex &gt;= GRAPHICS_CONSTANTS.PALETTE_COLORS) {      return DEFAULT_PALETTE[0];    }        return this.backgroundPalette[paletteIndex];  }}</code></pre><p>例如，当游戏写入调色板寄存器 <code>0xFF47</code> 时，<code>updatePaletteRegister</code> 方法会被调用，自动重新映射所有颜色。这意味着游戏可以通过一个简单的寄存器写入操作瞬间改变整个屏幕的色调。</p><h2 id="44-背景滚动控制"><a class="markdownIt-Anchor" href="#44-背景滚动控制"></a> 4.4. 背景滚动控制</h2><p>滚动控制器管理背景的偏移位置，这是实现动态背景效果的关键：</p><pre><code class="language-javascript">/** * 滚动控制器类 * 管理背景的滚动位置 */class ScrollController {  constructor() {    this.scrollX = 0; // 水平滚动位置    this.scrollY = 0; // 垂直滚动位置  }  /**   * 设置滚动位置   */  setScroll(x, y) {    this.scrollX = x &amp; 0xFF;    this.scrollY = y &amp; 0xFF;  }  /**   * 获取当前滚动位置   */  getScrollPosition() {    return {      x: this.scrollX,      y: this.scrollY    };  }}</code></pre><p>这个简单的类封装了 GameBoy 的 <code>SCX</code> 和 <code>SCY</code> 寄存器的功能。当游戏修改这些寄存器时，滚动位置会立即更新，下一帧的渲染就会反映出新的滚动位置。</p><h2 id="45-扫描线级背景渲染"><a class="markdownIt-Anchor" href="#45-扫描线级背景渲染"></a> 4.5. 扫描线级背景渲染</h2><p>背景渲染器是整个图形系统的核心，它负责将瓦片地图转换为实际的像素数据。渲染是按扫描线进行的，这模拟了 GameBoy 的真实渲染方式：</p><pre><code class="language-javascript">/** * 背景渲染器类 * 负责将瓦片地图渲染到帧缓冲区 */class BackgroundRenderer {  /**   * 渲染单条扫描线的背景   */  renderBackgroundScanline(lineNumber, frameBuffer) {    // 获取滚动位置    const scroll = this.scrollController.getScrollPosition();        // 计算当前扫描线在瓦片地图中的 Y 位置    const mapY = (lineNumber + scroll.y) &amp; 0xFF;    const tileY = Math.floor(mapY / GRAPHICS_CONSTANTS.TILE_HEIGHT);    const pixelY = mapY % GRAPHICS_CONSTANTS.TILE_HEIGHT;        // 计算瓦片地图行的起始偏移    const mapBaseAddr = this.backgroundMapSelect ?       VRAM_LAYOUT.TILEMAP_1_START : VRAM_LAYOUT.TILEMAP_0_START;    const mapOffset = mapBaseAddr - VRAM_LAYOUT.TILESET_1_START;    const mapLineOffset = mapOffset + (tileY * GRAPHICS_CONSTANTS.MAP_WIDTH_TILES);        // 计算起始瓦片的 X 位置    let mapX = scroll.x;    let tileX = Math.floor(mapX / GRAPHICS_CONSTANTS.TILE_WIDTH);    let pixelX = mapX % GRAPHICS_CONSTANTS.TILE_WIDTH;        // 计算帧缓冲区的起始位置    let canvasOffset = lineNumber * GRAPHICS_CONSTANTS.SCREEN_WIDTH * 4;        // 获取第一个瓦片    let tileIndex = this.getTileIndex(mapLineOffset + tileX);    let tileData = this.tileManager.getTileData(tileIndex);        // 渲染整条扫描线（160 像素）    for (let screenX = 0; screenX &lt; GRAPHICS_CONSTANTS.SCREEN_WIDTH; screenX++) {      // 获取当前像素的调色板索引      const paletteIndex = tileData ? tileData[pixelY][pixelX] : 0;            // 通过调色板获取最终颜色      const color = this.paletteManager.getColor(paletteIndex);            // 写入帧缓冲区      frameBuffer.data[canvasOffset] = color[0];     // R      frameBuffer.data[canvasOffset + 1] = color[1]; // G      frameBuffer.data[canvasOffset + 2] = color[2]; // B      frameBuffer.data[canvasOffset + 3] = color[3]; // A      canvasOffset += 4;            // 移动到下一个像素      pixelX++;      if (pixelX &gt;= GRAPHICS_CONSTANTS.TILE_WIDTH) {        // 移动到下一个瓦片        pixelX = 0;        tileX = (tileX + 1) &amp; 31; // 瓦片地图是 32x32，循环        tileIndex = this.getTileIndex(mapLineOffset + tileX);        tileData = this.tileManager.getTileData(tileIndex);      }    }  }}</code></pre><p>这个渲染过程的关键在于理解坐标转换：</p><ol><li>从屏幕坐标转换为背景地图坐标（考虑滚动偏移）</li><li>从背景地图坐标转换为瓦片坐标和瓦片内像素坐标</li><li>从瓦片地图读取瓦片索引</li><li>从瓦片缓存读取像素的调色板索引</li><li>通过调色板获取最终的 RGBA 颜色值</li></ol><h2 id="46-图形系统集成"><a class="markdownIt-Anchor" href="#46-图形系统集成"></a> 4.6. 图形系统集成</h2><p>最后，图形系统主类将所有组件协调起来工作：</p><pre><code class="language-javascript">/** * 图形系统主类 * 协调所有图形组件的工作 */class GameBoyGraphicsSystem {  constructor() {    // 创建各个组件    this.tileManager = new TileManager();    this.paletteManager = new PaletteManager();    this.scrollController = new ScrollController();    this.backgroundRenderer = new BackgroundRenderer(      this.tileManager,      this.paletteManager,      this.scrollController    );  }  /**   * 连接到 MMU 的 VRAM   */  connectVRAM(vramData) {    this.tileManager.setVRAM(vramData);    this.backgroundRenderer.setVRAM(vramData);  }  /**   * 处理图形寄存器写入   */  writeGraphicsRegister(register, value) {    switch (register) {      case 0xFF42: // SCY - 垂直滚动        this.scrollController.setScrollY(value);        break;              case 0xFF43: // SCX - 水平滚动        this.scrollController.setScrollX(value);        break;              case 0xFF47: // BGP - 背景调色板        this.paletteManager.updatePaletteRegister(value);        break;    }  }  /**   * 渲染单条扫描线   */  renderScanline(lineNumber, frameBuffer) {    if (!this.enabled || !this.backgroundEnabled) {      return;    }        this.backgroundRenderer.renderBackgroundScanline(lineNumber, frameBuffer);  }}</code></pre><p>这个集成系统的设计遵循了模块化原则 —— 每个组件都有清晰的职责，通过明确的接口进行通信。当 GPU 需要渲染一条扫描线时，它只需调用 <code>renderScanline</code> 方法，图形系统会自动协调所有子组件完成复杂的渲染过程。</p><h2 id="47-图形系统集成与性能优化"><a class="markdownIt-Anchor" href="#47-图形系统集成与性能优化"></a> 4.7. 图形系统集成与性能优化</h2><p>在完成了瓦片管理、调色板和背景渲染等核心组件后，我们需要将图形系统与现有的 GPU 时序系统集成起来，并进行性能优化以确保流畅的渲染效果（当时测试的时候 FPS 发现连 1 都不到……）。</p><p>首先，我们需要在 GPU 类中添加图形系统的初始化和管理逻辑：</p><pre><code class="language-javascript">/** * 初始化图形系统 */initializeGraphicsSystem() {  // 图形系统实例（如果可用）  this.graphicsSystem = null;  this.renderMode = 'test'; // 'test' 或 'graphics'  // 尝试初始化图形系统  if (typeof GameBoyGraphicsSystem !== 'undefined') {    try {      this.graphicsSystem = new GameBoyGraphicsSystem();      this.renderMode = 'graphics';      console.log('图形系统已集成到 GPU');    } catch (error) {      console.warn('图形系统初始化失败，使用测试模式:', error);    }  } else {    console.log('图形系统未加载，使用测试渲染模式');  }}</code></pre><p>接下来，我们需要建立 GPU 与图形系统之间的数据连接：</p><pre><code class="language-javascript">/** * 连接到 MMU 的 VRAM */connectVRAM(vramData) {  if (this.graphicsSystem) {    this.graphicsSystem.connectVRAM(vramData);    console.log('GPU 已连接到 VRAM');  }}/** * 处理 VRAM 写入事件 */onVRAMWrite(address, value) {  if (this.graphicsSystem) {    this.graphicsSystem.onVRAMWrite(address, value);  }}/** * 处理图形寄存器写入 */writeRegister(register, value) {  if (this.graphicsSystem) {    this.graphicsSystem.writeGraphicsRegister(register, value);  }}</code></pre><p>为了提供更好的调试体验和性能，我们要实现渲染模式切换：</p><pre><code class="language-javascript">/** * 渲染真实的 GameBoy 背景图形 */renderGameBoyGraphics() {  if (window.GameBoyGraphicsSystem &amp;&amp; this.graphicsSystem) {    this.graphicsSystem.renderScanline(this.currentLine, this.frameBuffer);  } else {    // 否则使用测试图案    this.renderTestPattern();  }}/** * 切换渲染模式 */setRenderMode(mode) {  if (mode === 'graphics' &amp;&amp; !this.graphicsSystem) {    console.warn('图形系统未初始化，无法切换到图形模式');    return;  }  this.renderMode = mode;  console.log(`渲染模式已切换到：${mode}`);}/** * 渲染当前扫描线 */renderScanline() {  // 根据渲染模式选择渲染方式  if (this.renderMode === 'graphics' &amp;&amp; this.graphicsSystem) {    this.renderGameBoyGraphics();  } else {    this.renderTestPattern();  }}</code></pre><p>最重要的性能优化是引入了简化的帧级别渲染，避免了复杂的周期级别计算：</p><pre><code class="language-javascript">/** * 简化的帧级别步进 * 每次调用渲染一整帧，避免复杂的周期计算 */stepFrame() {  // 1. 渲染所有可见扫描线 (0-143)  for (let line = 0; line &lt; GPU_TIMINGS.VISIBLE_LINES; line++) {    this.currentLine = line;    this.mode = GPU_MODES.PIXEL_TRANSFER;    this.renderScanline();  }  // 2. 模拟垂直消隐期间 (144-153)  this.mode = GPU_MODES.VBLANK;  this.currentLine = GPU_TIMINGS.VISIBLE_LINES;  // 3. 完成帧渲染  this.onFrameComplete();  // 4. 重置到下一帧开始  this.currentLine = 0;  this.mode = GPU_MODES.OAM_SEARCH;  this.modeClock = 0;}</code></pre><h1 id="5-系统集成构建完整的模拟器架构"><a class="markdownIt-Anchor" href="#5-系统集成构建完整的模拟器架构"></a> 5. 系统集成：构建完整的模拟器架构</h1><p>在前面的章节中，我们分别实现了 CPU 指令处理、MMU 内存管理、GPU 时序控制和图形渲染系统。虽然这些组件各自功能完善，但它们就跟分散的乐器差不多，需要一个指挥家来协调，不然是无法演奏出和谐的交响乐的。这一章的核心任务就是建立这样一个统一的系统架构，让所有硬件组件无缝协作。</p><h2 id="51-硬件抽象层与组件连接"><a class="markdownIt-Anchor" href="#51-硬件抽象层与组件连接"></a> 5.1. 硬件抽象层与组件连接</h2><p>在真实的 GameBoy 中，各个硬件组件通过物理总线连接。在我们的模拟器中，我们需要建立一个软件层面的「总线系统「，让组件间能够进行通信。MMU 作为内存管理的中心，天然地成为了这个连接中心。</p><p>我们为 MMU 添加硬件组件连接能力：</p><pre><code class="language-javascript">/** * 初始化硬件组件引用 */initializeHardwareReferences() {  // 硬件组件引用，由外部注入  this.gpu = null;  this.inputController = null;      // 第6章添加  this.timer = null;                // 第10章添加  this.interruptController = null;  // 第8章添加  console.log('📡 MMU 硬件接口已初始化');}/** * 连接硬件组件 * @param {string} componentType 组件类型（'gpu', 'input', 'timer', 'interrupt'） * @param {Object} component 硬件组件实例 */connectHardware(componentType, component) {  switch (componentType) {    case 'gpu':      this.gpu = component;      console.log('✅ GPU 已连接到 MMU');      break;    case 'input':      this.inputController = component;      console.log('✅ 输入控制器已连接到 MMU');      break;    // ... 其他组件  }}</code></pre><p>这种设计的优势在于 <strong>松耦合</strong>：每个组件都不需要知道其他组件的具体实现，只需要通过 MMU 这个「中介」进行通信。当我们要添加新的硬件组件时，只需要在 MMU 中注册即可。</p><h2 id="52-io-寄存器路由系统"><a class="markdownIt-Anchor" href="#52-io-寄存器路由系统"></a> 5.2. I / O 寄存器路由系统</h2><p>GameBoy 的硬件组件通过内存映射的 I / O 寄存器进行控制。这些寄存器位于 <code>0xFF00-0xFF7F</code> 地址范围内，不同的地址控制不同的硬件功能。我们需要建立一个路由系统，将对这些地址的读写操作转发给相应的硬件组件。</p><p>首先，定义一个完整的寄存器地址映射：</p><pre><code class="language-javascript">/** * I/O 寄存器映射常量 */const IO_REGISTERS = {  // GPU 寄存器范围（0xFF40-0xFF7F）  GPU_START: 0xFF40,  GPU_END: 0xFF7F,  // 具体的 GPU 寄存器  LCDC: 0xFF40,    // LCD 控制寄存器  STAT: 0xFF41,    // LCD 状态寄存器  SCY: 0xFF42,     // 垂直滚动  SCX: 0xFF43,     // 水平滚动  LY: 0xFF44,      // 当前扫描线（只读）  BGP: 0xFF47,     // 背景调色板  // 其他硬件寄存器  JOYPAD: 0xFF00,  // 按键输入（第6章实现）  IF: 0xFF0F,      // 中断标志  IE: 0xFFFF       // 中断使能};</code></pre><p>MMU 中的寄存器读写方法会根据地址范围自动将请求路由到对应的硬件组件：</p><pre><code class="language-javascript">/** * 连接硬件组件 * @param {string} componentType - 组件类型 ('gpu', 'input', 'timer', 'interrupt') * @param {Object} component - 硬件组件实例 */connectHardware(componentType, component) {  switch (componentType) {    case 'gpu':      this.gpu = component;      console.log('✅ GPU 已连接到 MMU');      break;    case 'input':      this.inputController = component;      console.log('✅ 输入控制器已连接到 MMU');      break;    case 'timer':      this.timer = component;      console.log('✅ 定时器已连接到 MMU');      break;    case 'interrupt':      this.interruptController = component;      console.log('✅ 中断控制器已连接到 MMU');      break;    default:      console.warn(`⚠️ 未知的硬件组件类型: ${componentType}`);  }}</code></pre><p>不同的寄存器地址控制不同的硬件功能，MMU 需要将读写操作正确路由到对应的硬件组件：</p><pre><code class="language-javascript">/** * 读取I/O寄存器 - 支持硬件组件路由 */readIORegister(address) {  // 🎨 GPU 寄存器范围 (0xFF40-0xFF7F)  if (address &gt;= IO_REGISTERS.GPU_START &amp;&amp; address &lt;= IO_REGISTERS.GPU_END) {    if (this.gpu &amp;&amp; typeof this.gpu.readRegister === 'function') {      return this.gpu.readRegister(address);    } else {      console.warn(`⚠️ GPU 未连接，无法读取寄存器 0x${address.toString(16)}`);      return 0xFF;    }  }  // TODO: 以下都会在未来的章节中实现  // 🎮 按键输入寄存器 (0xFF00)  if (address === IO_REGISTERS.JOYPAD) {    if (this.inputController &amp;&amp; typeof this.inputController.readJoypadRegister === 'function') {      return this.inputController.readJoypadRegister();    }    return 0xFF; // 默认：所有按键未按下  }  // ⏰ 定时器寄存器 (0xFF04-0xFF07)  if (address &gt;= IO_REGISTERS.TIMER_DIV &amp;&amp; address &lt;= IO_REGISTERS.TIMER_TAC) {    if (this.timer &amp;&amp; typeof this.timer.readRegister === 'function') {      return this.timer.readRegister(address);    }    return 0x00;  }  // 🔔 中断寄存器 (0xFF0F, 0xFFFF)  if (address === IO_REGISTERS.IF || address === IO_REGISTERS.IE) {    if (this.interruptController &amp;&amp; typeof this.interruptController.readRegister === 'function') {      return this.interruptController.readRegister(address);    }    return 0x00;  }  // 默认处理  const registerIndex = address - MEMORY_REGIONS.IO_START;  return this.ioRegisters[registerIndex] || 0xFF;}</code></pre><p>对应的写入路由逻辑确保了每个硬件组件都能及时收到控制指令：</p><pre><code class="language-javascript">/** * 写入I/O寄存器 - 支持硬件组件路由 * @param {number} address - I/O寄存器地址 * @param {number} value - 要写入的值 */writeIORegister(address, value) {  // 🎨 GPU 寄存器范围 (0xFF40-0xFF7F)  if (address &gt;= IO_REGISTERS.GPU_START &amp;&amp; address &lt;= IO_REGISTERS.GPU_END) {    if (this.gpu &amp;&amp; typeof this.gpu.writeRegister === 'function') {      this.gpu.writeRegister(address, value);    } else {      console.warn(`⚠️ GPU 未连接，无法写入寄存器 0x${address.toString(16)}`);    }    // 同时保存到本地数组（用于后备）    const registerIndex = address - MEMORY_REGIONS.IO_START;    if (registerIndex &gt;= 0 &amp;&amp; registerIndex &lt; this.ioRegisters.length) {      this.ioRegisters[registerIndex] = value;    }    return;  }  // 🎮 按键输入寄存器 (0xFF00) - 第6章实现  if (address === IO_REGISTERS.JOYPAD) {    if (this.inputController &amp;&amp; typeof this.inputController.writeJoypadRegister === 'function') {      this.inputController.writeJoypadRegister(value);    }    // 保存到本地数组    this.ioRegisters[address - MEMORY_REGIONS.IO_START] = value;    return;  }  // ⏰ 定时器寄存器 (0xFF04-0xFF07) - 第10章实现  if (address &gt;= IO_REGISTERS.TIMER_DIV &amp;&amp; address &lt;= IO_REGISTERS.TIMER_TAC) {    if (this.timer &amp;&amp; typeof this.timer.writeRegister === 'function') {      this.timer.writeRegister(address, value);    }    this.ioRegisters[address - MEMORY_REGIONS.IO_START] = value;    return;  }  // 🔔 中断寄存器 (0xFF0F, 0xFFFF) - 第8章实现  if (address === IO_REGISTERS.IF || address === IO_REGISTERS.IE) {    if (this.interruptController &amp;&amp; typeof this.interruptController.writeRegister === 'function') {      this.interruptController.writeRegister(address, value);    }    // 特殊处理：IE 寄存器在零页RAM中    if (address === IO_REGISTERS.IE) {      this.zram[0x7F] = value; // 0xFFFF -&gt; ZRAM[0x7F]    } else {      this.ioRegisters[address - MEMORY_REGIONS.IO_START] = value;    }    return;  }  // 默认处理：保存到本地寄存器数组  const registerIndex = address - MEMORY_REGIONS.IO_START;  if (registerIndex &gt;= 0 &amp;&amp; registerIndex &lt; this.ioRegisters.length) {    this.ioRegisters[registerIndex] = value;  } else {    console.warn(`⚠️ 无效的I/O寄存器写入: 0x${address.toString(16).padStart(4, '0')}`);  }}</code></pre><p>这样，当游戏代码写入 <code>0xFF40</code>（LCD 控制寄存器）时，MMU 会自动将这个写入操作转发给 GPU，GPU 就能实时更新其内部状态。</p><p>GPU 是 I / O 寄存器最密集的硬件组件，拥有十多个不同功能的寄存器。这些寄存器不仅控制显示行为，还影响中断、DMA 传输等关键功能。</p><pre><code class="language-javascript">/** * GPU 寄存器常量定义 */const GPU_REGISTERS = {  // LCD 控制和状态  LCDC: 0xFF40,    // LCD 控制寄存器  STAT: 0xFF41,    // LCD 状态寄存器    // 滚动位置  SCY: 0xFF42,     // 垂直滚动  SCX: 0xFF43,     // 水平滚动    // 扫描线相关  LY: 0xFF44,      // 当前扫描线（只读）  LYC: 0xFF45,     // 扫描线比较值    // DMA 传输  DMA: 0xFF46,     // DMA 传输寄存器    // 调色板  BGP: 0xFF47,     // 背景调色板  OBP0: 0xFF48,    // 精灵调色板 0  OBP1: 0xFF49,    // 精灵调色板 1    // 窗口位置  WY: 0xFF4A,      // 窗口 Y 位置  WX: 0xFF4B       // 窗口 X 位置};/** * LCD 控制寄存器标志位 */const LCDC_FLAGS = {  LCD_ENABLE: 0x80,        // 位 7：LCD 开关  WINDOW_TILEMAP: 0x40,    // 位 6：窗口瓦片地图选择  WINDOW_ENABLE: 0x20,     // 位 5：窗口开关  BG_TILESET: 0x10,        // 位 4：背景瓦片数据选择  BG_TILEMAP: 0x08,        // 位 3：背景瓦片地图选择  SPRITE_SIZE: 0x04,       // 位 2：精灵大小（0=8x8, 1=8x16）  SPRITE_ENABLE: 0x02,     // 位 1：精灵开关  BG_ENABLE: 0x01          // 位 0：背景开关};</code></pre><p>GPU 内部维护所有寄存器的当前状态：</p><pre><code class="language-javascript">/** * 初始化寄存器状态 */initializeRegisters() {  // GPU 寄存器状态  this.registers = {    // LCD 控制寄存器 (0xFF40)    lcdc: 0x00,    // LCD 状态寄存器 (0xFF41)    stat: 0x00,    // 滚动寄存器    scy: 0x00,   // 垂直滚动 (0xFF42)    scx: 0x00,   // 水平滚动 (0xFF43)    // 扫描线寄存器    ly: 0x00,    // 当前扫描线 (0xFF44) - 只读    lyc: 0x00,   // 扫描线比较值 (0xFF45)    // 调色板寄存器    bgp: 0xFC,   // 背景调色板 (0xFF47) - 默认值    // 窗口位置寄存器    wy: 0x00,    // 窗口 Y 位置 (0xFF4A)    wx: 0x00     // 窗口 X 位置 (0xFF4B)  };  // 解析控制标志位到独立变量（向后兼容）  this.updateControlFlags();}</code></pre><p>LCD 控制寄存器（LCDC）是一个特殊的寄存器，它的每一位都控制不同的显示功能：</p><pre><code class="language-javascript">/** * 从寄存器值更新控制标志位 */updateControlFlags() {  const lcdc = this.registers.lcdc;  // LCD 控制标志  this._lcdEnabled = (lcdc &amp; LCDC_FLAGS.LCD_ENABLE) !== 0;  this._windowEnabled = (lcdc &amp; LCDC_FLAGS.WINDOW_ENABLE) !== 0;  this._spritesEnabled = (lcdc &amp; LCDC_FLAGS.SPRITE_ENABLE) !== 0;  this._backgroundEnabled = (lcdc &amp; LCDC_FLAGS.BG_ENABLE) !== 0;  // 瓦片和地图选择  this._backgroundTileSet = (lcdc &amp; LCDC_FLAGS.BG_TILESET) !== 0 ? 1 : 0;  this._backgroundTileMap = (lcdc &amp; LCDC_FLAGS.BG_TILEMAP) !== 0 ? 1 : 0;  this._windowTileMap = (lcdc &amp; LCDC_FLAGS.WINDOW_TILEMAP) !== 0 ? 1 : 0;  this._spriteSize = (lcdc &amp; LCDC_FLAGS.SPRITE_SIZE) !== 0 ? 16 : 8;}</code></pre><p>GPU 提供完整的寄存器读写接口：</p><pre><code class="language-javascript">/** * 读取 GPU 寄存器 * @param {number} address - 寄存器地址 * @returns {number} 寄存器值 */readRegister(address) {  switch (address) {    // LCD 控制寄存器 (0xFF40)    case GPU_REGISTERS.LCDC:      return this.registers.lcdc;    // LCD 状态寄存器 (0xFF41)    case GPU_REGISTERS.STAT:      // 组合状态标志位和当前模式      let stat = this.registers.stat &amp; 0xF8; // 保留高 5 位      stat |= (this.mode &amp; 0x03); // 添加当前模式            // 检查 LYC=LY 标志      if (this.registers.ly === this.registers.lyc) {        stat |= STAT_FLAGS.LYC_FLAG;      }            return stat;    // 滚动寄存器    case GPU_REGISTERS.SCY:      return this.registers.scy;    case GPU_REGISTERS.SCX:      return this.registers.scx;    // 当前扫描线 (只读)    case GPU_REGISTERS.LY:      return this.registers.ly;    // 扫描线比较值    case GPU_REGISTERS.LYC:      return this.registers.lyc;    // DMA 寄存器 (写入专用，读取返回上次写入值)    case GPU_REGISTERS.DMA:      return this.registers.dma;    // 调色板寄存器    case GPU_REGISTERS.BGP:      return this.registers.bgp;    case GPU_REGISTERS.OBP0:      return this.registers.obp0;    case GPU_REGISTERS.OBP1:      return this.registers.obp1;    // 窗口位置寄存器    case GPU_REGISTERS.WY:      return this.registers.wy;    case GPU_REGISTERS.WX:      return this.registers.wx;    default:      console.warn(`⚠️ 尝试读取未知的 GPU 寄存器: 0x${address.toString(16).padStart(4, '0')}`);      return 0xFF;  }}/** * 写入 GPU 寄存器 * @param {number} address - 寄存器地址 * @param {number} value - 要写入的值 */writeRegister(address, value) {  // 确保值在 8 位范围内  value &amp;= 0xFF;  switch (address) {    // LCD 控制寄存器 (0xFF40)    case GPU_REGISTERS.LCDC:      this.registers.lcdc = value;      this.updateControlFlags();            // 当 LCD 被禁用时，重置一些状态      if (!this._lcdEnabled) {        this.currentLine = 0;        this.registers.ly = 0;        this.mode = GPU_MODES.HBLANK;        this.modeClock = 0;      }            console.log(`🎛️ LCD 控制寄存器更新: 0x${value.toString(16).padStart(2, '0')}`);      break;    // LCD 状态寄存器 (0xFF41) - 只有高 5 位可写    case GPU_REGISTERS.STAT:      this.registers.stat = (value &amp; 0xF8) | (this.registers.stat &amp; 0x07);      break;    // 滚动寄存器    case GPU_REGISTERS.SCY:      this.registers.scy = value;      // 通知图形系统滚动更新      if (this.graphicsSystem &amp;&amp; this.graphicsSystem.scrollController) {        this.graphicsSystem.scrollController.setScrollY(value);      }      break;    case GPU_REGISTERS.SCX:      this.registers.scx = value;      // 通知图形系统滚动更新      if (this.graphicsSystem &amp;&amp; this.graphicsSystem.scrollController) {        this.graphicsSystem.scrollController.setScrollX(value);      }      break;    // 当前扫描线 (只读寄存器，写入被忽略)    case GPU_REGISTERS.LY:      console.warn(`⚠️ 尝试写入只读寄存器 LY: 0x${value.toString(16)}`);      break;    // 扫描线比较值    case GPU_REGISTERS.LYC:      this.registers.lyc = value;      break;    // DMA 传输寄存器 (0xFF46)    case GPU_REGISTERS.DMA:      this.registers.dma = value;      this.performDMATransfer(value);      break;    // 背景调色板 (0xFF47)    case GPU_REGISTERS.BGP:      this.registers.bgp = value;      this.updateBackgroundPalette(value);      console.log(`🎨 背景调色板更新: 0x${value.toString(16).padStart(2, '0')}`);      break;    // 精灵调色板寄存器    case GPU_REGISTERS.OBP0:      this.registers.obp0 = value;      // TODO: 实现精灵调色板更新 (第7章)      break;    case GPU_REGISTERS.OBP1:      this.registers.obp1 = value;      // TODO: 实现精灵调色板更新 (第7章)      break;    // 窗口位置寄存器    case GPU_REGISTERS.WY:      this.registers.wy = value;      break;    case GPU_REGISTERS.WX:      this.registers.wx = value;      break;    default:      console.warn(`⚠️ 尝试写入未知的 GPU 寄存器: 0x${address.toString(16).padStart(4, '0')} = 0x${value.toString(16).padStart(2, '0')}`);  }}</code></pre><p>DMA（直接内存访问）是 GameBoy 的重要功能，允许快速复制精灵数据到 OAM：</p><pre><code class="language-javascript">/** * 执行 DMA 传输 * @param {number} sourceHigh - 源地址高字节 */performDMATransfer(sourceHigh) {  // DMA 传输：将 256 字节从 sourceHigh*0x100 复制到 OAM (0xFE00-0xFE9F)  const sourceAddr = sourceHigh &lt;&lt; 8;    console.log(`🚚 DMA 传输: 0x${sourceAddr.toString(16).padStart(4, '0')} -&gt; OAM`);    // TODO: 实现完整的 DMA 传输逻辑  // 需要从 MMU 读取数据并写入 OAM  // 在真实硬件中，这会锁定总线并需要特定的时序}</code></pre><pre><code class="language-javascript">/** * 更新背景调色板 * @param {number} paletteValue - 调色板寄存器值 */updateBackgroundPalette(paletteValue) {  if (this.graphicsSystem &amp;&amp; this.graphicsSystem.paletteManager) {    this.graphicsSystem.paletteManager.updatePaletteRegister(paletteValue);  }}</code></pre><h2 id="54-系统调度器架构"><a class="markdownIt-Anchor" href="#54-系统调度器架构"></a> 5.4. 系统调度器架构</h2><p>现在我们有了能够相互通信的硬件组件，但还需要一个「指挥家」来协调它们的工作。这就是系统调度器 <code>gameboy.js</code> 的作用。</p><p>系统调度器作为顶层管理器，负责创建、连接和管理所有硬件组件：</p><pre><code class="language-javascript">/** * 系统常量定义 */const SYSTEM_CONSTANTS = {  // 时序常量  CPU_FREQUENCY: 4194304,      // 4.194304 MHz  TARGET_FPS: 59.7,           // GameBoy 目标帧率  FRAME_CYCLES: 70224,        // 每帧的 CPU 周期数    // 系统状态  STATE_STOPPED: 'stopped',  STATE_RUNNING: 'running',  STATE_PAUSED: 'paused',  STATE_ERROR: 'error',    // 调度模式  SCHEDULE_FRAME: 'frame',     // 帧级别调度（默认）  SCHEDULE_CYCLE: 'cycle',     // 周期级别调度（精确）  SCHEDULE_BURST: 'burst'      // 突发调度（性能优先）};/** * GameBoy 主系统类 * 协调 CPU、MMU、GPU 和其他硬件组件的工作 */class GameBoySystem {  constructor() {    // 系统状态    this.state = SYSTEM_CONSTANTS.STATE_STOPPED;    this.scheduleMode = SYSTEM_CONSTANTS.SCHEDULE_FRAME;    // 硬件组件    this.cpu = null;    this.mmu = null;    this.gpu = null;    this.graphics = null;    // 调度器状态    this.runningInterval = null;    this.frameRequestId = null;        // 性能统计    this.stats = {      framesRendered: 0,      cyclesExecuted: 0,      startTime: 0,      currentFPS: 0,      averageFPS: 0,      errors: 0    };  }}</code></pre><p>系统调度器的初始化过程展示了完整的组件连接流程：</p><pre><code class="language-javascript">/** * 创建硬件组件实例 */async createHardwareComponents() {  // 创建 MMU（内存管理单元）  this.mmu = new GameBoyMMU();  console.log('✅ MMU 已创建');  // 创建 GPU（图形处理单元）  this.gpu = new GameBoyGPU();  console.log('✅ GPU 已创建');  // 获取图形系统引用  if (this.gpu.graphicsSystem) {    this.graphics = this.gpu.graphicsSystem;    console.log('✅ 图形系统已连接');  }  // 创建 CPU（中央处理器）  this.cpu = new GameBoyCPU();  console.log('✅ CPU 已创建');}/** * 连接硬件组件 */connectComponents() {  // 连接 GPU 到 MMU  this.mmu.connectHardware('gpu', this.gpu);  // 连接 GPU 到 VRAM  if (this.mmu.vram) {    this.gpu.connectVRAM(this.mmu.vram);    // 连接图形系统到 VRAM    if (this.graphics) {      this.graphics.connectVRAM(this.mmu.vram);    }  }  console.log('🔗 硬件组件连接完成');}</code></pre><p>这个连接过程确保了：</p><ol><li>GPU 能够通过 MMU 接收寄存器访问</li><li>GPU 能够直接访问 VRAM 进行渲染</li><li>图形系统能够接收 VRAM 更新通知</li></ol><h2 id="55-帧级别时序调度"><a class="markdownIt-Anchor" href="#55-帧级别时序调度"></a> 5.5. 帧级别时序调度</h2><p>先前我们实现了精确的周期级别时序，但在实际运行中这种精确度往往会带来性能负担，因此我们当时引入了帧级别调度，在保持足够精度的同时大幅提升性能。现在我们完善一下当时只是简化版本的 <code>stepFrame()</code>。</p><pre><code class="language-javascript">/** * 每次调用渲染一整帧，避免复杂的周期计算 */stepFrame() {  // 如果 LCD 被禁用，不渲染  if (!this._lcdEnabled) {    return;  }  // 1. 渲染所有可见扫描线 (0-143)  for (let line = 0; line &lt; GPU_TIMINGS.VISIBLE_LINES; line++) {    this.currentLine = line;    this.registers.ly = line;    this.mode = GPU_MODES.PIXEL_TRANSFER;    this.renderScanline();  }  // 2. 模拟垂直消隐期间 (144-153)  this.mode = GPU_MODES.VBLANK;  this.currentLine = GPU_TIMINGS.VISIBLE_LINES;  this.registers.ly = GPU_TIMINGS.VISIBLE_LINES;  // 3. 完成帧渲染  this.onFrameComplete();  // 4. 重置到下一帧开始  this.currentLine = 0;  this.registers.ly = 0;  this.mode = GPU_MODES.OAM_SEARCH;  this.modeClock = 0;}</code></pre><p>系统调度器支持多种调度模式以适应不同的需求：</p><pre><code class="language-javascript">/** * 帧级别调度循环（默认模式） */startFrameLoop() {  const frameLoop = (currentTime) =&gt; {    if (this.state !== SYSTEM_CONSTANTS.STATE_RUNNING) {      return;    }    try {      // 计算时间差      const deltaTime = currentTime - this.lastFrameTime;      // 如果达到目标帧时间，执行一帧      if (deltaTime &gt;= this.targetFrameTime) {        this.executeFrame();        this.lastFrameTime = currentTime;        this.updateFPS(deltaTime);      }      // 请求下一帧      this.frameRequestId = requestAnimationFrame(frameLoop);    } catch (error) {      this.handleError(error);    }  };  // 启动循环  this.frameRequestId = requestAnimationFrame(frameLoop);}/** * 执行一帧的渲染 */executeFrame() {  // TODO: 简化的帧执行：直接让 GPU 渲染一帧  if (this.gpu) {    this.gpu.stepFrame();  }  // 更新统计  this.stats.framesRendered++;  this.stats.cyclesExecuted += SYSTEM_CONSTANTS.FRAME_CYCLES;}</code></pre><p>这种设计的优势是：</p><ul><li>性能优化：避免了复杂的周期级别计算</li><li>稳定的帧率：使用 <code>requestAnimationFrame</code> 确保流畅的 60 FPS</li><li>灵活性：可以根据需要切换到其他调度模式</li></ul><h2 id="56-错误处理与系统监控"><a class="markdownIt-Anchor" href="#56-错误处理与系统监控"></a> 5.6. 错误处理与系统监控</h2><p>一个健壮的模拟器必须能够优雅地处理错误并提供丰富的监控信息。系统调度器实现了多层次的错误处理：</p><pre><code class="language-javascript">/** * 错误处理 */handleError(error) {  this.stats.errors++;  console.error(`🚨 系统错误 #${this.stats.errors}:`, error);  // 如果错误过多，停止系统  if (this.stats.errors &gt; 10) {    console.error('❌ 错误过多，停止系统运行');    this.stop();    this.state = SYSTEM_CONSTANTS.STATE_ERROR;    return;  }  // 尝试恢复  this.retryCount++;  if (this.retryCount &lt; this.maxRetries) {    console.log(`🔄 尝试恢复系统 (${this.retryCount}/${this.maxRetries})`);    setTimeout(() =&gt; {      if (this.state === SYSTEM_CONSTANTS.STATE_ERROR) {        this.reset();      }    }, 1000);  } else {    console.error('❌ 恢复失败，系统进入错误状态');    this.state = SYSTEM_CONSTANTS.STATE_ERROR;  }}</code></pre><p>系统提供了丰富的性能统计信息：</p><pre><code class="language-javascript">/** * 更新 FPS 计算 * @param {number} deltaTime - 帧时间差 */updateFPS(deltaTime) {  this.stats.currentFPS = deltaTime &gt; 0 ? 1000 / deltaTime : 0;}/** * 计算平均 FPS */calculateAverageFPS() {  const totalTime = (performance.now() - this.stats.startTime) / 1000;  this.stats.averageFPS = totalTime &gt; 0 ? this.stats.framesRendered / totalTime : 0;}/** * 获取系统状态 */getStatus() {  const status = {    state: this.state,    scheduleMode: this.scheduleMode,    statistics: { ...this.stats },    components: {      cpu: this.cpu ? this.cpu.getStatusString() : '未初始化',      mmu: this.mmu ? this.mmu.getMemoryStats() : '未初始化',      gpu: this.gpu ? this.gpu.getStatus() : '未初始化'    }  };  // 计算实时统计  if (this.stats.startTime &gt; 0) {    const totalTime = (performance.now() - this.stats.startTime) / 1000;    status.statistics.totalRunTime = totalTime;    status.statistics.averageFPS = totalTime &gt; 0 ? this.stats.framesRendered / totalTime : 0;  }  return status;}/** * 获取调试信息 * @returns {string} 格式化的调试信息 */getDebugInfo() {  const status = this.getStatus();  let debugInfo = `🎮 === GameBoy 系统状态 ===系统状态：${status.state}调度模式：${status.scheduleMode}运行时间：${status.statistics.totalRunTime?.toFixed(2) || 0}秒已渲染帧数：${status.statistics.framesRendered}执行周期数：${status.statistics.cyclesExecuted}当前 FPS：${status.statistics.currentFPS?.toFixed(2) || 0}平均 FPS：${status.statistics.averageFPS?.toFixed(2) || 0}错误计数：${status.statistics.errors}📱 硬件组件状态：`;  // CPU 状态  if (this.cpu) {    debugInfo += `\n\n💻 CPU 状态：\n${this.cpu.getStatusString()}`;  }  // GPU 状态  if (this.gpu) {    debugInfo += `\n\n🎨 GPU 状态：\n${this.gpu.getDebugInfo()}`;  }  // MMU 状态  if (this.mmu) {    const mmuStats = this.mmu.getMemoryStats();    debugInfo += `\n\n💾 MMU 状态：BIOS 启用：${mmuStats.biosEnabled ? '是' : '否'}ROM 已加载：${mmuStats.romLoaded ? '是' : '否'}硬件连接：GPU: ${mmuStats.hardwareConnections.gpu ? '✅' : '❌'}输入: ${mmuStats.hardwareConnections.input ? '✅' : '❌'}定时器: ${mmuStats.hardwareConnections.timer ? '✅' : '❌'}中断: ${mmuStats.hardwareConnections.interrupt ? '✅' : '❌'}`;  }  return debugInfo;}/** * 获取内存转储 * @param {number} address - 起始地址 * @param {number} length - 长度 * @returns {string} 内存转储 */getMemoryDump(address, length = 256) {  if (!this.mmu) {    return '❌ MMU 未初始化';  }  return this.mmu.getMemoryDump(address, length);}/** * 设置调试模式 * @param {boolean} enabled - 是否启用调试模式 */setDebugMode(enabled) {  window.DEBUG_MODE = enabled;  console.log(`🔧 调试模式${enabled ? '已启用' : '已禁用'}`);}/** * 销毁系统（清理资源） */destroy() {  console.log('💥 销毁 GameBoy 系统...');  // 停止运行  this.stop();  // 清理组件引用  this.cpu = null;  this.mmu = null;  this.gpu = null;  this.graphics = null;  // 清理全局引用  if (window.MMU) delete window.MMU;  if (window.GPU) delete window.GPU;  if (window.CPU) delete window.CPU;  if (window.Graphics) delete window.Graphics;  console.log('✅ 系统已销毁');}</code></pre><h2 id="57-现代化用户界面"><a class="markdownIt-Anchor" href="#57-现代化用户界面"></a> 5.7. 现代化用户界面</h2><details><summary>展开以查看</summary><pre><code class="language-html">&lt;!DOCTYPE html&gt;&lt;html lang="zh-CN"&gt;&lt;head&gt;  &lt;meta charset="UTF-8"&gt;  &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;  &lt;title&gt;GameBoy 模拟器 - JavaScript 版本&lt;/title&gt;  &lt;style&gt;    /* 全局样式重置 */    * {      margin: 0;      padding: 0;      box-sizing: border-box;    }    body {      font-family: 'Courier New', monospace;      background: linear-gradient(135deg, #2c5530, #4a7c59);      color: #000;      min-height: 100vh;      padding: 20px;      display: flex;      justify-content: center;      align-items: center;    }    /* 主容器 */    .gameboy-container {      background: linear-gradient(145deg, #8b956d, #9bb583);      border-radius: 20px 20px 60px 20px;      padding: 40px;      box-shadow:              0 20px 40px rgba(0, 0, 0, 0.3),              inset 0 2px 4px rgba(255, 255, 255, 0.1);      max-width: 700px;      width: 100%;    }    /* 顶部标题区域 */    .header {      text-align: center;      margin-bottom: 30px;    }    .title {      font-size: 28px;      font-weight: bold;      color: #2c5530;      text-shadow:              1px 1px 0 rgba(255, 255, 255, 0.3),              2px 2px 4px rgba(0, 0, 0, 0.2);      margin-bottom: 10px;      letter-spacing: 2px;    }    .subtitle {      font-size: 14px;      color: #5a6b4d;      margin-bottom: 5px;    }    .version {      font-size: 12px;      color: #6b7a5e;      font-style: italic;    }    /* 屏幕区域 */    .screen-container {      background: linear-gradient(145deg, #4a5c3a, #5a6c4a);      border-radius: 15px;      padding: 25px;      margin: 30px auto;      box-shadow:              inset 0 4px 8px rgba(0, 0, 0, 0.3),              0 2px 4px rgba(255, 255, 255, 0.1);      position: relative;      width: fit-content;    }    .screen-bezel {      background: linear-gradient(145deg, #2c3624, #3c4634);      border-radius: 10px;      padding: 15px;      box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.5);    }    /* GameBoy 屏幕 Canvas */    #screen {      display: block;      width: 320px;      height: 288px;      background: #9bbc0f;      border-radius: 5px;      image-rendering: pixelated;      image-rendering: -moz-crisp-edges;      image-rendering: crisp-edges;      box-shadow:              inset 0 0 0 2px #8bac0f,              inset 0 0 0 4px #5a6b4d;    }    /* 屏幕标签 */    .screen-label {      position: absolute;      bottom: 8px;      left: 50%;      transform: translateX(-50%);      font-size: 10px;      color: #6b7a5e;      letter-spacing: 1px;    }    /* 系统状态指示器 */    .status-indicator {      position: absolute;      top: 15px;      right: 15px;      display: flex;      gap: 8px;      font-size: 10px;    }    .indicator {      width: 12px;      height: 12px;      border-radius: 50%;      border: 1px solid #333;    }    .indicator.running { background: #00ff00; }    .indicator.stopped { background: #ff0000; }    .indicator.paused { background: #ffff00; }    .indicator.error { background: #ff8800; }    /* 控制面板 */    .controls {      display: grid;      grid-template-columns: 1fr 1fr;      gap: 20px;      margin-top: 30px;    }    .control-section {      background: linear-gradient(145deg, #7a8a6d, #8a9a7d);      border-radius: 12px;      padding: 20px;      box-shadow:              inset 0 2px 4px rgba(255, 255, 255, 0.1),              0 4px 8px rgba(0, 0, 0, 0.2);    }    .control-title {      font-size: 14px;      font-weight: bold;      color: #2c5530;      margin-bottom: 15px;      text-align: center;      border-bottom: 1px solid #5a6b4d;      padding-bottom: 8px;    }    /* 按钮样式 */    .btn {      background: linear-gradient(145deg, #a5b588, #95a578);      border: none;      border-radius: 8px;      padding: 12px 20px;      color: #2c5530;      font-weight: bold;      font-size: 12px;      cursor: pointer;      transition: all 0.2s ease;      box-shadow:              0 3px 6px rgba(0, 0, 0, 0.2),              inset 0 1px 2px rgba(255, 255, 255, 0.2);      margin: 5px;      width: calc(100% - 10px);      position: relative;    }    .btn:hover {      background: linear-gradient(145deg, #b5c598, #a5b588);      transform: translateY(-1px);      box-shadow:              0 4px 8px rgba(0, 0, 0, 0.3),              inset 0 1px 2px rgba(255, 255, 255, 0.3);    }    .btn:active {      transform: translateY(1px);      box-shadow:              0 2px 4px rgba(0, 0, 0, 0.2),              inset 0 2px 4px rgba(0, 0, 0, 0.1);    }    .btn:disabled {      opacity: 0.6;      cursor: not-allowed;      transform: none;    }    .btn.primary {      background: linear-gradient(145deg, #5a7c4a, #4a6c3a);      color: #fff;    }    .btn.primary:hover:not(:disabled) {      background: linear-gradient(145deg, #6a8c5a, #5a7c4a);    }    .btn.danger {      background: linear-gradient(145deg, #a56565, #955555);      color: #fff;    }    .btn.danger:hover:not(:disabled) {      background: linear-gradient(145deg, #b57575, #a56565);    }    .btn.success {      background: linear-gradient(145deg, #5a8a5a, #4a7a4a);      color: #fff;    }    .btn.success:hover:not(:disabled) {      background: linear-gradient(145deg, #6a9a6a, #5a8a5a);    }    /* 按钮状态指示 */    .btn.loading::after {      content: '';      position: absolute;      right: 10px;      top: 50%;      transform: translateY(-50%);      width: 12px;      height: 12px;      border: 2px solid transparent;      border-top: 2px solid currentColor;      border-radius: 50%;      animation: spin 1s linear infinite;    }    @keyframes spin {      to { transform: translateY(-50%) rotate(360deg); }    }    /* 状态显示区域 */    .status-panel {      margin-top: 30px;      background: linear-gradient(145deg, #3c4634, #4c5644);      border-radius: 12px;      padding: 20px;      box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.3);    }    .status-title {      color: #9bb583;      font-size: 14px;      font-weight: bold;      margin-bottom: 15px;      text-align: center;    }    .status-content {      background: #1a1a1a;      color: #00ff00;      font-family: 'Courier New', monospace;      font-size: 11px;      padding: 15px;      border-radius: 6px;      height: 250px;      overflow-y: auto;      border: 1px solid #333;      white-space: pre-wrap;    }    /* 性能面板 */    .performance-panel {      margin-top: 20px;      background: linear-gradient(145deg, #2c3624, #3c4634);      border-radius: 12px;      padding: 20px;      box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.3);    }    .performance-grid {      display: grid;      grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));      gap: 15px;      margin-top: 15px;    }    .performance-item {      text-align: center;      padding: 10px;      background: rgba(0, 0, 0, 0.3);      border-radius: 8px;    }    .performance-value {      display: block;      font-size: 18px;      font-weight: bold;      color: #00ff00;      margin-bottom: 5px;    }    .performance-label {      font-size: 10px;      color: #9bb583;      text-transform: uppercase;    }    /* 响应式设计 */    @media (max-width: 768px) {      .gameboy-container {        padding: 20px;        margin: 10px;      }      #screen {        width: 240px;        height: 216px;      }      .controls {        grid-template-columns: 1fr;        gap: 15px;      }      .title {        font-size: 24px;      }      .performance-grid {        grid-template-columns: repeat(2, 1fr);      }    }    /* 信息提示 */    .info-box {      background: linear-gradient(145deg, #6a7c5a, #7a8c6a);      border-radius: 8px;      padding: 15px;      margin: 20px 0;      border-left: 4px solid #4a6c3a;      color: #2c5530;      font-size: 13px;      line-height: 1.5;    }    .info-box h4 {      margin-bottom: 8px;      color: #1a3520;    }    /* 键盘快捷键显示 */    .keyboard-hint {      font-size: 10px;      color: #6b7a5e;      text-align: center;      margin-top: 10px;    }    .key {      background: #5a6b4d;      color: #fff;      padding: 2px 6px;      border-radius: 3px;      font-weight: bold;      margin: 0 2px;    }  &lt;/style&gt;&lt;/head&gt;&lt;body&gt;&lt;div class="gameboy-container"&gt;  &lt;!-- 顶部标题区域 --&gt;  &lt;div class="header"&gt;    &lt;h1 class="title"&gt;GAME BOY&lt;/h1&gt;    &lt;div class="subtitle"&gt;JavaScript 模拟器&lt;/div&gt;    &lt;div class="version"&gt;版本 0.5.0 - 系统集成&lt;/div&gt;  &lt;/div&gt;  &lt;!-- 屏幕区域 --&gt;  &lt;div class="screen-container"&gt;    &lt;div class="status-indicator"&gt;      &lt;div class="indicator stopped" id="system-indicator" title="系统状态"&gt;&lt;/div&gt;    &lt;/div&gt;    &lt;div class="screen-bezel"&gt;      &lt;canvas id="screen" width="160" height="144"&gt;&lt;/canvas&gt;      &lt;div class="screen-label"&gt;DOT MATRIX WITH STEREO SOUND&lt;/div&gt;    &lt;/div&gt;  &lt;/div&gt;  &lt;!-- 控制面板 --&gt;  &lt;div class="controls"&gt;    &lt;!-- 系统控制 --&gt;    &lt;div class="control-section"&gt;      &lt;div class="control-title"&gt;🎮 系统控制&lt;/div&gt;      &lt;button class="btn primary" id="init-btn"&gt;初始化系统&lt;/button&gt;      &lt;button class="btn success" id="start-btn" disabled&gt;开始运行&lt;/button&gt;      &lt;button class="btn" id="pause-btn" disabled&gt;暂停/恢复&lt;/button&gt;      &lt;button class="btn danger" id="stop-btn" disabled&gt;停止运行&lt;/button&gt;      &lt;button class="btn" id="reset-btn" disabled&gt;重置系统&lt;/button&gt;      &lt;div class="keyboard-hint"&gt;        快捷键：&lt;span class="key"&gt;Space&lt;/span&gt; 开始/暂停 &lt;span class="key"&gt;R&lt;/span&gt; 重置      &lt;/div&gt;    &lt;/div&gt;    &lt;!-- 程序加载 --&gt;    &lt;div class="control-section"&gt;      &lt;div class="control-title"&gt;📦 程序加载&lt;/div&gt;      &lt;button class="btn" id="load-demo-btn" disabled&gt;加载演示程序&lt;/button&gt;      &lt;button class="btn" id="load-rom-btn" disabled&gt;加载 ROM 文件&lt;/button&gt;      &lt;input type="file" id="rom-file-input" accept=".gb,.gbc" style="display: none;"&gt;      &lt;button class="btn" id="step-btn" disabled&gt;单步执行&lt;/button&gt;      &lt;div class="keyboard-hint"&gt;        快捷键：&lt;span class="key"&gt;L&lt;/span&gt; 加载演示 &lt;span class="key"&gt;S&lt;/span&gt; 单步      &lt;/div&gt;    &lt;/div&gt;  &lt;/div&gt;  &lt;!-- 调试和图形控制 --&gt;  &lt;div class="controls"&gt;    &lt;!-- 调试工具 --&gt;    &lt;div class="control-section"&gt;      &lt;div class="control-title"&gt;🔧 调试工具&lt;/div&gt;      &lt;button class="btn" id="show-status-btn"&gt;显示系统状态&lt;/button&gt;      &lt;button class="btn" id="show-memory-btn"&gt;内存转储&lt;/button&gt;      &lt;button class="btn" id="show-registers-btn"&gt;CPU 寄存器&lt;/button&gt;      &lt;button class="btn" id="toggle-debug-btn"&gt;切换调试模式&lt;/button&gt;      &lt;div class="keyboard-hint"&gt;        快捷键：&lt;span class="key"&gt;D&lt;/span&gt; 调试 &lt;span class="key"&gt;M&lt;/span&gt; 内存      &lt;/div&gt;    &lt;/div&gt;    &lt;!-- 图形控制 --&gt;    &lt;div class="control-section"&gt;      &lt;div class="control-title"&gt;🎨 图形控制&lt;/div&gt;      &lt;button class="btn" id="toggle-render-btn"&gt;切换渲染模式&lt;/button&gt;      &lt;button class="btn" id="show-graphics-btn"&gt;图形系统状态&lt;/button&gt;      &lt;button class="btn" id="test-graphics-btn"&gt;测试图形渲染&lt;/button&gt;      &lt;button class="btn danger" id="clear-console-btn"&gt;清空控制台&lt;/button&gt;      &lt;div class="keyboard-hint"&gt;        快捷键：&lt;span class="key"&gt;G&lt;/span&gt; 图形模式 &lt;span class="key"&gt;T&lt;/span&gt; 测试      &lt;/div&gt;    &lt;/div&gt;  &lt;/div&gt;  &lt;!-- 性能监控面板 --&gt;  &lt;div class="performance-panel"&gt;    &lt;div class="status-title"&gt;📊 实时性能监控&lt;/div&gt;    &lt;div class="performance-grid"&gt;      &lt;div class="performance-item"&gt;        &lt;span class="performance-value" id="fps-value"&gt;0.0&lt;/span&gt;        &lt;span class="performance-label"&gt;FPS&lt;/span&gt;      &lt;/div&gt;      &lt;div class="performance-item"&gt;        &lt;span class="performance-value" id="frames-value"&gt;0&lt;/span&gt;        &lt;span class="performance-label"&gt;帧数&lt;/span&gt;      &lt;/div&gt;      &lt;div class="performance-item"&gt;        &lt;span class="performance-value" id="instructions-value"&gt;0&lt;/span&gt;        &lt;span class="performance-label"&gt;指令数&lt;/span&gt;      &lt;/div&gt;      &lt;div class="performance-item"&gt;        &lt;span class="performance-value" id="cycles-value"&gt;0&lt;/span&gt;        &lt;span class="performance-label"&gt;周期数&lt;/span&gt;      &lt;/div&gt;      &lt;div class="performance-item"&gt;        &lt;span class="performance-value" id="errors-value"&gt;0&lt;/span&gt;        &lt;span class="performance-label"&gt;错误数&lt;/span&gt;      &lt;/div&gt;      &lt;div class="performance-item"&gt;        &lt;span class="performance-value" id="uptime-value"&gt;0s&lt;/span&gt;        &lt;span class="performance-label"&gt;运行时间&lt;/span&gt;      &lt;/div&gt;    &lt;/div&gt;  &lt;/div&gt;  &lt;!-- 状态显示面板 --&gt;  &lt;div class="status-panel"&gt;    &lt;div class="status-title"&gt;📋 系统控制台 &amp; 调试输出&lt;/div&gt;    &lt;div id="console-output" class="status-content"&gt;GameBoy 模拟器 v0.5.0 已准备就绪...🎮 第五章：系统集成✨ 新功能：完整的系统架构、CPU 指令集、寄存器控制等待系统初始化...使用说明：1. 点击"初始化系统"启动模拟器2. 点击"加载演示程序"或加载 ROM 文件3. 点击"开始运行"启动系统4. 观察实时性能监控和调试输出5. 使用调试工具查看系统状态组件状态：- CPU: 等待初始化...- MMU: 等待初始化...- GPU: 等待初始化...- 图形系统: 等待初始化...- 系统调度器: 等待初始化...    &lt;/div&gt;  &lt;/div&gt;&lt;/div&gt;&lt;!-- JavaScript 文件导入 --&gt;&lt;script src="mmu.js"&gt;&lt;/script&gt;&lt;script src="graphics.js"&gt;&lt;/script&gt;&lt;script src="gpu.js"&gt;&lt;/script&gt;&lt;script src="cpu.js"&gt;&lt;/script&gt;&lt;script src="gameboy.js"&gt;&lt;/script&gt;&lt;!-- 主程序脚本 --&gt;&lt;script&gt;(function() {  'use strict';    // 全局变量  let systemInstance = null;  // 避免与 gameboy.js 中的变量冲突  let performanceUpdateInterval = null;  let isDebugMode = false;  // UI 元素引用  const elements = {    // 按钮    initBtn: document.getElementById('init-btn'),    startBtn: document.getElementById('start-btn'),    pauseBtn: document.getElementById('pause-btn'),    stopBtn: document.getElementById('stop-btn'),    resetBtn: document.getElementById('reset-btn'),    loadDemoBtn: document.getElementById('load-demo-btn'),    loadRomBtn: document.getElementById('load-rom-btn'),    stepBtn: document.getElementById('step-btn'),    showStatusBtn: document.getElementById('show-status-btn'),    showMemoryBtn: document.getElementById('show-memory-btn'),    showRegistersBtn: document.getElementById('show-registers-btn'),    toggleDebugBtn: document.getElementById('toggle-debug-btn'),    toggleRenderBtn: document.getElementById('toggle-render-btn'),    showGraphicsBtn: document.getElementById('show-graphics-btn'),    testGraphicsBtn: document.getElementById('test-graphics-btn'),    clearConsoleBtn: document.getElementById('clear-console-btn'),        // 状态指示器    systemIndicator: document.getElementById('system-indicator'),        // 性能显示    fpsValue: document.getElementById('fps-value'),    framesValue: document.getElementById('frames-value'),    instructionsValue: document.getElementById('instructions-value'),    cyclesValue: document.getElementById('cycles-value'),    errorsValue: document.getElementById('errors-value'),    uptimeValue: document.getElementById('uptime-value'),        // 控制台输出    consoleOutput: document.getElementById('console-output'),        // 文件输入    romFileInput: document.getElementById('rom-file-input')  };  // 添加日志输出功能  function addLog(message, type = 'info') {    const timestamp = new Date().toLocaleTimeString();    const prefix = {      'info': '📝',      'success': '✅',      'warning': '⚠️',      'error': '❌',      'debug': '🔧'    }[type] || '📝';        elements.consoleOutput.textContent += `[${timestamp}] ${prefix} ${message}\n`;    elements.consoleOutput.scrollTop = elements.consoleOutput.scrollHeight;  }  // 重写 console.log 以在页面上显示  const originalConsoleLog = console.log;  const originalConsoleError = console.error;  const originalConsoleWarn = console.warn;  console.log = function(...args) {    originalConsoleLog.apply(console, args);    const message = args.join(' ');        // 只有重要消息才显示到页面    const importantKeywords = ['✅', '❌', '⚠️', '🎮', '📊', '🔧', '初始化', '加载', '错误', '完成'];    if (importantKeywords.some(keyword =&gt; message.includes(keyword)) || isDebugMode) {      addLog(message);    }  };  console.error = function(...args) {    originalConsoleError.apply(console, args);    addLog(args.join(' '), 'error');  };  console.warn = function(...args) {    originalConsoleWarn.apply(console, args);    addLog(args.join(' '), 'warning');  };  // 更新系统状态指示器  function updateSystemIndicator(state) {    const indicator = elements.systemIndicator;    indicator.className = `indicator ${state}`;    indicator.title = `系统状态: ${state}`;  }  // 更新按钮状态  function updateButtonStates(systemState) {    const isInitialized = systemInstance !== null;    const isRunning = systemState === 'running';    const isStopped = systemState === 'stopped';        elements.initBtn.disabled = isInitialized;    elements.startBtn.disabled = !isInitialized || isRunning;    elements.pauseBtn.disabled = !isInitialized || isStopped;    elements.stopBtn.disabled = !isInitialized || isStopped;    elements.resetBtn.disabled = !isInitialized;    elements.loadDemoBtn.disabled = !isInitialized;    elements.loadRomBtn.disabled = !isInitialized;    elements.stepBtn.disabled = !isInitialized || isRunning;  }  // 系统初始化  async function initializeSystem() {    try {      addLog('正在初始化 GameBoy 系统...', 'info');      elements.initBtn.classList.add('loading');            // 使用系统控制器      systemInstance = await window.GameBoySystemController.init();            updateSystemIndicator('stopped');      updateButtonStates('stopped');            // 启动性能监控      startPerformanceMonitoring();            addLog('✅ GameBoy 系统初始化完成', 'success');          } catch (error) {      addLog(`❌ 系统初始化失败: ${error.message}`, 'error');      updateSystemIndicator('error');    } finally {      elements.initBtn.classList.remove('loading');    }  }  // 系统控制函数  function startSystem() {    if (!systemInstance) {      addLog('❌ 系统未初始化', 'error');      return;    }    try {      window.GameBoySystemController.start();      updateSystemIndicator('running');      updateButtonStates('running');      addLog('🚀 系统开始运行', 'success');    } catch (error) {      addLog(`❌ 启动失败: ${error.message}`, 'error');    }  }  function pauseSystem() {    if (!systemInstance) return;        try {      window.GameBoySystemController.togglePause();      const status = window.GameBoySystemController.getStatus();      updateSystemIndicator(status.state);      updateButtonStates(status.state);      addLog(`⏸️ 系统${status.state === 'paused' ? '已暂停' : '继续运行'}`, 'info');    } catch (error) {      addLog(`❌ 暂停操作失败: ${error.message}`, 'error');    }  }  function stopSystem() {    if (!systemInstance) return;        try {      window.GameBoySystemController.stop();      updateSystemIndicator('stopped');      updateButtonStates('stopped');      addLog('⏹️ 系统已停止', 'info');    } catch (error) {      addLog(`❌ 停止操作失败: ${error.message}`, 'error');    }  }  function resetSystem() {    if (!systemInstance) return;        try {      window.GameBoySystemController.reset();      updateSystemIndicator('stopped');      updateButtonStates('stopped');      addLog('🔄 系统已重置', 'info');    } catch (error) {      addLog(`❌ 重置失败: ${error.message}`, 'error');    }  }  function stepSystem() {    if (!systemInstance) return;        try {      // TODO: 实现单步执行      addLog('👣 执行单步操作...', 'debug');    } catch (error) {      addLog(`❌ 单步执行失败: ${error.message}`, 'error');    }  }  // 程序加载函数  async function loadDemo() {    if (!systemInstance) {      addLog('❌ 系统未初始化', 'error');      return;    }    try {      addLog('📦 正在加载演示程序...', 'info');      const success = window.GameBoySystemController.loadDemo();            if (success) {        addLog('✅ 演示程序加载完成', 'success');        addLog('💡 现在可以点击"开始运行"启动系统', 'info');      } else {        addLog('❌ 演示程序加载失败', 'error');      }    } catch (error) {      addLog(`❌ 加载演示程序失败: ${error.message}`, 'error');    }  }  function loadROMFile() {    elements.romFileInput.click();  }  async function handleROMFile(event) {    const file = event.target.files[0];    if (!file) return;    try {      addLog(`📦 正在加载 ROM 文件: ${file.name}`, 'info');            const arrayBuffer = await file.arrayBuffer();      const success = await window.GameBoySystemController.loadROM(arrayBuffer);            if (success) {        addLog(`✅ ROM 文件加载完成: ${file.name}`, 'success');      } else {        addLog(`❌ ROM 文件加载失败: ${file.name}`, 'error');      }    } catch (error) {      addLog(`❌ 文件读取失败: ${error.message}`, 'error');    }  }  // 调试工具函数  function showSystemStatus() {    if (!systemInstance) {      addLog('❌ 系统未初始化', 'error');      return;    }    try {      const debugInfo = window.GameBoySystemController.getDebugInfo();      addLog('📊 === 系统状态 ===', 'debug');      addLog(debugInfo, 'debug');      addLog('=================', 'debug');    } catch (error) {      addLog(`❌ 获取系统状态失败: ${error.message}`, 'error');    }  }  function showMemoryDump() {    if (!systemInstance) {      addLog('❌ 系统未初始化', 'error');      return;    }    try {      const system = window.GameBoySystemController.getInstance();      if (system &amp;&amp; system.mmu) {        addLog('💾 === 内存转储 (0x0000-0x00FF) ===', 'debug');        const dump = system.getMemoryDump(0x0000, 256);        addLog(dump, 'debug');      }    } catch (error) {      addLog(`❌ 内存转储失败: ${error.message}`, 'error');    }  }  function showCPURegisters() {    if (!systemInstance) {      addLog('❌ 系统未初始化', 'error');      return;    }    try {      const system = window.GameBoySystemController.getInstance();      if (system &amp;&amp; system.cpu) {        addLog('💻 === CPU 寄存器状态 ===', 'debug');        addLog(system.cpu.getStatusString(), 'debug');      }    } catch (error) {      addLog(`❌ 获取 CPU 状态失败: ${error.message}`, 'error');    }  }  function toggleDebugMode() {    isDebugMode = !isDebugMode;    window.DEBUG_MODE = isDebugMode;    addLog(`🔧 调试模式${isDebugMode ? '已启用' : '已禁用'}`, 'debug');  }  // 图形控制函数  function toggleRenderMode() {    try {      const system = window.GameBoySystemController.getInstance();      if (system &amp;&amp; system.gpu) {        const currentMode = system.gpu.renderMode || 'test';        const newMode = currentMode === 'test' ? 'graphics' : 'test';        system.gpu.setRenderMode(newMode);        addLog(`🎨 渲染模式已切换到：${newMode === 'test' ? '测试模式' : '图形模式'}`, 'info');      }    } catch (error) {      addLog(`❌ 切换渲染模式失败: ${error.message}`, 'error');    }  }  function showGraphicsStatus() {    try {      const system = window.GameBoySystemController.getInstance();      if (system &amp;&amp; system.gpu) {        addLog('🎨 === 图形系统状态 ===', 'debug');        addLog(system.gpu.getDebugInfo(), 'debug');      }    } catch (error) {      addLog(`❌ 获取图形状态失败: ${error.message}`, 'error');    }  }  function testGraphicsSystem() {    try {      const system = window.GameBoySystemController.getInstance();      if (system &amp;&amp; system.gpu) {        addLog('🧪 运行图形系统测试...', 'debug');                // 创建测试数据        if (system.mmu &amp;&amp; system.mmu.vram) {          const vram = system.mmu.vram;                    // 创建测试瓦片          for (let i = 0; i &lt; 16; i += 2) {            vram[0x8000 + i] = Math.floor(Math.random() * 256);            vram[0x8000 + i + 1] = Math.floor(Math.random() * 256);          }                    addLog('✅ 测试数据已生成', 'debug');        }                // 测试渲染        system.gpu.stepFrame();        addLog('✅ 图形系统测试完成', 'success');      }    } catch (error) {      addLog(`❌ 图形系统测试失败: ${error.message}`, 'error');    }  }  function clearConsoleLog() {    elements.consoleOutput.textContent = 'GameBoy 模拟器控制台\n已清空...\n\n';  }  // 性能监控  function startPerformanceMonitoring() {    performanceUpdateInterval = setInterval(updatePerformanceDisplay, 500);  }  function updatePerformanceDisplay() {    if (!systemInstance) return;    try {      const status = window.GameBoySystemController.getStatus();      if (!status) return;      const stats = status.statistics;            // 更新显示      elements.fpsValue.textContent = (stats.currentFPS || 0).toFixed(1);      elements.framesValue.textContent = stats.framesRendered || 0;      elements.instructionsValue.textContent = formatNumber(stats.cyclesExecuted / 4 || 0);      elements.cyclesValue.textContent = formatNumber(stats.cyclesExecuted || 0);      elements.errorsValue.textContent = stats.errors || 0;      elements.uptimeValue.textContent = formatTime(stats.totalRunTime || 0);          } catch (error) {      // 静默处理性能监控错误    }  }  function formatNumber(num) {    if (num &gt;= 1000000) {      return (num / 1000000).toFixed(1) + 'M';    } else if (num &gt;= 1000) {      return (num / 1000).toFixed(1) + 'K';    }    return num.toString();  }  function formatTime(seconds) {    if (seconds &gt;= 60) {      const minutes = Math.floor(seconds / 60);      const remainingSeconds = Math.floor(seconds % 60);      return `${minutes}m${remainingSeconds}s`;    }    return `${Math.floor(seconds)}s`;  }  // 绑定事件监听器  function bindEventListeners() {    elements.initBtn.addEventListener('click', initializeSystem);    elements.startBtn.addEventListener('click', startSystem);    elements.pauseBtn.addEventListener('click', pauseSystem);    elements.stopBtn.addEventListener('click', stopSystem);    elements.resetBtn.addEventListener('click', resetSystem);    elements.loadDemoBtn.addEventListener('click', loadDemo);    elements.loadRomBtn.addEventListener('click', loadROMFile);    elements.stepBtn.addEventListener('click', stepSystem);    elements.showStatusBtn.addEventListener('click', showSystemStatus);    elements.showMemoryBtn.addEventListener('click', showMemoryDump);    elements.showRegistersBtn.addEventListener('click', showCPURegisters);    elements.toggleDebugBtn.addEventListener('click', toggleDebugMode);    elements.toggleRenderBtn.addEventListener('click', toggleRenderMode);    elements.showGraphicsBtn.addEventListener('click', showGraphicsStatus);    elements.testGraphicsBtn.addEventListener('click', testGraphicsSystem);    elements.clearConsoleBtn.addEventListener('click', clearConsoleLog);    elements.romFileInput.addEventListener('change', handleROMFile);  }  // 键盘快捷键  document.addEventListener('keydown', function(event) {    // 防止在输入框中触发快捷键    if (event.target.tagName === 'INPUT') return;        switch(event.code) {      case 'Space':        event.preventDefault();        if (systemInstance) {          const status = window.GameBoySystemController.getStatus();          if (status.state === 'running') {            pauseSystem();          } else {            startSystem();          }        }        break;      case 'KeyR':        event.preventDefault();        resetSystem();        break;      case 'KeyL':        event.preventDefault();        loadDemo();        break;      case 'KeyS':        event.preventDefault();        stepSystem();        break;      case 'KeyD':        event.preventDefault();        showSystemStatus();        break;      case 'KeyM':        event.preventDefault();        showMemoryDump();        break;      case 'KeyG':        event.preventDefault();        toggleRenderMode();        break;      case 'KeyT':        event.preventDefault();        testGraphicsSystem();        break;    }  });  // 页面加载完成后的初始化  window.addEventListener('load', function() {    bindEventListeners();        addLog('🎮 GameBoy 模拟器 v0.5.0 已准备就绪', 'success');    addLog('📚 当前版本：第五章 - 系统集成', 'info');    addLog('✨ 新功能：完整系统架构、CPU 指令集、寄存器控制', 'info');    addLog('💡 点击"初始化系统"开始使用', 'info');    // 检查组件加载状态    setTimeout(() =&gt; {      const components = [        { name: 'MMU', check: () =&gt; typeof GameBoyMMU !== 'undefined' },        { name: 'GPU', check: () =&gt; typeof GameBoyGPU !== 'undefined' },        { name: 'CPU', check: () =&gt; typeof GameBoyCPU !== 'undefined' },        { name: '图形系统', check: () =&gt; typeof GameBoyGraphicsSystem !== 'undefined' },        { name: '系统控制器', check: () =&gt; typeof GameBoySystem !== 'undefined' }      ];      components.forEach(comp =&gt; {        if (comp.check()) {          addLog(`✅ ${comp.name} 组件已加载`, 'success');        } else {          addLog(`❌ ${comp.name} 组件加载失败`, 'error');        }      });            addLog('🔧 所有组件检查完成，可以开始初始化', 'info');    }, 500);  });  // 页面卸载时清理  window.addEventListener('beforeunload', function() {    if (performanceUpdateInterval) {      clearInterval(performanceUpdateInterval);    }        if (systemInstance) {      window.GameBoySystemController.stop();    }  });})();&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;</code></pre></details><p>效果（点击 <em>初始化系统</em> → <em>切换渲染模式</em> → <em>测试图形渲染</em> → <em>加载演示程序</em> → <em>开始运行</em>）：</p><p><img src="/posts/4148/1.webp" alt="alt text" loading="lazy"></p><h2 id="58-全局系统控制接口"><a class="markdownIt-Anchor" href="#58-全局系统控制接口"></a> 5.8. 全局系统控制接口</h2><p>为了方便外部访问和调试，我们写一个统一的全局的系统控制接口：</p><pre><code class="language-javascript">/** * 全局系统控制函数 */window.GameBoySystemController = {/** * 初始化系统 */async init() {try {if (!gameBoySystem) {gameBoySystem = new GameBoySystem();}await gameBoySystem.initialize();window.GameBoySystem = gameBoySystem; // 全局引用return gameBoySystem;} catch (error) {console.error('❌ 系统初始化失败:', error);throw error;}},/** * 获取系统实例 */getInstance() {return gameBoySystem;},/** * 重置系统 */reset() {if (gameBoySystem) {gameBoySystem.reset();}},/** * 启动系统 */start(mode) {if (gameBoySystem) {gameBoySystem.start(mode);}},/** * 停止系统 */stop() {if (gameBoySystem) {gameBoySystem.stop();}},/** * 暂停/恢复 */togglePause() {if (gameBoySystem) {gameBoySystem.togglePause();}},/** * 加载 ROM */async loadROM(romData) {if (gameBoySystem) {return await gameBoySystem.loadROM(romData);}return false;},/** * 加载演示 */loadDemo() {if (gameBoySystem) {return gameBoySystem.loadDemo();}return false;},/** * 获取状态 */getStatus() {if (gameBoySystem) {return gameBoySystem.getStatus();}return null;},/** * 获取调试信息 */getDebugInfo() {if (gameBoySystem) {return gameBoySystem.getDebugInfo();}return '系统未初始化';}};</code></pre><p>这个控制器接口使得前端可以通过简洁的 API 来操作整个模拟器系统，同时在浏览器控制台中也可以直接调用这些方法进行调试：</p><pre><code class="language-javascript">// 在浏览器控制台中const system = window.GameBoySystemController.getInstance();// 查看系统状态console.log(system.getStatus());// 测试寄存器system.gpu.writeRegister(0xFF43, 50); // 设置水平滚动console.log(system.gpu.readRegister(0xFF43)); // 读取确认</code></pre><p><img src="/posts/4148/2.webp" alt="alt text" loading="lazy"></p></body></html>]]></content>
    
    
    <summary type="html">本文是一篇使用现代 JavaScript (ES6) 从零开始制作 GameBoy 模拟器的详细教程（上篇）。文章循序渐进地讲解了模拟 GameBoy 核心硬件的原理与实现，内容涵盖 Z80 CPU 的指令周期、内存管理单元（MMU）的内存映射、GPU 的显示时序和瓦片图形渲染系统。最终通过一个系统调度器将这些独立的模块集成起来，构建出一个完整、可运行的模拟器基础架构。本教程不仅提供了大量代码示例，还用通俗易懂的方式解释了底层硬件的工作原理，适合对模拟器开发、计算机体系结构或复古游戏技术感兴趣的开发者。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="JavaScript" scheme="https://blog.cytrogen.icu/tags/JavaScript/"/>
    
  </entry>
  
  <entry>
    <title>CMP 2800 笔记</title>
    <link href="https://blog.cytrogen.icu/posts/5e08.html"/>
    <id>https://blog.cytrogen.icu/posts/5e08.html</id>
    <published>2025-04-07T04:00:00.000Z</published>
    <updated>2026-02-09T17:16:54.681Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>世界文学经典学笔记，仅作为个人学习记录，不保证正确性。</p><span id="more"></span><div class="danger"><p>这节课以 <strong>The Norton Anthology: World Literature</strong> 为基础。</p></div><h1 id="1-古代美索不达米亚与近东文学"><a class="markdownIt-Anchor" href="#1-古代美索不达米亚与近东文学"></a> 1. 古代美索不达米亚与近东文学</h1><h2 id="11-创世与宇宙观"><a class="markdownIt-Anchor" href="#11-创世与宇宙观"></a> 1.1. 创世与宇宙观</h2><p>古代近东地区的多个文明都有自己的创世神话和宇宙观念。</p><p>美索不达米亚（两河流域，即底格里斯河和幼发拉底河之间的区域）的创世神话《埃努玛・埃利什》描述了马尔杜克神击败提亚玛特（混沌之海）创造世界。</p><blockquote><p>马尔杜克是巴比伦的主神，又称「太阳牛犊」、雷暴之神。</p><p>提亚玛特又被称为龙、咸海，同甜海阿普苏诞生出众神，却又因吵闹决定消灭后代，最终被后代马尔杜克所杀、尸骸被拿去创造了天和地。</p></blockquote><p>这个神话反映了秩序战胜混沌的主题，马尔杜克用提亚玛特的身体创造天地，建立了宇宙的秩序和规则。《埃努玛・埃利什》以「太初没有天地」开始，描述了诸神间的权力斗争，最终马尔杜克成为众神之王，确立了巴比伦作为宗教中心的合法性。</p><p>埃及人则相信世界起源于努恩（原初之水），由阿图姆神创造。在太初只有无边无际的黑暗水域，阿图姆从中自我创生，随后创造了空气之神舒和湿气女神泰芙努特，开启了世界的形成。</p><p>埃及的创世神话与尼罗河的季节性泛滥密切相关，反映了水在埃及文明中的核心地位。他们相信世界开始于一座从原初之水中升起的小山，就像尼罗河泛滥退去后露出的肥沃土地。</p><p>这些早期的创世叙事不仅解释了世界的起源，也为各自文明提供了宇宙秩序的基础架构，人类在其中找到了自己的位置。它们结合了观察自然现象的经验与对超自然力量的信仰，形成了复杂的世界解释系统。</p><h2 id="12-吉尔伽美什史诗"><a class="markdownIt-Anchor" href="#12-吉尔伽美什史诗"></a> 1.2. 《吉尔伽美什史诗》</h2><p>约公元前 2100 年，美索不达米亚（现今伊拉克）用楔形文字将《吉尔伽美什史诗》记录在泥板上。这部作品被公认为人类最早的史诗，见证了文字如何成为跨越时空的记忆载体。</p><p>最完整版本出土于亚述国王阿舒尔巴尼拔（公元前 668 到 627 年）的尼尼微图书馆，包含 12 块泥板。这位对知识有着强烈热情的国王派人收集和抄录了大量文献，无意中保存了这部珍贵的史诗，使它得以在数千年后重见天日。19 世纪的考古学家乔治・史密斯在大英博物馆发现并首次解读了其中描述洪水的片段，震惊了学术界。</p><blockquote><p>故事讲述了乌鲁克城邦王吉尔伽美什的冒险。</p><p>吉尔伽美什是一位半神半人的国王（三分之二神，三分之一人），力大无穷却暴虐无道。他强迫臣民为他建造城墙，还实行初夜权，引起民众不满。神明创造了野人恩奇都与他抗衡，两人却在搏斗后成为挚友。他们共同击败了森林守护者胡瓦瓦（又称洪巴巴）和天牛，因此激怒了诸神。诸神决定惩罚他们，使恩奇都生病死亡。</p><p>恩奇都死后，吉尔伽美什对死亡产生恐惧，决心寻找不死的秘密。他穿越危险的马苏山，遇到了酒馆女主人希杜丽，渡过死亡之水，最终找到了洪水幸存者乌特纳皮什提姆。乌特纳皮什提姆讲述了大洪水的故事，告诉吉尔伽美什有一种能让人恢复青春的水下植物。吉尔伽美什获得了这种植物，但在回程中却被蛇偷走。最终，他带着对生命有限性的理解回到乌鲁克，接受了人类的命运。</p></blockquote><p>无论是谁或许都会对永生产生渴望，面对挚友的离世，我们不禁思考自己的命运。吉尔伽美什的不朽追求正反映了人类面对死亡的普遍恐惧与对永恒的渴望，这一主题在后世文学中不断回响。当恩奇都临死前诅咒让他文明化的女祭司，却被太阳神沙玛什提醒他因文明而获得的好处时，史诗直接提出了关于人类文明本质的深刻问题。</p><p>故事中，恩奇都从野人变为文明人的过程揭示了古代美索不达米亚人对文明与自然关系的复杂思考。最初的恩奇都与野兽一同生活，「他的身体覆盖着浓密的毛发…… 他与瞪羚一起吃草，与野兽一起在水边饮水」。当女祭司沙姆哈特引诱他，与她同住七天七夜后，野兽们不再接纳他：「羚羊见到他就跑开了…… 恩奇都的身体变得迟钝，他的腿无法像从前那样快速奔跑。」这一转变既表明了文明的益处，也暗示了其代价。文明为恩奇都带来了友谊、美食、美酒和智慧：「他洗净身体，用油膏抹身…… 他穿上衣服，变得像个战士」，沙姆哈特告诉他：「恩奇都啊，你已经变得像神一样，为何还要与野兽一起在荒野游荡？」</p><p>文明使他获得了人性的高贵特质，但也失去了与自然的和谐共处和某种原始的纯真。更深层次上，这反映了农业文明兴起后人类对狩猎采集生活方式的某种怀念，暗示城市文明虽然带来了物质繁荣和知识进步，却也导致了与自然的疏离，并伴随着社会阶层分化和劳动强化。这种二元性在史诗末尾达到高潮 —— 吉尔伽美什虽然没能获得永生，却通过建造城墙（文明的象征）获得了某种形式的不朽。</p><p>乌特纳皮什提姆向吉尔伽美什讲述的洪水故事与圣经中的诺亚方舟有着惊人的相似之处，这表明古代近东地区可能确实经历过大洪水，或者这些文明间存在文化交流与影响。在两个故事中，神明都决定毁灭人类，只有一位义人及其家人（和动物）得以幸存。</p><p>《吉尔伽美什史诗》确立了英雄叙事的基本模式，探讨的命运、死亡、友谊等主题构成了人类共同的精神遗产。史诗中的重要象征如城墙（文明的边界）、森林（未知与野性）和水（生命与死亡）在后世无数作品中被重新诠释。透过这部作品，我们不仅看到古代美索不达米亚的世界观，也看到了人类自古以来就共有的情感与思考。</p><p>什么是史诗？史诗是一种长篇叙事诗，通常描述英雄的冒险或具有民族文化重要性的重大事件。史诗中的主角往往具有超凡品质，面对超越常人的挑战，其行动关乎整个民族或人类的命运。这种文学形式最初通过口头传统流传，由专业吟游诗人在宴会或庆典上演唱，通常伴有乐器伴奏。史诗不仅是娱乐，也是传承文化价值观和集体记忆的重要方式，在文字普及前，口头传统是知识传递的主要渠道。《吉尔伽美什史诗》作为最早被记录的史诗，成为了连接口头传统和书面文学的桥梁。</p><h1 id="2-古希腊与罗马文学"><a class="markdownIt-Anchor" href="#2-古希腊与罗马文学"></a> 2. 古希腊与罗马文学</h1><h2 id="21-荷马史诗"><a class="markdownIt-Anchor" href="#21-荷马史诗"></a> 2.1. 荷马史诗</h2><h4 id="211-荷马其人"><a class="markdownIt-Anchor" href="#211-荷马其人"></a> 2.1.1. 荷马其人</h4><p>「荷马」是西方文学传统的奠基者，却也是最神秘的作家之一。传统上认为他是一位生活在公元前 8 世纪的盲诗人，但现代学者对其真实身份存在诸多争议。「荷马问题」涉及《伊利亚特》和《奥德赛》是否由同一人创作，甚至这个「荷马」是否真实存在。许多学者认为这两部史诗可能是几个世纪的口头传统结晶，最终由多位诗人编撰而成。</p><p>无论如何，这两部作品奠定了西方文学的基础。它们最初通过口头传统流传，由专业的吟游诗人在贵族宴会和公共节日上吟诵，伴有七弦琴（lyre）伴奏。直到公元前 6 世纪，雅典暴君庇西特拉图斯才下令将它们记录成文。</p><h4 id="212-伊利亚特"><a class="markdownIt-Anchor" href="#212-伊利亚特"></a> 2.1.2. 《伊利亚特》</h4><p>《伊利亚特》成书于约公元前 8 世纪的希腊黑暗时代末期或古风时期初期，书名源自「伊利昂」，即特洛伊城的另一名称。</p><p>全诗共 24 卷，以十六音节的六步格（hexameter）写成，描述了特洛伊战争第十年的几周内发生的事件。虽然战争持续了十年，但史诗聚焦于「阿喀琉斯的愤怒」及其后果，而非整个战争过程。开篇即点明主题：「女神啊，请歌唱佩琉斯之子阿喀琉斯的愤怒，这致命的愤怒给阿开亚人带来了无尽的痛苦……」</p><blockquote><p>故事背景是特洛伊王子帕里斯在女神阿佛洛狄忒的帮助下，诱拐了斯巴达国王墨涅拉俄斯的妻子海伦，引发了希腊联军（阿开亚人）对特洛伊的战争。史诗开始时，希腊联军统帅阿伽门农（墨涅拉俄斯的兄长）夺走了阿喀琉斯的女奴布里塞伊斯，激怒了阿喀琉斯，使他退出战斗。</p><p>没有阿喀琉斯，希腊军队节节败退。特洛伊英雄赫克托尔（普里阿摩斯国王的长子）率军攻破希腊人的防线，几乎烧毁了他们的船只。阿喀琉斯拒绝亲自出战，但允许他的挚友帕特洛克罗斯穿上自己的盔甲上阵。帕特洛克罗斯奋勇作战，但最终被赫克托尔杀死。</p><p>失去挚友的阿喀琉斯悲痛欲绝，重返战场，杀死赫克托尔并亵渎其尸体，拒绝归还。最终，特洛伊国王普里阿摩斯冒险潜入希腊营地，恳求归还儿子的遗体。阿喀琉斯被这位父亲的勇气所感动，同意归还赫克托尔的遗体，史诗以特洛伊人为赫克托尔举行隆重葬礼结束。</p></blockquote><p>《伊利亚特》对古希腊文化产生了无法估量的影响，成为希腊教育的基础和民族身份的核心元素。亚历山大大帝据说随身携带一本《伊利亚特》，视阿喀琉斯为自己的榜样。</p><p>《伊利亚特》中的战争是特洛伊人与阿开亚人（早期希腊人）之间的冲突。这场战争不仅是人类间的冲突，诸神也介入其中，支持不同的阵营：阿波罗、阿佛洛狄忒、阿瑞斯支持特洛伊；赫拉、雅典娜、波塞冬则支持希腊人。这种神人交织的叙事反映了古希腊人的宇宙观，其中人类命运受到神明的影响，但个人选择仍具有决定性意义。</p><p>诗中充满了对战斗场景的生动描写，其中阵亡士兵的死法往往详细到令人不适的程度：「矛尖刺穿他的颈部，从咽喉穿出，他仰面倒地，铠甲在身上哐当作响」，展现了生命的脆弱与战争的残酷。</p><p>史诗也通过展示敌对双方的人性来突破民族界限，最感人的场景之一发生在赫克托尔与妻子安德洛玛刻告别时。赫克托尔脱下头盔抱起幼子，祈祷他将来能超越自己，安德洛玛刻则「含着泪微笑」。这种对敌人的人性化描写，使《伊利亚特》超越了单纯的战争史诗，成为探索人性的永恒经典。</p><h4 id="213-奥德赛"><a class="markdownIt-Anchor" href="#213-奥德赛"></a> 2.1.3. 《奥德赛》</h4><p>《奥德赛》创作于《伊利亚特》之后，可能约在公元前 725 到 675 年间。全诗同样分为 24 卷，讲述了伊萨卡国王奥德修斯（拉丁名：尤利西斯）在特洛伊战争结束后历经十年才返回家乡的冒险旅程。</p><p>与《伊利亚特》不同，《奥德赛》的故事结构更为复杂，采用了非线性叙事：</p><blockquote><p>史诗开始时，奥德修斯已在女神卡吕普索的岛上被囚禁七年。他的妻子珀涅罗佩在伊萨卡被 108 位求婚者围困，他们消耗着奥德修斯的财富，争夺他的王位。众神决定让奥德修斯回家，只有海神波塞冬因奥德修斯曾伤害其子独眼巨人波吕斐摩斯而继续反对。</p><p>女神雅典娜鼓励奥德修斯的儿子特勒马科斯（已二十岁）外出探寻父亲的下落。与此同时，赫耳墨斯奉宙斯之命前往卡吕普索岛，命她释放奥德修斯。后者乘木筏航行，但遭波塞冬掀起的风暴，漂流至费阿基亚。在那里，他向国王阿尔喀诺俄斯讲述了自己的旅程：从特洛伊出发后，他与船员遇到了食莲人、独眼巨人、女巫喀耳刻，他们甚至前往冥界拜访先知泰瑞西阿斯，又遭遇了塞壬女妖、海怪斯库拉和卡律布狄斯，最终全员遇难，只有奥德修斯漂流到卡吕普索岛。</p><p>阿尔喀诺俄斯国王被他的故事打动，提供船只送他回伊萨卡。到家后，雅典娜将他变装成老乞丐。他先拜访了忠诚的猪倌尤迈俄斯，与回国的特勒马科斯重逢，然后进入自己的宫殿。在那里，没人认出他，求婚者们还侮辱了他。</p><p>珀涅罗佩宣布将举行比赛，谁能用奥德修斯的弓射中目标，她就嫁给谁。求婚者们都无法拉开这把弓，但变装的奥德修斯轻松完成，随后与特勒马科斯和两位忠仆一起杀死了所有求婚者。最后，他向珀涅罗佩证明了自己的身份，两人重聚。</p></blockquote><p>《奥德赛》与《伊利亚特》共同构成了希腊史诗传统的双峰，但两者在主题和风格上有明显区别。如果说《伊利亚特》聚焦战争中的荣耀与悲剧，《奥德赛》则探索返乡、家庭与身份认同的主题。《伊利亚特》中的阿喀琉斯追求不朽的荣耀，宁死不屈；《奥德赛》中的奥德修斯则凭借智慧和坚韧，努力生存并回归家庭。这种转变反映了希腊人价值观的演变，从崇尚战争荣耀到重视智慧与家庭纽带。</p><p>《奥德赛》中的奥德修斯展现了希腊人推崇的多才多艺（polymētis）特质：他不仅是战士，更是航海家、说故事的能手、工匠和战略家。当卡吕普索提供永生的诱惑时，他仍选择回到凡间的家庭，这反映了希腊人对人的尊严和选择的重视。</p><p>这两部史诗展现了众多半神半人英雄的形象。阿喀琉斯是海洋女神忒提斯与凡人佩琉斯的儿子，海伦则是宙斯与勒达所生。这种半神血统反映了古希腊宗教中神与人之间没有绝对界限的观念，也为英雄的超凡能力提供了解释。</p><h2 id="22-变形记"><a class="markdownIt-Anchor" href="#22-变形记"></a> 2.2. 《变形记》</h2><p>《变形记》完成于约公元 8 年，作者是罗马诗人奥维德（Publius Ovidius Naso，约公元前 43 年 到公元 17 或 18 年）。这部作品是古典文学晚期的巅峰之作，也是奥维德最著名的代表作。</p><p>奥维德生活在罗马从共和国转变为帝国的关键时期，是奥古斯都统治下的「黄金时代」诗人。然而，他的《变形记》完成不久后便因不明原因被奥古斯都流放到黑海边缘的小镇托米斯（今罗马尼亚康斯坦察），度过了生命的最后十年。</p><p>《变形记》是一部包含约 250 个变形故事的长诗，共 15 卷，约 12,000 行，以六步格写成。不同于传统史诗聚焦单一英雄或事件，《变形记》以「变形」为线索，编织了一个从世界创生到凯撒转变为星辰的连续性叙事。</p><blockquote><p>作品以宇宙从混沌中形成开始：「在大地、海洋和覆盖万物的天空出现之前，自然在整个宇宙中只有一副面孔，人们称之为混沌……」然后描述了四个时代（黄金、白银、青铜和黑铁）的演变，以及普罗米修斯创造人类。<br>接下来的故事涵盖了众多著名神话：阿波罗追求达芙妮，她变成月桂树；伊卡洛斯飞向太阳，坠入大海；纳西索斯爱上自己的倒影，变成水仙花；俄耳浦斯下冥界寻妻，却因回头一望失去她；皮格马利翁爱上自己雕刻的象牙少女加拉忒亚，维纳斯使其复活；阿拉克涅与雅典娜比赛织布，被变成蜘蛛……</p><p>后半部分转向特洛伊战争和罗马的起源：阿喀琉斯之死、奥德修斯的冒险、特洛伊的陷落，以及埃涅阿斯逃离特洛伊并最终到达意大利，成为罗马人的祖先。最后，作品以凯撒之死和奥古斯都赞美结束，暗示历史循环与罗马的永恒。</p></blockquote><p>「变形」（Metamorphosis）一词源自希腊语，意为彻底的形态、结构或性质转变。在奥维德的作品中，变形往往是情感极端表达的结果：因爱而变形（达芙妮），因傲慢而变形（阿拉克涅），因悲伤而变形（俄耳浦斯之妻）。这些变形既是惩罚也是解脱，既是神圣干预也是情感的自然延伸。</p><p>奥维德对这些神话采取了一种精致、甚至有些嬉戏的态度，这反映了罗马帝国早期的文化氛围 —— 古老的神话已不再是严肃的宗教内容，而更多地成为艺术创作的素材。他以生动的细节和心理描写赋予这些故事以新的活力：「达芙妮的脸上苍白褪去，取而代之的是树皮；她的头发变成树叶；她的手臂长成枝桠；她那曾跑得如此迅捷的双脚变成固定的树根……」</p><p>《变形记》对后世艺术与文学的影响难以估量。它成为中世纪和文艺复兴时期对古典神话的主要来源，启发了但丁、乔叟、莎士比亚等作家，也为无数画家、雕塑家提供了创作题材。以拉斐尔、提香、伦勃朗、鲁本斯为首的艺术大师都创作过基于《变形记》故事的作品。</p><p>对于奥维德本人而言，《变形记》也具有某种预言性意义。在结尾他写道：「我已完成了一部不朽的作品，它将超越朱庇特的愤怒和火焰、利剑和时间的腐蚀…… 无论命运对我的身体有何安排，我最好的部分将永存，我的名字将永不消亡。」这位被流放的诗人确实通过自己的作品获得了永生，《变形记》成为将希腊 - 罗马神话传递给后世的最重要桥梁之一。</p><h1 id="3-印度文学与宗教"><a class="markdownIt-Anchor" href="#3-印度文学与宗教"></a> 3. 印度文学与宗教</h1><h2 id="31-印度教背景"><a class="markdownIt-Anchor" href="#31-印度教背景"></a> 3.1. 印度教背景</h2><p>在深入探索印度两大史诗之前，了解它们的宗教背景至关重要。印度教是世界上最古老的宗教之一，其历史可追溯至公元前 1500 年左右的吠陀时期。与西方的一神教不同，印度教是一个复杂多元的宗教体系，包含多种哲学观点、崇拜方式和神祇。</p><p>印度教的核心经典是《吠陀》（Vedas），共四部：《梨俱吠陀》（赞歌）、《夜柔吠陀》（祭祀歌）、《娑摩吠陀》（旋律）和《阿闼婆吠陀》（咒语）。这些经典最初通过口头传统传承，由婆罗门祭司阶层世代记忆，约在公元前 500 年才开始记录成文。</p><p>印度教的神系庞大而复杂。主要神祇包括：</p><ul><li>梵天（Brahma）：创造神，宇宙的创造者</li><li>毗湿奴（Vishnu）：维护神，宇宙的保护者，通过化身（阿凡达）多次降临人间</li><li>湿婆（Shiva）：破坏神，负责宇宙的更新与转变</li><li>女神（Devi）：以多种形式出现，如雪山神女（Parvati）、杜尔迦（Durga）和迦梨（Kali）</li></ul><p>印度文化中最重要的概念之一是「达摩」（Dharma），这个词难以用单一西方术语翻译。达摩同时指宇宙法则、社会秩序、个人道德义务和正确行为的规范。在不同语境下，它可以理解为「职责」、「美德」、「道德」、「宗教」或「正义」。每个人的达摩取决于其社会地位（瓦尔那）、人生阶段（阿什拉玛）和个人情况，因此构成了一种情境伦理学。</p><p>印度史诗不仅是文学作品，也是达摩的实践指南，通过生动的故事说明抽象的宗教概念，向各阶层民众传授价值观。两大史诗《罗摩衍那》和《摩诃婆罗多》早已超越了纯文学范畴，成为宗教典籍，至今仍在寺庙仪式、家庭祭祀和日常生活中发挥重要作用。</p><h2 id="32-罗摩衍那"><a class="markdownIt-Anchor" href="#32-罗摩衍那"></a> 3.2. 《罗摩衍那》</h2><p>《罗摩衍那》（Ramayana）意为「罗摩的旅程」，约成书于公元前 5 到 4 世纪，传统上认为是由圣人瓦尔米基（Valmiki）创作。原文以梵语写成，包含约 24,000 首诗偈（shloka），分为七卷（kanda）。这部作品被视为阿迪卡维亚（Adikavya），即「第一诗」，标志着梵语诗歌的正式诞生。</p><p>《罗摩衍那》的故事广为流传，在东南亚各国有不同版本，并通过各种艺术形式表现，如皮影戏、舞蹈、绘画和现代影视作品。</p><blockquote><p>故事发生在古代印度阿约提亚王国，国王达沙拉塔有三位王后，却一直没有子嗣。他举行祭祀后，四个儿子相继出生：长子罗摩（Rama）出生于王后考萨利亚，次子婆罗多（Bharata）出生于王后凯凯伊，双胞胎弟弟拉克什曼那（Lakshmana）和沙特鲁格纳（Shatrughna）出生于王后苏米特拉。</p><p>罗摩成年后，在一次比武大会上拉开了湿婆神的神弓，赢得了邻国国王之女悉多（Sita）的芳心。他们成婚后，老国王准备立罗摩为王储，却被凯凯伊阻止。凯凯伊要求国王实现他曾许下的两个愿望：立婆罗多为王储，并流放罗摩到森林十四年。国王不得不遵守诺言，罗摩欣然接受命运，前往森林。悉多和拉克什曼那坚持跟随他。</p><p>在森林生活期间，魔王罗波那（Ravana）对悉多产生了贪念。他派手下将罗摩引开，变身成苦行僧接近悉多，然后绑架她带回自己的王国楞伽岛（今斯里兰卡）。罗摩在猴神哈努曼（Hanuman）的帮助下得知悉多的下落，与猴族结盟，建造连接印度和楞伽岛的大桥，率军攻打楞伽。</p><p>经过激烈战斗，罗摩杀死罗波那，解救了悉多。然而，由于悉多在罗波那处滞留多时，民众对她的贞洁产生怀疑。为证明自己的清白，悉多经受了火的考验，安然无恙地从火中走出，证明了自己的纯洁。</p><p>流放期满，罗摩返回阿约提亚，婆罗多欣然交还王位。罗摩登基后，依然有人怀疑悉多的贞洁。为了平息谣言，罗摩不得不将已怀孕的悉多再次流放。她在圣人瓦尔米基的庇护下生下双胞胎儿子拉瓦（Lava）和库沙（Kusha）。多年后，罗摩认出了自己的儿子，请悉多回宫，但悉多选择回归大地母亲的怀抱。最终，罗摩完成在世使命，回归毗湿奴的本体。</p></blockquote><p>罗摩作为毗湿奴的第七个化身（avatar），代表了理想君主、完美丈夫和尽职兄长的典范。他的特质被概括为「玛莉亚达・普鲁肖塔马」（Maryada Purushottama），意为「最尊崇道德的人」。在印度文化中，「罗摩拉吉亚」（Ram-Rajya）成为理想王国的代名词，象征公正、繁荣与和谐的统治。</p><p>悉多则体现了印度传统中理想女性的特质：忠贞、坚韧、牺牲和对达摩的坚守。她被视为大地女神拉克什米的化身，与罗摩的结合象征着神圣婚姻。然而，现代印度女性主义者对悉多被迫证明贞洁的情节提出了批评，认为这反映了父权制对女性的不公正要求。</p><p>《罗摩衍那》对达摩概念的探索尤为深刻。罗摩面临着多重达摩的冲突：作为儿子（尊重父亲的诺言）、作为国王（保护子民）、作为丈夫（保护妻子）。当这些职责相互冲突时，如何抉择成为道德困境。罗摩最终选择了遵守父亲的诺言和履行王者职责，即使这意味着个人幸福的牺牲。这种抉择反映了印度传统价值观中，社会达摩（社会秩序）高于个人达摩（个人情感）的原则。</p><p>《罗摩衍那》在印度文化中的影响难以估量。每年的排灯节（Diwali）庆祝罗摩战胜罗波那、回归阿约提亚的胜利，象征光明战胜黑暗。在整个东南亚，罗摩的故事成为了道德教育和文化认同的核心元素。</p><h2 id="33-摩诃婆罗多"><a class="markdownIt-Anchor" href="#33-摩诃婆罗多"></a> 3.3. 《摩诃婆罗多》</h2><p>《摩诃婆罗多》（Mahabharata）意为「伟大的婆罗多（族）史诗」，是世界上最长的史诗，约成书于公元前 4 世纪到公元 4 世纪之间。传统上认为是由圣人毗耶娑（Vyasa）编撰，他也是史诗中的角色。全诗约 100,000 颂（约 1.8 百万字），分为 18 卷和一个附录（哈里旺沙）。</p><p>《摩诃婆罗多》的规模和复杂性远超《罗摩衍那》，它不仅讲述了中心故事，还包含了无数支线、伦理讨论、哲学论述和独立故事。正如史诗中所言：「在此未曾提及的事物，世上别处不会有；而此处所言，处处可闻。」</p><blockquote><p>核心故事围绕库卢族两支 —— 般度（Pandava）家族和俱卢（Kaurava）家族 —— 之间的继承权争夺和最终战争展开。</p><p>盲王持国（Dhritarashtra）与其弟弟般度（Pandu）共同统治哈斯提那布尔王国。般度早逝，留下五个儿子：长子阿周那（Arjuna）是雷神因陀罗之子，箭术无双；次子悉底米（Bhima）力大无穷；长兄阿修（Yudhishthira）贤明公正；双胞胎弟弟那库罗（Nakula）和萨哈提瓦（Sahadeva）分别擅长医术和占星术。持国则有一百个儿子，为首的是难敌（Duryodhana）。</p><p>般度五兄弟与表兄弟们一起长大，接受德罗纳（Drona）大师的武艺训练。阿周那成为最杰出的弟子，引起难敌的嫉妒。长大后，般度五兄弟共同娶了一位妻子德鲁帕蒂（Draupadi），一起统治因陀罗普拉斯塔王国。</p><p>难敌设计邀请阿修进行赌博，骗取了般度家族的全部财产和自由。五兄弟被迫流放十三年，其中最后一年需隐姓埋名。期满后，他们要求归还王国，但难敌拒绝。</p><p>在黑天（Krishna，毗湿奴的化身）的支持下，般度五兄弟向俱卢家族宣战。战前，黑天成为阿周那的战车御者。当阿周那看到对面阵营中有许多亲友和尊者，不忍作战时，黑天向他讲述了关于达摩、业力和解脱的哲理，这段对话即著名的《薄伽梵歌》（Bhagavad Gita）。</p><p>库卢之战持续十八天，双方都使用了神赐武器和非凡战术。般度兄弟最终获胜，但双方均损失惨重，几乎所有主要战士都阵亡。阿修登上王位，统治了三十六年后，五兄弟和德鲁帕蒂决定放弃王位，前往喜马拉雅山寻求解脱。在艰难的旅程中，除阿修外，其他人都因自身缺点而倒下。阿修最终以肉身进入天界。</p></blockquote><p>《摩诃婆罗多》最著名的部分是《薄伽梵歌》，这段约 700 首诗的对话被视为印度教最重要的经典之一。当阿周那在战场上犹豫不决时，黑天揭示了自己作为至高神的身份，讲述了关于行动（karma yoga）、知识（jnana yoga）和虔诚（bhakti yoga）三条解脱之路的教义，强调不执着于行动结果的无私行动（nishkama karma）。</p><p>《摩诃婆罗多》对达摩的探讨比《罗摩衍那》更加复杂和微妙。史诗中充满了达摩困境，没有简单的对错答案。例如：</p><blockquote><p>德罗纳作为老师，是否应该在战场上对抗自己的学生？</p><p>黑天使用欺骗战术击败俱卢将领，这是否违背战士达摩？</p><p>阿修明知赌局有诈，却因王者达摩不得不参与，这种选择是否正确？</p></blockquote><p>这些复杂的伦理问题展示了印度思想对道德相对性的深刻理解，暗示在复杂情境中，达摩的应用需要智慧而非教条。《摩诃婆罗多》的一个核心信息是：有时候任何选择都会导致某种达摩的违背，关键是在冲突中做出最小损害的决定。</p><p>阿周那作为《摩诃婆罗多》中最著名的半神英雄，代表了印度传统中理想战士的形象。他兼具超凡的武艺和深刻的精神觉悟，即使在战场上，也不忘思考行动的伦理意义。作为因陀罗之子，他拥有半神的血统，但仍然面临人类的情感和道德困境，这种二元性使他成为深受读者喜爱的复杂角色。</p><p>《摩诃婆罗多》对印度文化和宗教的影响无处不在。它不仅提供了伦理行为的范例，也为后世印度哲学和文学提供了思想资源。印度的政治理念、法律概念和社会规范都能在这部史诗中找到根源。在现代印度，《摩诃婆罗多》的改编版本不断出现在电影、电视剧和漫画中，证明这部古老史诗的生命力和现代意义。</p><h1 id="4-中世纪文学"><a class="markdownIt-Anchor" href="#4-中世纪文学"></a> 4. 中世纪文学</h1><h2 id="41-但丁的神曲"><a class="markdownIt-Anchor" href="#41-但丁的神曲"></a> 4.1. 但丁的《神曲》</h2><h4 id="411-时代背景与作者生平"><a class="markdownIt-Anchor" href="#411-时代背景与作者生平"></a> 4.1.1. 时代背景与作者生平</h4><p>《神曲》（Divina Commedia）创作于 1308 至 1320 年，正值欧洲中世纪晚期。这一时期，中世纪神学世界观达到顶峰，同时文艺复兴的曙光已初现意大利。佛罗伦萨作为新兴的城邦共和国，商业繁荣，艺术发达，但也陷入激烈的政治派系斗争中。</p><p>作者但丁・阿利吉耶里（Dante Alighieri, 1265-1321）出生于佛罗伦萨一个中等贵族家庭。他 9 岁时邂逅贝雅特丽齐・波尔蒂纳里（Beatrice Portinari），对她产生了柏拉图式的爱慕，这成为他诗歌创作的永恒灵感。贝雅特丽齐 24 岁时去世，但她的形象在但丁心中升华为神圣爱情的象征。</p><p>但丁积极参与佛罗伦萨政治，担任过城邦议员和使节。当时意大利陷入教皇派（Guelph）和皇帝派（Ghibelline）的争斗，佛罗伦萨内部教皇派又分为白派（主张城邦自治）和黑派（支持教皇干预）。1302 年，当但丁出使罗马期间，黑派夺权，他被流放并被判处缺席死刑。此后，他流亡北意大利各地，再未能返回故乡。</p><p>正是在流亡期间，但丁完成了《神曲》的创作。这部作品不仅反映了他个人的痛苦经历，也是对当时意大利和整个基督教世界精神状况的反思。他于 1321 年 9 月在拉文纳去世，至今长眠于此，而非他深爱的佛罗伦萨。</p><h4 id="412-作品结构与内容"><a class="markdownIt-Anchor" href="#412-作品结构与内容"></a> 4.1.2. 作品结构与内容</h4><p>《神曲》原名《喜剧》（Commedia），「神曲」（Divina）的称号是后人加上的。全诗采用意大利方言而非当时学术界通用的拉丁语写成，这一大胆创举奠定了意大利文学语言的基础。</p><p>诗歌结构严谨，分为三个部分：《地狱篇》（Inferno）、《炼狱篇》（Purgatorio）和《天堂篇》（Paradiso），每部各 33 篇（canto），加上《地狱篇》的序篇，共 100 篇。这种数字象征主义贯穿全诗：3 代表三位一体，9（3×3）代表神圣完美，10 代表宇宙秩序。诗歌采用三行韵（terza rima）形式，即 ABA BCB CDC…… 的押韵模式，创造出前进不息的韵律感。</p><blockquote><p>故事始于 1300 年的圣周五前夜（耶稣受难日之前），35 岁的但丁迷失在「黑暗的森林」中，象征人生中途的精神迷茫。他试图攀登光明之山，却被三只野兽（豹、狮、母狼，象征情欲、骄傲和贪婪）阻挡。此时，古罗马诗人维吉尔（Virgil）出现，告诉但丁必须通过地狱和炼狱才能到达天堂，并提出担任他的向导。</p><p>在《地狱篇》中，但丁和维吉尔穿过地狱的九个同心圆层，每层惩罚一种罪行，越往下罪行越重：第一层是未受洗礼的美德之人；第二至第五层是放纵、贪食、贪婪和愤怒；第六层是异端；第七层是暴力；第八层是欺诈；最深的第九层是背叛，其中最恶劣的叛徒犹大、布鲁图斯和卡修斯被路西法（Satan）亲自啃噬。地狱入口铭刻着著名警句：「进入此门，离弃所有希望。」</p><p>《炼狱篇》描述两人穿过地球中心，来到南半球的炼狱山。炼狱分为七个层级，对应七宗罪（傲慢、嫉妒、愤怒、懒惰、贪婪、贪食、淫欲），灵魂在此净化罪恶，为进入天堂做准备。在炼狱的顶端是伊甸园，但丁在此与贝雅特丽齐重逢，维吉尔则离去（作为异教徒，他不能进入天堂）。</p><p>在《天堂篇》中，贝雅特丽齐引导但丁穿越九层天：月亮、水星、金星、太阳、火星、木星、土星、恒星天和原动天，最后到达超越时空的天国玫瑰（Empyrean），在那里他得见上帝的荣光，体验到终极的神圣之爱。</p></blockquote><p>整部作品构成了一次精神朝圣，从罪恶和迷失，经过忏悔和净化，最终达到救赎和启示。这反映了基督教神学中灵魂得救的历程，也象征人类普遍的精神成长路径。</p><h4 id="413-思想内涵与影响"><a class="markdownIt-Anchor" href="#413-思想内涵与影响"></a> 4.1.3. 思想内涵与影响</h4><p>《神曲》最显著的特点是将基督教神学与古典人文主义融为一体。维吉尔代表人类理性和古典智慧，贝雅特丽齐则象征神圣启示和信仰。但丁虽然是虔诚的基督徒，却给予古典文化（尤其是维吉尔）崇高地位，甚至将许多古代哲人安置在地狱的较轻微区域，这预示了文艺复兴对古典文化的重新尊崇。</p><p>作品充满了丰富的象征主义。地狱的漏斗形状象征远离上帝的堕落；炼狱的螺旋山路表示艰难但充满希望的攀登；天堂的同心圆体现了完美的神圣秩序。三位主要向导（维吉尔、贝雅特丽齐和圣贝尔纳多）分别代表理性、信仰和神秘体验，构成了中世纪认识论的三个层次。</p><p>《神曲》展现了中世纪宇宙观的完整图景。根据托勒密体系，但丁的宇宙以地球为中心，地狱位于地下，天堂环绕地球，形成一个层级分明的有机整体。这种秩序化的宇宙观反映了中世纪思想中，物质世界与精神世界、自然秩序与道德秩序的对应关系。</p><p>作品中充满了对当时政治、宗教和社会问题的评判。但丁大胆地将许多教皇、政治人物和同时代人安置在地狱中，表达了他对教会腐败和意大利政治混乱的强烈批判。他理想中的世界秩序是教皇领导精神事务，皇帝管理世俗事务，两者相互独立又相互配合。</p><p>在文学技巧上，《神曲》创造了前所未有的叙事深度。但丁不仅是故事的主角，也是叙述者和评论者，时而参与情节，时而抽身反思，创造出多层次的叙事视角。他对人物心理的细腻描写和对复杂情感的捕捉，超越了同时代的大多数作品。</p><p>《神曲》对后世的影响难以估量。在文学上，它启发了从薄伽丘到乔叟，从弥尔顿到艾略特的众多作家；在美术上，波提切利、米开朗基罗和多雷等艺术家为它创作了著名插图；在音乐上，李斯特、柴可夫斯基和普契尼等作曲家受其启发创作了重要作品。更广泛地说，《神曲》塑造了西方文化对来世、罪恶与美德的想象，成为连接中世纪与现代的关键桥梁。</p><h4 id="414-与但丁相遇的重要人物和故事"><a class="markdownIt-Anchor" href="#414-与但丁相遇的重要人物和故事"></a> 4.1.4. 与但丁相遇的重要人物和故事</h4><p>但丁在冥界旅途中遇到众多历史和当代人物，每个故事都深具象征意义。在地狱第二环，他遇到了保罗和弗兰切斯卡，两人因通奸而被杀，永远被风暴卷在一起，象征情欲之罪；在第三环，他认出了贪食者恰科，后者预言佛罗伦萨的政治斗争；在第八环，他与曾任教皇的尼古拉三世交谈，后者因贪污被倒插在岩洞中。</p><p>特别值得一提的是尤利西斯（奥德修斯）的故事。但丁在第八环遇到这位希腊英雄，他因欺骗之罪被惩罚。尤利西斯讲述了自己如何不满足于平静的家庭生活，渴望探索未知世界，最终率领船员越过海克里斯柱（直布罗陀海峡），航向禁区，导致全船覆没。这个故事被许多学者解读为对人类求知欲的双重态度：既钦佩其勇气，又警惕其傲慢。</p><p>在《炼狱篇》中，但丁遇到许多艺术家和诗人，包括音乐家卡塞拉和诗人索尔德洛。在第五层，他看到教皇阿德里安五世因贪婪而俯卧在地；在第七层，他与古罗马诗人斯塔提乌斯交谈，后者刚完成净化，准备上升天堂。</p><p>《天堂篇》中，他在太阳天遇到神学家托马斯・阿奎那和圣方济各；在火星天，他遇到了十字军战士和佛罗伦萨的先祖卡恰圭达；在土星天，他与本笃会修士彼得・达米安交谈，后者谴责教会腐败。</p><p>《神曲》通过这些活灵活现的角色和引人入胜的故事，将抽象的神学概念具象化，展现了人类命运的多样性和生命抉择的重要性。但丁的天才在于，他创造的不是教条式说教，而是充满人性光辉的复杂世界，即使在最严厉的道德判断中，也流露出对人类弱点的深刻理解和同情。</p><p>自战后至今，《神曲》仍是西方文学最具影响力的作品之一，被翻译成世界上几乎所有主要语言。2021 年是但丁逝世 700 周年，世界各地举行了纪念活动，证明这位「神圣诗人」的作品超越了时空限制，继续对人类精神世界产生深远影响。</p><h1 id="5-宗教经典文学"><a class="markdownIt-Anchor" href="#5-宗教经典文学"></a> 5. 宗教经典文学</h1><h2 id="51-圣经"><a class="markdownIt-Anchor" href="#51-圣经"></a> 5.1. 《圣经》</h2><p>《圣经》（Bible）一词源自希腊语「biblia」，意为「书籍」，是犹太教和基督教的核心经典。它不是单一作品，而是由多位作者在长达千年的时间里（约公元前 1200 年至公元 2 世纪）创作的文集。《圣经》原文主要使用希伯来语、亚兰语和希腊语写成，如今已被翻译成 3000 多种语言，是世界上发行量最大、影响最广的文本。</p><p>《圣经》分为《旧约》（Old Testament）和《新约》（New Testament）两大部分。《旧约》被犹太教和基督教共同承认，《新约》则仅为基督教经典。</p><h4 id="511-旧约概述"><a class="markdownIt-Anchor" href="#511-旧约概述"></a> 5.1.1. 旧约概述</h4><p>《旧约》（犹太教称为《塔纳赫》）包含 39 卷书，可分为四部分：</p><ol><li>摩西五经（Torah / Pentateuch）：《创世记》《出埃及记》《利未记》《民数记》《申命记》，记录世界创造、族长故事、以色列人出埃及和摩西律法。</li><li>历史书：从《约书亚记》到《以斯帖记》，描述以色列人占领迦南地、建立王国、分裂、被掳与归回的历史。</li><li>智慧文学：《约伯记》《诗篇》《箴言》《传道书》《雅歌》，探讨生命意义、苦难、爱情等普遍人类问题。</li><li>先知书：从《以赛亚书》到《玛拉基书》，记录先知对以色列民族和周边国家的预言和劝诫。</li></ol><p>《旧约》通过神权史观展示了上帝（雅威）与以色列民族的立约关系。在这一框架中，历史事件被解释为上帝对以色列人忠诚或背叛的回应。《旧约》同时探讨了普世伦理问题，如公正、怜悯和人类在宇宙中的位置。</p><h4 id="512-约伯记"><a class="markdownIt-Anchor" href="#512-约伯记"></a> 5.1.2. 《约伯记》</h4><p>《约伯记》可能完成于公元前 6 到 4 世纪，是《旧约》中最引人深思的智慧文学作品之一。它以散文序幕和结尾，辅以长篇诗歌对话，探讨了「为何义人受苦」这一永恒难题。</p><blockquote><p>故事开始于上帝与撒旦关于义人约伯的对话。撒旦质疑约伯的虔诚只是因为他蒙福，上帝允许撒旦考验约伯，但不可取他性命。接着，约伯失去所有财产、子女，并染上恶疾，但他仍然持守信仰：「赏赐的是耶和华，收取的也是耶和华。」</p><p>约伯的三个朋友以利法、比勒达和琐法前来安慰，但逐渐转向指责，认为约伯一定犯了隐秘罪行才受此惩罚。他们代表了传统神学观点：义人受福，恶人遭殃。约伯则坚持自己的无辜，质疑上帝的公正：「我今日发出悲叹，我的创伤沉重，不得休息。」他要求与上帝直接对质。</p><p>年轻的以利户插入讨论，提出苦难可能是上帝的管教和教育。最终，上帝从旋风中显现，但并未直接回答约伯的问题，而是通过展示创造的奇妙与复杂，质问约伯是否有资格审判上帝的行为：「我立大地根基的时候，你在哪里呢？」</p><p>约伯认识到人类理解的局限，承认自己「说了自己不明白的事」。上帝恢复约伯的财富，赐给他新的儿女，约伯得享长寿。</p></blockquote><p>《约伯记》的核心问题是「神义论」（theodicy）：如果上帝全能且全善，为何允许恶和苦难存在？尤其是，为何义人也会受苦？文本并未提供简单答案，而是呈现了几种可能的解释：</p><ol><li>苦难是对信仰的考验</li><li>苦难是上帝的管教</li><li>上帝的计划超出人类理解范围</li><li>与上帝的相遇本身，而非理性解释，才是苦难的终极回应</li></ol><p>这种对简单解释的拒绝，以及对宗教经验复杂性的坦诚，使《约伯记》成为世界文学中最深刻的作品之一。其中第四个解释 ——「与上帝的相遇本身，而非理性解释，才是苦难的终极回应」—— 尤其具有存在主义式的突破性：这一解释突破了传统神义论的框架，指向一种存在主义式的宗教体验。当上帝从旋风中显现时（《约伯记》38-41 章），祂并未像法庭上的被告般回答约伯的质询，反而以一连串 137 个反问构建出恢弘的宇宙图景：</p><blockquote><p>「你能系住昴星的结吗？能解开参星的带吗？」</p><p>「山岩间的野山羊几时生产，你知道吗？」</p><p>「马的大力是你所赐的吗？它颈项上挓挲的鬃是你披上的吗？」</p></blockquote><p>这种充满十星张力的「非答案」，实则蕴含着深刻的解构：</p><ol><li><p>超越交易式信仰的灵性觉醒</p><p>传统宗教常将苦难视为「罪与罚」的因果链条（如约伯三友的立场），但上帝亲自否定了这种简化的功利主义逻辑。约伯的终极安慰不在于恢复双倍财产（42:10），而在于从「听见传说」（42:5）到「亲眼见你」（42:5）的认知跃迁 —— 这暗示真正的信仰不是利益交换，而是在与绝对他者的相遇中重塑存在维度。</p></li><li><p>认知暴力的消解与谦卑的重构</p><p>上帝的反问本质上是认知论革命：当人类试图用理性框定神圣意志时，实则是将无限者降格为可量化的对象。风暴中的上帝显现（theophany）以压倒性的美学体验，瓦解了约伯先前法庭辩论式的逻辑框架 —— 正如犹太哲学家马丁・布伯在《我与你》中指出，神圣相遇发生在「我 - 你」关系而非「我 - 它」的分析中。</p></li><li><p>苦难作为启示的催化剂</p><p>值得注意的是，约伯在顺境中从未要求见上帝。正是极端的苦难打破了他对「正义世界假设」（just-world hypothesis）的执念，迫使其进入更深层的灵性追问。这呼应了克尔凯郭尔所言：「只有当个人被推向极端处境时，才能与永恒建立真实关系。」苦难在此成为解构表象、触及本真的契机。</p></li><li><p>现代性的先知预表</p><p>卡夫卡在《审判》中让 K 至死未见「法」的真容，而约伯却获得了戏剧性的反转 —— 但这恰恰形成双重讽喻：卡夫卡展现现代人神性缺位的荒诞，而《约伯记》早在两千年前就预言，即便上帝显现，人类依然无法获得明晰答案。两者共同指向存在主义的核心命题：<strong>在无意义中创造意义，在沉默中聆听启示</strong>。</p></li></ol><p>这种「答案即非答案」的悖论，在犹太教卡巴拉神秘主义中发展为「神圣收缩」（Tzimtzum）理论 —— <strong> 上帝必须隐藏自身才能创造空间让世界存在</strong>。正如 13 世纪诗人鲁米所言：「伤口是光进入你内心的地方。」《约伯记》最终揭示的，或许正是苦难作为灵性裂痕，让神圣之光得以照入人性的深渊。</p><h4 id="513-新约"><a class="markdownIt-Anchor" href="#513-新约"></a> 5.1.3. 新约</h4><p>《新约》由 27 卷书组成，包括四福音书、《使徒行传》、保罗书信、其他书信和《启示录》。它记录了耶稣基督的生平、教导、死亡与复活，以及早期基督教的发展。</p><h4 id="514-四福音书概述"><a class="markdownIt-Anchor" href="#514-四福音书概述"></a> 5.1.4. 四福音书概述</h4><p>「福音」（Gospel）一词源自希腊语「euangelion」，意为「好消息」，指耶稣基督带来的救恩。四福音书分别是《马太福音》《马可福音》《路加福音》和《约翰福音》，均成书于公元 1 世纪后半叶，用希腊语（Koine Greek，通用希腊语）写成。</p><p>前三部福音书（马太、马可、路加）因内容相近而被称为「对观福音」（Synoptic Gospels）。学者普遍认为《马可福音》最早成书，《马太》和《路加》在此基础上扩展，并加入被称为「Q 资料」的共同口传材料。《约翰福音》则独立于对观福音传统，提供了不同的神学视角。</p><p>传统上认为四福音书的作者分别是：</p><ul><li>马太：耶稣的十二门徒之一，原为税吏</li><li>马可：彼得的同工和翻译</li><li>路加：保罗的同伴，医生和历史学家</li><li>约翰：耶稣所爱的门徒，也是《启示录》和约翰书信的作者</li></ul><p>然而现代学术研究认为，四福音书可能是早期基督徒社群集体创作的成果，而非个人作品。无论如何，它们代表了早期基督教对耶稣事迹和教导的不同理解和强调。</p><p>每部福音书都有其独特视角和神学强调：</p><ul><li>《马太福音》：<ul><li>主要受众为犹太基督徒</li><li>核心主题：耶稣是应验旧约预言的弥赛亚（基督）</li><li>频繁引用旧约预言；强调耶稣是新摩西；颁布新律法（如山上宝训）；包含五大讲论</li><li>独特材料：东方博士来朝；逃往埃及；八福；比喻中的绵羊和山羊</li><li>耶稣的形象为大卫的子孙、合法的犹太王</li></ul></li><li>《马可福音》：<ul><li>主要受众为罗马基督徒</li><li>核心主题：耶稣是受苦的仆人、带来上帝的国度</li><li>是最短且最早的福音书；强调十字架和受苦</li><li>独特材料：较少独特材料；强调「弥赛亚的秘密」</li><li>耶稣的形象为受苦的人子、战胜邪灵的驱魔者</li></ul></li><li>《路加福音》：<ul><li>主要受众为希腊人和外邦人</li><li>核心主题：耶稣带来普世救恩，特别关注弱势群体</li><li>历史细节丰富；与《使徒行传》成对；强调祷告和圣灵</li><li>独特材料：天使报喜；牧羊人来访；浪子回头；好撒玛利亚人</li><li>耶稣的形象为完美人性的救主、关爱穷人和被社会边缘化者</li></ul></li><li>《约翰福音》：<ul><li>主要受众为广泛的希腊、罗马世界</li><li>核心主题：耶稣是成肉身的道（logos），是上帝的儿子</li><li>高度象征性和神学性；使用「我是」宣言；强调耶稣的神性</li><li>独特材料：迦拿婚宴；尼哥底母夜访；与撒玛利亚妇人对话；拉撒路复活</li><li>耶稣形象：永恒的道成肉身，与父合一的神圣启示者</li></ul></li></ul><p>四部福音书虽各有侧重，但共享基础叙事框架：</p><ul><li>救赎序幕：施洗约翰的预备（玛 3:1/可 1:2/路 3:4/约 1:23）</li><li>加利利事工：呼召门徒、治病驱魔、登山宝训等（太 4-18/可 1-9/路 4-9/约 1-6）</li><li>耶路撒冷之旅：面向十字架的转折（太 19-20/可 10/路 9:51-19:27/约 7-12）</li><li>受难周：荣入圣殿、最后晚餐、被捕受审（太 21-27/可 11-15/路 19:28-23:56/约 12-19）</li><li>复活显现：空坟墓与复活见证（太 28/可 16/路 24/约 20-21）</li></ul><p>这种三层递进结构（启示→冲突→救赎）塑造了基督教的核心救赎叙事。四重见证既形成立体视角 —— 马太的律法成全、马可的戏剧张力、路加的人文关怀、约翰的永恒维度 —— 又通过差异化的细节选择（如只有约翰记载「复活拉撒路」）形成神学互补。</p><p>尽管视角各异，四福音书共同见证了耶稣的生命、教导、死亡和复活，以及这些事件对人类历史的深远意义。</p><h4 id="515-历史上的基督"><a class="markdownIt-Anchor" href="#515-历史上的基督"></a> 5.1.5. 历史上的基督</h4><p>根据学术研究，历史上的耶稣（Jesus of Nazareth）生活在约公元前 4 年至公元 30 到 33 年，出生于犹太加利利地区的拿撒勒，在罗马帝国统治下的巴勒斯坦地区传道。他是犹太人，受过施洗约翰的洗礼，聚集了一群门徒，巡回教导和治病。他的教导挑战了当时的宗教权威，特别是在耶路撒冷圣殿的做法。根据福音书记载，他最终在逾越节期间被罗马总督本丢・彼拉多判处钉十字架刑。</p><p>耶稣的教导核心包括上帝的国（Kingdom of God）、爱的律法、末世预言和个人与上帝的直接关系。他经常通过比喻和隐喻传递信息，其教导既扎根于犹太传统，又具革新性。</p><p>关于耶稣复活的记载是基督教信仰的基础，但这超出了历史研究的范畴，进入信仰领域。无论如何，耶稣及其追随者创立的运动最终发展成为世界性宗教，深刻塑造了人类历史。</p><h2 id="52-古兰经"><a class="markdownIt-Anchor" href="#52-古兰经"></a> 5.2. 《古兰经》</h2><p>《古兰经》（Al-Qur'an，意为「诵读」）是伊斯兰教的核心经典，穆斯林相信它是真主（Allah）通过天使吉卜利勒（Gabriel）向先知穆罕默德（Muhammad，约 570 到 632 年）的启示，在公元 610 到 632 年间陆续降示。</p><h4 id="521-结构与内容"><a class="markdownIt-Anchor" href="#521-结构与内容"></a> 5.2.1. 结构与内容</h4><p>《古兰经》由 114 章（苏拉，Surah）组成，除第一章外，大致按长度递减排列。全书约 77,000 词，长度与《新约》相近。它以阿拉伯语写成，穆斯林认为其阿拉伯文本具有神圣性，翻译只能视为解释，而非《古兰经》本身。</p><p>《古兰经》内容包括：</p><ul><li>一神论（tawhid）、末日审判、众先知传承</li><li>亚当、挪亚、亚伯拉罕、摩西和耶稣等先知的故事</li><li>伦理道德，如正义、诚实、谦卑、怜悯、慷慨</li><li>法律规定，如礼拜、施舍、婚姻、继承、商业交易</li><li>天地万物的起源与目的</li></ul><p>《古兰经》通过神圣启示的透镜，展现从创世到末日的宏大救赎史诗：</p><ol><li><p>创世之谜（30:20-25）</p><p>真主从水上创造生命（21:30），赋予人类代治大地的使命。阿丹（亚当）被造为「真主在大地上的代治者」（2:30），但因易卜劣厮（撒旦）的诱惑堕落，开启人性考验的序幕。</p></li><li><p>先知长链（40:78）</p><p>从努哈（诺亚）的方舟、易卜拉欣（亚伯拉罕）捣毁偶像，到穆萨（摩西）分开红海，26 位先知的故事构成神圣启示的连续剧。尤素福（约瑟）被兄长出卖终成埃及宰相的故事（12 章），成为人性善恶博弈的缩影。</p></li><li><p>终极启示（33:40）</p><p>穆罕默德在希拉山洞接受首次启示：「你当奉造物主的名义诵读！」（96:1）。历经 23 年启示，对抗麦加多神崇拜，建立麦地那穆斯林共同体，最终在辞朝演说中宣告：「今天，我已为你们成全你们的宗教」（5:3）。</p></li><li><p>审判之日（82:1-5）</p><p>当苍穹破裂、群星飘坠时（82:1-2），每个人将看到自己行为的账簿：「行一个小蚂蚁重的善事者，将见其善报；作一个小蚂蚁重的恶事者，将见其恶报」（99:7-8）。</p></li></ol><p>这些叙事如镶嵌画般散落各章，通过「认主独一」的金线交织成整体。正如夜行登霄（17:1）的隐喻 —— 先知从麦加禁寺升至七重天，最终回归人间 —— 象征人类从物质世界向神圣本源的溯游与复归。</p><p>《古兰经》的语言具有独特的韵律美和修辞力量，被视为阿拉伯文学的巅峰，对阿拉伯语的标准化和发展产生了决定性影响。</p><h4 id="522-与其他一神教经典的关系"><a class="markdownIt-Anchor" href="#522-与其他一神教经典的关系"></a> 5.2.2. 与其他一神教经典的关系</h4><p>《古兰经》承认并尊重犹太教和基督教的先知与经典。它提到《讨拉特》（Torah，摩西五经）、《宰逋尔》（Zabur，诗篇）和《引支勒》（Injil，福音）等早期启示。穆斯林相信《古兰经》是最后也是最完美的启示，纠正了之前经典中被人篡改的部分。</p><p>《古兰经》继承并重新诠释了许多圣经故事。例如，亚伯拉罕（Ibrahim）被描绘为最早的穆斯林（顺从者）；约瑟夫（Yusuf）的故事被完整讲述在第 12 章；耶稣（Isa）被尊为重要先知，但《古兰经》否认他的神性和被钉十字架的说法。</p><h4 id="523-盟约概念的延续与发展"><a class="markdownIt-Anchor" href="#523-盟约概念的延续与发展"></a> 5.2.3. 盟约概念的延续与发展</h4><p>「约」的概念从希伯来圣经延续到《新约》，再到《古兰经》，体现了一神教传统中上帝与人类关系的发展。在《古兰经》中，真主与人类的原初契约（Primordial Covenant）发生在创造之初，所有人类灵魂被问及：「难道我不是你们的主吗？」他们回答：「是的，我们作证。」（7:172）</p><p>这一概念与犹太教和基督教的盟约神学有相似之处，但更强调每个人与真主的直接关系，而非通过特定民族或中介。伊斯兰教认为，每个人生来就带有对真主的自然认知（fitrah），伊斯兰的使命是唤醒这种本性，而非引入全新的概念。</p><p>《古兰经》对盟约的理解展现了一神教思想的演进：从上帝与特定民族（以色列）的契约，到基督教强调通过耶稣建立的新约，再到伊斯兰教强调的普遍原初契约。这一演进反映了宗教概念的普世化趋势。</p><h2 id="53-印度教经典"><a class="markdownIt-Anchor" href="#53-印度教经典"></a> 5.3. 印度教经典</h2><p>印度教与西方一神教传统显著不同，它没有单一创始人、统一教义或中央权威，而是由多种哲学思想、崇拜方式和文化习俗组成的复杂系统。其核心经典也非单一文本，而是随时间演变的丰富文献传统。</p><h4 id="531-吠陀"><a class="markdownIt-Anchor" href="#531-吠陀"></a> 5.3.1. 《吠陀》</h4><p>《吠陀》（Vedas，意为「知识」）是印度最古老的宗教文献，约成形于公元前 1500-500 年，最初通过口头传诵，后来才记录成文。吠陀文献分为四部：</p><ol><li>《梨俱吠陀》（Rigveda）：最古老部分，包含 1,028 首赞美诗，主要献给阿格尼（火神）、因陀罗（雷神）、索玛（月神）等自然神祇。</li><li>《夜柔吠陀》（Yajurveda）：祭祀仪式的诵词和指导，包括黑夜柔和白夜柔两个传本。</li><li>《娑摩吠陀》（Samaveda）：祭祀中的颂歌，多数取自《梨俱吠陀》但配以旋律。</li><li>《阿闼婆吠陀》（Atharvaveda）：包含咒语、医药知识和哲学思考，反映了普通民众的宗教实践。</li></ol><p>每部吠陀又分为四个部分：</p><ul><li>本集（Samhitas）：原始颂歌和祭祀诵词</li><li>梵书（Brahmanas）：祭祀仪式的解释和指导</li><li>森林书（Aranyakas）：适合林居者的冥想实践</li><li>奥义书（Upanishads）：哲学探讨和精神智慧</li></ul><p>吠陀文献通过诗性想象构建了动态的宇宙图景，其核心叙事可概括为三幕神圣戏剧：</p><ol><li><p>原人之祭</p><p>《梨俱吠陀》第 10 卷第 90 首《原人歌》描绘惊心动魄的创世场景：</p><p>「原人有千头千眼千足，覆盖全地…… 诸神将原人作为祭品，春天为酥油，夏天为燃料，秋天为祭品…… 由其身体分化世界：头为天，足为地，呼吸生风，脐部生空界」（10.90.1-14）。这血腥而神圣的献祭确立了「祭祀即宇宙法则」（yajña）的核心理念。</p></li><li><p>因陀罗屠龙</p><p>雷神因陀罗与蛇形魔神弗栗多（Vritra）的对抗是《梨俱吠陀》最壮丽的史诗：</p><p>「他（因陀罗）举起金刚杵，击杀盘踞山中的巨龙，释放被囚禁的江河…… 七座城堡在他怒吼中崩塌」（1.32.1-5）。这场战役象征自然力（雨水 / 干旱）的斗争，更隐喻秩序（ṛta）对混沌的胜利。</p></li><li><p>苏摩之谜</p><p>诸神饮用的永生甘露苏摩（Soma）在祭祀中具象化为仪式饮品，《梨俱吠陀》第 9 卷专述其奥秘：</p><p>「我们饮下苏摩，获得不朽…… 它在石间榨取，如野牛咆哮，赋予诗人神力」（9.4.1-3）。这种致幻植物酿制的圣酒，成为连接人神的中介，激发吠陀先知（ṛṣi）的灵视。</p></li></ol><p>吠陀叙事最终落地为现实的火祭（agnihotra）仪式：</p><ul><li>黎明与黄昏，祭司将酥油倒入圣火，重演原初祭祀</li><li>吟诵《梨俱》诗节召唤诸神，如「阿耆尼啊，你是家族祭司，真理的见证者」（1.1.1）</li><li>通过《夜柔》指导的精准仪式动作，维系宇宙呼吸的节奏</li></ul><p>这种「神话 - 仪式」的闭环结构，使吠陀文明成为活态的神圣剧场。</p><p>《吠陀》反映了早期印度 - 雅利安人的世界观，展示了从自然崇拜向抽象哲学思考的演变。它们构成了印度所有哲学和宗教传统的基础，即使是批判吠陀权威的佛教和耆那教，也与吠陀传统有深刻联系。</p><p>《吠陀》的宇宙观围绕着「天道」（rita）概念，认为宇宙受到一种固有秩序的支配，通过适当的祭祀活动，人类可以维护这一秩序。《梨俱吠陀》中的《原人赞》（Purusha Sukta）描述世界起源于原初神人的祭祀，社会等级制度也源于此。这种宇宙 - 社会对应关系影响了印度文化数千年。</p><h4 id="532-奥义书"><a class="markdownIt-Anchor" href="#532-奥义书"></a> 5.3.2. 《奥义书》</h4><p>《奥义书》（Upanishads，意为「坐于附近」，暗示师徒间的秘密教导）是吠陀传统的哲学高峰，约成形于公元前 800-200 年。传统认为有 108 部奥义书，但最重要的是早期的主要奥义书，如《伊舍》《迦他》《文荼迦》《曼荼迦》等。</p><p>《迦陀奥义书》记载了少年纳奇柯达斯与死神阎摩的传奇对话：</p><blockquote><p>少年自愿走向冥界之门，用生命换取终极智慧。死神三次试图用诱惑劝退他：</p><p>第一次考验：「回去吧！我将赐你百象千金的财富」</p><p>少年答：「财富如朝露，请赐我超越生死的智慧」（1.1.24-25）</p><p>第二次考验：阎摩展示天界乐园 —— 黄金宫殿与不朽青春。</p><p>少年问：「当肉体消亡时，这些享乐将归于何处？」（1.2.10）</p><p>第三次考验：死神化作美艳女神，许诺永恒欢愉。</p><p>少年说：「感官如野马，唯有驭手（智慧）能达彼岸」（1.3.3-4）</p><p>最终阎摩揭示最高真理：</p><p>「知梵者超越生死，如同水溶于水，火归于火。自我（Atman）是战车主人，身体是战车，智慧是御者……」（1.3.9-14）</p><p>少年领悟「汝即彼」（Tat Tvam Asi）的真谛，肉身重返人间时，死亡枷锁已化为晨露。</p></blockquote><p>《大林间奥义书》的创世寓言：</p><blockquote><p>原初的自我（Ātman）在混沌中自语：「我是谁？」</p><p>他分裂为男女二形，交合诞生万物。但雌性化为母牛逃避，雄性化为公牛追逐；雌性变母马，雄性变公马…… 如此衍生众生（1.4.3-6）。</p><p>当他意识到「万物即自我」时，发出震撼三界的宣言：</p><p>「我是创造！我是毁灭！我是呼吸中的呼吸！光中的光！」（5.15.1）</p></blockquote><p>这个自我探索的寓言，成为吠檀多哲学「梵我同一」的终极隐喻。</p><p>《奥义书》标志着印度思想从祭祀仪式向内在探索的转向。它们的核心思想包括：</p><ol><li>梵我同一：个体灵魂（Atman，我）与宇宙本体（Brahman，梵）本质上是同一的。《文荼迦奥义书》宣称：「认识梵者，即成为梵。」这一洞见成为印度哲学的基石。</li><li>轮回与解脱：灵魂因无明（avidya）而困于生死轮回（samsara）；通过正确认识自我本性，可以获得解脱（moksha）。</li><li>业力法则：行为（karma）产生后果，决定未来生命形式和经历。</li><li>知行并重：既重视知识（jnana），也重视行动（karma）和虔诚（bhakti）。</li></ol><p>《奥义书》对印度哲学和宗教产生了决定性影响，所有后来的印度哲学流派，如吠檀多（Vedanta）、数论（Samkhya）、瑜伽（Yoga）等，都可视为对《奥义书》思想的不同诠释。即使佛教的「无我」（anatta）理论，也可理解为对奥义书「我」（atman）概念的批判性发展。</p><p>《奥义书》也影响了西方思想。19 世纪，叔本华接触到《奥义书》拉丁文译本后宣称：「它们是人类智慧的产物」；爱默生、梭罗等超验主义者从中汲取灵感；科学家如特斯拉、爱因斯坦和薛定谔也表达过对奥义书思想的赞赏。</p><h4 id="533-达摩法概念"><a class="markdownIt-Anchor" href="#533-达摩法概念"></a> 5.3.3. 达摩 / 法概念</h4><p>达摩（Dharma，巴利语：Dhamma）是印度宗教哲学中的核心概念，其含义随语境而变化，难以用单一西方术语准确翻译。</p><p>在最广泛意义上，达摩指维持宇宙和社会秩序的根本法则。更具体地说，它可以指：</p><ul><li><p>宇宙法则：支撑世界运行的自然规律</p></li><li><p>社会职责：基于种姓（varna）和人生阶段（ashrama）的社会责任</p><ul><li><p>种姓体系源于《梨俱吠陀》的《原人歌》（10.90.12），将社会分为四个理想类型：</p><ul><li>婆罗门（Brāhmaṇa）：祭司与学者，职责为研习吠陀、主持祭祀</li><li>刹帝利（Kṣatriya）：武士与统治者，负责保护众生、执行正义</li><li>吠舍（Vaiśya）：农民与商人，从事农业、畜牧与贸易</li><li>首陀罗（Śūdra）：劳动者，服务前三个种姓</li></ul><p>这种「原人身体分化说」（婆罗门生于口，刹帝利生于臂，吠舍生于腿，首陀罗生于足）在《摩奴法典》（约公元前 2 世纪）中被系统化为社会规范。但现实中还存在数千个亚种姓（jati），基于职业、地域形成复杂网络。</p><p>每个种姓有其专属的「种姓法」（svadharma）：</p><ul><li>婆罗门需终身学习，刹帝利需精于武艺，吠舍应诚实经商，首陀罗要勤于服务</li><li>违反种姓职责被视为「违逆达摩」，如《薄伽梵歌》警告：「履行他人职责是危险的」（3.35）</li><li>但《摩诃婆罗多》也通过妓女苏达玛的故事质疑僵化制度：她因诚实比许多婆罗门更接近真理</li></ul><p>值得注意的是，佛教和耆那教在继承达摩概念时，都批判种姓制度。佛陀宣称：「河水入海皆失旧名，四姓入我法中亦复如是」（《小部・经集》2.7）。</p></li></ul></li><li><p>道德行为：正义、诚实、非暴力等普遍美德</p></li><li><p>宗教教义：特定宗教传统的核心教导（如佛法）</p></li></ul><p>在《摩诃婆罗多》中，达摩概念被深入探讨，特别是在面临道德困境时。例如，阿周那在库卢之战前犹豫不决，因为无论他选择战斗还是退出，都会违背某种达摩（战士职责与家族责任的冲突）。黑天的教导（《薄伽梵歌》）解决了这一困境，强调行动本身不如行动时的心态重要，提倡「无执着的行动」（nishkama karma）。</p><p>与希腊悲剧类似，印度史诗中的达摩困境展示了道德选择的复杂性和悲剧性。然而，不同于希腊宿命观，印度思想强调通过正确理解和超越二元对立，可以解决这些冲突。《薄伽梵歌》教导阿周那战斗不是为了个人利益，而是为了维护宇宙秩序，这种理解将个人行动与宇宙规律统一起来。</p><p>达摩概念在印度各宗教传统中有不同解释。印度教强调种姓职责；佛教将达摩理解为宇宙真理和佛陀教导；耆那教极度强调非暴力（ahimsa）作为达摩的核心。尽管解释各异，达摩作为指导个人行为、社会关系和宇宙秩序的核心原则，贯穿了印度思想的各个流派。</p><h1 id="6-中国古代思想经典"><a class="markdownIt-Anchor" href="#6-中国古代思想经典"></a> 6. 中国古代思想经典</h1><h2 id="61-中国思想传统概述"><a class="markdownIt-Anchor" href="#61-中国思想传统概述"></a> 6.1. 中国思想传统概述</h2><p>在探讨具体经典前，先了解中国古代思想的整体背景十分必要。中国哲学与西方和印度传统有着根本性差异，它较少关注形而上学或宗教启示，而更专注于社会伦理、政治秩序和个人修养的实用智慧。</p><p>中国古代思想形成于春秋战国时期（公元前 770-221 年），这一被称为「百家争鸣」的时代，各种思想流派相互竞争，为解决社会动荡和道德危机提供方案。主要流派包括儒家、道家、墨家、法家、名家等。其中最有持久影响的是儒家和道家，它们代表了中国思想的两大主要取向。</p><p>中国古典哲学的特点包括：</p><ul><li>重实践轻理论：关注现实生活而非抽象概念</li><li>天人合一：强调人与自然和谐共处</li><li>整体性思维：倾向于综合而非分析</li><li>重德行轻信仰：以伦理修养而非宗教信条为核心</li><li>注重中庸之道：追求平衡与和谐，避免极端</li></ul><p>这些特点使中国哲学既独特又互补于西方和印度传统，为人类文明提供了另一种智慧路径。</p><h2 id="62-论语"><a class="markdownIt-Anchor" href="#62-论语"></a> 6.2. 《论语》</h2><h4 id="621-成书背景与历史地位"><a class="markdownIt-Anchor" href="#621-成书背景与历史地位"></a> 6.2.1. 成书背景与历史地位</h4><p>《论语》（Analects）是记录孔子（公元前 551-479 年）及其弟子言行的语录集，由孔子门人及再传弟子编撰，约成书于公元前 5-4 世纪。它包含 20 篇，共 492 章，主要采用对话形式，记录孔子与弟子、诸侯及他人的交谈。</p><p>《论语》的名称意为「讨论的言辞」，反映了它并非系统哲学著作，而是思想碎片的汇集。它通过简短对话和言论，展现孔子思想的多个方面，需要读者自行连接和解读。</p><p>作为儒家经典「四书」之首（其他三部为《大学》《中庸》《孟子》），《论语》在中国文化中的地位无可比拟。它不仅是中国古代教育的核心教材，也深刻影响了东亚文化圈（包括日本、朝鲜、越南）的思想传统。自汉代起，《论语》成为科举考试的必考内容，塑造了中国知识分子的思维方式和价值观。</p><h4 id="622-孔子及其时代"><a class="markdownIt-Anchor" href="#622-孔子及其时代"></a> 6.2.2. 孔子及其时代</h4><p>孔子生活在社会动荡的春秋末期，周王室衰微，诸侯争霸，礼崩乐坏。他生于鲁国（今山东曲阜）一个没落贵族家庭，年轻时曾做过小吏，后来创办私学，收徒讲学。他周游列国十四年，希望说服统治者采纳他的政治理念，但未能如愿。晚年返回鲁国，致力于整理古代文献和教育事业。</p><p>孔子自称「述而不作」，表明他不是创新者，而是古代文化的传承者和诠释者。然而，他对传统的重新解释实际上具有深刻的创新性，将古代贵族礼仪转化为普遍适用的伦理原则，使道德从血缘和地位的限制中解放出来。</p><p>他的生平和教学方法在《论语》中有生动描述：「子曰：『默而识之，学而不厌，诲人不倦，何有于我哉？』」（《述而》）这种谦虚和教学热忱塑造了他作为中国历史上最伟大教育家的形象。</p><blockquote><p>这句自述集中体现孔子的教育哲学：</p><ol><li>默而识（zhì）之：把所见所闻默默记在心里<ul><li>识：不是死记硬背，而是理解内化</li></ul></li><li>学而不厌：努力学习从不满足<ul><li>「厌」通「餍」，意为满足</li></ul></li><li>诲人不倦：教导别人从不厌倦</li><li>何有于我哉<ul><li>表面自谦：「这些我做到了哪些呢？」</li><li>实则暗含期许：「这些不正是教育者的本分吗？」</li></ul></li></ol></blockquote><h4 id="623-核心思想"><a class="markdownIt-Anchor" href="#623-核心思想"></a> 6.2.3. 核心思想</h4><p>《论语》虽然不是系统哲学著作，但包含几个相互关联的核心概念：</p><ol><li><p>仁</p><p>仁是孔子思想的核心，《论语》中提到 109 次。它最初指亲属间的亲爱之情，孔子将其扩展为普遍的人道精神和道德完善的理想。</p><p>「仁者爱人」（《颜渊》）简洁地表达了仁的本质。仁者是充满慈爱之心、满怀爱意的人。</p><p>仁的实践包括自律、尊重他人和推己及人：「己所不欲，勿施于人」（《颜渊》）—— 自己不愿意的，不要施加给别人。</p><p>仁不是抽象理念，而是具体行为中体现的品质：「仁远乎哉？我欲仁，斯仁至矣」（《述而》；译文：仁难道离我们很远吗？我想达到仁，仁就到了），强调道德实践的即时性和可得性，以及人进行道德修养的主观能动性。仁是人天生的本性，因此为仁就全靠自身的努力，不能依靠外界的力量。</p></li><li><p>礼</p><p>礼指规范社会行为的仪式和习俗。孔子强调礼不仅是外在形式，更是内在道德的表达：「人而不仁，如礼何？人而不仁，如乐何？」（《八佾》；译文：人的内心不追求仁，表面上遵守礼又有什么用呢？人的内心不追求仁，表面上演奏乐又有什么用呢？）儒家推崇礼乐，礼和乐是形式，其本质是为了提升人性，使上位者能爱民如子，百姓能知耻且格（指人有知耻之心，则能自我检点而归于正道）。</p><p>礼在孔子思想中有双重功能：维护社会秩序和培养个人品格。适当的礼仪表达了对他人的尊重，也帮助个人培养内在美德。礼的核心是「敬」，即真诚尊重之心。</p></li><li><p>义</p><p>义是道德正当性的标准，指行为符合道德原则而非追求私利。「君子喻于义，小人喻于利」（《里仁》）表明义与利的对立。然而，孔子并非完全否定利益追求，而是强调义应指导利：「富与贵，是人之所欲也；不以其道得之，不处也」（《里仁》；译文：财富与地位，是每个人都渴望的，但如果不用正当方法获得，君子绝不接受）。</p></li><li><p>智</p><p>智指道德智慧和判断力，而非纯粹的知识积累。孔子重视学习，但认为学习目的是道德实践：「学而不思则罔，思而不学则殆」（《为政》；译文：只学习不思考会陷入迷茫，只空想不学习会走向危险）。</p><p>真正的智慧包括认识自己的限度：「知之为知之，不知为不知，是知也」（《为政》；译文：知道就说知道，不知道就承认不知道，这才是真智慧）。</p></li><li><p>信</p><p>信是诚实和信用，社会和谐的基础：「人而无信，不知其可也」（《为政》；译文：如果一个人没有信用，真不知道他如何立身处世）。信任是社会关系和政治统治的基础：「民无信不立」（《颜渊》；译文：失去民众的信任，国家就无法存续）。</p></li><li><p>君子理想</p><p>君子是孔子提出的理想人格，原指贵族身份，被重新定义为道德卓越者。君子德行包括：</p><ul><li>自省：「君子求诸己，小人求诸人」（《卫灵公》；译文：君子遇事反思自己，小人遇事指责他人）</li><li>中庸：「君子和而不同，小人同而不和」（《子路》；译文：君子在差异中寻求和谐，小人在表面统一中制造矛盾）</li><li>执着于道德：「君子喻于义，小人喻于利」（《里仁》；译文：君子的思维围绕道义展开，小人的思维局限在利益算计）</li><li>勇于改错：「过而不改，是谓过矣」（《卫灵公》；译文：有了过错却不改正，这才是真正的错误）</li></ul><p>君子概念是孔子思想中重要的创新，将社会地位与道德成就分离，为中国建立了基于德行而非血统的精英理想。</p></li></ol><h4 id="624-政治与社会思想"><a class="markdownIt-Anchor" href="#624-政治与社会思想"></a> 6.2.4. 政治与社会思想</h4><p>孔子的政治思想基于「为政以德」原则：「为政以德，譬如北辰，居其所而众星共之」（《为政》；译文：用德行治理国家，就像北极星稳居中心，群星自然环绕）。他强调统治者的道德榜样作用超过法律强制：「道之以政，齐之以刑，民免而无耻；道之以德，齐之以礼，有耻且格」（《为政》；译文：用政令引导、刑罚约束，百姓只会逃避惩罚而无廉耻；用德行感化、礼教规范，百姓会有羞耻心且自觉守规）。</p><p>孔子提倡「正名」，即社会角色与实际行为相符：「君君，臣臣，父父，子子」（《颜渊》；译文：君王守君道，臣子尽臣责，父亲担父职，儿子行子孝）。这反映了他对社会秩序的关注和对个人责任的强调。</p><p>他的理想政治是大同社会：「大道之行也，天下为公」（《礼记・礼运》，虽非出自《论语》，但能够反映出孔子思想；译文：理想社会运行时，天下资源属于全体民众）。然而，他认识到这需要循序渐进的变革，而非革命，重视传统作为社会稳定的基础：「温故而知新，可以为师矣」（《为政》；译文：在传统中开创新知，方能成为时代的引领者）。</p><h4 id="625-教育思想"><a class="markdownIt-Anchor" href="#625-教育思想"></a> 6.2.5. 教育思想</h4><p>作为中国第一位专业教育家，孔子的教育观对中国产生深远影响：</p><ul><li>因材施教：「有教无类」，不分贵贱皆可教育</li><li>启发式教学：「不愤不启，不悱不发」（《述而》；译文：不到学生冥思苦想仍不通时，不去点拨；不到他想说却说不清时，不去引导）</li><li>理论与实践结合：「学而时习之，不亦说乎」（《学而》；译文：学习知识并能适时实践，岂不令人愉悦）</li><li>终身学习：「吾十有五而志于学，三十而立，四十而不惑，五十而知天命，六十而耳顺，七十而从心所欲，不逾矩」（《为政》）</li></ul><p>《论语》记录孔子教学方法灵活多样，针对不同学生提出不同要求。他强调学习古代经典，同时也重视实践和反思：「学而不思则罔，思而不学则殆」（《为政》）。</p><h4 id="626-历史影响与现代意义"><a class="markdownIt-Anchor" href="#626-历史影响与现代意义"></a> 6.2.6. 历史影响与现代意义</h4><p>《论语》对中国和东亚文化的影响难以估量。它塑造了中国知识分子的价值观，影响了政治制度、社会规范和家庭关系。儒家思想通过科举制度成为官方意识形态，成为统治阶级的合法性基础。</p><p>《论语》也影响了西方。17 世纪传入欧洲后，伏尔泰、康德等启蒙思想家对孔子的道德哲学表示赞赏。莱布尼茨认为中国文明可以补充欧洲文化。</p><p>20 世纪，《论语》经历了从被激烈批判到重新评价的过程。当代学者指出儒家思想中的普世价值，如仁爱、和谐、责任，对现代社会仍有启示。儒家强调和谐与平衡的思想，对处理全球化带来的文化冲突提供了另一种视角。</p><p>现代解读强调《论语》中的人文主义精神和批判精神，而非教条。儒家思想的现代转化可见于新加坡、韩国和日本的发展模式，展示了传统价值如何与现代化协调发展。</p><h2 id="63-道德经"><a class="markdownIt-Anchor" href="#63-道德经"></a> 6.3. 《道德经》</h2><h4 id="631-作者与成书"><a class="markdownIt-Anchor" href="#631-作者与成书"></a> 6.3.1. 作者与成书</h4><p>《道德经》，又称《老子》，传统上认为是春秋末期的老子（李耳，约公元前 571-471 年）所著。全书约 5000 字，分为道经（前 37 章）和德经（后 44 章）两部分。「道德」在这里不是现代伦理学意义，而是指宇宙本体（道）及其在人世的体现（德）。</p><p>老子的历史真实性一直存在争议。据《史记》记载，他是周朝守藏室的官员，与孔子同时代或稍早，晚年西行，应函谷关令尹喜之请写下此书。但现代学者对此存疑，有人认为《道德经》可能是战国时期（公元前 475-221 年）道家思想的集体结晶，而非单一作者所作。</p><p>最早的《道德经》文本来自 1973 年长沙马王堆汉墓出土的帛书，约公元前 200 年。1993 年，荆门郭店楚墓出土的竹简进一步推前了文本历史，约公元前 300 年。这些考古发现证实《道德经》至少在公元前 3 世纪末已成形。</p><h4 id="632-核心思想"><a class="markdownIt-Anchor" href="#632-核心思想"></a> 6.3.2. 核心思想</h4><ol><li><p>道</p><p>道是《道德经》最核心的概念，有多层含义：</p><ul><li>宇宙本体：「有物混成，先天地生…… 可以为天下母」（第 25 章）</li><li>自然规律：「道法自然」（第 25 章）</li><li>无为原则：「道常无为而无不为」（第 37 章）</li></ul><p>道具有矛盾特性：「道可道，非常道；名可名，非常名」（第 1 章），它超越语言和概念，只能通过悖论暗示：「玄之又玄，众妙之门」（第 1 章）。</p><p>道的本质是「无」和「空」：「天下万物生于有，有生于无」（第 40 章）。这种「无」不是虚无，而是充满潜在性的空白，如：「埏埴以为器，当其无，有器之用」（第 11 章）。</p></li><li><p>德</p><p>德是道在个体中的体现和实践。它不是外加的道德规范，而是顺应道的自然品质：「上德不德，是以有德；下德不失德，是以无德」（第 38 章）。真正的德是不刻意追求美德的结果，而是自然流露。</p></li><li><p>无为</p><p>无为是道家核心行动原则，不是绝对不行动，而是不做违背自然的强制行为：「为无为，则无不治」（第 3 章）。</p><p>无为的统治是顺应事物自身规律：「太上，下知有之；其次，亲而誉之…… 功成事遂，百姓皆谓：『我自然』」（第 17 章）。理想统治者工作不被察觉，让民众感到一切自然发生。</p></li><li><p>返朴归真</p><p>《道德经》批评文明的复杂性和人为规范：「绝圣弃智，民利百倍；绝仁弃义，民复孝慈；绝巧弃利，盗贼无有」（第 19 章）。它主张返回简朴自然状态：「见素抱朴，少私寡欲」（第 19 章）。</p><p>理想社会是「小国寡民」（第 80 章），人们安于简单生活，不追求复杂知识和远程交往：「甘其食，美其服，安其居，乐其俗」（第 80 章）。</p></li><li><p>辩证思维</p><p>《道德经》展现了独特的辩证思维，强调对立面相互依存：「有无相生，难易相成，长短相形，高下相倾」（第 2 章）。它认为事物会向反面转化：「祸兮福之所倚，福兮祸之所伏」（第 58 章）。</p><p>这种思维导致「反者道之动」原则，即事物发展趋向其反面：「弱者道之用」（第 40 章），「曲则全，枉则直，洼则盈，敝则新，少则得，多则惑」（第 22 章）。</p></li></ol><h4 id="633-政治思想"><a class="markdownIt-Anchor" href="#633-政治思想"></a> 6.3.3. 政治思想</h4><p>《道德经》的政治思想可概括为「无为而治」，认为最好的统治是最少的干预：「故圣人云：我无为，而民自化；我好静，而民自正；我无事，而民自富；我无欲，而民自朴」（第 57 章）。</p><p>它批评儒家的积极政治理念，认为道德教化和礼制只会使社会更加混乱：「天下多忌讳，而民弥贫；民多利器，国家滋昏；人多伎巧，奇物滋起；法令滋彰，盗贼多有」（第 57 章）。</p><p>《道德经》推崇柔弱胜刚强的治国策略：「天下莫柔弱于水，而攻坚强者莫之能胜」（第 78 章）。理想统治者应保持低调：「圣人不积，既以为人，己愈有；既以与人，己愈多」（第 81 章）。</p><h4 id="634-与儒家的关系"><a class="markdownIt-Anchor" href="#634-与儒家的关系"></a> 6.3.4. 与儒家的关系</h4><p>道家与儒家代表了中国思想的两大主要取向，它们的关系既对立又互补：</p><ul><li><p>对立方面：</p><ul><li>儒家强调社会参与，道家主张超脱尘世</li><li>儒家重视礼仪规范，道家推崇自然本性</li><li>儒家相信教育改良，道家怀疑知识价值</li><li>儒家推崇道德完善，道家追求自然和谐</li></ul></li><li><p>互补方面：</p><ul><li>都关注社会和谐，只是方法不同</li><li>都强调自我修养，儒家外向，道家内向</li><li>都批评暴力与战争</li><li>在中国历史上常互相融合，儒家入世，道家出世</li></ul></li></ul><p>中国文化传统常被概括为「外儒内道」，表明这两种思想在实践中的互补性。文人常在政治生涯（儒）与山水隐居（道）间转换，体现中国知识分子的双重理想。</p><h4 id="635-道家哲学的演变"><a class="markdownIt-Anchor" href="#635-道家哲学的演变"></a> 6.3.5. 道家哲学的演变</h4><p>《道德经》奠定了道家哲学基础，其思想在后世有多种发展方向：</p><ol><li>庄子（约公元前 369-286 年）将老子的自然主义发展为一种精神自由哲学，强调超越社会规范，《庄子》的寓言如《逍遥游》展现了道家精神自由的理想。</li><li>黄老道家（汉初）将道家思想与法家统治术结合，成为汉初的统治思想，强调顺应自然规律的统治艺术。</li><li>宗教道教（东汉末年）将道家哲学转化为追求长生不老的宗教体系，《太平经》和《周易参同契》等著作结合了道家思想与方士传统。</li><li>魏晋玄学（3-6 世纪）融合道家、儒家和佛教，发展出「贵无」和「崇有」两派，代表人物如王弼、郭象等，对老庄进行本体论诠释。</li><li>新道家（宋明理学）将道家思想融入儒家框架，如周敦颐《太极图说》结合了儒道宇宙观。</li></ol><p>这种多元发展表明《道德经》具有丰富的解释空间和深刻的启发性，使其成为中国思想史上最有生命力的经典之一。</p><h4 id="636-现代意义与全球影响"><a class="markdownIt-Anchor" href="#636-现代意义与全球影响"></a> 6.3.6. 现代意义与全球影响</h4><p>《道德经》是被翻译最广的中国古典文献，在西方引起广泛关注，影响了从物理学到生态环保的多个领域：</p><ol><li>现代物理学：量子物理学家如卡普拉（Fritjof Capra）在《道的物理学》中指出道家宇宙观与量子理论的相似性，如互补原理和整体性。</li><li>环境生态：道家的自然哲学启发了深层生态学，强调人与自然和谐共处，而非控制征服。</li><li>领导理论：无为而治的理念影响了现代组织管理，强调授权和创造性空间。</li><li>心理治疗：道家的接受与顺应思想影响了西方心理治疗，特别是接受与承诺疗法。</li><li>流行文化：从《星球大战》中的「原力」到各种冥想实践，道家思想渗透到西方流行文化的方方面面。</li></ol><p>《道德经》对现代社会的主要启示包括：批判消费主义和物质主义，强调简朴生活；提供替代性发展模式，不以单纯速度和规模为目标；在技术至上时代重新思考人与自然的关系；在充满对立的世界中，提供一种超越二元思维的智慧。</p><h1 id="7-早期基督教思想"><a class="markdownIt-Anchor" href="#7-早期基督教思想"></a> 7. 早期基督教思想</h1><h2 id="71-圣奥古斯丁与忏悔录"><a class="markdownIt-Anchor" href="#71-圣奥古斯丁与忏悔录"></a> 7.1. 圣奥古斯丁与《忏悔录》</h2><h4 id="711-作者生平与历史背景"><a class="markdownIt-Anchor" href="#711-作者生平与历史背景"></a> 7.1.1. 作者生平与历史背景</h4><p>圣奥古斯丁（Augustine of Hippo，354-430 年）是早期基督教最重要的神学家和哲学家之一，被称为拉丁教父中的巨擘。他出生于北非塔加斯特（今阿尔及利亚），父亲是异教徒，母亲莫尼卡则是虔诚的基督徒。</p><p>奥古斯丁的生涯正值罗马帝国转型的关键时期。君士坦丁大帝于 313 年颁布《米兰敕令》，使基督教从被迫害宗教转变为合法信仰，到奥古斯丁时代，基督教已成为帝国主导宗教。然而，帝国政治正日渐衰落，他去世前不久（410 年），罗马城被西哥特人洗劫，标志着西罗马帝国开始崩溃。</p><p>年轻时的奥古斯丁并非基督徒，而是沉迷于世俗享乐。他接受良好教育，成为修辞学教师，先后在迦太基、罗马和米兰任教。在米兰，他结识了安波罗修主教，并受到新柏拉图主义影响。经历长期精神挣扎后，在 387 年复活节前夕受洗，正式皈依基督教。</p><p>皈依后，他返回北非，创建修道院，过着禁欲生活。391 年，他在希波被祝圣为神父，396 年成为希波主教，直至去世。主教期间，他与多纳徒派、伯拉纠派等异端进行激烈辩论，著书立说，奠定了中世纪基督教神学的基础。</p><h4 id="712-忏悔录的写作与结构"><a class="markdownIt-Anchor" href="#712-忏悔录的写作与结构"></a> 7.1.2. 《忏悔录》的写作与结构</h4><p>《忏悔录》（Confessiones）写于 397-400 年间，是西方文学中第一部真正意义上的自传，以祈祷形式向上帝倾诉。然而，它远非简单的生平叙述，而是深刻的神学反思和哲学探索。全书共 13 卷：</p><ul><li>卷一至九：自传部分，记述奥古斯丁从童年到皈依的人生历程，特别强调他的精神探索与挣扎。</li><li>卷十：对当下自我的反思，探讨记忆本质。</li><li>卷十一至十三：对《创世记》的冥想与诠释，探讨时间、创造和三位一体等神学主题。</li></ul><p>《忏悔录》的标题「confessiones」在拉丁文中有双重含义：既是「忏悔」（认罪），也是「赞美」（认信上帝的伟大）。这双重意义贯穿全书，使之既是对个人罪的坦承，也是对神恩典的颂扬。</p><h4 id="713-自传叙事从迷失到皈依"><a class="markdownIt-Anchor" href="#713-自传叙事从迷失到皈依"></a> 7.1.3. 自传叙事：从迷失到皈依</h4><p>《忏悔录》开篇即点明全书主题：「我们的心若不安息在你怀中，便不得安宁。」这揭示了奥古斯丁对灵魂不安与对神渴望的核心体验。</p><p>奥古斯丁坦率描述自己的早年生活，包括犯下的各种罪行。他讲述自己如何偷窃梨子，不是因为饥饿，而是「为恶而恶」；他承认自己沉迷情欲，曾祈求「主啊，请赐我贞洁和节制，但不要太快」；他回忆自己追求名利与虚荣，以及对戏剧和竞技场娱乐的迷恋。</p><p>他的精神探索经历了多个阶段：</p><ul><li>青年时期接触西塞罗的《荷尔顿修斯》，激发对智慧的热爱</li><li>加入摩尼教九年，被其二元论所吸引</li><li>深入研究占星术，后在学术和逻辑上发现其谬误</li><li>接触学院派怀疑主义，对一切确定性产生怀疑</li><li>在米兰被新柏拉图主义吸引，特别是普罗提诺的著作</li></ul><p>关键转折发生在米兰花园。在痛苦挣扎中，奥古斯丁听到一个声音说「拿起来读」，随手翻开保罗的《罗马书》，读到「不可荒宴醉酒，不可好色邪荡，不可争竞嫉妒；总要披戴主耶稣基督，不要为肉体安排，去放纵私欲」（罗马书 13:13-14）。这段经文使他心中茅塞顿开，决定皈依基督教。</p><p>皈依后不久，他的母亲莫尼卡去世。书中记录了他与母亲在奥斯提亚的一次神秘体验，两人在谈话中共同上升，短暂感受到永恒的临在，这是书中最动人的段落之一。</p><h4 id="714-哲学与神学思想"><a class="markdownIt-Anchor" href="#714-哲学与神学思想"></a> 7.1.4. 哲学与神学思想</h4><p>《忏悔录》不仅是自传，也是深刻的哲学和神学著作，探讨了多个重要主题：</p><ol><li><p>罪恶与意志</p><p>奥古斯丁对罪恶本质的分析极为深刻。他认为罪不是实体，而是对善的缺失或扭曲：「我寻找恶是什么，发现它不是实体，而是意志从最高实体转向低级事物的扭曲。」</p><p>他提出「分裂的意志」概念，描述内心挣扎：「意志命令自己，而自己却不服从。」这种自我分裂反映了原罪对人类自由的损害。在奥古斯丁看来，真正的自由不是为所欲为，而是摆脱罪的束缚，做出正确选择的能力。</p></li><li><p>记忆与时间</p><p>《忏悔录》第十卷对记忆本质进行了开创性探讨。奥古斯丁将记忆描述为「广阔的宫殿」，包含过去经验、学习知识，甚至某种对神的内在认识。他提出记忆不仅储存感官经验，还包含非感官性概念，如数学真理。</p><p>第十一卷著名的时间分析至今仍有哲学价值。他质问：「什么是时间？如果没人问我，我知道；如果要我解释，我不知道。」他分析过去、现在和未来，认为只有「现在」真实存在，而过去是「不再」的现在，未来是「尚未」的现在。现在本身也是瞬息即逝的。这种分析导向对永恒的思考，永恒不是无尽时间，而是时间的彻底超越，在永恒中，一切都是「同时」的现在。</p></li><li><p>上帝与创造</p><p>奥古斯丁反对摩尼教的二元论，强调上帝创造的一切本质上都是善的：「你看你所创造的一切，都甚美好。」邪恶不是独立实体，而是善的缺失或扭曲。</p><p>在诠释《创世记》时，他探讨上帝如何「从无中创造」，以及时间与创造的关系。他认为上帝创造了时间本身，因此在创造之前谈论「时间」是没有意义的。这些思考展现了奥古斯丁将希腊哲学概念与基督教教义融合的才能。</p></li><li><p>恩典与预定论</p><p>《忏悔录》强调人类救赎完全依靠上帝的恩典。奥古斯丁认为，由于原罪，人类无法凭自己的力量选择善。即使信仰本身也是上帝的恩赐：「信仰不是出于我们自己，乃是上帝所赐的礼物。」</p><p>这导致他后来发展出预定论学说，认为上帝预先选择了得救者，这些思想对改教家马丁・路德和约翰・加尔文产生深远影响。</p></li></ol><h4 id="715-文学特色与修辞艺术"><a class="markdownIt-Anchor" href="#715-文学特色与修辞艺术"></a> 7.1.5. 文学特色与修辞艺术</h4><p>《忏悔录》不仅是哲学和神学著作，也是杰出的文学作品，展现了奥古斯丁作为修辞学教师的才华：</p><ol><li><p>祈祷式叙述</p><p>全书直接向上帝倾诉，创造了亲密对话的效果：「你创造了我们归向你，我们的心若不安息在你怀中，便不得安宁。」这种祈祷体强调了上帝作为隐形听众的临在，使读者成为这场灵魂对话的旁观者。</p></li><li><p>心理分析的深度</p><p>奥古斯丁对自己内心状态的分析惊人地现代。他描述记忆、情感、欲望和意志的复杂互动，展现了深刻的自我意识：「我已成为自己的内心荒地。」他对青少年心理的描述，如偷梨事件中对群体压力的分析，显示了对人性的敏锐洞察。</p></li><li><p>生动的意象与比喻</p><p>书中充满鲜活意象，如将上帝描述为「我灵魂的甘露」，将自己比作「浪子远离你的面容」。特别是对内心挣扎的描述常用生动比喻：「我旧日罪恶的习惯依然握住我，低声说：『你要抛弃我们吗？』」</p></li><li><p>语言的音乐性</p><p>拉丁文原文具有强烈的节奏感和韵律美，即使在翻译中也能感受到语言的起伏与张力。奥古斯丁善用排比、对照、顶真等修辞手法，创造出既激情又精确的语言风格。</p></li></ol><h4 id="716-历史影响与现代意义"><a class="markdownIt-Anchor" href="#716-历史影响与现代意义"></a> 7.1.6. 历史影响与现代意义</h4><p>《忏悔录》对西方文学、哲学和神学产生了深远影响：</p><ol><li><p>自传文学的开创</p><p>作为西方第一部成熟自传，《忏悔录》确立了内省自传的传统，影响了从卢梭的《忏悔录》到托尔斯泰的《忏悔》等后世经典。它开创了将个人经历与思想探索结合的文体。</p></li><li><p>神学影响</p><p>奥古斯丁的神学思想塑造了整个中世纪基督教。他关于原罪、神恩、预定论的学说成为天主教正统教义，也深刻影响了新教神学。《忏悔录》对信仰经验的描述为后世神秘主义传统提供了模板。</p></li><li><p>哲学贡献</p><p>他对时间、记忆、意识等主题的探讨影响了胡塞尔、海德格尔等现象学家。他的内省方法被视为现代意识哲学的先驱。维特根斯坦曾说：「如果把哲学比作城市，奥古斯丁是先民们留下的古城，而我们则生活在郊外的新区。」</p></li><li><p>心理学启示</p><p>弗洛伊德承认奥古斯丁对潜意识的洞察先于精神分析学。荣格则从奥古斯丁的自我探索中汲取灵感，发展个体化理论。现代心理治疗中的自传式叙事也可追溯到《忏悔录》的传统。</p></li><li><p>现代意义</p><p>在当代多元文化语境下，《忏悔录》仍具有重要价值。它对内心挣扎的真实描述，对生命意义的深刻探索，对善恶问题的不懈思考，超越了特定宗教框架，成为人类共同的精神遗产。</p><p>在个人身份日益碎片化的现代社会，《忏悔录》提供了一种整合自我的模式，表明个人叙事如何能赋予生命意义和连贯性。它证明，严肃的自我反思不仅具有心理价值，也有深刻的精神和哲学意义。</p><p>与现代许多自传不同，《忏悔录》不是自我肯定或自我辩护，而是谦卑的自我审视，承认人类的限度和对超越力量的需要。这种视角在今天的自我中心文化中尤为珍贵，提醒我们自我实现的真正意义可能恰恰在于超越自我。</p></li></ol></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;世界文学经典学笔记，仅作为个人学习记录，不保证正确性。&lt;/p&gt;</summary>
    
    
    
    <category term="学术笔记" scheme="https://blog.cytrogen.icu/categories/%E5%AD%A6%E6%9C%AF%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="大学课程" scheme="https://blog.cytrogen.icu/tags/%E5%A4%A7%E5%AD%A6%E8%AF%BE%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>React + NestJS 购物平台练习【5】用户登录功能</title>
    <link href="https://blog.cytrogen.icu/posts/270a.html"/>
    <id>https://blog.cytrogen.icu/posts/270a.html</id>
    <published>2025-02-12T05:00:00.000Z</published>
    <updated>2026-02-09T17:16:54.997Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>在构建电商平台的过程中，用户登录是一个不可或缺的核心功能。</p><p>本文将详细介绍如何在 React 前端实现登录表单组件，并结合 NestJS 后端完成完整的用户认证流程，包括 JWT 认证、记住我功能以及登录状态持久化等关键特性。</p><span id="more"></span><h1 id="1-小改动"><a class="markdownIt-Anchor" href="#1-小改动"></a> 1. 小改动</h1><h2 id="11-改变量字段名字"><a class="markdownIt-Anchor" href="#11-改变量字段名字"></a> 1.1. 改变量 / 字段名字</h2><p>将 React 项目的 <code>src/stores/user/types.ts</code> 中的 <code>LoginCredentials</code> 的 <code>email</code> 修改为 <code>username</code>：</p><pre><code class="language-ts">export interface LoginCredentials {   username: string;   password: string; }</code></pre><h2 id="12-修改依赖数组"><a class="markdownIt-Anchor" href="#12-修改依赖数组"></a> 1.2. 修改依赖数组</h2><p>在 <code>src/pages/VerifyEmail.tsx</code> 中的 <code>useEffect</code> 的依赖数组内加一个 <code>location.search</code>：</p><pre><code class="language-tsx">useEffect(() =&gt; {  const searchParams = new URLSearchParams(location.search);  const token = searchParams.get('token');  const currentToken = useUserStore.getState().verificationToken;  if (token &amp;&amp; !verificationInProgress &amp;&amp; !emailVerified &amp;&amp; token !== currentToken) {    handleVerification(token).then(r =&gt; {      if (r.success &amp;&amp; 'message' in r) console.log('邮箱验证成功：', r.message);    });  }}, [handleVerification, verificationInProgress, emailVerified, location.search]);</code></pre><h2 id="13-新建-email-verificationinterfacets"><a class="markdownIt-Anchor" href="#13-新建-email-verificationinterfacets"></a> 1.3. 新建 <code>email-verification.interface.ts</code></h2><p>将原本放在 <code>users.service.ts</code> 内的这段内容单独放在一个文件里：</p><pre><code class="language-ts">export enum EmailVerificationError {  TOKEN_INVALID = 'TOKEN_INVALID',  TOKEN_EXPIRED = 'TOKEN_EXPIRED',  ALREADY_VERIFIED = 'ALREADY_VERIFIED'}export interface VerificationResponse {  success: boolean;  message: string;  error?: EmailVerificationError;  userId?: string;}</code></pre><h2 id="14-统一查找用户的方法"><a class="markdownIt-Anchor" href="#14-统一查找用户的方法"></a> 1.4. 统一查找用户的方法</h2><p>原先我们只写了靠 ID 来查找用户的方法，如果要进行扩展的话，一个方法一个方法写太麻烦了，干脆写一个更灵活的查找方法、支持通过任何唯一字段查找用户：</p><pre><code class="language-ts">async findUser(criteria: UserSearchCriteria) {  this.logger.debug(`开始查找用户，条件：${JSON.stringify(criteria)}`);  const whereClause = Object.entries(criteria)    .filter(([, value]) =&gt; value !== undefined)    .reduce((acc, [key, value]) =&gt; ({ ...acc, [key]: value }), {});  if (Object.keys(whereClause).length === 0) {    this.logger.warn('查询条件为空');    throw new BadRequestException('至少需要一个查询条件');  }  const user = await this.usersRepository.findOne({    where: whereClause  });  if (!user) {    const [[key, value]] = Object.entries(whereClause);    const fieldMap = {      id: 'ID',      username: '用户名',      email: '邮箱',      verificationToken: '验证令牌'    };    const errorMessage = `未找到${fieldMap[key]}为 ${value} 的用户`;    this.logger.warn(`查找用户失败：${errorMessage}`);    throw new NotFoundException(errorMessage);  }  this.logger.debug(`用户查找成功：${user.id}，用户详细信息：${JSON.stringify(user)}`);  return user;}</code></pre><pre><code class="language-ts">export type UserSearchCriteria = Partial&lt;{  id: string;  username: string;  email: string;  verificationToken: string;}&gt;;</code></pre><p><code>UsersController</code> 的查找用户 API 也可以修改成类似的样子：</p><pre><code class="language-ts">@ApiOperation({ summary: '根据不同字段查找用户' })@ApiParam({ name: 'field', enum: ['id', 'username', 'email'], description: '查找字段' })@ApiParam({ name: 'value', description: '查找值' })@ApiResponse({ status: HttpStatus.OK, description: '获取用户信息成功', type: Users })@HttpCode(HttpStatus.OK)@Get(':field/:value')async findByField(@Param('field') field: 'id' | 'username' | 'email', @Param('value') value: string): Promise&lt;Users&gt; {  const validFields = ['id', 'username', 'email'];  if (!validFields.includes(field)) {    throw new BadRequestException(`不支持通过 ${field} 字段查找用户`);  }  return this.usersService.findUser({ [field]: value });}</code></pre><h2 id="15-jwt-payload-修复"><a class="markdownIt-Anchor" href="#15-jwt-payload-修复"></a> 1.5. <code>JWT Payload</code> 修复</h2><pre><code class="language-ts">// 过去的接口export interface JWTPayload {  sub: number;  // 错误的类型  username: string;  email: string;  role: string;  iat?: number;  exp?: number;  aud?: string;  iss?: string;}// 现在的接口export interface JWTPayload {  sub: string;  // 修正为 string 类型，因为使用 UUID  username: string;  email: string;  role: string;  verified: boolean;  // 新增字段，用于邮箱验证状态  iat?: number;  exp?: number;  aud?: string;  iss?: string;}</code></pre><h2 id="16-布局组件优化"><a class="markdownIt-Anchor" href="#16-布局组件优化"></a> 1.6. 布局组件优化</h2><p>为了更好地适应不同的页面布局需求，我们需要增加主布局组件的灵活性。原有的 <code>MainLayout</code> 组件只支持路由渲染：</p><pre><code class="language-tsx">const MainLayout = () =&gt; {  return (    &lt;div&gt;      &lt;header className="bg-primary shadow"&gt;        &lt;nav className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"&gt;          {/* TODO: 导航内容 */}        &lt;/nav&gt;      &lt;/header&gt;      &lt;main&gt;        &lt;div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"&gt;          &lt;Outlet /&gt;        &lt;/div&gt;      &lt;/main&gt;    &lt;/div&gt;  );};</code></pre><p>我们对其进行了改造，使其同时支持直接的子组件渲染：</p><pre><code class="language-tsx">import React from 'react';import { Outlet } from 'react-router-dom';interface MainLayoutProps {  children?: React.ReactNode;}const MainLayout = ({ children }: MainLayoutProps) =&gt; {  return (    &lt;div&gt;      &lt;header className="bg-primary shadow"&gt;        &lt;nav className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"&gt;          {/* TODO: 导航内容 */}        &lt;/nav&gt;      &lt;/header&gt;      &lt;main&gt;        &lt;div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"&gt;          { children ? children : &lt;Outlet /&gt; }        &lt;/div&gt;      &lt;/main&gt;    &lt;/div&gt;  );};export default MainLayout;</code></pre><h1 id="2-实现登录表单组件"><a class="markdownIt-Anchor" href="#2-实现登录表单组件"></a> 2. 实现登录表单组件</h1><p>在电商平台中，我们需要一个用户友好的登录界面，让用户能够：</p><ul><li>输入用户名和密码进行登录</li><li>在输入过程中获得适当的表单验证反馈</li><li>看到登录状态的加载提示</li><li>收到登陆成功或者失败的明确提示</li></ul><ol><li><p>让我们先在 <code>src/pages</code> 目录下创建 <code>Login.tsx</code>：</p> <pre><code class="language-tsx">import React from 'react'; import { useFormik } from 'formik'; import * as Yup from 'yup'; import { useNavigate } from 'react-router-dom'; import { useUserStore } from '../stores'; import AuthLayout from '../layouts/AuthLayout'; import logo from '../assets/ShoppingNest.png'; const Login = () =&gt; {   const navigate = useNavigate();   const login = useUserStore(state =&gt; state.login);   const isLoading = useUserStore(state =&gt; state.isLoading);   const error = useUserStore(state =&gt; state.error);   return (    // ...  )}export default Login;</code></pre></li><li><p>使用 Formik 管理表单状态和处理提交：</p> <pre><code class="language-tsx">const formik = useFormik({   initialValues: {     username: '',     password: ''   },   validationSchema,   onSubmit: async (values) =&gt; {     try {       const { username, password } = values;       await login({ username, password });       navigate('/', {         state: {           message: '登陆成功！'         }       })     } catch (error) {       console.error('登录失败：', error);     }   } }); </code></pre></li><li><p>使用 Yup 进行表单验证，确保用户名和密码不为空：</p> <pre><code class="language-tsx">const validationSchema = Yup.object().shape({  username: Yup.string().required('请输入用户名！'),  password: Yup.string().required('请输入密码！')});</code></pre></li><li><p>以下是页面的基本结构：</p> <pre><code class="language-tsx">return (   &lt;AuthLayout&gt;     &lt;img src={logo} className="w-1/4 mx-auto" alt="Shopping Nest的Logo" /&gt;     &lt;h2 className="text-2xl font-bold text-center m-6 text-neutral-content"&gt;       登录用户     &lt;/h2&gt;     {error &amp;&amp; (       &lt;div className="mb-4 p-3 text-sm text-error-content bg-error rounded-lg"&gt;         {error}       &lt;/div&gt;     )}     &lt;form onSubmit={formik.handleSubmit}&gt;       &lt;div className="mb-4"&gt;         &lt;label className="block text-sm font-semibold text-neutral-content" htmlFor="username"&gt;           用户名         &lt;/label&gt;         &lt;input           type="text"           id="username"           name="username"           className={`w-full mt-2 p-2 border rounded-lg bg-base-300 ${             formik.touched.username &amp;&amp; formik.errors.username               ? "border-error"               : "border-neutral-600"           } text-base-content`}           value={formik.values.username}           onChange={formik.handleChange}           onBlur={formik.handleBlur}           disabled={isLoading}         /&gt;         {formik.touched.username &amp;&amp; formik.errors.username &amp;&amp; (           &lt;p className="text-sm text-error mt-1"&gt;{formik.errors.username}&lt;/p&gt;         )}       &lt;/div&gt;       &lt;div className="mb-4"&gt;         &lt;label className="block text-sm font-semibold text-neutral-content" htmlFor="password"&gt;           密码         &lt;/label&gt;         &lt;input           type="password"           id="password"           name="password"           className={`w-full mt-2 p-2 border rounded-lg bg-base-300 ${             formik.touched.password &amp;&amp; formik.errors.password               ? "border-error"               : "border-neutral-600"           } text-base-content`}           value={formik.values.password}           onChange={formik.handleChange}           onBlur={formik.handleBlur}           disabled={isLoading}         /&gt;         {formik.touched.password &amp;&amp; formik.errors.password &amp;&amp; (           &lt;p className="text-sm text-error mt-1"&gt;{formik.errors.password}&lt;/p&gt;         )}       &lt;/div&gt;       &lt;button         type="submit"         className="w-full bg-primary text-primary-content py-2 rounded-lg mt-4 hover:brightness-90 disabled:opacity-50"         disabled={isLoading}       &gt;         {isLoading ? "登录中…" : "登录"}       &lt;/button&gt;     &lt;/form&gt;   &lt;/AuthLayout&gt; ) </code></pre></li><li><p>在 <code>src/router.tsx</code> 中添加 <code>/login</code> 路由：</p> <pre><code class="language-tsx">import Login from './pages/Login';const router = createBrowserRouter([   {     path: '/login',     element: &lt;Login /&gt;   }]); </code></pre></li></ol><h1 id="3-配置-jwt-认证"><a class="markdownIt-Anchor" href="#3-配置-jwt-认证"></a> 3. 配置 JWT 认证</h1><p>在实现用户登录功能时，我们需要一个安全可靠的身份验证机制，以确保用户身份的真实性并保护系统的安全。</p><p>JWT（JSON Web Token）是一个开放标准，它提供了一种紧凑且自包含的方式，在各方之间安全地传输信息。</p><p>通过 JWT，我们可以生成安全的访问令牌、验证用户的身份和权限、保护需要认证的 API 端点，并在服务端对令牌的有效性进行校验。</p><p>要实现 JWT 认证机制，我们需要从多个方面入手：</p><ol><li>配置认证模块、JWT 模块的签名密钥以及相关选项</li><li>集成用户模块，以便进行用户身份验证</li><li>实现认证服务，该服务需要负责验证用户凭据、生成 JWT 令牌、处理令牌刷新以及检查令牌的有效性，确保认证流程的完整性和安全性</li><li>创建一个认证控制器，专门处理用户的登录请求，并返回认证结果和 JWT 令牌，确保前端能够正确接收和使用身份验证信息</li><li>实现 JWT 策略和守卫：从请求中提取 JWT 令牌，并验证其有效性，以此来保护系统中需要认证的路由，确保只有经过身份经验的用户才能访问受保护的资源</li></ol><h2 id="31-安装依赖"><a class="markdownIt-Anchor" href="#31-安装依赖"></a> 3.1. 安装依赖</h2><pre><code class="language-bash">yarn add @nestjs/jwt @nestjs/passport passport passport-jwtyarn add -D @types/passport-jwt</code></pre><h2 id="32-认证模块"><a class="markdownIt-Anchor" href="#32-认证模块"></a> 3.2. 认证模块</h2><p>在 <code>src</code> 目录下创建 <code>auth</code> 目录，并创建 <code>auth.module.ts</code>：</p><pre><code class="language-ts">import { Module } from '@nestjs/common';import { PassportModule } from '@nestjs/passport';import { JwtModule } from '@nestjs/jwt';import { ConfigService } from '@nestjs/config';import { AuthController } from './auth.controller';import { AuthService } from './auth.service';import { JwtStrategy } from './jwt.strategy';import { UsersModule } from '../users/users.module';@Module({  imports: [    PassportModule.register({      defaultStrategy: 'jwt'    }),    JwtModule.registerAsync({      inject: [ConfigService],      useFactory: async (configService: ConfigService) =&gt; ({        secret: configService.get&lt;string&gt;('JWT_SECRET'),        signOptions: {          audience: configService.get&lt;string&gt;('JWT_TOKEN_AUDIENCE'),          issuer: configService.get&lt;string&gt;('JWT_TOKEN_ISSUER'),          expiresIn: configService.get&lt;number&gt;('JWT_ACCESS_TOKEN_TTL')        }      })    }),    UsersModule  ],  controllers: [AuthController],  providers: [AuthService, JwtStrategy],  exports: [AuthService]})export class AuthModule {}</code></pre><h2 id="33-用户验证和令牌生成"><a class="markdownIt-Anchor" href="#33-用户验证和令牌生成"></a> 3.3. 用户验证和令牌生成</h2><p>创建 <code>auth.service.ts</code>：</p><pre><code class="language-ts">import { Injectable, UnauthorizedException } from '@nestjs/common';import { JwtService } from '@nestjs/jwt';import { ConfigService } from '@nestjs/config';import * as bcrypt from 'bcrypt';import { UsersService } from '../users/users.service';import { JWTPayload } from './interfaces/jwt-payload.interface';@Injectable()export class AuthService {  constructor(    private jwtService: JwtService,    private usersService: UsersService,    private configService: ConfigService  ) {}  // ...}</code></pre><ol><li><p>验证用户：</p> <pre><code class="language-ts">async validateUser(username: string, password: string) {  const user = await this.usersService.findUser({ username: username });  if (!user) {    throw new UnauthorizedException('用户名或密码错误');  }  if (!user.verified) {    throw new UnauthorizedException('请先验证邮箱后再登录');  }  const isPasswordValid = await bcrypt.compare(password, user.password);  if (!isPasswordValid) {    throw new UnauthorizedException('用户名或密码错误');  }  return user;}</code></pre></li><li><p>用户登录：</p> <pre><code class="language-ts">async login(user: any) {  const payload: JWTPayload = {    sub: user.sub,    username: user.username,    email: user.email,    role: user.role  };</code></pre><p>首先构建 JWT 载荷。</p><blockquote><p>JWT 基本上由三个部分组成，使用 <code>.</code> 分割：</p><pre><code class="language-plaintext">头.载荷.签名</code></pre><ol><li><p>头包含了令牌类型和使用的签名算法：</p> <pre><code class="language-json">{  "alg": "HS256",  // 使用的算法  "typ": "JWT"}</code></pre></li><li><p>载荷包含了我们存储的实际数据：</p> <pre><code class="language-json">{  "sub": "1234567890",  // 用户 ID  "username": "john_doe",  // 用户名  "email": "john@doe.com",  // 邮箱  "role": "user",  // 角色  "iat": 1516239022,       // 签发时间  "exp": 1516242622        // 过期时间}</code></pre></li><li><p>签名则使用密钥、对头和载荷进行签名：</p> <pre><code class="language-javascript">HMACSHA256(  base64UrlEncode(header) + "." +  base64UrlEncode(payload),  secret  )</code></pre></li></ol></blockquote> <pre><code class="language-ts">const accessToken = this.jwtService.sign(payload, {  // 令牌接收方  audience: this.configService.get&lt;string&gt;('JWT_TOKEN_AUDIENCE'),  // 令牌发行方  issuer: this.configService.get&lt;string&gt;('JWT_TOKEN_ISSUER'),  // 令牌有效期  expiresIn: this.configService.get&lt;number&gt;('JWT_ACCESS_TOKEN_TTL'),});</code></pre><p>使用 <code>JwtService</code> 生成签名令牌。</p> <pre><code class="language-ts">  return {    access_token: accessToken,    token_type: 'Bearer',    expires_in: this.configService.get&lt;number&gt;('JWT_ACCESS_TOKEN_TTL'),    user: {      id: user.id,      username: user.username,      email: user.email,      role: user.role,      verified: user.verified    }  };}</code></pre><p>这里说一下令牌类型 <code>Bearer</code>，它是 OAuth 2.0 的标准组成部分。</p></li><li><p>在令牌过期前更新令牌：</p> <pre><code class="language-ts">async refreshToken(user: any) {  const payload: JWTPayload = {    sub: user.id,    username: user.username,    email: user.email,    role: user.role  };  return {    access_token: this.jwtService.sign(payload)  };}</code></pre><p>当现有访问令牌即将过期时，服务器会生成一个新的访问令牌。</p><p>使用与原始登录相同的用户信息构建新的载荷，这样用户就不需要重新登陆，可以无缝继续使用系统。</p></li><li><p>验证令牌：</p> <pre><code class="language-ts">verifyToken(token: string) {  try {    return this.jwtService.verify(token);  } catch (error) {    throw new UnauthorizedException('无效的令牌，错误：', error);  }}</code></pre><p>这个方法负责验证传入的 JWT 令牌的有效性。</p><p><code>JwtService.verify()</code> 方法会检查令牌是否：</p><ul><li>签名有效（未被篡改）</li><li>未过期</li><li>是由我们的系统签发的</li></ul></li></ol><p>在 <code>auth</code> 目录下创建 <code>interfaces/jwt-payload.interface.ts</code> 文件，定义 JWT 载荷的 TypeScript 接口：</p><pre><code class="language-ts">export interface JWTPayload {  sub: number;  username: string;  email: string;  role: string;  iat?: number;  exp?: number;  aud?: string;  iss?: string;}</code></pre><h2 id="34-认证控制器"><a class="markdownIt-Anchor" href="#34-认证控制器"></a> 3.4. 认证控制器</h2><p>我们先来写一下登录所需要的 DTO。</p><ol><li><p>定义登录请求的数据结构：</p> <pre><code class="language-ts">import { ApiProperty } from '@nestjs/swagger';import { IsNotEmpty, IsString, MinLength } from 'class-validator';export class LoginDto {  @ApiProperty({ example: 'johndoe', description: '用户名' })  @IsString()  @IsNotEmpty({ message: '用户名不能为空' })  username: string;  @ApiProperty({ example: 'password123', description: '密码' })  @IsString()  @IsNotEmpty({ message: '密码不能为空' })  @MinLength(6, { message: '密码长度不能小于6位' })  password: string;}</code></pre></li><li><p>登录响应 DTO：</p> <pre><code class="language-ts">import { ApiProperty } from '@nestjs/swagger';export class LoginResponseDto {  @ApiProperty({ description: '访问令牌' })  access_token: string;  @ApiProperty({ description: '令牌类型', example: 'Bearer' })  token_type: string;  @ApiProperty({ description: '过期时间（秒）', example: 3600 })  expires_in: number;  @ApiProperty({    description: '用户信息',    example: {      id: '1',      username: 'johndoe',      email: 'john@example.com',      role: 'user',      verified: true    }  })  user: {    id: string;    username: string;    email: string;    role: string;    verified: boolean;  };}</code></pre></li></ol><p>创建 <code>auth.controller.ts</code>：</p><pre><code class="language-ts">import { Controller, Post, Body, HttpCode, HttpStatus, UnauthorizedException } from '@nestjs/common';import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';import { AuthService } from './auth.service';import { LoginDto } from './dto/login.dto';import { LoginResponseDto } from './dto/login-response.dto';import winstonLogger from '../loggers/winston.logger';@ApiTags('认证')@Controller('auth')export class AuthController {  private readonly logger = winstonLogger;  constructor(private readonly authService: AuthService) {}  @ApiOperation({ summary: '用户登录' })  @ApiResponse({    status: HttpStatus.OK,    description: '登录成功',    type: LoginResponseDto  })  @ApiResponse({    status: HttpStatus.UNAUTHORIZED,    description: '登录失败'  })  @HttpCode(HttpStatus.OK)  @Post('login')  async login(@Body() loginDto: LoginDto): Promise&lt;LoginResponseDto&gt; {    try {      const user = await this.authService.validateUser(loginDto.username, loginDto.password);      this.logger.debug(`用户 ${loginDto.username} 验证通过，正在生成令牌`);      const loginResult = await this.authService.login(user);      this.logger.info(`用户 ${loginDto.username} 登录成功`);      return loginResult;    } catch (error) {      this.logger.error(`用户 ${loginDto.username} 登录失败: ${error.message}`);      throw error;    }  }}</code></pre><h2 id="35-策略实现"><a class="markdownIt-Anchor" href="#35-策略实现"></a> 3.5. 策略实现</h2><p><code>AuthService.validateUser()</code> 方法仅是用于登录时的用户验证，以及生成初始的 JWT 令牌。</p><p>那后续请求该由谁来验证呢？</p><blockquote><p>可以想象成有这么一个商场。</p><p>你在前台登记（登录），工作人员会验证你的身份（<code>AuthService.validateUser()</code>），验证成功后给了你一个特殊的通行证（JWT 令牌）。</p><p>你在商场里遛弯，发现有一个 VIP 区域（访问受保护的 API），门口站一保安。你说你想进去，保安说别急先看看你的通行证（JWT 令牌）。</p><p>保安需要看到的是：</p><ul><li>这个通行证是不是商场发的（JWT 签名验证）</li><li>通行证有没有过期（JWT 过期检查）</li><li>你的会员资格是否还有效（接下来要写的方法）</li></ul><p>JWT 策略实现就是这个保安。</p></blockquote><p>创建 <code>jwt.strategy.ts</code>：</p><pre><code class="language-ts">import { Injectable, UnauthorizedException } from '@nestjs/common';import { PassportStrategy } from '@nestjs/passport';import { ConfigService } from '@nestjs/config';import { Strategy, ExtractJwt } from 'passport-jwt';import { UsersService } from '../users/users.service';@Injectable()export class JwtStrategy extends PassportStrategy(Strategy) {  constructor(    private configService: ConfigService,    private usersService: UsersService  ) {    super({      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),      ignoreExpiration: false,      secretOrKey: configService.get&lt;string&gt;('JWT_SECRET'),      audience: configService.get&lt;string&gt;('JWT_TOKEN_AUDIENCE'),      issuer: configService.get&lt;string&gt;('JWT_TOKEN_ISSUER')    });  }</code></pre><p>检查用户是否还是「有效会员」：</p><pre><code class="language-ts">  async validate(payload: any) {    const user = await this.usersService.findUser({ id: payload.sub });    if (!user) {      throw new UnauthorizedException('用户不存在');    }    if (!user.verified) {      throw new UnauthorizedException('用户未验证');    }    return {      id: user.id,      username: user.username,      email: user.email,      role: user.role    };  }}</code></pre><h2 id="36-jwt-守卫"><a class="markdownIt-Anchor" href="#36-jwt-守卫"></a> 3.6. JWT 守卫</h2><blockquote><p>先前的商场例子里，提到了「受保护的 API」。</p><p>那么要如何创建这么个「VIP 区域」呢？我们就需要用到 JWT 守卫。</p></blockquote><p>创建 <code>jwt-auth.guard.ts</code>：</p><pre><code class="language-ts">@Injectable()export class JwtAuthGuard extends AuthGuard('jwt') {  handleRequest(error: any, user: any, info: any) {    if (error || !user) {      throw new UnauthorizedException('验证失败');    }    return user;  }}</code></pre><p>守卫的工作流程：</p><ol><li>收到请求时，检查 <code>Authorization</code> 头部是否包含 JWT 令牌</li><li>如果没有令牌或令牌无效，直接拦截请求并返回 <code>401</code> 错误</li><li>如果令牌有效，让请求通过并继续处理</li></ol><p>使用方式也很简单：</p><pre><code class="language-ts">@Controller('orders')export class OrdersController {  constructor(private ordersService: OrdersService) {}  // 无需登录即可访问的公开 API  // 例如获取热门商品  @Get('popular')  getPopularOrders() {    return this.ordersService.getPopularOrders();  }  // 需要登录才能访问的 API  // 例如用户的订单  @UseGuards(JwtAuthGuard)  @Get('my-orders')  getMyOrders(@CurrentUser() user: any) {    return this.ordersService.getOrdersByUserId(user.id);  }  // 用户下单  @UseGuards(JwtAuthGuard)  @Post('create')  createOrder(@CurrentUser() user: any, @Body() orderData: any) {    return this.ordersService.createOrder(user.id, orderData);  }}</code></pre><p>也可以直接保护控制器的所有路由：</p><pre><code class="language-ts">@UseGuards(JwtAuthGuard)  // 保护个人信息路由@Controller('profile')export class ProfileController {  @Get()  getProfile(@CurrentUser() user: any) {    return user;  }  @Put()  updateProfile(@CurrentUser() user: any, @Body() updateData: any) {    return this.profileService.update(user.id, updateData);  }}</code></pre><h2 id="37-用户装饰器"><a class="markdownIt-Anchor" href="#37-用户装饰器"></a> 3.7. 用户装饰器</h2><p>假设我们有一个购物车的 API，需要获取当前用户的购物车信息：</p><pre><code class="language-ts">@Controller('cart')export class CartController {  constructor(private cartService: CartService) {}  @UseGuards(JwtAuthGuard)  @Get('my-cart')  async getMyCart(@CurrentUser() user: any) {    // user 对象包含了 JWT 令牌中的用户信息    return this.cartService.getCartByUserId(user.id);  }}</code></pre><p>如果没有 <code>CurrentUser</code> 装饰器，我们需要：</p><pre><code class="language-ts">@Get('my-cart')async getMyCart(@Request() req: any) {  const user = req.user;  // 从 request 对象中手动获取用户信息  return this.cartService.getCartByUserId(user.id);}</code></pre><p><code>CurrentUser</code> 装饰器的实现：</p><pre><code class="language-ts">import { createParamDecorator, ExecutionContext } from '@nestjs/common';export const CurrentUser = createParamDecorator((data: unknown, ctx: ExecutionContext) =&gt; {  const request = ctx.switchToHttp().getRequest();  return request.user;});</code></pre><p>它的好处在于：</p><ul><li>简化代码：不需要手动从 <code>request</code> 中提取用户信息</li><li>类型安全：可以明确知道返回的是用户对象</li><li>可重用性：在任何需要当前用户信息的地方都可以使用</li><li>关注点分离：控制器方法只需要关心用户信息，不需要关心它是如何获取的</li></ul><p>像是还可以有这样的使用场景：</p><pre><code class="language-ts">@Controller('users')export class UsersController {  @UseGuards(JwtAuthGuard)  @Get('profile')  getProfile(@CurrentUser() user: any) {    return user;  // 直接返回用户信息  }}</code></pre><h1 id="4-添加记住我功能"><a class="markdownIt-Anchor" href="#4-添加记住我功能"></a> 4. 添加记住我功能</h1><p>在现代电商平台中，用户体验是至关重要的。用户希望能够快速、便捷地访问他们的账户，而不需要每次都重新输入用户名和密码。这就是「记住我」功能的用武之地。</p><p>通过「记住我」功能，用户可以选择在登录时保持一段时间的登录状态，即使关闭浏览器或重新打开应用，用户仍然可以自动登录，无需再次输入凭证。</p><h2 id="41-技术方案设计"><a class="markdownIt-Anchor" href="#41-技术方案设计"></a> 4.1. 技术方案设计</h2><p>我们采用 <code>RefreshToken</code> + <code>AccessToken</code> 的双令牌认证方案：</p><ul><li><code>AccessToken</code>：短期令牌，用于访问 API</li><li><code>RefreshToken</code>：长期令牌，用于刷新 <code>AccessToken</code></li></ul><p>这种方案的优势在于：</p><ul><li>安全性高：<code>AccessToken</code> 短期有效，即使泄露风险也较小</li><li>用户体验好：<code>RefreshToken</code> 可以静默刷新 <code>AccessToken</code>，用户无感知</li><li>可控性强：可以随时注销 <code>RefreshToken</code>，确保账户安全</li></ul><pre class="mermaid-error">Mermaid render failed: Mermaid render timed out after 30s</pre><h2 id="42-环境配置"><a class="markdownIt-Anchor" href="#42-环境配置"></a> 4.2. 环境配置</h2><h4 id="421-修改环境变量"><a class="markdownIt-Anchor" href="#421-修改环境变量"></a> 4.2.1. 修改环境变量</h4><p>首先需要在 <code>.env</code> 文件中添加新的配置项：</p><pre><code class="language-plaintext"># JWT JWT_ACCESS_SECRET=access_secret JWT_REFRESH_SECRET=refresh_secret JWT_TOKEN_AUDIENCE=localhost:4000 JWT_TOKEN_ISSUER=localhost:4000 JWT_ACCESS_TOKEN_TTL=3600 JWT_REFRESH_TOKEN_TTL=604800</code></pre><p>配置说明：</p><ul><li><code>JWT_ACCESS_SECRET</code>：访问令牌密钥</li><li><code>JWT_REFRESH_SECRET</code>：刷新令牌密钥</li><li><code>JWT_ACCESS_TOKEN_TTL</code>：访问令牌有效期（1 小时）</li><li><code>JWT_REFRESH_TOKEN_TTL</code>：刷新令牌有效期（7 天）</li></ul><h4 id="422-更新配置验证"><a class="markdownIt-Anchor" href="#422-更新配置验证"></a> 4.2.2. 更新配置验证</h4><p>在 <code>AppModule</code> 中更新 <code>ConfigModule</code> 的配置验证：</p><pre><code class="language-ts">@Module({  imports: [    ConfigModule.forRoot({      validationSchema: Joi.object({        // ... 其他配置项 ...                // JWT 配置        JWT_ACCESS_SECRET: Joi.string().required(),        JWT_REFRESH_SECRET: Joi.string().required(),        JWT_TOKEN_AUDIENCE: Joi.string().required(),        JWT_TOKEN_ISSUER: Joi.string().required(),        JWT_ACCESS_TOKEN_TTL: Joi.number().default(3600),        JWT_REFRESH_TOKEN_TTL: Joi.number().default(604800)      })    })  ]})</code></pre><h4 id="423-更新认证模块"><a class="markdownIt-Anchor" href="#423-更新认证模块"></a> 4.2.3. 更新认证模块</h4><p>在 <code>AuthModule</code> 中更新 <code>JwtModule</code> 的配置：</p><pre><code class="language-ts">@Module({  imports: [    JwtModule.registerAsync({      inject: [ConfigService],      useFactory: async (configService: ConfigService) =&gt; ({        secret: configService.get&lt;string&gt;('JWT_ACCESS_SECRET'),        signOptions: {          audience: configService.get&lt;string&gt;('JWT_TOKEN_AUDIENCE'),          issuer: configService.get&lt;string&gt;('JWT_TOKEN_ISSUER'),          expiresIn: configService.get&lt;number&gt;('JWT_ACCESS_TOKEN_TTL')        }      })    })  ]})</code></pre><h4 id="424-更新-jwt-策略"><a class="markdownIt-Anchor" href="#424-更新-jwt-策略"></a> 4.2.4. 更新 JWT 策略</h4><p>修改 <code>JwtStrategy</code> 的配置：</p><pre><code class="language-ts">@Injectable()export class JwtStrategy extends PassportStrategy(Strategy) {  constructor(private configService: ConfigService) {    super({      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),      ignoreExpiration: false,      secretOrKey: configService.get&lt;string&gt;('JWT_ACCESS_SECRET'),      audience: configService.get&lt;string&gt;('JWT_TOKEN_AUDIENCE'),      issuer: configService.get&lt;string&gt;('JWT_TOKEN_ISSUER')    });  }}</code></pre><h2 id="43-令牌生成与签名实现"><a class="markdownIt-Anchor" href="#43-令牌生成与签名实现"></a> 4.3. 令牌生成与签名实现</h2><h4 id="431-jwt-配置抽离"><a class="markdownIt-Anchor" href="#431-jwt-配置抽离"></a> 4.3.1. JWT 配置抽离</h4><p>为了更好地管理 JWT 相关的配置，我们首先创建了一个专门的配置文件 <code>jwt.config.ts</code>：</p><pre><code class="language-ts">import { ConfigService } from '@nestjs/config';export const getJWTVerifyOptions = (configService: ConfigService) =&gt; ({  accessToken: {    secret: configService.get('JWT_ACCESS_SECRET'),    audience: configService.get('JWT_TOKEN_AUDIENCE'),    issuer: configService.get('JWT_TOKEN_ISSUER'),    expiresIn: configService.get('JWT_ACCESS_TOKEN_TTL')  },  refreshToken: {    secret: configService.get('JWT_REFRESH_SECRET'),    audience: configService.get('JWT_TOKEN_AUDIENCE'),    issuer: configService.get('JWT_TOKEN_ISSUER'),    expiresIn: configService.get('JWT_REFRESH_TOKEN_TTL')  }});</code></pre><p>这样做的好处是：</p><ul><li>集中管理 JWT 配置</li><li>方便在不同地方复用配置</li><li>确保配置的一致性</li></ul><h4 id="432-数据结构调整"><a class="markdownIt-Anchor" href="#432-数据结构调整"></a> 4.3.2. 数据结构调整</h4><ol><li><p>在 <code>Users</code> 实体中添加 <code>refreshToken</code> 字段，用于存储刷新令牌：</p> <pre><code class="language-ts">@Column({ nullable: true })refreshToken?: string;</code></pre></li><li><p>在 <code>LoginDto</code> 中添加「记住我」选项：</p> <pre><code class="language-ts">@ApiProperty({ example: false, required: false, description: '是否记住我' })@IsBoolean()@IsOptional()rememberMe?: boolean;</code></pre></li><li><p>在 <code>LoginResponseDto</code> 中新增刷新令牌字段：</p> <pre><code class="language-ts">@ApiProperty({ description: '刷新令牌' })refresh_token: string;</code></pre></li></ol><h4 id="433-认证服务实现"><a class="markdownIt-Anchor" href="#433-认证服务实现"></a> 4.3.3. 认证服务实现</h4><p>在 <code>AuthService</code> 中，我们需要进行以下主要改动：</p><ol><li><p>为了支持「记住我」功能，需要在用户登录时生成两种令牌：访问令牌（<code>accessToken</code>）和刷新令牌（<code>refreshToken</code>）。</p><ol><li><p>将原有的令牌生成逻辑修改为：</p> <pre><code class="language-ts">// 之前的代码const accessToken = this.jwtService.sign(payload, {  audience: this.configService.get&lt;string&gt;('JWT_TOKEN_AUDIENCE'),  issuer: this.configService.get&lt;string&gt;('JWT_TOKEN_ISSUER'),  expiresIn: this.configService.get&lt;number&gt;('JWT_ACCESS_TOKEN_TTL')});// 修改后的代码const accessToken = this.jwtService.sign(payload);const refreshToken = this.jwtService.sign(  payload,   getJWTVerifyOptions(this.configService).refreshToken);</code></pre></li><li><p>在登录响应中添加刷新令牌：</p> <pre><code class="language-ts">// 之前的返回结果return {  access_token: accessToken,  token_type: 'Bearer',  expires_in: this.configService.get&lt;number&gt;('JWT_ACCESS_TOKEN_TTL'),  user: { ... }};// 修改后的返回结果return {  access_token: accessToken,  refresh_token: refreshToken,  // 新增  token_type: 'Bearer',  expires_in: this.configService.get&lt;number&gt;('JWT_ACCESS_TOKEN_TTL'),  user: { ... }};</code></pre></li></ol></li><li><p>新增令牌刷新功能，用于在访问令牌过期后获取新的访问令牌：</p> <pre><code class="language-ts">async refresh(refreshToken: string) {  this.logger.debug(`刷新访问令牌`);  // 验证刷新令牌  const refreshPayload = this.jwtService.verify(    refreshToken,     getJWTVerifyOptions(this.configService).refreshToken  );    // 查找用户  const user = await this.usersService.findUser({ id: refreshPayload.sub });  if (!user) {    this.logger.warn(`刷新失败，未找到用户：${user.username}`);    throw new UnauthorizedException('用户不存在');  }  // 生成新的访问令牌  const newAccessToken = this.jwtService.sign(    {      sub: user.id,      username: user.username,      email: user.email,      role: user.role    },    getJWTVerifyOptions(this.configService).accessToken  );  this.logger.info(`已为用户刷新访问令牌：${user.username}`);  return {    access_token: newAccessToken,    token_type: 'Bearer',    expires_in: this.configService.get&lt;number&gt;('JWT_REFRESH_TOKEN_TTL')  };}</code></pre></li><li><p>添加登出功能，用于清除用户的刷新令牌：</p> <pre><code class="language-ts">async logout(userId: string): Promise&lt;void&gt; {  await this.usersService.update(userId, { refreshToken: null });}</code></pre></li></ol><h4 id="434-控制器层改造"><a class="markdownIt-Anchor" href="#434-控制器层改造"></a> 4.3.4. 控制器层改造</h4><p>在 <code>AuthController</code> 中，我们需要添加新的接口来支持「记住我」功能：</p><pre><code class="language-ts">@ApiOperation({ summary: '刷新访问令牌' })@UseGuards(JwtRefreshGuard)@HttpCode(HttpStatus.OK)@Post('refresh')async refresh(@Body() body: { refreshToken: string }) {  try {    return await this.authService.refresh(body.refreshToken);  } catch (error) {    this.logger.error(`刷新 Token 失败：${error.message}`);    throw new UnauthorizedException('刷新 Token 失败');  }}</code></pre><p>同时添加获取当前用户信息和登出的接口：</p><pre><code class="language-ts">@ApiOperation({ summary: '获取当前用户信息' })@HttpCode(HttpStatus.OK)@Get('me')async getCurrentUser(@CurrentUser() user: JWTPayload) {  return this.authService.getCurrentUser(user.sub);}@ApiOperation({ summary: '登出用户' })@HttpCode(HttpStatus.OK)@UseGuards(JwtAuthGuard)@Post('logout')async logout(@Req() req: Request) {  const user = req.user as JWTPayload;  await this.authService.logout(user.sub);  return { message: '已登出' };}</code></pre><h4 id="435-守卫机制完善"><a class="markdownIt-Anchor" href="#435-守卫机制完善"></a> 4.3.5. 守卫机制完善</h4><ol><li><p>访问令牌守卫</p><p>原来的 <code>JwtAuthGuard</code> 实现存在几个问题：</p><ul><li>没有直接验证 <code>token</code> 的有效性</li><li>没有正确处理 <code>audience</code> 和 <code>issuer</code> 的验证</li></ul><p>看一眼原本的代码：</p> <pre><code class="language-ts">@Injectable()export class JwtAuthGuard extends AuthGuard('jwt') {  handleRequest(error: any, user: any, info: any) {    if (error || !user) {      throw new UnauthorizedException('验证失败');    }    return user;  }}</code></pre><p>现在，我们重新实现了这个守卫，提供了更严格的验证和更好的错误处理：</p> <pre><code class="language-ts">import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';import { JwtService } from '@nestjs/jwt';import { ConfigService } from '@nestjs/config';import { TokenUtils } from '../utils/token.utils';import winstonLogger from '../../loggers/winston.logger';@Injectable()export class JwtAuthGuard implements CanActivate {  private logger = winstonLogger;  constructor(    private jwtService: JwtService,    private configService: ConfigService  ) {}  async canActivate(context: ExecutionContext): Promise&lt;boolean&gt; {    const token = TokenUtils.extractTokenFromContext(context);    if (!token) {      this.logger.warn(`未提供访问令牌：${context}`);      throw new UnauthorizedException('未提供访问令牌');    }    try {      const request = context.switchToHttp().getRequest();      request.user = await this.jwtService.verifyAsync(token, {        audience: this.configService.get&lt;string&gt;('JWT_TOKEN_AUDIENCE'),        issuer: this.configService.get&lt;string&gt;('JWT_TOKEN_ISSUER')      });      return true;    } catch (error) {      this.logger.error(`验证访问令牌失败：${error.message}`, error.stack);      throw new UnauthorizedException('无效的访问令牌');    }  }}</code></pre></li><li><p>刷新令牌守卫</p><p>新增 <code>JwtRefreshGuard</code> 专门用于处理刷新令牌的验证：</p> <pre><code class="language-ts">import { ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';import { ConfigService } from '@nestjs/config';import { JwtService } from '@nestjs/jwt';import { TokenUtils } from '../utils/token.utils';import { getJWTVerifyOptions } from '../../config/jwt.config';import winstonLogger from '../../loggers/winston.logger';@Injectable()export class JwtRefreshGuard {  private logger = winstonLogger;  constructor(    private jwtService: JwtService,    private configService: ConfigService  ) {}  async canActivate(context: ExecutionContext) {    const token = TokenUtils.extractTokenFromContext(context);    const options = getJWTVerifyOptions(this.configService).refreshToken;    try {      this.jwtService.verify(token, options);      return true;    } catch (error) {      this.logger.error(`验证刷新令牌失败：${error.message}`, error.stack);      throw new UnauthorizedException('无效的刷新令牌');    }  }}</code></pre></li></ol><h4 id="436-工具类支持"><a class="markdownIt-Anchor" href="#436-工具类支持"></a> 4.3.6. 工具类支持</h4><p>在之前的实现中，令牌提取的逻辑分散在各处，容易导致处理不一致。为了统一处理令牌的提取逻辑，新增 <code>TokenUtils</code> 工具类：</p><pre><code class="language-ts">import { ExecutionContext } from '@nestjs/common';import { Request } from 'express';export class TokenUtils {  static extractToken(request: Request): string | undefined {    const [type, token] = request.headers.authorization?.split(' ') ?? [];    return type === 'Bearer' ? token : undefined;  }  static extractTokenFromContext(context: ExecutionContext): string | undefined {    const request = context.switchToHttp().getRequest&lt;Request&gt;();    return this.extractToken(request);  }}</code></pre><h2 id="44-客户端功能实现"><a class="markdownIt-Anchor" href="#44-客户端功能实现"></a> 4.4. 客户端功能实现</h2><h4 id="441-api-请求封装"><a class="markdownIt-Anchor" href="#441-api-请求封装"></a> 4.4.1. API 请求封装</h4><p>在用户登录后，我们需要确保所有 API 请求都能正确携带身份验证信息。然而，<code>accessToken</code> 可能会过期，如果没有自动刷新机制，用户将频繁被登出，影响体验。我们希望实现一个自动处理令牌的方案，使得：</p><ul><li>每个请求都自动携带 <code>accessToken</code> 进行身份验证。</li><li>当 <code>accessToken</code> 过期时，自动使用 <code>refreshToken</code> 获取新的 <code>accessToken</code>，并重试原请求。</li><li>如果 <code>refreshToken</code> 也失效，则清除令牌并让用户重新登录。</li></ul><p>我们使用 Axios 拦截器 来实现这一机制，主要分为两部分：</p><ol><li><p>请求拦截器：</p><ul><li>在每个请求发送前，自动读取 <code>accessToken</code>，并将其添加到请求头。</li><li>如果 <code>accessToken</code> 不存在，则直接发送请求。</li></ul></li><li><p>响应拦截器：</p><ul><li>监听 API 响应，如果返回 <code>401 Unauthorized</code>，说明 <code>accessToken</code> 可能已过期。</li><li>如果 <code>refreshToken</code> 仍然有效，则使用它请求新的 <code>accessToken</code>，然后重试原始请求。</li><li>如果 <code>refreshToken</code> 失效，则清除所有令牌，并要求用户重新登录。</li></ul></li></ol><p>这是客户端请求与响应拦截逻辑的流程：</p><svg aria-roledescription="flowchart-v2" role="graphics-document document" viewBox="-7.5 -8 497.21875 266.0390625" style="max-width: 497.21875px;" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="100%" id="mermaid-1789678110247"><style>#mermaid-1789678110247{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-1789678110247 .error-icon{fill:#552222;}#mermaid-1789678110247 .error-text{fill:#552222;stroke:#552222;}#mermaid-1789678110247 .edge-thickness-normal{stroke-width:2px;}#mermaid-1789678110247 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-1789678110247 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-1789678110247 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-1789678110247 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-1789678110247 .marker{fill:#333333;stroke:#333333;}#mermaid-1789678110247 .marker.cross{stroke:#333333;}#mermaid-1789678110247 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-1789678110247 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-1789678110247 .cluster-label text{fill:#333;}#mermaid-1789678110247 .cluster-label span,#mermaid-1789678110247 p{color:#333;}#mermaid-1789678110247 .label text,#mermaid-1789678110247 span,#mermaid-1789678110247 p{fill:#333;color:#333;}#mermaid-1789678110247 .node rect,#mermaid-1789678110247 .node circle,#mermaid-1789678110247 .node ellipse,#mermaid-1789678110247 .node polygon,#mermaid-1789678110247 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-1789678110247 .flowchart-label text{text-anchor:middle;}#mermaid-1789678110247 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-1789678110247 .node .label{text-align:center;}#mermaid-1789678110247 .node.clickable{cursor:pointer;}#mermaid-1789678110247 .arrowheadPath{fill:#333333;}#mermaid-1789678110247 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-1789678110247 .flowchart-link{stroke:#333333;fill:none;}#mermaid-1789678110247 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-1789678110247 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-1789678110247 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-1789678110247 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-1789678110247 .cluster text{fill:#333;}#mermaid-1789678110247 .cluster span,#mermaid-1789678110247 p{color:#333;}#mermaid-1789678110247 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-1789678110247 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-1789678110247 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker orient="auto" markerHeight="12" markerWidth="12" markerUnits="userSpaceOnUse" refY="5" refX="6" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678110247_flowchart-pointEnd"><path style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 0 0 L 10 5 L 0 10 z"></path></marker><marker orient="auto" markerHeight="12" markerWidth="12" markerUnits="userSpaceOnUse" refY="5" refX="4.5" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678110247_flowchart-pointStart"><path style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 0 5 L 10 10 L 10 0 z"></path></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5" refX="11" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678110247_flowchart-circleEnd"><circle style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" r="5" cy="5" cx="5"></circle></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5" refX="-1" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678110247_flowchart-circleStart"><circle style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" r="5" cy="5" cx="5"></circle></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5.2" refX="12" viewBox="0 0 11 11" class="marker cross flowchart" id="mermaid-1789678110247_flowchart-crossEnd"><path style="stroke-width: 2; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 1,1 l 9,9 M 10,1 l -9,9"></path></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5.2" refX="-1" viewBox="0 0 11 11" class="marker cross flowchart" id="mermaid-1789678110247_flowchart-crossStart"><path style="stroke-width: 2; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 1,1 l 9,9 M 10,1 l -9,9"></path></marker><g class="root"><g class="clusters"></g><g class="edgePaths"></g><g class="edgeLabels"></g><g class="nodes"><g transform="translate(-7.5, -8)" class="root"><g class="clusters"><g id="请求拦截" class="cluster default flowchart-label"><rect height="250.0390625" width="481.21875" y="8" x="8" ry="0" rx="0" style=""></rect><g transform="translate(236.921875, 8)" class="cluster-label"><foreignObject height="18" width="23.375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">请求拦截</span></div></foreignObject></g></g></g><g class="edgePaths"><path marker-end="url(#mermaid-1789678110247_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-A LE-B" id="L-A-B-0" d="M71.375,133.02L75.542,133.02C79.708,133.02,88.042,133.02,95.575,133.086C103.109,133.152,109.842,133.284,113.209,133.35L116.576,133.416"></path><path marker-end="url(#mermaid-1789678110247_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-B LE-C" id="L-B-C-0" d="M260.665,111.231L268.95,107.946C277.235,104.661,293.805,98.09,305.86,94.805C317.916,91.52,325.456,91.52,329.227,91.52L332.997,91.52"></path><path marker-end="url(#mermaid-1789678110247_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-B LE-D" id="L-B-D-0" d="M260.665,155.808L268.95,158.926C277.235,162.045,293.805,168.282,313.156,171.401C332.507,174.52,354.639,174.52,365.704,174.52L376.77,174.52"></path></g><g class="edgeLabels"><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g transform="translate(310.375, 91.51953125)" class="edgeLabel"><g transform="translate(-2.921875, -9)" class="label"><foreignObject height="18" width="5.84375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">是</span></div></foreignObject></g></g><g transform="translate(310.375, 174.51953125)" class="edgeLabel"><g transform="translate(-2.921875, -9)" class="label"><foreignObject height="18" width="5.84375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">否</span></div></foreignObject></g></g></g><g class="nodes"><g transform="translate(201.9140625, 133.01953125)" data-id="B" data-node="true" id="flowchart-B-1" class="node default default flowchart-label"><polygon style="" transform="translate(-80.5390625,80.5390625)" class="label-container" points="80.5390625,0 161.078125,-80.5390625 80.5390625,-161.078125 0,-80.5390625"></polygon><g transform="translate(-56.5390625, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="113.078125"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">存在 accessToken?</span></div></foreignObject></g></g><g transform="translate(52.1875, 133.01953125)" data-id="A" data-node="true" id="flowchart-A-0" class="node default default flowchart-label"><rect height="33" width="38.375" y="-16.5" x="-19.1875" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-11.6875, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="23.375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">发起请求</span></div></foreignObject></g></g><g transform="translate(401.2578125, 91.51953125)" data-id="C" data-node="true" id="flowchart-C-3" class="node default default flowchart-label"><rect height="33" width="125.921875" y="-16.5" x="-62.9609375" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-55.4609375, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="110.921875"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">添加 Authorization 头</span></div></foreignObject></g></g><g transform="translate(401.2578125, 174.51953125)" data-id="D" data-node="true" id="flowchart-D-5" class="node default default flowchart-label"><rect height="33" width="38.375" y="-16.5" x="-19.1875" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-11.6875, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="23.375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">直接发送</span></div></foreignObject></g></g></g></g></g></g></g></svg><svg aria-roledescription="flowchart-v2" role="graphics-document document" viewBox="-7.5 -8 910.515625 369.61328125" style="max-width: 910.515625px;" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="100%" id="mermaid-1789678112108"><style>#mermaid-1789678112108{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-1789678112108 .error-icon{fill:#552222;}#mermaid-1789678112108 .error-text{fill:#552222;stroke:#552222;}#mermaid-1789678112108 .edge-thickness-normal{stroke-width:2px;}#mermaid-1789678112108 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-1789678112108 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-1789678112108 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-1789678112108 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-1789678112108 .marker{fill:#333333;stroke:#333333;}#mermaid-1789678112108 .marker.cross{stroke:#333333;}#mermaid-1789678112108 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-1789678112108 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-1789678112108 .cluster-label text{fill:#333;}#mermaid-1789678112108 .cluster-label span,#mermaid-1789678112108 p{color:#333;}#mermaid-1789678112108 .label text,#mermaid-1789678112108 span,#mermaid-1789678112108 p{fill:#333;color:#333;}#mermaid-1789678112108 .node rect,#mermaid-1789678112108 .node circle,#mermaid-1789678112108 .node ellipse,#mermaid-1789678112108 .node polygon,#mermaid-1789678112108 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-1789678112108 .flowchart-label text{text-anchor:middle;}#mermaid-1789678112108 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-1789678112108 .node .label{text-align:center;}#mermaid-1789678112108 .node.clickable{cursor:pointer;}#mermaid-1789678112108 .arrowheadPath{fill:#333333;}#mermaid-1789678112108 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-1789678112108 .flowchart-link{stroke:#333333;fill:none;}#mermaid-1789678112108 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-1789678112108 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-1789678112108 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-1789678112108 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-1789678112108 .cluster text{fill:#333;}#mermaid-1789678112108 .cluster span,#mermaid-1789678112108 p{color:#333;}#mermaid-1789678112108 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-1789678112108 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-1789678112108 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker orient="auto" markerHeight="12" markerWidth="12" markerUnits="userSpaceOnUse" refY="5" refX="6" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678112108_flowchart-pointEnd"><path style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 0 0 L 10 5 L 0 10 z"></path></marker><marker orient="auto" markerHeight="12" markerWidth="12" markerUnits="userSpaceOnUse" refY="5" refX="4.5" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678112108_flowchart-pointStart"><path style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 0 5 L 10 10 L 10 0 z"></path></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5" refX="11" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678112108_flowchart-circleEnd"><circle style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" r="5" cy="5" cx="5"></circle></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5" refX="-1" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678112108_flowchart-circleStart"><circle style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" r="5" cy="5" cx="5"></circle></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5.2" refX="12" viewBox="0 0 11 11" class="marker cross flowchart" id="mermaid-1789678112108_flowchart-crossEnd"><path style="stroke-width: 2; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 1,1 l 9,9 M 10,1 l -9,9"></path></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5.2" refX="-1" viewBox="0 0 11 11" class="marker cross flowchart" id="mermaid-1789678112108_flowchart-crossStart"><path style="stroke-width: 2; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 1,1 l 9,9 M 10,1 l -9,9"></path></marker><g class="root"><g class="clusters"></g><g class="edgePaths"></g><g class="edgeLabels"></g><g class="nodes"><g transform="translate(-7.5, -8)" class="root"><g class="clusters"><g id="响应拦截" class="cluster default flowchart-label"><rect height="353.61328125" width="894.515625" y="8" x="8" ry="0" rx="0" style=""></rect><g transform="translate(443.5703125, 8)" class="cluster-label"><foreignObject height="18" width="23.375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">响应拦截</span></div></foreignObject></g></g></g><g class="edgePaths"><path marker-end="url(#mermaid-1789678112108_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-E LE-F" id="L-E-F-0" d="M71.375,218.688L75.542,218.688C79.708,218.688,88.042,218.688,95.575,218.754C103.109,218.82,109.842,218.952,113.209,219.018L116.576,219.084"></path><path marker-end="url(#mermaid-1789678112108_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-F LE-G" id="L-F-G-0" d="M206.701,193.545L215.545,185.726C224.389,177.906,242.077,162.268,254.775,154.516C267.473,146.764,275.181,146.9,279.035,146.968L282.888,147.036"></path><path marker-end="url(#mermaid-1789678112108_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-G LE-H" id="L-G-H-0" d="M423.045,126.752L431.012,123.803C438.978,120.854,454.911,114.956,466.648,112.008C478.384,109.059,485.925,109.059,489.695,109.059L493.466,109.059"></path><path marker-end="url(#mermaid-1789678112108_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-H LE-I" id="L-H-I-0" d="M548.828,109.059L553.482,109.059C558.135,109.059,567.443,109.059,575.95,109.126C584.458,109.194,592.165,109.33,596.019,109.398L599.873,109.465"></path><path marker-end="url(#mermaid-1789678112108_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-I LE-J" id="L-I-J-0" d="M676.693,100.799L682.723,99.009C688.754,97.219,700.814,93.639,710.615,91.849C720.416,90.059,727.956,90.059,731.727,90.059L735.497,90.059"></path><path marker-end="url(#mermaid-1789678112108_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-I LE-K" id="L-I-K-0" d="M665.273,129.738L673.207,137.76C681.141,145.781,697.008,161.824,716.48,174.348C735.953,186.873,759.031,195.878,770.57,200.381L782.109,204.883"></path><path marker-end="url(#mermaid-1789678112108_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-G LE-K" id="L-G-K-0" d="M409.182,181.369L419.459,189.464C429.736,197.559,450.29,213.748,469.392,221.843C488.495,229.938,506.146,229.938,523.797,229.938C541.448,229.938,559.099,229.938,579.268,229.938C599.438,229.938,622.125,229.938,644.813,229.938C667.5,229.938,690.188,229.938,713.02,228.207C735.852,226.477,758.829,223.017,770.317,221.287L781.806,219.556"></path><path marker-end="url(#mermaid-1789678112108_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-F LE-L" id="L-F-L-0" d="M206.701,244.83L215.545,252.483C224.389,260.135,242.077,275.441,264.43,283.093C286.783,290.746,313.8,290.746,327.309,290.746L340.817,290.746"></path></g><g class="edgeLabels"><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g transform="translate(259.765625, 146.62890625)" class="edgeLabel"><g transform="translate(-2.921875, -9)" class="label"><foreignObject height="18" width="5.84375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">是</span></div></foreignObject></g></g><g transform="translate(470.84375, 109.05859375)" class="edgeLabel"><g transform="translate(-2.921875, -9)" class="label"><foreignObject height="18" width="5.84375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">是</span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g transform="translate(712.875, 90.05859375)" class="edgeLabel"><g transform="translate(-2.921875, -9)" class="label"><foreignObject height="18" width="5.84375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">是</span></div></foreignObject></g></g><g transform="translate(712.875, 177.8671875)" class="edgeLabel"><g transform="translate(-2.921875, -9)" class="label"><foreignObject height="18" width="5.84375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">否</span></div></foreignObject></g></g><g transform="translate(576.75, 229.9375)" class="edgeLabel"><g transform="translate(-2.921875, -9)" class="label"><foreignObject height="18" width="5.84375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">否</span></div></foreignObject></g></g><g transform="translate(259.765625, 290.74609375)" class="edgeLabel"><g transform="translate(-2.921875, -9)" class="label"><foreignObject height="18" width="5.84375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">否</span></div></foreignObject></g></g></g><g class="nodes"><g transform="translate(176.609375, 218.6875)" data-id="F" data-node="true" id="flowchart-F-1" class="node default default flowchart-label"><polygon style="" transform="translate(-55.234375,55.234375)" class="label-container" points="55.234375,0 110.46875,-55.234375 55.234375,-110.46875 0,-55.234375"></polygon><g transform="translate(-31.234375, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="62.46875"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">状态码 = 401?</span></div></foreignObject></g></g><g transform="translate(52.1875, 218.6875)" data-id="E" data-node="true" id="flowchart-E-0" class="node default default flowchart-label"><rect height="33" width="38.375" y="-16.5" x="-19.1875" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-11.6875, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="23.375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">接收响应</span></div></foreignObject></g></g><g transform="translate(365.3046875, 146.62890625)" data-id="G" data-node="true" id="flowchart-G-3" class="node default default flowchart-label"><polygon style="" transform="translate(-77.6171875,77.6171875)" class="label-container" points="77.6171875,0 155.234375,-77.6171875 77.6171875,-155.234375 0,-77.6171875"></polygon><g transform="translate(-53.6171875, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="107.234375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">有 refreshToken?</span></div></foreignObject></g></g><g transform="translate(523.796875, 109.05859375)" data-id="H" data-node="true" id="flowchart-H-5" class="node default default flowchart-label"><rect height="33" width="50.0625" y="-16.5" x="-25.03125" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-17.53125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">发起刷新请求</span></div></foreignObject></g></g><g transform="translate(644.8125, 109.05859375)" data-id="I" data-node="true" id="flowchart-I-7" class="node default default flowchart-label"><polygon style="" transform="translate(-40.140625,40.140625)" class="label-container" points="40.140625,0 80.28125,-40.140625 40.140625,-80.28125 0,-40.140625"></polygon><g transform="translate(-16.140625, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="32.28125"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">刷新成功？</span></div></foreignObject></g></g><g transform="translate(809.15625, 90.05859375)" data-id="J" data-node="true" id="flowchart-J-9" class="node default default flowchart-label"><rect height="33" width="136.71875" y="-16.5" x="-68.359375" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-60.859375, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="121.71875"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">更新 accessToken 并重试</span></div></foreignObject></g></g><g transform="translate(809.15625, 215.4375)" data-id="K" data-node="true" id="flowchart-K-11" class="node default default flowchart-label"><rect height="33" width="44.21875" y="-16.5" x="-22.109375" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-14.609375, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="29.21875"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">跳转登录页</span></div></foreignObject></g></g><g transform="translate(365.3046875, 290.74609375)" data-id="L" data-node="true" id="flowchart-L-15" class="node default default flowchart-label"><rect height="33" width="38.375" y="-16.5" x="-19.1875" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-11.6875, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="23.375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">正常处理</span></div></foreignObject></g></g></g></g></g></g></g></svg><pre><code class="language-ts">const api = axios.create({  baseURL: process.env.REACT_APP_API_URL,  withCredentials: true,  timeout: 10000});// 请求拦截器：添加令牌api.interceptors.request.use(  (config) =&gt; {    const token = localStorage.getItem('accessToken');    if (token) {      config.headers = AxiosHeaders.from(config.headers);      config.headers.set('Authorization', `Bearer ${token}`);    }    return config;  },  (error) =&gt; Promise.reject(error));// 响应拦截器：处理令牌刷新api.interceptors.response.use(  (response) =&gt; response,  async (error) =&gt; {    const originalRequest = error.config;    // 处理 401 错误和令牌刷新    if (error.response?.status === 401 &amp;&amp; !originalRequest._retry) {      originalRequest._retry = true;      const refreshToken = localStorage.getItem('refreshToken');            if (refreshToken) {        try {          const { data } = await axios.post(            `${process.env.REACT_APP_API_URL}/auth/refresh`,            { refreshToken }          );          const newAccessToken = data.access_token;          localStorage.setItem('accessToken', newAccessToken);          originalRequest.headers.Authorization = `Bearer ${newAccessToken}`;          return api(originalRequest);        } catch (error) {          // 刷新失败时清除所有令牌          localStorage.removeItem('accessToken');          localStorage.removeItem('refreshToken');          return Promise.reject(error);        }      }    }    return Promise.reject(error);  });</code></pre><p>这个改造实现了对身份验证流程的优化和自动化：</p><ol><li>能够自动为请求添加访问令牌，确保每次请求都具备正确的身份验证信息。</li><li>能够检测令牌是否过期，并在必要时进行处理，防止因过期导致请求失败。</li><li>支持自动刷新令牌，并在刷新成功后重新尝试原始请求，从而提高用户体验，减少因身份验证失效带来的干扰。</li></ol><h4 id="442-状态管理优化"><a class="markdownIt-Anchor" href="#442-状态管理优化"></a> 4.4.2. 状态管理优化</h4><p>首先先介绍一下身份验证流程中整个认证状态的流转：</p><svg aria-roledescription="stateDiagram" role="graphics-document document" viewBox="0 0 281.8671875 416" style="max-width: 281.8671875px;" class="statediagram" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="100%" id="mermaid-1789678114396"><style>#mermaid-1789678114396{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-1789678114396 .error-icon{fill:#552222;}#mermaid-1789678114396 .error-text{fill:#552222;stroke:#552222;}#mermaid-1789678114396 .edge-thickness-normal{stroke-width:2px;}#mermaid-1789678114396 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-1789678114396 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-1789678114396 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-1789678114396 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-1789678114396 .marker{fill:#333333;stroke:#333333;}#mermaid-1789678114396 .marker.cross{stroke:#333333;}#mermaid-1789678114396 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-1789678114396 defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-1789678114396 g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-1789678114396 g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-1789678114396 g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-1789678114396 g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-1789678114396 g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-1789678114396 .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-1789678114396 .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-1789678114396 .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-1789678114396 .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-1789678114396 .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-1789678114396 .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-1789678114396 .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-1789678114396 .edgeLabel .label text{fill:#333;}#mermaid-1789678114396 .label div .edgeLabel{color:#333;}#mermaid-1789678114396 .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-1789678114396 .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-1789678114396 .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-1789678114396 .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-1789678114396 .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-1789678114396 .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-1789678114396 .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-1789678114396 #statediagram-barbEnd{fill:#333333;}#mermaid-1789678114396 .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-1789678114396 .cluster-label,#mermaid-1789678114396 .nodeLabel{color:#131300;}#mermaid-1789678114396 .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-1789678114396 .statediagram-state .divider{stroke:#9370DB;}#mermaid-1789678114396 .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-1789678114396 .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-1789678114396 .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-1789678114396 .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-1789678114396 .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-1789678114396 .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-1789678114396 .note-edge{stroke-dasharray:5;}#mermaid-1789678114396 .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-1789678114396 .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-1789678114396 .statediagram-note text{fill:black;}#mermaid-1789678114396 .statediagram-note .nodeLabel{color:black;}#mermaid-1789678114396 .statediagram .edgeLabel{color:red;}#mermaid-1789678114396 #dependencyStart,#mermaid-1789678114396 #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-1789678114396 .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-1789678114396 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><defs><marker orient="auto" markerUnits="strokeWidth" markerHeight="14" markerWidth="20" refY="7" refX="19" id="mermaid-1789678114396_statediagram-barbEnd"><path d="M 19,7 L9,13 L14,7 L9,1 Z"></path></marker></defs><g class="root"><g class="clusters"></g><g class="edgePaths"><path marker-end="url(#mermaid-1789678114396_statediagram-barbEnd)" style="fill:none" class="edge-thickness-normal transition" id="edge0" d="M145.828,22L145.828,26.167C145.828,30.333,145.828,38.667,145.828,47C145.828,55.333,145.828,63.667,145.828,67.833L145.828,72"></path><path marker-end="url(#mermaid-1789678114396_statediagram-barbEnd)" style="fill:none" class="edge-thickness-normal transition" id="edge1" d="M136.839,105L133.752,110.667C130.665,116.333,124.491,127.667,124.491,139C124.491,150.333,130.665,161.667,133.752,167.333L136.839,173"></path><path marker-end="url(#mermaid-1789678114396_statediagram-barbEnd)" style="fill:none" class="edge-thickness-normal transition" id="edge2" d="M145.828,206L145.828,211.667C145.828,217.333,145.828,228.667,145.828,240C145.828,251.333,145.828,262.667,145.828,268.333L145.828,274"></path><path marker-end="url(#mermaid-1789678114396_statediagram-barbEnd)" style="fill:none" class="edge-thickness-normal transition" id="edge3" d="M162.094,178.084L171.375,171.57C180.656,165.056,199.219,152.028,199.219,139C199.219,125.972,180.656,112.944,171.375,106.43L162.094,99.916"></path><path marker-end="url(#mermaid-1789678114396_statediagram-barbEnd)" style="fill:none" class="edge-thickness-normal transition" id="edge4" d="M129.563,297.328L112.224,304.607C94.885,311.885,60.208,326.443,44.973,339.388C29.738,352.333,33.945,363.667,36.049,369.333L38.152,375"></path><path marker-end="url(#mermaid-1789678114396_statediagram-barbEnd)" style="fill:none" class="edge-thickness-normal transition" id="edge5" d="M145.828,307L145.828,312.667C145.828,318.333,145.828,329.667,154.622,341.265C163.417,352.863,181.005,364.725,189.799,370.657L198.594,376.588"></path><path marker-end="url(#mermaid-1789678114396_statediagram-barbEnd)" style="fill:none" class="edge-thickness-normal transition" id="edge6" d="M223.902,375L225,369.333C226.098,363.667,228.295,352.333,217.994,339.867C207.693,327.401,184.893,313.801,173.493,307.002L162.094,300.202"></path><path marker-end="url(#mermaid-1789678114396_statediagram-barbEnd)" style="fill:none" class="edge-thickness-normal transition" id="edge7" d="M234.255,375L238.909,369.333C243.563,363.667,252.871,352.333,257.526,338.25C262.18,324.167,262.18,307.333,262.18,290.5C262.18,273.667,262.18,256.833,262.18,240C262.18,223.167,262.18,206.333,262.18,189.5C262.18,172.667,262.18,155.833,245.499,140.177C228.818,124.52,195.456,110.04,178.775,102.8L162.094,95.56"></path><path marker-end="url(#mermaid-1789678114396_statediagram-barbEnd)" style="fill:none" class="edge-thickness-normal transition" id="edge8" d="M50.415,375L52.523,369.333C54.631,363.667,58.847,352.333,60.955,338.25C63.063,324.167,63.063,307.333,63.063,290.5C63.063,273.667,63.063,256.833,63.063,240C63.063,223.167,63.063,206.333,63.063,189.5C63.063,172.667,63.063,155.833,74.146,140.654C85.229,125.475,107.396,111.95,118.479,105.187L129.563,98.425"></path></g><g class="edgeLabels"><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><rect height="0" width="0" ry="0" rx="0"></rect><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g transform="translate(118.31640625, 139)" class="edgeLabel"><g transform="translate(-17.53125, -9)" class="label"><rect height="18" width="35.0625" ry="0" rx="0"></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">自动登录检查</span></div></foreignObject></g></g><g transform="translate(145.828125, 240)" class="edgeLabel"><g transform="translate(-17.53125, -9)" class="label"><rect height="18" width="35.0625" ry="0" rx="0"></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">自动登录成功</span></div></foreignObject></g></g><g transform="translate(217.78125, 139)" class="edgeLabel"><g transform="translate(-17.53125, -9)" class="label"><rect height="18" width="35.0625" ry="0" rx="0"></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">自动登录失败</span></div></foreignObject></g></g><g transform="translate(25.53125, 341)" class="edgeLabel"><g transform="translate(-17.53125, -9)" class="label"><rect height="18" width="35.0625" ry="0" rx="0"></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">用户主动登出</span></div></foreignObject></g></g><g transform="translate(145.828125, 341)" class="edgeLabel"><g transform="translate(-52.9765625, -9)" class="label"><rect height="18" width="105.953125" ry="0" rx="0"></rect><foreignObject height="18" width="105.953125"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"> AccessToken 过期</span></div></foreignObject></g></g><g transform="translate(230.4921875, 341)" class="edgeLabel"><g transform="translate(-11.6875, -9)" class="label"><rect height="18" width="23.375" ry="0" rx="0"></rect><foreignObject height="18" width="23.375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">刷新成功</span></div></foreignObject></g></g><g transform="translate(262.1796875, 240)" class="edgeLabel"><g transform="translate(-11.6875, -9)" class="label"><rect height="18" width="23.375" ry="0" rx="0"></rect><foreignObject height="18" width="23.375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">刷新失败</span></div></foreignObject></g></g><g transform="translate(63.0625, 240)" class="edgeLabel"><g transform="translate(-17.53125, -9)" class="label"><rect height="18" width="35.0625" ry="0" rx="0"></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">清除本地存储</span></div></foreignObject></g></g></g><g class="nodes"><g transform="translate(145.828125, 15)" data-id="root_start" data-node="true" id="state-root_start-0" class="node default"><circle height="14" width="14" r="7" class="state-start"></circle></g><g transform="translate(145.828125, 88.5)" data-id="未认证" data-node="true" id="state-未认证-8" class="node  statediagram-state undefined"><rect height="33" width="32.53125" y="-16.5" x="-16.265625" style="" class="basic label-container"></rect><g transform="translate(-8.765625, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="17.53125"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">未认证</span></div></foreignObject></g></g><g transform="translate(145.828125, 189.5)" data-id="认证中" data-node="true" id="state-认证中-3" class="node  statediagram-state undefined"><rect height="33" width="32.53125" y="-16.5" x="-16.265625" style="" class="basic label-container"></rect><g transform="translate(-8.765625, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="17.53125"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">认证中</span></div></foreignObject></g></g><g transform="translate(145.828125, 290.5)" data-id="已认证" data-node="true" id="state-已认证-6" class="node  statediagram-state undefined"><rect height="33" width="32.53125" y="-16.5" x="-16.265625" style="" class="basic label-container"></rect><g transform="translate(-8.765625, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="17.53125"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">已认证</span></div></foreignObject></g></g><g transform="translate(44.27734375, 391.5)" data-id="已注销" data-node="true" id="state-已注销-8" class="node  statediagram-state undefined"><rect height="33" width="32.53125" y="-16.5" x="-16.265625" style="" class="basic label-container"></rect><g transform="translate(-8.765625, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="17.53125"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">已注销</span></div></foreignObject></g></g><g transform="translate(220.703125, 391.5)" data-id="令牌刷新中" data-node="true" id="state-令牌刷新中-7" class="node  statediagram-state undefined"><rect height="33" width="44.21875" y="-16.5" x="-22.109375" style="" class="basic label-container"></rect><g transform="translate(-14.609375, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="29.21875"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">令牌刷新中</span></div></foreignObject></g></g></g></g></g></svg><ol><li>用户在首次访问时可能处于 <strong>未认证</strong> 状态，系统会自动检查用户的登录状态。</li><li>认证过程中可能会发生令牌过期的情况，需要进行 <strong>令牌刷新</strong>。</li><li>而在用户注销时，系统会清除本地存储数据。</li></ol><p>为了有效管理用户的认证状态和流程，我们引入了一个状态机，覆盖以下几种主要状态和转变：</p><ol><li><p>未认证</p><p>初始状态，表示用户尚未通过认证。系统会自动检查是否有有效的认证信息（如 <code>accessToken</code> 或 <code>refreshToken</code>）。如果没有，用户将无法访问受保护的资源。</p></li><li><p>认证中</p><p>系统正在验证用户的认证信息，可能是通过自动登录检查（例如检查本地存储的 <code>accessToken</code> 或 <code>refreshToken</code>）来恢复用户的会话。若检查成功，用户进入 已认证 状态；若失败，进入 <strong>未认证</strong> 状态。</p></li><li><p>已认证</p><p>认证成功后，用户的身份验证信息有效，允许访问受保护的资源。如果在该状态下，用户的 <code>accessToken</code> 过期，系统会自动尝试通过刷新令牌（<code>refreshToken</code>）来更新 <code>accessToken</code>，进入 <strong>令牌刷新中</strong> 状态。</p></li><li><p>令牌刷新中</p><p>当 <code>accessToken</code> 过期且用户依然处于已认证状态时，系统会通过 <code>refreshToken</code> 尝试获取新的 <code>accessToken</code>。如果刷新成功，系统返回 <strong>已认证</strong> 状态；如果刷新失败，用户会被迫重新认证（进入 <strong>未认证</strong> 状态）。</p></li><li><p>已注销</p><p>用户主动退出时，系统会清除本地存储的认证信息，返回到 <strong>未认证</strong> 状态，确保用户的会话被完全销毁。</p></li><li><p>状态转换</p><p>通过自动登录检查、令牌刷新等机制，我们确保用户认证状态的持续性和稳定性。系统根据认证状态的变化自动调整访问权限和用户会话管理。</p></li></ol><p>在用户状态管理中，我们先添加了自动登录相关的功能：</p><pre><code class="language-ts">const createUserSlice: StateCreator&lt;UserState&gt; = (set, get) =&gt; ({  // ... 其他状态  isAutoLoading: false,  // 新增自动登录状态  // 清除用户信息  clearUser: () =&gt; {    localStorage.removeItem('accessToken');    localStorage.removeItem('refreshToken');    set({ user: null, isAutoLoading: false });  },  // 自动登录功能  autoLogin: async () =&gt; {    const state = get();    if (state.isAutoLoading || state.user) return;    const accessToken = localStorage.getItem('accessToken');    const refreshToken = localStorage.getItem('refreshToken');    if (!accessToken &amp;&amp; !refreshToken) return;    set({ isAutoLoading: true });    try {      let token = accessToken;      // 如果没有访问令牌但有刷新令牌，尝试刷新      if (!token &amp;&amp; refreshToken) {        const response = await api.post('/auth/refresh', { refreshToken });        token = response.data.access_token;        if (token) {          localStorage.setItem('accessToken', token);        }      }      // 获取用户信息      const response = await api.get('/auth/me', {        headers: { Authorization: `Bearer ${token}` }      });      set({ user: response.data, isAutoLoading: false });    } catch (error) {      localStorage.removeItem('accessToken');      localStorage.removeItem('refreshToken');      set({ user: null, isAutoLoading: false });      throw error;    }  },  // 登出功能增强  logout: async () =&gt; {    try {      await api.post('/auth/logout');    } finally {      localStorage.removeItem('accessToken');      localStorage.removeItem('refreshToken');      set({ user: null });    }  }});</code></pre><h4 id="443-状态管理范式转变"><a class="markdownIt-Anchor" href="#443-状态管理范式转变"></a> 4.4.3. 状态管理范式转变</h4><p>在登录功能中，我们需要处理用户的身份验证，同时提供「记住我」功能。然而，使用传统的状态管理（也就是我们的 Zustand）来存储 <code>error</code> 和 <code>isLoading</code> 状态可能会带来一些问题：</p><ul><li>全局状态污染：<code>error</code> 和 <code>isLoading</code> 这些状态只是登录相关，不需要在整个应用范围内存储。</li><li>手动管理状态：需要在 <code>try/catch</code> 中手动更新 <code>isLoading</code>，并在发生错误时手动存储 <code>error</code>，代码较为冗长。</li><li>状态同步问题：如果多个组件依赖相同的登录逻辑，手动管理状态可能会导致数据不同步。</li></ul><p>为了解决这些问题，我们决定使用 React Query 提供的 <code>useMutation</code>，将登录请求的状态管理完全交由 React Query 处理。</p><p>安装 React Query：</p><pre><code class="language-bash">yarn add @tanstack/react-query</code></pre><p>让我们以注册组件为例，来看看这次改造。</p><p>在之前的实现中，我们使用全局状态来管理加载状态和错误信息：</p><pre><code class="language-tsx">const Register = () =&gt; {  const register = useUserStore(state =&gt; state.register);  const isLoading = useUserStore(state =&gt; state.isLoading);  const error = useUserStore(state =&gt; state.error);  const formik = useFormik({    // ...    onSubmit: async (values) =&gt; {      try {        const { username, email, password } = values;        await register({ username, email, password });        navigate('/login', {          state: {            message: '注册成功！请登录您的账号。',            email: values.email          }        });      } catch (error) {        console.error('注册失败：', error);      }    }  });};</code></pre><p>这种方式存在以下问题：</p><ul><li>状态管理过于集中，不同组件的加载状态和错误状态混杂在一起</li><li>需要手动管理状态的清理和重置</li><li>错误处理不够优雅</li><li>缺乏对请求生命周期的完整控制</li></ul><p>在开始实现具体功能之前，我们需要先配置 React Query。首先修改应用的入口文件 <code>index.tsx</code>：</p><pre><code class="language-tsx">import { QueryClient, QueryClientProvider } from '@tanstack/react-query';const queryClient = new QueryClient();const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);root.render(  &lt;React.StrictMode&gt;    &lt;QueryClientProvider client={queryClient}&gt;      &lt;App /&gt;    &lt;/QueryClientProvider&gt;  &lt;/React.StrictMode&gt;);</code></pre><p>使用 React Query 的 <code>useMutation</code> 后，代码变得更加清晰和强大：</p><pre><code class="language-tsx">const Register = () =&gt; {  const setUser = useUserStore(state =&gt; state.setUser);  const { mutate: register, isPending, error } = useMutation({    mutationFn: async (values: {      username: string;      email: string;      password: string;    }) =&gt; {      const response = await api.post('/users/create', values);      return response.data;    },    onSuccess: (data) =&gt; {      setUser(data.user);      navigate('/login', {        state: {          message: '注册成功！请检查邮箱完成验证',          email: data.user.email        },        replace: true      });    }  });  const formik = useFormik({    // ...    onSubmit: async (values) =&gt; {      register({        username: values.username,        email: values.email,        password: values.password      });    }  });};</code></pre><p>这种改进带来了多个显著的好处，使得代码更加清晰、组件更加独立，且状态管理更加高效：</p><ol><li><p>实现了状态隔离。每个组件都有自己独立的加载和错误状态，不同的请求不会相互影响，从而避免了状态混乱的问题。同时，当组件卸载时，状态会自动清理，确保资源的合理释放。</p></li><li><p>得益于生命周期钩子的引入，异步操作的管理更加灵活。<code>mutationFn</code> 负责定义实际的异步操作，<code>onSuccess</code> 处理成功场景，而 <code>onError</code> 则用于错误处理。这些钩子让我们能够更精准地控制请求的执行过程。</p><p>在错误处理方面，这种改进也带来了增强。错误信息会被自动捕获并保存，同时错误状态与组件绑定，使得错误管理更加直观。此外，还能够提供更详细的错误类型信息，方便开发者调试和优化。</p></li><li><p>大幅简化了使用方式。开发者不需要手动处理 <code>try/catch</code> 逻辑，也不需要手动管理 <code>loading</code> 状态，只需直接调用 <code>mutate</code> 函数，即可完成异步操作，提高了开发效率和代码可读性。</p></li></ol><blockquote><p>使用 <code>useMutation</code> 的基本步骤：</p><ol><li>定义 <code>mutation</code> 函数：</li></ol><pre><code class="language-ts">mutationFn: async (values) =&gt; {  const response = await api.post('/users/create', values);  return response.data;}</code></pre><ol start="2"><li>配置生命周期钩子：</li></ol><pre><code class="language-ts">onSuccess: (data) =&gt; {  // 处理成功场景},onError: (error) =&gt; {  // 处理错误场景}</code></pre><ol start="3"><li>在组件中使用：</li></ol><pre><code class="language-ts">const { mutate, isPending, error } = useMutation({ ... });// 触发 mutationmutate(values);// 使用状态{isPending &amp;&amp; &lt;LoadingSpinner /&gt;}{error &amp;&amp; &lt;ErrorMessage error={error} /&gt;}</code></pre></blockquote><p>同样的，修改 <code>VerifyEmail</code> 组件：</p><pre><code class="language-tsx">import React, {useEffect} from 'react'; import {useLocation, useNavigate} from 'react-router-dom'; import {useMutation} from '@tanstack/react-query'; import {useUserStore} from '../stores'; import api from '../stores/common/api';  const VerifyEmail = () =&gt; {   const location = useLocation();   const navigate = useNavigate();   const token = new URLSearchParams(location.search).get('token');    const {     emailVerified,     verificationError,     verificationToken,     verificationUserId,     clearVerificationState   } = useUserStore(state =&gt; ({     emailVerified: state.emailVerified,     verificationError: state.verificationError,     verificationToken: state.verificationToken,     verificationUserId: state.verificationUserId,     clearVerificationState: state.clearVerificationState   }));    const { mutate: verifyEmail, isPending } = useMutation({     mutationFn: async (token: string) =&gt; {       const response = await api.get(`/users/verify-email?token=${token}`);       return response.data;     },     onSuccess: (data) =&gt; {       if (data.success) {         useUserStore.setState({           emailVerified: true,           verificationUserId: data.userId         });         navigate('/login', { replace: true })       } else {         useUserStore.setState({           verificationError: data.error,           verificationUserId: data.userId         });       }     },     onError: (error) =&gt; {       useUserStore.setState({ verificationError: error.message || '验证过程中发生未知错误' });     }   });    useEffect(() =&gt; {     if (token) verifyEmail(token);   }, [token]);    useEffect(() =&gt; {     return () =&gt; {       clearVerificationState();       window.history.replaceState({}, '', window.location.pathname);     }   }, []);    const handleResend = async () =&gt; {     if (verificationUserId) {       try {         await api.post(`/users/resend-verification/${verificationUserId}`);         navigate('/login', {           state: { message: '新的验证邮件已发送，请查收邮箱' }         });       } catch (error) {         useUserStore.setState({ verificationError: '重新发送验证邮件失败' });         throw error instanceof Error           ? error.message           : '重新发送验证邮件失败';       }     }   }    return (     &lt;div className="min-h-screen flex items-center justify-center bg-base-200"&gt;       &lt;div className="card w-96 bg-base-100 shadow-xl"&gt;         &lt;div className="card-body items-center text-center"&gt;           &lt;h2 className="card-title mb-4"&gt;             验证电子邮件           &lt;/h2&gt;            {isPending &amp;&amp; (             &lt;div className="flex flex-col items-center gap-4"&gt;               &lt;span className="loading loading-spinner loading-lg" /&gt;               &lt;p&gt;正在验证您的邮箱...&lt;/p&gt;             &lt;/div&gt;           )}            {emailVerified &amp;&amp; (             &lt;div className="alert alert-success"&gt;               &lt;span&gt;邮箱验证成功！正在跳转至登录页面……&lt;/span&gt;             &lt;/div&gt;           )}            {verificationError &amp;&amp; (             &lt;div className="alert alert-error flex flex-col gap-3"&gt;               &lt;span&gt;{verificationError}&lt;/span&gt;               {verificationUserId &amp;&amp; (                 &lt;button                   className="btn btn-sm btn-outline"                   onClick={handleResend}                 &gt;                   重新发送验证邮件                 &lt;/button&gt;               )}             &lt;/div&gt;           )}            {!isPending &amp;&amp; !emailVerified &amp;&amp; !verificationError &amp;&amp; verificationToken &amp;&amp; (             &lt;div className="flex flex-col gap-3"&gt;               &lt;p&gt;验证链接已失效&lt;/p&gt;               &lt;button                 className="btn btn-outline"                 onClick={() =&gt; verifyEmail(verificationToken)}               &gt;                 重新尝试验证               &lt;/button&gt;             &lt;/div&gt;           )}         &lt;/div&gt;       &lt;/div&gt;     &lt;/div&gt;   ); };  export default VerifyEmail; </code></pre><h4 id="444-登录组件改造"><a class="markdownIt-Anchor" href="#444-登录组件改造"></a> 4.4.4. 登录组件改造</h4><p>我们需要对登录组件（<code>Login.tsx</code>）进行改造，以支持「记住我」功能。</p><ol><li><p>在表单验证模式中增加「记住我」选项：</p> <pre><code class="language-tsx">const validationSchema = Yup.object().shape({   username: Yup.string().required('请输入用户名！'),   password: Yup.string().required('请输入密码！'),  rememberMe: Yup.boolean()  // 新增}); const formik = useFormik({   initialValues: {     username: '',     password: '',     rememberMe: false  // 新增  },   validationSchema,  onSubmit: async (values) =&gt; {    login(values);  }});</code></pre></li><li><p>使用 <code>useMutation</code> 重构登录逻辑：</p> <pre><code class="language-tsx">const { mutate: login, isPending, error } = useMutation({   mutationFn: async (credentials: {     username: string,     password: string,     rememberMe: boolean,   }) =&gt; {     const response = await api.post('/auth/login', credentials);     return response.data;   },   onSuccess: async (data) =&gt; {     localStorage.setItem('accessToken', data.access_token);     // 只有在用户选择“记住我”时才保存刷新令牌    if (formik.values.rememberMe) {      localStorage.setItem('refreshToken', data.refresh_token);     }    setUser(data.user);     navigate('/', {       state: { message: '登陆成功！' },       replace: true     })   },   onError: (error) =&gt; {     // 登录失败时清除所有令牌    localStorage.removeItem('accessToken');     localStorage.removeItem('refreshToken');     clearUser();     console.log('登录失败：', error);   } });</code></pre></li><li><p>添加自动登录检查逻辑：</p> <pre><code class="language-tsx">useEffect(() =&gt; {   const checkAutoLogin = async () =&gt; {     const accessToken = localStorage.getItem('accessToken');     const refreshToken = localStorage.getItem('refreshToken');     if (accessToken || refreshToken) {       try {         await autoLogin();       } catch (error) {         clearUser();         localStorage.removeItem('accessToken');         localStorage.removeItem('refreshToken');         console.log('检查自动登录失败：', error);       }     }   }   checkAutoLogin().then(r =&gt; console.log('检查自动登录成功：', r)); }, []);</code></pre></li><li><p>登录后自动跳转：</p> <pre><code class="language-tsx">useEffect(() =&gt; {   if (user &amp;&amp; !isAutoLoading) {     navigate('/', { replace: true });   } }, [user, isAutoLoading, navigate]);</code></pre></li><li><p>添加「记住我」选项的界面元素：</p> <pre><code class="language-tsx">&lt;div className="mb-4 flex items-center"&gt;   &lt;input     type="checkbox"     id="rememberMe"     name="rememberMe"     className="w-4 h-4 text-primary bg-base-300 border-neutral-600 rounded"     checked={formik.values.rememberMe}     onChange={formik.handleChange}     disabled={isPending}   /&gt;   &lt;label     htmlFor="rememberMe"     className="ml-2 text-sm text-neutral-content cursor-pointer"   &gt;     记住我   &lt;/label&gt; &lt;/div&gt;</code></pre></li></ol><h2 id="45-邮箱验证提示"><a class="markdownIt-Anchor" href="#45-邮箱验证提示"></a> 4.5. 邮箱验证提示</h2><p>为了提升用户体验，我们需要在用户未验证邮箱时给出明显的提示。这个功能包含两个部分：提示组件和布局改造。</p><p>创建 <code>UnverifiedBanner</code> 组件来显示验证提示：</p><pre><code class="language-tsx">import React from 'react';import { useUserStore } from '../stores';const UnverifiedBanner = () =&gt; {  const user = useUserStore(state =&gt; state.user);  if (user &amp;&amp; !user.verified) {    return (      &lt;div className="p-4 mb-4 text-sm text-warning-content bg-warning rounded"&gt;        您的邮箱尚未验证，请尽快验证。您可以修改邮箱地址或&lt;a href="/resend-verification" className="underline ml-1"&gt;重新发送验证邮件&lt;/a&gt;。      &lt;/div&gt;    );  }  return null;};export default UnverifiedBanner;</code></pre><p>这个组件具有几个重要特点。它通过全局状态获取用户信息，确保始终使用最新的用户数据。同时，它只会在用户尚未完成验证时显示，避免对已验证用户造成干扰。此外，组件还提供了快捷的邮箱验证操作，使用户能够方便地完成身份确认，提高使用体验。</p><p>将验证提示集成到 <code>AuthLayout</code> 中：</p><pre><code class="language-tsx">import React from 'react'; import UnverifiedBanner from '../components/UnverifiedBanner';  type AuthLayoutProps = {   children: React.ReactNode; };  const AuthLayout = ({ children }: AuthLayoutProps) =&gt; {   return (     &lt;div className="flex flex-col min-h-screen items-center justify-center bg-base-200"&gt;       &lt;UnverifiedBanner /&gt;       &lt;div className="w-full max-w-md bg-base-100 p-8 rounded-lg shadow-xl"&gt;         {children}       &lt;/div&gt;     &lt;/div&gt;   ); };  export default AuthLayout; </code></pre><p>这种改进带来了多方面的好处。用户可以及时了解自己的邮箱验证状态，避免因未验证而影响正常使用。同时，组件提供了直接的验证操作入口，使用户能够快速完成身份确认。此外，它保持了统一的视觉风格，与整体界面设计相协调，并且不会影响原有的布局结构，确保页面的整洁与一致性。</p><p>为了解决用户可能未收到验证邮件或验证邮件过期的问题，我们需要实现验证邮件重发功能：</p><pre><code class="language-tsx">import React, {useCallback, useEffect} from 'react';import { useNavigate } from 'react-router-dom';import {useMutation} from '@tanstack/react-query';import { useUserStore } from '../stores';import api from '../stores/common/api';const ResendVerification = () =&gt; {  const navigate = useNavigate();  const {    user,    verificationUserId,    clearVerificationState  } = useUserStore(state =&gt; ({    user: state.user,    verificationUserId: state.verificationUserId,    clearVerificationState: state.clearVerificationState  }));  const { mutate: resendEmail, isPending, error } = useMutation({    mutationFn: async (userId: string) =&gt; {      const response = await api.post(`/users/resend-verification/${userId}`);      return response.data;    },    onSuccess: () =&gt; {      navigate('/login', {        state: { message: '新的验证邮件已发送至你的注册邮箱' },        replace: true      });    }  })  const handleResend = useCallback(() =&gt; {    if (!verificationUserId) {      console.error('缺少用户 ID');      return;    }    resendEmail(verificationUserId);  }, [verificationUserId, resendEmail]);  useEffect(() =&gt; {    return () =&gt; {      clearVerificationState();    };  }, [clearVerificationState]);  return (    &lt;div className="min-h-screen flex items-center justify-center bg-base-200"&gt;      &lt;div className="card w-96 bg-base-100 shadow-xl"&gt;        &lt;div className="card-body items-center text-center"&gt;          &lt;h2 className="card-title mb-4"&gt;            邮箱验证          &lt;/h2&gt;          &lt;div className="flex flex-col items-center gap-4"&gt;            &lt;p className="text-sm"&gt;              你的邮箱 &lt;strong className="text-primary"&gt;{user?.email}&lt;/strong&gt; 还未验证            &lt;/p&gt;            {error &amp;&amp; (              &lt;div className="alert alert-error shadow-lg"&gt;                &lt;div&gt;                  &lt;svg xmlns="http://www.w3.org/2000/svg" className="stroke-current flex-shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"&gt;                    &lt;path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /&gt;                  &lt;/svg&gt;                  &lt;span&gt;{error.message}&lt;/span&gt;                &lt;/div&gt;              &lt;/div&gt;            )}            &lt;button              onClick={handleResend}              disabled={isPending}              className={`btn btn-primary w-full ${isPending ? 'loading' : ''}`}            &gt;              {isPending ? '发送中...' : '重新发送验证邮件'}            &lt;/button&gt;            &lt;div className="text-sm mt-4"&gt;              &lt;p className="text-gray-500"&gt;                没有收到邮件？请检查垃圾邮件文件夹              &lt;/p&gt;              &lt;p className="text-gray-500 mt-2"&gt;                需要修改邮箱？前往{' '}                &lt;a                  href="/settings"                  className="link link-primary"                  onClick={(e) =&gt; {                    e.preventDefault();                    navigate('/settings');                  }}                &gt;                  账户设置                &lt;/a&gt;              &lt;/p&gt;            &lt;/div&gt;          &lt;/div&gt;        &lt;/div&gt;      &lt;/div&gt;    &lt;/div&gt;  );}export default ResendVerification;</code></pre><p>通过这个功能，我们为用户提供了一个完整的邮箱验证补救方案，帮助他们顺利完成账号验证过程。</p><h2 id="46-错误边界处理"><a class="markdownIt-Anchor" href="#46-错误边界处理"></a> 4.6. 错误边界处理</h2><p>在复杂的单页应用中，错误处理是一个非常重要的环节。为了防止应用因为某个组件的错误而完全崩溃，我们引入了错误边界（Error Boundary）机制。</p><p>安装 <code>react-error-boundary</code>：</p><pre><code class="language-bash">yarn add react-error-boundary</code></pre><h4 id="461-应用入口改造"><a class="markdownIt-Anchor" href="#461-应用入口改造"></a> 4.6.1. 应用入口改造</h4><p>首先，我们在应用的最顶层添加错误边界保护。修改 <code>App.tsx</code>：</p><pre><code class="language-tsx">import React from 'react';import { RouterProvider } from 'react-router-dom';import { ErrorBoundary } from 'react-error-boundary';import router from './router';import ErrorFallback from './components/ErrorFallback';const App = () =&gt; {  return (    &lt;ErrorBoundary FallbackComponent={ErrorFallback}&gt;      &lt;RouterProvider router={ router } /&gt;    &lt;/ErrorBoundary&gt;  );}export default App;</code></pre><p>这样做可以捕获整个应用中的 React 组件错误，防止应用崩溃。</p><h4 id="462-错误回退组件"><a class="markdownIt-Anchor" href="#462-错误回退组件"></a> 4.6.2. 错误回退组件</h4><p>我们创建了一个专门的错误回退组件 <code>ErrorFallback.tsx</code>，用于显示错误信息并提供重试功能：</p><pre><code class="language-tsx">import React from 'react';import { FallbackProps } from 'react-error-boundary';const ErrorFallback = ({ error, resetErrorBoundary }: FallbackProps) =&gt; {  return (    &lt;div className="alert alert-error shadow-lg"&gt;      &lt;div&gt;        &lt;svg xmlns="http://www.w3.org/2000/svg" className="stroke-current flex-shrink-0 h-6 w-6" fill="none" viewBox="0 0 24 24"&gt;          &lt;path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z" /&gt;        &lt;/svg&gt;        &lt;div&gt;          &lt;h3 className="font-bold"&gt;发生错误！&lt;/h3&gt;          &lt;pre className="whitespace-pre-wrap"&gt;{error.message}&lt;/pre&gt;        &lt;/div&gt;      &lt;/div&gt;      &lt;button        className="btn btn-sm btn-primary"        onClick={resetErrorBoundary}      &gt;        重试      &lt;/button&gt;    &lt;/div&gt;  );}export default ErrorFallback;</code></pre><p>错误回退组件具备以下核心功能，旨在提升错误处理的可读性和用户体验：</p><ol><li>提供清晰的错误信息展示。组件能够显示友好的错误提示，同时呈现具体的错误详情，并保持错误信息的格式化显示，以便用户理解问题所在。</li><li>支持错误恢复功能。用户可以通过重试按钮尝试重新执行操作，同时，<code>resetErrorBoundary</code> 方法允许重置错误状态，使应用能够正常运行，让用户得以从错误中恢复。</li><li>在用户体验方面，组件采用统一的错误提示样式，确保与应用的整体设计风格保持一致。同时，它提供清晰的操作指引，帮助用户快速做出合适的应对操作，从而减少因错误导致的使用困扰。</li></ol><h2 id="47-路由访问控制"><a class="markdownIt-Anchor" href="#47-路由访问控制"></a> 4.7. 路由访问控制</h2><p>为了确保用户只能访问其权限内的页面，我们需要实现路由保护机制。这包括对私有路由的保护和对公共路由的控制。</p><h4 id="471-受保护路由组件"><a class="markdownIt-Anchor" href="#471-受保护路由组件"></a> 4.7.1. 受保护路由组件</h4><p>创建 <code>ProtectedRoute</code> 组件用于保护需要登录才能访问的页面：</p><pre><code class="language-tsx">import React from 'react';import {useLocation, Navigate} from 'react-router-dom';import {useUserStore} from '../stores';const ProtectedRoute = ({ children }: { children: React.ReactNode }) =&gt; {  const user = useUserStore(state =&gt; state.user);  const isAutoLoading = useUserStore(state =&gt; state.isAutoLoading);  const location = useLocation();  // TODO: 返回一个加载动画  if (isAutoLoading) return &lt;div&gt;加载中……&lt;/div&gt;;  if (!user) return &lt;Navigate to="/login" state={{from: location}} replace /&gt;;  return &lt;&gt;{children}&lt;/&gt;;}export default ProtectedRoute;</code></pre><h4 id="472-公共路由组件"><a class="markdownIt-Anchor" href="#472-公共路由组件"></a> 4.7.2. 公共路由组件</h4><p>创建 <code>PublicRoute</code> 组件用于处理登录、注册等公共页面：</p><pre><code class="language-tsx">import React from 'react';import {useUserStore} from '../stores';import {Navigate, useLocation} from 'react-router-dom';const PublicRoute = ({children} : {children: React.ReactNode}) =&gt; {  const user = useUserStore(state =&gt; state.user);  const isAutoLoading = useUserStore(state =&gt; state.isAutoLoading);  const location = useLocation();  if (isAutoLoading) return &lt;div&gt;加载中……&lt;/div&gt;;  if (user) {    const from = location.state?.from?.pathname || '/';    return &lt;Navigate to={from} replace /&gt;;  }  return &lt;&gt;{children}&lt;/&gt;;}export default PublicRoute;</code></pre><h4 id="473-路由配置优化"><a class="markdownIt-Anchor" href="#473-路由配置优化"></a> 4.7.3. 路由配置优化</h4><p>使用这些保护组件来包装路由：</p><pre><code class="language-tsx">const router = createBrowserRouter([   {     path: '/',     element: &lt;ProtectedRoute&gt;&lt;MainPage /&gt;&lt;/ProtectedRoute&gt;   },   {     path: '/register',     element: &lt;PublicRoute&gt;&lt;Register /&gt;&lt;/PublicRoute&gt;   },   {     path: '/login',     element: &lt;PublicRoute&gt;&lt;Login /&gt;&lt;/PublicRoute&gt;   },   {     path: '/verify-email',     element: &lt;VerifyEmail /&gt;   },   {     path: '/resend-verification',     element: &lt;ResendVerification /&gt;   } ]);</code></pre><blockquote><p>可以写一个简单的 <code>MainPage</code> 组件来测试登出功能：</p><pre><code class="language-tsx">import React from 'react';import { useUserStore } from '../stores';import MainLayout from '../layouts/MainLayout';const MainPage = () =&gt; {  const logout = useUserStore(state =&gt; state.logout);  return (    &lt;MainLayout&gt;      &lt;button onClick={logout}&gt;登出&lt;/button&gt;    &lt;/MainLayout&gt;  )};export default MainPage;</code></pre></blockquote></body></html>]]></content>
    
    
    <summary type="html">本文是 React + NestJS 全栈购物平台实践的第五篇，专注于实现完整的用户登录功能。前端部分，教程详细讲解了如何使用 Formik 和 Yup 构建登录表单，并结合 React Query 和 Zustand 实现“记住我”功能与自动登录检查。后端部分，则深入实现了基于 JWT 的双令牌（Access Token + Refresh Token）认证机制，包括令牌的生成、验证、刷新和注销。本教程为构建一个安全、用户体验友好的全栈登录系统提供了从前端交互到后端认证的完整实战指南。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="全栈实践" scheme="https://blog.cytrogen.icu/tags/%E5%85%A8%E6%A0%88%E5%AE%9E%E8%B7%B5/"/>
    
    <category term="Node.js" scheme="https://blog.cytrogen.icu/tags/Node-js/"/>
    
    <category term="React.js" scheme="https://blog.cytrogen.icu/tags/React-js/"/>
    
    <category term="TypeScript" scheme="https://blog.cytrogen.icu/tags/TypeScript/"/>
    
    <category term="NestJS" scheme="https://blog.cytrogen.icu/tags/NestJS/"/>
    
  </entry>
  
  <entry>
    <title>Hexo 配置 i18n</title>
    <link href="https://blog.cytrogen.icu/posts/17cc.html"/>
    <id>https://blog.cytrogen.icu/posts/17cc.html</id>
    <published>2024-12-02T02:20:17.000Z</published>
    <updated>2026-02-09T17:16:54.713Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>运营个人博客时，可能会遇到这样的需求：希望网站能够支持多语言，让来自不同地区的读者都能便捷地阅读我们的内容。</p><p>这就需要用到网站的国际化（也就是 i18n）功能。</p><p>对于使用 Hexo 搭建的博客而言，实现国际化不仅需要考虑内容的翻译，还要处理模板渲染等问题。</p><span id="more"></span><div class="danger"><ul><li><p>本文使用的主要插件是 <code>hexo-generator-plus</code>。</p><p><a href="https://github.com/kiwirafe/hexo-generator-plus"><img src="https://gh-card.dev/repos/kiwirafe/hexo-generator-plus.svg?fullname=" alt="kiwirafe/hexo-generator-plus - GitHub" loading="lazy"></a></p><p>在开始配置之前，请确保已经卸载以下插件以避免冲突：</p><ul><li><code>hexo-generator-archive</code></li><li><code>hexo-generator-category</code></li><li><code>hexo-generator-index</code></li><li><code>hexo-generator-tag</code></li></ul></li><li><p>本文使用的模板语言是 Pug 语言。</p></li><li><p>对于导航栏中切换语言的方案，我只实现了双语言的逻辑。</p></li></ul></div><h2 id="基础配置"><a class="markdownIt-Anchor" href="#基础配置"></a> 基础配置</h2><blockquote><p>为了避免困扰：</p><ol><li>Hexo 根目录下的 <code>_config.yml</code> 将被称呼为 <strong>Hexo 配置项</strong></li><li><code>themes/**/_config.yml</code> 将被称呼为 <strong>主题配置项</strong></li></ol></blockquote><p>首先，我们需要在 Hexo 的配置文件中进行一些基本设置。这些设置将决定网站的语言选项和 URL 结构。</p><pre><code class="language-yaml">language: [zh, en]  # 支持的语言列表，第一个为默认语言new_post_name: :title.md  # 新文章的命名方式# 如果你安装了 hexo-abbrlinkpermalink: posts/:abbrlink.html  # 文章的永久链接格式abbrlink:  rep: hex  # 使用十六进制作为文章的唯一标识# hexo-generator-plus 的配置项generator_plus:  language: [zh, en]  # 生成器支持的语言列表  pagination_dir: 'page'  # 分页目录  generator: ["index", "archive", "category", "tag"]  # 需要生成的页面类型  # 首页生成器配置  index_generator:    per_page: 10  # 这些数字和顺序可以自定义    order_by: -date  # 归档页面配置  archive_generator:    per_page: 25    order_by: -date  # 分类页面配置  category_generator:    per_page: 25    order_by: -date    enable_index_page: true  # 如果你想要分类列表页的话  # 标签页面配置  tag_generator:    per_page: 25    order_by: name    enable_index_page: true  # 如果你想要标签列表页的话</code></pre><p>接着在主题配置项里配置想要的菜单链接：</p><pre><code class="language-yaml">menu:   home: /   archive: /archives   categories: /categories   tags: /tags   about: /about   GitHub: https://github.com/cytrogen   RSS: /atom.xml</code></pre><h2 id="目录结构"><a class="markdownIt-Anchor" href="#目录结构"></a> 目录结构</h2><p>以下是必需的目录结构：</p><pre><code class="language-plaintext">source/├── _posts/                     # 默认语言的所有博文│   └── *.md                    # 不能有子目录├── en/                         # 英文版特定内容│   └── 与 source 目录结构相同├── archives/                   # 归档页面│   └── index.md                # layout: archive├── categories/                 # 分类页面│   └── index.md                # layout: category-index└── tags/                       # 标签页面    └── index.md                # layout: tag-index</code></pre><blockquote><p>当然，你也可以选择其他语言，但其他语言的目录需要和对应的 <code>themes/**/languages/*.yml</code> 的名称相同。</p></blockquote><p>请确保每个 <code>*.md</code> 的 Front-Matter 中都有 <code>lang: **</code>。</p><h2 id="语言文件配置"><a class="markdownIt-Anchor" href="#语言文件配置"></a> 语言文件配置</h2><p>网站的固定文本（如导航菜单、按钮文字等）需要通过语言文件来实现国际化。这些文件需要放在 <code>themes/**/languages/</code> 目录下。</p><p>这是我的例子：</p><ol><li><p><code>zh.yml</code>：</p> <pre><code class="language-yaml">menu:home: 首页archive: 归档tags: 标签categories: 分类about: 关于friendlinks: 友情链接archive_title: 归档tags_title: 标签categories_title: 分类prev: 上一页next: 下一页prev_post: 上一篇next_post: 下一篇more: ...阅读全文translated: 翻译 · 原文地址</code></pre></li><li><p><code>en.yml</code>：</p> <pre><code class="language-yaml">menu:home: HOMEarchive: ARCtags: TAGScategories: CATEabout: ABOUTfriendlinks: Friend Linksarchive_title: Archivetags_title: Tagscategories_title: Categoriesprev: PREVnext: NEXTprev_post: PREV POSTnext_post: NEXT POSTmore: ...MOREtranslated: Translate · Original Link</code></pre></li></ol><h2 id="模板文件实现"><a class="markdownIt-Anchor" href="#模板文件实现"></a> 模板文件实现</h2><p>从这里开始，只写关于我的博客网站所用的方案。</p><p><strong>请按照自己的主题，自行进行修改。</strong></p><h4 id="分类页面模板"><a class="markdownIt-Anchor" href="#分类页面模板"></a> 分类页面模板</h4><p>分类页面需要两个模板：分类列表页面和具体分类页面。</p><ol><li><p>分类列表页面（<code>category-index.pug</code>）：</p> <pre><code class="language-plaintext">extends partial/layoutblock container    .archive        // 标题内容优先使用 page.title        // 如果不存在则使用国际化函数 __() 获取 categories_title 的翻译        h2.archive-title= page.title || __('categories_title')        .category-list            // 获取所有分类数据            each category in get_categories().data                // 对每个分类计算符合当前语言的文章数量                - var postCount = category.posts.data ? category.posts.data.filter(post =&gt; post.lang === page.lang).length : 0                if postCount &gt; 0                    .category-item                        // 每个分类显示为一个链接，包含分类名称、文章数量计数                        // url_for_lang() 生成多语言支持的 URL                        - var categoryPath = category.slug || category.name                        a.post-title-link(href=url_for_lang(page.lang, 'categories/' + categoryPath))                            = category.name                            span.category-count= ` (${postCount})`</code></pre></li><li><p>具体分类页面（<code>category.pug</code>）：</p> <pre><code class="language-plaintext">extends partial/layoutblock container    include mixins/post    .archive        h2.archive-title= page.category        +postList()</code></pre><p>这里文章显示相关的功能被封装成了一系列混入（mixins），方便在不同页面重用（<code>mixins/post.pug</code>）：</p> <pre><code class="language-plaintext">mixin postInfo(item)    .post-info        != full_date(item.date, 'l')        // 如果文章有 from 属性且当前页面是首页或者文章页        if item.from &amp;&amp; (is_home() || is_post())            // 显示一个表示文章翻译来源的链接            a.post-from(href=item.from target="_blank" title=item.from)!= __('translated')mixin posts()    ul.home.post-list        // 遍历所有的文章        - for (var post of page.posts.data || [])            // 只显示与当前页面语言匹配的文章            - if (post.lang == page.lang)                li.post-list-item                    article.post-block                        h2.post-title                            a.post-title-link(href= url_for(post.path))                                != post.title                        +postInfo(post)                        // 如果有摘要，就显示摘要和“阅读全文”链接                        if post.excerpt                            .post-content                                != post.excerpt                            a.read-more(href= url_for(post.path))!= __('more')                        else                            .post-content                                != post.content</code></pre></li></ol><h4 id="标签页面模板"><a class="markdownIt-Anchor" href="#标签页面模板"></a> 标签页面模板</h4><p>和分类页面模板近乎一致：</p><ol><li><p><code>tag-index.pug</code>：</p> <pre><code class="language-plaintext">extends partial/layoutblock container    include mixins/post    .archive        h2.archive-title= page.title || __('tags_title')        .tag-list            each tag in get_tags().data                - var postCount = tag.posts.data ? tag.posts.data.filter(post =&gt; post.lang === page.lang).length : 0                if postCount &gt; 0                    .tag-item                        - var tagPath = tag.slug || tag.name                        a.post-title-link(href=url_for_lang(page.lang, 'tags/' + tagPath))                            = tag.name                            span.tag-count= ` (${postCount})`block pagination    include mixins/paginator    +home()block copyright    include partial/copyright</code></pre></li><li><p><code>tag.pug</code>：</p> <pre><code class="language-plaintext">extends partial/layoutblock container    include mixins/post    .archive        h2.archive-title= page.tag        +postList()block pagination    include mixins/paginator    +home()block copyright    include partial/copyright</code></pre></li></ol><h4 id="归档页面模板"><a class="markdownIt-Anchor" href="#归档页面模板"></a> 归档页面模板</h4><p>归档页面只需要一个 <code>archive.pug</code>：</p><pre><code class="language-plaintext">extends partial/layoutblock container    include mixins/post    +postList()block pagination    include mixins/paginator    +home()block copyright    include partial/copyright</code></pre><p>它调用的混入：</p><pre><code class="language-plaintext">mixin postList()    .archive        // 是否有文章数据        if page.posts            // 确保文章列表存在且不为空            - var posts = page.posts.data || page.posts            if posts &amp;&amp; posts.length                // 创建一个年份对象用于存储分组                // 只处理与当前页面语言相匹配的文章                // 使用文章日期获取年份                // 将文章添加到对应年份的数组中                - var years = {}                - for (var post of posts)                    - if (post.lang == page.lang)                        - var year = new Date(post.date).getFullYear()                        - if (!years[year]) years[year] = []                        - years[year].push(post)                // 将年份按降序排列（先显示年份最大的）                - Object.keys(years).sort((a, b) =&gt; b - a).forEach(function(year) {                    h2.archive-year!= year                    - years[year].forEach(function(post) {                        .post-item                            +postInfo(post)                            a.post-title-link(href= url_for(post.path))                                != post.title                    - })                - })</code></pre><h4 id="导航栏实现"><a class="markdownIt-Anchor" href="#导航栏实现"></a> 导航栏实现</h4><p>导航栏是实现语言切换的关键接口（<code>nav.pug</code>）。</p><p>由于我的博客主题中，导航栏并不宽，因此我写了顶底部来区分开部分链接：</p><pre><code class="language-plaintext">ul.nav.nav-list    // 顶层    div.nav-list-top        // 遍历主题配置项中 menu 的所有键值        each path, key in theme.menu            // 排除掉想要放在底部的链接，我这里写的 GitHub 和 RSS            if key !== 'GitHub' &amp;&amp; key !== 'RSS'                li.nav-list-item                    // 检测是否是外部链接                    // 如果是，就在新标签页打开                    // 英文页面的路径前添加 /en 前缀                    // 判断当前页面是否激活（用于高亮显示）                    - var re = /^(http|https):\/\/*/gi;                    - var tar = re.test(path) ? "_blank" : "_self"                    - var fullPath = page.lang === 'en' ? '/en' + path : path                    - var act = !re.test(path) &amp;&amp; "/" + page.current_url === fullPath                    a.nav-list-link(class={active: act} href=url_for(fullPath) target=tar)                        != __(('menu.' + key))    // 底部    div.nav-list-bottom        // 语言切换按钮        li.nav-list-item.lang-switch            if page.lang == 'en'                a.nav-list-link(href=url_for('/')) 中文            else                a.nav-list-link(href=url_for('/en')) ENGLISH</code></pre><h2 id="使用方法"><a class="markdownIt-Anchor" href="#使用方法"></a> 使用方法</h2><p>完成上述配置后，创建新文章时需要在 Front-Matter 中指定语言：</p><pre><code class="language-markdown">---title: 文章标题date: 2024-01-01lang: zh---</code></pre><p>如果想创建同一篇文章的其他语言版本，只需要创建一个新的 Markdown 文件，指定相应的 <code>lang</code>，并在 Front-Matter 中通过 <code>from</code> 字段关联原文：</p><pre><code class="language-markdown">---title: Article Titledate: 2024-01-01lang: enfrom: /posts/original-post.html---</code></pre></body></html>]]></content>
    
    
    <summary type="html">本文是一篇详细的 Hexo 博客国际化（i18n）配置教程，介绍了如何使用 hexo-generator-plus 插件为网站添加多语言支持。内容涵盖从基础的 Hexo 配置、目录结构规划、语言文件创建，到具体的 Pug 模板修改，全面讲解了首页、归档、分类和标签页面的改造过程，并提供了一个实用的导航栏语言切换方案。跟随本教程，你可以一步步为你的博客实现中英双语或更多语言功能。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Hexo" scheme="https://blog.cytrogen.icu/tags/Hexo/"/>
    
    <category term="Pug" scheme="https://blog.cytrogen.icu/tags/Pug/"/>
    
  </entry>
  
  <entry>
    <title>React + NestJS 购物平台练习【4】用户注册功能</title>
    <link href="https://blog.cytrogen.icu/posts/8853.html"/>
    <id>https://blog.cytrogen.icu/posts/8853.html</id>
    <published>2024-11-28T05:00:00.000Z</published>
    <updated>2026-02-09T17:16:54.997Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>全栈实践又到了我们喜闻乐见的用户注册功能……</p><span id="more"></span><h1 id="1-修-bug"><a class="markdownIt-Anchor" href="#1-修-bug"></a> 1. 修 BUG</h1><p>我们先修一下先前写的 BUG……</p><h2 id="11-导出-bug"><a class="markdownIt-Anchor" href="#11-导出-bug"></a> 1.1. 导出 BUG</h2><p>在我们先前创建的 <code>src/stores/index.ts</code> 中，我们写的是：</p><pre><code class="language-ts">import useUserStore from './user';</code></pre><p>这样写的话，实际运行项目后会报错。</p><p>正确的写法是：</p><pre><code class="language-ts">export { useUserStore } from './user';</code></pre><ol><li><p><code>index.ts</code> 是用于导出所有的 Store，因此是 <code>export</code> 而不是 <code>import</code></p></li><li><p>要理解为什么必须使用 <code>{ useUserStore }</code> 而不是 <code>useUserStore</code>，我们需要了解 JavaScript 和 TypeScript 中的默认导出（default export）和具名导出（named export）之间的区别</p></li></ol><h4 id="111-具名导出"><a class="markdownIt-Anchor" href="#111-具名导出"></a> 1.1.1. 具名导出</h4><p>在 <code>stores/user/index.ts</code> 中，<code>useUserStore</code> 是通过具名导出方式来导出的：</p><pre><code class="language-ts">export const useUserStore = createSelectors(useUserStoreBase);</code></pre><p>这表示我们将 <code>useUserStore</code> 作为一个具名导出，并且它可以通过具名导出来引用。具名导出的语法正是：</p><pre><code class="language-ts">export { useUserStore } from './user';</code></pre><h4 id="112-默认导出"><a class="markdownIt-Anchor" href="#112-默认导出"></a> 1.1.2. 默认导出</h4><p>如果我们使用的是默认导出，那么导出时应该写成：</p><pre><code class="language-ts">export default useUserStore;</code></pre><p>然后我们才可以在其他文件使用默认导出语法：</p><pre><code class="language-ts">export useUserStore from './user';</code></pre><h2 id="12-实体关系-bug"><a class="markdownIt-Anchor" href="#12-实体关系-bug"></a> 1.2. 实体关系 BUG</h2><p>后续在后端开发完注册 API、运行应用时，会遇到实体关系配置错误：</p><pre><code class="language-plaintext">TypeORMError: Entity metadata for Users#orders was not found. Check if you specified a correct entity object and if it's connected in the connection options.</code></pre><p>这是因为 NestJS 使用 TypeORM 时需要通过 <code>TypeOrmModule</code> 注册所有的实体。如果一个实体（例如 <code>Users</code>）中引用了其他实体（例如 <code>Orders</code>），TypeORM 会尝试加载并解析这些关系。如果 <code>Orders</code> 没有在 <code>TypeOrmModule</code> 配置中注册，TypeORM 将会因为找不到该实体的元数据而抛出错误。</p><p>唉，这时候有人该问了，<a href="/posts/8e94">第二篇</a> 里不是已经写了个 <code>database.module.ts</code> 来统一配置吗？里面还配置了个 <code>autoLoadEntities</code> 呢。</p><p>在数据库模块的配置中，我们确实加上了 <code>autoLoadEntities: true</code>，希望能自动加载所有实体，避免每次手动注册实体。然而，<code>autoLoadEntities</code> 的工作机制并非全局加载所有实体，它仅自动加载通过 <code>TypeOrmModule.forFeature()</code> 注册的实体。因此，如果某个实体未被 <code>forFeature</code> 导入到任何模块中，TypeORM 无法找到它。</p><p>在 <code>TypeOrmModule</code> 中，有三种方式来配置实体加载，每种方式有不同的适用场景：</p><ol><li><p>单独定义：</p> <pre><code class="language-ts">TypeOrmModule.forRoot({  //...  entities: [    Users,    Products,    Payments,    Orders,    OrderItems,    InventoryLogs,    Categories,    Carts,    CartItems,    Addresses,  ],}),</code></pre><p>这种方式适合开发阶段，明确知道所有实体的数量和位置时，每当创建新实体时手动添加即可。但在项目复杂、实体较多或依赖多模块的情况下，逐一引入会显得繁琐，容易出错，且不便于代码维护。</p></li><li><p>自动加载：</p> <pre><code class="language-ts">TypeOrmModule.forRoot({  //...  autoLoadEntities: true,}),</code></pre><p><code>autoLoadEntities</code> 会自动加载通过 <code>TypeOrmModule.forFeature()</code> 引入的实体。这意味着在模块中显式使用 <code>TypeOrmModule.forFeature([Entity])</code> 的实体将被自动添加到连接配置的 <code>entities</code> 数组中。</p><blockquote><p>注意：</p><p>这要求每个模块中要包含实体的 <code>forFeature</code> 配置。否则未注册的实体将无法自动加载，容易引发实体关系配置错误。</p><p>在 <code>Users</code> 实体中，<code>Orders</code> 实体被作为关联实体引用（<code>@OneToMany(() =&gt; Orders, order =&gt; order.user)</code>)，因此 TypeORM 会尝试在 <code>entities</code> 配置数组中找到并加载 <code>Orders</code> 的元数据。由于 <code>Orders</code> 没有在任何模块的 <code>forFeature</code> 中注册，TypeORM 会在解析 <code>Users</code> 实体的关系时找不到 <code>Orders</code>，导致报错。</p></blockquote></li><li><p>自定义引入路径：</p> <pre><code class="language-ts">TypeOrmModule.forRoot({  //...  entities: ['dist/**/*.entity{.ts,.js}'],}),</code></pre><p>这是官方推荐的方式，使用通配符路径直接加载所有编译后的实体文件（如 <code>dist/entities/*.entity.js</code>），避免了逐一手动添加的麻烦，并保证所有实体自动注册，减少遗漏问题。</p></li></ol><p>在我们的 <code>database.module.ts</code> 中添加第三种方式的配置，即可解决报错。</p><h1 id="2-实现注册表单组件"><a class="markdownIt-Anchor" href="#2-实现注册表单组件"></a> 2. 实现注册表单组件</h1><h2 id="21-基础结构"><a class="markdownIt-Anchor" href="#21-基础结构"></a> 2.1. 基础结构</h2><p>我们的注册页面由两个主要部分组成：</p><ul><li><code>Register</code> 组件：处理表单逻辑、验证以及提交请求</li><li><code>AuthLayout</code> 组件：负责提供页面的布局和样式</li></ul><p><code>Register</code> 组件嵌套在 <code>AuthLayout</code> 中，这样可以确保页面结构保持一致。</p><p>首先，我们来看看 <code>AuthLayout.tsx</code> 组件的代码，它定义了一个简单的容器，将任何传递给它的内容居中显示，并设置一些基本的样式：</p><pre><code class="language-tsx">import React from 'react';type AuthLayoutProps = {  children: React.ReactNode;};const AuthLayout = ({ children }: AuthLayoutProps) =&gt; {  return (    &lt;div className="flex min-h-screen items-center justify-center bg-base-200"&gt;      &lt;div className="w-full max-w-md bg-base-100 p-8 rounded-lg shadow-xl"&gt;        {children}      &lt;/div&gt;    &lt;/div&gt;  );};export default AuthLayout;</code></pre><p>这里使用了 Tailwind CSS 进行样式布局，<code>AuthLayout</code> 用于包装页面的子元素，确保其在屏幕上居中显示，并有一定的阴影和内边距。</p><p>接着在 <code>src/pages</code> 目录下创建 <code>Register.tsx</code>。</p><h2 id="22-表单开发"><a class="markdownIt-Anchor" href="#22-表单开发"></a> 2.2. 表单开发</h2><p>在我们的 <code>Register</code> 组件中，我们将使用 <code>Formik</code> 来处理表单的状态管理和提交，并使用 <code>Yup</code> 来进行表单验证。<code>Formik</code> 和 <code>Yup</code> 的结合提供了简洁且强大的表单验证和管理能力。</p><p>用以下命令安装 <code>Formik</code> 和 <code>Yup</code>：</p><pre><code class="language-bash">yarn add formik yup</code></pre><h4 id="221-formik-用法"><a class="markdownIt-Anchor" href="#221-formik-用法"></a> 2.2.1. <code>Formik</code> 用法</h4><p><code>Formik</code> 通过 <code>useFormik</code> Hook 管理表单的状态和行为。在 <code>Register</code> 页面中，我们初始化了一个表单，提供了初始值和 <code>onSubmit</code> 处理函数。</p><pre><code class="language-tsx">import { useFormik } from 'formik';const Register = () =&gt; {  const formik = useFormik({    initialValues: {      username: "",      email: "",      password: "",      confirmPassword: ""    },    validationSchema,    onSubmit: (values) =&gt; {      setIsSubmitting(true);      setTimeout(() =&gt; {        console.log(values);  // 模拟提交        setIsSubmitting(false);      }, 2000);    }  });  // ...}</code></pre><ul><li><code>initialValues</code>：初始化表单的默认值</li><li><code>validationSchema</code>：使用 <code>Yup</code> 创建的验证规则（稍后会详细介绍）</li><li><code>onSubmit</code>：处理表单提交的函数<ul><li><code>setIsSubmitting(true)</code>：在表单提交时，我们将 <code>isSubmitting</code> 设置为 <code>true</code>，这会触发按钮禁用以及按钮文本更新为「注册中……」</li><li><code>setTimeout</code>：为了模拟实际的提交过程，我们使用 <code>setTimeout</code> 延迟了 2 秒钟。实际应用中这里应该替换为 API 请求，不过我们的 API 还没完成呢</li><li><code>setIsSubmitting(false)</code>：当提交操作完成时，我们将 <code>isSubmitting</code> 设置为 <code>false</code>，恢复按钮的正常状态</li></ul></li></ul><h4 id="222-yup-验证"><a class="markdownIt-Anchor" href="#222-yup-验证"></a> 2.2.2. <code>Yup</code> 验证</h4><p><code>Yup</code> 是一个 JavaScript 的对象模式验证库，我们通过它来定义表单的验证规则。下面是每个字段的验证规则：</p><pre><code class="language-tsx">import * as Yup from 'yup';const Register = () =&gt; {  const validationSchema = Yup.object({    username: Yup.string().required("请输入用户名！"),    email: Yup.string().email("请输入有效的邮箱地址！").required("请输入邮箱地址！"),    password: Yup.string().min(6, "密码必须至少包含6个字符！").required("请输入密码！"),    confirmPassword: Yup.string()      .oneOf([Yup.ref("password")], "密码不匹配！")      .required("请输入确认密码！"),  });  // ...}</code></pre><ul><li><code>username</code>：必须填写，并且是字符串</li><li><code>email</code>：必须添加，并且符合邮箱格式</li><li><code>password</code>：必须至少有 6 个字符</li><li><code>confirmPassword</code>：必须与密码匹配</li></ul><p><code>Yup</code> 和 <code>Formik</code> 的结合提供了简洁的验证机制，自动管理每个字段的错误信息，并在表单提交时触发验证。</p><h4 id="223-表单渲染"><a class="markdownIt-Anchor" href="#223-表单渲染"></a> 2.2.3. 表单渲染</h4><p>表单输入框的渲染非常直观。我们通过 <code>formik.handleChange</code> 来处理用户输入，并通过 <code>formik.errors</code> 和 <code>formik.touched</code> 来显示错误信息。</p><pre><code class="language-tsx">const Register = () =&gt; {  // ...  return (    &lt;AuthLayout&gt;      &lt;h2 className="text-2xl font-bold text-center mb-6 text-neutral-content"&gt;        注册账户      &lt;/h2&gt;      &lt;form onSubmit={formik.handleSubmit}&gt;        &lt;div className="mb-4"&gt;          &lt;label className="block text-sm font-semibold text-neutral-content" htmlFor="username"&gt;            用户名          &lt;/label&gt;          &lt;input            type="text"            id="username"            name="username"            className={`w-full mt-2 p-2 border rounded-lg bg-base-300 ${formik.touched.username &amp;&amp; formik.errors.username ? "border-error" : "border-neutral-600"} text-base-content`}            value={formik.values.username}            onChange={formik.handleChange}            onBlur={formik.handleBlur}          /&gt;          {formik.touched.username &amp;&amp; formik.errors.username &amp;&amp; (            &lt;p className="text-sm text-error mt-1"&gt;{formik.errors.username}&lt;/p&gt;          )}        &lt;/div&gt;        {/* ... */}      &lt;/form&gt;    &lt;/AuthLayout&gt;  );};</code></pre><ul><li><code>value</code>：绑定表单值</li><li><code>onChange</code> 和 <code>onBlur</code>：处理表单输入和失去焦点事件</li><li><code>formik.errors</code>：在字段发生错误时显示错误信息</li></ul><p>用同样的写法，写完「邮箱地址」、「密码」和「确认密码」输入框：</p><pre><code class="language-tsx">const Register = () =&gt; {  // ...  return (    &lt;AuthLayout&gt;      &lt;h2 className="text-2xl font-bold text-center mb-6 text-neutral-content"&gt;        注册账户      &lt;/h2&gt;      &lt;form onSubmit={formik.handleSubmit}&gt;        {/* ... */}        &lt;div className="mb-4"&gt;          &lt;label className="block text-sm font-semibold text-neutral-content" htmlFor="email"&gt;            邮箱地址          &lt;/label&gt;          &lt;input            type="email"            id="email"            name="email"            className={`w-full mt-2 p-2 border rounded-lg bg-base-300 ${formik.touched.email &amp;&amp; formik.errors.email ? "border-error" : "border-neutral-600"} text-base-content`}            value={formik.values.email}            onChange={formik.handleChange}            onBlur={formik.handleBlur}          /&gt;          {formik.touched.email &amp;&amp; formik.errors.email &amp;&amp; (            &lt;p className="text-sm text-error mt-1"&gt;{formik.errors.email}&lt;/p&gt;          )}        &lt;/div&gt;        &lt;div className="mb-4"&gt;          &lt;label className="block text-sm font-semibold text-neutral-content" htmlFor="password"&gt;            密码          &lt;/label&gt;          &lt;input            type="password"            id="password"            name="password"            className={`w-full mt-2 p-2 border rounded-lg bg-base-300 ${formik.touched.password &amp;&amp; formik.errors.password ? "border-error" : "border-neutral-600"} text-base-content`}            value={formik.values.password}            onChange={formik.handleChange}            onBlur={formik.handleBlur}          /&gt;          {formik.touched.password &amp;&amp; formik.errors.password &amp;&amp; (            &lt;p className="text-sm text-error mt-1"&gt;{formik.errors.password}&lt;/p&gt;          )}        &lt;/div&gt;        &lt;div className="mb-4"&gt;          &lt;label className="block text-sm font-semibold text-neutral-content" htmlFor="confirmPassword"&gt;            确认密码          &lt;/label&gt;          &lt;input            type="password"            id="confirmPassword"            name="confirmPassword"            className={`w-full mt-2 p-2 border rounded-lg bg-base-300 ${formik.touched.confirmPassword &amp;&amp; formik.errors.confirmPassword ? "border-error" : "border-neutral-600"} text-base-content`}            value={formik.values.confirmPassword}            onChange={formik.handleChange}            onBlur={formik.handleBlur}          /&gt;          {formik.touched.confirmPassword &amp;&amp; formik.errors.confirmPassword &amp;&amp; (            &lt;p className="text-sm text-error mt-1"&gt;{formik.errors.confirmPassword}&lt;/p&gt;          )}        &lt;/div&gt;      &lt;/form&gt;    &lt;/AuthLayout&gt;  );};</code></pre><h4 id="224-按钮的状态管理"><a class="markdownIt-Anchor" href="#224-按钮的状态管理"></a> 2.2.4. 按钮的状态管理</h4><p>按钮的状态管理对于处理表单提交时的交互反馈是非常重要的。</p><p><code>useState</code> 是 React 中用于管理组件状态的 Hook。它允许我们在函数组件内部创建一个可变的状态，并返回一个更新该状态的函数。在注册页面中，我们使用 <code>useState</code> 来管理表单是否正在提交。</p><pre><code class="language-tsx">import React, { useState } from 'react';const Register = () =&gt; {    const [isSubmitting, setIsSubmitting] = useState&lt;boolean&gt;(false);        // ...};</code></pre><ul><li><code>isSubmitting</code>：表示表单是否正在提交，初始值是 <code>false</code>，即默认情况下表单没有提交</li><li><code>setIsSubmitting</code>：用于更新 <code>isSubmitting</code> 状态的函数</li></ul><p>每当表单提交时，我们会将 <code>isSubmitting</code> 设置为 <code>true</code>，表示正在进行提交操作。当提交完成后，再将其设置回 <code>false</code>。</p><h4 id="225-按钮的状态变化"><a class="markdownIt-Anchor" href="#225-按钮的状态变化"></a> 2.2.5. 按钮的状态变化</h4><p>在注册页面中，表单的提交按钮（<code>&lt;button&gt;</code>）会根据 <code>isSubmitting</code> 的状态进行显示不同的文本内容：</p><pre><code class="language-tsx">const Register = () =&gt; {  // ...  return (    &lt;AuthLayout&gt;      &lt;h2 className="text-2xl font-bold text-center mb-6 text-neutral-content"&gt;        注册账户      &lt;/h2&gt;      &lt;form onSubmit={formik.handleSubmit}&gt;        {/* ... */}        &lt;button type="submit" className="w-full bg-primary text-primary-content py-2 rounded-lg mt-4 hover:brightness-90" disabled={isSubmitting}&gt;          {isSubmitting ? "注册中……" : "注册"}        &lt;/button&gt;      &lt;/form&gt;  );};&lt;/button&gt;</code></pre><ul><li><code>disabled={isSubmitting}</code>：按钮在提交时被禁用，防止用户多次点击。每次表单提交时，<code>isSubmitting</code> 会被设为 <code>true</code>，这将使按钮处于禁用状态，直到提交结束</li><li>按钮文本切换：根据 <code>isSubmitting</code> 的值，按钮的文本会动态改变<ul><li>如果表单正在提交（<code>isSubmitting === true</code>），按钮文本会显示为「注册中……」</li><li>如果表单没有提交（<code>isSubmitting === false</code>），按钮显示为「注册」</li></ul></li></ul><h2 id="23-路由配置"><a class="markdownIt-Anchor" href="#23-路由配置"></a> 2.3. 路由配置</h2><p>为了使我们的页面能够被访问和管理，在我们的 <code>router.tsx</code> 中添加路由 <code>/register</code>：</p><pre><code class="language-tsx">import Register from './pages/Register';const router = createBrowserRouter([  // ...  {    path: '/register',    element: &lt;Register /&gt;  }]);</code></pre><p>运行 React 项目，访问 <code>localhost:3000/register</code>：</p><p><img src="/posts/8853/1.webp" alt="Register页面预览" loading="lazy"></p><blockquote><p>图片是另外加的。</p></blockquote><h1 id="3-实现后端注册-api"><a class="markdownIt-Anchor" href="#3-实现后端注册-api"></a> 3. 实现后端注册 API</h1><p>在现代的 Web 应用开发中，用户注册功能是几乎每个系统都需要的基础部分。用户注册不仅需要保存用户的基本信息，还要确保密码等敏感数据的安全性。</p><p>设想这样一个场景：我们正在开发一个用户系统，要求用户可以通过提供必要的个人信息进行注册，并创建一个账号。由于用户密码是非常敏感的信息，我们必须在保存密码之前进行加密，以确保其安全性。此外，我们还需要在需要时提供其他用户管理的接口，如更新、删除等操作。</p><h2 id="31-创建用户模块"><a class="markdownIt-Anchor" href="#31-创建用户模块"></a> 3.1. 创建用户模块</h2><p>用户模块负责管理用户相关的逻辑，创建 <code>users.module.ts</code> 文件：</p><pre><code class="language-ts">import { Module } from '@nestjs/common';import { TypeOrmModule } from '@nestjs/typeorm';import { UsersController } from './users.controller';import { UsersService } from './users.service';import { Users } from '../entities/users.entity';@Module({  imports: [TypeOrmModule.forFeature([Users])],  controllers: [UsersController],  providers: [UsersService]})export class UsersModule {}</code></pre><p>在此模块中，我们使用了 <code>TypeOrmModule.forFeature([Users])</code> 来将用户实体与 TypeORM 绑定，以便在 <code>UsersService</code> 中使用数据库的增删查改功能。</p><h2 id="32-创建用户控制器"><a class="markdownIt-Anchor" href="#32-创建用户控制器"></a> 3.2. 创建用户控制器</h2><p>控制器负责定义 API 路由和对应的处理方法，创建 <code>users.controller.ts</code> 文件：</p><pre><code class="language-ts">import { Controller, Post, Get, Body, Param } from '@nestjs/common';import { UsersService } from './users.service';import { Users } from '../entities/users.entity';@Controller('users')export class UsersController {  constructor(private readonly usersService: UsersService) {}  @Post('create')  create(@Body() user: Partial&lt;Users&gt;): Promise&lt;Users&gt; {    return this.usersService.create(user);  }  @Get(':id')  findById(@Param('id') id: string): Promise&lt;Users&gt; {    return this.usersService.findById(id);  }  @Post('update/:id')  update(@Param('id') id: string, @Body() updateUser: Partial&lt;Users&gt;): Promise&lt;Users&gt; {    return this.usersService.update(id, updateUser);  }  @Post('delete/:id')  remove(@Param('id') id: string): Promise&lt;void&gt; {    return this.usersService.remove(id);  }}</code></pre><p>我们定义了以下几个方法：</p><ul><li><code>create</code>：用于处理用户注册的 POST 请求，调用 <code>UsersService.create</code> 方法以保存用户信息</li><li><code>findById</code>、<code>update</code> 和 <code>remove</code> 方法：分别用于获取、更新和删除用户信息</li></ul><h2 id="33-编写用户服务"><a class="markdownIt-Anchor" href="#33-编写用户服务"></a> 3.3. 编写用户服务</h2><p><code>UsersService</code> 负责处理具体的业务逻辑，包括数据的加密和与数据库的交互。在实现注册功能时，我们需要对用户密码进行加密，并将加密后的密码与其他信息一起保存到数据库。</p><p>创建 <code>users.service.ts</code>：</p><pre><code class="language-ts">import { Injectable, NotFoundException } from '@nestjs/common';import { InjectRepository } from '@nestjs/typeorm';import { Repository } from 'typeorm';import * as bcrypt from 'bcrypt';import { Users } from '../entities/users.entity';@Injectable()export class UsersService {  constructor(@InjectRepository(Users) private usersRepository: Repository&lt;Users&gt;) {}  async create(user: Partial&lt;Users&gt;): Promise&lt;Users&gt; {    const hashedPassword = await bcrypt.hash(user.password, 10);    const newUser = this.usersRepository.create({      ...user,      password: hashedPassword    });    return this.usersRepository.save(newUser);  }  async update(id: string, updateUser: Partial&lt;Users&gt;): Promise&lt;Users&gt; {    const user = await this.findById(id);    if (updateUser.password) {      updateUser.password = await bcrypt.hash(updateUser.password, 10);    }    Object.assign(user, updateUser);    return this.usersRepository.save(user);  }  async remove(id: string): Promise&lt;void&gt; {    const result = await this.usersRepository.delete(id);    if (result.affected === 0) {      throw new NotFoundException(`User with ID ${id} is not found`);    }  }  async findById(id: string): Promise&lt;Users&gt; {    const user = await this.usersRepository.findOneBy({ id });    if (!user) {      throw new NotFoundException(`User with ID ${id} is not found`);    }    return user;  }}</code></pre><p><code>UsersService</code> 实现了以下方法：</p><ul><li><code>create</code>：用于创建用户。在保存用户数据前，通过 <code>bcrypt.hash</code> 方法对密码进行加密，然后将加密后的用户数据保存到数据库</li><li><code>update</code>：用于更新用户信息。如果更新的数据中包含 <code>password</code>，则需要再次加密后再保存</li><li><code>remove</code>：用于删除用户信息。如果删除操作没有影响任何行，则会抛出 <code>NotFoundException</code> 错误</li><li><code>findById</code>：用于根据用户 ID 查询用户信息。找不到用户时同样会抛出 <code>NotFoundException</code></li></ul><h2 id="34-通过-swagger-生成文档标签"><a class="markdownIt-Anchor" href="#34-通过-swagger-生成文档标签"></a> 3.4. 通过 Swagger 生成文档标签</h2><p>我们将为每个控制器方法添加 Swagger 标签：</p><pre><code class="language-ts">// ...import { ApiTags, ApiOperation, ApiBody, ApiResponse, ApiParam } from '@nestjs/swagger';@ApiTags('Users')@Controller('users')export class UsersController {  // ...  @ApiOperation({ summary: '创建新用户' })  @ApiBody({ description: '用户信息', type: Users })  @ApiResponse({ status: 201, description: '用户成功创建', type: Users })  @Post('create')  // ...  @ApiOperation({ summary: '根据ID获取用户信息' })  @ApiParam({ name: 'id', description: '用户ID' })  @ApiResponse({ status: 200, description: '获取用户信息成功', type: Users })  @Get(':id')  // ...  @ApiOperation({ summary: '更新用户信息' })  @ApiParam({ name: 'id', description: '用户ID' })  @ApiBody({ description: '更新的用户信息', type: Users })  @ApiResponse({ status: 200, description: '用户更新成功', type: Users })  @Post('update/:id')  // ...  @ApiOperation({ summary: '删除用户' })  @ApiParam({ name: 'id', description: '用户ID' })  @ApiResponse({ status: 200, description: '用户删除成功' })  @Post('delete/:id')  // ...}</code></pre><ul><li><code>@ApiTags('Users')</code>：将此标签添加到控制器顶部，使得所有方法都归入 <code>Users</code> 类别，便于在 Swagger 文档中管理</li><li><code>@ApiOperation</code>：为每个方法添加操作说明，使其清晰描述了 API 的功能</li><li><code>@ApiBody</code>：为 <code>POST</code> 请求体参数添加描述，指定了参数内容的描述和数据类型</li><li><code>@ApiParam</code>：为路径参数添加说明，方便开发者了解需要传入的参数</li><li><code>@ApiResponse</code>：指定响应的状态码和描述信息，以及返回的数据类型，便于用户了解响应格式</li></ul><p>访问 <code>localhost:APP_PORT/api-docs</code> 来查看 Swagger 文档。</p><h2 id="35-使用-dto-来进行优化"><a class="markdownIt-Anchor" href="#35-使用-dto-来进行优化"></a> 3.5. 使用 DTO 来进行优化</h2><p>在现代 Web 应用中，数据传输对象（DTO）是与外部通信的标准化方式之一。在 NestJS 项目中，DTO（Data Transfer Object）不仅帮助你确保传递的数据格式一致，还提供了结构化和验证机制，使得 API 接口更加清晰、安全和可维护。</p><p>DTO 通常用于：</p><ul><li>定义 API 接口所需的请求体和响应体的结构</li><li>对数据进行验证和转换</li><li>确保前后端在数据传输时遵循相同的约定</li></ul><p>在我们已经编写了注册用户的逻辑后，为什么还需要创建 DTO 并用它来顶替原本的写法？</p><p>答案是：<strong>增强数据验证和规范化输入输出</strong>。</p><ol><li><p>增强验证机制：DTO 通过类验证器（如 <code>class-validator</code>）来确保传入的数据符合预期。例如，我们可以设置 <code>MinLength</code> 来确保密码长度不小于 6 个字符、使用 <code>IsEmail</code> 来验证邮箱格式。这不仅使代码更加规范，而且还大大提高了 API 的可靠性和安全性</p></li><li><p>清晰的 API 结构：DTO 使 API 请求和响应体更加清晰。通过 DTO，前后端可以明确约定需要的数据字段和格式，这样可以减少由于数据格式不匹配导致的错误</p></li><li><p>易于扩展和维护：DTO 提供了一个灵活的扩展点。如果未来业务需求发生变化，我们只需修改 DTO，而不必修改整个业务逻辑。这样，系统的可维护性和扩展性更强</p></li></ol><p>我们已经有了一个用于用户注册的业务逻辑，现在我们要将 DTO 集成到 <code>UsersController</code> 和 <code>UsersService</code> 中。</p><h4 id="351-创建-dto"><a class="markdownIt-Anchor" href="#351-创建-dto"></a> 3.5.1. 创建 DTO</h4><p>在 <code>src/users</code> 目录下创建 <code>dto</code> 目录，并在其中再创建一个 <code>create-user.dto.ts</code> 文件：</p><pre><code class="language-ts">import { IsString, IsEmail, MinLength } from 'class-validator';export class CreateUserDto {  @IsString()  username: string;  @IsEmail()  email: string;  @MinLength(6, { message: '密码长度必须不小于6个字符' })  password: string;}</code></pre><p><code>CreateUserDto</code> 定义了用户注册时需要传入的字段，并且为这些字段添加了验证规则：</p><ul><li><code>username</code> 字段要求是字符串类型</li><li><code>email</code> 字段要求是有效的邮箱格式</li><li><code>password</code> 字段要求密码长度至少为 6 个字符</li></ul><h4 id="352-在控制器中使用-dto"><a class="markdownIt-Anchor" href="#352-在控制器中使用-dto"></a> 3.5.2. 在控制器中使用 DTO</h4><p>接下来，在 <code>UsersController</code> 中，我们将 <code>CreateUserDto</code> 引入，并将其用于 <code>create</code> 方法的请求体验证。我们需要使用 <code>@Body()</code> 装饰器将请求体映射到 DTO 类。</p><pre><code class="language-ts">// ...import { CreateUserDto } from './dto/create-user.dto';@ApiTags('Users')@Controller('users')export class UsersController {  // ...  @ApiOperation({ summary: '创建新用户' })  @ApiBody({ description: '用户信息', type: CreateUserDto })  // 使用DTO类型  @ApiResponse({ status: 201, description: '用户成功创建', type: Users })  @Post('create')  create(@Body() user: CreateUserDto): Promise&lt;Users&gt; {  // 接收CreateUserDto类型    return this.usersService.create(user);  }  // ...}</code></pre><p>在上述代码中：</p><ul><li>使用 <code>@ApiBody</code> 注解指定了请求体的描述，<code>type</code> 字段使用 <code>CreateUserDto</code></li><li><code>@Body()</code> 装饰器会将请求体映射到 <code>CreateUserDto</code> 类型，从而进行数据验证</li></ul><h4 id="353-在服务中使用-dto"><a class="markdownIt-Anchor" href="#353-在服务中使用-dto"></a> 3.5.3. 在服务中使用 DTO</h4><p>在 <code>UsersService</code> 中，<code>create</code> 方法接收了 <code>CreateUserDto</code> 类型的参数，并在保存到数据库之前进行密码的哈希处理：</p><pre><code class="language-ts">// ...import { CreateUserDto } from './dto/create-user.dto';@Injectable()export class UsersService {  constructor(@InjectRepository(Users) private usersRepository: Repository&lt;Users&gt;) {}  async create(user: CreateUserDto): Promise&lt;Users&gt; {    const hashedPassword = await bcrypt.hash(user.password, 10);  // 使用DTO中的password    const newUser = this.usersRepository.create({      ...user,      password: hashedPassword    });    return this.usersRepository.save(newUser);  }}</code></pre><p>在这里，我们在服务层接收的参数是 <code>CreateUserDto</code> 类型，它包含了所有必要的字段和验证规则。通过这种方式，我们避免了在控制器中进行复杂的验证操作，将其交给 DTO 来处理，使得业务逻辑更加简洁和清晰。</p><h4 id="354-定义-swagger-schema"><a class="markdownIt-Anchor" href="#354-定义-swagger-schema"></a> 3.5.4. 定义 Swagger Schema</h4><p>在 NestJS 中，你可以通过在 DTO 中使用 Swagger 的注解来定义和生成 API 的 Schema。</p><pre><code class="language-ts">import { IsString, IsEmail, MinLength } from 'class-validator';import { ApiProperty } from '@nestjs/swagger';export class CreateUserDto {  @ApiProperty({    description: '用户名，用户的唯一标识',    example: 'john_doe'  })  @IsString()  username: string;  @ApiProperty({    description: '用户的邮箱地址，必须为有效的邮箱格式',    example: 'johndoe@example.com'  })  @IsEmail()  email: string;  @ApiProperty({    description: '密码，必须至少包含6个字符',    example: 'password123456',    minLength: 6  })  @MinLength(6, { message: '密码长度必须不小于6个字符' })  password: string;}</code></pre><p><img src="/posts/8853/2.webp" alt="访问localhost:APP_PORT/api-docs，即可看到CreateUserDto Schema" loading="lazy"></p><h2 id="36-与前端的集成"><a class="markdownIt-Anchor" href="#36-与前端的集成"></a> 3.6. 与前端的集成</h2><p>先前写前端代码的时候，我们的 <code>Register.tsx</code> 并没有连接到后端 API，而是使用 <code>setTimeout</code> 模拟了一下提交。</p><p>因此我们要对现有的前端代码进行修改和优化。</p><h4 id="361-添加状态管理逻辑"><a class="markdownIt-Anchor" href="#361-添加状态管理逻辑"></a> 3.6.1. 添加状态管理逻辑</h4><p>在 <code>Register.tsx</code> 中，我们使用了本地状态管理 <code>isSubmitting</code>。</p><pre><code class="language-tsx">const [isSubmitting, setIsSubmitting] = useState&lt;boolean&gt;(false);</code></pre><p>为了让状态的管理更统一，我们需要将其改为使用全局状态管理，也为之后添加更多功能奠定了基础。</p><p>首先是修改 <code>stores/index.ts</code>：</p><pre><code class="language-ts">export { useUserStore } from './user';</code></pre><p>接着在 <code>Register.tsx</code> 中使用 <code>useUserStore</code>：</p><pre><code class="language-tsx">import { useUserStore } from '../stores';// ...const register = useUserStore(state =&gt; state.register);const isLoading = useUserStore(state =&gt; state.isLoading);const error = useUserStore(state =&gt; state.error);</code></pre><ul><li><code>register</code>：一个用于注册用户的全局方法</li><li><code>isLoading</code>：表单提交的状态</li><li><code>error</code>：记录注册过程中发生的错误信息</li></ul><h4 id="362-新增注册方法"><a class="markdownIt-Anchor" href="#362-新增注册方法"></a> 3.6.2. 新增注册方法</h4><p>在修改 <code>Register.tsx</code> 时，我们同样需要在 <code>stores</code> 目录下的状态管理逻辑中进行调整，以支持注册功能的完整实现。</p><p>首先在 <code>stores/user/types.ts</code> 中新增注册凭据类型：</p><pre><code class="language-ts">export interface RegisterCredentials {   username: string;   email: string;   password: string; }</code></pre><p>并更新用户状态类型：</p><pre><code class="language-ts">export interface UserState {  // ...  register: (credentials: RegisterCredentials) =&gt; Promise&lt;User&gt;;}</code></pre><p>接着在 <code>stores/user/actions.ts</code> 中新添注册功能：</p><pre><code class="language-ts">register: async (credentials: RegisterCredentials) =&gt; {   set({ isLoading: true, error: null });   try {     const response: AxiosResponse&lt;User&gt; = await api.post&lt;User&gt;('/users/create', credentials);     const user = response.data;     set({       isLoading: false,       error: null,       lastUpdated: Date.now()     });     return user;   } catch (error) {     const errorMessage = error instanceof Error       ? error.message       : '注册过程中发生意外错误';     set({       isLoading: false,       error: errorMessage     });     throw error;   } }, </code></pre><p>主要逻辑为：</p><ul><li>初始化状态：设置 <code>isLoading</code> 为 <code>true</code>，清空可能的旧错误</li><li>调用注册 API：发送用户的注册信息到 <code>/users/create</code>，并解析后端返回的用户数据</li><li>成功处理：更新状态，但不设置 <code>user</code> 值，因为注册完成后还需登录</li><li>错误处理：捕获错误并设置错误信息</li><li>状态恢复：无论成功或失败，都将 <code>isLoading</code> 恢复为 <code>false</code></li></ul><h4 id="363-实现与后端的连接"><a class="markdownIt-Anchor" href="#363-实现与后端的连接"></a> 3.6.3. 实现与后端的连接</h4><p>先前我们用了 <code>setTimeout</code> 来模拟注册：</p><pre><code class="language-tsx">setTimeout(() =&gt; {  console.log(values);  setIsSubmitting(false);}, 2000);</code></pre><p>现在我们应当与实际的后端进行交互，发送注册请求：</p><pre><code class="language-tsx">onSubmit: async (values) =&gt; {  try {    const { username, email, password } = values;    await register({ username, email, password });    navigate('/login', {      state: {        message: '注册成功！请登录您的账号。',        email: values.email      }    });  } catch (error) {    console.error('注册失败：', error);  }}</code></pre><p>成功后，跳转到 <code>/login</code> 页面，并通过 <code>state</code> 传递一条注册成功的信息。就算失败了，也会捕获错误信息，便于显示给用户。</p><p>由于我们在 <code>store</code> 中已经处理了注册错误，这里就不需要额外处理，直接 <code>console.error</code> 即可。</p><blockquote><p><code>navigate</code> 来自于 <code>react-router-dom</code> 库：</p><pre><code class="language-tsx">import { useNavigate } from 'react-router-dom';// ...const navigate = useNavigate();</code></pre></blockquote><h4 id="364-用户错误信息提示"><a class="markdownIt-Anchor" href="#364-用户错误信息提示"></a> 3.6.4. 用户错误信息提示</h4><p>在 <code>Register.tsx</code> 中添加以下内容：</p><pre><code class="language-tsx">return (    &lt;AuthLayout&gt;      &lt;img src={logo} className="w-1/4 mx-auto" alt="Shopping Nest的Logo" /&gt;      &lt;h2 className="text-2xl font-bold text-center m-6 text-neutral-content"&gt;        注册账户      &lt;/h2&gt;      {error &amp;&amp; (        &lt;div className="mb-4 p-3 text-sm text-error-content bg-error rounded-lg"&gt;          {error}        &lt;/div&gt;      )}      {/* ... */}    &lt;/AuthLayout&gt;);</code></pre><p>用户提交表单时，如果后端返回错误信息，将会在表单顶部显示一条清晰的错误提示。这提升了用户体验，让用户了解失败的原因并尝试修正。</p><h4 id="365-禁用表单控件"><a class="markdownIt-Anchor" href="#365-禁用表单控件"></a> 3.6.5. 禁用表单控件</h4><p>将 <code>Register.tsx</code> 中所有的 <code>&lt;input&gt;</code> 标签都添加上这个属性：</p><pre><code class="language-tsx">disabled={isLoading}</code></pre><p>这代表着提交过程中表单控件会被禁用，避免用户重复提交。</p><p><code>isLoading</code> 由状态管理工具提供，确保整个应用对状态变化的感知一致。</p><p>同样的，对 <code>&lt;button&gt;</code> 也进行修改：</p><pre><code class="language-tsx">&lt;button  type="submit"  className="w-full bg-primary text-primary-content py-2 rounded-lg mt-4 hover:brightness-90 disabled:opacity-50"  disabled={isLoading}&gt;  {isLoading ? "注册中…" : "注册"}&lt;/button&gt;</code></pre><p>运行前端和后端，进行注册测试。</p><p>别忘了在前端目录下创建 <code>.env</code>：</p><pre><code class="language-plaintext">REACT_APP_API_URL=http://localhost:后端的端口</code></pre><p>注册成功后你应该会被导向 <code>/login</code> 页面，上面会弹出：</p><pre><code class="language-plaintext">Unexpected Application Error!404 Not Found💿 Hey developer 👋You can provide a way better UX than this when your app throws errors by providing your own ErrorBoundary or errorElement prop on your route.</code></pre><h1 id="4-实现邮箱验证"><a class="markdownIt-Anchor" href="#4-实现邮箱验证"></a> 4. 实现邮箱验证</h1><p>邮箱验证是用户注册流程中的重要安全环节，旨在确认用户提供的邮箱地址是真实且可用、防止机器人和垃圾注册、提高账号安全性，同时为后续通信建立可靠的联系渠道。</p><p>典型的邮箱验证流程包括：</p><ol><li>用户注册提供邮箱</li><li>系统生成唯一验证令牌</li><li>发送包含验证链接的邮件</li><li>用户点击链接完成验证</li><li>系统校验令牌的有效性</li></ol><h2 id="41-前端实现"><a class="markdownIt-Anchor" href="#41-前端实现"></a> 4.1. 前端实现</h2><p>我们首先需要在路由中添加邮箱验证页面的路由。在 <code>router.tsx</code> 中进行修改：</p><pre><code class="language-ts">import VerifyEmail from './pages/VerifyEmail';const router = createBrowserRouter([  // ...  {    path: '/verify-email',    element: &lt;VerifyEmail /&gt;  }]);</code></pre><h4 id="411-zustand-状态管理更新"><a class="markdownIt-Anchor" href="#411-zustand-状态管理更新"></a> 4.1.1. Zustand 状态管理更新</h4><p>接下来，我们需要更新 Zustand 的用户状态管理，增加邮箱验证相关的状态的方法。</p><p>更新 <code>types.ts</code>，添加邮箱验证相关的枚举和接口：</p><pre><code class="language-ts">export enum EmailVerificationError {   TOKEN_INVALID = 'TOKEN_INVALID',   TOKEN_EXPIRED = 'TOKEN_EXPIRED',   ALREADY_VERIFIED = 'ALREADY_VERIFIED' }</code></pre><p>在实现邮箱验证功能时，我定义了三种可能的验证错误状态：</p><ol><li><code>TOKEN_INVALID</code>（无效令牌）</li></ol><ul><li>当用户提供的验证链接被篡改、不完整或不存在于系统</li><li>可能是用户误点击了错误的链接</li><li>可能是验证链接已被恶意修改</li><li>系统将拒绝这类验证请求，并显示错误提示</li></ul><ol start="2"><li><code>TOKEN_EXPIRED</code>（令牌过期）</li></ol><ul><li>验证链接已超过有效期限（24 小时）</li><li>防止长期未使用的过期链接被重复使用</li><li>用户需要重新请求发送验证邮件</li><li>提示用户链接已过期，需要重新获取</li></ul><ol start="3"><li><code>ALREADY_VERIFIED</code>（已验证）</li></ol><ul><li>用户尝试使用已经验证过的邮箱链接再次验证</li><li>可能是用户重复点击验证链接</li><li>系统将提示用户邮箱已成功验证</li><li>通常会直接引导用户登录</li></ul><pre><code class="language-ts">export interface VerificationResponse {   success: boolean;   message: string;   error?: EmailVerificationError;   userId?: string; }</code></pre><p>验证响应接口则设计了一个标准的响应接口：</p><ul><li>验证是否成功的标志</li><li>返回消息</li><li>可选的错误类型</li><li>可选的用户 ID</li></ul><pre><code class="language-ts">export interface UserState {  // ...  emailVerified: boolean;  verificationError?: EmailVerificationError;  verificationUserId?: string;  verificationInProgress: boolean;  verificationToken?: string;  verifyEmail: (token: string) =&gt; Promise&lt;VerificationResponse&gt;;  resendVerificationEmail: (userId: string) =&gt; Promise&lt;VerificationResponse&gt;;}</code></pre><h4 id="412-邮箱验证组件基础结构"><a class="markdownIt-Anchor" href="#412-邮箱验证组件基础结构"></a> 4.1.2. 邮箱验证组件基础结构</h4><p>在 <code>pages</code> 目录下创建 <code>VerifyEmail.tsx</code>。首先我们来构建组件的基本结构和状态管理：</p><pre><code class="language-tsx">import React, { useCallback, useEffect } from 'react'; import { useLocation, useNavigate } from 'react-router-dom'; import { useUserStore } from '../stores'; import { EmailVerificationError } from '../stores/user/types';const VerifyEmail = () =&gt; {   // 获取路由和导航相关钩子  const location = useLocation();   const navigate = useNavigate();   // 从 Zustand store 中获取状态和方法  const verifyEmail = useUserStore(state =&gt; state.verifyEmail);   const resendVerificationEmail = useUserStore(state =&gt; state.resendVerificationEmail);   const isLoading = useUserStore(state =&gt; state.isLoading);   const error = useUserStore(state =&gt; state.error);   const emailVerified = useUserStore(state =&gt; state.emailVerified);   const verificationError = useUserStore(state =&gt; state.verificationError);   const verificationUserId = useUserStore(state =&gt; state.verificationUserId);   const verificationInProgress = useUserStore(state =&gt; state.verificationInProgress);   // 渲染逻辑将在这里实现  return (     &lt;div className="min-h-screen flex items-center justify-center bg-base-200"&gt;       &lt;div className="card w-96 bg-base-100 shadow-xl"&gt;         &lt;div className="card-body items-center text-center"&gt;           &lt;h2 className="card-title mb-4"&gt;验证电子邮件&lt;/h2&gt;          {/* 不同状态的渲染将在这里实现 */}        &lt;/div&gt;      &lt;/div&gt;    &lt;/div&gt;  ); }; export default VerifyEmail;</code></pre><p>状态管理部分详解：</p><ul><li>从 Zustand store 中提取多个状态和方法</li><li><code>verifyEmail</code>：邮箱验证方法</li><li><code>resendVerificationEmail</code>：重新发送验证邮件方法</li><li><code>isLoading</code>：加载状态</li><li><code>error</code>：错误信息</li><li><code>emailVerified</code>：邮箱是否已验证</li><li><code>verificationError</code>：验证错误类型</li><li><code>verificationUserId</code>：用于重发验证邮件的用户 ID</li><li><code>verificationInProgress</code>：验证是否正在进行中</li></ul><p>接下来，我们实现邮箱验证的核心处理逻辑：</p><pre><code class="language-tsx">const handleVerification = useCallback(async (token: string) =&gt; {   try {     const result = await verifyEmail(token);     if (result.success) window.history.replaceState({}, '', window.location.pathname);     return result;   } catch (error) {     return {       success: false,       error: error instanceof Error ? error.message : '验证失败'     };   } }, [verifyEmail]);</code></pre><p>该方法的主要目的是处理邮箱验证逻辑。通过 <code>token</code> 调用 <code>verifyEmail</code> 函数，判断验证是否成功，并在页面历史状态中作出相应的更新。</p><p>这里使用了 <code>useCallback</code> 进行性能优化，确保在依赖项未变化时，返回的函数引用不会发生变化。</p><p><code>window.history.replaceState</code> 方法则是替换了当前历史记录的状态。当用户被验证成功后，<code>token</code> 会被移除，也避免了用户刷新页面时重复验证。</p><pre><code class="language-ts">const handleResendVerification = async () =&gt; {   if (verificationUserId) {     try {       const response = await resendVerificationEmail(verificationUserId);       if (response.success) {        navigate('/login', {           state: { message: '新的验证邮件已发送，请查收邮箱' }         });       }    } catch (error) {       console.error('重新发送验证邮件失败：', error);     }   } }</code></pre><p>这个函数的主要功能是为特定用户重新发送验证邮件。调用异步函数 <code>resendVerificationEmail</code> 成功后就会自动导航到登录页面。</p><p>添加两个 <code>useEffect</code> 钩子来管理验证流程：</p><pre><code class="language-tsx">// 处理邮箱验证useEffect(() =&gt; {   const searchParams = new URLSearchParams(location.search);   const token = searchParams.get('token');   const currentToken = useUserStore.getState().verificationToken;   if (token &amp;&amp; !verificationInProgress &amp;&amp; !emailVerified &amp;&amp; token !== currentToken) {     handleVerification(token).then(r =&gt; {       if (r.success &amp;&amp; 'message' in r) console.log('邮箱验证成功：', r.message);     });   } }, [handleVerification, verificationInProgress, emailVerified]); </code></pre><ol><li>使用 <code>URLSearchParams</code> 解析 <code>location.search</code>，获取查询参数中的 <code>token</code></li><li>在满足以下条件时调用 <code>handleVerification</code>：<ul><li>URL 中存在 <code>token</code></li><li>当前未在进行验证</li><li>邮箱尚未验证成功</li><li>传入的 <code>token</code> 不等于当前用户的 <code>verificationToken</code></li></ul></li><li>调用 <code>handleVerification</code> 处理邮箱验证</li></ol><pre><code class="language-tsx">// 处理验证成功后的跳转useEffect(() =&gt; {   if (emailVerified &amp;&amp; !isLoading) {     const redirectTimer = setTimeout(() =&gt; {       navigate('/login');     }, 1500);     return () =&gt; clearTimeout(redirectTimer);   } }, [emailVerified, isLoading, navigate]);</code></pre><ol><li>当 <code>emailVerified</code> 为 <code>true</code> 且 <code>isLoading</code> 为 <code>false</code> 时，触发跳转逻辑</li><li>使用 <code>setTimeout</code> 在 1.5 秒后执行 <code>navigate('/login')</code>，给用户留出视觉反馈时间</li><li>在组件卸载或依赖更新时，通过 <code>clearTimeout</code> 清除定时器，避免潜在内存泄漏或多余跳转</li></ol><p>最后，我们根据不同的验证状态渲染相应的界面：</p><pre><code class="language-tsx">return (   &lt;div className="min-h-screen flex items-center justify-center bg-base-200"&gt;     &lt;div className="card w-96 bg-base-100 shadow-xl"&gt;       &lt;div className="card-body items-center text-center"&gt;         &lt;h2 className="card-title mb-4"&gt;验证电子邮件&lt;/h2&gt;        {/* 加载中状态 */}        { isLoading &amp;&amp; (           &lt;div className="flex flex-col items-center gap-4"&gt;             &lt;span className="loading loading-spinner loading-lg" /&gt;             &lt;p&gt;正在验证您的电子邮件...&lt;/p&gt;           &lt;/div&gt;         )}        {/* 令牌过期状态 */}        { !isLoading &amp;&amp; verificationError === EmailVerificationError.TOKEN_EXPIRED &amp;&amp; (           &lt;div className="flex flex-col gap-4"&gt;             &lt;div className="alert alert-warning"&gt;               &lt;svg&gt;...&lt;/svg&gt;               &lt;span&gt;{error}&lt;/span&gt;             &lt;/div&gt;             &lt;button               className="btn btn-primary"               onClick={handleResendVerification}               disabled={isLoading}             &gt;               重新发送验证邮件             &lt;/button&gt;           &lt;/div&gt;         )}        {/* 已验证状态 */}        {!isLoading &amp;&amp; emailVerified &amp;&amp; (           &lt;div className="alert alert-success"&gt;             &lt;svg&gt;...&lt;/svg&gt;             &lt;span&gt;邮箱验证成功！即将跳转到登录页面...&lt;/span&gt;           &lt;/div&gt;         )}      &lt;/div&gt;    &lt;/div&gt;  &lt;/div&gt;);</code></pre><h4 id="413-邮件验证逻辑"><a class="markdownIt-Anchor" href="#413-邮件验证逻辑"></a> 4.1.3. 邮件验证逻辑</h4><p>上面说到了几个我们并没有写的方法：<code>verifyEmail</code> 和 <code>resendVerificationEmail</code>。</p><p>现在我们要在 <code>actions.ts</code> 中完善这两个方法。</p><p>先在文件开头位置导入 <code>types.ts</code> 中新增的内容：</p><pre><code class="language-ts">import {   User,   UserState,   LoginCredentials,   RegisterCredentials,   VerificationResponse } from './types';</code></pre><pre><code class="language-ts">const createUserSlice: StateCreator&lt;UserState&gt; = (set) =&gt; ({   // ...  emailVerified: false,   verificationError: undefined,   verificationUserId: undefined,   verificationInProgress: false,   verificationToken: undefined,   // ...});</code></pre><ol><li><p><code>verifyEmail</code> 方法：</p> <pre><code class="language-ts">verifyEmail: async (token: string): Promise&lt;VerificationResponse&gt; =&gt; {  // 下面继续...},</code></pre><p><code>verifyEmail</code> 方法的目的在于确保邮箱有效且记录验证状态。</p><p>首先为了避免用户重复提交相同的 <code>token</code>、导致不必要的 API 调用，我们需要检查当前的状态：</p><ul><li>若 <code>verificationInProgress</code> 为 <code>true</code>，那么就提示用户「验证正在进行中」</li><li>若 <code>emailVerified</code> 为 <code>true</code> 且 <code>verificationToken</code> 匹配，那么直接返回成功信息，避免重复请求</li></ul> <pre><code class="language-ts">const state = useUserStore.getState(); if (state.verificationInProgress || (state.verificationToken === token &amp;&amp; state.emailVerified)) {   return {     success: state.emailVerified,     message: state.emailVerified ? '邮箱已验证' : '验证正在进行中'   }; }</code></pre><p>进入验证流程前，我们需要确保应用的状态是明确的，并为用户显示验证的进度：</p> <pre><code class="language-ts">set({   isLoading: true,   error: null,   verificationInProgress: true,   verificationToken: token });</code></pre><p>验证邮箱地址需要服务端支持，因此发送带 <code>token</code> 的 API 请求进行校验（我这里设计的服务端 API 是要 <code>GET</code><br>的）：</p> <pre><code class="language-ts">try {  const response = await api.get(`/users/verify-email?token=${token}`);  const data = response.data;  // 下面继续...}</code></pre><p>验证成功后，更新状态以记录邮箱已验证，并清理其他临时状态：</p> <pre><code class="language-ts">try {  // ...  if (data.success) {     set({       isLoading: false,       error: null,       emailVerified: true,       verificationError: undefined,       verificationUserId: undefined,       verificationInProgress: false     });   }}</code></pre><p>如果验证失败，那就保存失败信息、供用户查看，并允许用户再次尝试：</p> <pre><code class="language-ts">try {  // ...  else {    set({       isLoading: false,       error: data.message,       emailVerified: false,       verificationError: data.error,       verificationUserId: data.userId,       verificationInProgress: false     });  }}</code></pre><p>当然，API 请求也有可能失败，我们需要显示错误提示、避免影响用户体验：</p> <pre><code class="language-ts">catch (error) {   const errorMessage = error instanceof Error     ? error.message     : '验证邮箱地址的过程中发生意外错误';   set({     isLoading: false,     error: errorMessage,     emailVerified: false,     verificationInProgress: false   });   return {     success: false,     message: errorMessage   }; }</code></pre></li><li><p><code>resendVerificationEmail</code> 方法</p><p>和 <code>verifyEmail</code> 基本上差不多：</p> <pre><code class="language-ts">resendVerificationEmail: async (userId: string) =&gt; {   set({ isLoading: true, error: null });   try {    const response = await api.post&lt;VerificationResponse&gt;(`/users/resend-verification/${userId}`);     const data = response.data;    set({       isLoading: false,       error: data.success ? null : data.message     });     return data;   } catch (error) {     const errorMessage = error instanceof Error       ? error.message       : '重新发送验证邮件失败';     set({       isLoading: false,       error: errorMessage     });     throw error;   } }, </code></pre></li></ol><h2 id="42-后端实现"><a class="markdownIt-Anchor" href="#42-后端实现"></a> 4.2. 后端实现</h2><p>在实现用户注册和邮箱验证功能时，我们通常会面临以下几个关键问题：</p><ol><li>如何确保用户提供的邮箱是真实有效的？</li><li>如何防止垃圾注册和恶意用户？</li><li>如何安全地管理用户的验证状态？</li></ol><h4 id="421-用户实体扩展"><a class="markdownIt-Anchor" href="#421-用户实体扩展"></a> 4.2.1. 用户实体扩展</h4><p>为了支持邮箱验证功能，我们要在 <code>Users</code> 实体中添加以下字段：</p><pre><code class="language-ts">@Column({ default: false })verified: boolean;@Column({ nullable: true })verificationToken: string;@Column({ nullable: true })verificationTokenExpires: Date;</code></pre><p>这三个新增字段解决了邮箱验证的核心需求：</p><ul><li><code>verified</code>：标记用户是否已验证邮箱</li><li><code>verificationToken</code>：存储唯一的验证令牌</li><li><code>verificationTokenExpires</code>：设置令牌的过期时间</li></ul><h4 id="422-用户服务中的邮箱验证逻辑"><a class="markdownIt-Anchor" href="#422-用户服务中的邮箱验证逻辑"></a> 4.2.2. 用户服务中的邮箱验证逻辑</h4><p>先在 <code>users.service.ts</code> 的上方引入我们需要的内容：</p><pre><code class="language-ts">import { ConflictException, Injectable, NotFoundException } from '@nestjs/common';import { v4 as uuidv4 } from 'uuid';import { EmailService } from '../email/email.service';import winstonLogger from '../loggers/winston.logger';export enum EmailVerificationError {  TOKEN_INVALID = 'TOKEN_INVALID',  TOKEN_EXPIRED = 'TOKEN_EXPIRED',  ALREADY_VERIFIED = 'ALREADY_VERIFIED'}interface VerificationResponse {  success: boolean;  message: string;  error?: EmailVerificationError;  userId?: string;}</code></pre><pre><code class="language-ts">@Injectable()export class UsersService {  private readonly logger = winstonLogger;  constructor(    @InjectRepository(Users)    private usersRepository: Repository&lt;Users&gt;,    private emailService: EmailService  ) {}  // ...}</code></pre><ol><li><p><code>create</code> 方法用于创建一个用户。当一个用户尝试注册自己时，系统应当通过以下步骤确保注册过程的安全性和可靠性：</p><ol><li><p>检查用户是否已存在，防止重复注册带来的冲突和逻辑错误：</p> <pre><code class="language-ts">async create(user: CreateUserDto): Promise&lt;{ id: string; email: string }&gt; {  const existingUser = await this.usersRepository.findOne({    where: [{ email: user.email }, { username: user.username }]  });  if (existingUser) {    this.logger.warn(`用户名为 ${user.username} 或者邮箱地址为 ${user.email} 的用户已存在`);    throw new ConflictException('用户名或邮箱已存在');  }  // 下面继续...}</code></pre></li><li><p>对用户密码进行加密后，生成验证令牌：</p> <pre><code class="language-ts">const hashedPassword = await bcrypt.hash(user.password, 10);const verificationToken = uuidv4();this.logger.debug('验证码已生成：' + verificationToken);</code></pre></li><li><p>结合用户信息和生成的安全数据，创建一个完整的用户对象：</p> <pre><code class="language-ts">const newUser = this.usersRepository.create({  ...user,  password: hashedPassword,  verificationToken,  verificationTokenExpires: new Date(Date.now() + 24 * 60 * 60 * 1000),  verified: false});this.logger.info('用户已被保存：' + JSON.stringify(newUser));</code></pre></li><li><p>将新用户记录写入数据库，完成用户创建：</p> <pre><code class="language-ts">const savedUser = await this.usersRepository.save(newUser);this.logger.debug('保存的用户：' + JSON.stringify(savedUser));</code></pre></li><li><p>发送验证邮件：</p> <pre><code class="language-ts">await this.emailService.sendVerificationEmail(savedUser);</code></pre></li><li><p>最终返回精简信息，避免返回敏感数据：</p> <pre><code class="language-ts">return {  id: savedUser.id,  email: savedUser.email};</code></pre></li></ol></li><li><p><code>verifyEmail</code> 方法用于验证用户邮箱。当用户点击验证链接时，系统通过该方法完成验证流程。此方法通过检查令牌的有效性和状态，确保邮箱验证的安全性和可靠性：</p><ol><li><p>根据提供的 <code>token</code> 查找用户，验证请求是否有效：</p> <pre><code class="language-ts">async verifyEmail(token: string): Promise&lt;VerificationResponse&gt; {  this.logger.debug(`接收到的 token：${token}`);  const user = await this.usersRepository.findOne({    where: {      verificationToken: token    }  });  if (!user) {    this.logger.debug(`验证失败：未找到对应 token 的用户，token：${token}`);    return {      success: false,      message: '无效的验证链接',      error: EmailVerificationError.TOKEN_INVALID    };  }  this.logger.debug(    `找到用户：${user.email}, 验证状态：${user.verified}, token 过期时间：${user.verificationTokenExpires}`  );  // 下面继续...}</code></pre></li><li><p>检查用户的验证状态。这里会有多个条件：</p><ol><li><p>用户是否已验证：</p> <pre><code class="language-ts">if (user.verified) {  this.logger.debug(`验证失败：用户 ${user.email} 已经验证过了`);  return {    success: false,    message: '邮箱已经验证过了',    error: EmailVerificationError.ALREADY_VERIFIED  };}</code></pre></li><li><p>验证令牌是否过期：</p> <pre><code class="language-ts">if (user.verificationTokenExpires &lt; new Date()) {  this.logger.debug(    `验证失败：token 已过期, 用户: ${user.email}, ` +      `过期时间：${user.verificationTokenExpires}, 当前时间：${new Date()}`  );  return {    success: false,    message: '验证链接已过期，请重新发送验证邮件',    error: EmailVerificationError.TOKEN_EXPIRED,    userId: user.id  };}</code></pre></li></ol></li><li><p>更新用户验证状态，将 <code>verified</code> 属性设置为 <code>true</code> 并保存到数据库：</p> <pre><code class="language-ts">user.verified = true;try {  await this.usersRepository.save(user);  this.logger.debug(`用户 ${user.email} 验证成功，已更新验证状态`);} catch (error) {  this.logger.error(`更新用户验证状态失败：${error.message}`, error.stack);  throw error;}</code></pre></li><li><p>返回成功信息，告诉调用方邮箱验证完成：</p> <pre><code class="language-ts">this.logger.debug(`验证流程完成，用户 ${user.email} 验证成功`);return {  success: true,  message: '邮箱验证成功'};</code></pre></li></ol></li><li><p><code>resendVerificationEmail</code> 方法用于重新发送验证邮件。当用户请求重发验证邮件时，此方法处理生成新的验证令牌并发送邮件的整个流程，确保未验证用户能够完成邮箱验证：</p><ol><li><p>通过 <code>userId</code> 查询目标用户，确保用户存在：</p> <pre><code class="language-ts">async resendVerificationEmail(userId: string): Promise&lt;VerificationResponse&gt; {  try {    const user = await this.findById(userId);    this.logger.debug(`找到用户：${user.email}, 当前验证状态：${user.verified}`);    // 下面继续...  }}</code></pre></li><li><p>检查用户的验证状态；用户是否已验证：</p> <pre><code class="language-ts">if (user.verified) {  this.logger.debug(`重发失败：用户 ${user.email} 已经验证过了`);  return {    success: false,    message: '邮箱已经验证过了',    error: EmailVerificationError.ALREADY_VERIFIED  };}</code></pre></li><li><p>生成新的验证令牌，确保安全性，并更新过期时间：</p> <pre><code class="language-ts">const oldToken = user.verificationToken;user.verificationToken = uuidv4();user.verificationTokenExpires = new Date(Date.now() + 24 * 60 * 60 * 1000);this.logger.debug(  `更新验证信息：用户：${user.email}, ` +    `旧 token：${oldToken}, ` +    `新 token：${user.verificationToken}, ` +    `过期时间：${user.verificationTokenExpires}`);</code></pre></li><li><p>保存用户数据：</p> <pre><code class="language-ts">await this.usersRepository.save(user);this.logger.debug(`用户验证信息已更新：${user.email}`);</code></pre></li><li><p>发送验证邮件：</p> <pre><code class="language-ts">await this.emailService.sendVerificationEmail(user);this.logger.debug(`验证邮件已重发至：${user.email}`);</code></pre></li><li><p>返回成功信息：</p> <pre><code class="language-ts">return {  success: true,  message: '验证邮件已重新发送'};</code></pre></li><li><p>如果出现异常，就得记录错误日志、返回失败消息：</p> <pre><code class="language-ts">catch (error) {  this.logger.error(`重发验证邮件失败：userId=${userId}, error=${error.message}`, error.stack);  return {    success: false,    message: '重新发送验证邮件失败',    error: EmailVerificationError.TOKEN_INVALID  };}</code></pre></li></ol></li></ol><h4 id="423-用户控制器新增接口"><a class="markdownIt-Anchor" href="#423-用户控制器新增接口"></a> 4.2.3. 用户控制器新增接口</h4><p>我们需要以下两个接口：</p><ol><li><code>GET /verify-email</code>：通过查询参数接收验证 <code>token</code>，完成用户邮箱验证</li><li><code>POST /resend-verification/:id</code>：接收用户 <code>id</code>，重新发送验证邮件</li></ol><pre><code class="language-ts">@ApiOperation({ summary: '验证用户邮箱' })@ApiQuery({ name: 'token', description: '验证token' })@ApiResponse({ status: HttpStatus.OK, description: '邮箱验证成功' })@HttpCode(HttpStatus.OK)@Get('verify-email')async verifyEmail(@Query('token') token: string): Promise&lt;{ message: string }&gt; {  return this.usersService.verifyEmail(token);}@ApiOperation({ summary: '重新发送验证邮件' })@ApiParam({ name: 'id', description: '用户ID' })@ApiResponse({ status: HttpStatus.OK, description: '验证邮件已重新发送' })@HttpCode(HttpStatus.OK)@Post('resend-verification/:id')async resendVerification(@Param('id') id: string): Promise&lt;{ message: string }&gt; {  return this.usersService.resendVerificationEmail(id);}</code></pre><blockquote><p>关于 <code>HttpStatus</code> 和 <code>@HttpCode</code>，请见 <a href="#52-%E4%BF%AE%E6%94%B9-swagger-%E6%A0%87%E7%AD%BE">这里</a>。</p></blockquote><h4 id="424-开发邮件模块"><a class="markdownIt-Anchor" href="#424-开发邮件模块"></a> 4.2.4. 开发邮件模块</h4><p>安装邮件模块 <code>@nestjs-modules/mailer</code>：</p><pre><code class="language-bash">yarn add @nestjs-modules/mailer</code></pre><p>在 <code>src</code> 目录下创建 <code>email</code> 目录，并在内创建 <code>email.module.ts</code>：</p><pre><code class="language-ts">import { Module } from '@nestjs/common';import { MailerModule } from '@nestjs-modules/mailer';import { ConfigService } from '@nestjs/config';import { HandlebarsAdapter } from '@nestjs-modules/mailer/dist/adapters/handlebars.adapter';import { join } from 'path';import { EmailService } from './email.service';@Module({  imports: [    MailerModule.forRootAsync({      useFactory: async (configService: ConfigService) =&gt; {        const transport = {          host: configService.getOrThrow&lt;string&gt;('SMTP_HOST'),          port: configService.getOrThrow&lt;number&gt;('SMTP_PORT'),          secure: false,          auth: {            user: configService.getOrThrow&lt;string&gt;('SMTP_USER'),            pass: configService.getOrThrow&lt;string&gt;('SMTP_PASS')          }        };        return {          transport,          defaults: {            from: `"Shopping Nest" &lt;${configService.getOrThrow&lt;string&gt;('SMTP_FROM_ADDRESS')}&gt;`          },          template: {            dir: join(__dirname, 'templates'),            adapter: new HandlebarsAdapter(),            options: {              strict: true            }          }        };      },      inject: [ConfigService]    })  ],  providers: [EmailService],  exports: [EmailService]})export class EmailModule {}</code></pre><blockquote><p>我们需要在 <code>.env</code> 里新增几个值：</p><pre><code class="language-plaintext">SMTP_HOST=SMTP_PORT=SMTP_USER=SMTP_PASS=SMTP_FROM_ADDRESS=</code></pre><p>这些是常见的 SMTP（Simple Mail Transfer Protocol）配置参数，用于设置邮件服务器的基本信息以发送电子邮件。</p><ol><li><p><code>SMTP_HOST</code>：邮件服务器的主机地址，通常是邮件服务提供商的域名或 IP 地址（例如用 Gmail 的话就是写 <code>smtp.gmail.com</code>）</p></li><li><p><code>SMTP_PORT</code>：邮件服务器使用的端口号，用于建立与邮件服务器的连接</p><ul><li>常用端口：<ul><li><code>587</code>：用于明文连接后升级为加密连接（STARTTLS）</li><li><code>465</code>：用于加密连接（SSL / TLS）</li><li><code>25</code>：传统的 SMTP 端口，可能被 ISP 限制</li></ul></li><li><code>587</code> 或 <code>465</code> 是现代邮件服务中最常见的选择</li></ul></li><li><p><code>SMTP_USER</code>：用于身份验证的用户名，通常是发送邮件的邮箱地址</p></li><li><p><code>SMTP_PASS</code>：与 <code>SMTP_USER</code> 对应的密码，用于 SMTP 身份验证（一些服务 —— 如 Gmail—— 可能要求使用应用专用密码而不是账户密码）</p></li><li><p><code>SMTP_FROM_ADDRESS</code>：邮件发送的来源地址，显示为邮件的 <code>From</code> 字段，通常是一个经过认证的邮箱地址</p><ul><li><code>no-reply@yourdomain.com</code>（用于自动邮件）</li><li><code>support@yourdomain.com</code>（用于支持邮件）</li><li>有些服务可能要求 <code>SMTP_FROM_ADDRESS</code> 必须与 <code>SMTP_USER</code> 保持一致（我使用的 MailGun 就是如此）</li></ul></li></ol></blockquote><blockquote><p>Handlebars 是一个简单但强大的模板语言，允许我们通过 <code>{{变量}}</code> 语法轻松插入动态内容。它支持部分模板（Partials），让我们可以模块化地构建电子邮件模板。</p><p>部分模版示例：</p><pre><code class="language-hbs">&lt;header class="email-header"&gt;  &lt;div class="logo"&gt;    &lt;img src="{{ base64Image }}" alt="Logo" style="max-height: 50px;"&gt;  &lt;/div&gt;&lt;/header&gt;</code></pre><p>我们希望邮件的内容是动态生成的，并且邮件的布局或样式能够灵活调整，那么就需要结合模板引擎来渲染邮件内容。</p></blockquote><p>接着创建 <code>email.service.ts</code>，它会封装邮件发送的所有复杂逻辑：</p><ol><li><p>导入模块并初始化：</p> <pre><code class="language-ts">import { Injectable } from '@nestjs/common';import { ConfigService } from '@nestjs/config';import { MailerService } from '@nestjs-modules/mailer';import { readFileSync, existsSync } from 'fs';import { join, resolve } from 'path';import { execSync } from 'child_process';import * as HandleBars from 'handlebars';import { Users } from '../entities/users.entity';import winstonLogger from '../loggers/winston.logger';@Injectable()export class EmailService {  private readonly logger = winstonLogger;  private readonly templatesDir: string;  private readonly partialsDir: string;  // 下面继续...}</code></pre></li><li><p>在构造函数中注入 <code>ConfigService</code> 和 <code>MailerService</code>。同时设置模板目录和部分模板目录的路径：</p> <pre><code class="language-ts">constructor(    private configService: ConfigService,    private mailerService: MailerService  ) {    this.templatesDir = resolve(__dirname, 'templates');    this.partialsDir = resolve(this.templatesDir, 'partials');  }</code></pre></li><li><p>初始化模块：</p> <pre><code class="language-ts">async onModuleInit() {  this.ensureTemplatesExist();  await this.registerPartials();}</code></pre><ul><li><code>onModuleInit</code> 方法会在模块初始化时被调用</li><li><code>ensureTemplatesExist</code> 方法应当是检查模板是否存在，如果不存在则通过执行命令 `yarn copy-templates 来复制模板文件</li><li><code>registerPartials</code> 方法则用于注册模板中的部分文件，确保这些部分模板可以在主模板中引用</li></ul></li><li><p>确保模板文件存在：</p> <pre><code class="language-ts">private ensureTemplatesExist() {  if (!existsSync(this.templatesDir)) {    this.logger.warn('dist 中无法找到 templates，复制中...');    execSync('yarn copy-templates');  }}</code></pre><p>该方法检查模板文件夹是否存在。如果文件夹不存在，则执行命令将模板文件复制过来。</p><p>这确保了在构建后的 <code>dist</code> 文件夹中也能找到模板文件。</p><blockquote><p>这需要在 <code>package.json</code> 里定义一条命令：</p><pre><code class="language-json">"scripts": {  // ...   "copy-templates": "copyfiles -u 3 src/email/templates/**/* dist/email/templates"}</code></pre><blockquote><p><code>copyfiles</code> 用法：</p><ol><li><p>安装 <code>copyfiles</code> 为开发依赖（或者直接全局安装）：</p> <pre><code class="language-bash">yarn add -D copyfiles</code></pre></li><li><p>如果是复制 <code>src</code> 下的所有 <code>.js</code> 文件到 <code>dist</code>，且保留目录结构：</p> <pre><code class="language-bash">yarn copyfiles 'src/**/*.js' dist/</code></pre></li><li><p>不保留目录结构：</p> <pre><code class="language-bash">yarn copyfiles -f 'src/**/*.js' dist/</code></pre></li></ol></blockquote><p><code>copyfiles -u 3 src/email/templates/**/* dist/email/templates</code> 的含义是将 <code>src/email/templates/</code> 文件夹下的所有文件和子文件夹复制到 <code>dist/email/templates/</code>，并通过 <code>-u 3</code> 参数调整复制时的目标路径结构。</p><p>其中 <code>-u 3</code> 表示忽略源路径中从末尾数起的 3 个目录层级，也就是不包含这些层级到目标路径中。</p></blockquote><p><code>ensureTemplatesExist</code> 方法解决了 NestJS 项目中、构建过程不会自动复制静态资源文件的问题。</p><p>当执行 <code>yarn build</code> 时，TypeScript 编译器只处理 <code>.ts</code> 文件。静态模板和资源不会自动复制到 <code>dist</code> 目录。</p></li><li><p>注册部分模板：</p> <pre><code class="language-ts">private async registerPartials() {  const partials = [    { name: 'header', file: 'header.hbs' },    { name: 'footer', file: 'footer.hbs' },    { name: 'styles', file: 'styles.hbs' }  ];  for (const partial of partials) {    const partialPath = join(this.partialsDir, partial.file);    if (!existsSync(partialPath)) {      this.logger.error(`部分模板文件不存在：${partialPath}`);      throw new Error(`找不到部分模板文件：${partial.file}`);    }    try {      const template = readFileSync(partialPath, 'utf8');      HandleBars.registerPartial(partial.name, template);      this.logger.debug(`成功注册部分模板：${partial.name}`);    } catch (error) {      this.logger.error(`注册部分模板失败：${partial.name}`, {        error: error.message,        stack: error.stack,        path: partialPath      });      throw error;    }  }}</code></pre><p>在模板中，通常会有一些公共部分（如页头、页脚、样式等），这些部分可以通过 Handlebars 的 <code>registerPartial</code> 方法来注册，之后可以在主模板中调用。</p><p>这里的三个 <code>.hbs</code> 文件会在后面完善。</p></li><li><p>编译模板：</p> <pre><code class="language-ts">private async compileTemplate(templateName: string, context: any): Promise&lt;string&gt; {  const templatePath = join(this.templatesDir, `${templateName}.hbs`);  if (!existsSync(templatePath)) {    this.logger.error(`模板文件不存在：${templatePath}`);    throw new Error(`找不到模板文件：${templateName}.hbs`);  }  try {    const templateContent = readFileSync(templatePath, 'utf8');    const template = HandleBars.compile(templateContent);    return template(context);  } catch (error) {    this.logger.error('编译模板失败', {      error: error.message,      stack: error.stack,      template: templateName,      path: templatePath    });    throw error;  }}</code></pre><p><code>compileTemplate</code> 方法用于读取模板文件并将其编译为 HTML 内容。它通过 <code>Handlebars.compile</code> 将模板文件内容编译为渲染函数，然后使用传入的 <code>context</code> 对象（包含动态内容）来渲染模板。</p></li><li><p>发送验证邮件：</p> <pre><code class="language-ts">async sendVerificationEmail(user: Users) {  const logoPath = join(__dirname, '../assets/ShoppingNest.png');  this.logger.debug('Logo Path：' + logoPath);  const logoBase64 = readFileSync(logoPath).toString('base64');  const logoMimeType = 'image/png';  const base64Image = `data:${logoMimeType};base64,${logoBase64}`;  const frontendUrl = this.configService.get&lt;string&gt;('CORS_ORIGIN');  const verificationUrl = `${frontendUrl}/verify-email?token=${user.verificationToken}`;  try {    const html = await this.compileTemplate('verification', {      username: user.username,      verificationUrl,      expiresIn: '24小时',      year: new Date().getFullYear(),      base64Image    });    await this.mailerService.sendMail({      to: user.email,      subject: '验证你的邮箱地址',      html    });    this.logger.info(`验证邮件已成功发送至 ${user.email}`);  } catch (error) {    this.logger.error('发送验证邮件失败', {      error: error.message,      stack: error.stack,      user: user.email    });    throw new Error(`发送验证邮件失败：${error.message}`);  }}</code></pre><p>首先，读取图片文件并将其转换为 base64 格式，之后拼接验证链接，并使用 Handlebars 模板渲染邮件内容。</p><p>最后调用 <code>MailerService.sendMail</code> 发送邮件。</p><blockquote><p>图片位置被我写在了 <code>src/assets</code> 目录中。但是它和 <code>src/email/templates</code> 目录一样，有着不会被自动复制到 <code>dist</code> 目录的问题。</p><p>解决方法也很简单，同样在 <code>package.json</code> 中定义一个命令：</p><pre><code class="language-json">"scripts": {  // ...  "copy-assets": "copyfiles -u 2 src/assets/**/* dist/assets"}</code></pre><p>然后在 <code>app.service.ts</code> 被初始化时调用（也可以在 <code>email.service.ts</code> 中调用，只是我认为 <code>src/assets</code> 内的静态文件并不是仅被邮件模块使用）：</p><pre><code class="language-ts">async onModuleInit() {  this.ensureAssetsExist();}private ensureAssetsExist() {  const assetsPath = resolve(__dirname, 'assets');  if (!existsSync(assetsPath)) {    this.logger.warn('dist 中无法找到 assets，复制中...');    execSync('yarn copy-assets');  }}</code></pre></blockquote></li></ol><p>现在我们可以开始写验证邮件的实际内容了：</p><ol><li><p>在 <code>src/email</code> 目录下创建 <code>templates</code> 目录，并创建 <code>verification.hbs</code>，作为验证邮件的主体模板：</p> <pre><code class="language-hbs">&lt;!DOCTYPE html&gt;&lt;html lang="zh"&gt;&lt;head&gt;  &lt;meta charset="utf-8"&gt;  &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;  &lt;title&gt;验证你的邮箱地址&lt;/title&gt;  &lt;style&gt;      {{&gt; styles}}  &lt;/style&gt;&lt;/head&gt;&lt;body&gt;{{&gt; header}}&lt;div class="email-content"&gt;  &lt;h2&gt;您好，{{username}}！&lt;/h2&gt;  &lt;p&gt;感谢您注册我们的服务。请点击下面的按钮验证您的邮箱地址：&lt;/p&gt;  &lt;div class="button-container"&gt;    &lt;a href="{{verificationUrl}}" class="verify-button"&gt;验证邮箱&lt;/a&gt;  &lt;/div&gt;  &lt;p&gt;如果上面的按钮无法点击，请复制以下链接到浏览器地址栏：&lt;/p&gt;  &lt;p class="verification-url"&gt;{{verificationUrl}}&lt;/p&gt;  &lt;p&gt;此验证链接将在{{expiresIn}}后过期。&lt;/p&gt;  &lt;p&gt;如果您没有注册我们的服务，请忽略此邮件。&lt;/p&gt;&lt;/div&gt;{{&gt; footer}}&lt;/body&gt;&lt;/html&gt;</code></pre><p>这里使用了三个动态内容插值：</p><ol><li><code>{{username}}</code>：动态填充用户名称</li><li><code>{{verification}}</code>：用户唯一的验证链接</li><li><code>{{expiresIn}}</code>：链接有效期提示</li></ol></li><li><p>在 <code>src/email/templates</code> 目录下创建 <code>partials</code> 目录，并在内创建 <code>header.hbs</code>：</p> <pre><code class="language-hbs">&lt;header class="email-header"&gt;&lt;div class="logo"&gt;  &lt;img src="{{ base64Image }}" alt="Logo" style="max-height: 50px;"&gt;&lt;/div&gt;&lt;/header&gt;</code></pre><p>这里的 <code>style</code> 可以根据自己的 Logo 图片进行调整。</p><blockquote><p>其实还有一种方法，是在前端项目中的 <code>public</code> 目录里放 Logo 图片，然后这里直接调用 <code>前端链接/图片文件名称.图片文件类型</code>。</p><p>但是这意味着如果前端项目是在本地环境运行的，图片链接便无效。</p></blockquote></li><li><p>在 <code>src/email/templates/partials</code> 目录下创建 <code>footer.hbs</code>：</p> <pre><code class="language-hbs">&lt;footer class="email-footer"&gt;  &lt;p&gt;© {{year}} 你的公司名称. 保留所有权利。&lt;/p&gt;  &lt;p&gt;此邮件由系统自动发送，请勿回复。&lt;/p&gt;&lt;/footer&gt;</code></pre><p>这里可以自行修改。</p></li><li><p>在 <code>src/email/templates/partials</code> 目录下创建 <code>styles.hbs</code>：</p> <pre><code class="language-hbs">body {  margin: 0;  padding: 0;  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;  line-height: 1.6;  color: #333;  background-color: #f9f9f9;}.email-header {  text-align: center;  padding: 20px;  background-color: #ffffff;  border-bottom: 1px solid #eee;}.email-content {  max-width: 600px;  margin: 0 auto;  padding: 20px;  background-color: #ffffff;  border-radius: 8px;  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);}.button-container {  text-align: center;  margin: 30px 0;}.verify-button {  display: inline-block;  padding: 12px 24px;  background-color: #4CAF50;  color: #ffffff;  text-decoration: none;  border-radius: 5px;  font-weight: bold;  transition: background-color 0.3s;}.verify-button:hover {  background-color: #45a049;}.verification-url {  word-break: break-all;  padding: 10px;  background-color: #f5f5f5;  border-radius: 4px;  font-family: monospace;}.email-footer {  text-align: center;  padding: 20px;  color: #666;  font-size: 0.9em;}</code></pre><p>同样可以自行修改。</p></li></ol><p>最后便是在各个模块中进行引用：</p><ol><li><p><code>users.module.ts</code>：</p> <pre><code class="language-ts">import { Module } from '@nestjs/common';import { TypeOrmModule } from '@nestjs/typeorm';import { UsersController } from './users.controller';import { UsersService } from './users.service';import { Users } from '../entities/users.entity';import { EmailModule } from '../email/email.module';@Module({  imports: [TypeOrmModule.forFeature([Users]), EmailModule],  controllers: [UsersController],  providers: [UsersService],  exports: [UsersService]})export class UsersModule {}</code></pre></li><li><p><code>app.module.ts</code>：</p> <pre><code class="language-ts">// ...import { EmailModule } from './email/email.module';@Module({  imports: [    ConfigModule.forRoot({      isGlobal: true,      validationSchema: Joi.object({        // ...        CORS_ORIGIN: Joi.string().required(),        // SMTP 配置        SMTP_HOST: Joi.string().required(),        SMTP_PORT: Joi.number().required(),        SMTP_USER: Joi.string().required(),        SMTP_PASS: Joi.string().required(),        SMTP_FROM_ADDRESS: Joi.string().required()      })    }),    // ...    EmailModule  ]})</code></pre></li></ol><h1 id="5-其他"><a class="markdownIt-Anchor" href="#5-其他"></a> 5. 其他</h1><h2 id="51-修改-http-exceptionfilterts"><a class="markdownIt-Anchor" href="#51-修改-http-exceptionfilterts"></a> 5.1. 修改 <code>http-exception.filter.ts</code></h2><pre><code class="language-ts">import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';import winstonLogger from '../loggers/winston.logger';@Catch()export class HttpExceptionFilter implements ExceptionFilter {  private readonly logger = winstonLogger;  catch(exception: unknown, host: ArgumentsHost) {    const ctx = host.switchToHttp();    const response = ctx.getResponse();    const request = ctx.getRequest();    const status = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;    const errorResponse = {      statusCode: status,      timestamp: new Date().toISOString(),      path: request.url,      message: exception instanceof HttpException ? exception.getResponse() : 'Internal server error'    };    // 用 winstonLogger 输出异常    if (exception instanceof HttpException) {      this.logger.warn(`HTTP 异常：${JSON.stringify(errorResponse)}`);    } else {      this.logger.error(`未处理异常：${exception}`);    }    response.status(status).json(errorResponse);  }}</code></pre><h2 id="52-修改-swagger-标签"><a class="markdownIt-Anchor" href="#52-修改-swagger-标签"></a> 5.2. 修改 Swagger 标签</h2><p>从</p><pre><code class="language-ts">@ApiResponse({ status: 200, description: 'xxx' })</code></pre><p>统统修改为</p><pre><code class="language-ts">@ApiResponse({ status: HttpStatus.OK, description: 'xxx' })@HttpCode(HttpStatus.OK)</code></pre><p>状态码本身是数字，对于大多数人而言并不直观、需要对其有较深的理解。若需要统一调整状态码（如规范化状态码的使用），代码中可能需要逐一查找和替换。更何况状态码本身也更容易被误写为其他数字，难以自动检测错误。</p><p>而枚举值提供了清晰的语义，直接描述了状态码的含义，因此更容易理解。当需要统一调整时，可以直接通过 IDE 的自动补全功能快速选择合适的状态码。</p><p>以下为对应：</p><table><thead><tr><th>HTTP 状态码</th><th><code>HttpStatus</code> 枚举值</th></tr></thead><tbody><tr><td><code>200</code></td><td><code>OK</code></td></tr><tr><td><code>201</code></td><td><code>CREATED</code></td></tr><tr><td><code>204</code></td><td><code>NO_CONTENT</code></td></tr><tr><td><code>400</code></td><td><code>BAD_REQUEST</code></td></tr><tr><td><code>401</code></td><td><code>UNAUTHORIZED</code></td></tr><tr><td><code>404</code></td><td><code>NOT_FOUND</code></td></tr><tr><td><code>409</code></td><td><code>CONFLICT</code></td></tr><tr><td><code>500</code></td><td><code>INTERNAL_SERVER_ERROR</code></td></tr></tbody></table><h2 id="53-清空数据库中所有表的内容"><a class="markdownIt-Anchor" href="#53-清空数据库中所有表的内容"></a> 5.3. 清空数据库中所有表的内容</h2><p>在开发和测试中，尤其是运行集成测试或重置开发环境时，可能需要快速清空数据库中的所有表数据。</p><p>我根据 MySQL 写了一个清空所有表数据的脚本，确保测试数据或旧数据被完全移除，便于后续的干净测试或初始化操作。</p><pre><code class="language-ts">import dataSource from '../config/data-source';async function deleteAllData() {  try {    await dataSource.initialize();    console.log('已连接到数据库');    const entityMetadatas = dataSource.entityMetadatas;    const totalTables = entityMetadatas.length;    await dataSource.query('BEGIN');    await dataSource.query('SET FOREIGN_KEY_CHECKS = 0');    for (let i = 0; i &lt; totalTables; i++) {      const entityMetadata = entityMetadatas[i];      const tableName = entityMetadata.tableName;      const startTime = Date.now();      try {        console.log(`清空表：${tableName}`);        await dataSource.query(`TRUNCATE TABLE \`${tableName}\``);        const elapsedTime = (Date.now() - startTime) / 1000;        console.log(`清空表 (${i + 1}/${totalTables}): ${tableName} 完成，耗时: ${elapsedTime.toFixed(2)} 秒`);      } catch (error) {        console.error(`清空表 ${tableName} 时报错：`, error);      }    }    await dataSource.query('COMMIT');    console.log('所有表都被清空');  } catch (error) {    console.error('删除数据期间报错：', error);    await dataSource.query('ROLLBACK');  } finally {    await dataSource.query('SET FOREIGN_KEY_CHECKS = 1');    await dataSource.destroy();  }}deleteAllData().catch(error =&gt; {  console.error('删除数据期间报错：', error);});</code></pre><p>可以在 <code>package.json</code> 中添加以下命令来使用：</p><pre><code class="language-json">"scripts": {  // ...  "delete-all-data": "ts-node src/database/delete-all-data.ts"}</code></pre></body></html>]]></content>
    
    
    <summary type="html">本文是 React + NestJS 全栈购物平台实践的第四篇，专注于实现完整的用户注册与邮箱验证功能。前端部分，教程详细讲解了如何使用 Formik 和 Yup 构建带实时校验的注册表单，并通过 Zustand 进行全局状态管理。后端部分，则深入实现了用户注册 API，涵盖了密码的 bcrypt 加密、数据库操作，并集成了邮件服务以发送验证链接。此外，文章还分享了开发过程中遇到的 BUG 及其解决方案，为构建一个安全、可靠的用户认证流程提供了详尽的实战指导。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="全栈实践" scheme="https://blog.cytrogen.icu/tags/%E5%85%A8%E6%A0%88%E5%AE%9E%E8%B7%B5/"/>
    
    <category term="Node.js" scheme="https://blog.cytrogen.icu/tags/Node-js/"/>
    
    <category term="React.js" scheme="https://blog.cytrogen.icu/tags/React-js/"/>
    
    <category term="TypeScript" scheme="https://blog.cytrogen.icu/tags/TypeScript/"/>
    
    <category term="NestJS" scheme="https://blog.cytrogen.icu/tags/NestJS/"/>
    
  </entry>
  
  <entry>
    <title>React + NestJS 购物平台练习【3】数据设计与实现</title>
    <link href="https://blog.cytrogen.icu/posts/5a4b.html"/>
    <id>https://blog.cytrogen.icu/posts/5a4b.html</id>
    <published>2024-11-07T05:00:00.000Z</published>
    <updated>2026-02-09T17:16:54.997Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>搭建完前端与后端的基础结构后，我们就可以开始着手于数据库设计了。</p><span id="more"></span><h1 id="1-设计基础实体"><a class="markdownIt-Anchor" href="#1-设计基础实体"></a> 1. 设计基础实体</h1><p>在设计我们的购物平台的过程中，实体及其关系是核心的数据模型。我们从业务逻辑的角度来看，每个实体的意义和作用，这样可以更好地理解其在系统中的角色。</p><p>这里，我们以「用户」、「商品」、「订单」等为主线，讲解如何建立这些实体以及它们之间的关系，并举例说明其在业务场景中的应用。</p><h2 id="11-用户"><a class="markdownIt-Anchor" href="#11-用户"></a> 1.1. 用户</h2><p>用户实体是系统的核心，因为大部分操作都需要绑定到用户。每个用户都有其唯一的 ID、用户名、邮箱和密码，这些信息用于身份验证和授权。</p><blockquote><p>示例，一个用户 <code>John Doe</code> 创建了账号，并通过邮箱 <code>johndoe@example.com</code> 登录系统。数据库会在 <code>Users</code> 表中新增一条记录，保存 John 的邮箱、加密密码和创建时间。</p></blockquote><h4 id="111-代码实现分析"><a class="markdownIt-Anchor" href="#111-代码实现分析"></a> 1.1.1. 代码实现分析</h4><p>让我们深入分析 <code>Users</code> 实体的代码实现：</p><pre><code class="language-ts">import {  Entity,  PrimaryGeneratedColumn,  Column,  CreateDateColumn,  UpdateDateColumn,  OneToMany,  OneToOne} from 'typeorm';@Entity()export class Users {  @PrimaryGeneratedColumn('uuid')  id: string;  @Column({ unique: true })  username: string;  @Column({ unique: true })  email: string;  @Column()  password: string;  @CreateDateColumn()  created_at: Date;  @UpdateDateColumn()  updated_at: Date;  // ...}</code></pre><p>这部分使用了 TypeORM 的装饰器来定义表结构：</p><ul><li><code>@Entity()</code> 装饰器将这个类标记为一个数据库实体</li><li><code>@PrimaryGeneratedColumn('uuid')</code> 表示自动生成 <code>UUID</code> 作为主键</li><li><code>@Column({ unique: true })</code> 为用户名和邮箱添加了唯一性约束，防止重复注册</li><li><code>@CreateDateColumn()</code> 会自动记录实体的创建时间</li><li><code>@UpdateDateColumn()</code> 会自动记录实体的更新时间</li></ul><p>用户表的字段及其业务含义如下：</p><ul><li><code>id</code>：主键，用于唯一标识每个用户，类型为 <code>UUID</code>，确保安全性和唯一性</li><li><code>username</code>：用户名，系统中用于显示的名称，通常在用户之间是唯一的</li><li><code>email</code>：用户的邮箱，通常作为主要联系手段，同时也是登录的标识之一</li><li><code>password</code>：用户密码，以加密方式存储，用于用户验证</li><li><code>created_at</code> 和 <code>updated_at</code>：创建时间和更新时间，记录用户注册和资料更新的时间</li></ul><h4 id="112-关联关系分析"><a class="markdownIt-Anchor" href="#112-关联关系分析"></a> 1.1.2. 关联关系分析</h4><p><code>Users</code> 实体与其他实体之间建立了多个关联关系：</p><pre><code class="language-ts">import { Orders } from './orders.entity';import { Carts } from './carts.entity';import { Addresses } from './addresses.entity';import { Payments } from './payments.entity';@Entity()export class Users {    // ...    @OneToMany(() =&gt; Orders, order =&gt; order.user)    orders: Orders[];    @OneToOne(() =&gt; Carts, cart =&gt; cart.user)    cart: Carts;    @OneToMany(() =&gt; Addresses, address =&gt; address.user)    addresses: Addresses[];    @OneToMany(() =&gt; Payments, payment =&gt; payment.user)    payments: Payments[];}</code></pre><p>这些关联展示了用户实体在系统中的核心地位：</p><ol><li>用户 - 订单关系（<code>@OneToMany</code>）<ul><li>一个用户可以有多个订单</li><li>这种一对多的关系允许系统追踪用户的所有购买历史</li></ul></li><li>用户 - 购物车关系（<code>@OneToOne</code>）<ul><li>每个用户只能有一个购物车</li><li>一对一的关系确保购物车数据的独立性和安全性</li></ul></li><li>用户 - 地址关系（<code>@OneToMany</code>）<ul><li>用户可以保存多个收货地址</li><li>方便用户在下单时快速选择收货地址</li></ul></li><li>用户 - 支付关系（<code>@OneToMany</code>）<ul><li>记录用户的所有支付记录</li><li>用于追踪交易历史和财务统计</li></ul></li></ol><h4 id="113-用户角色"><a class="markdownIt-Anchor" href="#113-用户角色"></a> 1.1.3. 用户角色</h4><p>在开发应用程序时，管理用户的权限和访问控制是至关重要的。这是因为不同类型的用户可能需要访问系统的不同功能。</p><p>例如，一个购物平台可能有以下几种角色：</p><ul><li>管理员：可以管理用户、查看所有订单、编辑商品等</li><li>普通用户：只能查看商品、下订单、查看个人资料等</li><li>游客：仅限浏览，不进行任何交互</li></ul><p>在这种场景下，我们需要为用户管理系统添加一个角色字段，以便区分不同的用户类型。</p><p>角色字段通常有助于完成以下任务：</p><ul><li>不同权限管理：每种角色都有不同的权限。管理员可能有权访问系统的所有数据，而普通用户只能查看他们自己的数据。通过角色字段，我们可以在数据库中存储每个用户的角色信息</li><li>角色控制的用户界面：角色字段可以帮助系统为不同角色的用户显示不同的页面或功能。例如，管理员可以访问管理控制台，而普通用户只能看到他们的订单历史</li><li>安全性增强：通过角色字段，系统可以在后端进行权限验证，确保不同角色的用户只能执行允许他们执行的操作，避免了恶意操作或权限滥用</li></ul><p>为了明确区分不同角色的值，通常我们会使用枚举（<code>enum</code>）来为角色提供固定的值。</p><blockquote><p><code>enum</code> 是一种特殊的类，用来表示一组固定的常量。</p></blockquote><p>通过将 <code>role</code> 字段设置为枚举类型，我们可以确保角色值仅限于我们定义的固定值，这些值会自动被 TypeORM 映射到数据库字段中。</p><pre><code class="language-ts">// 添加角色的枚举类型export enum UserRole {  ADMIN = 'admin',  USER = 'user',  GUEST = 'guest',}@Entity()export class Users {  // ...  // 在 Users 实体中添加 role 字段  @Column({    type: 'enum',    enum: UserRole,    default: UserRole.USER,  // 默认值为普通用户  })  role: UserRole;}</code></pre><h2 id="12-商品"><a class="markdownIt-Anchor" href="#12-商品"></a> 1.2. 商品</h2><p>商品实体是平台中与交易直接相关的核心实体，它承载了商品的基本信息、库存管理、定价等重要功能。一个设计良好的商品实体不仅要满足基本的展示需求，还要支持库存管理、订单处理等复杂业务场景。</p><p>商品表的作用是提供系统中可供购买的商品清单，记录商品价格和库存。在库存管理方面，当库存减少到零时，商品需要标记为「缺货」或「下架」。</p><blockquote><p>示例，商家上架了一款新商品「智能手表」，库存数量为 100，售价为 200 元，商品类别为「电子产品」。这款商品的信息会存储在 <code>Products</code> 表中，供用户选择和购买。</p></blockquote><h4 id="121-代码实现分析"><a class="markdownIt-Anchor" href="#121-代码实现分析"></a> 1.2.1. 代码实现分析</h4><p>让我们详细分析 <code>Products</code> 实体的代码实现：</p><pre><code class="language-ts">import {  Entity,  PrimaryGeneratedColumn,  Column,  CreateDateColumn,  UpdateDateColumn,  ManyToOne,  OneToMany} from 'typeorm';@Entity()export class Products {  @PrimaryGeneratedColumn('uuid')  id: string;  @Column()  name: string;  @Column('text')  description: string;  @Column('decimal')  price: number;  @Column()  stock: number;  @CreateDateColumn()  created_at: Date;  @UpdateDateColumn()  updated_at: Date;  // ...}</code></pre><p>代码实现的特点：</p><ul><li>使用 <code>text</code> 类型存储描述，支持长文本内容</li><li>使用 <code>decimal</code> 类型存储价格，避免浮点数计算误差</li><li><code>stock</code> 字段直接使用普通的数值类型，便于进行库存相关的计算</li></ul><p>商品表的字段及其业务含义如下：</p><ul><li><code>id</code>：主键，用于唯一标识每个商品，类型为 <code>UUID</code></li><li><code>name</code>：商品名称，帮助用户识别商品</li><li><code>description</code>：商品描述，用于展示商品的详细信息</li><li><code>price</code>：商品价格，定义用户在购买该商品时的成本</li><li><code>stock</code>：商品库存数量，代表当前商品的剩余数量</li><li><code>created_at</code> 和 <code>updated_at</code>：创建时间和更新时间，记录商品上架和更新的时间</li></ul><h4 id="122-关联关系分析"><a class="markdownIt-Anchor" href="#122-关联关系分析"></a> 1.2.2. 关联关系分析</h4><p><code>Products</code> 实体与其他实体建立了多个关联关系：</p><pre><code class="language-ts">import { Categories } from './categories.entity';import { OrderItems } from './order-items.entity';import { CartItems } from './cart-items.entity';import { InventoryLogs } from './inventory-logs.entity';@Entity()export class Products {  // ...  @ManyToOne(() =&gt; Categories, category =&gt; category.products)  category: Categories;  @OneToMany(() =&gt; OrderItems, orderItem =&gt; orderItem.product)  orderItems: OrderItems[];  @OneToMany(() =&gt; CartItems, cartItem =&gt; cartItem.product)  cartItems: CartItems[];  @OneToMany(() =&gt; InventoryLogs, inventoryLog =&gt; inventoryLog.product)  inventoryLogs: InventoryLogs[];}</code></pre><ol><li>商品 - 类别关系（<code>@ManyToOne</code>)<ul><li>一个商品属于一个类别</li><li>支持商品分类管理和分类检索</li><li>多对一的关系使得类别可以包含多个商品</li></ul></li><li>商品 - 订单项关系（<code>@OneToMany</code>)<ul><li>一个商品可以出现在多个订单中</li><li>通过 <code>OrderItems</code> 中间表存储具体的购买数量和价格</li><li>支持订单历史查询和销售统计</li></ul></li><li>商品 - 购物车项关系（<code>@OneToMany</code>)<ul><li>一个商品可以被加入多个用户的购物车</li><li>通过 <code>CartItems</code> 中间表记录购物车中的商品数量</li></ul></li><li>商品 - 库存日志关系（<code>@OneToMany</code>)<ul><li>记录商品库存变动历史</li><li>支持库存追踪和审计</li></ul></li></ol><h2 id="13-类别"><a class="markdownIt-Anchor" href="#13-类别"></a> 1.3. 类别</h2><p>类别实体是商品分类的基础，它帮助我们组织和管理商品，提供更好的浏览和检索体验。一个良好的类别系统能够帮助用户更快地找到所需商品，同时也便于商家进行商品管理。</p><blockquote><p>当平台增加新类别「智能家居」时，它会被添加到 <code>Categories</code> 表中。用户在浏览智能家居产品时，只需点击此类别，即可看到所有相关商品。</p></blockquote><h4 id="131-代码实现分析"><a class="markdownIt-Anchor" href="#131-代码实现分析"></a> 1.3.1. 代码实现分析</h4><pre><code class="language-ts">import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, OneToMany } from 'typeorm';@Entity()export class Categories {  @PrimaryGeneratedColumn('uuid')  id: string;  @Column()  name: string;  @Column('text')  description: string;  @CreateDateColumn()  created_at: Date;  @UpdateDateColumn()  updated_at: Date;  // ...}</code></pre><p>类别表的字段及其业务含义如下：</p><ul><li><code>id</code>：主键，唯一标识类别，类型为 <code>UUID</code></li><li><code>name</code>：类别名称，例如「电子产品」或「家具」</li><li><code>description</code>：类别描述，进一步解释类别内容</li><li><code>created_at</code> 和 <code>updated_at</code>：创建和更新时间，记录类别的管理信息</li></ul><h4 id="132-关联关系分析"><a class="markdownIt-Anchor" href="#132-关联关系分析"></a> 1.3.2. 关联关系分析</h4><p><code>Categories</code> 实体主要与 <code>Products</code> 实体建立了一对多的关联关系：</p><pre><code class="language-ts">import { Products } from './products.entity';@Entity()export class Categories {  // ...  @OneToMany(() =&gt; Products, product =&gt; product.category)  products: Products[];}</code></pre><ol><li>类别 - 商品关系（<code>@OneToMany</code>)<ul><li>一个类别可以包含多个商品</li><li>体现了分类组织的层次结构</li><li>支持按类别查询和统计商品</li></ul></li></ol><h2 id="14-订单"><a class="markdownIt-Anchor" href="#14-订单"></a> 1.4. 订单</h2><p>订单是电商系统中最核心的业务实体之一，它记录了交易的全过程，连接了用户、商品、支付等多个业务环节。一个完善的订单系统需要处理订单状态流转、支付流程、商品库存等复杂的业务场景。</p><blockquote><p>当用户下单购买一部智能手表，总价为 200 元，订单状态为「待支付」。在用户支付成功后，订单状态更新为「已支付」。</p></blockquote><h4 id="141-代码实现分析"><a class="markdownIt-Anchor" href="#141-代码实现分析"></a> 1.4.1. 代码实现分析</h4><pre><code class="language-ts">import {  Entity,  PrimaryGeneratedColumn,  Column,  CreateDateColumn,  UpdateDateColumn,  ManyToOne,  OneToMany} from 'typeorm';@Entity()export class Orders {  @PrimaryGeneratedColumn('uuid')  id: string;  @Column('decimal')  total_price: number;  @Column()  status: string;  @CreateDateColumn()  created_at: Date;  @UpdateDateColumn()  updated_at: Date;  // ...}</code></pre><ul><li><code>id</code>：订单的唯一标识符，使用 <code>UUID</code> 类型</li><li><code>total_price</code>：订单总价，使用 <code>decimal</code> 类型确保精确计算</li><li><code>status</code>：订单状态，用于追踪订单的处理流程</li><li><code>created_at</code> 和 <code>updated_at</code>：记录订单的创建和更新时间</li></ul><h4 id="142-关联关系分析"><a class="markdownIt-Anchor" href="#142-关联关系分析"></a> 1.4.2. 关联关系分析</h4><p><code>Orders</code> 实体与其他实体建立了多个关联关系：</p><pre><code class="language-ts">import { Users } from './users.entity';import { OrderItems } from './order-items.entity';@Entity()export class Orders {  // ...  @ManyToOne(() =&gt; Users, user =&gt; user.orders)  user: Users;  @OneToMany(() =&gt; OrderItems, orderItem =&gt; orderItem.order)  orderItems: OrderItems[];}</code></pre><p>这些关联关系支持了完整的订单业务流程：</p><ol><li>订单 - 用户关系（<code>@ManyToOne</code>)<ul><li>每个订单必须属于一个用户</li><li>支持用户订单历史查询</li><li>便于进行用户消费分析</li></ul></li><li>订单 - 订单项关系（<code>@OneToMany</code>)<ul><li>一个订单可以包含多个商品</li><li>通过 <code>OrderItems</code> 存储具体的商品信息和数量</li><li>支持订单明细查询和统计</li></ul></li></ol><h2 id="15-订单项"><a class="markdownIt-Anchor" href="#15-订单项"></a> 1.5. 订单项</h2><p>订单项实体记录了订单中每个商品的具体购买信息，包括数量、单价和总价等。它不仅连接了订单和商品，还保存了购买时的价格快照，这对于订单历史记录和财务核算都很重要。</p><h4 id="151-代码实现分析"><a class="markdownIt-Anchor" href="#151-代码实现分析"></a> 1.5.1. 代码实现分析</h4><pre><code class="language-ts">import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm';@Entity()export class OrderItems {  @PrimaryGeneratedColumn('uuid')  id: string;  @Column()  quantity: number;  @Column('decimal')  price: number;  @Column('decimal')  total_price: number;  // ...}</code></pre><ul><li><code>id</code>：订单项的唯一标识符，使用 <code>UUID</code> 类型</li><li><code>quantity</code>：购买数量</li><li><code>price</code>：商品单价的快照，使用 <code>decimal</code> 类型</li><li><code>total_price</code>：该项商品的总价，使用 <code>decimal</code> 类型</li></ul><h4 id="152-关联关系分析"><a class="markdownIt-Anchor" href="#152-关联关系分析"></a> 1.5.2. 关联关系分析</h4><p><code>OrderItems</code> 实体与其他实体建立了多个多对一的关联关系：</p><ol><li><p>订单项 - 订单关系（<code>@ManyToOne</code>)</p> <pre><code class="language-ts">@ManyToOne(() =&gt; Orders, order =&gt; order.orderItems)order: Orders;</code></pre><ul><li>多个订单项属于同一个订单</li><li>通过这个关系可以获取订单的完整商品清单</li><li>支持订单总价计算和商品统计</li></ul></li><li><p>订单项 - 商品关系（<code>@ManyToOne</code>）</p> <pre><code class="language-ts">@ManyToOne(() =&gt; Products, product =&gt; product.orderItems)product: Products;</code></pre><ul><li>记录该订单项对应的具体商品</li><li>支持商品销售统计和分析</li><li>可以追踪商品的购买历史</li></ul></li></ol><h2 id="16-购物车"><a class="markdownIt-Anchor" href="#16-购物车"></a> 1.6. 购物车</h2><p>每个用户都有一个购物车，用于暂存待购买的商品信息。</p><p>购物车实体记录了用户在线上选择和加入的商品，是下单前的临时存储。它与订单实体有着类似的结构，但服务于不同的业务场景。</p><h4 id="161-代码实现分析"><a class="markdownIt-Anchor" href="#161-代码实现分析"></a> 1.6.1. 代码实现分析</h4><pre><code class="language-ts">import { Entity, PrimaryGeneratedColumn, CreateDateColumn, UpdateDateColumn, OneToOne, OneToMany } from 'typeorm';import { Users } from './users.entity';import { CartItems } from './cart-items.entity';@Entity()export class Carts {  @PrimaryGeneratedColumn('uuid')  id: string;  @CreateDateColumn()  created_at: Date;  @UpdateDateColumn()  updated_at: Date;  // ...}</code></pre><p>代码实现的特点：</p><ul><li>使用一对一关系与用户实体关联，确保每个用户只有一个购物车</li><li>包含基本的时间戳字段，跟踪购物车的创建和更新</li></ul><p>购物车表的字段及其业务含义如下：</p><ul><li><code>id</code>：购物车的唯一标识符，使用 <code>UUID</code> 类型</li><li><code>created_at</code> 和 <code>updated_at</code>：记录购物车的创建和更新时间</li></ul><h4 id="162-关联关系分析"><a class="markdownIt-Anchor" href="#162-关联关系分析"></a> 1.6.2. 关联关系分析</h4><p><code>Carts</code> 实体与其他实体建立了以下关联关系：</p><ol><li><p>购物车 - 用户关系（<code>@OneToOne</code>）</p> <pre><code class="language-ts">@OneToOne(() =&gt; Users, user =&gt; user.cart)user: Users;</code></pre></li><li><p>购物车 - 购物车项关系（<code>@OneToMany</code>）</p> <pre><code class="language-ts">@OneToMany(() =&gt; CartItems, cartItem =&gt; cartItem.cart)cartItems: CartItems[];</code></pre><ul><li>一个购物车可以包含多个购物车项</li><li>通过这个关系可以获取购物车中的商品列表</li></ul></li></ol><h2 id="17-购物车项"><a class="markdownIt-Anchor" href="#17-购物车项"></a> 1.7. 购物车项</h2><p>购物车项实体记录了用户在购物车中选择的商品及其数量，它与订单项实体有着类似的结构。</p><blockquote><p>用户在购物车中添加了两部智能手表，购物车项记录该商品 ID、数量为 2，以及关联的购物车 ID。</p></blockquote><h4 id="171-代码实现分析"><a class="markdownIt-Anchor" href="#171-代码实现分析"></a> 1.7.1. 代码实现分析</h4><pre><code class="language-ts">import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm';@Entity()export class CartItems {  @PrimaryGeneratedColumn('uuid')  id: string;  @Column()  quantity: number;  // ...}</code></pre><p><code>CartItems</code> 实体的特点：</p><ul><li>使用多对一关系连接购物车和商品实体</li><li>记录了商品的购买数量，用于计算购物车总价</li></ul><h4 id="172-关联关系分析"><a class="markdownIt-Anchor" href="#172-关联关系分析"></a> 1.7.2. 关联关系分析</h4><ol><li><p>购物车项 - 购物车关系（<code>@ManyToOne</code>）</p> <pre><code class="language-ts">@ManyToOne(() =&gt; Carts, cart =&gt; cart.cartItems)cart: Carts;</code></pre></li><li><p>购物车项 - 商品关系（<code>@ManyToOne</code>）</p> <pre><code class="language-ts">@ManyToOne(() =&gt; Products, product =&gt; product.cartItems)product: Products;</code></pre></li></ol><h2 id="18-支付"><a class="markdownIt-Anchor" href="#18-支付"></a> 1.8. 支付</h2><p>支付实体记录了用户在完成下单后的支付信息，包括支付金额、支付状态等。它与订单实体有着直接的关联关系。</p><h4 id="181-代码实现分析"><a class="markdownIt-Anchor" href="#181-代码实现分析"></a> 1.8.1. 代码实现分析</h4><pre><code class="language-ts">import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, ManyToOne } from 'typeorm';@Entity()export class Payments {  @PrimaryGeneratedColumn('uuid')  id: string;  @Column('decimal')  amount: number;  @Column()  status: string;  @CreateDateColumn()  created_at: Date;  // ...}</code></pre><p><code>Payments</code> 实体的特点：</p><ul><li>使用多对一关系连接订单和用户实体</li><li>记录了支付的金额和状态</li><li>包含支付的创建时间戳</li></ul><h4 id="182-关联关系分析"><a class="markdownIt-Anchor" href="#182-关联关系分析"></a> 1.8.2. 关联关系分析</h4><ol><li><p>支付 - 订单关系（<code>@ManyToOne</code>）</p> <pre><code class="language-ts">@ManyToOne(() =&gt; Orders, order =&gt; order.id)order: Orders;</code></pre><ul><li>一笔订单可以有多个支付记录</li><li>通过这个关系可以获取支付所属的订单信息</li></ul></li><li><p>支付 - 用户关系（<code>@ManyToOne</code>）</p> <pre><code class="language-ts">@ManyToOne(() =&gt; Users, user =&gt; user.payments)user: Users;</code></pre><ul><li>一个用户可以有多笔支付记录</li><li>通过这个关系可以获取支付所属的用户信息</li></ul></li></ol><h2 id="19-地址"><a class="markdownIt-Anchor" href="#19-地址"></a> 1.9. 地址</h2><p>地址实体记录了用户的收货地址信息，包括街道、城市、州 / 省、邮编和国家等详细信息。这些信息在用户下单时需要用到，也可以用于生成发货标签等。</p><h4 id="191-代码实现分析"><a class="markdownIt-Anchor" href="#191-代码实现分析"></a> 1.9.1. 代码实现分析</h4><pre><code class="language-ts">import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne } from 'typeorm';@Entity()export class Addresses {  @PrimaryGeneratedColumn('uuid')  id: string;  @Column()  street: string;  @Column()  city: string;  @Column()  state: string;  @Column()  postal_code: string;  @Column()  country: string;  @CreateDateColumn()  created_at: Date;  @UpdateDateColumn()  updated_at: Date;  // ...}</code></pre><h4 id="192-关联关系分析"><a class="markdownIt-Anchor" href="#192-关联关系分析"></a> 1.9.2. 关联关系分析</h4><ol><li><p>地址 - 用户关系（<code>@ManyToOne</code>）</p> <pre><code class="language-ts">@ManyToOne(() =&gt; Users, user =&gt; user.addresses)user: Users; </code></pre><ul><li>一个用户可以有多个地址信息</li><li>通过这个关系可以获取地址所属的用户信息</li></ul></li></ol><h2 id="110-库存日志"><a class="markdownIt-Anchor" href="#110-库存日志"></a> 1.10. 库存日志</h2><p>库存日志实体记录了商品库存的变动历史，包括每次库存增减的数量和时间。这些记录对于库存管理、库存盘点和异常排查都非常重要。</p><h4 id="1101-代码实现分析"><a class="markdownIt-Anchor" href="#1101-代码实现分析"></a> 1.10.1. 代码实现分析</h4><pre><code class="language-ts">import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, ManyToOne } from 'typeorm';@Entity()export class InventoryLogs {  @PrimaryGeneratedColumn('uuid')  id: string;  @Column()  change: number;  @CreateDateColumn()  created_at: Date;  // ...}</code></pre><p><code>InventoryLogs</code> 实体的特点：</p><ul><li>使用多对一关系与商品实体关联</li><li>记录了库存变动数量（<code>change</code>)，正数表示入库，负数表示出库</li><li>包含时间戳，记录每次库存变动的具体时间点</li></ul><h4 id="1102-关联关系分析"><a class="markdownIt-Anchor" href="#1102-关联关系分析"></a> 1.10.2. 关联关系分析</h4><ol><li><p>库存日志 - 商品关系（<code>@ManyToOne</code>）</p> <pre><code class="language-ts">@ManyToOne(() =&gt; Products, product =&gt; product.inventoryLogs)product: Products;</code></pre><ul><li>一个商品可以有多条库存变动记录</li><li>通过这个关系可以追踪特定商品的库存变动历史</li></ul></li></ol><h1 id="2-创建数据库迁移文件"><a class="markdownIt-Anchor" href="#2-创建数据库迁移文件"></a> 2. 创建数据库迁移文件</h1><p>在开发应用程序时，数据库模式的更新是一项常见而重要的工作，尤其是在应用不断演进的过程中。</p><p>假设我们在开发一个应用，并需要更新数据库的表结构，比如添加新字段、修改字段类型等。如何在不丢失现有数据的情况下进行这些修改呢？</p><p>TypeORM 可以帮助我们轻松处理数据库操作。它内置了强大的迁移功能，使我们能够定义数据库结构变更并自动应用到数据库中。</p><h2 id="21-添加自定义命令"><a class="markdownIt-Anchor" href="#21-添加自定义命令"></a> 2.1. 添加自定义命令</h2><p>首先，我们在 <code>package.json</code> 中添加一些脚本来管理 TypeORM 的迁移操作。这些脚本将自动构建项目并运行相应的迁移命令，方便我们快速执行迁移操作：</p><pre><code class="language-json">{  "scripts": {    // ...    "typeorm": "typeorm-ts-node-commonjs -d src/config/data-source.ts",    "migration:initialize": "yarn build &amp;&amp; yarn typeorm migration:generate src/migrations/InitialMigration",    "migration:generate": "yarn build &amp;&amp; yarn typeorm migration:generate",    "migration:run": "yarn build &amp;&amp; yarn typeorm migration:run",    "migration:revert": "yarn build &amp;&amp; yarn typeorm migration:revert"  }}</code></pre><p>让我们一行一行地分析这些脚本的作用：</p><ul><li><code>typeorm</code>：指定 TypeORM 的配置文件路径（<code>src/config/data-source.ts</code>），它是所有 TypeORM 操作的基础</li><li><code>migration:initialize</code>：生成 <code>InitialMigration</code> 迁移文件</li><li><code>migration:generate</code>：生成新的迁移文件<ul><li>用法：<code>yarn migration:generate src/migrations/xxx</code></li></ul></li><li><code>migration:run</code>：执行所有还未运行的迁移，应用到数据库中</li><li><code>migration:revert</code>：撤销上一次迁移，通常用于回滚数据库结构到上一个状态</li></ul><h2 id="22-配置-typeorm-数据源"><a class="markdownIt-Anchor" href="#22-配置-typeorm-数据源"></a> 2.2. 配置 TypeORM 数据源</h2><p>接下来，我们需要设置 TypeORM 的数据库配置。</p><p>在项目的 <code>src/config/data-source.ts</code> 文件中，我们使用 <code>DataSourceOptions</code> 来定义数据库连接的详细信息。</p><p>这里我们还使用了 <code>@nestjs/config</code> 模块来动态读取环境变量，这样在不同环境中可以使用不同的数据库配置。</p><pre><code class="language-ts">import { ConfigService } from '@nestjs/config';import { DataSource, DataSourceOptions } from 'typeorm';import { config } from 'dotenv';config();const configService = new ConfigService();const dataSourceOptions: DataSourceOptions = {  type: configService.get&lt;any&gt;('DB_TYPE', 'mysql'),  host: configService.get&lt;string&gt;('DB_HOST'),  port: configService.get&lt;number&gt;('DB_PORT'),  username: configService.get&lt;string&gt;('DB_USER'),  password: configService.get&lt;string&gt;('DB_PASSWORD'),  database: configService.get&lt;string&gt;('DB_NAME'),  synchronize: configService.get&lt;string&gt;('APP_ENV') === 'development',  entities: ['dist/entities/*.entity{.ts,.js}'],  migrations: ['dist/migrations/*{.ts,.js}'],  subscribers: []};export default new DataSource(dataSourceOptions);</code></pre><ul><li><code>type</code>：指定数据库类型，这里我们通过环境变量 <code>DB_TYPE</code> 来设置，默认为 MySQL</li><li><code>host</code>、<code>port</code>、<code>username</code>、<code>password</code>、<code>database</code>：这些参数是数据库连接的必要信息，都可以通过环境变量配置</li><li><code>synchronize</code>：如果 <code>APP_ENV</code> 为 <code>development</code>，则会启用同步模式，让 TypeORM 自动更新数据库表结构<ul><li>注意：生产环境下建议禁用此项</li></ul></li><li><code>entities</code> 和 <code>migrations</code>：指定实体和迁移文件的路径。TypeORM 会使用这些路径找到相关文件</li></ul><h2 id="23-生成数据库迁移文件"><a class="markdownIt-Anchor" href="#23-生成数据库迁移文件"></a> 2.3. 生成数据库迁移文件</h2><p>当配置完成后，我们可以通过以下命令来生成用于初始化数据库的迁移文件：</p><pre><code class="language-bash">yarn migration:initialize</code></pre><p>这条命令会自动构建项目，并使用 TypeORM 生成一个迁移文件（位于 <code>src/migrations</code>，且默认命名为 <code>数字数字数字-InitialMigration.ts</code>）。</p><p>这个文件会包含创建、修改或删除表结构的 SQL 语句。例如，如果你添加了一个新的字段，生成的迁移文件就会包含一个 <code>ALTER TABLE</code> 语句。</p><h2 id="24-执行迁移"><a class="markdownIt-Anchor" href="#24-执行迁移"></a> 2.4. 执行迁移</h2><p>生成迁移文件后，使用以下命令将其应用到数据库：</p><pre><code class="language-bash">yarn migration:run</code></pre><p>此命令会检查并执行所有尚未在数据库中应用的迁移。这样可以确保你的数据库结构与最新的迁移文件一致。</p><h2 id="25-回滚迁移"><a class="markdownIt-Anchor" href="#25-回滚迁移"></a> 2.5. 回滚迁移</h2><p>在开发过程中，偶尔可能需要回滚上次迁移，例如在测试或调试时。使用以下命令可以撤销上一次迁移：</p><pre><code class="language-bash">yarn migration:revert</code></pre><p>TypeORM 会自动识别上次执行的迁移，并撤销相应的更改，恢复到之前的数据库结构。</p><h1 id="3-设置数据库索引"><a class="markdownIt-Anchor" href="#3-设置数据库索引"></a> 3. 设置数据库索引</h1><p>在开发应用程序时，尤其是当数据库中的数据量越来越大时，查询性能变得至关重要。</p><p>数据库索引是一种数据结构，它帮助数据库管理系统（DBMS）高效地检索数据。索引就像书籍中的目录，它可以快速定位到某个数据的位置，而不是扫描整个表。当我们对数据库表进行查询时，索引可以显著提高查询性能，尤其是在处理大量数据时。</p><p>在 MySQL 中，索引通常应用于那些需要频繁查询的字段。常见的索引类型有：</p><ul><li>主键索引：自动为表的主键字段创建</li><li>唯一索引：确保每个值唯一</li><li>普通索引：加速数据检索，但不强制唯一性</li><li>全文索引：用于加速文本内容的检索</li></ul><p>没有索引的情况下，数据库在执行查询时必须扫描整个表，逐行比较数据。这种方式在小型表中可能没什么问题，但在数据量较大时，会导致性能急剧下降。</p><blockquote><p>假设我们的购物平台，数据库中存储了数百万条订单记录。当用户搜索特定订单时，如果没有适当的索引，系统可能会扫描整个订单表来找到匹配的记录。随着数据量增加，查询速度变得非常慢，甚至可能导致系统响应延迟。</p><p>使用索引后，数据库不再需要扫描整个表，而是通过索引快速定位到目标数据，从而显著提升查询速度。</p></blockquote><p>在 NestJS 中，我们可以通过 TypeORM 为实体字段添加索引。TypeORM 提供了 <code>@Index()</code> 装饰器，允许我们在数据库表的字段上添加索引。</p><h2 id="31-用户"><a class="markdownIt-Anchor" href="#31-用户"></a> 3.1. 用户</h2><pre><code class="language-ts">@Index()@CreateDateColumn()created_at: Date;</code></pre><p>在 <code>Users</code> 实体中，我们使用了 <code>@Index()</code> 装饰器来为 <code>created_at</code> 字段添加索引。</p><p>在大多数应用程序中，<code>created_at</code> 字段通常用于按照时间排序或进行时间范围查询。</p><blockquote><p>例如，用户可能需要查看某一时间段内的所有注册用户，或者获取最近创建的用户列表。</p></blockquote><p>假设在应用程序中，用户经常执行以下查询：</p><ul><li>查询某个时间段内注册的用户。</li><li>按照注册时间排序显示用户列表。</li></ul><p>如果没有为 <code>created_at</code> 字段添加索引，数据库会需要扫描整个用户表来执行这些查询，这样会导致性能问题。添加索引后，数据库可以通过索引快速查找和排序数据，显著提高查询速度，尤其是在数据量较大的情况下。</p><h4 id="311-关系字段为何不需要索引"><a class="markdownIt-Anchor" href="#311-关系字段为何不需要索引"></a> 3.1.1. 关系字段为何不需要索引？</h4><p>这时候就有人问了：「难道像 <code>orders</code>、<code>cart</code> 这些字段，用户就不会查询了吗？如果经常用到，为什么不为它们加个索引呢？」答案是：确实不需要。</p><p>在 TypeORM 中，关系字段（比如 <code>orders</code> 和 <code>cart</code>）通常是外键字段，数据库会自动为这些字段创建索引。例如，在 <code>Users</code> 实体中，<code>orders</code> 字段是通过 <code>@OneToMany</code> 与 <code>Orders</code> 实体关联的。虽然我们没有显式地为 <code>orders</code> 字段添加索引，但在 <code>Orders</code> 表中，<code>user</code> 字段作为外键会自动被索引。</p><p>这意味着，当我们查询某个用户的所有订单时，数据库会直接利用 <code>Orders</code> 表中自动创建的 <code>user</code> 索引，来加速查询。而我们不需要额外为 <code>orders</code> 字段添加索引，TypeORM 和数据库已经为我们处理好了这部分的优化。</p><h2 id="32-商品"><a class="markdownIt-Anchor" href="#32-商品"></a> 3.2. 商品</h2><pre><code class="language-ts">@Index()@Column('decimal')price: number;</code></pre><p><code>price</code> 字段通常会用于以下几种查询：</p><ul><li>按照价格范围查询产品，例如查找价格低于某个值的所有产品</li><li>按照价格排序，例如将产品列表按价格从低到高或从高到低排序</li></ul><pre><code class="language-ts">@Index()@Column()stock: number;</code></pre><p><code>stock</code> 字段通常用于以下查询场景：</p><ul><li>查找库存数量为零或低于某个值的产品（例如「缺货」产品或「库存预警」产品）</li><li>按照库存数量排序，帮助商家快速查看库存最少的产品</li></ul><pre><code class="language-ts">@Index()@CreateDateColumn()created_at: Date;</code></pre><p>所有的 <code>created_at</code> 字段都需要添加索引。</p><h2 id="33-支付"><a class="markdownIt-Anchor" href="#33-支付"></a> 3.3. 支付</h2><pre><code class="language-ts">@Index()@CreateDateColumn()created_at: Date;</code></pre><h2 id="34-订单"><a class="markdownIt-Anchor" href="#34-订单"></a> 3.4. 订单</h2><pre><code class="language-ts">@Index()@Column()status: string;</code></pre><p><code>status</code> 字段通常用于查询订单的状态，例如：</p><ul><li>查询某一状态的订单（如「待处理」、「已发货」、「已完成」等）</li><li>按照订单状态统计订单数量</li></ul><pre><code class="language-ts">@Index()@CreateDateColumn()created_at: Date;</code></pre><h2 id="35-订单项"><a class="markdownIt-Anchor" href="#35-订单项"></a> 3.5. 订单项</h2><pre><code class="language-ts">@Index()@Column()quantity: number;</code></pre><p><code>quantity</code> 字段通常在以下情况中用于查询：</p><ul><li>查询具有特定数量的订单项（例如查询某种商品的批量购买情况）</li><li>按照数量对订单项进行筛选或排序</li></ul><h2 id="36-类别"><a class="markdownIt-Anchor" href="#36-类别"></a> 3.6. 类别</h2><pre><code class="language-ts">@Index()@Column()name: string;</code></pre><p><code>name</code> 字段是分类的唯一标识，用于以下情况：</p><ul><li>按类别名称搜索产品类别（例如，用户希望快速找到特定名称的类别）</li><li>在名称字段上进行排序或进行自动完成的匹配查询</li></ul><pre><code class="language-ts">@Index()@CreateDateColumn()created_at: Date;</code></pre><h2 id="37-购物车"><a class="markdownIt-Anchor" href="#37-购物车"></a> 3.7. 购物车</h2><pre><code class="language-ts">@Index()@CreateDateColumn()created_at: Date;</code></pre><h2 id="38-地址"><a class="markdownIt-Anchor" href="#38-地址"></a> 3.8. 地址</h2><pre><code class="language-ts">@Index()@Column()postal_code: string;</code></pre><p>在地址系统中，<code>postal_code</code>（邮政编码）字段可能用于以下场景：</p><ul><li>按邮政编码筛选地址。例如，在电商系统中，按邮政编码筛选用户地址，以确定是否支持配送</li><li>邮政编码的批量统计或区域分析，例如确定特定邮政编码区域的用户密度</li></ul><pre><code class="language-ts">@Index()@CreateDateColumn()created_at: Date;</code></pre><h2 id="39-库存日志"><a class="markdownIt-Anchor" href="#39-库存日志"></a> 3.9. 库存日志</h2><pre><code class="language-ts">@Index()@CreateDateColumn()created_at: Date;</code></pre><p>接下来，我们可以使用以下命令生成数据库迁移文件：</p><pre><code class="language-bash">yarn migration:generate src/migrations/CreateIndex</code></pre><p>然后使用以下命令应用迁移并更新数据库：</p><pre><code class="language-bash">yarn migration:run</code></pre></body></html>]]></content>
    
    
    <summary type="html">本文是 React + NestJS 全栈购物平台实践的第三篇，专注于后端数据库的设计与实现。文章从零开始，详细讲解了如何为购物平台定义核心实体（如用户、商品、订单），并使用 TypeORM 装饰器实现数据模型及其复杂的关联关系。接着，教程演示了如何配置和使用 TypeORM 的数据库迁移（Migration）功能，通过自定义脚本来自动化生成、应用和回滚数据库结构变更。最后，文章还探讨了数据库性能优化的关键——索引（Indexing），并为关键查询字段添加了索引。本教程为使用 NestJS 和 TypeORM 进行数据建模与管理提供了完整的实战指南。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="全栈实践" scheme="https://blog.cytrogen.icu/tags/%E5%85%A8%E6%A0%88%E5%AE%9E%E8%B7%B5/"/>
    
    <category term="Node.js" scheme="https://blog.cytrogen.icu/tags/Node-js/"/>
    
    <category term="React.js" scheme="https://blog.cytrogen.icu/tags/React-js/"/>
    
    <category term="TypeScript" scheme="https://blog.cytrogen.icu/tags/TypeScript/"/>
    
    <category term="NestJS" scheme="https://blog.cytrogen.icu/tags/NestJS/"/>
    
  </entry>
  
  <entry>
    <title>React + NestJS 购物平台练习【2】后端项目框架搭建</title>
    <link href="https://blog.cytrogen.icu/posts/8e94.html"/>
    <id>https://blog.cytrogen.icu/posts/8e94.html</id>
    <published>2024-11-04T05:00:00.000Z</published>
    <updated>2026-02-09T17:16:54.997Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>搭建基础的 NestJS 项目框架，包括以下内容：</p><ul><li>初始化 NestJS 项目</li><li>配置环境变量</li><li>配置数据库连接</li><li>配置 Swagger 文档</li><li>设置基础中间件</li><li>配置日志系统</li></ul><span id="more"></span><h1 id="1-初始化-nestjs-项目"><a class="markdownIt-Anchor" href="#1-初始化-nestjs-项目"></a> 1. 初始化 NestJS 项目</h1><h2 id="11-安装-nestjs-cli-工具"><a class="markdownIt-Anchor" href="#11-安装-nestjs-cli-工具"></a> 1.1. 安装 NestJS CLI 工具</h2><p>全局安装 NestJS 的 CLI 工具：</p><pre><code class="language-bash">yarn global add @nestjs/cli</code></pre><p>确保全局安装的包路径已被添加到环境变量 <code>PATH</code> 中，否则无法在终端中使用 <code>nest</code> 命令。</p><p>可以使用以下命令查看 Yarn 的全局包路径：</p><pre><code class="language-bash">yarn global bin</code></pre><p>将输出的路径添加到 <code>PATH</code> 中。</p><h2 id="12-创建新的-nestjs-项目"><a class="markdownIt-Anchor" href="#12-创建新的-nestjs-项目"></a> 1.2. 创建新的 NestJS 项目</h2><p>执行以下命令，创建一个名为 <code>shopping-nest-server</code> 的新项目：</p><pre><code class="language-bash">nest new shopping-nest-server</code></pre><p>运行后，NestJS CLI 会提示选择包管理工具，选择 <code>Yarn</code>，等待其自动安装所需的依赖。</p><p>项目生成后，NestJS CLI 默认会在根目录下生成一个 <code>test</code> 目录和一些单元测试文件（<code>.spec.ts</code>）。我暂时不需要测试，所以删去了这些内容。</p><p>NestJS CLI 创建的 NestJS 项目会自带 ESLint 和 Prettier，我们只需要将 <a href="/6d86">上一章</a> 配置好的 <code>.prettierrc</code> 复制过来、确保前端后端都遵循相同的代码规范即可：</p><pre><code class="language-json">{  "printWidth": 120,  "tabWidth": 2,  "useTabs": false,  "semi": true,  "singleQuote": true,  "trailingComma": "none",  "bracketSpacing":true,  "bracketSameLine": true,  "arrowParens": "avoid"}</code></pre><h1 id="2-配置环境变量和配置文件"><a class="markdownIt-Anchor" href="#2-配置环境变量和配置文件"></a> 2. 配置环境变量和配置文件</h1><p>在实际配置前，我们先来考虑一下，什么是需要配置的：</p><ol><li><p>应用基本配置</p><ul><li><code>APP_PORT</code>：定义应用监听的端口号</li><li><code>APP_ENV</code>：表示当前的应用环境。应用将根据环境做出一些环境特定的设置，比方说日志的详细级别</li></ul></li><li><p>核心数据库配置</p><p>数据库是应用的核心部分，用于存储应用的持久化数据。</p><ul><li><code>DB_TYPE</code>：数据库的类型。我选择使用 <code>mysql</code> 或者 <code>postgres</code></li><li><code>DB_HOST</code>、<code>DB_PORT</code>、<code>DB_USER</code>、<code>DB_PASSWORD</code>、<code>DB_NAME</code>：这些参数确保应用能连接到正确的数据库实例。不同环境中的数据库配置往往不尽相同，开发环境中可能连接到本地数据库、生产环境中可能连接到远程数据库</li></ul></li><li><p>缓存配置</p><p>缓存系统是提升应用性能的重要手段。</p><p>Redis 是一个高效的内存缓存数据库，常用于缓存频繁访问的数据，从而减轻数据库负载、提升响应速度。</p><ul><li><code>REDIS_HOST</code>、<code>REDIS_PORT</code>：让应用访问正确的 Redis 实例</li><li><code>REDIS_PASSWORD</code> 部分 Redis 服务需要密码验证，通过密码可以保障缓存数据的安全</li><li><code>REDIS_DB</code>：指定 Redis 数据库编号，有助于在同一 Redis 实例中隔离不同用途的数据</li></ul></li><li><p>Elasticsearch 配置</p><p>Elasticsearch 是一个分布式搜索和分析引擎，适用于海量数据的全文检索和分析。</p><ul><li><code>ELASTICSEARCH_HOST</code>、<code>ELASTICSEARCH_PORT</code>：定义了 Elasticsearch 服务的位置和端口</li><li><code>ELASTICSEARCH_USERNAME</code>、<code>ELASTICSEARCH_PASSWORD</code>：通过用户名和密码的方式实现对 Elasticsearch 集群的访问控制</li><li><code>ELASTICSEARCH_INDEX</code>：定义应用使用的索引。索引类似于数据库中的表，是 Elasticsearch 存储和查询数据的基本单位</li></ul></li><li><p>文件存储配置</p><p>对于需要上传文件（如用户头像、商品图片等）的应用来说，文件存储服务是不可或缺的。</p><p>很多应用会选择云存储服务（如 Amazon S3、Aliyun OSS）或者本地可用的 MinIO 来满足存储需求。</p><ul><li><code>STORAGE_ENDPOINT</code>：指定文件存储服务的 API 端点，便于与远程存储服务连接</li><li><code>STORAGE_ACCESS_KEY</code> 和 <code>STORAGE_SECRET_KEY</code>：用于认证的密钥对，保障文件存储服务的安全访问</li><li><code>STORAGE_BUCKET</code>、<code>STORAGE_REGION</code>：定义存储的目标存储桶和区域位置，以便更合理地管理文件资源，减少延迟</li><li><code>STORAGE_USE_SSL</code>：配置是否启用 HTTPS，以增强数据传输的安全性</li></ul></li><li><p>JWT 配置</p><p>JWT 用于实现用户身份验证和会话管理，是一种轻量的认证方式。</p><p>在过去的 <a href="/posts/40b4">React + NestJS + SocketIO 教程文章</a> 中，我们已经讲过了 JWT，感兴趣的可以看看。</p><ul><li><code>JWT_SECRET</code>：用于签发和验证 JWT 的密钥，确保身份认证的安全性。设计一个足够强度的密钥并保持其私密性至关重要</li><li><code>JWT_TOKEN_AUDIENCE</code>：指定 JWT 的受众，即令牌面向的服务或应用。设置受众可以帮助确保令牌仅被指定应用使用，提高认证的安全性</li><li><code>JWT_TOKEN_ISSUER</code>：用于声明 JWT 的发布者，一般设置为认证服务器的标识，确保 JWT 的来源是可信的</li><li><code>JWT_ACCESS_TOKEN_TTL</code>：JWT 访问令牌的有效时间，单位为秒。合理设置过期时间既能提升安全性（防止会话过长导致会话劫持风险），又可避免用户频繁重新登录带来的不便</li></ul></li></ol><h2 id="21-安装必要依赖"><a class="markdownIt-Anchor" href="#21-安装必要依赖"></a> 2.1. 安装必要依赖</h2><p>首先安装 <code>@nestjs/config</code>、<code>dotenv</code> 以及数据库驱动和 TypeORM，以支持加载环境变量、进行数据库连接和配置。</p><pre><code class="language-bash">yarn add @nestjs/configyarn add dotenv -Dyarn add @nestjs/typeorm typeorm mysql2 # 替换 mysql2 为 pg 以使用 PostgreSQL</code></pre><ul><li><code>@nestjs/config</code> 是 NestJS 提供的官方配置模块，专为加载、管理和验证环境变量而设计</li><li><code>dotenv</code> 是配置模块的底层依赖，通过 <code>.env</code> 文件加载环境变量</li><li>TypeORM 是一个 TypeScript 支持的 ORM（对象关系映射），能够与关系型数据库集成</li></ul><h2 id="22-创建环境变量文件"><a class="markdownIt-Anchor" href="#22-创建环境变量文件"></a> 2.2. 创建环境变量文件</h2><p>在项目根目录下创建 <code>.env</code> 文件：</p><pre><code class="language-plaintext"># 应用APP_PORT=4000APP_ENV=development# 核心数据库DB_TYPE=mysqlDB_HOST=localhostDB_PORT=3306DB_USER=用户名DB_PASSWORD=密码DB_NAME=数据库名称# Redis 缓存REDIS_HOST=localhostREDIS_PORT=6379REDIS_PASSWORD=密码REDIS_DB=0# ElasticsearchELASTICSEARCH_HOST=localhostELASTICSEARCH_PORT=9200ELASTICSEARCH_USERNAME=用户名ELASTICSEARCH_PASSWORD=密码ELASTICSEARCH_INDEX=products# 文件存储STORAGE_ENDPOINT=STORAGE_ACCESS_KEY=access_key_idSTORAGE_SECRET_KEY=secret_access_keySTORAGE_BUCKET=桶名STORAGE_REGION=STORAGE_USE_SSL=true# JWTJWT_SECRET=secretJWT_TOKEN_AUDIENCE=localhost:4000JWT_TOKEN_ISSUER=localhost:4000JWT_ACCESS_TOKEN_TTL=3600</code></pre><p>这里的环境变量覆盖了不同模块所需的配置项，确保各模块配置的灵活性。</p><h2 id="23-引入配置模块和验证"><a class="markdownIt-Anchor" href="#23-引入配置模块和验证"></a> 2.3. 引入配置模块和验证</h2><p>在 <code>AppModule</code> 中配置 <code>@nestjs/config</code>，使用 <code>Joi</code> 对环境变量进行验证，确保每个变量都满足格式要求：</p><pre><code class="language-ts">import { Module } from '@nestjs/common';import { ConfigModule } from '@nestjs/config';import { AppController } from './app.controller';import { AppService } from './app.service';import { DatabaseModule } from './database/database.module';import * as Joi from 'joi';@Module({  imports: [    ConfigModule.forRoot({      isGlobal: true, // 让 ConfigModule 全局可用      validationSchema: Joi.object({        APP_PORT: Joi.number().default(4000),        APP_ENV: Joi.string().valid('development', 'production', 'test').default('development'),        // 核心数据库        DB_TYPE: Joi.string().valid('mysql', 'postgres').default('mysql'),        DB_HOST: Joi.string().required(),        DB_PORT: Joi.number().default(3306),        DB_USER: Joi.string().required(),        DB_PASSWORD: Joi.string().required(),        DB_NAME: Joi.string().required(),        // Redis 缓存        REDIS_HOST: Joi.string().required(),        REDIS_PORT: Joi.number().default(6379),        REDIS_PASSWORD: Joi.string().allow(''),        REDIS_DB: Joi.number().default(0),        // Elasticsearch        ELASTICSEARCH_HOST: Joi.string().required(),        ELASTICSEARCH_PORT: Joi.number().default(9200),        ELASTICSEARCH_USER: Joi.string().required(),        ELASTICSEARCH_PASSWORD: Joi.string().required(),        ELASTICSEARCH_INDEX: Joi.string().required(),        // 文件存储        STORAGE_ENDPOINT: Joi.string().allow(''),        STORAGE_ACCESS_KEY: Joi.string().required(),        STORAGE_SECRET_KEY: Joi.string().required(),        STORAGE_BUCKET: Joi.string().required(),        STORAGE_REGION: Joi.string().allow(''),        STORAGE_USE_SSL: Joi.boolean().default(true),        // JWT        JWT_SECRET: Joi.string().required(),        JWT_TOKEN_AUDIENCE: Joi.string().required(),        JWT_TOKEN_ISSUER: Joi.string().required(),        JWT_ACCESS_TOKEN_TTL: Joi.number().default(3600)      })    }),    DatabaseModule  ],  controllers: [AppController],  providers: [AppService]})export class AppModule {}</code></pre><ul><li><code>isGlobal</code>：将配置模块设为全局模块，避免在其他模块中重复引入</li><li><code>validationSchema</code>：通过 <code>Joi</code> 验证环境变量的值，确保值类型与业务需求匹配；例如 <code>DB_HOST</code> 需要是字符串，<code>APP_PORT</code> 应为数值，且数据库和 JWT 密钥都必须存在</li></ul><blockquote><p><code>Joi</code> 是一个 JavaScript 数据验证库，通常用来确保应用中的数据符合特定的规则或格式。</p><h4 id="231-基本用法"><a class="markdownIt-Anchor" href="#231-基本用法"></a> 2.3.1. 基本用法</h4><p><code>Joi</code> 提供了一个简单的链式 API 来定义验证规则。验证的流程一般是：定义 schema（验证规则） -&gt; 验证数据 -&gt; 获取结果或错误。</p><pre><code class="language-ts">const Joi = require('joi');// 定义 schemaconst schema = Joi.object({  name: Joi.string().min(3).max(30).required(),  age: Joi.number().integer().min(0).max(120),  email: Joi.string().email()});// 验证数据const result = schema.validate({ name: 'Alice', age: 25, email: 'alice@example.com' });// 检查结果if (result.error) {  console.log(result.error.details);} else {  console.log(result.value);}</code></pre><h4 id="232-基本类型验证"><a class="markdownIt-Anchor" href="#232-基本类型验证"></a> 2.3.2. 基本类型验证</h4><p><code>Joi</code> 支持的基本类型包括：<code>string</code>、<code>number</code>、<code>boolean</code>、<code>array</code>、<code>object</code> 等。每种类型可以组合其他规则，如最小/最大值、必填/选填、格式限制等。</p><ol><li>字符串验证</li></ol><pre><code class="language-ts">Joi.string()  // 定义为字符串类型Joi.string().min(3)  // 最小长度Joi.string().max(30)  // 最大长度Joi.string().email()  // 必须是电子邮箱格式Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/)  // 使用正则表达式验证格式</code></pre><ol start="2"><li>数字验证</li></ol><pre><code class="language-ts">Joi.number()  // 定义为数字类型Joi.number().integer()  // 必须是整数Joi.number().min(0)  // 最小值Joi.number().max(100)  // 最大值Joi.number().positive()  // 必须是正数Joi.number().negative()  // 必须是负数</code></pre><ol start="3"><li>布尔值验证</li></ol><pre><code class="language-ts">Joi.boolean()  // 定义为布尔类型</code></pre><ol start="4"><li>数组验证</li></ol><pre><code class="language-ts">Joi.array()  // 定义为数组类型Joi.array().items(Joi.number())  // 数组中每项都必须是数字Joi.array().min(1).max(5)  // 数组长度限制Joi.array().unique()  // 数组中的每个元素必须唯一</code></pre><ol start="5"><li>对象验证</li></ol><pre><code class="language-ts">Joi.object({  username: Joi.string().required(),  password: Joi.string().min(8).required(),})</code></pre><h4 id="233-条件验证"><a class="markdownIt-Anchor" href="#233-条件验证"></a> 2.3.3. 条件验证</h4><p>条件验证允许定义复杂的规则，如基于字段值的条件或逻辑分支。</p><p><code>when</code> 条件验证：</p><pre><code class="language-ts">const schema = Joi.object({  password: Joi.string().min(8).required(),  confirmPassword: Joi.string().valid(Joi.ref('password')).when('password', {    is: Joi.exist(),  // 如果 password 存在……    then: Joi.required(),  // ……confirmPassword 也是必填    otherwise: Joi.forbidden()  // 否则不允许出现 confirmPassword  })});</code></pre><h4 id="234-嵌套对象和数组验证"><a class="markdownIt-Anchor" href="#234-嵌套对象和数组验证"></a> 2.3.4. 嵌套对象和数组验证</h4><p><code>Joi</code> 允许定义嵌套结构，如对象嵌套和数组嵌套。</p><ol><li>嵌套对象</li></ol><pre><code class="language-ts">const schema = Joi.object({  user: Joi.object({    name: Joi.string().required(),    age: Joi.number().min(0)  }).required()});</code></pre><ol start="2"><li>嵌套数组</li></ol><pre><code class="language-ts">const schema = Joi.array().items(  Joi.object({    id: Joi.number().required(),    name: Joi.string().required()  }));</code></pre><h4 id="235-自定义验证器"><a class="markdownIt-Anchor" href="#235-自定义验证器"></a> 2.3.5. 自定义验证器</h4><p><code>Joi</code> 支持自定义验证函数，用于更复杂的场景。</p><pre><code class="language-ts">const schema = Joi.string().custom((value, helpers) =&gt; {  if (!/^[a-zA-Z]+$/.test(value)) {    return helpers.error('any.invalid');  // 返回一个自定义错误  }  return value;  // 验证通过}, 'Custom alphabet validation');</code></pre><h4 id="236-配合-nestjs-使用"><a class="markdownIt-Anchor" href="#236-配合-nestjs-使用"></a> 2.3.6. 配合 NestJS 使用</h4><p>在 NestJS 中，可以结合 <code>@nestjs/config</code> 模块来使用 <code>Joi</code> 验证配置文件。</p><pre><code class="language-ts">import { Module } from '@nestjs/common';import { ConfigModule } from '@nestjs/config';import * as Joi from 'joi';@Module({  imports: [    ConfigModule.forRoot({      validationSchema: Joi.object({        // 假设有核心数据库的配置        DB_HOST: Joi.string().required(),        DB_PORT: Joi.number().default(5432),      })    })  ],})export class AppModule {}</code></pre><h4 id="237-错误处理与自定义错误消息"><a class="markdownIt-Anchor" href="#237-错误处理与自定义错误消息"></a> 2.3.7. 错误处理与自定义错误消息</h4><p><code>Joi</code> 会在验证失败时返回详细的错误信息，可以自定义错误消息。</p><pre><code class="language-ts">const schema = Joi.object({  name: Joi.string().min(3).required().messages({    'string.base': `"name" should be a type of 'text'`,    'string.empty': `"name" cannot be an empty field`,    'string.min': `"name" should have a minimum length of {#limit}`,    'any.required': `"name" is a required field`  })});</code></pre></blockquote><h2 id="24-使用配置"><a class="markdownIt-Anchor" href="#24-使用配置"></a> 2.4. 使用配置</h2><p>作为一个使用 <code>ConfigService</code> 的例子，我们将从 <code>.env</code> 中读取 <code>APP_PORT</code> 的值，并将其作为应用的启动端口。</p><pre><code class="language-ts">import { NestFactory } from '@nestjs/core';import { ConfigService } from '@nestjs/config';import { AppModule } from './app.module';async function bootstrap() {  const app = await NestFactory.create(AppModule);  const configService = app.get(ConfigService);  const port = configService.get&lt;number&gt;('APP_PORT') || 4000;  await app.listen(port);}bootstrap();</code></pre><p>运行 <code>nest start</code> 来查看是否有任何问题。</p><h1 id="3-设置数据库连接"><a class="markdownIt-Anchor" href="#3-设置数据库连接"></a> 3. 设置数据库连接</h1><div class="danger"><p>首先，确保自己的本机环境中有安装 MySQL 或者 PostgreSQL。</p><p>安装教程请自行在网上搜索，本篇文档将只会使用 <code>8.0.40 MySQL Community</code>。</p><blockquote><p>挖坑：未来可能会添加支持其他数据库的功能。</p></blockquote></div><h2 id="31-配置-mysql"><a class="markdownIt-Anchor" href="#31-配置-mysql"></a> 3.1. 配置 MySQL</h2><ol><li><p>打开 MySQL CLI（或者使用 <code>mysql -u root -p</code> 来进行连接）</p></li><li><p>创建数据库：</p> <pre><code class="language-sql">CREATE DATABASE 数据库名称;</code></pre><p><em>数据库名称</em> 要匹配 <code>.env</code> 中的：</p> <pre><code class="language-sql">DB_NAME=数据库名称</code></pre></li><li><p>创建用户：</p> <pre><code class="language-sql">CREATE USER '用户名'@'localhost' IDENTIFIED BY '密码';</code></pre><p>这里的内容要匹配 <code>.env</code> 中的这一段内容：</p> <pre><code class="language-plaintext">DB_USER=用户名DB_PASSWORD=密码</code></pre></li><li><p>设置权限：</p> <pre><code class="language-sql">GRANT ALL PRIVILEGES ON 数据库名称.* TO '用户名'@'localhost';FLUSH PRIVILEGES;</code></pre></li><li><p>设置完后可以测试一下：</p> <pre><code class="language-sql">mysql -u 用户名 -p -h localhost -P 3306 数据库名称</code></pre></li></ol><h2 id="32-创建-databasemodule"><a class="markdownIt-Anchor" href="#32-创建-databasemodule"></a> 3.2. 创建 <code>DatabaseModule</code></h2><p>在 NestJS 项目中，集中管理数据库连接的配置非常重要，尤其是在需要支持多种环境（如开发、测试、生产）时。</p><p>创建 <code>DatabaseModule</code> 能让我们将数据库的配置代码分离出来，以便在不同的环境中灵活调整配置，比如使用 <code>ConfigService</code> 来获取环境变量。</p><p>通过 <code>TypeOrmModule.forRootAsync</code> 方法，我们可以使用异步的方式配置 TypeORM。这样可以确保数据库配置在应用初始化时依赖于环境变量，如 <code>DB_HOST</code>、<code>DB_USER</code>、<code>DB_PASSWORD</code> 等，从而增强配置的灵活性和安全性。</p><pre><code class="language-ts">import { Module } from '@nestjs/common';import { TypeOrmModule } from '@nestjs/typeorm';import { ConfigModule, ConfigService } from '@nestjs/config';@Module({  imports: [    ConfigModule,    TypeOrmModule.forRootAsync({      imports: [ConfigModule],      inject: [ConfigService],      useFactory: (configService: ConfigService) =&gt; ({        type: configService.get&lt;'mysql' | 'postgres'&gt;('DB_TYPE'),        host: configService.get&lt;string&gt;('DB_HOST'),        port: configService.get&lt;number&gt;('DB_PORT'),        username: configService.get&lt;string&gt;('DB_USER'),        password: configService.get&lt;string&gt;('DB_PASSWORD'),        database: configService.get&lt;string&gt;('DB_NAME'),        autoLoadEntities: true,        synchronize: configService.get&lt;string&gt;('APP_ENV') === 'development'      })    })  ]})export class DatabaseModule {}</code></pre><ul><li><code>ConfigService</code>：用于从环境变量获取配置，确保 <code>DB_TYPE</code> 等参数的灵活性</li><li><code>forRootAsync</code>：动态配置 <code>TypeOrmModule</code>，适用于需要依赖环境变量初始化的模块</li><li><code>autoLoadEntities: true</code>：TypeORM 会自动加载应用中定义的所有实体。这让我们可以在项目中自由地添加新的实体，而不需要每次手动导入</li><li><code>synchronize</code>：将其设置为 <code>true</code> 会在开发环境中自动同步数据库表结构，以便在本地开发时快速响应数据结构的修改。但在生产环境中，建议关闭 <code>synchronize</code>，以防止意外数据丢失或表结构破坏</li></ul><h1 id="4-配置-swagger-文档"><a class="markdownIt-Anchor" href="#4-配置-swagger-文档"></a> 4. 配置 Swagger 文档</h1><p>在现代 Web 开发中，API 文档对于开发人员和用户来说都是至关重要的，特别是在团队协作中，清晰的 API 文档可以大大提高开发效率。</p><p>NestJS 提供了内置的 Swagger 支持，允许我们快速生成符合 OpenAPI 标准的文档，为用户提供更好的接口可视化。</p><blockquote><p>OpenAPI 是一种用于描述 RESTful API 的规范，它提供了一种标准化的格式，用于定义 API 的端点、请求、响应、认证等内容。</p><p>它的前身是 Swagger 规范，因此你可能听过 Swagger 和 OpenAPI 这两个词被混用。</p><p>OpenAPI 的主要目标是使 API 设计、文档、测试和集成过程更为高效和一致。</p></blockquote><h2 id="41-安装依赖"><a class="markdownIt-Anchor" href="#41-安装依赖"></a> 4.1. 安装依赖</h2><p>首先，我们需要安装 <code>@nestjs/swagger</code> 和 <code>swagger-ui-express</code> 两个模块。</p><ul><li><code>@nestjs/swagger</code> 提供了 NestJS 对 Swagger 的支持</li><li><code>swagger-ui-express</code> 是 Swagger UI 的依赖包，用于在浏览器中显示 API 文档</li></ul><p>在项目根目录下运行以下命令来安装它们：</p><pre><code class="language-bash">yarn add @nestjs/swagger swagger-ui-express</code></pre><h2 id="42-配置-swagger"><a class="markdownIt-Anchor" href="#42-配置-swagger"></a> 4.2. 配置 Swagger</h2><p>打开 <code>main.ts</code> 并添加以下代码：</p><pre><code class="language-ts">// ...import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';async function bootstrap() {  // ...  const swaggerConfig = new DocumentBuilder()    .setTitle('API 文档')    .setDescription('Shopping-Nest 的 API 文档')    .setVersion('1.0')    .addBearerAuth()    .build();  const document = SwaggerModule.createDocument(app, swaggerConfig);  SwaggerModule.setup('api-docs', app, document);  // ...}</code></pre><p>在这里，我们使用 <code>DocumentBuilder</code> 来创建 Swagger 文档的基本信息。常见的配置项有：</p><ul><li><code>.setTitle()</code>：设置 API 文档的标题</li><li><code>.setDescription()</code>：提供 API 的描述信息</li><li><code>.setVersion()</code>：指定 API 的版本号</li><li><code>.addBearerAuth()</code>：如果 API 需要 JWT 认证（通常用于保护 API），可以添加 Bearer 认证支持</li></ul><p><code>SwaggerModule.setup()</code> 方法将 Swagger UI 绑定到指定的路由路径（这里是 <code>/api-docs</code>），之后，我们可以通过访问 <code>http://localhost:APP_PORT/api-docs</code> 来查看生成的文档。</p><h2 id="43-如何使用-swagger"><a class="markdownIt-Anchor" href="#43-如何使用-swagger"></a> 4.3. 如何使用 Swagger</h2><p>在我们完成 Swagger 的基础配置后，接下来的步骤将详细介绍如何利用 Swagger 注释来生成清晰的 API 文档。这一部分将涵盖如何为控制器、DTO（数据传输对象）和请求参数添加 Swagger 装饰器，以便 Swagger 能够生成准确且全面的 API 文档。</p><h4 id="431-为控制器添加注释"><a class="markdownIt-Anchor" href="#431-为控制器添加注释"></a> 4.3.1. 为控制器添加注释</h4><p>在 NestJS 中，控制器负责处理客户端请求并返回响应。我们可以使用 Swagger 提供的装饰器为控制器中的每个方法添加注释，以描述其功能、请求参数和返回结果。</p><pre><code class="language-ts">import { Controller, Get, Post, Body } from '@nestjs/common';import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';import { CreateUserDto } from './dto/create-user.dto';@ApiTags('Users')  // 给控制器添加标签@Controller('users')export class UserController {    @Post()  @ApiOperation({ summary: 'Create a new user' })  // 描述此 API 的作用  @ApiResponse({ status: 201, description: 'The user has been successfully created.' })  // 201 状态响应  @ApiResponse({ status: 400, description: 'Invalid input data.' })  // 400 状态响应  create(@Body() createUserDto: CreateUserDto) {    return 'This action adds a new user';  }  @Get()  @ApiOperation({ summary: 'Retrieve a list of users' })  // 描述此 API 的作用  @ApiResponse({ status: 200, description: 'A list of users.' })  // 200 状态响应  getAllUsers() {    return [{ id: 1, name: 'John Doe' }];  }}</code></pre><h4 id="432-为-dto-添加注释"><a class="markdownIt-Anchor" href="#432-为-dto-添加注释"></a> 4.3.2. 为 DTO 添加注释</h4><p>DTO（数据传输对象）用于定义请求和响应的结构。使用 Swagger 的 <code>@ApiProperty</code> 装饰器，可以清晰地说明每个字段的含义和要求。</p><pre><code class="language-ts">import { ApiProperty } from '@nestjs/swagger';export class CreateUserDto {  @ApiProperty({ description: 'The name of the user' })  // 描述 name 字段  name: string;  @ApiProperty({ description: 'The age of the user', minimum: 1 })  // 描述 age 字段并设置最小值  age: number;  @ApiProperty({ description: 'The email of the user', required: true })  // 描述 email 字段  email: string;}</code></pre><p>在上面的例子中，<code>CreateUserDto</code> 包含了三个属性：<code>name</code>、<code>age</code> 和 <code>email</code>。每个属性都使用了 <code>@ApiProperty</code> 装饰器来提供详细描述，并且可以设置字段的其他约束（如是否必填、类型等）。</p><h4 id="433-为请求参数添加注释"><a class="markdownIt-Anchor" href="#433-为请求参数添加注释"></a> 4.3.3. 为请求参数添加注释</h4><p>如果你的 API 需要接受路径参数、查询参数或请求体中的数据，Swagger 也提供了相关的装饰器来帮助描述这些参数。</p><pre><code class="language-ts">import { Controller, Get, Param } from '@nestjs/common';import { ApiParam } from '@nestjs/swagger';@Controller('users')export class UserController {  @Get(':id')  @ApiOperation({ summary: 'Retrieve a user by ID' })  // 描述此 API 的作用  @ApiParam({ name: 'id', required: true, description: 'The ID of the user to retrieve', type: Number })  // 描述路径参数  getUserById(@Param('id') id: number) {    return { id, name: 'John Doe' };  // 示例返回  }}</code></pre><p>在这个示例中，<code>@ApiParam</code> 用于描述路径参数 id。它帮助用户理解这个参数是必须的，且应该是一个数字。</p><h1 id="5-设置基础中间件"><a class="markdownIt-Anchor" href="#5-设置基础中间件"></a> 5. 设置基础中间件</h1><p>在现代 Web 开发中，处理安全性、请求速率限制、响应压缩以及自定义日志记录是打造可靠、高效应用的基础。</p><p>NestJS 提供了简单灵活的中间件配置支持，通过整合 <code>helmet</code>、<code>@nestjs/throttler</code>、<code>compression</code> 等库，开发者可以轻松地实现这些功能。</p><h2 id="51-添加-cors-支持"><a class="markdownIt-Anchor" href="#51-添加-cors-支持"></a> 5.1. 添加 CORS 支持</h2><p>首先，我们需要确保应用支持跨域请求（CORS），特别是在前后端分离的情况下。以下是启用和配置 CORS 的方法：</p><pre><code class="language-ts">async function bootstrap() {  // ...  const corsOrigin = configService.get&lt;string&gt;('CORS_ORIGIN');  app.enableCors({    origin: corsOrigin,    methods: 'GET,POST',    credentials: true,  });  // ...}</code></pre><p>在 <code>.env</code> 中添加：</p><pre><code class="language-plaintext">CORS_ORIGIN=http://localhost:3000</code></pre><blockquote><p>使用 <code>http://localhost:3000</code> 是因为 React 本地环境默认运行在 <code>localhost:3000</code>。</p></blockquote><h2 id="52-增强安全性"><a class="markdownIt-Anchor" href="#52-增强安全性"></a> 5.2. 增强安全性</h2><p><code>helmet</code> 是一组帮助设置安全 HTTP 头的中间件，能够防范常见的 Web 攻击（例如，XSS 攻击和点击劫持）。</p><p>安装 <code>helmet</code> 库：</p><pre><code class="language-plaintext">yarn add helmet</code></pre><p>开启 <code>helmet</code> 保护：</p><pre><code class="language-ts">import helmet from 'helmet';async function bootstrap() {  // ...    app.use(helmet());  // ...}</code></pre><p>通过这段简单的代码，<code>helmet</code> 会自动添加一组常用的安全头（以下信息来自于 <a href="https://www.npmjs.com/package/helmet">npm</a>）：</p><ul><li><strong>Content-Security-Policy</strong>：一个强大的允许清单，控制页面上可以发生的操作，有助于缓解多种攻击</li><li><strong>Cross-Origin-Opener-Policy</strong>：帮助页面实现进程隔离</li><li><strong>Cross-Origin-Resource-Policy</strong>：阻止其他网站跨域加载您的资源</li><li><strong>Origin-Agent-Cluster</strong>：将进程隔离改为基于源的方式</li><li><strong>Referrer-Policy</strong>：控制 <code>Referer</code> 请求头</li><li><strong>Strict-Transport-Security</strong>：告知浏览器优先使用 HTTPS</li><li><strong>X-Content-Type-Options</strong>：避免 MIME 类型嗅探</li><li><strong>X-DNS-Prefetch-Control</strong>：控制 DNS 预取</li><li><strong>X-Download-Options</strong>：强制将下载的文件保存到本地（仅适用于 Internet Explorer）</li><li><strong>X-Frame-Options</strong>：传统的标头，用于防范点击劫持攻击</li><li><strong>X-Permitted-Cross-Domain-Policies</strong>：控制 Adobe 产品（如 Acrobat）的跨域行为</li><li><strong>X-Powered-By</strong>：关于 Web 服务器的信息，已移除，以防止简单攻击利用该信息</li><li><strong>X-XSS-Protection</strong>：传统的标头，旨在防止 XSS 攻击，但通常效果不佳，因此 Helmet 将其禁用</li></ul><h2 id="53-压缩响应"><a class="markdownIt-Anchor" href="#53-压缩响应"></a> 5.3. 压缩响应</h2><p>压缩响应能够有效减少传输的数据量，提升页面加载速度。</p><p>安装 <code>compression</code> 库：</p><pre><code class="language-bash">yarn add compression</code></pre><p>配置压缩的级别和触发条件：</p><pre><code class="language-ts">import * as compression from 'compression';async function bootstrap() {  // ...  const compressionLevel = configService.get&lt;number&gt;('COMPRESSION_LEVEL') || 6;  const compressionThreshold = configService.get&lt;number&gt;('COMPRESSION_THRESHOLD') || 1024;  app.use(    compression({      level: compressionLevel,      threshold: compressionThreshold,    })  );  // ...}</code></pre><p>在 <code>.env</code> 中添加：</p><pre><code class="language-plaintext"># 响应压缩COMPRESSION_LEVEL=6COMPRESSION_THRESHOLD=1024</code></pre><p>在上面的代码中，<code>level</code> 设置了压缩级别（范围从 0-9，数字越大压缩越强，但 CPU 负荷越高），而 <code>threshold</code> 设置了触发压缩的响应体积阈值（单位为字节）。</p><h2 id="54-限制请求速率"><a class="markdownIt-Anchor" href="#54-限制请求速率"></a> 5.4. 限制请求速率</h2><p>防止滥用 API 资源是每个 Web 应用的核心需求之一。我们可以使用 <code>@nestjs/throttler</code> 模块对请求速率进行限制，确保服务不会被大量请求淹没。</p><pre><code class="language-bash">yarn add @nestjs/throttler</code></pre><p>我们在 <code>AppModule</code> 中通过 <code>ThrottlerModule.forRootAsync</code> 配置速率限制。利用 <code>ConfigService</code> 从 <code>.env</code> 文件中获取 <code>ttl</code>（时间窗口）和 <code>limit</code>（最大请求数）参数：</p><pre><code class="language-ts">import { ThrottlerModule, ThrottlerModuleOptions } from '@nestjs/throttler';@Module({  imports: [    // ...    ThrottlerModule.forRootAsync({      inject: [ConfigService],      useFactory: (configService: ConfigService): ThrottlerModuleOptions =&gt; [        {          ttl: configService.get&lt;number&gt;('THROTTLE_TTL') || 60,          limit: configService.get&lt;number&gt;('THROTTLE_LIMIT') || 10        }      ]    }),  ],})</code></pre><p>在 <code>.env</code> 中添加：</p><pre><code class="language-plaintext"># 速率限制THROTTLE_TTL=60THROTTLE_LIMIT=10</code></pre><h4 id="541-使用例子"><a class="markdownIt-Anchor" href="#541-使用例子"></a> 5.4.1. 使用例子</h4><p>配置后，系统会自动为所有 API 路由设置速率限制。也可以在特定控制器或路由中通过 <code>@Throttle</code> 装饰器进行覆盖：</p><pre><code class="language-ts">import { Controller, Get } from '@nestjs/common';import { Throttle } from '@nestjs/throttler';@Controller('test')export class TestController {  @Throttle(5, 10)  // 每 10 秒最多 5 个请求  @Get()  testRoute() {    return "Testing rate limiting";  }}</code></pre><h2 id="55-自定义日志记录"><a class="markdownIt-Anchor" href="#55-自定义日志记录"></a> 5.5. 自定义日志记录</h2><p>为了记录请求信息，我们可以实现一个简单的 <code>LoggerMiddleware</code>，并在 <code>AppModule</code> 中配置它：</p><pre><code class="language-ts">import { Injectable, NestMiddleware } from '@nestjs/common';import { Request, Response, NextFunction } from 'express';@Injectable()export class LoggerMiddleware implements NestMiddleware {  use(req: Request, res: Response, next: NextFunction) {    console.log(`Request... ${req.method} ${req.url}`);    next();  }}</code></pre><p>在 <code>AppModule</code> 中使用 <code>configure</code> 方法应用此中间件：</p><pre><code class="language-ts">import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common';import { LoggerMiddleware } from './middlewares/logger.middleware';@Module({  imports: [/* 其他模块 */],})export class AppModule implements NestModule {  configure(consumer: MiddlewareConsumer) {    consumer.apply(LoggerMiddleware).forRoutes('*');  }}</code></pre><p>这样，每次请求都会在控制台输出请求方法和 URL 路径，帮助我们跟踪请求流向和响应情况。</p><p>启动 NestJS 项目，在浏览器中访问 <code>localhost:APP_PORT</code>（或者默认的 <code>localhost:4000</code>），就能在终端中看到 <code>Request... GET /</code> 的字眼。</p><h2 id="56-设置全局错误处理"><a class="markdownIt-Anchor" href="#56-设置全局错误处理"></a> 5.6. 设置全局错误处理</h2><p>为了统一错误响应格式，可以创建自定义异常过滤器来捕获异常，并返回标准化的错误信息。</p><p>我们在项目中定义 <code>HttpExceptionFilter</code> 类，并将其注册为全局过滤器：</p><pre><code class="language-ts">import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common';@Catch()export class HttpExceptionFilter implements ExceptionFilter {  catch(exception: unknown, host: ArgumentsHost) {    const ctx = host.switchToHttp();    const response = ctx.getResponse();    const request = ctx.getRequest();    const status = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;    const errorResponse = {      statusCode: status,      timestamp: new Date().toISOString(),      path: request.url,      message: exception instanceof HttpException ? exception.getResponse() : 'Internal server error'    };    response.status(status).json(errorResponse);  }}</code></pre><p>接着在 <code>main.ts</code> 中注册过滤器：</p><pre><code class="language-ts">import { HttpExceptionFilter } from './filters/http-exception.filter';async function bootstrap() {  // ...  app.useGlobalFilters(new HttpExceptionFilter());  // ...}</code></pre><p>通过此过滤器，所有未处理的异常都会以标准格式返回。</p><h1 id="6-配置日志系统"><a class="markdownIt-Anchor" href="#6-配置日志系统"></a> 6. 配置日志系统</h1><p>在开发和运维中，日志记录是至关重要的一部分。通过详细的日志记录，我们可以更好地了解应用的运行状态、排查错误，甚至帮助团队进行性能优化。</p><p>在开发或生产环境中，可能会遇到以下问题：</p><ul><li>控制台日志输出过于混乱：控制台日志输出没有明显的视觉区分，开发者难以快速找到关键信息</li><li>文件日志管理不当：日志文件没有分目录管理，日志存储时间不固定，且文件体积容易过大</li><li>日志轮转：没有对日志文件进行按日期轮换，容易导致单个日志文件过大，不利于维护</li></ul><h2 id="61-安装依赖"><a class="markdownIt-Anchor" href="#61-安装依赖"></a> 6.1. 安装依赖</h2><p>我们首先需要安装 <code>chalk</code>、<code>nest-winston</code>、<code>winston</code> 和 <code>winston-daily-rotate-file</code> 这些依赖。</p><pre><code class="language-bash">yarn add chalk@^4 nest-winston winston winston-daily-rotate-file</code></pre><div class="danger"><p>注意：由于我的 NestJS 项目使用的是 CommonJS 模块系统，和使用 ESM 的 <code>chalk@5</code> 不兼容，所以我采用的最简单直接的方法就是降级到 <code>chalk@4</code>。</p></div><h2 id="62-配置-winston-日志文件"><a class="markdownIt-Anchor" href="#62-配置-winston-日志文件"></a> 6.2. 配置 <code>winston</code> 日志文件</h2><p>在 NestJS 项目中创建一个 <code>winston.logger.ts</code> 文件，用于配置 <code>winston</code> 的日志记录选项，包括日志等级、日志格式、文件轮转等。</p><h4 id="621-配置日志目录"><a class="markdownIt-Anchor" href="#621-配置日志目录"></a> 6.2.1. 配置日志目录</h4><p>我们将设置不同的日志目录来分别存储错误日志、警告日志和常规应用日志。</p><p>使用 <code>fs</code> 来检查目录是否存在，不存在时自动创建：</p><pre><code class="language-ts">import * as fs from 'fs';import * as path from 'path';const logDirectories = ['logs/errors', 'logs/warnings', 'logs/app'];logDirectories.forEach(dir =&gt; {  const fullPath = path.join(__dirname, '..', '..', dir);  try {    if (!fs.existsSync(fullPath)) {      console.log(`Creating directory at: ${fullPath}`);      fs.mkdirSync(fullPath, { recursive: true });    }  } catch (error) {    console.error(`Error creating directory ${fullPath}:`, error);  }});</code></pre><p>这段代码创建了 <code>logs/errors</code>、<code>logs/warnings</code> 和 <code>logs/app</code> 三个目录，用于分别保存错误、警告和常规日志。</p><h4 id="622-定义日志颜色"><a class="markdownIt-Anchor" href="#622-定义日志颜色"></a> 6.2.2. 定义日志颜色</h4><p>接下来，通过 <code>chalk</code> 为不同的日志级别定义颜色。这样在控制台输出时，不同的日志级别会有明显的颜色区分：</p><pre><code class="language-ts">import * as chalk from 'chalk';const getChalkColor = (level: string): chalk.Chalk =&gt; {  switch (level) {    case 'error':      return chalk.red;    case 'warn':      return chalk.yellow;    case 'info':      return chalk.green;    case 'debug':      return chalk.blue;    case 'verbose':      return chalk.cyan;    default:      return chalk.white;  }};</code></pre><p>这样做的好处是，可以根据日志等级设置不同颜色，从而在控制台中快速识别重要的日志信息。</p><h4 id="623-配置-winston-日志选项"><a class="markdownIt-Anchor" href="#623-配置-winston-日志选项"></a> 6.2.3. 配置 <code>winston</code> 日志选项</h4><p>接下来，我们配置 <code>winston</code> 的核心功能，包括日志格式、日志文件轮转和控制台输出：</p><pre><code class="language-ts">import { createLogger, format, transports } from 'winston';import * as DailyRotateFile from 'winston-daily-rotate-file';const winstonLogger = createLogger({  format: format.combine(format.timestamp(), format.errors({ stack: true }), format.splat(), format.json()),  defaultMeta: { service: 'log-service' },  transports: [    new DailyRotateFile({      filename: path.join(__dirname, '..', '..', 'logs/errors/error-%DATE%.log'),      datePattern: 'YYYY-MM-DD-HH-mm-ss',      zippedArchive: true,      maxSize: '20m',      maxFiles: '14d',      level: 'error'    }),    new DailyRotateFile({      filename: path.join(__dirname, '..', '..', 'logs/warnings/warning-%DATE%.log'),      datePattern: 'YYYY-MM-DD-HH-mm-ss',      zippedArchive: true,      maxSize: '20m',      maxFiles: '14d',      level: 'warn'    }),    new DailyRotateFile({      filename: path.join(__dirname, '..', '..', 'logs/app/app-%DATE%.log'),      datePattern: 'YYYY-MM-DD-HH-mm-ss',      zippedArchive: true,      maxSize: '20m',      maxFiles: '14d'    }),    new transports.Console({      format: format.combine(        format.colorize(),        format.simple(),        format.printf(info =&gt; {          const level = info.level.toLowerCase();          const chalkColor = getChalkColor(level);          return `${chalkColor(`${info.timestamp} - ${info.level}:`)} ${info.message}`;        })      ),      level: 'debug'    })  ]});export default winstonLogger;</code></pre><p>这段配置实现了以下几个功能：</p><ul><li><code>DailyRotateFile</code>：设置了日志文件的轮转，每个日志类型（错误、警告、应用）都将按日期命名并存储</li><li>控制台输出：控制台输出带有颜色区分，并包含时间戳和日志级别，便于快速读取</li><li>日志格式：定义了 <code>json</code> 格式日志输出，并包含 <code>timestamp</code> 和 <code>stack</code> 信息</li></ul><h2 id="63-引入日志配置"><a class="markdownIt-Anchor" href="#63-引入日志配置"></a> 6.3. 引入日志配置</h2><p>在 <code>AppModule</code> 中通过 <code>WinstonModule</code> 引入 <code>winstonLogger</code>，使日志系统能够全局生效：</p><pre><code class="language-ts">import { WinstonModule } from 'nest-winston';import winstonLogger from './loggers/winston.logger';@Module({  imports: [    // ...    WinstonModule.forRoot({      transports: winstonLogger.transports,      format: winstonLogger.format,      defaultMeta: winstonLogger.defaultMeta,      exitOnError: false    })  ]});</code></pre><p>通过 <code>WinstonModule.forRoot()</code> 配置，我们将之前定义的 <code>winstonLogger</code> 作为全局日志管理器，使 NestJS 自动将应用日志转发到 <code>winston</code>。</p><h2 id="64-应用日志系统"><a class="markdownIt-Anchor" href="#64-应用日志系统"></a> 6.4. 应用日志系统</h2><p>为了启用配置的日志系统，我们需要在 <code>main.ts</code> 中将其应用到应用程序：</p><pre><code class="language-ts">import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';async function bootstrap() {  // ...    app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER));  // ...}</code></pre><p>这样就将 <code>winston</code> 配置的日志记录器注入到应用中，使日志管理器可以通过 NestJS 的日志 API 来记录日志。</p><h2 id="65-修改-loggermiddleware"><a class="markdownIt-Anchor" href="#65-修改-loggermiddleware"></a> 6.5. 修改 <code>LoggerMiddleware</code></h2><p>最后，我们来修改一下 <code>LoggerMiddleware</code>，将其记录下每个请求的详细信息，包括：</p><ul><li>请求方法</li><li>URL</li><li>IP</li><li>HTTP 版本</li><li>状态码</li><li>响应时间等</li></ul><p>这在调试和性能分析时尤为有用。</p><pre><code class="language-ts">import { Injectable, Logger, NestMiddleware } from '@nestjs/common';import { Request, Response, NextFunction } from 'express';import * as dayjs from 'dayjs';@Injectable()export class LoggerMiddleware implements NestMiddleware {  private logger = new Logger();  use(req: Request, res: Response, next: NextFunction) {    const start = Date.now();    const { method, originalUrl, ip, httpVersion, headers } = req;    const { statusCode } = res;    res.on('finish', () =&gt; {      const end = Date.now();      const duration = end - start;      const logFormat = `${dayjs().valueOf()} ${method} ${originalUrl} HTTP/${httpVersion} ${ip} ${statusCode} ${duration}ms ${headers['user-agent']}`;      if (statusCode &gt;= 500) {        this.logger.error(logFormat, originalUrl);      } else if (statusCode &gt;= 400) {        this.logger.warn(logFormat, originalUrl);      } else {        this.logger.log(logFormat, originalUrl);      }    });    next();  }}</code></pre><ul><li>事件监听：使用 <code>finish</code> 事件来确保所有响应数据都已发送</li><li>日志格式：每个请求记录的格式包括请求时间、请求方法、URL、IP、状态码、响应耗时等信息</li><li>自动区分日志级别：根据响应的状态码自动设置日志等级<ul><li>错误状态码（500+）记录为 <code>error</code></li><li>客户端错误（400+）记录为 <code>warn</code></li><li>其他成功请求则都记录为 <code>log</code></li></ul></li></ul></body></html>]]></content>
    
    
    <summary type="html">本文是 React + NestJS 全栈购物平台实践的第二篇，专注于从零搭建一个生产级的 NestJS 后端项目框架。教程详细讲解了如何通过 @nestjs/config 和 Joi 实现类型安全的环境变量配置；如何使用 TypeORM 动态连接数据库；以及如何集成 Swagger 快速生成 API 文档。此外，文章还介绍了如何配置 helmet 安全防护、compression 响应压缩、@nestjs/throttler 速率限制等核心中间件，并重点演示了如何使用 Winston 构建一个支持分级、文件轮转和彩色输出的专业日志系统。本教程为启动一个健壮、可维护的 NestJS 应用提供了全方位的基础设施搭建指南。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="全栈实践" scheme="https://blog.cytrogen.icu/tags/%E5%85%A8%E6%A0%88%E5%AE%9E%E8%B7%B5/"/>
    
    <category term="Node.js" scheme="https://blog.cytrogen.icu/tags/Node-js/"/>
    
    <category term="React.js" scheme="https://blog.cytrogen.icu/tags/React-js/"/>
    
    <category term="TypeScript" scheme="https://blog.cytrogen.icu/tags/TypeScript/"/>
    
    <category term="NestJS" scheme="https://blog.cytrogen.icu/tags/NestJS/"/>
    
  </entry>
  
  <entry>
    <title>React + NestJS 购物平台练习【1】前端项目框架搭建</title>
    <link href="https://blog.cytrogen.icu/posts/6d86.html"/>
    <id>https://blog.cytrogen.icu/posts/6d86.html</id>
    <published>2024-10-29T04:00:00.000Z</published>
    <updated>2026-02-09T17:16:54.997Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>在现代电子商务发展迅速的今天，构建一个高效、易用的购物平台是开发者的一项关键技能。</p><p>该系列是全栈实践新坑，使用 React 和 NestJS 的技术栈、从零开始开发一个完整的购物平台（其实是先前开的几个全栈实践坑都让我意识到自己基础实力不足）。</p><span id="more"></span><h1 id="1-初始化-react-typescript-项目"><a class="markdownIt-Anchor" href="#1-初始化-react-typescript-项目"></a> 1. 初始化 React + TypeScript 项目</h1><ol><li><p>使用以下命令创建 React 项目：</p> <pre><code class="language-bash">yarn create react-app shopping-nest --template typescript</code></pre></li><li><p>导航至 <code>shopping-nest</code> 目录：</p> <pre><code class="language-bash">cd shopping-nest</code></pre></li><li><p>使用 Yarn 安装依赖：</p> <pre><code class="language-bash">// 安装 ESLint 和 Prettier 相关依赖yarn add @typescript-eslint/eslint-plugin @typescript-eslint/parseryarn add -D eslint prettier eslint-config-prettier eslint-plugin-prettieryarn add -D eslint-config-react-app// 安装 react-router-domyarn add react-router-dom @types/react-router-dom// 安装 axiosyarn add axios// 安装 TailwindCSS 相关依赖yarn add tailwindcss postcss autoprefixer// 安装 UI 组件和图标库yarn add @headlessui/reactyarn add lucide-react</code></pre></li><li><p>运行 <code>yarn run start</code> 检查一下是否会出问题。</p></li></ol><h1 id="2-配置-eslint-和-prettier"><a class="markdownIt-Anchor" href="#2-配置-eslint-和-prettier"></a> 2. 配置 ESLint 和 Prettier</h1><div class="danger"><ul><li>我使用的是 Jetbrains WebStorm，记得要更新到 2024 的版本喔。</li><li>ESLint 的版本为 <code>9.13.0</code>。</li><li>Prettier 的版本为 <code>3.3.3</code>。</li></ul></div><h2 id="21-配置-eslint"><a class="markdownIt-Anchor" href="#21-配置-eslint"></a> 2.1. 配置 ESLint</h2><ol><li><p>运行以下命令：</p> <pre><code class="language-bash">npx eslint --init</code></pre></li><li><p>根据自己的习惯选择。</p></li><li><p>生成的 <code>mjs</code> 配置文件差不多如下，我自己修改了 <code>files</code> 值为 <code>src</code> 目录下的文件。</p> <pre><code class="language-mjs">import globals from "globals";import pluginJs from "@eslint/js";import tseslint from "typescript-eslint";import pluginReact from "eslint-plugin-react";export default [  {files: ["src/**/*.{js,mjs,cjs,ts,jsx,tsx}"]},  {languageOptions: { globals: globals.browser }},  pluginJs.configs.recommended,  ...tseslint.configs.recommended,  pluginReact.configs.flat.recommended,];</code></pre><p>可以查看 <a href="https://eslint.org/docs/latest/use/configure/">ESLint 官方文档</a> 或者 <a href="https://typescript-eslint.io/users/configs">TypeScript-ESLint 文档</a> 自行修改。我自己就保留默认的了。</p></li></ol><h2 id="22-配置-prettier"><a class="markdownIt-Anchor" href="#22-配置-prettier"></a> 2.2. 配置 Prettier</h2><ol><li><p>在项目目录处创建 <code>.prettierrc</code> 文件一个（项目目录这里默认为 <code>package.json</code> 所在的目录）。</p></li><li><p>除了查看 <a href="https://prettier.io/docs/en/configuration.html">Prettier 官方文档</a> 自己填写外，还可以使用一些工具生成 Prettier 配置内容。</p><p>我这里用了 <a href="https://michelelarson.com/prettier-config/">Prettier Config Generator</a> 生成：</p> <pre><code class="language-json">{  "printWidth": 120,  "tabWidth": 2,  "useTabs": false,  "semi": true,  "singleQuote": true,  "trailingComma": "none",  "bracketSpacing":true,  "bracketSameLine": true,  "arrowParens": "avoid"}</code></pre></li></ol><h1 id="3-配置-tailwind-css"><a class="markdownIt-Anchor" href="#3-配置-tailwind-css"></a> 3. 配置 Tailwind CSS</h1><h2 id="31-安装并初始化-tailwind-css-配置"><a class="markdownIt-Anchor" href="#31-安装并初始化-tailwind-css-配置"></a> 3.1. 安装并初始化 TailWind CSS 配置</h2><p>在项目目录下使用以下命令来生成 <code>tailwind.config.js</code> 和 <code>postcss.config.js</code>：</p><pre><code class="language-bash">npx tailwindcss init -p</code></pre><p>然后修改 <code>tailwind.config.js</code> 的内容，将 <code>content</code> 配置为监控 <code>src</code> 文件夹下的所有文件，以便在这些文件中应用 TailWind 的样式：</p><pre><code class="language-js">/** @type {import('tailwindcss').Config} */export default {  content: [],  theme: {    extend: {},  },  plugins: []};</code></pre><p>在 <code>src/index.css</code> 文件的顶部添加以下内容，导入 TailWind 的核心样式、组件和工具：</p><pre><code class="language-css">@tailwind base;@tailwind components;@tailwind utilities;</code></pre><h2 id="32-安装并配置-daisyui-组件库"><a class="markdownIt-Anchor" href="#32-安装并配置-daisyui-组件库"></a> 3.2. 安装并配置 daisyUI 组件库</h2><p>为了方便开发，安装 <code>daisyUI</code> 组件库，它提供了丰富的组件和自定义主题功能：</p><pre><code class="language-bash">yarn add daisyui</code></pre><p>然后在 <code>tailwind.config.js</code> 文件中引入 <code>daisyUI</code> 插件：</p><pre><code class="language-js">import daisyui from "daisyui";// ...export default {  // ...  plugins: [    daisyui,  ],  daisyui: {}}</code></pre><p>对于 <code>daisyUI</code> 的配置，可以根据其 <a href="https://daisyui.com/docs/config/">文档</a> 进行修改。</p><p>我安装 <code>daisyUI</code> 还有一个目的，那就是其自定义主题的功能。</p><p>在 <code>daisyUI</code> 的 <a href="https://daisyui.com/theme-generator/">主题生成器</a> 里，你可以选择自己设计一套颜色方案，或者说随机出一套颜色方案。该页面中还有预览页面可供参考。</p><p>我对颜色不敏感，设计能力也很遭殃。这是我随机出的：</p><pre><code class="language-js">export default {  // ...  daisyui: {    themes: [      {        mytheme: {          "primary": "#60a5fa",          "primary-content": "#030a15",          "secondary": "#00b7ac",          "secondary-content": "#000c0b",          "accent": "#d68900",          "accent-content": "#100700",          "neutral": "#182f19",          "neutral-content": "#ccd1cc",          "base-100": "#32253a",          "base-200": "#2a1f31",          "base-300": "#221928",          "base-content": "#d2cfd4",          "info": "#00a7c9",          "info-content": "#000a0f",          "success": "#67c400",          "success-content": "#040e00",          "warning": "#f97316",          "warning-content": "#150500",          "error": "#dc2626",          "error-content": "#ffd9d4",        }      }    ]  }}</code></pre><h2 id="33-配置-postcss"><a class="markdownIt-Anchor" href="#33-配置-postcss"></a> 3.3. 配置 PostCSS</h2><p>根据 <a href="https://postcss.org/docs/">PostCSS 官方</a> 说的：</p><blockquote><p>PostCSS 是一种利用 JS 插件转换样式的工具。</p><p>这些插件可以检查 CSS、支持变量和混合体、转译未来的 CSS 语法、内联图片等。</p></blockquote><p><code>postcss.config.js</code> 的初始配置如下：</p><pre><code class="language-js">export default {  plugins: {    tailwindcss: {},    autoprefixer: {},  },};</code></pre><p>目前这是基本的配置。如果需要更多 PostCSS 功能，可以根据需求进一步配置。</p><h1 id="4-设置路由基础结构"><a class="markdownIt-Anchor" href="#4-设置路由基础结构"></a> 4. 设置路由基础结构</h1><p>路由系统是管理不同 URL 对应显示不同页面内容的机制。</p><h2 id="41-创建统一布局"><a class="markdownIt-Anchor" href="#41-创建统一布局"></a> 4.1. 创建统一布局</h2><p>作为开发者，在构建 Web 应用时，创建一个统一的布局非常重要。因为它能够为用户提供一致的界面的导航体验。</p><p>在大多数应用中，我们会有一些固定的部分，比方说导航栏、页脚，以及一个用于动态展示内容的区域。</p><pre><code class="language-tsx">import React from 'react';import { Outlet } from 'react-router-dom';</code></pre><p>首先引入 <code>Outlet</code>，它是 <code>react-router-dom</code> 提供的一个工具，允许在布局中插入不同的内容。</p><p>通过 <code>Outlet</code>，我们可以渲染由路由定义的组件，也就是首页啦、关于页这些，也不需要每次都重写导航和布局。</p><pre><code class="language-tsx">const MainLayout = () =&gt; {  return (    &lt;div&gt;      &lt;header className="bg-primary shadow"&gt;        &lt;nav className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"&gt;          {/* TODO: 导航内容 */}        &lt;/nav&gt;      &lt;/header&gt;</code></pre><p>用 <code>&lt;header&gt;</code> 标签来定义页面的头部，这里我之后会引入导航栏组件，先放个 <code>TODO</code> 马克一下。</p><pre><code class="language-tsx">      &lt;main&gt;        &lt;div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"&gt;          &lt;Outlet /&gt;        &lt;/div&gt;      &lt;/main&gt;    &lt;/div&gt;  );};</code></pre><p>接下来是 <code>&lt;main&gt;</code> 标签，它是页面的核心内容区域。</p><p><code>&lt;Outlet /&gt;</code> 会根据当前路由，动态渲染不同的组件。在开发中，这个设计的好处是我们可以轻松地切换页面，并保持一致的布局框架。</p><h2 id="42-路由配置"><a class="markdownIt-Anchor" href="#42-路由配置"></a> 4.2. 路由配置</h2><p>在单页面应用，也就是 SPA 中，路由是关键。它决定了用户访问某个路径时应该显示哪个组件。</p><p>我们现在需要一个机制，让用户能够在不同页面之间切换，比如从首页切换到用户账户信息页。路由能够帮助我们将 URL 和组件相互关联，确保用户在访问特定路径时，看到对应的页面。</p><pre><code class="language-tsx">import { createBrowserRouter } from 'react-router-dom';import MainLayout from './layouts/MainLayout';</code></pre><p>首先导入 <code>createBrowserRouter</code>，用它可以创建一个支持浏览器历史记录的路由系统。接着我们将先前定义好的 <code>MainLayout</code> 引入作为根布局。</p><pre><code class="language-tsx">const router = createBrowserRouter([  {    path: '/',    element: &lt;MainLayout /&gt;  }]);</code></pre><p>这意味着，无论用户访问的子页面是什么，<code>MainLayout</code> 的结构都会保持一致，而页面主体部分会根据路由变化而动态加载。</p><h2 id="43-设置应用入口"><a class="markdownIt-Anchor" href="#43-设置应用入口"></a> 4.3. 设置应用入口</h2><p><code>App</code> 组件是整个应用的入口。它负责将路由系统注入到 React 的组件树中，这样其他组件才能知道根据不同的路径应该显示什么内容。</p><p>为了加载整个路由配置，我们需要一个统一的入口，因此需要用到 <code>RouterProvider</code>。它将之前配置的路由传递给应用，让各个子组件能够根据 URL 做出相应的渲染。</p><pre><code class="language-tsx">import { RouterProvider } from 'react-router-dom';import router from './router';</code></pre><p>引入 <code>RouterProvider</code> 和先前定义好的 <code>router</code> 配置。</p><pre><code class="language-tsx">const App = () =&gt; {  return &lt;RouterProvider router={router} /&gt;;};</code></pre><p>用 <code>RouterProvider</code> 包裹住应用的根组件，并把 <code>router</code> 传递给它。通过这种方式，整个应用的路由系统就生效了。</p><p>虽然话是这么说，但因为内部什么组件都没写好，运行时还是什么都看不到的……</p><h1 id="5-配置状态管理工具"><a class="markdownIt-Anchor" href="#5-配置状态管理工具"></a> 5. 配置状态管理工具</h1><p>在开发中，状态管理是前端应用的核心部分之一，尤其是在涉及到用户登录、登出、数据持久化等功能时。</p><p>Zustand 是一个轻量级的状态管理库，它相比于 Redux 等传统工具更加简洁易用。因为是个练习项目，我便选择了这个更小巧的状态管理库。</p><h2 id="51-简单的例子"><a class="markdownIt-Anchor" href="#51-简单的例子"></a> 5.1. 简单的例子</h2><h4 id="511-初始化-zustand-状态管理器"><a class="markdownIt-Anchor" href="#511-初始化-zustand-状态管理器"></a> 5.1.1. 初始化 Zustand 状态管理器</h4><p>在 <code>src</code> 目录下创建一个 <code>stores</code> 目录，用于存放状态管理相关的文件。</p><p>在本例子中，代码结构分为三部分：状态定义和处理（<code>UserState</code>、<code>actions.ts</code>），Zustand 状态创建和持久化（<code>index.ts</code>），以及一些辅助函数（<code>api.ts</code>、<code>log.ts</code> 和 <code>selector.ts</code>）。</p><p>使用以下命令安装 Zustand：</p><pre><code class="language-bash">yarn add zustand</code></pre><p><code>stores</code> 目录下创建 <code>index.ts</code>，用作状态管理的入口，这样在应用的其他部分就可以方便地引入状态管理逻辑。</p><pre><code class="language-ts">import useUserStore from './user';</code></pre><p>作为一个大致的参考，我选择去写一个用户状态。这里先引入一下这个还未开始写的自定义钩子，理想情况下，它应当允许我们访问和操作与用户相关的状态。</p><p>在整个应用中，我们将通过这个钩子获取当前用户信息或调用登录操作。</p><h4 id="512-定义用户状态类型和接口"><a class="markdownIt-Anchor" href="#512-定义用户状态类型和接口"></a> 5.1.2. 定义用户状态类型和接口</h4><p><code>stores</code> 目录下创建 <code>user</code> 目录，接着又在 <code>user</code> 目录下创建 <code>types.ts</code>。</p><pre><code class="language-ts">export interface User {  id: string;  name: string;  email: string;}export interface UserState {  user: User | null;  isLoading: boolean;  error: string | null;}</code></pre><ul><li>TypeScript 中的 <code>interface</code> 用于定义用户状态的结构。使用 <code>interface</code> 能更直观地展示用户状态中的各项属性，同时在项目扩展时易于维护</li></ul><p>这里定义了 <code>User</code> 和 <code>UserState</code>，这两个接口分别描述了用户对象的结构和与用户相关的状态。</p><blockquote><p>当然，作为一个参考，这些值后续一定会进行修改或者扩展。</p></blockquote><ul><li><p><code>User</code> 接口不用多说。<code>UserState</code> 接口包括了：</p><ul><li><code>user</code>：当前登录的用户信息；没有用户登录的话就是 <code>null</code></li><li><code>isLoading</code>：是否正在进行异步操作，比如登录请求</li><li><code>error</code>：当然是错误信息啦</li></ul></li><li><p><code>setUser</code> 是一个函数属性，接收一个 <code>User</code> 或者 <code>null</code> 类型的参数</p></li><li><p><code>login</code> 函数属性接收 <code>LoginCredentials</code> 参数，并返回一个 <code>Promise&lt;User&gt;</code>（使用 TypeScript 的时候这样写有助于检查函数的参数和返回值类型，减少类型错误）</p></li></ul><h4 id="513-创建-zustand-状态管理器"><a class="markdownIt-Anchor" href="#513-创建-zustand-状态管理器"></a> 5.1.3. 创建 Zustand 状态管理器</h4><p><code>user</code> 目录下创建 <code>index.ts</code>。</p><p>我们通过 Zustand 来创建一个用户状态管理器。</p><pre><code class="language-ts">import { create } from 'zustand';import { devtools, persist } from 'zustand/middleware';import { UserState } from './types';import createUserSlice from './actions';const useUserStore = create&lt;UserState&gt;()(  devtools(    persist(      createUserSlice,      {        name: 'user-storage'      }    )  ));export default useUserStore;</code></pre><p>这里我们引入了 Zustand 的两个中间件：<code>devtools</code> 和 <code>persist</code>。</p><ul><li><code>devtools</code> 允许我们在开发时使用 Redux DevTools 进行状态调试，方便查看状态的变化</li><li><code>persist</code> 实现状态的持久化，将用户状态保存在 <code>localStorage</code> 中（先前使用 Redux 的时候，都是要手动使用 <code>localStorage</code> 进行持久性保存。Zustand 则可以直接使用 <code>persist</code> 中间件实现状态的持久化）。这样即使用户刷新页面，用户信息依然保留<ul><li><code>name: 'user-storage'</code> 指定了持久化状态的存储键名</li></ul></li></ul><h4 id="514-定义用户状态的操作与异步行为"><a class="markdownIt-Anchor" href="#514-定义用户状态的操作与异步行为"></a> 5.1.4. 定义用户状态的操作与异步行为</h4><p><code>user</code> 目录下创建 <code>actions.ts</code>，定义状态和异步操作。</p><pre><code class="language-ts">import { StateCreator } from 'zustand';import { User, UserState } from './types';const createUserSlice: StateCreator&lt;UserState&gt; = (set) =&gt; ({  user: null,  isLoading: false,  error: null,  setUser: (user: User | null) =&gt; set({ user }),  login: async (credentials: { email: string; password: string }) =&gt; {    set({ isLoading: true, error: null });    try {      // TODO: 调用API      set({ isLoading: false, user: response.data });    } catch (error) {      set({ isLoading: false, error: error.message });    }  }});export default createUserSlice;</code></pre><p>在这个文件中，我们定义了用户状态的操作逻辑和异步操作。</p><p>对于大多数应用来说，登录是一个异步过程，我们需要在发起请求时更新 <code>isLoading</code> 状态，同时在请求失败时记录错误信息。</p><ol><li><p>初始状态，也就是用户未登录时，<code>user</code> 设为 <code>null</code>、<code>isLoading</code> 为 <code>false</code>，<code>error</code> 也为空。</p></li><li><p><code>setUser</code> 是一个简单的同步方法，用于手动设置用户信息。</p></li><li><p><code>login</code> 是一个异步函数，用于处理登录逻辑。</p><p>开发中，典型的流程是：</p><ol><li>设置 <code>isLoading</code> 为 <code>true</code>，以便显示加载状态</li><li>发起登录请求（因为还没写，就用 <code>TODO</code> 标记了。注意哈，现在这个时候跑指定报错）</li><li>请求成功后，将返回的用户信息存储到状态中，并重置 <code>isLoading</code> 为 <code>false</code></li><li>如果请求失败，捕获错误，并更新 <code>error</code> 状态，用户可看到错误提示（现在当然不行）</li></ol></li></ol><h2 id="52-进阶配置"><a class="markdownIt-Anchor" href="#52-进阶配置"></a> 5.2. 进阶配置</h2><p>我们已经配置了 Zustand 的基本用户状态管理。接下来，我们将借助 TypeScript，进一步优化和扩展状态管理的功能，包括状态持久化、自定义中间件和选择器等。</p><h4 id="521-状态持久化与部分存储"><a class="markdownIt-Anchor" href="#521-状态持久化与部分存储"></a> 5.2.1. 状态持久化与部分存储</h4><p>在生产环境中，为了提升用户体验，状态持久化是一个常见需求。Zustand 提供了 <code>persist</code> 中间件，帮助我们将部分状态保存在 <code>localStorage</code> 或其他存储中，以确保页面刷新后状态不会丢失。</p><p>在 <code>stores/user/index.ts</code> 中，我们定义了 <code>persistOptions</code>，并在其中使用了 <code>partialize</code> 功能，将状态中关键的部分（如用户信息和更新时间）持久化：</p><pre><code class="language-ts">import { create } from 'zustand';import { devtools, persist, subscribeWithSelector } from 'zustand/middleware';import type { PersistOptions } from 'zustand/middleware';import { UserState } from './types';import createUserSlice from './actions';import { log } from '../common/log';import { createSelectors } from '../common/selector';type UserPersist = Pick&lt;UserState, 'user' | 'lastUpdated'&gt;;const persistOptions: PersistOptions&lt;UserState, UserPersist&gt; = {  name: 'user-storage',  partialize: (state) =&gt; ({    user: state.user,    lastUpdated: state.lastUpdated,  }),};</code></pre><ul><li><code>Pick&lt;UserState, 'user' | 'lastUpdated'&gt;</code>：使用 <code>Pick</code> 类型将 <code>UserState</code> 中的 <code>user</code> 和 <code>lastUpdated</code> 属性挑选出来，简化了持久化的内容</li><li><code>PersistOptions</code> 类型：类型声明让我们清楚地知道哪些状态会被持久化，避免错误持久化不必要的数据<ul><li><code>partialize</code> 是一个用于选择性地存储状态对象中部分属性的函数。在我们的 <code>persistOptions</code> 里，它的作用是从 <code>UserState</code> 状态中挑出 <code>user</code> 和 <code>lastUpdated</code> 这两个属性，并将其存储到持久化的存储中</li></ul></li></ul><h4 id="522-订阅特定的状态"><a class="markdownIt-Anchor" href="#522-订阅特定的状态"></a> 5.2.2. 订阅特定的状态</h4><p><code>subscribeWithSelector</code> 允许我们订阅特定的状态属性变化。与直接订阅整个状态的变化不同，它可以细化到仅在某些具体属性更新时触发回调，从而减少不必要的订阅响应。</p><p>继续写 <code>stores/user/index.ts</code>：</p><pre><code class="language-ts">const useUserStoreBase = create&lt;UserState&gt;()(  devtools(    persist(      subscribeWithSelector(        log(createUserSlice),      ),      persistOptions,    )  ));</code></pre><p>通过组合其他的 Zustand 插件，我们创建了一个订阅机制。这样做的好处是提高性能、避免不必要的渲染。</p><p>接下来这段代码订阅了 <code>useUserStoreBase</code> 中的 <code>user</code> 属性：</p><pre><code class="language-ts">useUserStoreBase.subscribe(  (state) =&gt; state.user,  (user) =&gt; {    if (user) {      console.log('User logged in: ', user.name);    } else {      console.log('User logged out');    }  })export const useUserStore = createSelectors(useUserStoreBase);</code></pre><ul><li><code>(state) =&gt; state.user</code> 是一个选择器函数，只返回 <code>state</code> 中的 <code>user</code> 属性，从而使订阅仅响应 <code>user</code> 的变化</li><li>当 <code>user</code> 属性变化时，回调触发。回调会根据 <code>user</code> 是否存在（如 <code>user</code> 为 <code>null</code>，或者用户登陆了新的信息）来输出不同的登录状态信息</li></ul><h4 id="523-自定义日志中间件"><a class="markdownIt-Anchor" href="#523-自定义日志中间件"></a> 5.2.3. 自定义日志中间件</h4><p>为了方便调试，我们可以创建一个日志中间件。这个中间件会在每次状态更新时，记录状态变化信息。</p><p>在 <code>stores/common/log.ts</code> 中定义 <code>log</code> 函数，扩展 Zustand 的 <code>set</code> 方法，使其在应用状态变化时输出变更详情。</p><p>先写一个泛型类型，用于定义 <code>set</code> 函数所接收的各种更新方式：</p><pre><code class="language-ts">import { StateCreator } from 'zustand';type SetStateAction&lt;T&gt; = T | Partial&lt;T&gt; | ((state: T) =&gt; T | Partial&lt;T&gt;);</code></pre><ul><li><code>SetStateAction&lt;T&gt;</code> 的作用是确保状态的更新类型符合期望，允许直接提供新的状态值、部分更新或基于当前状态的更新函数<ul><li><code>T</code>：泛型参数，表示整个状态对象的类型，例如 <code>UserState</code></li><li>类型定义：<ul><li><code>T</code>：可以直接传入整个状态对象，用于完全替换现有状态</li><li><code>Partial&lt;T&gt;</code>：可以传入部分状态对象，即只更新部分属性。<code>Partial&lt;T&gt;</code> 将状态对象的所有属性变为可选</li><li><code>(state: T) =&gt; T | Partial&lt;T&gt;</code>：可以传入一个函数，这个函数接收当前状态作为参数，并返回新的状态或部分状态。这种方式允许在回调中基于现有状态动态生成更新值</li></ul></li></ul></li></ul><p>这样写的目的是为了更灵活的状态更新方式，不仅可以直接替换状态，也可以部分更新或在回调函数中动态更新。</p><pre><code class="language-ts">export const log = &lt;T extends object&gt;(  config: StateCreator&lt;T, [], [], T&gt;): StateCreator&lt;T, [], [], T&gt; =&gt;  (set, get, api) =&gt; config(    (partial: SetStateAction&lt;T&gt;, replace?: boolean) =&gt; {      console.log('Applying', { partial, replace });      if (replace) {        set(partial as T | ((state: T) =&gt; T), true);      } else {        set(partial as SetStateAction&lt;T&gt;);      }      console.log('New state: ', get());    },    get,    api  );</code></pre><p><code>log</code> 是一个高阶函数（也就是 HOC），接受一个 Zustand 的 <code>StateCreator</code> 配置函数，并返回一个经过增强的 <code>StateCreator</code>，用于记录状态的变化。</p><p><code>log</code> 的作用是对传入的 <code>config</code> 配置函数进行包装，以便在状态更新时打印更新的内容和更新后的状态，用于调试。</p><ul><li><p><code>log</code> 的内部逻辑：</p><ol><li><p>参数：</p><ul><li><code>config</code>：一个 Zustand 的 <code>StateCreator</code> 函数，负责创建状态。此函数会调用 <code>set</code> 函数来更新状态</li></ul></li><li><p>返回值：一个增强的 <code>StateCreator</code> 函数，用于替代原始 <code>config</code> 函数</p></li><li><p>内部逻辑：</p><ul><li><p>包装 <code>set</code> 函数：调用 <code>config</code> 时，将自定义的 <code>set</code> 函数传入</p><ul><li><p>自定义的 <code>set</code> 函数接收 <code>partial</code> 和 <code>replace</code> 两个参数：</p><ul><li><code>partial</code>：可以是新的状态值、部分状态值，也可以是一个返回状态的函数</li><li><code>replace</code>：布尔值，表示是否完全替换现有状态</li></ul></li><li><p>日志输出：</p><ul><li><code>console.log('Applying', { partial, replace })</code> 在更新前输出即将应用的部分状态或新状态</li><li><code>console.log('New state: ', get())</code> 在更新后输出新的</li></ul></li></ul></li><li><p>更新逻辑：</p><ol><li>若 <code>replace</code> 为 <code>true</code>，则完全替换当前状态；否则只应用部分更新</li><li>调用 <code>get</code> 获取新的状态并打印日志</li></ol></li></ul></li></ol></li></ul><h4 id="524-状态选择器"><a class="markdownIt-Anchor" href="#524-状态选择器"></a> 5.2.4. 状态选择器</h4><p>在状态管理中，我们通常需要对状态进行选择，以便在不同组件中访问特定的状态字段。</p><p><code>createSelectors</code> 帮助我们自动生成访问器，减少在不同组件中冗余的状态逻辑。</p><p><code>stores/common/selector.ts</code> 中定义 <code>createSelectors</code>，它会为状态中的每个字段创建一个 <code>getter</code> 函数，便于状态的解耦：</p><pre><code class="language-ts">import { StoreApi, UseBoundStore } from 'zustand';type WithSelectors&lt;S&gt; = S extends { getState: () =&gt; infer T }  ? S &amp; { use: { [K in keyof T]: () =&gt; T[K] } }  : never;</code></pre><ul><li><code>WithSelectors&lt;S&gt;</code> 定义了一个条件类型，用于增强传入的 <code>store</code> 类型 <code>S</code><ul><li><code>S extends { getState: () =&gt; infer T }</code> 检查 <code>S</code> 是否包含 <code>getState</code> 方法，并从中推断出 <code>T</code> 类型（状态对象的类型）</li><li>返回：<ul><li>若 <code>S</code> 满足条件，则返回 <code>S</code> 并附加一个 <code>use</code> 属性<ul><li><code>use</code> 是一个对象，包含状态对象中每个键对应的 <code>getter</code> 方法，这些方法返回 <code>T[K]</code>，即每个状态属性的值</li></ul></li><li>若 <code>S</code> 不满足条件，则返回 <code>never</code></li></ul></li></ul></li></ul><pre><code class="language-ts">export const createSelectors = &lt;  S extends UseBoundStore&lt;StoreApi&lt;T&gt;&gt;,  T extends object&gt;(_store: S) =&gt; {  const store = _store as WithSelectors&lt;S&gt;;  store.use = {} as { [K in keyof T]: () =&gt; T[K] };  const state = store.getState();  for (const k of Object.keys(state) as Array&lt;keyof T&gt;) {    store.use[k] = () =&gt; state[k];  }  return store;}</code></pre><p><code>createSelectors</code> 函数：</p><ul><li>参数：接收一个 Zustand store 实例 <code>_store</code></li><li>类型约束：<ul><li><code>S extends UseBoundStore&lt;StoreApi&lt;T&gt;&gt;</code>：约束 <code>S</code> 必须是一个 <code>UseBoundStore</code> 类型的 store</li><li><code>T extends object</code>：状态对象 <code>T</code> 必须是一个对象</li></ul></li><li>逻辑：<ol><li>将传入的 store <code>_store</code> 进行类型转换，以便使用 <code>WithSelectors</code> 增强后的类型</li><li>为 <code>store</code> 增加 <code>use</code> 属性（一个空对象），作为存放每个状态属性 <code>getter</code> 方法的容器</li><li>获取当前 store 的 <code>state</code> 对象</li><li><code>for</code> 循环遍历 <code>state</code> 对象的键（即状态对象的属性）<ul><li>对每个键 <code>k</code>，在 <code>store.use</code> 中创建一个对应的 <code>getter</code> 方法 <code>store.use[k]</code>，返回 <code>state[k]</code> 的值</li></ul></li><li>返回增强后的 store 实例 <code>store</code>，其中包含 <code>use</code> 对象和对应的 <code>getter</code> 方法</li></ol></li></ul><p>假设 store 的状态对象如下：</p><pre><code class="language-ts">const useStore = createSelectors(  create((set) =&gt; ({    user: { name: "Alice", age: 30 },    loggedIn: true  })));</code></pre><p>那么调用 <code>useStore.use.user()</code> 就会返回：</p><pre><code class="language-plaintext">{ name: "Alice", age: 30 }</code></pre><h4 id="525-api-请求的配置和错误处理"><a class="markdownIt-Anchor" href="#525-api-请求的配置和错误处理"></a> 5.2.5. API 请求的配置和错误处理</h4><p>在前端状态管理中，一般会包含 API 请求的逻辑。</p><p>我们在 <code>stores/user/actions</code> 中，定义一个 <code>createUserSlice</code> 函数，它是 Zustand 中 <code>UserState</code> 的部分实现，用于管理用户相关的状态和操作。</p><p>首先导入依赖：</p><pre><code class="language-ts">import { StateCreator } from 'zustand';import { AxiosResponse } from 'axios';import { User, UserState, LoginCredentials } from './types';import api from '../common/api';</code></pre><p>定义状态和操作：</p><pre><code class="language-ts">const createUserSlice: StateCreator&lt;UserState&gt; = (set) =&gt; ({  user: null,  isLoading: false,  error: null,  lastUpdated: null,  // ...</code></pre><ul><li><code>user</code>：存储当前用户信息</li><li><code>isLoading</code>：指示登录操作是否正在进行中</li><li><code>error</code>：保存登录过程中发生的错误信息</li><li><code>lastUpdated</code>：记录上次用户数据更新的时间戳</li></ul><pre><code class="language-ts">// ...setUser: (user: User | null) =&gt; set({ user }),// ...</code></pre><ul><li><code>setUser</code>：一个同步方法，用于直接设置 <code>user</code> 状态。接收一个 <code>User</code> 对象或者 <code>null</code>，并调用 <code>set</code> 更新状态</li></ul><pre><code class="language-ts">// ...login: async (credentials: LoginCredentials) =&gt; {  set({ isLoading: true, error: null });  try {    const response: AxiosResponse&lt;User&gt; = await api.post&lt;User&gt;('/auth/login', credentials);    const user = response.data;    set({      user,      isLoading: false,      lastUpdated: Date.now(),      error: null    });    return user;  } catch (error) {    const errorMessage = error instanceof Error      ? error.message      : 'An unexpected error occurred during login';    set({      isLoading: false,      error: errorMessage,      user: null    });    throw error;  }},// ...</code></pre><p><code>login</code> 方法：</p><ul><li>启动加载状态：调用 <code>set({ isLoading: true, error: null })</code> 将 <code>isLoading</code> 设置为 <code>true</code>，并清除之前的错误</li><li>API 请求：<code>await api.post&lt;User&gt;('/auth/login', credentials)</code> 向服务器发送登录请求。返回的 <code>response.data</code> 包含了用户信息</li><li>成功处理：<ol><li>若请求成功，<code>set</code> 更新状态，存储用户数据、停止加载、设置 <code>lastUpdated</code> 时间戳，并清除错误</li><li>返回 <code>user</code>，便于在调用 <code>login</code> 的地方使用</li></ol></li><li>错误处理：<ol><li>如果请求失败，捕获 <code>error</code> 并生成错误消息</li><li>更新 <code>set</code> 将 <code>isLoading</code> 设置为 <code>false</code>，保存 <code>error</code> 信息，并将 <code>user</code> 设置为 <code>null</code></li><li>抛出错误，以便调用 <code>login</code> 的组件也能捕获并处理该错误</li></ol></li></ul><pre><code class="language-ts">  // ...  logout: () =&gt; {    set({      user: null,      error: null,      lastUpdated: null    });  }});export default createUserSlice;</code></pre><p><code>logout</code> 方法是登出功能，说白了就是将所有的状态设置为 <code>null</code>，从而达到清除当前用户信息和错误的效果。</p><h1 id="6-设置-api-请求封装"><a class="markdownIt-Anchor" href="#6-设置-api-请求封装"></a> 6. 设置 API 请求封装</h1><p>至于 API 嘛，写在了 <code>stores/common/api.ts</code> 中：</p><pre><code class="language-ts">import axios from 'axios';const api = axios.create({  baseURL: process.env.REACT_APP_API_URL,  timeout: 10000});</code></pre><p><code>axios</code> 配置了一个 API 实例 <code>api</code>，设置了基本的请求和响应拦截器。</p><ul><li><code>baseURL</code> 为环境变量 <code>REACT_APP_API_URL</code>，还设置了 10 秒的超时时间</li></ul><pre><code class="language-ts">api.interceptors.request.use(  (config) =&gt; {    // TODO: 添加认证信息    return config;  },  (error) =&gt; Promise.reject(error));</code></pre><ol><li><p>请求拦截器 <code>api.interceptors.request.use</code> 提供了请求发送前的自定义逻辑处理。可以在 <code>config</code> 中添加认证信息（也就是老生常谈的 JWT <code>Authorization</code> 头）。</p></li><li><p>如果请求在发送前就失败了，那么拦截器将直接拒绝该错误</p></li></ol><pre><code class="language-ts">api.interceptors.response.use(  (response) =&gt; response,  (error) =&gt; {    // TODO: 统一错误信息    return Promise.reject(error);  });export default api;</code></pre><p>响应拦截器 <code>api.interceptors.response.use</code> 允许在接收到响应时进行自定义处理。</p><ol><li>响应成功会直接返回数据</li><li>请求出错，<code>error</code> 就会被统一处理，然后传递给调用方处理</li></ol><p>有很多功能先放 <code>TODO</code> 了，能差不多 GET 到意思就好。</p></body></html>]]></content>
    
    
    <summary type="html">本文是 React + NestJS 全栈购物平台系列实践的第一篇，专注于从零开始搭建一个现代化的前端项目框架。教程详细记录了项目的初始化、ESLint 与 Prettier 的配置、以及 Tailwind CSS 与 daisyUI 组件库的集成。文章重点讲解了如何使用 react-router-dom 构建路由结构，并引入轻量级状态管理库 Zustand，深入探讨了其状态持久化、选择性订阅和自定义中间件等高级用法。本教程为启动一个健壮、可维护的 React + TypeScript 项目提供了完整的脚手架搭建指南。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="全栈实践" scheme="https://blog.cytrogen.icu/tags/%E5%85%A8%E6%A0%88%E5%AE%9E%E8%B7%B5/"/>
    
    <category term="Node.js" scheme="https://blog.cytrogen.icu/tags/Node-js/"/>
    
    <category term="React.js" scheme="https://blog.cytrogen.icu/tags/React-js/"/>
    
    <category term="TypeScript" scheme="https://blog.cytrogen.icu/tags/TypeScript/"/>
    
    <category term="NestJS" scheme="https://blog.cytrogen.icu/tags/NestJS/"/>
    
  </entry>
  
  <entry>
    <title>MUS 1003 笔记</title>
    <link href="https://blog.cytrogen.icu/posts/8386.html"/>
    <id>https://blog.cytrogen.icu/posts/8386.html</id>
    <published>2024-09-29T08:00:48.000Z</published>
    <updated>2026-02-09T17:16:54.733Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>乐理笔记，仅作为个人学习记录，不保证正确性。</p><span id="more"></span><div class="danger"><p>采用的教科书是国外的，里面写的所有有关「我们」的字眼并非代表我本人！</p></div><h1 id="1-音乐基础"><a class="markdownIt-Anchor" href="#1-音乐基础"></a> 1. 音乐基础</h1><h2 id="11-声音-音高-动态和音色"><a class="markdownIt-Anchor" href="#11-声音-音高-动态和音色"></a> 1.1. 声音、音高、动态和音色</h2><p>声音（Sound）始于物体的振动，例如被敲击的桌子或者被拨动的琴弦。振动通过一种介质（通常是空气）传递到我们的耳朵。由于振动，我们的耳膜也开始振动，并将脉冲或信号传递到大脑。在那里，这些脉冲被选择、组织和解释。</p><p>我们可以通过识别音乐声音的四个主要属性来区分音乐和其他声音：</p><ul><li>音高（Pitch）</li><li>动态（响度或柔和度）（Dynamics）</li><li>音色（Tone color）</li><li>时长（Duration）</li></ul><h4 id="111-音高声音的高低"><a class="markdownIt-Anchor" href="#111-音高声音的高低"></a> 1.1.1. 音高：声音的高低</h4><p>音高（Pitch）是我们在声音中听到的相对高低。</p><blockquote><p>打个比方，我们听一下经典的生日歌，能发现最高的音调出现在第三个【生日】上。</p></blockquote><p>声音的音高由其振动频率决定。振动越快，音高越高；振动越慢，音高越低。振动频率以每秒周期数来衡量。在钢琴上，最高频率的音调是每秒 4186 个周期，最低的是每秒约 27 个周期。</p><p>一般来说，振动物体越小，振动越快，音高越高。在其他条件相同的情况下，拨动短弦会比拨动长弦产生出更高的音高。比方说小提琴，它的弦对比低音贝斯的弦更短、产生的音高自然也更高。</p><p>在音乐中，具有明确音高的声音被称为音调（Tone）。它具有特定的频率，且振动是规则的、以相等的时间间隔到达耳朵。另一方面，噪音类的声音（比如说刹车声、碰撞的钹声）由于由不规则的振动产生，因此具有不确定的音高。</p><p>当两个音调具有不同的音高时，它们会听起来不同。两个音调之间的「距离」被称为音程（Interval）。当音调被称为八度（Octave）的音程分隔时，它们听起来非常相似。</p><blockquote><p>八度指的是两个音之间的间隔、其中高音的频率是低音的两倍。</p><p>唱或听《Over the Rainbow》这首歌的开头：「Somewhere over the rainbow」。</p><p>注意，<em>-where</em> 上的音调听起来像 <em>Some-</em> 上的音调，尽管它更高。它们之间有一个八度。<em>Some-</em> 上的音调的振动频率正好是 <em>where</em> 上的音调的一半。如果 <em>Some-</em> 音调是每秒 440 个周期，那么 <em>where</em> 音调 —— 也就是高一个八度 —— 将是每秒 880 个周期。比 <em>Some-</em> 低一个八度的音调将是 440 的一半，即每秒 220 个周期。当同时发出时，相隔一个八度的两个音调融合得如此之好，以至于它们几乎似乎合并成一个音调。</p></blockquote><p>八度音程在音乐中很重要。它是熟悉的音阶中第一个音和最后一个音之间的音程。可以试试唱一下这个音阶：</p><p><img src="/posts/8386/1.webp" alt="do-re-mi-fa-sol-la-ti-do" loading="lazy"></p><p>注意，在到达高音 <em>do</em> 之前，八度音程由七个不同的音高填充，高音 <em>do</em>「复制」了低音 <em>do</em>。如果你从高音 <em>do</em> 开始并继续向上演奏音阶，你的每一个原始七个音调都会在高一个八度的地方被「复制」。几个世纪以来，这组七个音调一直是西方文明音乐的基础。这七个音调由钢琴键盘的白键产生：</p><p><img src="/posts/8386/2.webp" alt="钢琴白键上的do-re-mi-fa-sol-la-ti-do" loading="lazy"></p><p>随着时间的推移，原来的七个音高又增加了五个音高。这五个音高由键盘的黑键产生。所有十二个音调，像原来的七个音调一样，在高八度和低八度中被「复制」。每个音调都有「近亲」，相隔 1、2、3 或更多个八度。（在非西方音乐中，八度可能被分为不同数量的音调 —— 比如说，十七或二十二个。）</p><p>一个声音或乐器可以产生的最低音和最高音之间的距离称为其音高范围（Pitch range），或简称为范围（Range）。普通未经训练的声音范围在 1 到 2 个八度之间；钢琴的范围超过 7 个八度。当男人和女人唱同一首旋律时，他们通常会相隔一个八度来唱。</p><p>尽管我们所知道的大多数音乐都是基于明确的音高，但不确定音高（如低音鼓或钹发出的声音）也同样重要。一些打击乐器，如锣、牛铃和木块，有不同的尺寸，因此会产生更高或更低的不确定音高。高低不确定音高之间的对比在当代西方音乐和世界各地的音乐文化中起着至关重要的作用。</p><h4 id="112-动态"><a class="markdownIt-Anchor" href="#112-动态"></a> 1.1.2. 动态</h4><p>音乐中的响度或柔和度称为动态（Dynamics）—— 这是声音的第二个属性。响度与产生声音的振动幅度有关。吉他弦被拨动得越用力（离指板越远），声音就越响。当乐器演奏得更响或更柔和，或者听到的乐器数量发生变化时，就会产生动态变化；这种变化可以是突然的，也可以是逐渐的。响度的逐渐增加通常会产生兴奋感，特别是当音高也上升时。另一方面，响度的逐渐减小可以传达一种平静的感觉。</p><p>演奏者可以通过比周围音调更响亮地演奏某个音调来强调它。这种强调被称为重音（Accent）。巧妙、微妙的动态变化为表演增添了活力和情感。有时这些变化会写在乐谱中；但通常，它们并没有写出来，而是由演奏者对音乐的感受所激发的。</p><p>在记录音乐时，作曲家传统上使用意大利词语及其缩写来表示动态。最常见的术语是：</p><p><img src="/posts/8386/3.webp" alt="pianissimo-pp-very_soft;piano-p-soft;mezzo_piano-mp-moderately_soft;mezzo_forte-mf-moderately_loud;forte-f-loud;fortissimo-ff-very_loud" loading="lazy"></p><p>对于极端的柔和和响亮，作曲家使用 <em>ppp</em> 或 <em>pppp</em> 和 <em>fff</em> 或 <em>ffff</em>。以下符号表示动态的逐渐变化：</p><p><img src="/posts/8386/4.webp" alt="decrescendo/diminuedo-gradually_softer;crescendo-gradually_louder" loading="lazy"></p><p>像音乐的许多元素一样，动态指示并不是绝对精确的。一个音调的动态水平 —— 是柔和还是响亮 —— 是相对于周围的其他音调而言的。单把小提琴的最响亮声音与整个管弦乐队的最响亮声音相比是微不足道的，与扩音摇滚乐队相比则更微不足道。但在其自身的上下文中，它可以被认为是极强音（非常响亮）。</p><h4 id="113-音色"><a class="markdownIt-Anchor" href="#113-音色"></a> 1.1.3. 音色</h4><p>即使小号和长笛在相同的动态水平上演奏相同的音调，我们也能区分它们。区分它们的特质 —— 我们所说的音乐声音的第三个属性 —— 称为音色（也被称为 timbre，发音为 <em>tam′-ber</em>）。音色可以用明亮、暗淡、辉煌、柔和和丰富等词来描述。</p><p>与动态变化一样，音色变化也创造了多样性和对比。当同一旋律由一种乐器演奏，然后由另一种乐器演奏时，由于每种乐器的音色不同，它会呈现出不同的表现效果。另一方面，音色的对比可以用来突出新的旋律：在小提琴演奏旋律之后，双簧管可能会呈现出对比鲜明的旋律。</p><p>音色也建立了一种连续感；当每次都是相同的乐器演奏时，更容易识别旋律的回归。特定的乐器可以增强旋律的情感影响：小号的辉煌声音适合英雄或军队的曲调；长笛的舒缓音色适合平静的旋律。事实上，作曲家经常在创作旋律时考虑特定乐器的音色。</p><p>作曲家可以使用几乎无限多样的音色。结合不同的乐器 —— 例如小提琴、单簧管和长号 —— 会产生新的音色，这是单个乐器无法独自产生的。而且，通过改变演奏旋律的乐器或声音的数量，可以改变音色。最后，近年来发展起来的电子技术使作曲家能够创造出完全不同于传统乐器的音色。</p><h2 id="12-演奏媒介声音和乐器"><a class="markdownIt-Anchor" href="#12-演奏媒介声音和乐器"></a> 1.2. 演奏媒介：声音和乐器</h2><h4 id="121-声音"><a class="markdownIt-Anchor" href="#121-声音"></a> 1.2.1. 声音</h4><p>纵观历史，歌唱一直是最广泛和最熟悉的音乐形式。古希腊戏剧包括吟唱的合唱团，《圣经》记载摩西、米利暗和以色列人唱歌赞美主。歌手似乎总是具有磁性的吸引力，即使在今天，崇拜的观众也会模仿他们最喜欢的歌手的外貌和生活方式。</p><p>歌手和观众之间的交流包含了一点魔力，一种直接而迷人的东西。可能是因为歌手成为了一种乐器，我们特别能与他或她产生共鸣 —— 一个像我们自己一样的人体通过声音和词语表达情感。</p><p>声音具有将词语与音乐音调融合的独特能力，因此在许多文化中，诗歌和歌唱是不可分割的。歌唱可以使词语更容易记住，并能增强其情感效果。</p><p>由于许多原因，唱好歌是困难的。在歌唱中，我们使用比说话更广泛的音高和音量范围，并且我们更长时间地保持元音。歌唱需要更大的呼吸供应和控制。来自肺部的空气由下腹肌和横膈膜控制。空气使声带振动，歌手的肺、喉咙、嘴巴和鼻子共同作用以产生所需的声音。音调的高低随着声带的紧张度而变化；它们越紧，音调越高。</p><p>歌手的音域取决于训练和身体构造。专业歌手可以掌握 2 个八度甚至更多，而未经训练的声音通常限制在大约 1½ 个八度。男性的声带比女性的更长更厚，这种差异产生了较低的音高范围。以下是女性和男性的音域分类，从最高到最低排列（四个基本音域是女高音、女低音、男高音和男低音）：</p><table><thead><tr><th>女性</th><th>男性</th></tr></thead><tbody><tr><td>女高音（soprano）</td><td>男高音（tenor）</td></tr><tr><td>次女高音（mezzo-soprano）</td><td>男中音（baritone）</td></tr><tr><td>女低音（alto）或女中音（contralto）</td><td>男低音（bass）</td></tr></tbody></table><p>由于品味的不同，歌唱方法在不同文化中差异很大。例如，亚洲的歌唱比西方的更鼻音化。我们的文化中的古典歌手站立时姿势笔直，而西非的歌手则向前弯腰；印度的歌手则坐在地上。事实上，即使在西方，表演风格也有所不同：古典、流行、爵士、民间和摇滚音乐的演唱方式各不相同。例如，古典歌手通常不依赖麦克风，但摇滚音乐部分依靠扩音来传达其特点。</p><p>直到 17 世纪末，大多数西方文化的音乐都是声乐。但到 17 世纪末，器乐音乐的重要性与声乐音乐不相上下。从那时起，作曲家们继续创作独唱和合唱声乐作品，有的带有器乐伴奏，有的没有。作品有为男声合唱团创作的；为女声合唱团创作的；以及为混声合唱团创作的，通常结合女高音、女低音、男高音和男低音。声乐作品的伴奏范围从单一乐器（如吉他或钢琴）到整个管弦乐队。</p><h4 id="122-乐器"><a class="markdownIt-Anchor" href="#122-乐器"></a> 1.2.2. 乐器</h4><p>世界各地的人们使用的乐器在结构和音色上有很大的不同。乐器可以定义为除人声以外的任何产生音乐声音的机制。西方音乐家通常将乐器分为六大类：弦乐器（如吉他和小提琴）；木管乐器（长笛、单簧管）；铜管乐器（小号、长号）；打击乐器（低音鼓、钹）；键盘乐器（风琴、钢琴）；和电子乐器（合成器）。</p><p>一种乐器通常有不同的尺寸，产生不同的音域。例如，萨克斯管家族包括高音萨克斯管、中音萨克斯管、次中音萨克斯管、上低音萨克斯管和低音萨克斯管。乐器的音色可能会随着演奏的音区（总音域的一部分）而变化。单簧管在低音区听起来深沉而丰富，但在高音区则明亮而尖锐。</p><p>器乐演奏者试图模仿歌手声音的美丽和灵活的音色。然而，大多数乐器的音域比人声更广。先前说过，受过训练的歌手的音域大约是 2 个八度，但许多乐器可以达到 3 或 4 个八度，有些甚至可以达到 6 或 7 个八度。此外，乐器通常比人声更快地产生音调。在为特定乐器写作音乐时，作曲家必须考虑其音域和动态以及它能多快地产生音调。</p><h4 id="123-弦乐器"><a class="markdownIt-Anchor" href="#123-弦乐器"></a> 1.2.3. 弦乐器</h4><p>小提琴（Violin）、中提琴（Viola）、大提琴（Cello，有时也被称为 Violoncello）和低音贝斯（Double bass，有时也被简称为 Bass）构成了交响乐团的弦乐（String）部分。它们在音色、大小和音域上各不相同：小提琴是最小的，音域最高；低音贝斯是最大的，音域最低。在交响乐中，弦乐器通常用弓（Bow）演奏，弓是一根稍微弯曲的棍子，上面紧紧地系着马鬃（见下图）。交响乐的弦乐器也可以用手指拨奏。</p><p><img src="/posts/8386/5.webp" alt="img.png" loading="lazy"></p><p>在所有的乐器组中，弦乐器具有最大的多功能性和表现力。它们能产生许多音色，并且具有广泛的音高和动态范围。弦乐演奏者可以产生明亮而快速的音调，也可以产生缓慢而颤动的音调；他们可以像歌手一样微妙地控制音色。交响乐作品往往更多地依赖弦乐器，而不是其他乐器组。即使音色不同，这四种弦乐器也能完美地融合在一起。在这里，考虑弦乐器的结构和音色产生方式是有帮助的；小提琴可以代表整个家族。</p><p>小提琴的中空木质琴身支撑着四根通常由金属或合成材料制成的琴弦。（即使在今天，一些演奏者仍然偏爱由紧密缠绕的肠线制成的传统琴弦。）琴弦在张力下从一端的尾部穿过木桥延伸到另一端，在那里它们被固定在木钉上。琴桥将琴弦与指板分开，使其能够自由振动；琴桥还将琴弦的振动传递到琴身，从而放大和改变音色。每根琴弦通过拧紧或松开琴钉来调节不同的音高。（张力越大，音高越高。）</p><p>演奏者用右手拉动弓使琴弦振动。弓的速度和压力控制着产生的声音的动态和音色。音高由演奏者的左手控制。通过将琴弦按在指板上，演奏者改变了其振动部分的长度，从而改变了音高。这被称为按弦（Stopping）（因为振动在琴弦长度的某个点被停止）。因此，每根琴弦都可以产生一系列的音高。</p><p>基本上，中提琴、大提琴和低音贝斯的制作方式相同，发声方式也相似。弦乐器的演奏方式 —— 使用的弦乐演奏技巧 —— 决定了它们将产生的许多音乐效果。这里列出了最常用的技巧：</p><ul><li>拨弦（Pizzicato）：演奏者用右手的手指拨动琴弦。在爵士乐中，低音贝斯主要作为拨弦乐器演奏，而不是用弓拉奏。</li><li>双音（Double stop，两个音同时发声）：通过将弓拉过两根琴弦，弦乐演奏者可以同时发出两个音。通过快速旋转弓跨过三根琴弦（三音，Triple stop）或四根琴弦（四音，Quadruple stop），可以几乎同时发出三或四个音。</li><li>颤音（Vibrato）：弦乐演奏者可以通过在按下琴弦时摇动左手来产生颤动的、富有表现力的音调。这会引起小的音高波动，使音调更加温暖。</li><li>弱音器（Mute）：演奏者可以通过在琴桥上安装一个夹子（弱音器）来遮蔽或减弱音调。</li><li>颤音（Tremolo）：演奏者通过快速上下拉动弓来快速重复音调。当音量大时，这可以创造一种紧张感；当音量小时，可以产生一种闪烁的声音。</li><li>泛音（Harmonics）：当演奏者轻轻触摸琴弦的某些点时，会产生非常高的音调，类似于哨声。</li></ul><p>尽管小提琴、中提琴、大提琴和低音提琴相似，但它们就像任何家庭的成员一样，各有不同。</p><p>有些弦乐器不是用弓演奏的，而是用手指或拨片（Plectrum）拨奏的。其中最重要的是竖琴（Harp）和吉他（Guitar）。竖琴是唯一在交响乐团中获得广泛接受的拨弦乐器。</p><h4 id="124-木管乐器"><a class="markdownIt-Anchor" href="#124-木管乐器"></a> 1.2.4. 木管乐器</h4><p>木管乐器（Woodwind instruments）之所以得名，是因为它们在传统上是通过木制管内的空气振动来发声的。然而，在二十世纪期间，短笛（Piccolos）和长笛（Flutes）开始用金属制成。所有木管乐器沿其长度都有小孔，这些小孔可以用手指或由按键机制控制的垫片来开闭。通过开闭这些孔，木管乐器演奏者改变了振动空气柱的长度，从而改变音高。</p><p>交响乐团的主要木管乐器如下，按音域从最高（短笛）到最低（低音大管）排列。（每个家族中仅列出最常用的两种乐器。）</p><table><thead><tr><th>长笛家族</th><th>单簧管家族</th><th>双簧管家族</th><th>巴松管家族</th></tr></thead><tbody><tr><td>短笛（Piccolo）</td><td></td><td></td><td></td></tr><tr><td>长笛（Flute）</td><td>单簧管（Clarinet）</td><td></td><td></td></tr><tr><td></td><td></td><td>双簧管（Oboe）</td><td></td></tr><tr><td></td><td></td><td>中音双簧管 / 英国管（English horn）</td><td></td></tr><tr><td></td><td>低音单簧管（Bass clarinet）</td><td></td><td>巴松管（Bassoon）</td></tr><tr><td></td><td></td><td></td><td>倍低音管（Contrabassoon）</td></tr></tbody></table><p>木管乐器是伟大的个体主义者，其音色与各种弦乐器相比差异更大。长笛的银色音调与鼻音的双簧管相比，比小提琴与中提琴的差异更大。木管乐器独特的音色主要来自不同的振动方式。长笛和短笛演奏者通过吹过吹口边缘发声，就像吹空瓶口发声一样。（竖笛 Recorder 演奏者通过哨子吹口发声，竖笛是长笛的亲属。）其余的木管乐器依靠振动的簧片发声。簧片（Reed）是一块非常薄的芦苇片，约 2½ 英寸长，通过气流振动。</p><p>单簧木管乐器（Single-reed woodwinds）的簧片固定在吹口的孔上，当演奏者吹入乐器时，簧片振动。单簧管和低音单簧管是单簧木管乐器。萨克斯管（Saxophone）也是一种主要用于乐队的单簧木管乐器。在双簧木管乐器（Double-reed woodwinds）中，两片窄窄的芦苇片夹在演奏者的嘴唇之间。双簧管、英国管、巴松管和低音巴松管是双簧木管乐器。</p><p>单独听起来，簧片只会发出一种刺耳的声音。虽然簧片木管乐器的音色主要由乐器管的孔径决定，但簧片确实会对音色产生一定影响。专业的木管乐器演奏者花费大量时间浸泡和塑造他们的簧片，以确保获得最佳音色。</p><p>每种木管乐器的不同音区的音色也有很大差异。一般来说，低音区往往气息浓重，而高音区则更为尖锐。与可以双音演奏的弦乐器不同，木管乐器一次只能发出一个音。在交响乐中，它们经常被赋予旋律独奏。木管乐器非常适合户外演奏（牧羊人几千年来一直在演奏简单的木管乐器）。因此，它们经常出现在唤起乡村氛围的音乐中。</p><h4 id="125-铜管乐器"><a class="markdownIt-Anchor" href="#125-铜管乐器"></a> 1.2.5. 铜管乐器</h4><p>从高音区到低音区，交响乐团铜管乐器（Brass instruments）的主要乐器有小号（Trumpet）、法国号（French horn，有时简称为号 Horn）、长号（Trombone）和大号（Tuba）。小号和长号经常用于爵士乐和摇滚乐队。</p><p>铜管乐器的振动来自演奏者的嘴唇，当他或她吹入杯状或漏斗状的吹口（Mouthpiece）时产生振动。这些振动在一个盘绕的管子中被放大和改变音色（以便于携带和演奏）。管子的末端张开形成一个喇叭口（Bell）。现代铜管乐器实际上是由黄铜制成的，但它们的早期版本是由空心动物角、象牙、木头甚至玻璃制成的。</p><p>一些铜管乐器，如短号、上低音号和次中音号，主要用于音乐会和行进乐队。短号的形状类似于小号，但音色更柔和。上低音号看起来像大号，音域与长号相同。次中音号是大号家族中的男高音乐器。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;乐理笔记，仅作为个人学习记录，不保证正确性。&lt;/p&gt;</summary>
    
    
    
    <category term="学术笔记" scheme="https://blog.cytrogen.icu/categories/%E5%AD%A6%E6%9C%AF%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="大学课程" scheme="https://blog.cytrogen.icu/tags/%E5%A4%A7%E5%AD%A6%E8%AF%BE%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>IBM 全栈开发【13・下】：全栈应用程序开发者毕业设计</title>
    <link href="https://blog.cytrogen.icu/posts/ed32.html"/>
    <id>https://blog.cytrogen.icu/posts/ed32.html</id>
    <published>2024-07-08T03:54:00.000Z</published>
    <updated>2026-02-09T17:16:54.717Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程，故此记录学习笔记。</p><span id="more"></span><div class="danger"><p>该文章不会继续更新！</p></div><h1 id="1-复习和考试准备"><a class="markdownIt-Anchor" href="#1-复习和考试准备"></a> 1. 复习和考试准备</h1><h2 id="11-云计算概述"><a class="markdownIt-Anchor" href="#11-云计算概述"></a> 1.1. 云计算概述</h2><h4 id="111-云计算简介"><a class="markdownIt-Anchor" href="#111-云计算简介"></a> 1.1.1. 云计算简介</h4><ul><li>云计算是指通过互联网按需提供计算资源，采取即用即付的方式。</li><li>资源在多个用户之间动态分配和重新分配，并根据用户的需求扩大或缩小规模。</li><li>云计算的起源可以追溯到 20 世纪 50 年代的大型机，虚拟化技术和管理程序是现代云计算出现的催化剂。</li><li>企业必须考虑自身的业务需求、投资可行性和风险承受能力，以制定云计算应用战略，在不造成业务中断或安全、合规性或性能问题的情况下实现预期效益。</li><li>云技术应用的增长速度超过预期。推动这一技术浪潮的是提供从基础设施到平台和软件服务等一系列服务的云服务提供商。我们这个时代的一些主要云提供商包括 AWS、阿里巴巴云、谷歌、IBM 和 Microsoft Azure。</li></ul><h4 id="112-云计算的商业案例"><a class="markdownIt-Anchor" href="#112-云计算的商业案例"></a> 1.1.2. 云计算的商业案例</h4><ul><li>无论企业规模大小，采用云技术都能使企业变得灵活、具有创新性和竞争力，并创造与众不同的客户体验。企业提出的问题不是他们是否应该迁移到云技术，而是他们应该采取什么战略迁移到云技术。</li><li>一些案例研究展示了企业通过采用云技术所产生的影响：<ul><li>美国航空公司采用云技术，在整个企业内迅速为客户创造价值。</li><li>UBank 利用云平台服务为开发人员提供更多控制权，从而消除创新障碍。</li><li>Bitly 利用云基础设施提供的可扩展性，为其地理位置分散的企业客户提供低延迟交付。</li><li>ActivTrades 利用云计算提供的基础设施、存储、网络和安全服务，加快在线交易系统的执行，并向客户交付新功能。</li></ul></li></ul><h4 id="113-云技术加速了新兴技术的发展"><a class="markdownIt-Anchor" href="#113-云技术加速了新兴技术的发展"></a> 1.1.3. 云技术加速了新兴技术的发展</h4><ul><li>以云计算为动力的新兴技术正在颠覆现有的商业模式，为企业的发展、创新和为客户创造价值创造前所未有的机遇。</li><li>一些案例研究展示了云计算新兴技术的使用如何为全球数百万人创造价值：<ul><li>利用云上的物联网打击南非偷猎濒危犀牛的行为。</li><li>美国网球协会利用云上人工智能为全球数百万球迷提供独特的数字体验。</li><li>云端区块链通过建立食品供应链的可追溯性和透明度，帮助农民减少浪费。</li><li>KONE 公司利用数据分析为城市基础设施提供预测性维护解决方案。</li></ul></li></ul><h2 id="12-云计算模式"><a class="markdownIt-Anchor" href="#12-云计算模式"></a> 1.2. 云计算模式</h2><h4 id="121-服务模式"><a class="markdownIt-Anchor" href="#121-服务模式"></a> 1.2.1. 服务模式</h4><ul><li>云计算使我们能够以服务的形式利用技术，以按需付费的模式利用远程资源。云计算主要有三种服务模式：基础设施即服务（LaaS）、平台即服务（PaaS）和软件即服务（SaaS）。<ul><li>对于 IaaS，云提供商管理物理资源。</li><li>对于 PaaS，提供商管理平台基础设施。</li><li>在 SaaS 模式中，提供商托管并管理应用程序和数据。</li></ul></li><li>基础设施即服务是云计算的一种形式，通过网络以按需付费的方式向消费者提供基本的计算机、网络和存储资源。</li><li>云基础设施的主要组成部分包括：<ul><li>物理数据中心</li><li>计算</li><li>网络</li><li>存储</li></ul></li><li>平台即服务是一种为客户提供完整平台的云计算模式： 硬件、软件和基础设施。</li><li>高度抽象、支持服务、运行时环境、快速部署机制和中间件功能是 PaaS 云的显著特征。</li><li>PaaS 的优势在于：<ul><li>可扩展性</li><li>产品和服务更快上市</li><li>更大的灵活性和创新性</li></ul></li></ul></body></html>]]></content>
    
    
    <summary type="html">本文是 IBM 全栈开发毕业设计课程的最后一篇笔记（下篇），旨在为期末考试复盘云计算的基础知识。笔记回顾了云计算的定义、商业价值，及其在物联网、人工智能等领域的应用，并总结了IaaS、PaaS、SaaS三种核心服务模式的要点。请注意：作者已标明本文将不会继续更新。 这篇摘要可作为考前快速复习的参考资料。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="IBM" scheme="https://blog.cytrogen.icu/tags/IBM/"/>
    
  </entry>
  
  <entry>
    <title>IBM 全栈开发【13・上】：全栈应用程序开发者毕业设计</title>
    <link href="https://blog.cytrogen.icu/posts/41a3.html"/>
    <id>https://blog.cytrogen.icu/posts/41a3.html</id>
    <published>2024-07-07T04:00:00.000Z</published>
    <updated>2026-02-09T17:16:54.717Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程，故此记录学习笔记。</p><span id="more"></span><p>恭喜您成功完成 IBM 全栈软件开发人员专业证书的所有前面课程！现在是通过完成期末考试来检验您的新技能的时候了。</p><p>您将通过考试，了解自己在 PC 各门课程中学到的知识。现在，您应该已经熟练掌握了以下主题：</p><ul><li>云计算的核心概念</li><li>网页开发语言，包括 HTML、CSS 和 JavaScript</li><li>Git 和 GitHub</li><li>Node.js、Express 和 React</li><li>容器</li><li>Python</li><li>数据库概念和相关技术，如 SQL 和 Django</li><li>微服务和无服务器计算</li></ul><p>这是 IBM 全栈软件开发人员专业证书的最后一门课程。它将测试您迄今为止所掌握的知识和技能。本课程包含分级期末考试，涵盖 PC 中各种课程的内容。</p><p>您将就以下主题接受评估：核心云计算概念；HTML、CSS、JavaScript 和 Python 等语言；Node.js、Express 和 React 等框架；以及 Docker、Kubernetes、OpenShift、SQL、Django、微服务和 Serverless 等后端技术。</p><p>在学习本课程之前，请确保您已完成 IBM 全栈开发人员专业证书中的所有先前课程。</p><h1 id="通过附加功能丰富汽车经销商门户网站"><a class="markdownIt-Anchor" href="#通过附加功能丰富汽车经销商门户网站"></a> 通过附加功能丰富汽车经销商门户网站</h1><p>该课程从模块开始：通过三个实验丰富汽车经销商门户网站的附加功能。</p><p>在「全栈应用程序开发项目」（可见 <a href="/posts/fa4d.html">文章</a>）中，您创建了一个汽车经销商应用程序，需要开发前端页面、用户管理、构建数据库操作动作、创建后端服务以及配置 CI / CD 管道。前端使用的技术包括 HTML、CSS、JavaScript 和 React，后端使用的技术包括 Django、Node.js、NoSQL（Mongo）、容器化、IBM 代码引擎、Python 和 Kubernetes。</p><p>通过汽车经销商应用程序，我们可以根据经销商的 ID 查看所有经销商的详细信息和评论，还可以注册、登录为用户，并在注册或登录后为特定经销商添加新的评论，方法是将 <code>About</code> 和 <code>Contact Us</code> 等静态页面整合到一起。</p><p>用户注册和登录功能也是在为端点和 Django 视图配置了 Express-Mongo 后端微服务后实现的。还集成了一个情感分析微服务来分析评论。也实现了各种功能，如显示经销商列表、详细信息和评论，在 Django 应用程序中添加新的经销商评论。最后，将 CI / CD Linting 服务集成到应用程序中，并部署到 Kubernetes 上。</p><p>在本课程中，您将从增强同一个汽车经销商应用程序开始。改进的重点是前端方面，然后通过添加新的微服务转移到后端，最后在后续实验中将其与前端集成。</p><p>强烈建议先完成全栈应用程序开发项目课程，然后再学习本课程，因为本模块的实验是增强已建应用程序的一部分。虽然这些内容不属于评分标准的一部分，但它们对于增强你的理解和技能仍然很有价值。</p><h2 id="概述"><a class="markdownIt-Anchor" href="#概述"></a> 概述</h2><p>作为毕业设计项目的一部分，您已经成功创建并测试了 <code>Car Dealerships website</code>，确保其符合预期功能。这包括允许用户查看所有经销商的详细信息、查看对特定经销商的现有评论，以及在作为注册用户登录后发布对特定经销商的新评论。</p><p>完成上述工作后，下一步就是增强应用程序的功能。这涉及到应用程序的前端和后端方面。如下所述，您将分三部分实施这些增强功能：</p><ol><li><p>前端改进</p><ul><li>将 <code>Dealerships</code> 页面上的 <code>States</code> 下拉菜单转换为可搜索文本框，使用户能够通过输入搜索字符串来筛选经销商。</li><li>改进应用程序主页上导航栏和经销商按钮的配色方案，以及 <code>Dealerships Review</code> 页面上审查面板和审查图标的颜色。</li><li>微调经销商审查面板的视觉元素，对字体大小和字体对齐方式等方面进行调整。</li></ul></li><li><p>汽车库存后端服务</p><ul><li>使用 MongoDB 和 Node.js 服务器建立一个新的后端微型服务，专门用于获取与汽车库存相关的各种详细信息。</li><li>将新创建的微服务与 Django 应用程序的后端集成，并验证后端服务器的成功启动。</li></ul></li><li><p>汽车库存服务的前端开发</p><ul><li>开发前端组件，并将其与 <a href="#%E7%AC%AC-2-%E9%83%A8%E5%88%86%E6%B1%BD%E8%BD%A6%E5%BA%93%E5%AD%98%E5%90%8E%E7%AB%AF%E6%9C%8D%E5%8A%A1">第 2 部分：汽车库存后端服务</a> 中开发的后端汽车库存微服务集成。</li><li>创建一个按 <strong>品牌</strong>、<strong>型号</strong>、<strong>年份</strong>、<strong>里程</strong> 和 <strong>价格</strong> 选择汽车的选项。</li><li>对 Django 应用程序与集成的汽车库存服务生成的输出进行全面测试。</li></ul></li></ol><h2 id="前端改进"><a class="markdownIt-Anchor" href="#前端改进"></a> 前端改进</h2><h4 id="将-dealerships-页面上的-states-下拉菜单转换为可搜索文本框"><a class="markdownIt-Anchor" href="#将-dealerships-页面上的-states-下拉菜单转换为可搜索文本框"></a> 将 <code>Dealerships</code> 页面上的 <code>States</code> 下拉菜单转换为可搜索文本框</h4><ol><li>访问 <code>frontend/src/components/Dealers/Dealers.jsx</code> 文件。</li><li>您会注意到，经销商下拉菜单的代码是在 <code>&lt;select&gt;</code> 下拉菜单元素中显示的：<pre><code class="language-jsx">&lt;select name="state" id="state" onChange={(e) =&gt; filterDealers(e.target.value)}&gt;&lt;/select&gt;</code></pre></li><li>用包含以下属性的 <code>&lt;input&gt;</code> 字段取代现有的 <code>&lt;select&gt;</code> 元素：<ul><li>用户可在文本框中输入搜索州。</li><li>根据输入的搜索查询过滤显示的经销商，并与州匹配。</li><li>当输入框失去焦点时，将显示的经销商重置为原始列表。</li></ul><pre><code class="language-jsx">&lt;input type="text" placeholder="Search states..." onChange={handleInputChange} onBlur={handleLostFocus} value={searchQuery} /&gt;</code></pre></li></ol><p>观察输入元素中的函数。现在，让我们创建它们。</p><ol><li>创建一个名为 <code>handleInputChange</code> 的新函数，用于管理输入更改，并根据输入的状态查询过滤经销商。<pre><code class="language-jsx">const handleInputChange = (event) =&gt; {  const query = event.target.value;  setSearchQuery(query);  const filtered = originalDealers.filter(dealer =&gt;    dealer.state.toLowerCase().includes(query.toLowerCase())  );  setDealersList(filtered);};</code></pre><ul><li>每次输入框内的值发生变化时，都会触发该函数。</li><li>它会检索用户在输入框中输入的当前值，并将其作为查询存储在 <code>setSearchQuery</code> 变量中，用于筛选经销商。</li><li>系统会生成一个新数组，其中只包含状态与输入的查询相匹配的经销商。</li><li>通过将查询和经销商状态转换为小写，使其大小写不敏感，从而确保用户获得更友好的搜索体验。</li><li>然后，该函数将显示与输入的状态查询相匹配的经销商。</li></ul></li><li>总之，<code>handleInputChange</code> 函数可根据用户在搜索栏中的输入动态过滤经销商列表。它实时更新显示的经销商列表，为用户提供响应式搜索功能。</li><li>创建 <code>handleLostFocus</code> 函数，以确保当用户将搜索输入留空并点击或滑动标签离开时，经销商列表会重置为原始列表。<pre><code class="language-jsx">const handleLostFocus = () =&gt; {  if (!searchQuery) {    setDealersList(originalDealers);  }}</code></pre><ul><li>该函数在执行时验证 <code>searchQuery</code> 状态是否为空。</li><li>如果 <code>searchQuery</code> 确实为空，它就会将经销商列表恢复到开始搜索前的原始状态。</li><li><code>handleLostFocus</code> 函数在用户点击输入框外或标签页离开输入框时调用，由 <code>onBlur</code> 事件触发。</li></ul></li><li>将此代码与之前定义的其他状态变量一起添加：<pre><code class="language-jsx">const [searchQuery, setSearchQuery] = useState('');</code></pre><ul><li>这将利用 <code>useState</code> 钩子创建一个名为 <code>searchQuery</code> 的状态变量和一个相应的函数 <code>setSearchQuery</code> 来更新其值。</li><li><code>searchQuery</code> 状态变量实时保存用户在搜索输入框中输入的值。当用户在搜索栏中输入时，该状态变量会通过调用 <code>setSearchQuery</code> 进行更新，并触发组件的重新渲染，以反映对搜索查询所做的任何更改。</li></ul></li><li>初始化和设置状态变量，用于管理原始经销商列表。<ul><li>添加以下代码，初始化 <code>dealersList</code>、<code>searchQuery</code> 和 <code>states</code> 变量及其设置函数：<pre><code class="language-jsx">const [originalDealers, setOriginalDealers] = useState([]);</code></pre>在这段代码中，状态变量 <code>originalDealers</code> 及其设置函数 <code>setOriginalDealers</code> 用于跟踪和更新原始经销商列表。</li><li>将下面的代码放在 <code>getDealers</code> 函数中更新其他状态（<code>setStates</code> 和 <code>setDealersList</code>）的地方。<pre><code class="language-jsx">setOriginalDealers(all_dealers);</code></pre>这一行用从应用程序接口获取的所有经销商数组设置状态变量 <code>originalDealers</code>，用于存储过滤前的原始经销商列表。</li></ul></li><li>确保保存所有更改。</li><li>运行以下命令来构建应用程序的客户端：<pre><code class="language-bash">cd /home/project/xrwvm-fullstack_developer_capstone/server/frontendnpm run build</code></pre></li><li>访问经销商详细信息页面，测试应用程序的输出。</li><li>请观察用于经销商搜索的搜索框的外观，它取代了之前的下拉框。</li><li>输入搜索查询，例如 <code>Texas</code>，搜索该州来进行测试。</li></ol><h4 id="更改应用程序的配色方案"><a class="markdownIt-Anchor" href="#更改应用程序的配色方案"></a> 更改应用程序的配色方案</h4><p>在本节中，您将了解在以下区域更改应用程序配色方案的步骤：</p><ul><li><p>与应用程序主页有关的方面，包括：</p><ol><li>更改导航栏的背景颜色。</li><li>修改 <code>View Dealerships</code> 按钮的背景颜色。</li></ol></li><li><p>与 <code>Dealership Review</code> 页面有关的方面包括：</p><ol><li>调整与 <code>Review</code> 面板相关的背景颜色。</li><li>自定义与 <code>Review</code> 图标相关的悬浮边框。</li></ol></li></ul><ol><li><p><strong>更改导航栏的背景颜色</strong></p><ol><li>打开文件 <code>frontend/static/Home.html</code>。</li><li>您将看到以下代码片段，它将当前的深绿色背景添加到应用程序中的导航栏：<pre><code class="language-html">&lt;nav class="navbar navbar-expand-lg navbar-light" style={{backgroundColor:"darkturquoise",height:"1in"}}&gt;</code></pre></li><li>用您喜欢的颜色（如 <code>mediumspringgreen</code>）代替它，以修改页眉的背景颜色。<pre><code class="language-html">&lt;nav class="navbar navbar-expand-lg navbar-light" style="background-color:mediumspringgreen; height: 1in;"&gt;</code></pre></li><li>保存更改。</li><li>运行提供的命令构建客户端并显示上述更改：<pre><code class="language-bash">npm run build</code></pre></li><li>刷新应用页面。</li><li>观察导航栏背景的变化。</li></ol></li><li><p><strong>修改 <code>View Dealerships</code> 按钮的背景颜色</strong></p><ol><li>以下代码表示应用程序主页上 <code>View Dealerships</code> 按钮的背景颜色：<pre><code class="language-html">&lt;a href="/dealers" class="btn" style="background-color: aqua;margin:10px"&gt;View Dealerships&lt;/a&gt;</code></pre></li><li>将其调整为您喜欢的颜色（例如，<code>plum</code>，一种紫色）。<pre><code class="language-html">&lt;a href="/dealers" class="btn" style="background-color: plum; margin:10px"&gt;View Dealerships&lt;/a&gt;</code></pre></li><li>请观察 <code>View Dealerships</code> 按钮的最新配色方案。</li></ol></li><li><p><strong>调整与 <code>Review</code> 面板相关的背景颜色</strong></p><ol><li><code>Dealers.css</code> 文件中的样式是为应用程序中的 <code>Dealerships</code> 和 <code>Reviews</code> 面板定制的。<code>review_panel</code> 类包含用于设计经销商审查面板样式的代码。</li><li>请注意，它的边框是纯灰色的。<pre><code class="language-css">border: solid grey;</code></pre></li><li>调整代码，使其具有纯紫色边框：<pre><code class="language-css">border: solid purple;</code></pre></li><li>你会发现 <code>Review</code> 面板的边框变成了纯紫色，外观也发生了变化。</li></ol></li><li><p><strong>自定义与 <code>Review</code> 图标相连的悬浮边框</strong></p><ol><li>当用户将鼠标悬停在 <code>Review</code> 图标上时，<code>.review_icon:hover</code> 类将为其应用样式。</li><li>请注意，悬停时它的背景是纯浅灰色。<pre><code class="language-css">border: solid lightgray;</code></pre></li><li>将颜色调整为黑色色调，边框变细（如 2 像素），以便在悬停时呈现出鲜明而纤细的背景外观。<pre><code class="language-css">border: 2px solid #080808;</code></pre></li><li>观察修改后的图标，它带有细细的黑色边框，悬停时会显示出明显的存在感。</li></ol></li></ol><h4 id="更改应用程序的外观和感觉"><a class="markdownIt-Anchor" href="#更改应用程序的外观和感觉"></a> 更改应用程序的外观和感觉</h4><p>在本节中，您将学习如何改进应用程序中 <code>Dealer Review</code> 面板的视觉效果。</p><p>其中包括：</p><ul><li>调整字体大小</li><li>确保字体对齐正确，以改善整体外观</li></ul><ol><li><p><strong>调整字体大小</strong></p><ol><li><code>.reviewer</code> 类定义了用户评论的样式。</li><li>当前字体大小设置为小。</li><li>将字体大小调整到特定值（例如 18 像素），以放大 <code>Review</code> 文本，提高可读性。<pre><code class="language-css">font-size: 18px;</code></pre></li></ol></li><li><p><strong>确保字体对齐正确，改善整体外观</strong></p><ol><li>文本对齐属性并未被指定。</li><li>因此，浏览器的默认文本对齐方式（通常为左对齐）会被应用，从而产生左对齐的 <code>Review</code> 文本。</li><li>将文本居中，以确保 <code>User reviews</code> 显示在 <code>Review</code> 窗格的中心。<pre><code class="language-css">text-align: center;</code></pre></li></ol></li></ol><h2 id="汽车库存后端服务"><a class="markdownIt-Anchor" href="#汽车库存后端服务"></a> 汽车库存后端服务</h2><h4 id="使用-mongodb-和-nodejs-开发新的后端汽车库存微服务"><a class="markdownIt-Anchor" href="#使用-mongodb-和-nodejs-开发新的后端汽车库存微服务"></a> 使用 MongoDB 和 Node.js 开发新的后端汽车库存微服务</h4><ol><li><p>打开一个新的终端窗口，导航到 <code>xrwvm-fullstack_developer_capstone/server</code> 目录。<br>生成一个名为 <code>carsInventory</code> 的新目录。</p><pre><code class="language-bash">mkdir carsInventory</code></pre></li><li><p>执行以下命令，初始化一个新的 Node.js 项目，并在 <code>carsInvent</code> 目录下创建 <code>package.json</code> 文件：</p><pre><code class="language-bash">npm init</code></pre><p>将以下应用程序依赖项添加到 <code>package.json</code> 中：</p><pre><code class="language-json"> "cors": "^2.8.5",    "express": "^4.18.2","mongodb": "^6.3.0","mongoose": "^8.0.1"</code></pre><p>这些依赖项对于启用 CORS（跨源资源共享）、处理网络应用程序路由和中间件（Express）、与 MongoDB 交互（MongoDB 驱动程序）以及在使用 MongoDB 的 Node.js 应用程序中提供便捷的数据建模方式（Mongoose）至关重要。</p><p>每个依赖关系中版本号前的 <code>^</code> 符号允许在运行 <code>npm install</code> 命令时安装兼容的未来更新。</p><p>将 <code>name</code> 设置为 <code>carsInventory</code>，将 <code>main</code> 的值设置为 <code>app.js</code>。这样，<code>package.json</code> 文件看起来应该与下面相似：</p><pre><code class="language-json"> {  "name": "carsInventory",  "version": "1.0.0",  "description": "",  "main": "app.js",  "scripts": {     "test": "echo \"Error: no test specified\" &amp;&amp; exit 1"  },  "author": "",  "license": "ISC",  "dependencies": {    "cors": "^2.8.5",        "express": "^4.18.2",    "mongodb": "^6.3.0",    "mongoose": "^8.0.1"  }}</code></pre><p>执行命令安装这些依赖项：</p><pre><code class="language-bash">npm install</code></pre></li><li><p>在名为 <code>inventory.js</code> 的文件中设置 MongoDB schema。现在，您将使用 <code>mongoose</code> 库为名为 <code>cars</code> 的集合建立 MongoDB schema。<br>这将用于创建一个与 MongoDB 数据库交互的 <code>mongoose</code> 模型，使应用程序能够以更有条理、更有组织的方式对汽车文档执行 CRUD 操作。<br>schema 应定义汽车文件的结构，其中应包括以下字段及其数据类型：</p><ul><li><code>dealer_id</code>：<code>Number</code></li><li><code>make</code>：<code>String</code></li><li><code>model</code>：<code>String</code></li><li><code>bodyType</code>：<code>String</code></li><li><code>year</code>：<code>Number</code></li><li><code>mileage</code>：<code>Number</code></li><li><code>price</code>：<code>Number</code></li></ul><p>模型将被命名为 <code>cars</code>，与所连接的 MongoDB 数据库中的 <code>cars</code> 集合相对应。MongoDB 模型将以此名称导出。</p><pre><code class="language-js">const { Int32 } = require('mongodb');const mongoose = require('mongoose');const Schema = mongoose.Schema;const cars = new Schema({  dealer_id: {    type: Number,    required: true  },  make: {    type: String,    required: true  },  model: {    type: String,    required: true  },  bodyType: {    type: String,    required: true  },  year: {    type: Number,    required: true  },  mileage: {    type: Number,    required: true  },  price: {    type: Number,    required: true  }});module.exports = mongoose.model('cars', cars);</code></pre></li><li><p>获取包含汽车库存和相关详细信息的 JSON 数据集。<br>首先创建一个名为 <code>data</code> 的文件夹并导航进入：</p><pre><code class="language-bash">mkdir datacd data</code></pre><p>下载汽车库存数据集：</p><pre><code class="language-bash">wget https://cf-courses-data.s3.us.cloud-object-storage.appdomain.cloud/IBM-CD0321EN-SkillsNetwork/labs/v2/m6/car_records.json</code></pre><p>检查文件，发现每个汽车对象都有以下字段：</p><pre><code class="language-plaintext">make, model, bodyType, year, dealer_id, mileage, price</code></pre></li><li><p>返回 <code>carsInvent</code> 目录，创建更多文件。</p><p>建立具有后端端点功能的 Node.JS 服务器。首先创建一个名为 <code>app.js</code> 的文件：</p><pre><code class="language-bash">touch app.js</code></pre><p>它应具备以下功能：</p><ul><li>设置与 MongoDB 集成的 Express 服务器</li><li>从文件 <code>car_records.json</code> 中读取数据</li><li>建立与 MongoDB 的连接</li><li>定义根 API 端点 <code>/</code>，当访问根 API 时，它会响应一条欢迎访问 Mongoose API 消息</li><li>定义以下六个端点，用于根据各种条件查询汽车：<ul><li><code>cars/:id</code> 端点，可根据指定的经销商 ID 从 MongoDB 集合中检索并返回汽车文档</li><li><code>/carsbymake/:id/:make</code> 端点，可根据经销商 ID 和汽车品牌检索并返回汽车文档</li><li><code>/carsbymake/:id/:model</code> 端点，可根据经销商 ID 和车型检索并返回汽车文档</li><li><code>/carsbymaxmileage/:id/:mileage</code> 端点，可根据经销商 ID 和里程限制检索并返回汽车文件，如下所示：<ul><li>里程数：<ul><li>小于或等于 50000</li><li>50000 至 100000</li><li>100000 至 150000</li><li>150000 至 200000</li><li>大于 200000</li></ul></li></ul></li><li><code>/carsbyprice/:id/:price</code> 端点，可根据经销商 ID 和价格约束检索并返回汽车文件，如下所示：<ul><li>价格：<ul><li>小于或等于 20000</li><li>20000 至 40000</li><li>40000 至 60000</li><li>60000 至 80000</li><li>大于 80000</li></ul></li></ul></li><li><code>/carsbymake/:id/:year</code> 端点，可根据经销商 ID 和最低年份约束检索并返回汽车文件</li></ul></li><li>在 <code>3050</code> 端口启动服务器。</li></ul><pre><code class="language-js">/*jshint esversion: 8 */const express = require('express');const mongoose = require('mongoose');const fs = require('fs');const cors = require('cors');const app = express();const port = 3050;app.use(cors());app.use(express.urlencoded({ extended: false }));const carsData = JSON.parse(fs.readFileSync('car_records.json', 'utf8'));mongoose.connect('mongodb://mongo_db:27017/', { dbName: 'dealershipsDB' });const Cars = require('./inventory');try {  Cars.deleteMany({}).then(() =&gt; {    Cars.insertMany(carsData.cars);  });} catch (error) {  console.error(error);  // Handle errors properly here}app.get('/', async (req, res) =&gt; {  res.send('Welcome to the Mongoose API');});app.get('/cars/:id', async (req, res) =&gt; {  try {    const documents = await Cars.find({dealer_id: req.params.id});    res.json(documents);  } catch (error) {    res.status(500).json({ error: 'Error fetching reviews' });  }});app.get('/carsbymake/:id/:make', async (req, res) =&gt; {  try {    const documents = await Cars.find({dealer_id: req.params.id, make: req.params.make});    res.json(documents);  } catch (error) {    res.status(500).json({ error: 'Error fetching reviews by car make and model' });  }});app.get('/carsbymodel/:id/:model', async (req, res) =&gt; {  try {    const documents = await Cars.find({ dealer_id: req.params.id, model: req.params.model });    res.json(documents);  } catch (error) {    res.status(500).json({ error: 'Error fetching dealers by ID' });  }});app.get('/carsbymaxmileage/:id/:mileage', async (req, res) =&gt; {  try {    let mileage = parseInt(req.params.mileage)    let condition = {}    if(mileage === 50000) {      condition = { $lte : mileage}    } else if (mileage === 100000){      condition = { $lte : mileage, $gt : 50000}    } else if (mileage === 150000){      condition = { $lte : mileage, $gt : 100000}    } else if (mileage === 200000){      condition = { $lte : mileage, $gt : 150000}    } else {      condition = { $gt : 200000}    }    const documents = await Cars.find({ dealer_id: req.params.id, mileage : condition });    res.json(documents);  } catch (error) {    res.status(500).json({ error: 'Error fetching dealers by ID' });  }});app.get('/carsbyprice/:id/:price', async (req, res) =&gt; {  try {    let price = parseInt(req.params.price)    let condition = {}    if(price === 20000) {      condition = { $lte : price}    } else if (price=== 40000){      console.log("\n \n \n "+ price)        condition = { $lte : price, $gt : 20000}    } else if (price === 60000){      condition = { $lte : price, $gt : 40000}    } else if (price === 80000){      condition = { $lte : price, $gt : 60000}    } else {      condition = { $gt : 80000}    }    const documents = await Cars.find({ dealer_id: req.params.id, price : condition });    res.json(documents);  } catch (error) {    res.status(500).json({ error: 'Error fetching dealers by ID' });  }});app.get('/carsbyyear/:id/:year', async (req, res) =&gt; {  try {    const documents = await Cars.find({ dealer_id: req.params.id, year : { $gte :req.params.year }});    res.json(documents);  } catch (error) {    res.status(500).json({ error: 'Error fetching dealers by ID' });  }});app.listen(port, () =&gt; {  console.log(`Server is running on http://localhost:${port}`);});</code></pre></li><li><p>为 Node.js 应用程序创建 Docker 镜像。首先创建 <code>Dockerfile</code>：</p><pre><code class="language-bash">touch Dockerfile</code></pre><p>添加以下内容：</p><ul><li>基础 Docker 镜像：<code>node:18.12.1-bullseye-slim</code></li><li>安装 <code>9.1.3</code> 版本的 <code>npm</code></li><li>从当前目录内添加 <code>package.json</code>、<code>app.js</code>、<code>car_records.json</code> 到 Docker 镜像的根目录</li><li>复制当前目录的所有文件到 Docker 镜像</li><li>让容器监听 3050 端口</li><li>将容器启动时要运行的默认命令指定为 <code>node app.js</code></li></ul><pre><code class="language-dockerfile">FROM node:18.12.1-bullseye-slimRUN npm install -g npm@9.1.3ADD package.json .ADD app.js .ADD data/car_records.json .COPY . .RUN npm installEXPOSE 3050CMD [ "node", "app.js" ]</code></pre></li><li><p>为运行两个服务（MongoDB 容器和 Node.js 应用程序）设置 Docker Compose 配置文件。<br>创建 Docker Compose 配置 YAML 文件（<code>docker-compose.yml</code>）：</p><pre><code class="language-bash">touch docker-compose.yml</code></pre><p>添加内容：</p><pre><code class="language-yaml">version: '3.9'services:  # Mongodb service  mongo_db:    container_name: carsInventory_container    image: mongo:latest    ports:      - 27018:27017    restart: always    volumes:      - mongo_data:/data/db  # Node api service  api:    image: nodeapp    ports:      - 3050:3050    depends_on:      - mongo_dbvolumes:  mongo_data: {}</code></pre><p>构建 Docker 应用：</p><pre><code class="language-bash">docker build . -t nodeapp</code></pre><p>执行以下命令启动服务器：</p><pre><code class="language-bash">docker-compose up</code></pre><p>启动服务器并验证汽车库存服务的根端点是否显示了 <code>Welcome to the Mongoose API</code> 的消息。</p></li></ol><h4 id="将微服务与-django-应用程序后端集成并成功启动后端服务器"><a class="markdownIt-Anchor" href="#将微服务与-django-应用程序后端集成并成功启动后端服务器"></a> 将微服务与 Django 应用程序后端集成，并成功启动后端服务器</h4><ol><li><p>导航至 <code>xrwvm-fullstack_developer_capstone/server</code> 目录。如果 Django 服务器已在运行，则停止该服务器。</p></li><li><p>在 <code>.env</code> 文件中插入汽车库存服务端点的 URL（上一节已复制）。</p><pre><code class="language-plaintext">searchcars_url='your end'</code></pre><blockquote><p>不要添加尾端的 <code>\</code>。</p></blockquote></li><li><p>在 <code>restapis.py</code> 中加入执行以下功能的代码：</p><ol><li><p>从 <code>.env</code> 文件中获取 URL。</p><pre><code class="language-python">searchcars_url = os.getenv(    'searchcars_url',    default="http://localhost:3050/")</code></pre></li><li><p>执行一个名为 <code>searchcars_request</code> 的方法，该方法具有以下功能：</p><ul><li>接受端点和变量关键字参数</li><li>利用提供的端点、查询参数和基本 URL 构建一个完整的请求 URL</li><li>执行 GET 请求并返回响应的 JSON 内容</li><li>处理错误（包括网络异常）并提供成功完成消息</li></ul><p>代码结构将与您之前在 Capstone 主项目中创建的 <code>get_request</code> 方法非常相似：</p><pre><code class="language-python">def searchcars_request(endpoint, **kwargs):    params = ""    if (kwargs):    for key, value in kwargs.items():        params = params+key + "=" + value + "&amp;"        request_url = searchcars_url+endpoint+"?"+params        print("GET from {} ".format(request_url))        try:            # Call get method of requests library with URL and parameters            response = requests.get(request_url)            return response.json()        except:            # If any error occurs            print("Network exception occurred")        finally:            print("GET request call complete!")</code></pre></li></ol></li><li><p>在 <code>djangoapp/views.py</code> 文件中添加名为 <code>get_inventory</code> 的视图，以获取汽车库存。</p><ul><li>该视图应处理 HTTP 请求，提取查询参数和经销商 ID。</li><li>它应使用提供的参数构建一个 API 端点，并调用 <code>restapis.py</code> 中定义的 <code>searchcars_request</code> 函数来检索汽车数据。确保为 <code>searchcars_request</code> 函数加入模块导入。</li><li>它应返回状态为 <code>200</code> 的 JSON 响应，如果提供了经销商 ID，则返回获取的汽车。</li><li>如果没有经销商 ID，则应返回状态为 <code>400</code> 的 JSON 响应和 <code>Bad Request</code> 消息。</li></ul><pre><code class="language-python"># Module importfrom .restapis import get_request, analyze_review_sentiments, post_review, searchcars_request# Code for the viewdef get_inventory(request, dealer_id):    data = request.GET    if (dealer_id):        if 'year' in data:            endpoint = "/carsbyyear/"+str(dealer_id)+"/"+data['year']        elif 'make' in data:            endpoint = "/carsbymake/"+str(dealer_id)+"/"+data['make']        elif 'model' in data:            endpoint = "/carsbymodel/"+str(dealer_id)+"/"+data['model']        elif 'mileage' in data:            endpoint = "/carsbymaxmileage/"+str(dealer_id)+"/"+data['mileage']        elif 'price' in data:            endpoint = "/carsbyprice/"+str(dealer_id)+"/"+data['price']        else:            endpoint = "/cars/"+str(dealer_id)        cars = searchcars_request(endpoint)        return JsonResponse({"status": 200, "cars": cars})    else:        return JsonResponse({"status": 400, "message": "Bad Request"})    return JsonResponse({"status": 400, "message": "Bad Request"})</code></pre></li><li><p>在 <code>djangoapp/urls.py</code> 文件中包含该视图的路由。</p><pre><code class="language-python">path(route='get_inventory/&lt;int:dealer_id&gt;', view=views.get_inventory, name='get_inventory'),</code></pre></li><li><p>导航到 <code>xrwvm-fullstack_developer_capstone/server</code> 目录。<br>确保 Docker Compose 服务器正在运行。如果没有，请使用 <code>docker-compose up</code> 命令启动它。</p></li><li><p>执行模型迁移并启动服务器。</p><pre><code class="language-bash">python3 manage.py makemigrationspython3 manage.py migratepython3 manage.py runserver</code></pre></li><li><p>确保服务器启动成功且无错误。如果出现任何错误日志，请检查并根据需要处理您的代码。</p></li></ol><h2 id="汽车库存服务的前端开发"><a class="markdownIt-Anchor" href="#汽车库存服务的前端开发"></a> 汽车库存服务的前端开发</h2><h4 id="开发并集成与后端汽车库存微服务相对应的前端服务"><a class="markdownIt-Anchor" href="#开发并集成与后端汽车库存微服务相对应的前端服务"></a> 开发并集成与后端汽车库存微服务相对应的前端服务</h4><p>这需要创建一个 React 组件，专门用于搜索和显示汽车信息，并为该组件整合相应的路线。</p><ol><li><p>创建一个用于搜索和显示汽车信息的 React 组件。</p><ol><li>导航至 <code>xrwvm-fullstack_developer_capstone/server/frontend/src/components/Dealers</code> 目录，并添加名为 <code>SearchCars.jsx</code> 的新文件。</li><li>在该文件中加入以下内容：<pre><code class="language-jsx">import React, { useState, useEffect } from 'react';import { useParams } from 'react-router-dom';import Header from '../Header/Header';const SearchCars = () =&gt; {  const [cars, setCars] = useState([]);  const [makes, setMakes] = useState([]);  const [models, setModels] = useState([]);  const [dealer, setDealer] = useState({"full_name":""});  const [message, setMessage] = useState("Loading Cars....");  const { id } = useParams();  let dealer_url = `/djangoapp/get_inventory/${id}`;  let fetch_url = `/djangoapp/dealer/${id}`;  const fetchDealer = async ()=&gt;{    const res = await fetch(fetch_url, {      method: "GET"    });    const retobj = await res.json();    if(retobj.status === 200) {      let dealer = retobj.dealer;      setDealer({"full_name":dealer[0].full_name})    }  }  const populateMakesAndModels = (cars)=&gt;{    let tmpmakes = []    let tmpmodels = []    cars.forEach((car)=&gt;{      tmpmakes.push(car.make)      tmpmodels.push(car.model)    })    setMakes(Array.from(new Set(tmpmakes)));    setModels(Array.from(new Set(tmpmodels)));  }  const fetchCars = async ()=&gt;{    const res = await fetch(dealer_url, {      method: "GET"    });    const retobj = await res.json();    if(retobj.status === 200) {      let cars = Array.from(retobj.cars)      setCars(cars);      populateMakesAndModels(cars);    }  }  const setCarsmatchingCriteria = async(matching_cars)=&gt;{    let cars = Array.from(matching_cars)    console.log("Number of matching cars "+cars.length);    let makeIdx = document.getElementById('make').selectedIndex;    let modelIdx = document.getElementById('model').selectedIndex;    let yearIdx = document.getElementById('year').selectedIndex;    let mileageIdx = document.getElementById('mileage').selectedIndex;    let priceIdx = document.getElementById('price').selectedIndex;    if(makeIdx !== 0) {      let currmake = document.getElementById('make').value;      cars = cars.filter(car =&gt; car.make === currmake);    }    if(modelIdx !== 0) {      let currmodel = document.getElementById('model').value;      cars = cars.filter(car =&gt; car.model === currmodel);      if(cars.length !== 0) {        document.getElementById('make').value = cars[0].make;      }    }    if(yearIdx !== 0) {      let curryear = document.getElementById('year').value;      cars = cars.filter(car =&gt; car.year &gt;= curryear);      if(cars.length !== 0) {        document.getElementById('make').value = cars[0].make;      }    }    if(mileageIdx !== 0) {      let currmileage = parseInt(document.getElementById('mileage').value);      if(currmileage === 50000) {        cars = cars.filter(car =&gt; car.mileage &lt;= currmileage);      } else if (currmileage === 100000){        cars = cars.filter(car =&gt; car.mileage &lt;= currmileage &amp;&amp; car.mileage &gt; 50000);      } else if (currmileage === 150000){        cars = cars.filter(car =&gt; car.mileage &lt;= currmileage &amp;&amp; car.mileage &gt; 100000);      } else if (currmileage === 200000){        cars = cars.filter(car =&gt; car.mileage &lt;= currmileage &amp;&amp; car.mileage &gt; 150000);      } else {        cars = cars.filter(car =&gt; car.mileage &gt; 200000);      }    }    if(priceIdx !== 0) {      let currprice = parseInt(document.getElementById('price').value);      if(currprice === 20000) {        cars = cars.filter(car =&gt; car.price &lt;= currprice);      } else if (currprice === 40000){        cars = cars.filter(car =&gt; car.price &lt;= currprice &amp;&amp; car.price &gt; 20000);      } else if (currprice === 60000){        cars = cars.filter(car =&gt; car.price &lt;= currprice &amp;&amp; car.price &gt; 40000);      } else if (currprice === 80000){        cars = cars.filter(car =&gt; car.price &lt;= currprice &amp;&amp; car.price &gt; 60000);      } else {        cars = cars.filter(car =&gt; car.price &gt; 80000);      }    }    if(cars.length === 0) {      setMessage("No cars found matching criteria");    }    setCars(cars);  }  let SearchCarsByMake = async ()=&gt; {    let make = document.getElementById("make").value;    dealer_url = dealer_url + "?make="+make;    const res = await fetch(dealer_url, {      method: 'GET',      headers: {        'Content-Type': 'application/json',      }})    const retobj = await res.json();    if(retobj.status === 200) {      setCarsmatchingCriteria(retobj.cars);    }  }  let SearchCarsByModel = async ()=&gt; {    let model = document.getElementById("model").value;    dealer_url = dealer_url + "?model="+model;    const res = await fetch(dealer_url, {      method: 'GET',      headers: {        'Content-Type': 'application/json',      }})    const retobj = await res.json();    if(retobj.status === 200) {      setCarsmatchingCriteria(retobj.cars);    }  }  let SearchCarsByYear = async ()=&gt; {    let year = document.getElementById("year").value;    if (year !== "all") {      dealer_url = dealer_url + "?year="+year;    }    const res = await fetch(dealer_url, {      method: 'GET',      headers: {        'Content-Type': 'application/json',      }})    const retobj = await res.json();    if(retobj.status === 200) {      setCarsmatchingCriteria(retobj.cars);    }  }  let SearchCarsByMileage = async ()=&gt; {    let mileage = document.getElementById("mileage").value;    if (mileage !== "all") {      dealer_url = dealer_url + "?mileage="+mileage;    }    const res = await fetch(dealer_url, {      method: 'GET',      headers: {        'Content-Type': 'application/json',      }})    const retobj = await res.json();    if(retobj.status === 200) {      setCarsmatchingCriteria(retobj.cars);    }  }  let SearchCarsByPrice = async ()=&gt; {    let price = document.getElementById("price").value;    if(price !== "all") {      dealer_url = dealer_url + "?price="+price;    }    const res = await fetch(dealer_url, {      method: 'GET',      headers: {        'Content-Type': 'application/json',      }})    const retobj = await res.json();    if(retobj.status === 200) {      setCarsmatchingCriteria(retobj.cars);    }  }  const reset = ()=&gt;{    const selectElements = document.querySelectorAll('select');    selectElements.forEach((select) =&gt; {      select.selectedIndex = 0;    });    fetchCars();  }  useEffect(() =&gt; {    fetchCars();    fetchDealer();  },[]);  return (    &lt;div&gt;      &lt;Header /&gt;      &lt;h1 style={{ marginBottom: '20px'}}&gt;Cars at {dealer.full_name}&lt;/h1&gt;      &lt;div&gt;        &lt;span style={{ marginLeft: '10px', paddingLeft: '10px'}}&gt;Make&lt;/span&gt;        &lt;select style={{ marginLeft: '10px', marginRight: '10px' ,paddingLeft: '10px', borderRadius :'10px'}} name="make" id="make" onChange={SearchCarsByMake}&gt;          {makes.length === 0 ? (            &lt;option value=''&gt;No data found&lt;/option&gt;          ):(            &lt;&gt;              &lt;option disabled defaultValue&gt; -- All -- &lt;/option&gt;              {makes.map((make, index) =&gt; (                &lt;option key={index} value={make}&gt;                  {make}                &lt;/option&gt;              ))}            &lt;/&gt;          )          }        &lt;/select&gt;        &lt;span style={{ marginLeft: '10px', paddingLeft: '10px'}}&gt;Model&lt;/span&gt;        &lt;select style={{ marginLeft: '10px', marginRight: '10px' ,paddingLeft: '10px', borderRadius :'10px'}} name="model" id="model" onChange={SearchCarsByModel}&gt;          {models.length === 0 ? (            &lt;option value=''&gt;No data found&lt;/option&gt;          ) : (            &lt;&gt;              &lt;option disabled defaultValue&gt; -- All -- &lt;/option&gt;              {models.map((model, index) =&gt; (                &lt;option key={index} value={model}&gt;                  {model}                &lt;/option&gt;              ))}            &lt;/&gt;          )}        &lt;/select&gt;        &lt;span style={{ marginLeft: '10px', paddingLeft: '10px'}}&gt;Year&lt;/span&gt;        &lt;select style={{ marginLeft: '10px', marginRight: '10px' ,paddingLeft: '10px', borderRadius :'10px'}} name="year" id="year" onChange={SearchCarsByYear}&gt;          &lt;option selected value='all'&gt; -- All -- &lt;/option&gt;          &lt;option value='2024'&gt;2024 or newer&lt;/option&gt;          &lt;option value='2023'&gt;2023 or newer&lt;/option&gt;          &lt;option value='2022'&gt;2022 or newer&lt;/option&gt;          &lt;option value='2021'&gt;2021 or newer&lt;/option&gt;          &lt;option value='2020'&gt;2020 or newer&lt;/option&gt;        &lt;/select&gt;        &lt;span style={{ marginLeft: '10px', paddingLeft: '10px'}}&gt;Mileage&lt;/span&gt;        &lt;select style={{ marginLeft: '10px', marginRight: '10px' ,paddingLeft: '10px', borderRadius :'10px'}} name="mileage" id="mileage" onChange={SearchCarsByMileage}&gt;          &lt;option selected value='all'&gt; -- All -- &lt;/option&gt;          &lt;option value='50000'&gt;Under 50000&lt;/option&gt;          &lt;option value='100000'&gt;50000 - 100000&lt;/option&gt;          &lt;option value='150000'&gt;100000 - 150000&lt;/option&gt;          &lt;option value='200000'&gt;150000 - 200000&lt;/option&gt;          &lt;option value='200001'&gt;Over 200000&lt;/option&gt;        &lt;/select&gt;        &lt;span style={{ marginLeft: '10px', paddingLeft: '10px'}}&gt;Price&lt;/span&gt;        &lt;select style={{ marginLeft: '10px', marginRight: '10px' ,paddingLeft: '10px', borderRadius :'10px'}} name="price" id="price" onChange={SearchCarsByPrice}&gt;          &lt;option selected value='all'&gt; -- All -- &lt;/option&gt;          &lt;option value='20000'&gt;Under 20000&lt;/option&gt;          &lt;option value='40000'&gt;20000 - 40000&lt;/option&gt;          &lt;option value='60000'&gt;40000 - 60000&lt;/option&gt;          &lt;option value='80000'&gt;60000 - 80000&lt;/option&gt;          &lt;option value='80001'&gt;Over 80000&lt;/option&gt;        &lt;/select&gt;        &lt;button style={{marginLeft: '10px', paddingLeft: '10px'}} onClick={reset}&gt;Reset&lt;/button&gt;      &lt;/div&gt;      &lt;div style={{ marginLeft: '10px', marginRight: '10px' , marginTop: '20px'}} &gt;        {cars.length === 0 ? (          &lt;p style={{ marginLeft: '10px', marginRight: '10px', marginTop: '20px' }}&gt;{message}&lt;/p&gt;        ) : (          &lt;div&gt;            &lt;hr/&gt;            {cars.map((car) =&gt; (              &lt;div&gt;                &lt;div key={car._id}&gt;                  &lt;h3&gt;{car.make} {car.model}&lt;/h3&gt;                  &lt;p&gt;Year: {car.year}&lt;/p&gt;                  &lt;p&gt;Mileage: {car.mileage}&lt;/p&gt;                  &lt;p&gt;Price: {car.price}&lt;/p&gt;                &lt;/div&gt;                &lt;hr/&gt;              &lt;/div&gt;            ))}          &lt;/div&gt;        )}      &lt;/div&gt;    &lt;/div&gt;  );};export default SearchCars;</code></pre></li></ol></li><li><p>为该组件添加路由并构建前端。</p><ol><li>在 <code>frontend/src/App.js</code> 中为该组件添加导入语句和路由，将搜索路径设为 <code>/searchcars/:id</code>。<pre><code class="language-js">import SearchCars from "./components/Dealers/SearchCars";</code></pre><pre><code class="language-jsx">&lt;Route path="/searchcars/:id" element={&lt;SearchCars /&gt;} /&gt;</code></pre></li><li>整合锚链接，将用户从特定经销商的评论页面重定向到 <code>Search Cars</code> 页面。<ul><li>转到 <code>frontend/src/components/Dealers/Dealer.jsx</code>，插入一个锚元素。</li><li>将其标记为 <code>Search Cars</code>，并设置为点击后导航至 <code>Search Cars</code> 页面。</li></ul><pre><code class="language-jsx">&lt;a href={`/searchcars/${id}`}&gt;SearchCars&lt;/a&gt;</code></pre></li><li>构建应用程序的前端，以便部署。<pre><code class="language-bash">npm run build</code></pre></li><li>在 <code>djangoproj/urls.py</code> 中添加路径为 <code>searchcars/&lt;int:dealer_id&gt;</code> 的动态 URL 模式。<pre><code class="language-python">path('searchcars/&lt;int:dealer_id&gt;',TemplateView.as_view(template_name="index.html")),</code></pre></li></ol></li></ol></body></html>]]></content>
    
    
    <summary type="html">本文是 IBM 全栈开发毕业设计项目的实战笔记（上篇），旨在对已有的“Best Cars”汽车经销商应用进行功能增强。内容分为三大模块：首先，对 React 前端进行体验优化，包括将静态下拉菜单改为动态搜索框并美化UI；接着，使用 Node.js、Express 和 MongoDB 从零构建一个全新的、容器化的汽车库存后端微服务；最后，开发新的 React 前端组件，与后端服务集成，实现按品牌、型号、年份等多条件筛选汽车库存的动态功能。这篇笔记全面展示了在一个真实全-stack项目中进行功能迭代、构建新服务并完成前后端集成的完整流程。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="JavaScript" scheme="https://blog.cytrogen.icu/tags/JavaScript/"/>
    
    <category term="IBM" scheme="https://blog.cytrogen.icu/tags/IBM/"/>
    
    <category term="HTML" scheme="https://blog.cytrogen.icu/tags/HTML/"/>
    
    <category term="Node.js" scheme="https://blog.cytrogen.icu/tags/Node-js/"/>
    
    <category term="Express.js" scheme="https://blog.cytrogen.icu/tags/Express-js/"/>
    
    <category term="React.js" scheme="https://blog.cytrogen.icu/tags/React-js/"/>
    
  </entry>
  
  <entry>
    <title>Hexo 本地搜索插件教程</title>
    <link href="https://blog.cytrogen.icu/posts/49c3.html"/>
    <id>https://blog.cytrogen.icu/posts/49c3.html</id>
    <published>2024-07-03T05:00:00.000Z</published>
    <updated>2026-02-09T17:16:54.709Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>随着文章数量的增加，我们的博客网站自然是不能只有归档或者标签页的，更别提有时候我们不记得标题、只记得文章内一个简短的词汇。</p><p>一个简单的本地搜索栏可以帮到我们。</p><span id="more"></span><div class="danger"><ul><li><p>本文章使用到了 <code>Hexo-Generator-Search</code> 库。</p><p><a href="https://github.com/wzpan/hexo-generator-search"><img src="https://gh-card.dev/repos/wzpan/hexo-generator-search.svg" alt="wzpan/hexo-generator-search - GitHub" loading="lazy"></a></p></li><li><p>本文章使用的是 Pug 模板语言。</p></li></ul></div><h1 id="安装依赖"><a class="markdownIt-Anchor" href="#安装依赖"></a> 安装依赖</h1><pre><code class="language-bash">npm install --save hexo-generator-search</code></pre><p><code>Hexo-Generator-Search</code> 会生成搜索索引文件，其中包含文章的所有必要数据，可用于为博客编写本地搜索引擎。它支持 XML 和 JSON 格式输出，我们这里会使用 XML。</p><blockquote><p>两者的输出区别可见官方仓库的示例。</p></blockquote><p>在博客根目录中的 <code>_config.yml</code> 文件内添加以下配置项：</p><pre><code class="language-yaml">search:  path: search.xml  field: post  content: true  template: ./search.xml</code></pre><ul><li><code>path</code>：文件路径。默认为 <code>search.xml</code>。如果文件扩展名为 <code>.json</code>，则输出格式为 JSON。否则将输出 XML 格式文件。<ul><li>值得注意的是，这里的路径指的是 <code>public</code> 路径。</li></ul></li><li><code>field</code>：您要搜索的搜索范围，您可以选择：<ul><li><code>post</code>（默认）：仅涵盖博客的所有文章。</li><li><code>page</code>：只涵盖博客的所有页面。</li><li><code>all</code>：将涵盖博客的所有文章和页面。<ul><li><strong>页面</strong> 指的是 Hexo 中 <code>archive</code>、<code>tags</code> 等页面。</li></ul></li></ul></li><li><code>content</code>：是否包含每篇文章的全部内容。如果为 <code>false</code>，则生成的结果只包括标题和其他元信息，而不包括正文。默认为 <code>true</code>。</li><li><code>template</code>（可选）：自定义 XML 模板的路径。</li></ul><p>在博客根目录中添加 <code>search.xml</code>，用作生成搜索索引的模板：</p><pre><code class="language-xml">&lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;search&gt;   {% if posts %}  {% for post in posts.toArray() %}    {% if post.indexing == undefined or post.indexing %}    &lt;entry&gt;      &lt;title&gt;{{ post.title }}&lt;/title&gt;      &lt;link href="{{ (url + post.path) | uriencode }}"/&gt;      &lt;url&gt;{{ (url + post.path) | uriencode }}&lt;/url&gt;      {% if content %}        &lt;content type="html"&gt;&lt;![CDATA[{{ post.content | noControlChars | safe }}]]&gt;&lt;/content&gt;      {% endif %}      {% if post.categories and post.categories.length&gt;0 %}      &lt;categories&gt;          {% for cate in post.categories.toArray() %}          &lt;category&gt; {{ cate.name }} &lt;/category&gt;          {% endfor %}      &lt;/categories&gt;      {% endif %}      {% if post.tags and post.tags.length&gt;0 %}        &lt;tags&gt;            {% for tag in post.tags.toArray() %}            &lt;tag&gt; {{ tag.name }} &lt;/tag&gt;            {% endfor %}        &lt;/tags&gt;      {% endif %}    &lt;/entry&gt;    {% endif %}    {% endfor %}  {% endif %}  {% if pages %}    {% for page in pages.toArray() %}    {% if post.indexing == undefined or post.indexing %}    &lt;entry&gt;      &lt;title&gt;{{ page.title }}&lt;/title&gt;      &lt;link href="{{ (url + page.path) | uriencode }}"/&gt;      &lt;url&gt;{{ (url + page.path) | uriencode }}&lt;/url&gt;      {% if content %}        &lt;content type="html"&gt;&lt;![CDATA[{{ page.content | noControlChars | safe }}]]&gt;&lt;/content&gt;      {% endif %}    &lt;/entry&gt;    {% endif %}    {% endfor %}  {% endif %}&lt;/search&gt;</code></pre><p>官方仓库中提到，当运行以下命令后就可以在 <code>public</code> 路径中看到生成的结果：</p><pre><code class="language-bash">hexo g</code></pre><h1 id="显示结果"><a class="markdownIt-Anchor" href="#显示结果"></a> 显示结果</h1><p>首先需要清楚一件事：<code>Hexo-Generator-Search</code> <strong>仅</strong> 生成搜索索引文件！你要如何使用这个文件就是你自己的事情，包括写不写搜索栏、怎么写搜索结果等。此处仅讲解我自己的方案，极大参考了 <code>Hexo-Theme-Freemind</code> 的写法。</p><p><a href="https://github.com/wzpan/hexo-theme-freemind"><img src="https://gh-card.dev/repos/wzpan/hexo-theme-freemind.svg" alt="wzpan/hexo-theme-freemind - GitHub" loading="lazy"></a></p><blockquote><p>部分主题自带了本地搜索功能，建议先看一下你使用的主题是否有内置。</p></blockquote><p><code>Hexo-Theme-Freemind</code> 使用了 AJAX 和 jQuery。从网上找到最新的 jQuery CDN（要 <code>minified</code> 的），并将 <code>script</code> 标签写在 <code>head.pug</code> 中：</p><pre><code class="language-plaintext">script(src='https://code.jquery.com/jquery-3.7.1.min.js', integrity='sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=', crossorigin='anonymous')</code></pre><p>这样，我们就可以使用 jQuery 了。</p><blockquote><p>jQuery 是一个轻量级的 JavaScript 库，使得开发者在网站上使用 JavaScript 更容易更方便。</p><p>例如，我们想要在页面加载时添加一个动画效果，就可以写：</p><pre><code class="language-plaintext">script.    $(document).ready(function() {        $("body").fadeIn(2000);    });</code></pre><blockquote><p><code>$</code> 符号在 jQuery 中代表一个函数，也是 jQuery 对象的别名，可以靠它来选择和操作 HTML 元素。</p></blockquote></blockquote><blockquote><p>AJAX 是一种在客户端创建异步 Web 应用程序的 Web 开发技术。它允许 Web 应用程序在不干扰现有页面显示和行为的情况下，异步地从服务器发送和检索数据。这意味着可以更新网页的部分内容，而无需重新加载整个页面。</p></blockquote><h2 id="编写搜索视图"><a class="markdownIt-Anchor" href="#编写搜索视图"></a> 编写搜索视图</h2><p>搜索视图是用于显示搜索表单和搜索结果的地方。最直观的说法就是用户看到的搜索栏。</p><blockquote><p><code>Hexo-Theme-Freemind</code> 使用的是 EJS 模板语言，感兴趣的可以 <a href="https://github.com/wzpan/hexo-theme-freemind/blob/master/layout/_widget/search.ejs#L8">看一眼</a>。</p></blockquote><p>由于我使用的是单列主题 <code>Hexo-Theme-Hermes</code>，整个页面就没有什么侧边栏等地方存放搜索栏。</p><p><a href="https://github.com/claymcleod/hexo-theme-hermes"><img src="https://gh-card.dev/repos/claymcleod/hexo-theme-hermes.svg" alt="claymcleod/hexo-theme-hermes - GitHub" loading="lazy"></a></p><p>而多列主题（例如 <code>Hexo-Theme-Freemind</code>）就可以在侧边栏内直接塞入搜索栏。</p><p><img src="/posts/49c3/1.webp" alt="img.png" loading="lazy"></p><p>为了不破坏单列主题的核心概念，我决定在导航栏内添加一个搜索图标。当用户点击图标后，一个搜索窗口会弹出来，内含搜索栏以及显示搜索结果的子容器。用户再次点击搜索图标或者点击搜索窗口外的区域都会导致搜索窗口消失。</p><p>搜索图标我使用的是 FontAwesome 的 <code>fas fa-search</code>。从 FontAwesome 那边注册、拿到属于自己的 kit 后，在 <code>head.pug</code> 中添加：</p><pre><code class="language-plaintext">script(src="https://kit.fontawesome.com/########.js", crossorigin="anonymous")</code></pre><p><code>Hexo-Theme-Hermes</code> 的导航栏写法如下：</p><pre><code class="language-plaintext">ul.nav.nav-list    each value, key in theme.menu        li.nav-list-item            - var re = /^(http|https):\/\/*/gi;            - var tar = re.test(value) ? "_blank" : "_self"            - var act = !re.test(value) &amp;&amp; "/"+page.current_url === value            a.nav-list-link(class={active: act} href=url_for(value) target=tar)                != key.toUpperCase()</code></pre><p>它是根据 <code>theme</code> 路径的配置项依次添加 <code>li</code> 标签，我们的搜索图标可以直接添加到 <code>ul</code> 标签的内部（和 <code>each value, key in theme.menu</code> 同级）：</p><pre><code class="language-plaintext">if config.search    li.nav-list-item#search-icon        i.fas.fa-search</code></pre><p>CSS 样式：</p><pre><code class="language-css">#search-icon {    cursor: pointer;}</code></pre><blockquote><p><code>cursor</code> 属性设置鼠标指针在元素上方时显示的光标类型。<code>pointer</code> 表示光标将显示为一个指向链接的手指图标，通常在链接或可点击元素上使用，以向用户表明该元素可以被点击。这有助于提高用户界面的可用性。</p></blockquote><p><img src="/posts/49c3/2.webp" alt="img.png" loading="lazy"></p><p>接着我们来快速写一个显示搜索栏和搜索结果的容器。我要求不多，就是一个方方正正的小窗口在页面正中间。</p><pre><code class="language-plaintext">div#search-popup.hidden    div#search-panel        input(type="text", id="local-search-input", name="q", results="0", placeholder=__('搜索...'))        div#local-search-results</code></pre><p>CSS 样式：</p><pre><code class="language-css">.hidden {    display: none;}#search-popup {    position: fixed;    top: 50%;    left: 50%;    transform: translate(-50%, -50%);    width: 75%;    height: 50%;    padding: 20px;    border: 3px solid #ccc;    background-color: #fff;    text-align: center;    z-index: 10;}#search-popup input[type="text"] {    display: block;}</code></pre><p>该窗口必须初始状态为隐藏，显现后则是一个固定在屏幕中心的弹出窗口，文本内容居中对齐。如果需要输入文本，输入框就会块级显示。</p><p>因为我希望该弹窗在 Z 轴上的位置优先于其他，我就写了个 <code>z-index: 10</code>（实际测试时发现 <code>position: absolute</code> 的类会优先于 <code>#search-popup</code>，才决定加上的）。</p><pre><code class="language-css">#search-panel {    display: flex;    flex-direction: column;    padding: 0;    margin: 0;    height: 100%;    width: 100%;}</code></pre><p><code>#search-panel</code> 的主要目的是将搜索栏和搜索结果以更简单的方式分开。Flexbox 布局好用、爱用、不用不会写。</p><pre><code class="language-css">#local-search-input {    width: 100%;    margin-bottom: 1rem;}#local-search-results {    overflow-y: auto;    flex-grow: 1;}</code></pre><p>一些之后会用到的 CSS 样式：</p><pre><code class="language-css">em.search-keyword {    border-bottom: 1px dashed #4088b8;    font-weight: bold;}ul.search-result-list {    padding-left: 10px;}a.search-result-title {    font-weight: bold;}p.search-result {    color: #555;}</code></pre><p>最终结果：</p><p><img src="/posts/49c3/3.webp" alt="img.png" loading="lazy"></p><blockquote><p>写的很随便也不好看，未来再美化吧。能用就行。</p></blockquote><h4 id="添加弹出窗口的显示逻辑"><a class="markdownIt-Anchor" href="#添加弹出窗口的显示逻辑"></a> 添加弹出窗口的显示逻辑</h4><p>只是单单写一个图标和窗口还不够，我们还没有添加窗口的显示逻辑。先前说了，我希望的是点击图标之后，窗口会显示；再次点击图标，窗口会隐藏。</p><p>在 Pug 文件中添加 <code>script</code> 标签：</p><pre><code class="language-plaintext">script.    document.getElementById('search-icon').addEventListener('click', function(event) {        const popup = document.getElementById('search-popup');        if (popup.classList.contains('hidden')) {            popup.classList.remove('hidden');        } else {            popup.classList.add('hidden');        }        event.stopPropagation();    });    document.getElementById('search-popup').addEventListener('click', function(event) {        event.stopPropagation();    });    document.addEventListener('click', function() {        const popup = document.getElementById('search-popup');        if (!popup.classList.contains('hidden')) {            popup.classList.add('hidden');        }    });</code></pre><ol><li>当用户点击 ID 为 <code>search-icon</code> 的元素时，会触发事件监听器。监听器会首先获取 ID 为 <code>search-popup</code> 的元素，然后检查该元素是否包含 <code>hidden</code> 类。如果是，就移除这个类；反之添加这个类。最后调用 <code>event.stopPropagation()</code> 来阻止事件冒泡、传播到父元素。</li><li>当用户点击 ID 为 <code>search-popup</code> 的元素时，也会触发一个事件监听器。这个监听器只会做一件事，那就是调用 <code>event.stopPropagation()</code> 来阻止事件冒泡。这样做的目的是防止当用户在弹出窗口上点击时，触发下面的文档点击事件监听器。</li><li>当用户点击文档的任何地方时，会触发一个事件监听器。它首先会获取 ID 为 <code>search-popup</code> 的元素，然后检查是否包含 <code>hidden</code> 类。如果不是，就添加这个类。这样的话，每当用户点击弹出窗口以外的任何地方时，弹出窗口就会隐藏。</li></ol><h2 id="编写搜索脚本"><a class="markdownIt-Anchor" href="#编写搜索脚本"></a> 编写搜索脚本</h2><p>搜索脚本会告诉浏览器如何抓取搜索数据，并过滤出我们要搜索的内容。</p><blockquote><p>这里我近乎是照搬了 <code>Hexo-Theme-Freemind</code> 的 <a href="https://github.com/wzpan/hexo-theme-freemind/blob/master/source/js/search.js">写法</a>，只修改了一丢丢细节。</p><p>未来可能会尝试改进这段代码。先挖坑了。</p></blockquote><pre><code class="language-js">const searchFunc = function (path, search_id, content_id) {    'use strict';    $.ajax({        url: path,        dataType: "xml",        success: function (xmlResponse) {            const datas = $("entry", xmlResponse).map(function () {                return {                    title: $("title", this).text(),                    content: $("content", this).text(),                    url: $("url", this).text()                };            }).get();            const $input = document.getElementById(search_id);            if (!$input) return;            const $resultContent = document.getElementById(content_id);            if ($("#local-search-input").length &gt; 0) {                $input.addEventListener('input', function () {                    let str = '&lt;ul class=\"search-result-list\"&gt;';                    const keywords = this.value.trim().toLowerCase().split(/[\s\-]+/);                    $resultContent.innerHTML = "";                    if (this.value.trim().length &lt;= 0) {                        return;                    }                    datas.forEach(function (data) {                        let isMatch = true;                        const content_index = [];                        if (!data.title || data.title.trim() === '') {                            data.title = "Untitled";                        }                        const data_title = data.title.trim();                        const data_content = data.content.trim().replace(/&lt;[^&gt;]+&gt;/g, "");                        const data_url = data.url;                        let index_title = -1;                        let index_content = -1;                        let first_occur = -1;                        if (data_content !== '') {                            keywords.forEach(function (keyword, i) {                                index_title = data_title.toLowerCase().indexOf(keyword.toLowerCase());                                index_content = data_content.toLowerCase().indexOf(keyword.toLowerCase());                                if (index_title &lt; 0 &amp;&amp; index_content &lt; 0) {                                    isMatch = false;                                } else {                                    if (index_content &lt; 0) {                                        index_content = 0;                                    }                                    if (i === 0) {                                        first_occur = index_content;                                    }                                }                            });                        } else {                            isMatch = false;                        }                        if (isMatch) {                            str += "&lt;li&gt;&lt;a href='" + data_url + "' class='search-result-title'&gt;" + data_title + "&lt;/a&gt;";                            const content = data.content.trim().replace(/&lt;[^&gt;]+&gt;/g, "");                            if (first_occur &gt;= 0) {                                let start = first_occur - 20;                                let end = first_occur + 80;                                if (start &lt; 0) {                                    start = 0;                                }                                if (start === 0) {                                    end = 100;                                }                                if (end &gt; content.length) {                                    end = content.length;                                }                                let match_content = content.substring(start, end);                                                                keywords.forEach(function (keyword) {                                    const regS = new RegExp(keyword, "gi");                                    match_content = match_content.replace(regS, function(match) {                                        return "&lt;em class=\"search-keyword\"&gt;" + match + "&lt;/em&gt;";                                    });                                });                                str += "&lt;p class=\"search-result\"&gt;" + match_content + "...&lt;/p&gt;"                            }                            str += "&lt;/li&gt;";                        }                    });                    str += "&lt;/ul&gt;";                    $resultContent.innerHTML = str;                });            }        }    });};</code></pre><ol><li>函数定义和 AJAX 请求：<pre><code class="language-js">const searchFunc = function (path, search_id, content_id) {  'use strict';  $.ajax({    url: path,    dataType: "xml",    success: function (xmlResponse) {      // ... 后续代码    }  });};</code></pre>这段代码定义了一个名为 <code>searchFunc</code> 的函数，它接受三个参数：<ul><li><code>path</code>：XML 文件的路径</li><li><code>search_id</code>：搜索栏的 ID</li><li><code>content_id</code>：搜索结果显示区域的 ID<br>函数使用 jQuery 的 AJAX 方法从指定的 <code>path</code> 获取 XML 数据。</li></ul></li><li>数据处理：<pre><code class="language-js">const datas = $("entry", xmlResponse).map(function () {  return {    title: $("title", this).text(),    content: $("content", this).text(),    url: $("url", this).text()  };}).get();</code></pre>处理从 XML 响应中获取的数据，将每个 <code>entry</code> 元素转换为包含 <code>title</code>、<code>content</code> 和 <code>url</code> 的对象数组。<br>这里使用了 jQuery 的 <code>map</code> 方法来遍历 XML 元素，并使用 <code>get()</code> 来将结果转换为普通数组。</li><li>搜索输入监听：<pre><code class="language-js">const $input = document.getElementById(search_id);if (!$input) return;const $resultContent = document.getElementById(content_id);if ($("#local-search-input").length &gt; 0) {  $input.addEventListener('input', function () {    // ... 搜索逻辑  });}</code></pre>设置对搜索输入框的监听。当用户在搜索栏中输入内容时就会触发搜索。<br>这段代码混合使用了原生 JavaScript（<code>document.getElementById</code> 和 <code>addEventListener</code>）和 jQuery（<code>$("local-search-input").length</code>）。</li><li>搜索逻辑：<pre><code class="language-js">let str = '&lt;ul class=\"search-result-list\"&gt;';const keywords = this.value.trim().toLowerCase().split(/[\s\-]+/);$resultContent.innerHTML = "";if (this.value.trim().length &lt;= 0) {  return;}datas.forEach(function (data) {  // ... 匹配逻辑});str += "&lt;/ul&gt;";$resultContent.innerHTML = str;</code></pre>这是搜索功能的核心逻辑。将输入的搜索词与数据进行匹配，并构建搜索结果 HTML。</li><li>匹配和高亮显示：<pre><code class="language-js">if (isMatch) {  str += "&lt;li&gt;&lt;a href='" + data_url + "' class='search-result-title'&gt;" + data_title + "&lt;/a&gt;";  const content = data.content.trim().replace(/&lt;[^&gt;]+&gt;/g, "");  if (first_occur &gt;= 0) {    // ... 截取匹配内容    keywords.forEach(function (keyword) {      const regS = new RegExp(keyword, "gi");      match_content = match_content.replace(regS, function(match) {        return "&lt;em class=\"search-keyword\"&gt;" + match + "&lt;/em&gt;";      });    });    str += "&lt;p class=\"search-result\"&gt;" + match_content + "...&lt;/p&gt;"  }  str += "&lt;/li&gt;";}</code></pre>处理匹配结果的显示和关键词高亮。此处使用了正则表达式去除 HTML 标签，使用 <code>substring</code> 截取匹配上下文，然后使用 <code>replace</code> 和正则表达式实现关键词高亮。</li></ol><p>将 <code>search.js</code> 放在 <code>theme/hermes/source/js</code> 路径下，运行 <code>hexo g</code> 之后便会出现在 <code>public/js</code> 路径下。</p><h2 id="连接视图和脚本"><a class="markdownIt-Anchor" href="#连接视图和脚本"></a> 连接视图和脚本</h2><p>有了搜索视图和搜索脚本后，我们就可以把两者连接在一起。</p><p>在 Pug 文件中添加 <code>script</code> 标签：</p><pre><code class="language-plaintext">if config.search    script(src="/js/search.js")    script.        let search_path = "#{config.search.path}";        if (search_path.length === 0) {            search_path = "search.xml";        }        const path = "#{config.root}" + search_path;        searchFunc(path, 'local-search-input', 'local-search-results');</code></pre><p>首先是引入搜索脚本 <code>search.js</code>。前面说过，该脚本在 <code>public</code> 路径下时会是在 <code>js</code> 路径下。接着调用 <code>search.js</code> 中我们定义好的 <code>searchFunc</code> 函数。</p><p>最终效果：</p><p><img src="/posts/49c3/4.webp" alt="img.png" loading="lazy"></p></body></html>]]></content>
    
    
    <summary type="html">本文是一篇详细的 Hexo 本地搜索功能实现教程。文章指导你如何使用 hexo-generator-search 插件生成站点内容的索引文件，并结合 jQuery 和自定义 JavaScript 脚本，一步步构建出一个功能完善、无需后端的本地搜索引擎。内容涵盖插件配置、搜索弹窗的 Pug 视图与 CSS 样式编写、交互逻辑实现，以及核心的 Ajax 搜索与关键词高亮脚本。跟随本教程，可以轻松为你的博客添加一个实用的搜索功能，提升用户体验。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Hexo" scheme="https://blog.cytrogen.icu/tags/Hexo/"/>
    
    <category term="JavaScript" scheme="https://blog.cytrogen.icu/tags/JavaScript/"/>
    
  </entry>
  
  <entry>
    <title>ByteByteGo 简报翻译【1】：Netflix 如何管理 2.38 亿会员？</title>
    <link href="https://blog.cytrogen.icu/posts/75ba.html"/>
    <id>https://blog.cytrogen.icu/posts/75ba.html</id>
    <published>2024-06-29T02:48:00.000Z</published>
    <updated>2026-02-09T17:16:54.681Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>开了个新坑，近期从 Instagram 的广告上得知了 ByteByteGo，并且订阅了他们的简报（Newsletter）服务，基本上隔个两三天就会收到他们的简报邮件。其中有些简报让我非常感兴趣，故分享。</p><p><strong>2024 年 06 月 25 日</strong>：Netflix 如何管理 2.38 亿会员？<em>（How Netflix Manages 238 Million Memberships?）</em></p><span id="more"></span><div class="danger"><p>如果侵权，请联系我删除！</p></div><h1 id="简报内容"><a class="markdownIt-Anchor" href="#简报内容"></a> 简报内容</h1><p><em>免责声明：本文章中的细节来自 Netflix 工程团队的文章 / 演讲。所有架构细节均归功于 Netflix 工程团队。原文链接见文末参考文献部分。我们尝试分析了这些细节，并提供了我们的意见。如果您发现任何不准确或遗漏之处，请留下评论，我们将尽力修正。</em></p><p>作为一家基于订阅的流媒体服务公司，Netflix 的主要收入来源是会员业务。目前，Netflix 在全球拥有 2.38 亿名会员，有效管理会员对公司的成功和持续增长至关重要。</p><p>Netflix 的会员平台在处理用户订阅的整个生命周期中发挥着至关重要的作用。</p><p>会员生命周期由不同阶段和场景组成：</p><ul><li>注册： 用户可直接或通过 T-Mobile 等合作伙伴渠道注册 Netflix 服务，开始 Netflix 之旅。</li><li>计划变更： 现有会员可根据自己的喜好和需求修改订阅计划。</li><li>续订： 作为一项订阅服务，Netflix 会自动尝试使用与用户账户相关联的付款方式为用户续订计划。</li><li>付款问题： 如果支付网关出现问题或资金不足，用户的账户可能会被暂停或给予宽限期来解决问题。</li><li>会员资格暂停或取消： 用户可以选择暂时中止会员资格或永久取消订阅。</li></ul><p>在下面的章节中，我们将探讨 Netflix 工程团队为支持其会员平台的各种功能和可扩展性而做出的架构决策。</p><h2 id="netflix-会员平台的高级架构"><a class="markdownIt-Anchor" href="#netflix-会员平台的高级架构"></a> Netflix 会员平台的高级架构</h2><p>在深入了解 Netflix 会员制平台的细节之前，让我们先回顾一下该公司最初的定价架构是如何设计的。</p><p>早期，Netflix 的定价模型相对简单，只需管理少量计划和支持基本功能。</p><p>为了满足这些最初的要求，Netflix 采用了轻量级的内存库。事实证明，这种方法相当高效，因为定价系统的范围有限，因此设计简单、精简。</p><p>下图展示了这一基本架构：</p><pre class="mermaid-error">Mermaid render failed: Mermaid render timed out after 30s</pre><p>随着 Netflix 全球业务的扩展和产品的多样化，最初为定价架构提供服务的轻量级内存库变得不敷使用。</p><p>定价目录的复杂性和范围不断扩大，其在多个应用程序中的重要性也与日俱增，这给运营带来了挑战。该库的规模和依赖性使其难以维护和扩展，因此有必要过渡到更强大和可扩展的架构。</p><p>下图显示了 Netflix 现代会员制平台的高层架构：</p><svg aria-roledescription="flowchart-v2" role="graphics-document document" viewBox="-8 -49 743.4765625 652.8255615234375" style="max-width: 743.4765625px;" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="100%" id="mermaid-1789678110094"><style>#mermaid-1789678110094{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-1789678110094 .error-icon{fill:#552222;}#mermaid-1789678110094 .error-text{fill:#552222;stroke:#552222;}#mermaid-1789678110094 .edge-thickness-normal{stroke-width:2px;}#mermaid-1789678110094 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-1789678110094 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-1789678110094 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-1789678110094 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-1789678110094 .marker{fill:#333333;stroke:#333333;}#mermaid-1789678110094 .marker.cross{stroke:#333333;}#mermaid-1789678110094 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-1789678110094 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-1789678110094 .cluster-label text{fill:#333;}#mermaid-1789678110094 .cluster-label span,#mermaid-1789678110094 p{color:#333;}#mermaid-1789678110094 .label text,#mermaid-1789678110094 span,#mermaid-1789678110094 p{fill:#333;color:#333;}#mermaid-1789678110094 .node rect,#mermaid-1789678110094 .node circle,#mermaid-1789678110094 .node ellipse,#mermaid-1789678110094 .node polygon,#mermaid-1789678110094 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-1789678110094 .flowchart-label text{text-anchor:middle;}#mermaid-1789678110094 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-1789678110094 .node .label{text-align:center;}#mermaid-1789678110094 .node.clickable{cursor:pointer;}#mermaid-1789678110094 .arrowheadPath{fill:#333333;}#mermaid-1789678110094 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-1789678110094 .flowchart-link{stroke:#333333;fill:none;}#mermaid-1789678110094 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-1789678110094 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-1789678110094 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-1789678110094 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-1789678110094 .cluster text{fill:#333;}#mermaid-1789678110094 .cluster span,#mermaid-1789678110094 p{color:#333;}#mermaid-1789678110094 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-1789678110094 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-1789678110094 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker orient="auto" markerHeight="12" markerWidth="12" markerUnits="userSpaceOnUse" refY="5" refX="6" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678110094_flowchart-pointEnd"><path style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 0 0 L 10 5 L 0 10 z"></path></marker><marker orient="auto" markerHeight="12" markerWidth="12" markerUnits="userSpaceOnUse" refY="5" refX="4.5" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678110094_flowchart-pointStart"><path style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 0 5 L 10 10 L 10 0 z"></path></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5" refX="11" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678110094_flowchart-circleEnd"><circle style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" r="5" cy="5" cx="5"></circle></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5" refX="-1" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678110094_flowchart-circleStart"><circle style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" r="5" cy="5" cx="5"></circle></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5.2" refX="12" viewBox="0 0 11 11" class="marker cross flowchart" id="mermaid-1789678110094_flowchart-crossEnd"><path style="stroke-width: 2; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 1,1 l 9,9 M 10,1 l -9,9"></path></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5.2" refX="-1" viewBox="0 0 11 11" class="marker cross flowchart" id="mermaid-1789678110094_flowchart-crossStart"><path style="stroke-width: 2; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 1,1 l 9,9 M 10,1 l -9,9"></path></marker><g class="root"><g class="clusters"></g><g class="edgePaths"><path marker-end="url(#mermaid-1789678110094_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-A LE-B" id="L-A-B-0" d="M27.953,33L27.953,37.167C27.953,41.333,27.953,49.667,32.574,57.455C37.196,65.244,46.438,72.487,51.06,76.109L55.681,79.731"></path><path marker-end="url(#mermaid-1789678110094_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-B LE-C" id="L-B-C-0" d="M80.906,116L80.906,120.167C80.906,124.333,80.906,132.667,82.143,147.267C83.38,161.866,85.853,182.733,87.09,193.166L88.327,203.599"></path><path marker-end="url(#mermaid-1789678110094_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-C LE-D" id="L-C-D-0" d="M90.906,241.863L90.906,253.173C90.906,264.484,90.906,287.104,90.906,303.894C90.906,320.684,90.906,331.642,90.906,337.121L90.906,342.6"></path><path style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-D LE-E" id="L-D-E-0" d="M90.906,440.275L90.906,446.638C90.906,453,90.906,465.726,113.044,481.061C135.182,496.396,179.458,514.342,201.596,523.315L223.734,532.288"></path><path marker-end="url(#mermaid-1789678110094_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-F LE-E" id="L-F-E-0" d="M256.539,410.588L256.539,421.898C256.539,433.209,256.539,455.83,257.012,470.507C257.485,485.184,258.431,491.918,258.904,495.284L259.377,498.651"></path><path marker-end="url(#mermaid-1789678110094_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-G LE-E" id="L-G-E-0" d="M388.843,410.588L380.499,421.898C372.154,433.209,355.466,455.83,341.194,472.981C326.922,490.133,315.067,501.816,309.14,507.657L303.212,513.499"></path><path marker-end="url(#mermaid-1789678110094_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-G LE-H" id="L-G-H-0" d="M402.971,410.588L404.312,421.898C405.653,433.209,408.334,455.83,409.675,475.371C411.016,494.913,411.016,511.376,411.016,519.607L411.016,527.838"></path><path marker-end="url(#mermaid-1789678110094_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-I LE-B" id="L-I-B-0" d="M133.859,33L133.859,37.167C133.859,41.333,133.859,49.667,129.238,57.455C124.617,65.244,115.374,72.487,110.753,76.109L106.131,79.731"></path><path marker-end="url(#mermaid-1789678110094_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-J LE-B" id="L-J-B-0" d="M242.688,33L242.688,37.167C242.688,41.333,242.688,49.667,221.725,59.211C200.763,68.754,158.839,79.509,137.877,84.886L116.915,90.263"></path><path marker-end="url(#mermaid-1789678110094_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-K LE-C" id="L-K-C-0" d="M447.836,103.263L405.999,109.553C364.161,115.842,280.487,128.421,224.888,145.673C169.288,162.925,141.764,184.851,128.001,195.813L114.239,206.776"></path><path marker-end="url(#mermaid-1789678110094_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-K LE-L" id="L-K-L-0" d="M496.735,116L502.762,120.167C508.79,124.333,520.844,132.667,526.871,147.26C532.898,161.854,532.898,182.708,532.898,193.136L532.898,203.563"></path><path marker-end="url(#mermaid-1789678110094_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-L LE-M" id="L-L-M-0" d="M532.898,241.863L532.898,253.173C532.898,264.484,532.898,287.104,532.898,301.698C532.898,316.292,532.898,322.859,532.898,326.142L532.898,329.425"></path><path marker-end="url(#mermaid-1789678110094_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-N LE-C" id="L-N-C-0" d="M645.594,102.396L589.979,108.83C534.363,115.264,423.133,128.132,334.708,147.091C246.283,166.049,180.664,191.099,147.855,203.623L115.045,216.148"></path><path marker-end="url(#mermaid-1789678110094_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-N LE-O" id="L-N-O-0" d="M670.625,116L670.625,120.167C670.625,124.333,670.625,132.667,670.625,140.117C670.625,147.567,670.625,154.133,670.625,157.417L670.625,160.7"></path></g><g class="edgeLabels"><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g transform="translate(27.953125, 16.5)" data-id="A" data-node="true" id="flowchart-A-0" class="node default default flowchart-label"><rect height="33" width="55.90625" y="-16.5" x="-27.953125" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-20.453125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="40.90625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">会员宽限期服务</span></div></foreignObject></g></g><g transform="translate(80.90625, 99.5)" data-id="B" data-node="true" id="flowchart-B-1" class="node default default flowchart-label"><rect height="33" width="61.75" y="-16.5" x="-30.875" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-23.375, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="46.75"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">会员状态管理服务</span></div></foreignObject></g></g><g transform="translate(90.90625, 225.36264038085938)" data-id="C" data-node="true" id="flowchart-C-3" class="node default default flowchart-label"><rect height="33" width="38.375" y="-16.5" x="-19.1875" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-11.6875, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="23.375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">订阅服务</span></div></foreignObject></g></g><g transform="translate(90.90625, 394.0879211425781)" data-id="D" data-node="true" id="flowchart-D-5" class="node default default flowchart-label"><circle height="83" width="92.375" r="46.1875" ry="0" rx="0" style=""></circle><g transform="translate(-38.6875, -34)" style="" class="label"><rect></rect><foreignObject style="width: 77.375px; height: 68px;" height="68" width="77.375"><div style="display: table-cell; white-space: nowrap; max-width: 200px;" xmlns="http://www.w3.org/1999/xhtml">    <span class="nodeLabel markdown-node-label"><p> Cassandra<br>订阅数据库</p></span></div></foreignObject></g></g><g transform="translate(266.5390625, 549.6380615234375)" data-id="E" data-node="true" id="flowchart-E-7" class="node default default flowchart-label"><circle height="83" width="92.375" r="46.1875" ry="0" rx="0" style=""></circle><g transform="translate(-38.6875, -34)" style="" class="label"><rect></rect><foreignObject style="width: 77.375px; height: 68px;" height="68" width="77.375"><div style="display: table-cell; white-space: nowrap; max-width: 200px;" xmlns="http://www.w3.org/1999/xhtml">    <span class="nodeLabel markdown-node-label"><p> Cassandra<br>订阅历史数据库</p></span></div></foreignObject></g></g><g transform="translate(256.5390625, 394.0879211425781)" data-id="F" data-node="true" id="flowchart-F-8" class="node default default flowchart-label"><rect height="33" width="138.890625" y="-16.5" x="-69.4453125" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-61.9453125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="123.890625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"> Apache Spark 对账工作</span></div></foreignObject></g></g><g transform="translate(401.015625, 394.0879211425781)" data-id="G" data-node="true" id="flowchart-G-10" class="node default default flowchart-label"><rect height="33" width="50.0625" y="-16.5" x="-25.03125" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-17.53125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">订阅历史服务</span></div></foreignObject></g></g><g transform="translate(411.015625, 549.6380615234375)" data-id="H" data-node="true" id="flowchart-H-13" class="node default default flowchart-label"><rect height="33" width="53.25" y="-16.5" x="-26.625" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-19.125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="38.25"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"> kafka</span></div></foreignObject></g></g><g transform="translate(133.859375, 16.5)" data-id="I" data-node="true" id="flowchart-I-14" class="node default default flowchart-label"><rect height="33" width="55.90625" y="-16.5" x="-27.953125" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-20.453125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="40.90625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"> 会员捆绑包服务</span></div></foreignObject></g></g><g transform="translate(242.6875, 16.5)" data-id="J" data-node="true" id="flowchart-J-16" class="node default default flowchart-label"><rect height="33" width="61.75" y="-16.5" x="-30.875" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-23.375, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="46.75"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">会员应用商店服务</span></div></foreignObject></g></g><g transform="translate(472.8671875, 99.5)" data-id="K" data-node="true" id="flowchart-K-18" class="node default default flowchart-label"><rect height="33" width="50.0625" y="-16.5" x="-25.03125" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-17.53125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">会员定价服务</span></div></foreignObject></g></g><g transform="translate(532.8984375, 225.36264038085938)" data-id="L" data-node="true" id="flowchart-L-21" class="node default default flowchart-label"><rect height="33" width="61.75" y="-16.5" x="-30.875" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-23.375, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="46.75"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">计划定价目录服务</span></div></foreignObject></g></g><g transform="translate(532.8984375, 394.0879211425781)" data-id="M" data-node="true" id="flowchart-M-23" class="node default default flowchart-label"><path transform="translate(-56.8515625,-59.36263664332002)" d="M 0,11.908424428880018 a 56.8515625,11.908424428880018 0,0,0 113.703125 0 a 56.8515625,11.908424428880018 0,0,0 -113.703125 0 l 0,94.90842442888001 a 56.8515625,11.908424428880018 0,0,0 113.703125 0 l 0,-94.90842442888001" style=""></path><g transform="translate(-49.3515625, -34)" style="" class="label"><rect></rect><foreignObject style="width: 98.7031px; height: 68px;" height="68" width="98.703125"><div style="display: table-cell; white-space: nowrap; max-width: 200px;" xmlns="http://www.w3.org/1999/xhtml">    <span class="nodeLabel markdown-node-label"><p> CockroachDB<br>计划和定价表</p></span></div></foreignObject></g></g><g transform="translate(670.625, 99.5)" data-id="N" data-node="true" id="flowchart-N-24" class="node default default flowchart-label"><rect height="33" width="50.0625" y="-16.5" x="-25.03125" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-17.53125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">代码兑换服务</span></div></foreignObject></g></g><g transform="translate(670.625, 225.36264038085938)" data-id="O" data-node="true" id="flowchart-O-27" class="node default default flowchart-label"><path transform="translate(-56.8515625,-59.36263664332002)" d="M 0,11.908424428880018 a 56.8515625,11.908424428880018 0,0,0 113.703125 0 a 56.8515625,11.908424428880018 0,0,0 -113.703125 0 l 0,94.90842442888001 a 56.8515625,11.908424428880018 0,0,0 113.703125 0 l 0,-94.90842442888001" style=""></path><g transform="translate(-49.3515625, -34)" style="" class="label"><rect></rect><foreignObject style="width: 98.7031px; height: 68px;" height="68" width="98.703125"><div style="display: table-cell; white-space: nowrap; max-width: 200px;" xmlns="http://www.w3.org/1999/xhtml">    <span class="nodeLabel markdown-node-label"><p> CockroachDB<br>代码兑换表</p></span></div></foreignObject></g></g></g></g></g><text class="flowchartTitleText" y="-25" x="363.73828125"> Netflix 会员制服务的架构</text></svg><p>会员平台由十几个微服务组成，旨在支持四个九（99.99%）的可用性。</p><p>这种高可用性要求源于该平台在各种面向用户的流程中发挥的关键作用。如果任何服务出现宕机，都会直接影响用户体验。</p><p>该平台支持多个关键功能：</p><ul><li>当用户点击 Netflix 上的播放按钮时，会直接呼叫会员系统，以确定与其计划相关的服务质量。用户允许的并发流和支持的设备等因素都在考虑之列。由于 Netflix 每天都要处理数十亿个流媒体请求，因此该流程处理的流量最大。</li><li>当用户访问其账户页面时会触发会员流。更改计划、管理额外会员和取消会员资格等操作会直接与会员服务交互。</li><li>该平台是任何特定时间点会员总数的权威来源。它发出事件并写入持久存储，Netflix 内部和外部的下游分析系统都会使用该存储。</li></ul><p>架构图的要点如下：</p><ul><li>会员平台在全球范围内管理会员计划和定价目录，不同地区的计划和定价目录各不相同。计划定价目录服务处理基于特定地点产品的规则管理。</li><li>两个 CockroachDB 数据库用于存储计划定价和代码兑换信息。会员定价服务支持会员操作，如更改计划或添加额外会员。</li><li>专门的微服务负责处理与合作伙伴的互动，包括捆绑激活、注册以及与苹果应用商店等平台的集成。</li><li>会员数据存储在 Cassandra 数据库中，该数据库支持订阅服务和历史跟踪服务。</li><li>该平台不仅满足 2.38 亿活跃会员的需求，还关注前会员和重新加入会员的体验。</li><li>该平台生成的数据将提供给下游消费者，以便他们了解注册情况和收入预测。</li></ul><p>Netflix 选择使用 CockroachDB 和 Cassandra 很有意思。</p><p>CockroachDB 具有很强的一致性，适合处理计划定价信息等关键数据，而 Cassandra 则是一种高度可扩展的 NoSQL 数据库，适合处理大量会员数据。</p><p>此外，99.99% 的可用性也表明 Cassandra 非常注重弹性和容错性。无论如何，Netflix 以其全面的混乱工程实践而闻名，它可以主动测试系统的弹性。</p><h2 id="注册流程"><a class="markdownIt-Anchor" href="#注册流程"></a> 注册流程</h2><p>一旦用户开始 Netflix 之旅，他们就会遇到选择计划的选项。</p><p>由于货币、定价和可用计划存在地域差异，因此准确呈现计划选择页面至关重要。Netflix 的会员制平台可确保根据用户的位置和设备类型向其展示适当的选项。</p><p>下图显示了 Netflix 注册流程的详细步骤以及在流程中触发的服务：</p><svg aria-roledescription="flowchart-v2" role="graphics-document document" viewBox="-8 -8 441.62890625 706.8492431640625" style="max-width: 441.62890625px;" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="100%" id="mermaid-1789678113010"><style>#mermaid-1789678113010{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-1789678113010 .error-icon{fill:#552222;}#mermaid-1789678113010 .error-text{fill:#552222;stroke:#552222;}#mermaid-1789678113010 .edge-thickness-normal{stroke-width:2px;}#mermaid-1789678113010 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-1789678113010 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-1789678113010 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-1789678113010 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-1789678113010 .marker{fill:#333333;stroke:#333333;}#mermaid-1789678113010 .marker.cross{stroke:#333333;}#mermaid-1789678113010 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-1789678113010 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-1789678113010 .cluster-label text{fill:#333;}#mermaid-1789678113010 .cluster-label span,#mermaid-1789678113010 p{color:#333;}#mermaid-1789678113010 .label text,#mermaid-1789678113010 span,#mermaid-1789678113010 p{fill:#333;color:#333;}#mermaid-1789678113010 .node rect,#mermaid-1789678113010 .node circle,#mermaid-1789678113010 .node ellipse,#mermaid-1789678113010 .node polygon,#mermaid-1789678113010 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-1789678113010 .flowchart-label text{text-anchor:middle;}#mermaid-1789678113010 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-1789678113010 .node .label{text-align:center;}#mermaid-1789678113010 .node.clickable{cursor:pointer;}#mermaid-1789678113010 .arrowheadPath{fill:#333333;}#mermaid-1789678113010 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-1789678113010 .flowchart-link{stroke:#333333;fill:none;}#mermaid-1789678113010 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-1789678113010 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-1789678113010 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-1789678113010 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-1789678113010 .cluster text{fill:#333;}#mermaid-1789678113010 .cluster span,#mermaid-1789678113010 p{color:#333;}#mermaid-1789678113010 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-1789678113010 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-1789678113010 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker orient="auto" markerHeight="12" markerWidth="12" markerUnits="userSpaceOnUse" refY="5" refX="6" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678113010_flowchart-pointEnd"><path style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 0 0 L 10 5 L 0 10 z"></path></marker><marker orient="auto" markerHeight="12" markerWidth="12" markerUnits="userSpaceOnUse" refY="5" refX="4.5" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678113010_flowchart-pointStart"><path style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 0 5 L 10 10 L 10 0 z"></path></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5" refX="11" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678113010_flowchart-circleEnd"><circle style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" r="5" cy="5" cx="5"></circle></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5" refX="-1" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678113010_flowchart-circleStart"><circle style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" r="5" cy="5" cx="5"></circle></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5.2" refX="12" viewBox="0 0 11 11" class="marker cross flowchart" id="mermaid-1789678113010_flowchart-crossEnd"><path style="stroke-width: 2; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 1,1 l 9,9 M 10,1 l -9,9"></path></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5.2" refX="-1" viewBox="0 0 11 11" class="marker cross flowchart" id="mermaid-1789678113010_flowchart-crossStart"><path style="stroke-width: 2; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 1,1 l 9,9 M 10,1 l -9,9"></path></marker><g class="root"><g class="clusters"></g><g class="edgePaths"><path marker-end="url(#mermaid-1789678113010_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-A LE-B" id="L-A-B-0" d="M198.328,29.34L183.236,35.617C168.143,41.893,137.958,54.447,122.866,65.507C107.773,76.567,107.773,86.133,107.773,90.917L107.773,95.7"></path><path marker-end="url(#mermaid-1789678113010_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-B LE-C" id="L-B-C-0" d="M91.697,134L86.176,139.667C80.655,145.333,69.613,156.667,64.091,169.889C58.57,183.111,58.57,198.222,58.57,205.778L58.57,213.333"></path><path marker-end="url(#mermaid-1789678113010_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-B LE-D" id="L-B-D-0" d="M127.532,134L134.318,139.667C141.103,145.333,154.675,156.667,161.46,167.117C168.246,177.567,168.246,187.133,168.246,191.917L168.246,196.7"></path><path marker-end="url(#mermaid-1789678113010_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-A LE-E" id="L-A-E-0" d="M216.823,33L212.571,38.667C208.32,44.333,199.816,55.667,199.286,66.293C198.756,76.92,206.199,86.84,209.921,91.801L213.642,96.761"></path><path marker-end="url(#mermaid-1789678113010_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-E LE-A" id="L-E-A-0" d="M241.583,101L245.835,95.333C250.087,89.667,258.59,78.333,259.12,67.707C259.651,57.08,252.207,47.16,248.486,42.199L244.764,37.239"></path><path marker-end="url(#mermaid-1789678113010_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-A LE-F" id="L-A-F-0" d="M260.078,30.347L273.699,36.456C287.319,42.565,314.56,54.782,328.18,65.675C341.801,76.567,341.801,86.133,341.801,90.917L341.801,95.7"></path><path marker-end="url(#mermaid-1789678113010_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-F LE-G" id="L-F-G-0" d="M341.801,134L341.801,139.667C341.801,145.333,341.801,156.667,341.801,169.363C341.801,182.059,341.801,196.118,341.801,203.147L341.801,210.177"></path><path marker-end="url(#mermaid-1789678113010_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-G LE-H" id="L-G-H-0" d="M328.144,248.477L321.595,256.39C315.045,264.303,301.946,280.128,295.397,292.824C288.848,305.521,288.848,315.087,288.848,319.871L288.848,324.654"></path><path marker-end="url(#mermaid-1789678113010_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-H LE-I" id="L-H-I-0" d="M288.848,384.402L288.848,390.068C288.848,395.735,288.848,407.068,288.848,417.518C288.848,427.968,288.848,437.535,288.848,442.318L288.848,447.102"></path><path marker-end="url(#mermaid-1789678113010_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-G LE-M" id="L-G-M-0" d="M355.458,248.477L362.007,256.39C368.556,264.303,381.655,280.128,388.205,294.612C394.754,309.095,394.754,322.236,394.754,328.807L394.754,335.378"></path><path marker-end="url(#mermaid-1789678113010_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-M LE-N" id="L-M-N-0" d="M394.754,373.678L394.754,381.132C394.754,388.586,394.754,403.494,394.754,417.518C394.754,431.543,394.754,444.684,394.754,451.255L394.754,457.825"></path><path marker-end="url(#mermaid-1789678113010_flowchart-pointEnd)" style="fill:none;stroke-width:2px;stroke-dasharray:3;" class="edge-thickness-normal edge-pattern-dotted flowchart-link LS-I LE-J" id="L-I-J-0" d="M288.848,506.849L288.848,512.516C288.848,518.183,288.848,529.516,288.848,539.966C288.848,550.416,288.848,559.983,288.848,564.766L288.848,569.549"></path><path marker-end="url(#mermaid-1789678113010_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-J LE-K" id="L-J-K-0" d="M275.504,601.398L268.543,606.64C261.582,611.882,247.66,622.365,240.765,630.974C233.87,639.583,234.002,646.317,234.068,649.683L234.134,653.05"></path><path marker-end="url(#mermaid-1789678113010_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-J LE-L" id="L-J-L-0" d="M302.191,601.398L309.152,606.64C316.113,611.882,330.035,622.365,337.062,630.974C344.089,639.583,344.221,646.317,344.287,649.683L344.353,653.05"></path></g><g class="edgeLabels"><g transform="translate(107.7734375, 67)" class="edgeLabel"><g transform="translate(-26.4296875, -9)" class="label"><foreignObject height="18" width="52.859375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">1. 检索计划详情</span></div></foreignObject></g></g><g transform="translate(58.5703125, 168)" class="edgeLabel"><g transform="translate(-58.5703125, -9)" class="label"><foreignObject height="18" width="117.140625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"> 2. 基于区域、设备类型的加载和读取计划</span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g transform="translate(191.3125, 67)" class="edgeLabel"><g transform="translate(-20.5859375, -9)" class="label"><foreignObject height="18" width="41.171875"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"> 3. 展示选项</span></div></foreignObject></g></g><g transform="translate(267.09375, 67)" class="edgeLabel"><g transform="translate(-35.1953125, -9)" class="label"><foreignObject height="18" width="70.390625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"> 4. 会员选择了一个计划</span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g transform="translate(341.80078125, 168)" class="edgeLabel"><g transform="translate(-26.4296875, -9)" class="label"><foreignObject height="18" width="52.859375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"> 5. 会员服务启动</span></div></foreignObject></g></g><g transform="translate(288.84765625, 295.9538764953613)" class="edgeLabel"><g transform="translate(-26.4296875, -9)" class="label"><foreignObject height="18" width="52.859375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"> 5. 持续订阅信息</span></div></foreignObject></g></g><g transform="translate(288.84765625, 418.40157318115234)" class="edgeLabel"><g transform="translate(-26.4296875, -9)" class="label"><foreignObject height="18" width="52.859375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"> 6. 写入历史服务</span></div></foreignObject></g></g><g transform="translate(394.75390625, 295.9538764953613)" class="edgeLabel"><g transform="translate(-20.5859375, -9)" class="label"><foreignObject height="18" width="41.171875"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"> 7. 通知计费</span></div></foreignObject></g></g><g transform="translate(394.75390625, 418.40157318115234)" class="edgeLabel"><g transform="translate(-20.5859375, -9)" class="label"><foreignObject height="18" width="41.171875"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"> 8. 生成发票</span></div></foreignObject></g></g><g transform="translate(288.84765625, 540.8492698669434)" class="edgeLabel"><g transform="translate(-20.5859375, -9)" class="label"><foreignObject height="18" width="41.171875"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"> 9. 发布事件</span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g transform="translate(229.203125, 16.5)" data-id="A" data-node="true" id="flowchart-A-0" class="node default default flowchart-label"><rect height="33" width="61.75" y="-16.5" x="-30.875" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-23.375, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="46.75"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">增长工程应用程序</span></div></foreignObject></g></g><g transform="translate(107.7734375, 117.5)" data-id="B" data-node="true" id="flowchart-B-1" class="node default default flowchart-label"><rect height="33" width="50.0625" y="-16.5" x="-25.03125" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-17.53125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">会员计划目录</span></div></foreignObject></g></g><g transform="translate(58.5703125, 231.97693824768066)" data-id="C" data-node="true" id="flowchart-C-3" class="node default default flowchart-label"><circle height="33" width="26.6875" r="13.34375" ry="0" rx="0" style=""></circle><g transform="translate(-5.84375, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="11.6875"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">规则</span></div></foreignObject></g></g><g transform="translate(168.24609375, 231.97693824768066)" data-id="D" data-node="true" id="flowchart-D-5" class="node default default flowchart-label"><path transform="translate(-35.0625,-29.976937860345934)" d="M 0,8.984625240230622 a 35.0625,8.984625240230622 0,0,0 70.125 0 a 35.0625,8.984625240230622 0,0,0 -70.125 0 l 0,41.98462524023062 a 35.0625,8.984625240230622 0,0,0 70.125 0 l 0,-41.98462524023062" style=""></path><g transform="translate(-27.5625, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="55.125"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"> SKUDB</span></div></foreignObject></g></g><g transform="translate(229.203125, 117.5)" data-id="E" data-node="true" id="flowchart-E-7" class="node default default flowchart-label"><rect height="33" width="50.0625" y="-16.5" x="-25.03125" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-17.53125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"> 选择计划页面</span></div></foreignObject></g></g><g transform="translate(341.80078125, 117.5)" data-id="F" data-node="true" id="flowchart-F-11" class="node default default flowchart-label"><rect height="33" width="38.375" y="-16.5" x="-19.1875" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-11.6875, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="23.375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">付款页面</span></div></foreignObject></g></g><g transform="translate(341.80078125, 231.97693824768066)" data-id="G" data-node="true" id="flowchart-G-13" class="node default default flowchart-label"><rect height="33" width="50.0625" y="-16.5" x="-25.03125" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-17.53125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">会员状态服务</span></div></foreignObject></g></g><g transform="translate(288.84765625, 357.17772483825684)" data-id="H" data-node="true" id="flowchart-H-15" class="node default default flowchart-label"><path transform="translate(-25.03125,-27.2238486254909)" d="M 0,7.149232416993931 a 25.03125,7.149232416993931 0,0,0 50.0625 0 a 25.03125,7.149232416993931 0,0,0 -50.0625 0 l 0,40.14923241699393 a 25.03125,7.149232416993931 0,0,0 50.0625 0 l 0,-40.14923241699393" style=""></path><g transform="translate(-17.53125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">会员订阅服务</span></div></foreignObject></g></g><g transform="translate(288.84765625, 479.62542152404785)" data-id="I" data-node="true" id="flowchart-I-17" class="node default default flowchart-label"><path transform="translate(-25.03125,-27.2238486254909)" d="M 0,7.149232416993931 a 25.03125,7.149232416993931 0,0,0 50.0625 0 a 25.03125,7.149232416993931 0,0,0 -50.0625 0 l 0,40.14923241699393 a 25.03125,7.149232416993931 0,0,0 50.0625 0 l 0,-40.14923241699393" style=""></path><g transform="translate(-17.53125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">会员历史服务</span></div></foreignObject></g></g><g transform="translate(394.75390625, 357.17772483825684)" data-id="M" data-node="true" id="flowchart-M-19" class="node default default flowchart-label"><rect height="33" width="61.75" y="-16.5" x="-30.875" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-23.375, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="46.75"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">计费工程应用程序</span></div></foreignObject></g></g><g transform="translate(394.75390625, 479.62542152404785)" data-id="N" data-node="true" id="flowchart-N-21" class="node default default flowchart-label"><rect height="33" width="50.0625" y="-16.5" x="-25.03125" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-17.53125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">会员定价服务</span></div></foreignObject></g></g><g transform="translate(288.84765625, 591.3492698669434)" data-id="J" data-node="true" id="flowchart-J-23" class="node default default flowchart-label"><rect height="33" width="26.6875" y="-16.5" x="-13.34375" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-5.84375, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="11.6875"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">事件</span></div></foreignObject></g></g><g transform="translate(233.73828125, 674.3492698669434)" data-id="K" data-node="true" id="flowchart-K-25" class="node default default flowchart-label"><polygon style="" transform="translate(-25.03125,16.5)" class="label-container" points="0,0 50.0625,0 50.0625,-33 0,-33 0,0 -8,0 58.0625,0 58.0625,-33 -8,-33 -8,0"></polygon><g transform="translate(-17.53125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">数据科学管道</span></div></foreignObject></g></g><g transform="translate(343.95703125, 674.3492698669434)" data-id="L" data-node="true" id="flowchart-L-27" class="node default default flowchart-label"><polygon style="" transform="translate(-19.1875,16.5)" class="label-container" points="0,0 38.375,0 38.375,-33 0,-33 0,0 -8,0 46.375,0 46.375,-33 -8,-33 -8,0"></polygon><g transform="translate(-11.6875, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="23.375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">消息管道</span></div></foreignObject></g></g></g></g></g></svg><p>下面将详细介绍每个步骤：</p><ol><li>首先，用户通过 Netflix 的增长工程应用程序选择计划。计划详情从会员计划目录服务中获取，该服务由 CockroachDB 支持。</li><li>会员计划目录服务根据预定义的地区和设备类型规则加载和读取计划。</li><li>然后将检索到的计划展示给用户，让他们根据自己的偏好和预算做出明智的决定。</li><li>用户选择计划后，流程会进入付款确认屏幕。在这里，用户提供付款详情并确认订阅。</li><li>确认后，用户点击 <code>Start Membership</code> 按钮，触发会员状态服务。该服务会将相关信息（如所选计划、价格层级和国家）保存到 Cassandra 数据库中。</li><li>会员状态服务还会将付款情况通知计费工程应用程序。</li><li>计费工程应用程序根据从会员定价服务获取的注册数据生成发票。</li><li>会员数据会同时写入会员历史服务，以确保全面记录用户的订阅历史。</li><li>发布事件以提示激活会员资格。这些事件会触发信息管道，负责向用户发送欢迎邮件，并通知下游系统以进行分析。</li></ol><h2 id="如何跟踪会员历史"><a class="markdownIt-Anchor" href="#如何跟踪会员历史"></a> 如何跟踪会员历史？</h2><p>在 Netflix 会员平台的早期阶段，会员历史和数据是通过应用程序级事件来跟踪的。</p><p>虽然这种方法在初期已经足够，但随着 Netflix 的扩张和会员数据复杂性的增加，显然需要一种更精细、更持久的数据跟踪解决方案。</p><p>为了满足这一需求，Netflix 开发了基于变更数据捕获（CDC）模式的强大解决方案。</p><p>作为参考，CDC 是一种设计模式，可直接捕获对数据库所做的更改，并将这些更改传播到下游系统进行进一步处理或分析。</p><p>下图显示了 CDC 流程的工作原理：</p><svg aria-roledescription="flowchart-v2" role="graphics-document document" viewBox="-8 -49 513.328125 326" style="max-width: 513.328125px;" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="100%" id="mermaid-1789678115838"><style>#mermaid-1789678115838{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-1789678115838 .error-icon{fill:#552222;}#mermaid-1789678115838 .error-text{fill:#552222;stroke:#552222;}#mermaid-1789678115838 .edge-thickness-normal{stroke-width:2px;}#mermaid-1789678115838 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-1789678115838 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-1789678115838 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-1789678115838 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-1789678115838 .marker{fill:#333333;stroke:#333333;}#mermaid-1789678115838 .marker.cross{stroke:#333333;}#mermaid-1789678115838 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-1789678115838 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-1789678115838 .cluster-label text{fill:#333;}#mermaid-1789678115838 .cluster-label span,#mermaid-1789678115838 p{color:#333;}#mermaid-1789678115838 .label text,#mermaid-1789678115838 span,#mermaid-1789678115838 p{fill:#333;color:#333;}#mermaid-1789678115838 .node rect,#mermaid-1789678115838 .node circle,#mermaid-1789678115838 .node ellipse,#mermaid-1789678115838 .node polygon,#mermaid-1789678115838 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-1789678115838 .flowchart-label text{text-anchor:middle;}#mermaid-1789678115838 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-1789678115838 .node .label{text-align:center;}#mermaid-1789678115838 .node.clickable{cursor:pointer;}#mermaid-1789678115838 .arrowheadPath{fill:#333333;}#mermaid-1789678115838 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-1789678115838 .flowchart-link{stroke:#333333;fill:none;}#mermaid-1789678115838 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-1789678115838 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-1789678115838 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-1789678115838 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-1789678115838 .cluster text{fill:#333;}#mermaid-1789678115838 .cluster span,#mermaid-1789678115838 p{color:#333;}#mermaid-1789678115838 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-1789678115838 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-1789678115838 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker orient="auto" markerHeight="12" markerWidth="12" markerUnits="userSpaceOnUse" refY="5" refX="6" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678115838_flowchart-pointEnd"><path style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 0 0 L 10 5 L 0 10 z"></path></marker><marker orient="auto" markerHeight="12" markerWidth="12" markerUnits="userSpaceOnUse" refY="5" refX="4.5" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678115838_flowchart-pointStart"><path style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 0 5 L 10 10 L 10 0 z"></path></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5" refX="11" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678115838_flowchart-circleEnd"><circle style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" r="5" cy="5" cx="5"></circle></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5" refX="-1" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678115838_flowchart-circleStart"><circle style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" r="5" cy="5" cx="5"></circle></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5.2" refX="12" viewBox="0 0 11 11" class="marker cross flowchart" id="mermaid-1789678115838_flowchart-crossEnd"><path style="stroke-width: 2; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 1,1 l 9,9 M 10,1 l -9,9"></path></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5.2" refX="-1" viewBox="0 0 11 11" class="marker cross flowchart" id="mermaid-1789678115838_flowchart-crossStart"><path style="stroke-width: 2; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 1,1 l 9,9 M 10,1 l -9,9"></path></marker><g class="root"><g class="clusters"><g id="目标系统" class="cluster default flowchart-label"><rect height="269" width="193.890625" y="0" x="303.4375" ry="0" rx="0" style=""></rect><g transform="translate(388.6953125, 0)" class="cluster-label"><foreignObject height="18" width="23.375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">目标系统</span></div></foreignObject></g></g><g id="交易" class="cluster default flowchart-label"><rect height="103" width="170.90625" y="83" x="82.53125" ry="0" rx="0" style=""></rect><g transform="translate(162.140625, 83)" class="cluster-label"><foreignObject height="18" width="11.6875"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">交易</span></div></foreignObject></g></g></g><g class="edgePaths"><path marker-end="url(#mermaid-1789678115838_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-A LE-B" id="L-A-B-0" d="M32.531,134.5L36.698,134.5C40.865,134.5,49.198,134.5,57.531,134.5C65.865,134.5,74.198,134.5,81.648,134.5C89.098,134.5,95.665,134.5,98.948,134.5L102.231,134.5"></path><path marker-end="url(#mermaid-1789678115838_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-B LE-C" id="L-B-C-0" d="M140.063,134.5L144.229,134.5C148.396,134.5,156.729,134.5,164.179,134.5C171.629,134.5,178.196,134.5,181.479,134.5L184.763,134.5"></path><path marker-end="url(#mermaid-1789678115838_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-C LE-D" id="L-C-D-0" d="M228.438,134.5L232.604,134.5C236.771,134.5,245.104,134.5,253.438,134.5C261.771,134.5,270.104,134.5,278.438,134.5C286.771,134.5,295.104,134.5,302.554,134.5C310.004,134.5,316.571,134.5,319.854,134.5L323.138,134.5"></path><path marker-end="url(#mermaid-1789678115838_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-D LE-E" id="L-D-E-0" d="M370.186,118L377.621,106.917C385.056,95.833,399.927,73.667,410.645,62.583C421.364,51.5,427.93,51.5,431.214,51.5L434.497,51.5"></path><path marker-end="url(#mermaid-1789678115838_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-D LE-F" id="L-D-F-0" d="M389.797,134.5L393.964,134.5C398.13,134.5,406.464,134.5,414.401,134.5C422.338,134.5,429.878,134.5,433.648,134.5L437.419,134.5"></path><path marker-end="url(#mermaid-1789678115838_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-D LE-G" id="L-D-G-0" d="M370.186,151L377.621,162.083C385.056,173.167,399.927,195.333,410.645,206.417C421.364,217.5,427.93,217.5,431.214,217.5L434.497,217.5"></path></g><g class="edgeLabels"><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g><g class="edgeLabel"><g transform="translate(0, 0)" class="label"><foreignObject height="0" width="0"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"></span></div></foreignObject></g></g></g><g class="nodes"><g transform="translate(456.0625, 51.5)" data-id="E" data-node="true" id="flowchart-E-7" class="node default default flowchart-label"><rect height="33" width="32.53125" y="-16.5" x="-16.265625" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-8.765625, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="17.53125"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">数据库</span></div></foreignObject></g></g><g transform="translate(359.1171875, 134.5)" data-id="D" data-node="true" id="flowchart-D-5" class="node default default flowchart-label"><rect height="33" width="61.359375" y="-16.5" x="-30.6796875" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-23.1796875, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="46.359375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"> CDC 进程</span></div></foreignObject></g></g><g transform="translate(456.0625, 134.5)" data-id="F" data-node="true" id="flowchart-F-9" class="node default default flowchart-label"><rect height="33" width="26.6875" y="-16.5" x="-13.34375" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-5.84375, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="11.6875"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">缓存</span></div></foreignObject></g></g><g transform="translate(456.0625, 217.5)" data-id="G" data-node="true" id="flowchart-G-11" class="node default default flowchart-label"><rect height="33" width="32.53125" y="-16.5" x="-16.265625" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-8.765625, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="17.53125"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">数据仓</span></div></foreignObject></g></g><g transform="translate(209.25, 134.5)" data-id="C" data-node="true" id="flowchart-C-3" class="node default default flowchart-label"><rect height="33" width="38.375" y="-16.5" x="-19.1875" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-11.6875, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="23.375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">交易日志</span></div></foreignObject></g></g><g transform="translate(123.796875, 134.5)" data-id="B" data-node="true" id="flowchart-B-1" class="node default default flowchart-label"><rect height="33" width="32.53125" y="-16.5" x="-16.265625" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-8.765625, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="17.53125"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">交易表</span></div></foreignObject></g></g><g transform="translate(16.265625, 134.5)" data-id="A" data-node="true" id="flowchart-A-0" class="node default default flowchart-label"><path transform="translate(-16.265625,-24.243999206506643)" d="M 0,5.162666137671097 a 16.265625,5.162666137671097 0,0,0 32.53125 0 a 16.265625,5.162666137671097 0,0,0 -32.53125 0 l 0,38.162666137671096 a 16.265625,5.162666137671097 0,0,0 32.53125 0 l 0,-38.162666137671096" style=""></path><g transform="translate(-8.765625, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="17.53125"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">数据库</span></div></foreignObject></g></g></g></g></g><text class="flowchartTitleText" y="-25" x="248.6640625"> CDC 如何工作？</text></svg><p>采用类似 CDC 的方法可确保对会员数据源所做的所有 delta 更改都记录在一个仅有附件的日志系统中，该日志系统由 Cassandra 数据库提供支持。</p><p>下图显示了 Netflix 会员平台的历史数据流：</p><svg aria-roledescription="flowchart-v2" role="graphics-document document" viewBox="-8 -49 279.2109375 533.1976928710938" style="max-width: 279.2109375px;" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" width="100%" id="mermaid-1789678116771"><style>#mermaid-1789678116771{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-1789678116771 .error-icon{fill:#552222;}#mermaid-1789678116771 .error-text{fill:#552222;stroke:#552222;}#mermaid-1789678116771 .edge-thickness-normal{stroke-width:2px;}#mermaid-1789678116771 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-1789678116771 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-1789678116771 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-1789678116771 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-1789678116771 .marker{fill:#333333;stroke:#333333;}#mermaid-1789678116771 .marker.cross{stroke:#333333;}#mermaid-1789678116771 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-1789678116771 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-1789678116771 .cluster-label text{fill:#333;}#mermaid-1789678116771 .cluster-label span,#mermaid-1789678116771 p{color:#333;}#mermaid-1789678116771 .label text,#mermaid-1789678116771 span,#mermaid-1789678116771 p{fill:#333;color:#333;}#mermaid-1789678116771 .node rect,#mermaid-1789678116771 .node circle,#mermaid-1789678116771 .node ellipse,#mermaid-1789678116771 .node polygon,#mermaid-1789678116771 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-1789678116771 .flowchart-label text{text-anchor:middle;}#mermaid-1789678116771 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-1789678116771 .node .label{text-align:center;}#mermaid-1789678116771 .node.clickable{cursor:pointer;}#mermaid-1789678116771 .arrowheadPath{fill:#333333;}#mermaid-1789678116771 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-1789678116771 .flowchart-link{stroke:#333333;fill:none;}#mermaid-1789678116771 .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-1789678116771 .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-1789678116771 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-1789678116771 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-1789678116771 .cluster text{fill:#333;}#mermaid-1789678116771 .cluster span,#mermaid-1789678116771 p{color:#333;}#mermaid-1789678116771 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-1789678116771 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-1789678116771 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}</style><g><marker orient="auto" markerHeight="12" markerWidth="12" markerUnits="userSpaceOnUse" refY="5" refX="6" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678116771_flowchart-pointEnd"><path style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 0 0 L 10 5 L 0 10 z"></path></marker><marker orient="auto" markerHeight="12" markerWidth="12" markerUnits="userSpaceOnUse" refY="5" refX="4.5" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678116771_flowchart-pointStart"><path style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 0 5 L 10 10 L 10 0 z"></path></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5" refX="11" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678116771_flowchart-circleEnd"><circle style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" r="5" cy="5" cx="5"></circle></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5" refX="-1" viewBox="0 0 10 10" class="marker flowchart" id="mermaid-1789678116771_flowchart-circleStart"><circle style="stroke-width: 1; stroke-dasharray: 1, 0;" class="arrowMarkerPath" r="5" cy="5" cx="5"></circle></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5.2" refX="12" viewBox="0 0 11 11" class="marker cross flowchart" id="mermaid-1789678116771_flowchart-crossEnd"><path style="stroke-width: 2; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 1,1 l 9,9 M 10,1 l -9,9"></path></marker><marker orient="auto" markerHeight="11" markerWidth="11" markerUnits="userSpaceOnUse" refY="5.2" refX="-1" viewBox="0 0 11 11" class="marker cross flowchart" id="mermaid-1789678116771_flowchart-crossStart"><path style="stroke-width: 2; stroke-dasharray: 1, 0;" class="arrowMarkerPath" d="M 1,1 l 9,9 M 10,1 l -9,9"></path></marker><g class="root"><g class="clusters"></g><g class="edgePaths"><path marker-end="url(#mermaid-1789678116771_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-A LE-B" id="L-A-B-0" d="M106.797,33L106.797,38.667C106.797,44.333,106.797,55.667,106.797,66.117C106.797,76.567,106.797,86.133,106.797,90.917L106.797,95.7"></path><path marker-end="url(#mermaid-1789678116771_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-B LE-C" id="L-B-C-0" d="M81.766,146.36L75.836,153.541C69.906,160.722,58.047,175.085,52.117,187.05C46.188,199.014,46.188,208.581,46.188,213.364L46.188,218.148"></path><path marker-end="url(#mermaid-1789678116771_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-B LE-D" id="L-B-D-0" d="M131.828,146.36L137.758,153.541C143.688,160.722,155.547,175.085,161.477,190.21C167.406,205.336,167.406,221.223,167.406,229.167L167.406,237.111"></path><path marker-end="url(#mermaid-1789678116771_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-D LE-E" id="L-D-E-0" d="M148.813,294.496L142.784,303.717C136.756,312.938,124.698,331.381,118.669,345.385C112.641,359.389,112.641,368.956,112.641,373.739L112.641,378.523"></path><path marker-end="url(#mermaid-1789678116771_flowchart-pointEnd)" style="fill:none;" class="edge-thickness-normal edge-pattern-solid flowchart-link LS-D LE-F" id="L-D-F-0" d="M185.999,294.496L192.028,303.717C198.057,312.938,210.114,331.381,216.143,350.333C222.172,369.285,222.172,388.748,222.172,398.479L222.172,408.21"></path></g><g class="edgeLabels"><g transform="translate(106.796875, 67)" class="edgeLabel"><g transform="translate(-38.1171875, -9)" class="label"><foreignObject height="18" width="76.234375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel">1. 计费合作伙伴更新请求</span></div></foreignObject></g></g><g transform="translate(46.1875, 189.44769668579102)" class="edgeLabel"><g transform="translate(-41.0390625, -9)" class="label"><foreignObject height="18" width="82.078125"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"> 2. 更新客户的账单合作伙伴</span></div></foreignObject></g></g><g transform="translate(167.40625, 189.44769668579102)" class="edgeLabel"><g transform="translate(-35.1953125, -9)" class="label"><foreignObject height="18" width="70.390625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"> 3. 为客户添加更新数据</span></div></foreignObject></g></g><g transform="translate(112.640625, 349.822696685791)" class="edgeLabel"><g transform="translate(-38.1171875, -9)" class="label"><foreignObject height="18" width="76.234375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"> 4. 将数据插入会员历史表</span></div></foreignObject></g></g><g transform="translate(222.171875, 349.822696685791)" class="edgeLabel"><g transform="translate(-41.0390625, -9)" class="label"><foreignObject height="18" width="82.078125"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="edgeLabel"> 5. 发出更新会员资格的事件</span></div></foreignObject></g></g></g><g class="nodes"><g transform="translate(106.796875, 16.5)" data-id="A" data-node="true" id="flowchart-A-0" class="node default default flowchart-label"><rect height="33" width="38.375" y="-16.5" x="-19.1875" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-11.6875, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="23.375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">会员服务</span></div></foreignObject></g></g><g transform="translate(106.796875, 128.2238483428955)" data-id="B" data-node="true" id="flowchart-B-1" class="node default default flowchart-label"><path transform="translate(-25.03125,-27.2238486254909)" d="M 0,7.149232416993931 a 25.03125,7.149232416993931 0,0,0 50.0625 0 a 25.03125,7.149232416993931 0,0,0 -50.0625 0 l 0,40.14923241699393 a 25.03125,7.149232416993931 0,0,0 50.0625 0 l 0,-40.14923241699393" style=""></path><g transform="translate(-17.53125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel">会员订阅服务</span></div></foreignObject></g></g><g transform="translate(46.1875, 269.635196685791)" data-id="C" data-node="true" id="flowchart-C-3" class="node default default flowchart-label"><circle height="33" width="92.375" r="46.1875" ry="0" rx="0" style=""></circle><g transform="translate(-38.6875, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="77.375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"> Cassandra</span></div></foreignObject></g></g><g transform="translate(167.40625, 269.635196685791)" data-id="D" data-node="true" id="flowchart-D-5" class="node default default flowchart-label"><path transform="translate(-25.03125,-27.2238486254909)" d="M 0,7.149232416993931 a 25.03125,7.149232416993931 0,0,0 50.0625 0 a 25.03125,7.149232416993931 0,0,0 -50.0625 0 l 0,40.14923241699393 a 25.03125,7.149232416993931 0,0,0 50.0625 0 l 0,-40.14923241699393" style=""></path><g transform="translate(-17.53125, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="35.0625"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"> 会员历史服务</span></div></foreignObject></g></g><g transform="translate(112.640625, 430.010196685791)" data-id="E" data-node="true" id="flowchart-E-7" class="node default default flowchart-label"><circle height="33" width="92.375" r="46.1875" ry="0" rx="0" style=""></circle><g transform="translate(-38.6875, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="77.375"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"> Cassandra</span></div></foreignObject></g></g><g transform="translate(222.171875, 430.010196685791)" data-id="F" data-node="true" id="flowchart-F-9" class="node default default flowchart-label"><rect height="33" width="26.6875" y="-16.5" x="-13.34375" ry="0" rx="0" style="" class="basic label-container"></rect><g transform="translate(-5.84375, -9)" style="" class="label"><rect></rect><foreignObject height="18" width="11.6875"><div style="display: inline-block; white-space: nowrap;" xmlns="http://www.w3.org/1999/xhtml"><span class="nodeLabel"> 事件</span></div></foreignObject></g></g></g></g></g><text class="flowchartTitleText" y="-25" x="131.60546875">新会员历史记录流程</text></svg><p>让我们来看看这个过程的步骤：</p><ol><li>假设有一个修改会员计费伙伴的更新请求。会员订阅服务接收到该请求。</li><li>会员订阅服务会处理该请求并更新 Cassandra 数据库中的相关信息。</li><li>除了更新主数据库外，用户的更新数据还会附加到会员历史服务中。该服务负责维护会员数据所有更改的历史记录。</li><li>会员历史服务将附加数据插入会员历史表。该表是历史数据的持久存储。</li><li>最后会发出一个事件，通知下游系统有关成员资格更新的信息。这样，其他服务和流程就能对变化做出反应，并执行任何必要的操作。</li></ol><p>这种设计有多种好处：</p><ul><li><strong>详细调试</strong>：通过维护会员数据更改的全面历史记录，系统可以进行详细的调试和故障排除。开发人员可以追溯事件发生的顺序，了解数据是如何演变的。</li><li><strong>事件回放和对账</strong>：日志系统的只附加特性允许重放事件。在数据损坏或不一致的情况下，系统可以通过从已知的良好状态重放事件来调节数据。</li><li><strong>客户服务分析</strong>：会员历史记录服务捕获的历史数据使客户服务分析变得简单。</li></ul><h2 id="netflix-会员平台的技术足迹"><a class="markdownIt-Anchor" href="#netflix-会员平台的技术足迹"></a> Netflix 会员平台的技术足迹</h2><p>Netflix 会员制平台的技术架构可大致分为两个主要领域：开发和运营 / 监控。</p><p>让我们来详细了解每个领域。</p><h4 id="开发堆栈"><a class="markdownIt-Anchor" href="#开发堆栈"></a> 开发堆栈</h4><p>Netflix 会员制平台的开发堆栈可以用以下要点来描述：</p><ul><li>Netflix 的架构经过优化，可处理每秒高读取请求（RPS)，以支持其庞大的用户群。</li><li>会员平台由超过 12 个微服务组成，这些微服务在 HTTP 层使用 gRPC 进行通信。通常情况下，该平台每秒可处理 300-400 万个请求。为了支持如此大的处理量，Netflix 采用了 gRPC 层的客户端缓存和整个记录的内存缓存等技术，以防止 CockroachDB 成为单点故障。</li><li>会员平台使用的主要编程语言是带有 Spring Boot 的 Java。不过，在某些重写场景中，Netflix 正在逐步过渡到 Kotlin。</li><li>Kafka 在消息传递和与其他团队（如消息传递和下游分析）的接口方面发挥着关键作用。这确保了不同系统间的顺畅通信和数据流。</li><li>Netflix 利用 Spark 和 Flink 对其大数据执行离线对账任务。这些对账工作对于保持会员平台内各种记录系统（如订阅和会员历史数据库）之间的数据一致性和一致性至关重要。数据的准确性还延伸到外部系统，确保整个生态系统的状态一致。</li><li>为确保在线系统的数据一致性，Netflix 采用了轻量级事务并使用 Cassandra 等数据库。这种方法保证了不同服务间数据的完整性和可靠性。</li></ul><h4 id="运行和监测"><a class="markdownIt-Anchor" href="#运行和监测"></a> 运行和监测</h4><p>Netflix 非常重视可观察性和监控，以确保其会员平台的顺利运行：</p><ul><li>广泛的日志记录、仪表板和分布式跟踪机制可实现快速的错误检测和解决。在 Netflix 复杂的微服务环境中，这些工具对于发现和排除故障至关重要。</li><li>设置了生产警报，以跟踪运营指标并保证最佳服务水平。</li><li>利用运营数据来推动机器学习模型，从而增强异常检测并启用自动问题解决流程。所有这些都是为了努力为用户提供不间断的流媒体体验。</li><li>Netflix 利用 Kibana 和 Elasticsearch 等工具创建仪表板并分析日志数据。在错误率激增的情况下，这些仪表盘可让团队快速识别导致问题的特定端点，并采取纠正措施。</li></ul><h2 id="结论"><a class="markdownIt-Anchor" href="#结论"></a> 结论</h2><p>总之，Netflix 的会员平台是公司成功的关键组成部分，使其能够管理用户订阅的整个生命周期。该平台已从一个简单、轻量级的库发展成为一个强大、可扩展的架构，每秒可处理数百万个请求。</p><p>需要记住的一些关键要点如下：</p><ul><li>会员平台负责管理用户注册、计划变更、续订和取消。</li><li>它采用微服务架构，使用 CockroachDB 和 Cassandra 等数据库存储会员数据。</li><li>该平台使用 CDC 捕获并存储会员数据的历史变化，用于调试、事件重放和分析。</li></ul><h4 id="参考文献"><a class="markdownIt-Anchor" href="#参考文献"></a> 参考文献</h4><ul><li><a href="https://substack.com/redirect/19db3f26-2ee5-4ff7-ba91-dd7977f4d927?j=eyJ1IjoiM241d3VpIn0.zuhQr2h0bppviCayt6ZoA-2zzi3IsOcAKWBL0Cs6t9I">Managing 238M memberships at Netflix</a></li><li><a href="https://substack.com/redirect/3817e491-2856-4a03-8706-a2c103787021?j=eyJ1IjoiM241d3VpIn0.zuhQr2h0bppviCayt6ZoA-2zzi3IsOcAKWBL0Cs6t9I">Netflix』s Membership Platform</a></li><li><a href="https://substack.com/redirect/2c62bed5-a3b0-480d-90b0-620f99ff1c08?j=eyJ1IjoiM241d3VpIn0.zuhQr2h0bppviCayt6ZoA-2zzi3IsOcAKWBL0Cs6t9I">Presentation on Managing 238M memberships at Netflix</a></li></ul></body></html>]]></content>
    
    
    <summary type="html">本文是 ByteByteGo 简报的中文翻译，深入探讨了 Netflix 是如何设计其系统架构来管理全球 2.38 亿会员的。文章详细解析了 Netflix 会员平台的演进过程，从早期的轻量级库到如今由十几个微服务构成的高可用分布式系统。内容涵盖其技术选型（如 CockroachDB、Cassandra、Kafka），并重点介绍了用户注册流程和基于变更数据捕获（CDC）的会员历史追踪机制。通过本文，可以一窥世界顶尖流媒体服务背后，支撑其核心订阅业务的系统设计与实践。</summary>
    
    
    
    <category term="翻译" scheme="https://blog.cytrogen.icu/categories/%E7%BF%BB%E8%AF%91/"/>
    
    
    <category term="ByteByteGo" scheme="https://blog.cytrogen.icu/tags/ByteByteGo/"/>
    
  </entry>
  
  <entry>
    <title>IBM 全栈开发【12】：Git 和 GitHub 入门</title>
    <link href="https://blog.cytrogen.icu/posts/369.html"/>
    <id>https://blog.cytrogen.icu/posts/369.html</id>
    <published>2024-06-28T03:54:00.000Z</published>
    <updated>2026-02-09T17:16:54.717Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程，故此记录学习笔记。</p><p>唉，本来还剩一个证就考完了，结果原先十二个证的微学士学位路线被标过期，最新的路线新添了这个 Git 和 GitHub 入门的证，100 美元喜减一。</p><span id="more"></span><h1 id="1-git-和-github-基础知识"><a class="markdownIt-Anchor" href="#1-git-和-github-基础知识"></a> 1. Git 和 GitHub 基础知识</h1><p>应用程序开发人员很少单独工作。大型网络/云/移动开发和数据科学项目将包括许多人 —— 前端开发员、后端开发员、数据库管理员、存储库管理员等。必须跟踪和控制每个贡献者的每次更改，以实现协作、问责制和版本管理。这种分布式版本控制在管理小型和大型软件项目时都极为重要。</p><p>在本模块中，你将了解一些流行的版本控制工具，创建一个 GitHub 账户，并使用 GitHub 网页界面创建一个仓库，向其中添加文件并提交更改。在 GitHub 等基于 Git 的版本控制系统中，分支是工作流程的核心。您还将熟悉创建和使用分支，并将更改合并到主分支。</p><p>学习目标：</p><ul><li>定义分布式版本控制。</li><li>列出用于版本控制的几种工具，包括流行的 Git 平台。</li><li>描述 Git 的基本概念和仓库的目的。</li><li>在你的仓库中添加 / 编辑文件，并使用 GitHub 网页界面提交修改。</li><li>创建 GitHub 账户和仓库。</li><li>解释如何使用分支并描述拉取请求。</li><li>使用 GitHub Web 界面创建 GitHub 分支并执行合并操作。</li></ul><h2 id="11-git-和-github-概述"><a class="markdownIt-Anchor" href="#11-git-和-github-概述"></a> 1.1. Git 和 GitHub 概述</h2><p>Git 和 GitHub 是深受开发人员和数据科学家欢迎的环境，但如果不了解版本控制的基本知识，就无法讨论它们。</p><p>版本控制系统可让您跟踪对源代码的更改。这样，如果您犯了错误，就可以很容易地恢复旧版本的文档。此外，它还能让与其他团队成员的协作变得更加容易。</p><p>用一个例子来说明版本控制是如何工作的：假设你有一份购物清单，希望室友们确认你需要的东西并添加其他物品。如果没有版本控制，在去购物之前就会有一大堆乱七八糟的东西要收拾，而有了版本控制，在每个人都献计献策之后，你就能清楚地知道自己需要什么。</p><p>Git 是根据通用公共许可证或 GNU 发布的免费开源软件。它是一种分布式版本控制系统（或称 DVCS），这意味着世界上任何地方的用户都可以在自己的电脑上拥有项目的副本。当他们进行修改时，他们可以将自己的版本同步到远程服务器，与你共享。</p><p>Git 并不是唯一的版本控制系统，但它的分布式特性是其成为最流行版本控制系统的主要原因之一。版本控制系统广泛应用于涉及代码的事务，但你也可以对图像、文档和任何文件类型进行版本控制。请注意，Git 还支持分支策略，如功能分支，以组织和管理开发工作。</p><p>GitHub 是最受欢迎的 Git 仓库网络托管服务之一。其他服务包括 Git Lab、Bitbucket 和 Beanstock。</p><p>在开始之前，你需要了解一些基本术语：</p><ul><li>Secure Shell 或简称 SSH 协议是一种从一台计算机安全远程登录到另一台计算机的方法。</li><li>Fork 是一个仓库的副本。</li><li>拉取请求（Pull Request 或简称 PR）是指你请求他人在你的修改成为最终版本之前对其进行审核和批准。</li><li>工作目录（Working Directory）包含计算机上与 Git 仓库相关联的文件和子目录。</li><li>提交（Commit）是项目当前状态在某个特定时间点的快照，并附有所做改动的说明。</li><li>分支（Branch）是一条独立的开发线，可以让你独立完成功能或修正。</li><li>合并（Merge）是将一个分支中的改动合并到另一个分支中，通常是将特性分支合并到主分支中。</li><li>克隆（Clone）会在你的电脑上创建一个远程 Git 仓库的本地副本。</li></ul><h4 id="111-github-入门"><a class="markdownIt-Anchor" href="#111-github-入门"></a> 1.1.1. GitHub 入门</h4><p>2000 年代初，Linux 的开发由一个名为 BitKeeper 的免费系统管理。2005 年，BitKeeper 转为收费系统，出于多种原因，这给 Linux 开发人员带来了麻烦。Linus Torvalds 带领团队开发了一个替代的源代码版本控制系统。该项目在很短的时间内完成，主要特点由一个小组确定。其中包括：</p><ul><li>对非线性开发的强大支持。（当时，Linux 补丁以每秒 6.7 个的速度到达）</li><li>分布式开发。每个开发人员都可以拥有一份完整开发历史的本地副本。</li><li>与现有系统和协议兼容。这是承认 Linux 社区多样性的必要条件。</li><li>高效处理大型项目。</li><li>历史加密验证。这确保分布式系统的代码更新完全一致。</li><li>可插拔的合并策略。许多开发途径都可能导致复杂的整合决策，可能需要明确的整合战略。</li></ul><p>Git 仓库模型有什么特别之处？Git 是一个分布式版本控制系统。主要用于在开发过程中跟踪源代码。它包含在程序员之间进行协调、跟踪更改和支持非线性工作流程的元素。由 Linus Torvalds 于 2005 年创建，用于发布 Linux 内核。</p><p>Git 是一个分布式版本控制系统，用于跟踪内容变更。它是协作的中心点，尤其侧重于敏捷开发方法。在中央版本控制系统中，每个开发人员都需要从中央系统中签出代码并提交到中央系统中。由于 Git 是一种分布式版本控制系统，每个开发人员都有一份完整开发历史的本地副本，而且变更会从一个仓库复制到另一个仓库。每个开发人员都可以充当中枢。如果正确使用 Git，就会有一个与可部署代码相对应的主分支。团队可以持续整合已准备好发布的变更，并在两次发布之间同时在不同的分支上工作。</p><p>Git 还允许对任务进行集中管理，并对每个团队进行访问级别控制。Git 可通过 GitHub 桌面客户端等方式在本地使用，也可直接通过连接到 GitHub 网页界面的浏览器使用。IBM 云基于完善和成熟的开源工具，包括 Git 仓库（通常称为 repos）。</p><p>GitHub 是 Git 仓库的在线托管服务。GitHub 由微软的一家子公司托管。GitHub 提供免费、专业和企业账户。截至 2019 年 8 月，GitHub 拥有超过 1 亿个仓库。</p><p>仓库是用于存储文件（包括应用程序源代码）的数据结构。仓库可以跟踪和维护版本控制。</p><p>GitLab 是一个完整的 DevOps 平台，以单个应用程序的形式交付。GitLab 可访问由源代码管理控制的 Git 代码库。通过 GitLab，开发人员可以协作、审查代码、发表评论并帮助改进彼此的代码。使用自己的本地代码副本工作。在需要时对代码进行分支和合并。利用内置的持续集成（Cl）和持续交付（CD）简化测试和交付。</p><h4 id="112-github-分支"><a class="markdownIt-Anchor" href="#112-github-分支"></a> 1.1.2. GitHub 分支</h4><div class="danger"><p>本课内有关注册 GitHub 账户和创建 GitHub 仓库的内容被我跳过了，建议去网上搜索相关的教程。</p></div><p>GitHub 中的所有文件都存储在一个分支中。主分支是确定的，它存储的是代码的可部署版本。主分支是默认创建的，但你也可以使用任何分支作为代码的主要、完成和可部署版本。当你计划更改内容时，可以创建一个新的分支，并给它起一个描述性的名字。新分支一开始就是原始分支的完全副本。当你进行更改时，你创建的分支会保留更改后的代码。</p><p>要创建新分支，请单击下拉菜单 <code>Main</code>，在新分支文本中添加新分支名称，然后选择 <code>Create Branch</code>。</p><p>对于大型软件项目来说，GitHub 分支可能非常复杂。对于我们正在探索的这种简单项目，可以考虑以下方法：从一个共同的基础开始，也就是这个项目的初始源。在开发新功能时，代码会被分支。</p><p>举个例子，两个分支都在进行修改。当两个工作流准备好合并时，每个分支的代码都会被识别为一个提示（tip），然后将两个提示合并为第三个合并分支。</p><pre class="mermaid-error">Mermaid render failed: Mermaid render timed out after 30s</pre><p>开发人员在分支中处理源文件。由于有些项目需要一段时间，源文件并不能立即发挥作用。要更改文件内容，需要选择文件，点击铅笔图标，进行更改，然后提交更改。当开发人员完成指定的工作后，为了保存他们的修改，他们会提交代码。提交表示开发人员确信代码代表了正在开发的功能或功能集的稳定平台。</p><p>当开发人员将变更源提交到自己的路径时，他们需要写一个注释来描述变更。注释应具有意义和描述性。开发人员可以选择提交到当前分支或创建一个新分支。最后，点击 <code>Commit Changes</code>。</p><p>写注释时的一些最佳做法：不要用句号结束评论信息；提交信息的字符数不要超过 50 个；使用扩展窗口了解详情；始终使用主动语态。</p><p>拉取用于启动分支合并，以捕捉变更。拉取请求会将提交的修改建议提供给其他人审查和使用。即使代码尚未完成，也可以在任何提交后进行拉取。拉取需要用户批准更改。该用户可以是变更的作者，也可以是团队中的指定人员。</p><blockquote><p>请注意，如果你在不属于你的分支上做了改动，GitHub 会自动以你的名义提出拉取请求。由于日志文件不可更改，因此总能找到批准合并变更的人。</p></blockquote><p>要打开拉取请求，请单击 <code>Pull Requests</code> 并选择 <code>New Pull Request</code>：</p><ol><li>从比较框中选择新分支。</li><li>向下滚动查看变更。</li><li>确认这些更改就是你要评估的内容。</li><li>为请求添加标题和描述。</li><li>点击 <code>Create Pull Request</code>。</li></ol><p>Git 仓库的目的是让主分支成为唯一部署的代码。开发人员可以修改分支中的源文件，但只有提交后才会发布。拉取命令发出后，代码会被审核和批准。审核通过的代码会被合并回主代码。</p><p>要将已提交的代码变更合并到主代码中，请单击 <code>Merge Pull Request</code>，然后单击 <code>Confirm Merge</code>。当某个分支的所有变更完成后，该分支将被视为过时，应予以删除。</p><h1 id="2-分支-git-命令和管理-github-项目"><a class="markdownIt-Anchor" href="#2-分支-git-命令和管理-github-项目"></a> 2. 分支、Git 命令和管理 GitHub 项目</h1><p>当你开始使用 GitHub 仓库并自动化工作流程时，使用网页界面可能会受到限制，而且更耗时。这就是 Git 命令的用武之地。你可以在自己的桌面或云 IDE 提供的虚拟桌面上使用它，无论你在哪里开发代码。</p><p>在本模块中，你将熟悉并使用各种 Git 命令来克隆和分叉仓库，以及使用命令行提交、推送和拉取更改。</p><h2 id="21-git-工作流概览"><a class="markdownIt-Anchor" href="#21-git-工作流概览"></a> 2.1. Git 工作流概览</h2><p>想象一下，你加入了一个为电子商务平台开发功能的团队。你的任务是添加产品推荐功能。团队使用 Git 和 GitHub 进行版本控制和协作。您将如何与使用 Git 和 GitHub 的团队有效协作？清楚地了解 Git 工作流程能确保您有效地使用 Git 进行版本控制和协作。这些知识将帮助你避免代码冲突和无意中覆盖团队成员工作等问题。</p><p>第一步是克隆团队在 GitHub 上托管的仓库。克隆会在本地计算机上创建一个项目代码副本，以及远程仓库的完整版本历史。通过克隆过程中建立的连接，你可以向远程仓库推送代码变更。你也可以将远程仓库中的任何更改提取到本地仓库中并进行更新。</p><p>作为开发人员，您可能会尝试多种方法来编写该功能的代码。在代码准备就绪之前，您可能不想让更改影响主分支。好的做法是从主分支创建一个分支，然后在新创建的分支上工作。在 Git 中，分支是一个基于主分支的独立开发空间，您可以在其中进行修改。在这种情况下，添加功能时不能干扰主代码库。</p><p>开发完功能后，下一步就是选择修改过的文件并将它们移到暂存区（Staging area）。暂存区是一个临时存储空间，在要求 Git 将所选文件保存到本地仓库之前，您可以在这里收集这些文件。现在您可以将文件提交到新创建的分支。提交文件可以记录更改，确保新功能成为分支的一部分。当你提交文件时，包含提交信息可为你和团队成员提供上下文，以便他们理解变更。例如，在提交信息中加入「已实现产品推荐功能」。</p><p>下一步是将分支中的变更推送到远程仓库。通常情况下，代码在合并到远程仓库的主分支之前，会由负责管理仓库的维护者进行审核。要合并分支，需要创建拉取请求。这是向维护者提出的请求，请其审查并批准分支中的更改。维护者合并拉取请求后，分支中的更改就会反映在主分支中。同样，如果你有维护者权限，就会收到团队成员的拉取请求，你将审查并批准他们的请求。</p><p>您已经了解了软件开发项目的典型工作流程。在某些情况下，你可能会从头开始一个项目，并打算与他人合作。你可以将本地项目目录初始化为 Git 仓库，这样 Git 就会开始跟踪项目目录中的改动。下一步是选择所有需要 Git 跟踪的项目文件，将它们移到暂存区，然后进行初始提交。接着创建一个空白仓库，并将本地 Git 仓库链接到远程仓库。再之后，你会把本地仓库中的所有项目文件推送到远程仓库。其他开发人员可以克隆远程仓库，并按照常规工作流程更新项目文件。</p><p>让我们通过一个用例来更好地理解工作流程。某公司为一个新的网络应用程序开发项目指派了一个由开发人员、测试人员和产品经理组成的团队。首席开发员 Anne 在自己的工作目录中初始化了一个 Git 仓库。她创建项目文件，将其移动到暂存区域，然后进行初始提交。然后，她将提交推送到自己创建的空白远程仓库。所有开发人员都克隆了远程仓库，并通过创建分支开始工作。</p><p>其中一名开发人员 John 负责实现用户身份验证功能。他从主分支中创建了一个名为 <code>User Auth</code> 的新分支。经过全面测试后，他将分支推送到远程仓库，并创建了一个拉取请求。Anne 审核并批准了拉取请求，将修改合并到主分支中，这样其他开发人员就可以访问 John 所做的修改。同样，其他开发人员也会向远程仓库推送他们所做功能的提交。至此，功能开发完成，项目准备发布。</p><p>Anne 从远程仓库中的主分支创建了一个名为 <code>Release 1.0</code> 的发布分支。团队从远程仓库中提取变更，以便更新本地仓库。他们在 <code>Release 1.0</code> 分支中执行最终测试、错误修复和文档更新。测试完成后，他们提交更改，将提交推送到远程仓库，并创建拉取请求。Anne 审核并将更改合并到主分支中，然后将发布标记为 <code>Release 1.0</code>。</p><h2 id="22-git-命令概述"><a class="markdownIt-Anchor" href="#22-git-命令概述"></a> 2.2. Git 命令概述</h2><p>Git 命令有多种用途，例如跟踪和保存更改，以及与他人共享更改。通常情况下，许多此类活动都是通过网页界面执行的。命令行界面（或 CLI）是执行这些活动的另一种选择。</p><p>让我们来学习一些基本命令，如：</p><ul><li><code>git init</code></li><li><code>git add</code></li><li><code>git status</code></li><li><code>git commit</code></li><li><code>git reset</code></li><li><code>git log</code></li><li><code>git branch</code></li><li><code>git checkout</code></li><li><code>git merge</code></li></ul><p><code>git init</code> 命令会在一个目录中初始化一个新的 Git 仓库，这是为项目设置版本控制的第一步。要创建一个 Git 仓库，可以在命令提示符下导航到所需的目录。然后运行 <code>git init</code> 命令。该命令将创建一个名为 <code>.git</code> 的隐藏子目录。</p><p>第二个命令是 <code>git status</code> 命令。通过 <code>git status</code>，您可以查看工作目录的状态以及您所做修改的暂存快照。它提供的信息包括哪些文件已被修改，以及这些文件是否为下一次提交而暂存。为此，您可以导航到 git 仓库所在的目录，然后在命令提示符下运行 <code>git status</code> 命令。这将显示有关当前仓库状态的信息。</p><p>第三种是 <code>git add .</code> 命令，它可以将工作目录中的改动移动到暂存区域。例如，您的 Git 仓库中有一个名为 <code>index.html</code> 的文件，您在其中做了一些改动。这些改动将包含在下一次提交中。为此，你可以打开命令提示符并导航到有 <code>index-html</code> 文件的 Git 仓库。运行 <code>git add .</code> 命令。这样，当前目录中的所有改动都会在下一次提交时加入。</p><p>第四个是 <code>git commit</code> 命令。<code>git commit</code> 会将您所做修改的阶段快照保存到项目中，并附带说明性信息。这条信息解释了提交的目的。假设您想在仓库中创建一个新的 HTML 文件。您可以使用 <code>git commit -m "commit message"</code> 命令来提供描述性信息，比如 <code>git commit -m "created a new HTML file"</code>。</p><p>至此，你已经了解了 <code>git init</code>、<code>git add</code>、<code>git status</code> 和 <code>git commit</code> 命令。</p><p>现在，第五个命令是 <code>git log</code> 命令，它能让你浏览项目以前的改动。如果想查看提交历史，可以定位到 Git 仓库所在的目录，然后运行 <code>git log</code> 命令。这将提供每次提交的相关信息。例如，创建一个新的 HTML 文件就会反映在提交历史中。</p><p>下一个命令是 <code>git reset</code>。<code>git reset</code> 命令会撤销您对工作目录中文件所做的更改。因此，如果代码出错，可以运行 <code>git reset</code> 命令。通过使用 <code>git reset soft</code> 命令，您将重新添加已暂存的更改，并准备好再次提交。</p><p>第七个命令是 <code>git branch</code> 命令。它可以列出、创建、重命名甚至删除 Git 仓库中的分支。例如，如果想在项目中创建一个名为 <code>code list</code> 的新分支，可以使用 <code>git branch</code> 命令，后面跟上新分支的名称，在本例中就是 <code>code_list</code>。</p><p>第八个命令是 <code>git checkout</code> 命令。<code>git checkout</code> 命令可以让你在现有分支之间切换。因此，如果你想切换到 Git 仓库中名为 <code>code_list</code> 的分支，可以运行 <code>git checkout</code> 命令，后面跟上该分支的名称，即 <code>code_list</code>。这条命令会从仓库中签出一个分支到工作目录中。</p><p>第九条也是最后一条命令是 <code>git merge</code>。<code>git merge</code> 可以让你把所有东西重新组合在一起，并将特性分支与主分支合并。因此，如果您在代码列表分支上实现了一个新功能，您就会想把它合并回主分支。您可以使用 <code>git checkout</code> 命令进入目标分支，然后使用 <code>git merge</code> 命令，后面跟上分支名称，在本例中就是 <code>code_list</code>。该命令允许 Git 将特性分支的所有变更集应用到主分支的顶端。</p><h4 id="221-更多的命令"><a class="markdownIt-Anchor" href="#221-更多的命令"></a> 2.2.1. 更多的命令</h4><ul><li><code>git pull</code>：它能从远程仓库获取变更，并将其合并到本地分支。首先，运行 <code>git checkout</code> 命令切换到要合并的分支。然后，运行 <code>git pull</code> 命令，它会从远程仓库的主分支获取改动，并将其合并到你的当前分支。</li><li><code>git push</code>：它能将本地仓库内容上传到远程仓库。首先运行 <code>git checkout</code> 命令，确保您所在的是要推送的分支，然后再将该分支推送到远程仓库。</li><li><code>git version</code>：它显示系统上安装的当前 Git 版本。</li><li><code>git diff</code>：它能显示提交之间的变化、提交树和工作树等。它还能比较分支。</li><li><code>git revert</code>：它通过应用新提交来恢复提交。这会创建一个新的提交，撤销上次提交所做的更改。</li><li><code>git config -global user.email &lt;Your GitHub Email&gt;</code>：它为 Git 设置全局电子邮件配置。需要在提交前执行，以验证用户的电子邮件 ID。</li><li><code>git config –global user.name &lt;Your GitHub Username&gt;</code>：它为 Git 设置全局用户名配置。需要在提交前执行，以验证用户的用户名。</li><li><code>git remote</code>：它列出了与本地仓库相关联的所有远程仓库的名称。<ul><li><code>git remote -v</code>：它列出了本地 Git 仓库所连接的所有远程仓库，以及与这些远程仓库相关的 URL。</li></ul></li><li><code>git remote add origin &lt;URL&gt;</code>：它使用指定的 URL 添加一个名为 <code>origin</code> 的远程仓库。</li><li><code>git remote rename</code>：在 <code>git remote rename</code> 命令后面跟上要重命名的远程仓库名称（在这个例子中，<code>origin</code>）和新名称（例如：<code>upstream</code>）。这将把 <code>origin</code> 远程仓库重命名为 <code>upstream</code>。</li><li><code>git remote rm &lt;name&gt;</code>：它会删除指定名称的远程仓库。</li><li><code>git format-patch</code>：它可生成用于通过电子邮件提交的补丁。这些补丁可用于通过电子邮件提交更改或与他人共享。</li><li><code>git request-pull</code>：它能为电子邮件请求生成待处理更改摘要。它有助于将分支或分叉中的更改传达给上游仓库维护者。</li><li><code>git send-email</code>：它能以电子邮件的形式发送补丁集合。它允许你通过电子邮件向收件人发送多个补丁文件。请确保使用 <code>git config</code> 命令设置电子邮件地址和名称，以便电子邮件客户端在发送邮件时知道发件人的信息。</li><li><code>git am</code>：它将补丁应用到仓库。它将补丁文件作为输入，并将补丁文件中指定的更改应用到仓库。</li><li><code>git daemon</code>：它通过 <code>Git://</code> 协议公开软件仓库。Git 协议是一种轻量级协议，旨在实现 Git 客户端和服务器之间的高效通信。</li><li><code>git instaweb</code>：它能立即启动网络服务器来浏览资源库。它提供了一种简化的方式，无需配置完整的网络服务器，即可通过网络界面查看资源库内容。</li><li><code>git rerere</code>：它会重复使用之前已解决的合并冲突的解决记录。请注意，需要将 <code>rerere.enabled</code> 配置选项设为 <code>true</code>（<code>git config -global rerere.enabled true</code>），<code>git rerere</code> 才能工作。此外，请注意 <code>git rerere</code> 只适用于使用同一分支和提交解决的冲突。</li></ul><h1 id="3-最终项目"><a class="markdownIt-Anchor" href="#3-最终项目"></a> 3. 最终项目</h1><p>现在，你已经熟悉了 GitHub 仓库、分支和 Git 命令，在本模块中，你将运用所学知识和技能创建一个 GitHub 项目，添加一些文件（如开源许可证），并将其公开共享。</p><h2 id="31-概述和评分标准"><a class="markdownIt-Anchor" href="#31-概述和评分标准"></a> 3.1. 概述和评分标准</h2><p>现在您已经掌握了使用 GitHub UI 和 Git CLI 的知识和技能，您将利用这些技能在 Git 上创建一个开源项目，对该项目进行修改并将其提供给社区。您将分叉一个 GitHub 仓库，克隆该仓库到本地系统，更改本地仓库，在本地提交更改，推送回 GitHub 分叉仓库，并创建一个拉取请求，将您的更新添加到原始仓库。这个期末作业项目分为两个部分。</p><ol><li><p>GitHub UI</p><p>你最近受聘成为一家小额信贷初创公司的开发人员，该公司的使命是为低收入人群赋权并提供机会。核心团队目前使用 Subversion (SVN）管理代码。他们希望慢慢将代码转移到 Git。作为第一步，他们要求您在 GitHub 上的一个新仓库中托管计算单利的示例代码。您不仅要托管脚本，还要遵循本课程介绍的最佳实践，为开源项目创建支持文档，包括行为准则和贡献指南。此外，该资源库应根据 Apache License 2.0 向社区开放。</p></li><li><p>Git CLI</p><p>恭喜您与贵公司一起在 GitHub 上创建了一个开源的简单利息计算器 bash 脚本。您的更改已被接受和合并，公司已创建了一个新的全球资源库，供团队协作使用。随着时间的推移，其他开发人员也为该仓库做出了贡献。您的团队在其中一个标记文件中发现了一个错误。我们要求您 fork 这个仓库，在提供的实验室环境中使用 Git CLI 修正错误，并打开一个拉取请求。</p></li></ol><h2 id="32-第-1-部分-github-ui"><a class="markdownIt-Anchor" href="#32-第-1-部分-github-ui"></a> 3.2. 第 1 部分 - GitHub UI</h2><p>完成本实验后，你将证明自己可以：</p><ul><li>在 GitHub 账户中创建一个新仓库。</li><li>为项目选择合适的许可证。</li><li>创建一个 <code>README.md</code> 文件，解释项目的目的。</li><li>创建 <code>Code of Conduct</code> Markdown 文件，说明你希望社区成员如何行为和互动。</li><li>创建 <code>Contribution Guidelines</code> Markdown 文件，告诉社区如何贡献。</li><li>将新文件提交到仓库。</li></ul><p>注意：在整个实验过程中，系统会提示你将 URL 复制并粘贴到编辑器中，然后保存到自己的设备上。这些 URL 将在课程的 <code>Final Submission</code> 部分上传供同行评审。您可以使用任何编辑器应用程序来记录您的 URL。</p><h4 id="321-创建-github-仓库"><a class="markdownIt-Anchor" href="#321-创建-github-仓库"></a> 3.2.1. 创建 GitHub 仓库</h4><p>创建一个名为 <code>github-final-project</code> 的新 GitHub 仓库，并确保它是公开的。</p><p>选择 <code>Add a README file</code> 和 <code>Choose a license</code> 复选框。从下拉菜单中选择 <code>Apache 2.0 License</code>。</p><p><img src="/posts/369/1.webp" alt="" loading="lazy"></p><p>点击 <code>Create Repository</code>。您的仓库就创建完成了，其中包括 <code>README</code> 和 <code>LICENSE</code> 文件。现在，您可以更新仓库文件，为社区提供有用的信息。</p><p>将仓库的 URL 保存在记事本中，稍后提交给同行评审。</p><h4 id="322-更新-readme-文件"><a class="markdownIt-Anchor" href="#322-更新-readme-文件"></a> 3.2.2. 更新 <code>README</code> 文件</h4><p>在文件中添加以下信息：</p><pre><code class="language-markdown">A calculator that calculates simple interest given principal, annual rate of interest and time period in years.Input:  p, principal amount  t, time period in years  r, annual rate of interestOutput  simple interest = p*t*r</code></pre><blockquote><p>可选：您可以在开发项目的过程中继续更新 <code>README</code> 文件。您可以从以下资源中找到一些有用的 <code>README</code> 内容：</p><ul><li><a href="https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-readmes">GitHub README</a></li><li><a href="https://makeareadme.com/">Make a README</a></li><li><a href="https://github.com/matiassingers/awesome-readme">Awesome README</a></li></ul></blockquote><h4 id="323-添加行为准则"><a class="markdownIt-Anchor" href="#323-添加行为准则"></a> 3.2.3. 添加行为准则</h4><p>行为准则有助于为项目参与者的行为制定基本规则。它定义了如何参与社区活动的标准。</p><p>GitHub 提供了常用的行为准则模板，可帮助您快速为项目添加行为准则。要在项目中添加行为准则，请完成以下步骤：</p><ol><li>在仓库根目录下添加一个名为 <code>CODE_OF_CONDUCT.md</code>、模板为 <code>Contributor Covenant</code> 的新文件。</li><li>访问仓库主页，检查文件是否已创建。</li></ol><p><img src="/posts/369/2.webp" alt="img.png" loading="lazy"></p><p>输入 <code>CODE_OF_CONDUCT</code> 后就会自动出现选择模板的选择。</p><h4 id="324-增加贡献指南"><a class="markdownIt-Anchor" href="#324-增加贡献指南"></a> 3.2.4. 增加贡献指南</h4><p>贡献指南告诉项目参与者如何为项目做出贡献。要添加贡献指南，请完成以下步骤：</p><ol><li><p>在仓库根目录下创建一个名为 <code>CONTRIBUTING.md</code> 的新文件，其中包含以下信息：</p><pre><code class="language-markdown">All contributions, bug reports, bug fixes, documentation improvements, enhancements, and ideas are welcome.</code></pre></li><li><p>将文件提交到主分支，并检查它是否列在仓库的主页上。</p></li></ol><blockquote><p>您也可以选择查看以下指南，了解贡献指南的示例并更新此文件：</p><ul><li><a href="https://github.com/Call-for-Code-for-Racial-Justice/Legit-Info/blob/main/CONTRIBUTING.md">Contributing to Legit Info, a Call for Code for Racial Justice Project</a></li><li><a href="https://github.com/openeew/openeew/blob/master/CONTRIBUTING.md">Contributing to OpenEEW</a></li><li><a href="https://github.com/atom/atom/blob/master/CONTRIBUTING.md">Contributing to Atom</a></li><li><a href="https://github.com/rails/rails/blob/main/CONTRIBUTING.md">How to contribute to Ruby on Rails</a></li></ul></blockquote><h4 id="325-托管脚本文件"><a class="markdownIt-Anchor" href="#325-托管脚本文件"></a> 3.2.5. 托管脚本文件</h4><ol><li>在仓库根目录下新建一个名为 <code>simple-interest.sh</code> 的文件。</li><li>在新文件中添加以下代码：<pre><code class="language-sh">#!/bin/bash# This script calculates simple interest given principal,# annual rate of interest and time period in years.# Do not use this in production. Sample purpose only.# Author: Upkar Lidder (IBM)# Additional Authors:# &lt;your GitHub username&gt;# Input:# p, principal amount# t, time period in years# r, annual rate of interest# Output:# simple interest = p*t*recho "Enter the principal:"read pecho "Enter rate of interest per year:"read recho "Enter time period in years:"read ts=`expr $p \* $t \* $r / 100`echo "The simple interest is: "echo $s</code></pre></li><li>将文件提交到主分支。</li></ol><h2 id="33-第-2-部分-git-cli"><a class="markdownIt-Anchor" href="#33-第-2-部分-git-cli"></a> 3.3. 第 2 部分 - Git CLI</h2><p>完成本实验后，您将能够证明自己可以：</p><ul><li>将上游仓库 fork 到自己的账户。</li><li>本地克隆代码。</li><li>在仓库中创建一个分支。</li><li>在分支中进行修改并提交。</li><li>将分支合并回主分支。</li><li>从分叉仓库向上游仓库创建拉取请求。</li><li>还原之前所做的更改。</li></ul><h4 id="331-fork-仓库"><a class="markdownIt-Anchor" href="#331-fork-仓库"></a> 3.3.1. Fork 仓库</h4><p>Fork 项目的 <a href="https://github.com/ibm-developer-skills-network/jbbmo-Introduction-to-Git-and-GitHub">源代码库</a>。</p><p><a href="https://github.com/ibm-developer-skills-network/jbbmo-Introduction-to-Git-and-GitHub"><img src="https://gh-card.dev/repos/ibm-developer-skills-network/jbbmo-Introduction-to-Git-and-GitHub.svg" alt="ibm-developer-skills-network/jbbmo-Introduction-to-Git-and-GitHub - GitHub" loading="lazy"></a></p><h4 id="332-修正错字并与-master-合并"><a class="markdownIt-Anchor" href="#332-修正错字并与-master-合并"></a> 3.3.2. 修正错字并与 <code>master</code> 合并</h4><div class="danger"><p>我自己在本地环境使用 Git Bash，分支并非教程中写的 <code>main</code> 而是 <code>master</code>，因此下面的内容都会以 <code>master</code> 分支为主。</p></div><ol><li>克隆自己 Fork 的仓库。<pre><code class="language-bash">git clone https://github.com/&lt;Your name&gt;/jbbmo-Introduction-to-Git-and-GitHub.git</code></pre></li><li>创建一个名为 <code>bug-fix-typo</code> 的分支。<pre><code class="language-bash">git checkout -b bug-fix-typo</code></pre></li><li>将 <code>README.md</code> 中的页脚从<pre><code class="language-markdown">2022 XYZ, Inc.</code></pre>改为<pre><code class="language-markdown">2023 XYZ, Inc.</code></pre></li><li>添加修正后的文件并提交，同时写上有意义的信息。<pre><code class="language-bash">git add README.mdgit commit -m "Updated the footer year in README.md"</code></pre></li><li>将修复推送到 <code>bug-fix-typo</code> 分支。<pre><code class="language-bash">git push origin bug-fix-typo</code></pre></li><li>切换到 <code>master</code> 分支。将 <code>bug-fix-typo</code> 分支合并回 <code>master</code> 分支。<pre><code class="language-bash">git checkout mastergit merge bug-fix-typo</code></pre></li></ol><h4 id="333-还原错字并提交拉取请求"><a class="markdownIt-Anchor" href="#333-还原错字并提交拉取请求"></a> 3.3.3. 还原错字并提交拉取请求</h4><ol><li><p>检查 <code>master</code> 分支中 <code>README.md</code> 的内容。该文件现在应为：</p><pre><code class="language-markdown">2023 XYZ, Inc.</code></pre><blockquote><p>可以在 Git Bash 中使用 <code>cat &lt;filename&gt;</code> 命令来直接查看。</p></blockquote></li><li><p>创建一个名为 <code>bug-fix-revert</code> 的新分支。</p></li><li><p>使用 <code>git revert</code> 命令还原上一个任务中的更改。</p><pre><code class="language-bash">git loggit revert &lt;commit-hash&gt;</code></pre><blockquote><p>首先，您需要找到要恢复的变更的提交哈希值。这可以通过 <code>git log</code> 查看提交历史来实现。有了提交哈希值，就可以用 <code>git revert &lt;commit-hash&gt;</code> 来还原了。记得将 <code>&lt;commit-hash&gt;</code> 替换为实际的提交哈希值。</p></blockquote><p>现在文件应为：</p><pre><code class="language-markdown">2022 XYZ, Inc.</code></pre></li><li><p>将还原推送到你的仓库中的 <code>bug-fix-revert</code> 分支。</p></li><li><p>转到 GitHub UI。从你的仓库的 <code>bug-fix-revert</code> 分支向原始仓库的主分支创建一个新的拉取请求。此 PR 将自动关闭。</p></li></ol><p><img src="/posts/369/3.webp" alt="img.png" loading="lazy"></p><h4 id="334-检查分支状态"><a class="markdownIt-Anchor" href="#334-检查分支状态"></a> 3.3.4. 检查分支状态</h4><p>导航至页面上 GitHub UI 中的 <code>Branches</code> 部分。它的格式如下：</p><pre><code class="language-plaintext">https://github.com/&lt;Your Github username&gt;/jbbmo-Introduction-to-Git-and-GitHub/branches</code></pre><p>在这一部分中，您可以找到分支名称及其当前状态。</p></body></html>]]></content>
    
    
    <summary type="html">本文是 IBM 全栈开发课程的第十二篇学习笔记，详细介绍了版本控制工具 Git 与代码托管平台 GitHub 的入门知识。笔记内容从版本控制的核心理念讲起，涵盖了仓库、分支、提交、拉取请求等基本概念，并系统梳理了 git clone, commit, push, merge 等常用命令行操作。最后，通过一个完整的毕业项目，手把手指导读者分别使用 GitHub 网页界面和 Git 命令行（CLI）完成创建仓库、修复 Bug、分支管理和发起拉取请求的完整协作流程，为初学者提供了从理论到实战的全面指南。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="IBM" scheme="https://blog.cytrogen.icu/tags/IBM/"/>
    
    <category term="Git" scheme="https://blog.cytrogen.icu/tags/Git/"/>
    
    <category term="GitHub" scheme="https://blog.cytrogen.icu/tags/GitHub/"/>
    
  </entry>
  
  <entry>
    <title>IBM 全栈开发【11】：全栈应用程序开发项目</title>
    <link href="https://blog.cytrogen.icu/posts/fa4d.html"/>
    <id>https://blog.cytrogen.icu/posts/fa4d.html</id>
    <published>2024-06-27T20:41:00.000Z</published>
    <updated>2026-02-09T17:16:54.717Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程，故此记录学习笔记。</p><span id="more"></span><h1 id="1-应用程序静态页面"><a class="markdownIt-Anchor" href="#1-应用程序静态页面"></a> 1. 应用程序：静态页面</h1><p>恭喜您成为「Best Cars」汽车经销商的首席云应用程序开发员。作为热身任务，您需要运行并测试其主要 Django 应用程序。</p><p>Django 应用程序将主要用于用户管理和身份验证、管理汽车型号和品牌，以及路由其他 MongoDB 服务以获取经销商和客户评论。您将在毕业设计课程中分阶段构建此 Django 应用程序和相关服务。</p><blockquote><p>将更改推送到 Git 仓库的步骤：</p><pre><code class="language-bash">git config --global user.email "yourgithub@email.com"git config --global user.name "name"git add .git commit -m"Adding temporary changes to Github"git push</code></pre></blockquote><p><a href="https://github.com/ibm-developer-skills-network/xrwvm-fullstack_developer_capstone"><img src="https://gh-card.dev/repos/ibm-developer-skills-network/xrwvm-fullstack_developer_capstone.svg" alt="ibm-developer-skills-network/xrwvm-fullstack_developer_capstone - GitHub" loading="lazy"></a></p><p>导航至此仓库，并创建一个包含本项目所需的基本启动代码的版本库分叉（fork）。</p><h2 id="11-在开发服务器上运行-django-应用程序"><a class="markdownIt-Anchor" href="#11-在开发服务器上运行-django-应用程序"></a> 1.1. 在开发服务器上运行 Django 应用程序</h2><p>观察 Django 应用程序骨架结构的文件夹结构。您会看到服务器文件夹下有三个子文件夹：</p><ul><li><code>djangoapp</code>：包含 Django 应用程序。</li><li><code>djangoproj</code>：包含项目配置。</li><li><code>frontend</code>：HTML 和 CSS 以及 React 前端。</li></ul><p>接下来，让我们设置 Python 运行时并测试应用程序。</p><pre><code class="language-bash">cd xrwvm-fullstack_developer_capstone/serverpip install virtualenvvirtualenv djangoenvsource djangoenv/bin/activate</code></pre><p>在虚拟环境中安装必要的 Python 软件包。软件包名称已在 <code>requirements.txt</code> 中提供。</p><pre><code class="language-bash">python3 -m pip install -U -r requirements.txt</code></pre><p>在 <code>server/djangoproj/settings.py</code> 的 <code>TEMPLATES</code> 下，您会发现 <code>DIRS</code> 是一个空列表。在列表中添加 <code>os.path.join(BASE_DIR,'frontend/static')</code>，以便 Django 应用程序识别前端静态文件。设置如下：</p><pre><code class="language-python">'DIRS': [    os.path.join(BASE_DIR,'frontend/static')],</code></pre><p>在同一文件 <code>server/djangoproj/settings.py</code> 中，在文件底部添加 Django 应用程序查找静态文件的目录。</p><pre><code class="language-python">STATICFILES_DIRS = [    os.path.join(BASE_DIR,'frontend/static')]</code></pre><p>执行迁移，创建必要的表格。</p><pre><code class="language-bash">python3 manage.py makemigrations</code></pre><p>运行迁移以激活应用程序的模型。</p><pre><code class="language-bash">python3 manage.py migrate</code></pre><p>启动本地开发服务器。</p><pre><code class="language-bash">python3 manage.py runserver</code></pre><blockquote><p>在文件编辑器中打开 <code>server/djangoproj/settings.py</code>，设置 <code>ALLOWED_HOSTS</code> 和 <code>CSRF_TRUSTED_ORIGINS</code> 以反映 Django 应用程序的根 URL。</p><p>请不要在末尾添加 /。</p><pre><code class="language-python">ALLOWED_HOSTS=['localhost','&lt;your application URL here&gt;']CSRF_TRUSTED_ORIGINS=['&lt;your application URL here&gt;']</code></pre></blockquote><h2 id="12-添加-about-us-页面"><a class="markdownIt-Anchor" href="#12-添加-about-us-页面"></a> 1.2. 添加「About Us」页面</h2><p>在编辑器中打开 <code>server/frontend/static/About.html</code>。同一文件夹中还有样式表 <code>style.css</code>。在 <code>About.html</code> 中的 <code>&lt;head&gt;</code> 标签中链接样式表，以便在 HTML 文件中使用。</p><pre><code class="language-html">&lt;link rel="stylesheet" href="/static/style.css"&gt;&lt;link rel="stylesheet" href="/static/bootstrap.min.css"&gt;</code></pre><p>在名为 <code>about-header</code> 的 <code>&lt;div&gt;</code> 标记中粘贴以下内容。</p><pre><code class="language-html">&lt;h1&gt;About Us&lt;/h1&gt;Welcome to Best Cars dealership, home to the best cars in North America. We deal in sale of domestic and imported cars at reasonable prices.</code></pre><p>将图片 <code>person.png</code> 改为真人图片，并修改 <code>About.html</code> 中的所有文字，使其看起来更真实。根据您的喜好更改样式。</p><p>转到 <code>djangoproj/urls.py</code>，在 <code>urlpatterns</code> 中添加以下内容：</p><pre><code class="language-python">path('about/', TemplateView.as_view(template_name="About.html")),</code></pre><h2 id="13-添加-contact-us-页面"><a class="markdownIt-Anchor" href="#13-添加-contact-us-页面"></a> 1.3. 添加「Contact Us」页面</h2><p>在 <code>server/frontend/static</code> 文件夹下添加一个名为 <code>Contact.html</code> 的新文件。</p><p>添加样式表链接。</p><p>添加标题导航栏，将 <code>Contact Us</code> 作为活动链接。</p><p>在文件中写入联系信息内容。您可以发挥创意，编写自己的信息。使用 CSS 创建样式。</p><p>将 <code>contact</code> 路径添加到 <code>djangproj/urls.py</code>：</p><pre><code class="language-python">path('contact/', TemplateView.as_view(template_name="Contact.html")),</code></pre><p>Django 服务器会自动重启。</p><h1 id="2-应用程序用户管理"><a class="markdownIt-Anchor" href="#2-应用程序用户管理"></a> 2. 应用程序：用户管理</h1><p>现在，您已经构建并部署了最初的 Django 应用程序。下一步，经销商的管理员将查看应用程序，以识别用户并根据角色（如匿名用户或注册用户）管理其访问权限。为此，您需要在应用程序中添加身份验证和授权，即用户管理。在本课中，您需要执行以下任务来添加用户管理功能：</p><ul><li>为应用程序创建超级用户。</li><li>构建客户端并进行配置。</li><li>检查客户端配置。</li><li>添加登录视图以处理登录请求。</li><li>添加注销视图以处理注销请求。</li><li>添加注册视图来处理注册请求。</li></ul><h2 id="21-为您的应用创建超级用户"><a class="markdownIt-Anchor" href="#21-为您的应用创建超级用户"></a> 2.1. 为您的应用创建超级用户</h2><p>运行以下命令创建超级用户：</p><pre><code class="language-bash">python manage.py createsuperuser</code></pre><p>输入用户名、电子邮件和密码后，您应该会看到 <code>Superuser created successfully</code> 的信息，表明超级用户已创建。执行以下命令运行服务器：</p><pre><code class="language-bash">python manage.py runserver</code></pre><p>请在端口 <code>8000</code> 上启动应用程序，并在 URL 末尾添加 <code>/admin</code>，以进入 Django 管理用户界面。使用刚刚为超级用户创建的凭据登录管理员站点。单击 <code>AUTHENTICATION AND AUTHORIZATION</code> 部分下的 <code>Users</code>。您应该可以查看刚刚创建的超级用户。</p><h2 id="22-构建客户端并进行配置"><a class="markdownIt-Anchor" href="#22-构建客户端并进行配置"></a> 2.2. 构建客户端并进行配置</h2><p>打开新终端，切换到客户端目录：</p><pre><code class="language-bash">cd /server/frontend</code></pre><p>安装所有必需的软件包：</p><pre><code class="language-bash">npm install</code></pre><p>运行以下命令构建客户端：</p><pre><code class="language-bash">npm run build</code></pre><p>在编辑器中打开 <code>server/djangoproj/settings.py</code>。在 <code>TEMPLATES</code> 下可以找到 <code>DIRS</code>。在列表中添加 <code>os.path.join(BASE_DIR,'frontend/build')</code>，以便 Django 应用程序识别前端。设置如下：</p><pre><code class="language-python">'DIRS': [    os.path.join(BASE_DIR, 'frontend/static'),    os.path.join(BASE_DIR, 'frontend/build'),    os.path.join(BASE_DIR, 'frontend/build/static'),],</code></pre><p>在 <code>server/djangoproj/settings.py</code> 中，将 Django 应用程序查找静态文件的目录添加到名为 <code>STATICFILES_DIRS</code> 的列表中。设置如下：</p><pre><code class="language-python">STATICFILES_DIRS = [    os.path.join(BASE_DIR, 'frontend/static'),    os.path.join(BASE_DIR, 'frontend/build'),    os.path.join(BASE_DIR, 'frontend/build/static'),]</code></pre><h2 id="23-添加新的登录视图"><a class="markdownIt-Anchor" href="#23-添加新的登录视图"></a> 2.3. 添加新的登录视图</h2><p>接下来，您需要创建一个新的登录 Django 视图来处理登录请求。打开 <code>djangoapp/views.py</code>，取消顶部的导入语句。观察登录视图以验证用户身份。用户登录后，视图会返回一个包含用户名和状态的 JSON 对象。</p><p>打开 <code>server/djangoapp/urls.py</code>，取消注释顶部的导入语句：</p><pre><code class="language-python">from django.urls import pathfrom django.conf.urls.static import staticfrom django.conf import settingsfrom . import views</code></pre><p>通过取消对 <code>server/djangoapp/urls.py</code> 中路径条目的注释，为登录视图配置路由，如下所示：</p><pre><code class="language-python">path(route='login', view=views.login_user, name='login'),</code></pre><p>如下所示，在 <code>server/djangoproj/urls.py</code> 中添加路径条目，为登录页面配置路由。登录页面是通过 <code>/server/frontend/src/App.js</code> 中配置的路由呈现的 React 页面。</p><pre><code class="language-python">path('login/', TemplateView.as_view(template_name="index.html")),</code></pre><h2 id="24-添加注销功能"><a class="markdownIt-Anchor" href="#24-添加注销功能"></a> 2.4. 添加注销功能</h2><p>您需要创建一个新的注销 Django 视图来处理注销请求。</p><p>打开 <code>djangoapp/views.py</code>，添加一个新的注销视图来处理注销请求。用户注销后，视图应返回一个包含用户名的 JSON 对象。</p><pre><code class="language-python">def logout_request(request):    logout(request)    data = {"userName": ""}    return JsonResponse(data)</code></pre><p>在 <code>djangoapp/urls.py</code> 中添加路径条目，为注销视图配置路由：</p><pre><code class="language-python">path(route='logout', view=views.logout_request, name='logout'),</code></pre><p>在 <code>server/frontend/static/Home.html</code> 中的空白处加入以下代码，以处理用户退出登录：</p><pre><code class="language-python">const logout = async (e) =&gt; {  let logout_url = window.location.origin+"/djangoapp/logout";  const res = await fetch(logout_url, {    method: "GET",  });  const json = await res.json();  if (json) {    let username = sessionStorage.getItem('username');    sessionStorage.removeItem('username');    window.location.href = window.location.origin;    window.location.reload();    alert("Logging out "+username+"...")  }  else {    alert("The user could not be logged out.")  }};</code></pre><p>打开一个新的终端，运行以下命令：</p><pre><code class="language-bash">cd /server/frontendnpm run build</code></pre><p>如果会话没有过期，您将从上一步登录。如果没有，请登录，然后单击 <code>Logout</code>。</p><h2 id="25-添加注册功能"><a class="markdownIt-Anchor" href="#25-添加注册功能"></a> 2.5. 添加注册功能</h2><p>您需要创建一个新的注册 Django 视图来处理注册请求。</p><p>打开 <code>djangoapp/views.py</code>，添加一个新的注册视图来处理注册请求。用户注册时，应创建一个用户对象，并登录该用户。它应返回一个包含用户名的 JSON 对象。</p><pre><code class="language-python">@csrf_exemptdef registration(request):    context = {}    data = json.loads(request.body)    username = data['userName']    password = data['password']    first_name = data['firstName']    last_name = data['lastName']    email = data['email']    username_exist = False    email_exist = False    try:        # Check if user already exists        User.objects.get(username=username)        username_exist = True    except:        # If not, simply log this is a new user        logger.debug("{} is new user".format(username))    # If it is a new user    if not username_exist:        # Create user in auth_user table        user = User.objects.create_user(username=username, first_name=first_name, last_name=last_name,password=password, email=email)        # Login the user and redirect to list page        login(request, user)        data = {"userName":username,"status":"Authenticated"}        return JsonResponse(data)    else :        data = {"userName":username,"error":"Already Registered"}        return JsonResponse(data)</code></pre><p>在 <code>djangoapp/urls.py</code> 中添加路径条目，为注册视图配置路由：</p><pre><code class="language-python">path(route='register', view=views.registration, name='register'),</code></pre><p>在 <code>frontend/src/components/Register</code> 中创建一个名为 <code>Register.jsx</code> 的文件。我们已经提供了该页面要使用的 CSS。在 <code>Register.jsx</code> 中添加以下代码：</p><pre><code class="language-jsx">import React, { useState } from "react";import "./Register.css";import user_icon from "../assets/person.png"import email_icon from "../assets/email.png"import password_icon from "../assets/password.png"import close_icon from "../assets/close.png"const Register = () =&gt; {  const [userName, setUserName] = useState("");  const [password, setPassword] = useState("");  const [email, setEmail] = useState("");  const [firstName, setFirstName] = useState("");  const [lastName, setlastName] = useState("");  const gohome = ()=&gt; {    window.location.href = window.location.origin;  }  const register = async (e) =&gt; {    e.preventDefault();    let register_url = window.location.origin+"/djangoapp/register";        const res = await fetch(register_url, {        method: "POST",        headers: {            "Content-Type": "application/json",        },        body: JSON.stringify({            "userName": userName,            "password": password,            "firstName":firstName,            "lastName":lastName,            "email":email        }),    });    const json = await res.json();    if (json.status) {        sessionStorage.setItem('username', json.userName);        window.location.href = window.location.origin;    }    else if (json.error === "Already Registered") {      alert("The user with same username is already registered");      window.location.href = window.location.origin;    }};  return(    &lt;div className="register_container" style={{width: "50%"}}&gt;      &lt;div className="header" style={{display: "flex",flexDirection: "row", justifyContent: "space-between"}}&gt;          &lt;span className="text" style={{flexGrow:"1"}}&gt;SignUp&lt;/span&gt;           &lt;div style={{display: "flex",flexDirection: "row", justifySelf: "end", alignSelf: "start" }}&gt;          &lt;a href="/" onClick={()=&gt;{gohome()}} style={{justifyContent: "space-between", alignItems:"flex-end"}}&gt;            &lt;img style={{width:"1cm"}} src={close_icon} alt="X"/&gt;          &lt;/a&gt;          &lt;/div&gt;          &lt;hr/&gt;        &lt;/div&gt;        &lt;form onSubmit={register}&gt;        &lt;div className="inputs"&gt;          &lt;div className="input"&gt;            &lt;img src={user_icon} className="img_icon" alt='Username'/&gt;            &lt;input type="text"  name="username" placeholder="Username" className="input_field" onChange={(e) =&gt; setUserName(e.target.value)}/&gt;          &lt;/div&gt;          &lt;div&gt;            &lt;img src={user_icon} className="img_icon" alt='First Name'/&gt;            &lt;input type="text"  name="first_name" placeholder="First Name" className="input_field" onChange={(e) =&gt; setFirstName(e.target.value)}/&gt;          &lt;/div&gt;          &lt;div&gt;            &lt;img src={user_icon} className="img_icon" alt='Last Name'/&gt;            &lt;input type="text"  name="last_name" placeholder="Last Name" className="input_field" onChange={(e) =&gt; setlastName(e.target.value)}/&gt;          &lt;/div&gt;          &lt;div&gt;            &lt;img src={email_icon} className="img_icon" alt='Email'/&gt;            &lt;input type="email"  name="email" placeholder="email" className="input_field" onChange={(e) =&gt; setEmail(e.target.value)}/&gt;          &lt;/div&gt;          &lt;div className="input"&gt;            &lt;img src={password_icon} className="img_icon" alt='password'/&gt;            &lt;input name="psw" type="password"  placeholder="Password" className="input_field" onChange={(e) =&gt; setPassword(e.target.value)}/&gt;          &lt;/div&gt;        &lt;/div&gt;        &lt;div className="submit_panel"&gt;          &lt;input className="submit" type="submit" value="Register"/&gt;        &lt;/div&gt;      &lt;/form&gt;      &lt;/div&gt;  )}export default Register;</code></pre><p>在 <code>frontend/src/App.js</code> 中配置路由：</p><pre><code class="language-javascript">&lt;Route path="/register" element={&lt;Register /&gt;} /&gt;</code></pre><p>在之前用于运行 <code>npm run build</code> 的终端中，再次运行以反映最新更改。</p><p>在编辑器中打开 <code>server/djangoproj/urls.py</code>，在 <code>urlpatterns</code> 中添加以下路径。路由已在 <code>App.js</code> 中配置：</p><pre><code class="language-python">path('register/', TemplateView.as_view(template_name="index.html")),</code></pre><p>如果已登录，请注销，然后点击 <code>Register</code> 链接。您将看到如下所示的注册页面。</p><h1 id="3-后端服务"><a class="markdownIt-Anchor" href="#3-后端服务"></a> 3. 后端服务</h1><p>在本模块中，您将在 Express 应用程序中实现一些与 MongoDB 进行交易的端点。然后使用 Docker 将 Mongo 和 Express 服务器容器化并运行。此外，您还将使用 Django 模型设置 <code>CarMake</code> 和 <code>CarModel</code>，并填充数据库。然后，将情感分析器部署到 IBM 代码引擎。最后，您将创建代理服务来访问这些外部服务。</p><p>您在上一个模块中创建的 Django 应用程序需要与数据库通信。在本模块中，您将创建一个容器化的 Node.js 应用程序，使用 MongoDB 作为后端为 API 端点提供服务。</p><p>您将在 Express 应用程序中编写这些后端服务，并使用 Docker 将其容器化。</p><p>您将查看和测试以下端点：</p><ul><li><code>/fetchReviews/dealer/29</code></li><li><code>/fetchDealers</code></li><li><code>/fetchDealer/3</code></li><li><code>/fetchDealers/Kansas</code></li></ul><h2 id="31-使用-express-mongo-实现应用程序接口端点"><a class="markdownIt-Anchor" href="#31-使用-express-mongo-实现应用程序接口端点"></a> 3.1. 使用 <code>Express-Mongo</code> 实现应用程序接口端点</h2><p>切换到包含数据文件的目录：</p><pre><code class="language-bash">cd /server/database</code></pre><p>在在线课程实验项目中，我们为您提供了两个用于 <code>Reviews</code> 和 <code>Dealerships</code> 实体的模式文件，以及包含要加载到 MongoDB 并通过端点提供的经销商和评论数据的 JSON 文件。</p><ul><li><code>server/database/data/dealerships.json</code></li><li><code>server/database/data/reviews.json</code></li></ul><p>Node 应用程序将使用 <code>mongoose</code> 与 MongoDB 交互。评论和经销商的模式分别在 <code>review.js</code> 和 <code>dealership.js</code> 中定义。</p><p>查看 <code>server/database/app.js</code> 中的内容。它将提供以下端点：</p><ul><li><code>fetchReviews</code>（用于获取所有评论）</li><li><code>fetchReviews/dealer/:id</code>（用于获取特定经销商的评论）</li><li><code>fetchDealers</code>（用于获取所有经销商的评论）</li><li><code>fetchDealers/:state</code>（用于获取某一州的所有经销商信息）</li><li><code>fetchDealer/:id</code>（按 ID 查找经销商）</li><li><code>insert_review</code>（用于插入评论）</li></ul><p>有些端点已经为您实施。请利用这些想法和先前的学习成果，实施尚未实施的端点。</p><h4 id="311-与-mongoose-合作提供-api-端点"><a class="markdownIt-Anchor" href="#311-与-mongoose-合作提供-api-端点"></a> 3.1.1. 与 Mongoose 合作提供 API 端点</h4><p>运行以下命令来构建 Docker 应用程序。记住，每次更改 <code>app.js</code> 时都要这样做。</p><div class="danger"><p>请确保你的计算机里有安装 Docker。</p><p>运行 Docker 还需要开启 Hyper-V，可以上网找教程。</p></div><pre><code class="language-bash">docker build . -t nodeapp</code></pre><p>我们创建了用于运行两个容器的 <code>docker-compose.yml</code>，一个用于 Mongo，另一个用于 Node 应用程序。运行以下命令来运行服务器：</p><pre><code class="language-bash">docker-compose up</code></pre><h4 id="312-创建应用程序接口端点-url"><a class="markdownIt-Anchor" href="#312-创建应用程序接口端点-url"></a> 3.1.2. 创建应用程序接口端点 URL</h4><p>实现 <code>server/database/app.js</code> 中尚未实施的以下端点（可以直接参考已经被实现的端点写法）：</p><ul><li><p><code>fetchDealers</code>：</p><pre><code class="language-js">app.get('/fetchDealers', async (req, res) =&gt; {  try {    const documents = await Dealerships.find();    res.json(documents);  } catch (error) {    res.status(500).json({ error: 'Error fetching documents' });  }});</code></pre></li><li><p><code>fetchDealers/:state</code>：</p><pre><code class="language-js">app.get('/fetchDealers/:state', async (req, res) =&gt; {  try {    const documents = await Dealerships.find({state: req.params.state});    res.json(documents);  } catch (error) {    res.status(500).json({ error: 'Error fetching documents' });  }});</code></pre></li><li><p><code>fetchDealer/:id</code>：</p><pre><code class="language-js">app.get('/fetchDealer/:id', async (req, res) =&gt; {  try {    const documents = await Dealerships.find({id: req.params.id});    res.json(documents);  } catch (error) {    res.status(500).json({ error: 'Error fetching documents' });  }});</code></pre></li></ul><p>写完后，停止上一个任务中启动的 Docker 应用程序，接着再次执行 <code>docker build</code> 和 <code>docker-compose</code> 命令。</p><p>在 <code>3030</code> 端口中测试以下端点：</p><ul><li><code>/fetchReviews/dealer/29</code></li><li><code>/fetchDealers</code></li><li><code>/fetchDealer/3</code></li><li><code>/fetchDealers/Kansas</code></li></ul><h2 id="32-构建-carmodel-和-carmake-django-模型"><a class="markdownIt-Anchor" href="#32-构建-carmodel-和-carmake-django-模型"></a> 3.2. 构建 <code>CarModel</code> 和 <code>CarMake</code> Django 模型</h2><p>您已经创建了一个经销商和与 CRUD API 相关的评论。接下来，您需要为经销商的库存创建数据模型和服务。</p><p>每个经销商都管理着不同车型和品牌的汽车库存，这些都是相对静态的数据，因此适合本地存储在 Django 中。要集成外部经销商和审查数据，您需要从 Django 应用程序调用 API，并在 Django 视图中处理 API 结果，然后通过 React 页面呈现。此类 Django 视图使用代理服务根据用户请求从外部资源获取数据，并使用 React 组件进行渲染。</p><p>在本课中，您需要执行以下任务来添加汽车模型、与汽车相关的模型和视图以及代理服务：</p><ul><li>创建 <code>CarModel</code> 和 <code>CarMake</code> Django 模型</li><li>在管理网站注册 <code>CarModel</code> 和 <code>CarMake</code> 模型</li><li>创建带有相关汽车品牌和经销商的新汽车模型对象</li></ul><h4 id="321-建立-carmodel-和-carmake-模型的步骤"><a class="markdownIt-Anchor" href="#321-建立-carmodel-和-carmake-模型的步骤"></a> 3.2.1. 建立 <code>CarModel</code> 和 <code>CarMake</code> 模型的步骤</h4><p>您需要在 <code>server/djangoapp/models.py</code> 中创建两个新模型：</p><ul><li>一个 <code>CarMake</code> 模型，用于保存汽车品牌的一些数据。</li><li>一个 <code>CarModel</code> 模型，用于保存汽车模型的一些数据。</li></ul><p>创建汽车制造商 Django 模型 <code>class CarMake(models.Model)</code>：</p><ul><li>名称</li><li>描述</li><li>你想包含在汽车品牌中的任何其他字段</li><li>打印汽车品牌对象的 <code>__str__</code> 方法</li></ul><pre><code class="language-python">class CarMake(models.Model):    name = models.CharField(max_length=100)    description = models.TextField()    def __str__(self):        return self.name</code></pre><p>创建汽车模型 Django 模型 <code>class CarModel(models.Model)</code>：</p><ul><li>与 <code>CarMake</code> 模型的多对一关系（使用外键字段，一个汽车品牌可以有多个汽车型号）</li><li>经销商 ID（整数字段）指 Cloudant 数据库中创建的经销商</li><li>名称</li><li>类型（带选择参数的 <code>CharField</code>，用于提供有限的选择，如轿车、SUV 和旅行车）</li><li>年份（日期字段）</li><li>您希望包含在汽车模型中的任何其他字段</li><li>打印汽车品牌和车型对象的 <code>__str__</code> 方法</li></ul><pre><code class="language-python">class CarModel(models.Model):    car_make = models.ForeignKey(CarMake, on_delete=models.CASCADE)  # Many-to-One relationship    name = models.CharField(max_length=100)    CAR_TYPES = [        ('SEDAN', 'Sedan'),        ('SUV', 'SUV'),        ('WAGON', 'Wagon'),        # Add more choices as required    ]    type = models.CharField(max_length=10, choices=CAR_TYPES, default='SUV')    year = models.IntegerField(default=2023,        validators=[            MaxValueValidator(2023),            MinValueValidator(2015)        ])    def __str__(self):        return self.name</code></pre><p>您需要在管理网站上注册 <code>CarMake</code> 和 <code>CarModel</code>，这样就可以方便地管理它们的内容（即执行 CRUD 操作）：</p><pre><code class="language-python"># djangoapp/admin.pyfrom django.contrib import adminfrom .models import CarMake, CarModeladmin.site.register(CarMake)admin.site.register(CarModel)</code></pre><p>为模型运行迁移：</p><pre><code class="language-bash">python manage.py makemigrationspython manage.py migrate --run-syncdb</code></pre><blockquote><p><code>--run-syncdb</code> 允许在不迁移的情况下为应用程序创建表格。</p></blockquote><h4 id="322-在管理网站注册-carmake-和-carmodel-模型的步骤"><a class="markdownIt-Anchor" href="#322-在管理网站注册-carmake-和-carmodel-模型的步骤"></a> 3.2.2. 在管理网站注册 <code>CarMake</code> 和 <code>CarModel</code> 模型的步骤</h4><p>打开 <code>djangoapp/views.py</code>，在文件开头的其他导入语句之后导入 <code>CarMake</code> 和 <code>CarModel</code>，然后添加一个方法来获取汽车列表，方法中包含以下代码：</p><pre><code class="language-python">from .models import CarMake, CarModel# ...def get_cars(request):    count = CarMake.objects.filter().count()    print(count)    if(count == 0):        initiate()    car_models = CarModel.objects.select_related('car_make')    cars = []    for car_model in car_models:        cars.append({"CarModel": car_model.name, "CarMake": car_model.car_make.name})    return JsonResponse({"CarModels":cars})</code></pre><p>打开 <code>server/djangoapp/urls.py</code>，在其中添加 <code>get_cars</code> 的路径：</p><pre><code class="language-python">path(route='get_cars', view=views.get_cars, name ='getcars'),</code></pre><p>打开 <code>server/djangoapp/populate.py</code>，然后粘贴以下代码，以便在数据库中填充数据。如果 <code>CarModel</code> 为空，则在第一次调用 <code>get_cars</code> 时填充数据。如果您想手动添加数据，请跳过此步骤。</p><pre><code class="language-python">from .models import CarMake, CarModeldef initiate():    car_make_data = [        {"name":"NISSAN", "description":"Great cars. Japanese technology"},        {"name":"Mercedes", "description":"Great cars. German technology"},        {"name":"Audi", "description":"Great cars. German technology"},        {"name":"Kia", "description":"Great cars. Korean technology"},        {"name":"Toyota", "description":"Great cars. Japanese technology"},    ]    car_make_instances = []    for data in car_make_data:        car_make_instances.append(CarMake.objects.create(name=data['name'], description=data['description']))    # Create CarModel instances with the corresponding CarMake instances    car_model_data = [        {"name":"Pathfinder", "type":"SUV", "year": 2023, "car_make":car_make_instances[0]},        {"name":"Qashqai", "type":"SUV", "year": 2023, "car_make":car_make_instances[0]},        {"name":"XTRAIL", "type":"SUV", "year": 2023, "car_make":car_make_instances[0]},        {"name":"A-Class", "type":"SUV", "year": 2023, "car_make":car_make_instances[1]},        {"name":"C-Class", "type":"SUV", "year": 2023, "car_make":car_make_instances[1]},        {"name":"E-Class", "type":"SUV", "year": 2023, "car_make":car_make_instances[1]},        {"name":"A4", "type":"SUV", "year": 2023, "car_make":car_make_instances[2]},        {"name":"A5", "type":"SUV", "year": 2023, "car_make":car_make_instances[2]},        {"name":"A6", "type":"SUV", "year": 2023, "car_make":car_make_instances[2]},        {"name":"Sorrento", "type":"SUV", "year": 2023, "car_make":car_make_instances[3]},        {"name":"Carnival", "type":"SUV", "year": 2023, "car_make":car_make_instances[3]},        {"name":"Cerato", "type":"Sedan", "year": 2023, "car_make":car_make_instances[3]},        {"name":"Corolla", "type":"Sedan", "year": 2023, "car_make":car_make_instances[4]},        {"name":"Camry", "type":"Sedan", "year": 2023, "car_make":car_make_instances[4]},        {"name":"Kluger", "type":"SUV", "year": 2023, "car_make":car_make_instances[4]},    ]    for data in car_model_data:        CarModel.objects.create(name=data['name'], car_make=data['car_make'], type=data['type'], year=data['year'])</code></pre><p>如果您想手动添加汽车品牌和型号，也可以进入管理页面，根据自己的意愿添加。请注意，在项目后期，您只能从这些表格中选择一个品牌和车型发表评论。</p><p>进入 <code>127.0.0.1:8000/djangoapp/get_cars</code> 来查看已添加的汽车列表。</p><h2 id="33-创建后台-api-的-django-代理服务"><a class="markdownIt-Anchor" href="#33-创建后台-api-的-django-代理服务"></a> 3.3. 创建后台 API 的 Django 代理服务</h2><p>在之前的实验中，您创建了 <code>CarModel</code> 和 <code>CarMake</code> 的 Django 模型，这些模型驻留在本地 SQLite 存储库中。您还获得了由 Express API 端点提供服务的经销商和评论模型 Mongo DB。</p><p>现在，您需要集成这些模型和服务，以管理经销商和评论等所有实体。</p><p>要集成外部经销商和评论数据，您需要从 Django 应用程序调用 API 端点，并在 Django 视图中处理 API 结果。这些 Django 视图可以看作是终端用户的代理服务，因为它们会根据用户的请求从外部资源获取数据。</p><p>在本实验中，您将创建此类 Django 视图作为代理服务。</p><h4 id="331-运行-mongo-服务器"><a class="markdownIt-Anchor" href="#331-运行-mongo-服务器"></a> 3.3.1. 运行 Mongo 服务器</h4><p>后端 Mongo Express 服务器需要在实验室环境中的一个终端启动并运行。在这一阶段，服务器代码已经实现了所有的终端点。运行 <code>docker-compose up</code> 来启动服务器（端口 <code>3030</code>）。</p><p>打开 <code>djangoapp/.env</code>，将您的后台网址替换为上一步在记事本中复制的后台网址：</p><blockquote><p>确保末尾的 <code>/</code> 没有被复制。</p></blockquote><pre><code class="language-plaintext">backend_url=your backend url</code></pre><h4 id="332-创建与后端交互的函数"><a class="markdownIt-Anchor" href="#332-创建与后端交互的函数"></a> 3.3.2. 创建与后端交互的函数</h4><p>在之前的实验中，您已经创建了用于 <code>fetchReviews</code> 和 <code>fetchDealers</code> 的 API 端点。现在实现一个方法来从 Django 应用程序访问这些端点。</p><p>在 Django 中，有许多方法可以进行 HTTP 请求。这里我们使用一个非常流行且易于使用的 Python 库，名为 <code>requests</code>。</p><p>打开 <code>djangoapp/restapis.py</code>，添加 <code>get_request</code> 方法，如下所示：</p><pre><code class="language-python">def get_request(endpoint, **kwargs):    params = ""    if(kwargs):        for key,value in kwargs.items():            params=params+key+"="+value+"&amp;"    request_url = backend_url+endpoint+"?"+params    print("GET from {} ".format(request_url))    try:        # Call get method of requests library with URL and parameters        response = requests.get(request_url)        return response.json()    except:        # If any error occurs        print("Network exception occurred")</code></pre><h4 id="333-启动-code-engine"><a class="markdownIt-Anchor" href="#333-启动-code-engine"></a> 3.3.3. 启动 Code Engine</h4><blockquote><p>以下为 Code Engine 相关。该课程采用的是 IBM 的 Skills Network 实验环境，Code Engine 被直接嵌入在这个实验环境中。</p></blockquote><p>创建一个项目，启动 Code Engine。Code Engine 环境需要一段时间来准备。您将在设置面板中看到进度状态。</p><p>Code Engine 设置完成后，您可以看到它已激活。单击 <code>Code Engine CLI</code>，在下面的终端中开始预配置的 CLI。</p><h4 id="334-将情感分析作为微服务部署在-code-engine-上"><a class="markdownIt-Anchor" href="#334-将情感分析作为微服务部署在-code-engine-上"></a> 3.3.4. 将情感分析作为微服务部署在 Code Engine 上</h4><p>在 Code Engine CLI 中，更改为 <code>server/djangoapp/microservices</code> 目录：</p><pre><code class="language-bash">cd xrwvm-fullstack_developer_capstone/server/djangoapp/microservices</code></pre><p>我们为您提供了使用 NLTK 进行情感分析的 <code>sentiment_analyzer.py</code>。我们还为您提供了一个 Dockerfile，您将使用它在代码引擎中部署此服务，并将其作为微服务使用。</p><p>运行以下命令，用 Docker 构建情感分析应用程序（请注意，代码引擎实例是瞬时的，并附在你的实验室空间用户名上）：</p><pre><code class="language-bash">docker build . -t us.icr.io/${SN_ICR_NAMESPACE}/senti_analyzer</code></pre><p>运行以下命令推送 Docker 镜像：</p><pre><code class="language-bash">docker push us.icr.io/${SN_ICR_NAMESPACE}/senti_analyzer</code></pre><p>在 Code Engine 上部署 <code>senti_analyzer</code> 应用程序：</p><pre><code class="language-bash">ibmcloud ce application create --name sentianalyzer --image us.icr.io/${SN_ICR_NAMESPACE}/senti_analyzer --registry-secret icr-secret --port 5000</code></pre><p>连接到生成的 URL 以访问微服务，并检查部署是否成功。如果应用程序部署验证成功，请在浏览器中将 <code>/analyze/Fantastic</code> 服务附加到 URL，查看是否返回正值。</p><p>打开 <code>djangoapp/.env</code>，将 Code Engine 部署 URL 替换为上文获得的部署 URL：</p><pre><code class="language-plaintext">sentiment_analyzer_url=your code engine deployment url</code></pre><blockquote><p>URL 最后的 <code>/</code> 要去掉。</p></blockquote><blockquote><p>如果想要在本地环境中部署该微服务，可以进入 <code>/server/djangoapp/microservices</code> 目录，启动 Docker：</p><pre><code class="language-bash">docker build -t sentiment_app .docker run -p 5050:5050 my_microservice</code></pre><p>然后要在 <code>.env</code> 文件中注释掉 <code>sentiment_analyzer_url</code> 一行。</p></blockquote><p>更新 <code>djangoapp/restapis.py</code>，并在其中添加以下函数，以使用微服务分析情感：</p><pre><code class="language-python">def analyze_review_sentiments(text):    request_url = sentiment_analyzer_url+"/analyze/"+text    try:        # Call get method of requests library with URL and parameters        response = requests.get(request_url)        return response.json()    except Exception as err:        print(f"Unexpected {err=}, {type(err)=}")        print("Network exception occurred")</code></pre><h4 id="335-创建-django-视图以获取经销商"><a class="markdownIt-Anchor" href="#335-创建-django-视图以获取经销商"></a> 3.3.5. 创建 Django 视图以获取经销商</h4><p>使用以下代码更新 <code>djangoapp/views.py</code> 中的 <code>get_dealerships</code> 视图方法。它将使用您在 <code>restapis.py</code> 中通过 <code>/fetchDealers</code> 端点实现的 <code>get_request</code>。</p><pre><code class="language-python">def get_dealerships(request, state="All"):    if(state == "All"):        endpoint = "/fetchDealers"    else:        endpoint = "/fetchDealers/"+state    dealerships = get_request(endpoint)    return JsonResponse({"status":200,"dealers":dealerships})</code></pre><p>为 <code>url.py</code> 中的 <code>get_dealerships</code> 视图方法配置路由：</p><pre><code class="language-python">path(route='get_dealers', view=views.get_dealerships, name='get_dealers'),path(route='get_dealers/&lt;str:state&gt;', view=views.get_dealerships, name='get_dealers_by_state'),</code></pre><p>在 <code>views.py</code> 中创建一个以 <code>dealer_id</code> 为参数的 <code>get_dealer_details</code> 方法，并添加一个映射 <code>urls.py</code>。它将使用你在 <code>restapis.py</code> 中实现的 <code>get_request</code>，并传递 <code>/fetchDealer/&lt;dealer id&gt;</code> 端点。</p><pre><code class="language-python">def get_dealer_details(request, dealer_id):    if(dealer_id):        endpoint = "/fetchDealer/"+str(dealer_id)        dealership = get_request(endpoint)        return JsonResponse({"status":200,"dealer":dealership})    else:        return JsonResponse({"status":400,"message":"Bad Request"})</code></pre><p>同样配置路由：</p><pre><code class="language-python">path(route='dealer/&lt;int:dealer_id&gt;', view=views.get_dealer_details, name='dealer_details'),</code></pre><p>在 <code>views.py</code> 中创建以 <code>dealer_id</code> 为参数的 <code>get_dealer_reviews</code> 方法，并添加 <code>urls.py</code> 映射。它将使用在 <code>restapis.py</code> 中实现的 <code>get_request</code>，并传递 <code>/fetchReviews/dealer/&lt;dealer id&gt;</code> 端点。它还将调用 <code>restapis.py</code> 中的 <code>analyze_review_sentiments</code>，以消费微服务并确定每条评论的情感，然后在 <code>review_detail</code> 字典中设置值，并作为 <code>JsonResponse</code> 返回。</p><p>情感属性的值将由情感分析微服务决定。它可以是正面的、中性的或负面的。</p><pre><code class="language-python">def get_dealer_reviews(request, dealer_id):    # if dealer id has been provided    if(dealer_id):        endpoint = "/fetchReviews/dealer/"+str(dealer_id)        reviews = get_request(endpoint)        for review_detail in reviews:            response = analyze_review_sentiments(review_detail['review'])            print(response)            review_detail['sentiment'] = response['sentiment']        return JsonResponse({"status":200,"reviews":reviews})    else:        return JsonResponse({"status":400,"message":"Bad Request"})</code></pre><pre><code class="language-python">path(route='reviews/dealer/&lt;int:dealer_id&gt;', view=views.get_dealer_reviews, name='dealer_details'),</code></pre><h4 id="336-创建-django-视图以发布经销商评论"><a class="markdownIt-Anchor" href="#336-创建-django-视图以发布经销商评论"></a> 3.3.6. 创建 Django 视图以发布经销商评论</h4><p>你已经学会了如何进行各种 <code>GET</code> 调用，现在来创建 Django 视图以发布经销商评论：打开 <code>restapis.py</code>，添加一个 <code>post_review</code> 方法，该方法将接收一个数据字典，并在后台调用 <code>add_review</code>。字典将以键值对的形式接收经销商评论所需的所有值。</p><pre><code class="language-python">def post_review(data_dict):    request_url = backend_url+"/insert_review"    try:        response = requests.post(request_url,json=data_dict)        print(response.json())        return response.json()    except:        print("Network exception occurred")</code></pre><p>打开 <code>views.py</code>，创建一个新的 <code>def add_review(request)：</code> 方法来处理评论文章请求。在 <code>add_review</code> 视图方法中：</p><ul><li>首先检查用户是否通过身份验证，因为只有通过身份验证的用户才能为经销商发布评论。</li><li>使用字典调用 <code>post_request</code> 方法。</li><li>将 <code>post_request</code> 的结果返回 <code>add_review</code> 视图方法。您可以打印帖子响应。</li><li>以 JSON 格式返回成功状态和信息。</li><li>在 <code>url.py</code> 中为 <code>add_review</code> 视图配置路由。</li></ul><pre><code class="language-python">def add_review(request):    if(request.user.is_anonymous == False):        data = json.loads(request.body)        try:            response = post_review(data)            return JsonResponse({"status":200})        except:            return JsonResponse({"status":401,"message":"Error in posting review"})    else:        return JsonResponse({"status":403,"message":"Unauthorized"})</code></pre><pre><code class="language-python">path(route='add_review', view=views.add_review, name='add_review'),</code></pre><p>从 <code>restapis.py</code> 导入方法，以便在 <code>views.py</code> 中使用：</p><pre><code class="language-python">from .restapis import get_request, analyze_review_sentiments, post_review</code></pre><h1 id="4-应用程序动态页面"><a class="markdownIt-Anchor" href="#4-应用程序动态页面"></a> 4. 应用程序：动态页面</h1><p>在本模块中，您将使用 React 组件添加动态页面，以列出经销商、按州过滤经销商、查看经销商详细信息并添加经销商评论。</p><ul><li>创建前台页面，向终端用户展示后台服务。</li><li>创建一个组件来列出经销商。</li><li>开发一个经销商详情和评论组件。</li><li>创建评论提交页面。</li></ul><p>您在上一个模块中创建了所有必要的后台服务（Django 视图和 API 端点），用于管理经销商、评论和汽车。接下来，是时候创建一些风格化的前端 React 页面来向终端用户展示这些服务结果了。在本学习模块中，您需要执行以下任务将前端添加到应用程序中：</p><ul><li>创建一个经销商组件，列出所有经销商</li><li>创建一个经销商详细信息组件，显示特定经销商的评论</li><li>创建评论提交页面</li></ul><h2 id="41-为经销商页面添加和设置-react-组件"><a class="markdownIt-Anchor" href="#41-为经销商页面添加和设置-react-组件"></a> 4.1. 为经销商页面添加和设置 React 组件</h2><p>打开 <code>frontend/src/App.js</code>，导入 <code>Dealer</code> 组件并将其与其他组件一起添加到顶部。该组件已为您创建，并使用表格元素列出经销商。您可以随意更改外观和感觉。</p><pre><code class="language-jsx">import Dealers from './components/Dealers/Dealers';</code></pre><p>为 <code>/dealers</code> 添加路由，以呈现 <code>Dealers</code> 组件：</p><pre><code class="language-jsx">&lt;Route path="/dealers" element={&lt;Dealers/&gt;} /&gt;</code></pre><p>打开 <code>server/djangoproj/urls.py</code>，在其中添加 <code>Dealers</code> 和 <code>Dealer</code> 的路由：</p><pre><code class="language-python">path('dealers/', TemplateView.as_view(template_name="index.html")),</code></pre><p>打开一个新终端，像以前一样创建前端。进入 <code>127.0.0.1:8000/dealers</code> 测试 <code>get_dealers</code> 视图。</p><h2 id="42-添加-react-组件-dealer-显示评论"><a class="markdownIt-Anchor" href="#42-添加-react-组件-dealer-显示评论"></a> 4.2. 添加 React 组件 <code>Dealer</code> 显示评论</h2><p>打开 <code>frontend/src/App.js</code>，导入 <code>Dealer</code> React 组件的路由并将其添加到其他路由中。这样，当您点击经销商表上的链接时，就会呈现一个经销商特定的 React 页面以及评论。</p><blockquote><p>该页面还有一个链接，可以让已登录的用户发表评论。您将在下一个任务中添加发布评论页面。</p></blockquote><pre><code class="language-jsx">import Dealer from "./components/Dealers/Dealer"</code></pre><pre><code class="language-jsx">&lt;Route path="/dealer/:id" element={&lt;Dealer/&gt;} /&gt;</code></pre><p>在之前创建前端的同一终端再次创建前端。</p><p>打开 <code>server/djangoproj/urls.py</code>，加入以下代码，添加显示经销商页面的路径：</p><pre><code class="language-python">path('dealer/&lt;int:dealer_id&gt;',TemplateView.as_view(template_name="index.html")),</code></pre><p>刷新应用程序，进入 <code>View Reviews</code> 页面，点击任何经销商的名称链接，查看其评论。</p><h2 id="43-创建经销商详情或评论页面"><a class="markdownIt-Anchor" href="#43-创建经销商详情或评论页面"></a> 4.3. 创建经销商详情或评论页面</h2><p>通过身份验证的用户应能点击该链接并为经销商添加评论。我们将添加一个评论提交页面。</p><p>打开并查看 <code>frontend/src/components/Dealers/PostReview.jsx</code>。根据需要对外观和感觉进行修改。</p><p>导入 <code>PostReview</code> 组件，并在 <code>frontend/src/App.js</code> 中添加 <code>postreview/&lt;dealer id&gt;</code> 路由。</p><pre><code class="language-jsx">import PostReview from "./components/Dealers/PostReview"</code></pre><pre><code class="language-jsx">&lt;Route path="/postreview/:id" element={&lt;PostReview/&gt;} /&gt;</code></pre><p>转到构建前端的终端，再次运行构建。</p><p>打开 <code>server/djangoprojs/urls.py</code>，在其中加入以下代码，以添加审阅后页面的路径：</p><pre><code class="language-python">path('postreview/&lt;int:dealer_id&gt;',TemplateView.as_view(template_name="index.html")),</code></pre><p>使用已注册的用户名和密码登录。您将看到 <code>Post Review</code> 链接。向经销商添加评论，测试该链接。</p><h1 id="5-cicd-容器化和部署到-kubernetes"><a class="markdownIt-Anchor" href="#5-cicd-容器化和部署到-kubernetes"></a> 5. CI / CD、容器化和部署到 Kubernetes</h1><p>在本模块中，您将为您创建的所有 JavaScript 和 Python 文件设置一个 CI / CD 操作流程。然后，您将运行所有服务器端组件，包括 Docker 容器中的 Express-Mongo 服务器和代码引擎上的情感分析器无服务器部署。最后，您将构建前端 React 应用程序，并在 Kubernetes 上部署 Django 应用程序。</p><ul><li>配置 Django 应用程序并将其部署到 Kubernetes。</li></ul><p>恭喜您在添加静态页面和用户管理后测试了应用程序。下一步是为源代码设置持续集成和持续交付（CI / CD）。如果有多人参与项目，这一点尤为重要。持续集成（CI）为开发人员提供了一种协作方式，而持续交付（CD）则提供了一种不间断地向客户交付变更的方式。在本模块中，您将：</p><ul><li>了解所提供的 GitHub 工作流程（workflow）模板中的工作流程</li><li>了解所提供的 GitHub 工作流程模板中的 Linting 作业</li><li>启用 GitHub Actions 并运行 Linting 工作流</li></ul><blockquote><p>Linting 是一种自动检查源代码中是否存在编程和样式错误的方法，通常通过使用 Lint 工具（也称为 Linter）来实现。Lint 工具是一种基础的静态代码分析器。</p></blockquote><h2 id="51-添加持续集成和持续部署功能"><a class="markdownIt-Anchor" href="#51-添加持续集成和持续部署功能"></a> 5.1. 添加持续集成和持续部署功能</h2><p>您的团队正在壮大！管理层决定招聘前端和后端工程师，以确保路线图上的功能能在未来版本中及时开发出来。然而，这意味着多名工程师需要在版本库上并行工作。您的任务是确保推送到主分支的代码符合团队的编码风格，并且没有语法错误。</p><p>在本实验中，你将为版本库添加语法检查功能，在开发人员创建拉取请求或将分支合并到默认主分支时自动检查语法错误。在开始实验之前，我们先来了解一下 GitHub Actions。</p><h4 id="511-github-actions"><a class="markdownIt-Anchor" href="#511-github-actions"></a> 5.1.1. GitHub Actions</h4><p>GitHub Actions 提供了一种事件驱动的方式来自动执行项目中的任务。您可以监听多种事件。下面是几个例子：</p><ul><li><code>push</code>：当有人向版本库分支（branch）推送时运行任务。</li><li><code>pull_request</code>：当有人创建拉取请求（PR）时运行任务。您还可以在某些活动发生时启动任务，例如：<ul><li>PR 已打开</li><li>PR 已关闭</li><li>PR 被重新打开</li></ul></li><li><code>create</code>：当有人创建分支或标记时运行任务。</li><li><code>delete</code>：当有人删除分支或标记时运行任务。</li><li><code>manually</code>：手动启动任务。</li></ul><p>在本实验中，您将使用以下一个或多个组件：</p><ul><li>Workflows（工作流）：您可以添加到存储库的作业集合。</li><li>Events：启动工作流的活动。</li><li>Jobs（作业）：一个或多个步骤的序列。作业默认并行运行。</li><li>Steps：可在作业中运行的单个任务。一个步骤可以是一个操作或命令。</li><li>Actions：工作流的最小模块。</li></ul><p>下面为您提供了一个工作流程模板。让我们来研究一下：</p><pre><code class="language-yaml">name: 'Lint Code'on:  push:    branches: [master, main]  pull_request:    branches: [master, main]jobs:  lint_python:    name: Lint Python Files    runs-on: ubuntu-latest    steps:      - name: Checkout Repository        uses: actions/checkout@v3      - name: Set up Python        uses: actions/setup-python@v4        with:          python-version: 3.12      - name: Install dependencies        run: |          python -m pip install --upgrade pip          pip install flake8      - name: Print working directory        run: pwd      - name: Run Linter        run: |          pwd          # This command finds all Python files recursively and runs flake8 on them          find . -name "*.py" -exec flake8 {} +          echo "Linted all the python files successfully"  lint_js:    name: Lint JavaScript Files    runs-on: ubuntu-latest    steps:      - name: Checkout Repository        uses: actions/checkout@v3      - name: Install Node.js        uses: actions/setup-node@v3        with:          node-version: 14      - name: Install JSHint        run: npm install jshint --global      - name: Run Linter        run: |          # This command finds all JavaScript files recursively and runs JSHint on them          find ./server/database -name "*.js" -exec jshint {} +          echo "Linted all the js files successfully"</code></pre><ol><li>第一行命名工作流程。</li><li>下一行定义了工作流的运行时间。工作流应在开发人员向主分支推送变更或创建 PR 时运行。这两种方式的捕获方式如下：<ul><li>推送到主分支（主分支或主分支）时运行：<pre><code class="language-yaml">push:  branches: [master, main]</code></pre></li><li>在主分支（主分支或主分支）上创建 PR 时运行：<pre><code class="language-yaml">pull_request:  branches: [master, main]</code></pre></li></ul></li><li>然后，您将定义所有工作。本工作流程中有两个任务：<ul><li><code>lint_python</code>： 检查 Python 函数</li><li><code>lint_js</code>： 检查 JavaScript 函数</li></ul></li></ol><h4 id="512-github-jobs"><a class="markdownIt-Anchor" href="#512-github-jobs"></a> 5.1.2. GitHub Jobs</h4><p>让我们逐一看看这些作业：</p><ol><li><p><code>lint_python</code>：</p><ul><li>使用 <code>actions/setup-python@v4</code> 操作设置该操作的 Python 运行时。</li><li>使用 <code>pip install</code> 安装所有依赖项。</li><li>在服务器目录下的所有文件中递归运行 Linting 命令 <code>flake8 *.py</code>。</li><li>打印一条提示信息，说明 Linting 已成功完成。</li></ul></li><li><p><code>lint_function_js</code>：</p><ul><li>使用 <code>actions/setup-node@v3</code> 操作设置要运行的 Node.js 运行时。</li><li>安装所有 JSHint 内核 <code>npm install jshint</code>。</li><li>在数据库目录中的所有 <code>.js</code> 文件上递归运行 Linting 命令。</li><li>打印一条提示信息，说明 Linting 已成功完成。</li></ul></li></ol><h4 id="513-启动-github-actions"><a class="markdownIt-Anchor" href="#513-启动-github-actions"></a> 5.1.3. 启动 GitHub Actions</h4><p>要启用 GitHub Actions，请登录 GitHub 并打开已 Fork 的仓库。然后，转到 <code>Actions</code> 选项卡，点击 <code>Set up a workflow yourself</code>。将上述 Lint 代码粘贴到 <code>main.yml</code> 中并提交。再次打开 <code>Actions</code> 选项卡，就会看到提交已自动启动了检查工作流程。</p><p>您可以单击工作流程运行，查看单个作业和每个作业的日志。工作流程成功完成后，你会看到绿色的 <code>√</code>，表示工作顺利。红叉表示在检查代码时发现了错误。</p><p>查看这些提示，解决你可能遇到的常见 Linting 错误。</p><ol><li><p><code>Flake-8 Lint</code>（Python）Linting 错误：</p><ol><li><p>如果收到下列一个或多个错误：</p><pre><code class="language-plaintext">E117 over-indentedE128 continuation line under-indented for visual indent</code></pre><p>解决方法：</p><ul><li>确认所有代码都保持适当的缩进 —— 既不会缩进过小，也不会缩进过大。</li><li>注意：使用文本编辑器确保准确执行。</li></ul></li><li><pre><code class="language-plaintext">E501 line too long (xxx &gt; 79 characters)</code></pre><p>解决办法：</p><ul><li>将代码分成多行，确保每行最多不超过 79 个字符。</li></ul></li><li><pre><code class="language-plaintext">F401 'xxx' imported but unused</code></pre><p>解决方法：</p><ul><li>核实后续代码段中是否使用了提及的实体或变量（<code>xxx</code>）。如果未使用实体或变量，则删除包含该实体或变量的行。</li></ul><blockquote><p>这里有个小坑，<code>djangoapp/views.py</code> 文件中每个函数中的 <code>request</code> 参数绝对不能删除，建议在当前函数内 <code>print</code> 一下 <code>request</code> 参数来回避该错误。部分不能被删除但同时也没被用到的变量同理。</p></blockquote></li><li><pre><code class="language-plaintext">W292 no newline at end of file</code></pre><p>解决方法：</p><ul><li>在文件的最终代码后插入新行，并将光标置于垂直窗格的最左侧（不向右缩进）。</li></ul></li><li><pre><code class="language-plaintext">E302 expected 2 blank lines, found 1</code></pre><p>解决方案：</p><ul><li>确保每对相邻函数之间正好有两行空行（不能多也不能少）。</li></ul></li><li><pre><code class="language-plaintext">E231 missing whitespace after ':'</code></pre><p>解决方法：</p><ul><li>确保在所有字典键值对中的分号后留一个空格。</li><li>例如，如果现有代码为 <code>"a":"b"</code>，请将其更改为 <code>"a": "b"</code>。</li></ul></li><li><pre><code class="language-plaintext">E275 missing whitespace after keyword</code></pre><p>解决办法：</p><ul><li>确保每个关键字后都有一个空格。</li><li>例如，如果您的现有代码是 <code>if("condition"):</code>，请将其改为 <code>if ("condition"):</code>。</li></ul></li><li><pre><code class="language-plaintext">E722 do not use bare 'except'</code></pre><p>解决方法：</p><ul><li>使用 <code>except Exception:</code> 而不是 <code>except</code> 作为捕获异常和全面处理异常的最佳实践。</li><li>例如，如果现有代码是：<pre><code class="language-python">except:    print("Error")</code></pre>您可以将其改为：<pre><code class="language-python">except Exception as e:    print(f"Error: {e}")</code></pre></li></ul></li></ol></li><li><p><code>JS Hint</code>（JavaScript）Linting 错误：</p><ol><li><p>如果收到下列一个或多个错误：</p><pre><code class="language-plaintext">'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).'arrow function syntax (=&gt;)' is only available in ES6 (use 'esversion: 6').'async functions' is only available in ES8 (use 'esversion: 8').'let' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz).'template literal syntax' is only available in ES6 (use 'esversion: 6').</code></pre><p>解决方法：</p><ul><li>在报告此错误的文件开头添加以下一行：<pre><code class="language-js">/*jshint esversion: 8 */</code></pre></li></ul></li><li><pre><code class="language-plaintext">['xxxxxx'] is better written in dot notation.</code></pre><p>解决方法：</p><ul><li>当字典或 JSON 键值对的格式为 <code>key[value]</code> 时，就会出现这个问题。要解决这个问题，请将格式切换为 <code>key.value</code>。</li></ul></li></ol></li></ol><h2 id="52-容器化并部署到-kubernetes"><a class="markdownIt-Anchor" href="#52-容器化并部署到-kubernetes"></a> 5.2. 容器化并部署到 Kubernetes</h2><p>根据最新的技术发展趋势，并为了避免供应商锁定，贵公司的管理团队希望将经销商应用程序部署到多个云中。该应用程序目前在 Code Engine 上运行，但您被告知并非所有云提供商都提供托管 Code Engine 服务。所有大型云提供商都有托管和管理容器的方法，因此您被要求将容器作为缓解这一问题的可能方法。在对应用程序进行容器化时，过程包括将应用程序与其相关的环境变量、配置文件、库和软件依赖关系打包。其结果是一个容器映像，可以在容器平台上运行。您还需要使用 Kubernetes 来管理容器化部署。</p><blockquote><p>Kubernetes 是一个开源容器编排平台，可以自动部署、管理和扩展应用程序。</p></blockquote><p>在本模块中，您将：</p><ul><li>为应用程序添加在容器中运行的功能</li><li>为应用程序添加部署工件，以便 Kubernetes 对其进行管理</li></ul><blockquote><p>注意：在开始实验之前，请按照步骤检查和删除以前持续存在的会话，以避免在运行实验时出现任何问题。</p><p>请运行以下命令：</p><pre><code class="language-bash">kubectl get deployments</code></pre><p>如果您发现经部署 <code>dealership</code> 已经存在，请删除它：</p><pre><code class="language-bash">kubectl delete deployment dealership</code></pre><p>请运行以下命令：</p><pre><code class="language-bash">ibmcloud cr images</code></pre><p>如果有任何 <code>dealership</code> 镜像，请使用删除它：</p><pre><code class="language-bash">ibmcloud cr image-rm us.icr.io/&lt;your sn labs namespace&gt;/dealership:latest &amp;&amp; docker rmi us.icr.io/&lt;your sn labs namespace&gt;/dealership:latest</code></pre><blockquote><p>请输入您的 SN Labs 命名空间，以代替 <code>&lt;your sn labs namespace&gt;</code>。（SN Labs 命名空间是 IBM Skills Network 内置的）</p><p>如果您不记得自己的命名空间，可以使用以下任一命令获取：</p><ul><li>oc 项目</li><li>ibmcloud cr 命名空间（请使用格式为 <code>sn-labs-$USERNAME</code> 的命名空间）</li></ul></blockquote><ul><li>请退出 SN Labs 并清除浏览器缓存和 cookie。</li><li>请重新启动实验室并按以下步骤操作。</li></ul></blockquote><h4 id="521-设置环境"><a class="markdownIt-Anchor" href="#521-设置环境"></a> 5.2.1. 设置环境</h4><ol><li>如果实验室环境已重置，请克隆您的 Git 仓库。</li><li>打开一个新终端，切换到 <code>server/database</code> 目录，然后按照之前的操作运行 Mongo Express 服务器。</li><li>如果部署在 Code Engine 上的情感分析器微服务不可用，请重新部署并更新所需的 URL。</li><li>打开另一个新终端。切换到 <code>server/frontend</code> 目录。运行以下命令创建前端：<pre><code class="language-bash">npm installnpm run build</code></pre></li></ol><h4 id="522-添加-dockerfile"><a class="markdownIt-Anchor" href="#522-添加-dockerfile"></a> 5.2.2. 添加 Dockerfile</h4><p>在 <code>server</code> 目录下创建一个 <code>Dockerfile</code>。文件中应列出以下步骤：</p><ol><li>添加基础镜像。</li><li>添加 <code>requirements.txt</code> 文件。</li><li>安装并更新 Python。</li><li>更改工作目录。</li><li>公开端口。</li><li>运行命令启动应用程序。</li></ol><p>下面是一个示例文件，供您开始使用：</p><pre><code class="language-dockerfile">FROM python:3.12.0-slim-bookwormENV PYTHONBUFFERED 1ENV PYTHONWRITEBYTECODE 1ENV APP=/app# Change the workdir.WORKDIR $APP# Install the requirementsCOPY requirements.txt $APPRUN pip3 install -r requirements.txt# Copy the rest of the filesCOPY . $APPEXPOSE 8000RUN chmod +x /app/entrypoint.shENTRYPOINT ["/bin/bash","/app/entrypoint.sh"]CMD ["gunicorn", "--bind", ":8000", "--workers", "3", "djangoproj.wsgi"]</code></pre><p>请注意，<code>Dockerfile</code> 中倒数第二个命令指的是 <code>entrypoint.sh</code>。在 <code>server</code> 目录中创建该文件。该文件应包含以下内容：</p><pre><code class="language-shell">#!/bin/sh# Make migrations and migrate the database.echo "Making migrations and migrating the database. "python manage.py makemigrations --noinputpython manage.py migrate --run-syncdb --noinputpython manage.py collectstatic --noinputexec "$@"</code></pre><h4 id="523-构建镜像并将其推送到容器注册表"><a class="markdownIt-Anchor" href="#523-构建镜像并将其推送到容器注册表"></a> 5.2.3. 构建镜像并将其推送到容器注册表</h4><p>您必须记住如何构建镜像并将其推送到 IBM Cloud Image Registry (ICR)。您需要在这里执行相同的操作，然后在 Kubernetes 部署文件中引用该镜像。</p><p>请导出 SN Labs 命名空间，并在控制台中打印出来，如下所示：</p><pre><code class="language-bash">MY_NAMESPACE=$(ibmcloud cr namespaces | grep sn-labs-)echo $MY_NAMESPACE</code></pre><p>使用当前目录下的 <code>Dockerfile</code> 执行 docker 构建：</p><pre><code class="language-bash">docker build -t us.icr.io/$MY_NAMESPACE/dealership .</code></pre><p>接下来，将镜像推送到容器注册表：</p><pre><code class="language-bash">docker push us.icr.io/$MY_NAMESPACE/dealership</code></pre><h4 id="524-添加部署工件"><a class="markdownIt-Anchor" href="#524-添加部署工件"></a> 5.2.4. 添加部署工件</h4><p>在 <code>server</code> 目录下创建 <code>deployment.yaml</code> 文件，以创建部署和服务。文件应如下所示：</p><pre><code class="language-yaml">apiVersion: apps/v1kind: Deploymentmetadata:  labels:    run: dealership  name: dealershipspec:  replicas: 1  selector:    matchLabels:      run: dealership  strategy:    rollingUpdate:      maxSurge: 25%      maxUnavailable: 25%    type: RollingUpdate  template:    metadata:      labels:        run: dealership    spec:      containers:      - image: us.icr.io/your-name-space/dealership:latest        imagePullPolicy: Always        name: dealership        ports:        - containerPort: 8000          protocol: TCP      restartPolicy: Always</code></pre><p>请在上述文件中输入您的 SN Labs 命名空间，以代替 <code>your-name-space</code>。</p><h4 id="525-部署应用程序"><a class="markdownIt-Anchor" href="#525-部署应用程序"></a> 5.2.5. 部署应用程序</h4><p>使用以下命令和部署文件创建部署：</p><pre><code class="language-bash">kubectl apply -f deployment.yaml</code></pre><p>通常，我们会在部署中添加一个服务；不过，我们将在此环境中使用端口转发功能来查看正在运行的应用程序：</p><pre><code class="language-bash">kubectl port-forward deployment.apps/dealership 8000:8000</code></pre><blockquote><p>注意：如果出现任何错误，请稍等片刻，然后重新运行该命令。</p></blockquote></body></html>]]></content>
    
    
    <summary type="html">本文是 IBM 全栈开发课程的最终篇学习笔记，通过一个完整的“Best Cars”汽车经销商项目，将课程所学技能融会贯通。文章详细记录了从零构建一个全栈应用的完整流程：首先使用 Django 搭建基础网站并实现用户管理；接着，开发独立的 Node.js/MongoDB 后端服务和 AI 情感分析微服务；然后，创建动态的 React 前端来消费这些服务。最后，教程还演示了如何配置 GitHub Actions 实现 CI/CD，并将主应用容器化（Docker），最终部署到 Kubernetes (K8s) 集群。这篇笔记是对现代全栈开发、微服务和 DevOps 实践的一次全面实战演练。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Python" scheme="https://blog.cytrogen.icu/tags/Python/"/>
    
    <category term="Docker" scheme="https://blog.cytrogen.icu/tags/Docker/"/>
    
    <category term="IBM" scheme="https://blog.cytrogen.icu/tags/IBM/"/>
    
    <category term="Django" scheme="https://blog.cytrogen.icu/tags/Django/"/>
    
    <category term="HTML" scheme="https://blog.cytrogen.icu/tags/HTML/"/>
    
    <category term="Kubernetes" scheme="https://blog.cytrogen.icu/tags/Kubernetes/"/>
    
  </entry>
  
  <entry>
    <title>IBM 全栈开发【10】：微服务和无服务器</title>
    <link href="https://blog.cytrogen.icu/posts/52000.html"/>
    <id>https://blog.cytrogen.icu/posts/52000.html</id>
    <published>2024-06-11T02:32:00.000Z</published>
    <updated>2026-02-09T17:16:54.717Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程，故此记录学习笔记。</p><span id="more"></span><h1 id="1-微服务入门"><a class="markdownIt-Anchor" href="#1-微服务入门"></a> 1. 微服务入门</h1><h2 id="11-十二要素应用程序方法论"><a class="markdownIt-Anchor" href="#11-十二要素应用程序方法论"></a> 1.1. 十二要素应用程序方法论</h2><p>在现代软件开发中，软件通常以服务的形式交付。软件通过互联网集中托管和访问。这种软件通常被称为网络应用程序或软件即服务（简称 SaaS）。十二要素应用程序方法论适合这类应用程序。微服务不是十二要素应用程序的必要条件。不过，微服务通常与十二要素应用程序方法论结合使用。</p><p>十二要素可分为软件交付生命周期中的代码、部署和运维三个阶段。</p><h4 id="111-代码阶段"><a class="markdownIt-Anchor" href="#111-代码阶段"></a> 1.1.1. 代码阶段</h4><p>首先是 <strong>要素一</strong>：<em>代码库</em>。您应始终在版本控制系统（如 Git）中跟踪应用程序的代码库。代码库和应用程序之间是一一对应的关系。一个应用程序应包含在一个单一的代码库中。但是，应用程序会有多个部署或实例。虽然这些部署中的代码库是相同的，但每个部署中都可能存在不同的应用程序版本。例如，开发或测试环境中可能会有尚未到达生产环境的变更。</p><p>接下来是 <strong>要素五</strong>：<em>构建、发布和运行</em>。这一阶段展示了代码库如何成为生产部署。构建阶段编译代码、收集依赖关系，然后将代码库转化为称为构建的可执行单元。发布阶段将构建与部署的当前配置相结合，这样代码就可以运行了。然后，在运行阶段实现应用程序。这三个阶段应严格分开。例如，代码不应在运行时进行更改，因为这样会导致这些更改无法纳入构建阶段。</p><p><strong>要素十</strong> 是 <em>开发与开发的一致性</em>。这一要素最大限度地减少了开发环境和生产环境之间的差异，这对于持续交付以快速将变更推广到生产环境是必不可少的。此举可减少代码在一个环境中运行正常、而在另一个环境中运行不正常的情况。奇偶校验对于后端服务尤为重要：如果在生产中使用 MySQL 数据库，则应在开发环境中使用相同版本的 MySQL 数据库。奇偶校验有助于在开发过程中尽早发现故障。</p><p>我们要讨论的最后一个代码要素是 <strong>要素二</strong>：<em>依赖</em>。应用程序的可靠性取决于其最不可靠的依赖关系。因此，十二要素应用程序不依赖于任何软件包、依赖项或工具的隐式存在。您必须明确声明所有依赖关系。这样，当新开发人员抓取代码库时，就不会假设他们的机器上已经存在任何依赖关系。</p><h4 id="112-部署阶段"><a class="markdownIt-Anchor" href="#112-部署阶段"></a> 1.1.2. 部署阶段</h4><p>第一个部署要素是 <strong>要素三</strong>，即 <em>配置</em>。配置是指不同部署之间可能存在差异的一切。暂存和生产环境可能使用不同的数据库，因此开发人员应根据部署情况配置数据库的凭据和位置。应避免将配置存储为常量，因为不同环境下的配置可能不同。将配置存储在环境变量中，这样就可以在部署过程中轻松更改，而无需更改代码。</p><blockquote><p>暂存（也称为预生产，Staging）复制了一个完整的生产环境，以便在生产变更之前对其进行测试。自动化和公共云平台可按需提供暂存环境，以便对生产变更进行最终测试。</p></blockquote><p><strong>要素四</strong> 是 <em>后台服务</em>。十二要素应用程序不应区分本地服务和第三方服务。两者都应可通过 URL 或其他定位器信息以及任何凭据进行访问，这样开发人员就可以在不更改代码的情况下轻松更换后端服务。例如，如果数据库出现问题，就可以启动一个新的数据库，并在无需更改代码的情况下将其替换进来。</p><p><strong>要素六</strong> 是 <em>进程</em>。应用程序在环境中以一个或多个进程的形式执行。进程应该是无状态的，不共享任何东西。您应将持久数据存储在数据库等后端服务中，因为内存和文件系统不会在进程间共享。如果另一个进程处理后续事务，后续事务将无法访问前一个进程中的数据。因此，数据需要集中存储。</p><blockquote><p>如果进程是无状态的，不共享任何东西，那么应用程序就可以启动额外的进程进行横向扩展，处理额外的工作量，而不会在进程间产生相互依赖关系。</p></blockquote><p><em>端口绑定</em> 是 <strong>要素七</strong>。创建面向网络的服务时，不应在运行时将网络服务器注入应用程序。相反，网络应用程序应通过绑定端口并监听该端口上的传入请求来导出 HTTP。您可以将端口绑定用于 HTTP 和其他服务。绑定端口通常是在代码中通过声明网络服务器库为依赖关系来实现的。随后，由于这些应用程序可以通过 URL 访问，因此它们可以成为其他应用程序的后端服务。</p><h4 id="113-运维阶段"><a class="markdownIt-Anchor" href="#113-运维阶段"></a> 1.1.3. 运维阶段</h4><p>让我们从 <strong>要素八</strong>「<em>并发性</em>」开始。应用程序运行并发进程来处理不断增加的负载。由于进程是无状态的，不共享任何内容，因此应用程序可以启动更多进程进行横向扩展，处理更多传入请求，而不会在进程间产生相互依赖关系。</p><p><strong>要素九</strong> 是 <em>可处置性</em>，它规定应用程序进程需要最短的启动时间，并应在终止时优雅地结束。快速启动可让您快速部署代码或配置变更。您还可以轻松扩展应用程序，因为新的部署可以快速启动。</p><p><strong>要素十一</strong> 决定了 <em>如何处理日志</em>。日志可提供应用程序性能的可见性，因此应用程序不应关注日志的存储。相反，应用环境应将日志作为写入标准输出的事件流来处理。执行环境可以捕获所有运行应用程序的日志流，将其汇总并路由至目的地。当目的地是日志分析工具时，这一操作尤其有用。</p><p>最后一个要素是 <strong>要素十二</strong>：<em>管理流程</em>。管理流程是管理应用程序的一次性流程，例如数据库迁移。管理流程使用相同的代码库和配置针对发布版本运行。此外，应用程序代码应包含管理流程，使其与应用程序保持同步。</p><h2 id="12-微服务"><a class="markdownIt-Anchor" href="#12-微服务"></a> 1.2. 微服务</h2><p>微服务架构是一种方法，在这种方法中，单个应用程序由许多松散耦合且可独立部署的小型服务组成。这些服务通常有自己的技术栈，包括数据库和数据管理模式。团队甚至可以为不同的组件选择不同的编程语言，因为它们通过 API 端点相互依赖。</p><p>微服务组件通过 REST API、事件流和消息代理的组合相互通信，并根据业务功能进行隔离和组织，服务之间的分隔线称为有界上下文。</p><p>由于服务之间不存在相互依赖关系，因此您可以更轻松地更新代码，添加新特性或功能，而无需触及整个应用程序。每个团队都可以选择适合自身需求和专长的技术栈，构建团队负责的组件。这些组件可以相互独立地扩展，从而减少了因单一功能可能面临过多负载而不得不扩展整个应用程序所带来的浪费和成本。</p><p>无论你在哪里看到微服务的扩展，通常都涉及水平扩展。水平扩展是指通过添加更多的资源实例来进行扩展，也被称为「向外扩展」。有了微服务，单个服务可以单独部署和扩展。如果操作得当，微服务所需的基础架构会更少，因为它们可以只对需要的组件进行精确扩展，而不是像单体应用程序那样对整个应用程序进行扩展。</p><p>调用应用程序接口通常是建立特定服务状态的有效方法。然而，这并不是一种特别有效的了解最新进展的方式。此时，事件流可以帮助广播状态变化，从而通过引入消息代理帮助扩展微服务。</p><h4 id="121-单体应用程序-vs-soa-vs-微服务"><a class="markdownIt-Anchor" href="#121-单体应用程序-vs-soa-vs-微服务"></a> 1.2.1. 单体应用程序 VS SOA VS 微服务</h4><p>单体应用程序的所有或大部分功能都在一个进程中完成。应用程序由内部层或库来管理。这些层可用于安全、报告、分析、用户界面或数据访问。各层之间紧密相连，相互依赖。这正是单体设计的优势所在；因为一切都在同一个代码库中，所以简单、功能和特性之间的交叉较少。</p><p>然而，随着时间的推移，大多数产品都在不断发展，范围也在不断扩大，设计变得越来越复杂，修改起来也越来越困难。这也成为适应新技术的障碍，因为这意味着要重新编写整个应用程序。</p><p>Windows 窗体应用程序是单体设计的一个典型例子。在这里，我们将用户界面、业务逻辑和数据访问全部嵌入到一个代码库中，从而构成了整个应用程序。只有数据库不在其中。</p><p>面向服务架构（SOA）是以服务提供者和消费者的方式设计和构建的。所提供的服务作为一个离散的功能单元，无缝集成，易于重复使用。每个 SOA 服务都由三个部分组成。</p><ol><li>接口（interface）定义了服务提供商如何执行服务消费者的请求。</li><li>合约（contract）定义了服务提供商和服务消费者应如何交互。</li><li>实现（implementation）则是服务代码。</li></ol><p>拥有这三个独立组件的好处是，它们有助于提高可靠性，并由于服务之间的固定合约而支持并行开发。</p><p>然而，由于这些期望和要求，SOA 设计可能会变得复杂，阻碍快速应用开发。而且，SOA 设计是一项昂贵的投资，因此通常只适合那些能够投入所需资源和专业知识的企业团队。SOA 是一个企业范围的概念。银行系统就是一个例子。它使现有的应用程序能够通过松散耦合的接口进行公开，每个接口都与业务功能相对应，从而使扩展企业一部分的应用程序能够在其他应用程序中重复使用功能。银行的每个接口都提供服务，以完成其职责。</p><p>与 SOA 一样，微服务架构由松散耦合、可重用和专用的组件组成，这些组件通常彼此独立工作。即使是微服务中的数据也不会与其他服务共享，这有助于您独立扩展单个微服务，而独立也意味着您可以自由选择底层技术。这种架构的好处是易于开发，可以将单个工作单元定义为一项服务。由于每个服务都有指定的职责，因此可以灵活地添加新技术。</p><p>不过，虽然使用微服务有其令人信服的理由，但也存在一些相关的问题。首先是安全问题。现在有这么多不同的服务独立托管，每个服务都需要有自己的安全模式。例如，一个简单的要求，如传输层安全（或 TLS），以确保网络通信的安全。其次，调试和隔离问题也会变得更加困难，因为每个服务都是独立运行的，这意味着你可能会发现找到根本原因很有难度。</p><p>微服务架构是一个应用范围概念。例如，电子商务应用程序可以有独立的微服务来处理订单、安全和分析。微服务设计可将单个应用程序的内部结构分割成小块，这些小块可独立更改、扩展和管理。但是，微服务并没有定义应用程序之间的对话方式。</p><h4 id="122-微服务模式"><a class="markdownIt-Anchor" href="#122-微服务模式"></a> 1.2.2. 微服务模式</h4><p>微服务有许多可用的模式，可以应对一些更常见的问题和机遇。例如，单页面应用程序（或 SPA）模式、后端换前端（或 BFF）模式、Strangler 模式和服务发现模式。</p><ul><li><p>SPA 模式：<br>随着功能更强大的浏览器、速度更快的网络和客户端语言的融合，许多网络界面开始将所有功能整合到单页应用程序中。用户通过一个界面进入，不会重新加载登陆页面，也不会脱离最初的体验。<br>这些应用程序结合使用 HTML、CSS 和 JavaScript，通过动态服务调用后端基于 REST 的服务来响应用户输入，更新屏幕的部分内容，而不是重定向到一个全新的页面。<br>这种应用架构通常简化了前端体验，但后端服务需要承担更多责任。</p></li><li><p>BFF 模式：<br>虽然单页面应用程序能很好地满足单渠道用户体验的需求，但它在不同渠道（如移动和网络）的用户体验方面效果不佳。BFF 模式在用户体验和体验所调用的资源之间插入了一个层。这种设计可以在不同渠道之间实现定制的用户体验。<br>例如，在台式机上使用的应用程序与在移动设备上使用的应用程序在屏幕尺寸、显示效果和性能限制方面都有所不同。BFF 模式允许开发人员为每个用户界面创建和支持一种后端类型，并使用该界面的最佳选项，而不是试图支持一种通用后端，这种后端适用于任何界面，但可能会对前端性能产生负面影响。<br>假设用户可以通过移动应用程序或桌面上的网络应用程序访问应用程序。在应用 BFF 模式时，您需要开发一个专门用于移动体验的后端和另一个用于网络体验的后端。每个后端都知道如何调用正确的服务和协调代码，以优化所请求的渠道体验。<br>移动应用程序可能会显示更有限的数据子集，屏幕尺寸也会与网络体验不同。每个后端都是一个微服务。您可以应用微服务架构，将单体后端分离成不同的服务，执行各自特定的必要任务，而不是让单体应用程序先检查需要哪个通道，然后再包含所有逻辑，为该通道准备用户体验。</p></li><li><p>Strangler 模式：<br>有助于分阶段管理单体应用程序的重构。该模式的隐喻名称来源于花园中藤蔓缠绕树木的现象。试想一下，一个网络应用程序是通过单个 URL 构建的，这些 URL 的功能映射到业务域的不同方面。<br>利用 Strangler 模式，您可以使用网络应用程序的结构，将应用程序拆分成多个功能域，并一次针对一个域使用基于微服务的新实现来取代这些域。这两个方面形成了独立的应用程序，它们并排存在于同一个 URL 空间中。随着时间的推移，新重构的应用会取代原来的应用，直到最后可以关闭单体应用。<br>Strangler 模式包括以下步骤：</p><ol><li>转换。这将在云平台或现有环境中创建一个并行的新网站。</li><li>共存。这将使现有网站在指定时间内正常运行。它会逐步从当前位置重定向到新网站，以获得新实施的功能。</li><li>消除。这将删除现有网站上过时的功能，或在从原网站重定向流量时停止维护该功能。</li></ol></li><li><p>服务发现模式：<br>可帮助应用程序和服务相互发现。之所以需要这种模式，是因为在微服务架构中，服务实例会因扩展、升级、服务故障甚至服务终止而发生动态变化。负载平衡器也可以使用这种模式进行健康检查，并在服务失败时重新平衡流量。其他模式包括实体和聚合模式，这种模式可用于电子商务网站，在该网站上，订单将是由买方分组的产品的聚合。</p></li><li><p>适配器模式：<br>就像你去另一个国家旅行时想到插头适配器一样。适配器模式的目的是帮助转换原本不兼容的对象之间的关系。例如，如果您集成了第三方应用程序接口。</p></li></ul><h4 id="123-微服务反模式"><a class="markdownIt-Anchor" href="#123-微服务反模式"></a> 1.2.3. 微服务反模式</h4><p>虽然有很多模式可以很好地开发微服务，但同样也有很多模式会让开发团队很快陷入困境。以下是开发微服务时的一些禁忌：</p><ol><li><p><strong>不要构建微服务。</strong><br>微服务的第一条规则是不要从微服务开始。当您确定单体应用程序的复杂性会对应用程序的开发和维护产生负面影响时，请考虑将该应用程序重构为更小的服务。<br>当应用程序变得过于庞大，无法轻松更新和维护时，这些微服务将成为分解复杂性的理想选择，使应用程序更易于管理。<br>然而，在你感受到这种痛苦之前，你甚至还没有一个需要重构的单体。</p></li><li><p><strong>不重视自动化。</strong><br>如果您有一个单体应用程序，您只需要部署一个软件。一旦转向微服务架构，您将拥有不止一个应用程序，每个应用程序都有不同的代码、测试和部署周期。<br>试图构建微服务时，必须同时具备以下两个条件：</p><ul><li>适当的自动化部署和监控，或……</li><li>管理云服务，以支持您现在庞大的异构基础设施。</li></ul><p>会带来很多不必要的麻烦。<br>因此，在构建微服务时，一定要使用 DevOps 或云服务。</p></li><li><p><strong>不要构建纳米服务。</strong><br>如果过分追求微服务中的 <strong>微</strong>，就很容易发现自己正在构建纳米服务！其复杂性将超过微服务架构的总体收益。<br>倾向于创建大型服务，并在适当的时候创建小型服务：</p><ul><li>部署更改变得困难。</li><li>通用数据模型变得过于复杂。</li><li>加载和扩展要求不再同步并影响应用程序性能。</li></ul></li><li><p><strong>不要变成 SOA。</strong><br>微服务和面向服务架构（SOA）这两个概念经常被混为一谈，因为在最基本的层面上，两者都是构建可被其他应用程序使用的可重用的单个组件。<br>然而，微服务是细粒度的，每个微服务都有独立的数据存储，也就是有边界的上下文。<br>微服务项目如果演变成 SOA 项目，很可能会不堪重负。</p></li><li><p><strong>不要为每种服务建立网关。</strong><br>您应该使用 API 网关，而不是在每个服务中实施终端用户身份验证、节流、协调、转换、路由和分析。<br>API 网关是一种 API 管理工具，位于客户端和后端服务集合之间。<br>这将成为上述非功能性问题的核心，并避免在每个服务中重新设计这些问题。</p></li></ol><p>微服务的目的是解决三个最常见的挑战，即通过提供细粒度服务的业务功能来提升客户体验、灵活应对新需求和降低成本。</p><p>但是，在这样做的同时，你应该避免上述反模式的陷阱，以免微服务对你的开发、交付和管理要求造成困扰。</p><h1 id="2-web-api-要素rest-api-和-graphql"><a class="markdownIt-Anchor" href="#2-web-api-要素rest-api-和-graphql"></a> 2. Web API 要素：REST API 和 GraphQL</h1><h2 id="21-rest"><a class="markdownIt-Anchor" href="#21-rest"></a> 2.1. REST</h2><p>REST 是「表征状态传输」（Representational State Transfer）的缩写。REST API 为集成应用程序提供了一种灵活、轻量级的方式，并已成为微服务架构中连接组件的最常用方法。它是一种定义应用程序如何在网络中相互通信的架构风格。</p><p>应用程序接口（API）需具有三个特征才可将其归类为 RESTful（REST 式的）：</p><ol><li>它通过 HTTP 管理所有请求。</li><li>它提供无状态的客户端 - 服务器通信。</li><li>它由组件之间的统一接口组成。</li></ol><p>REST API 通过 HTTP 请求进行通信，以执行标准功能，如在资源中创建、读取、更新和删除记录（也称为 CRUD）。例如，REST API 使用 <code>POST</code> 请求创建记录，使用 <code>GET</code> 请求检索记录，使用 <code>PUT</code> 请求更新记录，使用 <code>DELETE</code> 请求删除记录。</p><p>REST 应用程序接口是无状态的，这意味着每个请求都包含处理该请求所需的全部信息。REST 的创始人罗伊・菲尔丁（Roy Fielding）在他的论文中说道：「<em>从客户端到服务器的每个请求都必须包含理解请求所需的全部信息，而不能利用服务器上的任何存储上下文。因此，会话状态完全保存在客户端。</em>」REST API 的这种无状态特性也使其具有可扩展性。</p><p>RESTful API 的主要优点是接口统一，无论请求来自何处。REST API 应确保同一块数据（如产品 ID）只属于一个统一资源标识符（或 URI）。资源应包含客户可能需要的所有信息。例如，客户可能需要产品的名称和价格。</p><p>让我们来看一个 REST 的例子：<a href="http://CEX.IO">CEX.IO</a> 是一个加密货币交易所。它通过 REST API 为开发者提供比特币、其他加密货币的价格和市场数据。CEX 在其开发人员部分记录了所有 API 调用，包括请求和响应参数的详细信息，全部采用简单的 JSON 格式，以及 JavaScript、Python、C# 和 Java 示例请求和代码片段。例如，您可以通过其公共 API 请求货币对的最后价格。</p><h4 id="211-创建-rest-api"><a class="markdownIt-Anchor" href="#211-创建-rest-api"></a> 2.1.1. 创建 REST API</h4><p>Python 是一种编程语言，能让您更快速地工作，更有效地集成系统。Python 可用于许多应用领域。它借助 Flask 等框架支持网络开发。借助数学、科学和工程领域的 SciPy 等库，Python 被广泛应用于科学和数值计算领域。Python 在人工智能和机器学习领域也很受欢迎。Flask 被归类为微型网络框架，因为它不需要特定的工具或库。它的构建考虑到了可扩展性和简单性。与其他框架相比，Flask 应用程序以轻量级著称。由于 Flask 对使用什么数据库或模板引擎没有意见，因此它是 RESTful API 的不错选择。</p><pre><code class="language-python"># hello.pyfrom flask import Flaskapp = Flask(__name__)@app.route('/')def hello_world():    return 'Hello World!'</code></pre><p>使用以下命令：</p><pre><code class="language-bash">flask --app hello run</code></pre><p>从浏览器中打开 <code>127.0.0.1:5000</code> 便能看到响应。</p><pre><code class="language-python"># products.pyfrom flask import Flask, jsonify, requestimport jsonapp = Flask(__name__)products = [    {'id': 143, 'name': 'Notebook', 'price': 5.49},    {'id': 144, 'name': 'Black Marker', 'price': 1.99}]</code></pre><p>现在，您将创建一个名为 <code>products.py</code> 的新 Python 文件，该文件将为产品微服务提供所有端点。首先定义导入并创建默认产品列表。我们不会使用任何数据库来持久化这些产品，因此每次重启 API 时，产品列表都是一样的。接下来，定义 <code>GET</code> 方法来检索所有产品。该方法隐式返回 <code>200</code>，在 HTTP 中表示 <strong>0K</strong>。</p><h4 id="212-使用-curl-和-postman-发送应用程序接口请求"><a class="markdownIt-Anchor" href="#212-使用-curl-和-postman-发送应用程序接口请求"></a> 2.1.2. 使用 cURL 和 Postman 发送应用程序接口请求</h4><p>与服务器之间的数据传输需要支持必要网络协议的工具。Linux 上有多种用于此目的的工具，其中最流行的是 curl。curl 是 Client URL 的缩写，是一种命令行工具，可以通过各种网络协议传输数据。它开发于 1998 年，通过指定相关的 URL 和需要发送或接收的数据，可用于与网络或应用程序服务器进行通信。你可以运行一个简单的 curl 命令（如本例所示），然后查看输出结果：</p><pre><code class="language-bash">curl https://www.example.com/</code></pre><p>curl 最常见的用例包括从互联网下载文件、端点测试、调试和错误记录。curl 支持的一些常见协议包括 HTTP、HTTPS、FTP 和 IMAP。</p><p>如果运行这个示例的 curl 命令：</p><pre><code class="language-bash">curl -X 'GET' 'http://127.0.0.1:5000/products' -H 'accept: application/json'</code></pre><p>你将得到如图所示的输出结果：</p><pre><code class="language-plaintext">[    {"id":143,"name":"Notebook","price":5.49},    {"id":144,"name":"Black Marker","price":1.99}]</code></pre><p>curl 接受多种选项，这使它成为一个用途极为广泛的命令。选项以一个或两个破折号开头，如果不需要附加值，单破折号选项可以写在一起。那么，让我们来分解一下命令和输出：连字符 <code>X</code> 表示明确指定 HTTP 函数，在本例中就是 <code>GET</code>。然后，我们指定要评估的 URL。连字符 <code>H</code> 允许您定义标题，在本例中就是告诉网络服务器我们要使用 JSON。我们的输出是以 JSON 表示的产品微服务返回的产品列表。</p><p>Postman 是一个用于构建和使用 API 的 API 平台，它基于一系列用户友好的强大工具，使开发人员能够轻松地创建、测试、共享和记录 API。Postman 简化了 API 生命周期的每个步骤，允许协调多个请求，这些请求可以在多次重复或迭代中执行，并帮助您简化协作，从而更快地创建更好的 API。由于其简单易用，它是最流行、最方便的工具之一，可用于测试支持多种协议的各种 API（例如 <code>GET</code>、<code>POST</code>、<code>PUT</code> 和 <code>PATCH</code> 等 HTTP 请求），然后将 API 转换为 JavaScript 和 Python 等语言的代码。</p><p>WhatsApp 业务平台云 API 就是一个广受欢迎的例子，它利用 Postman 创建了一种简化的、开发人员友好的体验。有了 Postman，使用自动化和预先填入的数据，入职时间缩短到几分钟，而其他需要手动设置的方法则无法做到这一点。从注册 WhatsApp 商务平台到测试电话号码和建立信息通话，开发人员只需几分钟就能完成。</p><p>您可以将 Postman 下载到电脑，也可以使用在线版本。</p><h4 id="213-记录和测试-rest-api-swagger"><a class="markdownIt-Anchor" href="#213-记录和测试-rest-api-swagger"></a> 2.1.3. 记录和测试 REST API Swagger</h4><p>API 指定了一个接口，并连接不同的系统，为它们提供一致的通信。API 文档就像一本参考手册，包含有效使用和集成系统的说明。Swagger 通过运行 OpenAPI 规范来确保您符合指导原则，从而节省了编写 API 文档的时间。</p><p>Swagger 允许您描述 API 的结构，以便机器可以读取它们。有了 API 的结构，Swagger 就能自动构建引人入胜的交互式 API 文档。该结构定义在符合 OpenAPl 规范的 JSON 或 YAML 文件中。</p><p>最初，API 并不是为了自我服务消费。它们由数据驱动，解决了连接和通信方面的一些特殊用例。而 OpenAPl 规范为 RESTful APIs 定义了一个标准的、与语言无关的接口 -- 该规范与语言无关，可由人类和机器读取。此外，它还允许人们和计算机发现并了解服务的功能，而无需访问源代码、额外的文档或检查网络流量。它定义了 API 支持的所有操作、所需参数和预期返回值，以及所需的 API 身份验证。它甚至还定义了服务条款、联系信息和暴露的 API 的许可证信息等内容。</p><p>Flask 支持将 Python 函数作为 API 暴露。Flask Swagger UI 允许您描述和可视化 REST API，从而改进了 Flask 的功能。要在应用程序中引入 Swagger UI，您需要使用 flask 蓝图 <code>flask-swagger-ui</code>：</p><pre><code class="language-bash">pip install flask-swagger-ui</code></pre><pre><code class="language-python">from flask import Flask, jsonify, requestimport jsonfrom flask_swagger_ui import get_swaggerui_blueprintswaggerui_blueprint = get_swaggerui_blueprint(    '/products/docs',    'https://{HOSTNAME}/swagger.json',    config={'app_name': "Products microservice"})app.register_blueprint(swaggerui_blueprint)</code></pre><p><code>Swagger.json</code> 以 JSON 文件的形式保存了 API 的定义和特征。您需要将此文件与您的 API 一起公开。因此，您需要一个路由来提供静态 <code>Swagger.json</code> 文件。</p><pre><code class="language-python">@app.route('/swagger.json')def static_file():    return app.send_static_file('swagger.json')</code></pre><p>您现在有了 API 定义和 Swagger。您可以使用 UI 测试您的 API，这是使用 Swagger 的主要好处。此外，它还能让消费者获得有关您的 API、支持的功能、请求和响应的更多详细信息。它还显示产品信息部分的内容。它显示了唯一可用的方法，即检索所有产品的 <code>GET</code> 方法。然后，您可以执行该端点并查看结果，在本例中，结果就是产品列表。</p><h2 id="22-api-网关"><a class="markdownIt-Anchor" href="#22-api-网关"></a> 2.2. API 网关</h2><p>API 网关是一种 API 管理工具，位于客户端和后台服务集合之间。它汇集了满足客户需求所需的各种服务，并返回相应的结果。为什么要使用 API 网关呢？因为 API 网关可以帮助您保护 API 免受恶意使用或过度使用。因此，您可以使用具有速率限制的验证服务。使用分析和监控服务还有助于了解 API 的使用情况。此外，您还可以使用计费系统将 API 货币化。网关还能为您的各种微服务提供单一接触点，并对请求作出单一响应。最后，您可以无缝添加或移除 API，而客户对后端运行的服务一无所知。</p><p>设您的网店采用的是微服务架构，因此其中的一些服务将包括：产品信息服务，用于共享产品的基本信息（如白痴名称和价格）；库存服务，用于显示现有库存；订单服务，用于让客户下订单购买产品；以及验证服务，用于验证平台上的用户。那么，客户端如何访问微服务呢？当您需要与多个应用程序接口交互时，这是一个问题。API 网关可以消除这种复杂性，并允许您：更改主机及其位置、增加或减少服务实例的数量，以及用新服务替换现有服务（例如订购服务）。客户对服务的访问不受影响。</p><p>使用 API 网关的好处如下：</p><ul><li>它能使客户端免受应用程序如何分割成微服务的影响。换句话说，它将调用多个服务的逻辑从客户端转移到网关，从而简化了客户端。</li><li>它还能为每个客户端提供最佳的应用程序接口，无论客户端是谁。</li><li>它减少了请求或往返的次数。</li></ul><p>例如，API Gateway 可以让客户只需往返一次，就能从多个服务中检索数据。无论您的微服务如何进行内部通信，API 网关都将提供与外界通信的标准协议。虽然 API 网关有很多好处，但它也有一些缺点：</p><ul><li>它是另一个需要开发和维护的组件。</li><li>如果设计不慎，它还可能成为应用程序的单点故障。</li><li>由于在执行应用程序时增加了网络步骤，网关会增加响应时间。</li></ul><p>市场上有很多 API 网关产品。您可以选择托管或开源方案。来自 IBM 的业界领先的高安全性应用网关 IBM DataPower Gateway 可根据您的需求提供两种产品：Apigee 或 Cloud Endpoints。</p><p>微软 Azure 和亚马逊 AWS 也在其平台上提供网关。虽然这些都是托管产品，但在开放源代码领域，一些著名的产品有：</p><ul><li>最受欢迎的 Kong</li><li>Apache APISIX</li><li>Tyk（也有托管版本）</li><li>Gloo（也有企业版本）</li></ul><h1 id="3-无服务器概述"><a class="markdownIt-Anchor" href="#3-无服务器概述"></a> 3. 无服务器概述</h1><h2 id="31-无服务计算"><a class="markdownIt-Anchor" href="#31-无服务计算"></a> 3.1. 无服务计算</h2><p>云原生计算基金会（或 CNCF）将无服务器定义为「<em><strong>构建和运行无需服务器管理的应用程序的概念</strong></em>」。它描述了一种更细粒度的部署模式，在这种模式下，捆绑为一个或多个功能的应用程序被上传到一个平台，然后根据当下所需的确切需求来执行、扩展和计费。换句话说，无服务器计算将基础设施管理的责任卸载给了云提供商，使开发人员能够专注于应用程序的业务逻辑。</p><p>将无服务器计算视为功能即服务（或 FaaS）平台和后台即服务（或 BaaS）服务的组合。FaaS 平台用于运行功能。BaaS 代表后端云服务，如云数据库、对象存储服务和消息队列。现在，IT 计算的历史显示了从传统计算到无服务器计算的渐进趋势，从而加快了部署速度、缩短了生命周期并提高了生产率。</p><p>这一演变趋势有几个里程碑：</p><ol><li>传统计算使用物理机，但受制于前期投资、容量规划等因素。物理机的部署需要数周或数月的时间，使用寿命长达数年。</li><li>在云计算中采用虚拟化技术，可实现更快的配置、高可扩展性和可用性。虚拟化有助于创建多个虚拟机（VM）或容器。虚拟机管理系统的部署只需几分钟，寿命为数天或数周。</li><li>基于操作系统虚拟化的容器只需几秒钟即可部署，并可存活几分钟或几小时。</li><li>而无服务器应用程序只需要无服务器架构的核心代码。无服务器功能的部署只需几毫秒，生命周期仅几秒钟。</li></ol><p>无服务器计算是标准云计算的进步，它抽象了基础设施和软件环境。它是一种架构风格，代码在云平台上运行，由云提供商管理硬件和软件设置、安全性、可扩展性等。客户只需为使用付费，而无需为 CPU 空闲时间付费。而开发人员只需关注函数形式的应用代码。</p><p>无服务器计算具有以下特点：</p><ul><li>它是无主机的，这意味着开发人员无需采购、管理和维护服务器。</li><li>它是弹性的，因为自动伸缩是无服务器的即时和固有特性。</li><li>它提供自动负载均衡，可在多个后端系统之间分配输入流量。</li><li>它是无状态的，因此性能更快，可扩展性更高。</li><li>它是事件驱动的，这意味着只有当事件发生时才会触发功能。</li><li>它提供高可用性，无需额外的工作或成本。</li><li>而且，它是基于使用量的细粒度计费。</li></ul><p>那么，无服务器世界中的功能是如何工作的呢？以创建 Docker 或 Kubernetes 容器所需的步骤为例。开发人员使用云提供商支持的语言（如 Python、Java、Node.js 或 Go）编写代码，创建一个函数。然后，开发人员将函数上传到云。然后，定义触发函数的事件，如用户点击。一旦事件发生，触发器就会被调用，云提供商就会运行函数，从而生成容器对象。</p><p>让开发人员花更多时间创建高质量和优化的应用程序对企业大有裨益。开发人员可以使用任何流行的编程语言构建功能，通过添加其他功能扩展应用程序的功能，执行更好的测试（因为功能一次只执行一项任务），优化应用程序和功能，并改善用户体验。</p><p>为了实现零运行成本的目标，云提供商负责日常基础设施的管理和维护工作，如最大限度地提高计算机内存和网络利用率，同时最大限度地降低成本，提供服务器管理（包括操作系统更新和安全补丁），启用自动扩展，维护高可用性，实施安全，配置高性能（或低延迟），以及设置监控和日志。</p><h4 id="311-无服务器责任模型"><a class="markdownIt-Anchor" href="#311-无服务器责任模型"></a> 3.1.1. 无服务器责任模型</h4><p><img src="/posts/52000/1.webp" alt="1.png" loading="lazy"></p><p>在比较图中所示的不同云服务模式时，让我们来看看您与云提供商的责任，尤其是无服务器服务模式。我们从最左侧的堆栈（传统堆栈）开始，完全由您来管理。在 IaaS 模式中，您负责管理从操作系统到顶层的各层，而云提供商负责管理较低的四层。在 PaaS 模式中，您管理前两层，即应用层和数据层，而云提供商管理其余各层。在无服务器模式中，用户只管理应用程序层，而云提供商管理其余各层。而在 SaaS 模式中，云提供商负责管理整个堆栈。</p><h4 id="312-无服务的利与弊"><a class="markdownIt-Anchor" href="#312-无服务的利与弊"></a> 3.1.2. 无服务的利与弊</h4><p>让我们来了解一下传统计算所面临的挑战，以及无服务器计算的出现是如何克服这些挑战的。</p><p>在传统计算中，开发和运营团队需要建立和维护自己的基础设施。这些过程耗费大量时间，非常复杂，而且需要资金投入。然而，随着云、容器和无服务器计算的出现，开发团队可以专注于编写高质量代码，并在毫秒级的时间内构建和运行应用程序，而无需担心基础设施、可扩展性和容错问题。无服务器计算也面临着一些挑战，包括供应商锁定、第三方依赖性和网络。</p><p>也让我们来看看无服务器计算的优势和限制，然后将其与容器和传统计算进行比较。</p><p>在无服务器计算中，云提供商承担了大部分工作，这带来了许多好处。由于云提供商负责管理基础设施，因此无需进行基础设施设置和维护，从而降低了成本。云提供商可确保可靠性，从而实现高可用性和容错性。开发人员受益匪浅，因为他们可以专注于应用程序，做自己最喜欢的事情。如果没有无服务器，应用程序的所有部分都会持续运行，从而造成资源浪费。</p><p>无服务器功能允许您对应用程序进行配置，使其仅在需要时运行某些部分。例如，应用程序的前端必须持续运行，以保持用户登录。而身份验证服务只需偶尔调用，因此可以节省资源和成本。函数的运行时间以毫秒为单位，而容器或虚拟机（VM）的运行时间则分别以秒和分钟为单位。</p><p>许多云提供商都内置了代码编辑器，称为集成开发环境（IDE），可加快开发、部署和更新。云服务提供商按请求付费，不收取任何闲置资源的费用。您可以使用任何流行的编程语言进行开发。在身份验证、数据库和其他后端服务方面有大量第三方支持。由于开发人员只专注于开发，因此企业可以专注于业务，以比竞争对手更快的速度发布产品。</p><p>无服务器环境允许更多的创新和实验，即使会有失败。由于没有基础设施需要管理，绿色计算也成为一种必然的可能。</p><p>然而，无服务器计算并非最适合每种情况，因为它确实存在一些限制：</p><ul><li>许多企业在处理突发性工作负载时都能节省大量成本，但对于以长期运行流程为特征的工作负载，按使用付费模式带来的好处就会减少。对于这类应用，传统环境可能更具成本效益。</li><li>对云提供商技术或环境的依赖会导致供应商锁定风险。</li><li>如果隔了很长时间才收到请求，应用程序通常必须重新启动所有进程，即所谓的冷启动。这会增加功能运行时间。对于银行、医疗保健或边缘相关应用等时间关键型应用而言，无服务器延迟是不可接受的。</li><li>由于从端点到源代码的攻击面发生了变化，加上提供商的安全实施存在局限性，安全问题日益突出。</li><li>在任何分布式系统中，监控和调试都很复杂。</li><li>由于无法在本地系统中模仿后端即服务（或 BaaS）环境，因此测试完整功能和调试应用程序问题具有挑战性。</li><li>语言支持取决于云提供商。并非所有云提供商都支持所有编程语言，因此您只能使用云提供商支持的语言。</li><li>没有服务器可优化利用率或性能，因为您无法控制服务器。</li><li>没有状态持久性。例如，在下一次调用同一函数时，将无法使用之前的运行状态。由于本地缓存只能持续几个小时，因此最好使用低延迟的外部缓存，如 Redis 或 Memcached。</li></ul><h4 id="313-无服务器-vs-容器"><a class="markdownIt-Anchor" href="#313-无服务器-vs-容器"></a> 3.1.3. 无服务器 VS 容器</h4><p>无服务器和容器能一起工作吗？当然可以！无服务器和容器并不相互排斥。它们在混合解决方案中配合得最好。如果你在无服务器或容器之间难以取舍，请遵循标准的行业建议：「首先构建无服务器。如果需要，再转向容器」。</p><p>让我们比较一下无服务器计算和容器化，从无服务器的优点和容器的缺点开始：</p><ul><li>无服务器计算更具成本效益，因为您只需为使用的内容付费。</li><li>对于无服务器计算，可扩展性完全由云提供商负责。</li><li>云提供商管理所有基础设施。部署时间只需几毫秒，而不是几秒钟。</li><li>就上市速度而言，由于开发速度快，企业可以专注于核心业务，而不必担心基础设施。</li></ul><p>现在，让我们来看看容器的优点和无服务器的缺点：</p><ul><li>有了容器，在本地环境或云中进行测试就更容易了。</li><li>移植容器更容易，因为它们不受操作系统、语言和提供商的影响。</li><li>容器的延迟非常低，因此即使是时间紧迫的工作负载也适用。</li><li>容器也非常适合长期运行的应用程序，因为完成批处理作业没有时间限制。</li><li>使用容器，你可以同时配置应用程序和资源。</li><li>在语言支持方面，容器化支持任何语言。</li></ul><p>让我们比较一下无服务器计算和传统计算，从无服务器计算的优点和传统计算的缺点开始：</p><ul><li>无服务器架构是一种云计算模式，开发人员专注于编写高质量代码。</li><li>无服务器计算更具成本效益，因为你只需为使用的内容付费。</li><li>可扩展性完全由云提供商负责。</li><li>库和集成可在应用程序中使用。</li></ul><p>最后，让我们来看看传统计算的优点和无服务器计算的缺点：</p><ul><li>在传统计算中，数据由您控制。</li><li>在网络方面，您可以通过常规的互联网协议（或 IP）地址访问代码，而无需设置专用的应用程序编程接口（或 API）。</li><li>只需在组织的网络边界内实施安全防护。</li><li>由于整个设置都由您来管理，因此很少出现供应商锁定的情况。</li></ul><h4 id="314-无服务器框架"><a class="markdownIt-Anchor" href="#314-无服务器框架"></a> 3.1.4. 无服务器框架</h4><p>无服务器框架（Serverless Framework）是一个使用 Node.js 编写的免费开源 Web 框架。它最初设计用于安全、快速地配置亚马逊网络服务或 AWS Lambda 函数、事件和基础设施资源。但它并不局限于 AWS。其他支持的提供商包括微软 Azure、谷歌云平台和 Apache OpenWhisk。</p><p>无服务器框架是一个命令行界面或 CLI，提供开箱即用的结构、自动化和最佳实践，让您可以专注于构建复杂的事件驱动型无服务器架构，包括函数、事件、资源和服务。</p><ul><li>功能只是部署在云中的代码，通常是为执行单个任务而编写的。每个功能都是一个独立的执行和部署单元，就像一个微服务。</li><li>任务可以是将用户保存到数据库，也可以是在指定时间执行任务。</li><li>功能由事件触发，而事件则来自其他资源，例如：API 网关、URL 上的 HTTP 请求或 S3 存储桶中上传的新文件。</li><li>资源是功能使用的基础设施组件，例如云提供商作为服务提供给您的数据库，或用于存储文件的 S3 存储桶。</li><li>服务是框架的组织单位。您可以将其视为一个项目文件，尽管您可以为一个应用程序提供多个服务。服务通过 <code>serverless.yml</code> 文件进行配置，您可以在其中定义要部署的功能、事件和资源。<br>使用框架 CLL 部署时，配置文件中的所有内容都会一次性部署。<code>serverless.yml</code> 文件控制着服务中的所有内容。该文件有专门的章节用于指定函数、事件和资源。<pre><code class="language-yaml">service: productsfunctions:  productsCreate:    events:      - httpApi: 'POST /products/create'  productsDelete:    events:      - httpApi: 'DELETE /products/delete'resources:</code></pre></li></ul><p>让我们在 AWS 上使用无服务器框架构建并部署一个 <code>Hello World</code> 应用程序。</p><p>首先，您需要 serverless CLI，可以使用 npm 全局安装：</p><pre><code class="language-bash">npm install -g serverless</code></pre><p>运行 <code>serverless</code> 命令：</p><pre><code class="language-bash">serverless</code></pre><p>使用 Python 创建第一个 AWS HTTP API。该命令将带您完成一个向导，部署完成后，将为您提供一个 URL。如果在浏览器中打开，就会看到如图所示的结果。</p><p>接着更改函数代码，以在请求时返回 <code>Hello World</code>：</p><pre><code class="language-python">def hello(event, context):    body = 'Hello World!'    response = {'statusCode': 200, 'body': body}    return response</code></pre><p>然后就只需重新部署并再次测试即可。</p><h4 id="315-无服务器参考架构和用例"><a class="markdownIt-Anchor" href="#315-无服务器参考架构和用例"></a> 3.1.5. 无服务器参考架构和用例</h4><p>让我们来看一个实现简单 TODO 应用程序的 Web 应用程序，其中注册用户可以创建、读取、更新和删除项目。</p><p>Web 应用程序参考架构是一个通用的、事件驱动的后端，使用 AWS Lambda 和 Amazon API Gateway 实现其业务逻辑。它还使用 Amazon DynamoDB 作为数据库，并使用 Amazon Cognito 进行用户管理。应用程序中的所有静态内容都使用 AWS Amplify Console 托管。</p><p>基本上，Web 应用程序包括 3 个不同的组件。前端应用程序包含使用创建 React 应用程序生成的所有静态内容，而创建 React 应用程序则借助 HTML 文件、用于样式设计的 CSS、在客户端运行的 JavaScript 以及图像来工作。所有这些对象都托管在 AWS Amplify Console 上。当用户连接到网站时，所需的资源就会下载到他们的浏览器并开始运行。当应用程序需要与后端通信时，就会向后端发出 REST API 调用。</p><p>后端应用程序是实现实际业务逻辑的地方。逻辑托管在 Lambda 函数中，前端通过 API Gateway 使用 REST API 进行访问。数据随后存储在 DynamoDB 中。TODO 应用程序将用户限制在自己的待办事项中。因此，用户必须经过注册和身份验证才能访问自己的待办事项。为此，您可以使用 Cognito 用户池，让用户注册应用程序并进行身份验证。</p><p>无服务器应用程序的一个常见用例是事件流。这些应用无需设置前期基础设施即可编写和部署。它们可以从发布者、订阅者主题或事件日志中触发，为您提供弹性、可扩展的事件管道，而无需维护复杂的集群。这些事件流管道可为分析系统提供动力，更新二级数据存储和缓存，或为监控系统提供信息。后处理的例子包括图像和视频处理，您可以针对不同的目标设备动态调整图像大小或更改视频转码。后期处理还可用于图像识别或人工智能目的，以检测护照照片上是否有阴影。</p><p>在构建应用程序时，您需要决定在应用程序中使用哪种语言。无服务器应用程序可以使用多种语言，从而防止团队被语言锁定，即不得不无限期地使用与传统软件相同的语言。通常，选择哪种语言来构建应用程序并不是最适合项目的，而是取决于可用资源。</p><h4 id="316-流行的无服务器平台"><a class="markdownIt-Anchor" href="#316-流行的无服务器平台"></a> 3.1.6. 流行的无服务器平台</h4><p>亚马逊网络服务（AWS）Lambda 是亚马逊提供的一种无服务器、事件驱动的计算服务。该服务可让您为任何应用程序或后端服务运行代码，而无需配置或管理服务器。它可以响应任何规模的执行请求，从每天十几个事件到每秒数十万个自动执行请求。</p><p>AWS 平台提供两百多种服务。您只需支付运行功能的费用以及在 Lambda 和其他 AWS 服务之间传输数据的费用。此外，它还可用于各种用例，例如文件处理、网络应用、物联网（IoT）和移动后端。其次，谷歌云功能具有简单直观的开发人员体验。只需编写代码，然后让谷歌云处理运行基础架构。它可以根据流量自动将所有基础架构管理抽象为零，并即时进行扩展和缩减。数据更新时，Google Firebase 会立即提醒开发人员。轻量级提取、转换和加载（ETL）功能等异步工作负载不需要单独的服务器。您可以直接部署与所选事件相关联的函数，然后执行该函数。</p><p>Azure 是一种无服务器解决方案，可让您编写更少的代码、维护更少的基础设施并节省成本。使用 C#、Java、JavaScript、PowerShell 或 Python 编写函数，或使用自定义处理程序来使用几乎任何其他语言。Microsoft Azure 具有出色的开发人员操作或 DevOps 功能，可为持续集成和交付提供简便的设置。这一功能也适用于 Azure 函数。</p><p>使用 Consumption 计划，您只需在函数运行时支付费用，而高级计划和应用程序服务计划则提供满足特殊需求的功能。例如，Azure Functions 有许多不同的用例：当文件上传或 blob 存储发生变化时运行代码，收集和处理来自物联网设备的数据，或在预先定义的定时间隔执行代码。</p><p>IBM 云函数允许您从事件或直接通过 REST API 触发操作，从而促进与其他服务的轻松集成。使用 IBM Cloud Functions，您只需为您使用的时间支付费用，甚至低至十分之一秒。</p><p>IBM 云功能的一部分是 IBM Watson 强大的认知服务。例如，检测图像或视频中出现的物体或人物。云功能可在多个 IBM 云区域内使用。它支持高可用性，以避免单点故障。客户数据（如操作代码）会在不同区域自动同步。在生产中调试无服务器应用程序可能很困难，因为无法访问运行代码的运行时环境和基础架构。为了访问环境，IBM 提供了 LogDNA 的日志分析和 IBM Cloud Monitoring 指标。</p><p>大多数平台都有特定的供应商。您还可以选择开源开发。Knative 就是这样一个选择。Knative 基于通过 Kubernetes 运行的容器，Kubernetes 是容器的协调框架。与其他无服务器平台相比，Knative 的优势在于它提供了一个基于 Kubernetes 开发的平台，从而避免了供应商锁定。您可以在任何支持 Kubernetes 的云中部署该平台，而无需做任何更改。这也使得它与平台无关。此外，它还允许您根据自己的需求制定推广策略，通过将流量逐步转移到无服务器组件的最新版本来实现。</p><h2 id="32-faas"><a class="markdownIt-Anchor" href="#32-faas"></a> 3.2. FaaS</h2><p>功能即服务或 FaaS 是一种云计算服务，可让您根据事件执行代码，而无需通常与构建和启动微服务应用程序相关的复杂基础设施。FaaS 具有以下特点：</p><ul><li>它是无服务器计算的一个子集。</li><li>它以多个函数的形式创建应用程序，其中一个函数是用任何编程语言编写的软件。</li><li>FaaS 既可以部署在混合云上，也可以部署在企业内部环境中。</li><li>它是无状态的，但可以使用外部缓存来维护状态。</li><li>函数以毫秒为单位执行，并行处理单个请求，因此具有瞬时可扩展性。</li><li>FaaS 按运行功能所需的时间计费，而不是按服务器实例大小计费。</li><li>使用 FaaS，您可以将服务器划分为可自动独立扩展的功能，这样您就不必管理基础设施，也就可以去专注于应用程序代码，从而缩短产品上市时间。</li><li>FaaS 模式的最大优势之一是成本。您只需在发生操作时支付费用。当操作完成时，一切都会停止 -- 没有代码运行，服务器不会闲置，也不会产生任何费用。</li><li>由于函数是无状态的、独立的小代码块，因此可以根据需要自动、独立、即时地扩展。如果需求下降，它们会自动缩减。</li><li>FaaS 本身具有高可用性，因为它分布在不同地区和可用区，部署时无需增加成本。</li></ul><p>无服务器堆栈由三个主要部分组成，即功能即服务（FaaS）、后台即服务（BaaS）和 API 网关。让我们来看看无服务器堆栈中的组件是如何工作的：</p><ol><li>事件请求来自不同的渠道，如 HTTP 请求、来自 GitHub 和 Docker Hub 等资源库的网络钩子以及计划作业。</li><li>这些请求会经过 API 网关，由该网关识别并转发给相应的功能。</li><li>然后，这些功能会处理这些请求，并进一步（如有必要）将它们导向后端服务（如文件和对象存储、块存储、通知服务等），以便进一步处理和 / 或存储。</li><li>然后通过 FaaS 组件和 API 网关将输出或响应发送回客户端。</li></ol><p>举个现实世界中的例子，您需要将个人资料图片上传到网站。网站可能还需要该图片的缩略图，以便在某些网页上显示。这是使用功能即服务的常见情况。用户选择一张个人照片。图片被上传到对象存储桶。该事件触发一个 IBM 云函数，该函数处理个人资料照片并创建缩略图。然后，该函数将缩略图存储在对象存储中，以便网站在需要时可以访问缩略图。</p><p>FaaS 函数应设计为响应事件时执行单个工作。因此，要限制代码范围、提高效率并减轻重量，以便函数能快速加载和执行。</p><p>FaaS 的价值在于功能的隔离。过多的函数会增加成本，并降低函数隔离的价值。使用过多的第三方库会减慢函数的初始化速度，使其难以扩展。</p><p>一些常见的托管 FaaS 提供商包括：</p><ul><li>亚马逊的 AWS Lambda</li><li>谷歌云功能</li><li>微软的 Azure 功能</li><li>IBM 的云功能</li><li>Red Hat 的 OpenShift 云功能</li><li>Netlify、Oracle 和 Twilio 等其他一些提供商</li></ul><p>如果不想依赖第三方管理平台，也有许多自我管理的 FaaS 可供选择。其中包括：</p><ul><li>Fission 是 Kubernetes 上的无服务器功能框架</li><li>Fn Project 是一个容器原生无服务器平台</li><li>Knative 是一个基于 Kubernetes 的平台，用于构建、部署和管理无服务器工作负载</li><li>OpenFaaS 允许您将任何 Linux 或 Windows 进程转化为函数</li></ul><h1 id="4-创建和部署微服务"><a class="markdownIt-Anchor" href="#4-创建和部署微服务"></a> 4. 创建和部署微服务</h1><p>在本地成功构建和测试微服务后，您需要部署微服务。如果选择自托管微服务，则需要进行详细调整，并认真应对许多非同小可的挑战。</p><p>首先，你需要特意配置和构建你的微服务，使它们为生产做好准备，包括必要的资产，如库依赖关系、资源、凭据等。然后将它们编译并构建成一个可执行的二进制文件，以便在托管环境中运行。接下来，您需要仔细选择运行微服务的基础设施，如网络服务器、操作系统、网络、数据库等等。您的团队需要从众多选项中谨慎选择。由于微服务的流量会发生波动，因此需要动态地扩大或缩小规模。例如，电子商务网站在节假日总是会出现流量高峰，而几天或一周后流量就会大幅下降。在大多数情况下，您需要部署多个相关的微服务来工作和通信。微服务之间的通信需要可靠和安全。最后，还需要进行日志记录、监控和仪表板工作等活动，以确保所有微服务的稳定性，并可识别甚至预见任何生产问题。自助托管还可能面临其他挑战，这些挑战取决于微服务的具体实施和构建。</p><p>接下来，我们将举例说明如何部署基于 Python 的微服务。假设您构建了一个基于 Python 的微服务，它可能是一个 Flask、Django 或任何其他 Python 网络应用程序。微服务无法直接开始提供所需的服务。它需要一个网络服务器接口或入口点来调用你的微服务。对于基于 Python 的微服务，主要有两种可用的接口：网络服务器网关接口（或 WSGI）是网络服务器与网络应用程序或微服务之间通信的主要 Python 标准。顾名思义，它只支持同步服务调用。</p><p>目前有许多流行的 WSGI 网络服务器，如 Gunicorn 和 uWSGI。你需要决定哪一种最适合你的需求。</p><p>异步服务器网关接口（ASGI）是另一种网络服务器接口。它与 WSGI 的主要区别在于它支持异步代码，因此你的微服务可以被异步调用。一些流行的 ASGI 网络服务器包括 Daphne 和 Hypercorn。</p><p>无论是 WSGI 还是 ASGI 网络服务器，都需要在特定类型的基础设施上运行。根据您的服务要求或协议，基础设施可以是一台笔记本电脑、一台专用工作站，也可以是一个拥有数百个计算和数据节点的复杂集群。</p><h2 id="41-ibm-云代码引擎"><a class="markdownIt-Anchor" href="#41-ibm-云代码引擎"></a> 4.1. IBM 云代码引擎</h2><p>可以看出，要在生产中部署微服务，您需要做出许多权衡和努力。值得庆幸的是，您现在可以在云平台上部署微服务，只需付出极少的努力。现在，让我们来介绍一下 IBM 云代码引擎（IBM Cloud Code Engine），这是一个可轻松部署微服务的全面而强大的平台。IBM 云代码引擎，简称「代码引擎」，抽象了构建、部署和管理工作负载的操作负担，使开发人员可以专注于代码开发。IBM Cloud Code Engine 的主要目标是减轻开发人员的部署负担。在它的帮助下，开发人员可以将代码推送到云平台，而无需考虑基础架构。</p><p>IBM 云代码引擎可以看作是一个完全托管的无服务器平台。它结合了平台即服务（PaaS）、容器即服务（CaaS）和无服务器部署模型所需的所有功能。IBM 云代码引擎可运行您的工作负载，包括微服务、Web 应用程序、事件驱动函数或批处理作业。如果您已构建了微服务，您可以将其作为 IBM Cloud Code Engine 应用程序运行，以直观的用户体验为传入的 HTTPS 请求提供服务，而无需轻松管理您的基础架构。</p><p>IBM 云代码引擎有三种主要用例或部署模式：第一种用例涉及将构建的应用程序部署到代码引擎。这里的应用程序可以是微服务、Web 应用程序或控制台应用程序。第二种用例是直接推送源代码。代码引擎可以从 GitHub repo 等远程仓库或本地工作区的源代码构建应用程序。构建好的应用程序可以自动部署，无需担心构建过程，既方便又省时。第三种用例是创建和运行批处理作业，如数据处理或分析任务。例如，如果您的一个微服务需要分析结果，您可以部署一个批处理作业，在同一平台上执行分析任务。因此，您部署的所有微服务和作业都可以无缝地协同工作，因为它们都托管在同一个基础架构中。</p><h2 id="411-术语"><a class="markdownIt-Anchor" href="#411-术语"></a> 4.1.1. 术语</h2><p>代码引擎中的「项目」一词代表一个包含并管理其资源和实体的组。代码引擎中的分组包含的实体有构建、应用程序、作业、传输层服务（或 TLS）HTTP 连接证书等。</p><p>项目的一个重要功能是为其实体提供命名空间。命名空间提供了一种在单个组内隔离实体组和资源的机制。在命名空间内，实体名称必须是唯一的，但在不同命名空间之间则不需要。另一个重要功能是管理资源和提供访问控制。</p><p>在代码引擎中，您的代码将运行应用程序。与常规部署的网络应用程序一样，运行中的应用程序可以提供 HTTP 请求或 REST API。除了传统的 HTTP 请求，代码引擎还支持使用 WebSockets 的应用程序。WebSocket 是一种基于传输控制协议（或 TCP）的通信协议。它主要用于客户端和服务器之间的长期运行和基于会话的通信，如聊天应用程序。代码引擎可通过创建或销毁应用程序运行实例来扩展应用程序。应用程序运行实例的数量会根据接收到的工作负载和您的配置设置自动增加或减少（至零）。</p><p>在代码引擎上下文中，构建或镜像构建（image build）是一种可用于从源代码创建容器镜像的机制。容器镜像包括容器运行所需的所有资产，如可执行源代码、依赖项、资源、容器引擎、系统库、配置设置等。</p><p>代码引擎支持从 Dockerfile 构建，Dockerfile 是一个文本文件，其中包含构建 Docker 容器镜像的所有命令。此外，它还可以使用云原生构建包（Cloud Native Buildpack）。构建包是另一种常用的容器镜像构建方式。它包含用于执行检查源代码、创建构建计划或执行构建计划以生成镜像等任务的可执行文件。从源代码构建容器镜像后，您可以将构建的容器镜像部署到代码引擎，并创建相应的应用程序。</p><p>作业是代码的一次性执行。与应用程序一样，作业也会运行可执行代码。根据工作量的不同，代码引擎会创建一个或多个作业实例。与主要处理 HTTP 请求或 WebSocket 会话的应用程序不同，作业旨在一次性运行并退出。在代码引擎中运行作业前，您可以指定作业每次运行时使用的工作负载配置。一些典型的作业包括批量查询和转换数据的数据处理作业、机器学习模型训练作业、根据预设计划生成报告的报告作业，以及创建和发送账单的计费作业。</p><h2 id="412-为微服务构建容器镜像"><a class="markdownIt-Anchor" href="#412-为微服务构建容器镜像"></a> 4.1.2. 为微服务构建容器镜像</h2><p>容器是一个独立的、包含所有内容的可执行软件单元。应用程序的源代码与其库、依赖项和运行时一起打包在容器中。容器构建完成后，可在任何设备上运行，如笔记本电脑、台式电脑或内部服务器。它还可以在云中运行。容器体积小、速度快、便于携带，因为与虚拟机不同，容器的每个实例都不需要客户操作系统，而是可以利用主机操作系统的功能和资源。微服务的关键要素之一是，就每个运行实例的计算资源而言，它通常规模较小且相互隔离。这使得容器与微服务架构中的这种小型轻量级服务完美匹配。</p><p>Docker 是一个软件平台，用于构建和运行作为容器的应用程序。此外，大量的互补工具、技术和开发方法仍在不断增长，并形成了庞大的 Docker 和容器化经济。Docker 提供了一种通过开源平台构建和运行容器的简单方法。Docker 是 IBM 云引擎中使用的主要容器技术。容器镜像是云引擎应用程序的基础。</p><p>现在让我们讨论使用 Docker 文件从源代码构建容器的典型方法。假设您已经完成了应用程序开发，并在集成开发环境中使用源代码、依赖项和库对其进行了本地测试。现在，你想构建一个 docker 容器。第一步就是创建一个 Dockerfile。Dockerfile 就像一个蓝图，通过它可以构建一个镜像。它概述了构建所需容器的所有说明。容器镜像是在创建 Dockerfile 之后构建的。</p><blockquote><p>请注意，容器镜像和容器是两种不同的东西。镜像是一个不可更改的文件，其中包含应用程序运行所需的所有应用程序资产，如源代码、库和依赖项。镜像是只读的；如果更改镜像，就需要创建一个新的镜像。与面向对象编程一样，容器镜像就像一个类，它就像一个正在运行的容器的模板。因此，如果我们实例化一个容器镜像，就会得到一个名为容器的运行镜像。</p></blockquote><p>因此，基本上你只需编写一个合适的 Dockerfile，剩下的就交给 Docker 来处理吧。</p><p>接下来，让我们看看构建基于 Flask 的微服务的 Dockerfile 示例。</p><pre><code class="language-dockerfile">FROM python:3.8</code></pre><p>Dockerfile 的第一行以 <code>FROM</code> 指令开始，用于指定后续指令将构建的基础镜像。该基础镜像通常来自公共资源库，比如操作系统，或者来自特定语言的基础镜像，比如 Python。你也可以选择添加一个更具体、更高级的基础镜像，以更好地服务于你的微服务，而不是一般的 Python docker 镜像。</p><pre><code class="language-dockerfile"># Or import a 3rd party image such as tiangolo/uwsgi-nginx-flask:python3.8</code></pre><p>你可以添加更具体、更先进的基础镜像，以便更好地为你的微服务服务。例如，<code>uwsgi-nginx-flask</code> 可让你创建 Python 语言的 Flask 微服务，并在单个容器中与 uWSGl 和 Nginx 一起运行。</p><pre><code class="language-dockerfile">COPY . /app</code></pre><p>下一条 <code>COPY</code> 指令会将所有文件复制到镜像中的 <code>/app</code> 文件夹。</p><pre><code class="language-dockerfile">ENV LISTEN_PORT 8080</code></pre><p>你可以使用 <code>ENV</code> 指令设置环境变量。在这里，你将 <code>LISTEN PORT</code> 设置为 <code>8080</code>，这意味着用该镜像制作的容器将监听 <code>8080</code> 端口。</p><pre><code class="language-dockerfile">EXPOSE 8080</code></pre><p>Dockerfile 中的 <code>EXPOSE</code> 关键字向 Docker 表明，容器将监听 <code>8080</code> 端口的流量。</p><pre><code class="language-dockerfile">RUN pip install -r requirements.txt</code></pre><p><code>RUN</code> 指令执行命令。</p><pre><code class="language-dockerfile">CMD ["python", "-m", "flask", "run"]</code></pre><p>最后一个是 <code>CMD</code>。该指令的主要目的是提供执行容器的默认值。该指令通常定义了应在容器中运行的可执行文件。在示例中，你运行的是 flask 微服务。但请注意，一个 Dockerfile 中只能有一条 CMD 指令。</p><p>容器镜像构建完成后，可以将其推送到容器存储库，以便更好地管理。这个容器存储库称为容器注册中心。常见的注册表有 Docker Hub 和 IBM Cloud Container Registry。注册表中的容器镜像可以通过唯一的镜像名称轻松提取和使用。</p><pre><code class="language-plaintext">hostname:repository:tage.g., icr.io/codeengine/hello</code></pre><p>镜像名称由主机名、存储库和标记组成。主机名标识了该镜像应推送到的注册中心。例如，<code>icr.io</code> 表示 IBM 容器注册中心。存储库是一组相关的容器镜像。通常，这些镜像是同一应用程序或服务的不同版本，因此应用程序或服务的名称就是一个好的资源库名称。最后，标签提供了有关镜像的特定版本或变体的信息。</p><h4 id="413-部署和运行应用程序"><a class="markdownIt-Anchor" href="#413-部署和运行应用程序"></a> 4.1.3. 部署和运行应用程序</h4><p>您可以使用两种模式之一将基于容器映像的应用程序部署到 IBM Cloud Code：</p><ol><li>首先，您可以构建容器映像并将其推送到私有或公共容器注册中心。云代码引擎可以使用唯一的映像名称提取映像，然后通过授予注册表访问权限自动进行部署。</li><li>或者，如果您不想手动构建映像，您可以指定一个 dockerfile 或一个 buildpack 以及您的代码，然后向云代码引擎发出指令，让它从源代码中构建您的应用程序，然后进行部署。因此，这两种模式本质上是一样的。</li></ol><p>唯一的区别是谁负责构建和推送容器映像。IBM 云控制台是一个精心设计的网络门户，供最终用户方便地管理他们的 IBM 云服务，包括代码引擎。在 IBM 云控制台中，只需点击几下，您就可以轻松创建和部署应用程序。如果您熟悉命令行界面（CLI)，并希望执行更精确的部署，可以选择 IBM Cloud CLI 来创建和部署应用程序。</p><p>您的应用程序部署到代码引擎后，引擎将提供应用程序的端点 URL，该 URL 可指向应用程序的主页面或微服务的入口端点。如上所述，IBM 云控制台提供了一个精心设计的用户界面，可帮助您轻松创建和部署应用程序。</p><p>现在让我们看看创建应用程序的主要步骤：首先，您需要指定应用程序的名称。然后，您可以选择从容器映像或源代码进行部署。这里您可以选择默认的容器映像选项。接下来，您需要提供图像的引用，还可选择提供注册表访问权限，以便代码引擎从注册表中提取图像。但请注意，这些只是主要步骤。您还可以根据应用程序的需要配置其他高级设置。创建应用后，云引擎将自动部署应用 如果应用运行无误，应在几分钟内准备就绪。应用程序就绪后，您可以单击「Test application」，使用 URL 进行测试。</p><p>如果您喜欢命令行界面，也可以使用 IBM Cloud CLI 部署应用程序。创建和部署应用程序的主要命令是 <code>ibmcloud ce app create</code>：它有三个主要参数：应用程序名称 <code>--name</code>、容器注册表中的映像引用 <code>--image</code> 以及注册表访问（如果容器注册表不是公开的）<code>--registry-secret</code>。</p><p>我们来看一个示例：</p><pre><code class="language-bash">ibmcloud ce app create --name helloworldapp --image us.icr.io/mynamespace/hello_repo --registry-secret myregistry</code></pre><p>在这里，您想通过 <code>us.icr.io</code> 注册服务器中的映像创建一个名为 <code>helloworldapp</code> 的应用程序。为了让代码引擎提取映像，您创建并提供了名为 <code>myregistry</code> 的注册表访问权限。</p><p>创建并部署应用程序后，可以使用 <code>ibmcloud ce app get</code> 命令运行并测试应用程序，该命令有两个主要参数：应用程序名称 <code>--name</code> 和应用程序的输出格式（如 URL）<code>--output</code>。下面，我们以获取先前部署的应用程序 <code>helloworldapp</code> 的输出为例进行说明。</p><pre><code class="language-bash">ibmcloud ce app get --name helloworldapp --output url</code></pre><p>使用应用程序名称调用 <code>ibmcloud ce app get</code>，并指定输出格式为 URL。然后，您就可以从命令输出中看到应用程序的公开访问 URL。</p><h4 id="414-更新已部署的应用程序"><a class="markdownIt-Anchor" href="#414-更新已部署的应用程序"></a> 4.1.4. 更新已部署的应用程序</h4><p>假设您为宠物业务开发了基于微服务的 PetShop 网络应用程序，并将每个微服务作为应用程序部署在代码引擎项目中。您的 PetShop 应用程序的网络流量很大，因此您决定将部分数据从 SQL DB 迁移到非 SQL DB。因此，您需要为新数据库服务开发和构建另一个容器映像，并根据新映像更新您的宠物数据库服务。此外，您还需要为应用程序添加一些新的环境变量，并需要更多计算资源来处理对 NoSQL DB 的请求。</p><p>代码引擎会管理已部署应用程序的每个修订版，因此您无需删除应用程序并部署新的应用程序。您只需更新现有应用程序，代码引擎就会为您创建和管理新版本。更新代码引擎应用程序有以下四种常见情况：</p><ol><li>更新环境变量，如数据库位置或秘钥</li><li>更新应用程序可见性，如将应用程序的 URL 从公开更改为私有或项目专用</li><li>更新应用程序的图片参考或 GitHub repo</li><li>更新应用程序的运行时资源</li></ol><p>与应用程序部署一样，您也可以使用 IBM 云代码引擎控制台或 CLI 更新应用程序。如果是添加环境变量之类的简单更新，使用精心设计的控制台 UI 会更方便快捷。对于更复杂、更精确的应用程序更新，代码引擎 CLI 可能更合适。执行所有应用程序更新相关操作的主要命令是 <code>ibmcloud ce application update</code>。</p><p>在应用程序控制台页面，点击环境变量表，可以找到所有环境变量。要添加或更新环境变量，您可以单击「Add environment variable（添加环境变量）」按钮。另外，如果您喜欢使用命令行界面（IBM Cloud CLI），则添加或更新环境变量的主要命令是 <code>ibmcloud ce app update</code>，其中包含两个主要参数：应用程序名称 <code>--name</code> 以及环境变量的名称和值 <code>--env</code>。</p><p>让我们来看一个快速示例：</p><pre><code class="language-bash">ibmcloud ce app update --name pet_db_service --env DB_HOST=localhost</code></pre><p>首先，在应用程序中添加一个名为 <code>DB_HOST</code> 的环境变量，其值为 <code>localhost</code>。<code>update</code> 命令会返回已更新到最新版本的信息。</p><pre><code class="language-bash">ibmcloud ce app get --name pet_db_service</code></pre><p>要仔细检查环境变量是否添加成功，可以使用 <code>app get</code> 命令显示 <code>pet_db_service</code> 应用程序的详细信息。现在可以看到环境变量 <code>DB_HOST</code> 已按预期添加。</p><p>部署应用程序时，会分配两种类型的 URL：内部 URL 和外部 URL。内部 URL 用于与应用程序内的其他应用程序通信。外部 URL 可以是公共 URL、外部 URL 或仅限 IBM 专用网络的 URL。选择 URL 类型可定义应用程序的可见性。</p><p>在应用程序控制台页面，单击系统域映射选项卡更新应用程序的可见性。选择「No external system domain mapping（无外部系统域映射）」时，此应用程序无法从公共互联网访问，只能从本项目内的组件（群集 - 本地）进行网络访问。选择此选项时，将显示群集本地 URL。选择私有时，可通过 IBM 云虚拟私有端点访问此应用程序。选择公开时，您可以查看应用程序的公开和群集本地 URL。</p><p>同样，您也可以通过 CLI 更新应用程序的可见性：主要命令仍然是 <code>ibmcloud ce app update</code>，有两个主要参数：应用程序名称 <code>--name</code> 和应用程序的可见性 <code>--visibility</code>。让我们来看一个快速示例：</p><pre><code class="language-bash">ibmcloud ce app update --name pet_db_service --visibility private</code></pre><p>首先将 <code>pet_db_service</code> 应用程序的可见性更新为 <code>private</code>。然后，如果您获取应用程序的详细信息，就会看到两个 URL。外部 URL 现在包含一个私有子域，这意味着现在只能通过 IBM 虚拟专用网络访问 <code>pet_db_service</code>。</p><p>现在，您可以通过控制台用户界面更新图像引用，方法如下：</p><ol><li>在应用程序控制台页面上，单击「Code」选项卡。</li><li>然后为应用程序指定新的映像引用。</li></ol><p>在 CLI 上，<code>ibmcloud ce app update</code> 命令有三个参数用于更新映像引用：应用程序名称 <code>--name</code>、映像引用的名称和值 <code>--image</code>，以及用于访问非公开容器注册表的注册表秘密 <code>--secret</code>。</p><p>例子：</p><pre><code class="language-bash">ibmcloud ce app update --name pet_db_service --image us.icr.io/petshop/no_sql_pet_db_service --registry-secret myregistry</code></pre><p>如果应用程序实例的响应时间过长或 CPU 和内存使用率过高，可以增加应用程序的运行时资源。为此，请进入应用程序页面并单击运行时选项卡。然后就可以根据需要更新实例的 CPU、内存和短暂存储。如果您想让应用程序扩大或缩小规模，也可以在同一用户界面上更新扩展和并发设置。</p><p>要通过 CLI 更新 CPU 或 GPU，需要使用相同的 <code>ibmcloud ce app update</code> 命令，其中包含三个主要参数：应用程序名称 <code>--name</code>、为实例设置的 CPU 数量 <code>--cpu</code> 和为实例设置的内存数量 <code>--memory</code>。</p><p>让我们看看示例：</p><pre><code class="language-bash">ibmcloud ce app update --name pet_db_service --cpu 2 --memory 16GB</code></pre><p>您将 <code>pet_db_service</code> 运行时资源的每个实例增加到 <code>2</code> 个 CPU 和 <code>16GB</code> 内存。</p></body></html>]]></content>
    
    
    <summary type="html">本文是 IBM 全栈开发课程的第十篇学习笔记，深入探讨了微服务与无服务器这两种现代云原生架构。笔记首先介绍了构建可扩展应用的十二要素方法论，并详细对比了单体、SOA与微服务的架构差异，涵盖了常见的设计模式与反模式。接着，文章转向无服务器计算，解释了其核心理念（FaaS）、优势与挑战。最后，笔记通过一个完整的流程，演示了如何为微服务构建 Docker 容器镜像，并使用 IBM Cloud Code Engine 这一全托管平台，轻松地部署和更新应用。这为理解和实践现代分布式系统的构建与部署提供了全面的理论指导。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="IBM" scheme="https://blog.cytrogen.icu/tags/IBM/"/>
    
    <category term="微服务" scheme="https://blog.cytrogen.icu/tags/%E5%BE%AE%E6%9C%8D%E5%8A%A1/"/>
    
    <category term="无服务器" scheme="https://blog.cytrogen.icu/tags/%E6%97%A0%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    
  </entry>
  
  <entry>
    <title>IBM 全栈开发【9】：使用 SQL 和数据库开发 Django 应用程序</title>
    <link href="https://blog.cytrogen.icu/posts/407.html"/>
    <id>https://blog.cytrogen.icu/posts/407.html</id>
    <published>2024-05-29T05:06:00.000Z</published>
    <updated>2026-02-09T17:16:54.721Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程，故此记录学习笔记。</p><span id="more"></span><h1 id="1-数据库入门"><a class="markdownIt-Anchor" href="#1-数据库入门"></a> 1. 数据库入门</h1><h2 id="11-sql"><a class="markdownIt-Anchor" href="#11-sql"></a> 1.1. SQL</h2><p>SQL 全称是 Structured Query Language，是为管理关系数据库中的数据而设计的，对于处理结构化数据非常有用。</p><p>数据是由文字、数字和图片组成的事实集合。而数据库是一个数据存储库，提供添加、修改和查询数据的功能。</p><p>关系数据库将表格数据存储为相关项目的集合，列中包含项目属性。非关系型数据库提供了一种灵活、可扩展的数据存储和检索方法。</p><p>关系数据库是优化存储、检索和处理大量数据的理想选择。</p><p>实体 - 关系模型（Entity-Relationship model）是设计关系数据库的工具。实体变为表、属性变为列。</p><p>基本 SQL 语句包括 <code>CREATE TABLE</code>、<code>INSERT</code>、<code>SELECT</code>、<code>UPDATE</code> 和 <code>DELETE</code>。</p><p>IBM DB2、SQL Server、MySQL、Oracle Database 和 PostgreSQL 都是有名的关系数据库。</p><p>部分有名的云关系数据库包括 RDS、Google Cloud SQL、IBM DB 2 on Cloud、Oracle Cloud 和 SQL Azure。</p><h4 id="111-用例"><a class="markdownIt-Anchor" href="#111-用例"></a> 1.1.1. 用例</h4><p>OLTP（Online Transaction Processing，在线事务处理）应用程序侧重于高速运行的事务型任务。关系数据库非常适合 OLTP 应用程序，因为它们可以容纳大量用户、支持插入更新或删除少量数据，还支持频繁查询和更新以及快速响应时间。</p><p>在数据仓库环境中，关系数据库可针对在线分析处理（或 OLAP）进行优化。在 OLAP 中，历史数据可用于商业智能分析。</p><p>物联网解决方案要求速度以及从边缘设备收集和处理数据的能力，这就需要一个轻量级的数据库解决方案。</p><h2 id="12-rdbms"><a class="markdownIt-Anchor" href="#12-rdbms"></a> 1.2. RDBMS</h2><p>DBRM 全称为 Database Management System，也就是数据库管理系统，是一组创建和维护数据库的程序。它允许存储、修改和查询数据库中的信息。</p><p>RDBMS 全称是 Rational Database Management System，也就是关系数据库管理系统。这是一种成熟的、文档齐全的技术，具有灵活性、减少冗余、易于备份和灾难恢复，并符合 ACID 标准。</p><blockquote><p>ACID 标准是指数据库管理系统在写入或更新资料的过程中，为保证交易是正确可靠的，所必须具备的四个特性：</p><ul><li>原子性，或称不可分割性（Atomicity）</li><li>一致性（Consistency）</li><li>隔离性（Isolation）</li><li>持久性（Durability）</li></ul></blockquote><h4 id="121-限制"><a class="markdownIt-Anchor" href="#121-限制"></a> 1.2.1. 限制</h4><p>RDBMS 不能很好地处理半结构化或非结构化数据，因此不适合对此类数据进行广泛分析。</p><p>要在两个 RDBMS 之间进行迁移，源表和目标表之间的模式和数据类型必须相同。</p><p>关系数据库对数据字段的长度有限制，这意味着如果尝试输入的信息超过字段所能容纳的长度，信息将不会被存储。</p><p>尽管数据有其局限性和演变性，但在大数据云计算、物联网设备和社交媒体时代，RDBMS 仍然是处理结构化数据的主要技术。</p><h2 id="13-nosql"><a class="markdownIt-Anchor" href="#13-nosql"></a> 1.3. NoSQL</h2><p>NoSQL 在过去的文章中有提到过，全称为 Not Only SQL（不只是 SQL），有时也指非 SQL，是一种非关系型数据库设计，为数据的存储和检索提供灵活的模式。</p><p>NoSQL 数据库有四种常见类型：</p><ul><li>键值存储</li><li>基于文档</li><li>基于列</li><li>基于图形</li></ul><h4 id="131-键值存储"><a class="markdownIt-Anchor" href="#131-键值存储"></a> 1.3.1. 键值存储</h4><p>键值数据库中的数据以键值对集合的形式存储。键代表数据的一个属性，是唯一的标识符。键和值可以是简单的整数或字符串，也可以是复杂的 JSON 文档。</p><p>键值存储非常适用于存储用户会话数据和用户偏好、实时推荐和定向广告以及内存数据缓存。</p><p>但是，如果想查询特定数据值的数据、需要数据值之间的关系，或者需要多个唯一键，键值存储可能不是最合适的选择。</p><p>Redis、Memcached 和 DynamoDB 就是这类数据库中的一些著名例子。</p><h4 id="132-基于文档"><a class="markdownIt-Anchor" href="#132-基于文档"></a> 1.3.2. 基于文档</h4><p>基于文档的文档数据库将每条记录及其相关数据存储在单个文档中。它们可以对文档集合进行灵活的索引、强大的临时查询和分析。文档数据库适用于电子商务平台、医疗记录、存储、客户关系管理平台和分析平台。</p><p>但是如果希望运行复杂的搜索查询和多操作事务，那么基于文档的数据库可能就不是最佳选择。</p><p>MongoDB、DocumentDB、CouchDB 和 Cloudant 是一些流行的基于文档的数据库。</p><h4 id="133-基于列"><a class="markdownIt-Anchor" href="#133-基于列"></a> 1.3.3. 基于列</h4><p>基于列的模型将数据存储在以数据列而不是行分组的单元格中。</p><p>列的逻辑分组，即通常一起访问的列，称为列族。例如，客户的姓名和个人资料信息很可能会一起被访问，但他们的购买历史记录却不会一起被访问，因此客户姓名和个人资料信息数据可以归入一个列族。</p><p>由于列数据库将与列相对应的所有单元格存储为连续的磁盘条目，因此访问和搜索数据的速度非常快。对于需要大量写入请求、存储时间序列数据、天气数据和物联网数据的系统来说，列式数据库是个不错的选择。</p><p>但是，如果您需要使用复杂的查询或经常改变查询模式，这可能不是最佳选择。</p><p>最流行的列数据库是 Cassandra 和 HBase。</p><h4 id="134-基于图形"><a class="markdownIt-Anchor" href="#134-基于图形"></a> 1.3.4. 基于图形</h4><p>基于图形的数据库使用图形模型来表示和存储数据。</p><p>它们特别适用于可视化、分析和查找不同数据之间的联系。圆圈是节点，包含数据，箭头代表关系。图形数据库是处理关联数据（即包含大量相互关联关系的数据）的最佳选择。</p><p>图形数据库非常适合社交网络、实时产品推荐、网络图、欺诈检测和访问管理。</p><p>但如果您想处理大量事务，它可能不是最佳选择，因为图形数据库没有针对大量分析查询进行优化。</p><p>Ne04J 和 CosmosDB 是比较流行的图数据库。</p><h2 id="14-测验"><a class="markdownIt-Anchor" href="#14-测验"></a> 1.4. 测验</h2><p>您正在为一家网上商店建立一个网站。您需要存储产品信息、客户详细信息和订单历史记录。以下哪项最恰当地描述了数据库在这种情况下的作用？</p><blockquote><p>在这种情况下，数据库是相关表格的集合。它提供了一种结构化的方式，将产品信息、客户详情和订单历史记录存储在不同的表格中，从而实现高效管理和数据检索。</p></blockquote><p>以下哪项是 RDBMS 的最大优势？</p><blockquote><p>符合 ACID 标准是 RDBMS 的重要优势之一。ACID 代表原子性（Atomicity）、一致性（Consistency）、隔离性（Isolation）和持久性（Durability），可确保数据事务得到可靠处理。</p></blockquote><p>在图书馆实体 - 关系数据模型中，图书是 _____ 的一个示例，而图书的书名、版本和出版日期则是 _______ 的示例。</p><blockquote><p>在实体 - 关系模型中，实体是一个名词（人、地点或事物）。属性是实体的属性或特征。</p></blockquote><p>关于数据库，以下哪些说法是正确的？</p><blockquote><p>数据库是逻辑上连贯的数据集合，具有一定的内在含义。</p></blockquote><p>关系型数据库的主要优势是什么？</p><blockquote><p>关系模型提供了逻辑和物理数据的独立性，允许在不影响底层数据库结构的情况下访问和修改数据。</p></blockquote><h1 id="2-orm弥合现实世界与关系模型之间的差距"><a class="markdownIt-Anchor" href="#2-orm弥合现实世界与关系模型之间的差距"></a> 2. ORM：弥合现实世界与关系模型之间的差距</h1><h2 id="21-django"><a class="markdownIt-Anchor" href="#21-django"></a> 2.1. Django</h2><p>Django 是一个可访问的高级开源 Python 网页框架。</p><p>Django 采用模型视图控制器 MVC 模式，可帮助开发人员快速高效地构建网络应用程序，从而实现快速开发和代码重用。用户几乎可以用 Django 构建任何网络应用程序，包括内容管理系统（CMS）、社交媒体平台、商业应用程序和新网站。</p><p>Django 提供了一系列开箱即用的特性和功能：Django 提供了一个对象关系映射或称 ORM 层，允许使用 Python 类定义数据模型。这使得使用数据库和执行操作变得更加容易。例如查询、插入、更新和删除记录。</p><p>Django 有一个内置模板引擎，使开发人员能够将应用程序的业务逻辑与表现逻辑分开。</p><p>Django 还提供根据应用程序中的模型自动生成的管理界面。它为管理网站内容提供了友好的用户界面，并可根据具体要求进行定制。Django 提供强大的安全功能，包括防止常见的网络漏洞，如跨站脚本（xss）、跨站请求伪造（CSRF）和 SQL 注入。</p><p>它还提供密码散列和用户会话管理机制。Django 内置身份验证和授权机制，允许管理用户账户，包括注册登录和密码管理。</p><p>它还提供细粒度的授权控制，以定义用户权限和访问限制。Django 可借助模块（也称为 Django 应用程序或包）进行扩展。这些模块是可重复使用的组件，可以将其集成到 Django 项目中，以添加特定的功能或特性。例如，Django 使用 <code>gettext</code> 模块支持语言本地化，Django 提供第三方软件包，如用于验证码集成的 Django Simple Captcha，它有助于防止表单中的自动僵尸提交，Django 的内置表单模块包括强大的表单。验证逻辑可确保表单数据符合标准。</p><p>Django 倡导的架构是每个网络服务器实例独立运行，称为无共享或无状态。该架构中的每个网络服务器实例都能自主处理请求和响应，而无需依赖共享资源或在请求之间维护任何服务器端状态。这使扩展变得容易，无状态使得开发人员可以添加更多应用程序实例，并在不丢失数据的情况下跨模型传输用户体验。</p><p>Django 支持各种测试，包括单元测试、集成测试和功能测试。Django 的测试框架包括一个测试运行器，允许开发人员快速运行测试并提供详细的测试报告。它提供各种测试工具、断言和固定装置，以方便编写和执行测试。</p><p>由于 Django 是基于 Python 构建的，因此与平台无关，这意味着它可以在许多平台上运行。这种平台独立性得益于 Python 的可移植性和在不同操作系统上的广泛可用性。这使得开发人员可以选择最适合其需求和基础设施的托管平台。Django 应用程序几乎可以在所有云提供商上运行。Django 的平台无关性使得可以根据具体要求和偏好将应用程序部署到各种云平台上。</p><p>一些著名的网页应用程序就是使用 Django 构建的。Instagram 是一个分享照片和视频的流行社交媒体平台，最初就是使用 Django 构建的。著名的音乐流媒体平台 Spotify 也使用了 Django 及其基础设施。著名的新闻出版物《华盛顿邮报》也采用了 Django 作为其内容管理系统或 CNS。</p><h2 id="12-ooad"><a class="markdownIt-Anchor" href="#12-ooad"></a> 1.2. OOAD</h2><p>面向对象的分析和设计（简称 OOAD）是一种分析和设计软件系统的方法，当系统将使用面向对象的编程语言来开发时，就需要使用这种方法。</p><p>在讨论 OOAD 之前，我们先来了解一下 Java 或 C++ 或 Python 等语言中的面向对象编程。OOAD 的核心是对象。对象包含数据，也有规定对象可以采取的行动的行为。</p><p>例如，我可以创建一个代表病人的对象。假设病人的名字是 Nia Patel、Nia 需要取消预约。不过，在创建 Nia 之前，我们必须先创建一个病人对象的通用版本。对象的通用版本称为类。接下来，让我们先讨论类，然后再详细讨论 Nia。</p><p>类是对象的蓝图或模板，从类中创建特定对象（也称为实例）。 考虑到 Nia 将是病人类的一个实例。类包含对象、通用属性、属性和方法，但只有在创建对象时，也就是代码中所谓的实例化时，这些通用属性才会被设置为特定值。病人类可能有一个名为 <code>LastName</code> 的变量，它是一个属性，但并不指定 <code>LastName</code> 是什么。<code>Lastname</code> 是一个占位符，直到创建了对象并分配了名称。一旦对象被实例化，就可以调用其方法使对象执行某些操作，如预约或取消预约。OOAD 可用于将系统分解为相互交互的对象。这样，多个开发人员就可以同时处理应用程序的不同方面。</p><h4 id="121-orm"><a class="markdownIt-Anchor" href="#121-orm"></a> 1.2.1. ORM</h4><p>对象关系映射（ORM）工具被广泛应用于现代软件开发中，为面向对象的编程语言和关系数据库之间架起了一座桥梁。ORM 工具提供了一种使用编程语言对象和概念与数据库交互的方便高效的方法，使开发人员无需编写复杂重复的 SQL 查询。</p><p>编程语言都有自己的 ORM 工具，可以简化数据库操作和开发流程。</p><ul><li><p>Django 是一个 Python 网络框架，内置 ORM，提供与数据库交互的高级应用编程接口（API）。Django 提供模型定义、查询构建、数据库迁移和自动查询优化等功能。</p></li><li><p>SQLAlchemy 是一个流行的 Python 综合 ORM 库，提供了一个灵活而富有表现力的 API，用于与数据库交互。SQLAlchemy 提供高级和低级 ORM 方法，允许开发人员选择所需的抽象级别。</p></li><li><p>web2py 是一个用 Python 编写的开源全栈网络框架，旨在通过提供包括网络服务器、数据库抽象层和基于网络的开发环境在内的一体化解决方案来简化网络应用程序开发。</p></li><li><p>Hibernate 广泛用于 Java 应用程序，因为它提供了功能强大、特性丰富的 API，可将 Java 对象映射到关系数据库。Hibernate 支持各种数据库系统，并提供懒加载、缓存和事务管理等高级功能。</p></li><li><p>EclipseLink 是另一种流行的 Java 工具。它是一个开源框架，为 Java 与关系数据库的映射提供广泛支持。EclipseLink 支持 Java Persistence API (JPA)、缓存、高级查询功能以及与各种应用服务器的集成等功能。</p></li><li><p>Apache OpenJPA 是 JPA 规范的开源实现。它便于将 Java 类映射到关系数据库表，并提供透明的 Java 对象持久性。</p></li><li><p>Entity Framework 是微软用于 .NET 应用程序的 ORM 框架。它提供了一个易于使用的 API，用于将 .NET 对象映射到关系数据库。Entity Framework 支持不同的数据库提供商，提供查询功能，并包含代码优先和数据库优先的模型创建方法等功能。</p></li><li><p>Dapper <a href="http://xn--0iv.NET">是.NET</a> 的微型操作系统，注重性能和简单性。它为查询数据库提供了轻量级、高效的 API。Dapper 适用于需要直接控制 SQL 查询和执行的场景。</p></li><li><p>NHibernate 是 .NET 平台上广泛使用的 ORM 工具。它的灵感来自 Java 的 Hibernate ORM 工具。NHibernate 在 .NET 面向对象编程和关系数据库之间架起了一座桥梁，允许开发人员使用 .NET 对象与数据库交互。</p></li><li><p>ActiveRecord 是 Ruby on Rails（一种流行的 Ruby 网络框架）中的默认 ORM。它提供了一种「约定重于配置」的方法，可轻松将 Ruby 对象映射到数据库表。ActiveRecord 提供了模型关联、查询生成和数据库迁移等功能。</p></li><li><p>Sequel 是一款灵活、功能丰富的 Ruby ORM 工具，它强调简单性和以 SQL 为中心的方法。Sequel 支持各种数据库系统，提供高级查询功能，并提供插件以实现更多功能。</p></li><li><p>DataMapper 注重简洁性、灵活性和易用性。它旨在为在 Ruby 应用程序中使用数据库提供简洁直观的 API。DataMapper 的功能包括灵活的映射、数据抽象、查询和存储库模式。</p></li><li><p>Propel 是一款适用于 PHP 的高性能 ORM 工具，专注于代码生成和简化。它采用代码优先的方法，由 PHP 类和对象定义数据库模式。Propel 可生成高效的 SQL 查询，并提供懒加载、急迫加载和缓存等功能。</p></li><li><p>CakePHP 包含一个内置的 ORM 组件，为数据库工作提供了一个强大而直观的 API，具有数据库抽象、查询构建和关联管理等功能。</p></li><li><p>Eloquent 是流行的 PHP 框架 Laravel 框架提供的默认 ORM。它为定义数据库模型和关系提供了简单明了、表现力丰富的语法。Eloquent 简化了数据库操作，包括查询、数据检索和数据库迁移，并支持不同的数据库引擎。</p></li></ul><p>软件开发人员通常使用数据库作为应用程序的主要数据存储库，因此需要将 SQL 集成到应用程序代码中。SQL 语句必须在应用程序代码中组装，并使用数据库 API 在数据库系统中执行 —— 检索到的数据库行将作为 <code>cursor</code>（一种用于遍历数据库中行的特殊控制数据结构）返回给应用程序代码。</p><p>在 Python 中运行 SQL 的例子：</p><pre><code class="language-python">connection = sqlite3.connect('course.db')cursor = connection.cursor()insert_statement = 'INSERT INTO data_learner (first_name, last_name, dob, occupation) VALUES ("John", "Doe", "1962-01-01", "Developer");'cursor.execute(insert_statement)cursor.execute('SELECT * FROM data_learner')learner = cursor.fetchone()</code></pre><p>与使用表格、行和列来模拟实体的 SQL 不同，面向对象语言使用类和对象来模拟实体。在 OOP 中，<code>Course</code> 实体将被定义为一个类，该类有两个基本属性：<code>name</code> 和 <code>description</code>；一个引用属性，即 <code>learner</code> 列表。</p><p>数据操作方法也需要与类属性一起定义。这里我们定义了一个简单的方法：<code>get Learners</code>。<code>Learner</code> 实体也将被定义为一个具有四个属性的类：名、姓、出生日期和职业。我们还将定义一个简单的打印个人资料方法。</p><pre><code class="language-python">connection = sqlite3.connect('course.db')cursor = connection.cursor()cursor.execute('SELECT * FROM data_learner')learner_row = cursor.fetchone()learner = Learner()learner.first_name = learner_row['first_name']learner.last_name = learner_row['last_name']learner.dob = learner_row['dob']learner.occupation = learner_row['occupation']learner.print_profile()</code></pre><p>我们已经看到，OOP 和 SQL 的数据建模方式是不同的。OOP 使用类、对象和属性对实体建模，而 SQL 则使用表、行和列对实体建模。最后，OOP 使用方法对数据进行 CRUD，而 SQL 则使用数据操作语言（如 SQL 语句插入、删除和更新）对数据进行 CRUD。</p><p>既然我们通常使用 OOP 构建现代应用程序，那么我们是否也可以使用 OOP 而不是 SQL 访问数据库呢？这样，我们就可以坚持使用一种编程范式进行开发。人们发明对象关系映射的主要原因是为了弥合 OOP 与 SQL 之间的差距，使使用 OOP 语言访问数据库成为可能。ORM 库或工具可以将关系数据库中存储的数据映射和传输为行到对象或对象到行。</p><p>假设我们有一个由开发人员使用 OOP 创建的 <code>Learner</code> 对象模型。ORM 可以帮助将 <code>Learner</code> 对象转移到 <code>Learner</code> 表中的 <code>Learner</code> 行中，并将其读回 <code>Learner</code> 对象。这就减少了开发人员的工作量，因为他们只需关注对象操作。下面是 ORM 如何以一行代码的形式传输三个表连接的 SQL 查询。</p><p>SQL 代码例子：</p><pre><code class="language-python">connection = sqlite3.connect('sample.db')cursor = connection.cursor()select_statement = 'SELECT learner.name FROM learner INNER JOIN enrollment ON (learner_id = enrollment.learner_id) INNER JOIN course ON (course_id = enrollment.course_id) WHERE course.name = "Introduction to Python"'cursor.execute(select_statement)learners = cursor.fetchall()</code></pre><p>ORM 代码例子：</p><pre><code class="language-python">Course.objects.get(name='Introduction to Python').learners.all()</code></pre><p>在开发 OOP 应用程序时，只需定义类和创建对象，无需编写 SQL 即可使用数据库。此外还可以使用一个 ORM 接口来管理多个数据库系统，而不必担心 SQL 语法的差异。所有这些优势都将加快应用程序的交付速度。</p><p>但是 SQL 和 OOP 仍然是两种不同的语言，具有不同的建模概念，而且 ORM 可能无法将对象映射到数据库表中。此外，由于 ORM 将数据访问逻辑与应用程序代码结合在一起，因此任何数据库变更都需要同时更改应用程序逻辑和数据访问逻辑。由于 ORM 隐藏了实现细节，因此调试可能很困难。ORM 也有可能会降低应用程序的性能：ORM 增加了一个额外的翻译层，但不能保证翻译后的 SQL 语句得到优化。</p><h4 id="122-django-orm"><a class="markdownIt-Anchor" href="#122-django-orm"></a> 1.2.2. Django ORM</h4><p>在 Django ORM 中，每个 Django 模型都映射到一个数据库表。当您创建一个类对象时，它代表一个表行。每个字段代表一个表列。一旦定义了模型类，模式和表格就会自动生成。</p><pre><code class="language-python">class User(models.Model):    first_name = models.CharField(max_length=30)</code></pre><p>例如，我们可以定义一个 <code>User</code> 类，它是 Django 模型的子类。然后，Django 将通过生成 <code>table create</code> 语句并根据类字段创建列，在数据库中创建相应的 <code>User</code> 表。在我们的例子中，将根据 <code>first_name</code> 字段创建 <code>first_name</code> 列。模型中的每个字段都应定义为一个 <code>Field</code> 类。</p><p>上面的 Python 代码等同于：</p><pre><code class="language-sql">CREATE TABLE data_user(    "id" serial NOT NULL PRIMARY KEY,    "first_name" varchar(30) NOT NULL)</code></pre><p>模型中的每个字段都应定义为 <code>Field</code> 类。Django 会将每个字段映射为列类型。在这里，<code>first_name</code> 被定义为字符字段，将被转换为 <code>varchar</code>，而 <code>dob</code> 是日期字段，将被转换为 <code>date</code>。对于每一列，我们通过在 Django <code>Field</code> 类中指定参数来定义其元数据，如类型和约束条件。例如，对于 <code>first_name</code> 字段，我们使用 <code>max_length</code> 参数指定 <code>varchar</code> 的长度。</p><pre><code class="language-python">class User(models.Model):    first_name = models.CharField(max_length=30)    last_name = models.CharField(max_length=30)    dob = models.DateField()</code></pre><p>等同于：</p><pre><code class="language-sql">CREATE TABLE data_user(    "id" serial NOT NULL PRIMARY KEY,    "first_name" varchar(30) NOT NULL,    "last_name" varchar(30) NOT NULL,    "dob" date NOT NULL)</code></pre><p>接下来，我们为实体之间的关系建模。Django ORM 支持常见的关系，如一对一、多对一和多对多。</p><p>我们从一对一关系开始。假设我们有一个 <code>Instructor</code> 和 <code>User</code> ER 图。<code>User</code> 类拥有一些常用字段，如姓名或出生日期，而 <code>Instructor</code> 类拥有一些特殊字段，如是否全职或讲师拥有的学员总数。一个教员只能在一个 <code>User</code> 类中存储基本信息，一个用户只能有一个角色，如 <code>Instructor</code> 或 <code>Learner</code>。</p><pre><code class="language-plaintext">Class: Instructoris_full_time: booleantotal_learners: int</code></pre><pre><code class="language-plaintext">Class: Userfirst_name: stringlast_name: floatdob: date</code></pre><p>将以上 ER 图转换为 Django 模型：</p><pre><code class="language-python">class Instructor(models.Model):    is_full_time = models.BooleanField()    total_learners = models.IntegerField()    user = models.OneToOneField(User)</code></pre><pre><code class="language-python">class User(models.Model):    first_name = models.CharField(max_length=30)    last_name = models.CharField(max_length=30)    dob = models.CharField(max_length=30)</code></pre><p>我们将使用 <code>Project</code> 和 <code>Course</code> ER 图来说明「多对一」关系。<code>Project</code> 类表示一个课程项目，包含项目名称和成绩等字段。<code>Course</code> 类代表在线课程实体。它有原子字段，如名称和描述。更重要的是，它有一个名为 <code>projects</code> 的集合字段，代表一组课程项目对象。因此，一门课程会有许多课程项目，而一个课程项目只属于一门课程。这是一种典型的多对一关系。要在 Django 中创建模型，我们需要添加一个额外的 <code>Course</code> 字段作为外键。请注意，这不是一对一字段，因为多个项目可能拥有相同的课程字段。</p><p>关于「多对多」关系，让我们来看看 <code>Course</code> 和 <code>Learner</code> ER 图。</p><pre><code class="language-plaintext">Class: Coursename: stringdescription: stringlearners: set</code></pre><pre><code class="language-plaintext">Class: Learneroccupation: enumsocial_link: URL</code></pre><p>为了模拟这种关系，我们在其中一个模型中添加了一个 <code>ManyToManyField</code>。通常，<code>ManyToManyField</code> 应放在最常编辑的模型中。例如，<code>Course</code> 可能会随着学习者的添加或删除而每小时被编辑一次，但每个学习者可能每周或每月才注册一次新课程。有时，您可能需要有关模型之间关系的额外信息。</p><p>例如，您可能需要学习者和课程之间的注册信息，如注册日期。Django 允许您指定用于管理多对多关系的模型。在我们的例子中，中间模型是 <code>Enrollment</code> 表。它使用 <code>through</code> 参数与 <code>ManyToManyField</code> 关联。</p><pre><code class="language-python">class Course(models.Model):    name = models.CharField(max_length=30)    description = models.CharField(max_length=30)    learners = models.ManyToManyField(Instructor, through='Enrollment')</code></pre><pre><code class="language-python">class Enrollment(models.Model):    course = models.ForeignKey(...)    learner = models.ForeignKey(...)    date_enrolled = models.DateField()</code></pre><pre><code class="language-python">class Learner(models.Model):    occupation = models.CharField(max_length=20)    social_link = models.URLField()</code></pre><p>Django 中的模型继承就像 Python 中的继承一样。你需要确定父模型是否只是通过子模型才能看到的通用信息的持有者，或者父模型是否应该有自己的表。</p><h4 id="123-crud"><a class="markdownIt-Anchor" href="#123-crud"></a> 1.2.3. CRUD</h4><blockquote><p>CRUD 就是喜闻乐见的 <strong>增删查改</strong>。</p></blockquote><p>Django 模型提供了全面的 CRUD API，无需编写 SQL 查询即可操作对象。让我们回顾一下我们将在示例中使用的在线课程模型。基本 <code>User</code> 模型包含有关 <code>Instructor</code> 和 <code>Learner</code> 模型的通用信息。<code>Instructor</code> 从 <code>User</code> 模型继承而来，拥有 <code>is_full_time</code> 或学习者总数等字段。<code>Learner</code> 也是继承的。它有 <code>occupation</code> 和 <code>social_link</code> 等字段。<code>Course</code> 模型与 <code>Instructor</code> 模型和 <code>Learner</code> 模型都有多对多关系。<code>Course</code> 模型还与 <code>Project</code> 模型有多对一关系。在 Django 模型中，创建一个对象并调用模型的保存方法将其作为记录插入数据库。</p><pre><code class="language-python">course_cloud_app = Course(name='Cloud Application Development with Database', description='Develop and deploy application on cloud')course_cloud_app.save()</code></pre><p>如果创建的对象包含对另一个模型的引用，如外键或多对多字段，则使用相关模型引用来创建关系。</p><pre><code class="language-python">project_orm = Project(name='Object-relational mapping project', grade=0.2, course=course_cloud_app)project_orm.save()</code></pre><p>我们创建了一个 <code>Project</code> 对象，并将其 <code>Course</code> 外键指向我们刚刚创建的 <code>course_cloud_app</code>。将对象及其关系插入数据库后，我们就可以进行查询了。首先，让我们看看如何读取模型的所有对象。这相当于在 SQL 中使用 <code>SELECT *</code> 从表中获取表的所有行。一般来说，要使用 Django Model API 读取对象，需要在模型类上使用 <code>Manager</code> 构建一个 <code>QuerySet</code>。</p><pre><code class="language-python">courses = Course.objects.all()</code></pre><p><code>filter</code> 方法可以有许多查找参数，如大于、小于、包含或为空。这就像 SQL <code>WHERE</code> 子句中的条件用法。查询参数包含字段名称和查询表达式，对于等价检查，查询表达式可以为空，对于其他检查，查询表达式可以用下划线分隔。</p><pre><code class="language-python">part_time_instructors = Instructor.objects.filter(is_full_time=False)</code></pre><p><code>exclude</code> 方法会返回一个与给定查找参数不匹配的新 <code>QuerySet</code>。由于 <code>exclude</code> 和 <code>filter</code> 方法都会返回一个 <code>QuerySet</code>，我们可以进一步追加 <code>exclude</code> 和 <code>filter</code> 方法，形成一个过滤链。这就像在 SQL 的 <code>Where</code> 子句中使用 <code>and</code> 添加多个条件一样。我们可以同时使用 <code>exclude</code> 和 <code>filter</code> 方法查找 <code>Instructor</code> 子集。</p><pre><code class="language-python">filtered_instructors = Instructor.objects.exclude(full_time=False).filter(total_learners__gt=30000).filter(first_name__startswith='J')</code></pre><pre><code class="language-python">filtered_instructors = Instructor.objects.filter(full_time=True, total_learners__gt=30000, first_name__startswith='J')</code></pre><p>如果只有一个对象符合您的查询，您可以使用 <code>Get</code> 方法返回该对象。例如，如果我们知道只有一个教员的名字是 John，我们就可以使用带有 <code>first_name</code> 查找参数的 <code>Get</code> 方法来获取教员。</p><pre><code class="language-python">instructor_john = Instructor.objects.get(first_name='John')</code></pre><p>更新对象的原始字段。对于我们的学习者对象，我们可以将 <code>dob</code> 字段更改为 1985 年 3 月 16 日，然后使用 <code>save</code> 方法将更改更新到数据库。Django 模型将创建并执行相应的 SQL 更新语句。我们还可以更新相关字段，如外键字段或多对多字段。</p><pre><code class="language-python">learner_john.dob = date(1985,3,16)learner_john.save()</code></pre><p>我们还可以更新相关字段，如外键字段或多对多字段。例如，我们可以更新课程外键字段，使其指向不同的课程。我们还可以 <code>Add</code> 方法将另一位学员添加到课程中。</p><pre><code class="language-python">project_orm.course = course_pythonproject_orm.save()</code></pre><p>要删除数据库中的记录，需要在模型对象或 <code>QuerySet</code> 上调用 <code>Delete</code> 方法。Django ORM 支持不同的 <code>on delete</code> 选项。</p><pre><code class="language-python">project_orm.delete()Course.objects.filter(name__contains='Python').delete()</code></pre><h1 id="3-全栈-django-开发"><a class="markdownIt-Anchor" href="#3-全栈-django-开发"></a> 3. 全栈 Django 开发</h1><h2 id="31-mvc"><a class="markdownIt-Anchor" href="#31-mvc"></a> 3.1. MVC</h2><p>MVC 设计模式将应用程序逻辑分为三个部分：</p><ol><li>模型访问和操作数据。</li><li>视图以各种形式显示数据。</li><li>控制器在模型和视图之间进行协调。</li></ol><p>Django 的 MVT 模式与 MVC 相似，只是没有控制器，Django 服务器自身会执行控制器的功能。</p><blockquote><p>MVT：Model-View-Template。</p></blockquote><h2 id="32-django"><a class="markdownIt-Anchor" href="#32-django"></a> 3.2. Django</h2><p>在 Django 中，视图（View）是一个 Python 函数。Django 视图接收网络请求，如 HTTP <code>GET</code>、<code>POST</code>、<code>DELETE</code> 或 <code>UPDATE</code>，并返回网络响应。网络响应可以是字符串、JSON / XML 文件、HTML 页面，也可以是表示客户端或服务器端错误的错误状态。</p><p>Django 使用包含静态 HTML 元素和特殊 Python 代码的模板来生成动态网页。可以在 Django 中创建模板来指定数据的展示方式。Django 模板将静态 HTML 元素与描述如何插入动态部分的 Django 模板标记和变量相结合。这些元素共同作用生成一个 HTML 页面，在用户的网络浏览器中呈现。</p><p>创建 Django 项目时，Django 会创建一些核心文件：</p><ul><li><code>manage.py</code> 是用于与 Django 项目交互的命令行界面。</li><li><code>settings.py</code> 包含 Django 项目的设置和配置。</li><li><code>urls.py</code> 包含 Django 应用程序的 URL 和路由定义。</li></ul><p>可以通过创建一个管理员用户开始构建 Django 管理站点。然后，就可以以超级用户身份登录，并将模型注册到管理员站点，以便对其进行管理。</p><h1 id="4-整合和部署-django-应用程序"><a class="markdownIt-Anchor" href="#4-整合和部署-django-应用程序"></a> 4. 整合和部署 Django 应用程序</h1><p>在 Django 中，类视图必须与 URL 模式进行映射，几乎就像为基于函数的视图配置 URL 一样。唯一的区别是你需要指定以下哪一项？</p><blockquote><p><code>as_view</code> 函数。这是 Django 类视图的一个重要方法，它负责创建一个适合用作视图的实例，并调用其 <code>dispatch</code> 方法。这是在 URL 配置中使用类视图时需要指定的方法。</p></blockquote><p>在通过登录 HTML 模板从用户处接收用户名和密码时，哪种 HTTP 方法将用户名或密码发送到在线课程登录视图以验证用户？</p><blockquote><p><code>POST</code> 请求。</p></blockquote><p>Django 提供了一个默认的静态文件应用，它将所有静态文件收集到一个目录中。当你将你的应用部署到生产 Web 服务器时，你可以将所有静态文件移动到这个目录。要做到这一点，有几个步骤。在最后一步，你需要调用什么？</p><blockquote><p>运行 <code>collectstatic</code> 命令。这是 Django 的一个管理命令，用于收集所有应用的静态文件到一个指定的位置，以便在生产环境中使用。</p></blockquote><p>ASGI 是 Django 应用支持的 Web 服务器接口。WSGI 和 ASGI 之间的主要区别是什么？</p><blockquote><p>ASGI 支持异步代码，而 WSGI 适合同步 Web 应用。这是 WSGI（Web 服务器网关接口）和 ASGI（异步服务器网关接口）之间的主要区别。ASGI 是 WSGI 的扩展，它增加了对异步编程的支持，这使得在处理大量并发连接时，可以更有效地利用系统资源。</p></blockquote><p>为了解决 Django 视图的可扩展性和可重用性问题，创建了哪种类型的视图？</p><blockquote><p>基于类的视图。Django 引入了基于类的视图（Class-Based Views），以提供更好的可重用性和可扩展性。基于类的视图允许你通过继承和混入（mixins）来重用和定制视图的行为。</p></blockquote><p>授权是在认证过程的什么时候发生的？</p><blockquote><p>认证之后。在大多数系统中，用户必须首先通过认证（例如，通过提供有效的用户名和密码），然后系统才会进行授权，以确定用户对资源的访问权限。</p></blockquote><p>如果你想在不手动下载和导入的情况下使用 Bootstrap CSS 样式类，你应该怎么做？</p><blockquote><p>在你的 HTML 模板的 <code>head</code> 元素中添加一个链接到最新的 Bootstrap 版本。这样，你就可以在你的网页中直接使用 Bootstrap 的 CSS 样式类，而无需手动下载和导入 Bootstrap。</p></blockquote><p>Django 应用可以有特定于应用的静态文件和外部静态文件。你在哪里定义外部静态文件的目录，以便你可以找到它们？</p><blockquote><p>在 <code>settings.py</code> 文件中的 <code>STATICFILES_DIRS</code> 列表。这是 Django 设置中的一个变量，用于指定包含你的静态文件的额外目录的列表。Django 将在这些目录中查找静态文件。</p></blockquote><p>WSGI 是 Python 用于在 Web 服务器和应用程序之间通信的主要标准。为了使 Django 应用与 WSGI 一起工作，启动项目命令创建了一个默认声明可调用应用程序的文件。这个文件叫什么名字？</p><blockquote><p><code>wsgi.py</code>。这是 Django 项目中的一个文件，它包含一个可调用的 WSGI 应用。当你使用 Django 的 <code>startproject</code> 命令创建一个新项目时，这个文件会被自动创建。</p></blockquote><h1 id="5-利用新功能增强在线课程应用程序"><a class="markdownIt-Anchor" href="#5-利用新功能增强在线课程应用程序"></a> 5. 利用新功能增强在线课程应用程序</h1><h2 id="51-最终项目概述和方案"><a class="markdownIt-Anchor" href="#51-最终项目概述和方案"></a> 5.1. 最终项目概述和方案</h2><p>您将有机会掌握 Django 技能并将其应用到项目中。您将收到一个在线课程应用程序的模板代码。然后，您将利用在本课程中学到的技能，计划并实施对应用程序的改进；这些改进包括：</p><ol><li>创建问题、选择和提交模型</li><li>使用管理站点创建带有考试相关模型的新课程对象</li><li>更新课程详细信息模板，以显示问题和选项</li><li>创建新的考试结果模板，以显示提交结果</li><li>创建新的考试结果提交视图</li><li>创建一个新视图来显示和评估考试结果</li></ol><p><a href="https://github.com/ibm-developer-skills-network/tfjzl-final-cloud-app-with-database"><img src="https://gh-card.dev/repos/ibm-developer-skills-network/tfjzl-final-cloud-app-with-database.svg" alt="ibm-developer-skills-network/tfjzl-final-cloud-app-with-database - GitHub" loading="lazy"></a></p><p>让我们建立一个虚拟环境，其中包含我们需要的所有软件包：</p><pre><code class="language-bash">pip install --upgrade distro-infopip3 install --upgrade pip==23.2.1pip install virtualenvvirtualenv djangoenvsource djangoenv/bin/activate</code></pre><pre><code class="language-bash">pip install -U -r requirements.txt</code></pre><p>创建初始迁移并生成数据库模式：</p><blockquote><p>迁移是 Django 将对模型所做的更改（添加字段、删除模型等）传播到数据库模式的方式。迁移主要是自动进行的，但你需要了解何时进行迁移、何时运行迁移以及可能遇到的常见问题。你将使用几条命令与迁移和 Django 处理数据库模式进行交互：</p><p><code>migrate</code>：负责应用和取消应用迁移。<br><code>makemigrations</code>：负责根据对模型所做的更改创建新的迁移。<br><code>sqlmigrate</code>：用于显示迁移的 SQL 语句。<br><code>showmigrations</code>：用于列出项目的迁移及其状态。</p></blockquote><pre><code class="language-bash">python manage.py makemigrationspython manage.py migrate</code></pre><p>这次成功运行服务器：</p><pre><code class="language-bash">python manage.py runserver</code></pre><blockquote><p>访问 <code>8000/onlinecourse</code>。</p></blockquote><h4 id="511-建立新模型"><a class="markdownIt-Anchor" href="#511-建立新模型"></a> 5.1.1. 建立新模型</h4><p>你需要在 <code>onlinecourse/models.py</code> 中创建几个新模型。</p><p><code>Question</code> 模型将保存具有以下特征的考试问题：</p><ul><li>用于保存课程试题</li><li>与课程有多对一关系</li><li>具有问题文本</li><li>每道题都有一个分数</li></ul><pre><code class="language-python">class Question(models.Model):    course = models.ForeignKey(Course, on_delete=models.CASCADE)    content = models.CharField(max_length=200)    grade = models.IntegerField(default=50)    def __str__(self):        return "Question: " + self.content</code></pre><p>此外，你还可以在 <code>Question</code> 模型中添加以下函数来计算分数：</p><pre><code class="language-python">def is_get_score(self, selected_ids):    all_answers = self.choice_set.filter(is_correct=True).count()    selected_correct = self.choice_set.filter(is_correct=True, id__in=selected_ids).count()    if all_answers == selected_correct:        return True    return False</code></pre><p><code>Choice</code> 模型可保存问题的所有选项：</p><ul><li>与 <code>Question</code> 模型的多对一关系</li><li>选项文本</li><li>表示该选项是否正确</li></ul><pre><code class="language-python">class Choice(models.Model):    question = models.ForeignKey(Question, on_delete=models.CASCADE)    content = models.CharField(max_length=200)    is_correct = models.BooleanField(default=False)</code></pre><p>我们为您提供了已注释的 <code>Submission</code> 模型，该模型具有以下特点：</p><ul><li>与 <code>Exam Submissions</code> 之间的多对一关系，例如，多个考试提交可能属于一个课程注册。</li><li>与选项或问题的多对多关系。为简单起见，您可以将提交与 <code>Choice</code> 模型相关联。</li></ul><p>您需要取消对 <code>Submission</code> 模型的注释，并使用它来关联选定的选择。</p><pre><code class="language-python">class Submission(models.Model):    enrollment = models.ForeignKey(Enrollment, on_delete=models.CASCADE)    choices = models.ManyToManyField(Choice)</code></pre><p>迁移：</p><pre><code class="language-bash">python manage.py makemigrations onlinecoursepython manage.py migrate</code></pre><h4 id="512-注册模式变更"><a class="markdownIt-Anchor" href="#512-注册模式变更"></a> 5.1.2. 注册模式变更</h4><p>现在，您将修改 <code>onlinecourse/admin.py</code>，以便使用您创建的新功能。</p><p>首先您需要导入 <code>Question</code>、<code>Choice</code> 和 <code>Submission</code>：</p><pre><code class="language-python">from .models import Course, Lesson, Instructor, Learner, Question, Choice, Submission</code></pre><p>创建 <code>QuestionInline</code> 和 <code>ChoiceInline</code> 类，这样就可以在管理网站的一个页面上一起编辑它们。</p><pre><code class="language-python">class ChoiceInline(admin.StackedInline):    model = Choice    extra = 2class QuestionInline(admin.StackedInline):    model = Question    extra = 2</code></pre><p>创建 <code>QuestionAdmin</code> 类：</p><pre><code class="language-python">class QuestionAdmin(admin.ModelAdmin):    inlines = [ChoiceInline]    list_display = ['content']</code></pre><p>注册新模型后，您可以使用管理网站创建一个包含课程、问题和问题选项的新课程。</p><pre><code class="language-python">admin.site.register(Question, QuestionAdmin)admin.site.register(Choice)admin.site.register(Submission)</code></pre><p>接着让我们创建一个管理员用户，其详细信息如下：</p><ol><li>用户名：<code>admin</code>。</li><li>邮箱：<em>留空</em>。</li><li>密码：可以使用 <code>p@ssword123</code>。</li></ol><pre><code class="language-bash">python manage.py createsuperuser</code></pre><p>运行 Django 开发服务器，检查是否可以使用管理站点添加 <code>Question</code> 和 <code>Choice</code> 对象。</p><h4 id="513-更新课程详细信息模板"><a class="markdownIt-Anchor" href="#513-更新课程详细信息模板"></a> 5.1.3. 更新课程详细信息模板</h4><p>现在，您将更新课程详情模板，创建一个包含问题和选项列表的考试部分。一次考试包含多个问题，每个问题都应该有一个以上的正确答案（多选）。</p><p>更改将在 <code>templates/onlinecourse/course_details_bootstrap.html</code> 中进行。</p><p>如果用户已通过身份验证，则显示带有问题和选项列表的课程考试：</p><pre><code class="language-html">{% if user.is_authenticated %}&lt;/br&gt;&lt;!-- Remaining code will go here --&gt;{% endif %}</code></pre><p>添加一个开始考试的按钮：</p><pre><code class="language-html">&lt;button class="btn btn-primary btn-block" data-toggle="collapse" data-target="#exam"&gt;Start Exam&lt;/button&gt;</code></pre><p>添加一个可折叠 <code>div</code>：</p><pre><code class="language-html">&lt;div id="exam" class="collapse"&gt;&lt;/div&gt;</code></pre><p>在表单中添加 <code>Question</code> 逻辑：</p><pre><code class="language-html">&lt;div id="exam" class="collapse"&gt;   &lt;form id="questionform" action="{% url 'onlinecourse:submit' course.id %}" method="POST"&gt;       {% for question in course.question_set.all %}           &lt;!-- Question UI components will go here --&gt;       {% endfor %}   &lt;/form&gt;&lt;/div&gt;</code></pre><p>添加 <code>Quesion</code> UI：</p><pre><code class="language-html">&lt;div class="card mt-1"&gt;   &lt;div class="card-header"&gt;&lt;h5&gt;{{ question.content }}&lt;/h5&gt;&lt;/div&gt;   {% csrf_token %}   &lt;div class="form-group"&gt;       &lt;!-- Choices components go here --&gt;   &lt;/div&gt;&lt;/div&gt;</code></pre><p>添加 <code>Choices</code> 组件：</p><pre><code class="language-html">{% for choice in question.choice_set.all %}&lt;div class="form-check"&gt;   &lt;label class="form-check-label"&gt;       &lt;input type="checkbox" name="choice_{{choice.id}}"              class="form-check-input" id="{{choice.id}}"              value="{{choice.id}}"&gt;{{ choice.content }}   &lt;/label&gt;&lt;/div&gt;{% endfor %}</code></pre><h4 id="514-提交评估"><a class="markdownIt-Anchor" href="#514-提交评估"></a> 5.1.4. 提交评估</h4><p>由于您已创建了多个新模型，因此现在需要在 <code>views.py</code> 的顶部导入它们。</p><pre><code class="language-python">from .models import Course, Enrollment, Question, Choice, Submission</code></pre><p>现在，您将为表单提交创建一个基于函数的视图。创建提交视图 <code>def submit(request,course_id)</code> 来为课程注册创建考试提交记录。您可以根据以下逻辑来实现它：</p><ul><li>获取当前用户和课程对象，然后获取相关的注册对象</li><li>参照注册信息创建一个新的提交对象</li><li>从 HTTP 请求对象中收集所选选项</li><li>将每个选定的选择对象添加到提交对象中</li><li>使用提交 ID 重定向到 <code>show_exam_result</code> 视图，以显示考试结果</li><li>配置 <code>urls.py</code> 以路由新的提交视图</li></ul><pre><code class="language-python">def submit(request, course_id):    course = get_object_or_404(Course, pk=course_id)    user = request.user    enrollment = Enrollment.objects.get(user=user, course=course)    submission = Submission.objects.create(enrollment=enrollment)    choices = extract_answers(request)    submission.choices.set(choices)    submission_id = submission.id    return HttpResponseRedirect(reverse(viewname='onlinecourse:exam_result', args=(course_id, submission_id,)))</code></pre><p>在 <code>urls.py</code> 中路由提交视图按钮：</p><pre><code class="language-python">path('&lt;int:course_id&gt;/submit/', views.submit, name="submit"),</code></pre><h4 id="515-评估视图"><a class="markdownIt-Anchor" href="#515-评估视图"></a> 5.1.5. 评估视图</h4><p>创建考试结果视图 <code>def show_exam_result(request,course_id,submission_id)</code> 来检查学员是否通过考试以及他们的答题结果。您可以根据以下逻辑实现视图：</p><ul><li>根据视图参数中的 id 获取课程对象和提交对象</li><li>从提交记录中获取所选选项的 id</li><li>检查每个所选选项是否为正确答案</li><li>将课程中所有问题的分数相加，计算总分</li><li>将课程、选项和成绩添加到上下文中，以便渲染 HTML 页面</li><li>配置 <code>urls.py</code> 以路由新的 <code>show_exam_result</code> 视图</li></ul><pre><code class="language-python">def show_exam_result(request, course_id, submission_id):    context = {}    course = get_object_or_404(Course, pk=course_id)    submission = Submission.objects.get(id=submission_id)    choices = submission.choices.all()    total_score = 0    for choice in choices:        if choice.is_correct:            total_score += choice.question.grade    context['course'] = course    context['grade'] = total_score    context['choices'] = choices    return render(request, 'onlinecourse/exam_result_bootstrap.html', context)</code></pre><h4 id="516-完成考试结果模板以显示考试提交结果"><a class="markdownIt-Anchor" href="#516-完成考试结果模板以显示考试提交结果"></a> 5.1.6. 完成考试结果模板以显示考试提交结果</h4><p>完成用于提交结果的 <code>exam_result_bootstrap.html</code> HTML 模板，该模板应显示学员是否通过考试，并提供总分、每道题的成绩等详细信息。</p><p>使用 Bootstrap 对更新后的模板进行样式调整，以符合设计团队的用户界面设计。</p><p>通过考试的学员应看到最终分数和祝贺信息：</p><pre><code class="language-html">&lt;b&gt;Congratulations, {{ user.first_name }}!&lt;/b&gt; You have passed the exam and completed the course with score {{ grade }}/100</code></pre><p>对于考试不及格的学员，应向其显示最终分数和错误选项。应允许学员重考并重新提交：</p><pre><code class="language-html">&lt;b&gt;Failed&lt;/b&gt; Sorry, {{ user.first_name }}! You have failed the exam with score {{ grade }}/100</code></pre><p>您还必须显示考试成绩，以便学员了解自己的成绩：</p><pre><code class="language-html">{% for question in course.question_set.all %}&lt;div class="card mt-1"&gt;    &lt;div class="card-header"&gt;&lt;h5&gt;{{ question.content }}&lt;/h5&gt;&lt;/div&gt;    &lt;div class="form-group"&gt;        {% for choice in question.choice_set.all %}        &lt;div class="form-check"&gt;            {% if choice.is_correct and choice in choices %}            &lt;div class="text-success"&gt;Correct answer: {{ choice.content }}&lt;/div&gt;            {% else %}{% if choice.is_correct and not choice in choices %}            &lt;div class="text-warning"&gt;Not selected: {{ choice.content }}&lt;/div&gt;            {% else %}{% if not choice.is_correct and choice in choices %}            &lt;div class="text-danger"&gt;Wrong answer: {{ choice.content }}&lt;/div&gt;            {% else %}            &lt;div&gt;{{ choice.content }}&lt;/div&gt;            {% endif %}{% endif %}{% endif %}        &lt;/div&gt;        {% endfor %}    &lt;/div&gt;&lt;/div&gt;{% endfor %}</code></pre></body></html>]]></content>
    
    
    <summary type="html">本文是 IBM 全栈开发课程的第九篇学习笔记，内容涵盖数据库基础与 Python Django 框架的实战应用。笔记首先对比了关系型（RDBMS）与四种主流 NoSQL 数据库的特点，随后重点讲解了 Django 框架及其强大的对象关系映射（ORM）功能，演示了如何用 Python 模型替代原生 SQL 进行增删查改（CRUD）操作。最后，通过一个完整的在线课程项目，手把手教你如何为 Django 应用添加考试功能，内容涉及模型设计、后台管理、视图逻辑编写和前端模板渲染，提供了一条从数据库理论到全栈开发的清晰学习路径。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Python" scheme="https://blog.cytrogen.icu/tags/Python/"/>
    
    <category term="IBM" scheme="https://blog.cytrogen.icu/tags/IBM/"/>
    
    <category term="Django" scheme="https://blog.cytrogen.icu/tags/Django/"/>
    
    <category term="SQL" scheme="https://blog.cytrogen.icu/tags/SQL/"/>
    
  </entry>
  
  <entry>
    <title>Hexo 源代码分析【1】：入口文件</title>
    <link href="https://blog.cytrogen.icu/posts/5d57.html"/>
    <id>https://blog.cytrogen.icu/posts/5d57.html</id>
    <published>2024-05-26T05:00:00.000Z</published>
    <updated>2026-02-09T17:16:54.713Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>使用 Hexo，痛骂 Hexo，理解 Hexo，成为 Hexo。</p><p>这篇文章是用来记录我阅读 Hexo 源代码的过程和分析。</p><span id="more"></span><h1 id="版本号"><a class="markdownIt-Anchor" href="#版本号"></a> 版本号</h1><p>文章写的时候，Hexo 的版本为 <strong>7.2.0</strong>：</p><pre><code class="language-json">{  "name": "hexo",  "version": "7.2.0",  "description": "A fast, simple &amp; powerful blog framework, powered by Node.js.",  "main": "dist/hexo",  "bin": {    "hexo": "./bin/hexo"  },  "scripts": {    "prepublishOnly": "npm install &amp;&amp; npm run clean &amp;&amp; npm run build",    "build": "tsc -b",    "clean": "tsc -b --clean",    "eslint": "eslint lib test",    "pretest": "npm run clean &amp;&amp; npm run build",    "test": "mocha test/scripts/**/*.ts --require ts-node/register",    "test-cov": "c8 --reporter=lcovonly npm test -- --no-parallel",    "prepare": "husky install"  },  "files": [    "dist/",    "bin/"  ],  "types": "./dist/hexo/index.d.ts",  "repository": "hexojs/hexo",  "homepage": "https://hexo.io/",  "funding": {    "type": "opencollective",    "url": "https://opencollective.com/hexo"  },  "keywords": [    "website",    "blog",    "cms",    "framework",    "hexo"  ],  "author": "Tommy Chen &lt;tommy351@gmail.com&gt; (https://zespia.tw)",  "maintainers": [    "Abner Chou &lt;hi@abnerchou.me&gt; (https://abnerchou.me)"  ],  "license": "MIT",  "dependencies": {    "abbrev": "^2.0.0",    "archy": "^1.0.0",    "bluebird": "^3.7.2",    "hexo-cli": "^4.3.2",    "hexo-front-matter": "^4.2.1",    "hexo-fs": "^4.1.3",    "hexo-i18n": "^2.0.0",    "hexo-log": "^4.0.1",    "hexo-util": "^3.3.0",    "js-yaml": "^4.1.0",    "js-yaml-js-types": "^1.0.0",    "micromatch": "^4.0.4",    "moize": "^6.1.6",    "moment": "^2.29.1",    "moment-timezone": "^0.5.34",    "nunjucks": "^3.2.3",    "picocolors": "^1.0.0",    "pretty-hrtime": "^1.0.3",    "resolve": "^1.22.0",    "strip-ansi": "^6.0.0",    "text-table": "^0.2.0",    "tildify": "^2.0.0",    "titlecase": "^1.1.3",    "warehouse": "^5.0.1"  },  "devDependencies": {    "0x": "^5.1.2",    "@types/abbrev": "^1.1.3",    "@types/bluebird": "^3.5.37",    "@types/chai": "^4.3.11",    "@types/js-yaml": "^4.0.9",    "@types/mocha": "^10.0.6",    "@types/node": "^18.11.8 &lt;18.19.9",    "@types/nunjucks": "^3.2.2",    "@types/rewire": "^2.5.30",    "@types/sinon": "^17.0.3",    "@types/text-table": "^0.2.4",    "c8": "^9.0.0",    "chai": "^4.3.6",    "cheerio": "0.22.0",    "decache": "^4.6.1",    "eslint": "^8.48.0",    "eslint-config-hexo": "^5.0.0",    "hexo-renderer-marked": "^6.0.0",    "husky": "^8.0.1",    "lint-staged": "^15.2.0",    "mocha": "^10.0.0",    "rewire": "^7.0.0",    "sinon": "^17.0.1",    "ts-node": "^10.9.1",    "typescript": "^5.3.2"  },  "engines": {    "node": "&gt;=14"  }}</code></pre><p>Hexo 的入口文件是 <code>dist/hexo/index.js</code>，我们来看看这个文件：</p><div class="danger"><p>部分代码因为太长了，所以先注释掉，后续会拿出来说。</p></div><pre><code class="language-javascript">"use strict";var __importDefault = (this &amp;&amp; this.__importDefault) || function (mod) {  return (mod &amp;&amp; mod.__esModule) ? mod : { "default": mod };};const bluebird_1 = __importDefault(require("bluebird"));const path_1 = require("path");const tildify_1 = __importDefault(require("tildify"));const warehouse_1 = __importDefault(require("warehouse"));const picocolors_1 = require("picocolors");const events_1 = require("events");const hexo_fs_1 = require("hexo-fs");const module_1 = __importDefault(require("module"));const vm_1 = require("vm");const { version } = require('../../package.json');const hexo_log_1 = __importDefault(require("hexo-log"));const extend_1 = require("../extend");const render_1 = __importDefault(require("./render"));const register_models_1 = __importDefault(require("./register_models"));const post_1 = __importDefault(require("./post"));const scaffold_1 = __importDefault(require("./scaffold"));const source_1 = __importDefault(require("./source"));const router_1 = __importDefault(require("./router"));const theme_1 = __importDefault(require("../theme"));const locals_1 = __importDefault(require("./locals"));const default_config_1 = __importDefault(require("./default_config"));const load_database_1 = __importDefault(require("./load_database"));const multi_config_path_1 = __importDefault(require("./multi_config_path"));const hexo_util_1 = require("hexo-util");let resolveSync; // = require('resolve');const libDir = (0, path_1.dirname)(__dirname);const dbVersion = 1;const stopWatcher = (box) =&gt; { if (box.isWatching())  box.unwatch(); };const routeCache = new WeakMap();const castArray = (obj) =&gt; { return Array.isArray(obj) ? obj : [obj]; };const mergeCtxThemeConfig = (ctx) =&gt; { ... };const createLoadThemeRoute = function (generatorResult, locals, ctx) { ... };function debounce(func, wait) { ... }class Hexo extends events_1.EventEmitter { ... }Hexo.lib_dir = libDir + path_1.sep;Hexo.prototype.lib_dir = Hexo.lib_dir;Hexo.core_dir = (0, path_1.dirname)(libDir) + path_1.sep;Hexo.prototype.core_dir = Hexo.core_dir;Hexo.version = version;Hexo.prototype.version = Hexo.version;module.exports = Hexo;//# sourceMappingURL=index.js.map</code></pre><h1 id="hexo类"><a class="markdownIt-Anchor" href="#hexo类"></a> <code>Hexo</code> 类</h1><p>重点来看 <code>Hexo</code> 类的定义：</p><pre><code class="language-javascript">class Hexo extends events_1.EventEmitter {  constructor(base = process.cwd(), args = {}) { ... }  _bindLocals() { ... }  init() { ... }  call(name, args, callback) { ... }  model(name, schema) { ... }  resolvePlugin(name, basedir) { ... }  loadPlugin(path, callback) { ... }  _showDrafts() { ... }  load(callback) { ... }  watch(callback) { ... }  unwatch() { ... }  _generateLocals() { ... }  _runGenerators() { ... }  _routerRefresh(runningGenerators, useCache) { ... }  _generate(options = {}) { ... }  exit(err) { ... }  execFilter(type, data, options) { ... }  execFilterSync(type, data, options) { ... }}</code></pre><h2 id="构造函数"><a class="markdownIt-Anchor" href="#构造函数"></a> 构造函数</h2><pre><code class="language-javascript">constructor(base = process.cwd(), args = {}) {  super();  this.base_dir = base + path_1.sep;  this.public_dir = (0, path_1.join)(base, 'public') + path_1.sep;  this.source_dir = (0, path_1.join)(base, 'source') + path_1.sep;  this.plugin_dir = (0, path_1.join)(base, 'node_modules') + path_1.sep;  this.script_dir = (0, path_1.join)(base, 'scripts') + path_1.sep;  this.scaffold_dir = (0, path_1.join)(base, 'scaffolds') + path_1.sep;  this.theme_dir = (0, path_1.join)(base, 'themes', default_config_1.default.theme) + path_1.sep;  this.theme_script_dir = (0, path_1.join)(this.theme_dir, 'scripts') + path_1.sep;  this.env = {    args,    debug: Boolean(args.debug),    safe: Boolean(args.safe),    silent: Boolean(args.silent),    env: process.env.NODE_ENV || 'development',    version,    cmd: args._ ? args._[0] : '',    init: false  };  this.extend = {    console: new extend_1.Console(),    deployer: new extend_1.Deployer(),    filter: new extend_1.Filter(),    generator: new extend_1.Generator(),    helper: new extend_1.Helper(),    highlight: new extend_1.Highlight(),    injector: new extend_1.Injector(),    migrator: new extend_1.Migrator(),    processor: new extend_1.Processor(),    renderer: new extend_1.Renderer(),    tag: new extend_1.Tag()  };  this.config = Object.assign({}, default_config_1.default);  this.log = (0, hexo_log_1.default)(this.env);  this.render = new render_1.default(this);  this.route = new router_1.default();  this.post = new post_1.default(this);  this.scaffold = new scaffold_1.default(this);  this._dbLoaded = false;  this._isGenerating = false;  const dbPath = args.output || base;  if (/^(init|new|g|publish|s|deploy|render|migrate)/.test(this.env.cmd)) {    this.log.d(`Writing database to ${(0, path_1.join)(dbPath, 'db.json')}`);  }  this.database = new warehouse_1.default({    version: dbVersion,    path: (0, path_1.join)(dbPath, 'db.json')  });  const mcp = (0, multi_config_path_1.default)(this);  this.config_path = args.config ? mcp(base, args.config, args.output)    : (0, path_1.join)(base, '_config.yml');  (0, register_models_1.default)(this);  this.source = new source_1.default(this);  this.theme = new theme_1.default(this);  this.locals = new locals_1.default();  this._bindLocals();}</code></pre><h4 id="路径"><a class="markdownIt-Anchor" href="#路径"></a> 路径</h4><pre><code class="language-javascript">this.base_dir = base + path_1.sep;this.public_dir = (0, path_1.join)(base, 'public') + path_1.sep;this.source_dir = (0, path_1.join)(base, 'source') + path_1.sep;this.plugin_dir = (0, path_1.join)(base, 'node_modules') + path_1.sep;this.script_dir = (0, path_1.join)(base, 'scripts') + path_1.sep;this.scaffold_dir = (0, path_1.join)(base, 'scaffolds') + path_1.sep;this.theme_dir = (0, path_1.join)(base, 'themes', default_config_1.default.theme) + path_1.sep;this.theme_script_dir = (0, path_1.join)(this.theme_dir, 'scripts') + path_1.sep;</code></pre><ul><li><code>base_dir</code>：项目的基础目录</li><li><code>public_dir</code>：项目生成的静态文件存放的目录（<code>./public</code>），当运行 <code>hexo generate</code> 时生成的所有静态文件都会被放在这个目录下</li><li><code>source_dir</code>：Markdown 文章（<code>./source</code>）</li><li><code>plugin_dir</code>：插件（<code>./node_modules</code>），Hexo 的插件机制基于 Node.js 的模块系统</li><li><code>script_dir</code>：脚本（<code>./scripts</code>），Hexo 启动时会自动执行这些 JavaScript 文件</li><li><code>scaffold_dir</code>：脚手架（<code>./scaffolds</code>）是一种模板，可以用它快速创建新的文章</li><li><code>theme_dir</code>：主题（<code>./themes</code>）<ul><li><code>theme_script_dir</code>：类似于脚本（<code>./themes/scripts</code>）</li></ul></li></ul><h4 id="环境信息"><a class="markdownIt-Anchor" href="#环境信息"></a> 环境信息</h4><pre><code class="language-javascript">this.env = {  args,  debug: Boolean(args.debug),  safe: Boolean(args.safe),  silent: Boolean(args.silent),  env: process.env.NODE_ENV || 'development',  version,  cmd: args._ ? args._[0] : '',  init: false};</code></pre><p>包含了关于 Hexo 运行环境的信息，如调试模式、安全模式、静默模式、环境变量、版本号、命令、是否初始化等。</p><h4 id="扩展"><a class="markdownIt-Anchor" href="#扩展"></a> 扩展</h4><pre><code class="language-javascript">this.extend = {  console: new extend_1.Console(),  deployer: new extend_1.Deployer(),  filter: new extend_1.Filter(),  generator: new extend_1.Generator(),  helper: new extend_1.Helper(),  highlight: new extend_1.Highlight(),  injector: new extend_1.Injector(),  migrator: new extend_1.Migrator(),  processor: new extend_1.Processor(),  renderer: new extend_1.Renderer(),  tag: new extend_1.Tag()};</code></pre><p>这些是 Hexo 的核心组件，以后会详细介绍。</p><blockquote><p>其实可以先行阅读 <a href="https://hexo.io/zh-cn/api/">Hexo 官方文档</a>，虽然初次看可能很难看懂，但是看了总是会在未来的某个时刻头脑一亮埋下伏笔。</p></blockquote><h4 id="配置"><a class="markdownIt-Anchor" href="#配置"></a> 配置</h4><pre><code class="language-javascript">this.config = Object.assign({}, default_config_1.default);</code></pre><p>默认配置的内容：</p><pre><code class="language-javascript">"use strict";module.exports = {    title: 'Hexo',    subtitle: '',    description: '',    author: 'John Doe',    language: 'en',    timezone: '',    url: 'http://example.com',    root: '/',    permalink: ':year/:month/:day/:title/',    permalink_defaults: {},    pretty_urls: {        trailing_index: true,        trailing_html: true    },    source_dir: 'source',    public_dir: 'public',    tag_dir: 'tags',    archive_dir: 'archives',    category_dir: 'categories',    code_dir: 'downloads/code',    i18n_dir: ':lang',    skip_render: [],    new_post_name: ':title.md',    default_layout: 'post',    titlecase: false,    external_link: {        enable: true,        field: 'site',        exclude: ''    },    filename_case: 0,    render_drafts: false,    post_asset_folder: false,    relative_link: false,    future: true,    syntax_highlighter: 'highlight.js',    highlight: {        auto_detect: false,        line_number: true,        tab_replace: '',        wrap: true,        exclude_languages: [],        language_attr: false,        hljs: false,        line_threshold: 0,        first_line_number: 'always1',        strip_indent: true    },    prismjs: {        preprocess: true,        line_number: true,        tab_replace: '',        exclude_languages: [],        strip_indent: true    },    default_category: 'uncategorized',    category_map: {},    tag_map: {},    date_format: 'YYYY-MM-DD',    time_format: 'HH:mm:ss',    updated_option: 'mtime',    per_page: 10,    pagination_dir: 'page',    theme: 'landscape',    server: {        cache: false    },    deploy: {},    ignore: [],    meta_generator: true};//# sourceMappingURL=default_config.js.map</code></pre><p>看着很熟悉吧，这些配置项都是我们初始化 Hexo 项目时，出现在根目录的 <code>_config.yml</code> 内的配置项。</p><blockquote><p>可见 <a href="https://hexo.io/zh-cn/docs/configuration">Hexo 官方文档</a>。</p></blockquote><h4 id="日志"><a class="markdownIt-Anchor" href="#日志"></a> 日志</h4><pre><code class="language-javascript">this.log = (0, hexo_log_1.default)(this.env);</code></pre><p>这里的 <code>hexo_log_1</code> 是：</p><pre><code class="language-javascript">const hexo_log_1 = __importDefault(require("hexo-log"));</code></pre><p><a href="https://github.com/hexojs/hexo-log"><img src="https://gh-card.dev/repos/hexojs/hexo-log.svg" alt="hexojs/hexo-log - GitHub" loading="lazy"></a></p><p><code>index.js</code> 中大量的导入变量都是这样命名的。</p><h4 id="渲染"><a class="markdownIt-Anchor" href="#渲染"></a> 渲染</h4><pre><code class="language-javascript">this.render = new render_1.default(this);</code></pre><blockquote><p>可见 <a href="https://hexo.io/zh-cn/api/rendering">Hexo 官方文档</a>。</p></blockquote><pre><code class="language-javascript">"use strict";var __importDefault = (this &amp;&amp; this.__importDefault) || function (mod) {    return (mod &amp;&amp; mod.__esModule) ? mod : { "default": mod };};const path_1 = require("path");const bluebird_1 = __importDefault(require("bluebird"));const hexo_fs_1 = require("hexo-fs");const getExtname = (str) =&gt; {    if (typeof str !== 'string')        return '';    const ext = (0, path_1.extname)(str);    return ext.startsWith('.') ? ext.slice(1) : ext;};const toString = (result, options) =&gt; {    if (!Object.prototype.hasOwnProperty.call(options, 'toString') || typeof result === 'string')        return result;    if (typeof options.toString === 'function') {        return options.toString(result);    }    else if (typeof result === 'object') {        return JSON.stringify(result);    }    else if (result.toString) {        return result.toString();    }    return result;};class Render {    constructor(ctx) {        this.context = ctx;        this.renderer = ctx.extend.renderer;    }    isRenderable(path) {        return this.renderer.isRenderable(path);    }    isRenderableSync(path) {        return this.renderer.isRenderableSync(path);    }    getOutput(path) {        return this.renderer.getOutput(path);    }    getRenderer(ext, sync) {        return this.renderer.get(ext, sync);    }    getRendererSync(ext) {        return this.getRenderer(ext, true);    }    render(data, options, callback) {        if (!callback &amp;&amp; typeof options === 'function') {            callback = options;            options = {};        }        const ctx = this.context;        let ext = '';        let promise;        if (!data)            return bluebird_1.default.reject(new TypeError('No input file or string!'));        if (data.text != null) {            promise = bluebird_1.default.resolve(data.text);        }        else if (!data.path) {            return bluebird_1.default.reject(new TypeError('No input file or string!'));        }        else {            promise = (0, hexo_fs_1.readFile)(data.path);        }        return promise.then(text =&gt; {            data.text = text;            ext = data.engine || getExtname(data.path);            if (!ext || !this.isRenderable(ext))                return text;            const renderer = this.getRenderer(ext);            return Reflect.apply(renderer, ctx, [data, options]);        }).then(result =&gt; {            result = toString(result, data);            if (data.onRenderEnd) {                return data.onRenderEnd(result);            }            return result;        }).then(result =&gt; {            const output = this.getOutput(ext) || ext;            return ctx.execFilter(`after_render:${output}`, result, {                context: ctx,                args: [data]            });        }).asCallback(callback);    }    renderSync(data, options = {}) {        if (!data)            throw new TypeError('No input file or string!');        const ctx = this.context;        if (data.text == null) {            if (!data.path)                throw new TypeError('No input file or string!');            data.text = (0, hexo_fs_1.readFileSync)(data.path);        }        if (data.text == null)            throw new TypeError('No input file or string!');        const ext = data.engine || getExtname(data.path);        let result;        if (ext &amp;&amp; this.isRenderableSync(ext)) {            const renderer = this.getRendererSync(ext);            result = Reflect.apply(renderer, ctx, [data, options]);        }        else {            result = data.text;        }        const output = this.getOutput(ext) || ext;        result = toString(result, data);        if (data.onRenderEnd) {            result = data.onRenderEnd(result);        }        return ctx.execFilterSync(`after_render:${output}`, result, {            context: ctx,            args: [data]        });    }}module.exports = Render;//# sourceMappingURL=render.js.map</code></pre><blockquote><p><code>bluebird</code> 库是一个流行的 JavaScript Promise 库，它提供了一种更加健壮、高效和优雅的方式来处理异步操作。</p><p>在传统的基于回调函数的异步编程中，存在着回调地狱、代码耦合等问题。Promise 的出现解决了这些问题，使着异步代码更加易于理解和维护。而 <code>bluebird</code> 在 Promise 的基础上提供了更多的增强功能和优化。</p></blockquote><p><a href="https://github.com/petkaantonov/bluebird"><img src="https://gh-card.dev/repos/petkaantonov/bluebird.svg" alt="petkaantonov/bluebird - GitHub" loading="lazy"></a></p><p><code>Render</code> 类包含两个主要方法：<code>render</code> 和 <code>renderSync</code>。</p><ol><li><code>render</code> 方法是一个异步方法，首先检查文件是否可根据其扩展名进行渲染。如果可以，它会获取相应的渲染器并将其应用于数据。渲染后的结果将通过一个过滤器，并在回调函数中返回。</li><li><code>renderSync</code> 方法是 <code>render</code> 的同步版本。工作方式类似，但使用同步文件读取，并使用异常代替回调和 Promise 处理错误。</li></ol><p>其他部分包括：</p><ul><li><code>getExtname</code> 是一个辅助函数，用于从文件路径中提取文件扩展名。</li><li><code>toString</code> 是一个辅助函数，根据提供的选项将结果对象转换为字符串表示。</li><li><code>Render</code> 类的构造函数接收 <code>Hexo</code> 上下文 <code>ctx</code>，并从中初始化 <code>renderer</code> 属性。</li><li><code>isRenderable</code> 和 <code>isRenderableSync</code> 方法检查给定扩展名的文件是否可渲染。</li><li><code>getOutput</code> 方法获取给定输入扩展名的输出扩展名。</li><li><code>getRenderer</code> 和 <code>getRendererSync</code> 方法获取给定扩展名的相应渲染器。</li></ul><p>这段代码为 Hexo 提供了一种基于文件扩展名渲染文件的方式，使用每种扩展名对应的渲染器。</p><h4 id="路由"><a class="markdownIt-Anchor" href="#路由"></a> 路由</h4><pre><code class="language-javascript">this.route = new router_1.default();</code></pre><p>这行代码实例化了 <code>Router</code> 类的对象，用于管理路由。在 <a href="https://hexo.io/zh-cn/api/router">Hexo 官方文档</a> 中，路由是 <strong>存储了网站中所用到的所有路径</strong>。</p><pre><code class="language-javascript">"use strict";var __importDefault = (this &amp;&amp; this.__importDefault) || function (mod) {    return (mod &amp;&amp; mod.__esModule) ? mod : { "default": mod };};const events_1 = require("events");const bluebird_1 = __importDefault(require("bluebird"));const stream_1 = __importDefault(require("stream"));const { Readable } = stream_1.default;class RouteStream extends Readable {    constructor(data) {        super({ objectMode: true });        this._data = data.data;        this._ended = false;        this.modified = data.modified;    }    // Assume we only accept Buffer, plain object, or string    _toBuffer(data) {        if (data instanceof Buffer) {            return data;        }        if (typeof data === 'object') {            data = JSON.stringify(data);        }        if (typeof data === 'string') {            return Buffer.from(data); // Assume string is UTF-8 encoded string        }        return null;    }    _read() {        const data = this._data;        if (typeof data !== 'function') {            const bufferData = this._toBuffer(data);            if (bufferData) {                this.push(bufferData);            }            this.push(null);            return;        }        // Don't read it twice!        if (this._ended)            return false;        this._ended = true;        data().then(data =&gt; {            if (data instanceof stream_1.default &amp;&amp; data.readable) {                data.on('data', d =&gt; {                    this.push(d);                });                data.on('end', () =&gt; {                    this.push(null);                });                data.on('error', err =&gt; {                    this.emit('error', err);                });            }            else {                const bufferData = this._toBuffer(data);                if (bufferData) {                    this.push(bufferData);                }                this.push(null);            }        }).catch(err =&gt; {            this.emit('error', err);            this.push(null);        });    }}const _format = (path) =&gt; {    path = path || '';    if (typeof path !== 'string')        throw new TypeError('path must be a string!');    path = path        .replace(/^\/+/, '') // Remove prefixed slashes        .replace(/\\/g, '/') // Replaces all backslashes        .replace(/\?.*$/, ''); // Remove query string    // Appends `index.html` to the path with trailing slash    if (!path || path.endsWith('/')) {        path += 'index.html';    }    return path;};class Router extends events_1.EventEmitter {    constructor() {        super();        this.routes = {};    }    list() {        const { routes } = this;        return Object.keys(routes).filter(key =&gt; routes[key]);    }    format(path) {        return _format(path);    }    get(path) {        if (typeof path !== 'string')            throw new TypeError('path must be a string!');        const data = this.routes[this.format(path)];        if (data == null)            return;        return new RouteStream(data);    }    isModified(path) {        if (typeof path !== 'string')            throw new TypeError('path must be a string!');        const data = this.routes[this.format(path)];        return data ? data.modified : false;    }    set(path, data) {        if (typeof path !== 'string')            throw new TypeError('path must be a string!');        if (data == null)            throw new TypeError('data is required!');        let obj;        if (typeof data === 'object' &amp;&amp; data.data != null) {            obj = data;        }        else {            obj = {                data,                modified: true            };        }        if (typeof obj.data === 'function') {            if (obj.data.length) {                obj.data = bluebird_1.default.promisify(obj.data);            }            else {                obj.data = bluebird_1.default.method(obj.data);            }        }        path = this.format(path);        this.routes[path] = {            data: obj.data,            modified: obj.modified == null ? true : obj.modified        };        this.emit('update', path);        return this;    }    remove(path) {        if (typeof path !== 'string')            throw new TypeError('path must be a string!');        path = this.format(path);        this.routes[path] = null;        this.emit('remove', path);        return this;    }}module.exports = Router;//# sourceMappingURL=router.js.map</code></pre><p>这段代码定义了一个名为 <code>Router</code> 的类和一个名为 <code>RouteStream</code> 的类。它们在 Hexo 框架中用于管理路由和从路由读取数据流。</p><p><code>RouteStream</code> 类：</p><ul><li>继承自 Node.js 内置的 <code>stream.Readable</code> 类，因此它是一个可读流。</li><li>构造函数接收一个 <code>data</code> 对象，该对象包含 <code>data</code> 属性和 <code>modified</code> 属性。</li><li><code>_read()</code> 方法是可读流的实现。如果 <code>data</code> 是一个函数，它会尝试从该函数中获取数据。否则，它会将 <code>data</code> 推送到流中。</li><li><code>_toBuffer()</code> 是一个内部方法，用于将数据转换为 <code>Buffer</code>。</li></ul><p><code>Router</code> 类：</p><ul><li>继承自 <code>EventEmitter</code>，因此可以发射和监听事件。</li><li><code>routes</code> 属性是一个对象，用于存储路径及其对应的数据。</li><li><code>list()</code> 方法返回所有已注册路径的列表。</li><li><code>format(path)</code> 方法用于格式化路径，移除前导斜杠、替换反斜杠，并为以斜杠结尾的路径添加 <code>index.html</code>。</li><li><code>get(path)</code> 方法用于获取给定路径的数据流。如果路径不存在或数据为 <code>null</code>，则返回 <code>undefined</code>。</li><li><code>isModified(path)</code> 方法用于检查给定路径的数据是否已修改。</li><li><code>set(path, data)</code> 方法用于设置给定路径的数据。如果 <code>data</code> 是一个函数，它会使用 <code>Bluebird</code> 库将其转换为 Promise。该方法还会触发 <code>update</code> 事件。</li><li><code>remove(path)</code> 方法用于移除给定路径的数据。它会将路径对应的值设置为 <code>null</code>，并触发 <code>remove</code> 事件。</li></ul><blockquote><p>Node.js 的 <code>EventEmitter</code> 是一个模块，提供基于事件驱动的编程方式，是 Node.js 很多核心模块和第三方模块的基础，也是 Node.js 中非常重要的一个概念和设计模式。</p><p><code>EventEmitter</code> 是一个构造函数，可以创建一个新的事件发射器对象。这个对象可以发射命名事件，并且可以通过添加事件监听器来监听特定事件。当事件被发射时，所有监听该事件的函数回调都会被同步地调用。</p><p><code>EventEmitter</code> 对象有以下常用方法：</p><ol><li><code>emitter.on(eventName, listener)</code> 为指定事件注册一个监听器。</li><li><code>emitter.once(eventName, listener)</code> 为指定事件注册一个一次性的监听器，触发后就会被移除。</li><li><code>emitter.off(eventName, listener)</code> 移除指定事件的监听器。</li><li><code>emitter.emit(eventName, [...args])</code> 发射指定事件，传递参数给监听器回调函数。</li></ol><p><a href="https://hexo.io/zh-cn/api/events">Hexo 官方文档</a> 中也提到了 <code>EventEmitter</code>。</p></blockquote><h4 id="博客文章"><a class="markdownIt-Anchor" href="#博客文章"></a> 博客文章</h4><pre><code class="language-javascript">this.post = new post_1.default(this);</code></pre><blockquote><p>可见 <a href="https://hexo.io/zh-cn/api/posts">Hexo 官方文档</a>。</p></blockquote><div class="danger"><p><code>post.js</code> 很长，因此将部分代码分开讲解。</p></div><pre><code class="language-javascript">"use strict";var __importDefault = (this &amp;&amp; this.__importDefault) || function (mod) {    return (mod &amp;&amp; mod.__esModule) ? mod : { "default": mod };};const assert_1 = __importDefault(require("assert"));const moment_1 = __importDefault(require("moment"));const bluebird_1 = __importDefault(require("bluebird"));const path_1 = require("path");const picocolors_1 = require("picocolors");const js_yaml_1 = require("js-yaml");const hexo_util_1 = require("hexo-util");const hexo_fs_1 = require("hexo-fs");const hexo_front_matter_1 = require("hexo-front-matter");const preservedKeys = ['title', 'slug', 'path', 'layout', 'date', 'content'];const rHexoPostRenderEscape = /&lt;hexoPostRenderCodeBlock&gt;([\s\S]+?)&lt;\/hexoPostRenderCodeBlock&gt;/g;const rSwigPlaceHolder = /(?:&lt;|&amp;lt;)!--swig\uFFFC(\d+)--(?:&gt;|&amp;gt;)/g;const rCodeBlockPlaceHolder = /(?:&lt;|&amp;lt;)!--code\uFFFC(\d+)--(?:&gt;|&amp;gt;)/g;const STATE_PLAINTEXT = Symbol('plaintext');const STATE_SWIG_VAR = Symbol('swig_var');const STATE_SWIG_COMMENT = Symbol('swig_comment');const STATE_SWIG_TAG = Symbol('swig_tag');const STATE_SWIG_FULL_TAG = Symbol('swig_full_tag');const isNonWhiteSpaceChar = (char) =&gt; char !== '\r'    &amp;&amp; char !== '\n'    &amp;&amp; char !== '\t'    &amp;&amp; char !== '\f'    &amp;&amp; char !== '\v'    &amp;&amp; char !== ' ';</code></pre><p><code>PostRenderEscape</code> 类用于处理 Swig / Nunjucks 标签和代码块的转义和还原：</p><blockquote><p>Swig 和 Nunjucks 是两种流行的模板引擎。</p><p>主要语法包括：</p><ul><li><code>{% ... %}</code>：用于执行语句，如条件语句和循环语句。</li><li><code>{{ ... }}</code>：用于输出变量值。</li></ul><p>在渲染文章内容时，Hexo 需要先对 Swig / Nunjucks 标签和代码块进行转义，防止被误解析，然后再使用相应的渲染器（如 Markdown）进行渲染。渲染完成后，需要将转义的内容还原回来。</p></blockquote><pre><code class="language-javascript">class PostRenderEscape {    constructor() {        this.stored = [];    }    static escapeContent(cache, flag, str) {        return `&lt;!--${flag}\uFFFC${cache.push(str) - 1}--&gt;`;    }    static restoreContent(cache) {        return (_, index) =&gt; {            (0, assert_1.default)(cache[index]);            const value = cache[index];            cache[index] = null;            return value;        };    }    restoreAllSwigTags(str) {        const restored = str.replace(rSwigPlaceHolder, PostRenderEscape.restoreContent(this.stored));        return restored;    }    restoreCodeBlocks(str) {        return str.replace(rCodeBlockPlaceHolder, PostRenderEscape.restoreContent(this.stored));    }    escapeCodeBlocks(str) {        return str.replace(rHexoPostRenderEscape, (_, content) =&gt; PostRenderEscape.escapeContent(this.stored, 'code', content));    }    /**     * @param {string} str     * @returns string     */    escapeAllSwigTags(str) {        if (!/(\{\{.+?\}\})|(\{#.+?#\})|(\{%.+?%\})/s.test(str)) {            return str;        }        let state = STATE_PLAINTEXT;        let buffer = '';        let output = '';        let swig_tag_name_begin = false;        let swig_tag_name_end = false;        let swig_tag_name = '';        let swig_full_tag_start_buffer = '';        const { length } = str;        for (let idx = 0; idx &lt; length; idx++) {            const char = str[idx];            const next_char = str[idx + 1];            if (state === STATE_PLAINTEXT) { // From plain text to swig                if (char === '{') {                    // check if it is a complete tag {{ }}                    if (next_char === '{') {                        state = STATE_SWIG_VAR;                        idx++;                    }                    else if (next_char === '#') {                        state = STATE_SWIG_COMMENT;                        idx++;                    }                    else if (next_char === '%') {                        state = STATE_SWIG_TAG;                        idx++;                        swig_tag_name = '';                        swig_full_tag_start_buffer = '';                        swig_tag_name_begin = false; // Mark if it is the first non white space char in the swig tag                        swig_tag_name_end = false;                    }                    else {                        output += char;                    }                }                else {                    output += char;                }            }            else if (state === STATE_SWIG_TAG) {                if (char === '%' &amp;&amp; next_char === '}') { // From swig back to plain text                    idx++;                    if (swig_tag_name !== '' &amp;&amp; str.includes(`end${swig_tag_name}`)) {                        state = STATE_SWIG_FULL_TAG;                    }                    else {                        swig_tag_name = '';                        state = STATE_PLAINTEXT;                        output += PostRenderEscape.escapeContent(this.stored, 'swig', `{%${buffer}%}`);                    }                    buffer = '';                }                else {                    buffer = buffer + char;                    swig_full_tag_start_buffer = swig_full_tag_start_buffer + char;                    if (isNonWhiteSpaceChar(char)) {                        if (!swig_tag_name_begin &amp;&amp; !swig_tag_name_end) {                            swig_tag_name_begin = true;                        }                        if (swig_tag_name_begin) {                            swig_tag_name += char;                        }                    }                    else {                        if (swig_tag_name_begin === true) {                            swig_tag_name_begin = false;                            swig_tag_name_end = true;                        }                    }                }            }            else if (state === STATE_SWIG_VAR) {                if (char === '}' &amp;&amp; next_char === '}') {                    idx++;                    state = STATE_PLAINTEXT;                    output += PostRenderEscape.escapeContent(this.stored, 'swig', `{{${buffer}}}`);                    buffer = '';                }                else {                    buffer = buffer + char;                }            }            else if (state === STATE_SWIG_COMMENT) { // From swig back to plain text                if (char === '#' &amp;&amp; next_char === '}') {                    idx++;                    state = STATE_PLAINTEXT;                    buffer = '';                }            }            else if (state === STATE_SWIG_FULL_TAG) {                if (char === '{' &amp;&amp; next_char === '%') {                    let swig_full_tag_end_buffer = '';                    let _idx = idx + 2;                    for (; _idx &lt; length; _idx++) {                        const _char = str[_idx];                        const _next_char = str[_idx + 1];                        if (_char === '%' &amp;&amp; _next_char === '}') {                            _idx++;                            break;                        }                        swig_full_tag_end_buffer = swig_full_tag_end_buffer + _char;                    }                    if (swig_full_tag_end_buffer.includes(`end${swig_tag_name}`)) {                        state = STATE_PLAINTEXT;                        output += PostRenderEscape.escapeContent(this.stored, 'swig', `{%${swig_full_tag_start_buffer}%}${buffer}{%${swig_full_tag_end_buffer}%}`);                        idx = _idx;                        swig_full_tag_start_buffer = '';                        swig_full_tag_end_buffer = '';                        buffer = '';                    }                    else {                        buffer += char;                    }                }                else {                    buffer += char;                }            }        }        return output;    }}</code></pre><ul><li><code>escapeContent</code>：用于将给定的字符串转义为占位符，并存储在缓存数组中。<ul><li>转义后的占位符格式为：<code><!--flag\uFFFC${index}--></code>。</li></ul></li><li><code>restoreContent</code>：用于将占位符还原为原始字符串。</li><li><code>restoreAllSwigTags</code>：使用正则表达式替换所有 Swig 标签占位符，调用 <code>restoreContent</code> 方法还原原始内容。</li><li><code>restoreCodeBlocks</code>：使用正则表达式替换所有代码块占位符，调用 <code>restoreContent</code> 方法还原原始内容。</li><li><code>escapeCodeBlocks</code>：使用正则表达式匹配所有 Markdown 代码块，调用 <code>escapeContent</code> 方法将它们转义为占位符。</li><li><code>escapeAllSwigTags</code>：用于转义 Swig 模板标签。首先检查输入字符串是否包含 Swig 标签，然后使用有限状态机的方式遍历每个字符，识别出 Swig 标签的类型和内容，并调用 <code>escapeContent</code> 进行转义。</li></ul><blockquote><p>有限状态机（Finite State Machine；FSM）是一种数学计算模型，用于描述具有有限个状态以及基于事件进行状态转移的系统。</p><p>一个有限状态机包含以下几个基本组成部分：</p><ul><li>有限状态集合（States）。</li><li>输入事件/符号集合（Input Events/Symbols）。</li><li>一个初始状态（Initial State）。</li><li>状态转移函数（State Transition Function）。</li><li>终止状态集合（Final States）。</li></ul><p>有限状态机的工作原理：</p><ol><li>机器初始处于一个确定的初始状态。</li><li>机器接收一个输入事件 / 符号。</li><li>根据当前状态和输入事件 / 符号，机器按照状态转移函数进行状态转移。</li><li>机器进入新的状态，等待下一个输入事件 / 符号。</li><li>重复以上过程，直到进入某个终止状态或发生无法处理的输入事件 / 符号。</li></ol><p><code>escapeAllSwigTags</code> 使用了一个有限状态机来精确识别和处理各种 Swig 标签。它定义了五种状态，通过遍历输入字符串，根据当前状态和字符进行状态转移，从而正确处理嵌套、注释等复杂情况。</p></blockquote><pre><code class="language-javascript">const prepareFrontMatter = (data, jsonMode) =&gt; {    for (const [key, item] of Object.entries(data)) {        if (moment_1.default.isMoment(item)) {            data[key] = item.utc().format('YYYY-MM-DD HH:mm:ss');        }        else if (moment_1.default.isDate(item)) {            data[key] = moment_1.default.utc(item).format('YYYY-MM-DD HH:mm:ss');        }        else if (typeof item === 'string') {            if (jsonMode || item.includes(':') || item.startsWith('#') || item.startsWith('!!')                || item.includes('{') || item.includes('}') || item.includes('[') || item.includes(']')                || item.includes('\'') || item.includes('"'))                data[key] = `"${item.replace(/"/g, '\\"')}"`;        }    }    return data;};const removeExtname = (str) =&gt; {    return str.substring(0, str.length - (0, path_1.extname)(str).length);};const createAssetFolder = (path, assetFolder) =&gt; {    if (!assetFolder)        return bluebird_1.default.resolve();    const target = removeExtname(path);    if ((0, path_1.basename)(target) === 'index')        return bluebird_1.default.resolve();    return (0, hexo_fs_1.exists)(target).then(exist =&gt; {        if (!exist)            return (0, hexo_fs_1.mkdirs)(target);    });};</code></pre><ul><li><p><code>prepareFrontMatter</code> 方法用于处理文章的 Front Matter 元数据。</p><blockquote><p>Front Matter 是指在 Markdown 或其他 markup 文件的头部添加的一组元数据。它通常被包裹在两组连续的三短横线之间，例如：</p><pre><code class="language-markdown">---title: My Blog Postdate: 2023-05-26tags: [blog, coding]---# My Blog PostThis is the content of the blog post...</code></pre><p>Front Matter 通常采用 YAML 或 JSON 格式来表示键值对的元数据。Front Matter 中的数据可以在渲染 markdown 文件时被解析和使用，例如在博客系统中用于生成文章的元数据、URL 等。不同的静态站点生成器和 markdown 渲染器支持不同的 Front Matter 语法和元数据项。</p></blockquote><p>它遍历 <code>data</code> 对象的每个键值对。如果值是 <code>moment</code> 对象或 <code>Date</code> 对象，则将其转换为 UTC 时区的 <code>YYYY-MM-DD HH:mm:ss</code> 格式的字符串。如果值是字符串，并且符合某些条件（包含特殊字符或需要转义），则将其用双引号包裹起来，并对双引号进行转义。</p><p>这个函数主要用于在生成文章时正确处理 Front Matter 中的日期和特殊字符。</p></li><li><p><code>removeExtname</code> 方法用于从文件路径中移除扩展名。它使用 <code>path.extname</code> 获取扩展名，然后从原始路径中截取并返回不包含扩展名的部分。</p></li><li><p><code>createAssetFolder</code> 方法用于在生成文章时创建与文章相关联的资源文件夹（如果配置启用了该选项）。</p><ul><li>如果 <code>assetFolder</code> 为 <code>false</code>，则直接返回一个已解决的 Promise。否则它会调用 <code>removeExtname</code> 来获取不包含扩展名的文件路径。</li><li>如果这个路径的基础名称是 <code>index</code>，则直接返回一个已解决的 Promise（因为 <code>index</code> 通常是默认文件名，不需要创建文件夹）。否则，它会检查该路径是否存在，如果不存在，则创建该路径作为文件夹。</li></ul></li></ul><pre><code class="language-javascript">class Post {    constructor(context) {        this.context = context;    }    create(data, replace, callback) {        if (!callback &amp;&amp; typeof replace === 'function') {            callback = replace;            replace = false;        }        const ctx = this.context;        const { config } = ctx;        data.slug = (0, hexo_util_1.slugize)((data.slug || data.title).toString(), { transform: config.filename_case });        data.layout = (data.layout || config.default_layout).toLowerCase();        data.date = data.date ? (0, moment_1.default)(data.date) : (0, moment_1.default)();        return bluebird_1.default.all([            // Get the post path            ctx.execFilter('new_post_path', data, {                args: [replace],                context: ctx            }),            this._renderScaffold(data)        ]).spread((path, content) =&gt; {            const result = { path, content };            return bluebird_1.default.all([                // Write content to file                (0, hexo_fs_1.writeFile)(path, content),                // Create asset folder                createAssetFolder(path, config.post_asset_folder)            ]).then(() =&gt; {                ctx.emit('new', result);                return result;            });        }).asCallback(callback);    }    _getScaffold(layout) {        const ctx = this.context;        return ctx.scaffold.get(layout).then(result =&gt; {            if (result != null)                return result;            return ctx.scaffold.get('normal');        });    }    _renderScaffold(data) {        const { tag } = this.context.extend;        let splitted;        return this._getScaffold(data.layout).then(scaffold =&gt; {            splitted = (0, hexo_front_matter_1.split)(scaffold);            const jsonMode = splitted.separator.startsWith(';');            const frontMatter = prepareFrontMatter(Object.assign({}, data), jsonMode);            return tag.render(splitted.data, frontMatter);        }).then(frontMatter =&gt; {            const { separator } = splitted;            const jsonMode = separator.startsWith(';');            // Parse front-matter            const obj = jsonMode ? JSON.parse(`{${frontMatter}}`) : (0, js_yaml_1.load)(frontMatter);            Object.keys(data)                .filter(key =&gt; !preservedKeys.includes(key) &amp;&amp; obj[key] == null)                .forEach(key =&gt; {                    obj[key] = data[key];                });            let content = '';            // Prepend the separator            if (splitted.prefixSeparator)                content += `${separator}\n`;            content += (0, hexo_front_matter_1.stringify)(obj, {                mode: jsonMode ? 'json' : ''            });            // Concat content            content += splitted.content;            if (data.content) {                content += `\n${data.content}`;            }            return content;        });    }    publish(data, replace, callback) {        if (!callback &amp;&amp; typeof replace === 'function') {            callback = replace;            replace = false;        }        if (data.layout === 'draft')            data.layout = 'post';        const ctx = this.context;        const { config } = ctx;        const draftDir = (0, path_1.join)(ctx.source_dir, '_drafts');        const slug = (0, hexo_util_1.slugize)(data.slug.toString(), { transform: config.filename_case });        data.slug = slug;        const regex = new RegExp(`^${(0, hexo_util_1.escapeRegExp)(slug)}(?:[^\\/\\\\]+)`);        let src = '';        const result = {};        data.layout = (data.layout || config.default_layout).toLowerCase();        // Find the draft        return (0, hexo_fs_1.listDir)(draftDir).then(list =&gt; {            const item = list.find(item =&gt; regex.test(item));            if (!item)                throw new Error(`Draft "${slug}" does not exist.`);            // Read the content            src = (0, path_1.join)(draftDir, item);            return (0, hexo_fs_1.readFile)(src);        }).then(content =&gt; {            // Create post            Object.assign(data, (0, hexo_front_matter_1.parse)(content));            data.content = data._content;            data._content = undefined;            return this.create(data, replace);        }).then(post =&gt; {            result.path = post.path;            result.content = post.content;            return (0, hexo_fs_1.unlink)(src);        }).then(() =&gt; {            if (!config.post_asset_folder)                return;            // Copy assets            const assetSrc = removeExtname(src);            const assetDest = removeExtname(result.path);            return (0, hexo_fs_1.exists)(assetSrc).then(exist =&gt; {                if (!exist)                    return;                return (0, hexo_fs_1.copyDir)(assetSrc, assetDest).then(() =&gt; (0, hexo_fs_1.rmdir)(assetSrc));            });        }).thenReturn(result).asCallback(callback);    }    render(source, data = {}, callback) {        const ctx = this.context;        const { config } = ctx;        const { tag } = ctx.extend;        const ext = data.engine || (source ? (0, path_1.extname)(source) : '');        let promise;        if (data.content != null) {            promise = bluebird_1.default.resolve(data.content);        }        else if (source) {            // Read content from files            promise = (0, hexo_fs_1.readFile)(source);        }        else {            return bluebird_1.default.reject(new Error('No input file or string!')).asCallback(callback);        }        // Files like js and css are also processed by this function, but they do not require preprocessing like markdown        // data.source does not exist when tag plugins call the markdown renderer        const isPost = !data.source || ['html', 'htm'].includes(ctx.render.getOutput(data.source));        if (!isPost) {            return promise.then(content =&gt; {                data.content = content;                ctx.log.debug('Rendering file: %s', (0, picocolors_1.magenta)(source));                return ctx.render.render({                    text: data.content,                    path: source,                    engine: data.engine,                    toString: true                });            }).then(content =&gt; {                data.content = content;                return data;            }).asCallback(callback);        }        // disable Nunjucks when the renderer specify that.        let disableNunjucks = ext &amp;&amp; ctx.render.renderer.get(ext) &amp;&amp; !!ctx.render.renderer.get(ext).disableNunjucks;        // front-matter overrides renderer's option        if (typeof data.disableNunjucks === 'boolean')            disableNunjucks = data.disableNunjucks;        const cacheObj = new PostRenderEscape();        return promise.then(content =&gt; {            data.content = content;            // Run "before_post_render" filters            return ctx.execFilter('before_post_render', data, { context: ctx });        }).then(() =&gt; {            data.content = cacheObj.escapeCodeBlocks(data.content);            // Escape all Nunjucks/Swig tags            if (disableNunjucks === false) {                data.content = cacheObj.escapeAllSwigTags(data.content);            }            const options = data.markdown || {};            if (!config.syntax_highlighter)                options.highlight = null;            ctx.log.debug('Rendering post: %s', (0, picocolors_1.magenta)(source));            // Render with markdown or other renderer            return ctx.render.render({                text: data.content,                path: source,                engine: data.engine,                toString: true,                onRenderEnd(content) {                    // Replace cache data with real contents                    data.content = cacheObj.restoreAllSwigTags(content);                    // Return content after replace the placeholders                    if (disableNunjucks)                        return data.content;                    // Render with Nunjucks                    return tag.render(data.content, data);                }            }, options);        }).then(content =&gt; {            data.content = cacheObj.restoreCodeBlocks(content);            // Run "after_post_render" filters            return ctx.execFilter('after_post_render', data, { context: ctx });        }).asCallback(callback);    }}module.exports = Post;//# sourceMappingURL=post.js.map</code></pre><p><code>Post</code> 类包含了在 Hexo 框架中创建、发布和渲染文章的和新方法。</p><ul><li><code>create(data, replace, callback)</code>：创建一篇新文章。<ol><li>首先根据配置和传入的数据准备文章的 slug、布局和日期。</li><li>然后通过执行 <code>new_post_path</code> 过滤器获取文章路径，并调用 <code>_renderScaffold</code> 方法渲染文章内容。</li><li>最后将渲染后的内容写入文件，并根据配置创建相关的资源文件夹。</li></ol></li><li><code>_getScaffold(layout)</code> 和 <code>_renderScaffold(data)</code>：<ul><li><code>_getScaffold</code> 方法用于获取指定布局的脚手架。</li><li><code>_renderScaffold</code> 方法用于渲染脚手架，并将传入的数据合并到模板中。<ul><li>先解析 Front Matter，然后使用标签插件渲染 Front Matter。最后将渲染后的 Front Matter 和原始内容合并，返回最终的文章内容。</li></ul></li></ul></li><li><code>publish(data, replace, callback)</code>：将草稿文章发布为正式文章。<ol><li>首先从 <code>_drafts</code> 目录查找对应的草稿文件，读取其内容。</li><li>然后将草稿内容与传入的数据合并，调用 <code>create</code> 方法创建正式文章。</li><li>最后删除原始的草稿文件，并根据配置复制相关的资源文件夹。</li></ol></li><li><code>render(source, data, callback)</code>：渲染文章内容。<ol><li>首先读取源文件或使用传入的内容。</li><li>然后执行 <code>before_post_render</code> 过滤器。</li><li>接着对代码块和 Swig / Nunjucks 标签进行转义，使用 Markdown 或其他渲染器渲染文章内容。</li><li>渲染完成后，将转义的内容还原，并执行 <code>after_post_render</code> 过滤器。</li><li>如果禁用了 Nunjucks，则返回渲染后的内容；否则使用标签插件渲染一次。</li></ol></li></ul><h4 id="脚手架"><a class="markdownIt-Anchor" href="#脚手架"></a> 脚手架</h4><p>脚手架文件是创建新文章或页面时使用的模板文件。</p><blockquote><p>可见 <a href="https://hexo.io/zh-cn/api/scaffolds">Hexo 官方文档</a>。</p></blockquote><pre><code class="language-javascript">this.scaffold = new scaffold_1.default(this);</code></pre><pre><code class="language-javascript">"use strict";const path_1 = require("path");const hexo_fs_1 = require("hexo-fs");class Scaffold {    constructor(context) {        this.context = context;        this.scaffoldDir = context.scaffold_dir;        this.defaults = {            normal: [                '---',                'layout: {{ layout }}',                'title: {{ title }}',                'date: {{ date }}',                'tags:',                '---'            ].join('\n')        };    }    _listDir() {        const { scaffoldDir } = this;        return (0, hexo_fs_1.exists)(scaffoldDir).then(exist =&gt; {            if (!exist)                return [];            return (0, hexo_fs_1.listDir)(scaffoldDir, {                ignorePattern: /^_|\/_/            });        }).map(item =&gt; ({            name: item.substring(0, item.length - (0, path_1.extname)(item).length),            path: (0, path_1.join)(scaffoldDir, item)        }));    }    _getScaffold(name) {        return this._listDir().then(list =&gt; list.find(item =&gt; item.name === name));    }    get(name, callback) {        return this._getScaffold(name).then(item =&gt; {            if (item) {                return (0, hexo_fs_1.readFile)(item.path);            }            return this.defaults[name];        }).asCallback(callback);    }    set(name, content, callback) {        const { scaffoldDir } = this;        return this._getScaffold(name).then(item =&gt; {            let path = item ? item.path : (0, path_1.join)(scaffoldDir, name);            if (!(0, path_1.extname)(path))                path += '.md';            return (0, hexo_fs_1.writeFile)(path, content);        }).asCallback(callback);    }    remove(name, callback) {        return this._getScaffold(name).then(item =&gt; {            if (!item)                return;            return (0, hexo_fs_1.unlink)(item.path);        }).asCallback(callback);    }}module.exports = Scaffold;//# sourceMappingURL=scaffold.js.map</code></pre><p><code>Scaffold</code> 类在 Hexo 框架中用于管理 Scaffold 模板文件，也就是脚手架文件。脚手架是用于生成新文章或页面的默认模板。</p><ul><li><code>constructor(context)</code>：初始化了 <code>scaffoldDir</code> 属性，指定脚手架文件所在的目录。它还定义了一个 <code>defaults</code> 对象，包含了默认的脚手架内容。</li><li><code>_listDir()</code>：用于列出 <code>scaffoldDir</code> 目录下的所有脚手架文件。它会忽略以下划线开头的文件或目录。</li><li><code>_getScaffold(name)</code>：根据给定的名称获取对应的脚手架文件信息。<ul><li>先调用 <code>_listDir()</code> 方法获取所有脚手架文件，然后查找名称匹配的文件。</li></ul></li><li><code>get(name, callback)</code>：用于获取指定名称的脚手架内容。<ul><li>如果找到对应的文件，它会读取并返回文件内容。如果没有找到，它会返回 <code>defaults</code> 对象中对应的默认脚手架内容。</li></ul></li><li><code>set(name, content, callback)</code>：用于设置或创建一个新的脚手架文件。<ul><li>首先检查是否已经存在同名的文件，如果存在就使用原有路径，否则就在 <code>scaffoldDir</code> 目录下创建新文件（文件扩展名默认为 <code>.md</code>）。</li></ul></li><li><code>remove(name, callback)</code>：用于删除一个脚手架文件。它会查找对应名称的文件，如果存在则将其删除。</li></ul><h4 id="数据库"><a class="markdownIt-Anchor" href="#数据库"></a> 数据库</h4><pre><code class="language-javascript">this._dbLoaded = false;this._isGenerating = false;// If `output` is provided, use that as the// root for saving the db. Otherwise default to `base`.const dbPath = args.output || base;if (/^(init|new|g|publish|s|deploy|render|migrate)/.test(this.env.cmd)) {  this.log.d(`Writing database to ${(0, path_1.join)(dbPath, 'db.json')}`);}</code></pre><ol><li>初始化两个内部状态标志，用于跟踪数据库是否已经加载（<code>_dbLoaded</code>）和网站是否正在生成（<code>_isGenerating</code>）。</li><li>确定数据库文件将要被保存在的路径。如果执行 Hexo 命令时提供了 <code>output</code> 参数，那么数据库就会被保存在该输出路径下；不然就保存在项目根目录下。</li><li>接着检查当前执行的 Hexo 命令是否属于 <code>init</code>、<code>new</code>、<code>g</code>、<code>publish</code>、<code>deploy</code>、<code>render</code> 或者 <code>migrate</code>。如果是，就打印说数据库文件被写入到哪里去了。</li></ol><pre><code class="language-javascript">this.database = new warehouse_1.default({  version: dbVersion,  path: (0, path_1.join)(dbPath, 'db.json')});</code></pre><p>Hexo 初始化和配置数据库，实例化过程中传入了一个配置对象：</p><ul><li><code>version</code>：数据库的版本号。在 <code>index.js</code> 的最上方能找到：<pre><code class="language-javascript">const dbVersion = 1;</code></pre></li><li><code>path</code>：数据库文件的保存路径，由先前定义的 <code>dbPath</code> 和文件名 <code>db.json</code> 拼接而成。</li></ul><p>此处实例化用到了 <code>warehouse</code> 库。这是一个轻量级的数据存储库，主要用于 Node.js 应用程序中处理 JSON 数据。它提供了一种简单的方式来定义、存储和检索模型数据，类似于一个迷你数据库或 ORM（对象关系映射）。</p><p><a href="https://github.com/dundalek/warehouse"><img src="https://gh-card.dev/repos/dundalek/warehouse.svg" alt="dundalek/warehouse - GitHub" loading="lazy"></a></p><h4 id="多配置文件路径管理"><a class="markdownIt-Anchor" href="#多配置文件路径管理"></a> 多配置文件路径管理</h4><pre><code class="language-javascript">const mcp = (0, multi_config_path_1.default)(this);</code></pre><pre><code class="language-javascript">"use strict";var __importDefault = (this &amp;&amp; this.__importDefault) || function (mod) {    return (mod &amp;&amp; mod.__esModule) ? mod : { "default": mod };};const path_1 = require("path");const hexo_fs_1 = require("hexo-fs");const js_yaml_1 = __importDefault(require("js-yaml"));const hexo_util_1 = require("hexo-util");module.exports = (ctx) =&gt; function multiConfigPath(base, configPaths, outputDir) {    const { log } = ctx;    const defaultPath = (0, path_1.join)(base, '_config.yml');    if (!configPaths) {        log.w('No config file entered.');        return (0, path_1.join)(base, '_config.yml');    }    let paths;    // determine if comma or space separated    if (configPaths.includes(',')) {        paths = configPaths.replace(' ', '').split(',');    }    else {        // only one config        let configPath = (0, path_1.isAbsolute)(configPaths) ? configPaths : (0, path_1.resolve)(base, configPaths);        if (!(0, hexo_fs_1.existsSync)(configPath)) {            log.w(`Config file ${configPaths} not found, using default.`);            configPath = defaultPath;        }        return configPath;    }    const numPaths = paths.length;    // combine files    let combinedConfig = {};    let count = 0;    for (let i = 0; i &lt; numPaths; i++) {        const configPath = (0, path_1.isAbsolute)(paths[i]) ? paths[i] : (0, path_1.join)(base, paths[i]);        if (!(0, hexo_fs_1.existsSync)(configPath)) {            log.w(`Config file ${paths[i]} not found.`);            continue;        }        // files read synchronously to ensure proper overwrite order        const file = (0, hexo_fs_1.readFileSync)(configPath);        const ext = (0, path_1.extname)(paths[i]).toLowerCase();        if (ext === '.yml') {            combinedConfig = (0, hexo_util_1.deepMerge)(combinedConfig, js_yaml_1.default.load(file));            count++;        }        else if (ext === '.json') {            combinedConfig = (0, hexo_util_1.deepMerge)(combinedConfig, js_yaml_1.default.load(file, { json: true }));            count++;        }        else {            log.w(`Config file ${paths[i]} not supported type.`);        }    }    if (count === 0) {        log.e('No config files found. Using _config.yml.');        return defaultPath;    }    log.i('Config based on', count.toString(), 'files');    const multiconfigRoot = outputDir || base;    const outputPath = (0, path_1.join)(multiconfigRoot, '_multiconfig.yml');    log.d(`Writing _multiconfig.yml to ${outputPath}`);    (0, hexo_fs_1.writeFileSync)(outputPath, js_yaml_1.default.dump(combinedConfig));    // write file and return path    return outputPath;};//# sourceMappingURL=multi_config_path.js.map</code></pre><p><code>multiConfigPath</code> 函数用于处理 Hexo 配置文件。该函数会根据传入的配置文件路径来合并多个配置文件并生成一个新的配置文件 <code>_multiconfig.yml</code>。</p><p>顺带一个读取配置文件路径的参数：</p><pre><code class="language-javascript">this.config_path = args.config ? mcp(base, args.config, args.output)  : (0, path_1.join)(base, '_config.yml');</code></pre><p>根据用户的命令行输入和 Hexo 项目的配置，决定要读取的配置文件的路径。</p><h4 id="注册模型"><a class="markdownIt-Anchor" href="#注册模型"></a> 注册模型</h4><pre><code class="language-javascript">(0, register_models_1.default)(this);</code></pre><pre><code class="language-javascript">"use strict";var __createBinding = (this &amp;&amp; this.__createBinding) || (Object.create ? (function(o, m, k, k2) {    if (k2 === undefined) k2 = k;    var desc = Object.getOwnPropertyDescriptor(m, k);    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {        desc = { enumerable: true, get: function() { return m[k]; } };    }    Object.defineProperty(o, k2, desc);}) : (function(o, m, k, k2) {    if (k2 === undefined) k2 = k;    o[k2] = m[k];}));var __setModuleDefault = (this &amp;&amp; this.__setModuleDefault) || (Object.create ? (function(o, v) {    Object.defineProperty(o, "default", { enumerable: true, value: v });}) : function(o, v) {    o["default"] = v;});var __importStar = (this &amp;&amp; this.__importStar) || function (mod) {    if (mod &amp;&amp; mod.__esModule) return mod;    var result = {};    if (mod != null) for (var k in mod) if (k !== "default" &amp;&amp; Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);    __setModuleDefault(result, mod);    return result;};const models = __importStar(require("../models"));module.exports = (ctx) =&gt; {    const db = ctx.database;    const keys = Object.keys(models);    for (let i = 0, len = keys.length; i &lt; len; i++) {        const key = keys[i];        db.model(key, models[key](ctx));    }};//# sourceMappingURL=register_models.js.map</code></pre><p>上三个函数是 TypeScript 编译器在编译时生成的，用于处理 ES 模块的导入和默认导出行为。它们确保在使用 CommonJS 模块时，能正确处理 ES 模块的导入。</p><p>接下来导入的 <code>models</code> 模块是 <code>hexo/dist/models</code> 目录，这里使用了 <code>__importStar</code> 函数导入 <code>models</code> 模块中的所有导出，作为 <code>models</code> 对象的属性。</p><blockquote><p><code>models</code> 模块内容很多，后续会仔细讲解。</p></blockquote><p><code>register_models</code> 模块导出一个函数，该函数接收一个 <code>ctx</code> 参数，并从 <code>ctx</code> 对象中获取数据库实例 <code>db</code>、获取 <code>models</code> 对象的所有键，遍历这些键，为每个模型在数据库中注册一个模型。</p><p>主要功能是导入所有的模型，并将这些模型注册到数据库中。</p><h4 id="源文件管理"><a class="markdownIt-Anchor" href="#源文件管理"></a> 源文件管理</h4><pre><code class="language-javascript">this.source = new source_1.default(this);</code></pre><pre><code class="language-javascript">"use strict";var __importDefault = (this &amp;&amp; this.__importDefault) || function (mod) {    return (mod &amp;&amp; mod.__esModule) ? mod : { "default": mod };};const box_1 = __importDefault(require("../box"));class Source extends box_1.default {    constructor(ctx) {        super(ctx, ctx.source_dir);        this.processors = ctx.extend.processor.list();    }}module.exports = Source;//# sourceMappingURL=source.js.map</code></pre><p><code>Source</code> 类继承自 <code>Box</code> 类，所以先看一眼 <code>Box</code> 类：</p><pre><code class="language-javascript">"use strict";var __awaiter = (this &amp;&amp; this.__awaiter) || function (thisArg, _arguments, P, generator) {    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }    return new (P || (P = Promise))(function (resolve, reject) {        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }        step((generator = generator.apply(thisArg, _arguments || [])).next());    });};var __importDefault = (this &amp;&amp; this.__importDefault) || function (mod) {    return (mod &amp;&amp; mod.__esModule) ? mod : { "default": mod };};Object.defineProperty(exports, "__esModule", { value: true });const path_1 = require("path");const bluebird_1 = __importDefault(require("bluebird"));const file_1 = __importDefault(require("./file"));const hexo_util_1 = require("hexo-util");const hexo_fs_1 = require("hexo-fs");const picocolors_1 = require("picocolors");const events_1 = require("events");const micromatch_1 = require("micromatch");const defaultPattern = new hexo_util_1.Pattern(() =&gt; ({}));class Box extends events_1.EventEmitter {    constructor(ctx, base, options) {        super();        this.options = Object.assign({            persistent: true,            awaitWriteFinish: {                stabilityThreshold: 200            }        }, options);        if (!base.endsWith(path_1.sep)) {            base += path_1.sep;        }        this.context = ctx;        this.base = base;        this.processors = [];        this._processingFiles = {};        this.watcher = null;        this.Cache = ctx.model('Cache');        this.File = this._createFileClass();        let targets = this.options.ignored || [];        if (ctx.config.ignore &amp;&amp; ctx.config.ignore.length) {            targets = targets.concat(ctx.config.ignore);        }        this.ignore = targets;        this.options.ignored = targets.map(s =&gt; toRegExp(ctx, s)).filter(x =&gt; x);    }    _createFileClass() {        const ctx = this.context;        class _File extends file_1.default {            render(options) {                return ctx.render.render({                    path: this.source                }, options);            }            renderSync(options) {                return ctx.render.renderSync({                    path: this.source                }, options);            }        }        _File.prototype.box = this;        return _File;    }    addProcessor(pattern, fn) {        if (!fn &amp;&amp; typeof pattern === 'function') {            fn = pattern;            pattern = defaultPattern;        }        if (typeof fn !== 'function')            throw new TypeError('fn must be a function');        if (!(pattern instanceof hexo_util_1.Pattern))            pattern = new hexo_util_1.Pattern(pattern);        this.processors.push({            pattern,            process: fn        });    }    _readDir(base, prefix = '') {        const { context: ctx } = this;        const results = [];        return readDirWalker(ctx, base, results, this.ignore, prefix)            .return(results)            .map(path =&gt; this._checkFileStatus(path))            .map(file =&gt; this._processFile(file.type, file.path).return(file.path));    }    _checkFileStatus(path) {        const { Cache, context: ctx } = this;        const src = (0, path_1.join)(this.base, path);        return Cache.compareFile(src.substring(ctx.base_dir.length), () =&gt; getHash(src), () =&gt; (0, hexo_fs_1.stat)(src)).then(result =&gt; ({            type: result.type,            path        }));    }    process(callback) {        const { base, Cache, context: ctx } = this;        return (0, hexo_fs_1.stat)(base).then(stats =&gt; {            if (!stats.isDirectory())                return;            // Check existing files in cache            const relativeBase = base.substring(ctx.base_dir.length);            const cacheFiles = Cache.filter(item =&gt; item._id.startsWith(relativeBase)).map(item =&gt; item._id.substring(relativeBase.length));            // Handle deleted files            return this._readDir(base)                .then((files) =&gt; cacheFiles.filter((path) =&gt; !files.includes(path)))                .map((path) =&gt; this._processFile(file_1.default.TYPE_DELETE, path));        }).catch(err =&gt; {            if (err &amp;&amp; err.code !== 'ENOENT')                throw err;        }).asCallback(callback);    }    _processFile(type, path) {        if (this._processingFiles[path]) {            return bluebird_1.default.resolve();        }        this._processingFiles[path] = true;        const { base, File, context: ctx } = this;        this.emit('processBefore', {            type,            path        });        return bluebird_1.default.reduce(this.processors, (count, processor) =&gt; {            // patten supports *nix style path only, replace backslashes on Windows            const params = processor.pattern.match(escapeBackslash(path));            if (!params)                return count;            const file = new File({                // source is used for file system path, keep backslashes on Windows                source: (0, path_1.join)(base, path),                // path is used for URL path, replace backslashes on Windows                path: escapeBackslash(path),                params,                type            });            return Reflect.apply(bluebird_1.default.method(processor.process), ctx, [file])                .thenReturn(count + 1);        }, 0).then(count =&gt; {            if (count) {                ctx.log.debug('Processed: %s', (0, picocolors_1.magenta)(path));            }            this.emit('processAfter', {                type,                path            });        }).catch(err =&gt; {            ctx.log.error({ err }, 'Process failed: %s', (0, picocolors_1.magenta)(path));        }).finally(() =&gt; {            this._processingFiles[path] = false;        }).thenReturn(path);    }    watch(callback) {        if (this.isWatching()) {            return bluebird_1.default.reject(new Error('Watcher has already started.')).asCallback(callback);        }        const { base } = this;        function getPath(path) {            return path.substring(base.length);        }        return this.process().then(() =&gt; (0, hexo_fs_1.watch)(base, this.options)).then(watcher =&gt; {            this.watcher = watcher;            watcher.on('add', path =&gt; {                this._processFile(file_1.default.TYPE_CREATE, getPath(path));            });            watcher.on('change', path =&gt; {                this._processFile(file_1.default.TYPE_UPDATE, getPath(path));            });            watcher.on('unlink', path =&gt; {                this._processFile(file_1.default.TYPE_DELETE, getPath(path));            });            watcher.on('addDir', path =&gt; {                let prefix = getPath(path);                if (prefix)                    prefix += path_1.sep;                this._readDir(path, prefix);            });        }).asCallback(callback);    }    unwatch() {        if (!this.isWatching())            return;        this.watcher.close();        this.watcher = null;    }    isWatching() {        return Boolean(this.watcher);    }}function escapeBackslash(path) {    // Replace backslashes on Windows    return path.replace(/\\/g, '/');}function getHash(path) {    const src = (0, hexo_fs_1.createReadStream)(path);    const hasher = (0, hexo_util_1.createSha1Hash)();    const finishedPromise = new bluebird_1.default((resolve, reject) =&gt; {        src.once('error', reject);        src.once('end', resolve);    });    src.on('data', chunk =&gt; { hasher.update(chunk); });    return finishedPromise.then(() =&gt; hasher.digest('hex'));}function toRegExp(ctx, arg) {    if (!arg)        return null;    if (typeof arg !== 'string') {        ctx.log.warn('A value of "ignore:" section in "_config.yml" is not invalid (not a string)');        return null;    }    const result = (0, micromatch_1.makeRe)(arg);    if (!result) {        ctx.log.warn('A value of "ignore:" section in "_config.yml" can not be converted to RegExp:' + arg);        return null;    }    return result;}function isIgnoreMatch(path, ignore) {    return path &amp;&amp; ignore &amp;&amp; ignore.length &amp;&amp; (0, micromatch_1.isMatch)(path, ignore);}function readDirWalker(ctx, base, results, ignore, prefix) {    if (isIgnoreMatch(base, ignore))        return bluebird_1.default.resolve();    return bluebird_1.default.map((0, hexo_fs_1.readdir)(base).catch(err =&gt; {        ctx.log.error({ err }, 'Failed to read directory: %s', base);        if (err &amp;&amp; err.code === 'ENOENT')            return [];        throw err;    }), (path) =&gt; __awaiter(this, void 0, void 0, function* () {        const fullpath = (0, path_1.join)(base, path);        const stats = yield (0, hexo_fs_1.stat)(fullpath).catch(err =&gt; {            ctx.log.error({ err }, 'Failed to stat file: %s', fullpath);            if (err &amp;&amp; err.code === 'ENOENT')                return null;            throw err;        });        const prefixPath = `${prefix}${path}`;        if (stats) {            if (stats.isDirectory()) {                return readDirWalker(ctx, fullpath, results, ignore, prefixPath + path_1.sep);            }            if (!isIgnoreMatch(fullpath, ignore)) {                results.push(prefixPath);            }        }    }));}exports.default = Box;//# sourceMappingURL=index.js.map</code></pre><p>部分辅助函数：</p><ul><li><code>__awaiter</code>：用于处理异步函数和生成器函数，使得可以使用 <code>async/await</code> 语法。</li><li><code>__importDefault</code>：用于处理默认导入。</li><li><code>escapeBackslash</code>：将路径中的反斜杠替换为斜杠。</li><li><code>getHash</code>：生成文件的 SHA-1 哈希值。</li><li><code>toRegExp</code>：将字符串转换为正则表达式。</li><li><code>isIgnoreMatch</code>：检查路径是否与忽略模式匹配。</li><li><code>readDirWalker</code>：递归读取目录，并收集所有符合条件的文件路径。</li></ul><p><code>box/index.js</code> 也导入了一个 <code>file.js</code> 文件，该文件定义了一个 <code>File</code> 类，用来表示文件对象，并提供了一些方法来读取和获取文件状态：</p><pre><code class="language-javascript">"use strict";const hexo_fs_1 = require("hexo-fs");class File {    constructor({ source, path, params, type }) {        this.source = source;        this.path = path;        this.params = params;        this.type = type;    }    read(options) {        return (0, hexo_fs_1.readFile)(this.source, options);    }    readSync(options) {        return (0, hexo_fs_1.readFileSync)(this.source, options);    }    stat() {        return (0, hexo_fs_1.stat)(this.source);    }    statSync() {        return (0, hexo_fs_1.statSync)(this.source);    }}File.TYPE_CREATE = 'create';File.TYPE_UPDATE = 'update';File.TYPE_SKIP = 'skip';File.TYPE_DELETE = 'delete';module.exports = File;//# sourceMappingURL=file.js.map</code></pre><ul><li><code>read(options)</code>：异步读取文件内容，返回一个 Promise。</li><li><code>readSync(options)</code>：同步读取文件内容，返回文件内容。</li><li><code>stat()</code>：异步获取文件状态，返回一个 Promise。</li><li><code>statSync()</code>：同步获取文件状态，返回文件状态。</li><li>文件类型常量：明确表示文件的操作类型。</li></ul><p><code>Box</code> 类也是继承自 <code>EventEmitter</code>。</p><p>主要的属性和方法：</p><ul><li>构造函数：初始化 Box 类的实例，设置：<ul><li><code>options</code>：默认选项和用户传入的选项合并。</li><li><code>context</code>：上下文对象。</li><li><code>base</code>：基础路径。</li><li><code>processors</code>：处理器列表。</li><li><code>_processingFiles</code>：正在处理的文件。</li><li><code>watcher</code>：文件监视器。</li><li><code>Cache</code>：缓存模型。</li><li><code>File</code>：文件类。</li><li><code>ignore</code>：忽略模式。</li></ul></li><li><code>_createFileClass</code>：创建一个文件类，用于处理文件的渲染操作。</li><li><code>addProcessor</code>：添加一个处理器，用于处理特定模式的文件。</li><li><code>_readDir</code>：读取目录，并递归处理所有文件。</li><li><code>_checkFileStatus</code>：检查文件状态，比较缓存文件和实际文件。</li><li><code>process</code>：处理目录中的所有文件。</li><li><code>_processFile</code>：处理单个文件，根据文件类型执行处理器。</li><li><code>watch</code>：监视目录中的文件变化，并在文件添加、修改或删除时触发相应的处理。</li><li><code>unwatch</code>：停止监视目录。</li><li><code>isWatching</code>：检查是否正在监视目录。</li></ul><p><code>Box</code> 类的更多详情可见 <a href="https://hexo.io/zh-cn/api/box">Hexo 官方文档</a>。</p><p>现在再来看 <code>Source</code> 类。它继承自 <code>Box</code> 类，拥有着 <code>Box</code> 类的所有属性和方法。<code>Box</code> 类提供了文件读取、监视、处理等能力。而 <code>Source</code> 类在此基础上，专注于处理特定于源文件的逻辑。</p><h4 id="主题"><a class="markdownIt-Anchor" href="#主题"></a> 主题</h4><pre><code class="language-javascript">this.theme = new theme_1.default(this);</code></pre><div class="danger"><p><code>Theme</code> 类被定义在 <code>hexo/dist/theme</code> 中，未来会详细说。目前只讲 <code>index.js</code> 的大致逻辑。</p></div><p><code>Theme</code> 类是 Hexo 中负责管理主题的核心模块。</p><blockquote><p>可见 <a href="https://hexo.io/zh-cn/api/themes">Hexo 官方文档</a>。</p></blockquote><pre><code class="language-javascript">"use strict";var __importDefault = (this &amp;&amp; this.__importDefault) || function (mod) {    return (mod &amp;&amp; mod.__esModule) ? mod : { "default": mod };};const path_1 = require("path");const box_1 = __importDefault(require("../box"));const view_1 = __importDefault(require("./view"));const hexo_i18n_1 = __importDefault(require("hexo-i18n"));const config_1 = require("./processors/config");const i18n_1 = require("./processors/i18n");const source_1 = require("./processors/source");const view_2 = require("./processors/view");class Theme extends box_1.default {    constructor(ctx, options) {        super(ctx, ctx.theme_dir, options);        this.config = {};        this.views = {};        this.processors = [            config_1.config,            i18n_1.i18n,            source_1.source,            view_2.view        ];        let languages = ctx.config.language;        if (!Array.isArray(languages))            languages = [languages];        languages.push('default');        this.i18n = new hexo_i18n_1.default({            languages: [...new Set(languages.filter(Boolean))]        });        class _View extends view_1.default {        }        this.View = _View;        _View.prototype._theme = this;        _View.prototype._render = ctx.render;        _View.prototype._helper = ctx.extend.helper;    }    getView(path) {        // Replace backslashes on Windows        path = path.replace(/\\/g, '/');        const ext = (0, path_1.extname)(path);        const name = path.substring(0, path.length - ext.length);        const views = this.views[name];        if (!views)            return;        if (ext) {            return views[ext];        }        return views[Object.keys(views)[0]];    }    setView(path, data) {        const ext = (0, path_1.extname)(path);        const name = path.substring(0, path.length - ext.length);        this.views[name] = this.views[name] || {};        const views = this.views[name];        views[ext] = new this.View(path, data);    }    removeView(path) {        const ext = (0, path_1.extname)(path);        const name = path.substring(0, path.length - ext.length);        const views = this.views[name];        if (!views)            return;        views[ext] = undefined;    }}module.exports = Theme;//# sourceMappingURL=index.js.map</code></pre><p><code>Theme</code> 类同样继承自 <code>Box</code> 类：</p><ul><li><code>constructor(ctx, options)</code>：构造函数接受上下文对象 <code>ctx</code> 和选项 <code>options</code>，调用父类 <code>box_1.default</code> 的构造函数。</li><li>初始化 <code>config</code> 和 <code>views</code> 属性为空对象。</li><li><code>processors</code>：设置处理器数组，包括配置、国际化、源文件和视图处理器。</li><li>初始化多语言支持，确保 <code>languages</code> 是数组，并添加 <code>default</code> 语言。使用 <code>hexo-i18n</code> 库创建 <code>i18n</code> 对象。</li><li>定义一个新的 <code>_View</code> 类，继承自 <code>view_1.default</code>，并在其原型上添加 <code>_theme</code>、<code>_render</code> 和 <code>_helper</code> 属性。</li></ul><p>撇开本地文件导入，这里的 <code>hexo-i18n</code> 是 Hexo 自己的 i18n 模块。</p><p><a href="https://github.com/hexojs/hexo-i18n"><img src="https://gh-card.dev/repos/hexojs/hexo-i18n.svg" alt="hexojs/hexo-i18n - GitHub" loading="lazy"></a></p><blockquote><p>i18n 的全程是 <strong>Internationalization</strong>（国际化），是指在设计软件、将软件与特定语言及地区脱钩的过程。由于英文单字长度过长，所以常被简称为 i18n（18 意味着在 Internationalization 这个单字中，i 和 n 之间有 18 个字母。</p></blockquote><p><code>Theme</code> 类也有以下方法：</p><ul><li><code>getView(path)</code>：根据给定路径获取视图。</li><li><code>setView(path, data)</code> 设置指定路径的 <code>View</code> 内容。</li><li><code>removeView(path)</code> 移除指定路径的 <code>View</code>。</li></ul><p>通过实例化 <code>Theme</code> 类，Hexo 可以获得一个用于操作当前主题的对象，从而正确地渲染和生成静态页面。</p><blockquote><p>视图（<code>View</code>）在 Hexo 中是用于渲染页面内容的模板文件。通常使用模板引擎语法编写，如 Swig、Pug 等，允许在模板中嵌入动态数据和逻辑。</p><p>视图主要有以下几种类型：</p><ol><li>布局（Layout）：定义了页面的基本结构，如 HTML 头部、导航栏、页脚等通用部分。所有其他视图都将被渲染到布局视图中的特定位置。</li><li>包含（Partial）：可重用的模板片段，通常用于渲染页面的某一部分，如文章列表、评论区等。它们可以在其他视图中被引入和渲染。</li><li>页面（Page）：用于渲染特定的页面内容，如文章、分类、标签等。它们通常会引入布局视图和其他所需的包含视图。</li><li>助手（Helper）：一些辅助函数，用于在模板中执行特定的逻辑或操作，如格式化日期、生成链接等。</li></ol></blockquote><h4 id="本地数据"><a class="markdownIt-Anchor" href="#本地数据"></a> 本地数据</h4><pre><code class="language-javascript">this.locals = new locals_1.default();</code></pre><p><code>Locals</code> 类用于管理和缓存局部变量：</p><pre><code class="language-javascript">"use strict";const hexo_util_1 = require("hexo-util");class Locals {    constructor() {        this.cache = new hexo_util_1.Cache();        this.getters = {};    }    get(name) {        if (typeof name !== 'string')            throw new TypeError('name must be a string!');        return this.cache.apply(name, () =&gt; {            const getter = this.getters[name];            if (!getter)                return;            return getter();        });    }    set(name, value) {        if (typeof name !== 'string')            throw new TypeError('name must be a string!');        if (value == null)            throw new TypeError('value is required!');        const getter = typeof value === 'function' ? value : () =&gt; value;        this.getters[name] = getter;        this.cache.del(name);        return this;    }    remove(name) {        if (typeof name !== 'string')            throw new TypeError('name must be a string!');        this.getters[name] = null;        this.cache.del(name);        return this;    }    invalidate() {        this.cache.flush();        return this;    }    toObject() {        const result = {};        const keys = Object.keys(this.getters);        for (let i = 0, len = keys.length; i &lt; len; i++) {            const key = keys[i];            const item = this.get(key);            if (item != null)                result[key] = item;        }        return result;    }}module.exports = Locals;//# sourceMappingURL=locals.js.map</code></pre><p><code>Locals</code> 类有两个属性：</p><ul><li><code>cache</code>：使用 <code>hexo-util</code> 模块的 <code>Cache</code> 类实例化缓存对象。</li><li><code>getters</code>：初始化一个空对象，用于存储 <code>getter</code> 函数。</li></ul><p><code>Locals</code> 类也有以下方法：</p><ul><li><code>get(name)</code> 获取指定名称的本地数据。</li><li><code>set(name, value)</code> 设置指定名称的本地数据。</li><li><code>remove(name)</code> 移除指定名称的本地数据。</li><li><code>invalidate()</code> 清空缓存。</li><li><code>toObject()</code> 将本地数据转换为普通对象。</li></ul><p><code>Locals</code> 类是 Hexo 中用于管理本地数据的模块。本地数据在 Hexo 插件开发中意外重要，后续会详细讲解。</p><blockquote><p>暂且，请看 <a href="https://hexo.io/zh-cn/api/locals">Hexo 官方文档</a>。</p></blockquote><h2 id="本地数据绑定"><a class="markdownIt-Anchor" href="#本地数据绑定"></a> 本地数据绑定</h2><p>构造函数的最后一行是用来绑定本地数据的：</p><pre><code class="language-javascript">this._bindLocals();</code></pre><pre><code class="language-javascript">_bindLocals() {  const db = this.database;  const { locals } = this;  locals.set('posts', () =&gt; {    const query = {};    if (!this.config.future) {      query.date = { $lte: Date.now() };    }    if (!this._showDrafts()) {      query.published = true;    }    return db.model('Post').find(query);  });  locals.set('pages', () =&gt; {    const query = {};    if (!this.config.future) {      query.date = { $lte: Date.now() };    }    return db.model('Page').find(query);  });  locals.set('categories', () =&gt; {    // Ignore categories with zero posts    return db.model('Category').filter(category =&gt; category.length);  });  locals.set('tags', () =&gt; {    // Ignore tags with zero posts    return db.model('Tag').filter(tag =&gt; tag.length);  });  locals.set('data', () =&gt; {    const obj = {};    db.model('Data').forEach(data =&gt; {      obj[data._id] = data.data;    });    return obj;  });}</code></pre><p>首先获取 <code>Hexo</code> 实例的数据库对象 <code>this.database</code>，接着使用对象解构赋值的语法从 <code>this</code> 对象中提取 <code>locals</code> 属性的值。<code>this</code> 指向的是当前执行上下文中的对象实例，在这里，<code>this</code> 是 <code>Hexo</code> 实例本身。</p><p><code>const { locals } = this;</code> 相当于这行代码：</p><pre><code class="language-javascript">const locals = this.locals;</code></pre><p>通过调用 <code>locals.set()</code> 方法，为不同的本地数据设置了获取器函数。当其他地方访问这些本地数据时，相应的获取器函数将被执行，从数据库中查询并返回所需的数据。</p><p>具体来说，这个方法设置了以下几个本地数据及其获取器：</p><ul><li><code>posts</code>：获取所有已发布且不是未来日期的文章。如果 <code>config.future</code> 设置为 <code>true</code>，则也包括未来日期的文章。如果 <code>_showDrafts()</code> 返回 <code>true</code>，则也包括草稿文章。</li><li><code>pages</code>：获取所有已发布且不是未来日期的页面。如果 <code>config.future</code> 设置为 <code>true</code>，则也包括未来日期的页面。</li><li><code>categories</code>：获取所有包含文章的分类。</li><li><code>tags</code>：获取所有包含文章的标签。</li><li><code>data</code>：获取所有自定义数据。</li></ul><h2 id="初始化"><a class="markdownIt-Anchor" href="#初始化"></a> 初始化</h2><pre><code class="language-javascript">init() {  this.log.debug('Hexo version: %s', (0, picocolors_1.magenta)(this.version));  this.log.debug('Working directory: %s', (0, picocolors_1.magenta)((0, tildify_1.default)(this.base_dir)));  // Load internal plugins  require('../plugins/console')(this);  require('../plugins/filter')(this);  require('../plugins/generator')(this);  require('../plugins/helper')(this);  require('../plugins/highlight')(this);  require('../plugins/injector')(this);  require('../plugins/processor')(this);  require('../plugins/renderer')(this);  require('../plugins/tag').default(this);  // Load config  return bluebird_1.default.each([    'update_package', // Update package.json    'load_config', // Load config    'load_theme_config', // Load alternate theme config    'load_plugins' // Load external plugins &amp; scripts  ], name =&gt; require(`./${name}`)(this)).then(() =&gt; this.execFilter('after_init', null, { context: this })).then(() =&gt; {    // Ready to go!    this.emit('ready');  });}</code></pre><p><code>init</code> 方法负责进行初始化工作：</p><ol><li>打印 Hexo 版本和工作目录信息到控制台，使用 <code>picocolors</code> 库为版本和目录路径上色。</li><li>加载内部插件。</li><li>执行一系列初始化步骤后，使用了 <code>bluebird.each</code> 方法按顺序执行以下步骤：<ul><li><code>update_package</code>：更新 <code>package.json</code> 文件。</li><li><code>load_config</code>：加载配置文件。</li><li><code>load_theme_config</code>：加载主题配置文件。</li><li><code>load_plugins</code>：加载外部插件和脚本。</li></ul></li><li>在所有初始化步骤完成后，执行 <code>after_init</code> 过滤器，允许插件和主题在初始化后进行一些额外的操作。</li><li>发射 <code>ready</code> 事件，表示 Hexo 已经准备就绪，可以执行其他操作了。</li></ol><h2 id="调用控制台命令"><a class="markdownIt-Anchor" href="#调用控制台命令"></a> 调用控制台命令</h2><pre><code class="language-javascript">call(name, args, callback) {  if (!callback &amp;&amp; typeof args === 'function') {    callback = args;    args = {};  }  const c = this.extend.console.get(name);  if (c)    return Reflect.apply(c, this, [args]).asCallback(callback);  return bluebird_1.default.reject(new Error(`Console \`${name}\` has not been registered yet!`));}</code></pre><p>这段代码定义了 <code>call</code> 方法，用于调用已注册的控制台命令。</p><p>先是检查了是否传入回调函数。如果没有，但是第二个参数是一个函数的话，就将第二个参数视为回调函数，同时将 <code>args</code> 设置为一个空对象。这是为了兼容只传入回调函数的情况。</p><p>从 <code>this.extend.console</code> 对象中获取名为 <code>name</code> 的控制台命令。如果找到了对应的控制台命令对象 <code>c</code>，便执行以下步骤：</p><ol><li>使用 <code>Reflect</code> 对象的 <code>apply</code> 方法调用控制台命令 <code>c</code>。</li><li><code>.asCallback(callback)</code> 将上一步的调用结果转换为一个 Promise 对象，并将该 Promise 与回调函数 <code>callback</code> 关联。这样就可以在 Promise 完成时自动调用回调函数。</li></ol><p>如果未能找到对应的控制台命令对象，就返回一个被拒绝的 Promise，其中包含一个表示该命令尚未注册的错误消息。</p><h2 id="定义数据库模型"><a class="markdownIt-Anchor" href="#定义数据库模型"></a> 定义数据库模型</h2><pre><code class="language-javascript">model(name, schema) {  return this.database.model(name, schema);}</code></pre><p>回到 <a href="####%E6%95%B0%E6%8D%AE%E5%BA%93">数据库</a> 的 <code>Database</code> 类，能看出 <code>model</code> 方法是用来创建一个模型的。</p><h2 id="解析插件"><a class="markdownIt-Anchor" href="#解析插件"></a> 解析插件</h2><pre><code class="language-javascript">resolvePlugin(name, basedir) {  try {    // Try to resolve the plugin with the Node.js's built-in require.resolve.    return require.resolve(name, { paths: [basedir] });  }  catch (err) {    try {      // There was an error (likely the node_modules is corrupt or from early version of npm)      // Use Hexo prior 6.0.0's behavior (resolve.sync) to resolve the plugin.      resolveSync = resolveSync || require('resolve').sync;      return resolveSync(name, { basedir });    }    catch (err) {      // There was an error (likely the plugin wasn't found), so return a possibly      // non-existing path that a later part of the resolution process will check.      return (0, path_1.join)(basedir, 'node_modules', name);    }  }}</code></pre><p>先是使用 <code>require.resolve</code> 方法用于解析模块。如果解析失败了，就继续尝试使用 <code>resolve.sync</code> 方法。最后如果依然失败，则返回一个可能不存在的路径以供后续处理。</p><blockquote><p><code>require.resolve</code> 方法是 Node.js 内置的，用于解析模块的路径。 如果 <code>require.resolve</code> 失败，通常是由于 <code>node_modules</code> 目录损坏或其他原因。</p><p><code>require('resolve').sync</code> 方法是一个更兼容旧版本 npm 的解决方案，类似于早期 Hexo 版本的插件解析方式。<code>resolve.sync</code> 方法如果也失败，很有可能是因为插件未找到，这时候便返回一个大概并不存在的路径。</p></blockquote><h2 id="加载插件"><a class="markdownIt-Anchor" href="#加载插件"></a> 加载插件</h2><pre><code class="language-javascript">loadPlugin(path, callback) {  return (0, hexo_fs_1.readFile)(path).then(script =&gt; {    // Based on: https://github.com/nodejs/node-v0.x-archive/blob/v0.10.33/src/node.js#L516    const module = new module_1.default(path);    module.filename = path;    module.paths = module_1.default._nodeModulePaths(path);    function req(path) {      return module.require(path);    }    req.resolve = (request) =&gt; module_1.default._resolveFilename(request, module);    req.main = require.main;    req.extensions = module_1.default._extensions;    req.cache = module_1.default._cache;    script = `(async function(exports, require, module, __filename, __dirname, hexo){${script}\n});`;    const fn = (0, vm_1.runInThisContext)(script, path);    return fn(module.exports, req, module, path, (0, path_1.dirname)(path), this);  }).asCallback(callback);}</code></pre><ol><li><p>使用 <code>hexo-fs</code> 库的 <code>readFile</code> 异步读取插件文件的内容，返回一个 Promise 对象。</p><blockquote><p><code>hexo-fs</code> 库的源代码未来再说，暂且只需要知道是 Hexo 的文件系统模块。</p></blockquote><p><a href="https://github.com/hexojs/hexo-fs"><img src="https://gh-card.dev/repos/hexojs/hexo-fs.svg" alt="hexojs/hexo-fs - GitHub" loading="lazy"></a></p></li><li><p>接着创建模块环境，并设置 <code>filename</code> 和 <code>paths</code> 属性。这里的 <code>module_1</code> 是 <code>module</code> 模块，定义了多种与模块加载、解析和处理相关的类型和接口。<code>filename</code> 属性被赋值插件的路径 <code>path</code>；<code>paths</code> 被赋值模块的搜索路径。</p></li><li><p><code>req</code> 方法用于模块加载。这个方法实际上模拟了 <code>require</code> 函数。之后这段代码分别定义了 <code>req.resolve</code> 方法来解析模块的绝对路径，设置 <code>req.main</code> 属性来指向 Node.js 主模块、<code>req.extensions</code> 属性来处理模块文件的加载、<code>req.cache</code> 属性来缓存加载的模块。</p></li><li><p>插件的内容被包装在一个异步函数中，并传入了必要的参数、赋值给变量 <code>script</code>。</p></li><li><p>使用 <code>vm_1.runInThisContext</code> 方法将包装后的插件内容编译为可执行函数。</p><ul><li><code>vm_1</code> 是 <code>vm</code> 模块，提供了一组 API 用于在 JavaScript 中创建虚拟机和运行沙盒化的代码。</li></ul></li><li><p>执行编译后的函数，传入需要的参数。</p></li><li><p>最终将 Promise 对象转换为回调函数形式，并进行执行。</p></li></ol><h2 id="显示草稿内容"><a class="markdownIt-Anchor" href="#显示草稿内容"></a> 显示草稿内容</h2><pre><code class="language-javascript">_showDrafts() {  const { args } = this.env;  return args.draft || args.drafts || this.config.render_drafts;}</code></pre><p>根据用户的输入和 Hexo 的配置，确定是否应该显示草稿内容。</p><h2 id="加载"><a class="markdownIt-Anchor" href="#加载"></a> 加载</h2><pre><code class="language-javascript">load(callback) {  return (0, load_database_1.default)(this).then(() =&gt; {    this.log.info('Start processing');    return bluebird_1.default.all([      this.source.process(),      this.theme.process()    ]);  }).then(() =&gt; {    mergeCtxThemeConfig(this);    return this._generate({ cache: false });  }).asCallback(callback);}</code></pre><blockquote><p><code>load_database</code> 模块检查数据库文件是否存在，存在则尝试加载数据库。如果加载失败，则删除数据库文件。它使用了 <code>hexo-fs</code> 模块来处理文件系统操作，并使用 <code>bluebird</code> 提供的 Promise 来管理异步操作。通过 <code>ctx</code> 上下文对象来传递数据库和日志对象，以及跟踪数据库加载状态。</p><pre><code class="language-javascript">"use strict";var __importDefault = (this &amp;&amp; this.__importDefault) || function (mod) {  return (mod &amp;&amp; mod.__esModule) ? mod : { "default": mod };};const hexo_fs_1 = require("hexo-fs");const bluebird_1 = __importDefault(require("bluebird"));module.exports = (ctx) =&gt; {  if (ctx._dbLoaded)    return bluebird_1.default.resolve();  const db = ctx.database;  const { path } = db.options;  const { log } = ctx;  return (0, hexo_fs_1.exists)(path).then(exist =&gt; {    if (!exist)      return;    log.debug('Loading database.');    return db.load();  }).then(() =&gt; {    ctx._dbLoaded = true;  }).catch(() =&gt; {    log.error('Database load failed. Deleting database.');    return (0, hexo_fs_1.unlink)(path);  });};//# sourceMappingURL=load_database.js.map</code></pre></blockquote><p>在数据库加载完成后，使用 <code>then</code> 方法处理返回的 Promise。在这个处理函数中，首先记录了日志信息 <code>Start processing</code>，然后使用 <code>bluebird_1.default.all</code> 方法并行处理两个任务：</p><ul><li><code>this.source.process()</code> 处理源文件。</li><li><code>this.theme.process()</code> 处理主题。</li></ul><p>处理完源文件和主题后，再次使用了 <code>then</code> 方法处理返回的 Promise。调用 <code>mergeCtxThemeConfig</code> 函数，将 <code>Hexo</code> 实例的上下文与主题配置合并，然后调用了 <code>this._generate({ cache: false })</code> 方法，生成静态文件。</p><p><code>mergeCtxThemeConfig</code> 函数在 <code>index.js</code> 文件的很上方：</p><pre><code class="language-javascript">const mergeCtxThemeConfig = (ctx) =&gt; {  if (ctx.config.theme_config) {    ctx.theme.config = (0, hexo_util_1.deepMerge)(ctx.theme.config, ctx.config.theme_config);  }};</code></pre><p>该函数用于将 <code>ctx.config.theme_config</code>（主题配置）合并到 <code>ctx.theme.config</code>（博客目录）中。这里还使用了 <code>hexo-util</code> 库的深度合并。<code>hexo-util</code> 库也是未来会讲的。</p><p><a href="https://github.com/hexojs/hexo-util"><img src="https://gh-card.dev/repos/hexojs/hexo-util.svg" alt="hexojs/hexo-util - GitHub" loading="lazy"></a></p><pre><code class="language-javascript">_generate(options = {}) {  if (this._isGenerating)    return;  const useCache = options.cache;  this._isGenerating = true;  this.emit('generateBefore');  // Run before_generate filters  return this.execFilter('before_generate', null, { context: this })    .then(() =&gt; this._routerRefresh(this._runGenerators(), useCache)).then(() =&gt; {      this.emit('generateAfter');      // Run after_generate filters      return this.execFilter('after_generate', null, { context: this });    }).finally(() =&gt; {      this._isGenerating = false;    });}</code></pre><p>为了防止重复生成，<code>_generate</code> 方法先是判断了 <code>_isGenerating</code> 变量，再进行接下来的操作。从 <code>options</code> 参数中提取 <code>cache</code> 选项，是为了决定是否在生成过程中使用缓存。</p><p>设置 <code>this._isGenerating</code> 为 <code>true</code> 后，便开始生成。<code>generateBefore</code> 事件被触发，接着执行 <code>before_generate</code> 过滤器。</p><blockquote><p>过滤器（Filter）后续会讲解。目前先延申 <a href="https://hexo.io/zh-cn/api/filter">Hexo 官方文档</a> 中的说明：</p><blockquote><p>过滤器用于修改特定文件，Hexo 将这些文件依序传给过滤器，而过滤器可以针对文件进行修改。</p></blockquote></blockquote><blockquote><p>其中的 <code>execFilter</code> 方法在 <code>Hexo</code> 类的最下方被定义：</p><pre><code class="language-javascript">execFilter(type, data, options) {    return this.extend.filter.exec(type, data, options);}</code></pre><blockquote><p><code>Hexo</code> 类也有一个 <code>execFilterSync</code> 方法：</p><pre><code class="language-javascript">execFilterSync(type, data, options) {  return this.extend.filter.execSync(type, data, options);}</code></pre></blockquote></blockquote><p><code>before_generate</code> 过滤器执行完毕后，调用 <code>_routerRefresh</code> 方法：</p><blockquote><pre><code class="language-javascript">_routerRefresh(runningGenerators, useCache) {  const { route } = this;  const routeList = route.list();  const Locals = this._generateLocals();  Locals.prototype.cache = useCache;  return runningGenerators.map((generatorResult) =&gt; {    if (typeof generatorResult !== 'object' || generatorResult.path == null)      return undefined;    const path = route.format(generatorResult.path);    const { data, layout } = generatorResult;    if (!layout) {      route.set(path, data);      return path;    }    return this.execFilter('template_locals', new Locals(path, data), { context: this })      .then(locals =&gt; { route.set(path, createLoadThemeRoute(generatorResult, locals, this)); })      .thenReturn(path);  }).then(newRouteList =&gt; {    for (let i = 0, len = routeList.length; i &lt; len; i++) {      const item = routeList[i];      if (!newRouteList.includes(item)) {        route.remove(item);      }    }  });}</code></pre><ol><li>初始化和获取路由列表：从 <code>this</code> 中获取 <code>route</code> 对象，并调用其 <code>list</code> 方法获取当前路由列表；生成局部变量 <code>Locals</code>，并将 <code>useCache</code> 选项赋给 <code>Locals.prototype.cache</code>，决定是否使用缓存。</li><li>处理生成器结果：遍历 <code>runningGenerators</code> 数组，对于每个生成器结果进行处理。如果 <code>generatorResult</code> 不是对象或 <code>path</code> 为空，则返回 <code>undefined</code>。</li><li>格式化路径并处理数据：调用 <code>route.format</code> 方法格式化路径；解构 <code>generatorResult</code>，获取 <code>data</code> 和 <code>layout</code>。如果 <code>layout</code> 不存在，直接将 <code>path</code> 和 <code>data</code> 设置到路由中，并返回 <code>path</code>。</li><li>执行 <code>template_locals</code> 过滤器并设置路由：调用 <code>execFilter</code> 方法执行 <code>template_locals</code> 过滤器，传入新的 <code>Locals</code> 实例。在过滤器执行完毕后，将路径和创建的主题路由设置到路由中，并返回 <code>path</code>。<pre><code class="language-javascript">const createLoadThemeRoute = function (generatorResult, locals, ctx) {  const { log, theme } = ctx;  const { path, cache: useCache } = locals;  const layout = [...new Set(castArray(generatorResult.layout))];  const layoutLength = layout.length;  locals.cache = true;  return () =&gt; {    if (useCache &amp;&amp; routeCache.has(generatorResult))      return routeCache.get(generatorResult);    for (let i = 0; i &lt; layoutLength; i++) {      const name = layout[i];      const view = theme.getView(name);      if (view) {        log.debug(`Rendering HTML ${name}: ${(0, picocolors_1.magenta)(path)}`);        return view.render(locals)          .then(result =&gt; ctx.extend.injector.exec(result, locals))          .then(result =&gt; ctx.execFilter('_after_html_render', result, {            context: ctx,            args: [locals]          }))          .tap(result =&gt; {            if (useCache) {              routeCache.set(generatorResult, result);            }          }).tapCatch(err =&gt; {            log.error({ err }, `Render HTML failed: ${(0, picocolors_1.magenta)(path)}`);          });      }    }    log.warn(`No layout: ${(0, picocolors_1.magenta)(path)}`);  };};</code></pre><code>createLoadThemeRoute</code> 方法创建加载主题路由的闭包。<br>首先从 <code>ctx</code> 中获取日志记录器 <code>log</code> 和主题对象 <code>theme</code>、从 <code>locals</code> 中获取路由的路径 <code>path</code> 和缓存标志 <code>useCache</code>。然后将 <code>generatorResult.layout</code> 转换为一个唯一的布局数组，记录布局的长度，同时将 <code>locals.cache</code> 设置为 <code>true</code>，以确保视图在渲染期间使用缓存。<br>返回一个闭包。闭包指的是函数和函数内部引用的外部变量的组合。该闭包在调用时会渲染 HTML 视图。<br>如果 <code>useCache</code> 为 <code>true</code>，并且缓存中存在 <code>generatorResult</code>，直接返回缓存的结果。否则遍历布局数组，并尝试从主题中获取对应的视图。<br>如果找到了视图，就使用该视图渲染 <code>locals</code>，并执行注入器和过滤器，最后返回渲染结果。否则记录警告并返回。</li></ol><blockquote><p>注入器（Injector）是 Hexo 扩展之一，在 <a href="https://hexo.io/zh-cn/api/injector">Hexo 官方文档</a> 中被声明为 <strong>用于将静态代码片段注入生成的 HTML 的 <code>&lt;head&gt;</code> 和 / 或 <code>&lt;body&gt;</code> 中</strong>，且注入必须在 <code>after_render:html</code> 过滤器之前完成。</p></blockquote><ol start="5"><li>移除旧路由：获取新生成的 <code>newRouteList</code>；遍历旧路由列表 <code>routeList</code>，如果某个路由不在 <code>newRouteList</code> 中，则将其移除。</li></ol><p><code>_routerRefresh</code> 方法确保了生成器结果正确应用到路由中，同时清理不再需要的旧路由，保持路由的最新状态。</p></blockquote><p>路由刷新完成后，<code>_generate</code> 方法触发了 <code>generateAfter</code> 事件，并执行 <code>after_generate</code> 过滤器。</p><p>最后使用 <code>finally</code> 方法确保无论生成过程成功与否，都会将 <code>this._isGenerating</code> 重置为 <code>false</code>，允许后续生成操作进行。</p><p>通过执行前后过滤器和触发事件，<code>_generate</code> 方法确保生成过程的各个阶段都可以被插件或自定义代码扩展和修改。</p><p><code>load</code> 方法在调用 <code>_generate</code>、生成静态文件后，将整个异步操作的结果传递给回调函数 <code>callback</code>。<code>asCallback</code> 方法将 <code>Promise</code> 转换为传统的回调形式，以兼容老式回调风格的代码。</p><h2 id="监视文件变化"><a class="markdownIt-Anchor" href="#监视文件变化"></a> 监视文件变化</h2><p><code>watch</code> 函数的目的是在监视文件变化时重新生成内容，并在需要时启用缓存。</p><pre><code class="language-javascript">watch(callback) {  let useCache = false;  const { cache } = Object.assign({    cache: false  }, this.config.server);  const { alias } = this.extend.console;  if (alias[this.env.cmd] === 'server' &amp;&amp; cache) {    // enable cache when run hexo server    useCache = true;  }  this._watchBox = debounce(() =&gt; this._generate({ cache: useCache }), 100);  return (0, load_database_1.default)(this).then(() =&gt; {    this.log.info('Start processing');    return bluebird_1.default.all([      this.source.watch(),      this.theme.watch()    ]);  }).then(() =&gt; {    mergeCtxThemeConfig(this);    this.source.on('processAfter', this._watchBox);    this.theme.on('processAfter', () =&gt; {      this._watchBox();      mergeCtxThemeConfig(this);    });    return this._generate({ cache: useCache });  }).asCallback(callback);}</code></pre><ol><li><code>watch</code> 函数会先从 <code>this.config.server</code> 中读取 <code>cache</code> 配置，默认值为 <code>false</code>。如果当前命令为 <code>server</code>，并且配置了 <code>cache</code>，就会启用缓存。</li><li>接着使用 <code>debounce</code> 函数防抖 <code>_generate</code> 方法，间隔设置为 100 毫秒：<pre><code class="language-javascript">function debounce(func, wait) {    let timeout;    return function () {        clearTimeout(timeout);        timeout = setTimeout(() =&gt; {            func.apply(this);        }, wait);    };}</code></pre><code>debounce</code> 函数的目的是限制某个函数在一段时间内的调用次数，当该函数被连续调用时，只有在停止调用后等待指定的时间才会真正执行。这样便可以优化性能。</li><li>调用 <code>load_database_1.default</code> 方法加载数据库，打印日志 <code>Start processing</code>，同时监视 <code>source</code> 和 <code>theme</code> 的变化，使用 <code>bluebird_1.default.all</code> 以并行方式执行。</li><li>合并主题配置并设置监控回调：这里的 <code>mergeCtxThemeConfig</code> 方法之前已经说过了。当 <code>source</code> 处理完成后，调用 <code>_watchBox</code>；当 <code>theme</code> 处理完成后，调用 <code>_watchBox</code> 并再次合并主题配置。</li><li>调用 <code>_generate</code> 方法，初次生成内容，并根据 <code>useCache</code> 决定是否使用缓存。</li><li>最后使用 <code>bluebird</code> 库的 <code>asCallback</code> 方法，将结果作为回调传递给 <code>callback</code>。</li></ol><h2 id="停止监控"><a class="markdownIt-Anchor" href="#停止监控"></a> 停止监控</h2><p>既然有了监视用的方法，那么也有取消监视的方法。</p><pre><code class="language-javascript">unwatch() {  if (this._watchBox != null) {    this.source.removeListener('processAfter', this._watchBox);    this.theme.removeListener('processAfter', this._watchBox);    this._watchBox = null;  }  stopWatcher(this.source);  stopWatcher(this.theme);}</code></pre><p><code>unwatch</code> 方法检查并清除了 <code>_watchBox</code>。根据上面 <code>watch</code> 方法的内容，<code>this._watchBox</code> 是一个防抖函数，用来处理文件变动后的生成操作。如果它存在，就需要将其从 <code>source</code> 和 <code>theme</code> 对象的 <code>processAfter</code> 事件监听器中移除。</p><p><code>stopWatcher</code> 函数被定义在 <code>index.js</code> 的最上方：</p><pre><code class="language-javascript">const stopWatcher = (box) =&gt; { if (box.isWatching())  box.unwatch(); };</code></pre><p>它用于停止对给定对象的监控。逻辑很简单：该对象是否正在被监控，如果是，就调用 <code>unwatch</code> 方法停止监控。</p><h2 id="生成本地环境"><a class="markdownIt-Anchor" href="#生成本地环境"></a> 生成本地环境</h2><pre><code class="language-javascript">_generateLocals() {  const { config, env, theme, theme_dir } = this;  const ctx = { config: { url: this.config.url } };  const localsObj = this.locals.toObject();  class Locals {    constructor(path, locals) {      this.page = Object.assign({}, locals);      if (this.page.path == null)        this.page.path = path;      this.path = path;      this.url = hexo_util_1.full_url_for.call(ctx, path);      this.config = config;      this.theme = theme.config;      this.layout = 'layout';      this.env = env;      this.view_dir = (0, path_1.join)(theme_dir, 'layout') + path_1.sep;      this.site = localsObj;    }  }  return Locals;}</code></pre><p><code>Locals</code> 类中，许多环境相关的属性，如 <code>url</code>、<code>config</code> 等属性都被设置。该方法生成了本地环境的信息对象，以便在模块渲染过程中使用。</p><h2 id="运行生成器"><a class="markdownIt-Anchor" href="#运行生成器"></a> 运行生成器</h2><blockquote><p>同样，生成器（Generator）后续也会讲解。</p><p>在 <a href="https://hexo.io/zh-cn/api/generator">Hexo 官方文档</a> 中，生成器被解释为 <strong>会根据处理后的原始文件建立路由</strong>。</p></blockquote><pre><code class="language-javascript">_runGenerators() {  this.locals.invalidate();  const siteLocals = this.locals.toObject();  const generators = this.extend.generator.list();  const { log } = this;  // Run generators  return bluebird_1.default.map(Object.keys(generators), key =&gt; {    const generator = generators[key];    log.debug('Generator: %s', (0, picocolors_1.magenta)(key));    return Reflect.apply(generator, this, [siteLocals]);  }).reduce((result, data) =&gt; {    return data ? result.concat(data) : result;  }, []);}</code></pre><ol><li><code>invalidate</code> 方法使 <code>Hexo</code> 实例的本地数据无效，以便在生成器运行之前重新加载。</li><li>提取当前 <code>Hexo</code> 实例的本地数据对象，将其赋值给 <code>siteLocals</code> 变量。</li><li>获取 <code>Hexo</code> 实例中已注册的所有生成器，将它们保存在 <code>generators</code> 变量中。</li><li>运行生成器之前，记录了一条调试信息，指示将要运行哪个生成器。</li><li>使用 <code>bluebird</code> 库的 <code>map</code> 方法对生成器进行并行处理。每个生成器都被调用 <code>Reflect.apply(generator, this, [siteLocals])</code>，将生成器函数应用到当前的 <code>Hexo</code> 实例上。</li><li>使用 <code>bluebird</code> 库的 <code>reduce</code> 方法将生成器返回的数据收集到一个数组中，并返回这个数组。</li></ol><p><code>_runGenerators</code> 方法运行 <code>Hexo</code> 实例中所有注册的生成器，并将它们返回的数据收集到一个数组中。</p><h2 id="退出进程"><a class="markdownIt-Anchor" href="#退出进程"></a> 退出进程</h2><p><code>exit</code> 方法用于退出 Hexo 进程。</p><pre><code class="language-javascript">exit(err) {  if (err) {    this.log.fatal({ err }, 'Something\'s wrong. Maybe you can find the solution here: %s', (0, picocolors_1.underline)('https://hexo.io/docs/troubleshooting.html'));  }  return this.execFilter('before_exit', null, { context: this }).then(() =&gt; {    this.emit('exit', err);  });}</code></pre><p>这里值得说的是，<code>exit</code> 方法会触发 <code>execFilter</code> 方法、触发 <code>before_exit</code> 过滤器。以及最终它会触发 <code>exit</code> 事件。</p><h2 id="定义属性和导出"><a class="markdownIt-Anchor" href="#定义属性和导出"></a> 定义属性和导出</h2><pre><code class="language-javascript">Hexo.lib_dir = libDir + path_1.sep;Hexo.prototype.lib_dir = Hexo.lib_dir;Hexo.core_dir = (0, path_1.dirname)(libDir) + path_1.sep;Hexo.prototype.core_dir = Hexo.core_dir;Hexo.version = version;Hexo.prototype.version = Hexo.version;module.exports = Hexo;</code></pre><p><code>Hexo</code> 类本身终于讲完了，在 <code>Hexo</code> 类的下方，它的部分属性和原型属性被定义，并最终被导出为模块的默认输出。</p><ul><li><code>LibDir</code>：<code>Hexo</code> 库目录的路径。</li><li><code>core_dir</code>：核心目录的路径。</li><li><code>version</code>：版本号。</li></ul></body></html>]]></content>
    
    
    <summary type="html">本文深入分析了 Hexo 7.2.0 的源代码，从入口文件 dist/hexo/index.js 入手，详细剖析了核心 Hexo 类的构造函数、属性和关键方法。文章逐一解读了路径管理、配置加载、渲染、路由、插件机制、数据模型等核心模块的实现原理，帮助你理解 Hexo 的底层工作机制，为深度定制或插件开发打下坚实基础。</summary>
    
    
    
    <category term="代码解读" scheme="https://blog.cytrogen.icu/categories/%E4%BB%A3%E7%A0%81%E8%A7%A3%E8%AF%BB/"/>
    
    
    <category term="Hexo" scheme="https://blog.cytrogen.icu/tags/Hexo/"/>
    
    <category term="JavaScript" scheme="https://blog.cytrogen.icu/tags/JavaScript/"/>
    
  </entry>
  
  <entry>
    <title>IBM 全栈开发【8】：用于人工智能和开发项目的 Python</title>
    <link href="https://blog.cytrogen.icu/posts/224a.html"/>
    <id>https://blog.cytrogen.icu/posts/224a.html</id>
    <published>2024-05-19T22:49:00.000Z</published>
    <updated>2026-02-09T17:16:54.721Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程，故此记录学习笔记。</p><span id="more"></span><h1 id="1-python编码实践和打包概念"><a class="markdownIt-Anchor" href="#1-python编码实践和打包概念"></a> 1. Python 编码实践和打包概念</h1><h2 id="11-开发生命周期"><a class="markdownIt-Anchor" href="#11-开发生命周期"></a> 1.1. 开发生命周期</h2><p>应用程序开发生命周期分为七个阶段，包括：</p><ul><li>收集需求： 收集应用程序的用户、业务和技术需求。</li><li>分析： 分析需求。</li><li>设计： 设计完整的解决方案。</li><li>编码和测试： 构建和测试应用程序的不同组件。</li><li>用户和系统测试： 用户测试应用程序的可用性，进行系统集成测试和性能测试。</li><li>生产： 应用程序可供所有最终用户使用。</li><li>维护： 升级或修复任何用户或系统问题。</li></ul><h2 id="12-pep8"><a class="markdownIt-Anchor" href="#12-pep8"></a> 1.2. PEP8</h2><p>PEP8 关于代码可读性的指导原则包括以下内容：</p><ul><li>缩进四个空格。</li><li>空行用于分隔函数和类。</li><li>操作符周围和逗号后的空格。</li></ul><p>PEP8 的编码规范具有一致性和可管理性，其中包括：</p><ul><li>在函数内添加较大的代码块。</li><li>使用带下划线的小写字母命名函数和文件。</li><li>使用驼峰大写为类命名。</li><li>用大写字母命名常量，单词之间用下划线分隔。</li></ul><h2 id="13-单元测试"><a class="markdownIt-Anchor" href="#13-单元测试"></a> 1.3. 单元测试</h2><p>单元测试是一种验证代码单元是否按设计运行的方法。在与最终代码库集成之前，必须测试每个单元。</p><h4 id="131-例子"><a class="markdownIt-Anchor" href="#131-例子"></a> 1.3.1. 例子</h4><pre><code class="language-python">def add(a,b):    return a + bdef substract(a,b):    return a - b</code></pre><pre><code class="language-python">import unittestfrom math import add, substractclass TestMain(unittest.TestCase):    def test_add(self):        self.assertEqual(add(6,4),10)        def test_substract(self):        self.assertEqual(substract(6,4),3)</code></pre><h2 id="14-创建包"><a class="markdownIt-Anchor" href="#14-创建包"></a> 1.4. 创建包</h2><ol><li>以软件包名称创建文件夹。</li><li>创建一个空的 <code>__init__.py</code> 文件。</li><li>创建所需的模块。</li><li>在 <code>__init__.py</code> 文件中，添加代码以引用软件包中需要的模块。</li></ol><p>可以在 Python shell 中通过 bash 终端验证软件包。</p><h2 id="15-其他"><a class="markdownIt-Anchor" href="#15-其他"></a> 1.5. 其他</h2><p>关于网络应用程序，以下两种说法是正确的：</p><blockquote><p>所有网络应用程序都是 API。</p><p>网络应用支持 CRUD 操作。</p></blockquote><p>在哪个测试阶段验证应用程序在更大框架内的功能？：</p><blockquote><p>集成测试。</p></blockquote><p>PyLint 是一款 Python 静态代码分析工具。</p><p>在为一个管理活动的应用程序收集需求时，客户提到项目的目标是提高客户保留率。<br><strong>业务需求</strong> 描述了上述情况。</p><h1 id="2-使用flask部署网络应用程序"><a class="markdownIt-Anchor" href="#2-使用flask部署网络应用程序"></a> 2. 使用 Flask 部署网络应用程序</h1><h2 id="21-flask"><a class="markdownIt-Anchor" href="#21-flask"></a> 2.1. Flask</h2><p>Flask 是一个微型框架，只需最少的依赖即可运行。Flask 具有调试服务器、路由、模板和错误处理等功能，可用于构建网站。Flask 可以作为 python 软件包安装。与 Flask 相比，Django 是一个全栈框架。你可以通过实例化 Flask 类来创建服务器。</p><p>Flask 为每次客户端调用提供一个请求和一个响应对象。可以从 Flask 请求中获取更多信息，如标题。您可以解析请求对象，获取查询参数、正文和其他参数。您甚至可以在将响应发送回客户端之前，在响应对象上设置状态。</p><p>可以使用动态路由创建 RESTful 端点。</p><p>HTTP 状态代码有多种类型，分别显示成功、用户错误或服务器错误。Flask 在响应时会隐式返回成功代码 200。您也可以明确提供状态代码。Flask 还提供应用程序级的错误处理程序。</p><p>Flask 支持 CRUD。</p><p>可以使用 Flask 渲染静态和动态模板。</p><h4 id="211-代码案例"><a class="markdownIt-Anchor" href="#211-代码案例"></a> 2.1.1. 代码案例</h4><p>实例化 Flask：</p><pre><code class="language-python">from flask import Flaskapp = Flask(__name__)</code></pre><p><code>@app.route</code> 装饰器：</p><pre><code class="language-python">@app.route('/')def hello_world():    return "&lt;b&gt;My first Flask application in action!&lt;/b&gt;"</code></pre><p>400 错误：</p><pre><code class="language-python">@app.route('/')def search_response():    query = request.args.get('q')    if not query:        return {"error_message": "Input parameter missing"}, 422    resource = fetch_from_database(query)    if resource:        return {"message": resource}    else:        return {"error_message": "Resource not found"}, 404</code></pre><h1 id="3-使用flask创建人工智能应用并进行部署"><a class="markdownIt-Anchor" href="#3-使用flask创建人工智能应用并进行部署"></a> 3. 使用 Flask 创建人工智能应用并进行部署</h1><div class="danger"><p><code>Watson NLP</code> 库被嵌入到实验网页中，外部工具无法访问。</p></div><h2 id="31-项目概述"><a class="markdownIt-Anchor" href="#31-项目概述"></a> 3.1. 项目概述</h2><p>在这个同行评分的毕业设计中，你将扮演一名软件工程师，需要开发一款基于人工智能的网络应用程序。您将分析情景并执行以下任务：</p><ol><li>克隆项目资源库。</li><li>使用 <code>Watson NLP</code> 库创建一个情绪检测应用程序。</li><li>格式化应用程序的输出。</li><li>打包应用程序。</li><li>在应用程序上运行单元测试。</li><li>使用 Flask 对应用程序进行网络部署。</li><li>纳入错误处理。</li><li>运行静态代码分析。</li></ol><div class="github-card" data-github="ibm-developer-skills-network/oaqjp-final-project-emb-ai" data-width="400" data-height="150" data-theme="default"></div><script src="//cdn.jsdelivr.net/github-cards/latest/widget.js"></script><p>在这个项目中，您将开发一个集成了 Embeddable Watson 人工智能库的网络应用程序。然后，您将提交相关截图供同行评审。</p><h2 id="32-情景"><a class="markdownIt-Anchor" href="#32-情景"></a> 3.2. 情景</h2><p>你被一家电子商务公司聘为软件工程师，负责创建一个基于人工智能的网络应用程序，对其特色产品的客户反馈进行分析。为实现这一要求，您将创建一个情感检测系统，处理客户以文本格式提供的反馈，并解读相关的情感表达。</p><blockquote><p>情感检测扩展了情感分析的概念，从语句中提取更细微的情感，如喜悦、悲伤、愤怒等，而不是情感分析所提供的简单极性。这使得情感检测成为一个非常重要的研究分支，企业将此类系统广泛用于基于人工智能的推荐系统、自动聊天机器人等。</p></blockquote><h4 id="321-详情"><a class="markdownIt-Anchor" href="#321-详情"></a> 3.2.1. 详情</h4><p><code>Watson NLP</code> 库是预装在 Cloud IDE 框架中的可嵌入库。因此，无需将它们导入到你的代码中。你只需向库中的正确函数发送 post 请求，然后接收输出。</p><p>这些可嵌入的人工智能库基于流行的人工智能模型，提供了各种基于 NLP 和语音的功能。</p><p>使用 <code>Watson NLP</code> 库的 <code>Emotion Predict</code> 方法。访问该功能的 URL、Headers 和 Input json 格式如下。</p><pre><code class="language-plaintext">URL: 'https://sn-watson-emotion.labs.skills.network/v1/watson.runtime.nlp.v1/NlpService/EmotionPredict'Headers: {"grpc-metadata-mm-model-id": "emotion_aggregated-workflow_lang_en_stock"}Input json: { "raw_document": { "text": text_to_analyse } }</code></pre><blockquote><p><code>text_to_analyze</code> 被用作一个变量，用于保存需要分析的实际书面文本。</p></blockquote><ol><li><p>在项目根目录创建 <code>emotion_detection.py</code> 文件。</p></li><li><p>创建 <code>emotion_detector</code> 方法用于运行情感检测。</p><ul><li>用于分析的文本会被存储在 <code>text_to_analyze</code> 变量中，并会被作为参数传入该方法内。</li></ul><pre><code class="language-python">import requests def emotion_detector(text_to_analyse: str):URL = 'https://sn-watson-emotion.labs.skills.network/v1/watson.runtime.nlp.v1/NlpService/EmotionPredict'Headers = { "grpc-metadata-mm-model-id": "emotion_aggregated-workflow_lang_en_stock" }Input_Json = { "raw_document": { "text": text_to_analyse } }response = requests.post(url=URL, json=Input_Json, headers=Headers)return response.json()</code></pre><p>返回的内容：</p><pre><code class="language-json">{    "emotionPredictions": [         {             "emotion": {                 "anger": 0.0132405795,                 "disgust": 0.0020517302,                 "fear": 0.009090992,                 "joy": 0.9699522,                 "sadness": 0.054984167             },             "target": "",             "emotionMentions": [                 {                     "span": {                         "begin": 0,                         "end": 26,                         "text": "i love this new technology"                     },                     "emotion": {                         "anger": 0.0132405795,                         "disgust": 0.0020517302,                         "fear": 0.009090992,                         "joy": 0.9699522,                         "sadness": 0.054984167                     }                 }             ]         }    ],    "producerId": {        "name": "Ensemble Aggregated Emotion Workflow",         "version": "0.0.1"    }}</code></pre></li><li><p>调整输出，使其返回以下格式的内容：</p><pre><code class="language-json">{    "anger": anger_score,    "disgust": disgust_score,    "fear": fear_score,    "joy": joy_score,    "sadness": sadness_score,    "dominant_emotion": "&lt;name of dominant emotion&gt;"}</code></pre><pre><code class="language-python">def emotion_detector(text_to_analyse: str):    URL = 'https://sn-watson-emotion.labs.skills.network/v1/watson.runtime.nlp.v1/NlpService/EmotionPredict'    Headers = { "grpc-metadata-mm-model-id": "emotion_aggregated-workflow_lang_en_stock" }    Input_Json = { "raw_document": { "text": text_to_analyse } }    response = requests.post(url=URL, json=Input_Json, headers=Headers)    emotions = response.json()['emotionPredictions'][0]['emotion']    items = emotions.items()    max_item = max(items, key=lambda x: x[1])    emotions['dominant_emotion'] = max_item[0]    return emotions</code></pre></li><li><p>创建 <code>EmotionDetection</code> Python 包。</p><ol><li>创建文件夹，命名为 <code>EmotionDetection</code>。</li><li>创建 <code>__init__.py</code> 文件。</li><li>在包的根目录下创建 <code>emotion_detector.py</code> 文件，其中包含我们之前创建的 <code>emotion_detector</code> 函数。</li></ol></li><li><p>在应用程序上运行单元测试。</p><ol><li>创建新文件 <code>test_emotion_detection.py</code>，调用包中的函数，并针对以下语句和主要情绪进行测试：<table><thead><tr><th>语句</th><th>主要情绪</th></tr></thead><tbody><tr><td>I am glad this happened</td><td>joy</td></tr><tr><td>I am really mad about this</td><td>anger</td></tr><tr><td>I feel disgusted just hearing about this</td><td>disgust</td></tr><tr><td>I am so sad about this</td><td>sadness</td></tr><tr><td>I am really afraid that this will happen</td><td>fear</td></tr></tbody></table><pre><code class="language-python">import pytestfrom EmotionDetection import emotion_detectordef test_emotion_detector():    test_cases = [        ("I am glad this happened", "joy"),        ("I am really mad about this", "anger"),        ("I feel disgusted just hearing about this", "disgust"),        ("I am so sad about this", "sadness"),        ("I am really afraid that this will happen", "fear"),    ]    for text, expected_emotion in test_cases:        result = emotion_detector(text)        assert result['dominant_emotion'] == expected_emotion, f"For text: {text}, expected: {expected_emotion}, but got: {result['dominant_emotion']}"if __name__ == "__main__":    pytest.main()</code></pre></li><li>检查单元测试输出，验证单元测试是否通过。<pre><code class="language-bash">python3.11 test_emotion_detection.py</code></pre></li></ol></li></ol><p>使用 Flask 进行应用程序的网络部署：</p><div class="danger"><p>注意：模板文件夹中的 <code>index.html</code> 文件和静态文件夹中的 <code>mywebscript.js</code> 文件已作为仓库的一部分提供。本项目无需对这些文件进行改动。</p></div><ol><li>在项目根目录下创建 <code>server.py</code>。确保应用程序调用函数的 Flask 装饰器是 <code>\emotionDetector</code>。客户要求以下面示例中的格式显示输出结果（假设是对 "I love my life" 这句话进行评价）：<pre><code class="language-json">{    "anger": 0.006274985,    "disgust": 0.0025598293,    "fear": 0.009251528,    "joy": 0.9680386,    "sadness": 0.049744144,    "dominant_emotion":"joy"}</code></pre>响应应当被格式化为：<pre><code class="language-plaintext">For the given statement, the system response is 'anger': 0.006274985, 'disgust': 0.0025598293, 'fear': 0.009251528, 'joy': 0.9680386 and 'sadness': 0.049744144. The dominant emotion is joy.</code></pre>应用程序需要部署在 <code>localhost:5000</code> 上。</li><li>在函数 <code>emotion_detector</code> 中加入错误处理功能，以管理用户的空白条目，即在没有任何输入的情况下运行应用程序。<ul><li>访问服务器响应的 <code>status_code</code> 属性，以正确显示空白条目的系统响应。</li><li>对于 <code>status_code = 400</code>，函数将返回相同的字典，但所有键的值均为 <code>None</code>。</li></ul></li><li>修改 <code>server.py</code>，在 <code>dominant_emotion</code> 为 <code>None</code> 时加入错误处理。在这种情况下，响应应显示 <code>Invalid text! Please try again!.</code>。</li></ol><p><code>EmotionDetection/__init__.py</code>：</p><pre><code class="language-python">import requestsdef emotion_detector(text_to_analyse: str):    if not text_to_analyse:        return {'anger': None, 'disgust': None, 'fear': None, 'joy': None, 'sadness': None, 'dominant_emotion': None}            URL = 'https://sn-watson-emotion.labs.skills.network/v1/watson.runtime.nlp.v1/NlpService/EmotionPredict'    Headers = { "grpc-metadata-mm-model-id": "emotion_aggregated-workflow_lang_en_stock" }    Input_Json = { "raw_document": { "text": text_to_analyse } }    response = requests.post(url=URL, json=Input_Json, headers=Headers)    if response.status_code == 400:        return {'anger': None, 'disgust': None, 'fear': None, 'joy': None, 'sadness': None, 'dominant_emotion': None}    emotions = response.json()['emotionPredictions'][0]['emotion']    items = emotions.items()    max_item = max(items, key=lambda x: x[1])    emotions['dominant_emotion'] = max_item[0]    return emotions</code></pre><p><code>server.py</code>：</p><pre><code class="language-python">"""This module defines a Flask application that provides an emotion detection API."""from flask import Flask, request, render_templatefrom EmotionDetection import emotion_detectorapp = Flask(__name__)@app.route('/emotionDetector')def handle_emotion_detector():    """    This function handles GET requests to the /emotionDetector route. It    expects a textToAnalyze arg that contains the text to analyze. It returns    a string with all predicted emotions.    """    predicted_emotions = emotion_detector(request.args.get('textToAnalyze'))    if predicted_emotions['dominant_emotion'] is None:        return 'Invalid text! Please try again!'    response_text = ("For the given statement, " +                     f"the system response is 'anger': {predicted_emotions['anger']}, "                     f"'disgust': {predicted_emotions['disgust']}, " +                     f"'fear': {predicted_emotions['fear']}, "                     f"'joy': {predicted_emotions['joy']} " +                     f"and 'sadness': {predicted_emotions['sadness']}. "                     f"The dominant emotion is {predicted_emotions['dominant_emotion']}.")    return response_text@app.route("/")def render_index_page():    """    This function renders index.html to the / route.    """    return render_template('index.html')if __name__ == '__main__':    app.run(host='localhost', port=5000)</code></pre></body></html>]]></content>
    
    
    <summary type="html">本文是 IBM 全栈开发课程的第八篇学习笔记，聚焦于将 Python 应用于人工智能和实际开发项目。笔记首先介绍了 Python 的编码规范（PEP8）、单元测试、包的创建等软件工程最佳实践。接着，文章讲解了如何使用 Flask 微框架来部署网络应用，涵盖了路由、请求处理和错误处理等核心功能。最后，通过一个完整的毕业项目案例，详细演示了如何利用 Watson NLP 库创建一个情感检测 AI 应用，并将其打包、测试，最终通过 Flask 部署为一个功能完善的网络服务。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Python" scheme="https://blog.cytrogen.icu/tags/Python/"/>
    
    <category term="IBM" scheme="https://blog.cytrogen.icu/tags/IBM/"/>
    
  </entry>
  
  <entry>
    <title>IBM 全栈开发【7】：数据科学的 Python 基础</title>
    <link href="https://blog.cytrogen.icu/posts/b1c6.html"/>
    <id>https://blog.cytrogen.icu/posts/b1c6.html</id>
    <published>2024-05-18T04:27:00.000Z</published>
    <updated>2026-02-09T17:16:54.717Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程，故此记录学习笔记。</p><span id="more"></span><h1 id="1-python基础"><a class="markdownIt-Anchor" href="#1-python基础"></a> 1. Python 基础</h1><h1 id="2-python数据结构"><a class="markdownIt-Anchor" href="#2-python数据结构"></a> 2. Python 数据结构</h1><h1 id="3-python编程基础"><a class="markdownIt-Anchor" href="#3-python编程基础"></a> 3. Python 编程基础</h1><h1 id="4-用python处理数据"><a class="markdownIt-Anchor" href="#4-用python处理数据"></a> 4. 用 Python 处理数据</h1><h2 id="41-pandas"><a class="markdownIt-Anchor" href="#41-pandas"></a> 4.1. Pandas</h2><p><code>Pandas</code> 是一个功能强大的 Python 库，用于数据处理和分析，提供数据结构和函数来处理结构化数据，如数据帧和序列。</p><ul><li>可以使用 <code>import</code> 命令导入文件，然后输入文件名。</li><li>使用 <code>as</code> 命令可以为文件提供一个更短的名称。</li><li>在 Pandas 中，使用数据帧（<code>df</code>）来指定要读取的文件。</li><li>数据帧由行和列组成。</li><li>可以使用特定 <code>DataFrame</code> 的一列或多列来创建新的 <code>DataFrame</code>。</li><li>我们可以处理 <code>DataFrames</code> 中的数据，并将结果保存为不同的格式。</li><li>在 Python 中，可以使用 <code>Unique</code> 方法来确定 <code>DataFrames</code> 列中的唯一元素。</li><li>您可以使用不等式运算符和 <code>df</code>，为 <code>DataFrames</code> 中选定的列分配一个布尔值。</li><li>将新的 <code>DataFrame</code> 保存为不同的 <code>DataFrame</code>，其中可能包含先前 <code>DataFrame</code> 中的值。</li></ul><h2 id="42-numpy"><a class="markdownIt-Anchor" href="#42-numpy"></a> 4.2. NumPy</h2><p><code>NumPy</code> 是一个用于数值和矩阵运算的 Python 库，提供多维数组对象和各种数学函数，可高效处理数据。</p><ul><li><code>NumPy</code> 是 <code>Pandas</code> 的基础。</li><li><code>NumPy</code> 数组或 <code>ND</code> 数组类似于列表，通常具有固定大小和同类元素。</li></ul><p>一维 <code>NumPy</code> 数组是具有单轴的元素线性序列，就像传统的列表，但针对数值计算和数组操作进行了优化。</p><ul><li>可以使用索引访问 <code>NumPy</code> 数组中的元素。</li><li>使用属性 <code>dtype</code> 可以获取数组元素的数据类型。</li><li>你可以使用 <code>nsize</code> 和 <code>ndim</code> 分别获取数组的大小和维度。</li><li>可以在 <code>NumPy</code> 中使用索引和切片方法。</li><li>向量加法是 Python 中广泛使用的操作。</li><li>用线段或箭头来表示向量加法是非常有用的。</li><li><code>NumPy</code> 代码的运行速度更快，这对处理大量数据很有帮助。</li><li>用负号代替加号，可以执行向量减法。</li><li>在 Python 中，数组与标量相乘需要将数组中的每个元素与标量值相乘，从而得到一个新数组，其中的每个元素都按标量缩放。</li><li><code>Hadamard</code> 积是指两个相同形状的数组按元素相乘，得到一个新数组，其中每个元素都是输入数组中相应元素的乘积。</li><li>Python 中的点乘是两个数组的元素乘积之和，通常用于向量和矩阵操作，以找到相应元素相乘并求和的标量结果。</li><li>在使用 <code>NumPy</code> 时，通常会使用 <code>Matplotlib</code> 等库来从存储在 NumPy 数组中的数值数据创建图表和可视化效果。</li></ul><p>二维 <code>NumPy</code> 数组是一种具有行和列的网格状结构，适合以矩阵或表格的形式表示数据，用于数值计算。</p><ul><li>在 <code>NumPy</code> 中，<code>shape</code> 指的是数组的维数（行列数），表示数组的大小和结构。</li><li>使用属性 <code>size</code> 可以获得数组的大小。</li><li>使用矩形属性可以访问数组中的各种元素。</li><li>在 <code>NumPy</code> 中使用标量对元素进行乘法运算。</li></ul><h1 id="5-api和数据收集"><a class="markdownIt-Anchor" href="#5-api和数据收集"></a> 5. API 和数据收集</h1><h2 id="51-api"><a class="markdownIt-Anchor" href="#51-api"></a> 5.1. API</h2><p>Python 中的简单 API 是应用程序编程接口，它提供了与服务、库或数据交互的简单易用的方法，通常只需最少的配置或复杂度。<br>API 使两个软件可以相互对话。</p><p>在 Python 中使用 API 库需要导入该库，调用其函数或方法来发出 HTTP 请求，并解析响应以访问 API 提供的数据或服务。<br><code>Pandas</code> API 通过与其他软件组件通信来处理数据。</p><p>当你创建一个字典，然后使用 <code>DataFrames</code> 构造函数创建一个 <code>Pandas</code> 对象时，实例就形成了。</p><p>方法 <code>head</code> 将从 <code>DataFrames</code> 的顶部（默认为 <code>5</code>）显示所提及的行数，而方法 <code>means</code> 将计算平均值并返回值。</p><h4 id="511-rest-api"><a class="markdownIt-Anchor" href="#511-rest-api"></a> 5.1.1. REST API</h4><p>REST API 允许通过互联网进行通信，利用存储、访问更多数据、人工智能算法等资源。</p><ul><li><code>HTTP</code> 方法通过互联网传输数据。</li><li>HTTP 消息通常包含一个 JSON 文件，其中包含操作指令。</li><li>包含 JSON 文件的 HTTP 消息会作为网络服务的响应返回给客户端。</li><li>处理时间序列数据需要使用 <code>Pandas</code> 时间序列函数。</li><li>您可以获取每日蜡烛图数据，并使用 <code>Plotly</code> 绘制蜡烛图。</li></ul><h4 id="512-http"><a class="markdownIt-Anchor" href="#512-http"></a> 5.1.2. HTTP</h4><p>HTTP（超文本传输协议）在客户端（网络浏览器）和万维网服务器之间传输数据，包括网页和资源。</p><ul><li>HTTP 协议可能包括多种类型的 REST API。</li><li>HTTP 响应包括资源类型、资源长度等信息。</li><li>统一资源定位符（URL）是在网络上查找资源的最常用方法。</li><li>URL 分为三个部分：方案、互联网地址或基本 URL 和路径。</li><li><code>GET</code> 方法是请求信息的常用方法之一。其他一些方法也可能包含正文。</li><li>响应方法包含响应的版本和正文。</li><li><code>POST</code> 向服务器提交数据，<code>PUT</code> 更新服务器上已有的数据，<code>DELETE</code> 从服务器删除数据。</li></ul><h4 id="513-requests"><a class="markdownIt-Anchor" href="#513-requests"></a> 5.1.3. <code>Requests</code></h4><p><code>Requests</code> 是一个 Python 库，可以轻松发送 HTTP / 1.1 请求。</p><ul><li>可以使用 <code>GET</code> 方法修改查询结果。</li><li>可以用一个 Query 字符串从一个 URL 获取多个请求，如名称、ID 等。</li></ul><h4 id="514-爬虫"><a class="markdownIt-Anchor" href="#514-爬虫"></a> 5.1.4. 爬虫</h4><p>Python 中的网络抓取包括从网站中提取和解析数据，以便使用 <code>Beautiful Soup</code> 和 <code>requests</code> 等库为各种应用程序收集信息。</p><ul><li>HTML 包含由角括号（称为标签）括起来的蓝色文本元素所包围的文本。</li><li>Python 中的每个标签名称都是一个类，每个标签都是一个实例。</li><li>您可以选择网页上的 HTML 元素来查看网页。</li><li>网页可能还包含 CSS 和 JavaScript 以及 HTML 元素。</li><li>每个 HTML 文档就像一个 HTML 树，其中可能包含字符串和其他标记。</li><li>每个 HTML 表格都有表格标记，并定义了行、页眉、正文等。</li></ul></body></html>]]></content>
    
    
    <summary type="html">本文是 IBM 全栈开发课程的第七篇学习笔记，重点介绍了 Python 在数据科学领域的应用基础。笔记围绕两个核心库 Pandas 和 NumPy，讲解了如何使用 DataFrame 进行数据处理、如何利用多维数组进行高效的数值与矩阵运算。此外，文章还涵盖了数据收集技术，包括调用 REST API、使用 requests 库发送 HTTP 请求，以及通过 Beautiful Soup 进行网页抓取等。这篇笔记为使用 Python 进行数据分析和获取的初学者提供了清晰的入门路径。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Python" scheme="https://blog.cytrogen.icu/tags/Python/"/>
    
    <category term="IBM" scheme="https://blog.cytrogen.icu/tags/IBM/"/>
    
  </entry>
  
  <entry>
    <title>React + NestJS + Socket.io 项目实践【3】：消息发送</title>
    <link href="https://blog.cytrogen.icu/posts/b5ac.html"/>
    <id>https://blog.cytrogen.icu/posts/b5ac.html</id>
    <published>2024-05-14T07:41:50.000Z</published>
    <updated>2026-02-09T17:16:54.993Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期在期末考，所以更新会比较慢，这篇文章主要讲解如何实现消息发送功能。</p><span id="more"></span><h1 id="客户端的私聊界面"><a class="markdownIt-Anchor" href="#客户端的私聊界面"></a> 客户端的私聊界面</h1><p>之前的文章中我都没有去讲解客户端的代码。在讲解消息发送之前，我先介绍一下客户端的代码。</p><p>我的客户端中有一个 <code>PrivateMessageChatPage</code> 组件，用来显示和某个用户的私聊界面。这是最终的效果：</p><video id="video" controls="" height="420">    <source id="mp4" src="b5ac/Test.mp4" type="video/mp4"></video><p>而 <code>PrivateMessageChatPage</code> 的布局是这样的：</p><p><img src="/posts/b5ac/1.webp" alt="PrivateMessageChatPage" loading="lazy"></p><p>目前只有 <code>PrivateMessageMessagesWrapper</code> 和 <code>PrivateMessageTextBox</code> 组件是有内容的，其他的组件都是空的。不过这不影响我们的消息显示。</p><p>首先导入这些组件和一些类型：</p><pre><code class="language-tsx">import React, { useState } from 'react'import PrivateMessageTabBar from './Private_Message_Tab_Bar'import PrivateMessageMessagesWrapper from './Private_Message_Messages_Wrapper'import PrivateMessageProfilePanel from './Private_Message_Profile_Panel'import PrivateMessageTextBox from './Private_Message_Text_Box'import FriendsListSideBar from '../private_message_common/Friends_List_Sidebar'import { Message } from '../../types/interfaces'import { MessageContext } from '../context/Message_Context'</code></pre><p><code>Message</code> 类型：</p><pre><code class="language-typescript">export interface Message {  id?: string  senderId: string  receiverId: string  text: string  timestamp: string}</code></pre><p>每条消息都有一个 <code>senderId</code>、<code>receiverId</code>、<code>text</code> 和 <code>timestamp</code>。<code>id</code> 是消息的唯一标识符。</p><p>我们之后会根据 <code>senderId</code> 和 <code>receiverId</code> 来从服务端获取消息。</p><p><code>PrivateMessageChatPage</code> 组件：</p><pre><code class="language-tsx">const PrivateMessageChatPage = () =&gt; {  const [receiverName, setReceiverName] = useState&lt;string&gt;('Dummy')  const [newMessage, setNewMessage] = useState&lt;Message | null&gt;(null)  const addMessage = (message: Message) =&gt; {    setNewMessage(message)  }  return (    &lt;MessageContext.Provider value={{ newMessage, addMessage }}&gt;      &lt;FriendsListSideBar /&gt;      &lt;div className="d-flex flex-column mx-0 h-100 w-100"&gt;        &lt;div          className="d-flex flex-row"          style={{ height: '48px', padding: '8px', fontSize: '16px', borderBottom: 'solid 3px rgba(45, 47, 52)' }}&gt;          &lt;PrivateMessageTabBar receiverUsername={receiverName} setReceiverUsername={setReceiverName} /&gt;        &lt;/div&gt;        &lt;div className="d-flex flex-row flex-fill align-items-stretch p-0"&gt;          &lt;div            className="d-flex flex-column h-100 position-relative"            style={{ minWidth: 0, minHeight: 0, flex: '1 1 auto' }}&gt;            &lt;div className="position-relative" style={{ flex: '1 1 auto', minHeight: 0, minWidth: 0, zIndex: 0 }}&gt;              &lt;PrivateMessageMessagesWrapper receiverUsername={receiverName} /&gt;            &lt;/div&gt;            &lt;div className="position-sticky bottom-0 w-100" style={{ backgroundColor: 'rgba(49, 51, 56)' }}&gt;              &lt;PrivateMessageTextBox receiverUsername={receiverName} addMessage={addMessage} /&gt;            &lt;/div&gt;          &lt;/div&gt;          &lt;PrivateMessageProfilePanel /&gt;        &lt;/div&gt;      &lt;/div&gt;    &lt;/MessageContext.Provider&gt;  )}export default PrivateMessageChatPage</code></pre><p><code>MessageContext</code> 是一个 React 上下文，用来传递消息。</p><blockquote><p>React 的 Context API 是一种在组件之间共享数据的方法，而不必通过组件树的逐层传递 <code>props</code>。</p><p>通过创建一个 Context 对象，然后使用 <code>&lt;MyContext.Provider&gt;</code> 组件将值传递给后代组件，可以在组件树中传递数据。</p></blockquote><pre><code class="language-tsx">import React from 'react'import { Message } from '../../types/interfaces'interface MessageContextType {  newMessage: Message | null  addMessage: (message: Message) =&gt; void}export const MessageContext = React.createContext&lt;MessageContextType | undefined&gt;(undefined)</code></pre><p>在这个例子中，<code>MessageContext</code> 被用来在组件树中共享 <code>newMessage</code> 和 <code>addMessage</code>。</p><ul><li><code>newMessage</code> 是最新的消息。</li><li><code>addMessage</code> 是一个函数，用来添加消息。</li></ul><p>我们的 <code>PrivateMessageTextBox</code> 组件是用来发送消息的，当用户在输入框中输入新的消息并发送时，组件会调用 <code>addMessage</code> 方法，将新消息添加到 <code>MessageContext</code> 中。而 <code>PrivateMessageMessagesWrapper</code> 组件会监听 <code>newMessage</code> 的改变，一旦 <code>newMessage</code> 出现了变化，新消息就会被添加到该组件的状态中用于显示。</p><p>这意味着，用户只要发送了消息，消息就会立即显示在界面上。</p><p><code>PrivateMessageTextBox</code> 组件的 <code>handleSendMessage</code> 方法：</p><pre><code class="language-tsx">const PrivateMessageTextBox: React.FC&lt;PrivateMessageTextBoxProps&gt; = ({ receiverUsername }) =&gt; {  const [message, setMessage] = useState&lt;string&gt;('')  const context = useContext(MessageContext)  if (!context) {    throw new Error('MessageContext is undefined')  }  const {addMessage} = context  const handleChange = (e: ChangeEvent&lt;HTMLTextAreaElement&gt;) =&gt; {    setMessage(e.target.value)  }    const handleSendMessage = async (e?: FormEvent) =&gt; {    e &amp;&amp; e.preventDefault()    const jwtToken = localStorage.getItem('jwtToken')    const senderId = localStorage.getItem('userId')    if (!senderId) {      throw new Error('User ID not found in local storage')    }    const response = await UserService.getUserByUsername(jwtToken, receiverUsername)    const receiver = response.data    const privateMessage = {      id: `${socket.id}${Math.random()}`,      senderId: senderId,      receiverId: receiver._id,      text: message,      timestamp: new Date().toISOString(),    }    socket.emit('privateMessageSent', privateMessage)    addMessage(privateMessage)    setMessage('')  }}</code></pre><blockquote><p>这里的 <code>UserService.getUserByUsername</code> 方法进行了更改，需要多传入一个 <code>jwtToken</code> 参数。</p><pre><code class="language-typescript">export const UserService = {  getUserByUsername: (token: string | null, username: string) =&gt; {    return api.get(`/users/username/${username}`, { headers: { Authorization: `Bearer ${token}` } })  },  getUserByUserId: (token: string | null, userId: string) =&gt; {    return api.get(`/users/userid/${userId}`, { headers: { Authorization: `Bearer ${token}` } })  },}</code></pre><p>这是因为在上个文章中我实现了 <code>@Public</code> 装饰器，用来标记哪些路由是公开的。</p><p>根据用户的用户名或者 ID 来获取用户信息，都应当是私有的，所以需要传入 <code>jwtToken</code>。</p><blockquote><p>OAuth 2.0 授权框架规范中定义了 <code>Bearer</code> 令牌类型，它是一种用于 OAuth 2.0 的访问令牌，用于对资源进行身份验证。任何持有 <code>Bearer</code> 令牌的人都可以访问与该令牌相关联的资源。</p></blockquote></blockquote><p>向服务端发送 <code>privateMessageSent</code> 事件后，立即调用 <code>addMessage</code> 方法，将消息添加到 <code>MessageContext</code> 中。</p><h1 id="消息传递"><a class="markdownIt-Anchor" href="#消息传递"></a> 消息传递</h1><p>如果只是写了客户端的代码，那么消息只是在客户端显示，而不会真正的发送到服务端。要实现消息发送，我们需要在服务端中接收消息。</p><p>在 <a href="/posts/40b4.html">上个文章</a> 的最后一个分段中，我实现了 Socket 模块。</p><p>Socket 用白话来说就是一个通道，客户端和服务端可以通过这个通道进行双向通信。双向通信和传统的 HTTP 请求不同，HTTP 请求是单向的，客户端向服务端发送请求、服务端返回响应。而 Socket 是双向的，客户端和服务端可以随时向对方发送消息。</p><p>上个文章中 <code>SocketGateway</code>（网关）订阅了 <code>privateMessageSent</code> 事件，但我只是简单的打印了一下消息，并没有去更进一步的处理。</p><pre><code class="language-typescript">@SubscribeMessage('privateMessageSent')handlePrivateMessage(@MessageBody() data: any, client: Socket) {  console.log('Received private message:', data, 'from', client)}</code></pre><p>这次我要详细地讲解如何实现消息传递。首先消息传递在技术上的流程是这样的：</p><ol><li>客户端使用 Socket 向服务端发送 <code>privateMessageSent</code> 事件。</li><li>服务端在 <code>SocketGateway</code> 中接收到 <code>privateMessageSent</code> 事件后，依靠 <code>MessagesService</code> 将消息存储到数据库中。</li></ol><p>为什么要细分出两个模块呢？因为我认为这两个模块的职责不同，<code>Socket</code> 模块负责处理 Socket 相关的逻辑，<code>Messages</code> 模块则负责处理消息的存储与获取。</p><p>上个文章中并没有细写 <code>Messages</code> 模块，我现在来写一下：</p><pre><code class="language-typescript">import { Module } from '@nestjs/common'import { MongooseModule } from '@nestjs/mongoose'import { Message, MessageSchema } from './message.schema'import { MessagesService } from './messages.service'import { MessagesController } from './messages.controller'@Module({  imports: [MongooseModule.forFeature([{ name: Message.name, schema: MessageSchema }])],  providers: [MessagesService],  controllers: [MessagesController],  exports: [MessagesService],})export class MessagesModule {}</code></pre><blockquote><p><code>exports</code> 是用来导出 <code>MessagesService</code> 的，这样其他模块就可以使用 <code>MessagesService</code> 了。刚才也说过，<code>SocketGateway</code> 需要使用 <code>MessagesService</code> 来存储消息。</p></blockquote><p>我在这里做了一些修改，将 <code>MessagesSchema</code> 更改为了 <code>MessageSchema</code>。因为这个模型实际上是用来存储单一的消息，所以我认为它的名字应该是单数形式。同时，我将原先的 <code>sender</code> 和 <code>receiver</code> 更改为了 <code>senderId</code> 和 <code>receiverId</code>，因为我想通过用户的 ID 来查找用户，而不是直接使用用户对象。</p><pre><code class="language-typescript">import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'import { Document } from 'mongoose'@Schema()export class Message extends Document {  @Prop({ required: true })  senderId: string  @Prop({ required: true })  receiverId: string  @Prop({ required: true })  text: string  @Prop({ default: Date.now })  timestamp: Date}export const MessageSchema = SchemaFactory.createForClass(Message)</code></pre><blockquote><p>在这里，我添加了一个 <code>timestamp</code> 字段，用来记录每条消息的发送时间。</p></blockquote><div class="danger"><p>在客户端里，我将发送给服务端的消息数据结构设计为以下形式：</p><pre><code class="language-typescript">{  id: `${socket.id}${Math.random()}`,  senderId: senderId,  receiverId: receiver._id,  text: message,  timestamp: new Date().toISOString(),}</code></pre><p>这里，我也添加了一个 <code>timestamp</code> 字段。这是因为我希望客户端在发送消息后，能立即在界面上显示这条消息，而不需要等待服务端的响应。</p><p>值得注意的是，我选择让客户端直接显示消息，而没有等待服务端存储消息并返回。这样做的结果是，客户端显示的时间戳实际上是客户端发送消息的时间，而不是服务端存储消息的时间，除非用户刷新了页面，让客户端向服务端请求实际的数据。</p></div><p>接着我们要在 <code>MessagesService</code> 中添加一个方法，用来存储消息。</p><pre><code class="language-typescript">import { Injectable } from '@nestjs/common'import { InjectModel } from '@nestjs/mongoose'import { Model } from 'mongoose'import { Message } from './message.schema'import { CreateMessageDto } from './dto/create-message.dto'@Injectable()export class MessagesService {  constructor(@InjectModel(Message.name) private messageModel: Model&lt;Message&gt;) {}  async create(createMessageDto: CreateMessageDto): Promise&lt;Message&gt; {    const createdMessage = new this.messageModel(createMessageDto)    return await createdMessage      .save()      .then(async (message) =&gt; {        console.log('Message saved:', message)        return message      })      .catch((error: any) =&gt; {        console.log('Error saving message:', error)        throw error      })  }}</code></pre><blockquote><p><code>CreateMessageDto</code> 是一个数据传输对象，用来传输消息的数据。</p><pre><code class="language-typescript">export class CreateMessageDto {  readonly text: string  readonly senderId: string  readonly receiverId: string}</code></pre><p>在这个方法中，我只需要 <code>text</code>、<code>senderId</code> 和 <code>receiverId</code> 这三个字段。</p><p>接着使用 <code>save</code> 方法来保存消息，如果保存成功则返回消息，否则抛出错误。</p></blockquote><p>最后就是在 <code>SocketGateway</code> 中调用 <code>MessagesService</code> 的 <code>create</code> 方法：</p><pre><code class="language-typescript">import { MessagesService } from '../messages/messages.service'// ...export class SocketGateway implements OnGatewayInit {  constructor(    // ...    private messagesService: MessagesService,  ) {}  @SubscribeMessage('privateMessageSent')  async handlePrivateMessage(@MessageBody() data: any): Promise&lt;void&gt; {    await this.messagesService.create({ senderId: data.senderId, receiverId: data.receiverId, text: data.text })  }}</code></pre><p>别忘了 <code>SocketModule</code> 中要导入 <code>MessagesModule</code>，才能让 <code>SocketGateway</code> 使用 <code>MessagesService</code>。</p><pre><code class="language-typescript">import { Module } from '@nestjs/common'import { SocketService } from './socket.service'import { SocketGateway } from './socket.gateway'import { MessagesModule } from '../messages/messages.module'@Module({  imports: [MessagesModule],  providers: [SocketGateway, SocketService],})export class SocketModule {}</code></pre><p>这样服务端就可以接收到客户端发送的消息，并将消息存储到数据库中。</p><h1 id="消息显示"><a class="markdownIt-Anchor" href="#消息显示"></a> 消息显示</h1><p>用户点击他们和其他用户的私聊界面时，我们需要从服务端获取他们之间的所有消息。</p><p>在我的应用中，因为是仿照 Discord 的，所有的私聊路由都是 <code>/channel/@me/:id</code> 这种形式的。<code>id</code> 是接收者的 ID。</p><p>也就是说我们可以让服务端有一个 GET 路由，当客户端访问这个路由时，服务端会返回当前用户和 <code>id</code> 用户之间的所有消息。</p><p>在 <code>MessagesController</code> 中添加 GET 路由：</p><pre><code class="language-typescript">import { Controller, Get, Param, Request } from '@nestjs/common'import { Request as ExpressRequest } from 'express'import { MessagesService } from './messages.service'@Controller('messages')export class MessagesController {  constructor(private readonly messagesService: MessagesService) {}  @Get(':senderId/:receiverId')  async getMessages(    @Request() req: ExpressRequest,    @Param('senderId') senderId: string,    @Param('receiverId') receiverId: string,  ) {    return await this.messagesService.getMessages(senderId, receiverId)  }}</code></pre><p>当客户端访问 <code>/api/messages/:senderId/:receiverId</code> 时，服务端会返回当前用户（<code>senderId</code>）和 <code>receiverId</code> 用户之间的所有消息。</p><p><code>MessagesService</code> 中添加 <code>getMessages</code> 方法：</p><pre><code class="language-typescript">async getMessages(senderId: string, receiverId: string) {  return this.messageModel    .find({      senderId: senderId,      receiverId: receiverId,    })    .exec()    .then((messages) =&gt; {      console.log('Messages found:', messages)      return messages    })    .catch((error: any) =&gt; {      console.log('Error finding messages:', error)      throw error    })}</code></pre><p>客户端里也添加一个方法，专门访问 <code>/api/messages/:receiverId</code>：</p><pre><code class="language-typescript">export const MessageService = {  getMessagesByUserId: (token: string | null, senderId: string | null, receiverId: string) =&gt; {    return api.get(`/messages/${senderId}/${receiverId}`, { headers: { Authorization: `Bearer ${token}` } })  },}</code></pre><p>现在回到客户端的 <code>PrivateMessageMessagesWrapper</code> 组件。我们需要明白这个组件的职责是什么：</p><ol><li>当用户点击某个用户的私聊界面时，组件会向服务端请求 <code>senderId</code> 用户和 <code>receiverId</code> 用户之间的所有消息。</li><li>当用户发送消息时，组件会将新消息添加到消息列表中来立即显示。</li></ol><p>首先以最基础的形式来写这个组件：</p><pre><code class="language-tsx">const PrivateMessageMessagesWrapper: React.FC&lt;PrivateMessageMessagesWrapperProps&gt; = ({ receiverUsername }) =&gt; {  const [messages, setMessages] = useState&lt;Message[]&gt;([])  const currentUser = useSelector((state: { auth: { user: UserProfile } }) =&gt; state.auth.user)  return (    &lt;div      className="d-flex flex-column position-absolute top-0 bottom-0 overflow-y-scroll overflow-x-hidden"      style={{ left: 0, right: 0, overflowAnchor: 'none' }}&gt;      &lt;ol className="p-0 m-0" style={{ flex: 1, minHeight: '0', listStyle: 'none' }}&gt;        {messages.map((message, index) =&gt; (          &lt;li key={message.id || index} className="position-relative mx-2" style={{ outline: 'none' }}&gt;            &lt;div              className="position-relative"              style={{                marginTop: '1.0625rem',                minHeight: '2.75rem',                paddingTop: '0.125rem',                paddingBottom: '0.125rem',                paddingLeft: '72px',                paddingRight: '48px!important',                wordWrap: 'break-word',                userSelect: 'text',              }}&gt;              &lt;div className="position-static ms-0 ps-0" style={{ textIndent: 'none' }}&gt;                {/* User's avatar */}                &lt;img                  src={imgURL}                  className="position-absolute overflow-hidden"                  style={{                    pointerEvents: 'auto',                    textIndent: '-9999px',                    left: '16px',                    marginTop: 'calc(4px-0.125rem)',                    width: '40px',                    height: '40px',                    borderRadius: '50%',                    cursor: 'pointer',                    userSelect: 'none',                  }}                  alt=""                /&gt;                {/* Username and message time */}                &lt;h3                  className="overflow-hidden position-relative p-0 m-0 d-flex flex-row align-items-center"                  style={{                    display: 'block',                    lineHeight: '1.375rem',                    minHeight: '1.375rem',                    whiteSpace: 'break-spaces',                  }}&gt;                  &lt;span                    className="me-1 fs-6 position-relative overflow-hidden text-white"                    style={{                      fontWeight: '500',                      display: 'inline',                      verticalAlign: 'baseline',                      outline: 'none',                    }}&gt;                    {message.senderId === currentUser._id ? currentUser.username : receiverUsername}                  &lt;/span&gt;                  &lt;span                    className="ms-1"                    style={{                      fontSize: '0.75rem',                      height: '1.25rem',                      verticalAlign: 'baseline',                      display: 'inline-block',                      cursor: 'default',                      pointerEvents: 'none',                      outline: 'none',                      fontWeight: '500',                      color: 'rgba(148, 154, 158)',                    }}&gt;                    &lt;time dateTime={message.timestamp.toString()}&gt;{formatDate(message.timestamp)}&lt;/time&gt;                  &lt;/span&gt;                &lt;/h3&gt;              &lt;/div&gt;              {/* Message Content */}              &lt;div                className="overflow-hidden position-relative fs-6 p-0 m-0"                style={{                  userSelect: 'text',                  whiteSpace: 'break-spaces',                  wordWrap: 'break-word',                  marginLeft: 'calc(-1 * 72px)',                  paddingLeft: '72px',                  textIndent: '0',                  lineHeight: '1.375rem',                  color: 'rgba(219, 222, 225)',                }}&gt;                &lt;span&gt;{message.text}&lt;/span&gt;              &lt;/div&gt;            &lt;/div&gt;          &lt;/li&gt;        ))}      &lt;/ol&gt;    &lt;/div&gt;  )}</code></pre><ul><li><code>messages</code> 是该组件的状态，用来存储所有的需要被显示的消息。消息的数据结构是 <code>Message</code>，上面已经定义过了。</li><li><code>currentUser</code> 是从 Redux 中提取出的当前用户的信息，包括了用户的 ID 和用户名。</li></ul><p>这个组件的底层逻辑是这样的：</p><ol><li><code>map</code> 遍历 <code>messages</code> 数组，对每一条消息都生成一个 <code>li</code> 元素。</li><li>每一条消息都包含了用户的头像（这里写死了）、用户名（如果消息的 <code>senderId</code> 和当前用户的 ID 相同，那么消息的用户名就是当前用户的用户名，否则就是接收者的用户名）、消息发送时间和消息内容。</li></ol><blockquote><p>消息发送时间是通过 <code>formatDate</code> 函数格式化的：</p><pre><code class="language-typescript">export const formatDate = (timestamp: string) =&gt; {  const date = new Date(timestamp)  const year = date.getFullYear()  const month = String(date.getMonth() + 1).padStart(2, '0')  const day = String(date.getDate()).padStart(2, '0')  const hours = String(date.getHours()).padStart(2, '0')  const minutes = String(date.getMinutes()).padStart(2, '0')  return `${year}/${month}/${day} ${hours}:${minutes}`}</code></pre></blockquote><p>那么我们该如何获取消息、并将消息添加到 <code>messages</code> 中呢？</p><p>当 <code>PrivateMessageMessagesWrapper</code> 组件被挂载时，以及 <code>receiverUsername</code> 发生变化时，我们都需要向服务端请求消息：</p><pre><code class="language-tsx">useEffect(() =&gt; {  const fetchMessages = async () =&gt; {    const jwtToken = localStorage.getItem('jwtToken')    const senderId = localStorage.getItem('userId')    const response = await UserService.getUserByUsername(jwtToken, receiverUsername)    const receiver = response.data    try {      const res = await MessageService.getMessagesByUserId(jwtToken, senderId, receiver._id)      setMessages(res.data)      return res.data    } catch (err) {      console.error(err)    }  }  fetchMessages().then((r) =&gt; console.log('Messages fetched:', r))}, [receiverUsername])</code></pre><p>这里我使用了 <code>useEffect</code> 钩子，当 <code>receiverUsername</code> 发生变化时，就会调用 <code>fetchMessages</code> 方法。</p><p><code>fetchMessages</code> 方法会向服务端请求 <code>senderId</code> 用户和 <code>receiverId</code> 用户之间的所有消息，并将消息存储到 <code>messages</code> 中。</p><p>不只是如此，先前我们在 <code>PrivateMessageTextBox</code> 组件中发送消息时，会将用户自身发送的消息添加到 <code>MessageContext</code> 中。<code>PrivateMessageMessagesWrapper</code> 组件同样也需要去监听用户自身发送的消息，并将这些消息添加到 <code>messages</code> 中：</p><pre><code class="language-tsx">const context = useContext(MessageContext)if (!context) {  throw new Error('MessageContext is undefined')}const { newMessage } = contextuseEffect(() =&gt; {  if (newMessage) {    setMessages((prevMessages) =&gt; [...prevMessages, newMessage])  }}, [newMessage])</code></pre><h1 id="滚动到底部"><a class="markdownIt-Anchor" href="#滚动到底部"></a> 滚动到底部</h1><p>当该被显示的消息超过了可视区域时，用户需要手动滚动到底部才能看到最新的消息。这是不友好的，我们应当让用户看到最新的消息。</p><pre><code class="language-tsx">const endOfMessagesRef = useRef&lt;null | HTMLSpanElement&gt;(null)const prevMessagesLength = useRef&lt;number&gt;(0)useEffect(() =&gt; {  if (endOfMessagesRef.current &amp;&amp; messages.length &gt; prevMessagesLength.current) {    endOfMessagesRef.current.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'start' })  }  prevMessagesLength.current = messages.length}, [messages])return (  &lt;div&gt;    &lt;ol&gt;      {messages.map((message, index) =&gt; (        // ...      ))}      &lt;span ref={endOfMessagesRef} /&gt;    &lt;/ol&gt;  &lt;/div&gt;)</code></pre><p>我使用了 <code>useRef</code> 来创建一个 <code>endOfMessagesRef</code> 引用，用来指向消息列表的最底部。当 <code>messages</code> 数组的长度发生变化时，我就将 <code>endOfMessagesRef</code> 滚动到可视区域。</p><p><code>prevMessagesLength</code> 也是一个 <code>useRef</code>，用来存储上一次 <code>messages</code> 的长度。这个长度在回调函数的最后会被更新为当前的 <code>messages</code> 的长度。</p><p><code>useEffect</code> 的回调函数会先检查 <code>endOfMessagesRef.current</code> 是否存在，以及 <code>messages</code> 的长度是否大于 <code>prevMessagesLength.current</code>。如果两个条件都满足，就将 <code>endOfMessagesRef.current</code> 滚动到可视区域。</p><blockquote><p><code>scrollIntoView</code> 方法是一个 DOM 方法，用来将元素滚动到可视区域。</p><ul><li><code>behavior</code> 决定了滚动的动画效果，<code>smooth</code> 表示平滑滚动。</li><li><code>block</code> 决定了元素在垂直方向上的对齐方式，<code>nearest</code> 表示将元素对齐到最接近的边缘。</li><li><code>inline</code> 决定了元素在水平方向上的对齐方式，<code>start</code> 表示将元素对齐到起始边缘。</li></ul></blockquote><p><code>span</code> 标签是一个空元素，用来占位，需要放在 <code>ol</code> 标签的最后一个子元素后面。</p><h1 id="浏览器刷新后状态丢失"><a class="markdownIt-Anchor" href="#浏览器刷新后状态丢失"></a> 浏览器刷新后状态丢失</h1><p>在用户刷新浏览器后，Redux 的状态会丢失。这是因为 Redux 的状态是存储在内存中的，刷新浏览器后内存被清空，状态也就丢失了。</p><p>由于我们已经在 <code>localStorage</code> 中存储了用户的 <code>jwtToken</code> 和 <code>userId</code>，我们可以从 <code>localStorage</code> 中获取这些信息，并重新设置 Redux 的状态。</p><pre><code class="language-tsx">import { useAppDispatch } from './redux/store'import { setUserDetails } from './redux/actions/authActions'function App() {  const dispatch = useAppDispatch()  useEffect(() =&gt; {    const token = localStorage.getItem('jwtToken')    const userId = localStorage.getItem('userId')    if (token &amp;&amp; userId) {      dispatch(setUserDetails(userId))    }  }, [dispatch])}</code></pre><p><code>setUserDetails</code> 是一个 Redux 的 action，用来设置用户的 ID。</p><pre><code class="language-typescript">export const setUserDetails = (userId: string) =&gt; {  return async (dispatch: Dispatch) =&gt; {    try {      const token = localStorage.getItem('jwtToken')      const response = await UserService.getUserByUserId(token, userId)      if (response.status === 200) {        dispatch(setCurrentUser(response.data))      } else {        console.log(response.data.message)      }    } catch (error) {      console.error(error)    }  }}</code></pre><p>此处使用了 <code>localStorage</code> 中的 <code>userId</code> 来向服务端请求了用户的信息，并将用户信息存储到 Redux 的状态中。</p><h1 id="令牌过期"><a class="markdownIt-Anchor" href="#令牌过期"></a> 令牌过期</h1><p>服务端向客户端返回的 <code>jwtToken</code> 是有过期时间的。当 <code>jwtToken</code> 过期后，客户端再向服务端发送请求时，服务端会返回 <code>401 Unauthorized</code> 错误。</p><p>在这种情况下，我们应当让用户重新登录。我在 <code>axios</code> 的拦截器中添加了一个拦截器，用来处理 <code>401</code> 错误。</p><pre><code class="language-typescript">api.interceptors.response.use(  (response) =&gt; {    return response  },  (error) =&gt; {    if (error.response) {      if (error.response.status === 401 &amp;&amp; error.response.statusText === 'Unauthorized') {        localStorage.removeItem('jwtToken')        window.location.reload()      }    }    return Promise.reject(error)  },)</code></pre><p><code>window.location.reload()</code> 会重新加载页面，没有 <code>jwtToken</code> 的情况下，用户会因为路由守卫而被重定向到登录页面。</p><h1 id="其他的小改动"><a class="markdownIt-Anchor" href="#其他的小改动"></a> 其他的小改动</h1><h2 id="user接口"><a class="markdownIt-Anchor" href="#user接口"></a> <code>User</code> 接口</h2><p><code>User</code> 接口的 <code>id</code> 字段改为 <code>_id</code>：</p><pre><code class="language-typescript">export interface User {  _id?: string  emailAddress?: string  username: string  password?: string  access_token?: string}</code></pre><p>这是因为在 MongoDB 中，每个文档都有一个 <code>_id</code> 字段，用来唯一标识文档。为了可以直接将 MongoDB 中的文档映射到 <code>User</code> 接口，我将 <code>id</code> 改为了 <code>_id</code>。</p><h2 id="自定义滚动条"><a class="markdownIt-Anchor" href="#自定义滚动条"></a> 自定义滚动条</h2><p>我使用的是 Edge 浏览器，它的滚动条不能说难看，只能说和好看不搭边。所以我在 <code>index.css</code> 中自定义了滚动条的样式：</p><pre><code class="language-css">::-webkit-scrollbar {  width: 16px;  height: 16px;}::-webkit-scrollbar-track {  background: hsl( 220 calc( 1 * 6.5%) 18% / 1);  margin-bottom: 8px;  border: 4px solid transparent;  background-clip: padding-box;  border-radius: 8px;}::-webkit-scrollbar-thumb {  background: hsl( 225 calc( 1 * 7.1%) 11% / 1);  background-clip: padding-box;  border: 4px solid transparent;  border-radius: 8px;  min-height: 40px;}::-webkit-scrollbar-corner {  background: transparent;}</code></pre><p>这些样式是根据 Discord 的滚动条样式来写的。</p></body></html>]]></content>
    
    
    <summary type="html">本文是 React + NestJS + Socket.io 全栈项目实践的第三篇，核心是实现用户间的私聊消息发送与实时显示。后端部分，教程讲解了如何通过 SocketGateway 接收消息并调用服务将其持久化到 MongoDB。前端部分，则演示了如何构建私聊界面，通过 Socket.io emit 发送消息，并利用 React Context 实现消息的即时渲染。此外，文章还解决了多个常见开发问题：聊天窗口的自动滚动、浏览器刷新后登录状态的恢复，以及通过 Axios 拦截器处理过期的 JWT Token，从而构建出一个体验完善的实时聊天核心功能。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="全栈实践" scheme="https://blog.cytrogen.icu/tags/%E5%85%A8%E6%A0%88%E5%AE%9E%E8%B7%B5/"/>
    
    <category term="Node.js" scheme="https://blog.cytrogen.icu/tags/Node-js/"/>
    
    <category term="React.js" scheme="https://blog.cytrogen.icu/tags/React-js/"/>
    
    <category term="TypeScript" scheme="https://blog.cytrogen.icu/tags/TypeScript/"/>
    
    <category term="NestJS" scheme="https://blog.cytrogen.icu/tags/NestJS/"/>
    
  </entry>
  
  <entry>
    <title>React + NestJS + Socket.io 项目实践【2】：JWT 验证</title>
    <link href="https://blog.cytrogen.icu/posts/40b4.html"/>
    <id>https://blog.cytrogen.icu/posts/40b4.html</id>
    <published>2024-04-28T04:25:50.000Z</published>
    <updated>2026-02-09T17:16:54.993Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>上篇文章我们迁移了整个项目到 NestJS，这篇文章我们将实现 JWT 验证。</p><span id="more"></span><h2 id="一些改动"><a class="markdownIt-Anchor" href="#一些改动"></a> 一些改动</h2><p>为了项目的可维护性，我对项目的目录结构进行了一些调整。</p><p>首先是把所有注册登录相关的代码都从 <code>users</code> 文件夹放到 <code>auth</code> 文件夹中，只给 <code>users</code> 文件夹留下用户信息的相关代码。</p><p><code>UsersModule</code>：</p><pre><code class="language-typescript">import { Module } from '@nestjs/common'import { MongooseModule } from '@nestjs/mongoose'import { User, UserSchema } from './user.schema'import { UsersController } from './users.controller'import { UsersService } from './users.service'@Module({  imports: [    MongooseModule.forFeature([      {        name: User.name,        schema: UserSchema,      },    ]),  ],  controllers: [UsersController],  providers: [UsersService],})export class UsersModule {}</code></pre><p><code>UsersService</code> 添加了更多用来查询用户的方法：</p><pre><code class="language-typescript">import { Injectable } from '@nestjs/common'import { InjectModel } from '@nestjs/mongoose'import { Model } from 'mongoose'import { User } from './user.schema'@Injectable()export class UsersService {  constructor(    @InjectModel(User.name)    private usersModel: Model&lt;User&gt;,  ) {}  async findByEmail(emailAddress: string): Promise&lt;User | null&gt; {    return this.usersModel.findOne({ emailAddress }).exec()  }    async findByUsername(username: string): Promise&lt;User | null&gt; {    return this.usersModel.findOne({ username }).exec()  }    async findAll(): Promise&lt;User[]&gt; {    return this.usersModel.find().exec()  }}</code></pre><p><code>UsersController</code> 新添了一个 <code>GET</code> 路由，用于根据用户名查询用户信息，后续会用到：</p><pre><code class="language-typescript">import { Controller, Get, Param } from '@nestjs/common'import { UsersService } from './users.service'import { Public } from '../common/decorator/public.decorator'@Controller('users')export class UsersController {  constructor(private readonly usersService: UsersService) {}  @Public()  @Get(':username')  async findOne(@Param('username') username: string) {    return this.usersService.findByUsername(username)  }}</code></pre><blockquote><p>假设要查询的用户的用户名是 <code>dummy</code>，那么请求的 URL 就是 <code>/api/users/dummy</code>。</p></blockquote><p>客户端的文件改动则是将大部分文件从 <code>components</code> 目录中拿了出来，例如 Redux 相关的文件被统一放到了 <code>redux</code> 目录、和 <code>components</code> 同级。</p><p>同时我还删除了上一篇文章中写的 <code>Guard</code> 组件，因为在这篇文章中我们会要写 <a href="#%E5%AE%A2%E6%88%B7%E7%AB%AF%E5%88%A4%E6%96%AD%E7%94%A8%E6%88%B7%E6%98%AF%E5%90%A6%E7%99%BB%E5%BD%95">功能更为复杂的升级版路由守卫</a>。</p><h2 id="jwt生成"><a class="markdownIt-Anchor" href="#jwt生成"></a> JWT 生成</h2><p>JWT 是一种用于在网络上传输信息的简洁方法。对比 Session 和 Cookie，JWT 的优势在于不需要在服务端存储用户信息，而是通过加密的方式将用户信息存储在 Token 中，然后在客户端存储这个 Token。</p><p>有关 JWT 的更多信息，可以自行查阅资料。</p><p>JWT 验证的实现很大程度上参照了稀土掘金上的一篇文章：<a href="https://juejin.cn/post/7236593818594312229">NestJS 登录功能：基于 JWT 的身份验证</a>。</p><p><code>.env</code> 文件中配置：</p><pre><code class="language-plaintext">JWT_SECRET=secretJWT_TOKEN_AUDIENCE=localhost:4000JWT_TOKEN_ISSUER=localhost:4000JWT_ACCESS_TOKEN_TTL=3600</code></pre><p><code>AppModule</code> 中配置 <code>ConfigModule</code>，这里需要用到 <code>Joi</code> 包（用于验证环境变量）：</p><pre><code class="language-typescript">import { ConfigModule } from '@nestjs/config'import * as Joi from 'joi'@Module({  imports: [    ConfigModule.forRoot({      validationSchema: Joi.object({        JWT_SECRET: Joi.string().required(),        JWT_TOKEN_AUDIENCE: Joi.string().required(),        JWT_TOKEN_ISSUER: Joi.string().required(),        JWT_ACCESS_TOKEN_TTL: Joi.number().default(3600),      }),    }),  ],  // ...})</code></pre><blockquote><p>使用 <code>Joi</code> 包的目的是为了验证环境变量是否存在，以及是否符合预期的类型。</p><p>假设环境变量 <code>JWT_SECRET</code> 不存在，那么 <code>Joi</code> 会抛出一个错误，阻止应用程序启动。</p></blockquote><p>新建一个 <code>jwt.config.ts</code> 文件，用于配置 <code>JwtModule</code>：</p><pre><code class="language-typescript">import { registerAs } from '@nestjs/config'export default registerAs('jwt', () =&gt; {  return {    secret: process.env.JWT_SECRET,    audience: process.env.JWT_TOKEN_AUDIENCE,    issuer: process.env.JWT_TOKEN_ISSUER,    accessTokenTtl: parseInt(process.env.JWT_ACCESS_TOKEN_TTL ?? '3600', 10),  }})</code></pre><p>接着在 <code>AuthModule</code> 引入这个配置：</p><pre><code class="language-typescript">import { JwtModule } from '@nestjs/jwt'import jwtConfig from '../common/config/jwt.config'@Module({  imports: [    ConfigModule.forFeature(jwtConfig),    JwtModule.registerAsync(jwtConfig.asProvider()),  ],  // ...})</code></pre><p>回到我们用户登陆的逻辑。当服务端验证用户信息后，我们需要生成一个 Token，然后返回给客户端。</p><p>新建一个 <code>active-user-data.interface.ts</code> 文件，用于定义 Token 中的负载：</p><pre><code class="language-typescript">export interface ActiveUserData {  sub: number  name: string}</code></pre><p>在 JWT 中，<code>sub</code>（主题，通常是 ID）和 <code>name</code> 是常见的有效载荷字段，定义这些字段有助于应用进行身份验证和授权、帮助服务器识别发送请求的用户。</p><p><code>AuthService</code> 中添加两个方法，用于生成 Token 和验证 Token：</p><pre><code class="language-typescript">// ...import { JwtService } from '@nestjs/jwt'import { ConfigType } from '@nestjs/config'import { User } from '../users/user.schema'import jwtConfig from '../common/config/jwt.config'import { ActiveUserData } from './interfaces/active-user-data.interface'@Injectable()export class AuthService {  constructor(    private readonly jwtService: JwtService,    @Inject(jwtConfig.KEY)    private readonly jwtConfiguration: ConfigType&lt;typeof jwtConfig&gt;,  ) {}  async generateTokens(user: User) {    return await this.signToken&lt;Partial&lt;ActiveUserData&gt;&gt;(user._id, {name: user.username})  }  private async signToken&lt;T&gt;(userId: number, payload?: T) {    return await this.jwtService.signAsync(      {        sub: userId,        ...payload,      },      {        secret: this.jwtConfiguration.secret,        audience: this.jwtConfiguration.audience,        issuer: this.jwtConfiguration.issuer,        expiresIn: this.jwtConfiguration.accessTokenTtl,      },    )  }    // ...}</code></pre><blockquote><p><code>signToken</code> 方法接收一个用户 ID 和一个负载对象，然后使用 <code>JwtService</code> 的 <code>signAsync</code> 方法生成一个 Token。这里使用的 <code>jwtConfig</code> 是我们之前配置的 JWT 配置。</p><p><code>generateTokens</code> 方法接收一个用户对象，然后调用 <code>signToken</code> 方法生成一个 Token。</p></blockquote><p>在 <code>login</code> 方法中调用 <code>generateTokens</code> 方法：</p><pre><code class="language-typescript">async login(loginUserDto: LoginUserDto) {  const user = await this.usersModel.findOne({      username: loginUserDto.username,  })  if (!user) throw new UnauthorizedException('The username is invalid')  const passwordValid = await bcrypt.compare(loginUserDto.password, user.password)  if (!passwordValid) throw new UnauthorizedException('The password is invalid')  // 返回Token  return await this.generateTokens(user)}</code></pre><p><code>AuthController</code> 也需要做一些改动：</p><pre><code class="language-typescript">@Post('login')async login(@Body() loginUserDto: LoginUserDto, @Res() res: Response) {  try {    const resultToken = await this.authService.login(loginUserDto)    res.status(HttpStatus.OK).json({      status: '00000',      message: 'User logged in successfully',      token: resultToken,  // &lt;-- 向客户端返回Token    })  } catch (error) {    console.error(error)    if (error instanceof UnauthorizedException) {      res.status(HttpStatus.UNAUTHORIZED).json({        status: 'U0202',        message: 'The username or password is invalid',      })    } else {      res.status(HttpStatus.BAD_REQUEST).json({        status: 'U0200',        message: 'Failed to log in user due to an unknown error',      })    }  }}</code></pre><p>客户端接收到 Token 后，可以将 Token 存储在 <code>localStorage</code> 中，以便后续请求时使用：</p><pre><code class="language-typescript">const loginUser = (userData: User, navigate: (path: string) =&gt; void) =&gt; {  return async (dispatch: Dispatch) =&gt; {    try {      const response = await UsersService.login(userData);      const data = response.data;      if (data.status === "00000") {        localStorage.setItem("jwtToken", data.token);        dispatch(setCurrentUser({          ...userData,          access_token: data.token,        }));          console.log(data);          navigate("/");      } else console.log(data.message);    } catch (error) {      console.error(error);    }  }}</code></pre><h2 id="jwt验证"><a class="markdownIt-Anchor" href="#jwt验证"></a> JWT 验证</h2><p>生成 Token 后，我们需要在每次请求时验证 Token。</p><p>服务端新建一个 <code>access-token.guard.ts</code> 文件：</p><pre><code class="language-typescript">import { CanActivate, ExecutionContext, Inject, Injectable, UnauthorizedException } from '@nestjs/common'import { ConfigType } from '@nestjs/config'import { JwtService } from '@nestjs/jwt'import { Reflector } from '@nestjs/core'import { Request } from 'express'import { REQUEST_USER_KEY } from '../../common'import jwtConfig from '../../common/config/jwt.config'import { IS_PUBLIC_KEY } from '../../common/decorator/public.decorator'@Injectable()export class AccessTokenGuard implements CanActivate {  constructor(    private readonly reflector: Reflector,    private readonly jwtService: JwtService,    @Inject(jwtConfig.KEY)    private readonly jwtConfiguration: ConfigType&lt;typeof jwtConfig&gt;,  ) {}  async canActivate(context: ExecutionContext): Promise&lt;boolean&gt; {    const isPublic = this.reflector.get(IS_PUBLIC_KEY, context.getHandler())    if (isPublic) return true      const request = context.switchToHttp().getRequest()    const token = this.extractTokenFromHeader(request)    if (!token) throw new UnauthorizedException()    try {      request[REQUEST_USER_KEY] = await this.jwtService.verifyAsync(token, this.jwtConfiguration)    } catch (error) {      throw new UnauthorizedException()    }    return true  }    private extractTokenFromHeader(request: Request): string | undefined {    const authorization = request.headers['authorization']    const [, token] = authorization?.split(' ') ?? []    return token  }}</code></pre><blockquote><p><code>AccessTokenGuard</code> 类实现了 <code>CanActivate</code> 接口，该接口用于验证请求是否可以通过。</p><p><code>extractTokenFromHeader</code> 方法用于从请求头中提取 Token。</p></blockquote><p>上述代码中导入的两个新文件分别是 <code>common/index.ts</code> 和 <code>common/decorator/public.decorator.ts</code>：</p><pre><code class="language-typescript">export const REQUEST_USER_KEY = 'user'</code></pre><p>这个常量在 <code>request</code> 对象中用作键、用于存储已验证的 JWT 的解码信息。具体来说，当一个请求到达并通过 <code>canActivate</code> 方法时，会从请求的 <code>Authorization</code> 头中提取 JWT。如果 JWT 存在且有效（也就是能够被 <code>JwtService</code> 和 <code>verifyAsync</code> 方法验证），那么 JWT 的解码信息就会被存储在 <code>request[REQUEST_USER_KEY]</code> 中。</p><p>这样做的目的是为了在后续的请求处理中，可以直接通过 <code>request[REQUEST_USER_KEY]</code> 来获取 JWT 的解码信息，无需再次验证。</p><pre><code class="language-typescript">import { SetMetadata } from '@nestjs/common'export const IS_PUBLIC_KEY = 'isPublic'export const Public = () =&gt; SetMetadata(IS_PUBLIC_KEY, true)</code></pre><p>首先我们要清楚一个概念。在我们启用了 JWT 验证的情况下，会导致所有的请求都需要携带 JWT Token。但是有些请求我们并不想要求用户携带 Token，比如说注册和登录请求（因为用户还没有 Token）。这时我们就需要一个装饰器来标记这些请求是公开的。</p><p><code>Public</code> 装饰器标记了一个请求是公开的，这样在 <code>AccessTokenGuard</code> 中就可以根据这个标记来判断是否需要验证 Token。</p><p>有了 <code>Public</code> 装饰器后我们就可以在 <code>AuthController</code> 中标记 <code>register</code> 和 <code>login</code> 路由是公开的：</p><pre><code class="language-typescript">import { Public } from '../common/decorator/public.decorator'// ...@Public()@Post('register')@Public()@Post('login')</code></pre><p>NestJS 的项目每当新建一个东西时，都需要在 <code>app.module.ts</code> 中引入。这里我们导入 <code>AccessTokenGuard</code>：</p><pre><code class="language-typescript">import { APP_GUARD } from '@nestjs/core'import { AccessTokenGuard } from './guards/access-token.guard'@Module({  // ...  providers: [    {      provide: APP_GUARD,      useClass: AccessTokenGuard,    },    // ...  ],})export class AppModule {}</code></pre><blockquote><p><code>APP_GUARD</code> 用于告诉 NestJS 我们要使用 <code>AccessTokenGuard</code> 这个守卫。</p></blockquote><p>有了这个守卫后，每次请求都会被验证 Token。如果请求中没有 Token 或者 Token 无效，那么请求就会被拒绝。</p><h2 id="客户端判断用户是否登录"><a class="markdownIt-Anchor" href="#客户端判断用户是否登录"></a> 客户端判断用户是否登录</h2><p>未登录的用户是不能访问某些页面的，同理，已登录的用户也不能访问登录和注册页面。</p><p>我们先自定义一个 Hook 来检查用户是否已经进行了身份验证。新建一个 <code>useAuth</code> 文件：</p><pre><code class="language-typescript">import { useEffect, useState } from 'react'export const useAuth = () =&gt; {  const [isAuthenticated, setIsAuthenticated] = useState(false);  const [isAuthChecked, setIsAuthChecked] = useState(false);  useEffect(() =&gt; {    const token = localStorage.getItem("jwtToken");    if (token) {      setIsAuthenticated(true);    } else {      setIsAuthenticated(false);    }    setIsAuthChecked(true);  }, []);  return { isAuthenticated, isAuthChecked };}</code></pre><p>这个 Hook 会检查 <code>localStorage</code> 中是否存在 <code>jwtToken</code>，如果存在则认为用户已经登录、设置 <code>isAuthenticated</code> 为 <code>true</code>，否则设置为 <code>false</code>。</p><p>为了不重复进行这个检查，我们还设置了一个 <code>isAuthChecked</code> 状态，用于标记用户是否已经进行了身份验证。</p><p>在我们当前的项目中，身份验证无非有两种必需导向用户到不同页面的情况：</p><ol><li>用户未登录，但是访问了首页，这时我们需要将用户导向登录页面。</li><li>用户已经登录，但是访问了登录或注册页面，这时我们需要将用户导向首页。</li></ol><p>我们先解决第一个问题。新建一个 <code>ProtectedRoute</code> 组件（意味着只有登录用户才能访问的路由）：</p><pre><code class="language-tsx">export const ProtectedRoute: React.FC&lt;RouteProps&gt; = ({ children }) =&gt; {  const { isAuthenticated, isAuthChecked } = useAuth()  const navigate = useNavigate()  useEffect(() =&gt; {    if (!isAuthenticated &amp;&amp; isAuthChecked) {      if (window.location.pathname === '/channels/@me') {        navigate('/login', { replace: true })      }    }  }, [isAuthenticated, isAuthChecked, navigate])  if (!isAuthChecked) return null  return &lt;&gt;{isAuthenticated ? children : &lt;Navigate to="/login" replace /&gt;}&lt;/&gt;}</code></pre><p>在 <code>App.tsx</code> 中使用这个组件：</p><pre><code class="language-tsx">function App() {  return (    &lt;BrowserRouter&gt;      &lt;Routes&gt;        &lt;Route path="/" element={ &lt;Navigate to="/channels/@me" replace /&gt; } /&gt;        &lt;Route path="/channels/@me/*" element={ &lt;ProtectedRoute&gt;&lt;Home /&gt;&lt;/ProtectedRoute&gt; } /&gt;  {/* &lt;--- 这里 */}        {/* ... */}      &lt;/Routes&gt;    &lt;/BrowserRouter&gt;  );}</code></pre><p>当用户尝试访问 <code>/channels/@me</code> 页面或其子页面时，如果用户未登录，那么就会被导向登录页面。</p><p>第二个问题同理，只要写一个逻辑相反的 <code>UnauthenticatedRoute</code> 组件即可：</p><pre><code class="language-tsx">export const UnauthenticatedRoute: React.FC&lt;RouteProps&gt; = ({ children }) =&gt; {  const { isAuthenticated, isAuthChecked } = useAuth()  const navigate = useNavigate()  useEffect(() =&gt; {    if (isAuthenticated &amp;&amp; isAuthChecked) {      navigate('/channels/@me', { replace: true })    }  }, [isAuthenticated, isAuthChecked, navigate])  if (!isAuthChecked) return null  return &lt;&gt;{!isAuthenticated ? children : &lt;Navigate to="/channels/@me" replace /&gt;}&lt;/&gt;}</code></pre><p>使用方法也是一样的：</p><pre><code class="language-tsx">function App() {  return (    &lt;BrowserRouter&gt;      &lt;Routes&gt;        // ...        &lt;Route path="/login" element={ &lt;UnauthenticatedRoute&gt;&lt;Login /&gt;&lt;/UnauthenticatedRoute&gt; } /&gt;        &lt;Route path="/register" element={ &lt;UnauthenticatedRoute&gt;&lt;Register /&gt;&lt;/UnauthenticatedRoute&gt; } /&gt;      &lt;/Routes&gt;    &lt;/BrowserRouter&gt;  );}</code></pre><h2 id="eslint和prettier配置"><a class="markdownIt-Anchor" href="#eslint和prettier配置"></a> ESLint 和 Prettier 配置</h2><p>我开发这个项目一直用的是 WebStorm。最近换设备后，一进入客户端的目录后都会弹出错误，说是 ESLint 配置冲突，就决定重新为两个目录配置 ESLint 和 Prettier。</p><p>服务端因为新建项目时就自带了 <code>.eslintrc.js</code> 和 <code>.prettierrc</code> 文件，所以只需要在客户端新建这两个文件即可。</p><p>客户端下安装必要的包：</p><pre><code class="language-bash">npm install --save-dev eslint-plugin-prettier eslint-config-prettier</code></pre><p>新建 <code>.eslintrc.js</code> 文件：</p><pre><code class="language-javascript">module.exports = {  parser: '@typescript-eslint/parser',  parserOptions: {    project: 'tsconfig.json',  // &lt;--- 这个文件是WebStorm新建项目时自动生成的    tsconfigRootDir: __dirname,    sourceType: 'module',  },  plugins: ['@typescript-eslint/eslint-plugin', 'react'],  extends: [    'plugin:@typescript-eslint/recommended',    'plugin:react/recommended',    'plugin:prettier/recommended',  ],  root: true,  env: {    browser: true,    jest: true,    es6: true,  },  rules: {    '@typescript-eslint/interface-name-prefix': 'off',    '@typescript-eslint/explicit-function-return-type': 'off',    '@typescript-eslint/explicit-module-boundary-types': 'off',    '@typescript-eslint/no-explicit-any': 'off',    'react/prop-types': 'off',  },};</code></pre><p><code>.prettierrc</code> 文件我直接搬的服务端的配置，如下：</p><pre><code class="language-json">{  "singleQuote": true,  "trailingComma": "all",  "endOfLine": "lf",  "arrowParens": "always",  "bracketSameLine": true,  "bracketSpacing": true,  "embeddedLanguageFormatting": "auto",  "htmlWhitespaceSensitivity": "css",  "insertPragma": false,  "jsxSingleQuote": false,  "printWidth": 120,  "proseWrap": "never",  "quoteProps": "as-needed",  "requirePragma": false,  "semi": false,  "tabWidth": 2,  "useTabs": false,  "vueIndentScriptAndStyle": false,  "singleAttributePerLine": false}</code></pre><p>重启 WebStorm 后，错误提示消失，一切正常。</p><h2 id="其他"><a class="markdownIt-Anchor" href="#其他"></a> 其他</h2><p>我长期没有更新的原因非常简单，我于三月底的时候遇到了一个不知道是什么 BUG 的 BUG。无论怎么修改代码，客户端都无法连接到服务端，而服务端也没有报告详细的错误信息。那时候直接摆烂了，也没有再继续开发。</p><p>最近重新看了一下代码，发现问题竟然是服务端的 <code>logger.middleware.ts</code> 的一个参数被我手贱抹去！</p><pre><code class="language-typescript">import { Injectable, NestMiddleware } from '@nestjs/common'import { Request, Response, NextFunction } from 'express'@Injectable()export class LoggerMiddleware implements NestMiddleware {  use(req: Request, res: Response, next: NextFunction) {  // &lt;--- res参数被我删掉了    console.log('Request...', req.method, req.originalUrl)    next()  }}</code></pre><p>那么为什么这个异常没有被服务端捕获呢？因为我的全局异常过滤器也没有写好！</p><p>这是原先的全局异常过滤器：</p><pre><code class="language-typescript">import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common'@Catch()export class AnyExceptionFilter implements ExceptionFilter {  catch(exception: any, host: ArgumentsHost) {    const ctx = host.switchToHttp()    const response = ctx.getResponse()    const request = ctx.getRequest()    const status = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR    const message = exception instanceof HttpException ? exception.getResponse() : 'Internal server error'    response.status(status).json({      statusCode: status,      timestamp: new Date().toISOString(),      path: request.url,      message: message,    })  }}</code></pre><p>能发现问题没有？<code>status</code> 和 <code>message</code> 都被我写死了！如果异常不是 <code>HttpException</code>，那么这两个值就都只会是 <code>500</code> 和 <code>Internal server error</code>。</p><p>这是我修改后的全局异常过滤器：</p><pre><code class="language-typescript">import { ExceptionFilter, Catch, ArgumentsHost, HttpException, HttpStatus } from '@nestjs/common'import { Request, Response } from 'express'@Catch()export class AnyExceptionFilter implements ExceptionFilter {  catch(exception: any, host: ArgumentsHost) {    const ctx = host.switchToHttp()    const response = ctx.getResponse&lt;Response&gt;()    const request = ctx.getRequest&lt;Request&gt;()    const status = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR    const message = exception instanceof HttpException ? exception.getResponse() : exception    console.error(exception)    response.status(status).json({      statusCode: status,      timestamp: new Date().toISOString(),      path: request.url,      message: message,    })  }}</code></pre><p>现在，无论异常是什么，都会被正确地捕获并返回给客户端。</p><p>希望大家以我为戒，不要犯我这样的错误。</p><h4 id="新添加但没有完成的东西"><a class="markdownIt-Anchor" href="#新添加但没有完成的东西"></a> 新添加但没有完成的东西</h4><p>服务端新增了 Socket 模块，毕竟完成了注册登录、JWT 生成验证等功能后，下一个就是老生常态的消息接收发送。既然我们使用的是 Socket.IO，那就要新建一个 Socket 模块。</p><p><code>SocketModule</code>：</p><pre><code class="language-typescript">import { Module } from '@nestjs/common';import { SocketService } from './socket.service';import { SocketGateway } from './socket.gateway';@Module({  providers: [SocketGateway, SocketService],})export class SocketModule {}</code></pre><p><code>SocketService</code>：</p><pre><code class="language-typescript">import { Injectable } from '@nestjs/common'import { Server } from 'socket.io'@Injectable()export class SocketService {  private server: Server  initialize(server: Server) {    this.server = server  }  sendMessage(event: string, message: any) {    this.server.emit(event, message)  }}</code></pre><blockquote><p><code>initialize</code> 方法用于初始化 Socket 服务器。</p><p><code>sendMessage</code> 方法用于向所有连接的客户端发送消息。</p></blockquote><p>这里讲一下 Controller 和 Gateway 的区别。</p><p>在传统的 HTTP 请求 / 响应模型中，Controller 负责处理来自客户端的请求并返回响应。然而，我们在使用 WebSocket 时，不再有请求和响应的概念，而是有事件和消息的概念。这时，Gateway（网关）就是用来处理这些事件和消息的。</p><p><code>SocketGateway</code>：</p><pre><code class="language-typescript">import { WebSocketGateway, WebSocketServer, SubscribeMessage, MessageBody, OnGatewayInit } from '@nestjs/websockets'import { Server, Socket } from 'socket.io'import { SocketService } from './socket.service'@WebSocketGateway(3001, {  allowEIO3: true,  cors: {    origin: process.env.CLIENT_ORIGIN || 'http://localhost:3000',    credentials: true,  },})export class SocketGateway implements OnGatewayInit {  @WebSocketServer()  server: Server  constructor(private readonly socketService: SocketService) {}  afterInit(server: Server) {    this.socketService.initialize(server)  }  @SubscribeMessage('privateMessageSent')  handlePrivateMessage(@MessageBody() data: any, client: Socket) {    console.log('Received private message:', data, 'from', client)  }}</code></pre><p>在 <code>SocketGateway</code> 中，我们使用 <code>this.socketService.initialize(server)</code> 初始化了 Socket 服务器，然后使用 <code>@SubscribeMessage</code> 装饰器来监听客户端发送的消息。</p><p>我们可以在客户端发送消息时调用 <code>socket.emit('privateMessageSent', message)</code>。来看一下我的输入框 <code>PrivateMessageTextBox</code> 组件：</p><pre><code class="language-tsx">import React, { useState, KeyboardEvent, ChangeEvent, FormEvent } from "react";import { Icon } from "@iconify/react";import socket from "../../redux/actions/messageActions";import { UsersService } from '../../redux/actions/serverConnection'interface PrivateMessageTextBoxProps {  receiverUsername: string;}const PrivateMessageTextBox: React.FC&lt;PrivateMessageTextBoxProps&gt; = ({ receiverUsername }) =&gt; {  const [message, setMessage] = useState&lt;string&gt;("");    const handleKeyDown = (e: KeyboardEvent) =&gt; {    if (e.key === "Enter" &amp;&amp; !e.shiftKey) {      e.preventDefault();      handleSendMessage();    }  }    const handleChange = (e: ChangeEvent&lt;HTMLTextAreaElement&gt;) =&gt; {    setMessage(e.target.value);  }    const handleSendMessage = async (e?: FormEvent) =&gt; {    e &amp;&amp; e.preventDefault();    const senderId = localStorage.getItem("userId");    const response = await UsersService.getUserByUsername(receiverUsername);    const receiver = response.data;    socket.emit("privateMessageSent", {      id: `${socket.id}${Math.random()}`,      senderId: senderId,      receiverId: receiver._id,      text: message    });    setMessage("");  }  return (    &lt;form className="px-2 m-3" onSubmit={ handleSendMessage }&gt;      &lt;div        className="w-100 p-0 m-0"        style={{ marginBottom: '24px', backgroundColor: 'rgba(56, 58, 64)', textIndent: '0', borderRadius: '8px' }}      &gt;        &lt;div          className="overflow-x-hidden overflow-y-scroll"          style={{ borderRadius: '8px', backfaceVisibility: 'hidden', scrollbarWidth: 'none' }}        &gt;          &lt;div className="d-flex position-relative"&gt;            &lt;span className="position-sticky" style={{ flex: '0 0 auto', alignSelf: 'stretch' }}&gt;              &lt;Icon                icon="bi:plus-circle-fill"                className="position-sticky w-auto m-0"                style={{                  height: '44px', padding: '10px 16px', top: '0', marginLeft: '-16px',                  background: 'transparent', color: 'rgba(181, 186, 193)', border: '0'                }}              /&gt;            &lt;/span&gt;            &lt;span              className="p-0 fs-6 w-100 position-relative"              style={{                background: 'transparent', resize: 'none', border: 'none', appearance: 'none',                fontWeight: '400', lineHeight: '1.375rem', height: '44px', minHeight: '44px',                boxSizing: 'border-box', color: 'rgba(219, 222, 225)',              }}            &gt;              &lt;textarea                autoCapitalize="none" autoComplete="off" autoCorrect="off" autoFocus={ true }                placeholder="Text @dummy" spellCheck="true"                className="position-absolute overflow-hidden"                value={ message }                onChange={ handleChange }                onKeyDown={ handleKeyDown }                style={{                  border: 'none', outline: 'none', resize: 'none',                  paddingBottom: '11px', paddingTop: '11px', paddingRight: '10px',                  left: '0', right: '10px', background: 'transparent',                  caretColor: 'rgba(219, 222, 225)', color: 'rgba(219, 222, 225)'                }}              /&gt;          &lt;/span&gt;          &lt;/div&gt;        &lt;/div&gt;      &lt;/div&gt;    &lt;/form&gt;  )}export default PrivateMessageTextBox;</code></pre><p>这个组件是一个输入框，用户输入消息后按下回车键就会发送消息。发送的消息会被 <code>SocketGateway</code> 监听到，然后打印到控制台。</p><p>其他的地方可以忽略掉不看，只需要重点看 <code>handleSendMessage</code> 方法。这个方法会向服务器发送一个 <code>privateMessageSent</code> 事件，事件的数据是一个对象，包含了消息的 ID、发送者 ID、接收者 ID 和消息内容：</p><pre><code class="language-tsx">const handleSendMessage = async (e?: FormEvent) =&gt; {  e &amp;&amp; e.preventDefault();  const senderId = localStorage.getItem("userId");  const response = await UsersService.getUserByUsername(receiverUsername);  const receiver = response.data;  socket.emit("privateMessageSent", {    id: `${socket.id}${Math.random()}`,    senderId: senderId,    receiverId: receiver._id,    text: message  });  setMessage("");}</code></pre><blockquote><p>这里提一嘴 <code>userId</code> 的来处。</p><p>在服务端的 <code>AuthController</code> 的 <code>login</code> 方法中，我们向客户端发送了一个 Token，但我们也可以发送其他东西，比如用户的 ID。</p><pre><code class="language-typescript">const user = await this.usersService.findByUsername(loginUserDto.username)res.status(HttpStatus.OK).json({  status: '00000',  message: 'User logged in successfully',  token: resultToken,  userId: user._id,})</code></pre><p>在客户端也要写对应的接收逻辑：</p><pre><code class="language-typescript">const loginUser = (userData: User, navigate: (path: string) =&gt; void) =&gt; {  return async (dispatch: Dispatch) =&gt; {    try {      const response = await UsersService.login(userData)      const data = response.data      if (data.status === '00000') {        localStorage.setItem('jwtToken', data.token)        localStorage.setItem('userId', data.userId)  // &lt;--- 这里        dispatch(          setCurrentUser({            ...userData,            access_token: data.token,            id: data.userId,  // &lt;--- 也把ID存储到Redux里，说不定未来会用到呢          }),        )        console.log(data)        navigate('/')      } else console.log(data.message)    } catch (error) {      console.error(error)    }  }}</code></pre></blockquote><p>消息从客户端发送到服务端后，服务端会打印出消息的内容。</p><p>一个简单的消息发送就这样完成了。</p><p>接下来还需要完成消息的接收、存储和展示，这个就留到下一篇文章再说了。</p></body></html>]]></content>
    
    
    <summary type="html">本文是 React + NestJS + Socket.io 全栈项目实践的第二篇，核心内容是实现基于 JWT 的用户身份验证。后端部分，教程详细讲解了如何配置 NestJS 的JWT模块、在登录成功后生成Token，并创建全局路由守卫 AccessTokenGuard 配合 @Public 装饰器来保护接口。前端部分，则演示了 React 应用在登录后如何存储Token，并利用自定义 useAuth Hook 和 ProtectedRoute 组件，根据认证状态实现动态的页面访问控制。本教程完整地展示了一个安全的全栈JWT认证流程，为后续功能开发奠定了权限基础。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="全栈实践" scheme="https://blog.cytrogen.icu/tags/%E5%85%A8%E6%A0%88%E5%AE%9E%E8%B7%B5/"/>
    
    <category term="Node.js" scheme="https://blog.cytrogen.icu/tags/Node-js/"/>
    
    <category term="React.js" scheme="https://blog.cytrogen.icu/tags/React-js/"/>
    
    <category term="TypeScript" scheme="https://blog.cytrogen.icu/tags/TypeScript/"/>
    
    <category term="NestJS" scheme="https://blog.cytrogen.icu/tags/NestJS/"/>
    
  </entry>
  
  <entry>
    <title>Pug 学习笔记</title>
    <link href="https://blog.cytrogen.icu/posts/a039.html"/>
    <id>https://blog.cytrogen.icu/posts/a039.html</id>
    <published>2024-04-03T03:05:28.000Z</published>
    <updated>2026-02-09T17:16:54.757Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>我的博客网站基于 Hexo，使用了 Pug 模板引擎。有时候感觉现在正在使用的主题不够满足自己的需求，就得手动修改 Pug 文件。</p><span id="more"></span><h1 id="1-pug基础"><a class="markdownIt-Anchor" href="#1-pug基础"></a> 1. Pug 基础</h1><p>Pug 过去被称为 Jade，是一种高性能的模板引擎，广泛用于 Node.JS。它使用简洁的缩进语法，使得 HTML 更易于编写和阅读。</p><h2 id="11-pug语法"><a class="markdownIt-Anchor" href="#11-pug语法"></a> 1.1. Pug 语法</h2><p>Pug 使用缩进来表示标签的嵌套关系：</p><pre><code class="language-plaintext">doctype htmlhtml    head        title My Pug Template    body        h1 Hello, Pug!</code></pre><p>这将生成以下 HTML：</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;&lt;html&gt;    &lt;head&gt;        &lt;title&gt;My Pug Template&lt;/title&gt;    &lt;/head&gt;    &lt;body&gt;        &lt;h1&gt;Hello, Pug!&lt;/h1&gt;    &lt;/body&gt;&lt;/html&gt;</code></pre><p>树状结构：</p><pre><code class="language-plaintext">ul    li Item 1    li Item 2    li Item 3</code></pre><p>标签后面使用括号来添加属性，并使用空格来添加内容：</p><pre><code class="language-plaintext">a(href="https://www.example.com") Visit Example.com</code></pre><p>约等于：</p><pre><code class="language-html">&lt;a href="https://www.example.com"&gt;Visit Example.com&lt;/a&gt;</code></pre><p>你可以声明一个标签是自闭合的，加上一个斜杠的话：</p><pre><code class="language-plaintext">img/</code></pre><p>纯文本使用管道符 <code>|</code>：</p><pre><code class="language-plaintext">p    | This is a paragraph of text.    | This is another line of text.</code></pre><p>标签内文本是最常见的：</p><pre><code class="language-plaintext">p This is a paragraph of &lt;strong&gt;text&lt;/strong&gt; .</code></pre><p>Pug 模板中也可以使用 JavaScript 变量：</p><pre><code class="language-plaintext">- var name = 'World'h1 Hello, #{name}!</code></pre><pre><code class="language-html">&lt;h1&gt;Hello, World!&lt;/h1&gt;</code></pre><p>以及标准的 JavaScript 控制结构：</p><pre><code class="language-plaintext">- var user = { name: 'John', admin: true }if user.admin    p Hello, #{user.name}! You are an admin.else    p Hello, #{user.name}!</code></pre><pre><code class="language-html">&lt;p&gt;Hello, John! You are an admin.&lt;/p&gt;</code></pre><h1 id="2-hexo中的pug"><a class="markdownIt-Anchor" href="#2-hexo中的pug"></a> 2. Hexo 中的 Pug</h1><p>Hexo 可以使用 Pug 模板引擎，但是需要安装 <code>hexo-renderer-pug</code> 插件：</p><pre><code class="language-bash">npm install hexo-renderer-pug --save</code></pre><h2 id="21-配置项"><a class="markdownIt-Anchor" href="#21-配置项"></a> 2.1. 配置项</h2><p>在 Pug 模板中可以使用 <code>theme</code> 对象来访问主题配置项：</p><pre><code class="language-plaintext">year = year == theme.startyear ? year : theme.startyear + ' - ' + year;</code></pre><p>而在 <code>_config.yml</code> 中内容如下：</p><pre><code class="language-yaml">startyear: 2022</code></pre><p>对于 Hexo 项目根目录下的 <code>_config.yml</code> 文件，可以使用 <code>config</code> 对象来访问配置项：</p><pre><code class="language-plaintext">title = config.title</code></pre><h2 id="22-页面布局"><a class="markdownIt-Anchor" href="#22-页面布局"></a> 2.2. 页面布局</h2><p>模板文件模板文件，重点便是「模板」这个词。我们可以将一些重复的内容放在模板文件中，然后在其他页面中引用。</p><p>比方说 HTML 的 <code>&lt;head&gt;</code> 标签：</p><pre><code class="language-plaintext">// head.pugmeta(charset="utf-8")meta(name="X-UA-Compatible", content="IE=edge")title     block site_title        = config.titleblock description    meta(name="description", content= config.description ? config.description : 'A Blog Powered By Hexo')meta(name="viewport", content="width=device-width, initial-scale=1")link(rel="icon", href=url_for(theme.favicon))link(rel="stylesheet", href=url_for("css/hermes.css"))- var xml = config.url + '/atom.xml'    link(rel="search", type="application/opensearchdescription+xml", href=xml, title=config.title)</code></pre><p>又或者说导航栏、页脚等等。</p><p><code>layout.pug</code> 文件是一个特殊的模板文件，它是所有页面的父模板。这里是一个简单的例子：</p><pre><code class="language-plaintext">doctypehtml(lang=config.language)    head        include head    body        header            include header.pug        main            block content        footer            include footer.pug</code></pre><p><code>block</code> 是一个特殊的标签，它允许子模板文件覆盖父模板文件中的内容。比如说，我们可以在 <code>layout.pug</code> 中定义一个 <code>block content</code>，然后在其他页面中覆盖它。</p><pre><code class="language-plaintext">extends layoutblock content    h1 Hello, Pug!    p This is a paragraph.</code></pre><blockquote><p><code>extends</code> 则是用来引用父模板文件的。</p></blockquote></body></html>]]></content>
    
    
    <summary type="html">本文是一篇 Pug 模板引擎的学习笔记，侧重于其在 Hexo 博客框架中的应用。文章从 Pug 的基础语法入手，介绍了其缩进式写法、属性、文本处理，以及如何在模板中嵌入 JavaScript 变量与控制流。接着，笔记讲解了在 Hexo 中使用 Pug 的关键技巧，如访问站点与主题的配置项，和利用 extends、block 与 include 构建可复用的页面布局。这篇笔记为希望自定义 Hexo 主题的开发者提供了清晰的入门指南。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Pug" scheme="https://blog.cytrogen.icu/tags/Pug/"/>
    
  </entry>
  
  <entry>
    <title>React + NestJS + Socket.io 项目实践【1】：从 Express 迁移</title>
    <link href="https://blog.cytrogen.icu/posts/3b97.html"/>
    <id>https://blog.cytrogen.icu/posts/3b97.html</id>
    <published>2024-03-30T04:06:13.000Z</published>
    <updated>2026-02-09T17:16:55.001Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>二月份的时候我写了一篇 <a href="/posts/bb3e">React + Express + Socket.io 之间的实时通信【2】：注册登录</a>，那时候我还在用 Express 作为后端框架。</p><p>因为中途想到使用 TypeScript，所以我决定迁移到 NestJS。</p><span id="more"></span><h1 id="前端"><a class="markdownIt-Anchor" href="#前端"></a> 前端</h1><p>先说一下我对前端的改动。</p><p>因为是想要整个项目都用 TypeScript，所以我把 <code>src</code> 目录下的所有 <code>.js</code> 文件都改成了 <code>.tsx</code>。</p><p>很多文件都不需要改动，例如 <code>App.js</code>：</p><pre><code class="language-js">import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";import "./App.css";import "bootstrap/dist/css/bootstrap.min.css";import Home from "./components/Home";import Login from "./components/Login";import Register from "./components/Register";import PrivateMessageHomepage from "./components/private_message_homepage/Private_Message_Homepage";import PrivateMessageChatpage from "./components/private_message_chatpage/Private_Message_Chatpage";import socket from "./components/utils/actions/authActions";function App() {    return (        &lt;BrowserRouter&gt;            &lt;Routes&gt;                &lt;Route path="/" element={ &lt;Navigate to="/channels/@me" replace /&gt; } /&gt;                &lt;Route path="/channels/@me" element={ &lt;Home /&gt; }&gt;                    &lt;Route path="" element={ &lt;PrivateMessageHomepage style={{ flex: '1 1 auto' }} /&gt; } /&gt;                    &lt;Route path="dummy" element={ &lt;PrivateMessageChatpage style={{ flex: '1 1 auto' }} /&gt; }/&gt;                &lt;/Route&gt;                &lt;Route path="/login" element={ &lt;Login socket={ socket } /&gt; } /&gt;                &lt;Route path="/register" element={ &lt;Register /&gt; } /&gt;            &lt;/Routes&gt;        &lt;/BrowserRouter&gt;    );}export default App;</code></pre><p><code>App.tsx</code>：</p><pre><code class="language-tsx">import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";import "bootstrap/dist/css/bootstrap.min.css";import "./App.css";import Home from "./components/Home";import Login from "./components/Login";import Register from "./components/Register";import Guard from "./components/utils/guard";// import PrivateMessageHomepage from "./components/private_message_homepage/Private_Message_Homepage";import PrivateMessageChatPage from "./components/private_message_chat_page/Private_Message_Chat_Page";function App() {  return (    &lt;BrowserRouter&gt;      &lt;Routes&gt;        &lt;Route path="/" element={ &lt;Navigate to="/channels/@me" replace /&gt; } /&gt;        &lt;Route path="/channels/@me" element={ &lt;Guard /&gt; }&gt;          &lt;Route path="" element={ &lt;Home /&gt;} /&gt;          &lt;Route path="dummy" element={ &lt;PrivateMessageChatPage style={{ flex: '1 1 auto' }} /&gt; }/&gt;        &lt;/Route&gt;        &lt;Route path="/login" element={ &lt;Login /&gt; } /&gt;        &lt;Route path="/register" element={ &lt;Register /&gt; } /&gt;      &lt;/Routes&gt;    &lt;/BrowserRouter&gt;  );}export default App;</code></pre><p>对比一下会发现其实没有变化，<code>PrivateMessageHomepage</code> 改成了 <code>Guard</code> 只是因为业务逻辑的改动，跟 TypeScript 无关。</p><h2 id="redux"><a class="markdownIt-Anchor" href="#redux"></a> Redux</h2><p>涉及到 Redux 的文件多多少少都有一些改动。</p><p><code>store.js</code>：</p><pre><code class="language-js">import { configureStore } from "@reduxjs/toolkit";import authSlice from "./reducers/authSlice";export default configureStore({  reducer: {    auth: authSlice  }});</code></pre><p><code>store.ts</code>：</p><pre><code class="language-ts">import { configureStore } from "@reduxjs/toolkit";import { useDispatch } from "react-redux";import authSlice from "./reducers/authSlice";const store = configureStore({  reducer: {    auth: authSlice,  }})export type RootState = ReturnType&lt;typeof store.getState&gt;;export type AppDispatch = typeof store.dispatch;export const useAppDispatch = () =&gt; useDispatch&lt;AppDispatch&gt;();export default store;</code></pre><p>原先的 <code>store.js</code> 是直接导出了 <code>configureStore</code> 的返回值；<code>store.ts</code> 先是导出了 <code>RootState</code> 和 <code>AppDispatch</code> 这两个类型，然后道出了 <code>useAppDispatch</code> 这个自定义 Hook、以替代 <code>useDispatch</code>。</p><p><code>authSlice.js</code>：</p><pre><code class="language-js">import { createSlice } from "@reduxjs/toolkit";export const authSlice = createSlice({    name: "auth",    initialState: {        isAuthenticated: false,        user: {},        error: null    },    reducers: {        setCurrentUser: (state, action) =&gt; {            state.isAuthenticated = true;            state.user = action.payload;        },        setError: (state, action) =&gt; {            state.error = action.payload;        }    }});export const { setCurrentUser, setError } = authSlice.actions;export default authSlice.reducer;</code></pre><p><code>authSlice.ts</code>：</p><pre><code class="language-ts">import { createSlice, PayloadAction } from '@reduxjs/toolkit';import { User } from '../interfaces';interface AuthState {  isAuthenticated: boolean;  user: User | null;  error: string | null;}const initialState: AuthState = {  isAuthenticated: false,  user: null,  error: null,};export const authSlice = createSlice({  name: 'auth',  initialState,  reducers: {    setCurrentUser: (state, action: PayloadAction&lt;User&gt;) =&gt; {      state.isAuthenticated = true;      state.user = action.payload;    },    setError: (state, action: PayloadAction&lt;string&gt;) =&gt; {      state.error = action.payload;    },  },});export const { setCurrentUser, setError } = authSlice.actions;export default authSlice.reducer;</code></pre><p><code>authSlice.js</code> 和 <code>authSlice.ts</code> 的区别在于 <code>action</code> 的类型声明。TypeScript 是 JavaScript 的超集，目的是为了更好地进行静态类型检查，以避免各种各样的错误。要知道 JavaScript 是弱类型语言，这意味着你可以在不同的地方使用不同的类型而不报错。</p><p><code>interface</code> 关键字用于定义一个接口，接口是一种抽象的结构、定义了一个对象应该具有的属性和方法。<code>AuthState</code> 接口被定义后，有三个属性：<code>isAuthenticated</code>、<code>user</code> 和 <code>error</code>。然后设置 <code>initialState</code> 为 <code>AuthState</code> 类型。</p><p>也就是说 <code>initialState</code> 无论怎么改动，都必须符合 <code>AuthState</code> 的结构。假设我在 <code>initialState</code> 的 <code>isAuthenticated</code> 属性后面加了一个 <code>isRegistered</code> 属性，那么在 <code>reducers</code> 中的 <code>state</code> 就会报错，因为 <code>isRegistered</code> 属性并不在 <code>AuthState</code> 中。</p><p><code>setCurrentUser</code> 和 <code>setError</code> 的 <code>action</code> 参数都是 <code>PayloadAction</code> 类型，<code>PayloadAction</code> 是一个泛型接口，接受一个类型参数，这个类型参数就是 <code>action.payload</code> 的类型。这样一来，<code>action.payload</code> 的类型就被限制了，不会出现不符合预期的情况。</p><p>比方说 <code>setError</code> 的 <code>action</code> 参数就被限制为 <code>string</code> 类型。</p><p>我还新建了一个 <code>interfaces.ts</code> 文件来存放会被多个文件引用的接口：</p><pre><code class="language-ts">export interface User {  id?: number;  emailAddress?: string;  username: string;  password?: string;  access_token?: string;}</code></pre><p>属性后面的 <code>?</code> 表示这个属性是可选的。想象一下，<code>User</code> 接口会被注册、登录以及登出的组件引用：</p><ul><li>注册时，用户传来的数据中不会有 <code>id</code>、<code>access_token</code> 这两个属性</li><li>登录时，用户传来的数据中不会有 <code>emailAddress</code> 这个属性</li><li>登出时，用户传来的数据中不会有 <code>password</code> 这个属性</li></ul><p>所以这些属性都是可选的。</p><h2 id="axios"><a class="markdownIt-Anchor" href="#axios"></a> Axios</h2><p>我本来是全程使用 Socket.io 来进行通信，这也包括了登录、注册等操作。但是 Socket.io 并不适合用来做这些操作，所以我还是用了 Axios。</p><p>比方说注册用户，使用 Socket.io 的话就是这样：</p><pre><code class="language-js">const registerUser = (userData, navigate) =&gt; {  return dispatch =&gt; {    socket.emit("register", userData);        socket.on("newRegisteredUser", data =&gt; {      data.status === "00000" ? navigate("/login") : console.log(data.message);    });  }};</code></pre><p>先发送 <code>register</code> 事件，然后接收从服务端发来的 <code>newRegisteredUser</code> 事件，根据 <code>data.status</code> 的值来决定跳转到登录页面还是打印错误信息。</p><p>换成 Axios 的话，要先创建一个服务：</p><pre><code class="language-ts">import axios from 'axios';import { User } from "../interfaces";const api = axios.create({  baseURL: 'http://localhost:4000/api',});export const UsersService = {  register: (data: User) =&gt; {    return api.post('/users/register', data);  },  login: (data: User) =&gt; {    return api.post('/users/login', data);  },}</code></pre><p>使用 <code>baseURL</code> 的好处是如果后端地址改变、只需要改动一次就行了。</p><p><code>UsersService</code> 对象中有两个方法：<code>register</code> 和 <code>login</code>，分别用于注册和登录。当我们需要向后端发送请求时，只需要调用这些方法即可：</p><pre><code class="language-ts">const registerUser = (userData: User, navigate: (path: string) =&gt; void) =&gt; {  return async (dispatch: Dispatch) =&gt; {    try {      const response = await UsersService.register(userData);      const data = response.data;      if (data.status === "00000") navigate("/login");    } catch (error) {      console.error(error);    }  }}</code></pre><p>我还添加了一个 <code>try...catch</code> 语句，用于捕获请求失败的情况。</p><h2 id="登录和注册"><a class="markdownIt-Anchor" href="#登录和注册"></a> 登录和注册</h2><p>在写函数组件时，需要定义函数组件的类型：</p><pre><code class="language-tsx">import React from "react";// ...const Register: React.FC = () =&gt; {  // ...}</code></pre><blockquote><p>如果该函数组件还有 props，那么就需要定义 props 的类型：</p><pre><code class="language-tsx">import React from 'react';// ...interface PrivateMessageHomepageProps {    style: React.CSSProperties;}const PrivateMessageHomepage: React.FC&lt;PrivateMessageHomepageProps&gt; = ({ style }) =&gt; {    // ...}</code></pre><p>例如这里的 <code>PrivateMessageHomepage</code> 组件有一个 <code>style</code> 属性，所以需要定义其类型为 <code>React.CSSProperties</code>，毕竟是一个 CSS 样式对象嘛。</p></blockquote><p>之前讲到共用的 <code>User</code> 接口，但对于注册来说还需要 4 个必需的属性：<code>emailAddress</code>、<code>birthYear</code>、<code>birthMonth</code> 和 <code>birthDay</code>。其中 <code>emailAddress</code> 虽在 <code>User</code> 接口中，但是是可选的，不符合注册的要求。</p><p>所以我们可以使用 <code>&amp;</code> 运算符来合并两个接口：</p><pre><code class="language-ts">import { User } from "./utils/interfaces";// ...type RegisterUser = User &amp; {  emailAddress: string;  birthYear: string;  birthMonth: string;  birthDay: string;}</code></pre><p><code>RegisterUser</code> 接口继承了 <code>User</code> 接口，并添加了 4 个必需的属性。后加的属性会覆盖前面的属性，所以 <code>User</code> 接口中的 <code>emailAddress</code> 属性被覆盖了。</p><p>之后再使用 <code>useState</code> 来定义 <code>userData</code>：</p><pre><code class="language-tsx">const [userData, setUserData] = useState&lt;RegisterUser&gt;({    username: "",    emailAddress: "",    password: "",    birthYear: "",    birthMonth: "",    birthDay: ""  });</code></pre><p>登录时我们不需要 <code>User</code> 接口中其他的属性，只需要 <code>username</code> 和 <code>password</code> 属性。所以我们可以挑选出需要的属性：</p><pre><code class="language-tsx">type LoginUser = Pick&lt;User, "username" | "password"&gt;;</code></pre><p><code>Pick</code> 的用处是从一个对象中挑选出一些属性，返回一个新的对象。这意味着 <code>LoginUser</code> 接口只包含 <code>User</code> 接口中的 <code>username</code> 和 <code>password</code> 属性。</p><blockquote><p>像是需要展现出用户名的地方我们也可以这样写：</p><pre><code class="language-tsx">type UserProfile = Pick&lt;User, "username"&gt;;</code></pre></blockquote><h2 id="页面跳转"><a class="markdownIt-Anchor" href="#页面跳转"></a> 页面跳转</h2><p>最前面提及到的 <code>Guard</code> 组件是用来判断用户是否登录的，如果用户没有登录，那么就跳转到登录页面：</p><pre><code class="language-tsx">import React from "react";import { Navigate, Outlet } from "react-router-dom";const Guard: React.FC = () =&gt; {  const auth = localStorage.getItem("auth");  if (auth) return &lt;Outlet/&gt;;  else return &lt;Navigate to="/login" /&gt;;}export default Guard;</code></pre><p>如果 <code>localStorage</code> 中有 <code>auth</code> 这个键，那么就渲染 <code>Outlet</code> 组件，否则就跳转到登录页面。</p><p><code>Outlet</code> 组件是用来渲染子路由的。回到 <code>App.tsx</code>，能看到 <code>/channels/@me</code> 路由被 <code>Guard</code> 组件保护，子路由分别是默认的 <code>Home</code> 组件和 <code>dummy</code> 子路由。</p><p>也就是说用户在登陆后跳转到 <code>/channels/@me</code> 路由，会被 <code>Guard</code> 组件验证，然后渲染 <code>Home</code> 组件。</p><p><code>/channels/@me/dummy</code> 路由是用来测试私聊的，但是它也在 <code>Guard</code> 组件的保护之下。</p><h2 id="其他"><a class="markdownIt-Anchor" href="#其他"></a> 其他</h2><p>我的项目中有一些按钮在被鼠标悬停时会有一些样式变化，原先的逻辑是这样的：</p><pre><code class="language-jsx">const [hoverStates, setHoverStates] = useState({});const updateHoverState = (item, isHovered) =&gt; {    setHoverStates(prev =&gt; ({ ...prev, [item]: isHovered }));}</code></pre><p>转换到 TypeScript 后：</p><pre><code class="language-tsx">const [hoverStates, setHoverStates] = useState&lt;Record&lt;string, boolean&gt;&gt;({});const updateHoverState = (item: string, isHovered: boolean) =&gt; {    setHoverStates({      ...hoverStates,      [item]: isHovered    });  }</code></pre><p><code>Record</code> 的第一个参数定义了键的类型，第二个参数定义了值的类型。<code>hoverStates</code> 被定义为一个字典，键和值再被定义为 <code>string</code> 和 <code>boolean</code> 类型。</p><p>输入框组件里分别有着：</p><ul><li>判断用户是否按下了回车键的 <code>handleKeyDown</code> 函数</li><li>处理用户输入信息的 <code>handleChange</code> 函数</li><li>处理用户提交表单的 <code>handleSendMessage</code> 函数</li></ul><p>这些函数都需要定义类型：</p><pre><code class="language-tsx">const handleKeyDown = (e: KeyboardEvent) =&gt; {}const handleChange = (e: ChangeEvent&lt;HTMLTextAreaElement&gt;) =&gt; {}const handleSendMessage = (e: FormEvent) =&gt; {}</code></pre><h1 id="后端"><a class="markdownIt-Anchor" href="#后端"></a> 后端</h1><p>NestJS 是一个基于 Node.js 的后端框架，它使用 TypeScript 编写，提供了一些装饰器来简化开发。</p><p>我目前有的依赖：</p><pre><code class="language-json">{    "@nestjs/common": "^10.3.3",    "@nestjs/core": "^10.3.3",    "@nestjs/jwt": "^10.2.0",    "@nestjs/mapped-types": "*",    "@nestjs/mongoose": "^10.0.4",    "@nestjs/platform-express": "^10.3.3",    "@nestjs/platform-socket.io": "^10.3.3",    "@nestjs/typeorm": "^10.0.2",    "@nestjs/websockets": "^10.3.3",    "bcrypt": "^5.1.1",    "class-validator": "^0.14.1",    "cookie-parser": "^1.4.6",    "dotenv": "^16.4.5",    "mongoose": "^8.2.1",    "morgan": "^1.10.0",    "reflect-metadata": "^0.2.1",    "rxjs": "^7.8.1",    "typeorm": "^0.3.20"}</code></pre><p>NestJS 的入口文件是 <code>main.ts</code>：</p><pre><code class="language-ts">import { NestFactory } from '@nestjs/core'import { AppModule } from './app.module'import * as dotenv from 'dotenv'import { Server } from 'socket.io'dotenv.config()async function bootstrap() {  const app = await NestFactory.create(AppModule)  app.enableCors({    origin: process.env.CLIENT_ORIGIN || 'http://localhost:3000',    credentials: true,  })  app.setGlobalPrefix('api')  const server = app.getHttpServer()  new Server(server)  await app.listen(process.env.PORT || 4000)}bootstrap().catch((err) =&gt; console.error(err))</code></pre><p><code>dotenv</code> 是用来读取 <code>.env</code> 文件的，<code>.env</code> 文件用来存放环境变量。<code>CLIENT_ORIGIN</code> 是前端的地址，<code>PORT</code> 是后端的端口。</p><p>因为前后端分离的项目中，前端和后端是不同的域名，所以会有跨域问题。<code>app.enableCors</code> 方法用来解决跨域问题，<code>origin</code> 参数是前端的地址，<code>credentials</code> 参数是 <code>true</code> 表示允许携带 cookie。</p><p><code>app.setGlobalPrefix</code> 方法用来设置全局前缀，所有的路由都会加上这个前缀。比方说后面设置的 <code>/users/register</code> 路由会变成 <code>/api/users/register</code>。</p><p><code>app.getHttpServer</code> 方法返回一个 <code>http.Server</code> 实例，<code>new Server(server)</code> 用来创建一个 Socket.io 服务器。</p><p>最后调用 <code>app.listen</code> 方法来启动服务器。</p><h2 id="nestjs概念"><a class="markdownIt-Anchor" href="#nestjs概念"></a> NestJS 概念</h2><p>NestJS 目前支持两个 HTTP 平台：Express 和 Fastify。这是因为 NestJS 的开发团队认为 NestJS 立志于成为一个模块化的框架，不单单是一个 HTTP 框架。只要创建了适配器，NestJS 就可以在任何平台上运行。</p><p>NestJS 的核心概念有：</p><ul><li>控制器（Controller）</li><li>服务（Service）</li><li>模块（Module）</li></ul><h4 id="控制器"><a class="markdownIt-Anchor" href="#控制器"></a> 控制器</h4><p>控制器是处理传入请求的地方，它们会调用服务来完成请求。控制器的方法可以使用装饰器来定义路由。</p><pre><code class="language-ts">import { Controller, Get } from '@nestjs/common'import { AppService } from './app.service'@Controller()export class AppController {  constructor(private readonly appService: AppService) {}  @Get()  getHello(): string {    return this.appService.getHello()  }}</code></pre><p><code>@Controller</code> 装饰器用来定义一个控制器。假设我们的后端地址是 <code>http://localhost:4000</code>，那么 <code>@Controller()</code> 装饰器的参数就是 <code>http://localhost:4000</code>。</p><p><code>@Get()</code> 装饰器用来定义一个 GET 请求，这个请求的路径就是控制器的路径，也就是请求 <code>http://localhost:4000</code>。</p><p>假设我想要请求 <code>http://localhost:4000/api/users/register</code>，那么就要写成：</p><pre><code class="language-ts">@Controller('users')@Get('register')</code></pre><p>为什么不写成 <code>@Controller('api/users')</code> 呢？因为全局前缀已经被我们设置为 <code>api</code> 了。</p><h4 id="服务"><a class="markdownIt-Anchor" href="#服务"></a> 服务</h4><p>刚才的控制器中有一个 <code>AppService</code> 服务，服务是处理业务逻辑的地方。服务可以被控制器调用，也可以被其他服务调用。</p><pre><code class="language-ts">import { Injectable } from '@nestjs/common'@Injectable()export class AppService {  getHello(): string {    return 'Welcome to HotaruTS!!'  }}</code></pre><p><code>@Injectable</code> 装饰器用来定义一个服务。服务中的方法可以被其他服务调用，也可以被控制器调用。</p><p>刚才调用的是 <code>getHello</code> 方法，返回的是一个字符串。如果使用 Postman 请求 <code>http://localhost:4000</code>，响应的内容就是 <code>Welcome to HotaruTS!!</code>。</p><h4 id="模块"><a class="markdownIt-Anchor" href="#模块"></a> 模块</h4><p>模块是一个用来组织应用程序的地方，每个应用程序至少有一个根模块。模块中可以包含控制器、服务、提供器等。</p><p>根模块可以看成是 Express 里的 <code>app</code> 对象，它是所有模块的入口。</p><p>先来看一下我 Express 项目中的 <code>app.js</code>：</p><pre><code class="language-js">const createError = require('http-errors');const express = require('express');const path = require('path');const cookieParser = require('cookie-parser');const logger = require('morgan');const indexRouter = require('./routes/index');const usersRouter = require('./routes/users');const app = express();app.set('views', path.join(__dirname, 'views'));app.set('view engine', 'pug');app.use(logger('dev'));app.use(express.json());app.use(express.urlencoded({ extended: false }));app.use(cookieParser());app.use(express.static(path.join(__dirname, 'public')));app.use('/', indexRouter);app.use('/users.js', usersRouter);app.use(function(req, res, next) {    next(createError(404));});app.use(function(err, req, res, next) {    res.locals.message = err.message;    res.locals.error = req.app.get('env') === 'development' ? err : {};    res.status(err.status || 500);    res.render('error');});module.exports = app;</code></pre><ol><li>导入依赖</li><li>创建路由器 <code>indexRouter</code> 和 <code>usersRouter</code></li><li>创建 <code>app</code> 对象，也就是 Express 的实例</li><li>设置视图引擎和视图路径</li><li>使用中间件，分别是：<ol><li><code>logger</code>：记录请求日志，<code>dev</code> 参数表示开发环境</li><li><code>express.json</code>：解析 JSON 格式的请求体</li><li><code>express.urlencoded</code>：解析 URL 编码的请求体，<code>extended</code> 参数表示是否使用 <code>qs</code> 库</li><li><code>cookieParser</code>：解析 cookie</li><li><code>express.static</code>：设置静态文件目录，也就是 <code>public</code> 目录</li></ol></li><li>配置路由，让 <code>indexRouter</code> 和 <code>usersRouter</code> 分别处理 <code>/</code> 和 <code>/users</code> 路径</li><li>处理 404 错误</li><li>处理其他错误</li><li>导出 <code>app</code> 对象</li></ol><p>得知了这些，我们就可以仿照 Express 的写法来写 NestJS 的模块。</p><p>首先导入依赖：</p><pre><code class="language-ts">import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common'import { APP_FILTER } from '@nestjs/core'import { MongooseModule } from '@nestjs/mongoose'import * as express from 'express'import * as cookieParser from 'cookie-parser'import * as morgan from 'morgan'import { AppController } from './app.controller'import { AppService } from './app.service'import { AnyExceptionFilter } from './any-exception.filter'import { LoggerMiddleware } from './common/middleware/logger.middleware'import { SocketModule } from './socket/socket.module'import { UsersModule } from './users/users.module'</code></pre><p><code>@Module</code> 装饰器可以定义一个模块，参数分别是：</p><ul><li><code>imports</code>：导入其他模块</li><li><code>controllers</code>：控制器</li><li><code>providers</code>：提供器</li></ul><p>因为这个项目的数据库是 MongoDB，所以我导入了 <code>MongooseModule</code> 模块。<code>SocketModule</code> 和 <code>UsersModule</code> 是自定义的模块。</p><p><code>UsersModule</code> 后面会详细讲解，<code>SocketModule</code> 等未来写到消息传递时再讲。</p><p>控制器就不用多说了，模块本来就是用来组织控制器的。<code>AppModule</code> 中只有一个控制器 <code>AppController</code>。</p><p>提供器是一个用来提供服务的地方，服务可以被控制器调用。<code>AppService</code> 就是一个提供器。除此之外，还有一个全局异常过滤器 <code>AnyExceptionFilter</code>。</p><pre><code class="language-ts">@Module({  imports: [    MongooseModule.forRoot(process.env.DATABASE_URL || 'mongodb://localhost:27017/hotaru'),    SocketModule,    UsersModule,  ],  controllers: [AppController],  providers: [    AppService,    {      provide: APP_FILTER,      useClass: AnyExceptionFilter,    },  ],})</code></pre><p>为 <code>AppModule</code> 添加了一个 <code>configure</code> 方法，这个方法是 <code>NestModule</code> 接口的一个方法，作用是添加中间件。</p><p><code>consumer.apply</code> 方法用来添加中间件，参数是一个或多个中间件。这里添加了 <code>morgan</code>、<code>express.json</code>、<code>express.urlencoded</code>、<code>cookieParser</code>、<code>express.static</code> 和 <code>LoggerMiddleware</code> 中间件。</p><p><code>forRoutes('*')</code> 表示所有路由都会使用这些中间件。</p><p>最终导出 <code>AppModule</code>：</p><pre><code class="language-ts">export class AppModule implements NestModule {  configure(consumer: MiddlewareConsumer) {    consumer      .apply(        morgan('dev'),        express.json(),        express.urlencoded({ extended: false }),        cookieParser(),        express.static('public'),        LoggerMiddleware,      )      .forRoutes('*')  }}</code></pre><p>这样，我们就完成了一个 NestJS 的模块。</p><h2 id="日志中间件"><a class="markdownIt-Anchor" href="#日志中间件"></a> 日志中间件</h2><p><code>LoggerMiddleware</code> 中间件是一个自定义的中间件，用来记录请求日志：</p><pre><code class="language-ts">import { Injectable, NestMiddleware } from '@nestjs/common';import { Request, Response, NextFunction } from 'express';@Injectable()export class LoggerMiddleware implements NestMiddleware {  use(req: Request, res: Response, next: NextFunction) {    console.log('Request...', req.method, req.originalUrl);    next();  }}</code></pre><p>目前这个中间件只是简单地打印请求方法和请求路径。</p><h2 id="用户模块"><a class="markdownIt-Anchor" href="#用户模块"></a> 用户模块</h2><p>用户模块是一个用来处理用户注册、登录、登出的模块。</p><p>在 NestJS 里创建一个模块可以使用 CLI：</p><pre><code class="language-bash">nest g module users</code></pre><p>这个命令会在 <code>src</code> 目录下创建一个 <code>users</code> 目录，里面有一个 <code>users.module.ts</code> 文件。</p><p>首先我们得知道原先的 Express 项目里，用户注册的逻辑是怎么写的：</p><pre><code class="language-js">socket.on("register", async userData =&gt; {    const existingUserEmail = await User.findOne({        emailAddress: userData.emailAddress    });    const existingUsername = await User.findOne({        username: userData.username    });        if (existingUserEmail || existingUsername) {        console.log(`[U0102] User already exists: ${userData.username}`);        User.find({}).then((docs) =&gt; {            console.log(docs);        }).catch((err) =&gt; {            console.error(err);        });        socket.emit("newRegisteredUser", {            status: "U0102",            message: "User already exists."        });        return;    }        await User.create({        emailAddress: userData.emailAddress,        username: userData.username,        password: userData.password,        DOBYear: userData.birthYear,        DOBMonth: MonthToNumber[userData.birthMonth],        DOBDay: userData.birthDay    })    console.log(`[00000] User registered: ${userData.username}`);        socketIO.emit("newRegisteredUser", {        status: "00000",        token: generateJWT(userData.username)    });});</code></pre><p>因为使用的是 Socket.io，所以要监听 <code>register</code> 事件，然后验证用户填写的信息。如果用户已经存在，就返回错误信息；如果用户不存在，就创建一个新用户。</p><p>其中的状态码是自定义的，采用的是类似于阿里巴巴代码规约的状态码。</p><p>在 NestJS 中，鉴于客户端已经改为使用 Axios 这样的 HTTP 库，我们就不再使用 Socket.io 了。先创建一个路径为 <code>/users</code> 的控制器：</p><pre><code class="language-ts">@Controller('users')export class UsersControllers {  constructor(private readonly usersService: UsersService) { }}</code></pre><p><code>constructor</code> 方法中注入了一个私有且只读的 <code>usersService</code> 服务，这意味着这个服务只能在这个控制器中使用。</p><pre><code class="language-ts">@Post('register')async register(@Body() registerUserDto: RegisterUserDto, @Res() res: Response) {}</code></pre><p><code>@Post('register')</code> 装饰器用来定义一个 POST 请求，请求路径是 <code>/users/register</code>。</p><p><code>@Body()</code> 装饰器用来获取请求体，<code>registerUserDto</code> 是一个数据传输对象，包含了用户注册时需要的信息，也就是客户端传来的数据：</p><ul><li><code>emailAddress</code></li><li><code>username</code></li><li><code>password</code></li><li><code>birthYear</code></li><li><code>birthMonth</code></li><li><code>birthDay</code></li></ul><p><code>@Res()</code> 装饰器用来获取响应对象。</p><pre><code class="language-ts">const existingUser = await this.usersService.findByEmail(registerUserDto.emailAddress)if (existingUser) {  throw new HttpException('Email address already in use', HttpStatus.BAD_REQUEST)}if (!registerUserDto.emailAddress) {  throw new HttpException('Email address is required', HttpStatus.BAD_REQUEST)}try {  const user = this.usersService.register(registerUserDto)  res.status(HttpStatus.OK).json({    status: '00000',    message: 'User registered successfully',    user: user,  })} catch (error) {  res.status(HttpStatus.BAD_REQUEST).json({    status: 'U0100',    message: 'Failed to register user',  })}</code></pre><p>首先调用 <code>this.usersService.findByEmail</code> 方法来查找用户是否已经存在，如果存在就返回错误信息。接着判断用户填写的信息是否完整，如果不完整就返回错误信息。</p><p>最后调用 <code>this.usersService.register</code> 方法来注册用户，如果注册成功就返回成功信息，否则返回错误信息。</p><p>每次返回响应时都要设置状态码，比方说请求成功时写的 <code>HttpStatus.OK</code>，请求失败时写的 <code>HttpStatus.BAD_REQUEST</code>。尽管已经自定义了一套状态码，但是还是要遵循 HTTP 协议的状态码，谁叫我们是用 HTTP 协议的呢。</p><p>那么 <code>UsersService</code> 里到底是什么样的呢？</p><pre><code class="language-ts">import { Injectable, UnauthorizedException } from '@nestjs/common'import { JwtService } from '@nestjs/jwt'import { InjectModel } from '@nestjs/mongoose'import { v4 as uuidv4 } from 'uuid'import * as bcrypt from 'bcrypt'import { Model } from 'mongoose'import { RegisterUserDto, LoginUserDto } from './dto'import { User, UserDocument } from './user.schema'@Injectable()export class UsersService {  constructor(    @InjectModel(User.name) private usersModel: Model&lt;UserDocument&gt;,    private jwtService: JwtService,  ) {  }  async register(registerUserDto: RegisterUserDto): Promise&lt;void | User&gt; {    const id = uuidv4()    const hashedPassword = await bcrypt.hash(registerUserDto.password, 10)    const newUser = new this.usersModel({      id,      ...registerUserDto,      password: hashedPassword,    })      let savedUser: void | User    try {      savedUser = await newUser.save().then(() =&gt; console.log('User registered successfully'))    } catch (err) {      console.error(err)    }    return savedUser  }  async findByEmail(emailAddress: string): Promise&lt;User | null&gt; {    return this.usersModel.findOne({ emailAddress }).exec()  }}</code></pre><p><code>@InjectModel(User.name)</code> 注入了一个 Mongoose 模型，用来操作数据库。下面的 <code>jwtService</code> 是用来生成 JWT 的服务，以后再聊聊 JWT。</p><p><code>register</code> 方法中我们先用 <code>uuidv4</code> 方法生成一个唯一的 ID，然后用 <code>bcrypt</code> 库对密码进行加密。接着使用 <code>new</code> 关键字创建一个用户实例、传入所有创建用户时需要的信息。 最后调用 <code>save</code> 方法保存用户信息，如果保存成功就返回用户信息，否则返回 <code>void</code>。</p><p><code>findByEmail</code> 方法用来查找用户是否已经存在，如果存在就返回用户信息，否则返回 <code>null</code>。</p><blockquote><p>现在已经看到了很多次 <code>...Dto</code>，这是什么呢？</p><p>DTO 的全程为 Data Transfer Object，数据传输对象。它是一个用来传输数据的对象，通常用来传输数据给服务端或者从服务端传输数据给客户端。在 NestJS 中，DTO 是一个用来定义数据结构的类，用来规范数据的传输。</p><p>例如 <code>RegisterUserDto</code> 类用来定义用户注册时需要的信息：</p><pre><code class="language-ts">import { IsEmail, IsNotEmpty, IsString } from 'class-validator'export class RegisterUserDto {  @IsEmail()  emailAddress: string  @IsString()  @MinLength(6)  username: string  @IsString()  @MinLength(8)  password: string  @IsString()  birthYear: string  @IsString()  birthMonth: string  @IsString()  birthDay: string}</code></pre><p>这里使用了多个装饰器来定义每个属性的类型，有助于进行数据验证。</p></blockquote><p><code>UserSchema</code> 则是用来定义用户模型的，是 MongoDB 要求的数据结构：</p><pre><code class="language-ts">import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'import { Document } from 'mongoose'export type UserDocument = User &amp; Document@Schema()export class User {  @Prop({ required: true, unique: true })  username: string  @Prop({ required: false, unique: true })  emailAddress: string  @Prop({ required: true })  password: string  @Prop({ required: false })  birthYear: string  @Prop({ required: false })  birthMonth: string  @Prop({ required: false })  birthDay: string}export const UserSchema = SchemaFactory.createForClass(User)</code></pre><p><code>@Prop</code> 装饰器用来定义一个属性，<code>@Schema</code> 装饰器用来定义一个模式。<code>UserDocument</code> 是一个用户文档，继承了 <code>User</code> 和 <code>Document</code>。</p><p>这里我们定义的属性和 <code>RegisterUserDto</code> 中的属性是一样的，但 <code>UserSchema</code> 注重于定义会被存储在数据库中的数据结构，<code>RegisterUserDto</code> 注重于定义会在客户端和服务端之间传输的数据结构。</p><p>最终，我们在 <code>UsersModule</code> 中导入这些模块：</p><pre><code class="language-ts">import { Module } from '@nestjs/common'import { MongooseModule } from '@nestjs/mongoose'import { JwtService } from '@nestjs/jwt'import { User, UserSchema } from './user.schema'import { UsersControllers } from './users.controllers'import { UsersService } from './users.service'@Module({  imports: [MongooseModule.forFeature([{ name: User.name, schema: UserSchema }])],  controllers: [UsersControllers],  providers: [UsersService, JwtService],})export class UsersModule {}</code></pre><div class="danger"><p>不要忘了，新建的模块要在 <code>AppModule</code> 中导入：</p><pre><code class="language-ts">@Module({ imports: [UsersModule] })</code></pre></div></body></html>]]></content>
    
    
    <summary type="html">本文是 React + NestJS + Socket.io 全栈项目实践的第一篇，详细记录了如何将原有的 Express.js 后端迁移至 TypeScript 驱动的 NestJS 框架。前端部分，文章重点展示了将 React 项目升级为 TypeScript 的关键改动，包括为 Redux store、slice 和 action 添加强类型，并使用 Axios 处理用户认证请求。后端部分，则深入介绍了 NestJS 的核心概念（控制器、服务、模块），并一步步重构了用户注册等业务逻辑，内容涵盖了使用 DTO 进行数据验证和 Mongoose 定义数据模型。本文为希望从 Express 过渡到 NestJS 的开发者提供了一份清晰的迁移指南。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="全栈实践" scheme="https://blog.cytrogen.icu/tags/%E5%85%A8%E6%A0%88%E5%AE%9E%E8%B7%B5/"/>
    
    <category term="Node.js" scheme="https://blog.cytrogen.icu/tags/Node-js/"/>
    
    <category term="React.js" scheme="https://blog.cytrogen.icu/tags/React-js/"/>
    
    <category term="TypeScript" scheme="https://blog.cytrogen.icu/tags/TypeScript/"/>
    
    <category term="NestJS" scheme="https://blog.cytrogen.icu/tags/NestJS/"/>
    
  </entry>
  
  <entry>
    <title>MTH 2207 笔记</title>
    <link href="https://blog.cytrogen.icu/posts/2537.html"/>
    <id>https://blog.cytrogen.icu/posts/2537.html</id>
    <published>2024-03-14T03:55:28.000Z</published>
    <updated>2026-02-09T17:16:54.733Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>微积分笔记，仅作为个人学习记录，不保证正确性。</p><span id="more"></span><h1 id="1-渐近线"><a class="markdownIt-Anchor" href="#1-渐近线"></a> 1. 渐近线</h1><p>垂直渐近线（Vertical asymptote）和水平渐近线（Horizontal asymptote）是两种常见的渐近线类型。</p><h2 id="11-垂直渐近线"><a class="markdownIt-Anchor" href="#11-垂直渐近线"></a> 1.1 垂直渐近线</h2><p>垂直渐近线是函数图像在某个特定的<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi> x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span></span></span></span> 值附近无限接近但永远不会达到的垂直线，这通常发生在函数的分母为零、分子不为零的情况下。</p><p>例如函数 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mn>1</mn><mi>x</mi></mfrac></mrow><annotation encoding="application/x-tex">f (x) = \frac{1}{x}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span> 中，<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">x=0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span> 是一个垂直渐近线，因为当 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span></span></span></span> 无限接近 0 时，<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f (x)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span> 无限接近 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">∞</mi></mrow><annotation encoding="application/x-tex">\infty</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord">∞</span></span></span></span> （或 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>−</mo><mi mathvariant="normal">∞</mi></mrow><annotation encoding="application/x-tex">-\infty</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.66666em;vertical-align:-0.08333em;"></span><span class="mord">−</span><span class="mord">∞</span></span></span></span>，取决于 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span></span></span></span> 的正负、是从左边还是右边无限接近）。</p><h2 id="12-水平渐近线"><a class="markdownIt-Anchor" href="#12-水平渐近线"></a> 1.2 水平渐近线</h2><p>要找到水平渐近线，我们需要考虑函数在 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span></span></span></span> 值无限大或无限小时的行为。对于有理函数，你可以通过比较分子和分母的最高此项的次数来确定是否存在水平渐近线，以及它的位置在哪里：</p><ul><li>如果分子的最高次项的次数大于分母的最高次项的次数，那么函数没有水平渐近线；例如 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mrow><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><mn>1</mn></mrow><mi>x</mi></mfrac></mrow><annotation encoding="application/x-tex">f (x) = \frac{x^2+1}{x}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.36292em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.01792em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8913142857142857em;"><span style="top:-2.931em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mbin mtight">+</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></li><li>如果分子的最高次项的次数等于分母的最高次项的次数，那么函数有一个水平渐近线，它的值等于分子的最高次项的系数除以分母的最高次项的系数；例如 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mrow><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><mn>1</mn></mrow><msup><mi>x</mi><mn>2</mn></msup></mfrac></mrow><annotation encoding="application/x-tex">f (x) = \frac{x^2+1}{x^2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.36292em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.01792em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7463142857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8913142857142857em;"><span style="top:-2.931em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mbin mtight">+</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span>，水平渐近线的值是 1</li><li>如果分子的最高次项的次数小于分母的最高次项的次数，那么函数有一个水平渐近线，它的值等于 0；例如 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mrow><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><mn>1</mn></mrow><msup><mi>x</mi><mn>3</mn></msup></mfrac></mrow><annotation encoding="application/x-tex">f (x) = \frac{x^2+1}{x^3}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.36292em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.01792em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7463142857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">3</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8913142857142857em;"><span style="top:-2.931em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mbin mtight">+</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></li></ul><h1 id="2-导数"><a class="markdownIt-Anchor" href="#2-导数"></a> 2. 导数</h1><p>导数是函数在某一点的瞬时变化率，它的定义是函数在这一点的切线的斜率。导数的计算方法有很多，其中最常见的是使用极限的定义：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msup><mi>f</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><munder><mo><mi>lim</mi><mo>⁡</mo></mo><mrow><mi>h</mi><mo>→</mo><mn>0</mn></mrow></munder><mfrac><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo>+</mo><mi>h</mi><mo stretchy="false">)</mo><mo>−</mo><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><mi>h</mi></mfrac></mrow><annotation encoding="application/x-tex">f'(x) = \lim_{h \to 0} \frac{f(x+h)-f(x)}{h}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.051892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.801892em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.179108em;vertical-align:-0.7521079999999999em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.69444em;"><span style="top:-2.347892em;margin-left:0em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">h</span><span class="mrel mtight">→</span><span class="mord mtight">0</span></span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span><span class="mop">lim</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.7521079999999999em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">h</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathnormal">h</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p>这个定义的意思是，当 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>h</mi></mrow><annotation encoding="application/x-tex">h</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">h</span></span></span></span> 无限接近 0 时，函数在 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span></span></span></span> 点的瞬时变化率等于 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo>+</mo><mi>h</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f(x+h)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">h</span><span class="mclose">)</span></span></span></span> 和 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f(x)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span> 之间的变化量除以 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>h</mi></mrow><annotation encoding="application/x-tex">h</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">h</span></span></span></span>。</p><h2 id="21-导数的性质"><a class="markdownIt-Anchor" href="#21-导数的性质"></a> 2.1 导数的性质</h2><p>导数（Derivative）有很多有用的性质，其中最重要的是：</p><ul><li>导数可以用来判断函数的增减性：<ul><li>如果 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>f</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>&gt;</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">f'(x)&gt;0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span>，那么 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f(x)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span> 在 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span></span></span></span> 点是增加的</li><li>如果 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>f</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>&lt;</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">f'(x)&lt;0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span>，那么 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f(x)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span> 在 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span></span></span></span> 点是减少的</li><li>如果 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>f</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">f'(x)=0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span>，那么 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f(x)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span> 在 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span></span></span></span> 点是不变的</li></ul></li></ul><blockquote><p>一个圆的半径以每秒 3 英寸的速度增加。当半径为 5 英寸时，它的面积增长速度是多少（单位为平方英寸 / 秒）？</p><p>我们知道一个量（圆的半径）的变化速度，想要求另一个量（圆的面积）的变化速度。这是一个典型的导数问题，因为导数描述了一个量的变化速度。我们可以使用导数的定义来解决这个问题：</p><p>圆的面积 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span> 和半径 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi></mrow><annotation encoding="application/x-tex">r</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span></span></span></span> 之间的关系是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi><mo>=</mo><mi>π</mi><msup><mi>r</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">A = \pi r^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8141079999999999em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span>。我们知道半径 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi></mrow><annotation encoding="application/x-tex">r</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span></span></span></span> 随着时间 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>t</mi></mrow><annotation encoding="application/x-tex">t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.61508em;vertical-align:0em;"></span><span class="mord mathnormal">t</span></span></span></span> 的变化速度（即半径的导数）是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>3</mn></mrow><annotation encoding="application/x-tex">3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span></span></span></span> 英寸 / 秒，所以我们可以写出 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo><mo>=</mo><mn>5</mn><mo>+</mo><mn>3</mn><mi>t</mi></mrow><annotation encoding="application/x-tex">r(t) = 5 + 3t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">5</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span><span class="mord mathnormal">t</span></span></span></span>。我们想要求 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span> 随着时间的变化速度，也就是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mrow><mi>d</mi><mi>A</mi></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">\frac{dA}{dt}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">A</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span>。我们可以使用链式法则来解决这个问题：</p><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mrow><mi>d</mi><mi>A</mi></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac><mo>=</mo><mfrac><mrow><mi>d</mi><mi>A</mi></mrow><mrow><mi>d</mi><mi>r</mi></mrow></mfrac><mo>⋅</mo><mfrac><mrow><mi>d</mi><mi>r</mi></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">\frac{dA}{dt} = \frac{dA}{dr} \cdot \frac{dr}{dt}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">A</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight" style="margin-right:0.02778em;">r</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">A</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight" style="margin-right:0.02778em;">r</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></p><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi><mo>=</mo><mi>π</mi><msup><mi>r</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">A = \pi r^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8141079999999999em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span>，所以 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mrow><mi>d</mi><mi>A</mi></mrow><mrow><mi>d</mi><mi>r</mi></mrow></mfrac><mo>=</mo><mn>2</mn><mi>π</mi><mi>r</mi></mrow><annotation encoding="application/x-tex">\frac{dA}{dr} = 2\pi r</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight" style="margin-right:0.02778em;">r</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">A</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span></span></span></span>。</p><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mo>=</mo><mn>5</mn><mo>+</mo><mn>3</mn><mi>t</mi></mrow><annotation encoding="application/x-tex">r = 5 + 3t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">5</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span><span class="mord mathnormal">t</span></span></span></span>，所以 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mrow><mi>d</mi><mi>r</mi></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac><mo>=</mo><mn>3</mn></mrow><annotation encoding="application/x-tex">\frac{dr}{dt} = 3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight" style="margin-right:0.02778em;">r</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span></span></span></span>。</p><p>把这两个值代入上面的公式，我们得到：</p><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mrow><mi>d</mi><mi>A</mi></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac><mo>=</mo><mn>2</mn><mi>π</mi><mi>r</mi><mo>⋅</mo><mn>3</mn><mo>=</mo><mn>6</mn><mi>π</mi><mi>r</mi><mo>=</mo><mn>6</mn><mi>π</mi><mo stretchy="false">(</mo><mn>5</mn><mo>+</mo><mn>3</mn><mi>t</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\frac{dA}{dt} = 2\pi r \cdot 3 = 6\pi r = 6\pi (5 + 3t)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">A</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">6</span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">6</span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span><span class="mopen">(</span><span class="mord">5</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">3</span><span class="mord mathnormal">t</span><span class="mclose">)</span></span></span></span></p><p>当 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi><mo>=</mo><mn>5</mn></mrow><annotation encoding="application/x-tex">r = 5</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">5</span></span></span></span> 时，<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>t</mi><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">t = 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.61508em;vertical-align:0em;"></span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span>，所以 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mrow><mi>d</mi><mi>A</mi></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac><mo>=</mo><mn>6</mn><mi>π</mi><mo>⋅</mo><mn>5</mn><mo>=</mo><mn>30</mn><mi>π</mi></mrow><annotation encoding="application/x-tex">\frac{dA}{dt} = 6\pi \cdot 5 = 30\pi</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">A</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">6</span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">5</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span><span class="mord">0</span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span></span></span></span> 平方英寸 / 秒。</p></blockquote><blockquote><p>点 P 沿 x 轴以每秒 2 个单位的速度向右移动。当 P 位于（4,0）时，P 和（0,3）之间的距离增加的速度是多少？</p><p>点 P 的坐标随时间变化，即 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo><mo separator="true">,</mo><mn>0</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(x(t), 0)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord">0</span><span class="mclose">)</span></span></span></span>，其中 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">x(t)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">x</span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span></span></span></span> 是时间 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>t</mi></mrow><annotation encoding="application/x-tex">t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.61508em;vertical-align:0em;"></span><span class="mord mathnormal">t</span></span></span></span> 的函数，并且 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mrow><mi>d</mi><mi>x</mi></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac><mo>=</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">\frac{dx}{dt} = 2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">x</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span></span></span></span> （单位 / 秒）。</p><p>我们需要找到点 P 和点（0,3）之间的距离 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>D</mi></mrow><annotation encoding="application/x-tex">D</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span></span></span></span> 随时间 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>t</mi></mrow><annotation encoding="application/x-tex">t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.61508em;vertical-align:0em;"></span><span class="mord mathnormal">t</span></span></span></span> 的变化率，也就是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mrow><mi>d</mi><mi>D</mi></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">\frac{dD}{dt}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight" style="margin-right:0.02778em;">D</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span>。我们可以使用勾股定理来解决这个问题：</p><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>D</mi><mn>2</mn></msup><mo>=</mo><mo stretchy="false">(</mo><mi>x</mi><mo>−</mo><mn>0</mn><msup><mo stretchy="false">)</mo><mn>2</mn></msup><mo>+</mo><mo stretchy="false">(</mo><mn>0</mn><mo>−</mo><mn>3</mn><msup><mo stretchy="false">)</mo><mn>2</mn></msup><mo>=</mo><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><mn>9</mn></mrow><annotation encoding="application/x-tex">D^2 = (x-0)^2 + (0-3)^2 = x^2 + 9</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8141079999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.064108em;vertical-align:-0.25em;"></span><span class="mord">0</span><span class="mclose"><span class="mclose">)</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.064108em;vertical-align:-0.25em;"></span><span class="mord">3</span><span class="mclose"><span class="mclose">)</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.897438em;vertical-align:-0.08333em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">9</span></span></span></span></p><p>由于求的点 P 在（4,0)，所以 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>=</mo><mn>4</mn></mrow><annotation encoding="application/x-tex">x = 4</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">4</span></span></span></span>，得出 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>D</mi><mo>=</mo><mn>5</mn></mrow><annotation encoding="application/x-tex">D = 5</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">5</span></span></span></span>。</p><p>我们可以对上面的公式求导数，得到：</p><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mi>d</mi><mrow><mi>d</mi><mi>t</mi></mrow></mfrac><msup><mi>D</mi><mn>2</mn></msup><mo>=</mo><mfrac><mi>d</mi><mrow><mi>d</mi><mi>t</mi></mrow></mfrac><mo stretchy="false">(</mo><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><mn>9</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\frac{d}{dt} D^2 = \frac{d}{dt} (x^2 + 9)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">9</span><span class="mclose">)</span></span></span></span></p><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mi>D</mi><mo>⋅</mo><mfrac><mrow><mi>d</mi><mi>D</mi></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac><mo>=</mo><mn>2</mn><mi>x</mi><mo>⋅</mo><mfrac><mrow><mi>d</mi><mi>x</mi></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">2D \cdot \frac{dD}{dt} = 2x \cdot \frac{dx}{dt}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight" style="margin-right:0.02778em;">D</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">x</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></p><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mrow><mi>d</mi><mi>D</mi></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac><mo>=</mo><mfrac><mrow><mn>2</mn><mi>x</mi><mo>⋅</mo><mfrac><mrow><mi>d</mi><mi>x</mi></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac></mrow><mrow><mn>2</mn><mi>D</mi></mrow></mfrac><mo>=</mo><mfrac><mi>x</mi><mi>D</mi></mfrac><mo>⋅</mo><mfrac><mrow><mi>d</mi><mi>x</mi></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">\frac{dD}{dt} = \frac{2x \cdot \frac{dx}{dt}}{2D} = \frac{x}{D} \cdot \frac{dx}{dt}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight" style="margin-right:0.02778em;">D</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.51182em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.16682em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span><span class="mord mathnormal mtight" style="margin-right:0.02778em;">D</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.5508em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span><span class="mord mathnormal mtight">x</span><span class="mbin mtight">⋅</span><span class="mord mtight"><span class="mopen nulldelimiter sizing reset-size3 size6"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8800285714285714em;"><span style="top:-2.656em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.2255000000000003em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line mtight" style="border-bottom-width:0.049em;"></span></span><span style="top:-3.384em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">x</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.344em;"><span></span></span></span></span></span><span class="mclose nulldelimiter sizing reset-size3 size6"></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.040392em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.695392em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.02778em;">D</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">x</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></p><p>导入已知的值，我们得到：</p><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mrow><mi>d</mi><mi>D</mi></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac><mo>=</mo><mfrac><mn>4</mn><mn>5</mn></mfrac><mo>⋅</mo><mn>2</mn><mo>=</mo><mfrac><mn>8</mn><mn>5</mn></mfrac></mrow><annotation encoding="application/x-tex">\frac{dD}{dt} = \frac{4}{5} \cdot 2 = \frac{8}{5}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight" style="margin-right:0.02778em;">D</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">5</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">4</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">5</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">8</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></p></blockquote><h4 id="211-区间"><a class="markdownIt-Anchor" href="#211-区间"></a> 2.1.1. 区间</h4><p>一个函数在某个区间是增加的还是减少的，可以查看该区间的导数是正还是负。</p><p>如果函数 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>g</mi><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">g(t)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span></span></span></span> 的一阶导数在某个区间内大于 0，那么函数在该区间内是增加的；如果导数小于 0，那么函数在该区间内是减少的。</p><p>在一个闭区间内，函数的绝对最小值是该函数在该区间上取得的最小的函数值；绝对最大值同理。</p><h4 id="212-临界点"><a class="markdownIt-Anchor" href="#212-临界点"></a> 2.1.2. 临界点</h4><p>一个函数的临界点（Critical point）是指函数的导数等于 0 或不存在的点。临界点是函数的极值点的候选者，因为函数在极值点处的导数是 0。</p><h4 id="213-微分运算符"><a class="markdownIt-Anchor" href="#213-微分运算符"></a> 2.1.3. 微分运算符</h4><p>微分运算符 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mi>d</mi><mrow><mi>d</mi><mi>x</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">\frac{d}{dx}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">x</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span> 是一个用来表示对 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span></span></span></span> 的导数的运算符，它的作用是把一个函数变成它的导数。例如：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mfrac><mi>d</mi><mrow><mi>d</mi><mi>x</mi></mrow></mfrac><msup><mi>x</mi><mn>2</mn></msup><mo>=</mo><mn>2</mn><mi>x</mi></mrow><annotation encoding="application/x-tex">\frac{d}{dx} x^2 = 2x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.05744em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.37144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">d</span><span class="mord mathnormal">x</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">d</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord mathnormal">x</span></span></span></span></span></p><p>这意味着 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>x</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">x^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8141079999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span> 的导数是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mi>x</mi></mrow><annotation encoding="application/x-tex">2x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord mathnormal">x</span></span></span></span>，或者说，<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>x</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">x^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8141079999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span> 在任何点的瞬时变化率都是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn><mi>x</mi></mrow><annotation encoding="application/x-tex">2x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord mathnormal">x</span></span></span></span>。</p><blockquote><p>微分运算符公式：</p><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mi>d</mi><mrow><mi>d</mi><mi>x</mi></mrow></mfrac><msup><mi>x</mi><mi>n</mi></msup><mo>=</mo><mi>n</mi><msup><mi>x</mi><mrow><mi>n</mi><mo>−</mo><mn>1</mn></mrow></msup></mrow><annotation encoding="application/x-tex">\frac{d}{dx} x^n = nx^{n-1}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">x</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8141079999999999em;vertical-align:0em;"></span><span class="mord mathnormal">n</span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span><span class="mbin mtight">−</span><span class="mord mtight">1</span></span></span></span></span></span></span></span></span></span></span></span></p></blockquote><h2 id="22-切线"><a class="markdownIt-Anchor" href="#22-切线"></a> 2.2. 切线</h2><p>一个函数在某一点的导数描述了该函数在该点处的斜率，也就是说，它描述了函数在该点处的切线（Tangent line）。</p><p>具体来说，如果我们有一个函数 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f (x)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span>，并且我们知道它在 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>=</mo><mi>a</mi></mrow><annotation encoding="application/x-tex">x=a</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">a</span></span></span></span> 处的导数是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>f</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">(</mo><mi>a</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f'(a)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">a</span><span class="mclose">)</span></span></span></span>，那么我们可以使用点斜式来写出它在 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>=</mo><mi>a</mi></mrow><annotation encoding="application/x-tex">x=a</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">a</span></span></span></span> 处的切线方程：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>y</mi><mo>−</mo><msub><mi>y</mi><mn>1</mn></msub><mo>=</mo><mi>m</mi><mo stretchy="false">(</mo><mi>x</mi><mo>−</mo><msub><mi>x</mi><mn>1</mn></msub><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">y - y_1 = m(x - x_1)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7777700000000001em;vertical-align:-0.19444em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">m</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span></p><p>其中 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>m</mi></mrow><annotation encoding="application/x-tex">m</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">m</span></span></span></span> 是斜率，也就是导数 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>f</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">(</mo><mi>a</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f'(a)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">a</span><span class="mclose">)</span></span></span></span>；<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>x</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">x_1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 和 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>y</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">y_1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 是切线上的一个点，也就是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mi>a</mi><mo separator="true">,</mo><mi>f</mi><mo stretchy="false">(</mo><mi>a</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(a, f(a))</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal">a</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">a</span><span class="mclose">)</span><span class="mclose">)</span></span></span></span>。</p><h2 id="23-导数规则"><a class="markdownIt-Anchor" href="#23-导数规则"></a> 2.3. 导数规则</h2><p>导数有很多规则，其中最常见的是：</p><ul><li>积规则：<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mi>d</mi><mrow><mi>d</mi><mi>x</mi></mrow></mfrac><mo stretchy="false">(</mo><mi>u</mi><mi>v</mi><mo stretchy="false">)</mo><mo>=</mo><msup><mi>u</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mi>v</mi><mo>+</mo><mi>u</mi><msup><mi>v</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup></mrow><annotation encoding="application/x-tex">\frac{d}{dx} (uv) = u'v + uv'</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">x</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mopen">(</span><span class="mord mathnormal">u</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.835222em;vertical-align:-0.08333em;"></span><span class="mord"><span class="mord mathnormal">u</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.751892em;vertical-align:0em;"></span><span class="mord mathnormal">u</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span></span></span></span></li><li>商规则：<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mi>d</mi><mrow><mi>d</mi><mi>x</mi></mrow></mfrac><mfrac><mi>u</mi><mi>v</mi></mfrac><mo>=</mo><mfrac><mrow><msup><mi>u</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mi>v</mi><mo>−</mo><mi>u</mi><msup><mi>v</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup></mrow><msup><mi>v</mi><mn>2</mn></msup></mfrac></mrow><annotation encoding="application/x-tex">\frac{d}{dx} \frac{u}{v} = \frac{u'v - uv'}{v^2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">x</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.695392em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">u</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.31848em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.97348em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7463142857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight">u</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8278285714285715em;"><span style="top:-2.931em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span><span class="mbin mtight">−</span><span class="mord mathnormal mtight">u</span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8278285714285715em;"><span style="top:-2.931em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></li><li>链式法则：<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mi>d</mi><mrow><mi>d</mi><mi>x</mi></mrow></mfrac><mi>f</mi><mo stretchy="false">(</mo><mi>g</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo><mo>=</mo><msup><mi>f</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">(</mo><mi>g</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo><msup><mi>g</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\frac{d}{dx} f(g(x)) = f'(g(x))g'(x)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">x</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mclose">)</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span><ul><li>也可以是：<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mrow><mi>d</mi><mi>y</mi></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac><mo>=</mo><mfrac><mrow><mi>d</mi><mi>y</mi></mrow><mrow><mi>d</mi><mi>x</mi></mrow></mfrac><mo>⋅</mo><mfrac><mrow><mi>d</mi><mi>x</mi></mrow><mrow><mi>d</mi><mi>t</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">\frac{dy}{dt} = \frac{dy}{dx} \cdot \frac{dx}{dt}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.277216em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.9322159999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.446108em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight" style="margin-right:0.03588em;">y</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.277216em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.9322159999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">x</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.446108em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight" style="margin-right:0.03588em;">y</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">t</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">d</span><span class="mord mathnormal mtight">x</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></li></ul></li></ul><h2 id="24-高阶导数"><a class="markdownIt-Anchor" href="#24-高阶导数"></a> 2.4. 高阶导数</h2><p>高阶导数（Higher-order derivative）是指一个函数的导数的导数。例如，如果 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>f</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f'(x)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span> 是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f(x)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span> 的导数，那么 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>f</mi><mrow><mo mathvariant="normal">′</mo><mo mathvariant="normal">′</mo></mrow></msup><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f''(x)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span> 是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>f</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f'(x)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span> 的导数，也就是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f(x)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span> 的二阶导数。</p><p>在物理学中，高阶导数通常用来描述加速度、速度和位移之间的关系。例如，如果 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f(t)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span></span></span></span> 是一个物体的位移函数，那么 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>f</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f'(t)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span></span></span></span> 是速度函数，<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>f</mi><mrow><mo mathvariant="normal">′</mo><mo mathvariant="normal">′</mo></mrow></msup><mo stretchy="false">(</mo><mi>t</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f''(t)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">t</span><span class="mclose">)</span></span></span></span> 是加速度函数。</p><h2 id="25-实践"><a class="markdownIt-Anchor" href="#25-实践"></a> 2.5. 实践</h2><blockquote><p>Suppose f′(2) = 0 and f′′(2) &gt; 0. Which of the following statements is true?</p><p>a) f(2) must be a relative maximum of f</p><p>b) f(2) must be a relative minimum of f</p><p>c) f(2) must be a relative extremum of f, which could be a max or min</p><p>d) (2, f(2)) must be a point of inflection of f</p><p>e) Not enough information to know whether (2, f(2)) is a point of inflection</p></blockquote><p>首先 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>=</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">x = 2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span></span></span></span> 处函数的切线斜率（导数）为 0，这意味着 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>2</mn></mrow><annotation encoding="application/x-tex">2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span></span></span></span> 可能是函数的局部极大值或者局部极小值，或者可能是拐点。这是因为导数为零代表着函数在该点的切线是水平的，这通常发生在两种情况下：函数的山顶或谷底，或者函数的形状从上升到下降或者从下降到上升的地方。</p><p>再看第二个条件，<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>f</mi><mrow><mo mathvariant="normal">′</mo><mo mathvariant="normal">′</mo></mrow></msup><mo stretchy="false">(</mo><mn>2</mn><mo stretchy="false">)</mo><mo>&gt;</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">f''(2) &gt; 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord">2</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span>。基于第一个条件，我们知道 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>=</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">x = 2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span></span></span></span> 处的切线是水平的，所以 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>f</mi><mrow><mo mathvariant="normal">′</mo><mo mathvariant="normal">′</mo></mrow></msup><mo stretchy="false">(</mo><mn>2</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">f''(2)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord">2</span><span class="mclose">)</span></span></span></span> 的正负号告诉我们 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>=</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">x = 2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span></span></span></span> 处的函数是凹还是凸。因为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>f</mi><mrow><mo mathvariant="normal">′</mo><mo mathvariant="normal">′</mo></mrow></msup><mo stretchy="false">(</mo><mn>2</mn><mo stretchy="false">)</mo><mo>&gt;</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">f''(2) &gt; 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord">2</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span>，所以 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>=</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">x = 2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span></span></span></span> 处的函数是凹的，这意味着 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>=</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">x = 2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span></span></span></span> 处的函数是一个局部极小值。</p><blockquote><p>On which interval is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>g</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mn>1</mn><mi>x</mi></mfrac><mo>+</mo><mi>ln</mi><mo>⁡</mo><mi>x</mi></mrow><annotation encoding="application/x-tex">g(x) = \frac{1}{x} + \ln x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal">x</span></span></span></span> increasing?</p></blockquote><p>这个问题在询问函数 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>g</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">g(x)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span> 在哪个区间是呈现凹增的。函数的二阶导数告诉我们函数的凹凸性，如果函数的二阶导数大于 0，那么函数是凹的；如果函数的二阶导数小于 0，那么函数是凸的。</p><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mn>1</mn><mi>x</mi></mfrac></mrow><annotation encoding="application/x-tex">\frac{1}{x}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span> 的导数是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>−</mo><mfrac><mn>1</mn><msup><mi>x</mi><mn>2</mn></msup></mfrac></mrow><annotation encoding="application/x-tex">-\frac{1}{x^2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord">−</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7463142857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span>，<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ln</mi><mo>⁡</mo><mi>x</mi></mrow><annotation encoding="application/x-tex">\ln x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mop">ln</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal">x</span></span></span></span> 的导数是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mn>1</mn><mi>x</mi></mfrac></mrow><annotation encoding="application/x-tex">\frac{1}{x}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span>，所以 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>g</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><mo>−</mo><mfrac><mn>1</mn><msup><mi>x</mi><mn>2</mn></msup></mfrac><mo>+</mo><mfrac><mn>1</mn><mi>x</mi></mfrac></mrow><annotation encoding="application/x-tex">g'(x) = -\frac{1}{x^2} + \frac{1}{x}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord">−</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7463142857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span>。<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>g</mi><mrow><mo mathvariant="normal">′</mo><mo mathvariant="normal">′</mo></mrow></msup><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mn>2</mn><msup><mi>x</mi><mn>3</mn></msup></mfrac><mo>−</mo><mfrac><mn>1</mn><msup><mi>x</mi><mn>2</mn></msup></mfrac></mrow><annotation encoding="application/x-tex">g''(x) = \frac{2}{x^3} - \frac{1}{x^2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7463142857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">3</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7463142857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span>，所以 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>g</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">g(x)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span> 是凹的。</p><p>我们还要找出在哪个区间 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>g</mi><mrow><mo mathvariant="normal">′</mo><mo mathvariant="normal">′</mo></mrow></msup><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>&gt;</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">g''(x) &gt; 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span>，将 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>g</mi><mrow><mo mathvariant="normal">′</mo><mo mathvariant="normal">′</mo></mrow></msup><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">g''(x)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span></span></span></span> 替换成 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>0</mn></mrow><annotation encoding="application/x-tex">0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span>，算出 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>=</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">x=2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span></span></span></span>。</p><p>接下来我们要找出区间 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mn>0</mn><mo separator="true">,</mo><mn>2</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(0,2)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">0</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord">2</span><span class="mclose">)</span></span></span></span> 和 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mn>2</mn><mo separator="true">,</mo><mo>+</mo><mi mathvariant="normal">∞</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(2,+\infty)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">2</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord">+</span><span class="mord">∞</span><span class="mclose">)</span></span></span></span> 中具体哪里才是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>g</mi><mrow><mo mathvariant="normal">′</mo><mo mathvariant="normal">′</mo></mrow></msup><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>&gt;</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">g''(x) &gt; 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span>。</p><h2 id="26-应用"><a class="markdownIt-Anchor" href="#26-应用"></a> 2.6. 应用</h2><p>生产 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span></span></span></span> 个单位的产品的成本是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mrow><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><mn>30</mn><mi>x</mi><mo>+</mo><mn>72</mn></mrow><msqrt><mi>x</mi></msqrt></mfrac></mrow><annotation encoding="application/x-tex">C(x) = \frac{x^2+30x+72}{\sqrt{x}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.55592em;vertical-align:-0.538em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.01792em;"><span style="top:-2.6258665em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord sqrt mtight"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8059050000000001em;"><span class="svg-align" style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mtight" style="padding-left:0.833em;"><span class="mord mathnormal mtight">x</span></span></span><span style="top:-2.765905em;"><span class="pstrut" style="height:3em;"></span><span class="hide-tail mtight" style="min-width:0.853em;height:1.08em;"><svg width="400em" height="1.08em" viewBox="0 0 400000 1080" preserveAspectRatio="xMinYMin slice"><path d="M95,702c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429c69,-144,104.5,-217.7,106.5,-221l0 -0c5.3,-9.3,12,-14,20,-14H400000v40H845.2724s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47zM834 80h400000v40h-400000z"></path></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.234095em;"><span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8913142857142857em;"><span style="top:-2.931em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mbin mtight">+</span><span class="mord mtight">3</span><span class="mord mtight">0</span><span class="mord mathnormal mtight">x</span><span class="mbin mtight">+</span><span class="mord mtight">7</span><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.538em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span>，其中 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>≥</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">x \geq 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7719400000000001em;vertical-align:-0.13597em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">≥</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span>。求边际成本为 0 时的生产量。</p><p>在经济学中，边际成本（Marginal cost）是生产一个额外单位产品所需的额外成本。在微积分中，边际成本可以通过求生产成本函数的导数来得到。</p><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>C</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><mn>1.5</mn><msup><mi>x</mi><mrow><mo>−</mo><mn>1</mn><mi mathvariant="normal">/</mi><mn>2</mn></mrow></msup><mo stretchy="false">(</mo><mi>x</mi><mo>−</mo><mn>2</mn><mo stretchy="false">)</mo><mo stretchy="false">(</mo><mi>x</mi><mo>+</mo><mn>12</mn><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">C'(x) = 1.5x^{-1/2} (x-2) (x+12)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.138em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mord">.</span><span class="mord">5</span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8879999999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">−</span><span class="mord mtight">1</span><span class="mord mtight">/</span><span class="mord mtight">2</span></span></span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">2</span><span class="mclose">)</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mord">2</span><span class="mclose">)</span></span></span></span></p><p>因为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span></span></span></span> 不能为负数，所以 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi><mo>=</mo><mn>2</mn></mrow><annotation encoding="application/x-tex">x=2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span></span></span></span> 是边际成本为 0 时的生产量。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;微积分笔记，仅作为个人学习记录，不保证正确性。&lt;/p&gt;</summary>
    
    
    
    <category term="学术笔记" scheme="https://blog.cytrogen.icu/categories/%E5%AD%A6%E6%9C%AF%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="大学课程" scheme="https://blog.cytrogen.icu/tags/%E5%A4%A7%E5%AD%A6%E8%AF%BE%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>IBM 全栈开发【6】：容器 &amp; Kubernetes 和 OpenShift 简介</title>
    <link href="https://blog.cytrogen.icu/posts/eb2a.html"/>
    <id>https://blog.cytrogen.icu/posts/eb2a.html</id>
    <published>2024-03-12T02:48:00.000Z</published>
    <updated>2026-02-09T17:16:54.717Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程，故此记录学习笔记。</p><span id="more"></span><p>在现代软件开发中，容器技术已经成为了一种必备的技术。它们通过提供一种轻量级、可移植且独立于平台的方式来封装和运行应用程序，解决了许多传统软件开发和部署过程中的问题。</p><h1 id="1-容器和容器化"><a class="markdownIt-Anchor" href="#1-容器和容器化"></a> 1. 容器和容器化</h1><p>尽管容器化（Containerization）并非全新的技术概念，但直到 2013 年 —— 随着 Docker 的出现 —— 它才开始引起人们的广泛关注并迅速成长。如今，容器已经成为现代云原生（Cloud Native）开发的核心技术之一。</p><p>容器技术解决了长期困扰软件开发的一个重要问题：软件的可移植性。它使得应用程序能在多种不同的平台上无缝运行。</p><p>容器是由容器化引擎支持的标准软件单元，它封装了应用程序代码、运行时环境（Runtime）、系统工具，以及开发者构建、发布和运行应用程序所需的所有设置。由于容器的体积小巧，开发者可以在几乎无需等待的情况下，立即开始容器化他们的应用程序。</p><p>在传统的软件开发环境中，开发人员往往难以有效地隔离应用程序，也无法为物理服务器上的应用程序指定或分配特定的存储和内存资源。这导致服务器的资源往往被未充分利用或过度利用，从而降低了效率并减少了投资的回报。</p><p>此外，传统的部署方式需要对资源进行全面的配置，并且维护成本高昂。物理服务器的限制可能会在高峰工作负载期间影响应用程序的性能。容器技术通过虚拟化操作系统并管理容器的运行，有效地解决了这些问题。</p><h2 id="11-容器引擎"><a class="markdownIt-Anchor" href="#11-容器引擎"></a> 1.1. 容器引擎</h2><p>容器引擎提供了运行和管理容器的基础设施。这些引擎使得容器能够独立于平台、操作系统、编程语言和 IDE 运行，降低了部署时间和成本，提高了资源利用率，并实现了跨不同环境的端口。</p><ul><li>Docker：最流行的容器引擎，它提供了一种轻量级的、可移植的、自包含的容器化解决方案。Docker 容器可以在任何地方运行，无论是开发人员的笔记本电脑、数据中心的物理服务器，还是云服务提供商的虚拟机</li><li>Podman：开源的容器引擎，它提供了一个简单的命令行界面，用于管理容器和镜像。Podman 可以在不需要守护进程的情况下运行容器，这使得它更适合于在生产环境中使用、对比 Docker 更安全</li><li>LXC：Linux 容器（Linux Containers，LXC），一个操作系统级的虚拟化技术，它允许多个 Linux 系统共享同一个内核。LXC 适合进行数据密集型应用程序的测试和开发</li><li>Vagrant：开源的虚拟化工具，它在正在运行的物理机上提供更高级别的隔离</li></ul><h2 id="12-docker"><a class="markdownIt-Anchor" href="#12-docker"></a> 1.2. Docker</h2><p>Docker 是目前最流行的容器平台：</p><ul><li>它是一个开发平台，用于以容器形式开发、发布和运行应用程序</li><li>架构简单，具有巨大的可扩展性和可移植性，得到了开发者的欢迎</li><li>将应用程序和基础设施隔离，包括硬件、操作系统和容器运行时</li><li>使用 Go 语言编写，利用 Linux 内核特性提供其功能，并使用命名空间来提供称为容器的隔离工作区</li><li>为每个容器创建一组命名空间</li></ul><p>Docker 通过提供一致且隔离的环境实现稳定的应用程序部署，部署快速：</p><ul><li>镜像小且可重用</li><li>自动化功能有助于消除错误，简化维护周期，并支持敏捷和 CI / CD DevOps 实践</li><li>简单版本控制可以加快测试、回滚和重新部署的速度</li><li>有助于对应用程序进行分段，以便于刷新、清理和修复</li></ul><p>Docker 激发了更多的创新，例如：</p><ul><li>Docker CLI：Docker 命令行界面</li><li>Docker Compose：用于定义和运行多容器 Docker 应用程序的工具</li><li>Prometheus：用于监控和警报的开源系统</li><li>Docker Swarm 或者 Kubernetes 的编排技术</li><li>使用微服务和 Serverless 的开发方式</li></ul><p>然而，Docker 并不适合所有的应用场景。例如，对于需要高性能或安全性、基于 Monolith、需要丰富 GUI 功能、或者执行标准桌面或有限功能的应用程序，就可能不适合使用 Docker。</p><h4 id="121-docker的工作流程"><a class="markdownIt-Anchor" href="#121-docker的工作流程"></a> 1.2.1. Docker 的工作流程</h4><p>在 Docker 中，开发者首先创建一个 Dockerfile，然后使用 Dockerfile 创建容器镜像，最后使用容器镜像创建正在运行的容器。</p><p>Dockerfile 中的 <code>FROM</code> 命令用于定义基础镜像，<code>CMD</code> 命令用于定义容器启动后需要执行的命令。</p><pre><code class="language-dockerfile">FROM nginx:latestCMD ["nginx", "-g", "daemon off;"]</code></pre><blockquote><p>以上 Dockerfile 用于创建一个基于 Nginx 的容器镜像，它使用了 <code>nginx:latest</code> 作为基础镜像，并在容器启动后执行 <code>nginx -g daemon off;</code> 命令、也就是启动 Nginx 服务</p></blockquote><p>Docker 提供了一套命令行工具，用于管理容器和镜像：</p><ul><li><code>docker build -t my-app:v1 .</code> 命令用于使用 Dockerfile 中的标签创建容器镜像<ul><li><code>-t</code> 参数用于指定镜像的标签</li><li><code>.</code> 参数用于指定 Dockerfile 所在的目录</li><li><code>my-app:v1</code> 用于指定镜像的名称和版本</li></ul></li><li><code>docker run -p 8080:80 nginx</code> 命令用于从镜像创建并运行容器<ul><li><code>-p</code> 参数用于指定容器端口和主机端口的映射</li><li><code>nginx</code> 用于指定容器镜像的名称</li><li><code>8080:80</code> 用于指定主机端口和容器端口的映射</li></ul></li><li><code>docker push my-app:v1</code> 命令用于将镜像存储在配置的注册表中</li><li><code>docker pull nginx</code> 命令用于从配置的注册表中检索镜像</li></ul><p>Docker 主机包含了 Dockerfile、镜像（Image）、容器、网络（Network）、存储卷（Storage）等对象，以及其他的插件和附加组件。其中，网络用于隔离容器通信，存储卷（Volume）和绑定挂载（Bind mount）用于在容器停止运行后保留数据。</p><p>Docker 的工作原理如下：</p><ol><li>用户通过 Docker 命令行接口（CLI）或 Docker 的 REST API 客户端向 Docker 主机服务器（Host）发送指令</li><li>Docker 主机内部运行着一个被称为 dockerd 的守护进程</li><li>守护进程负责监听并处理来自 Docker API 的请求或命令</li><li>守护进程承担了构建、运行和分发 Docker 容器的重要任务</li><li>Docker 将构建好的容器镜像存储在注册表（Registry）中，以便于后续的提取和运行</li></ol><h4 id="122-docker的客户端-服务器架构"><a class="markdownIt-Anchor" href="#122-docker的客户端-服务器架构"></a> 1.2.2. Docker 的客户端 - 服务器架构</h4><p>Docker 客户端具有与本地或远程的 Docker 主机进行通信的能力。</p><p>在一个系统上，Docker 客户端和 Docker 守护进程可以同时运行，或者 Docker 客户端可以连接到远程的 Docker 守护进程进行操作。同时，Docker 守护进程也能与其他守护进程进行交互，以共同管理 Docker 服务。</p><p>Docker 利用注册表来存储和分发镜像。这些注册表可以是公开的，如 Docker Hub，也可以是私有的。注册表的托管位置可以由第三方供应商提供，或者在私有数据中心或云环境中自我托管。</p><p>将镜像推送到注册表的过程如下：</p><ol><li>开发人员首先构建镜像，然后将其推送到注册表。这个过程可以手动执行，也可以通过自动化构建管道实现。在这个过程中，Docker 将这些镜像存储在注册表中</li><li>之后，本地计算机、云系统或其他本地系统就可以从注册表中拉取这些镜像进行使用</li></ol><h1 id="2-kubernetes基础"><a class="markdownIt-Anchor" href="#2-kubernetes基础"></a> 2. Kubernetes 基础</h1><p>每个人的容器之旅都是从一个容器开始的。然而，随着时间的推移，新的应用程序被编写出来，项目被部署到全球范围内以增加可用性。最初的一个容器不可避免地会变成多个容器。此时，我们需要考虑如何将数百或数千个容器连接、管理和扩展为一个大型应用程序，例如数据库或 Web 应用程序。为了创建、扩展和管理大量容器，容器编排（Container orchestration）是必要的。</p><p>容器编排是一种自动化容器管理的方法，它可以帮助开发人员和系统管理员在大规模容器环境中管理容器。容器编排系统可以自动化容器的部署、扩展、管理和运行，从而简化了容器的管理和维护。</p><p>在大型动态环境中，容器编排是必不可少的：</p><ul><li>简化复杂性，自动化复杂的管理、协调任务</li><li>无需人工干预的部署和扩展</li><li>提高我们的开发速度、敏捷性和效率，无缝地集成到我们的 CI / CD 工作流程和 DevOps 实践中</li></ul><p>容器编排使用以 YAML 或 JSON 格式编写的配置文件来定义容器的部署、扩展和管理。这些配置文件可以用于定义容器的资源、网络、存储、服务发现、负载均衡、监控和日志记录等方面。</p><p>容器编排工具有：</p><ul><li>Marathon：Apache Mesos 的一个框架，是一个开源的集群管理器，允许通过自动化管理和监控来扩展容器的基础设施任务</li><li>Nomad：HashiCorp 的一个开源的集群管理和调度工具，支持 Docker 和其他容器化工作负载</li><li>Docker Swarm：Docker 的一个编排工具，它允许用户在 Docker 主机上运行和管理多个容器；经过专业设计，它可以与 Docker Engine 无缝集成</li><li>Kubernetes：Google 开源的容器编排工具，它提供了一种自动化容器部署、扩展和操作的平台，支持多个云环境；因其广泛的社区支持和丰富的功能，Kubernetes 已经成为了最流行的容器编排工具</li></ul><h2 id="21-kubernetes"><a class="markdownIt-Anchor" href="#21-kubernetes"></a> 2.1. Kubernetes</h2><p>Kubernetes 被官方描述为一个开源系统，用于自动化容器化应用程序的部署、扩展和操作。它是由 Google 设计并捐赠给 Cloud Native Computing Foundation（CNCF）的，它促进了声明式管理、自动化部署、自我修复、水平扩展和服务发现等功能。</p><p>Kubernetes 的主要概念是：</p><ul><li>Pod：Kubernetes 中最小的部署单元，它是一个或多个容器的集合，它们共享网络和存储资源<ul><li>每个 Pod 都有一个唯一的 IP 地址，它们可以通过这个 IP 地址进行通信</li></ul></li><li>服务：一组 Pod 的抽象概念，它们共享一个策略，定义了如何访问这些 Pod<ul><li>一组具有相同 Service 的 Pod 会有一个共享的 DNS 名称</li></ul></li><li>Persistent Volume（持久卷）：Kubernetes 提供的持久存储</li><li>资源配置：决定了 Pod 的资源使用情况，包括 CPU、内存、存储等</li><li>安全措施：保护云原生工作负载</li><li>调度和驱逐：资源紧张的情况下，Kubernetes 的调度器可以决定在哪个 Node 上启动 Pod，或者在需要的时候驱逐（Evict）Pod<ul><li>Kubernetes 还支持抢占（Preemption），即在资源紧张的情况下，可以终止优先级较低的 Pod，以便优先级较高的 Pod 可以运行</li></ul></li><li>集群管理：Kubernetes 提供了一系列的工具和资源，用于管理集群的状态和配置</li></ul><h4 id="211-kubernetes生态系统"><a class="markdownIt-Anchor" href="#211-kubernetes生态系统"></a> 2.1.1. Kubernetes 生态系统</h4><p>在容器化应用程序的生态系统中，除了 Kubernetes 这样的容器编排工具外，还需要一些其他的工具来完成各种任务：</p><ul><li>构建容器镜像</li><li>容器注册表</li><li>应用程序日志记录和监控</li><li>持续集成/持续部署（CI/CD）</li></ul><p>在 Kubernetes 生态系统中，有许多不同类型的提供商都在为这个生态系统做出贡献。这些提供商包括：</p><ul><li><p>公共云提供商如 Prisma、IBM、Google 和 AWS 提供了 Kubernetes 服务，使得用户可以在他们的云平台上轻松部署和管理 Kubernetes 集群。这些公共云提供商通常会提供一些附加的服务，如托管的数据库服务、存储服务和网络服务，以支持 Kubernetes 的运行</p></li><li><p>开源框架提供商如 Red Hat、VMWare、SUSE、Mesosphere 和 Docker 提供了一些开源的 Kubernetes 发行版，这些发行版包含了一些额外的功能，如更强大的网络插件、存储插件和安全插件，以满足特定的企业需求</p></li><li><p>管理提供商如 Digital Ocean、Ioodse、SUPERGIANT、CloudSoft、Turbonomic、Techtonic 和 Weaverworks 提供了一些工具和服务，以帮助用户更轻松地管理 Kubernetes 集群。这些工具和服务可以帮助用户自动化一些常见的管理任务，如集群的创建和删除、节点的添加和移除、以及应用的部署和更新</p></li><li><p>工具提供商如 Jfrog、Univa、Aspen Mesh、Bitnami 和 Cloud 66 提供了一些工具，以帮助用户更轻松地使用 Kubernetes。这些工具包括容器镜像构建工具、CI / CD 工具、网络插件、存储插件等</p></li><li><p>监控和日志记录提供商如 Sumo Logic、DATADOG、New Relic、Iguazio、Grafana、SignalFX、Sysdig 和 Dynatrace 提供了一些工具和服务，以帮助用户收集和分析 Kubernetes 集群的日志和性能指标</p></li><li><p>安全提供商如 GUARDCORE、BLACKDUCK、Yubico、Cilium、Aqua、Twistlock 和 Alcide 提供了一些工具和服务，以帮助用户保护 Kubernetes 集群的安全。这些工具和服务可以帮助用户防止未经授权的访问，以及检测和防止安全威胁</p></li><li><p>负载平衡提供商如 AVI Networks、VMWare 和 NGiNX 提供了一些工具和服务，以帮助用户在 Kubernetes 集群中实现负载均衡。这些工具和服务可以帮助用户在多个 Pod 或 Node 之间分配流量，以实现高可用性和伸缩性</p></li></ul><h4 id="212-kubernetes系统的主要组件"><a class="markdownIt-Anchor" href="#212-kubernetes系统的主要组件"></a> 2.1.2. Kubernetes 系统的主要组件</h4><p>Kubernetes 系统由一系列的组件构成，这些组件共同协作，以管理和运行容器化应用程序。以下是 Kubernetes 系统的主要组件：</p><ul><li><p>集群（Cluster）：这是运行容器化应用程序的节点（Node）集群。每个集群都由一个主节点（也称为控制面板）和一个或多个工作节点组成</p></li><li><p>控制面板（Control Plane）：控制面板维护着集群的预期状态。它负责调度和启动新的应用程序，监控应用程序的运行状态，以及在应用程序出现问题时进行自动恢复</p></li><li><p>节点（Node）：节点是运行应用程序的工作机器，它可以是虚拟机或物理机。每个节点都由控制面板管理，并运行着 Kubernetes 的一些组件，如 kubelet 和 kube-proxy</p></li><li><p>API 服务器（API Server）：API 服务器公开了 Kubernetes API，它是控制面板的前端，所有的集群通信都通过这个 API 进行</p></li><li><p>etcd：etcd 是一个高可用的分布式键值存储系统，它存储了集群的所有配置数据，定义了集群的状态</p></li><li><p>调度器（Scheduler）：调度器负责将新创建的 Pod 分配给节点。它会根据各种调度策略，如资源需求、硬件/软件/策略约束、亲和性和反亲和性规格、数据位置等，选择一个最适合的节点</p></li><li><p>控制器管理器（Controller Manager）：控制器管理器运行所有的控制器进程，包括节点控制器、复制控制器、端点控制器、服务账户和令牌控制器等。它持续监控集群的状态，并确保实际状态与预期状态一致</p></li><li><p>云控制器管理器（Cloud Controller Manager）：云控制器管理器运行与底层云服务商交互的控制器，将集群链接到云提供商的 API 中</p></li><li><p>Pod：Pod 是 Kubernetes 的最小部署单元，每个 Pod 包含一个或多个紧密相关的容器。这些容器共享相同的网络命名空间，可以通过 localhost 互相通信</p></li><li><p>kubelet：kubelet 是工作节点上最重要的组件，它与 API 服务器通信，接收新的和修改的 Pod 规范，并确保 Pod 及其关联的容器按需运行</p></li><li><p>容器运行时（Container Runtime）：容器运行时是负责运行容器的软件。它提供了容器的可插拔性，也就是说，你可以选择使用 Docker、containerd、CRI - O 或其他兼容 Kubernetes 的容器运行时</p></li><li><p>kube-proxy：kube-proxy 是一个在集群中每个节点上运行的网络代理，它维护网络规则，使得从网络外部访问 Pod 的请求可以正确路由到目标 Pod，同时也实现了服务的负载均衡</p></li></ul><h4 id="213-kubernetes对象"><a class="markdownIt-Anchor" href="#213-kubernetes对象"></a> 2.1.3. Kubernetes 对象</h4><p>在 Kubernetes 中，对象是一种持久化的实体，它表示了 Kubernetes 集群中的一种状态。这些对象包括 Pod、Service、Volume、Namespace 等，它们定义了你在集群中运行的应用程序、应用程序可用的资源、应用程序的行为方式（如重启策略）、以及应用程序应该如何处理更新。</p><p>Kubernetes 对象由两个主要字段构成：规范（Spec）和状态（Status）。规范描述了对象的期望状态，这是由用户提供的。状态描述了对象的当前状态，这是由 Kubernetes 系统提供的。</p><p>要使用 Kubernetes 对象，你可以直接使用 Kubernetes API，或者使用 kubectl 命令行界面，或者两者结合使用。例如，你可以使用 <code>kubectl create</code> 命令来创建一个新的对象，或者使用 <code>kubectl get</code> 命令来查看对象的状态。</p><p>标签（Labels）是附加到 Kubernetes 对象上的键值对，用于识别和组织对象。一个对象可以有多个标签，而且多个对象可以有相同的标签。这使得你可以轻松地组织和选择你的对象。标签选择器（Label Selectors）是 Kubernetes 中的一种核心分组机制，它允许你根据标签来选择一组对象。</p><p>命名空间（Namespace）在 Kubernetes 中提供了一种资源隔离的机制。一个 Kubernetes 集群可以包含多个命名空间，每个命名空间代表了集群中的一个逻辑分区。你可以在不同的命名空间中运行不同的应用程序，这些应用程序的资源是彼此隔离的。这使得你可以在一个集群中运行多个独立的应用程序，而不需要担心它们会相互干扰。</p><p>YAML 文件可以定义要创建的对象。例如我们来定义一个简单的 Pod：</p><pre><code class="language-yaml">apiVersion: v1kind: Podmetadata:  name: nginxspec:  containers:  - name: nginx    image: nginx:1.7.9    ports:    - containerPort: 80</code></pre><p>ReplicaSet 是 Pod 的一组副本，它确保指定数量的 Pod 副本在任何时间都是可用的。例如我们来定义一个简单的 ReplicaSet：</p><pre><code class="language-yaml">apiVersion: apps/v1kind: ReplicaSetmetadata:  name: nginx-replicaset  labels:    app: nginxspec:  replicas: 3  selector:    matchLabels:      app: nginx  template:    metadata:      labels:        app: nginx      specs:        containers:        - name: nginx          image: nginx:1.7.9          ports:          - containerPort: 80</code></pre><p>ReplicaSet 其实并不建议直接创建，而是通过 Deployment 来创建。Deployment 是 ReplicaSet 的一种控制器，它提供了一种声明式的方式来管理 Pod 的副本。例如我们来定义一个简单的 Deployment：</p><pre><code class="language-yaml">apiVersion: apps/v1kind: Deploymentmetadata:  name: nginx-deployment  labels:    app: nginxspec:  replicas: 3  selector:    matchLabels:      app: nginx  template:    metadata:      labels:        app: nginx    spec:        containers:        - name: nginx          image: nginx:1.7.9          ports:          - containerPort: 80</code></pre><p>对比 ReplicaSet，Deployment 提供了一个关键功能：滚动更新。滚动更新是指在不中断服务的情况下，逐步更新 Pod 的副本。这样可以确保应用程序在更新过程中保持可用性。</p><p>Deployment 适合无状态的应用程序，而 StatefulSet 适合有状态的应用程序。StatefulSet 是 Pod 的一组有序的副本，它确保每个 Pod 副本都有唯一的标识符和稳定的网络标识符。</p><p>Service 是一个 REST 对象，它定义了一组 Pod 的访问策略。Service 可以通过标签选择器来选择一组 Pod，然后通过 Service 的 IP 地址和端口号来访问这些 Pod。Service 有四种类型：ClusterIP、NodePort、ExternalLoadBalancer 和 ExternalName。</p><ul><li>ClusterIP：Service 的默认类型，它将 Service 暴露为集群内部的 IP 地址</li><li>NodePort：在静态端口上暴露 Service，这样就可以通过 Node 的 IP 地址和静态端口来访问 Service；不建议在生产环境中使用 NodePort</li><li>ExternalLoadBalancer（又称 ELB）：自动将流量引导到 NodePort</li><li>ExternalName：将 Service 映射到外部的 DNS 名称</li></ul><p>Ingress 是一个 API 对象，它定义了一组 HTTP 和 HTTPS 路由规则，用于将外部流量引导到集群内部的 Service。Ingress 可以提供负载均衡、SSL 终止、主机名基于路由、路径基于路由等功能。</p><p>DaemonSet 是一个确保每个 Node 上都运行一个 Pod 的控制器。它通常用于运行一些系统级的服务，如日志收集器、监控代理、网络代理等。</p><p>Job 是一个确保 Pod 成功运行一次的控制器。它通常用于运行一些独立的任务，如数据备份、数据迁移、数据处理等。如果 Pod 失败，Job 会自动重试，直到 Pod 成功运行。</p><ul><li>aCronJob 是一个确保 Pod 周期性运行的控制器</li></ul><h2 id="22-kubectl命令行工具"><a class="markdownIt-Anchor" href="#22-kubectl命令行工具"></a> 2.2. kubectl 命令行工具</h2><p>kubectl 是 Kubernetes 的命令行工具，它允许你与 Kubernetes 集群进行交互。kubectl 可以用于创建、删除、更新、查看和监控 Kubernetes 对象。</p><p>kubectl 命令类型有：</p><ul><li>命令式命令（Imperative Commands）</li><li>命令式对象配置（Imperative Object Configuration）</li><li>声明式对象配置（Declarative Object Configuration）</li></ul><h4 id="221-命令式命令"><a class="markdownIt-Anchor" href="#221-命令式命令"></a> 2.2.1. 命令式命令</h4><p>命令式命令是一种直接操作 Kubernetes 对象的方式。例如，你可以使用 <code>kubectl run</code> 命令来创建一个新的 Pod：</p><pre><code class="language-bash">kubectl run nginx --image nginx</code></pre><ul><li>适合用于开发和测试环境，但不适合用于生产环境</li><li>并不灵活，选项相当有限</li><li>持久性差，不容易追踪和管理</li><li>不易于在团队中共享和协作</li></ul><h4 id="222-命令式对象配置"><a class="markdownIt-Anchor" href="#222-命令式对象配置"></a> 2.2.2. 命令式对象配置</h4><p>命令式对象配置是一种指定必需的操作、参数和选项来创建 Kubernetes 对象的方式。例如，你可以使用 <code>kubectl create</code> 命令来创建一个新的 Pod：</p><pre><code class="language-bash">kubectl create -f nginx.yaml</code></pre><ul><li>多个环境中使用相同的配置文件将产生相同的结果</li><li>对比命令式命令结构更清晰，更易于维护</li><li>可重用也可共享</li><li>状态管理不易，需要手动维护</li><li>如果需要管理多个对象，使用命令式对象配置会变得非常复杂</li></ul><h4 id="223-声明式对象配置"><a class="markdownIt-Anchor" href="#223-声明式对象配置"></a> 2.2.3. 声明式对象配置</h4><p>声明式对象配置是一种将配置数据存储在文件中，然后使用 <code>kubectl apply</code> 命令来应用这些配置数据的方式。操作由 kubectl 自动完成，而不是由用户手动完成：</p><pre><code class="language-bash">kubectl apply -f nginx/</code></pre><ul><li>声明式对象配置关注状态而非操作，用户只需要描述所需的最终状态</li><li>可以轻松地在多个环境中共享和重用</li><li>学习曲线较陡，需要一定的学习成本</li><li>适合用于生产环境</li><li>调试和故障排除较为困难</li></ul><h1 id="3-使用kubernetes管理应用"><a class="markdownIt-Anchor" href="#3-使用kubernetes管理应用"></a> 3. 使用 Kubernetes 管理应用</h1><h2 id="31-replicaset"><a class="markdownIt-Anchor" href="#31-replicaset"></a> 3.1. ReplicaSet</h2><p>ReplicaSet 是 Kubernetes 中的一个控制器，它确保指定数量的 Pod 副本在任何时间都是可用的。ReplicaSet 使用标签选择器来选择一组 Pod，并确保这些 Pod 的副本数量与指定的数量一致。</p><p>ReplicaSet 总是尝试将指定数量的 Pod 副本保持在运行状态。如果有 Pod 失败，ReplicaSet 会自动创建新的 Pod 副本来替换它。如果有 Pod 副本数量超过指定数量，ReplicaSet 会自动删除多余的 Pod 副本。</p><h2 id="32-自动扩展器"><a class="markdownIt-Anchor" href="#32-自动扩展器"></a> 3.2. 自动扩展器</h2><p>Kubernetes 中的自动扩展器（Autoscaler）是一个控制器，它根据 CPU 利用率或自定义指标自动调整 Pod 的副本数量。</p><ol><li><p>水平自动扩展器（Horizontal Pod Autoscaler，HPA）根据 CPU 利用率自动调整 Pod 的副本数量。</p></li><li><p>垂直自动扩展器（Vertical Pod Autoscaler，VPA）根据内存利用率自动调整 Pod 的资源请求和限制。</p></li><li><p>集群自动扩展器（Cluster Autoscaler）根据节点资源利用率自动调整节点的数量。</p></li></ol><h2 id="33-滚动更新"><a class="markdownIt-Anchor" href="#33-滚动更新"></a> 3.3. 滚动更新</h2><p>滚动更新是指在不中断服务的情况下，逐步更新 Pod 的副本。滚动更新可以确保应用程序在更新过程中保持可用性。</p><p>滚动更新有两种策略：滚动更新和重启更新。滚动更新是逐步替换旧的 Pod 副本，而重启更新是一次性重启所有的 Pod 副本。</p><h2 id="34-configmaps"><a class="markdownIt-Anchor" href="#34-configmaps"></a> 3.4. ConfigMaps</h2><p>ConfigMaps 是 Kubernetes 中的一种对象，它用于存储配置数据。ConfigMaps 可以存储任意类型的配置数据，如环境变量、配置文件、命令行参数等。</p><p>ConfigMaps 可以通过两种方式使用：直接注入到 Pod 中，或者通过卷挂载到 Pod 中。</p><p>这些配置数据可以在 Pod 中使用，以便应用程序可以访问它们。</p><h2 id="35-secrets"><a class="markdownIt-Anchor" href="#35-secrets"></a> 3.5. Secrets</h2><p>Secrets 相对于 ConfigMaps，它是一种更安全的存储机制，用于存储敏感数据，如密码、密钥、证书等。</p><h1 id="4-kubernetes生态系统openshift-istio等"><a class="markdownIt-Anchor" href="#4-kubernetes生态系统openshift-istio等"></a> 4. Kubernetes 生态系统：OpenShift、Istio 等</h1><h2 id="41-red-hat-openshift"><a class="markdownIt-Anchor" href="#41-red-hat-openshift"></a> 4.1. Red Hat OpenShift</h2><p>Kubernetes 和 OpenShift 都是容器编排平台，后者是专门为开放式混合云端构建的企业级 Kubernetes 容器平台。</p><p>OpenShift 运行在 Kubernetes 集群上，对象数据被存储在 etcd 中，使用 Kubernetes API 进行通信。OpenShift 提供了一些额外的功能，如构建、部署、监控、日志记录、安全性、网络、存储、服务发现、负载均衡等。</p><p>OpenShift 也和 Jenkins 集成，具有更多的服务和功能。</p><h2 id="42-构建"><a class="markdownIt-Anchor" href="#42-构建"></a> 4.2. 构建</h2><p>构建（build）是将输入转换成对象的过程，构建输入包括内联 Dockerfile 定义，以及从图片、Git 仓库、二进制文件等提取出的内容。</p><p>ImageStream 是 OpenShift 中引用容器镜像的一个抽象。它可以引用一个或多个镜像，以及一个或多个标签。ImageStream 还可以引用一个或多个构建配置，以及一个或多个构建。</p><p>Webhook、图像更改或配置更改都可以触发构建。常见的构建策略包括 Source-to-Image（S2I）构建、Dockerfile 构建、Pipeline 构建等。</p><p>构建需要一个构建配置（BuildConfig）来定义构建的策略和参数。构建配置可以定义构建触发器、构建策略、构建输出、构建环境等。</p><h2 id="43-crd"><a class="markdownIt-Anchor" href="#43-crd"></a> 4.3. CRD</h2><p>自定义资源定义（Custom Resource Definition，CRD）是 Kubernetes 中的一种机制，它允许用户定义自己的资源类型。CRD 可以用于定义新的资源类型，如 Pod、Service、ReplicaSet 等。</p><p>CRD 扩展了 Kubernetes API。与自定义控制器配合使用的话可以在 Kubernetes 中创建新的声明式 API。</p><p>Operator 使用 CRD 和自定义控制器来自动化集群任务。Operator Framework 涵盖了编码、测试、交付和更新。</p><p>Operator Maturity Model（OMM）是一个用于评估 Operator 的成熟度的模型。OMM 包括五个阶段：初始、基本、稳定、成熟和退休。</p><h2 id="44-istio"><a class="markdownIt-Anchor" href="#44-istio"></a> 4.4. Istio</h2><p>Istio 是一个开源的服务网格平台，它提供了一种简单的方式来连接、管理和保护微服务。Istio 可以在 Kubernetes 中运行，也可以在其他环境中运行。</p><p>服务网格（Service Mesh）是一种用于管理服务之间通信的基础设施层。服务网格可以提供流量管理来控制服务之间的流量，用于加密服务之间流量的安全性，以及用于排除故障的服务行为的可观察性并优化应用程序。</p><p>Istio 支持连接、安全、执行和可观察性这四个概念。常用的示例之一是微服务应用程序。Istio 也为基本服务监控需求提供服务通信指标，包括延迟、流量、错误和饱和度。</p></body></html>]]></content>
    
    
    <summary type="html">本文是 IBM 全栈开发课程的第六篇学习笔记，系统性地介绍了从容器化到大规模容器编排的核心技术。笔记从 Docker 的基础概念、工作流和客户端-服务器架构讲起，随后深入探讨了 Kubernetes (K8s) 的核心组件、关键对象（如Pod, Service, Deployment），并对比了 kubectl 的三种管理模式。内容还涵盖了应用管理（如自动扩展、滚动更新）以及 Kubernetes 生态中的企业级平台 OpenShift 和服务网格 Istio。这篇笔记为理解现代云原生应用的部署与管理提供了完整的知识框架。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Docker" scheme="https://blog.cytrogen.icu/tags/Docker/"/>
    
    <category term="IBM" scheme="https://blog.cytrogen.icu/tags/IBM/"/>
    
    <category term="Kubernetes" scheme="https://blog.cytrogen.icu/tags/Kubernetes/"/>
    
  </entry>
  
  <entry>
    <title>PHY 2002 笔记</title>
    <link href="https://blog.cytrogen.icu/posts/3875.html"/>
    <id>https://blog.cytrogen.icu/posts/3875.html</id>
    <published>2024-03-06T04:05:28.000Z</published>
    <updated>2026-02-09T17:16:54.757Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>物理学笔记，仅作为个人学习记录，不保证正确性。</p><span id="more"></span><h1 id="1-一维运动"><a class="markdownIt-Anchor" href="#1-一维运动"></a> 1. 一维运动</h1><p>位移（Displacement）是一个物体从起始点到终点的直线距离和方向。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="normal">Δ</mi><mi>x</mi><mo>=</mo><msub><mi>x</mi><mi>f</mi></msub><mo>−</mo><msub><mi>x</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">\Delta x = x_f - x_i </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8694379999999999em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>x</mi><mi>f</mi></msub></mrow><annotation encoding="application/x-tex">x_f</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span>：终点位置</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>x</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">x_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>：起始位置</li></ul><p>速度（Velocity）是物体位置随时间的变化率。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>v</mi><mtext>avg</mtext></msub><mo>=</mo><mfrac><mrow><mi mathvariant="normal">Δ</mi><mi>x</mi></mrow><mrow><mi mathvariant="normal">Δ</mi><mi>t</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">v_{\text{avg}} = \frac{\Delta x}{\Delta t} </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">avg</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.04633em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.36033em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">Δ</span><span class="mord mathnormal">t</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">Δ</span><span class="mord mathnormal">x</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><ul><li>瞬时速度（Instantaneous velocity）是物体在某一时刻的速度</li></ul><p>加速度（Acceleration）是速度随时间的变化率。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>a</mi><mtext>avg</mtext></msub><mo>=</mo><mfrac><mrow><mi mathvariant="normal">Δ</mi><mi>v</mi></mrow><mrow><mi mathvariant="normal">Δ</mi><mi>t</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">a_{\text{avg}} = \frac{\Delta v}{\Delta t} </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">avg</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.04633em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.36033em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">Δ</span><span class="mord mathnormal">t</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">Δ</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><ul><li>瞬时加速度（Instantaneous acceleration）是物体在某一时刻的加速度</li><li>恒定加速度的情况下，<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>v</mi><mo>=</mo><msub><mi>v</mi><mn>0</mn></msub><mo>+</mo><mi>a</mi><mi>t</mi></mrow><annotation encoding="application/x-tex">v=v_0+at</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.73333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.61508em;vertical-align:0em;"></span><span class="mord mathnormal">a</span><span class="mord mathnormal">t</span></span></span></span></li></ul><h2 id="11-匀速匀加速直线运动"><a class="markdownIt-Anchor" href="#11-匀速匀加速直线运动"></a> 1.1. 匀速 / 匀加速直线运动</h2><p>假设速度随着时间呈线性变化、恒定加速度也是如此的情况（见下图）下，起始速度和终点速度的算术平均值可以用来表示任意时间间隔内的平均速度：<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><mi>v</mi><mo>ˉ</mo></mover><mo>=</mo><mfrac><mrow><msub><mi>v</mi><mn>0</mn></msub><mo>+</mo><mi>v</mi></mrow><mn>2</mn></mfrac></mrow><annotation encoding="application/x-tex">\bar{v}=\frac{v_0+v}{2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.56778em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.22222em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.1634309999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8184309999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.4101em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31731428571428577em;"><span style="top:-2.357em;margin-left:-0.03588em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.143em;"><span></span></span></span></span></span></span><span class="mbin mtight">+</span><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span>。</p><p><img src="/posts/3875/1.webp" alt="1.png" loading="lazy"></p><p>基于这个公式，我们可以推导出物体位移随时间变化的公式：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="normal">Δ</mi><mi>x</mi><mo>=</mo><mover accent="true"><mi>v</mi><mo>ˉ</mo></mover><mi>t</mi><mo>=</mo><mo stretchy="false">(</mo><mfrac><mrow><msub><mi>v</mi><mn>0</mn></msub><mo>+</mo><mi>v</mi></mrow><mn>2</mn></mfrac><mo stretchy="false">)</mo><mi>t</mi></mrow><annotation encoding="application/x-tex">\Delta x = \bar{v} t = (\frac{v_0+v}{2}) t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.61508em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.22222em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.9463300000000001em;vertical-align:-0.686em;"></span><span class="mopen">(</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.2603300000000002em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose">)</span><span class="mord mathnormal">t</span></span></span></span></span></p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="normal">Δ</mi><mi>x</mi><mo>=</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mo stretchy="false">(</mo><msub><mi>v</mi><mn>0</mn></msub><mo>+</mo><mi>v</mi><mo stretchy="false">)</mo><mi>t</mi></mrow><annotation encoding="application/x-tex">\Delta x = \frac{1}{2} (v_0+v) t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.00744em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mclose">)</span><span class="mord mathnormal">t</span></span></span></span></span></p><p>再把速度公式代入，得到：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="normal">Δ</mi><mi>x</mi><mo>=</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mo stretchy="false">(</mo><msub><mi>v</mi><mn>0</mn></msub><mo>+</mo><msub><mi>v</mi><mn>0</mn></msub><mo>+</mo><mi>a</mi><mi>t</mi><mo stretchy="false">)</mo><mi>t</mi></mrow><annotation encoding="application/x-tex">\Delta x = \frac{1}{2} (v_0 + v_0 + at) t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.00744em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.73333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">a</span><span class="mord mathnormal">t</span><span class="mclose">)</span><span class="mord mathnormal">t</span></span></span></span></span></p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="normal">Δ</mi><mi>x</mi><mo>=</mo><msub><mi>v</mi><mn>0</mn></msub><mi>t</mi><mo>+</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mi>a</mi><msup><mi>t</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">\Delta x = v_0 t + \frac{1}{2} a t^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.76508em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:2.00744em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord mathnormal">a</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span></p><p>如果不想要包含时间的话，可以推出：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="normal">Δ</mi><mi>x</mi><mo>=</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mo stretchy="false">(</mo><mi>v</mi><mo>+</mo><msub><mi>v</mi><mn>0</mn></msub><mo stretchy="false">)</mo><mo stretchy="false">(</mo><mfrac><mrow><mi>v</mi><mo>−</mo><msub><mi>v</mi><mn>0</mn></msub></mrow><mi>a</mi></mfrac><mo stretchy="false">)</mo><mo>=</mo><mfrac><mrow><msup><mi>v</mi><mn>2</mn></msup><mo>−</mo><msubsup><mi>v</mi><mn>0</mn><mn>2</mn></msubsup></mrow><mrow><mn>2</mn><mi>a</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">\Delta x = \frac{1}{2} (v + v_0) (\frac{v-v_0}{a}) = \frac{v^2-v^2_0}{2a}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.00744em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.9463300000000001em;vertical-align:-0.686em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mopen">(</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.2603300000000002em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">a</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.177108em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.4911079999999999em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span><span class="mord mathnormal">a</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-2.4518920000000004em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.24810799999999997em;"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msup><mi>v</mi><mn>2</mn></msup><mo>=</mo><msubsup><mi>v</mi><mn>0</mn><mn>2</mn></msubsup><mo>+</mo><mn>2</mn><mi>a</mi><mi mathvariant="normal">Δ</mi><mi>x</mi></mrow><annotation encoding="application/x-tex">v^2 = v^2_0 + 2a \Delta x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8641079999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.1111079999999998em;vertical-align:-0.247em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-2.4530000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord mathnormal">a</span><span class="mord">Δ</span><span class="mord mathnormal">x</span></span></span></span></span></p><h4 id="111-总结"><a class="markdownIt-Anchor" href="#111-总结"></a> 1.1.1. 总结</h4><table><thead><tr><th>公式</th><th>介绍</th></tr></thead><tbody><tr><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>v</mi><mo>=</mo><msub><mi>v</mi><mn>0</mn></msub><mo>+</mo><mi>a</mi><mi>t</mi></mrow><annotation encoding="application/x-tex">v=v_0+at</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.73333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.61508em;vertical-align:0em;"></span><span class="mord mathnormal">a</span><span class="mord mathnormal">t</span></span></span></span></td><td>速度随时间的变化</td></tr><tr><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Δ</mi><mi>x</mi><mo>=</mo><msub><mi>v</mi><mn>0</mn></msub><mi>t</mi><mo>+</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mi>a</mi><msup><mi>t</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">\Delta x = v_0 t + \frac{1}{2} a t^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.76508em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord mathnormal">a</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></td><td>位移随时间的变化</td></tr><tr><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>v</mi><mn>2</mn></msup><mo>=</mo><msubsup><mi>v</mi><mn>0</mn><mn>2</mn></msubsup><mo>+</mo><mn>2</mn><mi>a</mi><mi mathvariant="normal">Δ</mi><mi>x</mi></mrow><annotation encoding="application/x-tex">v^2 = v^2_0 + 2a \Delta x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8141079999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.0622159999999998em;vertical-align:-0.24810799999999997em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-2.4518920000000004em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.24810799999999997em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord mathnormal">a</span><span class="mord">Δ</span><span class="mord mathnormal">x</span></span></span></span></td><td>速度和位移的关系</td></tr></tbody></table><h2 id="12-自由落体"><a class="markdownIt-Anchor" href="#12-自由落体"></a> 1.2. 自由落体</h2><p>亚里士多德认为物体的速度与质量成正比，也就是说物体越重，下落的速度越快。但据说伽利略通过实验发现，不同质量的物体在没有空气阻力的情况下，下落的速度是相同的。宇航员在月球上的实验也证实了这一点。在空气阻力可以忽略不计的情况下，这种运动称为自由落体。</p><p>自由落体的加速度是一个常量，通常用<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi> g</mi></mrow><annotation encoding="application/x-tex">g</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span></span></span></span> 表示，称为重力加速度。在地球表面，<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>g</mi><mo>=</mo><mn>9.8</mn><mtext>&nbsp;</mtext><mi>m</mi><mi mathvariant="normal">/</mi><msup><mi>s</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">g=9.8\ m/s^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.064108em;vertical-align:-0.25em;"></span><span class="mord">9</span><span class="mord">.</span><span class="mord">8</span><span class="mspace">&nbsp;</span><span class="mord mathnormal">m</span><span class="mord">/</span><span class="mord"><span class="mord mathnormal">s</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span>。</p><ul><li>重力加速度的方向是向下的。不过在运动方程中重力加速度为正还是负取决于我们选择的坐标系。如果我们选择向上定义为负值，那么重力加速度就是负的</li></ul><p>自由落体的速度随时间的变化是线性的：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>v</mi><mo>=</mo><msub><mi>v</mi><mn>0</mn></msub><mo>+</mo><mi>g</mi><mi>t</mi></mrow><annotation encoding="application/x-tex">v = v_0 + gt</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.73333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.80952em;vertical-align:-0.19444em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mord mathnormal">t</span></span></span></span></span></p><p>自由落体的位移随时间的平方增加：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>h</mi><mo>=</mo><msub><mi>h</mi><mn>0</mn></msub><mo>+</mo><msub><mi>v</mi><mn>0</mn></msub><mi>t</mi><mo>+</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mi>g</mi><msup><mi>t</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">h = h_0 + v_0 t + \frac{1}{2} g t^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">h</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.84444em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">h</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.76508em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:2.00744em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span></p><h1 id="2-二维运动"><a class="markdownIt-Anchor" href="#2-二维运动"></a> 2. 二维运动</h1><p>在二维空间中，位移、速度和加速度的概念与一维运动类似。不过在二维运动中，我们需要考虑两个方向上的运动，通常指的是水平方向和竖直方向。</p><p>二维位移是一个物体从起始点到终点的直线距离和方向，同时也要考虑两个方向上的变化。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="normal">Δ</mi><mover accent="true"><mi>r</mi><mo>⃗</mo></mover><mo>=</mo><msub><mover accent="true"><mi>r</mi><mo>⃗</mo></mover><mi>f</mi></msub><mo>−</mo><msub><mover accent="true"><mi>r</mi><mo>⃗</mo></mover><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">\Delta \vec{r} = \vec{r}_f - \vec{r}_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.714em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">r</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.17994em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.000108em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">r</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.17994em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.864em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">r</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.17994em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><mi>r</mi><mo>⃗</mo></mover></mrow><annotation encoding="application/x-tex">\vec{r}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.714em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">r</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.17994em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span></span></span></span>：位置矢量</li></ul><p><img src="/posts/3875/2.webp" alt="img.png" loading="lazy"></p><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Δ</mi><mover accent="true"><mi>r</mi><mo>⃗</mo></mover></mrow><annotation encoding="application/x-tex">\Delta \vec{r}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.714em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">r</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.17994em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span></span></span></span> 包含了<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal"> Δ</mi><mi>x</mi></mrow><annotation encoding="application/x-tex">\Delta x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord mathnormal">x</span></span></span></span> 和<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal"> Δ</mi><mi>y</mi></mrow><annotation encoding="application/x-tex">\Delta y</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord">Δ</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span></span></span></span> 两个分量，代表着物体在<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal"> Δ</mi><mi>t</mi></mrow><annotation encoding="application/x-tex">\Delta t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord mathnormal">t</span></span></span></span> 时间内从<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false"> (</mo><msub><mi>x</mi><mi>i</mi></msub><mo separator="true">,</mo><msub><mi>y</mi><mi>i</mi></msub><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(x_i, y_i)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span> 到<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false"> (</mo><msub><mi>x</mi><mi>f</mi></msub><mo separator="true">,</mo><msub><mi>y</mi><mi>f</mi></msub><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(x_f, y_f)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.036108em;vertical-align:-0.286108em;"></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span> 的位移。</p><p><img src="/posts/3875/3.webp" alt="img.png" loading="lazy"></p><p>平均速度的定义与一维运动类似：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mover accent="true"><mi>v</mi><mo>⃗</mo></mover><mtext>avg</mtext></msub><mo>=</mo><mfrac><mrow><mi mathvariant="normal">Δ</mi><mover accent="true"><mi>r</mi><mo>⃗</mo></mover></mrow><mrow><mi mathvariant="normal">Δ</mi><mi>t</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">\vec{v}_{\text{avg}} = \frac{\Delta \vec{r}}{\Delta t}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.000108em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.20772em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">avg</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.077em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.391em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">Δ</span><span class="mord mathnormal">t</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">Δ</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">r</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.17994em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p>因为位移是一个矢量、时间是一个标量，所以我们可以总结出平均速度也是一个矢量、沿着<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal"> Δ</mi><mover accent="true"><mi>r</mi><mo>⃗</mo></mover></mrow><annotation encoding="application/x-tex">\Delta \vec{r}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.714em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">r</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.17994em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span></span></span></span> 的方向。</p><p>瞬时速度是其平均速度在<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal"> Δ</mi><mi>t</mi></mrow><annotation encoding="application/x-tex">\Delta t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord mathnormal">t</span></span></span></span> 为 0 时的极限：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mover accent="true"><mi>v</mi><mo>⃗</mo></mover><mo>=</mo><munder><mo><mi>lim</mi><mo>⁡</mo></mo><mrow><mi mathvariant="normal">Δ</mi><mi>t</mi><mo>→</mo><mn>0</mn></mrow></munder><mfrac><mrow><mi mathvariant="normal">Δ</mi><mover accent="true"><mi>r</mi><mo>⃗</mo></mover></mrow><mrow><mi mathvariant="normal">Δ</mi><mi>t</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">\vec{v} = \lim_{\Delta t \to 0} \frac{\Delta \vec{r}}{\Delta t}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.714em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.20772em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.135331em;vertical-align:-0.744331em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.69444em;"><span style="top:-2.355669em;margin-left:0em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">Δ</span><span class="mord mathnormal mtight">t</span><span class="mrel mtight">→</span><span class="mord mtight">0</span></span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span><span class="mop">lim</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.744331em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.391em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">Δ</span><span class="mord mathnormal">t</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">Δ</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">r</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.17994em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p>平均加速度：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mover accent="true"><mi>a</mi><mo>⃗</mo></mover><mtext>avg</mtext></msub><mo>=</mo><mfrac><mrow><mi mathvariant="normal">Δ</mi><mover accent="true"><mi>v</mi><mo>⃗</mo></mover></mrow><mrow><mi mathvariant="normal">Δ</mi><mi>t</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">\vec{a}_{\text{avg}} = \frac{\Delta \vec{v}}{\Delta t}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.000108em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">a</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.2355em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">avg</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.077em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.391em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">Δ</span><span class="mord mathnormal">t</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">Δ</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.20772em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p>瞬时加速度：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mover accent="true"><mi>a</mi><mo>⃗</mo></mover><mo>=</mo><munder><mo><mi>lim</mi><mo>⁡</mo></mo><mrow><mi mathvariant="normal">Δ</mi><mi>t</mi><mo>→</mo><mn>0</mn></mrow></munder><mfrac><mrow><mi mathvariant="normal">Δ</mi><mover accent="true"><mi>v</mi><mo>⃗</mo></mover></mrow><mrow><mi mathvariant="normal">Δ</mi><mi>t</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">\vec{a} = \lim_{\Delta t \to 0} \frac{\Delta \vec{v}}{\Delta t}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.714em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">a</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.2355em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.135331em;vertical-align:-0.744331em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.69444em;"><span style="top:-2.355669em;margin-left:0em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">Δ</span><span class="mord mathnormal mtight">t</span><span class="mrel mtight">→</span><span class="mord mtight">0</span></span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span><span class="mop">lim</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.744331em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.391em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">Δ</span><span class="mord mathnormal">t</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">Δ</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.20772em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><h2 id="21-二维运动"><a class="markdownIt-Anchor" href="#21-二维运动"></a> 2.1. 二维运动</h2><p>在二维运动中，物体可以同时在水平方向和竖直方向上运动。这种二维运动的一个重要特例是抛体运动（Projectile motion）。</p><p><img src="/posts/3875/4.webp" alt="img.png" loading="lazy"></p><p>如图，物体离开地面时的抛物线轨迹速度为<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mover accent="true"><mi> v</mi><mo>⃗</mo></mover><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">\vec{v}_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.864em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.20772em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>，<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><mi>v</mi><mo>⃗</mo></mover></mrow><annotation encoding="application/x-tex">\vec{v}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.714em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.20772em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span></span></span></span> 会随着时间增长。但是<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi> v</mi><mi>x</mi></msub></mrow><annotation encoding="application/x-tex">v_x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">x</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>，也就是水平方向的速度是恒定的，依旧等同于<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi> v</mi><mn>0</mn></msub><mi>x</mi></mrow><annotation encoding="application/x-tex">v_0x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">x</span></span></span></span>。当物体到达最高点时，<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>v</mi><mi>y</mi></msub></mrow><annotation encoding="application/x-tex">v_y</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">y</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span>呈现为 0，但加速度依然等同于自由落体的加速度、方向向下。</p><p>假设物体在离开地面的时候<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi> t</mi><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">t=0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.61508em;vertical-align:0em;"></span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span>、起始速度为<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mover accent="true"><mi> v</mi><mo>⃗</mo></mover><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">\vec{v}_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.864em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.20772em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>，且速度矢量形成了一个角度<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi> θ</mi></mrow><annotation encoding="application/x-tex">\theta</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">θ</span></span></span></span>，那么我们可以得到：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>v</mi><mrow><mn>0</mn><mi>x</mi></mrow></msub><mo>=</mo><msub><mi>v</mi><mn>0</mn></msub><mi>cos</mi><mo>⁡</mo><mi>θ</mi></mrow><annotation encoding="application/x-tex">v_{0x} = v_0 \cos \theta</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">0</span><span class="mord mathnormal mtight">x</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.84444em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mop">cos</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">θ</span></span></span></span></span></p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>v</mi><mrow><mn>0</mn><mi>y</mi></mrow></msub><mo>=</mo><msub><mi>v</mi><mn>0</mn></msub><mi>sin</mi><mo>⁡</mo><mi>θ</mi></mrow><annotation encoding="application/x-tex">v_{0y} = v_0 \sin \theta</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.301108em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">0</span><span class="mord mathnormal mtight" style="margin-right:0.03588em;">y</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.84444em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mop">sin</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">θ</span></span></span></span></span></p><p>如果只考虑水平方向、水平方向的加速度恒定，那么我们可以得到：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>v</mi><mi>x</mi></msub><mo>=</mo><msub><mi>v</mi><mrow><mn>0</mn><mi>x</mi></mrow></msub><mo>+</mo><msub><mi>a</mi><mi>x</mi></msub><mi>t</mi></mrow><annotation encoding="application/x-tex">v_x = v_{0x} + a_x t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">x</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.73333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">0</span><span class="mord mathnormal mtight">x</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.76508em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">x</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">t</span></span></span></span></span></p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="normal">Δ</mi><mi>x</mi><mo>=</mo><msub><mi>v</mi><mrow><mn>0</mn><mi>x</mi></mrow></msub><mi>t</mi><mo>+</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><msub><mi>a</mi><mi>x</mi></msub><msup><mi>t</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">\Delta x = v_{0x} t + \frac{1}{2} a_x t^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.76508em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">0</span><span class="mord mathnormal mtight">x</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:2.00744em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">x</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span></p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msubsup><mi>v</mi><mi>x</mi><mn>2</mn></msubsup><mo>=</mo><msubsup><mi>v</mi><mrow><mn>0</mn><mi>x</mi></mrow><mn>2</mn></msubsup><mo>+</mo><mn>2</mn><msub><mi>a</mi><mi>x</mi></msub><mi mathvariant="normal">Δ</mi><mi>x</mi></mrow><annotation encoding="application/x-tex">v_x^2 = v_{0x}^2 + 2 a_x \Delta x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.1111079999999998em;vertical-align:-0.247em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-2.4530000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">x</span></span></span><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.1111079999999998em;vertical-align:-0.247em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-2.4530000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">0</span><span class="mord mathnormal mtight">x</span></span></span></span><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord">2</span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">x</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord">Δ</span><span class="mord mathnormal">x</span></span></span></span></span></p><ul><li>以上的<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi> v</mi><mrow><mn>0</mn><mi>x</mi></mrow></msub></mrow><annotation encoding="application/x-tex">v_{0x}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">0</span><span class="mord mathnormal mtight">x</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>等于<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi> v</mi><mn>0</mn></msub><mi>cos</mi><mo>⁡</mo><msub><mi>θ</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">v_0 \cos \theta_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.84444em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mop">cos</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">θ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.02778em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></li></ul><p>反过来只考虑垂直方向和垂直方向的加速度的话，那便是：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>v</mi><mi>y</mi></msub><mo>=</mo><msub><mi>v</mi><mrow><mn>0</mn><mi>y</mi></mrow></msub><mo>+</mo><msub><mi>a</mi><mi>y</mi></msub><mi>t</mi></mrow><annotation encoding="application/x-tex">v_y = v_{0y} + a_y t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">y</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8694379999999999em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.301108em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">0</span><span class="mord mathnormal mtight" style="margin-right:0.03588em;">y</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.9011879999999999em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">y</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mord mathnormal">t</span></span></span></span></span></p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi mathvariant="normal">Δ</mi><mi>y</mi><mo>=</mo><msub><mi>v</mi><mrow><mn>0</mn><mi>y</mi></mrow></msub><mi>t</mi><mo>+</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><msub><mi>a</mi><mi>y</mi></msub><msup><mi>t</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">\Delta y = v_{0y} t + \frac{1}{2} a_y t^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord">Δ</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.9011879999999999em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.301108em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">0</span><span class="mord mathnormal mtight" style="margin-right:0.03588em;">y</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:2.00744em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">y</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span></p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msubsup><mi>v</mi><mi>y</mi><mn>2</mn></msubsup><mo>=</mo><msubsup><mi>v</mi><mrow><mn>0</mn><mi>y</mi></mrow><mn>2</mn></msubsup><mo>+</mo><mn>2</mn><msub><mi>a</mi><mi>y</mi></msub><mi mathvariant="normal">Δ</mi><mi>y</mi></mrow><annotation encoding="application/x-tex">v_y^2 = v_{0y}^2 + 2 a_y \Delta y</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.2472159999999999em;vertical-align:-0.383108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.864108em;"><span style="top:-2.4530000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">y</span></span></span><span style="top:-3.1130000000000004em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.383108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.2472159999999999em;vertical-align:-0.383108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.864108em;"><span style="top:-2.4530000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">0</span><span class="mord mathnormal mtight" style="margin-right:0.03588em;">y</span></span></span></span><span style="top:-3.1130000000000004em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.383108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.969438em;vertical-align:-0.286108em;"></span><span class="mord">2</span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">y</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mord">Δ</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span></span></span></span></span></p><ul><li>同理，<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>v</mi><mrow><mn>0</mn><mi>y</mi></mrow></msub></mrow><annotation encoding="application/x-tex">v_{0y}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.301108em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">0</span><span class="mord mathnormal mtight" style="margin-right:0.03588em;">y</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span>等于<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi> v</mi><mn>0</mn></msub><mi>sin</mi><mo>⁡</mo><msub><mi>θ</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">v_0 \sin \theta_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.84444em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mop">sin</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">θ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.02778em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>，且<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi> a</mi><mi>y</mi></msub></mrow><annotation encoding="application/x-tex">a_y</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">y</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span>恒定</li></ul><p>这种情况下速度<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi> v</mi></mrow><annotation encoding="application/x-tex">v</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span></span> 可以使用勾股定理表示：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>v</mi><mo>=</mo><msqrt><mrow><msubsup><mi>v</mi><mi>x</mi><mn>2</mn></msubsup><mo>+</mo><msubsup><mi>v</mi><mi>y</mi><mn>2</mn></msubsup></mrow></msqrt></mrow><annotation encoding="application/x-tex">v = \sqrt{v_x^2 + v_y^2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.84em;vertical-align:-0.6276249999999999em;"></span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.2123750000000002em;"><span class="svg-align" style="top:-3.8em;"><span class="pstrut" style="height:3.8em;"></span><span class="mord" style="padding-left:1em;"><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.740108em;"><span style="top:-2.4530000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">x</span></span></span><span style="top:-2.9890000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.7401079999999999em;"><span style="top:-2.4530000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">y</span></span></span><span style="top:-2.989em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.383108em;"><span></span></span></span></span></span></span></span></span><span style="top:-3.1723749999999997em;"><span class="pstrut" style="height:3.8em;"></span><span class="hide-tail" style="min-width:1.02em;height:1.8800000000000001em;"><svg width="400em" height="1.8800000000000001em" viewBox="0 0 400000 1944" preserveAspectRatio="xMinYMin slice"><path d="M983 90l0 -0c4,-6.7,10,-10,18,-10 H400000v40H1013.1s-83.4,268,-264.1,840c-180.7,572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7s-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744c-10,12,-21,25,-33,39s-32,39,-32,39c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30c26.7,-32.7,52,-63,76,-91s52,-60,52,-60s208,722,208,722c56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,-658.5c53.7,-170.3,84.5,-266.8,92.5,-289.5zM1001 80h400000v40h-400000z"></path></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.6276249999999999em;"><span></span></span></span></span></span></span></span></span></span></p><p>角度<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi> θ</mi></mrow><annotation encoding="application/x-tex">\theta</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">θ</span></span></span></span> 可以使用反正切函数表示：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>θ</mi><mo>=</mo><msup><mo><mi>tan</mi><mo>⁡</mo></mo><mrow><mo>−</mo><mn>1</mn></mrow></msup><mfrac><msub><mi>v</mi><mi>y</mi></msub><msub><mi>v</mi><mi>x</mi></msub></mfrac></mrow><annotation encoding="application/x-tex">\theta = \tan^{-1} \frac{v_y}{v_x}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">θ</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.94356em;vertical-align:-0.8360000000000001em;"></span><span class="mop"><span class="mop">tan</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.864108em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">−</span><span class="mord mtight">1</span></span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.1075599999999999em;"><span style="top:-2.3139999999999996em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">x</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">y</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.8360000000000001em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><ul><li>如果矢量落在第二或第三象限，那么<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi> θ</mi></mrow><annotation encoding="application/x-tex">\theta</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">θ</span></span></span></span> 的值需要加上<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn> 180</mn><mi mathvariant="normal">°</mi></mrow><annotation encoding="application/x-tex">180°</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord">1</span><span class="mord">8</span><span class="mord">0</span><span class="mord">°</span></span></span></span></li></ul><h2 id="22-相对速度"><a class="markdownIt-Anchor" href="#22-相对速度"></a> 2.2. 相对速度</h2><p>相对速度将两个不同观测者的测量结果联系起来。物体的测量速度取决于观察者相对于物体的速度。例如高速公路上同方向行驶的汽车，它们相对于地球而言是高速行驶的，但相对于彼此，它们几乎没有移动。</p><p>因此，速度的测量取决于观察者的参照系。参照系只是坐标系。大多数时候，我们使用相对于地球的静止参照系，但偶尔我们也会使用与相对于地球以恒定速度运动的公共汽车、汽车或飞机相关的运动参照系。</p><p>在二维空间中，相对速度的计算可能令人困惑，因此采用系统的方法非常重要和有用。假设 E 是一个观察者，相对于地球静止不动。将两辆汽车分别标记为 A 和 B，并引入以下符号：</p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><msub><mi>r</mi><mrow><mi>A</mi><mi>E</mi></mrow></msub><mo>⃗</mo></mover></mrow><annotation encoding="application/x-tex">\vec{r_{AE}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.864em;vertical-align:-0.15em;"></span><span class="mord accent"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.02778em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">A</span><span class="mord mathnormal mtight" style="margin-right:0.05764em;">E</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.2355em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span>：汽车 A 相对于 E 的位移</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><msub><mi>r</mi><mrow><mi>B</mi><mi>E</mi></mrow></msub><mo>⃗</mo></mover></mrow><annotation encoding="application/x-tex">\vec{r_{BE}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.864em;vertical-align:-0.15em;"></span><span class="mord accent"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.02778em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05017em;">B</span><span class="mord mathnormal mtight" style="margin-right:0.05764em;">E</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.2355em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span>：汽车 B 相对于 E 的位移</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><msub><mi>v</mi><mrow><mi>A</mi><mi>B</mi></mrow></msub><mo>⃗</mo></mover></mrow><annotation encoding="application/x-tex">\vec{v_{AB}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.864em;vertical-align:-0.15em;"></span><span class="mord accent"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">A</span><span class="mord mathnormal mtight" style="margin-right:0.05017em;">B</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.2355em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span>：汽车 A 相对于 B 的速度</li></ul><p><img src="/posts/3875/5.webp" alt="img.png" loading="lazy"></p><h1 id="3-牛顿运动定律"><a class="markdownIt-Anchor" href="#3-牛顿运动定律"></a> 3. 牛顿运动定律</h1><p>牛顿运动定律是描述物体运动的基本规律，由牛顿在 17 世纪提出。这些定律是经典力学的基础，对于理解和预测物体如何在力的作用下移动至关重要。</p><p>牛顿第一定律也被称为惯性定律，它表明如果没有外力作用，物体将保持其状态不变。也就是说静止的物体将保持静止，而移动的物体将以恒定速度直线运动。</p><p>比方说，当你在车上的时候，车突然启动，你会向后倾斜。这是因为你的身体保持了静止状态，而车突然加速了。当车突然停下来的时候，你会向前倾斜。这是因为你的身体保持了前进的状态，而车突然停下了。</p><p>牛顿第二定律是最重要的定律之一，它表明力（Force）等于物体的质量乘以加速度，或者说物体的加速度是力和质量的商。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mover accent="true"><mi>F</mi><mo>⃗</mo></mover><mo>=</mo><mi>m</mi><mover accent="true"><mi>a</mi><mo>⃗</mo></mover></mrow><annotation encoding="application/x-tex">\vec{F} = m \vec{a}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9663299999999999em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.9663299999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">F</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.15216em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.714em;vertical-align:0em;"></span><span class="mord mathnormal">m</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.714em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">a</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.2355em;"><span class="overlay" style="height:0.714em;width:0.471em;"><svg width="0.471em" height="0.714em" style="width:0.471em" viewBox="0 0 471 714" preserveAspectRatio="xMinYMin"><path d="M377 20c0-5.333 1.833-10 5.5-14S391 0 397 0c4.667 0 8.667 1.667 12 53.333 2.667 6.667 9 10 19 6.667 24.667 20.333 43.667 41 57 7.333 4.667 1110.667 11 18 0 6-1 10-3 12s-6.667 5-14 9c-28.667 14.667-53.667 35.667-75 63-1.333 1.333-3.167 3.5-5.5 6.5s-4 4.833-5 5.5c-1 .667-2.5 1.333-4.5 2s-4.333 1-7 1c-4.667 0-9.167-1.833-13.5-5.5S337 184 337 178c0-12.667 15.667-32.333 47-59H213l-171-1c-8.667-6-13-12.333-13-19 0-4.667 4.333-11.333 13-20h359c-16-25.333-24-45-24-59z"></path></svg></span></span></span></span></span></span></span></span></span></span></span></p><p>这个定律解释了为什么物体在受到外力作用时会加速。它还解释了为什么物体的质量越大，所需的力越大，加速度越小。</p><p>牛顿第三定律也被称为作用与反作用定律，它表明对于每一个作用力，都有一个与之大小相等、方向相反的反作用力。如果物体 A 对物体 B 施加一个力，那么物体 B 对物体 A 也会施加一个大小相等、方向相反的力。</p><p>当我们使用锤子敲击钉子时，我们施加了一个向下的力，钉子对锤子也施加了一个向上的力。这个力使得锤子停止下降。当我们在地面上行走时，我们对地面施加了一个向后的力，地面对我们也施加了一个向前的力。这个力使得我们向前移动。</p><h2 id="31-力"><a class="markdownIt-Anchor" href="#31-力"></a> 3.1. 力</h2><p>力是一个矢量，它有大小和方向。</p><p>如果拉动弹簧，弹簧就会拉伸；如果用力拉小车，小车就会移动；如果踢足球，足球就会短暂变形然后飞出去。这些都是接触力（Contact force）的例子。</p><p>重力（Gravitational force）是地球对物体的吸引力。它的大小等于物体的质量乘以重力加速度（在地球表面约为 9.8 m / s²）。重力总是朝下。</p><p>摩擦力（Frictional force）是阻止物体在表面上滑动的力。摩擦力的方向总是与物体相对于表面的运动方向相反。</p><p>电磁力（Electromagnetic force）是电荷之间的相互作用力。</p><h2 id="32-运动定律"><a class="markdownIt-Anchor" href="#32-运动定律"></a> 3.2. 运动定律</h2><p>力的国际单位是牛顿（N）：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mn>1</mn><mtext>&nbsp;</mtext><mi>N</mi><mo>=</mo><mn>1</mn><mtext>&nbsp;</mtext><mi>k</mi><mi>g</mi><mo>⋅</mo><mi>m</mi><mi mathvariant="normal">/</mi><msup><mi>s</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">1\ N = 1\ kg \cdot m/s^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">1</span><span class="mspace">&nbsp;</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord">1</span><span class="mspace">&nbsp;</span><span class="mord mathnormal" style="margin-right:0.03148em;">k</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.1141079999999999em;vertical-align:-0.25em;"></span><span class="mord mathnormal">m</span><span class="mord">/</span><span class="mord"><span class="mord mathnormal">s</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span></p><ul><li>在美国，磅（lb）是力的单位：<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mtext>&nbsp;</mtext><mi>N</mi><mo>=</mo><mn>0.225</mn><mtext>&nbsp;</mtext><mi>l</mi><mi>b</mi></mrow><annotation encoding="application/x-tex">1\ N = 0.225\ lb</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">1</span><span class="mspace">&nbsp;</span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord">0</span><span class="mord">.</span><span class="mord">2</span><span class="mord">2</span><span class="mord">5</span><span class="mspace">&nbsp;</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">b</span></span></span></span></li></ul><h2 id="33-动摩擦力"><a class="markdownIt-Anchor" href="#33-动摩擦力"></a> 3.3. 动摩擦力</h2><p>摩擦力是一种接触力，源于物体与其环境之间的微观相互作用。空气摩擦力（Air friction）影响着各种交通工具，流体摩擦力（Fluid friction）影响着船只的运动。摩擦力并不单单是阻碍物体运动的力，它还可以使物体运动。</p><p>动摩擦力（Force of kinetic friction）是当两个物体在相对运动时、产生出的抵抗这种运动的力。它的方向总是与物体相对运动的方向相反。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>f</mi><mtext>k</mtext></msub><mo>=</mo><msub><mi>μ</mi><mi>k</mi></msub><mi>N</mi></mrow><annotation encoding="application/x-tex">f_{\text{k}} = \mu_{k} N</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.33610799999999996em;"><span style="top:-2.5500000000000003em;margin-left:-0.10764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">k</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">μ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.33610799999999996em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03148em;">k</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>N</mi></mrow><annotation encoding="application/x-tex">N</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span></span></span></span> 是作用于物体上的法向力（Normal force），公式为<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi> N</mi><mo>=</mo><mi>m</mi><mi>g</mi></mrow><annotation encoding="application/x-tex">N = mg</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">m</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span></span></span></span></li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>μ</mi><mi>k</mi></msub></mrow><annotation encoding="application/x-tex">\mu_{k}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">μ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.33610799999999996em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03148em;">k</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>是物体和表面之间的动摩擦系数（Coefficient of kinetic friction）</li></ul><p>动摩擦力的特点是它与物体的速度无关，只取决于接触表面的性质和正压力的大小。这就是为什么在相同表面下，重的物体比轻的物体更难推动。</p><h2 id="34-静摩擦力"><a class="markdownIt-Anchor" href="#34-静摩擦力"></a> 3.4. 静摩擦力</h2><p>静摩擦力（Static friction forces）是当两个物体试图滑动但实际上并未滑动时、产生的抵抗滑动的力。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mn>0</mn><mo>≤</mo><msub><mi>f</mi><mtext>s</mtext></msub><mo>≤</mo><msub><mi>f</mi><mtext>s,&nbsp;max</mtext></msub><mo>≤</mo><msub><mi>μ</mi><mi>s</mi></msub><mi>N</mi></mrow><annotation encoding="application/x-tex">0 \leq f_{\text{s}} \leq f_{\text{s, max}} \leq \mu_{s} N</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.78041em;vertical-align:-0.13597em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">≤</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.10764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">s</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">≤</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.980548em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:-0.10764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">s,&nbsp;max</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">≤</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">μ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">s</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>N</mi></mrow><annotation encoding="application/x-tex">N</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span></span></span></span> 是法向力</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>μ</mi><mi>s</mi></msub></mrow><annotation encoding="application/x-tex">\mu_{s}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">μ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">s</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>是物体与表面之间最大的静摩擦系数</li><li>该公式仅用于计算最大静摩擦力</li></ul><h2 id="35-张力"><a class="markdownIt-Anchor" href="#35-张力"></a> 3.5. 张力</h2><p>将绳索固定在物体上并拉动它，即可产生张力（Tension force）。张力是绳索内部的拉力，它总是朝着绳索的两端方向。</p><h1 id="4-能量"><a class="markdownIt-Anchor" href="#4-能量"></a> 4. 能量</h1><p>能量（Energy）以各种形式存在于宇宙中，即使是日常物质中的惰性物质也蕴含着大量的能量。虽然能量可以从一种转化为另一种，但迄今为止的所有观测和实验都表明，宇宙中的能量总量从未发生过变化。</p><p>对于孤立系统来说也是如此，孤立系统是一组物体的集合，它们可以相互交换能量，但不能与宇宙的其他部分交换能量。如果孤立系统中的一种能量形式减少，那么系统中的另一种能量形式必然增加。</p><p>例如，如果系统由连接到电池的电机组成，那么电池将化学能转化为电能，电机将电能转化为机械能。了解能量如何从一种形式转化为另一种形式，对所有科学都至关重要。</p><h2 id="41-功"><a class="markdownIt-Anchor" href="#41-功"></a> 4.1. 功</h2><p>功（Work）用于描述力在物体上所做的影响。在物理学中，功是通过力使物体移动一定距离所做的工作。如果力的方向与物体移动的方向一致，那么功就是力和距离的乘积。</p><p>功的直观定义：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>W</mi><mo>=</mo><mi>F</mi><mo>⋅</mo><mi>d</mi></mrow><annotation encoding="application/x-tex">W = F \cdot d</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">d</span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>F</mi></mrow><annotation encoding="application/x-tex">F</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span></span></span></span> 是作用在物体上的力的大小</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>d</mi></mrow><annotation encoding="application/x-tex">d</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">d</span></span></span></span> 是物体位移的大小</li><li>这个定义仅给出了当力恒定，并且位移平行时物体所做的功，这代表着在这个定义下位移必须沿着一条直线</li></ul><p>功是一个标量，对比矢量更容易处理。它与方向无关，也不明确取决于时间。因为功的单位是力和距离的单位，所以国际单位是牛顿米（N・m），也称为焦耳（J）。</p><p>如果力的方向与物体移动的方向不一致，那么我们可以使用以下公式：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>W</mi><mo>=</mo><mi>F</mi><mo>⋅</mo><mi>d</mi><mo>⋅</mo><mi>cos</mi><mo>⁡</mo><mi>θ</mi></mrow><annotation encoding="application/x-tex">W = F \cdot d \cdot \cos \theta</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mop">cos</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">θ</span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>θ</mi></mrow><annotation encoding="application/x-tex">\theta</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">θ</span></span></span></span> 是力和位移之间的夹角</li></ul><h2 id="42-动能"><a class="markdownIt-Anchor" href="#42-动能"></a> 4.2. 动能</h2><p>动能（Kinetic energy）是物体由于运动而具有的能量。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>K</mi><mo>=</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mtext>&nbsp;</mtext><mi>m</mi><msup><mi>v</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">K = \frac{1}{2}\ m v^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.00744em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace">&nbsp;</span><span class="mord mathnormal">m</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span></p><p>功 - 能定理（Work-energy theorem）表明，当力对物体做功时，物体的动能会增加。这个定理可以用来解释为什么物体在受到外力作用时会加速。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>W</mi><mo>=</mo><mi mathvariant="normal">Δ</mi><mi>K</mi></mrow><annotation encoding="application/x-tex">W = \Delta K</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span></span></span></span></span></p><ul><li>该定理是牛顿第二定律的一个推论，为我们提供了一种计算物体速度变化的方法</li><li>例如你用力推动一个静止的物体使其开始运动，那么你对物体做的功就等于物体获得的动能。如果你用力使一个正在运动的物体停下来，那么你对物体做的功就等于物体失去的动能</li></ul><p>净功（Net work）等同于物体动能的变化：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>W</mi><mtext>net</mtext></msub><mo>=</mo><mi>K</mi><msub><mi>E</mi><mi>f</mi></msub><mo>−</mo><mi>K</mi><msub><mi>E</mi><mi>i</mi></msub><mo>=</mo><mi mathvariant="normal">Δ</mi><mi>K</mi><mi>E</mi></mrow><annotation encoding="application/x-tex">W_{\text{net}} = KE_f - KE_i = \Delta KE</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2805559999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">net</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.969438em;vertical-align:-0.286108em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span></span></span></span></span></p><p>净功是所有作用在物体上的力所做的功的总和。如果净功为正，那么物体的动能会增加；如果净功为负，那么物体的动能会减少。</p><h2 id="43-保守力和非保守力"><a class="markdownIt-Anchor" href="#43-保守力和非保守力"></a> 4.3. 保守力和非保守力</h2><p>力可以被分为两种类型：保守力（Conservative force）和非保守力（Non-conservative force）。</p><p>保守力的特点是它做的功仅仅取决于物体的初始位置和最终位置，而不依赖于物体从初始位置到最终位置所走的路径。换句话说，对于保守力而言，从一点到另一点的路径无论如何变化，只要初始和最终位置相同，做的功就是相同的。重力和弹簧力便是两个常见的保守力。</p><p>保守力的一个重要特性便是它们可以与势能（Potential energy）联系起来。</p><p>非保守力也被称为耗散力（Dissipative force），它们做的功取决于物体所走的路径。摩擦力和空气阻力便是两个常见的非保守力。</p><p>非保守力通常会导致物体的机械能（Mechanical energy，是动能和势能的和）减少，因为它们会将物体的机械能转化为其他形式的能量，例如热能。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>W</mi><mtext>nc</mtext></msub><mo>+</mo><msub><mi>W</mi><mtext>c</mtext></msub><mo>=</mo><mi mathvariant="normal">Δ</mi><mi>K</mi><mi>E</mi></mrow><annotation encoding="application/x-tex">W_{\text{nc}} + W_{\text{c}} = \Delta KE</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">nc</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">c</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span></span></span></span></span></p><h2 id="44-重力势能"><a class="markdownIt-Anchor" href="#44-重力势能"></a> 4.4. 重力势能</h2><p>具有动能的物体可以对另一个物体做功，例如一个正在移动的锤子可以把钉子钉进墙里。高架上的砖块也能做功：它可以从架子上掉下来、加速向下、正中钉子、将钉子打入地板。这块砖可以具有势能，因为从它的位置来看，它有可能做功。</p><p>重力是一种保守力，每一种保守力都可以从中找到一种叫做势能函数的特殊表达式。重力功（Gravitational work）是当物体在重力的作用下位移时、重力对物体做的功。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>W</mi><mi>g</mi></msub><mo>=</mo><mi>F</mi><mi>d</mi><mi>cos</mi><mo>⁡</mo><mi>θ</mi><mo>=</mo><mi>m</mi><mi>g</mi><mo stretchy="false">(</mo><msub><mi>y</mi><mi>i</mi></msub><mo>−</mo><msub><mi>y</mi><mi>f</mi></msub><mo stretchy="false">)</mo><mi>cos</mi><mo>⁡</mo><mn>0</mn><mi mathvariant="normal">°</mi><mo>=</mo><mo>−</mo><mi>m</mi><mi>g</mi><mo stretchy="false">(</mo><msub><mi>y</mi><mi>f</mi></msub><mo>−</mo><msub><mi>y</mi><mi>i</mi></msub><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">W_g = Fd \cos \theta = mg(y_i-y_f) \cos 0 \degree = -mg(y_f-y_i)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.969438em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mord mathnormal">d</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mop">cos</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">θ</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">m</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.036108em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mop">cos</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord">0</span><span class="mord">°</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.036108em;vertical-align:-0.286108em;"></span><span class="mord">−</span><span class="mord mathnormal">m</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span></p><ul><li>该公式描述了一本质量为<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi> m</mi></mrow><annotation encoding="application/x-tex">m</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">m</span></span></span></span> 的书从<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi> y</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">y_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>摔落到<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi> y</mi><mi>f</mi></msub></mrow><annotation encoding="application/x-tex">y_f</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span>（不考虑空气摩擦力）</li><li>计算净功：<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>W</mi><mtext>net</mtext></msub><mo>=</mo><msub><mi>W</mi><mrow><mi>n</mi><mi>c</mi></mrow></msub><mo>+</mo><msub><mi>W</mi><mi>g</mi></msub><mo>=</mo><mi mathvariant="normal">Δ</mi><mi>K</mi><mi>E</mi></mrow><annotation encoding="application/x-tex">W_{\text{net}} = W_{nc} + W_g = \Delta KE</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2805559999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">net</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span><span class="mord mathnormal mtight">c</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.969438em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span></span></span></span><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>W</mi><mrow><mi>n</mi><mi>c</mi></mrow></msub></mrow><annotation encoding="application/x-tex">W_{nc}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span><span class="mord mathnormal mtight">c</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>意味着由非保守力做的功</li></ul></li></ul><p>重力势能（Gravitational potential energy）是一个物体由于其在地球表面或其他天体表面以上的位置而获得的能量。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>P</mi><mi>E</mi><mo>=</mo><mi>m</mi><mi>g</mi><mi>y</mi></mrow><annotation encoding="application/x-tex">PE = mgy</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">m</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>y</mi></mrow><annotation encoding="application/x-tex">y</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span></span></span></span> 是相对于地球表面、物体所在的高度</li></ul><p>重力功和重力势能的关系：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>W</mi><mi>g</mi></msub><mo>=</mo><mo>−</mo><mo stretchy="false">(</mo><mi>P</mi><msub><mi>E</mi><mi>f</mi></msub><mo>−</mo><mi>P</mi><msub><mi>E</mi><mi>i</mi></msub><mo stretchy="false">)</mo><mo>=</mo><mo>−</mo><mo stretchy="false">(</mo><mi>m</mi><mi>g</mi><msub><mi>y</mi><mi>f</mi></msub><mo>−</mo><mi>m</mi><mi>g</mi><msub><mi>y</mi><mi>i</mi></msub><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">W_g = - (PE_f-PE_i) = - (mgy_f - mgy_i)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.969438em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">g</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.036108em;vertical-align:-0.286108em;"></span><span class="mord">−</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.036108em;vertical-align:-0.286108em;"></span><span class="mord">−</span><span class="mopen">(</span><span class="mord mathnormal">m</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">m</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span></p><p>根据这两个公式，功 - 能定理（对于非保守力）的公式可以进行扩展：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>W</mi><mrow><mi>n</mi><mi>c</mi></mrow></msub><mo>=</mo><mo stretchy="false">(</mo><mi>K</mi><msub><mi>E</mi><mi>f</mi></msub><mo>−</mo><mi>K</mi><msub><mi>E</mi><mi>i</mi></msub><mo stretchy="false">)</mo><mo>+</mo><mo stretchy="false">(</mo><mi>P</mi><msub><mi>E</mi><mi>f</mi></msub><mo>−</mo><mi>P</mi><msub><mi>E</mi><mi>i</mi></msub><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">W_{nc} = (KE_f - KE_i) + (PE_f - PE_i)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span><span class="mord mathnormal mtight">c</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.036108em;vertical-align:-0.286108em;"></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.036108em;vertical-align:-0.286108em;"></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span></p><h2 id="45-重力与机械能守恒定律"><a class="markdownIt-Anchor" href="#45-重力与机械能守恒定律"></a> 4.5. 重力与机械能守恒定律</h2><p>机械能（Mechanical energy）是一个物体的动能和势能之和。假设在一个封闭的系统中，如果只有保守力作用，那么这个物体的机械能就是守恒的。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>K</mi><msub><mi>E</mi><mi>i</mi></msub><mo>+</mo><mi>P</mi><msub><mi>E</mi><mi>i</mi></msub><mo>=</mo><mi>K</mi><msub><mi>E</mi><mi>f</mi></msub><mo>+</mo><mi>P</mi><msub><mi>E</mi><mi>f</mi></msub></mrow><annotation encoding="application/x-tex">KE_i + PE_i = KE_f + PE_f</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.969438em;vertical-align:-0.286108em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.969438em;vertical-align:-0.286108em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span></span></p><p>如果重力是系统中唯一做功的力，那么机械能守恒原理的形式为：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mfrac><mn>1</mn><mn>2</mn></mfrac><mtext>&nbsp;</mtext><mi>m</mi><msubsup><mi>v</mi><mi>i</mi><mn>2</mn></msubsup><mo>+</mo><mi>m</mi><mi>g</mi><msub><mi>y</mi><mi>i</mi></msub><mo>=</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mtext>&nbsp;</mtext><mi>m</mi><msubsup><mi>v</mi><mi>f</mi><mn>2</mn></msubsup><mo>+</mo><mi>m</mi><mi>g</mi><msub><mi>y</mi><mi>f</mi></msub></mrow><annotation encoding="application/x-tex">\frac{1}{2}\ mv^2_i + mgy_i = \frac{1}{2}\ mv^2_f + mgy_f</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:2.00744em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace">&nbsp;</span><span class="mord mathnormal">m</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-2.4530000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.247em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">m</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.00744em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace">&nbsp;</span><span class="mord mathnormal">m</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.864108em;"><span style="top:-2.4530000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span><span style="top:-3.1130000000000004em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.383108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord mathnormal">m</span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span></span></p><h2 id="46-弹簧势能"><a class="markdownIt-Anchor" href="#46-弹簧势能"></a> 4.6. 弹簧势能</h2><p>在拉伸或压缩弹簧时，外力所做的功可以通过消除外力来恢复，因此弹簧力和重力一样、也是保守力。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>P</mi><msub><mi>E</mi><mi>s</mi></msub><mo>=</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mtext>&nbsp;</mtext><mi>k</mi><msup><mi>x</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">PE_s = \frac{1}{2}\ kx^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">s</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.00744em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace">&nbsp;</span><span class="mord mathnormal" style="margin-right:0.03148em;">k</span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>k</mi></mrow><annotation encoding="application/x-tex">k</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03148em;">k</span></span></span></span> 是弹簧的硬度</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span></span></span></span> 是弹簧被压缩或拉伸的长度</li></ul><p>加上弹簧势能，功 - 能定理又可以进行一波扩展：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>W</mi><mrow><mi>n</mi><mi>c</mi></mrow></msub><mo>=</mo><mo stretchy="false">(</mo><mi>K</mi><msub><mi>E</mi><mi>f</mi></msub><mo>−</mo><mi>K</mi><msub><mi>E</mi><mi>i</mi></msub><mo stretchy="false">)</mo><mo>+</mo><mo stretchy="false">(</mo><mi>P</mi><msub><mi>E</mi><mrow><mi>g</mi><mi>f</mi></mrow></msub><mo>−</mo><mi>P</mi><msub><mi>E</mi><mrow><mi>g</mi><mi>i</mi></mrow></msub><mo stretchy="false">)</mo><mo>+</mo><mo stretchy="false">(</mo><mi>P</mi><msub><mi>E</mi><mrow><mi>s</mi><mi>f</mi></mrow></msub><mo>−</mo><mi>P</mi><msub><mi>E</mi><mrow><mi>s</mi><mi>i</mi></mrow></msub><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">W_{nc} = (KE_f - KE_i) + (PE_{gf} - PE_{gi}) + (PE_{sf} - PE_{si})</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">W</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span><span class="mord mathnormal mtight">c</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.036108em;vertical-align:-0.286108em;"></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">K</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.036108em;vertical-align:-0.286108em;"></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">g</span><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.036108em;vertical-align:-0.286108em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.311664em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">g</span><span class="mord mathnormal mtight">i</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.036108em;vertical-align:-0.286108em;"></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3361079999999999em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">s</span><span class="mord mathnormal mtight" style="margin-right:0.10764em;">f</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">s</span><span class="mord mathnormal mtight">i</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span></p><h2 id="47-能量守恒定律"><a class="markdownIt-Anchor" href="#47-能量守恒定律"></a> 4.7. 能量守恒定律</h2><p>能量守恒定律（Conservation of energy）是物理学中的基本定律之一，它指出，在一个封闭的系统中，能量不能被创建也不能被销毁，只能从一种形式转化为另一种形式。也就是说，系统的总能量在任何时候都保持不变。</p><h2 id="48-功率"><a class="markdownIt-Anchor" href="#48-功率"></a> 4.8. 功率</h2><p>在物理学中，功率（Power）是做功或转移能量的速率。也就是说，功率描述了单位时间内做多少功或转移多少能量。功率的定义式为：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mover accent="true"><mi>P</mi><mo>ˉ</mo></mover><mo>=</mo><mfrac><mi>W</mi><mrow><mi mathvariant="normal">Δ</mi><mi>t</mi></mrow></mfrac><mo>=</mo><mfrac><mrow><mi>F</mi><mi mathvariant="normal">Δ</mi><mi>x</mi></mrow><mrow><mi mathvariant="normal">Δ</mi><mi>t</mi></mrow></mfrac><mo>=</mo><mi>F</mi><mover accent="true"><mi>v</mi><mo>ˉ</mo></mover></mrow><annotation encoding="application/x-tex">\bar{P} = \frac{W}{\Delta t} = \frac{F \Delta x}{\Delta t} = F \bar{v}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8201099999999999em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">P</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.04633em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.36033em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">Δ</span><span class="mord mathnormal">t</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">W</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.04633em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.36033em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">Δ</span><span class="mord mathnormal">t</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mord">Δ</span><span class="mord mathnormal">x</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.22222em;"><span class="mord">ˉ</span></span></span></span></span></span></span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>W</mi></mrow><annotation encoding="application/x-tex">W</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">W</span></span></span></span> 是做的功或者转移的能量（瓦特）</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">Δ</mi><mi>t</mi></mrow><annotation encoding="application/x-tex">\Delta t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">Δ</span><span class="mord mathnormal">t</span></span></span></span> 是时间周期</li></ul><p>以上是速度平均的情况下，如果是瞬时速度：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>P</mi><mo>=</mo><mi>F</mi><mi>v</mi></mrow><annotation encoding="application/x-tex">P = Fv</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span></span></span></p><p>功率的国际单位是焦耳，也可以被称为瓦特：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mn>1</mn><mtext>&nbsp;W</mtext><mo>=</mo><mn>1</mn><mtext>&nbsp;J/s</mtext><mo>=</mo><mn>1</mn><mtext>&nbsp;kg</mtext><mo>⋅</mo><msup><mtext>m</mtext><mn>2</mn></msup><mi mathvariant="normal">/</mi><msup><mtext>s</mtext><mn>3</mn></msup></mrow><annotation encoding="application/x-tex">1\ \text{W} = 1\ \text{J/s} = 1\ \text{kg} \cdot \text{m}^2 / \text{s}^3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">1</span><span class="mspace">&nbsp;</span><span class="mord text"><span class="mord">W</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">1</span><span class="mspace">&nbsp;</span><span class="mord text"><span class="mord">J/s</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord">1</span><span class="mspace">&nbsp;</span><span class="mord text"><span class="mord">kg</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.1141079999999999em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord text"><span class="mord">m</span></span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mord">/</span><span class="mord"><span class="mord text"><span class="mord">s</span></span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span></span></span></span></span></span></span></span></span></p><p>单位马力（Horsepower）有时也会被使用：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mn>1</mn><mtext>&nbsp;hp</mtext><mo>=</mo><mn>550</mn><mtext>&nbsp;</mtext><mfrac><mrow><mtext>ft</mtext><mo>⋅</mo><mtext>lb</mtext></mrow><mtext>s</mtext></mfrac><mo>=</mo><mn>746</mn><mtext>&nbsp;W</mtext></mrow><annotation encoding="application/x-tex">1\ \text{hp} = 550\ \frac{\text{ft} \cdot \text{lb}}{\text{s}} = 746\ \text{W}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord">1</span><span class="mspace">&nbsp;</span><span class="mord text"><span class="mord">hp</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.05744em;vertical-align:-0.686em;"></span><span class="mord">5</span><span class="mord">5</span><span class="mord">0</span><span class="mspace">&nbsp;</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.37144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord">s</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord">ft</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord text"><span class="mord">lb</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord">7</span><span class="mord">4</span><span class="mord">6</span><span class="mspace">&nbsp;</span><span class="mord text"><span class="mord">W</span></span></span></span></span></span></p><p>在发电领域，人们习惯用千瓦时来衡量能量：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mn>1</mn><mtext>&nbsp;kWh</mtext><mo>=</mo><mo stretchy="false">(</mo><mn>1</mn><msup><mn>0</mn><mn>3</mn></msup><mtext>&nbsp;W</mtext><mo stretchy="false">)</mo><mo stretchy="false">(</mo><mn>3600</mn><mtext>&nbsp;s</mtext><mo stretchy="false">)</mo><mo>=</mo><mo stretchy="false">(</mo><mn>1</mn><msup><mn>0</mn><mn>3</mn></msup><mtext>&nbsp;J</mtext><mi mathvariant="normal">/</mi><mtext>s</mtext><mo stretchy="false">)</mo><mo stretchy="false">(</mo><mn>3600</mn><mtext>&nbsp;s</mtext><mo stretchy="false">)</mo><mo>=</mo><mn>3.60</mn><mo>⋅</mo><mn>1</mn><msup><mn>0</mn><mn>6</mn></msup><mtext>J</mtext></mrow><annotation encoding="application/x-tex">1\ \text{kWh} = (10^3\ \text{W}) (3600\ \text{s}) = (10^3\ \text{J} / \text{s}) (3600\ \text{s}) = 3.60 \cdot 10^6 \text{J}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord">1</span><span class="mspace">&nbsp;</span><span class="mord text"><span class="mord">kWh</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.1141079999999999em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">1</span><span class="mord"><span class="mord">0</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span></span></span></span></span><span class="mspace">&nbsp;</span><span class="mord text"><span class="mord">W</span></span><span class="mclose">)</span><span class="mopen">(</span><span class="mord">3</span><span class="mord">6</span><span class="mord">0</span><span class="mord">0</span><span class="mspace">&nbsp;</span><span class="mord text"><span class="mord">s</span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.1141079999999999em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">1</span><span class="mord"><span class="mord">0</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span></span></span></span></span><span class="mspace">&nbsp;</span><span class="mord text"><span class="mord">J</span></span><span class="mord">/</span><span class="mord text"><span class="mord">s</span></span><span class="mclose">)</span><span class="mopen">(</span><span class="mord">3</span><span class="mord">6</span><span class="mord">0</span><span class="mord">0</span><span class="mspace">&nbsp;</span><span class="mord text"><span class="mord">s</span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span><span class="mord">.</span><span class="mord">6</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.8641079999999999em;vertical-align:0em;"></span><span class="mord">1</span><span class="mord"><span class="mord">0</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">6</span></span></span></span></span></span></span></span><span class="mord text"><span class="mord">J</span></span></span></span></span></span></p><h1 id="5-旋转运动和万有引力"><a class="markdownIt-Anchor" href="#5-旋转运动和万有引力"></a> 5. 旋转运动和万有引力</h1><h2 id="51-角的单位"><a class="markdownIt-Anchor" href="#51-角的单位"></a> 5.1. 角的单位</h2><p>在物理学中，角度通常用弧度（Radian）来表示。弧度是一个角度单位，它定义为半径等于圆弧长度的角度。弧度的符号是 rad。</p><p>但在日常生活中，我们通常使用度（Degree）来表示角度。一个圆有 360 度，一个弧度等于 180/π 度。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>rad</mtext><mo>=</mo><mtext>degree</mtext><mo>⋅</mo><mfrac><mi>π</mi><mn>180</mn></mfrac></mrow><annotation encoding="application/x-tex">\text{rad} = \text{degree} \cdot \frac{\pi}{180}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord text"><span class="mord">rad</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord text"><span class="mord">degree</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.7935600000000003em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.10756em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span><span class="mord">8</span><span class="mord">0</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">π</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p>转数（Revolutions）是一个物体绕一个轴旋转的次数，通常用符号 rev 表示。一个完整的旋转是 360 度或<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn> 2</mn><mi>π</mi></mrow><annotation encoding="application/x-tex">2\pi</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span></span></span></span> 弧度。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>rev</mtext><mo>=</mo><mtext>rad</mtext><mo>⋅</mo><mfrac><mn>1</mn><mrow><mn>2</mn><mi>π</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">\text{rev} = \text{rad} \cdot \frac{1}{2\pi}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord text"><span class="mord">rev</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord text"><span class="mord">rad</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:2.00744em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p>rpm（Revolutions per minute）是一个物体每分钟绕轴旋转的次数。它是一个常用的单位，特别是在描述发动机和电机的转速时。</p><p>已知 1 转等于<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn> 2</mn><mi>π</mi></mrow><annotation encoding="application/x-tex">2\pi</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span></span></span></span> 弧度，1 分钟等于 60 秒，我们可以得到：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>rad/s</mtext><mo>=</mo><mtext>rpm</mtext><mo>⋅</mo><mfrac><mrow><mn>2</mn><mi>π</mi></mrow><mn>60</mn></mfrac></mrow><annotation encoding="application/x-tex">\text{rad/s} = \text{rpm} \cdot \frac{2\pi}{60}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord text"><span class="mord">rad/s</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.63889em;vertical-align:-0.19444em;"></span><span class="mord text"><span class="mord">rpm</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">⋅</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:2.00744em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">6</span><span class="mord">0</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><h2 id="52-角速度加速度"><a class="markdownIt-Anchor" href="#52-角速度加速度"></a> 5.2. 角速度 / 加速度</h2><p>角速度（Angular velocity）是一个物体绕轴旋转的速度。它是角度的变化率，通常用符号<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi> ω</mi></mrow><annotation encoding="application/x-tex">\omega</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">ω</span></span></span></span> 表示。角速度的国际单位是弧度每秒（rad / s）。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>ω</mi><mo>=</mo><mfrac><mi>v</mi><mi>r</mi></mfrac></mrow><annotation encoding="application/x-tex">\omega = \frac{v}{r}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">ω</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.7935600000000003em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.10756em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.02778em;">r</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>v</mi></mrow><annotation encoding="application/x-tex">v</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span></span></span></span> 是物体的线速度</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi></mrow><annotation encoding="application/x-tex">r</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span></span></span></span> 是物体绕轴旋转的半径</li></ul><p>角加速度（Angular acceleration）是角速度随时间的变化率，通常用符号<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi> α</mi></mrow><annotation encoding="application/x-tex">\alpha</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span></span></span></span> 表示。角加速度的国际单位是弧度每秒的平方（rad / s²）。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>α</mi><mo>=</mo><mfrac><mi>ω</mi><mi>t</mi></mfrac></mrow><annotation encoding="application/x-tex">\alpha = \frac{\omega}{t}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.7935600000000003em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.10756em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">t</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">ω</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><blockquote><p>以该公式为基底，我们也能推导出：</p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ω</mi><mo>=</mo><mi>α</mi><mi>t</mi></mrow><annotation encoding="application/x-tex">\omega = \alpha t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">ω</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.61508em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span><span class="mord mathnormal">t</span></span></span></span></li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>t</mi><mo>=</mo><mfrac><mi>ω</mi><mi>α</mi></mfrac></mrow><annotation encoding="application/x-tex">t = \frac{\omega}{\alpha}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.61508em;vertical-align:0em;"></span><span class="mord mathnormal">t</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.040392em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.695392em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0037em;">α</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">ω</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></li></ul><p>我们也知道角位移<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi> θ</mi></mrow><annotation encoding="application/x-tex">\theta</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">θ</span></span></span></span> 的公式：<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>θ</mi><mo>=</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mi>α</mi><msup><mi>t</mi><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">\theta = \frac{1}{2} \alpha t^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">θ</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span><span class="mord"><span class="mord mathnormal">t</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span>，</p><p>因此，<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>θ</mi><mo>=</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mi>α</mi><mo stretchy="false">(</mo><mfrac><mi>ω</mi><mi>α</mi></mfrac><msup><mo stretchy="false">)</mo><mn>2</mn></msup><mo>=</mo><mfrac><msup><mi>ω</mi><mn>2</mn></msup><mrow><mn>2</mn><mi>α</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">\theta = \frac{1}{2} \alpha (\frac{\omega}{\alpha})^2 = \frac{\omega^2}{2\alpha}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">θ</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span><span class="mopen">(</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.695392em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.0037em;">α</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">ω</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mclose"><span class="mclose">)</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.36292em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.01792em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span><span class="mord mathnormal mtight" style="margin-right:0.0037em;">α</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">ω</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8913142857142857em;"><span style="top:-2.931em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span>。</p><p>线位移<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi> s</mi></mrow><annotation encoding="application/x-tex">s</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">s</span></span></span></span> 的公式为：<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mo>=</mo><mi>r</mi><mi>θ</mi></mrow><annotation encoding="application/x-tex">s = r \theta</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">s</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal" style="margin-right:0.02778em;">θ</span></span></span></span>，所以<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi> s</mi><mo>=</mo><mi>r</mi><mfrac><msup><mi>ω</mi><mn>2</mn></msup><mrow><mn>2</mn><mi>α</mi></mrow></mfrac></mrow><annotation encoding="application/x-tex">s = r \frac{\omega^2}{2\alpha}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">s</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.36292em;vertical-align:-0.345em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.01792em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span><span class="mord mathnormal mtight" style="margin-right:0.0037em;">α</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">ω</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8913142857142857em;"><span style="top:-2.931em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span>。</p></blockquote><p>而线性速度和角速度之间的关系是：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>v</mi><mo>=</mo><mi>r</mi><mi>ω</mi></mrow><annotation encoding="application/x-tex">v = r \omega</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal" style="margin-right:0.03588em;">ω</span></span></span></span></span></p><p>线性加速度和角加速度之间的关系是：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>a</mi><mo>=</mo><mi>r</mi><mi>α</mi></mrow><annotation encoding="application/x-tex">a = r \alpha</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">a</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span></span></span></span></span></p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;物理学笔记，仅作为个人学习记录，不保证正确性。&lt;/p&gt;</summary>
    
    
    
    <category term="学术笔记" scheme="https://blog.cytrogen.icu/categories/%E5%AD%A6%E6%9C%AF%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="大学课程" scheme="https://blog.cytrogen.icu/tags/%E5%A4%A7%E5%AD%A6%E8%AF%BE%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>Docker 实践：构建 React 和 Express 项目</title>
    <link href="https://blog.cytrogen.icu/posts/de2c.html"/>
    <id>https://blog.cytrogen.icu/posts/de2c.html</id>
    <published>2024-03-01T06:11:13.000Z</published>
    <updated>2026-02-09T17:16:54.693Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期考虑了去学习如何部署自己的网站项目。根据网上的资料，决定先使用 Docker + Nginx 的组合来部署到本地上，之后再考虑部署到云端。</p><span id="more"></span><h2 id="项目结构"><a class="markdownIt-Anchor" href="#项目结构"></a> 项目结构</h2><p>我的项目前端是 React，后端是 Express、使用了 Socket.io 来实现实时通信、使用了 MongoDB 来存储数据。</p><p>Docker 容器的话需要为每个服务创建一个容器，所以我需要创建三个容器：前端、后端、数据库。同时还要创建一个 Nginx 容器来作为反向代理。</p><blockquote><p>Nginx 是一个高性能的 HTTP 和反向代理服务器，也是一个 IMAP/POP3/SMTP 代理服务器。</p><p>那么反向代理是什么意思呢？通常情况下我们如果访问一个网站，浏览器会直接向服务器发送请求，服务器再返回数据给浏览器。而反向代理是指，浏览器发送请求给 Nginx，Nginx 再将请求转发给服务器，服务器返回数据给 Nginx，Nginx 再返回数据给浏览器。</p><p>这么做的目的是为了隐藏服务器的真实 IP 地址，提高安全性。因为用户只能向 Nginx 发送请求，而不能直接向服务器发送请求。</p></blockquote><h2 id="dockerfile"><a class="markdownIt-Anchor" href="#dockerfile"></a> Dockerfile</h2><p>Docker 是一个开源的应用容器引擎，让开发者可以打包他们的应用以及依赖包到一个可移植的容器中，然后发布到任何流行的 Linux 机器上，也可以实现虚拟化。</p><blockquote><p>为什么要使用 Docker 呢？因为 Docker 可以让开发者摆脱「在我的机器上可以运行」的问题。</p><p>应用能够在任何地方运行，而不用担心环境问题。这样就可以避免因为环境问题导致的 bug，也可以避免因为环境问题导致的部署问题。</p></blockquote><p>Docker 的两个重要概念为镜像和容器。</p><p>镜像是一个只读的模板，可以想象为一个菜谱、详细列出了如何制作一道菜的步骤。就像你无法在菜谱上做菜一样，你也无法在镜像上做任何操作。</p><p>容器是镜像的一个实例，可以想象为一道菜。Docker（厨师）会根据镜像（菜谱）制作出容器（菜），并且可以对容器进行操作。</p><p>Dockerfile 则是编写菜谱的过程。它是一个文本文件，包含了一条条的指令，每一条指令构建一层，从而构建出一个完整的镜像。</p><p>每个服务都需要一个 Dockerfile 来构建镜像。我的项目结构中暂且只有前端和后端，所以我需要创建两个 Dockerfile、存放在这两个目录下。</p><pre><code class="language-dockerfile"># client/Dockerfile# 使用node:20.11.0-alpine作为基础镜像# alpine代表着这是一个轻量级的镜像、体积更小FROM node:20.11.0-alpine# 设置工作目录# 工作目录是容器中的一个目录，用来存放项目文件WORKDIR /app# 复制package.json到工作目录COPY package.json .# 安装依赖RUN npm install# 复制所有文件到工作目录COPY . .# 启动项目CMD ["npm", "start"]</code></pre><pre><code class="language-dockerfile">FROM node:20.11.0-alpineWORKDIR /appCOPY package.json .RUN npm installCOPY . .# EXPOSE指令通知了Docker、容器在运行时监听的端口# 这个指令并不会让容器的端口映射到宿主机的端口，如果需要映射，还需要在运行容器时使用-p参数EXPOSE 4000CMD ["node", "./bin/www"]</code></pre><blockquote><p>宿主机是指安装了 Docker 的机器，也就是我们的电脑。</p></blockquote><h2 id="docker-compose"><a class="markdownIt-Anchor" href="#docker-compose"></a> Docker Compose</h2><p>Docker Compose 是一个用来定义和运行多容器 Docker 应用的工具。通过一个单独的 <code>docker-compose.yml</code> 配置文件来配置应用的服务，然后使用 <code>docker-compose up</code> 命令来从配置文件中构建、启动、管理整个应用。</p><p>因为我需要创建多个容器，所以我需要一个 <code>docker-compose.yml</code> 文件来更好地管理这些容器。</p><p>在整个项目的根目录下创建一个 <code>docker-compose.yml</code> 文件：</p><pre><code class="language-yaml"># docker-compose.ymlversion: '3'# 定义服务services:  # 定义nginx服务  nginx:    image: nginx:alpine    ports: # 将容器的80端口映射到宿主机的80端口      - "80:80"    depends_on: # 依赖于client和server服务      - client      - server    volumes: # 将宿主机的nginx.conf文件映射到容器的/etc/nginx/conf.d/default.conf文件      # 这里的nginx.conf文件之后会提到      - ./nginx.conf:/etc/nginx/conf.d/default.conf    networks: # 将nginx服务加入到app-network网络中      - app-network  client:    build: ./client # 使用client目录下的Dockerfile构建镜像    ports:      - "3000:3000"    networks:      - app-network  server:    build: ./server    ports:      - "4000:4000"    networks:      - app-network  # 定义mongodb服务  mongodb:    image: mongo    ports: # 将容器的27017端口映射到宿主机的28017端口，之后会提到为什么端口号不一样      - "28017:27017"    volumes: # 将mongodb_data卷挂载到/data/db目录      - mongodb_data:/data/db    networks:      - app-networkvolumes: # 定义mongodb_data卷  mongodb_data:networks:  app-network: # 定义app-network网络    driver: bridge</code></pre><blockquote><p>卷是一种数据持久化和数据共享的机制。它可以将宿主机的目录挂载到容器中，这样容器中的数据就可以持久化到宿主机上了。 即使容器被删除，宿主机上的数据也不会丢失。</p><p>网络定义了容器之间如何相互通信。每个网络都代表了一个独立的虚拟网络，容器可以连接到这个网络上，从而实现容器之间的通信。<code>bridge</code> 类型会给容器分配一个 IP 地址，这样容器之间就可以通过 IP 地址相互通信。不同 <code>bridge</code> 类型的网络是隔离的，即使是同一台宿主机上的容器也不能相互通信。</p></blockquote><h4 id="配置nginx"><a class="markdownIt-Anchor" href="#配置nginx"></a> 配置 Nginx</h4><p>Nginx 的配置文件是 <code>nginx.conf</code>，这个文件需要放在 <code>docker-compose.yml</code> 文件所在的目录下。</p><pre><code class="language-nginx">server {    listen 80;  # 告诉Nginx监听80端口    location / { # 当访问根路径时        proxy_pass http://client:3000; # 将请求转发到client服务的3000端口    }    location /api/ { # 当访问/api路径时        proxy_pass http://server:4000; # 将请求转发到server服务的4000端口    }    location /socket.io/ { # 当访问/socket.io路径时        proxy_pass http://server:4000; # 将请求转发到server服务的4000端口        proxy_http_version 1.1; # 使用HTTP/1.1协议        proxy_set_header Upgrade $http_upgrade; # 设置请求头，和WebSocket有关        proxy_set_header Connection 'upgrade';    }}</code></pre><h4 id="mongodb"><a class="markdownIt-Anchor" href="#mongodb"></a> MongoDB</h4><p>Docker 容器中的 MongoDB 服务不同于平常的 MongoDB 服务。通常服务端连接 MongoDB 的地址是 <code>localhost:27017</code>，但是在 Docker 容器中，要使用 <code>mongodb:27017</code>。</p><p>由于我的宿主机上已经有一个 MongoDB 服务在运行，所以我将容器的 27017 端口映射到了宿主机的 28017 端口。这样便可以避免端口冲突、使用宿主机上的 MongoDB Compass 直接连接 <code>localhost:28017</code> 来管理容器中的 MongoDB 服务。</p><h2 id="构建和运行"><a class="markdownIt-Anchor" href="#构建和运行"></a> 构建和运行</h2><p>首先要构建整个应用：</p><pre><code class="language-bash">docker-compose build</code></pre><blockquote><p>如果是想要构建单个服务，可以使用 <code>docker-compose build 服务名</code>。</p><p>服务名就是 <code>docker-compose.yml</code> 文件中定义的服务名。</p></blockquote><p>然后运行整个应用：</p><pre><code class="language-bash">docker-compose up</code></pre><blockquote><p>如果想要停止应用，使用 <code>docker-compose down</code>。</p><p>和 <code>docker-compose build</code> 一样，如果是想要运行 / 停止单个服务，可以使用 <code>docker-compose up/down 服务名</code>。</p></blockquote><p>运行后就可以在浏览器中访问 <code>localhost</code> 来查看应用了。</p><p>但是以上步骤只是在本地运行，并且我也没有使用开发环境。部署到云端、使用生产环境还需要更多的实践，之后再说。</p></body></html>]]></content>
    
    
    <summary type="html">本文是一篇 Docker 全栈项目实践教程，详细介绍了如何将一个包含 React、Express 和 MongoDB 的应用进行容器化。文章从为前端和后端服务编写独立的 Dockerfile 开始，到使用 Docker Compose 统一编排前端、后端、数据库以及 Nginx 四个容器，一步步带你完成整个部署流程。内容涵盖 docker-compose.yml 的详细配置、Nginx 作为反向代理的设置（包括对 Socket.io 的支持），以及容器网络和数据卷的使用，旨在帮助开发者为复杂的多服务应用搭建一个隔离、可移植的本地开发环境。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Docker" scheme="https://blog.cytrogen.icu/tags/Docker/"/>
    
    <category term="全栈实践" scheme="https://blog.cytrogen.icu/tags/%E5%85%A8%E6%A0%88%E5%AE%9E%E8%B7%B5/"/>
    
  </entry>
  
  <entry>
    <title>React 的 Markdown 渲染</title>
    <link href="https://blog.cytrogen.icu/posts/c0fc.html"/>
    <id>https://blog.cytrogen.icu/posts/c0fc.html</id>
    <published>2024-02-21T04:11:13.000Z</published>
    <updated>2026-02-09T17:16:55.001Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>项目需求中有一个功能是支持 Markdown 渲染，尽量仿照 ChatGPT、Claude 的效果。</p><p>该文章的目的是记录我在实现这个功能时遇到的问题和解决方案。</p><span id="more"></span><h2 id="react-markdown"><a class="markdownIt-Anchor" href="#react-markdown"></a> <code>react-markdown</code></h2><p>先安装 <code>react-markdown</code>。</p><pre><code class="language-bash">npm install react-markdown</code></pre><p>此处运用 <code>react-markdown</code> 库的官方示例中的文本来进行测试：</p><pre><code class="language-plaintext"># A demo of `react-markdown``react-markdown` is a markdown component for React.👉 Changes are re-rendered as you type.👈 Try writing some markdown on the left.## Overview* Follows [CommonMark](https://commonmark.org)* Optionally follows [GitHub Flavored Markdown](https://github.github.com/gfm/)* Renders actual React elements instead of using `dangerouslySetInnerHTML`* Lets you define your own components (to render `MyHeading` instead of `'h1'`)* Has a lot of plugins## ContentsHere is an example of a plugin in action([`remark-toc`](https://github.com/remarkjs/remark-toc)).**This section is replaced by an actual table of contents**.## Syntax highlightingHere is an example of a plugin to highlight code:[`rehype-highlight`](https://github.com/rehypejs/rehype-highlight).```jsimport React from 'react'import ReactDOM from 'react-dom'import Markdown from 'react-markdown'import rehypeHighlight from 'rehype-highlight'const markdown = `# Your markdown here`ReactDOM.render(  &lt;Markdown rehypePlugins={[rehypeHighlight]}&gt;{markdown}&lt;/Markdown&gt;,  document.querySelector('#content'))\```&gt; Pretty neat, eh?## GitHub flavored markdown (GFM)For GFM, you can *also* use a plugin:[`remark-gfm`](https://github.com/remarkjs/react-markdown#use).It adds support for GitHub-specific extensions to the language:tables, strikethrough, tasklists, and literal URLs.These features **do not work by default**.👆 Use the toggle above to add the plugin.| Feature    | Support              || ---------: | :------------------- || CommonMark | 100%                 || GFM        | 100% w/ `remark-gfm` |~~strikethrough~~* [ ] task list* [x] checked itemhttps://example.com## HTML in markdown⚠️ HTML in markdown is quite unsafe, but if you want to support it, you canuse [`rehype-raw`](https://github.com/rehypejs/rehype-raw).You should probably combine it with[`rehype-sanitize`](https://github.com/rehypejs/rehype-sanitize).&lt;blockquote&gt;  👆 Use the toggle above to add the plugin.&lt;/blockquote&gt;## ComponentsYou can pass components to change things:```markdownimport React from 'react'import ReactDOM from 'react-dom'import Markdown from 'react-markdown'import MyFancyRule from './components/my-fancy-rule.js'const markdown = `# Your markdown here`ReactDOM.render(  &lt;Markdown    components={{      // Use h2s instead of h1s      h1: 'h2',      // Use a component instead of hrs      hr(props) {        const {node, ...rest} = props        return &lt;MyFancyRule {...rest} /&gt;      }    }}  &gt;    {markdown}  &lt;/Markdown&gt;,  document.querySelector('#content'))/```</code></pre><div class="danger"><p>测试文本中也有代码块，但是因为我用的是 Hexo 写的博客，这些原本应该在（我自己设置的）代码块内的文本都被渲染成了代码块。</p><p>因此我在每个代码块的后面都加了个斜杠，以使其不被渲染成代码块。你们在测试时可以 <strong>将这些斜杠去掉</strong>。</p></div><pre><code class="language-jsx">import ReactMarkdown from "react-markdown";function App() {    const markdownContent = `{刚才说的Markdown测试文本}`;    return (        &lt;&gt;            &lt;ReactMarkdown&gt;{markdownContent}&lt;/ReactMarkdown&gt;        &lt;/&gt;    );}</code></pre><p>显示出来的效果（记得将 <code>markdownContent</code> 的值替换掉）：</p><p><img src="/posts/c0fc/1.webp" alt="img.png" loading="lazy"></p><p>可以看出和 Typora 或者 GitHub 的渲染效果有一些差异，比方说代码块和普通文字的样式过于贴近，我们还是更适用于有着明显背景色以及代码高亮的代码块。</p><p>并且像是表格、任务列表、删除线等特殊样式也没有被渲染出来。</p><h2 id="remark-gfm"><a class="markdownIt-Anchor" href="#remark-gfm"></a> <code>remark-gfm</code></h2><p>其实测试文本都告诉了我们为什么：那些是 GFM，也就是 GitHub Flavored Markdown 的特性，而 <code>react-markdown</code> 默认是不支持 GFM 的。</p><p>所以我们需要安装 <code>remark-gfm</code> 插件来支持 GFM：</p><pre><code class="language-bash">npm install remark-gfm</code></pre><p><code>react-markdown</code> 引用插件的方式也很简单：</p><pre><code class="language-jsx">import remarkGfm from "remark-gfm";// ...&lt;ReactMarkdown remarkPlugins={[remarkGfm]}&gt;{markdownContent}&lt;/ReactMarkdown&gt;</code></pre><p>展现出来的效果：</p><p><img src="/posts/c0fc/2.webp" alt="img.png" loading="lazy"></p><p>看到这里，你肯定很是疑惑：表格的边框呢？？</p><p>如果我们用开发者工具查看这个表格的样式，会发现表格确确实实被渲染成 <code>table</code> 标签，但是 User Agent Stylesheet 中的样式对 <code>table</code> 标签做了一些处理。 所以我们需要自己写一些样式来覆盖这些默认样式：</p><pre><code class="language-css">table {    border-spacing: 0 !important;    border-collapse: collapse !important;    border-color: inherit !important;    display: block !important;    width: max-content !important;    max-width: 100% !important;    overflow: auto !important;}tbody, td, tfoot, th, thead, tr {    border-color: inherit !important;    border-style: solid !important;    border-width: 2px !important;}</code></pre><p>把所有的样式统统加上 <code>!important</code>，这样就可以覆盖掉 User Agent Stylesheet 中的样式了。</p><p>再次展现出来的效果：</p><p><img src="/posts/c0fc/3.webp" alt="img.png" loading="lazy"></p><div class="danger"><p>HTML 支持因为安全性考虑，我决定不使用，所以这里就不再展示了。</p></div><p>这样我们就完成了一个简单的 Markdown 渲染功能。不过在这个需求中有一个最为重要的功能：代码块的高亮。</p><h2 id="代码块的高亮"><a class="markdownIt-Anchor" href="#代码块的高亮"></a> 代码块的高亮</h2><p>因为项目的要求，代码块必须是突显出来、语句高亮的，这对行内代码块也一样。</p><p>这里我们可以使用 <code>react-syntax-highlighter</code>。</p><pre><code class="language-bash">npm install react-syntax-highlighter</code></pre><p><code>react-syntax-highlighter</code> 具有两个引擎：<code>prism</code> 和 <code>highlight.js</code>。两者的区别详细可以直接去网上搜索。</p><p>这里我们使用 <code>prism</code> 引擎以及 <code>oneDark</code> 主题：</p><pre><code class="language-jsx">import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism";</code></pre><p>在 <code>ReactMarkdown</code> 的 <code>components</code> 属性中，我们可以自定义代码块的渲染方式。如果你看过网上的其他教程，近乎清一色的都是这样写的：</p><pre><code class="language-jsx">&lt;ReactMarkdown    remarkPlugins={[remarkGfm]}    components={{        code({ node, inline, className, children, ...props }) {            const match = /language-(\w+)/.exec(className || '')            return !inline &amp;&amp; match ? (                &lt;SyntaxHighlighter                    style={nightOwl}                    language={match[1]}                    PreTag="div"                    children={String(children).replace(/\n$/, '')}                    {...props}                /&gt;            ) : (                &lt;code className={className} {...props} children={children} /&gt;            )        }    }}&gt;    {markdownContent}&lt;/ReactMarkdown&gt;</code></pre><p>这里我们自定义了 <code>code</code> 组件的渲染行为。</p><blockquote><p><code>code({ node, inline, className, children, ...props }) {}</code> 中的参数们分别表示了：</p><ul><li><code>node</code>：当前节点</li><li><code>inline</code>：是否是行内代码块</li><li><code>className</code>：类名</li><li><code>children</code>：子节点（代码块中的内容）</li><li><code>...props</code>：其他属性</li></ul></blockquote><p>接着我们使用正则表达式来匹配 <code>className</code> 中的 <code>language-xxx</code>，如果匹配到并且不是行内代码块，就使用 <code>SyntaxHighlighter</code> 来渲染代码块，否则使用默认的 <code>code</code> 标签。</p><p><em><strong>但是！！！！</strong></em></p><p><code>inline</code> 属性在新版本的 <code>react-markdown</code> 中已经被废弃、不会作为参数传入了！！！</p><p>这让当时的我非常头疼，网上的资料翻了翻也没有找到解决方案，一时选择去解决另一个问题：没有定义语言的代码块的渲染。</p><p>代码块被渲染后，和行内代码块最大的区别是外面贴了一套 <code>pre</code> 标签。由于 <code>code</code> 标签作为子标签无法从 <code>props</code> 中获取到父标签的样式，但是反过来想，<code>pre</code> 标签是可以获取到 <code>code</code> 标签的样式的呀！</p><p>于是我嘎嘎乱写：</p><pre><code class="language-jsx">&lt;Markdown    remarkPlugins={[remarkGfm]}    components={{        pre({node, className, children, ...props}) {            if (children["type"] === "code") {                try {                    const match = children["props"]["className"].match(/language-(\w+)/)                    return (                        &lt;pre&gt;                            &lt;SyntaxHighlighter                                style={oneDark}                                language={match[1]}                                PreTag="div"                                showLineNumbers                                wrapLongLines                                children={String(children["props"]["children"]).replace(/\n$/, '')}                            /&gt;                        &lt;/pre&gt;                    )                } catch (e) {                    return (                        &lt;pre&gt;                            &lt;SyntaxHighlighter                                style={oneDark}                                language="python"                                PreTag="div"                                showLineNumbers                                wrapLongLines                                children={String(children["props"]["children"]).replace(/\n$/, '')}                            /&gt;                        &lt;/pre&gt;                    )                }            }        }    }}&gt;    {markdownContent}&lt;/Markdown&gt;</code></pre><p>直接在 <code>pre</code> 标签中判断 <code>children</code> 的类型，如果是 <code>code</code> 那就肯定是代码块了，然后再去匹配 <code>className</code> 中的语言类型。</p><p>如果匹配不到就会导致错误，所以我临时加了一个 <code>try...catch</code> 语句，匹配不到的话就默认渲染成 <code>python</code> 语言的代码块吧。</p><p>效果还是不错的：</p><p><img src="/posts/c0fc/4.webp" alt="img.png" loading="lazy"></p><h2 id="后话"><a class="markdownIt-Anchor" href="#后话"></a> 后话</h2><p>这个需求的实现还是有一些问题的，比方说行内代码块的渲染就没有解决、 <code>try...catch</code> 语句并不是一个好的解决方案，以及没有定义语言就默认渲染成 <code>python</code> 语言的代码块的技术债太鬼畜了！</p><p>但是由于项目的时间紧迫，我也没有再去深究这个问题。或许以后时间充裕了我会再去解决这个问题。以后再说吧。</p></body></html>]]></content>
    
    
    <summary type="html">本文是一篇在 React 中实现 Markdown 渲染的实战教程，重点解决了新版 react-markdown 库中代码高亮的难题。文章首先介绍了如何使用 react-markdown 和 remark-gfm 插件来支持 GitHub 风格的 Markdown（如表格、删除线）。核心部分针对 react-markdown 新版废弃 inline 属性导致旧教程失效的问题，提供了一个创新的解决方案：通过自定义 pre 组件来准确识别并使用 react-syntax-highlighter 渲染代码块。本文为希望在 React 项目中实现现代化 Markdown 渲染的开发者提供了一套与时俱进的实用方法。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="JavaScript" scheme="https://blog.cytrogen.icu/tags/JavaScript/"/>
    
    <category term="React.js" scheme="https://blog.cytrogen.icu/tags/React-js/"/>
    
  </entry>
  
  <entry>
    <title>React 的 Textarea 高度自适应</title>
    <link href="https://blog.cytrogen.icu/posts/14d5.html"/>
    <id>https://blog.cytrogen.icu/posts/14d5.html</id>
    <published>2024-02-20T04:11:13.000Z</published>
    <updated>2026-02-09T17:16:55.001Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>上次提到过我接触了一个新项目，是校友们策划的一个类 ChatGPT 的项目，我负责前端部分，用的是 React + TailwindCSS 的组合。 我这个刚接触 React 一个月的小白肯定是搓手等着上手、跃跃欲试。</p><p>像是 ChatGPT、Claude，甚至是 Discord 这样的聊天室 App，输入框都是能够让用户换行、输入代码块的。我们的项目也不例外。 但是，<code>textarea</code> 组件就算是默认单行，换行时也会向下增加高度，导致脱离原本的父容器，甚至跑到屏幕外面去。</p><span id="more"></span><h2 id="最终结果"><a class="markdownIt-Anchor" href="#最终结果"></a> 最终结果</h2><p><img src="/posts/14d5/result.webp" alt="result" loading="lazy"></p><h2 id="环境"><a class="markdownIt-Anchor" href="#环境"></a> 环境</h2><p>先说父容器的样式，一个带了 <code>flex</code> 的 <code>div</code>：</p><pre><code class="language-jsx">&lt;div className="flex flex-col h-full"&gt;    &lt;div className="flex-1"&gt;{/* 信息内容 */}&lt;/div&gt;        {/* 主角 */}    &lt;Textbox /&gt;&lt;/div&gt;</code></pre><p>而 <code>Textbox</code> 组件的样式差不多是这样的：</p><pre><code class="language-jsx">&lt;div className="flex items-center w-full"&gt;    &lt;textarea        name="message"        className="w-full resize-none"        placeholder="Type a message..."        rows="1"    /&gt;    &lt;button&gt;发送&lt;/button&gt;&lt;/div&gt;</code></pre><p>正常来说，<code>textarea</code> 的大小是朝下无限增长的，但这不是我们想要的，我们希望它能够朝上增长、挤压信息内容的高度，直到达到一定高度后出现滚动条。</p><h2 id="解决方案"><a class="markdownIt-Anchor" href="#解决方案"></a> 解决方案</h2><p>为什么要特意说到父容器是一个带了 <code>flex</code> 的 <code>div</code> 呢？因为这是解决问题的关键。</p><p>包含了信息内容的兄弟元素会铺满剩余没有被 <code>Textbox</code> 组件占用的空间，而 <code>Textbox</code> 组件的高度是可以动态修改的。</p><p>也就是说，我们可以通过监听 <code>textarea</code> 的 <code>scrollHeight</code> 属性，来动态修改 <code>Textbox</code> 整个组件的高度，最终保持让它一直待在父容器的里面。</p><p>先创建一个 <code>useRef</code> 来引用 <code>textarea</code>：</p><pre><code class="language-jsx">const textareaRef = useRef(null);// ... &lt;textarea ref={textareaRef} /&gt;</code></pre><p>我们还需要创建一个 <code>useState</code> 来保存我们想要的高度：</p><pre><code class="language-jsx">const [height, setHeight] = useState(40);</code></pre><blockquote><p>这里的 <code>40</code> （像素）是我自己设定的一个最小高度。</p></blockquote><p>创建 <code>useEffect</code> 来监听 <code>textarea</code> 的 <code>scrollHeight</code> 属性：</p><pre><code class="language-jsx">useEffect(() =&gt; {    const handleResize = () =&gt; {        const textareaElement = textareaRef.current;        textareaElement.style.height = "auto";        textareaElement.style.height = `${textareaElement.scrollHeight}px`;        setHeight(Math.max(40, textareaElement.scrollHeight));    }        const textareaElement = textareaRef.current;    textareaElement.addEventListener("input", handleResize);        return () =&gt; textareaElement.removeEventListener("input", handleResize);}, []);</code></pre><p>在 <code>handleResize</code> 中，我们先将 <code>textarea</code> 的高度设置为 <code>auto</code>，这样就可以让它自己决定高度，然后用 <code>setHeight</code> 来保存 <code>scrollHeight</code> 的值。</p><blockquote><p><code>Math.max(40, textareaElement.scrollHeight)</code> 是为了保证 <code>textarea</code> 的高度不会小于 <code>40</code> 像素，也就是我刚才说的，我自己设定的一个最小高度。</p></blockquote><p><code>handleResize</code> 需要在用户输入时触发，所以还要用 <code>addEventListener</code> 来监听 <code>input</code> 事件。</p><p>最后别忘了卸载监听器。</p><p>那么我们得到的 <code>height</code> 要用在哪里呢？<code>Textbox</code> 组件的最外层 <code>div</code> 上：</p><pre><code class="language-jsx">&lt;div className="flex items-center w-full" style={{ height: `${height}px` }}&gt;    &lt;textarea        name="message"        className="w-full resize-none"        placeholder="Type a message..."        rows="1"        ref={textareaRef}    /&gt;    &lt;button&gt;发送&lt;/button&gt;&lt;/div&gt;</code></pre><p>每次用户输入，<code>height</code> 都会被更新，<code>Textbox</code> 组件的高度也会被更新。拥有着固定高度的 <code>Textbox</code> 组件能够在 Flexbox 布局中自由伸缩，装有信息内容的兄弟元素则会根据 <code>Textbox</code> 组件的高度自动调整。</p><p>不过呢还是有需求没能完成：<code>Textbox</code> 组件要在伸展到一定高度时出现滚动条。之后再说吧。</p><h2 id="后话"><a class="markdownIt-Anchor" href="#后话"></a> 后话</h2><p>其实之后测试时发现还是有问题的，原因很简单：</p><pre><code class="language-jsx">onKeyDown={e =&gt; {    if (e.key === "Enter" &amp;&amp; !e.shiftKey) {        e.preventDefault();  // 我当时忘记加这一句了        handleSendMessage(e.target.value)            .then(r =&gt; console.log("Message sent"))            .catch(e =&gt; console.error("Error in sending message:", e));    }}}</code></pre><p>因为没有添加 <code>e.preventDefault()</code> 导致每次发送消息时都会多出一行，<code>scrollHeight</code> 也会多出一行，最终导致 <code>Textbox</code> 组件的高度一直在增加、甚至超出父容器。</p><p>切记不要忘了啊！血的教训！让我白白修了一天的 bug！</p><p><code>handleSize</code> 也可以更新为：</p><pre><code class="language-jsx">const handleResize = e =&gt; {    e.target.style.height = `inherit`;    e.target.style.height = `${e.target.scrollHeight}px`;        if (e.target.scrollHeight &gt; 232) {        e.target.style.overflowY = "scroll";        e.target.style.height = "232px";    } else {        e.target.style.overflowY = "hidden";        e.target.style.height = Math.max(40, e.target.scrollHeight);    }}</code></pre><p>这样当 <code>scrollHeight</code> 超过 <code>232</code> 时（在我的案例中也就是 9 行），就会停止增加高度、出现滚动条。</p></body></html>]]></content>
    
    
    <summary type="html">本文是一篇在 React 中实现 textarea 高度自适应功能的实战教程，旨在模仿 ChatGPT 等现代聊天应用的输入框体验。教程详细讲解了如何利用 React Hooks (useRef, useEffect) 监听用户输入，通过动态计算 scrollHeight 来让文本框根据内容自动伸缩，并在达到最大高度后显示滚动条。文章还特别强调了在 Flexbox 布局下的实现技巧，并分享了一个因忘记 e.preventDefault() 而导致意外换行的常见“血泪教训”，为开发者提供了完整的实现方案和宝贵的避坑经验。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="JavaScript" scheme="https://blog.cytrogen.icu/tags/JavaScript/"/>
    
    <category term="React.js" scheme="https://blog.cytrogen.icu/tags/React-js/"/>
    
  </entry>
  
  <entry>
    <title>React + Express + Socket.io 之间的实时通信【2】：注册登录</title>
    <link href="https://blog.cytrogen.icu/posts/bb3e.html"/>
    <id>https://blog.cytrogen.icu/posts/bb3e.html</id>
    <published>2024-02-19T05:06:13.000Z</published>
    <updated>2026-02-09T17:16:54.997Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p><s>接连着昨日的年轻莽撞，今天</s> 继续研究如何去制作一个类 Slack、Discord 的网页聊天室 App。</p><p>其实这篇文在 1 月 23 日开始起草的，然后写代码写着写着就忘了写文。</p><p>再加上近期加入了一个新的项目，自己的项目不得不搁置一下。</p><span id="more"></span><h1 id="前端"><a class="markdownIt-Anchor" href="#前端"></a> 前端</h1><p>页面设计的工作我交给了 reactstrap 包，其实用 React-bootstrap 包、或者干脆直接引入 Bootstrap 的 CSS 文件都是可以的。</p><pre><code class="language-bash">npm install reactstrap</code></pre><p>仿制 Discord 的登录 &amp; 注册页面还是相当容易的：</p><p><img src="/posts/bb3e/login.webp" alt="登录页面" loading="lazy"></p><p><img src="/posts/bb3e/Register.webp" alt="注册页面" loading="lazy"></p><p>这里就不说写页面的具体细节，只挑几个我花了时间去搞的地方说。</p><h2 id="1-卡片居中"><a class="markdownIt-Anchor" href="#1-卡片居中"></a> 1. 卡片居中</h2><p>居中，是前端界最老生常谈的话题之一。浏览器上搜索「居中」一词，会发现十年前大家在聊怎么居中，几年后在聊怎么居中，现在还有 GitHub 网页上出现没有好好居中的标签。</p><p>Discord 的登录 / 注册页面的设计方案很简单，正中间一个卡片，上面嘎嘎放表单即可。</p><p>我的实现：</p><pre><code class="language-jsx">&lt;Container className='d-flex vh-100'&gt;    &lt;Row className='m-auto align-self-center'&gt; ... &lt;/Row&gt;&lt;/Container&gt;</code></pre><p>这里推荐一下微软近期出的强力工具：PowerToys，用快捷键 <code>Windows</code> + <code>Shift</code> + <code>C</code> 就可以在屏幕上吸色了，吸的 RGB 值正好用来给我们的标签添加颜色样式。</p><h2 id="2-生日日期选择"><a class="markdownIt-Anchor" href="#2-生日日期选择"></a> 2. 生日日期选择</h2><p><img src="/posts/bb3e/Birthday_Select.webp" alt="" loading="lazy"></p><p>这个其实就是：</p><pre><code class="language-jsx">&lt;Container&gt;    &lt;Row xs='3'&gt;        &lt;Col className='ps-0 pe-1'&gt;&lt;/Col&gt;        &lt;Col className='px-1'&gt;&lt;/Col&gt;        &lt;Col className='ps-1 pe-0'&gt;&lt;/Col&gt;    &lt;/Row&gt;&lt;/Container&gt;</code></pre><p>不过重点不在这里，而在 JSX 中用 <code>.map()</code> 方法生成下拉选项。</p><p>先看一眼年份的：</p><pre><code class="language-jsx">const currentYear = new Date().getFullYear();const years = [];for (let i = 0; i &lt; 100; i++) {    years.push(currentYear - i);}// ...&lt;Input&gt;    {years.map(        year =&gt; (            &lt;option key={year}&gt;{year}&lt;/option&gt;        )    )}&lt;/Input&gt;</code></pre><blockquote><p>其实可以再简化一些，不过能看就行！</p></blockquote><p>月份的逻辑相同：</p><pre><code class="language-jsx">const months = [    'January', 'February', 'March', 'April', 'May', 'June',    'July', 'August', 'September', 'November', 'December'];// ...&lt;Input&gt;    {months.map(        month =&gt; (            &lt;option key={month}&gt;{month}&lt;/option&gt;        )    )}&lt;/Input&gt;</code></pre><p>日期就更简单了：</p><pre><code class="language-jsx">&lt;Input&gt;    {Array.from({ length: 31 }, (_, i) =&gt; i + 1).map(        day =&gt; (            &lt;option key={day} style={{ color: 'rgba(117,122,129)' }}&gt;{day}&lt;/option&gt;        )    )}&lt;/Input&gt;</code></pre><blockquote><p>看着没做每个月内有多少天的逻辑对吧？其实 Discord 也是这样设计的。这种逻辑交给后端就好啦~</p></blockquote><p>不过我研究了会儿都没实现出来 Discord 的效果：用户还未选择时，年月份三个下拉框都默认显示「年」/「月」/「日」。</p><h2 id="3-数据处理"><a class="markdownIt-Anchor" href="#3-数据处理"></a> 3. 数据处理</h2><p>今日的重头戏。用户在注册时这些数据总要传到服务端去的吧？今天就是来解决这个的。</p><p>先装包：</p><pre><code class="language-bash">npm install react-redux @reduxjs/toolkit</code></pre><p>Redux 的知识点可以去看我之前的一篇关于 React 的文章。Redux 的概念可以用三个东西来概括：Action、Store 和 Reducer。每当用户与某个组件交互时就会触发 Action（比方说点击按钮），接着 Action 会携带着数据去往 Store 进行存储，途中遇到 Reducer、状态被按照我们要求的进行了更改，最终回到 Store 这个大仓库手里。</p><p>为什么我们要使用 Redux 呢？如果我们需要在客户端向服务端发送数据，Redux 可以更好地帮我们管理这些数据，并且 Store 还是全局的，在任一组件中我们都可以访问 Store 中的数据。</p><p>我们可以用 @reduxjs / toolkit 包配置 Redux Store。新建一个文件 <code>store.js</code>：</p><pre><code class="language-js">import { configureStore } from "@reduxjs/toolkit";const store = configureStore({ reducers: {} });export default store;</code></pre><p>不过在完成这段代码之前，我们需要初始化状态。我们的状态需要什么样的数据存储其中？作为一个可以登陆注册的网页 App，我们需要存储用户的登录状态、用户的信息、错误信息等等。这些存储的动作都需要一个 Reducer 来完成。</p><p>Redux 官网中在文档里使用了 <code>createSlice</code> 方法来创建 State Slice。</p><p>新建一个文件 <code>authSlice.js</code>：</p><pre><code class="language-jsx">import { createSlice } from "@reduxjs/toolkit";export const authSlice = createSlice({    name: "auth",    initialState: {        isAuthenticated: false,        user: {},        error: null    },    reducers: {        setCurrentUser: (state, action) =&gt; {            state.isAuthenticated = true;            state.user = action.payload;        },        setError: (state, action) =&gt; {            state.error = action.payload;        }    }});export const { setCurrentUser, setError } = authSlice.actions;export default authSlice.reducer;</code></pre><p>这下我们可以完成 <code>store.js</code> 了：</p><pre><code class="language-jsx">import { configureStore } from "@reduxjs/toolkit";import authSlice from "./reducers/authSlice";export default configureStore({    reducer: {        auth: authSlice    }});</code></pre><p>Store 和 Reducer 都有了，自然少不了 Action。</p><p>Socket.io 的连接逻辑我会在下一篇文章中讲解，这里我们只需要知道，当用户点击注册按钮时，我们需要将用户的信息发送到服务端。这个过程就是一个 Action。</p><p>目前我们只需要验证用户信息是否合法，所以只写了一个 Action：<code>authActions.js</code>。</p><p>验证用户信息需要使用到 Socket.io 来和服务端进行通信：</p><pre><code class="language-jsx">import socketIO from "socket.io-client";const socket = socketIO.connect("http://localhost:4000");</code></pre><blockquote><p>此处假设服务端的端口是 4000。</p></blockquote><h2 id="4-注册和登录"><a class="markdownIt-Anchor" href="#4-注册和登录"></a> 4. 注册和登录</h2><p>这两个页面的逻辑是一样的，都是用户输入信息后点击按钮，触发 Action，将用户信息发送到服务端。</p><p>在 Socket.io 的连接逻辑中，用户点击按钮后、信息会在客户端中被发送到服务端，服务端会对用户信息进行验证，如果验证通过，服务端会返回一个 Token 给客户端，客户端将 Token 存储到 Store 中；如果验证不通过，服务端则会返回一个错误信息给客户端。</p><p>这里只讲一下注册页面的逻辑。</p><pre><code class="language-jsx">import { useState } from "react";import { useDispatch } from "react-redux";import { useNavigate } from "react-router-dom";import { registerUser } from "./utils/actions/authActions";</code></pre><blockquote><p><code>useState</code> 是 React 的一个 Hook，用于在函数组件中使用状态。</p><p><code>useNavigate</code> 是 React Router 的一个 Hook，用于在函数组件中进行页面跳转。</p></blockquote><p><code>registerUser</code> 是等会儿我们会定义的 Action，先不写。</p><pre><code class="language-jsx">const Register = () =&gt; {    const dispatch = useDispatch();    const navigate = useNavigate();    const [userData, setUserData] = useState({        username: "",        emailAddress: "",        password: "",        birthYear: "",        birthMonth: "",        birthDay: ""    });}</code></pre><p><code>useState</code> 的用法是这样的：接受一个参数作为状态的初始值，比方说我们这里是一个字典，包含着注册页面中所有输入框的值。它会返回一个数组，第一个元素代表着状态的当前值，第二个元素代表着一个函数，用于更新状态。</p><p>每当用户输入信息时，我们都应该更新状态。React 提供了一个 <code>onChange</code> 事件供我们使用：</p><pre><code class="language-jsx">const handleChange = e =&gt; {    setUserData({        ...userData,        [e.target.name]: e.target.value    });};// ...&lt;Input onChange={ handleChange } /&gt;</code></pre><blockquote><p>每次用户输入信息时，<code>handleChange</code> 函数都会被触发，而 <code>handleChange</code> 函数会调用 <code>setUserData</code> 函数，更新状态。</p></blockquote><p>表单被用户提交后，我们也需要触发一个 Action 来发送用户信息到服务端：</p><pre><code class="language-jsx">const handleSubmit = e =&gt; {    e.preventDefault();    dispatch(registerUser(userData, navigate));};// ...&lt;Form onSubmit={ handleSubmit } /&gt;</code></pre><blockquote><p><code>useDispatch</code> 是 React Redux 的一个 Hook，用于在函数组件中传递 Action。</p></blockquote><p>那么 <code>registerUser</code> 方法是怎么写的呢？</p><pre><code class="language-jsx">const registerUser = (userData, navigate) =&gt; {    return dispatch =&gt; {        socket.emit("register", userData);                socket.on("newRegisteredUser", data =&gt; {            data.status === "00000" ? navigate("/login") : console.log(data.message);        });    }};</code></pre><blockquote><p><code>socket.emit</code> 用于发送数据到服务端；<code>socket.on</code> 用于接收服务端返回的数据。</p></blockquote><p><code>registerUser</code> 方法会先发送用户填写的信息到服务端，接着监听服务端返回的数据。如果服务端返回的数据中 <code>status</code> 是 <code>00000</code>，则说明注册成功，我们就跳转到登录页面；如果不是，我们就在控制台打印出服务端返回的错误信息。</p><p>而在服务端中，我们需要接受名为 <code>register</code> 的事件、验证用户填写的信息，然后发送 <code>newRegisteredUser</code> 事件：</p><pre><code class="language-jsx">socket.on("register", async userData =&gt; {    const existingUser = await User.findOne({        emailAddress: userData.emailAddress,        username: userData.username    });    if (existingUser) {        console.log(`[U0102] User already exists: ${userData.username}`);        socket.emit("newRegisteredUser", {            status: "U0102",            message: "User already exists."        });        return;    }        await User.create({        emailAddress: userData.emailAddress,        username: userData.username,        password: userData.password,        DOBYear: userData.birthYear,        DOBMonth: MonthToNumber[userData.birthMonth],        DOBDay: userData.birthDay    })    console.log(`[00000] User registered: ${userData.username}`);        socketIO.emit("newRegisteredUser", {        status: "00000",        token: generateJWT(userData.username)    });});</code></pre><blockquote><p><code>User</code> 是一个 Mongoose 模型，用于操作 MongoDB 数据库。</p><pre><code class="language-js">const mongoose = require("mongoose");mongoose.connect("mongodb://localhost:27017/hotaru")    .then(() =&gt; console.log("Connected to MongoDB"))    .catch(err =&gt; console.error("Could not connect to MongoDB", err));module.exports = mongoose;</code></pre><pre><code class="language-js">const bcrypt = require( "bcrypt");const mongoose = require("./mongodb");const UserSchema = new mongoose.Schema({    emailAddress: {        type: String,        unique: true    },    username: {        type: String,        unique: true    },    password: {        type: String,        set(val) { return bcrypt.hashSync(val, 10) },        select: false    },    DOBYear: {        type: Number    },    DOBMonth: {        type: Number    },    DOBDay: {        type: Number    },    createTime: {        type: Date,        default: Date.now    }})const User = mongoose.model("User", UserSchema);module.exports = { User };</code></pre><blockquote><p><code>bcrypt</code> 是一个用于加密密码的包，不只是加密密码，我们验证用户登录时也会用到它。</p><p>最根本的原因是我们不会在数据库中存储用户的明文密码，要验证用户登陆的话，只能用加密后的用户输入的密码和数据库中的密码进行比对。</p></blockquote><p>我这里也根据网上的文章自己定义了一套错误码，未来可能会展开说说。</p></blockquote><p>这样，我们就完成了注册页面的逻辑。</p><p>登录页面的逻辑和注册页面的逻辑是一样的，只是在 <code>registerUser</code> 方法中，我们需要发送 <code>login</code> 事件，而在服务端中，我们需要接受名为 <code>login</code> 的事件：</p><pre><code class="language-js">const loginUser = (userData, navigate) =&gt; {    return dispatch =&gt; {        socket.emit("login", userData);        socket.on("loggedInUser", data =&gt; {            if (data.status === "00000") {                const { token } = data;                localStorage.setItem("jwtToken", token);                userData["token"] = token;                dispatch(setCurrentUser(userData));                navigate("/channels/@me");            } else {                console.log(data.message);            }        });    }};</code></pre><blockquote><p><code>localStorage</code> 是浏览器提供的一个 API，用于在浏览器中存储数据。这里存储了 JWT Token，以后会提到这是什么。</p></blockquote><pre><code class="language-js">socket.on("login", async userData =&gt; {    const existingUser = await User.findOne({        username: userData.username    });    if (!existingUser) {        console.log(`[U0201] User does not exist: ${userData.username}`);        socket.emit("loggedInUser", {            status: "U0201",            message: "User does not exist."        });        return;    }        bcrypt.compare(userData.password, existingUser.password, (err, confirmPassword) =&gt; {        if (err) {            console.error(err);            return;        }        if (!confirmPassword) {            console.log(`[U0202] Password is incorrect: ${userData.password}`);            socket.emit("loggedInUser", {                status: "U0202",                message: "Password is incorrect."            });            return;        }        console.log(`[00000] User logged in: ${userData.username}`);        socket.emit("loggedInUser", {            status: "00000",            token: generateJWT(userData.username)        });    });});</code></pre><p>一套组合拳下来，一旦用户的信息被验证成功，就会跳转到频道页面。</p></body></html>]]></content>
    
    
    <summary type="html">本文是 React + Express + Socket.io 实时通信应用教程的第二篇，重点实现用户的注册与登录功能。在前端，教程介绍了如何使用 Redux Toolkit (@reduxjs/toolkit) 管理认证状态，并通过 Socket.io 向后端发送用户数据。在后端，文章演示了如何使用 Mongoose (MongoDB) 建立用户模型，监听客户端事件，并利用 bcrypt 对密码进行哈希加密与验证。本教程完整地展示了一个包含前后端交互、数据库操作和安全实践的全栈用户认证流程。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="全栈实践" scheme="https://blog.cytrogen.icu/tags/%E5%85%A8%E6%A0%88%E5%AE%9E%E8%B7%B5/"/>
    
    <category term="JavaScript" scheme="https://blog.cytrogen.icu/tags/JavaScript/"/>
    
    <category term="Node.js" scheme="https://blog.cytrogen.icu/tags/Node-js/"/>
    
    <category term="Express.js" scheme="https://blog.cytrogen.icu/tags/Express-js/"/>
    
    <category term="React.js" scheme="https://blog.cytrogen.icu/tags/React-js/"/>
    
  </entry>
  
  <entry>
    <title>React + Express + Socket.io 之间的实时通信【1】：简单连接</title>
    <link href="https://blog.cytrogen.icu/posts/948f.html"/>
    <id>https://blog.cytrogen.icu/posts/948f.html</id>
    <published>2024-01-22T05:06:13.000Z</published>
    <updated>2026-02-09T17:16:54.997Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>在跟着 IBM 的课程学习全栈开发的时候，期间想到了我于两年前写的一个小项目，当时学习了 Python 的 Flask 框架，就异想天开地编写了一个基于频道的聊天室。当时并不知道实时通信的原理，只是简单地用 Flask 和 SQLite—— 连 Socket.io 都没用上 —— 实现了一个简单的类 Slack 聊天室。</p><p>现在见识到了更多的技术，年轻莽撞的我自然是想要重写这个项目。不过具体能不能完成，就是另外一回事了。</p><span id="more"></span><div class="danger"><p>阅读本文需知道：</p><ul><li>我使用 Jetbrains WebStorm 作为 IDE，新建项目也是使用了 WebStorm 提供的模板</li><li>写这个文章时我安装的 Node.js 版本是 <strong> v20.11.0</strong>、npm 版本是 <strong> 10.2.4</strong></li></ul></div><h1 id="项目结构"><a class="markdownIt-Anchor" href="#项目结构"></a> 项目结构</h1><p>首先，我们需要新建两个文件夹（废话）：一个是用于存放前端代码的 <code>client</code> 文件夹，另一个是用于存放后端代码的 <code>server</code> 文件夹。</p><p>在 WebStorm 中，先在 <code>client</code> 文件夹中新建一个 React 项目，然后在 <code>server</code> 文件夹中新建一个 Express 项目。</p><p>总体的项目结构差不多是这样的：</p><pre><code class="language-plaintext">总项目（其实不放在一起也OK）/├─ client/│  ├─ node_modules/│  ├─ public/│  ├─ src/│  │  ├─ App.js│  │  ├─ index.js│  ├─ package.json├─ server/│  ├─ bin/│  │  ├─ www│  ├─ node_modules/│  ├─ public/│  ├─ routes/│  ├─ views/│  ├─ app.js│  ├─ package.json</code></pre><ul><li>在 <code>client</code> 文件夹中，最重要的便是 <code>src</code> 文件夹，其中的 <code>App.js</code> 和 <code>index.js</code> 是 React 项目的入口文件</li><li>在 <code>server</code> 文件夹中，最重要的便是 <code>app.js</code> 文件。不过由于 <code>bin/www</code> 文件是服务器的启动关键，所以需要修改它而不是 <code>app.js</code> 文件</li></ul><h1 id="后端"><a class="markdownIt-Anchor" href="#后端"></a> 后端</h1><p>我们率先开始装包：</p><pre><code class="language-bash">npm install socket.io cors nodemon</code></pre><p>不装 Express 包自然是因为 WebStorm 已经帮我们装好了，哈哈。</p><p>Socket.io 包是我们这次项目的核心。它能够轻松地实现实时通信，也就是多人聊天的基础。Cors 包用于解决跨域问题，比方说我们的前端项目是运行在 <code>localhost:3000</code>，而后端项目是运行在 <code>localhost:4000</code>，这样就会出现跨域问题。而 Nodemon 包是用于自动重启服务器的，这样我们就不用每次修改代码后都手动重启服务器了，懒人福音。</p><p>我们直接来看 <code>bin/www</code> 文件。它的一行代码便告诉了我们它的作用：</p><pre><code class="language-javascript">/** * Create HTTP server. */const server = http.createServer(app);</code></pre><p><code>bin/www</code> 创建了一个 HTTP 服务器，而 <code>app</code> 则是我们的 Express 应用。</p><p>在导入依赖的地方，我们先导入 Socket.io 和 Cors 包：</p><pre><code class="language-javascript">const cors = require('cors');const { Server } = require("socket.io");</code></pre><p>要想使用 Cors 包，我们就需要激活它：</p><pre><code class="language-javascript">app.use(cors());</code></pre><p>在 HTTP 服务器被创建之后，我们就需要创建 Socket.io 服务器了：</p><pre><code class="language-javascript">const socketIO = new Server(server, {    cors: {        origin: "http://localhost:3000"    }});</code></pre><p>此处的 <code>cors</code> 选项指定了 React 项目的默认端口，为我们之后的前后端通信提供了便利。</p><p>接下来，我们需要监听 Socket.io 服务器的连接事件：</p><pre><code class="language-javascript">socketIO.on("connection", (socket) =&gt; {    console.log(`A user connected: ${socket.id}`);        socket.on("disconnect", () =&gt; {        console.log(`A user disconnected: ${socket.id}`);    });});</code></pre><p>这个连接事件会在客户端连接到服务器时触发，打印出客户端的 ID。</p><p>最后我们要用上最先装的 Nodemon 包。进入 <code>package.json</code> 文件，找到 <code>scripts</code> 选项，将 <code>start</code> 选项改为：</p><pre><code class="language-json">{    "start": "nodemon ./bin/www"}</code></pre><p>至此，我们的 <code>server</code> 目录就可以先不管了。</p><h1 id="前端"><a class="markdownIt-Anchor" href="#前端"></a> 前端</h1><p>和后端一样，先来装包：</p><pre><code class="language-bash">npm install socket.io-client</code></pre><p>为啥不装 React 包呢？额…… 不皮了。</p><p>Socket.io-client 包是用于在前端连接到 Socket.io 服务器的。</p><p>其实前端的代码很简单，我们只需要在 <code>App.js</code> 中写入以下代码：</p><pre><code class="language-javascript">import socketIO from "socket.io-client";const socket = socketIO.connect("http://localhost:4000");</code></pre><p>好了，大功告成，就这么简单。</p><h1 id="后话"><a class="markdownIt-Anchor" href="#后话"></a> 后话</h1><p>最后只需要在两个项目中分别运行 <code>npm start</code>，然后打开浏览器窗口，访问 <code>localhost:3000</code> 就可以看到服务端的终端输出了。</p><p>为什么我要水这么一篇文章呢？因为我觉得这个项目的基础部分还是挺有意思的，而且我也想把我学到的东西记录下来，以便日后查阅。</p><p>好吧其实根本就是今天早上睡过头、压根没时间花在代码上，所以一整天就干了这么点实质性的东西。</p><p>水文章还是挺好玩的，以后有机会再水一篇。</p></body></html>]]></content>
    
    
    <summary type="html">本文是使用 React、Express 和 Socket.io 构建实时通信应用系列教程的第一篇，专注于搭建项目基础并建立简单的双向连接。教程将分别指导你如何配置 Express 后端服务器，包括安装 socket.io 和 cors、设置 connection 连接监听事件；以及如何在 React 前端应用中引入 socket.io-client 并成功连接到后端。本文为你清晰地展示了项目的第一步，为后续开发实时聊天等功能打下坚实基础。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="全栈实践" scheme="https://blog.cytrogen.icu/tags/%E5%85%A8%E6%A0%88%E5%AE%9E%E8%B7%B5/"/>
    
    <category term="JavaScript" scheme="https://blog.cytrogen.icu/tags/JavaScript/"/>
    
    <category term="Node.js" scheme="https://blog.cytrogen.icu/tags/Node-js/"/>
    
    <category term="Express.js" scheme="https://blog.cytrogen.icu/tags/Express-js/"/>
    
    <category term="React.js" scheme="https://blog.cytrogen.icu/tags/React-js/"/>
    
  </entry>
  
  <entry>
    <title>IBM 全栈开发【5】：Node.js &amp; Express 创建后端</title>
    <link href="https://blog.cytrogen.icu/posts/fed2.html"/>
    <id>https://blog.cytrogen.icu/posts/fed2.html</id>
    <published>2024-01-21T05:26:13.000Z</published>
    <updated>2026-02-09T17:16:54.717Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程，故此记录学习笔记。</p><span id="more"></span><h1 id="1-服务端javascript入门"><a class="markdownIt-Anchor" href="#1-服务端javascript入门"></a> 1. 服务端 JavaScript 入门</h1><p>客户端 - 服务端的应用程序（比如基于云的应用程序）通常由「前端」和「后端」组成。前端是指用户在浏览器中看到的应用程序的部分，后端是指在服务器上运行的应用程序的部分。</p><h2 id="11-后端"><a class="markdownIt-Anchor" href="#11-后端"></a> 1.1. 后端</h2><p>后端开发人员负责开发确保网站正常运行的技术，包括服务器端的应用程序、数据库和服务器。</p><ul><li>服务器由硬件和软件组成，它们与客户端进行通信并提供功能。多种类型的服务器可用于不同的目的：Web 服务器用于存储和提供网站的内容，数据库服务器用于存储和提供数据，应用程序服务器用于存储和提供应用程序的功能</li><li>数据库是一种用于存储和访问数据的软件。数据库服务器是一种用于存储和访问数据的服务器。数据库服务器可以存储和访问结构化数据（例如，关系数据库）和非结构化数据（例如，文本文件、图像和视频）</li><li>网页应用程序接口（API）允许两个软件之间相互通信。网络服务便是网页应用程序接口的一种、使用 HTTP 请求进行通信</li><li>编程语言是一种用于编写软件的语言。用于后端开发的编程语言包括 Java、Python、PHP、Ruby、JavaScript 和 C#</li><li>框架是一种用于编写软件的工具。框架提供了一组通用的功能，可以帮助开发人员编写软件。用于后端开发的框架包括 Spring、Django、Laravel、Ruby on Rails、<a href="http://Node.xn--jsASP-sn9h.NET">Node.js 和 ASP.NET</a></li><li>runtimes 是一种用于运行软件的工具，行为类似于微型操作系统，为应用程序的运行提供必要的资源。Node.js 就是后端 runtime 环境的一个例子</li></ul><p>Node.js 作为一种后端技术之所以如此流行，原因之一是它运行在谷歌 Chrome 浏览器的开源 V8 引擎上。V8 引擎也是在前端运行浏览器的引擎。大多数现代浏览器都使用 V8 引擎，因此，Node.js 和浏览器之间的代码兼容性很好。</p><h4 id="111-可扩展性"><a class="markdownIt-Anchor" href="#111-可扩展性"></a> 1.1.1. 可扩展性</h4><p>可扩展性对企业软件的成功至关重要。它受应用程序负载的影响，是后端的一大责任。而负载指的是并发用户、交易、数据量和其他因素的总和。</p><p>可扩展性是指应用程序在不影响性能的情况下动态处理负载增减的能力。</p><h2 id="12-nodejs"><a class="markdownIt-Anchor" href="#12-nodejs"></a> 1.2. Node.js</h2><p>Node.js 是一个运行在 V8 上的开源语言，它是 JavaScript 的服务器端实现。Node.js 由事件驱动，使用非阻塞 I / O 模型，这使得它非常轻量级、高效和可扩展。</p><p>Node.js 着重强调使用轻量级语言进行并发编程，它是一种单线程语言，但是，它可以使用事件循环和回调函数来处理并发。</p><p>Node.js 适合希望使用回调函数和 Node.js runtime 事件循环等功能来构建并发应用程序的开发人员。JavaScript 语言和 Node.js runtime 的这些功能使得开发人员只需使用一套最少的工具就可以实现快速开发。</p><p>通过服务器端 JavaScript，Node.js 的应用程序可以处理和路由来自客户端的请求：</p><ol><li>用户在用 HTML 和 CSS 编写的用户界面中选择一个选项</li><li>用户的这一操作会触发在客户端实现业务逻辑的 JavaScript 代码</li><li>JavaScript 代码会向服务器发送一个请求（通过 HTTP 调用带有 JSON 数据的 API）</li><li>作为在服务器上运行的 Node.js 应用程序的一部分，REST 网络服务会接收请求并处理它</li><li>REST 网络服务处理请求后，通过 HTTP 将结果作为 JSON 数据返回给客户端</li></ol><h4 id="121-模块"><a class="markdownIt-Anchor" href="#121-模块"></a> 1.2.1. 模块</h4><p>在 Node.js 中，模块是包含相关的、已封装的 JavaScript 代码的文件，用于实现特定的功能。模块可以是内置的，也可以是外部的；可以是单个文件，也可以是文件夹。</p><p>当外部应用程序需要使用模块中包含的代码时，应用程序需要调用该模块。而调用模块就需要使用语句 <code>import()</code> 或者 <code>require()</code>。</p><blockquote><p>模块规范：<br>一个或多个模块组成一个包，包是一个目录，其中包含一个 <code>package.json</code> 文件，该文件描述了包的内容。包可以发布到 npm（Node.js 包管理器）上，以便其他开发人员可以使用它们。</p><p>常用的模块规范有 CommonJS 和 ES。默认情况下，Node.js 使用 CommonJS 规范，但是，Node.js 也支持 ES 规范。库作者仅需要将包文件的扩展名从 <code>.js</code> 更改为 <code>.mjs</code>，就可以使用 ES 模块规范。</p><p>CommonJS 规范使用 <code>require()</code>，而 ES 规范使用 <code>import()</code>。<br>当需要在自身文件之外使用模块时，必须先导出模块。在使用 CommonJS 规范时，可以使用 <code>module.exports</code> 导出模块；在使用 ES 规范时，可以使用 <code>export</code> 导出模块。</p></blockquote><p><code>import()</code> 和 <code>require()</code> 的区别：</p><table><thead><tr><th style="text-align:left">import()</th><th style="text-align:left">require()</th></tr></thead><tbody><tr><td style="text-align:left">必须在文件开头调用</td><td style="text-align:left">可以在文件的任何位置调用</td></tr><tr><td style="text-align:left">不能在条件语句和函数中调用</td><td style="text-align:left">可以在条件语句和函数中调用</td></tr><tr><td style="text-align:left">静态绑定</td><td style="text-align:left">动态绑定</td></tr><tr><td style="text-align:left">在编译时解析</td><td style="text-align:left">在运行时解析</td></tr><tr><td style="text-align:left">异步</td><td style="text-align:left">同步</td></tr><tr><td style="text-align:left">对比 <code>require()</code>，在涉及到加载数百个模块的应用程序中运行速度更快</td><td style="text-align:left"></td></tr></tbody></table><blockquote><p><code>require()</code>：</p><pre><code class="language-js">// export from a file named message.jsmodule.exports = 'Hello Programmers';</code></pre><pre><code class="language-js">// import from the message.js filelet msg = require('./message.js');console.log(msg);</code></pre></blockquote><blockquote><p><code>import()</code>：</p><pre><code class="language-js">// export from file named module.mjsconst a = 1;export { a as "myvalue" };</code></pre><pre><code class="language-js">// import from module.mjsimport { myvalue } from module.mjs;</code></pre></blockquote><h4 id="122-创建简单的网络服务器"><a class="markdownIt-Anchor" href="#122-创建简单的网络服务器"></a> 1.2.2. 创建简单的网络服务器</h4><p>Node.js runtime 打包了许多实用程序模块，你可以使用它们来创建和扩展应用程序。例如，HTTP Node.js 模块提供了能够监听 HTTP 请求的功能。</p><pre><code class="language-js">let server = http.createServer(function(request, response) {  // create an instance of a web server    let body = "Hello World!";    response.writeHead(200, {  // this callback function handles the incoming request message and provides an appropriate response message        "Content-Length": body.length,        "Content-Type": "text/plain"    });    response.end(body);});server.listen(8080);  // set the server to listen to a specific port</code></pre><h4 id="123-packagejson"><a class="markdownIt-Anchor" href="#123-packagejson"></a> 1.2.3. <code>Package.json</code></h4><p>一个软件包由一个或多个模块组成。每个软件包都有一个 <code>package.json</code> 文件，用于描述 Node.js 模块的详细信息。</p><p>如果模块没有 <code>package.json</code> 文件，Node.js 就会假定主模块是 <code>index.js</code> 文件。</p><pre><code class="language-json">// Package.json{    "name": "mod_today",    "version": "1.0.0",    "main": "./lib/today",    "license": "Apache-2.0"}</code></pre><p>要为模块指定不同的主模块，可以在模块目录中 Node.js 脚本的相对路径中指定主模块。</p><h4 id="124-导入导出nodejs模块"><a class="markdownIt-Anchor" href="#124-导入导出nodejs模块"></a> 1.2.4. 导入 / 导出 Node.js 模块</h4><p>你可以使用 <code>require()</code> 函数导入 Node.js 模块。</p><pre><code class="language-js">let today = require("./today");</code></pre><p><code>require()</code> 语句假定了脚本的文件扩展名为 <code>.js</code>。它会创建一个对象来表示导入的模块，并将其分配给变量 <code>today</code>。</p><p>每个 Node.js 模块都有一个隐式 <code>exports</code> 对象。要向导入模块的 Node.js 应用程序提供函数或值，就需要在 <code>exports</code> 中添加属性。</p><pre><code class="language-js">let date = new Date();let days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];exports.dayOfWeek = function() {  // the dayOfWeek property is added to the exports object    return days[date.getDay() - 1];};</code></pre><p>导入 Node.js 模块时，<code>require()</code> 函数会返回一个 JavaScript 对象，该对象代表着模块的一个实例。</p><pre><code class="language-js">let today = require("./mod_today");  // the today variable is an instance of the today Node.js module that is called "today"</code></pre><p>要访问模块的属性，就要从变量中检索属性。</p><pre><code class="language-js">console.log("Happy %s!", today.dayOfWeek());  // today.dayOfWeek() represents the current exported property from the today Node.js module</code></pre><h2 id="13-express"><a class="markdownIt-Anchor" href="#13-express"></a> 1.3. Express</h2><p>Express.js 是一个高度可配置的框架，用于在 Node.js 上构建应用程序。它通过使用 HTTP 实现程序方法和中间件来抽象出 Node.js 中的低级 API。</p><p>以下功能可让你快速开发应用程序：</p><ol><li><p>Express.js 应用程序</p> <pre><code class="language-js">const app = express();</code></pre></li><li><p>图像、CSS 和 JavaScript 文件等静态文件</p></li><li><p>静态路由：定义接收和处理客户端请求的端点</p></li><li><p><code>server.js</code>：用于启动应用程序的文件</p></li><li><p><code>package.json</code>：用于定义应用程序的依赖项和脚本的文件</p></li></ol><h2 id="14-软件包管理器"><a class="markdownIt-Anchor" href="#14-软件包管理器"></a> 1.4. 软件包管理器</h2><p>软件包管理器是一套用于处理包含依赖关系的模块和软件包的工具。依赖关系是指一个软件包依赖于另一个软件包。</p><p>代码库通常包含着许多依赖项，但代码库本身是独立的，不依赖于代码库之外的任何东西。这种独立性使得代码库可以在不同的环境中使用。</p><p>软件包管理器能够自动完成查找、安装、更新、配置、维护和删除软件包的工作。它们通常连接并维护一个数据库，其中包含着软件包的依赖关系和版本信息。</p><h4 id="141-npm"><a class="markdownIt-Anchor" href="#141-npm"></a> 1.4.1. npm</h4><p>npm 是 Node.js 的软件包管理器。它是一个命令行工具，用于安装、更新、配置和删除 Node.js 软件包。</p><p>所有的 npm 软件包都需要一个 <code>package.json</code> 文件，该文件描述了软件包的详细信息。</p><pre><code class="language-json">{    "name": "myapp",    "version": "1.0.0",    "description": "My first Node.js app",    "main": "server.js",    "scripts": {        "start": "node server.js"    },    "author": "John Doe",    "license": "ISC",    "dependencies": {        "express": "^4.17.1"    }}</code></pre><p>npm 使用 <code>package.json</code> 文件中的 <code>dependencies</code> 属性来确定软件包的依赖关系。<code>dependencies</code> 属性是一个对象，其中包含着软件包的名称和版本号。</p><p>npm 有两种安装软件包的方式：本地安装或者全局安装。如果安装的软件包要在应用程序中使用，就应该使用本地安装。如果安装的软件包要在命令行中使用，就应该使用全局安装。</p><p>默认情况下 npm 会采用本地安装。</p><pre><code class="language-bash">npm install &lt;package_name&gt;</code></pre><p>该命令将在当前工作目录中创建一个 <code>node_modules</code> 文件夹，并将软件包安装到该文件夹中。</p><p>全局安装意味着安装软件包的计算机上的所有应用程序都可以使用该代码。全局安装应当谨慎使用，因为它会在计算机上创建一个全局软件包，这可能会导致版本冲突。</p><p>要安装 <code>node_modules</code> 文件夹中的所有软件包，要使用以下命令：</p><pre><code class="language-bash">npm install -g &lt;package_name&gt;</code></pre><h1 id="2-异步io与回调编程"><a class="markdownIt-Anchor" href="#2-异步io与回调编程"></a> 2. 异步 I / O 与回调编程</h1><h2 id="21-异步io"><a class="markdownIt-Anchor" href="#21-异步io"></a> 2.1. 异步 I / O</h2><p>所有的网络操作都是异步的，因为它们需要等待网络响应。</p><blockquote><p>网络服务调用的响应可能不会立即返回。当应用程序阻塞（或等待）网络操作完成时，就会浪费服务器上的处理时间。</p></blockquote><p>Node.js 以非阻塞方式进行所有网络操作。每个网络操作都会立即返回。要处理网络调用的结果，就需要编写一个回调函数。</p><p>应用程序、Node.js 框架、调用远程服务器的网络服务和回调函数之间的交互如下：</p><ol><li>应用程序会调用 <code>http.request()</code>，该函数会调用远程网络服务器并请求网络服务</li><li>在 Node.js 框架从远程网络服务器接收 HTTP 响应消息之前，它会立即返回 <code>http.request()</code> 函数调用的结果。该结果只表明请求消息已成功发送，并不会说明任何有关响应消息的信息</li><li>当 Node.js 框架从远程服务器接收到 HTTP 响应消息时，它会调用在 <code>http.request()</code> 函数调用过程中定义的回调函数。该函数处理 HTTP 响应消息，并将结果返回给应用程序</li></ol><pre><code class="language-js">let options = {  // included the hostname of the remote server, and a URL resource path    host: "w1.weather.gov",    path: "/xml/current_obs/KSFO.xml"};http.request(options, function(response) {  // when the Node.js module calls this anonymous function, events occur while it is receiving parts of the HTTP response object    let buffer = "";    let result = "";        response.on("data", function(chunk) {        buffer += chunk;    });        response.on("end", function() {        console.log(buffer);    });}).end();</code></pre><ul><li>在实际的应用程序时，你可能需要使用 HTTPS 而不是 HTTP</li></ul><h4 id="211-httprequest"><a class="markdownIt-Anchor" href="#211-httprequest"></a> 2.1.1. <code>http.request()</code></h4><p>该函数接收一个 URL 和一组选项。如果 URL 和选项都被传入，则将两者合并，选项优先。</p><pre><code class="language-js">http.request(options, [callback function]);</code></pre><p>该方法还可以接收一个可选的回调函数，在收到响应后立即调用。</p><pre><code class="language-js">http.request(options, function(response) { ... });</code></pre><p>当 <code>http.request()</code> 调用回调函数时，会在回调函数的第一个参数中传递一个响应对象。该回调函数的第一个参数就是响应对象。</p><p>Node.js 框架会在请求函数运行时发出多个事件。你可以使用 <code>object.on()</code> 方法并将事件名称作为第一个参数传递，从而监听这些事件。如果请求成功，每次数据输入时都会在响应对象上触发一个数据事件，响应结束时触发一个结束事件。</p><h4 id="212-处理错误"><a class="markdownIt-Anchor" href="#212-处理错误"></a> 2.1.2. 处理错误</h4><p>如果请求失败，在 <code>close</code> 事件之后就会出现 <code>error</code> 事件。</p><pre><code class="language-js">let request = http.request(options, function(response) { ... });                                                        request.on("error", function(e) {    resultCallback(e.message);});request.end();</code></pre><h2 id="22-回调函数"><a class="markdownIt-Anchor" href="#22-回调函数"></a> 2.2. 回调函数</h2><p>作为一个异步框架，Node.js 广泛地使用了回调函数。回调函数是一个函数，它作为参数传递给另一个函数，并在另一个函数完成后调用。</p><p>软件开发工具包（SDK）中的 Node.js 模块会将错误对象作为回调函数的第一个参数。</p><pre><code class="language-js">Call function((error))</code></pre><p>根据这一约定，回调函数会检查第一个参数是否包含了错误对象。</p><pre><code class="language-js">function(error, parameter1, parameter2, ...) { ... }</code></pre><p>如果定义了错误对象，回调函数就会处理错误并清理所有打开的网络或数据库连接。</p><pre><code class="language-js">weather.current(location, function(error, temp_f) {    if (error) {        console.log(error);  // if the error is defined, print the error message        return;    }        // otherwise, the weather.current function call completed successfully    console.log("The current weather reading is %s degrees.", temp_f);});response.end("... ${temp_f}_")</code></pre><h4 id="221-传递错误对象"><a class="markdownIt-Anchor" href="#221-传递错误对象"></a> 2.2.1. 传递错误对象</h4><pre><code class="language-js">exports.current = function(location, resultCallback) {    // ...    http.request(options, function(response) {        let buffer = "";        let result = "";                response.on("data", function(chunk) {            buffer += chunk;        });                response.on("end", function() {            parseString(buffer, function(error, result) {                if (error) {                    resultCallback(error);                    return;                }                                resultCallback(null, result.current_observation.temp_f[0]);            });        });    });}</code></pre><h4 id="222-每级一个回调"><a class="markdownIt-Anchor" href="#222-每级一个回调"></a> 2.2.2. 每级一个回调</h4><p>当 Node.js 应用程序以非阻塞方式来调用一个模块时，该应用程序会提供一个回调函数来处理结果。 如果主应用程序调用了 <code>http.request()</code>，它就必须提供一个回调处理程序来处理 HTTP 响应消息。</p><p>如果主应用程序调用了一个调用了 <code>http.request()</code> 的函数，那就会有两个回调函数：</p><ol><li>自定义模块有一个回调函数，用于处理来自 <code>http.request()</code> 的 HTTP 响应消息</li><li>主营用程序有一个回调函数，用于处理第一个回调函数捕获的结果</li></ol><p>带回调的主应用程序：</p><pre><code class="language-js">let weather = require("./weather");let location = "KSFO";weather.current(location, function(temp_f) {    console.log(temp_f);});</code></pre><p>主程序调用 <code>weather.current()</code> 时，会传递一个匿名的回调函数来处理调用结果。</p><pre><code class="language-js">exports.current = function(location, resultCallback) {    // ...    http.request(options, function(response) {        // ...        response.on("end", function() {            resultCallback(...);        });    }).end();}</code></pre><p>自定义的 Node.js 模块函数中的 <code>resultCallback()</code> 函数链接着主应用程序中 <code>weather.current()</code> 函数的匿名回调函数 <code>function(temp_f)</code>。</p><p>通过回调返回结果：</p><pre><code class="language-js">exports.current = function(location, resultCallback) {    let option = {        host: "w1.weather.gov",        path: "/xml/current_obs/" + location + ".xml"    };        http.request(options, function(response) {        let buffer = "";                response.on("data", function(chunk) {            buffer += chunk;        });                response.on("end", function() {            parseString(buffer, function(error, result) {                // ...                resultCallback(null, result.current_observation.temp_f[0]);            });        });    }).end();}</code></pre><p>另一个回调函数的例子：</p><pre><code class="language-js">const message = function() {    console.log("This message is shown after 3 seconds");}setTimeout(message, 3000);</code></pre><p>JavaScript 中有一个内置方法叫 <code>setTimeout()</code>，它会在执行操作前等待指定的时间（以毫秒为单位）。在示例中，信息被传入 <code>setTimeout()</code> 函数。因此，在等待 3 秒后，<code>setTimeout()</code> 会将消息写入控制台。</p><p>通常这些异步回调（简称 async）都用于访问数据库中的数值、下载图像、读取文件等。</p><h4 id="223-回调地狱"><a class="markdownIt-Anchor" href="#223-回调地狱"></a> 2.2.3. 回调地狱</h4><p>回调地狱是指在异步编程中，回调函数嵌套过多，导致代码难以阅读和维护。每个回调函数都依赖于前一个回调函数，并等待前一个回调函数完成后才能执行。</p><pre><code class="language-js">firstFunction(args, function() {    secondFunction(args, function() {        thirdFunction(args, function() {            // And so on ...        });    });});</code></pre><blockquote><p>这种结构有时也被称为「The Pyramid of Doom」（末日金字塔）。</p></blockquote><p>回调的另一个问题是 IoC（控制反转）。当控制流（如指令的执行）处于代码的外部时，就会发生控制反转。很多时候，回调会将控制权转交给第三方，但是第三方代码的问题和错误可能很难被发现。这种情况下你不得不去信任第三方代码或者编写额外的代码来确保第三方代码不会在不应该的时候被调用、被调用的次数过多或过少、丢失上下文、传回错误的参数等。</p><p>要想缓解回调地狱和 IoC 的问题，你可以：</p><ul><li>写注释</li><li>使用 Promise</li><li>将函数拆分成更小的函数</li><li>使用 <code>async/await</code></li></ul><h2 id="23-promise"><a class="markdownIt-Anchor" href="#23-promise"></a> 2.3. Promise</h2><p>对于 API 请求、I / O 操作和其他异步操作，Promise 是一种更好的解决方案。</p><pre><code class="language-js">let prompt = require("prompt-sync");let fs = require("fs");const methCall = new Promise((resolve, reject) =&gt; {    setTimeout(() =&gt; {        let filename = prompt("What is the name of the file?");        try {            const data = fs.readFileSync(filename, {                encoding: "UTF-8",            flag: "r"            });            resolve(data);        } catch(err) {            reject(err);        }    }, 3000);});</code></pre><h4 id="231-axios请求"><a class="markdownIt-Anchor" href="#231-axios请求"></a> 2.3.1. Axios 请求</h4><p>HTTP 请求在同步调用时可能会阻塞。Node.js 生态系统中有许多包，它们将 Promise 封装在 HTTP 请求中，axios 就是其中之一。</p><pre><code class="language-js">const axios = require("axios").default;const connectToURL = (url) =&gt; {    const req = axios.get(url);  // the status of the promise until it hears back from the URL requested is pending    console.log(req);    req.then(resp =&gt; {        console.log("Fulfilling");        console.log(resp.data);    })    .catch(err =&gt; {        console.log("Rejected");    });}</code></pre><h2 id="24-json"><a class="markdownIt-Anchor" href="#24-json"></a> 2.4. JSON</h2><p>JSON 是 API 数据交换的标准格式。</p><p>要将 JSON 字符串解析为 JavaScript 对象，可以使用方法 <code>JSON.parse()</code>。而要将 JavaScript 对象转换为 JSON 字符串，可以使用方法 <code>JSON.stringify()</code>。</p><h1 id="3-express网页开发框架"><a class="markdownIt-Anchor" href="#3-express网页开发框架"></a> 3. Express 网页开发框架</h1><p>默认的 Node.js 框架为构建网页应用程序提供了一套有限的功能。</p><blockquote><p>例如，Node.js 不提供 XML 消息的解析功能。在简单消息中，你可以使用 JavaScript 字符串函数来解析消息，也可以使用 XML 文档对象，但该对象解析 XML 数据流的效率并不高。</p></blockquote><p>开发人员往往依赖第三方软件包来扩展 Node.js 功能。</p><p>你可以将网络服务信息解析为字符串：</p><pre><code class="language-js">response.on("data", function(chunk) {    buffer += chunk;});response.on("end", function() {    let matches = buffer.match(/\&lt;temp_f\&gt;.+\&lt;\/temp_f\&gt;/g);    if (null != matches || matches.length &gt; 0) {        let result = matches[0].replace(/\&lt;temp_f\&gt;/, "").replace(/\&lt;\temp_f\&gt;/, "");    }        resultCallback(null, result);});</code></pre><p>这种手动解析的方法有着许多缺点：</p><ul><li>字符串匹配忽略了 XML 数据的结构</li><li>信息体可能包含了畸形的 XML 数据</li><li>根据 XML 数据的复杂程度，字符串匹配可能要比构建数据的 XML 树更有效率</li><li>字符串匹配对 XML 数据结构变化的容忍度很低</li><li>如果信息添加或删除了任何 XML 元素，那就必须更改字符串匹配函数的正则表达式</li></ul><p>xml2js 是一个流行的 Node.js 软件包，它可以将 XML 数据解析为 JavaScript 对象。与其他 XML 解析包不同，xml2js 只使用 JavaScript 而不是其他语言。</p><blockquote><p>第三方软件包的软件许可可能与 Node.js 框架不同。在安装软件包之前，请确认许可条款是否适用于你的公司和应用程序。</p></blockquote><pre><code class="language-bash">npm install xml2js</code></pre><p>将软件包导入到 Node.js 应用程序中：</p><pre><code class="language-js">let parseString = require("xml2js").parseString;exports.current = function(location, resultCallback) {    // ...    let request = https.request(options, function(response) {        // ...        response.on("end", function() {            parseString(buffer, function(error, result) {                if (error) { ... }                                // the result JavaScript variable represents the contents of the XML fragment in buffer                resultCallback(null, result.current_observation.temp_f[0]);            });        });    });}</code></pre><h2 id="31-网页框架"><a class="markdownIt-Anchor" href="#31-网页框架"></a> 3.1. 网页框架</h2><p>Node.js 不是网页框架，而是在服务器上执行 JavaScript 的 runtime 环境。网页框架是支持网页应用程序的基本结构，因此要使用 Node.js，就需要使用与之配合使用的网页框架。</p><p>与 Node.js 协同工作的框架被称为 node 网页框架。它们可采用两种方法构建后端：</p><ol><li>MVC（模型 - 视图 - 控制器）：将应用程序分解为三个部分，每个部分都有自己的职责</li><li>REST API</li></ol><h4 id="311-mvc"><a class="markdownIt-Anchor" href="#311-mvc"></a> 3.1.1. MVC</h4><p>MVC 是一种设计模式，用于将应用程序分解为三个部分：</p><ol><li>模型：负责处理数据</li><li>视图：负责渲染模型传递的数据</li><li>控制器：负责管理数据流、处理用户提供的数据，并将数据发送给模型</li></ol><p>MVC 框架一般用于开发需要将数据、数据的展示和操作数据的模块分开的应用程序。</p><p>MVC 模式的框架包括 Koa、Django、Express 和 NestJS。</p><h4 id="312-rest-api"><a class="markdownIt-Anchor" href="#312-rest-api"></a> 3.1.2. REST API</h4><p>REST API 允许多个网络服务相互通信。但这会受到一些限制：客户端的代码必须完全独立于服务器端的代码；客户端代码的更新不会干扰服务器端代码的运行，反之亦然。</p><p>REST API 是无状态的。这代表着客户端不需要知道服务器的状态，服务器也不需要知道客户端的状态。这种无状态的特性使得 REST API 非常适合用于构建分布式应用程序。</p><p>REST API 通过对资源的操作进行通信，不依赖于 API 的特定实现。当客户端使用 <code>GET</code>、<code>POST</code>、<code>PUT</code> 和 <code>DELETE</code> 等 HTTP 方法与服务器通信时，服务器便会向客户端响应资源状态。</p><h4 id="313-express"><a class="markdownIt-Anchor" href="#313-express"></a> 3.1.3. Express</h4><p>Express.js 是最流行的 node 网页框架之一。它用于路由和中间件、使用 JavaScript 进行直接编程，意味着学习曲线很低。</p><p>Express.js 提供调试机制，有助于轻松找出应用程序中的错误。它采用异步编程方式，同时处理多个相互独立的操作请求，因此性能很好。</p><h4 id="314-koa"><a class="markdownIt-Anchor" href="#314-koa"></a> 3.1.4. Koa</h4><p>Koa 是一个相对较新的网页框架，由设计 Express 的同一团队设计。它设计得更小巧、更具表现力，并为网页应用程序和 API 提供了更强大的基础。</p><p>Koa 使用异步函数，因此不需要回调，这提高了处理错误的能力。该框架适合由经验丰富的大型团队开发高性能、高要求、复杂的应用程序。</p><h4 id="315-socketio"><a class="markdownIt-Anchor" href="#315-socketio"></a> 3.1.5. <a href="http://Socket.IO">Socket.IO</a></h4><p>Socket.IO 是开发在客户端和服务器之间实时交换双向数据的应用程序的绝佳选择。你可以开发利用 Websocket 而不是 HTTP 协议的应用程序。</p><p>它的服务器可以推送数据，而无需客户端调用数据，因此十分适用于聊天室、短信应用、视频会议和多人游戏等应用程序。</p><h4 id="316-hapijs"><a class="markdownIt-Anchor" href="#316-hapijs"></a> 3.1.6. Hapi.js</h4><p>Hapi.js 是一个可靠的开源节点网页框架，内置了大量安全功能。它的插件系统使得开发人员可以轻松地扩展应用程序的功能。</p><p>它最著名的用途是开发代理和 API 服务器、HTTP 代理用户程序、REST API 以及其他桌面和应用程序。</p><h4 id="317-nestjs"><a class="markdownIt-Anchor" href="#317-nestjs"></a> 3.1.7. NestJS</h4><p>NestJS 框架适合构建动态、可扩展的企业应用程序，其灵活性得益于大量的库。它采用了 MVC 架构。</p><p>NestJS 构建在 Express 的基础之上，因此它们具有相似的功能。</p><p>NestJS 与 TypeScript 兼容，还能与前端 Angular 框架结合使用。</p><blockquote><p>TypeScript 是一种 JavaScript 的超集，它添加了类型和其他功能，以帮助开发人员编写更好的代码。</p></blockquote><p>NestJS 结合了面向对象编程和函数式编程的优点，因此它的代码易于阅读和维护。</p><h2 id="32-express"><a class="markdownIt-Anchor" href="#32-express"></a> 3.2. Express</h2><p>Express 主要用于两个目的：</p><ol><li>API</li><li>使用服务端渲染（SSR）来设置模板</li></ol><p>Express API 设置了一个与应用程序数据层交互的 HTTP 接口。在 API 的情况下，数据会使用响应对象（简称 <code>res</code>）以 JSON 格式返回给客户端。</p><p><code>res.json()</code> 方法用于通知客户端发送数据的内容类型，如图像或文本。它还可用于对数据进行字符串化。</p><p>而在 SSR 中，Express 用于设置模板。Express 负责使用客户端通过 HTTP 请求的数据、结合模板动态编写 HTML、CSS 和 / 或 JavaScript。</p><h4 id="321-nodejs应用程序框架"><a class="markdownIt-Anchor" href="#321-nodejs应用程序框架"></a> 3.2.1. Node.js 应用程序框架</h4><p>Express 实现了一个 <code>app</code> 类，你可以将其映射到网络资源路径。</p><pre><code class="language-js">const express = require("express");const app = express();const port = 3000;// ...let server = app.listen(port, function() {    console.log(`Listening on URL http://localhost:${port}`);});</code></pre><h4 id="322-express是如何工作的"><a class="markdownIt-Anchor" href="#322-express是如何工作的"></a> 3.2.2. Express 是如何工作的</h4><ol><li>在 Node.js 项目的包文件中，将 Express 作为依赖项添加到 <code>dependencies</code> 属性中</li><li>运行 <code>npm</code> 命令来下载缺少的模块</li><li>导入 Express 模块并创建一个 Express 应用程序实例</li><li>创建一个新的路由处理程序</li><li>在指定端口号上启动 HTTP 服务器</li></ol><pre><code class="language-js">// mynodeserver.jsconst express = require("express");const app = express();const port = 3000;app.get('/temperature/:location_code', function(request, response) {    const varlocation = request.params.location_code;    weather.current(location, function(error, temp_f) {        // ...    });});let server = app.listen(port, function() {    console.log(`Listening on URL http://localhost:${port}`);});</code></pre><p>要处理网页应用程序请求，可将 HTTP 方法和网络资源路径映射到 JavaScript 函数。</p><h4 id="323-路由"><a class="markdownIt-Anchor" href="#323-路由"></a> 3.2.3. 路由</h4><p>路由是服务器端脚本的一个重要组成部分。对同一服务器的不同路由的请求必须由服务器处理。服务器必须处理对每个路由的请求，否则就会返回相应的错误信息。路由可在应用程序级或路由器级处理。</p><pre><code class="language-js">const express = require("express");const app = new express();app.get("user/about/:id", (req, res) =&gt; {    res.send("Response about user " + req.params.id);});app.post("user/about/:id", (req, res) =&gt; {    res.send("Response about user " + req.params.id);});app.get("item/about/:id", (req, res) =&gt; {    res.send("Response about user " + req.params.id);});app.post("item/about/:id", (req, res) =&gt; {    res.send("Response about user " + req.params.id);});app.listen(3333, () =&gt; {    console.log(`Listening at http://localhost:3333`);});</code></pre><p>你需要在应用程序级别使用单独的方法来处理每个路由上的每个方法。当端点或路由较少时，这种方法很简单。但是，当端点或路由数量增加时，这种方法就会变得复杂。我们需要使用路由器来让我们的代码更加简洁、易于阅读和维护。</p><p>路由器本身用于处理分支查询，并以不同方法路由每个查询。</p><pre><code class="language-js">const express = require("express");const app = new express();let userRouter = express.Router();let itemRouter = express.Router();app.use("/item", itemRouter);app.use("/user", userRouter);userRouter.get("/about/:id", (req, res) =&gt; {    res.send("Response about user " + req.params.id);});userRouter.get("/details/:id", (req, res) =&gt; {    res.send("Details about user " + req.params.id);});itemRouter.get("/about/:id", (req, res) =&gt; {    res.send("Information about item " + req.params.id);});itemRouter.get("/details/:id", (req, res) =&gt; {    res.send("Details about item " + req.params.id);});app.listen(3333, () =&gt; {    console.log(`Listening at http://localhost:3333`);});</code></pre><h4 id="324-中间件"><a class="markdownIt-Anchor" href="#324-中间件"></a> 3.2.4. 中间件</h4><p>中间件包括了可以访问请求和响应对象以及下一个函数的函数。下一个参数决定了函数执行后的操作。</p><p>一个 Express 应用程序可以有多个中间件，而且它们之间可以相互连接。</p><p>中间件根据目的、用途和功能分为不同的类型：</p><ol><li>应用程序级</li><li>路由器级</li><li>错误处理</li><li>内置</li><li>第三方</li></ol><p>应用程序级中间件可以使用 <code>app.use()</code> 方法绑定到应用程序上：</p><pre><code class="language-js">const express = require("express");const app = new express();app.use(function(req, res, next) {    if (req.query.password !== "pwd123") {        return res.status(402).send("This user cannot login ");    }    console.log("Time:", Date.now());});app.get("/", (req, res) =&gt; {    return res.send("Hello World!");});app.listen(3333, () =&gt; {    console.log(`Listening at http://localhost:3333`);});</code></pre><p>客户端向服务器应用程序发出的所有请求都会通过该中间件进行路由。这种路由对验证和检查会话信息等操作很有用。</p><p>路由器级中间件不与应用程序绑定。相反，它与 <code>express.Router()</code> 实例绑定。你可以为特定路由使用特定的中间件，而不是让所有请求都通过同一个中间件：</p><pre><code class="language-js">const express = require("express");const app = new express();let userRouter = express.Router();let itemRouter = express.Router();userRouter.use(function(req, res, next) {    console.log("User query Time: ", Date());    next();});userRouter.get("/:id", function(req, res, next) {    res.send("User " + req.params.id + " last successful login " + Date());});itemRouter.use(function(req, res, next) {    console.log("Item query Time: ", Date());next();});itemRouter.get("/:id", function(req, res, next) {    res.send("Item " + req.params.id + " last enquiry " + Date());});app.use("/user", userRouter);app.use("/item", itemRouter);app.listen(3333, () =&gt; {    console.log(`Listening at http://localhost:3333`);});</code></pre><ul><li>响应将根据客户端的请求路径而不同</li></ul><p>错误处理中间件既可以绑定到整个应用程序，也可以绑定到特定路由器：</p><pre><code class="language-js">const express = require("express");const app = new express();app.use("/user/:id", function(req, res, next) {    if (req.params.id == 1) {        throw new Error("Trying to access admin login");    } else {        next();    }});app.use(function(err, req, res, next) {    if (err != null) {        res.status(500).send(err.toString());    } else {        next();    }});app.get("/user/:id", (req, res) =&gt; {    return res.send("Hello! User Id ", req.params.id);});app.listen(3333, () =&gt; {    console.log(`Listening at http://localhost:3333`);});</code></pre><p>错误处理中间件总是需要四个参数：<code>error</code>、<code>request</code>、<code>response</code> 和 <code>next()</code>。不过，你可以省略 <code>next()</code> 参数；即使省略了，也可以在方法中定义。</p><p>内置中间件可以绑定到整个应用程序或者特定路由器上。内置中间件对于从服务器渲染 HTML、解析来自前端的 JSON 输入和解析 cookie 等操作很有用。</p><pre><code class="language-js">const express = require("express");const app = new express();// define the static files that can be rendered from the cad220_staticfiles directoryapp.use(express.static("cad220_staticfiles"));app.listen(3333, () =&gt; {    console.log(`Listening at http://localhost:3333`);});</code></pre><p>你也可以定义自己的中间件或使用第三方中间件，这些中间件可以通过 <code>npm install</code> 命令安装。</p><p>创建中间件很简单。你可以定义一个包含三个参数的函数，然后将其与 <code>app.use()</code> 或者 <code>router.use()</code> 绑定。中间件的顺序取决于 <code>.use()</code> 方法用于绑定中间件的顺序。</p><pre><code class="language-js">const express = require("express");const app = new express();function myLogger(req, res, next) {    req.timeReceived = Date();    next();}app.use(myLogger);app.get("/", (req, res) =&gt; {    res.send("Request received at " + req.timeReceived + " is a success!");});app.listen(3333, () =&gt; {    console.log(`Listening at http://localhost:3333`);});</code></pre><h4 id="325-模板渲染"><a class="markdownIt-Anchor" href="#325-模板渲染"></a> 3.2.5. 模板渲染</h4><p>模板渲染是服务器在 HTML 模板中填充动态内容的能力。</p><pre><code class="language-js">const express = require("express");const app = new express();const expressReactViews = require("express-react-views");const jsxEngine = expressReactViews.createEngine();app.set("view engine", 'jsx');  // views are JSX codeapp.set("views", "myviews");  // the views are in a directory named myviewsapp.engine("jsx", jsxEngine);app.get("/:name", (req, res) =&gt; {   res.render("index", {name: req.params.name});});app.listen(3333, () =&gt; {   console.log(`Listening at http://localhost:3333`);});</code></pre><p>本代码示例使用了 express-React-views 软件包，它是一个用于渲染 React 视图的 Express 模板引擎。</p><h2 id="33-验证"><a class="markdownIt-Anchor" href="#33-验证"></a> 3.3. 验证</h2><p>身份验证是通过获取凭证并使用这些凭证验证用户身份的过程。身份验证的目的是识别用户身份，并根据其身份提供访问权限和内容。</p><p>身份验证可以通过以下方法实现：</p><ul><li>基于会话</li><li>基于令牌</li><li>无密码</li></ul><h4 id="331-基于令牌的身份验证"><a class="markdownIt-Anchor" href="#331-基于令牌的身份验证"></a> 3.3.1. 基于令牌的身份验证</h4><p>基于令牌的身份验证是在 Node.js 中实施身份验证的最常见方法。由于令牌只需存储在客户端，所以基于令牌的身份验证更具有可扩展性；服务器只需要验证令牌和用户信息，因此更容易处理多个用户；其灵活性能够在多个服务器上实现身份验证。基于令牌的身份验证中使用的 JWT 可以签名和加密，这意味着它们不会被篡改、没有私人加密密钥便无法读取。</p><p>让我们建立一个 Express.js API 服务器、根据使用权限访问员工信息。应用程序将有两个 API，每个 API 都有自己的端点：</p><ol><li>使用 <code>POST</code> API 登录，通过在请求体中发送用户名和密码、返回网页令牌（对该应用程序接口端点的调用应当通过托管应用程序前端的网页服务器来进行）</li><li><code>GET</code> API 将获取只有通过身份验证的用户才能访问的员工信息：<pre><code class="language-js">const express = require("express");const myapp = express();// creates a web server module by calling the express() function and assigning it to the constant myapp// the myapp.get() function creates a GET API endpoint for the Employees API, and any call to this endpoint currently returns an HTTP status code of 401// 401 means Not Authorizedmyapp.get("/employees". (req, res) =&gt; {    return res.status(401).json({message: "Please login to access this resource"});});myapp.listen(5000, () =&gt; {    console.log("API Server is localhost:5000");});</code></pre>在代码的下一部分，只要用户名和密码正确，我们就允许用户登录，并返回经过验证生成的令牌。一般来说，用户名和密码都存储在数据库中。但是，为了简单起见，我们将在代码中使用「user」和「password」作为用户名和密码。<br>要生成经过验证的 JWT（JSON Web Token），要使用 jsonwebtoken 包：<pre><code class="language-js">const express = require("express");const jsonwebtoken = require("jsonwebtoken");const JWT_SECRET = "aVeryVerySecretString";</code></pre>通过 <code>myapp.use()</code> 方法，API 方法可以返回 JSON 响应：<pre><code class="language-js">const myapp = express();myapp.use(express.json());myapp.post("/signin", (req, res) =&gt; {    const {uname, pwd} = req.body;    // however, that the JWT Secret should always be generated using a password generator and stored in the config file as an environment variable and not hard coded in the API, as shown here});</code></pre>然后将请求正文中的用户名和密码与从数据库中获取的值进行比较：<pre><code class="language-js">if (uname === "user" &amp;&amp; pwd === "password") {    return res.json({        // Once the username and password match, the JWT is generated using the jsonwebstoken.sign() function by including the username and the JWT secret as parameters and is returned as a JSON response from the signin API        token: jsonwebtoken.sign({user: "user"}, JWT_SECRET)    });    // if the username and password match fails, then a HTTP status code of 401 is returned with the message "Invalid username and/or password"    return res.status(401).json({message: "Invalid username and/or password"});});</code></pre>接着，我们用「employees」端点定义 <code>GET</code> API 方法：<pre><code class="language-js">myapp.get("/employees", (req, res) =&gt; {    let tkn = req.header("Authorization");    if (!tkn) return res.status(401).send("No Token");    if (tkn.startsWith("Bearer ")) {        tokenValue = tkn.slice(7, tkn.length).trimLeft();    }    // ...});</code></pre>从 <code>signin</code> API 调用中获取的令牌会在 <code>Authorization</code> 标头中传递。<code>GET</code> API（也就是「employees」）已更新，可以使用 <code>req.header()</code> 函数从传入的 API 请求中读取 <code>Authorization</code> 标头。值得注意的是，<code>Authorization</code> 标头的值总是以 <code>Bearer</code> 开头，因此这个令牌也被称为 Bearer 令牌。<br>获取的 JWT 可通过传递获取的令牌和 JWT 密钥、使用函数 <code>jsonwebtoken.verify()</code> 进行验证：<pre><code class="language-js">myapp.get("/employees", (req, res) =&gt; {    // ...    const verificationStatus = jsonwebtoken.verify(tokenValue, "aVeryVerySecretString");    if (verificationStatus.user === "user") {        return res.status(200).json({message: "Access Successful to Employee Endpoint"});    }});</code></pre>如果验证失败，则会将 401 状态码返回给客户端。</li></ol></body></html>]]></content>
    
    
    <summary type="html">本文是 IBM 全栈开发课程的第五篇学习笔记，详细介绍了如何使用 Node.js 和 Express.js 构建后端应用。笔记从服务端 JavaScript 的基础出发，讲解了 Node.js 的非阻塞I/O、模块化（CommonJS vs ES Modules）以及异步回调编程，并引入 Promise 来解决“回调地狱”问题。教程的核心部分深入探讨了 Express.js 框架，涵盖了路由、中间件、模板渲染，并提供了一个基于 JWT（JSON Web Token）实现用户身份验证的完整代码示例。这篇笔记为学习和掌握 Node.js 后端开发提供了一份全面的知识点总结。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="JavaScript" scheme="https://blog.cytrogen.icu/tags/JavaScript/"/>
    
    <category term="IBM" scheme="https://blog.cytrogen.icu/tags/IBM/"/>
    
    <category term="Node.js" scheme="https://blog.cytrogen.icu/tags/Node-js/"/>
    
    <category term="Express.js" scheme="https://blog.cytrogen.icu/tags/Express-js/"/>
    
  </entry>
  
  <entry>
    <title>IBM 全栈开发【4】：React 创建前端应用</title>
    <link href="https://blog.cytrogen.icu/posts/d011.html"/>
    <id>https://blog.cytrogen.icu/posts/d011.html</id>
    <published>2024-01-18T05:40:13.000Z</published>
    <updated>2026-02-09T17:16:54.717Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程，故此记录学习笔记。</p><span id="more"></span><h1 id="1-使用react和es6创建前端应用"><a class="markdownIt-Anchor" href="#1-使用react和es6创建前端应用"></a> 1. 使用 React 和 ES6 创建前端应用</h1><h2 id="11-前端框架"><a class="markdownIt-Anchor" href="#11-前端框架"></a> 1.1. 前端框架</h2><p>前端框架用于创建可连接服务器的动态客户端应用程序。它们通常是开源项目：</p><ul><li>Angular</li><li>React</li><li>Vue</li></ul><h4 id="111-angular"><a class="markdownIt-Anchor" href="#111-angular"></a> 1.1.1. Angular</h4><p>Angular 是一个开源的框架，由谷歌维护。它基于 HTML 和 JavaScript，并且易于实现。</p><p>Angular 使用指令来使 HTML 更加动态，所有指令都可用于包含库的 HTML。</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;&lt;html&gt;    &lt;head&gt;        &lt;script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.16/angular"&gt;&lt;/script&gt;    &lt;/head&gt;    &lt;body ng-app&gt;        Company Name: &lt;input type="text" ng-model="comp_name"&gt;        &lt;br&gt;        &lt;label ng-bind="comp_name"&gt;&lt;/label&gt;    &lt;/body&gt;&lt;/html&gt;</code></pre><h4 id="112-vue"><a class="markdownIt-Anchor" href="#112-vue"></a> 1.1.2. Vue</h4><p>Vue 是一个开源的前端框架，它使用虚拟 DOM 来实现高性能，HTML 被视为一个完整的对象。Vue 非常轻量级、渲染速度快、易于学习。</p><pre><code class="language-html">&lt;html&gt;    &lt;head&gt;        &lt;title&gt;VueJS Introduction&lt;/title&gt;        &lt;script src="https://cdn.jsdelivr.net/.../vue.js"&gt;&lt;/script&gt;    &lt;/head&gt;    &lt;body&gt;        &lt;div id="intro" style="text-align: center;"&gt;            &lt;h5&gt;                {{ message }}            &lt;/h5&gt;        &lt;/div&gt;        &lt;script type="text/javascript"&gt;        var vue_det = new Vue({                el: "#intro",                data: {                    message: "This is a Vue HTML"                }            });        &lt;/script&gt;    &lt;/body&gt;&lt;/html&gt;</code></pre><h4 id="113-react"><a class="markdownIt-Anchor" href="#113-react"></a> 1.1.3. React</h4><p>React 是一个用于构建客户端动态网络应用程序的框架，使用动态数据绑定和虚拟 DOM 来扩展 HTML 语法，而不需要编写额外的代码，并保持用户界面元素与应用程序状态的同步。</p><pre><code class="language-html">&lt;html&gt;    &lt;body&gt;        &lt;h1&gt;            Watson Author Finder        &lt;/h1&gt;        &lt;p&gt;            Please write your details        &lt;/p&gt;        &lt;form&gt;            &lt;input type="text" id="name"&gt;            &lt;input type="text" id="age"&gt;        &lt;/form&gt;    &lt;/body&gt;&lt;/html&gt;</code></pre><p>React 使用 JavaScript XML 这种类似于 HTML 的特殊语言来创建用户界面，其可被 Babel 编译器编译为 JavaScript。</p><p>JavaScript XML 要嵌入在特殊的脚本标签中，其中的 <code>type</code> 属性指定了需要 Babel 的内容。</p><blockquote><p>用于构建 React 应用程序的三个重要软件包：</p><ul><li>React 包：保存组件以及其状态和属性的 React 源代码</li><li>ReactDOM 包：React 和 DOM 之间的粘合剂</li><li>Babel 编译器：将 JavaScript XML 编译为 JavaScript</li></ul></blockquote><pre><code class="language-html">&lt;html&gt;    &lt;!-- Load React API --&gt;    &lt;script src="https://unpkg.com/react@16/umd/react.production.min.js"&gt;&lt;/script&gt;    &lt;!-- Load React DOM --&gt;    &lt;script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"&gt;&lt;/script&gt;    &lt;!-- Load Babel Compiler --&gt;    &lt;script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"&gt;&lt;/script&gt;        &lt;body&gt;        &lt;div id="comp1"&gt;&lt;/div&gt;        &lt;script type="text/babel"&gt;        class Mycomp extends React.Component {        // override the render method        render() {        return &lt;h1&gt;This is my own component named {this.props.name}&lt;/h1&gt;;        }        }        ReactDOM.render(&lt;Mycomp name="myBrandNewComp")/&gt;, document.getElementById("comp1"));        &lt;/script&gt;    &lt;/body&gt;&lt;/html&gt;</code></pre><ul><li>React 组件要在 <code>&lt;script&gt;</code> 标签中定义，<code>type</code> 属性的类型需要设置为 <code>text/babel</code>，以便 Babel 编译器将其编译为 JavaScript<ul><li>定义的组件为 <code>Mycomp</code>，继承自 <code>React.Component</code>，并重写了 <code>render()</code> 方法</li></ul></li><li><code>ReactDOM.render()</code> 方法用于渲染组件，并指定组件名称、HTML 标签和要设置的任何属性（该例子中就设置了 <code>name</code> 属性）</li><li>组件需要被指定呈现在 HTML 页面的哪个位置（该例子中就是 <code>comp1</code>）</li></ul><p>Facebook 提供了一个名为「Create React App」的工具，可以简化创建 React 应用程序的过程。</p><p>如果已安装 Node.js，就可以运行以下命令来安装 Create React App：</p><pre><code class="language-bash">npx create-react-app my-app</code></pre><p>当运行完上述命令后，系统会自动创建一个包含所有必要文件的目录结构。该目录结构包含创建和运行 React 应用程序所需的所有文件。</p><ul><li><code>src</code> 目录是我们需要修改的主要目录<ul><li><code>App.js</code> 文件是我们要添加到 HTML 页面的 React 根组件</li><li><code>index.js</code> 文件将应用程序添加到 HTML 页面</li></ul></li></ul><h2 id="12-es6"><a class="markdownIt-Anchor" href="#12-es6"></a> 1.2. ES6</h2><p>ES6 的全程为 ECMAScript 6，制定了广泛的全球信息和通信技术标准。</p><p>JavaScript 遵循 ECMAScript 6 标准（2015 年），其最主要的更改是：</p><ul><li><code>let</code></li><li><code>const</code></li><li>箭头函数</li><li>Promise 构造函数</li><li>类</li></ul><h4 id="121-let和const"><a class="markdownIt-Anchor" href="#121-let和const"></a> 1.2.1. <code>let</code> 和 <code>const</code></h4><p><code>let/const</code> 和 <code>var</code> 不同：</p><ul><li><code>var</code> 声明的变量的作用域是全局的。这很有挑战性，尤其是在大型项目中，代表着有许多变量需要维护</li><li><code>let</code> 可以将变量的作用域限制在声明变量的代码块中 <pre><code class="language-js">function() {    let num = 5;    num = 6;}console.log(num);  // will throw an error</code></pre></li><li><code>const</code> 声明的变量的值不能被修改 <pre><code class="language-js">const num = 5;console.log(num);num = 6;  // will throw an errorconsole.log(num);</code></pre></li></ul><h4 id="122-箭头函数"><a class="markdownIt-Anchor" href="#122-箭头函数"></a> 1.2.2. 箭头函数</h4><p>箭头函数允许函数像变量一样声明，这是一种更简洁的函数声明方式。</p><pre><code class="language-js">// how a function was written in the older ES5 JavaScriptfunction sayHello() {    console.log("ES5 function - Hello world!");}// arrow function in ES6const sayHello = ()=&gt; console.log("ES6 function - Hello world!");</code></pre><p>箭头函数可以被调用，并可以作为回调的参数传递。</p><pre><code class="language-js">const sayHello = ()=&gt; console.log("Hello world!");setTimeout(sayHello, 1000);</code></pre><p>箭头函数也可以像普通函数一样接受参数。</p><pre><code class="language-js">// takes one parameter// brackets are not mandatory// because the code returns a value, it must be in curly bracketsconst oneParamArrowFunc = name =&gt; {return "hello " + name};// function brackets must be put around the parameters list// does not need curly brackets because it only has one line of code and returns nothingconst twoParamsArrowFuncWithoutReturn = (first, last) =&gt; console.log("hello " + first + " " + last);const twoParamsArrowFuncWithReturn = (first, last) =&gt; {return "hello " + first + " " + last};const twoParamsTwoLinesArrowFunc = (first, last) =&gt; {    const greeting = "hello ";    return greeting + " " + first + " " + last;}</code></pre><h4 id="123-promise"><a class="markdownIt-Anchor" href="#123-promise"></a> 1.2.3. Promise</h4><p>Promise 对象表示了一个异步操作的最终完成或失败，以及其返回值。每当你调用异步操作时，Promise 会处于 pending（挂起）状态；当操作成功地执行时，Promise 会处于 fulfilled（履行）状态；当操作失败时，Promise 会处于 rejected（拒绝）状态。</p><pre><code class="language-js">let promiseArgument = (resolve, reject) =&gt; {    setTimeout(() =&gt; {        let currTime = new Date().getTime();        if (currTime % 2 === 0) {            resolve("Success!");        } else {            reject("Failed!");        }    }, 2000);};let myPromise = new Promise(promiseArgument);</code></pre><pre><code class="language-js">let myPromise = new Promise((resolve, reject) =&gt; {    setTimeout(() =&gt; {        let currTime = new Date().getTime();        if (currTime % 2 === 0) {            resolve("Success!");        } else {            reject("Failed!");        }    }, 2000);});</code></pre><blockquote><p>以上两种写法是等价的。</p></blockquote><h4 id="124-类"><a class="markdownIt-Anchor" href="#124-类"></a> 1.2.4. 类</h4><p>ES6 中的类使面向对象编程在 JavaScript 中更加容易。类创建了对象的模板，且建立在原型（即 prototype，是所有 JavaScript 对象的属性，包括函数，而函数可用于创建对象实例）的基础上。</p><pre><code class="language-js">function Person(name, age) {    this.name = name;    this.age = age;    return this;}let person1 = Person("John", 20);</code></pre><ul><li><code>this</code> 指代的是当前对象</li><li>类的概念是在函数原型的前提下建立的，目的是将面向对象编程扩展到 JavaScript 中</li></ul><p>构造函数（constructor）是一个特殊的函数，用于创建一个类对象：</p><pre><code class="language-js">class Rectangle {    constructor(height, width) {        this.height = height;        this.width = width;    }};let myRectangle = new Rectangle(10, 5);</code></pre><ul><li>使用 <code>new</code> 关键字就可以创建一个类的实例</li></ul><p>在 JavaScript ES6 中，类可以继承自其他类。继承其他类的类被称为子类（subclass），而超类（superclass）是被子类继承的类。子类会继承超类的所有属性和方法。</p><p>子类具有特殊权限，能够使用 <code>super()</code> 方法来调用超类的构造函数。</p><pre><code class="language-js">class Square extends Rectangle {    constructor(height, width) {        if (height === width) {            super(height, width);        } else {            // if the height is not the same as the width specified,            // the width will become equal to the height            super(height, height);        }    }}let mySquare = new Square(5, 5);</code></pre><h2 id="13-jsx"><a class="markdownIt-Anchor" href="#13-jsx"></a> 1.3. JSX</h2><p>JSX 是 JavaScript XML 或 JavaScript Syntax Extension 的缩写，是一种类似于 React 使用的 XML 或 HTML 类语法，用于创建 React 元素。 JSX 允许 XML 或 HTML 类文本与 JavaScript 或 React 代码并存。</p><p>JSX 使用预处理器将 JavaScript 文件中的 HTML 类文本转换为标准的 JavaScript 对象，例如转译器或编译器（比方说 Babel）。</p><pre><code class="language-jsx">const el1 = &lt;h1&gt;This is a sample JSX code snippet&lt;/h1&gt;</code></pre><ul><li>JSX 代码的语法就像是 HTML 使用了类似 JavaScript 的变量</li></ul><h4 id="131-react代码例子"><a class="markdownIt-Anchor" href="#131-react代码例子"></a> 1.3.1. React 代码例子</h4><pre><code class="language-jsx">import React from 'react'function App () {    return (    &lt;div&gt;        &lt;p&gt;This is a sample list&lt;/p&gt;            &lt;ul&gt;            &lt;li&gt;List item no. 1&lt;/li&gt;                &lt;li&gt;List item no. 2&lt;/li&gt;            &lt;/ul&gt;        &lt;/div&gt;    );}</code></pre><p>而这是普通的 JavaScript 代码：</p><pre><code class="language-js">import React from 'react'function App () {    return React.createElement(    "div",        null,        React.createElement("p", null, "This is a sample list"),        React.createElement("ul", null,            React.createElement("li", null, "List item no. 1"),                React.createElement("li", null, "List item no. 2"))    );}</code></pre><p>可以看出来，如果没有 JSX，React 代码将不得不使用大量嵌套来编写，这会导致代码变得难以阅读和维护。</p><h4 id="132-组件"><a class="markdownIt-Anchor" href="#132-组件"></a> 1.3.2. 组件</h4><p>组件（component）是 React 的核心构件，是一个可重用的代码块，用于创建用户界面。组件可以是函数或类，它们接受输入并返回 React 元素。</p><p>组件可以拥有自己的状态，这些状态是描述了组件行为的对象。有状态的组件的类型为类，而无状态的组件的类型为函数。</p><p>React 组件通过三个概念实现这些功能：</p><ol><li>属性（property）：用于从父组件向子组件传递数据</li><li>事件（event）：使组件能够管理 DOM 事件和用户在系统上交互的动作</li><li>状态（state）：根据组件的当前状态更新用户界面</li></ol><p>React 应用程序是一颗组件树：根组件就像一个容器，它包含了所有其他组件。 所有组件的名称，无论是函数还是类，都必须以大写字母开头。组件可以通过使用 <code>className</code> 属性和 CSS 来进行样式化。</p><p>组件类型：</p><ol><li><p>函数式组件通过编写 JavaScript 函数来创建，可以接受也可以不接受数据作为参数，返回 JSX 函数。它们本身没有状态或生命周期方法，因此也被称为无状态组件，但是可以通过实现 React Hooks 来添加这些功能。</p><ul><li>React Hook 是 React 的一项新功能，它能让你在不编写类的情况下使用 React 的特性</li><li>生命周期方法（lifecycle methods）是 React 内置的方法，可以在 DOM 中的整个持续时间内对组件进行操作</li></ul><p>函数式组件用于显示易于阅读、调试和测试的静态数据。</p> <pre><code class="language-jsx">const Democomponent = () =&gt; {    return &lt;h1&gt;welcome Message!&lt;/h1&gt;;}</code></pre><p>当组件有属性但生命周期不需要管理时最有用。</p><p>函数式组件可以接受用户自定义的属性作为参数：</p> <pre><code class="language-jsx">function App(props) {  // props passed as a function parameter    const compStyle = {        color: props.color,        fontSize: props.size + 'px'    };        return (        &lt;div&gt;            &lt;span style={compStyle}&gt;I am a sentence.&lt;/span&gt;        &lt;/div&gt;    );}export default App;</code></pre> <pre><code class="language-jsx">ReactDOM.render(    &lt;React.StrictMode&gt;        &lt;App color="blue" size="25"/&gt;  &lt;!-- props being sent to the component --&gt;    &lt;/React.StrictMode&gt;,    document.getElementById('root'));</code></pre><p>事件处理程序（event handler）可以通过属性来设置，其中 <code>onClick</code> 处理程序在功能组件中使用的最多：</p> <pre><code class="language-jsx">import React from 'react';import ReactDOM from 'react-dom';import App from './App';ReactDOM.render(    &lt;React.StrictMode&gt;        &lt;App color="blue" size="25" clickEvent={  &lt;!-- setting an event handler method as a property --&gt;                () =&gt; { alert("You clicked me!") }            }/&gt;    &lt;/React.StrictMode&gt;,    document.getElementById('root'));</code></pre> <pre><code class="language-jsx">function App(props) {    return (        &lt;div&gt;            &lt;button onClick={props.clickEvent}&gt;Click Me!&lt;/button&gt;  &lt;!-- setting an event handler from props --&gt;        &lt;/div&gt;    );}export default App;</code></pre></li><li><p>类组件要比函数式组件更复杂，它们可以将数据传递给其他类组件、可以被 JavaScript ES6 的类创建、可以使用状态、属性和生命周期方法等 React 功能。</p> <pre><code class="language-jsx">class Democomponent extends React.Component {    render() {        return &lt;h1&gt;Welcome Message!&lt;/h1&gt;;    }}</code></pre><p>由于其多功能性，类组件要比函数式组件更受青睐。由于它们继承了 <code>React.Component</code>，因此必须要覆盖 <code>render()</code> 方法。</p> <pre><code class="language-jsx">// import the React module from the react packageimport React from 'react';// create the App class that extends React.Componentclass App extends React.Component {    constructor(props) {        super(props)    }        // override the render method    render() {        return &lt;button onClick={this.props.clickEvent}&gt;Click Me!&lt;/button&gt;;    }}export default App;</code></pre><p><code>props</code> 在类组件外部设置，而状态要在类组件内部设置：</p> <pre><code class="language-jsx">import Reach from 'react';class App extends React.Component {    constructor(props) {        super(props)    }    state = {counter: "0"};  // define the state counter of the component App        // a function to increment the counter every time a button is clicked    incrementCounter = () =&gt; {        this.setState({counter: parseInt(this.state.counter) + 1});    }        // override the render method    render() {        return &lt;div&gt;            &lt;button onClick={this.incrementCounter}&gt;Click Me!&lt;/button&gt;            &lt;br/&gt;            {this.state.counter}        &lt;/div&gt;    }}</code></pre></li><li><p>纯组件（pure component）优于函数式组件，主要用于提供优化。它们是编写起来最简单最快的组件，不依赖于其作用域之外的任何变量状态，可以用来替代简单的函数式组件。</p></li><li><p>高阶组件（higher-order component）是 React 中重用组件逻辑的高级技术。API 不提供高阶组件。它们返回组件的函数，用于与其他组件共享逻辑。</p> <pre><code class="language-jsx">// import React and React Native's Text Core Componentimport React from 'react';import { Text } from 'react-native';// define a component as a functionconst Helloworld = () =&gt; {    return (        &lt;Text&gt;Hello, World!&lt;/Text&gt;    );}// export your function component// the function can then be imported in any applicationexport default Helloworld;</code></pre></li></ol><h1 id="2-react组件"><a class="markdownIt-Anchor" href="#2-react组件"></a> 2. React 组件</h1><h2 id="21-状态"><a class="markdownIt-Anchor" href="#21-状态"></a> 2.1. 状态</h2><p>状态允许你在一个应用程序中修改数据。它被定义为一个对象，使用键值对来存储数据，并帮助你跟踪应用程序中不同类型的数据。</p><p>React 组件有一个内置的状态对象，可以在状态对象中存储属于组件的属性值。当状态对象发生变化时，组件会重新渲染。</p><pre><code class="language-jsx">// componentclass TestComponent extends React.component {    constructor() {        this.state = {            id: 1,            name: "John",            age: 28        };    }    render() {        return (        &lt;div&gt;            &lt;p&gt;{ this.state.name }&lt;/p&gt;                &lt;p&gt;{ this.state.age }&lt;/p&gt;            &lt;/div&gt;        )    }}</code></pre><ul><li>本代码示例展示出了如何创建一个测试组件，该组件包含 <code>id</code>、<code>name</code> 和 <code>age</code> 三个状态属性</li><li>组件的 <code>render()</code> 方法返回了状态属性的值</li><li>包含属性的状态将根据组件的要求进行更改</li></ul><p>React 状态的类型：</p><ol><li>共享状态（shared state）：由多个组件共享，比较复杂。例如订单应用程序中的所有订单列表</li><li>本地状态（local state）：存在于单个组件中，不用于其他组件。例如隐藏和显示信息</li></ol><h2 id="22-属性"><a class="markdownIt-Anchor" href="#22-属性"></a> 2.2. 属性</h2><p>属性用于在 React 组件之间传递数据。工作方式与 HTML 属性类似，它们存储标签的属性值。</p><blockquote><p>React 组件之间的数据流是从父组件到子组件的单向数据流。</p></blockquote><p>属性可以像函数参数一样被传递，但它们是只读的，不能在组件内部更改。属性允许子组件访问父组件中被定义的方法（状态则是由父组件管理，而子组件没有自己的状态），大部分组件将根据接收到的属性来显示信息，并保持无状态。</p><pre><code class="language-jsx">// componentclass TestComponent extends React.component {    render() {        return &lt;div&gt;Hi { this.props.name }&lt;/div&gt;    }}// passing the props as examples to the text component&lt;TestComponent name="John" /&gt;&lt;TestComponent name="Jill" /&gt;</code></pre><ul><li>该代码示例创建了一个类 <code>TestComponent</code>，该类扩展了 React 组件</li></ul><h2 id="23-组件阶段"><a class="markdownIt-Anchor" href="#23-组件阶段"></a> 2.3. 组件阶段</h2><p>每个 React 组件在其生命周期中都有三个阶段：</p><ol><li><p>挂载阶段（mounting phase）：组件被创建并插入 DOM 中。当组件被创建时，会有四个方法被依次调用：</p><ol><li><code>constructor()</code>：用于初始化组件的状态和属性</li><li><code>getDerivedStateFromProps()</code>：用于更新组件的状态</li><li><code>render()</code>：用于渲染组件；必须且只能返回一个 DOM 元素</li><li><code>componentDidMount()</code>：用于在组件被插入 DOM 后执行一些操作</li></ol> <pre><code class="language-jsx">import React from 'react';class App extends React.Component {  // when the component App is created, the constructor is invoked  constructor(props) {    super(props)    console.log("Inside the constructor")  }  // the componentDidMount method is invoked  componentDidMount = () =&gt; {    console.log("Inside component did mount")  }  // the render method is invoked  render() {    console.log("Inside render method")    return (            &lt;div&gt;              The component is rendered            &lt;/div&gt;    );  }}export default App;</code></pre></li><li><p>更新阶段（updating phase）：组件的状态或属性发生变化时，会触发更新阶段。当组件更新时，会有五个方法被依次调用：</p><ol><li><code>getDerivedStateFromProps()</code>：用于更新组件的状态</li><li><code>shouldComponentUpdate()</code>：每当状态发生变化时被调用；默认返回 <code>true</code>；应当仅在不想渲染状态的变化时返回 <code>false</code></li><li><code>render()</code>：用于渲染组件；必须且只能返回一个 DOM 元素</li><li><code>getSnapshotBeforeUpdate()</code>：用于在 DOM 更新前获取 DOM 状态</li><li><code>componentDidUpdate()</code>：用于在 DOM 更新后执行一些操作</li></ol> <pre><code class="language-jsx">import React from 'react';class App extends React.Component {    state = {counter: "0"};        incrementCounter = () =&gt; this.setState({counter: parseInt(this.state.counter) + 1});        // returns true by default    // its behavior is rarely changed    shouldComponentUpdate() {        console.log('Inside shouldComponentUpdate')        return true;    }        getSnapshotBeforeUpdate(prevProps, prevState) {        console.log('Inside getSnapshotBeforeUpdate');        console.log('Prev counter is ' + prevState.counter);        console.log('New counter is ' + this.state.counter);        return prevState;    }        componentDidUpdate() {        console.log('Inside componentDidUpdate')    }        // logs on to the console and then renders the component    render() {        console.log('Inside render')        return (            &lt;div&gt;                &lt;!-- With the onClick of the button, incrementCounter is invoked, increasing the counter state by 1 --&gt;                &lt;button onClick={this.incrementCounter}&gt;Click Me!&lt;/button&gt;                {this.state.counter}            &lt;/div&gt;        );    }}export default App;</code></pre></li><li><p>卸载阶段（unmounting phase）：组件从 DOM 中移除时，会触发卸载阶段。当组件被卸载时，会有一个方法被调用：</p><ol><li><code>componentWillUnmount()</code>：用于在组件被卸载前执行一些操作</li></ol> <pre><code class="language-jsx">import React from 'react';class AppInner extends React.Component {    componentWillUnmount() {        console.log('This component will unmount')    }        render() {        return &lt;div&gt;Inner component&lt;/div&gt;    }}class App extends React.Component {    state = {innerComponent:&lt;AppInner/&gt;}        componentDidMount() {        setTimeout(() =&gt; {            this.setState({innerComponent: &lt;div&gt;unmounted&lt;/div&gt;})            }, 5000)    }        render() {        console.log('Inside render')        return (            &lt;div&gt;                {this.state.innerComponent}            &lt;/div&gt;        );    }}export default App;</code></pre></li></ol><h2 id="24-组件之间的数据传递"><a class="markdownIt-Anchor" href="#24-组件之间的数据传递"></a> 2.4. 组件之间的数据传递</h2><p>React 组件之间的数据传递可以有：</p><ol><li>使用属性的「父到子」数据传递</li><li>使用回调函数的「子到父」数据传递</li><li>使用 Redux 的「兄弟」数据传递（此处不做讨论）</li></ol><p>父到子：</p><pre><code class="language-jsx">class App extends React.Component {    state = {childColor: "green", name: "John"}        changeColor = () =&gt; {        const newcolor = document.getElementById('colorbox').value;        this.setState({childColor: newcolor})    }        changeName = () =&gt; {        const newname = document.getElementById('namebox').value;        this.setState({name: newname})    }        render() {        console.log('Inside render')        return (        &lt;div&gt;            Color &lt;input type="Text" onChange={this.changeColor} id="colorbox" /&gt;                &lt;br/&gt;                Name &lt;input type="Text" onChange={this.changeName} id="namebox" /&gt;                                &lt;!-- App sets the property color and name for AppInner --&gt;                &lt;!-- The data is passed to the child every time a new value is entered in the input boxes in the parent --&gt;                &lt;AppInner color={this.state.childColor} name={this.state.name} /&gt;            &lt;/div&gt;        );    }}</code></pre><pre><code class="language-jsx">class AppInner extends React.Component {    constructor(props) {        super(props)    }        render() {        const txtStyle = {color: this.props.color}        return &lt;span style={txtStyle}&gt;{this.props.name}&lt;/span&gt;    }}</code></pre><ul><li>其中，<code>App</code> 组件是 <code>AppInner</code> 组件的父组件</li></ul><p>子到父：</p><pre><code class="language-jsx">class App extends React.Component {    state = {message: ""}        // Func1 is a parent component function which takes a string argument    func1 = (childData) =&gt; {        this.setState({message: childData})    }        render() {        return (        &lt;div&gt;                &lt;!-- Pass the callback func1 as a property to the child --&gt;            &lt;AppInner parentCallback = {this.func1} /&gt;                &lt;p&gt;{this.state.message}&lt;/p&gt;            &lt;/div&gt;        );    }}</code></pre><pre><code class="language-jsx">class AppInner extends React.Component {    sendData = () =&gt; {        setInterval(() =&gt; {            const currTime = Date();            // the parent class method which sets the state of the parent component            this.props.parentCallback(currTime);        }, 1000);    }        // invoke the sendData method    componentDidMount() {        this.sendData();    }        render() {        return &lt;div&gt;&lt;/div&gt;    }}</code></pre><h2 id="25-组件的生命周期"><a class="markdownIt-Anchor" href="#25-组件的生命周期"></a> 2.5. 组件的生命周期</h2><p>组件的生命周期代表了组件从创建到销毁的整个过程。React 组件的生命周期包含四个阶段，每个阶段都有不同的方法：</p><ol><li>初始化（initialization）：组件以给定的属性和默认状态被创建</li><li>挂载（mounting）：渲染由 <code>render()</code> 方法返回的 JSX</li><li>更新（updating）：当组件的状态或属性发生变化时，会触发更新阶段</li><li>卸载（unmounting）：组件从 DOM 中移除</li></ol><h4 id="251-挂载阶段"><a class="markdownIt-Anchor" href="#251-挂载阶段"></a> 2.5.1. 挂载阶段</h4><p>挂载阶段中，组件被添加到 DOM，并在组件加载前和加载后调用两个预定义方法：</p><ol><li><code>componentWillMount()</code></li><li><code>componentDidMount()</code></li></ol><h4 id="252-更新阶段"><a class="markdownIt-Anchor" href="#252-更新阶段"></a> 2.5.2. 更新阶段</h4><p>组件的状态或属性发生变化时，会触发更新阶段。变化可以在组件内发生，也可以通过后台发生，这些变化都会触发 <code>render()</code> 方法的调用。</p><ol><li><code>getDerivedStateFromProps()</code></li><li><code>shouldComponentUpdate()</code></li><li><code>render()</code></li><li><code>getSnapshotBeforeUpdate()</code></li><li><code>componentDidUpdate()</code></li></ol><h4 id="253-卸载阶段"><a class="markdownIt-Anchor" href="#253-卸载阶段"></a> 2.5.3. 卸载阶段</h4><p>组件从 DOM 中移除时，会触发卸载阶段。在卸载阶段，只有一个方法被调用：</p><ol><li><code>componentWillUnmount()</code></li></ol><h2 id="26-外部服务"><a class="markdownIt-Anchor" href="#26-外部服务"></a> 2.6. 外部服务</h2><p>路由器（router）可以连接到外部服务以执行多种操作，例如：</p><ol><li><p><code>GET</code>：从服务器获取数据</p> <pre><code class="language-jsx">class App extends React.Component {    state = {        user: "None Logged In"    }        // connect to a server through an axios request    componentDidMount() {        const req = axios.get("&lt;external server&gt;");        req.then(resp =&gt; {            // then the promise is fulfilled, you parse the response and extract the data from it to change user to have the same name as its value            this.setState({user: resp.data.name});        })        .catch(err =&gt; {            this.setState({user: "Invalid user"});        });    }        render() {        return (            &lt;div&gt;                Current user - {this.state.user}            &lt;/div&gt;        );    }}</code></pre></li><li><p><code>POST</code>：将数据发送到服务器</p> <pre><code class="language-jsx">const express = require("express");const app = new express();// this server uses the CORS middleware to allow cross-origin requests to the serverconst cors_app = require("cors");app.use(cors_app());let usercollection = [];app.post("/user", (req, res) =&gt; {    let newuser = {"name": req.query.name, "gender": req.query.gender}    usercollection.push(newuser);    return res.send("User successfully added");});app.get("/user", (req, res) =&gt; {    return res.send(usercollection);})app.listen(3333, () =&gt; {    console.log("Listening at http://localhost:3333")})</code></pre><ul><li>Express 服务器接收端点 <code>/user</code> 的 <code>POST</code> 请求，并将数据存储在 <code>usercollection</code> 数组中</li></ul> <pre><code class="language-jsx">class App extends React.Component {    state = {completionstatus: ""}        postDataToServer = () =&gt; {        axios.post("http://localhost:3333/user?name=" +                   document.getElementById("name").value +                  "&amp;gender=" + document.getElementById("gender").value        )        .then(response =&gt; {            this.setState({completionstatus: response.data})        }).catch((err) =&gt; {            this.setState({completionstatus: "Operation failure"})        })    }        render() {        return (            &lt;div&gt;                Enter the name &lt;input type="text" id="name" /&gt;                &lt;br /&gt;                Enter the gender &lt;input type="text" id="gender" /&gt;                &lt;br /&gt;                &lt;button onClick={this.postDataToServer}&gt;Post Data&lt;/button&gt;                &lt;span&gt;{this.state.completionstatus}&lt;/span&gt;            &lt;/div&gt;        );    }}</code></pre></li><li><p><code>UPDATE</code>：修改数据</p></li><li><p><code>DELETE</code>：删除数据</p></li></ol><p>大多数对外部服务器的请求都是阻塞性的。要异步调用，可以使用 Promise。</p><h2 id="27-测试"><a class="markdownIt-Anchor" href="#27-测试"></a> 2.7. 测试</h2><p>测试可以是一套由代码组成的，以验证应用程序的无差错执行。</p><p>测试 React 组件有多个好处：验证代码运行无误；通过复制最终用户的行为来测试组件；通过测试组件的不同状态来测试组件；防止先前已修复的错误再次出现。</p><p>测试有着两种类型：</p><ol><li>在简单的测试环境中渲染组件树并验证其输出</li><li>在真实的浏览器环境中运行应用程序，进行端到端的测试</li></ol><h4 id="271-react组件测试的阶段"><a class="markdownIt-Anchor" href="#271-react组件测试的阶段"></a> 2.7.1. React 组件测试的阶段</h4><ol><li>安排（arrange）：组件需要将其 DOM 渲染到用户界面</li><li>操作（act）：注册任何可能以编程方法触发的用户行为</li><li>断言（assert）：验证组件的输出是否与预期的输出相匹配</li></ol><h4 id="272-测试工具"><a class="markdownIt-Anchor" href="#272-测试工具"></a> 2.7.2. 测试工具</h4><p>速度 vs 环境：</p><ul><li>有些工具能在做出修改和看到结果之间提供非常快的回馈，但无法精确地模拟浏览器行为</li><li>有些工具可能会使用真实的浏览器环境，但会降低迭代速度，在持续集成环境中使用时可能会导致不稳定</li></ul><p>测试工具有：</p><ul><li>Mocha</li><li>Chai：断言库</li><li>Sinon</li><li>Enzyme：渲染组件</li><li>Jest：测试 React 组件，并拥有着 Mocha、Chai、Sinon 以及其他工具的能力</li><li>React Testing Library：测试 React 组件</li></ul><h1 id="3-react进阶"><a class="markdownIt-Anchor" href="#3-react进阶"></a> 3. React 进阶</h1><h2 id="31-hooks"><a class="markdownIt-Anchor" href="#31-hooks"></a> 3.1. Hooks</h2><p>Hooks 是在用户界面中封装有状态的行为的更简单的方法，它们允许函数式组件访问状态和其他 React 功能。Hooks 是常规的 JavaScript 函数，提供使用上下文或状态等功能的方法，且无需编写类，帮助你使代码更简洁。</p><blockquote><p>类组件有时会带来一些问题，例如封装复杂、组件大小难以管理以及类混淆等。</p></blockquote><p>标准的 Hooks：</p><ul><li><code>useState</code>：为函数式组件添加状态</li><li><code>useEffect</code>：管理副作用（side effects）</li><li><code>useContext</code>：管理上下文</li><li><code>useReducer</code>：管理 Redux 的状态变化</li></ul><p>自定义 Hooks 允许你为应用程序添加特殊功能。它们可以由一个或多个 Hooks 组成、可以被重复使用、分解为更小的 Hooks。自定义 Hooks 需要以 <code>use</code> 开头。</p><pre><code class="language-jsx">import React, { useState } from "react";function CntApp() {    // declare a new state variable "count"    // useState is the hook which needs to call inside a function component to add some local state to it    const [count, setCount] = useState(0);    return (    &lt;div&gt;        &lt;p&gt;You clicked {count} many times&lt;/p&gt;            &lt;button onClick={() =&gt; setCount(count + 1)}&gt;            Click me            &lt;/button&gt;        &lt;/div&gt;    );}export default CntApp;</code></pre><h2 id="32-表单"><a class="markdownIt-Anchor" href="#32-表单"></a> 3.2. 表单</h2><p>大多数 React 表单都是单页面应用程序（SPA）或者加载单个页面的网络应用程序。表单使用组件处理数据、使用事件处理程序控制变量的变化和状态的更新。</p><p>表单标签有：</p><ul><li><code>&lt;input&gt;</code></li><li><code>&lt;textarea&gt;</code></li><li><code>&lt;select&gt;</code></li></ul><p>在 HTML，状态由表单元素管理；在 React，组件的状态管理着表单元素。</p><h4 id="321-输入类型"><a class="markdownIt-Anchor" href="#321-输入类型"></a> 3.2.1. 输入类型</h4><table><thead><tr><th>非受控输入</th><th>受控输入</th></tr></thead><tbody><tr><td>允许浏览器处理大部分表单元素，并通过 React 的变化事件收集数据</td><td>使用 React 直接设置和更新输入值，从而完全控制元素</td></tr><tr><td>在输入的 DOM 节点中管理自己的状态</td><td>函数管理数据的传递</td></tr><tr><td>元素会在输入值发生变化的时候更新</td><td>更好地控制表单元素和数据</td></tr><tr><td><code>ref</code> 函数用于从 DOM 中获取表单值</td><td>属性获取当前值并通知更改</td></tr><tr><td></td><td>父组件控制更改</td></tr></tbody></table><p>表单示例：</p><pre><code class="language-jsx">import React, { Component } from "react";export default function App() {    // to track the state of the email address, this example uses a hook    const [email, setEmail] = React.useState("");    const [password, setPassword] = React.useState("");        const handleSubmit = (event) =&gt; {        console.log("Email: ${email}\nPassword: ${password}");        event.preventDefault();    }        return (        &lt;form onSubmit={handleSubmit}&gt;        &lt;h1&gt;Registration&lt;/h1&gt;            &lt;label&gt;                &lt;!-- to ensure that the email remains updated when the use interacts with form, you must add as input, value, and onChange attributes to the email address --&gt;            Email: &lt;input name="email" type="email" value={email} onChange={e =&gt; setEmail(e.target.value)} required /&gt;            &lt;/label&gt;            &lt;label&gt;            Password: &lt;input name="password" type="password" value={password} onChange={e =&gt; setPassword(e.target.value)} required /&gt;            &lt;/label&gt;                        &lt;button&gt;Submit&lt;/button&gt;        &lt;/form&gt;    );}</code></pre><blockquote><p>React Hook Form 是一个创建表单的实用软件包，它可以帮助你创建可重用的表单组件。</p></blockquote><h2 id="33-redux"><a class="markdownIt-Anchor" href="#33-redux"></a> 3.3. Redux</h2><p>Redux 是一个状态管理库，它遵循一种称为 Flux 架构的模式，通常在组件数量较多的时候实用。</p><p>Redux 提供了一个集中的状态管理系统，它将应用程序的所有状态存储在一个单一的对象中，称为存储（store）。存储是一个 JavaScript 对象，它包含了应用程序的所有状态。</p><p>Redux 的工作流程：当用户与应用程序的某个组件交互时，<code>Action</code> 会更新整个应用程序的状态，这反过来又会触发组件的重新渲染，从而更新该组件的属性，这些属性会将结果反馈给用户。</p><h4 id="331-概念"><a class="markdownIt-Anchor" href="#331-概念"></a> 3.3.1. 概念</h4><ol><li><code>Action</code>：【你的应用程序能做什么】。它是一个由选择单选按钮、复选框或点击按钮触发的事件 / JSON 对象；它包含着需要对状态进行更改的信息，并由被称为操作创建器（action creator）的函数创建。<code>Action</code> 由应用程序的各个部分派发，并由存储空间接收</li><li><code>Store</code>：应用程序状态的唯一位置和权威来源。它是一个包含着状态、函数和其他对象的对象，可以调度和接收操作。<code>Store</code> 的更新能够被订阅</li><li><code>Reducers</code>：返回全新的状态的函数。它们从 <code>Store</code> 接收 <code>Action</code>，并对状态进行适当更改。作为事件监听器，<code>Reducer</code> 会读取 <code>Action</code> 的有效载荷（payload）并更新 <code>Store</code>。<ul><li><code>Reducer</code> 接收两个参数：先前的应用程序状态和 <code>Action</code></li></ul></li></ol><h4 id="332-中间件"><a class="markdownIt-Anchor" href="#332-中间件"></a> 3.3.2 中间件</h4><p>中间件（middleware）是一个函数，它可以访问 <code>Action</code> 和 <code>Store</code>，并且可以在 <code>Action</code> 到达 <code>Reducer</code> 之前执行某些操作。它可以用于日志记录、分析、异步请求等。</p><ol><li>Thunk 中间件：允许在操作创建器中传递函数以创建 <code>async</code> Redux、允许编写操作创建器、允许延迟调度操作、允许调度多个操作。优势是 Thunk 中间件可以无需大量模板代码即可实现异步操作、学习难度小、易于使用；缺点是不能直接对操作做出响应、难以处理可能出现的并发问题、是命令式的、不太容易测试和扩展</li><li>Saga 中间件：使用称为生成器（generator）的 ES6 功能来实现异步操作、允许以纯函数的形式表达复杂的逻辑、易于测试、允许分离关注点、易于扩展具有副作用的复杂操作、易于通过 <code>try/catch</code> 处理错误；缺点是不适合简单的应用程序、需要更多的模板代码、需要具备生成器的知识</li><li>基于 Promise 的中间件</li></ol><h4 id="333-数据流"><a class="markdownIt-Anchor" href="#333-数据流"></a> 3.3.3. 数据流</h4><p>React-Redux 应用程序的数据流是单向的。它只朝一个方向流动。</p><ol><li>操作创建器（action creator）朝根归纳器（root reducer）流动</li><li>根归纳器处理 <code>Action</code> 并返回新的状态到储存空间（store）</li><li>存储空间更新用户界面（UI）</li><li>用户界面调用操作创建器</li></ol><p>为什么要选择单向数据流：双向数据绑定会影响浏览器性能，而且很难跟踪数据流，因此 Redux 的单向数据流解决了这个问题。</p></body></html>]]></content>
    
    
    <summary type="html">本文是 IBM 全栈开发课程的第四篇学习笔记，系统性地介绍了如何使用 React 和 ES6 构建前端应用。内容从 React 的基础概念（如JSX、组件化）和 ES6 核心语法（箭头函数、类）讲起，深入探讨了组件的状态（state）与属性（props）、完整的生命周期、父子组件间的数据通信，以及如何使用 Hooks 为函数式组件添加状态。此外，笔记还涵盖了 React 表单处理和使用 Redux 进行全局状态管理等进阶主题。这篇笔记为 React 初学者提供了一份从入门到进阶的完整学习路径和知识点梳理。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="IBM" scheme="https://blog.cytrogen.icu/tags/IBM/"/>
    
    <category term="React.js" scheme="https://blog.cytrogen.icu/tags/React-js/"/>
    
  </entry>
  
  <entry>
    <title>IBM 全栈开发【3】：云原生 + 开发运维 + Agile + NoSQL</title>
    <link href="https://blog.cytrogen.icu/posts/d62.html"/>
    <id>https://blog.cytrogen.icu/posts/d62.html</id>
    <published>2024-01-10T16:22:41.000Z</published>
    <updated>2026-02-09T17:16:54.717Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程，故此记录学习笔记。</p><span id="more"></span><h1 id="1-云原生入门"><a class="markdownIt-Anchor" href="#1-云原生入门"></a> 1. 云原生入门</h1><p>云原生应用是一种构建和运行在云上的应用程序。云原生应用由协同工作的微服务组成，以充分利用云计算的优势。</p><p>云计算，简称「云」，是一种基于互联网的计算方式，通过这种方式，共享的软硬件资源和信息可以按需求提供给计算机各种终端和其他设备。</p><ul><li>NIST 将其定义为：一种实现对可配置计算资源的共享池进行便捷、按需网络访问的模式，这些资源可快速调配和释放，只需极少的管理工作或服务提供商的互动</li><li>计算资源包括网络、服务器、存储、应用程序和服务</li></ul><p>云模式由五个基本特征、四种部署模式和三种服务模式组成：</p><ul><li>五个基本特征：按需自助服务、广泛网络访问、资源池共享、快速弹性伸缩、可度量服务</li><li>四种部署模式：私有云、社区云、公有云、混合云</li><li>三种服务模式：基础设施即服务（IaaS）、平台即服务（PaaS）、软件即服务（SaaS）</li></ul><h2 id="11-现代软件开发"><a class="markdownIt-Anchor" href="#11-现代软件开发"></a> 1.1. 现代软件开发</h2><ul><li>以服务形式交付</li><li>集中托管并通过互联网访问</li><li>网络应用程序、SaaS</li></ul><h2 id="12-云原生堆栈"><a class="markdownIt-Anchor" href="#12-云原生堆栈"></a> 1.2. 云原生堆栈</h2><ol><li>应用程序代码：持有云原生应用程序</li><li>应用程序运行时：中间件</li><li>应用程序和数据服务：数据库、消息队列、缓存</li><li>调度和协调：控制面板，比如 Kubernetes</li><li>云基础设施：定义环境</li></ol><h2 id="13-使用案例"><a class="markdownIt-Anchor" href="#13-使用案例"></a> 1.3. 使用案例</h2><p>云中的一切都应采用云原生方法构建，以充分利用云的优势。</p><p>应用代码需要使用以下工具：</p><ul><li>标准化的日志</li><li>标准化的事件</li><li>多个微服务和云原生应用程序可使用的标准目录</li><li>微服务的标准化跟踪</li></ul><h2 id="14-cncf"><a class="markdownIt-Anchor" href="#14-cncf"></a> 1.4. CNCF</h2><p>云原生计算基金会（CNCF）是一个非营利性组织，致力于促进云原生计算的采用和技术进步。CNCF 的使命是通过开源、中立和可持续的项目来推动云原生计算的采用。</p><p>CNCF 通过为参与公司的项目提供营销和支持来帮助他们。CNCF 还通过培训和认证来支持开发人员。</p><h2 id="15-混合云"><a class="markdownIt-Anchor" href="#15-混合云"></a> 1.5. 混合云</h2><p>混合云是指在私有云和公有云之间创建连接的计算环境。 混合云允许应用程序和数据在私有云和公有云之间移动。</p><p>公共云由外部提供商管理，在一个硬件平台上有多个租户，可包括多个地点的服务器；私有云由企业管理，通常在企业的数据中心中，由企业拥有和使用。</p><p>内部部署的私有云属于单个组织，由其托管和管理自己的云空间。</p><h2 id="16-实践与方法"><a class="markdownIt-Anchor" href="#16-实践与方法"></a> 1.6. 实践与方法</h2><ul><li>测试驱动开发（TDD）：在编写代码之前编写测试</li><li>行为驱动开发（BDD）：关注从外部看到的系统行为，而非系统内部的工作方式</li><li>持续集成/持续交付（CI/CD）：一种软件开发方式；你可以构建和部署软件，以便随时将其发布到生产中</li><li>敏捷开发（Agile）：一种迭代的项目管理方法，可帮助团队快速响应并向客户交付价值</li><li>Scrum：一种进行增量产品开发的管理框架</li><li>微服务架构：一种单一应用程序由多个松散且可独立部署的小型服务组成的方法，每个服务通过 API 进行通信</li><li>容器（Container）：独立的、包罗万象的可执行软件单元</li></ul><h1 id="2-开发运维和cicd"><a class="markdownIt-Anchor" href="#2-开发运维和cicd"></a> 2. 开发运维和 CI / CD</h1><h2 id="21-开发运维devops"><a class="markdownIt-Anchor" href="#21-开发运维devops"></a> 2.1. 开发运维（DevOps）</h2><p>DevOps 是一种软件开发方法，旨在通过自动化软件交付流程来加快软件交付速度。DevOps 是开发（Dev）和运维（Ops）的组合。</p><blockquote><p>Patrick Debois 是 DevOps 的创始人。<br>他如此形容 DevOps：「敏捷开发环境的延伸，旨在加强整个软件交付的过程。「</p></blockquote><p>DevOps 推动文化和技术变革，促进开发和运维团队之间的协作，简化流程，自动化任务，并持续交付高质量的软件。</p><p>DevOps 提高了效率和客户价值，要求组织学习和文化转型。</p><p>其核心目标是自动化软件交付。</p><p>DevOps 诞生前，开发和运维团队之间的沟通和协作很少。开发团队开发软件，然后将其交付给运维团队，运维团队负责部署和维护软件。这种模式导致了开发和运维团队之间的隔阂，从而导致了低效率、低质量的软件交付。</p><p>各自为政行不通，因此 DevOps 的目标是将开发和运维团队合并为一个团队，并遵循敏捷开发原则，以便更快地交付更高质量的软件。</p><h4 id="211-devops的要求"><a class="markdownIt-Anchor" href="#211-devops的要求"></a> 2.1.1. DevOps 的要求</h4><ul><li>改变文化：重视开放、信任和透明度</li><li>新的应用设计：无需为增加一项功能而重新部署整个系统</li><li>利用自动化：加快并提高应用交付的一致性</li><li>可编程平台：持续部署</li></ul><h4 id="212-这些不是devops"><a class="markdownIt-Anchor" href="#212-这些不是devops"></a> 2.1.2. 这些不是 DevOps！</h4><ul><li>DevOps 不单单是简单地将开发和运营结合起来</li><li>DevOps 不是一种工具或技术</li><li>DevOps 不是一个独立的团队</li><li>DevOps 不是一刀切的解决方案</li><li>DevOps 不只是自动化</li></ul><h4 id="213-工具"><a class="markdownIt-Anchor" href="#213-工具"></a> 2.1.3. 工具</h4><ul><li><p>版本控制</p><ul><li>管理和跟踪更改</li><li>实现团队协作</li><li>维护记录</li><li>Git 实现了无缝代码管理</li><li>GitLab 和 GitHub 是两个流行的 Git 托管服务</li></ul></li><li><p>CI/CD</p><ul><li>自动构建、测试和部署流程</li><li>整合变更并自动发布</li><li>CI 工具：构建和测试<ul><li>Concourse CI</li><li>Circle CI</li><li>Travis CI</li></ul></li><li>CD 工具：自动化应用发布<ul><li>Spinnaker</li><li>Go CD</li><li>Argo CD</li></ul></li><li>CI / CD 工具<ul><li>Jenkins</li><li>Tekton</li><li>GitLab CI/CD</li><li>GitHub Actions</li></ul></li></ul></li><li><p>配置管理</p><ul><li>自动配置软件和基础设施，确保一致性并简化环境管理</li><li>Ansible</li><li>Chef</li><li>Puppet</li><li>SaltStack</li></ul></li><li><p>容器化和容器协调</p><ul><li>可在容器中打包和部署应用程序，从而实现轻松扩展和高效资源管理</li><li>Docker</li><li>Kubernetes</li></ul></li><li><p>监控和日志记录</p><ul><li>监视应用程序性能、健康状况并分析日志</li><li>Prometheus</li><li>Grafana</li><li>ELK Stack</li><li>Mesmo</li><li>New Relic</li></ul></li><li><p>合作和交流</p><ul><li>促进团队成员之间有效的团队合作、知识共享和协调</li><li>Slack</li><li>Microsoft Teams</li><li>Atlassian Jira</li><li>Trello</li><li>Asana</li></ul></li></ul><h2 id="22-cicd"><a class="markdownIt-Anchor" href="#22-cicd"></a> 2.2. CI/CD</h2><p>持续集成（CI）确保变更通过必要的测试；将测试变更集成到主分支中。</p><p>持续交付（CD）确保快速安全的部署；将变更交付到类似生产的环境中。</p><p>CI / CD 不是一个过程，而是两个不同的过程：CI 不断将代码整合回 <code>main/master/trunk</code> 分支，CD 将整合后的代码部署到生产环境。</p><ul><li>CI 包括计划、编码、构建和测试阶段</li><li>CD 包括发布、部署和运行阶段</li></ul><blockquote><p>持续部署（Continuous Deployment）是生产自动化，专门用于实际持续推送到生产环境的情况。<br>它与持续交付不同，后者是将代码部署到类似生产的环境中，比如开发服务器，但不会自动部署到生产环境。</p></blockquote><h4 id="221-ci的优势"><a class="markdownIt-Anchor" href="#221-ci的优势"></a> 2.2.1. CI 的优势</h4><ul><li>更快的代码更改反应时间<ol><li>更改代码</li><li>测试代码</li><li>构建变更</li><li>快速向客户交付解决方案</li></ol></li><li>降低代码集成风险<ul><li>集成小的内容</li><li>无需在代码库中集成大量代码</li><li>只需集成 10-50 行代码</li></ul></li><li>更高的代码质量<ul><li>PR（Pull Request）：开发人员将代码更改推送到代码库中的分支，然后请求其他开发人员审查和合并代码更改</li><li>当有人提出 PR 时，就可以对代码进行审查</li></ul></li><li>版本控制中的代码工作</li></ul><h2 id="23-tdd"><a class="markdownIt-Anchor" href="#23-tdd"></a> 2.3. TDD</h2><p>测试驱动开发（TDD）是一种软件开发方法，它要求在编写代码之前编写测试。</p><ol><li>编写失败的测试用例</li><li>编写足够的代码使测试通过</li><li>重构代码</li><li>重复</li></ol><p>TDD 意味着测试用例驱动代码的设计和开发，使开发人员能够更快地编写代码。</p><h2 id="24-bdd"><a class="markdownIt-Anchor" href="#24-bdd"></a> 2.4. BDD</h2><p>行为驱动开发（BDD）是一种软件开发方法，它关注从外部看到的系统行为，而非系统内部的工作方式。</p><p>在软件测试中执行 BDD 的适当级别是集中测试、系统测试和验收测试。</p><h1 id="3-agile"><a class="markdownIt-Anchor" href="#3-agile"></a> 3. Agile</h1><p>敏捷开发是一种迭代的项目管理方法，可帮助团队快速响应并向客户交付价值。</p><p>Agile 强调了：</p><ul><li>适应性规划</li><li>渐进式发展</li><li>早期交付</li><li>持续改进</li></ul><p>敏捷开发宣言：</p><ul><li>个人和互动高于流程和工具</li><li>可以工作的软件高于详尽的文档</li><li>客户合作高于合同谈判</li><li>响应变化高于遵循计划</li></ul><p>符合敏捷开发宣言的迭代式软件开发方法强调灵活性、互动性和高透明度，使用小型、同地办公、跨职能、自组织的团队。</p><blockquote><p>主要启示：按需建设，而非按计划建设。</p></blockquote><h2 id="31-scrum"><a class="markdownIt-Anchor" href="#31-scrum"></a> 3.1. Scrum</h2><div class="danger"><p>Agile 和 Scrum 不是同一个东西！</p><p>两者的区别为：</p><ul><li>Agile 是一种工作哲学（非规范性的）</li><li>Scrum 是一种工作方法（增加流程）</li></ul></div><p>Scrum 是一种渐进式产品开发的管理框架。</p><ul><li>规定了小型、跨职能、自我组织的团队</li><li>提供角色、会议、规则和工件的结构</li><li>使用固定长度的迭代，称为 Sprint</li><li>目标是在每次迭代中构建一个可交付的产品增量</li></ul><h4 id="311-sprint"><a class="markdownIt-Anchor" href="#311-sprint"></a> 3.1.1. Sprint</h4><p>Sprint 是设计、代码、测试和部署周期中的一次迭代。</p><p>每个 Sprint 都应有一个目标，且通常持续两周。</p><h4 id="312-scrum流程"><a class="markdownIt-Anchor" href="#312-scrum流程"></a> 3.1.2. Scrum 流程</h4><ol><li>产品积压（Product Backlog）：产品所有者（Product Owner）创建产品积压，其中包含想在产品中实现且未在 Sprint 中实施的所有功能<ul><li>按重要性和业务价值排序，最上方的功能最详细</li></ul></li><li>积压工作细化（Backlog Refinement）：团队和产品所有者一起讨论产品积压中的功能，以便团队了解功能的细节</li><li>Sprint 计划：定义在 Sprint 阶段可以交付的工作以及如何完成这些工作<ul><li>产品所有者、Scrum 主管（Scrum Master）和开发团队参与</li><li>目标在于定义每个 Sprint 的明确业务目标</li></ul></li><li>Sprint 积压（Sprint Backlog）：要比产品积压小得多，仅包含团队在下个 Sprint 中（未来两周内）要完成的功能</li><li>每日 Scrum：每个人都应回答三个问题<ul><li>昨天做了什么？</li><li>今天要做什么？</li><li>遇到了什么问题？</li></ul></li><li>有价值的产品</li></ol><h4 id="313-团队"><a class="markdownIt-Anchor" href="#313-团队"></a> 3.1.3. 团队</h4><p>适当的组织是成功的关键，这往往意味着现有团队可能需要重组。</p><p>团队应当是松散耦合、又紧密配合的。这代表着每个团队都有着自己的任务，同时还要与业务保持一致。</p><p>Scrum 强调自主权，这同时是一种鼓励团队成员自我管理的方法，也是速度和质量的保证。</p><p>决策在团队中就地做出，同时还让团队成员为自己构建的产品承担完全的责任。</p><p>自主权最大限度地减少了交接和等待，让团队成员能够快速做出决策并采取行动。</p><h2 id="32-agile不是"><a class="markdownIt-Anchor" href="#32-agile不是"></a> 3.2. Agile 不是……</h2><p>Agile 不仅仅只是迭代。在每次迭代的最后，团队都必须在部署应用程序后从客户那里收到反馈。</p><p>Agile 不是瀑布式软件开发生命周期的新版本。每次 Sprint 阶段都不应当是采取传统的开发方法，并且不能只有开发人员参与，它涉及一个跨职能的团队。</p><h2 id="33-鸡汤"><a class="markdownIt-Anchor" href="#33-鸡汤"></a> 3.3. 鸡汤</h2><p>不要在最不了解的时候决定一切，应当根据所了解的情况制定计划。 随着了解的增多而调整计划，你的估计会更加准确。</p><p>如何失败：不对员工进行培训就安排他们担任新职务。</p><h4 id="331-职务之间的区别"><a class="markdownIt-Anchor" href="#331-职务之间的区别"></a> 3.3.1. 职务之间的区别</h4><p>产品经理（Product Manager）：管理预算的业务人员，主要负责业务运营方面。</p><p>产品所有者（Product Owner）：项目中有远见的人，带领团队进行一系列旨在实现 Sprint 目标的实验。</p><p>项目经理（Project Manager）：让每个人都按照固定计划行事的任务负责人。</p><p>Scrum 主管（Scrum Master）：让团队专注于当前 Sprint 的教练，帮助团队解决问题、消除障碍并保持团队的高效率。</p><p>开发团队（Development Team）：仅由开发人员组成的团队。</p><p>Scrum 团队（Scrum Team）：跨职能团队，包括开发人员、测试人员、安全人员、业务分析师、运营人员等。</p><h2 id="34-用户故事"><a class="markdownIt-Anchor" href="#34-用户故事"></a> 3.4. 用户故事</h2><p>用户故事（User Story）是一种简短的、简单的描述，代表团队在一次迭代中可以交付的一小部分业务价值。</p><p>用户故事往往包含了以下几个部分：</p><ul><li>为谁而设？</li><li>他们需要什么？</li><li>为什么他们需要？</li><li>他们从中获得的商业价值是什么？</li></ul><p>用户故事的内容应是需求和业务价值的简要说明，包含了所有的假设和细节，即「完成」的定义。</p><p>用户故事记录了一个角色为实现目标而提出的功能要求，即：作为一个【角色】我需要【功能】以便【目标】。</p><h4 id="341-验收标准"><a class="markdownIt-Anchor" href="#341-验收标准"></a> 3.4.1. 验收标准</h4><p>记录「完成」的定义至关重要，要让利益相关者、客户和开发人员都能轻松描述「完成」的定义。</p><p>也就是：给定【条件】，当【事件】发生时，我希望【结果】。</p><h4 id="342-invest原则"><a class="markdownIt-Anchor" href="#342-invest原则"></a> 3.4.2. INVEST 原则</h4><ul><li>独立性（Independent）：用户故事应该是独立的，这样就可以按照任何顺序进行开发</li><li>可协商性（Negotiable）：用户故事应该是可协商的，这样就可以在开发过程中进行更改</li><li>有价值（Valuable）：用户故事应该是有价值的，这样就可以在每次迭代中交付价值</li><li>可估算（Estimable）：用户故事应该是可估算的，这样就可以在每次迭代中估算工作量</li><li>小型（Small）：用户故事应该是小型的，这样就可以在每次迭代中交付</li><li>可测试（Testable）：用户故事应该是可测试的，这样就可以在每次迭代中测试</li></ul><h4 id="343-epic"><a class="markdownIt-Anchor" href="#343-epic"></a> 3.4.3. Epic</h4><p>Epic 是一种大型用户故事，它可以进一步分解为较小的用户故事。</p><p>当一个用户故事的范围过大时，就会被称为 Epic。当优先级较低、定义较少时，积压项目往往会以 Epic 的形式存在。</p><h4 id="344-故事点"><a class="markdownIt-Anchor" href="#344-故事点"></a> 3.4.4. 故事点</h4><p>故事点（Story Points）是一种估算工作量、估算特定用户故事实施难度的指标。它是总体工作量的抽象度量，而非时间单位。</p><p>我们需要承认人类非常不善于估算时间，因此要使用相对估算。许多工具采取了 Fibonacci 数列，因为它们是一种指数级增长的数列。用更抽象的概念来比喻的话，就是衣服的尺码。</p><p>例如，在第一个 Sprint 中，团队估算一个用户故事的故事点为 M 尺码，这可能会花费两天时间，也可能会花费一周时间。在第二个 Sprint 中，团队对故事点的估算有了更精准的认知，因此在估算另一个用户故事时，会根据花费在第一个用户故事上的时间，以及第二个用户故事的复杂程度，来估算第二个用户故事的故事点。</p><p>切记，绝对不要将故事点与时间混淆。</p><h1 id="4-nosql"><a class="markdownIt-Anchor" href="#4-nosql"></a> 4. NoSQL</h1><p>NoSQL 这个概念在一次关于分布式数据库的开源活动中被提出。全称是 Not Only SQL，意思是「不仅仅是 SQL」。</p><p>NoSQL 是一种非关系型数据库，它不使用 SQL 作为查询语言，而是使用其他语言。没有了标准的行和列，NoSQL 数据库可以存储各种类型的数据，且在存储和查询数据的方式上更加灵活。</p><p>NoSQL 设计用于大型数据集的高性能和灵活性，它们通常用于 Web 应用程序和大数据应用程序。</p><h2 id="41-mongodb"><a class="markdownIt-Anchor" href="#41-mongodb"></a> 4.1. MongoDB</h2><p>MongoDB 是一种开源的文档和 NoSQL 数据库，它使用类似于 JSON 对象和 Python 字典的文档来存储数据。</p><pre><code class="language-json">{    "firstName": "John",    "lastName": "Doe",    "email": "john.doe@email.com",    "studentId": 20217484}</code></pre><p>集合（Collection）是一组文档，类似于关系数据库中的表。比方说，你可以创建一个名为 <code>students</code> 的集合，其中包含所有学生的文档。</p><p>数据库（Database）是一组集合，类似于关系数据库中的数据库。比方说，你可以创建一个名为 <code>school</code> 的数据库，其中包含所有学生的集合。</p><h4 id="411-mongodb的优势"><a class="markdownIt-Anchor" href="#411-mongodb的优势"></a> 4.1.1. MongoDB 的优势</h4><ul><li>在读取和写入数据时建立数据模型，而非传统的先创建模式、再创建表格</li><li>让用户能够引入任何结构化或非结构化数据</li><li>通过保存多份数据副本，提高数据的可用性</li></ul><p>MongoDB 适合用于大型和非结构化、复杂、灵活、高度可扩展的应用程序。</p><p>在传统的关系数据库中，你需要先设计，再写代码。例如：</p><pre><code class="language-bash">CREATE TABLE Students (FirstName varchar(255),    LastName varchar(255),    Email varchar(255),    StudentId int);INSERT INTO StudentsVALUES ("John",        "Doe",       "john.doe@email.com",        20217484);</code></pre><p>而在 MongoDB 中，你可以直接写代码，无需设计复杂的表格定义。例如：</p><pre><code class="language-bash">db.persons.insertOne({"firstName": "John",    "lastName": "Doe",    "email": "john.doe@email.com",    "studentId": 20217484})</code></pre><h4 id="412-案例"><a class="markdownIt-Anchor" href="#412-案例"></a> 4.1.2. 案例</h4><p>假设你正经营一家快递公司，因此需要存储送货地址。随着 2020 年送货流程的巨大变化，你需要存储更多的数据，比如该客户是否选用了无接触送货。</p><p>使用 MongoDB 可以轻松存储这些数据；如果使用的是关系数据库，你可能需要重新设计表格，以便存储新的数据。</p><h4 id="413-查询和分析"><a class="markdownIt-Anchor" href="#413-查询和分析"></a> 4.1.3. 查询和分析</h4><p>MongoDB 提供了一种查询语言，称为 MongoDB 查询语言（MQL）。MQL 拥有多种操作符，可用于查询和分析数据。</p><p>如果查询还要更复杂，你可以使用 MongoDB 聚合管道（Aggregation Pipeline）。</p><p>以下是一些实践练习：</p><ol><li><p>启动 MongoDB Shell</p><pre><code class="language-bash">mongo</code></pre></li><li><p>连接到 MongoDB 服务器</p><pre><code class="language-bash">mongosh -u root -p xxx --authenticationDatabase admin local</code></pre></li><li><p>列出所有数据库</p><pre><code class="language-bash">show dbs</code></pre></li><li><p>创建一个名为 <code>school</code> 的数据库</p><pre><code class="language-bash">use school</code></pre></li><li><p>创建一个名为 <code>students</code> 的集合</p><pre><code class="language-bash">db.createCollection("students")</code></pre></li><li><p>列出所有集合</p><pre><code class="language-bash">show collections</code></pre></li><li><p>向 <code>students</code> 集合中插入一条文档</p><pre><code class="language-bash">db.students.insertOne({"firstName": "John",     "lastName": "Doe"})</code></pre></li><li><p>数插入了多少条文档</p><pre><code class="language-bash">db.students.count()</code></pre></li><li><p>列出所有文档</p><pre><code class="language-bash">db.students.find()</code></pre></li><li><p>更新一条文档</p><pre><code class="language-bash">db.students.updateOne({"firstName": "John"},    {$set: {"lastName": "Smith"}})</code></pre></li><li><p>删除一条文档</p><pre><code class="language-bash">db.students.deleteOne({"firstName": "John"})</code></pre></li><li><p>从服务器断开连接</p><pre><code class="language-bash">exit</code></pre></li></ol><h4 id="414-mongo-shell"><a class="markdownIt-Anchor" href="#414-mongo-shell"></a> 4.1.4. Mongo Shell</h4><p>Mongo Shell 是 MongoDB 的命令行接口，它允许你与 MongoDB 服务器进行交互。</p><p>Mongo Shell 也是一种 JavaScript 解释器，它允许你在 MongoDB 服务器上运行 JavaScript 代码。</p><p>连接到集群：</p><pre><code class="language-bash">mongosh "mongodb://USER:PASSWORD@url/test"</code></pre></body></html>]]></content>
    
    
    <summary type="html">本文是 IBM 全串开发课程的第三篇学习笔记，集中梳理了现代软件开发的四大关键领域：云原生、DevOps、敏捷开发和NoSQL数据库。内容涵盖云原生的核心理念与技术栈，DevOps的文化精髓与CI/CD自动化流程，敏捷开发中的Scrum框架、用户故事和Sprint迭代，以及以MongoDB为例的NoSQL数据库模型与操作。这篇笔记为理解当今主流的软件开发与运维模式提供了高度浓缩的知识框架。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="IBM" scheme="https://blog.cytrogen.icu/tags/IBM/"/>
    
    <category term="Agile" scheme="https://blog.cytrogen.icu/tags/Agile/"/>
    
    <category term="NoSQL" scheme="https://blog.cytrogen.icu/tags/NoSQL/"/>
    
  </entry>
  
  <entry>
    <title>IBM 全栈开发【2】：网页三剑客</title>
    <link href="https://blog.cytrogen.icu/posts/3571.html"/>
    <id>https://blog.cytrogen.icu/posts/3571.html</id>
    <published>2024-01-09T21:32:04.000Z</published>
    <updated>2026-02-09T17:16:54.717Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程，故此记录学习笔记。</p><span id="more"></span><h1 id="1-云编程入门"><a class="markdownIt-Anchor" href="#1-云编程入门"></a> 1. 云编程入门</h1><p>SASS：语法强大的样式表（Syntactically Awesome Style Sheets）。</p><ul><li>CSS 的扩展</li><li>可以使用变量、嵌套规则、内联导入等方法来保持条理清晰</li><li>更快、更轻松地创建样式表</li></ul><p>LESS：动态样式语言（Leaner Style Sheets）。</p><ul><li>增强 CSS</li><li>向后兼容 CSS</li><li><code>Less.js</code> 是一种 JavaScript 工具，可将 LESS 样式转换为 CSS 样式</li></ul><h2 id="11-javascript框架"><a class="markdownIt-Anchor" href="#11-javascript框架"></a> 1.1. JavaScript 框架</h2><h4 id="111-angular"><a class="markdownIt-Anchor" href="#111-angular"></a> 1.1.1. Angular</h4><ul><li>开源</li><li>由 Google 维护</li><li>让网站快速高效地呈现 HTML 页面</li><li>内置路由器、表单验证工具</li></ul><h4 id="112-react"><a class="markdownIt-Anchor" href="#112-react"></a> 1.1.2. React</h4><ul><li>由 Facebook 开发和维护</li><li>用于构建和渲染网页组件的 JavaScript 库</li></ul><h4 id="113-vue"><a class="markdownIt-Anchor" href="#113-vue"></a> 1.1.3. Vue</h4><ul><li>由社区维护，其主要重要是视图层，包括用户界面、按钮和可视化组件</li><li>灵活、可扩展，能与其他框架很好地集成</li><li>适应性强</li></ul><h2 id="12-代码库"><a class="markdownIt-Anchor" href="#12-代码库"></a> 1.2. 代码库</h2><ul><li>jQuery：简化 DOM 操作的 JavaScript 库</li><li>Email-validator：验证电子邮件地址的构造是否正确有效</li><li>Apache Commons Proper：可重复使用的 Java 组件</li></ul><h2 id="13-cicd"><a class="markdownIt-Anchor" href="#13-cicd"></a> 1.3. CI/CD</h2><p>CI 指的是「持续集成」，CD 指的是「持续交付」或「持续部署」。</p><p>CI / CD 是开发团队的最佳实践，可帮助团队更快地交付高质量的软件。</p><p>通过构建自动化服务器实施，CI 确保所有代码组件顺利协同工作，而 CD 则确保代码在构建后自动部署到生产环境。</p><h2 id="14-构建工具"><a class="markdownIt-Anchor" href="#14-构建工具"></a> 1.4. 构建工具</h2><p>构建工具是一种将源代码转换为二进制文件以便安装或部署的工具。</p><p>它在有许多相互连接的项目的环境中非常有用，因为它可以自动化构建过程，从而减少了手动操作的数量。</p><ol><li>构建自动化实用程序：通过编译和链接源代码来生成可执行文件</li><li>构建自动化服务器：按计划或触发式执行构建自动化实用程序</li></ol><blockquote><ul><li>Webpack：模块打包器，将应用程序的所有模块打包到一起</li><li>Babel：JavaScript 编译器，将 ES6 + 代码转换为向后兼容的 JavaScript 代码</li><li>Web Assembly：一种可移植、体积小、加载快的二进制格式，可在 Web 上运行</li></ul></blockquote><h4 id="141-云应用程序软件包管理器"><a class="markdownIt-Anchor" href="#141-云应用程序软件包管理器"></a> 1.4.1. 云应用程序软件包管理器</h4><ul><li>npm：Node.js 的包管理器</li><li>Maven：Java 的包管理器</li><li>Gradle：Java 的构建自动化工具</li><li>RubyGems：Ruby 的包管理器</li><li>Pip：Python 的包管理器</li><li>Conda：Python 的包管理器</li></ul><h2 id="15-api-路由和端点"><a class="markdownIt-Anchor" href="#15-api-路由和端点"></a> 1.5. API、路由和端点</h2><p>API（应用程序编程接口）是一组定义了应用程序如何与其他软件组件进行交互的规则。它处理数据的请求和响应。</p><p>路由是一种将 URL 映射到应用程序中的特定端点的方法。它是通往网站的路径。</p><p>端点可以是 API 也可以是路由。它是应用程序中的特定位置，用于处理特定的请求。</p><h2 id="16-orm"><a class="markdownIt-Anchor" href="#16-orm"></a> 1.6. ORM</h2><p>ORM（对象关系映射）是一种将对象模型映射到关系模型的技术。它可用于连接数据库和检索正确的数据，并可隐藏查询数据库的部分复杂性。</p><h1 id="2-html概述"><a class="markdownIt-Anchor" href="#2-html概述"></a> 2. HTML 概述</h1><h2 id="21-html5规范"><a class="markdownIt-Anchor" href="#21-html5规范"></a> 2.1. HTML5 规范</h2><ul><li>定义了 HTML5，可以用 HTML 或者 XML 编写</li><li>定义了一种可与早期 HTML 实现互操作的模式</li></ul><h2 id="22-html5的新特性"><a class="markdownIt-Anchor" href="#22-html5的新特性"></a> 2.2. HTML5 的新特性</h2><ul><li>改进了语义元素</li><li>包括了 API，如网络存储、地理定位、拖放和多媒体</li><li>对网页进行了分类</li><li>开发了跨浏览器和跨平台的应用程序</li><li>创造了引人入胜的用户体验</li></ul><p>关键主题：</p><ul><li>语法与 HTML4 和 XHTML1 文档兼容</li><li>将用户代理和作者的一致性要求分开<ul><li>用户代理：支持早期用户代理规范的元素和属性</li><li>作者：删除了一些元素和属性以简化语言</li></ul></li></ul><h2 id="23-元素"><a class="markdownIt-Anchor" href="#23-元素"></a> 2.3. 元素</h2><p>元素是 HTML 文档的构建块，由开始标记、结束标记和内容组成。</p><p>HTML5 新增了许多元素，如：</p><ul><li><code>&lt;section&gt;</code>：定义文档中的节</li><li><code>&lt;article&gt;</code>：定义独立的内容</li><li><code>&lt;aside&gt;</code>：定义页面内容之外的内容</li><li>等等等等</li></ul><h2 id="24-dom"><a class="markdownIt-Anchor" href="#24-dom"></a> 2.4. DOM</h2><p>DOM（文档对象模型）是一种将 HTML 文档表示为树结构的方法。它定义了访问和操作 HTML 文档的标准。</p><table><thead><tr><th>属性</th><th>描述</th></tr></thead><tbody><tr><td><code>head</code></td><td>返回文档的 <code>&lt;head&gt;</code> 元素</td></tr><tr><td><code>title</code></td><td>设置或返回文档的 <code>&lt;title&gt;</code> 元素</td></tr><tr><td><code>images</code></td><td>返回文档中的所有 <code>&lt;img&gt;</code> 元素</td></tr><tr><td><code>lastModified</code></td><td>返回文档最后修改的日期和时间</td></tr><tr><td><code>scripts</code></td><td>返回文档中的所有 <code>&lt;script&gt;</code> 元素</td></tr><tr><td><code>getElementById()</code></td><td>返回第一个具有指定 ID 的元素</td></tr><tr><td><code>getElementByTagName()</code></td><td>返回具有指定标签名称的所有元素的集合</td></tr><tr><td><code>open()</code></td><td>打开一个流，以收集来自任何 <code>write()</code> 或 <code>writeln()</code> 方法的输出</td></tr><tr><td><code>write()</code></td><td>向文档写入 HTML 表达式或 JavaScript 代码</td></tr><tr><td><code>close()</code></td><td>关闭由 <code>open()</code> 方法打开的输出流</td></tr></tbody></table><p>例子：</p><pre><code class="language-html">&lt;script type="text/javascript"&gt;    function textChecker() {        const textField1 = document.getElementById('textField1');        if (textField1.value === '') {            alert('Please type in the field');        } else {            alert('You entered: ' + textField1.value);        }    }&lt;/script&gt;&lt;body&gt;&lt;input type='text' id='textField1'&gt;&lt;input type='button' onClick='textChecker()' value='Submit'&gt;&lt;/body&gt;</code></pre><h4 id="241-dom树访问器"><a class="markdownIt-Anchor" href="#241-dom树访问器"></a> 2.4.1. DOM 树访问器</h4><p>每个 HTML 和 XML 文档都由一个文档对象来表示，DOM 树访问器可用于访问和操作该文档对象。</p><h2 id="25-xml"><a class="markdownIt-Anchor" href="#25-xml"></a> 2.5. XML</h2><p>XML（可扩展标记语言）是一种用于定义其他标记语言的元语言。它是一种可扩展的标记语言，可用于定义其他标记语言。</p><p>例子：</p><pre><code class="language-xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;&lt;html xmlns="https://www.w3.org/1999/xhtml"&gt;    &lt;head&gt;        &lt;meta http-equiv="Content-Type" content="application/xhtml+xml; charset=ISO-8859-1" /&gt;          &lt;title&gt;Example document&lt;/title&gt;    &lt;/head&gt;    &lt;body&gt;        &lt;p&gt;            Example paragraph.        &lt;/p&gt;    &lt;/body&gt;&lt;/html&gt;</code></pre><blockquote><p>内容类型必须指定为 XML 媒体类型。</p></blockquote><p>那 HTML 和 XHTML 哪个更好呢？</p><p>XHTML 中标签必须小写、代码必须格式正确；HTML 中标签可以大写，代码格式不重要、允许使用不匹配的引号、非结束元素和非包含元素。</p><h2 id="26-脚本"><a class="markdownIt-Anchor" href="#26-脚本"></a> 2.6. 脚本</h2><p>脚本是一种用于控制应用程序行为的编程语言。它可以嵌入到 HTML 中，也可以作为外部文件引用。</p><p>脚本提供了交互式用户体验，用于各种用途，如表单验证、动画、游戏、动态更新等。</p><p>开发者可以使用 <code>&lt;script&gt;</code> 元素将脚本嵌入到 HTML 中。</p><h2 id="27-iframe"><a class="markdownIt-Anchor" href="#27-iframe"></a> 2.7. iframe</h2><p>iframe 是一种 HTML 元素，用于在网页中嵌入另一个网页。它是一种内联框架，可用于在网页中显示其他网页。</p><p>iframe 可以用于显示广告、嵌入视频、显示其他网站的内容等。</p><p>例子：</p><pre><code class="language-html">&lt;iframe src=""&gt;&lt;/iframe&gt;</code></pre><p>为了防止授予隐式权限，iframe 可以使用 <code>sandbox</code> 属性。</p><pre><code class="language-html">&lt;iframe src="" sandbox&gt;&lt;/iframe&gt;</code></pre><h2 id="28-浏览器"><a class="markdownIt-Anchor" href="#28-浏览器"></a> 2.8. 浏览器</h2><p>并非所有浏览器都完全支持 HTML5 和 CSS3。比方说 <code>&lt;input type="date"&gt;</code>，在不同浏览器中的显示效果是不一样的。</p><p>可以使用 JavaScript 来检测浏览器是否支持某些功能。</p><p>例子：</p><pre><code class="language-html">&lt;body&gt;    &lt;form id='thisform'&gt;&lt;/form&gt;    &lt;script&gt;        const datepicker = document.createElement('input');        const formelement = document.getElementById('thisform');        datepicker.setAttribute('type', 'date');        formelement.appendChild(datepicker);        if (datepicker.type === 'text') {            alert('Date input not supported');        }    &lt;/script&gt;&lt;/body&gt;</code></pre><h1 id="3-css概述html5元素"><a class="markdownIt-Anchor" href="#3-css概述html5元素"></a> 3. CSS 概述 &amp; HTML5 元素</h1><h2 id="31-html5结构元素"><a class="markdownIt-Anchor" href="#31-html5结构元素"></a> 3.1. HTML5 结构元素</h2><ul><li><code>&lt;article&gt;</code>：代表独立的内容，如博客文章、报纸文章、杂志文章或论坛帖子；和 <code>&lt;time pubdate ...&gt;</code> 属性一起使用可以表示发布日期</li><li><code>&lt;section&gt;</code>：代表文档中的节或主题，如章节、页眉、页脚或文档中的其他部分；它可以包含标题</li><li><code>&lt;header&gt;</code>：代表文档或节的标题；它可以包含标题</li><li><code>&lt;footer&gt;</code>：代表文档或节的页脚；它可以包含页脚</li></ul><h4 id="311-内容分组"><a class="markdownIt-Anchor" href="#311-内容分组"></a> 3.1.1. 内容分组</h4><ul><li><code>&lt;div&gt;</code>：提供了灵活的控制，可将样式应用于文档的各个部分；除了对内容进行分组之外，它没有任何特定的含义</li><li><code>&lt;aside&gt;</code>：代表页面内容之外的内容，如侧栏、广告、导航链接、引用或其他类似的内容</li><li><code>&lt;nav&gt;</code>：代表导航链接的部分，如菜单、目录或索引</li><li><code>&lt;figure&gt;</code>：代表独立的内容，如图表、图像、照片、代码清单、音频或视频</li><li><code>&lt;figcaption&gt;</code>：代表 <code>&lt;figure&gt;</code> 元素的标题</li></ul><h2 id="32-css"><a class="markdownIt-Anchor" href="#32-css"></a> 3.2. CSS</h2><p>CSS 设计了 HTML 文档的外观和样式。</p><p>在 CSS 中，子元素通常继承了父元素的样式。</p><p>CSS 可以作为 HTML 标签、文档标题、文档头部、文档内部或外部的样式表来实现。</p><blockquote><p>数据与设计分离，这意味着可以在不更改 HTML 的情况下更改样式。<br>使用 HTML 向浏览器发送数据，并使用 CSS 对数据进行设计，这允许在不进行设计的情况下根据特殊的无障碍需求呈现网页。</p></blockquote><p>将 CSS 应用于 HTML 文档有三个方法，它们的顺序决定了优先级：</p><ol><li>内联样式：将样式应用于单个元素</li><li>内部样式表：将样式应用于整个文档</li><li>外部样式表：将样式应用于多个文档</li></ol><h4 id="321-布局"><a class="markdownIt-Anchor" href="#321-布局"></a> 3.2.1. 布局</h4><ol><li>流式布局（Fluid Layout）：使用百分比来定义宽度，使网页能够适应不同的屏幕尺寸<ul><li>元素的尺寸根据浏览器窗口的大小而变化</li><li>优点：适应性强</li><li>缺点：设计困难</li></ul></li><li>固定布局（Fixed Layout）：使用像素来定义宽度，使网页在不同的屏幕尺寸下保持固定的宽度<ul><li>元素的尺寸不会随着浏览器窗口的大小而变化</li><li>优点：设计简单</li><li>缺点：不适应不同的屏幕尺寸</li></ul></li></ol><h4 id="322-css框架"><a class="markdownIt-Anchor" href="#322-css框架"></a> 3.2.2. CSS 框架</h4><p>CSS 框架是一种用于设计网页的 CSS 库。它们提供了一组可重复使用的 CSS 类，可用于设计网页。</p><ol><li><p>不使用任何框架的情况下，开发者需要编写大量的 CSS 代码来设计网页。优点是可以完全控制网页的设计，缺点是需要花费大量的时间和精力</p><p>例如：</p> <pre><code class="language-css">a {    color: red;    text-decoration: underline;}a:hover {    color: rgb(185, 28, 28);}</code></pre></li><li><p>实用优先的框架：Tailwind CSS，它提供了可以使用的 CSS 属性。优点是给予了开发者更多的控制权</p><p>例如：</p><pre><code class="language-html">&lt;a href="..." class="underline text-red-500 hover:text-red-700"&gt;Dangerous Link&lt;/a&gt;</code></pre></li><li><p>组件框架：Bootstrap，它提供了一系列可重复使用的预定义组件。优点是可以快速设计网页，缺点是开发者无法完全控制网页的设计</p><p>例如：</p><pre><code class="language-html">&lt;a href="..." class="link-danger"&gt;Dangerous Link&lt;/a&gt;</code></pre></li></ol><h1 id="4-网络应用程序的-javascript-编程"><a class="markdownIt-Anchor" href="#4-网络应用程序的-javascript-编程"></a> 4. 网络应用程序的 JavaScript 编程</h1><h2 id="41-javascript的性质"><a class="markdownIt-Anchor" href="#41-javascript的性质"></a> 4.1. JavaScript 的性质</h2><p>JavaScript 是一种脚本语言，用于控制应用程序的行为。它是一种解释性语言，不需要编译。</p><ul><li>源自 ECMAScript 标准</li><li>最初设计用于在 NetScape Navigator 中使用</li><li>与 Java 无关！</li><li>JavaScript 解释器嵌入在浏览器中，为静态网页内容添加动态功能</li><li>核心功能为异步 JavaScript 和 XML（AJAX）</li></ul><h2 id="42-变量作用域"><a class="markdownIt-Anchor" href="#42-变量作用域"></a> 4.2. 变量作用域</h2><p>变量作用域是指变量在程序中可见的区域。在 JavaScript 中，变量可以是全局的或局部的。</p><ul><li>全局变量：在函数外部声明的变量</li><li>局部变量：在函数内部声明的变量</li></ul><p>不使用 <code>var</code> 关键字声明的变量是全局变量，即使它们在函数内部声明。其值为 <code>undefined</code>。</p><h2 id="43-函数"><a class="markdownIt-Anchor" href="#43-函数"></a> 4.3. 函数</h2><p>例子：</p><pre><code class="language-javascript">function add(n, m) {    return n + m;}var x = add(1,2); // returns 3x = add(1.23, 3.45); // returns 4.68x = add("hello", "world"); // returns "helloworld"</code></pre><pre><code class="language-javascript">function Car(make, model, year) {    this.make = make;    this.model = model;    this.year = year;    this.getName = function () {        return this.make + ' ' + this.model + ' ' + this.year;    }}var c = new Car ("Meridian", "Saber GT", 2012);alert(c.getName()); // displays "Meridian Saber GT 2012"</code></pre><h2 id="44-api"><a class="markdownIt-Anchor" href="#44-api"></a> 4.4. API</h2><p>常用的 API：</p><table><thead><tr><th>文档</th><th>元素</th><th>Window</th></tr></thead><tbody><tr><td><code>document.getElementById()</code></td><td><code>element.innerHTML</code></td><td><code>window.open</code></td></tr><tr><td><code>document.getElementByTagName()</code></td><td><code>element.style</code></td><td><code>window.onload</code></td></tr><tr><td><code>document.createElement()</code></td><td><code>element.setAttribute</code></td><td><code>window.scrollTo</code></td></tr><tr><td><code>parentNode.appendChild()</code></td><td><code>element.getAttribute</code></td><td></td></tr></tbody></table><p>例子：</p><pre><code class="language-javascript">// how to retrieve all the image elements from a web pagevar imgSet = document.getElementsByTagName("img");var output = "";for (var i = 0; i &lt; imgSet.length; i++) {    output += "&lt;p&gt;Source for image ";    output += i;    output += ": ";    output += imgSet[i].src;    output += "&lt;\/p&gt;";}document.write(output);</code></pre><pre><code class="language-html">&lt;!-- How to add a node to a document --&gt;&lt;head&gt;    &lt;script&gt;        function addPara() {            const newPara = document.createElement("p");            const newText = document.createTextNode("Hello World!");            newPara.appendChild(newText);            document.body.appendChild(newPara);        }    &lt;/script&gt;&lt;/head&gt;&lt;body onload="addPara()"&gt;&lt;/body&gt;</code></pre><pre><code class="language-html">&lt;script&gt;    onload = (function () {        addPara();    })();    function addPara() {        const newPara = document.createElement("p");        newPara.innerHTML = "Hello world!";        document.body.appendChild(newPara);    }&lt;/script&gt;</code></pre><h2 id="45-html中的脚本"><a class="markdownIt-Anchor" href="#45-html中的脚本"></a> 4.5. HTML 中的脚本</h2><p>脚本为作者提供了一种以高度交互方式扩展 HTML 文档的方法，例如：</p><ul><li>在加载 HTML 文档后运行</li><li>验证表单并处理输入的内容</li><li>由影响文档的事件触发</li><li>在 HTML 页面中动态创建内容</li></ul><h4 id="451-脚本不可用时"><a class="markdownIt-Anchor" href="#451-脚本不可用时"></a> 4.5.1. 脚本不可用时</h4><p>如果浏览器不支持脚本或者脚本被禁用，可以使用 <code>&lt;noscript&gt;</code> 元素来提供替代内容。</p><pre><code class="language-html">&lt;noscript&gt;    &lt;p&gt;JavaScript is not enabled!&lt;/p&gt;&lt;/noscript&gt;</code></pre><h2 id="46-dom"><a class="markdownIt-Anchor" href="#46-dom"></a> 4.6. DOM</h2><p>万维网联盟（W3C）定义了 DOM（文档对象模型）标准，用于访问和操作 HTML 文档。DOM 规范有四级：</p><ol start="0"><li>DOM Level 0：最初的 DOM 规范，定义了 HTML 和 JavaScript 之间的接口</li><li>DOM Level 1：定义了 HTML 和 XML 文档的核心接口</li><li>DOM Level 2：包括了样式表模型和用于操作附加到文档中的样式信息的接口</li><li>DOM Level 3：指定了内容模型和文件验证</li><li>DOM Level 4：添加了突变观察器，以替代突变事件</li></ol><h4 id="461-浏览器的基本dom模型"><a class="markdownIt-Anchor" href="#461-浏览器的基本dom模型"></a> 4.6.1. 浏览器的基本 DOM 模型</h4><ul><li><code>window</code> 对象：代表浏览器窗口<ul><li>位于对象层级的顶端</li><li>浏览器加载页面时自动创建</li><li>可通过 JavaScript 代码访问属性和函数</li><li>在客户端 JavaScript 中，<code>window</code> 对象是全局对象</li></ul></li><li><code>history</code> 对象：允许模拟点击浏览器的前进和后退按钮</li><li><code>location</code> 对象：代表当前加载的文档的 URL</li><li><code>navigator</code> 对象：代表浏览器的信息</li><li><code>screen</code> 对象：代表用户的屏幕信息</li><li><code>document</code> 对象：代表当前加载的文档</li></ul><h4 id="462-dom第二级"><a class="markdownIt-Anchor" href="#462-dom第二级"></a> 4.6.2. DOM 第二级</h4><p>DOM 第二级添加了回车、制表符和空格。</p><table><thead><tr><th>节点类型</th><th>整数值</th><th>节点名称</th><th>节点值</th><th>描述</th></tr></thead><tbody><tr><td>元素</td><td>1</td><td><code>Tag name</code></td><td><code>null</code></td><td>任意 HTML 标签</td></tr><tr><td>属性</td><td>2</td><td><code>Attribute name</code></td><td><code>Attribute value</code></td><td>键值对</td></tr><tr><td>文本</td><td>3</td><td><code>#text</code></td><td><code>Text content</code></td><td>元素包含的文本</td></tr><tr><td>注释</td><td>8</td><td><code>#comment</code></td><td><code>Text comment</code></td><td>HTML 注释</td></tr><tr><td>文档</td><td>9</td><td><code>#document</code></td><td><code>null</code></td><td>文档对象</td></tr><tr><td>文档类型</td><td>10</td><td><code>DOCTYPE</code></td><td><code>null</code></td><td>DTD 规范</td></tr><tr><td>Fragment</td><td>11</td><td><code>#document fragment</code></td><td><code>null</code></td><td>文档外的节点</td></tr></tbody></table><p>DOM 二级节点对象属性和相应的数据类型：</p><table><thead><tr><th>对象属性</th><th>数据类型</th><th>描述</th></tr></thead><tbody><tr><td><code>nodeName</code></td><td>字符串</td><td>参考上表</td></tr><tr><td><code>nodeValue</code></td><td>字符串</td><td>参考上表</td></tr><tr><td><code>nodeType</code></td><td>整数</td><td>整数常数；参考上表</td></tr><tr><td><code>parentNode</code></td><td>对象</td><td>最近的包含对象</td></tr><tr><td><code>childNodes</code></td><td>数组</td><td>所有的子节点</td></tr><tr><td><code>firstChild</code></td><td>对象</td><td>第一个子节点</td></tr><tr><td><code>lastChild</code></td><td>对象</td><td>最后一个子节点</td></tr><tr><td><code>Attributes</code></td><td>NodeMap</td><td>属性的数组</td></tr></tbody></table></body></html>]]></content>
    
    
    <summary type="html">本文是 IBM 全栈开发课程系列的学习笔记第二篇，内容围绕构建现代网页应用的核心技术——HTML、CSS和JavaScript展开。笔记首先概述了云编程的生态环境，涵盖前端框架、CI/CD、构建工具等关键概念。随后，文章深入探讨了HTML5的语义化标签与DOM操作，CSS的布局模式与框架分类（如Bootstrap、Tailwind），以及JavaScript的核心语法、浏览器API和DOM编程。这篇笔记为Web开发初学者系统性地梳理了“网页三剑客”的知识体系。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="IBM" scheme="https://blog.cytrogen.icu/tags/IBM/"/>
    
    <category term="HTML" scheme="https://blog.cytrogen.icu/tags/HTML/"/>
    
    <category term="CSS" scheme="https://blog.cytrogen.icu/tags/CSS/"/>
    
  </entry>
  
  <entry>
    <title>IBM 全栈开发【1】：云计算</title>
    <link href="https://blog.cytrogen.icu/posts/2f6a.html"/>
    <id>https://blog.cytrogen.icu/posts/2f6a.html</id>
    <published>2024-01-09T21:30:20.000Z</published>
    <updated>2026-02-09T17:16:54.717Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>近期在学习 IBM 全栈应用开发微学士课程，故此记录学习笔记。</p><span id="more"></span><h1 id="1-云计算"><a class="markdownIt-Anchor" href="#1-云计算"></a> 1. 云计算</h1><p>云计算是一种能够方便地按需通过网络访问可配置计算资源的共享池的模型，这些资源可以快速地提供和释放，而且可以以服务的方式提供。</p><ol><li>按需自助服务：除了故障排除和安全漏洞修补之外，用户可以全天候自助访问计算资源。例如：24 小时 ATM 机</li><li>广泛的网络接入：云计算资源、公共云服务、多设备访问、私有云上的内联网</li><li>资源池：节约成本、计算资源服务于多个用户、云资源可动态分配给不同的用户、不受地理位置限制</li><li>快速弹性：根据需求增减计算资源</li><li>计量服务：按使用量付费、实用计量</li></ol><h2 id="11-云计算的发展"><a class="markdownIt-Anchor" href="#11-云计算的发展"></a> 1.1. 云计算的发展</h2><ol><li>虚拟机：同一物理硬件上存在多个不同的计算环境</li><li>虚拟化：通信和计算革命的巨大催化剂、共享主机环境、虚拟专用服务器</li><li>虚拟机管理程序（Hypervisor）：小型软件层，可使多个操作系统同时运行、共享相同的物理计算资源</li></ol><h2 id="12-云服务提供商"><a class="markdownIt-Anchor" href="#12-云服务提供商"></a> 1.2. 云服务提供商</h2><ol><li>阿里巴巴云：提供全面的全球云计算服务、一系列产品和服务</li><li>AWS：以按表计量、即用即付地方式向个人、公司和政府组织提供云计算平台</li><li>谷歌云计算：提供基础设施、平台和无服务器计算环境<ul><li>谷歌应用引擎是一个用于在谷歌管理的数据中心开发和托管 Web 应用程序的平台</li></ul></li><li>IBM 云：跨越公共、私有和混合环境的全栈云平台</li><li>微软 Azure：灵活的云平台，可通过微软管理的数据中心构建、测试、部署和管理应用程序</li><li>Oracle 云：主要以 SaaS 和数据库为重点的云计算服务提供商</li><li>Salesforce：专注于客户关系管理（CRM）的云计算公司</li><li>SAP：以在云中运行企业应用程序、客户关系管理和供应链管理为重点的云计算公司</li></ol><h2 id="13-云技术应用"><a class="markdownIt-Anchor" href="#13-云技术应用"></a> 1.3. 云技术应用</h2><p>利用云技术实现以下目标的案例研究：</p><ul><li>更好的客户服务</li><li>消除创新障碍</li><li>实现企业规模</li><li>加速增长</li></ul><h2 id="14-iot"><a class="markdownIt-Anchor" href="#14-iot"></a> 1.4. IoT</h2><p>物联网（IoT）是指通过互联网连接的物理设备和传感器的网络，这些设备和传感器可以收集和交换数据。</p><p>物联网改变了我们日常生活的许多方式，例如：</p><ul><li>智能家居</li><li>智能驾驶</li></ul><p>通过物联网设备收集的数据在云端存储和处理，因为物联网设备可能处于移动状态，云端可作为最接近的收集点，最大限度地减少延迟。</p><h2 id="15-ai"><a class="markdownIt-Anchor" href="#15-ai"></a> 1.5. AI</h2><ol><li>云端提供可扩展地按需资源</li><li>AI 对来自物联网设备的数据采取行动</li><li>基于 AI 响应的物联网行为</li></ol><blockquote><p>简单来说：物联网传递数据，AI 为数据提供洞察力，而这两种技术都利用了云端的可扩展性和处理能力。</p></blockquote><h2 id="16-区块链"><a class="markdownIt-Anchor" href="#16-区块链"></a> 1.6. 区块链</h2><p>区块链是一种安全的分布式开放技术，有助于加快流程、降低成本、增强安全性和可靠性，并在交易应用中建立透明度和可追溯性。</p><ol><li>区块链提供可信的、去中心化的记录</li><li>云端提供全球分布式、可扩展和具有成本效益的计算资源</li><li>AI 为从收集到的数据中进行分析和决策提供支持</li></ol><h1 id="2-云计算模型"><a class="markdownIt-Anchor" href="#2-云计算模型"></a> 2. 云计算模型</h1><h2 id="21-服务模式"><a class="markdownIt-Anchor" href="#21-服务模式"></a> 2.1. 服务模式</h2><ol><li>基础设施即服务（IaaS）：云提供商管理物理资源、数据中心、网络和虚拟化层，用户负责管理操作系统、中间件、应用程序和数据</li><li>软件即服务（SaaS）：云提供商托管并管理应用程序、数据、基础设施和平台资源</li><li>平台即服务（PaaS）：云提供商管理平台基础设施，包括操作系统、开发工具、数据库、业务分析和计算资源；PaaS 的用户通常是开发人员</li></ol><h4 id="211-iaas"><a class="markdownIt-Anchor" href="#211-iaas"></a> 2.1.1. IaaS</h4><ul><li>客户可根据自己的选择在云提供商提供的地区、可用性区域和区域中创建或配置虚拟机</li><li>云提供商通常为客户提供跟踪和监控云服务性能和使用情况以及管理灾难恢复的工具</li></ul><p>云基础设施：</p><ul><li>物理数据中心</li><li>计算</li><li>网络</li><li>存储</li><li>对象存储</li></ul><p>使用案例：</p><ul><li>使团队能够更快地建立测试和开发环境</li><li>帮助开发人员更专注于业务逻辑，而不是基础设施</li><li>业务连续性和灾难恢复需要大量的技术和人员投资，而 IaaS 可以帮助企业降低成本</li><li>更快地部署网络应用程序</li><li>随着需求的波动上下扩展基础设施</li><li>解决涉及数百万个变量和计算的复杂问题</li><li>挖掘海量数据集，找出有价值的趋势和模式</li><li>提供所需的高性能计算并使其经济实惠</li></ul><p>关注问题：</p><ul><li>在配置和管理上缺乏透明度</li><li>工作负载的可用性和性能依赖于第三方</li></ul></body></html>]]></content>
    
    
    <summary type="html">本文是 IBM 全栈开发课程系列的学习笔记第一篇，系统性地梳理了云计算的核心概念。内容从云计算的五大基本特征和发展历史讲起，介绍了各大主流云服务提供商，并探讨了云技术与物联网（IoT）、人工智能（AI）、区块链的结合。此外，文章还详细解读了 IaaS、PaaS、SaaS 三种服务模式，并重点分析了基础设施即服务（IaaS）的应用场景与挑战。这篇笔记为云计算初学者提供了一个清晰的学习框架。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="IBM" scheme="https://blog.cytrogen.icu/tags/IBM/"/>
    
    <category term="云计算" scheme="https://blog.cytrogen.icu/tags/%E4%BA%91%E8%AE%A1%E7%AE%97/"/>
    
  </entry>
  
  <entry>
    <title>JS 逆向网易云音乐</title>
    <link href="https://blog.cytrogen.icu/posts/f8ce.html"/>
    <id>https://blog.cytrogen.icu/posts/f8ce.html</id>
    <published>2023-11-27T21:00:57.000Z</published>
    <updated>2026-02-09T17:16:54.729Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>该文章记录了我如何逆向网易云 <s>并制作一个简易的播放器（鸽了）</s>。</p><span id="more"></span><h1 id="逆向网易云"><a class="markdownIt-Anchor" href="#逆向网易云"></a> 逆向网易云</h1><p>用浏览器打开网易云的网站，随意挑选一首歌曲进行播放，同时检查网络选项卡中的响应。我们能看到媒体类型中有一个 <code>.m4a</code> 文件。直接用 Python 的 requests 爬取下来进行播放，够厚道，爬下来就能听。</p><p><img src="/posts/f8ce/1.webp" alt="" loading="lazy"><br><img src="/posts/f8ce/2.webp" alt="" loading="lazy"></p><p>当然在页面源代码里找这个 <code>.m4a</code> 文件是找不到的，不然也不会说要 <strong>逆向</strong> 网易云了。我们该如何找到这个 <code>.m4a</code> 文件的 URL 呢？继续看看网络选项卡里的请求：</p><p><img src="/posts/f8ce/3.webp" alt="" loading="lazy"></p><p>赫然出现这么一个请求，返回的 JSON 数据中有 <code>.m4a</code> 的链接。嗯，就是你了！看看负载：</p><p><img src="/posts/f8ce/4.webp" alt="" loading="lazy"></p><p><code>csrf_token</code> 为空，重点是表单数据的 <code>params</code> 和 <code>encSecKey</code>。其中的内容都是一大串反正不是明文的东西，那么逆向的目标就是找到这两个参数的生成方式。</p><p>原本想要直接在源代码里一个个找过去这两个参数，后来突然想到客户端反正都会朝 <code>https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=</code> 发送请求，那么直接在 XHR / 提取断点里选择所有包含着 <code>v1?csrf_token=</code> 的 URL 不就行了。</p><p>关注 <code>arguments</code> 的构造此时成为了我们的目标。</p><p><img src="/posts/f8ce/5.webp" alt="" loading="lazy"></p><p>用调用堆栈陆续向上查看，发现 <code>params</code> 和 <code>encSecKey</code> 依旧是加密过后的。哎，加把劲吧，继续向上查看。</p><p><img src="/posts/f8ce/6.webp" alt="" loading="lazy"></p><p>一直到这一步…… 观察其前面的代码能发现一个非常有意思的事情：</p><p><img src="/posts/f8ce/7.webp" alt="" loading="lazy"></p><ol><li>变量 <code>bKC1x</code> 被赋值</li><li><code>e1x.data</code> 被赋值时，<code>bKC1x</code> 被用到了，参数中还赫然写着 <code>params</code> 和 <code>encSecKey</code></li><li>根据我们之前查看的调用堆栈，<code>chF5K(X2x, e1x)</code> 的第二个参数必定是 <code>params</code> 和 <code>encSecKey</code> 的组合</li></ol><p>这说明什么？说明 <code>bKC1x</code> 就是生成 <code>params</code> 和 <code>encSecKey</code> 的关键！我们仔细分析一下它的构造：</p><pre><code class="language-js">var bKC1x = window.asrsea(JSON.stringify(i1x), bvh3x(["流泪", "强"]), bvh3x(Rf5k.md), bvh3x(["爱心", "女孩", "惊恐", "大笑"]));</code></pre><p>其中第三个参数所使用的 <code>Rf5k.md</code> 的内容如下：</p><p><img src="/posts/f8ce/10.webp" alt="" loading="lazy"></p><blockquote><p>很想吐槽…… 这些字符串的意义是什么？？？</p></blockquote><p><code>bKC1x</code> 本身会生成一个字典，其中包含 <code>encText</code> 和 <code>encSecKey</code> 两个键。而屡次出现的 <code>bvh3x()</code> 函数的构造如下：</p><pre><code class="language-js">var bvh3x = function(chL5Q) {    var m1x = [];    j1x.bg2x(chL5Q, function(chK5P) {        m1x.push(Rf5k.emj[chK5P])    });    return m1x.join("")};</code></pre><p><img src="/posts/f8ce/8.webp" alt="" loading="lazy"></p><p>它的运作差不多是这样子的。</p><p><code>Rf5k.emj</code> 是一个字典，构造非常激寒：</p><p><img src="/posts/f8ce/9.webp" alt="" loading="lazy"></p><blockquote><p>…… 谁来告诉我这些键到底都是什么意思？？？</p></blockquote><p>也就是说 <code>bvh3x()</code> 函数接收参数，按照每个元素的字符串、对比 <code>Rf5k.emj</code> 字典中的键来返回对应的值，最后拼接成一个列表。</p><p>知道了 <code>bKC1x</code> 中后三个参数的生成方式，我们便只需要知道第一个参数 —— <code>JSON.stringify(i1x)</code> —— 是什么来头的了：</p><p><img src="/posts/f8ce/11.webp" alt="" loading="lazy"></p><p>手到擒来，这个 id 不就是歌曲 id 么？！</p><p>参数已经全部知晓，最后要看网易云如何加密它们。<code>window.asrsea()</code> 函数作为加密这些参数的老大哥，它的构造如下：</p><pre><code class="language-js">function d(d, e, f, g) {    var h = {}        , i = a(16);    return h.encText = b(d, g),    h.encText = b(h.encText, i),    h.encSecKey = c(i, e, f),    h}</code></pre><p><code>d()</code> 函数需要好好说道说道。接收的四个参数我们已述说过，这里不废话了。<code>d()</code> 先创建了一个空字典 <code>h</code>，接着创建了一个 <code>i</code>。要知道 <code>i</code> 的值，我们需要知道 <code>a()</code> 的内容：</p><pre><code class="language-js">function a(a) {    var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";    for (d = 0; a &gt; d; d += 1)        e = Math.random() * b.length,        e = Math.floor(e),        c += b.charAt(e);    return c}</code></pre><ul><li>变量 <code>d</code>、<code>e</code>、<code>b</code> 都是字符串</li><li><code>for</code> 循环中 <code>d</code> 变成整数 0，每次循环加 1，直到 <code>a</code> 的值，也就是上面 <code>d()</code> 函数中传入的整数 16</li><li><code>e</code> 在每次循环都是一个随机数，有着 <code>b</code> 的长度，并且会被 <code>Math.floor()</code> 函数取整</li><li><code>c</code> 是一个空字符串，每次循环都会被 <code>b</code> 的第 <code>e</code> 个字符所填充</li></ul><p>用人话来说便是：<code>a()</code> 函数会 <strong>生成一个长度为 16 的随机字符串</strong>。</p><p>回到 <code>d()</code> 函数，<code>h.encText</code> 的值是 <code>b(d, g)</code>，而 <code>b()</code> 函数的构造如下：</p><pre><code class="language-js">function b(a, b) {    var c = CryptoJS.enc.Utf8.parse(b)        , d = CryptoJS.enc.Utf8.parse("0102030405060708")        , e = CryptoJS.enc.Utf8.parse(a)        , f = CryptoJS.AES.encrypt(e, c, {        iv: d,        mode: CryptoJS.mode.CBC    });    return f.toString()}</code></pre><blockquote><p><code>CryptoJS</code> 是一个 JavaScript 的加密算法库，这里不做过多介绍，后面会讲到如何引用。</p></blockquote><p>该函数先是声明了变量 <code>c</code>、<code>d</code> 和 <code>e</code> 这三个由不同的值被 UTF-8 编码后的字符串。接着声明了变量 <code>f</code> —— 一个由 AES.CBC 模式加密的 <code>e</code> —— 其密钥为 <code>c</code>、偏移量为 <code>d</code>。返回的 <code>f</code> 的字符串形式最终变成了我们的 <code>encText</code>。</p><p>值得注意的是，在 <code>d()</code> 函数里，<code>h.encText</code><strong>又</strong> 被塞进 <code>b()</code> 函数里加密了一次。</p><p>而 <code>h.encSecKey</code> 由 <code>c()</code> 函数生成，它的构造如下：</p><pre><code class="language-js">function c(a, b, c) {    var d, e;    return setMaxDigits(131),    d = new RSAKeyPair(b,"",c),    e = encryptedString(d, a)}</code></pre><p>在 <code>c()</code> 函数里，先是调用了 <code>setMaxDigits()</code> 函数；这个函数接收一个需要加密的字符串 <code>a</code>，一个公钥 <code>b</code>，以及生成 RSA 密钥对所需的另一个参数 <code>c</code>。它先是使用 <code>setMaxDigits()</code> 函数设置了 <code>BigInt</code> 可操作的最大位数为 131。然后使用提供的公钥 <code>b</code> 和参数 <code>c</code> 生成 RSA 密钥对 <code>d</code>。最后，它使用生成的密钥对加密了字符串 <code>a</code>。</p><p>问题又双叒叕来了，什么是 <code>setMaxDigits()</code>？什么是 <code>BigInt</code>？莫急，再再再来看一眼网易云的源代码：</p><p><img src="/posts/f8ce/12.webp" alt="" loading="lazy"></p><p><code>setMaxDigits()</code> 和以上提到的函数们有一个天大的区别：它是全局函数，无论在哪里都能被调用。而这种全局函数的定义在网易云的源代码中只有一处：第 89 行。我们可以直接把这第 89 行的内容全部复制粘贴下来使用。</p><details><summary>展开</summary><pre><code class="language-js">function RSAKeyPair(a, b, c) {    this.e = biFromHex(a),    this.d = biFromHex(b),    this.m = biFromHex(c),    this.chunkSize = 2 * biHighIndex(this.m),    this.radix = 16,    this.barrett = new BarrettMu(this.m)}function twoDigit(a) {    return (10 &gt; a ? "0" : "") + String(a)}function encryptedString(a, b) {    for (var f, g, h, i, j, k, l, c = new Array, d = b.length, e = 0; d &gt; e; )        c[e] = b.charCodeAt(e),        e++;    for (; 0 != c.length % a.chunkSize; )        c[e++] = 0;    for (f = c.length,    g = "",    e = 0; f &gt; e; e += a.chunkSize) {        for (j = new BigInt,        h = 0,        i = e; i &lt; e + a.chunkSize; ++h)            j.digits[h] = c[i++],            j.digits[h] += c[i++] &lt;&lt; 8;        k = a.barrett.powMod(j, a.e),        l = 16 == a.radix ? biToHex(k) : biToString(k, a.radix),        g += l + " "    }    return g.substring(0, g.length - 1)}function decryptedString(a, b) {    var e, f, g, h, c = b.split(" "), d = "";    for (e = 0; e &lt; c.length; ++e)        for (h = 16 == a.radix ? biFromHex(c[e]) : biFromString(c[e], a.radix),        g = a.barrett.powMod(h, a.d),        f = 0; f &lt;= biHighIndex(g); ++f)            d += String.fromCharCode(255 &amp; g.digits[f], g.digits[f] &gt;&gt; 8);    return 0 == d.charCodeAt(d.length - 1) &amp;&amp; (d = d.substring(0, d.length - 1)),    d}function setMaxDigits(a) {    maxDigits = a,    ZERO_ARRAY = new Array(maxDigits);    for (var b = 0; b &lt; ZERO_ARRAY.length; b++)        ZERO_ARRAY[b] = 0;    bigZero = new BigInt,    bigOne = new BigInt,    bigOne.digits[0] = 1}function BigInt(a) {    this.digits = "boolean" == typeof a &amp;&amp; 1 == a ? null : ZERO_ARRAY.slice(0),    this.isNeg = !1}function biFromDecimal(a) {    for (var d, e, f, b = "-" == a.charAt(0), c = b ? 1 : 0; c &lt; a.length &amp;&amp; "0" == a.charAt(c); )        ++c;    if (c == a.length)        d = new BigInt;    else {        for (e = a.length - c,        f = e % dpl10,        0 == f &amp;&amp; (f = dpl10),        d = biFromNumber(Number(a.substr(c, f))),        c += f; c &lt; a.length; )            d = biAdd(biMultiply(d, lr10), biFromNumber(Number(a.substr(c, dpl10)))),            c += dpl10;        d.isNeg = b    }    return d}function biCopy(a) {    var b = new BigInt(!0);    return b.digits = a.digits.slice(0),    b.isNeg = a.isNeg,    b}function biFromNumber(a) {    var c, b = new BigInt;    for (b.isNeg = 0 &gt; a,    a = Math.abs(a),    c = 0; a &gt; 0; )        b.digits[c++] = a &amp; maxDigitVal,        a &gt;&gt;= biRadixBits;    return b}function reverseStr(a) {    var c, b = "";    for (c = a.length - 1; c &gt; -1; --c)        b += a.charAt(c);    return b}function biToString(a, b) {    var d, e, c = new BigInt;    for (c.digits[0] = b,    d = biDivideModulo(a, c),    e = hexatrigesimalToChar[d[1].digits[0]]; 1 == biCompare(d[0], bigZero); )        d = biDivideModulo(d[0], c),        digit = d[1].digits[0],        e += hexatrigesimalToChar[d[1].digits[0]];    return (a.isNeg ? "-" : "") + reverseStr(e)}function biToDecimal(a) {    var c, d, b = new BigInt;    for (b.digits[0] = 10,    c = biDivideModulo(a, b),    d = String(c[1].digits[0]); 1 == biCompare(c[0], bigZero); )        c = biDivideModulo(c[0], b),        d += String(c[1].digits[0]);    return (a.isNeg ? "-" : "") + reverseStr(d)}function digitToHex(a) {    var b = 15      , c = "";    for (i = 0; 4 &gt; i; ++i)        c += hexToChar[a &amp; b],        a &gt;&gt;&gt;= 4;    return reverseStr(c)}function biToHex(a) {    var d, b = "";    for (biHighIndex(a),    d = biHighIndex(a); d &gt; -1; --d)        b += digitToHex(a.digits[d]);    return b}function charToHex(a) {    var h, b = 48, c = b + 9, d = 97, e = d + 25, f = 65, g = 90;    return h = a &gt;= b &amp;&amp; c &gt;= a ? a - b : a &gt;= f &amp;&amp; g &gt;= a ? 10 + a - f : a &gt;= d &amp;&amp; e &gt;= a ? 10 + a - d : 0}function hexToDigit(a) {    var d, b = 0, c = Math.min(a.length, 4);    for (d = 0; c &gt; d; ++d)        b &lt;&lt;= 4,        b |= charToHex(a.charCodeAt(d));    return b}function biFromHex(a) {    var d, e, b = new BigInt, c = a.length;    for (d = c,    e = 0; d &gt; 0; d -= 4,    ++e)        b.digits[e] = hexToDigit(a.substr(Math.max(d - 4, 0), Math.min(d, 4)));    return b}function biFromString(a, b) {    var g, h, i, j, c = "-" == a.charAt(0), d = c ? 1 : 0, e = new BigInt, f = new BigInt;    for (f.digits[0] = 1,    g = a.length - 1; g &gt;= d; g--)        h = a.charCodeAt(g),        i = charToHex(h),        j = biMultiplyDigit(f, i),        e = biAdd(e, j),        f = biMultiplyDigit(f, b);    return e.isNeg = c,    e}function biDump(a) {    return (a.isNeg ? "-" : "") + a.digits.join(" ")}function biAdd(a, b) {    var c, d, e, f;    if (a.isNeg != b.isNeg)        b.isNeg = !b.isNeg,        c = biSubtract(a, b),        b.isNeg = !b.isNeg;    else {        for (c = new BigInt,        d = 0,        f = 0; f &lt; a.digits.length; ++f)            e = a.digits[f] + b.digits[f] + d,            c.digits[f] = 65535 &amp; e,            d = Number(e &gt;= biRadix);        c.isNeg = a.isNeg    }    return c}function biSubtract(a, b) {    var c, d, e, f;    if (a.isNeg != b.isNeg)        b.isNeg = !b.isNeg,        c = biAdd(a, b),        b.isNeg = !b.isNeg;    else {        for (c = new BigInt,        e = 0,        f = 0; f &lt; a.digits.length; ++f)            d = a.digits[f] - b.digits[f] + e,            c.digits[f] = 65535 &amp; d,            c.digits[f] &lt; 0 &amp;&amp; (c.digits[f] += biRadix),            e = 0 - Number(0 &gt; d);        if (-1 == e) {            for (e = 0,            f = 0; f &lt; a.digits.length; ++f)                d = 0 - c.digits[f] + e,                c.digits[f] = 65535 &amp; d,                c.digits[f] &lt; 0 &amp;&amp; (c.digits[f] += biRadix),                e = 0 - Number(0 &gt; d);            c.isNeg = !a.isNeg        } else            c.isNeg = a.isNeg    }    return c}function biHighIndex(a) {    for (var b = a.digits.length - 1; b &gt; 0 &amp;&amp; 0 == a.digits[b]; )        --b;    return b}function biNumBits(a) {    var e, b = biHighIndex(a), c = a.digits[b], d = (b + 1) * bitsPerDigit;    for (e = d; e &gt; d - bitsPerDigit &amp;&amp; 0 == (32768 &amp; c); --e)        c &lt;&lt;= 1;    return e}function biMultiply(a, b) {    var d, h, i, k, c = new BigInt, e = biHighIndex(a), f = biHighIndex(b);    for (k = 0; f &gt;= k; ++k) {        for (d = 0,        i = k,        j = 0; e &gt;= j; ++j,        ++i)            h = c.digits[i] + a.digits[j] * b.digits[k] + d,            c.digits[i] = h &amp; maxDigitVal,            d = h &gt;&gt;&gt; biRadixBits;        c.digits[k + e + 1] = d    }    return c.isNeg = a.isNeg != b.isNeg,    c}function biMultiplyDigit(a, b) {    var c, d, e, f;    for (result = new BigInt,    c = biHighIndex(a),    d = 0,    f = 0; c &gt;= f; ++f)        e = result.digits[f] + a.digits[f] * b + d,        result.digits[f] = e &amp; maxDigitVal,        d = e &gt;&gt;&gt; biRadixBits;    return result.digits[1 + c] = d,    result}function arrayCopy(a, b, c, d, e) {    var g, h, f = Math.min(b + e, a.length);    for (g = b,    h = d; f &gt; g; ++g,    ++h)        c[h] = a[g]}function biShiftLeft(a, b) {    var e, f, g, h, c = Math.floor(b / bitsPerDigit), d = new BigInt;    for (arrayCopy(a.digits, 0, d.digits, c, d.digits.length - c),    e = b % bitsPerDigit,    f = bitsPerDigit - e,    g = d.digits.length - 1,    h = g - 1; g &gt; 0; --g,    --h)        d.digits[g] = d.digits[g] &lt;&lt; e &amp; maxDigitVal | (d.digits[h] &amp; highBitMasks[e]) &gt;&gt;&gt; f;    return d.digits[0] = d.digits[g] &lt;&lt; e &amp; maxDigitVal,    d.isNeg = a.isNeg,    d}function biShiftRight(a, b) {    var e, f, g, h, c = Math.floor(b / bitsPerDigit), d = new BigInt;    for (arrayCopy(a.digits, c, d.digits, 0, a.digits.length - c),    e = b % bitsPerDigit,    f = bitsPerDigit - e,    g = 0,    h = g + 1; g &lt; d.digits.length - 1; ++g,    ++h)        d.digits[g] = d.digits[g] &gt;&gt;&gt; e | (d.digits[h] &amp; lowBitMasks[e]) &lt;&lt; f;    return d.digits[d.digits.length - 1] &gt;&gt;&gt;= e,    d.isNeg = a.isNeg,    d}function biMultiplyByRadixPower(a, b) {    var c = new BigInt;    return arrayCopy(a.digits, 0, c.digits, b, c.digits.length - b),    c}function biDivideByRadixPower(a, b) {    var c = new BigInt;    return arrayCopy(a.digits, b, c.digits, 0, c.digits.length - b),    c}function biModuloByRadixPower(a, b) {    var c = new BigInt;    return arrayCopy(a.digits, 0, c.digits, 0, b),    c}function biCompare(a, b) {    if (a.isNeg != b.isNeg)        return 1 - 2 * Number(a.isNeg);    for (var c = a.digits.length - 1; c &gt;= 0; --c)        if (a.digits[c] != b.digits[c])            return a.isNeg ? 1 - 2 * Number(a.digits[c] &gt; b.digits[c]) : 1 - 2 * Number(a.digits[c] &lt; b.digits[c]);    return 0}function biDivideModulo(a, b) {    var f, g, h, i, j, k, l, m, n, o, p, q, r, s, c = biNumBits(a), d = biNumBits(b), e = b.isNeg;    if (d &gt; c)        return a.isNeg ? (f = biCopy(bigOne),        f.isNeg = !b.isNeg,        a.isNeg = !1,        b.isNeg = !1,        g = biSubtract(b, a),        a.isNeg = !0,        b.isNeg = e) : (f = new BigInt,        g = biCopy(a)),        new Array(f,g);    for (f = new BigInt,    g = a,    h = Math.ceil(d / bitsPerDigit) - 1,    i = 0; b.digits[h] &lt; biHalfRadix; )        b = biShiftLeft(b, 1),        ++i,        ++d,        h = Math.ceil(d / bitsPerDigit) - 1;    for (g = biShiftLeft(g, i),    c += i,    j = Math.ceil(c / bitsPerDigit) - 1,    k = biMultiplyByRadixPower(b, j - h); -1 != biCompare(g, k); )        ++f.digits[j - h],        g = biSubtract(g, k);    for (l = j; l &gt; h; --l) {        for (m = l &gt;= g.digits.length ? 0 : g.digits[l],        n = l - 1 &gt;= g.digits.length ? 0 : g.digits[l - 1],        o = l - 2 &gt;= g.digits.length ? 0 : g.digits[l - 2],        p = h &gt;= b.digits.length ? 0 : b.digits[h],        q = h - 1 &gt;= b.digits.length ? 0 : b.digits[h - 1],        f.digits[l - h - 1] = m == p ? maxDigitVal : Math.floor((m * biRadix + n) / p),        r = f.digits[l - h - 1] * (p * biRadix + q),        s = m * biRadixSquared + (n * biRadix + o); r &gt; s; )            --f.digits[l - h - 1],            r = f.digits[l - h - 1] * (p * biRadix | q),            s = m * biRadix * biRadix + (n * biRadix + o);        k = biMultiplyByRadixPower(b, l - h - 1),        g = biSubtract(g, biMultiplyDigit(k, f.digits[l - h - 1])),        g.isNeg &amp;&amp; (g = biAdd(g, k),        --f.digits[l - h - 1])    }    return g = biShiftRight(g, i),    f.isNeg = a.isNeg != e,    a.isNeg &amp;&amp; (f = e ? biAdd(f, bigOne) : biSubtract(f, bigOne),    b = biShiftRight(b, i),    g = biSubtract(b, g)),    0 == g.digits[0] &amp;&amp; 0 == biHighIndex(g) &amp;&amp; (g.isNeg = !1),    new Array(f,g)}function biDivide(a, b) {    return biDivideModulo(a, b)[0]}function biModulo(a, b) {    return biDivideModulo(a, b)[1]}function biMultiplyMod(a, b, c) {    return biModulo(biMultiply(a, b), c)}function biPow(a, b) {    for (var c = bigOne, d = a; ; ) {        if (0 != (1 &amp; b) &amp;&amp; (c = biMultiply(c, d)),        b &gt;&gt;= 1,        0 == b)            break;        d = biMultiply(d, d)    }    return c}function biPowMod(a, b, c) {    for (var d = bigOne, e = a, f = b; ; ) {        if (0 != (1 &amp; f.digits[0]) &amp;&amp; (d = biMultiplyMod(d, e, c)),        f = biShiftRight(f, 1),        0 == f.digits[0] &amp;&amp; 0 == biHighIndex(f))            break;        e = biMultiplyMod(e, e, c)    }    return d}function BarrettMu(a) {    this.modulus = biCopy(a),    this.k = biHighIndex(this.modulus) + 1;    var b = new BigInt;    b.digits[2 * this.k] = 1,    this.mu = biDivide(b, this.modulus),    this.bkplus1 = new BigInt,    this.bkplus1.digits[this.k + 1] = 1,    this.modulo = BarrettMu_modulo,    this.multiplyMod = BarrettMu_multiplyMod,    this.powMod = BarrettMu_powMod}function BarrettMu_modulo(a) {    var i, b = biDivideByRadixPower(a, this.k - 1), c = biMultiply(b, this.mu), d = biDivideByRadixPower(c, this.k + 1), e = biModuloByRadixPower(a, this.k + 1), f = biMultiply(d, this.modulus), g = biModuloByRadixPower(f, this.k + 1), h = biSubtract(e, g);    for (h.isNeg &amp;&amp; (h = biAdd(h, this.bkplus1)),    i = biCompare(h, this.modulus) &gt;= 0; i; )        h = biSubtract(h, this.modulus),        i = biCompare(h, this.modulus) &gt;= 0;    return h}function BarrettMu_multiplyMod(a, b) {    var c = biMultiply(a, b);    return this.modulo(c)}function BarrettMu_powMod(a, b) {    var d, e, c = new BigInt;    for (c.digits[0] = 1,    d = a,    e = b; ; ) {        if (0 != (1 &amp; e.digits[0]) &amp;&amp; (c = this.multiplyMod(c, d)),        e = biShiftRight(e, 1),        0 == e.digits[0] &amp;&amp; 0 == biHighIndex(e))            break;        d = this.multiplyMod(d, d)    }    return c}var maxDigits, ZERO_ARRAY, bigZero, bigOne, dpl10, lr10, hexatrigesimalToChar, hexToChar, highBitMasks, lowBitMasks, biRadixBase = 2, biRadixBits = 16, bitsPerDigit = biRadixBits, biRadix = 65536, biHalfRadix = biRadix &gt;&gt;&gt; 1, biRadixSquared = biRadix * biRadix, maxDigitVal = biRadix - 1, maxInteger = 9999999999999998;setMaxDigits(20),dpl10 = 15,lr10 = biFromNumber(1e15),hexatrigesimalToChar = new Array("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"),hexToChar = new Array("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"),highBitMasks = new Array(0,32768,49152,57344,61440,63488,64512,65024,65280,65408,65472,65504,65520,65528,65532,65534,65535),lowBitMasks = new Array(0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535);</code></pre></details><p>至此，整个网易云逆向的思路已清晰。我们可以开始用 Python 来实现它了。</p><h1 id="用js生成数据"><a class="markdownIt-Anchor" href="#用js生成数据"></a> 用 JS 生成数据</h1><p>既然我们已经明白了网易云的加密方式，那么我们就可以先用 JS 来生成 <code>params</code> 和 <code>encSecKey</code>，然后再传到 Python 来发出请求。</p><blockquote><p>我使用的是 PyCharm；你可以新建一个 <code>.js</code> 文件并且使用 <code>node.exe</code> 来运行 JS 代码。</p></blockquote><p>首要的便是引入 <code>CryptoJS</code>，与 Python 导包一样，我们需要先下载它。在终端中输入：</p><pre><code class="language-bash">npm install crypto-js</code></pre><p>之后便是引入它：</p><pre><code class="language-js">var CryptoJS = require("crypto-js");</code></pre><p>接着复制粘贴之前说的那一大串全局函数以及 <code>a()</code>、<code>b()</code>、<code>c()</code>、<code>d()</code> 函数下去。</p><p><code>d()</code> 函数所需要的变量中有三个是固定的，我们可以先定义好：</p><pre><code class="language-js">key_2 = '010001';key_3 = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7';key_4 = '0CoJUm6Qyw8W8jud';</code></pre><p>而第一个参数中歌曲的 id 是动态的，我们可以先填写一个固定的 id 进去：</p><pre><code class="language-js">key_1 = '{"ids": "[2094817741]", "level": "standard", "encodeType": "aac", "csrf_token": ""}'</code></pre><p>最后打印一下结果：</p><pre><code class="language-js">console.log(d(key_1, key_2, key_3, key_4));</code></pre><p><code>params</code> 和 <code>encSecKey</code> 就这么简单地生成出来了。不过仅是生成出来是不够的，我们还需要把它们传到 Python 里去。</p><h1 id="用python发出请求"><a class="markdownIt-Anchor" href="#用python发出请求"></a> 用 Python 发出请求</h1><p>为了让 Python 那边取到的数据即拿即用，我悄咪咪地加了一个函数：</p><pre><code class="language-js">function main(key) {    result = d(key, key_2, key_3, key_4);    return {        'params': result['encText'],        'encSecKey': result['encSecKey']    }}</code></pre><blockquote><p>参数 <code>key</code> 的内容会在 Python 中进行修改。</p></blockquote><p>那么要如何让 Python 调用这个函数呢？我们可以使用 <code>PyExecJS</code> 这个库：</p><pre><code class="language-python">import execjsjs_code = open('文件.js', mode='r', encoding='utf-8').read()ctx = execjs.compile(js_code)</code></pre><p>这样我们便可以调用 <code>.js</code> 文件中的 <code>main()</code> 函数了：</p><pre><code class="language-python">song_id = input('输入歌曲id：')key = '{"ids": "[%s]", "level": "standard", "encodeType": "aac", "csrf_token": ""}' % song_idresult = ctx.call('main', key)</code></pre><p>给网易云发送请求：</p><pre><code class="language-python">form_data = {    'params': result['params'],    'encSecKey': result['encSecKey']}response = requests.post(    url='https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=',    headers=headers,  # 自己定义    data=form_data).json()m4a_url = response['data'][0]['url']</code></pre><p>拿到了我们的 <code>.m4a</code> 链接后，该怎么做嘛…… 我想也不用多说了吧。</p><pre><code class="language-python">m4a_response = requests.get(m4a_url, headers=headers).contentif not os.path.exists('music'):    os.mkdir('music')with open('music/%s.m4a' % song_id, mode='wb') as fp:    fp.write(m4a_response)</code></pre><p>网易云逆向大功告成！</p><h1 id="顺便逆向个歌曲id不过分吧"><a class="markdownIt-Anchor" href="#顺便逆向个歌曲id不过分吧"></a> 顺便逆向个歌曲 id 不过分吧</h1><p>在网易云中，当用户进行搜索时会出现这么一个请求：<code>https://music.163.com/weapi/search/suggest/web?csrf_token=</code>。和 <code>.m4a</code> 文件请求一样，这个请求也需要 <code>params</code> 和 <code>encSecKey</code> 两个参数。我们可以使用同样的方法来生成它们。</p><p>该请求会根据用户输入的关键词返回搜索结果：</p><pre><code class="language-python">title = input('请输入歌曲名：')search_key = '{"s": "%s", "limit": "8", "csrf_token": ""}' % titleresult = ctx.call('main', search_key)</code></pre><p>然后我们就可以拿到搜索结果了：</p><pre><code class="language-python">response = requests.post(    url='https://music.163.com/weapi/search/suggest/web?csrf_token=',    params=result,    headers=headers).json()return response['result']['songs']  # 返回歌曲列表，response['result']['songs'][数字]['id']就是我们上面自己定义的song_id，完全可以串起来用</code></pre></body></html>]]></content>
    
    
    <summary type="html">本文是一篇网易云音乐网页版 API 的逆向分析实战教程，旨在解决如何获取歌曲真实 .m4a 播放链接的问题。教程通过浏览器开发者工具，一步步追踪并剖析了其核心加密参数 params 和 encSecKey 的生成过程，深入分析了背后涉及的 AES 和 RSA 加密算法。最终，通过 Python 结合 PyExecJS 库调用复现的 JavaScript 加密逻辑，成功构造请求并获取到歌曲链接，同时还逆向了歌曲搜索接口。本文为对网页逆向、API分析和加解密技术感兴趣的开发者提供了一次完整的实战演练。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Python" scheme="https://blog.cytrogen.icu/tags/Python/"/>
    
    <category term="JavaScript" scheme="https://blog.cytrogen.icu/tags/JavaScript/"/>
    
    <category term="网页逆向" scheme="https://blog.cytrogen.icu/tags/%E7%BD%91%E9%A1%B5%E9%80%86%E5%90%91/"/>
    
  </entry>
  
  <entry>
    <title>JS 逆向有道翻译 &amp; wxPython 制作便宜翻译器</title>
    <link href="https://blog.cytrogen.icu/posts/a4b5.html"/>
    <id>https://blog.cytrogen.icu/posts/a4b5.html</id>
    <published>2023-10-30T02:28:10.792Z</published>
    <updated>2026-02-09T17:16:54.721Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>该文章讲述了如何逆向有道翻译，并且使用 wxPython 库来制作一个便宜翻译器。</p><span id="more"></span><div class="danger"><p>事先说明：</p><ul><li>本文仅供学习交流，严禁用于商业用途，否则后果自负！</li><li>本文仅供学习交流，严禁用于商业用途，否则后果自负！</li><li>本文仅供学习交流，严禁用于商业用途，否则后果自负！</li><li>你要先有 Python、requests 库和一定的 JS 基础</li><li>你要先知道如何使用网页开发者工具</li></ul></div><h1 id="逆向有道翻译"><a class="markdownIt-Anchor" href="#逆向有道翻译"></a> 逆向有道翻译</h1><p>我们首要知道的是有道翻译客户端是如何发送请求给服务器的，才能知道如何逆向它。</p><p>随便在有道翻译上输入一个单词，再在网络选项卡里翻找，你会发现有一个请求是这样的：</p><p><img src="/posts/a4b5/1.webp" alt="" loading="lazy"></p><p>该请求发送的表单数据中赫然出现了我们输入的单词，这就是我们要找的东西了。</p><p>再来看看这个请求的响应：</p><p><img src="/posts/a4b5/2.webp" alt="" loading="lazy"></p><p>嗯…… 是一大串加密过的东西，完全看不懂捏。解密的事情之后再说，我们先来想：要如何发出请求才能得到类似的响应呢？</p><p>重新来看该请求的表单数据，参数 <code>i</code> 顾名思义便是我们输入的单词的明文，而参数 <code>mysticTime</code> 一眼就能看出是一个时间戳。我们可以此时再输入一个单词，来看看表单数据的哪些参数是不变的、哪些是变化的。</p><p><img src="/posts/a4b5/3.webp" alt="" loading="lazy"></p><p>除了时间戳外，还有个参数 <code>sign</code> 也是动态的。也就是说整个请求中，仅有 <code>sign</code> 和 <code>mysticTime</code> 是动态的。又因为 <code>mysticTime</code> 是一个时间戳，所以我们只需要关注、逆向 <code>sign</code> 就行了。</p><p>既然客户端需要发送请求给服务器，那自然就需要一个加密算法来加密 <code>sign</code>、便于服务器解密。我们可以在网页开发者工具中找到这个加密算法。有道翻译还是很厚道的，一搜索「sign」这个字眼就能找到客户端封装表单数据的函数：</p><p><img src="/posts/a4b5/4.webp" alt="" loading="lazy"></p><p>是不是很熟悉？这个函数中的每个变量都能在「webtranslate」这个请求的表单数据里找到。</p><p>让我们来分析一下这个函数：</p><ul><li><code>o</code> 是一个时间戳</li><li><code>sign</code> 值由 <code>k(o, e)</code> 得到，<code>o</code> 是时间戳、<code>e</code> 我们暂且不知道</li></ul><p>再来看看 <code>k</code> 函数，还真别说，就在 <code>E</code> 函数的上面：</p><pre><code class="language-js">function k(e, t) {    return j(`client=${d}&amp;mysticTime=${e}&amp;product=${u}&amp;key=${t}`)}</code></pre><blockquote><p>需要注意一点，<code>sign: k(o, e)</code> 中 <code>o</code> 是时间戳、<code>e</code> 是不知名的变量；而到 <code>k</code> 函数中，<code>e</code> 是时间戳，<code>t</code> 才是不知名的变量。<br>切记不要搞混了！</p></blockquote><p>能看出，被传入 <code>k</code> 函数中的不知名的变量实际上是 key，并且还多了两个不知名的变量 <code>d</code> 和 <code>u</code>。我们可以直接打断点，看看这些变量的值：</p><p><img src="/posts/a4b5/5.webp" alt="" loading="lazy"></p><p>再走一步我们便能看到 <code>k</code> 函数的两个参数。<code>e</code> 属实是时间戳，千万不要混淆了！</p><p><img src="/posts/a4b5/6.webp" alt="" loading="lazy"></p><p>停在该断点，我们可以看到 <code>d</code> 和 <code>u</code> 的值：</p><p><img src="/posts/a4b5/8.webp" alt="" loading="lazy"></p><p>相当于在 <code>k</code> 函数中，会生成这么一个字符串：<code>client=fanyideskweb&amp;mysticTime=${t}&amp;product=webfanyi&amp;key=fsdsogkndfokasodnaso</code>，仅有时间戳是动态，我们无脑塞时间戳就完事了。</p><p>但是！这个字符串被生成后，还会被传入 <code>j</code> 函数进行加密，所以我们还需要看看 <code>j</code> 函数的内容：</p><pre><code class="language-js">function j(e) {    return i.a.createHash("md5").update(e.toString()).digest("hex")}</code></pre><p>嗯…… 无比熟悉有木有，这就是 MD5 加密算法；<code>j</code> 函数把 <code>k</code> 函数拼凑的字符串进行了 MD5 加密（注意是 hex 格式的），然后返回加密后的结果。</p><p>继续走两步，<code>E</code> 函数到了尾声，果断打开控制台查询一下 <code>sign</code> 的值，正是加密后的内容，而不是一串明文：</p><p><img src="/posts/a4b5/7.webp" alt="" loading="lazy"><br><img src="/posts/a4b5/9.webp" alt="" loading="lazy"></p><div class="danger"><p>继续码字的时候页面被刷新了，所以 <code>sign</code> 值和用上面的时间戳以及 key 加密出来的结果不同，懒得再截图了，大家自己试试吧。</p></div><p>至此我们已经搞清楚了有道翻译客户端是拿着什么参数去请求服务器的，接下来我们可以用 Python 来模拟这个请求。</p><h1 id="python模拟请求"><a class="markdownIt-Anchor" href="#python模拟请求"></a> Python 模拟请求</h1><p>比起直接用 <code>requests.post()</code>，我们这次要使用 <code>requests.session.post()</code>，否则不会成功；<code>headers</code> 和 <code>data</code> 之后再怼：</p><pre><code class="language-python">session = requests.session()session.get('https://fanyi.youdao.com/')res = session.post('https://dict.youdao.com/webtranslate')</code></pre><p><code>headers</code> 的内容可以直接从开发者工具那边复制，别忘了加上 <code>Referer</code>。</p><p><code>data</code> 的内容我们需要模拟一下：</p><pre><code class="language-python"># 时间戳# 因为JS的时间戳是毫秒级的，而Python的是秒级的，所以要乘以1000t = str(int(time.time() * 1000))# 加密和构建sign值s = f'client=fanyideskweb&amp;mysticTime={t}&amp;product=webfanyi&amp;key=fsdsogkndfokasodnaso'sign = hashlib.md5(s.encode()).hexdigest()data={    'i': word,  # 要翻译的单词    'from': 'auto',    'domain': 0,    'dictResult': 'true',    'keyid': 'webfanyi',    'sign': sign,    'client': 'fanyideskweb',    'product': 'webfanyi',    'appVersion': '1.0.0',    'vendor': 'web',    'pointParam': 'client,mysticTime,product',    'mysticTime': t,    'keyfrom': 'fanyi.web',    'mid': 1,    'screen': 1,    'model': 1,    'network': 'wifi',    'abtest': 0,    'yduuid': 'abcdefg'}</code></pre><p>接着来看一下响应的内容~</p><p><img src="/posts/a4b5/10.webp" alt="" loading="lazy"></p><p>居然是一大串看不懂的东西？！当然，相信大家看到这一大串中结尾的 <code>=</code> 时，应该就知道这是 base64 编码了。我们可以用 Python 来解码，不过还要插一句题外话：这个是 base64 变种，叫做 URL-safe base64，它把 <code>+</code> 和 <code>/</code> 换成了 <code>-</code> 和 <code>_</code>。这个变种的诞生是为了让 base64 编码后的内容能够安全地放在 URL 中。</p><p>简单来说就是：我们还需要把 <code>-</code> 和 <code>_</code> 换回来才能解码：</p><pre><code class="language-python">res = res.replace('-', '+').replace('_', '/')data = base64.b64decode(res)</code></pre><p>再次运行，好家伙，得到了一串更过分的字节。</p><p><img src="/posts/a4b5/11.webp" alt="" loading="lazy"></p><h1 id="解密"><a class="markdownIt-Anchor" href="#解密"></a> 解密</h1><p>既然有道翻译客户端已经准备好了表单数据，那证明这之后它就会发送请求给服务器，我们且看客户端是如何发送请求、又如何处理响应的。</p><p>继续往下走一步，我们就能看到客户端发送请求的代码了：</p><p><img src="/posts/a4b5/12.webp" alt="" loading="lazy"></p><p>中间的链接是不是很熟悉？再看看右边的 <code>E(t)</code>，这正是会返回 <code>sign</code> 值的 <code>E</code> 函数。再用控制台一一检查过去，会发现老面孔和新面孔：</p><p><img src="/posts/a4b5/13.webp" alt="" loading="lazy"></p><ul><li><code>(e,t)</code> 是 key 值</li><li><code>a["d"]</code> 返回一个 <code>Promise</code> 对象，等下细说</li><li><code>e</code> 是表单数据的一部分，里面包含了我们要翻译的单词的明文</li><li><code>n["a"]</code> 可以不深究，你只需要知道它可以把多个对象合并成一个。事实上，它的作用就是把 <code>e</code> 和 <code>E(t)</code> 返回的两个表单数据合并成一个</li></ul><p>这里说一下 <code>a["d"]</code>，它的结构是这样的：</p><pre><code class="language-js">function l(e, t, o) {    return new Promise((n,c)=&gt;{        a["a"].post(e, t, o).then(e=&gt;{            n(e.data)        }        ).catch(e=&gt;{            c(e)        }        )    }    )}</code></pre><ul><li><code>e</code> 是请求的链接</li><li><code>t</code> 是表单数据</li><li><code>o</code> 是请求头，也就是上上图中那个孤零零的 <code>"Content-Type": "application/x-www-form-urlencoded"</code></li></ul><blockquote><p>如果你不了解 <code>Promise</code>，那么你可以把它理解成一个异步函数，它的作用是等待 <code>a["a"].post(e, t, o)</code> 这个请求完成，然后返回响应的内容。<br>如果这个请求成功了，那么 <code>e</code> 就是响应的内容，给到 <code>n()</code>；如果这个请求失败了，那么 <code>e</code> 就是错误信息，给到 <code>c()</code>。</p><blockquote><p><code>n()</code> 和 <code>c()</code> 的内容都是空函数，所以我们不需要管它们。</p></blockquote></blockquote><p>那么 <code>a["d"]</code> 返回的 <code>Promise</code> 对象去了哪里咧？回到客户端发送请求的那一步（也就是上上图的 <code>I = (e,t)=&gt;略略略</code>），看开发者工具的 <strong>调用堆栈</strong>。</p><blockquote><p>调用堆栈：在开发者工具中你可以看到每个函数被调用的顺序。</p></blockquote><p><img src="/posts/a4b5/14.webp" alt="" loading="lazy"></p><p>点击 <code>Po</code> 便会自动引导到这个函数的定义处：</p><p><img src="/posts/a4b5/15.webp" alt="" loading="lazy"></p><p><code>Mo["a"].getTextTranslateResult()</code> 正是函数 <code>I</code>！</p><p><img src="/posts/a4b5/16.webp" alt="" loading="lazy"></p><p>刚才提到的 <code>a["d"]</code> 所返回的 <code>Promise</code> 对象去了此处的 <code>Mo["a"].getTextTranslateResult()</code>，服务器成功响应，走到 <code>then</code>，也就是我们解密的关键：有道翻译客户端对这个响应做了什么处理？</p><p>我们来看一下 <code>then</code> 中的代码：</p><pre><code class="language-js">.then(o=&gt;{    Mo["a"].cancelLastGpt();    const n = Mo["a"].decodeData(o, Ko["a"].state.text.decodeKey, Ko["a"].state.text.decodeIv)        , a = n ? JSON.parse(n) : {};    0 === a.code ? e.success &amp;&amp; t(e.success)(a) : e.fail &amp;&amp; t(e.fail)(a)})</code></pre><ul><li><code>Mo["a"].cancelLastGpt()</code> 不需要管，感兴趣的可以自己去看看</li><li><code>const n = Mo["a"].decodeData...略</code> 才是我们要看的，<code>decodeData</code>，是不是立即就明白这行代码的作用了？</li></ul><p>有道翻译客户端使用了 <code>Ko["a"].state.text.decodeKey</code> 和 <code>Ko["a"].state.text.decodeIv</code> 来解密响应的内容。Key 和 Iv，好好好，这不就是 AES 加密算法吗？！</p><p>打开控制台打印一下这两个变量的值：</p><p><img src="/posts/a4b5/17.webp" alt="" loading="lazy"></p><p>万事俱备，只欠东风，让我们最后看一眼 <code>Mo["a"].decodeData()</code> 函数：</p><p><img src="/posts/a4b5/18.webp" alt="" loading="lazy"></p><ul><li>接收 <code>t</code>、<code>o</code>、<code>n</code> 三个参数，分别代表了 base64 编码后的数据、用于解密的 key 和用于解密的 iv</li></ul><ol><li>分别将解密用的 key 和 iv 转化为 16 进制的字节</li><li>用 key 和 iv 创建一个 AES 解密器 <code>r</code></li><li>用解密器 <code>r</code> 解密 base64 编码后的数据 <code>t</code>，得到 JSON 数据，也就是原始的响应数据</li><li>最终返回明文</li></ol><p>搞清楚逻辑后我们便可以继续用 Python 解密：</p><pre><code class="language-python">def digest_key(value):    md5_new = hashlib.md5()    md5_new.update(val.encode())    return md5_new.digest()o = 'ydsecret://query/key/B*RGygVywfNBwpmBaZg*WT7SIOUP2T0C9WHMZN39j^DAdaZhAnxvGcCY6VYFwnHl'n = 'ydsecret://query/iv/C@lZe2YzHtZ2CYgaXKSVfsb7Y4QWHjITPPZ0nQp87fBeJ!Iv6v^6fvi2WN@bYpJ4'key = digest_key(o)iv = digest_key(n)aes = AES.new(key, AES.MODE_CBC, iv)data = aes.decrypt(data).decode()</code></pre><p>得到的结果：</p><p><img src="/posts/a4b5/19.webp" alt="" loading="lazy"></p><h1 id="制作翻译器"><a class="markdownIt-Anchor" href="#制作翻译器"></a> 制作翻译器</h1><p>经过以上逆向过程，我们还可以制作一个翻译器，让它能够翻译我们输入的单词。</p><p>首先我们需要一个 GUI 库，这里我选择了 wxPython。安装方法：</p><pre><code class="language-bash">pip install wxPython</code></pre><p>其次我们需要定义一个窗口类，该类继承自 <code>wx.Frame</code>：</p><pre><code class="language-python">class MyFrame(wx.Frame):    def __init__(self, parent, title):        # 调用父类的构造函数        super(MyFrame, self).__init__(parent, title=title, size=(400, 250))        # 创建一个面板        panel = wx.Panel(self)        # 左侧文本框        input_text = wx.TextCtrl(panel, style=wx.TE_MULTILINE, size=(150, 150))        # 右侧文本框        output_text = wx.TextCtrl(panel, style=wx.TE_MULTILINE | wx.TE_READONLY, size=(150, 150))        # 按钮        button = wx.Button(panel, label='翻译', size=(50, 25))        # 水平布局        sizer = wx.BoxSizer(wx.HORIZONTAL)        # 添加输入框和输出框        sizer.Add(input_text, 1, wx.EXPAND)        sizer.Add(output_text, 1, wx.EXPAND)        # 垂直布局        inner_sizer = wx.BoxSizer(wx.VERTICAL)        # 添加水平布局和按钮        inner_sizer.Add(sizer, 0, wx.ALL | wx.EXPAND, 10)        inner_sizer.Add(button, 0, wx.ALIGN_CENTER)        # 设置面板的布局        panel.SetSizerAndFit(inner_sizer)</code></pre><p>运行一下，布局长这样：</p><p><img src="/posts/a4b5/20.webp" alt="" loading="lazy"></p><p>用户需要在左侧输入单词、点击按钮，右侧才能够显示翻译的结果。因此我们还需要给按钮绑定一个事件：</p><pre><code class="language-python">    # ...继def __init__()的内容...    # 绑定按钮事件    self.Bind(wx.EVT_BUTTON, self.on_button_click, button)# 当按钮被点击时，执行该函数def on_button_click(self, event):    # 获取输入框和输出框    input_text = self.FindWindowById(event.GetId()-2)    output_text = self.FindWindowById(event.GetId()-1)    # 获取输入框的内容    word = input_text.GetValue()</code></pre><p>接下来的内容我相信大家都心知肚明，正是上述的所有内容的结合体。我把那些代码封装成了函数塞在按钮事件中，大家则可以自己动动手、试试看（绝对不是因为我懒）。</p><pre><code class="language-python"># 继def on_button_click()的内容# 发送请求res = request(word)# 将响应用base64解码data = decode_result(res)# 解密解码后的响应，获得JSON数据中的翻译结果word = decrypt_data(data)# 设置输出框的内容output_text.SetValue(word)</code></pre><p><img src="/posts/a4b5/21.webp" alt="" loading="lazy"></p><p>完工！</p></body></html>]]></content>
    
    
    <summary type="html">本文是一篇逆向分析有道翻译网页版API，并制作简易桌面翻译器的实战教程。文章通过浏览器开发者工具，详细追踪并破解了请求参数 sign 的MD5加密算法，以及响应内容的AES解密方法。在成功逆向API后，教程进一步展示了如何使用Python requests库模拟加密请求，并结合wxPython图形库，将成果封装成一个简单实用的桌面翻译工具。本文为对网页逆向、API抓包和加解密技术感兴趣的读者提供了一次从分析到应用的完整实践。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Python" scheme="https://blog.cytrogen.icu/tags/Python/"/>
    
    <category term="JavaScript" scheme="https://blog.cytrogen.icu/tags/JavaScript/"/>
    
    <category term="网页逆向" scheme="https://blog.cytrogen.icu/tags/%E7%BD%91%E9%A1%B5%E9%80%86%E5%90%91/"/>
    
  </entry>
  
  <entry>
    <title>STA 2000 笔记</title>
    <link href="https://blog.cytrogen.icu/posts/875a.html"/>
    <id>https://blog.cytrogen.icu/posts/875a.html</id>
    <published>2023-10-17T06:24:26.000Z</published>
    <updated>2026-02-09T17:16:55.001Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>统计学笔记，仅作为个人学习记录，不保证正确性。</p><span id="more"></span><h1 id="index"><a class="markdownIt-Anchor" href="#index"></a> Index</h1><details><ul><li><a href="#index">Index</a></li><li><a href="#chapter-1-defining-and-collecting-data">Chapter 1: Defining and Collecting Data</a><ul><li><a href="#11-variables">1.1 Variables</a><ul><li><a href="#111-measurement-scales">1.1.1 Measurement Scales</a></li></ul></li><li><a href="#12-population-and-sample">1.2 Population and Sample</a><ul><li><a href="#121-parameter-and-statistic">1.2.1 Parameter and Statistic</a></li><li><a href="#122-sources-of-data">1.2.2 Sources of Data</a></li><li><a href="#123-probability-sample">1.2.3 Probability Sample</a></li></ul></li></ul></li><li><a href="#chapter-2-organizing-and-visualizing-variables">Chapter 2: Organizing and Visualizing Variables</a><ul><li><a href="#21-organizing-categorical-data">2.1 Organizing Categorical Data</a></li><li><a href="#22-organizing-numerical-data">2.2 Organizing Numerical Data</a></li><li><a href="#23-visualizing-categorical-data">2.3 Visualizing Categorical Data</a></li><li><a href="#24-visualizing-numerical-data">2.4 Visualizing Numerical Data</a><ul><li><a href="#241-visualing-two-numerical-variables">2.4.1 Visualing Two Numerical Variables</a></li></ul></li></ul></li><li><a href="#chapter-3-numerical-descriptive-measures">Chapter 3: Numerical Descriptive Measures</a><ul><li><a href="#31-measures-of-central-tendency">3.1 Measures of Central Tendency</a><ul><li><a href="#311-mean">3.1.1 Mean</a></li><li><a href="#312-median">3.1.2 Median</a></li><li><a href="#313-mode">3.1.3 Mode</a></li></ul></li><li><a href="#32-measures-of-variation">3.2 Measures of Variation</a><ul><li><a href="#321-range">3.2.1 Range</a></li><li><a href="#322-sample-variation">3.2.2 Sample Variation</a></li><li><a href="#323-sample-standard-deviation">3.2.3 Sample Standard Deviation</a></li><li><a href="#324-coefficient-of-variation">3.2.4 Coefficient of Variation</a></li><li><a href="#325-z-score">3.2.5 Z-Score</a></li></ul></li><li><a href="#33-shape-of-a-distribution">3.3 Shape of a Distribution</a><ul><li><a href="#331-skewness">3.3.1 Skewness</a></li><li><a href="#332-kurtosis">3.3.2 Kurtosis</a></li></ul></li><li><a href="#34-quartile-measures">3.4 Quartile Measures</a><ul><li><a href="#341-locating-quartiles">3.4.1 Locating Quartiles</a></li><li><a href="#342-interquartile-range">3.4.2 Interquartile Range</a></li></ul></li><li><a href="#35-five-number-summary">3.5 Five Number Summary</a><ul><li><a href="#351-relationships-among-the-five-number-summary-and-distribution-shape">3.5.1 Relationships Among the Five Number Summary and Distribution Shape</a></li><li><a href="#352-boxplot">3.5.2 Boxplot</a></li></ul></li><li><a href="#36-numerical-descriptive-measures-for-populations">3.6 Numerical Descriptive Measures for Populations</a><ul><li><a href="#361-population-mean">3.6.1 Population Mean</a></li><li><a href="#362-population-variance">3.6.2 Population Variance</a></li><li><a href="#363-population-standard-deviation">3.6.3 Population Standard Deviation</a></li></ul></li><li><a href="#37-empirical-rule">3.7 Empirical Rule</a></li><li><a href="#38-chebyshevs-rule">3.8 Chebyshev's Rule</a></li><li><a href="#39-covariance">3.9 Covariance</a></li><li><a href="#310-correlation-coefficient">3.10 Correlation Coefficient</a><ul><li><a href="#3101-features-of-the-correlation-coefficient">3.10.1 Features of the Correlation Coefficient</a></li></ul></li><li><a href="#311-pitfalls-in-numerical-descriptive-measures">3.11 Pitfalls in Numerical Descriptive Measures</a></li></ul></li><li><a href="#chapter-4-basic-probability">Chapter 4: Basic Probability</a><ul><li><a href="#41-events">4.1 Events</a></li><li><a href="#42-probability">4.2 Probability</a></li><li><a href="#421-three-approaches-to-assigning-probability">4.2.1 Three Approaches to Assigning Probability</a><ul><li><a href="#422-simple-probability">4.2.2 Simple Probability</a></li><li><a href="#423-joint-probability">4.2.3 Joint Probability</a></li><li><a href="#424-marginal-probability">4.2.4 Marginal Probability</a></li><li><a href="#425-general-addition-rule">4.2.5 General Addition Rule</a></li><li><a href="#426-conditional-probability">4.2.6 Conditional Probability</a></li><li><a href="#427-independent-events">4.2.7 Independent Events</a></li><li><a href="#428-multiplication-rule">4.2.8 Multiplication Rule</a></li></ul></li></ul></li><li><a href="#chapter-5-discrete-probability-distributions">Chapter 5: Discrete Probability Distributions</a><ul><li><a href="#51-expected-value">5.1 Expected Value</a></li><li><a href="#52-variance-and-standard-deviation">5.2 Variance and Standard Deviation</a></li></ul></li><li><a href="#chapter-6-the-normal-distribution">Chapter 6: The Normal Distribution</a><ul><li><a href="#61-continuous-probability-distributions">6.1 Continuous Probability Distributions</a></li><li><a href="#62-normal-distribution">6.2 Normal Distribution</a><ul><li><a href="#621-density-function">6.2.1 Density Function</a></li><li><a href="#622-standardized-normal">6.2.2 Standardized Normal</a></li><li><a href="#623-normal-probabilities">6.2.3 Normal Probabilities</a></li></ul></li></ul></li><li><a href="#chapter-7-sampling-distributions">Chapter 7: Sampling Distributions</a><ul><li><a href="#71-sample-mean-sampling-distribution">7.1 Sample Mean Sampling Distribution</a><ul><li><a href="#711-standard-error-of-the-mean">7.1.1 Standard Error of the Mean</a></li><li><a href="#712-z-value-for-sampling-distribution-of-mean">7.1.2 Z-Value for Sampling Distribution of Mean</a></li><li><a href="#713-sampling-distribution-properties">7.1.3 Sampling Distribution Properties</a></li><li><a href="#714-central-limit-theorem">7.1.4 Central Limit Theorem</a></li></ul></li><li><a href="#72-population-proportions">7.2 Population Proportions</a><ul><li><a href="#721-sampling-distribution-of-the-sample-proportion">7.2.1 Sampling Distribution of the Sample Proportion</a></li><li><a href="#722-z-value-for-proportions">7.2.2 Z-Value for Proportions</a></li></ul></li></ul></li><li><a href="#chapter-8-confidence-interval-estimation">Chapter 8: Confidence Interval Estimation</a><ul><li><a href="#81-point-and-interval-estimates">8.1 Point and Interval Estimates</a></li><li><a href="#82-confidence-intervals">8.2 Confidence Intervals</a></li></ul></li><li><a href="#chapter-9-fundamentals-of-hypothesis-testing-one-sample-tests">Chapter 9: Fundamentals of Hypothesis Testing: One-Sample Tests</a><ul><li><a href="#91-the-null-hypothesis">9.1 The Null Hypothesis</a></li><li><a href="#92-the-alternative-hypothesis">9.2 The Alternative Hypothesis</a></li><li><a href="#93-the-hypothesis-testing-process">9.3 The Hypothesis Testing Process</a><ul><li><a href="#931-the-test-statistic-and-critical-values">9.3.1 The Test Statistic and Critical Values</a></li><li><a href="#932-risks-in-decision-making-using-hypothesis-testing">9.3.2 Risks in Decision Making Using Hypothesis Testing</a></li><li><a href="#933-level-of-significance-and-the-rejection-region">9.3.3 Level of Significance and the Rejection Region</a></li></ul></li><li><a href="#94-hypothesis-tests-for-the-mean">9.4 Hypothesis Tests for the Mean</a><ul><li><a href="#941-z-test-of-hypothesis-for-the-mean">9.4.1 Z Test of Hypothesis for the Mean</a></li></ul></li></ul></li><li><a href="#chapter-10-two-sample-tests-and-one-way-anova">Chapter 10: Two-Sample Tests and One-Way ANOVA</a><ul><li><a href="#101-two-sample-tests">10.1 Two-Sample Tests</a><ul><li><a href="#1011-difference-between-two-means">10.1.1 Difference Between Two Means</a></li></ul></li></ul></li></ul></details><center>-----</center><h1 id="chapter-1-defining-and-collecting-data"><a class="markdownIt-Anchor" href="#chapter-1-defining-and-collecting-data"></a> Chapter 1: Defining and Collecting Data</h1><h2 id="11-variables"><a class="markdownIt-Anchor" href="#11-variables"></a> 1.1 Variables</h2><p>Categorical (qualitative): a variable that can be placed into a specific category, according to some characteristic or attribute.</p><ul><li>Nominal: no natural ordering of the categories</li><li>Ordinal: natural ordering of the categories</li></ul><p>Numerical (quantitative): a variable that can be measured numerically.</p><ul><li>Discrete: arise from a counting process</li><li>Continuous: arise from a measuring process</li></ul><h4 id="111-measurement-scales"><a class="markdownIt-Anchor" href="#111-measurement-scales"></a> 1.1.1 Measurement Scales</h4><p>Interval scale: an ordered scale in which the difference between measurements is a meaningful quantity but the measurements do not have a true zero point.</p><p>Ratio scale: an ordered scale in which the difference between measurements is a meaningful quantity and the measurements have a true zero point.</p><p><img src="/posts/875a/Types_Of_Variables.webp" alt="" loading="lazy"></p><h2 id="12-population-and-sample"><a class="markdownIt-Anchor" href="#12-population-and-sample"></a> 1.2 Population and Sample</h2><p>Population: the set of all elements of interest in a particular study.</p><ul><li>contains all measurements of interest to the investigator</li></ul><p>Sample: a subset of the population.</p><ul><li>a part of the population selected for analysis</li></ul><h4 id="121-parameter-and-statistic"><a class="markdownIt-Anchor" href="#121-parameter-and-statistic"></a> 1.2.1 Parameter and Statistic</h4><p>Population parameter: a numerical measure that describes an aspect of a population.</p><p>Sample statistic: a numerical measure that describes an aspect of a sample.</p><h4 id="122-sources-of-data"><a class="markdownIt-Anchor" href="#122-sources-of-data"></a> 1.2.2 Sources of Data</h4><p>Primary sources: data that are generated by the investigator conducting the study.</p><ul><li>from a political survey</li><li>collected from an experiment</li><li>observed data</li></ul><p>Secondary sources: data that were produced by someone other than the investigator conducting the study.</p><ul><li>analyzing census data</li><li>examining data from print journals or data published on the Internet</li></ul><p><img src="/posts/875a/Types_Of_Samples.webp" alt="" loading="lazy"></p><h4 id="123-probability-sample"><a class="markdownIt-Anchor" href="#123-probability-sample"></a> 1.2.3 Probability Sample</h4><p>In a probability sample, items in the sample are chosen on the basis of known probabilities.</p><p><img src="/posts/875a/Types_of_Samples_1.webp" alt="" loading="lazy"></p><ul><li>Simple random sample: every individual or item from the frame has an equal chance of being selected</li><li>Systematic sample: the items are selected according to a specified time or item interval in the sampling frame<ul><li>divide frame of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>N</mi></mrow><annotation encoding="application/x-tex">N</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span></span></span></span> individuals into groups of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>k</mi></mrow><annotation encoding="application/x-tex">k</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03148em;">k</span></span></span></span> individuals: <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>k</mi><mo>=</mo><mfrac><mi>N</mi><mi>n</mi></mfrac></mrow><annotation encoding="application/x-tex">k=\frac{N}{n}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03148em;">k</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.217331em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.872331em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.10903em;">N</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></li></ul></li><li>Stratified sample: divide population into two or more subgroups (strata) according to some characteristic that is important to the study</li><li>Cluster sample: population is divided into several "clusters" or sections, then some of those clusters are randomly selected and all members of the selected clusters are used as the sample</li></ul><center>-----</center><h1 id="chapter-2-organizing-and-visualizing-variables"><a class="markdownIt-Anchor" href="#chapter-2-organizing-and-visualizing-variables"></a> Chapter 2: Organizing and Visualizing Variables</h1><h2 id="21-organizing-categorical-data"><a class="markdownIt-Anchor" href="#21-organizing-categorical-data"></a> 2.1 Organizing Categorical Data</h2><p><img src="/posts/875a/Organizing_Categorical_Data.webp" alt="" loading="lazy"></p><ul><li>Summary table: tallies the frequencies or percentages of items in a set of categories so that you can see differences between categories<ul><li><img src="/posts/875a/Organizing_Categorical_Data_1.webp" alt="" loading="lazy"></li></ul></li><li>Contingency table: a table that classifies sample observations according to two or more identifiable categories so that the relationship between the categories can be studied<ul><li><img src="/posts/875a/Organizing_Categorical_Data_2.webp" alt="" loading="lazy"></li></ul></li></ul><h2 id="22-organizing-numerical-data"><a class="markdownIt-Anchor" href="#22-organizing-numerical-data"></a> 2.2 Organizing Numerical Data</h2><p><img src="/posts/875a/Organizing_Numerical_Data.webp" alt="" loading="lazy"></p><ul><li>Ordered array: a sequence of data, in rank order, from the smallest value to the largest value.</li><li>Frequency distribution: a summary table in which the data are arranged into numerically ordered classes</li></ul><h2 id="23-visualizing-categorical-data"><a class="markdownIt-Anchor" href="#23-visualizing-categorical-data"></a> 2.3 Visualizing Categorical Data</h2><p><img src="/posts/875a/Visualizing_Categorical_Data.webp" alt="" loading="lazy"></p><ul><li>Bar chart: visualizes a categorical variable as a series of bars</li><li>Pie chart: a circle broken up into slices that represent categories</li><li>Doughnut chart: the outer part of a circle broken up into pieces that represent categories</li><li>Pareto chart: a vertical bar chart, where categories are shown in descending order of frequency</li><li>Side by side bar chart: a bar chart that compares two or more categories</li><li>Doughnut chart (contingency): a doughnut chart that compares two or more categories</li></ul><h2 id="24-visualizing-numerical-data"><a class="markdownIt-Anchor" href="#24-visualizing-numerical-data"></a> 2.4 Visualizing Numerical Data</h2><p><img src="/posts/875a/Visualizing_Numerical_Data.webp" alt="" loading="lazy"></p><ul><li>Stem-and-leaf display: a simple way to see how the data are distributed and where concentrations of data exist</li><li>Histogram: a vertical bar chart of the data in a frequency distribution</li><li>Percentage polygon: formed by having the midpoint of each class represent the data in that class and then connecting the sequence Of midpoints at their respective class percentages</li></ul><h4 id="241-visualing-two-numerical-variables"><a class="markdownIt-Anchor" href="#241-visualing-two-numerical-variables"></a> 2.4.1 Visualing Two Numerical Variables</h4><p><img src="/posts/875a/Visualing_Two_Numerical_Variables.webp" alt="" loading="lazy"></p><ul><li>Scatter plot: used for numerical data consisting of paired observations taken from two numerical variables</li><li>Time series plot: used to study patterns in the values of a numeric variable over time</li></ul><center>-----</center><h1 id="chapter-3-numerical-descriptive-measures"><a class="markdownIt-Anchor" href="#chapter-3-numerical-descriptive-measures"></a> Chapter 3: Numerical Descriptive Measures</h1><p>Central tendency: the extent or inclination to which the values of a numerical variable group or cluster around a typical or central value.</p><h2 id="31-measures-of-central-tendency"><a class="markdownIt-Anchor" href="#31-measures-of-central-tendency"></a> 3.1 Measures of Central Tendency</h2><p>Measure of central tendency: a single value that attempts to describe a set of data by identifying the central position within that set of data.</p><h4 id="311-mean"><a class="markdownIt-Anchor" href="#311-mean"></a> 3.1.1 Mean</h4><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover><mo>=</mo><mfrac><mrow><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><msub><mi>X</mi><mi>i</mi></msub></mrow><mi>n</mi></mfrac><mo>=</mo><mfrac><mrow><msub><mi>X</mi><mn>1</mn></msub><mo>+</mo><msub><mi>X</mi><mn>2</mn></msub><mo>+</mo><mo>⋯</mo><mo>+</mo><msub><mi>X</mi><mi>n</mi></msub></mrow><mi>n</mi></mfrac></mrow><annotation encoding="application/x-tex">\bar{X} = \frac{\sum_{i=1}^{n} X_i}{n} = \frac{X_1 + X_2 + \cdots + X_n}{n}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8201099999999999em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.180002em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.494002em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.6897100000000003em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:-0.0000050000000000050004em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.804292em;"><span style="top:-2.40029em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.2029em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.29971000000000003em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.07847em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.04633em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.36033em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.07847em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.07847em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="minner">⋯</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.07847em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover></mrow><annotation encoding="application/x-tex">\bar{X}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8201099999999999em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord">ˉ</span></span></span></span></span></span></span></span></span></span> -&gt; sample mean; pronounced "X-bar"</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span></span></span></span> -&gt; sample size</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>X</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">X_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.07847em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> -&gt; the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi></mrow><annotation encoding="application/x-tex">i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.65952em;vertical-align:0em;"></span><span class="mord mathnormal">i</span></span></span></span>th value in the sample</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>X</mi><mi>n</mi></msub></mrow><annotation encoding="application/x-tex">X_n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.151392em;"><span style="top:-2.5500000000000003em;margin-left:-0.07847em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> -&gt; the observed values</li></ul><h4 id="312-median"><a class="markdownIt-Anchor" href="#312-median"></a> 3.1.2 Median</h4><ol><li>Sample size is odd:</li></ol><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>Median</mtext><mo>=</mo><msup><mfrac><mrow><mi>x</mi><mo>+</mo><mn>1</mn></mrow><mn>2</mn></mfrac><mrow><mi>t</mi><mi>h</mi></mrow></msup><mtext>position</mtext></mrow><annotation encoding="application/x-tex">\text{Median} = \frac{x+1}{2}^{th} \text{position}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord text"><span class="mord">Median</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.246448em;vertical-align:-0.686em;"></span><span class="mord"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:1.560448em;"><span style="top:-3.7743400000000005em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">t</span><span class="mord mathnormal mtight">h</span></span></span></span></span></span></span></span></span><span class="mord text"><span class="mord">position</span></span></span></span></span></span></p><ol start="2"><li>Sample size is even:</li></ol><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>Median</mtext><mo>=</mo><msup><mfrac><mi>n</mi><mn>2</mn></mfrac><mrow><mi>t</mi><mi>h</mi></mrow></msup><mtext>and</mtext><mfrac><mi>n</mi><mn>2</mn></mfrac><mo>+</mo><msup><mn>1</mn><mrow><mi>t</mi><mi>h</mi></mrow></msup><mtext>positions</mtext></mrow><annotation encoding="application/x-tex">\text{Median} = \frac{n}{2}^{th} \text{and} \frac{n}{2} + 1^{th} \text{positions}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord text"><span class="mord">Median</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.032568em;vertical-align:-0.686em;"></span><span class="mord"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.10756em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:1.346568em;"><span style="top:-3.5604600000000004em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">t</span><span class="mord mathnormal mtight">h</span></span></span></span></span></span></span></span></span><span class="mord text"><span class="mord">and</span></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.10756em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">2</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.093548em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord">1</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8991079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">t</span><span class="mord mathnormal mtight">h</span></span></span></span></span></span></span></span></span><span class="mord text"><span class="mord">positions</span></span></span></span></span></span></p><h4 id="313-mode"><a class="markdownIt-Anchor" href="#313-mode"></a> 3.1.3 Mode</h4><p>Mode: the value that occurs most frequently in a data set.</p><h2 id="32-measures-of-variation"><a class="markdownIt-Anchor" href="#32-measures-of-variation"></a> 3.2 Measures of Variation</h2><p>Measure of variation: gives information on the spread or variability or dispersion of the data values.</p><h4 id="321-range"><a class="markdownIt-Anchor" href="#321-range"></a> 3.2.1 Range</h4><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>Range</mtext><mo>=</mo><mtext>Maximum</mtext><mo>−</mo><mtext>Minimum</mtext></mrow><annotation encoding="application/x-tex">\text{Range} = \text{Maximum} - \text{Minimum}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord text"><span class="mord">Range</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord">Maximum</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord">Minimum</span></span></span></span></span></span></p><h4 id="322-sample-variation"><a class="markdownIt-Anchor" href="#322-sample-variation"></a> 3.2.2 Sample Variation</h4><p>Sample variance: average of squared deviations of values from the mean.</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msup><mi>S</mi><mn>2</mn></msup><mo>=</mo><mfrac><mrow><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><mo stretchy="false">(</mo><msub><mi>X</mi><mi>i</mi></msub><mo>−</mo><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover><msup><mo stretchy="false">)</mo><mn>2</mn></msup></mrow><mrow><mi>n</mi><mo>−</mo><mn>1</mn></mrow></mfrac></mrow><annotation encoding="application/x-tex">S^2 = \frac{\sum_{i=1}^{n} (X_i - \bar{X})^2}{n-1}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8641079999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.27915em;vertical-align:-0.7693300000000001em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.50982em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord">1</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.6897100000000003em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:-0.0000050000000000050004em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.804292em;"><span style="top:-2.40029em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.2029em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.29971000000000003em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.07847em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose"><span class="mclose">)</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.7693300000000001em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><mi>x</mi><mo>ˉ</mo></mover></mrow><annotation encoding="application/x-tex">\bar{x}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.56778em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.56778em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">x</span></span></span><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.22222em;"><span class="mord">ˉ</span></span></span></span></span></span></span></span></span></span> -&gt; arithmetic mean</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span></span></span></span> -&gt; sample size</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>X</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">X_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.07847em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> -&gt; the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi></mrow><annotation encoding="application/x-tex">i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.65952em;vertical-align:0em;"></span><span class="mord mathnormal">i</span></span></span></span>th value in the sample</li></ul><h4 id="323-sample-standard-deviation"><a class="markdownIt-Anchor" href="#323-sample-standard-deviation"></a> 3.2.3 Sample Standard Deviation</h4><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>S</mi><mo>=</mo><msqrt><mfrac><mrow><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><mo stretchy="false">(</mo><msub><mi>X</mi><mi>i</mi></msub><mo>−</mo><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover><msup><mo stretchy="false">)</mo><mn>2</mn></msup></mrow><mrow><mi>n</mi><mo>−</mo><mn>1</mn></mrow></mfrac></msqrt></mrow><annotation encoding="application/x-tex">S = \sqrt{\frac{\sum_{i=1}^{n} (X_i - \bar{X})^2}{n-1}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:3.04em;vertical-align:-1.0358800000000001em;"></span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.00412em;"><span class="svg-align" style="top:-5em;"><span class="pstrut" style="height:5em;"></span><span class="mord" style="padding-left:1em;"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.50982em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord">1</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.6897100000000003em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:-0.0000050000000000050004em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.804292em;"><span style="top:-2.40029em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.2029em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.29971000000000003em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.07847em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose"><span class="mclose">)</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.740108em;"><span style="top:-2.9890000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.7693300000000001em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span><span style="top:-3.96412em;"><span class="pstrut" style="height:5em;"></span><span class="hide-tail" style="min-width:1.02em;height:3.08em;"><svg width="400em" height="3.08em" viewBox="0 0 400000 3240" preserveAspectRatio="xMinYMin slice"><path d="M473,2793c339.3,-1799.3,509.3,-2700,510,-2702 l0 -0c3.3,-7.3,9.3,-11,18,-11 H400000v40H1017.7s-90.5,478,-276.2,1466c-185.7,988,-279.5,1483,-281.5,1485c-2,6,-10,9,-24,9c-8,0,-12,-0.7,-12,-2c0,-1.3,-5.3,-32,-16,-92c-50.7,-293.3,-119.7,-693.3,-207,-1200c0,-1.3,-5.3,8.7,-16,30c-10.7,21.3,-21.3,42.7,-32,64s-16,33,-16,33s-26,-26,-26,-26s76,-153,76,-153s77,-151,77,-151c0.7,0.7,35.7,202,105,604c67.3,400.7,102,602.7,104,606zM1001 80h400000v40H1017.7z"></path></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.0358800000000001em;"><span></span></span></span></span></span></span></span></span></span></p><h4 id="324-coefficient-of-variation"><a class="markdownIt-Anchor" href="#324-coefficient-of-variation"></a> 3.2.4 Coefficient of Variation</h4><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>C</mi><mi>V</mi><mo>=</mo><mfrac><mi>S</mi><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover></mfrac><mo>×</mo><mn>100</mn><mi mathvariant="normal">%</mi></mrow><annotation encoding="application/x-tex">CV = \frac{S}{\bar{X}} \times 100\%</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal" style="margin-right:0.22222em;">V</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.07044em;vertical-align:-0.7101099999999999em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.36033em;"><span style="top:-2.28989em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord">ˉ</span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.7101099999999999em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.80556em;vertical-align:-0.05556em;"></span><span class="mord">1</span><span class="mord">0</span><span class="mord">0</span><span class="mord">%</span></span></span></span></span></p><h4 id="325-z-score"><a class="markdownIt-Anchor" href="#325-z-score"></a> 3.2.5 Z-Score</h4><p>Z-Score: the number of standard deviations that a given value <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>X</mi></mrow><annotation encoding="application/x-tex">X</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span></span> is above or below the mean.</p><ul><li>a data value is considered an extreme outlier if its Z-Score is less than -3 or greater than +3</li></ul><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>Z</mi><mo>=</mo><mfrac><mrow><mi>X</mi><mo>−</mo><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover></mrow><mi>S</mi></mfrac></mrow><annotation encoding="application/x-tex">Z = \frac{X - \bar{X}}{S}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">Z</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.18311em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.49711em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord">ˉ</span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><h2 id="33-shape-of-a-distribution"><a class="markdownIt-Anchor" href="#33-shape-of-a-distribution"></a> 3.3 Shape of a Distribution</h2><h4 id="331-skewness"><a class="markdownIt-Anchor" href="#331-skewness"></a> 3.3.1 Skewness</h4><p>Skewness: a measure of the degree of asymmetry of a distribution.</p><p><img src="/posts/875a/Skewness.webp" alt="" loading="lazy"></p><h4 id="332-kurtosis"><a class="markdownIt-Anchor" href="#332-kurtosis"></a> 3.3.2 Kurtosis</h4><p>Kurtosis: a measure of the degree of peakedness of a distribution.</p><p><img src="/posts/875a/Kurtosis.webp" alt="" loading="lazy"></p><h2 id="34-quartile-measures"><a class="markdownIt-Anchor" href="#34-quartile-measures"></a> 3.4 Quartile Measures</h2><p>Quartile: a value that divides a data set into four groups containing (as far as possible) an equal number of observations.</p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">Q_1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> -&gt; first quartile</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mn>2</mn></msub></mrow><annotation encoding="application/x-tex">Q_2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> -&gt; second quartile; the median</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mn>3</mn></msub></mrow><annotation encoding="application/x-tex">Q_3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> -&gt; third quartile</li></ul><h4 id="341-locating-quartiles"><a class="markdownIt-Anchor" href="#341-locating-quartiles"></a> 3.4.1 Locating Quartiles</h4><ol><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mn>1</mn></msub><mo>=</mo><mfrac><mrow><mi>n</mi><mo>+</mo><mn>1</mn></mrow><mn>4</mn></mfrac></mrow><annotation encoding="application/x-tex">Q_1 = \frac{n+1}{4}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">4</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span><span class="mbin mtight">+</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span> ranked value</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mn>2</mn></msub><mo>=</mo><mfrac><mrow><mi>n</mi><mo>+</mo><mn>1</mn></mrow><mn>2</mn></mfrac></mrow><annotation encoding="application/x-tex">Q_2 = \frac{n+1}{2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span><span class="mbin mtight">+</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span> ranked value</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mn>3</mn></msub><mo>=</mo><mfrac><mrow><mn>3</mn><mo stretchy="false">(</mo><mi>n</mi><mo>+</mo><mn>1</mn><mo stretchy="false">)</mo></mrow><mn>4</mn></mfrac></mrow><annotation encoding="application/x-tex">Q_3 = \frac{3(n+1)}{4}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.355em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.01em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">4</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.485em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span><span class="mopen mtight">(</span><span class="mord mathnormal mtight">n</span><span class="mbin mtight">+</span><span class="mord mtight">1</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span> ranked value</li></ol><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span></span></span></span> -&gt; the number of observed values</li></ul><h4 id="342-interquartile-range"><a class="markdownIt-Anchor" href="#342-interquartile-range"></a> 3.4.2 Interquartile Range</h4><p>Interquartile range: the difference between the third and first quartiles.</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>I</mi><mi>Q</mi><mi>R</mi><mo>=</mo><msub><mi>Q</mi><mn>3</mn></msub><mo>−</mo><msub><mi>Q</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">IQR = Q_3 - Q_1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord mathnormal" style="margin-right:0.07847em;">I</span><span class="mord mathnormal">Q</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></span></p><h2 id="35-five-number-summary"><a class="markdownIt-Anchor" href="#35-five-number-summary"></a> 3.5 Five Number Summary</h2><p>Five number summary: the five numbers that help describe the center, spread and shape of data.</p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>minimum</mtext></mrow><annotation encoding="application/x-tex">\text{minimum}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.66786em;vertical-align:0em;"></span><span class="mord text"><span class="mord">minimum</span></span></span></span></span></li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">Q_1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mn>2</mn></msub></mrow><annotation encoding="application/x-tex">Q_2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> / Median</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mn>3</mn></msub></mrow><annotation encoding="application/x-tex">Q_3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>maximum</mtext></mrow><annotation encoding="application/x-tex">\text{maximum}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.66786em;vertical-align:0em;"></span><span class="mord text"><span class="mord">maximum</span></span></span></span></span></li></ul><h4 id="351-relationships-among-the-five-number-summary-and-distribution-shape"><a class="markdownIt-Anchor" href="#351-relationships-among-the-five-number-summary-and-distribution-shape"></a> 3.5.1 Relationships Among the Five Number Summary and Distribution Shape</h4><table><thead><tr><th>Left-Skewed</th><th>Symmetric</th><th>Right-Skewed</th></tr></thead><tbody><tr><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>M</mi><mi>e</mi><mi>d</mi><mi>i</mi><mi>a</mi><mi>n</mi><mo>−</mo><mtext>minimum</mtext><mo>&gt;</mo><mtext>maximum</mtext><mo>−</mo><mi>M</mi><mi>e</mi><mi>d</mi><mi>i</mi><mi>a</mi><mi>n</mi></mrow><annotation encoding="application/x-tex">Median - \text{minimum} &gt; \text{maximum} - Median</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.77777em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal">e</span><span class="mord mathnormal">d</span><span class="mord mathnormal">i</span><span class="mord mathnormal">a</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.70696em;vertical-align:-0.0391em;"></span><span class="mord text"><span class="mord">minimum</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.75119em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord">maximum</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal">e</span><span class="mord mathnormal">d</span><span class="mord mathnormal">i</span><span class="mord mathnormal">a</span><span class="mord mathnormal">n</span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>M</mi><mi>e</mi><mi>d</mi><mi>i</mi><mi>a</mi><mi>n</mi><mo>−</mo><mtext>minimum</mtext><mo>≈</mo><mtext>maximum</mtext><mo>−</mo><mi>M</mi><mi>e</mi><mi>d</mi><mi>i</mi><mi>a</mi><mi>n</mi></mrow><annotation encoding="application/x-tex">Median - \text{minimum} \approx \text{maximum} - Median</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.77777em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal">e</span><span class="mord mathnormal">d</span><span class="mord mathnormal">i</span><span class="mord mathnormal">a</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.66786em;vertical-align:0em;"></span><span class="mord text"><span class="mord">minimum</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.75119em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord">maximum</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal">e</span><span class="mord mathnormal">d</span><span class="mord mathnormal">i</span><span class="mord mathnormal">a</span><span class="mord mathnormal">n</span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>M</mi><mi>e</mi><mi>d</mi><mi>i</mi><mi>a</mi><mi>n</mi><mo>−</mo><mtext>minimum</mtext><mo>&lt;</mo><mtext>maximum</mtext><mo>−</mo><mi>M</mi><mi>e</mi><mi>d</mi><mi>i</mi><mi>a</mi><mi>n</mi></mrow><annotation encoding="application/x-tex">Median - \text{minimum} &lt; \text{maximum} - Median</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.77777em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal">e</span><span class="mord mathnormal">d</span><span class="mord mathnormal">i</span><span class="mord mathnormal">a</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.70696em;vertical-align:-0.0391em;"></span><span class="mord text"><span class="mord">minimum</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.75119em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord">maximum</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal">e</span><span class="mord mathnormal">d</span><span class="mord mathnormal">i</span><span class="mord mathnormal">a</span><span class="mord mathnormal">n</span></span></span></span></td></tr><tr><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mn>1</mn></msub><mo>−</mo><mtext>minimum</mtext><mo>&gt;</mo><mtext>maximum</mtext><mo>−</mo><msub><mi>Q</mi><mn>3</mn></msub></mrow><annotation encoding="application/x-tex">Q_1 - \text{minimum} &gt; \text{maximum} - Q_3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.70696em;vertical-align:-0.0391em;"></span><span class="mord text"><span class="mord">minimum</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.75119em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord">maximum</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mn>1</mn></msub><mo>−</mo><mtext>minimum</mtext><mo>≈</mo><mtext>maximum</mtext><mo>−</mo><msub><mi>Q</mi><mn>3</mn></msub></mrow><annotation encoding="application/x-tex">Q_1 - \text{minimum} \approx \text{maximum} - Q_3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.66786em;vertical-align:0em;"></span><span class="mord text"><span class="mord">minimum</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.75119em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord">maximum</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mn>1</mn></msub><mo>−</mo><mtext>minimum</mtext><mo>&lt;</mo><mtext>maximum</mtext><mo>−</mo><msub><mi>Q</mi><mn>3</mn></msub></mrow><annotation encoding="application/x-tex">Q_1 - \text{minimum} &lt; \text{maximum} - Q_3</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.70696em;vertical-align:-0.0391em;"></span><span class="mord text"><span class="mord">minimum</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.75119em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord">maximum</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">3</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></td></tr><tr><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>M</mi><mi>e</mi><mi>d</mi><mi>i</mi><mi>a</mi><mi>n</mi><mo>−</mo><msub><mi>Q</mi><mn>1</mn></msub><mo>&gt;</mo><msub><mi>Q</mi><mn>2</mn></msub><mo>−</mo><mi>M</mi><mi>e</mi><mi>d</mi><mi>i</mi><mi>a</mi><mi>n</mi></mrow><annotation encoding="application/x-tex">Median - Q_1 &gt; Q_2 - Median</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.77777em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal">e</span><span class="mord mathnormal">d</span><span class="mord mathnormal">i</span><span class="mord mathnormal">a</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal">e</span><span class="mord mathnormal">d</span><span class="mord mathnormal">i</span><span class="mord mathnormal">a</span><span class="mord mathnormal">n</span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>M</mi><mi>e</mi><mi>d</mi><mi>i</mi><mi>a</mi><mi>n</mi><mo>−</mo><msub><mi>Q</mi><mn>1</mn></msub><mo>≈</mo><msub><mi>Q</mi><mn>2</mn></msub><mo>−</mo><mi>M</mi><mi>e</mi><mi>d</mi><mi>i</mi><mi>a</mi><mi>n</mi></mrow><annotation encoding="application/x-tex">Median - Q_1 \approx Q_2 - Median</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.77777em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal">e</span><span class="mord mathnormal">d</span><span class="mord mathnormal">i</span><span class="mord mathnormal">a</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal">e</span><span class="mord mathnormal">d</span><span class="mord mathnormal">i</span><span class="mord mathnormal">a</span><span class="mord mathnormal">n</span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>M</mi><mi>e</mi><mi>d</mi><mi>i</mi><mi>a</mi><mi>n</mi><mo>−</mo><msub><mi>Q</mi><mn>1</mn></msub><mo>≈</mo><msub><mi>Q</mi><mn>2</mn></msub><mo>−</mo><mi>M</mi><mi>e</mi><mi>d</mi><mi>i</mi><mi>a</mi><mi>n</mi></mrow><annotation encoding="application/x-tex">Median - Q_1 \approx Q_2 - Median</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.77777em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal">e</span><span class="mord mathnormal">d</span><span class="mord mathnormal">i</span><span class="mord mathnormal">a</span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">≈</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">M</span><span class="mord mathnormal">e</span><span class="mord mathnormal">d</span><span class="mord mathnormal">i</span><span class="mord mathnormal">a</span><span class="mord mathnormal">n</span></span></span></span></td></tr></tbody></table><h4 id="352-boxplot"><a class="markdownIt-Anchor" href="#352-boxplot"></a> 3.5.2 Boxplot</h4><p>Boxplot: a graphical display of the five number summary.</p><h2 id="36-numerical-descriptive-measures-for-populations"><a class="markdownIt-Anchor" href="#36-numerical-descriptive-measures-for-populations"></a> 3.6 Numerical Descriptive Measures for Populations</h2><h4 id="361-population-mean"><a class="markdownIt-Anchor" href="#361-population-mean"></a> 3.6.1 Population Mean</h4><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>μ</mi><mo>=</mo><mfrac><mrow><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>N</mi></munderover><msub><mi>X</mi><mi>i</mi></msub></mrow><mi>N</mi></mfrac></mrow><annotation encoding="application/x-tex">\mu = \frac{\sum_{i=1}^{N} X_i}{N}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">μ</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.356941em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.670941em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10903em;">N</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.6897100000000003em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:-0.0000050000000000050004em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.981231em;"><span style="top:-2.40029em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.2029em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.10903em;">N</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.29971000000000003em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.07847em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>μ</mi></mrow><annotation encoding="application/x-tex">\mu</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">μ</span></span></span></span> -&gt; population mean</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>N</mi></mrow><annotation encoding="application/x-tex">N</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span></span></span></span> -&gt; population size</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>X</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">X_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.07847em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> -&gt; the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi></mrow><annotation encoding="application/x-tex">i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.65952em;vertical-align:0em;"></span><span class="mord mathnormal">i</span></span></span></span>th value in the population</li></ul><h4 id="362-population-variance"><a class="markdownIt-Anchor" href="#362-population-variance"></a> 3.6.2 Population Variance</h4><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msup><mi>σ</mi><mn>2</mn></msup><mo>=</mo><mfrac><mrow><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>N</mi></munderover><mo stretchy="false">(</mo><msub><mi>X</mi><mi>i</mi></msub><mo>−</mo><mi>μ</mi><msup><mo stretchy="false">)</mo><mn>2</mn></msup></mrow><mi>N</mi></mfrac></mrow><annotation encoding="application/x-tex">\sigma^2 = \frac{\sum_{i=1}^{N} (X_i - \mu)^2}{N}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8641079999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.356941em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.670941em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10903em;">N</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.6897100000000003em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:-0.0000050000000000050004em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.981231em;"><span style="top:-2.40029em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.2029em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.10903em;">N</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.29971000000000003em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.07847em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathnormal">μ</span><span class="mclose"><span class="mclose">)</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><h4 id="363-population-standard-deviation"><a class="markdownIt-Anchor" href="#363-population-standard-deviation"></a> 3.6.3 Population Standard Deviation</h4><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>σ</mi><mo>=</mo><msqrt><mfrac><mrow><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>N</mi></munderover><mo stretchy="false">(</mo><msub><mi>X</mi><mi>i</mi></msub><mo>−</mo><mi>μ</mi><msup><mo stretchy="false">)</mo><mn>2</mn></msup></mrow><mi>N</mi></mfrac></msqrt></mrow><annotation encoding="application/x-tex">\sigma = \sqrt{\frac{\sum_{i=1}^{N} (X_i - \mu)^2}{N}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:3.04em;vertical-align:-0.9136544999999998em;"></span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:2.1263455em;"><span class="svg-align" style="top:-5em;"><span class="pstrut" style="height:5em;"></span><span class="mord" style="padding-left:1em;"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.670941em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10903em;">N</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.6897100000000003em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:-0.0000050000000000050004em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.981231em;"><span style="top:-2.40029em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.2029em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.10903em;">N</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.29971000000000003em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.07847em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathnormal">μ</span><span class="mclose"><span class="mclose">)</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.740108em;"><span style="top:-2.9890000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span><span style="top:-4.0863455em;"><span class="pstrut" style="height:5em;"></span><span class="hide-tail" style="min-width:1.02em;height:3.08em;"><svg width="400em" height="3.08em" viewBox="0 0 400000 3240" preserveAspectRatio="xMinYMin slice"><path d="M473,2793c339.3,-1799.3,509.3,-2700,510,-2702 l0 -0c3.3,-7.3,9.3,-11,18,-11 H400000v40H1017.7s-90.5,478,-276.2,1466c-185.7,988,-279.5,1483,-281.5,1485c-2,6,-10,9,-24,9c-8,0,-12,-0.7,-12,-2c0,-1.3,-5.3,-32,-16,-92c-50.7,-293.3,-119.7,-693.3,-207,-1200c0,-1.3,-5.3,8.7,-16,30c-10.7,21.3,-21.3,42.7,-32,64s-16,33,-16,33s-26,-26,-26,-26s76,-153,76,-153s77,-151,77,-151c0.7,0.7,35.7,202,105,604c67.3,400.7,102,602.7,104,606zM1001 80h400000v40H1017.7z"></path></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.9136544999999998em;"><span></span></span></span></span></span></span></span></span></span></p><h2 id="37-empirical-rule"><a class="markdownIt-Anchor" href="#37-empirical-rule"></a> 3.7 Empirical Rule</h2><p>Empirical rule: approximates the variation of data in a symmetric mound-shaped distribution.</p><ul><li>68% of the data values lie within one standard deviation of the mean</li><li>95% of the data values lie within two standard deviations of the mean</li><li>99.7% of the data values lie within three standard deviations of the mean</li></ul><h2 id="38-chebyshevs-rule"><a class="markdownIt-Anchor" href="#38-chebyshevs-rule"></a> 3.8 Chebyshev's Rule</h2><p>Chebyshev's rule: applies to any data set, regardless of the shape of the distribution.</p><ul><li>at least <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><mo>−</mo><mfrac><mn>1</mn><msup><mi>k</mi><mn>2</mn></msup></mfrac></mrow><annotation encoding="application/x-tex">1-\frac{1}{k^2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72777em;vertical-align:-0.08333em;"></span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03148em;">k</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7463142857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span> of the data values lie within <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>k</mi></mrow><annotation encoding="application/x-tex">k</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03148em;">k</span></span></span></span> standard deviations of the mean, where <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>k</mi></mrow><annotation encoding="application/x-tex">k</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03148em;">k</span></span></span></span> is any value greater than 1</li></ul><h2 id="39-covariance"><a class="markdownIt-Anchor" href="#39-covariance"></a> 3.9 Covariance</h2><p>Covariance: a measure of the linear association between two variables.</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>C</mi><mi>o</mi><mi>v</mi><mo stretchy="false">(</mo><mi>X</mi><mo separator="true">,</mo><mi>Y</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mrow><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><mo stretchy="false">(</mo><msub><mi>X</mi><mi>i</mi></msub><mo>−</mo><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><mo stretchy="false">(</mo><msub><mi>Y</mi><mi>i</mi></msub><mo>−</mo><mover accent="true"><mi>Y</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo></mrow><mrow><mi>n</mi><mo>−</mo><mn>1</mn></mrow></mfrac></mrow><annotation encoding="application/x-tex">Cov(X,Y) = \frac{\sum_{i=1}^{n} (X_i - \bar{X})(Y_i - \bar{Y})}{n-1}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal">o</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.27915em;vertical-align:-0.7693300000000001em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.50982em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord">1</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.6897100000000003em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:-0.0000050000000000050004em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.804292em;"><span style="top:-2.40029em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.2029em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.29971000000000003em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.07847em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.22222em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.25em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.7693300000000001em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi><mi>o</mi><mi>v</mi><mo stretchy="false">(</mo><mi>X</mi><mo separator="true">,</mo><mi>Y</mi><mo stretchy="false">)</mo><mo>&gt;</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">Cov(X,Y) &gt; 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal">o</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span> -&gt; positive covariance; as <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>X</mi></mrow><annotation encoding="application/x-tex">X</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span></span> increases, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>Y</mi></mrow><annotation encoding="application/x-tex">Y</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span></span></span></span> increases</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi><mi>o</mi><mi>v</mi><mo stretchy="false">(</mo><mi>X</mi><mo separator="true">,</mo><mi>Y</mi><mo stretchy="false">)</mo><mo>&lt;</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">Cov(X,Y) &lt; 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal">o</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span> -&gt; negative covariance; as <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>X</mi></mrow><annotation encoding="application/x-tex">X</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span></span> increases, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>Y</mi></mrow><annotation encoding="application/x-tex">Y</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span></span></span></span> decreases</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi><mi>o</mi><mi>v</mi><mo stretchy="false">(</mo><mi>X</mi><mo separator="true">,</mo><mi>Y</mi><mo stretchy="false">)</mo><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">Cov(X,Y) = 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal">o</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span> -&gt; no linear relationship between <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>X</mi></mrow><annotation encoding="application/x-tex">X</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span></span> and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>Y</mi></mrow><annotation encoding="application/x-tex">Y</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span></span></span></span></li></ul><h2 id="310-correlation-coefficient"><a class="markdownIt-Anchor" href="#310-correlation-coefficient"></a> 3.10 Correlation Coefficient</h2><p>Correlation coefficient: a measure of the linear association between two variables.</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>r</mi><mo>=</mo><mfrac><mrow><mi>C</mi><mi>o</mi><mi>v</mi><mo stretchy="false">(</mo><mi>X</mi><mo separator="true">,</mo><mi>Y</mi><mo stretchy="false">)</mo></mrow><mrow><msub><mi>S</mi><mi>X</mi></msub><msub><mi>S</mi><mi>Y</mi></msub></mrow></mfrac></mrow><annotation encoding="application/x-tex">r = \frac{Cov(X,Y)}{S_X S_Y}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.263em;vertical-align:-0.8360000000000001em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.3139999999999996em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.07847em;">X</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.22222em;">Y</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal">o</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.8360000000000001em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi><mi>o</mi><mi>v</mi><mo stretchy="false">(</mo><mi>X</mi><mo separator="true">,</mo><mi>Y</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mrow><msubsup><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></msubsup><mo stretchy="false">(</mo><msub><mi>X</mi><mi>i</mi></msub><mo>−</mo><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo><mo stretchy="false">(</mo><msub><mi>Y</mi><mi>i</mi></msub><mo>−</mo><mover accent="true"><mi>Y</mi><mo>ˉ</mo></mover><mo stretchy="false">)</mo></mrow><mrow><mi>n</mi><mo>−</mo><mn>1</mn></mrow></mfrac></mrow><annotation encoding="application/x-tex">Cov(X,Y) = \frac{\sum_{i=1}^{n} (X_i - \bar{X})(Y_i - \bar{Y})}{n-1}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mord mathnormal">o</span><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord mathnormal" style="margin-right:0.22222em;">Y</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.5124149999999998em;vertical-align:-0.403331em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.109084em;"><span style="top:-2.655em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span><span class="mbin mtight">−</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.5350070000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mop mtight"><span class="mop op-symbol small-op mtight" style="position:relative;top:-0.0000050000000000050004em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.7385428571428572em;"><span style="top:-2.1785614285714283em;margin-left:0em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-2.931em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.32143857142857146em;"><span></span></span></span></span></span></span><span class="mopen mtight">(</span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3280857142857143em;"><span style="top:-2.357em;margin-left:-0.07847em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.143em;"><span></span></span></span></span></span></span><span class="mbin mtight">−</span><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.07847em;">X</span></span></span><span style="top:-2.9523300000000003em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span><span class="mclose mtight">)</span><span class="mopen mtight">(</span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.22222em;">Y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3280857142857143em;"><span style="top:-2.357em;margin-left:-0.22222em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.143em;"><span></span></span></span></span></span></span><span class="mbin mtight">−</span><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.22222em;">Y</span></span></span><span style="top:-2.9523300000000003em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.25em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.403331em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>S</mi><mi>X</mi></msub><mo>=</mo><msqrt><mfrac><mrow><msubsup><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></msubsup><mo stretchy="false">(</mo><msub><mi>X</mi><mi>i</mi></msub><mo>−</mo><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover><msup><mo stretchy="false">)</mo><mn>2</mn></msup></mrow><mrow><mi>n</mi><mo>−</mo><mn>1</mn></mrow></mfrac></msqrt></mrow><annotation encoding="application/x-tex">S_X = \sqrt{\frac{\sum_{i=1}^{n} (X_i - \bar{X})^2}{n-1}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.07847em;">X</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.84em;vertical-align:-0.5021235000000002em;"></span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3378765em;"><span class="svg-align" style="top:-3.8em;"><span class="pstrut" style="height:3.8em;"></span><span class="mord" style="padding-left:1em;"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.109084em;"><span style="top:-2.655em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span><span class="mbin mtight">−</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.5350070000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mop mtight"><span class="mop op-symbol small-op mtight" style="position:relative;top:-0.0000050000000000050004em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.7046857142857144em;"><span style="top:-2.1785614285714283em;margin-left:0em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-2.8971428571428572em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.32143857142857146em;"><span></span></span></span></span></span></span><span class="mopen mtight">(</span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3280857142857143em;"><span style="top:-2.357em;margin-left:-0.07847em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.143em;"><span></span></span></span></span></span></span><span class="mbin mtight">−</span><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.07847em;">X</span></span></span><span style="top:-2.9523300000000003em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span><span class="mclose mtight"><span class="mclose mtight">)</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7463142857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.403331em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span><span style="top:-3.2978764999999997em;"><span class="pstrut" style="height:3.8em;"></span><span class="hide-tail" style="min-width:1.02em;height:1.8800000000000001em;"><svg width="400em" height="1.8800000000000001em" viewBox="0 0 400000 1944" preserveAspectRatio="xMinYMin slice"><path d="M983 90l0 -0c4,-6.7,10,-10,18,-10 H400000v40H1013.1s-83.4,268,-264.1,840c-180.7,572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7s-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744c-10,12,-21,25,-33,39s-32,39,-32,39c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30c26.7,-32.7,52,-63,76,-91s52,-60,52,-60s208,722,208,722c56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,-658.5c53.7,-170.3,84.5,-266.8,92.5,-289.5zM1001 80h400000v40h-400000z"></path></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.5021235000000002em;"><span></span></span></span></span></span></span></span></span></li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>S</mi><mi>Y</mi></msub><mo>=</mo><msqrt><mfrac><mrow><msubsup><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></msubsup><mo stretchy="false">(</mo><msub><mi>Y</mi><mi>i</mi></msub><mo>−</mo><mover accent="true"><mi>Y</mi><mo>ˉ</mo></mover><msup><mo stretchy="false">)</mo><mn>2</mn></msup></mrow><mrow><mi>n</mi><mo>−</mo><mn>1</mn></mrow></mfrac></msqrt></mrow><annotation encoding="application/x-tex">S_Y = \sqrt{\frac{\sum_{i=1}^{n} (Y_i - \bar{Y})^2}{n-1}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.22222em;">Y</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.84em;vertical-align:-0.5021235000000002em;"></span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3378765em;"><span class="svg-align" style="top:-3.8em;"><span class="pstrut" style="height:3.8em;"></span><span class="mord" style="padding-left:1em;"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.109084em;"><span style="top:-2.655em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span><span class="mbin mtight">−</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.5350070000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mop mtight"><span class="mop op-symbol small-op mtight" style="position:relative;top:-0.0000050000000000050004em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.7046857142857144em;"><span style="top:-2.1785614285714283em;margin-left:0em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-2.8971428571428572em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.32143857142857146em;"><span></span></span></span></span></span></span><span class="mopen mtight">(</span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.22222em;">Y</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3280857142857143em;"><span style="top:-2.357em;margin-left:-0.22222em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.143em;"><span></span></span></span></span></span></span><span class="mbin mtight">−</span><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.22222em;">Y</span></span></span><span style="top:-2.9523300000000003em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.25em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span><span class="mclose mtight"><span class="mclose mtight">)</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7463142857142857em;"><span style="top:-2.786em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.403331em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span><span style="top:-3.2978764999999997em;"><span class="pstrut" style="height:3.8em;"></span><span class="hide-tail" style="min-width:1.02em;height:1.8800000000000001em;"><svg width="400em" height="1.8800000000000001em" viewBox="0 0 400000 1944" preserveAspectRatio="xMinYMin slice"><path d="M983 90l0 -0c4,-6.7,10,-10,18,-10 H400000v40H1013.1s-83.4,268,-264.1,840c-180.7,572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7s-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744c-10,12,-21,25,-33,39s-32,39,-32,39c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30c26.7,-32.7,52,-63,76,-91s52,-60,52,-60s208,722,208,722c56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,-658.5c53.7,-170.3,84.5,-266.8,92.5,-289.5zM1001 80h400000v40h-400000z"></path></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.5021235000000002em;"><span></span></span></span></span></span></span></span></span></li></ul><h4 id="3101-features-of-the-correlation-coefficient"><a class="markdownIt-Anchor" href="#3101-features-of-the-correlation-coefficient"></a> 3.10.1 Features of the Correlation Coefficient</h4><p>The population coefficient of correlation, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>ρ</mi></mrow><annotation encoding="application/x-tex">\rho</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">ρ</span></span></span></span>, is a measure of the linear association between two variables.</p><p>The sample coefficient of correlation, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>r</mi></mrow><annotation encoding="application/x-tex">r</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span></span></span></span>, is a measure of the linear association between two variables.</p><h2 id="311-pitfalls-in-numerical-descriptive-measures"><a class="markdownIt-Anchor" href="#311-pitfalls-in-numerical-descriptive-measures"></a> 3.11 Pitfalls in Numerical Descriptive Measures</h2><ul><li>Data analysis is objective</li><li>Data interpretation is subjective</li></ul><center>-----</center><h1 id="chapter-4-basic-probability"><a class="markdownIt-Anchor" href="#chapter-4-basic-probability"></a> Chapter 4: Basic Probability</h1><p>Sample space: the set of all possible outcomes of an experiment.</p><h2 id="41-events"><a class="markdownIt-Anchor" href="#41-events"></a> 4.1 Events</h2><p>Simple event: an event described by a single characteristic or an event that is a set of outcomes of an experiment.</p><p>Joint event: an event described by two or more characteristics.</p><blockquote><p>Complement of an event A:</p><ul><li>all events that are not part of event A</li></ul></blockquote><h2 id="42-probability"><a class="markdownIt-Anchor" href="#42-probability"></a> 4.2 Probability</h2><p>Probability: the numerical value representing the chance, likelihood, or possibility that a certain event will occur.</p><ul><li>always between 0 and 1</li></ul><p>Impossible event: an event that has no chance of occurring.</p><p>Certain event: an event that is sure to occur.</p><p>Mutually exclusive events: events that cannot occur at the same time.</p><p>Collectively exhaustive events: the set of events that covers the entire sample space.</p><ul><li>one of the events must occur</li></ul><h2 id="421-three-approaches-to-assigning-probability"><a class="markdownIt-Anchor" href="#421-three-approaches-to-assigning-probability"></a> 4.2.1 Three Approaches to Assigning Probability</h2><p>A priori probability: a probability assignment based upon prior knowledge of the process involved.</p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mtext>number&nbsp;of&nbsp;outcomes&nbsp;in&nbsp;A</mtext><mtext>total&nbsp;number&nbsp;of&nbsp;outcomes</mtext></mfrac></mrow><annotation encoding="application/x-tex">P(A) = \frac{\text{number of outcomes in A}}{\text{total number of outcomes}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.2251079999999999em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">total&nbsp;number&nbsp;of&nbsp;outcomes</span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">number&nbsp;of&nbsp;outcomes&nbsp;in&nbsp;A</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></li><li>Example: randomly selecting a day from the year 2019. What is the probability that the day is in January?<ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mtext>January</mtext><mo stretchy="false">)</mo><mo>=</mo><mfrac><mn>31</mn><mn>365</mn></mfrac></mrow><annotation encoding="application/x-tex">P(\text{January}) = \frac{31}{365}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord text"><span class="mord">January</span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.190108em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.845108em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span><span class="mord mtight">6</span><span class="mord mtight">5</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></li></ul></li></ul><p>Empirical probability: a probability assignment based upon observations obtained from probability experiments.</p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mtext>number&nbsp;of&nbsp;times&nbsp;A&nbsp;occurs</mtext><mtext>number&nbsp;of&nbsp;times&nbsp;the&nbsp;experiment&nbsp;is&nbsp;repeated</mtext></mfrac></mrow><annotation encoding="application/x-tex">P(A) = \frac{\text{number of times A occurs}}{\text{number of times the experiment is repeated}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.3612159999999998em;vertical-align:-0.481108em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8801079999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">number&nbsp;of&nbsp;times&nbsp;the&nbsp;experiment&nbsp;is&nbsp;repeated</span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">number&nbsp;of&nbsp;times&nbsp;A&nbsp;occurs</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.481108em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></li><li>Example: <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mtext>male&nbsp;taking&nbsp;stats</mtext><mo stretchy="false">)</mo><mo>=</mo><mfrac><mtext>number&nbsp;of&nbsp;males&nbsp;taking&nbsp;stats</mtext><mtext>total&nbsp;number&nbsp;of&nbsp;people</mtext></mfrac></mrow><annotation encoding="application/x-tex">P(\text{male taking stats}) = \frac{\text{number of males taking stats}}{\text{total number of people}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord text"><span class="mord">male&nbsp;taking&nbsp;stats</span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.4133239999999998em;vertical-align:-0.481108em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.9322159999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">total&nbsp;number&nbsp;of&nbsp;people</span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.446108em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">number&nbsp;of&nbsp;males&nbsp;taking&nbsp;stats</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.481108em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></li></ul><p>Subjective probability: a probability assignment based upon judgment.</p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mtext>degree&nbsp;of&nbsp;belief&nbsp;that&nbsp;A&nbsp;will&nbsp;occur</mtext><mrow><mtext>degree&nbsp;of&nbsp;belief&nbsp;that&nbsp;A&nbsp;will&nbsp;occur</mtext><mo>+</mo><mtext>degree&nbsp;of&nbsp;belief&nbsp;that&nbsp;A&nbsp;will&nbsp;not&nbsp;occur</mtext></mrow></mfrac></mrow><annotation encoding="application/x-tex">P(A) = \frac{\text{degree of belief that A will occur}}{\text{degree of belief that A will occur} + \text{degree of belief that A will not occur}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.4133239999999998em;vertical-align:-0.481108em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.9322159999999999em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">degree&nbsp;of&nbsp;belief&nbsp;that&nbsp;A&nbsp;will&nbsp;occur</span></span><span class="mbin mtight">+</span><span class="mord text mtight"><span class="mord mtight">degree&nbsp;of&nbsp;belief&nbsp;that&nbsp;A&nbsp;will&nbsp;not&nbsp;occur</span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.446108em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">degree&nbsp;of&nbsp;belief&nbsp;that&nbsp;A&nbsp;will&nbsp;occur</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.481108em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></li><li>differs from person to person</li></ul><h4 id="422-simple-probability"><a class="markdownIt-Anchor" href="#422-simple-probability"></a> 4.2.2 Simple Probability</h4><p>Simple probability: the probability of a single event occurring.</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mtext>number&nbsp;of&nbsp;outcomes&nbsp;satisfying&nbsp;A</mtext><mtext>total&nbsp;number&nbsp;of&nbsp;outcomes</mtext></mfrac></mrow><annotation encoding="application/x-tex">P(A) = \frac{\text{number of outcomes satisfying A}}{\text{total number of outcomes}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.0574399999999997em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3714399999999998em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord">total&nbsp;number&nbsp;of&nbsp;outcomes</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord">number&nbsp;of&nbsp;outcomes&nbsp;satisfying&nbsp;A</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><h4 id="423-joint-probability"><a class="markdownIt-Anchor" href="#423-joint-probability"></a> 4.2.3 Joint Probability</h4><p>Joint probability: the probability of two or more events occurring simultaneously.</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∩</mo><mi>B</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mtext>number&nbsp;of&nbsp;outcomes&nbsp;satisfying&nbsp;A&nbsp;and&nbsp;B</mtext><mtext>total&nbsp;number&nbsp;of&nbsp;outcomes</mtext></mfrac></mrow><annotation encoding="application/x-tex">P(A \cap B) = \frac{\text{number of outcomes satisfying A and B}}{\text{total number of outcomes}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.0574399999999997em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3714399999999998em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord">total&nbsp;number&nbsp;of&nbsp;outcomes</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord">number&nbsp;of&nbsp;outcomes&nbsp;satisfying&nbsp;A&nbsp;and&nbsp;B</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><h4 id="424-marginal-probability"><a class="markdownIt-Anchor" href="#424-marginal-probability"></a> 4.2.4 Marginal Probability</h4><p>Marginal probability: the probability of a single event occurring without regard to any other event.</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mtext>number&nbsp;of&nbsp;outcomes&nbsp;satisfying&nbsp;A</mtext><mtext>total&nbsp;number&nbsp;of&nbsp;outcomes</mtext></mfrac><mo>=</mo><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∩</mo><mi>B</mi><mo stretchy="false">)</mo><mo>+</mo><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∩</mo><msup><mi>B</mi><mi>c</mi></msup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A) = \frac{\text{number of outcomes satisfying A}}{\text{total number of outcomes}} = P(A \cap B) + P(A \cap B^c)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.0574399999999997em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3714399999999998em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord">total&nbsp;number&nbsp;of&nbsp;outcomes</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord">number&nbsp;of&nbsp;outcomes&nbsp;satisfying&nbsp;A</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.7143919999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span></p><table><thead><tr><th></th><th><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span></span></span></span></th><th><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>B</mi><mi>c</mi></msup></mrow><annotation encoding="application/x-tex">B^c</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span></span></span></span></span></span></span></span></th><th>Total</th></tr></thead><tbody><tr><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∩</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A \cap B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∩</mo><msup><mi>B</mi><mi>c</mi></msup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A \cap B^c)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mclose">)</span></span></span></span></td></tr><tr><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mi>A</mi><mi>c</mi></msup></mrow><annotation encoding="application/x-tex">A^c</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord"><span class="mord mathnormal">A</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span></span></span></span></span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><msup><mi>A</mi><mi>c</mi></msup><mo>∩</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A^c \cap B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">A</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><msup><mi>A</mi><mi>c</mi></msup><mo>∩</mo><msup><mi>B</mi><mi>c</mi></msup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A^c \cap B^c)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">A</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><msup><mi>A</mi><mi>c</mi></msup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A^c)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">A</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></td></tr><tr><td>Total</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><msup><mi>B</mi><mi>c</mi></msup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(B^c)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></td><td>1</td></tr></tbody></table><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∩</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A \cap B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span> and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∩</mo><msup><mi>B</mi><mi>c</mi></msup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A \cap B^c)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span> are joint probabilities</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><msup><mi>A</mi><mi>c</mi></msup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A^c)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">A</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span> and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><msup><mi>B</mi><mi>c</mi></msup><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(B^c)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.664392em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">c</span></span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span> are marginal probabilities</li></ul><h4 id="425-general-addition-rule"><a class="markdownIt-Anchor" href="#425-general-addition-rule"></a> 4.2.5 General Addition Rule</h4><p>General addition rule: the probability of the union of two events is the sum of the probabilities of the two events minus the probability of their intersection.</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∪</mo><mi>B</mi><mo stretchy="false">)</mo><mo>=</mo><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo><mo>+</mo><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo><mo>−</mo><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∩</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A \cup B) = P(A) + P(B) - P(A \cap B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∪</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span></span></p><p>If <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span> and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span></span></span></span> are mutually exclusive, then <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∩</mo><mi>B</mi><mo stretchy="false">)</mo><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">P(A \cap B) = 0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">0</span></span></span></span>. Therefore, the general addition rule becomes:</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∪</mo><mi>B</mi><mo stretchy="false">)</mo><mo>=</mo><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo><mo>+</mo><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A \cup B) = P(A) + P(B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∪</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span></span></p><h4 id="426-conditional-probability"><a class="markdownIt-Anchor" href="#426-conditional-probability"></a> 4.2.6 Conditional Probability</h4><p>Conditional probability: the probability of an event occurring given that another event has already occurred.</p><ol><li>The condition probability of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span> given that <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span></span></span></span> has occured:</li></ol><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∩</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo></mrow></mfrac></mrow><annotation encoding="application/x-tex">P(A|B) = \frac{P(A \cap B)}{P(B)}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mord">∣</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.363em;vertical-align:-0.936em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.936em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><ol start="2"><li>The condition probability of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span></span></span></span> given that <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span> has occured:</li></ol><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>A</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∩</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo></mrow></mfrac></mrow><annotation encoding="application/x-tex">P(B|A) = \frac{P(A \cap B)}{P(A)}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathnormal">A</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.363em;vertical-align:-0.936em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mclose">)</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.936em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><ul><li>where <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∩</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A \cap B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span> is the joint probability of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span> and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span></span></span></span><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mclose">)</span></span></span></span> -&gt; marginal probability of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span></li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span> -&gt; marginal probability of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span></span></span></span></li></ul></li></ul><h4 id="427-independent-events"><a class="markdownIt-Anchor" href="#427-independent-events"></a> 4.2.7 Independent Events</h4><p>Independent events: two events are independent if the occurrence of one event does not affect the probability of the occurrence of the other event.</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo><mo>=</mo><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo><mtext>&nbsp;;&nbsp;</mtext><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>A</mi><mo stretchy="false">)</mo><mo>=</mo><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A|B) = P(A) \space \text{;} \space P(B|A) = P(B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mord">∣</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mclose">)</span><span class="mspace">&nbsp;</span><span class="mord text"><span class="mord">;</span></span><span class="mspace">&nbsp;</span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathnormal">A</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span></span></p><ul><li>events <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span> and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span></span></span></span> are independent when the probability of one event is not affects by the fact that the other event has occurred</li></ul><h4 id="428-multiplication-rule"><a class="markdownIt-Anchor" href="#428-multiplication-rule"></a> 4.2.8 Multiplication Rule</h4><p>Multiplication rule: the probability of the intersection of two events is the product of the probability of the first event and the conditional probability of the second event given that the first event has occurred.</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∩</mo><mi>B</mi><mo stretchy="false">)</mo><mo>=</mo><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo><mo>×</mo><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>A</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A \cap B) = P(A) \times P(B|A)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathnormal">A</span><span class="mclose">)</span></span></span></span></span></p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mi mathvariant="normal">∣</mi><mi>B</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∩</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo></mrow></mfrac><mo>=</mo><mfrac><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo><mo>×</mo><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>A</mi><mo stretchy="false">)</mo></mrow><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo></mrow></mfrac></mrow><annotation encoding="application/x-tex">P(A|B) = \frac{P(A \cap B)}{P(B)} = \frac{P(A) \times P(B|A)}{P(B)}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mord">∣</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.363em;vertical-align:-0.936em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.936em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.363em;vertical-align:-0.936em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathnormal">A</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.936em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p>If <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi></mrow><annotation encoding="application/x-tex">A</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">A</span></span></span></span> and <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>B</mi></mrow><annotation encoding="application/x-tex">B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span></span></span></span> are independent, then <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mi mathvariant="normal">∣</mi><mi>A</mi><mo stretchy="false">)</mo><mo>=</mo><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(B|A) = P(B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mord">∣</span><span class="mord mathnormal">A</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span>, and the multiplication rule becomes:</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo>∩</mo><mi>B</mi><mo stretchy="false">)</mo><mo>=</mo><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">)</mo><mo>×</mo><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(A \cap B) = P(A) \times P(B)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∩</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal">A</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mclose">)</span></span></span></span></span></p><center>-----</center><h1 id="chapter-5-discrete-probability-distributions"><a class="markdownIt-Anchor" href="#chapter-5-discrete-probability-distributions"></a> Chapter 5: Discrete Probability Distributions</h1><p>Probability distribution: a listing of all the outcomes of an experiment and the probability associated with each outcome.</p><h2 id="51-expected-value"><a class="markdownIt-Anchor" href="#51-expected-value"></a> 5.1 Expected Value</h2><p>Expected value: the mean of a probability distribution -&gt; <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>μ</mi></mrow><annotation encoding="application/x-tex">\mu</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">μ</span></span></span></span>.</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>μ</mi><mo>=</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><msub><mi>x</mi><mi>i</mi></msub><mi>P</mi><mo stretchy="false">(</mo><msub><mi>x</mi><mi>i</mi></msub><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\mu = \sum_{i=1}^{n} x_i P(x_i)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">μ</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.929066em;vertical-align:-1.277669em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6513970000000002em;"><span style="top:-1.872331em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.050005em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span><span style="top:-4.3000050000000005em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.277669em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>x</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">x_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> -&gt; the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi></mrow><annotation encoding="application/x-tex">i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.65952em;vertical-align:0em;"></span><span class="mord mathnormal">i</span></span></span></span>th value in the probability distribution</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><msub><mi>x</mi><mi>i</mi></msub><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(x_i)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span> -&gt; the probability associated with the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi></mrow><annotation encoding="application/x-tex">i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.65952em;vertical-align:0em;"></span><span class="mord mathnormal">i</span></span></span></span>th value in the probability distribution</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span></span></span></span> -&gt; the number of values in the probability distribution</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>μ</mi></mrow><annotation encoding="application/x-tex">\mu</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">μ</span></span></span></span> -&gt; the expected value</li></ul><h2 id="52-variance-and-standard-deviation"><a class="markdownIt-Anchor" href="#52-variance-and-standard-deviation"></a> 5.2 Variance and Standard Deviation</h2><p>Variance: the average of the squared deviations of the possible values from the expected value.</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msup><mi>σ</mi><mn>2</mn></msup><mo>=</mo><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><mo stretchy="false">(</mo><msub><mi>x</mi><mi>i</mi></msub><mo>−</mo><mi>μ</mi><msup><mo stretchy="false">)</mo><mn>2</mn></msup><mi>P</mi><mo stretchy="false">(</mo><msub><mi>x</mi><mi>i</mi></msub><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">\sigma^2 = \sum_{i=1}^{n} (x_i - \mu)^2 P(x_i)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8641079999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.929066em;vertical-align:-1.277669em;"></span><span class="mop op-limits"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.6513970000000002em;"><span style="top:-1.872331em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.050005em;"><span class="pstrut" style="height:3.05em;"></span><span><span class="mop op-symbol large-op">∑</span></span></span><span style="top:-4.3000050000000005em;margin-left:0em;"><span class="pstrut" style="height:3.05em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.277669em;"><span></span></span></span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1.1141079999999999em;vertical-align:-0.25em;"></span><span class="mord mathnormal">μ</span><span class="mclose"><span class="mclose">)</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8641079999999999em;"><span style="top:-3.113em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>x</mi><mi>i</mi></msub></mrow><annotation encoding="application/x-tex">x_i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> -&gt; the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi></mrow><annotation encoding="application/x-tex">i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.65952em;vertical-align:0em;"></span><span class="mord mathnormal">i</span></span></span></span>th value in the probability distribution</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>P</mi><mo stretchy="false">(</mo><msub><mi>x</mi><mi>i</mi></msub><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">P(x_i)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">x</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span></span></span></span> -&gt; the probability associated with the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>i</mi></mrow><annotation encoding="application/x-tex">i</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.65952em;vertical-align:0em;"></span><span class="mord mathnormal">i</span></span></span></span>th value in the probability distribution</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span></span></span></span> -&gt; the number of values in the probability distribution</li></ul><p>Standard deviation: the square root of the variance.</p><center>-----</center><h1 id="chapter-6-the-normal-distribution"><a class="markdownIt-Anchor" href="#chapter-6-the-normal-distribution"></a> Chapter 6: The Normal Distribution</h1><h2 id="61-continuous-probability-distributions"><a class="markdownIt-Anchor" href="#61-continuous-probability-distributions"></a> 6.1 Continuous Probability Distributions</h2><p>Continuous variable: a variable that can assume any value on a continuum (can assume an uncountable number of values)</p><p>For example, the thickness of an item, the time required to complete a task.</p><h2 id="62-normal-distribution"><a class="markdownIt-Anchor" href="#62-normal-distribution"></a> 6.2 Normal Distribution</h2><p>Normal Distribution:</p><ul><li>bell shaped</li><li>symmetrical</li><li>mean, median and mode are equal</li></ul><p>The location is determined by the mean, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>μ</mi></mrow><annotation encoding="application/x-tex">\mu</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">μ</span></span></span></span>, and the spread is determined by the standard deviation, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>σ</mi></mrow><annotation encoding="application/x-tex">\sigma</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span></span></span></span>.</p><p>The random variable has an infinite theoretical range: <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mo>−</mo><mi mathvariant="normal">∞</mi><mo separator="true">,</mo><mi mathvariant="normal">∞</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(-\infty, \infty)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">−</span><span class="mord">∞</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord">∞</span><span class="mclose">)</span></span></span></span>.</p><h4 id="621-density-function"><a class="markdownIt-Anchor" href="#621-density-function"></a> 6.2.1 Density Function</h4><p>Probability density function: a function whose integral is calculated to find probabilities associated with a continuous random variable.</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>x</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mn>1</mn><mrow><mi>σ</mi><msqrt><mrow><mn>2</mn><mi>π</mi></mrow></msqrt></mrow></mfrac><msup><mi>e</mi><mrow><mo>−</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><mo stretchy="false">(</mo><mfrac><mrow><mi>x</mi><mo>−</mo><mi>μ</mi></mrow><mi>σ</mi></mfrac><msup><mo stretchy="false">)</mo><mn>2</mn></msup></mrow></msup></mrow><annotation encoding="application/x-tex">f(x) = \frac{1}{\sigma \sqrt{2\pi}} e^{-\frac{1}{2}(\frac{x-\mu}{\sigma})^2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal">x</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.25144em;vertical-align:-0.93em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.2027799999999997em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.90722em;"><span class="svg-align" style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord" style="padding-left:0.833em;"><span class="mord">2</span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span></span></span><span style="top:-2.86722em;"><span class="pstrut" style="height:3em;"></span><span class="hide-tail" style="min-width:0.853em;height:1.08em;"><svg width="400em" height="1.08em" viewBox="0 0 400000 1080" preserveAspectRatio="xMinYMin slice"><path d="M95,702c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429c69,-144,104.5,-217.7,106.5,-221l0 -0c5.3,-9.3,12,-14,20,-14H400000v40H845.2724s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47zM834 80h400000v40h-400000z"></path></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.13278em;"><span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.93em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:1.0369199999999998em;"><span style="top:-3.4130000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">−</span><span class="mord mtight"><span class="mopen nulldelimiter sizing reset-size3 size6"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8443142857142858em;"><span style="top:-2.656em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span><span style="top:-3.2255000000000003em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line mtight" style="border-bottom-width:0.049em;"></span></span><span style="top:-3.384em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.344em;"><span></span></span></span></span></span><span class="mclose nulldelimiter sizing reset-size3 size6"></span></span><span class="mopen mtight">(</span><span class="mord mtight"><span class="mopen nulldelimiter sizing reset-size3 size6"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.87905em;"><span style="top:-2.656em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">σ</span></span></span></span><span style="top:-3.2255000000000003em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line mtight" style="border-bottom-width:0.049em;"></span></span><span style="top:-3.4623857142857144em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">x</span><span class="mbin mtight">−</span><span class="mord mathnormal mtight">μ</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.344em;"><span></span></span></span></span></span><span class="mclose nulldelimiter sizing reset-size3 size6"></span></span><span class="mclose mtight"><span class="mclose mtight">)</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8913142857142857em;"><span style="top:-2.931em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>e</mi></mrow><annotation encoding="application/x-tex">e</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">e</span></span></span></span> -&gt; the mathematical constant approximately equal to 2.71828</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi></mrow><annotation encoding="application/x-tex">\pi</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span></span></span></span> -&gt; the mathematical constant approximately equal to 3.14159</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>μ</mi></mrow><annotation encoding="application/x-tex">\mu</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">μ</span></span></span></span> -&gt; the mean of the distribution</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>σ</mi></mrow><annotation encoding="application/x-tex">\sigma</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span></span></span></span> -&gt; the standard deviation of the distribution</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>x</mi></mrow><annotation encoding="application/x-tex">x</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">x</span></span></span></span> -&gt; the value of the continuous variable</li></ul><h4 id="622-standardized-normal"><a class="markdownIt-Anchor" href="#622-standardized-normal"></a> 6.2.2 Standardized Normal</h4><p>Standardized normal distribution: a normal distribution with a mean of 0 and a standard deviation of 1.</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>z</mi><mo>=</mo><mfrac><mrow><mi>x</mi><mo>−</mo><mi>μ</mi></mrow><mi>σ</mi></mfrac></mrow><annotation encoding="application/x-tex">z = \frac{x-\mu}{\sigma}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.04398em;">z</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.9463300000000001em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.2603300000000002em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">x</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathnormal">μ</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p>Its density function is:</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>f</mi><mo stretchy="false">(</mo><mi>z</mi><mo stretchy="false">)</mo><mo>=</mo><mfrac><mn>1</mn><msqrt><mrow><mn>2</mn><mi>π</mi></mrow></msqrt></mfrac><msup><mi>e</mi><mrow><mo>−</mo><mfrac><mn>1</mn><mn>2</mn></mfrac><msup><mi>z</mi><mn>2</mn></msup></mrow></msup></mrow><annotation encoding="application/x-tex">f(z) = \frac{1}{\sqrt{2\pi}} e^{-\frac{1}{2}z^2}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.10764em;">f</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.04398em;">z</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.25144em;vertical-align:-0.93em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.2027799999999997em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.90722em;"><span class="svg-align" style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord" style="padding-left:0.833em;"><span class="mord">2</span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span></span></span><span style="top:-2.86722em;"><span class="pstrut" style="height:3em;"></span><span class="hide-tail" style="min-width:0.853em;height:1.08em;"><svg width="400em" height="1.08em" viewBox="0 0 400000 1080" preserveAspectRatio="xMinYMin slice"><path d="M95,702c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429c69,-144,104.5,-217.7,106.5,-221l0 -0c5.3,-9.3,12,-14,20,-14H400000v40H845.2724s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47zM834 80h400000v40h-400000z"></path></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.13278em;"><span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.93em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mord"><span class="mord mathnormal">e</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:1.0369199999999998em;"><span style="top:-3.4130000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">−</span><span class="mord mtight"><span class="mopen nulldelimiter sizing reset-size3 size6"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8443142857142858em;"><span style="top:-2.656em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span><span style="top:-3.2255000000000003em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line mtight" style="border-bottom-width:0.049em;"></span></span><span style="top:-3.384em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.344em;"><span></span></span></span></span></span><span class="mclose nulldelimiter sizing reset-size3 size6"></span></span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.04398em;">z</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8913142857142857em;"><span style="top:-2.931em;margin-right:0.07142857142857144em;"><span class="pstrut" style="height:2.5em;"></span><span class="sizing reset-size3 size1 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>e</mi></mrow><annotation encoding="application/x-tex">e</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">e</span></span></span></span> -&gt; the mathematical constant approximately equal to 2.71828</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi></mrow><annotation encoding="application/x-tex">\pi</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span></span></span></span> -&gt; the mathematical constant approximately equal to 3.14159</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>z</mi></mrow><annotation encoding="application/x-tex">z</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.04398em;">z</span></span></span></span> -&gt; the standardized value of the continuous variable</li></ul><h4 id="623-normal-probabilities"><a class="markdownIt-Anchor" href="#623-normal-probabilities"></a> 6.2.3 Normal Probabilities</h4><p>Probability is measured by the area under the curve.</p><p><img src="/posts/875a/Finding_Normal_Probabilities.webp" alt="" loading="lazy"></p><p>Uniform Distribution: a continuous probability distribution in which the probability of observing a value x in any interval of equal length is the same for each interval of the same length. Also known as rectangular distribution.</p><p>Exponential Distribution: a continuous probability distribution that is used to describe the time between events that occur at a constant average rate and are independent of each other. The exponential distribution is skewed to the right.</p><center>-----</center><h1 id="chapter-7-sampling-distributions"><a class="markdownIt-Anchor" href="#chapter-7-sampling-distributions"></a> Chapter 7: Sampling Distributions</h1><p>Sampling distribution: a distribution of all of the possible values of a sample statistic for a given sample size selected from a population.</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover><mo>=</mo><mfrac><mrow><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><msub><mi>X</mi><mi>i</mi></msub></mrow><mi>n</mi></mfrac></mrow><annotation encoding="application/x-tex">\bar{X} = \frac{\sum_{i=1}^{n} X_i}{n}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8201099999999999em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.180002em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.494002em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.6897100000000003em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:-0.0000050000000000050004em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.804292em;"><span style="top:-2.40029em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.2029em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.29971000000000003em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.07847em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><blockquote><p>Assume there is a population:</p><ul><li>population size <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>N</mi><mo>=</mo><mn>4</mn></mrow><annotation encoding="application/x-tex">N=4</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.10903em;">N</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">4</span></span></span></span></li><li>variable of interest is, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>X</mi></mrow><annotation encoding="application/x-tex">X</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span></span>, age of individuals</li><li>values of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>X</mi></mrow><annotation encoding="application/x-tex">X</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span></span>: <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>18</mn><mo separator="true">,</mo><mn>20</mn><mo separator="true">,</mo><mn>22</mn><mo separator="true">,</mo><mn>24</mn></mrow><annotation encoding="application/x-tex">18, 20, 22, 24</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8388800000000001em;vertical-align:-0.19444em;"></span><span class="mord">1</span><span class="mord">8</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord">2</span><span class="mord">0</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord">2</span><span class="mord">2</span><span class="mpunct">,</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord">2</span><span class="mord">4</span></span></span></span> (years)</li></ul><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>μ</mi><mo>=</mo><mfrac><mrow><mn>18</mn><mo>+</mo><mn>20</mn><mo>+</mo><mn>22</mn><mo>+</mo><mn>24</mn></mrow><mn>4</mn></mfrac><mo>=</mo><mn>21</mn></mrow><annotation encoding="application/x-tex">\mu = \frac{18+20+22+24}{4} = 21</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">μ</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.00744em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.32144em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">4</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord">1</span><span class="mord">8</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord">2</span><span class="mord">0</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord">2</span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord">2</span><span class="mord">4</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord">1</span></span></span></span></span></p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>σ</mi><mo>=</mo><msqrt><mfrac><mrow><munderover><mo>∑</mo><mrow><mi>i</mi><mo>=</mo><mn>1</mn></mrow><mi>n</mi></munderover><mo stretchy="false">(</mo><msub><mi>X</mi><mi>i</mi></msub><mo>−</mo><mi>μ</mi><msup><mo stretchy="false">)</mo><mn>2</mn></msup></mrow><mi>N</mi></mfrac></msqrt><mo>=</mo><mn>2.236</mn></mrow><annotation encoding="application/x-tex">\sigma = \sqrt{\frac{\sum^n_{i=1}(X_i-\mu)^2}{N}} = 2.236</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.44em;vertical-align:-0.702124em;"></span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.737876em;"><span class="svg-align" style="top:-4.4em;"><span class="pstrut" style="height:4.4em;"></span><span class="mord" style="padding-left:1em;"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.494002em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.10903em;">N</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.6897100000000003em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mop"><span class="mop op-symbol small-op" style="position:relative;top:-0.0000050000000000050004em;">∑</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.804292em;"><span style="top:-2.40029em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">i</span><span class="mrel mtight">=</span><span class="mord mtight">1</span></span></span></span><span style="top:-3.2029em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.29971000000000003em;"><span></span></span></span></span></span></span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.31166399999999994em;"><span style="top:-2.5500000000000003em;margin-left:-0.07847em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">i</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathnormal">μ</span><span class="mclose"><span class="mclose">)</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.740108em;"><span style="top:-2.9890000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span><span style="top:-3.6978760000000004em;"><span class="pstrut" style="height:4.4em;"></span><span class="hide-tail" style="min-width:1.02em;height:2.48em;"><svg width="400em" height="2.48em" viewBox="0 0 400000 2592" preserveAspectRatio="xMinYMin slice"><path d="M424,2478c-1.3,-0.7,-38.5,-172,-111.5,-514c-73,-342,-109.8,-513.3,-110.5,-514c0,-2,-10.7,14.3,-32,49c-4.7,7.3,-9.8,15.7,-15.5,25c-5.7,9.3,-9.8,16,-12.5,20s-5,7,-5,7c-4,-3.3,-8.3,-7.7,-13,-13s-13,-13,-13,-13s76,-122,76,-122s77,-121,77,-121s209,968,209,968c0,-2,84.7,-361.7,254,-1079c169.3,-717.3,254.7,-1077.7,256,-1081l0 -0c4,-6.7,10,-10,18,-10 H400000v40H1014.6s-87.3,378.7,-272.6,1166c-185.3,787.3,-279.3,1182.3,-282,1185c-2,6,-10,9,-24,9c-8,0,-12,-0.7,-12,-2z M1001 80h400000v40h-400000z"></path></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.702124em;"><span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord">.</span><span class="mord">2</span><span class="mord">3</span><span class="mord">6</span></span></span></span></span></p></blockquote><h2 id="71-sample-mean-sampling-distribution"><a class="markdownIt-Anchor" href="#71-sample-mean-sampling-distribution"></a> 7.1 Sample Mean Sampling Distribution</h2><h4 id="711-standard-error-of-the-mean"><a class="markdownIt-Anchor" href="#711-standard-error-of-the-mean"></a> 7.1.1 Standard Error of the Mean</h4><p>Standard error of the mean: the standard deviation of the sampling distribution of the sample mean.</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>σ</mi><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover></msub><mo>=</mo><mfrac><mi>σ</mi><msqrt><mi>n</mi></msqrt></mfrac></mrow><annotation encoding="application/x-tex">\sigma_{\bar{X}} = \frac{\sigma}{\sqrt{n}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6598369999999998em;vertical-align:-0.22927699999999984em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.4707230000000004em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.07847em;">X</span></span></span><span style="top:-2.9523300000000003em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.22927699999999984em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.03756em;vertical-align:-0.9300000000000002em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.10756em;"><span style="top:-2.30972em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8002800000000001em;"><span class="svg-align" style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord" style="padding-left:0.833em;"><span class="mord mathnormal">n</span></span></span><span style="top:-2.76028em;"><span class="pstrut" style="height:3em;"></span><span class="hide-tail" style="min-width:0.853em;height:1.08em;"><svg width="400em" height="1.08em" viewBox="0 0 400000 1080" preserveAspectRatio="xMinYMin slice"><path d="M95,702c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429c69,-144,104.5,-217.7,106.5,-221l0 -0c5.3,-9.3,12,-14,20,-14H400000v40H845.2724s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47zM834 80h400000v40h-400000z"></path></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.23972em;"><span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.9300000000000002em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><h4 id="712-z-value-for-sampling-distribution-of-mean"><a class="markdownIt-Anchor" href="#712-z-value-for-sampling-distribution-of-mean"></a> 7.1.2 Z-Value for Sampling Distribution of Mean</h4><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>Z</mi><mo>=</mo><mfrac><mrow><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover><mo>−</mo><mi>μ</mi></mrow><msub><mi>σ</mi><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover></msub></mfrac><mo>=</mo><mfrac><mrow><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover><mo>−</mo><mi>μ</mi></mrow><mfrac><mi>σ</mi><msqrt><mi>n</mi></msqrt></mfrac></mfrac></mrow><annotation encoding="application/x-tex">Z = \frac{\bar{X}-\mu}{\sigma_{\bar{X}}} = \frac{\bar{X}-\mu}{\frac{\sigma}{\sqrt{n}}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">Z</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.412387em;vertical-align:-0.9152769999999999em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.4971099999999997em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.4707230000000004em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.07847em;">X</span></span></span><span style="top:-2.9523300000000003em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.22927699999999984em;"><span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathnormal">μ</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.9152769999999999em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.72111em;vertical-align:-1.2240000000000002em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.4971099999999997em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.695392em;"><span style="top:-2.6258665em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord sqrt mtight"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.8059050000000001em;"><span class="svg-align" style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord mtight" style="padding-left:0.833em;"><span class="mord mathnormal mtight">n</span></span></span><span style="top:-2.765905em;"><span class="pstrut" style="height:3em;"></span><span class="hide-tail mtight" style="min-width:0.853em;height:1.08em;"><svg width="400em" height="1.08em" viewBox="0 0 400000 1080" preserveAspectRatio="xMinYMin slice"><path d="M95,702c-2.7,0,-7.17,-2.7,-13.5,-8c-5.8,-5.3,-9.5,-10,-9.5,-14c0,-2,0.3,-3.3,1,-4c1.3,-2.7,23.83,-20.7,67.5,-54c44.2,-33.3,65.8,-50.3,66.5,-51c1.3,-1.3,3,-2,5,-2c4.7,0,8.7,3.3,12,10s173,378,173,378c0.7,0,35.3,-71,104,-213c68.7,-142,137.5,-285,206.5,-429c69,-144,104.5,-217.7,106.5,-221l0 -0c5.3,-9.3,12,-14,20,-14H400000v40H845.2724s-225.272,467,-225.272,467s-235,486,-235,486c-2.7,4.7,-9,7,-19,7c-6,0,-10,-1,-12,-3s-194,-422,-194,-422s-65,47,-65,47zM834 80h400000v40h-400000z"></path></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.234095em;"><span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">σ</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.538em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathnormal">μ</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.2240000000000002em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover></mrow><annotation encoding="application/x-tex">\bar{X}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8201099999999999em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord">ˉ</span></span></span></span></span></span></span></span></span></span> -&gt; sample mean</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>μ</mi></mrow><annotation encoding="application/x-tex">\mu</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">μ</span></span></span></span> -&gt; population mean</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>σ</mi><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover></msub></mrow><annotation encoding="application/x-tex">\sigma_{\bar{X}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6598369999999998em;vertical-align:-0.22927699999999984em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.4707230000000004em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.07847em;">X</span></span></span><span style="top:-2.9523300000000003em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.22927699999999984em;"><span></span></span></span></span></span></span></span></span></span> -&gt; standard error of the mean</li></ul><h4 id="713-sampling-distribution-properties"><a class="markdownIt-Anchor" href="#713-sampling-distribution-properties"></a> 7.1.3 Sampling Distribution Properties</h4><ul><li>The mean of the sampling distribution of the sample mean is equal to the mean of the population</li><li>As <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span></span></span></span> increases, the standard error of the mean (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>σ</mi><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover></msub></mrow><annotation encoding="application/x-tex">\sigma_{\bar{X}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6598369999999998em;vertical-align:-0.22927699999999984em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.4707230000000004em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.07847em;">X</span></span></span><span style="top:-2.9523300000000003em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.22927699999999984em;"><span></span></span></span></span></span></span></span></span></span>) decreases</li></ul><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>μ</mi><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover></msub><mo>=</mo><mi>μ</mi></mrow><annotation encoding="application/x-tex">\mu_{\bar{X}} = \mu</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.6598369999999998em;vertical-align:-0.22927699999999984em;"></span><span class="mord"><span class="mord mathnormal">μ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.3448em;"><span style="top:-2.4707230000000004em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord accent mtight"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-2.7em;"><span class="pstrut" style="height:2.7em;"></span><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.07847em;">X</span></span></span><span style="top:-2.9523300000000003em;"><span class="pstrut" style="height:2.7em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord mtight">ˉ</span></span></span></span></span></span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.22927699999999984em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">μ</span></span></span></span></span></p><h4 id="714-central-limit-theorem"><a class="markdownIt-Anchor" href="#714-central-limit-theorem"></a> 7.1.4 Central Limit Theorem</h4><p>Central limit theorem: the sampling distribution of the sample mean is approximately normal for a sufficiently large sample size.</p><ul><li>as the sample size gets large enough, the sampling distribution of the sample mean becomes almost normal regardless of shape of population</li></ul><p>Central limit theorem is used when the population is not normal.</p><blockquote><p>How large is large enough?</p><ul><li>for most distributions, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>&gt;</mo><mn>30</mn></mrow><annotation encoding="application/x-tex">n \gt 30</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span><span class="mord">0</span></span></span></span> is sufficient</li><li>for fairly symmetric distributions, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>&gt;</mo><mn>15</mn></mrow><annotation encoding="application/x-tex">n \gt 15</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.5782em;vertical-align:-0.0391em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span><span class="mord">5</span></span></span></span> is sufficient</li><li>for a normal population distribution, the sampling distribution of the sample mean is always normally distributed</li></ul></blockquote><h2 id="72-population-proportions"><a class="markdownIt-Anchor" href="#72-population-proportions"></a> 7.2 Population Proportions</h2><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi></mrow><annotation encoding="application/x-tex">\pi</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span></span></span></span>: the proportion of the population having some characteristic.</p><p>Sample proportion (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi></mrow><annotation encoding="application/x-tex">p</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">p</span></span></span></span>): provides an estimate of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi></mrow><annotation encoding="application/x-tex">\pi</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span></span></span></span>:</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>p</mi><mo>=</mo><mfrac><mtext>number&nbsp;of&nbsp;items&nbsp;in&nbsp;the&nbsp;population&nbsp;having&nbsp;the&nbsp;characteristic</mtext><mtext>total&nbsp;number&nbsp;of&nbsp;items&nbsp;in&nbsp;the&nbsp;population</mtext></mfrac></mrow><annotation encoding="application/x-tex">p = \frac{\text{number of items in the population having the characteristic}}{\text{total number of items in the population}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.25188em;vertical-align:-0.8804400000000001em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3714399999999998em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord">total&nbsp;number&nbsp;of&nbsp;items&nbsp;in&nbsp;the&nbsp;population</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord">number&nbsp;of&nbsp;items&nbsp;in&nbsp;the&nbsp;population&nbsp;having&nbsp;the&nbsp;characteristic</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.8804400000000001em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>0</mn><mo>≤</mo><mi>p</mi><mo>≤</mo><mn>1</mn></mrow><annotation encoding="application/x-tex">0 \leq p \leq 1</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.78041em;vertical-align:-0.13597em;"></span><span class="mord">0</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">≤</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8304100000000001em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">≤</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">1</span></span></span></span></li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi></mrow><annotation encoding="application/x-tex">p</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">p</span></span></span></span> is approximately distributed as a normal distribution when <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span></span></span></span> is large</li></ul><h4 id="721-sampling-distribution-of-the-sample-proportion"><a class="markdownIt-Anchor" href="#721-sampling-distribution-of-the-sample-proportion"></a> 7.2.1 Sampling Distribution of the Sample Proportion</h4><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msub><mi>σ</mi><mi>p</mi></msub><mo>=</mo><msqrt><mfrac><mrow><mi>π</mi><mo stretchy="false">(</mo><mn>1</mn><mo>−</mo><mi>π</mi><mo stretchy="false">)</mo></mrow><mi>n</mi></mfrac></msqrt></mrow><annotation encoding="application/x-tex">\sigma_p = \sqrt{\frac{\pi(1-\pi)}{n}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">p</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.44em;vertical-align:-0.7356250000000002em;"></span><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.7043749999999998em;"><span class="svg-align" style="top:-4.4em;"><span class="pstrut" style="height:4.4em;"></span><span class="mord" style="padding-left:1em;"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">n</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">π</span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span><span class="mclose">)</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span><span style="top:-3.664375em;"><span class="pstrut" style="height:4.4em;"></span><span class="hide-tail" style="min-width:1.02em;height:2.48em;"><svg width="400em" height="2.48em" viewBox="0 0 400000 2592" preserveAspectRatio="xMinYMin slice"><path d="M424,2478c-1.3,-0.7,-38.5,-172,-111.5,-514c-73,-342,-109.8,-513.3,-110.5,-514c0,-2,-10.7,14.3,-32,49c-4.7,7.3,-9.8,15.7,-15.5,25c-5.7,9.3,-9.8,16,-12.5,20s-5,7,-5,7c-4,-3.3,-8.3,-7.7,-13,-13s-13,-13,-13,-13s76,-122,76,-122s77,-121,77,-121s209,968,209,968c0,-2,84.7,-361.7,254,-1079c169.3,-717.3,254.7,-1077.7,256,-1081l0 -0c4,-6.7,10,-10,18,-10 H400000v40H1014.6s-87.3,378.7,-272.6,1166c-185.3,787.3,-279.3,1182.3,-282,1185c-2,6,-10,9,-24,9c-8,0,-12,-0.7,-12,-2z M1001 80h400000v40h-400000z"></path></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.7356250000000002em;"><span></span></span></span></span></span></span></span></span></span></p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>π</mi></mrow><annotation encoding="application/x-tex">\pi</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span></span></span></span> -&gt; population proportion</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi></mrow><annotation encoding="application/x-tex">n</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">n</span></span></span></span> -&gt; sample size</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>σ</mi><mi>p</mi></msub></mrow><annotation encoding="application/x-tex">\sigma_p</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.716668em;vertical-align:-0.286108em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">p</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span></span> -&gt; standard error of the sample proportion</li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>p</mi></mrow><annotation encoding="application/x-tex">p</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">p</span></span></span></span> -&gt; sample proportion</li></ul><h4 id="722-z-value-for-proportions"><a class="markdownIt-Anchor" href="#722-z-value-for-proportions"></a> 7.2.2 Z-Value for Proportions</h4><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mi>Z</mi><mo>=</mo><mfrac><mrow><mi>p</mi><mo>−</mo><mi>π</mi></mrow><msub><mi>σ</mi><mi>p</mi></msub></mfrac><mo>=</mo><mfrac><mrow><mi>p</mi><mo>−</mo><mi>π</mi></mrow><msqrt><mfrac><mrow><mi>π</mi><mo stretchy="false">(</mo><mn>1</mn><mo>−</mo><mi>π</mi><mo stretchy="false">)</mo></mrow><mi>n</mi></mfrac></msqrt></mfrac></mrow><annotation encoding="application/x-tex">Z = \frac{p-\pi}{\sigma_p} = \frac{p-\pi}{\sqrt{\frac{\pi(1-\pi)}{n}}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">Z</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.232438em;vertical-align:-0.972108em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.2603300000000002em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.15139200000000003em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">p</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.286108em;"><span></span></span></span></span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.972108em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.99033em;vertical-align:-1.73em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.2603300000000002em;"><span style="top:-2.11em;"><span class="pstrut" style="height:3.3175em;"></span><span class="mord"><span class="mord sqrt"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.3175000000000001em;"><span class="svg-align" style="top:-3.8em;"><span class="pstrut" style="height:3.8em;"></span><span class="mord" style="padding-left:1em;"><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.01em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">n</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.485em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">π</span><span class="mopen mtight">(</span><span class="mord mtight">1</span><span class="mbin mtight">−</span><span class="mord mathnormal mtight" style="margin-right:0.03588em;">π</span><span class="mclose mtight">)</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span><span style="top:-3.2775em;"><span class="pstrut" style="height:3.8em;"></span><span class="hide-tail" style="min-width:1.02em;height:1.8800000000000001em;"><svg width="400em" height="1.8800000000000001em" viewBox="0 0 400000 1944" preserveAspectRatio="xMinYMin slice"><path d="M983 90l0 -0c4,-6.7,10,-10,18,-10 H400000v40H1013.1s-83.4,268,-264.1,840c-180.7,572,-277,876.3,-289,913c-4.7,4.7,-12.7,7,-24,7s-12,0,-12,0c-1.3,-3.3,-3.7,-11.7,-7,-25c-35.3,-125.3,-106.7,-373.3,-214,-744c-10,12,-21,25,-33,39s-32,39,-32,39c-6,-5.3,-15,-14,-27,-26s25,-30,25,-30c26.7,-32.7,52,-63,76,-91s52,-60,52,-60s208,722,208,722c56,-175.3,126.3,-397.3,211,-666c84.7,-268.7,153.8,-488.2,207.5,-658.5c53.7,-170.3,84.5,-266.8,92.5,-289.5zM1001 80h400000v40h-400000z"></path></svg></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.5225em;"><span></span></span></span></span></span></span></span><span style="top:-3.5475em;"><span class="pstrut" style="height:3.3175em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.9945em;"><span class="pstrut" style="height:3.3175em;"></span><span class="mord"><span class="mord mathnormal">p</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">π</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:1.73em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><center>-----</center><h1 id="chapter-8-confidence-interval-estimation"><a class="markdownIt-Anchor" href="#chapter-8-confidence-interval-estimation"></a> Chapter 8: Confidence Interval Estimation</h1><h2 id="81-point-and-interval-estimates"><a class="markdownIt-Anchor" href="#81-point-and-interval-estimates"></a> 8.1 Point and Interval Estimates</h2><p>Point estimate: a single number.</p><p>Confidence interval: a set of two plausible values at a specified confidence level that contains true parameter.</p><p><img src="/posts/875a/Point_And_Interval_Estimates.webp" alt="" loading="lazy"></p><h2 id="82-confidence-intervals"><a class="markdownIt-Anchor" href="#82-confidence-intervals"></a> 8.2 Confidence Intervals</h2><p>Interval estimate: provides more information about a population characteristic than does a point estimate -&gt; confidence intervals.</p><center>-----</center><h1 id="chapter-9-fundamentals-of-hypothesis-testing-one-sample-tests"><a class="markdownIt-Anchor" href="#chapter-9-fundamentals-of-hypothesis-testing-one-sample-tests"></a> Chapter 9: Fundamentals of Hypothesis Testing: One-Sample Tests</h1><p>Hypothesis: a claim or assertion about a population parameter.</p><blockquote><p>Example:<br>The mean diameter of a manufactured bolt is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>30</mn></mrow><annotation encoding="application/x-tex">30</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span><span class="mord">0</span></span></span></span>mm -&gt; <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>H</mi><mn>0</mn></msub><mo>:</mo><mi>μ</mi><mo>=</mo><mn>30</mn></mrow><annotation encoding="application/x-tex">H_0:\mu=30</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.08125em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">μ</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span><span class="mord">0</span></span></span></span></p></blockquote><h2 id="91-the-null-hypothesis"><a class="markdownIt-Anchor" href="#91-the-null-hypothesis"></a> 9.1 The Null Hypothesis</h2><ul><li>begin with the assumption that the null hypothesis is true</li><li>similar to the notion of innocent until proven guilty</li><li>represents the current belief in a situation</li><li>always contains <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>=</mo></mrow><annotation encoding="application/x-tex">=</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.36687em;vertical-align:0em;"></span><span class="mrel">=</span></span></span></span>, or <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>≤</mo></mrow><annotation encoding="application/x-tex">\leq</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7719400000000001em;vertical-align:-0.13597em;"></span><span class="mrel">≤</span></span></span></span>, or <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>≥</mo></mrow><annotation encoding="application/x-tex">\geq</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7719400000000001em;vertical-align:-0.13597em;"></span><span class="mrel">≥</span></span></span></span> sign</li><li>may or may not be rejected</li></ul><h2 id="92-the-alternative-hypothesis"><a class="markdownIt-Anchor" href="#92-the-alternative-hypothesis"></a> 9.2 The Alternative Hypothesis</h2><ul><li>is the opposite of the null hypothesis</li><li>the mean diameter of a manufactured bolt is not equal to <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>30</mn></mrow><annotation encoding="application/x-tex">30</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span><span class="mord">0</span></span></span></span>mm</li><li>challenges the status quo</li><li>never contains the <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>=</mo></mrow><annotation encoding="application/x-tex">=</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.36687em;vertical-align:0em;"></span><span class="mrel">=</span></span></span></span>, or <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>≤</mo></mrow><annotation encoding="application/x-tex">\leq</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7719400000000001em;vertical-align:-0.13597em;"></span><span class="mrel">≤</span></span></span></span>, or <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>≥</mo></mrow><annotation encoding="application/x-tex">\geq</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7719400000000001em;vertical-align:-0.13597em;"></span><span class="mrel">≥</span></span></span></span> sign</li><li>may or may not be proven</li><li>is generally the hypothesis that the researcher is trying to prove</li></ul><h2 id="93-the-hypothesis-testing-process"><a class="markdownIt-Anchor" href="#93-the-hypothesis-testing-process"></a> 9.3 The Hypothesis Testing Process</h2><blockquote><p>The population mean age is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>50</mn></mrow><annotation encoding="application/x-tex">50</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">5</span><span class="mord">0</span></span></span></span>.</p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>H</mi><mn>0</mn></msub><mo>:</mo><mi>μ</mi><mo>=</mo><mn>50</mn></mrow><annotation encoding="application/x-tex">H_0: \mu = 50</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.08125em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">μ</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">5</span><span class="mord">0</span></span></span></span></li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>H</mi><mn>1</mn></msub><mo>:</mo><mi>μ</mi><mo mathvariant="normal">≠</mo><mn>50</mn></mrow><annotation encoding="application/x-tex">H_1: \mu \neq 50</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.08125em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">μ</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"><span class="mrel"><span class="mord vbox"><span class="thinbox"><span class="rlap"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="inner"><span class="mrel"></span></span><span class="fix"></span></span></span></span></span><span class="mrel">=</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">5</span><span class="mord">0</span></span></span></span></li></ul><p>Suppose the sample mean age was <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover><mo>=</mo><mn>20</mn></mrow><annotation encoding="application/x-tex">\bar{X} = 20</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8201099999999999em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord">0</span></span></span></span>.<br>This is lower than the claimed mean population age of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>50</mn></mrow><annotation encoding="application/x-tex">50</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">5</span><span class="mord">0</span></span></span></span>.</p><p>If the null hypothesis were true, the probability of getting such a different sample mean would be very small, so you reject the null hypothesis.</p><p>In other words, getting a sample mean of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>20</mn></mrow><annotation encoding="application/x-tex">20</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mord">0</span></span></span></span> is so unlikely if the population mean was <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>50</mn></mrow><annotation encoding="application/x-tex">50</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">5</span><span class="mord">0</span></span></span></span>, you conclude that the population mean must not be <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>50</mn></mrow><annotation encoding="application/x-tex">50</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">5</span><span class="mord">0</span></span></span></span>.<br><img src="/posts/875a/The_Hypothesis_Testing_Process.webp" alt="" loading="lazy"></p></blockquote><h4 id="931-the-test-statistic-and-critical-values"><a class="markdownIt-Anchor" href="#931-the-test-statistic-and-critical-values"></a> 9.3.1 The Test Statistic and Critical Values</h4><p>If the sample mean is close to the stated population mean, the null hypothesis is not rejected.</p><p>If the sample mean is far from the stated population mean, the null hypothesis is rejected.</p><p>How far is "far enough" to reject <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>H</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">H_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.08125em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>?</p><p>The critical value of a test statistic creates a "line in the sand" for decision making -- it answers the question of how far is far enough.</p><p><img src="/posts/875a/The_Test_Statistic_And_Critical_Values.webp" alt="" loading="lazy"></p><h4 id="932-risks-in-decision-making-using-hypothesis-testing"><a class="markdownIt-Anchor" href="#932-risks-in-decision-making-using-hypothesis-testing"></a> 9.3.2 Risks in Decision Making Using Hypothesis Testing</h4><ul><li>Type I error: rejecting the null hypothesis when it is true<ul><li>a "false alarm"</li><li>the probability of a Type I Error is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>α</mi></mrow><annotation encoding="application/x-tex">\alpha</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span></span></span></span><ul><li>called level of significance of the test</li><li>set by researcher in advance</li></ul></li></ul></li><li>Type II error: failing to reject the null hypothesis when it is false<ul><li>a "missed opportunity"</li><li>the probability of a Type II Error is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>β</mi></mrow><annotation encoding="application/x-tex">\beta</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord mathnormal" style="margin-right:0.05278em;">β</span></span></span></span></li></ul></li></ul><p><img src="/posts/875a/Risks_In_Decision_Making_Using_Hypothesis_Testing.webp" alt="" loading="lazy"></p><ul><li>the confidence coefficient is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mn>1</mn><mo>−</mo><mi>α</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(1-\alpha)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span><span class="mclose">)</span></span></span></span>: the probability of not rejecting <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>H</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">H_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.08125em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> when it is true</li><li>the confidence level of a hypothesis test is <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mn>1</mn><mo>−</mo><mi>α</mi><mo stretchy="false">)</mo><mo>×</mo><mn>100</mn><mi mathvariant="normal">%</mi></mrow><annotation encoding="application/x-tex">(1-\alpha)\times 100 \%</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.80556em;vertical-align:-0.05556em;"></span><span class="mord">1</span><span class="mord">0</span><span class="mord">0</span><span class="mord">%</span></span></span></span></li><li>the power of a statistical test <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mn>1</mn><mo>−</mo><mi>β</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">(1-\beta)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord">1</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="mclose">)</span></span></span></span> is the probability of rejecting <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>H</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">H_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.08125em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> when it is false</li></ul><p>Type I and Type II errors cannot happen at the same time.</p><ul><li>A Type I error can only occur if <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>H</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">H_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.08125em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> is true</li><li>A Type II error can only occur if <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>H</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">H_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.08125em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> is false</li></ul><blockquote><p>Factors affecting Type II Error:<br>All else equal……</p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>β</mi><mo>↑</mo></mrow><annotation encoding="application/x-tex">\beta \uparrow</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">↑</span></span></span></span> when the difference between hypothesized parameter and its true value <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>↓</mo></mrow><annotation encoding="application/x-tex">\downarrow</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mrel">↓</span></span></span></span></li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>β</mi><mo>↑</mo></mrow><annotation encoding="application/x-tex">\beta \uparrow</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">↑</span></span></span></span> when <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>α</mi><mo>↓</mo></mrow><annotation encoding="application/x-tex">\alpha \downarrow</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">↓</span></span></span></span></li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>β</mi><mo>↑</mo></mrow><annotation encoding="application/x-tex">\beta \uparrow</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">↑</span></span></span></span> when <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>σ</mi><mo>↑</mo></mrow><annotation encoding="application/x-tex">\sigma \uparrow</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">↑</span></span></span></span></li><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>β</mi><mo>↑</mo></mrow><annotation encoding="application/x-tex">\beta \uparrow</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord mathnormal" style="margin-right:0.05278em;">β</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">↑</span></span></span></span> when <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>n</mi><mo>↓</mo></mrow><annotation encoding="application/x-tex">n \downarrow</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">↓</span></span></span></span></li></ul></blockquote><h4 id="933-level-of-significance-and-the-rejection-region"><a class="markdownIt-Anchor" href="#933-level-of-significance-and-the-rejection-region"></a> 9.3.3 Level of Significance and the Rejection Region</h4><blockquote><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>H</mi><mn>0</mn></msub><mo>:</mo><mi>μ</mi><mo>=</mo><mn>30</mn></mrow><annotation encoding="application/x-tex">H_0: \mu = 30</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.08125em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">μ</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span><span class="mord">0</span></span></span></span><br><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>H</mi><mn>1</mn></msub><mo>:</mo><mi>μ</mi><mo mathvariant="normal">≠</mo><mn>30</mn></mrow><annotation encoding="application/x-tex">H_1: \mu \neq 30</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.08125em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord mathnormal">μ</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"><span class="mrel"><span class="mord vbox"><span class="thinbox"><span class="rlap"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="inner"><span class="mrel"></span></span><span class="fix"></span></span></span></span></span><span class="mrel">=</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">3</span><span class="mord">0</span></span></span></span><br>Level of significance = <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>α</mi></mrow><annotation encoding="application/x-tex">\alpha</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span></span></span></span><br><img src="/posts/875a/Level_Of_Significance_And_The_Rejection_Region.webp" alt="" loading="lazy"></p><p>This is a two-tail test because there is a rejection region in both tails.</p></blockquote><h2 id="94-hypothesis-tests-for-the-mean"><a class="markdownIt-Anchor" href="#94-hypothesis-tests-for-the-mean"></a> 9.4 Hypothesis Tests for the Mean</h2><p><img src="/posts/875a/Hypothesis_Tests_For_The_Mean.webp" alt="" loading="lazy"></p><h4 id="941-z-test-of-hypothesis-for-the-mean"><a class="markdownIt-Anchor" href="#941-z-test-of-hypothesis-for-the-mean"></a> 9.4.1 Z Test of Hypothesis for the Mean</h4><p>Convert sample statistic (<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover></mrow><annotation encoding="application/x-tex">\bar{X}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8201099999999999em;vertical-align:0em;"></span><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord">ˉ</span></span></span></span></span></span></span></span></span></span>) to a <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Z</mi><mtext>STAT</mtext></msub></mrow><annotation encoding="application/x-tex">Z_{\text{STAT}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07153em;">Z</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.07153em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord mtight">STAT</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> test statistic.</p><p><img src="/posts/875a/Z_Test_Of_Hypothesis_For_The_Mean.webp" alt="" loading="lazy"></p><blockquote><p>For a two-tail test for the mean, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>σ</mi></mrow><annotation encoding="application/x-tex">\sigma</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">σ</span></span></span></span> known:</p><ul><li>determine the critical <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>Z</mi></mrow><annotation encoding="application/x-tex">Z</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">Z</span></span></span></span> values for a specified level of significance <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>α</mi></mrow><annotation encoding="application/x-tex">\alpha</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.0037em;">α</span></span></span></span> from a table or by using computer software<br>Decision rule: if the test statistic falls in the rejection region, reject <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>H</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">H_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.08125em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> otherwise do not reject <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>H</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">H_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.08125em;">H</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.08125em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></li></ul></blockquote><p><img src="/posts/875a/Z_Test_Of_Hypothesis_For_The_Mean_1.webp" alt="" loading="lazy"></p><center>-----</center><h1 id="chapter-10-two-sample-tests-and-one-way-anova"><a class="markdownIt-Anchor" href="#chapter-10-two-sample-tests-and-one-way-anova"></a> Chapter 10: Two-Sample Tests and One-Way ANOVA</h1><h2 id="101-two-sample-tests"><a class="markdownIt-Anchor" href="#101-two-sample-tests"></a> 10.1 Two-Sample Tests</h2><p><img src="/posts/875a/Two_Sample_Tests.webp" alt="" loading="lazy"></p><h4 id="1011-difference-between-two-means"><a class="markdownIt-Anchor" href="#1011-difference-between-two-means"></a> 10.1.1 Difference Between Two Means</h4><p>To test hypothesis or form a confidence interval for the difference between two population means, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>μ</mi><mn>1</mn></msub><mo>−</mo><msub><mi>μ</mi><mn>2</mn></msub></mrow><annotation encoding="application/x-tex">\mu_1 - \mu_2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.7777700000000001em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">μ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">μ</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>.</p><blockquote><p>The point estimate for the difference is:<br><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover><mn>1</mn></msub><mo>−</mo><msub><mover accent="true"><mi>X</mi><mo>ˉ</mo></mover><mn>2</mn></msub></mrow><annotation encoding="application/x-tex">\bar{X}_1 - \bar{X}_2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.9701099999999999em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">1</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.9701099999999999em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord accent"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8201099999999999em;"><span style="top:-3em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.07847em;">X</span></span></span><span style="top:-3.25233em;"><span class="pstrut" style="height:3em;"></span><span class="accent-body" style="left:-0.16666em;"><span class="mord">ˉ</span></span></span></span></span></span></span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span></p></blockquote></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;统计学笔记，仅作为个人学习记录，不保证正确性。&lt;/p&gt;</summary>
    
    
    
    <category term="学术笔记" scheme="https://blog.cytrogen.icu/categories/%E5%AD%A6%E6%9C%AF%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="大学课程" scheme="https://blog.cytrogen.icu/tags/%E5%A4%A7%E5%AD%A6%E8%AF%BE%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>ECO 1001 笔记</title>
    <link href="https://blog.cytrogen.icu/posts/9e+71.html"/>
    <id>https://blog.cytrogen.icu/posts/9e+71.html</id>
    <published>2023-10-17T06:21:26.000Z</published>
    <updated>2026-02-09T17:16:54.693Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>微观经济学笔记，仅作为个人学习记录，不保证正确性。</p><span id="more"></span> <h1 id="目录"><a class="markdownIt-Anchor" href="#目录"></a> 目录</h1><details><ul><li><a href="#%E7%9B%AE%E5%BD%95">目录</a></li><li><a href="#%E7%AC%AC%E4%B8%89%E7%AB%A0%E5%B8%82%E5%9C%BA">第三章：市场</a><ul><li><a href="#31-%E5%B8%82%E5%9C%BA%E7%9A%84%E5%AE%9A%E4%B9%89">3.1 市场的定义</a></li><li><a href="#32-%E5%B8%82%E5%9C%BA%E9%9C%80%E6%B1%82">3.2 市场需求</a><ul><li><a href="#321-%E9%9C%80%E6%B1%82%E8%A1%A8">3.2.1 需求表</a></li><li><a href="#322-%E9%9C%80%E6%B1%82%E6%9B%B2%E7%BA%BF">3.2.2 需求曲线</a></li><li><a href="#323-%E9%9C%80%E6%B1%82%E7%9A%84%E5%8F%98%E5%8C%96">3.2.3 需求的变化</a></li><li><a href="#324-%E9%9C%80%E6%B1%82%E6%9B%B2%E7%BA%BF%E7%9A%84%E7%A7%BB%E5%8A%A8">3.2.4 需求曲线的移动</a></li><li><a href="#325-%E7%A7%BB%E5%8A%A8-vs-%E6%B2%BF%E7%9D%80%E6%9B%B2%E7%BA%BF%E7%9A%84%E7%A7%BB%E5%8A%A8">3.2.5 移动 vs. 沿着曲线的移动</a></li></ul></li><li><a href="#33-%E5%B8%82%E5%9C%BA%E4%BE%9B%E7%BB%99">3.3 市场供给</a><ul><li><a href="#331-%E4%BE%9B%E7%BB%99%E8%A1%A8">3.3.1 供给表</a></li><li><a href="#332-%E4%BE%9B%E7%BB%99%E6%9B%B2%E7%BA%BF">3.3.2 供给曲线</a></li><li><a href="#333-%E4%BE%9B%E7%BB%99%E7%9A%84%E5%8F%98%E5%8C%96">3.3.3 供给的变化</a></li><li><a href="#334-%E4%BE%9B%E7%BB%99%E6%9B%B2%E7%BA%BF%E7%9A%84%E7%A7%BB%E5%8A%A8">3.3.4 供给曲线的移动</a></li><li><a href="#335-%E7%A7%BB%E5%8A%A8-vs-%E6%B2%BF%E7%9D%80%E6%9B%B2%E7%BA%BF%E7%9A%84%E7%A7%BB%E5%8A%A8">3.3.5 移动 vs. 沿着曲线的移动</a></li></ul></li><li><a href="#34-%E5%B8%82%E5%9C%BA%E5%9D%87%E8%A1%A1">3.4 市场均衡</a><ul><li><a href="#341-%E4%BE%9B%E7%BB%99%E8%BF%87%E5%89%A9">3.4.1 供给过剩</a></li><li><a href="#342-%E9%9C%80%E6%B1%82%E4%B8%8D%E8%B6%B3">3.4.2 需求不足</a></li><li><a href="#343-%E5%B8%82%E5%9C%BA%E5%9D%87%E8%A1%A1%E7%9A%84%E5%8F%98%E5%8C%96">3.4.3 市场均衡的变化</a></li><li><a href="#344-%E9%9C%80%E6%B1%82%E5%92%8C%E4%BE%9B%E7%BB%99%E7%9A%84%E5%8F%98%E5%8C%96">3.4.4 需求和供给的变化</a></li></ul></li></ul></li><li><a href="#%E7%AC%AC%E5%9B%9B%E7%AB%A0%E5%BC%B9%E6%80%A7">第四章：弹性</a><ul><li><a href="#41-%E5%BC%B9%E6%80%A7%E7%9A%84%E5%AE%9A%E4%B9%89">4.1 弹性的定义</a></li><li><a href="#42-%E9%9C%80%E6%B1%82%E7%9A%84%E4%BB%B7%E6%A0%BC%E5%BC%B9%E6%80%A7">4.2 需求的价格弹性</a><ul><li><a href="#422-%E8%AE%A1%E7%AE%97%E4%BB%B7%E6%A0%BC%E5%BC%B9%E6%80%A7">4.2.2 计算价格弹性</a></li><li><a href="#423-%E4%BB%B7%E6%A0%BC%E5%BC%B9%E6%80%A7%E7%9A%84%E5%88%86%E7%B1%BB">4.2.3 价格弹性的分类</a></li><li><a href="#424-%E9%9C%80%E6%B1%82%E4%BB%B7%E6%A0%BC%E5%BC%B9%E6%80%A7%E7%9A%84%E7%94%A8%E5%A4%84">4.2.4 需求价格弹性的用处</a></li><li><a href="#425-%E9%9C%80%E6%B1%82%E5%BC%B9%E6%80%A7%E5%92%8C%E6%80%BB%E6%94%B6%E5%85%A5">4.2.5 需求弹性和总收入</a></li></ul></li><li><a href="#43-%E4%BE%9B%E7%BB%99%E7%9A%84%E4%BB%B7%E6%A0%BC%E5%BC%B9%E6%80%A7">4.3 供给的价格弹性</a></li><li><a href="#44-%E9%9C%80%E6%B1%82%E7%9A%84%E4%BA%A4%E5%8F%89%E4%BB%B7%E6%A0%BC%E5%BC%B9%E6%80%A7">4.4 需求的交叉价格弹性</a></li><li><a href="#45-%E9%9C%80%E6%B1%82%E7%9A%84%E6%94%B6%E5%85%A5%E5%BC%B9%E6%80%A7">4.5 需求的收入弹性</a></li><li><a href="#46-%E5%9B%9B%E7%A7%8D%E5%BC%B9%E6%80%A7%E7%9A%84%E6%80%BB%E7%BB%93">4.6 四种弹性的总结</a></li></ul></li><li><a href="#%E7%AC%AC%E4%BA%94%E7%AB%A0%E6%95%88%E7%8E%87">第五章：效率</a><ul><li><a href="#51-%E6%94%AF%E4%BB%98%E5%92%8C%E9%94%80%E5%94%AE%E6%84%8F%E6%84%BF">5.1 支付和销售意愿</a></li><li><a href="#52-%E8%AE%A1%E7%AE%97%E8%BF%87%E5%89%A9">5.2 计算过剩</a><ul><li><a href="#521-%E8%AE%A1%E7%AE%97%E6%B6%88%E8%B4%B9%E8%80%85%E8%BF%87%E5%89%A9">5.2.1 计算消费者过剩</a></li><li><a href="#522-%E8%AE%A1%E7%AE%97%E7%94%9F%E4%BA%A7%E8%80%85%E8%BF%87%E5%89%A9">5.2.2 计算生产者过剩</a></li><li><a href="#523-%E8%AE%A1%E7%AE%97%E6%80%BB%E8%BF%87%E5%89%A9">5.2.3 计算总过剩</a></li></ul></li><li><a href="#53-%E5%B8%82%E5%9C%BA%E5%9D%87%E8%A1%A1%E5%92%8C%E6%95%88%E7%8E%87">5.3 市场均衡和效率</a></li><li><a href="#54-%E6%97%A0%E8%B0%93%E6%8D%9F%E5%A4%B1">5.4 无谓损失</a></li><li><a href="#55-%E4%B8%A2%E5%A4%B1%E7%9A%84%E5%B8%82%E5%9C%BA">5.5 丢失的市场</a></li></ul></li><li><a href="#%E7%AC%AC%E5%85%AD%E7%AB%A0%E6%94%BF%E5%BA%9C%E5%B9%B2%E9%A2%84">第六章：政府干预</a><ul><li><a href="#61-%E4%BB%B7%E6%A0%BC%E6%8E%A7%E5%88%B6">6.1 价格控制</a></li><li><a href="#62-%E4%BB%B7%E6%A0%BC%E4%B8%8A%E9%99%90">6.2 价格上限</a><ul><li><a href="#621-%E4%BB%B7%E6%A0%BC%E4%B8%8A%E9%99%90%E5%AF%B9%E7%A6%8F%E5%88%A9%E7%9A%84%E5%BD%B1%E5%93%8D">6.2.1 价格上限对福利的影响</a></li><li><a href="#622-%E9%9D%9E%E7%BA%A6%E6%9D%9F%E6%80%A7%E4%BB%B7%E6%A0%BC%E4%B8%8A%E9%99%90">6.2.2 非约束性价格上限</a></li></ul></li><li><a href="#63-%E4%BB%B7%E6%A0%BC%E4%B8%8B%E9%99%90">6.3 价格下限</a><ul><li><a href="#631-%E4%BB%B7%E6%A0%BC%E4%B8%8B%E9%99%90%E5%AF%B9%E7%A6%8F%E5%88%A9%E7%9A%84%E5%BD%B1%E5%93%8D">6.3.1 价格下限对福利的影响</a></li><li><a href="#632-%E6%97%A0%E6%95%88%E7%9A%84%E4%BB%B7%E6%A0%BC%E4%B8%8B%E9%99%90">6.3.2 无效的价格下限</a></li></ul></li><li><a href="#64-%E7%A8%8E%E6%94%B6%E5%92%8C%E8%A1%A5%E8%B4%B4">6.4 税收和补贴</a></li><li><a href="#65-%E7%A8%8E%E6%94%B6">6.5 税收</a><ul><li><a href="#651-%E5%8D%96%E6%96%B9%E7%BA%B3%E7%A8%8E%E7%9A%84%E5%BD%B1%E5%93%8D">6.5.1 卖方纳税的影响</a></li><li><a href="#652-%E4%B9%B0%E6%96%B9%E7%BA%B3%E7%A8%8E%E7%9A%84%E5%BD%B1%E5%93%8D">6.5.2 买方纳税的影响</a></li><li><a href="#653-%E7%A8%8E%E6%94%B6%E5%AF%B9%E4%B9%B0%E5%8D%96%E5%8F%8C%E6%96%B9%E7%9A%84%E5%BD%B1%E5%93%8D">6.5.3 税收对买卖双方的影响</a></li><li><a href="#654-%E7%A8%8E%E6%94%B6%E5%8F%91%E7%94%9F%E7%8E%87">6.5.4 税收发生率</a></li></ul></li><li><a href="#66-%E8%A1%A5%E8%B4%B4">6.6 补贴</a><ul><li><a href="#661-%E8%A1%A5%E8%B4%B4%E9%80%A0%E6%88%90%E7%9A%84%E6%8D%9F%E5%A4%B1">6.6.1 补贴造成的损失</a></li><li><a href="#662-%E6%94%BF%E5%BA%9C%E8%A1%A5%E8%B4%B4%E6%94%AF%E5%87%BA">6.6.2 政府补贴支出</a></li><li><a href="#663-%E8%A1%A5%E8%B4%B4%E5%B8%A6%E6%9D%A5%E7%9A%84%E6%B6%88%E8%B4%B9%E8%80%85%E7%94%9F%E4%BA%A7%E8%80%85%E8%BF%87%E5%89%A9">6.6.3 补贴带来的消费者 / 生产者过剩</a></li></ul></li><li><a href="#67-%E7%A8%8E%E6%94%B6%E6%88%96%E8%A1%A5%E8%B4%B4%E7%9A%84%E5%BD%B1%E5%93%8D">6.7 税收或补贴的影响</a></li><li><a href="#68-%E9%95%BF%E6%9C%9F%E5%BD%B1%E5%93%8D%E4%B8%8E%E7%9F%AD%E6%9C%9F%E5%BD%B1%E5%93%8D">6.8 长期影响与短期影响</a></li></ul></li><li><a href="#%E7%AC%AC%E4%B8%83%E7%AB%A0%E6%B6%88%E8%B4%B9%E8%80%85%E8%A1%8C%E4%B8%BA">第七章：消费者行为</a><ul><li><a href="#71-%E6%95%88%E7%94%A8%E5%9F%BA%E7%A1%80">7.1 效用基础</a><ul><li><a href="#711-%E6%95%88%E7%94%A8%E5%87%BD%E6%95%B0">7.1.1 效用函数</a></li><li><a href="#712-%E8%BE%B9%E9%99%85%E6%95%88%E7%94%A8">7.1.2 边际效用</a></li><li><a href="#713-%E6%95%88%E7%94%A8">7.1.3 效用</a></li><li><a href="#714-%E8%BE%B9%E9%99%85%E6%95%88%E7%94%A8%E9%80%92%E5%87%8F">7.1.4 边际效用递减</a></li></ul></li><li><a href="#72-%E5%B8%A6%E7%BA%A6%E6%9D%9F%E6%9D%A1%E4%BB%B6%E7%9A%84%E6%95%88%E7%94%A8%E6%9C%80%E5%A4%A7%E5%8C%96">7.2 带约束条件的效用最大化</a><ul><li><a href="#721-%E9%A2%84%E7%AE%97%E7%BA%A6%E6%9D%9F">7.2.1 预算约束</a></li><li><a href="#722-%E6%80%BB%E6%95%88%E7%94%A8%E6%9C%80%E5%A4%A7%E5%8C%96">7.2.2 总效用最大化</a></li><li><a href="#723-%E5%BA%94%E5%AF%B9%E6%94%B6%E5%85%A5%E5%8F%98%E5%8C%96">7.2.3 应对收入变化</a></li><li><a href="#724-%E5%BA%94%E5%AF%B9%E4%BB%B7%E6%A0%BC%E5%8F%98%E5%8C%96">7.2.4 应对价格变化</a></li></ul></li><li><a href="#73-%E6%95%88%E7%94%A8%E5%92%8C%E7%A4%BE%E4%BC%9A">7.3 效用和社会</a></li><li><a href="#74-%E6%95%88%E7%94%A8%E5%88%A9%E4%BB%96%E4%B8%BB%E4%B9%89%E5%92%8C%E4%BA%92%E6%83%A0">7.4 效用、利他主义和互惠</a></li></ul></li><li><a href="#%E7%AC%AC%E5%8D%81%E4%BA%8C%E7%AB%A0%E7%94%9F%E4%BA%A7%E6%88%90%E6%9C%AC">第十二章：生产成本</a><ul><li><a href="#121-%E6%94%B6%E5%85%A5%E6%88%90%E6%9C%AC%E5%92%8C%E5%88%A9%E6%B6%A6">12.1 收入、成本和利润</a><ul><li><a href="#1211-%E5%9B%BA%E5%AE%9A%E6%88%90%E6%9C%AC%E5%92%8C%E5%8F%AF%E5%8F%98%E6%88%90%E6%9C%AC">12.1.1 固定成本和可变成本</a></li><li><a href="#1212-%E6%98%BE%E6%80%A7%E5%92%8C%E9%9A%90%E6%80%A7%E6%88%90%E6%9C%AC">12.1.2 显性和隐性成本</a></li><li><a href="#1213-%E7%BB%8F%E6%B5%8E%E5%92%8C%E4%BC%9A%E8%AE%A1%E5%88%A9%E6%B6%A6">12.1.3 经济和会计利润</a></li></ul></li><li><a href="#122-%E6%80%BB%E4%BA%A7%E9%87%8F%E8%BE%B9%E9%99%85%E4%BA%A7%E5%93%81%E5%92%8C%E5%B9%B3%E5%9D%87%E4%BA%A7%E5%93%81">12.2 总产量、边际产品和平均产品</a><ul><li><a href="#1221-%E7%94%9F%E4%BA%A7%E5%87%BD%E6%95%B0">12.2.1 生产函数</a></li><li><a href="#1222-%E5%B9%B3%E5%9D%87%E5%92%8C%E8%BE%B9%E9%99%85%E4%BA%A7%E5%93%81">12.2.2 平均和边际产品</a></li></ul></li><li><a href="#123-%E7%94%9F%E4%BA%A7%E6%88%90%E6%9C%AC">12.3 生产成本</a><ul><li><a href="#1231-%E6%88%90%E6%9C%AC%E6%9B%B2%E7%BA%BF">12.3.1 成本曲线</a></li><li><a href="#1232-%E8%BE%B9%E9%99%85%E6%88%90%E6%9C%AC%E6%9B%B2%E7%BA%BF%E5%92%8C%E5%B9%B3%E5%9D%87%E6%88%90%E6%9C%AC%E6%9B%B2%E7%BA%BF">12.3.2 边际成本曲线和平均成本曲线</a></li></ul></li><li><a href="#124-%E9%95%BF%E6%9C%9F%E6%88%90%E6%9C%AC">12.4 长期成本</a></li><li><a href="#125-%E8%A7%84%E6%A8%A1%E6%8A%A5%E9%85%AC">12.5 规模报酬</a></li><li><a href="#126-%E9%95%BF%E6%9C%9F%E5%B9%B3%E5%9D%87%E6%80%BB%E6%88%90%E6%9C%AC">12.6 长期平均总成本</a></li></ul></li><li><a href="#%E7%AC%AC%E5%8D%81%E4%B8%89%E7%AB%A0%E5%AE%8C%E5%85%A8%E7%AB%9E%E4%BA%89">第十三章：完全竞争</a><ul><li><a href="#131-%E5%AE%8C%E5%85%A8%E7%AB%9E%E4%BA%89%E5%B8%82%E5%9C%BA">13.1 完全竞争市场</a><ul><li><a href="#1311-%E5%B8%82%E5%9C%BA%E5%8A%9B%E9%87%8F">13.1.1 市场力量</a></li><li><a href="#1312-%E5%AE%8C%E5%85%A8%E7%AB%9E%E4%BA%89%E5%B8%82%E5%9C%BA%E7%9A%84%E6%94%B6%E5%85%A5">13.1.2 完全竞争市场的收入</a></li></ul></li><li><a href="#132-%E5%88%A9%E6%B6%A6%E5%92%8C%E7%94%9F%E4%BA%A7%E5%86%B3%E7%AD%96">13.2 利润和生产决策</a><ul><li><a href="#1321-%E5%88%A9%E6%B6%A6">13.2.1 利润</a></li><li><a href="#1322-%E5%86%B3%E5%AE%9A%E4%BD%95%E6%97%B6%E6%93%8D%E4%BD%9C">13.2.2 决定何时操作</a></li><li><a href="#1323-%E7%9F%AD%E6%9C%9F%E4%BE%9B%E7%BB%99%E6%9B%B2%E7%BA%BF%E5%92%8C%E5%81%9C%E4%BA%A7%E8%A7%84%E5%88%99">13.2.3 短期供给曲线和停产规则</a></li><li><a href="#1324-%E9%95%BF%E6%9C%9F%E4%BE%9B%E7%BB%99%E6%9B%B2%E7%BA%BF%E5%92%8C%E5%81%9C%E4%BA%A7%E8%A7%84%E5%88%99">13.2.4 长期供给曲线和停产规则</a></li></ul></li><li><a href="#133-%E4%BC%81%E4%B8%9A%E5%92%8C%E5%B8%82%E5%9C%BA%E4%BE%9B%E5%BA%94%E6%9B%B2%E7%BA%BF">13.3 企业和市场供应曲线</a><ul><li><a href="#1331-%E9%95%BF%E6%9C%9F%E4%BE%9B%E5%BA%94">13.3.1 长期供应</a></li><li><a href="#1332-%E9%95%BF%E6%9C%9F%E7%BB%8F%E6%B5%8E%E5%88%A9%E6%B6%A6">13.3.2 长期经济利润</a></li><li><a href="#1333-%E5%9B%A0%E7%94%9F%E4%BA%A7%E6%88%90%E6%9C%AC%E5%8F%98%E5%8C%96%E8%80%8C%E8%BF%9B%E5%85%A5%E5%B8%82%E5%9C%BA">13.3.3 因生产成本变化而进入市场</a></li><li><a href="#1334-%E5%BA%94%E5%AF%B9%E9%9C%80%E6%B1%82%E7%9A%84%E5%8F%98%E5%8C%96">13.3.4 应对需求的变化</a></li></ul></li></ul></li><li><a href="#chapter-14-monopoly">Chapter 14: Monopoly</a><ul><li><a href="#141-monopolists-and-demand-curve">14.1 Monopolists and Demand Curve</a></li><li><a href="#142-monopoly-revenue">14.2 Monopoly Revenue</a></li><li><a href="#143-monopoly-profit-maximizing-quantity">14.3 Monopoly Profit-maximizing Quantity</a></li><li><a href="#144-problems-with-monopoly">14.4 Problems with Monopoly</a></li><li><a href="#145-comparing-market-characteristics">14.5 Comparing Market Characteristics</a></li></ul></li><li><a href="#chapter-17-international-trade">Chapter 17: International Trade</a><ul><li><a href="#171-roots-of-comparative-advantage">17.1 Roots of Comparative Advantage</a></li><li><a href="#172-from-autarky-to-free-trade">17.2 From Autarky to Free Trade</a><ul><li><a href="#1721-net-importer-or-net-exporter">17.2.1 Net-Importer or Net-Exporter</a></li><li><a href="#1722-big-economy-small-economy">17.2.2 Big Economy, Small Economy</a></li></ul></li><li><a href="#173-restrictions-on-trade">17.3 Restrictions on Trade</a></li><li><a href="#174-tariffs">17.4 Tariffs</a><ul><li><a href="#1741-domestic-welfare-effects-of-a-tariff">17.4.1 Domestic Welfare Effects of a Tariff</a></li></ul></li><li><a href="#175-quotas">17.5 Quotas</a></li><li><a href="#176-international-labor-and-capital">17.6 International Labor and Capital</a></li></ul></li></ul></details><center>-----</center><h1 id="第三章市场"><a class="markdownIt-Anchor" href="#第三章市场"></a> 第三章：市场</h1><h2 id="31-市场的定义"><a class="markdownIt-Anchor" href="#31-市场的定义"></a> 3.1 市场的定义</h2><p>市场是指买卖某种特定商品或服务的买家和卖家。</p><p>其中一种特殊的市场是竞争市场，它有以下特征：</p><ul><li>标准化商品 / Standardized goods</li><li>无成本交易 / No transaction costs</li><li>充分信息 / Full information</li><li>参与者是价格接受者 / Participants are price takers</li></ul><h2 id="32-市场需求"><a class="markdownIt-Anchor" href="#32-市场需求"></a> 3.2 市场需求</h2><p>消费者决定了市场需求，市场需求是所有消费者需求的总和。</p><p>需求量（Quantity demand）是指消费者愿意购买的某种商品的数量。</p><p>需求定律（Law of demand）：需求量随价格的上升而下降，随价格的下降而上升。</p><h4 id="321-需求表"><a class="markdownIt-Anchor" href="#321-需求表"></a> 3.2.1 需求表</h4><p>需求表（Demand schedule）：描述了在不同价格下，消费者愿意购买的商品数量。</p><p><img src="/posts/9e+71/Demand_Schedule.webp" alt="" loading="lazy"></p><h4 id="322-需求曲线"><a class="markdownIt-Anchor" href="#322-需求曲线"></a> 3.2.2 需求曲线</h4><p>需求曲线（Demand curve）：描述了在不同价格下，消费者愿意购买的商品数量。</p><p><img src="/posts/9e+71/Demand_Curve.webp" alt="" loading="lazy"></p><p>在需求曲线上，所有的其他非价格因素都保持不变。</p><h4 id="323-需求的变化"><a class="markdownIt-Anchor" href="#323-需求的变化"></a> 3.2.3 需求的变化</h4><p>五大非价格因素分别是：</p><ul><li>收入 / Income</li><li>相关商品的价格 / Price of related goods</li><li>消费者偏好 / Consumer preferences</li><li>买家数量 / Number of buyers</li><li>预期 / Expectations</li></ul><p>当这些非价格因素发生变化时：</p><ul><li>如果是正面变化，需求曲线向右移动，需求增加</li><li>如果是负面变化，需求曲线向左移动，需求减少</li></ul><h4 id="324-需求曲线的移动"><a class="markdownIt-Anchor" href="#324-需求曲线的移动"></a> 3.2.4 需求曲线的移动</h4><p>当需求增加时，需求曲线向右移动；当需求减少时，需求曲线向左移动。</p><p><img src="/posts/9e+71/Shifting_The_Demand_Curve.webp" alt="" loading="lazy"></p><h4 id="325-移动-vs-沿着曲线的移动"><a class="markdownIt-Anchor" href="#325-移动-vs-沿着曲线的移动"></a> 3.2.5 移动 vs. 沿着曲线的移动</h4><p>需求曲线的移动和沿着曲线的移动是不同的。</p><p>当非价格因素发生变化时，需求曲线会移动，而当价格发生变化时，需求曲线沿着曲线移动。</p><p><img src="/posts/9e+71/Shift_Versus_Movements_Demand.webp" alt="" loading="lazy"></p><h2 id="33-市场供给"><a class="markdownIt-Anchor" href="#33-市场供给"></a> 3.3 市场供给</h2><p>生产者决定了市场供给，市场供给是所有生产者供给的总和。</p><p>供给量（Quantity supplied）是指生产者愿意出售的某种商品的数量。</p><p>供给定律（Law of supply）：供给量随价格的上升而上升，随价格的下降而下降。</p><h4 id="331-供给表"><a class="markdownIt-Anchor" href="#331-供给表"></a> 3.3.1 供给表</h4><p>供给表（Supply schedule）：描述了在不同价格下，生产者愿意出售的商品数量。</p><h4 id="332-供给曲线"><a class="markdownIt-Anchor" href="#332-供给曲线"></a> 3.3.2 供给曲线</h4><p>供给曲线（Supply curve）：描述了在不同价格下，生产者愿意出售的商品数量。</p><p><img src="/posts/9e+71/Supply_Curve.webp" alt="" loading="lazy"></p><p>在供给曲线上，所有的其他非价格因素都保持不变。</p><h4 id="333-供给的变化"><a class="markdownIt-Anchor" href="#333-供给的变化"></a> 3.3.3 供给的变化</h4><p>五大非价格因素分别是：</p><ul><li>生产要素价格 / Prices of inputs</li><li>生产技术 / Technology</li><li>生产者的数量 / Number of producers</li><li>相关商品的价格 / Price of related goods</li><li>预期 / Expectations</li></ul><p>当这些非价格因素发生变化时：</p><ul><li>如果是正面变化，供给曲线向右移动，供给增加</li><li>如果是负面变化，供给曲线向左移动，供给减少</li></ul><h4 id="334-供给曲线的移动"><a class="markdownIt-Anchor" href="#334-供给曲线的移动"></a> 3.3.4 供给曲线的移动</h4><p>当供给增加时，供给曲线向右移动；当供给减少时，供给曲线向左移动。</p><h4 id="335-移动-vs-沿着曲线的移动"><a class="markdownIt-Anchor" href="#335-移动-vs-沿着曲线的移动"></a> 3.3.5 移动 vs. 沿着曲线的移动</h4><p>供给曲线的移动和沿着曲线的移动是不同的。</p><p>当非价格因素发生变化时，供给曲线会移动，而当价格发生变化时，供给曲线沿着曲线移动。</p><h2 id="34-市场均衡"><a class="markdownIt-Anchor" href="#34-市场均衡"></a> 3.4 市场均衡</h2><p>市场均衡（Market equilibrium）：市场需求和市场供给相等的价格。在市场均衡下，需求量等于供给量、消费者愿意购买的商品数量等于生产者愿意出售的商品数量。</p><p><img src="/posts/9e+71/Market_Equilibrium.webp" alt="" loading="lazy"></p><p>如果市场并不在均衡状态，那么需求量和供给量就不相等，价格就会发生变化，直到市场达到均衡状态。</p><p>假设价格高于均衡价格，那么就会发生供给过剩（Surplus）；假设价格低于均衡价格，那么就会发生需求不足（Shortage）。</p><h4 id="341-供给过剩"><a class="markdownIt-Anchor" href="#341-供给过剩"></a> 3.4.1 供给过剩</h4><p>供给过剩（Surplus）：价格高于均衡价格，供给量大于需求量。</p><p><img src="/posts/9e+71/Surplus.webp" alt="" loading="lazy"></p><p>当价格减少时，供给量减少，需求量增加。</p><p>价格会持续下降，直到 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mi>S</mi></msub><mo>=</mo><msub><mi>Q</mi><mi>D</mi></msub><mo>=</mo><msup><mi>Q</mi><mo>∗</mo></msup></mrow><annotation encoding="application/x-tex">Q_S=Q_D=Q^*</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.05764em;">S</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.02778em;">D</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8831359999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.688696em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mbin mtight">∗</span></span></span></span></span></span></span></span></span></span></span>。</p><h4 id="342-需求不足"><a class="markdownIt-Anchor" href="#342-需求不足"></a> 3.4.2 需求不足</h4><p>需求不足（Shortage）：价格低于均衡价格，需求量大于供给量。</p><p><img src="/posts/9e+71/Shortage.webp" alt="" loading="lazy"></p><p>当价格增加时，供给量增加，需求量减少。</p><p>价格会持续上升，直到 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>Q</mi><mi>S</mi></msub><mo>=</mo><msub><mi>Q</mi><mi>D</mi></msub><mo>=</mo><msup><mi>Q</mi><mo>∗</mo></msup></mrow><annotation encoding="application/x-tex">Q_S=Q_D=Q^*</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.05764em;">S</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8777699999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.02778em;">D</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8831359999999999em;vertical-align:-0.19444em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.688696em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mbin mtight">∗</span></span></span></span></span></span></span></span></span></span></span>。</p><h4 id="343-市场均衡的变化"><a class="markdownIt-Anchor" href="#343-市场均衡的变化"></a> 3.4.3 市场均衡的变化</h4><p>均衡价格和数量会随着需求和供给的变化而变化。</p><p>如果有一个非价格因素发生变化，那这就会影响到市场均衡。</p><h4 id="344-需求和供给的变化"><a class="markdownIt-Anchor" href="#344-需求和供给的变化"></a> 3.4.4 需求和供给的变化</h4><p>无论是需求还是供给发生变化，都会对均衡价格和数量产生明确的影响。</p><table><thead><tr><th>曲线</th><th>变化</th><th>价格变化</th><th>数量变化</th></tr></thead><tbody><tr><td>供给</td><td>减少</td><td>上升</td><td>下降</td></tr><tr><td>供给</td><td>增加</td><td>下降</td><td>上升</td></tr><tr><td>需求</td><td>减少</td><td>下降</td><td>下降</td></tr><tr><td>需求</td><td>增加</td><td>上升</td><td>上升</td></tr></tbody></table><p>非价格因素是有可能同时影响到需求和供给的：</p><ul><li>需求和供给同时变化、曲线移动</li><li>全新的均衡点会出现</li></ul><table><thead><tr><th>供给变化</th><th>需求变化</th><th>价格变化</th><th>数量变化</th></tr></thead><tbody><tr><td>减少</td><td>减少</td><td>？</td><td>下降</td></tr><tr><td>减少</td><td>增加</td><td>上升</td><td>？</td></tr><tr><td>增加</td><td>增加</td><td>？</td><td>上升</td></tr><tr><td>增加</td><td>减少</td><td>下降</td><td>？</td></tr></tbody></table><center>-------</center><h1 id="第四章弹性"><a class="markdownIt-Anchor" href="#第四章弹性"></a> 第四章：弹性</h1><h2 id="41-弹性的定义"><a class="markdownIt-Anchor" href="#41-弹性的定义"></a> 4.1 弹性的定义</h2><p>弹性（Elasticity）：描述了需求或供给对价格变化的敏感程度。</p><p>该概念衡量了对以下变化的响应：</p><ul><li>商品价格</li><li>相关商品的价格</li><li>收入</li></ul><h2 id="42-需求的价格弹性"><a class="markdownIt-Anchor" href="#42-需求的价格弹性"></a> 4.2 需求的价格弹性</h2><p>需求价格弹性（Price elasticity of demand）：需求对价格变化的敏感程度。</p><p>需求价格弹性介绍了需求量随价格的变化而变化的程度。</p><p>消费者对价格变化的敏感程度取决于：</p><ul><li>商品是否是必需品</li><li>商品是否有替代品</li><li>商品占消费者预算的比例</li><li>时间</li><li>市场范围</li></ul><h4 id="422-计算价格弹性"><a class="markdownIt-Anchor" href="#422-计算价格弹性"></a> 4.2.2 计算价格弹性</h4><p>中点法（Midpoint method）：计算价格弹性的方法。</p><p>中点弹性（Midpoint elasticity）：任意两个数的差除以它们的平均值。</p><h4 id="423-价格弹性的分类"><a class="markdownIt-Anchor" href="#423-价格弹性的分类"></a> 4.2.3 价格弹性的分类</h4><p>价格弹性的分类：</p><ul><li>弹性（Elastic）：价格的变化会导致需求量相对较大百分比的变化</li><li>非弹性（Inelastic）：价格的变化会导致需求量相对较小百分比的变化</li></ul><p>在极端情况下，需求可以是完全弹性（Perfectly elastic）或完全非弹性（Perfectly inelastic）。</p><p><img src="/posts/9e+71/Perfectly_Elastic_And_Perfectly_Inelastic.webp" alt="" loading="lazy"></p><p>在这两个极端情况之间，弹性还可以分为：</p><ul><li>弹性（Elastic）：价格弹性大于 1</li><li>单位弹性（Unit elastic）：价格弹性等于 1</li><li>非弹性（Inelastic）：价格弹性小于 1</li></ul><p><img src="/posts/9e+71/Other_Elasticities.webp" alt="" loading="lazy"></p><h4 id="424-需求价格弹性的用处"><a class="markdownIt-Anchor" href="#424-需求价格弹性的用处"></a> 4.2.4 需求价格弹性的用处</h4><p>在知道一个商品的需求是否是弹性的情况下，可以：</p><ul><li>允许管理者确定价格上涨是否会导致总收入（Total revenue）上升或下降</li><li>总收入是一家公司从销售商品和服务中获得的金额</li><li>总收入 = 价格 × 需求量</li></ul><p><img src="/posts/9e+71/Using_Price_Elasticity_Of_Demand.webp" alt="" loading="lazy"></p><p><img src="/posts/9e+71/Using_Price_Elasticity_Of_Demand_1.webp" alt="" loading="lazy"></p><h4 id="425-需求弹性和总收入"><a class="markdownIt-Anchor" href="#425-需求弹性和总收入"></a> 4.2.5 需求弹性和总收入</h4><p>需求弹性和总收入的关系：</p><p><img src="/posts/9e+71/Elasticity_Of_Demand_And_Total_Revenue.webp" alt="" loading="lazy"></p><h2 id="43-供给的价格弹性"><a class="markdownIt-Anchor" href="#43-供给的价格弹性"></a> 4.3 供给的价格弹性</h2><p>供给价格弹性（Price elasticity of supply）：供给对价格变化的敏感程度。</p><p>供给价格弹性永远是正数，因为供给量和价格总是正相关的。</p><p>生产者对价格变化的敏感程度取决于：</p><ul><li>生产者是否能够轻易地改变生产量</li><li>时间</li><li>生产要素的可用性</li></ul><h2 id="44-需求的交叉价格弹性"><a class="markdownIt-Anchor" href="#44-需求的交叉价格弹性"></a> 4.4 需求的交叉价格弹性</h2><p>需求交叉价格弹性（Cross-price elasticity of demand）：当一个商品的价格发生变化时，另一个商品的需求量发生变化的程度。</p><p>中点法可以计算商品 A 的需求量和商品 B 的价格之间的弹性：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>交叉价格弹性</mtext><mo> =</mo><mfrac><mtext> 商品&nbsp;A&nbsp;的需求量变化的百分比</mtext><mtext>商品&nbsp;B&nbsp;的价格变化的百分比</mtext></mfrac><mo> =</mo><mfrac><mrow><mo stretchy="false">(</mo><msub><mi>Q</mi><mrow><mi>A</mi><mn>2</mn></mrow></msub><mo>−</mo><msub><mi>Q</mi><mrow><mi>A</mi><mn>1</mn></mrow></msub><mo stretchy="false">)</mo><mi mathvariant="normal">/</mi><mo stretchy="false">[</mo><mo stretchy="false">(</mo><msub><mi>Q</mi><mrow><mi>A</mi><mn>2</mn></mrow></msub><mo>+</mo><msub><mi>Q</mi><mrow><mi>A</mi><mn>1</mn></mrow></msub><mo stretchy="false">)</mo><mi mathvariant="normal">/</mi><mn>2</mn><mo stretchy="false">]</mo></mrow><mrow><mo stretchy="false">(</mo><msub><mi>P</mi><mrow><mi>B</mi><mn>2</mn></mrow></msub><mo>−</mo><msub><mi>P</mi><mrow><mi>B</mi><mn>1</mn></mrow></msub><mo stretchy="false">)</mo><mi mathvariant="normal">/</mi><mo stretchy="false">[</mo><mo stretchy="false">(</mo><msub><mi>P</mi><mrow><mi>B</mi><mn>2</mn></mrow></msub><mo>+</mo><msub><mi>P</mi><mrow><mi>B</mi><mn>1</mn></mrow></msub><mo stretchy="false">)</mo><mi mathvariant="normal">/</mi><mn>2</mn><mo stretchy="false">]</mo></mrow></mfrac></mrow><annotation encoding="application/x-tex">\text {交叉价格弹性}=\frac {\text {商品 A 的需求量变化的百分比}}{\text {商品 B 的价格变化的百分比}}=\frac {(Q_{A2}-Q_{A1})/[(Q_{A2}+Q_{A1})/2]}{(P_{B2}-P_{B1})/[(P_{B2}+P_{B1})/2]}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">交叉价格弹性</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.04633em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.36033em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord cjk_fallback"> 商品</span><span class="mord">&nbsp;B&nbsp;</span><span class="mord cjk_fallback">的价格变化的百分比</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord cjk_fallback">商品</span><span class="mord">&nbsp;A&nbsp;</span><span class="mord cjk_fallback">的需求量变化的百分比</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.363em;vertical-align:-0.936em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.427em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05017em;">B</span><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05017em;">B</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord">/</span><span class="mopen">[</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05017em;">B</span><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.13889em;">P</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.13889em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight" style="margin-right:0.05017em;">B</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord">/</span><span class="mord">2</span><span class="mclose">]</span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">A</span><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">A</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord">/</span><span class="mopen">[</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">A</span><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mord"><span class="mord mathnormal">Q</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.32833099999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">A</span><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mclose">)</span><span class="mord">/</span><span class="mord">2</span><span class="mclose">]</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.936em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p>需求交叉价格弹性可以是正数或负数。如果大于 0，那么两个商品是替代品；如果小于 0，那么两个商品是互补品</p><p>需求收入弹性可以是正数或负数。如果大于 0，那么商品是正常品；如果大于 1，那么商品是奢侈品；如果小于 0，那么商品是劣等品。</p><h2 id="46-四种弹性的总结"><a class="markdownIt-Anchor" href="#46-四种弹性的总结"></a> 4.6 四种弹性的总结</h2><table><thead><tr><th>弹性</th><th>公式</th><th>负数</th><th>正数</th><th>更弹性</th><th>更不弹性</th></tr></thead><tbody><tr><td>需求价格弹性</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mtext>需求量百分比变化</mtext><mtext>价格百分比变化</mtext></mfrac></mrow><annotation encoding="application/x-tex"> \frac {\text {需求量百分比变化}}{\text {价格百分比变化}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.217331em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.872331em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord cjk_fallback mtight"> 价格百分比变化</span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord cjk_fallback mtight">需求量百分比变化</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></td><td>永远</td><td>从不</td><td>替代品和奢侈品</td><td>必需品和劣等品</td></tr><tr><td>供给价格弹性</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mtext>供给量百分比变化</mtext><mtext>价格百分比变化</mtext></mfrac></mrow><annotation encoding="application/x-tex"> \frac {\text {供给量百分比变化}}{\text {价格百分比变化}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.217331em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.872331em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord cjk_fallback mtight"> 价格百分比变化</span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord cjk_fallback mtight">供给量百分比变化</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></td><td>从不</td><td>永远</td><td>短期</td><td>长期</td></tr><tr><td>需求交叉价格弹性</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mtext>商品&nbsp;A&nbsp;的需求量百分比变化</mtext><mtext>商品&nbsp;B&nbsp;的价格百分比变化</mtext></mfrac></mrow><annotation encoding="application/x-tex"> \frac {\text {商品 A 的需求量百分比变化}}{\text {商品 B 的价格百分比变化}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.217331em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.872331em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord cjk_fallback mtight"> 商品</span><span class="mord mtight">&nbsp;B&nbsp;</span><span class="mord cjk_fallback mtight">的价格百分比变化</span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord cjk_fallback mtight">商品</span><span class="mord mtight">&nbsp;A&nbsp;</span><span class="mord cjk_fallback mtight">的需求量百分比变化</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></td><td>互补品</td><td>替代品</td><td>近乎完全的替代品以及强的互补品</td><td>无关商品</td></tr><tr><td>收入弹性</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mfrac><mtext>商品的需求量百分比变化</mtext><mtext>消费者的收入百分比变化</mtext></mfrac></mrow><annotation encoding="application/x-tex"> \frac {\text {商品的需求量百分比变化}}{\text {消费者的收入百分比变化}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.217331em;vertical-align:-0.345em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.872331em;"><span style="top:-2.6550000000000002em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord cjk_fallback mtight"> 消费者的收入百分比变化</span></span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.394em;"><span class="pstrut" style="height:3em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord text mtight"><span class="mord cjk_fallback mtight">商品的需求量百分比变化</span></span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.345em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></td><td>劣等品</td><td>正常品</td><td>奢侈品</td><td>必需品</td></tr></tbody></table><center>-------</center><h1 id="第五章效率"><a class="markdownIt-Anchor" href="#第五章效率"></a> 第五章：效率</h1><h2 id="51-支付和销售意愿"><a class="markdownIt-Anchor" href="#51-支付和销售意愿"></a> 5.1 支付和销售意愿</h2><p>消费者往往愿意支付比市场价格更高的价格，如果价格低于他们的最大支付意愿（Willingness to pay）。</p><p><img src="/posts/9e+71/Willingness_To_Pay_And_The_Demand_Curve.webp" alt="" loading="lazy"></p><p>生产者同样愿意以低于市场价的价格出售，如果价格高于他们的最小销售意愿（Willingness to sell）。</p><p><img src="/posts/9e+71/Willingness_To_Sell_And_The_Supply_Curve.webp" alt="" loading="lazy"></p><p>自愿交换能创造价值，并能使参与其中的每个人过得更好。</p><h2 id="52-计算过剩"><a class="markdownIt-Anchor" href="#52-计算过剩"></a> 5.2 计算过剩</h2><p>当消费者在低于市场价格的价格下购买商品时，就会发生消费者过剩。</p><ul><li>消费者过剩（Consumer surplus）：消费者从购买中获益的衡量标准。</li></ul><p>当生产者在高于市场价格的价格下销售商品时，就会发生生产者过剩。</p><ul><li>生产者过剩（Producer surplus）：生产者从销售中获益的衡量标准。</li></ul><p>过剩（Surplus）： 买家或卖家愿意交易的价格与实际价格之间的差异。</p><h4 id="521-计算消费者过剩"><a class="markdownIt-Anchor" href="#521-计算消费者过剩"></a> 5.2.1 计算消费者过剩</h4><p>消费者过剩可以通过求个人的消费者过剩的和来计算。</p><p><img src="/posts/9e+71/Consumer_Surplus.webp" alt="" loading="lazy"></p><h4 id="522-计算生产者过剩"><a class="markdownIt-Anchor" href="#522-计算生产者过剩"></a> 5.2.2 计算生产者过剩</h4><p>生产者过剩可以通过求个人的生产者过剩的和来计算。</p><p><img src="/posts/9e+71/Producer_Surplus.webp" alt="" loading="lazy"></p><h4 id="523-计算总过剩"><a class="markdownIt-Anchor" href="#523-计算总过剩"></a> 5.2.3 计算总过剩</h4><p>总过剩（Total surplus）：每个人从参与商品或服务交换中获得的综合利益。</p><p><img src="/posts/9e+71/Total_Surplus.webp" alt="" loading="lazy"></p><p><img src="/posts/9e+71/Total_Surplus_1.webp" alt="" loading="lazy"></p><h2 id="53-市场均衡和效率"><a class="markdownIt-Anchor" href="#53-市场均衡和效率"></a> 5.3 市场均衡和效率</h2><p>市场均衡是当总过剩最大化时的均衡。</p><p><img src="/posts/9e+71/Market_Equilibrium_And_Efficiency.webp" alt="" loading="lazy"></p><h2 id="54-无谓损失"><a class="markdownIt-Anchor" href="#54-无谓损失"></a> 5.4 无谓损失</h2><p>无谓损失（Deadweight loss）：当市场不在均衡状态时，会发生的损失。</p><p>无谓损失被定义为当商品的购买量和销售量低于市场均衡量时、会导致的总过剩损失。</p><p><img src="/posts/9e+71/Deadweight_Loss.webp" alt="" loading="lazy"></p><h2 id="55-丢失的市场"><a class="markdownIt-Anchor" href="#55-丢失的市场"></a> 5.5 丢失的市场</h2><p>当潜在买家和卖家想要进行的一些交易没有发生时，市场就会丢失。</p><p>这会因为以下原因发生：</p><ul><li>公共政策</li><li>税收</li><li>准确信息或沟通的缺乏</li><li>促进交换的技术的缺乏</li></ul><center>-----</center><h1 id="第六章政府干预"><a class="markdownIt-Anchor" href="#第六章政府干预"></a> 第六章：政府干预</h1><h2 id="61-价格控制"><a class="markdownIt-Anchor" href="#61-价格控制"></a> 6.1 价格控制</h2><p>价格控制（Price control）：政府对价格的干预。</p><p>价格控制可以被划分为两种类型：</p><ul><li>价格上限</li><li>价格下限</li></ul><h2 id="62-价格上限"><a class="markdownIt-Anchor" href="#62-价格上限"></a> 6.2 价格上限</h2><p>价格上限（Price ceiling）：政府规定的商品的最高价格。</p><p>假设价格上限低于市场均衡价格，那么就会发生供给不足。</p><p><img src="/posts/9e+71/Price_Ceiling.webp" alt="" loading="lazy"></p><h4 id="621-价格上限对福利的影响"><a class="markdownIt-Anchor" href="#621-价格上限对福利的影响"></a> 6.2.1 价格上限对福利的影响</h4><p>价格上限会造成死重损失，并将生产者的福利转移给消费者。</p><p><img src="/posts/9e+71/Welfare_Effects_Of_A_Price_Ceiling.webp" alt="" loading="lazy"></p><p>因为价格上限会导致供给不足，所以政府会采取以下措施：</p><ul><li>平等分配商品</li><li>先到先得</li><li>分配给政府优先考虑的人或者卖方的亲朋好友</li></ul><p>短缺会导致人们采取寻租行为（Rent-seeking），例如贿赂分配商品的人。</p><h4 id="622-非约束性价格上限"><a class="markdownIt-Anchor" href="#622-非约束性价格上限"></a> 6.2.2 非约束性价格上限</h4><p>价格上限不一定会导致供给不足。有时候，价格上限会高于市场均衡价格。</p><h2 id="63-价格下限"><a class="markdownIt-Anchor" href="#63-价格下限"></a> 6.3 价格下限</h2><p>价格下限（Price floor）：政府规定的商品的最低价格。</p><p>假设价格下限高于市场均衡价格，那么就会发生供给过剩。</p><h4 id="631-价格下限对福利的影响"><a class="markdownIt-Anchor" href="#631-价格下限对福利的影响"></a> 6.3.1 价格下限对福利的影响</h4><p>价格下限会造成死重损失，并将消费者的福利转移给生产者。</p><p><img src="/posts/9e+71/Welfare_Effects_Of_A_Price_Floor.webp" alt="" loading="lazy"></p><h4 id="632-无效的价格下限"><a class="markdownIt-Anchor" href="#632-无效的价格下限"></a> 6.3.2 无效的价格下限</h4><p>价格下限不一定会导致供给过剩。有时候，价格下限会低于市场均衡价格。</p><h2 id="64-税收和补贴"><a class="markdownIt-Anchor" href="#64-税收和补贴"></a> 6.4 税收和补贴</h2><p>税收（Taxes）：政府对商品或服务的销售征收的费用。</p><p>补贴（Subsidies）：政府对商品或服务的销售提供的补助。</p><p>税收和补贴可用于纠正市场失灵，并提供激励或抑制措施，使生产量高于或低于均衡生产量。</p><h2 id="65-税收"><a class="markdownIt-Anchor" href="#65-税收"></a> 6.5 税收</h2><p>税收有着两大影响：</p><ul><li>抑制被征税商品的生产和消费</li><li>通过继续买卖商品者支付的费用增加政府收入</li></ul><p>征税将减少消费，提供新的公共收入来源。</p><h4 id="651-卖方纳税的影响"><a class="markdownIt-Anchor" href="#651-卖方纳税的影响"></a> 6.5.1 卖方纳税的影响</h4><p>假设政府对每售出一个单位征收 0.20 美元的税，卖方必须支付。这会对市场产生什么影响？</p><p><img src="/posts/9e+71/Effects_Of_A_Tax_Paid_By_The_Seller.webp" alt="" loading="lazy"></p><ul><li>新的供给曲线会在所有价格上增加 0.20 美元，即税额</li><li>税收在买方价格和卖方价格之间制造了一个楔子</li><li>均衡数量从 3000 万减少到 2500 万</li></ul><p>可以计算出对卖方征税的税收收入和无谓损失：</p><p><img src="/posts/9e+71/Effects_Of_A_Tax_Paid_By_The_Seller_1.webp" alt="" loading="lazy"></p><ul><li>产生的税收为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>税收收入</mtext><mo> =</mo><mtext> 税收</mtext><mo> ×</mo><mtext> 数量</mtext></mrow><annotation encoding="application/x-tex"> \text {税收收入}=\text {税收} \times \text {数量}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 税收收入</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord cjk_fallback"> 税收</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin"> ×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 数量</span></span></span></span></span></li><li>税收收入是消费者和生产者向政府的转移</li><li>无谓损失来自销售数量的损失</li></ul><h4 id="652-买方纳税的影响"><a class="markdownIt-Anchor" href="#652-买方纳税的影响"></a> 6.5.2 买方纳税的影响</h4><p>假设政府对售出的每件产品征收 0.20 美元的税，买方必须支付。这会对市场产生什么影响？</p><p><img src="/posts/9e+71/Effects_Of_A_Tax_Paid_By_The_Buyer.webp" alt="" loading="lazy"></p><ul><li>新的需求曲线降低了 0.20 美元，也就是税额</li><li>税收在买方价格和卖方价格之间制造楔子</li><li>均衡数量从 3000 万减少到 2500 万</li></ul><h4 id="653-税收对买卖双方的影响"><a class="markdownIt-Anchor" href="#653-税收对买卖双方的影响"></a> 6.5.3 税收对买卖双方的影响</h4><p>无论对买方还是卖方征税，税收都会产生四种相同的影响：</p><ul><li>均衡数量减少</li><li>买方为每个购买单位支付更多，而卖方获得更少<ul><li>税楔（Tax wedge）形成，相当于买方支付的价格与卖方收到的价格之间的差额</li></ul></li><li>政府获得的收入等于税额乘以新的均衡数量</li><li>税收造成无谓损失</li></ul><h4 id="654-税收发生率"><a class="markdownIt-Anchor" href="#654-税收发生率"></a> 6.5.4 税收发生率</h4><p>假设政府对售出的每件产品征收 0.20 美元的税，卖方必须支付。谁来承担税收负担或税收发生率？</p><ul><li>税收发生率（Tax incidence）等于消费者和生产者盈余中用于税收的损失</li><li>哪一方市场的价格弹性更大，哪一方就会承担更少的负担</li></ul><p><img src="/posts/9e+71/Tax_Incidence.webp" alt="" loading="lazy"></p><h2 id="66-补贴"><a class="markdownIt-Anchor" href="#66-补贴"></a> 6.6 补贴</h2><p>补贴有着两大主要影响：</p><ul><li>鼓励受补贴物品的生产和消费</li><li>政府通过补贴向继续销售商品的生产者提供资金</li></ul><p>补贴会增加商品的消费。</p><h4 id="661-补贴造成的损失"><a class="markdownIt-Anchor" href="#661-补贴造成的损失"></a> 6.6.1 补贴造成的损失</h4><p>假设政府对每售出一件产品补贴 0.35 美元，卖方也获得了补贴。这会对市场产生什么影响？</p><p><img src="/posts/9e+71/Deadweight_Loss_From_Subsidy.webp" alt="" loading="lazy"></p><ul><li>补贴导致生产过剩</li><li>生产过剩造成福利损失</li><li>按无谓损失计算</li></ul><h4 id="662-政府补贴支出"><a class="markdownIt-Anchor" href="#662-政府补贴支出"></a> 6.6.2 政府补贴支出</h4><p>对卖方征税造成的自重损失可计算如下：</p><p><img src="/posts/9e+71/Government_Expenditures_From_Subsidy.webp" alt="" loading="lazy"></p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>政府补贴支出</mtext><mo> =</mo><mtext> 补贴</mtext><mo> ×</mo><mtext> 数量</mtext></mrow><annotation encoding="application/x-tex"> \text {政府补贴支出}=\text {补贴} \times \text {数量}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">政府补贴支出</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord cjk_fallback"> 补贴</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin"> ×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 数量</span></span></span></span></span></span></p><h4 id="663-补贴带来的消费者生产者过剩"><a class="markdownIt-Anchor" href="#663-补贴带来的消费者生产者过剩"></a> 6.6.3 补贴带来的消费者 / 生产者过剩</h4><p>消费者和生产者过剩都会增加，但不足以抵消补贴成本和无谓损失。</p><p><img src="/posts/9e+71/Changes_In_CS_And_PS_From_Subsidy.webp" alt="" loading="lazy"></p><h2 id="67-税收或补贴的影响"><a class="markdownIt-Anchor" href="#67-税收或补贴的影响"></a> 6.7 税收或补贴的影响</h2><p>能否提前预测税收或补贴对均衡数量的影响？答案是可以的，只要供求的价格弹性已知。</p><h2 id="68-长期影响与短期影响"><a class="markdownIt-Anchor" href="#68-长期影响与短期影响"></a> 6.8 长期影响与短期影响</h2><p>政府的税收和补贴政策会对市场产生长期影响和短期影响。</p><p>汽油和其价格控制就是一个例子。</p><p><img src="/posts/9e+71/Long_Run_Versus_Short_Run_Impact.webp" alt="" loading="lazy"></p><blockquote><p>在短期内，驾驶习惯很难改变，生产商需要时间来提高产量，因此对数量的影响很小</p><p>而从长远来看，驾驶习惯可以改变，生产者可以提高产量。 因此对数量的影响很大。</p></blockquote><p>由于买方和卖方需要时间对价格变化做出反应，有时价格控制的全部效果只有在长期内才能显现出来。</p><center>-----</center><h1 id="第七章消费者行为"><a class="markdownIt-Anchor" href="#第七章消费者行为"></a> 第七章：消费者行为</h1><h2 id="71-效用基础"><a class="markdownIt-Anchor" href="#71-效用基础"></a> 7.1 效用基础</h2><p>效用（Utility）：消费者从消费中获得的满足程度。</p><p>理性个体在做出选择时会让效用最大化。例如，如果在接下来的一个小时里踢足球比打棒球产生的效用更大，那么理性的人会选择去踢足球。</p><h4 id="711-效用函数"><a class="markdownIt-Anchor" href="#711-效用函数"></a> 7.1.1 效用函数</h4><p>效用是难以衡量的。但是，可以通过观察消费者的选择来揭示他们的喜好。</p><p>然而，揭示喜好原则在分析他人会如何作出选择时并不总是有效。相反，需要一种更正式的方法。</p><p>效用函数（Utility functions）有助于系统分析选择。它用于计算某个人从消费某种商品和服务组合中获得的总效用。</p><p>效用函数会量化偏好，效用测量是相对的而不是绝对的。例如，假设莎拉每吃一份奶酪通心粉就会得到 3 个效用值，西兰花得到 2 个效用值，冰淇淋得到 8 个效用值，那么如果她吃了一份通心粉、两份西兰花和两份冰淇淋，她的总效用就是 23。</p><h4 id="712-边际效用"><a class="markdownIt-Anchor" href="#712-边际效用"></a> 7.1.2 边际效用</h4><p>边际效用（Marginal utility）：消费一件商品或服务会增加的效用。</p><p>当个人继续从事某项活动或消费更多某种商品或服务时，下一个单位的效用将会不如上一个单位的大。</p><p>边际效用递减（Diminish marginal utility）原理：连续消费一个单位的商品或服务所获得的额外效用，往往小于消费前一个单位或服务所获得的效用。</p><h4 id="713-效用"><a class="markdownIt-Anchor" href="#713-效用"></a> 7.1.3 效用</h4><p>每多消费一个单位的商品所带来的效用可以用一个数字来表示。</p><p><img src="/posts/9e+71/Utility.webp" alt="" loading="lazy"></p><ul><li>在吃完第 8 勺冰淇淋之前，每增加一勺冰淇淋都能提供效用</li><li>在吃第 8 勺时，边际效用转为负值</li><li>总效用是该勺之前的边际效用之和</li></ul><h4 id="714-边际效用递减"><a class="markdownIt-Anchor" href="#714-边际效用递减"></a> 7.1.4 边际效用递减</h4><p>可以绘制出效用函数和边际效用。当总效用最大或边际效用为零时，个人的效用最大化。</p><p><img src="/posts/9e+71/Diminishing_Marginal_Utility.webp" alt="" loading="lazy"></p><h2 id="72-带约束条件的效用最大化"><a class="markdownIt-Anchor" href="#72-带约束条件的效用最大化"></a> 7.2 带约束条件的效用最大化</h2><p>人们有很多需求，但会受到时间和金钱的限制。理性的个体在这些约束条件下通过将资源用于产生最高可能总效用的组合来实现效用最大化。</p><p>预算约束（Budget constraint）提供了消费者在收入一定的情况下可以购买的商品和服务的所有可能组合。</p><h4 id="721-预算约束"><a class="markdownIt-Anchor" href="#721-预算约束"></a> 7.2.1 预算约束</h4><p>以电影票价 15 美元、音乐会票价 30 美元和收入 120 美元来显示两种商品的预算约束。</p><p><img src="/posts/9e+71/The_Budget_Constraint.webp" alt="" loading="lazy"></p><ul><li>A 点：所有收入都花在电影上（8 张电影票）</li><li>B 点：收入用于购买两种商品（4 张电影票和 2 张音乐会门票）</li><li>C 点：用于音乐会的所有收入（4 张音乐会门票）</li></ul><h4 id="722-总效用最大化"><a class="markdownIt-Anchor" href="#722-总效用最大化"></a> 7.2.2 总效用最大化</h4><p>以下是消费一定数量的音乐会和电影票所产生的相关效用：</p><p><img src="/posts/9e+71/Maximizing_Total_Utility.webp" alt="" loading="lazy"></p><p>为了使总效用最大化，需要确定每个可行捆绑的总效用，然后相互比较。</p><p><img src="/posts/9e+71/Maximizing_Total_Utility_1.webp" alt="" loading="lazy"></p><ul><li>包含 1 张音乐会门票和 6 张电影票的捆绑包 B 的总效用最高，是首选捆绑包</li><li>在此预算下，理性的消费者会将所有收入用于购买电影票和音乐会门票的组合，从而使效用最大化</li></ul><h4 id="723-应对收入变化"><a class="markdownIt-Anchor" href="#723-应对收入变化"></a> 7.2.3 应对收入变化</h4><p>当一个人的收入增加时，就会有更多的商品和服务可以负担得起。自然，当收入减少时，能买得起的捆绑商品就会减少，消费者就有可能需要不得不减少某些商品的消费。</p><p>收入变化表现为整个预算线向外移动。</p><p>假设某人的收入从 120 美元增至 180 美元。</p><p><img src="/posts/9e+71/The_Effect_Of_An_Increase_In_Income.webp" alt="" loading="lazy"></p><ul><li>收入增加使个人能够购买更多商品</li><li>整条预算线向外转移</li></ul><h4 id="724-应对价格变化"><a class="markdownIt-Anchor" href="#724-应对价格变化"></a> 7.2.4 应对价格变化</h4><p>当价格发生变化时，个人的预算约束会受到两方面的影响：</p><ul><li>由于价格下降导致有效财富增加、消费发生变化，从而产生收入效应（Income effect）</li><li>替代效应（Substitution effect）是指商品相对价格的变化导致的消费变化<ul><li>消费某种商品的机会成本随价格变化而变化</li></ul></li></ul><p>假设电影票的价格从 15 美元降至 10 美元。</p><p><img src="/posts/9e+71/The_Effect_Of_A_Price_Change.webp" alt="" loading="lazy"></p><ul><li>当一种商品的价格发生变化时，预算约束向外旋转</li><li>新的预算线展示了现在可用的新捆绑包</li><li>预算线斜率的变化反映了两种商品相对价格的变化</li></ul><h2 id="73-效用和社会"><a class="markdownIt-Anchor" href="#73-效用和社会"></a> 7.3 效用和社会</h2><p>人们从各种来源获得效用：</p><ul><li>外部感知：他人对你购物的看法、他人有多少……</li><li>内部偏好：你喜欢如何花钱……</li></ul><p>外部感知和内部偏好都有助于决策。</p><h2 id="74-效用-利他主义和互惠"><a class="markdownIt-Anchor" href="#74-效用-利他主义和互惠"></a> 7.4 效用、利他主义和互惠</h2><p>效用最大化包括个人给予他人。利他主义（Altruism）是一种行动动机，在这种动机下，一个人的效用增加，仅仅是因为其他人的效用增加了。</p><blockquote><p>利他和自私或注重形象的动机完全可以共存。</p></blockquote><p>效用最大化建议人们通过惩罚不良行为和奖励良好行为来获得效用。</p><ul><li>互惠（Reciprocity）是以类似的行动回应他人的行动</li></ul><center>-----</center><h1 id="第十二章生产成本"><a class="markdownIt-Anchor" href="#第十二章生产成本"></a> 第十二章：生产成本</h1><h2 id="121-收入-成本和利润"><a class="markdownIt-Anchor" href="#121-收入-成本和利润"></a> 12.1 收入、成本和利润</h2><p>一所公司的目标是实现利润最大化：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>利润</mtext><mo> =</mo><mtext> 总收入</mtext><mo>−</mo><mtext>总成本</mtext></mrow><annotation encoding="application/x-tex"> \text {利润} = \text {总收入} - \text {总成本}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">利润</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord cjk_fallback"> 总收入</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">总成本</span></span></span></span></span></span></p><ul><li><p>总收入（Total revenue）是企业从销售商品和服务中获得的金额，计算方法是销售数量乘以为每个单位支付的价格：</p><ul><li><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>总收入</mtext><mo> =</mo><mtext> 价格</mtext><mo> ×</mo><mtext> 销售数量</mtext></mrow><annotation encoding="application/x-tex"> \text {总收入} = \text {价格} \times \text {销售数量}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">总收入</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord cjk_fallback"> 价格</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin"> ×</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 销售数量</span></span></span></span></span></span></p></li></ul></li><li><p>总成本（Total cost）是企业为生产商品或服务所投入的成本</p></li></ul><p>总收入的计算很简单，而成本则更为复杂和难以计算。</p><h4 id="1211-固定成本和可变成本"><a class="markdownIt-Anchor" href="#1211-固定成本和可变成本"></a> 12.1.1 固定成本和可变成本</h4><p>企业的总成本定义为：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>总成本</mtext><mo> =</mo><mtext> 固定成本</mtext><mo> +</mo><mtext> 可变成本</mtext></mrow><annotation encoding="application/x-tex"> \text {总成本} = \text {固定成本} + \text {可变成本}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">总成本</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord cjk_fallback"> 固定成本</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin"> +</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 可变成本</span></span></span></span></span></span></p><p>固定成本（Fixed costs）是不取决于产出数量的成本。</p><ul><li>生产开始前的一次性预付款，如购买设备</li></ul><p>可变成本（Variable costs）是指取决于产出数量的成本。</p><ul><li>包括原材料和劳动力成本</li></ul><h4 id="1212-显性和隐性成本"><a class="markdownIt-Anchor" href="#1212-显性和隐性成本"></a> 12.1.2 显性和隐性成本</h4><p>企业经营的机会成本由两部分组成：</p><ul><li>显性成本（Explicit costs）是企业为生产商品或服务而支付的现金支出，由固定成本和可变成本组成</li><li>隐形成本（Implicit costs）是企业为生产商品或服务而支付的非现金支出</li></ul><h4 id="1213-经济和会计利润"><a class="markdownIt-Anchor" href="#1213-经济和会计利润"></a> 12.1.3 经济和会计利润</h4><p>公司报告利润时，提供的是会计利润（Accounting profits）：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>会计利润</mtext><mo> =</mo><mtext> 总收入</mtext><mo>−</mo><mtext>显性成本</mtext></mrow><annotation encoding="application/x-tex"> \text {会计利润} = \text {总收入} - \text {显性成本}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">会计利润</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord cjk_fallback"> 总收入</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">显性成本</span></span></span></span></span></span></p><p>会计利润可能会误导企业的真实经营状况。</p><p>为了考虑隐性成本，经济利润（Economic profit）进一步减去了隐性成本：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>经济利润</mtext><mo> =</mo><mtext> 会计利润</mtext><mo>−</mo><mtext>隐性成本</mtext></mrow><annotation encoding="application/x-tex"> \text {经济利润} = \text {会计利润} - \text {隐性成本}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">经济利润</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord cjk_fallback"> 会计利润</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">隐性成本</span></span></span></span></span></span></p><h2 id="122-总产量-边际产品和平均产品"><a class="markdownIt-Anchor" href="#122-总产量-边际产品和平均产品"></a> 12.2 总产量、边际产品和平均产品</h2><p>企业创造价值的方式是将不同的成分组合在一起，创造出消费者需要的商品或服务。</p><p>生产函数（Production function）：投入量与产出量之间的关系。</p><p>边际产品（Marginal product）：增加一单位投入量所产生的额外产出。</p><ul><li>边际产品递减（Diminishing marginal product）原理指出，投入品的边际产品随着投入品数量的增加而减少</li></ul><p>平均产品是总产量除以工人人数。</p><h4 id="1221-生产函数"><a class="markdownIt-Anchor" href="#1221-生产函数"></a> 12.2.1 生产函数</h4><p>生产函数可以直观地表示出来。同时，边际产品是总产量曲线的斜率。</p><p><img src="/posts/9e+71/Production_Function.webp" alt="" loading="lazy"></p><ul><li>当产出很低时，每个新增工人的边际产品都高于前一个工人</li><li>随着工人的增加，边际产品开始减少</li></ul><h4 id="1222-平均和边际产品"><a class="markdownIt-Anchor" href="#1222-平均和边际产品"></a> 12.2.2 平均和边际产品</h4><p>边际产品递减原则和平均产品递减原则都可以直观地表示出来。这会确定边际产品和平均产品之间的关系。</p><p><img src="/posts/9e+71/Average_And_Marginal_Product.webp" alt="" loading="lazy"></p><ul><li>当新增工人的边际产品大于现有平均产品时，平均产品就会增加</li><li>当边际产品曲线与平均产品曲线交叉时，平均产品也开始减少</li><li>当新增工人的边际产品少于现有平均产品时，平均产品就会减少</li></ul><h2 id="123-生产成本"><a class="markdownIt-Anchor" href="#123-生产成本"></a> 12.3 生产成本</h2><p>当企业通过调整投入品的使用来增加产出时，就会产生与这一决策相关的成本。</p><p>产出与成本之间的关系是：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>平均固定成本</mtext><mo> =</mo><mfrac><mtext> 固定成本</mtext><mtext>产出</mtext></mfrac></mrow><annotation encoding="application/x-tex"> \text {平均固定成本} = \frac {\text {固定成本}}{\text {产出}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">平均固定成本</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.04633em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.36033em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord cjk_fallback"> 产出</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord cjk_fallback">固定成本</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>平均可变成本</mtext><mo> =</mo><mfrac><mtext> 可变成本</mtext><mtext>产出</mtext></mfrac></mrow><annotation encoding="application/x-tex"> \text {平均可变成本} = \frac {\text {可变成本}}{\text {产出}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">平均可变成本</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.04633em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.36033em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord cjk_fallback"> 产出</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord cjk_fallback">可变成本</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>平均总成本</mtext><mo> =</mo><mtext> 平均固定成本</mtext><mo> +</mo><mtext> 平均可变成本</mtext></mrow><annotation encoding="application/x-tex"> \text {平均总成本} = \text {平均固定成本} + \text {平均可变成本}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">平均总成本</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord cjk_fallback"> 平均固定成本</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin"> +</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 平均可变成本</span></span></span></span></span></span></p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>边际成本</mtext><mo> =</mo><mfrac><mtext> 变化的总成本</mtext><mtext>变化的产出</mtext></mfrac></mrow><annotation encoding="application/x-tex"> \text {边际成本} = \frac {\text {变化的总成本}}{\text {变化的产出}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">边际成本</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.04633em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.36033em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord cjk_fallback"> 变化的产出</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord cjk_fallback">变化的总成本</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p>下表提供了一家披萨店的生产情况和成本，该披萨店需要租赁 300 美元的店面， 工人工资为每人 200 美元。</p><p><img src="/posts/9e+71/Costs_Of_Production.webp" alt="" loading="lazy"></p><h4 id="1231-成本曲线"><a class="markdownIt-Anchor" href="#1231-成本曲线"></a> 12.3.1 成本曲线</h4><p>成本函数可以直观表示：</p><p><img src="/posts/9e+71/Cost_Curves.webp" alt="" loading="lazy"></p><ul><li>可变成本（VC）曲线最初变得不那么陡峭，反映出前几名员工的边际产品不断增加</li><li>由于边际产品递减原则的作用，可变成本曲线逐渐变得陡峭</li></ul><p>平均成本也可以直观地表现出来：</p><p><img src="/posts/9e+71/Cost_Curves_1.webp" alt="" loading="lazy"></p><ul><li><p>平均固定成本（AFC）呈下降趋势</p><ul><li>相同成本分摊到更多产出单位</li></ul></li><li><p>平均可变成本（AVC）呈 U 型</p><ul><li>先减后增，反映投入的边际产品</li></ul></li><li><p>平均总成本（ATC）曲线呈 U 形</p><ul><li>平均固定成本下降，平均可变成本上升</li></ul></li></ul><p>边际成本也可以直观地表示出来：</p><p><img src="/posts/9e+71/Cost_Curves_2.webp" alt="" loading="lazy"></p><ul><li>边际成本（MC）曲线呈 U 型，是边际产品曲线的反形状<ul><li>每增加一个投入单位，无论其对生产的贡献如何，成本都是一样的</li><li>随着劳动边际产品最初的增加，边际成本会下降</li><li>随着边际产品的减少，边际成本也会增加</li></ul></li></ul><h4 id="1232-边际成本曲线和平均成本曲线"><a class="markdownIt-Anchor" href="#1232-边际成本曲线和平均成本曲线"></a> 12.3.2 边际成本曲线和平均成本曲线</h4><p>边际成本和平均总成本之间的关系可以直观地建立起来：</p><p><img src="/posts/9e+71/Marginal_And_Average_Cost_Curves.webp" alt="" loading="lazy"></p><ul><li>当生产另一个单位的边际成本小于平均总成本时，多生产一个单位都会减少平均总成本</li><li>当生产另一个单位的边际成本高于平均总成本时，多生产一个单位将增加平均总成本</li><li>边际成本曲线在最低点与平均总成本曲线相交</li></ul><h2 id="124-长期成本"><a class="markdownIt-Anchor" href="#124-长期成本"></a> 12.4 长期成本</h2><p>长期成本（Long-run costs）是企业在所有投入品都是可变的情况下的成本。例如，可以调整工厂尺寸以增加或减少产能。</p><blockquote><p>在短期内，固定投入无法调整。</p></blockquote><p>当企业调整其中一项长期成本时，整个固定成本曲线都会移动，因为企业的效率更高，可以生产更高的产出。</p><h2 id="125-规模报酬"><a class="markdownIt-Anchor" href="#125-规模报酬"></a> 12.5 规模报酬</h2><p>成本与产出之间的关系取决于生产规模。</p><p>如果扩大生产规模以获得更高的产量，可以降低平均总成本的最低值，那么就会产生规模经济（Economies of scale）。</p><p>如果扩大生产规模以获得更高的产量，会提高平均总成本的最低值，那么就会出现规模不经济（Diseconomies of scale）。</p><p>当平均总成本的最小值不取决于产出量时，规模收益不变（Constant returns to scale）。</p><ul><li>当平均总成本达到最小值时，就实现了有效规模（Efficient scale）</li></ul><h2 id="126-长期平均总成本"><a class="markdownIt-Anchor" href="#126-长期平均总成本"></a> 12.6 长期平均总成本</h2><p>长期平均总成本曲线由所有可能的短期平均总成本曲线组合而成，而短期平均总成本曲线由更改生产规模而产生。</p><p><img src="/posts/9e+71/Long_Run_ATC.webp" alt="" loading="lazy"></p><ul><li>不同规模的企业会面临的短期平均总成本</li><li>通过扩大或缩小生产规模，企业可以沿着长期平均总成本曲线从一条短期平均总成本曲线移动到另一条短期平均总成本曲线</li></ul><center>-----</center><h1 id="第十三章完全竞争"><a class="markdownIt-Anchor" href="#第十三章完全竞争"></a> 第十三章：完全竞争</h1><h2 id="131-完全竞争市场"><a class="markdownIt-Anchor" href="#131-完全竞争市场"></a> 13.1 完全竞争市场</h2><p>The characteristics of a perfectly competitve market:</p><p>完全竞争市场（Perfectly competitive market）：市场中有许多买家和卖家，每个人都是价格接受者（price taker）。</p><p>完全竞争市场的特征：</p><ul><li>买方和卖方都是价格接受者</li><li>商品是标准化的</li><li>买方和卖方都有充分的信息</li><li>不存在交易成本</li></ul><h4 id="1311-市场力量"><a class="markdownIt-Anchor" href="#1311-市场力量"></a> 13.1.1 市场力量</h4><p>市场力量（Market power）：影响价格的能力。</p><p>大多数卖家和买家都无法自行定价，尽管他们可能有一定的定价能力。</p><h4 id="1312-完全竞争市场的收入"><a class="markdownIt-Anchor" href="#1312-完全竞争市场的收入"></a> 13.1.2 完全竞争市场的收入</h4><p>在完全竞争的市场中，生产者可以在不影响市场价格的情况下，想卖多少就卖多少。</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>总收入</mtext><mo> =</mo><mtext> 价格</mtext><mo>−</mo><mtext>卖出的数量</mtext></mrow><annotation encoding="application/x-tex"> \text {总收入} = \text {价格} - \text {卖出的数量}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">总收入</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord cjk_fallback"> 价格</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">卖出的数量</span></span></span></span></span></span></p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>平均收入</mtext><mo> =</mo><mfrac><mtext> 总收入</mtext><mtext>卖出的数量</mtext></mfrac></mrow><annotation encoding="application/x-tex"> \text {平均收入} = \frac {\text {总收入}}{\text {卖出的数量}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">平均收入</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.04633em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.36033em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord cjk_fallback"> 卖出的数量</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord cjk_fallback">总收入</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>边际收入</mtext><mo> =</mo><mfrac><mtext> 总收入的变化</mtext><mtext>卖出数量的变化</mtext></mfrac></mrow><annotation encoding="application/x-tex"> \text {边际收入} = \frac {\text {总收入的变化}}{\text {卖出数量的变化}}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">边际收入</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:2.04633em;vertical-align:-0.686em;"></span><span class="mord"><span class="mopen nulldelimiter"></span><span class="mfrac"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:1.36033em;"><span style="top:-2.314em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord cjk_fallback"> 卖出数量的变化</span></span></span></span><span style="top:-3.23em;"><span class="pstrut" style="height:3em;"></span><span class="frac-line" style="border-bottom-width:0.04em;"></span></span><span style="top:-3.677em;"><span class="pstrut" style="height:3em;"></span><span class="mord"><span class="mord text"><span class="mord cjk_fallback">总收入的变化</span></span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.686em;"><span></span></span></span></span></span><span class="mclose nulldelimiter"></span></span></span></span></span></span></p><blockquote><p>因此：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>价格</mtext><mo> =</mo><mtext> 平均收入</mtext><mo> =</mo><mtext> 边际收入</mtext></mrow><annotation encoding="application/x-tex"> \text {价格} = \text {平均收入} = \text {边际收入}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">价格</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 平均收入</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 边际收入</span></span></span></span></span></span></p></blockquote><h2 id="132-利润和生产决策"><a class="markdownIt-Anchor" href="#132-利润和生产决策"></a> 13.2 利润和生产决策</h2><h4 id="1321-利润"><a class="markdownIt-Anchor" href="#1321-利润"></a> 13.2.1 利润</h4><p>企业追求利润最大化。在竞争激烈的市场中，定价企业影响利润的唯一选择就是生产数量。</p><p>竞争性企业的利润最大化规则是生产出 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>边际收入</mtext><mo> =</mo><mtext> 边际成本</mtext></mrow><annotation encoding="application/x-tex"> \text {边际收入} = \text {边际成本}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 边际收入</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 边际成本</span></span></span></span></span> 的产出量。</p><p><img src="/posts/9e+71/Profits_And_Production_Decisions.webp" alt="" loading="lazy"></p><h4 id="1322-决定何时操作"><a class="markdownIt-Anchor" href="#1322-决定何时操作"></a> 13.2.2 决定何时操作</h4><p>在决定生产数量时，企业还必须决定是否：</p><ul><li>继续生产</li><li>暂时关闭</li><li>完全退出市场</li></ul><p>而这一切都是根据利润来决定的：</p><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>利润</mtext><mo> =</mo><mtext> 总收入</mtext><mo>−</mo><mtext>总成本</mtext></mrow><annotation encoding="application/x-tex"> \text {利润} = \text {总收入} - \text {总成本}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">利润</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord text"><span class="mord cjk_fallback"> 总收入</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback">总成本</span></span></span></span></span></span></p><p>当企业停产时，就可以避免产生可变成本：</p><ul><li>固定成本是不可避免的，因此在决定是否停产时不考虑这些成本</li></ul><p>生产的短期决策取决于可变成本，而生产的长期决策取决于总成本。</p><p>假设价格跌至 400。生产 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>边际收入</mtext><mo> =</mo><mtext> 边际成本</mtext></mrow><annotation encoding="application/x-tex"> \text {边际收入} = \text {边际成本}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 边际收入</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 边际成本</span></span></span></span></span> 的数量可能会使损失最小化。</p><p><img src="/posts/9e+71/Deciding_When_To_Operate.webp" alt="" loading="lazy"></p><h4 id="1323-短期供给曲线和停产规则"><a class="markdownIt-Anchor" href="#1323-短期供给曲线和停产规则"></a> 13.2.3 短期供给曲线和停产规则</h4><p>短期停产规则：如果 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>利润</mtext><mo> &lt;</mo><mtext> 平均可变成本</mtext></mrow><annotation encoding="application/x-tex"> \text {利润} &lt; \text {平均可变成本}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72243em;vertical-align:-0.0391em;"></span><span class="mord text"><span class="mord cjk_fallback"> 利润</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> &lt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 平均可变成本</span></span></span></span></span> 那就不生产。</p><h4 id="1324-长期供给曲线和停产规则"><a class="markdownIt-Anchor" href="#1324-长期供给曲线和停产规则"></a> 13.2.4 长期供给曲线和停产规则</h4><p>由于所有成本在长期内都是可变的，因此，如果 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>利润</mtext><mo> &gt;</mo><mtext> 平均总成本</mtext></mrow><annotation encoding="application/x-tex"> \text {利润} &gt; \text {平均总成本}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72243em;vertical-align:-0.0391em;"></span><span class="mord text"><span class="mord cjk_fallback"> 利润</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> &gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 平均总成本</span></span></span></span></span>，长期停产规则就是退出市场。</p><h2 id="133-企业和市场供应曲线"><a class="markdownIt-Anchor" href="#133-企业和市场供应曲线"></a> 13.3 企业和市场供应曲线</h2><p>企业的供给曲线就是其边际成本。市场供给曲线就是各公司供给曲线的总和。</p><p><img src="/posts/9e+71/Firm_And_Market_Supply_Curves.webp" alt="" loading="lazy"></p><h4 id="1331-长期供应"><a class="markdownIt-Anchor" href="#1331-长期供应"></a> 13.3.1 长期供应</h4><p>短期供应与长期供应的主要区别在于：企业在长期内可以进入和退出市场。</p><p>如果存在正经济利润：</p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>利润</mtext><mo> &gt;</mo><mtext> 平均总成本</mtext></mrow><annotation encoding="application/x-tex"> \text {利润} &gt; \text {平均总成本}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72243em;vertical-align:-0.0391em;"></span><span class="mord text"><span class="mord cjk_fallback"> 利润</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> &gt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 平均总成本</span></span></span></span></span></li><li>新公司进入以获取利润</li><li>市场供应曲线向外移动，直至 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>利润</mtext><mo> =</mo><mtext> 平均总成本</mtext></mrow><annotation encoding="application/x-tex"> \text {利润} = \text {平均总成本}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 利润</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 平均总成本</span></span></span></span></span></li><li>所有企业的经济利润为零</li></ul><p>而如果存在负经济利润：</p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>利润</mtext><mo> &lt;</mo><mtext> 平均总成本</mtext></mrow><annotation encoding="application/x-tex"> \text {利润} &lt; \text {平均总成本}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.72243em;vertical-align:-0.0391em;"></span><span class="mord text"><span class="mord cjk_fallback"> 利润</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> &lt;</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 平均总成本</span></span></span></span></span></li><li>部分企业退出以避免损失</li><li>市场供应曲线向内移动，直至 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>利润</mtext><mo> =</mo><mtext> 平均总成本</mtext></mrow><annotation encoding="application/x-tex"> \text {利润} = \text {平均总成本}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 利润</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 平均总成本</span></span></span></span></span></li><li>所有企业的经济利润为零</li></ul><p>市场进入和退出过程导致了完全竞争市场中的企业长期经济利润为零。</p><ul><li>长期中，<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>利润</mtext><mo> =</mo><mi>min</mi><mo>⁡</mo><mrow><mo stretchy="false">(</mo><mtext>平均总成本</mtext><mo stretchy="false">)</mo></mrow><mo>=</mo><mtext> 边际收入</mtext><mo> =</mo><mtext> 边际成本</mtext></mrow><annotation encoding="application/x-tex"> \text {利润} = \min {(\text {平均总成本})} = \text {边际收入} = \text {边际成本}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 利润</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop">min</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mopen">(</span><span class="mord text"><span class="mord cjk_fallback">平均总成本</span></span><span class="mclose">)</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 边际收入</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 边际成本</span></span></span></span></span></li><li>会计利润长期为正数</li><li>企业赚取会计利润，以补偿其机会成本</li></ul><p>由于所有企业都在 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>利润</mtext><mo> =</mo><mi>min</mi><mo>⁡</mo><mrow><mo stretchy="false">(</mo><mtext>平均总成本</mtext><mo stretchy="false">)</mo></mrow></mrow><annotation encoding="application/x-tex">\text {利润} = \min {(\text {平均总成本})}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 利润</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop">min</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mopen">(</span><span class="mord text"><span class="mord cjk_fallback">平均总成本</span></span><span class="mclose">)</span></span></span></span></span> 这一点上运营，因此竞争市场中的企业都以有效规模运营。</p><p><img src="/posts/9e+71/Long_Run_Supply.webp" alt="" loading="lazy"></p><p>鉴于 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>利润</mtext><mo> =</mo><mi>min</mi><mo>⁡</mo><mrow><mo stretchy="false">(</mo><mtext>平均总成本</mtext><mo stretchy="false">)</mo></mrow></mrow><annotation encoding="application/x-tex">\text {利润} = \min {(\text {平均总成本})}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 利润</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop">min</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mopen">(</span><span class="mord text"><span class="mord cjk_fallback">平均总成本</span></span><span class="mclose">)</span></span></span></span></span>，在长期内，任何数量的价格都是相同的。</p><p><img src="/posts/9e+71/Long_Run_Supply_1.webp" alt="" loading="lazy"></p><ul><li>如果有任何因素导致市场平衡偏离这一价格，那么由此产生的正或负利润都会导致企业进入或退出市场，直到恢复零经济利润为止</li></ul><blockquote><p>为什么长期市场供给曲线不应该向上倾斜，但却向上倾斜了？</p><p>竞争性市场理论认为，市场供应曲线应始终保持完全弹性。</p><p>大多数长期市场供给曲线（Long-run market supply curves）都是向上倾斜的。这是由于假设所有公司都具有相同的成本结构。</p><p>如果新进入者的成本高于现有企业，则价格必须上涨到足以吸引新企业进入市场的程度。</p></blockquote><h4 id="1332-长期经济利润"><a class="markdownIt-Anchor" href="#1332-长期经济利润"></a> 13.3.2 长期经济利润</h4><p>竞争性市场理论认为，从长远来看，所有企业的经济利润都应为零。</p><p>实际上，只有市场上效率最低的企业的 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mtext>价格</mtext><mo> =</mo><mi>min</mi><mo>⁡</mo><mrow><mo stretchy="false">(</mo><mtext>平均总成本</mtext><mo stretchy="false">)</mo></mrow></mrow><annotation encoding="application/x-tex">\text {价格} = \min {(\text {平均总成本})}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord text"><span class="mord cjk_fallback"> 价格</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel"> =</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mop">min</span><span class="mspace" style="margin-right:0.16666666666666666em;"></span><span class="mord"><span class="mopen">(</span><span class="mord text"><span class="mord cjk_fallback">平均总成本</span></span><span class="mclose">)</span></span></span></span></span>。</p><ul><li>通常而言，这是最后进入市场的公司</li><li>平均总成本较低的企业效率较高，从长期来看可获得正经济利润</li></ul><h4 id="1333-因生产成本变化而进入市场"><a class="markdownIt-Anchor" href="#1333-因生产成本变化而进入市场"></a> 13.3.3 因生产成本变化而进入市场</h4><p>技术和生产能力的提高降低了边际成本和平均总成本。</p><p><img src="/posts/9e+71/Market_Entry_Due_To_Changing_Production_Costs.webp" alt="" loading="lazy"></p><ul><li>创新型企业寻求更好的生产工艺和新技术，从而以更低的成本生产商品</li><li>正利润会吸引投资者</li><li>价格随生产成本下降</li></ul><h4 id="1334-应对需求的变化"><a class="markdownIt-Anchor" href="#1334-应对需求的变化"></a> 13.3.4 应对需求的变化</h4><p>假设对完全竞争商品的需求增加，短期和长期会发生什么情况？</p><p><img src="/posts/9e+71/Responding_To_Shifts_In_Demand.webp" alt="" loading="lazy"></p><center>-----</center><h1 id="chapter-14-monopoly"><a class="markdownIt-Anchor" href="#chapter-14-monopoly"></a> Chapter 14: Monopoly</h1><p>Monopoly: a firm that is the only producer of a good or service with no close substitutes.</p><ul><li>a firm is a perfect monopoly if it controls the entire market</li><li>a firm has monopoly power if it can manipulate the price</li></ul><p>Monopolies exist because of barriers to entry that prevent other firms from entering the market.</p><table><thead><tr><th>Scarce resources</th><th>Economies of scale</th></tr></thead><tbody><tr><td>Governmental intervention</td><td>Aggressive business tactics</td></tr></tbody></table><p>Natural monopoly: a market where a single firm can produce the entire market quantity demanded at a lower cost than multiple firms.</p><h2 id="141-monopolists-and-demand-curve"><a class="markdownIt-Anchor" href="#141-monopolists-and-demand-curve"></a> 14.1 Monopolists and Demand Curve</h2><p>Monopolies differ from perfectly competitive firms with regard to their demand curves.</p><p><img src="/posts/9e+71/Monopolists_And_Demand_Curve.webp" alt="" loading="lazy"></p><h2 id="142-monopoly-revenue"><a class="markdownIt-Anchor" href="#142-monopoly-revenue"></a> 14.2 Monopoly Revenue</h2><p>Monopolist produces more of a good -&gt; market price is driven down. Therefore, producing an additional unit of output has two effects on revenue:</p><ol><li>Quantity effect: total revenue increases</li><li>Price effect: total revenue decreases</li></ol><p>In monopoly markets, a firm is the only producer and faces a downward-sloping demand curve.</p><h2 id="143-monopoly-profit-maximizing-quantity"><a class="markdownIt-Anchor" href="#143-monopoly-profit-maximizing-quantity"></a> 14.3 Monopoly Profit-maximizing Quantity</h2><p>Monopolist maximizes profit by producing the quantity where marginal revenue equals marginal cost.</p><h2 id="144-problems-with-monopoly"><a class="markdownIt-Anchor" href="#144-problems-with-monopoly"></a> 14.4 Problems with Monopoly</h2><p>Monopoly power benefits monopolists but causes social welfare losses.</p><p>Monopolists produce at a lower quantity than the efficient level.</p><ul><li>total surplus is not maximized</li><li>producer surplus increases</li><li>consumer surplus decreases</li><li>the loss of total surplus is a deadweight loss equal to the total surplus under perfect competition minus the total surplus under monopoly</li></ul><p class="katex-block"><span class="katex-display"><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><mtext>Deadweight&nbsp;loss</mtext><mo>=</mo><mtext>Total&nbsp;surplus&nbsp;under&nbsp;perfect&nbsp;competition</mtext><mo>−</mo><mtext>Total&nbsp;surplus&nbsp;under&nbsp;monopoly</mtext></mrow><annotation encoding="application/x-tex">\text{Deadweight loss} = \text{Total surplus under perfect competition} - \text{Total surplus under monopoly}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord text"><span class="mord">Deadweight&nbsp;loss</span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord text"><span class="mord">Total&nbsp;surplus&nbsp;under&nbsp;perfect&nbsp;competition</span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.8888799999999999em;vertical-align:-0.19444em;"></span><span class="mord text"><span class="mord">Total&nbsp;surplus&nbsp;under&nbsp;monopoly</span></span></span></span></span></span></p><h2 id="145-comparing-market-characteristics"><a class="markdownIt-Anchor" href="#145-comparing-market-characteristics"></a> 14.5 Comparing Market Characteristics</h2><table><thead><tr><th>Characteristic</th><th>Perfect competition</th><th>Monopoly</th></tr></thead><tbody><tr><td>Number of firms</td><td>Many</td><td>One</td></tr><tr><td>Price taker or maker</td><td>Price taker</td><td>Price maker</td></tr><tr><td>Marginal revenue</td><td>Equal to price</td><td>Less than price</td></tr></tbody></table><center>-----</center><h1 id="chapter-17-international-trade"><a class="markdownIt-Anchor" href="#chapter-17-international-trade"></a> Chapter 17: International Trade</h1><p>A country has an absolute advantage if it can produce more of a good or service than other countries.</p><p>A country has a comparative advantage if it can produce a good or service at a lower opportunity cost than other countries.</p><blockquote><p>Example:<br>U.S. and Bangladeshi produce wheat and T-shirts.<br><img src="/posts/9e+71/Why_Trade.webp" alt="" loading="lazy"></p><ul><li>without specialization and trade -&gt; able to produce on their PPF -&gt; still inefficient.</li><li>with specialization and trade -&gt; coordinate their production and produce more goods.</li></ul></blockquote><h2 id="171-roots-of-comparative-advantage"><a class="markdownIt-Anchor" href="#171-roots-of-comparative-advantage"></a> 17.1 Roots of Comparative Advantage</h2><p>Comparative advantage: the ability to produce a good or service at a lower opportunity cost than other producers.</p><p>Characteristics that affect the costs of production:</p><ol><li>Technology</li><li>Factor endowment</li><li>Natural resources and climate</li></ol><h2 id="172-from-autarky-to-free-trade"><a class="markdownIt-Anchor" href="#172-from-autarky-to-free-trade"></a> 17.2 From Autarky to Free Trade</h2><p>Autarky economy: an economy that is self-contained and does not engage in trade with outsiders.</p><ul><li>does not export or import any goods or services<ul><li>imports: goods and services that are produced in other countries and consumed domestically</li><li>exports: goods and services that are produced domestically and consumed in other countries</li></ul></li><li>the domestic price and quantity is determined by the intersection of the domestic supply and domestic demand curves</li></ul><p><img src="/posts/9e+71/From_Autarky_To_Free_Trade.webp" alt="" loading="lazy"></p><p>When an economy decides to engage in trade, the domestic price and quantity change.</p><ul><li>if the world price is less than autarky domestic price:<ul><li>domestic price decreases to equal the world price</li><li>excess demand occurs</li></ul></li><li>imports make up the difference between domestic supply and demand, eliminating the shortage</li></ul><p><img src="/posts/9e+71/From_Autarky_To_Free_Trade_1.webp" alt="" loading="lazy"></p><p>Consumer and producer surpluses are affected.</p><p><img src="/posts/9e+71/From_Autarky_To_Free_Trade_2.webp" alt="" loading="lazy"></p><h4 id="1721-net-importer-or-net-exporter"><a class="markdownIt-Anchor" href="#1721-net-importer-or-net-exporter"></a> 17.2.1 Net-Importer or Net-Exporter</h4><p><img src="/posts/9e+71/Net_Importer_Or_Net_Exporter.webp" alt="" loading="lazy"></p><ul><li>the world price is greater than autarky domestic price</li><li>domestic producers can earn higher profits by exporting their goods abroad</li><li>the country is a net-exporter of airplanes</li></ul><h4 id="1722-big-economy-small-economy"><a class="markdownIt-Anchor" href="#1722-big-economy-small-economy"></a> 17.2.2 Big Economy, Small Economy</h4><p><img src="/posts/9e+71/Big_Economy_Small_Economy.webp" alt="" loading="lazy"></p><ul><li>if a country is relatively "big", then it can influence the world price</li><li>when the U.S. moves from autarky to free trade, the world demand curve shifts to the right because U.S. consumers have entered the market<ul><li>world demand shifts right</li><li>world supply shifts right</li></ul></li><li>on net, because world demand shifted more than world supply, the world price increases</li></ul><p>For many goods, the price goes down, and the country as a whole is better off, but producers lose out.</p><p><img src="/posts/9e+71/Big_Economy_Small_Economy_1.webp" alt="" loading="lazy"></p><h2 id="173-restrictions-on-trade"><a class="markdownIt-Anchor" href="#173-restrictions-on-trade"></a> 17.3 Restrictions on Trade</h2><p>Laws limiting trade are referred to as trade protection:</p><ul><li>protectionism: a preference for policies that limit trade</li><li>trade liberalization: policies and actions that reduce trade restrictions</li></ul><h2 id="174-tariffs"><a class="markdownIt-Anchor" href="#174-tariffs"></a> 17.4 Tariffs</h2><p>Tariff: a tax targeted at certain imports.</p><ul><li>its purpose is to reduce the quantity of imports to protect domestic producers</li><li>tariff increases the world price for domestic consumers</li><li>tariff decreases the amount of shortage made up by imports</li></ul><p><img src="/posts/9e+71/Tariffs.webp" alt="" loading="lazy"></p><h4 id="1741-domestic-welfare-effects-of-a-tariff"><a class="markdownIt-Anchor" href="#1741-domestic-welfare-effects-of-a-tariff"></a> 17.4.1 Domestic Welfare Effects of a Tariff</h4><p><img src="/posts/9e+71/Domestic_Welfare_Effects_Of_A_Tariff.webp" alt="" loading="lazy"></p><blockquote><p>Example:<br>A tariff of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">$</mi><mi>t</mi></mrow><annotation encoding="application/x-tex">\$t</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.80556em;vertical-align:-0.05556em;"></span><span class="mord">$</span><span class="mord mathnormal">t</span></span></span></span> per unit is imposed on foreign copper.<br><img src="/posts/9e+71/Domestic_Welfare_Effects_Of_A_Tariff_1.webp" alt="" loading="lazy"></p><table><thead><tr><th>Measure</th><th>Before</th><th>After</th><th>Change</th></tr></thead><tbody><tr><td>CS</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi><mo>+</mo><mi>B</mi><mo>+</mo><mi>C</mi><mo>+</mo><mi>D</mi><mo>+</mo><mi>E</mi><mo>+</mo><mi>F</mi></mrow><annotation encoding="application/x-tex">A + B + C + D + E + F</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>A</mi><mo>+</mo><mi>B</mi></mrow><annotation encoding="application/x-tex">A + B</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal">A</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05017em;">B</span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>−</mo><mo stretchy="false">(</mo><mi>C</mi><mo>+</mo><mi>D</mi><mo>+</mo><mi>E</mi><mo>+</mo><mi>F</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">-(C+D+E+F)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">−</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mclose">)</span></span></span></span></td></tr><tr><td>PS</td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>G</mi></mrow><annotation encoding="application/x-tex">G</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal">G</span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>G</mi><mo>+</mo><mi>C</mi></mrow><annotation encoding="application/x-tex">G+C</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal">G</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>+</mo><mi>C</mi></mrow><annotation encoding="application/x-tex">+C</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord">+</span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span></span></span></span></td></tr><tr><td>Gov't Rev</td><td></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>E</mi></mrow><annotation encoding="application/x-tex">E</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>+</mo><mi>E</mi></mrow><annotation encoding="application/x-tex">+E</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord">+</span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span></span></span></span></td></tr><tr><td>DWL</td><td></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>D</mi><mo>+</mo><mi>F</mi></mrow><annotation encoding="application/x-tex">D+F</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span></span></span></span></td><td><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo>+</mo><mo stretchy="false">(</mo><mi>D</mi><mo>+</mo><mi>F</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">+(D+F)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">+</span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span><span class="mclose">)</span></span></span></span></td></tr></tbody></table></blockquote><h2 id="175-quotas"><a class="markdownIt-Anchor" href="#175-quotas"></a> 17.5 Quotas</h2><p>Quota: a limit on the amount of a particular good that can be imported.</p><p>Quota rents: profits earned by foreign firms or governments under a quota.</p><p><img src="/posts/9e+71/Quotas.webp" alt="" loading="lazy"></p><p>A quota has the following effects:</p><ul><li>decreases imports</li><li>increases import price</li><li>increases producer surplus by <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi></mrow><annotation encoding="application/x-tex">C</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span></span></span></span></li><li>decreases consumer surplus by <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>C</mi><mo>+</mo><mi>D</mi><mo>+</mo><mi>E</mi><mo>+</mo><mi>F</mi></mrow><annotation encoding="application/x-tex">C + D + E + F</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.07153em;">C</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span></span></span></span></li><li>foreign companies earn quota rents of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>E</mi></mrow><annotation encoding="application/x-tex">E</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.05764em;">E</span></span></span></span></li><li>deadweight loss of <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>D</mi><mo>+</mo><mi>F</mi></mrow><annotation encoding="application/x-tex">D + F</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.02778em;">D</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.13889em;">F</span></span></span></span> occurs</li></ul><h2 id="176-international-labor-and-capital"><a class="markdownIt-Anchor" href="#176-international-labor-and-capital"></a> 17.6 International Labor and Capital</h2><p>Although countries gain from trade liberalization, certain segments of the population lose out.</p><p>Free trade increases demand for factors of production that are domestically abundant, and it increases the supply of factors that are domestically scarce.</p><ul><li>causes factor prices to converge across countries</li><li>owners of domestically scarce factors of production lose due to increased competition, and owners of domestically abundant factors gain from increased demand</li></ul><blockquote><p>Each country has its own set of laws and policies governing the economy.<br>The World Trade Organization is an international organization designed to monitor and enforce trade agreements while also promoting free trade</p><ul><li>import standards and the fair trade movement are ways in which countries</li></ul></blockquote></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;微观经济学笔记，仅作为个人学习记录，不保证正确性。&lt;/p&gt;</summary>
    
    
    
    <category term="学术笔记" scheme="https://blog.cytrogen.icu/categories/%E5%AD%A6%E6%9C%AF%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="大学课程" scheme="https://blog.cytrogen.icu/tags/%E5%A4%A7%E5%AD%A6%E8%AF%BE%E7%A8%8B/"/>
    
  </entry>
  
  <entry>
    <title>CS50AI Python 笔记</title>
    <link href="https://blog.cytrogen.icu/posts/d235.html"/>
    <id>https://blog.cytrogen.icu/posts/d235.html</id>
    <published>2023-09-05T14:00:00.000Z</published>
    <updated>2026-02-09T17:16:54.681Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>仅作个人用途。CS50AI 课程的笔记。</p><span id="more"></span><h1 id="0-search"><a class="markdownIt-Anchor" href="#0-search"></a> 0. Search</h1><p>什么能够制造 AI：</p><ol><li>搜索：寻找问题的解决方案</li><li>知识：展示信息和相关知识</li><li>不确定性：使用概率来解决不确定的事件</li><li>优化：不单是找到解决问题的正确方案，而是找到更好更棒的解决方案</li><li>学习：基于对数据和经验的获取而提高性能</li><li>神经网络：一种受人脑启发的程序结构，能够有效地执行任务</li><li>语言：处理由人类产生和理解的自然语言</li></ol><h2 id="搜索"><a class="markdownIt-Anchor" href="#搜索"></a> 搜索</h2><p>搜索问题设计了一个代理，它：</p><ul><li>被赋予一个初始状态</li><li>被赋予一个目标状态</li><li>返回一个如何从前者到后者的解决方案</li></ul><h2 id="解决搜索问题"><a class="markdownIt-Anchor" href="#解决搜索问题"></a> 解决搜索问题</h2><p>解决方案是从初始状态到目标状态的一连串行动。</p><p>而最佳解决方案，是一个在所有解决方案中具有最低路径成本的解决方案。</p><p>在搜索过程中，数据通常被存储在一个节点（node）中。节点是一个数据结构，包含：</p><ul><li><p>一个状态</p></li><li><p>父节点</p></li><li><p>应用于父节点状态的行动，以达到当前节点的目的</p></li><li><p>从初始状态到这个节点的路径成本</p></li></ul><p>节点包含的信息对搜索算法的目的很有用。不过节点仅持有信息。为了实际搜索，我们使用前沿（frontier），即管理节点的机制。</p><p>前沿开始时包含一个初始状态和一个空的已探索集合，然后重复直到达到一个解决方案：</p><ol><li><p>如果前沿是空的：</p><ul><li>停止。这个问题没有解决方案</li></ul></li><li><p>从前沿中移除一个节点，该节点会被考虑</p></li><li><p>如果节点持有目标状态：</p><ul><li>返回解决方案。停止</li></ul><p>否则：</p><ol><li>扩展节点（找到所有可以从这个节点到达的新节点）</li><li>将产生的节点添加到前沿</li><li>将当前节点添加到已探索集合中</li></ol></li></ol><p>上述没有提到哪个节点应该被移除。这个选择对解决方案的质量和实现的速度都有影响。有多种方法可以解决哪些节点应该被首先考虑：</p><ol><li>堆栈/深度优先搜索（stack/depth-first search）</li></ol><ul><li>在尝试另一个方向之前会穷尽每一个方向</li><li>前沿被作为一个堆栈数据结构来管理</li><li>「后进先出」</li><li>当节点被添加到前沿之后，第一个要移除和考虑的节点是最后被添加的节点</li><li>在第一个方向上尽可能地深入，而把所有其他方向留给以后</li></ul><blockquote><p>例子：你在寻找钥匙</p><ol><li>选择从裤子开始搜索</li><li>先翻遍每一个口袋</li><li>当裤子的每个口袋里都找完了，再停止对裤子的搜索</li><li>搜索其他地方</li></ol></blockquote><p>优点：</p><ul><li>在最好的情况下，速度最快</li></ul><p>缺点：</p><ul><li>找到的解决方案有可能并不是最优的</li><li>在最坏的情况下，可能在找到解决方案之前就探索了所有可能的路径，导致花费了更长的时间</li></ul>  <pre><code class="language-python">def remove(self):    if self.empty():        # 如果前沿是空的，终止搜索        raise Exception("空前沿")    else:        # 保存最新添加的节点        node = self.frontier[-1]        # 从前沿里移除最新添加的节点        self.frontier = self.frontier[:-1]        return node</code></pre><ol start="2"><li>队列/广度优先搜索（queue/breadth-first search）</li></ol><ul><li><p>同时遵循多个方向</p></li><li><p>在每个可能的方向上走一步，然后在每个方向上走第二步</p></li><li><p>前沿被作为一个队列数据结构来管理</p></li><li><p>「先进先出」</p></li><li><p>所有的新节点都是排队增加的</p></li><li><p>节点被考虑的依据是哪一个先被添加</p></li></ul><blockquote><p>例子：你又在找钥匙</p><ol><li>从裤子开始搜索</li><li>从裤子右边口袋里寻找</li><li>在抽屉里看一看</li><li>在桌子上看</li><li>用尽了所有的位置之后，回到裤子，寻找下一个口袋</li></ol></blockquote><p>优点：</p><ul><li>保证能找到最优解</li></ul><p>缺点：</p><ul><li>运行的时间比最小时间长</li><li>在最坏的情况下，这个算法需要尽可能长的时间来运行</li></ul>  <pre><code class="language-python">def remove(self):    if self.empty():        # 如果前沿为空，终止搜索        raise Exception('空前沿')    else:        # 保存第一个被添加的节点        node = self.frontier[0]        # 从前沿中移除第一个节点        self.frontier = self.frontier[1:]        return node</code></pre><ol start="3"><li><p>贪婪的最佳优先搜索（greedy best-first search）</p><p>广度优先和深度优先都是无信息的搜索算法。这些算法不利用任何它们没有通过自己的探索而获得的关于问题的知识。然而，关于问题的一些知识实际上是可用且常用的。</p><ul><li>扩展了最接近目标的节点</li><li>该行为由启发式函数（heuristic function）决定</li><li>函数估计下一个节点离目标有多近，但可能是错误的</li></ul></li><li><p>A* 搜索（A* search）</p><p>作为贪婪的最佳优先算法的发展，A* 搜索不仅考虑了启发式函数 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>h</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">h(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">h</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span>，还考虑了直到当前位置的累计成本 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>g</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">g(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal" style="margin-right:0.03588em;">g</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span>。结合这两个值，该算法确定解决方案的成本更精准，还会优化其在路上的选择。</p><p>该算法会一直跟踪 <code>到现在位置的路径成本 + 到目标的估计成本</code>。一旦超过之前某个选项的估计成本，该算法就会抛弃当前的路径，回到之前的选项，从而避免自己走一条被 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>h</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">h(n)</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">h</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span></span></span></span> 错误地标记为最佳、实际为漫长且低效的路径。</p><p>这个算法也依赖着启发式。某些情况下，效率要比贪婪的最佳优先搜索低，甚至低于无信息的算法。为了使 A* 搜索成为最优，启发式函数应该是：</p><ul><li><p>可接受的 / 永远不会高估真实成本</p></li><li><p>一致性</p></li><li><p><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>h</mi><mo stretchy="false">(</mo><mi>n</mi><mo stretchy="false">)</mo><mo>&lt;</mo><mo>=</mo><mi>h</mi><mo stretchy="false">(</mo><msup><mi>n</mi><mo mathvariant="normal" lspace="0em" rspace="0em">′</mo></msup><mo stretchy="false">)</mo><mo>+</mo><mi>c</mi></mrow><annotation encoding="application/x-tex">h(n) &lt;= h(n') + c</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">h</span><span class="mopen">(</span><span class="mord mathnormal">n</span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">&lt;</span></span><span class="base"><span class="strut" style="height:0.36687em;vertical-align:0em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:1.001892em;vertical-align:-0.25em;"></span><span class="mord mathnormal">h</span><span class="mopen">(</span><span class="mord"><span class="mord mathnormal">n</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.751892em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">′</span></span></span></span></span></span></span></span></span><span class="mclose">)</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">c</span></span></span></span></p></li></ul></li><li><p>对抗性搜索（adversarial search）</p><p>该搜索中，算法面临着一个试图实现相反目标的对手。例如井字棋。</p><ol><li><p>极小化极大（minimax）</p><p>对抗性搜索中的一种算法：</p><ul><li>将一方的获胜条件表示为 <code>-1</code>，另一方的获胜条件为 <code>+1</code></li><li>进一步的行动将由这些条件驱动</li></ul><blockquote><p>井字棋 AI：</p><ul><li><span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>s</mi><mn>0</mn></msub></mrow><annotation encoding="application/x-tex">s_0</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal">s</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">0</span></span></span></span><span class="vlist-s">​</span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 代表初始状态（一个空的 3x3 棋盘）</li><li><code>Players(s)</code>：参数 <code>s</code> 是一个状态；返回哪个玩家的回合（X 或者 O）</li><li><code>Actions(s)</code>：参数 <code>s</code> 是一个状态；返回当前状态所有有效的移动（棋盘上哪些格子是空闲的）</li><li><code>Results(s,a)</code>：参数 <code>s</code> 和 <code>a</code> 分别是一个状态和一个行动；返回一个全新的状态（在状态 <code>s</code> 上执行行动 <code>a</code> 后的棋盘）</li><li><code>Terminal(s)</code>：参数 <code>s</code> 是一个状态；检查是否是棋盘中最后一次行动（是否有人胜出或平局）；如果游戏结束返回 <code>True</code>，反之返回 <code>False</code></li><li><code>Utility(s)</code>：参数 <code>s</code> 是一个临终状态；返回该状态的效用值：<code>-1</code>、<code>0</code>、<code>1</code></li></ul></blockquote><p><img src="/posts/d235/Minimax_Tictactoe.webp" alt="Minimax in Tic Tac Toe" loading="lazy"></p><ol><li>根据状态（本回合轮到谁），该算法可以知道当前的玩家在进行优化游戏时是否会选择导致了一个较低 / 较高数值的状态的行动</li><li>在最小化和最大化之间交替进行</li><li>为每个可能的行动所导致的状态创造值</li></ol> <pre><code class="language-plaintext">Function Max-Value(state):v = -∞if Terminal(state):return Utility(state)for action in Actions(state):v = Max(v,Min-Value(Result(state,action)))return v      Function Min-Value(state):          v = ∞          if Terminal(state):              return Utility(state)          for action in Actions(state):              v = Min(v,Max-Value(Result(state,action)))              return v</code></pre></li><li><p>Alpha-beta 剪枝（alpha-beta pruning）</p></li></ol><p>作为优化极小化极大的一种方式，Alpha-beta 剪枝跳过了一些明显不利的递归计算。</p><p>在确定了一个行动的值后，如果有初步证据表明之后的行动可以使对手得到比已经确定的行动更好的分数，那么就没有必要进一步研究这个行动，因为它将决定性地比之前确定的行动更不利。</p><blockquote><p>例子：</p><p>一个最大化的棋手知道：在下一步，最小化的棋手将试图达到最低分数。</p><p>假设最大化的棋手有三个可能的行动，第一个行动的值为 4。为此，如果当前棋手实施了该行动，棋手会生成最小化者的行动值，因为他知道最小化者会选择最低的行动。</p><p>然而，在完成对最小化者的所有可能行动的计算之前，棋手看到其中一个选项的值为 3。这意味着对于最小化者来说，没有理由继续探索其他可能的行动。尚未取值的行动的值并不重要，无论是 10 还是 - 10。</p><p>如果值是 10，最小化者就会选择最低的选项，也就是 3，这已经比预先确定的 4 更糟糕。因此，此时计算最小化者的额外可能行动与最大化者无关，因为最大化者已经有一个明确的更好的选择，即 4。</p></blockquote><ol start="3"><li>深度有限的极小化极大（depth-limited minimax）</li></ol><p>井字棋一共有 255168 个可能，而国际象棋有 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mn>1</mn><msup><mn>0</mn><mn>290</mn></msup></mrow><annotation encoding="application/x-tex">10^{290}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8141079999999999em;vertical-align:0em;"></span><span class="mord">1</span><span class="mord"><span class="mord">0</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span><span class="mord mtight">9</span><span class="mord mtight">0</span></span></span></span></span></span></span></span></span></span></span></span> 个可能。到目前为止，极小化极大算法要求生成从某一点到目标条件的所有假设。虽然计算所有的井字棋游戏假设对现代计算机来说并不困难，但如果在国际象棋里呢？</p><p>深度限制的极小化极大在停止前只考虑先定义的棋步数，而不去考虑临终状态。然而这并不允许为每个行动获取一个精确的数值，因为假想游戏的终点还未达到。</p><p>为了处理这个问题，深度有限的极小化极大依赖于一个评估函数，该函数估计了从给定状态开始的游戏的预期效用，或者换句话说，为状态赋值。</p><blockquote><p>例子：</p><p>在国际象棋中，一个效用函数将棋盘的当前配置作为输入，试图评估其预期效用（基于每个玩家拥有的棋子和它们在棋盘上的位置），然后返回一个正值或负值，代表棋盘对一个玩家与另一个玩家的有利程度。</p><p>这些值可以用来决定正确的行动。评估函数越好，依赖它的极小化极大算法就越好。</p></blockquote></li></ol><h2 id="作业degrees"><a class="markdownIt-Anchor" href="#作业degrees"></a> 作业 Degrees</h2><blockquote><p>根据 Six Degrees of Kevin Bacon 游戏，好莱坞电影界的任何人都可以在 6 个步骤内与 Kevin Bacon 联系起来，其中每个步骤都包括找到两个演员都出演的电影。</p><p>问题：通过选择一连串的电影，找到任何两个演员之间的最短路径。</p><blockquote><p>例子：Jennifer Lawrence 和 Tom Hanks 的最短路径为 2。</p><ol><li>Jennifer Lawrence 和 Kevin Bacon 都出演了《X-Men: First Class》</li><li>Kevin Bacon 和 Tom Hanks 都出演了《Apollo 13》</li></ol></blockquote></blockquote><h3 id="分发代码"><a class="markdownIt-Anchor" href="#分发代码"></a> 分发代码</h3><ol><li><p>large 目录下的 csv 数据文件</p></li><li><p>small 目录下的 csv 数据文件（用于测试）：<br>在 small 目录下的 people.csv 中，能看到每个人都有一个独特的 id、他们的名字和生日；在 movies.csv 中，每个电影都有一个独特的 id、它们的标题和发布的年份；在 stars.csv 中，每一行都是一组人的 id 和电影的 id。</p><blockquote><p>例子：人的 id 为 102，电影的 id 为 104257。这代表了 Kevin Bacon 出演过《A Few Good Men》。</p></blockquote></li><li><p><a href="http://degrees.py">degrees.py</a>。在最上方一些数据结构被定义（<code>names</code>、<code>people</code>、<code>movies</code>），这些数据结构将保存从 CSV 文件中的信息。</p><ul><li><code>names</code> 字典，将名字映射到一组对应的 id（可能有多个演员有相同的名字）</li><li><code>people</code> 字典，将人 id 映射到另外一个字典（存有名字、出生年份、主演的所有电影的集合）</li><li><code>movies</code> 字典，将电影 id 映射到另外一个字典（存有标题、发行年份、所有出演演员的 id）</li></ul><p>文件已经事先定义了一个函数 <code>load_data()</code>，它从 CSV 文件里加载数据，并存在上述这些数据结构中。</p><p>主函数 <code>main()</code> 首先将数据加载到内存中（加载数据的目录需要通过命令行参数指定）。之后函数会提示用户输入两个名字，另一个函数 <code>person_id_for_name()</code> 会检索这个名字并返回 id（如果有多个演员叫这个名字，就会提示用户找出正确的 id）。然后主函数会调用 <code>shortest_path()</code> 来计算这两个人之间的最短路径，并打印出这个路径。</p><p>然而，<code>shortest_path()</code> 要你来写。</p></li></ol><h3 id="目标"><a class="markdownIt-Anchor" href="#目标"></a> 目标</h3><p>完成 <code>shortest_path()</code> 的实现，使其返回源 id 到目标 id 的最短路径</p><ol><li>假设有一条从源 id 到目标 id 的路径，你的函数应该返回一个列表，每个元素是一个元组：<code>(movie_id, person_id)</code></li><li>如果 <code>shortest_path()</code> 返回了 <code>[(1, 2), (3, 4)]</code>，那就意味着源 id 和人 2 一起出演了电影 1，人 2 在电影 3 中和人 4 出演，而人 4 是目标</li><li>如果从源 id 到目标 id 之间有多条最小长度的路径，你的函数可以返回其中的任何一条</li><li>如果两个演员之间没有可能的路径，你的函数应该返回 <code>None</code></li><li>你可以调用 <code>neighbors_for_person()</code>，该函数接收一个人的 id 作为参数，并返回装有 <code>(movie_id, person_id)</code> 元组的集合（这些人都和提供的人出演过电影）</li></ol><h2 id="作业tic-tac-toe"><a class="markdownIt-Anchor" href="#作业tic-tac-toe"></a> 作业 Tic-Tac-Toe</h2><h3 id="分发代码-2"><a class="markdownIt-Anchor" href="#分发代码-2"></a> 分发代码</h3><p>项目中有两个主要文件：<a href="http://runner.py">runner.py</a> 和 <a href="http://tictactoe.py">tictactoe.py</a>，后者包含了所有玩游戏、做出最佳动作的逻辑，而前者包含了所有运行游戏的代码。</p><p><a href="http://tictactoe.py">tictactoe.py</a> 定义了三个变量：<code>X</code>、<code>O</code>、<code>EMPTY</code>，代表了棋盘上可能出现的移动。</p><p>函数 <code>initial_state()</code> 返回棋盘的起始状态。将棋盘表示为三个列表以代表三行，其中每个内部列表都包含了我们刚定义的变量的值。</p><h3 id="目标-2"><a class="markdownIt-Anchor" href="#目标-2"></a> 目标</h3><p>完成 <code>player()</code>、<code>actions()</code>、<code>result()</code>、<code>winner()</code>、<code>terminal()</code>、<code>utility()</code>，和 <code>minimax()</code> 这些函数。</p><ol><li><p><code>player()</code> 接受棋盘状态作为输入，然后返回当前回合属于哪个棋手</p><ul><li>棋盘初始化时，棋手 X 先手下棋</li></ul></li><li><p><code>action()</code> 返回一个装有在当前棋盘上可以采取的所有行动的集合</p><ul><li>每个行动是一个元组 <code>(i, j)</code>，其中 <code>i</code> 对应行，<code>j</code> 对应一行中的单元格</li><li>可以采取的行动代表的是在棋盘上任何尚未有 X 或者 O 的单元格</li></ul></li><li><p><code>result()</code> 接受一个棋盘和一个行动作为输入，然后返回一个新的棋盘状态</p><ul><li>如果动作并不有效，程序应该引发一个异常</li></ul></li><li><p><code>winner()</code> 接受一个棋盘作为输入。如果已经有人胜出，返回赢家</p><ul><li><p>假设棋手 X 赢了，就返回 <code>X</code></p></li><li><p>胜利目标：在水平、垂直或对角线上连续走了三步</p></li><li><p>如果平手，则返回 <code>None</code></p></li></ul></li><li><p><code>terminal()</code> 接受一个棋盘作为输入，然后返回一个布尔值，表示游戏是否结束</p></li><li><p><code>utility()</code> 接受一个结束了的棋盘作为输入，并输出该棋盘的效用</p><ul><li>如果棋手 X 胜利，效用为 <code>1</code>；如果棋手 O 胜利，效用为 <code>-1</code>；如果平局，效用为 <code>0</code></li><li>只有在 <code>terminal(board)</code> 为 <code>True</code> 时才会调用该函数</li></ul></li><li><p><code>minimax()</code> 接受一个棋盘作为输入，并返回棋手在棋盘上的最佳行动</p><ul><li>返回的应该是最优行动 <code>(i, j)</code></li><li>如果多个行动是最优的，那么任意一个行动都可以被返回</li><li>如果棋盘是结束了的棋盘，返回 <code>None</code></li></ul></li></ol><hr><h1 id="1-knowledge"><a class="markdownIt-Anchor" href="#1-knowledge"></a> 1. Knowledge</h1><p>人类根据现有的知识进行推理并得出结论。人工智能也可以从知识里得出结论。</p><p>什么是」基于知识进行推理以得出结论「？</p><p>考虑以下这些句子：</p><ol><li>如果没有下雨的话，哈利今天就会去拜访海格了</li><li>哈利今天拜访了海格或邓布利多，但没有同时拜访</li><li>哈利今天拜访了邓布利多</li></ol><p>根据这三个句子，我们可以回答」今天下雨了吗？「这个问题，尽管没有一个单独的句子告诉我们关于今天是否下雨的信息。我们可以这样做：看句子 3，得知哈利拜访了邓布利多；看句子 2，得知哈利拜访了海格或邓布利多。因此我们可以得出结论：</p><ol start="4"><li>哈利没有拜访海格</li></ol><p>现在再去看句子 1，我们明白，如果没有下雨，哈利就会去拜访海格。了解了句子 4 后，我们可以得出结论：</p><ol start="5"><li>今天下雨了</li></ol><p>逻辑，我们使用了逻辑来得出结论。人工智能该如何使用逻辑在现有信息的基础上得出新的结论？</p><p>句子是人工智能存储知识并使用它来推断新信息的方式。</p><h2 id="命题逻辑"><a class="markdownIt-Anchor" href="#命题逻辑"></a> 命题逻辑</h2><p>命题逻辑以命题为基础，即可以是真的、也可以是假的、关于世界的陈述。例如上述的句子 1~5。</p><ol><li><p>命题符号</p><ul><li>最常见的是字母（<code>P</code>、<code>Q</code>、<code>R</code>），用于表示一个命题</li></ul></li><li><p>逻辑连接词</p></li></ol><ul><li>连接命题符号的逻辑符号，以便以更复杂的方式对世界进行推理</li></ul><ol><li><p><code>¬</code>，」不「符号，用于反转命题的真值。例如 <code>P</code> 是」正在下雨「，<code>¬P</code> 就是」没有下雨「</p></li><li><p><code>^</code>，」和「符号，用于连接两个不同的命题</p></li><li><p><code>∨</code>，「或」符号，只要其中一边是真，那就是真</p></li></ol><pre><code>1. 排他性“或”：如果`P^Q`为真，那`P∨Q`就是假；排他性语句只要求其中一个参数为真2. 包容性“或”：只要`P`、`Q`、`P^Q`为真，那就是真我们会更倾向于使用包容性“或”。&gt; 更多的例子：&gt;&gt; - 包容性“或”：为了吃甜点，你必须清理你的房间或者修剪草坪&gt; - 如果你清理了房间，还修剪了草坪，你仍然会吃到甜点&gt; - 排他性“或”：甜点的话，你可以吃饼干或者吃冰淇淋&gt; - 你不能同时吃到饼干和冰淇淋&gt; - 排他性“或”通常被简称为XOR，符号是⊕</code></pre><ol start="4"><li><p><code>→</code>，「暗示」符号，表示「如果 <code>P</code> 那么 <code>Q</code>」的结构。例如 <code>P</code> 是「正在下雨」，<code>Q</code> 是「我在室内」，那么 <code>p→Q</code> 意味着「如果正在下雨，那么我在室内」。这个案例中，<code>P</code> 被称为前项（antecedent），<code>Q</code> 被称为后项（consequent）</p><ul><li>如果前项为真，后项为真，那么整个暗示就为真</li><li>如果前项为真，后向为假，那么整个暗示就为假</li><li>然而，当前项为假，后项为真时，暗示总是真的</li></ul></li><li><p><code>↔</code>，「双条件」符号，或「如果 &amp; 只有当」。<code>P↔Q</code> 相当于 <code>P→Q</code> 和 <code>Q→P</code>。引用上述的例子，<code>P↔Q</code> 就是「如果正在下雨，那么我在室内」和「如果我在室内，那么正在下雨」</p></li></ol><h3 id="模型"><a class="markdownIt-Anchor" href="#模型"></a> 模型</h3><p>模型是对每个命题的真值的分配，而命题是关于世界的陈述，可以是真也可以是假。然而，关于世界的知识就体现在这些命题的真值中。模型是提供关于世界的信息的真值分配。</p><p>例如，<code>P</code> 是「正在下雨」，<code>Q</code> 是「今天是周二」，一个模型可以是以下的真值赋值：<code>{P=True, Q=False}</code>。这个模型意味着正在下雨，但今天不是周二。在这种情况下还有更多可能的模型，例如 <code>{P=True, Q=True}</code>，也就是现在既下雨，也是周二。</p><p>事实上，可能的模型的数量是命题的数量的两倍。如果我们有两个命题，那就有 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mn>2</mn><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">2^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8141079999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span> 个可能的模型。</p><h3 id="知识库"><a class="markdownIt-Anchor" href="#知识库"></a> 知识库</h3><p>知识库是一组被基于知识的代理所知道的句子，也就是人工智能以命题逻辑句子的形式提供的关于世界的知识，可以用来对世界进行额外的推断。</p><h3 id="蕴涵"><a class="markdownIt-Anchor" href="#蕴涵"></a> 蕴涵（<code>⊨</code>）</h3><p>如果 <code>α⊨β</code>，那么在任何 <code>α</code> 为真的世界中，<code>β</code> 也是真的。</p><ul><li>例如 <code>α</code> 是「这是一月中的一个周二」，<code>β</code> 是「这是一个周二」，然后 <code>α⊨β</code>。那么我们能知道这是一个在一月内的周二，并且这是一个周二</li><li>蕴含和暗示不同。暗示是两个命题间的逻辑连接词，而蕴含是一种关系，意味着如果 <code>α</code> 中所有的信息都是真，那么 <code>β</code> 中所有的信息也都是真</li></ul><h2 id="推理"><a class="markdownIt-Anchor" href="#推理"></a> 推理</h2><p>推理是指从旧的句子中推导出新的句子的过程。</p><p>例如上述的哈利波特例子中，句子 4~5 是句子 1~3 中推断出来的。</p><p>有多种方法可以在现有知识的基础上推断出新的知识。首先，我们将考虑模型检查算法（Model Checking algorithm）。</p><ul><li><p>为了确定 <code>KB⊨α</code>（换言之，回答问题「我们能否根据我们的知识库得出 <code>α</code> 为真的结论」）：</p><ul><li>列举所有可能的模型</li><li>如果每个模型中 <code>KB</code> 为真，那么 <code>α</code> 也都是真的，因此 <code>KB⊨α</code></li></ul></li><li><p>再考虑这个例子：</p><ul><li><p><code>P</code> 是「今天是星期二」，<code>Q</code> 是「现在在下雨」，<code>R</code> 是「哈利要去跑步」</p></li><li><p><code>KB</code>：<code>(P^¬Q) → R</code>，用话说就是：<code>P</code> 和 <code>¬Q</code> 暗示了 <code>R</code>。<code>P</code> 是真，<code>Q</code> 是假，那么 <code>R</code> 是真还是假？<code>KB</code> 是否 <code>⊨R</code>？</p></li><li><p>先列举出所有可能的模型</p><table><thead><tr><th>命题</th><th>值</th></tr></thead><tbody><tr><td>P<br>Q<br>R</td><td>false<br>false<br>false</td></tr><tr><td>P<br>Q<br>R</td><td>false<br>false<br>true</td></tr><tr><td>P<br>Q<br>R</td><td>false<br>true<br>false</td></tr><tr><td>P<br>Q<br>R</td><td>false<br>true<br>true</td></tr><tr><td>P<br>Q<br>R</td><td>true<br>false<br>false</td></tr><tr><td>P<br>Q<br>R</td><td>true<br>false<br>true</td></tr><tr><td>P<br>Q<br>R</td><td>true<br>true<br>false</td></tr><tr><td>P<br>Q<br>R</td><td>true<br>true<br>true</td></tr></tbody></table></li><li><p>通过每一个模型，检查它在我们的知识库中是否为真</p></li><li><p>首先，我们知道 <code>P</code> 为真，因此所有 <code>P</code> 为假的模型里，<code>KB</code> 都为假。同样地，我们知道 <code>Q</code> 为假，因此所有 <code>Q</code> 为真的模型里，<code>KB</code> 都为假。最终我们只剩下两个模型，<code>P</code> 都是真且 <code>Q</code> 都是假。我们知道 <code>R</code> 是真，因此最后 <code>R</code> 为假的模型中，<code>KB</code> 自然也是假</p></li><li><p>再来看看我们的表，我们只有一个 <code>KB</code> 为真的模型。根据蕴含的含义，得出 <code>KB⊨R</code></p></li><li><p>这些知识和逻辑可以被这样写：</p>  <pre><code class="language-python">from logic import *# 创建新的类，每个类都有一个名字或符号，代表命题rain = Symbol("rain")  # 在下雨hagrid = Symbol("hagrid")  # 哈利见海格dumbledore = Symbol("dumbledore")  # 哈利见邓布利多# 将句子保存进知识库# 先使用“和”逻辑，因为每个命题都代表了我们已知为真的知识knowledge = And( Implication(Not(rain), hagrid),  # ¬(在下雨)→(哈利见海格)    Or(hagrid, dumbledore),  # (哈利见海格)∨(哈利见邓布利多)    Not(And(hagrid, dumbledore)),  # ¬(哈利见海格^哈利见邓布利多)，但没有见两人    dumbledore  # 哈利见邓布利多（事实）)</code></pre></li><li><p>要运行模型检查算法，我们需要这些信息：</p><ul><li>知识库，用于推理</li><li>一个查询，或我们感兴趣的命题是否被 KB 所包含</li><li>一个装有所有被使用的符号（或原子命题）的列表（也就是我们案例中的 <code>rain</code>、<code>hagrid</code>、<code>dumbledore</code>）</li><li>模型</li></ul>  <pre><code class="language-python">def check_all(knowledge, query, symbols, model):    # 如果模型有分配给每个符号    # 逻辑：从一个符号列表开始。函数递归时，每次的调用都会从列表中删除一个符号，并从中生成模型。当符号列表为空时，我们知道我们已经完成了对符号的每一个可能的真值分配的模型生成    if not symbols:        # 如果在模型中的KB为真，查询也就是真        if knowledge.evaluate(model):            return query.evaluate(model)        return True        else:        # 选择剩余的未使用符号的其中一个        remaining = symbols.copy()        p = remaining.pop()                # 创建一个符号为真的模型        model_true = model.copy()        model_true[p] = True                # 创建一个符号为假的模型        model_false = model.copy()        model_false[p] = False                # 确保两个模型中都有蕴含关系        return(            check_all(knowledge, query,                       remaining, model_true)             and             check_all(knowledge, query,                       remaining, model_false)        )</code></pre></li><li><p>我们只对 <code>KB</code> 为真的模型感兴趣。如果 <code>KB</code> 为假，那么这个模型就和我们的案例无关</p><blockquote><p>例子：</p><ul><li><code>P</code> 为「哈利扮演 seeker」、<code>Q</code> 为「奥利弗扮演 keeper」，<code>R</code> 为「格兰芬多获胜」</li><li><code>KB</code> 规定 <code>P Q (P ^ Q) → R</code><ul><li>也就是 <code>P</code> 为真，<code>Q</code> 为真，那么 <code>R</code> 也为真</li></ul></li><li>想象一个模型，哈利扮演的是 beater 而非 seeker，也就是 <code>P</code> 为假。这种情况下我们并不关心格兰芬多是否胜利（即 <code>R</code> 是否为真）。因为我们只对 <code>P</code> 和 <code>Q</code> 为真的模型感兴趣</li></ul></blockquote></li><li><p>此外，<code>check_all()</code> 的工作方式是递归的。也就是说它会选择一个符号，创建两个模型，其中一个符号为真，另一个符号为假，然后再次调用自己，现在有两个模型因这个符号的真值分配而不同。这个函数会一直这样做，直到所有的符号都在模型中被分配了真值、让列表中的符号为空。一旦列表为空，函数会在每个实例中检查模型中的 KB 是否为真。如果为真，函数就会检查查询是否为真，如前面所述</p></li></ul></li></ul><h2 id="知识工程"><a class="markdownIt-Anchor" href="#知识工程"></a> 知识工程</h2><p>知识工程是弄清如何在人工智能中表示命题和逻辑的过程。</p><p>来看看例子：游戏 Clue。</p><ul><li>在这个游戏中，一个人用一个工具在一个地方犯下了一起谋杀案</li><li>人、工具、地点都用卡片表示</li><li>每个类别的卡片被随机抽取并装入一个信封，由参与者来揭开谁是凶手</li><li>参与者通过揭开卡片并从这些线索中推断出信封里一定有什么</li></ul><p>我们将使用模型检查算法来揭开这个谜团。在我们的模型中，我们把我们知道的、与谋杀案有关的项目标记为真，其余的都为假。</p><p>假设我们的游戏是这样的：</p><ul><li>有三个人：芥末、梅子、猩红</li><li>有三个工具：刀、左轮手枪、扳手</li><li>有三个地点：舞厅、厨房、图书馆</li></ul><p>我们可以通过添加游戏规则开始创建我们的知识库：</p><ol><li><p>我们肯定的是：有一个人是凶手，使用的是一种工具，而且谋杀发生在一个地点。命题逻辑：</p><ul><li><code>(芥末∨梅子∨猩红)</code></li><li><code>(刀∨左轮手枪∨扳手)</code></li><li><code>(舞厅∨厨房∨图书馆)</code></li></ul></li><li><p>游戏开始时，每个玩家会看到一个人、一个工具、一个地点，并且得知这些与谋杀没有联系。玩家们不会共享从卡片中看到的信息。假设我们的玩家得到了芥末、厨房和左轮手枪的卡片。因此我们可以添加这些命题逻辑进我们的知识库：</p><ul><li><code>¬(芥末)</code></li><li><code>¬(厨房)</code></li><li><code>¬(左轮手枪)</code></li></ul></li><li><p>在游戏的其他情况下，人们可以进行猜测，提出人、工具、地点的一种组合。假设推测是「猩红用扳手在图书馆作案」。如果这个推测是错误的，那么可以推导出以下内容：</p><ul><li><code>(¬猩红∨¬图书馆∨¬扳手)</code></li></ul></li><li><p>现在有人给我们看到了梅子的卡片，我们可以添加这个到我们的知识库：</p><ul><li><code>¬(梅子)</code></li></ul></li><li><p>这时我们可以得出结论，凶手是猩红，因为我们有证据表明另外两个人不是</p></li><li><p>只要在增加一个知识，比如说，不是舞厅，就可以给我们更多的信息：</p><ul><li><code>¬(舞厅)</code></li></ul></li><li><p>现在利用之前的多个数据，我们可以推断出是猩红在图书馆内用刀杀了人。然而这个猜测是错的，因为我们没有证据表明凶器具体是什么。最终的结论是刀</p></li></ol><p>整个流程在 Python 中就是：</p><pre><code class="language-python"># 添加线索至知识库knowledge = And(    # 添加游戏起始条件    Or(mustard, plum, scarlet),    Or(ballroom, kitchen, library),    Or(knife, revolver, wrench),        # 添加我们所看到的第一组卡片    Not(mustard),    Not(kitchen),    Not(revolver),        # 添加他人举出的猜测    Or(Not(scarlet), Not(library), Not(wrench)),        # 添加我们之后得知的线索    Not(plum),    Not(ballroom))</code></pre><p>我们还可以看看另外一个逻辑谜题：</p><ul><li><p>有四个不同的人：吉尔德洛依、波莫纳、密涅瓦、霍勒斯</p></li><li><p>他们被分配到四个不同的学院：格兰芬多、赫夫帕夫、拉文克劳、斯莱特林</p></li><li><p>每个学院正好有一个人</p></li></ul><p>首先，这个谜题的条件很难被命题逻辑来表示，因为每一个可能的分配都是一个命题。其次为了表示每个人都属于某个学院，就需要 <code>Or()</code> 来包含所有每个人可能的学院分配情况。接着，为了说明如果有一个人被分配到一个学院，他们就不会被分配到其他学院，我们还要给每个人写一大堆命题。</p><p>另一种可以用命题逻辑解决的谜题是 Mastermind。</p><ul><li>玩家 1 按照一定的顺序排列颜色，玩家 2 要猜出该顺序</li><li>每个回合里，玩家 2 做出猜测，玩家 1 给出一个数字，表示玩家 2 猜对了多少种颜色</li></ul><ol><li>假设玩家 2 猜测「红蓝绿黄」，玩家 1 给出数字 2</li><li>玩家 2 仅切换 2 个颜色的位置：「蓝红绿黄」，玩家 1 给出数字 0</li><li>借此得知，红蓝原先的位置是正确的，这时切换另外 2 个颜色的位置：「红蓝黄绿」，玩家 1 给出数字 4，代表游戏结束。</li></ol><ul><li>用命题逻辑来表示这一点，需要我们有 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo><mtext>颜色的数量</mtext><msup><mo stretchy="false">)</mo><mn>2</mn></msup></mrow><annotation encoding="application/x-tex">(\text {颜色的数量})^2</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1.064108em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord text"><span class="mord cjk_fallback">颜色的数量</span></span><span class="mclose"><span class="mclose">)</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight">2</span></span></span></span></span></span></span></span></span></span></span> 个原子命题。因此在有四种颜色的情况下，我们将有红 0、红 1、红 2、红 3、蓝 0…… 这些命题代表着颜色和位置</li><li>用命题逻辑表示游戏规则，也就是每个位置只有一种颜色，而且没有颜色重复，并将其加入知识库</li><li>最后将我们拥有的所有线索添加到知识库中</li></ul><h2 id="推理规则"><a class="markdownIt-Anchor" href="#推理规则"></a> 推理规则</h2><p>模型检查不是一种有效的算法，因为它必须在给出答案之前考虑每一种可能的模型。</p><blockquote><p>如果是 <code>KB</code> 为真的模型，那么查询 <code>R</code> 也是真的</p></blockquote><p>推理规则允许我们在现有知识的基础上生成新的信息，而无需考虑每一个可能的模型。推理规则通常使用一个横条来表示，横条将上面的部分（前提）和下面的部分（结论）分开。前提是我们拥有的任何知识，而结论是基于前提可以产生的知识。</p><p><img src="/posts/d235/Modus_Ponens_Example.webp" alt="Modus Ponens Example" loading="lazy"></p><h3 id="肯定前件"><a class="markdownIt-Anchor" href="#肯定前件"></a> 肯定前件</h3><p>肯定前件（Modus Ponens）就是在我们知道一个暗示、其前项是真的，那么后项也是真的。</p><p><img src="/posts/d235/Modus_Ponens.webp" alt="Modus Ponens" loading="lazy"></p><h3 id="连词消除"><a class="markdownIt-Anchor" href="#连词消除"></a> 连词消除</h3><p>也被称为和消除（And Elimination）。</p><p>如果一个「和」的命题为真，那么其中任何一个原子命题也是真。</p><blockquote><p>例子：</p><ul><li>已知：哈利是罗恩和赫敏的朋友</li><li>结论：哈利是赫敏的朋友</li></ul></blockquote><p><img src="/posts/d235/And_Elimination.webp" alt="And Elimination" loading="lazy"></p><h3 id="双重否定"><a class="markdownIt-Anchor" href="#双重否定"></a> 双重否定</h3><p>一个命题如果被否定了两次，那它就是真。</p><blockquote><p>例子：哈利没有通过考试是不真实的。</p><ol><li><code>(哈利没有通过考试)是不真实的</code></li><li><code>¬(哈利没有通过考试)</code></li><li><code>¬(¬(哈利没有通过考试))</code></li><li>双重否定抵消了彼此，让该命题「哈利通过了考试」变为真</li></ol></blockquote><p><img src="/posts/d235/Double_Negation_Elimination.webp" alt="Double Negation Elimination" loading="lazy"></p><h3 id="暗示消除"><a class="markdownIt-Anchor" href="#暗示消除"></a> 暗示消除</h3><p>暗示相当于被否定的前项和后项之间的「或」关系。</p><blockquote><p>例子：以下等同于彼此</p><ul><li>如果下雨了，那么哈利在室内</li><li>（没有下雨） 或（哈利在室内）</li></ul></blockquote><p><img src="/posts/d235/Implication_Elimination.webp" alt="Implication Elimination" loading="lazy"></p><p>由于 <code>P→Q</code> 和 <code>P∨Q</code> 有相同的真值分配，因此在逻辑上是等价的。</p><p>另一种思考方式是如果满足两个可能的条件中的任何一个，暗示就是真的：</p><ol><li>如果前项为假，那么暗示为真<ul><li><code>¬P∨Q</code>：如果 <code>P</code> 为假，那么这个命题总是真的</li></ul></li><li>如果前项为真，只有当后项为真时，暗示才为真<ul><li>如果 <code>P</code> 和 <code>Q</code> 都是真，那么 <code>¬P∨Q</code> 就为真</li><li>如果 <code>P</code> 为真，<code>Q</code> 为假，那么 <code>¬P∨Q</code> 就为假</li></ul></li></ol><h3 id="双条件消除"><a class="markdownIt-Anchor" href="#双条件消除"></a> 双条件消除</h3><p>一个双条件命题等同于一个暗示命题和其翻转命题用「和」连接在一起。</p><blockquote><p>例子：以下等同于彼此。</p><ul><li>只有在哈利在室内的时候，外面才会下雨</li><li>（如果下雨了，那么哈利在室内） 和（如果哈利在室内，那么外面在下雨）</li></ul></blockquote><p><img src="/posts/d235/Biconditional_Elimination.webp" alt="Biconditional_Elimination" loading="lazy"></p><h3 id="德摩根定律"><a class="markdownIt-Anchor" href="#德摩根定律"></a> 德摩根定律</h3><p>有可能把一个「和」连接词变成一个「或」连接词。例如：「哈利和罗恩都通过了测试，这不是真的」，可以得出结论：「哈利通过考试不是真的」或者「罗恩通过考试不是真的」。也就是说，要使前面的「和」命题为真，「或」命题中的至少一个命题必须为真。</p><p><img src="/posts/d235/De_Morgans_1.webp" alt="De Morgan's 1" loading="lazy"></p><p>同样地，也可以得出相反的结论。例如命题「哈利或罗恩通过测试是不真实的」可以被改写为「哈利没有通过测试」和「罗恩没有通过测试」。</p><h3 id="分配律"><a class="markdownIt-Anchor" href="#分配律"></a> 分配律</h3><p>一个由两个元素组成的命题，如果使用「和」或「或」连接词来分组，那就可以被分配或分解成由「和」和「或」组成的更小的单元。</p><p><img src="/posts/d235/Distributive_1.webp" alt="Distributive 1" loading="lazy"></p><h3 id="知识和搜索问题"><a class="markdownIt-Anchor" href="#知识和搜索问题"></a> 知识和搜索问题</h3><p>推理可以被看作是一个具有以下属性的搜索问题：</p><ul><li>初始状态：起始初始库</li><li>行动：推理规则</li><li>过渡模型：推理中的新知识库</li><li>目标测试：检查我们要证明的语句是否在知识库内</li><li>路径成本函数：证明中的步骤数量</li></ul><p>这些都表示了搜索算法的多功能性，使我们能够在现有知识的基础上利用推理规则得出新的信息。</p><h2 id="归结原理"><a class="markdownIt-Anchor" href="#归结原理"></a> 归结原理</h2><p>归结原理（resolution）是一个强大的推理规则。如果「或」命题中的两个原子命题中的一个为假，那么另外一个就必须为真。</p><p><img src="/posts/d235/Resolution_1.webp" alt="Resolution" loading="lazy"></p><p>归结原理依赖于互补文字（complementary literals），即两个相同的原子命题，其中一个被否定，另一个没有被否定。</p><p><img src="/posts/d235/Resolution_2.webp" alt="Resolution" loading="lazy"></p><p>互补文字使我们能够通过解析推理产生新的句子。因此推理算法通过定位互补文字来生成新的知识。</p><p>一个从句是一个字词的二元链接（一个命题符号或者一个命题符号的否定）。分句由一个「或」逻辑连接词（<code>P∨Q∨R</code>）连接。另一方面，连词由「和」逻辑连接词相连的的命题组成（<code>P^Q^R</code>）。</p><p>分句允许我们把任何逻辑语句转换成合取范式（CNF），也就是分句的连接，例如：</p><ul><li><code>(A∨B∨C)^(D∨¬E)^(F∨G)</code></li></ul><p>将命题转换为合取范式的步骤：</p><ol><li>消除双条件；将 <code>α↔β</code> 变成 <code>(α→β)^(β→α)</code></li><li>消除暗示；将 <code>α→β</code> 变成 <code>¬α∨β</code></li><li>使用德摩根定律，将否定向内移动，直到只有文字被否定；将 <code>¬(α∨β)</code> 变为 <code>¬α∨¬β</code></li></ol><blockquote><p>更多的例子：<code>(P∨Q)→R</code></p><ol><li><code>¬(P∨Q)∨R</code>，消除暗示</li><li><code>(¬P∨¬Q)∨R</code>，德摩根定律</li><li><code>(¬P∨R)^(¬Q∨R)</code>，分配律</li></ol></blockquote><p>在这一点上，我们可以对合取范式运行推理算法。偶尔在解析推理的过程中我们会遇到这样的情况：一个子句包含两次相同的文字。我们会需要使用一个叫做分解（factoring）的过程，将重复的文字删除。</p><blockquote><p>例子：</p><p><code>(P∨Q∨S)^(¬P∨R∨S)</code> 允许我们通过解析推断 <code>(Q∨S∨R∨S)</code>。重复的 S 会被删除，得到 <code>(Q∨R∨S)</code>。</p></blockquote><p>消除一个文字和它的否定，也就是 <code>¬P</code> 和 <code>P</code>，可以得到空的分句。空句总是假，因为 <code>P</code> 和 <code>¬P</code> 不可能都是真：</p><ul><li>确定 KB 是否 <code>⊨α</code>：<ul><li>检查：<code>(KB^¬α)</code> 是否是矛盾的？<ul><li>如果是，则 <code>KB⊨α</code></li><li>如果否，则没有蕴含关系</li></ul></li></ul></li></ul><p>矛盾证明是计算机科学中经常使用的一种工具。如果我们的知识库为真，而它与 <code>¬α</code> 相矛盾。这意味着 <code>¬α</code> 为假。因此 <code>α</code> 绝对为真。</p><ul><li>确定 <code>KB</code> 是否 <code>⊨α</code>：<ul><li>将 <code>(KB^¬α)</code> 转换为合取范式</li><li>继续检查，看我们能否用归结原理产生一个新的分句</li><li>如果产生了一个空句，代表我们得到了一个矛盾，从而证明 <code>KB⊨α</code></li><li>如果没有产生矛盾，也没有更多的子句可以被推断出来，也就没有蕴含关系</li></ul></li></ul><blockquote><p>例子：<code>(A∨B)^(¬B∨C)^(¬C)</code> 是否蕴含 A？</p><ol><li>用矛盾法证明。假设 A 为假，那就会得出 <code>(A∨B)^(¬B∨C)^(¬C)^(¬A)</code></li><li>既然我们知道 <code>C</code> 为假（因为 <code>¬C</code>），那么 <code>(¬B∨C)</code> 的唯一可能是 B 也是假的，这样 <code>¬B</code> 就为真（将 <code>¬B</code> 加入到我们的知识库）</li><li><code>(A∨B)</code> 的唯一可能是 <code>A</code> 为真（将 A 加入我们的知识库）</li><li>现在知识库中有两个互补的文字：<code>A</code> 和 <code>¬A</code>。我们得到了一个空的集合，根据定义，空的集合为假，所以我们得到了一个矛盾</li></ol></blockquote><h2 id="一阶逻辑"><a class="markdownIt-Anchor" href="#一阶逻辑"></a> 一阶逻辑</h2><p>一阶逻辑（First-Order Logic）是另一种类型的逻辑，它允许我们比命题逻辑更简洁地表达更复杂的想法。一阶逻辑使用两种类型的符号：常量符号和谓词符号。</p><ul><li>常量符号代表对象</li><li>谓词符号更像是关系或函数，接受一个参数并返回一个真或假的值</li></ul><p>回到逻辑谜题：在霍格沃茨有不同的人和房子的分配。常量符号是人或者学院，而谓词符号就是一些持有常量符号真或假的属性。</p><blockquote><p>例子：</p><ul><li>使用句子 <code>Person(Minerva)</code> 来表达 Minerva 是一个人</li><li>使用句子 <code>House(Gryffindor)</code> 来表达格兰芬多是一个学院</li></ul></blockquote><p>所有的逻辑连接词在一阶逻辑中的使用方式与命题逻辑的相同。</p><blockquote><p>例子：</p><ul><li><code>¬House(Minerva)</code> 表达了 Minerva 不是一个学院</li></ul></blockquote><p>一个谓词符号也可以接受两个或以上的参数，并表达它们之间的关系。</p><blockquote><p>例子：</p><ul><li><code>BelongsTo</code> 表达了两个参数之间的关系，即人和人所属的房子</li><li>Minerva 属于格兰芬多可以写成：<code>BelongsTo(Minerva, Gryffindor)</code></li></ul></blockquote><h3 id="全称量化"><a class="markdownIt-Anchor" href="#全称量化"></a> 全称量化</h3><p>量化是一种工具，可以在一阶逻辑中用来表示句子而不使用特定的常数符号。全称量化使用符号 <code>∀</code> 来表达」对于所有「（for all）。</p><blockquote><p>例子：<code>∀x.BelongsTo(x, Gryffindor) -&gt; ¬BelongsTo(x, Hufflepuff)</code>，表达了对于所有符号来说，如果这个符号属于格兰芬多，那么它就不属于赫夫帕夫。</p></blockquote><h3 id="存在量化"><a class="markdownIt-Anchor" href="#存在量化"></a> 存在量化</h3><p>存在量化是一个与全称量化平行的概念。然而，全称量化被用来创建对所有 <code>x</code> 都为真的句子，存在量化被用来创建对至少一个 <code>x</code> 为真的句子。存在量化使用符号 <code>∃</code> 来表示。</p><blockquote><p>例子：<code>∃x.House(x)^BelongsTo(Minerva, x)</code>，意味着至少有一个符号既是学院，Minerva 也属于它。</p><p>换句话说，这表达了 Minerva 属于一个学院的想法。</p></blockquote><p>存在量化和全称量化可以在同一个句子中使用。</p><blockquote><p>例子：<code>∀x.Person(x) -&gt; (∃x.House(y)^BelongsTo(x,y))</code> 表达的意思是如果 <code>x</code> 是一个人，那么至少有一个学院 <code>y</code> 是这个人的归属。</p><p>换句话说，这个句子意味着每个人都属于一个学院。</p></blockquote><h2 id="测验"><a class="markdownIt-Anchor" href="#测验"></a> 测验</h2><ol><li><p>考虑以下逻辑句子：</p><ol><li>如果赫敏在图书馆内，那么哈利就在图书馆内</li><li>赫敏在图书馆内</li><li>罗恩在图书馆并且罗恩不在图书馆内</li><li>哈利在图书馆内</li><li>哈利不在图书馆内或赫敏在图书馆内</li><li>罗恩在图书馆内或赫敏在图书馆内</li></ol><p>哪个逻辑蕴含为真：</p><ul><li>句子 6 蕴含了句子 3</li><li>句子 6 蕴含了句子 2</li><li>句子 2 蕴含了句子 5</li><li>句子 5 蕴含了句子 6</li><li>句子 1 蕴含了句子 4</li><li>句子 2 蕴含了句子 2</li></ul></li><li><p>表达式 <code>A⊕B</code> 表示句子 "A 或 B，但不是全部为真"。以下哪个在逻辑上等同于 <code>A⊕B</code>：</p><ul><li><code>(A ∨ B) ∧ ¬ (A ∧ B)</code></li><li><code>(A ∨ B) ∧ (A ∧ B)</code></li><li><code>(A ∧ B) ∨ ¬ (A ∨ B)</code></li><li><code>(A ∨ B) ∧ ¬ (A ∨ B)</code></li></ul><blockquote><p>答案：<code>(A ∨ B) ∧ ¬ (A ∧ B)</code></p><p>解析：(A 或者 B）和 不是（A 和 B)</p></blockquote></li><li><p><code>R</code> 是」现在下雨「，<code>C</code> 是」现在多云「，<code>S</code> 是」现在晴天「。哪个表达了」如果现在下雨，那么现在是多云而不是晴天「：</p><ul><li><p><code>(R → C) ∧ ¬S</code></p></li><li><p><code>R → C → ¬S</code></p></li><li><p><code>R ∧ C ∧ ¬S</code></p></li><li><p><code>R → (C ∧ ¬S)</code></p></li><li><p><code>(C ∨ ¬S) → R</code></p></li></ul><blockquote><p>答案：<code>R → (C ∧ ¬S)</code></p><p>解析：（现在下雨） 暗示（现在多云 和 不是（现在晴天）)</p></blockquote></li><li><p><code>Student(x)</code> 代表了」x 是一个学生「；<code>Course(x)</code> 代表了」x 是一个课程「；<code>Enrolled(x,y)</code> 代表了」x 入学了 y「。哪个一阶逻辑句子代表了」哈利和赫敏同时入学了的课程「：</p><ul><li><p><code>∃x. Enrolled(Harry, x) ∨ Enrolled(Hermione, x)</code></p></li><li><p><code>∀x. Enrolled(Harry, x) ∨ Enrolled(Hermione, x)</code></p></li><li><p><code>∀x. Course(x) ∧ Enrolled(Harry, x) ∧ Enrolled(Hermione, x)</code></p></li><li><p><code>∃x. Course(x) ∧ Enrolled(Harry, x) ∧ Enrolled(Hermione, x)</code></p></li><li><p><code>∀x. Enrolled(Harry, x) ∧ ∀y. Enrolled(Hermione, y)</code></p></li><li><p><code>∃x. Enrolled(Harry, x) ∧ ∃y. Enrolled(Hermione, y)</code></p></li></ul><blockquote><p>答案：<code>∃x. Course(x) ∧ Enrolled(Harry, x) ∧ Enrolled(Hermione, x)</code></p><p>解析：(x 是一个课程） 和（哈利入学了 x）和（赫敏入学了 x)；存在量化：至少有一个课程，并且哈利属于它，赫敏也属于它</p></blockquote></li></ol><h2 id="作业knights"><a class="markdownIt-Anchor" href="#作业knights"></a> 作业 Knights</h2><p>1978 年，逻辑学家 Raymond Smullyan 出版了《这本书叫什么名字？》。这是一本逻辑谜题书。在这本书中，有一类谜题被 Smullyan 称作为」骑士和无赖「（Knights and Knaves）。</p><p>在这个谜题中，以下信息被给出：</p><ul><li>每个角色要么是骑士，要么就是无赖</li><li>骑士总是说真话，而无赖总是撒谎</li></ul><p>这个迷题的目的是，给定一组由每个角色说出的句子，对于每个角色，确定该角色是骑士还是无赖。</p><p>例如单个角色 A，它说」我既是骑士也是无赖「。根据逻辑，我们可以推断这句话不可能为真。因此 A 一定是无赖。</p><h3 id="分发代码-3"><a class="markdownIt-Anchor" href="#分发代码-3"></a> 分发代码</h3><p>瞅瞅 logic.py 文件，它定义了一些用于不同类型的逻辑连接词的类。这些类可以互相组成，例如 <code>And(Not(A), Or(B, C))</code> 这样的表达式代表了一个逻辑句子，说明 <code>A</code> 不是真的，而 <code>B</code> 或 <code>C</code> 是真。</p><p>该文件还有一个函数 <code>model_check()</code>，它接收一个知识库和一个查询作为参数。知识库是一个单一的逻辑句子：如果多个逻辑句子是已知的，它们就可以被连接到一个 <code>And()</code> 中。<code>model_check()</code> 递归地考虑了所有可能的模型。如果知识库包含了查询，就返回 <code>True</code>，否则返回 <code>False</code>。</p><p><a href="http://xn--puzzle-200ky68hgexroha.py">现在来看看 puzzle.py</a>。在顶部有六个命题符号被定义，例如 <code>AKnight</code> 表示」A 是一个骑士「，而 <code>AKnave</code> 表示」A 是一个无赖「。我们也同样为人物 B 和 C 定义了命题符号。</p><p>下面还有四个不同的知识库：<code>knowledge0</code>、<code>knowledge1</code>、<code>knowledge2</code>、<code>knowledge3</code>，它们将分别包含推导谜题所需的知识。</p><p>puzzle.py 的主函数在所有谜题上循环，并使用模型检查来计算，给定该谜题的知识并打印出模型检查算法能够得出的任何结论。</p><h3 id="目标-3"><a class="markdownIt-Anchor" href="#目标-3"></a> 目标</h3><p>将知识添加到知识库中，以解决下列谜题：</p><ol><li>A 说」我既是骑士也是无赖「</li><li>A 说」我们都是骑士「；B 没有说话</li><li>A 说「我们是同类人」；B 说「我们是不同类的人」</li><li>A 要么说了「我是一个骑士」，要么说了「我是一个无赖」，但是你不知道；B 说「A 说了他是一个无赖」；C 说「A 是一个骑士」</li></ol><h2 id="作业minesweeper"><a class="markdownIt-Anchor" href="#作业minesweeper"></a> 作业 minesweeper</h2><p>扫雷是一个益智游戏，由一个单元格组成，其中一些单元格中隐藏着地雷。点击含有地雷的单元格会引爆地雷，并导致用户输掉游戏。点击一个安全的单元格会显示一个数字，表明有多少个相邻的单元格含有炸弹。</p><h3 id="命题逻辑-2"><a class="markdownIt-Anchor" href="#命题逻辑-2"></a> 命题逻辑</h3><p>你在这个项目中的目标是建立一个能玩扫雷游戏的人工智能。我们可以用一种方法来表示人工智能对扫雷游戏的了解，那就是让每个单元格成为一个命题变量，如果该单元格含有地雷，则为真，否则就是假。</p><p>人工智能会知道每次点击安全的单元格时显示的数字。</p><p><img src="/posts/d235/Middle_Safe.webp" alt="Middle cell with labeled neighbors" loading="lazy"></p><p>用上图作为例子，我们知道八个相邻的单元格中会有一个是地雷。因此我们可以写一个像下面这样的逻辑表达式来表示相邻单元格中的一个是地雷：<code>Or(A,B,C,D,E,F,G,H)</code>。</p><p>但实际上我们知道的要比这个表达式所说的要多。上面这个逻辑句子表达的是这八个变量中至少有一个是真的，但我们可以做一个比这更有力的声明：我们知道这八个变量中只有一个是真的。那就是：</p><pre><code class="language-python">Or(    And(A, Not(B), Not(C), Not(D), Not(E), Not(F), Not(G), Not(H)),    And(Not(A), B, Not(C), Not(D), Not(E), Not(F), Not(G), Not(H)),    And(Not(A), Not(B), C, Not(D), Not(E), Not(F), Not(G), Not(H)),    And(Not(A), Not(B), Not(C), D, Not(E), Not(F), Not(G), Not(H)),    And(Not(A), Not(B), Not(C), Not(D), E, Not(F), Not(G), Not(H)),    And(Not(A), Not(B), Not(C), Not(D), Not(E), F, Not(G), Not(H)),    And(Not(A), Not(B), Not(C), Not(D), Not(E), Not(F), G, Not(H)),    And(Not(A), Not(B), Not(C), Not(D), Not(E), Not(F), Not(G), H))</code></pre><p>嗯…… 是不是太复杂了？这只是为了表达一个单元格中有 1。如果单元格中有 2 或者 3 或者其他的值，表达式可能会更长。</p><p>试图对这种类型的问题进行模型检查，也会很快变得难以解决：在一个 8x8 的网格上，也就是简单模式会用的尺寸，我们会有 64 个变量，因此有 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msup><mn>2</mn><mn>64</mn></msup></mrow><annotation encoding="application/x-tex">2^{64}</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8141079999999999em;vertical-align:0em;"></span><span class="mord"><span class="mord">2</span><span class="msupsub"><span class="vlist-t"><span class="vlist-r"><span class="vlist" style="height:0.8141079999999999em;"><span style="top:-3.063em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">6</span><span class="mord mtight">4</span></span></span></span></span></span></span></span></span></span></span></span> 个可能的模型需要检查。对于一台计算机来说，在任何合理的时间内计算的数量都太多了。对于这个问题，我们需要一个更好的知识来表示。</p><h3 id="知识表示"><a class="markdownIt-Anchor" href="#知识表示"></a> 知识表示</h3><p>又称知识重呈、知识表现、知识表征……</p><p>我们将像这样表示人工智能的每一句知识：<code>{A,B,C,D,E,F,G,H}=1</code>。</p><p>这个表达式中的每个逻辑句子都有两个部分：黑板上涉及该句子的一组单元格，以及一个数字计数，代表这个单元格中有多少是地雷的计数。上面的逻辑句子表示了「在这八个单元格中正好有一个是地雷」。</p><h3 id="分发代码-4"><a class="markdownIt-Anchor" href="#分发代码-4"></a> 分发代码</h3><p>这个项目有两个主要文件：<a href="http://runner.xn--pyminesweeper-q59v.py">runner.py 和 minesweeper.py</a>。前者已被实现，后者包含了游戏本身和 AI 玩游戏的所有逻辑。</p><p>minesweeper.py 定义了三个类：<code>Minesweeper</code>、<code>Sentence</code>、<code>MinesweeperAI</code>。第一个处理游戏的玩法，第二个表示一个逻辑句子，第三个处理根据知识推断出要做的动作。</p><p><code>Minesweeper</code> 类已被实现。每个单元格是一对 <code>(i,j)</code>，其中 <code>i</code> 是行号（从 0 到 <code>高度-1</code>），<code>j</code> 是列号（从 0 到 <code>宽度-1</code>）。</p><p><code>Sentence</code> 类被用来表示背景中描述的逻辑句子的形式。每个句子中都有一组单元格，以及这些单元格中有多少个地雷的计数。该类还包含函数 <code>known_mines()</code> 和 <code>known_safes()</code> 用于确定句子中的任何单元格是否为已知的地雷或已知的安全区。它还包含了 <code>mark_mine()</code> 和 <code>mark_safe()</code> 用来更新句子，以应对关于一个单元格的新信息。</p><p>最后，<code>MinesweeperAI</code> 类将实现一个可以玩扫雷的 AI。这个 AI 类记录了一些数值：</p><ul><li><code>self.moves_made</code> 包含了一个装有所有已经点击过的单元格的集合，所以 AI 知道不要再去选择那些单元格</li><li><code>self.mines</code> 包含了一个装有所有已知是地雷的单元格的集合</li><li><code>self.safes</code> 包含了一个装有所有已知是安全的的单元格的集合</li><li><code>self.knowledge</code> 包含了一个装有所有人工智能已知为真的句子的列表</li></ul><p><code>mark_mine()</code> 将一个单元格添加到 <code>self.mines</code> 中。<code>mark_safe()</code> 同理。</p><hr><h1 id="2-uncertainty"><a class="markdownIt-Anchor" href="#2-uncertainty"></a> 2. Uncertainty</h1><p>在现实里，人工智能往往只拥有对世界的部分知识，剩余的空间则都是不确定性（uncertainty）。尽管如此，我们仍希望我们的人工智能在这些情况下做出最佳的决策。</p><ul><li>例如：在预测天气时，人工智能能拥有今天的天气信息，但无法百分之百准确地预测明天的天气</li></ul><p>不过我们还是可以在有限信息和不确定性地情况下创建出可以做出最佳决策的人工智能。</p><h2 id="概率"><a class="markdownIt-Anchor" href="#概率"></a> 概率</h2><p>不确定性可以被表示为一些事件及其发生的可能性或概率。</p><h3 id="可能的世界"><a class="markdownIt-Anchor" href="#可能的世界"></a> 可能的世界</h3><p>每种可能的情况都可以被看作是一个世界，用小写希腊字母 <code>ω</code> 来表示。</p><ul><li>例如：投掷骰子时可以产生六个可能的世界</li></ul><p>为了表示某个世界的概率，我们使用 <code>P(ω)</code>。</p><h3 id="概率的公理"><a class="markdownIt-Anchor" href="#概率的公理"></a> 概率的公理</h3><p>概率的公式为 <code>0 &lt; P(ω) &lt; 1</code>，每个表示概率的值必须在 0 和 1 之间。0 是不可能发生的事件，比如投掷骰子时得到了点数 7；1 是一定会发生的事件，比如投掷一个标准骰子得到一个小于 10 的点数。通常值越高，事件发生的可能性就越大。每个可能事件的概率加起来等于 1。</p><p><img src="/posts/d235/Lotp.webp" alt="Summing Probabilities" loading="lazy"></p><p>用标准骰子掷出一个数字 <code>R</code> 的概率可以表示为 <code>P(R)</code>。在我们的例子中，<code>P(R) = 1/6</code>，因为有六个可能的世界，每个都同样可能发生。现在考虑一下投掷两个骰子的事件，一下就有了 36 种可能的事件。</p><p><img src="/posts/d235/36_Events.webp" alt="36 Events" loading="lazy"></p><p>但是，如果我们试图预测两个骰子的和会发生什么？在这种情况下，我们只有 11 个可能的值。</p><p><img src="/posts/d235/Sum_Of_Two_Dice.webp" alt="Sum of Two Dice" loading="lazy"></p><p>要得到一个事件的概率，我们要将它发生的世界数除以所有可能的世界数。例如，投掷两个骰子时会有 36 个可能的世界。只有在其中一个世界里，当两个骰子都掷出 6 时，我们才能得到 12 的总和。因此 <code>P(12) = 1/36</code>。</p><ul><li>例子：<code>P(7)</code> 的概率是多少？7 出现在六个世界中，因此 <code>P(7) = 6/36 = 1/6</code></li></ul><h3 id="无条件概率"><a class="markdownIt-Anchor" href="#无条件概率"></a> 无条件概率</h3><p>无条件概率是在没有其他证据的情况下对一个命题的信度。我们迄今为止提出的所有问题都是无条件概率的问题，因为掷骰子的结果不依赖于先前的事件。</p><h2 id="条件概率"><a class="markdownIt-Anchor" href="#条件概率"></a> 条件概率</h2><p>条件概率是在已经揭示了一些证据的情况下对一个命题的信度。如前言所述，人工智能可以利用部分信息对未来做出有根据的猜测。为了使用这些信息，它们会影响事件在未来发生的概率，我们依赖于条件概率。</p><p>条件概率用 <code>P(a | b)</code> 来表示，意思是「在我们知道事件 b 已经发生的情况下，事件 a 发生的概率」。</p><ul><li>例如：如果昨天下雨了，今天下雨的概率是多少？ -&gt; <code>P(今天下雨 | 昨天下雨)</code></li></ul><p><img src="/posts/d235/Conditional.webp" alt="Conditional Probability Formula" loading="lazy"></p><p>换句话说，给定 b 为真的 a 的概率等同于 a 和 b 都为真的概率除以 b 的概率。</p><p>一种直观的推理方法是这样的：「我们对 a 和 b 都为真的事件感兴趣（分子），但只来自我们知道 b 为真的世界（分母）」</p><p><img src="/posts/d235/Conditional_Equivalent.webp" alt="Equivalent Formulas" loading="lazy"></p><p>计算一下 <code>P(总和为12 | 在骰子上掷出6)</code>。首先我们要把我们的世界限制在第一个骰子的点数为 6 的世界。其次我们要得出在我们限制了问题的世界中，事件 a（总和为 12）发生了多少次（除以 <code>P(b)</code>，即第一个骰子掷出 6 的概率）。</p><p><img src="/posts/d235/Sum_Conditional_2.webp" alt="Conditioned Probability" loading="lazy"></p><h2 id="随机变量"><a class="markdownIt-Anchor" href="#随机变量"></a> 随机变量</h2><p>随机变量是概率论中具有可能取值域的变量。</p><ul><li>例如：为了表示掷骰子时的可能结果，我们可以定义一个随机变量 <code>Roll</code>，它可以取值 <code>{0, 1, 2, 3, 4, 5, 6}</code>；为了表示航班的状态，我们可以定义一个变量 <code>Flight</code>，它可以取值 <code>{准时, 延误, 取消}</code></li><li>通常我们会对每个值发生的概率感兴趣，这一点可以使用概率分布来表示：<ul><li><code>P(Flight = 准时) = 0.6</code></li><li><code>P(Flight = 延误) = 0.3</code></li><li><code>P(Flight = 取消) = 0.1</code></li></ul></li><li>概率分布可以更简洁地表示为向量：<ul><li><code>P(Flight) = &lt;0.6, 0.3, 0.1&gt;</code></li></ul></li><li>为了使这种表示法可解释，值必须有一个固定的顺序（在我们的例子里，就是准时、延误、取消）</li></ul><h3 id="独立性"><a class="markdownIt-Anchor" href="#独立性"></a> 独立性</h3><p>独立性指的是一个事件的发生不影响另一个事件的概率。</p><ul><li>例如：当投掷两个骰子时，每个骰子的结果都与另一个骰子独立。这与依赖事件相反，比如早上的云和下午的雨（如果早上多云，那么下午下雨的可能性就更大）</li></ul><p>独立性可以用数学定义：当且仅当 a 和 b 的概率等于 a 的概率乘以 b 的概率时，事件 a 和 b 是独立的：<code>P(a ∧ b) = P(a)P(b)</code>。</p><h2 id="贝叶斯定理"><a class="markdownIt-Anchor" href="#贝叶斯定理"></a> 贝叶斯定理</h2><p>贝叶斯定理通常用于概率论中计算条件概率。给定 a 的 b 的概率等于给定 b 的 a 的概率乘以 b 的概率，除以 a 的概率。</p><p><img src="/posts/d235/Bayes_Rule.webp" alt="Bayes' Rule" loading="lazy"></p><ul><li>例如：计算如果早上有云，下午下雨的概率（也就是 <code>P(雨 | 云)</code>）<ul><li>80% 的下午下雨始于早晨的多云，即 <code>P(云 | 雨)</code></li><li>40% 的日子是早上多云，即 <code>P(云)</code></li><li>10% 的日子是下午下雨，即 <code>P(雨)</code></li></ul></li><li>应用贝叶斯定理，<code>(0.1)(0.8)/(0.4) = 0.2</code>。也就是说，如果早上多云，那么下午下雨的概率为 20%</li></ul><p>知道了 <code>P(a | b)</code> 后还可以让我们计算出 <code>P(b | a)</code>。知道一个可见效果给定一个未知原因的条件概率（<code>P(可见效果 | 未知原因)</code>）可以让我们计算出未知原因给定可见效果的概率（<code>P(未知原因 | 可见效果)</code>）。</p><ul><li>例如：我们可以通过医学试验来了解 <code>P(医学检查结果 | 疾病)</code>，在那里我们测试患有疾病的人并看看测试多久能检测到。知道这一点，我们可以计算出 <code>P(疾病 | 医学检查结果)</code>，即宝贵的诊断信息</li></ul><h2 id="联合概率"><a class="markdownIt-Anchor" href="#联合概率"></a> 联合概率</h2><p>联合概率是多个事件都发生的可能性。考虑一下关于早上多云和下午下雨的概率的例子：</p><ul><li><code>C = cloud</code>，0.4</li><li><code>C = ¬cloud</code>，0.6</li><li><code>R = rain</code>，0.1</li><li><code>R = ¬rain</code>，0.9</li></ul><p>我们无法说早上多云是否与下午下雨的可能性有关。为了能够这样做，我们需要看两个变量的所有可能结果的联合概率：</p><table><thead><tr><th></th><th><code>C = cloud</code></th><th><code>C = ¬cloud</code></th></tr></thead><tbody><tr><td><code>R = rain</code></td><td>0.08</td><td>0.02</td></tr><tr><td><code>R = ¬rain</code></td><td>0.32</td><td>0.58</td></tr></tbody></table><p>使用联合概率，我们可以推导出条件概率。</p><ul><li>例如：我们对下午下雨时早上多云的概率分布感兴趣。<code>P(C | 雨) = P(C, 雨)/P(雨)</code>（在概率中，逗号和 <code>∧</code> 可以互换使用）<ul><li>在最后一个方程中，可以将 <code>P(雨)</code> 视为乘以 <code>P(C, 雨)</code> 的某个常数</li><li>因此我们可以重写 <code>P(C, 雨)/P(雨) = αP(C, 雨)</code> 或 <code>α&lt;0.08, 0.02&gt;</code></li><li>提取 <code>α</code> 后，我们得到了 <code>C</code> 在下午下雨时可能值的概率比例</li><li>也就是说，如果下午下雨，那么早上多云和早上没有云的概率比例是 <code>0.08 : 0.02</code><ul><li>注意 0.08 和 0.02 并不加起来等于 1；然而，由于这是随机变量 C 的概率分布，我们知道它们应该加起来等于 1</li><li>因此，我们需要通过计算 α 使 <code>α0.08 + α0.02 = 1</code> 来归一化这些值。最后，我们可以说 <code>P(C | 雨) = &lt;0.8, 0.2&gt;</code></li></ul></li></ul></li></ul><h2 id="概率规则"><a class="markdownIt-Anchor" href="#概率规则"></a> 概率规则</h2><ul><li><p>否定：<code>P(¬a) = 1 - P(a)</code></p><ul><li>源于所有可能的世界的概率总和为 1，而补充文字 <code>a</code> 和 <code>¬a</code> 包括了所有的可能的世界</li></ul></li><li><p>容斥：<code>P(a ∨ b) = P(a) + P(b) - P(a ∧ b)</code></p><ul><li><code>a</code> 或 <code>b</code> 为真的世界等于所有 <code>a</code> 为真的世界加上 <code>b</code> 为真的世界</li><li>然而在这种情况下，有些世界会被多次计算（即 <code>a</code> 和 <code>b</code> 都为真的世界）。为了消除这种重叠，我们减去一次 <code>a</code> 和 <code>b</code> 都为真的世界<ul><li>例如：我有 80% 的时间吃冰淇淋、70% 的时间吃饼干。如果我们在计算今天吃冰淇淋或饼干 <code>P(冰淇淋 ∨ 饼干)</code> 时不减去 <code>P(冰淇淋 ∧ 饼干)</code>，我们就会错误地得到 <code>0.7 + 0.8 = 1.5</code>，这与概率在 0 和 1 之间的公理相互矛盾</li></ul></li></ul></li><li><p>边缘化：<code>P(*a*) = P(*a, b*) + P(*a, ¬b*)</code></p><ul><li><p><code>b</code> 和 <code>¬b</code> 是不相交的概率，或者说，<code>b</code> 和 <code>¬b</code> 同时发生的概率是 0。我们也知道 <code>b</code> 和 <code>¬b</code> 加起来是 1。因此当 <code>a</code> 发生时，<code>b</code> 可以发生也可以不发生。当我们取 <code>a</code> 和 <code>b</code> 时发生的概率加上 <code>a</code> 和 <code>¬b</code> 同时发生的概率时，我们最终得到了 <code>a</code> 的概率</p></li><li><p><img src="/posts/d235/Marginalization.webp" alt="Marginalization" loading="lazy"></p><p>这个方程的左边意味着」随机变量 <code>X</code> 取值为 <code>xᵢ</code> 的概率「</p><ul><li>例如：对于我们前面提到的变量 <code>C</code>，两个可能的值分别是早上多云和早上没云</li></ul><p>方程的右边则是」<code>xᵢ</code> 和随机变量 <code>Y</code> 的每个值的所有联合概率之和「</p><ul><li>例如：<code>P(C = 多云) = P(C = 多云, R = 下雨) + P(C = 多云, R = ¬下雨) = 0.08 + 0.32 = 0.4</code></li></ul></li></ul></li><li><p>条件化：<code>P(a) = P(a | b)P(b) + P(a | ¬b)P(¬b)</code></p><ul><li><p>与边缘化相似，事件 <code>a</code> 发生的概率等于给定 <code>b</code> 的 <code>a</code> 的概率乘以 <code>b</code> 的概率，加上给定 <code>¬b</code> 的 <code>a</code> 的概率乘以 <code>¬b</code> 的概率</p></li><li><p><img src="/posts/d235/Conditioning.webp" alt="Conditioning" loading="lazy"></p><p>随机变量 <code>X</code> 以概率等于 <code>xᵢ</code> 给定随机变量 <code>Y</code> 的每个值的概率之和乘以变量 <code>Y</code> 取该值的概率。记住 <code>P(a | b) = P(a, b)/P(b)</code>，如果我们将这个表达式乘以 <code>P(b)</code>，我们就会得到 <code>P(a, b)</code>，之后的步骤便和边缘化一样</p></li></ul></li></ul><h2 id="贝叶斯网络"><a class="markdownIt-Anchor" href="#贝叶斯网络"></a> 贝叶斯网络</h2><p>贝叶斯网络是一种表示随机变量之间依赖关系的数据结构，其特性如下：</p><ul><li>是有向图，图上的每个节点都代表一个随机变量</li><li>从 X 到 Y 的箭头表示 X 是 Y 的父节点，即 Y 的概率分布取决于 X 的值</li><li>每个节点 X 都有概率分布 <code>P(X | Parents(X))</code></li></ul><p>考虑这个例子，它涉及影响了我们是否按时赴约的变量：</p><p><img src="/posts/d235/Bayesian_Network.webp" alt="Bayesian Network" loading="lazy"></p><ul><li><p><code>Rain</code> 是这个网络中的根节点。这意味着它的概率分布不依赖于任何先前的事件。在我们的例子中，<code>Rain</code> 是一个随机变量，可以取值 <code>{none, light, heavy}</code>，具有以下概率分布：</p><table><thead><tr><th>值</th><th>概率</th></tr></thead><tbody><tr><td><code>none</code></td><td>0.7</td></tr><tr><td><code>light</code></td><td>0.2</td></tr><tr><td><code>heavy</code></td><td>0.1</td></tr></tbody></table></li><li><p>在我们的例子中，<code>Maintenance</code> 编码是否有火车轨道维护，取值 <code>{yes, no}</code>。<code>Rain</code> 是 <code>Maintenance</code> 的父节点，这意味着 <code>Maintenance</code> 的概率分布受 <code>Rain</code> 的影响</p><table><thead><tr><th></th><th><code>none</code></th><th><code>light</code></th><th><code>heavy</code></th></tr></thead><tbody><tr><td><code>yes</code></td><td>0.4</td><td>0.2</td><td>0.1</td></tr><tr><td><code>no</code></td><td>0.6</td><td>0.8</td><td>0.9</td></tr></tbody></table></li><li><p><code>Train</code> 变量编码火车是否准时或延误，取值 <code>{on time, delayed}</code>。注意，<code>Maintenance</code> 和 <code>Rain</code> 都有箭头指向 <code>Train</code>，这意味着它们都是 <code>Train</code> 的父节点，它们的值会影响 <code>Train</code> 的概率分布</p><table><thead><tr><th></th><th><code>none</code> + <code>yes</code></th><th><code>none</code> + <code>no</code></th><th><code>light</code> + <code>yes</code></th><th><code>light</code> + <code>no</code></th><th><code>heavy</code> + <code>yes</code></th><th><code>heavy</code> + <code>no</code></th></tr></thead><tbody><tr><td><code>on time</code></td><td>0.8</td><td>0.9</td><td>0.6</td><td>0.7</td><td>0.4</td><td>0.5</td></tr><tr><td><code>delayed</code></td><td>0.2</td><td>0.1</td><td>0.4</td><td>0.3</td><td>0.6</td><td>0.5</td></tr></tbody></table></li><li><p><code>Appointment</code> 是一个随机变量，代表我们是否出席了预约，取值 <code>{attend, miss}</code>。它的唯一父节点是 <code>Train</code></p><ul><li><p>根据贝叶斯网络，父节点只包括直接关系。<code>Maintenance</code> 确实会影响 <code>Train</code> 是否准时，而 <code>Train</code> 是否准时会影响到我们是否出席了预约。然而，最终直接影响我们出席预约的机会的是火车是否准时到达</p><ul><li>例如：如果火车准时到达，那么即使下大雨并且轨道在维修，也不会影响我们是否赶上预约</li></ul><table><thead><tr><th></th><th><code>on time</code></th><th><code>delayed</code></th></tr></thead><tbody><tr><td><code>attend</code></td><td>0.9</td><td>0.6</td></tr><tr><td><code>miss</code></td><td>0.1</td><td>0.4</td></tr></tbody></table><ul><li>例如：如果我们想要找到在没有维修、没有下雨的一天，火车晚点时错过预约的概率，也就是 <code>P(light, no, delayed, miss)</code>，我们将计算以下内容：<ul><li><code>P(light)P(no | light)P(delayed | light, no)P(miss | delayed)</code></li><li>每个单独概率的值都可以在上面的概率分布中找到，然后将这些值相乘就能得到 <code>P(no, light, delayed, miss)</code></li></ul></li></ul></li></ul></li></ul><h3 id="推理-2"><a class="markdownIt-Anchor" href="#推理-2"></a> 推理</h3><p>早些时候我们通过蕴涵来推理，意味着我们可以根据我们已有的信息明确地得出新信息，也可以根据概率推断新信息。虽然这无法让我们确定新信息，但可以让我们找出某些值地概率分布。</p><p>推理具有多个属性：</p><ul><li><p>查询变量 X：我们想要计算概率分布的变量</p></li><li><p>证据变量 E：一个或多个一观察到的事件 <code>e</code> 的变量</p><ul><li>例如：我们可能观察到有轻微的雨。这个观察帮助我们计算火车延迟的概率</li></ul></li><li><p>隐藏变量 Y：不是查询变量，也没有被观察过的变量</p><ul><li>例如：在火车站台上，我们可以观察到是否在下雨，但是无法得知路的下方是否有维修工作。因此在这种情况下，维修工作是一个隐藏变量</li></ul></li><li><p>目标：计算 <code>P(X | e)</code></p><ul><li>例如：给予我们知道有轻微的雨的证据变量 E，计算火车变量（查询变量）的概率分布</li></ul></li></ul><p>举个例子，我们想要计算在有轻微的雨和没有轨道维修的证据下、预约变量的概率分布。也就是说，我们知道有轻微的雨并且没有轨道维修，我们想要确定我们参加预约和错过预约的概率分别是多少，也就是 <code>P(预约 | 有雨，无维修)</code>。根据联合概率部分，我们知道我们可以将预约随机变量的可能值表示为一个比例，将 <code>P(预约 | 有雨，无维修)</code> 重写为 <code>αP(预约，有雨，无维修)</code>。如果预约的父节点只有火车变量，而没有雨或者维修，我们该如何计算预约的概率分布？</p><p>在这里，我们将使用边缘化。<code>P(预约，有雨，无维修)</code> 的值等同于 <code>α[P(预约，有雨，无维修，延误) + P(预约，有雨，无维修，准时)]</code>。</p><h3 id="枚举推理"><a class="markdownIt-Anchor" href="#枚举推理"></a> 枚举推理</h3><p>枚举推理是一种根据观察到的证据 <code>e</code> 和一些隐藏变量 <code>Y</code> 来找到变量 <code>X</code> 的概率分布的过程。</p><p><img src="/posts/d235/Inference_By_Enumeration.webp" alt="Inference by Enumeration" loading="lazy"></p><p>在这个方程中，<code>X</code> 代表查询变量，<code>e</code> 代表观察到的证据，<code>y</code> 代表所有隐藏变量的值，<code>α</code> 对结果进行归一化，使得我们得到的概率总和为 1。</p><p>用文字解释这个方程，它表示给定 <code>e</code> 的情况下 <code>X</code> 的概率分布等于 <code>X</code> 和 <code>e</code> 的归一化概率分布。为了得到这个分布，我们对 <code>X</code>、<code>e</code> 和 <code>y</code> 的归一化概率求和，其中 <code>y</code> 每次取隐藏变量 <code>Y</code> 的不同值。</p><p>Python 中存在多个库以简化概率推理的过程。我们将使用 pomegranate 库来看看如何将上述数据表示为代码：</p><ol><li><p>创建节点并为每个节点提供概率分布</p><pre><code class="language-python">from pomegranate import *# 雨节点没有父节点rain = Node(DiscreteDistribution({    "none": 0.7,    "light": 0.2,    "heavy": 0.1}), name="rain")# 轨道维修节点是基于雨的条件概率maintenance = Node(ConditionalProbabilityTable([    ["none", "yes", 0.4],    ["none", "no", 0.6],    ["light", "yes", 0.2],    ["light", "no", 0.8],    ["heavy", "yes", 0.1],    ["heavy", "no", 0.9]], [rain.distribution]), name="maintenance")# 火车节点是基于雨和维修的条件概率train = Node(ConditionalProbabilityTable([    ["none", "yes", "on time", 0.8],    ["none", "yes", "delayed", 0.2],    ["none", "no", "on time", 0.9],    ["none", "no", "delayed", 0.1],    ["light", "yes", "on time", 0.6],    ["light", "yes", "delayed", 0.4],    ["light", "no", "on time", 0.7],    ["light", "no", "delayed", 0.3],    ["heavy", "yes", "on time", 0.4],    ["heavy", "yes", "delayed", 0.6],    ["heavy", "no", "on time", 0.5],    ["heavy", "no", "delayed", 0.5],], [rain.distribution, maintenance.distribution]), name="train")# 预约节点是基于火车的条件概率appointment = Node(ConditionalProbabilityTable([    ["on time", "attend", 0.9],    ["on time", "miss", 0.1],    ["delayed", "attend", 0.6],    ["delayed", "miss", 0.4]], [train.distribution]), name="appointment")</code></pre></li><li><p>通过添加所有节点来创建模型，然后通过在它们之间添加边来描述哪个节点是哪个其他节点的父节点（贝叶斯网络）</p><pre><code class="language-python"># 创建一个贝叶斯网络并添加状态model = BayesianNetwork()model.add_states(rain, maintenance, train, appointment)# 给节点之间添加用来连接的边model.add_edge(rain, maintenance)model.add_edge(rain, train)model.add_edge(maintenance, train)model.add_edge(train, appointment)# 最终确定模型model.bake()</code></pre></li><li><p>为了询问某个事件的概率有多大，我们使用我们感兴趣的值来运行模型。在这个例子中，我们想要问的是没有雨、没有轨道维修、火车准时到达并且我们准点参加会议的概率是多少</p><pre><code class="language-python"># 基于提供的观察，计算概率probability = model.probability([["none", "no", "on time", "attend"]])print(probability)</code></pre></li><li><p>否则我们可以使用该程序在给定一些观察到的证据时提供所有变量的概率分布。在下面的情况中，我们知道火车延误了。根据这个信息，我们计算并打印变量 <code>Rain</code>、<code>Maintenance</code> 和 <code>Appointment</code> 的概率分布</p><pre><code class="language-python"># 基于火车延误的证据进行预测计算predictions = model.predict_proba({    "train": "delayed"})# 打印每个节点的预测结果for node, prediction in zip(model.states, predictions):    if isinstance(prediction, str):        print(f"{node.name}: {prediction}")    else:        print(f"{node.name}")        for value, probability in prediction.parameters[0].items():            print(f"    {value}: {probability:.4f}")</code></pre></li></ol><p>上述代码使用了枚举推理。然而这种计算概率的方式是低效的，特别是当模型中有许多变量时。另一种方法是放弃精确推理，转而采用近似推理。通过这样做，我们在生成的概率中失去了一些精度，但通常这种不精确性是可以忽略的。相反我们获得了一种可扩展的计算概率的方法。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;仅作个人用途。CS50AI 课程的笔记。&lt;/p&gt;</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Python" scheme="https://blog.cytrogen.icu/tags/Python/"/>
    
    <category term="CS50" scheme="https://blog.cytrogen.icu/tags/CS50/"/>
    
  </entry>
  
  <entry>
    <title>在云服务器上搭建 Nostr 中继器</title>
    <link href="https://blog.cytrogen.icu/posts/2abc.html"/>
    <id>https://blog.cytrogen.icu/posts/2abc.html</id>
    <published>2023-08-23T17:49:11.000Z</published>
    <updated>2026-02-09T17:16:55.213Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>如何在云服务器上搭建 Nostr 中继器，并在 Nostr 客户端中连接使用。</p><span id="more"></span><div class="danger"><p>我在这个文章 <strong>还未写完</strong> 的时候就 <strong>鸽</strong> 掉了 Nostr 的搭建！</p><p>强烈建议不要根据这个教程来搭建 Nostr 中继器！</p></div><div class="danger"><p>你需要先知道：</p><ul><li>我使用的云服务器的提供商为 DigitalOcean</li><li>我使用的云服务器的系统为 Ubuntu 22.04 (LTS) x64</li><li>我使用的云服务器的配置为 1 个 CPU、1GB 内存，以及 25GB 固态</li><li>我使用的云服务器有 ipv6 地址和固定公共 IP 地址</li><li>你需要有一个域名</li></ul></div><h1 id="创建用户"><a class="markdownIt-Anchor" href="#创建用户"></a> 创建用户</h1><ol><li><p>创建一个不是 root 的用户：</p><pre><code class="language-bash">adduser 用户名</code></pre><p>如果执行这个指令后系统要求你创建一个密码，那就不需要执行下面这个指令；反之，执行该命令给该用户设置密码：</p><pre><code class="language-bash">passwd 用户名</code></pre></li><li><p>将该用户添加到 sudo 组中，从而授予其 sudoer 权限：</p><pre><code class="language-bash">usermod -aG sudo 用户名</code></pre></li><li><p>从 root 切换到我们创建的用户：</p><pre><code class="language-bash">su 用户名</code></pre></li></ol><h1 id="安装-docker"><a class="markdownIt-Anchor" href="#安装-docker"></a> 安装 Docker</h1><pre><code class="language-bash">sudo apt updatesudo apt install nodejs npm nginx certbot python3-certbot-nginx# 下载 Docker 的 GPG 密钥sudo mkdir -p /etc/apt/keyringscurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg# 安装 Dockerecho "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"echo "sudo tee /etc/apt/sources.list.d/docker.list &gt; /dev/null"sudo chmod a+r /etc/apt/keyrings/docker.gpgsudo apt updatesudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin</code></pre><h1 id="下载-nostream"><a class="markdownIt-Anchor" href="#下载-nostream"></a> 下载 nostream</h1><pre><code class="language-bash">cd /home/用户名git clone https://github.com/Cameri/nostream.git</code></pre><h1 id="配置-nginx"><a class="markdownIt-Anchor" href="#配置-nginx"></a> 配置 nginx</h1><pre><code class="language-bash"># 删除默认的 nginx 配置文件rm -rf /etc/nginx/sites-available/default# 通过 nano 进入新的配置文件sudo nano /etc/nginx/sites-available/default</code></pre><p>将以下内容复制粘贴到这个新的配置文件：</p><pre><code class="language-nginx">server{    server_name 子域名.域名.后缀;    location / {        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;        proxy_set_header Host $host;        proxy_pass http://127.0.0.1:8008;        proxy_http_version 1.1;        proxy_set_header Upgrade $http_upgrade;        proxy_set_header Connection "upgrade";    }}</code></pre><p>最后重启一下 nginx：</p><pre><code class="language-bash">sudo service nginx restart</code></pre><h1 id="设置域名的-dns"><a class="markdownIt-Anchor" href="#设置域名的-dns"></a> 设置域名的 DNS</h1><p>在你的域名 DNS 设置中，你需要添加两个记录：</p><p><img src="/posts/2abc/1.webp" alt="" loading="lazy"></p><h1 id="启动-nostr-中继器"><a class="markdownIt-Anchor" href="#启动-nostr-中继器"></a> 启动 Nostr 中继器</h1><pre><code class="language-bash">sudo certbot --nginx -d 子域名.域名.后缀cd ~/nostream# 开启 TMUX 会话# 用于分离和维护进程运行tmux# 启动中继器sudo chmod 666 /var/run/docker.socknpm run docker:compose:start</code></pre></body></html>]]></content>
    
    
    <summary type="html">本文记录了在 Ubuntu 云服务器上部署 Nostr 中继器（使用 nostream 项目）的尝试过程。内容涵盖了安装 Docker、配置 Nginx 反向代理及使用 Certbot 获取证书等关键步骤。重要提示：作者明确表示本教程未完成，并建议读者不要参照此文进行搭建，本文仅作为过程记录。</summary>
    
    
    
    <category term="工具" scheme="https://blog.cytrogen.icu/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="云服务器" scheme="https://blog.cytrogen.icu/tags/%E4%BA%91%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    
    <category term="Nostr" scheme="https://blog.cytrogen.icu/tags/Nostr/"/>
    
  </entry>
  
  <entry>
    <title>PC 通过 Proxmox 安装 MacOS</title>
    <link href="https://blog.cytrogen.icu/posts/deef.html"/>
    <id>https://blog.cytrogen.icu/posts/deef.html</id>
    <published>2023-08-17T01:15:00.000Z</published>
    <updated>2026-02-09T17:16:54.737Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>使用 Proxmox VE 在 PC 上安装 MacOS。</p><span id="more"></span><div class="danger"><p>我在这个文章 <strong>还未写完</strong> 的时候就 <strong>鸽</strong> 掉了 MacOS 的安装！</p><p>该教程暂且只写到了安装 Proxmox VE 和安装 MacOS 13.0 Ventura，并未对之后的操作进行详细说明。</p><p>强烈建议不要根据这个教程来安装 MacOS！</p></div><h1 id="前言"><a class="markdownIt-Anchor" href="#前言"></a> 前言</h1><div class="danger">阅读该文章之前，你需要：<ul><li>有一个至少 1GB 以上的 USB</li><li>有 UltroISO 或者类似的启动盘制作工具</li><li>知道如何进入 BIOS 界面</li><li>给要装上 Proxmox VE 的电脑连接上 <strong>网线</strong>！<strong>不要</strong> 无线连接！</li><li>另外一台可以联网的电子设备，无线连也可以，这台不挑<ul><li>建议在开始安装 Proxmox VE 之前就拿这台电子设备下载 MacOS ISO 文件。13GB 下载起来还是蛮花时间的。<a href="#MacOS">跳转到安装 MacOS？</a></li></ul></li><li>清楚该文章的日期是 <strong>2023 年 8 月 16 日</strong>，且我安装的并非最新版本而是 <strong>7.4</strong>！<ul><li>不装 8.0 的原因：安装 8.0 时卡在加载驱动无法继续，换成 7.4 后秒装好，真是醉了…</li></ul></li></ul></div><center>————————</center><h1 id="安装-proxmox-ve"><a class="markdownIt-Anchor" href="#安装-proxmox-ve"></a> 安装 Proxmox VE</h1><div class="danger"><p>因为一些原因，安装 Proxmox VE 时截下来的图片都不见了，所以这段就只能用文字描述。</p></div><ol><li>进入 <a href="https://www.proxmox.com/en/downloads/proxmox-virtual-environment/iso">Proxmox VE 官网</a>，下载 Proxmox VE ISO Installer。</li><li>使用 UltroISO 制作启动盘。</li><li>重启电脑、进入 BIOS 界面。</li><li>先进入 Advanced 界面，开启 Intel Virtualization Technology。</li><li>电脑再次重启后进入 BIOS，在 Boot Menu 中通过 USB 启动。</li><li>看到硕大的 PROXMOX 后，选择 <strong>Install Proxmox VE</strong>。</li><li>安装结束后点击右下角的 <strong>I agree</strong>。</li><li>接下来的界面中，需要按照自己的配置依次选择目标硬盘、国家地区、键盘布局、密码邮箱、网络管理、主机名、IP 地址、网关、DNS。绝大多数都可以默认跳过，故仅展示部分界面，<sub>才不是重装了太多次完全忘记拍下来了呢！</sub></li><li>设置结束后等配置，配置结束后等电脑重启，电脑重启后会自动启动 Proxmox VE，放着不管即可。<br>之后 Proxmox VE 会显示一个地址。这个地址的一部分正是之前设置的 IP 地址。</li><li>启动同互联网下的另一个电子设备，打开浏览器访问该地址。<br><img src="/posts/deef/2_001.webp" alt="" loading="lazy"><br>用户名是 <em>root</em>，密码则是先前我们设置的那个。<br>顺带一提 Proxmox VE 是有中文的。</li><li>登陆成功。至此 Proxmox VE 安装好了。</li></ol><center>————————</center><h1>安装 MacOS</h1><div class="danger" id="MacOS">我测试安装的版本为 13.0 Ventura Beta。因此以下的设置无法保证对其他版本的 MacOS 同样有效。<p>你可以在 <a href="https://archive.org/details/macos-collection"> archive.org</a> 下载它或者其他版本。</p></div><ol><li><p>依旧是在另一台电子设备上。现在我们需要将 MacOS ISO 文件上传到 Proxmox VE。<br>打开节点的 local 存储空间后点击 <strong>ISO Images</strong> &gt; <strong>Upload</strong> &gt; 找到 MacOS ISO 文件 &gt; <strong>Upload</strong>。</p><p><img src="/posts/deef/2_002.webp" alt="" loading="lazy"><br>看到 <strong>TASK OK</strong> 就代表上传成功。</p><p><img src="/posts/deef/2_003.webp" alt="" loading="lazy"></p></li><li><p>想要启动 MacOS，还需要从 GitHub 上安装一个工具：<a href="https://github.com/thenickdude/KVM-Opencore">KVM-Opencore</a>。<br>直接进到 Release 并下载 <strong>OpenCore-v20.iso.gz</strong>（最新版本）。</p><p><img src="/posts/deef/2_004.webp" alt="" loading="lazy"></p></li><li><p>解压该文件，获得崭新 ISO 文件一个。<br>使用和 MacOS ISO 文件一样的方法将其上传到 Proxmox VE。</p><p><img src="/posts/deef/2_005.webp" alt="" loading="lazy"></p></li><li><p>上传完成后，点击页面右上角的 <strong>Create VM</strong>。<br>给该虚拟机随便取一个名字。</p><p><img src="/posts/deef/2_006.webp" alt="" loading="lazy"></p></li><li><p>点击 OS 页面：</p><ul><li>在 ISO image 一栏选择 <strong>OpenCore-v20.iso</strong></li><li>在 Type 一栏选择 <strong>Other</strong></li></ul><p><img src="/posts/deef/2_007.webp" alt="" loading="lazy"></p></li><li><p>点击 System 页面：</p><ul><li>在 Graphic card 一栏选择 <strong>VMware compatible</strong></li><li>在 Machine 一栏选择 <strong>q35</strong></li><li>在 BIOS 一栏选择 <strong>OVMF (UE5FI)</strong></li><li>在 EFI Storage 一栏选择 <strong>local-lvm</strong></li><li>取消勾选 <strong>Pre-Enroll keys</strong></li><li>在 SCSI Controller 一栏选择 <strong>VirtIO SCSI</strong></li></ul><p><img src="/posts/deef/2_008.webp" alt="" loading="lazy"></p></li><li><p>点击 Disks 页面：</p><ul><li>在 Bus / Device 一栏选择 <strong>VirtIO Block</strong></li><li>在 Disk size (GiB）一栏输入 <strong>64</strong></li><li>在 Cache 一栏选择 <strong>White back (unsafe)</strong></li></ul><p><img src="/posts/deef/2_009.webp" alt="" loading="lazy"></p></li><li><p>点击 CPU 页面：</p><ul><li>在 Cores 一栏根据你自己的配置输入核的数量（我输入了 4）</li><li>在 Type 一栏选择 <strong>host</strong></li></ul><p><img src="/posts/deef/2_010.webp" alt="" loading="lazy"></p></li><li><p>点击 Memory 页面。至少也需要 4GB 的内存，我输入了 6GB。<br><img src="/posts/deef/2_011.webp" alt="" loading="lazy"></p></li><li><p>点击 Network 页面：</p><ul><li>在 Model 一栏选择 <strong>VMWare vmxnet3</strong></li></ul><p><img src="/posts/deef/2_012.webp" alt="" loading="lazy"></p></li><li><p>最终创建虚拟机。<br><img src="/posts/deef/2_013.webp" alt="" loading="lazy"></p></li><li><p>这时能在左侧看到我们的 Mac 虚拟机，点击后选择 <strong>Hardware</strong> &gt; <strong>Add</strong> &gt; <strong>CD/DVD Drive</strong>。<br><img src="/posts/deef/2_014.webp" alt="" loading="lazy"></p><ul><li>在 Storage 一栏中选择 <strong>local</strong></li><li>在 ISO image 一栏中选择我们的 MacOS ISO 文件，然后点击 <strong>Add</strong></li></ul><p><img src="/posts/deef/2_015.webp" alt="" loading="lazy"></p></li><li><p>选择 <strong>Options</strong>，选中 <strong>Boot Order</strong> 后点击上方的 <strong>Edit</strong> 来修改虚拟机的 Boot 顺序。</p><p><img src="/posts/deef/2_016.webp" alt="" loading="lazy"><br>拖拽 OpenCore 的 ISO 到第一位，接着拖拽 MacOS ISO 到第二位。拖拽完后点击 <strong>OK</strong>。</p><p><img src="/posts/deef/2_017.webp" alt="" loading="lazy"></p></li><li><p>点击左侧的节点 &gt; <strong>Shell</strong>。</p><p><img src="/posts/deef/2_018.webp" alt="" loading="lazy"><br>安装 MacOS 之前我们还需要再修改一些配置文件。在 Shell 中输入以下命令：</p><pre><code class="language-bash">nano /etc/pve/qemu-server/VM的ID.conf如果没有设置的话，默认的 ID是100，所以就是100.conf</code></pre><p>进入该配置文件后，需要复制粘贴参数信息。</p><ul><li>如果你是英特尔处理器：<pre><code class="language-plaintext">args: -device isa-applesmc,osk="ourhardworkbythesewordsguardedpleasedontsteal(c)AppleComputerInc" -smbios type=2 -device usb-kbd,bus=ehci.0,port=2 -global nec-usb-xhci.msi=off -global ICH9-LPC.acpi-pci-hotplug-with-bridge-support=off -cpu host,vendor=GenuineIntel,+invtsc,+hypervisor,kvm=on,vmware-cpuid-freq=on</code></pre></li><li>如果你是 AMD 处理器：<pre><code class="language-plaintext">args: -device isa-applesmc,osk="ourhardworkbythesewordsguardedpleasedontsteal(c)AppleComputerInc" -smbios type=2 -device usb-kbd,bus=ehci.0,port=2 -global nec-usb-xhci.msi=off -global ICH9-LPC.acpi-pci-hotplug-with-bridge-support=off -cpu Haswell-noTSX,vendor=GenuineIntel,+invtsc,+hypervisor,kvm=on,vmware-cpuid-freq=on</code></pre></li></ul><p>我是英特尔处理器，复制粘贴完事。<br>接着将文件中出现的两条 <code>media=cdrom</code> 替换为 <code>cache=unsafe</code>。</p><p><img src="/posts/deef/2_019.webp" alt="" loading="lazy"></p><p>按 <code>Ctrl+O</code> &gt; <code>Enter</code> 保存，接着按 <code>Ctrl+X</code> 退出。</p></li><li><p>回到 Mac 虚拟机，点击右上方的 <strong>Start</strong> 启动虚拟机，然后选中左侧的 <strong>Console</strong>。</p><p><img src="/posts/deef/2_020.webp" alt="" loading="lazy"></p><p>回车进入 UEFI Interface Shell，输入以下命令：</p><pre><code class="language-plaintext">fs0:System\Library\CoreServices\Boot.efi</code></pre><p><img src="/posts/deef/2_021.webp" alt="" loading="lazy"></p><p>熟悉的苹果图标出现！</p><p><img src="/posts/deef/2_022.webp" alt="" loading="lazy"></p></li><li><p>点击 <strong>Disk Utility</strong>，找到 VirtIO Block 硬盘并点击 <strong>Erase</strong>。</p><p><img src="/posts/deef/2_023.webp" alt="" loading="lazy"><br><img src="/posts/deef/2_024.webp" alt="" loading="lazy"></p><p>修改硬盘的名称，点击 <strong>Erase</strong>。</p><p><img src="/posts/deef/2_025.webp" alt="" loading="lazy"></p></li><li><p>结束后左上角关闭 Disk Utility，接着点击 <strong>Install macOS Ventura</strong>。</p><p><img src="/posts/deef/2_026.webp" alt="" loading="lazy"></p><p>同意协议后，选择我们刚才格式化的硬盘来安装。</p><p><img src="/posts/deef/2_027.webp" alt="" loading="lazy"></p></li><li><p>回车继续安装，差不多要等半个小时左右。<br>期间可能会弹出多次下图的界面，回车就行。（我弹出了很多次…… 还重装了一遍…）</p><p><img src="/posts/deef/2_028.webp" alt="" loading="lazy"></p></li><li><p>经过多次硬盘弹出洗礼，终于看到了代表着胜利的橘色！</p><p><img src="/posts/deef/2_029.webp" alt="" loading="lazy"></p><p>之后的自行设置。</p></li></ol><h1 id="安装-opencore-configurator"><a class="markdownIt-Anchor" href="#安装-opencore-configurator"></a> 安装 OpenCore Configurator</h1><ol><li>前往 <a href="https://mackie100projects.altervista.org/opencore-configurator/">OpenCore Configurator 的网站</a> 来安装 OpenCore Configurator。<br>下载后可以在右下角找到它的图标，开启。（可能需要进入系统设置的 Privacy &amp; Security 中打开，因为它既不是 App Store 里的应用，也不来自于已被识别的开发者）</li></ol><div class="danger"><p>这个文章没写完的时候我就鸽了 MacOS 的安装，所以这个部分暂且不写、如果以后再捣鼓的话再补上。</p></div></body></html>]]></content>
    
    
    <summary type="html">本文记录了在普通 PC 上使用 Proxmox VE 7.4 虚拟化平台安装 macOS Ventura 的详细过程。教程涵盖了从安装 Proxmox、配置虚拟机硬件（CPU, OVMF/UEFI, VirtIO），到使用 KVM-OpenCore 引导并完成 macOS 初步安装的全流程。重要提示：作者明确表示本教程并未写完，后续关键配置已“鸽掉”，因此强烈建议不要完全参照此文进行安装，本文仅作为一次安装尝试的记录。</summary>
    
    
    
    <category term="工具" scheme="https://blog.cytrogen.icu/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="Proxmox" scheme="https://blog.cytrogen.icu/tags/Proxmox/"/>
    
  </entry>
  
  <entry>
    <title>BUFFALO LinkStation Pro Duo【1】初步设置</title>
    <link href="https://blog.cytrogen.icu/posts/66e.html"/>
    <id>https://blog.cytrogen.icu/posts/66e.html</id>
    <published>2023-07-27T23:40:26.000Z</published>
    <updated>2026-02-09T17:16:54.609Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>BUFFALO LinkStation Pro Duo 的相关教程第 1 节：映射。</p><span id="more"></span><div class="danger"> 首先，什么是 LinkStation Pro Duo？（以下节选自 BUFFALO 的亚太官网）<ul><li>LinkStation Pro Duo 是一款高性能双盘位 RAID 网络存储设备，它包含一些列特色功能，是存储、共享、服务和保护你最重要数据的最佳设备。能够同时备份多台计算机和苹果机，即便不在家也通过因特网连续访问自己网络中存储的数据</li></ul></div><p>想必能搜到这个文章的人都多多少少不需要以上的介绍。</p><p><img src="/posts/66e/1.webp" alt="BUFFALO LinkStation Pro Duo整图" loading="lazy"></p><p>几日前我从老师手中白嫖到这么一台 NAS，型号为 LS - WTGL/R1-V3 F/W3.10。</p><p>不过 LinkStation Pro Duo 的教程在网上实在是少之又少，不少教程还因为年代久远导致无法参考。很难想象我在拿到这台 NAS 后就因为无法正常映射而查资料查了快一天的时间才解决。</p><p>先来看看我们的 LinkStation Pro Duo。包装中自带一个 CD 供用户安装所需的软件（还有 Memeo 数据备份，Win 系统要比 Mac 多一个 Adobe Reader），可惜 CD 的时代已经过去，我的笔记本电脑并没有光驱。</p><p><img src="/posts/66e/2.webp" alt="BUFFALO LinkStation Pro Duo说明书和软件安装用的CD" loading="lazy"></p><h2 id="前期准备"><a class="markdownIt-Anchor" href="#前期准备"></a> 前期准备</h2><ul><li><p>一台 LinkStation Pro Duo（型号和我的不同也没关系，顶多是网页 UI 布局的区别）</p></li><li><p>NAS Navigator2</p><ul><li><p>官方下载链接：<a href="https://www.buffalotech.com/products/linkstation-pro-duo">点我</a></p></li><li><p>点击 <strong>Utilities</strong> → 根据你的系统选择前两个下载连接。我是 Win10 系统所以自然下载第一个</p><p><img src="/posts/66e/3.webp" alt="官网下载链接Utilities区域" loading="lazy"></p></li></ul></li></ul><h2 id="初步连接"><a class="markdownIt-Anchor" href="#初步连接"></a> 初步连接</h2><ol><li><p>首先先把 NAS 连接上电源和 LAN。</p><p><img src="/posts/66e/5.webp" alt="连接电源和LAN" loading="lazy"></p></li><li><p>将开关调到 ON。</p><p><img src="/posts/66e/6.webp" alt="开关调到中间的ON" loading="lazy"></p></li><li><p>坐等 NAS 前面的这两个灯亮起。</p><p><img src="/posts/66e/7.webp" alt="NAS前方亮起上下两个绿灯" loading="lazy"></p></li><li><p>坐到我们的电脑前（和 NAS 在同一个网络下）打开 NAS Navigator2，能看到我们的 NAS 出现。</p><p><img src="/posts/66e/8.webp" alt="NAS Navigator2中出现NAS图标 " loading="lazy"></p></li></ol><h2 id="映射"><a class="markdownIt-Anchor" href="#映射"></a> 映射</h2><ol><li><p>右键 NAS 的图标，选择 <strong>Map Share</strong>。如果没有任何错误弹出，那可以无视下面的步骤直接开跳。</p><p><img src="/posts/66e/9.webp" alt="右键NAS图标并在右键菜单中选择Map Share" loading="lazy"></p></li><li><p>选择看到这里就代表你见到了 <em>Could not map the share. Create a folder named「share」before mapping the drive</em> 这样的弹窗。我们先进入 NAS 的设置页面：右键 NAS 图标，选择 <strong>Open Settings</strong>。</p><p><img src="/posts/66e/10.webp" alt="错误弹窗：Could not map the share. Create a folder named “share” before mapping the drive" loading="lazy"></p></li><li><p>用户名默认是 <strong>admin</strong>，密码默认是 <strong>password</strong>（传统艺能）。</p><p><img src="/posts/66e/11.webp" alt="LinkStation NAS设置页面" loading="lazy"></p></li><li><p>首先先设置 RAID，点击 <strong>RAID Setup</strong> 下的 <strong>RAID Array 1。</strong></p><p><img src="/posts/66e/12.webp" alt="先点击左边的Disk Management，再点击左边的RAID Setup，最后点击中间RAID Setup下的RAID Array 1" loading="lazy"></p><div class="danger">在进行 RAID Array 设置之前，你需要先明白 RAID 在这里是什么用的。<p>在 BUFFALO 亚太官网中提到：</p><blockquote><p>「LinkStation Pro Duo 包含两个内置硬盘机架，安装两个硬盘后可支持 RAID 0 / 1 系统。当使用 RAID1 系统时，可便捷安装最多两个硬盘，并自动复制（不包含硬盘）。使用 LinkStation Pro Duo 设备时，可随时添加第二个硬盘，在 RAID1 系统中设置而不会损坏任何数据。轻松省时备份和保护你的数据。」</p></blockquote><p>也就是说：RAID 0 代表 <strong>将所有硬盘合并为单一阵列，能够最大化存储容量，不具有冗余功能</strong>，而 RAID 1 代表着 <strong>备份两个硬盘，为了应对意外故障，能够精准复制数据</strong>。</p><p>我在这里设置的是 RAID 1，你不需要一定跟着我的来做，只是以下的步骤我都会以「设置 RAID Array 为 1」的前提来进行。</p></div></li><li><p>确保 <strong>RAID Mode</strong> 为 <strong>RAID1</strong>、<strong>Disk Structure</strong> 下的硬盘都被勾选后，点击 <strong>Setup RAID Array</strong>。</p><p><img src="/posts/66e/13.webp" alt="点击设置RAID Array" loading="lazy"></p></li><li><p>之后会出现弹窗让你确认，还有个验证码需要跟着输入，快速过完确认流程后耐心等待 RAID Array 被构建。</p><p><img src="/posts/66e/14.webp" alt="页面上显示Building RAID Array和进度条" loading="lazy"></p><p><img src="/posts/66e/15.webp" alt="RAID Array构建完毕" loading="lazy"></p></li><li><p>构建完 RAID Array 之后，我们会立即收到一个来自于 NAS Navigator2 的桌面通知，表示 RAID Array 1 正在被同步。</p><p><img src="/posts/66e/16.webp" alt="NAS Navigator2的桌面通知，显示Resyncing RAID Array 1" loading="lazy"></p><p>同时设置页面在我们点击 <strong>Continue</strong> 之后、主页出现了 <strong>Checking RAID Array 1</strong> 的选项。点击后我们能看到 RAID Array 1 的同步状态（对，我们真的是要等 160+ 分钟。这个时间段我们可以先吃个饭~）。</p><p><img src="/posts/66e/17.webp" alt="LinkStation设置主页出现了Checking RAID Array 1" loading="lazy"></p><p><img src="/posts/66e/18.webp" alt="RAID Array 1的状态信息，需要等待近三个小时" loading="lazy"></p><p>顺带一提，这个页面并非实时修改内容。要查看现在的同步状态，我们要先去到主页面，再点击 <strong>Checking RAID Array 1</strong> 导回该页面才能看到内容变动。</p></li><li><p>同步完成后，主页面的 <strong>HDD Space Used</strong> 会变为单个 RAID Array 1。</p><p><img src="/posts/66e/19.webp" alt="主页面的HDD Space Used变为RAID Array 1" loading="lazy"></p><p>现在点击 <strong>Shared Folders</strong> 来创建一个名为 <em>share</em> 的文件夹。</p><p><img src="/posts/66e/20.webp" alt="点击左边的Shared Folder，然后点击中间的Add" loading="lazy"></p><p><img src="/posts/66e/21.webp" alt="在Shared Folder Name中填写share，然后检查Volume是否为RAID Array 1，最后点击Apply" loading="lazy"></p><p>成功添加。</p><p><img src="/posts/66e/22.webp" alt="Shared Folders页面显示Settings Have Been Saved Successfully，并且Shared Folders Setup栏下多出了Disk or Array为RAID Array 1的share文件夹" loading="lazy"></p></li><li><p>现在回到 NAS Navigator2，重新右键 NAS 图标并点击 <strong>Map Share</strong>。可算是映射成功了。</p><p><img src="/posts/66e/23.webp" alt="弹窗显示“LS-WTGLCDBhare is mapped to drive L”" loading="lazy"></p></li><li><p>右键 NAS 图标并点击 <strong>Browse Share</strong>，系统会自动打开文件夹。当然也可以选择在文件管理器里自己打开。</p><p><img src="/posts/66e/24.webp" alt="右键NAS并点击Browse Share" loading="lazy"></p><p><img src="/posts/66e/25.webp" alt="自动打开的Network中的文件夹" loading="lazy"></p><p><img src="/posts/66e/26.webp" alt="在文件管理器中打开。Share文件夹会自动出现在Network Locations下方" loading="lazy"></p></li></ol><h2 id="结束语"><a class="markdownIt-Anchor" href="#结束语"></a> 结束语</h2><p>好的，大功告成！你已经完成了初步设置。只是现在这个 NAS 仅能在同互联网的情况下进行存储，而我们往往都是希望在外面访问它。</p><p>后续关于外网访问的教程可能很快就能端上来，也有可能成为巨坑。</p><p>总之祝大家玩 NAS 玩的开心、玩出新奇。</p></body></html>]]></content>
    
    
    <summary type="html">本文是一篇针对 BUFFALO LinkStation Pro Duo 网络存储器（NAS）的入门设置教程，旨在解决初次使用时映射网络驱动器失败的常见问题。教程通过详细的图文步骤，引导用户如何配置RAID阵（以RAID 1为例），创建共享文件夹，并最终通过 NAS Navigator2 软件成功将NAS映射为本地网络驱动器，解决了“Could not map the share”的报错。如果你刚入手一台老款 BUFFALO NAS 不知如何下手，本教程将为你提供清晰的实操指引。</summary>
    
    
    
    <category term="工具" scheme="https://blog.cytrogen.icu/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="NAS" scheme="https://blog.cytrogen.icu/tags/NAS/"/>
    
  </entry>
  
  <entry>
    <title>树莓派 Pico 通过有源蜂鸣器播放音频</title>
    <link href="https://blog.cytrogen.icu/posts/ba6a.html"/>
    <id>https://blog.cytrogen.icu/posts/ba6a.html</id>
    <published>2023-05-15T22:49:48.000Z</published>
    <updated>2026-02-09T17:16:55.401Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>如何使用 MicroPython 在树莓派 Pico 上通过有源蜂鸣器播放音频。</p><span id="more"></span><h1 id="目录"><a class="markdownIt-Anchor" href="#目录"></a> 目录</h1><ul><li><a href="#%E7%9B%AE%E5%BD%95">目录</a></li><li><a href="#%E5%89%8D%E8%A8%80">前言</a></li><li><a href="#%E5%87%86%E5%A4%87">准备</a><ul><li><a href="#%E5%AF%BC%E5%85%A5%E5%BA%93">导入库</a></li><li><a href="#%E9%9F%B3%E7%AC%A6%E4%B8%8E%E9%A2%91%E7%8E%87">音符与频率</a><ul><li><a href="#%E9%A2%98%E5%A4%96%E8%AF%9D">题外话</a></li></ul></li><li><a href="#%E8%AE%BE%E7%BD%AE%E8%9C%82%E9%B8%A3%E5%99%A8">设置蜂鸣器</a></li></ul></li><li><a href="#%E7%BC%96%E5%86%99%E4%BB%A3%E7%A0%81">编写代码</a><ul><li><a href="#%E8%8E%B7%E5%8F%96%E4%B9%90%E8%B0%B1">获取乐谱</a></li><li><a href="#%E6%92%AD%E6%94%BE%E9%9F%B3%E9%A2%91">播放音频</a></li><li><a href="#%E6%92%AD%E6%94%BE%E4%B9%90%E8%B0%B1">播放乐谱</a></li></ul></li><li><a href="#%E6%9C%80%E7%BB%88%E6%95%88%E6%9E%9C">最终效果</a></li></ul><center> ————————</center><h1 id="前言"><a class="markdownIt-Anchor" href="#前言"></a> 前言</h1><p>我的树莓派 Pico 早在过年时就到手了，但是一直没有时间玩，最近闲到开始生一种叫做 senioritis 的病，才开始捣鼓起来。</p><p>买的时候贪方便，直接购入了已焊接的板子，如下图所示：</p><img src="/posts/ba6a/1.webp" alt="创乐博MAKEROBO PicoBlock扩展板，已焊接树莓派Pico主板、面包板、LED灯、方向按键、有源蜂鸣器、传感器等套件" loading="lazy"><p>不过本文内容专注于 MicroPython，所以不会细讲硬件部分。如何配置树莓派 Pico 和安装 IDE 等基础内容也不会讲，可以自行搜索。</p><div class="danger"><ul><li>本文使用的 IDE 为 Thonny</li><li>本文乐谱均来自于 <a href="https://onlinesequencer.net/">Online Sequencer</a> 这个网站</li></ul></div><center>————————</center><h1 id="准备"><a class="markdownIt-Anchor" href="#准备"></a> 准备</h1><h2 id="导入库"><a class="markdownIt-Anchor" href="#导入库"></a> 导入库</h2><pre><code class="language-python">import timefrom machine import PWM, Pin</code></pre><ul><li><code>time</code> 库自不用多说，是用来延时的</li><li><code>machine</code> 库则包含了和特定电路板上的硬件有关的方法，例如我们刚刚导入的 <code>PWM</code> 和 <code>Pin</code>。详细的内容可以参考 <a href="https://docs.micropython.org/en/latest/library/machine.html">MicroPython 官方文档</a></li></ul><h2 id="音符与频率"><a class="markdownIt-Anchor" href="#音符与频率"></a> 音符与频率</h2><pre><code class="language-python">tones = {    'C0': 16, 'C#0': 17, 'D0': 18, 'D#0': 19, 'E0': 21, 'F0': 22,    'F#0': 23, 'G0': 24, 'G#0': 26, 'A0': 28, 'A#0': 29, 'B0': 31,    'C1': 33, 'C#1': 35, 'D1': 37, 'D#1': 39, 'E1': 41, 'F1': 44,    'F#1': 46, 'G1': 49, 'G#1': 52, 'A1': 55, 'A#1': 58, 'B1': 62,    'C2': 65, 'C#2': 69, 'D2': 73, 'D#2': 78, 'E2': 82, 'F2': 87,    'F#2': 92, 'G2': 98, 'G#2': 104, 'A2': 110, 'A#2': 117, 'B2': 123,    'C3': 131, 'C#3': 139, 'D3': 147, 'D#3': 156, 'E3': 165, 'F3': 175,    'F#3': 185, 'G3': 196, 'G#3': 208, 'A3': 220, 'A#3': 233, 'B3': 247,    'C4': 262, 'C#4': 277, 'D4': 294, 'D#4': 311, 'E4': 330, 'F4': 349,    'F#4': 370, 'G4': 392, 'G#4': 415, 'A4': 440, 'A#4': 466, 'B4': 494,    'C5': 523, 'C#5': 554, 'D5': 587, 'D#5': 622, 'E5': 659, 'F5': 698,    'F#5': 740, 'G5': 784, 'G#5': 831, 'A5': 880, 'A#5': 932, 'B5': 988,    'C6': 1047, 'C#6': 1109, 'D6': 1175, 'D#6': 1245, 'E6': 1319, 'F6': 1397,    'F#6': 1480, 'G6': 1568, 'G#6': 1661, 'A6': 1760, 'A#6': 1865, 'B6': 1976,    'C7': 2093, 'C#7': 2217, 'D7': 2349, 'D#7': 2489, 'E7': 2637, 'F7': 2794,    'F#7': 2960, 'G7': 3136, 'G#7': 3322, 'A7': 3520, 'A#7': 3729, 'B7': 3951,    'C8': 4186, 'C#8': 4435, 'D8': 4699, 'D#8': 4978, 'E8': 5274, 'F8': 5588,    'F#8': 5920, 'G8': 6272, 'G#8': 6645, 'A8': 7040, 'A#8': 7459, 'B8': 7902,    'C9': 8372, 'C#9': 8870, 'D9': 9397, 'D#9': 9956, 'E9': 10548, 'F9': 11175,    'F#9': 11840, 'G9': 12544, 'G#9': 13290, 'A9': 14080, 'A#9': 14917, 'B9': 15804}</code></pre><p>这个字典包含了从 C0 到 B9 的所有音符的频率，单位为 Hz。这些频率之后会被用来设置 PWM 的频率。</p><h4 id="题外话"><a class="markdownIt-Anchor" href="#题外话"></a> 题外话</h4><p>如果不懂音符，但又想要照着现实中的乐谱来弹奏，那该怎么办？（当然，如果你懂的话，可以直接跳到 <a href="#%E8%AE%BE%E7%BD%AE%E8%9C%82%E9%B8%A3%E5%99%A8">这个位置</a>）</p><p>先来看看一个简单的乐谱长什么样子。有请我们的主角 ——《小星星》：</p><img src="/posts/ba6a/2.webp" alt="小星星乐谱" loading="lazy"><p>首先，乐谱每一行都有数个小节，被竖线隔开。</p><p>每一行的最左边都有一个数字，代表了这一行的拍子。例如这个乐谱的拍子是 4 / 4 拍，也就是说每一小节有四拍，每一拍是一个四分音符。</p><p>那什么又是四分音符？这又要从音符的时值说起了。</p><p>音符的时值分为全音符、二分音符、四分音符、八分音符、十六分音符、三十二分音符等等。为了直接分辨，上图：</p><img src="/posts/ba6a/3.webp" alt="圆圈，全音符，时值为4拍，简谱符号为1---；圆圈插一个天线，二分音符，时值为2拍，简谱符号为1-；黑圆圈插一个天线，四分音符，时值为1拍，简谱符号为1；黑圆圈插一个挂了旗子的天线，八分音符，时值为1/2拍，简谱符号为1.；黑圆圈插一个挂了俩旗子的天线，十六分音符，时值为1/4拍，简谱符号为1..；黑圆圈插一个挂了仨旗子的天线，三十二分音符，时值为1/8拍，简谱符号为1...；所有的.代表下划线" loading="lazy"><p>现在回到《小星星》的乐谱上，我们可以看到，第一小节正好有四个四分音符，而第二小节则有两个四分音符和一个二分音符：</p><img src="/posts/ba6a/4.webp" alt="小星星简谱的第1小节和第2小节" loading="lazy"><p>那么在实际演奏中，这两个小节的区别是什么呢？</p><p>四个四分音符实际演奏：啊 啊 啊 啊；<br>两个四分音符 &amp; 一个二分音符实际演奏：啊 啊 啊 ——。</p><p>也就是说，在这个谱子里一个二分音符相当于把两个四分音符融合在一起，拉了个长音。</p><p>说完时值，现在来看五线谱中各个音符所处的位置。想必你也发现了，有些音符在线上、有些音符在线下、有些音符在中间、有些音符在上下两个线之间…… 这是为什么呢？</p><p>这又要说到音符的音高了。这里要注意一点，《小星星》的乐谱中标记了 1 = C，也就是 C 大调。C 大调由 C、D、E、F、G、A、B 七个音组成，况且还是唯一一个没有升降号的大调。</p><blockquote><p>钢琴上不是有白键和黑键吗？白键总体分为 C、D、E、F、G、A、B 七个音，而黑键总体分为 C#、D#、F#、G#、A# 五个音。<br># 符号代表了升号，也就是把这个音调提高半个音阶。比如 C# 是 C 的升半音，也是 C 和 D 之间的音。<br>还有一个名为 b 的符号，代表了降号。和 #符号相反，b 符号是把这个音调降低半个音阶。Db 是 D 的降半音，是 C 和 D 之间的音，也是 C#。</p></blockquote><p>我们说了这么多 C、D、E、F、G、A、B，但是在《小星星》里，我们只看到了数字。这是因为在简谱中，用以表示音的高低的符号是阿拉伯数字。1 代表了 C，2 代表了 D，3 代表了 E，以此类推。</p><blockquote><p>而在现实生活中，我们最常使用的还是唱名，由 do、re、mi、fa、so、la、si 来表示音的高低。do 代表了 C，re 代表了 D，mi 代表了 E，以此类推。</p></blockquote><img src="/posts/ba6a/6.webp" alt="阿拉伯数字、唱名、汉字的对照表" loading="lazy"><p>我们已经知道了如何用阿拉伯数字辨认音的高低，但是这仅能在简谱中使用。我们依旧还是要学会如何看五线谱。C 大调的音阶是这样的：</p><img src="/posts/ba6a/7.webp" alt="C大调的音阶" loading="lazy"><p>来看《小星星》的第一小节。不需要看阿拉伯数字，这次也可以参照上一张图判断出这是 CCGG 了：</p><img src="/posts/ba6a/5.webp" alt="小星星的第一小节，1155" loading="lazy"><p>但是在我们先前的 <a href="#%E9%9F%B3%E7%AC%A6%E4%B8%8E%E9%A2%91%E7%8E%87">音符对频率字典</a> 里，C、D、E、F、G、A、B 后面还跟了多个数字。比如 C4、C5、C6…… 这些数字代表了这个音的频率，也就是音的高低。C4 通常被认为是中央 C，C5 是高一个八度的 C，C6 是再高一个八度的 C，以此类推。</p><blockquote><p>八度指的是音的高低，在频率上是 2 倍的关系。比如 C4 的频率是 261.63Hz，C5 的频率是 523.25Hz，C6 的频率是 1046.50Hz，以此类推。<br>不过我们不需要那么详细的小数，只要四舍五入到整数即可。</p></blockquote><p>为了方便，我们直接使用中央 C 作为基准，也就是 C4。这样，我们就可以把《小星星》的乐谱和音符结合起来了：</p><pre><code class="language-plaintext">C4 C4 G4 G4 A4 A4 G4- F4 F4 E4 E4 D4 D4 C4- G4 G4 F4 F4 E4 E4 D4- G4 G4 F4 F4 E4 E4 D4- C4 C4 G4 G4 A4 A4 G4- F4 F4 E4 E4 D4 D4 C4-</code></pre><div class="danger">这不是最终我们会使用的乐谱，只是为了方便理解而已。</div><h2 id="设置蜂鸣器"><a class="markdownIt-Anchor" href="#设置蜂鸣器"></a> 设置蜂鸣器</h2><p>来设置蜂鸣器的引脚。我习惯使用 GP15（参考 <a href="#%E5%89%8D%E8%A8%80">先前的图片</a>，GP15 引脚已经和蜂鸣器连接好了）。你自然也可以根据自己的需要更改引脚：</p><pre><code class="language-python">buzzer = PWM(Pin(15))buzzer.freq(50000)buzzer.duty_u16(int(65536 * 0.2))</code></pre><p>我们先创建了一个 PWM 对象，然后设置了 PWM 周期的频率为 50000Hz（不发出任何声音），最后设置了占空比为 20%。</p><center>————————</center><h1 id="编写代码"><a class="markdownIt-Anchor" href="#编写代码"></a> 编写代码</h1><h2 id="获取乐谱"><a class="markdownIt-Anchor" href="#获取乐谱"></a> 获取乐谱</h2><p>我选择用超级马里奥的 <a href="https://onlinesequencer.net/25966">经典曲子</a> 来演示。Online Sequencer 的乐谱可以直接复制粘贴，如下：</p><pre><code class="language-plaintext">Online Sequencer:616413:0 F#5 1 7;0 E6 1 7;2 F#5 1 7;2 E6 1 7;6 F#5 1 7;6 E6 1 7;10 F#5 1 7;10 C6 1 7;12 F#5 1 7;12 E6 1 7;16 G5 1 7;16 B5 1 7;16 G6 1 7;24 G5 1 7;32 E5 1 7;32 C6 1 7;38 C5 1 7;38 G5 1 7;44 G4 1 7;44 E5 1 7;50 C5 1 7;50 A5 1 7;54 D5 1 7;54 B5 1 7;58 C#5 1 7;58 A#5 1 7;60 C5 1 7;60 A5 1 7;64 C5 1 7;64 G5 1 7;66 G5 1 7;66 E6 1 7;69 B5 1 7;69 G6 1 7;72 C6 1 7;72 A6 1 7;76 A5 1 7;76 F6 1 7;78 B5 1 7;78 G6 1 7;82 A5 1 7;82 E6 1 7;86 E5 1 7;86 C6 1 7;88 F5 1 7;88 D6 1 7;90 D5 1 7;90 B5 1 7;96 E5 1 7;96 C6 1 7;102 C5 1 7;102 G5 1 7;108 G4 1 7;108 E5 1 7;114 C5 1 7;114 A5 1 7;118 D5 1 7;118 B5 1 7;122 C#5 1 7;122 A#5 1 7;124 C5 1 7;124 A5 1 7;128 C5 1 7;128 G5 1 7;130 G5 1 7;130 E6 1 7;133 B5 1 7;133 G6 1 7;136 C6 1 7;136 A6 1 7;140 A5 1 7;140 F6 1 7;142 B5 1 7;142 G6 1 7;146 A5 1 7;146 E6 1 7;150 E5 1 7;150 C6 1 7;152 F5 1 7;152 D6 1 7;154 D5 1 7;154 B5 1 7;164 E6 1 7;164 G6 1 7;166 D#6 1 7;166 F#6 1 7;168 D6 1 7;168 F6 1 7;170 B5 1 7;170 D#6 1 7;174 C6 1 7;174 E6 1 7;178 E5 1 7;178 G#5 1 7;180 F5 1 7;180 A5 1 7;182 G5 1 7;182 C6 1 7;186 C5 1 7;186 A5 1 7;188 E5 1 7;188 C6 1 7;190 F5 1 7;190 D6 1 7;196 E6 1 7;196 G6 1 7;198 D#6 1 7;198 F#6 1 7;200 D6 1 7;200 F6 1 7;202 B5 1 7;202 D#6 1 7;206 C6 1 7;206 E6 1 7;210 F6 1 7;210 G6 1 7;210 C7 1 7;214 F6 1 7;214 G6 1 7;214 C7 1 7;216 F6 1 7;216 G6 1 7;216 C7 1 7;228 E6 1 7;228 G6 1 7;230 D#6 1 7;230 F#6 1 7;232 D6 1 7;232 F6 1 7;234 B5 1 7;234 D#6 1 7;238 C6 1 7;238 E6 1 7;242 E5 1 7;242 G#5 1 7;244 F5 1 7;244 A5 1 7;246 G5 1 7;246 C6 1 7;250 C5 1 7;250 A5 1 7;252 E5 1 7;252 C6 1 7;254 F5 1 7;254 D6 1 7;260 G#5 1 7;260 D#6 1 7;266 F5 1 7;266 D6 1 7;272 C5 1 7;272 E5 1 7;272 C6 1 7;292 E6 1 7;292 G6 1 7;294 D#6 1 7;294 F#6 1 7;296 D6 1 7;296 F6 1 7;298 B5 1 7;298 D#6 1 7;302 C6 1 7;302 E6 1 7;306 E5 1 7;306 G#5 1 7;308 F5 1 7;308 A5 1 7;310 G5 1 7;310 C6 1 7;314 C5 1 7;314 A5 1 7;316 E5 1 7;316 C6 1 7;318 F5 1 7;318 D6 1 7;324 E6 1 7;324 G6 1 7;326 D#6 1 7;326 F#6 1 7;328 D6 1 7;328 F6 1 7;330 B5 1 7;330 D#6 1 7;334 C6 1 7;334 E6 1 7;338 F6 1 7;338 G6 1 7;338 C7 1 7;342 F6 1 7;342 G6 1 7;342 C7 1 7;344 F6 1 7;344 G6 1 7;344 C7 1 7;356 E6 1 7;356 G6 1 7;358 D#6 1 7;358 F#6 1 7;360 D6 1 7;360 F6 1 7;362 B5 1 7;362 D#6 1 7;366 C6 1 7;366 E6 1 7;370 E5 1 7;370 G#5 1 7;372 F5 1 7;372 A5 1 7;374 G5 1 7;374 C6 1 7;378 C5 1 7;378 A5 1 7;380 E5 1 7;380 C6 1 7;382 F5 1 7;382 D6 1 7;388 G#5 1 7;388 D#6 1 7;394 F5 1 7;394 D6 1 7;400 E5 1 7;400 C6 1 7;416 G#5 1 7;416 C6 1 7;418 G#5 1 7;418 C6 1 7;422 G#5 1 7;422 C6 1 7;426 G#5 1 7;426 C6 1 7;428 A#5 1 7;428 D6 1 7;432 G5 1 7;432 E6 1 7;434 E5 1 7;434 C6 1 7;438 E5 1 7;438 A5 1 7;440 C5 1 7;440 G5 1 7;448 G#5 1 7;448 C6 1 7;450 G#5 1 7;450 C6 1 7;454 G#5 1 7;454 C6 1 7;458 G#5 1 7;458 C6 1 7;460 A#5 1 7;460 D6 1 7;462 G5 1 7;462 E6 1 7;480 G#5 1 7;480 C6 1 7;482 G#5 1 7;482 C6 1 7;486 G#5 1 7;486 C6 1 7;490 G#5 1 7;490 C6 1 7;492 A#5 1 7;492 D6 1 7;496 G5 1 7;496 E6 1 7;498 E5 1 7;498 C6 1 7;502 E5 1 7;502 A5 1 7;504 C5 1 7;504 G5 1 7;512 F#5 1 7;512 E6 1 7;514 F#5 1 7;514 E6 1 7;518 F#5 1 7;518 E6 1 7;522 F#5 1 7;522 C6 1 7;524 F#5 1 7;524 E6 1 7;528 G5 1 7;528 B5 1 7;528 G6 1 7;536 G5 1 7;544 E5 1 7;544 C6 1 7;550 C5 1 7;550 G5 1 7;556 G4 1 7;556 E5 1 7;562 C5 1 7;562 A5 1 7;566 D5 1 7;566 B5 1 7;570 C#5 1 7;570 A#5 1 7;572 C5 1 7;572 A5 1 7;576 C5 1 7;576 G5 1 7;578 G5 1 7;578 E6 1 7;581 B5 1 7;581 G6 1 7;584 C6 1 7;584 A6 1 7;588 A5 1 7;588 F6 1 7;590 B5 1 7;590 G6 1 7;594 A5 1 7;594 E6 1 7;598 E5 1 7;598 C6 1 7;600 F5 1 7;600 D6 1 7;602 D5 1 7;602 B5 1 7;608 E5 1 7;608 C6 1 7;614 C5 1 7;614 G5 1 7;620 G4 1 7;620 E5 1 7;626 C5 1 7;626 A5 1 7;630 D5 1 7;630 B5 1 7;634 C#5 1 7;634 A#5 1 7;636 C5 1 7;636 A5 1 7;640 C5 1 7;640 G5 1 7;642 G5 1 7;642 E6 1 7;645 B5 1 7;645 G6 1 7;648 C6 1 7;648 A6 1 7;652 A5 1 7;652 F6 1 7;654 B5 1 7;654 G6 1 7;658 A5 1 7;658 E6 1 7;662 E5 1 7;662 C6 1 7;664 F5 1 7;664 D6 1 7;666 D5 1 7;666 B5 1 7;672 C6 1 7;672 E6 1 7;674 A5 1 7;674 C6 1 7;678 E5 1 7;678 G5 1 7;684 E5 1 7;684 G#5 1 7;688 F5 1 7;688 A5 1 7;690 C6 1 7;690 F6 1 7;694 C6 1 7;694 F6 1 7;696 F5 1 7;696 A5 1 7;704 G5 1 7;704 B5 1 7;706 F6 1 7;706 A6 1 7;709 F6 1 7;709 A6 1 7;712 F6 1 7;712 A6 1 7;714 E6 1 7;714 G6 1 7;717 D6 1 7;717 F6 1 7;720 C6 1 7;720 E6 1 7;722 A5 1 7;722 C6 1 7;726 F5 1 7;726 A5 1 7;728 E5 1 7;728 G5 1 7;736 C6 1 7;736 E6 1 7;738 A5 1 7;738 C6 1 7;742 E5 1 7;742 G5 1 7;748 E5 1 7;748 G#5 1 7;752 F5 1 7;752 A5 1 7;754 C6 1 7;754 F6 1 7;758 C6 1 7;758 F6 1 7;760 F5 1 7;760 A5 1 7;768 G5 1 7;768 B5 1 7;770 D6 1 7;770 F6 1 7;774 D6 1 7;774 F6 1 7;776 D6 1 7;776 F6 1 7;778 C6 1 7;778 E6 1 7;781 B5 1 7;781 D6 1 7;784 G5 1 7;784 C6 1 7;786 E5 1 7;790 E5 1 7;792 C5 1 7;800 C6 1 7;800 E6 1 7;802 A5 1 7;802 C6 1 7;806 E5 1 7;806 G5 1 7;812 E5 1 7;812 G#5 1 7;816 F5 1 7;816 A5 1 7;818 C6 1 7;818 F6 1 7;822 C6 1 7;822 F6 1 7;824 F5 1 7;824 A5 1 7;832 G5 1 7;832 B5 1 7;834 F6 1 7;834 A6 1 7;837 F6 1 7;837 A6 1 7;840 F6 1 7;840 A6 1 7;842 E6 1 7;842 G6 1 7;845 D6 1 7;845 F6 1 7;848 C6 1 7;848 E6 1 7;850 A5 1 7;850 C6 1 7;854 F5 1 7;854 A5 1 7;856 E5 1 7;856 G5 1 7;864 C6 1 7;864 E6 1 7;866 A5 1 7;866 C6 1 7;870 E5 1 7;870 G5 1 7;876 E5 1 7;876 G#5 1 7;880 F5 1 7;880 A5 1 7;882 C6 1 7;882 F6 1 7;886 C6 1 7;886 F6 1 7;888 F5 1 7;888 A5 1 7;896 G5 1 7;896 B5 1 7;898 D6 1 7;898 F6 1 7;902 D6 1 7;902 F6 1 7;904 D6 1 7;904 F6 1 7;906 C6 1 7;906 E6 1 7;909 B5 1 7;909 D6 1 7;912 G5 1 7;912 C6 1 7;914 E5 1 7;918 E5 1 7;920 C5 1 7;928 G#5 1 7;928 C6 1 7;930 G#5 1 7;930 C6 1 7;934 G#5 1 7;934 C6 1 7;938 G#5 1 7;938 C6 1 7;940 A#5 1 7;940 D6 1 7;944 G5 1 7;944 E6 1 7;946 E5 1 7;946 C6 1 7;950 E5 1 7;950 A5 1 7;952 C5 1 7;952 G5 1 7;960 G#5 1 7;960 C6 1 7;962 G#5 1 7;962 C6 1 7;966 G#5 1 7;966 C6 1 7;970 G#5 1 7;970 C6 1 7;972 A#5 1 7;972 D6 1 7;974 G5 1 7;974 E6 1 7;992 G#5 1 7;992 C6 1 7;994 G#5 1 7;994 C6 1 7;998 G#5 1 7;998 C6 1 7;1002 G#5 1 7;1002 C6 1 7;1004 A#5 1 7;1004 D6 1 7;1008 G5 1 7;1008 E6 1 7;1010 E5 1 7;1010 C6 1 7;1014 E5 1 7;1014 A5 1 7;1016 C5 1 7;1016 G5 1 7;1024 F#5 1 7;1024 E6 1 7;1026 F#5 1 7;1026 E6 1 7;1030 F#5 1 7;1030 E6 1 7;1034 F#5 1 7;1034 C6 1 7;1036 F#5 1 7;1036 E6 1 7;1040 G5 1 7;1040 B5 1 7;1040 G6 1 7;1048 G5 1 7;1056 C6 1 7;1056 E6 1 7;1058 A5 1 7;1058 C6 1 7;1062 E5 1 7;1062 G5 1 7;1068 E5 1 7;1068 G#5 1 7;1072 F5 1 7;1072 A5 1 7;1074 C6 1 7;1074 F6 1 7;1078 C6 1 7;1078 F6 1 7;1080 F5 1 7;1080 A5 1 7;1088 G5 1 7;1088 B5 1 7;1090 F6 1 7;1090 A6 1 7;1093 F6 1 7;1093 A6 1 7;1096 F6 1 7;1096 A6 1 7;1098 E6 1 7;1098 G6 1 7;1101 D6 1 7;1101 F6 1 7;1104 C6 1 7;1104 E6 1 7;1106 A5 1 7;1106 C6 1 7;1110 F5 1 7;1110 A5 1 7;1112 E5 1 7;1112 G5 1 7;1120 C6 1 7;1120 E6 1 7;1122 A5 1 7;1122 C6 1 7;1126 E5 1 7;1126 G5 1 7;1132 E5 1 7;1132 G#5 1 7;1136 F5 1 7;1136 A5 1 7;1138 C6 1 7;1138 F6 1 7;1142 C6 1 7;1142 F6 1 7;1144 F5 1 7;1144 A5 1 7;1152 G5 1 7;1152 B5 1 7;1154 D6 1 7;1154 F6 1 7;1158 D6 1 7;1158 F6 1 7;1160 D6 1 7;1160 F6 1 7;1162 C6 1 7;1162 E6 1 7;1165 B5 1 7;1165 D6 1 7;1168 G5 1 7;1168 C6 1 7;1170 E5 1 7;1174 E5 1 7;1176 C5 1 7;0 D4 1 7;2 D4 1 7;6 D4 1 7;10 D4 1 7;12 D4 1 7;24 G4 1 7;32 G4 1 7;38 E4 1 7;44 C4 1 7;50 F4 1 7;54 G4 1 7;58 F#4 1 7;60 F4 1 7;64 E4 1 7;66 C5 1 7;69 E5 1 7;72 F5 1 7;76 D5 1 7;78 E5 1 7;82 C5 1 7;86 A4 1 7;88 B4 1 7;90 G4 1 7;96 G4 1 7;102 E4 1 7;108 C4 1 7;114 F4 1 7;118 G4 1 7;122 F#4 1 7;124 F4 1 7;128 E4 1 7;130 C5 1 7;133 E5 1 7;136 F5 1 7;140 D5 1 7;142 E5 1 7;146 C5 1 7;150 A4 1 7;152 B4 1 7;154 G4 1 7;160 C4 1 7;166 G4 1 7;172 C5 1 7;176 F4 1 7;182 C5 1 7;184 C5 1 7;188 F4 1 7;192 C4 1 7;198 E4 1 7;204 G4 1 7;206 C5 1 7;220 G4 1 7;224 C4 1 7;230 G4 1 7;236 C5 1 7;240 F4 1 7;246 C5 1 7;248 C5 1 7;252 F4 1 7;256 C4 1 7;260 G#4 1 7;266 A#4 1 7;278 G4 1 7;280 G4 1 7;284 C4 1 7;288 C4 1 7;294 G4 1 7;300 C5 1 7;304 F4 1 7;310 C5 1 7;312 C5 1 7;316 F4 1 7;320 C4 1 7;326 E4 1 7;332 G4 1 7;334 C5 1 7;348 G4 1 7;352 C4 1 7;358 G4 1 7;364 C5 1 7;368 F4 1 7;374 C5 1 7;376 C5 1 7;380 F4 1 7;384 C4 1 7;388 G#4 1 7;394 A#4 1 7;400 C5 1 7;406 G4 1 7;408 G4 1 7;412 C4 1 7;416 G#3 1 7;422 D#4 1 7;428 G#4 1 7;432 G4 1 7;438 C4 1 7;444 G3 1 7;448 G#3 1 7;454 D#4 1 7;460 G#4 1 7;464 G4 1 7;470 C4 1 7;476 G3 1 7;480 G#3 1 7;486 D#4 1 7;492 G#4 1 7;496 G4 1 7;502 C4 1 7;508 G3 1 7;512 D4 1 7;514 D4 1 7;518 D4 1 7;522 D4 1 7;524 D4 1 7;536 G4 1 7;544 G4 1 7;550 E4 1 7;556 C4 1 7;562 F4 1 7;566 G4 1 7;570 F#4 1 7;572 F4 1 7;576 E4 1 7;578 C5 1 7;581 E5 1 7;584 F5 1 7;588 D5 1 7;590 E5 1 7;594 C5 1 7;598 A4 1 7;600 B4 1 7;602 G4 1 7;608 G4 1 7;614 E4 1 7;620 C4 1 7;626 F4 1 7;630 G4 1 7;634 F#4 1 7;636 F4 1 7;640 E4 1 7;642 C5 1 7;645 E5 1 7;648 F5 1 7;652 D5 1 7;654 E5 1 7;658 C5 1 7;662 A4 1 7;664 B4 1 7;666 G4 1 7;672 C4 1 7;678 F#4 1 7;680 G4 1 7;684 C5 1 7;688 F4 1 7;692 F4 1 7;696 C5 1 7;698 C5 1 7;700 F4 1 7;704 D4 1 7;710 F4 1 7;712 G4 1 7;716 B4 1 7;720 G4 1 7;724 G4 1 7;728 C5 1 7;730 C5 1 7;732 G4 1 7;736 C4 1 7;742 F#4 1 7;744 G4 1 7;748 C5 1 7;752 F4 1 7;756 F4 1 7;760 C5 1 7;762 C5 1 7;764 F4 1 7;768 G4 1 7;774 G4 1 7;776 G4 1 7;778 A4 1 7;781 B4 1 7;784 C5 1 7;788 G4 1 7;792 C4 1 7;800 C4 1 7;806 F#4 1 7;808 G4 1 7;812 C5 1 7;816 F4 1 7;820 F4 1 7;824 C5 1 7;826 C5 1 7;828 F4 1 7;832 D4 1 7;838 F4 1 7;840 G4 1 7;844 B4 1 7;848 G4 1 7;852 G4 1 7;856 C5 1 7;858 C5 1 7;860 G4 1 7;864 C4 1 7;870 F#4 1 7;872 G4 1 7;876 C5 1 7;880 F4 1 7;884 F4 1 7;888 C5 1 7;890 C5 1 7;892 F4 1 7;896 G4 1 7;902 G4 1 7;904 G4 1 7;906 A4 1 7;909 B4 1 7;912 C5 1 7;916 G4 1 7;920 C4 1 7;928 G#3 1 7;934 D#4 1 7;940 G#4 1 7;944 G4 1 7;950 C4 1 7;956 G3 1 7;960 G#3 1 7;966 D#4 1 7;972 G#4 1 7;976 G4 1 7;982 C4 1 7;988 G3 1 7;992 G#3 1 7;998 D#4 1 7;1004 G#4 1 7;1008 G4 1 7;1014 C4 1 7;1020 G3 1 7;1024 D4 1 7;1026 D4 1 7;1030 D4 1 7;1034 D4 1 7;1036 D4 1 7;1048 G4 1 7;1056 C4 1 7;1062 F#4 1 7;1064 G4 1 7;1068 C5 1 7;1072 F4 1 7;1076 F4 1 7;1080 C5 1 7;1082 C5 1 7;1084 F4 1 7;1088 D4 1 7;1094 F4 1 7;1096 G4 1 7;1100 B4 1 7;1104 G4 1 7;1108 G4 1 7;1112 C5 1 7;1114 C5 1 7;1116 G4 1 7;1120 C4 1 7;1126 F#4 1 7;1128 G4 1 7;1132 C5 1 7;1136 F4 1 7;1140 F4 1 7;1144 C5 1 7;1146 C5 1 7;1148 F4 1 7;1152 G4 1 7;1158 G4 1 7;1160 G4 1 7;1162 A4 1 7;1165 B4 1 7;1168 C5 1 7;1172 G4 1 7;1176 C4 1 7;:</code></pre><p>真是一大串呢~</p><p>稍微分析一下 Online Sequencer 乐谱的格式：</p><ol><li><code>Online Sequencer:616413:</code> 没有什么用，要被除掉</li><li><code>0 F#5 1 7;</code> 才是重点。<code>0</code> 是音符所处的时间位置，<code>F#5</code> 是音符的音高，<code>1</code> 是音符的持续时间，<code>7</code> 是播放用的乐器类型。Online Sequencer 乐谱中每个音符都是这样的格式，用分号隔开</li><li>还要注意最后有一个 <code>:</code>，这个也要除掉</li></ol><p>那么来编写一下将 Online Sequencer 乐谱转换为 Python 字典的代码吧。</p><p>先将 Online Sequencer 乐谱中需要被去除的部分去除掉，然后将乐谱中的音符部分根据 <code>;</code> 分割开来：</p><pre><code class="language-python">song = song_file.split(":")[2]notes_list = song.split(";")[:-1]</code></pre><p>接着把音符的时间位置提取出来，设为字典的键，音符的音高、持续时间和乐器类型设为字典的值：</p><pre><code class="language-python">notes_dict = {}for note in notes_list:    note_parts = note.split()    beat = float(note_parts[0])    # 如果该时间位置是初次被添加到字典当中    if beat not in notes_dict:        # 添加该音符的信息到字典里        notes_dict[beat] = note_parts[1:]    # 如果该时间位置并不是第一次被添加到字典当中    else:        # 如果该音符的音高比字典中已有的音符的音高更高        if tones[note_parts[1]] &gt; tones[notes_dict[beat][0]]:            # 将该音符的信息覆盖到字典里            notes_dict[beat] = note_parts[1:]</code></pre><p>由于是单个蜂鸣器播放，所以无法同时播放多个音符。当同个时间位置有多个音符时，我们只能选择音高最高的音符来播放。</p><p>至此，我们已经有了一个 Python 字典作为我们的乐谱。</p><h2 id="播放音频"><a class="markdownIt-Anchor" href="#播放音频"></a> 播放音频</h2><p>想要让蜂鸣器发出声音来很简单，代码如下：</p><pre><code class="language-python">buzzer.freq(tones[tone])time.sleep(duration)</code></pre><p><code>buzzer.freq()</code> 会设置蜂鸣器的频率，<code>time.sleep()</code> 会让程序暂停一段时间（在我们这个例子中，就是用来拉长音的）。</p><h2 id="播放乐谱"><a class="markdownIt-Anchor" href="#播放乐谱"></a> 播放乐谱</h2><p>结合上面两个部分，我们可以让字典中的音符一个一个地播放出来。但在这之前，还需要设置乐谱的播放速度。</p><pre><code class="language-python">bpm = 199  # 每分钟节拍数time_signature = [4, 4]  # 拍号beat_duration = (60 / bpm) / time_signature[0]  # 每拍的持续时间</code></pre><p>聊 <a href="#%E9%A2%98%E5%A4%96%E8%AF%9D">乐谱知识</a> 时说到过，拍号决定了每一小节有多少拍，什么音符的时值是一拍。从我们拿来马里奥曲子的 <a href="https://onlinesequencer.net/25966">网站</a> 里能看到，马里奥曲子的 bpm 是 199、拍号是 4 / 4。</p><p>进行一小些计算，算出每一拍的持续时间为 <code>(60 / 199) / 4</code>。</p><p>继续编写播放乐谱的代码：</p><pre><code class="language-python"># 从第0拍开始播放current_beat = float(0)# 播放到乐谱中最后一个音符的时间位置while current_beat &lt;= max(notes_dict.keys()):       # 取出当前时间位置的音符的持续时间（持续了多少拍），乘以每拍的持续时间，得到音符的持续时间（持续了多少秒）    note_duration = float(notes_dict[current_beat][1]) * beat_duration     # 如果当前时间位置有音符，就播放    if current_beat in notes_dict:        note_name = notes_dict[current_beat][0]                print("第" + str(current_beat) + "拍：播放音符 " + note_name + " 中，持续时间为 " + str(note_duration) + " 秒。")        buzzer.freq(tones[note_name])        time.sleep(note_duration)        current_beat += float(notes_dict[current_beat][1])        buzzer.freq(50000)        # 如果当前时间位置没有音符，就暂停    else:        print("第" + str(current_beat) + "拍：暂停，持续时间为" + str(note_duration) + " 秒。")        buzzer.freq(50000)        time.sleep(beat_duration)        current_beat += 1print("播放结束。")buzzer.freq(50000)</code></pre><p>一个简单的播放乐谱的程序便完成了。</p><p>最终代码可以在 <a href="https://github.com/Cytrogen/Music_Player_Pico">这个仓库</a> 里找到。</p><center>————————</center><h1 id="最终效果"><a class="markdownIt-Anchor" href="#最终效果"></a> 最终效果</h1><div class="danger">该视频实际上并未是最终版本的效果，但没有差别多少。</div><video id="video" controls="" height="420">    <source id="mp4" src="ba6a/8.mp4" type="video/mp4"></video></body></html>]]></content>
    
    
    <summary type="html">本文是一篇使用 MicroPython 在树莓派 Pico 上通过有源蜂鸣器播放音乐的详细教程。文章以《超级马里奥》主题曲为例，从零开始指导你如何将在线乐谱（来自 Online Sequencer）解析为程序可用的数据结构，并利用 MicroPython 的 PWM 功能精确控制蜂鸣器的频率和发声时长。内容不仅涵盖了代码实现，还为不熟悉乐理的读者科普了音符、节拍等基础知识，非常适合 Pico 入门玩家和对硬件音乐项目感兴趣的朋友。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Python" scheme="https://blog.cytrogen.icu/tags/Python/"/>
    
    <category term="树莓派" scheme="https://blog.cytrogen.icu/tags/%E6%A0%91%E8%8E%93%E6%B4%BE/"/>
    
  </entry>
  
  <entry>
    <title>DiskGenius 分配空闲空间至 C 盘</title>
    <link href="https://blog.cytrogen.icu/posts/cf92.html"/>
    <id>https://blog.cytrogen.icu/posts/cf92.html</id>
    <published>2023-04-20T00:37:26.000Z</published>
    <updated>2026-02-09T17:16:54.689Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>如何使用 DiskGenius 将空闲空间添加至爆满的 C 盘。</p><span id="more"></span><h1 id="前言"><a class="markdownIt-Anchor" href="#前言"></a> 前言</h1><p>省流：C 盘满了。老是忘记 DiskGenius 怎么操作。故给未来的自己写个小教程。</p><img src="/posts/cf92/C盘.webp" alt="爆满的C盘，9.47GB可用，共109GB" loading="lazy"><p>DiskGenius 如何下载就不说了，直接开始分配。</p><h1 id="分配空闲空间"><a class="markdownIt-Anchor" href="#分配空闲空间"></a> 分配空闲空间</h1><ol><li><p>打开我们的 DiskGenius，先把我们的 E 盘「切」掉一块，供后续喂给 C 盘。<br>右键 E 盘，点击 <code>Resize partition</code>。<br><img src="/posts/cf92/1.webp" alt="右键点击 E 盘，点击 Resize partition" loading="lazy"></p></li><li><p>先切个 20GB 出来。<br>在 <code>Space of Front Part</code> 处输入 20.00GB，然后右侧的下拉栏改成 <code>Merge to C盘</code>。<br><img src="/posts/cf92/2.webp" alt="在Space of Front Part输出20.00GB，Merge to C盘" loading="lazy"></p></li><li><p>确认、确认、确认……<br>注意图 2 是确认重启计算机。<br><img src="/posts/cf92/3.webp" alt="依次点击 Start 和 Yes" loading="lazy"><br><img src="/posts/cf92/4.webp" alt="确认重启计算机" loading="lazy"></p></li><li><p>计算机重启后再次查看 C 盘容量。不是红的了呢~<br><img src="/posts/cf92/5.webp" alt="蓝色的C盘，28.6GB可用，共129GB" loading="lazy"></p></li></ol></body></html>]]></content>
    
    
    <summary type="html">C盘空间不足、爆红了怎么办？本文是一篇使用 DiskGenius 工具为C盘扩容的图文教程。文章通过详细的截图和步骤，清晰地演示了如何从其他磁盘分区（如D盘、E盘）中划分出一部分空闲空间，并将其无损地合并到C盘，从而解决系统盘容量告急的问题。本教程操作简单，适合新手快速上手。</summary>
    
    
    
    <category term="工具" scheme="https://blog.cytrogen.icu/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="DiskGenius" scheme="https://blog.cytrogen.icu/tags/DiskGenius/"/>
    
  </entry>
  
  <entry>
    <title>GPT-3 API 笔记</title>
    <link href="https://blog.cytrogen.icu/posts/40b3.html"/>
    <id>https://blog.cytrogen.icu/posts/40b3.html</id>
    <published>2023-03-09T19:02:26.000Z</published>
    <updated>2026-02-09T17:16:54.709Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>GPT-3 和 GPT-3.5-Turbo API 的学习日志，仅作个人用途。</p><span id="more"></span><h1 id="目录"><a class="markdownIt-Anchor" href="#目录"></a> 目录</h1><ul><li><a href="#%E7%9B%AE%E5%BD%95">目录</a></li><li><a href="#%E4%BA%8B%E5%85%88%E5%87%86%E5%A4%87">事先准备</a></li><li><a href="#%E5%88%9B%E5%BB%BA%E5%BE%AE%E8%B0%83%E6%A8%A1%E5%9E%8B">创建微调模型</a><ul><li><a href="#%E6%9F%A5%E7%9C%8B%E5%BE%AE%E8%B0%83%E5%B7%A5%E4%BD%9C">查看微调工作</a></li></ul></li><li><a href="#%E5%88%A0%E9%99%A4%E5%BE%AE%E8%B0%83%E6%A8%A1%E5%9E%8B">删除微调模型</a></li><li><a href="#%E4%BD%BF%E7%94%A8%E5%BE%AE%E8%B0%83%E6%A8%A1%E5%9E%8B">使用微调模型</a></li></ul><center> ------------------</center><h1 id="事先准备"><a class="markdownIt-Anchor" href="#事先准备"></a> 事先准备</h1><pre><code class="language-bash">pip install openai# 使用bash...export OPENAI_API_KEY="你的OpenAI API KEY"</code></pre><h1 id="创建微调模型"><a class="markdownIt-Anchor" href="#创建微调模型"></a> 创建微调模型</h1><div class="danger"><p>注意，GPT-3.5-Turbo API 目前 <strong>不支持</strong> 微调！</p><p>该栏块说的 API 统一默认为 <strong>GPT-3</strong>！</p></div><p>微调 GPT-3 所需要的数据必须是 <code>JSONL</code> 文件，格式为：</p><pre><code class="language-plaintext">{"prompt": "提白文本", "completion": "想要生成的文本"}</code></pre><p>假设已经有一个 <code>CSV</code>、<code>TSV</code>、<code>XLSX</code> 或 <code>JSON</code> 文件作为数据库，则可以使用以下命令行来重新格式化数据：</p><pre><code class="language-bash">openai tools fine_tunes.prepare_data -f 文件名</code></pre><p>有了 <code>JSONL</code> 文件后，开始微调：</p><pre><code class="language-bash">openai api fine_tunes.create -t JSONL文件名 -m 模型名</code></pre><blockquote><p>模型名分为：ada、babbage、curie、davinci。<br>从左到右，速度越来越慢，能力越来越强。</p></blockquote><div class="danger"><p>注意：</p><p>一定要仔细查看微调模型的价格表！</p><table><thead><tr><th>模型</th><th>训练</th><th>使用</th></tr></thead><tbody><tr><td>Ada</td><td>$0.0004 / 1K tokens</td><td>$0.0016 / 1K tokens</td></tr><tr><td>Babbage</td><td>$0.0006 / 1K tokens</td><td>$0.0024 / 1K tokens</td></tr><tr><td>Curie</td><td>$0.0030 / 1K tokens</td><td>$0.0120 / 1K tokens</td></tr><tr><td>Davinci</td><td>$0.0300 / 1K tokens</td><td>$0.1200 / 1K tokens</td></tr></tbody></table></div><p>有时事件流可能会被中断，使用以下命令行来恢复微调：</p><pre><code class="language-bash">openai api fine_tunes.follow -i 微调工作ID</code></pre><blockquote><p>事件流被中断后会自动生成一个命令供你复制粘贴运行。</p></blockquote><h2 id="查看微调工作"><a class="markdownIt-Anchor" href="#查看微调工作"></a> 查看微调工作</h2><p>列出所有被创建的微调工作：</p><pre><code class="language-bash">openai api fine_tunes.list</code></pre><p>检索一个微调工作的状态和其他信息：</p><pre><code class="language-bash">openai api fine_tunes.get -i 微调工作ID</code></pre><p>取消一个微调工作：</p><pre><code class="language-bash">openai api fine_tunes.cancel -i 微调工作ID</code></pre><h1 id="删除微调模型"><a class="markdownIt-Anchor" href="#删除微调模型"></a> 删除微调模型</h1><p>有光就有影子，有创建就有删除：</p><pre><code class="language-bash">openai api models.delete -i 微调模型</code></pre><p>Python 也可以删除一个微调模型：</p><pre><code class="language-python">import openaiopenai.Model.delete(微调模型)</code></pre><center>------------------</center><h1 id="使用微调模型"><a class="markdownIt-Anchor" href="#使用微调模型"></a> 使用微调模型</h1><p>你可以直接使用微调成功后，自动生成的命令行：</p><pre><code class="language-bash">openai api completions.create -m 微调模型 -p 提白</code></pre><p>当然主要的还是我们的 Python，这是官网示范：</p><pre><code class="language-python">import openaiopenai.Completion.create(    model=FINE_TUNED_MODEL,    prompt=YOUR_PROMPT)</code></pre><p><code>openai.Completion.create()</code> 返回一个字典：</p><pre><code class="language-python">{    "choices": [        {            "finish_reason": "length",            "index": 数字,            "logprobs": null,            "text": "字符串"        }    ],    "created": 数字,    "id": "字符串",    "model": "微调模型",    "object": "text_completion",    "usage": {        "completion_tokens": 数字,        "prompt_tokens": 数字,        "total_tokens": 数字    }}</code></pre><p>也就是说，只要拿到 <code>openai.Completion.create()['choices'][0]['text']</code>，就拿到了模型返回的字符串，我们打印这个字符串就好了。</p><p>稍作修改一番：</p><pre><code class="language-python">import openaiimport prompt_toolkitwhile True:    user_input = prompt_toolkit.prompt('&gt; ')    response = openai.Completion.create(        model=微调模型,        prompt=user_input    )    print(response['choices'][0]['text'])</code></pre><p>一个简易的控制台机器人就写好了。</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;GPT-3 和 GPT-3.5-Turbo API 的学习日志，仅作个人用途。&lt;/p&gt;</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Python" scheme="https://blog.cytrogen.icu/tags/Python/"/>
    
    <category term="AI" scheme="https://blog.cytrogen.icu/tags/AI/"/>
    
  </entry>
  
  <entry>
    <title>Bot Framework SDK 学习日志</title>
    <link href="https://blog.cytrogen.icu/posts/60db.html"/>
    <id>https://blog.cytrogen.icu/posts/60db.html</id>
    <published>2023-03-07T18:28:26.000Z</published>
    <updated>2026-02-09T17:16:54.681Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>仅作个人用途，微软 Azure 的机器人框架 SDK Python 分支的学习日志。</p><span id="more"></span><h1 id="目录"><a class="markdownIt-Anchor" href="#目录"></a> 目录</h1><ul><li><a href="#%E7%9B%AE%E5%BD%95">目录</a></li><li><a href="#%E6%9C%BA%E5%99%A8%E4%BA%BA%E5%88%9D%E8%AF%86">机器人初识</a><ul><li><a href="#%E6%9C%BA%E5%99%A8%E4%BA%BA%E4%BA%A4%E4%BA%92">机器人交互</a></li><li><a href="#%E6%9C%BA%E5%99%A8%E4%BA%BA%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E7%BB%93%E6%9E%84">机器人应用程序结构</a></li><li><a href="#%E6%9C%BA%E5%99%A8%E4%BA%BA%E9%80%BB%E8%BE%91">机器人逻辑</a></li><li><a href="#%E6%9C%BA%E5%99%A8%E4%BA%BA%E9%80%82%E9%85%8D%E5%99%A8">机器人适配器</a></li><li><a href="#%E8%BD%AE%E6%AC%A1%E4%B8%8A%E4%B8%8B%E6%96%87">轮次上下文</a></li><li><a href="#%E4%B8%AD%E9%97%B4%E4%BB%B6">中间件</a></li><li><a href="#%E6%B4%BB%E5%8A%A8%E5%A4%84%E7%90%86%E5%A0%86%E6%A0%88">活动处理堆栈</a></li><li><a href="#%E6%9C%BA%E5%99%A8%E4%BA%BA%E6%A8%A1%E6%9D%BF">机器人模板</a></li></ul></li><li><a href="#%E6%9C%BA%E5%99%A8%E4%BA%BA%E5%8A%A0%E6%B7%B1%E8%AE%A4%E8%AF%86">机器人加深认识</a><ul><li><a href="#%E7%AE%A1%E7%90%86%E7%8A%B6%E6%80%81">管理状态</a></li><li><a href="#%E6%B4%BB%E5%8A%A8%E5%A4%84%E7%90%86%E7%A8%8B%E5%BA%8F">活动处理程序</a></li><li><a href="#%E5%AF%B9%E8%AF%9D%E5%BA%93">对话库</a></li><li><a href="#%E4%B8%89%E5%A4%A7%E5%AF%B9%E8%AF%9D%E6%A1%86">三大对话框</a></li><li><a href="#%E4%BD%BF%E7%94%A8%E5%AF%B9%E8%AF%9D%E6%A1%86">使用对话框</a></li><li><a href="#%E9%85%8D%E7%BD%AE%E6%9C%BA%E5%99%A8%E4%BA%BA">配置机器人</a></li></ul></li></ul><center> -----------------------------</center><h1 id="机器人初识"><a class="markdownIt-Anchor" href="#机器人初识"></a> 机器人初识</h1><h2 id="机器人交互"><a class="markdownIt-Anchor" href="#机器人交互"></a> 机器人交互</h2><p>机器人交互涉及到活动的交换，而这些活动在轮次中进行处理。</p><ol><li><p><em>活动（activities）</em>：活动是用户或者 <em>通道（channel）</em> 与机器人之间的交互。</p></li><li><p><em>轮次（turns）</em>：一轮次的对话包含了用户传给机器人的活动，也包含了机器人发给用户的即时响应（也是活动）。</p><p>类似于回合制战斗，速度快的我方先行采取一个行动后，速度慢的对面再采取一个行动，双方行动过后该轮次（或称回合）结束。</p></li></ol><h2 id="机器人应用程序结构"><a class="markdownIt-Anchor" href="#机器人应用程序结构"></a> 机器人应用程序结构</h2><ol><li>* <strong> 机器人</strong>（bot）* 类，用于处理机器人应用的聊天推理<ul><li>识别 &amp; 解释用户的输入</li><li>对输入进行推理 &amp; 执行相关任务</li><li>生成响应（如：机器人正在干什么）</li></ul></li><li>* <strong> 适配器</strong>（adapter）* 类，用于处理与通道的连接<ul><li>提供用于处理来自用户通道的请求的方法</li><li>提供用于对用户通道生成请求的方法</li><li>包含一个中间件通道，包括机器人轮次处理程序外部的轮次处理</li><li>调用机器人的轮次处理程序</li><li>捕获不在轮次处理程序中处理的错误</li></ul></li></ol><p>机器人每个轮次还需要检索和存储 <em>状态（state）</em>。状态通过 <em>存储（storage）</em>、<em>机器人状态（bot state）</em> 和 <em>属性访问器（property accessor）</em> 类进行处理。</p><h2 id="机器人逻辑"><a class="markdownIt-Anchor" href="#机器人逻辑"></a> 机器人逻辑</h2><ol><li><em><strong>活动处理程序</strong>（activity handler）</em>，提供事件驱动模型，其中传入的活动类型 &amp; 子类型是 <em>事件（event）</em>。</li><li><em><strong>对话库</strong>（dialog library）</em>，提供基于状态的模型用于管理与用户进行的长时间聊天。</li></ol><h2 id="机器人适配器"><a class="markdownIt-Anchor" href="#机器人适配器"></a> 机器人适配器</h2><p>适配器提供用于启动轮次的 <em>过程活动（process activity）</em> 方法。</p><ul><li>将请求正文和请求头用于参数</li><li>检查身份验证头是否有效</li><li>为轮次创建一个 <em>上下文（context）</em> 对象<ul><li>上下文对象包含有关活动的信息</li></ul></li><li>通过中间件管道发送上下文对象</li><li>将上下文对象发送到机器人对象的 <em>轮次处理程序（turn handler）</em></li></ul><blockquote><p>适配器还可以：</p><ul><li>格式化 &amp; 发送响应活动</li><li><em>公开机器人连接器（Bot Connector）</em> REST API 提供的其他方法</li><li>捕获在轮次中不会被捕获到的错误 &amp; 异常</li></ul></blockquote><h2 id="轮次上下文"><a class="markdownIt-Anchor" href="#轮次上下文"></a> 轮次上下文</h2><p><em>轮次上下文（turn context）</em> 对象提供有关活动的信息。</p><ul><li>例如发送方和接收方、通道、处理该活动所需的其他数据</li></ul><p>轮次上下文不仅将 <em>入站活动（inbound activity）</em> 传递到所有的中间件组件和应用程序逻辑，还提供了所需要的机制让中间件组件和机器人逻辑发送 <em>出站活动（outbound activity）</em>。</p><h2 id="中间件"><a class="markdownIt-Anchor" href="#中间件"></a> 中间件</h2><p>SDK 的中间件由一组线性组件构成，其中每一个组件都会按照顺序执行并有一个操作活动的机会。</p><p>中间件管道的最后一个阶段：回调机器人类中的轮次处理程序（已经被适配器的过程活动方法注册）。中间件执行被适配器调用的 <code>on turn</code> 方法。</p><p>轮次处理程序采用轮次上下文作为参数。在轮次处理程序函数内运行的应用程序逻辑会处理入站活动的内容，并生成活动作为响应，在轮次上下文中调用 <code>send activity</code> 方法来发送出站活动。调用 <code>send activity</code> 方法会导致中间件组件在出站活动上被调用。</p><p>中间件组件于轮次处理程序函数之前和之后执行。这些执行在本质上是套娃。</p><h2 id="活动处理堆栈"><a class="markdownIt-Anchor" href="#活动处理堆栈"></a> 活动处理堆栈</h2><ol><li>通道终结点向 Azure 机器人服务发送 HTTP POST 信息</li><li>Azure 机器人服务处理活动，发送给适配器和轮次上下文</li><li>适配器和轮次上下文调用 <code>on turn</code> 方法，发送给机器人</li><li>机器人调用 <code>send activity</code> 方法，一个个返回给通道终结点</li><li>通道终结点发送回状态码 200，机器人同理</li></ol><h2 id="机器人模板"><a class="markdownIt-Anchor" href="#机器人模板"></a> 机器人模板</h2><ul><li>资源预配</li><li>一个特定于语言的 HTTP 终结点实现，可以将传入的活动路由到一个适配器</li><li>一个适配器对象</li><li>一个机器人对象</li></ul><center>-----------------------------</center><h1 id="机器人加深认识"><a class="markdownIt-Anchor" href="#机器人加深认识"></a> 机器人加深认识</h1><h2 id="管理状态"><a class="markdownIt-Anchor" href="#管理状态"></a> 管理状态</h2><p>之前说过，机器人本质上是没有状态的。状态并不是必需的，部分机器人可以不需要状态（也就是用户不提供信息）就正常运行；部分机器人则必须提供了状态才能提供有用的聊天信息，例如以前收到的有关用户的数据。</p><p>状态就像是记忆，提供给了机器人后便能让机器人记住有关用户或者本次聊天的信息。</p><ul><li><p><em><strong>存储层</strong>（storage layer）</em>，在后端实际存储状态信息的一层。采用物理存储，如：内存、Azure 服务器、第三方服务器。</p><blockquote><ul><li>内存存储：临时存储，机器人一重开就清除</li><li>Azure Blob 存储：连接到 Azure Blob 存储对象数据库</li><li>Azure Cosmos DB 分区存储：连接到分区的 Cosmos DB NoSQL 数据库</li></ul></blockquote></li><li><p><em><strong>状态管理</strong>（state management）</em>，自动在基础存储层中读取 &amp; 写入机器人的状态。状态以 <em>状态属性（state properties）</em> 的键值对形式存储。</p><p>状态属性被集结到有范围的「桶」（帮助组织这些属性的集合）内，SDK 的三个桶分别是：<em>用户状态（user state）</em>、<em>聊天状态（conversation state）</em>、<em>私人聊天状态（private conversation state）</em>。这些桶又是 <code>bot state</code> 类的子类。</p><ul><li><p>用户状态适合用于跟踪有关用户的信息，如：用户的姓名</p></li><li><p>聊天状态适合用于跟踪聊天的上下文，如：机器人是否向用户提出了问题，这个问题又是啥</p></li><li><p>私人聊天状态适合用于支持群组聊天的通道，如：课堂抢答机器人（聚合每位学生的成绩，最终用私聊方式将信息发送给相应的学生）</p></li></ul></li><li><p><em><strong>状态属性访问器</strong>（state property accessors）</em>，用于实际读取 &amp; 写入某个状态属性，提供了 <code>get</code>、<code>set</code> 和 <code>delete</code> 方法用于从轮次内部访问状态属性。</p><p>访问器创建需要用到属性名称。之后便可以使用访问器来获取和处理机器人状态的该属性。</p><p>访问器允许 SDK 从基础存储获取状态 &amp; 更新机器人的状态缓存（机器人维护的本地缓存，用于存储状态对象和允许在不访问基础存储的情况下执行读取 &amp; 写入操作）。</p><ul><li><p><code>get</code> 方法，从状态缓存请求属性。如果在缓存中就返回属性，否则从状态管理对象获取该属性</p></li><li><p><code>set</code> 方法，使用新属性值更新状态缓存</p></li><li><p><code>delete</code> 方法，从缓存和基础存储中删除属性</p></li><li><p><code>save changes</code> 方法（状态管理对象的），检查状态缓存中属性所有的更改，并将属性写入存储</p><ul><li>要注意，<code>set</code> 方法记录更新的状态后，该状态属性尚未保存到持久性存储，只是保存到机器人的状态缓存内而已。</li></ul></li></ul></li></ul><p><em>对话框（dialog）</em> 库使用在机器人的 <em>会话状态（conversation state）</em> 上定义的对话框状态属性访问器来保留对话在会话中的位置。对话框状态属性还允许每个对话框在轮次之中存储临时信息。</p><p><em>对话框管理器（dialog manager）</em> 使用用户和会话状态管理对象提供内存范围（这些内存范围可以用于自适应对话框）。</p><h2 id="活动处理程序"><a class="markdownIt-Anchor" href="#活动处理程序"></a> 活动处理程序</h2><p>生成机器人时，用于处理和响应消息的机器人逻辑将进入 <code>on_message_activity</code> 处理程序。同样，用于处理正在添加到聊天中的成员的逻辑将进入 <code>on_members_added</code> 处理程序。每当一个成员加入到聊天，这个处理程序就会被调用。</p><p>机器人逻辑处理来自单个或多个通道的传入活动，并在响应中发生传出活动。</p><p>在 Python 里，要使用 <code>ActivityHandler</code> 派生机器人类，前者为不同类型的活动定义各种各样的处理程序，例如上文的 <code>on_message_activity</code> 处理程序。</p><details><table><thead><tr><th>事件</th><th style="text-align:left">Handler</th><th>说明</th></tr></thead><tbody><tr><td>已收到任一活动类型</td><td style="text-align:left"><code>on_turn</code></td><td>根据收到的活动类型，调用其他处理程序。</td></tr><tr><td>已收到消息活动</td><td style="text-align:left"><code>on_message_activity</code></td><td>处理 <code>message</code> 活动。</td></tr><tr><td>已收到聊天更新活动</td><td style="text-align:left"><code>on_conversation_update_activity</code></td><td>收到 <code>conversationUpdate</code> 活动时，如果除了机器人以外的成员加入或者退出聊天，则调用某个处理程序。</td></tr><tr><td>非机器人成员加入了聊天</td><td style="text-align:left"><code>on_members_added_activity</code></td><td>处理加入聊天的成员。</td></tr><tr><td>非机器人成员退出了聊天</td><td style="text-align:left"><code>on_members_removed_activity</code></td><td>处理退出聊天的成员。</td></tr><tr><td>已收到事件活动</td><td style="text-align:left"><code>on_event_activity</code></td><td>收到 <code>event</code> 活动时，调用特定于事件类型的处理程序。</td></tr><tr><td>已收到令牌响应事件活动</td><td style="text-align:left"><code>on_token_response_event</code></td><td>处理令牌响应时间。</td></tr><tr><td>已收到非令牌响应事件活动</td><td style="text-align:left"><code>on_event_activity</code></td><td>处理其他类型的事件。</td></tr><tr><td>已收到消息回应活动</td><td style="text-align:left"><code>on_message_reaction_activity</code></td><td>收到 <code>messageReaction</code> 活动时，如果已经在消息中添加 &amp; 删除一个或多个回应，则调用处理程序。</td></tr><tr><td>消息回应已添加到消息</td><td style="text-align:left"><code>on_reaction_added</code></td><td>处理添加到消息的回应。</td></tr><tr><td>从消息中删除了消息回应</td><td style="text-align:left"><code>on_reaction_removed</code></td><td>处理从消息中删除的回应。</td></tr><tr><td>已收到安装更新活动</td><td style="text-align:left"><code>on_installation_update</code></td><td>对于 <code>installationUpdate</code> 活动，根据机器人是「已安装」还是「已卸载」来调用处理程序。</td></tr><tr><td>安装了机器人</td><td style="text-align:left"><code>on_installation_update_add</code></td><td>添加逻辑来确定何时在组织单位中安装了机器人。</td></tr><tr><td>卸载了机器人</td><td style="text-align:left"><code>on_installation_update_remove</code></td><td>添加逻辑来确定何时在组织单位中卸载了机器人。</td></tr><tr><td>已收到其他活动类型</td><td style="text-align:left"><code>on_unrecognized_activity_type</code></td><td>处理未经处理的任何活动类型。</td></tr></tbody></table></details><p>每个处理程序都有一个 <code>turn_context</code>，用于提供有关对应于入站 HTTP 请求的传入活动的信息。</p><blockquote><p>示例：</p><ul><li>处理 <code>on_members_added</code> 来发送欢迎信息，并处理 <code>on_message</code> 来当复读机</li></ul><pre><code class="language-python">class EchoBot(ActivityHandler):    async def on_members_added_activity(    self,        members_added: [ChannelAccount],        turn_context: TurnContext    ):        """        每当一个成员加入聊天，就发送`Hello and Welcome`。        """        for member in members_added:            if member.id != turn_context.activity.recipient.id:                await turn_context.send_activity('Hello and Welcome!')        async def on_message_activity(    self,        turn_context: TurnContext    ):        """        每收到一个消息，就发送`Echo: {消息}`        """        return await turn_context.send_activity(        MessageFactory.text(f'Echo: {turn_context.activity.text}')        )</code></pre></blockquote><h2 id="对话库"><a class="markdownIt-Anchor" href="#对话库"></a> 对话库</h2><p>对话框提供管理与用户长期对话的方法。</p><ul><li>每一个对话框都代表了一个会话任务（运行完成后可以返回收集到的信息）</li><li>每一个对话框都代表了一个基本的控制流单元：可以开始、继续和停止；暂停和恢复；或被取消</li><li>对话框类似于编程语言中的方法或者函数。启动对话框时可以传入参数，且该对话框之后可以在结束时生成一个返回值</li></ul><p>对话框可以实现 <em>多轮会话（multi-turn conversation）</em>，所以对话框依赖于跨多个轮次的 <em>持久性状态（persisted state）</em>。如果对话框中没有状态，机器人就会不知道它在会话中所处的位置，也不知道它已经收集好的信息。</p><p>因此，想要在会话中保留对话框的位置，就要在每个轮次中检索对话框状态并保存到内存。这一操作由（机器人的会话状态定义的）对话框状态属性访问器处理。</p><details><table><thead><tr><th>类</th><th>说明</th></tr></thead><tbody><tr><td>对话框集（Dialog set）</td><td>定义一组对话框，这些对话框可以相互引用 &amp; 协同工作。</td></tr><tr><td>对话框上下文（Dialog context）</td><td>包含有关所有正在活动中的对话框的信息。</td></tr><tr><td>对话框实例（Dialog instance）</td><td>包含有关单个正在活动中的对话框的信息。</td></tr><tr><td>对话框轮次结果（Dialog turn result）</td><td>包含活动的或最近的活动对话框中的状态信息。如果活动对话框已经结束，则包含其返回值。</td></tr></tbody></table></details><br><p>为了简化管理机器人聊天，对话框库提供了一些对话框类型：</p><table><thead><tr><th>类型</th><th>说明</th></tr></thead><tbody><tr><td>对话框（Dialog）</td><td>所有对话框的基类。</td></tr><tr><td>容器对话框（Container dialog）</td><td>所有容器对话框的基类。</td></tr><tr><td>组件对话框（Component dialog）</td><td>一种通用类型的容器对话框。它封装了一组对话框作为一个整体重复使用集。<br>组件对话框启动后，将以其集合中的指定对话框开头。内部进程完成后，组件对话框便结束。</td></tr><tr><td>瀑布对话框（Waterfall dialog）</td><td>定义一系列步骤，使机器人能够引导用户完成线性流程。</td></tr><tr><td>提示对话框（Prompt dialogs）</td><td>要求用户输入并返回结果。</td></tr></tbody></table><h2 id="三大对话框"><a class="markdownIt-Anchor" href="#三大对话框"></a> 三大对话框</h2><ul><li><p><strong>组件对话框</strong> 是一种容器对话框，允许集合中的对话框调用集合中的其他对话框，如：瀑布式对话框调用提示对话框。</p><p>组件对话框还提供了一种创建独立对话框以及处理特定场景的策略，将一个大的对话框集分解成更易于管理的片段。每个片段又都有着自己的对话框集，并避免与包含它的对话框集发生任何名称冲突。</p></li><li><p><strong>提示对话框</strong> 是一个旨在向用户询问特定类型信息的对话框，如：一个日期。</p></li><li><p><strong>瀑布式对话框</strong> 是对话的具体实现，通常用于收集用户的信息，或者引导用户完成一系列的任务。对话的每一步都被实现为一个需要 <em>瀑布式步骤上下文（waterfall step context）</em> 作为参数的异步函数。</p><p>每一步，机器人提示用户输入，或者可以开启一个子对话框，等待回应，然后将结果传递给下一步。第一个函数的结果被作为参数传给下一个函数，以此类推。</p><blockquote><ol><li>对话框上下文开始瀑布</li><li>瀑布 #1：第一次提示</li><li>瀑布 #2：处理来自第一个提示的结果，并开始第二次提示</li><li>瀑布 #3：处理来自第二个提示的结果，结束对话（堆栈入口消失）</li></ol></blockquote><p>瀑布式对话框的上下文被存储在瀑布式步骤上下文中。这个步骤上下文与对话上下文类似，提供对当前轮次上下文和状态的访问。使用瀑布式步骤上下文对象来与瀑布式步骤中的对话框集进行交互。</p><p>对话框的返回值可以在瀑布式步骤中处理，也可以从机器人的轮次处理程序中处理（一般只需要在机器人的轮次论及中检查对话框轮次结果的状态）。</p></li></ul><br><p>瀑布步骤上下文包含以下属性：</p><ul><li><code>Options</code>：包含对话框的输入信息</li><li><code>Values</code>：包含可以添加到上下文中的信息，并被带入后续步骤中</li><li><code>Result</code>：包含前一个步骤的结果</li></ul><blockquote><p>Python 的 <code>next</code> 方法可以在同一轮次内继续进行瀑布式对话框的下一步，也就是在需要时跳过某个步骤。</p></blockquote><p><em>提示（Prompt）</em> 提供了一种简单的方法来询问用户的信息并评估他们的反应。</p><ul><li><p>提示本质上就是一个两步的对话框。首先提示会要求输入，然后返回有效值，或者从头开始重新提示。</p></li><li><p>调用提示时，可以在 <em>提示选项（prompt options）</em> 中指定要提示的文本、如果验证失败了的重新提示，以及回答提示的选择。</p><ul><li>一般而言，提示和重新提示属性都属于活动。</li></ul></li><li><p>当提示被创建时，也可以选择为提示添加自定义验证（如：小于 18 岁就不行的年龄验证）。提示先行检查它是否接收到了一个有效的数字，然后运行自定义验证。假如验证失败了，就重新提示。</p></li><li><p>当一个提示完成时，就会明确地返回所要求的结果值。</p></li></ul><table><thead><tr><th>提示</th><th>说明</th><th>返回值</th></tr></thead><tbody><tr><td>附件提示（Attachment prompt）</td><td>要求一个或多个附件，例如文档或者图片。</td><td>一个 <em>附件（attachment）</em> 对象的集合</td></tr><tr><td>选项提示（Choice prompt）</td><td>从一系列的选项中要求选择一个。</td><td>一个找到的选项对象</td></tr><tr><td>确认提示（Confirm prompt）</td><td>请求提供 <em>Yes</em> 或 <em>No</em></td><td>一个布尔值</td></tr><tr><td>日期时间提示（Date-time prompt）</td><td>请求提供一个日期时间</td><td>一个日期时间解析对象的集合</td></tr><tr><td>数字提示（Number prompt）</td><td>请求提供一个数字</td><td>一个数字值</td></tr><tr><td>文本提示（Text prompt）</td><td>请求提供一个常规的文字输入</td><td>一个字符串</td></tr></tbody></table><br><p>步骤上下文的 <code>prompt</code> 方法的第二个参数要求提供一个 <code>prompt options</code> 对象，该对象包含了这些属性：</p><table><thead><tr><th>属性</th><th>描述</th></tr></thead><tbody><tr><td>初始提示（Prompt / Initial prompt）</td><td>发送给用户的初始活动，用来征求用户的输入</td></tr><tr><td>重试提示（Retry prompt）</td><td>如果用户的第一个输入没有得到验证，就发送该活动</td></tr><tr><td>选项（Choices）</td><td>一个供用户选择的选项列表，和选项提示配合使用</td></tr><tr><td>验证（Validations）</td><td>用于自定义验证器的额外参数</td></tr><tr><td>样式（Style）</td><td>定义选项提示或确认提示的选项将如何呈现给用户</td></tr></tbody></table><p>始终应当指定好初始提示和重试提示。假设用户的输入无效，重试提示就会发送给用户；假设重试提示没有被指定，则会发送初始提示。</p><p>但是假设发回给用户的活动来自于验证器，就不会发送重试提示。</p><br><p>一个验证器函数带有一个 <em>提示验证器上下文（prompt validator context）</em> 参数，并返回一个布尔值，代表了输入是否通过了验证。</p><p>提示验证器上下文包含了这些属性：</p><table><thead><tr><th>属性</th><th>描述</th></tr></thead><tbody><tr><td>上下文（Context）</td><td>机器人当前的轮次上下文</td></tr><tr><td>识别（Recognized）</td><td>一个带有被识别器处理过的用户输入信息的 <em>提示识别器结果（prompt recognizer result）</em></td></tr><tr><td>选项（Options）</td><td>包含了在调用中提供的提示选项，以启动提示</td></tr></tbody></table><p>而提示识别器结果有这些属性：</p><table><thead><tr><th>属性</th><th>描述</th></tr></thead><tbody><tr><td>成功（Succeeded）</td><td>表示识别器是否能够解析输入的内容</td></tr><tr><td>值（Value）</td><td>识别器的返回值。如果必要，验证码可以修改此值</td></tr></tbody></table><h2 id="使用对话框"><a class="markdownIt-Anchor" href="#使用对话框"></a> 使用对话框</h2><p>位于堆栈最顶层的被视为活动中的对话框，对话框上下文会将所有的输入引向这个活动中的对话框。</p><ol><li>对话框开始</li><li>对话框被推入堆栈，成为活动中的对话框</li><li>对话框结束（被 <code>replace dialog</code> 方法移除）或者另一个对话框被推入堆栈并成为活动中的对话框</li></ol><center>-----------------------------</center><div class="danger"> 按照微软官方文档，我的 Python 版本为 3.8.3。</div><h2 id="配置机器人"><a class="markdownIt-Anchor" href="#配置机器人"></a> 配置机器人</h2><p>在 Python 中，机器人的配置文件为 <code>config.py</code>。</p><p>配置格式：<code>XXX = os.environ.get(标识属性, 标识值)</code>。</p><pre><code class="language-python">import osclass DefaultConfig:    PORT = 3978    APP_ID = os.environ.get('MicrosoftAppId', '')    APP_PASSWORD = os.environ.get('MicrosoftAppPassword', '')</code></pre><table><thead><tr><th>标识属性</th><th>标识值</th></tr></thead><tbody><tr><td><code>MicrosoftAppType</code></td><td><code>MultiTenant</code>（多租户）</td></tr><tr><td><code>MicrosoftAppId</code></td><td>机器人的应用 ID</td></tr><tr><td><code>MicrosoftAppPassword</code></td><td>机器人的应用密码</td></tr><tr><td><code>MicrosoftAppTenantId</code></td><td>多租户可无视</td></tr></tbody></table></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;仅作个人用途，微软 Azure 的机器人框架 SDK Python 分支的学习日志。&lt;/p&gt;</summary>
    
    
    
    <category term="翻译" scheme="https://blog.cytrogen.icu/categories/%E7%BF%BB%E8%AF%91/"/>
    
    
    <category term="Python" scheme="https://blog.cytrogen.icu/tags/Python/"/>
    
    <category term="Azure" scheme="https://blog.cytrogen.icu/tags/Azure/"/>
    
    <category term="Bot" scheme="https://blog.cytrogen.icu/tags/Bot/"/>
    
  </entry>
  
  <entry>
    <title>通过 Docker 在移动端使用 VSCode</title>
    <link href="https://blog.cytrogen.icu/posts/891a.html"/>
    <id>https://blog.cytrogen.icu/posts/891a.html</id>
    <published>2023-01-26T23:49:48.000Z</published>
    <updated>2026-02-09T17:16:55.565Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>利用 Docker 和 code-server 在浏览器中访问 Visual Studio Code，从而在移动端使用它。</p><span id="more"></span><div class="danger">开始阅读前，需要知道：<ul><li>鉴于我的电脑为 Windows 10，安装 Docker 时使用的自然也会是 Windows 版本</li><li>Docker 镜像将会拉取的是最新版的 Ubuntu</li></ul></div><h1 id="安装docker-desktop"><a class="markdownIt-Anchor" href="#安装docker-desktop"></a> 安装 Docker Desktop</h1><ol><li>进入 <a href="https://www.docker.com/products/docker-desktop/">Docker Desktop 下载网址</a>，点击 <strong>Download Docker Desktop</strong>。<br><img src="/posts/891a/Docker Desktop.webp" alt="Docker Desktop页面" loading="lazy"></li><li>安装完成后点击 <strong>Close</strong> 关闭界面。<br><img src="/posts/891a/Installing Docker Desktop.webp" alt="Docker Desktop安装完成界面" loading="lazy"><br>下图为 Docker Desktop 的界面：<br><img src="/posts/891a/Docker Desktop 1.webp" alt="Docker Desktop主界面" loading="lazy"></li><li>在终端内输入 Docker 检查版本的命令，检查是否安装成功：<br><img src="/posts/891a/Docker Version.webp" alt="终端内输入docker version" loading="lazy"></li></ol><h1 id="创建容器"><a class="markdownIt-Anchor" href="#创建容器"></a> 创建容器</h1><ol><li>打开任一终端，拉取 Ubuntu 镜像：<pre><code class="language-bash">docker pull ubuntu</code></pre><img src="/posts/891a/Docker Pull.webp" alt="终端内输入docker pull ubuntu" loading="lazy"></li><li>继续在终端内创建空容器：<pre><code class="language-bash">docker run -it --name CodeServer ubuntu:latest /bin/bash</code></pre></li><li>此时终端的目标路径变为了 <code>root@巴拉巴拉巴拉:/#</code>，输入以下命令安装 curl 库：<pre><code class="language-bash">apt-get updateapt install curl</code></pre><img src="/posts/891a/apt-get update.webp" alt="终端内输入apt-get update" loading="lazy"><img src="/posts/891a/apt install curl.webp" alt="终端内输入apt install curl" loading="lazy"></li></ol><h1 id="安装code-server"><a class="markdownIt-Anchor" href="#安装code-server"></a> 安装 code-server</h1><blockquote><p>详情请查看 <a href="https://github.com/coder/code-server">code-server</a> 仓库。</p></blockquote><ol><li><p>依然是在终端内，执行以下命令来安装：</p><pre><code class="language-bash">curl -fsSL https://code-server.dev/install.sh | sh</code></pre></li><li><p>为了能够让其他设备也可以访问网页，需要执行以下命令：</p><pre><code class="language-bash">code-server --link</code></pre><img src="/posts/891a/code-server --link.webp" alt="终端内输入code-server --link" loading="lazy"><blockquote><p>我在这里换了个终端，实际上不需要更换。</p></blockquote></li><li><p>进入最后一行提供的网址，进入 GitHub 页面登录。<br>我因为先前登陆过，直接导向了 IDE 网址。</p></li><li><p>最终会提供给你一个 IDE 网址。<br><img src="/posts/891a/IDE网址.webp" alt="登录GitHub后在终端会提供一个IDE网址" loading="lazy"></p><p>进入该网址，便会看到熟悉的 Visual Studio Code。<br><img src="/posts/891a/Visual Studio Code.webp" alt="IDE网址内的VSCode" loading="lazy"></p></li></ol><h1 id="移动端访问"><a class="markdownIt-Anchor" href="#移动端访问"></a> 移动端访问</h1><ol><li><p>到这儿就已经很明显要怎么做了。</p><p>进入手机的浏览器，输入上面的 IDE 网址，就可以在手机上使用 Visual Studio Code 了。<br><img src="/posts/891a/移动端.webp" alt="手机上的Visual Studio Code" loading="lazy"></p></li></ol></body></html>]]></content>
    
    
    <summary type="html">本文是一篇关于如何在移动端（如手机、平板）使用 VS Code 的详细教程。文章利用 Docker 和 code-server 项目，指导读者一步步在本地电脑上创建一个运行着 VS Code 的 Docker 容器，并通过 code-server 的链接功能生成一个公开的网址。最终，你可以在任何设备的浏览器中访问这个网址，从而实现随时随地编写代码的便携开发体验。</summary>
    
    
    
    <category term="工具" scheme="https://blog.cytrogen.icu/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="Docker" scheme="https://blog.cytrogen.icu/tags/Docker/"/>
    
    <category term="VSCode" scheme="https://blog.cytrogen.icu/tags/VSCode/"/>
    
  </entry>
  
  <entry>
    <title>ffmpy3 批量合并 ts 文件</title>
    <link href="https://blog.cytrogen.icu/posts/a3e5.html"/>
    <id>https://blog.cytrogen.icu/posts/a3e5.html</id>
    <published>2023-01-21T01:37:26.000Z</published>
    <updated>2026-02-09T17:16:55.009Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>如何使用 Python 的 ffmpy3 包来批量合并 ts 文件至单个 mp4 文件。</p><span id="more"></span><div class="danger">开始阅读前，需要知道：<ul><li>ffmpy3 是 FFmpeg 的 Python 包装器</li><li>ffmpy3 根据提供的参数和选项来编译 FFmpeg 命令行</li></ul></div><h1 id="ffmpy3使用"><a class="markdownIt-Anchor" href="#ffmpy3使用"></a> ffmpy3 使用</h1><h2 id="安装ffmpy3包"><a class="markdownIt-Anchor" href="#安装ffmpy3包"></a> 安装 ffmpy3 包</h2><p>使用 pip 来安装：</p><pre><code class="language-bash">pip install ffmpy3</code></pre><h2 id="ffmpy3简单例子"><a class="markdownIt-Anchor" href="#ffmpy3简单例子"></a> ffmpy3 简单例子</h2><pre><code class="language-python">import ffmpy3ff = ffmpy3.FFmpeg (    inputs = {'输入文件': '参数1'},    outputs = {'输出文件': '参数2'})</code></pre><p>最终得出结果相当于在终端里输入：</p><pre><code class="language-bash">FFmpeg 参数1 -i 输入文件 参数2 输出文件</code></pre><h1 id="批量合并ts文件"><a class="markdownIt-Anchor" href="#批量合并ts文件"></a> 批量合并 ts 文件</h1><h2 id="路径构造"><a class="markdownIt-Anchor" href="#路径构造"></a> 路径构造</h2><pre><code class="language-plaintext">├───文件夹│    Python文件.py│    file.txt│    文件A.ts│    文件B.ts│    文件C.ts│    文件D.ts...</code></pre><h2 id="filetxt"><a class="markdownIt-Anchor" href="#filetxt"></a> file.txt</h2><p>在 file.txt 内部写下 ts 文件名：</p><pre><code class="language-plaintext">file '文件A.ts'file '文件B.ts'file '文件C.ts'file '文件D.ts'</code></pre><blockquote><p>注意：</p><ol><li>使用单引号，而非双引号，后者会导致报错！</li><li>引号内的路径使用相对路径</li></ol></blockquote><h2 id="python文件"><a class="markdownIt-Anchor" href="#python文件"></a> Python 文件</h2><p>使用这段代码来批量合并 ts 文件：</p><pre><code class="language-python">ff = ffmpy3.FFmpeg(        inputs={f'file.txt': '-f concat'},        outputs={f'文件名.mp4': '-c copy'})ff.run()</code></pre><p>上述代码相当于在终端中输入：</p><pre><code class="language-bash">FFmpeg -f concat -i file.txt -c copy 文件名.mp4</code></pre></body></html>]]></content>
    
    
    <summary type="html">本文是一篇关于使用 Python 批量合并 TS 视频文件的简明教程。文章介绍了如何利用 ffmpy3 这个 FFmpeg 的 Python 包装库，通过创建一个列表文件来指定需要合并的 TS 文件，并使用几行 Python 代码调用 FFmpeg 的 -f concat 和 -c copy 命令，从而实现无损、快速地将多个 TS 片段合并成一个完整的 MP4 文件。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Python" scheme="https://blog.cytrogen.icu/tags/Python/"/>
    
    <category term="ffmpy3" scheme="https://blog.cytrogen.icu/tags/ffmpy3/"/>
    
  </entry>
  
  <entry>
    <title>使用 Flask-Mail 和 Ionos 邮箱发送邮件</title>
    <link href="https://blog.cytrogen.icu/posts/d995.html"/>
    <id>https://blog.cytrogen.icu/posts/d995.html</id>
    <published>2022-11-06T18:49:48.000Z</published>
    <updated>2026-02-09T17:16:55.009Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>该文档讲述了如何使用 Flask-Mail 库和 Ionos 的邮箱来发送邮件。</p><span id="more"></span><div class="danger">开始阅读前，需要知道：<ul><li>Flask 是一个使用 Python 编写的 Web 应用框架</li><li>Flask-Mail 提供了接口以让 Web 应用程序向客户端发送邮件</li><li>Flask 和 Flask-Mail 都可以使用 <code>pip install</code> 来安装</li><li>Ionos 是一家网络托管公司，提供域名注册、SSL 证书、电子邮件等服务</li><li>Ionos 的电子邮件可在域名注册后获得</li></ul></div><h1 id="配置flask-mail"><a class="markdownIt-Anchor" href="#配置flask-mail"></a> 配置 Flask-Mail</h1><blockquote><p>请先确保你已经从 Ionos <strong>购买</strong> 了一个域名，且创建了一个邮箱。</p></blockquote><ol><li><p>在 <strong><a href="http://app.py">app.py</a></strong> 中输入以下几行进行配置。</p><p>Ionos 邮箱可在 <a href="https://my.ionos.com/email-overview"> Ionos 的邮箱概述</a> 中找到。</p> <pre><code class="language-python">app.config['MAIL_SERVER'] ='smtp.ionos.com'app.config['MAIL_PORT'] = 587app.config['MAIL_USERNAME'] = '你的Ionos邮箱'app.config['MAIL_PASSWORD'] = '你的Ionos邮箱密码'app.config['MAIL_USE_TLS'] = Trueapp.config['MAIL_USE_SSL'] = False</code></pre></li><li><p>配置完毕后加上这行代码。</p><p>该行代码必须写在以上配置的后面，否则会出错。</p> <pre><code class="language-python">mail = Mail(app)</code></pre></li></ol><h1 id="发送邮件"><a class="markdownIt-Anchor" href="#发送邮件"></a> 发送邮件</h1><ol><li><p>导入 Flask-Mail 包。</p> <pre><code class="language-python">from flask_mail import Mail, Message</code></pre></li><li><p>将 URL 与函数绑定。</p> <pre><code class="language-python">@app.route('/')def index():    return "Hey!"</code></pre></li><li><p>创建 Message 实例和邮件内容。</p> <pre><code class="language-python">msg = Message("这里是主题",            sender="你的Ionos邮箱",            recipients=['收件人的邮箱'])msg.body = "这里是邮件内容"</code></pre></li><li><p>使用 Mail 实例发送邮件。</p> <pre><code class="language-python">mail.send(msg)</code></pre></li><li><p>整体代码如下。</p> <pre><code class="language-python">@app.route('/')def index():    msg = Message("这里是主题",            sender="你的Ionos邮箱",            recipients=['收件人的邮箱'])    msg.body = "这里是邮件内容"    mail.send(msg)        return "Hey!"</code></pre></li></ol></body></html>]]></content>
    
    
    <summary type="html">本文是一篇关于在 Python Flask 应用中发送邮件的简明教程，具体介绍了如何配置 Flask-Mail 扩展并结合 Ionos 邮箱服务。内容涵盖了在 Flask 应用中设置 Ionos 的 SMTP 服务器、端口、用户名和密码等关键配置项，并提供了一个清晰的代码示例，演示了如何创建 Message 对象并发送一封简单的电子邮件。如果你正在使用 Flask 和 Ionos 邮箱，并希望为你的网站添加邮件发送功能，本教程将为你提供直接的指导。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Python" scheme="https://blog.cytrogen.icu/tags/Python/"/>
    
    <category term="Flask" scheme="https://blog.cytrogen.icu/tags/Flask/"/>
    
    <category term="Ionos" scheme="https://blog.cytrogen.icu/tags/Ionos/"/>
    
  </entry>
  
  <entry>
    <title>Speller 笔记</title>
    <link href="https://blog.cytrogen.icu/posts/ad97.html"/>
    <id>https://blog.cytrogen.icu/posts/ad97.html</id>
    <published>2022-10-04T17:28:26.000Z</published>
    <updated>2026-02-09T17:16:55.005Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>CS50 计算机科学入门第 5 周作业 <strong>Speller</strong> 笔记，仅作个人用途。</p><span id="more"></span><h1 id="目录"><a class="markdownIt-Anchor" href="#目录"></a> 目录</h1><ul><li><a href="#%E7%9B%AE%E5%BD%95">目录</a></li><li><a href="#%E4%BD%9C%E4%B8%9A%E4%BB%8B%E7%BB%8D">作业介绍</a><ul><li><a href="#dictionaryh">DICTIONARY.H</a></li><li><a href="#dictionaryc">DICTIONARY.C</a></li><li><a href="#spellerc">SPELLER.C</a></li></ul></li><li><a href="#%E4%BD%9C%E4%B8%9A%E7%9B%AE%E7%9A%84">作业目的</a><ul><li><a href="#%E8%A7%84%E5%88%99">规则</a></li></ul></li></ul><h1 id="作业介绍"><a class="markdownIt-Anchor" href="#作业介绍"></a> 作业介绍</h1><p>在 <em>speller.c</em> 文件中，学生需要编写一个程序，该程序的目的是在将磁盘上的单词字典加载到内存中后对文件进行拼写检查。</p><p>同时，这个字典是在一个叫做 <em>dictionary.c</em> 的文件中实现的。其中的函数原型不在 <em>dictionary.c</em> 中定义，而是在 <em>dictionary.h</em> 中。这样 <em>speller.c</em> 和 <em>dictionary.c</em> 都可以 <code>#include</code> 这个文件。</p><h2 id="dictionaryh"><a class="markdownIt-Anchor" href="#dictionaryh"></a> DICTIONARY.H</h2><p><em>dictionary.h</em> <code>#include</code> 了一个叫做 <em>stdbool.h</em> 的文件，它定义了 <strong>bool</strong> 本身。</p><p>学生还要注意 <code>#define</code> 的使用，这是一个 <strong>预处理器指令</strong>，定义了一个名为 <code>LENGTH</code> 的常数（constant），其值为 <code>45</code>。常数无法在代码中被改变， clang 会在你自己的代码中用 45 替换掉所有提到的 <code>LENGTH</code>。换句话说，常数并非一个变量，而是一个「查找和替换」。</p><p>最后，学生要注意五个函数的原型： <code>check</code> 、 <code>hash</code> 、 <code>load</code> 、 <code>size</code> 和 <code>unload</code>。其中 <code>check</code> 、 <code>hash</code> 和 <code>load</code> 使用指针作为参数（有 * 符号）。</p><h2 id="dictionaryc"><a class="markdownIt-Anchor" href="#dictionaryc"></a> DICTIONARY.C</h2><p>在 <em>dictionary.c</em> 的顶部定义了一个叫做 <code>node</code> 的结构（struct），它代表了哈希表中的一个节点。</p><p>一个全局指针数组（global pointer array） <code>table</code> 也被声明，它将代表你用来跟踪字典中的单词的哈希表。这个数组包含 26 （暂时） 个节点指针，以便于下面描述的默认哈希函数相匹配。这个数字能够被改变，取决于学生自己想如何实现哈希。</p><p>注意到程序的代码里只有一个基于单词首字母的样本算法来实现哈希。学生该做的便是尽可能巧妙地重新实现这些函数。</p><h2 id="spellerc"><a class="markdownIt-Anchor" href="#spellerc"></a> SPELLER.C</h2><p><em>speller.c</em> 不需要被编辑。通过一个叫做 <code>getrusage</code> 的函数，程序将对学生的 <code>check</code> 、 <code>load</code> 、 <code>size</code> 和 <code>unload</code> 的实现进行「基准测试」，也就是对执行进行计时。</p><p>还需要注意的是程序如何逐字逐句地传递要检查的某个文件的内容。最终，程序会报告该文件中的每个拼写错误，以及一系列的统计数据。</p><h1 id="作业目的"><a class="markdownIt-Anchor" href="#作业目的"></a> 作业目的</h1><p>学生的目的是尽可能有效地使用哈希表来实现 <code>load</code> 、 <code>hash</code> 、 <code>size</code> 、 <code>check</code> 和 <code>unload</code>，并使每个函数运行所需的时间都达到最小。</p><h2 id="规则"><a class="markdownIt-Anchor" href="#规则"></a> 规则</h2><ol><li><em>speller.c</em> 和 <em>Makefile</em> 不能被修改</li><li><em>dictionary.c</em> 可以被修改，但五个函数的声明无法被修改</li><li>可以在 <em>dictionary.c</em> 中添加新的函数和变量</li><li><em>dictionary.c</em> 中 N 的值可以被修改</li><li><em>dictionary.h</em> 可以被修改，但五个函数的声明无法被修改</li><li><code>check</code> 的实现必须是不区分大小写的。如果「foo」在 <em>dictionary</em> 中，那么 <code>check</code> 应该在任何字母大写的情况下返回 <code>true</code></li><li><code>check</code> 的检查实现应该只对实际在 <em>dictionary</em> 中的单词返回 <code>true</code></li><li>可以假设传递给程序的任何字典的结构与作业提供的完全一样：按字母顺序从上到下排序、每行一个词、每行以 <code>\n</code> 结尾。也可以假定字典至少包含一个词、没有一个词的长度超过 <code>LENGTH</code> 、没有一个词会出现一次以上、每个词只包含小写字母、可能还有单引号，以及没有一个词以单引号开头</li><li>可以假设 <code>check</code> 仅让包含字母字符和单引号的单词通过</li><li>程序可能只接受文本和可选的字典作为输入。学生可能倾向于对默认字典进行预处理，以便得出一个理想的哈希函数，但学生不能为了获得该优势而将任何这种预处理的输出保存在磁盘上以及程序后续运行时重新将其载入内存</li><li>必须不泄露任何内存，一定要用 <code>valgrind</code> 检查泄露</li><li>学生所写的哈希函数最终应该是学生自己的，而非在网上搜索的</li></ol></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;CS50 计算机科学入门第 5 周作业 &lt;strong&gt;Speller&lt;/strong&gt; 笔记，仅作个人用途。&lt;/p&gt;</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="CS50" scheme="https://blog.cytrogen.icu/tags/CS50/"/>
    
    <category term="C语言" scheme="https://blog.cytrogen.icu/tags/C%E8%AF%AD%E8%A8%80/"/>
    
  </entry>
  
  <entry>
    <title>AP 计算机科学原理课笔记</title>
    <link href="https://blog.cytrogen.icu/posts/ebfb.html"/>
    <id>https://blog.cytrogen.icu/posts/ebfb.html</id>
    <published>2022-10-03T18:02:26.000Z</published>
    <updated>2026-02-09T17:16:54.609Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>高中大学选修计算机科学原理课（CSP）课堂笔记，仅作个人用途。</p><span id="more"></span><h1 id="目录"><a class="markdownIt-Anchor" href="#目录"></a> 目录</h1><ul><li><a href="#%E7%9B%AE%E5%BD%95">目录</a></li><li><a href="#ap%E8%80%83%E8%AF%95%E8%AF%AD%E8%A8%80">AP 考试语言</a><ul><li><a href="#assignment-display-and-input">Assignment, Display, and Input</a></li><li><a href="#arithmetic-operators-and-numeric-procedures">Arithmetic Operators and Numeric Procedures</a></li><li><a href="#relational-and-boolean-operators">Relational and Boolean Operators</a></li></ul></li></ul><h1 id="ap考试语言"><a class="markdownIt-Anchor" href="#ap考试语言"></a> AP 考试语言</h1><h2 id="assignment-display-and-input"><a class="markdownIt-Anchor" href="#assignment-display-and-input"></a> Assignment, Display, and Input</h2><table><thead><tr><th>On the AP Exam</th><th>In Snap!</th><th>备注</th></tr></thead><tbody><tr><td>a &lt;- expression</td><td>- set <code>a</code> to <code>expression</code></td><td><code>a</code> 是用户自定义的 global variable</td></tr><tr><td>DISPLAY (expression)</td><td>- say <code>expression</code> <br> - think <code>expression</code> <br> - write <code>expression</code> size <code>n</code></td><td></td></tr><tr><td>INPUT ()</td><td>- ask <code>expression</code> and wait <br> - answer</td><td></td></tr></tbody></table><h2 id="arithmetic-operators-and-numeric-procedures"><a class="markdownIt-Anchor" href="#arithmetic-operators-and-numeric-procedures"></a> Arithmetic Operators and Numeric Procedures</h2><table><thead><tr><th>On the AP Exam</th><th>In Snap!</th><th>备注</th></tr></thead><tbody><tr><td>a + b <br> a - b <br> a * b <br> a / b</td><td>- <code>a</code> + <code>b</code> <br> - <code>a</code> - <code>b</code> <br> - <code>a</code> x <code>b</code> <br> - <code>a</code> / <code>b</code></td><td></td></tr><tr><td>a MOD b</td><td>- <code>a</code> mod <code>b</code></td><td></td></tr><tr><td>RANDOM (a, b)</td><td>- pick random <code>a</code> to <code>b</code></td><td></td></tr></tbody></table><h2 id="relational-and-boolean-operators"><a class="markdownIt-Anchor" href="#relational-and-boolean-operators"></a> Relational and Boolean Operators</h2><table><thead><tr><th>On the AP Exam</th><th>In Snap!</th><th>备注</th></tr></thead><tbody><tr><td>a = b <br> a ≠ b <br> a &gt; b <br> a &lt; b <br> a ≥ b <br> a ≤ b</td><td>- <code>a</code> = <code>b</code> <br> - <code>a</code> &gt; <code>b</code> <br> - <code>a</code> &lt; <code>b</code></td><td>在 Snap！中，≠、≥和≤符号并不存在</td></tr></tbody></table></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;高中大学选修计算机科学原理课（CSP）课堂笔记，仅作个人用途。&lt;/p&gt;</summary>
    
    
    
    <category term="学术笔记" scheme="https://blog.cytrogen.icu/categories/%E5%AD%A6%E6%9C%AF%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="AP" scheme="https://blog.cytrogen.icu/tags/AP/"/>
    
  </entry>
  
  <entry>
    <title>AP 政治课笔记</title>
    <link href="https://blog.cytrogen.icu/posts/e48.html"/>
    <id>https://blog.cytrogen.icu/posts/e48.html</id>
    <published>2022-10-01T03:24:26.000Z</published>
    <updated>2026-02-09T17:16:54.609Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>高中大学选修政治课课堂笔记，仅作个人用途。</p><span id="more"></span><h1 id="目录"><a class="markdownIt-Anchor" href="#目录"></a> 目录</h1><ul><li><a href="#%E7%9B%AE%E5%BD%95">目录</a></li><li><a href="#%E6%84%8F%E8%AF%86%E5%BD%A2%E6%80%81">意识形态</a><ul><li><a href="#%E7%A4%BE%E4%BC%9A%E6%94%BF%E7%AD%96">社会政策</a></li><li><a href="#%E6%94%BF%E6%B2%BB%E5%85%9A%E6%B4%BE">政治党派</a></li><li><a href="#%E7%BB%8F%E6%B5%8E%E6%94%BF%E7%AD%96">经济政策</a></li><li><a href="#%E6%94%BF%E7%AD%96%E5%88%B6%E5%AE%9A">政策制定</a></li></ul></li><li><a href="#%E6%94%BF%E6%B2%BB%E6%96%87%E5%8C%96%E4%B8%8E%E7%A4%BE%E4%BC%9A%E5%8C%96">政治文化与社会化</a><ul><li><a href="#%E7%BE%8E%E5%9B%BD%E4%BA%BA%E5%AF%B9%E6%94%BF%E5%BA%9C%E5%92%8C%E6%94%BF%E6%B2%BB%E7%9A%84%E6%80%81%E5%BA%A6">美国人对政府和政治的态度</a></li><li><a href="#%E6%94%BF%E6%B2%BB%E7%A4%BE%E4%BC%9A%E5%8C%96">政治社会化</a></li><li><a href="#%E6%84%8F%E8%AF%86%E5%BD%A2%E6%80%81%E7%9A%84%E5%8F%98%E5%8C%96">意识形态的变化</a></li><li><a href="#%E6%94%BF%E6%B2%BB%E4%BA%8B%E4%BB%B6%E5%AF%B9%E6%84%8F%E8%AF%86%E5%BD%A2%E6%80%81%E7%9A%84%E5%BD%B1%E5%93%8D">政治事件对意识形态的影响</a></li></ul></li><li><a href="#%E5%85%AC%E4%BC%97%E8%A7%82%E7%82%B9">公众观点</a><ul><li><a href="#%E8%A1%A1%E9%87%8F%E6%B0%91%E6%84%8F">衡量民意</a></li></ul></li><li><a href="#%E7%BE%8E%E5%9B%BD%E6%B0%91%E4%B8%BB%E7%9A%84%E5%9F%BA%E7%A1%80">美国民主的基础</a><ul><li><a href="#%E6%B0%91%E4%B8%BB%E7%90%86%E6%83%B3">民主理想</a></li></ul></li><li><a href="#%E5%9B%BD%E4%BC%9A">国会</a><ul><li><a href="#%E5%9B%BD%E4%BC%9A%E8%A1%8C%E4%B8%BA">国会行为</a></li><li><a href="#%E6%80%BB%E7%BB%9F%E9%80%9A%E8%AE%AF">总统通讯</a></li><li><a href="#%E6%89%A9%E5%A4%A7%E6%80%BB%E7%BB%9F%E6%9D%83%E5%8A%9B">扩大总统权力</a></li><li><a href="#%E5%AF%B9%E6%80%BB%E7%BB%9F%E8%81%8C%E4%BD%8D%E7%9A%84%E5%88%B6%E7%BA%A6">对总统职位的制约</a></li><li><a href="#%E6%80%BB%E7%BB%9F%E7%9A%84%E6%9D%83%E5%8A%9B">总统的权力</a></li></ul></li></ul><h1 id="意识形态"><a class="markdownIt-Anchor" href="#意识形态"></a> 意识形态</h1><h2 id="社会政策"><a class="markdownIt-Anchor" href="#社会政策"></a> 社会政策</h2><table><thead><tr><th>单词</th><th>释义</th></tr></thead><tbody><tr><td>Government Intervention</td><td>- regulatory actions taken in order to affect decisions made by individuals, groups, or organizations regarding social and economic matters</td></tr><tr><td>Individual Liberties</td><td>- personal freedoms that the government cannot abridge, particularly those guarantees found in the Bill of Rights</td></tr><tr><td>Right To Privacy</td><td>- the right to be free of government scrutiny into one's private beliefs and behavior</td></tr><tr><td>Social Policy</td><td>- public policy related to health care, human services, criminal justice, inequality, education, and labor</td></tr></tbody></table><br><table><thead><tr><th style="text-align:center"></th><th>Social</th><th>Economic</th></tr></thead><tbody><tr><td style="text-align:center">More Control</td><td>1. Affirmative action is a good thing <br> 2. Marriage should be between a man and a woman <br> 3. We need tougher penalties and policing to deal with crime</td><td>1. Everyone has a right to quality healthcare <br> 2. Rent control is a good thing <br> 3. Social safety nets are crucial <br> 4. Every worker has the right to a living wage</td></tr><tr><td style="text-align:center">Less Control</td><td>1. Marijuana should be legalized <br> 2. Laws restriction gun rights are unconstitutional and won't have the intended impact <br> 3. Same-sex couples should have full marriage rights</td><td>1. Government intervention in the free market will slow the economy, hurting everyone</td></tr></tbody></table><blockquote><p>政府应在多大程度上进行干预，以促进社会和经济平等？<br>政府政策应在多大程度上尊重个人隐私或促进传统道德？<br>为了保护公共安全而限制个人自由是否是可以允许的？</p></blockquote><p>公民如何回答以上问题，可以显示出他们对政府在塑造社会方面的适当作用的意见的尖锐分歧，这被称为社会政策（social policy）。</p><h2 id="政治党派"><a class="markdownIt-Anchor" href="#政治党派"></a> 政治党派</h2><p>美国的两个主要政党 ———— 民主党和共和党 ———— 分别与自由派（liberal）和保守派（conservative）的意识形态紧密对应。这些意识形态影响着美国的政策辩论，而这些辩论往往涉及到政府对经济或社会行为的适当干预。</p><p>尽管个人的意识形态与他们的政党选择之间有很强的相关性，但美国人在经济和社会问题上持有一系列观点，并不能只是整齐地归入简单的「左 - 右」。</p><blockquote><p><strong>Liberal Ideologies</strong></p><ul><li>tend to favor more government intervention in order to promote social and economic equality</li><li>更多支持废除死刑；认为死刑代表了残酷的惩罚，因此比起死刑更多会支持预防犯罪的政策</li><li>认为强大的联邦政府更能保证社会内的平等</li><li>支持保底周薪（wages）</li><li>认为如果没有政府干涉，商业会压榨员工导致经济不平衡</li><li>反对政府干涉私人生活，例如限制了同性婚姻的法律或政策</li><li>支持合法化大麻</li><li>认为政府应当提供大范围的社会服务以保证社会平等和幸福</li></ul></blockquote><blockquote><p><strong>Conservative Ideologies</strong></p><ul><li>tend to oppose government intervention in order to promote social and economic equality</li><li>支持死刑</li><li>认为自由市场会奖励有天赋且努力工作的人</li><li>反对政府限制 Bill of Rights，例如用武器保护自己</li><li>反对堕胎；比起 pro-liberty 更 pro-life</li><li>强烈支持政府花钱在军事 &amp; 国际安全上</li><li>多数认为大麻合法化会导致社会不纪律 &amp; 不安全</li><li>支持禁带有危险主题的书；认为这些书籍不应该免费提供给年轻孩子，并认为孩子父母应该负责孩子阅读的书籍类型</li><li>认为政府应当是小规模的，主要于州或当地运营</li><li>Social conservatives 认为政府应该支持 traditional morality，例如限制堕胎、同性婚姻</li></ul></blockquote><blockquote><p><strong>Libertarian Party / Ideologies</strong></p><ul><li>美国第三大政派</li><li>反对政府通过任何与经济和社会有关的政策</li><li>认为政府的存在只应该是为了保护私人财产和其他小事</li><li>支持合法化赌博</li><li>反对扩大政府以解决社会和经济问题</li><li>认为政府不应该有支持或反对宗教的行为</li></ul></blockquote><blockquote><p><strong>Progressive Ideologies</strong></p><ul><li>认为政府应当解决过去的错误并改革导致了不利因素的系统问题</li><li>为了重建社会和系统机制，会支持更强的联邦计划</li></ul></blockquote><blockquote><p><strong>Communitarians</strong></p><ul><li>支持将社区需要放在个人需要之上的法律</li><li>多数在经济上自由，但社会上保守</li><li>为了保护社区，有些支持死刑</li></ul></blockquote><blockquote><p><strong>Democratic Party</strong></p><ul><li>美国最大的政派之一</li><li>the world's oldest active political party</li><li>would be most likely to oppose reduced sentencing for nonviolent felony offenders（非暴力重罪罪犯）</li><li>would be most likely to oppose reduced sentencing for nonviolent felony offenders（非暴力重罪罪犯）</li></ul></blockquote><blockquote><p><strong>Republican Party</strong></p><ul><li>美国最大的政派之一</li><li>would most likely to support opening public lands for ranching and oil exploration</li><li>would most likely to support opening public lands for ranching and oil exploration</li></ul></blockquote><blockquote><p><strong>Green Party</strong></p><ul><li>美国第四大政派</li><li>支持更强大的联邦政府</li><li>其候选人通常支持基层民主（grassroots democracy）、非暴力、社会正义，以及环境主义</li></ul></blockquote><blockquote><p><strong>Nationalists</strong></p><ul><li>支持促进国家利益</li><li>通常认为自己的国家比他国优越</li><li>因为了最大化国家利益，可能会支持死刑</li></ul></blockquote><h2 id="经济政策"><a class="markdownIt-Anchor" href="#经济政策"></a> 经济政策</h2><table><thead><tr><th>单词</th><th>释义</th></tr></thead><tbody><tr><td>The Federal Reserve</td><td>- also called "The Fed" <br> - an independent federal agency that determines US monetary policy with the goal of stabilizing the banking system and promoting economic growth</td></tr></tbody></table><blockquote><p><strong>Fiscal Policy</strong></p><ul><li>government decisions about how to influence the economy by taxing and spending</li><li>由国会控制</li><li>指政府如何对公民征税和花钱，或政府的资金进出预算</li></ul></blockquote><blockquote><p><strong>Monetary Policy</strong></p><ul><li>government decisions about how to influence the economy using control of the money supple and interest rates</li><li>由 the Federal Reserve 决定</li><li>指政府如何通过调整货币供应量和利率来控制货币价值</li></ul></blockquote><blockquote><p><strong>Keynesian Economics</strong></p><ul><li>an economic philosophy that encourages government spending (through the creation of jobs or the distribution of unemployment benefits) in order to promote economic growth</li><li>认为当经济糟糕时，政府应该多干预市场</li><li>于 1929-1939 的大萧条时期中盛行；以政府支出和管控来促进经济</li><li>例如政府盖太阳能农场以创造更多的工作</li></ul></blockquote><blockquote><p><strong>Supply-Side Economics</strong></p><ul><li>an economic philosophy that encourages tax cuts and deregulation in order to promote economic growth</li><li>认为当经济糟糕时，政府应该少干预市场</li><li>libertarian 相比较于 conservative 会更反对政府干预市场，他们觉得政府就不应该干预市场</li><li>1970 年时 conservative 开始反对政治支出，认为减税和放松管制才能促进繁荣</li><li>反对政府消费</li><li>强调降低税收和以低价格刺激商品和服务的供应来增加就业</li><li>也称作为 Trickle Down Policy</li><li>为了经济增长提议减少商业税，因此商业能够用省下来的钱投资以增加更多的工作</li></ul></blockquote><h2 id="政策制定"><a class="markdownIt-Anchor" href="#政策制定"></a> 政策制定</h2><table><thead><tr><th>单词</th><th>释义</th><th>例子</th></tr></thead><tbody><tr><td>Policy Mood</td><td>- measure of the public's preferences toward policy choices <br> - economic and cultural attitudes</td><td></td></tr><tr><td>Position Issues</td><td>- divide voters, opinions don't overlap <br> - an issue that divides voters</td><td>1. gun control <br> 2. death penalty</td></tr><tr><td>Valence Issues</td><td>- most voters agree with the values if not the approach <br> - an issue most voters will agree with</td><td>1. economic prosperity <br> 2. caring for the elderly</td></tr></tbody></table><p>公共政策反映了当时选择参与政治的公民的态度和信念，因此随着公民态度和信念的变化，政策也在逐年变化。</p><p>政党将政策问题的解决方案作为其政纲的一部分，但这些解决方案也会随着公众态度的变化而变化。当政党进行研究和观察民意调查时，他们会调整他们提出的政策解决方案，以最好地反映他们期望的选民的需求。</p><p>在所有这些政策议程波动的基础上，公众倾向于对总统的做法失去信心。总统在任时间越长，他们的意识形态立场就会失去支持。两届总统在任的第七年是意识形态支持率最低的时候。</p><p>也就是说，总统在职的时间越长，公众就越希望有新的解决方案，从而导致公众偏向相反党派的意识形态。</p><p>政府不会一次只针对一项政策，因为这样做的效率并不高。</p><p>当针对某项的公众支持率上升时，国会成员便会引入与该项相关的法律。</p><h1 id="政治文化与社会化"><a class="markdownIt-Anchor" href="#政治文化与社会化"></a> 政治文化与社会化</h1><h2 id="美国人对政府和政治的态度"><a class="markdownIt-Anchor" href="#美国人对政府和政治的态度"></a> 美国人对政府和政治的态度</h2><p>大多数意识形态范围内的美国人相信着的核心价值观（core values）：</p><ol><li>机会平等（equality of opportunity）</li><li>法治（the rule of law）</li><li>有限政府（limited government）</li><li>自力更生/个人主义（self-reliance / individualism）</li><li>自由企业（free enterprise）</li></ol><p>但是对于这些价值观含义的解释可能会有很大的差异，不同的公民对某些价值观的重视程度高于其他价值观。</p><p>而这些对价值观的解释和相对重要性的差异形成了公民对政府作用的信念，并在决定人们在重大选举中支持哪一个政党方面发挥了作用。</p><table><thead><tr><th>单词</th><th>释义</th></tr></thead><tbody><tr><td>American Political Culture</td><td>- the value that influence individuals' attitudes and beliefs about the relationship between citizens and the federal government</td></tr><tr><td>Equality of Opportunity</td><td>- the belief that each person should have the same opportunities to advance in society <br> - everyone should have the opportunity to be healthy, regardless of their family income <br> - all should have ability to compete on a level playing field where success is determined by hard work and talent</td></tr><tr><td>Free Enterprise</td><td>- the belief in the right to compete freely in a market government by supply and demand with limited government involvement <br> - the government should not involve itself in citizens' health; that would give it too much power over their private lives <br> - an economic system of which the government does not put their hands on private company</td></tr><tr><td>Equality of Opportunity</td><td>- the belief that each person should have the same opportunities to advance in society <br> - everyone should have the opportunity to be healthy, regardless of their family income <br> - all should have ability to compete on a level playing field where success is determined by hard work and talent</td></tr><tr><td>Free Enterprise</td><td>- the belief in the right to compete freely in a market government by supply and demand with limited government involvement <br> - the government should not involve itself in citizens' health; that would give it too much power over their private lives <br> - an economic system of which the government does not put their hands on private company</td></tr><tr><td>Ideology</td><td>- the beliefs and ideas that help to shape political opinion and policy</td></tr><tr><td>Individualism</td><td>- the principle of valuing individual rights over those of the government, with a strong emphasis on individual initiative and responsibility <br> - values of individual rights / freedom over the government <br> - protecting personal freedoms from government interference <br> - must be balanced with responsibility of government to provide order and stability</td></tr><tr><td>Limited Government</td><td>- a political system in which there are restrictions placed on the government to protect individual rights and liberties <br> - limitations on the power of government</td></tr><tr><td>Rule of Law</td><td>- the principle that government is based on a body of law applied equally and fairly to every citizen, not on the whims of those in charge, and that no one is above the law, including the government <br> - principle by which all people and institutions are equally accountable towards the law</td></tr><tr><td>Individualism</td><td>- the principle of valuing individual rights over those of the government, with a strong emphasis on individual initiative and responsibility <br> - values of individual rights / freedom over the government <br> - protecting personal freedoms from government interference <br> - must be balanced with responsibility of government to provide order and stability</td></tr><tr><td>Limited Government</td><td>- a political system in which there are restrictions placed on the government to protect individual rights and liberties <br> - limitations on the power of government</td></tr><tr><td>Rule of Law</td><td>- the principle that government is based on a body of law applied equally and fairly to every citizen, not on the whims of those in charge, and that no one is above the law, including the government <br> - principle by which all people and institutions are equally accountable towards the law</td></tr></tbody></table><p>价值观含义的解释差异举例：</p><ol><li>A 认为 individualism 指的是政府不应该干涉美国公民的任何经济或社会习惯</li><li>B 认为 individualism 指的是政府不应该干涉由 Bill of Rights 保护的权利；但如果有商业或州侵犯了这些权利，政府应当干涉</li></ol><h2 id="政治社会化"><a class="markdownIt-Anchor" href="#政治社会化"></a> 政治社会化</h2><table><thead><tr><th>单词</th><th>释义</th><th>例子</th></tr></thead><tbody><tr><td>单词</td><td>释义</td><td>例子</td></tr><tr><td>----</td><td>----</td><td>----</td></tr><tr><td>Demographic Characteristics</td><td>- socioeconomic characteristics of a population that influence how individuals tend to vote and whether they identify with a political party</td><td>1. age, race, gender, religion, marital status, occupation, education level and more</td></tr><tr><td>Globalization</td><td>- the growth of an interconnected world economy and culture, fueled by lowered trade barriers between nations and advances in communications technology <br> - has influenced American politics by increasing the extent to which the United States influences, and is influenced by, the values of other countries</td><td></td></tr><tr><td>Party Identification</td><td>- an individual's sense of loyalty to a specific political party</td><td></td></tr><tr><td>Political Socialization</td><td>- the process by which a person develops political values and beliefs, including through interactions with family, friends, school, religious and civic groups, and the media <br> - complicated manner in which an individual's sense of politic identity, politic party affiliation, and values related to government are shaped by broader culture</td><td></td></tr><tr><td>Polarization</td><td>- the divergence of political attitudes away from the centre, towards ideological extremes</td><td></td></tr><tr><td>Political Efficacy</td><td>- the belief that an individual can impact political outcomes</td><td></td></tr></tbody></table><blockquote><p><strong>Influence of factors on political beliefs</strong></p><table><thead><tr><th>因素</th><th>解析</th></tr></thead><tbody><tr><td>家人</td><td>- 最能影响到个体政治社会化的因素，包括意识形态和政党偏向 <br> - 孩童会通过讨论和媒体重复性地受父母的观点影响</td></tr><tr><td>朋友</td><td>- 与朋友相处会影响到态度培养 <br> - 没有家人那么有影响力</td></tr><tr><td>教育等级</td><td>- 公立学校的作用便是教授基本政府、民主观点、爱国主义，以及促进参政 <br> - 教育等级越高，越可能参政，投票率也会因政治效能（political efficacy）而变高</td></tr><tr><td>社会群体</td><td>- 成员通常已经有了共同的价值观和人生目标 <br> - 群体中的社会互动对成员的政党归属和对政策问题的看法有影响</td></tr><tr><td>宗教群体</td><td>- 群体中的领导将直接讨论特定的政策问题 <br> - 通过群体在特定政策问题所站的立场来影响个体的政治思想</td></tr><tr><td>地理</td><td>- 来自特定地区的人们倾向于有着共同的观点 <br> - 乡村和城市的住民也可以有相同的利益</td></tr><tr><td>年龄</td><td>- 在人生的不同阶段中个体的政治态度都会发生可预测的变化</td></tr><tr><td>媒体</td><td>- 让个体对政治方面的背景信息、政府的价值有了更全面的认知 <br> - 可以让个体选择信息来源，例如有着共同价值观的信息来源</td></tr></tbody></table></blockquote><p>| Political Socialization | - the process by which a person develops political values and beliefs, including through interactions with family, friends, school, religious and civic groups, and the media <br> - complicated manner in which an individual's sense of politic identity, politic party affiliation, and values related to government are shaped by broader culture | |<br>| Polarization | - the divergence of political attitudes away from the centre, towards ideological extremes | |<br>| Political Efficacy | - the belief that an individual can impact political outcomes | |</p><blockquote><p><strong>Influence of factors on political beliefs</strong></p><table><thead><tr><th>因素</th><th>解析</th></tr></thead><tbody><tr><td>家人</td><td>- 最能影响到个体政治社会化的因素，包括意识形态和政党偏向 <br> - 孩童会通过讨论和媒体重复性地受父母的观点影响</td></tr><tr><td>朋友</td><td>- 与朋友相处会影响到态度培养 <br> - 没有家人那么有影响力</td></tr><tr><td>教育等级</td><td>- 公立学校的作用便是教授基本政府、民主观点、爱国主义，以及促进参政 <br> - 教育等级越高，越可能参政，投票率也会因政治效能（political efficacy）而变高</td></tr><tr><td>社会群体</td><td>- 成员通常已经有了共同的价值观和人生目标 <br> - 群体中的社会互动对成员的政党归属和对政策问题的看法有影响</td></tr><tr><td>宗教群体</td><td>- 群体中的领导将直接讨论特定的政策问题 <br> - 通过群体在特定政策问题所站的立场来影响个体的政治思想</td></tr><tr><td>地理</td><td>- 来自特定地区的人们倾向于有着共同的观点 <br> - 乡村和城市的住民也可以有相同的利益</td></tr><tr><td>年龄</td><td>- 在人生的不同阶段中个体的政治态度都会发生可预测的变化</td></tr><tr><td>媒体</td><td>- 让个体对政治方面的背景信息、政府的价值有了更全面的认知 <br> - 可以让个体选择信息来源，例如有着共同价值观的信息来源</td></tr></tbody></table></blockquote><blockquote><p><strong>Influence of demographic factors on party identification</strong></p><table><thead><tr><th>特征</th><th>在统计上更有可能被认为为民主党</th><th>在统计上更有可能被认为为共和党</th></tr></thead><tbody><tr><td>性别</td><td>- 女</td><td>- 男</td></tr><tr><td>收入</td><td>- 低收入</td><td>- 高收入</td></tr><tr><td>婚姻状态</td><td>- 单身 <br> - 离婚 <br> - 守寡</td><td>- 已婚</td></tr><tr><td>职业状态</td><td>- 蓝领</td><td>- 白领 <br> - 居家工作的女性</td></tr><tr><td>种族</td><td>- African Americans <br> - Hispanic Americans</td><td>- Whites</td></tr><tr><td>宗教</td><td>- 犹太人 <br> - 无宗教信仰者</td><td>- 新教徒（基督教徒） <br> - 天主教徒</td></tr><tr><td>地区</td><td>- Northeasterners <br> - Westerners</td><td>- Midwesterners <br> - Southerners</td></tr><tr><td>年龄</td><td>- 年轻或年老的美国人</td><td>- 中年美国人</td></tr><tr><td>性别</td><td>- 女</td><td>- 男</td></tr><tr><td>收入</td><td>- 低收入</td><td>- 高收入</td></tr><tr><td>婚姻状态</td><td>- 单身 <br> - 离婚 <br> - 守寡</td><td>- 已婚</td></tr><tr><td>职业状态</td><td>- 蓝领</td><td>- 白领 <br> - 居家工作的女性</td></tr><tr><td>种族</td><td>- African Americans <br> - Hispanic Americans</td><td>- Whites</td></tr><tr><td>宗教</td><td>- 犹太人 <br> - 无宗教信仰者</td><td>- 新教徒（基督教徒） <br> - 天主教徒</td></tr><tr><td>地区</td><td>- Northeasterners <br> - Westerners</td><td>- Midwesterners <br> - Southerners</td></tr><tr><td>年龄</td><td>- 年轻或年老的美国人</td><td>- 中年美国人</td></tr><tr><td>Union Membership</td><td>- union members</td><td>- non-union members</td></tr><tr><td>父母亲的政治立场</td><td>- parents strongly aligned with Democratic Party</td><td>- parents strongly aligned with Republican Party</td></tr><tr><td>父母亲的政治立场</td><td>- parents strongly aligned with Democratic Party</td><td>- parents strongly aligned with Republican Party</td></tr></tbody></table></blockquote><blockquote><p><strong>Political Socialization</strong></p><ul><li>one example of the process of political socialization in school is students are required to take an American government course to graduate from high school</li><li>media, family, and school are the major agents of political socializations</li></ul></blockquote><blockquote><p><strong>Liberty V.S. Order</strong></p><ul><li>must be balanced in order for society to function optimally</li><li>policy outcomes reflect preference of voters and policymakers at any given time</li><li>changing power of various groups leads to policy changes<ul><li>for example: Alcohol prohibition in 1920 got repealled in 1933</li></ul></li><li>excessive personal liberty will lead to chaos, while excessive social order will stifle personal liberty and creativity</li></ul></blockquote><blockquote><p><strong>Culture War</strong></p><ul><li>deep divisions and increase in polarization between Americans who wish to return to an idealized culture based on traditional values and Americans who favor change<ul><li>于保守派和自由派之间的政治极化（political polarization）和冲突便导致了文化战争（culture war）</li></ul></li><li>政治组织和其利益群体通过媒体带动了积极性 / 热情（enthusiasm）和政党支持，并驱使了政治极化，让公民们越来越能接受极端立场</li></ul></blockquote><h2 id="意识形态的变化"><a class="markdownIt-Anchor" href="#意识形态的变化"></a> 意识形态的变化</h2><table><thead><tr><th>单词</th><th>释义</th><th>例子</th></tr></thead><tbody><tr><td>Generational Effects</td><td>- experiences shared by a group of people who came of age together that affect their political attitudes</td><td>- wars and economic recessions that hit one generation particularly hard have lasting effects on the political attitudes of that generations as its members progress through life</td></tr><tr><td>Lifecycle Effects</td><td>- changes over the course of an individual's lifetime, which affect their political attitudes and participation</td><td>- as individuals develop from young people to adults to senior citizens, their concerns and values change</td></tr><tr><td>Period Effects</td><td>- major events and social trends that affect the political attitudes of the entire population</td><td>- the terrorist attacks on September 11 and the Watergate scandal had lasting effects on the political attitudes of those who lived through them</td></tr></tbody></table><h2 id="政治事件对意识形态的影响"><a class="markdownIt-Anchor" href="#政治事件对意识形态的影响"></a> 政治事件对意识形态的影响</h2><table><thead><tr><th>单词</th><th>释义</th></tr></thead><tbody><tr><td>Formative Age</td><td>- young adulthood, between ages 18 and 24, when many people form long-lasting political attitudes</td></tr><tr><td>Party Realignment</td><td>- a sharp change in the issues or voting blocs that a party represents</td></tr><tr><td>Period Effects</td><td>- major events and social trends that affect the political attitudes of the entire population</td></tr></tbody></table><p>除开导致了政治社会化的因素外，政治事件也能够强烈地影响到个体的意识形态。</p><p>部分社会学家认为，绝大多数人的政治观念会在 18 到 24 岁之间建立完成。而在这个年龄段内发生的重要事件都会对人们的三观产生强烈的影响。</p><blockquote><p>例如在大萧条中成年的人（18 到 24 岁）会比其他没有在经济危机中成年的人更显现出在消费观念上的保守。</p></blockquote><h1 id="公众观点"><a class="markdownIt-Anchor" href="#公众观点"></a> 公众观点</h1><h2 id="衡量民意"><a class="markdownIt-Anchor" href="#衡量民意"></a> 衡量民意</h2><p>投票（polls）是一个用于衡量民意的常用方法。而民意代表了公众如何看待问题、选举人，以及官员。</p><blockquote><p><strong>Types of Polls</strong></p><table><thead><tr><th>单词</th><th>释义</th></tr></thead><tbody><tr><td>Opinion Poll</td><td>- determine beliefs citizens have</td></tr><tr><td>Benchmark Polls</td><td>- used at beginning of a campaign that can be used later for comparison</td></tr><tr><td>Tracking Polls</td><td>- ask individuals the same questions at different time intervals to measure data trends over time</td></tr><tr><td>Entrance Polls</td><td>- given to voters before voting</td></tr><tr><td>Exit Polls</td><td>- given to voters after voting</td></tr><tr><td>Push Polls</td><td>- propaganda technique designed to manipulate voter opinion with bias questions or by spreading false information</td></tr></tbody></table></blockquote><blockquote><p><strong>Sampling</strong></p><table><thead><tr><th>单词</th><th>释义</th></tr></thead><tbody><tr><td>Sample</td><td>- a small group to study to make predictions about the larger population <br> - the group of people a researcher surveys to gauge the whole population's opinion <br> -</td></tr><tr><td>Sampling (Margin of) Error</td><td>- potential discrepancy between poll results and actual opinion <br> - as the sample size increases, the sampling error decreases <br> - the predicted difference between the average opinion expressed by survey respondents and the average opinion in the population</td></tr><tr><td>Mass Survey</td><td>- typically use 1,000 to 2,000 respondents</td></tr><tr><td>Random Sample</td><td>- each member of a population mush have an equal probability of selection</td></tr><tr><td>Representative Sample</td><td>- sample must accurately and proportionally mirror the diversity of the population being surveyed <br> - politic scientist mathematically weight certain demographic characteristics <br> - a relatively small number of respondents who accurately reflect the variety of opinions, demographics, etc. in the broader population</td></tr><tr><td>Sampling Technique</td><td>- the process by which pollsters select respondents to a survey or the sample population for a poll</td></tr><tr><td>Random Sample</td><td>- a random selection from a population, random sampling techniques ensures an equal probability of individuals being selected for a survey or poll</td></tr></tbody></table></blockquote><blockquote><p><strong>Question Design</strong></p><table><thead><tr><th>单词</th><th>释义</th></tr></thead><tbody><tr><td>Forced Choice &gt; Open Ended</td><td>- produce more accurate results and simplify data calculation and analysis</td></tr><tr><td>Question Wording</td><td>- should be concise and neutral in tone to avoid influencing responses <br> - no emotionally charged language</td></tr></tbody></table><ul><li>Question order can influence result of future poll questions</li><li>Some polls force respondents to answer questions about things they don't know<ul><li>"I don't know" options can increase accuracy of results</li></ul></li></ul></blockquote><blockquote><p><strong>Focus Groups</strong></p><ul><li>small group of people who participate in a structured discussion led by a moderator to discover insight into public opinion</li><li>can provide qualitative data and insight into voter perception of issues</li><li>do not provide quantitative data about the broader population</li></ul></blockquote><blockquote><p><strong>Polls and Elections</strong></p><ul><li>polls and focus group data used to form messaging in advertising and preparation for public debates</li><li>tailor policy stances to align with voter opinion</li><li>candidates with high polling ratings will be invited to debates, therefore (free) media coverage and fundraising increase<br>| 单词 | 释义 |<br>| ---- | ---- |<br>| Bandwagon Effect | - as the candidate popularity increases, number of others getting on the bandwagon increases as well |</li></ul></blockquote><blockquote><p><strong>Polling and Public Policy</strong></p><ul><li>politicians use polling to figure how public feels about proposed or existing public policies, and what problems and solutions are favored by the public</li><li>politicians up for reelection are more impacted by public opinion</li></ul></blockquote><blockquote><p><strong>Polling Reliability and Veracity (Validity)</strong></p><table><thead><tr><th>单词</th><th>释义</th></tr></thead><tbody><tr><td>Reliability</td><td>- consistency or repeatability of a survey</td></tr><tr><td>Veracity (Validity)</td><td>- data accuracy</td></tr><tr><td>Predictive Validity</td><td>- how accurate a poll is at forecasting future behaviors</td></tr><tr><td>Polling Accuracy</td><td>- does poll accurate measure the full topic area being studied</td></tr></tbody></table></blockquote><h1 id="美国民主的基础"><a class="markdownIt-Anchor" href="#美国民主的基础"></a> 美国民主的基础</h1><h2 id="民主理想"><a class="markdownIt-Anchor" href="#民主理想"></a> 民主理想</h2><p>美国政治建立在 <strong>limited government</strong> 的思想之上，包含了 natural rights 、popular sovereignty 、republicanism，以及 social contract。</p><p>该思想认为政府应当有种种限制才能够保护个体的权利和公民的自由。</p><p>美国在宣言独立时便在思考除了君主制外的政府机制，以及什么样的政府才能够在不侵犯公民的个体自由的情况下保护他们。最终得到的结果便是 limited government，以及其的四个子思想。</p><p>美国政府建立起前，构造政府的人决定看向政治哲学家 ———— Thomas Hobbes 和 John Locke。</p><blockquote><p><strong>Natural Rights</strong><br>美国宣言独立的最主要问题便是英国的君主制侵犯了美国人民的 natural rights。</p><blockquote><p>Natural rights</p><ul><li>sometimes called unalienable rights</li><li>are rights the Framers believed all people are born with and can never give up</li></ul></blockquote><p>John Locke 认为 natural rights 是 <em>个体的人生、自由，和所有物的权利</em>。这一思想感染了 Thomas Jefferson，使他描绘 natural rights 为 <em>个体的人生、自由，和追求幸福的权利</em>。</p></blockquote><blockquote><p><strong>Social Contract</strong><br>为了政府去保护美国公民的 natural rights，美国公民也要视政府为有权柄权威的。而 social contract 便是美国社会赞同牺牲部分自由，以换取联邦政府的保护。<br>Thomas Hobbes 认为 social contract 是政府的基础。</p></blockquote><blockquote><p><strong>Popular Sovereignty</strong></p><blockquote><p>Popular sovereignty</p><ul><li>the idea that the government's power comes from the will of the people or the "consent of the governed"</li></ul></blockquote><p>当政府开始去侵犯公民的意愿，那公民有权利去改变这一切。正因为英国君主制的权利愈来愈强大，且不再聆听殖民者的意愿，才导致了殖民者后来的反叛和脱离。构思美国政府的人认为，这些殖民者拥有反叛的权利。<br>政府权力在政党之间转移时，也表明了人民的意愿也发生了变化。政党是美国政治的一大重要角色，因为它们代表了人民对政府的意愿和观点。</p></blockquote><blockquote><p><strong>Republicanism</strong><br>构思美国政府的人认为政府的最佳形态应是民选领导人来代表人民的利益。这也就是 republicanism，共和主义。<br>然而最初的领导人投票仅向拥有土地的白人男性开放，直到 200 年后才向全部的美国公民开放。</p></blockquote><br><p>独立宣言和宪法都为美国的民主政府提供了其意识形态的基础：独立宣言提供了 popular sovereignty 的基础，而宪法勾勒出了美国政府系统的蓝图。</p><blockquote><p><strong>The Declaration of Independence</strong><br>参与了写独立宣言的 Thomas Jefferson 因受 John Locke 的启发，认为所有人一出生都拥有着 natural rights，以及政府是人民和领导者之间的 social contract。</p><p>他写下了独立宣言的草稿，并让 John Adams 和 Benjamin Franklin 来进行修改。简单而言，独立宣言就是一份对英国君主制的抱怨清单。但在更高的层面上，独立宣言表达的思想是美国民主价值观的灵感来源。</p></blockquote><blockquote><p><strong>The Constitution</strong><br>尽管独立宣言是美国民主的灵感来源，但它并没有写下政府具体是什么样的。革命后美国政府首先有的政府系统是 <strong>Articles of Confederation</strong>，也就是联邦条例。该系统将大多数的权利都给予在了州政府的手中。<br>因为种种原因，联邦条例并不强悍，反而非常的弱小。很明显这是一个失败品，美国需要一个更强大的政府系统。</p><p>各州的代表举行了 Constitutional Convention 以探讨什么政府既强大到可以支撑美国的需求，又不会强大的十分强横。<br>在 George Washington 的领导下，代表们最终得出了最终版本的宪法，且该宪法深受 James Madison 和 Alexander Hamilton 的影响。</p></blockquote><br><table><thead><tr><th>单词</th><th>释义</th></tr></thead><tbody><tr><td>Constitutional Convention</td><td>- also called the Philadelphia Convention <br> - a meeting of delegates from 12 of the 13 states to revise or replace the Articles of Confederation with a new Constitution featuring a stronger central government</td></tr><tr><td>Limited Government</td><td>- a political system in which the government's power is restricted by laws or a written Constitution</td></tr><tr><td>Natural Rights</td><td>- the right to life, liberty, and property, which no government may take away</td></tr><tr><td>Republicanism</td><td>- the principles of governing through elected representatives</td></tr><tr><td>Social Contract</td><td>- an agreement between people and government in which citizens consent to be governed so long as the government protects their natural rights</td></tr></tbody></table><br><table><thead><tr><th>人名</th><th>贡献</th></tr></thead><tbody><tr><td>John Adams</td><td>- Massachusetts statesman and leader in the movement for American independence <br> - aided Jefferson in drafting the Declaration of Independence</td></tr><tr><td>Ben Franklin</td><td>- Pennsylvania statesman and leader in the movement for American independence <br> - aided Jefferson in drafting the Declaration of Independence</td></tr><tr><td>Alexander Hamilton</td><td>- New York statesman who promoted replacing the Articles of Confederation with a stronger central government <br> - coauthored the Federalist Papers, which argued in favor of ratifying the Constitution</td></tr><tr><td>Thomas Jefferson</td><td>- principal author of the Declaration of Independence</td></tr><tr><td>James Madison</td><td>- Virginia statesman and major contributor to the US Constitution <br> - coauthored the Federalist Papers and wrote the Bill of Rights</td></tr><tr><td>George Washington</td><td>- Revolutionary War general who presided over the Constitutional Convention</td></tr></tbody></table><p><strong>政府权力与个体权利</strong></p><p>当构思美国政府的人们打算将联邦条例替换掉时，联邦党人（Federalist）和反联邦党人（Anti-Federalist）辩论着不同结构的政府。</p><table><thead><tr><th>单词</th><th>释义</th></tr></thead><tbody><tr><td>Articles of Confederation</td><td>- the first government system of the United States, which lasted from 1776 until 1789 <br> - the Articles placed most power in the hands of state governments <br> - government under the Articles lacked an executive or a judicial branch</td></tr><tr><td>Confederation Congress</td><td>- the central government under the Articles of Confederation, composed of delegates chosen by state governments <br> - each state had one vote in the Congress, regardless of its population <br> - the Congress had difficulty legislating as the Articles required nine of the thirteen states to vote to approve any measure, and a unanimous vote in order to amend the Articles themselves</td></tr></tbody></table><p>辩论中有两份重要的文档：<strong>Federalist No. 10</strong> 和 <strong>Brutus No. 1</strong>。前者是由 James Madison 编写的，持强大的中央政府能够控制所有由派系带来的影响这一观点；后者则认为一个强大的中央政府并不能满足所有美国公民的需求。</p><p><strong>民主类型</strong></p><p>当美国建国时，建国者们创建的是 <strong>Democratic Republic</strong>，一种权力来源于人民，但人民的利益由民选官员代表的政府系统。</p><p>美国政府有着许多不同的级别和部门，而这些级别和部门任何美国公民都有可能接近。政治理论家们对于美国公民是否可以影响政府行为这一观点上催生出了三种流行的民主模式，即 Participatory 、 Pluralist，和 Elite。</p><blockquote><p><strong>Participatory Democracy</strong></p><blockquote><ul><li>a model of democracy in which citizens have the power to decide directly on policy and politicians are responsible for implementing those policy decisions</li></ul></blockquote><p>参与式民主：公民有权做出政策决定。<br>参与式民主强调公民广泛参与政治，只是公民并非负责制定政策决定，而是影响它们。负责执行政策决定的依然是政客。</p><p>美国并没有纯粹的参与式民主，但是能在地方政府和州政府中看到参与式民主的影子。<br>例如市政厅会议（Town hall meetings）：政治家和选民当面讨论感兴趣的话题和即将到来的立法。<br>倡议（Initiatives）和公投（Referendums）也是地方政府和州政府允许公民影响政策决定的两个方法。<br>倡议允许公民绕过他们的州立法机构，将拟议的法律放在选票上。一些州甚至允许公民在选票上提出宪法修正案。公投则允许选民批准或废除州立法机构的一项法案。</p></blockquote><blockquote><p><strong>Pluralist Democracy</strong></p><ul><li>a model of democracy in which no one group dominates politics and organized groups compete with each other to influence policy</li></ul><p>多元化民主：没有任何一个团体主导政治，有组织的团体相互竞争以影响政策。<br>与参与式民主不同的是，多元化民主是个体们通过围绕着共同事业而形成的团体来进行政策决策影响工作。<br>支持多元化民主的理论家们认为，人们会自行选择他们想花时间的事业，然后支持这些团体。同时这些团体会获得知名政治家的支持而竞争。这些政治家们则提倡他们的利益。</p><p>美国政治体系中最明显的带有多元化民主元素的例子便是利益团体。他们是试图影响政策制定者的群体，以支持他们在特定的共同利益或关切问题上的立场。<br>例如全国步枪协会 NRA 和全国妇女组织 NOW，这些团体以许多方式影响着政策制定者，比如通过金钱捐赠、游说和在国会听证会（Congressional hearings）上影响政治家。</p></blockquote><blockquote><p><strong>Elite Democracy</strong></p><ul><li>a model of democracy in which a small number of people, usualyy whose who are wealthy and well-educated, influence political decision making</li></ul><p>精英民主：由富有或受过良好教育的少数人来影响政治决策。<br>提倡精英民主的制宪者（Framers）认为对政治的参与应仅限于一小群高度知情的人，而他们能够为所有公民做出最佳的决定。</p><p>选举团（Electoral College）的结构中有着精英民主的影子。尽管人民通过选举产生了总统候选人，但选举团对潜在的多数人暴政起到了制约作用。</p></blockquote><table><thead><tr><th>单词</th><th>释义</th></tr></thead><tbody><tr><td>Democracy</td><td>- a system of government in which the power of the government is vested in the people, who rule directly or through elected representatives</td></tr><tr><td>Participatory Democracy</td><td>- a form of democracy that emphasizes broad, direct participation in politics and civil society, in which most or all citizens participate in politics directly</td></tr><tr><td>Elite Democracy</td><td>- a form of democracy in which a small number of people, usually those who are wealthy and well-educated, influence political decisionmaking</td></tr></tbody></table><table><thead><tr><th>文档</th><th>描述</th></tr></thead><tbody><tr><td>Federalist No. 10</td><td>- an essay written by James Madison, in which he argued that a strong representative government would be able to control the effects of factions</td></tr><tr><td>Brutus No. 1</td><td>- an Anti-Federalist essay which argued against a strong, central government based on the belief that it would not be able to meet the needs of all U.S. citizens</td></tr><tr><td>Constitution</td><td>- the fundamental laws and principles that govern the United States <br> - the document was the result of several compromises between Federalists and Anti-Federalists surrounding the ratification of the Constitution</td></tr></tbody></table><h1 id="国会"><a class="markdownIt-Anchor" href="#国会"></a> 国会</h1><h2 id="国会行为"><a class="markdownIt-Anchor" href="#国会行为"></a> 国会行为</h2><table><thead><tr><th>Term</th><th>Definition</th></tr></thead><tbody><tr><td>Gridlock</td><td>- when the government is unable to reach compromises or make policy decisions</td></tr><tr><td>Partisan</td><td>- a firm supporter of one political party</td></tr><tr><td>Redistricting</td><td>- the process of adjusting electoral districts in the United States</td></tr><tr><td>Gerrymandering</td><td>- the act of changing the boundaries of an electoral district to favor one party over another</td></tr><tr><td>Dividing Government</td><td>- when one party controls one or more houses in the legislative branch while the other party controls in executive branch</td></tr><tr><td>"Lame Duck"</td><td>- an elected official who continues to hold political office during the period between the election and the inauguration of their successor</td></tr><tr><td>Trustee</td><td>- a member of Congress who takes into account the views of their constituents and use their own judgment to decide how to vote</td></tr><tr><td>Delegate</td><td>- a member of Congress who always follows their constituents』voting preferences</td></tr><tr><td>Politico</td><td>- a member of Congress who acts as a delegate on issues that their constituents care about, and as a trustee on issues that their constituents don』t care about</td></tr></tbody></table><blockquote><p><strong>重要案件</strong></p><blockquote><p><em>Baker v. Carr (1961)</em></p><ul><li>法院裁定 Tennessee 自 1901 年以来都没有重新选区的行为违反了宪法</li><li>法院确立「一人一票」原则 —— 选区应按照比例来划分 —— 且法院有权审查各州的重新选区问题</li></ul></blockquote><blockquote><p><em>Shaw v. Reno (1993)</em></p><ul><li>该案件确立，尽管立法重新划分选区必须考虑到种族问题并遵守 1965 年的《投票权法》（the Voting Rights Act of 1965），但不能超过避免种族失衡的合理必要范围</li></ul></blockquote></blockquote><p>选区划分的重要性：</p><ul><li>重新划分选区会影响到选区对部分国会议员的「安全性」</li><li>假设一个国会议员位于安全区，那 TA 就会基于大多数选民的政党在选举中获胜。这也会导致该国会议员有可能因为觉得自己更有权力，而采取选民不喜欢的立场</li></ul><h2 id="总统通讯"><a class="markdownIt-Anchor" href="#总统通讯"></a> 总统通讯</h2><p>美国宪法 II 第三款规定总统为首席立法者（Chief Legislator），也就是说，总统有权指定政策并影响国会试图通过的法案。</p><p>通信技术的进步改变了总统与其他政府部门和选民的关系，增加了总统对立法议程的影响力。</p><table><thead><tr><th>Term</th><th>Definition</th></tr></thead><tbody><tr><td>State of the Union</td><td>- an annual presidential report required by the Constitution, conventionally delivered as a speech to Congress since 1913 and televised since 1947<br>- the president can use the State of the Union to set their policy agenda and recommend policies to members of Congress</td></tr><tr><td>Bully Pulpit</td><td>- Theodore Roosevelt』s notion of the presidency as a platform from which the president could promote an agenda directly to the public</td></tr></tbody></table><h2 id="扩大总统权力"><a class="markdownIt-Anchor" href="#扩大总统权力"></a> 扩大总统权力</h2><p>总统应该有多少权力？</p><ol><li>强大的行政人员可以采取快速果断的行动，这对于应对时事很重要</li><li>但如果总统权力太大，国会和人民可能缺乏追究 TA 责任的能力</li></ol><table><thead><tr><th>Term</th><th>Definition</th><th>Examples</th></tr></thead><tbody><tr><td>Formal Powers</td><td>- powers expressly granted to the president under Article II of the Constitution</td><td>1. making treaties<br>2. commanding the military<br>3. appointing Supreme Court justices<br>4. vetoing legislation</td></tr><tr><td>Informal Powers</td><td>- powers claimed by presidents as necessary in order to execute the law</td><td>1. issuing executive orders and negotiating executive agreements</td></tr><tr><td>Single Executive</td><td>- an executive branch led by a single person</td><td></td></tr><tr><td>Twenty-Second Amendment (1951)</td><td>- applies term limits to the office of the president<br>- no one may be elected president more than twice, or serve as president longer than ten years</td><td></td></tr><tr><td>War Powers Act (1973)</td><td>- also called the War Powers Resolution<br>- limits the president』s power to deploy US armed forces<br>- every president since Nixon has contested the War Powers Act as an infringement of their role as Commander in Chief of the armed forces</td><td></td></tr></tbody></table><blockquote><p><strong>Federalist No. 70 (1788)</strong></p><ul><li>由 Hamilton 撰写。他认为，单个行政人员（single executive）是美国行政部门的最佳形式</li><li>Hamilton 认为，与一大群领导人相比，一位总统可以更快地采取行动，并在必要时更加保密</li><li>同时，与委员会（council）相比，单个行政人员比民主主义的危害更小，因为识别和罢免一个腐败的领导人要比在多个领导人中发现谁是不良行为者更容易</li></ul></blockquote><h2 id="对总统职位的制约"><a class="markdownIt-Anchor" href="#对总统职位的制约"></a> 对总统职位的制约</h2><table><thead><tr><th>Term</th><th>Definition</th></tr></thead><tbody><tr><td>Presidential Nomination</td><td>- a president』s formal proposal of a candidate to fill a position, such as a cabinet member or Supreme Court justice</td></tr><tr><td>Confirmation</td><td>- senate approval of a presidential nomination</td></tr><tr><td>Executive Order</td><td>- a rule or order issued by the president without the cooperation of Congress that carries the force of law</td></tr></tbody></table><h2 id="总统的权力"><a class="markdownIt-Anchor" href="#总统的权力"></a> 总统的权力</h2><p>制宪者希望行政部门有足够的权力采取行动，因此在宪法 II 中规定美国的行政权属于总统。</p><p>宪法 II 中概述的权力被称为正式权力（formal powers），而其他未被概述的权力则称为非正式权力（informal powers）。</p><table><thead><tr><th>Term</th><th>Definition</th><th>Example</th></tr></thead><tbody><tr><td>Cabinet</td><td>- a group of presidential advisers</td><td>1. the heads of the executive departments<br>2. the attorney general<br>3. other officials chosen by the president</td></tr><tr><td>Executive Agreement</td><td>- an international agreement between the president and another country, which does not require the consent of the Senate</td><td></td></tr><tr><td>Executive Order</td><td>- a presidential order to the executive branch that carries the force of law<br>- the Supreme Court can rule executive orders unconstitutional</td><td></td></tr><tr><td>Pocket Veto</td><td>- an indirect veto, which the president can use by neither signing or vetoing a bill passed by Congress fewer than 10 days before it adjourns</td><td></td></tr><tr><td>Signing Statement</td><td>- a presidential statement upon signing a bill into law, which explains how a president』s administration intends to interpret the law</td><td></td></tr><tr><td>State of the Union Address</td><td>- the president』s annual message to a joint session of Congress, which includes recommended legislation and evaluations of the nation』s top priorities and economic health</td><td></td></tr><tr><td>Veto</td><td>- the president』s constitutional right to reject a law passed by Congress<br>- Congress may override the president』s veto with a two-thirds vote</td><td></td></tr></tbody></table><blockquote><p><strong>总统的正式权力</strong></p><table><thead><tr><th>Category</th><th>Powers</th></tr></thead><tbody><tr><td>Executive</td><td>- take care that the laws be faithfully executed<br>- nominate officials (with Senate confirmation)<br>- request written opinions from administrative officials<br>- fill administrative vacancies during congressional recesses</td></tr><tr><td>Foreign Policy</td><td>- act as Commander in Chief of the armed forces<br>- make treaties (with Senate ratification)<br>- nominate ambassadors (with Senate confirmation)<br>- receive ambassadors<br>- confer diplomatic recognition on other governments</td></tr><tr><td>Judicial</td><td>- grant reprieves and pardons for federal offenses (except impeachment)<br>- nominate federal judges (with Senate confirmation)</td></tr><tr><td>Legislative</td><td>- recommend legislation to Congress<br>- present information on the State of the Union to Congress<br>- convene Congress on extraordinary occasions<br>- adjourn Congress if House and Senate cannot agree<br>- veto legislation (Congress may overrule with supermajority)</td></tr></tbody></table></blockquote><blockquote><p><strong>总统的非正式权力</strong></p><table><thead><tr><th>Power</th><th>Definition</th></tr></thead><tbody><tr><td>Bargaining and Persuasion</td><td>- setting priorities for Congress and attempting to get majorities to put through the president』s legislative agenda</td></tr><tr><td>Issuing Executive Orders</td><td>- regulations to run the government and direct the bureaucracy</td></tr><tr><td>Issuing Signing Statements</td><td>- giving the president's intended interpretation of bills passed by Congress</td></tr><tr><td>Negotiating Executive Agreements</td><td>- agreements with heads of foreign governments that are not ratified by the Senate</td></tr></tbody></table></blockquote></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;高中大学选修政治课课堂笔记，仅作个人用途。&lt;/p&gt;</summary>
    
    
    
    <category term="学术笔记" scheme="https://blog.cytrogen.icu/categories/%E5%AD%A6%E6%9C%AF%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="AP" scheme="https://blog.cytrogen.icu/tags/AP/"/>
    
  </entry>
  
  <entry>
    <title>Hoka-bot 功能列表</title>
    <link href="https://blog.cytrogen.icu/posts/94b.html"/>
    <id>https://blog.cytrogen.icu/posts/94b.html</id>
    <published>2022-08-17T18:32:04.000Z</published>
    <updated>2026-02-09T17:16:54.713Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>欢迎使用 Hoka-bot！</p><p>该文档将列出 Hoka-bot （以下称 Hoka）的功能以及详细介绍。</p><span id="more"></span><div class="danger"><p>阅读前，需要：</p><ul><li>查看该文档的日期是否已经过时</li></ul></div><center>————————</center><h1 id="目录"><a class="markdownIt-Anchor" href="#目录"></a> 目录</h1><ul><li><a href="#%E7%9B%AE%E5%BD%95">目录</a></li><li><a href="#%E4%BB%8B%E7%BB%8D">介绍</a><ul><li><a href="#%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8-hoka">如何使用 Hoka</a></li><li><a href="#%E5%8A%9F%E8%83%BD%E7%AE%A1%E7%90%86">功能管理</a></li></ul></li><li><a href="#%E5%8A%9F%E8%83%BD%E5%88%97%E8%A1%A8">功能列表</a><ul><li><a href="#rauthman%E6%8F%92%E4%BB%B6%E5%8A%9F%E8%83%BD%E5%88%97%E8%A1%A8">rauthman 插件功能列表</a></li></ul></li></ul><center> ————————</center><h1 id="介绍"><a class="markdownIt-Anchor" href="#介绍"></a> 介绍</h1><blockquote><p>Hoka，或称 <em>霍卡</em>，是一个 QQ 群聊机器人。</p><p><a href="https://cytrogen.icu/2022/06/30/hoka-bot%E9%83%A8%E7%BD%B2%E6%95%99%E7%A8%8B/">Hoka 的部署教程</a>，看了或许能够更了解 Hoka。</p></blockquote><h2 id="如何使用-hoka"><a class="markdownIt-Anchor" href="#如何使用-hoka"></a> 如何使用 Hoka</h2><ul><li>在 Hoka 所在的群聊中发送命令 <code>hoka help</code>，能够得到帮助菜单插件的帮助</li><li>发送命令 <code>hoka help list</code>，能够得到 Hoka 现有的插件列表</li></ul><h2 id="功能管理"><a class="markdownIt-Anchor" href="#功能管理"></a> 功能管理</h2><p>Hoka 的 <code>rauthman</code> 插件提供了插件授权管理的功能，也就是说， Hoka 的部分功能在管理员没有开启前是无法使用的。</p><p>不受 <code>rauthman</code> 插件影响的插件有：</p><ul><li><code>help | 帮助菜单</code></li><li><code>admin | 简易群管</code></li><li><code>contact | 联系管理员</code></li><li><code>eventdone | 好友申请</code></li><li><code>read_60s | 60秒读世界</code></li></ul><p>而 <code>admin</code> 插件自有一套独立的权限系统，其权限系统仅对该插件的功能生效。</p><center>————————</center><h1 id="功能列表"><a class="markdownIt-Anchor" href="#功能列表"></a> 功能列表</h1><details><table><thead><tr><th style="text-align:center">插件名</th><th style="text-align:center">功能</th><th>命令</th><th>备注</th></tr></thead><tbody><tr><td style="text-align:center">abbrrebly</td><td style="text-align:center">缩写猜测</td><td>缩写 &lt;文本&gt;</td><td></td></tr><tr><td style="text-align:center">admin</td><td style="text-align:center">简易群管</td><td>群管初始化</td><td>初始化该群聊</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>禁 &lt;@&gt; &lt;秒数&gt;</td><td>禁言，0 秒为解禁</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>解 &lt;@&gt;</td><td>解禁</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>/all</td><td>全体禁言</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>改 &lt;@&gt; &lt;群名片&gt;</td><td>更改群名片</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>头衔 &lt;@&gt; &lt;头衔&gt;</td><td>更改群头衔</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>删头衔</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>踢 &lt;@&gt;</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>黑 &lt;@&gt;</td><td>拉黑</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>撤回</td><td>需要回复信息</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>管理员 + / - &lt;@&gt;</td><td>添加或移除管理员</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>查看词条</td><td>查看本群加群自动审批的词条</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>词条 + / - &lt;文本&gt;</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>所有词条</td><td>超级用户独占</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>指定词条 + / - &lt;群号&gt; &lt;词条&gt;</td><td>超级用户独占</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>查看分管</td><td>分管是可以接受加群处理结果消息的用户</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>所有分管</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>群管接收</td><td>如关闭则审批结果不会发送给超级用户</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>分管 + / -</td><td>添加或移除分群管理员</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>记录本群</td><td>记录本群的聊天记录</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>停止记录本群</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>群词云</td><td>生成该群的群词云</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>简单违禁词</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>严格违禁词</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>更新违禁词库</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>开关 &lt;功能名&gt;</td><td>1. 管理、踢、禁、改、基础群管 <br> 2. 加群、审批、加群审批、自动审批 <br> 3. 词云、群词云、wordcloud <br> 4. 违禁词、违禁词检测</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>开关状态</td><td></td></tr><tr><td style="text-align:center">bilibili_analysis</td><td style="text-align:center">B 站视频解析</td><td>&lt;B 站视频链接、小程序、BV 号等&gt;</td><td></td></tr><tr><td style="text-align:center">bilibili_cover</td><td style="text-align:center">B 站视频封面提取</td><td>提取封面 &lt;视频链接、AV 号、BV 号&gt;</td><td></td></tr><tr><td style="text-align:center">bilibili_viode</td><td style="text-align:center">B 站视频分享卡片</td><td>&lt;B 站视频 ID&gt;</td><td></td></tr><tr><td style="text-align:center">cataas</td><td style="text-align:center">随机猫咪</td><td>来点猫咪</td><td></td></tr><tr><td style="text-align:center">contact</td><td style="text-align:center">联系管理员</td><td>hoka 私聊 / contact &lt;文本&gt;</td><td>发送私聊给超级用户； <br> 会取 QQ 号</td></tr><tr><td style="text-align:center">ELF_RSS2</td><td style="text-align:center">RSS 订阅</td><td>add/添加订阅/sub &lt;订阅名&gt; &lt;RSS 地址&gt;</td><td>RSS 地址看 <a href="https://docs.rsshub.app/">这里</a></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td> rsshub_add &lt;RSSHub 路由名&gt; &lt;订阅名&gt;</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>deldy/删除订阅/drop &lt;订阅名&gt;</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>show_all/showall/select_all/selectall/所有订阅 &lt;关键词&gt;</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>show / 查看订阅 &lt;订阅名&gt;</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>change/修改订阅/moddy &lt;订阅名&gt; &lt;属性&gt;=&lt;值&gt;</td><td>属性表看 <a href="https://github.com/Quan666/ELF_RSS/blob/2.0/docs/2.0%20%E4%BD%BF%E7%94%A8%E6%95%99%E7%A8%8B.md#%E4%BF%AE%E6%94%B9%E8%AE%A2%E9%98%85">这里</a></td></tr><tr><td style="text-align:center"> eventdone</td><td style="text-align:center">好友申请</td><td></td><td>超级用户独占</td></tr><tr><td style="text-align:center">game</td><td style="text-align:center">群组游戏</td><td>装弹 / 轮盘 &lt;子弹&gt; &lt;金额&gt;</td><td>开始一场轮盘游戏； <br> 子弹数必须大于 0 小于 7</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>接受 / 拒绝</td><td>接受或拒绝他人的轮盘邀请</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>开枪</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>结算</td><td>跳过该次轮盘游戏，直接进到结算画面； <br> 发送该指令的人会自动算为输家</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>我的战绩</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>金币/胜场/败场/欧洲人/慈善家 排行</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>hoka 抽卡 / 十连</td><td>抽卡一次花费 100 金币</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>卡池 &lt;星数&gt;/全部/UP</td><td>查看卡池</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>我的背包</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>售卖 &lt;数量&gt; 个 &lt;星数&gt; 星</td><td>三星卡售价 25 金币； <br> 四星卡售价 50 金币； <br> 五星卡售价 250 金币； <br></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>hoka 签到</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>hoka 打工</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>hoka 找工作 / 职业 &lt;职业名&gt;</td><td>职业：<br> 1. 爱豆 <br> 2. 传教士 <br> 3. 家庭教师 <br> 4. 皮条客</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>hoka 辞职</td><td>一周仅能辞职一次</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>职业信息</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>我的职业</td><td></td></tr><tr><td style="text-align:center">help</td><td style="text-align:center">帮助菜单</td><td>hoka help</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>hoka help list</td><td>查看全部插件</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>hoka help &lt;插件名&gt;</td><td>查看指定插件帮助菜单</td></tr><tr><td style="text-align:center">logo</td><td style="text-align:center">Logo 制作</td><td>hoka ph / phlogo &lt;左&gt; &lt;右&gt;</td><td>PornHub 风格 Logo</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>hoka yt / ytlogo &lt;左&gt; &lt;右&gt;</td><td>YouTube 风格 Logo</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>hoka 5000 兆 &lt;左&gt; &lt;右&gt;</td><td>5000 兆风格 Logo</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>hoka douyin / dylogo &lt;文字&gt;</td><td>抖音风格 Logo</td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>hoka google / gglogo &lt;文字&gt;</td><td>谷歌风格 Logo</td></tr><tr><td style="text-align:center">memes</td><td style="text-align:center">表情包制作</td><td>表情包制作</td><td></td></tr><tr><td style="text-align:center"></td><td style="text-align:center"></td><td>hoka &lt;表情包名&gt; &lt;文字&gt;</td><td></td></tr><tr><td style="text-align:center">read_60s</td><td style="text-align:center">60 秒读世界</td><td></td><td>需要联系管理员手动开启</td></tr><tr><td style="text-align:center">setu</td><td style="text-align:center">色卡查询</td><td>setu &lt;张数&gt; <r18> &lt;关键词&gt;</r18></td><td>r18 需要管理员手动开启</td></tr><tr><td style="text-align:center">withdraw</td><td style="text-align:center">信息撤回</td><td>bot 撤回 / withdraw &lt;倒数第 x 条信息&gt; <br> &lt;回复需要撤回的信息「bot 撤回」&gt;</td><td></td></tr></tbody></table></details><h2 id="rauthman插件功能列表"><a class="markdownIt-Anchor" href="#rauthman插件功能列表"></a> rauthman 插件功能列表</h2><div class="danger"><p><strong>功能名</strong> 不同于 <strong>插件名</strong></p></div><table><thead><tr><th>指令</th><th>备注</th></tr></thead><tbody><tr><td>功能 开启 / 关闭 &lt;功能名&gt;</td><td></td></tr><tr><td>功能查询</td><td>获取该群组已开启的功能</td></tr><tr><td>功能全局查询</td><td>获取 Bot 所有的功能</td></tr></tbody></table></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;欢迎使用 Hoka-bot！&lt;/p&gt;
&lt;p&gt;该文档将列出 Hoka-bot （以下称 Hoka）的功能以及详细介绍。&lt;/p&gt;</summary>
    
    
    
    <category term="文档" scheme="https://blog.cytrogen.icu/categories/%E6%96%87%E6%A1%A3/"/>
    
    
    <category term="Nonebot" scheme="https://blog.cytrogen.icu/tags/Nonebot/"/>
    
  </entry>
  
  <entry>
    <title>学术评估测验 - 总结</title>
    <link href="https://blog.cytrogen.icu/posts/3b.html"/>
    <id>https://blog.cytrogen.icu/posts/3b.html</id>
    <published>2022-08-15T22:47:18.000Z</published>
    <updated>2026-02-09T17:16:55.213Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>该文档是给自己复习用的。</p><p>并不包含所有的知识点，且知识点不一定正确。</p><span id="more"></span><h1 id="目录"><a class="markdownIt-Anchor" href="#目录"></a> 目录</h1><details><ul><li><a href="#%E7%9B%AE%E5%BD%95">目录</a></li><li><a href="#%E5%8D%95%E8%AF%8D">单词</a></li><li><a href="#%E8%AF%AD%E6%B3%95">语法</a><ul><li><a href="#%E5%8F%A5%E5%AD%90%E6%8E%92%E5%BA%8F">句子排序</a></li><li><a href="#%E8%A1%A8%E8%BE%BE%E9%A3%8E%E6%A0%BC">表达风格</a></li><li><a href="#%E5%A2%9E%E5%87%8F%E5%8F%A5%E5%AD%90">增减句子</a></li><li><a href="#%E7%89%B9%E6%AE%8A%E5%8D%95%E5%A4%8D%E6%95%B0">特殊单复数</a></li><li><a href="#%E4%B8%A4%E8%80%85%E5%B9%B6%E5%88%97">两者并列</a></li><li><a href="#%E6%97%B6%E6%80%81">时态</a></li><li><a href="#%E5%9B%BA%E5%AE%9A%E6%90%AD%E9%85%8D">固定搭配</a></li><li><a href="#%E6%AF%94%E8%BE%83%E5%AF%B9%E8%B1%A1%E7%9A%84%E4%B8%80%E8%87%B4%E6%80%A7">比较对象的一致性</a></li><li><a href="#%E6%A0%87%E7%82%B9%E7%AC%A6%E5%8F%B7">标点符号</a></li><li><a href="#%E8%BF%9E%E8%AF%8D--%E9%80%BB%E8%BE%91%E8%AF%8D">连词 &amp; 逻辑词</a></li><li><a href="#%E5%8F%A5%E5%AD%90%E5%90%88%E5%B9%B6">句子合并</a></li><li><a href="#%E4%BB%A3%E8%AF%8D">代词</a></li><li><a href="#%E9%80%BB%E8%BE%91%E4%B8%BB%E8%AF%AD%E4%B8%80%E8%87%B4">逻辑主语一致</a></li><li><a href="#%E4%BB%8E%E5%8F%A5">从句</a></li></ul></li><li><a href="#%E6%95%B0%E5%AD%A6">数学</a><ul><li><a href="#%E6%A0%87%E5%87%86%E5%B7%AE">标准差</a></li><li><a href="#%E6%A0%87%E5%87%86%E8%AF%AF">标准误</a></li><li><a href="#%E5%BC%A7%E9%95%BF">弧长</a></li><li><a href="#%E7%99%BE%E5%88%86%E6%AF%94%E5%B7%AE%E5%88%AB">百分比差别</a></li><li><a href="#%E8%A7%92%E5%BA%A6">角度</a></li><li><a href="#%E5%BC%A7%E5%BA%A6">弧度</a></li><li><a href="#%E4%BA%8C%E6%AC%A1%E5%87%BD%E6%95%B0">二次函数</a></li><li><a href="#%E5%8D%95%E4%BD%8D%E6%8D%A2%E7%AE%97">单位换算</a></li><li><a href="#%E6%96%B9%E7%A8%8B%E7%BB%84">方程组</a></li><li><a href="#%E5%AE%9E%E9%AA%8C%E5%AF%B9%E7%85%A7%E7%BB%84">实验对照组</a></li><li><a href="#%E5%B9%B3%E5%9D%87%E5%80%BC">平均值</a></li><li><a href="#%E5%87%BD%E6%95%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F">函数表达式</a></li><li><a href="#%E4%BA%8C%E6%AC%A1%E6%96%B9%E7%A8%8B%E7%9A%84%E6%A0%B9">二次方程的根</a></li><li><a href="#%E5%8D%95%E8%AF%8D-1">单词</a></li></ul></li></ul></details><center> ————————</center><h1 id="单词"><a class="markdownIt-Anchor" href="#单词"></a> 单词</h1><details><table><thead><tr><th>字母</th><th>单词</th><th>意思</th></tr></thead><tbody><tr><td>A</td><td>accredited</td><td>经认可的</td></tr><tr><td></td><td>accumulated</td><td>积聚、堆积</td></tr><tr><td></td><td>acquaintances</td><td>认识的人、熟人</td></tr><tr><td></td><td>adaptable</td><td>能适应的、适合的、可修改的</td></tr><tr><td></td><td>address</td><td>发表、对付、着手处理、解决</td></tr><tr><td></td><td>adopting</td><td>采取、接受、收养、正式通过、过继</td></tr><tr><td></td><td>advocate</td><td>提倡者、拥护者</td></tr><tr><td></td><td>afflict</td><td>使苦恼、折磨</td></tr><tr><td></td><td>agile</td><td>敏捷的、灵巧的</td></tr><tr><td></td><td>ambitious</td><td>有野心的</td></tr><tr><td></td><td>amid</td><td>在其中</td></tr><tr><td></td><td>anguish</td><td>剧痛、痛苦</td></tr><tr><td></td><td>answer</td><td>回答、反驳、适应、符合</td></tr><tr><td></td><td>anticipated</td><td>预期的、期望的</td></tr><tr><td></td><td>antifungal</td><td>抗真菌的</td></tr><tr><td></td><td>antique</td><td>古董、古物</td></tr><tr><td></td><td>aphids</td><td>蚜虫</td></tr><tr><td></td><td>apparatus</td><td>装置、器具</td></tr><tr><td></td><td>appearance</td><td>外观、外表</td></tr><tr><td></td><td>arousal</td><td>唤醒、觉醒</td></tr><tr><td></td><td>ascertain</td><td>查明</td></tr><tr><td></td><td>asserted</td><td>明确肯定、断言</td></tr><tr><td></td><td>assessing</td><td>评价、评估</td></tr><tr><td></td><td>assuring</td><td>使人放心的、使人有自信的</td></tr><tr><td></td><td>astonish</td><td>使惊讶</td></tr><tr><td></td><td>astrophysicists</td><td>天体物理学家</td></tr><tr><td></td><td>asymmetric</td><td>不对称的</td></tr><tr><td></td><td>augment</td><td>增长、增加</td></tr><tr><td></td><td>autobiographical</td><td>自传的</td></tr><tr><td></td><td>auxiliary</td><td>辅助的、备用的</td></tr><tr><td></td><td>avian</td><td>鸟类的</td></tr><tr><td>B</td><td>beanstalks</td><td>豆茎</td></tr><tr><td></td><td>betokened</td><td>预示</td></tr><tr><td></td><td>biomarkers</td><td>生物标记</td></tr><tr><td></td><td>birthed</td><td>生成了、生育了</td></tr><tr><td></td><td>blunt</td><td>坦率地、钝的</td></tr><tr><td></td><td>bolder</td><td>更大胆的</td></tr><tr><td></td><td>borrowing</td><td>借款、贷款</td></tr><tr><td></td><td>boudoir</td><td>闺房</td></tr><tr><td></td><td>breed</td><td>饲养、繁殖</td></tr><tr><td></td><td>broad-bean</td><td>蚕豆</td></tr><tr><td>C</td><td>carriage</td><td>马车、客车</td></tr><tr><td></td><td>casual</td><td>偶然的、不经意的</td></tr><tr><td></td><td>causal</td><td>因果的</td></tr><tr><td></td><td>Centenary</td><td>一百年</td></tr><tr><td></td><td>chambers</td><td>房间、室</td></tr><tr><td></td><td>chickadees</td><td>山雀</td></tr><tr><td></td><td>citation</td><td>引用</td></tr><tr><td></td><td>cite</td><td>引用</td></tr><tr><td></td><td>civility</td><td>礼貌、礼仪</td></tr><tr><td></td><td>clamber</td><td>攀登、爬上</td></tr><tr><td></td><td>cobbled together</td><td>拼凑起来的</td></tr><tr><td></td><td>coined</td><td>创造了、创设了</td></tr><tr><td></td><td>cognition</td><td>认识、识别</td></tr><tr><td></td><td>coherently</td><td>结合地</td></tr><tr><td></td><td>commemoration</td><td>纪念、庆典</td></tr><tr><td></td><td>commitment</td><td>委托</td></tr><tr><td></td><td>compelled</td><td>强迫、迫使</td></tr><tr><td></td><td>compensation</td><td>补偿、工资</td></tr><tr><td></td><td>component</td><td>元件、组件、成分</td></tr><tr><td></td><td>compounds</td><td>化合物</td></tr><tr><td></td><td>comprehended</td><td>理解、领会</td></tr><tr><td></td><td>comprehension</td><td>理解、包含</td></tr><tr><td></td><td>conceived</td><td>构想、设想</td></tr><tr><td></td><td>concentrations</td><td>浓度</td></tr><tr><td></td><td>concoction</td><td>调制、调和</td></tr><tr><td></td><td>conduit</td><td>导管、水管</td></tr><tr><td></td><td>conglomerations</td><td>团块、聚集</td></tr><tr><td></td><td>conquests</td><td>征服、获取</td></tr><tr><td></td><td>consensual</td><td>交感的、在两方愿意下成立的</td></tr><tr><td></td><td>consistent</td><td>一致的、并立的</td></tr><tr><td></td><td>conspicuous</td><td>显眼的</td></tr><tr><td></td><td>constellation</td><td>星座</td></tr><tr><td></td><td>cosmos</td><td>宇宙</td></tr><tr><td></td><td>counterintuitive</td><td>违反直觉的</td></tr><tr><td></td><td>cultivation</td><td>培养、耕作</td></tr><tr><td></td><td>curatorial</td><td>管理者的</td></tr><tr><td>D</td><td>decommissioned</td><td>停用、退役</td></tr><tr><td></td><td>delineation</td><td>略图、描述</td></tr><tr><td></td><td>demanded</td><td>要求</td></tr><tr><td></td><td>demeanour</td><td>行为、举止</td></tr><tr><td></td><td>depleting</td><td>耗尽、使枯竭</td></tr><tr><td></td><td>deprivation</td><td>剥夺</td></tr><tr><td></td><td>derived</td><td>导出的、衍生的</td></tr><tr><td></td><td>devoted</td><td>投入</td></tr><tr><td></td><td>differing</td><td>不同</td></tr><tr><td></td><td>dilate</td><td>扩大、膨胀、详述</td></tr><tr><td></td><td>diminished</td><td>减弱的</td></tr><tr><td></td><td>disfluencies</td><td>不流利</td></tr><tr><td></td><td>disparity</td><td>不一致、差异</td></tr><tr><td></td><td>dispersal</td><td>散布、传播</td></tr><tr><td></td><td>displacements</td><td>换置、取代</td></tr><tr><td></td><td>disproportion</td><td>不均衡</td></tr><tr><td></td><td>dissolution</td><td>分解、溶解</td></tr><tr><td></td><td>distanced</td><td>远离、疏离</td></tr><tr><td></td><td>ditched</td><td>抛弃</td></tr><tr><td></td><td>diverse</td><td>不同的、变化多的</td></tr><tr><td></td><td>divulge</td><td>泄露、透露</td></tr><tr><td></td><td>domestication</td><td>驯养</td></tr><tr><td></td><td>dropped</td><td>降低、放弃</td></tr><tr><td>E</td><td>efforts</td><td>努力</td></tr><tr><td></td><td>elicited</td><td>引出、探出</td></tr><tr><td></td><td>elusive</td><td>难懂的、易忘的</td></tr><tr><td></td><td>embodied cognition</td><td>体化认知</td></tr><tr><td></td><td>emergent</td><td>紧急的、以外的</td></tr><tr><td></td><td>emit</td><td>发出、发射</td></tr><tr><td></td><td>endeavor</td><td>努力、尽力</td></tr><tr><td></td><td>endurance</td><td>忍耐</td></tr><tr><td></td><td>engrossed</td><td>全神贯注的</td></tr><tr><td></td><td>enormous</td><td>巨大的、庞大的</td></tr><tr><td></td><td>enshrouding</td><td>掩盖、遮掩</td></tr><tr><td></td><td>ensuring</td><td>确保、使（人）获得、使安全</td></tr><tr><td></td><td>envisioned</td><td>想象、展望</td></tr><tr><td></td><td>equilibrium</td><td>平衡、均衡</td></tr><tr><td></td><td>established</td><td>（幼苗）成活</td></tr><tr><td></td><td>evoke</td><td>唤起</td></tr><tr><td></td><td>excluded</td><td>被排除、不包括</td></tr><tr><td></td><td>exerted</td><td>外露的</td></tr><tr><td></td><td>existing</td><td>现存的、现有的</td></tr><tr><td>F</td><td>faint</td><td>模糊的</td></tr><tr><td></td><td>fashionable</td><td>时髦的</td></tr><tr><td></td><td>fathom</td><td>摸索</td></tr><tr><td></td><td>feral</td><td>凶猛的</td></tr><tr><td></td><td>fickle</td><td>变幻无常的、浮躁的、薄情的</td></tr><tr><td></td><td>fierce</td><td>凶猛的</td></tr><tr><td></td><td>filaments</td><td>丝状物</td></tr><tr><td></td><td>firm</td><td>坚定的、坚强的</td></tr><tr><td></td><td>fixation</td><td>定置、固定</td></tr><tr><td></td><td>flockmates</td><td>同伴</td></tr><tr><td></td><td>foppishness</td><td>浮华的</td></tr><tr><td></td><td>foraging</td><td>搜寻</td></tr><tr><td></td><td>forgeries</td><td>伪造</td></tr><tr><td></td><td>fostered</td><td>培养、促进</td></tr><tr><td></td><td>freelance</td><td>自由职业</td></tr><tr><td></td><td>fusion</td><td>聚变</td></tr><tr><td>G</td><td>gained</td><td>获得、得到</td></tr><tr><td></td><td>genetic profile</td><td>基因图谱、遗传基因</td></tr><tr><td></td><td>genome</td><td>基因组</td></tr><tr><td></td><td>given</td><td>鉴于</td></tr><tr><td></td><td>grapple</td><td>抓住、掌握</td></tr><tr><td></td><td>gratify</td><td>使高兴、使满足</td></tr><tr><td></td><td>grieve</td><td>使悲伤</td></tr><tr><td></td><td>guarantees</td><td>担保</td></tr><tr><td>H</td><td>hampers</td><td>妨碍、束缚、限制</td></tr><tr><td></td><td>harbored</td><td>庇护</td></tr><tr><td></td><td>harmonious</td><td>和谐的</td></tr><tr><td></td><td>hastily</td><td>匆忙地、急躁地</td></tr><tr><td></td><td>heritage</td><td>遗产、继承物</td></tr><tr><td></td><td>hippocampus</td><td>海马</td></tr><tr><td></td><td>homogeneously</td><td>同一的</td></tr><tr><td></td><td>hyphae</td><td>菌丝</td></tr><tr><td>I</td><td>implication</td><td>牵连、含义</td></tr><tr><td></td><td>inclination</td><td>倾向、趋向</td></tr><tr><td></td><td>indissoluble</td><td>不能分解的、坚固的</td></tr><tr><td></td><td>indulge</td><td>放任、迁就</td></tr><tr><td></td><td>inland reservoirs</td><td>内陆水库</td></tr><tr><td></td><td>infer</td><td>推断</td></tr><tr><td></td><td>infrared</td><td>红外线的</td></tr><tr><td></td><td>innate</td><td>先天的</td></tr><tr><td></td><td>inoculated</td><td>接种</td></tr><tr><td></td><td>inscrutable</td><td>难以了解的</td></tr><tr><td></td><td>insolent</td><td>粗野的、无礼的</td></tr><tr><td></td><td>insuring</td><td>保证、确保</td></tr><tr><td></td><td>integrate</td><td>复杂地</td></tr><tr><td></td><td>intensity</td><td>强度</td></tr><tr><td></td><td>interpersonal</td><td>人与人之间的</td></tr><tr><td></td><td>intimacies</td><td>亲密、亲切</td></tr><tr><td></td><td>intimate</td><td>私人的</td></tr><tr><td></td><td>intoxicated</td><td>极其兴奋的</td></tr><tr><td></td><td>invoke</td><td>实行、调用、恳请、祈求</td></tr><tr><td></td><td>irremediably</td><td>无可救药地</td></tr><tr><td></td><td>irrespective</td><td>不顾一切的</td></tr><tr><td></td><td>irritate</td><td>激怒</td></tr><tr><td>J</td><td>jibes</td><td>相符</td></tr><tr><td></td><td>jolting</td><td>震动</td></tr><tr><td></td><td>junked</td><td>丢弃、废弃</td></tr><tr><td></td><td>juvenile</td><td>少年的</td></tr><tr><td>L</td><td>legumes</td><td>豆类蔬菜</td></tr><tr><td></td><td>leguminous</td><td>豆科的</td></tr><tr><td></td><td>lens</td><td>透镜、镜头、晶状体</td></tr><tr><td></td><td>lilt</td><td>轻快的调子或动作</td></tr><tr><td>M</td><td>malleable</td><td>有延展性的、易适应的</td></tr><tr><td></td><td>meaty</td><td>似肉的、多肉的</td></tr><tr><td></td><td>Medieval</td><td>中世纪的</td></tr><tr><td></td><td>mesh</td><td>网状物、陷阱</td></tr><tr><td></td><td>mesocosms</td><td>中型实验生态系</td></tr><tr><td></td><td>metabolism</td><td>新陈代谢</td></tr><tr><td></td><td>microbial</td><td>微生物的</td></tr><tr><td></td><td>mimicked</td><td>模仿过的</td></tr><tr><td></td><td>miraculous</td><td>奇迹的、不可思议的</td></tr><tr><td></td><td>mobbing</td><td>聚众扰乱</td></tr><tr><td></td><td>monoculture</td><td>单一栽培、单一农作物</td></tr><tr><td></td><td>mortified</td><td>使受辱</td></tr><tr><td></td><td>mutual</td><td>相互的、共有的</td></tr><tr><td>N</td><td>novel</td><td>新奇的、异常的</td></tr><tr><td>O</td><td>obstacle</td><td>障碍、妨碍物</td></tr><tr><td></td><td>occasions</td><td>机会、场合</td></tr><tr><td></td><td>occupy</td><td>占领</td></tr><tr><td></td><td>odorless</td><td>没有气味的</td></tr><tr><td></td><td>ongoing</td><td>进行的、前进的</td></tr><tr><td></td><td>opposes</td><td>反对、抵制</td></tr><tr><td></td><td>ordinary</td><td>平凡、普通</td></tr><tr><td></td><td>orientation</td><td>定方位、方向</td></tr><tr><td>P</td><td>paleontologists</td><td>古生物学者</td></tr><tr><td></td><td>pang</td><td>剧痛、悲痛</td></tr><tr><td></td><td>panoply</td><td>全套披甲</td></tr><tr><td></td><td>parasites</td><td>寄生虫</td></tr><tr><td></td><td>parids</td><td>山雀、雏鸟</td></tr><tr><td></td><td>patches</td><td>斑块</td></tr><tr><td></td><td>pathogens</td><td>病原体</td></tr><tr><td></td><td>pelvis</td><td>骨盆</td></tr><tr><td></td><td>penetrated</td><td>穿透</td></tr><tr><td></td><td>perceived</td><td>感觉、认为</td></tr><tr><td></td><td>perceptibly</td><td>显然地</td></tr><tr><td></td><td>perch</td><td>栖木、高位</td></tr><tr><td></td><td>perched</td><td>栖息着的</td></tr><tr><td></td><td>perils</td><td>极大危险</td></tr><tr><td></td><td>perspective</td><td>观点的、透视的</td></tr><tr><td></td><td>pertained</td><td>涉及、关于</td></tr><tr><td></td><td>phenomenon</td><td>现象、迹象</td></tr><tr><td></td><td>pigmentation</td><td>着色</td></tr><tr><td></td><td>piqued</td><td>伤害…… 的自尊心</td></tr><tr><td></td><td>plagues</td><td>折磨、使得灾祸</td></tr><tr><td></td><td>pledged</td><td>保证、许诺、发誓</td></tr><tr><td></td><td>pollsters</td><td>民意调查者</td></tr><tr><td></td><td>polycultural</td><td>多文化的</td></tr><tr><td></td><td>porous</td><td>多孔的、能渗透的</td></tr><tr><td></td><td>prescriptive</td><td>规定的、指定的</td></tr><tr><td></td><td>preserving</td><td>保留、保存</td></tr><tr><td></td><td>presumably</td><td>推测上、大概</td></tr><tr><td></td><td>presuming</td><td>假定、推测、擅自、意味着、相信</td></tr><tr><td></td><td>pretending</td><td>假装、伪装</td></tr><tr><td></td><td>prevailing</td><td>盛行的、优势的</td></tr><tr><td></td><td>prevalence</td><td>流行、盛行</td></tr><tr><td></td><td>probes</td><td>探针、探头、探测仪</td></tr><tr><td></td><td>prodigious</td><td>惊人的</td></tr><tr><td></td><td>prone</td><td>有…… 倾向的</td></tr><tr><td></td><td>proscriptive</td><td>禁止的、放逐的</td></tr><tr><td></td><td>prospective</td><td>潜在的、有望的</td></tr><tr><td></td><td>purpose</td><td>目的、用途、效果、意向</td></tr><tr><td>R</td><td>rational</td><td>理性的、合理的</td></tr><tr><td></td><td>reassert</td><td>再断言、重复主张</td></tr><tr><td></td><td>recedes</td><td>逐渐远离</td></tr><tr><td></td><td>recruit</td><td>征募、招聘</td></tr><tr><td></td><td>removed</td><td>移除</td></tr><tr><td></td><td>repercussions</td><td>反响</td></tr><tr><td></td><td>report</td><td>报告、报道</td></tr><tr><td></td><td>resists</td><td>阻止、抵抗、对抗</td></tr><tr><td></td><td>retrieval</td><td>取回、恢复</td></tr><tr><td></td><td>revered</td><td>崇敬的</td></tr><tr><td></td><td>revival</td><td>复兴、苏醒</td></tr><tr><td></td><td>ripple effect</td><td>连锁反应、骨牌效应、波纹效应</td></tr><tr><td></td><td>rudimentary</td><td>基本的、初步的</td></tr><tr><td>S</td><td>sanction</td><td>认可、核准、同意、裁决</td></tr><tr><td></td><td>scarcely</td><td>简直不、一定不、仅仅</td></tr><tr><td></td><td>scenario</td><td>情节、剧本</td></tr><tr><td></td><td>scrutinize</td><td>仔细检查</td></tr><tr><td></td><td>secrete</td><td>隐藏</td></tr><tr><td></td><td>securing</td><td>固定住的</td></tr><tr><td></td><td>seductive</td><td>诱惑的、引人注意的</td></tr><tr><td></td><td>self-referential</td><td>自我指认的</td></tr><tr><td></td><td>separated</td><td>分离、分开</td></tr><tr><td></td><td>sever</td><td>切断、脱离</td></tr><tr><td></td><td>sight</td><td>视野</td></tr><tr><td></td><td>silhouette</td><td>轮廓、剪影</td></tr><tr><td></td><td>site</td><td>地址</td></tr><tr><td></td><td>solemn</td><td>严肃的、庄严的</td></tr><tr><td></td><td>solidarity</td><td>团结</td></tr><tr><td></td><td>solitude</td><td>孤独、孤寂</td></tr><tr><td></td><td>stabilized</td><td>稳定</td></tr><tr><td></td><td>stead</td><td>用处、好处</td></tr><tr><td></td><td>sterile</td><td>无菌的</td></tr><tr><td></td><td>sticklebacks</td><td>棘鱼</td></tr><tr><td></td><td>stimuli</td><td>刺激物</td></tr><tr><td></td><td>Styrofoam</td><td>泡沫聚苯乙烯</td></tr><tr><td></td><td>subdues</td><td>征服、克制、制服</td></tr><tr><td></td><td>subterranean</td><td>地下的、秘密的</td></tr><tr><td></td><td>subtly</td><td>巧妙地</td></tr><tr><td></td><td>supercilious</td><td>傲慢的、自大的</td></tr><tr><td></td><td>surface tension</td><td>表面张力</td></tr><tr><td></td><td>surviving</td><td>依然健在的、未死的</td></tr><tr><td></td><td>symbiotic</td><td>共生的</td></tr><tr><td>T</td><td>tactile</td><td>触觉的</td></tr><tr><td></td><td>temporal</td><td>暂时的</td></tr><tr><td></td><td>tendencies</td><td>趋向</td></tr><tr><td></td><td>tentative</td><td>犹豫不定的</td></tr><tr><td></td><td>theorize</td><td>理论化</td></tr><tr><td></td><td>threads</td><td>纤维</td></tr><tr><td></td><td>toil</td><td>苦干、跋涉</td></tr><tr><td></td><td>tonal</td><td>音调的</td></tr><tr><td></td><td>traverse</td><td>穿过、经过</td></tr><tr><td>U</td><td>unamimously</td><td>全体一致地、无异议地</td></tr><tr><td></td><td>unbeknownst</td><td>最不为人知的</td></tr><tr><td></td><td>undertake</td><td>保证、承担、同意、接受<br>表从事</td></tr><tr><td></td><td>unimpeded</td><td>无阻的</td></tr><tr><td></td><td>universally</td><td>普遍的、一般的</td></tr><tr><td></td><td>unlike</td><td>不像</td></tr><tr><td></td><td>unparalleled</td><td>无比的、无双的</td></tr><tr><td></td><td>unparatable</td><td>不可口的、使人不快的</td></tr><tr><td></td><td>unspecified</td><td>未特别指出的、未特别提到的</td></tr><tr><td></td><td>utterly</td><td>完全地、全然</td></tr><tr><td>V</td><td>vacant</td><td>空置的</td></tr><tr><td></td><td>vexed</td><td>使烦恼、使苦恼</td></tr><tr><td></td><td>violated</td><td>违反、妨碍</td></tr><tr><td></td><td>viscoelastic</td><td>粘弹性的</td></tr><tr><td></td><td>vividness</td><td>鲜艳、逼真</td></tr><tr><td></td><td>volatile</td><td>可变的、不稳定的<br>挥发物</td></tr><tr><td>W</td><td>wasps</td><td>黄蜂</td></tr><tr><td></td><td>whence</td><td>从何处、从哪个</td></tr><tr><td></td><td>winced</td><td>畏缩、退避</td></tr><tr><td></td><td>withheld</td><td>保留、扣留</td></tr><tr><td>Y</td><td>yardstick</td><td>计算标准</td></tr></tbody></table></details><h1 id="语法"><a class="markdownIt-Anchor" href="#语法"></a> 语法</h1><h2 id="句子排序"><a class="markdownIt-Anchor" href="#句子排序"></a> 句子排序</h2><details><pre><code class="language-plaintext">有时句子排序可以仅靠看主语来得出答案。例如当插入语的主语是代词时，就要排除掉没有出现过该指代的物体或人的句子。</code></pre></details><h2 id="表达风格"><a class="markdownIt-Anchor" href="#表达风格"></a> 表达风格</h2><details><pre><code class="language-plaintext">表达风格的题不能使用带有修辞的选项，要使用带书面表达的。</code></pre><pre><code class="language-plaintext">书面表达：find one's way [to / into] sth：成功地达到了某个效果</code></pre></details><h2 id="增减句子"><a class="markdownIt-Anchor" href="#增减句子"></a> 增减句子</h2><details><pre><code class="language-plaintext">插入句对句子而言是否有意义，例如尾句的插入句对该段落的总结有没有意义。</code></pre></details><h2 id="特殊单复数"><a class="markdownIt-Anchor" href="#特殊单复数"></a> 特殊单复数</h2><details><pre><code class="language-plaintext">mice 是 mouse 的复数。</code></pre></details><h2 id="两者并列"><a class="markdownIt-Anchor" href="#两者并列"></a> 两者并列</h2><details><pre><code class="language-plaintext">两个 that 从句的并列："... that... and that ...."</code></pre></details><h2 id="时态"><a class="markdownIt-Anchor" href="#时态"></a> 时态</h2><details><table><thead><tr><th style="text-align:center"></th><th style="text-align:center">一般时</th><th style="text-align:center">进行时</th><th style="text-align:center">完成时</th><th style="text-align:center">完成进行时</th></tr></thead><tbody><tr><td style="text-align:center">现在</td><td style="text-align:center">一般现在时</td><td style="text-align:center">现在进行时</td><td style="text-align:center">现在完成时</td><td style="text-align:center">现在完成进行时</td></tr><tr><td style="text-align:center">过去</td><td style="text-align:center">一般过去时</td><td style="text-align:center">过去进行时</td><td style="text-align:center">过去完成时</td><td style="text-align:center">过去完成进行时</td></tr><tr><td style="text-align:center">将来</td><td style="text-align:center">一般将来时</td><td style="text-align:center">将来进行时</td><td style="text-align:center">将来完成时</td><td style="text-align:center">将来完成进行时</td></tr><tr><td style="text-align:center">过去将来</td><td style="text-align:center">一般过去将来时</td><td style="text-align:center">过去将来进行时</td><td style="text-align:center">过去将来完成时</td><td style="text-align:center">过去将来完成进行时</td></tr></tbody></table><details><blockquote><p>一般现在时：<br><code>teach</code><br><code>teaches</code></p><blockquote><p><code>usually</code><br><code>every day</code></p></blockquote></blockquote><blockquote><p>一般过去时：<br><code>taught</code></p><blockquote><p><code>yesterday</code><br><code>just now</code></p></blockquote></blockquote><blockquote><p>一般将来时：<br><code>will teach</code><br><code>be going to teach</code><br><code>shall teach</code></p><blockquote><p><code>later</code><br><code>in the future</code></p></blockquote></blockquote><blockquote><p>一般过去将来时：<br><code>would teach</code><br><code>should teach</code></p><blockquote><p>宾语从句中，例 <code>I knew he would come</code><br>虚拟语气中，例 <code>If I were you, I would go</code><br><code>should</code> 少用</p></blockquote></blockquote><blockquote><p>现在进行时：<br><code>am teaching</code><br><code>is teaching</code><br><code>are teaching</code></p><blockquote><p><code>now</code></p></blockquote></blockquote><blockquote><p>过去进行时：<br><code>was teaching</code><br><code>were teaching</code></p><blockquote><p><code>at that time</code><br><code>while</code></p></blockquote></blockquote><blockquote><p>将来进行时：<br><code>will be teaching</code><br><code>be going to teaching</code><br><code>shall be teaching</code></p><blockquote><p>同 <strong>一般将来时</strong>，只是强调动作的进行状态</p></blockquote></blockquote><blockquote><p>过去将来进行时：<br><code>would be teaching</code><br><code>should be teaching</code></p><blockquote><p>同 <strong>一般过去将来时</strong>，只是强调动作的进行状态</p></blockquote></blockquote><blockquote><p>现在完成时：<br><code>has taught</code><br><code>have taught</code></p><blockquote><p><code>already</code><br><code>just</code><br><code>yet</code></p></blockquote></blockquote><blockquote><p>过去完成时：<br><code>had taught</code></p><blockquote><p><code>by the end of last year/term</code><br>从句是过去式</p></blockquote></blockquote><blockquote><p>将来完成时：<br><code>will have taught</code><br><code>be going to have taught</code><br><code>shall have taught</code></p><blockquote><p><code>by then</code><br><code>by the end of next month/year</code></p></blockquote></blockquote><blockquote><p>过去将来完成时：<br><code>would have taught</code><br><code>should have taught</code></p><blockquote><p>虚拟语气中，表示对过去已经发生的事情的建议<br><code>I would have gone there, if I had been invited</code><br><code>You shouldn't have done it</code></p></blockquote></blockquote><blockquote><p>现在完成进行时：<br><code>has been teaching</code><br><code>have been teaching</code></p><blockquote><p><code>since</code><br><code>for</code></p></blockquote></blockquote><blockquote><p>过去完成进行时：<br><code>had been teaching</code></p><blockquote><p>同 <strong>过去完成时</strong>，只是强调动作的过程以及延续性</p></blockquote></blockquote><blockquote><p>将来完成进行时：<br><code>will have been teaching</code><br><code>be going to have been teaching</code><br><code>shall have been teaching</code></p><blockquote><p>很少使用</p></blockquote></blockquote><blockquote><p>过去将来完成进行时：<br><code>would have been teaching</code><br><code>should have been teaching</code></p><blockquote><p>同 <strong>过去将来完成时</strong>，但这个很少用</p></blockquote></blockquote></details><div class="danger"><p>时态题不需要也不可能完全和上下句时态相同，所以不能盲目地看上下句，而是要看这句话在上下文里表达的是什么语义逻辑</p></div></details><h2 id="固定搭配"><a class="markdownIt-Anchor" href="#固定搭配"></a> 固定搭配</h2><details><blockquote><p><code>prevents sth from</code></p></blockquote><blockquote><p><code>be subject to</code><br><em>受到…… 影响</em>、<em>受…… 支配</em>、<em>服从于……</em></p><blockquote><p><code>be subjected to</code><br><em>使遭受（糟糕的东西、坏东西）</em></p></blockquote></blockquote><blockquote><p><code>and which</code><br><em>而其中</em>、<em>和其中</em>、<em>以及哪些</em></p></blockquote><blockquote><p><code>by which</code><br><em>由……</em>、<em>凭……</em></p></blockquote><blockquote><p><code>distinct from</code><br><em>不同于……</em></p></blockquote><blockquote><p><code>dreamed up</code><br><em>梦见了</em></p></blockquote><blockquote><p><code>for which</code><br><em>为其中的……</em>、<em>为之……</em></p></blockquote><blockquote><p><code>slunk out</code><br><em>鬼鬼祟祟地从某处离开</em></p></blockquote></details><h2 id="比较对象的一致性"><a class="markdownIt-Anchor" href="#比较对象的一致性"></a> 比较对象的一致性</h2><details><pre><code class="language-plaintext">先要找出这句话要比较谁和谁，其次查看比较对象的单复数，最终找出相对应的代词替代后者比较对象。</code></pre></details><h2 id="标点符号"><a class="markdownIt-Anchor" href="#标点符号"></a> 标点符号</h2><details><pre><code class="language-plaintext">双逗号、双破折号：形成插入语冒号：连接两个完整句，后句为前句的补充单逗号：无法连接两个完整句</code></pre></details><h2 id="连词-逻辑词"><a class="markdownIt-Anchor" href="#连词-逻辑词"></a> 连词 &amp; 逻辑词</h2><details><blockquote><p><code>although</code> <code>though</code><br><em>尽管</em><br>让步与转折</p></blockquote><blockquote><p><code>given that</code><br><em>鉴于</em></p></blockquote><blockquote><p><code>thus</code><br><em>因此</em><br>因果</p></blockquote><blockquote><p><code>namely</code><br><em>换句话说</em>、<em>即</em></p></blockquote><blockquote><p><code>rather</code><br><em>而是</em></p></blockquote><blockquote><p><code>regardless of</code><br><em>无论怎样</em></p></blockquote><blockquote><p><code>subsequent to</code><br><em>之后的</em></p></blockquote><blockquote><p><code>crucially</code><br><em>关键是</em></p></blockquote></details><h2 id="句子合并"><a class="markdownIt-Anchor" href="#句子合并"></a> 句子合并</h2><details><ol><li>表达正确，即意思应和原句相同</li><li>尽可能简洁，即句子结构以简单句为最简洁<br>最简洁的句子结构通常不用倒装</li><li>同一概念表达了一次以上的话，简洁性就会下降</li></ol></details><h2 id="代词"><a class="markdownIt-Anchor" href="#代词"></a> 代词</h2><details><blockquote><p><code>such</code><br>指示代词<br>前一句话需要提到 <code>such</code> 后面接的名词</p></blockquote></details><h2 id="逻辑主语一致"><a class="markdownIt-Anchor" href="#逻辑主语一致"></a> 逻辑主语一致</h2><details><blockquote><p><em>分词作状语，其逻辑主语为句子主语</em><br>例如：<code>Hearing the news, she felt her blood rushing to her face.</code><br>句子主语 <code>she</code> 是 <code>hearing</code> 的逻辑主语</p></blockquote></details><h2 id="从句"><a class="markdownIt-Anchor" href="#从句"></a> 从句</h2><details><table><thead><tr><th>状语从句</th><th>备注</th></tr></thead><tbody><tr><td><code>be it by ...</code></td><td><strong>倒装</strong><br>在句末时前面可以放 <em>破折号</em></td></tr></tbody></table></details><center>————————</center><h1 id="数学"><a class="markdownIt-Anchor" href="#数学"></a> 数学</h1><h2 id="标准差"><a class="markdownIt-Anchor" href="#标准差"></a> 标准差</h2><details><blockquote><p><em>Standard Derivation</em><br><code>基础数据分析</code> <code>概率论</code></p></blockquote><pre><code class="language-plaintext">衡量一个数据的大小需要根据它和均值之间差了多少个标准差。</code></pre><pre><code class="language-plaintext">标准差集中：数据越聚在一起（特别是在数据的正中间），标准差越小标准差分散：数据分布得越平均，或者很多数据在两边，标准差越大</code></pre></details><h2 id="标准误"><a class="markdownIt-Anchor" href="#标准误"></a> 标准误</h2><details><blockquote><p><em>Standard Error</em><br><code>统计推断</code></p></blockquote><pre><code class="language-plaintext">关键词：confidence intervalmargin of error</code></pre><pre><code class="language-plaintext">sample size 越大， margin or error 越小</code></pre></details><h2 id="弧长"><a class="markdownIt-Anchor" href="#弧长"></a> 弧长</h2><details><blockquote><p><em>Arc Length</em><br><code>几何</code> <code>圆</code></p></blockquote><pre><code class="language-plaintext">公式：(Θ/360)(2πr)</code></pre></details><h2 id="百分比差别"><a class="markdownIt-Anchor" href="#百分比差别"></a> 百分比差别</h2><details><blockquote><p><em>Percent Increase</em><br><code>比例</code></p></blockquote><pre><code class="language-plaintext">公式：(大数字 - 小数字) / 小数字</code></pre></details><h2 id="角度"><a class="markdownIt-Anchor" href="#角度"></a> 角度</h2><details><blockquote><p><em>Degrees</em><br><code>几何</code></p></blockquote><pre><code class="language-plaintext">π 是 180 度</code></pre></details><h2 id="弧度"><a class="markdownIt-Anchor" href="#弧度"></a> 弧度</h2><details><blockquote><p><em>Radians</em><br><code>几何</code></p></blockquote><pre><code class="language-plaintext">π 弧度 = 180 角度</code></pre></details><h2 id="二次函数"><a class="markdownIt-Anchor" href="#二次函数"></a> 二次函数</h2><details><blockquote><p><em>Quadratic Function</em><br><code>代数</code> <code>函数</code></p></blockquote><pre><code class="language-plaintext">开口朝上为正数，开口朝下为负数。</code></pre><pre><code class="language-plaintext">m (x^2) -&gt; 没有最大值-m (x^2) -&gt; 最大值为 0-(x^2) + m -&gt; 最大值为 m-(x + m)^2 -&gt; 最大值为 0</code></pre></details><h2 id="单位换算"><a class="markdownIt-Anchor" href="#单位换算"></a> 单位换算</h2><details><blockquote><p><em>Unit</em><br><code>单位</code></p></blockquote><pre><code class="language-plaintext">英制单位</code></pre></details><h2 id="方程组"><a class="markdownIt-Anchor" href="#方程组"></a> 方程组</h2><details><blockquote><p><em>System of Equations</em><br><code>代数</code></p></blockquote><pre><code class="language-plaintext">方程组无解：两个方程代表的直线斜率相同</code></pre></details><h2 id="实验对照组"><a class="markdownIt-Anchor" href="#实验对照组"></a> 实验对照组</h2><details><pre><code class="language-plaintext">想要从两组中得到某物的因果关系，那需要做到随机分组。</code></pre></details><h2 id="平均值"><a class="markdownIt-Anchor" href="#平均值"></a> 平均值</h2><details><blockquote><p><em>Mean</em><br><code>基础数据分析</code></p></blockquote><pre><code class="language-plaintext">数据组 A 和数据组 B 近乎一样，仅是多了一个最小值，那么 A 的平均值一定比 B 的小。</code></pre></details><h2 id="函数表达式"><a class="markdownIt-Anchor" href="#函数表达式"></a> 函数表达式</h2><details><blockquote><p><em>Function Expression</em><br><code>代数</code></p></blockquote><pre><code class="language-plaintext">当 f(x) 等于一个分数，且分母中包含 x 时，先要让分母等于 0 ，排除掉不可能的 x 。</code></pre></details><h2 id="二次方程的根"><a class="markdownIt-Anchor" href="#二次方程的根"></a> 二次方程的根</h2><details><blockquote><p><em>Roots of Quadratic Equation</em><br><code>代数</code></p></blockquote><pre><code class="language-plaintext">韦达定理：二次方程的根的总和为 -(b/a)二次方程的根的积为 c/a</code></pre></details><h2 id="单词-2"><a class="markdownIt-Anchor" href="#单词-2"></a> 单词</h2><details><table><thead><tr><th>英文</th><th>解析</th><th>例</th></tr></thead><tbody><tr><td>……is twice as large as……</td><td>前者是后者的两倍</td><td></td></tr><tr><td>……is <code>n</code> less than……</td><td>前者比后者少 <code>n</code></td><td></td></tr></tbody></table></details></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;该文档是给自己复习用的。&lt;/p&gt;
&lt;p&gt;并不包含所有的知识点，且知识点不一定正确。&lt;/p&gt;</summary>
    
    
    
    <category term="学术笔记" scheme="https://blog.cytrogen.icu/categories/%E5%AD%A6%E6%9C%AF%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="SAT" scheme="https://blog.cytrogen.icu/tags/SAT/"/>
    
  </entry>
  
  <entry>
    <title>Linux Desmume 安装</title>
    <link href="https://blog.cytrogen.icu/posts/ec37.html"/>
    <id>https://blog.cytrogen.icu/posts/ec37.html</id>
    <published>2022-08-02T00:37:26.000Z</published>
    <updated>2026-02-09T17:16:54.733Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>该文档讲述了如何在 Linux 系统下安装最新版本的 Desmume。</p><span id="more"></span><div class="danger"><p>开始阅读前，需要知道：</p><ul><li>Desmume 是一个 NDS 模拟器</li><li>NDS 是任天堂在 04 年发售的便携式游戏机，具有双屏幕显示、触摸屏等功能或特色</li><li>该文档搬运且汉化了 <a href="https://wiki.desmume.org/index.php?title=Installing_DeSmuME_from_source_on_Linux">Wiki</a> 上的安装方法：用 Git 安装</li></ul></div><center>————————</center><h1 id="获取源码"><a class="markdownIt-Anchor" href="#获取源码"></a> 获取源码</h1><h2 id="如果没有git"><a class="markdownIt-Anchor" href="#如果没有git"></a> 如果没有 Git</h2><ol><li>进入 Desmume 的 <a href="https://github.com/TASVideos/desmume">GitHub 仓库</a>。</li><li>点击绿色的 <strong>Code</strong> 按钮，点击 <strong>Download ZIP</strong>。</li><li>解压后备用。</li></ol><h2 id="反之有git"><a class="markdownIt-Anchor" href="#反之有git"></a> 反之有 Git</h2><ol><li>打开终端，输入 <code>git clone https://github.com/TASVideos/desmume</code></li></ol><center> ————————</center><h1 id="安装"><a class="markdownIt-Anchor" href="#安装"></a> 安装</h1><ol><li><p>打开终端，输入以下：</p> <pre><code class="language-bash">cd desmume/desmume/src/frontend/posix./autogen.sh./configuremakesudo make install</code></pre><p>如果想使用 offscreen mesa 作为替补 3D 引擎，改用 <code>./configure --enable-osmesa</code>。</p><p>如果想启用 HUD 显示，则用 <code>./configure --enable-hud</code>。</p></li><li><p>安装成功，在终端中输入 <code>desmume</code> 或在应用中点击其图标即可开启。</p></li></ol></body></html>]]></content>
    
    
    <summary type="html">本文是一篇在 Linux 系统上安装 NDS 模拟器 DeSmuME 的简明教程，内容搬运并汉化自其官方。文章主要介绍了如何通过从源代码编译的方式来安装最新版本的 DeSmuME，涵盖了使用 Git 克隆或直接下载源码，以及执行 ./autogen.sh, ./configure, make 等一系列编译安装命令的完整流程。本教程为希望在 Linux 上运行 NDS 游戏的玩家提供了清晰直接的操作指南。</summary>
    
    
    
    <category term="工具" scheme="https://blog.cytrogen.icu/categories/%E5%B7%A5%E5%85%B7/"/>
    
    
    <category term="Linux" scheme="https://blog.cytrogen.icu/tags/Linux/"/>
    
  </entry>
  
  <entry>
    <title>Hoka-bot 部署教程</title>
    <link href="https://blog.cytrogen.icu/posts/9b61.html"/>
    <id>https://blog.cytrogen.icu/posts/9b61.html</id>
    <published>2022-06-30T15:04:02.000Z</published>
    <updated>2026-02-09T17:16:54.713Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>该文档将讲述如何部署 Hoka-bot（以下称为 Hoka）。</p><span id="more"></span><img src="/posts/9b61/HOKA简介.webp" alt="Hokabot-bot" loading="lazy"><div class="danger"><p>在开始本教程前，需要知道该教程：</p><ul><li>基于 Python3.9</li><li>基于 Linux 系统 / Ubuntu（我是 20.04.1 版本）</li><li>是 <strong> 6 月 30 日</strong> 版本的 Hoka-bot 部署教程</li></ul></div><h1 id="开始部署之前"><a class="markdownIt-Anchor" href="#开始部署之前"></a> 开始部署之前</h1><blockquote><p>理所当然的，你需要将 Hoka 的代码克隆至本地。</p></blockquote><ol><li><p>进入 <a href="https://github.com/Cytrogen/Hoka-Bot">Hoka 的仓库</a>。</p></li><li><p>如下图所示，克隆或下载代码的压缩文件：</p></li></ol><img src="/posts/9b61/Clone.webp" alt="克隆或下载ZIP" loading="lazy"><ol start="3"><li>得到的文件夹应如下图：</li></ol><img src="/posts/9b61/主文件夹.webp" alt="主文件夹" loading="lazy"><blockquote><p>关于 bot 代码结构可以看看 <a href="https://cytrogen.netlify.app/2022/02/01/nonebot-beta1%E6%95%99%E7%A8%8B/">这篇 Nonebot2 教程</a></p></blockquote><p>你已经得到了一个 Hoka！但他还是个空壳，无法立马投入使用。</p><center>————————</center><h1 id="配置hoka的环境配置文件"><a class="markdownIt-Anchor" href="#配置hoka的环境配置文件"></a> 配置 Hoka 的环境配置文件</h1><blockquote><p>Hoka 部署最为紧要的部分是 <code>.env</code> 文件，也就是 <strong>环境配置文件</strong>。</p></blockquote><ol><li><p>进入 <code>.env</code> 文件进行编辑：</p>   <pre><code class="language-plaintext">ENVIRONMENT=devHOST=127.0.0.1PORT=56766LOG_LEVEL=INFOFASTAPI_RELOAD=trueSUPERUSERS = [""]NICKNAME = ["hoka"]COMMAND_START = ["hoka", ""]COMMAND_SEP = ["*"]GOCQ_ACCOUNR = [{   "uin": ,   "password": "",   "protocol": 1}]GOCQ_URL = https://github.com/Mrs4s/go-cqhttp/releases/download/v1.0.0-rc3/go-cqhttp_linux_amd64.tar.gzAPSCHEDULER_AUTOSTART = trueAPI_TIMEOUT = 3600RAM_CMD = 功能RAM_ADD = 开启RAM_RM = 关闭RAM_SHOW = 查询RAM_AVAILABLE = 全局查询GAME_PATH = ''MAX_BET_GOLD = 10000READ_QQ_FRIENDS = []READ_QQ_GROUPS = []READ_INFORM_TIME = [{"HOUR": 9, "MINUTE": 5}]</code></pre></li><li><ul><li><p>环境默认为 <code>dev</code>，即 <code>development</code>、开发环境；</p></li><li><p>可更改为 <code>prod</code>，即 <code>production</code>、生产环境；</p> <pre><code class="language-plaintext">ENVIRONMENT=dev</code></pre></li></ul></li></ol><br><ol start="3"><li><p>如下，这里分别是 <code>HOST 监听IP/主机名</code>、<code>PORT 监听端口</code>、<code>LOG LEVEL 日志等级</code> 和 <code>FASTAPI_RELOAD</code> 的配置：</p><ul><li><p>下面的端口如果已被使用可以修改为其他数字，其它则都不需要碰。</p> <pre><code class="language-plaintext">HOST=127.0.0.1PORT=56766LOG_LEVEL=INFOFASTAPI_RELOAD=true</code></pre></li></ul></li><li><ul><li><p>配置 <code>SUPERUSERS 超级用户</code>：超级用户是 Hoka 的管理员，有着最高权限。<br>这里推荐只写你自己的 QQ 号；</p></li><li><p>配置 <code>NICKNAME bot昵称</code>：不建议修改，因为我都是直接在代码里写的 Hoka，改了没啥用；</p></li><li><p>配置 <code>COMMAND_START 命令前缀</code>：不建议修改，但也不是不能改；</p></li><li><p>配置 <code>COMMAND_SEP 命令隔开符</code>：不咋用到这个，随意更改。</p> <pre><code class="language-plaintext">SUPERUSERS = [""]NICKNAME = ["hoka"]COMMAND_START = ["hoka", ""]COMMAND_SEP = ["*"]</code></pre></li></ul></li><li><p>配置 <code>Go-CQHTTP插件</code>：</p><ul><li><p><strong>介于该插件的前端可以登录账号，你不需要配置 <code>GOCQ_ACCOUNR</code>；</strong></p></li><li><p>该插件将会下载 <code>GOCQ_URL</code> 中填写的地址，什么都不输入将自动使用该插件默认的镜像站以及最新版本。</p> <pre><code class="language-plaintext">GOCQ_ACCOUNR = [{   "uin": ,   "password": "",   "protocol": 1}]GOCQ_URL = https://github.com/Mrs4s/go-cqhttp/releases/download/v1.0.0-rc3/go-cqhttp_linux_amd64.tar.gz</code></pre></li></ul></li><li><p>不需要管这俩。</p>   <pre><code class="language-plaintext">APSCHEDULER_AUTOSTART = trueAPI_TIMEOUT = 3600</code></pre></li><li><p><code>rauthman 权限管理插件</code> 的配置项：</p><ul><li><p>其实只是指令名更改，不建议修改。</p> <pre><code class="language-plaintext">RAM_CMD = 功能RAM_ADD = 开启RAM_RM = 关闭RAM_SHOW = 查询RAM_AVAILABLE = 全局查询</code></pre></li></ul></li><li><p><code>game 群组游戏插件</code> 的配置项：</p><ul><li><p><code>GAME_PATH</code> 不要碰；</p></li><li><p><code>MAX_BET_GOLD</code> 为俄罗斯轮盘中赌注的上限，可以调低防止一夜暴富一夜回到解放前。</p> <pre><code class="language-plaintext">GAME_PATH = ''MAX_BET_GOLD = 10000</code></pre></li></ul></li><li><p><code>read_60s 60秒读世界插件</code> 的配置项：</p><ul><li><p><code>READ_QQ_FRIENDS</code> 为每日定时发送的 QQ 好友号；</p></li><li><p><code>READ_QQ_GROUPS</code> 为每日定时发送的 QQ 群聊号；</p></li><li><p><code>READ_INFORM_TIME</code> 为每日定时发送的时间，按照本地时间为标准，如下便是每日早上 9 点 5 分。</p> <pre><code class="language-plaintext">READ_QQ_FRIENDS = []READ_QQ_GROUPS = []READ_INFORM_TIME = [{"HOUR": 9, "MINUTE": 5}]</code></pre></li></ul></li><li><p>你已经配置好了环境配置文件！</p></li></ol><center>————————</center><h1 id="配置hoka的群组游戏"><a class="markdownIt-Anchor" href="#配置hoka的群组游戏"></a> 配置 Hoka 的群组游戏</h1><blockquote><p>需要配置的只有群组卡池。</p></blockquote><ol><li><p>进入 <code>src/plugins/game/gacha.py</code>，找到 <code>class NormalData</code>：</p>   <pre><code class="language-python">class NormalData:   sixList = []   fiveList = []   fourList = []   threeList = []   onelist = ['虾虾']   fiveListUp = []   sixListUP = []</code></pre></li><li><p><code>sixList</code> 为卡池的六星角色，<code>fiveList</code> 为五星… 以此类推。<br><code>oneList</code> 建议保留为虾虾，因为虾虾这个名字也在代码内，当然你也可以自己一次性全部修改。<br><code>fiveListUp</code> 和 <code>sixListUP</code> 都是概率 UP 角色。</p></li><li><p>填写格式像这样：<code>sixList = ['名字', '另一个名字']</code>。</p></li></ol><center>————————</center><h1 id="配置go-cqhttp-运行hoka"><a class="markdownIt-Anchor" href="#配置go-cqhttp-运行hoka"></a> 配置 Go-CQHTTP &amp; 运行 Hoka</h1><ol><li><p>首先需要运行一次 Hoka。<br>在有 <code>bot.py</code> 的主文件夹内开终端输入 <code>python3.9 bot.py</code>。</p></li><li><p>在终端中找到这么一行：</p>   <pre><code class="language-plaintext">[INFO] nonebot_plugin_gocqhttp | Startup complete, Web UI has served to http://127.0.0.1:56766/go-cqhttp/</code></pre></li><li><p>进入后面的这个地址，页面应如下：</p></li></ol><img src="gocqhttp.webp" alt="Go-CQHTTP前端" loading="lazy"><ol start="4"><li><p>点击左上角的 <code>添加账号</code>。<br>依次输入 bot 的 QQ 号、密码，并选择登录设备类型。个人通常使用 Android Phone。</p></li><li><p>提交后关闭页面，回到终端关闭过程，再次输入 <code>python3.9 bot.py</code>。<br>此时终端会多出来自于 <code>nonebot_plugin_gocqhttp</code> 的信息，并开始登录 bot 账号。<br>在网络诊断完成后，Hoka 便运行成功，可以使用了。</p></li></ol><center>————————</center><h1 id="后言"><a class="markdownIt-Anchor" href="#后言"></a> 后言</h1><p>你已经学会如何配置 &amp; 部署 Hoka 了！</p></body></html>]]></content>
    
    
    <summary type="html">&lt;p&gt;该文档将讲述如何部署 Hoka-bot（以下称为 Hoka）。&lt;/p&gt;</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Nonebot" scheme="https://blog.cytrogen.icu/tags/Nonebot/"/>
    
  </entry>
  
  <entry>
    <title>Nonebot beta1 教程</title>
    <link href="https://blog.cytrogen.icu/posts/41a5.html"/>
    <id>https://blog.cytrogen.icu/posts/41a5.html</id>
    <published>2022-02-02T01:46:02.000Z</published>
    <updated>2026-02-09T17:16:54.733Z</updated>
    
    <content type="html"><![CDATA[<html><head></head><body><p>Nonebot2 在更新到 beta1 版本后许多地方和 alpha16 版本有许多差异，包括但不限于适配器、依赖的更改。</p><span id="more"></span><p><img src="/posts/41a5/Nonebot.webp" alt="Nonebot2" loading="lazy"></p><center>Nonebot2 是 Python 聊天机器人框架，目前仅支持 Python 3.7.3 以上的版本</center><div class="danger"><p>开始本教程前，需要知道该教程：</p><ul><li>Python 版本 ≥ 3.7</li><li>基于 Windows 10 版本（Win11 也可以但我只能说快逃）</li><li>使用了 pip 用于安装</li><li>使用了脚手架 nb-cli</li><li>使用了 onebot.v11 适配器</li></ul></div><h1 id="创建项目之前"><a class="markdownIt-Anchor" href="#创建项目之前"></a> 创建项目之前</h1><p>在创建机器人项目前需要安装：</p><ul><li><a href="#%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE%E4%B9%8B%E5%89%8D">创建项目之前</a><ul><li><a href="#%E4%B8%8B%E8%BD%BDpython">下载 Python</a></li><li><a href="#%E5%AE%89%E8%A3%85pip">安装 pip</a></li><li><a href="#%E5%AE%89%E8%A3%85nb-cli">安装 nb-cli</a></li><li><a href="#%E4%B8%8B%E8%BD%BDgo-cqhttp">下载 go-cqhttp</a></li></ul></li><li><a href="#%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE">创建项目</a><ul><li><a href="#%E6%96%B0%E5%BB%BA%E9%A1%B9%E7%9B%AE">新建项目</a></li><li><a href="#%E9%85%8D%E7%BD%AE%E9%A1%B9%E7%9B%AE">配置项目</a></li><li><a href="#%E7%94%A8%E4%B8%8B%E6%9C%BA%E5%99%A8%E4%BA%BA">用下机器人</a></li></ul></li><li><a href="#%E6%B7%B1%E5%85%A5%E6%8F%92%E4%BB%B6">深入插件</a><ul><li><a href="#%E4%BB%80%E4%B9%88%E6%98%AF%E6%8F%92%E4%BB%B6">什么是插件</a></li><li><a href="#%E5%88%9B%E5%BB%BA%E6%8F%92%E4%BB%B6">创建插件</a></li><li><a href="#%E7%94%A8%E5%88%AB%E4%BA%BA%E7%9A%84%E6%8F%92%E4%BB%B6">用别人的插件</a></li><li><a href="#%E4%BA%8B%E4%BB%B6%E5%93%8D%E5%BA%94%E5%99%A8">事件响应器</a></li><li><a href="#%E5%A4%84%E7%90%86%E6%B5%81%E7%A8%8B">处理流程</a></li><li><a href="#%E6%8F%92%E4%BB%B6%E5%AE%9E%E4%BE%8B">插件实例</a></li></ul></li></ul><p>而这些都会讲到，已经安装过了的建议 <a href="#%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE">空降</a>。</p><center>————————</center><h2 id="下载python"><a class="markdownIt-Anchor" href="#下载python"></a> 下载 Python</h2><ol><li><p>进入 <a href="https://www.python.org/downloads/windows/">Python 官网</a>。</p></li><li><p>选择 3.7.3 版本以上的进行下载。</p><p><img src="/posts/41a5/python.webp" alt="python 3.9.9" loading="lazy"></p></li><li><p>我的 Python 版本是 3.9.9，选择上图中的 <strong>Windows installer (64-bit)</strong> 进行下载。</p></li><li><p>下载完成后点进 <strong>python-3.9.9-amd64.exe</strong>，勾选 <strong>Add Python 3.9 to PATH</strong> 后点击 <strong>Install Now</strong>。<br>当然，你也可以自定义路径，但一定要勾选 PATH。</p><p><img src="/posts/41a5/python_version.webp" alt="python --version" loading="lazy"></p></li><li><p>等待下载……</p><p>下载完毕后开个 CMD 输入 <code>python --version</code>，出现 <code>Python 3.9.9</code> 就代表能用了。</p></li></ol><center>————————</center><h2 id="安装pip"><a class="markdownIt-Anchor" href="#安装pip"></a> 安装 pip</h2><p>pip 是 Python 包管理工具，用来下载 Python 的包。</p><ol><li><p>进入 <a href="https://pypi.org/project/pip/">PyPI</a>，选择最新版本的 pip。</p><p><img src="/posts/41a5/pip.webp" alt="pip" loading="lazy"></p></li><li><p>选择 Download Files，下载 pip-22.0.2.tar.gz 进行解压。</p><p><img src="/posts/41a5/pip_com.webp" alt="pip解压" loading="lazy"></p></li><li><p>解压后进入文件夹内，右键空白处打开 CMD，输入 <code>python setup.py install</code></p></li><li><p>等待安装……<br>安装完成后开个 CMD 输入 <code>pip --version</code>，出现 <code>pip 22.0.2 from 路径……</code> 时就代表能用了。</p></li></ol><center>————————</center><h2 id="安装nb-cli"><a class="markdownIt-Anchor" href="#安装nb-cli"></a> 安装 nb-cli</h2><p>Nonebot2 提供了相当便利的工具 nb-cli，安装它也会直接安装 nonebot 2.0.0-beta1。</p><ol><li><p>开个 CMD 输入 <code>pip install nb-cli</code></p></li><li><p>出现 <code>Successfully installed nb-cli……</code> 就代表 pip 安装 nb-cli 成功了。</p></li></ol><center>————————</center><h2 id="下载go-cqhttp"><a class="markdownIt-Anchor" href="#下载go-cqhttp"></a> 下载 go-cqhttp</h2><p>做机器人只有 Nonebot2 是不足够的，Nonebot2 仅能做到处理机器人上报的事件。<br>机器人的实际工作流程为：</p><ol><li><strong>协议端</strong> 上报数据给 <strong>后端驱动</strong>；</li><li><strong>后端驱动</strong> 将原始数据转交给 <strong>协议适配</strong> 处理；</li><li><strong>协议适配</strong>，或称为 bot，将数据转化为 event 转交给 Nonebot2；</li><li>Nonebot2 处理 event。</li></ol><p>很显然，我们只有处理 event 的 Nonebot2。</p><p>获取数据的工作便交到了 go-cqhttp 身上：它相当于你的另一个 QQ，接收到信息后便转交到 Nonebot2 手上等着处理完和发送。</p><ol><li><p>进入 <a href="https://github.com/Mrs4s/go-cqhttp/releases">go-cqhttp 仓库</a>，下载最新版本的 releases。</p></li><li><p>选择 <strong>go-cqhttp_windows_amd64.exe</strong> 进行下载和备用。</p></li></ol><center>————————</center><h1 id="创建项目"><a class="markdownIt-Anchor" href="#创建项目"></a> 创建项目</h1><p>现在该下的都下载完了，是时候创建机器人项目了：</p><ol><li><a href="#%E6%96%B0%E5%BB%BA%E9%A1%B9%E7%9B%AE">新建项目</a></li><li><a href="#%E9%85%8D%E7%BD%AE%E9%A1%B9%E7%9B%AE">配置项目</a></li><li><a href="#%E7%94%A8%E4%B8%8B%E6%9C%BA%E5%99%A8%E4%BA%BA">用下机器人</a></li></ol><center> ————————</center><h2 id="新建项目"><a class="markdownIt-Anchor" href="#新建项目"></a> 新建项目</h2><ol><li><p>新建一个文件夹，右键打开 CMD，输入 <code>nb create</code>。</p></li><li><p><code>Project Name:</code>，输入你想给你机器人取的名字。</p></li><li><p><code>Where to store the plugin?</code>，这意味着机器人插件的存放路径，建议选择 <code>In a "src" folder</code>。</p></li><li><p><code>Which builtin plugin(s)……巴拉巴拉</code>，这就是在问你你的机器人要不要 Nonebot2 内嵌的插件，建议只选择 <code>echo</code> 插件。</p><p><img src="/posts/41a5/echo.webp" alt="echo" loading="lazy"></p><p>需要注意的是，选择内嵌插件时要按下空格再回车继续。</p></li><li><p><code>Which adapter(s)……巴拉巴拉</code>，选择你想要的协议适配，这里要选择 <code>OneBot V11</code>，别忘了空格再回车。</p></li><li><p>期间会进行适配器等的安装，结束后你的文件夹内便会出现机器人名字的文件夹，差不多长这样：</p> <pre><code class="language-plaintext">机器人名字├── src│   └── plugins├── .env├── .env.dev├── .env.prod├── .gitignore├── bot.py├── docker-compose.yml├── Dockerfile├── pyproject.toml└── README.md</code></pre></li></ol><ul><li><code>src/plugins</code> 为 Nonebot2 插件存放处，插件则是 Nonebot2 的核心，可以实现模块化、功能扩展等</li><li><code>.env.*</code> 等文件是项目的配置文件，内存有变量 <code>ENVIRONMENT</code>，是 Nonebot2 启动时就会寻找的系统环境变量</li><li><code>.gitignore</code>，如果不上传到 git 仓库的话可以无视</li><li><code>bot.py</code> 是是启动 Nonebot2 时默认的入口文件</li><li><code>pyproject.toml</code> 是项目插件配置文件</li><li><code>Dockerfile</code> 和 <code>docker-compose.yml</code> 皆为 Docker 镜像配置文件</li></ul><center>————————</center><h2 id="配置项目"><a class="markdownIt-Anchor" href="#配置项目"></a> 配置项目</h2><p><code>.env</code> 文件是基础的环境配置文件，不管是什么环境都会被加载，不过还是会被 <code>.env.{环境}</code> 文件所覆盖。</p><p>而环境有：</p><ul><li>开发环境 development 或 dev</li><li>生产环境 production 或 prod<br>等等等等，就不一一列举了。</li></ul><ol><li><p>打开 <code>.env</code> 文件写入：<code>ENVIRONMENT=dev</code>。<br>开发环境将会报告错误日志，这也会将环境变量的加载导向 <code>.env.dev</code> 文件。</p></li><li><p>打开 <code>.env.dev</code> 文件，写入以下配置：</p> <pre><code class="language-plaintext">HOST=127.0.0.1PORT=xxxxSUPERUSERS=["xxxxx"]NICKNAME=["xxx"]COMMAND_START=["/",""]COMMAND_SEP=["x"]</code></pre><ul><li>其中，<code>HOST</code> 为 Nonebot2 监听的 IP /主机名</li><li><code>PORT</code> 为监听的端口，这里可以随意选择一个四位数</li><li><code>SUPERUSERS</code> 为超级用户，后面会说作用。值是一个 QQ 号，建议使用大号</li><li><code>NICKNAME</code> 为机器人的昵称</li><li><code>COMMAND_START</code> 为命令起始字符，后面会说作用，这里先用 "/"</li><li><code>COMMAND_SEP</code> 为命令分割字符</li></ul></li><li><p>第 2 步完成后对 Nonebot2 的基础配置就完成了，但我们还未配置 go-cqhttp。</p><p>再新建一个文件夹，里边存放我们之前下载的 <strong>go-cqhttp_windows_amd64.exe</strong>，同时我建议将该 exe 文件重命名为 <strong>go-cqhttp.exe</strong>。</p></li><li><p>新建一个 <code>config.yml</code> 文件，作为 go-cqhttp 的配置文件。</p><ul><li>配置信息前往 <a href="https://docs.go-cqhttp.org/guide/config.html#%E9%85%8D%E7%BD%AE%E4%BF%A1%E6%81%AF">go-cqhttp 文档</a> 内进行复制粘贴</li><li><code>servers</code> 下面选择 <code>ws-reverse</code>，如下图</li></ul><p><img src="/posts/41a5/wsreverse.webp" alt="ws-reverse" loading="lazy"></p></li><li><p>修改配置信息：</p><ul><li><code>account</code> 下的 <code>uin</code> 需要填写机器人所用的 QQ 账号</li><li><code>password</code> 需要填写 QQ 账号的密码</li><li><code>servers</code> 下的 <code>port</code> 需要填写配置 Nonebot2 时填写的四位数 PORT</li></ul></li><li><p>启动 go-cqhttp.exe。百分百会弹出生成 .bat 文件的窗口，直接关闭后会发现文件夹内多出了一个 <strong>go-cqhttp.bat</strong>，以后启动 go-cqhttp 都需要用到这个文件。</p><p>启动后 go-cqhttp 会进行登录，出现 <code>[INFO]: アトリは、高性能ですから!</code> 时便是登陆成功，要开始连接到 Nonebot2 了。</p><p>因为我们 Nonebot2 还未开启，此时的 go-cqhttp 只会一直弹出黄色的连接失败。</p></li></ol><center>————————</center><h2 id="用下机器人"><a class="markdownIt-Anchor" href="#用下机器人"></a> 用下机器人</h2><p>一切准备成功，机器人已经可以使用了！</p><p>使用机器人时，Nonebot2 和 go-cqhttp 都需要 <strong>一直开启</strong>。对于不想长期开着电脑的小伙伴，建议使用云服务器。</p><ol><li><p>打开存放 <strong><a href="http://bot.py">bot.py</a></strong> 的文件夹，右键开启 CMD，输入 <code>nb run</code>。</p></li><li><p>打开存放 <strong>go-cqhttp.bat</strong> 的文件夹，左键打开。</p></li><li><p>等待第 1 步的 CMD 出现了</p> <pre><code class="language-plaintext">[INFO] nonebot | OneBot V11 | Bot QQ账号 connected[INFO] websockets | connection open</code></pre><p>便意味着机器人可以使用了。</p></li><li><p>快马加鞭通过大号给机器人账号发送 <code>/echo 喵</code></p><p><img src="/posts/41a5/echomeow.webp" alt="echo" loading="lazy"></p><p>这边是因为我的机器人命令起始字符为 "hoka"，你也可以修改成自己喜欢的</p></li><li><p>机器人一旦复读了，便真正的代表着，你成功的搭建了一个 QQ 机器人。</p><p><s>好了，现在新手教程结束了，来试试这些插件吧.jpg</s></p></li></ol><center>————————</center><h1 id="深入插件"><a class="markdownIt-Anchor" href="#深入插件"></a> 深入插件</h1><p>咳咳，恭喜你获得了一个刚出生的 QQ 机器人！但它九年义务教育还未完成……<br>对于一个功能完善的机器人而言，<strong>完善的插件系统</strong> 是不可缺少的。</p><p>我们接下来的才是 Nonebot2 的重头戏：<strong>插件讲解</strong>。</p><ul><li><a href="#%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE%E4%B9%8B%E5%89%8D">创建项目之前</a><ul><li><a href="#%E4%B8%8B%E8%BD%BDpython">下载 Python</a></li><li><a href="#%E5%AE%89%E8%A3%85pip">安装 pip</a></li><li><a href="#%E5%AE%89%E8%A3%85nb-cli">安装 nb-cli</a></li><li><a href="#%E4%B8%8B%E8%BD%BDgo-cqhttp">下载 go-cqhttp</a></li></ul></li><li><a href="#%E5%88%9B%E5%BB%BA%E9%A1%B9%E7%9B%AE">创建项目</a><ul><li><a href="#%E6%96%B0%E5%BB%BA%E9%A1%B9%E7%9B%AE">新建项目</a></li><li><a href="#%E9%85%8D%E7%BD%AE%E9%A1%B9%E7%9B%AE">配置项目</a></li><li><a href="#%E7%94%A8%E4%B8%8B%E6%9C%BA%E5%99%A8%E4%BA%BA">用下机器人</a></li></ul></li><li><a href="#%E6%B7%B1%E5%85%A5%E6%8F%92%E4%BB%B6">深入插件</a><ul><li><a href="#%E4%BB%80%E4%B9%88%E6%98%AF%E6%8F%92%E4%BB%B6">什么是插件</a></li><li><a href="#%E5%88%9B%E5%BB%BA%E6%8F%92%E4%BB%B6">创建插件</a></li><li><a href="#%E7%94%A8%E5%88%AB%E4%BA%BA%E7%9A%84%E6%8F%92%E4%BB%B6">用别人的插件</a></li><li><a href="#%E4%BA%8B%E4%BB%B6%E5%93%8D%E5%BA%94%E5%99%A8">事件响应器</a></li><li><a href="#%E5%A4%84%E7%90%86%E6%B5%81%E7%A8%8B">处理流程</a></li><li><a href="#%E6%8F%92%E4%BB%B6%E5%AE%9E%E4%BE%8B">插件实例</a></li></ul></li></ul><center> ————————</center><h2 id="什么是插件"><a class="markdownIt-Anchor" href="#什么是插件"></a> 什么是插件</h2><p>仔细读的都知道，插件是 Nonebot2 的核心。插件既可以是一个模块，也可以是一个包。</p><p>插件的存放路径是 <code>src/plugins</code>，在这个路径下，任何 <strong>.py 文件</strong> 或 <strong>有__init__.py 文件的文件夹</strong> 都算为插件。</p><div class="danger"><p>插件名称不可以重复。</p></div><p>多说不如少做，瞅一眼 <a href="#%E6%8F%92%E4%BB%B6%E5%AE%9E%E4%BE%8B">插件实例</a>，说不定能够更理解插件的用处。</p><center>————————</center><h2 id="创建插件"><a class="markdownIt-Anchor" href="#创建插件"></a> 创建插件</h2><ol><li><p>在机器人文件夹里右键开启 CMD，输入 <code>nb plugin create</code>。</p></li><li><p><code>Project Name:</code>，输入插件的名称</p></li><li><p><code>Where to store the plugin?</code>，自处是询问插件存放的路径，选择 <code>src/plugins</code> 即可。</p></li><li><p><code>Do you want to load……巴拉巴拉</code>。如果你想在你创建的这个插件里再套娃一个插件，就选 <code>y</code>；反之就 <code>n</code>。正常都是不用套娃。</p></li><li><p>没了，你的插件创建完成噜。</p><p>进入 <code>src/plugins</code> 里边，就能看到插件名称的文件夹，里边分别躺着 <strong><strong>init</strong>.py</strong> 和 <strong><a href="http://config.py">config.py</a></strong> 文件。</p><p>前者用于编写插件内容，相当于插件的入口文件；后者则是插件的配置文件。</p><p><s>其实直接在文件夹内新建也可以，就提一嘴。</s></p></li></ol><center>————————</center><h2 id="用别人的插件"><a class="markdownIt-Anchor" href="#用别人的插件"></a> 用别人的插件</h2><p><em>要是自己代码写不明白，岂不是永远都没法整一个机器人了？</em></p><p><strong>没有的事</strong>。Nonebot2 具有一个专属的 <a href="https://v2.nonebot.dev/store">商店</a>，其包含了开源的</p><ul><li>驱动器</li><li>适配器</li><li>插件</li><li>机器人</li></ul><p>使用他人的插件很简易，方法也多，就是别忘了用了后给他们一个 <strong>STAR</strong> ~</p><center>……</center><p><strong>pip 安装法：</strong></p><p><img src="/posts/41a5/docs.webp" alt="docs" loading="lazy"></p><ol><li><p>举例：NoneBot 离线文档【nonebot_plugin_docs】</p><p>这个插件在加载后会输出一个可以 <strong>离线打开</strong> 的 Nonebot2 网址。</p></li><li><p>开个 CMD，输入 <code>pip install nonebot_plugin_docs</code></p></li><li><p>等待安装完成……</p><p><img src="/posts/41a5/bot.webp" alt="bot.py" loading="lazy"></p></li><li><p>来到机器人文件夹下的 <strong><a href="http://bot.py">bot.py</a></strong>，找到上图这个位置。</p><p><code>nonebot.load_builtin_plugins("echo")</code> 意思便是 Nonebot2 加载了内嵌的 echo 插件，也就是我们之前试用机器人时用的 echo 功能。</p><p><code>nonebot.load_from_toml("pyproject.toml")</code> 加载了配置内插件存放路径下所有的插件，也就是 <code>src/plugins</code>。</p><p>实际上，插件的加载也有前后之分。按照上图的顺序来说，机器人启动时都会事先加载 echo 插件，其次才是 <code>src/plugins</code> 下的插件。</p></li><li><p>按照你想要的顺序，在 <strong><a href="http://bot.py">bot.py</a></strong> 里加入 <code>nonebot.load_plugin("nonebot_plugin_docs")</code></p><p>注意，一定要是 <code>_</code>，而不是 <code>-</code>。</p></li><li><p>启动机器人，加载插件时应当会出现一句 <code>[INFO] nonebot_plugin_docs | Nonebot docs will be running at: http://localhost:端口/website/</code></p><p>有了便是加载成功，没有也没关系，必定会有一大串红红绿绿的错误日志等待着你。回头看看哪里疏漏，修复了就成。</p></li></ol><center>……</center><p><strong>脚手架安装法：</strong></p><p><img src="/posts/41a5/apscheduler.webp" alt="apscheduler" loading="lazy"></p><ol><li><p>举例：定时任务【nonebot_plugin_apscheduler】</p><p>该插件为定时任务插件，使用方式见 <a href="https://github.com/nonebot/plugin-apscheduler">其仓库</a>。</p></li><li><p>进入有 <strong>pyproject.toml</strong> 的机器人文件夹内，右键开启 CMD，输入 <code>nb plugin install nonebot_plugin_apscheduler</code></p><p><img src="/posts/41a5/pyproject.webp" alt="pyproject" loading="lazy"></p></li><li><p>等待安装完成……</p><p>完成后便能在 <strong>pyproject.toml</strong> 里面发现多了一句 <code>plugins = ["nonebot_plugin_apscheduler"]</code></p><p>要是没有也没关系，还是那句话，一大串错误日志等待着你。看看哪里出了问题，修复了就成。</p></li></ol><center>……</center><p><strong>GitHub 下载法：</strong></p><p><img src="/posts/41a5/withdraw.webp" alt="withdraw" loading="lazy"></p><ol><li><p>这个法子的好处是可以自行修改源代码，不过手要勤奋点了。</p><p>GitHub 账号如何注册这里就不写了。<s>喂明明连 Python 怎么安装都写了</s></p><p>举例：Nonebot2 消息撤回插件【nonebot_plugin_withdraw】</p><p><img src="/posts/41a5/download.webp" alt="download" loading="lazy"></p></li><li><p>进入 <a href="https://github.com/MeetWq/nonebot-plugin-withdraw">其仓库</a>，找到上图这个地方，选择 Download ZIP。</p><p><img src="/posts/41a5/zip.webp" alt="zip" loading="lazy"></p></li><li><p>单单解压上图选中的这个文件夹在你的 <code>src/plugins</code> 下。</p><p>解压时如果出现同名文件夹套文件夹，将被套的文件夹移上一级即可。</p></li><li><p>启动机器人，出现 <code>[SUCCESS] nonebot | Succeeded to import "nonebot_plugin_withdraw"</code> 这句便代表成功力。</p><p>没有的话，错误日志.jpg</p></li><li><p><s>如果文件不是很多的话，可以直接复制粘贴文件内容。</s></p></li></ol><center>————————</center><h2 id="事件响应器"><a class="markdownIt-Anchor" href="#事件响应器"></a> 事件响应器</h2><p>事件响应器，或 Matcher，是响应接收到的事件的单元。</p><p>多说不如少做，我们来写一个 <strong>接收到 "hi" 这个词时就作出响应</strong> 的事件响应器吧。</p><ol><li><p>定义辅助函数即可在插件内创建事件响应器。</p><p>不过事先我们得从 nonebot 主模块里导出辅助函数。</p></li><li><p>按照上边的教程，随便建立一个插件，进入其 <strong><strong>init</strong>.py</strong> 文件，写入 <code>from nonebot import on_command</code></p><p><code>on_command</code> 就是这里我们要用的辅助函数，它会创建命令消息事件响应器。</p><p>因为我们要在接收到 "hi" 时就有响应，"hi" 就是这里的命令消息。</p></li><li><p>写入 <code>from nonebot.permission import SUPERUSER</code></p><p>该步骤实际为可选，SUPERUSER 我们在上边配置 .env 文件时有提到过，即超级用户。</p><p>在 Nonebot2 中，超级用户就像是 QQ 群聊中的管理员，享受着高贵的特权。</p><p>被设置了超级用户权限的事件响应器 <strong>只会</strong> 对超级用户账号作出响应。</p><p><img src="/posts/41a5/hi.webp" alt="hi" loading="lazy"></p></li><li><p>写入 <code>matcher = on_command("hi", permission=SUPERUSER, priority=10)</code></p><p><code>matcher</code> 在这里是事件响应器的名称，<strong>可以随便取</strong>，就是在同个文件里不能重名。</p><p><code>"hi"</code> 指定了 "hi" 为命令消息，只有在接收到命令消息时机器人才会响应。</p><p><code>permission=SUPERUSER</code> 设置了超级用户权限，只有在超级用户发送 "hi" 时机器人才会响应。</p><p><code>priority=10</code> 定义了该事件响应器的优先级。优先级数字越小越先响应，以 1 开始。<strong>可以不填</strong>，这边提一嘴。</p><p>和优先级一样可选的变量还有：匹配规则、阻断等等。</p><p>辅助函数大全可见 <a href="https://v2.nonebot.dev/docs/tutorial/plugin/create-matcher#%E5%88%9B%E5%BB%BA%E4%BA%8B%E4%BB%B6%E5%93%8D%E5%BA%94%E5%99%A8">官方网址</a>。</p></li></ol><p>不过现在只是建立了一个 <strong>可以响应</strong> 的事件响应器，处理流程还没写呢。</p><center>————————</center><h2 id="处理流程"><a class="markdownIt-Anchor" href="#处理流程"></a> 处理流程</h2><p>事件的处理流程由处理依赖组成，即 <strong>Dependent</strong>。</p><p>而装饰器能够装饰一个函数，让其自动转换为 Dependent 对象并加入事件响应器的处理流程中。</p><p>装饰器分为：</p><ul><li>handle；最基本的装饰器</li><li>receive；在 handle 的基础上会中断当前事件处理流程，并等待一个新的事件</li><li>got；和 receive 相似但用于接收消息，贴近于对话形式会话</li></ul><p>由于我们的例子是 <strong>接收到 "hi" 这个词时就作出响应</strong>，这里用 handle 装饰器即可。</p><ol><li><p>在事件响应器下面写入 <code>@matcher.handle()</code></p><p><code>matcher</code> 依旧是事件响应器的名称。</p><p>这里的 handle 为装饰器。</p></li><li><p>写入 <code>async def func():</code></p><p>我们定义了一个名为 func 的函数，而在 handle 装饰器下，func 函数已经变成了 Dependent 对象。</p><p><img src="/posts/41a5/await.webp" alt="await" loading="lazy"></p></li><li><p>在 QQ 里面，我们要如何才能知道发了 "hi" 后，机器人到底有没有作出响应？</p><p>我的建议是让机器人也发送什么，比如 "喵"。</p><p>在 func 函数内写入 <code>await matcher.send("喵")</code>，即这个名为 matcher 的事件响应器响应后发送了 "喵"。</p></li></ol><p>到这里，处理流程也写好了，不过还是缺些什么才能作为一个可运作的插件。</p><center>————————</center><h2 id="插件实例"><a class="markdownIt-Anchor" href="#插件实例"></a> 插件实例</h2><p>虽然处理流程写出模子来了，但问题也来了：这么写是 <strong>没法获取上下文信息</strong> 的。</p><p>获取上下文信息的重点就在 func 函数里，该函数需要从 Onebot.11 适配器里导出的 <code>Bot</code> 参数。</p><ol><li><p>分别添加 <code>from nonebot.params import State</code></p><p><code>from nonebot.typing import T_State</code></p><p><code>from nonebot.adapters.onebot.v11 import Bot, Event</code></p></li><li><p>在 func 函数括号内添加 <code>bot: Bot, event: Event, state: T_State = State()</code></p><p>对于更多的参数，见 <a href="https://v2.nonebot.dev/docs/tutorial/plugin/create-handler#%E8%8E%B7%E5%8F%96%E4%B8%8A%E4%B8%8B%E6%96%87%E4%BF%A1%E6%81%AF">官方网址</a>。</p></li><li><p><code>Bot</code> 基类用于处理上报消息、提供 API 调用接口。</p><p><code>Event</code> 基类提供了关键信息的方法，如获取事件消息内容。</p><p><code>T_State</code> 表明了该事件处理状态为 State 类型。</p><p><code>State</code> 则是 Nonebot2 beta1 版本新添的依赖，<code>T_State</code> 必须要陪着一个 <code>State</code>。</p><p>对于我们的例子来说，除了 <code>Bot</code> 实际都是可选项，只是提一嘴。</p></li></ol><p><img src="/posts/41a5/awaitbot.webp" alt="test_plugin" loading="lazy"></p><p>上图便是一个小型插件的完整样貌。</p><p>启动机器人，快马加鞭使用大号向机器人账号发送 "hi"，便会收获一个你自己写出来的 <s>猫咪女仆</s> 聊天机器人。</p></body></html>]]></content>
    
    
    <summary type="html">本文是一篇面向新手的 NoneBot2 (beta1 版本) QQ 机器人开发入门教程。教程从零开始，详细讲解了从 Python 环境、nb-cli 脚手架的安装，到 go-cqhttp 协议端的配置，再到创建并运行一个基础机器人的完整流程。教程的核心部分深入介绍了 NoneBot2 的插件系统，包括如何创建、安装和使用插件，并以一个“hi-喵”的实例清晰地解释了事件响应器（Matcher）和处理器（Handler）的工作原理。本教程为初学者提供了一条清晰的学习路径，帮助你快速搭建并开始定制自己的 QQ 机器人。</summary>
    
    
    
    <category term="编程笔记" scheme="https://blog.cytrogen.icu/categories/%E7%BC%96%E7%A8%8B%E7%AC%94%E8%AE%B0/"/>
    
    
    <category term="Python" scheme="https://blog.cytrogen.icu/tags/Python/"/>
    
    <category term="Nonebot" scheme="https://blog.cytrogen.icu/tags/Nonebot/"/>
    
  </entry>
  
</feed>
