Author: qingbo

  • D-Link DWL G122 与 Linux 驱动

    从朋友那儿借了个联想的破笔记本竟然没有无线网卡,这样的配置在这年头显得有些奇特。于是在京东买了一个友讯 (D-Link) DWL-G122 无线USB网卡,省得拉网线麻烦。

    这只有1G内存的破电脑还装着 Windows 7,慢得要死。今天装了一个 Ubuntu 11.04,装的时候想到这个 USB 无线网卡可能在 Linux 里会有安装驱动的麻烦。装完之后也没多想就开始倒腾 Linux 驱动。先把 D-Link 给的 Windows 驱动盘插上,看到里面的驱动文件名是 rtl8192su.sys

    D-Link DWL-G122

    于是在 Realtek 网站的下载页面搜索 rtl8192su,找到了 Linux 驱动的下载。看到是11年7月29日更新的,还挺勤快!不过是 for kernel 2.6.37 and earlier,可是 Ubuntu 11.04 的 kernel 恰好是2.6.38!不管了,先装上试试。解压 zip 之后,进入 driver 目录又解压 .tar.gz,make, make install, sudo depmod -a,抬头一看,咦,右上角有个无线的标志啊,真管用!点开之后选择我的路由器,输入密码,连上了!

    比较兴奋,于是想在 blog 里把过程简单记录一下。写了几个字以后感觉有点不对,好像我装好系统后 ifconfig 就看到了 wlan0… 应该是 Ubuntu 本身就已经支持这个 USB 无线网卡了,只是没有主动让我选择一个无线网络吧。我又跑到下载的驱动目录里,make uninstall,重启系统。果然,本来就可以上网的!本来此文的标题是 “D-Link DWL G122 安装 Linux 驱动”,我又舍不得丢掉已经写出来的东西,就把“安装”改成了“与” 🙂

    记得六七年前尝试使用 Linux 的时候真的很有难度,装个系统得折腾好久。装完之后还有网络、显卡等各种驱动等着折腾,当然,还有可恶的中文输入法(当时我都觉得中文输入法是阻碍 Linux 在国内发展的一个重要原因了)。现在安装 Linux 不比 Windows 复杂了,新的 kernel 对新显卡、网卡的支持又相对比较好,另外中文输入法点几下配置就可以用,实在是方便多了。可惜还是缺少一个优秀的、一致的 GUI 系统,抄 Mac 也好,抄 Windows 也好,只能得其皮毛。

    又想起前些天一帮人从京东使用 .NET 开始争论 Linux 和 Windows 各自的优势了。我觉得吧,即使 Windows 非常棒,即使微软白给 Windows 授权,也还是 Linux 成本低。了解 Windows 皮毛容易,深入掌握精髓可就难了。就像 .NET 程序员一大把一大把的,但是真正理解 .NET Framework 的牛人没几个。或许大多情况下,探索精神或是别的某种性格导致了不同的选择。

  • Python 多进程日志记录

    刚开始用 Python 做 web 开发的时候我就想一个问题,如果 Python 应用需要自己记录一些比 accesslog 更详细的日志(使用 Python 的 logging module),又有多个进程,怎么办最好呢?多个进程往同一个日志文件写入会不会出问题?

    最近有个在 Apache 里用 mod_wsgi 运行的程序,设置了4个 process. 最初没有设置日志的 rotation,看起来一切正常。有一天设定了每天 midnight rotate(换成 TimedRotatingFileHandler), 第二天就出问题了,前一天的日志完全丢失,当天日志分散在前一天和当天的两个文件里,并且两个文件都在增长。比如今天是2011-08-14,现在去观察就会发现昨天的 customlog-20110813 和今天的 customlog 两个文件都在被写入。

    看了一下 TimedRotatingFileHandler 的 doRollover 方法:

        t = self.rolloverAt - self.interval
        if self.utc:
            timeTuple = time.gmtime(t)
        else:
            timeTuple = time.localtime(t)
        dfn = self.baseFilename + "." + time.strftime(self.suffix, timeTuple)
        if os.path.exists(dfn):
            os.remove(dfn)
        os.rename(self.baseFilename, dfn)
        ...
    

    这就了然了。每个进程在过了 rotate 时间点之后写第一条日志的时候,都会执行这个 doRollover,先看有没有 customlog-20110813 存在,存在的话删掉,把 customlog 改名为 customlog-20110813(注意这一步,文件名只是文件的一个属性,如果有进程已经打开该文件正在写入,并不会受影响,除非文件被删除),然后往新的 customlog 里写入。等四个进程都执行完这个方法的时候,就是一团糟了,不仅昨天的日志完全被删除,今天的日志也会有一小部分被删掉了。

    多进程 (Multiprocessing) vs. 多线程 (multithreading)

    假如只有一个进程,就不用操心这些了。我这个 qingbo.net 一直都是设置1个进程。于是我在 Stack Overflow 上问,如果 multithreading 就够了,为啥还要 multiprocessing 呢?回答者 Graham 好像是 mod_wsgi 的作者,从他的回答看,对于 Python 来说,由于 GIL 的限制,多进程才能利用多 CPU 或 core 的架构。

    好吧,想想有什么办法可以解决这个问题。

    Write separate files

    取得当前进程 ID (os.getpid()),然后把这个 pid 作为日志文件名的一部分,这样各个进程的日志操作就完全不会互相影响了。

    缺点是当服务器重启的时候,新的进程会有新的 pid,于是旧的文件不会被改成带有日期标识的名字,看起来不是那么干净。不过这个问题通过写一个简单的 shell 脚本即可修复,可以放在 crontab 里每天凌晨检查前一天的日志。

    结合 WatchedFileHandler 与 TimedRotatingFileHandler?

    以下是 WatchedFileHandler 的 emit 方法:

    def emit(self, record):
        """
        Emit a record.
    
        First check if the underlying file has changed, and if it
        has, close the old stream and reopen the file to get the
        current stream.
        """
        if not os.path.exists(self.baseFilename):
            stat = None
            changed = 1
        else:
            stat = os.stat(self.baseFilename)
            changed = (stat[ST_DEV] != self.dev) or (stat[ST_INO] != self.ino)
        if changed and self.stream is not None:
            self.stream.flush()
            self.stream.close()
            self.stream = self._open()
            if stat is None:
                stat = os.stat(self.baseFilename)
            self.dev, self.ino = stat[ST_DEV], stat[ST_INO]
        logging.FileHandler.emit(self, record)
    

    每写一条日志之前它先判断日志文件是不是被改名了,如果是的话就重新创建一个。如果 TimedRotatingFileHandler 在 doRollover 之前做这么一个检查,不就解决问题了吗?不过实际上这又牵扯到进程间同步的问题,还挺复杂的。

    WatchedFileHandler 结合 cron job

    一个取巧的办法是使用 WatchedFileHandler,并在 crontab 里每天零点添加一个任务,把日志文件改名。于是所有的进程在之后写第一条日志的时候会发现这一点,开始往新的文件里写入。

    我没有尝试这个办法所以不知到是不是有问题。但是它的前提是没一个写入操作是一个 atom operation,否则两条日志有可能混杂在一起,就坏了。我不太了解,不过这里有个讨论,看起来每条日志不超过 4K 的话是安全的。该文还展示了另一种办法——

    将日志发给一个独立的进程

    Python 的 logging module 还提供了一个 SocketHandler,用来把日志通过网络发送出去。文档里有一个非常基本的服务器端的实现。有人还基于 Twisted 写了一个更好的 logging server.

    但是这样我们除了需要维护 web server,又要维护 logging server. 万一 logging server 挂了怎么办?我有点担心。

    把日志发给 web server

    其实也是发给一个独立进程了。mod_wsgi 提供了一种途径,可以把 debug 信息写到 Apache 的 errorlog 里。不过把应用日志跟服务器 errorlog 混在一起,这显然不是什么好办法。

    比起多进程的解决方案,我更倾向于使用单线程省去这些烦恼。一方面是我的服务器比较弱,只有两个 core 🙂 正如 Graham 所说,除了 python code,还有许多处理比如接受、分发请求,发送响应回客户端,处理静态文件请求等都是在 Apache 的 C code里执行的,所以不会让一个 core 忙不过来另一个却闲着。我倒没有实际经验看看单个 Python 应用进程在4核或8核机器上面对大并发量的情况。

    单进程的另一个好处,可以不用 memcached 之类的东西,自己直接在进程的内存里方便地作缓存。如果有多个进程这么搞,那就太浪费内存了。

  • 使用第三方网站作为用户认证系统

    很早的时候就有人发明了 OpenID,希望解决用户在每一个网站都重复注册流程的问题,但是由于种种原因,这个事情好久没什么起色。我曾经也弄过 OpenID,后来发现由于不怎么常用,我连 URL、密码之类的都记不住,还不如在每个网站上都注册一下。从网站的角度看,他们也不愿意把网站的入口交给第三方——这个 OpenID provider 的网站挂了怎么办?直到出现 Google/Yahoo! 这样级别的大佬作为 OpenID provider 还比较靠谱。第一,它们足够稳定;第二,它们本身就是许多广为使用的服务的提供商,这个也让人可以信赖第一点是成立的,它们从自身利益出发就有足够的理由去保障。到了这个阶段,就不是 OpenID 的成功了,而是 Google/Yahoo! 的成功,或者说第三方登录的成功,选择什么协议已经不重要了。

    现在国外许多网站都使用 Facebook Connect,大部分都是为了让自己的用户把 Facebook 账户关联起来,好从 Facebook 拿到用户的数据,或者让用户把本站的信息向 Facebook 发送,利用 Facebook 的巨大社交网络作传播。所以大部分的 Facebook Graph 教程,都在讲怎么往自己网站加个 Facebook Connect 的按钮,如何重定向,如何拿到用户的隐私数据等等。

    不过我最近在想做一个新的网站的时候,就想直接依赖第三方的用户认证系统,而不自己实现了。向第三方网站 pull/push 数据只是一个附带产物。以下只是我很粗浅的想法,还没有实现,等将来有了实际经验的话也许再回来更新一下这篇文章吧。

    基于 cookie 的用户名密码认证

    每个做过网站的都记得一般是怎么用用户名密码做用户登录的。数据库里有一个表来记录用户名和 hash 过的密码,登录时,用同样的算法 hash 提交过来的密码,看跟数据库里的记录是否一致。如果登录成功,创建一个或几个 cookie,里面记录该用户已经登录成功,并且有算法保证这个 cookie 的信息(用户名、过期时间)不是伪造的(许多使用 HMAC 算法)。这样用户下次请求的时候,就不再需要重新提交用户名密码了,直接检查请求中附带的 cookie 即可知道他是谁。

    一直遵从这么一个思路,我都快忘了它是干嘛的了。如果一个网站有 UGC,那么很多情况下我们都需要知道访问者的身份。我们所需要的就是身份认证,让用户可以安全地保存他的内容或秘密。

    Facebook Connect 作为身份认证服务

    使用第三方用户认证的概念就是,以前我们直接问用户要口令,来确定来者是谁,现在转而去一个可信的人(Facebook/Google)那儿去查。一旦查清楚身份,我们就给用户一个临时的通行证(cookie),在一段时间内就不用再要密码或者再去第三方哪里查了。看起来很显然,不过我花了点时间才想清楚这一点。所以现在我们最需要的就是从 Facebook/Google 那儿要一个 ID,就好像一个人的名字、身份证号码一样。有一些选择:

    • Facebook ID 是一个号码,在 Facebook 的用户系统中是绝对不会重复的
    • 申请授权的时候,同时申请得到用户 email 的权限。email 也是一个非常合适的 ID,甚至比 Facebook ID 还好,因为它在 Facebook 之外也是唯一的。

    Stack Overflow 的身份认证

    上面也提到了,一旦确认身份之后,还是用 cookie 作为临时通行证。我们可以把 Facebook ID 或者 email 放在 cookie 里,同时放一个 hash 来保证它的真实性。Stack Overflow 就是一个很好的例子,我觉得它是使用 email 作为 ID 的,可以这么来验证这一点:

    1. 确保你的 Google/Facebook 账户使用的 email 地址是一样的
    2. 通过 Google 登录 Stack Overflow,创建账户
    3. 退出登录,然后用 Facebook 重新登录
    4. 这时候你就看到,进入了刚才通过 Google 登录创建的账户了!

    Stack Overflow 在一个名为 “usr” 的 cookie 里保存认证信息,并且 cookie 的有效期是6个月(也许应该加个 “remember me” 的选项吧?)。所以即使退出 Google/Facebook,也不会影响在 Stack Overflow 的登录状态。把这个 cookie 复制到另一台计算机上,然后访问 Stack Overflow,你会发现你已经登录了。

    这样做会威胁到 Facebook 账户的安全吗?不会。Facebook 使用的是 OAuth 2.0,authorization code 和 acess code 很快就过期,即使有个人偷到了 cookie,闯入别人的 Stack Overflow 账户,他如果想通过 SO 在 Facebook 做点坏事的话,SO 也需要重新走个流程,获取 authorization code 及 access code。

    Quora的身份认证

    依赖第三方的登录看起来有点危险,即使是 Facebook/Google,它们也难免有 downtme,这时候用户就无法被认证了。但是如果你得到了用户的 email,将来有一天就可以摆脱 Facebook/Google,让用户在本站建立密码。

    Quora 也是个很有意思的例子。比如最初的时候我记得 Quora 是只接受 email 注册的,我就用 gmail 邮箱注册了一个账户。过了很久以后再去登录,发现有了 Connect to Facebook 这么个按钮,就点了。然后发现我进入了原来用 email 注册的那个账户,看起来跟 Stack Overflow 是一样的道理。

    不过不一样的地方是,不管你怎么登录,Quora 都要求你在它网站上设立一个密码。Twitter 的 OAuth 不提供 Email 信息,所以如果用 twitter 登录的话,还要你输入 email. 因此 Quora 并不依赖第三方认证,它只是让用户把账户跟 Facebok/Twitter 连接起来,好利用它们扩大影响。即使 twitter 几年以后不存在了,也不影响用户在 Quora 登录。

    如果我的网站要依赖第三方的用户认证,也应适当地要一些多的权限,好利用这些 SNS 的力量。归根结底,它们的 API 就是为了这个设计的,并不只是用户认证。

  • OpenVPN 客户端在 Windows 里的配置

    自己搭了一个 OpenVPN Server,以前一直是在 Mac 里使用客户端,加上 chnroutes,用得很舒服。最近想在 Windows 里用一下,结果显示能连上,但是流量就是不从 VPN 走,很郁闷。

    试了一下,连服务器 IP 10.0.0.1 都 ping 不通。运行 ipconfig 显示 OpenVPN 创建的 interface 信息为:

        Connection-specific DNS Suffix  . :
        IP Address. . . . . . . . . . . . : 10.0.0.6
        Subnet Mask . . . . . . . . . . . : 10.0.0.5
        Default Gateway . . . . . . . . . :
    

    显然错得很厉害。看客户端日志,看服务器日志,都没找出什么原因来。最终发现是客户端配置文件里有个:

    dev tap
    

    好像网上很多教程都说 Windows 平台就用 tap,其它平台用 tun (或者是我的误解吧)。看 openvpn 官方的 manual:

    TUN/TAP virtual network device ( X can be omitted for a dynamic device.)

    See examples section below for an example on setting up a TUN device.

    You must use either tun devices on both ends of the connection or tap devices on both ends. You cannot mix them, as they represent different underlying protocols.

    tun devices encapsulate IPv4 while tap devices encapsulate ethernet 802.3.

    所以这个配置必须与 Server 的配置保持一致。果然,改成 tun 以后一切正常了。


    关于 chnroutes, 以前总是打开 Usage 就直接往下找 Windows 那块,刚发现这个已经是过时的方法了。这个老办法是先找到默认网关,然后把所有中国网段的流量都从这个默认网关走,所以应该在 OpenVPN 修改默认网关(如果服务器端设置了 push “redirect-gateway” 的话客户端会自动把默认网关改成 OpenVPN 的虚拟网卡)之前执行,否则就成了所有中国网段的流量都从 OpenVPN 走(可以用 route print * 验证一下)——没有意义。并且在我的机器上不知道为什么执行那个vbs脚本没有任何效果。

    Usage 的开头就说,OpenVPN 版本在 2.1 以上的话,直接在配置文件里写上路由规则即可,用 net_gateway 表示原来的默认网关。我试了一下,路由完全正确地添加了。此法非常简单易用,看来以后看文档还是要仔细啊。

  • 欢乐谷玩了一圈

    在北京去了几次北京游乐园,却没有去过欢乐谷。趁现在没有工作,今天去玩了一圈。早就知道暑假已经来了,估计即使是工作日小孩们也会很多,有点心理准备,于是找了一个预报有雷阵雨的天去。谁知道是大家现在都不信天气预报了,还是百折不挠长了这么大连雷劈都不怕了,去到欢乐谷门口的时候还没开门就发现长队已经排起来了。

    事先查了一下,攻略说一进去就赶紧到奥德塞之旅那儿,我就按攻略去了。八点半开门,但是大部分项目九点才开始运行,所以等了二十多分钟,坐上了第一条船。视频:

    下了船全湿了,不过是夏天,后来一个小时就干了。丛林飞车是个很初级的过山车,保护措施都不需要太完善,坐我旁边的是一个老大爷,一直张着双臂很惬意的样子。天地双雄是两个柱子,一个急升,一个急降。我去的时候只开了急降的,排队大概20分钟,急降的那一瞬间感觉挺恐怖的,不光是下面没有了支撑(过山车或者奥德塞之类的),它还给你一个向下的力。还好只是很短的时间。

    玩水晶神翼的时候排了半小时,保护装置就位之后还没出发就成了贴地飞行的姿势,完全是让人体验做鸟人的感觉,第一次玩还是很恐怖的,很刺激。下午又去玩了一次基本就不用排队了,放松心情,充分信任设备的安全性,就可以享受飞翔的感觉了。雪域金翅中午12点才开始运行,排队20分钟左右,这个悬挂式过山车速度比较快,有好多翻转的地方,身体经常感受到很大的力量,这一点比水晶神翼厉害,就是第二次再去坐我觉得也不会觉得轻松。

    后来看到了极速飞车,很酷的弹射式过山车,但是人山人海,插队的,吵架的,简直就是传说中的人道主义灾难。感叹祖国大地真是狼多肉少,当初在 LA 去 Universal Studios, 还是周末,几乎所有的项目都不需要排队,最多也就几分钟,喜欢的项目可以有机会反复玩。过山车在一段直道突然加速,然后冲上最高点,我觉得这一段如果设计在一个黑暗的洞里或者水下会更刺激(像 Universal Studios 里的 Mummies 一样)。好玩是好玩,可我不想在那儿挤3个小时。问了一下工作人员,据说常年这么多人,这可如何是好……拍了一段别人玩的视频:

    太阳神车主要是感受在谷底时的速度和嗖嗖的风,我有点理解在电影 The World’s Fastest Indian 里小孩问老头速度到了 200 MPH 的时候张开嘴是什么感觉,老头好像是说张开嘴就把你吹爆了……当然太阳神车远远没有达到这个速度。站在旁边看有时候也会遇见趣事。有个女生,设备一启动就开始不由自主尖叫,两脚紧紧缠在一起,把下面的人笑弯腰了都。

    最后做了个非常错误的决定,坐了一个欢乐风火轮,转得我开始恶心,于是回家来了。工作人员一般会在介绍的时候说如果遇到身体不适可以招手,游乐园里这种项目千万不能玩。还有一个特征是在旁边看着摇啊摇,玩的人里面却没有尖叫声。这种转啊转却不刺激的项目,容易让人头晕恶心。

    还发现欢乐谷里的所谓“高速摄影”,有很多是人肉拿着单反加长焦镜头在拍呢,祖国真是劳动力物美价廉。不过我猜他们用的是 Eye-Fi 卡吧,也算高科技了(也许是人肉速递的)。

    得到的经验就是,暑假工作日去的话,就奥德赛(我后来再去的时候都找不到排到哪儿了)和极速飞车很难排上,其它的到了下午最多排个十几二十分钟,当然也许跟天气预报有点关系。

  • 瑕疵的粉饰

    最近在看林达关于美国法治与民主进程、历史的一系列书,里面讲述的许多历史事件让人收获颇丰。但是让我经常感到不舒服的是,在描写许多事件或者人物遇到一些瑕疵的时候(但是作者可能认为是完美的),总是尝试从一个顺手的角度,比如法律或者人性,去为他们的不完美做一个合理的解释,以显示他们仍旧是最好的。

    完全没有必要,读者自有能力去分辨是非,有些东西就是错的,不需要你证明这个错误是正确的合理的。这种行为让我反感的原因可能是我已经受够了从小到大被灌输的一些完美的概念。

    今天读到最后一本,第一篇里就又遇到了这种“老套的情节”。南北战争,联邦政府做手脚“合法”地将属于南军首领的阿灵顿收入囊中。但是此处林达加了一段——

    尽管在这个过程中,我们还是看到美国的法律文化在起着一定作用,换个地方,只需一纸通令,作敌产没收即可,哪里还需要费这些周折。

    我实在有点恶心,忍不住中断阅读来 blog 里记录一下。这无疑是一件肮脏的交易,是耻辱,有些人就是能从屎里发现金子。如同现今国内政府部门招标,自己注册一个公司去中标,同时还要请一个“第三方”公司代理招标以起到“监督”作用,你批判之余,难道还要赞美一下这符合流程吗?

    是不是我思维能力太差,看到很多历史的时候,我只能惊叹,却没有足够的脑力去想明白它的对错。

  • 找一份网站开发工作

    我最近要换工作,也在 blog 里发一篇,希望能增加遇见合适互联网公司的几率。简历在这里,也可下载 pdf 版本(中文 | 英文)。

    我喜欢技术,不糟蹋技术。喜欢读英文书,包括技术、非技术。最近在读 The Pragmatic Programmer,深深认同其中的观点。喜欢通过实践学习技术,比如2年前开始对 Python 感兴趣,于是基于 web.py,把这个个人网站(原来是 WordPress)用 Python 改写。

    对新公司的期望,除了经济上的回报,还希望能进入一个喜欢、尊重技术的团队,让我可以学到更多东西,同时把能力发挥到极致。我有一定经验但不是为了卖经验的,希望双方能达到共赢。

    憋不出字来了,就这样吧。朋友们看到合适的机会帮我引荐一下,谢谢!我现在住北京,但如果其它城市有合适的机会,我很乐意离开这儿。

  • 实践是砖头,理论是水泥

    这两样东西缺了一个都垒不起墙来。最近觉得实践经验不少了,但是理论缺了点,所以感觉像一堵没用水泥垒起来的墙,摇摇晃晃就快倒了。

    于是决定补补基础,从 computer architecture 到 operating system 到 compiler,再看一遍。当时因为缺少实践,很多东西也是没搞明白就过去了,重新看一次效果一定更好。

  • 读完了 In the Plex

    我买了 Kindle 上的英文版读的。读一下你就知道这本书为什么不会有中文版在大陆出售了,Google,你知道的。从我个人的角度,我越来越喜欢读英文,喜欢欧美的文化和历史,虽然英文底子还是需要大力加强。Kindle 读英文也很舒服很强大,每天都能学到一些新的单词,比纯背单词好多了。

    作为跟随 Google 成长起来的一代网民,这么多年来在网上一直不停看到 Google 的消息,而今年刚出的这本 In the Plex 则是系统地把众多的关于 Google 的故事串联起来,成为一本公司传记。作者 Steven Levy 本来就是一位对科技非常关注的记者,以前就写过一些非常出名的书比如 Hackers,是一个出色的科技作家。持一贯的认真态度,在这本 In the Plex 上 Steven Levy 也下了不少功夫,对 Google 的两位创始人,前 CEO,以及员工或前员工做了许多深入的采访,他甚至得到许可,参加一些 Google 内部的例会。

    正因为这些访谈的深入,这本书也肯定不只是已为世人熟知的旧闻的简单串联,在里面可以找到一些鲜为人知的故事。“改变世界”在常人嘴里也就是说笑而已,但是 Google 的创始人却一直认为这是他们可实现的任务,是他们创立 Google 的目的。在公司成长的过程中,他们寻找具有超人天赋的工程师帮他们实现这个愿景,但是同时又有一些相对传统、保守的人进来,帮他们做好与社会“非理想状态”的衔接——他们也需要赚钱,需要律师的保护,需要职业的管理团队。创始人的某些想法说出来很容易把旁边的人吓晕,以为是在开玩笑,而他们却是认真的,又经常为常人不能理解他们的小目标而痛苦、暴怒——比如把全世界的所有书籍扫描、识别并且让它们可以被搜索,这对人类的知识是多么大的一个贡献,可是这些混蛋为什么要百般阻挠?读这本书可以清楚地感受到在 Google 成长为今天规模的过程中,理想主义和务实主义两股力量的抗衡。

    而在此书的后记里,当时已经提到 Eric Schmidt 要把 CEO 的位置还给创始人,”Day-to-day adult supervision no longer needed!” 不知道这个 Montessori school 培养出来的狂人会把 Google 带到什么地方。

  • Book Stand

    [本文有特效无法在 RSS Reader 里展示,请查看原文]

    一个月前写了一文,说看厚书太累,那时就开始谋划找个工具来帮助我拿书——平放在桌子上读书得低着头,也还是不舒服。

    最先注意到这个 Bookgem Book Holder,不过后来看到有评论说这玩意太小,对于厚重的书来说不太适用。好处是可以架起 iPad/Kindle 之类的。

    后来顺着 Amazon 的推荐找到了一款透明的 book stand,看起来很不错,于是买了。今天终于拿到,跟预想的比较相符,感觉挺结实的(看了一下,Made in Korea)。看图:

    IMG_5559

    最下面有个,可以把底座扳开,用于支撑书不滑下来。两边的两个小手臂可以转动,并且有弹性,用于夹住翻开的书页,不用的时候底座上有个凹槽可以放进去。手臂的末端是一个可以转动的橡胶头,所以翻页还是比较容易的。背面是支架,可以随意调整各种角度,支架底部两端各缠了两个细橡胶圈,于是在光滑的桌面上也可以站得比较稳。

    这东西的卖家是 BestBookStand,这家店如其名字所表达,就是卖这种东西的,不过只有上面说的一款是用透明的硬塑料做的,其它都是各种木质材料如 Jasmine Book Stand,都比塑料的贵。木质的也有结构更复杂的比如可以放两本书的。不好的地方是没有免费配送。

    今天拿到手,旁边的同事就说他们小时候就用它保护视力和身体,我咋小时候就没见过呢。不过上淘宝看了一下,质量、设计比这个肯定都差太远了。况且我就是喜欢这种设计精良的小玩意儿,虽然以后看书的时间可能不多(一大部分也可以在 Kindle 上看)。

    我觉得 Book stand 对于看书学编程的人会比较有用,可以一边翻着书一边打字。还有厨房里的新手,像我一样必须翻着菜谱才能做饭的 🙂 最理想的当然是像吊臂台灯一样的架子,可以让人躺在床上脸朝上看书的,Amazon 上确实还真有这样的(不愧是 a to z),不过价格超高,有人也抱怨时间长了以后会稍微变形,还有书倒过来了,怎么支撑和翻页是个问题。

    最后来一个实际效果图,翻开一本厚度大约3厘米的书 (我想应该架起 iPad 也挺舒服,不过没试):

    book stand