用 GNU sed 开天辟地

如果你熟悉中国神话或博客众,那么你说不定听说过被半开玩笑地称作“盘古之白”的排版习惯:在中文字符(但不包括标点符号)和拉丁字符或数字之间增加一定间隔。我所实行的这一规则的变体还包括在所有 HTML 元素(如链接和强调)的周围也加上间隔。

到目前为止,我一直在源文件(Markdown 或 org 格式)中手动添加空格:这无疑是实行这一规则最糟糕的方法。除了要费额外的工夫之外,这类排版规则还应该,在我看来,仅在输出/渲染时应用。更不用说手动调整我刚刚恢复的那一大堆旧日志不是什么吸引人的差事。因为不愿加载额外的 JavaScript,我转向了万能的 GNU sed。为了将盘古之白添加到 Hugo 生成的 HTML 和 XML 文件中(通常在 ./public 目录里),我使用了以下 shell 脚本:

#! /usr/bin/env sh
# For punctuation marks to be recongnized correctly.
export LC_CTYPE=en_US.UTF-8
find . -path "./public/*" \( -name "*.html" -or -name "*.xml" \) -print -exec sed \
     -e 's/\([a-zA-Z0-9]\|<\/[a-z]*>\)\([^[:punct:][:space:]a-zA-Z0-9\s]\)/\1 \2/g' \
     -e 's/\([^[:punct:][:space:][:alnum:]]\)\([a-zA-Z0-9]\|<[a-z]\)/\1 \2/g' \
     -i {} ";"

如果你想坚持履行这一 W3C 工作草案 给出的第一选择,且并不在意生成网页的大小的话,可以换用 CSS 来生成这一间隔:

find . -path "./public/*" \( -name "*.html" -or -name "*.xml" \) -print -exec sed \
     -e 's/\([a-zA-Z0-9]\|<\/[a-z]*>\)\([^[:punct:][:space:]a-zA-Z0-9\s]\)/\1<span style="margin:0.25ch;"><\/span>\2/g' \
     -e 's/\([^[:punct:][:space:]a-zA-Z0-9]\)\([a-zA-Z0-9]\|<[a-z]\)/\1<span style="margin:0.25ch;"><\/span>\2/g' \
     -i {} ";"

如果你也是盘古之白的信徒,那么在本站留下评论时请不必担心手动添加空格:由于 Hyperskip 评论会在 Hugo 构建站点时插入,它们也会被以上的脚本影响到。请尽管坐下、放松、享受这空白一片的绝景吧。

三月结束时也和狮子一样

直到几周前(在看 Level1 News 时),我才了解到这条谚语的完整版本:“三月像狮子一样来临,像羔羊一样离去。”我是从漫画《3 月的狮子》得知前半部分的,但我当时并不知道这句话是在描述三月的天气。

以上其实就是我开始写这篇日志的的全部动机,但今年的三月的确相当不寻常。由于 COVID-19,我正在家中“远离社交”,或者说是沉浸在独处的享受中。为了准备长时间在家工作(绝对是借口),我进行了一连串的电子产品升级:我购置了第二台显示器、显示器支架和更大容量的 NAS 硬盘。实际上,去年秋天以来我一直在逐步扩展我的设备库。也许我该写一篇日志来记录这些。

我开始自己做饭是三年之前,而最近两年亚马逊的 Prime Now 服务成了我赖以果腹的唯一食材来源。自己的日常起居竟然如此依赖亚马逊的事实是有点令我担忧。但是在我拥有自己的地下基地和蓝藻农场之前,我只能凑合维持这种共生(或者应该说是寄生)关系。不过,我不确定我是否真的喜欢烹饪,至少我花在烹饪上的大部分精力都在如何减少而非增加在厨房里花费的时间。幸运的是,我几乎从不厌倦吃相同的食物,所以我一直做着相同的几道菜肴,并逐步将每一道菜的准备工作优化到最简:我的早餐是酸奶和混合干果,午餐是咖喱牛肉饭,而晚餐则是煎三文鱼配米饭和炒卷心菜。

病毒的肆虐也使我不得不暂时搁置跑步计划:我平时使用的路线已经不向公众开放。所幸在开始居家远离社交之前,我已经超前完成了不少里程(比起预订计划提前了 4 周),所以我仍然有望实现 2020 年的目标。也许是由于路上的积雪,我的跑步鞋(美津浓 Wave Rider 23)磨损得比以前更快:在累积里程达到 250 英里时,我已经感觉到跑长距离时足弓不适,而这双鞋以前的版本可以一直撑到 300 英里左右。除了鞋子问题外,随着我逐步延长的跑步时间,我时有胫骨疼痛的现象,所以我正好趁这个机会休息一阵。为了最终在工作日也能跑步,我转为了晨跑派。到目前为止,尽管有个别风雪交加的日子比较难熬(但其实挺有趣的),我仍喜欢这一决定。另外,能看到更令人振奋的日出而非日落也是个优点。

在病毒爆发期间所读到的新闻经常给我带来一种不真实感:既因为实际发生的事情,也因为新闻那种刻意挑起矛盾的报导方式。好吧,公平地说,要求一个以掠夺人们注意力为食的机构以朴实、不带修饰的方式来报导新闻本身就是一种矛盾。不过话说回来,同样从当前的情况更多地感到兴奋而非不安的我或许没有资格对新闻媒体的做法挑三拣四:仅仅想到这间普通的公寓现在是我抵御尚无治疗方法的病原体的个人要塞就足以让我睡不着觉。

如果这确实是人类覆灭的开始,至少我的博客和 Emacs 配置将由于 Github 存档计划 继续存在(假设微软没有说一套作一套的话)。在那之前,请保持安全,不要随便离开自己的胶囊生活仓,并做好准备迎接我们一直苦苦等待的荧光色太空时代藻制食品吧。

Mastodon 和 Gitea 的静态替代品

就像我当时决定换掉 Wordpress 一样,我觉得我已经受够了运行 Mastodon 和 Gitea。

跟上 Gitea 设置选项的频繁改变一直很烦人,而使用 Mastodon 时,由于系统库版本不匹配(通常是 protobuf)造成的依赖软件包出错十分常见。尽管后者不是 Mastodon 本身的错,但需要额外安装两个软件包管理器(分别用于 Ruby 和 Node.js)来运行一个程序对我来说是很荒谬的。

我于 2018 年开始在服务器上运行两者:先开始的是作为 Twitter 替代品的 Mastadon,而 Gitea 则是我后来对微软收购 Github 的回应。回头想想,相对于我的需求,这有点大材小用:我的 git 服务器和微型博客的主要用例都是单用户中心的只写任务。这意味着这些内容应以只读形式提供给我网站的访问者,而静态网页正是完美的替代品。

从 Mastadon 开始说起,我现在使用 twtxt 格式存储和发布我的微型博客。这一格式已经存在了一段时间,但最近在波浪号社区(tildeverse,一系列提供可公共访问的类 Unix 系统的网站)中开始重新流行。尽管现在有一整个旨在为该格式添加更多功能的社区支持的生态系统(其中包含各种语法扩展和软件),但我发现最基本的的时间戳加制表键加文字的语法已足够满足我的需求。这种即写即忘的形式确实很容易上瘾,尤其是与自己写的命令行客户端搭配使用时(我的版本被恰当地命名为 twixter)。

至于 Gitea,虽然我认为是 Github 的优秀替代品,但它更适合于多用户协作,而不是作为个人项目的闲置场。我决定直接自己管理 git 仓库(参阅《Pro Git》的 4.44.5 章),然后使用 stagit 生成相应的 HTML 文件。这些由 stagit 生成的页面已经替代 Gitea 作为新生的 川陀全息档案馆

在解决了我在线存在的只写任务需求后,我将继续探索剩下的两个难题:只读(内容消费)和交互(通讯方式)类操作。目前,订阅源和电子邮件是我最好的答案,但是它们仍然不足以涵盖我所有的需求。

外太空九号博客

最近,我在想办法将我的微型博客整合到当前网站里,所以我开始重新考虑 IndieWeb 所提倡的一些构想:与希望一切都通过服务器 API 和 JSON 响应来动态完成的 ActivityPub(Mastodon、Pleroma 等用于互联的协议)不同,IndieWeb 社区推荐的不少标准都支持从有正确标记的静态 HTML 文件中直接生成机器可读的网站源。IndieWeb 隐含地依赖的一大核心要素是 URI(统一资源标志符)的稳定性,或者从更高的角度来说,站点所有者对域名的控制。由于最近关于.ORG 域名的 闹剧,我逐渐意识到,一个域名昂贵到无法维护(或可能随时被扣押)的未来可能并不是遥不可及的。这会严重破坏整个 IndieWeb 赖以建立的前提,更不用说更常见的链接失效了。幸运的是,我觉得 IPFS(星际文件系统)有潜力能够解决这两个问题。

IPFS 速成班

好的,好的,我知道和一些类似的项目,例如 Dat 协议pingfs,甚至 Scruttlebutt,比起来,IPFS 的名称听起来非常不靠谱(相信我,我开始时也和你一样怀疑),而不少加密货币类创业公司将 IPFS 与各种首字母缩写词混杂在其营销资料中的事实更降低了它的可信度,但 IPFS 看起来的确是类似项目中最成熟且易于使用的。以下我对解释 IPFS 所做的尝试,其信息大部分来自 官方文档 和这一 讲座。如果你对进一步的实现细节感兴趣,这一 来自 IPFS Camp 2019 的专题讨论 是一个很好的起始点。

简单地说,一条网页链接只是指向某服务器上文件路径的一种花哨说法。就像一般的文件路径一样,服务器下线后,即使坐在同一房间的某人可能缓存了网页内容,该链接也无法被访问。在 IPFS 中,文件(或数据块)通过与其内容相应的加密哈希值作为地址,并以分布式的方式存储在所有用户群中。这意味着我们不需要中心化的设施来访问文件、可以简单地验证文件完整性、可以使用 P2P 共享来加快访问速度、以及以这种方式存储的文件内容是无法改变的。

无法更改文件内容相比我们所得到的好处来说似乎是一个相当昂贵的代价,但是就像计算机科学中的任何其他问题一样,这可以通过添加抽象层来解决。解决这一问题的 IPNS(星际域名系统)利用公钥加密来创建可以指向不同文件的不可变地址。IPNS 地址基本上就是某个公钥的哈希值。一次 IPNS 查找包括取回公钥本身、搜索具有相应的私钥签名的指针文件(一个包含 IPFS 地址的文件)、辨认最新的指针文件、以及重定向到正确的地址几个步骤。要利用 IPNS,用户首先要创建一个公私钥对,然后将公钥、想分享的文件和带有签名的指针文件上传到 IPFS 上。当需要更新时,用户只需要签署并上传新的指针文件就可以了。

IPFS 的不少方面都可以在过去的项目中看到踪影,例如 BitTorrent(P2P 共享)、Plan 9 下的 FossilVenti(一次写入的数据块和路径重定向)、和 git(哈希树/有向无环图)。但是,IPFS 的杀手级功能在于其与现有架构集成的便捷程度。专用的 HTTP 网关允许从浏览器(而不是 IPFS 客户端)中直接访问 IPFS 或 IPNS 地址,而且 IPFS 还具有与 FUSE(用户空间文件系统)的兼容性,这意味着我们甚至可以将整个 IPFS 挂载为一个只读分区:这一兼容性也让我们能够托管静态网站,但是我必须承认,访问全球(甚至星际)规模的 P2P 共享盘是个明显更酷的用法。

在 IPFS 上架设静态网站

官方指南 已经很好地概述了使用方法。以下是简要概括:

  • 运行 ipfs initipfs daemon 初始化并启动 IPFS 守护进程。
  • 生成网站文件并运行 ipfs add -r <网站文件路径> 将其内容发送到 IPFS。输出的最后几行会有路径根目录的哈希值。
  • 如果要使用 IPNS,请运行 ipfs name publish <网站根目录哈希> 以将 IPNS 链接定向到刚刚上传的文件夹上。IPNS 公钥的哈希值可以通过 ipfs key list -l 获得。
  • 在更新或重建网站文件时重复以上两个步骤。由于 IPFS 寻址过程固有的数据去重功能,该过程的实际开销并不大。对静态站点这一用例来说非常合适:越大的文件(例如照片)更新频率就越低。

完成此操作后,我们就可以从任何专用 HTTP 网关使用 <网关地址>/ipfs/<网站根目录哈希><网关地址>/ipns/<ipns-地址> 来访问刚才上传的网站了:我们可以使用由 IPFS 守护进程启动的本地网关(通常位于 127.0.0.1:8080),也可以使用 公共网关(由于 IPFS 文件取回需要在运行网关的服务器上进行,因此使用公共网关有遭受来自服务器所有者的中间人攻击的额外风险)。如果想要架设多个网站,则可以使用 ipns key gen 来生成更多 IPNS 密钥对,并在执行 ipfs name publish 时通过 --key 选项指定发布地址。

在 IPFS支持 IPNS 密钥的导入/导出 之前(这有助于我们备份密钥并从多台设备发布内容),DNSLink 可用于更方便地访问站点,但代价是需要拥有域名并信任 DNS 服务提供者。要想通过 /ipns/<域名> 从 HTTP 网关访问站点,只需为域名加入以下 TXT 记录:

dnslink=/ipfs/<网站根目录哈希>

dnslink=/ipns/<ipns-地址>

例如本站就可以通过 /ipns/shimmy1996.com(该链接使用 ipfs.io 架设的公共网关)来访问。虽然算不上是一个完全没有缺点的办法,但对我来说这是个合理的妥协。我发现 IPFS 通常比 IPNS 快,所以在 DNSLink 里用 IPFS 地址应该更加合适。为了避免每次手动复制粘贴,我在博客构建脚本中添加了以下内容以自动将网站上传到 IPFS 并更新 DNS 记录(使用 DigitalOcean 的 API):

echo "上传网站至 IPFS..."
hash=$(/usr/bin/ipfs add -Qr "<网站根目录>")

echo "更新 DNSLink 记录..."
token="<digitalocean-api-令牌>"
curl -X PUT \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer $token" \
     -d "{\"data\":\"dnslink=/ipfs/$hash\"}" \
     "https://api.digitalocean.com/v2/domains/<域名>/records/<记录-id>"

DigitalOcean 上 DNS 记录的记录 ID 也可以通过 其 API 取回,不过你可能需要在请求中增加 ?page=2 或更后面的页码才能找到你想要更新的记录。

对了,还需要注意的是,正如同使用任何脱机 HTML 文件时一样,我们需要在生成的网页中使用相对链接。在 Hugo 中,这可以通过在 config.toml 中加入

relativeURLs = true

来实现。

当然,作为一个 P2P 网络,IPFS 无法取回已经不存在于任何节点上的文件。默认情况下,IPFS 客户端会 固定 从本地计算机共享的任何内容:固定内容不会被删除,这确保 IPFS 上至少有一个可用的副本。我们可以取消固定网站的过时版本,或者,如果需要,在多台设备上查找并固定网站地址以防万一。

繁星若尘

回到 IndieWeb 的问题上:越来越黑的域名系统和链接失效使基于 HTTP 的 URI 的稳定性难以保证。但是,如果我们使用 IPFS 或 IPNS 地址作为 URI 呢?简直完美!我们通过由数学而非 FBI 警告所控制的地址获得了(理论上可以永久持续下去的)对静态网页的稳定分布式访问。消除拥有服务器的需要还降低了拥有个人网站的门槛。HTTP 协议已经存在了 29 年,而 IPFS 仅存在了 5 年。我不知道 IPFS 在接下来的 24 年中是否还会继续存在,但是如果是的话,我希望我们会看到一个或许更加混乱,但更加健壮、充满活力、多彩的在线世界。

TIReD:我的评分系统

疫情给了我更多时间来回顾想看的电影、节目和书籍,所以我考虑建立一套自己的评分系统,以简化写(如果有的话)评论的过程。

指导原则

一般的评分标准具有 10 个或更多级别。这个选择范围在我看来太大了,更不用说那些采用百分制的评分系统了。即使是最常见的五颗星系统也会在引入半颗星后变得繁琐。6 分与 7 分或 4.6 分与 5.1 分间究竟有什么区别?较高的精细度在汇总大量评分中可能会有用,但从单个评论者的角度却不是这样。我更喜欢 S1 漫区投票 所采用的方法:让评论者在更少但区别更明显的几个级别中作出选择。

我的身边统计学表明,大多数在线评分都聚集在 70%周围,这是个与 预测任何事物的成功率都为 40% 一样没用的分数。换句话说,大多数评分系统的下半部分都没有得到充分利用:我想不到任何我会给出一星半而非一星评价的情况。此外,我查看评分和评论的目的在于了解高质量的作品,而不是差的那些。一个评分系统仅关注“更好的那一半”就足够了:为什么我在忍受完一个糟糕的节目后,还要给它一个评分?《米其林指南》可没有负一颗星,不是吗?

单纯地用一个分数来概括任何东西的质量都不怎么公平。我想有一个更具表现力的评分系统,以传达我对所喜欢作品不同方面的看法。至少一个恰好对上我的波长的作品应该和一个更具大众吸引力的作品得到不一样的评价。

评分方法

隆重推出 TIReD 评分系统!以下主要以动画/电视节目为例,但这种方法中的许多内容也适用于其他艺术形式。每个作品会在以下项目中进行评分,分数之和构成最终评分:

项目范围
有形(Tangible)0-2
无形(Intangible)0-2
回味(Revisit-ability)0-1
酌情加分(Discretionary)0-1

作品的有形方面包括视觉风格、动画、配乐、CG 质量、特殊效果等等。简单来说,作品的制作是否精良。以 0 分为起点,评分标准为:

  • 1 分:如果作品总体上吸引人,且维持了稳定的高质量、缺点极少(完美)或利用独特的想法、技术产生了非常棒的效果(高妙);
  • 2 分:作品采取的表现手法本身就足以作为观看的理由,即使作品在其他项目中得分全部为 0 分。

作品的无形方面包括故事本身、角色塑造、剧情节奏、文化背景参考等等。这些特质应该一定程度上独立于作品的具体表现介质而存在:我至少可以同样地享受基于其他艺术形式对作品的忠实再现。评分标准与之前类似,不过对于明显遵循原作内容的翻拍或改编作品,且我看过原作时,评分标准会有所调整:评分将以原作在无形方面的得分-1 为起点,视翻拍、改编的质量、难度、效果作出最多 1 分的调整后舍去超出 0-2 分的部分。例如,对+2 故事的平庸重述最多只能授予+1。翻拍和改编的起点往往比原创容易一些,所以我想以“作品本来可以有多好”为基础作出调整,对“如果我看过原作,还应该看吗”这类问题作出回应,并方便挑选出那些“不必看原作”或“已经超越了原作”的作品。

回味,顾名思义,衡量我是否想重温这一作品。这更多地与我自己的口味或怀旧之情相关:这应该是我会在一个无所事事的午后重新观看的作品。较长的作品在这一指标上会处于比较不利的地位,所以我会将特别令人难忘的片段也计算在内。在翻拍和改编的情况下,这一项目的得分大多数时候都应该仅授与我认为最好的版本。

酌情加分不应该轻易使用,且对已经在其他三个项目中获得满分的作品无效,这使得最高总得分为 5 分而不是 6 分。设置这一项目的主要目的是对于我认为作品优点没能很好地被现有评分标准体现出来时作出调整。适用的常见情况包括但不限于:

  • 类型天花板:同类最佳;
  • 作品的有形和无形方面有着紧密的联系,缺一不可;
  • 超越客观条件限制的质量,尤其是对于年代久远或预算紧张的作品。

记录格式

TIReD 评分记录的格式为 X=T/I/Re[+D]。例如:

  • 一个有形得分为 1 分、无形得分为 2 分、回味得分为 0 分、酌情加分为 0 分的作品会被记录为 3=1/2/0
  • 一个有形得分为 1 分、无形得分为 0 分、回味得分为 0 分、酌情加分为 1 分的作品会被记录为 2=1/0/0+1

对于我半途放弃看下去的作品(意味着我无法给出评分),会被标记为 DNF(did not finish)。

自我问答

我在制定 TIReD 时的一些想法碎片。

问:应该评定书籍的有形得分?

答:我觉得应该就是看行文本身的质量,例如其能否称为“文学作品”。虽然我对自己鉴定优秀作品的能力并不那么有信心,但是至少获得 2 分的作品应当比《哈利波特》要好。

问:在其他相关作品中建立的世界设定如何影响评分?

答:世界设定会影响回味得分(系统或世界是否有趣、让我想进一步了解)和无形得分(人物背景是否合乎其行为)。

问:酌情加分的规则是如何确定的?

答:不论分数范围多大,最好的作品始终会获得满分,所以给它们再加分没有什么意义。另一方面,有一些看似不起眼的作品却充满了制作团队、作者的热爱和诚意,还有一些作品存在本身就足以称为爱好者的福音。我想在保证较为客观地评判作品的有形和无形方面得分的前提下表达自己的欣赏,而酌情加分提供了一个途径。

问:在看原作前后,改编或翻拍作品的评分会如何变化?

答:在看过原作后,我将调整改编或翻拍作品的分数。

问:翻译常常会漏掉一些细节,如何处理翻译作品?

答:处理方式与翻拍相同,在看过原作后评分会被调整。

问:“TIReD”(以及分项得分名称)是怎么确定的?

答:第一个有具体名称的项目是回味(revisit-ability),后面的大部分时间都花在玩单词排列和缩写上。由于 Urban Dictionary,我差点将这套评分标准命名为“TIRD”。不过,至少不是所有的作品都是*。😜

Get GOing

我今年 完成Advent of Code!除了问题比去年(对我来说)变得简单了之外,我换用 Go 完成了今年的挑战:我觉得 Go 特别适合这类任务。

今年的谜题主要涉及字符串解析以及寻找最高效的数据结构。大部分解题流程的逻辑都比较简单,几乎不需要任何复杂的算法。

对于字符串解析,正则表达式(Go 自带支持)是最佳途径。今年为数不少的字符串解析问题意味着想只用基本的字符串操作解答会十分痛苦。我已经看够了用查找、剪切、提取子串等操作拼砌起来的怪物代码。

绝大部分时候,切片(slice)和集合(map)足够满足我的要求。Go 支持多返回值,却不支持元组(tuple);不过,我发现序列(array)和结构体(struct)基本取代了元组的功能。这些数据结构由于 Go 鼓励使用常量而非枚举类型(enum)而变得更加多功能:将所有信息储存为整形(int)使得一些捷径成为可能,同时也省去了类型转换的麻烦。和更让人安心的支持类型检查的枚举类型不同,(滥用)这些选择让用 Go 写短程序有着和行走在刀刃上(或者在 Zoom 通话时不穿裤子)一样的莫名快感。

Go 简单明了的控制流和缺少多范式支持的特点让指令式程序编写起来非常容易。不必担心是否应该使用 STL 算法或者串联迭代器方法:写个循环就好了。合理的对象可变机制也有帮助:不论是边遍历边修改集合元素,还是将带有切片的结构体传给函数,我发现我可以很快地让 Go 做我所想的事情,而不用反复翻阅语言规范。

这让我想到了 ZOI 这一经验法则:只有零、一、无穷多是合理的个数。不少我所熟悉的编程语言,例如 Python、C++、Rust,都为了追求一致性落在这一光谱的两极:一切都有着相同的规则,用户就和语言本身一样有着决定语法含义的能力。Go 有着更多的异常之处(尽管 Go 并没有异常支持)和只有“一”个的例外:内置容器神奇地有泛型支持、它们方法的返回值数量可变、除它们之外的容器都没有获得迭代支持的资格。

这只是一个不涉及 Go 其他特性(例如界面(interface)或协程(goroutine),不过这些对解决 Advent of Code 并不是必须的)的简单比较。我觉得 Go 的选择独特且有趣:一切都,嗯,不大一样

回顾 2020

今早,窗外的屋顶上都是白色一片。那些广告牌在阴沉的天空下失去了平时的光辉。就连橙色的路灯也没法让一辆车都没有的道路显得温暖。不过,来自少数建筑物窗户的光点却比平时更加耀眼。

真是不寻常的一年。时空密度比平常高出不少——能将阳光削弱成象牙白的微弱光晕的程度——看看过去这多事的三百多天。

我其实挺高兴看到 2021 年的第一天感觉就和 2020 年中的任何一天一样。给这么一个随意选定的数字+1 不应该对现实产生任何实际变化。不过也许正是因为缺少变化,我们才需要时不时地看到一些新的、能让人眼前一亮的东西,不论多么微不足道。

话说回来,偶尔享受下这种廉价的心理学把戏大概也不会有什么坏处。

新年快乐,我们终于等到了。

2020: 天启

这次我可不会在进度上再打马虎眼了。

  • 跑 550 英里。 跑 205 英里并骑车 865 英里(2.5 倍)。[205/205][872/865]
  • ☑ 写 14 篇日志。[16/14]
  • ☑ 不吃甜面包圈。
  • ☐ 了解 Go 和 C++20。[1/2]
  • ☐ 建立正式的数据备份流程。
  • ☐ 阅读非技术类书籍。

由于 COVID-19,我从 3 月初开始就停止了在户外跑步。在偷懒了几个月后,我在 6 月份买了一台自行车和训练器,改为在室内骑行。2.5 倍的换算比例是基于我骑车和跑步的速度差异而定的。在一个更可控的环境里锻炼非常让人享受。除了能方便地补充能量和不受天气影响外,能够在骑行的同时看动画/听声优广播真是太赞了。果然科技是第一生产力!

写关于博客本身的博文仍然占据了我的日志中相当大的一部分(这真是种令人沮丧的自欺欺人的行为),不过至少我积累了相当数量的鸮文:这些转瞬即逝的想法流对于日志来说太过松散,但仍然有趣到我想把它们记录下来。我同时也用鸮文来存放我对其他博客的回复。略显繁琐的回复流程让我意识到,大部分时候我似乎并没有什么真正想说的内容。别误会,这并不意味着这种麻烦的半手动回复系统有多么优越,但我觉得能够提高所写内容的信噪比是有实在的好处的,不论对我还是对其他人来说。

啊,甜甜圈,这刷满蜜糖的罪恶之枷锁,这油炸的放纵之镣铐。虽然我很想把成功抵御诱惑归功于我的钢铁意志,但 COVID-19 才是根本原因。我的懒惰和对隔离生活的兴奋劲消除了任何深夜造访 Dunkin'的机会。大概是时候把挑战升级了。

Go 写起来相当无脑而有趣。找到一个有效的掌握 C++20 特性的方法则要难得多。<format> 是新特性中最直截了当的一个,基本用法、功能和你能想象出来的基本一致(还没有编译器支持新标准的版本,尝鲜的话可以用 原版)。<ranges> 类似于 Rust 的迭代器方法,而且允许串联。也许是时候更新那篇 用 C++ 来 enumerate() 的日志 了。<concepts> 应该是 SFINAE 所试图解决问题的真正答案,但我还没有一个好的实际运用环境来测试它的威力。顺便一提,Zig 用编译时间函数来实现泛型的方法也很让我感兴趣。

3 份副本,有了。2 种不同的储存介质,有了。1 个非本地备份,还没有。这还是已经算上 Syncthing 副本(这能不能当作一份完整的备份还有待商酌)的进度,看来我离完成正式的备份流程还是有不少距离。

严格地说,我确实 阅读 了非技术类的书籍;只不过我没有 读完 任何一本(不算漫画的话)。事实上,除了那些我纯粹为了娱乐而读的,我并没有什么想读的非技术类的书。大多数非虚构类的书看起来像是被阿谀奉承和幸存者偏见腌制过的成功者故事。而我又不怎么提得起兴致阅读小说:和获得一个能够复述给他人听的故事相比,我更愿意了解一种新的算法。啧,这听起来真刻薄。难道我觉得我的日志能赢过所有的小说?总之,在认输之前,今年我会给出更加认真的一次尝试。

2021: 未来昔日

疫情引发了前所未有的怀旧情绪。人们表现出来的对“正常日子”的眷恋,却让我莫名地反感。并不是说我对这种异样的气氛完全免疫,只不过它对我的效果似乎正好相反:我发现自己变得比以前更加坚持己见了。说到底,人们不都暗自认为自己的水平在平均之上、能够作出更加合理的判断吗(尤其是在看完新闻之后)?同时,我的理性则告诉我要在这种冲动变成傲慢,或更糟糕的无知,之前将其抑制住。也许我应该学会把这些想法以日志的形式释放出来,比如写成非技术版本的 EWD

换个积极一些的话题吧,我向朝 5 晚 10 生活习惯的过渡非常成功。封城居家办公对这一过渡有着很大帮助:我能够更加从容地调整睡眠时间了。现在每天早上我都有充足的时间用于锻炼,甚至还可以选择睡上两个小时(三个小时也不是不可以!)的回笼觉。考虑我在年末假期的短短几天里就完成了最后 100 英里的骑行,今年我会把目标里程数提高一些。

生活习惯的改变也让我意识到我睡前的几个小时大多在碌碌无为中度过:在一天的工作和急需的晚餐后,我不大有动力进行锻炼或长时间集中注意力于任何事情。同时,受到用 beanancount 记账的影响,我有了将类似的方法应用于时间管理的想法。我正在在测试用 Toggl Track 记录我是如何度过一天中的大块时间的,以及中间有多少分钟随着我在大脑空白状态下刷 YouTube 而溜走。对了,有这么一个可以勉强当作读书版 Strava 的系统应该能让我的阅读目标更容易实现。至于要读哪些书,我觉得经典小说是个不错的开始。

继甜甜圈之后,我今年的挑战是戒掉曲奇饼干,我工作场所的午餐时常提供它们。直接吃曲奇饼干的原料(例如成条的黄油和大堆的砂糖)只是想想都觉得恶心,但烤成饼干后吸引力却能指数性增长,真是奇怪。

我怀疑这个现象到了一定年龄才会出现:人类成长到一定程度时,听觉会和电吉他的声音一拍即合,使其变得无法抗拒。我想多花一些的时间来学这一乐器、在 2021 年底时能弹好一两首歌。

Z 之后的世代居然叫 Alpha,真是完全不讲道理。吔屎啦,这毫无逻辑的命名方式。吔屎啦,COVID-19(当然是因为命名方式以外的理由)。

Un de ces matins disparaissent
Le soleil brillera toujours.

个人介绍与多尺度写作与可扩展人格档案

换句话说,这是为什么我没有在站点上设置“关于”页面。

个人介绍

我一直觉得个人介绍很难写。

我不怎么待见这样的个人介绍:

史科特・危险・索罗,MIB,是 WHSA 认证的西格玛级虫洞冲浪专业人士。他敢于开第一枪,会毫不犹豫地交叉粒子流,善于进行第四维度的思考。

这读起来就像嚼他人自我风味的泡泡糖一样让我感到恶心。我总忍不住把这些听起来冠冕堂皇实则空虚异常的表述当作是试图给在线内容增加可信度的绝望尝试。

大多数时候,我选择不在网上写个人介绍。我的旧 WordPress 博客上的关于页面是少数例外之一:

EE 狗;技术渣,WP 新手;ACG 相关;喜欢硬件但是没有小钱钱;足迹可能遍布各大社交网站,通常名字为 shimmy1996;求友链 XDD。

即使是这种简单的介绍,对我来说也有种过于露骨的感觉。在其他情况下,我会使用随口编出的科幻风无稽之谈,例如:

川陀大学地外生命饲养与烹饪技术系

编造这些空想职业其实非常有趣,我几乎可以整天沉迷其中而不感到厌倦。这只是我库存中的一小部分:

  • 超级坏蛋技工(从事他们的修理和维护工作,而不是帮他们统治世界);
  • 土星民俗学和恶魔学爱好者;
  • 鱼语(亚特兰蒂斯语的一种方言,为北太平洋的甲壳类和海洋哺乳动物所使用;我知道,这名字非常容易让人混淆)母语使用者;
  • 根沸能板(时伏电池模组,你可以理解为一个反向通量电容器)工程师;
  • 超声音乐(不,这不包括蛇爵士乐,因为它们远比不上鲸布鲁斯或者蝙蝠摇滚)收藏家;
  • 星等调节专员;
  • 梦境摄影与作梦专家。

如果不是因为全光谱摄影真实存在,这个列表还会再长一些。

啊,不难看到我很容易就会被这有趣的活动分心。让我们回到如何在这个有着鸟类(或者说是生物燃料侦查用无人机)却没有树章鱼的地球上写个人介绍的话题上吧。

为何我在读个人介绍时总下意识地觉得它们是以树立权威或者“建立个人品牌”为目的而写的呢?这不意味着对别人的资历表现出敌意和轻视的我才是表现出近似优势情结现象的一方吗?还是说从小听到大的“谦虚是最好的美德”终于开始产生反效果了?如果个人介绍的目的是便于他人将我的个性轻易地、削足适履一般塞进寥寥数个标签定义的边框里的话,那我宁可不提供这一可能会从网站内容分散注意力的目标。话又说回来,如果我经由站点所展现出来的个性能够被区区个人介绍页所扭曲,那也许站点内容也不具有多少代表性。

多尺度写作

我目前将站点上的内容大致分为三类:

  • 日志:任何带有发布时间和标题的内容;
  • 鸮文:任何具有发布时间但没有标题的内容;
  • 固定:任何没有发布时间的内容。

目前为止,我一直将个人简介页放在“固定”类别下。 但是,我开始逐渐意识到显示发布时间与否有着更微妙的含义。

最早让我意识到这一点的是一次经由 RSS 阅读器点进一篇没有标明发布时间的日志的经历。由于我对日志标题有点印象,我本能地开始在寻找任何类型的时间戳。一番侦查工作后,我在 HTML 源码里找到了发布日期的蛛丝马迹。在意识到这一页面早已发布、只不过是因为网站源的格式更新才在 RSS 阅读器中重新出现后,我很快关闭了那一标签页。和上一次读到时相比,这篇日志会不会有些地方措辞发生了变化?有这个可能,但我的记性没有好到能察觉这些的程度。有没有可能这篇日志其实经过了大幅修改?的确也不能排除这种情况,不过要是页面上没有会让人因为担心错过而焦虑异常、大红色字体的“更新于 XXXX-XX-XX”,我大概还是不会看下去的。顺便一提,我造访的另外一些博客除了标注发表日期之外,还会放上一条非常显眼的横幅来警告读者页面内容可能已经过时、作者的观点也可能已经改变。这显而易见的常识居然需要免责条款一样的声明让我觉得有点滑稽,不过这倒是很好地引出了我的观察:我在读到没有发布时间的页面时会将其视为不需改动的成品、已完成的杰作、(作者眼中)宇宙的真理。

我想要通过个人介绍来表达的内容不兼容一般的固定页面格式。那有什么其他的选择呢?我并不想要一个 E/N 站点,因为我觉得整理思想碎片这一过程的价值至少等同于、甚至超过收集这些碎片本身。我有考虑过设立 个人维基,但我想让页面的每个“主要版本”分别存在,而不是把所有改动不论大小全部扫进编辑历史里。虽然对于技术性内容而言,包含了所有勘误的最新修订版自然是最佳选择,但我并不认为过去自己的想法全是过时或错误的,可我也不喜欢将过去和现在混在同一“长内容”页面上。

我想让个人介绍成为脱去水分后文字版的自我,而这是一个固定页面只能永远追赶而不可到达的、不断随着时间的推移而变化的移动目标。在固定页面和日志之间,有个空缺的时间尺度:我需要一种能够比固定页面更快展现变化、但又比注明发布时间的日志更加持久的格式。

可扩展人格档案(XPA,eXtensible Personality Archive)

不觉得这名字超赞的吗?XPA 还恰好是 负责修复 DNA 损伤 的一种蛋白质及其对应基因的名字。

好啦好啦,在把这一切贬低为不必要的折腾之前,给我个解释的机会。比起一个固定的个人介绍页,我觉得最合适的替代品是一系列逐渐被更新的记录,像一本书的不同章节一样。有些书籍,例如漫画或连载小说,通常是马尔可夫过程般一章接着一章地不停发布的;我设想的则是一种修订与更新更频繁发生的非线性增长。

我访问的部分博客有着与“日志”独立开的、目的类似的“文章”或“观点”分区。比起这些,我所想的格式更接近 RFCPEP 这类文件。XPA 会被编号,而每个 XPA 的内容会是我对某个主题相关的当前一切想法,并可以被新的包含类似内容的 XPA 所取代。同时,日志则保留给我做过或经历的具体事情。换句话说,XPA 包含我字面意义上的思想状态,日志和鸮文则用来记录这些状态之间的一些增量变化。

严格按照定义,XPA 实际上是一种比我最初所想要灵活得多的格式:对影视作品的评论也可以归入它的范围。想想那无数的可能性!现在我只要把剩下这点微小的工作做完就可以开始了:确定怎么在站点上显示 XPA,是否从 0 开始计算编号,想好应该使用那种进制,决定编号的具体格式……

啧,命名真不是件容易的事。