Blog

  • 【一日一得】spring brother is true man

    今天我终于知道了为什么最近好多人都在提到春哥是纯爷们–或者更严肃的说法是spring brother is true man。

    一切都源于这个所谓Talk to strangers网站:http://omegle.com

    这实在是将IM的领域扩展到了一个新的领域。不过,话说回来,以前的IM工具,比如Skype,也不是没有这样的功能,只是从来没有人将这个功能独立出来并成为一个单独的功能并运行。

    自然,我可以想到的是,如果两个stranger真的可以聊的投机,大可以交换一下MSN或者ICQ或者其它什么IM的方式而进行no more stranger的交流。这种SNS的方式之所以能吸引最多高达15万浏览的原因就在于虽然在理论上只要通过6度跳跃就可以联系上地球上的任何一个人,但是人们还是愿意通过更直接、更没有风险、更隐蔽的方式来probe。

    据说Omegle站点已经错误的将spring brother is true man列为类似MSN的病毒,其原因是所有中国的用户在开谈后都会说一句spring brother is true man。如果对方也是中国人,自然能心照不宣。不得不说,在有限的范围内,大家的创造力还是异常强悍的。

    当然,中文克隆版的Omegle也已经上线,http://luguode.com/。不过这篇文章说的好:

    虽然功能上略显单薄,但是山寨总会挂上中国特色,希望不要像Omegle沦落为拉皮条的平台,上来就问sex,没两句就希望deepin,人人都going down,谈谈理想,说说事业,拉拉家常,我们需要的是河蟹。

    嗯,我们需要河蟹。只是当我想到这样的可能性的时候,我就会stop,不会去做。

  • Going for Symfony | 第七天

    在第七天,我终于完成了将任氏有无轩的最重要的部分:藏书管理部分迁移到了Symfony,并且是在应用环境。进行了一些小的修改就不说了。

    本来是要用Lucene进行索引编制的,但是我的应用实践表明,Lucene实在对中文支持很不好。所以,我只好放弃Lucene,而改用最原始select大法。

    发布完毕后,基本没有大的问题。一个小问题是,原来www.rsywx.net/wiki就无法访问了,需要用www.rsywx.net/wiki/doku.php 1 来访问,这个应该是路径映射的问题,不过既然改好了我也就不管那么多了。

    从1月12日开始,到4月14日基本完成,历时3个月断断续续的开发。这样的开发进度,在真正的软件公司是不可以接受的。但是,这就是我之前一直说的:为自己开发软件的好处和悠闲。不用担心进度,随时可以让步……

    接下来的工作相对比较简单了,准备再慢慢搞。

    迁移的另一个重要意义在于,我的Vista机器终于可以关机了,本来由于一直要提供InterBase的数据库服务而不能关机,现在全部迁移到MySQL后就可以了……

    仅作此文留念。


    1. 维客地址现在是:rsywx.com 

  • 蜂蜜水和唱歌

    家里有一瓶蜂蜜,最近和老彼得迷上了喝蜂蜜水–老彼得说成蜜蜂水。

    取一匙蜂蜜,用温开水泡开,再勾兑一些凉水调温,成为满满一杯。

    蜂蜜水略带一些淡黄色,喝在嘴里甜甜的、暖暖的。我和老彼得一人一杯,坐在饭桌边,边喝边聊天。

    头顶的鸟巢灯散发出来的光线也是黄黄的,暖暖的。这正如我和老彼得在一起的亲密和随意。

    ========

    老彼得告诉我,今天他们学校进行了唱歌比赛。唱的曲目正是前两天他练得很起劲的《闪闪的红星》。那两天他练习的时候,他还要我下载MP3,然后还要我们在他练唱的时候在周围起哄,唱别的歌干扰他,从而巩固唱歌。想不到今天就正式唱了。

    他还告诉我,今天唱的时候,一开始伴奏弹错了。而他们居然也就一路唱下去,按照老彼得的说法,沈老师当时就觉得完了,这次肯定不能得奖了。谁知老师后来也发现弹错了伴奏,于是从头唱过……

    真是很好玩的一件事情。

  • 2F的不靠谱性

    买2F已经很久了,在硬件方面我没有什么抱怨的,可以连续运行个10天8天的。但是说到软件支持,实在令我头晕……

    之前的半年,还有Wingsun同学当免费技术支持,但是自从Wingsun不在花蕾后,我的dist-upgrade就从来没有新的东西下来过。最近要在2F上装postfix,问题来了,好多库都没有。

    一个硬件平台的诞生,硬件的设计当然是很基础的。但是,之后的软件支持十分重要,特别是一些基础的软件。在这方面,国内的厂商显然很不靠谱。

  • A Good Friday

    今天是4月10日,是基督教国家很重要的一个节日Good Friday,中文翻译为耶稣受难日。

    我第一次知道这个节日是10多年前。我在CSSD的时候,正好在这段时间和刘东东一起出差到新加坡。然后在周五晚上窝在住的饭店里一起看完了这本片子《宾·虚》(Ben Hur)。片子很长,应该有3个小时。但是看了很让人震撼。

    影片可以看成–也应该理所当然的看成–是Ben Hur个人的传记,一个英雄兴衰复仇的故事。在这个层面上,我觉得和大仲马的《基督山伯爵》很接近。

    不过,这本片子不能简单地就这么去看。它更大的意义上是一本宗教片。如同《蝴蝶梦》中真正的主角是从未出现过的Rebecca,《等待戈多》中真正令人刻骨铭心的是从未出现的戈多,《宾虚》中真正的主角是那出场不多的耶稣。

    当耶稣被钉在十字架上,鲜血流淌在耶路撒冷街头,宾虚的母亲和妹妹的麻风病在鲜血的浸润下豁然痊愈,这一时刻将耶稣慨然赴难的意义表现的淋漓尽致了……

    而宾虚在这样的力量的冲击下,才深刻的领会到,自己的复仇力量和耶稣的力量相比,是多么的渺小;而就是这么一个拥有神力的人,对所有的人都给予了宽恕,而不是以眼还眼以牙还牙的复仇。这才是耶稣之爱的真意所在。

    一饮一啄,莫非前定。当年宾虚还被罗马士兵驱赶在沙漠中时,他不顾军官的皮鞭用水瓢舀水给一位小孩喝,多年以后,他怎么能想到这个小孩已经成年,并用他的血为他的母亲和妹妹治愈了病症,为他洗涤了所有的罪孽?影片的这个细节的处理和呼应实在是经典中的经典。

    从某种意义上说,《宾虚》比《十诫》更好看,也更震撼。《十诫》是讲先知为了完成上帝赋予的使命而奋斗,《宾虚》是讲耶稣受难而拯救世人。

    《宾虚》影片的最后,远景是耶稣受难的加略山,近景是牧羊人赶着羊群匆匆走过。这一切的一切都是那么的令人震撼。 所以,在Good Friday,只要有机会,我一定会向大家推荐去看《宾虚》。

    ===================

    Ben

    (VCD截屏,不是很清楚。)

  • 体检完成

    前两天公司的HR通知我说,我2008年度的体检还没有做,4月15日之前是最后期限。正好昨天在上海开完一个脑力大震荡的会,所以就决定今天去做体检。

    我做体检的地方是在园区职业技术学校(IVT),一进门就发现那叫一个people mountain people sea……

    体检有好几种:入职体检,公司年检,还有什么健康证之类的。我想进行公司年检,但是显然我们的HR比较宽松,并不限制我们非要去哪里体检,所以在IVT也就可耻地没有我们公司的登记信息,于是我就以个人体检的名义交了300元进行体检(反正公司给我的额度就是如此)。

    一切都比较顺利。做B超前我很木有经验的先去做了尿检,结果被医生要求先去喝十杯水。然后医生很神秘的拿出一摞一次性杯子,要我拿一个,并同时告诉我:这个一次性杯子很少的……

    外科检查排起了长队。最后我只好厚了脸皮插队,而且插了好多未成年小loli的队。显然她们还没有进入职场就对怪蜀黍有了印象……

    虽然结果还没有出来,不过应该还是一切都OK的。只是B超显示肝部有囊肿,而且医生说是遗传性的,而且基本是来自母亲的遗传。可是我回忆不出母亲曾有肝囊肿的经历。不过这样也好,如果是母系遗传,那么至少老彼得也被遗传的可能性会比较小。

    医生的告诫是要戒酒,好吧。古有奉旨填词,今有奉医嘱戒酒。

  • 老猫近照一张

    老猫终于爬上了阳台的栏杆,从而可以在一个更高的角度审视地面:

    Technorati : Del.icio.us : Zooomr : Flickr :

  • Going for Symfony | 第六天

    这是我对任氏有无轩改造的(第N个)第六天……

    我要完成的是至关重要的功能:加入全文搜索。今天的收获还算可以,还需要我进行更多实际数据的测试进行验证。

    程序开发的一个重要原则是:DRY(Don\’t Repeat Yourself),或者说不要去发明轮子。大意是说,要尽量多的复用现有的东西。比如在搜索功能上,我们完全可以使用现成的Lucene模块。在Symfony中,更是将DRY原则进一步发挥,我们不会从最基本的Lucene库开始开发,而是直接使用Zend Framework中包含的Lucene模块。

    首先要安装并配置ZF。从Zend的网站下载Zend Framework,然后解压到lib/vendor/Zend目录下。由于我们不会用到那么多Zend的模块,所以可以删除一些目录,在lib/vendor/Zend目录下只保留这样一些内容:

    • Exception.php
    • Loader/
    • Loader.php
    • Search/

    在ProjectConfiguration.class.php中注册Zend的自动加载器:

    // config/ProjectConfiguration.class.php
    class ProjectConfiguration extends sfProjectConfiguration
    {
        static protected $zendLoaded = false;
        static public function registerZend()
        {
            if (self::$zendLoaded)
            {
                return;
            }
            set_include_path(sfConfig::get('sf_lib_dir').'/vendor'.PATH_SEPARATOR.get_include_path());
            require_once sfConfig::get('sf_lib_dir').'/vendor/Zend/Loader.php';
            Zend_Loader::registerAutoload();
            self::$zendLoaded = true;
        }
    // ...
    }

    好了,Zend已经注册,我们已经可以进入编程了。 我们需要在BookBookPeer类中创建一个函数,用来打开或者创建索引文件:

    // lib/model/BookBookPeer.php
    static public function getLuceneIndex()
    {
        ProjectConfiguration::registerZend();
        if (file_exists($index = self::getLuceneIndexFile()))
        {
            return Zend_Search_Lucene::open($index);
        }
        else
        {
            return Zend_Search_Lucene::create($index);
        }
    }
    static public function getLuceneIndexFile()
    {
        return sfConfig::get('sf_data_dir').'/job.'.sfConfig::get('sf_environment').'.index';
    }

    索引的保存应该和记录的保存同时进行,所以我们需要改写BookBook类的save函数:

    public function save(PropelPDO $con=null)
    {
        if(is_null($con))
            $con=Propel::getConnection(BookBookPeer::DATABASE_NAME, Propel::CONNECTION_WRITE);
        $con->beginTransaction();
        try
        {
            $ret=parent::save($con);
            $this->updateLuceneIndex();
            $con->commit();
            return $ret;
        }
        catch (Exception $e)
        {
            $con->rollBack();
            throw $e;
        }
    }

    这里用到了事务,因为我们希望保存记录本身和保存索引这两个动作要么都成功,要么都不成功。否则会出现索引和记录不匹配的问题。updateLuceneIndex()的方法是这样的:

    public function updateLuceneIndex()
    {
        $index=BookBookPeer::getLuceneIndex();
        //remove an existing entry
        if($hit=$index->find('pk:'.$this->getId()))
            $index->delete($hit->id);
        $doc=new Zend_Search_Lucene_Document();
        //Store book pk URI to identify it in the search results
        $doc->addField(Zend_Search_Lucene_Field::UnIndexed('pk', $this->getId()));
        //Index book fields
        $doc->addField(Zend_Search_Lucene_Field::UnStored('title', $this->getTitle(), 'utf-8'));
        $doc->addField(Zend_Search_Lucene_Field::UnStored('author', $this->getAuthor(), 'utf-8'));
        $doc->addField(Zend_Search_Lucene_Field::UnStored('id', $this->getId(), 'utf-8'));
        //I will leave tags search later
        //add job to the index
        $index->addDocument($doc);
        $index->commit();
    }

    我只对三个字段进行了索引:titleauthorid。如果将来要增加索引字段(例如tag),只要相应增加$doc->addField即可。

    完成这个任务之后,我们基本已经大功告成,下面要做的就是编写对应的动作,并构造正确的搜索条件。由于搜索和列表实际上是功能相同的工作(后者可以看做没有搜索关键字的搜索),所以我将这两个功能的路径设置为一样的。另外,在Symfony的官方教程中,搜索并没有加入分页的功能,我也会一并加入。因此我改写了executeSearch函数:

    public function executeSearch(sfWebRequest $request)
    {
        $key=$request->getParameter('key', 'null');
        $c=new Criteria();
        if($key!='null')
        {
            $c=BookBookPeer::getLuceneCriteria($key);
        }
        $this->pager=new sfPropelPager('BookBook', sfConfig::get('app_records_on_book_search'));
        $this->pager->setCriteria($c);
        $this->pager->setPage($request->getParameter('p',1));
        $this->pager->init();
        $this->key=$key;
    }

    我首先判断是否有key(搜索关键词),如果有的话,需要重新定义$c这个搜索条件(由getLuceneCriteria完成)。然后创建一个pager,并传递$c搜索条件。 getLuceneCriteria()函数的定义如下:

    static public function getLuceneCriteria($key)
    {
        $hits=self::getLuceneIndex()->find($key);
        $pks=array();
        foreach($hits as $hit)
            $pks[]=$hit->pk;
        $c=new Criteria() ;
        $c->add(self::ID, $pks, Criteria::IN);
        return $c;
    }

    从代码中可以看到,这实际上是一个IN的条件搜索。

    做完这些,我们还要稍微改写一下搜索(列表)页面的导航条显示,我们必须加入key参数,否则在导航后,就会失去搜索条件:

    <a echo="" href="<?php" url_for="">?p=<?php echo $pager-?>getPreviousPage() ?>&key=<?php echo $key ??>>
    <img alt="Previous" page="" src="/images/previous.png"></img>
    </a>

    其它链接的改写也类似,就不举例了。

  • BT群3月份签名档

    2009-03-03 15:14:32 谁的终身大事成得最快就应该获得终身成就奖 评奖那么多,BT群当然也可以评。只是,该qmd本身就创下了一个记录:2分钟后就被新的qmd取代,从而成为BT群有屎以来生存时间最短的qmd(没有之一)。

    2009-03-03 15:16:03 BT群即将召开两会总结回顾表彰大会 不知道,两会结束了麽?

    2009-03-05 BT群成功吸纳两名新成员。特此祝贺! 这两名新成员是:学打架之yukifighting,待被发育之菜。从此,BT群进入了被新人围观的新时期。

    2009-03-09 肥要日日减,胸需天天增 好像这个是某些人的生活目标?

    2009-03-13 狮屎证明,MK真的是最强! 没什么,我们只是re-assure一下而已。

    2009-03-17 BT群七宗最:MK最强,令狐最囧,猛禽最EX,QQ最2,猪手最被BS,女王最怨念,蕊抽最被抽…… 这个总结是最完整、最深刻、最公正、最无党争的……

    2009-03-24 BT群抽风中,大家各自打酱油去吧…… 山雨欲来啊……其直接后果就是,btfans.cn上线了……

    2009-03-26 一小粒很遗憾 或者用我表扬simp的一句话:You are a good guy. Of course, you are more than that. You are a hurted good guy. 其康泰克请搜索hr 面试 歧视 没事。当然,这个qmd是前令狐假传圣旨擅自改的,所以很快被取代了。

    2009-03-26 今天你缺陷了没有 本qmd的康泰克同上……

  • 2009-10年度我想完成的几件事

    4月1日是我们公司新的财务年度开始的第一天,而0910财务年度的最后一天是2010年3月31日。我也想给自己定一些目标:

    • 完成任氏有无轩的改版;
    • 完成狗屎皮的开发;
    • 完成一本书的翻译