发点牢骚

公司的人一多,网速就几何级下降,弄得断网了,只好离线发点牢骚。

用了很久的笔记本也是一个慢字。窗口一多,简单的事情都要你等上半分多钟,好脾气也要变成坏脾气了。老机器,已经换过 5400 转的硬盘了,算是快了许多,不过内存还是 128M ,想加都找不到 SDRAM 的条子了。还被我摔过几次,有时候会突然死机,花屏,或者干脆点不亮。刚才擦了擦屏幕上的水珠,突然间就鄢掉了。还好工作的东西都保存过,不至于太大的损失。

于是彷徨。想换台式机,跑客户不方便,加班不方便。想换新的笔记本,刚买了房子,欠了人家好几万的债,哪来的钱买新的?唯一的办法就是忍。大概这样再过几年,我就可以说我是忍者了。哈哈。

世界本来就不完美。还是我的心态不完美?

这段时间总是很激动,加上感冒(不知道是不是人流感),心跳的很快,不得安逸。心跳得一快,呼吸就无法均匀,要么喘喘气,要么大大地喘口粗气。现在不抽烟了,所以唯一的选择就是喝茶。茶水泡过三巡就要换。坐在座位上起来三次,两次是跑水,一次是上洗手间。当然也有合着来的,这半圈过去泡水,顺着那半圈提着杯子上洗手间。

hoho, 网通了。

javascript 实践

这两天在做公司的项目,为了更好的用户体验,我在界面上做足了功夫,当然也离不开 Javascript。

以前用 prototype.js 的时候,只是参照 HTML::Prototype 中的文档,照葫芦画瓢,未得深意。后来从 fayland 的共享连接中看到了 prototype.js 的非官方版本的中文翻译,大致看了下,才知道自己错过了很多东西。

于是打印出来,在回家的路上通读了一遍,小有收获。起码我知道可以用 $() 和 $F() 这两个简单的写法,再也不用满页面写 document.getELementById() 了,虽然我已经写起来非常熟练。此外,我经常做的一件事情 — 显示或者隐藏某个 id 的元素 — 再也不用直接设定 style.display = ‘inline’ 什么的,直接用它提供的 Element 类的 show, hide, toggle 方法即可。Javascript 其实远比以前我所认识的要丰富,除了像以前那样构造一些 function 之外,我还可以轻松的构造一个对象来做一些事情。虽然 JS 没有像 Perl 一样的 Hash 数据结构可以直接调用,不过可以用 Object 来代替。

prototype.js 被提到的时候,通常作为 Ajax 技术而被谈论。在看过这篇文章之后,你就该了解,prototype 叫做原型的道理,就说明了它是构建于 Ajax 这种技术之上的,Ajax 只不过是它默认提供的原型之一。prototype.js 的目的是要简化人们的日常工作,提供更为快捷有效的方法来让人们直接在业务层上考虑问题。同时作为对现有的 Javascript 以及对 DOM 操作的扩展,提供了更强有力的后援。所以在我看来,Prototype.js 好比是 Perl 里面的 Module。那么是不是我将来的关于 Javascript 的操作也可以自己扩展出一套 module 来简化我自己的工作呢?当然可以!Rico (rico.js) 什么的就是在它的基础上继续扩展衍生的产物。看看 prototype.js 的源代码吧,并非讳莫如深,仔细研读之下,甚至你可以自己动手修改扩展它的功能。

在自己的项目中,当文本输入框中的输入变化的时候,我希望在展示区域动态的现实当前的内容。而当用户按下 Enter 键(包括 Table 键)的时候,我希望能够对输入内容作出检查并跳转到下一个 card (并非 form 的 submit)。前面的好办,在 input 标签后面写上 onkeyup=”apply();” 即可,可 Enter/Table 怎么处理呢?嗬嗬,合起来,自己写个 Watcher 类:

Watcher = Class.create();
Watcher.prototype = {
	initialize: function(element, apply_func ) {
		this.element = $(element);
		this.apply_func = apply_func;
		this.eventKeypress  = this.keyPress.bindAsEventListener(this);
		this.eventKeydown  = this.keydown.bindAsEventListener(this);
		Event.observe(this.element, "keypress", this.eventKeypress);
		Event.observe(this.element, "keyup", this.eventKeydown);
	},
	keyPress: function(event) {
		if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN) {
				next_card();
		}else{
				this.apply_func();
		}
	},
	keydown: function(event) {
		this.apply_func();
	}
};

我们观察 keypress 事件,如果发生了该事件,就让 this.eventKeydown 来接手处理。而 this.eventKeydown 这个对象属性已经绑定为 keydown 这个方法的事件监听器,所以,让 this.eventKeydown 接手,实际上就是触发调用了 keydown 对应的 function 。这里的 keydown 可以理解为像 Perl 里面的匿名代码引用(code ref)。原本传入的 apply_func 也是 code ref,所以 this.apply_func 也是 code ref ,而在这个 ref 后面加上 () 就是 call the code。完美解决。HTML 里面什么都不用写。只要 new Watcher( ‘text_id’, apply_text ); 就可以了。

后来我在使用 $() 的时候发生一个奇怪的问题。当 $() 内部调用通过 innerHTML 插入的某个元素的 id 的时候,如 $(test_id) 会报告 test_id 未定义。为此我困惑了很久,还另外作了实验验证。最后发现,$() 的语法有两种用法,$(test_id) 和 $(‘test_id’) 。不一样吗?确实不一样。用后面一种就安全得多。至少不会和既有的对象名称重复。不过 IE 下面的 Javascript 调试很麻烦,这也是为什么一直没有深入系统的学习 Javascript 的原因之一。

在经历了一系列的痛苦和喜悦之后,这个世界变得越来越和谐统一了。Perl/Javascript/Ruby/… 形式不同,思想皆通。

Google Ads

Catalyst 5.58 正式支持 PAR

目前的 5.57 还有些 bug ,不过当前 trunk 里面的(未来的 5.58)将正式支持 PAR 封装应用为一个独立的程序。这样我们用 Catalyst 开发的产品就可以轻松的卖给那些使用普通虚拟主机的用户了。

这里是简单的构建 PAR 包的步骤:

把下面这些代码添加到 Makefile.PL 里面:

catalyst_par_core();
catalyst_par();

然后执行:

$ perl Makefile.PL; make test; perl Makefile.PL

然后用 PAR 模块的 pp 打包:

$ pp -o myapp myapp.par

所生成的 myapp 就是可执行的二进制文件了。可以连同帮助文件,版权声明一起压缩打包后发布了。

sri 提供了 OSX 下面的演示打包文件:http://files.oook.de/myapp-osx

$ ./myapp-osx
Usage:
     [parl] myapp[.par] [script] [arguments]
 
   Examples:
     parl myapp.par myapp_server.pl -r
     myapp myapp_cgi.pl
 
   Available scripts:
     myapp_cgi.pl
     myapp_create.pl
     myapp_fastcgi.pl
     myapp_server.pl
     myapp_test.pl

Catalyst::Plugin::Redirect 0.01

Catalyst 本身就提供了 $c->res->redirect(“…”); 的用法。不过这个 redirect 是全局的。如果 /admin 那就 redirect 到 http://example.com/admin 。如果你的应用直接部署在域名的根路径下不会有问题。但如果你部署在 /myapp 下面的话 $c->res->redirect(‘/admin’) 会重定向到 http://example.com/admin 而非预期的 http://example.com/myapp/admin 。

于是有了 Catalyst::Plugin::Redirect

这回你可以用 $c->redirect() 来做。他封装了 $c->res->redirect();

当你给出的 url 是 http 开头的,或者不是 / 开头的 url 的话,直接交给 $c->res->redirect 来处理。但当给出的 url 是以 / 开头的话,则重新构造目标 url 。假设部署在 http://example.com/myapp/chunzi 下面,给出的 url 为 /admin ,则重定向到 /myapp/chunzi/admin 。

很简单,不过还是比较有用,其实完全可以放到 core 里面而不是作为一个 plugin ,呵呵。

JSON

http://www.crockford.com/JSON/说到数据交换,大体上我们的第一反应就是 XML 。严谨规范。Java 的世界里面如果不用 XML 来配置或者部署,就免不了有血统不纯的嫌疑。不过我不喜欢 XML ,好啰嗦。

然后在我们的应用中喜欢用 YAML 。一种人类可以直接读懂和修改的数据交换格式。它可以很简单,比 windows 下面的 ini 配置文件还简单,也可以很复杂,你可以把你的 Perl 代码中的对象序列化到 YAML 文件里,然后在 Java 里面构造出同样数据结构的 Java 对象来。让人爽得不行。

现在出来了个 JSON ,叫做 JavaScript Object Notation 。这里有篇介绍 。而 CPAN 上也有一个 Perl 模块 JSON,用来把 Perl 的数据结构转化为 JSON 。

JSON 有什么用呢?既然它是一个数据交换格式,我们就可以通过它来做比如远程调用。XMLRPC?现在可以 json-rpc 了。

现在广泛运用和讨论的 Ajax 技术,在后端从服务器取回来的响应一般有以下几种应用:

  • 返回的内容(html 代码片断)直接更新为 DOM 中某个元素的 innerHTML
  • 返回一段 Javascript 然后在客户端浏览器上 eval 运行
  • 返回一段 XML 文档,通过客户端对该 XML 文档的解析来同步更新多个 DOM 元素或者作出各种响应。

现在好了,我们可以返回 JSON 代码,然后通过客户端的 javascript 直接将它转化为 Javascript 的对象和数据,然后做各种你想要做的事情。我不得不说很酷。

目前公司的代理平台项目,我本打算做一个类似 api.xxx.com 的站点,提供 http post 请求,返回 xml 响应,以便客户端的 js (像 Rico 这样的 Ajax 引擎)来分析并处理。还好尚未有时间实施,看来用 JSON 更妥。

lzmail – Flash Webmail

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

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

domains.live.com

从 webleon 的这篇 Blog 看到,微软他妈的也开始做邮局了,只要你把 MX 纪录指过去就可以了,默认每个域 20 个账户。每个账户 250 M 空间。

他这样一来,肯定要分掉一部分企业邮件市场。而整个市场中,需要 20 个账户的公司就像浮油生物一样,虽然小,却是数目庞大。我们以后靠什么吃饭?

现在不用担心的是,那些高端用户,他们在乎特别的需求,在乎有个人在电话另一端能够听他的指挥,哪怕是牢骚。看来以后的方向一定要从企业的心理去挖掘,避免可恶的 live 分流。

不过,话说回来,这一切也都是必然,迟早要来的。

Catalyst-5.57

Catalyst 5.57 刚刚发布。

– 更新了 uri_for ,现在可以接受 undef 的 action 了
– 改用 Module::Install
– 为了方便编辑,重新命名了测试脚本
– 文档重构
– 把 -nonew 改名为 -force
– 现在开始支持 PAR 打包了
– 对 HTTP 引擎增加了对 keep-alive 的支持,并修复若干问题
– 为 FastCGI 引擎增加了后台运行的选项

此外,同期发布的还有 Task::Catalyst 。有点类似 Bundle::Catalyst 主要目的是帮助你一下在安装好所有常见的 Catalyst 应用所需要的相关模块。

$ perl -MCPAN -e 'install Task::Catalyst'

Task::* 模块的目的是要取代 Bundle 机制。看看 Task 的文档。

MIME-Lite-TT-HTML-0.01

看到 cpan 出来了个 MIME-Lite-TT-HTML-Japanese 模块。

之前就有个 MIME-Lite-TT-Japanese 模块,为了解决字符集的问题,不过它 hardcode 为日本的常用字符集,所以在自己的项目中作了个简单的 MIME::Lite::TT::Charset 来完成工作。

这个新的 HTML::Japanese 增加了对邮件中 html 正文和 text 正文的支持。Okey,我就像要一个更为抽象或者通用的模块来处理这些事情。结合之前的经验,大多数国人所用的邮件客户端尚不能很好的支持 utf8 标准字符集,而我又希望项目使用 utf8 来实现,所以除了制定字符集外,我还希望能有字符集转换的功能:项目以及模版都用 utf8 ,发送出去的邮件中,使用转换结果:gb2312。

于是动手自己做了一个,MIME::Lite::TT::HTML,虽然很不好的爬到人家头上去了,不过想来想去也只有这个比较合适。源代码已经上传到 svn.perlchina.org ,也刚刚上传到 cpan。

由 Behaviour.js 到 Degrader.js

Behaviour.js

Ajax 用起来很酷,可是你要要在 XHTML 里面写上 onclick,onmouseout,onkeyup 等等来触发调用一些 js function 。于是,Ben Nolan 在 http://bennolan.com/behaviour/ 上发布了 Behaviour.js 。和之前谈到的 FSA::Rule 模块类似,只要在 XHMTL 中给出 id 并且定义好一些 Javascript 的 Rules,并把这些规则注册到 Behaviour 引擎中即可。至于规则的定义,分三部分,也就是对谁在什么时候做什么事情。通过 css selector 来实现“对谁”,所以之前定义的 id 在这里派上用场了,也是 js 和 xhtml 只见的纽带。“在什么时候”,也就是相关的事件出发,比如一系列的 on… 事件。一旦发生事件,就触发去做一件事情,“做什么事情”也就是要做事情的 js function ,至于其中如何,随你的便了。

Degrader.js

Encytemedia 觉得 Behaviour.js 不爽,很多业务细节暴露在外面,也就是不够抽象。于是在这里(这是Part2) 发布了他自己改良的 Degrader.js 。废话少说,先看张图示:

通过对 id 名称的模式匹配,可以对许多个 id 绑定义系列的事件触发。所以,你只需要给出 pattern 并在 onMatch 的时候,动态注册一系列的事件观察(Event.observe),一旦发生了某个 event 就调用某个 function 。使用 Observe 设计模式,代码更为简洁优雅清晰。接下来该作者还会发布 Part3 给出一个实际的 RubyOnRails 应用。

此外,W3C 开始介入 Ajax 相关的领域,成立了 Web APIs Working Group ,开始要制定一系列的标准。看来真的要革命了。