2017流水账

  • 一月
    • 在元旦的锐豪杯围棋赛中,Juha七盘五胜,成功晋级一级。
    • 迪卡侬弄了一台椭圆机,要锻炼身体啦。
    • 同事彬彬离职。
    • 爸妈红宝石婚家宴。
    • Stefan Rink到杭州来传道,说服中国这边用puppet配置测试环境。
    • 春节,大年初一去看了电影《大话天竺》,妈在电影院里睡着了。
    • 到大悦城坐摩天轮。来家过年的亲戚去东海大桥。
  • 二月
    • 跑了几次医院。
    • 买了一块2T的硬盘。
    • 按照往年惯例给江妹下载超级碗录像。
    • 小学开学。
    • 买了两本书,《笔记术》和《数据术》,都是日本人写的。
    • 同事给我留下的月流量5G的联通卡失效,买了一元一天五百兆流量卡。
    • 办公室换座位,新座位0712A,打印机边过道处。
  • 三月
    • 115上续费一个月。
    • 飘鹰健身卡到期,练习最后一次。
    • Juha拍照,申领新一期身份证。
    • 同学移民澳洲,告别宴。大雨,在中山公园附近日本料理。
  • 四月
    • 为了方便,买了一台佳能的打印机,喷墨的。
    • puppet的事情还是落在我头上,之前我只玩过玩具,这真的要进入生产环境了。
    • Juha参加小应氏杯,胜一场。
    • 肇嘉浜路医院边上谈了一次。
    • 115又续费一个月。
    • 秋霞带孩子们来上海。姐妹团聚。
    • Juha摔跤,休息三周。
  • 五月
    • 继续用puppet配置环境,已经可以规模化了。
    • Juha新身份证拿到。
    • 开始晚上在办公室加班生活,很晚才回住处。
    • 还掉居委会的轮椅,使用费20快,日均一元。
    • 出差到上海部门帮搭建puppet,一周时间。
    • 杭州Team Building,去汗蒸,吃两顿。很爽。
    • 百度会员买了个季卡,72块。
  • 六月
    • 配了新眼镜。
    • “无支持”会议。
    • 到杭州城里转一圈。
    • 去了一次海洋馆,家庭卡就到期了。
    • 开始玩ELK,想在开发环境中起作用。
    • 月底决定了转到上海的部门。
  • 七月
    • 暑假开始。
    • 佘山、朱家角游玩。
    • 衢州探亲。周末游览水亭街。
    • 杭州旅游四天。
    • 持续优化AutoHotKey脚本。
    • 出差在上海,为正式转移做准备。
  • 八月
    • 北京旅游一周,住前门富力。
    • 长城、故宫、牛街、德云社、天坛、北海;见小舅。
    • 在电脑上装luajit,现在已经想不起来缘由了。
    • 34周开始在上海工作。
    • 上海puppet重新部署。
  • 九月
    • 见青岛同事,问黄岛事。
    • 参加为期四天的Java培训。
    • 老付到上海传经一周。可以学习的东西很多很多。
  • 十月
    • 衢州三个孩子到上海过假期。
    • 115又续费一个月。
    • 参观自然博物馆。
    • 树莓派上机器人重新部署起来。
    • SCM向Git迁移启动会。
    • 新部门,新领导。
    • 为老付的项目做贡献,写Keyword,要写成递归的。
    • 男人四十。
  • 十一月
    • 到江湾体育场看三对三篮球赛。看见活的邱峻。
    • Juha封窝沟。
    • Juha学会骑自行车。
    • 为知笔记续费,买一送一。
    • 给家里装上监控。
    • Team Building,滨江森林公园烧烤,半天。看见了黄浦江和长江交界的地方。
    • 在大学参加git的培训,半天。觉得讲得一般,但是事后发现能讲好很难。
    • 见吕丰一家。
    • 修理iPhone 5S。没几天屏幕又碎了。
    • 看电影Coco,曲阳电影院。
  • 十二月
    • Juha开始篮球训练。
    • 着手解决netboot问题。
    • 周末到柚子的工作室玩一个。
    • 到天潼路吃好吃的东北菜。
    • 给部门做教室内的git培训,失败。需要总结的点有很多很多。
    • 和同学见面,交流软件开发流程。
    • 小超和Juha过生日。
    • 到杭州一天,和饭团吃饭;办公室里问问题。
    • 同学回沪,聚会吃饭唱K。

Git 基础培训

12月14日的时候在部门内组织了一次Git的基础培训,效果不太好。

对于效果为什么不好,我觉得有一些原因。

  • PowerPoint的演示我用得太少。我借了一个投影仪,用了复制模式。按理说我笔记本的屏幕应该和幕布应该显示同样的内容,但是,PowerPoint在播放的时候在笔记本上显示的演讲者模式,幕布上就用不一样的分辨率显示观众内容。这个是我始料未及的。由于分辨率的改变导致观众内容非常模糊,所以在前半部分根本在和银幕做斗争。后来,我干脆不播放PPT,直接在Bash窗口里打我的命令,效果反而好些。
  • 准备的东西有点儿多,进程也编排得有点花哨。忽略了受众是常年用SVN,对分布式版本控制完全没有概念的。解释起来有一定的难度。应该拆成两个培训,可能效果会好一些。
  • 下次如果有机会再做这类的培训,我会选择Jupyter Notebook来做演示;或者写扁平风格的PPT来做,不要动画效果,朴实一些。

我准备的材料差不多是下面的这些。

0

Centralized VCS: designed with the intent that there is One True Source that is Blessed, and therefore Good.

Distributed VCS: systems are designed with the intent that one repository is as good as any other.

1 Git

Since 2005 created by Linus Torvalds

Installations

Linux: apt-get install git
Windows: Git for Windows(Git Bash)/TortoiseGit/SourceTree

Basic configurations

git config –global user.name “Your name”
git config –global user.email [email protected]
git config –global color.ui true

Commands

Basic Commands

  • init
  • add
  • commit
  • status
  • log
  • diff
  • show
  • mv
  • rm
  • reset

Branch Related Commands

  • branch
  • checkout
  • merge
  • rebase

Collaborating Commands

  • clone
  • fetch
  • push
  • pull

2 Basic Workflow

Like SVN

  • git init
  • git status
  • git add
  • git commit
  • git log
  • git diff
  • git tag

Branching

  • git branch
  • git checkout –b xxx
  • git merge xxx

Stashing

  • git stash
  • git stash apply
  • git stash pop
  • git stash drop
  • git stash list

3 Collaborating with Other Colleagues

GitLab or GitHub

Creating Repositories

Cloning others’ Repository

Collaborating Commands

4 Other Tips

I am so sorry that I have done these…

  • git checkout — files
  • git reset –hard/–soft

I can ignore the conflicts, using mine…

  • git checkout –ours/–theirs

I need one node, instead of whole branch

  • git cherry-pick

What have I done in this repo?

  • git reflog

Comprehensive logs

  • git log v2.5.. # commits since (not reachable from) v2.5
  • git log test..master # commits reachable from master but not test
  • git log master..test # commits reachable from test but not master
  • git log master…test # commits reachable from either test or master, but not both
  • git log –since=”2 weeks ago” # commits from the last 2 weeks
  • git log Makefile # commits that modify Makefile
  • git log –no-merges # dont show merge commit

Python 的 with 语句(2)

我们经常既想利用with语句的便利,又不想很麻烦的写一个类来实现__enter__() 和 __exit__()方法,有什么比较现成的办法呢?

Python的标准库里引入了contextlib 模块可以解决这个问题。contextlib 模块提供了装饰器contextmanager,使用这个,可以对已有的生成器函数或者对象进行包装,加入对上下文管理协议的支持,避免了专门编写上下文管理器来支持 with 语句。

contextmanager 用于对生成器函数进行装饰,生成器函数被装饰以后,返回的是一个上下文管理器,其 enter() 和 exit() 方法由 contextmanager 负责提供。被装饰的生成器函数只能产生一个值,否则会导致异常 RuntimeError,产生的值会赋值给 as 子句中的 target,如果使用了 as 子句的话。

from contextlib import contextmanager

@contextmanager
def demo():
    print '[Allocate resources]'
    print 'Code before yield-statement executes in __enter__'
    yield '*** contextmanager demo ***'
    print 'Code after yield-statement executes in __exit__'
    print '[Free resources]'

with demo() as value:
    print 'Assigned Value: %s' % value

例子的执行结果是:

[Allocate resources]
Code before yield-statement executes in __enter__
Assigned Value: *** contextmanager demo ***
Code after yield-statement executes in __exit__
[Free resources]

可以看到,生成器函数中 yield 之前的语句在 __enter__() 方法中执行,yield 之后的语句在 __exit__() 中执行,而 yield 产生的值赋给了 as 子句中的 value 变量。

需要注意的是,contextmanager 只是省略了 __enter__() / __exit__() 的编写,但并不负责实现资源的“获取”和“清理”工作;“获取”操作需要定义在 yield 语句之前,“清理”操作需要定义 yield 语句之后,这样 with 语句在执行 __enter__() / __exit__() 方法时会执行这些语句以获取/释放资源,即生成器函数中需要实现必要的逻辑控制,包括资源访问出现错误时抛出适当的异常。

贴一下contextmanager的实现。用的时候就当成一个修饰器(decorator)来用。

def contextmanager(func):
    """@contextmanager decorator.

    Typical usage:

        @contextmanager
        def some_generator(<arguments>):
            <setup>
            try:
                yield <value>
            finally:
                <cleanup>

    This makes this:

        with some_generator(<arguments>) as <variable>:
            <body>

    equivalent to this:

        <setup>
        try:
            <variable> = <value>
            <body>
        finally:
            <cleanup>

    """
    @wraps(func)
    def helper(*args, **kwds):
        return GeneratorContextManager(func(*args, **kwds))
    return helper

另外说一句。with 语句的管理上下文的能力在python中往往被定义成设计模式的一种。下面就是一个例子。其实就是实现上下文管理协议,但是名字叫ResourceAcquisitionIsInitialization(资源获取初始化)。只贴代码,不另外做解释了。

class Box(object):
    
    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print("Box " + self.name + " Opened")
        return self

    def __exit__(self, exception_type, exception, traceback):
        all_none = all(
            arg is None for arg in [exception_type, exception, traceback]
            )
        if (not all_none):
            print("Exception: \"%s\" raised." %(str(exception)))
        print("Box Closed")
        print("")
        return all_none

#===============================================================
if (__name__ == "__main__"):
    with Box("tupperware") as simple_box:
        print("Nothing in " + simple_box.name)
    with Box("Pandora's") as pandoras_box:
        raise Exception("All the evils in the world")
    print("end")

-EOF-

Python 的 with 语句(1)

参考了 浅谈 Python 的 with 语句

最近组里在CoDe(Competence Development,能力培养)。花姐讲文件操作,例子里有如下的代码:

with open(r'demo.txt') as f:
    for line in f:
        print line
        # ...more code

语句很简单,就是把demo.txt文件打开,逐行打印出来。我感兴趣的是这里的with语句,这个用法很简洁,比下面的try … except 用法要少一些代码量。

f = open(r'demo.txt')
try:
    for line in f:
        print line
        # ...more code
finally:
    f.close()

可以看到,下面的这种用法代码稍微复杂一些,还涉及到了文件的关闭操作。而with语句是怎么避免了显性的关闭文件呢?更进一步,with这个语句是怎么实现的,它的目的和好处是什么呢?

对比着看,可以感觉到with做了一系列的操作,准备工作、用户代码、扫尾工作。准备工作就是打开文件并且返回文件句柄(是不是这么定义?),用户代码就是中间那一部分逐行打印。扫尾工作就是关闭文件。

再做一个类比。在用robotframework做自动化测试时,总会定义 suite setup 和 suite teardown,这就是保证测试的进入和退出都有一定的保护措施,进入时做准备,退出时打扫战场。Python 的 with 语句就是suite setup 和 suite teardown的作用,是Python 2.5以后引入的特性。

在Python 2.5里要通过

from __future__ import with_statement

才能使用with 语句,到了Python 2.6就可以直接用了,它从一个实验性的特性变成了内置的了。

直接了当说,with的原理是实现了一个上下文管理协议(Context Management Protocol),而这个协议的两个必要部分就是两个方法,__enter__() 和 __exit__(),任何支持该协议的对象要实现这两个方法。一目了然了吧,这两个方法可以对应robotframework里的suite setup 和 suite teardown

先看一个例子吧。

class DummyResource(object):
    def __init__(self, tag):
        self.tag = tag
        print 'Resource [%s]' % tag

    def __enter__(self):
        print '[Enter %s]: Allocate resource.' % self.tag
        return self	

    def __exit__(self, exc_type, exc_value, exc_tb):
        print '[Exit %s]: Free resource.' % self.tag
        if exc_tb is None:
            print '[Exit %s]: Exited without exception.' % self.tag
        else:
            print '[Exit %s]: Exited with exception raised.' % self.tag
            return False

这段代码我是从最顶上那个帖子里抄的。可以做一些说明。

  • 这是一个叫DummyResource的类,提供了__enter__() 和 __exit__()两个方法,说明这个类是可以用with语句来调用的。另外从类名我们可以感觉到,with语句的运用都是和资源相关的。什么是资源?文件,网络套接字,线程thread,等等这些都是资源。
  • __enter__()方法里,除了一句打印“山顶的朋友,我在这里”,就是一句返回语句:
class DummyResource(object):
    # ...
    def __enter__(self):
        print '[Enter %s]: Allocate resource.' % self.tag
        return self	
    # ...

返回了一个self!这是什么意思?就是把这个类的实例返回出去。这样

with context_expression [as target(s)]:
    with-body

中的as target(s)就可以得到这个值了。忘了说,target(s)之所以有或许复数,是因为__enter__()方法是可以返回多个值成为一个元组的。

  • __exit__() 是个更复杂的方法,用来定义退出时候的动作。在方法的定义中可以看到有额外的参数exc_type、exc_value 和 exc_tb。这三个都是和异常相关的。如果with语句包住的用户代码正常执行,那么这三个变量都是None;反之,如果出错了,可以简单通过exc_type来判断异常的类型,配合后面两个变量获得更多的异常信息,进一步做相应的处理。
  • __exit__()方法中更重要的是它的返回值。return False。False的意思是“我还没有处理完,我要把这个异常继续抛出去,你们外面的代码去抓住它继续处理吧”。如果心满意足的,或者心怀鬼胎的觉得已经处理完了,就返回个真值,外面的代码就不会知道有异常发生过。很多问题的根本原因就这么湮没了。:-(

结合这个类定义,看看实用的调用例子吧。
小乖乖:

with DummyResource('Normal'):
    print '[with-body] Run without exceptions.'

和不乖的:

with DummyResource('With-Exception'):
    print '[with-body] Run with exception.'
    raise Exception
    print '[with-body] Run with exception. Failed to finish statement-body!'

小乖乖的输出是这样的:

Resource [Normal]
[Enter Normal]: Allocate resource.
[with-body] Run without exceptions.
[Exit Normal]: Free resource.
[Exit Normal]: Exited without exception.

很好,按部就班,只要读得懂类代码就很容易看出这些输出。下面看一下“小淘气”的输出呢。

Resource [With-Exception]
[Enter With-Exception]: Allocate resource.
[with-body] Run with exception.
[Exit With-Exception]: Free resource.
[Exit With-Exception]: Exited with exception raised.

Traceback (most recent call last):
  File "G:/demo", line 20, in <module>
   raise Exception
Exception

除了读代码能看清的输出,还要说一两句。

  • 用户代码中是先抛出了异常后又打印了一句“[with-body] Run with exception. Failed to finish statement-body!”。在输出中这句没有打印。这说明了__exit__()方法是清道夫,你们用户代码怎么乱糟糟,你先跑,抛出异常了,就别接着往下走了,我留下来打扫战场。
  • 输出中的“Traceback (most recent call last):”一段是解释器抛出的异常,在__exit__()方法中的开关就是最后的那个返回否值。如果是返回真值,这段Traceback是不会输出的。

最后,说说最初的那个花姐举出来的例子。

with open(r'demo.txt') as f:
    for line in f:
        print line
        # ...more code

打开一个Python的IDE(我用的是Pycharm CE),可以点到open的定义,就是一句话。

def open(name, mode=None, buffering=None): # real signature unknown; restored from __doc__
    """
    open(name[, mode[, buffering]]) -> file object
    
    Open a file using the file() type, returns a file object.  This is the
    preferred way to open a file.  See file.__doc__ for further information.
    """
    return file('/dev/null')

仅仅返回一个file实例。继续点过去,就豁然开朗了。

class file(object):
     # ... some codes

    def __enter__(self): # real signature unknown; restored from __doc__
        """ __enter__() -> self. """
        return self

    def __exit__(self, *excinfo): # real signature unknown; restored from __doc__
        """ __exit__(*excinfo) -> None.  Closes the file. """
        pass
     # ... more codes

file 这个类 实现了__enter__()和__exit__()方法,那外面当然可以用with语句来建立文件操作的上下文。

其实实现上下文管理协议并不是每次都需要写一个类实现两个办法,还有其他的方法,会另开一篇写写。

-EOF-

狗屎皮聚会

简单记一笔。8月20日,苏州。

因为先要去酒店入住,稍晚到会场。后来才发现第一场Scala的分享已经完全错过了。

TR在讲Symfony。由于技术细节听不太懂,只能关注一些方法,比如:

  • 跟数据相关的操作往后拖,所有的api都返回json格式的结果,前面的操作可以有更灵活的选择。
  • 路由用正则表达式来进行限制,超出这个范围的不做理会。
  • 要构造测试样本数据,合理真实,并有确实的期望结果做参考。

TR在gitbook上发布了一本相关的电子书,大家又讨论了一下gitbook的生成等周边技能。

午饭吃湖南菜。

下午令狐从架构的角度讲了讲。我能记下的是:

  • 一定要有技术手段来限制客户那些操作不能做。
  • 一定要考虑到灾难,比如硬盘坏了,节点挂了,大楼炸了。不是说过度设计,但是要找到一个平衡的点。
  • 代码检查,静态检查。要有,要有给对方犯错的机会。(这是不是说我们都长大了?)
  • 升级自己的产品的时候要兼容以前的版本,旧用户发现不能继续使用了是不可以接受的。

接下来我给大家看了一个docker-elk的image,ELK 的一个小例子。我事先导入了一本小说,然后可以分析词频,仅此而已。昨天,公司里有个培训,一个CI工程师分享ELK使用。他就是在Jenkins上用ZMQ插件把数据都规整成一定格式,用json方式发给ELK,就有各种可以供分析的新tags。我准备在自己的Jenkins上也这么弄一弄。

最后三火演示了一些Mesos,Marathon的东西,虽然知道这是分布式的方向,但是也不是个人能玩的。

每年有这么一次交流的机会很好。期待明年。

见Cliff

三月九号晚上在星光二期的新疆菜见了一个长辈Cliff,十几年没见了,又是同行,谈得非常投机。

有几点感受。

  • 专注。他一直在一个行业里工作,从来没有因为软件是万金油而转行,专注做那一块。
  • 积累。他二十年了还在用MFC,大浪淘沙,现在会MFC的高手已经少而又少了,他就是一等一的高手。二十年来他写了很多能给自己用的类库,积木搭一搭就很快了。反而不用不断的跟进新技术。
  • 围棋还是很开发智力的,要坚持。

PyCharm两件事

这是一篇技术相关的笔记,如果没有兴趣请绕路。

由于工种的变化,我开始用python写一个比较大的工程。那小作坊式的编辑器就不适合我,PyCharm就是我的选择。

单位的操作系统是Windows 7,家里的是Windows XP,两个系统上用的都是 PyCharm Community Edition 3.1.3, 都遇到了一些问题,分别说。

家里Windows XP上PyCharm 装好,启动。 发现内置的Terminal不能用,是灰的。

一开始我还到Twitter上去问,没有人给我回音。后来我发现可以看到PyCharm后台的log,具体的位置在“c:\Documents and Settings\username\.PyCharm30\system\log\idea.log”。打开,查找“Terminal”,能看到一些java抛出的异常信息。向上看,能看到一条:

“Unable to load library ‘D:\USERS\Haijiang\tools\PyCharm313\lib\libpty\win\x86\libwinpty.dll”

好吧,估计就是这个dll出的错啦。google上查找,找到了https://code.google.com/p/android/issues/detail?id=62572 这个帖子。帖子里说的是 android-studio 碰到这个问题,鉴于PyCharm和android-studio用同样的IDE,那就试试看。在#3答案里面提供了一个链接,github上的: https://github.com/rprichard/winpty/downloads 里面有一些编译好的包下载,我下载了winpty-0.1.1-msys.zip 这个包,替换了原来的位置的dll和exe文件,名字改成原来的样子。

重启,Terminal用起来。

在办公室(Windows 7)遇见的问题倒是简单一些。我最近偏爱Solarized Light这个配色主题。在github上我找到了一个为PyCharm做的主题,在这里:https://github.com/sevas/pycharm-color-schemes 。用起来还不错,有一个小问题,就是Terminal里的配色默认的情况下文字和背景是一样的,只有在选中的情况下才能看出来原来那里是有字的。一开始我以为Terminal也是灰的呢,后来发现能用,只是暗夜里的乌鸦,墨墨黑。

通过和其他的配色文件进行比较,我发现有两个变量控制终端的前景色和背景色,CONSOLE_BLUE_OUTPUT 和 CONSOLE_GREEN_OUTPUT。看到这里哑然失笑有没有?!github上的那个主题是没有这两个变量的,加上,给不同的值,把配色的xml文件放到 “c:\Documents and Settings\username\.PyCharm30\config\colors\” 下面去,PyCharm里面选好,重启。Terminal就用起来舒服了。

改良过的主题文件我放在我的github页面上了,这里

停电

家里前天晚上停电了。

楼上那家在装修,倒是好心早早就在楼下写了条子,说家里要装修了会扰民,到时候请联系,电话号码电报挂号等等,我也没当回事。一天从外面回来发现家里断电了,进门,推电闸,电来了。只是冰箱上有水,地板上的电插板也湿了。自己弄干净了就没事。再后来,下水堵了,楼上在弄水管的时候把小石子扔下来,跟他们说了,也修好了。家里的基础建设就这么一轮一轮的经受考验。

前两天情况有点变化,跳闸的时候楼上的空气开关是好的,得到楼下总闸去看看保险丝。这样弄过两次,想想和楼上的装修也关系不大,是冬天来了的信号吧。只是大晚上的去弄保险丝挺烦人,需要跑上跑下。

前天晚上十一点多,已经躺在那里打游戏,突然就断线了。起来要开灯灯不亮,知道是停电了。打手电去看空开,也还好,那就是楼下的总闸跳了。算了,不要抹黑穿衣服拿工具下楼上楼装好再下楼上楼了,睡觉吧,明天是新的一天。

可是长夜是漫漫的,翻来翻去不能入睡。网络是断了的,冰箱是热了的,电视是没的看的,和外界唯一的连接线是手机上的Edge。感觉怪怪的,好像自己困住,在一个黑漆漆的异次元,想叫叫不出,伸手一探一切都是虚幻,我在天边仿佛看到一丝白光,但是又不能向那个方向前进。我只好拿出手机看扎克看饭否看大众点评看街旁。我就想着我是一盘童安格的磁带,放了A面《干燥花》该翻面到B面放《忘不了》,唉,折腾好久,到三点,入睡。

东方既白,下楼,弄保险丝,一切都欣欣然的样子。

=====================

自从Mansum离世都没有想起写点别的。今天早上在公车上看村上春树的《当我谈跑步时,我谈些什么》,突然有写写闲话的冲动。

早上很冷,我开了空调暖了好久才爬出被窝。想着周末小超母子可以过来收拾一些冬衣。到了办公室,听说过两天会升温,那就还是我一个人跑跑吧。我是靠近天蝎的天秤,纠结的天秤。

纪念李文琛先生

m

 

这是LinkedIn上的一个截图,可惜这个页面该不会再更新了,消息也送达不到收信人了,李先生已经荣归天家了。

Man Sum为他们公司的产品提供支持,为我们提供帮助。渐渐的他和我们很多人都成了好朋友,这是一个谦逊善良的兄长,一个真正的朋友。

第一次见到Man Sum是2006年底。他和John第一次来我们这里访问。我那时还对这个领域很陌生,Man Sum给了我很大的帮助。

Man Sum总是耐心的听完我的问题,然后耐心的告诉我怎么做。有的时候我都觉得我提出的问题是很蠢,提出来多么的不应该,起码应该自己找找解决方案。可是Man Sum没有嘲笑我,没有指出应该先去RTFM或者STFW,而是撸起袖子帮我一起做,同时会一点一点的告诉我这个信息到哪里去找,如何找到相应的资料。

Man Sum总是很耐心的记录下所有的需求。他会说不能马上答复你,但是他总会给你一个说法。哪怕这件事情是多么的小,小到你已经忘记。

后来我有了Juha。Man Sum建议我多给孩子拍照。他自己也是个摄影爱好者,为了家里的狗狗拍了很多好看的照片。为了这些照片还制备了RAID等硬件。他是一个热爱生活的人,为了生活拼命的工作。

Man Sum帮我带了几次香港的奶粉,后来他跟我说杭州的海关都认识他了。有一次Juha生病,需要保婴丹,正好知道Man Sum第二天要来杭州,我就冒昧的在晚上打电话给他,他二话不说就出去买,回到家还电话我说运气好,在超市关门前一刻买到最后的两盒。我和小超都很感激他,一直说要吃一餐饭。可是就永远的错过了。要是能换Man Sum回来,哪怕一天,烧掉一个Justin Bieber我也不在乎的。

很多话到了指尖就是打不出来。我想,除了我一定会有别家公司的人在写纪念Man Sum的文字吧?我也在想,是Man Sum什么样的品格使他受到这么多人的尊敬呢?技术人员的路就是该像他这样踏实的走下去的。

这两天总想到Man Sum。总想着办公室的门打开,他清瘦的身影背着黑色的电脑包闪进来,总是这么希望。

李先生一路走好。