联邦宇宙历险记

介绍 最近马一龙老板在 Twitter 搞了一系列事情,炒红了「联邦宇宙」这个概念,很多推友都申请了帐号。我一开始是拒绝的,因为我不怎么看好这个东西。分布式服务里用户最多的当属 email,可以说是失败的典型了⸺email 现在的状态可以说和「分布式」一点关系都没有,我认为这是所有分布式服务足够流行以后的必然归宿。但是后来马老板的政策过于光怪陆离,基本上是逼着我开始考虑其他平台了。 「联邦宇宙」这个词听起来神神叨叨的,其实它就是指网上有一票服务器,它们都使用同一个协议互相发消息,这个消息可以是一段文本(micro-blog),可以是图片(类 instagram 服务),也可以是视频(Peertube),而这个协议就是 ActivityPub。如果你注意看这个链接就会发现⋯⋯没错,这是个 W3C recommendation~~ 既然有协议,就要有实现这个协议的软件,其中最流行的当然就是现在烂大街的 Mastodon。本着「流行的一定不是最好的」的原则,我选择了比较小众的 Pleroma⋯⋯我在家里有自己的服务器硬件和环境,其中开了数个虚拟机,所以我直接就装在其中一台虚拟机上了。Pleroma 有官方编译好的二进制版本,可以直接运行,没有其它运行上的依赖,所以架起来十分简单,直接跟着官方文档走就可以了。我的虚拟机用的是 Arch Linux,所以用了 AUR(后来我自己升级到了 2.5)。整个安装过程用 Ansible 自动化,目前为止还比较无痛。 坑,好大一个 但是目前 Pleroma 有个惊天神坑,就是它对于「用户 ID 域名和服务域名不一样」这件事的支持。这要从 WebFinger 说起,WebFinger 的逻辑是这样的:你有个域名,很短很好看,你想用这个域名作为你 ID 的一部分,我们暂且把这个叫做你的公开域名。但是你想挂很多 HTTP 服务,每个服务都有自己的入口,一般这种情况有两种做法, 所有的服务都挂在公开域名下面,但是在不同的路径下,比如 blog 在 /blog 下,Wiki 在 /wiki 下,等等。这种方法有很大的局限性,比如有些服务可能就不支持挂在非根路径下面;如果在根路径下挂服务还要保证 URI 不能重。 在公开域名下开子域名,把服务挂在子域名下,在 HTTP 服务器里给每个子域名开虚拟服务器。这是比较好的做法。这里暂且把这个子域名叫做内部域名。 我家里的网络本来就在一个内部域名下面,所以我肯定是选择第二种方法,更何况 Pleroma 压根就不支持第一种方法。那么问题来了:内部域名很长,我就想用公开域名作为 ID,但是在内部域名下面架服务,怎么办呢?这里就需要一种机制,当外面看到我的 ID,认为我的服务在公开域名下,但是公开域名里有个东西告诉对方,我的服务其实是在内部域名下,让对方去那找。WebFinger 就是这样一种机制。Pleroma 用到的 WebFinger 其实是两个协议: Web Host Metadata(RFC6415),这个协议说的是当外面想访问一个域名下的某个资源的时候,这个域名可以告诉对方关于这个资源的元信息。协议规定支持这个协议的程序在访问一个资源的时候,会先访问 /.well-known/host-meta 这个 URI,如果服务也支持这个协议,应该返回一个 XRD 文档。 WebFinger(RFC7033),这个协议说的是如何在一个服务里找一个人。 Host-meta 在 Pleroma 的语境下,这两个协议的用法是这样的: 每个人有自己的 ID,公开域名是这个 ID 的一部分。这个 ID 就是这个服务里的一个资源。所以如果有人想找到我,这个人应该先访问 host-meta,注意这时外面并不知道内部域名的存在,所以访问的是公开域名下的 /.well-known/host-meta。这时应该返回下面这个 XRD 文档: <?xml version="1.0" encoding="UTF-8"?> <XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0"> <Link rel="lrdd" template="https://internal.domain/.well-known/webfinger?resource={uri}" type="application/xrd+xml" /> </XRD> 简单地说这个文档的意思是你要找人的话就去这里看 WebFinger,其它的事我不管。LRDD link 是另一个 RFC,里面的 {uri} 就是要找的人的 ID(包含公有域名)。 注意这个请求发生在公有域名,所以 Pleroma 是看不到的。所以这时有两种方法: 把这个请求重定向到内部域名,让 Pleroma 处理,这个 Pleroma 是支持的。 这个文档是不用变的,所以可以手动在公有域名的目录里创建这个文件,或者把文件内容直接写在 HTTP 服务器的配置里。 对面在收到这个文档以后应该去访问里面提供的这个 URL,也就是 WebFinger 请求。 WebFinger 这时对面其实就已经知道了服务是在内部域名下。//internal.domain/.well-known/webfinger 这个 URL 完全是 Pleroma 负责的,回应里会包括用户的 profile URL(当然是内部域名)。如果 Pleroma 的版本是 2.4 或更老,这里还有一个二阶神坑。前面说到 host-meta 的回应里有 webfinger 的 URL,其中包括一个 {uri} 变量。对面看到这个以后应该把这个 {uri} 替换为用户的 ID,然后去访问 URL。所以整个 WebFinger URL 是 https://internal.domain/.well-known/webfinger?resource=name@public.domain。但是在 2.4 或更老的版本里,这个 URL 会返回 404,因为 Pleroma 期望对面会把这个 {uri} 替换为使用内部域名的 ID⋯⋯这根本就不对,也没有其它实现会这样干。所以当时我在 Apache proxy 里有几个重写规则来处理这个事: RewriteCond %{REQUEST_URI} "/.well-known/webfinger" RewriteCond %{QUERY_STRING} "resource=acct:(.*)@public.domain" RewriteRule ^ "http://127.0.0.1:1234/.well-known/webfinger?resource=acct:%1@internal.domain**?**" [P,L] RewriteCond %{REQUEST_URI} "/.well-known/webfinger" RewriteCond %{QUERY_STRING} "resource=acct%3A(.*)%40public.domain" RewriteRule ^ "http://127.0.0.1:1234/.well-known/webfinger?resource=acct:%1@internal.domain**?**" [P,L] 在 2.5 版里已经修复了这个 bug。 到此为止,整个查询用户 ID 的流程就完成了,Pleroma 对这个流程的实现是没有问题的。但是我觉得官方根本就没有想明白为什么要来这么一套复杂的逻辑⸺是为了可以让用户声称自己的 ID 就是在公开域名之下,别人看到的 ID 和别人搜索这个用户时使用的 ID 都应该使用公开域名!而你在 Pleroma 和 HTTP 服务器里设置好这一切以后(官方甚至专门有文档教你设置),Pleroma 依然傻了吧唧在网站上显示用户的内部域名 ID,别人用公开域名也找不到你。这样 WebFinger 的意义何在? 解决办法 理论上这个坑是可以填的,我想的一个办法就是把公有域名下的 HTTP 服务器当作 proxy,这样外面看来服务就在公开域名之下,完全看不到内部域名。但是这个方法对我不可行,因为我的公开域名解析到外面的 VPS,内部域名解析到家里,中间的网络延迟不可忽略。当然另一个方法就是抛弃 Pleroma,使用其它实现,比如 Mastodon,其实我一开始是准备架这个的,但是我折腾了一个星期都没架起来,总是有各种错误,弃疗。 Misskey,JavaScript 写的,不考虑。 GoToSocial,有可能会换到这个,但是似乎功能不多,尚处于开发的早期阶段。 除此以外我也只能等官方修了。等我其它玩具项目写完以后可能会自己写一个 ActivityPub 实现。 一些想法 本文最开始说了,我对联邦宇宙这个东西是不看好的。这里的「不看好」并不是说这个东西不好用(虽然现在确实没有很好用⋯⋯),而是我认为所有这种 federated 分布式服务最后都会是两个结局中的一个⸺要么用的人很多,成为事实上的中心化系统;要么没什么人用,成为少数 geek 的玩具。前者的例子是 email,后者的例子⋯⋯是所有其它分布式服务。这个趋势在我看来是必然的,用户多起来以后必然就会有大公司想来分一杯羹,它会搞出一套特别好用(至少是看起来好用)的实现吸引用户。而这些用户里必然只有极少数是真正关心「分布式」这件事的,大部分人都只是想找个方便且稳定的服务,以及别人用什么自己就用什么。大公司的用户多起来以后就要留住用户,这里的方法之一就是以安全为名强行把标准拉高,然后拒绝与不够标准的实现(也就是其它所有实现)互通。 这套伎俩不仅用在了 email 上,还用在另一个受众更广的协议/实现上,那就是 HTTP 和浏览器,具体来说就是拔高 SSL 的标准,并且强行在浏览器里引入证书。 不知道你知道不知道,现在的浏览器都认为如果你的 SSL 证书有效期多于一年,那就是不安全的。Excuse you?? 我自己在家里的网络上,外面又访问不到,给自己开一个有效期十年的证书,不行吗??你算什么东西?告诉我我自己的证书不安全??关你屁事啊??这也太把自己当人了吧??要是真想安全的话你咋不要求每个 session 都新开个证书啊?? 另外在浏览器(和操作系统)里默认自带一套证书这件事,实在是太过虚伪。大家都知道 SSL 证书的信任关系是树状的,最后总会追溯到少数几个根证书上。这里的逻辑是这些根证书是由一些比较「权威」的公司颁发的,其它人如果想要证书的话,要向这些公司(以及他们信任的其它机构)申请,证明你是你,你妈是你妈,你祖宗十八代是你祖宗十八代,这些公司验证过后,就会颁发证书。问题是这种破事你们几个公司之间玩玩就算了,不就是花钱买信任么?不新鲜。你信任他,那是你的事,跟我没关系,但是你把这些证书放到浏览器里,让所有用户默认信任,这算什么道理?我又不认识你们,凭什么信任你们?你们又没给我钱对不对?这也太把自己当人了吧?我认为这里正确的做法是浏览器默认不信任任何证书,但是能访问使用证书的网站(当然要是真想安全的话应该连访问都不让访问),地址栏里放个叹号(说真的,反正又没人 care,放了就放了),让用户选择信任哪些证书。 当然有人说了,这些大公司都是有一定公信力的,他们旗下的证书都是他们验证过的,确实它是它,它妈是它妈,值得信赖。那请问 Let’s Encrypt 是怎么回事?我开 Let’s Encrypt 的时候怎么没人验证我是我我妈是我妈?Let’s Encrypt 的 HTTP 验证本身就是不安全的,怎么不说了?所以就不要假模假式地搞这些事了,何必呢对不对~~ 扯远了,回到分布式服务这件事上。这里的矛盾其实是少数 geek 和大多数小白之间的人民内部矛盾。少数 geek 的需求是分布式,去中心化,这就必然意味着鼓励每个人(或者至少每个小团体)搭建自己的服务,这和其它大部分人的需求是完全相反的。此外还有另一个问题,就是分布式的协议设计和实现都比中心化的要复杂,所以对社区的要求更高。我忘了是在哪里看到的了,Matrix 的设计者和 Signal 的大佬(Jabber 的大佬?)吵架,Signal 大佬说你们这样是不行的,分布式太难做了,你们成功不了。Matrix 大佬回答说这就是为什么我们要做。 当然现在 Matrix 的实现和客户端确实没几个好用的就是了,就像 Fediverse 一样。

2022/12/27
articleCard.readMore

Xenoblade 3 玩后感(剧透)

历时 65 小时,我终于把《印度神剑 3》通关了,目前的时长是 122 小时,总的来说比较失望。剧情和音乐平淡无奇,战斗系统和收集元素比较出彩。这个游戏本质上就是个大号的 fan service,其实根本是没必要存在的,Monolith 可能觉得把前两代的宇宙停掉太可惜了,决定再收割一波。 这里需要说明一下,本文对这个游戏的评价是以《异度之刃》前两代为标准,这是个非常非常非常高的标准。 剧情 这游戏最严重的问题在于剧情非常简单,缺乏深度。整个故事主要就两个矛盾:主角队伍和执政党之间的矛盾,和执政党高层的内部矛盾。这两个矛盾都非常平淡,毫无悬念。主角队伍在游戏中的路径大概是这样的: 走路 队长别开枪,是我 有超能力了 走路 走路 走路 女主死了! 女主没死! 走路 大 boss 哪里跑! 而 N 的剧情其实就仅限于: 大 boss:你想吃蓝药还是红药? N:蓝药!我喜欢蓝色! N:我错了我错了还是红药好! 整个过程中唯一比较让人投入的地方就是女主死了女主没死那里,由于 Mio 是全队唯一有生存压力的人,而在监狱里编剧非常聪明地把 Mio 和其他人分割,这里的悲剧处理很好地调动了观众的情绪。但是这里其实就彰显了这个游戏剧情的根本问题:由于 fan service 的定位,剧情缺乏悲剧。反观二代,反派队伍不仅人多,而且每个人都充满了悲剧。Jinn 就不说了,他其实是二代本质上的主角。像 Malos 这样一开始疯狗一样的人物,到最后也发现他其实是没有自由意志的,整个行为是由 Amalthus 自带的反人类属性驱动,Malos 在二代正传里的故事其实是一个追寻自我的过程;而 Amalthus 的反人类属性也有其悲剧的来源。这三个人构成了二代悲剧的扛把子,在这个基础上发展出了 Haze 和 Mikhail 等一票有头有尾的悲剧人物,整个结构宏大、精妙且充满深度。 而三代里能撑场面的悲剧人物其实就只有 M 一个,N 由于剧情过于老套和可预测只能算半个⋯⋯ 抛开这些,故事本身其实简单地令人发指,主角队伍基本上是一路平步青云杀到大 boss 那里,然后居然就完事了?我当时打到大 boss 的时候还隐隐觉得这游戏应该会转折的吧,大 boss 后面应该还有隐藏的巨 boss 吧?然后发现真的就没有了,Z 真的就是大 boss⋯⋯ 说到 Z,这个人简直就是莫名其妙。这个人的来历据游戏里说就是世界上有很多保守人士,由于这些人过于保守,保守观念过于强大,这些观念化成了人形,诞生了 Z⋯⋯哪尼???(咳咳,这一定不是在暗指某些人,嗯。)除此以外,整个世界里也充满了莫名其妙的「人为」设定,比如人只能活十年什么的,为什么不是九年或者十一年?对比一下,二代像是用第一性原理导出的理论,而三代就像是个充满参数的模型(咳咳超对称咳咳⋯⋯)。 最后我想问一下,结尾两个世界分开以后,City 的人怎么样了⋯⋯? 总结一下,这代由于剧情的限制,我认为它只能作为一个 fan service,无法和一代二代并列成为第三代。但是这里有个很可惜的地方,就算这代剧情有诸多缺点,但其实只要把结尾改一下,它不仅能很好地融入前两代的宇宙,还能把全部三代整合并提升为一整个更大的悲剧故事。这里卖个关子,最后再说。 音乐 《异度之刃》这个系列,我觉得剧情、音乐和系统各自贡献三分之一,少一样只能算勉强及格,少两样就废了。二代基本三样都可以满分,战斗系统繁琐了点,但不差;一代剧情我觉的略有欠缺,但同样不差,其他两样满分;三代刚才说了,剧情已经废了,音乐我觉的能给一半分。但这个问题有点复杂,不能单从好听不好听来考虑。 三代的音乐往大了说,有背叛 JRPG 传统的嫌疑。JRPG 的音乐一般有个特点,就是不仅在游戏里好听,单拿出来听也好听,换句话说就是真・好听。不仅《异度之刃》的一代二代是这样,连《仙剑》系列也这样,这几个游戏的音乐都是我音乐库的永久成员。很多时候 JRPG 的音乐过于好听,以至于会喧宾夺主,这也是游戏媒体在评论 JRPG 的时候一个比较常见的评价。 三代的音乐从「好听」这个角度讲,离前两作有很大的距离。具体说,就是这次的音乐都特别平淡,像电梯音乐。即使是剧情转折处的过场动画配乐,也没有像二代 Counterattack 和《君との未来》那样音乐本身跌宕起伏也在讲故事的曲目。《君との未来》在这方面尤其突出,这个曲子其实就是把二代剧情用音乐又讲了一遍,堪称神曲。一代里这样的曲子不多,但是一代音乐的亮点在地图配乐,以 Eryth Sea 的配乐为代表,旋律美轮美奂,优美到令人发指。而且 Monolith 也知道这点,在三代里数次使用 Eryth Sea 的变奏,连片尾曲都是,这也造成了一个很囧的现象:这代里最好听的音乐是前代音乐⋯⋯ 但是「平淡」和「不好听」,都不算「背叛 JRPG 传统」,我之所以说「背叛」,逻辑在这里:三代的音乐用的是前两代的原班人马,水平摆在那,前两代的音乐加起来有九张 CD 之多,所以这帮人能作出好听的音乐肯定不是巧合,所以真相只有一个⸺这代音乐做成这样是故意的,很显然,这次音乐的重点由音乐性本身转向了功能性,变成了「氛围音乐」。这次的音乐大多旋律比较简单,配器比较轻,明显是想占据一个背景的位置,让你好好享受这次的巨型地图。对比前代,一代里 Colony 9 的小提琴一响起,我就想放下手柄闭眼听音乐了;而二代里的帝国配乐就不用我多说了吧?前两代是买音乐送游戏,这个说法至少对我来说并不夸张。这代里的音乐是对这个特点的一个很强的背离。顺便说一下,这个趋势其实从二代的 Torna DLC 就开始了。 这代音乐的弱音乐性和强功能性,是我觉得它「背叛 JRPG 传统」的地方,但这没什么错,只是方向变了。我不喜欢,但是我算老几? 其它 前面说了这么多不好的地方,这里说点好的。这代的升级和战斗系统是集前两代(包括 Torna)的集大成之作。一代的主要问题是过于简单,人物就那么几个,重点在装备搭配。打架的时候基本就是几个招轮着用,但是一代有个巨大的亮点:主角的时光机。这个机制的存在让这个简单的系统可以登上异度系列的大雅之堂。二代的战斗系统比一代复杂了很多很多,但同时战斗过程也冗长了很多,这个主要归功于新加的一个机制:挂球⋯⋯在 Torna DLC 里 Monolith 终于找到了正确的节奏,让二代的系统手感轻快了起来。这一代的战斗系统集成了前两代的诸多优点。和二代一样,武器和招式来源于英雄,相当于二代里的 blade。很显然 blade 是个极其成功的设定,但是这一代没有吸收二代的一个败笔⸺抽卡,而改成了剧情驱动英雄解锁,顺带着就取消了二代里鸡肋的 common blade,可以说是把这个系统的精华完全继承了过来。连二代里很成功的 Poppy,这代里也拿过来变成了 Triton。节奏上这代没有使用引出二代里挂球机制的元素设定,而使用了一代的简单系统,还解锁了 chain attack 的伤害上限,让 chain attack 比二代更有可玩性,诞生了打 super boss 的时候砍三两下直接开 chain attack 的流派。 总的来说,这代的升级和战斗系统基本可以说是完美了。 前面说剧情的时候我说了很多的黑点,但这些黑点都是主线剧情上的。这代的支线任务剧情比主线好很多,很多配角在连续的支线任务里都发展得非常丰满。比如 Colony 9 的老大 Zeon,在 Colony 9 的种田任务线最后和 Tau 的一姐 Juniper 结成了扶贫对子。这个任务线做完以后的感觉就是,主角的脸上又增添几道皱纹,但是想到两位老大都各自收获了好吃的土豆,这一切努力都是值得的。我觉得这一代要玩剧情的话,就把主线剧情当作一种解锁支线剧情的机制来玩就好了⋯⋯ 最后要把一开始卖的那个关子圆回来。我设想了一个结局,可以很好地把这三作统一成一整个大的悲剧故事,这个结局是这样的: 打完大 boss 以后主角团队,Nia 和 Melia 发现 Z 的死亡解锁了 Origin 的一个不为人所知的机制,可以使得这个世界永久稳定地存在,并且不需要两波人互相打这样的弱智设定,但是代价是主角团队必须死(或者是 Nia 和 Melia 必须死,不重要)。为了保护来之不易的革命成果,主角团队毅然决定牺牲自己。一阵操作之后,Nia 和 Melia 启动了这个机制,世界得救了。 如果你觉得这就是我说的悲剧,那就错了,悲剧在后面。 之后这个世界就这样运行了几百年,当然世界上的人就都是 City 的后代了。这几百年里科技高速发展,人们生活水平飞速提高,农民们用上了彩色电视机、缝纫机、自行车、手表⋯⋯太空上甚至建起了空间站。后来在这个世界上诞生了一个最杰出的科学家,叫 Klaus⋯⋯

2022/8/22
articleCard.readMore

关于一些学术软件的八卦

老婆在某大学里管超算,收到一个 ticket 说有人有个 Python + C 的程序出错,段错误,让我看看怎么修。我折腾了一个晚上,发现是 Python 会默认 C 函数的返回值类型是 int,但是那个函数的返回值是个指针,而且在 Python 里拿到返回值以后会传给另一个 C 函数,在我们测试的机器上(超算和我自己的机器)Python 会把那个返回值截断再补上,不段错误就怪了。不过这个修起来很简单,在 Python 里声明返回值类型是指针就好了。但是我修好了以后发现这破程序还有别的恶性 bug,比如 use after free⋯⋯ 于是我们让他找作者修,作者是个康奈尔的教授。他说之前找过了,作者坚持说程序是对的,而且他在其他机器上都能跑。当时我就呵呵了,这也太把自己当人了。如果我是用户大概直接 email 就骂过去了⋯⋯ 学术圈这样的破程序挺多的,我一直在想为什么这些人就不能好好地写个好程序。我的一个感觉就是除了物理以外其他科都不喜欢搞大 collaboration,都是各干个各的。我用过的物理圈的牛逼程序大多都是 collaboration 搞的,比如 CERN 的 ROOT 和 USQCD 的 Chroma,当然个人写的也有,这些人最后都转码了嗯。 另一个想法是为什么不好好地开源一下让社区写,也相当于搞 collaboration 了,问老婆,老婆说搞不起来,因为这些程序一般没什么人用⋯⋯ 关于 collaboration,我又想到了以前在囧乎上和别人的讨论,为什么像生物这样的学科只满足于 p=0.05,做实验就只用几只几十只小白鼠,为什么文章里 error bar 都碰上了还大言不惭地说 significant。比如我之前随便看的一篇关于 Covid 的文章里面有这个图: Figure 1. 这要是都能算 Significant 天下人都能水 PRL 了……我严重怀疑这人说的 significant 意思是中心值相差多于一倍,他标 significant 的那几组数据都符合,没标的都不符合……Error bar 什么的可能就是个装饰。 有人评论说小白鼠很贵的,我问那为什么不搞 collaboration,有几个人回复说想搞到基因满足某些条件的小白鼠很贵很难而且很难维护什么的。最后我懒得再打字了就说好吧我也不了解情况大概确实很难吧,但其实我白眼都翻到天上去了,难个屁啊,再难能有 LHC 的百分之一难么⋯⋯人家 CERN 几百个人做十年,最后没有五个 sigma 的信号都不敢发文章⋯⋯ 所以真的,做事要认真,不然就别占着茅坑不拉屎了,给别人腾腾地儿。 在分子动力学界,有个著名的软件叫 Gaussian,性能特别好,但是是个商业软件,还很贵。不同于其他很多 MD 界的学术软件,这玩意是个「现代」的软件,有文档、安装包、论坛和技术支持。但是这玩意在圈里名声很差,因为这程序最早是一个叫 John Pople 的有志大叔写的自由软件,成型以后让合伙人窃取了,成立了公司也闭源了。这公司跟我国一样,骂不得。你说它不好它就会把你拉到黑名单里让你用不了,所以也有很多人用着其他更奇葩的软件,比如 CHARMM, GROMACS 和 NAMD 什么的。CHARMM 是 Fortran 的,后面两个是 C++ 的,这些功能都 不如 Gaussian 多,所以有时就需要你自己写插件。比如我老婆之前需要撸一个特殊的力场,研究了半天 GROMACS 的 API 都没整明白,我也没时间帮她写,所以最后用了她老板的祖传 Fortran 插件⋯⋯总之,这些科研工作者对 Gaussian 敢怒不敢言。 后来 John Pople 受不了了,从 Gaussian 跑路出来又开始了一个新的 MD 软件 Q-Chem。老婆跟我说 Q-Chem 最初也是自由的,后来又让人窃取了,但是这个就无从考证了。 这件事告诉我们学术圈懂软件工程的人真不怎么多(因为懂的都转码了),不然那些自由软件没什么道理功能跟不上,毕竟数学上都是推好的的,写程序实现一下就好了⋯⋯CHARMM 和 GROMACS 的文档我也看过,感觉还挺全的,各种基础库和结构也都做的不错,扩展起来不难。 说到 CERN,可能很多在圈外的人不知道 CERN 在计算上有多牛逼,其实很多物理圈的也不知道(比如我以前)。我读博的最后一年 LHCb 的人来我校做了个报告,扯了很多 penta-quark 啦 dark matter 啦我都没在意,但他后来讲数据处理的时候我都震精了⋯⋯他说他们有一套自己设计的软硬件用来实时采集和处理 TB/s 级别的实验数据,有专门的超算做实时的 preliminary 分析,实时出结果,而且分析还是带 machine learning 的。我当时作为一个计算狗感觉就是无地自容⋯⋯ 所以我转码了。

2022/3/23
articleCard.readMore

记一件有意义的事

水果 CSAM 识别 最近水果出了个事,叫做 CSAM,Child Sexual Abuse Material,简单地说就是儿童色情检测。这是 iOS 15 将要加入的「新」功能(待会儿要说到为什么「新」是加引号的)。消息一开始是泄露出来的,从泄露出来的消息来看,这个系统是这样的: 对于手机里的照片,计算某种 hash,并上传 hash,iCloud 和本地照片都有。 对于匹配的照片进行人工审核。 这年头上传 hash 这件事基本就不是事,涉及到隐私的部分在「人工审核」这里。人工审核肯定不是审核 hash 了,必然要上传照片本身(当然水果并没有说,我猜的)。那么水果凭什么偷偷上传你的照片本片呢?肯定是要在用户协议里偷偷加东西了。 但是!!! 这件事最可怕的点不在这,而是 水果把所有人都当成潜在的儿童色情罪犯。 如果我国要求水果扫描用户的政治性图片并上报怎么办? 后来水果发布了一个 FAQ,并且某高管接受了一个采访,透露出了另外一些信息: 匹配 hash 的过程发生在本地,hash 不上传。而且这个匹配是「非常准确」的。 只匹配 iCloud 上的照片,用户可以通过关闭 iCloud Photo 来 opt-out。 在孩子的 iMessage 里自动识别 18+ 内容。这个家长需要 opt-in。这个和上面那个儿童色情匹配无关,是个独立的功能。 所以至少这些功能是可以关闭的。但是这点很奇怪⋯⋯既然匹配是在本地,为什么不同时也匹配本地非 iCloud 照片?非 iCloud 的儿童色情就不是儿童色情了?水果不关心儿童安全么? 为什么允许 opt-out?Opt-out 的儿童色情就不是儿童色情了?水果不关心儿童安全么?我觉得大概的确是这样,水果只关心自己的云里有没有 CASM,用户本地的照片不是水果的责任。 另外在采访里,记者连续问了三个同样的问题,就是如果政府要求水果识别除儿童色情以外的照片,水果怎么办。水果在第三个问题的时候才稍微沾点边地回答了这个问题:这个功能只在美国启用,在美国的法律框架下政府很难强迫水果加入识别合法内容的功能。那么如果我国政府要求水果加入其他识别功能呢?水果的回答是这样的: The hash list is built into the operating system, we have one global operating system and don’t have the ability to target updates to individual users and so hash lists will be shared by all users when the system is enabled. 简单地说就是「我们的操作系统是全球统一的,所以我们无法单独为一群人加入某个功能」。 哪尼???你刚刚不是才说了识别儿童色情这个功能只在美国有么???你可以在全球加入这个功能然后只在某国开启啊?????所以实际上水果是承认了他们会在政府的要求下加入其他识别功能。 不过我国人民也不用过于担心,我国有云上贵州,不需要这个功能。 Did someone say “hash”? 既然是 hash,那必然就有碰撞。水果官方说了,每年发生碰撞的概率大概是「万亿分之一」。所以自然发生的碰撞几乎是不可能了?那么有没有可能人工构造碰撞呢? 有大佬发现,在 iOS 14 里其实已经内置了这个匹配功能,并且能导出模型。使用这个模型,另外一些大佬很容易的就构造出了碰撞;还有些大佬构造出的图,内容就是这张图的 hash。所以人工构造碰撞不仅可能,而且似乎很简单。这有没有可能是一个攻击的方向呢?我作为安全小白就不知道了。假设有人构造了一个看似无辜的碰撞图,比如看起来是个酷炫的壁纸,发到网上让人下载,会在很多人的手机里触发 CSAM。这种「自然发生」的人工碰撞,概率肯定是要大于万亿分之一的。 另外真・自然发生碰撞概率是不是真的这么低呢?显然这个概率很难估计,但是有人使用导出的模型扫描了 ImageNet,已经发现了两对碰撞(互相碰撞,不是和 CSAM 碰撞)。 「新」功能? CSAM 这件事本来到这里就没什么好说的了,但是无独有偶,水果正在和 Epic 进行的官司竟然透露出了更多的信息。在这个官司公开的文件中,有水果高管在内部邮件里说了这么几句: The spotlight at Facebook etc. is all on trust and safety (fake accounts, etc). In privacy, they suck. Our priorities are the inverse. Which is why we are the greatest platform for distributing child porn, etc. 哪尼??水果是最大的儿童色情流通平台???当然这倒不是特别值得惊讶,就算水果不是「最大的」,也肯定是「很大的」,毕竟水果有那么多用户。关键是水果怎么知道自己是最大的儿童色情流通平台?答案当然是:水果扫描用户信息了。的确,在这个邮件公开以后,水果不得不承认,他们从 2019 年就开始扫描用户的邮件中的 CSAM 了。 长期以来水果的卖点一直都是隐私。水果从自研芯片(iPhone 4)开始,基本上所有的技能点都是围绕这个主题展开的。Security enclave,Touch/Face ID,differential privacy 等等这些与隐私密切相关并且水果大书特书的特性,其实归根结底起点都是自研芯片。我们都知道在大概 iPhone 5s 和 iPhone 6 的时候,水果设备的安全性得到了一次巨大的提升。从此以后,FBI 就很难从锁着的 iPhone 里提取数据了,关注这点的同学可能还记得 2016 年 FBI 因为无法破解一个 iPhone,要求水果给操作系统添加后门的事,我当时还在囧乎写了一篇文章。水果甚至还在 Black Hat 2016 上做了个报告,来显摆 iPhone 和 iCloud 的安全架构。 但是 CSAM 这件事基本上就相当于重置了水果的这些努力。如果水果也会扫猫用户的照片甚至邮件,Google 也会扫描(其他厂商很早就开始扫描 CSAM 了),那水果在隐私方面还有什么优势呢? 一个违背祖宗的决定 大家都知道水果是一个在用户体验设计上高度自负的厂商,同时他们只为主流市场设计体验。这样就形成了一个局面:当水果认定自己的设计对于主流是最佳体验以后,他们就会非常的固执,并且拒绝为非主流用户提供选项,而主流用户确实也非常买账。但是对我来说有个问题⸺我不是主流用户⋯⋯ 在 iPhone 上,想从电脑上传音乐文件只能使用 iTunes,这是一个特别古老的设定,古老到乔帮主刚回到水果,发布 iPod 的时代。为什么水果不更新这个古老的设定呢?因为主流用户都去用 streaming 服务了,没有人再想从电脑上上传音乐。但是我想。我有 74 GB 的音乐文件,并且我只听这些音乐;实践证明,只要是我音乐库以外的音乐,我一定不爱听,这 74 GB 就是全宇宙仅有的我爱听的音乐。我为什么还要用 streaming 服务呢? 在 iPhone 上,如果用户想要运行自己写的 app,就必须每年交 $100 成为开发者,否则自己写的程序只能在 iPhone 上运行几天。这是一个安全设定,现在认为对于主流用户,可以随心所欲地运行任何程序是巨大的安全漏洞;事实也确实如此,想想我国有多少个人电脑上装着 360 和百度全家桶,再回忆一下上次的 XcodeGhost。但是我既不是主流用户也不是开发者,我是那种 95% 的时间很正常,剩下 5% 的时间会写点自用 app 的奇怪用户,我才不会为了那 5% 而交 $100 的年费。 水果去掉了 iPhone 上的耳机口,因为水果认为 iPhone 的终极体验就是无线使用 AirPods, it just works™。AirPods 音质不好?主流用户不会在意的,毕竟水果耳塞可能就是他们这辈子听过的音质最好的设备。但是我在意,我买 UM3X 回来不是当摆设的。 因为这些原因,我一直在考虑换成安卓手机,但基本一直是观望。这次 CSAM 事件之后,我终于认真考虑更换了,毕竟就像之前说的,至少在隐私上水果已经没什么优势了。安卓手机的选择很多,我看了一圈评测,最终选中了全宇宙最便宜的 Pixel 4a。 Figure 1. 换鸡辣~~ 违背祖宗后的体验 到目前为止,新手机已经用了两个月,最大的感觉就是在 iOS 上自带的程序在安卓这边都是第三方的。比如听音乐的程序,如果你像我一样只听本地存储的音乐,在 iOS 上基本就只能使用自带的音乐程序,而在安卓这边有很多的选择。这其中根本的原因是 iOS 不开放文件系统,用户没法自由地上传音乐文件。而在安卓上上传音乐,又比用 iTunes 上传方便很多。除了可以自由地用目录组织文件以外,还可以直接用 m3u8 播放列表,而不用依赖 iTunes 里的弱智播放列表管理。至于像 iPhone 只能和一台电脑同步音乐这样莫名其妙的古老设定,在安卓上当然也是不存在的。 关于音乐,在水果这边还有个奇妙的设定:我不知道你知道不知道,iPhone 其实原生支持 FLAC 编码的音乐!如果你在 Files 或者 iCloud Drive 里放个 FLAC 文件,是可以直接播放的。但!是!iTunes 里不支持导入 FLAC 音乐,所以 iOS 自带的音乐播放器依然不能播放 FLAC 文件⋯⋯由于 iTune 支持的音乐格式太少,我的音乐库有个特别弱智的 hack。在我家里的服务器上,有个 music 目录,里面按照专辑存放着所有的音乐: % ls -1 | sort -R | head -n 4 André Cluytens - 1958 [Shostakovich -- Piano Concertos; 3 Fantastic Dances; 5 Preludes & Fugues, Op. 87]/ Itzhak Perlman - 1977 [Goldmark Violin Concerto - Sarasate Zigeunerweisen]/ Metallica - 1991 [Metallica]/ Ginger Baker Trio - 1994 [Going Back Home]/ 由于这些音乐的来源不同,文件是不同的格式,比如在 iTunes 上买的是 AAC,在 HDTracks 上买的是 FLAC,本科和高中就一直流传下来祖传音乐是 MP3。除此以外还有少量的 WavPack 等奇葩编码。但是如果我把这个 music 目录拖到 iTunes 里,是不能导入全部音乐的,因为 iTunes 只支持 AAC 和 MP3。这个问题最简单的解决方法当然是把不支持的文件全都转成 AAC,我可以在专辑目录里再开两个目录,叫 “flac” 和 “aac”,分别放两种编码的版本。这样如果我把 music 目录拖到 iTunes 里,就可以一键导入所有音乐了。 但是这个方法有个 bug,就是在其他音乐播放器上(比如 Foobar 2000),把 music 拖进去会出现重复的音乐⋯⋯我的解决办法是在 music 目录外面开一个 music_copy 目录,把转码的版本全都放到这个目录里,music 目录保留原始版本。这样如果一个专辑本来就是 AAC 或者 MP3,就只会存在 music 目录里;如果是 FLAC,就会在 music 里存放 FLAC 版,在 music_copy 里存放 AAC 版。如果我需要导入到 iTunes 里,就把这两个目录一起拖进去,而如果是其他的播放器,就只需要拖 music 目录。 没错,这一切都是因为我要迁就垃圾 iTunes。 安卓这边自然没有这个问题,像 FLAC, Vorbis 这些自由的编码都是支持的,甚至像 Opus 这样的最新最好的编码也没问题,不要问我为什么会有 Opus 编码的音乐⋯⋯ 我常用的其它程序在安卓大多都有对应, 比如 OTP Auth,这是一个个人开发的 OTP 软件,而且是自由的,基本上在 iOS 里是最好用的了,强烈推荐。在安卓里我换成了 Aegis,同样也是自由软件,重要的是这个 app 和 OTP Auth 一样,可以直接设置 OTP 的 hash 算法,位数等等。 Twitter 客户端用了 Twidere,没什么大毛病,有些行为和我惯用的 Twitterrific 不一样,但是习惯就好了。 我同时用很多聊天软件,包括 iMessage。忽悠里面仅有的几个联系人换成了 Signal,但是不得不说,Signal bug 真的多⋯⋯干啥都有 bug⋯⋯ 天气软件是我没想到的,在安卓上我居然没找到能和 iOS 自带天气软件一样支持多个城市同时还不难看的,目前在用 OpenWeather。 另一个没找到合适 app 的门类是计算器,不过倒是不怎么奇怪,毕竟 iOS 上的 PCalc 太优秀了,我的需求也比较奇葩(RPN + 好看 + 非模拟真・计算器)。目前正在自己写⋯⋯ 对于我来说,水果这边最不可替代的其实是果表,目前在安卓平台还没有找到合适的对应。我把十多年前买的 G-Shock GW2500B 又挖了出来,依然运行良好。

2021/10/27
articleCard.readMore

组装键盘记

自从忍痛流浪购买了全宇宙最贵的薄膜键盘以后,我就发现了一个一般人我不告诉他的秘密:樱桃的键盘开关手感真的挺烂的。但是这个键盘又不像樱桃一样能随便换键帽,如果我想要好的手感,同时还想换花里胡哨的键帽该怎么办呢?答案当然是自己 DIY 一个比全宇宙最贵的薄膜键盘还要贵的机械键盘,这就是键盘侠们经常挂在嘴边的定制键盘。 初期调研 一说到定制,键盘侠们的第一反应肯定是选择很多,琳琅满目。但是实际上在考虑到个人需求以后,往往选择就不那么多,甚至没有了。比如我需要有数字小键盘,这基本上已经把 90% 的选择刷掉了。因为市场上的定制键盘绝大部分都是所谓的「60%」构型,就是只有主键区的那六十几个键。剩下的那小部分里的大部分也都是 tenkeyless,和 70% 等等,都是没有数字小键盘的。想要小键盘,就只有两种构型:全尺寸和 96 键。全尺寸我觉得还是太宽了,如果在旁边放上鼠标的话,要么鼠标离得太远,要么主键区不在中央,都不好。所以最后就剩下 96 键一种构型了。这个构型一般人可能听都没有听说过,因为批量生产的成品键盘里据我所知就只有一个品牌的一个型号使用了这个构型,后面我会再次提到。一般的定制 96 键会使用下图这个键位。 可以看到这种键位保留了完整的数字小键盘,同时又有完整的方向键和 home, end 等按键,几乎覆盖了全尺寸键盘的所有键。但是明明这个键盘的按键比标准的 104 键要少啊,都少了那些键呢?答案是右边的 alt 和 super,加上 prtsc, scroll lock 和 pause。Alt super 什么的就不说了,scroll lock 和 pause,没什么用的,去掉也不可惜吧? 当然可惜了!像这样完全没有用的键,才是设定快捷键的最佳选择,因为几乎不可能冲突!在我的 Windows 游戏电脑上,这两个按键我绑定了 OBS 录像和广播功能。有人说了,绑定组合键不行么,比如 ctrl+f12 什么的?不行,尤其是在游戏电脑上。因为很多游戏里 ctrl alt shift 这些键都不是 modifier,而是独立起作用的(比如按 ctrl 切换下蹲/站立),绑定 ctrl+f12 会与这些功能冲突(不要问我是怎么知道的)。像 scroll lock 这种操作系统和应用程序肯定不会绑定任何功能的按键屈指可数,尤其宝贵。 除了缺少这些键以外,这个键位还有几个缺点,比如 home end 这些键不是按照标准键位排列,需要时间习惯;再比如右 shift 和小键盘的零都比全尺寸的要短。这些都不是什么大问题,但是如果能解决的话还是会方便很多。有没有不存在这些缺点,同时又使用 96 键构型的「完美键盘」呢?听起来似乎不太可能,但是确实是有。这就要说回我之前提到的唯一一种量产 96 键键盘:Cooler Master Masterkeys Pro M。 Figure 1. Cooler Master Masterkeys Pro M,键位是这个键盘的主要卖点之一。 当然这个键盘还是比之前的 96 键少了几个键,但我觉得精神是一样的。而且如果你仔细看数字键区,会发现这个键盘不仅有 home end 等键,还有 prtsc, scroll lock 和 pause,怎么做到的?答案在那个 num lock 上。Num lock 激活的时候,数字键区就是正常的数字键,但是在 num lock 关闭时整个数字键区就会变成导航区,这样就保留了标准键盘的所有按键。 ⋯⋯ ⋯⋯ 咦?似乎有什么地方不对?标准键盘有 104 个键啊!而且也有 num lock 用来切换数字键区。这个 90+ 键的键盘不可能有标准键盘的所有键?! 你如果有这个想法的话,也没有错。这里矛盾的地方在于标准的 num lock(以及 caps lock)是一个特殊的键。在标准键盘中,num lock 用来切换数字键和方向键。这个行为其实不是键盘本身定义的,而是操作系统定义的。这也就是为什么你可以在操作系统里用软件切换 num lock。换句话说,不管 num lock 打开还是关闭,键盘硬件输出的键码都是一样的,操作系统会根据 num lock 的状态转换键码。转换后的数字键和主键区上方那一排数字的作用是一样的,但是在操作系统里,数字键区的数字键码其实是独立的一组,和主键区的数字键码不一样;方向键也同理。Cooler Master 的键盘少掉的就是这些方向键。然而缺少这些方向键并不可惜,尽管它们是有功能的,但是与导航区的方向键重复;而且正是由于有功能,所以不能绑快捷键,成了鸡肋。这里也可以看出,这个键盘的 num lock 只是上面印了这几个字,它的功能不可能是标准的 num lock 功能,因为数字键和方向键的对应并不由键盘决定,这个 num lock 其实是定制键盘里常用的切换键层功能。 明白了这些以后,我们也能设计出类似的键位用在 96 键的定制键盘上,以下是我设计的键位。 按下右上角的 TG1 键以后数字小键盘会变成这样: 而那个 num lock 键是真正的 num lock,这样如果由于某种原因,操作系统关闭了 num lock,我可以再把它激活。除此以外,我这个布局还有个彩蛋:这个键盘有 F13 和 F14!是的,相比标准 104 键键盘,这个布局不仅没有少键,反而还多出了两个键。这两个键虽然现在很少见,但是在以前的老键盘的上还是会经常出现的,有些老键盘甚至有 24 个 F 键。直到现在操作系统也都支持这些键。 既然有了这个布局,准备工作就差不多了,剩下的就是选配件。对于外壳和电路,我选了当时唯一一种有现货的型号:XD96。幸运的是,虽然官网上没有明确说明,这个型号是支持 QMK 的,可以很容易地实现我设计的键位。键帽选择了 EnjoyPBT 的 GrayScale。开关的选择我纠结了很长时间,还买了几个试键器,最后锁定了 Zealios 65g。在选择开关的过程中我还发现了一件事,不知道是不是由于我小时候用过了很长时间的老式键盘(薄膜键盘流行之前的键盘),我对段落感的要求极高(或者应该说极怪)。在我试过的十几种开关里,就只有 Zealios 和凯华的 click bar 开关在我看来算是有段落感。像很多人交口称赞的 Outemu 天蓝和各种仿樱桃褐色,我按起来感觉就像有毛病的线性开关⋯⋯凯华的 click bar 我觉得手感比 Zealios 还要更好些,但是真的太吵了,不得已选择了后者。 组装 啊,XD96⋯⋯组装过程真是一言难尽。这个键盘的设计有个不大不小的坑,就是支撑开关的那个铝板左右两边没有螺丝,所以装好以后如果使劲按左右两边的键,整个支撑板和电路板结构会变形一小点。当然一般打字时是感觉不出来的,但是作为一个比全宇宙最贵的薄膜键盘还贵的定制键盘,各方面都要做到完美才对。这个问题有 Reddit 用户给出了解决方案,就是自己 3D 打印两个支撑的结构放在外壳和支撑板中间。我试了一下效果还可以。 除此以外,这个键盘还有个惊天神坑,见下图。 Figure 2. ??????????? 谁能告诉我这是怎么设计出来的?嗯?如果不是设计出来的,难道是加工时的公差?有人见过不到一厘米的开孔有几毫米的公差么?有么?这里我不想吐槽国产货怎么怎么样,只说一句:都是国产货,这水平还不如当年的白沟。 当然这个巨坑我最终还是填上了。我买了一套锉刀,把这个开口扩大了大概 3 毫米⋯⋯ Figure 3. 扩大后的 USB 口 组装这个键盘的倒数第二步,是把玻璃背板装到外壳上,并用螺丝固定。那个螺丝也是我见过的最烂的没有之一。在拧的过程中十字坑就已经花了⋯⋯但是写到这里我也不想再说什么更多的了,就这水平,爱咋咋地吧。 最后一步是装键帽,也有坑!PBT 的键帽在加工过程中会变形,所以有时一些长键出厂时是弯曲的。我手里的这套 EPBT 键帽,所有 1.5u 或更长的键帽都是弯的,装上以后按下弹不起来。这个问题我以前早有耳闻,只是没想到会这么严重。解决办法也是有的,就是把键帽放到开水里加热一下,然后拿出来往反方向掰,直到冷却。不过不要以为 PBT 在开水里一煮就软了,可以随便掰;PBT 好歹是比 ABS 还硬的塑料,是有尊严的。我掰了一晚上,基本上把所有长键都纠正了,除了数字键区的加号。因为那是我最后掰的一个,手上实在没劲了⋯⋯所有键帽都装好以后,组装就算完成了。 刷固件 QMK 的固件刷起来特别方便,只要在 Configurator 里设置好键位,点一下 Compile,就可以直接下载编译好的固件了。不过我还加了一个小功能,就是把 num lock 写死成打开的状态。在 keymap.c 里我有这么几行: void led_set_keymap(uint8_t usb_led) { if(!(usb_led & (1<<USB_LED_NUM_LOCK))) { register_code(KC_NUMLOCK); unregister_code(KC_NUMLOCK); } } 我的键位后来还修改了几次,最终版本在这里。 总结及未来展望? 到这里这个键盘就算真正完成了,虽然过程比较坎坷,最终效果还是不错的。 但是生命在于折腾,俗话说得好,树折腾死,人折腾活。这个键盘我已经用了大概八个月,还记得我之前说那些长键都是我一个个掰过来的么?有些键已经开始偷偷地回弹了,虽然目前还不影响使用,但我觉得是时候考虑换键帽了。目前有两个候选,一是某种 MT3 的键帽,比如 MT3 /dev/tty。但是这种键帽有两个问题, 凹陷的形状是球形的,可能打游戏不方便,不确定。 目前只有 Drop 上有货。但是 Drop 的版本没有平的底排键,所以 ctrl alt 这些键用大拇指按的话会硌手,这个问题对于球形凹陷的键帽尤其严重。 另一个选择是等一波合适的 GMK,传说中 GMK 是质量最好的 ABS 键帽。一般来说 ABS 的键帽用不了几个月就会开始打油,但是好的 ABS 可以坚持更长时间。我在办公室用的 Type Heaven 就是 ABS 的键帽,我连续用了快四年,只在少数一些键上有非常轻微的打油。但是 GMK 每种一般就只产一次,所以只能等下一波合适的。 除此以外这个键盘也没什么其他好折腾的了。如果有机会的话,我的下一个定制键盘大概就会是支持热插拔的了,可能会试一下凯华的 click bar 开关,毕竟吵死人不偿命,吵死一个是一个。

2020/7/23
articleCard.readMore

Raspberry Pi 2 模拟 Switch 手柄

最近看到了一个叫 joycontrol 的玩意,可以通过蓝牙模拟 Switch 手柄。原则上这个东西可以装在任何 Linux 机器上,README 里也说在 Ubuntu 和 Raspberry Pi 4 上测试过,但是我手上只有一个 Raspberry Pi 2B+,不自带蓝牙,我只好单独买了个 USB 蓝牙适配器。注意很多蓝牙适配器是不支持 Linux 的(比如我一开始看到的 TP-Link UB400),买的时候还是要看一下。 我的树莓派上装的是官方推荐的 Raspbian,在安装 joycontrol 的过程中踩了很多坑,最终基本都可以归结到一个问题,就是软件仓库里只有 Python 3.5,而 joycontrol 用到了一些 3.6 之后才有的特性,比如 f-string(难道我会告诉你我是昨天才知道 Python 有 f-string 的这个秘密么)。当然大便有很多 backport 仓库,但是我懒得折腾了,决定手动编译 Python 3.8。在编译之前,还需要安装这些包: # apt install ffi-dev libdbus-1-dev libdbus-glib-1-dev libbluetooth-dev libhidapi-hidraw0 libhidapi-libusb0 其中 libbluetooth-dev 是 Python 支持蓝牙的头文件,没有这个 Python 就不能支持蓝牙的 socket;FFI 和 dbus 是后面编译 dbus-python 需要;libhid(好像)是运行 joycontrol 需要。 有了这些以后,剩下的就简单了。按照正常工序编译安装最新版 Python,并使用其中的 pip 安装 dbus-python。最后 clone joycontrol 的仓库,按照 README 里的方法安装测试就好。 整个安装过程总结成一句话就是:滚动升级大法好。

2020/4/25
articleCard.readMore

装 Mac 虚拟机

最近想整理一下我的各种配置文件,需要撸一个 Mac 虚拟机做测试。于是打开上古神器 VirtualBox。 要装系统首先要有安装盘。进入 Mac App Store,找到最新版的 macOS,并猛击“Get”。这样会下载一个安装系统的 app。正常安装的话你只需要运行这个 app 就可以了,我们要装虚拟机显然是不可能让 UEFI 运行这个 app 的,所以需要想办法做出个安装盘来引导。和所有 Mac app 一样,这个安装 app 其实是个伪装的目录。进入这个目录,并且进入 Contents/SharedSupport,几个 DMG 文件映入眼帘。这里的 BaseSystem.dmg 就是安装时的临时系统,是可以引导的,但是真正安装的内容在 InstallESD.dmg 里,真正可用的镜像文件应该是这两个文件组合起来。这个 app 的 Contents/Resources 里其实提供了制作镜像的工具 createinstallmedia,可以直接用。 首先创建一个空的镜像并 mount, hdiutil create -o install.dmg -size 8g -layout SPUD -fs HFS+J hdiutil attach install.dmg -noverify -mountpoint /Volumes/install 在镜像里写入安装盘,程序会自动重新 mount 写好的镜像, sudo "/Applications/Install macOS Mojave/Contents/Resources/createinstallmedia" --volume /Volumes/install hdiutil detach "/Volumes/Install macOS Mojave" 把写好的镜像文件转成 ISO。如果你在 macOS 里跑 VirtualBox 的话,是可以直接用 DMG 镜像的,原则上不需要这步,不过我没试过。 hdiutil convert install.dmg -format UDTO -o install.cdr mv install.{cdr,iso} 接下来就可以创建虚拟机了,macOS 好像不支持 USB 1 的设备,所以要先装 VirtualBox 的 host extension pack。新建一个虚拟机,VRAM 要拉到头 128MB。同时新建一坨硬盘镜像文件(注意 Mojave 是小于 22GB 不给装⋯⋯)。在 Ports → USB 那里选 USB 3.0 controller,其他应该默认就好。 众所周知,macOS 是没法装在随便一台 x86 机器上,它得看到是个 Mac 机器才给装。我大 Mac 自有国情在,我大 Mac 的软件是开放的,任何硬件只要遵守我大 Mac 的法律法规都可以装⋯⋯(并没有。)所以有些额外的设置需要做,我直接抄的这里, vmname="macos" resolution="1440x900" # valid serial required for iCloud, iMessage. Structure: PPPYWWUUUMMM # - Plant, Year, Week, Unique identifier, Model Whether the serial is # valid depends on the device name and board, below: serialnumber="NOTAVALIDSN0" devicename="MacBookPro11,3" # personalize to match serial if desired boardid="Mac-2BD1B31983FE1663" VBoxManage setextradata "${vmname}" "VBoxInternal/Devices/efi/0/Config/DmiSystemProduct" "${devicename}" VBoxManage setextradata "${vmname}" "VBoxInternal/Devices/efi/0/Config/DmiSystemVersion" "1.0" VBoxManage setextradata "${vmname}" "VBoxInternal/Devices/efi/0/Config/DmiBoardProduct" "${boardid}" VBoxManage setextradata "${vmname}" "VBoxInternal/Devices/smc/0/Config/DeviceKey" "ourhardworkbythesewordsguardedpleasedontsteal(c)AppleComputerInc" VBoxManage setextradata "${vmname}" "VBoxInternal/Devices/smc/0/Config/GetKeyFromRealSMC" 1 VBoxManage setextradata "${vmname}" "VBoxInternal2/EfiGraphicsResolution" "${resolution}" VBoxManage setextradata "${vmname}" "VBoxInternal/Devices/efi/0/Config/DmiSystemSerial" "${serialnumber}" VBoxManage modifyvm "${vmname}" --cpuidset 00000001 000106e5 00100800 0098e3fd bfebfbff 这样就把这台虚拟机伪装成了一台 Mac⋯⋯ 现在终于可以开始装系统了。把刚写好的安装盘塞到虚拟机里,开机,引导后会出现熟悉的安装界面。进入 Disk Utility,把硬盘 erase 成一个 APFS 盘。接着退出 Disk Utility,选择安装,并使用一路回车法。安装程序会显示还剩几分钟(一般是个很短的时间,我这里三分钟),并开始滚进度条。这时它其实是在把 base system 和数据写到硬盘里,并试图在硬盘上做引导(重点是「试图」)。过一会儿就会屏幕一黑,重启了。很神奇的是,重启以后你如果不管它,它就会再次跑到光盘上的安装程序那里,并让你大侠重新来过。实际上如果是个真实机器的话,硬盘引导应该已经做好,这次重启会直接从硬盘引导并继续安装的。我不知道这是 VirtualBox 还是水果的 bug,这里引导并没有做好,需要我们手动引导。 直接关机,(其实刚才重启的时候就可以直接关了。)并弹出安装光盘。到这里下载一个 UEFI 的 APFS 驱动,塞到光盘里,待会儿你就知道干什么用了。再次开机,系统会跑到这样的一个界面里: 这就是传说中的 UEFI shell,如果你对这种突如其来像素风感到恐惧,不要慌,这玩意和以前的 GRUB shell 是一个档次的东西(好像并没有什么卵用⋯⋯)。这里显示的 FS 几几几是识别出来的文件系统,相当于已经 mount 好的分区,可以直接看文件的那种;而 BLK 几几几就是没识别出文件系统的 block device,相当于 Linux 里的 /dev/sda 什么的。 从这个 mapping table 可以看出,FS0 是硬盘里的一个分区(因为是 SATA0,还带 GPT 分区表的),很明显是安装时分出的区,专门用来引导,是 FAT 文件系统的,所以 UEFI 可以直接识别。FS1 是光盘(SATA1)。 一般情况下,UEFI 的逻辑很简单,就是从某个可以识别的分区里找到一些 efi 文件并执行。这些 efi 文件就相当于 UEFI 的可执行文件,里面可以包含各种逻辑,比如读一些 UEFI 本来不能读的文件系统,然后引导操作系统。这里 macOS 的安装程序不能引导,就是因为上一步没有把需要的 efi 文件和指令写到 FS0 里,而安装程序的 efi 在某个 APFS 的分区里,UEFI 看不到,所以就杯具了。这里只需要让 UEFI 加载 APFS 的驱动,我们就可以跑正确的 efi 文件了。在 UEFI shell 里输入这些命令: load fs1:\EFI\drivers\apfs.efi load fs1:\EFI\drivers\AppleUiSupport.efi load fs1:\EFI\drivers\ApfsDriverLoader.efi map -r 这样 mapping table 里就会刷出 APFS 的分区,安装程序的引导在 FS2 里(至少我这里是这样)。直接跑里面的 efi 程序引导: fs2:\System\Library\CoreServices\boot.efi 这时系统就会继续刚才的安装。这次特别的慢,完事以后还会重启一次,依然会进入刚才的 UEFI shell,如果我们想进入系统的话还要再输入刚才的那些命令。有没有一劳永逸的方法呢?当然有~~ 如果在 FS0 里有个叫 startup.nsh 的文件,UEFI 就会自动执行文件里的命令,所以只要把上面的命令写到这个文件里即可。在这个文件中,UEFI 可以执行一些在 shell 里用不了的表达式,比如 for 循环,所以我们可以写一个循环来找有 boot.efi 的那个分区。不过在此之前,FS1 里的那些文件得复制到 FS0 里,这样我们就不需要那个 APFS 驱动镜像了。复制方法和一般的 bash 里是一样的,复制的命令就是 cp。接下来就可以写启动脚本了,UEFI 里贴心地自带了一个记事本,叫 edit,所以执行 edit fs0:\startup.nsh。我依然无耻地复制粘贴了这里的代码: load fs0:\EFI\drivers\apfs.efi load fs0:\EFI\drivers\AppleUiSupport.efi load fs0:\EFI\drivers\ApfsDriverLoader.efi map -r for %a run (1 5) fs%a: "macOS Install Data\Locked Files\Boot Files\boot.efi" "System\Library\CoreServices\boot.efi" endfor 写完后按 Ctrl+Q 保存退出。 直接 reset 机器,系统就会正常加载,并出现正常的图形界面让你输入 Apple ID 帐号什么。到此为止,这个虚拟机就算架好了。

2019/2/13
articleCard.readMore

拔智齿记

在很长时间以内,我都不知道智齿是个什么东西,就知道会疼,要拔。但是我的牙从来没疼过,所以我也不知道到底有几颗智齿,长在哪。我的左下方牙龈有一个小坑,经常积累食物的残渣,我没事就会舔着玩。后来隐约觉得那可能就是个没长出来的智齿。去年去做牙齿清洁的时候拍了片子,我才确认那真的是个智齿,而且是横着长的。除此以外另外三颗也都健在,歪七扭八地长在最里面。于是两周前,在妹子的怂恿下,我决定去拔智齿。 一周前 拔牙前,要先拍 X 光确定能不能拔,要怎么拔。我做的是一个所谓全景 X 光,大概就是一个圆柱投影。结果显示我左下方的智齿确实是横长的,而右下方的牙根离神经比较近,需要小心拔(然而感觉并没有⋯⋯)。拔牙可以选择局部麻醉或者全麻,我觉得全麻太麻烦了,所以选择了局部麻醉。后来的经验证明,这个选择一点也不重要⋯⋯ 最后牙医给我开了一瓶抗生素和一瓶止痛药。这也是我第一次在美国买处方药,我很光荣地记错了保险公司,一开始跑到了一个错误的医院⋯⋯ 我从来不生病,所以身上也没有保险的任何材料,医院的技师查了半天最后说你不是我们的客户⋯⋯ 最后在 Walgreen(大概相当于金象大药房⋯⋯)拿到了。在维基百科上查了一下,强力抗生素,强力止痛药。 一天前 按照牙医的指示,开始吃抗生素。每天四片,每片隔六小时,直到吃完。所以我还定了一个凌晨的闹钟把自己叫起来吃药。 第零天 去拔牙了!忐忑不安!会不会痛!会不会很长时间!会不会把下巴拔掉!正在我胡思乱想地时候,医生的召唤把我一下拉回了现实(⇐小学作文常用句式)。我就这样被历史的浪潮拍到了手术台上! 医生决定先拔最难的那颗,也就是那个横着长的。我不知道他用了什么样的方法,但是用到的工具里有电锯。那颗牙最后是一小块一小块取出来的,牙龈缝了针。剩下的三颗过程差不多,似乎是用一个小勺状的东西在里面一阵挖,然后牙就可以拽掉了,不缝针。整个拔牙的过程(加上麻醉)只用了半个小时,而且总的来说不怎么疼,就是会大力拽脸。 我一直觉得在现在充斥着碎片信息的互联网中,blog 算是种比较严肃的发表形式,所以我从来不在 blog 中用表情图这种东西,但是⋯⋯ 完事以后医生让我咬住两个纱布球,止血,并嘱咐我要不时地换纱布。最后给了我一些纱布和消肿用的冰袋,就把我赶出了诊所。当然拔牙的过程本身只是个开始,恢复过程才是漫长而艰巨的。医生还给我了一张纸,上面密密麻麻地写满了恢复中的各种注意事项,比如不能吃热的东西,不能吃硬的东西,不能吃辣的东西,不能吃脆的东西,不能用吸管,等等等等。 如果你认为咬两个纱布球没什么大不了的,那就大错特错了。人在正常状态下咀嚼肌是放松的,但是这两个纱布球需要有意识地持续地咬,我大概咬了一个半小时,确定血止住以后才停止。其实血还是在不停地往纱布上渗,只是不会往外涌了。这时脸上已经没有任何力气了,俗称面瘫⋯⋯ 等脸恢复了一些,已经是下午了,麻药的效用已过,疼痛开始加剧。尤其是开刀的那颗牙,已经近乎无法忍受,于是我吃了一颗止痛药,然后尝试吃了顿饭。当然大鱼大肉是没有的,喝了晚粥,吃了个面包。 晚上,昏昏沉沉地在 Netflix 上看了个《银翼杀手》。又吃了一顿,依然是稀饭面包。然后不知道为什么开始发低烧,这一天是不能刷牙也不能漱口的,所以就这么睡了。 第一天 喝粥,吃面包。疼痛已经减轻了很多,不需要吃止痛药了。继续发低烧。按照医生的指示,每日三餐和睡觉前用温的淡盐水轻轻地漱口,但是依然不能刷牙。 第二天 已经基本不疼了,烧也退了。有点受不了普通的粥和面包了,自己做了一锅皮蛋瘦肉粥,还挺成功。 第三天 继续喝皮蛋瘦肉粥,把之前做的那锅喝完了,再也不想喝了⋯⋯ 第四天 不知道为什么又开始疼了,但是还没到需要吃止痛药的程度。 第五天 更疼了一些,晚上吃了一片止痛药,不然睡觉的时候会疼醒。给医生打了个电话,医生说手术以后几天又变疼是正常的。 第六天 凌晨吃了最后一片抗生素。 第七天 按约定去诊所复查。医生用一个注射器对拔牙的地方滋了一番,滋出了好几坨食物残渣,然后说现在可以刷牙了,每次吃完饭以后用盐水滋拔牙的地方,然后用盐水漱口,需要滋一个月。另外要再过一周才能恢复以前的饮食习惯。 然后我就回家了⋯⋯ 回到家吃完饭,就开始滋牙。不滋不要紧,一滋吓一跳。拔牙的地方留下了四个大坑,怪不得会积累好几坨。据说这些坑要三个月才能完全恢复⋯⋯ ⋯⋯第十四天 基本恢复了饮食习惯,赶紧出去猛吃了几顿肉。后面的臼齿由于失去了支撑,有点松,咬东西的时候还是有点疼的,过了几天就好了。滋牙还是要滋的,除此以外生活基本恢复正常。

2018/12/14
articleCard.readMore

UHD/4K is the future

The main stream UHD monitors Is UHD/4K the future? Of course it is. And that means it is not the present. UHD has been around for at least five years. The main stream computer monitor market has changed a lot during this time. For example, 21:9 ultrawide has become “a thing”. It is very popular in the gaming community. Nowadays if a gamer upgrades his/her monitor, the hard choice is usually between ultrawide and 2.5K/G-Sync/144Hz. It even has its own master race. I bought one specifically for gaming, and it has served me well. On the other hand, low-end 1080p monitors are now “legacy” products. Two years ago I bought an Acer 1080p 60Hz monitor, with sRGB coverage and good overall performance. It was $100. Now you can get similar products with ~$60. It seems to me that the low-end market has been “low” enough, that some of the high-end (read: UHD) products should have creeped into the main stream by now. So I looked online, and realized: not quite. Usually a UHD monitor is at least $500. Of course it may not be a large sum if you consider the fact that high-end 1080p monitors can go above $1000, but those $500 UHDs don’t even have the shiny features — no true 10-bit color, no wide-gamut coverage, and usually not even a USB-C port. And I will remind you that with $600 you can buy a decently capable PC. Also I found some interesting quirks in these products (and UHD monitors in general): Dithered 10-bit color seems to be the standard now. People say that it is very close to true 10-bit, and they could be right. However, if you do not deal with high color depth media processing, 10-bit may be a bad thing. More on that later. The I/O situation is a mess. A lot of people (maybe even the majority of people) still have HDMI 1.4 outputs (which only supports UHD at 30Hz), and that includes me. Yes, I have a high-end gaming PC, and a Macbook Pro 2016, but I still have a HDMI 1.4 output. Why? Because my USB-C hub that connects all the peripherals to my MBP has a (and only one) HDMI 1.4 port. And generally people don’t get why their new UHD monitors only work at 30Hz. (“Bad product! Insta return! Avoid!”) Pretty much all computer monitor brands only have a handful of UHD (or better) models. The vast majority of models are still 1080p and 2.5K (2560 × 1440). Yes, UHD is still the high-end, at least in the general consumer market. The low-end of the high-end At this point, I couldn’t resist but upgrade my 1080p Acer, so I started looking for cheap UHD monitors. My criteria are IPS. I need to do photo and video processing. Height-adjustable. I am a freakin’ code monkey. ≤ 27 inch. < $400. I found only three candidates. LG 27UD58/27MU58. These two seem to be the same screen with different outfits. The UD is already discontinued. The MU is the “business” model of the two (officially you need to make an “inquery” before buying), and is still officially sold. Dell P2415Q/P2715Q. The difference between the two is the size (24 vs 27 inch). Again, old models. These are among the first set of UHD monitors that could operate at 60Hz with a single input, and were considered professional monitors back then (there was no UltraSharp counterpart). Sceptre U278W-4000R. What? Dell people are usualy the boring ones in suits, so I bought the LG 27MU58. The monitor was said to be factory-caliberated, and it came with a caliberation report, which I trashed immediately. I bought a USB-C to DisplayPort 1.2 cable with it, and used it to connect my MBP and the monitor. Very quickly I found something wrong — the color was off (against D65 white), and there was no good color presets; it was either too warm, or too cold. The closest preset it had was at 6900K, measured by my A7R2 camera, which I could probably tolerate if the monitor was otherwise perfect; but it was not. The screen was slightly bent, with the center went towards me (so no, I didn’t get a curved screen for free). And the screen would randomly go black shortly after waking up, and recover immediately. There were reviews saying a bad cable could cause the black screen, so I couldn’t decide if it was the monitor or the cable (I later found out it was the monitor). There was also something very strange with the dark grey on it. If I make a gradient from mid grey to black, I could see “bumps” in the gradient (more on that later). I returned it, and decided to never buy from LG. The Dell P2715Q Of course, the only choice left is the Dell, so I bought the P2715Q. It was also factory-caliberated, with a report. The report looked like this: According to the report, the white point was exactly at D65, but I still saw it to be a bit warm, but it was already better than the LG. My camera measured the white to be at 6000K. It was also a bit different from the screen on the MBP. Figure 1. The Dell P2715Q compared with MBP 2016 The monitor had 10-bit color, and macOS respected that. Figure 2. A section from System Report. The really annoying problem was in the dark-grey presentation on this monitor. Like the LG (they could be using the same panel actually), a gradient from mid-grey to black had severl “bumps”. Consider the following pattern, and remember you can open these images in a new tab to see them in full-size: Figure 3. The gradient test pattern from mid-grey to black. This is generated in Affinity Photo in a 16-bit file, and down-sampled to 8-bit PNG. This was what it was like on my monitor: Figure 4. The test pattern above displayed on my monitor. Taken with my camera. It is hard to see what was wrong, especially against a light background. So I pushed the photo to make it more prominent. Figure 5. The photo above, pushed. The arrows mark places of “bumps”. As you can see (hopefully), this was not a smooth transition. I have no idea what could have caused this issue. My cheap Acer monitor did not have this problem. Another way to see this problem is to use a 8-bit test pattern, and look at individual colors. Here is the pattern I used: Figure 6. The gradient test pattern in 8-bit. You should see banding in this pattern (again, try open it in a new tab). And if you use a tool, for example the Digital Color Meter in macOS, to extract the colors, you should see individual colors in these bands, with the RGB values differing by 1 between adjacent bands. All bands should have the same width. But this was not what I saw on the monitor. What I saw was this: Figure 7. The test pattern shown on the monitor. This is zoomed in to the right half, and pushed. Here I mark the edge of the bands with red lines. Obviously they are not evenly-spaced (the left half is fine). Initiaully I thought this is a seperate issue from the “bump” problem, but at the time I wrote this, I realized that they could share the same underlying cause. I then did more tests on this monitor. I also had a 2015 MBP from work, which still had Thunderbolt 2.0 ports. The monitor came with a mini-DisplayPort to DisplayPort cable. I used that to connect the 2015 MBP to the monitor. Interestingly, in this setup the banding looked much better. There were still some mild sudden jumps, but the bands had the same width. A closer look in System Report revealed that on that MBP the output was 8-bit. Perhaps it was the 10-bit dithering that caused the problem. Another interesting find was that if I connect the 2015 MBP with a HDMI cable, the gradient is much worse, and it was also different from the 2016 MBP result. There were still unknown variables in this situation. For example, did macOS render the UI in 10-bit? In principle this had nothing to do with the problem, but color issues were never simple. Some updates The date is 2019-01-08. I gave the P2715Q to my wife, and I need a new one. Very unfortunately, it was discontinued (I think at the end of 2018). Given that the P2415Q is still there, and is the only 24 inch UHD monitor in the lineup, I suspect it was to make way for Dell’s new 27 inch models, namely the U2718Q. From what I gathered, the new model has some QC problems, and is not as good as the P2715Q performance-wise (apparently the P2715Q is considered to be very accurate in terms of colors), and it is more expensive. Therefore for me, Dell is out. My only hope right now is the Monoprice 27 inch UDH monitor. But it is out of stock until the next month. Also, some time ago I read that the uneven banding problem is due to the (lack of) precision of the DAC in the monitor.

2018/8/10
articleCard.readMore

IBDesignable is not enough

I was writing a macOS app in Swift, and I needed several text fields accompanied by those little stepper buttons, like what’s shown below. So I decided to write my own control which wraps the text field and the stepper together. Figure 1. A bunch of NSStepper’s The custom control itself was simple enough. It was pretty much just a class containing an NSTextField with a formatter and an NSStepper, and that was it (I added a label later). @IBDesignable class NumberStepper: NSControl { private var Text: NSTextField = NSTextField(string: "0") private var Stepper: NSStepper = NSStepper() // ... func initSubControls() { addSubview(Text) addSubview(Stepper) // Add constraints and stuff... } override init(frame frameRect: NSRect) { super.init(frame: frameRect) initSubControls() } required init?(coder: NSCoder) { super.init(coder: coder) initSubControls() } override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) } } Notice I added an @IBDesignable before the class defintion. This was to say that the interface builder in Xcode should draw this control when I add it to my UI, so that it should show what’s in the control (the text field and the stepper), instead of just a grey box with “custom NSView” written on it. This was not the first time I did this. I had programmed custom views that had complicated draw() behavior, and @IBDesignable worked nicely for them. But not this time. This was shown in interface builder: What?! I consulted the official doc, again, (It took me a while to find, because interestingly enough, this doc is not in Apple’s dev site. It is under help.apple.com.) Above the class declaration in the implementation file, enter @IBDesignable for Swift and IB_DESIGNABLE for Objective-C. … Enter the code for your custom view’s draw method. Save the file. Interface Builder renders the view in the canvas. What I did should be all I needed. So what was wrong? Was it yet another Xcode bug? I spent over two hours trying to find out why my code failed, yet all the materials pointed to the same thing: it should work. (BTW, none of the blog posts and guides I read had a link to the official doc. None.) As my last resort, I posted a question on Stack Overflow. Stack Overflow is full of smart and kind-hearted people. Surely one of them would point me to the right direction, … … right…? Minutes after I posted my question, it was flagged by a guy named matt as a duplicate of this question. “Stack Overflow is truely an amazing place,” I thought. With gratitude, I followed the link. Well that question did contain words like “interface builder”, “subclass”, and “render”, etc., but the issue of that setup (complicated draw()) did not apply to my case. The accepted answer was informative, but again the extra information was not useful for me in particular. But there must be a reason my question was marked as duplicate. That matt guy is a Stack Overflow guru, and he marked my post so fast and so decisively; surely he knew what he was doing. “The solution must be in one of the answers in that question,” I thought. So I started to tinker with prepareForInterfaceBuilder() and TARGET_INTERFACE_BUILDER. I spent over one hour on it, but nothing worked. Eventually I drew the conclusion that the discussion in the duplicated question had little to do with my situation. Wow, amazing! Thanks for wasting one hour of my life, matt guy! Furthermore, nobody would be able to answer my question anymore, because you cannot do that on a freakin’ duplicate! I noted that under my question, there was a paragraph, This question has been asked before and already has an answer. If those answers do not fully address your question, please edit this question to explain how it is different or ask a new question. At that point I had already edited my question stating why it was not a duplicate. Probably I would just post a new question like suggested. So I essentially copied my question into a new one. Not surprisingly, another guy came and asked me to delete it and wait for my original question to be unmarked, “or do you want to marked as a spammer?” he asked. Fair enough. And now I’m stuck. I could perhaps reword my question and post yet a new one, but my original question perfectly described the problem; there was no point changing it. Did I expect that matt guy to realize his mistake and unflag my question? No. From experience, I knew a hot-headed guy like him who was not so smart would not ever think about consequences of his/her own action, otherwise s/he would not be hot-headed in the first place, by definition. Welp, that’s fine. It’s not like I had not solved any problem by myself before. It would just take more time. After some painful research, I eventually stumbled upon this post. Perhaps I was right to ask if it was an Xcode bug (it was not. But it could use more documentation), and should have posted that question instead. Oh wait, no, never mind; it would just be marked as duplicate by matt. Anyways, it looked like to me that the way interface builder draws custom views was by “importing” the layer of the views into its canvas. All UIViews are layer-based (which is the case for pretty much all the materials online), so that works. NSViews are not layer-based by default, therefore there is nothing to draw by interface builder, hence the empty box. All I needed to do was turning on layers by setting some properties. And since I did not actually need the layers, I should only do that in the context of interface builder (as opposed to running apps in production). Combining all information, the solution was to put this piece #if TARGET_INTERFACE_BUILDER wantsLayer = true canDrawSubviewsIntoLayer = true #endif into my initSubControls(). And sure enough, it worked. You can find the program here. Figure 2. A working NumberStepper in interface builder. For some reason it is improperly scaled. But that’s detail. Aaannd as I had expected, one week later, my question on Stack Overflow was still flagged. So I deleted my question.

2018/8/1
articleCard.readMore

「军训是服兵役的一种基本形式」

这是我在这个囧乎问题下的回答:大学生军训的意义在哪里,我觉得有必要贴过来。以下为正文。 我是来政治不正确的。 本来写了一大堆,后来全删了,感觉没什么用。我就想说接受军训是学生的义务,如果你不接受军训,就说明你不是学生,就要服兵役。另外有些知识分子真是狡猾,在别的法律问题下一口一个「法治社会」、「权力」、「义务」,张口就来,冠冕堂皇,在面对自己的义务时满腹牢骚,学的历史、政治一股脑全拿来引经据典了。有一种人是不用服兵役也不用军训的,《兵役法》第三条: 依照法律被剥夺政治权利的人,不得服兵役。 有些人还抱怨军训项目单一,整天就是站军姿和队列⋯⋯ 说真的如果加上投弹训练,这帮学生(当然我也是其中之一)能投多远⋯⋯ 加上定向越野有几个能完成⋯⋯ 而像武器射击什么的,我觉得是真不敢了,我当年军训是打枪的。教官给我们讲过一个事,以前有一届打枪,打完一轮,教官喊停,然后躲在靶后面战壕里的教官出去看靶,这时突然一声枪响⋯⋯⋯⋯⋯⋯⋯⋯ 不过好还好没打着人。 我觉得真正应该增加的是理论内容。不知道还有没有人记得前一段时间有个美国华裔学生被伊朗当间谍抓起来的事,这问题 如何看待一普林斯顿美籍华裔博士生因间谍罪在伊朗被捕?下面的有些回答简直惨不忍睹⋯⋯ 居然有人说这人平时是个好学生所以他肯定不是间谍的⋯⋯⋯⋯⋯⋯⋯⋯ 如果这些人周围有间谍的话,这间谍就方便了⋯⋯ 顺便说个重要的事,《兵役法》1998 年版第十二条: 每年十二月三十一日以前年满十八岁的男性公民,应当被征集服现役。当年未被征集的,在二十二岁以前,仍可以被征集服现役。 所以服兵役的年龄是十八岁到二十二岁之间,正好是上大学的年龄。同版第十五条: 应征公民是维持家庭生活的唯一劳动力或者是正在全日制学校就学的学生,可以缓征。 同时第四十五条: 普通高等学校的学生在就学期间,必须接受基本军事训练。 请自行理解其中的逻辑,同时理解这句话:「军训是服兵役的一种基本形式」。这句话法条没说过,但是新华社说过。说这句话是扯蛋的,请再反复理解,同时反思自己的政治觉悟。 重点在这:修订后的现行《兵役法》把第十五条挪到了第十六条: 应征公民是维持家庭生活唯一劳动力的,可以缓征。 同时第十二条加了一句 普通高等学校毕业生的征集年龄可以放宽至二十四周岁。 有些知识分子,不要觉得社会主义的铁拳只是用来砸别人的,与自己无关,就可以大放厥词。

2018/4/4
articleCard.readMore

对于现在各种文档系统的吐槽

作为强迫症患者,选择合适的文档工具是个特别纠结的问题。过程中涉及到的两种主要需求是 存档需求,要求文档包含足够的结构信息。比如 ConTeXt 里有个宏 \quotation,用来排行间引用,就比直接写引号要包含更多的结构信息。 展示需求,要求工具有足够的设施用来实现各种排版效果。 同时满足这两个需求的工具才是好工具。 HTML + CSS HTML 作为文档格式最大的问题就是结构上的表达能力太弱,简单地说就是 tag 的种类太少。比如你想写一段引文,只有一个 blockquote 可用,没有特殊的 tag 来表示引文出处之类的结构。原则上你可以写个 <div class="source"> 这样的 tag 来自己定义任何结构,而且在设计网页的时候这是个标准操作,但是用来存档的话就很弱鸡了,不如使用 XML,写起来差不多复杂。 HTML 5 加入了几个重要的结构标签,比如 article 和 section,但有个很严重的问题,就是 HTML 5 没有 schema⋯⋯(是的,HTML 4 居然是有 DTD 的⋯⋯)这就是说 HTML 5 不能使用 XML 工具(包括 XSLT)来处理,只能使用专门的解释器。 HTML 的另一个问题是历史包袱太重,标准中充满了诸如 <font>, <i> 这种纯粹用于展示用途的标签。当然你可以选择不用,但是你不能保证别人不用,也不能保证你不需要处理包含这些标签的文档⋯⋯ (眼睛看向 LaTeX。) EPUB 和其他电子书格式 这些电子书格式一般都是编译结果,也就是单纯用于展示。这些格式问题是它们都是打包的 HTML,一般是由设备内嵌的浏览器渲染,所以几乎一定特别难看⋯⋯ 这里的难看并不是指字体不好,或者行间距太小之类的,而是不使用高级的排版算法(比如断行和各种 micro-typography)。当然表面上来讲这不是电子书的锅,而是 HTML 和浏览器的锅,但是 HTML 是用来写网页的啊,浏览器是用来看网页的啊,好的排版算法只是网页渲染里一个非常微不足道的需求,高效地实现各种交互和动态效果远比排版算法重要的多,也是浏览器厂商关注的重点。然而电子书是本书啊!丫的是书啊!书!一本排版难看的书,不扔难道留着过年⋯⋯?所以电子书使用浏览器渲染,阅读器厂商这种懒惰的行为造就了电子书「难看」的印象。 一般来说我拿到 ePUB 之后会解包转成 TeX 重排一遍⋯⋯ Markdown 和其他简化 markup 我觉得所有这些格式里,Markdown 是最弱鸡但同时也是最无辜的一个。Markdown 的功能特别少,因为发明者 John Gruber 在设计 Markdown 的时候从来就没有想过要用它处理复杂的格式,Gruber 只是为了能方便地写 blog 而已。你去看看他的 blog 就知道 Markdown 为何如此简单了。 然而在懒惰的开源社区开始动歪脑筋以后,一切都改变了⋯⋯ Markdown 有了各种各样的扩展,巨硬甚至有人闲得没事搞了扩展用来写学术文档⋯⋯ 但是 TeX 已经存在了啊,有这个功夫还不如自己搞一套宏包⋯⋯ 这就好像你想去赛车,本来你车库里就有辆 Nissian GTR, 调一调悬挂可以直接上,你却非要翻新一辆报废的夏利然后换台发动机⋯⋯ 这种事也只有开源社区能干的出来⋯⋯ 如果你执意要用 Markdown 处理复杂文档,你最终一定会遇到这些问题: 基本控制符不分左右,无法处理复杂格式。Gruber 最初的 Markdown 处理器是一个基于正则表达式的 Perl 程序,大家都知道标准的正则表达式是不能处理任意层数的嵌套的(比如 HTML 里的嵌套 div),所以 Markdown 里的控制符没有必要分左右(因为反正不能嵌套⋯⋯)。另外由于同样的原因,很多 Markdown 处理器都不能可靠地处理这种情况:_aa*a$2*x_0$b*bb_(假设 $ 是行间公式)。 Markdown 标准并不是非常详细,很多行为都是未定义的,所以处理器之间存在兼容问题。比如 some_long_name 这样的表达,有些处理器会认为 “long” 应该加强(一般是斜体),有些会直接把下划线排出来(因为两边没有空格),还有一些有开关可以切换。 处理中文文档不方便,这主要是上一条的特殊情况。由于中文字之间不空格,有些处理器会忽略中间的控制字符。 没有扩展性,官方没有宏语法,你为一种处理器写的宏不能保证在其他支持宏的处理器都能用。 总之使用 Markdown 写复杂文档是件特别蛋疼的事。 AsciiDoc 表面上看起来,AsciiDoc 是一套和 Markdown 长得差不多的简单语法,实际上它的设计目标和 Markdown 完全不同。AsciiDoc 使用 DocBook 作为中间格式(而不像 Markdown 和其他语法是为输出 HTML 优化),从一开始就是为了给复杂文档提供一套简单且完备的语法。举几个高级功能的例子: 区分 article 和 book 类型。在 book 文档类里有 frontmatter 和 backmatter,附记、摘要、引用、索引应有尽有。 所有的元素都可以附加属性,AsciiDoc 自己不用的属性会带到输出文档里。 基本控制符有两套,用来区分周围有没有空格的情况。 所有的 block 元素都可以加标题,都可以带 id 用来交叉引用。 记得我之前说 HTML tag 不够丰富么?AsciiDoc 里的引文有特殊的属性用来标记出处。 解决 block 元素之间从属关系的歧义。比如你在一个列表后面写了一个段落,你如何告诉处理器这个段落是列表的一部分,而不在列表之外?AsciiDoc 有特殊语法解决这个问题。随之而来的另一个问题如果你有一个一级列表,里面有个二级列表,后面有个段落,你怎么告诉处理器这个段落属于一级列表而不属于二级列表?AsciiDoc 把这个问题也解决了。 AsciiDoc 是我非常常用的语法,它有足够丰富的设施用来实现一般文档可能碰到的所有需求,同时源码写出来简单易读。我以前的 blog 引擎使用 Flask-FlatPages 渲染文章,默认使用 Markdown 语法。我为了用 AsciiDoc,最近重写了 blog 引擎,加入了自定义后端支持。这篇文章就是用 AsciiDoctor(一个 Ruby 写的 AsciiDoc 处理器)渲染的。 *TeX 在这些所有的工具里,TeX 有特殊地位。首先,TeX 是一个真正的排版工具,它自己决定每一个字、每一个标点符号的位置(而不依靠像浏览器这样的前端),相比之下像 Markdown 和 AsciiDoc 只能叫「文档工具」。更重要的是,Knuth 是现代极其少见的对数学、计算机和排版都有深刻理解的文艺复兴男。而 TeX 也是这些文档工具里唯一一个表达能力、排版效果都很优秀,同时支持数学公式的。所以尽管现在看来 TeX 有各种各样的缺点(大多是历史包袱),但在需要排高质量学术文档的时候,TeX 仍然是第一选择,也是事实上的标准。在民用领域,尽管有些工具可以在某些方面超越 TeX,但没有任何一个系统在所有方面都有优势。同时,TeX 应该说是计算机排版领域的一个开创性工作,其中的断行和公式布局等算法到今天依然在行业中广泛使用(可能是唯一可用的)。在像 InDesign 等现代排版系统中,断行算法基本都是 TeX 断行算法的某种改进版。而 Office 里的新版公式编辑器(民用领域除 TeX 以外唯一可用的公式排版工具)也是用了改进后的 TeX 公式布局。 当然我们现在说的 TeX 系统,一般是指 TeX 编译器加上一大堆宏包,其中最常用的两套宏包是 LaTeX 和 ConTeXt。这两套宏包从设计理念上基本是两个极端,所以必须分别讨论。 LaTeX 面向的主要用户是学术文档的作者。对于这些人来说,LaTeX 与其说是个排版工具,不如说是个像 Word 一样的字处理程序。LaTeX 自带一套还算说得过去的默认风格,你只需要告诉它文章的标题、作者、摘要和正文,它就会自动排出一个看上去还行的文档,但是如果你想完全自己设计版面,或者使用 LaTeX 本身没有的高级功能,就有点麻烦了,需要使用第三方宏包。比如如果你需要排一本正经的书,那就需要 Memoir 宏包。这个宏包提供了许多专业排版必须的工具,比如它有个专门的宏用来排 epigraph,并且允许分别设置 stock size 和 paper size。由于 LaTeX 的用户众多,它有海量的第三方宏包可供选择。但是这些宏包有两个特点,导致了 LaTeX 的几乎所有不足: 这些宏包是很多不同的人写的。 这些宏包的作者很多都是科研人员,他们有些不懂编程,有些不懂排版,大部分人两者都不懂。 首先,每个宏包作者都有自己的命名风格和宏调用风格,所以在同一个文档里调用多个宏包的宏就会导致代码可读性很差。同时,不同的宏包之间很可能互相冲突,导致莫名其妙的 bug。另一个很坑的因素就是很多宏包都不能保证向前兼容,所以说不好哪天你的文章就不能编译了。这就导致了 LaTeX 文档实际使用时的一个重要缺陷:在空间和时间上都不能很好的移植。如果你拿到了别人的文档源代码,大多数情况下你是不太可能完全看懂的,而如果这是个很老的文档,可能连编译都不行,因为其中用到的某些宏已经改了名字,或者压根就不存在了。想改?看都看不懂,怎么改⋯⋯ LaTeX 社区宏包的另一个重要缺陷就是大部分作者并不懂如何设计一套好的宏,导致在写文档时很难分离结构和表示。这和前面的几个缺陷共同就导致了 LaTeX 文档并不适合作为存档格式。 在意识到 LaTeX 的这些缺陷后,我转向了 ConTeXt。这个系统在设计上与 LaTeX 有两点巨大的区别。ConTeXt 的作者是个专业排版工作者,所以它是一个正统的排版工具,默认样式惨不忍睹,用户需要从头定义好自己的样式才能使用;而 ConTeXt 不依赖第三方宏,几乎所有的功能都可以用内置宏完成,而且设置起来极其方便并且风格统一。如果你需要改变某种现有元素的风格,只需要写 \setupxxxx[a,b,c][d=e, f=g];如果你需要新定义一种元素,只需要写 \definexxxx[a,b,c][d=e, f=g]。 比如我在排作业的时候,定义了一套新的列表叫 problem,大题用数字编号,小题用字母编号,大题之间空 1cm,只需要如下几行: \defineitemgroup[problem][levels=2] \setupitemgroup[problem][1][n, inmargin] \setupitemgroup[problem][1][style=\tfb, inbetween={\blank[1cm]}] \setupitemgroup[problem][2][a, standard] \setupitemgroup[problem][2][left=(, right=), stopper=] 在写题的时候使用 \startproblem \item ... \item \startproblem \item ... \stopproblem \stopproblem 这样就很好地做到了结构与样式分离。当然 ConTeXt 也不是完美的,它在时间上的不可移植性比 LaTeX 更严重,在我使用的这六年里就已经遇到了一些以前的文档现在不能编译,或者编译以后乱掉的情况,所以 ConTeXt 文件也不适合存档。 关于 ConTeXt 的最后一个槽点,就是它实在是太强大了。裸的 TeX 也很强大,但是 TeX 的强大是因为它只包含了很少量的基础能力,复杂性来源于这些基础能力的组织形式。ConTeXt 正好相反,它包含的宏数目众多,每个宏都有大量的选项,有些宏还有多种用法,这些所有的信息很难完整的整理到一套文档里。ConTeXt MkIV 的手册至少七年前就开始动工,到现在还没写完,其中光是如何定义和使用字体的部分就长达 70 页(而且版面还挺宽的⋯⋯)。ConTeXt 中包含一个扩展的 Metapost 实现,这部分的手册单独成书,也长达 376 页。除此以外官方还有大量的手册和教程,专门介绍系统的某些方面(比如如何使用 visual debugging)。即便如此,我在使用过程中还是遇到了一些需要使用 undocumented feature 的情况,我在邮件列表里问了以后才知道。 XML-based applications & Docbook 据说现在出版业有转向使用 XML 的大趋势。工业上使用的 XML 工具,我们草民是用不了的。如果你想搞家用 XML 流程,目前大概就只有一个选择,就是 Docbook。使用 XML 显而易见的好处就是不用担心可移植性。就算以后 XML 格式淘汰了,你也能猜出每个 tag 的意思,然后自己写个程序解析。 Docbook 用两种用法,普通的一种是你随便写个程序,或者使用 Pandoc 这样的转换器,把 Docbook 文档转成其他格式(比如 TeX),然后用相应的处理器处理。而比较文艺的一种用法是使用 XSLT 处理器把 XML 渲染成最终格式,这就是所谓的「纯 XML 流程」,据说在工业界很时髦。我还是比较倾向于第一种方法,原因在后面会说到。使用 XSLT 就需要有相应的 XSLT 样式表。Docbook 有一套免费的样式表,支持输出多种格式,包括 HTML,PDF,和 ePUB。比较神奇的是,输出 PDF 的流程也是纯 XML 的,需要先使用样式表把 Docbook 转成 XSL-FO,再使用 FO 处理器(比如免费的 Apache FOP)渲染成 PDF。 在我使用 Docbook 的经验中,数学公式的处理是最大的坑。Docbook 的 schema 并没有规定数学公式应该如何写,所以这里就有三种可能: 由于 Docbook 本身是 XML,一种自然的写法是使用 MathML。但并不是所有前端(最终渲染出文档的东西)都支持。现在的浏览器一般都支持 Presentational MathML,所以对于 HTML 和 ePUB 输出来说,MathML 是可用的。但是 PDF 输出就很麻烦了,FOP 压根就不支持渲染公式。所以使用纯 XML 流程只能输出到 HTML。 Figure 1. iBook 渲染包含 MathML 的 ePUB。文本断行难看到爆。 写 TeX 公式。输出 HTML 的话依然可以使用 MathJax 做到纯 XML 流程。需要 PDF 的话可以先转成 TeX 再编译;我还没有用过这种方法,因为我一直在试图搞定下面这种方法。 写 MathML,输出 PDF 的时候先转成 TeX。这就需要一套把 MathML 转成 TeX 格式的程序,理论上 XSLT 可以方便地实现这个功能。我想到这个方法以后就开始着手写一套 XSLT 2 实现,但是在写的过程中发现一个惊天神坑:居然没有好用的免费 XSLT 2 处理器⋯⋯ 如果你搜索 XSLT 处理器,出来的结果一般都是 XSLT 1 的(其实连浏览器都支持 XSLT 1),支持 XSLT 2 的免费处理器好像就只有 Saxon 一个。但是 Saxon 的尾递归优化有 bug(好像是吧,我记不清了⋯⋯),所以我没法用它替换 MathML 中的众多 entities。我觉得做这件事最好还是找个有 XML 库的通用语言,XSLT 有自己的局限性,但是这样就不文艺了⋯⋯ 总的来说,Docbook 是个适合存档的格式,但是目前并没有足够好用的免费工具链。 Scribble 最后说说 Racket 的官方文档系统 Scribble。Racket 是一个实现各种奇葩小语种的平台,而 Scribble 正是这个平台上的小语种之一。Scribble 的语法看起来和 TeX 差不多,但实际上它是个正经的函数式语言,语法可以和 Racket 的 s 表达式无缝转换。比如下面的代码 This is @italic{important}. 就等价于 "This is " (italic "important") "." 并且还可以内嵌 s 表达式,所以原则上你可以在文档中嵌入任何形式的逻辑,包括 Racket 的宏,这就又比 TeX 宏强大许多了。 Scribble 自带了很多写 Racket 文档有用的宏,和一些生成计算机期刊论文的文档类,但除此以外并没有其他丰富的格式。我觉得它是个很有潜力的系统,如果你有足够的意愿来设计一套自己的宏(甚至可以搞一套输出 XSL-FO 的前端),Scribble 大概会非常好用。但是如果你像我一样懒的话,Scribble 只能用来写写程序文档。 不爽的总结 总的来说,个人排版/出版和其他多媒体领域(比如视频编辑)一样。如果你看看网上的普世价值,都说现在的免费程序可以让你足不出户就排版并发表自己的书和文章,如果你要求不高的话也的确如此。但是如果你对产品的要求和工业上一样严格,就会发现免费的工具要不然就远远达不到要求,要不然就是年代过于久远,已经开始不能适应现在的新技术和流程。像我这样的弱鸡此时就只能在家打打游戏,坐等下一位大牛的出现。

2018/1/15
articleCard.readMore

中英混排规范

之前的某篇文章说到中英混排时,中文和英文之间应该加空格,实际上中英混排还有其他很多要素。这里我试图列举一下我平时经常遇到的情况。 中英文/数字之间的空格 有很多语言使用空格分词,英语就是最常见的一种。中文和这些语言的字母之间应该加上空格。比如在下面的例子中, 他就是a piece of shit. 由于 “a” 和前面的中文之间没有空格,看上去 “a” 像是中文的一部分。 他就是 a piece of shit. 这样就好多了,可以清楚地看到 “a” 是一个单词。同理,中文和阿拉伯数字之间也应该有空格。 标点符号的处理 在中英混排中,标点符号是个巨坑。要填好这个坑需要讨论很多种情况。 句号逗号问号叹号冒号破折号 这几种是最简单的标点,但就已经非常纠结了。它们的用法类似,所以放在一起讨论。首先是最显然的情况:标点符号两边是同一种语言,直接使用那种语言的符号。但是如果两边分别是中文和英文该怎么办?我以前的办法是标点符号跟着它前面的语言走,比如: 拉完发现又没纸了,fml. Fml. 拉完发现又没纸了。 但是我后来发现一个问题,如果在很多中文标点中夹杂着这样一个英文标点,由于它后面的空白很短,很容易顺便把这个标点忽略掉。比如 我去炸学校,天天不迟到,一拉弦,赶快跑,fml, 是个哑炮。 看上去 “fml” 明显离后面的「是」更近。这样做的另一个问题就是如果文章里有很多这样的情况,文章就会显得很乱。所以我现在倾向于除了两边都是英文的情况以外,全部都用中文标点,干净整洁又清楚,虽然有时候看起来比较怪。 引号和括号 这是个真正的坑。在电脑上,英文的引号有弱鸡无方向引号和正常有方向引号。原则上文章里出现的引号都应该是有方向的,但是如果你不用中文输入法的话,按键盘打出来的引号都是弱鸡引号,而且人类么,你懂的,都懒。好在现在的操作系统里一般都默认打开自动转换引号的功能,所以比以前好一些了。(Linux 有么?不清楚。) 你以为这就是引号的全部问题了?Naive!原则上,中英文的引号应该是不一样的,就好像中英文的逗号一样,但是由于某些诡异的原因,中英文的引号居然是相同的字符??为了个毛线啊???黑人问号.jpg……这样就尴尬了,虽然我很想用中文引号,但是居然没的选……好在中文还有另一套引号:「」,这种引号宽度正确,还有逼格,最适合我这样的闷骚青年。所以我现在的做法是如果引号里面是中文,就用中文方引号;如果里面是英文,就用英文引号。但是注意这种方案是不符和国标的,国标规定这种方引号只在竖排时使用。 你以为这就是引号的全部问题了?Naive!如果引号里面前面是英文,后面是中文,怎么办?如果引号外面前面是英文后面是中文怎么办?如果是「中文左引号中文英文右引号英文」怎么办?如果是「中文左引号英文中文右引号英文」怎么办?和前面那种情况的处理方法是不是应该一样?对于这些情况,我的做法一般是:看心情…… 你以为这就是引号的全部问题了?Naive!引号还会改变其他标点符号的使用。比如按照我的规则,我这样写: 拉完发现又没纸了,fml。我只好发推求救。 但是有引号时,明显这样比较好,吧………………: 「拉完发现又没纸了,fml.」我只好发推求救。 对比 「拉完发现又没纸了,fml。」我只好发推求救。 好像差不多一样难看………… 书名号 英文没有书名号,其它和引号一样。 间隔号 间隔号就是中文里用来分隔老外姓和名的那个玩意,比如「安娜・卡列尼娜」。严格来讲间隔号是个纯粹的中文排版问题,因为英文里不需要这个符号,而且也不会出现一边中文另一边英文的情况,但是我对于这个符号现在的使用情况很不爽,所以在这里一块吐槽了。 在我从小到大读过的所有书里,包括国标的文档,这个符号都是个「全角」符号,和一个中文字符一样宽,但是不知道为什么在使用 Unicode 的时候大家都不约而同地用了 0x2027 和 0xb7 这亮个字符。这尼玛是什么精神啊???这玩意叫 hyphenation point 和 middle dot 啊,谁规定这丑了吧唧的玩意就是间隔号啊???如果真有人这么规定了,为什么这货不是全角符号啊????Unicode 里规定这玩意的 East_Asian_Width 是 ambiguous???谁他妈 ambiguous 啊????Ambiguity 哪来的啊?????说好的漂亮的间隔号呢?????自己看: Thus, William Shakespeare is signified as 威廉·莎士比亞 or 威廉·莎士比亚 (p Wēilián Shāshìbǐyà), George W. Bush as 喬治·W·布殊 or 乔治·W·布什 (p Qiáozhì W. Bùshí), and the full name of the prophet Muhammad as 阿布·卡西木·穆罕默德·本·阿布杜拉·本·阿布杜勒-穆塔利卜·本·哈希姆 (p Ābù Kǎxīmù Mùhǎnmòdé Běn Ābùdùlā Běn Ābùdùlè-Mùtǎlìbǔ Běn Hāxīmǔ). 这玩意怎么看啊????眼睛不疼么?????为什么会有人用这个破符号啊?????我一般都遵循日本的规范,用 0x30fb (katakana middle dot)。这是一个全宽的字符,写出来是这样的: Thus, William Shakespeare is signified as 威廉・莎士比亞 or 威廉・莎士比亚 (p Wēilián Shāshìbǐyà), George W. Bush as 喬治・W・布殊 or 乔治・W・布什 (p Qiáozhì W. Bùshí), and the full name of the prophet Muhammad as 阿布・卡西木・穆罕默德・本・阿布杜拉・本・阿布杜勒-穆塔利卜・本・哈希姆 (p Ābù Kǎxīmù Mùhǎnmòdé Běn Ābùdùlā Běn Ābùdùlè-Mùtǎlìbǔ Běn Hāxīmǔ). 这样多好看啊!!!妈的气死我了!

2017/6/2
articleCard.readMore

Molecule visualization with Blender

So, suppose you have an exotic molecule in some chemistry program, maybe PyMOL or VMD, and it looks hideous in that tiny window. You want to give it a face lift by rendering it in a fancy fashion. You want to show it to your advisor and she will be happy, and let you do everyone else’s visualization work in the future. How do you do that? The first step is of course to export your molecule to a 3D model. So far I have found that OBJ format is the most reliable. However, PyMOL does not export OBJ with textures, so you will just see a plain white material across the model, but maybe that is what you want. Then you need to import the model in some 3D animation/rendering package. We will use Blender. It was used to be called Blender3D, when it was just a toy program with ugly UI, but now it has become a full-featured 3D animation package, and its new Cycles renderer is very capable. Usually when you first import the model, it will have some problems. A common one is duplicated vertices. It can be solved by selecting the model, press Tab, then Space, and type “remove doubles”. The menu now should have only one item. Press Enter on it, and it will be done. Another problem you will see from time to time is z-fighting. It happens when you have two triangles at exactly the same location, and the renderer does not know which one should be covered by the other. This is different from duplicated vertices, because in this case, the two triangles can belong to different meshes, and one is meant to cover the other, it is just that the author of the chemistry software is too lazy to do it correctly. In my case, my molecule looks like this As you can see, portions of the mesh are colored. Those are seperated meshed that are exact copies of part of the main mesh, and therefore z-fight with the main mesh. My solution is to add a solidify modifier to these colored meshes, and set offset to be slightly larger than -1. By doing so the colored meshes will be slightly blown up, and thus correctly cover the main mesh. Now that we have fixed all the errors on the meshes, from this point on things are mostly up to your personal preference. My result is like this To achieve this kind of flat cartoon effect, you will need to light the whole model evenly and strongly (for example with a strong hemisphere light), and make 2 render layers. The 1st layer consists the main object without outline, and 2nd layer outline only. And then use the this node setup: The Compositor node group is like this The Tonemap node is the key to achieve the flat effect, and the RGB Curves node is to brighten up the pure black material, so it will not be confused with the black outline.

2016/4/22
articleCard.readMore

Meow video streaming with Raspberry Pi

First of all, let’s make one thing clear—you don’t take care of your cat; your cat takes care of you. In order for my cat to take better care of me, I was planning to purchase a home surveillance camera, something like a Nest camera. However my cat told me such a thing is too expensive, and not worth the price. After all I don’t need fancy features like motion detection, online backup, and all those “cloud” nonsense, I don’t even need video storage at all (I only want to see live video feed). I wouldn’t trust any company to have videos of my home, where my cat sometimes walks naked. So I decided to build my own video streaming server. I bought a Raspberry Pi 2, the official IR camera module, and a plastic case for the Pi. Upon 1st time it is booted, it shows a interface to select a OS to install. I tried Arch Linux, but it won’t boot after restart. So I went with the default Debian. It’s a pretty capable OS right after installation; it even has a version of Mathematica on it! Who knows, I might just migrate my research work to the Pi. The easy way Naturally, a lot of people want to do the same thing on their Pis, and there are a bunch of articles on how to do it. The catch is, 99% of them don’t work. For example, UV4L promises 0 configuration video streaming on HTML5, along with a bunch of other things. But it appears that the video is not compressed with hardware acceleration. I’m not entirely sure, but this is the only reason I can think of that explains why the video is fixed at 640x480 (strangely it has a setting page that is suppose to change this, and guess what, it never works) , and are so darn laggy. It also provides configuration files and is able to stream the video through other means than HTML5, but it never worked on me. The same goes all methods based on v4l2 module. It does not utilize hardware acceleration, and therefore is always laggy and unusable. The not-working-but-should way I had a lot of good experience with FFmpeg, and expected it to just work. However it is not the case this time. I set up FFserver with something like HTTPPort 8090 HTTPBindAddress 0.0.0.0 MaxHTTPConnections 8 MaxClients 4 MaxBandwidth 1000 CustomLog - #NoDaemon <Feed feed1.ffm> File /tmp/feed1.ffm FileMaxSize 5M ACL allow 127.0.0.1 </Feed> <Stream live.flv> Feed feed1.ffm NoAudio </Stream> <Stream stat.html> Format status # Only allow local people to get the status ACL allow localhost ACL allow 192.168.0.0 192.168.255.255 </Stream> Then I start the server with ffserver -f server.conf &, and use raspivideo to feed the (hardware accelerated!) H264 stream into ffmpeg, which is supposed to just wrap the stream in a FLV container, raspivid -t 0 -w 640 -h 480 -b 1024000 -fps 5 -ih -n -o - | \ ffmpeg -i - -c:v copy -r 5 -an -f flv -override_ffserver \ http://localhost:8090/feed1.ffm That should be all I need to do. However FFmpeg refused to wrap the H.264 stream, and complained [flv @ 0x215e520] Timestamps are unset in a packet for stream 0. This is deprecated and will stop working in the future. Fix your code to set the timestamps properly Thu Mar 3 02:58:36 2016 127.0.0.1 - - [POST] "/feed1.ffm HTTP/1.1" 200 276 av_interleaved_write_frame(): Connection reset by peer [flv @ 0x215e520] Failed to update header with correct duration. [flv @ 0x215e520] Failed to update header with correct filesize. Error writing trailer of http://localhost:8090/feed1.ffm: Connection reset by peer I posed a question in StackExchange, but so far nobody seems to know what’s wrong. The only way After some annoying trial-and-error, the following is the only way I can get it to work, It’s not an elegant solution, and VLC is lacking in many ways in comparison with FFmpeg. But at least now I can see my cat in office.

2016/4/9
articleCard.readMore

炸辣椒油

辣椒油乃是我辈中人居家旅行,杀人越货必备之良品。它既可以拌饭拌面蘸馒头,也可以炒菜炖肉涮火锅,过雪山时还可以用来激发革命志士的内力,实在是调味料中的战斗鸡。这次我就来教大家炸辣椒油的正确姿势。 炸辣椒油,最重要的当然是选用正确的辣椒。辣椒油对辣椒的选用异常挑剔,必须满足如下几个严苛的条件: 必须是红的 必须是干的 必须是碎的 必须是辣的 除此以外还需要几味佐料: 油,传说菜油最好,因为油温低,炸出来不容易发黑,不过我也不知道其它油行不行,没用过。这个好像不能算佐料……? 香叶,一棵 花椒,一吨 茴香,一车 大料,一坨 白芝麻(可选,主要是逼格比较高) 集齐了这些装备,就可以开始打 boss 了。 把辣椒和茴香倒到一个碗里,拌在一起。茴香不用太多,一小撮就行了,上面说的「一车」是逗你玩的,又不是做茴香豆…… 你想放点盐也可以,反正你高兴就好。 热锅,然后倒入油油,开中火,注意在这个温度下油不应该冒烟,传说温度是 100℃ 多一点。油热了以后放入香叶、花椒和大料。 等一会儿,用筷子挑逗一下香叶,如果香叶已经变脆了,把香叶、花椒和大料捞出来扔掉;如果没有脆就再热一会儿,或者把火稍微开大一点,然后重复这一步。注意如果这些调料变黑了,就是油温太高了,gg. 开大火,把油加热到冒烟。注意别点着了,好多油呢…… 关火,然后别动,静置两分钟。 把油慢慢倒入碗中。友情提醒:如果是玻璃碗或者瓷碗的话,最好把碗放在水池里再倒,别问我怎么知道的。然后不能用塑料碗,你懂的。 放入三分之一总量的辣椒,一边放一边搅一边听声音。其实听声音没什么用,我就是觉得那个声音挺爽的。 静置一分钟。 放入三分之一总量的辣椒,放入白芝麻,搅。 静置一分钟。 放入剩下的辣椒,搅。 闻一闻做好的辣椒油,并发出高潮的声音。 嗯,大概就这样。与一般的方法不同之处大概在于我是把辣椒放到油里,而不是把油放到辣椒里。这样色香味才能俱全。

2016/4/4
articleCard.readMore

做一个黑色的东东就这么难吗?

今天在知乎上看到一个问题:冰块放入开水中降温会产生对人体有害的物质吗?这本来是个没什么意思的问题,连常识都算不上。依照知乎惯例,问题下会有各种段子手讲冰块放入水中如何有害,然后被朋友圈拿去成为 2015 十大谣言之一。同时也会有回答义正言辞地说你们这样是不对的,对待文盲要像秋风扫同志般温柔,荒诞的问题也是值得尊重的。于是我思考了一下“荒诞”和“蠢”的区别…… 区分“荒诞”和“蠢”的一个方法就是看问题能否引发对专业内容的进一步讨论。我们在听报告的时候经常会有这样的经历:有人提问题,报告人给出回答,然后继续讲,像什么都没发生过,这种问题就是蠢问题。另外一些问题,报告人要想一下才能答,报告人还会反问提问者问题,然后和提问者讨论,旁边还有人加入讨论,这种就不是蠢问题。 这也让我想起了两年前听的一次报告,内容是关于量子力学的非线性效应。主讲人的小组设计了一个三缝实验,主讲人用一些时间陈述了他们遇到的困难,尤其是试验用遮光片的材料要求。这时我们系一个凝聚态理论大牛提了一个问题:“Why is it so hard to make something black?” 当时我就愣住了,因为我听的时候一直把注意力放在量子力学上,完全没有想过这个听起来简单到有些荒谬的问题也值得讨论。主讲人停顿了一下,然后开始具体阐述这个缝为什么很难做,我印象很深的一个理由是如果你要求材料不透光,就要有一定的厚度,但是如果缝很窄,这个缝就会变成一个波导,影响实验的信号。主讲人答完以后还不忘调侃一句:“You are a theorist, right?”全场爆笑。 这就是一个看似荒诞,同时又非常聪明的问题,这样的问题可以同时引发听众和主讲人的思考,还能引出段子。而蠢问题只能引出人们对“义务教育已经普及了问什么还有人有这种问题”的思考,和段子。

2015/7/7
articleCard.readMore

论洁癖

关于中英文间空格 不知道怎么逛到了 @acgtyrant 的一篇文章,讲中英混排的时候为什么在中文和英文之间应该空格。这个其实是我开始用电脑以后就一直坚持的规范。一开始我们家没有网络,我没事经常在 Word 6 里打字玩,当时也没有注意什么排版什么节奏,也不知道中英混排有什么讲究。后来上网以后和别人聊天就发现问题了,我在聊天窗口里打出来的东西如果同时有中文和英文的时候看起来就会很奇怪,也不知道哪里不对,一段时间后才突然发现,Word 会自动帮我在中英文之间加一个很小的空白,但在聊天软件里不会。于是我就这样很无辜地患上了强迫症…… 这样说起来虽然我现在是个彻头彻尾的 Office 黑,但是我对排版的变态追求确实是始于 Word. 在看 @acgtyrant 那篇文章的时候我又顺带着看了里面的几个链接,都是在讲为什么中英文之间应该空格,那个知乎问题我之前也看到了,而且我觉得在这个问题上我也很有发言权,但是我当时看了一眼题目就把它关了。在我看来这个问题其实没有为什么,或者说讲“为什么”没有用。硬要说为什么的话回答也很简单,因为这样做“美”,然后就没有然后了。“美”有为什么么?(话说这帮搞美学的整天到底在干些啥……?)换句话说,你问那些不 care 的人你为什么中英文之间不加空格,大部分人可能会疑惑地反问加空格干嘛,你跟他们说因为这样可读性好,然后他们说没觉得。 我经常会对周围人的行为表示疑惑,我不明白为什么有人愿意装 360 和迅雷把自己的文档暴露在云里;我不明白为什么有人给自己的硬盘用强密码加密但是却让 QQ/微信/微话读取自己手机上的联系人;我不明白为什么有人宁愿用 Word 敲一篇满是公式的论文却不愿意花一个小时学一下 LaTeX; 我不明白为什么有人号称能听出水电和火电的区别却不在中英文之间加空格。我只能假设这些人从来没有被优雅的甚至是正常的东西熏陶过,而对美的理解需要长期的熏陶来培养。 简书 觉得我太过矫情和夸张么?我听说很多人愿意用 Medium 的山寨版——简书, 因为它的版面设计考究而优雅。真的是这样么?这是简书的首页: 我一眼睛看出了四个问题: 字体太小,而且用的是宋体。当然用宋体本身没问题,小号的宋体么… 呵呵…… 文字太宽,读起来累 白色图片上放白色文字???设计师是瞎的么?如果图片是会变的,为什么没有 javascript 来调文字的颜色?或者加一个半透明黑色背景也行啊,解决方法太多了。 标题用粗体??这是要亮瞎读者的碳纤维狗眼么?有人说了,大家标题都用粗体啊,连 LaTeX 默认标题都是粗体!呵呵,大家都做的就一定对么? 又有人说了,谁没事闲的看简书主页啊,大家都是进去看文章的。没错,那姑且进去看一眼~~ 以下的例子都是我随便找的。先看标题: 请问设计师: 你是出于什么样的情怀(情怀,Smartisan~~ Get it? 2333…)才会把楷体和 Georgia Bold 放一起? 又是粗体?你跟我的眼睛是有多大仇…… 再看正文: 这里的问题是我对简书最大的槽点。这里有一个二级标题和一些段落,你看看那个二级标题和下面那段的间隔,再看看相邻两段之间的间隔,前者居然比后者还小!!??这是要闹哪样??设计版面时最重要的就是节奏感,我相信只要稍微看过一些排版方面的书就不会设计出这样的版面。不过这里也有简书版面设计上最大的亮点——行的宽度、字体大小和行间距都掌握得非常好,撒花!这里还有一个可以讨论的地方,就是 web 中如何用正确地使用宋体作为正文字体。简书使用了 Songti SC 和 Simsun 来兼顾 Mac 和 Windoze. 但是这两个字体都很细,看起来有点费眼睛。我这里使用了华文中宋,优点是比较粗,但并不是每个机器上都有,而且貌似有点过于粗了……中文字体又太大不能当 web 字体用,真是很纠结…… Web 排版 说到行间距和节奏感,我又有槽可吐了,而且是几个大槽。 传统上,英文中段落之间不空行。段落分割的方法在历史上有很多种,比如有只使用一个分段符(❡ 这种)而不另起一行的,有直接下沉一行但是保持横向位置不变的,还有另起一行但是突出去的(和缩进相反),最后演化到另起一行缩进大概 1.2–1.5em 这样,段之间没有多余的空白。现代中文貌似也是学的西方,段首缩进两个字符,没有多余的空白。我相信你拿起手边任何一本正规的书都是这样分段的。这是因为分段是一种很弱的逻辑分割,很多时候在写作中都会有可分可不分的情况。而多余的空行迫使你停下来,喘口气,再继续读,从而打断你绵绵不绝的思绪。所以一般这样的空白都用在标题、引用、引用诗歌的周围,或者说是用在需要让你“切换一下环境”的地方。 但是到了 web 里,主流却变成了段之间空行,甚至出现了简书(嗯,就认准你黑了)那样标题后的空白比段间空白还小的情况,如果说在 html 发展初期没有足够的机制实现正确的分段还可以容忍的话,在现在科技高度发达 CSS 3 高度普及的今天还是用这种分段方法我就不知道说什么好了。每次看到这种空白的地方我都会不由自主地想哽咽一下…… 另一个槽点是文字块的对齐。你再拿起手边的任何一本正规的英文书来看看,沿着文本的右边界从上到下看下去,发现什么了么?丫的右边都是对齐的啊!!你再到随便一个英文网站上看看,傻眼了吧~~ 文本的右边都跟狗啃的一样。有些人可能觉得这是现代科技还不够发达而带来的限制,其实不是这样,和分段的情况一样,只要你的文本块不是特别窄,现代科技打造的浏览器已经发达到可以很好地两端对齐了。如果你和我一样,平时浏览以英文内容为主,你可以尝试在你浏览器的全局 CSS 里加这么几行 :::CSS p, li { text-align: justify; hyphens: auto; -webkit-hyphens: auto; -moz-hyphens: auto; -ms-hyphens: auto; } 然后再打开个英文网页看看~~ 我从 Svbtle 这里截了个图 虽然不如 TeX 出来的好,但是完全可以接受。所以当你下次为英文网站设计版面的时候,对于大段的文本内容,不要再给自己找借口不两端对齐。 最后一个槽点,其实现在已经不那么强烈了,就是文本的宽度。文本太宽的话就容易看串行,这个道理再简单不过。可喜的是现在大部分以文字内容为主的新网站在这一点上都做得很好,比如 Medium 和简书。但是仍然有一些老牌网站不知悔改,非得让文本铺满屏幕的整个宽度……(Wikipedia, 说你呢,没错就是你!) 回到开始 有人说了,你吐了这么多槽,还是没有说怎么才能懂得欣赏和分辨 web 排版的美啊! 我觉得只有一个办法,就是把自己多多的浸泡在美中,多读一些关于排版的好书。在此推荐两本强迫症患者必读的圣经: The Elements of Typographic Style. 这本书的版面本身就是教科书式的典范,从字体选用到版面节奏都无可挑剔! The Chicago Manual of Style. 这本书是芝加哥大学出版社的风格指南,在美国享有盛誉。里面不厌其烦地讲解了美国英语文法中的各种细节,比如什么样的名词不能使用复数形式,缩写的大小写怎么处理,缩写要不要加点,什么时候该用分号,blabla… 简直就是强迫症患者的天堂!可以免费在线阅读,实体书的装帧和排版都很考究,值得拥有。 那中英文之间的空格问题该怎么解决呢?我觉得其实最好的解决办法就是在浏览器或者是 CSS 中设计这样的功能,像 Word 那样在中英文之间自动加入合适的空白;如果发现 html 里已经手动加了,就不再加,或者是调整一下空白的大小。所以这样看来,貌似科技还是不够发达…… UPDATE: 發現了這個…… 為什麼你們就是不能加個空格呢?

2014/7/11
articleCard.readMore

Impact of cache prefetching

I am not always interested in the low-level nonsense. But when I am, I write a blog post about it. A while ago a colleague of mine had a discussion with me about our data structure. I was considering using lists instead of arrays for a matrix-like object, and he was objective about it. Eventually he convinced me by reasoning that cache prefetching is advantageous which is very hard to achieve with a linked list. I believed him and put the idea aside. But I knew I would not be really convinced without any experimental data. So I wrote this quick program (part of it): int main() { srandom(time(0)); const unsigned long NElements = 100000000; const unsigned int NRuns = 100; const unsigned int SizeInMB = NElements * sizeof(Type) / 1024 / 1024; std::cout I wanted to see how a loop over array elements can benefit from cache prefetching. First the program loops over an array in an ordered fashion, and then refers to elements in another array randomly. Since random number generation may be slow, I generate the random sequence of array indices before the test. The test function is just the loop that should be measured, Measurement test(const unsigned long n_data, const unsigned long n_run, const unsigned long* indices) { Type* Data = new Type[n_data]; unsigned long Times[n_run]; timeval Begin, End; for(unsigned int Run = 0; Run On my 2011 Macbook Pro, the test results are Size of structure: 381MB Time of reference in order: 107.156 ± 18.2239ms (100 samples) Time of reference at random: 2204.8 ± 124.422ms (100 samples) These numbers, my friends, is a textbook example of what are “significantly different”. And also kids, a measurement without error is not meaningful in anyway; remember that. I compiled the program with clang++ -O2. I got similar results with -O1 and no optimization, as well as with GCC on Linux. UPDATE: I made a statistical mistake in my program. I should have used standard error instead of standard deviation as the error estimator of the average run time. As a result the error on those numbers should be smaller by a factor of 10.

2014/7/10
articleCard.readMore

贴呀贴呀贴标签

前几天升级 OS X Mavericks, 发现我的 Aperture 洗白了,于是决定就用 Aperture 管理照片了,什么时候有白白的 Lightroom 再说。把照片导入到 Aperture 以后发现关键词全乱了,以前在 Lightroom 里的关键词层级没有了,而且由于 Aperture 自带一套默认关键词,照片的关键词都绑在了那些默认的上面,很不爽。Aperture 还有一点很诡异,就是如果一个关键词不是顶层关键词,那它这辈子都不可能是顶层关键词了, 我试了半个小时都没试出如何把一个关键词从下层变成顶层…… 于是我毅然决定删掉所有的关键词重做。这次照片比较多,而且也略有经验,我找了一套比较简单地规则来管理关键词: 关键词树状分类,顶层按照 5W 的原则规划,简单地说就是小学作文里的“时间地点人物事件”,还有个“为嘛”。 非叶子的关键词可以出现在照片的元数据里,也可以不出现,仅作分类用。所有可以出现在元数据里的关键词都首字母大写,除非是“iPhone”这种诡异的专有名词。不出现在元数据里的关键词一律小写。 可以出现在元数据里的关键词名词一律使用单数,动词一律使用正常语态。所以表示照片主体正在拍照这个意思的关键词是“Shoot”(射),而不是“Shooting” (啊大大大大大大)。 于是现在我的顶层关键词是 metainfo People place shooting subject technicality time 最新的关键词列表在这里,有这样一个复杂的关键词结构的直接后果就是给照片分陪关键词的过程变得很冗长,我滑了几个小时过完了所有的照片,但大部分照片只是很粗略的整理一下,只对少数几个 projects 仔细地分陪了关键词。 做完这件事以后我又想到另外一件事,就是 Mavericks 里新加入的 tags 元数据。我在考虑要不要把我的文件都贴上 tag. 这件事的困难有三点,第一是我的文件比照片要多,所以工作量更大;第二是想出一套可行的 tags, 能大体描述所有文件的所有重要属性;第三是这个 tags 没有树状结构,完全是平的,所以管理起来会比较困难... 目前在网上还没发现有人贴出自己的 tag 策略,所以这件事暂时搁置。

2013/10/30
articleCard.readMore

炖牛肉

炖牛肉是人民喜闻乐见的一种文化活动,两年前我曾经写过一篇《炖牛肉》,不过当时就是葱姜蒜和牛肉一阵炖,做工比较粗糙。经过两年的科研攻关,炖出的牛肉已经有了长足的进步,现将炖牛肉 2.0 发布。炖牛肉 2.0 是牛的一个 major update, 推荐所有用户升级。 需要材料: 牛肉一箩筐,我一般一顿吃 1lb 左右。 胡萝卜(或土豆)一箩筐 西红柿三个 蘑菇数个 黄油一小块,我一般放大概 2–3 cm³. 洋葱一个,如果比较大的话就半个也行,我就是把洋葱当大葱用。 姜一大段 蒜五瓣 料酒小半勺,勺是那种做菜用的大勺,煮饺子用的那种,下同。 生抽两勺 花椒一撮 大料一个,我不喜欢吃大料,所以放得少,但还是要放的 香叶四五片 胡椒粉,我用的是黑胡椒,不知道白胡椒怎么样。 可选材料: 辣椒,干的湿的都行,我一般每次放一吨。 青花椒,超香的~~ 我一般每次放一吨。 列完了发现材料居然有这么多... 不管了。开做之前先把牛肉切成块,用凉水泡泡。像我这种偏执狂可以泡个半小时,中间换一次水。然后就可以开始烧水,一开始水放多点,同时可以开始切洋葱神马的。把蒜剥了,姜我一般削皮但不切开。等水开了以后放入牛肉然后盖上盖耐心等待。水再次开了以后上面会有一些很恶的沫子,撇之,这就是为什么一开始要多放点水,牛肉不好的话沫子会很多。撇完以后如果发现水多可以把水撇出去点,最终水比牛肉高个两三厘米就行,不用很多。撇完沫子以后把洋葱、姜、蒜、花椒、香叶、料酒和黄油放进去,这时候锅里就很香了,小心不要过度陶醉。 接下来关小火,让水稍微有一点点开就行,反正大开小开都是 100˚C, 物理知识很重要,没文化真可怕。然后你就可以去打个游戏或者 de 个 bug 神马的,让它炖两个半到三个小时左右,放入蘑菇和切成块的胡萝卜,把生抽也倒进去。再炖半个小时,放入西红柿、胡椒和辣椒,如果你前面那一步不放生抽的话这时候放也行。再炖十分钟,放入盐、味精和青花椒。盐不用放很多,如果你口味淡的话酱油已经够你吃了,不放盐都行。再炖五分钟,就可以出锅了~~ 灭哈哈哈哈!

2013/4/21
articleCard.readMore

五支钢笔

五支钢笔五支钢笔跑得快跑得快…… 这几年我一直在试用各种不同的笔,就是写字用的那种笔,别想歪了!我不喜欢任何用滚珠的笔头,因为太滑了,所以一开始我用铅笔,然后用了几种 felt tip pen, 就是类似水彩笔那种,不过很细,可以写字。今年冬天我回来以后很伤心,决定给自己找点乐子,遂上各大论坛和 blog 一阵浏览,入了一支 Lamy Safari, 发现钢笔这东西好啊,出水刚猛,写字流畅,实乃我辈中人画积分号之利器。但是 Safari 的 EF 笔头比较垃圾,不够光滑还刮纸,画出的积分号不够圆滑,不好。于是又断断续续入了四支笔…… 以下是全家福一张。 五支笔从上到下依次是 Lamy Safari 这个笔在国内被吹得天花烂坠,我满怀希望地买了以后就囧了,神马垃圾塑料啊,是 ABS 么,要是也是最次的那种,比乐高的塑料差远了~~ M 头还不错,挺顺滑的,但还是有点刮纸。这个笔我有两个头,另一个 EF 头就是纯垃圾啊,刮纸刮得跟裁纸刀似的。不好。对我来说这个笔还有一个硬伤,就是尺寸。写的时候不带笔帽就有点短,而且太轻,带笔帽就有点太长了,笔帽那段还嫌重,总之就是不爽。 Kaweco Classic Sport 刚刚入的,F 头。神马垃圾塑料啊,跟 Safari 的差不多。我入这个笔是因为传说笔头很好,很顺滑。试了以后觉得还好,比我的 Prera M 差一些,但起码是同一档次的。问题是我现在用自带的墨会不时地断水啊,过几天改装成 eye-dropper 再试试。这个笔很小也很轻,不过把笔帽装在后面以后手感还不错,笔尖比较软,能劈叉。笔帽是拧上去的,很装逼。 Pilot Prera 我在网上看到这个笔的照片,心想这估计就是用那种很脆的透明塑料做的吧,胆战心惊地买回来以后,拿在手里一秒钟就放心了。塑料的质量很好,而且用料充足,笔杆最厚可能能有两毫米。这个笔也很短,但是很有分量,质量分布得很舒服。这个是 F 头的,写出来线很细,不像前两个,号称 EF 和 F, 写字像毛笔似的…… 总之,这个笔基本上无缺陷了。 另一支 Prera 上一支是 F 头,这一支是 M 头,这是五支笔里手感最好的一个。神器! 三文堂 Mini 三文堂就是 TWSBI, 英文名字的来历是 TW’s Bi… 总觉得那个“bi”很违和…… 这个笔碉堡了!!!用料超级充足,笔杆厚实得跟坦克一样。而且是活塞式上墨啊!!!业界良心啊!!就是笔头一般,不如 Prera, 比 Kaweco 稍好。业界良心! 下面放个样片~~ 纸是 Field Note. 有人问了,墨水呢?墨水在这里~~ 另外前几天翻硬盘的时候不小心找到了去年下的一个电影,Drive. 于是又看了一遍。这个电影的光线和用镜都超好啊,就是剧情狗血了点。去年看的时候我想,这剧情也太假了吧,现在再看,觉得还是挺真实的。有时现实就是既痛苦,又无奈,又狗血,又痛苦,又无奈,嗯。

2013/2/22
articleCard.readMore

Another Statically Generated Blog

Two weeks ago I decided to open another blog. I was tired of Hyde because its codebase is too big for me, so I decided to write my own. So I made Blogsair. It is a Flask application in the core. It uses Flask-FlatPages to process Markdown, and Frozen-Flask to convert the blog to static code. It contains about only 100 lines of Python code. I have used virtually the same template as in the Hyde code. My new blog is in Chinese, which is very different from English typographically, so I had to prepare different CSS codes for it. Now in each post I can specify the language of the article, and the proper CSS will be loaded. One issue was that in Hyde, each post is part of the template, which means one can reference variables in the article. In Blogsair, posts are processed with FlatPages instead of a template engine, so I had to implement a very quick and dirty variable system, so that in a post I can write something like ![The red button](\{\{ url_for('static', filename="img/2012/DSC_0054.jpg") \}\})

2013/1/13
articleCard.readMore

Wallpaper in a Encrypted Volume

The Problem I have three volumes in my Mac. I decided to encrypt the two non-boot volumes just for the sake of it. So I did that. The next time I booted into the OS, I was greeted by an ultra-friendly dialog box asking for passwords. I did not want to do that every time I restart, so I let it remember the passwords in keychain. And the next time I restarted, I found my fine wallpaper was replaced by the default galaxy-in-space image, which I did not really fancy. Solution Number One I knew the reason was that the encrypted volumes were mounted after the desktop was loaded. And given the stuborn-ness of Mac OS, it is probably humanly impossible to change that order. So I looked for an alternative — writing a script to kill the Dock application, which automatically reloads the desktop, and somehow running this script when I log in. If I am lucky enough, the script might be run after the encrypted volume is mounted. Here is the script, :::Bash #!/bin/sh exec killall Dock I ran it to confirm its correctness. Then I added it to my “Login Items” (try a better name next time, Apple). But, it did not work. Apparently it was executed before the volume was mounted. Solution Number Two I had to search on the web to start my second attempt. This time it was a more apple-ish method. One can attach a script to a directory in Mac by setup a “folder action”, so that when there are some changes to that directory, the script gets to run. So in principle I could do this to /Volumes, and when a volume is mounted, the folder action should be done automatically. The problem is I do not like my desktop to flick all the time, so I need to know the mounted volume has a specific name. Noticing “Shared” being the name, I wrote an applescript for that, :::Applescript on adding folder items to this_folder after receiving MountedVolumes repeat with Volume in MountedVolumes if name of Volume is "Shared" then quit application "Dock" end if end repeat end adding folder items to I did not know if this is correct. I did not even read it a second time, and I suggest you avoid doing that as well. Applescripts are so purely ugly, one would have nightmares after reading too many of them. If one insists on getting some nightmares, I recommend Peskin — at least it has much more contents. So I attached the script to /Volumes, and tried to unmount and mount the encrypted volume. Nothing happened (well, I mean besides the volume being unmounted and mounted...). Awesome. I did not like this method in the first place. Solution Number Three So I did more search on the web, and found that the daemon launcher in Mac was launchd. It has a bunch of interfaces. One may use launchctl to start or stop a daemon, to list all daemons alive, to list all daemons available, and much more. Daemons are defined with XML files. A feature particularly useful in my scenario is the ability to run a daemon when a volume is mounted. So I created the following launchd job, and saved it as a plist under ~/Library/LaunchAgents, :::XML <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC -//Apple Computer//DTD PLIST 1.0//EN http://www.apple.com/DTDs/PropertyList-1.0.dtd > <plist version="1.0"> <dict> <key>Label</key> <string>org.darksair.refreshdesktop</string> <key>ProgramArguments</key> <array> <string>/Users/corsair/programs/refresh-desktop.sh</string> </array> <key>KeepAlive</key> <false/> <key>StartOnMount</key> <true/> <key>LaunchOnlyOnce</key> <true/> </dict> </plist> And refresh-desktop.sh ran like thus :::Bash #!/bin/sh FileVolList=/tmp/volume-list.txt if [ ! -e ${FileVolList} ]; then touch ${FileVolList} fi if ! grep '^Shared' ${FileVolList} > /dev/null; then ls -1 /Volumes > ${FileVolList} if grep '^Shared' ${FileVolList} > /dev/null; then # Shared is mounted. exec killall Dock fi fi ls -1 /Volumes > ${FileVolList} Then I restarted the machine, and found that several seconds after the encrypted volume was mounted, the desktop flickered, and the correct wallpaper was loaded. Another stupid problem solved!

2012/7/26
articleCard.readMore

Sony NEX-7 Review

I finally pulled the trigger and bought a Sony NEX-7; the most powerful EVIL camera, ’nuf said. Well actually there are a lot to talk about. As mentioned in many other reviews, this camera is extremely versatile. It features three control wheels, six (or five depending how you count) customizable buttons, a solid grip, an awesome EVF, a tiltable screen, a 18 mm flange distance, a flat top with a manly profile, and a movie button with a red dot on it. I have done some quick tests, and the bottom line is, it is a very good camera for people who don’t shoot photos for bread. Craftsmanship To be honest, I’m not impressed by the manufactureing. Although it is a top-of-the-line EVIL, it just does not compete with even the most pitiable SLR. The buttons and switches feel soft and unclear in comparison with my Nikon D40. There are also uneven seams through out the construction, among which the most annoying one I found is the one between the battery room door and the body. And—I don’t know how a normal human being can make a decision like this—the hot shoe is made of plastic?? WTF Sony? Last but not least, it seems to me that the three teeth of the lens mount are also made of plastic? Very unlikely, but they are black instead of the usual polished silver that you can find on any other interchangeable-lens cameras, and it does not feel as cold as other metal parts. I have already said a bunch of bad things about NEX-7. But notice, that I’m paranoid about craftsmanship—very much so. It is quite likely that when you get one of these in your hand, you feel nothing but the opposite of mine. And I have read a number of reviews that praise the construction of this camera. Handling I don’t expect it to compete with SLRs, and I have never handled any other EVIL cameras before, so I cannot compare. But overall the handling is very good. I can naturally hold the camera single-handedly and let my thumb rest on the slope next to the movie button. And I didn’t experience the accidental movie recording problem that happened to many. I am currently using a Voigtlander Ultron 40mm f/2 SL II with Nikon mount, which is a heavy mixture of metal and glass. It makes the camera unbalanced in my hand, and extremely awkward when shooting with one hand. Placement of buttons and wheels are not bad. They are distributed with enough space in between. The back wheel is a bit hard to reach when shooting, but it’s alright. The EVF In the official specification, the EVF is said to be with XGA resolution, and “2359k dots”. Sony is being a little dirty here, because XGA means 1024 × 768 ≈ 800 k pixels. Apparently Sony counts each single LED as a dot, and thus 3 dots form a pixel. Who cares whether regular customers understand, right? But leaving marketing behind, I have to say the EVF on the 7 is awesome. It is very bright. Unlike LCD, black in OLED is actually real black; and that makes it also very contrasty. The color representation is extremely good, probably only a tiny little bit warm. I didn’t pay any particular attention, but I couldn’t notice any lag. When shooting in dark, the EVF is noisy, as one should expect, and is still very usable. Image quality Simply put, there is nothing wrong with NEX-7’s image quality. It is not a Leica killer, or a killer of any full-frame. The noise level is descent among APS cameras, especially so considering the sheer amount of pixels it has. ISO1600 is usually usable, although the noise arises pretty early at ISO200. What shines is its giant dynamic range at highlight. Pulling by 4EV (note to self that no one else would understand: not “eV” you moron...) is a no-brainer on this camera. In the following photo, the sky was originally pure white, because I metered on the road sign, which was in shadow. I was able to pull tons of information out of it. On the number of pixels, it does have 24M of them, but you’ll probably need a ultra-sharp lens and a tripod to make them count. And people who really need that many pixels won’t buy this camera. This camera does an excellent job on white balance under incandescent light. The output is tinted with a natural and subtle warm tone, which is extremely pleasing to look at. The gradient from grey to highlight is soft (“creamy”). Other factors Currently the only descent E mount lens is that Zeiss 24mm f/1.8, but it is not worth the price in my opinion. However, this is not really a problem. With the 7’s small flange distance and focus peaking, what we are talking about is a camera born to be used with third-party manual lenses. And in reality, using the peaking feature is indeed pure joy. (Split screen sucks...) // More to come (maybe)... Conclusion Pros: Easy and comfort to handle Giant dynamic range Awesome EVF! Tons of manual lens to choose Good white balance at night Cons: Not all metal Craftsmanship suffers a little bit Shutter sound not gentle enough

2012/4/26
articleCard.readMore

A Statically Generated Blog

Why move? I have been using WordPress since prehistory, and it served me well. I watched it grow from version 1, when it was still a simple and somewhat elegant blog system, to a huge and cluttered CMS as it is now. And now it is time we part ways. I don’t like PHP PHP is big. Too big. The interpreter takes more than a 100MB of memory when running, and my web-hosting virtual machine only has 500MB of it. I have to kill my web server in order to do an aptitude upgrade. I cannot get rid of PHP completely though. I have two other (secret) blogs running on WordPress. I’m too lazy to transfer them to something light-weight, for now. And I have a PHP photo gallery, which I do plan to move later. But at least I’ll do what I can to minimize my PHP dependence. It needs a HTML overhaul The web has changed much since I created my old blog. Now HTML 5 is mostly usable, and CSS 3 is, errr…, somewhat usable. And they are very cool! The theme of my WordPress blog was written in HTML 5, but it is getting old. It needs a restyling. Managing a blog in a web interface sucks It is slow, and it is not Emacs. Not much to say here. Styling I focused on typography when I styled this blog. Some features are Fully justified text Text justification has been a big pain for the web. Since bad justification can be really really bad, most web pages just do it ragged right; and, most unbearably, make text hyper-wide (I’m looking at you, Wikipedia). For this blog, I want to achieve at least reasonable justification by enabling hyphen in CSS, with something like :::CSS p, li { text-align: justify; hyphens: auto; -webkit-hyphens: auto; -moz-hyphens: auto; -ms-hyphens: auto; } There are still occasional bad lines, but mostly ok. Proper paragraphs I have always been wondering, why all most all web pages seperate paragraphs with extra leading and no indentation. To me that extra white space is a rhythm breaker. Following typographic tradition, I eliminated that, and added 1.2em indentation to paragraphs that do not follow a heading. :::CSS p { text-indent: 1.2em; margin-top: 0pt; margin-bottom: 0pt; } p:first-of-type, h1 + p, h2 + p, h3 + p { text-indent: 0pt; } And also by tradition, 0.5em extra leading was added between paragraph and style changers including lists, quotes and codes. Typefaces Typefaces were carefully chosen. (Well actually they were not; I just chose the fonts I liked XD). Main text: the awesome FF Scala, or Mate (free alternative). Supplementary sans-serif: the legendary Futura, or Fabrik (free alternative). Remarks on the new blog Hyde, and another Hyde I did not know that until I finished the template of this blog, but there are two major “flavors” of Hyde! The old version was a straight forward and brutal set of Python scripts, which is the way I like; and the new version is more complete, polished, and convenient, but its site configuration file is not in Python! This, in my opinion, is not tolerable for this kind of Python program. So I’m glad I am using the old one. A better CSS language There are a bunch of languages that extend CSS, and add features like variables, macros, etc. I chose SCSS. I would like to use LESS but I don’t have Node.js installed. Local management One thing I like about this static business is that I can locally manage everything. I use Emacs to edit posts, and a Makefile to create new post, regenerator the site, and upload it to remote server. Todo Disqus Livefyre comment system ✓ MathJax ✓ \(\alpha^2 \lambda^2\) Category ✓ Sidebar ✓

2012/4/5
articleCard.readMore

BCM4331 Native Driver for Linux

This is an update to the new Macbook post, in which I said I had to use Ndiswrapper to drive the BCM4331 wireless adapter. Now there is a native solution here. The steps are explained in detail. However I was not able to use patched compat-wireless-2011-08-27. In 2.6.39 (ck-patched) kernel, it refused to detect any wireless network; in 3.0 kernel, it simply wouldn't load. Modprobe complained about unknown symbols. Today I tried an updated version of compat-wireless, which was labeled as 2011-09-27, and it worked in both kernels. Note that the patches mentioned in the link above are not needed anymore, and also that since kernel.org has been down forever, I downloaded the compat-wireless module from here. I made some PKGBUILDs for the firmware of BCM4331 and compat-wireless based on the PKGBUILD of compat-wireless-patched. Here they are~~ :::Bash pkgname=b43-firmware pkgver=5.100.138 pkgrel=1 pkgdesc='Firmware for BCM43xx wireless adapters' url='http://wireless.kernel.org/' arch=('x86_64') license=('GPL') depends=() makedepends=("b43-fwcutter") source=("http://www.lwfinger.com/b43-firmware/broadcom-wl-${pkgver}.tar.bz2") sha1sums=('21691a8c99c66f58d18f863ee43593d1633b454c') # install=install build() { msg "Nothing to build..." } package() { mkdir -pv "${pkgdir}/lib/firmware" cd "${srcdir}" b43-fwcutter -w "${pkgdir}/lib/firmware" \ broadcom-wl-5.100.138/linux/wl_apsta.o } Another one :::Bash pkgname=compat-wireless pkgver=20110927 realver=2011-09-27 pkgrel=1 pkgdesc='Compat wireless driver, enabled for b43 support.' url='http://wireless.kernel.org/' arch=('x86_64') license=('GPL') depends=('linux' "b43-firmware") makedepends=('linux-api-headers' 'linux-headers') source=("compat-wireless-2.6.tar.bz2") sha1sums=('e6b6fd94aa6e9442c1ff0daaf09e0690866ce787') install=install build() { cd "${srcdir}/${pkgname}-${realver}" scripts/driver-select b43 if grep '# CONFIG_B43_PHY_HT=y' config.mk; then sed -i 's/# CONFIG_B43_PHY_HT=y/CONFIG_B43_PHY_HT=y/g' config.mk fi make } package() { cd "${srcdir}/${pkgname}-${realver}" make INSTALL_MOD_PATH="${pkgdir}" install-modules find "${pkgdir}" -name '*.ko' -exec gzip -9 {} \; install -d "${pkgdir}"/usr/sbin install scripts/{athenable,athload,b43enable,b43load,\ iwl-enable,iwl-load,madwifi-unload} \ "${pkgdir}"/usr/sbin/ install -d "${pkgdir}"/usr/lib/compat-wireless install scripts/{check_depmod,modlib.sh} \ "${pkgdir}"/usr/lib/compat-wireless/ install -d "${pkgdir}"/lib/udev/rules.d install udev/50-compat_firmware.rules \ "${pkgdir}"/lib/udev/rules.d/ install udev/compat_firmware.sh \ "${pkgdir}"/lib/udev/ }

2011/10/3
articleCard.readMore

Reference Managment & Freedesktop

I have always just put downloaded papers into seperated directories for later use. I name them in the form of "year - title". But I know at some point, I will need a database to manage all of these pieces with odd-looking names. And I have reached this point today. The stuff I need is simple: Only store locations of file in the database, instead of the files themselves Tag support Project/topic/whatever tree Open PDF and others with program of my choice Ability to change the location in which I store all the files. I was fully-prepared to write my own paper manager when I first thought about this. But nonetheless I read this Wikipedia entry, and looked into each free (as in “freedom”) reference manager it mentioned. Sadly most of them were search-based. While there was nothing wrong with that, I would just use Google Scholar when I need to search. And then there were few left. Zotero was one of them. The problem of it to me was being too popular, and popular, in my mind, is somewhat equivalent to slow, big, and ugly-written. I thought I should check it out just to have an idea what features a full-featured reference manager has. So I installed it, and fired it up. Its biggest advantage, as is advertised, is the ability to utilize the address bar to quickly add articles, which is totally useless to me, because I hide the space-wasting address bar. It supports the first three things I need. I am not sure about the last one, but since Zotero uses Sqlite, I can probably manipulate the database itself to do that. The issue is the second last one in the list. When I chose to open a PDF in Zotero, it oddly opened Inkscape. There was no option in its preference panel to change this behavior. First I thought naturally that it may used Firefox to open anything. But no, I set Firefox to ask me when encountering a PDF. And it would be totally stupid that Zotero was hard-coded to use Inkscape. So there was only one possiblity—it used “system defaults”. As we all know, Linux itself does not know how to open a certain kind of file. This behavior is governed by desktop environments, which all follow the Freedesktop standard. When a file is opened by xdg-open (or gnome-open, etc.), its mime type is checked, and it is opened according to the corresponding desktop file. The mime type of a file can be queried with xdg-mime query filetype FILENAME And its corresponding desktop file can be queried with xdg-mime query default MIMETYPE Then to set a different desktop file to be associated with a mime type, do xdg-mime default DESKTOP MIMETYPE in which DESKTOP is only the basename of the desktop file. The full name will be looked up inside directory applications inside $XDG_DATA_DIRS and $XDG_DATA_HOME. So it is only a matter of writing a proper desktop file for my home-made, super fast and totally awesome PDF viewer to solve the PDF opening issue in Zotero. I copied and modified an existing desktop file for Evince, and it worked well. I am still considering writing my own reference manager, but Zotero has to do for now. BTW, Zotero can show the current selected entries in a file manage, and for that I installed Thunar, the file manage in Xfce. With the A New Hope GTK theme and the Faenza icon theme, it looks awesome.

2011/8/29
articleCard.readMore

New Macbook Pro

So, I bought myself a new 15 inch Macbook Pro. It’s the 2011 model Macbook Pro 8,2. It has OS X Lion pre-installed, which is also new and shiny. But I was most interested in fitting an Arch Linux into it. I burned a Arch Linux install CD, and booted from it. Surprisingly it complained about not finding root fs (as far as I can recall) which should be the CD itself. Google showed that the DVD-rom device cannot be identified by the kernel when booting in BIOS mode (as oppose to EFI mode), even though Grub knows it[1. https://bbs.archlinux.org/viewtopic.php?pid=935983#p935983, http://ubuntuforums.org/showpost.php?p=10836560&postcount=442]. I ended up using Archboot. It still couldn’t find the DVD, but it seemed to load itself into the RAM first, so it didn’t need the DVD to load the kernel. Then I could continue the installation according to this guide. OS X Lion comes with a recovery partition of about 650MB. So before installing Linux, three primary partitions were already occupied (The EFI partition, Lion itself, and the recovery partition). This left me with no choice but to make a last primary partition for /boot. After that, I made three extended partitions for a shared space, /home, and root. As a side note, usually the kernel doesn’t have to be in a primary partition; however rEFIt may have problem booting the Linux from an extended one. There are generally two ways to boot a Linux on a macbook: directly boot in EFI mode, or use rEFIt to boot in BIOS mode. Booting in EFI mode requires to install Grub2 as a EFI application, which is described here and here. Basically I needed to checkout the newest Grub2, compile it with EFI support, make a EFI image with grub-mkimage, and copy all the stuff to the EFI partition. Once that is done, I may either load it from rEFIt, or bless it and boot directly from it. Booting in BIOS mode means to install Grub into /boot, and set the boot flag on that partition, then rEFIt can boot it as a legacy OS. I got both setup work. However, as expected, in BIOS mode, the DVD-rom is not identified. And the Intel graphic card is totally missing. In EFI mode, the Radeon graphic card has “corrupted rom”, and I haven’t got the Intel card working in Xorg. In both mode, I can’t have multitouch, the fn key doesn’t work[2. https://bbs.archlinux.org/viewtopic.php?id=123749], and I also can’t adjust the screen brightness (I succeeded once, but never did after that). The BCM4331 wireless adapter doesn’t have a native driver yet. I was able to find a windoze driver for Ndiswrapper, but it randomly (with a good possibility) freezes when modprobing. UPDATE: I got wireless work natively[3. BCM4331 wireless native driver].

2011/8/10
articleCard.readMore

Ath9k as AP in Arch Linux

I have a Macbook with an Atheros AR5008 wireless network adapter, which is supposed to be able to act as an AP. Some time ago I used Madwifi driver for it. It includes a tool that can create multiple “virtual adapters” and I could use one as an AP to share either my wired or wireless network. However now I use the stock ath9k driver in the kernel, and I need my Macbook to share its PPP connection wirelessly with my iPhone. It is claimed that ath9k has the ability to put my adapter into master mode, but I could not just do iwconfig wlan0 mode Master to get it. After some research, it looked like to me that ath9k did that by implementing the hostap driver, which was utilized by the hostapd program. Then I found this document, that described all that was needed to be done. I do not need DHCP, so that falls into four steps. Set up my wireless adapter, my PPP interface has IP address like 118.207.x.y, so I can safely use 192.168.1.0/24 as my wireless LAN IPs. # ifconfig wlan0 192.168.1.1 netmask 255.255.255.0 Config hostapd by editing /etc/hostapd/hostapd.conf. Change interface and SSID. Then start hostapd daemon by # /etc/rc.d/hostapd start Enable IP forwarding by # echo 1 > /proc/sys/net/ipv4/ip_forward then optionally make it permanent by editing /etc/sysctl.conf and setting net.ipv4.ip_forward to 1. 4. Actually forward IP packets with iptables, # iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERADE

2011/6/11
articleCard.readMore

Transfer to VPS

I have moved most part of my website from Hostmonster to Burst VPS. The plan I choose has 512MB ram. When I first logged into the Debian 6 system and did a aptitude upgrade, it crashed with a message saying not having enough memory. I checked the memory usage. It was more than 300MB, 250MB of which was taken by Apache. So I decided to use Cherokee instead. Cherokee is a fast and efficient HTTP server, and it obviously does not support Apache’s .htaccess files. Most server-side programs (well, most PHP programs) ship with such a file with some rewrite rules in it. A common set of such rules goes like Redirect `/prefix/` to `/prefix/index.php`. Serve `/prefix/blabla` if this `blabla` is an actual file, otherwise redirect `/prefix/blabla` to `/prefix/index.php/blabla`. These rules apply to all the PHP programs I am using, including Wordpress. Sometimes an extra “?” is needed immediately after index.php in the last rule. How these rules can be implemented in Cherokee depends on whether the program is in a virtual server or a sub-directory of a virtual server. In most cases, this means to see if a program is in the root directory of a web site. If the program is directly in a virtual server, the first rule is covered by the directory indexes setting of the virtual server; otherwise it has to be a behavior rule of the virtual server. A simple path rule that substitutes (.*)/ to $1/index.php will do. The second rule can be implemented with a logic and of a directory and a file exists match rule, that servers static content. The third rule can be done with a regexp matching of /prefix/(.+) and substitute it with /prefix/index.php/$1. Cherokee has a Wordpress wizard which does one more rule between the first and the seond, if Wordpress is in a sub-directory of a virtual server. It set the document root to that sub-directory. And this rule is non-final. I am also changing my gallery program from Gallery to Piwigo, because Gallery 3 is probably not very non-Apache-friendly. We will see how that works out.

2011/5/27
articleCard.readMore

DWM2 Breeding Searcher

写了一个用来查看 Dragon Warrior: Monsters 1/2 (勇者斗恶龙怪物篇)孵化数据的 web 程序。可以查询某种怪物可以用什么孵出来,也可以查询某种怪物可以用来孵什么~~ 比如要查询 KingSlime,可以进入这里。所有的怪物都是交叉引用的,查起来非常爽~~ 写这个程序主要是体力活。首先写个程序把这篇文章 Breeding 一节的文本 parse 一下,存在一个字典里,剩下的就是 Django 了。

2010/10/20
articleCard.readMore

今日十大

今天小百合十大的前三条是这样的: 第二条的内容是这样的:

2010/7/23
articleCard.readMore

RPN Calculator for iPhone

从拿到 iPhone 的第一天起,我就在不断地寻找好用的 RPN 计算器。我的要求是 类似 Emacs Calc 的进栈出栈方式 无限大的堆栈 要牛逼 我一直使用的都是一个 HP i41CX 模拟器。它基本符合第一条,但是不符合第二条:它的堆栈只有四层,而且最顶层还就是你正在输入的这个。不过它非常非常得符合第三条,看看这个计算器的像板砖一样的手册就知道了。这个计算器也有一些不便,它实在是太复杂了。比如他默认的键盘配置上没有切换弧度和角度的键。键绑定是可以设的,但是我一直没有搞明白怎么设...  同样因为这个原因,我一直不知道怎么算双曲三角函数。其他的 RPN 计算器要不就是操作方式诡异,要不就是功能太少。所以昨天我终于决定自己写一个计算器。 奋斗了两天以后把四则运算都搞定了... -_-  在 iPhone 上开发程序还是很方便的,和在 Mac 上差不多,熟练了以后写界面用不了太多的时间,而且 Interface Builder 做 prototyping 也非常得爽。我的时间主要都浪费在用 UITableView 显示一个堆栈上。UITableView 就是一个和菜单差不多的可选择的列表,几乎每一个 iPhone 程序里都能看到。但是这个东西必须要有一个符合某种特定协议的数据源...  我曾经一度都想自己用 label 和 UIScrollView 实现一个这种列表了...  不过最后搞定以后发现这个东西还是挺爽的,并且附赠动画效果~~ 在 iPhone 上开发程序需要花 $99 买一个许可证。... ... ...... 噢,不对,说错了,是苹果声称你需要买一个,实际上你不需要。免费开发程序的代价就是开发出来的程序只能在 jailbreak 过的 iPhone 上运行。当然这其实没什么,因为各种迹象表明,没有 jailbreak 过的 iPhone 的使用价值其实就和一个板砖差不多。默认情况下,如果你没买这个许可证,Xcode 是不会让你把程序往 iPhone 上传的,只能在模拟器里运行。要想在 iPhone 里运行, 当然要先 jailbreak 照着 Compiling 一节做 Replacing codesign with `ldid`,这一节貌似没什么用,我从来没有成功的运行过 `ldid`,不过我还是做了。 给 iPhone 装 AppSync 补丁。很多 Cydia 源里都有,比如 hackulo.us 源。 编译时使用自己生成的那个许可证。 关于调试,在开始使用 Linux 之后,我就再也没有使用过任何调试器,只使用 printf(及各种语言里的等效的函数)。Objective-c 里是有 printf的,但是比较方便的做法是使用 NSLog()。运行的时候在 Xcode 里选择 Run -> Console,可以看到输出。顺便提一下,Objective-c 的标准库还是很牛逼的,嗯,NSString, NSNumber, NSArray, ...

2010/6/27
articleCard.readMore

Typescripts Rearranged

今天好好看了一下 ConTeXt 的新文档 co-fonts,然后把平时常用的字体都写成 typescript 放到 texmf-local 里。这样以后写作业就不会出现字体定义比文档内容还长的情况了-_-... 首先定义几个 feature sets :::TeX \definefontfeature[latin-smallcaps][smallcaps][script=latn] \definefontfeature [fancy] [language=dflt, script=latn, method=node, pnum=yes, onum=no, kern=yes, liga=yes, dlig=no, zero=no, tlig=yes, trep=yes, protrusion=quality, expansion=quality, mapping=tex-text] 然后定义单个字体的 typescript :::TeX \starttypescript[myCaslon] \definefontsynonym[proserif][name:ACaslonPro-Regular] \definefontsynonym[proserifit][name:ACaslonPro-Italic] \definefontsynonym[proserifbf][name:ACaslonPro-Bold] \definefontsynonym[proserifbi][name:ACaslonPro-BoldItalic] \definefontsynonym[Serif][proserif][features=fancy] \definefontsynonym[SerifItalic][proserifit][features=fancy] \definefontsynonym[SerifBold][proserifbf][features=fancy] \definefontsynonym[SerifBoldItalic][proserifbi][features=fancy] \definefontsynonym[SerifCaps][Serif][features=latin-smallcaps] \stoptypescript \starttypescript[myPalatino] \definefontsynonym[palarm][name:PalatinoLTStd-Roman] \definefontsynonym[palait][name:PalatinoLTStd-Italic] \definefontsynonym[palabf][name:PalatinoLTStd-Bold] \definefontsynonym[palabi][name:PalatinoLTStd-BoldItalic] \definefontsynonym[Serif][palarm][features=fancy] \definefontsynonym[SerifItalic][palait][features=fancy] \definefontsynonym[SerifBold][palabf][features=fancy] \definefontsynonym[SerifBoldItalic][palabi][features=fancy] \definefontsynonym[SerifCaps][Serif][features=latin-smallcaps] \stoptypescript \starttypescript[myOptima] \definefontsynonym[prosans][name:OptimaLTStd] \definefontsynonym[prosansit][name:OptimaLTStd-Italic] \definefontsynonym[prosansbf][name:OptimaLTStd-Bold] \definefontsynonym[prosansbi][name:OptimaLTStd-BoldItalic] \definefontsynonym[Sans][prosans][features=fancy] \definefontsynonym[SansItalic][prosansit][features=fancy] \definefontsynonym[SansBold][prosansbf][features=fancy] \definefontsynonym[SansBoldItalic][prosansbi][features=fancy] \definefontsynonym[SansCaps][Sans][features=latin-smallcaps] \stoptypescript \starttypescript[myFutura] \definefontsynonym[prosans][name:FuturaStd-Medium] \definefontsynonym[prosansit][name:FuturaStd-MediumOblique] \definefontsynonym[prosansbf][name:FuturaStd-Bold] \definefontsynonym[prosansbi][name:FuturaStd-BoldOblique] \definefontsynonym[Sans][prosans][features=fancy] \definefontsynonym[SansItalic][prosansit][features=fancy] \definefontsynonym[SansBold][prosansbf][features=fancy] \definefontsynonym[SansBoldItalic][prosansbi][features=fancy] \definefontsynonym[SansCaps][Sans][features=latin-smallcaps] \stoptypescript \starttypescript[myMyriad] \definefontsynonym[prosans][name:MyriadPro-Regular] \definefontsynonym[prosansit][name:MyriadPro-It] \definefontsynonym[prosansbf][name:MyriadPro-Bold] \definefontsynonym[prosansbi][name:MyriadPro-BoldIt] \definefontsynonym[Sans][prosans][features=fancy] \definefontsynonym[SansItalic][prosansit][features=fancy] \definefontsynonym[SansBold][prosansbf][features=fancy] \definefontsynonym[SansBoldItalic][prosansbi][features=fancy] % No smallcaps % \definefontsynonym[SansCaps][Sans][features=latin-smallcaps] \stoptypescript \starttypescript[myMonaco] \definefontsynonym[promono][name:Monaco_Linux] \definefontsynonym[Mono][promono][features=default] \stoptypescript 把 ConTeXt Minimals 自带的 px-math 也定义一个 :::TeX % The internal px-math \starttypescript[myPxMath] \loadfontgoodies[px-math] \definefontsynonym[MathRoman][pxmath@px-math] \stoptypescript 最后写几个常用组合 :::TeX \starttypescript[PalatinoOptima] \usetypescript[myPalatino] \usetypescript[myOptima] \usetypescript[myMonaco] \usetypescript[myPxMath] \definetypeface[PalatinoOptima][rm][serif][myPalatino][default] \definetypeface[PalatinoOptima][ss][sans][myOptima][default] \definetypeface[PalatinoOptima][tt][mono][myMonaco][default][rscale=0.8] \definetypeface[PalatinoOptima][mm][math][myPxMath][default] \stoptypescript \starttypescript[PalatinoMyriad] \usetypescript[myPalatino] \usetypescript[myMyriad] \usetypescript[myMonaco] \usetypescript[myPxMath] \definetypeface[PalatinoMyriad][rm][serif][myPalatino][default] \definetypeface[PalatinoMyriad][ss][sans][myMyriad][default] \definetypeface[PalatinoMyriad][tt][mono][myMonaco][default][rscale=0.8] \definetypeface[PalatinoMyriad][mm][math][myPxMath][default] \stoptypescript \starttypescript[CaslonMyriad] \usetypescript[myCaslon] \usetypescript[myMyriad] \usetypescript[myMonaco] \usetypescript[myPxMath] \definetypeface[CaslonMyriad][rm][serif][myCaslon][default] \definetypeface[CaslonMyriad][ss][sans][myMyriad][default] \definetypeface[CaslonMyriad][tt][mono][myMonaco][default][rscale=0.8] \stoptypescript 把这些写成一个文件扔到 textmf-local/tex/context/base 里,然后 luatools --generate; context --make。测试: :::TeX \input type-mine \usetypescript[PalatinoOptima] \setupbodyfont[PalatinoOptima, roman, 12pt] \setuppapersize[B5][B5] \setupinterlinespace[line=1.4em] \starttext Serif test 1234567890. {\ss Sans test}. {\tt Typewriter test.} {\it Serif test 1234567890. {\ss Sans test}.} {\bf Serif test 1234567890. {\ss Sans test}.} $M_{ath} \times t^{est} = 1234567890.$ \placeformula \startformula \widetilde{G}(\vec k, \omega) = \int_{-\infty}^{+\infty} e^{i(\vec k\cdot \vec x - \omega t)} G(\vec x, t)\, {\rm d}^3 \vec x\, {\rm d}t \stopformula \stoptext 效果如图 PalatinoCaslon

2010/5/13
articleCard.readMore

Code Hilighting in ConTeXt

今天需要排一个带 Scheme 代码的文档,里面还有点数学公式,所以决定用 ConTeXt。正好前几天 Steamedfish 同学跟我说过 ConTeXt 可以读取 Vim 的语法加亮,决定看一看。 Google 了一下之后发现 ConTeXt 是使用一个叫做 t-vim 的 module 来干这件事的,我使用的 ConTeXt 发行是 ConTeXt Minimal,于是进入 ConTeXt 的安装目录,更新 ./first-setup.sh --extras=t-vim 然后随便排了一个代码。ConTeXt 报错 VIM - Vi IMproved 7.2 (2008 Aug 9, compiled Mar 8 2010 22:56:09) Garbage after option argument: "-u NONE -e -C -n -c "set tabstop=8" -c "syntax on" -c "set syntax=scheme" -c "let contextstartline=1" -c "let contextstopline=0" -c "source 2context.vim" -c "wqa" "009-vimsyntax.tmp" " 哭了... 这不是要整死我这个 Vim 白痴么... 经过无穷多小时的 google,我终于认识到“Garbage after option argument”错误表示 Vim 的参数有错... 看来要改 t-vim 的代码了。于是打开 t-vim.tex,一看又哭了... 一个 macro 都不认识,这不是要整死我这个 TeX 白痴么... 经过 3000+ ms 的搜索,我终于认识到问题出在 t-vim.tex 的第 344 行: :::TeX {\executesystemcommand {mtxrun --verbose --noquote bin:vim "-u NONE % No need to read unnessary configurations -e % run in ex mode -C % Set compatibile -n % No swap % -V10log % For debugging only, will go away later. -c \shellescapedquote set tabstop=\@@vstab \shellescapedquote\space -c \shellescapedquote syntax on\shellescapedquote\space -c \shellescapedquote set syntax=\@@vssyntax\shellescapedquote\space -c \shellescapedquote let contextstartline=\@@vsstart\shellescapedquote\space -c \shellescapedquote let contextstopline=\@@vsstop\shellescapedquote \space -c \shellescapedquote source kpse:2context.vim\shellescapedquote\space -c \shellescapedquote wqa\shellescapedquote\space \shellescapedquote#1\shellescapedquote\space "}} Macro \shellescapedquote 后面的 \space 会在文件名(#1)的后面加上一个空格。而 mtxrun 会把这个空格当作参数的一部分??!!!于是 vim 就会收到一个很诡异的参数而报错。所以我首先想到的解决方法就是把最后那个 \space 去掉。然后发现编译时最后的那个引号(\shellescapedquote)居然就没了,还是出错... 于是我怒了,毅然决定把 mtxrun 换成无敌的 Bash。 :::TeX \def\runvimsyntax#1 {\executesystemcommand {bash -c "vim -u NONE -e -C -n -c \shellescapedquote set tabstop=\@@vstab \shellescapedquote\space -c \shellescapedquote syntax on\shellescapedquote\space -c \shellescapedquote set syntax=\@@vssyntax\shellescapedquote\space -c \shellescapedquote let contextstartline=\@@vsstart\shellescapedquote\space -c \shellescapedquote let contextstopline=\@@vsstop\shellescapedquote \space -c \shellescapedquote source /home/corsair/software/context/tex/texmf-context/tex/context/third/vim/2context.vim\shellescapedquote\space -c \shellescapedquote wqa\shellescapedquote\space \shellescapedquote#1\shellescapedquote\space "}} 宇宙终于又开始正常运行了。

2010/4/2
articleCard.readMore

春节

把房间整理了一下,准备过节。【全文】

2010/2/16
articleCard.readMore

关于 Photoshop

这几天我给一个同学看我的照片,他听说我用了 PS 以后大喊:“You ruined your photos man!  Don't do it!” 本来我想以中学作文的形式来写这个东西的。写了一半发现没必要,因为有些东西太显然了。所以我决定这么写: 摄影是一种艺术,我的目标是艺术(有没有达到是另一回事哈) 艺术是用来让人(别人)深思的 制作艺术的过程不能让人(别人)深思 艺术品的艺术价值与制作过程无关,只与内容有关 另外 暗房和 PS 都是 post-processing 胶片机和 DC 都是照相机 刻活字和 Fontforge 都是字体设计 排活字和 TeX 都是排版 用笔写和用计算机写都是写作 手算和 Mathematica 算都是计算 乱摸和在网上使用挑逗性言论都是性骚扰 还用再举例么? 最后 老子就是要 PS,老子就是要狂 PS,老子的 PS 水平巨高,老子能把照片 PS 得巨贱,怎么着吧你~~?

2009/12/14
articleCard.readMore

听 Muse 新砖有感

我一直认为我不听流行不是因为我高雅,而是因为流行实在过于低俗。我几乎不听非主流摇滚就是我不高雅的最好佐证。[... full text]

2009/11/22
articleCard.readMore

D40 Test

Just bought a Nikon D40 DSLR.  Since today I had an exam, I just did one test to it: night shooting in my very dim room. Shot with the lens in package, under 18mm, aperture-priority, f/3.5, 1/6s, ISO1600.  And white-balanced in Photoshop, because I only have two light bubbles that emit yellow white lights.   A portion of the 100% image is here.  I'm more than satisfied with this photo because My room is very dim, very very dim. This was shot under ISO1600, which means D40’s high ISO is awesome. I can hold this camera steadily enough.

2009/11/14
articleCard.readMore

IPhone Jailbreak

正在 Dev-team 忙着整 3.1 jailbreak 的时候,惊闻某大牛已经搞出了 3.1 和 3.1.2 都能用的 jailbreak,Blackra1n。遂装,成功。然后第一件事就是装了个 MobileTerminal 和 OpenSSH,呵呵。不过 jailbreak 了以后还是不能运行自己写的代码,有两个问题: Xcode 只能编译在 simulator 运行的代码,编译 iPhone 上运行的代码还需要 sign。 IPhone 还是需要检查 SHA1 hash。 第一个问题很好解决,编辑文件 /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.1.sdk/SDKSettings.plist,把 CODE_SIGNING_REQUIRED 下面的 YES 改成 NO,然后在 Xcode 里设置项目的 certificate identity 为不需要签名。第二个问题比较麻烦。Cydia 的网站里提到可以在 iPhone 里运行一条命令 sysctl -w security.mac.proc_enforce=0 \ security.mac.vnode_enforce=0 就搞定了。我这里执行以后的确可以运行没有签名的程序了,但是副作用是一旦重启 SpringBoard 就连不上 wifi。不过这个倒是不麻烦,把这两个值都恢复成原来的就行了。其实最好的解决办法是 self-signing。但是我用 codesign 老是出错... 嗯。不废话了,上 pp~~

2009/10/12
articleCard.readMore

误人子弟记

今天上完电动力学课,我去某指定地点答疑。进去时已经有三个小孩在了。其中两个在激烈讨论(这两个好像都比我大...),还有一个闷头做题。然后我自我介绍说我是 lab TA。过了一会儿,那个闷头做题的过来问一道很弱智的电磁学问题。我想我虽然不是电磁学的 TA,但是应付一下也是没问题的,于是就看题目。题目是这样的 两个电荷都是 \(-q\) 相距 10cm。求空间中总电场为零的点。 于是我就很认真的告诉那个小孩,设两电荷之间的一点,距其中一个电荷为 \(r\)。这点的总电场为两个电荷的电场之和 $$\displaystyle E = \frac{-q}{4\pi\epsilon_0}\left[\frac{1}{r^2} + \frac{1}{(10 - r)^2}\right]$$ $$E=0$$ 也就是 \(r^2 + (10 - r)^2 = 0\), 鉴于这是两个平方之和,所以 \(r = 10 - r = 0\), 所以这道题出错了。 下午上数理的时候才反应过来,下课后想去找该小孩,未遂。 郑重告诫各位,刚上完电动量子广相或场论之后不宜思考。思考必死。

2009/9/12
articleCard.readMore

New Theme, with No Change

Not exactly... There are some visible changes. I rewrote the theme of this blog using HTML 5 and CSS 3. Everything seems fine. But can someone please tell me why the following video does not work? (At least not in my Firefox 3.5.) Your browser does not support the `video` element. I tested this theme on Chrome under Windoze, and the video was normal. I don't know what is wrong with my Firefox because it can play many other videos without problem.

2009/8/24
articleCard.readMore

美国初印象

到米国已经三天了,基本上已经不像刚来时那样惊慌。芝加哥的机场有奇形怪状的椅子在超级长的走廊两侧,来到入关的地方,第一感觉是,靠,老外真多啊...  入关时我的 officer 是个印度人,他第一遍问我 where will you study 的时候我还没听懂,囧...  入关以后随着人流来到行李转盘取了行李,然后随着人流走,接着就被一个很胖的黑人大妈拦住了,她一把抢过我的行李,然后冲我喊了一声“F1”,我过了老半天才想明白原来她是让我去 F1 gate 转机,然后我才意识到不知什么时候我已神不知鬼不觉的过了海关了?! 做地铁到 Terminal 1,这里是国内航班的地方,满世界都是老外!并且米国的安检还要脱鞋、解腰带?! 资本主义真是太腐朽了!我一定要多多挖墙脚!然后做一个超级小的飞机来到了超级小的 Lexington Bluegrass 机场,并发现这里取行李的地方同时就是机场的大厅,穿过一道门就直接出去了...  同时我又发现接机的人没有出现,行李也没有出现。于是我去推行李车,准备 DIY 了,然后很窘地发现,所有的行李车都卡在一个轨道里,拿不出来。我心想米国真是先进啊,连行李车都有防盗设施。然后我看见旁边坐这一对白人青年男女,于是就问他们怎么用,他们看了看,然后很有耐心的说,你往里面塞 $3,现金和信用卡都可以,然后就可以用了。我被资本主义的腐朽本质深深地震惊了!正在我很囧的踌躇是否要花这 300 日元的时候,我使用眼睛的旁光看见门口走进来一对帅哥靓女,其中女的手里举着一张纸,上面赫然写着老子的名字!哇嘎嘎~~ 于是我扑过去激动地说 I'm <老子的名字>!,那两个人也激动地说 Hi! How are you~~ ...  然后等了老半天行李,接着就开车走了。(奇迹啊,行李居然没有丢。) 到了外面街上,我又发现,这里的街景完全不陌生啊,和 GTA 里的基本 identical 么~~  连车都很像。街上随处可见各种超大皮卡,muscle cars,在去学校短短的十几分钟里,我居然见到了两辆 Mustang!  然后到了临时宿舍,看门的是一个很 pp 的黑人 mm,估计是打工的本科生。跟帅哥美女道别后,我决定上网,给家人报个平安。本科生宿舍里没有无线网,只有一个 Cisco (!) 的路由器。于是我跑到楼下 ppmm 处,管她借网线,她说没有多余的,我就问附近有没有能免费上无线网的地方,她说你可以去图书馆看看。于是我来到图书馆发现关门了,就在外面找了个隐蔽的台阶,开始上网啦。Kentucky 是个很穷的州,大部分税收都来自农业,所以这里的环境很好,晚上非常安静。后来电脑没电了,我就回去睡觉了。 第二天醒来,感觉很迷茫,就下去逛街。我顺着昨晚黑色 ppmm 的指示找到学校的书店及其入口,刚一钻进去,一个人就冲过来很热情的问我要什么,我说我要网线,他就很热情的把我领到网线处,我就很囧的开始挑。后来想了想,又买了个面包,然后就回去了。中午实在是饿了,于是硬着头皮跑到一个餐馆里,吃了一个汉堡加一大堆薯条。 Some facts: 美国的车很强悍,我见到了 Mustang, Viper, Corvette,和各种敞篷。 这边清晨出来的时候地上会有很多松鼠,不怕人。 薯条是赠品,一大堆薯条也是赠品。 可乐分为大杯,超大杯和小桶。 我的口语真搓阿...

2009/8/9
articleCard.readMore

关于高考加分

刚才吃饭的时候被迫看了 CCAV 的一个辩论节目,主题是要不要取消高考加分。辩论在热烈友好的气氛中进行,在场猴子中一群认为应该取消高考加分,另一群认为不应该取消高考加分,大家各抒己见,畅所欲言。辩论取得了建设性成果,与会猴子一致同意,要么取消高考加分,要么不取消高考加分。 支持不取消高考加分的猴子们大多认为,我国很穷,教育资源有限,分配不均匀,所以对于少数猴种比如金丝猴和猕猴就应该加分。支持取消高考加分的猴子们大多认为,那个... 嗯,我忘了他们的论据了。 我是支持取消高考加分的。原因很简单:加分是一种不公。加分是一种特权,特权和歧视是一对矛盾,马克思爷爷曾经说过,矛盾的两方面互相依赖,缺一不可,所以给特定的猴群加分必然意味着对这些猴子的歧视。对于少数猴种来说,这一点是很明显的。我特别喜欢女权运动,所以我不喜欢女士优先,因为这根本就是对女性的歧视。有些猴说了,那特长生和三好优干加分呢,谁歧视丫了?答:是啊,本来就没猴歧视丫,加个毛分啊??有些猴子又说了,特长生他们多辛苦啊,整天要 xxxx, yyyy, 还要 zzzz。答:他们愿意,你管的着么?有特长猴说了,你看我会弹钢琴,多牛逼阿,应该遭到无情地奖励。答:老子还会 TeX 呢,怎么上头没猴奖励老子啊?有些猴子使用例证法说,发达国家也有加分,比如米国就有越战老兵优先录取。答:战死了还授予烈士呢,给你也授一个?老兵为了国家身心受到了巨大的创伤,所以才有特权,特长生受啥巨大创伤了?另外,作为一个中国猴,我们每只猴的心灵都受到了巨大创伤,所以每只猴都加分好了。 所以,这事咋办呢?其实道理是很简单的,高考是一坨屎,我党拥有的大学们是一坨坨屎,我们是一只只的屎壳郎。

2009/7/19
articleCard.readMore

香格里拉:云与山的彼端

<div><object style="width:480px;height:340px" ><param name="movie" value="http://static.issuu.com/webembed/viewers/style1/v1/IssuuViewer.swf?mode=embed&amp;layout=http%3A%2F%2Fskin.issuu.com%2Fv%2Fcolor%2Flayout.xml&amp;backgroundColor=2e3735&amp;showFlipBtn=true&amp;documentId=090712170111-41383350f752419f93dbc4b2dd87b732&amp;docName=shangrila-20090713&amp;username=Corsair&amp;loadingInfoText=Shangri-La%3A%20%E4%BA%91%E4%B8%8E%E5%B1%B1%E7%9A%84%E5%BD%BC%E7%AB%AF%20(2009-07-13)&amp;et=1247419113124&amp;er=38" /><param name="allowfullscreen" value="true"/><param name="menu" value="false"/><embed src="http://static.issuu.com/webembed/viewers/style1/v1/IssuuViewer.swf" type="application/x-shockwave-flash" allowfullscreen="true" menu="false" style="width:480px;height:340px" flashvars="mode=embed&amp;layout=http%3A%2F%2Fskin.issuu.com%2Fv%2Fcolor%2Flayout.xml&amp;backgroundColor=2e3735&amp;showFlipBtn=true&amp;documentId=090712170111-41383350f752419f93dbc4b2dd87b732&amp;docName=shangrila-20090713&amp;username=Corsair&amp;loadingInfoText=Shangri-La%3A%20%E4%BA%91%E4%B8%8E%E5%B1%B1%E7%9A%84%E5%BD%BC%E7%AB%AF%20(2009-07-13)&amp;et=1247419113124&amp;er=38" /></object></div>

2009/7/13
articleCard.readMore

ConTeXt MKIV

订阅了 ConTeXt 的邮件列表,看的手痒的不行了,下了一个 ConTeXt minimal。这个东西安装极其的方便,这里有详细流程。唯一的不爽是安装以后是一个独立的 TeX 发行版,不能和现有的TeX tree 合并起来。我试过把安装好的目录拷到 ~/.texmf 里,然后设环境变量,但是 LuaTeX 老是说找不到 script,很郁闷... 现在的 ConTeXt 和一年前已经大不一样。对中英混排已经有了一定的支持。我从这里抄了一份测试文档,稍微改了一下,编译出来效果还是很不错的。 注意原文档编译出来是不行的,ConTeXt 不会在中文之间断行。必须要在文件里加入 \setscript[hanzi] 才行。另外 MKIV 的内存占用及其恐怖,编译这个文档用了 148M 的内存。

2009/5/13
articleCard.readMore

关于 IBM developerWorks 里的文章

经常看 IBM developerWorks 里关于 Linux 和 UNIX 的文章,不过大部分都看不懂。我一直以为是因为我太搓了,对 Linux 还不够了解。但是今天看到这篇文章以后,我觉得作者们应该承担一部分责任。 对于 Screen 这个东西,我是比较了解的,也经常在 SSH 的远程 shell 里用,所以我完全没期望看这篇文章的时候会遇到任何困难。但是,我看到文章里的第二个图的时候就愣住了。当然后来我反应过来了,然后对这个图极端的无语。首先,一般的地球人在看这种图的时候大多会从上至下的看。于是先看到一个很诡异的 Window A。WTF is "Window A"?? 如果读者很乖的看了图上面的文字介绍的话,会知道 window A 是一个 shell,再往下看,这个 shell 和一个叫做 Screen session 的云“连着”。很好,再往下,Screen session 和 Remote login “连着”,然后 Remote login 通过 SSH 和 Local login “连着”(原来老子在最底下!)。所以这个图很简单,就是四个连成一条链的东西。鉴于地球人都知道 Remote login 和 Local login 是通过网络连接的,一般的逻辑会自然的推出 Screen session 是一片网络云,window A 在云的另一边的某台主机上,于是恍然大悟:screen 的作用就是通过 Remote login 来管理在更 remote 的主机上的 window(很乖的人前来补充:也就是 shell)。 看懂这个以后,下面的事就顺理成章了。图 3 这个垃圾图和上面的图一模一样,不知道什么意思。图 4 说明 Screen 还可以透过网络云连接多台主机!太强大了!图 5 说明连接多台主机以后可以把 remote login 断掉,而 screen session 和他的 window 们还连着!太和谐了! ... 如何改进?很简单,把图都删了!用文字说明。如果一个地方不需要图,就别随便画个小猫小狗来充数。如果硬要画小猫小狗的话,起码也应该把 screen session 画在 remote login 的里面吧??然后把 windows 画在 screen session 的里面。这才像话。

2009/4/30
articleCard.readMore

Charisma 更新

我的 blog 发布程序 Charisma 更新了。 可以在配置里设置多个 blog,在程序中选择使用 Tag 支持 我平时的需求基本都满足了,下一步可能是加上删除 post 功能。

2009/4/29
articleCard.readMore

写了一个 WP 发布程序 aka. 我把自己侮辱了

在试用 Charm 未遂的情况下,我决定写自己的 blog 发布程序。看了一下 XML-RPC 的资料,发现 Python 对 XML-RPC 的包装极好,深得我心,于是简单的把 WP 的 API 包装了一下,开始想界面怎么写。Charm 使用了风格比较古老的菜单界面,我不是很喜欢。写起来比较简单的非交互式命令行参数界面好像也不是很合适,想来想去决定写一个类似 Mutt 的界面。 我以前从来没有用过 ncurse。看了一点 Python 的 curse 模块文档以后我发现我丫就是一个 curse/terminal 白痴,但我发扬了我党“一不怕苦,二不怕死”的大无畏精神,找到了一个从文档上看很强大的库 Urwid,开始写界面,结果写的痛不欲生,生不如死,flag 和全局变量满天飞... 总算把发布功能写完了。 以下是我写之前对程序的预期: 实现 WP XML-RPC 的全部功能 类似 Mutt 的界面 从配置文件里读取全部键绑定 配置文件里实现多 blog 配置 以下是已经实现的功能: 实现列出 post 和发布新 post 功能 类似 Mutt 0.0.1 的界面(估计值) 硬编码全部键绑定 硬编码 API URI, 用户名和密码 ... 最后套用 Mutt 作者的话:All blog publishing programs suck. This one just sucks the most! Edit: 这是在 Charisma 里编辑的。

2009/4/17
articleCard.readMore

CSS Selectors

CSS selectors 昨天做 blog 的文章首字突出显示,使劲看了一下 CSS 的 selector。Selector 分为 9 类 Type selector, 就是地球人都会用的那种,h1, p 什么的都是。CSS3 里引入了 namespace,也算在 type selector 里。 Universal selector, 就是传说中的通配符 *。 Attribute selector, 我昨天才知道 CSS 里有这么强悍的东西。比如 p[attr=blah] 会选择 <p attr="blah">.  还有很多其他的用法。 Descendant selector, 一个空格,地球人都用的,比如 h1 em 表示包含在 h1 中的 em.  个人认为 CSS3 中的叫法 descendant combinator 更为准确。 Child selector, 一个大于号。貌似很少用。这个也是表示从属关系,和 descendant selector 的区别是 child 只选择直接的下级。比如 <div><p><span>aaa</span></p></div> 中的 span 可以被 div span 选择,但是不能被 div > span 选择。个人认为 CSS3 中的叫法 child combinator 更为准确。 Class selector & ID selector Adjacent sibling selector, 一个加号。div + p, 选择紧跟在 div 后面的 p,并且这两个要有相同的父标签。个人认为 CSS3 中的叫法 adjacent sibling combinator 更为准确。在 CSS3 里还有一个和这个差不多的 general sibling combinator, 暂时还没搞明白怎么用。 Pseudo-class.  很常用,我们用的最多的就是 a:visited, a:hover. 除了这个 a 系列以外,还有 :first-child 和 :lang.  CSS3 中的 pseudo-class 就多得让人发指了,随便说几个::nth-child(), :nth-of-type(), :only-child ... Pseudo-element, 经常和 pseudo-class 混,包括 :first-line, :first-letter, :before 和 :after.  在 CSS3 里,为了和 pseudo-class 区分,pseudo-element 的符号变成了两个冒号。 Pseudo-class 和 Pseudo-element 的区别 其实很简单。Pseudo-class 的冒号可以想象成 which is.  Pseudo-element 的冒号(或两个冒号)可以想象成 's.  也就是说前者选择的是符合条件的冒号前面的东西,而后者选择的是冒号前面的东西的一部分。  感觉有点像面向对象的类包容和类继承~~ 回到首字突出 在网上看到很多实现文章首字突出的方法,居然有很多是用 javascript 搞的... 其实完全用不着。我的方法是 :::CSS .entry-content > p:first-child::first-letter { background-color: #2e3735; float: left; margin: -0.2em 0 -0.2em -1.15em; padding: 0.2em 0 0.2em 0.15em; font-family: Arno, Palatino, Georgia, Times, serif; font-size: 3em; border-radius: 0.2em; -moz-border-radius: 0.2em; -webkit-border-radius: 0.2em; } Reference http://www.w3.org/TR/CSS21/selector.html http://www.w3.org/TR/css3-selectors/ http://www.w3.org/TR/CSS21/conform.html

2009/4/4
articleCard.readMore

Google 发布 Fallout 3 版搜索界面

Google 已经发布了用于 Pipboy 3000 的搜索界面。用户可以在 Fallout 3 按 TAB 调出 pipboy,然后按下波浪键 (~) 调出控制台,输入 google 回车,便可以在 Fallout 3 中使用 Google 搜索。Google 的产品经理 Doug Garland 同学说 pipboy 的搜索界面极大的方便了同学们的游戏过程,Google 以后还将发布类似的产品(比如 The Sims 3 中的搜索界面)。

2009/4/1
articleCard.readMore

YAFV

早就想写一个地球人能用的字体查看器了。现存的字体查看器都存在一个问题,就是只能查看系统已经识别的字体,或者只能查看某个字体文件,所以对于我这种看到好字体就两眼发直且配字体可以配一整天综合症患者来说,系统里要备有两套字体查看器。 But worry no more~~  新一代轻量级字体查看器 YAFV 已经诞生。功能: 列出系统中的字体名,并查看 查看指定的字体文件 查看指定的字体名 Todo: 查看一票字体文件,像在 feh 里一样切换。 EDIT: 查看一票字体文件的功能已经实现,但是有一个严重问题:如果要查看的字体已经被安装到了系统里,会按照系统中的 style 顺序查看,而不是命令行参数中的顺序。这是因为 Qt 只能以 family name 来调用字体。我得看看 Kfontview 是怎么调用字体的... EDIT2: 最新更新:已经可以正常的查看系统中已安装的字体文件。在 Google Code 建立了项目。

2009/3/27
articleCard.readMore

可怜的孩子

某人要动手术了...  起因是某人某天乐呵呵的买了一个二手自行车,在学校里美滋滋的骑。突然,前方出现一个地球人,某人一时间忘了应该刹车,为了保护忠厚老实的地球人民,某人毅然把身体向旁边一歪~~  于是韧带断了... 衷心祝愿某人手术顺利,早日康复~~  顺便早日拿 offer~

2009/3/17
articleCard.readMore

WSU 面试

定的是北京时间今天 0:00。到 10:00 的时候开始紧张。材料都准备好了,问答写了 4 大张,到网上打了会儿 Quake Live,延迟的实在太厉害,被人虐了...  11:10 不行了,开始听音乐,被某人和朋友鼓励了,然后渐渐的感觉好多了。最后一首是 Pink Floyd 的 Time。 到 0:00,电话准时响了。Tom Johnson 同学的声音和我在网上录像里听到的一样。上来我先 hello,然后他自我介绍说自己是 WSU 物理系技术总监 (-_-),我说 Hello Mr. Johnson.  This is Mingyang Sun, an appliance of your physics Ph.D program.  然后他楞了一下,估计是第一次听到 Mingyang 这么诡异的发音,然后说我是受物理系 xxxx committee 的委托,问你几个问题。我说 Ya, sure.  Go ahead. (一紧张连 please 都忘了... 囧),然后他就开始问了。 What is your interests of study? Condensed matter, nonlinear physics, complex system, that kinda stuff. What do you plan to research in the future? 和我的兴趣一样,Condensed matter, nonlinear physics, complex system, that kinda stuff.  然后我又想怎么两个问题答案一样呢... 于是又加了一句 If that's what you mean。然后他又问了一遍,于是我又答了一遍... 然后是一段很尴尬的时间,我说完了,等着他继续,他不说了... 僵持了一下,然后继续问 Do you have any experience in teaching? 我问他在小组讨论的时候发言算么?其实我没有什么小组讨论的经历,但不知为什么问出来了 -_- 他说算啊,于是我就很满足的说我大一的时候对全班同学做过光学史的介绍。加入 NJU LUG 以后做过几次关于 Emacs 和 TeX 的讲座,然后我充满期望的说这些东西你可能听说过吧? 然后他就笑了一下,说我不怎么懂 Linux,那个东西太难了(我很想插一句 It's actually very simple,然后显摆一下,不过他没给我机会...)。这里有些同学懂。但我是系里的 technical supervisor,基本什么都知道一点。然后我也笑了一下,说 You know, I'm a big fan of it.  然后他接着问 Do you have any interest on a specific group in the department? 这个我也准备了,就说 Yes.  That would be Dr. AAA 和 Dr. BBB 的组,他们的主题和我的兴趣很符合,you know, the nonlinear and condensed matter stuff.  If I'm admitted.  I would like to work with them. 他说其实没有也没关系。你们第一年的时候会有一次,所有的组都过来显摆一下,让你们选择。所以你不用现在选定。然后不知道为什么我说 Ah...  You know, for me it's pretty much decided.  然后忽然想起来可以把这个引到我的论文上,于是说因为我的毕业论文是关于非整数维空间中的磁性系统的,基本就是 condensed matter 和 complex system 的问题,so... (但是这时我居然忘了说我的论文发表了!!)他说 ok,然后继续问我有没有什么问题。 我说当然有啊,你们哪里天气如何,is it too cold in winter? 他反问我什么是 too cold?  我说就是零下吧。他说偶尔会有,但是他已经很久没遇到了。然后他开始兴奋,说他是从 California/Canada(我没听清是哪个-_-)来的,很喜欢这里,这里的气候很爽,冬天不冷,夏天不是很热,而且夏天非常的漂亮。我说 Wow, that's so great. 然后我问 Can you tell me how the committee thinks of my profile(又没注意礼节-_-)?  What's the chance that I will be admitted?  他说 sorry,我不是 committee 的成员,我只是面试你,然后写个报告给他们看。他们下次会讨论的。又说他们希望招收各种不同属性的学生(和我们游戏里招宝宝一个样...),你的兴趣是我从来没见过的。然后我接着问什么时候有结果,他说不知道...  我比较失望,随便说了一句 You know, if I'm admitted, I will definitely come.  You are my first choice.  然后他马上说 you know what, 我会把这个信息写进我的报告,这是他们希望看到的。然后我想起我的论文了,说还有一个信息你们可能想知道,我的论文 xxxx xxxx xxxxx is accepted by JMMM, Journal of magnetism and magnetic material,那人貌似不知道这个期刊,说 well, 你可以写个 email 给我,我说 Ya, I'll do that. 然后他好像临时想起来这个问题,问 Why do you choose WSU? 我说因为你们对 novel state of matter 很下功夫,这很对我的兴趣,而且 WSU is one of the best in the US.  So, why not?  他说很好。 然后就随便客套了一下就 88 了。 总得来说还凑合吧。表达的还算清楚,他貌似基本能听明白,我也能听明白他说的。但是很不爽的一点是我一紧张没有注意礼节,而且貌似说的还是太快了...

2009/3/3
articleCard.readMore

Plot with Python

昨天某人给我一堆数据,需要画图。数据是一堆矩阵一个一个的放在文件里,本来想用 Python 处理成 Gnuplot 那种格式就行了,不管画图,后来发现数据多了以后需要一次一次的到 Gnuplot 里 plot "filename" with vector,如果要保存下来还要 set term post, set output xxxx,太麻烦...  遂决定直接用 Python 画了。图形库当然是用传说中的 Matplotlib。为了遵循 KISS 原则,数据处理和画图写成两个程序,用管道连接。 Google 了半天,发现 Matplotlib 里画矢量场的函数叫 quiver -_-,画图流程大概就是 :::Python import matplotlib.pyplot as Plot Plot.figure(figsize=(5, 5)) Q = Plot.quiver(X, Y, DX, DY, width=0.001) 然后要直接显示就 Plot.show(),要保存就用 Plot.savefig。Matplotlib 为了给使用者“命令行”的感觉,把整个画图过程做成了一个状态机,搞得我用着很灵异...  效果还是不错的,两个命令用管道一接,很装逼~ 哈哈哈~~

2009/2/22
articleCard.readMore

Fight Against Spam

看来有必要装一个反垃圾插件了。现在每天会收到 100+ 个垃圾 comments,我原来是把这些 comments 里的链接的域名部分加到 spam 列表里,后来发现每过几个小时这些 spam 就会换里面的链接... 又发现这些 spam 里都包含 comment[0-9],于是把 “comment” 加到 moderation list 里,很管用,但是每天又有那么多需要手动从 moderation list 移到垃圾箱里了... Google 了一下,找到几个比较有意思的反垃圾插件: Challenge: 给写评论的人出一道题,打对才显示评论 WPBayes: 这个比较强悍,使用了贝页斯过滤器... Referrer Bouncer: Er... 不知道这个是什么原理。 后面两个貌似都许久不更新了。还有一个 wp-spam-hitman,可以搞正则表达式匹配,应该很有用。暂时决定先试试 Challenge。 更新:装了一个 Antispam Bee,效果不错。又装了一个 is-human(),可以在评论页放一个随机问题,正在想问题中...

2009/2/21
articleCard.readMore

学车第一天

严格来讲不能叫第一天,不过是第一次开车。那个教练很强悍,为了鼓励我帮他推荐学生,态度极好,教的也很好。把两天的课程都学了,起步、停车、转弯、穿桩、直角弯、坡起、8 字弯、100 米加减挡,在路上以四档横冲直撞...  不过很简单,坡起我第一次就起来了。直角弯和 8 字弯一次也没上路沿,哈哈哈哈哈^^ BTW, WP 升级到 2.7.1 以后 K2 主题乱掉了,这是一个在 K2 用户中普遍发生的问题。我一度试图找到一个可以达到我这个主题的 PP 程度 10% 的 WP 暗色主题,未遂。后来重新 svn 了一个 K2,解决了。

2009/2/13
articleCard.readMore

Fallout 3

玩了几天 Fallout 3,给我留下了极其深刻的印象。 首先,游戏在视觉上极其的强悍。这个游戏刻画了世界核战争以后的 Washington D.C.,基本满屏幕都是破败的黄色(又称屎黄色)。但是这并没有影响画面的牛逼性。在开放场景中,D.C. 的外观表现的美轮美奂,叹为观止;室内场景中规中矩,但气氛绝对是有的。昼夜循环和天气变化都很完美,不过很傻逼的一点是夜里人物投影的方向不和月亮的方向相反 -_-...  另外游戏的 HDR 优化的很好,打开以后速度只有 3fps 左右的下降。 但是这个游戏的亮点不在图像,而在系统。Fallout 3 给我的最强大震撼在于虽然游戏的背景是科幻的,但是情节和环境设计的非常真实,令人信服。这个游戏非常的自由。当你从 Vault 101 出来以后,你可以在 Capital Wasteland 上到处乱走。如果你强悍到一下走到了 GNR Station,你甚至可以跳过整个 Megaton。在 Megaton 里有一个未爆炸的核弹,你可以放任不管,也可以把核弹 deactivate 了,也可以躲到安全的地方直接引爆核弹,把 Megaton 从地图上抹掉。但是不管你怎么做,你都要为自己的行为负责,而且这个责任的影响往往非常深远。如果你引爆了核弹,你就会被很多人视为坏人,并且短期内找不到安全的地方存放外面捡来的破烂;如果你 deactivate 了核弹,村里的大部分人会对你很好,甚至 GNR 的 DJ Three Dog 也会对你刮目相看,但是一些极端分子就会开始盯上你。另外,在你下这个决定之前,可以找到一个西装革履的人,他会让你引爆这个核弹然后给你一些报酬。然后再次和 Megaton 的 sheriff(相当于镇长和警卫)对话的时候会多出一个选项来告发这个人。在你告发他以后,sheriff 会去找他,让他去坐牢,然后在 sheriff 转身的时候,这个人会掏出枪来把 sheriff 毙了,然后这个重要的 NPC 就会永远从游戏里消失。再比如,在游戏中,暴力往往不是解决问题的唯一途径。如果你需要找一个房子住,你可以在 Megaton 随便找一个房子,把里面的居民都杀了,把房子据为己有,也可以在外面端掉一个 raider 窝点,使用那里的设备,还可以 deactivate Megaton 里的核弹,然后 sheriff 同学会给你一个空房子的钥匙。再比如,你在 20:00 左右的时候访问 Rivet City Market,那些店主就会告诉你要关门了,让你快点搞定。如果你夜里在那里转悠的话,那些店主就会开始怀疑你,甚至直接跟你火拼。再比如,由于我扮演的是一个超级善良的人,某天早上我从 Megaton 的家里出来时,一个居民走过来送给我一个蛋糕... 再比如,游戏里的每一个尸体都会永久的存在下去,你甚至可以使用尸体来作为可靠的储物柜。 游戏里也有一些非常搞笑的东西,比如在 Vault 101 里有一道题,大意是“在 Vault 101 里,是谁给了我们干净的水、食物,是谁给了我们生命?”,四个选项都是“Overseer”-_-...  还有很多人的对话。 继续发掘中...

2009/1/29
articleCard.readMore

主题,和 LaTeX 插件

给 K2 主题做了一个主题 Deviant,颜色模仿第二版 DeviantART,并且做了一个自认为很强大的标题图片,哈哈 ^^ 顺便给这个 blog 装了个 LaTeX 插件,测试一下: $$!\displaystyle\textrm{\LaTeX} = A !\int_0^\infty !!! \epsilon_0 \sin \frac{\omega t}{\beta x} \,\mathrm{d}x$$ $$(a+b)^2 = a^2 + b^2 + 2ab$$

2009/1/25
articleCard.readMore

What's the Deal?

总算把空间搞起来了。HostMonster 自带 Python 2.3 和 2.6,但是 2.6 的库不全,起码没有 select 库,2.3 是全的,很诡异。过几天装个 Django 试试。自己编译 Python 2.6 未遂,编译了一个 Emacs23 和 Htop。另外还搞了个相册,Gallery 的,很好很强大,在 community 的插件库里有个可以在 Google Maps 上标明照相地点的插件,以后可能会有用,但是这个相册缺乏对照片进行批量操作的能力。 下面还有很多事要做: 装 Django,把我的 Django 程序都放上来 把我的 wiki 搬过来。 今天去考交规了,89 分,太郁闷了... :-( 过了春节继续... :::C /* It's a GeShi test */ #include <stdio.h> int main() { printf("Hello world!\n"); return 0; }

2009/1/17
articleCard.readMore

生成 ASCII Arts 的程序

做个广告先:我的 wiki 搬家且更新了,重新设计了 CSS。新地址在这里。 写了一个生成 ASCII arts 的程序,效果如下。 __ __ _ \ \ / / ___ _ _ ___ _ _ __ | |__ \ V / / _ \| || | (_-<| || |/ _|| / / |_| \___/ \_,_| /__/ \_,_|\__||_\_\ 这个程序支持读取 FIGlet 的字体,并且支持两种 kerning style: 不 kern 和 fitting。展示如下: No kerneling Fitting 字体在 figlet 网站下载。顺便展示几个~~ \_/ _ _ _ | | | (_) |_| _> |_| (_ |< o .oooooo..o oooo .o. d8P' `Y8 `888 888 Y88bo. oooo oooo .ooooo. 888 oooo 888 `"Y8888o. `888 `888 d88' `"Y8 888 .8P' Y8P `"Y88b 888 888 888 888888. `8' oo .d8P 888 888 888 .o8 888 `88b. .o. 8""88888P' `V88V"V8P' `Y8bod8P' o888o o888o Y8P _____ ______ _ __ __ / ___/ ___ ___ /_ __/ ___ | |/_/ / /_ / /__ / _ \ / _ \ / / / -_) _> < / __/ \___/ \___//_//_//_/ \__/ /_/|_| \__/ 嘿嘿 :-D

2008/11/6
articleCard.readMore

在 Emacs 里以 root 权限运行程序

囧阿,一直用 Emacs 的 dictionary.el 作字典,但是启动 dictd 的时候都要跑到终端里去,因为要 sudo。今天下决心解决这个问题。到 emacswiki 里看了一圈,到 IRC 里问了一圈,把 Tramp, shell-mode 和 intcmd-mod 的 sudo 问题都解决了,但还是搞不定 shell-command 的 sudo。看来这个函数运行的时候完全没有办法接受用户的输入作为 stdin。最后翻到 Tramp 的手册,发现以 root 权限运行 shell-command 需要先 C-x C-f /sudo::,把当前目录变为 /sudo::/root,然后再 M-! 运行 shell-command... 太囧了...

2008/9/23
articleCard.readMore

买书去了

本来是陪我弟买 PHP 相关书籍的,结果我也忍不住买了三本。 第一本是 N. Gregory Mankiw 写的 Principles of Microeconomics,一本普通的微观经济学著作,不说了。 第二本是漫画《找死的兔子》,以前在网上看到过一些,这次发现有卖的,顺手就买了。 第三本是孙荣恒的《趣味随机问题》。这本书看名字显然是一本科普读物,但是我翻看来第一节赫然是讲集合和可测性的,而且所有的定义都像教科书一样严密的给出,所有的定理都有详细证明,每个例子都给出详细的推导,而不像某些自诩为教科书的书那样充满了“显然,xxxx”和“经证明,可得xxx”,遂买下。这书的内容虽不高深,但对我这样没有正经学过数学的人来说,也合适了。

2008/8/25
articleCard.readMore

Suffix Tree

在负暄琐话里看到关于 suffix tree 的帖子,感觉很牛逼,于是用 scheme 实现了一个,写了一个多小时。唉,以我现在的水平,用 scheme 写点东西还是很费劲的... 话说用 suffix tree 可以在线性时间内实现很多字符串匹配和查找的功能,无边强大~ (define (gen-suffix x) ; x is a list (if (null? (cdr x)) (list x) (cons x (gen-suffix (cdr x))))) (define (compare-two stringcons) ;stringcons is a cons ;; anyone is empty? (if (or (null? (car stringcons)) (null? (cdr stringcons))) '() ; one of them is empty (if (equal? (car (car stringcons)) ; none of them is empty (car (cdr stringcons))) (cons (car (car stringcons)) (compare-two (cons (cdr (car stringcons)) (cdr (cdr stringcons))))) '() ))) (define (next-to-common stringcons common) (if (null? common) (cons (if (null? (car stringcons)) '() (car (car stringcons))) (if (null? (cdr stringcons)) '() (car (cdr stringcons)))) (next-to-common (cons (cdr (car stringcons)) (cdr (cdr stringcons))) (cdr common)))) (define (make-tri index node childs) (cons index (cons node childs))) (define (node tri) (car (cdr tri))) (define (index tri) (car tri)) (define (childs tri) (cdr (cdr tri))) (define (find-index char kids) (if (null? kids) '() (if (equal? char (index (car kids))) (car kids) (find-index char (cdr kids))))) (define (replace-by-index idx kids newkid) (if (null? kids) '() (if (equal? (index (car kids)) idx) (cons newkid (cdr kids)) (cons (car kids) (replace-by-index idx (cdr kids) newkid))))) (define (insert-string string tri) ;; tri: (list index node child1 chind2 ...) (let* ((common (compare-two (cons string (node tri)))) (nextchar (next-to-common (cons string (node tri)) common))) (if (equal? common (node tri)) (if (null? (find-index (car nextchar) (childs tri))) (make-tri (index tri) (node tri) (cons (make-tri (car nextchar) string '()) (childs tri))) (make-tri (index tri) (node tri) (replace-by-index (car nextchar) (childs tri) (insert-string string (find-index (car nextchar) (childs tri)))))) (make-tri (index tri) common (list (make-tri (cdr nextchar) (node tri) (childs tri)) (make-tri (car nextchar) string '())))))) (define (insert-string-list strlist tri) (if (null? strlist) tri (insert-string (car strlist) (insert-string-list (cdr strlist) tri)))) (define (gen-suffix-tree string) (insert-string-list (gen-suffix string) (make-tri '() '() '()))) 运行一下: > (gen-suffix-tree (string->list "bananas$")) (() () (#\b (#\b #\a #\n #\a #\n #\a #\s #\$)) (#\n (#\n #\a) (#\s (#\n #\a #\s #\$)) (#\n (#\n #\a #\n #\a #\s #\$))) (#\a (#\a) (#\s (#\a #\s #\$)) (#\n (#\a #\n #\a) (#\s (#\a #\n #\a #\s #\$)) (#\n (#\a #\n #\a #\n #\a #\s #\$)))) (#\s (#\s #\$)) (#\$ (#\$))) 很乱很正确~~ 一些链接: Suffix tree @ wikipedia 讲解生成方法的视频,在 mac os 里用一个未知软件做的 Tries 和 suffix trees

2008/6/23
articleCard.readMore

Glenn Gould

Gould 是个争议性人物,他的钢琴演奏受到无数人的唾骂,也受到无数人的赞美。我今天听了他的 Mozart piano sonata no.12,感觉是:这应该才是 Mozart 爷爷想说的。 下面是一个 Gould 弹 Mozart 的视频。传说他在音乐会上也是这样弹的... 下面有个 comment 也表达了我的想法: Glenn is such a phenomenom to me, he plays exact, and precise, evey note is exactly equal in value, yet, there is passion and love for the music, if anybody else played like this, it would be almost mechanical, robotic, gould has mastered something i dont think many others will come close to.

2008/3/28
articleCard.readMore

Phun

Phun 是一个 “2D physics sandbox”,是 Umeå 大学一个硕士生的毕业作品,使用了 C++ + boost + OpenGL + GLEW + SDL。这个东西最强悍的地方在于可以用鼠标画一个任意形状的物体参与计算。以下是官方的介绍视频: 以下两个是我做的~~ :-p 4WD (2WD...) 不 incredible 的 incredible machine 这个东西目前还未开源,不过作者说以后会开的~~

2008/3/11
articleCard.readMore

冰岛语 KDE

KDE 新出的 4.0.2 版的 changelog 的最后有 Icelandic has been added to KDE translations. 难道这就是传说中的只有几千人用的冰岛语??:-D

2008/3/6
articleCard.readMore

SSH in The Matrix

这几天重新看 The Matrix,发现在第二部的后面,Trinity crack 进电力系统的网络,准备关闭备用系统的时候,她用的居然是 SSH?!看截图。 从这个截图里还可以推测出他们 crack 的过程: 使用 nmap 对主机 10.2.2.2 进行端口扫描,看到 SSH 端口开着。虽然这个命令行没有给出,不过可以想象大概为这个样子: # nmap -sT 10.2.2.2 使用 `sshnuke` 更改 10.2.2.2 的 root 密码。不用试了,你的机器里没有这个程序 以 root 登录 10.2.2.2 另外,我发现两个证据说明这是一个苹果机网络(起码都运行着苹果的操作系统)。一个是那个输入密码的对话框,窗口装饰很像是古老的 Mac OS,另一个是 nmap 的扫描过程。大家注意这行字: The 1539 port scanned but not shown below are in state: closed 1539 端口貌似是一种叫作 Mac-net 的服务的端口... 补充(2008-03-06):`sshnuke` 的输出里有一句 Attempting to exploit SSHv1 CRC32 ... successful. 一定要使用 v2 协议!^_^

2007/12/30
articleCard.readMore

Computer Generated Hologram

CGH,计算机生成全息,就是可以把入射光的相位信息保存下来的东西。目前网上介绍这个东西的文章大多以论文(而且都是要钱的...)的形式出现,不利于我等民间人士访问。正好这几天由于学习上的需要写了一个二维 CGH 的程序。大家都知道光学的全息就是让物光通过一组透镜产生傅立叶变换,然后用一束参考光干涉来记录,所以在 CGH 里只要对物做傅立叶变换,然后记录变换结果就行了。具体步骤如下: 把物做成图片 对图片做 FFT,生成一组复数 把复数编码成图片并保存 我这个程序比较弱智,我自己写了一个读写 bmp 文件的类,只能操作 windows 格式的 24 bit bmp,编码用了类似 Lohmann 的,用开孔的位置表示相位,孔的深浅表示幅度。用法为 holo -i <inputfile> [-o <outputfile>] [-w <site width>] [-h <site height>] [-d <hole width>] [-r] 其中 `site width` 是每个孔能活动的宽度,`site height` 是孔的高度,`hole width` 是孔的宽度,`site width - hole width` 决定了相位的精度,而幅度的精度永远是 8 bit。

2007/11/19
articleCard.readMore

id Tech5

上个月的 QuakeCon 上,id 发布了使用 id Tech5 引擎制作的 Rage 的一段 demo,传说这是用 id Tech5 引擎实际渲染出来的。从这个 demo 里,我们可以大概看出新引擎的一些特性: 真实的景深效果,只有镜头焦点附近的东西是清晰的,其它东西按照离焦点的远近呈现不同半径的模糊。按照 John Carmack 的一贯作风,我怀疑离焦点的远近被简化成 z 轴坐标~~ 真实的阴影。Doom3 引擎的阴影已经很好了,就缺少模糊的边缘。很多其他游戏里有边缘模糊的阴影,一般来说这可能是两种情况: 阴影是 buffer shadow,精度不够所以模糊了 先搞一个精确的阴影,然后对阴影整体模糊 这张图就知道了,这是我用 Blender 渲染的。看到了么?真实的阴影在离物体近的地方是比较锐利的,离物体越远越模糊。而 id Tech5 似乎已经实现了真实阴影的“一阶近似”(也许是更高阶)。注意下面第三张截图的左边,人物肩膀上的盔甲在衣服上投下的阴影。 开放的户外场景,改进的 MegaTexture。 更先进的 shader。从截图上看,不仅是金属,其他各种材质在 id Tech5 里都有异常真实的表现,不像 Doom3 里只有金属... 那个人脸的特写,就像照片一样... HDR。这个是 Doom3 的一大缺憾... 改写一段 Man in Black 的台词作为结尾吧: After Quake, everybody knew that the world was 3D. After Quake II, everybody knew that lights could be colorful. After Quake III, everybody knew that a texture could be mapped onto a cylinder. After Doom3, everybody knew that without light, the world would be all black. Today, we know that shadows are fuzzy. Imagine what we will know, tomorrow.

2007/10/6
articleCard.readMore

Ligatures in Firefox

在写完上一篇关于 CSS3 分栏的 post 以后,我查看分栏的效果,突然发现底下英文那一段中的 figure 比较诡异,放大以后发现 Firefox 居然支持字体中的 ligatures~~ 关于 ligatures,简单的说就是把某些字母组合搞成一个字母,这样看起来更好看(一般来说是更紧凑)。还有三点补充: Ligatures 很神奇 Windows 下的程序基本都不能识别 ligatures,除非是 Safari 3 和 Adobe 这样自己写字体引擎的 X 的 Freetype 2 在 patch 之后支持 ligatures。 连在一起的 f 和 i普通的 i

2007/10/3
articleCard.readMore

Multi-column

CSS3 中增添了对分栏排版的支持,这个我很早就知道了,但是今天才发现 Firefox 和 Safari 3 已经实现了这个东西,真是惊天地泣鬼神... 测试一下~~ 中文的: 英文的: A small figure gallops across the windswept ice slope. The bundled rider is mounted on a large gray snow lizard, a Tauntaun. Curving plumes of snow rise from beneath the speeding paws of the two-legged beast. The rider gallops up a slope and reins his lizard to a stop. Pulling off his protective goggles, Luke Skywalker notices something in the sky. He takes a pair of electrobinoculars from his utility belt and through them sees smoke rising from where the probe robot has crashed. The wind whips at Luke's fur-lined cap and he activates a comlink transmitter. His Tauntaun shifts and moans nervously beneath him.

2007/10/3
articleCard.readMore

TeXPNG GUI

这是以前写的 texpng 程序的图形界面版,我把以前的 texpng.py 改写了一下(这是好听的说法,其实是剪切粘贴了一下),把转换过程抽象了一下,方便在图形界面里调用。和 texpng.py 一样,这个东西需要一个正常的 LaTeX 系统、dvipng 和 Imagemagick,除此之外,图形库使用了 wxpython。用法就不废话了,GUI 啊同志们... 最后,那三个图标是 oslo 图标集中的,版权属于原作者。 截图 下载 对了,过几天大家可能会看到一个更牛逼的转换 TeX 的程序,不过不是在我这里~~ :-p 最后的最后,说点感想~~ 在 Linux 下写程序太方便了,感觉 Linux 就是写程序用的~~。这两天狂用了 Mac OS X 之后,隆重宣布:宇宙里最好用的 PC 操作系统是配置好的 Linux~~ 现在写个图形界面太方便了!这个小破程序是我三个小时攒的... 还没想好... PS:这个程序在运行的的时候会覆盖当前目录下的 temp.png 文件(如果有的话),退出的时候把这个文件删除。

2007/9/30
articleCard.readMore

MacTeX

安上了 MacTeX,这是运行在 Mac OS X 下的基于 TeXLive 的发行版,比 CTeX 还大... 不过像 CTeX 一样,装起来很方便,不用配置,而且一上来就可以排中文~~,不过据我的试验,编码只能为 utf-8,而且可以用的简体字体只有一个 gbsn,这个字体比 M$ 的那个 simsun 好看多了~~。 :::LaTeX \documentclass[12pt]{article} \usepackage{CJK} \begin{document} \begin{CJK}{UTF8}{gbsn} This is a test. 中文测试。 \textbf{粗体},\textit{斜体},\texttt{等宽字体}\ldots \end{CJK} \end{document}

2007/9/27
articleCard.readMore

Mozilla @ Mac OS X

可能是由于安在 x86 上的缘故,Safari 不太稳定,一打开某些中文网页就崩溃... 真不知道为啥在中国大家都不遵守 HTML 4 和 XHTML 1.0 呢~~~ 于是还是用 Firefox... 但是 Firefox 似乎对 OS X 的 Type1 字体有强烈的不满,不是显示一堆火星文就是显示成脚标/上标状... 搞得我看中文像看公式一样... 后来听说还有个 Camino,也是 Mozilla 的,会好一点,赶快安上,发现确实好一点,基本没有火星文,公式也比较少... 看截图: FirefoxCamino 我想出现这种鸟事是因为 Mozilla 们为了跨平台,搞了自己的字体引擎,不肯使用各操作系统自带的 API,但是对 Type1 支持又不好,不能正确读取字体中的某些信息,于是就出现了火星文和公式...

2007/9/26
articleCard.readMore

OS X: 配置完了,小研究一下

Google 了无数次,也找到了一些安装显卡驱动的方法,但在我的机器上就是不管用... 所以到现在还没有硬件加速,这个本来没什么,少一些特效而已,但是发现 OS X 里播放视频是需要硬件加速的... 大概研究了一下 OS X 下的程序,标准的 OS X 程序都是一个名字以 .app 结尾的文件夹,里边一般只有一个文件夹叫 Contents,这个程序的一切都在这个文件夹里,包括图标,配置(有些比较底层的会在 /Library 和 /System 里面放配制)语言文件等等。比较爽的是,OS X 和它里面的程序都是极端脚本化的,不仅配置一律是 xml,而且控件的摆放(!),图片的位置,dock 图标,甚至部分逻辑都是 xml,对于我们这些喜欢没事瞎改的人来说,这样的系统基本上就是天堂了~~。举个简单的例子,无论在什么操作系统里,只要有一个图形界面的文件管理器,你在里面新建一个目录的时候都有一个默认的目录名,比如在 Windows 里叫“新建文件夹”,这是被硬编码的,没有源代码的人改不了;在 OS X 里叫 untitled name,这个可以在 /System/Library/CoreServices/Contents/Resources/English.lproj 中修改,这个 .lproj 是一个语言文件,会被其他的 xml 调用。貌似现在达到这种境界的基本上就只有 wxWindow 了(用 xml 来摆控件)。 OS X 里面是有 python 的,不过是 2.3 版,严重不爽,于是装了一个 2.5(装好以后还要手动做符号连接...),开始考虑有什么程序可以写~~。想了半天,决定写一个批量删除语言文件的东西,把机器里的那些非人类语言都删掉,可以节省数百 MB 的硬盘~~,代码(用法看开头的注释): :::Python #!/usr/bin/env python # # Usage: # kill-lang.py app_list # # eg: kill-lang.py mail.app aquamacs.app # ls -1 | awk '{print "\""$0"\""}' | xargs kill-lang.py import os import sys import re import shutil ReservedLang = ["English", "zh_CN"] if len(sys.argv) == 1: usage() sys.exit(1) def usage(): print(' '.join(["Usage:", sys.argv[0], "application_names (with \".app\")"])) return def handleRmError(function, path, excinfo): sys.stderr.write(''.join(["Error deleting ", path, ", err:\n", str(excinfo), "\n"])) def killLang(app): # Get the path where language files are located. AppResource = '/'.join([app, "Contents", "Resources"]) if not os.path.isdir(AppResource): sys.stderr.write("This program dose not have a standard app structure.\n") sys.exit(2) AppSubs = os.listdir(AppResource) Langs = [] for Sub in AppSubs: if re.match(".*\.lproj$", Sub) != None: Langs.append(Sub) FullLangs = ['/'.join([AppResource, Lang]) for Lang in Langs] for i in range(len(FullLangs)): if not Langs[i][:-6] in ReservedLang: print("".join(["Deleting ", Langs[i], "..."])) shutil.rmtree(FullLangs[i], False, handleRmError) return 0 def main(): for App in sys.argv[1:]: App = os.path.abspath(App) print App + ':' if not os.path.isdir(App) or len(App) - App.rfind(".app") != 4: print "Not an app, skipped" continue killLang(App) return 0 sys.exit(main())

2007/9/21
articleCard.readMore

Mac OS X

终于按耐不住,把 Windows 删了,装了一个苹果的操作系统,安装的道路上布满荆棘... 我的硬盘上分区众多,主分区和扩展分区相间而生,而且前后历经 Windows 的 parted,Powerquest Magic,和 cfdisk 的多重折磨,估计 MBR 已经变的像我的宿舍一样乱糟糟的,OS X 的安装程序能读出来已经很让我满意了,试了数次之后发现用那个 Disk Utility 只能读,连格式化都不行... 那时 Windows 已经光荣牺牲,所以决定把整个硬盘重新分区。在备份了 30 多 G 的重要数据以后,一闭眼,打了 cfdisk -z /dev/hda,面对空荡荡的 MBR,心中感慨万千~~ 在 cfdisk 里划了一个 15G 的主分区,然后兴奋的跑到 OS X 安装程序里,发现还是不行,这个比较奇怪,到现在也不知道为什么... 最后经过数次尝试发现只有在 Windows(的安装程序)里分区,Disk Utility 才能正确的格式化。安装过程倒是挺快的,和 Ubuntu 差不多,就是要打个 SSE2 的补丁。 如果平时只是上上网,处理一下 routine stuff 的话,OS X 在安完之后就已经是一个非常全面的系统。浏览器、终端、文件管理器、邮件客户端、日程管理、播放器等等一应俱全(想想 Windows 吧...)。不过自带的那个 iChat 只能使用自己的协议,要是需要类似 Pidgin 的那种多协议 IM 的话,可以下载 Adium,这是宇宙里最漂亮,最好用的 IM,而且是开源的。BT 客户端可以用 BitRocket,也是开源的。OS X 的软件资源非常丰富,而且基本上都比 Windows 的同类软件好用。 操作系统本身基本上是完美的,配置也非常简单,都集中在 System Preferences 里,不像 Windows 要到处找。还有那个 Dock,以前用 Windows 的时候用过一个模仿 dock 的软件叫 RocketDock,手感很好,但是安上 OS X 之后才发现 dock 有一些不可能在 Windows 里模仿出的功能,它可以与其它程序交换信息,比如那个 Adium,你在里面设置自己的状态为 away 以后,Adium 就会告诉 dock,于是 dock 里的那个小鸭子图标就会举个牌子,上面写着 Away~~ 其它的就不说了,只有在用过之后才能体会到它的方便... 下面是截图: About this MAC~~ Adium 聊天 安装 Aquamacs,一拖动就行了 安装 Firefox,我们要开源~~ 用 Safari 上网 桌面,注意底下的 dock,鼠标在的位置是 BitRocket,可以实时地显示下载速度

2007/9/19
articleCard.readMore

Pac 自动代理配置

今天在网上乱逛,不小心看到一个自动代理配置脚本(就是传说中的 pac 文件),发现语法怎么就和 Java 那么像呢~~?Google 一番之后发现其实 pac 就是一个 Javascript 函数,名叫 FindProxyForURL。它接收两个参数,url 和 host,都是字符串。url 是浏览器将要进入的地址,host 就是地址中 :// 和第一个 / 之间的部分。返回值为一个字符串,有三种情况: 直接连接,不经过代理,返回 "DIRECT" 经过代理,返回 "PROXY host:port" 经过 socks 服务器,返回 "SOCKS host:port" 有了这些规则,我们就可以随意加入逻辑,一劳永逸地解决是否使用代理,何时使用代理,使用什么代理等一系列重大问题。比如,我要对 blogspot 使用 72.14.219.190,其他某些倒霉的地址使用 Tor,剩下的碌碌无为的地址不使用代理,就可以用下面这个 pac。 :::Javascript function FindProxyForURL(url, host) { url = url.toLowerCase(); host = host.toLowerCase(); if(dnsDomainIs(host, ".blogspot.com")) return "PROXY 72.14.219.190:80"; if(dnsDomainIs(host, ".wikipedia.org") || dnsDomainIs(host, ".technorati.com") ) return "SOCKS 127.0.0.1:9050"; return "DIRECT"; } Reference: http://wp.netscape.com/eng/mozilla/2.0/relnotes/demo/proxy-live.html#dnsDomainIs。Netscape 真是有长者风范啊~~

2007/9/13
articleCard.readMore

Eragon

昨晚看了电影 Eragon,中文好像翻成《龙骑士》。从那个 Eragon 背对摄像机面向日落的镜头开始,我就是像看笑话一样的看完的,因为它和 Star Wars 实在是太像了。 比如上面那个镜头就几乎和 Star Wars 里 Luke Skywalker 在 Tatooin 面对两个太阳的日落的镜头一模一样,而且 Eragon 和 Luke 的装束也长得差不多,并且他们都是由叔叔养大的。公主都是一开始被坏蛋抓去的,然后被不成熟的主角救出。以下是主要角色的对应: Eragon Star Wars Eragon Luke Skywalker 教 Eragon 技能的那个很帅的老头 Obi-wan 公主 Princess Leia 帅老头的仇人的儿子 Han Solo King Palpatin (Darth Sidous) King 的牛逼部下 Darth Vader 公主那边的军队 The Rebellion King 的军队 Storm Troopers 其它相似之处就不列举了,这个电影基本上就是 Star Wars 的缩减傻逼奇幻版。另外有些镜头的运用和背景音乐与 The Lord of The Rings 十分相似。 Eragon 里最让我不满的一点就是为什么要把龙的想法用地球话表示出来,而且还是一个性感的女声,听到这个声音就让我想到了 Disney 前几年的动画片《恐龙》...

2007/8/15
articleCard.readMore

随机生成句子的程序和 Emacs 排名的降低

写了一个用来搞笑的 python 程序,可以随机地按照一定的语法生成句子。若干时间前写过一个功能差不多的程序,但是比较傻逼。 这个程序使用了 recursive transition networks 来表示一些简单的语法,目前可以递归地生成主语从句和宾语从句,并组合成完整的句子。看一些例子: The fool which reluctantly rocks unwillingly eats a book. The silly man that is silly unwillingly kicks a book which finally pisses. A book reluctantly eats a bug that is red. A man unwillingly sucks. The piece of shit that happily runs reluctantly kicks a bug. :-p 词表里本来还有一个 fucking 的,考虑到这里的都是文化人,删了。代码在最后。 另外,Vincent 在 The slow downfall of Emacs 里写道 Emacs 在编辑器中的 popularity 排名正在降低。在几年前,编辑器的 top two 永远是 Vi/Vim 和 Emacs,但是现在 Emacs 竟然落在了 GEdit 和 Kite 之后(这帮傻逼都是怎么想的?!),到底是为什么?Vincent 在最后写道:“Why is that? Not pretty enough? Too powerful for the simple needs of the new users that Ubuntu brought to the Linux world?” #!/usr/bin/env python import random END = "end" TITLE = -1 Noun = ["bug", "book", "piece of shit", "man", "iPod", "ass", "fool"] Be = ["is"] Vi = ["sucks", "rocks", "runs", "flies", "pisses"] Vt = ["eats", "reads", "laughs at", "bites", "kicks"] Adj = ["red", "passing", "shitty", "dying", "silly"] Adv = ["finally", "reluctantly", "happily", "unwillingly"] Trans = ["that", "which"] Artical = ["the", "a"] MainPart = {TITLE: "Main part", 1: [(Adv, 4), (Be, 3)], 2: [(2, END)], 3: [(Adj, END)], 4: [(Vi, END), (Vt, 2)]} NounClause = {TITLE: "Noun clause", 1: [(Artical, 2)], 2: [(Noun, 3), (Adj, 2)], 3:[(Trans, 4)], 4: [(MainPart, END)]} Subject = {TITLE: "Subject", 1: [(Artical, 2), (NounClause, END)], 2: [(Noun, END)]} Object = Subject Sentence = {TITLE: "Sentence", 1: [(Subject, 2)], 2:[(MainPart, END)]} EleList = [Sentence, Subject, Object, NounClause, MainPart] def genSentence(tree): random.seed() Sent = "" Index = 1 if type(tree) == type({}): while Index != END: Node = random.choice(tree[Index]) After = genSentence(Node[0]) if After != None: Sent = ' '.join([Sent, After]) Index = Node[1] elif type(tree) == type(""): return tree elif type(tree) == type([]): return random.choice(tree) elif type(tree) == type(1): while Index != END: Node = random.choice(EleList[tree][Index]) After = genSentence(Node[0]) if After != None: Sent = ' '.join([Sent, After]) Index = Node[1] elif tree == None: return else: print "Error: invalid type of tree in genSentence()." return ' '.join(Sent.split()) def main(): print genSentence(Sentence).capitalize() + '.' return if name == "main": main()

2007/8/6
articleCard.readMore

Youtube Video URL Extractor in Python

看到了 Cheng Meng 的那个 Youtube downloader,由于对 Ruby 的无知,一点也看不懂,所以就参考 DownloadYoutube video with GAWK 用 python 自己写了一个。与 Cheng Meng 那个不同,我这个只负责把视频文件 url 打印出来。用法是 youtube-url.py video-id 所以要下载 id为 `qNKtKm3SXvs` 的视频,可以用这个命令 wget -O video.flv youtube-url.py qNKtKm3SXvs youtube-url.py 的代码: #!/usr/bin/env python # Time-stamp: <corsair 2007-07-28 16:16:38> # Corsair <chris.corsair@gmail.com> # Usage: youtube-url video-id import sys import urllib2 import getopt def main(): # Options parsing, fake for now. try: Options, Args = getopt.gnu_getopt(sys.argv[1:], "", []) except getopt.GetoptError: # print help information and exit: pass <span class="keyword">if</span> len(sys.argv) == 1: <span class="keyword">print</span> <span class="string">"Pleas specify a video-id."</span> sys.exit(1) VideoID = sys.argv[1] WatchPage = urllib2.urlopen( <span class="string">""</span>.join([<span class="string">"http://youtube.com/watch?v="</span>, VideoID])) HtmlLine = <span class="string">""</span> <span class="keyword">while</span> HtmlLine.find(<span class="string">"SWFObject"</span>) == -1: HtmlLine = WatchPage.readline() UrlOriginal = HtmlLine[HtmlLine.find(<span class="string">"BASE_YT_URL"</span>)+12:] UrlOriginal = <span class="string">'?'</span>.join([<span class="string">"http://www.youtube.com/get_video"</span>, UrlOriginal[:UrlOriginal.find(<span class="string">'\"'</span>)]. partition(<span class="string">'&amp;'</span>)[2]]) <span class="comment"># Redirect RedirectOpener = urllib2.build_opener( urllib2.HTTPRedirectHandler) Request = urllib2.Request(UrlOriginal) UrlReal = RedirectOpener.open(Request).url print UrlReal if name == "main": main()

2007/7/28
articleCard.readMore

NetHack

NetHack 头一次达到了 Dungeon of Doom 的第七层。在这层里找到了 Oracle of Delphi,还第一次碰见了 fire ants,截图一张~~~ 光标所在的那个 @ 就是我~~,两个 f 是我的两只宠物,红色的 a 就是 fire ants,那四个蓝色的 { 的中间是 Oracle 的位置,但是墙挡住了,看不见。 以前玩的时候一般都是找不到吃的饿死了,要不然就是吃了个 goblin 的尸体毒死了,在要不然就是做了什么奇怪的事挂掉了(比如不小心走到一个陷阱上,头上掉下来一块石头...)

2007/7/25
articleCard.readMore

Wordpress 中的代码加亮

一个在 Wordpress 中使代码加亮的办法,需要激活 MyCSS 插件,并且保证 WP Lightbox 2 插件是禁用的。 写一段程序代码(我是写的 C++),尽量包含最多的语法元素,然后把代码给 htmlize 了(可以用 Emacs 的 `htmlize.el` 或者 Vim),这里有一个要求,就是生成的 html 必须是 CSS 与 `<pre>` 分开的,CSS 在 `<head>` 里, `<pre>` 在 `<body>` 中,然后把 CSS copy 到 MyCSS 里。 以后贴代码的时候,只要用同样的方法生成 html,然后把那个 `<pre>` 贴到 post 里就行了。还有一点需要注意,MyCSS 会生成一个 `my.css` 放在 blog 的 `<head>` 里,位置是比较靠前的,在我这里比 Coolcode 和 SyntaxHighlighter 都要考前,所以 `my.css` 里的内容可能会被覆盖掉。 测试: ;; =============== Unfill-buffer ===============> (defun unfill-buffer () "Unfill current buffer." (interactive "") (setq m (point-marker)) (beginning-of-buffer) (while (re-search-forward "\\([^ ]+\\) * *\\([^ ]\\)" nil t) (replace-match "\\1\\2")) (set-marker m 0 (current-buffer))) 顺便把我的 CSS 贴在这里,是 Emacs 的 htmlize 生成的,我做了一些改动: .comment { / font-lock-comment-face / color: #b22222; font-style: italic; } .comment-delimiter { / font-lock-comment-delimiter-face / color: #b22222; } .constant { / font-lock-constant-face / color: #5f9ea0; } .function-name { / font-lock-function-name-face / color: #0000ff; } .keyword { / font-lock-keyword-face / color: #a020f0; font-weight: bold; } .preprocessor { / font-lock-preprocessor-face / color: #5f9ea0; } .string { / font-lock-string-face / color: #ab7e7e; } .type { / font-lock-type-face / color: #228b22; } .variable-name { / font-lock-variable-name-face / color: #b8860b; }

2007/7/23
articleCard.readMore

C++ 类模板和多文件编译

才知道原来在多文件编译时 c++ 类模板的声明和定义一定包含在同一个文件里。 以前写 Game of Life 的时候写了一个动态二维数组的模板,当时的文件是这样包含的: // matrix.hpp template<class T> class TMatrix { // Declarations... }; #include "matrix.cpp" // Definitions 今天又用到了这个类,看这个文件包含不爽,改成了常规的 // matrix.hpp template<class T> class TMatrix { // Declarations... }; // matrix.cpp include "matrix.cpp" ... // Definitions 然后在主程序里引用了一个成员函数 // main.cpp include "matrix.hpp" int main() { TMatrix<int> Matrix; Matrix.row(); return 0; } 编译:g++ -g main.cpp matrix.cpp 呜呼!出错了!说 `TMatrix<int>::row()` 只是声明了,没有定义。把 matrix 里的文件包含改成原来那个样子,然后只编译 `main.cpp` 就没问题了。百思不得其解,后来在 CSDN 上找到了这个。理论上,只要在模板声明前加上 `export` 关键字,然后用常规的多文件编译方法就可以,但是目前大部分编译器都不支持这个关键字。`g++` 说“目前尚未实现,忽略”,真够直接的...

2007/7/20
articleCard.readMore

Unfill-buffer

写了个简单的 elisp 函数 unfill-buffer,用来去掉当前 buffer 的所有单独的换行。 [coolcode lang="lisp" download="unfill-buffer.el"] (defun unfill-buffer () "Unfill current buffer." (interactive "") (setq m (point-marker)) (beginning-of-buffer) (while (re-search-forward "\([^ ]+\) * *\([^ ]\)" nil t) (replace-match "\1\2")) (set-marker m 0 (current-buffer))) [/coolcode]

2007/7/20
articleCard.readMore

菩提树

末日的不死菩提树... 说到菩提树,我们大脑中第一个想到的是什么?是“菩提本无树,明镜亦非台”,还是那种某某科某某属的多年生植物? 我第一个想到的是舒伯特的那首艺术歌曲《菩提树》,在这个艺术人都梳小辫的时代,不知道还有没有人听艺术歌曲(其实我也不听,只是凑巧有这首歌)。我住的地方的楼下不远有个卖乐器的,我在那里见过两个店主,一个比较矮,梳小辫,另一个又矮又胖,一副暴发户的模样。这个人压制了我进去摸摸吉他的欲望。 菩提树是一种寿命很长的树。中国原本是没有菩提树的,当年释迦牟尼来到中国时,顺便走私了过来,于是中国就有了这种宁静的树。假如宇宙的质量大于临界质量,希望宇宙毁灭的时候,菩提树可以代替时空而存在。

2007/7/19
articleCard.readMore

Hello world!

突然发现 Wordpress 会很贱地保留源文件中的换行,这是否意味着我将不能用 Emacs 写 blog? Test image. :::C++ #include "stdio.h" int main() { printf("Hello world!\n"); return 0; } $$\int_0^\infty \frac{1}{x}\textrm{d}x$$

2007/7/19
articleCard.readMore