Read Sean

Read me, read Sean.
posts - 508, comments - 655, trackbacks - 9, articles - 4


回想大学时代,我第一本从头到尾读完的英文小说是Arthur Hailey的《Airport》,是在大学门口的外研书店买的。当时的想法很单纯:要证明自己的英文阅读水准不差,光靠新闻、应用文和专业文献是不够的,小说占到native speaker们日常阅读相当大的比重。如果能够啃下一本真正原汁原味的长篇小说,至少说明他们读什么,我也能读、能欣赏。最终花了一个礼拜,利用课余时间读完了。

这个看似不起眼的"成就",对我自信心的建立至关重要。没有这个打底,后面恐怕也不会在知识"原始积累"的时候能有心有力去大量地阅读原版或影印版的书籍,并且往往能比别人更准确地把握原著要表达的意思。这个阅读小说原著的习惯一直延续到今天,量虽然不大,一直都有意识地在进行,比如前几年的《The Da Vinci Code》,这几年的《Animal Farm》、《1984》、《Twilight》等等。

就个人成长而言,光靠别人给你压力,给你找突破点是不够的。经验告诉我,影响自己最深远的,通常是那些自己给自己找的突破点。你能走多远,成为什么样的人,很大程度上取决于你自己。

posted @ 2011-01-01 21:09 laogao 阅读(647) | 评论 (1)编辑 收藏


相信大家对SOA这个词并不陌生,很多企业都在讲我们要上SOA,也有很多企业在呼应:我们能帮忙。但究竟什么是SOA,SOA能做什么,如何在企业中推行SOA,采用什么样的技术,这些都是摆在我们面前的现实问题。

我为什么会对这本书产生兴趣?这要从我的工作说起。我从2004年开始投身到企业软件开发当中,具体而言,就是医院管理信息系统(HIS)。我们的团队,一直都是扮演独立软件厂商(ISV)的角色,为国内大中型医院提供高品质的HIS产品和服务。

接触过医院信息化的朋友都知道,医院对软件的需求是多方面的,通常很难有一家厂商能够提供从ICU/CCU、LIS、RIS/PACS到财务软件的全线产品和服务。而HIS在所有这些系统中,管理着医院的核心运营,贯穿医院业务的各个环节,经常需要和第三方系统进行通信。如何能更好地集成医院的各类资产,为医院这个特殊的企业提供优质的服务,与医院一同成长,就成为我们关注的焦点。

作为独立软件厂商,同时也考虑到医院的实际承受能力,我们很难说服自己和医院接受那些闭源SOA大厂高昂的产品服务价格。同时,出于对灵活配置和伸缩性的要求,我们在一开始就把目光锁定在开源产品上。

SOA为我们提供了架构设计丰富的营养和施展拳脚的平台。这本书要带给大家的,正是如何用开源的产品实现完整的SOA。在这个过程中,作者为我们分析了SOA的方方面面,对每个环节采用的技术都做了大量翔实的评估和介绍,对每个关键点都给出了详细的说明和完整的源代码。

如果你是企业主管、业务专家,相信你读完本书,会对SOA有更清楚的认识,对SOA能为你的企业带来什么样的价值会有更深的理解和体会。

如果你是架构师或程序员,相信你也和我一样,在阅读完本书之后,能更明白SOA的本质,掌握实际开发SOA的技能,懂得如何在企业或现有系统中引入SOA的思想。

得知博文视点引进并准备翻译这本书时,网上传来了质疑的声音,认为开源加上SOA,受众太小。我却不这么看。中国的软件产业,并非只剩下互联网和外包,除了叫得出名字的大公司,有大量中小型的独立软件厂商在暗自努力,他们在网上的曝光率很低,但都在踏踏实实地做事。他们是可爱、可敬的一批人,做的是幕后支撑企业运营的重要产品和服务,这本书也是为他们准备的。

在这里,我要特别感谢武汉博文视点的周筠老师,给我翻译本书的机会,与她相识是我的荣幸。感谢莫锡昌、成硕为审稿付出的宝贵时间。感谢编辑卢鸫翔、刘唯一和其他所有幕后工作者的辛勤劳动。

我还要感谢在事业上给予我重要帮助的两个人:毛颖和林勇,是他们的信任和鼓励让我走到今天。

最后要感谢我的家人,为了让我安心翻译这本书,牺牲了太多的周末和假期,谢谢你们对我的包容和支持,无私的爱当然要用无私的爱来回报,我爱你们!

在本书的翻译过程中,译者虽已尽力确保专业术语符合中文读者的习惯,也尽力将原著的真实意图以符合中文习惯的方式呈现给大家,毕竟水平有限,书中的问题和疏漏之处在所难免,恳请各位读者朋友批评指正,联系邮箱:gaoyuxiang.soa@gmail.com。

高宇翔

2010年11月于上海

posted @ 2010-12-30 16:20 laogao 阅读(486) | 评论 (0)编辑 收藏

2010年即将过去,在这一年里,我做了什么?找到自我了吗?我问自己。

整个2010年,我大概有这么几件事值得一提:

    首先,我去年向公司争取的产品改造计划,执行到中段,可耻地失败了;
    其次,我有幸参与翻译了两本外版IT书:《Scala编程》《开源SOA》,目前两本书均已上架;
    再次,我下了很大的决心转行做出版,最终也可耻地失败了。

不过,我找到自我了吗?我想是的:命中注定做架构师。

这两天在读周国平的《人生哲思录》:

“古希腊哲人赫拉克利特说:‘一个人的性格就是他的命运。’这句话包含两层意思:一,对于每个人来说,性格是与生俱来、伴随终身的,永远不可摆脱,如同不可摆脱命运一样;二,性格决定了一个人在此生此世的命运……赫拉克利特的名言的真正含义是:一个人应该认清自己的天性,过最适合于他的天性的生活,而对他而言这就是最好的生活……为别人对你的好感、承认、报偿做的事,如果别人不承认,便等于零。为自己的良心、才能、生命做的事,即使没有一个人承认,也丝毫无损。”

我想,这就是为什么人在抉择时要追随自己的内心和天性,因为这才是对自己最合理的安排。

posted @ 2010-12-22 23:22 laogao 阅读(512) | 评论 (1)编辑 收藏


这篇日记写给自己,发散式+意识流,赶时间的朋友请放心略过。

进入2010年,头1个月,到今天是最后1天,家里的事暂不去提,这个月是我参加工作以来感觉最累的1个月。

加入现在的这支创业团队4年,我们的产品,从无到有(1.0),到现在的2.x,倾注了很多人的心血,我们的团队,在后面的这2年多,也经历和见证了很多伤感的离别,"元老"级的人物,已经屈指可数。万事不能尽如人意,能有今天的结果,也许应该庆幸而不是哀伤,至少产品还在,至少团队还在运转。但未来会如何,谁也无法预知,我也不敢多想,我只知道,工作带给我的幸福感,正在不停的创造新低。

创业型团队的一大特点,就是一个人要同时承担多个角色的职能,而且比其他团队更容易受到外部环境的冲击。为了生存,有时不得不做一些不相关的项目、不相关的事,活下来比什么都重要,你东西再好,技术再牛逼,没人要就是没人要,没资源就是没资源,哭爹喊娘,没人理你。

去年年底,我们的老板带着我们一起,并入了现在这家集团公司,一个比我们大得多的团队。按说这应该是好事,我们也不必像原来那样担惊受怕,但事实证明这个想法非常天真,外部环境的冲击比以前更加真实的发生在我们身边,无时无刻不在提醒我们它的存在。以前我们卖力做事,一狠心一咬牙一跺脚,创业嘛,为整个团队付出,咱认了;现在我们卖力做事,不知道是在为谁付出:累的是你自己,收获的是别人。从创业的角度来说,我们失败了,我们为创业比别人多付出的那些汗水,除了回忆,现在看,也只有回忆了。对我们这个小团队来说,情形依然是:为了生存,有时不得不做一些不相关的项目、不相关的事,活下来比什么都重要,你东西再好,技术再牛逼,没人要就是没人要,没资源就是没资源,哭爹喊娘,没人理你。

有人说,其实哪里都一样。这样想可能会让人更快乐,不那么痛苦,但我很清楚,这是精神毒药,如果事实果真如此,那就不仅仅是令人伤感苦闷,而是彻彻底底的让人绝望了。

物以类聚,人以群分。我的群在哪儿?


posted @ 2010-01-31 21:25 laogao 阅读(496) | 评论 (1)编辑 收藏


周二的时候拿到了新的T400s,安装Linux(64位Karmic)的过程比预想的要曲折,趁周末有时间,整理记录于此,希望对遇到同样问题的人有所帮助。

T400s送到之前,我先简单的在网上查了查基本的配置信息,同时也看到有很多网友十分顺利的安装了Linux,不论是Ubuntu Karmic还是Arch Linux,基本都是除了指纹都是out-of-box就可直接工作的,这也符合我的预期。于是,拿着amd64版的Karmic盘,开始在T400s上安装。

基本系统的安装很顺利,跟着提示一路走完,Karmic就能够boot并正常login了,so far so good。不过登录进去之后,无线网卡不工作,只有有线连接,这是怎么回事?用lspci一看:
  • 00:00.0 Host bridge: Intel Corporation Mobile 4 Series Chipset Memory Controller Hub (rev 07)
  • 00:02.0 VGA compatible controller: Intel Corporation Mobile 4 Series Chipset Integrated Graphics Controller (rev 07)
  • 00:02.1 Display controller: Intel Corporation Mobile 4 Series Chipset Integrated Graphics Controller (rev 07)
  • 00:03.0 Communication controller: Intel Corporation Mobile 4 Series Chipset MEI Controller (rev 07)
  • 00:03.3 Serial controller: Intel Corporation Mobile 4 Series Chipset AMT SOL Redirection (rev 07)
  • 00:19.0 Ethernet controller: Intel Corporation 82567LM Gigabit Network Connection (rev 03)
  • 00:1a.0 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #4 (rev 03)
  • 00:1a.1 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #5 (rev 03)
  • 00:1a.2 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #6 (rev 03)
  • 00:1a.7 USB Controller: Intel Corporation 82801I (ICH9 Family) USB2 EHCI Controller #2 (rev 03)
  • 00:1b.0 Audio device: Intel Corporation 82801I (ICH9 Family) HD Audio Controller (rev 03)
  • 00:1c.0 PCI bridge: Intel Corporation 82801I (ICH9 Family) PCI Express Port 1 (rev 03)
  • 00:1c.1 PCI bridge: Intel Corporation 82801I (ICH9 Family) PCI Express Port 2 (rev 03)
  • 00:1c.2 PCI bridge: Intel Corporation 82801I (ICH9 Family) PCI Express Port 3 (rev 03)
  • 00:1c.3 PCI bridge: Intel Corporation 82801I (ICH9 Family) PCI Express Port 4 (rev 03)
  • 00:1d.0 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #1 (rev 03)
  • 00:1d.1 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #2 (rev 03)
  • 00:1d.2 USB Controller: Intel Corporation 82801I (ICH9 Family) USB UHCI Controller #3 (rev 03)
  • 00:1d.7 USB Controller: Intel Corporation 82801I (ICH9 Family) USB2 EHCI Controller #1 (rev 03)
  • 00:1e.0 PCI bridge: Intel Corporation 82801 Mobile PCI Bridge (rev 93)
  • 00:1f.0 ISA bridge: Intel Corporation ICH9M-E LPC Interface Controller (rev 03)
  • 00:1f.2 SATA controller: Intel Corporation ICH9M/M-E SATA AHCI Controller (rev 03)
  • 00:1f.3 SMBus: Intel Corporation 82801I (ICH9 Family) SMBus Controller (rev 03)
  • 03:00.0 Network controller: Realtek Semiconductor Co., Ltd. Device 8172 (rev 10)
  • 04:00.0 Memory controller: Intel Corporation Turbo Memory Controller (rev 11)
  • 05:00.0 SD Host controller: Ricoh Co Ltd Device e822 (rev 01)
  • 05:00.1 System peripheral: Ricoh Co Ltd Device e230 (rev 01)
注意03:00.0这一行,竟然是Realtek的8172,对应Windows下的型号是8192,Lenovo什么时候把T400s原本的无线芯片配置(Intel WiMAX/WiFi Link 5xxx)换成了Realtek 8172的?难怪没有无线,这块网卡的驱动还没有被Linux内核直接支持,需要手工安装。网上搜到很多方案,比如ndiswrapper+win版驱动等等,但这个Ubuntu LaunchPad上的方案[1]看上去最靠谱,还等什么,开工吧。
  • 首先下载驱动: http://launchpadlibrarian.net/34090404/rtl8192se_linux_2.6.0010.1012.2009_64bit.tar.gz
  • 解压后进入rtl8192se_linux_2.6.0010.1020.2009_64bit子目录,make
  • 成功后在HAL/rtl8192下能够找到r8192se_pci.ko文件,cp至/lib/modules/`uname -r`/kernel/drivers/net/wireless/
  • 然后将固件相关文件,即firmware/RTL8192SE目录,cp至/lib/firmware/`uname -r`/
  • 执行命令depmod -a重新扫描module依赖关系
  • 执行命令modprobe r8192se_pci加载该module,这一步完成以后NetworkManager就可以搜到无线网络并进行连接了
好了,到此最大的拦路虎已经消灭,开始装别的软件吧。就在这时,新的问题出现了,dmesg可以看到重复出现的如下报错/警告信息:
  • [ 483.431670] DMA: Out of SW-IOMMU space for 9100 bytes at device 0000:0e:00.0
  • [ 483.435783] DMA: Out of SW-IOMMU space for 9100 bytes at device 0000:0e:00.0
  • [ 483.439867] DMA: Out of SW-IOMMU space for 9100 bytes at device 0000:0e:00.0
  • ...
通常经过数分钟的积累,系统就死机了,只剩下CapsLock键上的小灯不停闪烁,典型的kernel panic? 根据网友提供的线索[2],由于Intel的64位实现虽是参考AMD64但细节有差异,所以在实际内存大于等于4G的环境下,某些未考虑到该特性的代码会leak memory,怎么办?增加内核启动参数mem=4G iommu=off,一方面限定内存范围,另一方面关闭IOMMU。

经过测试,这样的配置下系统和无线网络都能够持续稳定运行。系统安装到此,一个大的里程碑达成,唯一的缺憾是每次kernel升级,可能还需要手工做一些工作,且暂时不能既开无线又开4G以上内存,不过这样总好过没有无线,或者缴枪投降,不是吗?本想多骂几句Lenovo,好好的Intel芯片不用,要换Realtek,但转念一想,这已是既成事实,而且看到很多其他型号的ThinkPad,如R500、SL400等,也有不少用上了Realtek的这款无线芯片,让我们一起期待稳定可靠的驱动最终被Linux内核支持的那一天吧。

参考链接:
[1] https://bugs.launchpad.net/ubuntu/+source/linux/+bug/401126
[2] http://lwn.net/Articles/91870/

posted @ 2009-12-26 11:14 laogao 阅读(1404) | 评论 (2)编辑 收藏

到处吹嘘Scala很长时间了,却一直没有在自己的blog上增加过任何相关内容,今天就来补一补。当然,Scala的基本特性就不多废话了,网上已经有相当多的资料,如果懒得google,只想看完本文,那么你只需要知道它是一门以JVM为目标运行环境的静态编程语言(当然,Scala官方也有.NET版,但已不是其重点),同时具备面向对象和函数式编程语言的特点。本文将通过一个简单的示例,展示Scala的FP能力,其中十分heavy的用到了implicit隐式转换和模式匹配。

代码是从guithub的gist上抄的,简单改了改,原始代码见: http://gist.github.com/66925

import scala.reflect.Manifest
  
def simpleName(m:Manifest[_]):String 
= {
  val name 
= m.toString
  name.substring(name.lastIndexOf(
'$')+1)
}
  
trait Num
final class Succ[Pre<:Num] extends Num
final class _1 extends Num
type _2 
= Succ[_1]
type _3 
= Succ[_2]
type _4 
= Succ[_3]
 
case class Move[N<:Num,A,B,C]()

implicit def move1[A,B,C](implicit a:Manifest[A], b:Manifest[B]) : Move[_1,A,B,C] 
= {
  System.out.println(
"Move from " + simpleName(a) + " to " + simpleName(b))
  
null
}
 
implicit def moveN[P
<:Num,A,B,C](implicit m1:Move[P,A,C,B], m2:Move[_1,A,B,C], m3:Move[P,C,B,A]) : Move[Succ[P],A,B,C] = null
  
def run[N
<:Num,A,B,C](implicit m:Move[N,A,B,C]) = null
  
case class Left()
case class Center()
case class Right()
  
run[_3,Left,Right,Center]

 

这段代码解决的是经典的汉诺塔问题,通过一根中柱,将左柱上64个大小依次叠加的圆盘全部移动到右柱,要求整个过程中每次只能移动一个圆盘,且每个圆盘只能独立占据一根柱子或是叠加在比自身更大的圆盘上。

简单分析一下就知道,这是一个递归问题(FP的英雄特长):

  • 当只有1个圆盘时,不用通过中柱,直接可以从左柱移动到右柱;
  • 当有2个圆盘时,将小盘移动到中柱,剩下的大盘移动到右柱,再从中柱把小盘移动到右柱;
  • 当有3个圆盘时,先移动2个圆盘到中柱,再移动大盘到右柱,再移动2个圆盘到右柱;
  • ...

很容易发现一个pattern,那就是移动N(N>1)个圆盘,可以通过以下三个步骤:

  1. 移动N-1个圆盘,从左柱到中柱;
  2. 移动剩下的1个圆盘,从左柱到右柱;
  3. 移动N-1个圆盘,从中柱到右柱。

在解释代码之前,先说说Scala的implicit隐式转换,这是一个非常powerful的idea,当Scala编译器发现类型不匹配,它不会直接fail,而是尝试从代码中指定的,在scope内的implicit转换定义,来替换问题对象或表达式以满足类型要求,当然,为了避免歧义,同一时刻Scala需要找到唯一的一个满足条件的implicit定义。

我们的代码首先定义了一个取得友好类名的方法,不去深究它,然后定义了一个正整数的序列,也不去深究它了,你只需要当作他们是正整数就好,接触过FP的同学应该对此类定义不陌生,接下来定义了如下3个支持implicit传入参数的方法:

  1. implicit def move1[A,B,C](implicit a:Manifest[A], b:Manifest[B]) : Move[_1,A,B,C]
  2. implicit def moveN[P<:Num,A,B,C]( implicit
    m1:Move[P,A,C,B],
    m2:Move[_1,A,B,C],
    m3:Move[P,C,B,A]
    ) : Move[Succ[P],A,B,C]
  3. def run[N<:Num,A,B,C](implicit m:Move[N,A,B,C])

含义分别是:

  1. 当需要Move[_1,A,B,C]值时,可以找我帮忙(我有个side-effect,那就是输出移动指令);
  2. 当需要Move[Succ[P],A,B,C]时,可以找我帮忙;
  3. 运行我,我接受Move[N,A,B,C]类型的参数。

简单说明:Scala用[]表示类型参数,区别于Java的<>,另外,Scala的类型声明在变量/函数定义之后。Move[_,A,B,C]的含义是通过C,从A移动圆盘到B。

我们来模拟运行一下,为了演示效果,用一个中等复杂的数目,3个圆盘,从Left移动到Right。

run[_3,Left,Right,Center],对应Move[Succ[_2],Left,Right,Center],于是展开成三个Move:

Move[_2,Left,Center,Right]即Move[Succ[_1],Left,Center,Right]
Move[_1,Left,Right,Center]
Move[_2,Center,Right,Left]即Move[Succ[_1],Center,Right,Left]

然后继续展开Move[_2,Left,Center,Right]和Move[_2,Center,Right,Left],得到:

Move[_1,Left,Right,Center]
Move[_1,Left,Center,Right]
Move[_1,Right,Center,Left]
--------------------------
Move[_1,Left,Right,Center]
--------------------------
Move[_1,Center,Left,Right]
Move[_1,Center,Right,Left]
Move[_1,Left,Right,Center]

这个时候已经全部都匹配Move[_1,A,B,C],于是我们很容易得到以下输出:

Move from Left to Right
Move from Left to Center
Move from Right to Center
Move from Left to Right
Move from Center to Left
Move from Center to Right
Move from Left to Right

希望本文能带给Scala初学者一些感性认识和启发。


posted @ 2009-11-23 19:20 laogao 阅读(2605) | 评论 (3)编辑 收藏


前两天看到网友关于铁观音泡法的留言,接受建议,收了只手绘青花瓷盖碗,和一只公杯:



家里还有些去年的秋茶存货,开始练习用盖碗,右手的拇指、食指和中指被烫到不行,据说烫出一层老茧就好了,我觉得应该不至于那么夸张,慢慢来,挺好玩的。

posted @ 2009-10-18 11:57 laogao 阅读(406) | 评论 (0)编辑 收藏


最近围观一本JavaScript的书籍引发的争论,一不小心碰到一篇讲编程语言类型系统划分的帖子,回想起当年还在公司内部的Tech Session上主讲过这个话题,不过只涉及到静态/动态、强类型/弱类型,远没有这位仁兄总结的那么全面。

原文链接
http://www.reddit.com/r/programming/comments/63tnv/bruce_eckel_33104_im_over_it_java/c02qx55

不多废话,直入正题:

[维度一] Static vs Dynamic Typing
静态类型和动态类型,区分的关键点为编译期或运行期确定类型:静态类型在编译期确定,动态类型在运行期确定。
静态类型代表 Java、Scala、Haskell
动态类型代表 Ruby、Python、Erlang

[维度二] Strong vs Weak Typing
强类型和弱类型,区分的关键点为运行时是否自动转换到与实际类型不符的类型:强类型要求手工类型转换,弱类型自动转换。
强类型代表 Java、Scala、Python
弱类型代表 C、Assembly、JavaScript

[维度三] Latent (Implicit) vs Manifest (Explicit) Typing
隐式类型和显式类型,区分的关键点为是否要在源码中声明类型:隐式类型不需要,显式类型需要。
隐式类型代表 Haskell、Erlang、Python
显式类型代表 C、C++、Java

[维度四] Nominal vs Structural Typing
名义类型和结构类型,区分的关键点为类型判定是根据标称还是根据内容:名义类型根据标称,结构类型根据内容。
名义类型代表 C、C++、Java
结构类型代表 Haskell、Erlang、Python

关于JavaScript书籍的争论,请移步如下网址:
1- 网友Hax的"炮轰"帖 http://www.javaeye.com/topic/474725
2- 周爱民(aimingoo)的MSN空间 http://aimingoo.spaces.live.com/blog/
3- 火星常驻JE办事处相关帖 http://mars.group.javaeye.com/group/topic/14325

posted @ 2009-09-28 19:19 laogao 阅读(1120) | 评论 (0)编辑 收藏


这个周末又去收了一只紫砂,这下除了龙井,我平常喝的所有品种的茶,都有了各自专用的壶。贴个"全家福":


从左到右依次为铁观音、高山乌龙、熟普洱和生普洱。目前只有第一只养成了,其余的三只还得多花些时间和心思呢。


posted @ 2009-08-30 11:58 laogao 阅读(487) | 评论 (1)编辑 收藏


我曾经一度是Twitter重度用户,直到上周五,@laogao这个账号,被Twitter无端禁言了。被禁时,我follow 133人,被241人follow,共2260历史推。

Follow我的推友们,以及我经常@的兄弟姐妹,抱歉了,尤其那些被我"忽悠"上Twitter的朋友。当你访问http://twitter.com/laogao时,暂时只能看到"该用户被suspend"的信息。这并非是因为我是一个spammer,或者有什么所谓的"strange behaviour",至于被封的具体原因,直到今天,Twitter仍没有给予正面答复。

作为一个喜欢Twitter的简单、直接的人,我从来都很认真的对待我的每一推,尊重他人的意见,善待每个@我的朋友,也在现实世界的朋友圈中推荐大家使用这个服务。但从今天开始,我将不再向人推荐Twitter,也无法确定什么时候@laogao这个账号能够被reinstate或者再次被suspend,各位关注我的朋友,请移步https://friendfeed.com/laogao

对那些仍然天真的以为Twitter封号肯定是用户自己的问题的朋友,我很理解你们的想法,当初我看到别人被封时,也是这么想的。

各位推友保重!


posted @ 2009-07-06 21:15 laogao 阅读(515) | 评论 (0)编辑 收藏


周末去败了只全新的紫砂回来,宜兴红泥的,专门用来泡台湾高山乌龙。用之前,当然少不了开壶的过程,虽然比较耗时,但也挺有趣,在这里做个记录。

首先将新买的紫砂壶用清水洗净,浸泡一整天,其间换水2~3次,去除掉残余的泥土、灰尘等。然后放入锅内,加入清水煮上1个小时,继续消毒。


接下来,放置一边,冷却后,取老豆腐半块,放入清水中,再煮1小时,去火气。


第三步,用清水洗净,根据今后用这个紫砂壶泡什么类型的茶,选用单次用量的2~4倍茶叶,加清水,煮沸后,待茶汁完全浸出,捞起茶叶残渣,继续用茶汤煮上1个小时。


出锅。


这是成品,可以正式开始享用了:


现在开始,从头养我的第二只紫砂,细细体味那份安静和从容,让每日忙碌和疲惫的身心,有一个休息和平复的空间。

posted @ 2009-06-08 22:07 laogao 阅读(504) | 评论 (1)编辑 收藏

各位童鞋们过节好啊,今天给大家带来的是在bash中DIY制表符键自动补全。

bash是大多数主流Linux发行版的默认shell,如果你用过bash,那么一定会接触到<tab>键自动补全的这个方便的功能,当你一个命令的头几个字符敲下去,按下<tab>,如果以此开头的命令只有1个, bash会直接帮你补全,如果有多个,则会有相应提示,而在后续的参数输入时,也会带有默认的自动补全文件路径的功能。当你习惯了<tab>,很难想象没有自动补全的日子会是什么样子。

bash默认支持常见的补全功能,如可执行命令、文件路径等,如果安装了bash-completion包,甚至连chown, man, svn, ssh这些也会带有相应的自动补全提示,而不是单纯的文件路径补全。好奇的你一定想知道是怎么实现的吧,其实很简单,我们举个例子来说:

假定你有一个命令,叫做abc,它又有自己的子命令,分别是build_all、compile和update,其中compile这个子命令需要的参数必须来自project.list这个文件中列出的值,怎么实现<tab>自动补全,让bash知道abc的合法子命令和compile子命令的合法参数列表呢?

在你的~/.bashrc或者任何一个启动bash时会被执行的文件中加入下面的代码:

function _abc() {
    COMPREPLY=()
    local cur=${COMP_WORDS[COMP_CWORD]};
    local com=${COMP_WORDS[COMP_CWORD-1]};
    case $com in
    'abc')
        COMPREPLY=($(compgen -W 'build_all compile update' -- $cur))
        ;;
    'compile')
        local pro=($(awk '{print $1}' project.list))
        COMPREPLY=($(compgen -W '${pro[@]}' -- $cur))
        ;;
    *)
        ;;
    esac
    return 0
}

complete -F _abc abc

手动载入一下,或者重启bash,再敲abc命令,即可自动补全子命令,如果子命令是compile,还能自动补全相应的参数值。我们来简单分析一下这段代码。首先我们定义一个function _abc,这个函数先清空自动补全列表,根据当前输入位置前一个token判断目前需要自动补全的语境,如果是abc,则将自动补全内容设置为'build_all'、'compile'和'update',如果是'compile',则将project.list文件内容输出到补全列表,当然,这里我们也可以换成其他任何必要的方式。最后我们通过complete -F _abc abc将这段自动补全逻辑注册到abc这个主词上。这样当我们敲abc时,后续内容就能自动补全了。

Enjoy!

posted @ 2009-06-01 00:11 laogao 阅读(4073) | 评论 (1)编辑 收藏


本来是手写的一张草稿,清理台面的时候,正要扔,发现内容还有点意思,干脆吧,开个随笔记录一下,备忘,说不定还能帮到别人。

在我们日常生活和工作中,尤其浏览含有中文的网站,时常会为乱码问题犯愁,一些天生Unicode支持不到位的编程语言和软件更是加重了这个现象。虽说已经是2009年了,我们时不时还是能碰到一些明显脑残的code,吐出一堆乱码,不论你用选什么字符集,似乎都无法还原最初的中文。比如"å·²",或者同一个页面,无法用同一个字符集显示,任何一种字符都至少有一部分显示不正确,不是这儿就是那儿。

首先科普一下UTF-8。UTF-8是Unicode所有字符编码实现中,应用范围最广的一个,最大的特点是兼容ASCII码,在此基础上,通过1..4个byte来表示每一个Unicode字符。它是怎么做到的?其实很简单,看首个byte:
00000000 ~ 01111111 : 0~127 (ASCII, 单个byte) 表示Unicode范围\u0000 ~ \u007F
11000000 ~ 11011111 : (2个1打头,所以2个byte) 表示Unicode范围\u0080 ~ \u07FF
11100000 ~ 11101111 : (3个1打头,所以3个byte) 表示Unicode范围\u0800 ~ \uFFFF
11110000 ~ 11110111 : (4个1打头,所以4个byte) 表示Unicode范围\u10000 ~ \u10FFFF

除了单个byte这个case,其他情况下,后续的byte均以10打头。这些打头的bit:10、110、1110、11110,都不作为具体编码的一部分参与真正Unicode编码的计算。所以1..4个byte,其有效位数分别为:7、11、16、21,因此才有了\u007F、\u07FF、\uFFFF这样的临界值,且4个byte的空间还有富余。

有了这个基础知识,我们就来具体看看这个"已"字,是怎么被UTF-8表示的,以及为什么处理不当的代码会最终输出"å·²"。

"已"字,用Unicode表示法,是\u5DF2,按照2个byte拆开成二进制表示:
01011101 11110010
如果用UTF-8编码,采用1110???? 10?????? 10??????这个格式,?号部分填入上述01011101 11110010,得到
11100101 10110111 10110010 这样3个byte。

好了,这个时候脑残代码出现,假如它不认识UTF-8,那么他会看到这样3个前后没有关联的byte,在西欧Latin-1字符集(即ISO 8859-1)中,它们分别表示"å"、"·"、"²"这3个字符。如果把它们分别再按照UTF-8编码,就成了:
11000011 10100101 11000010 10110111 11000010 10110010
完美的UTF-8编码,只不过,这完全是假象,只能通过非常规手段才能恢复它原本的样子。


posted @ 2009-05-05 19:24 laogao 阅读(1148) | 评论 (0)编辑 收藏


上周在北京参加QCon大会,回来以后一直没有成块的时间,把一些之前只是通过Twitter分享出来的信息汇总整理出来。已经有不少朋友都在各自的博客上记录了大会感闻,所以我还是抓紧些吧,不然真要成没有营养的废话了。

QCon这次是首次进入中国,我有幸得以抽身参加。大会为期三天,由InfoQ中文站组织策划,包括 @taiwen 在内InfoQ中文站只有3个人,这是我之前没有想到的,感谢他们和志愿者的辛勤劳动,使得这次大会得以顺利举行。大会嘉宾包括了国内外许多大名鼎鼎的牛人,比如前TSS和后来InfoQ的主创Floyd Marinescu、ThoughtWorks首席科学家Martin Fowler、Spring之父Rod Johnson、eBay架构师Randy Shoup、《硝烟中的Scrum和XP》作者Henrik Kniberg、《大道至简》作者周爱民、支付宝数据库架构师冯大辉 @Fenng 等。

大会第一天,上午和下午都安排了Martin Fowler的session,分别是DSL和Ruby,虽然内容算不上特别新,但幻灯片准备很到位,而大师就是大师,思路清晰,言简意赅,尺度分寸拿捏的很好。唯一感觉可能是大家都比较含蓄,或者热身不够,沟通和对话的环节显得不是很活跃,除了买书签名的,到后面Dojo的创始人Dylan Schiemann讲Open Web,气氛就开始暖和一些了。至于Amazon的Jeff Barr,不少朋友也都说了,基本上就是来打广告的,可惜QCon北京的赞助商中,没有发现Amazon。晚上的沙龙,国际讲师唱主角,分享关于软件开发趋势的见解。

大会第二天,可能是最精彩的一天,尤其是下午 @Fenng 主持的网站架构这个Track。上午的大戏是Rod Johnson,不过也许是大家期望比较高,反倒是没觉出特别出彩的地方,Rod特别强调Simplicity和Lean,同时通批了一顿Java EE,不过把Tomcat作为simplicity和lean的代表举例,似乎大家都不是特别买账。后来才知道原来Tomcat 90%的commit都来自SpringSource,而稍后SpringSource会在此基础上推出功能更丰富的Spring tc server,以及(我猜)Spring 3.0。接下来eBay的Randy Shoup,带来了一场颇为精彩的演讲。下午来自支付宝、豆瓣网、网易有道和优酷网的架构师们共同创造了本次QCon大会最受欢迎的半天,尤其是豆瓣的 @hongqn ,内容相当务实、精彩、有货。说到这,插句题外话,如果没记错, @hongqn 是这次大会中唯一一位使用Mac的国内讲师,国际讲师用Mac的好像也只有Martin Fowler (如果说的不对还请同学们指正)。到了这个时候,国际讲师们渐渐淡出,场子交给了国内的讲师们,会场气氛也更加热闹和随意起来,包括晚上的沙龙。

大会第三天,从日程上看,并没有特别重量级的session,似乎除了云还是云,不过如果因此选择不参加的话,可能就会错过了两场很不错的演讲,分别是高焕堂的"提高架构质量的10个观点"和周爱民的"我之于架构的主要观点"。高焕堂的演讲让人耳目一新,明显感觉来自台湾的专家,比大陆的专家,对中国传统文化,有更深的理解和思考,他的"序"、"容"、"易"三角,让人印象深刻,另外他还对目前我们软件产业的结构性问题提出了批评。而周爱民的演讲同样很有深度,尤其是后面说到架构师的决策作用时,很引起我的共鸣:"架构师不需要让所有人都理解你的每一个决定和这些决定最终要达成的目标,去做就是了。"(可能原话不是这么说的,但意思是这样) 也许有些朋友觉得这两个session虚幻的成分比较重,但对我来说,收益颇丰,因为很多观点,都能够在我之前经历的一些项目和设计中找到支撑。至于其他几讲,关于云计算的,确实提不起什么兴趣,尤其是Azure,干的要命(小插曲: 现场演示一段ASP.NET代码,至少修改和重编译了3次才搞定)。大公司带着推销产品/服务的目的来参加开发会议,有点浪费大家的时间和银子啊。

最后说说大会的组织相对还有待提高的地方:
1- 第一天入场时,志愿者的引导不是很到位,报到的地方和其他展台秩序稍显混乱。
2- 同声传译据说质量不高,白天没用,但是周围的朋友在用,耳机漏音比较严重,稍影响一些效果,晚上直接通过扩音设备翻译,就很明显的感觉到脱节了。
3- 午餐和沙龙的地方,显得还是小了些,而且中午所有人都集中在一个时间去,不论排队打饭还是找位置,都比较吃力,以至于第二天中午有一小撮脑筋比较活络的同学,提前下课去打饭吃。
4- 现场网络环境比较差,害我只能用手机上twittai。

总的来说,这次的QCon还是挺不错的,希望明年的QCon会继续在中国举办,更多的嘉宾,更丰富的内容,更有深度的主题,更加精彩。


posted @ 2009-04-17 00:36 laogao 阅读(608) | 评论 (0)编辑 收藏


其实很早就听说有这个东东,只是一直没玩过,最近公司调整PC服务器,正好找个空闲实战了一把。基本的配置步骤如下(时间有限,挑简单的说,假定你要Wake-on-LAN的机器是Windows,控制服务器是Linux):

[被控制方]
1- 正常开机进入BIOS设置
2- 找到Wake-on-LAN的选项enable它(如果是Dell的机器这个选项叫Remote Wake Up)
3- 进入OS,在需要配置Wake-on-LAN的网络端口的配置项中(网络连接属性->配置->电源管理),选择允许此设备使计算机脱离待机状态
4- 记录网卡的MAC地址
5- 正常关机
// 如果被控制方是Linux/Ubuntu,OS的配置方法参考链接[4]

[控制方]
1- 安装wakeonlan,可以选择(如果有的选) apt-get install wakeonlan,或者从链接[3]获取源码手工安装(是Perl写的)
2- 通过wakeonlan+MAC地址的命令行方式控制需要wake up的机器,如 wakeonlan 01:23:45:67:89:AB
// 更高级的用法包括编写脚本,添加到cron,以及通过-f指定一个包含多个MAC地址的文件同时操作等

[基本原理]

Wake-on-LAN的相关通信协议位于OSI七层模型中的数据链路层,比IP需要的网络层还要低一层,在局域网范围发送广播,数据包格式为:
FF FF FF FF FF FF $MAC*16
即 FF FF FF FF FF FF然后重复16次对方的MAC地址,被戏称为"magic packet"。

配置成功后,只要被控制方正常关机、挂起、休眠,且环境始终不掉电,任何时候在局域网中广播"magic packet",指定网卡的机器就可以被唤醒。

链接:

[1] http://en.wikipedia.org/wiki/Wake-on-LAN
[2] http://en.wikipedia.org/wiki/OSI_model
[3] http://gsd.di.uminho.pt/jpo/software/wakeonlan/
[4] http://ubuntuforums.org/showthread.php?t=234588


posted @ 2009-03-18 20:03 laogao 阅读(1122) | 评论 (0)编辑 收藏

仅列出标题
共34页: 上一页 1 2 3 4 5 6 7 8 9 下一页 Last