六月 23, 2007

Two kinds of judgement

从被别人面试到面试别人,我对招聘这点事有了更清楚的认识。成与不成,貌似应聘者的命运全掌握在面试官一念之间。只是我这点感性认识比不上Paul Graham的理性分析那般透彻,他在Two Kinds of Judgement中说道:

评判本身不是要对单个人做出准确的评估,而是要选择一个接近最优的集合。

又说:

你越是能意识到大多数评判受到一些额外的随机因素很大影响,……,你就越能相信你可以做些事情影响最终结果。

Paul Graham的分析精僻透彻,我试着翻译了一下,名为“评判人的两种目的”。

六月 17, 2007

Three questions from Productivity501

Productivity501提出了三个问题,非常有趣,我在这里尝试回答一下。

问题一:你认为人们无意识地把时间浪费在什么地方?请举出你认为最浪费时间的一种行为?

回答:仅仅抱怨!我们也许无力改变所有事情,但至少可以改变一些事情;我们也许无力改变别人,但至少可以改变自己;我们也许无法让改变立即发生,但一天一点也可以聚沙成塔。当然抱怨也并非一无是处,适当发泄有利于心理健康,切忌滥用。

问题二:到目前为止,什么给你带来的变化最大?

回答:开源软件!如果没有开源软件,我不会喜欢上编程这行;如果不是开源软件,我不会为自己是个程序员而骄傲。开源世界就像一个大家庭,按需索取,力所能及地回馈。“在那一刻,他不是一个人在战斗,他不是一个人!”:-)

问题三:如果有人想只读一篇你的站点上的文章,你希望是哪一篇?为什么?

回答:Secure your job,一篇写于英特尔大裁员期间的感想。梦想!梦想?梦想……希望不仅仅是梦,也并非想想而已。

六月 14, 2007

Extract quoted string with Regexp::Common

为了增强电子书搜索功能,我们引入两个元字符:\"。当我们想搜索一个词组(而不是单词)的时候,可以使用双引号将多个单词引起来,此时,双引号本身不作为搜索内容的一部分。当我们确实想搜索双引号时,需要写成\",反斜杠取消了双引号的元字符功能。当我们想搜索\本身时,就要写连续两个反斜杠。

对用户输入要分两步处理,首先,逐个取出引号引起来的部分,然后对剩下的部分分词。前一部分工作可以用Regexp::Common来完成:

my @quoted_string;

while ($search_string =~ s/$RE{delimited}{-delim=>q{"}}{-keep}//) {

push @quoted_string, escape_special_char($3);

}



sub escape_special_char {

my $string = shift;



$string =~ s/\\([\\\"])/$1/g;

return $string;

}

其中$3是指被引号引起来的部分(不包含两边的引号),而escape_special_char\"替换为",将\\替换为\。完整源程序参见这里,版本号为1,其中还有警告双引号不匹配的功能。程序截图如下:

六月 13, 2007

Ebook feeds

一直没学会怎么用搜索引擎找电子书,幸好订阅了几个feed:

更多其它类的feed参见我的OPML

六月 11, 2007

Search ebooks with File::Find

使用HTML::Pager可以写一个列出电子书的cgi小程序,在此基础上,可以很容易地增加文件名搜索功能。

首先增加搜索框和按钮,只需修改最后的打印语句:

my $title = "Book List ($num_of_books)";



print $cgi->header,

$cgi->start_html($title),

$cgi->h3($title),

$pager->output,

$cgi->h3('Book Search'),

$cgi->start_form,

$cgi->textfield('search'),

$cgi->submit,

$cgi->end_form,

$cgi->end_html;

接下来要构造搜索匹配字符串表,当输出框内为空时,搜索结果与以前一样,否则搜索结果应该包括所有用户提供的单词,为了简单起见,我们认为单词由空格分隔,暂不考虑引号。

my $cgi = CGI->new;



my @search_pattern = (qr/\.(?:chm|pdf)$/i);

if ($cgi->param('search')) {

push @search_pattern,

map { qr/\Q$_\E/i }

split('\s+', $cgi->param('search'));

}



my @books;

sub search_book {

for my $pattern (@search_pattern) {

return unless $_ =~ /$pattern/;

}

push @books, $_;

}



find( { wanted => \&search_book, no_chdir => 1 }, '.');

程序截图如下:

六月 10, 2007

2007 resolution revisited

2007年就快过去一半了,回头看看年初指定的计划,感觉到了调整的时候,免得成为一纸空文。

  1. Perl Module没看几个就停了,倒是开始看parrot的文档。第一次试图了解开源项目的实现,感觉开头很难,无处下手,只得从读文档开始了。Feedman开了个头,就停下来了,如果不增加用户管理功能,后面的事情很难做下去。测试仍然没有开始,OO仍在学习。
  2. 全都推迟了。
  3. 闲书确实没少读,linux上的游戏也装了几个。
  4. 哑铃偶尔举一举,一周两次都不能保证。
  5. Emacs上也没有什么进展,虽然最近重温emacs lisp写了几个函数。

也不知道计划起到多大作用,自己做事向来随心所欲,执行计划的动力也不是很足。

六月 05, 2007

Capture window with import

gnome-screenshot是Linux上的抓图工具,可以很方便的抓取整个屏幕或单个窗口,然而它只能保存为png文件格式。

使用ImageMagick套件里面的import可以方便的选择图像文件格式,比如我上一篇文章里的截图是gif格式,就是使用import抓下来的。选择文件格式的方式就是使用相应的后缀名,如:

$ import image.gif

然后用鼠标点击一下即可。

import有很多参数,详见:

$ import -help

抓整个屏幕的方法参见Donald Knuth的截屏:-)。

六月 01, 2007

List ebooks with HTML::Pager

自从皈依了FOSS,盗版软件是不用了,电子书还是照下不误。曾经想过用apache和scuttle来管理,然而使用起来仍然很麻烦,所以找书的时候还是到各个目录里面去翻。

feedman的时候学会了HTML::Pager,于是写了一个简单的CGI脚本,放到电子书的根目录下。缺省情况下,apache打开一个目录的样子很难看,而且长一点的文件名都被截断了,偏偏电子书的文件名都很长。这个CGI程序的作用就是输出一个文件列表,提供完成的文件名和链接。程序出奇的简单,首先用File::Find找出想要列出的文件,如所有的chm和pdf文件。

#!/usr/bin/perl -T

use File::Find;
use HTML::Pager;
use CGI;
use URI::Escape;
use File::Basename;

my @books;
find({ wanted => sub{ push @books $_ if /\.(?:chm|pdf)$/ },
       no_chdir => 1 },
     '.');

my $num_of_books = scalar @books;

这样,所有的文件名就保存在数组@books里面,文件总数保存在变量$num_of_books里面。接下来我们要写一个函数,从@books中抽取出部分文件,供HTML::Pager输出到页面上。

sub list_book_callback {
  my ($offset, $rows) = @_;
  my $current_books;

  for my $b ($offset .. $offset + $rows - 1) {
    last if $b == $num_of_books;
    my $filename = $books[$b];
    $filename =~ s{^\./}{};
    my $url = 'http://localhost/book/'
              . uri_escape($filename);
    my $title = basename($filename);
    if ($title =~ /^(?:ch(?:apter)?)?\d+\.(?:chm|pdf)$/i) {
         $title = $filename;
    }
    push @current_books, [ qq(<a href="$url">$title</a>) ];
  }
  return \@current_books;
} 

这段函数对文件名做了一些特殊的处理,一般来讲,文件名即书名,我们可以去掉路径部分。而有些特殊的文件名字可能为ch01.pdf或ch02.pdf等等,上一层目录名才是书名,这时就将路径和文件名一起输出。最后就是用HTML::Pager生成列表并用CGI输出。

my $cgi = CGI->new;

my $pager = HTML::Pager->new
    (query => $cgi,
     get_data_callback => \&list_book_callback,
     rows => $num_of_books,
     page_size => 25,
    );

print $cgi->header,
   $cgi->start_html,
   $pager->output,
   $cgi->end_html;

程序运行结果如截图: