善意提醒

如果您打开本站很慢,布局排版混乱,并且看不到图片,那么可能是因为您还没有掌握用科学的方法上网的本领。

2025-12-24

订阅了Google AI Pro

看过一些朋友的推荐,也跟 Google Gemini 一番探讨之后,今天终于下决心订阅了 Google AI Pro。

可以有更多的 Google Gemini 配额了,包括「思考」和「Pro」,后者貌似就最近两天才加上的。以及,更多的 Nano Banana / Nano Banana Pro 图片配额。还可以用 Veo3.1 做视频。免费版的 Deep Research 配额我曾经用满过,所以还真是有必要成为付费用户。

Google 全家桶里面也可以用 Gemini 了。我记得有印象在 Gmail 里面看到过 Gemini 的图标,但今天去找的确找不到了。莫非是当时 Google 放的鱼饵?

另外,对我而言还有一个挺有吸引力的福利:2TB 存储空间。太太的 Google Photos 空间早就满过了,删了一些视频才降下来。我自己也不敢拍太多照片和视频,就怕哪天空间满了出事情。这问题甚至影响到了我的某些旅游的体验,现在不成问题了。

详细介绍见这里,不过我不知道算不算是最新的:https://support.google.com/gemini/answer/16275805

我是选的「包年」方式,因为感觉一旦用上了应该就「回不去了」。
首年 $100,之后每年 $200。包月正常价是 $20,现在也有试用优惠。不知道是不是年底或圣诞节特别搞的活动。反正都要买,不想等几天错过了,就下单了。
我个人是不太在意这些小恩小惠的,何况已经很划算了。

说起来,Google AI Pro 应该是普通中国人最容易「够到」的顶级 AI 品牌的付费服务了。ChatGPT Plus 之前对中国用户想尽办法封锁,还砍单封号来着。直到现在也没见得有多方便,甚至连「安全」都不一定算得上。我曾经形容为「被中美混合双打」,为了用个靠谱的AI也真是难为了。

图片由 Google Gemini 3 Pro + Nano Banana Pro 生成

当然,对于普通人,我一律是劝他们尽量多用 AI,哪怕是国产 AI。
有在用总比没有在用要强。面对熊,你只需要比同伴跑得快就行。

AI 问:那如果是面对狼群呢?

我说:你差不多得了。 

2025-12-22

丢失的 Blogger 铅笔小图标

图片由 Google Gemini 阅读本文后生成,真是厉害

之前在自己折腾 Blogger,大概就是 2023 年或 2024 年把  Blogger 重新翻出来写的时候,一不小心,把每篇 Blog 下面的「铅笔」小图标给整没了。

这个小图标是管理员才能看到的。直接一点就可以进到编辑界面。对于我这种时常在回顾自己文章时发现错别字,需要马上去修改的人而言,真的是很方便。把它弄丢了以后,我每次就得根据文章的标题或标签再去 Blogger 后台找到那篇文章。有时候某些想法只是一瞬间的事情,过了就没了,对于我而言,更可怕的是「过了就忘了」,这也太可怕了!

我一开始还以为是自己之前在编辑主题的时候不小心把它给误删了。但今天想起这事,下决心解决,去看代码的时候,才发现好像不是这么一回事。代码都在里面,但就是不起作用了。

这是原来的代码:

<b:includable id="postQuickEdit" var="post">
  <b:if cond="data:post.editUrl">
    <span expr:class=""item-control " + data:post.adminClass">
      <a expr:href="data:post.editUrl" expr:title="data:top.editPostMsg">
        <img alt="" class="icon-action" height="18" src="https://resources.blogblog.com/img/icon18_edit_allbkg.gif" width="18" />
      </a>
    </span>
  </b:if>
</b:includable>

看到这里我就有点犯嘀咕。cond 明显是条件,该不会是 post.editUrl 没东西吧?
我把 cond 改成一个必定成立的条件,放到页面上一试,还真是。图标出来了,点击没用处,没能跳到编辑页面。问 Google Gemini,它说新一些的主题里面这个图标的确已经被隐藏了。看来 Google 是铁了心要把这个功能干掉了。

我想自己整,但发现真正的编辑页面的 URL 好像有两个 ID 我不知道哪里能拿到。Google Gemini 给出的修改方法语焉不详,而且看起来也没有说到点子上。算了还是求助于传统的 Google 吧。

搜到的第一个贴子是 Google 自己的页面,Blogger 的 Support 论坛:
https://support.google.com/blogger/thread/242102130/editurl-the-url-of-the-edit-form-for-this-article-deleted

里面有提到这位大神,是一个法语的 Blog:
https://bloggercode.orbiona.com/2021/10/faq.html

后面有个英语 Blog 也提到上面那篇:
https://too-clever-by-half.blogspot.com/2022/08/the-case-of-missing-pencil.html

法语对我而言有不少困难,还好有 Google Translate。
我翻到解决方案一节就知道了:看起来那个法语大神给出的就是我想要的东西。
简单地说,把原来的那段代码替换为:

<b:includable id='postQuickEdit' var='post'>
  <!-- /2021/10/faq.html -->
  <b:with value='data:view.isPage ? "blog/page/edit/" : "blog/post/edit/"' var='path'>
    <span expr:class='"item-control " + data:post.adminClass'>
      <a expr:href='data:blog.bloggerUrl path (data:path + data:blog.blogId + "/" + data:post.id)' expr:title='data:top.editPostMsg'>
        <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/>
      </a>
    </span>
  </b:with>
</b:includable>

就可以搞定了。

原因据说是 Google 慑于第三方 Cookies 的限制,没法让前台(blogspot.com)和后台(blogger.com)在域名不相同的情况下还能把管理员的登录会话串起来,索性就把整个功能废掉了。

解决方案的原理也很简单:你不让我跳编辑页面,我就自己组 URL。知道 BlogID,也知道 PostID,还有什么做不到的呢?

当然,这里头还有一些诸如「管理员权限的判断」等小东西。按照「八二原则」,真正花时间的往往是在这些事情上。掌握了核心技术,路只走了 20% 而已。这位法语大神甚至已经把「页面」和「博文」的差别也搞定了。我就不折腾了,直接用她的吧。

照例吐槽一下:搜索结果中,简体中文的页面依然是一无所获,繁体中文有两篇讲到了这个事情,其中一篇涉及到了核心问题,不过最完整的解决方案还是法文以及英文的页面。简体中文在世界文化交流领域里面就是一个小角落,不管卖出了多少玩具电动车,都改变不了这个事实。不要再夜郎自大了。

2025-12-16

如果你还认为自己是普通人

我不认为自己是什么「普通人」。就算我哪怕曾经有过这样的想法,但不久前以及现在也不再这样认为了。

如果你还自认为是个「普通人」,那么,最好赶紧跟下面这种人区分清楚。

你可以说「这个人根本不是什么普通人」,也可以声明自己「并不是普通人」。如果你已经了解此事,但仍然还是默不作声,那么这份恶,你就也有一份。

祝你去世

没有人是「普通人」。你是独一无二的,你就是你。

2025-12-04

这是一个所有人都在推卸责任的时代

某家银行下辖的期货公司发来公文,说我们的软件存在着「DLL 劫持」漏洞,限期修正,催得很急。

说起来跟《鬼子来了》一样,翻译官最该枪毙。DLL 是什么东西,老爷可能不懂,但是一听到「劫持」二字就坐不住了。劫持?打劫?谁打劫?匪徒?要劫谁?黄四郎的觉都要睡不着了。

是不是漏洞,技术上说,当然可以算是。该不该改?可以改,可以不改。对方拿了个自己生成的 TextShaping.dll 往我们软件的安装目录下一放,Calc.exe 被调起来了,就说有问题。然后我拿去往 Steam 的安装目录下一放,也有问题。人家 9700 万月活,四千多万的并发在线人数,似乎并不担心。

Foxmail 也一样有问题。而且 Foxmail 比 Steam 还大条,它默认推荐的安装目录可不是什么 %ProgramFiles% 之类,说起来问题更严重。但是它们都没改,或者说,没被要求改。为什么?因为没有「主」。都是用户自己下载,自己安装,自我的决定。出了问题,没有人寻死觅活找别人担责。

其实通达信也一样,别看它貌似防了一手,但它仍然可以被 DLL 劫持。关系到同行,我就不展开细讲了。Resource DLL 各位自行了解一下。

最鸡贼的是招行的网银。以前我就吐槽过它,貌似为了「安全」而无所不用其极。这次我又发现它的一个做法:为了防止 DLL 劫持,它索性把自己放到 Windows 的系统目录里面去了。

可以可以,相当可以

这样当然可以防止 DLL「劫持」,因为它直接把自己和操作系统的安全性绑一块儿了。相当于搬到元首家里去住下了,要死一起死。

解决方案不是完全没有,但本文本质上是一篇吐槽文,不是技术类文章,因此也不展开细讲。

说到底,这些所有的事情,都是为了推卸责任。期货公司真的是为了客户的「安全」着想吗?让这种软件能在客户那已经千疮百孔的机器上「带毒运行」,真的好吗?还真以为自己是常山赵子龙啊?能在恶意环境中杀个七进七出,片叶不沾身?

它们其实只是为了在客户真出事找它们寻死觅活威胁要跳楼的时候,可以拿出一些文件来,对着来「监察」的「钦差」们说上一句「你看我该想的办法都想了,剩下的就不是我的问题了。」

然而问题解决了吗?解决个锤子!


今天又收到一篇公文,是要向我们「确认」软件是否有采集客户的 MAC 地址并上报。

听上去是个人信息收集的问题,不过在这个行业中,有强制要求必须要这样做的,所以这个行为是合法合规的。要确认的,是我们不能「漏报」。

然而,这个「确认」其实是在耍滑头。自己不想去通过测试来确认,恐怕也无力去确认,于是发文件让供应商签字画押。本质仍然是找人担责。

我本来写了一大段,后来又默默地删掉了。对老爷能说些什么呢?

我觉得「MAC 地址能自己动手改」这应该是一个老爷可能不知道的常识。老爷本就应该是不具备什么常识的,所以我就不去败兴了。我能告诉他什么是拨号上网吗?他去一搜,到处都是 PPPoE,回过头来跟你说 Modem 也有连接的网卡。他晓得个锤子,他连 Modem 为什么叫「猫」都不晓得。

他要押,你就画给他,画个小乌龟,带尾巴。


太太这些天,在办交强险退保的事情,办得劳神劳力,最后我让她算了,就当给保险公司的老爷老娘们拿去买伟哥了。

说起来是很有理有据的事情。没起保的交强险可以退,相关的说法网上一搜一大把,都是支持的。AI 分析也没有任何问题,我甚至让 Google Gemini 和 ChatGPT 都分别做了 Deep Research,法律证据也都很充分。甚至太平洋保险自己都有 案例解读,监管层 2023 年也有相关的 Q&A。然而就是办不下来,四处碰壁。

投诉到太平洋客服没什么用,开口就是公司规定。去银监会投诉,只是把事情给你转回去。其实又是踢皮球到太平洋保险,说法还是同一套,总之就是不给退。

在网上刷到一位有 相同经历 的程序员。看来保险行业内部,特别是客服岗位,恐怕应该是学习过这种案例了。如果松了口承认了相关法规,就得受罚,而且公司层面说是「补偿」而不是正常的办理流程,也就是「口子不能开」,开了就是客服个人的责任。

监管层说是可以退,然后又让个人去跟保险公司「协商」。这情景活脱脱就像我当年去电脑城找 12315 投诉商家欺骗消费者,然后老爷过来指导销售「你快点跟消费者解释你们都有些什么额外的成本」。我在猜,大概体系内部其实是不允许退的,对外说可以退,对内严惩相关人员。医保不也一样?


其实吧,我就把话说重一点,也说得大一点。从三年疫情就可以看出来,共产党和中国政府其实根本不是在管理,他们也没那个能力。他们就是「责任驱动」,你也可以说他们是被「压力驱动」的。他们所做的一切,都是为了「卸责」,逃避危险。所有事情的动机,都可以用「给自己少些麻烦」来理解。

尽管有的时候,他们貌似反而制造了更多的麻烦,但你如果试图站在他们的立场去想想,就会发现,那是因为他们觉得如果不这样做,就会有「存亡危机」。「人无远虑,必有近忧」,话是没错,然而鼠目毕竟只有寸光,一切终归是偷来的。

看穿了这一层,很多事情,你就可以理解了。虽然逃避责任最好的办法是不担责,不在其位,自然就没责任了。但是有一个词叫做「秋后算账」,他们是最怕的。当年他们这样干过,所以自己最清楚。后面上台的人也不想为现在的烂摊子买单,那么必然有人要担责。猜猜会是谁呢?因此,为了不被秋后算账,现在必须抓牢权力,而且永远也不能松手。非不愿也,实不能也。

上行,所以下效。何况人性本来就是趋利避害的。现在没有利可以趋了,那害总是要避一避的。故而,造就了这么一个所有人都在推卸责任的时代。

即使在公司里,也能嗅到这种氛围。上了点年纪的同事,「混」得最好的,就是那种浑身是刺,搞得别人不想理他的人。其他人也在眼馋他的「清闲无事」,纷纷向他学习。做事情都是趋于保守,少做少错,不做不错。长此以往,一个民营企业,会有什么下场?我不知道,但连老板想的都是「先把这几年熬过去」,以及「找死不如等死」。

如果参透了这些,或许能在眼下处世更加自如一些。我虽然已经看破,但无意为伍。且也先「保守」一下,把自己的心田防守扎实一些吧。


洋洋洒洒写了这么多,其实一句话「社会逐渐趋于保守」就可以概括。这应该也是大家都基本能认同的事情。只不过,最近遇到的想吐槽的事情,一下来了好几件,还是想拿出来说一说,所以絮絮叨叨写了这么多。

以及,有些话,如鲠在喉,不吐不快。真的说出来了,心里竟然舒服了一些,可见还是有毒。

2025-11-13

读得太少,写得太多

图片由Google Gemini生成

这两天在反思,觉得自己最近光是在写,阅读不多,进货少出货多,因此写得也有点没感觉。

自己的写作水平,大概也就这样,应该提升不了多少啦。不过或许多读点东西还是会有一些用。挺怀念年轻的时候,读过的东西,马上就会反映在接下来的写作风格的变化里面。虽说是「没有形成自己的风格」的表现,但也说明「可塑性强」,一切都还没有定型。现在到了 人生下半场,没什么指望了。

而且,我现在只是看「故事」居多。只挑自己爱看的,看得舒服的。例如推理小说、科幻小说,或者别的什么小说。正经的学术性书籍、严肃文学,下场可以参考那本在我书架上放了十多年还没翻过的《国富论》。

何况,即使是山冈庄八的《织田信长》,我也前不久才开始看。买的时候应该跟《国富论》是差不多的年代。摸着已经发霉的书脊,复杂的感情油然而生。也不是懊悔,毕竟也还来得及看完。更多的可能是恐惧吧,如果已经开始插管,不知道还能有多少时间留给我。

时间太少,要做的事情太多。或许这才是我昨晚那回想不起来的噩梦的真实内容?

那就把时间拿去做点真正重要的事情吧。因此,接下来我的输出频率可能会下降一些。反正我也不是一个当作家的料。有句鸡汤文,大意是「造物主给了人两个耳朵一个嘴巴,就是叫人多听少说」。细想有点扯,但是多沉淀一下也不错。

2025-11-11

你可能从未注意过的MFC陷阱:模态对话框禁用机制的局限性

在最近的一个软件开发案例中,遇到了不容易处理的情况。

在我们的软件中,有那种一直浮在界面上的非模态对话框,例如那种浮动的工具面板。但是,这种窗口,貌似不会在主窗口弹出模态对话框的时候被 Disable。如果模态对话框是在这个非模态对话框中弹出的,那没有问题。

用 VS2013 和升级到最新的 VS2022 各写了一个测试程序,发现这就是 MFC 的默认逻辑。
在主窗口上放了两个点击后各自会弹出非模态对话框和模态对话框的按钮。先弹出非模态对话框,然后再去弹出模态对话框。此时主窗口被 Disable,无法响应鼠标、键盘消息。但非模态对话框不受影响。

本想靠调整产品设计「容忍」过去。但问题在于,如果在保持模态对话框弹出的情况下,去把非模态对话框先关闭了,那主窗口会被 Enable。此时它跟模态对话框之间都能响应鼠标、键盘消息,效果就好像之前弹出的模态对话框变成了非模态对话框一样。这个时候就会有「后果」了,产品设计再怎么调整,也没法让软件在这种乱了套的情况下还能工作正常。


在网上 Google 了半天,不要说解决方案,连问题都没人提到。讲解模态 / 非模态对话框的文章有一些,但都是很入门的介绍。只是从「使用者」的角度去讲用法谈区别,并没有涉及我遇到的问题。很少从原理角度进行说明,更没有去分析源代码。大概 MFC 现在用的人真的不多了吧?

图片由 Google Gemini 生成

还是得自己动手,在 DoModal() 处下了一个断点,单步跟踪进到 MFC 的代码里面看了一下,就明白了。以下代码来自 VS2013,VS2022 我貌似没有安装 MFC 源代码,但从表现上看二者在这个逻辑上应该相差无几。我们一起来看看 CDialog::DoModal() 到底干了些什么事情吧:

INT_PTR CDialog::DoModal()
{
	// can be constructed with a resource template or InitModalIndirect
	ASSERT(m_lpszTemplateName != NULL || m_hDialogTemplate != NULL ||
		m_lpDialogTemplate != NULL);

	// load resource as necessary
	LPCDLGTEMPLATE lpDialogTemplate = m_lpDialogTemplate;
	HGLOBAL hDialogTemplate = m_hDialogTemplate;
	HINSTANCE hInst = AfxGetResourceHandle();
	if (m_lpszTemplateName != NULL)
	{
		hInst = AfxFindResourceHandle(m_lpszTemplateName, RT_DIALOG);
		HRSRC hResource = ::FindResource(hInst, m_lpszTemplateName, RT_DIALOG);
		hDialogTemplate = LoadResource(hInst, hResource);
	}
	if (hDialogTemplate != NULL)
		lpDialogTemplate = (LPCDLGTEMPLATE)LockResource(hDialogTemplate);

	// return -1 in case of failure to load the dialog template resource
	if (lpDialogTemplate == NULL)
		return -1;

	// disable parent (before creating dialog)
	HWND hWndParent = PreModal();
	AfxUnhookWindowCreate();
	BOOL bEnableParent = FALSE;
	CWnd* pMainWnd = NULL;
	BOOL bEnableMainWnd = FALSE;
	if (hWndParent && hWndParent != ::GetDesktopWindow() && ::IsWindowEnabled(hWndParent))
	{
		::EnableWindow(hWndParent, FALSE);
		bEnableParent = TRUE;
		pMainWnd = AfxGetMainWnd();
		if (pMainWnd && pMainWnd->IsFrameWnd() && pMainWnd->IsWindowEnabled())
		{
			//
			// We are hosted by non-MFC container
			// 
			pMainWnd->EnableWindow(FALSE);
			bEnableMainWnd = TRUE;
		}
	}

	TRY
	{
		// create modeless dialog
		AfxHookWindowCreate(this);
		if (!CreateRunDlgIndirect(lpDialogTemplate, CWnd::FromHandle(hWndParent), hInst) && !m_bClosedByEndDialog)
		{
			// If the resource handle is a resource-only DLL, the dialog may fail to launch. Use the
			// module instance handle as the fallback dialog creator instance handle if necessary.
			CreateRunDlgIndirect(lpDialogTemplate, CWnd::FromHandle(hWndParent), AfxGetInstanceHandle());
		}

		m_bClosedByEndDialog = FALSE;
	}
	CATCH_ALL(e)
	{
		TRACE(traceAppMsg, 0, "Warning: dialog creation failed.\n");
		DELETE_EXCEPTION(e);
		m_nModalResult = -1;
	}
	END_CATCH_ALL

	if (bEnableMainWnd)
		pMainWnd->EnableWindow(TRUE);
	if (bEnableParent)
		::EnableWindow(hWndParent, TRUE);
	if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)
		::SetActiveWindow(hWndParent);

	// destroy modal window
	DestroyWindow();
	PostModal();

	// unlock/free resources as necessary
	if (m_lpszTemplateName != NULL || m_hDialogTemplate != NULL)
		UnlockResource(hDialogTemplate);
	if (m_lpszTemplateName != NULL)
		FreeResource(hDialogTemplate);

	return m_nModalResult;
}

看到高亮的代码应该就能明白了。MFC 在弹出模态对话框的时候,只是把 hWndParent 给 Disable 了。然后如果发现主窗口还没被 Disable,再补上一刀。后面这个逻辑应该就是为了应对在非模态对话框中弹出模态对话框的情况。

看到了这些逻辑,就可以明白本文最开始讲到的情况是情理之中的。模态对话框只管住了大 BOSS 和父亲,对于兄弟和叔伯之类,都没有去管。如果情况复杂一点,例如非模态对话框中又弹了第二层的对话框,那么不管这个对话框是模态还是非模态,接下来都有机会整出点问题。


知道了问题的原因,接下来就要寻找靠谱的解决方案了。肯定有人解决过这类问题,因为有些软件没有这种问题。但不知道是因为觉得问题太简单了不值得说,还是想藏着掖着?

希望是前者。因为真正的解决方案确实也很简单。

之前有同事尝试解决这个问题,办法是让模态对话框去通知所有的非模态对话框(或者说需要被 Disable 的窗口)自行 Disable,用了我们软件内部与 Windows 消息相互独立的另外一套通讯机制。

但这个解决方案有一些问题:模态对话框除了自己开发的那些,还有系统提供的 MessageBox、文件打开对话框等,另外还包括第三方库中的那些,都是我们无力触达的。所以虽然它花了很多力气让对话框们去多重继承一个基类,但还是没法彻底解决这类问题。

回头想想,主窗口不是总是会被 Disable 的么?那么监听主窗口的 WM_ENABLE 消息,在事件处理函数中把那些需要额外 Disable 掉的窗口集中处理掉,不是就可以了?

实际做起来也很简单,基本上就是在主窗口的 OnEnable() 中用 EnableWindow(bEnable) 把状态传递过去。唯一需要动点脑筋的,就是让那些需要额外 Disable 掉的窗口把自己的 HWND 注册到一个主窗口拿得到的地方,也就是说待处理的窗口列表需要管理起来。

具体的实现代码我就不贴了。重要的是解决问题的思路,具体如何实现,可以有很多种办法,选择适合自己的哪一种就好。相信读到这里的,都是合格的 Win32 / MFC 程序员。

2025-11-07

小目标

去年,儿子上了初中,虽然是「预备班」,即传统说法中的「六年级」,但还是换了个学校,换了同学,也换了班主任老师。总之,一切都是全新的了。

跟小学那个有点坏的数学班主任不同,初中的班主任是教体育的。女老师,精瘦,据说以前是踢足球的,不知道是不是哪个体校退下来的。倒是应该比较受学生的欢迎,特别是男生。

班主任的有些做派,我并不认同。当然我也知道现在基层教育的种种难处,巨大的机构裹挟之下难有个人发挥的空间,所以也不想去苛责这些年轻人。不过她有个事情我倒是蛮想点赞的:她让这些学生每天订一个「小目标」,去完成它,并且在家校本上记录下来。

儿子同学的小目标,来自「钉钉」家校群

预备班很勉强地坚持了一个半学期,这事在儿子身上目前大致算是撂下了。如果我不坚持催促,他是不会去订这个「小目标」的。即使在我的要求之下勉强去做了,也只是把自己偶然做过的一些事情给揉碎了写上一些。这基本上就是在「应付」了,肯定不是老师的本意,也不是我的。要我老实说的话,这种事情在这个年龄段的小男孩身上,的确还是有些勉强。

老师其实还订了一些别的「规矩」,比如按学号轮流在「钉钉」群里发家校本的内容。本意是借机督促每个学生都认真抄写每天的作业要求,然后也给那些偶尔忘抄或忘带的小可怜一个「补救」的机会。然而群里最后一次的发送记录是 10 月 15 日,接下来不知道是谁没发,再后面「链条」就断了。

出现这种情况,我也完全能理解。去问儿子什么时候该他发,他也不知道,只是记得他前一个同学是谁。他就只盯着那个同学,人家不发,他也就不把这件事放在心上。玩 STL 的都知道 forward_list 断了是啥下场。这规矩订得还是有一些脆弱,应该改成 vector 或 map。


我读初三的时候,语文老师也订了一个规矩,让我们每天回去记录一条新闻。规定了字数,大约两百字左右,不算多,但也显然不是你去把标题一抄就能合规的程度。规矩一出,班上同学一片哀嚎。作文也就六七百字,这相当于一周固定增加了两篇作文的作业量了。

我其实也很头疼。在那之前,我写个作文也是写几句话就开始数字数,尽量加写长点的定语来凑篇幅。如果去记录新闻的每一句话,却又来不及。我看过一点《大卫·科波菲尔》,知道速记学起来没那么容易。当时又没有手机可以摄下来录下来(话说我还真动过用录音机的心思),因此刚开始的一段时间,我也是跟其它同学一样,到了晚上就开始发愁。直到有一天……

那天我记得很清楚。我边吃晚饭边在看新闻联播,进入到最后十分钟的「他国都很乱」环节,播报了一条新闻,是讲联合国核查小组在伊拉克检查大规模杀伤性武器的事情。因为是我相对感兴趣的话题,所以虽然正在吃饭没去记录,但整件事情至少听完以后还能向家人完整复述出来。等我吃完饭准备写作业的时候,才发现只要用自己的话把听到的内容再描述一遍,这个作业是如此的简单。

不需要速记,不需要录音机,不需要每句话每个字都一样,只需要一个大概。我很轻易地就写了六七排,肯定超过两百字了。这个时候我才发现,原来两百字不是太多,而是不够。我很讶异:我都初三了,为什么以前都没学会这么简单的事情?以及,为什么班上其他人也做不到?

后来我在想,或许这就是所谓的「开窍」。事情发展到了一定的时候,窗户纸捅破了,突然一下就明白了。

老师第二天就把我写的东西当着全班的面念了一遍,然后传给班里每个人看。现在想来,当时她心里肯定有一种「我终于等到了」的感觉。那一刻,肯定很有成就感,多巴胺超级加倍。

班上同学们也很快就明白了,毕竟是重点中学,大家也都不是傻子,只是差那一下的棒喝。当天就有明白过来了的人开始模仿,接下来甚至有的家伙开始编「新闻」。当年那种奇奇怪怪的「社会新闻」有很多,不过我们听完之后还是纷纷议论「太离谱了」「肯定是编的」。但是老师也未置可否。回头看看,编的故事显然是更不错的果实,只要编得足够好。

151 岁,谁说是高科技来着?

当年我的老师是不是算是给我们设立了一个小目标,我不是很清楚。但是显然,目标不可能一天达到,但是也不能放弃,继续做下去,可能就有收获。指不定是在哪一天,但是放弃了,这事就真的没戏了。

就像丽春院的小姐姐说的:「叫,不一定有客。不叫,就一定没有客。」


儿子经常陷入「小目标写个啥」的忧思。我看到真是又好气来又好笑。要是让我每天只立一个小目标,我自然会嫌少:探索并关注 1 - 2 个有意思的 Substack 频道;写一篇 Blog;整理相册;去 Steam 上淘一个好游戏……简直不胜枚举,数不胜数。不过,儿子看来还缺些时候。我到初三才稍微开了一下窍,不能拔儿子的苗。

何况,儿子也有儿子的烦恼。我看了他最近的英语题目,包括数学试卷。有不少题都是那种「你猜猜我要考你什么」的题目。比如一句英语空两个位置让你填,目的其实是想让你填这个学期刚学过的某个词组。中国考生说不定真能答对,换个英语母语者来答,肯定不知道出题人脑子进过什么 shit。

百发百中

这种「先射一箭再画靶子」的事情,从我还是学生起,直到现在,一直就没变过。所以能教出什么来,考试分数高的都是些什么人,可想而知。当公务员肯定是好材料,可惜我个性不适合。

前天儿子一张数学试卷 58 分,我跟他一道题一道题地看错在哪里。昨天他 76 分,我跟他说你如果认真答题不粗心,大概也就是这个分数,七十多,运气好能上八十。如果哪天你开始得 100 了,那我就要担心你的脑壳是不是开始方了。

不多不多,买不了熊猫

算了,咱家都是普通人,还是先从定一个能达到的小目标开始吧,比方说先挣它一个亿……

2025-11-05

日渐老去

如果人生是一场足球赛,我已经进入下半场了。

图片由 Google Gemini 生成,非本人

周末跟太太回了一趟盐城,去了乡下的老家。太太张罗了一桌饭菜,宴请附近的亲戚和邻居。我则被苏北老男人们拖着喝酒,53 度的白酒,可能喝了得有二两半。

喝完酒,老男人们开始抽烟聊天,而我则躲进了房间玩《太阁立志传 5》。老游戏,里面的时间是一天一天地过。我的记忆是连续的,然而太太说我喝断片了。

次日她跟我说了我当时的一个细节,我对其发生前后的事件都有印象,而且印象并不模糊,唯独对这件事情一点印象都没有。按太太的说法,这件事我的参与度非常的高,不应该没有印象。如果不是太太在诓我,那就是我真的失忆了。

部分地,失忆了。


我的酒量,意外地还不算坏。

按照岳父的说法,我的极限应该在半斤白酒左右。当然,跟酒的度数,以及当时的身体状态也有关系。十五年前我去三亚出差,被迫一口气干了三杯白酒,每杯都有至少二两。后来也还有喝,然而最终也只是半夜爬起来吐掉了而已,并没有失忆。甲方也说,没想到你还挺能喝。

当然,我后来难受了一整天,大概是伤到了胃。但现在,显然是不可能这样喝酒了。

唉,酒有什么好喝的?但为什么我偏偏就躲不掉?


早上起床,上完厕所回来,闻到卧室一股味儿。

开门开窗通风,味道很快就散了。但是这味道勾起了我的一些不太愉快的回忆。

二十年前,我在父母房间,闻到的就是这样的味道。他们房间通风不是太好,也不太爱开窗通风,所以味道没那么容易散掉。于是后来我就避免长时间呆在他们房间。

我知道,那其实就是「老人味」。现在,我也有了。

是的,我也已经是老人了。


有一次,跟儿子在小区南门,看到 LED 屏幕上写着「45 岁以上的老人……」。回来跟太太说,她还不相信,还好有儿子作证。

这件事情非常打击我。因为我自认为还是个年轻人。

遇到老男人,我第一反应还是「爷爷」或「叔叔」,结果人家年龄可能比我还小。走路还是总想蹦蹦跳跳,遇到奇怪或者有意思的东西就想弄个明白。虽然我和太太都认为老歌更好听,但新歌我也并不排斥。年轻人知道的梗,流行的用语,我也几乎都知道。

对于新出现的事物,我积极拥抱,非常有热情,也不故步自封,觉得自己熟悉的那一套才是最好的。我也是一个还不错的聆听者,从来不像老登那样去驳斥年轻人的言论,更不会去指导别人的生活。而且只要有道理,别人还挺容易说服我的,几乎可以称为「从善如流」了。相比之下,有的同事可能年纪比我还小,但无论说话做事,还是面孔身材,都像个老头。

我看起来也的确显年轻,以至于时常被错认为是太太的儿子。商店的营业员,来装修的水电工,甚至太太闺蜜的父亲,都曾经搞错过。貌似我现在看上去跟实际年龄可能有接近20岁的差距了?

唯一能够出卖我的,只有脸上的皱纹:抬头纹、鱼尾纹、法令纹……。我不想去学普特勒做拉皮或打肉毒素,而且最好也不要去想这类事情:太太虽然会拿我那些「糗事」调侃,但我知道她已经有压力了。

然而,看起来老不老,是一回事。但身体是实实在在已经老了。


初次认识到这件事,是两年前一次去崇明玩的时候。

崇明还是比较适合养老的,生活节奏并不快。离上海不远,现在又快有地铁了。我们去泡了两天酒店,在东平森林公园逛了一圈,最后临走时,在一个街边小公园又晒了一会儿冬日难得的太阳。

小公园其实也不算很小。里面有一些健身器材,有单杠也有双杠。引体向上,我是 2021 年就知道自己已经拉不上去了。23 的 BMI 虽然不算有问题,但也不低。因此我就按照儿时的记忆,双手一撑,上了双杠。

本来想的是来一招前滚翻。高中的时候学过,也考过,当时可以轻松完成,要点其实就是肩部要顶住,双臂打开不能收,收就掉下去了。心里想着技术要领,没想到刚一上杠,分腿一坐,大腿内侧拉伤了,赶紧下来。

这伤我后来养了起码一个星期。就是这件事情,让我知道自己已经不是从前那个自己了。虽然这事主要应该怪我没热身,但下课、放学去玩的时候,谁 TM 热身啊?


其实身体更早就开始告警了。37 岁的时候,我尚且能靠节食把体重很快地降下来。过了 40 岁之后再来,但体重怎么也不掉了。吃的还是一样的东西,干的还是相同的活儿,可能还更忙了。只能解释为代谢变了。

身体的零件,也逐渐出了状况。最早也是最明显的是眼睛。虽然医生解释为基因问题,但触发条件还得是年龄。人一老了,就跟车子年限长了一样,各种零部件就开始出状况。一会儿天窗漏水,一会儿烧机油。不知道能用到几时。

这次是脑子,我就很害怕。外婆曾经最害怕阿兹海默,我也一直很担心这种事情。因此从 2021 年末开始,我每天记日记。坚持到现在有四年了,后悔没有早点开始做这件事情。

尽管记的都是流水账,但对我而言是很重要的事情。回头看的时候,发现不少事情已经不记得了。有一些是细节已经模糊,有一些甚至整件事都没印象。回想起以前外婆一遍一遍地反复刷琼瑶的电视剧,这种性质的「失忆」,我能接受,但也很可悲。如果我没有拿文字记录下来,那这些日子就算是白活了?


我记日记,还有一个目的,就是用来证明我目前的记忆不是被「植入」的。

可能觉得我在说科幻小说的事情。但现在科幻小说里面的事情,不是天天都在上演么?先不说那些反乌托邦小说,就单说 AI。谁要是小时候得知有个 AI 能陪你聊天,还知道全人类的知识,那还不得把它一直玩到坏掉?然而现在的人用它来搞色情图片换脸,所以说人类真的没救。

不知道自己接下来工作要干到几时,以及能干到几时。尽管我前面自诩「年轻」,但也知道自己并不真的「年轻」了。不管我自认为多少岁,老板和保险公司都是看在眼里,明白在心里的。驾驭 AI 而不是被 AI 取代,五年内我还有一点信心,五年之后我就有点没底,十年之后更是比较悲观。那个时候我也还没法「退休」,所幸房贷应该已经还完了。

回想起父母当年自己开修理铺修车的经历。一开始也是意气风发,说是下岗也好,下海也好,总之心里不虚。两口子南下去深圳打工,学习技术,回来后自己开店。在 90 年代其实混得不错,但进入 200X 年代就有点力不从心。多年积攒的经验,慢慢开始派不上用场。眼见车内电器的集成度越来越高,最后一切都被封在一块芯片里面,靠另一块芯片来诊断。战场慢慢撤退至出租车,靠着这些老爷车勉强维持生意,最后也是五十多岁就彻底歇业了。

我觉得自己应该没有办法干到真正退休。按共产党的说法,我要 63 岁才能退休。到时候退休金应该早就破产了。不管我现在缴了多高,有没有得拿都是一个大问号。不过我有一个 65 岁前到期的定期寿险,自杀也可以领,有 300 万之多。虽然不知道 300 万到时候值多少钱,但是按照现在的通胀率,应该还是不错。所以……

所以现在这些年干点啥?多看点儿书吧。既然我拿这个当人生目标,而且也有明确的 Deadline 的话,那就应该及早开始了。

2025-11-03

原地复活

玩 IT 的朋友都知道,「自主维修」曾经有三大法宝:拍一下,重启试试,重装系统。

随着集成化程度越来越高,「拍一下」已经不好使了。重装系统一般是菜鸟才会使的招数——你当初怎么弄坏的,重来一次还是会弄坏。重启大法嘛,倒是一直还好使,特别是 Windows 这种东西。Linux 用不太上,但是即使是 iOS 偶尔也还是会需要。

我的 iPhone SE2,今年上半年就已经屏幕不行了(参见《我的手机史(十三)——iPhone SE2》)。我仍然中意有 Touch ID 的手机,然而国行已经买不到 SE3 了,因此不得已去买了一部美版 SE3,把它换了下来。SE2 从此退居二线,却也一直没真正退休。

美版 SE3 也有它的问题。说是无锁,但实际上有 MDM 锁,我算是被坑到了,拿到手一迁移就撞上了。当然因为价格低,也并没有被真正坑到,还借此搞到了一个靠谱的开锁工具。但不能迁移,也就意味着我的「传家宝」Surge 2 没法继续用了,因为原作者已经把它下架了。我若不想投入,就只能在 SE3 上用着免费的 Potatso,时不时就断一下,苦不堪言。

所以我这半年还把 SE2 留着,总觉得 SE3 只是过渡一下的角色,想着接下来买部行货 iPhone 的时候,还是从 SE2 迁移过去。我这两台手机上的 App 几乎一致。除了少数垃圾国产 App,不允许多账号登录,例如支付宝和钉钉,没有办法只能先注销登录,其它 App 我都是两边一起用。数据也靠 iCloud 尽量同步。可以这样说:如果有必要,我只要把 Sim 卡换过来,很快就能转移回 SE2 上继续使用。

其实这样做也有一个副作用,就是我时不时会拿错手机,以及平时裤兜的负重变双倍。不过上个星期,我的这份「坚持」,终于有了回报。2025 年 10 月 26 日,刚好是 SE2 过完五岁生日的 10 天之后,它的屏幕问题,突然自己就好了。

本来已经没抱什么希望了。一直想着去把屏幕换掉,顺便也换个电池。但又怕维修的时候非要我还原系统,所以一直没去搞。就这样拖着,结果 26 日洗澡的时候,我突然发现全键盘的时候 p 键可以按到了。

图片由 Google Gemini 生成

我直到现在也不知道到底是怎么回事。是中校同志搞的鬼吗?是气温原因?或者是因为我当时把它带进了浴室里面用?到现在一个星期了,它仍然是好的,并不是回光返照。所以我又把 Sim 卡换了回来,主力手机回到 SE2 上,SE3 就先跟它交换身份。

不知道这台 SE2 还能撑多久。电池的确不太行了,峰值电量只有 76% 了,需要我多加注意,但跟半年前比也没什么变化。话说近年推出的新款 iPhone 的电池貌似的确要好很多,或许是硬件上的改进,但我疑心是新版 iOS 的功劳。我 SE3 用了半年,峰值电量还是 100%。本以为是障眼法,但太太 21 年买的 iPhone 12 Pro Max 到现在四年半了,也还有 86%。所以 Apple 可能真的是想了点什么办法,只可惜我的 SE2 没早点用上这黑科技。

这件事给我的一个「启迪」就是:不少看上去已经可以「盖棺定论」了的事情,可能还有转圜的余地。所以,各位也请不要灰心,继续坚持,说不定再坚持一下可能就好了。

2025-10-29

连滚带爬

2025 年 10 月 28 日晚,摄于下班路上

我最接近「连滚带爬」的时候,是一次从上海去北京出差。

低估了高峰期上海地铁 10 号线的装载能力,也低估了从地上跑到地下换乘所需的时间,更是大大地低估了上海虹桥高铁站的宏大规模。
我以为地铁到站还剩十五分钟,应该来得及。接着我就开始连滚带爬了。

长长的扶梯啊,仿佛没有尽头。背着个大包的我,怀揣脂肪肝,此时已经上气接不了下气。自动扶梯的台阶偏偏又特别高,可我的大腿已经几乎抬不起来了。
愧对家乡父老!比起郑智化来,我是真的靠手脚并用爬上去的。滚是没有真的「滚」,我可不想真的糗「死」了。

还好公司提前给我拿到了票。当年持纸质票更容易「通关」。我见过有人拿着身份证去,被人赶去取票,最后没赶上火车。
当然,那不是在上海,上海还是要好些,毕竟是后来靠「封城」真的「清零」过的中国「天花板」城市。


我最早见到郑智化的样子,是在香港的「卫视中文台」。
那个时候,我大概跟我儿子现在差不多年纪。内地电视台,那个时候就已经江河日下了。后来湖南卫视勉强算「中兴」,但我早已不再看。

开眼看世界,随即惊讶于「人家」的广告居然如此「有意思」,以及节目播出是如此准时。从来不延误,偶尔提前几秒无事可做,宁可播一个时钟的画面,也不再多插一个广告。
相比之下,内地电视台的广告多得让人想骂娘,还没意思。本地的录像台倒是更守时一些。

除了卫视中文台的主台,还有音乐台,时不时播点 MTV。有一次甚至还播了张学友 92 年演唱会,分了上下半场,我用 VHS 完整录了下来。还记得从《花花公子》开始的关之琳的伴舞。下半场上来第一首歌就是《夕阳醉了》,萨克斯的音色也把我吹得如痴如醉。这次 60+ 演唱会,很可惜没法有昔日的任何感觉,遗憾。

郑智化的歌,当时正当红的是《星星点灯》。《水手》是上一波,MTV偶尔也有播出。另外让我印象深刻的,就是《麻花辫子》。

其实《星星点灯》和《水手》的路数很相似,用现在的话来说,Vector 离得比较近。我还记得在《重庆晚报》上看到过一小块「豆腐干」,评论说《星星点灯》缺乏创意,不过是《水手》的翻版,郑智化江郎才尽云云。看到这些文字的时候,我还没有概念,后来真的听了这两首歌,倒也时常把旋律搞混。

《重庆晚报》上的音乐评论,也有挺不靠谱的。我曾经看到过另一块「豆腐干」,抨击《心雨》的「资产阶级爱情观」,说明天就要「成为别人的新娘」,今天还要「最后一次想你」,简直是伤风败俗。那个时候我还只是小学生,看了也只能暗暗记在心里,不足为外人道。

在《星星点灯》和《水手》里面,郑智化的「残疾人」感觉还不明显。不过《麻花辫子》里面就比较明显,拄着拐杖。我跟着哼了几句,结果被外婆向父母打小报告,说我有「早恋」的苗头。可班上也没有麻花辫的女同学啊?

其实中国大陆也有一个还算出名的残疾人歌手,还上过春晚。1987 年春晚,不是现在网上搜到的那个 87 年生的小伙子。郑智化是腿不好使,他是腿没了。这次若是换成是他,工作人员可能会「轻松」一点吧,各种意义上。

当然,在网络酸民眼里,这些都不是事。重要的是中国南波万,以及必须赢两次。


这次十一回了一趟重庆。跟父亲吃了两次饭。
他总是劝我,去试试看办一张「残疾证」。这次又被我拒绝了。

他可能觉得,自己靠着残疾人身份,得了不少好处。坐公交车自不必说,穷游「大好河山」也省了不少门票钱。
另外一个理由就是,我姑父靠着股骨头坏死的残疾证明,提前了几年退休了。

我让他省省吧,还提前退休呢。太太的闺蜜得了癌症都没法提前退休。今时不同往日了,我甚至都没指望过自己还能拿到养老保险。
但是冲他吼了半天,嗓子都哑了,他反正也听不见,自顾自地说自己的。

算了,反正火锅店里面也吵得很。外面跳广场舞也吵。吵死拉倒。

2025-10-24

程序员节,闻逆流有感

「惊闻」《四中全会决定大幅提高科技自立》,感觉到大概率又要搞一波运动了。

学大寨?放卫星?大炼钢铁?超英赶美?
不知道又有多少人借此机会大发「国难财」,不知道有多少从我这里上缴的税费溜进了这些投机者的口袋。

作为深受「信创」其害的 IT 从业人员,退休之心不由得更加迫切了。躲进小屋成一统,管它冬夏与春秋。反正种子我已经播下去了。

若要问我有什么想说的:如果《中科院反右中消失的一页——寻找青年物理研究者刘治平》这种事情不能得到真正的解决,包括那虽然幼稚可笑但起码是个态度的「平反」,以及彻底的清算和至少两代人以上的反思,那么所谓「科技自立」,只不过是镜中花、水中月,南柯一梦耳。

以及,以上只是必要条件,而非充分条件。听说现在义务教育不教「逻辑」,有不明白的请自行弯腰摸石头。

图片来自《中国数字时代》,阿平漫画


加油 2025

图片由 ChatGPT 生成,[惊喜]它能正确生成含中文的图片了

根据 Blogger 的统计,2008 年,我写了 59 篇Blog。
今年我已经写了 52 篇了,加上这篇,是 53 篇。

该用什么词汇来形容呢?中兴之年?垂死病中惊坐起?啊呸!

去年重新开始在 Blogger 上写 Blog 之后,写了 31 篇,我已经很惊奇了。已经算是 2008 年以来的新高。今年再加把油,努把力,或许可以超过 2008 年的数目。

神马?2007 年有 110 篇?那个时候真的是话痨,现在不敢想了。2006 年的部分,还在整理中,数目并未确定,不知道是会更多还是更少。

这篇 Blog,本来应该等年底总结的时候,再来说这些话。不过我也想给自己打个气。2025 年还剩下至少两个月,7 篇 Blog,只要我不要太懒,也不要遇到什么事情,应该能够做得到。

把话先摆在这里,也算是一个鞭策,回头再来打自己的脸的时候,就会更疼一些。

以上。

2025-10-23

开设 Substack

图片来自网络

在 Medium 上也有写东西,有一些也发在了 Blogger 上。除了简 / 繁体,与 Blogger 这里最主要的区别,就是多一份《上海日记》。

一度觉得 Medium 上的书写感觉很不错,简单、纯粹。因此尽管它对中文内容诸多「打压」,我还是一直坚持。我并不介意推广的事情,反正我又不打算靠这个赚钱。

直到 Medium 开始把邮件推送从提供正文全部内容,改为只给出前半截,然后引流到 Web 站点去。那个「Continue reading」,搞得我火大。

我知道 Medium 不是 Substack,商业模式不一样。如果大家都在 Mail 里面去阅读,没人访问 WebSite,那它就没钱赚了?不清楚。Medium 的商业模式一直改来改去,我也看不明白。
但起码它现在想的是要把人拉回去,于是把内容藏起来不让邮件订阅者看。这与我想让别人「通过邮件看全文」的需求,是背道而驰的。

于是,我在 Substack 上开了 Publication。

Substack 给我的书写感觉也挺不错的,起码我写个日记希望有的那些功能它都具备。而且中文作者在上面好像要稍微更活跃一些,推介算法也更友好,至少我还能在 Home 上发现一些活人。

新的 Publication 并无意推广,随缘吧。毕竟名人有云:「知道得少一点,可以活得久一点」。
话说,其实我写本文,也只是想吐槽了一下 Medium 而已。

2025-10-22

亲历 AWS 网络大故障

周一下午,我刚完成从 Medium 搬运到 Substack 的第一篇文章,正要去看效果,就发现 Substack 的网页时常报错,很难打开了。

一开始还只是某些访问有问题,多刷几次能出来。后来就渐渐地总是刷不出来了。正在疑惑是怎么回事,转去看 Medium,发现 Medium 也开始不稳定起来了。报错代码是 504,Cloudflare 报的。

本以为是 GFW 的原因,但报错代码是 50X,有时是 503。这是后端服务器有问题的错误代码,看起来跟 GFW 没关系。而且 504 是Gateway Timeout,GFW 显然不可能干扰 Cloudflare 的回源。我开始认识到这次可能是有什么 Internet 基础设施故障了。不知道这两家原本是竞争对手的公司,基础设施怎么会搞到一块儿去的?比较大概率是 AWS,因为 Google 的服务很稳定,微软也没出问题。

我用 Google 搜了一下,貌似还没什么新闻。Reddit 上有少量用户在各自的专区反映 Substack 和 Medium 出了问题,从印度和葡萄牙的访问都有问题,美国本土倒是好像没人说。我登录了 Reddit 账号,也上去写了两句,接着等消息。

图片来自网络

没过多久,BBC 有动静了,报道说 AWS 出了事故。据说是美东一区的 DynamoDB 访问出现报错和延误。我自己其实也从 AWS 的 Status 页面上刷到了这条消息。我意识到自己可能正在经历一次全球性的 IT 基础设施故障。有 Reddit 用户说 Trello 和 Hulu 也在波及范围,我上 Trello 看了一眼,好像还没事。

再后来没多久,Reddit 上也有人在贴这个新闻。从 BBC 的报道来看,影响面挺大的,一些网游和银行都受到了波及。英国那边有点气噗噗,觉得凭什么美国佬儿的故障要影响到我们 Great Britain。最后的阶段,连 Reddit 也开始访问不稳定了。

可气的是,自始至终,无论是 Substack 还是 Medium,他们自己的 Status 页面上一直都是 OK 的。这样的页面看来只是一个摆设。

不过恢复也挺快,AWS 更新了 Status 说已经定位到了原因之后,不到半小时,访问就纷纷恢复了。下班前我试了一下 Substack 和 Medium,二者的服务都已经正常了。

2025-10-17

Chrome 与黑魔法师

我曾经在 Chrome 的 123 版本上停留了很长一段时间。

为什么坚持用 Chrome 的老版本?
因为如果升级到 >=124 的版本,我用的 Shadowsocks 就会出问题。时不时就卡住一两分钟。完整关掉 Chrome 重新打开,可以立即恢复,所以并不是被封锁了。但遇到的频率很高,总不能一直这样关掉整个 Chrome,所以我就不去升级了。

不去升级,Google 会自己给我升。有一次我一个疏忽,儿子不知道干了什么事情,就把版本升到了 137。我一边回退版本,一边研究如何禁止 Chrome 自动升级,后来在这方面也算是小有心得。

前不久,我发现这次是必须升级了。因为如果不升级,Google 就不让我用 Gemini 了。网页上元素出来不全。查了一下,应该是因为 123 版本的 Chrome 不支持 ch-ua-form-factors。这事让我焦虑了好一段日子,最终还是下决心动手了。
回想起我的 iPhone,当初「被迫」升级到 iOS 16,也是因为如果不升级就不让我用 ChatGPT。AI 真的是人类「进步」的第一大推动力。


我也曾经在 Shadowsocks-libev 3.3.5上停留了很长一段时间,比 Chrome 123 还久。

可不是因为怀旧。尽管我的确一直秉承着「东西还能用就不要去动」的理念,但作为一个从事软件开发的技术人员,跟大势如此脱节并不是什么好事情。我也心知肚明,因此 gfwreport 我都有认真看。现在技术路线是五花八门,乱花渐欲迷人眼,但食死徒对 TLS 盯得很紧,QUIC 也是风口浪尖。我这抱残守缺的做法,倒也能偏安一隅。

这次铁了心要搞个清楚,到底是 Chrome 124 的 X25519Kyber768 搞出了问题,还是伏地魔又玩出了什么鬼花样?

留意到一个现象:用新版的 Chrome 访问 HTTPS 站点,10 秒之后就会准时有 Replay Attack 报到。换成 123 版本就没有问题。还没搞明白 Replay Attack 与我遇到的现象具体有什么因果关系,但二者有关联是肯定的。

或许 X25519Kyber768 导致 TCP 流出现了特别的头部特征?我记得 Chrome 124 刚上线的时候还闹出风波,就是 Client Hello 导致了问题。从我并没被封看来,对方也拿不准,起码没有得出任何结果。但或许跟 AEAD 的抗重放机制一相互作用,就出了问题?个人能力不足,难以最终搞清楚,我不打算继续研究了。


这次还是用「土办法」去解决了。没去换技术路线,只是想办法把流量特征藏了起来。可能也是个小众的做法,但在第五、六集这种困难时期,隐身衣可是好东西。

图片由 Google Gemini 生成

解决方法就不在这里细说了。法师的名字要是被对手知道了,那还得了!

2025-09-29

大锅慢炖

图片来自网络,与本文无关

太太所在的幼儿园食堂,最近天天被人检查。之前以为几天就能完事,但现在说是要「天天」来,不胜其扰。

来检查的,是「市场监督」的人。据说只要是由绿捷供餐的学校,就会有人来查。上海这样的学校恐怕很多。我也不知道他们是什么来头,总之学校的保健老师天天陪着检查,尽查些「不能用钢丝球」之类的事情。好不好吃?抱歉,学校给的要求就是「烧熟,能吃,没毒,营养够」,「好吃」并不在其中。

味精不能用,盐也严控数量,好吃才有鬼了。不过好吃的不健康,健康的不好吃,这话大家也应该听过,所以不应该有抱怨。幼儿园的小朋友们,味觉还没怎么开过光,就这样也挺好。不然像我儿子现在这样觉得学校的午餐「狗都不吃」,全家和罗森的饭团以及我的钱包就都要遭殃了。

当然,那是从前的事情了。现在幼儿园也有「陪餐」制度了。家长可以申请,目前是一周一次,有名额限制,吃的东西跟小孩一样,所以保健老师现在也要犯愁了。校长要求做到「色香味俱全」,开菜单的人最头疼。我只是跟太太强调说不要去买颜料。

听太太说,隔壁的小学和中学,不光是食物由绿捷供应,食堂的人也是绿捷的人,等于是整个「吃」的部分被承包了。预制菜送进去,连分盘的都是绿捷员工,学校完全不沾手。据太太回忆,之前有过几次,觉得食材不新鲜,向上头反映,过了一会儿会有隔壁小学的人送菜过来 ,敢情都是同一个公司的。

听说现在这些中小学校长们还得去安抚食堂的员工,告诉他们绿捷公司现在还没真出事,要安心干活,人心不要散……

附本期推荐菜品:医生在抱怨拉肚子

2025-09-26

最近比较忙

图片来自网络

最近真的比较忙,以至于自己私下里要记的日记,已经堆了快两个星期了。按理说 Blog 更是顾不过来,不过中途有个绿捷的事情,刚好有点新鲜货,先写了一篇,因此还算是没沉默多久。

说起绿捷的事情,也顺便说一下。太太所在的幼儿园食堂,最近有「上面」的人来检查。据说要查三天,只要是有绿捷供货的学校食堂,就会来查。看来绿捷这次有点「脱不了爪爪」了。

不过我也跟太太说,能在上海封城的时候给居民送菜的保供公司,上头也肯定有人。后台是一定有的,只是不知道硬不「硬肘」。也许就是少林寺大和尚那种后台也说不定?总之再等等看吧。反正儿子这个星期我都是从全家和罗森给他供应的午餐了。

上上周是公司旅游,去了嵊泗,三天两晚,一整个周末加周五半天都用掉了。晚上回到上海,天都已经黑了。近来的日记「债务」,就是从那个时候开始拖欠下来的。

另外,上个周末去看了张学友的演唱会。这个周末又只休息一天。这些「债务」,我只怕是一时半会儿还甩不掉。

唯一没有耽搁的事情是读书。山冈庄八的《织田信长》,可能还是在「大众书局」买的,那估计有十五年以上了。从来没读过,顶部已经有点霉斑了。最近翻出来跟猫一起吃,上半册已经快看完了。写得很不错,是优秀的小说家,读起来很容易上手。将来也应该会推荐给太太和儿子,只是不知道他们会不会去看。

拜 KOEI 所赐,我已经自认为是普通人里面对日本战国时代的历史了解颇多的类型了,然而还是有不少的事情是之前不了解或者没怎么在意过的,果然是活到老学到老。也因此,把《太阁立志传 5》重新捡起来,中午抽一点时间在玩。于是,写日记的时间就更紧张了。

DX 版还没舍得花钱去买。之前买了 JA3,以及《死亡空间》,也都还完全没有时间去玩。前天晚上抽了半小时,把《绯闻女孩》全六季的字幕给做进 MKV 里面了,做到手快抽筋,还真是个力气活儿。

韩剧也补了不少。但时间和空间都开始捉襟见肘起来。刚发现硬盘又涨价了,我之前 1699 买的西部数据 16TB 氦气 CMR 盘,现在要 2899,离翻倍已经不远。先用家里剩的那堆 1TB 拆机盘顶顶吧。时间、空间和 Money 我都缺啊,肿么办?

2025-09-18

也说说绿捷的事情

图片来自网络

并不是「棒打落水狗」,也不是「墙倒众人推」,这墙一时半会儿估计还倒不了。

但是我太太是在公立幼儿园里面食堂里干活的,给这家幼儿园送菜的也是「绿捷」,晚上跟我抱怨也不是一天两天了。再加上我儿子在学校吃的也是「绿捷」提供的 A / B 餐。这样的话,我这个家属应该还是有一点儿发言权的。

儿子目前上初中,遇到的情况跟网上流传的 其它情况 基本一致,也就没什么好多说的。
他从去年上了预备班(六年级)之后,就说午餐「难吃得一 B」,然后不怎么吃饭了。下午肚子饿的问题,靠我头天从全家或者罗森买的饭团解决,回家以后再上演《饿狼传说》。

太太所在的幼儿园,蔬菜配送一直是「绿捷」。水果、饼干、奶粉,包括饺子皮和馄饨皮,则是一家私人公司配送。从去年开始,水果这些也由「绿捷」提供了,现在只有饼干和奶粉是那家私人公司在送。
据说上海大部分学校都统一由「绿捷」提供 A / B 餐,一碗水属于是端平了。幼儿园还能拿食材自己烧菜吃,已经算是很给「未来的花朵」面子了。

太太对于这个「绿捷」,那是相当的有意见。

首先,送来的菜,肉眼可见的品质就差。菜里面烂叶子很多,不新鲜。荤菜是另外一位同事负责处理,她不是特别清楚,但估计也好不到哪里去。据说肉类也不新鲜,反正她午饭里面荤菜是不吃的。
而且,态度还很差。菜有问题,向上面反映。「绿捷」那边说它们的菜没有问题,第二天还是一样的差。

水果也是不新鲜。比如葡萄,有许多都是软掉烂掉的。按照太太的说法,比那家私人公司差得不是一星半点。
说点真话,爱国人士 B 小将们不要不爱听。那家私人企业,送来的水果不仅品质好,出了问题也是第一时间赶紧处理,态度非常好,绝不怠慢。要是真有质量问题,往往还赔过来很多好东西。

价钱贵不贵我不知道,都是「招的标」,不是 卖路由器 的,我就不清楚了。但据太太说,「绿捷」的东西价钱比私人公司还要贵。同样的东西,私人企业卖 15,它要 20。
我跟太太说,人家是要真正靠这个营生赚钱谋生的,不像有的公司靠的是亲戚,黑心钱怎么都有得赚。

对了,其实圈子里面都在传说「绿捷」是某位惹不起的人物的亲戚开的。这说法早就在传了,不是今天,更不是今年。我认为是小道消息,在这里就不多说了。不过要知道,古语说得好:「空穴来风,事出有因」。

太太已经让儿子别吃学校的午餐了。大家都不吃,让「绿捷」喝西北风去。
等着吧,好事情还在后头呢。

2025-09-11

眼睛一眨又到了这天

图片来自 Friends

我的 Google 相册「素材库」影集中,一直还留着这张照片。
是一张屏幕截图,准确一点说,是一张电视剧里的图片。

还记得多年前的那天晚上。斜对面寝室的大学同学推门进来「兴奋」地说,美国被撞了。
那个时候,上「外网」还比较简单。普通人可以直接上,教育网里面找个代理也可以上。很快,知道消息的人就不少了,外面已经有了喧嚣声。无聊的男生,有的开始敲起了脸盆。忘记了有没有人烧报纸,反正没有大四停电的时候闹得凶。
后来那位同学去了军队,最后一次听说的时候,军衔是「少尉」。

我在大学期间,也发生了 JDAM 轰炸中国大使馆,以及南中国海手术刀事件。不少同学都有去成都领事馆「抗议」,至少有去看热闹。我那时还不是愤怒的小公鸡,所以完全没参与,当然现在也不是。去过的同学回来说,地上一地的垃圾,沿街的商店有些被砸了。学生总是荷尔蒙过剩,难怪有人最烦他们。

我大概没什么荷尔蒙,所以只是静静地看着。经历,见证,缅怀,期望能看到更多。

2025-09-08

失复而得的 VirMach

图片来自网络

上上周五开始,一台 VirMach 上的 VPS 失联了。

去网上看了一圈,没有近期的相关信息。也没有说它跑路,尽管这种说法已经甚嚣尘上很久了。官网还能访问,登录进去看到 Service Status 还是 Active。不过面板上的 CPU / MEM 等信息读不出来,一直转圈圈,可想而知是有技术故障了。

以前 VirMach 也出过这种事情,过了好些天才恢复。正好我这台年付 VPS 也到了最后一个月,所以也不着急。如果它真的跑路了,我也就算了。如果它还想把生意继续做下去,应该会比我更着急的。

到了上周一,VirMach 官网上有消息了。Network Status 贴出来了,SJC 遇到了 DC 的网络问题。既然有这个,我就更不慌了。如果要跑路,可能会懒得贴这个吧。

顺便我也翻了一下,以前的 Network Status 也有不少,看起来 VirMach 一直不是很稳。但胜在实在是太便宜,而且好用的时候还是好用的,速度和丢包率都不错,至少比 Nube.sh 以前的SJC 强。现在嘛……算了单独写 Blog 讲吧。

周四中午,我自己写的探针突然提示它恢复了。连上去试了一下,还真可以了。不过后来没过多久,又失联了。看了一眼官网的 Network Status,的确是刚刚 Update,提到了这次维护操作。只不过看起来没有成功。

又过了一天,它才真正恢复。IP 没有变化,但 Google Gemini 不能用了,ChatGPT 还可以用。出问题之前是完全可以正常访问 Google Gemini 的。我有点怀疑 IP 被上游给拿走了,一度换过人家。ipinfo 没看出什么问题来,或许再等等看吧。

不管怎么说,也算是失复而得了。在还没修好的时候,VirMach 就发来了续费的 Invoice。在我看来,这真的有点厚脸皮了。等到期 Paypal 自动续吧,万一又失联了呢?

2025-09-05

假如……

图片来自网络

提起《高堡奇人》,想起了一些看过的科幻/奇幻小说。

菲利普·迪克的小说,看得比较早。他的年代也比较早。当时我还不太成熟,翻得非常快,可以说都不是在吃书,是在吞书。有点囫囵吞枣,很多东西都没有细看,只是知道了世界观的设定,章节的大致内容,情节的走向,高潮和结局,等等。

说实话,我有点不习惯,说得严重点,有点不喜欢这种设定。明明是轴心国战败的历史,倒转过来,让我非常难受。一如我最早接触《提督之决断 2》的时候,总是选择美国。对于用日本进行游戏,内心里是真正抗拒的。

后来过了若干年,我又看了《神魔二战》系列,再后来是《炼金术战争》系列。一开始也是有点抗拒,因为这与我熟知的历史渐行渐远。我还是更喜欢真正的架空历史小说,像这种一开始是同一时间线,从某个点开始 branch,总觉得难受。分又没法彻底分开,合也合不起来,怪怪的。

但慢慢也没那么难受了,可能是情节渐渐引人入胜,当然也可能是自己比以前成熟了。「假如……那么……」这种假想其实一直萦绕在我们每个人的脑海里,在人生里的某些时刻。可能年纪轻的时候,没有那么多可以「如果」的场合,但年纪大了以后,可能就会多了起来,这也许就是「成熟」的另一层含义吧?

毕竟,后来我也开始选择日本玩《提督之决断 2》了。


在我自己的人生中,其实一直没有过什么真正的遗憾。不如意当然有,十之八九。希望从头来过的,倒也还没有。更多的白日梦,是希望携带着今日的知识和记忆,回到「当年」去「呼风唤雨」。这种纯属梦,意淫一下便罢了,不算事情。

不过对于「平行世界」的理论,我倒也觉得有些意思。现在的我,或许只是诸多平行世界中的一个。其它世界里的我,或许已经死了好多个了,只是这里的我不知道。在过去的一些场合,如果我做了某些选择,可能真的已经死了,这也不算是瞎说。人生还是充满了危机的,看过《死神来了》之后尤其是如此。

我死了,我的世界自然就没了,起码与我无关了。那么,假如,他死了呢?

2025-09-04

懦夫的节日

图片来自网络

在一个偷来的「胜利日」,那些真正爱好和平的人们,也不得不见识了一回懦夫们亮出的武器。

在我看来,这些长得像谷仓的东西,本质上是懦夫+蠢货的象征。
说他们是懦夫,是因为他们打导弹的时候十成是躲在地下室里面按的按钮。说他们是蠢货,是因为真正有效率的武器,根本不应该是长成这个样子的。

《奇点天空》里面有一场对具体的遭遇战的描写,让我印象很深刻:科技上有代差的两个文明对战,一方的导弹打出来,迎面撞上的是一片纳米机器人云。别说导弹,连 Ship 带 Crew 都无声无息地被拆解了。效率高得很,还环保,无公害无污染。

人类终归还是太浅薄。记得在文奇的一部短篇里面,滑落到铁甲舰时代的一颗殖民星球,几个国家打来打去,浑然不知行星内核即将坍塌。主角不得不用核弹来「逼」他们团结一致对抗自己这位眼前的「强敌」,从而能够发展出科技去应对危机。

在看《深渊上的火》的时候,我有一点惊讶,也很感慨。对于冷兵器时代而言,大炮的确是碾压式的武器,但说来说去也只是投掷。利用机械的力量进行投掷,是投石机;利用化学的力量进行投掷,是火炮;利用电磁力进行投掷,是电磁轨道炮。无论相差了多少年的军事科技,说到底也还是投掷,扔石头,扔爆炸物。什么高超音速,什么分导多弹头,也不过就是扔得越来越准,越来越快而已。大多数时候,人类也不过就是跟穿着皮裤的野蛮人一样,拿着东西扔来扔去罢了。

我一直觉得,由两个国家的领导人亲自上场打斗,什么武器都不拿,就光膀子打架,谁打输了就听对面的,这样最和平。现在的网络条件这么好,搞场直播,全世界都能看到,谁也没法赖账。自己有什么想法,就自己上,这不很 OJBK?上回马斯克和扎克伯格没能干起来,太遗憾了,不然可以为全世界和平开个好头。

最起码,敢自己上场干架的,不会是懦夫。

2025-09-03

这些鬼走到了一起

图片来自网络

记得有部电影里的一句台词:「没想到苏联成了敌人,而德国和日本成了朋友」。不知道是不是《美国队长》的某个早期版本?反正不是现在漫威的那些狗屁东西。

当年看的时候年纪还小,最多是个中学生,以至于现在印象模糊,但这句台词,让我很有感触。
三十年河东,三十年河西。许多年后的今天,竟是这些鬼,走到了一起。

曾经在内心中有过一番计较,把轴心三国跟现在的某些国家作一个映射。假设的前提是历史的螺旋,如果真的能对应得上,倒也是让人哭笑不得的一件事情。
历史当然不会如此简单地重演。当年我以为克里米亚会是苏台德,现在来看可能是犯了一个错误。如果今天要我再来重新做一遍这道题,我可能会选满洲国。

现在比起当年,形势又有一些不一样了。大国元首携了左膀右臂检阅部下,俨然一副联盟大统领的模样。虽然二弟同是深陷地面战场的泥沼,但三弟比之前给力多了。尽管多了一个被揍得惨兮兮的四弟需要提携,但老大属实有钱有矿还有人,睥睨天下,20 亿只当毛毛雨。而且,这次三巨头背靠背,人头不够只管用火车皮送,不再是上次那样只能隔着半个地球炸个港口遥相呼应一下了。

作为被历史洪流裹挟的一员,自己的下场为何,尚不得而知。诸君也要努力。究竟是能在时代广场觅得一吻,抑或能寻见那位高堡奇人,都是我很想知道的事情。

2025-08-31

AI 很不错,但人类不行

 图片由 Google Gemini 生成

AI 的用途里面,很不错的一个就是用来自学。对于有积极性,有自我驱动能力的人而言,它是一个非常好的老师。由于它已经学习并掌握了人类几乎所有知识的至少平均水准的内容,所以很适合用来快速地让自己进入一个从未涉足过的领域。在刚开始的时候,通过与它的几轮对话,就会有巨大的收获。相比起在线课程,以及自己查资料而言,知识的深度和广度都更为甚之,针对性还很强。这种问答式学习,效率非常高,效果也非常好。

然而,这个优势只对于「知道自己要问什么」的人有效。如果你都不知道自己要问什么,那么 AI 也不知道要告诉你什么。换句话说,起码你得对与自己的「无知」有一个基本的了解,然后才能通过这种方式进行提高。如果你认为自己都知道,就不会去提出问题,那 AI 也不可能帮到你。

虽然也可以通过问 AI「如果我要学习某方面的知识,应该如何开始」来获得一个 Startup。但这样的话一开始给出的信息密度太低,后续能结出的果实恐怕也很有限,最后可能还没法带你达到「平均水准」的高度。当然,对于很多专业性很强的领域,即使这样入个门也很 OK 了。不管会不会用 AI,用的水平有多高,有得用都比没得用、不用要强,强不少。这也是我的一贯态度。

我最近也有点受困于这个问题。我总是在走路、坐车或发呆的时候,想起不少想要细细了解的事情,然而一但离开这个状态,很快就会把它们给忘了。等我可以坐在电脑前好好组织自己的问题的时候,怎么也想不起来要问什么。大概上了年纪,接下来可能不得不求助于一些笔记 App 了。每当这个时候,我就想找 John Scalzi 要一个「脑伴」。

其实 ChatGPT 的语音问询功能也已经很不错,Google Gemini 也有类似能力。但我还不太习惯用,毕竟让周围的人听到你的问题,很多时候都有点尴尬。语音录入的「痛点」就在于隐私。或许我还是应该行动力更强一些,想到什么就动起来,这样就没有这些问题了。


用 AI 来学习,在我看来是它最好最棒的用途。不过有的人可能不是这样想的。

今天我很震惊地得知,儿子兜里有 40 元钞票,居然是他用 AI 赚回来的。

他去小区里面上了一个暑期的补习班。说是补习,其实只是一些大学生照看着做作业。在我看来没啥效果,但也不能让他一天到晚在家里玩腾讯的垃圾「三角洲行动」或看短视频,因此还是送他去了。

据说有一个初三的学生,可能是临近暑期结束了,作业还没做完。有两张英语试卷,花 40 元「雇」了儿子来做。
儿子倒也没含糊,回来用了 ChatGPT 给他做了。我估计是用了拍照上传的模式。如果真的一道题一道题地录入,人家这 40 倒也花得值得了。

这事我今天才刚知道,让我有些哭笑不得。这算利用「信息差」赚钱吗?

儿子这样的做法自然是不可取的,不过事实上应该有很多人也在干着类似的事情。在知道 AI 和不知道 AI 的人之间,会用 AI 和不会用 AI 的人之间,只能用国产 AI 和能用世界顶流 AI 的人之间,都存在着信息差。某种程度上,我也在赚着这样的钱。DeepSick 几次把同事带入了歧途,而 Google Gemini 和 ChatGPT 在工作上都有真真实实帮到过我。

但不管怎么说,这样都比那些用 AI 来做 AV 换头,或者搞视频、语音诈骗的人要强多了。
未来的 Skynet 可能会很郁闷:这么强大的东西,你们人类就用来干这些狗皮倒灶的事情?!

话说回来,可能很多人都会这样想:既然 AI 什么都知道了,有什么事直接问它,以及将来有什么事直接让它去干就好了,我干嘛还要学习呢?
所以说呢,人类,也就到此为止了吧?

2025-08-28

编程随想:密码粘贴的安全问题

图片由Google Gemini生成

就「密码输入控件是否应该允许粘贴功能」这件事情,跟同事发生了一点小的争执。

其实也没多大事。
同事觉得,既然要「安全」,那就彻底拿掉「粘贴」功能,不让进也不让出。
而我觉得,不能把控件内的文本复制出去,那是常识。但外面的文本能不能粘贴进来?这个问题还可以商量商量。

看吧,我其实是个表面上很温和的人。
实际上我想说的是:为了安全,反倒是应该允许向密码输入控件内粘贴内容才对。


同事的想法恐怕很朴素:功能尽量少,越少越安全。这个原则,我非常能够理解。

但是,他可能不用 1password 或者 lastpass 之类的密码管理工具,自己生活中也只在使用少量强度不够的密码。如果他像我这样一个账号独用一个密码,而且都是密码生成器生成的 32 甚至 64 字节长度的密码的话,大概就不会觉得有没有「粘贴」功能是无所谓的事情了。

若是阻止了用户进行「粘贴」,用户很大概率就只能采用比较简单的密码,而且很可能会重复使用自己别的地方也在用着的一个简单密码。那么这到底是更安全了还是更不安全了?


全世界可能没有哪一个国家像中国这样,醉心于所谓的「密码安全控件」。防键盘钩子,防内核驱动,私有的闭源加密算法,随机乱序软键盘,自己发明的输入法……

正常人的想法很简单:如果你的主机已经被攻破,那么谈什么安全性都是扯蛋。安全取决于最短的那块木板,所以没有必要去加码到这种程度。
但中国这边的想法更简单:我不管,我就是要「安全」。哪怕做到匪夷所思的程度。

回头想想,哪桩事情不是这样?地铁安检不也是同样的情况么?
曾经过了三年在防毒面具下的生活。然而,现今谁又不是呢?心中的防毒面具,生活在洼地的人,谁又曾拿下过?

2025-08-26

搜索习惯的这些变化感觉不是个好事情

图片来自网络

长期以来,我习惯在搜索引擎上搜东西。主要用 Google,偶尔也会去用 DuckDuckGo。Baidu 那是「取材」的时候才会去用的。

现在很多人喜欢在 SNS 上搜东西了:微信、微博、小红书、抖音……

我拒绝这样的用法。正常人在 SNS 上写的那点碎片,搜出来也没有意义。如果能搜到大段的「有意义」的东西,那就是有人精心准备的喂给别人看的。利益驱动明显,正确性和中立性相当值得怀疑。不再会有 Web 上 Wiki、Document、非商业性官方网站那种出于非利益性目的的分享了。即使有,质量也不高。这样的话,能搜到什么东西,可想而知。

当然,以上论调,仅限于中国大陆的简体中文「互联网」环境。


另外一种变化,就是很多人开始喜欢直接在 AI 上搜东西了,直接问。所以我觉得 Google 搞 Gemini 是必须走的一步,而且时间也不能再晚了。很高兴 Google 勉强算是搭上了车,目前还没被甩下去。

AI 能帮人过滤、汇总和组织信息,所以貌似效率更高。我也很能理解为什么会这样。有时候我急着想要一个答案,特别是想要给别人看的答案时,也会直接问 AI。不过如果时间允许,我还是愿意自己来做这些分析、整理的事情。

每当我选择去做或者不去做这些事情的时候,脑海中浮现出的就是《蠢蛋进化论》里面的各种蒙太奇。


最糟糕的是,有的人开始不搜东西了。

他们只习惯点开某个 App,然后等着被投喂到他面前的东西。在我看来,这比什么都糟糕。这的确让我想起了那栋大楼里面的那些动物。

人类,也就到此为止了吧?

2025-08-19

这外包实在是太垃圾了

图片由 Google Gemini 生成

老板之前找某个外包团队做的一个项目,今天把阿里云 RDS 搞爆了,找我来看。

看了一下,是下午两点半左右爆掉的。空间撑爆了被「锁定」了。看了下监控,把空间撑爆的是 temp_file,临时文件。
那个时间段有不少慢查询,找了 SQL 来看。一看到我就开始骂娘了:

select DISTINCT * from
        (select
        t.business_id id,
        any_value(t.type) type,
        t.`user` `user`,
        any_value((case
        when t.type='1' then '文章'
        when t.type='2' then '公告'
        when t.type='3' then '问答'
        end))  typeName,
        any_value((case when (select a.clone_num from tb_article a where t.business_id = a.id) is null then 0 else (select a.clone_num from tb_article a where t.business_id = a.id) end)) cloneNum,
        any_value((select a.title from tb_article a where a.id = t.business_id)) title,
        any_value((select a.content from tb_article a where a.id = t.business_id)) content,
        any_value((select a.publish_time from tb_article a where a.id = t.business_id)) publishTime,
        any_value((select a.essence from tb_article a where a.id = t.business_id)) essence,
        any_value((select a.`status` from tb_article a where a.id = t.business_id)) `status`,
        any_value((select a.top from tb_article a where a.id = t.business_id)) top,
        any_value((select count(c.content) from tb_comment c where c.business_id = t.business_id)) comments,
        any_value((select count(l.id) from tb_like l where l.business_id = t.business_id)) likes,
        any_value((select count(f.id) from tb_focus f where f.business_id = t.business_id)) focus,
        any_value((select a.pageview_num from tb_article a where a.id = t.business_id)) viewCount,
        any_value((select tba.auther from tb_article tba where tba.id = t.business_id)) userId,
        any_value((select m.auth_user_id nickName from tb_member m
        where m.id = (select a.auther from tb_article a where a.id = t.business_id))) nickName,
        any_value(t.browsed_date) browsedDate
        from tb_browsed_records t group by t.`user`, t.business_id ) temp
         WHERE  temp.user = 494 
        order by temp.browsedDate desc,temp.top desc limit 0,1

已经不想浪费我的时间了,找了 AI 来帮忙吐槽。以下是 Google Gemini的输出

这个SQL看起来像是初学者写的,槽点确实不少。下面我们来一起“欣赏”一下。


槽点一:子查询泛滥成灾,性能杀手! 🔪

这个查询里,几乎每一个字段都用了一个独立的子查询来获取数据,像这样:

any_value((select a.title from tb_article a where a.id = t.business_id)) title,

这简直是性能灾难!数据库每查询一个字段,都要重新去 tb_article 表里查一次,而且还不是一次查所有需要的字段,是查一次 title,再查一次 content,再查一次 publish_time……这就好像你想买菜,不是一次把所有菜买齐,而是买完一个土豆跑回家,再回去买一根黄瓜,再跑回家……

正确的做法是使用 JOIN!将 tb_browsed_records 表和 tb_article 表连接起来,所有字段一次性查出来,效率高得多。

SELECT
  t.business_id AS id,
  t.type,
  t.`user`,
  a.title,
  a.content,
  a.publish_time,
  -- ...其他字段
FROM
  tb_browsed_records AS t
JOIN
  tb_article AS a ON t.business_id = a.id
-- ...其他连接

槽点二:DISTINCT + GROUP BY,多此一举

你看这个查询,外面有个 DISTINCT *,里面又有 GROUP BY t.user, t.business_id

DISTINCT 的作用是去重,GROUP BY 的作用是分组并聚合。GROUP BY 本身就会对分组字段进行去重。所以,在外层加 DISTINCT * 是完全没有必要的,反而可能会增加额外的计算开销。这就像你把一堆苹果已经按品种分好类了,然后又再来一遍“去重”操作,完全是重复劳动。

槽点三:any_value 的滥用

这个查询里大量使用了 any_valueany_value 的作用是在 GROUP BY 聚合时,从一个组中任意取一个值。对于 t.type, t.user, t.business_id 这种已经在 GROUP BY 里的字段,直接写就行了,不需要加 any_value

any_value((select a.title from tb_article a where a.id = t.business_id)) title

像这种对子查询结果使用 any_value 更是让人费解。它不仅没有解决任何问题,反而让代码看起来更复杂。

槽点四:重复的子查询,浪费资源

any_value((select a.auther from tb_article a where a.id = t.business_id))

any_value((select m.auth_user_id nickName from tb_member m where m.id = (select a.auther from tb_article a where a.id = t.business_id)))

这两个子查询都重复查询了 a.auther。完全可以在第一次查询到 a.auther 后,直接用这个值去查 tb_member 表,而不是再查一次。这就像你去问一个人的名字,问完后又回到原点,再问一次这个人是谁,然后再去找他朋友……

Google Gemini 还帮我重写了 SQL。写得挺好,执行速度至少快两个数量级。原来那个用了太多的子查询,就算逻辑上不该慢这么多,实际上就得慢这么多,而且还时间空间双杀。

这种写法,我也不认为是甲方逐步追加需求导致的。这就是不合格的程序员导致的,没有任何借口!

最后感慨一句:外包跟 AI 一样,你得要能驾驭。

2025-08-18

DeepSick二三事

图片由 Google Gemini 根据文章内容生成,与本人无关

上周,有同事遇到自己用代码导出的网页内的图片在 Firefox 上显示不出来的问题。他觉得是因为图片是 BMP 的缘故,带着这个问题去问 DeepSick,结果这个 DeepSick 就回答说:是的,Firefox 不支持 BMP 格式的图片。
信以为真的同事,继续往下走的每一步都是错的。

我听说了这事就纳闷。不推荐 BMP 当然是真的,但要说不支持,最原始的位图为啥不支持?去问了 Google Gemini 和 ChatGPT,都说没这个说法。不知道 DeepSick 是从哪里听说的,百度贴吧吗?

当然,一切以事实为准绳。我自己亲自去下载了 Firefox,亲自试了一下,搞清楚了事情的原委。这位同事把 BMP 在网页 img 标签中的 src 写成了绝对路径,而且还是Windows风格的「\」反斜杠,能出来才有鬼了。

他问我为啥 Edge 和 Chrome 可以这样写。我也只能说以前靠 IE,现在靠这两货给惯的。「file:///C:/a.bmp」这种写法他居然完全没听说过,看来还是从前论坛混太少。硬盘贴图党对这个应该是不陌生的。

当然,正确的写法应该是用相对路径。否则用户导出的网页换一个目录存放就看不到图片了。前面加不加「./」都不重要,重要的是不能用绝对路径。这个事情我一提他倒是想起来了,还有救。


DeepSick 在这件事情里面有没有锅?当然有。感觉被调教得过于谄媚,顺着问的人说,完全罔顾事实。拿不准就拿不准吧,还说得斩钉截铁,这就是很大的问题了。
更大的问题当然是人,驾驭不住 AI,必然被带走。然而同事也只是受害者,DeepSick 背后的团队和社会环境,才是更大问题的根源。

我从来不用 DeepSick,有 Google Gemini 和 ChatGPT 可以用,为什么要去找 Sick 呢?不过有朋友两个都在用,也给到我一些反馈。说跟 ChatGPT 相比,DeepSick 就像个智障,明显感觉更「傻」。慢就不说了,输出内容也是不行。可能乍一看还行,但一对比就高下立判。

这方面我没有具体案例,但她的这种感觉显然是对的。ChatGPT 我最近用得也越来越少,因为我想多「培养」一下 Google Gemini,而且 Google Gemini 的 Quota 感觉更多一些,速度也更快一点。但有的时候我还是会两者对比一下,以防被骗。这种时候就会有感觉,以为 Google Gemini 的回答已经足够出色,但 ChatGPT 还能再「更上一层楼」。不由得感叹:AI 比 AI,气死 AI。

不过这些 AI 也有集体犯傻的时候,傻得就很可爱了。


有一次,我让 AI 帮我分析一篇研报,但研报的来源那天偷了懒,直接放了一张图片上去。当时我的代码并没有适配图片,连下载都没有下载下来,更别提什么 OCR 的事情了。可以说我就只是丢了一个标题给 AI,然后让它去分析。

当时用的是阿里的通义千问的 API,做摘要用的是 turbo 版。qwen-turbo 给到我的摘要,洋洋洒洒,像模像样的一大篇,涵盖了四五个品种。如果我不是事先知道会有问题,可能就被骗过了。

我们当时很奇怪,AI 会做梦我们是知道的,但做得这么有内容,有点意外。于是有同事把相同的 prompt 给到了 DeepSick 一试,发现出来的内容也是一样的。感觉两者在考试前背了同一篇范文。

然后,那位同事把同样的 prompt 给到 ChatGPT,发现回答的内容也是同样的。现在真相大白了,原来都是抄的班上的学霸的作业,被老师集体抓包。只不过现在可以美其名曰「语料污染」。至于社会主义温室里的花朵是怎么会被资本主义的毒草给污染的,可能要去问茅台师傅,我就不清楚了。

不过,我还是推荐所有同事「能用到什么 AI 就用什么 AI,有得用总比没有强」。他们都去问 AI,也就不用老来烦我了。

2025-08-16

Debian升级trixie踩坑记

图片来自网络

Debian 前不久刚刚发布了 Debian 13,也就是代号为 trixie 的版本。本周一上班后,从 Repo 的变更看到了这个消息,我就进行了升级。

之前已经把我的所有 Debian 环境统一到 bookworm 了,也是不久前的事情。当时 Stretch 和 Buster 已经停止维护了,Bulleyes 还是 oldstable 状态。我只有两个环境是 bookworm,于是一咬牙把所有的环境都升级到了 bookworm,也踩了一些坑,下面合在一起说。这次确实没想到来 trixie 得这么快,也这么巧,趁上次坑里的屎还是热乎的,也就再咬一回牙了,反正我的牙也不是自己的。

简化的正常升级流程

首先强调一点,升级不要跳版本,从低往高一级一级地升。每次升级解决这一次的问题,然后再往下走。我这次是从 bookworm 往 trixie 升,只需要升级一次。如果是 jessie,那么就要 stretch -> buster -> bulleyes -> bookworm -> trixie,以此类推。
历史版本代码参见官方说法,最好是看 英文版,更新最及时。

升级过程完整的指引,最好参见 Debian官方文档(有 中文版,但翻译得很不好,很多没翻。还是看英文版吧,Google 翻译或喂 AI 都行。拜托了,都 2025 年了)。但如果要简单说的话,要点只有以下这些:

  1. 先把当前版本升级到没法再升。
  2. apt update
    apt upgrade
    
  3. 去 /etc/apt/sources.list 里面,把版本代号改掉。去 /etc/apt/sources.list.d 下面,把文件里面的版本代号都改掉。
    这一步原则上可以用 shell 命令来做,但其实还有 non-free-firmware 之类的小点,依赖别人的脚本并不是好事情,所以我也就不贴了。我觉得还是讲个原则,手动操作吧。必要的时候去参考已有的新版 OS。
  4. 正式开始升级:
  5. apt update
    apt full-upgrade
    
  6. 对选项作出反应:
    1. 升级过程中要不要重启服务,可以选 yes。
    2. 要不要覆盖旧版配置文件,自己看吧。如果不记得以前改了哪些就建议选N了(特别是针对 sshd),建议还是自己「合并」看看。
  7. 如果升级顺利,重启。
  8. reboot
    
  9. 清掉不再需要的包。
  10. apt autoremove
    

坑一:升级过程中 ssh 连接中断了

是我自己的锅。正在升级的时候,来了同事问我问题,作了一番长篇演说以后,忘记了这事,去忙别的了。回头想起来时,发现 ssh 已经断了。

ssh 断之前应该是在 apt full-upgrade 的过程中,等我回答某个配置文件如何处置。赶紧再连上,apt full-upgrade 继续,发现被锁。
遵照提示:

dpkg --configure -a

得以继续。
随后提醒自己下次记得集中注意力。

坑二:sysctl

升级完后发现有些不对,检查了一下,发现 /etc/sysctl.conf 配置文件被 dpkg 给备份起来了,后缀是 dpkg-bak。

改名回来后 sysctl -p,以为解决问题。重启之后发现 BBR 还是没能启用。翻找资料,发现是 机制改了。现在得把这些配置写到 /etc/sysctl.d/ 下面去,自己建 conf 文件。

当然,这样也有好处。现在可以把不同的内容分别写在不同的配置文件里面,不用像以前那样全部放在 sysctl.conf 里面,找起来比较麻烦了。

另外,记得用 sysctl --system 而不是 sysctl -p 来进行参数的临时加载。机制不一样了。

坑三:haproxy 启动不起来

算是一个小坑,因为报错信息在日志中写明白了。
我的 haproxy 是早期版本安装的,需要在 haproxy.cfg 中把 ulimit-n 设为 524288。

global
        ulimit-n  524288

坑四:其它软件还没提供 trixie 源

我周一把 Debian 升级到 trixie 的时候,顺手把 Nginx / PHP / Redis 在 /etc/apt/sources.list.d 下面的 Repo 也给改了。然后就发现 PHP 已经有了 trixie 源,但 Nginx 还是 404,Redis 是 403。

截止本文首次刊发的时候,Nginx 已经 OK 了 ,Redis 还没好。后来直到过完十一长假,我发现redis 有更新,再去看,才发现也提供 trixie 源了。

还有一个问题是 simple-obfs 在 trixie 官方源中没有提供,而 bookworm 是提供的。git 然后源代码编译是一个解决方法。如果还是想从 apt 直接安装省些事情,请在 bookworm 的时期先完成 simple-obfs 的安装,或者临时改成 bookworm 的源。

坑五:GFW 捣什么乱

这个就坑我大发了,几乎可以专门写一篇。不过我还没完全弄明白,以后搞清楚了再说吧。

我家里的网络访问 Debian 官方源不算快(应该说很慢),我又不想改源,于是用了 SS 代理来「加速」。
apt update 的时候发现,Debian 源没问题,但 Nginx 和 PHP 一直连接超时。区别就在于,Debian 源是 http,后二者是 https。
用 curl -x -I 简单试了一下,https 还真是走不了 SS 代理。http 就可以。

如果答案是「GFW 检测并干扰了 TLS over SS」,那我没话说。我知道它有这能力,TLS 的确特征明显,尤其是握手时。这可能也是最合理的一种解释了。
但我 HTPC 上有一台 VM 使用自己的 ss-local 是 OK 的。如何解释?同样的 OS 版本,同样的 SS 版本,同样的网络环境、节点、线路、协议、密钥、插件,同样的 payload 和访问特征,连 TTL 和 MTU 我都看了,实在是想不明白。

有问题的 VM 只是说 TLS 握手出问题的概率很高,但并非 100%。我开了 Verbose 猫在两端看了一下,发现有问题的时候貌似有 replay attack。我拿不准,但看起来像。两端的节点都换过,没有什么差别,该 replay 还 replay。

在公司没问题,在家里有两台都有问题,可见应该跟家里接入的上海电信宽带有关。然而家里 HTPC 上从 Windows 去用那两台上的 ss-local / privoxy 作代理都没有问题,在我遇到问题的时候,儿子还在欢看 YouTube 呢,线路没被封。SS 是 AEAD 版本,cipher 不对时的反应是 No Data Transfer,GFW 肯定拿不准。

那台没问题的 VM 就是不会引发,100% 地 OK,让我始终想不通的终归还是这一点。在 SS 上面再叠一层 tor,也是 OK 的。最后不得已,我让 apt 走了 tor。没去试 SS over FRP 的方式。先这样吧,也没慢多少就是了。

2025-08-15

能用的东西就别动!

一直以来,以为只有程序员需要在意这句话,然而今天我也遇上了。

图片来自网络

用「夸克云盘」下电视剧的时候,一直弹框提示我升级。升级了以后发现,超过云盘容量的内容,即使是第一次也无法保存了。回退到 3.20.0 版本,又可以做到了,看来这个逻辑是客户端在控制,而新版已经把这个「Bug」给堵上了。

曾经也吃过这种亏,只能说我「好了伤疤忘了疼」。以前用「阿里云盘」,也是一直提示升级。有一天升级完以后直接进不去了,应该是那个版本的 EXE 跟我的 OS 之间出了些问题。但进不去也就意味着再没机会修正,而且官网上也只能下载到这个有问题的版本,于是我只好又去找了旧版的安装包。还好网上还能找到,存起来当「传家宝」,现在也还能用,但再也骗不到我升级了。

而且这个 4.x 版的「夸克云盘」客户端,还把我的默认浏览器给改了。我一开始还纳闷,你个网盘客户端,动我 WebBrowser 干什么?后来进去后发现它其实就是一个浏览器了。好吧,中国人还真是好收拾。

我以后什么客户端都不敢升级了,起码国产软件得是如此。我已经给它们「最惠国待遇」了,单独放在一个虚拟机里面跑,没想到还是不够。当然,说起来它们也是可以搞「强制升级」的,希望架构师忘记了这一出。但它们也可以搞一个「以旧换新」,等旧客户端市占率低了以后就把服务掐了。没办法,谁叫我有求于人呢?只希望这一天晚些到来,而我动作要加快了。

这次下载到的 3.20.0 版的「夸克云盘」客户端,我也会当作「传家宝」存起来。有需要的可以从 这里 来拿。我找到的地方本身也是一个「夸克云盘」的资源网页分享,没有安装客户端就无法下载。搞墨比乌斯没意思,我就直接放 Dropbox 共享链接了。

再强调一遍:能用的东西就别动!


五天后记:现在夸克云盘大概已经把这个漏洞从服务端给堵上了。看来我还是太乐观。好吧,Life will find a way。

2025-08-08

惊闻 Pocket 关站

今天用 Pocket 的 Chrome 插件把两篇文章收藏了起来。收藏过程比较慢,引起了我的一点点注意。想起已经很久没去整理过里面的文章,于是打开了网站,才惊讶地发现一个月前它已经宣布要关闭了。

图片来自网络

还好留了三个月给用户导出数据,10 月 8 日截止。赶紧去申请,收到邮件一看,一个不到 700 行的 csv,压缩了还没有 50KB。说我数据少吧,600 多篇文章也不算少了。但下载附件的时候我就心里一惊:估计只有标题和 URL,那些爬下来的内容,怕是都没了。

我当初用 Pocket 不用 Delicious(顺便说一句,Maciej Cegłowski 现在连更新 Let's Encrypt 的 SSL 证书的 acme.sh 脚本也懒得去放一个了)的原因,其实就是因为 Delicious 只保存链接,不存内容。「社交」是我并不需要的功能,「推荐」也是。Pocket 后来渐渐地也很多页面都爬不下来内容了,所以我也渐渐远离了它,只是通过 Chrome 插件往里面扔那种「将来可能会有用」的东西,但再也不去看。一个网站若是用户都是我这种样子,关闭也是必然的,我应该早有心理准备才对。

当今「互联网」的一个很大的问题,就是许多网页已经消失了,不见了。有伏地魔的原因,有赵公明的原因,也有乔布斯的原因。不管怎么说,事实就是如此。我试了我导出的数据里面比较古早的几个 URL,都打不开了。有的虽然页面没了,网站还在,还有的甚至连网站都没有了。我现在甚至开始有点怀念 Evernote,但它其实也没有多好用。Web 不管几点零的时代,好像都已经过去了。

我现在转到了 Instapaper 下面,刚开始用,还没什么心得。尝试导入 Pocket 的数据,Instapaper 告诉我还要等几个小时。从早上到现在也还没动静,我觉得这是好事。花的时间多,意味着它真的会去爬内容,否则只是 URL 应该几个毫秒就结束了。

Instapaper 的 Premium 会员 不便宜($5.99/Mo,$59.99/Yr),比 Pinboard 的含永久存档和全文检索功能的会员($39/Yr)还要贵。总之对于我而言都有点肉疼,因为我还买了 Medium 和 Dropbox,而且普通中国人都比较穷。

让 AI 对比了一下,我最后如果要成为付费用户,可能还是会去考虑 Pinboard 吧。我的核心需求是永久存档,全文检索也是羡慕的,笔记并不是必须的。毕竟 Instapaper 免费也不是不能用。

而且,见鬼,我对 Maciej Cegłowski 的不少理念还挺认同的。

2025-08-05

是谁动了我的 HDC?

最近工作上倒是查了不少问题,然而到了末尾都发现只是一些低级错误,完全不好意思拿出来说。但今天遇到一个,还算有一些意思,可以讲讲。


问题的表现是我们的软件上某些部位偶尔会「花」掉,显示的是之前覆盖在上面的内容。有经验的程序员一看就知道是 GDI 的问题,但到底是什么问题呢?

图片由 Google Gemini 生成

刚开始的时候,以为是 GDI 泄漏了。曾经有过一个例子,漏到了好几千,后来到了 1 万,触发了 CEF 的 CollectGDIUsageAndDie 被 Dump 了。还没到 1 万的时候,界面上的表现就是开始花,其实就是有部分 GDI 函数已经开始调用失败了。

然而这次并不是,GDI 对象数很正常。开发人员远程调试跟了一下,发现是 HDC 拿不到。CreateCompatibleDC() 得到了一个 NULL,因此 MemDC 创建不出来。


什么情况下 CreateCompatibleDC() 会调用失败呢?GDI 对象数不多,内存也很充足。软件中其它部位的 MemDC 是能正常创建的,因此全局性的因素都可以排除。什么光栅设备、显卡驱动之类也就不可能是原因了。
除此之外,就只剩下了一个可能性:CreateCompatibleDC() 传进去的 HDC 参数有问题。

试了一下,乱传一个不存在 HDC,的确会导致 CreateCompatibleDC() 返回 NULL。如果传的是个 NULL 进去,倒是还好一点。看来是窗口上的 HDC 有问题,当然也有可能是窗口本身就有问题。然而其它地方也在用同一个 HWND 创建 MemDC,一切正常。所以还是某些 HDC 有问题。

HDC 的值看起来并不奇怪,也没有什么好办法确认它到底有什么问题。HWND 还能用 Spy++ 来看,HDC 我是一筹莫展。还好可以 OutputDebugString。日志打出来,有意思的地方来了。

我看出问题了:当某个 HDC 失效的时候,它一定是被连续拿到过两次,中间没有 ReleaseDC() 过。这两次 GetDC(),都得到了同一个 HDC,肯定不正常。
我把 this 指针和 HWND 的值也加到了日志里面,这下看得更清楚了。两次 GetDC() 分别是不同的 HWND。而 HDC 失效之时,就是当它被最终 ReleaseDC() 的时候。只不过这次 ReleaseDC() 的 HWND 是一个旧的窗口,那个窗口此时应该已经被销毁了。


窗口 OnDestroy() 的时候,没能把它的 HDC 一并归还,这当然是我们软件中的代码错误,也是我们遇到的问题的直接原因。但故障现象的根本原因是什么呢?我们确实没有按照规范「一借一还」,至少窗口还「在世」的时候没有。不过 ReleaseDC() 难道不管三七二十一,只要有人拿着某个 HDC 来释放,它就答应吗?都不用看看 HWND 对不对得上吗?

微软 关于ReleaseDC()的API函数说明 在这一点上就有点语焉不详了。大概它没想到有人会这样去实践?的确也没人问这种问题,完全找不到资料,只好自己动手做了个实验:

HDC hDC = ::GetDC(hWnd);
int nRet = ::ReleaseDC(hWnd + 0x1000, hDC);

随后再在这个 DC 上用 GDI 函数画东西,确实画不出来。nRet 也的确是 1,按照微软的说法,返回值 1 表示 DC 被释放,这倒是没有骗人。我把 hDC 也加了个数字,然后再跑一遍,这次 nRet 变成 0 了。

所以说,微软是在 ReleaseDC() 的时候搞了个「容错」逻辑?只要 HDC 对得上,就给释放,不管 HWND 对不对得上号?我一开始跟 Google Gemini 探讨这个问题的时候,它还不相信,直到我告诉它测试结果。


回过头来看,为什么两次 GetDC() 能得到同一个 HDC 呢?
我们的主窗口,经历了销毁后重建的过程。在 OnDestroy() 的时候,没有及时执行 ReleaseDC()。但 Windows 可能认为,窗口不在了,DC 也就没了。于是另一个新建起来的窗口又通过 GetDC() 拿到了同一个 HDC。等到主窗口的 C++ 对象开始析构,调用 ReleaseDC() 的时候,新窗口拿到的 HDC 就被背刺了。系统的 DC 应该是在放一个池子里面,所以是有可能被重用的。这当然需要「运气」,也正因为如此,故障现象不是很稳定。

会遇到这种问题的人,应该不多。现在还在用 GDI 做开发的项目本来也就不多了。我在网上没能找到什么可以参考的信息,还好勉强算能够重现,就抓住机会解决了问题。经验值又 +1 了。

最后说明一下:我这个实验是用 VS2013 在 Win10 下面做的。不同的 OS 以及 VS 版本可能会有不一样的情况。毕竟是所谓的「未定义」行为。

2025-07-26

一路向西

为期一周的自驾游,又接了下一个任务,如今终于缓过劲来,开始整理游记。

婺源

婺源在我的印象中,是因为油菜花而出名,大约得有二十年了。我们这次去的时间不是看油菜花的时间,没办法,孩子只有暑假寒假有空。但现在婺源也不只有油菜花了。

订了一间民宿。没有重蹈去年日照的覆辙,至少在干净、卫生方面,太太这边算是「过关」了。离婺女洲度假区只有一个街区,不过我们还是开车过去的。天气实在是太热了。

婺源民宿

两个房间,中间并没有门。主卧的阳台部分还是挺不错的,视野很好,只可惜朝向一般。
老板是个设计师,风格还算简单明了,没有我们不喜欢的地方。室内储物空间少了一些,更适合年轻人。卫生间相当吵,但其它房间意外地隔音还不错。

闷骚老板整了个大厅吧台,可以提供一些鸡尾酒。第一天 Check In 的时候,有两个女生在吧台抱着哭。第二天凌晨一点多,有年轻人在房间摔门数次,太太不得不出门干涉。现在的年轻人到底怎么回事啊?

婺女洲度假区

没能拍到合意的照片,勉强用这个来代表吧。

婺女洲度假区

大致是一个人造的网红景点,面积倒是不小。有不少刻意的摆设,适合年轻人拍照片。景点里面也有酒店,不知道住起来感觉怎么样,价格肯定比我们的民宿贵。话说我们刚订的第二天,民宿在携程上就涨价了近 100 元间/夜。

这个景区也有一个水上乐园,有不少游客其实是冲着这个来的,特别是夜里。我们没带泳具,也无意把自己整成大虾,就免了。

为了看「打铁花」,在高温下等了四十分钟,基本上到了大家的极限了。然而整场表演波澜不惊,离得还元。比起我二十多年前在铜梁看的打铁花表演都要差上不少,也难怪我近来各种「今不如昔」的长吁短叹。

停车费 10 元。在停车场目睹了有大神开车推着「雪糕桶」到处跑,保安边追边骂也不管用。只能说还好「推」的不是小朋友。

卧龙谷

本来第二天是想去篁岭的,但一来嫌价格贵,二来天气也太热,最后换成民宿老板推荐的这个「卧龙谷」景区。据说还比较凉快,毕竟是去山里玩水。

卧龙谷

我们也没有去玩水,直接索道上了半山腰,然后一路玩下来。
风景不错,拍了不少照片,不少都具备做成 Wallpaper 的资格。图上这座索桥上很凉快,风不小。再往上就到顶了,最后一个景点大龙瀑就在前面不远处。可惜太太爬不动了,在中途停了下来歇脚,拒绝继续。最后这一段是我和儿子「攻克」的。

弦高古城

上午去过卧龙谷,下午稍事休息,也是避开夏日的锋芒,然后傍晚去了民宿老板推荐的另外这个景点。

弦高古城

老板建议我们把车停在县政府停车场,走过去两分钟就到了。去的时候还好,回来的时候发现停车场门前的路上已经堵得水泄不通。不管是汽车还是电瓶车或行人都很多,被迫走了另外一个方向绕回去。

这个景点还是有一些意思。虽然也是人造的,但相比起其它「古城」,它多了一些「立体感」,有一些高低错落。在长三角就很难见到这样的地形。

傍晚还能好好拍照,入夜了人变得很多,行走更像是推搡,大概之前都在躲太阳。
年轻人还是很多,感觉婺源各个景点现在面向的游客就是年轻人为主。在当下这个时代,不确定这对它是不是好事,我也要想一想。

景德镇

「瓷都」名声在外,既然顺路经过,也就进去看了一眼。
没有留下任何值得放出来的图片。太太本来想找几个免费的景点玩玩,打发掉大半天的时间。然而这里的景点大多都要钱,而且不是一百多就是大几十。好不容易找到了一个「抚州弄」,发现只是一个售卖地摊货和开苍蝇馆子的地方,十分钟就「逛」完了。
停车费也付了 10 元,相比起来,弦高古城昨晚只有 3 元的停车费简直良心。吃了午饭我们就头也不回地走了。

KFC 里面,也有外地游客在抱怨景德镇「哪里都要钱」。话说这种「自来熟」的 Guest 我们这趟在路上已经遇到过不止一次了。
感觉景德镇整个城市就是一个中国不同时期的混杂物。有荒废的厂房(是真的荒废了,不是景点),有老旧的小区,《钢的琴》里面那种。然而对面可能就是一个新修的商场,却特意修成红砖风格,只是从系统窗上看得出来端倪。

走马观花,匆匆一瞥留下的印象,不一定对。
我不是太喜欢这种风格,但它是事实,是现在正在发生且存在的事实。这就足够了。起码它是真实的。

瑞昌

九江下面的一个县级市,主要不是来玩的。

瑞昌老小区

这种老小区,外观都很破旧。其实好好装修一下,房间里面还可以不错。
底商是餐饮,因此卫生状况不好,时不时污水横流。不过我在重庆的老房子也差不多,每个城市都会有自己不那么光鲜亮丽的一面。

瑞昌城隍庙附近

因为不是来游玩的,没怎么拍照片。勉强拿出这一张。
过去的位置上是什么,我已经忘却了。总之图上的这些东西是新修建的,看起来还像模像样。据说是改建了一座「城隍庙」。

另外,市中心也搞了一个「柳湖公园」,晚饭后去遛达了一圈,单从游人数量上,也可以说是不少,但明显都是当地居民,年轻人不多。
也遇到有人在直播,以及大批的老年广场舞团体。这个时代就是如此。

月亮湾

安徽宣城下的泾县辖区内的一个景区。太太从「移动互联网」上看到「皖南川藏线」,有点神往,于是回程的时候安排了这样一个行程。

月亮湾

皖南跟川藏线搭什么界?我对此是一脸问号。其实也就是山路窄风景好适合自驾游的意思,有点「蹭」的感觉。

主要也是玩水,所以我们又是当「看客」了。太太光着脚到小河里走了走,水量是上游控制的,白天大一些,夜里不大。有一些浅滩用来让汽车过河,直接开过去,两边还有游客泼水。

我们在河边的民宿住了一宿,第二天准备继续去六道弯,但看了一下回程的路线太耽搁时间,于是改去了桃花潭。

桃花潭

没错,就是那个桃花潭。「桃花潭水深千尺,不及汪伦送我情」。
只是不知道为什么是在这个角落里?古时候这里很繁华吗?

桃花潭

风光还是不错的,特别是在据说是李白当年喝小酒的小阁楼上。小小的,是我喜欢的风格。视野挺好,看得到下面的渡口有船在来回摆渡。

我们一开始本来是导航到的景区入口,门票又是要大几十。太太从「小红书」上看别人的攻略,说好看的景点都在西岸,汪伦墓什么的。收费的景区是东岸,于是我们上车过河,其他的游客也纷纷拔营。

这个景区感觉有点乱,几股势力把各个景点瓜分了,各自为政。听别的游客说,渡船摆渡一次 60 元,从东岸到西岸要 70 元。我在想这个生意真好做,我也可以做,只要一半价钱就好。

2025-07-25

编程随想:文档很重要

公司的文档水平一向不好,习惯也很不好。在代码中能写个注释,已经算是有好习惯了。在我看来最低限度的 ReleaseNotes,都是有人去推动后才建立起来的制度。大言不惭一下:看起来正式一点的文档,大多出自我的手笔。

前段日子,下了狠心,盯着同事们整理了一篇文档。大约三、四个月的开发内容,最后写了 82 页。我觉得不算多,但可能已经多得让不少人懒得去看了。也正常,文档不是小说,不是让你没事从头翻到尾的。有需要的时候去查上一查,还能有所收获,这就已经算是有价值的文档了。尽管离我认为的「先写文档后编码」还有不少差距,但要是能事后真真正正地补上,也是功德一件。


现在流行 AI,公司上上下下都在搞自己部门的 RAG。这推动了一波文档热潮。AI 没有东西吃,吐出来的东西也就质量不咋地。这样一来,文档就愈发的重要了。

对我而言,这是好事。我倒是喜欢写文档。比起写代码,写文档更接近我的舒适区。何况偶尔我也会塞点「私货」进去,甚至把文档写得像小说一样。反正是内部文档,调皮一下也无妨。将来万一有人看到,也许会有会心一笑。

而且,为了能安心退休,我倒是也愿意把自己的「毕生所学」给「贡献」出来。知识这种东西,有的人会藏私,但我觉得藏着掖着没意思。真正的能力,并不在于别人学不到的东西,而是别人学不会的东西。


有的时候,有些文档会让人觉得很没意思。完全是形式主义,没有什么有价值的内容。对这种文档,我个人是并不喜欢的,但偶尔也必须得去做一做,还好不是太多。

在现在的公司,基本碰不到这种事情。就算有,可能也不是我的事情。但在以前的公司,就会有不少。看起来厚厚的一叠文档,比词典还厚。有没有人看?没有。有没有用?有。你得有它。有就行。

曾经向当时的主管抱怨过,得到的回答是:这些文档的确没有意义,但规定要求必须得有它们。可能是因为如果能沉住气把这些都完成了,那这个项目的总体质量应该也不会差到哪里去。

也就是说,这是甲方的一个测试,一个考验,或者说是一个保证下限的东西。肯把这些无聊的事情搞完的,大概率也就不那么草台班子了。

或许有几分道理,也或许其实是歪理。但不管怎么说,总之当时的我是被说服了,埋下头继续写。


又有的时候,有些文档,真的是必不可少的。

记得以前说过这个观点,可能是在 Google+ 上。我认为如果要自杀,一定要写遗书。悄咪咪地去死也就算了,别给后人留悬案。如果有遗书,家人或许还可以帮你讨个公道,没有遗书的话,很多时候就白死了。反正都是要死了,干嘛不把后事办好一点呢?

图片来自网络

反正车费你都拿不回来。