从 logo 猜出来的,不过好像还没有看到相关的新闻。
突然体会到,iPad 放在 dock 上看,无比登对。 7 hours 59 minutes ago
dp.SyntaxHighlighter,一个 JS 写的语法高亮显示工具。好处在于可以直接在客户端完成语法高亮显示功能。这样 Blog 上的代码可以在不加后端处理程序的情况下,直接在页面上展示。它可以动态的替换 textarea 中的内容为高亮后的 html 代码,只需要在 textarea 的 class 属性中指定即可。
只可惜官方还没有对 Perl 的处理,或许哪一天我可以写一个,hoho~
Ajax 技术热起来之后,相继出现了各式各样的 Ajax 框架库。Catalyst 使用了其中的一种:Prototype 。Mochikit 刚刚发布了 1.0 版本,虽然不是完整的关于 Ajax 处理的库,不过对于常用的一些处理,都提供了相关的函数。
Mochikit 声称自己高度文档化以及良好单元测试。所以看起来是个可以实用的好东西。
Prototype 仅仅提供在 js 内发送请求到服务器,然后照本宣科的把返回的内容给程序员进一步处理,如果服务器没有响应,或者出现意外情况,返回的可能是一堆 404, 500 错误的页面代码。Mochikit 则通过他自己的 MochiKit.Async 提供了 XMLHttpRequestError ,如果出错,会通过 alert 通知客户发生意外。
MochiKit 对于 DOM 的支持也非常不错,我以前要写一堆的 function 来细化的工作,现在只要几句话就可以了。此外,Mochikit 可以直接对字符串或者数字格式化输出,比较实用和方便。
它还有自己的 js 代码解释器,它的交互模式借鉴了 Python 解释器。它还有自己的正则表达式引擎。个人感觉还是 DOM 这部分更加实用一些。
Catalyst 下面的 Plugin 总是那么简单。这个 Plugin 目标要对来自请求的所有参数进行 html 安全过滤或者代码清理。核心过滤使用了 HTML::Scrubber 模块,所以相关的 Plugin 配置也是迎合 HTML::Scrubber 的需要。
所谓安全,就是去掉 Javascript 代码,所谓干净,就是去掉 html 注释,并且仅仅允许使用若干指定的 html 标签。如果我们要做 CMS 并提供用户编辑 html 源文件的话,这个 Plugin 可以帮助我们简化安全过滤。只是它针对所有的请求参数,也就是 $c->req->params 都进行了这样的过滤,是不是会发生聪明人自作聪明多干活的事情呢?我宁愿在指定的参数上作这样的过滤。或许该模块作者要做的项目确保不会出现干扰问题,所以才写了这样的 Plugin 吧。
Ruby on Rails 的又一作品。RSS Fwd 就是说要把订阅的 RSS 的内容通过邮件转发(Forward)过来。很简单的思路,实质上是把内容从 Pull 变为 Push 。设置定时收取邮件,即可在第一时间,轻松阅读最新的文章,而我现在,一有空闲,就会上 gouogu.com 去查阅最新的内容,有些麻烦。
不过这样会有一个问题,在我订阅的那么多东西里面,有些是我比较关注的,有些是可看可不看的,所以如果一股脑儿所有的更新都蜂拥而至的话,可能会把真正有价值的东西淹没掉(看不到,分散注意力)。所以我想应该有一个按照关注程度来设定是否发送邮件的选项。进一步的,对于短时间内会集中更新的那些 Feed ,也应该可以设定比如 4 小时作一个摘要邮件一起发送的设定。
刚试用了一下,就出现“Server Busy”,呵呵,看看再说。
这次更新除了 fix 一些 bug 之外,还提供一些新的特性,所以有必要了解一下。
原来默认使用 Template::Timer 来统计每个模版段落处理所消耗的时间,现在即便在 debug 模式下也不会启用该功能,除非在配置中指定:
MyApp->config({ 'MyApp::V::TT' => { TIMER => 1, }, });
原来模版文件是放在 root 目录下面的,现在不这样做了。原先我就奇怪,root 下面基本上都是 public 的东西,为何 template 也放在其中,所以我自己写的时候都在自己的 view 里面定义好 INCLUDE_PATH 的,不过现在好了,直接在外面写好配置:
our $ROOT = '/home/dent/catalyst/MyApp'; MyApp->config({ name => 'MyApp', root => $ROOT, 'MyApp::V::TT' => { INCLUDE_PATH => ["$ROOT/templates/src", "$ROOT/templates/lib"], PRE_PROCESS => 'config/main', WRAPPER => 'site/wrapper', }, });
Technorati 是个对 Blog 做搜索和聚合的网站,早就听说大名,也看过几回,终于尝试一下用用看。
用了大约半年,我的笔记本开始频繁出现各种异常。速度也越来越慢,实在不堪忍受,于是终于下定决心重灌。目前我的开发都是在 Windows XP 下面安装了 Vmware 的虚拟机,跑一个 FreeBSD 来做的。以前配置 Vmware 的时候也是痛苦万分,总也不得正果,这次又要重配,按理说按照原来的思路做下来应该不会有问题,可事实无情的嘲讽了我,一度让我怀疑是不是老了,很多次解决掉的疑难问题再次出现的时候,只记得曾经发生过并且成功解决过,可就是死活记不起来具体是如何做的。这让我的内心无比痛苦。但是问题出现,就必须解决,上帝保佑,这次我还是在经历了很多个小时后,终于重见天日。回过头来看看,多么简单阿。
虚拟机在我的笔记本上,需要能够连接到外网。我工作中有两种上网方式,公司里,有一个 IP 为 192.168.1.2 的 ADSL 路由器拨号上网,windows 被 DHCP 分配一个内网的 IP 192.168.1.x 。家里通过有线通的 Cable Moden ,windows 直接获取外部 IP 地址。所以我需要在两种环境下都能使 FreeBSD 能够访问外网。
FreeBSD 设定为一个固定的内部 IP 地址,192.168.1.10 网关 192.168.1.2 。在公司内部,使用 Bridge 方式,将虚拟机直接挂到公司的内部网段中。简单而完美。
回到家里,或者无线拨号上网,则改为 host-only 方式,选择 Vmnet1 网段,该网段设为 192.168.1.0 ,而在 windows 的网络连接中对应的 Vmnet1 设置一个固定的 IP 192.168.1.2 。也就是说,这个时候 192.168.1.0 网段在我的 windows 内部,windows 本身作为 1.2 连到这个虚拟网络,之所以选这个 1.2 ,是因为如此可以不用修改 FreeBSD 的网络配置。FreeBSD 依然通过 1.2 这个 Gateway 出去。同时我们不需要 Vmware 自己提供的 DHCP 功能,直接从 dhcp adaptor 中删除 vmnet1 网段即可。
本来事情就是这么简单的。我从 1.2 ping 到 1.10 通。从 1.10 ping 1.2 不通。这个问题困扰了我很久。最后把 windows 的防火墙关掉,就通了。现在 FreeBSD 虽然可以 ping 到 1.2 可却 ping 不到外网地址。第一反应是共享连接。于是将连接到外网的连接属性中设置共享,于是提示将会改为 192.168.0.1 的 IP 地址。我立马选择否,因为我不需要使用 0.x 网段。于是事情依然没有进展。在万般无奈下,我选择了是,然后 Vmnet1 的网络连接从原来我设定的 192.168.1.2 被强制改为 192.168.0.1 。这让我很不爽。再手动改回来。到此为止,天空变得蔚蓝蔚蓝。
我遗漏了这两步,想来该是以前配置的时候,稀里糊涂地先做了这两步,而后才做之前的那些配置。所以我明白了,并不是记性不好,实在是以前解决问题的时候囫囵吞枣,迷迷糊糊的走过来的,所以自然不能回想起来喝醉酒时走过的路。还好不是老年痴呆,万幸万幸。知其所以然比起知其然,更为重要,否则冤枉路要走不止一回。
做 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 ); }