悲剧的 MSN Space

MSN Space 总算倒了,所有用户都要求被迁往 wordpress.com,或者下载备份文件。话说我第一个用得顺手的 blog 还是 MSN Space,也用了很长的时间,不免觉得有些悲凉。

今天有同事问我,MSN Space 为什么混到这个地步?我说,本来 MSN Space 还凑合可用,但是每一次改版、每一次改名,都让你觉得更加难用。产品能做到这个份上,也真是不容易,不过无独有偶,MSN 也算得上跟它的绝配了!不知道什么时候能看到 MSN 整体搬迁用户到 AIM 或者改版到 XMPP?

哦,我又忘了,国内还有个飞信呢!不愧是外包给 MSN 做的产品,看看现在的飞信 4.x,我好怀念飞信 3.x 啊!

这件事情让我感兴趣的一点是,我总算看到一个可能,可以将以前在 MSN Space 上的评论,合并到现在的博客中了。或许需要自己写个小工具,假期可以尝试做一下。

逝去的周末

我觉得我越来越向居家男人的特质靠近了。

虽然咱公司实行的是弹性工作制,不强制要求上班时间,但是我早上要送女友到地铁站,不好再回去补觉啥的,只好也直接去上班。这样一来,在工作日我便几乎没有了什么私人的时间,所有的个人事务都得留到周末处理。

今天早上一起来,清理完垃圾篓,便跑去工行交水费,然后回来用清洁剂彻底清洁了下卫生间的马桶,把一个旧的简易衣柜组装起来,把秋天的衣服从箱子里翻出来挂上,又去了几个超市(附近的超市是清真超市,就不明说原因了 ^_^)买吃的用的。一晃眼,一天就这样过去了。

其实一些事情上周末/上上周末就应该做,只是没来得及。上上个周末逛街和看电影来着,上个周末部门又组织了去坝上草原玩。说起去坝上,这次找的旅行团挺差的:首先第一天带我们去一个山寨游乐场玩,贵还不说,还不好玩,太~~~山寨了!然后第二天带我们去骑马,收费五十块一个小时,据说自驾游过去找的才二十块。加上路上颠簸的十二三个小时,实在让人身心俱疲,也没有太多玩的兴致。回来我一直想,集体出去玩到底以什么形式才好呢?总不能真的只是“换个地方打牌”吧。其实我更想弄明白的是,如果自己出去玩呢,仅仅带着“到此一游”见识一下的心态去玩,有没有意义?

相比于以前,现在我住到了“城里”,身处二环和三环中间,也切实体会到了另一种交通的不便。从我家到地铁站这一段路,是无差别的堵车,几乎每天的任何时候,都可能堵起来。特别是恶劣天气时,例如昨天,下雨我不想骑车,结果两公里的路公交车走了五十分钟。平时你比自行车慢我也就忍了,这次居然比走的还慢!今天下午还看到一急救车在路上堵的哇哇叫,这可是周末啊!所以我决定了,以后高峰期不乘坐机动车辆了,宁愿用两条腿走的。

正是由于各种没时间,我和同学朋友的联系目前也降低了很多,博客和微博更新频率都大为下降了。不过还是有几个和我离的比较近的,例如加入旁边一家公司的小明同学前段刚结束了封闭培训,开始到西二旗上班。小伙子一见面就向我炫耀第一天上班发现公司里美女之多,让我好生羡慕。同样是IT企业,差距怎么就那么大涅?

PS:最近鄙厂搞了个“实名社交平台”——说吧(非官方简称 SB ),我这还有不少邀请,想要尝试的朋友可以留言索取,送完为止。

我要一所大房子,有很大的落地窗户

我真的不曾想到工作了那么久我还会有那么的不安稳感。我是一个心里存不住事的人,一件烦心事于我就相当于一个已知现象却不知缘由的 bug 一样,不解决掉它我感觉整个系统都不稳定。

前面曾说过办手续的各种烦,没想到才见看稳定下来,又得到一条消息:女友可以提前调回北京总部了。而我们工作地位一个在丰台总部基地,一个在海淀西二旗,这就意味着必须得换房子了——令人愉悦的烦恼!

先说说我现在住的房子吧:西二旗智学苑,三室一厅次卧,无隔断间,距公司一千米,日常设施齐全,北大家属楼,北大校园网,房东直租,便宜——950/月,再加上免取暖物业费,网费和取暖费一年下来省不少;缺点是:小——实测只有九平米 + 一平米飘窗(虽然号称12平米),脏——关注我 Twitter 或者 Buzz 的同学应该知道卫生间我是如何打扫干净的。

毕竟住了三个月了,已经熟悉,而且离公司不是一般的近,骑自行车就更方便了。在校园网里,还可以上 IPV6 下电影,真有些舍不得,但是没办法。

我是一个土人,很羡慕那些电视里精心装修的干干净净的家居环境,比如《家有儿女》那种。本来换房子也想租个那样的,无奈房子太难找,好点儿的房子迟一点儿就会被人抢走。即使是找中介,也没有很多信息。而且都比较贵,因此都不敢想租个一居二居啥的,觉得负担不起。

在水木租房版、豆瓣租房小组、赶集网之类的地方关注了很久,也找了我爱我家中介,都没找到合适的。本来目标是长椿街和宣武门地铁站附近的合租主卧,昨天鬼使神差地在豆瓣租房小组多翻了一会儿,居然翻出来个牛街的一居,还挺便宜。赶忙提前下班去看了一下,怕被别人抢走,当场就定下来了,今天晚上刚和房东签了合同回来。

房子不能完全如我所期望,没有什么高档家具,全部都是简易的,也不是木地板,距离地铁也不是特别近。但让我满意的是:比较新——06年的房子、落地窗带阳台、卫生间和厨房都很干净、小区也比较安全。总共使用面积有四十多平吧,进去和我九平米的房间果然感觉不一样!

其实,最开心的是,总算能住上自己独门独户的房子了!再也不用和别人合用厨房、冰箱、卫生间、洗衣机——这可是我从上学时就梦寐以求的事情!

这个周末,就要用来搬家了。

广告:我的朋友们,谁想换个离西二旗地铁近的合租单间,可以和我联系了。要求高的满足不了,但是有两点必须得赞:房子很实惠,房东很实在。

Fastbit中的bitmap索引算法

摘要:bitmap 索引是一种典型的数据库索引方案,本文基于 Fastbit 软件包,使用实际用例对一些常用的 bitmap 索引算法进行了一个较为系统的介绍。

一、Fastbit是什么?

引用 Fastbit 的官方网站上的介绍:Fastbit是一个追随 NoSQL(Not Only SQL) 运动精神的开源的数据处理程序库,它提供了一系列的用压缩的 bitmap 索引支持的查询函数。在这里,我们关注的关键词是“bitmap 索引”。Fastbit 使用的是按列存储方式,其 bitmap 索引也是在按列存储的数据上建立起来的。

二、Fastbit 中的 bitmap 索引算法

Fastbit 的源代码有着非常清晰的结构。在 Fastbit 的源代码中,每个索引算法都用一个 C++ 类来实现,所有的索引算法类都是基类 index 的派生,并且在 fastbit 源代码中保存为以 i 开头的源文件。

下面是 Fastbit 中的索引类的派生关系图,从美观考虑,直接使用 xmind 思维导图而不是 UML 来展现了:

fastbit 索引算法派生关系图

下面我们将对其中部分算法进行简单的介绍。我们将这些索引算法分为几大类:基础算法、扩展算法、多层算法和多成分算法。

三、基础 bitmap 索引算法

基础的 bitmap 索引算法是最简单的 bitmap 索引算法,给出了 bitmap 索引的基本原理。

3.1 relic

relic (定义在 irelic.h 中,实现在 irelic.cpp ) 是最原始的 equality-encoded 算法,这个单词代表“遗迹”的意思。它可谓是最简单直观的 bitmap 索引算法。relic 为需要索引的每个值都建立一个 bitvector,在该 bitvector 中,只有等于该值的列才会被置 1,其它位都被置 0,如下表所示:

数据 索引(bitmap)
a b d e g
a 1 0 0 0 0
g 0 0 0 0 1
d 0 0 1 0 0
e 0 0 0 1 0
b 0 1 0 0 0
d 0 0 1 0 0
g 0 0 0 0 1
e 0 0 0 1 0
3.2 bin

bin (定义于 ibin.h,实现在 ibin.cpp)是 binned equality-encoded 算法,这里它代表“桶”的意思。它可以视为是 relic 的一种变形,它将值域分为几个不相交的区间,将原本是相等才置一的规则转变为值落在该区间内就置一,如下表所示。当然,relic 也可以视为 bin 的一个特例(将区间定义为 [a, a+ε)。bin 每个区间的范围由程序遵从某些规则设定,这些规则由命令行通过参数传入。

数据 索引(bitmap)
(…,b) [b,e) [e,…)
a 1 0 0
g 0 0 1
d 0 1 0
e 0 0 1
b 0 1 0
d 0 1 0
g 0 0 1
e 0 0 1
3.3 bin->range

range (定义于 ibin.h,实现于 irange.cpp)是 range-encoded 算法,这里它代表“范围”的意思。正如它字面所表达的意思,range 的每个 bitvector 标记着小于某边界值的值,如下表所示。因此,它可以视为是 bin 的一个累积表示,这也是 fastbit 软件包中所做的:首先构造 bin,然后累加转换成 range。值得注意的是,一般最后一列代表着小于无穷大,因此该 bitvector 全为 1,会被略去不写。

数据 索引(bitmap)
(…,b) (…,e) (…,g)
a 1 1 1
g 0 0 0
d 0 1 1
e 0 0 1
b 0 1 1
d 0 1 1
g 0 0 0
e 0 0 1
3.4 bin->mesa

mesa (定义于 ibin.h,实现于 imesa.cpp)是 interval-encoded 算法[1],它与 bin 类似,只不过它的区间之间有重叠部分。与 range 相同,在 fastbit 软件包中,它也是通过 bin 构造起来的。

数据 索引(bitmap)
(…,d) [a,e) [b,g) [d,…)
a 1 1 0 0
g 0 0 0 1
d 0 1 1 1
e 0 0 1 1
b 1 1 1 0
d 0 1 1 1
g 0 0 0 1
e 0 0 1 1

四、扩展 bitmap 索引算法

4.1 direkte

direkte (定义于 idirekte.h,实现于 idirekte.cpp)是丹麦语中的 direct,它与 relic 几乎是一样的,不同点只是它为小于最大值的所有值都建立了一个 bitvector(即使该值并不存在于列中)。

数据 索引(bitmap)
a b c d e f g
a 1 0 0 0 0 0 0
g 0 0 0 0 0 0 1
d 0 0 0 1 0 0 0
e 0 0 0 0 1 0 0
b 0 1 0 0 0 0 0
d 0 0 0 1 0 0 0
g 0 0 0 0 0 0 1
e 0 0 0 0 1 0 0
4.2 relic->slice

slice(定义于 irelic.h,实现于 islice.cpp)实现了 O'Neil'97 [2] 提出的 bit-slice 算法。它的基本思想就是首先将原始数据用二进制进行编码,bitmap 就是所有值的二进制编码表示的集合,bitvector 的个数由最大值的二进制表示决定,如下表所示:

数据 编码 索引(bitmap)
a 0 0 0 0
g 4 1 0 0
d 2 0 1 0
e 3 0 1 1
b 1 0 0 1
d 2 0 1 0
g 4 1 0 0
e 3 0 1 1
4.3 bin->bak

bak (定义于 ibin.h,实现于 idbak.cpp)是丹麦语中的 bin,因此它是 bin 的变形。它使用减精度来表示 bin 区间的中心,即它的每一个区间都是用一个更低精度的数来表示,具体来说就是四舍五入啦。下面是一个对 1-100 的数据列建立 bak 索引的输出,其中第一列表示区间的中心,第二三列代表区间最小最大值,第四列代表该区间内数据的个数:

index (equality encoding on reduced precision values) for data.a contains 19 bitvectors for 100 objects
1   1   1   1
2   2   2   1
3   3   3   1
4   4   4   1
5   5   5   1
6   6   6   1
7   7   7   1
8   8   8   1
9   9   9   1
10  10  14  5
20  15  24  10
30  25  34  10
40  35  44  10
50  45  54  10
60  55  65  11
70  66  74  9
80  75  84  10
90  85  94  10
100 95  100 6
4.4 bin->bak2

bak2 (定义于 ibin.h,实现于 idbak2.cpp)是 bak 的变形,也是以减精度来表示区间。但与 bak 不同的是,它将 bak 的每个区间区分为两个区间:小于减精度数的区间,和大于等于减精度数的区间。虽然注释中这样说,但实现时 bak2 是将 bak 的区间分为了三个:小于、等于和大于。下面是一个对 1-100 的数据列建立 bak2 索引的输出,每列的含义与 bak 中示例相同:

index (equality encoding on reduced precision values) for data.a contains 37 bitvectors for 100 objects
1   1   1   1
2   2   2   1
3   3   3   1
4   4   4   1
5   5   5   1
6   6   6   1
7   7   7   1
8   8   8   1
9   9   9   1
10  10  10  1   
10  11  14  4   
15  15  19  5
20  20  20  1
20  21  24  4
25  25  29  5
30  30  30  1
30  31  34  4
35  35  39  5
40  40  40  1
40  41  44  4
45  45  49  5
50  50  50  1
50  51  54  4
55  55  59  5
60  60  60  1
60  61  65  5
66  66  69  4
70  70  70  1
70  71  74  4
75  75  79  5
80  80  80  1
80  81  84  4
85  85  89  5
90  90  90  1
90  91  94  4
95  95  99  5
100 100 100 1

除了上面几个算法之外,扩展的算法还有 roster 和 keywords,这两种算法比较复杂,这里就不示例讲解了。

五、多层 bitmap 索引算法

有了几个基础的 bitmap 索引算法,我们就可以考虑将这些算法组合成一个层次的结构,构造出多层的 bitmap 索引算法。下面的几个算法,即是由前面的基础 bitmap 索引算法构造出来的二(多)层 bitmap 索引算法。

5.1 bin->ambit

ambit(定义于 ibin.h,实现于 ixambit.cpp)是 multilevel-range based算法,在这个算法中索引分为多层,每层索引都是基于 range 的索引。具体实现时,fastbit 首先构造 bin,然后对桶进行分组(调用 bin::divideBitmaps),然后构造 ambit。分组粒度可以由命令行传入参数 ncoarse=x 和/或 nrefine=n 指定,否则由一简单算法确定,确定分组个数的算法为(第一个桶不参与分组):

ixambit.cpp:
33     // the default number of coarse bins is determined based on a set
34     // of simplified assumptions about expected sizes of range encoded
35     // bitmaps and word size being 32 bits.
36     const uint32_t defaultJ = static_cast
37         (nbins < 100 ? sqrt((double)nbins) :
38          0.5*(31.0 + sqrt(31.0*(31 + 4.0*nbins))));

下面看一个实际的例子,左侧是对 1-100 的数据列构造的 bin,右侧是基于该 bin 构造的 ambit:

ambit 索引

5.2 bin->pale

pale(定义于 ibin.h,实现于 ixpale.cpp)是 two-level binned equality-range算法,它的索引分为两层,第一层为 binned equality(bin) 索引,第二层为 range 索引。在具体实现时,pale 首先构造 bin,然后对桶进行分组(调用 bin::divideBitmaps),然后构造 pale。与 ambit 相同,分组粒度可以由命令行传入参数 ncoarse=x 和/或 nrefine=n 指定,否则当 bin 桶数大于31时,默认第一层为16个组:

ixpale.cpp:
45     else { // default -- 16 coarse bins
46         if (nbins > 31) {
47         j = 16;
48         }
49         else {
50         j = nbins;
51         }
52     }

下面看一个实际的例子,左侧是对 1-100 的数据列构造的 bin,右侧是基于该 bin 构造的 pale:

pale 索引

5.3 bin->pack

pack(定义于 ibin.h,实现于 ixpack.cpp)是 two-level binned range-equality 算法。它的索引分两层,与 pale 相反,第一层为 range 索引,第二层为 binned equality(bin) 索引。具体实现时,fastbit 首先构造 bin,然后对桶进行分组(调用bin::divideBitmaps),然后构造 pack。分组粒度可以由命令行传入参数 ncoarse=x 和/或 nrefine=n 指定,否则当bin桶数大于63时,默认第一层为31个组:

ixpack.cpp:
44     else { // default -- 31 coarse bins
45         if (nbins > 63) {
46         j = 31;
47         }
48         else {
49         j = nbins;
50         }
51     }

下面看一个实际的例子,左侧是对 1-100 的数据列构造的 bin,右侧是基于该 bin 构造的 pack:

pack 索引

5.4 bin->zone

zone(定义于 ibin.h,实现于 ixzone.cpp)是 two-level binned equality-equality 算法,它的索引分两层,两层均为 binned equality(bin) 索引。它的实现方式也是首先构造 bin,然后对桶进行分组(调用 bin::divideBitmaps),然后构造 zone。其分组粒度可以由命令行传入参数 ncoarse=x 和/或 nrefine=n 指定,否则当bin桶数大于31时,默认第一层为14个组:

ixpack.cpp:
46     else { // default -- 14 coarse bins
47         if (nbins > 31) {
48         j = 14;
49         }
50         else {
51         j = nbins;
52         }
53     }

下面看一个实际的例子,左侧是对 1-100 的数据列构造的 bin,右侧是基于该 bin 构造的 zone:

zone 索引

5.5 bin->fuge

fuge(定义于 ibin.h,实现于 ixfuge.cpp)是 two-level binned interval-equality 算法,fuge 为德语中 interstice 的表述。fuge 的索引分两层,第一层为 interval(mesa) 索引,第二层为 binned equality(bin) 索引,它也是采用首先构造 bin,然后基于 bin 构造 fuge 的方式。其分组粒度由 ncoarse=x 指定,否则默认的分组个数由下面算法确定:

ixfuge.cpp:
887     // default size based on the size of fine level index sf: sf(w-1)/N/sqrt(2)
...
899     if (ncoarse < 5U && offset32.back() >
900     offset32[0]+static_cast(nrows/31)) {
901     ncoarse = sizeof(ibis::bitvector::word_t);
...
913     else {
914         ncoarse = ncmax;
915     }
916     }

下面看一个实际的例子,左侧是对 1-100 的数据列构造的 bin,右侧是基于该 bin 构造的 fuge:

fuge 索引

5.6 relic->bylt

bylt(定义于 irelic.h,实现于 ixrelic.cpp)是 two-level unbinned range-equality 算法,bylt 是丹麦语的 pack(binned 版本算法)。bylt 索引分两层,第一层为 range 索引,第二层为 unbinned equality(relic) 索引。在实现时首先构造 relic,然后对桶进行分组(调用bin::divideBitmaps),然后构造 bylt。分组粒度可以由 ncoarse=x 指定,bylt 保证每组中桶数是大致均匀的,否则由下面算法决定分组的个数:

ixbylt.cpp:
182     // default size based on the size of fine level index sf:
183     // (w-1) * sqrt(sf*(sf-N/(w-1))) / (2N)
184     if (ncoarse < 5U && offset64.back() > offset64[0]+(int32_t)(nrows/31U)) { 
185     ncoarse = sizeof(ibis::bitvector::word_t);
     const int wm1 = ncoarse*8-1;
...
199         ncoarse = ncmax;
200     }
201     }

下面看一个实际的例子,左侧是对 1-100 的数据列构造的 relic,右侧是基于该 relic 构造的 bylt:

bylt 索引

5.7 relic->fuzz

fuzz(定义于 irelic.h,实现于 ixfuzz.cpp)是two-level unbinned interval-equality 算法,即 fuge 的 unbinned 版本,名字起源于 fuzzy 聚类/分类。fuzz 索引分两层,第一层为 interval(mesa) 索引,第二层为 unbinned equality(relic) 索引,具体实现时 fastbit 也是采用首先构造 relic,然后构造 fuzz 的方式。其分组粒度可以由 ncoarse=x 指定,否则默认分组个数由下面算法确定:

ixfuzz.cpp:
168     // default size based on the size of fine level index sf: sf(w-1)/N/        sqrt(2) 
169     if (ncoarse < 5U && offset64.back() > offset64[0]+nrows/31U) {
170     ncoarse = sizeof(ibis::bitvector::word_t);
...
182     else {
183         ncoarse = ncmax;
184     }
185     }

下面看一个实际的例子,左侧是对 1-100 的数据列构造的 relic,右侧是基于该 relic 构造的 fuzz:

fuzz 索引

5.8 relic->zona

zona(定义于 irelic.h,实现于 ixzona.cpp)是 two-level unbinned equality-equality 算法,zona 是丹麦语的zone(binned 版本算法),其索引分两层,两层均为 unbinned equality(relic) 索引。首先构造 relic,然后对桶进行分组构造zona,分组个数默认为11个。下面看一个实际的例子,左侧是对 1-100 的数据列构造的 relic,右侧是基于该 relic 构造的 zona:

zona 索引

六、多成分 bitmap 索引

多成分(multi-component)bitmap 索引[3]是使用一组基数将数据值分解成多个部分,分别对每个部分进行 bitmap 索引的方案。原理描述如下:给定 n-1 个基数 { bn-1, bn-2, ..., b1},那么一个值 v 可以通过下式分解为 {vn, vn-1, ..., v1}:

数据值的分解

这和数的表示法类似,如果令 bi 都是 10,那么 vi 就是十进制表示法中第 i 位的值(大于等于0,小于10)。更准确的表述可以参考[3]。下面我们来看 fastbit 中的几个实现。

6.1 relic->fade

fade(定义于 irelic.h,实现于 ifade.cpp)是 multicomponent range-encoded 算法,即在每个部分中,是使用的 range 索引。下面来看一个 range-encoded 的例子:

fade 索引

在(b)图中,选择的基数是 9,那么索引就变成了一个单成分的 range 索引算法;在(c)图中,选择的基数是 <3, 3> 这样一个双成分编码,对分解出来的每个成分(大于等于0,小于3)生成 range 索引,就得出了 (c) 图中的结果。

6.2 relic->fade->sapid

sapid(定义于 irelic.h,实现于 isapid.cpp)是 multicomponent equality-encoded 算法,即在每个部分中是使用的 equality(relic) 索引。下面来看一个 equality-encoded 的例子:

sapid 索引

在(b)图中,选择的基数是 <3, 4> 这样一个双成分编码,对分解出来的每个成分生成 relic 索引,就得到了 (b) 图中的索引结果。

除了这两个索引算法之外,还有 sbiad(multicomponent interval-encoded),egale(multicomponent equality code on bins), entre(multicomponent interval code on bins), moins(multicomponent range code on bins)这几个索引算法。从括号中我们可以大致猜出这些索引的实现方式,但是由于我们现在没有一个很好的示例展现方式,用实际用例来展现这些索引算法的效果将会留给以后的文章进行。

七、总结

这篇文章基于 fastbit 软件包,加以实际的用例对常用的 bitmap 索引算法进行了一个较为系统的介绍。不过生成 bitmap 索引仅仅是第一步,bitmap 索引在存储时会有很大的开销,在不损害(较少损害)查询效率的情况下,对 bitmap 索引进行有效的压缩是一个非常有挑战性的课题。除了 bitmap 索引的生成和存储之外,在不同类型的 bitmap 索引上实现高效的各种类型的查询,也是一个值得进一步探讨的问题。我们很高兴地看到 fastbit 软件包实现了很多这些相关领域的算法,为我们提供了非常宝贵的资料。

参考文献

[1] C-Y. Chan and Y. E. Ioannidis, An efficient bitmap encoding scheme for selection queries, in Proceedings of the ACM international conference on Management of data (SIGMOD), 1999.
[2] P. O’Neil and DalIan Quass, Improved Query Performance with Variant Indexes, in Proceedings of the ACM international conference on Management of data (SIGMOD), 1997.
[3] C-Y. Chan and Y. E. Ioannidis, Bitmap Index Design and Evaluation, in Proceedings of the ACM international conference on Management of data (SIGMOD), 1998.

我为什么这么忙

这里已经很长时间没有更新了,原因很简单,我很忙!敲下这几个字时,我正坐在母校中国科学院研究生院中关村园区东小楼的台阶上,等待某人过来给我盖一个戳——如果能把这个行为称为被“戳”一下的话,我已经千疮百孔了。

1. 品行鉴定

今天这个戳,是要戳到“品行鉴定”上。我个人是相当不理解该文件存在的意义,但是为了这个戳,我已经是第二次跑过来了。最开始给院系总支的老师打电话,她说,嗯,我们已经放假了,你8月26号以后再来吧。幸运的是,我最后总算联系上一个非常好心的老师,他给我戳了一下。但没有料到的是,过了一个星期之后,该文件又回来了,意见是:落款不能用手写,必须机打。于是,我只能打电话找人,然后再跑来。

2. 离校手续单

拿到离校手续单的时候,我花了几天时间跑了一圈,我以为都办完了。然后才被告知,虽然我一次没踏入过机房,也一次没从学校财务借过钱,我仍然需要到两个相关部门去签字盖戳,否则离校手续就是没有办全,连校园卡都不给你退。

3. 某某部

第一次去某某部,那时还没有放假,但等到9点半还没有上班;第二次去某某部,已经放假了,虽然前一个周二、五和后一个周二、五都有人值班,但是去的那个周五就是没人值班;第三次去某某部,我变聪明了,让同学先去打听一下他们上不上班,结果同学只问了保安,没看到通知,通知上写的是,8月6日以后必须得等到8月26日开学才开始值班。然后...我只能继续等。

4. 毕业推荐表

由于当时工作确定较早,使用的是2009年的毕业推荐表,把2009改成2010,然后戳一下。入职后公司说,新的推荐表格式都不一样了,最好要一张新的。然后我只能先跑到院系要一张新表盖戳,然后再找就业指导中心盖戳,他们暑假里都是某天才上班,而且这天还不固定。照片还只能要白底的,只好再照一张。

5. 成绩单

上头说成绩单上非百分制都要给出说明并盖戳,而我们的教务处说,已经放假,8月26日以后上班,暑假不值班。

6. 关于校区

最要命的是,我们有两个校区,一个在玉泉路,一个在中关村。所有和院系相关的证明、戳,我都得在中关村办;所有和学校相关的证明、戳,我都得在玉泉路办。所以我有时候得来回辗转多次,而这两个校区,相距15公里,距离我住的地方,也有10公里。

7. 关于学校

在母校读研期间,我深深地羡慕该校行政人员的舒适。校图书室的上班时间为:周一到周五9点到5点,中午休息两个小时,周五下午不上班,周末不上班;校园卡中心每天中午休息两个小时,周六下午上班,周日不上班,充电卡必须在规定的时间,否则即使有工作人员也不予受理;上班时间去找科研处的工作人员,打电话背景音是商场里。更别提放寒暑假时候了,虽然很多科研人员、研究僧们连个高温假都没有,行政仍然可以理直气壮地休假,连定期值班的人都没有。

虽然前面列举了遭遇到的种种困难,但值得说明的是也有我自己的问题在里面。由于母亲重病,我办完入职手续就请假回家陪护了,因此没有来得及在放暑假前把各种手续办完。

大家都没有错,学校行政人员有权利享受假期,国家行政机关有权利要求各种靠谱和离谱材料,只剩下的是我们这些小人物,埋头捡拾着新鲜出炉的一个又一个杯具。

Shell Tips: GNU Screen 的一些小技巧

由于工作环境的问题,最近越来越感觉到 screen 命令的可贵,下面总结一点使用 screen 命令的小技巧。

最常用的参数组合:

screen -ls // 列出已有的 screen
screen -D -R // 进入指定的 screen 名,如果没有,则以该名称创建 screen

由于很常用,我把这两个命令取了个 alias:

alias sl='screen -ls'
alias sr='screen -D -R'

除了命令之外,还有快捷键 Ctrl+ac 创建 screen;Ctrl+aa 在两个 screen 之间相互切换;Ctrl+ad 从 screen 中 detach;Ctrl+a数字,跳转到数字指代的 screen。

在 screen 最下方显示状态栏,状态栏包括已经打开的 screen 标签列表,当前的 screen 和时间。其中在 screen 标签处显示该 screen 所处的目录名。显示 screen 所处的目录名这一点实现起来要困难一些,首先得修改 .bashrc,加入 screen term 对应的信息

case $TERM in
    screen*)
        # This is the escape sequence ESC k \w ESC
        # Use current dir as the title
        SCREENTITLE='\[\ek\W\e\\\]'
        PS1="${SCREENTITLE}${PS1}"
        ;;
    *)
        ;;
esac

然后 . 或者 source 一下,再修改 screen 的配置文件,添加状态栏,在 .screenrc 中添加:

caption always '%{=b cw}%-w%{=rb db}%>%n %t%{-}%+w%{-b}%< %{= kG}%-=%D %c%{-}'
shelltitle '$ |bash'

最终效果为:

GNU Screen 多标签状态栏

宅并低俗着

其实我今天本来想出门的,但是睡到 11 点,吃了 xixi 昨晚买好的蛋糕之后,再也不想动了。算了,鞋子也是买亦可不买亦可的东西,带回北京反而比较累。

xixi 去改高考卷了,白天也没时间陪我。是我逼着她去的,因为我比较爱财,改卷子能赚不少钱呢,所以这是自作自受。不过等她离开了南大,这种机会也不会再有了。我忽然意识到今年江苏数学卷好像是传说中的“数学帝”出的,不过我不太相信,出高考卷子这种事,难道只赖一个人吗?

起来以后就在网上闲逛,看了看《非诚勿扰》被整改的评论,小百合 BBS 上居然有不少人(可能甚至是大多数人)持赞同态度,让我心里着实郁闷了一把。其实韩寒对“69 圣战”的评论完全可以应用在此:

“...不要以任何名义去驱逐任何一种文化,更不要想教训和消灭它的受众群体,无论是文化还是政治都不能排他,也不能代替别人做出选择,哪怕它很傻,哪怕它不合你的口味,只要它不反人类。”

有很多人担忧会污染青少年,天,我倒希望自己被早教会一点,而且,小孩子会喜欢看这类节目吗?还提到拜金主义、低俗、虚荣,我只能说,哈!大家都去看“做好事从不留名”的《雷锋的故事》吧。

然后,然后我就发现 Twitter 抽风了,扯淡都不能了,然后我就开始看一个叫做《泡沫之夏》的偶像剧,继续低俗。

因为我 fo 的人太少,忽然觉得可看的东西少了,于是就启用了 Buzz。在 Google Reader 看到订阅了很久的一个博主今天早上生了个姑娘,当爹的喜悦洋洋溢溢飘飘洒洒,连我都跟着高兴。不过想到这样一来他责任又重了几分,况且还要在北京把孩子抚养大,我又不知道该不该高兴了。

世界杯开始了。球赛我是爱看的,因为好歹我也踢过几年球,但因为关注得少,我总是记不住那些球星。我会为精彩的传球射门欢呼,也会为失去的机会遗憾,但我讲不出那漂亮的脚法是梅西还是贝利玩出来的,也记不住巴西还是法国上届世界杯进过多少球。所以我一般不讨论这个话题,也不掺和这类讨论。

南京这几天的天气还不错——至少在屋里感觉是这样。昨天下午我出了趟门,被淋得湿透,却还愤怒于找不到一个建设银行的提款机。易于愤怒是不成熟的表现,那么我认为至少在面对系统故障的时候,我是比较成熟了。当电脑诡异地当掉且手边没有任何工具盘时,我居然没有感觉气愤,而是想尽各种办法解决问题,事后还写了篇博客记录一番。

我的 D630 要给 xixi 了,然后把她的本要来给我妹,替换掉给她的那个台式机。这是为了资源的最优配置,最差的电脑给最不需要的人。我很惊奇于居然有博客的读者还记得我的笔记本型号,我想可能是与他用的型号相同吧。等入职后公司应该会配电脑,到时候如果能折腾的话,我还会继续写折腾的记录。

该吃饭了,先宅到这里吧。

删除 MBR 引发的诡异问题

我要跟女友交换一下笔记本电脑,她不常用 Linux,而我的 Ubuntu 分区占了好几十 G 空间,因此我想还是删了再给她吧。

我的电脑有两个系统:Windows Server 2008 和 Ubuntu 10.04。按照惯常的思维,删除 Ubuntu 只需要先格式化 MBR,然后删除 Ubuntu 分区即可。因为手头没有 DOS 启动盘,我想到一键恢复的硬盘版是带 DOS 工具的,就在 Windows 下装了个一键恢复硬盘版,然后进 DOS 命令行 “fdisk /mbr”。

可谁知道做完这些之后,MBR 是清掉了,但系统无法启动了,提示消息是这样的:

Windows 未能将启动原因可能是最近更改了硬件或软件
文件:\Windows\system32\winload.exe
状态:0xc000000e
信息:无法加载所选项,因为应用程序丢失或损坏。
...

然后我就傻眼了,从来没有遇到过这种情况呀!搜索了一番之后,才明白了这是什么意思。

Windows Vista 之后的系统,不再使用 boot.ini 保存启动菜单,而是使用一种叫做 BCD(Boot Configuration Data)机制来管理启动菜单,其默认的配置文件是活动分区(一般是 C:\)的 \Boot\BCD。简单的来说,可以将 \Boot\BCD 文件看成是 GRUB 的 menu.lst(grub.conf)文件,里面储存着系统装载程序的路径和参数等。

在我这里,出现上面问题的原因是 BCD 每项记录中的 device 选项被“一键恢复硬盘版”改成了 unknown,这样启动程序不知道到哪里去找系统的装载程序,自然也就无法启动了。使用 bcdedit /store C:\Boot\BCD 可以查看系统的 BCD 每项记录。(较为诡异的是,在没有删除 MBR 之前,我是如何进入到启动项里的?)

我用的解决方法是把所有默认启动项中的 unknown 改成了 boot。还得依靠工具,使用 WinPE U 盘(DOS 启动盘未尝试)启动,进入 C:\Windows\System32\,执行 bcdedit 命令:

bcdedit /store C:\Boot\BCD /set {default} osdevice boot
bcdedit /store C:\Boot\BCD /set {default} device boot
bcdedit /store C:\Boot\BCD /set {default} detecthal 1

然后就可以启动进入 Windows 了。

南京一樽牛排

在这一个月里,我正在进行着一个人生阶段的重要跨越——从学生转型为程序员。最近在忙毕业的事情,很久没有更新博客。虽然也不是忙得没有空闲,但空闲时也没有心情来写字。体验过中国官僚制度的同学们应该都知道,跑手续是一件多么繁琐累人的事情。

到目前为止,琐事基本上告了一个段落,已经通过答辩,各项材料等都提交了上去。下面只需要办离校手续和等待发放毕业证和学位证。据说中科院的学位证一般是在七月中旬发放,唉,这样一来只能暂时拿大半个月的实习工资了。

我在西二旗的智学苑小区租了间房子,大部分东西已经搬了过去,我也准备定居在那里了。如果有朋友也同样住智学苑的,以后不妨结识一下 :)

趁着入职前的这段空闲,我请了一周的假。

今天早上到的南京,中午女朋友带我去吃垂涎已久的一樽牛排。牛排的味道很不错,还搭配饮料、汤、面包等,加上自助水果,尤其是南大学生可以打六折,这样就让它显得超值了。而且,女朋友说我运气真好,这次的牛排、果汁、水果都是她吃过量最足的。

晚上蹭了一顿南大数学系研究生的毕业聚餐。

世界杯开始了。

向费师兄家属捐款事宜

不了解此事件的,参见这个链接

消息来源:南大数学 02 级原年级长博客

关于向费存林同学捐款的办法,国内,请发信至 dean1873@gmail.com 获鼎处了解账号的相关信息,为了安全起见,不公布账号。

北美的同学,请寄支票到我处
139 Running Farm LN
Apt 104
Stanford CA 94305

支票寄出后,请给我电话确认。

捐款会在 6 月底结束。

本来我没想转发这个捐款的消息,但是我今天遇到一个和我联系的陌生朋友居然也认识费师兄。我想也许有一些有心想帮助费师兄家人的同学和朋友不能从 gookbaby 博客上了解这个信息,所以在这里我算尽一份自己的力量吧。

南京大学学位论文 LaTeX 模板

由于女朋友要写毕业论文,一些前人写的模板我不熟悉,并且摘要格式好像都不符合南京大学研究生院要求,所以我就在中科院学位论文模板的基础上给她改了一个南大研究生学位论文 LaTeX 模板。主要工作是将封面和摘要格式都改成符合南大研究生院给的样张格式,实话说,花了不少工夫。

既然模板都已经写好,后来我干脆又完善了一下,添加了博士毕业论文需要的国家图书馆论文封面。这样大概可以作为一个完整的,包含硕士和博士毕业论文格式的南大研究生学位论文 LaTeX 模板包,我将这个 LaTeX 模板释出在下面这个地址:
http://share.solrex.org/njuthesis/,或者Google Code页:http://njuthesis.googlecode.com/
下面是一个 flash 的预览:
http://share.solrex.org/njuthesis/template-preview.swf

有需要的同学可以去下载,最起码可以作为一个修改的基础,希望这些工作能够对别人有所助益。我会尽量地维护这个模板,所以如果有哪位校友觉得有不完善的地方,可以和我联系,我会修正相应的缺点。

初次尝试网上冲印

由于数码照片很普及,好久没有冲印照片的需求了。最近临近毕业,各种乱七八糟的申请表都需要一些证件照片,于是一寸照片就给用完了。

为图省事,我手头上有之前一张一寸照片的数码底板,而且觉得那张相片照得还不错,就想着再多冲洗几张算了。谁知道到附近的照相馆一问,一版一寸照片需要五块钱一张,而且还要第二天取,我怎么算都觉得不值。想起来惠普喀嚓鱼曾经有过免费洗照片的优惠,算上运费应该也不比这贵,于是就干脆回来网上冲印算了。

回来先上网调研了一下,网上冲印看起来比较靠谱的有两家:惠普喀嚓鱼网易印象派。比较了一下价格:单张照片网易印象派要便宜一些,6寸的照片,富士相纸 0.45 元一张,柯达相纸 0.6 元一张;考虑到运费和促销,惠普喀嚓鱼要便宜一些,喀嚓鱼开头免费送 10 张(首页上常年挂的免费 20 张是骗人的),超过 30 张运费就是 5 块而印象派的运费都是 8 块。

由于以前在卓越买东西喀嚓鱼老给我发优惠券,虽然一张都没来得及用,我想还是先试试它家的服务吧。为了凑齐 30 张省 5 块钱运费,我就拾掇拾掇把以前拍的一些照片觉得好的也拿出来洗了,总共凑了 33 张,算上运费是 18.8 元,平均每张合到 0.57 元。

我是 2010 年 4 月 21 日晚上 10 点左右下的单,22 日下午 5 点多通知我处理完成,23 日也就是今天中午 12 点多收到的照片。38 个小时,从这个速度来看,是相当快的了。

照片的包装是铜板纸袋外面套一层塑料封套,里面除了照片之外还有两张广告。照片用的是富士相纸,当时可选光面和磨砂的,我选的是光面的。总的来看觉得冲洗的效果很不错,我想这种成天大批量冲洗的网站,师傅手艺应该不会比一般照相馆差。

总之这次尝试让我觉得挺满意,以后有数码照片不用再专门跑照相馆去洗了。由于网上冲印又便宜又方便,看来以后实体冲洗店免不了遭受和实体书店相同的冲击。

惊闻一师兄轻生

昨天下午我在忙着提交答辩申请书的时候,忽然听到有人说我们宿舍楼有一个师兄跳楼自杀了。当时惋惜了一会儿,心想恐怕又是哪个心理变态的导师给逼的。

今天去打篮球的路上,忽然接到获鼎师兄的电话,问我知道费存林师兄吗?我当时没反应过来,说见过一面但是对不上号。获鼎问我知道不知道昨天发生的事,我才忽然被震惊了——昨天自杀的师兄姓费!

多方找人询问,了解到真的是在南大数学系时高我一届的师兄。我刚来中科院的时候,这上一届的师兄还一起请过我们吃饭,唉!

其实我很能理解费师兄的压力,中科院这种地方就是惟科研至上的地方,你发不出论文,想不出 idea,在导师眼里你就是一无能的废物,而且不能正常毕业给他丢脸。在我没有论文的时候,天天都似有一块大石压在我的心头。最苦闷的时候我脑中也曾飘过轻生的想法,但幸好还有那么多关心我的人让我觉得这个世界还有很多温情,不像毕业条例那么冷酷。

费师兄才博士二年级,按理说不是最敏感的时候,毕竟还有一年。而且这里四年五年毕业的也不是没有,三年毕业反而显得有点儿反常。但是我想费师兄一定面临着我们想象不到的压力,才会做出这样的举动。

无论如何,我对师兄的离去表示哀悼,并祝福他在天堂安息!

我将看看能否给他的家人提供什么力所能及的帮助。其实受损失最大的是他的亲人们,好好的一个孩子就这么没了,恐怕他们很难接受。

支持多浏览器的网站变灰方法

这篇文章中给出了针对 IE 浏览器的使网站变灰的方法,具体做法是在 CSS 文件的开头添加这样一行:

html { filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale=1); }

但是很遗憾这种方法并不能支持 Firefox 和 Chrome。这篇博客介绍一种支持各种浏览器的网站变灰方法,试验其支持 Firefox、Chrome 和 IE,据说可以支持 Opera(未测试),方法比较简单,就直接介绍步骤了。

1. 到这里下载 grayscale.js 文件到你网站的根目录(或者也可以不下载,直接引入该 js,未测试)。

2. 在网站的 footer 或者 header 等全局的文件中插入以下代码(注意,$() 和 .load handler需要 jquery.js 的支持,不使用 jquery 的同学可以自行搜索解决标签查找和 window onload 事件处理问题,例如这里这里):

<script type="text/javascript" src="/grayscale.js"></script>
<script type="text/javascript">
$(window).load(function () {
  grayscale( $('body') );
});
</script>

该方法的缺点是:

1. 页面加载完后才对整个页面进行变灰操作;
2. 在非 IE 浏览器中不支持来自其它域名的网站图片的变灰;
3. 造成非 IE 浏览器在加载完页面后进行大量 js 计算,该计算负担可以通过仅变灰 img, a 等标签而不是 body 来优化。

一些论文相关 LaTeX 技巧

最近在写毕业论文,记录一下使用 LaTeX 排版时的一些笔记:

1. 正文英文使用 Times * 字体:

\usepackage{times}

2. 自定义列表样式

\usepackage{enumitem}
% 例:缩略语列表,缩略语大写,全称左侧缩进对齐
\begin{description}[font=\textbf, labelindent=2em, leftmargin=6em, style=sameline]

\item[CA] Central Authority.

\end{description}

% 例:列表标签使用 *) + 元素中段落首行缩进
\begin{enumerate}[label=\alph*)]
\setlength{\parindent}{2em}

\item 测试标签

测试段落

\end{enumerate}

3. 想使用列表但不希望列表中段落整体有缩进

% 自定义 minisection 命令,小标题,无编号
\newcommand\minisection[1]{\vspace{2ex}{\heiti #1}\vspace{1ex}}
% 例
\minisection{1)测试小标题}

4. vim 中使用 gqap 命令对中文文本格式化

下载 vim 插件:http://info.sayya.org/~edt1023/vim/format.vim

5. 按行方向合并单元格

\usepackage{multirow}

6. 拼凑中文生僻字

\hbox{\scalebox{0.4}[1]{王}\scalebox{0.6}[1]{莹}}

7. 为插图加框

\fbox{\includegraphics[width=0.9\textwidth]{figname}}

8. 设置 pdf 属性,设置参考文献链接和图片链接颜色为黑色

\hypersetup{linkcolor=black, %
            citecolor=black, %
             pdftitle={Title}, %
            pdfauthor={Name}, %
           pdfsubject={Subject}, %
          pdfkeywords={Key words}}

9. 对某页分栏排版

\usepackage{multicol}
% 分两栏
\begin{multicols}{2}

不可用于浮动环境。

\end{multicols}

10. 中文 LaTeX 编译 Makefile(注意缩进应替换为制表符)

ARTICLE=filename
ARTICLE_SRC=$(ARTICLE).tex $(ARTICLE).bib CASthesis.cls CASthesis.cfg
IMAGES=

all: article

article: $(ARTICLE).pdf

$(ARTICLE).pdf: $(ARTICLE_SRC) $(IMAGES)
    latex $(ARTICLE).tex
    bibtex $(ARTICLE)
    latex $(ARTICLE).tex
    gbk2uni $(ARTICLE)
    latex $(ARTICLE).tex
    dvipdfmx $(ARTICLE).dvi

clean:
    rm -f *.aux *.toc *.lon *.lor *.lof *.ilg *.idx *.ind *.out *.log *.exa
    rm -f *.nav *.snm *.bbl *.blg *.spl *.lot *.bak *~

distclean: clean
    rm -f *.pdf *.dvi *.ps

11. IEEE 投稿 LaTeX 编译 Makefile,主要处理嵌入字体和 pdf 版本问题(注意缩进应替换为制表符)

ARTICLE=filename
ARTICLE_SRC=$(ARTICLE).tex

#DVIFLAGS=-t [letter/a4]
DVIFLAGS=
# To avoid fonts and pdfinfo problems with the pdf file.
#PS2PDFFLAGS=-sPAPERSIZE=letter -dCompatibilityLevel=1.4 \
-dPDFSETTINGS=/prepress -dMaxSubsetPct=100 -dSubsetFonts=true \
-dEmbedAllFonts=true
PS2PDFFLAGS=-dCompatibilityLevel=1.4 -dPDFSETTINGS=/prepress \
-dMaxSubsetPct=100 -dSubsetFonts=true -dEmbedAllFonts=true

all: article

article: $(ARTICLE).pdf

$(ARTICLE).pdf: $(ARTICLE_SRC) $(IMAGES)
    latex $(ARTICLE).tex
    latex $(ARTICLE).tex
    dvips $(DVIFLAGS) $(ARTICLE).dvi
    ps2pdf $(PS2PDFFLAGS) $(ARTICLE).ps

test: $(ARTICLE).pdf
    @echo "****************************************************************************"
    @echo "** IMPORTANT: PDF version should be 1.4!!!                                **"
    @echo "****************************************************************************"
    @pdfinfo $<
    @echo "****************************************************************************"
    @echo "** IMPORTANT: All Type 1 and Type 1C fonts should be embeded!!!           **"
    @echo "****************************************************************************"
    @pdffonts $<

clean:
    rm -f *.aux *.toc *.lon *.lor *.lof *.ilg *.idx *.ind *.out *.log *.exa
    rm -f *.nav *.snm *.bbl *.blg

distclean: clean
    rm -f *.pdf *.dvi *~ *.ps

又想念南京了

今天晚上把女友送上火车回南京了。她在北京年前年后花了两个月找工作,最终的结果不好不坏。签了某行卡中心,但是要下到南京基层轮岗,还不知道什么时候能调回北京。我以后又不可避免地要在南北两京之间多走几回。

关于这两个城市,我记得我曾经说过,我比较喜欢北京的大气,相比起来南京小气很多。但是体会过才发现,大气有大气的苦,小气有小气的福!

南大老校区在南京的位置相当优越,生活还是很便利的。平时逛街买衣服,往北到湖南路,往南到新街口,都是散步就可以走到了。即使是稍远点儿的夫子庙,公交也不用花很长时间。我一般都是节假日过去买些打折的衣服。

在北京,无论是办事还是闲逛,出个门实在是太累了。拿购物来说,虽然商业圈不少,但从中关村,或者现在所在的玉泉路,都不可避免地要坐很长时间的公交或地铁,特别是要赶什么特卖,就要跑更远更偏的路。经历过北京交通的朋友,其中的苦,你懂的。

从到这里的生活来说,研究生院的生活要比大学枯燥无聊得多,压力也大。周围很多同学都有类似的抱怨,后悔来到了这个地方,那又有什么办法呢?我现在唯一的想法就是赶紧毕业,脱离这一团压抑的空气。

唉,写着写着又成抱怨了,其实两个城市个中好坏自己都有评价,要不然也不会找工作继续选择留在北京。只是不知道工作以后生活和心情会不会变得好些,能够更有趣快乐一些,只当是个期冀吧,为将来可能的幸福。

我的京东换货经历

京东上也买过不少东西,这两天第一次体验了京东的售后客服,如实记录一下经历:

2010 年 4 月 2 日 22:09,在京东下了买电熨斗的单;

2010 年 4 月 3 日 08:39,收到订单已到达自提点的手机短信通知;

2010 年 4 月 3 日 10:55,在石景山自提点付款提货(必须先付款才能检查物品),拿到货物检查发现有问题,电熨斗有明显使用过的痕迹。当场提出换货,被告知自提点只负责提货,不负责售后,需要自己回去与客服联系;

2010 年 4 月 3 日 11:44,由于网上订单仍然显示未完成,无法提交返修申请,于是拨打京东客服 400 电话询问了一下情况,客服小姐的回答仍是等订单显示完成后在网上提交返修单;

2010 年 4 月 3 日 15:56,网上订单显示已完成;

2010 年 4 月 3 日 16:26,提交返修单,返修类型:换货,问题描述:电熨斗被使用过: 1. 电熨斗水箱内有残留水珠; 2. 电熨斗尾部下方支撑脚有磨损和污迹; 3. 电熨斗中部塑料转盘有破损; 4. 电熨斗插头周围有污迹;

2010 年 4 月 3 日 16:54,收到返修已生成换货新单的手机短信通知;

2010 年 4 月 4 日 09:46,接到快递电话,更换了新品。

说实话,事情顺利地挺出乎我意料的。因为从论坛上还有其它网站看到很多对京东售后的抱怨,本来有做好长期抗战的心理准备,没想到那么容易就把问题解决了,这件事情的处理我还是很满意的。当然,这只是个案,我只如实记录个人遭遇,不参与对京东客服整体质量的讨论。

使用无线自组网共享互联网接入

在这个互联网已经渗透入每个角落的时代,GUCAS 的网络接入收费显得非常不合时宜:(二年级以上同学)每个月 25 元套餐,其中包括5G国内流量、2G 国际流量,国内流量超出部分按 10元/G 收费,国际超出部分按 1元/M 收费。幸好有了 IPv6 BT(IPv6 流量不计入收费流量),不然 GUCAS 的网络就是一个悲剧。

对于高年级同学来说稍微好一点的是,某些实验室会有免费的网络,还可稍解流量窘迫。但如果不下 BT、不看视频、不视频聊天的话,5G 每月也是用不完的,而且 25 元的价钱也并不便宜,所以很多高年级同学都是宿舍共用一个上网帐号。

共用上网帐号有几种方式:1> 使用路由器,这是比较简洁的方式,但是这样就无法使用 IPv6——目前的路由器一般不支持 IPv6 路由功能,因此需要使用特别的配置才能同时支持 IPv6;2> 使用代理,一台电脑作为主机,为另一台电脑开一个代理,这种方式可以使用 IPv6,但缺点是主机分配的 IP 可能变化,需要手动更新代理地址,而且部分软件并不能完美支持代理。

我这里尝试了另外一种方式,使用无线自组网共享互联网接入,只适用于两台都带无线网卡的电脑共享上网。简单点儿来说,就是让两台电脑无线网卡相连,其中一台(主机)将有线的互联网接入通过无线链路共享给另外一台(从机)。这种方案同样适用于那些家里有两台笔记本却只有一个网口的家庭,省了买路由器的钱。

注:下文使用操作系统平台为 Windows XP SP3。

首先,需要将主机的有线连接即“本地连接”设为可共享。具体方法是,在主机上右击“本地连接”,选择“属性”,进入“高级”选项卡,“选中 Internet 连接共享”中的两个复选框,即“允许其他网络用户通过此计算机的 Internet 连接来连接”和“允许其他网络用户控制或禁用共享的 Internet 连接”。

其次,将两台电脑进行无线自组网。无线自组网的建立方式根据网卡管理软件的不同可能有不同的方法,简单的来说就是建立一个两台笔记本之间的一个点到点的(不需要接入点的)无线连接。一个典型的配置是:

主机:
Ethernet adapter 无线网络连接:

        Connection-specific DNS Suffix  . :
        IP Address. . . . . . . . . . . . : 192.168.0.1
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . :
从机:
Ethernet adapter 无线网络连接:

        Connection-specific DNS Suffix  . : mshome.net
        IP Address. . . . . . . . . . . . : 192.168.0.27
        Subnet Mask . . . . . . . . . . . : 255.255.255.0
        Default Gateway . . . . . . . . . : 192.168.0.1

需要注意的一点是,两台电脑需要在同一个 Windows 工作组中,这里两台电脑的工作组都是 MSHOME。

如果对无线自组网不是很了解,以上两步可以通过软件来进行设定。联想有一款叫做“闪联任意通”的软件,配置起来相对简单好用,用它的“共享网络”功能即可做到以上两步。但是闪联任意通有一些BUG,会造成服务占用 CPU 过高。一旦配置成功之后,记住建立的点到点网络 SSID(一般以 PAN_ 开头),以后每次两台电脑都连接至该网络即可。不再需要闪联任意通的运行。

最后,将从机有线接口的 IPv4 功能禁用,将从机无线接口的 IPv6 功能禁用。具体方法是,在从机上右击“本地连接”,选择“属性”,在“常规”选项卡中的“此连接使用下列项目”选择框中的“Internet 协议 (TCP/IP)”前的复选框去掉,确定退出;在从机上右击“无线网络连接”(也可能是其它名称),在类似于上面的位置找到“Microsoft TCP/IP 版本 6”,去掉前面的复选框。

经过上面三步之后,就可以保证从机的 IPv4 的流量会走无线接口,使用主机共享的 IPv4 互联网接入;而 IPv6 的流量会走有线接口,使用本地交换机提供的 IPv6 互联网接入。第二步建立的点到点网络会保存到无线网络配置中,两台电脑开机只要打开无线,一般就会自动连接到该点到点网络,无需再进行额外的手动修改。(即便是使用代理的同学,由于无线的 IP 不会变化,这样做也能带来不用修改代理地址的好处。)

综上,这种方式可以完美地实现共享 IPv4 接入而又不影响 IPv6 连接。

注册 Google Voice 的曲折经历

昨天 iron-feet 同学给我讲了不少 Google Voice 的好处,搞得我也心痒痒的(技术男的通病),想去注册一个。但后来发现只有收到邀请才能注册,Google 官方的邀请可能要等很长时间,于是我就在 Twitter 上发推求邀请,非常感谢好心的 @liyong3 同学(blog),马上就给我发了邀请。

前面是好运,下面就是悲剧的开始。在注册之前我也知道注册 Google Voice 的麻烦之处:不允许中国网络访问,要有出国代理或VPN;激活时不允许绑定非美国号码,要申请到一个虚拟的美国号码,并转发电话到自己的聊天软件。我就是在激活上出了问题。

在目前网上流传的几个可以申请美国号码的服务里:ipkall 注册时无论如何都会出现密码错误;Gizmo 已经被 Google 收购,目前不提供注册;Freedigits 早就不提供注册了。所以从我的体验来看,能用的就只剩下:http://www.virtualphoneline.comhttp://www.groovytel.com 了。其实这两家网站的页面风格一模一样,很可能是一个公司的产品。

http://www.virtualphoneline.com 之所以流行跟谷奥那篇介绍注册 Google Voice 的文章有关,但是 virtualphoneline 注册的免费虚拟号码只能试用 24 天,不过能以更多的形式(10 种)转发来电;至少从声明上来看,http://www.groovytel.com 要好一些,免费号码能试用 3 年,但是转发形式少了(6种)些。不过还好他们都支持转发到 Gtalk。

我一开始就注册了这两个服务的号码,也设置了转发到 Gtalk。但在 Google Voice 里尝试打了几十次激活电话,也没收到一个来电。于是我就对网上流传的各种方案进行尝试,包括网上没有的方案。整整尝试了一下午,才收到了那么几次 virtualphoneline+nonoh 的电话,但是很悲剧,nonoh 的拨号盘不能配合 virtualphoneline 输入认证码。于是我只好无奈放弃了。

到了晚上 11 点多我看 Google Reader 的时候,心仍有些不甘。看了一个视频,发现别人 Gtalk 有个联系人叫做 service@gtalk2voip.com,我顺手也加上了。然后将 groovytel 改回转发到 Gtalk,看文章的时候一会儿过去打一下,一会儿过去打一下,没想到还真给我打通了。按照网上的方法,先输一个数字,回车,再输一个数字,回车,就通过了验证。

总结一下下午激活失败的可能原因:

1. 没有加 service@gtalk2voip.com 机器人为联系人。其实我不确定这个有没有用,反正加个机器人也不麻烦。

2. 可能在通话的高峰期打电话。从我看 groovytel 和 virtualphoneline 的通话记录,发现很多通话没应答只持续 5 秒钟。我不知道是不是意味着如果 5 秒钟没有接通 Gtalk 他们就放弃了连接。按说北京的下午在美国是凌晨呀,不应该是高峰的。

反正不管怎样,结果表明还是多尝试好,要有耐心,反正 Google Voice 貌似也没有限制可以尝试多少次,多次尝试打不通就换个时间打。我在 Twitter 上也碰到和我一样没能激活的好友,也许大家可以借鉴一下这里的经验。

有关 SVN、Cygwin 和 Notepad++

1. svn 的访问控制

很久以前我就自己配置过 svn 服务器,但总是不能访问成功。到最后还是使用文件系统(即用 file:/// 而不是 svn:// 或其它)访问 svn 仓库,因为自己建立的文件系统不需要认证。

今天我又尝试琢磨了一下我 svn 仓库的设置,才发现之前没配置成功的原因:svn 对用户的权限默认是关闭的。因此当我设置了用户名密码,svn ls 时得到的提示信息仍然是:

svn: Authorization failed

时,我就糊涂了,我的用户名密码没错呀,为啥还是Authorization failed?我还以为是密码设置有问题,没想到除了用户名以外,还得给用户配置访问列表(ACL),否则就什么都访问不了。说简单点儿就是 svn 用户访问控制是一个白名单机制,而我当成了黑名单机制。

知道了错误原因,就很简单了。到与 svnserve.conf 同目录下的 authz 为对应用户添加可以访问的项目就可以了。

2. cygwin 的启动速度

最近发现 cygwin 的启动速度大大变慢,一个终端起来至少要 30 秒。而且不仅仅是启动,所有程序的运行速度都变慢了,比如文件名补全竟然需要好几秒!我忍了很久,就差卸了重装它了,只是想到好不容易配好的各种环境,给忍耐了下来。

今天琢磨了一下 cygwin 的启动过程,发现可以在 bash 命令后加 -x 参数打印所有执行的命令。于是把启动 log 打印出来,查找到引起运行变慢的罪魁祸首:bash_completion。我之前装了一个名叫 bash_completion 的包所谓命令补全的增强包,好家伙,在 /etc/bash_completion.d/ 下面添加了 144 个文件。在启动的时候要一个个 source 这些脚本,怪不得慢呢!

卸载掉这个 bash_completion 包后,cygwin 的运行速度回到了原来的水平,敲命令的时候总算不用憋屈地等补全了。

3. Notepad++ 的中文搜索

使用 2.6.8 版本时,又发现无法搜索中文的 bug。我非常搞不懂 Notepad++ 的作者怎么维护软件质量的,这 bug 在我的印象里就反覆出现两次了。这样的bug都不写一个回归测试用例来检查,实在是有点儿不可思议。无奈之下只好退回到 2.6.7 版本了。