空手哲学

年岁越是上去,越是觉得身边的附属品太多太杂。每每在家整理东整理西的时候,都因为“舍不得”,“或许将来还有用”,“这可是一段回忆啊”等等,重新放回箱子。可是,真的需要么?未必。

看过《Up in the Air》的一定对 George Clooney 在演讲台上的一番话记忆犹新,那是关于 backpack 的一段说辞。看过《Fight Club》的一定对火烧 IKEA 家居变得一无所有而感到兴奋,却始终没有那样的勇气和非理智。人们总是倾向于拥有,不愿舍弃。在原始社会,这是值得嘉奖的,因为那时候物资匮乏。而我们生活的时代,物资充裕,拥有的多过所需的。不愿舍弃拥有的,这种进化而来的本能,使得生活在当今的我们,变得愈发烦躁和浮夸。同人于野有篇文章《坏比好重要》解释了为什么人们害怕损失(不愿舍弃)。

舍弃,开始变为一种哲学,一种生活态度。gugod 在以前的一篇“减法上等”的文章中说:

我也很愛這句安東·德·聖艾修伯(《小王子》的作者)所說過的話:

Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.

私譯為:

完美,並非能再加入些什麼,而是無法再減去些什麼。

为求完美,必先舍弃。《Rework》中也提到“Say no by default”,在大家热衷于堆砌各种功能的时候,dhh 清醒并明白舍弃的积极意义。Apple  的产品也到处体现着舍弃哲学。

人们不愿尝试做些改变,多半只是因为没有尝到改变以后的甜头。虽然道理上明白,但未实践,就无从体会,也就没有动力改变。舍弃之后,带来的利弊究竟各有多少?何不亲身实践一下,然后理智分析。

就像 Gmail 里的邮件,删除还是存档?电脑里的文件,commit 还是 delete?purge-me。抽屉里的杂物,数月没用过的有几样?如果在可预见的未来并不需要,那就直接舍弃。如果是孤本,做好索引;如果是副本,需要时再去找好了。绝大多数我们看似用得着的东西,实际上几乎没有再用到的可能。

空手哲学,是一种境界。如同两袖清风,一身淡泊的出家修行者,虽然两手空空,但内心殷实。作为第一实践,我刚刚删除了无数 Google Reader 里的订阅(终于有了 unsubscribe from all 的功能,等了多少年了。)当然,除了实在的东西需要舍弃,还有许多情感也需要舍弃。此谓之放得下。

被盯上了

很有意思,刚才发了关于 IRC 聊天工具 Colloquy 的 blog,洗完奶瓶回来发现 Gmail 里收到 Twitter 发来的通知,一个叫做 chatonic_room 的人 follow 了我。当然一眼就知道是个机器人,上面只有一条 tweet,一个连接,指向一个在线聊天工具网站,还有 for adults,呵呵。所以利用 Twitter 做营销应该也是不错的。

实际上的信息流有点复杂:

  1. iPhone 上 print screen 再通过 flickr app 上传。
  2. flickr 网站上 blog this 发文到自己博客站点。
  3. FriendFeed 收录 blog feed,于是实时转发了一条 tweet 到 Twitter。
  4. chatonic_room 的机器人利用 Twitter API 搜索相关产品(Colloquy)名字找出潜在用户(本人,以及其他 chatonic_room follow 的人),自动 follow。
  5. Twitter 发送通知邮件到 Gmail。

Google Ads

使用 curl 提交 twitter 消息

一直对 twitter 不怎么感冒,貌似没有必要让朋友知道我每时每刻的行踪,也没有朋友需要了解我的 timeline。不过随手一句话用来发发牢骚。做个小笔记什么的还是蛮不错的,特别是当提交信息的方式可以离线用手机发。 与此同时,twitter 的 API 提供了无限的创造力和可能性。除了在 Gmail 里向 twitter bot 发消息外,最便捷的莫过于在随时开着的终端 shell 里面写上一句然后敲回车。 找来这段脚本,用 curl 一下搞定。

#!/bin/bash
read -p "twitter> " -e input
curl --basic --user username:password --data status="$input" http://twitter.com/statuses/update.xml > /dev/null
echo "OK"

修改其中的用户名密码,保存为 twitter ,再 +x 后扔到 /usr/local/bin 里面,然后就可以直接通过执行这个命令来发消息了。十分 handy 的东西。

Gmail 的附件下载

  • 发现先是显示“正在检查病毒”,然后再变成下载连接。
  • 貌似原来不是这样子的。
  • 猜想它是要确保在下载前的最后一刻,用最新的病毒库检查。
  • 不预先扫描,以此达到资源和准确性的平衡。

Gmail 的 IMAP 服务的小发现

通过 IMAP 协议创建的目录,名称可以是中文,不过服务器上保存在文件系统上的不能是用户输入的文字,需要经过 Modified UTF7 编码,所以中文目录名称看起来都是 & 开头 – 结尾的一串字符。

Gmail 开放 IMAP 之后,可以看到一个名为 [Gmail] 的目录,其中还有六个子目录,分别对应 web 上的那些信箱名称。原本我是用中文的 web 界面,所以看到的这些子目录也都是中文的。今天偶然改用英文之后,发现 MUA 报错,无法连接到那些 & 开头 – 结尾的资源。我立即意识到,Gmail 作了同步更新,于是重开 MUA,确实 [Gmail] 下的子目录都已改为英文名。好细致周到的设计。

于是我在想它的实现方法。开始我觉得可能改了 IMAP 服务器软件。想起来 Gmail 存储的邮件应该不是简单的在文件系统中的 Maildir 格式下的文件,只需要按照协议返回相应的数据就好了。因为 Google 的强大令人觉得它无所不能。后来我在想,或许并不是这样,搞几个目录,然后给文件做上 hard link ,语言改变的时,rename 一下也费不了多少资源。

可后来的验证说明,Gmail 的 IMAP 服务器还是修订过的:当我重命名 [Gmail] 下的目录时,返回错误:

Folder name [Gmail]/Sent Mail - chunzi is not allowed. (Failure)".

但修改标签目录是可以的,刷新 webmail 后,标签的名称也跟着变化了。另外验证 IMAP 协议打上 Flagged 的标记后,也确实会跟着在 web 上标为 Starred。

Jemplate – Javascript Templating with Template Toolkit

今天一早来,很高兴看到能有这样一个模块。名字不太好读,不过很容易记。

http://search.cpan.org/~ingy/Jemplate-0.16/lib/Jemplate.pm

这个模块提供了一个工具,叫做 jemplate ,用来将 TT 的模板文件(可以是若干个)整合为某个 js 文件。结合该模块提供的另一 js 模板引擎 Jemplate.js ,在所使用的页面中,同时加载这两个 js 文件,于是你就有了在客户端,动态加载模板化驱动数据展示的能力。而这个数据则可以通过 Ajax 返回的 json 格式的代码获取。Damn cooool!!

第一个反应就是,我也可以做到和 Gmail 一样的多语言加载了。

HTML 洗刷刷

webmail 上如何显示 HTML 格式的邮件正文?用 iframe;或格式化后嵌入当前页。

iframe 可以最大限度还原原来的 HTML 页面效果,但存在安全隐患。而且可能需要用户横向移动滚动条,不宜阅读。直接将源代码嵌入当前的显示页面,也存在安全隐患,而且很容易引入 css 而使 webmail 的整体风格破坏。除了 Js 带来的问题,还可能由于 HTML 中引用了外部的“图片”,而暴露邮件账户的真实性 — 垃圾邮件制造者可以通过一个形如静态图片连接的程序,在纪录邮件地址的有效性后,返回一张图片的二进制数据流。所以,Gmail 会提示是否现实外部图片。

仔细参考 Gmail,它是用了后种策略。而且,不光是去掉了 js 和 css ,还对外部图片和外部连接作了处理。 默认,img 标签被去除了 src 属性。所以仅显示占位区。而 a 标签增加了 onclick 事件绑定,这样,点击邮件中的连接不再直接当前 webmail 页面中跳转,而是新开窗口。对于 class 和 style 属性,Gmail 也都作了删除处理。所以 Gmail 给你的并不是原汁原味的 HTML 邮件。

未必一定要原汁原味 – Gmail 是这样处理的,作出这样的决定,就我而言,是不容易的。我总希望能“高保真”。如何取舍?用户关心什么?在乎视觉效果?还是在乎邮件所表达的信息?Gmail 给了我一个很好的启示。

于是,我希望有一种类似的方法处理原始 HTML 数据。当然,可以用 HTML::Parser 来做,不过太过低级别。因为我们还有 HTML::SantizerHTML::ScrubberHTML::Truncate

这三个有所类同,又有所区别。我还是比较习惯于 Scrubber 。记以抛砖引玉。

lzmail – Flash Webmail

http://www.laszlomail.com/lzmail/

做得还不错的 Flash Webmail。不过我还是喜欢用 Gmail 简单清爽。

addEvent()

做 web 应用的人,经常会用到 Javascript 来处理页面上的一些事情。表单验证我们不谈,在根据用户使用情况,显示/隐藏,或者执行一段 js function,的时候,我们需要和页面的 DOM 树打交道。看看 Gmail ,发送邮件,按下“发送”钮后,用 Ajax 在后端发送邮件内容,根据返回的状态,在编辑页面的上方直接显示一小段文字“您的邮件已经发送。”。

通常的思想,我们会在那个发送按钮里面写上:

onclick="javascript:sendmail();"

然后由它来处理。Ajax 返回后,再触发另一个 show_status() 在 id=status 的对象中给出相关的状态信息。 复杂的应用的话,源代码里面满目的 html 和 js 混杂。不易维护,也不足够灵活。按理,XHTML 只是用来表示一个表示层的 DOM 树,JS 则对这棵树来做一些操作。交错混杂都谁都不好。

现在有了 addEvent() 和 removeEvent() 。问题就简单了。对一个 dom 对象,给出事件类型,给出所要触发的 function ,这个世界就清静了。你可以随时 remove 掉,换个新的事件处理。如此可以简化很多代码。quirksmode 搞了个比赛,ejohn 拿了第一名,他的实现是所有参与者中最简单明了的一个,在他的 blog 上给出了相关的说明和演示

addEvent( object, eventType, function );
addEvent( document.getElementById('foo'), 'click', doSomething );
addEvent( obj, 'mouseover', function(){ alert('hello!'); } );

使用之前,先把下面的代码复制过来:

function addEvent( obj, type, fn ) {
  if ( obj.attachEvent ) {
    obj['e'+type+fn] = fn;
    obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
    obj.attachEvent( 'on'+type, obj[type+fn] );
  } else
    obj.addEventListener( type, fn, false );
}
function removeEvent( obj, type, fn ) {
  if ( obj.detachEvent ) {
    obj.detachEvent( 'on'+type, obj[type+fn] );
    obj[type+fn] = null;
  } else
    obj.removeEventListener( type, fn, false );
}