2009-09-26

显示网易评论的总条数

  1. 使用 firefox
  2. 安装 greasemonkey 插件, https://addons.mozilla.org/en-US/firefox/addon/748
  3. 重启 firefox
  4. 打开 http://userscripts.org/scripts/show/58599
  5. 点击 Install

源码位于: http://userscripts.org/scripts/review/58599

2009-08-09

广州第一次技术沙龙总结

昨天总共有两个讲座:

第一个是赖永浩的"单枪匹马做游戏", 主要是讲了现在做网页游戏和手机软件都已经晚了,做 SNS 插件还有机会 (比如《开心农场》), 还提了几个游戏的技术点,比如要分表,尽可能用K/V 数据库。

第二个讲座是 Tim Yangkey-value 数据库。技术介绍方面很扎实,了解了不少新东西。不过评测方面有点潦草。没分析 erlang 的 key-value 数据库也是一个遗憾。

印象最深的是 KV 数据库 + lucene 的解决方案, 把以前查找的需求都交给 lucene 来完成。

每有一个新技术,大家都希望他是一个银弹,能解决所有的问题,从会后的提问中可以看出大家也有这种倾向, :)

另: 做网游似乎挣钱很容易。

2009-08-08

最近一个月(200907)的反省

  • 产品和运营很重要的,但不是我应该去做的, 应该更加关注设计,开发和技术。
  • 对一项技术的关注应该有持续性, 应该有阶段目标和时间点。
  • 应当保证时间的连续性,尽量避免被 twitter 和 google reader 打碎时间。

2009-06-28

程序治理

本文是对许老大的 一篇博文 的评论。

垃圾回收是 C++ 语言层不具备的一个功能, boost shared_ptr 在库层次实现了这个功能。对于这种超越语言功能的库,我的建议就是加强程序治理: 对使用这些库建立一些规则, 扬长避短。

  1. 对于同一个对象,要么完全使用 shared_ptr, 要么完全不使用 shared_ptr,原文提到的几个问题似乎都与这个相关。

  2. 对于一个类,在设计时就要决定这个类是否要以 shared_ptr 方法来使用。

  3. 对于需要用 shared_ptr 的类,建议采用如下的定义方式

    class _Foo {
    };
    typedef boost::shared_ptr<_Foo> Foo;
    Foo foo_new(constructor args...);




这套规则有一个变种(主要是为了解决 shared_ptr 的传播性问题): 限制 shared_ptr 在一个模块内部使用, 在模块的入口 API 处对需要返回的对象进行拷贝,以脱离 shared_ptr。

C 语言的 gobject 和 pyobject 库都有 GC 的支持,但解决起来似乎比 C++ 顺利很多,我觉得有如下的原因

  • 类和GC的概念是同时引入的, 而 C++ 的解决方案则拆成了两块

  • C++ 过于崇尚自由, 而 C 语言则已经在程序治理方面积累了很多经验

2009-05-20

[2cents] ssh 登录过慢的问题

[2cents] ssh 登录过慢的问题

可能原因

1. 服务端对客户端IP进行DNS反解过慢, 解决方法是在 /etc/ssh/sshd_config 中加入一行

UseDNS no

然后用 /etc/init.d/ssh restart 重启 DNS 服务 (ssh 重启时不会切断已有的连接)

2. 客户端 GSSAPI 认证过慢, 解决方法是在 $HOME/.ssh/config 中加入如下一段

Host *
  GSSAPIAuthentication no


3. 其他情况,可以用 ssh -vvv hostname 查看 ssh 在哪一步等待时间最长,用对应的关键词搜索即可。





2009-05-16

机房网段更改后,如何避免在机房逐台更改IP?

机房网段更改后,如何避免在机房逐台更改IP?



方法如下:


  1. 假定更改前网段为 10.0.1.*, 更改后为 10.0.2.*
  2. 先在机房内把 10.0.1.2 改为 10.0.2.2, 然后你就可以离开机房了
  3. 远程登录 10.0.2.2, 在 /etc/network/interfaces 上加入如下的一段
          iface eth0:0 inet static
                  address 10.0.1.2
                  netmask 255.255.255.0
          注意,不要加入 gateway
  4. 运行 sudo ifup eth0:0, 运行 netstat -rn 检验是否成功:
    $ netstat -rn
    Kernel IP routing table
    Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
    10.0.1.0        0.0.0.0         255.255.255.0   U         0 0          0 eth0
    10.0.2.0        0.0.0.0         255.255.255.0   U         0 0          0 eth0
    0.0.0.0         10.0.2.1        0.0.0.0         UG        0 0          0 eth0
  5. 此时你已经可以登录 10.0.1.* 网段的机器
  6. 登录 10.0.1.3 更改IP, 重启
  7. 重复第6部,直到所有机器的IP更改完毕
  8. 在 10.0.2.2 上运行 sudo ifdown eth0:0, 从 /etc/network/interfaces 中清除添加的配置段

2009-05-14

replace compiz with xcompmgr when dual-head

compiz can't be activated when I am using dual-head mode (2560x1024).

using xcompmgr is a good idea, which makes gnome-do can work in docky mode.

2009-05-09

new OpenPGP key


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1,SHA256

Sat, 09 May 2009 17:23:00 +0800

For a number of reasons, i've recently set up a new OpenPGP key, and
will be transitioning away from my old one.

The old key will continue to be valid for some time, but i prefer all
future correspondence to come to the new one. I would also like this
new key to be re-integrated into the web of trust. This message is
signed by both keys to certify the transition.

the old key was:

pub 1024D/6087D2F8 2004-09-05
Key fingerprint = 2F18 9473 01F7 5240 A6E8 B1BC E535 0AE0 6087 D2F8

And the new key is:

pub 4096R/2F6E9AE0 2009-05-09
Key fingerprint = 4223 125E ED8B 189C 67CA 2B52 8CB9 287E 2F6E 9AE0

To fetch key, you can get it with:

gpg --keyserver keys.gnupg.net --recv-key 2F6E9AE0

If you already know my old key, you can now verify that the new key is
signed by the old one:

gpg --check-sigs 2F6E9AE0

If you don't already know my old key, or you just want to be double
extra paranoid, you can check the fingerprint against the one above:

gpg --fingerprint 2F6E9AE0

If you are satisfied that you've got the right key, and the UIDs match
what you expect, I'd appreciate it if you would sign my key:

gpg --sign-key 2F6E9AE0

Lastly, if you could upload these signatures, i would appreciate it.
You can either send me an e-mail with the new signatures (if you have
a functional MTA on your system):

gpg --armor --export 2F6E9AE0 | mail -s 'OpenPGP Signatures' lidaobing@gmail.com

Or you can just upload the signatures to a public keyserver directly:

gpg --keyserver keys.gnupg.net --send-key 2F6E9AE0

Please let me know if there is any trouble, and sorry for the
inconvenience.

Regards,
LI Daobing
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEARECAAYFAkoFWHUACgkQ5TUK4GCH0vht3gCeJ76nYpGU+91pArBxH0zmv/hY
xRMAn0jcxnAkAp40BdnPQkC+mkRMeYBziQIcBAEBCAAGBQJKBVh1AAoJEIy5KH4v
bprgsh4QALvXQd+Lst/+WR7WpUF0h5efBlb8uc4lU5LAnlMS+UuDZSJuLOIJZX4z
6nHbyqfJa9WbnVeme9wlvdEM2BHw5A58b6+lxNEcjoINuYEbQriAJ66LaH+o0Qoj
tf6w3ojRp+YZrsdQJYmZkZoPEYXuOnH3rVSNzmI6HnkW5VePp8J5twxRkKCg3kM4
XSm9uzq8Aj7lD+q0CMdqKeTm6Yxu+XCXRvvyNEMbNbyZTRJFVSqzUvc+TrTz+nz5
1sLG1icFGEh8iqzO9Mq0xUpD74mLy/7s0fG0bvTUXu9VmcarweEp5l3IU5hGgQXr
pXWAtvTvOq42gVJcsQ2KQDLwcUq55oEP5l5ioDzqcK2l2x6kUJ+z7x1xgTDpdt97
CU8QeWKNblHLNtGipJs/qNvE0JLS+soUH0wfBEy333+dHhRqmyjJ+Q8GAu0bdv2D
MPIKA7HURao7MKnF7HNjKAPgrrCGYQ4WcR1n1O3LLzAg2ag1bd0vx5XjQWhPnEhN
/ttJTNW3qzw1fXsNHLK3UUcS5KX9Evyr81DwzbHjn2F5Gk7P1/0/Ed/6akf6pGpJ
ho4aVfZgz7zdDL0yG3800YCxs6nJMSt1IKimJA2bh3zAtox+QUgxnQqL4Bp6one+
+3ttIgdMEOmcIcGV0zh9RCxt+JpXeqQ5/TLsUpdYS20aqtEZaVeM
=H6UO
-----END PGP SIGNATURE-----

2009-05-01

debian/control: switch between debian and ubuntu format


#!/usr/bin/env python

import logging
import sys

log = logging.getLogger(__name__)

def main():
lines = file('debian/control').readlines()

l1 = None
l2 = None

for idx, x in enumerate(lines):
if x.startswith('Maintainer:'):
l1 = idx
elif x.startswith('XSBC-Original-Maintainer:'):
l2 = idx

if l1 is None:
log.error("can't find maintainer line")
sys.exit(1)

isUbuntu = l2 is not None

if isUbuntu:
maintainer = lines[l2].lstrip('XSBC-Original-Maintainer:').strip()
else:
maintainer = lines[l1].lstrip('Maintainer:').strip()

if isUbuntu:
lines[l1] = 'Maintainer: %s\n' % maintainer
del lines[l2]
else:
lines[l1] = 'Maintainer: Ubuntu MOTU Developers <ubuntu-motu@lists.ubuntu.com>\n' \
+ 'XSBC-Original-Maintainer: %s\n' % maintainer

file('debian/control', 'w').writelines(lines)

if __name__ == '__main__':
main()

2009-03-28

[感想] 平台,语言,库

早期的时候,要发展一门语言,需要考虑两件事情,语言本身,以及这个语言所用到的库,这时候的层次结构比较简单,就是 "操作系统 | 语言 | 库 | 程序"。

稍后出现的 Java 引入了 JVM 平台的概念,现在的层次结构就变成了 "操作系统 | 平台 | 语言 | 库 | 程序"。

这还不够, .NET 上的库已经不再依赖于语言,所以现在又变成了 "操作系统 | 平台+库 | 语言 | 程序"

这样做的好处在于:

  • 创建一门新语言不再是一门庞大的工程,你无须创建库,语言的推广不再被你所需的库没有准备好,库没有稳定这类事情的拖累。

  • 当你想革新你的项目,采用一种新的语言时,不用在意如何移植旧项目,只要新旧语言能采用同一种平台即可



事实上 JVM 平台早就有这种能力,不过却没有好好推广这种能力,早期只有 Java 和 JSP 这两种语言工作在 JVM 平台上(JSP的应用范围还严重受限),Jython, Groovy, JRuby 之类语言很晚才得到一定程度的应用,这个时候 .NET 平台已经发展了很久了。

这是我为什么不看好 D 语言的原因,他基于 C 语言的平台,却不能反馈给 C 平台(C++ 比他稍好,能用 extern "C" 的方式反馈),当然这跟 C 平台本身也有一点关系,仅有 "栈", "堆", "函数" 这样几个概念,难免有些难用。

同样我也不看好函数式语言成为一门通用的语言,他们与现有的平台的概念离得太远,同时又没有建设好自己的平台。

2009-03-17

尝试了一下直接写 gobject

先说结论吧: 1. 痛苦的体验,2. 用面向过程的语言来做面向对象的事时你需要处理很多繁琐的事情 3. 用 gob2 之类的工具可以改善体验。

基本结构


这部分有模板可以套(30-40行),你只需要把里面的名字换成自己的类的名字, 不过由于存在全大写, 首字母大写,用下划线分割的小写三种情况,所以你需要替换三次。

在这一步,你定义了 6 个宏,两个 struct 和两个函数 xxx_init 和 xxx_class_init.


处理析构


如果你的对象引用了其他对象,或者有动态分配的内存(比如字符串), 那么你就需要处理析构的问题。 gobject 为了解决循环引用的问题,所以析构分为两步, 第一步是解除对其他对象的引用(这一步叫做 dispose), 第二步是释放动态分配的内存(叫做 finialize)。在这一步中,你需要添加一个全局静态变量保存 parent_class, 定义 xxx_dispose 和 xxx_finalize (记得通过 parent_class 调用父类的对应的析构函数), 在 xxx_class_init 代码中初始化 parent_class, 已经把 xxx_dispose 和 xxx_finalize 关联到这个类。

私有成员


封装很重要,所以私有成员不应当放到头文件中,所以类 Xxx 的定义应该如下所示。

struct _Xxx {
GObject parent_instance;
XxxPrivate* priv;
}

gobject 用了一个小技巧来防止生成一个对象时分配两次内存,他可以让生成对象时申请的内存大小为 sizeof(Xxx) + sizeof(XxxPrivate),当然这个是可选的。

通常,你为了支持私有成员,你需要添加一个宏,同时在 xxx_init 和 xxx_class_init 中加入必要的初始化代码。

属性


gobject 的属性主要功能是为了实现事件监听,你可以在属性上挂回调函数来监听属性的改变。如果你不需要的监听的话,那么简单的一个私有成员,再加上 set 和 get 函数即可。实现属性是一件很郁闷的事,你首先要定义一个 enum 来给每个属性一个顺序号, 然后定义 xxx_get_property 和 xxx_set_property 来覆盖基类的实现,然后在 xxx_class_init 中为没个属性定义一个包含属性元数据的结构,最后依次用 g_object_class_install_property 安装。

仅有这些似乎还不够,你一般还需要定义一些辅助函数或辅助宏来降低用户使用的难度,包括 set, get, signal_connect 等。

信号


其实属性的大部分的功能都可以用信号来实现(在属性的 set 函数上 emit 一个 foo-changed 信号),而且 signal 的写法比较简单,无须重写 xxx_set_property 和 xx_get_property。

总之


总之,写的很烦,而且写了半天还没有写到业务代码,每增加一个属性或者信号都需要不少的工作量。看了一下 python 的 gobject 封装感觉很漂亮(见下), gob2 也不错,能让你开发得开心一点。


import gobject

class MyObject(gobject.GObject):

foo = gobject.property(type=str, default='bar')
boolprop = gobject.property(type=bool, default=False)

def __init__(self):
gobject.GObject.__init__(self)

@gobject.property
def readonly(self):
return 'readonly'



最后补一句,虽然 C 语言有些繁琐,但 C 平台真的非常成功,有空再补一下我对平台,库,语言三者关系的观点。

2009-03-13

在 Java 服务端使用 syslog 作为日志系统

1. 为什么要用 syslog?


使用 syslog 的最大理由就是可以集中处理日志,通常一个中小型的服务端10来台机器,如果日志集中到一台服务器处理起来就非常方便。

其次,你可以很方便地利用 syslog-ng 这一类的服务器来对日志进行分流,在只需要跟踪某一种类型的日志时就比较方便。

除此之外,用文件做日志在部署时总会出现目录不存在,目录没有权限的情况,而用 syslog 就没有这个问题。

2. 配置 log4j


把如下的一段加入 log4j.properties 即可把日志重定向到 syslog(同时保留了终端,方便调试)

log4j.appender.SYSLOG=org.apache.log4j.net.SyslogAppender
log4j.appender.SYSLOG.syslogHost=192.168.101.101
log4j.appender.SYSLOG.facility=local3
log4j.appender.SYSLOG.facilityPrinting=false
log4j.appender.SYSLOG.layout=org.apache.log4j.PatternLayout
log4j.appender.SYSLOG.layout.ConversionPattern=%d{dd-MM-yyyy HH:mm:ss} %-5p (%C:%M:%L) - %m%n

log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{dd-MM-yyyy HH:mm:ss} %-5p (%C:%M:%L) - %m%n

log4j.rootLogger=info, CONSOLE, SYSLOG


syslog 的每一条记录有两个属性,一个是 facility(可用于日志分类), 另外一个是 priority.

facility 就在上面的 log4j.appender.SYSLOG.facility 属性中配置,缺省值是 user, 对于服务器,我觉得在 local0 到 local7 之间选一个比较好,便于将日志分类。所有可用的 facility 可以参考log4j的文档

priority 在我们用 log.error, log.warn 之类地命令进行日志操作时就已经指定了,syslog 有 8 个优先级,log4j 用了其中的 5 个,对应关系如下(syslog的 ALERT, CRIT, NOTICE 3个等级未被使用)

log4j.FATAL = 0 = syslog.EMERG
log4j.ERROR = 3 = syslog.ERR
log4j.WARN = 4 = syslog.WARNING
log4j.INFO = 6 = syslog.INFO
log4j.DEBUG = 7 = syslog.DEBUG


log4j.appender.SYSLOG.syslogHost 这个配置选项用于配置 syslog 机的 IP, log4j.appender.SYSLOG.facilityPrinting 设为 true 时会在每条日志前打印 "local3:", 在日志没有分流时打开此选项可以用 tail -f /var/log/syslog | grep local3 来只跟踪从你的服务器传来的日志。

syslog 服务端


我一般使用 syslog-ng 来作为 syslog 服务器,安装后打开 /etc/syslog-ng/syslog-ng.conf,把 "udp()" 这一行取消掉注释后重启 syslog-ng 服务即可正常使用,所有的日志会被输出到 /var/log/syslog。(注意,如果日志服务器在外网,建议修改 /etc/hosts.deny 和 /etc/hosts.allow, 防止被人灌数据灌着玩)

一般我们会把服务器的日志定向一个单独的文件来进一步处理,最简单的情况就是把如下的一段追加到 /etc/syslog-ng/syslog-ng.conf, 然后重启 syslog-ng 服务。

filter f_foo { facility(local3); };
destination df_foo { file("/var/log/foo.log" owner("foo")); };
log {
source(s_all);
filter(f_foo);
filter(f_at_least_warn);
destination(df_foo);
};

syslog-ng 也支持把日志的输出重定向到你的程序,具体可以参见 syslog-ng 的文档。

最后你可能需要把你的日志文件加入 logrotate 的配置, 这样方便日志滚动。

2009-02-14

tegaki 0.1 is ready for ubuntu 8.10 (a handwriting input method)

Hello,

tegaki 0.1 is ready for ubuntu 8.10 in my ppa. (need more refinement before submit it to the Debian/Ubuntu official repos)

tegaki provide a handwriting input method for scim, support japanese and simplified chinese.

INSTALL:


  1. add the following line to your /etc/apt/sources.list:

    deb http://ppa.launchpad.net/lidaobing/ppa/ubuntu intrepid main

  2. run "sudo apt-get update"

  3. run "sudo apt-get install scim-tegaki"

  4. if you want to recognize Simplified Chinese, run "sudo apt-get install tegaki-zinnia-simplified-chinese"

  5. if you want to recognize Japanese, run "sudo apt-get install tegaki-zinnia-japanese"



这个情人节过得很充实

ibus 0.1.1 for ubuntu 8.10 is ready

Hello,

I have add ibus 0.1.1 to my ppa (ubuntu 8.10), you can install this by add the following line to your /etc/apt/sources.list:

deb http://ppa.launchpad.net/lidaobing/ppa/ubuntu intrepid main


all packages are in this site except two:
1. ibus-chewing: have some packaging issue not resolved.
2. ibus-table-zengma: law issue

this site is slow in China (also slow for me), if anyone want to setup (or already have setup) a mirror for this site, leave me a information, thanks.

2009-02-07

dell inspiron 1420 打开 mic 的方法

启动 gnome-volume-control 后

1. Device 选择 HDA Intel (Alsa mixer)
2. 选择 Options Tab
3. Digital Input Source 改为 Digitial Mic 1

2009-01-17

egit 安装方法

由于某些原因[1]不能直接使用 egit 的 update site. 以下为直接安装 egit 的方法

1. 下载 egit 源码
$ git clone git://repo.or.cz/egit.git

2. 打开 eclipse, 选择 File -> Import -> General -> Existing Projects into Workspace, 选择刚才的 git 目录, 导入全部的项目(大约是9个)

3. 等待 Eclipse 的 Building Workspace 结束

4. 找到 org.spearce.egit-updatesite 项目,用 "Site Manifest Editor" 打开 site.xml (缺省就是这个)

5. 在打开的界面点击 "Build All"。 注意如果以前安装过 egit, 这一步会出错,需要全部删除后重新开始。

6. 在 Help->Software Updates 中选择 Add Site, 然后点击 Local, 选择 org.spearce.egit-updatesite 的工程目录即可。

[1] http://code.google.com/p/egit/issues/detail?id=53

mylyn 连接 google code 出错的解决办法

通过 mylyn 的 Generic Web Connector(从[1]安装) 可以连接 Google Code, 不过最近没法正常连接, 解决方案如下(参考[2]):

修改 repository 的属性, 修改其中的 Additional Settings -> Advanced Configuration 中的 "Query Request URL" 和 "Query Pattern" 两项, 分别修改为
  • Query Request URL: ${serverUrl}/csv?colspec=ID+Status+Type+Owner+Summary
  • Query Pattern: "({Id}[0-9]+?)","({Status}.*?)","({Type}.*?)","({Owner}.*?)","({Description}.*?)"
具体效果参见下图:



[1] http://download.eclipse.org/tools/mylyn/update/incubator
[2] https://bugs.eclipse.org/bugs/show_bug.cgi?id=260137