Author: Raymond

处理Emacs中的行号和空白字符

做过开源项目的童鞋可能会知道,在很多开源项目中会有专门的脚本来检查代码风格。其中包括行尾是否有多余的空白字符,是否使用使用tab,每一行是否超过了指定的宽度等等。这些问题通常在敲代码的时候并不容易看出来,等到要提交代码的时候才发现问题。稍微搜索了一下发现在emacs中有一个很有用的whitespace插件可以解决这个问题。

whitespace可以针对设置的规则对上面提到的问题进行高亮显示,效果如下:

WhiteSpaceOnLight

whitespace具体可以找到的问题包括tab, 空格混用;行尾多余的空白字符;文件结束前的空白字符;超过指定长度的行等等。可以通过设置whitespace-style来指定需要提示哪些问题。在我的配置中使用了如下配置:

1
2
3
4
5
6
7
;; deal with white spaces
(require 'whitespace)
(global-whitespace-mode)
(setq whitespace-style
      '(face trailing tabs lines lines-tail empty
        space-after-tab space-before-tab))
(add-hook 'before-save-hook 'delete-trailing-whitespace)

默认的whitespace-style把整个buffer被搞得有点乱糟糟的,因此我把不是很需要的部分都去掉了,只剩下检测行尾空白、tab等少数几个问题。对于行尾的多余字符而言,一个个删除也是很麻烦的事情。所以我直接用delete-trailing-whitespace在保存的时候把它们都干掉了。

不过在这里whitespace会和行号有一点点冲突。通常为了显示行号都会打开linum-mode,行号会是右边对其的数字。whitespace会认为行号前面的空白字符是问题字符而高亮显示,搞得非常难看。为了解决这个问题可以用下面代码对linum进行设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
;; Show line number
(require 'linum)
(global-linum-mode t)
(setq column-number-mode t)
(setq line-number-node t)
(setq linum-format "%5d ")
(add-hook 'linum-before-numbering-hook
          (lambda ()
            (let ((w (+
                      (length
                       (number-to-string
                        (count-lines (point-min) (point-max))
                        ))
                      2)
                     ))
              (setq linum-format
                    `(lambda (line)
                       (propertize (concat
                                    (truncate-string-to-width
                                     "" (- ,w (length (number-to-string line)))
                                     nil ?x2007)
                                    (number-to-string line))
                                   'face 'linum))))))

这是从emacs wiki上面抄过来的一段代码,用了一个特殊的unicode字符x2007来设置行号的格式,既能达到右端对其的效果又不会被whitespace误杀。

Emacs中处理日志文件

最近写的东西会将信息输出到一个日志文件中去,每次调试的时候log文件内容都会刷新。每次都手动revert-buffer比较烦人,查了一下发现有一个auto-revert-mode可以自动刷新。下面的配置可以实现对于.log文件调用auto-revert-mode:

1
2
3
4
5
6
7
8
9
10
11
;; auto revert log files
(add-hook 'find-file-hook
          (lambda ()
            (if (string-equal
                 ".log"
                 (substring (buffer-file-name)
                            (search "." (buffer-file-name))))
                (progn
                  (setq auto-revert-mode t)
                  (message "Enabling auto-revert-mode for log file")))
            ))

如果是比较长的日志文件,并且日志使用追加内容的方式添加上去的话,可以将上面的(setq auto-revert-mode t)换成(setq auto-revert-tail-mode t)以提高效率。

STL中的红黑树

平时用STL通常只是顺手把vector, map之类常用的类拿来用用就完了,也没有想到去仔细研究里面都有些什么东西。这两天有一个算法程序需要将一堆对象排序,并且会非常频繁的插入删除,对效率的要求极高。原本想用priority queue,但是发现它是对一个数组进行堆排序的方式来操作,效率并不高。在STL的文档里面找了找发现居然没有红黑树,google了一下才知道set, map底层都是用红黑树实现的,只是这个红黑树没有暴露出来给人用。

也不知道是出于什么考虑,性能优秀的红黑树虽然标准库里面有,但是却遮遮掩掩不直接提供给大家用。值得注意的是,因为红黑树是内部使用的类,各个STL实现中的红黑树还不一样。

在VC的实现中红黑树是在xtree文件中的_Tree类,用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include 
#include 
#include 
 
using namespace std;
 
typedef _Tree< _Tset_traits, allocator, false > > rb_tree;
 
int main()
{
    rb_tree* tree = new rb_tree( less(), allocator() );
    for(int i=35; iinsert(i);
 
    printf("output: %d ", *tree->begin() );
}

gcc中的实现则是在bits/stl_tree.h文件中,而且类的名字和用法都不一样:

1
2
3
4
5
6
7
8
9
10
11
12
#include 
 
typedef _Rb_tree,
                 less > rb_tree;
typedef rb_tree::iterator rb_tree_iter;
 
int main()
{
    rb_tree queue;
    queue._M_insert_unique( int );
    printf("size: %d", queue.size() );
}

对Archlinux的怨念

之前之所以开始使用Archlinux是因为觉得ubuntu的软件包更新太慢,有的软件居然用的还是一年多以前的版本。冲着Archlinux的Rolling Release的名号在自己电脑上把它装上了。

事实上Archlinux的确是一个很有特色的发行版,主要在于它的软件包管理系统可以支持用户向软件仓库中提交软件包的编译脚本。通过这个编译脚本它可以自动化的完成下载源代码、编译、打包、安装的过程。因为编译出来的代码是经过打包以后再安装的,自然这就比传统的make install要保险的多,至少你不用担心卸载的问题,同时还能够随时用到最新的软件。

另一个特点是它的包管理器不会去修改你的配置文件,很多升级相关的操作也没有实现自动化(比如说内核升级以后有些内核的mod就必须自己手动编译、设置),而ubuntu则会在内核升级的时候把所有相关的东西都给你设置好。Archlinux的开发者声称这是一个feature而不是一个bug,因为Archlinux的哲学是不会让软件自作聪明。

好吧,看起来这真是一个能让你变成资深黑客的发行版(或者至少是看起来像黑客)。但是用了一段时间以后发现Archlinux有的时候实在是会有让你砸电脑的冲动。它的软件仓库实在是太不靠谱了!我在虚拟机里面跑了几个月的Archlinux,经历了两次更新以后莫名其妙的问题。在直接装到硬盘上以后又经历了两次。或者是更新以后死活进不了gnome,一登录就重新回到gdm;或者是更新完以后直接所有bash命令都失效;或者是告诉你内核出了虾米虾米问题。

当然hacker就要有hacker的样子,找到bug,告诉developer,甚至自己写个补丁发过去。但问题是这种问题通常都是快速出现并且快速消失的。也许这个问题只是在某种特殊情况下出现,当过两天软件更新到某个更新的版本的时候这个问题又不复存在了,每次我都会在irc, news letter, forum, google里面到处问但是却根本没有人知道是怎么回事,看来我是少有的几个遇到问题的倒霉蛋。更要命的是它出问题的时候正是大作业如滔滔江水绵绵不绝的时候,而我想要写篇latex却要用另外一条电脑满世界找不知道藏在哪个犄角旮旯的解决方案。

好吧,我认输。在忙过那一段时间以后又一次直接把archlinux重装了,并且决定要是下一次还在更新以后出问题我就再也不用这个东西了。后来再跟一个朋友聊天的时候知道他以前也用的archlinux,一问才知道他也遇到了所有bash命令出错的问题,一怒之下又装回了ubuntu。看来倒霉的人不止我一个 Orz
以前有人说Linux是一个危险的东西–它会让你不知不觉的把大量时间耗费在无意义的对系统的配置上面,而正经事儿却一件也没有干。对于其他Linux可能未必是这样,但是,Archlinux的童鞋们,小心了。

尝试给开源项目打补丁

最近开始尝试给开源项目打补丁。首先是跑到Gnome Love上面去逛了一圈。GnomeLove是Gnome官方为了降低开源开发者加入的门槛而搞的一个页面,上面有一些帮助入门的文档链接,从GTK开发到git的使用都有。然后再到Bugzilla上面用GnomeLove作为关键词,能够搜索出一堆比较容易改的bug。
我抓了Empathy的一个bug开始改。Empathy有一个问题就是,它的聊天窗口不会记忆联系人边栏的位置,每次打开一个窗口都需要自己重新拖动它。修改这个bug也很简单,在聊天窗口创建的时候加入一个事件响应函数。然后再在窗口边栏位置变化的时候把这个位置保存在GConf里面,下次窗口打开的时候再把这个数读出来就好了。上次Jesse给Gnome给数独游戏修改bug的时候对方一个多月以后才有反应,不知道这个bug多久以后会有人理我?

尝试VPS中

前两周俱乐部买了一个VPS服务器,几天下来基本上明白VPS是个怎么个用法儿了。
首先VPS是一个运行在服务器上面的虚拟机,你可以通过ssh等方式来控制它。我们买的这个是centos的系统,搭配了Kloxo来进行管理。Kloxo是一个通过网页方式来控制VPS的管理程序,功能非常强大,域名、DNS、WEB服务器、配额管理、文件管理、进程管理、文件操作、文件解压,什么都可以做。通过Kloxo可以直接添加域名,设置web服务器的基本配置,启动服务,中间不用一个配置文件都不用改。

Kloxo另外一个很有用的功能是“客户”功能。你可以在Kloxo里面添加“客户”或者“代理”,他们就会拥有自己的一个Kloxo账户,还会自动生成Linux帐号、服务器配置文件、FTP帐号等等。客户和代理的区别在于后者拥有添加客户的权限。而对于每一个Kloxo帐号还可以添加一个子帐号来共同管理同一个Kloxo帐号(说的真绕,不知道说明白没有)。你可以买一个VPS然后给几个朋友分别开一个客户,分上限额,共同来用这个VPS。甚至都可以不会用命令行,只要明白了Kloxo那个网页界面就成。

通过ssh远程控制服务器的感觉的确比较酷,不过也出现了没有想到的问题。首先VPS价格会比普通的虚拟空间要贵,这直接导致我们买了只有128M内存的VPS。然后就是VPS不够稳定,这一点在我们这个小内存VPS上面就非常明显。一开始web服务器默认使用的是lighttpd,在换成apache以后一天之内死机了两次,而且都是在几乎没有流量的情况下发生的。检查了一下发现是内存用完了导致的死机。apache一启动以后就会有6个线程,每个线程显示占用20-30M内存。虽说实际使用的并没有这么多,但是随便来一点点访问量内存就全部耗完了。不得以换回了lighttpd,发现传说中lighttpd省内存还真不是吹的。

使用seige对VPS进行了一个小小的压力测试(其实没有多大访问量)。使用15个并发访问,每两次访问之间间隔1秒钟,也就是说每秒访问15次。总共持续10分钟。服务器方面,放了3个域名,分别对应了mediawiki, wordpress, drupal三个php程序。seige随机的访问三个域名中的任意一个。

seige统计如下:
Date & Time,      Trans,      Elap Time,      Data Trans,    Resp Time,    Trans Rate,    Throughput,    Concurrent,    OKAY,    Failed
2009-11-10 21:20:17,       5886,         598.99,        41,        1.02,        9.83,        0.07,        10.02,        5163,    0
这10分钟总共有接近6000次http访问,平均响应时间是1.02秒,最长响应时间7.7秒,最短0.49秒。

服务器端使用vmstatm每隔十秒记录一次内存使用量,内存余量一直在20-30M之间波动,在测试的后半段系统把一部分内存移到了swap分区,物理内存空余量回到了接近40M。CPU占用率一直在30%左右。

用GAE开发wiki

  我越来越发现我out了,GAE都出来这么久了我才发现在google code上面有一个google官方的项目,里面塞满了各种使用GAE来做应用的例子。于是国庆这段时间把它整个下了下来,将其中的cccwiki这个例子修改了一下成了一个可用性更强一点(但是功能仍然很弱,国庆闲暇时候做的东西不要有太高期待哈)的wiki。点这里可以看到例子,如果对源代码感兴趣的话可以在这里找到(使用Mercurial版本管理)。

wiki-screenshot

wiki-screenshot

  最初的cccwiki只是很简单的把每一个页面的html源代码保存并展示出来。我做了以下修改:

  • 增加了revision功能,把修改的历史记录都全部保存了下来
  • 使用wiki标记语法,而不是直接标记html
  • 用MarkItUp替代原先的TinyMCE作为编辑器。因为前者支持wiki语法,而且貌似也更灵活
  • 加入了CreoleParser来解析wiki标记语法。不过Creole语法和MarkItUp所支持的wiki语法不大一样,还需要对MarkItUp进行修改
  • 对界面进行了一点点修改,看起来似乎是要好一些了?

  整个修改的过程非常的顺利。我是用的Eclipse+Aptana PyDev来开发的,虽然整个过程中没有用一个完整的rails或者django之类的框架,但是效率并不低,很多功能很快就实现了。

  一方面是因为GAE特殊的数据存储机制。GAE中不能使用通常意义上的数据库,而是用的google自己开发的使用的分布式数据存储(官方管这个叫做 Google App Engine datastore)。感觉上应该很适合wiki这种数据。经过GAE包装以后感觉用起来非常像Ruby on Rails中存储数据的方式--你只需要声明一个类,然后把数据直接赋值给它的某些成员变量,然后调用一个叫做put的成员函数就保存进去了。对于查询也可以用类似Rails的类成员函数的方法来进行,同样的如果想要进行复杂的查询的话也可以使用GQL(一个google自己搞的类似于SQL的语言)来弄。总而言之,你不需要也不能和数据库打交道,也就免去了很多数据存储方面的代码量。这方面整体感觉和Rails非常像。
另一方面,虽然GAE并没有提供创建项目的一些脚本,但是这对于开发效率的影响其实也并不大。众所周知,那些脚本无非是给你创建一些文件夹和没有多少行代码的文件,在Eclipse中干这些事情也不会多花几分钟。

  django的粉丝肯定会对GAE非常不爽,因为数据库不能用直接导致django的MVC中的Model一层完全就不能用了。不过另一方面,自己重新写一个Model层也不会很费事,google已经把datastore弄得很好用了。真正让人觉得不舒服的是GAE中的诸多限制。你只能通过GAE中的接口通过http方式访问外部的资源,发邮件也是如此。如果你的程序太消耗CPU,或是带宽,或是其他什么硬件资源,那么它会被停掉。不过相对于其他的免费空间GAE已经算是很不错了。

  GAE上线到现在时间已经不短了,但是仍然没有多少出名的应用部署在GAE上面。这个结果似乎也是显而易见的:虽然GAE的软件部分已经开源了,但是其中的关键技术--分布式的计算和存储--却是其他人所很难复制的。为了开发GAE上面的应用我必须遵从它的软件接口,那也就意味着这个东西如果不想在google上面跑的时候就必须面临大量改动。而且谁也不能保证什么时候google会不会像关闭其他半途而废的项目一样关掉GAE。对GAE这个东西玩玩就好了,要是真想做东西的话还是用django吧。

Free Software Day @ Beihang

Free Software Day相片

活动结束以后所有干活儿的人一块儿拍的相片,头最大的就是我啦

在上次的InstallFest之后,北航开源软件俱乐部又弄了一次活动–FSD北航站。今年的自由软件日活动貌似声势浩大,光是北京就有12个地方在弄,其中绝大部分是高校。

这次活动BLUG给联系到了6位嘉宾前来演讲,包括北航毕业的3个师兄和3个来自不同地方的老外。计算机系的师兄分别介绍了云集算,moblin等。一位老兄介绍了很新鲜的OpenSource Hardware的概念,感觉上就好像是DIY程度很高的单片机之类的东西。用着可爱的100美元电脑的Martin仍然活跃在开源圈子里面,时隔一年又来到了北航介绍如何开始使用Linux。

整个活动从两点持续到四点。原本担心会因为没有人来而变成我们这帮人的自娱自乐,结果演讲还没有开始教室里面就已经做的满满当当了。因为基本上是讲座,组织起来倒是省事儿很多。不过我的电脑在连接投影仪的时候却因为分辨率没有设置对头,导致有人讲的东西在投影仪上一直有一道黑边 :cry:

我的代理被挤爆鸟…

在之前的一篇文章中我公布了自己的GAppProxy服务器地址,现在它终于达到了Google App Engine免费空间的带宽上限,被挤爆鸟 8O 我另外新开了一个服务器,地址是:http://confusedfly2.appspot.com 看看它多长时间能爆掉

另外就是,GAppProxy最近有了更新,修复了在处理cookies时候的bug。以前经常遇到的使用代理的时候不能登录twitter等问题现在已经不存在了。而且从GAE的路线图中可以看到,未来将会添加对大文件处理的支持。而且貌似最新版的GAppProxy通过使用多段下载的方式来突破GAE免费版一次访问只能下载1M文件的限制。

GAppProxy的管理功能

之前因为工作的原因掉到了没有网的地方去了好长一段时间,现在终于回到文明社会了。。。

今天无聊翻GAppProxy的代码,才发现它的服务器一段的代码非常的简单,只有3个源文件,也就是fetch.py, admin.py和accesslog.py。其中代理功能就是使用fetch.py来实现的,而admin和accesslog则是实现了简单的日志功能。于是乎尝试访问admin.py,但是服务器只是简单的丢出来一句“Forbiden!”了事。看了看代码才发现,可能是作者考虑到性能的因素把日志功能部分的代码给注释掉了,而且官方网站上面也没有任何关于这个管理功能的文档。

要打开这个功能很简单,只需要做以下几个修改:

  1. 在fetch.py的185行 logAccess(netloc, self.request.remote_addr) 取消注释
  2. 在fetch.py的32行 from accesslog import logAccess 取消注释
  3. admin.py的第90行 if user.email() == ‘xxxxx’: 把xxxx改成你管理GAE用的google账号地址

好了,现在只需要更新服务期短的代码就可以使用简单的日志功能了。GAppProxy带的有两个简单的功能:记录使用代理机器的IP和请求访问的网址。只需要在登录google账号以后访问以下网址:


http://xxxx.appspot.com/admin.py?obj=accesslog&cmd=list_pop_desti

http://xxxx.appspot.com/admin.py?obj=accesslog&cmd=list_freq_fro

http://xxxx.appspot.com/admin.py?obj=accesslog&cmd=clear

就可以查看最热门访问站点、查看最常用的用户和清除记录。

但是现在GAppProxy的记录功能还很简单,这也许也是为什么作者把它注释掉的原因。但是使用这个东西还是能看到一些有意思的东西的,比如说我看了看我之前公布出来的FetchServer的记录,发现其实还是有一些人一直在用它,而且还发现了一些被墙掉的有意思的网站 :D 貌似现在就属GAppProxy和Tor是最稳定的翻墙手段了,估计只要GAE一天不倒这个GAppProxy就可以一直用下去。