qyb的博客

电影里的三句半

CCTV 我最喜欢的栏目就是《第十放映室》,周末看它介绍"香港喜剧电影",里面放了一段《92黑玫瑰对黑玫瑰》,当时笑笑就过去了,但今早醒来的时候居然第一时间心里头就响起了里面的一段音乐。

我很郁闷,为什么这段音乐能绕梁三日,睡觉还能念念不忘呢?于是想了半天,听出来这是恰恰恰的节奏,再想了半天,靠,原来这里梁家辉两人表演的是一段三句半——这两天琢磨搜狐年会三句半的台词有走火入魔之势,连看的一段八竿子都打不着的电视节目也能入梦。

从第8分钟开始看

嵌入视频看不了的去:http://www.tudou.com/programs/view/Xke1As34cLQ/

kaopubility

从别人那里看到一个"水木靠谱男女鉴定委员会"给靠谱男女下的定义(针对网络交友):

  • 知道自己是什么,拥有什么
  • 知道自己想要什么
  • 知道需要付出什么才能得到自己想要的东西
  • 知道自己能不能付出那样的代价
  • 有信用守时,对家庭对社会保持自己的一份义务与职责
  • 这个定义很赞啊,实际上招聘员工也不过就这个标准了,把家庭二字换成企业就可以

    sohu 邮件支持 Gears 做附件断点上传了

    附件断点上次这个需求很早就提出了,但我一直不觉得我们邮件中心来做一个浏览器插件有什么可持续性,因此没有多想。直到 gears 0.4 发布前夕,看到了它的 feature list,包括了 blob upload 的功能,这才决定利用这个特性来实现断点上载。

    除了技术外,还有一个商业上的考虑就是在 sohu 的产品里,去引用一个来自 google 的服务是否好呢?我的意见是完全没有问题,我并不觉得这样会伤害我们自己的品牌或者商誉,反而是有助于传播我们开放的形象。当然,慎重起见,我也和KCN交换了这个观点,他并不反对我这么做。

    从产品的角度,我们并没有在免费邮箱里面去提示用户安装Gears——毕竟现在只支持10M附件,在这个容量级别,需要断点上载的必要性并不大,因此也没有必要在这里干扰用户——只不过是如果你浏览器有Gears支持的话,我们自动利用Gears的特性上载。在有更大附件服务的 VIP 邮箱,以及未来的网络U盘产品,是会鼓励用户安装Gears的。

    我想未来我们可能会更多的利用来自 google,或者其它厂商的网络API,来完善我们的邮件系统。当然,我们也会逐步开放自己的 API,以及一部分代码滴。

    Topic: 商业 技术

    Browser War 之搜狗浏览器

    很久很久以前,我就听说 sogou 有一个秘密的桌面产品项目,具体是什么不得而知,我自己简单推理了一下:

  • sogou 肯定做的是中国网民最常用的软件,以期获得最大用户覆盖
  • 这类软件按覆盖程度排列:浏览器、下载工具、Media Player、杀毒/安全工具、词典。
  • 浏览器肯定不是,竞争品牌太多,整个市场份额也不大——大部分用户还是用原装 IE
  • 那下面应该是下载工具了...
  • 结果前天传来的消息把我震惊鸟,搜狗居然真的是在做浏览器

    然后赶快去找搜狗的同事,要了个内部版试用。第一印象是 IE 内核,界面类似 Maxthon。用了一圈下来,没有感觉和以前用 Maxthon 有太大区别。当然,那个消息里提到的教育网免费访问国外是一个 killer app;另外,这个浏览器是我见过首个在右上角搜索框整合搜狗搜索的浏览器,从这个角度看,该浏览器对搜狗搜索引擎意义巨大。

    昨天中午吃饭的时候碰到小川,打听了一下他的真实想法,现在关于这个决策我大概能理解个7,8分了:

  • 浏览器是最重要的网络入口
  • 现有的产品远远不能满足用户访问网络资源的需求——离InternetOS的角度还差的很远
  • 微软在网络产品方面太弱,以至于可以忽略原装IE的市场统治力——所以市场是很大的
  • 最后一个原因,搜狗搜索的整合
  • 小川自认有七成胜算,我本来是有些怀疑的,但现在再想,他已经是破釜沉舟,从这个心态和气势上看,很可以加几分期望值。

    Topic: 商业

    iconv(3)

    iconv 可能是我遇过的最让人困惑的C标准库函数了——因为它竟然一次性的返回 5 个值,如果算上全局变量 errno 的话,那就是 6 个(如果你知道还有哪个 libc 函数能超过它的,请告诉我)。而作为调用者,必须对返回的 6 个值逐一检查,然后,OMG,可能还需要再调用 iconv 继续转码...如此反复。

    所以每当我需要在 C 里面 iconv 一个字符串的话,我会去找 php 4.x 的源代码(现在最新应该是 4.4.9),从 ext/iconv/iconv.c 里面 Copy&Paste 一段代码,再自己简单包装一下使用。

    在上周我帮一个程序员提供这个函数包装的时候,我不禁开始思考怎么会有一个如此违背 UNIX 设计哲学的函数存在,后来想到两种可能。一个是字符编码转换这件事情,本来就是一个不那么 UNIX 的操作,再牛的天才,也只能如此设计接口;另一个可能是这个函数完全是 UNIX 商业化过程中为了向非 ANSI 字符语种国家推广,而由一个标准化委员会搞出来的怪物。

    如果对 iconv 使用的复杂程度还没有一个感性认识的话,从 PHP 搞来的这段东西会帮助理解这一点:

    1. /*
    2. --------------------------------------------------------------------
    3.                   The PHP License, version 3.01
    4. Copyright (c) 1999 - 2008 The PHP Group. All rights reserved.
    5. --------------------------------------------------------------------
    6.  
    7.      "This product includes PHP software, freely available from
    8.      <<a href="http://www.php.net/software/>".
    9. */
    10. #include">http://www.php.net/software/>".
    11. */
    12. #include</a> <stdlib.h>
    13. #include <string.h>
    14. #include <iconv.h>
    15. #include <errno.h>
    16.  
    17. //from PHP 4.4.9 ext/iconv/iconv.c
    18. //为了便于在 blog 上表现,把返回简化成 3, 2, 1, 0, -1, -2, -3
    19. //返回值非零表示转码失败,其中大于零则说明返回的 out 不需要 free
    20. //这段代码只在 Linux 下测试
    21. int _iconv_string(const char *in_p, size_t in_len, char **out, size_t *out_len, const char *in_charset, const char *out_charset)
    22. {
    23.     iconv_t cd;
    24.     size_t in_left, out_size, out_left;
    25.     char *out_p, *out_buf, *tmp_buf;
    26.     size_t bsz, result = 0;
    27.     int retval = 0;
    28.  
    29.     cd = iconv_open(out_charset, in_charset);
    30.     if (cd == (iconv_t)(-1)) {
    31.         if (errno == EINVAL) {
    32.             return 1; // WRONG_CHARSET
    33.         } else {
    34.             return 2;
    35.         }
    36.     }
    37.  
    38.     in_left= in_len;
    39.     out_left = in_len + 32; /* Avoid realloc() most cases */
    40.     out_size = 0;
    41.     bsz = out_left;
    42.     out_buf = (char *)malloc(bsz+1);
    43.     out_p = out_buf;
    44.  
    45.     while (in_left > 0) {
    46.         result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left);
    47.         out_size = bsz - out_left;
    48.         if (result == (size_t)(-1)) {
    49.             if (errno == E2BIG && in_left > 0) {
    50.                 /* converted string is longer than out buffer */
    51.                 bsz += in_len;
    52.                 tmp_buf = (char*)realloc(out_buf, bsz+1);
    53.                 if (tmp_buf != NULL) {
    54.                     out_p = out_buf = tmp_buf;
    55.                     out_p += out_size;
    56.                     out_left = bsz - out_size;
    57.                     continue;
    58.                 }
    59.             }
    60.         }
    61.         break;
    62.     }
    63.     if (result != (size_t)(-1)) {
    64.         /* flush the shift-out sequences */
    65.         for (;;) {
    66.             result = iconv(cd, NULL, NULL, (char **) &out_p, &out_left);
    67.             out_size = bsz - out_left;
    68.             if (result != (size_t)(-1)) {
    69.                 break;
    70.             }
    71.             if (errno == E2BIG) {
    72.                 bsz += 16;
    73.                 tmp_buf = (char *)realloc(out_buf, bsz);
    74.                 if (tmp_buf == NULL) {
    75.                     break;
    76.                 }
    77.                 out_p = out_buf = tmp_buf;
    78.                 out_p += out_size;
    79.                 out_left = bsz - out_size;
    80.             } else {
    81.                 break;
    82.             }
    83.         }
    84.     }
    85.     iconv_close(cd);
    86.     if (result == (size_t)(-1)) {
    87.         switch (errno) {
    88.             case EINVAL:
    89.                 retval = -1;
    90.                 break;
    91.             case EILSEQ:
    92.                 retval = -2;
    93.                 break;
    94.             case E2BIG:
    95.                 retval = -3;
    96.                 break;
    97.             default:
    98.                 free(out_buf);
    99.                 return 3;
    100.         }
    101.     }
    102.     *out_p = '\0';
    103.     *out = out_buf;
    104.     *out_len = out_size;
    105.     return retval;
    106. }
    107.  
    108. //qyb wrap _iconv_string
    109. //由调用者负责 free 返回值
    110. char *iconv_string(const char *string, const char *in_charset, const char *out_charset)
    111. {
    112.     char *result;
    113.     int retval;
    114.     size_t in_len, out_len;
    115.     in_len = strlen(string);
    116.     retval = _iconv_string(string, in_len, &result, &out_len, in_charset, out_charset);
    117.     if (retval > 0) {
    118.         return NULL;
    119.     }
    120.     return result;
    121. }
    Topic: 技术

    去铁道博物馆和电影博物馆的行车路线

    查看大图

    今天去了一趟铁道博物馆和电影博物馆,自驾主要是去铁道博物馆的路不好找。我去的时候是走北四环,然后霄云桥下上芳园西路,酒仙桥路,酒仙桥北路,然后受纸质地图的错误影响,拐到了彩虹路上——其实只要一直沿酒仙桥北路走过了五环就是了——还好从彩虹路一路往东北方向只有一条道,然后上了南皋路,某路口再误打误撞的向南拐,开到一个丁字口的时候停车四处张望,居然就是正确的路口。

    这两个博物馆靠的挺近的,适合一天的游玩。免费停车,中午可在电影博物馆里的食堂解决午饭。

    铁道博物馆适合小孩玩,和蒸汽机车头合影留念;电影博物馆适合大人,而且理所当然的配置了一个电影院。都值得一去

    注意:必须从上图的左下角那个点标示的路口进铁道博物馆,然后向东北方向的蓝线是行车路线;另外一条蓝线则是今天从霄云桥过去绕的大弯。据我从卫星地图上观察,走五环是不太可能绕到南皋路上的,还是从四环过去,走酒仙桥北路或机场高速辅路才靠谱

    Topic: 生活

    最近看吴晓波和张维迎的文章

    吴晓波是我所知不多的中国商业/企管作家,最近他的新文章首富与二富的劫难,将日照钢铁和4年前的铁本对比,让人嗟叹。

    最近几个月网上一直热议杨佳,陇南。。。直到现在还有人在打口水仗。其实我觉得民营资本和国家权力的博弈更能影响我们社会的走向,应该更多关注。

    还有就是张维迎,那个被网民骂烂了的人,在 FTChinese 上的文章我看中国改革30年。也可以看到很多政治事件和经济改革关联的地方,比如"...1988年春...邓小平同志...下决心搞“价格闯关”...同年8月份中旬,中央政治局开会讨论通过了《关于价格工资改革的初步方案》,并要求军队和警察做好准备...",真是环环相扣。他在文章里对未来三十年的预测也很有意思:"政治体制改革也可以分成两个15年。第一个15年,主要任务是建立相对独立的司法制度,减少政府部门的权力......第二个15年主要是要建立民主选举制度....."

    貌似比他"左"很多的郎咸平可从来不说这么激进的话,呵呵

    Topic: 社会

    setproctitle

    从 javaeye 的 robbin 那儿看到 rails 的这个技巧,觉得还是挺实用的,于是就下令在 web.py 上实现类似的功能。

    经过 douyuan 同学的一番折腾,然后我也做了几个小实验,最后结论如下:

    • FreeBSD 下有 setproctitle(3) 函数来完成这个功能
    • Linux 对应的是系统调用 prctl(2), option 是 PR_SET_NAME, 宏定义是 15。注意 15 调用是从 2.6.9 引入的,虽然在 2.6.9 的内核头文件 linux/prctl.h 里没有 PR_SET_NAME 的宏定义,但仍然可以直接用 15 来成功调用... 换句话说,RHEL4/CentOS4的系统是可以利用这个特性的

    对于 Linux 来说,prctl 并没有修改 argv/cmdline 的值,而是 /proc 文件系统里的内容(comm)。用 top 看是可以看到修改结果的,如果用 ps 命令,必须用参数 c 或者增加 output 格式 comm 才能看到修改结果,比如命令 ps axc (详情请参考 manual)

    这样看在 FreeBSD or Linux 2.6.9+ 上用 ctypes 就可以搞定我想要的功能了,但对于更古老的 Linux 内核甚至别的操作系统怎么处理呢?看起来就只能去修改 argv[0] 的内容了,不过修改 argv[0] 也不是一件那么容易的事情,Linux 下运行例程:

    1. #include <unistd.h>
    2.  
    3. extern char **environ;
    4. int main(int argc, char *argv[])
    5. {
    6.     int i;
    7.     for (i = 0; i < argc; i++) {
    8.         printf("%p, %s\n", argv[i], argv[i]);
    9.     }
    10.     for (i = 0; environ[i]; i++) {
    11.         printf("%p, %s\n", environ[i], environ[i]);
    12.     }
    13. }

    可以看到命令行参数,以及 environ 环境变量,是存储在一整块连续的内存上的(据说 Solaris 也是这样),如果向 argv[0] 里复制内容过长,有可能造成 environ 被破坏,进而对程序运行产生影响。正确的做法是先把 environ 内容复制出来,再修改 environ[] 数组里的指针地址到新的位置,然后就可以对 argv[0] 为所欲为了。nginx 的 os/unix/ngx_setproctitle.c 也是这么工作的。

    换个角度,argv/environ 的这种存储方式使得如果知道所有 argv 的长度之和,从 environ[0] 向前偏移这个数字就是 argv[0] 的地址。这样看写一个 python extension 完成这个功能是可行的——虽然无法在模块里直接获得 argv[0] 地址,但可以取到 environ[0] 的地址,argv 的总长度则可以从 sys.argv 里计算出来然后作为参数传入... 这种方法潜在的问题也不少,比如在一个 python 进程里多次调用该怎么办,可似乎也只能这么来做了。

    UPDATE: 发现 prctl 的一个问题是,它最多能设 15 字节长度的 comm, 这就导致可用性降低,也许最终还是要改 argv

    Topic: 技术

    You're beautiful

    吃晚饭的时候,听到背后电视里传来 "You're beautiful, you're beautiful, you're beautiful, it's true",我很诧异——怎么经济节目突然放起 James Blunt 了,回过头来才发现,原来这是大众新宝来的广告曲..

    我几乎喷饭,这也太扯了吧,怎么用这首歌来做广告?歌词的结尾可是 But it's time to face the truth,I will never be with you

    估计看我 blog 的人知道 James Blunt 的也比较少,分享一下这首歌的 MV

    Topic: 音乐

    立起一个口香糖瓶

    From blog 配图

    绝非PS

    我右手网络冲浪鼠标点来点去的时候,左手就在玩这个瓶子。瓶里大约还剩21-22颗口香糖的时候,成功的将瓶子斜着立起来了

    现在还剩18颗,仍然可以这样立起来。

    Topic: 生活
    订阅 RSS - qyb的博客