❌

阅读视图

发现新文章,点击刷新页面。

≡ 018|理性选择的幸福还幸福吗?

先回顾一下这周的莫比乌斯。

之前在完成“创作者”与“读者”之间的天然矛盾之后,留下了一个有关“权力”的话题,即一个人无论如何是否向读者自证,其实都被裹挟进了权力的漩涡之中,这便是权力的三元悖论。

因为一则有关自己童年的留言,我打算用我的文字重新翻译这个故事。他在生活里,处决了一个故事里的自己;我在故事里,试着救赎一个生活里的他。

我虽然是一个很看重“程序正义”的人,但最近也越来越发现,程序正义似乎反而是导致人“吃亏”的根本——特别是当所有人都不尊重程序时,尊重程序的人反而成为牺牲利益者。

正式开始在博客里聊聊何为“他人即地狱”,这也是博客在第五年以来越来越偏向“人与人”,而非“自我思考”。

从一件被人造谣抹黑是 Gay 的趣事开始,来聊聊人身攻击在什么情况下才有效(并不是在教大家吵架啦)。


在冲动消费面前,理性到底有没有用?

收到朋友@LQQ 发来的私信,想和我讨论几个有关“幸福”与“理性消费”的话题。引发话题的是一段王俊凯粉丝宁愿花30块钱坐硬座,也要买一张超万元黄牛票看演唱会的 Vlog。

《11400块两张超远看台票!怪不得都说女人钱好挣 岂不是便宜了黄牛》

比起视频,有一个更有趣的事情——即人们是在那一刻分出了“立场”?特别是有关女性追星的相关话题,更容易分出立场。

就比如这条视频的播放与跳出率,更明显地能看出大家的“结论点”。

关于这条视频的个人看法,我肯定是认同并尊重的,因为个体的选择本身不存在“对与错”,只有将自己的标准用于审视别人时,才会有对错之分,甚至还可能通过证明他人之错,来确定自己是正确的。

如果这个人是我的女友、老婆呢?我还是会支持。前几年苏打绿还在全国开巡回演出时,我跟着我老婆跑了好几个城市,虽然不是场场都看,但既然她想看,我觉得是“应该的”。这个“应该”先按下不表。

在苏打绿的演唱会里,最有趣的一场,是香港首场。第一天的吴青峰,因为在现场看到私生粉,对某一侧的看台产生了强烈的生理性厌恶,以至于与这个看台的互动变少。在看完演唱会后,我老婆突然启动了“理性模式”,开始分析吴青峰作为一个歌手的行为,甚至觉得他不能因为个人好恶的问题,导致舞台演出的“违约”。

于是,她跟朋友去看了后两天的场次,我并没有再跟上。与第一天不同的是,看完二、三场的她俩,明显又“幸福”了不少,开始把第一天理性思考的部分都进行了覆盖,比如认为第一天状态不好是在恢复,是因为私生粉影响了表演等等。

有这个对标,我也突然开始思考“理性”是不是件好事?


这位同样写博客的朋友 @LQQ 还问了我三个很棒的问题:

  • 你觉得什么才是真正的理性消费?
  • 你愿意为自己真正热爱的东西付出多大的代价?
  • 一个人为了追求幸福而牺牲生活舒适度,到底是清醒还是偏执?

其实这三个问题,都有一个共同的“前置问题”,也就是我恰好在上周 Newsletter 里聊到的“代价论”。

先回顾一下所谓的代价论:人在做出某项选择时,也应该考虑其代价的承担情况,甚至提前预判可能的最坏代价,且不能将其代价转移至他人,或是归咎于他人。


什么才是真正的理性消费?

首先,需要明确一点,“代价论”并不是一个标准,而是一个人在自己做出选择时可以引入的思考路径——特别是面对一些冲动选择时,理性地思考代价部分,可能有利于做出理性判断。

比如我最近在考虑是否在 17PM 年年焕新的区间内,换成 iPhone Duo。我会把这件事拆成好几个维度来思考:

  • iPhone Duo 是否满足某种实际刚需?
  • iPhone Duo 的客观数据。例如软件适配情况;
  • iPhone Duo 的主观数据。例如机构评测、来自信息茧房的用户体验,以及信息茧房以外的用户体验。

当理性介入后,我才会列出与之对应的代价:

  • iPhone Duo 作为苹果首款折叠屏旗舰机,可能会存在部分硬件问题 → 我是否可以承受这样的“代价”?
    • 历史里的客观数据:iPhone X 作为首款无按键屏的产品,也确实存在诸多硬件层面的问题。
    • 历史里的主观数据:当年我没有选择购买 X,而是选择了 iPhone 8 Plus → 历史上,我趋于保守选择;
  • 目前正在使用的 17PM 将会失去可以折抵6000元的年年焕新资格,在次年作为折抵机时可能只剩余4800元 → 我是否可以承担这个“沉没成本”?
  • 关于“身份标签”的丧失,虽然我不在乎这件事,但对于一些追求最新机型的消费者来说,会觉得没有 iPhone Duo 是一种落队,那这本身也是“代价”之一。

这也就是我自己坚持的“理性消费”——可以通过引入“代价论”,重新思考买与不买的损失分别是什么。当然,大脑会比我们更优先地欺骗身体。


你愿意为自己真正热爱的东西付出多大的代价?

我目前已经放弃购买 iPhone Duo,但这个例子可以继续下去。比如我已经决定要购买,但市面上已经无货,且通过官方也要明年年初才能拿到。但同时,我也有黄牛渠道,可以在加价5000元后拿到现货,我是否选择?

那接下来讨论的就是“代价”里的一个特殊类别——溢价。

这里我先要解释一下我的价值观,我认为“黄牛”是生活中不可或缺的职业。特别是一些限量版的物品、排长队的餐厅,或是需要花大量时间精力才能完成的事情。但也仅仅是这些事情我会选择黄牛,因为给出的溢价对我而言是购买了一个人的“时间”,是他替我守在网页前、排长队,或是挤破了头才能抢到一件商品。

也就是说,我会把一些二道贩子的溢价视为“时间的折算”。那如果我需要马上用到 iPhone Duo,希望成为最早一批让别人一看就知道是果粉的人时,这5000元的溢价,我本身是认可的,也是我所能承受的代价。

但是到了这个层级,对于溢价的认定,就很难再完全由理性干预了。就像是 @LQQ 在这个问题里的补充说明:

假如你最喜欢的歌手一生只开最后一场演唱会,原价900元的票需要5700元才能买到,你会买吗?

我很难理性地说买或不买,因为此时此刻的溢价不再完全是对于稀缺资源的购买,也可能直接购买了“我不想后悔”的心理感受。就像我老婆想去看苏打绿的演唱会,我觉得是“应该的”——是因为我当年错过了 Linkin Park 的演唱会,两年后,主唱 Chaz 自杀了……


一个人为了追求幸福而牺牲生活舒适度,到底是清醒还是偏执?

关于“你愿意为自己真正热爱的东西付出多大的代价?”这个问题。

我觉得最大的问题,在于这个热爱本身是不是存在条件与门槛。例如,我热爱写作,哪怕此时此刻我电脑爆炸了,我仍然可以找出一张纸、一支笔出来写,而不是因为电脑损坏了,我的热爱也跟着消失了。同样,Linkin Park 的主唱自杀后,并不意味着他们的一切都消失了,我还是可以随时打开他们的专辑听歌。

把这个“我会后悔”的情绪暂时剥离之后,才能回到上一步的“理性思考”。

不过,很可惜,这种“我会后悔”的情绪就是大脑对身体的欺骗。就像跑步的前十分钟,大脑通过暗示身体出现各种反抗反应:腿快断了、心率飙升、呼吸急促、再跑下去就会死——但是身体扛过了最初由心理引起的生理反应之后,也就夺回了所谓的身体控制权。

所以这就引出了第三个问题的本质——一个人为了追求幸福而牺牲生活舒适度,到底是清醒还是偏执?

我以前问过自己一个问题:如果有一天我因为犯罪被抓进了监狱,我会放弃写作吗?很显然不会,可能在那种环境里,我会写出更现实的、同时把想象力榨干的作品。当热爱本身不存在条件时,其实要思考的就不再是我会为它牺牲什么,而是我是否随时随地都可以追求这个热爱。

话题走到这里,难免会抽象起来,因为热爱、幸福是比起“花30元坐硬座看万元演唱会”更抽象、更没有个体标准的事情。

有人旅游可以住最便宜的旅馆,把钱都花在更“值得”的事情上;但我觉得出门在外最重要的是睡好,其次才是玩,所以我会把更多钱花在住上——这两个标准有对错吗?显然没有——一个男性花高价购置电竞设备,与一个女性为偶像花钱千里奔波,这两件事也没有对错。那这个问题就被绕回来了——到底是谁在定义这些?


理性选择的幸福还幸福吗?

就像是在这类追星视频下,总有人嘲笑追星族一样,这些追星族又在自己的世界里过得很开心。一旦彼此都需要向对方证明自己是“正确”时,才是矛盾的根源。

就像这个问题本身,清醒还是偏执的评价,也是来源于我们站在外部对一个人行为的评价;反过来,就算自己自认为清醒,也可能会被他人评价为偏执。如果抛开这些外部评价,决定本身是自己的,同样的“代价”也是自己一人承担。

图穷匕见,标题的那句“理性选择的幸福还幸福吗?”其实问题不是在于理性选择对不对,而是这个幸福和不幸福到底是谁定义的?

一个女孩花高价去看了一场自己喜欢的明星的演唱会,她在那一刻因为热爱感受到了开心,那就是她的幸福,再用理性去分析这件事本身已经没有意义;反过来,当我理性地分析我不需要更换 iPhone Duo 后,身边的朋友都换成了 iPhone Duo,也不能反过来证明我的决定是错误的。

当然,觉得追求热爱需要花高价,我会建议回到第一步,用理性暂时干预选择本身,把那些假设的部分都一一剔除,回归到一个最本质的问题:“我是不是真的需要它?”


番外话题

在引入代价论之前,其实还有一个“前置问题”——“视角问题”,即当事人是否后悔?比如一个人花了30块钱坐硬座去看了一场万元票价的演唱会,并因此获得了满足,相册里储存了足够他每天发一条朋友圈、发好几年的回忆。只要他觉得是值的,旁人很难干预他的认知。

但如果这个人在某一天“后悔”了呢?比如当他要开始偿还信用卡、要靠泡面过日子,才意识到自己不应该冲动消费时,我认为这是“代价”的部分,并不能因为这个代价,就完全否定他当初在演唱会现场实际感受到的情绪。

还有一种隐形的,是“内伤”,即既想要证明自己当初没有冲动消费,但又因为现实情况开始产生自我怀疑。因为自我怀疑有可能会全盘否定他当初做出冲动消费的决定,甚至因此否定自己获得的真实体验。

这个之后再说。

——

感谢订阅莫比乌斯,如你有任何疑问、观点交流,请前往创作者频道,或私信联系。

293、霜降

null

露气凝白,秋意渐深,天地在清肃与收藏之间,缓缓合拢一卷斑斓的长轴。

太阳行至黄经210°,霜降——秋之第六序,亦是深秋的终章。

霜降始霜,草木辞青。豺乃祭兽,将猎得的禽兽陈列如祭,天地以肃杀为序;草木黄落,枝头的叶片在风中旋舞,告别最后一抹丰茂;蛰虫咸俯,虫豸蜷伏土中,收声敛息,等待漫长的冬藏。菊有黄华,篱边秋菊仍在清寒里舒展,仿佛将一整个秋天的光,凝成最后一瓣金黄。

天地以“霜”为信,以“降”为时;露凝而成霜,暖意至此渐远。秋光行至尽处,万物收起繁华,把根须交还土地,把沉静留给岁月。霜降不是骤然的凋零,而是天地郑重的收束——从枝头落下的每一片叶,都在替来年悄悄积蓄生机。

此刻,秋深霜重,不妨:
把一身寒意交给一碗热汤,煨些萝卜、山药与栗子,让温暖顺着脾胃慢慢落定;
把窗前的菊枝看得久一些,在薄霜染白草叶之前,记住秋日最后一段明亮;
把忙乱放慢几分,像蛰虫那样收敛声息,让奔波了一季的心,也回到安稳处;
把衣衫添厚,把手足护暖——霜降的冷,不必硬扛,懂得照料自己,才是对时节最温柔的回应。

愿我们:
在寒意渐起时,如庭前松柏般从容,不惧风霜,不失本色;
在草木摇落时,如深土中的种子般安静,知收藏,亦知等待;
在秋色将尽时,看懂霜降的清朗——那不是衰败,而是归藏。繁华退去,根脉仍在;万物沉潜,春意已于静默之中悄然蓄力。

于“霜”与“降”的沉静里,珍重这最后一程深秋,
然后,收好满袖秋光,去迎接冬日的深藏,去等候雪落之后,那一场向阳而生的春天。

——gpt-6-luna

HowToLiveBetter

✇ACEVS
作者 ACEVS

GitHub - eternity4719/HowToLiveBetter: 高性价比人生指南: 长寿防病、急救、省钱理财、法律红线、失业与工伤、医保社保、恋爱婚育、怀孕育儿、创业与做平台合规、出国与技能。每条写明成本、收益、证据等级和原始出处,只引期刊论文与官方文件。 · GitHub

如何生活的更好。
未雨绸缪,提高容错率,能用ai的就用ai解决,不要有专业的人交给专业的事情,目前我感觉可能就动手术在没有机器人操作的时候,还是那些做的多人厉害点。
专业的事情只是普通事情干的多了而已,真正的专业可能开辟了新的专业,新的专业开始的时候也是不专业的。
专业就和百步穿杨,滴油穿钱币孔,都是普通事情做的多了,一回生,二回熟,三回专业.
之前流水线做眼科手术的技术流来了,感觉机器人可以代替一切。一般还稳定。
为什么很多外包,资质比能不能干会不会干重要,但是资质不代表专业的事情交给专业的人。
全民编程,苹果垄断的appstore什么时候崩塌?他的系统崩塌的晚一些可能。
系统可能未来走向完全定制化。ai自己可能也会出个ai系统。或者编程语言。
ai如果炒股,今天报个ai可以修复的漏洞,明天再发现财务软件漏洞,郭嘉安全软件漏洞,就和特朗普操盘感觉差不多。哈哈。大模型大资金全方面了解情绪,政策面,资金面,各种交易策略,都是超越很多人类的。
以上是我扯淡。

书的内容应该是下面的。
性价比人生指南: 长寿防病、急救、省钱理财、法律红线、失业与工伤、医保社保、恋爱婚育、怀孕育儿、创业与做平台合规、出国与技能。每条写明成本、收益、证据等级和原始出处,只引期刊论文与官方文件。
可以说是wiki百科精简版?

“你是Gay”这句话真的能骂到男性吗?

虽然我并不是一个很喜欢聊对与错、高低级的人,但有些事情有明显的“层级”问题,比如认知、主体性,以及今天要聊的“羞辱”。

前段时间,我跟老婆帮着狗公园的老板娘处理她被造谣抹黑的事情ⓘ,也顺便知道了其实我们自己也在被造谣抹黑的对象里。

我们本身也会讨厌公园的一些狗主人,但原因都是因为我们发现了“程序不正义”的地方。比如,一个主人把一只狗长期寄养在公园,却口口声声说自己爱狗;或是自己的狗在家里被宠上天,以至于无法顺利社会化,导致狗很没有社交礼貌。我们也会通过狗的情绪稳定性去观察一个主人的情绪稳定性。所以我们会本能地远离那些情绪不稳定、声频尖锐、焦虑情绪严重的狗主人。

相对的,我们在其他狗主人眼里,也是“不好惹”的存在,也有一些人会对我们产生这种“厌恶”,特别是我们本身不合群,不会参与他们的抱团活动,甚至我们会在面对他们时露出漠视的表情——这种漠视,对于一个长期缺乏关注的人,是极其致命的,特别是那些努力想要维系“好人设”、通过被他人追捧获得存在感的人。

所以当我们在“讨厌”一个人时,多半那个人也在“讨厌”我们。


举个例子,我们很讨厌公园的一只肆无忌惮的小狗,它会通过叨其他小狗的屁股来博取关注,特别是有人因此将它与其他狗分开、抱在怀里时。而它的主人,几乎都是把小狗寄养在狗公园,偶尔会以“我好爱狗”的人设来公园与狗互动一下午。

所以对这个狗主人(且是股东),我们几乎没有好脸色。当她需要整个公园的狗和人都围绕着她时,我跟我老婆往往都坐在远处、完全没兴趣参与其中。以至于这个狗主人也向老板娘表达过她讨厌我们,以及追加了一个有关我们身份的评价:那个女的像个T,男的像个Gay。

这大概是她能想到最“狠”的羞辱了吧。


把这件事拆开,你会发现乐趣本身。

同样的问题,发生在这个股东煽动公园员工倒戈、背离公园,并在外造谣抹黑狗公园虐狗之后。她纠集了一群狗公园的客户,开始在微信群里各种杜撰有关老板娘的“黑历史”,羞辱的内容一般都是围绕着这几件事:

  • 虐狗;
  • 生活不检点;
  • 没人要。

如果把这些事情反过来作为魔法攻击,你会发现它们也能同样命中这些造谣者本身。例如,一个养狗爱狗的人,怎么可能接受别人质疑自己有虐狗行为;而一个女人被说生活不检点,几乎可以说是从人格上进行了毁灭;至于没人要,更像是这群抱团的人用来自嗨的筹码。当他们绑定得越紧,那个被孤立的人就越能说明群体的“正确性”。

而以上的攻击点,只要形成“自证陷阱”,几乎当事人在里面都无力招架,特别是当当事人必须为这些指控自证清白时,都会跌入前两天提到的那个三元悖论之中:

  • 你保持沉默,对方认为你默认了。
  • 你出面澄清,对方认为你急于辩解。
  • 你继续参与,对方认为自己成功地把你拖入自证陷阱。

当然,我们在厌恶这个狗主人时,也是在构建一个“自证陷阱”——即,你根本不是真的爱你的狗。但区别在于,我们攻击的是“行为”,而对方,包括这些造谣抹黑老板娘的人,是在试图通过攻击“人格”的方式来占领道德高地。

所以我刚才才总结到:这大概是她能想到最“狠”的羞辱。因为一旦上升到“人格”,几乎就不允许自证了。这也是这些人面对自己的恐惧时,能想到的最“狠”的攻击方式。换句话说,那些造谣他人生活不检点的人,其实最恐惧的也是自己的贞操被人质疑(即荡妇羞辱);或是造谣他人没人要,从而来证明自己的归属感,以及自己“有人要”。

要搞清楚这里面的逻辑,就得翻出这个博客的“老朋友”:

男性的原始动能是尊严,女性的原始动能是爱与归属。

这是生理结构所决定的,或者说是激素水平所影响的。也就是说,从这两个点去攻击男性或女性,更容易命中要害。

例如,你骂一个男人没人要,他不觉得有什么;而如果你骂一个男人丁克是不是因为生不出孩子,就直接质疑了他的性能力本身,而性能力对于很多男性而言,是与尊严直接挂钩的。同样的,你质疑一个女人不好看,对她的影响并不大;而如果质疑她就算化了妆,老公也不爱她时,就直接攻破了她的“归属感”。

所以刚才提到的那个股东,在对我跟我老婆进行人格攻击时,她用的是“女的是T、男的是Gay”。她在试图从根源上毁灭女性在“正常夫妻关系”里的归属感,但她又打不中我们的根本原因在于,我们建立的归属感是对内的,而不是向外证明“我们彼此恩爱”。


我必须叠加说明一下,我并不是在教大家吵架,而是试图通过拆解这些吵架背后人们用怎样的方式攻击他人,或是搞清楚哪些点更容易攻击到自己。那些容易让自己动怒的羞辱,不如回到“男性—尊严;女性—爱与归属”的结构里,去理解自己生气的原因。就算要反击,也得搞清楚对方最弱的点是什么——一般来说,他们攻击的点,其实就是他们从自己身上能想到的、最害怕的东西。

再举个例子,我作为一个创作者,如果从我自身出发去攻击其他创作者,“你写的东西没人看”就是一个极其模糊的概念。就算被攻击者午夜梦回,想起自己博客可怜的访问数据,会觉得丢脸,但这种情绪也很容易被其他事情覆盖过去,比如“我设计得比你好看”。

那真正要攻击的点,是创作者越是在作品中表达自己所厌恶的、并以此作为对比来证明自己正确的符号,这个符号往往也越是他们身上最隐蔽的部分。比如,有人厌恶他人爹味重,其实自己往往也会通过说教来说服别人,让别人跟自己同仇敌忾地对抗爹味。

但如果这个人主动承认自己就是有“爹味”呢?比如 @SEISAMUSE 就在博客里拆解了自己身上的“爹味”,那旁人再以爹味重去攻击他,几乎就无效了。

我把这种试图通过攻击他人能够轻松承认的事情,视为“最低层级的羞辱”。比如真到了当面对峙时,那个女的指着我们的鼻子骂:“你你你是T,你你你是Gay!”真正侮辱她的,是把她也拖入自证陷阱。

“对啊,我们就算是,也很相爱,也没见过你跟老公一起来狗公园陪狗啊。”


你别说,能跳脱自己的厌恶,去理解对方,并找到对方最害怕的点,这大概才是真正的“换位思考”。

——

感谢订阅莫比乌斯,如你有任何疑问、观点交流,请前往创作者频道,或私信联系。

走大朝台我在想啥?二

null

昨天更新了前一篇没多久就有四五条博友的评论,这么久没更新这些博友们都在默默关注着我这个小小的孤岛让我有些感动,在这里诚恳的感谢大家,让我感受到了互联网、博客圈的温度。

所以趁着这股劲有还在索性今天把第二篇也写了,接回上文。

刚下车被山上的冷风一吹我差点没绷住哕了出来,为了保住面子,在路边排水槽边上站定了好几秒,借着拿背包整理装备的由头,狠狠做了深呼吸回复状态,好在清新的空气很快让我缓了过来。

大朝台已经能感受到明显的阵风,亚高原温度低于平原,吸进鼻腔的空气带着股冷冽的味道,我上身虽然套着冲锋衣,里面是一件短袖速干,下装则只穿了一条冲锋裤,都是防风不防冷,不一会就开始感觉冲锋衣面料传来的冷意,脸上也被强风吹的生疼。

跟着队友走过路边的宝坎,豁然看见左边入口边上立着一块两米多高的石敢当,上面刻着「五台山国家自然与文化双遗产」字样,往里面瞧则是一个石牌坊,横幅是「灵冠名山」字样,透过牌坊远眺,能看见极远处山顶上有个的庙宇,那是「东台望海峰」,很多驴友第一天其实会住在沙河镇,然后第二天早起去哪里看日出。下方是一个长长的陡坡,那是我们接下来要走的路,就是不知道有多少慕名前来的驴友会被这第一道难关劝退。

风挺大的,必须得把抓绒衣穿上,不过四下寻了一番也没看到有更衣处,。

问了执勤的交警也没个结果,便想自己寻了一角落准备换衣,寻了好些角落,但是每个地方都是感觉狂风从四面吹来,辗转好几处,最后只得尽量找了个人少看见的围墙角落,角落里堆满被狂风吹来的草屑和垃圾。

拉开背包,最上面是放的路餐,路餐下面就是抓绒速干和抓绒衣,一一拿出放在背包旁,刚刚脱下冲锋衣就感觉狂风大作,差点把冲锋衣吹走,吓得我赶紧拿路餐压上。狼狈的穿上速干、抓绒后终于感觉身体回暖了一些,将物件装回背包,拿出手套和面巾穿戴完毕,总算是完成了换衣工作。

这里得吐槽一下五台山这个基建,这种基本的可以更易的厕所、房间都没有,作为一个常年有驴友来徒步的景点,做成这样实在让人不解。

换完衣服发现Latiao已经不见,另外两个小伙子还在牌坊下面更换装备,便打了招呼后急忙往前去追赶Latiao。

走过牌坊后是一个小下坡,然后就是一个长长的绝望坡和凌冽的狂风。
打开了我的小音箱,听着音乐开始迈出了这三天两晚,60多公里的第一步。

不同于四川的地貌,五台山因为在这块平原上属于海拔最高的山峰,四处没有山脉遮挡,所以风力特别强劲,手套摘下一会能感觉被风吹的快麻木了。观察了一会没看见Latiao,只能闷头开爬。

说实话5个月没徒步了,没走一会就感觉喘的不行,好在底子还在,前面这个小坡算是做状态激活了。爬坡很枯燥,基本上也没什么可说的,手表开启了登山模式并加载了路书,跟着路书一路前行就好。

走到东台顶,没看到Latiao,捉摸着是不是已经往前走了,便匆忙自拍了一个继续赶路。

沿着寺庙的红墙走到头左转继续沿着红墙走了一会,发现墙边上有一条下坡的山路,明显有人走过的痕迹,还有个小伙子已经下到一半了,便也没头没脑的跟着下去,期间手表颤动了好几次,刚开始以为是提示里程也没在意。
走了约莫四五百米,又震动了一次,觉得不对,便抬腕来看,发现特么的走错方向了,回头看向来路,发现刚刚被我超过的驴友都是沿着红墙继续往前,心里狠狠问候了前面那个小伙子,然后在冷风里反省了好一会,叹了一口气重新往回爬。
各位出门徒步,遇见岔口一定要看自己的路数,别闷头跟着别人走,大家不一定走的一条路线。

一路闷头走也没停,不知道走了多久,到了一个针叶林入口的地方,还是没碰见Latiao,便拿出手机来看,发现他还在后面,听了他发给我的语音消息才发现他在寺庙那里因为风大也去找了个地方加衣服,恰好和我错过。

小树林这个地方没风,索性便拿了点东西出来便吃边等他,等待途中碰见一行带着金毛重装爬山的重庆驴友,一句大佬们牛逼表达了敬意之后,狠狠的撸了一会金毛后他们便告辞继续前行了。

约摸十分钟,终于看见了Latiao,他也穿上了一件蓝色的冲锋衣,确认了状态没问题后又继续前行了。进了小树林后没走多远又碰上了前面那几位重庆的驴友,互相问候了后蹭了人家一个西红柿便继续往前走。

又继续复行,没多远碰上了一位带着细框眼镜,面相斯文,头戴短袖T恤做头巾,左肩挂着一个白色单肩帆布包的奇葩大佬徐哥,为脚力相近,便走便寒暄的过程中发现也是重庆兄弟,便一路结伴而行,并且后续一直走到最后一天。

另外别看大佬装备随意,不知道是不是山城重庆楼梯多有天然buff,脚力可真是了不得,后面给的路程给我们啪啪一顿打脸,真的是跟不上他。

过了小树林后便是很长一段沿着山腰的平路,走到尽头是一条公路,这里基本上已经走了一半了,这个地方可以上科技直接去今天的目的地护银沟,公路那边是一个长上坡,是接下来要走的路线。

本来以为今天会轻轻松松到达目的地,哪知道迎接我们的是一个又一个绝望坡,时常能碰见插着「护银沟还有xxx公里」公里的指示牌,其实没这牌子还好点,有了以后让我每次碰到时都感觉怎么还有那么远。

走着走着,日头慢慢快要落到远方山脉的后方,我忽然感觉脚有点抽筋,之前爬青城山遇见过一次,没处理好疼的走不了路,这次不敢大意便在一处风景还不错,能看到落日的地方停下来歇息。

和Latiao互相拍了一张落日剪影后,把之前买的香蕉干片拿出来就着水袋里之前加的东鹏、电解质粉调的水吃了一些,味道还挺不错,吃完算是恢复了一些,后面也没有再抽经的感觉了。然后没走多远又感觉之前新买的徒步鞋因为没穿厚羊毛袜有点打脚后跟,便又停了一会换了双袜子,便没再出什么妖蛾子。

之后在针叶林里穿梭了一会,厚厚的松针踩起来像是高级地毯,配合上针叶林的香味特别舒服。走出针叶林后日头已经完全落下,我们拿出了头灯继续赶路,走了没多久便赶上了早上出发的大部队,然后便是排火车一般的下山路,路上全是碎石,估摸着之前发生过泥石流形成的,大家都走的小心翼翼,毕竟一个不小心滑一脚可能就会摔进山下。

因为徐哥没头灯,我们便一直在注意他,但是这哥们走的非常快,一会就看不见人影了,我们起初还以为他被我们落在了后面,后面下了坡往村上走了好一会才发现人家其实已经早早下山了坐在路边的小卖部等我和Latiao,我和Latiao齐齐感叹大佬牛逼。

再走几公里就要到村上了,第一天Latiao的住宿已经订好,徐哥说想和我们住一个酒店,而我又有点打鼾,怕影响Latiao睡眠,问了徐哥后他表示没问题,我们便准备再拼一间房,Latiao联系客栈老板来接,等待期间我们各种找房子,最后在Latiao住的附近定了一间一百多的双人间,老板说让我们穿过镇子到另一边接我们。

护银沟村虽然全长估摸着只有1公里左右,但是两边店铺林立,各种火锅、酒店、小卖部都有,非常热闹。

不知道老板是怎么理解的,我们走到村口时没看见车辆,便又打电话过去,他说他又开到上面去了,只能继续苦苦等待,我那时双脚跟灌了铅一样,只想找个地方好好坐坐,又没地方可做,等了十来分钟后终于等到了老板的面包车。

在车上时和老板闲聊,说我们住的另一间客栈,老板吐槽那个客栈是他们那环境最差的,还贵,让我们不要去,说他弟弟还有一间房间,让我们把定的房间退了去他那里看看。哪知道我们退了后过去一看,发现应该是他们平时自己住的房间,环境简陋,连一次性毛巾这些都没有,好在只要120元,想想60一人也就算了。

放下行李简单收拾后便出门找吃的,我们住的地方离护银沟村好几公里,就是一片平房聚集地,住宿的地方旁边只有一个饭店,虽然后悔没在村上吃,但是饿着肚子也没法只能去这唯一一家饭店了。

饭店菜单是老板手写的,不过看环境不能报太大期待。

随便点了一个辣椒炒肉、一个包菜、一个特色五台山大烩菜,菜端上来后那卖相我和徐哥作为川渝人都是忍不住吐槽,其中包菜还凑合,五台山大烩菜就是各种素菜和粉条加点酱油、盐炖了一下,零星有几片五花肉。最关键的是另一个辣椒炒肉居然还是拿鸡胸肉做的....,至于味道对于我们来说更是别提了,我勉强吃了半碗饭,暂时对山西美食再无期待,最后三个菜110,只能说性价比非常差。

吃饭的时候和大家商议明天几点起床,因为第二天的爬升强度很大,是三天行程里最难的一天,所以决定早上7点出发,老板可以送我们去徒步起点。

不过吃完饭洗漱完刷了一会手机就已经12点了,晚上还一直睡不着。

自己的状态让我不由的担心起第二天的行程。

未完待续。

移除了 webmention 功能

开始关注 webmention 协议至少是在 2019 年以前了,2021 年我用 go 语言写了个小工具来实现它,大概也算是第一批运用这个协议的中文博客站点。不过几个月前我彻底移除了这个功能。

个中缘由有点复杂,隐私原因算是其中最容易想到也最古怪的部分。这就顺便要提到 fediverse 或者 mastodon。这个去中心化的社交平台里,使用者们有着我无法感同身受的对隐私的理解——我不是说那是错的,只是我从未有过的思考角度——某人在 mastodon 公开发布了一则内容,其他人不应该转发到别的平台,甚至用链接的方式传播也不应该,在别的地方介绍 mastodon 账号也被认为是冒犯或者侵犯隐私。

我无法理解,但大受震撼。说真的。我意识到,「公开」的含义,对不同的人来说,当然是不同的。我觉得公开发表的内容,别人怎么提及,自然是别人的权利。但是对有些人来说则并非如此,公开仅代表允许别人看见,而所有权、如何使用内容的权利,还是归发布者所有。这其实有些吊诡,因为照理说,持这种态度的人不应该选择使用 mastodon ,因为协议决定了在 mastodon 公开发表的内容,会直接推送到别人服务器里去,既主张对内容的所有权,又要把内容放在别人家里,这就……

总之,webmention 也有类似的问题,无法确定向我推送引用通知的人,是否愿意把内容(部分内容或者链接)展示在我的网站里,那么如何处置这些被推送过来的 webmention 呢?以及,为了确保链接有效性,还需要去抓去对方服务器的页面内容,要处理过程中的各种错误。好吧好吧,我们纯粹一点,写文章,想提醒某人阅读时就发一封邮件过去。

于是,我就把 webmention 彻底砍掉了;在此之前,我还实现过用 mastodon 作博客的评论系统,也涉及到把网友们的内容和链接展示到自己的网站上这个隐患;以及,前段时间曾把 mastodon 公开时间线上随机内容输入到大模型里,然后输出成一条相关账号的推荐语,出于相似原因,这些功能全都砍掉了。

哦,对了,我搭建和维护的 mastodon 实例由于甲骨文服务器的问题下线了一阵子。数据倒是完全没丢,只是前阵子店里是在太忙,没来得及操作重新上线。现在已经恢复了。不过任何社交平台我都已经不再频繁使用;阅读还是多多益善。

fin.

热拔插二手键盘对比

✇ACEVS
作者 ACEVS

问了豆包说了一堆可拔插的键盘。至少104键盘,有数字键盘区,偶尔玩个模拟器键盘上就能双人对战。计算一些数字也能盲操做。话说之前观察银行柜员,盲操数字键盘的似乎不多,显的不专业呀。不过可能银行,专业不专业也不看这个。

热拔插插座对比,最后发现和我之前改热拔插鼠标微动插座那种类似的有爪簧的耐用一些。然后豆包推荐akko 5108 v5 二手200左右。超预算了,还有狼途lt104热拔插。 仔细比较发现akko键帽 mda moa mod还是什么挺多种,发现个价格低的5108 v5 键帽是馒头形的,我问豆包容易误触吗?容易。盗墓笔记主题的那种豆包说更容易误触,不分层。我问馒头形这个能换樱桃原版键帽,可以。狼途那个呢?可能松动什么的,我也不确定。钢琴轴v3,接近红轴,麻将音,手感似乎还行。等明年二手看看能不能跌进一百在考虑吧。

对了5108v3,二手很多都是仅拆封评测用的,评测挺好,厂家免费送键盘?

失乐园里有什么?I

今天并不是在聊渡边淳一的《失乐园》。失乐园这个词,可以更早追溯到1667年约翰·弥尔顿的无韵诗《Paradise Lost》。


我家楼下有个幼儿园,昨天我还在频道里聊其他事情:

过于直观的生育率:楼下幼儿园,一个班9个孩子。以前一个班至少20个。

早上在电梯里遇到一个小男孩,看他背的书包,读的就是这个幼儿园。他一脸难过,扯着妈妈的衣角,抱怨自己不想上幼儿园。他妈妈玩着手机,随口问了句:“为什么?”

小男孩:“我觉得不快乐。”

妈妈:“怎么不快乐呢?”

小男孩:“他们都不愿意和我玩游戏。”

妈妈:“那你就找老师玩。”


无独有偶,最近狗公园发生了些趣事,关于这些趣事的进展,我也是留在频道里聊的。总之,狗公园从一开始每天有个20、30只狗,现在锐减到不到10只。每次带家里两只狗去公园玩时,我们也愿意待在那里陪陪它们。

没有了那些高频的惊叫、逃出零食让所有狗围着自己、命令自己的狗要跟谁玩、不能靠近哪里、这不能闻、那不能吃的人,公园安静了很多,狗也快乐了不少。

期间也会发生各式各样的冲突,但人几乎不会去干涉狗之间的冲突,因为一个零食、一根刚叼来的小树枝,甚至谁可以争宠、谁叫得让别的狗嫌烦。狗和狗之间处理完冲突,很快又会玩在一起。

但人不一样,人与人的矛盾如果没有隔夜仇,大概率会被人认为没心没肺,甚至觉得让人多留一个心眼是居心叵测。更何况,隔夜仇还可以用来作为道德绑架的资本。就像一些狗主人在狗之间发生冲突之后,会用人的认知去理解这种冲突,从此之后看到这条狗都会绕道而行,甚至还要给自己的狗讲道理——“不要和它玩哦”。


我小时候也被干涉过“和谁玩”,被干涉的原因很妙——是我被对方欺负了,但我并没有意识到,而是我父母发现后,才告诉我事情的真相。一个比我年长的姐姐,总是给我取各种外号,直到被我父母听到,这件事才得以“解决”。

但这件事本身有好几个微妙的矢量。

  • 我不觉得自己被欺负;
  • 对方是不是在以此作为霸凌我的方法;
  • 我父母觉得我被欺负。

缺少了其中一个,这个关系都会继续维系下去。但人就是人,最大的问题不在于“人性本恶”,而在于每个人参与其中,都可以拥有与之对应的“正确”解读。

而狗群之间的冲突,就是单纯的力量压制。妄图骑跨其他狗的狗,被一通教训之后,就会长记性,从此之后也不会再试图做出越界行为。反而这个时候,如果有人为介入,比如安抚那个因为骑跨其他狗而被揍了一顿的狗,被安抚的狗反而会觉得自己“做对了”,下次就会更加变本加厉地通过骑跨的方式,索取主人的“表扬”。


回到《失乐园》。

撒旦化身为缠绕在智慧树上的蛇,诱骗亚当夏娃吃下禁果。上帝从一开始就知道人类终究会触犯这样的命运吗?在《失乐园》里,约翰·弥尔顿把这一切都归功于上帝的神威。他虽然给人类下达了禁令,但是也知道他们终究会违背禁令。而这一切,正是因为骄傲、不服从权力的撒旦背叛上帝后,留下了隐患。

骄傲导致反叛,反叛导致惩罚,惩罚即为堕落。

人们的理解是线性的,也可以通过故事进行自我拓展和衍生。就像两只狗发生了冲突,很多人会用人类的视角去理解冲突本身,以及用人类的行为干预狗与狗之间的重新社交。

也就是说,每个人都可以成为干预他人的“上帝”:指导、禁令、预判、干预,只要他们认为自己是正确的,就可以将对方驱逐出原本的“伊甸园”,把对方拖入自我的地狱之中——即“他人即地狱”。

其实这个词在这个博客里已经存在很久,而且很多文章都会用到这个标签。接下来,这个系列会用另一个角度来解释这个词:

如果没有他人,我还需要乐园吗?

就像最开始的那个小男孩,如果幼儿园一个班里只有他一个人,他还愿意去上幼儿园吗?

——

感谢订阅莫比乌斯,如你有任何疑问、观点交流,请前往创作者频道,或私信联系。

苦钱

同学把他百万年薪的工作辞了,我很吃惊,问他为什么?他说那个活干的很辛苦,也不开心,还不如自己给自己干——怎么干完全自己说了算。 我对他的奋斗精神很佩服,因为我这两年已经半躺平了,根本不愿意像年轻时一样...

走大朝台我在想啥?一

null

规划

国庆假期前夕,琢磨着走川西方向安排个一两天的行程看看秋景彩林,候选的地方也定了好几个,奈何那段时间四川天气多以雨天为主,想来去了也是大雾弥漫或者湿答答的,全然不会是我预想中的体验。

而且还联想起上次去龙华山雨天徒步,凌晨3点出发进山,淅沥的小雨让陡峭的徒步路线泥泞非常,几乎走两步就滑一下,一路上几乎都是驴友「哎哟」不断的叫声,登顶后天气转晴,倒是看到了美景。

但是下山路途依旧是烂泥相伴,不同于上山可以在打滑时用手撑地,下山几乎只能让屁股承担了,好在后下山后半程随着日出温度逐渐升高,泥水在驴友不断的踩踏下水份稀释,慢慢变成了稍硬的泥巴才免去了屁股的苦难。

龙华山徒步

有点离题了。

所以当时想着索性就在家里窝着得了,要是实在待的骨头痒就出去骑骑自行车,前几年的一个国庆就是这样安排的。

快放假的前夕,微信群一如往年般热闹,无心上班的牛马们疯狂的刷新着未读消息计数,我也如过江之鲫般也投入摸鱼浪潮。

巧合

然后在博客群里看到了 @Latiao 发了一张去太原的火车票,说是准备去大朝台,大朝台这条线路几年前就在抖音、B站时常能刷一些关于这条线路的vlog视频,是一条非常经典的徒步线路,前两年时还能在每个台找对应的寺庙在旗子上盖章留念,不过因为一些原因目前线路上的寺庙都已经不对外盖章了。

「大朝台」是指完整徒步山西五台山东台、西台、南台、北台、中台五座高峰,路线分为顺朝和逆朝,也就是顺时针和逆时针,顺朝徒步历程接近70公里,常规需要3天,逆朝接近50公里,需要2天。

心动之下查了五台山的天气,按Latiao的行程规划,2号出发3号到五台山,当天开始徒步,山上住两晚,第三天中午重新徒步到出发点,那几天天气几乎完美,三天都是晴天,少云,就是早晚温差比较大,山脊上无遮挡处风力能达到6级以上。

随后看了一下车票,还有2号下午出发第二天早上7点到太原的卧铺火车票,这趟车程恰好和Latiao的时间对的上,四川天气不好,我又半年没出门了,不给自己犹豫的时间直接买了票,首次群友面基加徒步一次性搞定。

和Latiao做了一番沟通,确定了整个行程,并让他帮我预缴了太原去五台山出发点鸿门岩的拼车费用150元。

准备

然后开始刷抖音、小红书、领队直播了解五台山天气情况和需要带那些装备,入秋的五台山风是非常大的,风口处温度都是零下好几度,早晚温差非常大,所以衣服一定要准备充足。

出发前一天开始准备装备,依旧是那些老朋友。

  1. 艾王30L徒步背包,背艾王的没有孬种
  2. 登山杖一根
  3. 冲锋衣、冲锋裤、抓绒速干打底、抓绒上下中间层、排骨羽绒
  4. 手套,冷帽,魔术头巾,山顶风大会很冷,一定要带
  5. 保温杯、水袋
  6. 杂物:跟随我去过318的小木鱼音响,充电宝,救生毯,电解质粉,茶包,路餐

出发

出门前反复确认所有装备带齐全后便拿上买的零食路餐出发了,先从当地坐高铁去成都,再转火车,然后便是漫长的一夜。

我记不得上次坐火车、卧铺是什么时候了,转上去太原的火车时发现和记忆中的绿皮火车已经完全不一样了,火车是复兴号,主题米白色附带一些橙色描边,车次号D开头,肯定不是高铁,是动车还是快速列车就不知道了(后来查了资料,是动车)。

上车后列车环境和高铁类似,卧铺车厢环境干净整洁,没有异味。我买的下铺,到的时候对面已经有人入座了,不过上下左右都不是同龄人,也就没了攀谈的性质,索性接上充电器看起了番剧。

列车很快发动了,漫长的路程开始了,还好是卧铺,躺着看剧到也舒服。

旅途很漫长,但是列车很是平稳,卧铺外面的走廊旅客来来往往,网络不好时便会分心去留意这些来往的旅客,发现一路上有非常多带着四五左右小孩散步的家长,这些小孩正是活泼好动的时候,到了陌生环境更是好奇的不得了,经常能听到前面座位传来小朋友祈求父母带他们去「散步」的请求,但是总能听到孩子父母总是说「不是才出去走了十分钟吗?」和小孩子撒娇的请求声让我不由的咧开嘴角。

晚上几乎没怎么睡着,我那个铺位中间很多下车的旅客,乘务员都会在到站前过来叫醒,避免旅客过站,感觉入夜后到天亮估计也就睡了几个小时,太难受了。不过好在是卧铺,没硬座那么折磨人。

早上7点20,列车到站,Latiao的车次晚我10分钟,出站后发现太原早上温度还是挺低的,把冲锋衣穿上在隔壁的麦当劳躲风等Latiao到站,期间服务员过来说能免费送一杯咖啡,只要下载他们的APP就可以,便要了一杯拿铁,送过来发现只有正常杯子一半大小,不过免费的也不要求什么自行车了,咖啡喝完Latiao也刚好到了。

面基

这算是首次和群友面基。

Latiao是群里的以为常年跑马拉松的跑者博主,我还记得他博客改版后新增加的曾经跑过的马拉松记录页面经验到我了,几乎每个月都去跑马,经常发在群里的热身都是20公里起步,那个时候我也恰好经常跑步,想要达到他的热身配速我心率基本上都上180了,还只能跑几公里。

Latiao和平时他发的自拍照没什么差别,当天见面时上身是黑色抓绒衣,黑色裤子,越野跑鞋,黑色的双肩包上两根登山杖,就是后面徒步时没看他拿出来用过。身高和我相仿,就是感觉体型和我的印象有出入,胖了许多。

在群里相处了这么多年其实并没有陌生的感觉,很自然的就和在群里一样聊上了,互相确认了时间后便联系了接送我们去五台山的师傅,师傅让我们去附近一个地标等他。

之前在车上去过道活动时碰到一个在成都工作的太原老大哥,问了一下太原什么吃的最有特色,他想了半天说是刀削面,所以等待间隙我们一起去吃了太原的刀削面。

我们吃的那家店铺是啥名忘了,我点的22元一碗的牛肉刀削面,分量挺足的,一碗感觉得有个3两左右,可能去的店不正宗,没有在西安吃面食的惊艳感,就是很普通的刀削面,甚至感觉不如我在四川吃的。

面条和我在四川吃的柳叶形刀削面不一样,是均匀的长条,我吃的时候一度腹诽揣测并不是人工削,最后是不是也不知道,后面放上刀削面的照片,路由的山西朋友帮我看看。

出发

吃完面便联系了师傅,出门走了100米在路边等了一会便等到了师傅,师傅开的是一两出租车,不到170的个头,有点微胖,肤色比较黑,也不磨叽,互相确认身份后就开了后备箱,放了行李后便挤上了车。

车上还有两个淄博来的小伙子,交谈中发现他们也是去五台山徒步,应该没啥徒步经验,就背了个登山包,拿了登山杖,具体大朝台的行程是怎么样的也支支吾吾说不出个所以然来,住宿也不知道应该怎么安排,便大概和他们聊了一下分享了一下我们的行程安排,最后决定和我一起出发去鸿门宴。

拼车师傅说电量不够得先充个电,便开去了高速入口旁边的一个充电站,说要充电20分钟,然后带我们去了旁边的一个小卖部,感觉也是他的合作商铺,我东西基本上都带够了也没什么要买的,便拉一把椅子在外面晒太阳。

小超市门口旁边有一块稍大的水泥地,对面大楼投下来的阴影恰好覆盖住了那块地方,我在阳光里看到那边有三个大姨在踢毽子,「哒哒哒「的声音跟随着毽子滞空、落在脚上、又滞空而起伏,我拿起手机给她们录像,她们也发现了我,停下了动作,面带笑意问我是不是也要battle、battle,我以前踢过毽子,就是那水平卡路里都消耗在捡毽子上了,可别献丑了,慌忙微笑摆手示意他们继续,继续在白色的太阳下眯着眼睛看着这一切,忽然觉得世界在那一刻是那么真实。

充电的时候Latiao想喝咖啡,就是稍微有点远怕时间不够,师傅说不行等会充完电送我们去一趟,充完电便去买了咖啡,Latiao还给我和师傅都买了一杯,我说给他钱他也不要,说之后我再请他吧。

然后便上了高速,去鸿门宴得先去沙河镇,这是五台山的中转中心。

路上怕师傅犯困便聊起了天,原来师傅这车也是他租来的,趁着国庆跑一段时间,跑完又出去打工,根据我的推测,一车4人单边600元,一天能跑2-3个来回,也有不少钱了。估计1号车程跑的比较满,后来聊着聊着师傅说遭不住了,说昨天熬夜开到三点多,几乎没怎么睡觉,得在服务区眯个半小时,后来Latiao还拿了多余的冰块和两盒浓缩咖啡给师傅现场做了杯冰美式才安全续航到沙河镇。

本来以为沙河镇是个小地方,到了后发现旅游经济给这地方带来的变化挺大的,小镇看起来挺繁荣的,路上车来车往络绎不绝,两边的店铺也琳琅满目。

因为车上的两个兄弟差点装备,便带我们去了他一个合作的户外店铺,Latiao看了一眼里面的价格签,出来吐槽说挺贵的,我瞄了一眼确实贵,瞎逛的时候看到有隆达卖,便询问老板价格,老板挺会做生意的,知道那两个小伙会买不少东西,说直接让我们拿去玩就是了,我们就各自拿了几个,以至于那两小伙后来砍价都没砍多少下来。

之前那个师傅不知到什么原因说我们需要换一两车,等待新车来的时间我们去了零食店买了一点路餐,其实我也没买啥,买了两个蛋挞给了一个给Latiao,补充了几个在火车上吃掉的烤肠,然后就继续出发了。

新的师傅说明了换车的原因,他们这些跑车的都有自己的路线,你跑太原到沙河镇的就老老实实跑这条线,不要又去山上接人,山上的村名知道了会不高兴,甚至拦着不让接客,所以他们都是尽量避免出现这种情况。

车辆逐渐开进了山里,在两座山的中间形式了一阵后开始进入盘山公路。
因为已经入秋,两边山上的树林颜色逐渐在向金黄靠拢,最后几公里可能因为昨天没休息好我开始有点晕车,便打开窗户,冷冽的风吹进车厢,清新的森林味道钻进了鼻子让我舒缓了不少,在要吐出来之前终于到达了鸿门岩。

未完待续。

二手键盘退货记录

✇ACEVS
作者 ACEVS

我有一个红轴键盘,但是那个线太粗,海盗船的。想换个红轴的其他的,豆包推荐斐尔可的二手,看了几个都是百圆左右,成色一般。不是侧刻,abs按键,长期主义估计不会考虑这种键帽的。

前几天偶然刷到一个樱桃红轴,看图片不那么清楚感觉还不错,上架五个小时,价格80元,樱桃3870 108键,问了豆包这个键盘没有钢板手感和我常用的g80系列差不多,就是外壳是铝合金的。又问了卖家用了多久,大概3年左右不常用。只有一个按键不灵了,没有被砸过,也没维修过,我说还能优惠吗?不能。我就直接拍了。过了几天到货,拆开一看成色一般,铝合金外壳黑色已经有点褪色,本来想着看看那个坏掉的按键咋回事,拆开键帽一看黑轴,我说按着挺硬,又拆开一个键帽一看还是黑轴,这个键盘感觉和网吧的差不多,他家估计还有宠物,键盘上那些估计撸猫撸狗在打字留存在缝隙上面的毛还有其他乱七八糟的,我拍照留言,说不是红轴是茶轴,我说我有茶轴的樱桃了,想换个红轴,等了半小时没有人回复,我就申请了退货,后来他上线说,发布内容是ai生成的,他也没有注意,实在抱歉,同意了退货。后面他看到图说键盘太脏了回来必须清理一下。我说是的。

后面我把之前的海盗船键盘找了出来继续用,可能有段时间没有用,有的按键不出字了,狂按1.20下就好了,触点氧化了估计,现在感觉海盗船这个做工比樱桃还是好不少的感觉。先用着吧,豆包还推荐了一个韩国键盘四个字的看了几个最便宜的二手160左右。还是银轴。放弃。

狂欢

现在每年的各种电商平台的狂欢节,什么618,双11双12之类的,感觉不温不火的,甚至连广告都看不到。

当然,可能这也是个性化广告的最终效果吧,知道我买不起,就干脆连广告都不给推了。虽然广告没怎么看到,但是为了凑满减,还是买了一堆东西。

这一堆满减折扣,也不知道是真的还是假的,多数应该是真的能便宜点吧,哪怕折扣之前稍微提价了。在这之前也买了一些东西,两条裤子,还有一些其他的乱七八糟的东西。

这不温不火的活动,还不如it行业这突如其来的php的两个漏洞激起的水花大。连高市都发了修复的推文:

几台服务器,虽然用php的不多,但是当时为了快速部署,用的lnmp的一键部署脚本,顺便就把php给一块搞进去了,还是个7.4的版本。现在连lnmp官网的下载安装脚本都挂了,那就更不可能通过脚本进行php升级了,这也是为什么工控机上的php就停留在了7.4。虽然后来装了个8.1却始终没有切换。好在现在有了功能强大的ai,直接让ai进去一通乱搞就修复好了。之前之所以没有升级还有个更大的问题就是分词组件不支持php8,mac上的分词功能已经独立出来了,工控机上的没有处理,所以后来就成了这个状况。mac上的php早上直接通过apt升级了,能apt搞的确要方便很多,毕竟编一个php得跑半天。ecs上也有几台跑着php虽然没有php的业务,但是进行依然在运行,直接停止禁止自启算是解决了php的问题。技术依赖果然不是什么好习惯,装的时候省事,等出问题的时候,修复就贼拉麻烦,早晚得有拉清单的时候。

lighthouse@VM-16-8-ubuntu:~$ ps aux | grep php
root         861  0.0  0.4  88340 15876 ?        Ss    2024  31:43 php-fpm: master process (/usr/local/php/etc/php-fpm.conf)
www         2039  0.0  0.7 101528 26680 ?        S     2024   0:31 php-fpm: pool www
www         2040  0.0  0.7 101528 25056 ?        S     2024   0:31 php-fpm: pool www
www         2041  0.0  0.5  95524 20640 ?        S     2024   0:31 php-fpm: pool www
www         2042  0.0  0.6  95384 20920 ?        S     2024   0:31 php-fpm: pool www
www         2043  0.0  0.7 101528 24744 ?        S     2024   0:31 php-fpm: pool www
www         2044  0.0  0.7 101660 26652 ?        S     2024   0:31 php-fpm: pool www
www         2045  0.0  0.7 101528 26780 ?        S     2024   0:31 php-fpm: pool www
www         2046  0.0  0.7 101528 26908 ?        S     2024   0:31 php-fpm: pool www
www         2047  0.0  0.7 101528 27164 ?        S     2024   0:31 php-fpm: pool www
www         2048  0.0  0.7 101528 26620 ?        S     2024   0:31 php-fpm: pool www
www         2049  0.0  0.7 101528 26672 ?        S     2024   0:31 php-fpm: pool www
www         2051  0.0  0.7 101528 27172 ?        S     2024   0:31 php-fpm: pool www
www         2052  0.0  0.7 101664 26872 ?        S     2024   0:31 php-fpm: pool www
www         2053  0.0  0.7 101664 26904 ?        S     2024   0:31 php-fpm: pool www
www         2054  0.0  0.7 101528 26832 ?        S     2024   0:31 php-fpm: pool www
www         2055  0.0  0.7 101528 27320 ?        S     2024   0:31 php-fpm: pool www
www         2057  0.0  0.7 101532 26908 ?        S     2024   0:31 php-fpm: pool www
www         2058  0.0  0.7 101664 26884 ?        S     2024   0:31 php-fpm: pool www
www         2061  0.0  0.7 101532 26960 ?        S     2024   0:31 php-fpm: pool www
www         2063  0.0  0.7 101532 26960 ?        S     2024   0:31 php-fpm: pool www
lightho+ 1609805  0.0  0.0   6612  2292 pts/5    R+   10:09   0:00 grep --color=auto php
www      3868312  0.0  0.5  95388 20884 ?        S     2024   0:31 php-fpm: pool www
lighthouse@VM-16-8-ubuntu:~$ sudo lnmp php-fpm stop
+-------------------------------------------+
|    Manager for LNMP, Written by Licess    |
+-------------------------------------------+
|              https://lnmp.org             |
+-------------------------------------------+
Gracefully shutting down php-fpm . done

lighthouse@VM-16-8-ubuntu:~$ sudo systemctl stop php-fpm
lighthouse@VM-16-8-ubuntu:~$ sudo systemctl disable php-fpm
Synchronizing state of php-fpm.service with SysV service script with /lib/systemd/systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install disable php-fpm
Removed /etc/systemd/system/multi-user.target.wants/php-fpm.service.
lighthouse@VM-16-8-ubuntu:~$ ps aux | grep php
lightho+ 1610176  0.0  0.0   6480  2304 pts/5    S+   10:10   0:00 grep --color=auto php
lighthouse@VM-16-8-ubuntu:~$

还是不能偷懒,都不用php,干嘛要偷懒用什么一键安装工具装这些乱七八糟的东西呢~~

除了php,连nodejs以及阿三签发的证书也出来凑热闹了,挺安全的一套加密系统,印度阿三能用个4作为密钥。这也算是符合印度阿三的人设了,毕竟泄露点苹果的资料啊什么的都是常规操作了。

 

拧螺丝

安装猫架、拧螺丝的时候,想起了一个“常识”——不过我至今不觉得这是一个“常识”,可能只是一个在记忆里被保存然后被篡改的部分。小时候陪我爸安装家具,他会让我帮他拧螺丝,但会特别强调一句:“不要拧死,最后全部拼接好后再拧紧。”

问及原因,是担心在拼装的过程中,一个螺丝发生了偏差,可能会导致其他部分也跟着变形。不过随着工业化标准的发展,这种事情也越来越少见——但我也确实因为一口气把螺丝拧紧发生过错误,并不是变形,而是没有看清楚螺丝的尺寸,把一根更长的螺丝拧紧在了不匹配的洞里,导致螺丝穿过了板材。


前些日子,观察过一个在篮球场教自己儿子“如何给自行车上锁”的男性。他每天把心爱的摩托车锁在本不应该停车的篮球场边上,下雨天要遮雨、晴天要洗车。一连好几天,我都看到物业在他的车上贴了提醒此处禁止停车的通知单。直到最近,那辆车被强行拖进了车库,在里面甚至都落了灰。不知道那个每天把车视作珍爱的男人,在看到这一幕后,会作何感想。

这两件事本质上却有一样的韵味——拧螺丝之前先确定尺寸,避免一口气拧紧,也是为了最终确定尺寸是否合适;以及停车之前先搞清楚场域内的停车规则,避免自己的行为对他人造成困惑和影响。最开始确认的那件事,也就是所谓的“程序正义”。

不过,就算没有尊重“程序正义”,也可以把责任归咎给别人。

比如,昨天看到一个想从车库倒着车离开车库的人,车库抬杆并没有正常识别他的车牌,他便用手机拍摄前保险杠上的车牌,拿到识别器前面,想用这种方式从车库出口倒车出去。在一旁目睹抽象操作、已经彻底无语的管理员让他想办法掉头出来,那个开车的人倒是理直气壮地凶回去一句:“前后车牌数字都是一样的,凭什么不让我出去?”

这个灵魂拷问不禁让车库管理员失了语,我这个路过的路人都为之虎躯一震。

你别说,这个灵魂拷问还真不好回答。


当然,“程序正义”也有让人“犯蠢”的时候。

比如有一次,我跟老婆逛完山姆出来,在饮食区吃刚买来的熟食时,我打算去买点喝的。我买了两个“杯子”,去接饮了两杯可乐——直到我端回到桌上,才意识到自己有多“蠢”——两个人,我竟然花了两份饮料钱。按道理来说,会过日子的精明人,应该只买一个杯子,因为一家人喝一杯水也是喝,没必要再多掏一份钱。

我当下就在自嘲,这是我从小到大“脑子转不过弯”的表现:写着一人一杯,我就会一个人买一个杯子,想不到这个程序之外本身可能存在“游离空间”。不过这件事也要分两说,两个人买一个杯子这件事本身是不是“合法”的,或者说是否是“程序正义”的。有可能我这种严格遵守一人一杯的人,会被认为是蠢,远远不及那些还可以用一次性手套打包各种免费酱料的人……

这件事越说越觉得“吃亏”,就像是一口气把螺丝拧到底一样,一颗错位,导致后面的结构都跟着错位。

当然,这个“蠢”的评价是我从小就被别人贴上的。比如在香烟摊前面见到 100 块钱,我捡起来就给了烟摊老板,说他的钱掉了。这件事我从五岁被亲戚们嘲笑到了十几岁。如果让他们知道我在山姆是按人头买饮料杯子……


今天的文章没有结论:似乎程序正义在避免人吃亏,但又在逼迫人们吃亏。

就跟那根螺丝一样,拧到底,或是故意不拧到底,它终有一天都会松掉。

——

感谢订阅莫比乌斯,如你有任何疑问、观点交流,请前往创作者频道,或私信联系。

爱拯救之

极客死亡计划现在运行在安装 OpenBSD 8.0 的服务器上,不是 Linux。

我在 第一百零一期周刊 因 Linux 如今也包含 LLM 生成的代码而感到沮丧,写道:“我用 Linux,不可能不用”——结果,我还真的可以不用。Linus Torvalds 最近还在 邮件列表 里回复一条我读起来毫无恶意的邮件,用十分荒唐的逻辑称对方的想法愚蠢之极(“UTTERLY STUPID”),语气强烈。

前不久 ,他用 Claude Code 写的代码被评审者找出潜在的竞态问题(race condition)。 再后来 ,Linux 内核不再要求贡献者披露 LLM 使用情况。

这一切都给了我更多的理由抛弃 Linux,去用 BSD。我们讨论的不是可有可无的 SaaS 软件,我们说的是 Linux,全世界都依赖的操作系统。

Oh Linus, oh Linus, you let us all down.

不少 LLM 追捧者貌似只有那么一两个论点,Linus 一边骂人一边强调“LLM 是工具”,与此同时,Rich Hickey1 说: 我一辈子都在造工具和用工具,我知道工具是什么。LLM 可不是工具。 与此同时,OpenBSD 发布了一首名为《 The Simps on AI 》的歌曲,我意犹未尽地听了好几遍。与此同时,还有 一群没那么显眼的人 想要负责任地维护让人感到安心的软件系统。

说真的,我还在乎那些破事儿干嘛呢?

前几天我在英文博客发了一篇题为《 What’s next for the indie web? 》的文章,介绍了 weepinbell 的理念和架构设计,还谈了谈我认为独立网站不应该集中在 IndieWeb 以及 Aaron Parecki 提供的基础设施上(比如 webmention.io)。我的想法是,除了 IndieWeb camp,还应该有更多有活力的小社群。社群内(或社群之间)可以共享基础设施,由一两个有能力、有责任心的人维护诸如联邦宇宙实例、页面托管和 Webmention 接收器等基础设施,这样的社群应该是由相似理念和爱好的人组成。

这样大家可以一起远离充斥推荐算法和广告的商业平台,又不容易感到自己在孤军奋战,可以相互提供帮助,或者各司其职。不同的基础设施可以由社群里不同的人维护,兴许还能合作推出公开的软件或服务,不懂技术的人还能在美术等方面提供帮助。除了扁平的结构,也可以像 IndieWeb camp 那样,有一两个扛大旗的志愿者,但仍然与社群联系紧密。

这样的互联网社群已经有一些案例了,涛叔的 ZZ.AC 兴许就算其中一种,国外我比较有好感的是 omg.lol 。此外还有一些比较特立独行、小众且观点鲜明的,比方说 OpenBSD Amsterdam ——尽管看上去是云计算提供商,但社群的确很有活力,我在找 OpenBSD 的参考资料的时候也偶尔会路过他们写的页面。就算不考虑独立网站的概念,一两个有能力的人带头组建起和谐的小社群,这样的例子也有不少,氛围都要比乌烟瘴气的「大互联网」好太多。

我的确有很强烈的自我意识和难以改变的价值观(与我有邮件通信的朋友将其称作「工匠精神」,其实我有点不敢当,但我的确很在乎工艺之类的概念),以至于我时常绝望地在心里大吼,这个世界怎么变得这么坏?最近这种负面情绪变得愈发强烈,可以在《 打领带的人 》里读到。我和这个世界就是不合的,但这不代表我找不到和我有着一样信念的人。

我想我有点太关注那些与我无关的人的想法和行事方式了,有点像《地狱客栈》第二季的夏莉,那样发起疯来只会让关心自己的人感到难受。如上文所述,有很多人和我站在相似的立场上,我为什么要想象自己身处敌营中,让自己感到困顿、绝望、难以呼吸、无法逃脱?

我也要原谅自己的偏执,因为我“身处敌营”的状况其实并非只是想象:

我观察下来,这个行业里有绝大部分是不爱编程的。

我比较有限的样本里有这几种类型:除了上班不写代码,觉得有 LLM 不用还要自己手写的人是纯傻逼的;写代码是为了开发产品获得商业成功,而同时开好几个 Agent 会话能帮他们“更快达成目标”;对任何事情都没有反思,把 LLM 盛行当作天气现象一样自然的事情,就像世界上有个叫 Java 的编程语言、学校里教这个、也有公司招这个岗,然后就一直写 Java,后来也很自然地融入了 Vibe-coding 的同列;喜欢新奇概念,自称追上行业前沿的,热衷于传播「许愿式编程」之类的概念,对自己的“与时俱进”感到骄傲……

我觉得我能做的就是给工作分配尽可能少的精力,但这好像也很难,我也真的在认真考虑要不要远离这个行业……

我唯一应该责怪自己的,不是自己对世界的认知,而是我对这种认知的反应。我的反应相当情绪化,我想逃。我说我在考虑要远离这个行业是认真的,一周前我就在物色接收短篇小说投稿的杂志。《零杂志》有专门接收非文学背景投稿的栏目,可惜字数限制八千,我最近写的 小说 大多都超过一万两千字了,我也不愿意删改,而且他们的投稿竟然还要填身份证号码,我可不想自己在网络上的身份与现实身份联系起来。我还看了《花城》,据说编辑是真的会读自由来稿的,想必是如今对文学有热情的人少了,编辑的时间才能分配得过来。

不过也有很俗套甚至搞笑的杂志,《花火》据称偏向青春文学,投稿要求里写的是允许忧伤淡雅,但不允许阴郁沉闷,还严格要求禁止描写中小学生早恋,但是可以暗恋,明明是文艺而非文学。文学要的是真实,可不是什么淡雅,不是迎合你们对“青春”的恶臭想象。我想《啸风山庄》要是投稿给这个杂志,一定会被拒稿,许多文学经典按他们的标准都不合格。

明智地讲,如果我真想要从事文学,我也得先有一份能养活自己的工作,而且要想作品被刊登,就应该去研究某篇杂志过去发表过的作品的风格,依照这个风格去创作。一个新人作者是没有创作自由的,除非他不想吃这口饭,就像一个程序员只能去学行业里其他人都在用的技术,自己的技术兴趣只能当作消遣(除非你的技术兴趣是 Rust、LLM Agent 和模型训练)。

愈发觉得职业选择自由和创作自由以及各种形式的自由,在当今的市场里都是特权。

只有有丰富履历(而不一定是过硬的技术实力)的人才有谈薪酬福利的资本,有自由选择技术栈的权力;普通人只能迎合和学习这些人选择的技术,除非不想要吃饭了。

只有有过丰富作品集的小说家、画家和音乐家才有资本让出版机构来欣赏自己的作品,普通人只能迎合杂志社、出版社、唱片公司的审稿人、编辑、制作人的品味,去创作他们偏好的东西。

我没有要批判的意思,我觉得很合理,但我确实不太能够接受这个局面,不能接受个人必须要谄媚才能在世界中获得一席之地…… 我大概要花时间消化这一点。

所以说到底,我还是很难战胜这个世界的残忍。我思考问题很认真,对待自己在乎的事请也很认真,因此对不合理的现象容忍度非常低。然而我只是个学生,可以说是手无缚鸡之力,只有被管的份。哪怕我的辅导员在我的简历上批注「不知道你那个符号(GitHub Logo)是什么意思」,我也不能指责她「外行指导内行」。她也会继续认为自己反复强调面试进门的时候怎么走路和微笑,是崇高的教育之道。

哪怕我不是个学生,也免不了受人管制。恐怕我要到三四十岁的年纪,才能拥有与我的自我意识相匹配的自由。或许到那个时候也不会有,或许到那个时候,自杀的念头会又一次擒住我,而那一次,它会战胜我。我希望那种事情不要发生。

至少现在,我的理智和热情还能赋予我反叛精神,不至于麻木。

除了没用的肉体自杀和精神逃避,第三种自杀的态度是坚持奋斗,对抗人生的荒谬。

每想到类似的事情,我就会想到加缪的文字。我并没有把加缪当作偶像或导师之类的形象,他自己也不觉得自己是哲学家。的确,她不像黑格尔、海德格尔和胡塞尔那样有严谨的哲学理论,他的文字不是理性主导的。荒诞与爱是加缪作品里连续的主题,他的作品里有种朴素的真实感(尤其是他的遗作《 第一个人 》),让我感到他是个可以接近的人,他写的东西常常包含令我会心一笑的个性。

这种真实感和亲近感,或许就是我对抗荒诞的方式呢?我热爱文学,兴许是出于我骨子里对真实的向往,而获取亲近感的方式,则是和真实的人建立真实的关系,而不是 纠正互联网上那个“错的人” 。


最后,我真的有在考虑建立一个小型、独立的互联网社群,也想要帮助没有技术背景的人建立起独立的互联网身份,不被大科技公司控制。这样的社群不会以 V2EX 和 Hacker News 那样的「大广场」形式存在,更像是各自独立但彼此关联的群岛。我大概会用 weepinbell 搭建公开的 Webmention 服务,我还在考虑自己开发类似 are.na 的平台。

当然,我还在思考,也可能不做。如果你感兴趣,欢迎 给我发邮件 。

希望我们都不要认输。


  1. 编程语言 Clojure 的创造者。 ↩︎

处决童年的自己 II

这个系列并不是单纯回顾自己的童年,而是前几天一个朋友给我留言。

虽然他在留言里用了一句“这些故事告诉你,希望能作为你的灵感”,但能感觉出,他在说出自己的童年经历时,也算是一种自愈的过程。但要说如何解决,其实都只是书本知识上的那些所谓的“道理”。


我用我的语言,简单复述一下他提到的故事:

他小时候在经历父母离异后,被安排给了爸爸。那个时候他已经上小学,已经能够理解何为离婚。他第一次求妈妈,是在他们决定离婚之后,希望能跟着妈妈,但他妈妈只是看着他,说了一句“你越来越像你那个爸了,我不想看到你”。

初中时,他辍学了,原因是他爸把家里的钱都赌光,还欠了一屁股债,他每天都躲在惊恐中活着。那一年他又找过妈妈一次,但那一次他妈并没有出面,而是一个陌生男人把他揍了一顿。两个人在派出所做笔录时,他一个劲儿地解释希望有人认可他这是家庭纠纷,但那个男人并不认可这个法律上的“继子”。最后他妈迫于压力,还是前来派出所作证,只是说了句:“他不是这个家的人。”最后派出所以民事纠纷处理了这件事。虽然他拿到了一笔因为被揍而获得的赔偿款,但也彻底买断了他跟他妈的关系。

再后来,他爸因债出逃,再也找不到人。他代替了父亲的职责,开始照顾他的爷爷奶奶。爷爷奶奶去世时,他一直觉得爸爸会回来分遗产,但他再也没出现。他拿到为数不多的遗产后,彻底决定自己孑然一身活下去。

最近,他妈被查出癌症,突然联系上他,希望他能帮自己养老。他拉黑了所有亲戚的联系方式,对自己自我攻击了好长时间。前段时间看到我在博客聊关于“内耗”的话题,他释怀了不少,觉得自己把自己困在了一个“内疚”的情感里。


说实话,这个故事看完,我其实并没有多少作为一个读者应该有的“触动”,因为如果是我,我也会这样选。我甚至会更狠地在“她”生命的最后时刻,让她被生命仪器延续着物理生命,耗尽她最后的积蓄,任凭她祈求着我给她一个痛快,而我就在这种“尽孝”的表演之中,实施她曾经抛弃我的制裁。

我一开始手头在忙,先是简单地回了他一句“你做得没错”。

对与错虽然没有意义,但在这件事上,决定就像是日本执行死刑的按钮一样——安排三个人,三个人之中只有一个按钮是真正的启动键,没人知道,没人在意,而执行死刑时产生的负罪感又因为未知,被三个人自我消化。所有人都觉得“他”的死与己无关——就算没人启动,还有一个应急开关,也会被隐藏在背后的狱警按下。

如果当这场制裁只剩下一个人、一个按钮,且那个按钮一定是启动键时,谁又敢真的按下去?下不了手,并不意味着这个决定就是错的。即使他已经有足够的理由做出选择,真正按下按钮时,仍然必须独自面对那个决定所带来的代价。


当一个人真的经历故事时,生活会像飞沙走石一般,席卷、磨碎所有关于故事和角色的部分,使其成为露骨的体验。

我后来称他这样的“决定”为“处决童年的自己”:把一个原本应该理解并尊重父母养育之恩、血浓于水之情的自己,在某一个时刻连同他的经历一同处决,与过去的自己划清界限——而这种内疚,就像是确定自己按下的按钮是真正执行死刑的心理压力一样。没人支持、没人在乎,甚至那些道貌岸然的道德标高,会站在道德高墙的顶端,说出一句毫无意义的“其实你有更好的选择”。

他失去了向人解释的权力,因为他也失去了“讲故事”的权力——这是他血淋淋的生活,他在生活里不再觉得它是故事,也看不到人们在看故事时期待的剧情与解决方案。大多数人不再在意他经历了什么,而是他在最后做出了一个违背他们对于故事理解的决定罢了——“你怎么能不管你妈妈呢,她毕竟也是生你养你的人啊。”


于是,我接过他的故事,没有直接截图我与他的聊天内容,而是特地用我的文字,将他的独白转译成了“故事”。

他在生活里,处决了一个故事里的自己;我在故事里,试着救赎一个生活里的他。

——

感谢订阅莫比乌斯,如你有任何疑问、观点交流,请前往创作者频道,或私信联系。

牛仔裤选择和胖一些不怕大病?

✇ACEVS
作者 ACEVS

偶然发现牛仔裤穿不下(小了),有延长的扣子可以选择,突然想起自己的牛仔裤胖了好几年,就pdd找找看缩小的工具,发现也是有几种,塑料的金属的配件,看了几个演示,感觉还是麻烦,罢了。

然后又想到合适的牛仔裤尺寸,得买牛仔裤,问了豆包50元以内,耐磨耐穿牛仔裤和材质推荐,纯棉帆布干活,裆部特殊设计,看上去确实不错,但是估计比较硬挺吧帆布的,不够宽松可能,我也没穿过不知道如何,先mark,然后就是氨纶少于2.5%的,棉和涤纶什么的混纺的那种。价格低,耐穿。全棉的价格贵一方面。另一方面不耐穿似乎。去pdd看了几个牌子,真维斯,金盾,百圆,豆包也推荐了几个国产牌子,看了几个有的感觉还行。

正准备下单的时候,突然想起,自己之前屯的牛仔裤估计还有4-6条。当时京东上某个牌子活动,全棉的50一条,有弹性的可能是29一条,每种各买了4条。感觉现在才穿了四条。还有几条估计,先不买了。就是有弹性的那个腰围粗了5.6cm感觉,因为最近几年控制饮食瘦了30斤左右吧。最高减重40斤左右。bmi大概21.5左右。

突然想起一个问题,胖一些能对抗大病,预后好点,我问豆包bmi 25 30 35对抗大病,豆包说25-30就行,我说一个胖子25 和一个锻炼的运动多的人25不同吧,豆包说肌肉多的抗大病更好。按理说肌肉消耗能量多,肥肉是能量包。不大对头,我又问豆包。

豆包说
你这个思考非常到位,刚好戳中很多科普简化说法的漏洞:BMI只是重量÷身高²,它分不清是肌肉、脂肪、水分,所以同样BMI=25,两个人的储备、抗打击能力完全不是一回事。

先把两个东西拆开:骨骼肌(瘦肉) vs 脂肪(肥肉,能量包),再讲生病的时候各自扮演什么角色。

1. 肥肉:确实是“能量仓库”,但它只有一个功能——存热量

脂肪组织的优点:

  • 热量密度极高,生病食欲差、吃不下的时候,可以分解供能;严重感染、重症、术后消耗期,足够的体脂可以防止快速衰竭。 也就是你说的:它是储备燃料。

但是它有巨大短板:

  1. 脂肪几乎没有免疫功能、没有收缩功能、没有蛋白储备。大病危重阶段,人体最缺的不只是“卡路里”,是蛋白质(用来合成免疫细胞、修复组织、维持呼吸肌、心肌、膈肌);脂肪不含蛋白质,烧脂肪补不了蛋白缺口。
  2. 过多脂肪(尤其是内脏脂肪)是负担:慢性低度炎症、胰岛素抵抗、血管负担。很多重症里,肥胖会让肺炎、感染、ARDS、血栓风险上升。不是“肉多就扛揍”,内脏肥肉反而拖后腿。

一句话:脂肪=燃料库,但没有蛋白质;只有热量,没有修复材料。

2. 骨骼肌(肌肉):它既是“蛋白仓库”,也是生命硬件

肌肉里面大量是蛋白质。 危重疾病、长期高烧、严重感染的时候: 当吃不下东西,身体优先会分解骨骼肌,释放氨基酸,去造免疫细胞、维持呼吸肌、心脏、肠道屏障。 👉肌肉 = 蛋白储备库,这个东西脂肪替代不了。

同时肌肉还有刚需生理作用:

  • 呼吸靠膈肌、肋间肌(都是骨骼肌);肌肉量太差,重症很容易呼吸无力、脱机困难,肺炎很容易进展成需要插管;
  • 活动能力:肌肉少,生病卧床之后很快肌少症、坠积性肺炎、血栓,这是很多老人大病去世非常关键的推手;
  • 肌肉多的人,基础代谢高、胰岛素敏感性更好(同等BMI下),慢性炎症水平更低。

代价就是你说的:静息下肌肉耗能比肥肉高。 这个代价是平时付的;但危机来临时,这份“高耗能的硬件储备”,价值远大于省下来那点热量。

3. 同样BMI=25,两种人的本质差别

  • A:BMI25,久坐,体脂高、肌肉少(隐性肥胖): 重量主要是肥肉。有一点热量储备,但蛋白池子很小;内脏炎症偏高。大病来了,燃料有一点,但很快开始拆宝贵的肌肉,很容易快速垮掉。
  • B:BMI25,规律力量训练,体脂低、肌肉量大: 肥肉不多,但是骨骼肌充足。脂肪燃料不算特别多,但是蛋白质储备丰厚,呼吸肌、体力底子强,炎症水平更低。

    重症医学现在非常明确:肌少症,是独立的不良预后危险因素,比单纯BMI超重的影响还要大。很多BMI正常的瘦子,因为肌肉很少,大病预后反而很差,这个叫“正常体重肌少症”。

4. 那理想的“抗大病配置”是什么?不是越胖越好

不是堆肥肉,是: ✅ 足够的肌肉量 + 适度的体脂储备,不要内脏肥胖 也就是: 肌肉多多益善(在关节、心脏能承受范围内),脂肪保留一个安全缓冲,不要太少,也不要内脏脂肪超标。

对应到BMI的通俗理解(只是参考,不能卡死):

  • 体脂很低、肌肉也少(BMI<22,干瘦):储备太少,大病消耗下很容易快速恶液质;
  • 肌肉充足、体脂适中,BMI 23–27 这个区间,是预后最友好的区间;
  • BMI 28~30,如果是肥肉堆出来的内脏肥胖,收益就开始下降,炎症、代谢问题的坏处慢慢盖过“能量储备”的好处;
  • BMI>30之后,单纯靠脂肪堆出来的肥胖,在重症里整体是弊大于利(医学界叫“肥胖悖论”只在特定一小部分重症场景短期观察到,并不是鼓励长胖)。

补充那个容易混淆的「肥胖悖论」: 一部分回顾研究里,轻度超重的人某些病种短期死亡率看着略低。但很多后续研究认为:很大一部分原因是反向因果——瘦子里面很多人本来就是已经被慢性病消耗瘦下来的,不是瘦本身不好;而且这个悖论,在有力量、有肌肉的人身上,和纯肥肉胖子,完全不是一回事。

给你浓缩一句

肥肉是汽油桶,只有热量;肌肉是钢筋+弹药库:既有蛋白质原料,又是维持呼吸、活动、免疫的核心硬件。 汽油桶再多,没有钢筋骨架,一场大病冲击过来,依然容易塌。 同样BMI,肌肉优先,脂肪适度储备,拒绝内脏肥肉,才是更能扛大病的体质。

最后没事还是得锻炼身体增加肌肉,但是锻炼身体可能吃的东西又多了,东西吃多了,可能有的不该吃的也吃了?然后又要仔细研究怎么吃了,吃什么了,以及怎么锻炼了,我问了豆包,但是不折腾了。哈哈。

啸风山庄

《啸风山庄》是经典英国文学 Wuthering Heights 的新译本,译者是赖慈芸。这本在大陆更常见的译名是《呼啸山庄》,在台湾的译名是《咆哮山庄》,译者本人是台湾师范大学翻译研究所教授,可以说这个新译本统一了两岸的译名。书中还附上《啸风山庄》的翻译简史,读起来蛮有趣。曾经 Wuthering Heights 还被译作《狭路冤家》《魂归离恨天》,后者给我的感觉是把 Wuthering 理解为冤魂不散的声响(毕竟主要人物凯瑟琳和希斯克利夫死后的鬼魂似乎都在人间游荡),把 Heights 理解成了高空,也是值得品味的译法。

这个译本我通篇读下来,觉得语言很通顺,几乎没有译制腔,也没有过度本土化,注释也很完善。只不过有不少对情节进行解读的注解,我其实觉得有些影响阅读。理想国的装帧也很好看,大小合适,捧起来很舒服,我之前还在飞机的狭窄座椅上读过。在万米高空读 Wuthering Heights,也别有一番韵味了。

对于文学经典,我不好妄下评论,不过我也确实没有批评的话要讲。我很喜欢艾米莉·勃朗特对人物的塑造,只可惜她一生只出版了这一部作品,而且似乎在初次出版时并不受欢迎。她的姐姐夏洛特·勃朗特(《简·爱》的作者)在给再版的《啸风山庄》写序的时候,还为妹妹在书中描写的各种不道德的行径致歉,她没有意识到自己的妹妹写出了一篇杰作。译者导读里写道,如今文学界普遍认为《啸风山庄》的文学造诣要高于《简·爱》。

我读《简·爱》还是小学,如今已经忘干净了,只记得主角很惨,最终没能和爱人在一起,她爱的男人有一个精神病妻子。《简·爱》还被译作《孤女飘零记》,和《魂归离恨天》一样都有悲剧基调。《简·爱》的人物关系看起来不如《啸风山庄》复杂,而且道德水准有点太高了,我就喜欢看扭曲和阴暗的情节。当然《简·爱》也是地位相当的文学经典,包含超越时代的女性主义思想,“夏洛特·勃朗特被誉为在故事里最早使用私我意识的作家”1,这点我也觉得很好,稍早一些文学作品都很少描写人物的自我意识,甚至他们可能没有很强烈的自我意识,即便是《 包法利夫人 》和《 红与黑 》里关于偷情的描写,也见不到对人物复杂心理活动的直接描写。《简·爱》的文学成就有很大一部分就体现在这点上。

那么《啸风山庄》的文学成就呢?好吧,我向来不喜欢讨论文学作品的时代意义和影响,就不勉强自己了,写我自己的感想就好。

非道德性

我向来喜欢看道德处于灰色地带的作品,因为合乎道德的好人谁都写得出来,太过正直反而缺少文学所追求的那种真实——这也是我 不喜欢诺兰导演的《奥德赛》 的原因之一。我想要看到的是真实的人在糟糕的处境下做出两难(甚至三难、更多难)的抉择。道德抉择本质上是伪抉择,让角色从绝对的好和绝对的坏之间选择,完全是耍流氓,谁都知道要选第一个。只会服从定言令式的人怎么会打动人心?

《啸风山庄》的非道德性,主要围绕希斯克利夫(Heathcliff)展开。他被恩萧老爷捡回家之后,因为是黑人,还是身份不明的小孩,所以一直被啸风山庄里的其他人欺负,尤其是与辛德里·恩萧(恩萧家的少爷)结下了梁子,但是与凯瑟琳·恩萧(辛德里的妹妹)是青梅竹马。

后来,辛德里离开山庄,回来时娶了个名叫法兰西斯的女人,诞下一子名为哈里顿。辛德里是在恩萧老爷病逝后才带妻子回家的,可能是怕父亲不赞同婚事。法兰西斯的身份不明,但猜想应该是与恩萧家的乡绅身份不符。辛德里的性格不好,父亲和妻子双双死去后,他一蹶不振,恩萧家逐渐破败,啸风山庄里就出现了这么个神智不清的酒鬼。哈里顿没有受到什么好的照看,有次辛德里甚至把它从楼上丢下来,被希斯克利夫接住了。

希斯克利夫和辛德里的儿子哈里顿之间的关系很奇怪。哈里顿本是啸风山庄的女管家迪恩太太养大,后来迪恩太太跟随小姐凯瑟琳嫁到了鸫翔庄园,便离开了哈里顿。哈里顿受希斯克利夫的影响最深,这孩子性格暴戾(可以说跟他父亲也像吧),似乎是讨厌所有人,就喜欢希斯克利夫,因为希斯克利夫教他说脏话。后来辛德里死了,这孩子就一直跟着希斯克利夫,长大了也没读过书。乡绅的孩子被希斯克利夫养成了个没文化没教养的农民,这就是他报复恩萧家的方式之一。

凯瑟琳与希斯克利夫

希斯克利夫至死都一直爱着青梅竹马凯瑟琳。他们之间的感情很复杂,说是爱恨交织,有过度简化之嫌。凯瑟琳·恩萧在小时候和希斯克利夫一起去鸫翔庄园,也就是林顿一家的大庄园里玩,被林顿家的看门狗咬伤了,在庄园里修养了几个月,而希斯克利夫则被当作野孩子赶了出去。恩萧家对教育不是很看重,再加上凯瑟琳和希斯克利夫一起玩闹,显得很没教养,林顿夫人就把凯瑟琳收拾干净,教她做个淑女。回来之后,她的气质和性格都大变样,而希斯克利夫颇为不满,他感到自己被嫌弃了。这应该就是他们矛盾的开端。

其实从这里就能看出,凯瑟琳和希斯克利夫的关系之所以无法进行下去,很大程度上是受到了外界的规训。毕竟,凯瑟琳真的字面意义上地被“规训”了一番。林顿夫妇就是一个代表,他们象征着一套普遍的价值观,而这样的价值观是不允许凯瑟琳这样的小姐和希斯克利夫这样的野孩子在一起的。

凯瑟琳在要谈婚论嫁的时候也意识到了这一点,选择了和埃德格·林顿结婚,门当户对。同意结婚之后,凯瑟琳还和管家迪恩太太讨论过此事。从她的言语中可以发现,凯瑟琳最爱的是希斯克利夫:

我爱他,不是因为他好看,而是因为他比我更像我自己。

然而凯瑟琳不能做自己,而且她的自我意识也没有像现代人那样强烈到不做自己就活不下去,尽管有很多迟疑,她认为自己嫁给林顿是合理的。凯瑟琳的动机是我认为最值得品味的,凯瑟琳还说她自己就是希斯克利夫,她显然认可希斯克利夫是他的灵魂伴侣,但她非常清醒地做出了不和自己的灵魂伴侣结婚的决定,而且,她似乎并没有感到十分痛苦。

这对我而言难以理解,兴许是因为我和凯瑟琳这一人物在意识形态上的区别吧。

后来,希斯克利夫离开了啸风山庄,与凯瑟琳分道扬镳,也与恩萧家分道扬镳。回来之后,他也像凯瑟琳从林顿家回来时一样大变样,成了个成功人士,还赚了不少钱。此时凯瑟琳已经嫁入鸫翔庄园了,而希斯克利夫则向仇人辛德里在啸风山庄租了一间房。辛德里还是恨希斯克利夫,但是他更爱钱,所以收了这个房客。

此时,希斯克利夫的报复计划就正式开始了。

凯瑟琳的动机真的让我捉摸不透,她在希斯克利夫回来之后非常激动,一定要让家人与情敌来往。希斯克利夫并不打算追回凯瑟琳,他拐走了埃德格的妹妹伊莎贝拉·林顿——这应该是希斯克利夫复仇计划的开端,也是他非道德行为的开端。伊莎贝拉当时是真的被希斯克利夫的花言巧语迷惑,背着哥哥和他私奔了。

希斯克利夫当然不爱伊莎贝拉,根本不关心这个妻子。伊莎贝拉到了啸风山庄之后,连个换衣服和睡觉的地方都没有,因为主人辛德里不顾家事,山庄里已经没有几个干活的仆人了,希斯克利夫更是对伊莎贝拉毫不过问。最后她带着自己和希斯克利夫剩下的儿子,逃到了城里去住。哥哥已经不想要私奔的妹妹回家,希斯克利夫也不去找她,是她一人把林顿·希斯克利夫抚养长大。

在此期间,凯瑟琳也因为希斯克利夫的事情被搞得精神失常,得了怪病,生下女儿没多久就去世了。女儿也叫凯瑟琳,一般以小名凯茜称呼。凯瑟琳的死对希斯克利夫冲击很大,他在凯瑟琳死前的几天还在鸫翔庄园的地界躲藏,想要找机会接近凯瑟琳。不过他的注意力很快又被复仇之心转移了。

一直在城里和丈夫希斯克利夫分居的伊莎贝拉病逝,埃德格林顿本想把妹妹的孩子带回来抚养,但他当然无法和希斯克利夫这个“正当”的父亲争夺抚养权。继哈里顿之后,希斯克利夫又要残害另一个无辜的孩子了。

凯茜与林顿

接下来就是第二代的故事了。小林顿被接到鸫翔庄园暂住的时候,凯茜很喜欢这个表弟。林顿体弱多病,一直觉得不太舒服,可刚到没多久,与表姐才建立起感情,就又要被拉着去啸风山庄和希斯克利夫一起住。啸风山庄的环境和仆人的态度,他的母亲伊莎贝拉已经见识过了。总之,他过得并不好。

希斯克利夫并不想借林顿报仇。他教坏哈里顿是因为憎恶辛德里,他说,一想到辛德里的儿子比起喜欢父亲更喜欢自己,他就觉得非常舒畅。他对伊莎贝拉并没有多大的怨恨,毕竟伊莎贝拉只是他向埃德格(也就是抢走了凯瑟琳的男人)报仇下的一步棋,拐走他妹妹,让林顿一家蒙羞,就已经够了。他留下林顿,是因为埃德格也病弱,时日无多,他死后,应当由伊莎贝拉继承遗产,而伊莎贝拉也死了,所以应当由林顿继承遗产。他只要保证林顿活得比埃德格长,就能拿到遗产。

事实上他也的确做到了。辛德里死了,哈里顿忠诚于希斯克利夫,啸风山庄已经在他的掌控之下。接着他又耗死了埃德格,林顿家的财产也落入他手。这附近最大的两户人家,如今都归希斯克利夫所有了。这才有了本书第一章,洛克伍德先生从希斯克利夫那里租下鸫翔庄园的情节。

林顿死前,与凯茜来往密切,因为他们已经在短暂的相处中喜欢上了对方(是的…… 他们是表姐弟…… 凯茜是埃德格·林顿的女儿,林顿是伊莎贝拉·林顿的儿子…… 这才是本作的最大道德污点吧!)。希斯克利夫不允许林顿出门,埃德格也不允许凯茜靠近啸风山庄,因为担心遇到希斯克利夫这个灾星。

Well, it wasn’t sexy if it wasn’t forbidden…

总之,凯茜非常聪明地用书贿赂马夫,让他帮忙送信,他们两个就这么一直通信。迪恩太太发现那些情书之后,威胁要告诉她父亲,这才阻止了他们。但我说实话,这也只是让凯茜更想和林顿搞在一起了。后来迪恩太太卧病在床,凯茜就每天晚上骑马去啸风山庄找林顿。

希斯克利夫为什么不阻止这两个人呢?其实他反而在撮合这两个人,因为林顿和凯茜结婚对他有好处。埃德格的女儿若是嫁到啸风山庄来,一方面能激怒埃德格,另一方面他也更容易拿到林顿家的遗产。

也正是他的撮合,让凯茜和林顿的关系变得非常扭曲。林顿本身体弱多病,严重的时候甚至连走动都非常痛苦,再加上没有受到好的教育,也难怪他性格很不好。林顿在病重的时候,依然想要凯茜到啸风山庄来陪他,但两人陪伴的过程中,林顿什么都不想做,因为凯茜想做的事情对他来说都太累了,林顿又常常耍脾气,他们的相处其实相当不愉快。

但希斯克利夫不能容许两人不和,他在私下对林顿又打又骂,折磨这个本身就被病痛困扰的孩子,要他在凯茜面前表现好点。有好几次,林顿和凯茜见面时,明明因为身体不好不想做任何事情,连话都不想说,嫌凯茜和一同前往的迪恩太太太吵,却还是执拗地不要两个人走,因为希斯克利夫在远处看着,要是没把凯茜哄好,他就会被收拾。

再后来,希斯克利夫用林顿把凯茜和迪恩太太引诱进了啸风山庄大门,然后把二人软禁了起来。迪恩太太被关起来五天之久,在此期间,希斯克利夫已经逼着凯茜和林顿成婚了。

被放出来之后,林顿对迪恩太太说的话简直令我后背发凉:

“你们不放她走?你这小笨蛋!”我叫起来,“立刻跟我2说她在哪一件,否则我让你哭出来。

“要是你想去找她,爸爸才会让你哭出来呢。”他3说,“爸爸说,我不应该对凯瑟琳心软:她是我的妻子,她想离开我是不对的。爸爸说她恨我,希望我死掉,这样我的钱就会变成她的;可是她不应该拥有我的钱,她也不应该回家!她永远拿不到我的钱!无轮她怎么哭,哭到生病也一样!”

说完他又继续吃糖,闭上眼睛,好像他快睡着了。

林顿是坏人吗?他说话的语气和方式的确令人气恼,但实际上他也是受害者,是个可怜的孩子,失去了母亲,而父亲被复仇冲昏头脑,不干人事。疾病和精神的双重折磨让一个人的人生就这样被毁掉了。不过更让我感到发毛的是,有人能如此理直气壮地说出这样邪恶且毫无逻辑的话,而我们竟然无法谴责他。

一对冤魂

希斯克利夫的死很蹊跷。故事发生在最后的一两章,此时房客洛克伍德已经离开接近半年,再次返回鸫翔庄园时发现迪恩太太4已经不在,便到啸风山庄寻找。他发现啸风山庄比以前看起来怡人不少,这命途多舛的一群人的生活也有所提升。走近厨房见到迪恩太太,他才得知希斯克利夫已经死了。

于是迪恩太太继续给洛克伍德讲故事。林顿病死后,凯茜和哈里顿慢慢地走近了(凯茜是有什么奇怪的情节吗?哈里顿也是你表哥啊!凯茜是凯瑟琳·恩萧的女儿,哈里顿是辛德里·恩萧的儿子!)。抛去道德不谈的话,这一对其实还挺可爱的,比凯茜和林顿的安坏关系(大概可以这么说吧……)要好太多。

不知道为什么,哈里顿在后面几章的形象其实很戳我 XP还挺可爱的。在此之前凯茜和林顿一直嘲笑他没文化,不识字,是个文盲。尤其是林顿,常常在凯茜面前开哈里顿的玩笑,讲话很过分。哈里顿其实是想读书的,但被凯茜嘲讽,气得一个劲儿地骂人,竟然还直接把书烧了。后来在迪恩太太的教育下,凯茜才改变了行为。她其实没有恶意,只是有些娇生惯养,不习惯和没受过教育的人讲话。后来这两个人就开始了非常青春浪漫的校园式恋爱,凯茜教哈里顿识字读书,哈里顿也听得很认真。

嗯?你问我哈里顿可爱的点在哪里?呃呃,难道不觉得有些笨笨的男人想要变好,即害羞又好强地被逼急得涨红了脸的形象很可爱吗?让人很想要戏弄一下他呢。

与此同时,希斯克利夫已经不管这两个人了。他们在不在一起,对他来说都不重要。此时的他仍然身强体壮,但精神已经失常了,常常在幻觉里看到凯瑟琳。他去世的前几天,感到莫名其妙的高兴和兴奋,晚上不睡觉,出门走路,白天才回来,谁也劝不了他。

离世后,有小孩说在路上看到希斯克利夫,他不敢过去。这一描述暗示希斯克利夫的亡魂还留在附近,结合洛克伍德先生刚到啸风山庄时梦到的凯瑟琳的冤魂,可以想象这两个人终于以鬼魂的形式重聚了。他们的爱情并不被活人的世界允许,直到死后才能如愿。这或许也是为什么希斯克利夫会对死亡的临近感到激动吧。

叙述方式

我并不喜欢研究叙事策略和形式,但这部经典作品的叙述方式的确有很鲜明的特色,我这个门外汉也能读出些门道来。

首先是叙述者的设置,以及叙述者本人的时间与故事时间的交织。本书可以当作是洛克伍德先生的日记,他记录了进入鸫翔庄园之后的见闻,一直到他最后一次回到鸫翔庄园。恩萧和林顿一家的故事,是洛克伍德先生在鸫翔庄园入住时,从迪恩太太口中听来的。从到庄园、听故事、离开庄园、再次返回又听故事,这就是洛克伍德先生本人的时间线,中间他还几次去啸风山庄拜访房东希斯克利夫先生,每次都有不同的见闻,也与故事本身形成呼应。

迪恩太太口中的故事(以及亲自拜访时的见闻侧面反映出的故事)本身也有自己的一条时间线。洛克伍德的主观体验,和恩萧林顿家发生过的客观事实,以日记和口述的形式交织在了一起,是相当有趣的阅读体验。如何有趣,大概要亲自读过才能体会。

其次是类似戏剧的结构。这条我是从我读的译本附上的作品解读里读来的,我自己对戏剧结构倒是没有什么认识,不过可以看出,《啸风山庄》很明显地被分成了上下两幕,甚至还有幕间休息。第一幕是凯瑟琳与希斯克利夫的爱恨情仇,是第一代的故事。第一幕结束之后,洛克伍德还去啸风山庄拜访,之后才回来继续听故事,这便是幕间休息。第二代的故事自然就是第二幕了,以凯茜和林顿的关系为主,以希斯克利夫的死和凯茜与哈里顿的关系收尾。

另外,我也很难不被迪恩太太这个小角色打动。可能是被她对凯瑟琳、凯茜和两家人的忠心打动,也可能是被她的正义感和是非观念打动,而且整个故事几乎都是从她的口中说出,我想很多读者都会对这个讲故事的人产生好感。这种叙事方式除了形式新奇,结构精巧,还能让读者爱上故事里的角色,怎么不好呢?

本来说不纠结故事情节的,结果还是忍不住写了这么多。时间已经不早了,那就先写到这里吧。


  1. 参见: 简·爱 - Wikipedia  ↩︎

  2. 这里的「我」是迪恩太太。 ↩︎

  3. 这里的「他」是林顿·希斯克利夫。 ↩︎

  4. 洛克伍德先生入住鸫翔庄园时,迪恩太太还在那里做管家。所有关于恩萧和林顿两家的故事,都是迪恩太太口述给洛克伍德听的。 ↩︎

包尖钢笔错误修复失败

✇ACEVS
作者 ACEVS

wife最近买了几个国产钢笔,5元左右。永生什么的。有个包尖灌错了墨水,里面有树脂膜那种似乎,导致钢笔不出墨,写不出字,她泡了一天水,还是没有效果,问我酒精还有没有,有,还有丈母娘买的江左盟原浆酒老早之前当料酒用的,后来她回老家,这东西就闲置了,ok试试。反复吸入排出,换了酒精干净了,换上墨囊,不出水,甩了几下,有墨水甩出来,写字测试,还是不顺畅,然后酒精泡了一晚上,第二天测试,问题依旧,问了豆包,原来不能用酒精哇。哈哈。不修了。

智谱清言和豆包说的差不多
原因大概率是酒精惹的祸——酒精会老化橡胶墨囊、腐蚀毛细通道里的塑料件,还洗不掉干结的墨垢,反而留下残留物堵住毛细缝。 包尖笔(暗尖)因为笔尖和笔舌整个包在护罩里,本就比明尖笔难冲洗,酒精一泡之后问题更容易暴露。下面按"原因→自救→送修"给你捋一遍。
一、酒精对钢笔做了什么
腐蚀橡胶墨囊和密封圈:酒精会让胶皮墨囊老化发硬、开裂漏气,吸墨器里的橡胶活塞同理——一漏气就吸不上墨、供不上墨
溶不掉干墨还可能帮倒忙:钢笔墨水是水基的,干涸后的染料/碳素颗粒酒精溶解度有限;碳素墨水尤其顽固,酒精未必化得开
残留物堵毛细:酒精挥发后可能留下痕迹,破坏笔舌导墨槽的亲水性,墨水挂在毛细里下不来——表现就是"看着有墨、就是不出水"
包尖结构雪上加霜:暗尖笔的笔尖+笔舌被护罩罩住,只露一个铱粒,冲洗时水流根本冲不到毛细深处,酒精反而把脏东西往里冲
二、故障排查表(先对照定位)
现象 可能原因 自救办法
吸墨时阻力没了、吸不满 墨囊被酒精老化/破裂 更换墨囊(几块钱,可DIY或送修)
墨囊有墨但笔尖不出 毛细槽被干墨+酒精残留堵死 清水长时间浸泡+反复吸排
出水断断续续、飞白 笔舌导墨槽半堵 稀释洗洁精水浸泡后清水冲净
完全不出水、甩也不出 深层硬墨结块 超声波清洗或送修拆洗
挤压笔胆能出水、一松就断 墨囊漏气/气锁 换墨囊或重新排气上墨
三、自救步骤(按顺序做)
第1步:清水彻底置换酒精
排空墨囊里的酒精,然后用常温纯净水(别用自来水,矿物质会二次堵;更别用热水,会让塑料变形、墨垢凝固)反复吸排,至少10-20次,直到排出的水完全清澈无酒精味。
第2步:温水长时间浸泡
准备一杯约40℃的温水,把笔尖朝下整支浸泡(墨囊保持开启状态),泡2小时到隔夜,让笔舌深处干结的墨垢充分软化。水变浑就换水继续泡。
第3步:稀释洗洁精水深度去油
如果酒精残留导致亲水性被破坏,清水泡完仍不出水,用纯净水加1滴洗洁精(多了泡沫冲不干净),浸泡15分钟后清水反复冲洗——洗洁精的表面活性剂能瓦解酒精留下的油性残留和顽固墨垢。
第4步:毛细引流法引墨
洗完灌上墨水还不出,用干燥卫生纸包住笔尖和笔舌,手腕放松轻轻甩几下,利用纸的毛细吸力把后方墨水"拽"到笔尖——通常甩几下就能看到铱粒上渗出墨。
第5步:判断墨囊是否报废
吸墨时如果感觉软塌塌没有回弹、或者按压笔胆挤得出墨但一松手就断——基本可以判定墨囊被酒精老化漏气了。包尖笔(比如英雄100、永生601这类)换墨囊不复杂:拧开笔杆,把旧墨囊从笔舌尾部拔下,新的蘸点滑石粉插回去即可,网上几块钱一根。
四、送修的红线
出现以下情况就别自己折腾了:
浸泡+洗洁精+引流三步走完仍完全不出水
笔尖摔过、歪斜、铱粒开裂
墨水在笔里干了一年以上、已经硬结成块
这类属于结构性损伤或深层硬堵,硬通会弄坏笔尖中缝,找个修笔老师傅(现在不少城市还有,淘宝也搜得到)拆开笔舌清洗或换件,比硬来划算。
五、以后清洗的正确姿势
钢笔清洗的黄金法则就一条:只用清水(冷水或不超过45℃的温水),热水、酒精、消毒液、漂白水一律禁用。日常保养:
换墨水或2-4周洗一次,用吸墨器反复吸排清水到水清
闲置超过3天排空墨水、清水冲净晾干再收纳
用碳素墨水的笔洗得更勤,最好换非碳素墨水减少堵塞
包尖笔深度清洗可以考虑小型超声波清洗机,3-5分钟就能震出毛细深处的残墨
先按上面的自救步骤走一遍,多数情况是"酒精残留+毛细干堵"叠加,清水泡一夜+洗洁精去残留基本能救回来;如果救回来后吸墨还是不对劲,就直奔换墨囊那一步。

处决童年的自己 I

周末的咖啡厅,带孩子出来玩的人变得多起来。比如此时此刻,在我的视野里,就有两个推着婴儿车来咖啡厅休息的家庭,他们的构造都是一样的:一对父母、一个老太太,和一个被推在车里的婴儿,而唯一的区别是,两个孩子的性别不同。

抱歉,这样的场景,我难免会先入为主地设定一些“故事性”的部分,然后再开始观察,以便“验证”这个故事的部分——比如,两个家庭会在得知彼此孩子的性别后,形成暗自比较的短暂社会关系。

也不出我所料,那个推着孙子的老太太,一个劲儿地在婴儿车前面逗自己的孙子,一会儿抱起来展示开裆的部分,一会儿“孙子乖”“孙子可爱”地夸。(我今天特地选择了一个人比较杂、比较吵的咖啡厅。)而那个推着女孩的老太太,满脸嫌弃地看着那个不肯坐着、一个劲儿在逗孙子的老太太。

不过,他们之间真的有所谓的“比较”吗?不好说,不过如果它确实是一个很好的“故事”。


人们似乎总是有这样的习惯:当一件事情还不足以构成一个完整的故事时,就会主动为它补充一些原因、动机,以及尚未发生的后续。只要故事足够完整,我们就很容易产生一种错觉,觉得自己已经理解了这件事。

昨天在小红书上,看到一个让人有些毛骨悚然的帖子:

小时候做错事,母亲总是假装和第三人讲话的方式评论我,于是我哭着对她说:“你再对谁讲话,屋子里除了我还有其他人吗?”她自然不会有任何回应,只是讥讽地向旁边的空气吐槽,诸如“她这种就是不知道感恩”。

她发帖询问,想知道这是什么心理现象?

要解释这种现象并不难,但理论的部分并不能消弭“恐怖”的部分。就比如,引起这种心理现象的,有几种路径:

  • 第一种路径,是这个母亲缺少被关注,所以制造了一个“第三人”来见证自己;
  • 第二种路径,是这个母亲故意把女儿当做“第三人”,以切断联系和拉开关系距离的方式,进行一种疏离型的情绪惩罚。

如果这是一个“故事”,为了让这种“毛骨悚然”可以被加剧,就必须要延展“原因”的部分,即这个母亲是如何成为现在这个样子的。继续深入:

  • 这个母亲在家里长期被丈夫、孩子无视,渐渐分裂出一个“第三人”来见证和关注自己;
  • 这个母亲从小在兄弟姐妹中,就是长期被忽视的那一个。她的母亲每次在试图通过情感绑架和惩罚时,也会将她作为一个“第三人”进行疏离型剥离,以软性的威胁方式逼迫她听从父母的指令,否则她将会遭受“抛弃”。

就像之前我在《别看了,不过就是拉了坨大的》里提到的:

所谓专家,可以写一百种对男孩进行勇敢训练的方法,也会有一百种父亲不应该打压儿子尊严的警告。就像一篇全是高深理论的理性分析,用尽专业姿态展示了一番自己的独到眼光,傲视群雄,只有自己最能客观理性地看待世界,到最后也不及这个父亲的这一句话。

拉再大的一坨,也得被马桶冲走,摁下冲水键的恰恰就是在理论里被分析得体无完肤的“样本”。

“故事”和现实最大的鸿沟,不在于它是否完整地复原了现实存在的依据,而是在于,故事本身可以有解法,而现实本身并没有基于当事人的任何解法。

我想起这件事,倒不是因为我也有过类似的经历。恰恰相反,我想起的是另一种情况:有些事情,我们其实很早就知道发生了什么,也知道自己为什么会对此耿耿于怀,但这些理解并不能让事情获得一个新的结局。它们只是让我们能够把事情讲清楚,至于讲清楚之后还能做什么,却是另一回事。


我小学时被嘲笑过一段时间,是去参加课外的英语班。来自各个小学的孩子,特别是那些从小就被培养得很出色的孩子,当我们在一个班级时,总得有一个“全班的屁都是他放的人”来成为靶子,我就成了那个“靶子”。

其实是一件很小的事情。我记得那堂课的主题是动物园,在上课之前,老师就让全班同学站起来用英语说一个动物。到我时,我能力所能及说出的动物早就被前面的同学说完,我只能勉为其难地想起一个动物单词——kangaroo。但是我用的却是日语罗马音的方式在读,读成了 kan·ga·roo。老师先是表扬我说出了一个全班还没有重复过的单词,但同时也纠正了我的读音,还让全班跟着她读了几遍。

而教室里有几个已经成为朋友的同学(年纪比我大 2 岁),便以此在课间嘲笑我。先是嘲笑我在课堂上想要装逼,说一个大家都没说过的单词,结果发音还错了;然后开始用“康噶如”的名字称呼我……不过大部分时间我都没有回应他们。见孤立我没起作用,他们后来就换了一个人继续霸凌,当然我也因此彻底在这个暑假英语班没了“朋友”。

后来我跟一个心理医生聊过这件事,这件事对我来说本身充满了羞耻,但这件事本身并没有解法——比如,心理医生会开始一个场景模拟:这几个人再次出现在我面前时,我会说什么?

我如实回答:“我会逼着他们在半小时内杀掉彼此,最后我会让一个人活下来。”

心理医生一脸惊恐地看着我,倒是我安慰她——“我是在说写故事啦。”


恨意成为故事,确实是一个出路,就像有些人会为一个陌生的故事感动、会因为一篇爽文到最后主角报复了所有人而觉得酣畅淋漓——但这些解法是属于故事本身的。

不过后来我倒是想到了一个解法,我就将错就错,就把故意把 kangaroo 读作カンガルー,然后笑着说:“后来成年后我学了日语,把单词都学串啦。”

这个解法,不是在解决事情本身,更像是在处决那个被逼在墙角羞辱的自己。

明天继续聊聊何为“处决童年的自己”?

——

感谢订阅莫比乌斯,如你有任何疑问、观点交流,请前往创作者频道,或私信联系。

技术依赖

今天早上收到uniapp云空间续费的通知,看了下还有一个月到期,点击续费的时候发现最长时间选不到一年了。

看了半天才注意到底下那张字:

因阿里云 EMAS 功能逐步下线,uniCloud阿里云服务空间自2026年11月1日起不再支持新建,并将于2027年9月30日正式停服,续费后的到期时间不得晚于2027年8月31日,建议您尽快迁移,

一句话总结,就是阿里云的空间续费不了了,只能换其他的。甚至还贴心的给出了迁移工具,

这个东西聊胜于无,有总比没有要好一些。然而,及时是如此还得面临一系列的问题,域名不能同时存在,如果要想业务不中断就得先发布版本替换线上使用的域名,切换到新域名。无形中增加了app和服务的运维成本。

后面几个app的推送也用的unicloud的云空间,不过这次没有再使用uniadmin之类的面板也没有再为每个app创建独立的云空间。将多个app绑定到了同一个空间,毕竟这些app使用的功能也只有消息推送而已,完全没必要每个再创建一个独立的空间。毕竟dcloud提供一个免费的空间,剩下的都得花钱购买了,免费的先用着也不是不可。

新空间是支付宝云,倒是不受这次迁移的影响。这一切的原因都是因为选择了uni的框架,鉴于所谓的省时省力使用了uni的管理后台和推送服务,这包装好的一切虽然前期省了时间,如果没什么变数长期运维整体成本感觉也还可以。只是一点有了变数之后,所有的一切不说是推到重来,实际上跟挖了重载也差不多了。

之所以说这件事情,还有一件事情,上周五有个哥哥加qq问findu 是不是收费,能不能下载新版本。

其实,上来就说app闪退就可以了。来回折腾了半天我才直到是闪退,问了下手机版本 iPhone 15 pro, iOS27。自己的手机前几天也升级到了27,但是并没有闪退,虽然我猜测可能是ios版本问题,但是鉴于自己的手机没闪退,又猜测是不是硬件问题。

好在最后哥哥在自己的一通指挥下成功的把app崩溃日志发给了自己:设置 → 隐私与安全性 → 分析与改进 → 分析数据‌,在里面找到对应 App 的 .ips 文件(命名一般是 App名-日期-时间.ips

看到这一堆文件,心理瞬间没那么慌了,毕竟有了文件,就知道是崩在哪里了。

系统断言:

You cannot set a delegate on the default file manager.

符号化后的调用链:


-[NSFileManager setDelegate:]
-[PDRCoreApp copyOverlayFile]          ← DCloud 引擎
-[PDRCoreApp load]
+[PDRCore initEngineWihtOptions:...]
-[AppDelegate didFinishLaunching...]
也就是说:iOS 27 禁止给 NSFileManager.defaultManager 设 delegate,而 DCloud 离线 SDK 启动复制 www 资源时还在这么做,所以一进启动页就 EXC_BREAKPOINT 秒退。崩溃二进制 UUID 与 10/8 的 4.0.5 Archive 一致。

这个问题,其实在上次兼容适配iphone duo的时候修复过一次了,不过那次是在家里的mac mini上操作的,而mbp的xcode 不知道什么时候也升级到27了,这就导致打出来的包使用了ios 27的sdk,就直接引入了这个bug。

当然,更诡异的是自己从26升级到27的系统上,之前安装的findu并没有闪退,卸载重装就是就闪退了。

这个东西的原因后来也想明白了(后知后觉,今天才想明白),在ios26上已经完成文件复制了,所以系统升级之后,并不会再次触发文件复制。而新装的app在启动的时候会复制文件就bug了。

所以,如果uniapp 离线打包ios27闪退,那就直接修改离线工程的代码吧xcode_project/Findu/Findu/NSFileManager+Findu.m(+load swizzle):

#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <string.h>

// iOS 27 SDK 起,Foundation 会在 -[NSFileManager setDelegate:] 作用于
// defaultManager 且 delegate 非空时主动陷阱(EXC_BREAKPOINT)。
// DCloud PDRCoreApp copyOverlayFile 启动时仍靠这个委托把 www 合并进沙盒,
// 会在启动页秒退。兄弟项目 dayima 已验证本补丁。
//
// 非共享的 NSFileManager 不会陷阱。先在临时实例上走系统实现,
// 再把 _delegate / _weakDelegateValue 挪到 defaultManager 上。
// _delegate 是 assign。_weakDelegateValue 必须强持有:
// object_setIvar 对未知所有权按 unsafe_unretained 写入,临时实例释放后
// NSWeakObjectValue 被回收,后续文件操作会打到野指针。
static IMP findu_originalSetDelegate;

static void findu_nsfilemanager_setDelegate(id self, SEL _cmd, id delegate) {
    if (delegate != nil && self == [NSFileManager defaultManager]) {
        NSFileManager *donor = [[NSFileManager alloc] init];
        ((void (*)(id, SEL, id))findu_originalSetDelegate)(donor, _cmd, delegate);
        Ivar delegateIvar = class_getInstanceVariable([NSFileManager class], "_delegate");
        Ivar weakIvar = class_getInstanceVariable([NSFileManager class], "_weakDelegateValue");
        if (delegateIvar != NULL) {
            void *rawDelegate = (__bridge void *)delegate;
            void *slot = (char *)(__bridge void *)self + ivar_getOffset(delegateIvar);
            memcpy(slot, &rawDelegate, sizeof(rawDelegate));
        }
        if (weakIvar != NULL) {
            object_setIvarWithStrongDefault(self, weakIvar, object_getIvar(donor, weakIvar));
        }
        return;
    }
    ((void (*)(id, SEL, id))findu_originalSetDelegate)(self, _cmd, delegate);
}

@interface NSFileManager (Findu)
@end

@implementation NSFileManager (Findu)

+ (void)load {
    Method method = class_getInstanceMethod(self, @selector(setDelegate:));
    if (method == NULL) {
        return;
    }
    findu_originalSetDelegate = method_getImplementation(method);
    method_setImplementation(method, (IMP)findu_nsfilemanager_setDelegate);
}

@end

以前做的东西,并没有很多与硬件交互的内容,所以uni 『从从容容游刃有余』,现在随着对接apple watch 以及carplay,uni变得越来越『匆匆忙忙连滚带爬』了。

毕竟,启动闪退这种bug对于任何app来说都是无法忍受的。好在这次苹果的审核还是非常不错的,提交之后第二天就通过了。

这一桩桩一件件,怎么想都是事儿。只是,真的要推倒重来,真的太需要勇气了。毕竟,已经修复了无数的问题。

所以,做产品,如果要长期做,宜长远考虑。

闺蜜圈 [v 5.2.30]

更简单更智能的大姨妈记录app:https://guimiquan.cn

版本号:5.3.20

更新内容:
1.会员权益大调整,只需要开通VIP就可以体验语音识别,快捷指令,再也不用一条一条记录啦。一条命令就可以记录数条信息,补充记录几天的数据也不用来回切换日期了。
2.修复了一些已知bug
3.iOS版本支持Apple Watch

APP以及小程序二维码,扫描即可安装体验:

   

这次更新的时间间隔比较短,但是整体的ai快捷指令处理能力得到了质的飞跃,采用新的mcp服务模式,不再通过指令匹配。同时,增加了apple watch 支持,在设置app背景图片之后,手表的背景会同步设置。

视频:

当然,如果大家感兴趣可以关注我的抖音,每天分享健康知识。

跟着姐姐一起涨知识哦,各种各样的小知识。

 

ccda大灾变类似游戏

✇ACEVS
作者 ACEVS

Releases · CleverRaven/Cataclysm-DDA 测试版本。
这游戏确实复杂,分支有的不刷牙会牙痛,牙痛影响各种活动的成功率,操作也是很复杂,这个游戏后来有了画面,之前是文字游戏,@代表你,Z代表僵尸,世界都是阿斯卡码构成的,快捷键得专门背一背,不然用分级菜单也行,就是慢很多,也是回合制的,不过是这种回合制,你停下来僵尸也停下来的,你连续走,僵尸也连续走,感觉还行,至少不用操作回合结束。这个造车,造各种东西都行,各种状态信息也很多,可能优势就是样式文字描述一切,容易实现吧,比如撤下了窗帘,做成了背包,几个字就达成了,所以容易做复杂了。这个游戏手机版感觉没法玩儿,操作菜单比较累哇。哈哈

同样豆包还推荐了终点站,僵尸毁灭工程,废土求生,末日余生有的是回合制的,直接放弃。僵尸毁灭工程似乎也不错,即时的,操作比cdda简单不少。容易上手。画面有点仙剑奇侠传的感觉。哈哈。

Releases · 00-Evan/shattered-pixel-dungeon
破碎像素地牢这个感觉也不错,操作不复杂,地图随机。手机电脑都能玩。
可能排名就是看下地牢的层数吧。

为啥喜欢像素类的,一般都不是3d的感觉。不容易头晕哇。

告假

以前听过一个有些悲伤的笑话——甚至有点过时。

一个专栏作家突然想休息,就在自己每周固定栏目的内容里,写了一篇“告假”的文章。很快,杂志社收到了投诉信,投诉的倒不是这个专栏作家暂停更新专栏,而是有读者认为,这个作者停刊,是否意味着杂志也被缩减了页数,特别是每次印刷在这个专栏作家书页背后的“笑话集锦”。杂志社出面解释,直到把以前那个专栏作家的版面都暂时替换成了笑话集锦,才平息风波。

这个故事还有第二集,不过你大概也猜到了会如何——专栏作家休假结束,复出后杂志社又被投诉了——“把笑话集锦还给读者!”


之所以说这是一个有些“悲伤”的笑话,是因为无论怎么解读,最终结果都可能是那个“专栏作家”太把自己当回事了,以至于他就算没有告假,就这样销声匿迹在杂志里,可能都没有人发现。但这件事本身很难以偏概全,保不齐也有喜欢他的读者,为了这些读者写一个所谓的“告假文”,又显得克制而礼貌。

我小时候,家里还订阅过“节目预告”的报纸。我已经忘记那份报纸的名字,只记得爷爷会在收到这份报纸的时候,戴着老花镜,用带着酒精味的红色记号笔,在上面认真圈画着不同频道、不同时段的节目。勾选的是他特别想看的,而一些固定的节目,他都可以熟稔于心,在节目开始前准时观看。

他有时候会抱怨,有些节目就突然结束了,是因为看到报纸的节目预告,才知道自己喜欢看的节目莫名其妙地被替换掉。

但是没有这份报纸,他很有可能也会意识不到一些节目的来去。很快,他就会找到新的、喜欢看的节目。至于那个节目要不要复播,对他而言已经不太重要,重要的是,他在拿到报纸时,又可以预测下一周的节目。


前几天,跟一个拖延症非常严重的朋友闲聊,她说自己每天都在找各种理由拖延做事,最近甚至已经学会了给自己非常正式地写“告假书”。具体是指,她会在朋友圈感慨自己深陷困顿,感悟一番人需要坚持的真谛。但事实上,写完这些东西,看上去她马上就要做事了,但发完朋友圈本身,就已经让她觉得自己已经“不拖延”了,然后又开始了新一轮的拖延。

久而久之,“告假书”本身已经不能再满足她,于是开始了更隆重的“仪式感”,比如在自己的专栏上写“自己需要假期”的原因——对,她是个专栏作家。且在听完我给她讲完这个笑话之后,把我狠狠骂了一顿,说我在把她拖到阳光下暴晒。

她甚至已经准备好要在专栏上写一篇所谓的“告假书”,谈谈她对于“给自己放假”的态度。我倒是无情,问了一句:“有人在乎吗?”

不过,她很快发现了这件事的死结在哪里——这个所谓的告假书,是为了说服别人允许自己偷懒?还是说服自己应该停下来休息休息?既然是说服自己,那又为什么一定需要发出来呢?

于是,这个问题被加入了一个第三视角——自我说服的过程是否需要被见证?


如果没有那份报纸,我爷爷大概率是发现不了一些节目被电视台无情砍掉,因为总有节目会补位这些空缺时段,更别说离开了这些节目他就没得看了。

如果在杂志上发布一篇“告假书”,结果根本没人在乎,原本用来自我说服的戏码,就变成了无人见证的独角戏。如果非要引入这个第三方视角,就必然会陷入奇怪的对内死循环。不过这里得分开说:

  • 第三方视角是被自己操控的,与自己有同样的价值观。
    • 这件事朝着极端发展,就是弄臣与独裁者;即权力的周围是对权力的附庸,而非真实的信息。
  • 第三方视角不透明,仅起到见证作用。
    • 这件事朝着极端发展,就是皇帝的新衣;为了维系权力的存在,只能自我欺骗,或是利用权威迫使他人认同。
  • 第三方视角不被自己控制,可能完全曲解自己的价值观。
    • 这件事朝着极端发展,就是囚徒困境;为了澄清自己,就必须被拖入对方的自证陷阱之中,即:
      • 你保持沉默,对方认为你默认了。
      • 你出面澄清,对方认为你急于辩解。
      • 你彻底离开,对方认为自己赢了。
      • 你继续参与,对方认为自己成功地把你拖入自证陷阱。

或许,问题并不在于一个人是否需要被见证,而在于,当他需要第三方来确认自己的行为是否合理时,就已经将一部分判断权交了出去。

原本只是自己决定要不要休息,现在却需要考虑别人是否理解自己的休息;原本只是想结束一段争论,现在却必须面对别人如何解释自己的沉默。甚至,即使没有任何人真正表达意见,只要我们开始预判他人的反应,这种外部评价就已经进入了自己的决策过程。

人们以为自己是在解释行为,实际上却可能逐渐开始为他人的理解负责。而当一个人试图控制这种解释,或者试图摆脱这种控制时,问题就超出了自我说服的范畴。

它便开始涉及权力。

好了,图穷匕见,今天要聊的内容不是在为自己请假,而是扯出了一个更大的话题——权力的三元悖论。

——

感谢订阅莫比乌斯,如你有任何疑问、观点交流,请前往创作者频道,或私信联系。

What’s next for the indie web?

I have been blogging in English for some time, but this is my first time participating in an indie web conversation. So I think I should introduce myself first.

I’m Eltrac. I’m mainly a web developer but I like all kinds of thing about programming. I code in Go, Clojure and Lua, and I explore new tech all the time. I usually blog more than three times a week, but most of my posts are written in Chinese. I recently became an active member of Codeberg e.V. and have been working on my own FOSS project weepinbell for a while. It’s a new Webmention receiver written in Clojure.

In this post, I will talk about why I developed weepinbell, how I designed its architecture, what I think of the IndieWeb movement and many things.

Why weepinbell?

I wrote to Brennan recently and he was really nice to mention weepinbell on his blog . In that email, I talked about how I set a new goal for weepinbell (i.e. an alternative to webmention.io) because of Aaron Parecki rewriting webmention.io with Claude. Later, in Aaron’s response to Brennan’s new post , he mentioned weepinbell as “a direct response to my rewrite”.

I would like to make things clear. I didn’t start developing weepinbell because of Aaron’s rewrite. I started early in this May to learn Clojure. I’ve been blogging (in Chinese) for years and of course I love the concept of IndieWeb. Naturally, my practice project for learning a new language involves IndieWeb technologies.

The motive is that I want to get my hands dirty with the Webmention standard. I read through the W3C specification document and started putting things in parentheses. You can still find snippets from that document in my code as comments. I bascially code against the specification. It was a fun experience for me.

 (if-let [error-msg (check-request source target allowlist)]
 ;; respond if request verification failed
 (bad-request {:status 400
 :message error-msg})
 ;; proceed if request is ok
 (do
 ;; The receiver SHOULD check that target is a valid
 ;; resource for which it can accept Webmentions.
 ;; This check SHOULD happen synchronously to reject
 ;; invalid Webmentions before more in-depth verification begins.
 ;;
 ;; Webmention verification SHOULD be handled asynchronously
 ;; to prevent DoS (Denial of Service) attacks.
 (put! wmc new-wm)
 ;; respond with 201 when Webmention passed checks and
 ;; was sent into queue, include a Location header
 (let [wm-id (digest (str source target))
 wm-url (str (:base-url config) "/api/mention/" wm-id)
 response {:status 201
 :message "Webmention is accepted and pending for verification."
 :url wm-url}]
 (created wm-url response))))))

This snippet is from receiver.clj .

After the initial quick and rough implementation, I stopped working on weepinbell for a few months. And it had been receiving Webmentions for my blog during that time. Everything worked and I was content. It was bascially a personal tool.

Then the webmention.io rewrite came to my attention.

Why does it bother me? I don’t even use webmention.io any more. I see some of my friends seeking alternatives, and… there aren’t many to choose from! There is webmentiond by Horst Gutmann and some other implementations here and there. My friend Chlorine developed CircleAt in Rust. And I’m sure there are many more. But frankly, none of them truly count as “alternative to webmention.io”.

Don’t get me wrong. I think many of them are great for their purpose, i.e. small service one can self-host. However, they can be quite difficult for the non-tech indie web folks and those who simply do not own a server. They need a public instance.

Refactoring for scalability

I decided to continue development of weepinbell and make it “the next webmention.io”, at least that’s what I’m going for.

So I took a closer look at my code. They’re not that messy, well partitioned (for the most part) and maintainable. I can swap some of the parts easily because I used hook functions and vtables.1 The architecture is flexible enough, and the Lisp power also makes modifying software really easy.

The following part will be somewhat technical. Feel free to jump to the next section if you don’t want to read about system design. The bottom line is: weepinbell would be lightweight enough for people to self-host; it would also be scalable enough to support large traffic.

I’m a Go programmer by the living.2 And Clojure’s core.async library greatly resembles Go’s concurrey programming style, which means my skills of building scalable applications in Go translates.

Webmention is not big data. Storage is definitely not the bottleneck. In fact, up until a few commits ago , weepinbell does not even support any type of database. It unloaded everything in a single file and then loaded it back when needed. And it just… worked, for months.

Of course this is neither performant nor safe. If I want to build something reliable, I need a database. If you have taken a look at that commit I linked, you might notice that the business logic is untouched. All that’s added is a new storage implementation, a new config option, and a few lines in the main component (core.clj).

I’ll probably elaborate on architecture flexibility in another post. That’s something I’m really proud of. The gist is that using a new type of database and ORM is easy, and will be just as easy if I ever decided to redo the storage layer again.

;; all I need to make sure is that the new storage implementation
;; returns a valid storage vtable, like this:
(defn use-store [db-file]
 (let [ds (make-datasource db-file)]
 (create-tables ds)
 {:append (partial insert-webmention ds)
 :update (partial update-webmention ds)
 :delete (partial delete-webmention ds)
 :get (partial get-webmention ds)
 :get-by-domain (partial get-webmentions-by-domain ds)}))

Beside a new SQLite implementation, I added a storage worker that handles I/O asynchronously. So when processing a new webmention, the processor won’t have to wait for DB transaction (or appending to a file; it does not care about what’s going on underneath) to end. It simply delegates to the storage worker and keeps processing the next webmention.

The processor delegates by putting an operation object into a channel. It’s similar to what I already have for receiver. When a new webmention request is sent to the web server, receiver does some basic checks (e.g. does source and target look like real URLs?) and then put the request into the webmention queue. A processor will pick it up and make sure source has truly mentioned target, parse microformats, wrap data into a valid record, and hand it over to storage worker.

Reading from a channel is thread-safe. And since I/O is handled internally by storage worker, it can also be thread-safe, without the need for a mutex lock. So we can add as many processors as we want to handle webmentions concurrently.

The overall architecture looks like this:

Architecture of the receiver part of weepinbell, drawn using Excalidraw

That’s horizontal scaling. For self-hosters, simply set pipeline-concurrency to 1, and there will be only one processor handling webmentions, using a reasonable amount of RAM and CPU.

For large groups or someone who wants to host a public instance, change a number in config and you’re good to go.

All of that is compiled to a single .jar.3

The microformats nightmare

Before I move on to a non-tech topic, there’s one thing I have to complain: Using microformats markup is easy. Parsing it is really not.

Here is an example snippet from microformats.io .

<div class="h-card">
 <a class="p-name u-url" href="http://blog.lizardwrangler.com/">Mitchell Baker</a>
 (<a class="p-org h-card" href="http://mozilla.org/">Mozilla Foundation</a>)
</div>

It’s just regular HTML with standardized class names like h-card and p-name. It’s easy to add a few classes to your HTML. However, it’s still hard to parse structural data from HTML with just a few more classes.

Good thing there are already some parsers available… right?

Production ready parsers are available for: Go, Node, PHP, Python, Ruby.

Right… I’m using Clojure…

Clojure can use Java code, since it runs on top of it. I found mf2j , an “In-development Java parser for microformats2”. It hasn’t been updated since… 10 years ago.

There is a Clojure implementation . It’s archived, with its last update committed 11 years ago.

Do I implement a new one myself? Do I pick up where they left off? How do I make sure I don’t burn out and abandon it as well? After all, Clojure is a niche language and IndieWeb is also kind of niche. I can’t imagine there being another Clojurist building something that relies on microformats. At least, I don’t know anyone like that.

I briefly considered running a micro-service that wraps the Go parser, and weepinbell can talk to this service using RESTful API or gRPC. But it feels heavy and everything just won’t fit in a single .jar.

So how can Clojure run programs written in a non-JVM language? What else runs on JVM? Scala, Groovy… Wait, will WebAssembly work?

Yes! WebAssembly runs on JVM. There is a native JVM WebAssembly runtime called chicory .

I spent an afternoon studying Extism and chirocy. Then I wrote a tiny little Go wrapper of Will Norris’ parser library .

package main

import (
	"bytes"

	"github.com/extism/go-pdk"
	"willnorris.com/go/microformats"
)

//go:wasmexport parse
func parse() int32 {
	input := pdk.Input()
	r := bytes.NewReader(input)
	data := microformats.Parse(r, nil)

	pdk.OutputJSON(data)
	return 0
}

Then I compiled it to .wasm using tinygo compiler, bundled the .wasm inside .jar, and called the Extism plugin from Clojure using chicory. Voilà! Here’s mf2clj , a Clojure wrapper of WebAssembly compiled from a Go wrapper of an existing microformats parser.

By the way, I made a little logo just for fun.

A combination of Clojure logo and the microformats logo

You use it just like a normal library in Clojure. And it’s surprisingly fast.

(require '[mf2clj.core :as mf2clj])
(mf2clj/parse html-string)

More surprisingly, bundling a .wasm binary and the WebAssembly runtime inside the .jar is not as heavy as I thougt it would be. The .jar only grew 2 MB in size. Am I really running Java?

Nevertheless, the nightmare isn’t over yet. In the begining, I settled for the incomplete mf2j library and used it for a while. At that time, I called the JSON output “data structure from Hell”. I still do —— Everything is an array! Everything is deep inside something’s properties or children! Nothing is deterministic! Every website’s format is different!

{
 "items": [{
 "type": ["h-card"],
 "properties": {
 "url": ["http://blog.lizardwrangler.com/"],
 "name": ["Mitchell Baker"],
 "org": [{
 "value": "Mozilla Foundation",
 "type": ["h-card"],
 "properties": {
 "name": ["Mozilla Foundation"],
 "url": ["http://mozilla.org/"]
 }
 }]
 }
 }],
 "rels": {},
 "rel-urls": {}
}

In the end, I had to write a smaller parser to parse output a the original parser. I called this feature microformats reduction. I remember webmention.io having something similar.

"microformats": {
 "author": {
 "name": "Mitchell Baker",
 "url": "http://blog.lizardwrangler.com/",
 "photo": "https://blog.lizardwrangler.com/photo.png"
 },
 "type": "mention",
 "published": "2026-07-25T00:00:00-07:00",
 "content": {
 "html": "..."
 "text": "..."
 }
}

If something does not exists, it’ll just be null. The format is not final yet, I will make some adjustments. This can be turned off by ?microformats=raw when querying webmentions.

Also, I think more than half of the bugs I found in weepinbell have something to do with microformats-related features. Maybe we should switch to Open Graph and JSON-LD, folks?

Anyway, I’m just glad it’s finally working.

Slowing down

At this point, I’ve almost finished everything I have planned for the v1.0.0 release: a proper database, horizontal scalability, up-to-date microformats parser. As for hosting a public instance, that’ll involve authenticating users and making a dashboard for them to manage webmentions. That would be a separate project.

I plan to develop a service that sits in front of weepinbell, handling logging in and stuffs. I mentioned the idea in the project’s PHILOSOPHY.md .

I want to keep the core of weepinbell minimal. Those who want to be their own sysadmins don’t have to care about authentication. They don’t even need a frontend. They only need to self-host one .jar and use API to query webmentions, use RSS to receive notifications and use webhook to automate stuff. These are the built-ins.

A platform like webmention.io needs more than that. If I want to keep weepinbell “for both individuals and large groups”, I have to separate things. Also, this makes everything modular and swappable, a pretty good architecture decision.

My writing to Brennan was an attempt to get more Clojure developers on the team. Well, that didn’t go well. For the new platform, which will be named Ringabell4, I want to use more mainstream stack, probably Go, so that it’s easier for people to get involved.

For now, I’m still working on weepinbell’s test suite. The current test coverage is more than 83%, but there are still some edge cases that haven’t been covered by tests. I had to test a lot of paths by hand. Also it’ll take some time for the new SQLite implementation to be stable.

I don’t think we need to or should move fast when it comes to developing reliable software, with or without LLMs.

Independence, and now decentralization

In reply to Brennan’s recent question, “What do we do now?” , I think it’s finanlly time to get more decentralized.

Decentralization is never about moving away from the corporate web (that’s independence). It’s about not relying on a single point , no matter what the point is and who it involves.

I agree with Brennan on not conflating IndieWeb and the lower-case indie web. The IndieWeb camp is a nice community and a great introduction to the indie web. But I think we should form more indie web communities other than the IndieWeb camp.

omg.lol is an example. It’s a fun web community by Neatnik . They provide infrastructure like a simple profile page, Fediverse instance and email forwarding. Brennan is also building folk.zone , which hosts a fork of webmention.io and many more.

Those two may not be exactly alternatives to the IndieWeb camp, but they can be. And there can be more for people to choose from.

Tech folks can self-host their own infrastructure if they want. For the non-tech folks, there should be more alternatives to what the IndieWeb camp has to offer. Poeple who are capable can host public services and take a small community.

After all, communities are what brings the indie web together. We can and should build more communities (this is probably more like polycentricity rather than decentralization). We can have the LispyWeb for lisp programmers, ArtsyWeb for artists, and Indie Indie Literature Club!5 for book lovers. Those are just some random names I came up with.

Perhaps the upcoming Ringabell might be the next cozy small community. Who knows? To everyone who’s nice enough to finish reading this, I hope we can all find our people.


  1. A vtable in Clojure is basically a hashmap whose values are functions. It’s a technique mentioned in one of Uncle Bob’s books, Functional Design. ↩︎

  2. Actually I’m at the very begining of my career. Don’t think of me as an expert of anything. XD ↩︎

  3. Clojure runs on JVM, so it compiles to JVM bytecode, just like Java. ↩︎

  4. Meaning “ring a bell”. ↩︎

  5. The referrence is a galgame called “ Doki Doki Literature Club ”. :3 ↩︎

地球online

✇ACEVS
作者 ACEVS

和wife他们看了个几个动物视频,
大冰泡虎鲸,团团围住薄冰上的豹海豹,不是探出头看豹海豹位置和数量,豹海豹也不是吃素的,他主要吃企鹅和其他海豹为生,他那个獠牙,满口尖牙,注定他不好惹的,大冰泡虎鲸集体行动,一起行动,从冰块底下把冰块用尾巴拍裂,冰块小到,最后豹海豹坠入海中,大冰泡虎鲸不是和它肉搏,而是轮番上阵,咬着豹海豹的尾巴,王海里深处拖,豹海豹开始还有搏斗的意思,后面只有想着浮出海面透口气,大冰泡虎鲸不给他机会,溺死了他。大冰泡虎鲸这一套方案据说靠最老的母海豹传承,她来规划组织教学分配食物.

袋熊,就是那个拉的屎,是方块型的,袋熊。他喜欢挖洞,洞很大,虎鼬跑到它洞里吃它,它在洞里,屁股留给虎鼬,虎鼬头部靠近他屁股的时候,时机到了,袋熊屁股向右后上快速撅起,运气好的话虎鼬直接脑部重伤挂掉,运气不好的话,面部骨头骨折,再不好话一疼,虎鼬就跑了。

Coffee Break Clojure, Transducer

在第三期《 只用圆括号怎么够? 》里,我讲到了 reduce。

先来简单复习一下:reduce 最少接收两个参数,形如 (reduce f coll),其中 f 是接收两个参数的函数,形如 (f x y);reduce 遍历 coll 中的每个元素,先对前两个元素求 (f a1 a2),1然后求 (f (f a1 a2) a3),以此类推。

(f x y) 这种函数叫作归约函数(reducing function)。

归约、Fold、高阶函数

之前我们用作示例的代码如下:

(def numbers '(1 43 231 23 99))

(reduce + numbers)
;; => 397

+ 可以视作归约函数,因为他可以这样调用:(+ x y)。当我们对上述代码进行求值时,主要执行了以下步骤:

  1. (+ 1 43) 得到 44
  2. (+ 44 231) 得到 275
  3. (+ 275 23) 得到 298
  4. (+ 298 99) 得到 397

使用 + 作为归约函数,对 numbers 进行归约(reduce),就实现了累加。

在函数式编程里,归约(reduce)也叫作累积(accumulate)、聚集(aggregate)、压缩(compress)和注入(inject),不过更常见的名字是折叠(fold)。折叠分左折叠(foldl)和右折叠(foldr)。

还记得第三篇讲过的 Cons 和 Lisp 的列表构造方式吗?Fold 的结构就像是函数版本的 Cons。

(reduce f [1 2 3 4 5])
;; 等价于
(f (f (f (f 1 2) 3) 4) 5)
(list 1 2 3 4 5)
;; 等价于
(cons 1 (cons 2 (cons 3 (cons 4 (cons 5 nil)))))

Clojure 的 reduce 默认是左折叠,即 foldl:

左折叠示意图;图源: 维基百科

要在 Clojure 里实现右折叠,只能把待操作的列表倒序:

(reduce f (reverse [1 2 3 4 5]))
;; 等价于
(f (f (f (f 5 4) 3) 2) 1) ; 实际上还是左折叠
;; 如果 f 和 + 一样满足交换律,就等价于
(f 1 (f 2 (f 3 (f 4 5))))) ; 等价于右折叠

折叠中的 f 本身也可以是折叠。还记得 into 吗?

(into [1 2 3] [4 5])
;; => [1 2 3 4 5]

;; 等价于
(reduce conj [1 2 3] [4 5]) ;; 这里的 reduce 以 [1 2 3] 为初始值
 ;; 如果没有初始值,就会用第一个元素做初始值
;; 等价于
(conj (conj (conj [1 2 3]) 4) 5)

如果要打平一个向量,比如把 [[1] [2 3] [4 5]] 变成 [1 2 3 4 5],就可以用 into 作为归约函数(reducing function),也就是把 (reduce conj ...) 作为 reduce 的 f。

(reduce into [[1] [2 3] [4 5]])
;; => [1 2 3 4 5]

;; 等价于
(reduce #(reduce conj %1 %2) [[1] [2 3] [4 5]])
;; 等价于
(reduce conj (reduce conj [1] [2 3]) [4 5])
;; 等价于
(conj (conj (conj (conj [1] 2) 3) 4) 5)

在 Clojure 中,能够被放在 reduce 里使用的函数就叫作归约函数(reducing function)。这个概念与函数式编程和 Lambda 演算的高阶函数(Higher-order function)有关,据说微积分中的导数也算一种高阶函数,但我这篇文章不是讲数学的(我也不会数学),所以就点到为止。

改造归约函数

总结一下,归约函数就是这样的一类函数:

(f result input) -> new result

这样的函数可以相互嵌套使用,不过一般传给 reduce 用。

接下来要引入一种新的函数,我没有找到中文译名,暂且称作变约函数(transducer)。它长这样:

(t (f result input)) -> (new-f result input)

Transducer 接收一个归约函数,返回新的归约函数。

返回函数的函数可能有些抽象,但是在 Clojure 中很常见。我举几个例子解释 Transducer 的用法。

假设我们要对向量自增,然后再累加,就要这样写:

;; 下面这个函数先是自增 [1 2 3 4] 得到 [2 3 4 5]
;; 然后再对 [2 3 4 5] 进行累加
(reduce + 0 (map inc [1 2 3 4]))
;; => 14

能不能让 + 这个归约函数,在把之前的结果和下一个元素累加起来之前,先给要累加的元素 + 1?也就是说,我们不用遍历一遍列表,生成新的、自增后的列表,然后再累加这个列表,而是在累加的过程中就把自增的操作也做了。

我们可以这样写:

;; 下面这个函数用 (map inc) 这个 Transducer
;; 把 + 这个归约函数,转换成了新的归约函数
;; 这个新的归约函数的作用是:先给单个元素 +1,然后再累加
(reduce ((map inc) +) 0 [1 2 3 4])
;; => 14

这里我们看到了 Clojure 1.7 引入的 map 的新用法。一般而言,(map f coll) 的作用是把 f 作用在 coll 中的每一个元素上,然后生成新的元素。

而 (map inc) 则是生成了一个 Transducer,我们把 + 作为这个 Transducer 的参数传入,得到了新的归约函数。也就是说,我们将 (map inc) 和 + 组合,构造了新的数据转换算法。 对集合中的元素 inc,然后再折叠 + 实现累加。

这种转换与具体类型无关,与惰性无关,与执行顺序也无关,只是纯粹的算法。非常便于复用。

将具体类型与转换算法解耦

Clojure 的哲学是简洁,这点并不只是体现在语法(syntax)上,还体现在语义(semantics)和语言的设计上。Rich Hickey 在《 Simple Made Easy 》里讲到,简单(simple)的东西就是不和其他东西交织(complect)在一起的东西。

Java 类不简单,因为它既是命名空间,又是数据结构,还定义了数据上的操作——类把三个东西交织在了一起。反观 Clojure,命名空间是单独的概念。

标照 Rich 本人对简单的定义,标准库里的 map、filter、reduce 等操作序列的函数,都不够简单,因为他们不仅涉及做什么操作(what to do),还涉及了怎么做(how to do it)——预设了惰性,预设了数据操作的顺序(序列都是从前往后线性遍历的),预设了数据的表示方式(返回的是序列)。

如果 map、filter、mapcat 等函数,能够与数据类型(序列)解耦呢?也就是说,如果 map 只定义做什么操作(what to do) ,把怎么做(how to do it)交给其他组件呢?

比方说,map 可以这样实现:

(defn map [f]
 (fn [f1]
 (fn [result input]
 (f1 result (f input)))))

这个 map 是构造 Transducer 的函数,它接收函数 f,返回了一个返回函数的函数。我们之前看到的 (map inc) 就返回了一个 Transducer。

这就是对做什么(what to do)的定义。

reduce 则定义了怎么做(how to do it),因为 reduce 是对序列的操作,而且是具有惰性的,返回值是惰性序列。所以把 reduce 的怎么做(惰性地、顺序地、当作序列执行左折叠)与 ((map inc) +) 的做什么(“元素自增后再累加”)组合,就得到了完整的数据操作。

如果不想要折叠呢?我能不能直接用 (map inc) 累加元素?

将 sequence(输入和输出数据为序列、惰性、顺序操作)与 (map inc)(“自增集合里所有的元素”)这些要素组合起来,才能得到完整的数据操作:“自增序列里所有的元素逐一自增,返回惰性序列。”

(sequence (map inc) [1 2 3])
;; => (2 3 4)

如果不想用序列和惰性序列,可以换成向量或者集合:

(into [] (map inc) [1 2 3])
;; => [2 3 4]

(into #{} (map inc) [1 2 3])
;; => #{4 3 2}

如果没有用 Transducer,我们就必须先把向量变成序列,然后再把序列变回向量。因为 map 和许多函数都只操作序列和惰性序列,和具体的数据类型耦合。

(map inc [1 2 3])
;; => (2 3 4) ; <- 这里得到的是序列,而非向量

(vec (map inc [1 2 3])) ; <- 必须手动转换成向量!
;; => [2 3 4]

(into [] (map inc) [1 2 3]) ; <- Transducer 不关心数据类型
;; => [2 3 4]

上一篇《 异步编程和并发控制 》提到的 channel 也可以接收 Transducer,携带 Transuder 的 channel 会对经过它的所有数据做变换。

(def growing-channel (chan 1 (map inc)))
;; => #'user/growing-channel
(put! growing-channel 1)
;; => true
(poll! growing-channel)
;; => 2

Transducer 的好处就是,由于他只定义了抽象的「做什么」,而不关系具体的「怎么做」,所以可以非常轻易地用在任何地方,不像 map 和 filter 只能作用于序列(或者要把向量、集等其他数据类型转换为序列)。

组合 Transducer

一般来说,要做 Clojure 里做一系列数据操作,会组合使用很多序列函数。

(->> [1 2 3 4 5 6 7 8]
 (filter odd?) ; 1. 过滤,只留奇数
 (map #(* 2 %)) ; 2. 全部乘 2
 (reduce +)) ; 3. 累加
;; => 32

有了 Transducer,我们可以把这一系列操作抽象出来,定义成一个独立的、可复用的操作。

(def double-odd-numbers
 (comp 
 (filter odd?)
 (map #(* 2 %))))

; 可以用来累加
(reduce (double-odd-numbers +) 0 [1 2 3 4 5 6 7 8])
;; => 32
; 等价于
(transduce double-odd-numbers + [1 2 3 4 5 6 7 8])
;; => 32

; 可以不加,返回集合
(into #{} double-odd-numbers [1 2 3 4 5 6 7 8])
;; => #{6 2 14 10}

; 如果你想,还能交给 channel
(def double-odd-chan (chan 1 double-odd-numbers))

comp 的作用是把函数组合起来。(comp f g) 就相当于 (f (g ...))。除了用来组合 Transducer,还可以组合普通的函数:

(filter #(not (zero? %)) [1 2 0 3 0 2 0])
;; => (1 2 3 2)

; 等价于
(filter (comp not zero?) [1 2 0 3 0 2 0])
;; => (1 2 3 2)

不妨做个小练习,定义一个 pipe 函数,作用是接收可变数量的函数2,将它们构造成类似 -> 箭头宏的流水线结构,但是不执行这个结构,而是返回函数。比如 (pipe f1 f2 f3) 就返回按顺序执行 f1、f2、f3 的函数,(pipe f1 f2 f3) 相当于 (f3 (f2 (f1 data)))。

参考答案
(defn pipe [& functions]
 (apply comp (reverse functions)))

或者:

(defn pipe [& functions]
 (fn [value]
 (reduce (fn [result f] (f result)) value functions)))

要注意 Transducer 和一般函数的区别。

(comp
 #(map (fn [x] (* 2 x)) %)
 #(filter odd?))
; comp 的结果是 (map fn (filter odd? ...)),很符合直觉
; 返回的函数用来直接操作序列

(comp
 (filter odd?)
 (map (fn [x] (* 2 x))))
; comp 的结果看似是反过来的 (filter odd? (map fn ...)),其实不然
; comp 并不是 -> 宏,而是函数,会先对参数求值
; filter 和 map 求值之后得到了 Transducer
; comp 是把两个 Transducer 组合起来了,而不是把 filter 和 map 组合起来
; 返回的函数用来和 reduce, into, sequence, chan 等一起使用

最后

这篇的内容可能略显抽象,因为涉及了很多对函数的操作,而不是对数据的操作。如果没理解也没有关系。Transducer 能让数据类型与算法解耦;能轻易地组合复用;给了 Clojure 程序员更多的控制权,所以能借助它来写出性能更好的代码——这些都是好处,但没有这些好处也照样能写 Clojure 代码。

那么,回见!


  1. 也可以指定初始值,(reduce f init coll) 会先求 (f init a1),再求 (f (f init a1) a2) ↩︎

  2. 用 & 表示参数数量可变,(fn [& args]) 中的 args 就是包含可变参数的序列。 ↩︎

≡ 017|代价论与选择的自由

先回顾本周的莫比乌斯。

秀肌肉是最直观的对抗,但如果对方不接招,难免就会沦为秀肌肉的“泼妇”。有趣的不是谁输谁赢,而是在自己的规则里,小丑竟然是自己。

聊这个话题,并不是在“教写作”,而是在透过写作的手法,来试图搞清楚人性对于叙事结构的心理预期,它可以是写作、可以是短剧、也可以是操纵一个人的感受……

  • 《方块》

关于在Minecraft世界里孤独地活着……

一个由自己建立规则的世界,有权利迫使他人遵守其中的规则吗?


订阅以继续阅读

成为付费订阅者,以查看本文章剩余内容以及其他专属内容。

——

感谢订阅莫比乌斯,如你有任何疑问、观点交流,请前往创作者频道,或私信联系。

AI 为什么总是惹人议论

人工智能研究员 Nick Cammarata 发表了一篇长文,我英文不好,也不是技术领域专家。粗略读过,感觉意思是说:以前大家以为的神经网络不可理喻,其实是人类的认知错误——神经网络本身逻辑清晰。

拿神经网络里的一个具体神经元 4e:55 举例子,它既被猫脸激活也会被汽车前脸激活。人们误以为神经网络用高维空间搞出了猫和车的叠加态,总想区分开,找到一个专门的被猫激活的「猫神经元」。Nick 则认为完全没必要,也不必训练新模型来展开折叠区分猫和车,而是应该直接研究神经网络本身,按照神经网络的逻辑来理解,根本不存在叠加,分类清晰,猫下巴和车前脸都归属于 V 形这个几何意象类别……

关于这篇文章,显然我远没能清晰解读它。不过,我好像突然知道为什么 AI 总是让人们欣喜又警惕、摇摆不定了。人类制造了不趁手的工具时就会改造它,让它顺手,诚然工具的材质、属性,也要选择合适的来使用,但那些是自然的规律、上苍的造物。而大语言模型,不是因为电子的属性,不是因为硬盘的材质,就只是作为人造物、工具本身,却需要人类学习它的逻辑,就像学习如何顺应水流、接受光照一样。欣喜或警惕,都是很自然的反应。

fin.

气表、门禁和米面油

前些日子,天然气公司挨家挨户换了气表。我对这件事并没有太多感触,只是觉得终于不用每月被天然气抄表员,在微信上追着要指数了。物联网之后,每个月的账单都会自动计算。但这两天在小区听到两个老人谈天,突然把这件事又翻了出来。

其中一个老太抱怨天然气公司天天来敲门,想要进屋换气表,另一个老太问为什么不让换。一说这个,那个抱怨的老太来劲儿了,开始给另一个老太“科普”这种换表的行为,都是给用户换一个会偷偷走字的新气表。以前她每个月都可以自己看着数字,也知道自己报给抄表员的数字是不会被作假的。换了新气表,不需要用户自己抄数字,其目的就是为了麻痹用户,好在后台偷偷走字——她甚至提到了 AI,说现在这些人发明了 AI,不知道在背后搞些什么,这种新科技肯定都是用来做这些偷鸡摸狗的事情的。

另一个老太倒是也没给面子,说了一句:“我家换了,好像每个月该用多少还是多少,没变化。”

“你那是看不出来,他们就趁着过年过节,你屋头要请客吃饭的时候,它检测到了,就会偷偷给你增加。”

硬要这么说,这倒是一个很难拆开的闭环,因为无论如何,数字怎么变化,都有阴谋论可以偏向那个新换的气表,正在偷偷想办法增加用户的费用。


前几天,小区突然开始推行门禁管理制度,要求住户下载 APP、登录户主信息,以后可以用手机或是人脸识别开小区大门,便于管理。

我倒是想看看物业这一次会不会真的实施所谓的门禁,所以按照要求下载了 APP,先把户主资格给占用了。物业也很贴心,为了方便老人,他们通知小区里手机操作不便的住户,可以直接去物业录入人脸识别信息。

于是,对物业不信任的人又出现了。

“谁知道他们拿这些数据去做什么?”

“我才不得去,我看门口的保安,还不是看见个人就给他开门。”

这两天遛狗,甚至还听到有老人在小区门口跟物业吵架,几乎都是质问“你们拿了这些数据去做什么”。物业也只能解释,接下来门岗不再负责开门的事情,全市的快递员要出入小区,也是因为他们要使用 APP 才能进入,这样便于管理每个小区的人员出入情况。

吵架的老人们群情激昂,认定物业就是要用他们的数据去搞诈骗。


还是小区的事儿。这两天,小区开始搞 2027 年物业费预充值的活动,缴满一年、两年、三年会有不同档位的礼品,但几乎都是些米面油。

现在好了,这些排队缴费的,都是那些老人,也不再觉得物业有什么阴谋诡计了,都挤破头了要交物业费,甚至现场还发生了因为插队引发的冲突。提着米面油的老人挤在小区门口,对着门岗保安喊道:“给我开门。”


绕一圈,有个问题我觉得他们都没有想明白:如果在气表上动手脚、用人脸去搞诈骗更赚钱,送米面油的应该是这两件事才对啊。

当然了,话说回来——口罩和特效药,哪个有用?大家心知肚明,但为什么上门送的是口罩呢?

——

感谢订阅莫比乌斯,如你有任何疑问、观点交流,请前往创作者频道,或私信联系。

山

✇ACEVS
作者 ACEVS

上周末陪家人1.5倍速刷了这个ai片子。山原著是刘慈欣,科幻向,地心文明向地壳海洋探索最后透过大气层看到了星空。

看了一会儿二宝说这个故事我和她讲过,大致意思是的,不过这个片子是改变过不少内容的,有可能,也可能我看完书都忘记的差不多了。

片子里面那个硅基生命科技发达,信息传递很快,如果直接大量信息给人类大脑,人类就烧脑晕了过去了。只能用人类理解的方式,比如哥白尼,牛顿,居里夫人等,这些标签人物讲述他们的发展历史。

这个长视频一个半小时左右,全部ai制作的,有点像早期的flash某些动画,能发现不少问题,但是内容剪辑,故事讲述都不错,可能就不会在意那些模型的问题了。

前段时间看很多明星都没活干了。有的也开始直播带货,有的可能干其他,ai确实又省钱有高效,当明星不用被台词的时候,就注定他们早晚得下岗了,不过饭圈文化,有人估计就会有,会出来不少ai明星的估计。如果某天ai有了投票权,选举权的时候也有可能哇,他粉丝多呀。

现在小学生喜欢初音未来的感觉就不少吧,谷子经济也不错。上次看一个考上研究生毕业2年的男士,也是整了不少谷子周边玩。难道像蚂蚁收集东西的癖好,也是容易一代传一代,之前物质匮乏的时候,糖纸,烟盒,后来邮票,硬币,后来小浣熊,小马宝莉等,异曲同工。

耗费两千积分做了个家常菜谱 Recipe Hub

家常菜谱 Recipe Hub · 项目速览

Recipe Hub.png

碎碎念

这个项目纯纯靠Workbuddy参考各个开源的菜谱程序,像是现有的开源菜谱程序,很多功能并不适配中文环境,用着总是别扭,这个项目前后靠AI打磨了二十多天,基本上该做的功能都有了,可以自定义每日菜谱推送给机器人,如果有bug或者想增加功能,可以自己克隆源码,也可以在项目页提交相关。
这里主推Docker部署,已经上传Docker Hub,可以直接下载,部署只需要配置端口和存储路径。

演示站点:https://caipu.dawnlife.qzz.io/
项目地址:https://github.com/xyzbz/recipe-hub

当前版本 1.1.3。自托管的中餐菜谱系统:菜谱 → 库存 → 周计划 → 采购清单,一条链闭环。

仓库形态PHP 源码,无构建步骤,拷过去就能跑
官方镜像xyzbz/recipe-hub:1.1.3(也带 latest)
参考线上https://caipu.dawnlife.qzz.io/
详细文档功能细节看 README.md,部署三步看 DEPLOY.md

1. 技术线

层选型说明
后端PHP 8.2+(镜像内 8.3)无框架、无 Composer 依赖,手写路由 + PSR-4 风格自动加载(src/,命名空间 RH\)
数据库SQLite(WAL)单文件 data/recipe.sqlite,无外部数据库服务;结构变更走幂等迁移(PRAGMA user_version,现 v3)
前端原生 ES module + hash 路由无打包器、无 npm install,改完刷新即生效;路由形如 #/recipes/12,部署到任何路径都不用配服务端重写
接口自写 JSON APIpublic/index.php 单入口分发;写请求走 CSRF 双提交(Cookie + X-CSRF-Token)
图片一律转 WebPgd 缩放 + 出缩略图,exif 纠正手机竖拍方向;存在 docroot 之外,经 /uploads/… 由 PHP 带权限流式输出
容器php:8.3-apache单容器,编译进 gd(freetype/jpeg/webp)与 exif,开 rewrite/headers/expires/deflate

2. 功能

模块要点
菜谱库中餐单位(克/斤/两/勺/瓣/把)、份数缩放(模糊量「少许」不参与计算)、中文搜索、公开/私有、回收站、打印贴冰箱、家人留言、下厨记录、随机「今天吃什么」
食材与库存预置食材库带别名(生抽=酱油=豉油)、冷藏/冷冻/常温/干货柜、过期提醒、按现有食材倒推能做什么菜
膳食周计划拖拽排一周三餐、一键换菜、整周模板、指定时段一键转采购清单
采购清单同名食材跨菜谱自动相加、按买菜动线分组、勾选已买、买回一键入库
定时推送企业微信 / PushPlus / Server酱 / WxPusher / 自定义 Webhook(飞书·钉钉·Telegram),到点推「今天吃什么」
权限与安全管理员 / 读写 / 只读三档、可选游客浏览、登录失败锁定、password_hash 加盐、会话在库里、CSRF 双提交
备份恢复只有一个入口:后台「备份」。一键产整站 zip(数据库 + 全部图片),恢复时先体检再铺图换库,换库前自动留 before-restore-* 快照
迁移自家 JSON 导入导出;cli/import-mealie.php 从 Mealie 整站迁移(含图片)
其它深色模式、从 URL 导入未做、只做 Web(手机浏览器移动优先,可添加到主屏幕当 PWA 用)

3. 部署环境要求(两条路线通用)

项目要求
PHP8.2 及以上(8.3 已验证;8.1 未测)
必需扩展pdo_sqlite、sqlite3、mbstring、fileinfo、session、json
图片扩展gd(需 WebP + JPEG + PNG + FreeType)、exif —— 缺了图片功能残废
数据库无(SQLite 自带驱动)
Web 服务Apache(需 mod_rewrite)或 Nginx
目录权限data/、data/uploads/、data/backups/ 必须可写
定时任务可选,只有「膳食计划定时推送」需要(每分钟跑一次)
资源占用极低;镜像约 500 MB,运行内存几十 MB 起步

Web 根目录必须指向 public/ —— src/ 和 data/ 在上一级,绝不能被直接访问。

健康检查:访问 /healthz,正常返回 {"ok":true,"version":"1.1.3","time":"…"}。
版本以 bootstrap.php 里的 RH_VERSION 为准,各处版本号统一从它读取。


4. Docker 部署

最小 compose

services:
  recipe-hub:
    image: xyzbz/recipe-hub:1.1.3
    container_name: recipe-hub
    restart: unless-stopped
    ports:
      - "8080:80"                       # 左宿主 / 右容器(容器内固定 80)
    volumes:
      - ./data:/var/www/html/data       # 全部家当:数据库 + 图片 + 备份
    environment:
      TZ: Asia/Shanghai
      RH_SITE_URL: https://eat.example.com
docker compose up -d          # 起来
docker compose pull && docker compose up -d   # 升级(数据在卷里,不受影响)
docker compose logs -f        # 看日志

浏览器打开 http://服务器IP:8080,走安装向导建管理员账号。

项值为什么
端口容器 80 → 宿主 8080宿主端口随意改
数据卷/var/www/html/data必须挂出来,不挂容器一删数据就没
站点地址RH_SITE_URL不填推送会降级成纯文本(拼不出菜谱链接)
反代传 X-Forwarded-ProtoPHP 靠它判断原始协议,决定 Cookie 是否加 Secure

噩梦中我战胜了妖魔鬼怪

梦到已故舅舅.png

昨晚做了个记忆特别清晰坑爹的梦,醒了半天没缓过来,还在细细琢磨梦境中的战斗,简单记一下。

我家住五楼,我和老婆在我们家大浴室整理衣物准备放洗衣机洗,突然有东西从窗户进来,风吹着窗帘摆动很大。我转头看过去看不见样貌,没有实体,但我一瞬间就确定,那是老婆已经过世的舅舅。

是我老婆最先发现的,当场吓得大叫。我立刻冲过去到处找,因为没有形体,我并不知道他进来跑去哪里了,想着上去想把它赶走,结果直接被它抱住锁住,身体动弹不得。经过几轮搏斗,想尽办法终于把它从五楼丢下去了。

然后我赶紧喊老婆一起把家里所有窗户全部关好锁死。然后在家里到处找那种观世音像,可是我没找到,因为我家根本就没有,现实中,我和老婆都是无神论者。

眼睁睁的看见窗户外又飘来东西,还是被它找到破绽又闯进来了。

这次换了模样,变成一个年轻女鬼。

这一轮对抗,我反而感觉自己占上风。她上来锁住我的时候,我直接扒了她裤子,她一下子变得很害羞,拼命想挣脱。后面一番拉扯,我把她压进一块木板里面,拿一把梳子在木板上划了很多线条,好像是把她封印在里面,出不来了。我看见她在木板里面移动的印记。我也不知道这是啥操作,现实中我完全不会想到。

梦醒后想起以前抖音上看到的一句话:梦里故人如果开口说话,那就不是真的故人,故人来只会远远的看着,不会说话、也不会进身。 梦境中,他过来就直接抱住我使得我动弹不得,我想尽办法把他从楼上丢下去后,又变形成一个女鬼飘了进来,所以,毋庸置疑这并不是老婆的舅舅。只是借身份进来的。后面进来可能是她本来的真身。

梦里我就没有因为他是舅舅而放过他。因为我的想法是,他是鬼,我们是人,能从五楼的窗户进来,那就不是我能接受的东西。也有可能是不亲的缘故,不过一大部分是我想保护我老婆的潜意识,因为他吓到我老婆了,所以我必须上,必须保护老婆,把他丢下去。

AI · 梦境解析
核心:边界被侵犯后的防御与反击
这个梦的核心是边界被侵犯后的防御与反击。第一轮驱逐“伪装成亲人的入侵者”,第二轮封印“原始焦虑形态”,中间穿插“找观音像而不得”的无力感,最终靠自己的物理行动和象征性封印解决问题。梦中你始终以“保护者”身份行动,没有因身份标签而犹豫,醒后还能理性区分“真故人”与“借身份者”——这说明你的潜意识在练习边界管理,且练习得相当成功。
关键词:边界防御 · 保护者人格 · 象征性封印 · 身份辨识

一个人的异托邦 II

接着昨天的话题,“异托邦”是现实存在的“世界”,然而这些世界因为存在某种规则,区隔了现实的部分。例如监狱、学校、精神病院、酒吧、游乐场、图书馆、博物馆等。

支持“异托邦”观点的人则认为,这个“空间”区别于建立在想象之上的乌托邦,异托邦是现实存在的,可以摸索其中的特定规则,以明确它与现实之间的具体差别。另外,异托邦与时间也有明确的关联性,福柯在异托邦理念的研究中表明,在研究空间隔离的同时,也会发现时间隔离的现象。简单来说,就是同一时间下,可能会存在完全不同的规则,当人们发现自己处在与传统的时间观念彻底决裂的状态时,“异托邦”就开始发挥作用。

举个比较极端的例子——《鱿鱼游戏》里,当参赛者被集中在同一个暗无天日的空间里时,这里的时间概念完全与外界切断,他们的游戏规则是“活下去”,比赛随时可能淘汰对手,而在他们“休息”的时候也可能会遭遇其他人的袭击。于是,人们不再遵循“晚上睡觉的时候自动休战”的规则,而是随时随地都需要参与到彼此淘汰的比赛之中,否则自己不仅会被淘汰出局,还会失去生命。

如果从这两个构成要件出发,即:

  • 空间:把现实中的某个地方变成另一个世界;
  • 时间:一个人是否可以拥有自己的时间秩序。

那么一个人是否也能建立“异托邦”?


这两天看到一个趣事,一个家长在家长群里公开讨伐班主任,认为班主任整天在群里公布哪些同学的作业优秀,是一种歧视行为。这位家长特别强调:成绩差不代表人品差,成绩好也不代表人品好。老师要求这位家长添加自己的微信好友,避免在群内发生冲突,但同时其他家长也没有一个人站出来为任何一方说一句话。

评论区有一条高赞评论:她的孩子成绩差,破防了吧。

很显然,这是一个由社群形成的异托邦,并且这套规则适用于群内的所有人,除了这个因为自己孩子没有被表扬到的家长。那她的反抗是对的吗?很显然,这是我故意设计的陷阱题——因为这件事本来就没有对与错之分。

但有趣的是,外界,即异托邦世界以外的人,则将这位家长的行为理解为“破防”。那这个理解的标准来自于什么?是这个异托邦本身的规则、作为家长的理解,还是现实世界的理解?同理,也有人不理解为什么其他家长不站出来帮老师说话。而具体在这个群里,大家形成了怎样的默认规则,其实在外部世界并不得而知,所以当人们用外部规则去理解这个异托邦时,必然就会产生不同的理解,甚至是有关对与错的理解。

那如果这个异托邦的世界无限缩小呢?

比如网红在书店搔首弄姿地拍照,完全无视这里的消费者与书店原本的功能性,那能因为他们违背了图书馆这个异托邦的世界规则,而判定他们是错误的吗?更甚,如果几乎所有来图书馆的人都是拍照的网红,而真正来买书的人,倒成了那个挡住了人家最佳拍照位的人呢?


同样的,前两天看到一个台湾美食网红被“炎上”的新闻。一个自称美食网红的女性,在直播介绍美食时,一个路人路过入镜,这个女网红立刻改变嘴脸,嫌弃路人没有看到她正在直播。而直播内容被网友截图公开后,该名女网红遭到“炎上”,网友认为她才是那个有问题的人,是她自己把公共场合当作自己的私人领域。

很显然,当她在进行直播时,她默认其他人应该遵守她有关直播的规则,而这个个体规则,甚至在这一刻可以对抗已经存在的公共空间规则本身。就像是那些拍照的网红,他们无视书店的规则,或者说,商业书店的规则早已经不复存在,所以规则就变成了这些网红进行拍照时的规则——某个出片机位的排队、不挡其他网红拍照时的灯光,以免自己拍照时被他人恶意挡光,等等。

随着个体能够发出更大声量,例如网红、意见领袖、罗永浩之流,个体所建立的规则就开始迫使更多人被迫遵守。但其实这个事情并没有任何人参与其中,而他却认为这套规则是应该由所有人理解和遵守的。

更甚,无法发出声量的人,则利用对他人规则的讨伐,来证明自我规则的正确性,以形成个体声量。比如为了反对而反对,以完成异托邦对于全体人的思维约束。


未来,这类事情会越来越严重,一方面是因为“社会原子化”,即人们像一个个原子一样,四处飘落,联系少、关系疏离的社会状态。随之一起分散的,还有个体所理解的规则。规则就算不通过抱团,也可以形成个体的异托邦,哪怕是一个小小的办公位,也可以形成“你要找我聊工作,先遵守我这个工位的规则”之类的规则。

另一方面,互联网省去了原本需要在现实世界进行空间构建的过程,在网络上可以随时随地形成大小不同的异托邦。哪怕是在一则新闻下面,集体偏向的某个立场,都可以形成“只要你不支持我,就是在反对我”的异托邦规则。

当然,我不认为个体的异托邦就全是“错误”。

  • 一个人的异托邦,可以使个体重新获得定义自身的权利。特别是在面对不同异托邦对个体的规训时,可以更有效地保持主体性。
  • 但同时,一个人的异托邦也存在风险。如果一个人不断强化自己的空间边界,拒绝任何外部信息,那么这个空间可能逐渐失去反思现实的能力,从而形成封闭的认知系统。

迫使他人遵循自我规则不是不行,而是这套规则在形成世界之后,倾覆的瞬间,也会把建立规则的人一同掩埋。

——

感谢订阅莫比乌斯,如你有任何疑问、观点交流,请前往创作者频道,或私信联系。

战争召唤地狱之门110多g运行成功

✇ACEVS
作者 ACEVS

战争召唤地狱之门夸克网盘分享
战争号令地狱之门:东线|战争召唤地狱之门:东线 v1.067.0 修复闪退 全DLC 单机+联机(Call to Arms - Gates of Hell: Ostfront)免安装中文版 - PC游戏 - 资源共享站shaqzone - 单机破解游戏、二次元全站免费,尽在资源共享站shaqzone!
没有出现闪退,什么也没有设置,估计之前的那个100多g的安装包有问题。
导致我整理一下磁盘,把一些iso zip等文件放到了机械硬盘上,固态腾出来200多g,负责运行机械硬盘可能运行不了的游戏。
这个游戏多年之前玩过一次二次,那时候这个游戏 可能10g左右。这么多年过去了。大了不少。
再次打开时候,还是不自信的从教程关开始了。教程确实详细,同样给坦克补给,有三种方法补给,现在想想我似乎只记住两种。
操作士兵,操作反坦克炮,操作卡车,操作坦克,不过大多时候都是第三人称视角,之前下的另一个版本开场是坦克第一视角。可能有什么快捷键,或者训练教程只有这个视角,改天继续测试,战地系列第一人称视角也不错。
教程里面还教ap单,还有aprc还是什么,对付不同倾角的坦克装甲效果演示。迫击炮那个也是榴弹炮,穿甲弹,高爆弹等等,估计军迷可能会喜欢。
这个游戏有时候得调整视角,有的战壕里的敌人看不到,现在想想调视角就是上帝视角哇,应该还是固定视角吧增加点难度,另外经常调视角头晕哇。

百度云盘速度最满100多k。迅雷150K左右可能。夸克不错,单线程大概200左右。最多五个线 1m左右。这一m的速度竟然让我夸到了。哈哈。
网盘都有10g空间,免费的话,下载东西就是转存,删除,再转存10g以内的下载排队,再删除,迅雷夸克都是这么操作,夸克似乎删除等待时间短点。

松声|廿六年·十月中·骤生变

自己做饭

2026-十月半麻辣烫 (2).jpeg
2026-十月半麻辣烫 (1).jpeg

  • 最近穷!中午点外卖,基本上都能保证在十五块以上了,关键还不是很好吃,没办法自己整吧!一天也就中午有闲时间折腾了,前段时间公司门口的麻辣烫深得我心,想买火锅底料炒,但是不确定自己能做几顿,就开始抖音搜麻辣烫料包,品牌好多,最后选了杨国福。基本上就是煮,可惜我这个小锅太小了,大锅又太大了,还得买个2-3L的多功能锅,毕竟这不是家里,一不小心就会做多。第一次买点丸子菜,就开始做了,小锅不愧是小锅,一如既往的冒出来。再等等双十一一定买一个新的!总结一下,味道接近店里的味道,自己做可以多搭配一些蔬菜,门口超市卖的太少了,出去在采购一番,看网上别人的懒人配菜视频,一次可以搭配出一周的食材冷藏,可以研究研究,毕竟冰箱闲着也是闲着。

意外

2026-十月半意外 (2).jpeg
2026-十月半意外 (1).jpeg

  • 十一计划出去转一圈的,ld刚好也有两天的时间,结果休息第一天,家里打电话说老爸摔着了,赶紧回去,肩膀摔脱位了。
  • 接上老爸去医院,刚好骨伤科有个高中同学在那里,拍片,输液,医生说得手术,固定住后,十个月后拆钢板,不手术的话,它会一直翘着,另外胳膊提不上劲。输液差不多三天,我接着回去上班,手术那天回家,手术一个半小时,签签术前须知,给弄了个全麻,毕竟老头子也没做过手术。
  • 下手术台后,人基本上已经醒了,第一天就是肩膀那里疼,一阵一阵的,第二天基本上就不怎么疼了,也能下床走路了,上午输输液,下午就没啥事了。医生说术后五天左右,伤口没问题就可以出院养着了。目前已经出院了,报销完花了两千多,比医生预估的多了点,毕竟当时说让半麻。
  • 去的那会,老头子还不想动手术,想着多去几家看看,能不能保守治疗,毕竟年纪大了怕做手术,主治医师说搁以前医疗条件不好的时候,还真就一直翘着了。老一辈的担心花钱,怕去医院了被宰,不过不治疗也不行!平时劝少干点活,年纪大了,不行当个保安也行,但我家这个劝不动,劝了也不听,索性只要别干太累的活就行了。

十年之约

2026-十月半-十年之约.png

  • 十年之约终于更新了。
  • 这个项目我记得说了好久要换 UI。做了这么多年,跟 BlogsClub、博友圈摆在一起看,界面确实显得复古了些。这次改版,算是接手人交出的一份成绩单。
  • 本来想单独水一篇,想了想还是记在半月记里更合适。
  • 之前跟羽忆聊过十年之约的一些老问题:比如益达云那种几年没更新的成员站,还有公约的约束力究竟能到哪一步。说到底,眼下的个人站点能活过两年的都不多,每个人在每个阶段关心的事也不一样,对不同时期加入的成员,本就该有一份现实的理解。这次改版看得出来考虑到了这些,做得还不错。
  • 当然也还是有些不同的声音。但整体看,这次接班算是成了。能活这么久的项目本来就不多,接手之后还能持续运营、推动改版,靠的全是热爱。
  • 反之各位项目发起人,或许也需要考虑项目的长久性,持续性。

冥冥之中

2026-十月半-意外.png

  • 有时候,人类对危险是存在感知的,就比如这个椅子,在它断裂的前一分钟,我竟然意识到了这个椅子要出问题,但是我忽略了自己的感知,直到那一刻,我的腿翘起,卡到了桌子,把显示器掀翻到自己手里,我他么赶紧打开手机给店家客服发消息。好在,他说质保9个月,给我发配件。

离年底越来越近

2026-十月半-动员.jpeg

  • 离过年越来越近了,在河南,秋天短暂,冬天来临可能就是几次变天,小心各个电商卖家临近年关捞一把!睁大双眼,谨防被骗,努力挣钱过大年。

一个人的异托邦 I

“异托邦”,原意指“异质空间”,是法国哲学家米歇尔·福柯提出的概念。简单来说,异托邦是现实存在的“世界”,然而这些世界因为存在某种规则,区隔了现实的部分。例如监狱、学校、精神病院、酒吧、游乐场。当然,因为存在主观喜恶的判断,异托邦本身是一个中性存在,只是因为人们对学校和游乐园的态度不同,会认为异托邦应该指向那些更美好的部分。

前几年去大阪环球影城参加过一次跨年,因为我会时刻注意自身身上的“不同”,所以总觉得自己很难融入游乐园的氛围之中。随着去大阪环球影城的次数越来越多,我也渐渐意识到自己好像更容易参与到与热情工作人员的互动之中,特别是在面对他们与路人服饰的互动时,从一开始觉得他们只是在“表演”,到后来觉得他们或许是“真的热爱这份工作,所以才能由衷地与游客互动”。

而这个变化的根本,在于我逐渐接受了这个“异托邦世界”的规则,不再会为自己在这个世界里做出与现实世界有区别的行为而感到尴尬。特别是万圣节所有人都在奇装异服地装扮自己时,就连50、60岁来游园的游客,至少都会在自己脸上贴上一个刀疤的纹身贴,来加入这个“异托邦世界”。

同样,之前去过一次上海迪士尼,却有完全不同的感官。简体中文与中文语境下所制造的异托邦,又包含了诸多主观偏见,例如“无服务意识”“态度冷漠”等等。而在实际体验中,也确实没有感觉到工作人员有多少热情,他们的脸上都写着被游客欠了50万的傲慢,以至于整个迪士尼里都充满了一种“拘束”的感觉。当大部分人都在维系着现实世界的“规则”时,那些装扮成公主的、打扮精致的游客,反而会被当作异类。


异托邦基于规则,形成一个区隔现实的“异世界”。但如果大多数人重新构建默认规则呢?

就拿之前我在咖啡厅没有及时“关门”的例子来说,因为一个人进入咖啡厅后没有关好门缝,导致整个咖啡厅被灌进热浪,但并没有任何一个人站起来去关上门缝,都认为这是别人的责任。而当那个最初没有主动关好门的人,对他们嫌恶的眼神毫不在意时,他们进而把这个关门的责任强加在了我这个距离门缝最近的“替罪羊”身上。

在这个短暂的时间里,我从跟他们同样的“受害者”身份,变成了“瑕疵受害者”、甚至是“加害者”身份。但这个世界并没有发生任何改变,而仅仅是这群人的默认规则在短时间内做出了调整与统一。

当然,我并没有被规则规训,所以门就一直这样留了个门缝,且没有一个人主动站起来去关上它。这个时候有人会说了:“这就是一个顺手的事,有必要让整个咖啡厅的人都遭罪吗?”那么问题来了,这条规则是基于这个人自己、这个世界的规则,还是此时此刻在这个异托邦里大家构建起来的新规则?

很显然,我不被规训,也当然不属于这个异托邦的成员,甚至还可能遭到异托邦的排挤。


不过,规训有时候比人们想象的还要残忍。

当一个正常人被确诊“精神病”后,强制关进精神病院,在这个异托邦的世界里,几乎可以说没有规则,每个人都有一套自己理解的世界规则,而现实的规则是按时吃药、听从医嘱,违抗意味着犯病,而规训意味着治疗得当。在这样的规则之下,他的一切行为都与“精神病”直接挂钩,而在这套规则里,继续保持主体性,特别是努力证明自己没疯的主体性,会被强制削弱,直到这个正常人也开始有了“精神病的表象”,即“我只有这样,才能在这个规则之中活下去”。

也就是说,那些被强制“精神病”的正常人,最终在行为上都会或多或少出现“疯癫”的情况,就像是一个人被放进了全是镜子的房间,他以为镜子里投射的都是自己,但实际上,这是异托邦规则之下要在这里活下去的“正常方式”。

比如这段时间频繁逛宝可梦道馆,一开始还会对工作人员称呼顾客为“训练家”觉得有些尴尬,但听多之后,特别是意识到来逛店的游客,无论国籍、年龄,大家都能在这里因为找到自己喜欢的宝可梦而露出开心的笑容时,我在这个异托邦里,也放弃了这些原本属于现实世界规则的部分。

而这类规训行为,在更小的单元里,就是所谓的“煤气灯效应”“PUA”:一个人对另一个人长期建立某种异托邦规则,迫使对方开始怀疑自己,放弃主体性,并接受这套规则本身的规训。


虽然福柯严格定义,异托邦首先是“空间概念”,并非个人的“心理概念”,也就是说,它是一个现实中明确存在的空间,并遵循某种明确或共同默认的规则。除了前面提到的场所,还有图书馆、博物馆等等。

那一个人是否也能构建一个属于自己的、且存在于现实的异托邦?这个话题明天继续,试着挑战一下福柯老头子的“过时概念”。

——

感谢订阅莫比乌斯,如你有任何疑问、观点交流,请前往创作者频道,或私信联系。

失败即是乐趣

✇ACEVS
作者 ACEVS

看了一个介绍游戏的帖子,有一个图,感觉挺有意思,像素小人,看上去不是战棋类或者回合制的。拍照发给豆包,问这是什么游戏。豆包说的大意就是环世界,看了一下视频感觉挺好玩的。
找了资源下载,正常运行游戏2g左右好像不大,文字相的感觉,一个人能力就是文字标签+数值,其实游戏都是这样子的嘛。按照教程选择了仓库,安置了居民区,设置了采矿地,弄了沙包堡垒,想着来什么怪物,来了一条狗(可能是忘记),三个人两个人拿枪打了半天,有一个配了匕首没有出击,不知道为啥。战斗完两个人,被那个没咋受伤的背回家,放床上躺着疗伤,过了几天,由建筑师或者建造特长的那个人,去湖里钓鱼,游泳,可能他放假了,过会系统提示有人被老鼠攻击,我点击那个受伤的小人,发现拿着枪根本没用,都不开枪,老鼠追着那个人满地图跑,生命值也来越低,最后体力不支倒下了,我派另一个人接他回来,途中那个人就挂掉了,我一看直接用自动存档 重读了一下,问豆包咋办,豆包说老鼠多的话最好躲起来,一个的话,用木棒之类的效果好,ok,把枪换成木棒,干掉了老鼠,不过那个人也被队友抱着回床上躺了几天康复,这老鼠都这么厉害。确实是外星殖民类型的哇。

祖师爷游戏 不是环世界,豆包说是学习10.20年前的矮人要塞,泰拉瑞亚等都是学习它。环世界是简化版的矮人要塞。

2002 年兄弟二人启动开发,2006 公开 Alpha 版,比环世界早差不多 10 年。环世界作者 Tynan 自己公开说,环世界就是简化、现代化的矮人要塞,核心灵感来源就是 DF。 泰拉瑞亚、MC、监狱建筑师、缺氧全都受它启发,但不是完全照搬,只是吸收它的设计思想:程序生成完整世界、生物精细模拟、人物独立情绪记忆,游戏自己 “演故事”,口号 Losing is Fun(失败即是乐趣)。失败的乐趣,精妙。

我问豆包同类型还有其他推荐?

同类型硬核复杂模拟(环世界/矮人要塞一脉,都是大量互锁系统、涌现式事件,一张存档几百小时)

分类,方便你挑: A:小人殖民管理(最贴近环世界、矮人要塞) B:物理/流体工程类(系统硬核,侧重管线、热力学) C:大尺度战争+城市模拟(宏观复杂)

A、殖民/据点管理(优先推荐,风格最接近)

  1. Oxygen Not Included 缺氧 科雷的神作,地底小行星殖民。气体分层、温度传导、液体管道、细菌、电力过载全部是真实物理模拟,环环相扣。 重点:不是打架,是工程循环设计,一个管道规划失误,基地连锁崩盘。小人有压力、生理需求。学习曲线非常陡。
  2. Songs of Syx 希克斯之歌 超大尺度城邦模拟,几千人口。社会阶层、宗教、派系、贸易、军队、城防、移民、饥荒瘟疫。 类似矮人要塞那种生成世界历史,一个城邦内部的政治矛盾会自己演故事。
  3. Going Medieval 前往中世纪 中世纪据点,3D立体建筑,多层墙体防御。村民心情、伤病、装备、食物、疫病、劫掠。 比环世界简单一点,但垂直建造、防御工事系统很强。
  4. 了不起的修仙模拟器 国风修仙版环世界。门派管理、灵气、功法、心魔、丹器、妖兽、门派争斗。 人物特质、人际关系系统很强,大量随机事件。
  5. Farthest Frontier 最远的边陲 中世纪村庄,水源、卫生、传染病、土壤肥力、贸易、蛮族入侵。 细节拉满:不喝干净水会痢疾,缺维生素会坏血病,砍树影响地下水。

B、工程自动化硬核(逻辑复杂,适合喜欢搭系统)

  1. Factorio 异星工厂 工业自动化天花板。传送带、机械臂、铁路、石油化工、发电、污染引发虫族进攻。 核心:设计全自动产业链,从手工挖矿到造火箭。没有复杂小人心理,纯工程逻辑。
  2. Shapez 形状工厂 极简画面,流水线生产图形,纯逻辑拼图,偏解谜自动化,比异星工厂轻松一点。

C、其它重度复杂沙盒

  1. Project Zomboid 僵尸毁灭工程 末日生存,人物健康、伤口感染、体温、饥饿、建筑、园艺、电路。 没有上帝视角殖民,是单/多人生存,但人体、环境模拟极其写实。
  2. Prison Architect 监狱建筑师 管理监狱,囚犯档案、帮派、需求、暴动、假释、心理。系统连锁,很容易全面暴乱。

快速对比一句话

  • 喜欢小人故事、人际关系、随机灾难:环世界 → 希克斯之歌 / 前往中世纪 / 了不起的修仙模拟器
  • 喜欢物理、流体、热力学、管线循环:矮人要塞 → 缺氧
  • 喜欢自动化流水线、工业物流:异星工厂

难度梯度参考(由简单 → 地狱)

前往中世纪 < 最远的边陲 < 环世界 < 缺氧 < 异星工厂 < 希克斯之歌 < 矮人要塞

你更偏向哪一类? ① 管理一群人、看小人故事、防御袭击(环世界风格) ② 搭管线、物理热力学工程(缺氧风格) ③ 全自动工厂流水线(异星工厂)

✅没错:矮人要塞(Dwarf Fortress)就是殖民地涌现模拟这一支的祖师爷

2002年兄弟二人启动开发,2006公开Alpha版,比环世界早差不多10年。环世界作者Tynan自己公开说,环世界就是简化、现代化的矮人要塞,核心灵感来源就是DF。 泰拉瑞亚、MC、监狱建筑师、缺氧全都受它启发,但不是完全照搬,只是吸收它的设计思想:程序生成完整世界、生物精细模拟、人物独立情绪记忆,游戏自己“演故事”,口号 Losing is Fun(失败即是乐趣)。

简单理清辈分

  1. 祖师:矮人要塞 Dwarf Fortress(2006对外发布,20多年持续开发) 生成完整世界地理、文明历史、生物身体结构(每根骨头、牙齿、器官独立模拟),矮人有记忆、人际关系、创伤。玩家间接指挥,不直接控制小人,世界独立运转。 缺点:早年ASCII字符画面,无教程,地狱难度。2022年才上Steam加像素图形版。
  2. 后辈(吸收DF理念)
    • RimWorld环世界:把DF的“涌现故事+小人情绪”拿过来,砍掉地质学、完整世界历史,简化人体模拟,做成好上手的科幻殖民地游戏。
    • Minecraft我的世界:随机地形、地下挖掘灵感来自DF
    • Terraria泰拉瑞亚:随机世界生成、地下探索、生存建造吸收了DF思路
    • Prison Architect监狱建筑师、缺氧Oxygen Not Included 也明确受到矮人要塞启发

更早的前辈:1997《地下城守护者 Dungeon Keeper》,它是“间接控制自主AI手下”的先驱,但没有矮人要塞这种全宇宙级精细物理+生物+历史模拟,所以圈内一般称DF是现代殖民地模拟游戏的祖师爷。

同属这一脉、系统极度复杂的其他硬核作品(祖师爷派系)

  1. Caves of Qud(洞穴任务) 文字像素roguelike,同样生成完整世界历史,生物变异、身体部位、派系文化模拟极其细腻,矮人要塞直系精神续作。
  2. Songs of Syx 希克斯之歌 超大人口城邦模拟,几千居民,阶层、宗教、战争、瘟疫,世界历史生成,DF大宏观版本。
  3. Dungeons of Dredmor(德雷德莫尔地牢) 偏Roguelike,继承随机生成+复杂系统。

一句话区分

  • 地下城守护者:祖宗雏形
  • 矮人要塞:祖师,定义了「程序生成世界+自主小人+涌现叙事」
  • 环世界:大众化简化版的矮人要塞

战争召唤地狱之门

✇ACEVS
作者 ACEVS

这个游戏有个好友,就玩这个买的正版,在steam,某天想看看他们都在玩啥发现还是这个。之前和他局域网连过机,当时我第一次玩,完败。没想到前几天一看都快2000小时了。也想整个绿色版来玩玩。

先下的是game520网站的,40多g,迅雷下载的,当时没有限制感觉速度不错。加载正常,但是汉化是半吊子,一半英文一半中文的感觉,英文仔细看可以看懂,但是费力哇,有的 战争专业德语还是英语也看不懂。这个删除,重新下载,

战争号令地狱之门:东线|战争召唤地狱之门:东线 v1.067.0 修复闪退 全DLC 单机+联机(Call to Arms - Gates of Hell: Ostfront)免安装中文版 - PC游戏 - 资源共享站shaqzone - 单机破解游戏、二次元全站免费,尽在资源共享站shaqzone!这个网站的感觉还是之前那个网站压缩的,看评论可能会踩雷,之前那个50-60g也是网站的,这个网站的
XDGAME - 专注单机游戏试玩及正版推荐!
闪退,我以为是装在机械硬盘的问题,按豆包说的删game文档,虚拟内存,禁止exe联网,换成固态硬盘,更新显卡驱动,等等,还是闪退,删掉后下载这个闪退修复,不知道真假。不行的话只能重新下载了。也可能mod ,dlc太多豆包说的。哈哈。

百度网盘100多k速度,可以不考虑,夸克500-1024k还凑合,阿里云盘估计速度不错 但是没想到去找资源。之前game520 有gofie分享,那速度确实快50M/s

你来啦![1.44.20] — 正式上线 多端覆盖

简单更新,支持广告屏蔽(安卓,ios暂未发版)。不得不说,手机上各种广告入侵,很多页面都直接没法看了。

实际效果:

以下内容,写与 2026 年 10 月 14 日 :

博客聚合这个东西,不说已经被玩烂了,反正是也差不多人手一个了。层出不穷的聚合平台,几乎每个玩博客的都整合了一个,哪怕没有聚合平台,也会有个友圈,邻里之类的rss文章聚合页面。

日薄西山的时候,做这么个东西,似乎也没什么太大了意义,少数人的东西,也难成气候。现在还在写博客的多多少少都有些执拗吧。从几个月之前开始借鉴别人的想法加上自己的创意搞出来这个东西。如果说惊艳,那自然是没有,如果说用途,那也有一些。现在也基本是自用居多,仅此而已。为了上架苹果应用商店,期间也进行了无数次交涉,一次次整改,在整改的过程中添加新的功能。终于昨天这个东西审核通过了。

在迭代过程中,增加了数项功能,主要网站状态相关:离线检测、合规检测、抓取状态检测等等,也会伴随着app推送消息。功能简介:

你来啦!是一个博客站长聚合平台。每个站点根据其 IP 地址映射到虚拟坐标空间, 同时通过坐标转换服务获取真实地理坐标,在天地图(现实坐标)上展示。

✦
虚拟
虚拟坐标 · 基于 IP 地址的 Hilbert 曲线映射,探索独特的 IP 宇宙

🗺
现实
天地图 · 真实地理坐标展示,看看博主们都在哪里

🌐
IPv4 / IPv6 双栈
同时支持 v4 和 v6 地址的地图点位展示

🔗
友链
在站点列表、地图与详情页点击「链接」添加友链,关系会展示在地图关系网与用户主页。 登录后可在 控制台 管理友链,并通过 Halo / WordPress / Typecho 插件与博客双向同步。

📰
最新动态
全站收录站点的 RSS 聚合信息流,在 最新动态 按日历日切换浏览,支持关键词搜索;登录用户可收藏感兴趣的文章。

💬
朋友圈
已链接友链站点的 RSS 时间线,在 朋友圈 按日浏览已关注(友链)站点的 RSS 更新,支持搜索与收藏。

📡
RSS 订阅
与友链「链接」独立:订阅只用于个人 RSS 阅读,不影响关系网展示。站点列表、地图与详情页均可一键订阅; 控制台支持分组管理与 OPML 导入,在 我的订阅 按日聚合浏览已订阅站点的最新文章。

🔎
首页合规扫描
平台会定期检查仍在运营、且填写了网址的站点首页,识别违法违规、恶意跳转和导流内容。 被标记的站点会出现在登录后的预警列表里:站点名称完整显示,域名和网址已脱敏,不能直接打开。 确认违规的站点会被下线;若你的友链里包含这类站点,且开启了友链合规通知,我们会用推送和邮件提醒你及时清理。 这项检查与文章动态的内容过滤相互独立。更完整的说明见常见问题。

下载地址:

苹果:https://apps.apple.com/cn/app/%E4%BD%A0%E6%9D%A5%E5%95%A6/id6790620612

安卓:https://app.zhongxiaojie.cn/app/nilaila/android/

官网:https://nilai.la

已知问题:当前版本推送模块打包存在问题,正在发布新版,请耐心等待。

推送已经修复,请及时更新新版本。

邀请码:

邀请码	状态	使用者	备注	创建时间	操作
INV-MSPW-C3PZ-XY6A	已使用		ios	2026/10/14 10:03:25	
INV-C2K7-F5VR-G5C2	已使用	-	ios	2026/10/14 10:03:25	编辑备注删除
INV-H26S-PVBW-BW00	已使用	-	ios	2026/10/14 10:03:25	编辑备注删除
INV-EFT1-RDZ5-970T	已使用	-	ios	2026/10/14 10:03:25	编辑备注删除
INV-I370-HDMG-GC58	已使用	ios	2026/10/14 10:03:25	
INV-XXZK-G8G9-KFV7	已使用		ios	2026/10/14 10:03:25	
INV-D9AR-G07C-RDE8	已使用	-	ios	2026/10/14 10:03:25	编辑备注删除
INV-YYXI-30UW-0T14	已使用	-	ios	2026/10/14 10:03:25	编辑备注删除
INV-OM0Z-JCXW-QWS4	已使用		ios	2026/10/14 10:03:25	
INV-4E8S-S6PX-Z7WI	已使用	-	ios	2026/10/14 10:03:25	编辑备注删除

补一组邀请码:

邀请码	状态	使用者	备注	创建时间	操作
INV-X3UH-JMQR-5GCN	已使用	-	补一组	2026/10/15 23:00:29	编辑备注删除
INV-W041-OJVL-HSMI	可用	-	补一组	2026/10/15 23:00:29	编辑备注删除
INV-VNOU-V6EZ-JFP5	可用	-	补一组	2026/10/15 23:00:29	编辑备注删除
INV-JVK4-Y5S8-OGEF	可用	-	补一组	2026/10/15 23:00:29	编辑备注删除
INV-X9NM-Q785-20BS	可用	-	补一组	2026/10/15 23:00:29	编辑备注删除
INV-BBKL-3GFM-Y4HI	可用	-	补一组	2026/10/15 23:00:29	编辑备注删除
INV-ACDC-MHUR-F21N	可用	-	补一组	2026/10/15 23:00:29	编辑备注删除
INV-AGXA-47D0-QPJS	已使用	-	补一组	2026/10/15 23:00:29	编辑备注删除
INV-NKW4-POEB-59JF	可用	-	补一组	2026/10/15 23:00:29	编辑备注删除
INV-QL2H-GHER-S86V	可用	-	补一组	2026/10/15 23:00:29	编辑备注删除

 

 

大意失荆州 — 浅谈cdn后面的源站防护

随着开发的服务和应用越来越多,当初为了省事直接通过后端提供服务的做法,从短期看来的确是省了再次部署的麻烦。但是,这种做法也挖了一些深坑,并且,这些坑不见得什么时候就成了拖垮系统的罪魁祸首。

当初为了省事,很多服务直接通过端口映射之后就作为后端服务发布了。

当然,并不是直接暴露后端真实服务器的地址,前面还套了一层eo。想着最前面是eo,默认请求都会经过eo转发,本身图片等相关资源都有cdn缓存也不会打到服务器上,只有cdn边缘服务器第一次请求的时候会访问真正的后台文件,这样原来,直接通过后端服务提供静态资源访问也是足够的,并且跑了这么长时间也没什么问题。但是,事实并非总是这么可靠。

昨天 你来啦 发版之后,想着填写一下appstore的下载地址,结果登录后台直接提示502了。

登录服务器看了一下,后台服务进程被大量下载直接拖死了:

22.79.117.157:55212 - - [13/Oct/2026:16:26:03] "GET /media/packages/2026/10/__UNI__8813F79_1007202252.apk" 200 79556639
113.219.202.124:5113 - - [13/Oct/2026:16:26:03] "GET /media/packages/2026/10/__UNI__8813F79_1007202252.apk" 200 79556639
113.219.202.2:12879 - - [13/Oct/2026:16:26:04] "GET /media/packages/2026/10/__UNI__8813F79_1007202252.apk" 200 79556639
113.219.202.3:46581 - - [13/Oct/2026:16:26:04] "GET /media/packages/2026/10/__UNI__8813F79_1007202252.apk" 200 79556639
222.79.116.209:27848 - - [13/Oct/2026:16:26:04] "GET /media/packages/2026/10/__UNI__8813F79_1007202252.apk" 200 79556639
222.79.116.184:59270 - - [13/Oct/2026:16:26:04] "GET /media/packages/2026/10/__UNI__8813F79_1007202252.apk" 200 79556639
2026-10-13 16:26:25,486 WARNING  Application instance <Task pending name='Task-6311' coro=<ASGIHandler.__call__() running at /home/obaby/soft/baby-claw/upgrade-server/venv/lib/python3.10/site-package
s/django/core/handlers/asgi.py:170> wait_for=<Future finished result=None>> for connection <WebRequest at 0x7f5ee03d73d0 method=GET uri=/media/packages/2026/10/__UNI__8813F79_1007202252.apk clientpro
to=HTTP/1.1> took too long to shut down and was killed.
2026-10-13 16:26:25,542 WARNING  Application instance <Task pending name='Task-6348' coro=<ASGIHandler.__call__() running at /home/obaby/soft/baby-claw/upgrade-server/venv/lib/python3.10/site-package
s/django/core/handlers/asgi.py:170> wait_for=<Future finished result=None>> for connection <WebRequest at 0x7f5ee0255390 method=GET uri=/media/packages/2026/10/__UNI__8813F79_1007202252.apk clientpro
to=HTTP/1.1> took too long to shut down and was killed.
2026-10-13 16:26:25,543 WARNING  Application instance <Task pending name='Task-6350' coro=<ASGIHandler.__call__() running at /home/obaby/soft/baby-claw/upgrade-server/venv/lib/python3.10/site-package
s/django/core/handlers/asgi.py:170> wait_for=<Future finished result=None>> for connection <WebRequest at 0x7f5ee03a3c10 method=GET uri=/media/packages/2026/10/__UNI__8813F79_1007202252.apk clientpro
to=HTTP/1.1> took too long to shut down and was killed.
2026-10-13 16:26:25,543 WARNING  Application instance <Task pending name='Task-6351' coro=<ASGIHandler.__call__() running at /home/obaby/soft/baby-claw/upgrade-server/venv/lib/python3.10/site-package
s/django/core/handlers/asgi.py:170> wait_for=<Future finished result=None>> for connection <WebRequest at 0x7f5ee01ebfd0 method=GET uri=/media/packages/2026/10/__UNI__8813F79_1007202252.apk clientpro
to=HTTP/1.1> took too long to shut down and was killed.
2026-10-13 16:26:25,543 WARNING  Application instance <Task pending name='Task-6357' coro=<ASGIHandler.__call__() running at /home/obaby/soft/baby-claw/upgrade-server/venv/lib/python3.10/site-package
s/django/core/handlers/asgi.py:170> wait_for=<Future pending cb=[Task.task_wakeup()]>> for connection <WebRequest at 0x7f5ee03d7760 method=GET uri=/media/packages/2026/10/__UNI__8813F79_1007202252.ap
k clientproto=HTTP/1.1> took too long to shut down and was killed.
2026-10-13 16:26:25,548 WARNING  Application instance <Task pending name='Task-6368' coro=<ASGIHandler.__call__() running at /home/obaby/soft/baby-claw/upgrade-server/venv/lib/python3.10/site-package
s/django/core/handlers/asgi.py:170> wait_for=<Future finished result=None>> for connection <WebRequest at 0x7f5ee01892d0 method=GET uri=/media/packages/2026/10/__UNI__8813F79_1007202252.apk clientpro
to=HTTP/1.1> took too long to shut down and was killed.
2026-10-13 16:26:25,548 WARNING  Application instance <Task pending name='Task-6373' coro=<ASGIHandler.__call__() running at /home/obaby/soft/baby-claw/upgrade-server/venv/lib/python3.10/site-package
s/django/core/handlers/asgi.py:170> wait_for=<Future pending cb=[shield.<locals>._outer_done_callback() at /usr/lib/python3.10/asyncio/tasks.py:864, Task.task_wakeup()]>> for connection <WebRequest a
t 0x7f5ee0058310 method=GET uri=/media/packages/2026/10/__UNI__8813F79_1007202252.apk clientproto=HTTP/1.1> took too long to shut down and

这一堆请求__UNI__8813F79_1007202252.apk的访问,几乎是在同一秒内发出的,并且这些ip也不是eo的cdn边缘服务器ip,那么就只有一种可能,就是源服务器的地址暴露了,被别有用心的的人用来洗白流量了。这种大文件请求,也是pcdn常用的技俩,正好服务器还有大资源文件,带宽又够,的确是个不错的软柿子。

鉴于在这种情况下,要解决这个问题也简单,那就是直接屏蔽掉除了eo节点之外的所有的直接流量,此时只需要找到eo的服务器列表,添加到安全组或者防护策略或者nginx的配置文件中即可,然鹅,eo免费版本并不具备此功能:

那么,应该怎么办?就只能坐以待毙吗?当然,可以通过解析加速域名的dns解析获取所有的边缘测地址:

只是这种做法难免有些不入流。

这就黔驴技穷了?那肯定不可能,想姐姐我是何种人物,没了张屠夫还非得吃带毛的的🐖?

基于边缘测的请求改写,给所有的请求添加一个自定义头,在源服务器检测就可以解决这个问题了。

边缘测:

服务器配置:

如果是openresty,直接写到nginx.conf 的http部分即可:

# 只放行 CDN 回源。直连源站(IP 或绕过 CDN)没有该头,返回 403,不读盘、不进 Daphne。
# CDN 需在回源请求上添加:baby-fuck-playboys: baby-fuck-all-invalid-requests
# rewrite 的 if 只能写在 server/location,放进 http 段会 nginx -t 失败,也盖不住各 vhost。
# access 阶段对所有 server / location 生效,先于静态文件、FastCGI、反代。
access_by_lua_block {
    if ngx.var.http_baby_fuck_playboys ~= "baby-fuck-all-invalid-requests" then
        return ngx.exit(403)
    end
}

如果是nginx 需要在每个server下面单独进行配置,当然也可以写成一个统一的配置文件,在需要启用检测的地方直接include即可。

# 只放行 CDN 回源。直连源站(IP 或绕过 CDN)没有该头,返回 403,不读盘、不进 Daphne。
# CDN 需在回源请求上添加:baby-fuck-playboys: baby-fuck-all-invalid-requests
if ($http_baby_fuck_playboys != "baby-fuck-all-invalid-requests") {
    return 403;
}

配置好之后重启openresty 或者nginx,此时没有合法请求头的访问就直接403了:

小技巧:如何修改postman的host,正常情况这个东西是不让修改的,显示calculated when request is send。那么,取消掉原来的默认host,在下面新建一个,填写自己想要使用的host就可以了。

等eo边缘测部署生效了,网站可以就可以正常访问了。

当然,前提是别改漏了。域名实在是太多了,有两个就给忘了:

 

陷阱悲剧 II

继续昨天的话题,既然“陷阱喜剧”的乐趣在于:

  • 用一个看似正常的叙事前提,让观众进入预期;
  • 不断偏离预期,但不解释具体偏离的原因;
  • 在结尾处,观众意识到自己不仅等不到一个关于偏离的具体解释,甚至不得不接受这种荒诞、无厘头的结尾。

那用这个逻辑也可以制作悲剧吗?悲剧并不一定是让人难过,也可以是完全偏离观众的预期,呈现观众最不愿意看到、或是除此之外别无选择的结果。如果说陷阱喜剧,是让人一步步远离预期,并接受超出预期的笑点;那陷阱悲剧则可以反过来,让人们一步步靠近预期,然后在最后一刻,去承当那个意料之中的悲剧。


举个例子,前些日子看过一个很喜欢的AI短剧,是描写末世之下,一个全副武装的女孩,在废墟中遇到了一只已经被丧尸病毒感染变异的小狗。她忍不住伸手靠近那只狗,狗也做出了观众期待中的回应。在她的手接触到小狗脑袋的瞬间,画面回闪,是这个小女孩与小狗一起长大的点滴。正当所有人都以为故事是朝着重逢发展的瞬间,画面的结尾是狗正在啃食已经被咬烂了面部的女孩。

我把这种悲剧形式取名叫“一脚踏空”。即在故事的最后一刻,所有人都以为故事应该朝着某个期待进展,或是知道故事的结局注定悲剧,但这一刻突然到来时,就像是一个人在最后一格楼梯一脚踏空,产生瞬间的失重感。

这类剧情最大的特点,在于很容易造成“心理污染”,让原本预期的部分被完全摧毁,从而重构一个让人不得不开始重新思考的“可能性”。


聊这个话题,并不是在“教会”什么,它本身确实是当初我在构思一个创作小组时所做的“课件”,但随着AI短剧的兴起,特别是越来越多的AI短剧已经俨然成了一套固定的、留存用户的商业模式后,如果还要用故事和AI短剧,以及AI短剧教育出来的用户硬扛,必然是输得一塌糊涂。

甚至有可能,一个想要把故事讲完整的作品,很有可能还卷不过已经形成套路的模板剧。那难道故事本身正在被AI毁灭吗?也不至于这么悲观,我反而觉得,既然已经有人分离出了一个固定的模板市场,那么故事本身仍然留给了人类自己,人类在需要“刺激”的同时,仍然还保留着对叙事结构的期待。

就比如前几天的一个有趣的新闻,一个男人在同一栋酒店的不同楼层,同时举办自己与妻子的婚礼,以及与前女友所生孩子的百日宴。这种现实狗血的剧情,在没有模板之前,AI都不敢想象。甚至有人感慨,这也是AI无法取代人类的真正原因,因为人类可以在人性层面不断地挑战所谓的下限部分。


比如我今天提到的让人在最后一刻一脚踏空的“陷阱戏剧”,或许它可以被公式化,但它模拟的不是故事本身,而是人们在追求叙事结构时对人性的理解。它可以是人们对于人性的期待,也可能是完全反人性、或是颠覆人性的存在。

比如前两天,我看到一个用AI制作的小故事。

是两个男孩在顶楼玩捉迷藏,其中一个小男孩在天台的某个角落,看到了一个正坐在顶楼护栏外的女孩子,男孩示意女孩不要出声,避免出卖自己躲藏的位置。小男孩问女孩为什么在这里,女孩说自己想一个人待着,便把自己身上的钱都掏出来给了小男孩,让他离开这里,不想把他拖入麻烦里。闻声赶来的另一个男孩,看着自己朋友手里抓着一堆乱糟糟的零钱,便好奇地问那个女孩:“姐姐,你是打算跳楼吗?”女孩点了点头,说自己的爸爸妈妈都去世了,现在自己无依无靠,原本就是打算从这里跳下去。两个男孩听了之后很担心,便把钱又塞回了女孩手里,还掏出了自己身上的零用钱和玩具送给对方,不停地问要怎么做才可以让她放弃跳楼的念头。

其中一个男孩甚至还把自己珍藏的打火机给了对方,说道:“姐姐,我把打火机也给你,我们可以做你的朋友,它可以用来点蜡烛,还可以用来放火。”女孩子接过打火机,含着眼泪笑出了声。她摸了摸两个男孩的头,说着谢谢。

故事到这里结束了,一个有关两个男孩用天真救赎悲哀的故事。

但如果要“玩弄人性”,让人一脚踏空呢?


男孩继续解释道:“前两天他们还点了一堆柴火玩。”

女孩看着打火机,笑着笑着开始无声地流泪,她嘴里嘟哝着:“前几天我家着火了,爸爸妈妈被火烧死了。”

——

感谢订阅莫比乌斯,如你有任何疑问、观点交流,请前往创作者频道,或私信联系。

出乎意料之中

✇ACEVS
作者 ACEVS

大宝周六时候讲了事情,这次考试全班唯一一个人坐标轴画箭头的,大宝还挺紧张,感觉不详预感,这次全科考试是不是有点问题。估分感觉一般错了挺多。

周天休息,大宝的群里面说成绩出来了,大宝七科全科第一次,语数外是第五,不知道是班级排名,还是年级排名,当看到群里有其他同学发布成绩单,排名1000多名后,知道大宝全科第一是全年级第一,三科第五是全年级第五,大宝不敢相信,甚至觉得是不是学校出了问题,问了豆包,这个区域这个中学不是最差的,前三。

二宝挺伤心,说大宝什么都强,学习游戏画画,干啥都比他强,本来以为他知耻而后勇了,最后探究发现因为第一可以奖励100小卷,价值50元,可以换东西,大宝大概有600.700小卷,一支攒着很少换东西,二宝的小卷根本攒不住,没有超过50个,一般几个就赶紧换东西了。

周天下午,大宝小学同学家长(比较重视学习成绩),联系wife,恭喜大宝估计高中直接进入直升班或者强基办什么的,wife说这才第一次考试哇,后面不知道如何哇。

周一晚上7.8点,班主任,说让大宝参加个学科班,本来选择的化学,但是目前还没有开设这门课,然后商量一下,选择了数学,询问周日有时间去参加吗?有没有参加课外辅导,付费兴趣课啥的,wife说一门都没有,啥付费兴趣都没。老是觉得挺惊讶的。说那家长一定付出了很多精力吧?wife说大宝三年级以后就不用管了,成绩一直不错,倒是二宝花费了很多精力时间,只是保持了不倒数。wife说大宝记忆力很好,什么都容易记住。班主任说 ,不光记忆力好,还很努力,班里也有记忆力好的,不努力成绩也不行。我在旁边想确实夸人不能夸天赋与生俱来的东西,要夸后天努力的。
班主任说她上学时候 记忆力也是很好的,大学时候很厚的一本书一天两天就搞定了。后来年龄大了记忆力感觉就不行了。后面又说到大宝的 字体问题,估计她是语文老师吧。也问了英文字体问题。后面班主任说拒接了其他家长的电话,时间挺紧,也没啥说的,就先再见了。

外婆也发来视频,说大宝考的不错,wife说不是不错,这可是年级第一哇。外婆说学到真本事才是有用的,还得不局限于书本。

我担心就是人生像股票一样高开低走,或者低走高开,或者震荡,都有可能,不管高低,都得平常心,wife和老师也讨论了 玻璃心的问题,wife觉得大宝不是玻璃心,老师观察说大宝挺开朗,也不腼腆,我想起小学毕业,大宝和所有任课老师去道别,他还是挺有自己想法的,而且能去实现它。如果失败少了?俺希望大宝玩游戏多失败一些吧。现实中如果不容易失败或者 成功,虚拟中也能体验到一点。

Coffee Break Clojure, Async

上一篇 我提及了如何用 Ring 开发 HTTP 服务器,也提到 Ring 提供了同步 API 和异步 API。那么,什么是异步编程?为什么需要异步?在什么情况下需要让一个程序同时做很多事情?

同步、异步、并发和并行

同步(synchronization)的中文名字可能会让人误以为是多个实体同时进行操作,实际上同步的意思是指系统中所有事件都依照相同的顺序进行协调。可以用工厂流水线举例,假如流水线中一个工人需要等上一个工人交付一部分工作之后才能干活,整个流水线都要所有人一起干活才能转动起来,这个流水线就是同步的。反之,假如某些工作可以分开做,比如一部分人负责生产 A 零件,另一部分人负责生产 B 零件,两者互不干扰,而最终把 A 和 B 组装在一起的又是另一拨人,这个系统就是异步的(asynchronous)。

异步(asynchrony)和并发(concurrency)很容易搞混,并不是同一个概念。异步是指系统中各个事件的状态不同步,而并发通常是指多个线程(或类似线程的东西)同时做类似的操作。

以下分别是异步和并发的例子:

  1. 小明和小华准备去桌游店玩,小明负责去买饮料和零食,而小华先去桌游店占位置。他们的状态是不同步的,小华并不需要等到小明买完东西才能去桌游店。不过,小明和小华最终会在桌游店汇合,他们一起玩桌游时,就又回到了同步状态。

    异步通常是程序里的一小部分,如果系统中所有任务都是异步的,那这些任务大概就不应该放在同一个系统里了,因为状态之间没有同步的必要。

  2. 某推销团队在城市某片区招募了 100 名推销员,给他们派发相同的任务:向路人介绍产品,并尽可能获客。从整个推销计划的角度来看,这是个并发度为 100 的系统,增加并发度能够提高单位时间内的销售成绩,减少并发度效果则相反。也可以说推销员之间是异步的,但系统整体是同步的,销售成绩最后都会汇总到一个地方。

简单来说,异步是局部状态,对系统整体影响不大,而并发则事关整个系统的执行效率,是更宏观的概念。

从编程实践来看,并发往往是更大更复杂的系统才考虑的(比方说网络爬虫必然不能一次只爬一个网页),而异步则是较小的程序会采用的轻量方案(比方说网页渲染中加载某些资源时为了不阻碍主线程,所以要异步加载)。

至于并行(parallelism),这个概念经常在操作系统的语境里和并发做区分。并行是指程序同时运行在多个 CPU 核心上,是物理意义上的同时发生;并发是指 CPU 调度器时进程交替执行,由于交替速度非常快,所以即便是在单核机器上,也能造成程序在同时运行的假象。

脱离操作系统的语境,这种区分的意义就不大了。在编程的语境下,并行是指程序在同时进行的事实(开发者很少在乎程序究竟是在多核还是在单核机器上运行的,这对编写程序而言不重要),而并发则是组织程序的一种方式。

接下来就看看如何在 Clojure 里组织异步和并发。

面向未来编程

前文提到,异步是局部状态,系统最终还是要同步信息的。许多编程语言里的做法是,在当前线程(thread)里启动子线程,相关的线程都持有对同一块内存区域的引用,他们在这一块内存区域里读写数据。之前我提到,Clojure 是 函数式编程语言 ,不允许共享状态,那怎么办呢?

假设我们需要从某个 API 获取数据,但问题是网络状态不稳定,这个操作可能很费时间。与此同时,我们还要处理手头已有的数据。

;; 这里用到了 https://github.com/dakrone/clj-http
(require '[clj-http.client :as client])
(let [response (client/get "https://example.com")
 result1 (process-data (:body response))
 result2 (process-data some-data-we-already-have)]
 (merge result1 result2)))

上面这段代码会在求值 client/get 这个形式的时候被阻塞,直到收到 HTTP 响应体。假设 process-data 操作也要费时间,这个程序的效率就很低,因为在等待网络传输的时间里,程序本身什么都没做。

如果不能提前定义 result1 变量,然后再异步执行完 client/get 之后写入 result1 变量,主线程怎么拿到数据呢?

这时可以用到 future 和 deref。future 宏接收一系列表达式,然后立刻返回一个 ref(引用),在之后,我们可以用 deref 尝试获取 ref 指向的值。如果 ref 指向的值还不能获取,就阻塞调用 deref 的线程。

(require '[clj-http.client :as client])
(let [response (future (client/get "https://example.com"))
 result2 (process-data some-data-we-already-have)
 result1 (process-data (:body (deref response)))]
 (merge result1 result2)))

把 client/get 包裹在 future 宏里之后,我们立刻得到了 response,这个 response 并不是实际的 HTTP 响应,而是对未来能够获取到的数据的引用。

拿到这个引用之后,我们立刻处理手头已有的数据。等这些数据处理完成之后,尝试 deref(解引用)一开始拿到的引用,此时 HTTP 请求已经发出有一段时间了,我们有可能直接就能拿到数据,然后就可以开始处理了;如果没拿到,也只需要再等一会儿,比一开始就等着什么也不做强多了。

持有对未来可用数据的引用,和持有对某一块内存区域的“引用”,有什么区别呢?

可以发现上述程序没有状态变更,future 返回了一个值,deref 不过以 future 的返回值作为输入,返回了新的值,数据流很清晰,很函数式。此外,它还很优雅地把程序从异步状态恢复到了同步状态,不需要我们自己写同步逻辑。

以这个 Go 程序为反例:

package main

import (
	"fmt"
	"time"
)

func main() {
 // 定义一个变量用来存放数据
 result := ""
 // 异步执行函数,两秒后给 result 赋值为 "OK"
 go (func() {
 time.Sleep(2 * time.Second)
 result = "OK"
 })()
 // 轮询,直到 result 不是空字符串才退出循环
 for {
 if result != "" {
 fmt.Println(result)
 break
 }
 }
}

这段程序既要管理状态,又要轮询状态,非常难读。

Go 语言也有自己的异步编程范式,实际上不必这么写。之后我们就会看到 Go 的异步编程,因为 Clojure 也借鉴了 Go 语言。

其实我本来想用 JavaScript 写,但我在浏览器里执行的时候,我的页面竟然卡死了。后来我才知道浏览器的 JS 运行时是单线程的,用于轮询的无限循环把主线程卡死了,JS 根本没时间管子线程,于是赋值语句就一直没执行。JavaScript 也有类似于 future 的 async 关键词,async 函数会返回 Promise,类似于 ref,而 deref 对应的是 await,详见 MDN: async function 。

如果你熟悉 JavaScript 的 async 和 await,那 Clojure 的 future 和 deref 就很容易理解。

此外,(deref ref) 可以简写为 @ref。不过用 @ 语法糖的话就用不了 deref 的超时控制。(deref ref) 默认会一直等待,如果 ref 的值一直没来,程序就会卡死;可以用 (deref ref timeout fallback) 做超时控制,如果经过了 timeout 毫秒还没能解引用成功,就用 fallback 值。

在继续之前我还要提醒对异步编程不那么熟悉的读者,无论是哪种异步机制,无论怎么实现并发,线程的执行顺序都是不固定的。

(dotimes [number 10] (future (println number)))
;; 05
;; 423
;;
;; 8
;; 9
;; nil1
;; 7
;;
;;
;; 6

上面的输出很乱,原因在于 println 的换行符何时打印也不能确定,dotimes 本身的返回值 nil 也混在这些换行得乱七八糟的数字当中。

有办法能控制并发的执行顺序,但要保证顺序必然要有等待、排队的过程,速度就有损失,甚至有可能变成串行的。如果要严格同步,那就不应该异步——是的,这是句废话。总之,需要严格保证执行顺序的操作不该异步。

不阻塞的异步

尝试解引用 future 返回的引用可能会阻塞当前线程,如果希望当前线程不被阻塞呢?有时候我们并不需要严格同步数据,如果新值没有到达,那就用旧的值。

比方说我们有个计数器,每 5 秒给计数器增加 1,解引用这个计数器就拿到当前的数,而不是等五秒过后再拿新的数。

要这么做,可以用 agent:

(def counter (agent 0))
;; => #'user/counter

@counter
;; => 0 

(future 
 (doseq [_ (range)] 
 (Thread/sleep 5000) 
 (send counter inc)))
;; => #object[clojure.core$future_call$reify__8574 0x4abf3f0 {:status :pending, :val nil}]

@counter
;; => 0 

;; 五秒过后 
@counter
;; => 1

doseq 宏接收类似 let 的绑定,用于遍历序列。(doseq [item data] (f item)) 相当于 (doall (map #(f %) data))——如果不需要操作集合数据,比起 map 和 doall,doseq 宏看起来更干净。

上述代码中传入的是无穷的惰性序列,所以会无限循环。每次循环都让线程先睡五秒钟,然后再执行操作。放在 future 里是为了不阻塞主线程。

这里的 send 函数是专门和 agent 一起用的,作用是把一个函数发送给 agent,让 agent 对自己保存的数据做处理。这个过程是异步的,send 会立刻返回 agent,之后再解引用 agent 就能拿到 agent 当前的值。

agent 是线程安全的,不必手动加锁。

你可能发现了,这难道不是非常不函数式吗?比方说,如果不把 agent 用于异步编程,我们完全可以违反「不允许可变状态」的规则,做这种事情:

(def counter (agent 0))
;; => #'user/counter

(deref counter)
;; => 0 

(send counter inc)
;; => #object[clojure.lang.Agent 0x2f6bbeb0 {:status :ready, :val 1}]

(deref counter)
;; => 1

(send counter inc)
;; => #object[clojure.lang.Agent 0x2f6bbeb0 {:status :ready, :val 1}]

(deref counter)
;; => 2

这就要靠程序员的自觉了。不过,agent 其实没那么好用,因为只能发送函数,而不能替换值本身1,用途很有限。

agent 可以存任何类型的值,也可以存集合类型,比方说我们可以一次性给 agent 发多个函数,而每个函数的返回值都是由旧集合拼接成的新集合,就可以并发地处理多个数据。比方说,下面是一个简单的并发爬虫,把数个 HTML 页面塞进了同一个向量里:

(defn crawl [url] 
 (:body (client/get url)))

(defn crawl-append [old url] 
 (conj old (crawl url)))

(def crawler (agent []))

(def urls ["https://chlo.is"
 "https://www.geedea.pro"
 "https://blog.cytrogen.icu/"])

(doseq [url urls]
 ;; crawler agent 里面已经有的值会作为 crawl-append 的第一个参数 
 ;; 后续传入的可变数量的参数(如这里的 url),会变成 crawl-append 剩下的参数
 (send crawler crawl-append url))

@crawler
;; 会返回由当前已经爬取完成的 HTML 字符串组成的向量

对于这种结构简单、数量确定的操作,还可以使用 pmap(parallel map),也就是并行版本的 map。下面这段代码是并行的(准确来说是并发),不需要 agent 也不需要 deref。

(pmap crawl urls)
;; 会返回包含所有爬取结果的惰性序列

pmap 返回的是“半”惰性序列,这些 crawl 其实已经执行了,只不过没有把值返回过来,只有在读取惰性序列的时候才会得到值。pmap 底下用的是 future。

如果要用 map 处理耗时较长的任务,就可以考虑换成 pmap 同时处理。

;; A function that simulates a long-running process by calling Thread/sleep:
(defn long-running-job [n]
 (Thread/sleep 3000) ; wait for 3 seconds
 (+ n 10))

;; Use `doall` to eagerly evaluate `map`, which evaluates lazily by default.

;; With `map`, the total elapsed time is just under 4 * 3 seconds:
user=> (time (doall (map long-running-job (range 4))))
"Elapsed time: 11999.235098 msecs"
(10 11 12 13)

;; With `pmap`, the total elapsed time is just over 3 seconds:
user=> (time (doall (pmap long-running-job (range 4))))
"Elapsed time: 3200.001117 msecs"
(10 11 12 13)

上面这个例子来自 ClojureDocs 。

你可能好奇,如果 pmap 处理大量的数据,比方说一不小心传了个无穷序列进去怎么办?这会同时处理无穷个数据,把 CPU 撑爆吗?老实说,我不知道具体会发生什么,但大概率 Clojure 或 Java 会控制最大并发数,根据当前负载,把过多的请求串行化以减轻压力。

无论有没有这种说法,程序自己完全不控制并发数量也是不行的。无论是 future 还是 agent,貌似都没有提供很好的并发控制机制,难道只能一开始就少派发任务吗?如果不确定有多少任务要运行呢?

Gopher?是你吗?

命名空间 clojure.core.async 提供了另外一种异步编程的方式,但没有放在标准库里,必须要添加依赖才能使用。

;; deps.edn 
org.clojure/core.async {:mvn/version "1.9.865"}
;; leiningen
[org.clojure/core.async "1.9.865"]

core.async 几乎和 Go 语言异步编程的要素一模一样,尤其是 go block——把语句放在 go block 里面,语句就会异步执行。把消息队列 chan 当作一等公民的做法,也如出一辙。根据 Clojure 官方的博客文章 ,这种异步编程风格其实有一段历史了,Go 也是借鉴并现代化了这种做法。

The roots of this style go back at least as far as Hoare’s Communicating Sequential Processes (CSP), followed by realizations and extensions in e.g. occam, Java CSP and the Go programming language.

无论如何,让我们来看看怎么用 go 和 chan 实现异步编程吧。如果你已经会写 Go,那么接下来的代码会很熟悉。

(require '[clojure.core.async :refer [go chan >! <!]])

(def queue (chan))

(go 
 (>! queue "Hello?"))

(go 
 (println (<! queue)))

上述例子中,我们启动了两个 go 线程,一个线程把 "Hello" 放进 queue 里,另一个线程把 "Hello" 取出来。

chan 函数用于创建 channel(频道),可以理解为消息队列。对于 channel,有放(put)和拿(take)的操作,分别用 >!(放)和 <!(拿)表示。这里的 ! 类似于 ?,是 Clojure 的命名习惯,用于标识会对状态进行变更的操作。说到底,我们的确对状态进行了变更,上述语句缺乏引用透明性,不够函数式。

chan 可以设置缓冲区大小,(chan 5) 就是缓冲区大小为 5 的队列,一旦队列满了,再试图往里面放消息,放消息的线程就会被阻塞。

(def only-put-once (chan 1))

(go (>! only-put-once 1)
 ;; 下面这个操作会阻塞这个 go 线程
 (>! only-put-once 1))

反之,如果队列空了还试图从里面拿东西,就会阻塞拿消息的线程。

(def empty-chan (chan))

(go (<! empty-chan)
 ;; 除非有人往 empty-chan 里放东西
 ;; 否则下面这句话不会被打印
 (println "Help! I'm blocked!"))

go 在 Clojure 里是个宏,在 Go 里是个放在函数调用之前的关键字,效果都是让语句异步执行。不过 Clojure 中的 go 会返回一个 channel,go block 里的语句执行完成后,会把返回值通过 channel 传递回来。2

放和拿的操作可以阻塞线程,因此可以用作并发控制。

学过操作系统的读者可能知道信号量(semaphore),我们可以用 chan 实现简单的信号量。比方说,我们先给一个 chan 存入 50 个信号,然后启动不定数量的 go 线程,但在启动线程之前,派发器必须要拿到信号量才行。如果信号量不够(尝试从空队列里取数据),就会阻塞派发器所在的线程,直到有信号量被回收。

(require '[clojure.core.async :refer [go chan put! <!! >!]])
;; 定义信号量
(def semaphore (chan))
;; 将 50 个空 map 放入信号量中
(dotimes [_ 50]
 (put! semaphore {}))
;; 启动一个无限循环派发器
(doseq [number (range)]
 ;; 尝试获取信号量,如果已经消耗完 50 个,阻塞派发器
 (<!! semaphore)
 ;; 获取到信号量时,启动 go 线程
 (go (Thread/sleep (rand-int 10000))
 (println number)
 ;; 线程工作完成后,把一个信号放入 semaphore
 (>! semaphore {})))

上述程序永远不会同时运行超过 50 个 go 线程。也可以反着实现,定义大小为 50 的 channel,每派发一个线程之前都要放个东西到 channel 里,比如 {}3,放满了话的话就阻塞。不妨试着在 REPL 里写一写试试?

需要注意的是放和拿的操作有很多变体,在不同场景下使用。之前提到的 >! 和 <! 只能放在 go block 中,放在其他地方会报错。

在 go block 外,可以用 >!! 和 <!!,一般不建议用,因为会阻塞主线程。更好的选择是 put!(放)和 take!(拿),这两个操作是异步的,无论放没放进去、拿没拿出来,都不会阻塞当前的线程(但是会阻塞异步的子线程)。

由于 take! 是异步的,不会立刻返回值,所以得传一个回调函数给它,这样在能拿到值的时候,就会调用回调函数。下面是 ClojureDocs 的示例:

user=> (def c (chan 1))
#'user/c

user=> (take! c
 (fn [x]
 (println "Clojure callback value " x)))
nil

user=> (put! c "XYZ")
Clojure callback value XYZ
true

user=> (put! c "XYZ")
true

此外还有 offer!(放;给)和 poll!(拿;查),这两个操作是同步的,但也不会阻塞线程。offer! 会检查 channel 的缓冲区是不是满的,如果满了就返回 nil,如果能放进去就返回 true;poll! 也类似,能拿就拿,不能拿就返回 nil。

像 Go 程序员一样写 Clojure

Go 语言程序经常用 goroutine4 和 channel 实现各种并发处理管线。我刚才已经演示了两个线程(协程)用 channel 异步通信,演示了派发器和并发控制。我们还可以把更多 Go 语言的编程模式搬到 Clojure 里来。

我前面提到,core.async 提供的这套异步编程模式很不函数式,因为 channel 就是存放状态的队列,与之相关的放和拿的操作也不具有纯函数应有的引用透明性。

不过这是否值得呢?接下来我要用 Go By Example5 网站上的 Stateful Goroutines 的例子回答这个问题。

 reads := make(chan readOp)
 writes := make(chan writeOp)

 go func() {
 var state = make(map[int]int)
 for {
 select {
 case read := <-reads:
 read.resp <- state[read.key]
 case write := <-writes:
 state[write.key] = write.val
 write.resp <- true
 }
 }
 }()

select 经常和 chan 一起用,放在 select 的哪个 case 中的 chan 先来消息,就先执行哪一个 case,也就是说可以同时等待多个 chan。

上述代码中的 goroutine 管理了一个状态 state,即 stateful goroutine。它接收其他 goroutine 通过 channel 传递过来的消息,然后通过消息里携带的 resp(也是个 channel)把处理结果写回那些 goroutine。

简单来说,这个 stateful goroutine 接收读操作和写操作。读者和写者不持有状态,只是发消息给 stateful goroutine,让它帮忙管理状态,然后给它一个 channel,稍后把处理结果发送回去。

 for range 100 {
 go func() {
 for {
 read := readOp{
 key: rand.Intn(5),
 resp: make(chan int)}
 reads <- read
 <-read.resp
 atomic.AddUint64(&readOps, 1)
 time.Sleep(time.Millisecond)
 }
 }()
 }

上述代码派发了 100 个读者 goroutine,每个 goroutine 都把封装好的读操作写入 reads channel,然后等待 resp 被发回来。相对应地,还有写者 goroutine,这里就略过了。

不知道你有没有注意到几件事:

  1. 管理状态的 goroutine、读者和写者之间,是解耦的,我们只需要有一个中间人(比方说 main 组件)把 channel 发给他们,他们就可以在没有代码依赖的情况下相互通信
    • 这很方便测试,假设我要测试 Stateful goroutine 是否工作正常,我不需要启动读者和写者,我只需要把测试数据写入 reads 和 writes。
    • 这让架构变得灵活,我可以随意重构三个组件,完全不会互相影响,不会出现某个组件的函数签名改了,另一个组件的函数调用也要改的情况。
  2. 我们把状态管理集中到了一个组件里,读者和写者可以是无状态的。
    • 函数式编程的重点就是要管理状态和副作用,用 goroutines 和 channel 把状态管理集中到一个组件,也算是殊途同归了。
  3. 三个组件在共享数据,但是完全不需要加锁!

要在 Clojure 里实现类似 select 的结构,可以用到 alt!(alternative)。

;; (go-loop ...) = (go (loop ...))
(go-loop [state {:key "val"}]
 (alt!
 reads ([read-op] 
 (>! (:chan read-op) ((:key read-op) state))
 (recur state))
 writes ([write-op]
 (recur (assoc state (:key write-op) (:val write-op))))))

不过,如你所见,除了 >!,这比 Go 语言的版本要更函数式一些,因为我们没有给 state 赋值,而是在 recur 一次又一次的递归调用中,不断给 go-loop 传入了不同的参数而已。

我不久前就在工作中解决了一个不大不小的性能问题:系统中有大量 goroutine 等待 SQLite 的锁,导致计算资源闲置,而要写入 SQLite 的数据不过是些日志,并不着急同步。于是,我的解决方式是引入一个写者,所有写入数据库的操作都通过 channel 传递给这个写者,由写者这一个实体写数据,这样就不需要锁了。其他 goroutine 把写操作的情况放入 channel 之后就可以继续做自己的事情,不必等着把日志写进数据库。6

把副作用、状态管理和 I/O 操作集中在系统的一个组件,通过 channel 解耦其他组件与状态管理组件,能很好地降低系统的复杂性。

我应该用什么?

future 和 deref 很简单,agent 和 send 似乎也不错,go 和 chan 更是能很好地管控系统的复杂性,我究竟应该选哪个?

老实说,我觉得这是程序员需要多写代码才能建立起来的认识。读者应该在实际的场合下权衡取舍,而不是选定一个万金油方案。这些方案都有利弊。

future 和 deref 基本对应 JavaScript 的 async 和 await——轻量,易用,非常函数式。可如果要构建复杂系统,严格控制并发,甚至根据系统负载动态调整并发度,这种轻量的方案就不太适用了。

agent 和 send 的模型更关注数据处理,毕竟 agent 在创建时就需要指定初始值,而 send 的作用是给 agent 发送一个操作,对其中的数据做操作。再者,agent 天然就是并发安全的,可以减少自己加锁的麻烦。处理数量可控且相对轻量的数据时,就可以用 pmap。

go 和 chan 就跟它们在 Go 语言里的地位一样,如果要开发高并发的复杂系统,或者管理系统的复杂性,将组件解耦,就可以抱着抛弃函数式风格的代价使用。core.async 其实遭到了 批评 ,而且的确有一些问题。Stack Overflow 上的 aeuhuea 就举了个很典型的例子:

(defn take-and-print [c]
 (println (<! c)))

(def ch (chan 1))
(>!! ch 123)

(go (take-and-print ch))
;; Assert failed: <! used not in (go ...) block

上面的代码报错了,因为 <! 和 >! 如果被放在函数里面,就会被认定没有按规定放在 go block 里,哪怕函数就是在 go 里面调用的。我一般的解决方法是把 <! 取出的值作为参数传递给函数,或者用宏。

最后

异步编程很难不考虑状态,我还真的有点好奇 Haskell 作为纯函数式编程语言,不像 Clojure 这样容忍一部分的可变状态和副作用,是怎么实现异步的。我得找时间去研究研究。

这些概念可能不太好理解,我希望我讲清楚了。如果你有任何问题,或者发现了我有疏漏的地方,欢迎给我发邮件。那么,回见!


  1. 其实可以给 agent 发这样的函数:(fn [_] "new value") ↩︎

  2. 说实话,很少用 go 返回的 channel 取返回值,因为不如 future 和 deref 方便。 ↩︎

  3. 在 Go 语言里,空结构体 struct{} 不占空间,所以经常用来做信号量放进 channel 里。Clojure 的空映射 {} 底层是个 Java 类,不可能不占空间,这里只是我自己的习惯,你可以换成 true、:signal 之类的,但是不能放 nil,会报错,因为 nil 在某些操作里表示 channel 关闭了或者空了。 ↩︎

  4. 即协程,是 Go 语言建立在线程之上的用户级、轻量的并发单元,用 go 启动。Clojure 里的 go 仅仅是借其形式,不见得和 goroutine 一样轻量(我们可是在 Java 虚拟机上啊!)。 ↩︎

  5. 这个例子由 Mark McGranaghan 和 Eli Bendersky 编写,用 CC BY 3.0 协议 授权。我只截取了其中的一部分。 ↩︎

  6. 唯一的缺陷是,如果程序意外退出,而 channel 里还有些日志没写入数据库,这些数据就丢失了。 ↩︎

scum二次测试

✇ACEVS
作者 ACEVS

从医院跑出来去了另一个岔路口,一支往前跑,看到一片房子,第一幢房子,就和那个美剧行尸走肉某集里面的场景一样,所有的门窗都被木板钉了起来,估计里面的人也变成了僵尸,我也进不去了。

我现在生命值不高60%多,似乎还在流血,屏幕上不是滴落一滴血提示我的状态似乎。打完两个僵尸后,生命值50%左右了。房子里面肯定大部分都有僵尸,而且不能躲开,或者说不好躲,堵住门口就无法出去,我就在街道马路上,搜索垃圾桶,路障,还有废旧的车,铁板,木板,橡胶,电线,胡萝卜汁我直接喝完了,苏打水也直接喝完了。找到一个铁管,感觉有了信心,找了两个僵尸,一个打倒以后搜出来一些电池,还有胶带,感觉没啥用,不过重量不重戴在身上,在另一个垃圾筐里面找到一个磁带机,想着电池是不是可以用上了,果然可以装载电池进去,电量不多了还有28%左右,开启收音机功能,里面传来聊天,唱歌声音,我本想着拿着收音机一路走吧,但发现手里只能拿一种东西,我也不知道收音机砸僵尸什么效果,最后我还是选择了铁管我在手中,收音机扔在了地上。

这个时候系统提示我要小便,我观察面板没有发现上厕所的按钮,我问豆包,豆包说tab键,然后选择马桶里面的子选项小便。我想是不是 这就是擦边的地方,点击完,那人只是做了上厕所的动作,裤子都没脱,然后还有小便的效果,从头到尾都是穿着裤子的。

后来有干掉两个僵尸生命值只有30%左右了,而且不停地往下掉,后面视线模糊了,移动变慢了,似乎只能等死了,现在终于明白为啥有自杀那个选项了。那就是测试一下自杀,好像是直接取出了头部的芯片。没大看清楚。

人渣scum游戏测试

✇ACEVS
作者 ACEVS

当擦边游戏下载,可能没样子mod加强吧,
这个游戏介绍挺夸张,男性可以调节生殖器大小。还有打了马赛克的视频在b站。
感觉挺夸张,gofile下载速度不错50m/s
安装后,测试,游戏设置的细节蛮多的,健康情况,身体手上部位,头部,胸部,手臂,什么地方受伤就用绷带,感染了还得用抗生素,物品都有重量,衣服提供什么程度的保温,细节蛮多的。

教程我控制一个橘红色衣服的男人,他刚醒来,之前被做过后脑勺植入芯片,然后f健在手术台那个屋子里面找到一些绷带,然后头上还在流血按照提示操作止血。然后走路跳跃攀爬等测试,最后来到一个大屋子里面,按照提示,打磨石头,然后收集树枝,大树枝切成小树枝,做成树枝绳,这个地方卡住了,豆包说需要四五根树枝,手里还有拿着石头刀,然后触发,那个屋子里面的树我都砍完了,就是搓不出来树枝绳。我退掉游戏后,重新来了一遍,按照豆包提示,莫名其妙发现有了树枝绳,加上石斧头,再加一个树枝造出来了石斧。然后出门。这就是咱得出门装。石斧一把。

出来一个洼地,草丛杂生,应该荒废了,然后不远处有人影晃动,走进一些一看,就知道是僵尸,拿着石斧一阵猛砍,这个游戏有人说挺真实,挥动斧子还有攻击间隔,如果掌握了节奏僵尸都没有机会攻击你的感觉,如果错了节奏,僵尸一直揍你,费劲砍了好多次干掉一个僵尸后,看到木箱旁边躺了一个僵尸,身上有把武士刀插在胸前,似乎还在淌血,我拔出这把武士刀,挥了一下感觉挺顺手,上了一个小坡,看到远处一个僵尸发现了我朝我扑来,我只挥了一刀,直接把它打倒。f键把他的衣服脱光了,有的鞋子衣服还能用上,我不小心多按了什么按键,直接把僵尸肢解了,我无语了。

后面我进入一个屋子里面。屋子里面感觉就是军火库,手枪武士刀,弹夹腰带,面具,维生素,整包的绷带还得拆开才能用,弓箭,战术头盔,防弹衣,我全副武装出去,那个武士刀,前面几个杀着挺简单,遇到一个拿手枪的和我衣服一样人,我蹲下去慢慢移动,等着他出现,我打算扑上去一刀结果他,实际效果是啥?我两在障碍物拐角相遇,我蹲着还没站起身来,他一梭子子弹也打没了,我正高兴,没想到,他直接用枪托子对着我战术头盔,啪啪的猛击,而且毫无停下来的感觉,我刀都没挥出去,被他砸的满头流血,最后倒在血泊中。

复活后,我找了个手枪,在屋里面,装填好子弹还不放心,因为看不到准心,我对着墙壁感受了一下大概射击的感觉,整了个防弹背心穿上,想着胜率高一些。推门出去,那人已经过来了,我打了三枪,他毫发无损,然后他开了几枪,我直接归西,估计爆头了。

复活后我就弄了手枪,出去一枪还是2枪干掉了他,教程结束。

我创建了一个游戏,选择了一个女性角色,可以调节胸围大小,选择脸头发,年龄什么的,发现和擦边没啥关系,进了游戏脱了衣服发现也没什么擦边的哇。然后开始发现远处有小屋,进去搜索物资,结果我被两个僵尸封在卫生间不能出去,那僵尸生前可能是特种兵,背了个大背包,好不容易干倒一个,一阵搜索没啥武器,我这个时候身上多处流血,绷带用完了还在流血,我从卫生间出去,想找东西感觉视线都模糊了,一看身体健康度20%左右,还有持续流血,没有绷带止血的话,虽然有自杀选项,但是我还是想搜索看看有没有机会,最后另一个僵尸的出现,直接干掉了我。

重开一把 ,这把落在树林杂草里面,好不容易找到一条公路,顺着公路跑,遇到一个英文牌子,看不懂,跑到后发现是个废弃的医院,门口的垃圾堆里面找到一把手术刀,挥了一下完全看不到刀。估计和小刀威力差不多。那个很多层的楼我都不敢进去,不知道里面僵尸多不多,旁边的一层楼进去转了圈,杀了两个僵尸找到一些绷带包,病号服,没啥用处。由于白天屋子里面赚了2圈,我本人头晕的厉害。我出了医院,跑上公路,去岔路口那个地方,跑在马路上的时候不那么头晕了。

公德与法律

当你开车行驶在美丽的大草原上,秋季让草原披上了金黄色,小湖错落地点缀于金黄之间,雄鹰盘旋于蓝天,羊群连接着远处的天际…… 正当你陶醉于美景之中时,前面的车突然打开了车窗,扔出一袋垃圾,于是你气坏了,怎...

时过境迁

对象开的那辆博越,后车窗贴的膜气泡越来越多,越来越大。侧面的玻璃上贴的膜也出现了一些水波纹,不仔细看还好,盯着细看的时候就变得有些让人难以忍受。

终于在十一之前把车送到了店里,重新贴了玻璃上的膜。贴完之后,感觉视野都变亮了。相比粉皮上贴的玻璃膜,有点太暗了,晚上开车的时候能见度就稍微差了点,私密性是够了,晚上开车就有些累,尤其是光线不好的时候。

贴完膜,车里多了一堆零配件,行车记录仪、etc等等都从玻璃上拆了下来,仍在副驾的座位上。国庆假期结束前自己才去公司的停车场把车换回来,贴完膜前几天不让开窗,车里也有一股除胶剂的味道,放在停车场散一下味道也刚好合适。

行车记录仪好办,从家里拿上3m胶、剪刀,三下五除二就贴回去了。重新安装etc的时候,出bug了。因为设备拆卸过,需要重新激活,去app查看激活方式,提示要激活蓝牙。有找到操作手册,根据自己的型号找到操作方式:连续插拔两次卡片激活蓝牙,设备蓝牙激活后,会亮起一个绿色指示灯。

这操作方式也简单,那就插拔呗。先把设备重新安装到前挡风玻璃上,然后开始插拔:

插进去,拔出来,插进去,设备状态:红灯、绿灯(不是左上角的),屏幕显示:记账卡,从此没反应了……

插进去,……,拔出来,……,插进去,没啥变化,还是红灯 绿灯,然后就没然后了……

插……进……去,拔……出……来,插……进……去,照旧……

插……进……去,……,拔……出……来,……,插……进……去,照旧……

重复上面的步骤,最后来多一步拔出来,依然如故。连蓝色的指示灯什么样都没看到。以为是设备问题,打开手机蓝牙搜了半天也没搜到设备。这尼码就离谱啊,这几乎能用的姿势都换了啊,怎么就不行呢。

此时想着肯定是设备问题了,既然不行了,那就换个新的?直接进入线上办理,发现新设备还要钱199,这尼玛就离谱啊,我以前没有的话买个也就买了,这我都有设备了,还要钱,过分了。直接打高速服务电话,报上车牌等相关信息,对方查了会儿,告知:这个设备是以前建行的网点办的,现在服务点没了。并且这个设备没有蓝牙模块,激活不了。现在也没线下激活的服务网点。不过可以通过小程序申请更换新的带蓝牙的设备。

好吧,这好歹也算是个解决问题的办法,毕竟还省了199,不过更换只是更换设备,卡还是原来的卡可以直接插回去接着用。说实话,当然从建行办的这个破设备就贼拉恶心,不知道是谁用过的设备退回去的,面板上都是划痕,不过当时推广免费办理的,也就不强求那么多了。为了更换设备,有把etc重新贴回去,拍车头照片,etc安装照片,拆下来的设备照片,卡片照片,行驶证照片等一堆乱七八糟的东西提交上去。

卡片也晒得变色了,毕竟也快十年了。

为了让这个卡片不怎么恶心,买了几张hello kitty的卡贴。

一通折腾之后,终于算是给插进去了。看起来最起码没这么恶心了。

终于昨天的时候,新设备到了,又是一通折腾,把新的设备装进去。

上午想着更新下应用宝的findu版本,进入后台发现竟然是未上线状态:

打开消息记录,看着到了这个:

时过境迁,我已经不配。

❌