20121228

用邮件分割和传送大文件,python实现 III

用邮件分割和传送大文件,python实现 III

4. 接收端baoyu

4.1 导言和import

这部分,是从zhumao.py中抄过来的。

1 #! /usr/bin/python
2 # -*- coding: utf-8 -*-
3
4 # baoyu, 邮件接收者
5 __usage__ = "usage: %baoyu.py [--help]"
6 __version__ = "baoyu by Young 2012-12-21"
7
8 from optparse import OptionParser
9 import base64
10 import time
11 import sys
12 import poplib
13 import time
14 from email.Parser import Parser
15 from email.header import decode_header
16

4.2 helper函数们

这里是一些在后面的业务逻辑实现中要调用的一些函数。它们在此声明和定义,定义的方式一般应依据动机、目的,而不是根据实现手段。也就是说,使用的词汇应该是分析阶段的词汇。函数被从"后面的业务逻辑"中抽取到这里,可能因为被调用很多次,也可能只调用一次,但是在业务上具有较为鲜明的特征。如果调用很多次,抽取出来的原因之一就是重用,这样可以避免后续维护的时候一旦有修改需求,这个功能相关的很多地方都要修改;如果只调用一次,但是业务特征明显,就是为了信息隐藏,以后或别人读代码的时候要容易一些。

根据场合和组织方式的差异,这些函数有不同的称呼。在C++/java中,私有函数基本上实现了这样的功能;在flex/bison及我一时没想起来的很多领域中,它们被称为helper函数。

17 ######
18 # helpers
19 ######
20 def getheader(header_text, default="ascii"):
21 """Decode the specified header"""
22 try:
23 headers = decode_header(header_text)
24 header_sections = [unicode(text, charset or default)
25 for text, charset in headers]
26 return u"".join(header_sections)
27 except:
28 return u"".join("invalidated encode")
29

上面的代码是从某位貌似日本人的站点上抄来的,它的名字其实不应该叫做getheader,而是"根据charset解码"邮件头或正文。

30 def get_msg(which):
31 return "\n".join(server.top(which, 1)[1])

这是根据 which指定的邮件id号,从邮件服务器上取得对应的邮件,但是不删除。server.top()。详见手册[http://docs.python.org/2/library/poplib.html],"POP3.top(which,
howmuch)"。

33 def get_from(msg):
34 email = parser.parsestr(msg)
35 return email.get("From")

上述的 pserser 就是 第14行 "from email.Parser import Parser"
中的Parser的实例,在下面的第82行。手册[http://docs.python.org/2/library/email.parser.html]。这个parser是专门用来从邮件中析出邮件头部等各个部分的。

第35行,解析出From部分,也就是邮件发送者地址。baoyu.py根据这个来判断某封邮件符合"zhumao-baoyu"协议的发送者部分。

这个粗糙的协议包括:发送者、邮件主题、第几封邮件、共几封。其中,发送者和邮件主题作为下载和删除邮件的过滤条件。

37 def get_body(which):
38 msg = "\n".join(server.retr(which)[1])
39 email = parser.parsestr(msg)
40 return email.get("BODY_START")

与第33行开始的函数类似,get_body用于取得which指定的id对应的邮件的body。不同的是,get_body把这封邮件标记为已读。

此外,上文提到,我们为了解析方便,在body的开头标记了"BODY_START:",所以此处,body可以视为"BODY_START"部分的值。

42 def get_subject(msg):
43 return getheader(parser.parsestr(msg).get("Subject"))

还是与第33行开始的函数类似,取主题部分。

45 # e.g. [base64-2] 1/2
46 def get_cur_num(subject, subject_prefix):
47 start = subject.find(opt.subject_prefix)+len(opt.subject_prefix)
48 slash = subject.find('/', start)
49 return int(subject[start:slash])

51 def get_all_num(subject, subject_prefix):
52 start = subject.find(opt.subject_prefix)+len(opt.subject_prefix)
53 slash = subject.find('/', start)
54 return int(subject[slash+1:])

以上两个函数,是从邮件头里取得这是第几个包、一共几个包这两个数据,使用的方法是字符串处理,以"/"分割类似"[base64-2] 1/2"的邮件头部。

4.3 命令行解析

与发送端zhumao.py的命令行解析类似,解释从略。

57 #--------------------------------------------------------------------
58 # 命令行解析
59 p = OptionParser(usage=__usage__, version=__version__, description=__doc__)
60 p.add_option("-F", "--file", dest="filename",
61 help="file need to be saved", metavar="FILE",
62 default="test.out")
63 p.add_option("-P", "--pop", dest="pop",
64 help="pop3 server", metavar="POP3_SERVER",
65 default="pop3.nenu.edu.cn")
66 p.add_option("-u", "--user", dest="user",
67 help="user name", metavar="USER")
68 p.add_option("-p", "--password", dest="password",
69 help="password", metavar="PASSWORD")
70 p.add_option("-f", "--from", dest="fromaddr",
71 help="from whom to be filtered", metavar="FROM",
72 default='gift.young.1@gmail.com' )
73 p.add_option("-L", "--subject", dest="subject_prefix",
74 help="the prefix of mail subject as filter",
metavar="subject_prefix",
75 default='[zhumao_baoyu_mail]')
76
77 (opt, args) = p.parse_args()
78

4.4 准备连接邮件服务器

82 parser = Parser()
83 server = poplib.POP3(opt.pop)
84 server.user(opt.user)
85 server.pass_(opt.password)
86 server.set_debuglevel(0)
87 sleep = 0.1
88 count = server.stat()[0]
89 d = dict()

使用pop3接收,各种参数设置。

第88行,取得stat命令时的邮件数量,即未读邮件数量。

第89行,初始化一个字典 (映射)。后面准备把第1封邮件放到"1"的值里面,第2封邮件放到"2"的值里面,依此类推。这样,在拼邮件的时候,可以按key排序。

4.5 接收邮件

检查邮件,根据邮件头过滤,下载并删除符合要求的邮件,显示接收百分比。

从第90行到第107行,是一个循环,用于遍历所有邮件,并在第103行当查找到所有符合要求的邮件 (数量达到要求)以后跳出循环。

90 for i in xrange(1, count, 1):
91 current = get_msg(i)

调用helper函数 get_msg,取得id为i的邮件 (的邮件头和body第一行) 。

92 if (get_from(current).find(opt.fromaddr) != -1 and
93 get_subject(current).find(opt.subject_prefix) != -1):
94 b = get_body(i)

如果邮件的发送者符合要求 (比如 zhumao@nenu.edu.cn) ,并且主题的prefix也符合要求 (比如 [base64-2]),取整封邮件。

如果不过滤直接在遍历的时候取整封邮件,因为邮件数量众多,带附件的邮件又很大,性能会比较低。而仅遍历邮件头,对网络带宽就没有那么高的要求了。

95 print '+-------------------------'
96 print '|' + str(i)+' '+ get_subject(current)
97 # print '|' + b
98 print '+-------------------------'

显示进度,避免用户着急。

99 current_seq = get_cur_num(get_subject(current), opt.subject_prefix)
100 all_number = get_all_num(get_subject(current),
opt.subject_prefix)

调用helper函数,取得当前是这一文件的第几包邮件 和 一共几包邮件。一共几句邮件,数值在遍历中一直不会变,但是重复计算了很多次。

101 print (str(current_seq) +'/'+ str(all_number))

再显示进度,第几封,共几封。

102 d [current_seq] = b

把第N封邮件放到字典键N的位置。参见前面提到的第89行,这里是向字典中插入数据。

103 if len(d) >= all_number :
104 break
106 else:
107 print 'filtered out: '+str(i)+'/'+str(count)+'
'+get_subject(current)

如果把这个文件对应的所有邮件都已下载完毕,跳出循环;否则的话,也告诉用户一声,这封邮件不符合条件,不然出现大量不符合条件的邮件时,用户看到的是程序假死。

109 server.quit()

收完邮件,关闭连接,保持优雅。

4.6 合并文件

111 # 合并文件
112 s=""
113 for k in xrange(1, all_number+1, 1):
114 s += d[k]
115

接key的顺序遍历字典d,把对应的值拼接在一起。这个对应的值来自第102行的插入,此处是取出数据。字典d综上所述,在第89行初始化,在第102行插入数据,在第114行读取使用。如果不用字典,而使用一个链表,以下标代替key,也可以。

4.7 解码文件

我们拼接出来的文件是base64编码的,所以需要解码,然后写出。

116 # 解码文件
117 s = base64.standard_b64decode(s)
118
119 file = open (opt.filename, "w")
120 file.write(s)


5. 回顾数据流

发送端的数据流为: 文件binary -> 读入文件 -> base64编码 -> cut -> smtp.

接收端的数据流为:pop3 -> merge -> base64解码 -> 写出文件 -> 文件binary。

如果思想的传递,也能无误地这样传输,该有多好。

6. 进一步的工作

还有很多进一步的工作可以做,让这个协议及应用程序更好一些。比如,加错误检校,指定重传错误的包而不是全部重传,由baoyu访问zhumao的共享目录并指定下载某个文件,不使用SMTP/POP3而是通过论坛的贴子传递信息。

还可以在传送前加压缩 (不过对于视频和音频,没啥意义)。

还可以用这种隧道做成反向代理……

未来有无数种可能。可能这正是人生的迷人之处,如果今天就能看到明天及所有以后的日子,那还有什么希望可言。

完整代码在这里 [http://my.csdn.net/my/code/detail/33574] 和
[http://my.csdn.net/my/code/detail/33573].

--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

20121227

用邮件分割和传送大文件,python实现 II

用邮件分割和传送大文件,python实现 II

3. 软件的使用过程

下面这段,是软件写完以后运行的效果,不过,在软件开始写以前,它的样子就已经在我的心中。用个去年还是前年流行然后就消声匿迹的词来形容,软件在写第一行代码以前,就应该有个"愿景"。


以下,以发送191字节的 test.in
为例,分成3个包,每包100字节。从young@nenu.edu.cn发出,发给young@nenu.edu.cn。每包100字节是参数的默认值指定的。

3.1. 发送方zhumao

~/running/zhumao-baoyu-mail $ python zhumao.py -f young@nenu.edu.cn -t
young@nenu.edu.cn -L "[test-in]" -p "mypass***" -F test.in

To:young@nenu.edu.cn From: young@nenu.edu.cn Subject:[test-in] 1/3

sent.

To:young@nenu.edu.cn From: young@nenu.edu.cn Subject:[test-in] 2/3

sent.

To:young@nenu.edu.cn From: young@nenu.edu.cn Subject:[test-in] 3/3

sent.

3.2 接收方baoyu

~/running/zhumao-baoyu-mail $ python baoyu.py -u young@nenu.edu.cn -p
"mypass***" -L "[test-in]" -f young@nenu.edu.cn -F test.out
+------------------------- |1 [test-in] 3/3 +-------------------------
3/3 +------------------------- |2 [test-in] 2/3
+------------------------- 2/3 +------------------------- |3 [test-in]
1/3 +------------------------- 1/3

以上接收过程可以看到,一共3包,第3包的接收早于第2包,早于第1包。

用diff对比发送和接收到的文件,一致。

~/running/zhumao-baoyu-mail $ diff test.in test.out
~/running/zhumao-baoyu-mail $


3.3. 手册,帮助

$ python zhumao.py --help Usage: %zhumao.py [--help]

Options: --version show program's version number and exit -h, --help
show this help message and exit -F FILE, --file=FILE file need to be
sent -S SMTP_SERVER, --smtp=SMTP_SERVER smtp server -f FROM,
--from=FROM mail sender -p PASSWORD, --password=PASSWORD password -t
TO, --to=TO mail receiver -s SIZE, --size=SIZE size of each mail -L
subject_prefix, --subject=subject_prefix the prefix of mail subject

$ python baoyu.py --help Usage: %baoyu.py [--help]

Options: --version show program's version number and exit -h, --help
show this help message and exit -F FILE, --file=FILE file need to be
saved -P POP3_SERVER, --pop=POP3_SERVER pop3 server -u USER,
--user=USER user name -p PASSWORD, --password=PASSWORD password -f
FROM, --from=FROM from whom to be filtered -L subject_prefix,
--subject=subject_prefix the prefix of mail subject as filter

4. 发送方zhumao

以下是发送方zhumao.py的代码及讨论。希望能为像我一样的初学者带来启发的同时,渴望熟悉python什么的大牛们指导和批评我代码的各种错误,一方面我求进步,另一方面也免得我误导别人。谢谢啦。

这两天又访问不了github了,所以暂时没传上去。各位将就着看吧。

不连续的行号,是空行,我解释的时候略过了。

4.1 基本相当于导言

1 #! /usr/bin/python 2 # -*- coding: utf-8 -*- 3 4 # zhumao,邮件发送者

第1行,注释,指定脚本解释器。这和shell程序设计是一个路子。

第2行,注释,文件编码。祖国尚未统一世界,看来各种编码的乱像还会继续相当长时间。

5 __usage__ = "usage: %zhumao.py [--help]" 6 __version__ = "zhumao by
Young 2012-12-21"

我照抄的,看效果是显示使用方法。这个实现有意思,方便程序员与用户沟通啊。增加一点方便,估计就多几个百分比的程序员实现这一功能。

8 from optparse import OptionParser 9 import smtplib 10 import base64
11 import time 12 import sys

我猜就是 C里的include,猜的。还有名字空间、模块这样的作用。from的作用,似乎是使得模块中的符号名在当前作用域可见。这些模块是后面的代码要用到的。

4.2 命令行解析

这里使用了

8 from optparse import OptionParser

中指定的模块,第15行中的p是个OptionParser实例。在第16行以后,调用实例的方法
p.add_option。这些参数,基本可以根据出现的顺序、内容,与上述"愿景"对比,猜出来含义。不赘述。

14 # 命令行解析15 p = OptionParser(usage=__usage__, version=__version__,
description=__doc__) 16 p.add_option("-F", "--file", dest="filename",
17 help="file need to be sent", metavar="FILE", default="test.in") 18
p.add_option("-S", "--smtp", dest="smtp", 19 help="smtp server",
metavar="SMTP_SERVER", default="smtp.nenu.edu.cn") 20 # help="smtp
server", metavar="SMTP_SERVER", default="smtp.gmail.com") 21
p.add_option("-f", "--from", dest="fromaddr", 22 help="mail sender",
metavar="FROM") 23 p.add_option("-p", "--password", dest="password",
24 help="password", metavar="PASSWORD") 25 p.add_option("-t", "--to",
dest="to", 26 help="mail receiver", metavar="TO") 27
p.add_option("-s", "--size", dest="size", 28 help="size of each mail",
metavar="SIZE", default=100) 29 p.add_option("-L", "--subject",
dest="subject_prefix", 30 help="the prefix of mail subject",
metavar="subject_prefix", default='[zhumao_baoyu_mail]') 31 32 (opt,
args) = p.parse_args()

到这里为止,命令行参数 (及其默认值)就已经成为p的成员了。后面这样引用,比如: opt.smtp。

第32行,这个返回值对C程序员来说,看起来有点奇特。手册[http://docs.python.org/2/library/optparse.html]说

"parse_args() returns two values:

options, an object containing values for all of your options—e.g. if
--file takes a single string argument, then options.file will be the
filename supplied by the user, or None if the user did not supply that
option args, the list of positional arguments leftover after parsing
options"

4.3 输入文件

34 # 输入文件35 file = open (opt.filename, "r") 36 s = file.read()

第35行,opt.filename是从命令行中解析出来的,在我们的"愿景"中,就是test.in。open,
read,这样的写法,容易望文生义,而且似乎也对,不赘述。执行完这段以后,文件的内容全在s中了。

4.4 编码文件

38 # 编码文件39 s = base64.standard_b64encode(s) 40 41 ## sys.stdout.write(s)

第39行,使用了 base64编码 字符串s,编码的结果再赋值给s。第41行是我写程序的时候用来输出测试的。

4.5 准备发送,登录

43 # 准备发送,登录44 sleep = 1 45 to = opt.to 46 user = opt.fromaddr 47 pwd
= opt.password 48 smtp = opt.smtp

第44行,准备每发送一包睡一秒。根据你用的SMTP服务器对你的坏人判断有多严格,你可以调整sleep的值。

从第45行至第48行,从命令行解析的结果中得到 发给谁、发送者、SMTP发送者的口令、SMTP服务器地址。

49 smtpserver = smtplib.SMTP(smtp) 50 # smtpserver =
smtplib.SMTP(smtp, 587) # for gmail 51 smtpserver.ehlo() 52
smtpserver.starttls() 53 smtpserver.ehlo 54 smtpserver.login(user,
pwd)

第49行使用smtplib,构造出smtpserver实例。如果用的是gmail,端口需要指定为587。

从第51行到第54行,根据你选的smtp服务器的要求决定对它说些啥。我的smtp服务器要求先
扩展的hello,然后tls架密,然后再问候一次,然后登录。如果不知道应该说些啥,可以用thunderbird登录一次,用sniffer看一下正确的步骤。

4.6 拆分-标记-发送

麻烦的地方到了。

4.6.1 拆成

56 # 折分文件57 end = len(s) 58 for i in xrange(0, end, opt.size): 59 if
i+opt.size < end : 60 current = s[i:i+opt.size] 61 else: 62 current =
s[i:]

python的for循环语法,我老是忘。希望这回能记住。

"for 变量 in 待遍历的东西 : "。

这里,待遍历的东西是一个数据范围,用xrange生成,从0开始,到end结束,步进为 opt.size。

在循环体中--这也是python有意思的一个地方,缩进是语法要求,而不仅是为了美观--如果没有到最后一包,当前的这包就是字符串切割出来的。s[i:i+opt.size]表示切割s,从
i 切到 i+opt.size;如果不是最后一包,从i切到结尾,写作 s[i:]。

python切割字符串的方法,还真是有C的风格,把字符串当成纯粹的容器/数组看待。

4.6.2 标记

还在循环里。

63 # 标记64 subject = opt.subject_prefix + ' '
+str(i/opt.size+1)+'/'+str(end/opt.size+1) 65 header = 'To:' + to +
'\n' + 'From: ' + user + '\n' + 'Subject:' + subject +' \n' 66 current
= 'BODY_START:' + current + '\n' + 'BODY_END:NOTHINGGOESHERE' 67 print
68 print header

第64行,生成主题subject,第65行,生成邮件头header,第66行,生成正文。第67和第68行,不是为了调试,而是为了避免用户在长时间切割的时候不知道跑了多远,还剩多远。

这里输出的东西就是下面这段:

To:young@nenu.edu.cn From: young@nenu.edu.cn Subject:[test-in] 2/3

sent.

其中,主题里的 [test-in]
是加的标记,包师弟接收的时候可以用这个标记过滤出我们特别的邮件。太阳底下无新鲜事,大毅同学提到在cisco设备中,vlan/trunk也使用了类似的方法做标记tag。后面的2/3表示共3包,这是第2包,用来在baoyu接收端拼接文件的时候作为顺序的依据,也用来显示出来,避免包师弟了解下载了多少,还有多少没下载。

4.6.3 发送

还在循环里。

69 #发送70 msg = header + current 71 smtpserver.sendmail(user, to, msg)
72 print 'sent.' 73 time.sleep(sleep) 74 75 smtpserver.close()

第70行,把邮件头和邮件正文拼在一起。这看起来是很天真的做法,邮件头和正文就这么就拼一起了啊?是的,是SMTP还是什么协议,就是这么规定的。好像head和body中间还有个回车。

第71行,发送出去了。

第72行,避免用户心急,程序把邮件发出去了要告诉用户一声。

第73行,前面提到了,睡一下,避免SMTP服务器认为我们是发送垃圾邮件的坏人。

第75行,离开循环,邮件都发送完了,断开连接。做事要有始有终,保持优雅。

明天,或者后天,讨论一下接收端baoyu.py。

--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

20121225

两张图片:Visual Studio DSL工具特定领域开发指南 笔记

两张图片:Visual Studio DSL工具特定领域开发指南 笔记

精读了《Visual Studio DSL工具特定领域开发指南》,写了笔记,画了图。拖
了几天,估计还是没时间整理笔记。

以下两张图片,权当笔记了吧。


--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

耳机收纳制作

耳机收纳制作

没有耳机听电话的时候耳机疼,有耳机呢,耳机线老是卷在一起。所以我用麦当劳的优惠卡做了一个耳机收纳,把线缠上面。用了几天,效果不错。

我得意地掏出DIY的耳机收纳,鞠孙谷三位同学说,"你网上买的啊。"我说,"不是啊,我做的。"又问,"你了网上以后做的啊"。我说,"不是,独立创造的。"

我又得意地掏出DIY的耳机收纳,关郑两位同学说,"你网上买的啊。"我说,"不是啊。为什么你们也这么说。"他俩说,"因为网上有卖的,而且巨便宜,种类也多。"

我搜了下,真是不少,做成各种可爱卡通的。买了几种试用,都不咋地。重要原因是,它们都太小,耳机线缠很多圈,打开的时候费劲。不过,它们提供了很好的设计方案,比如都有个小孔,耳机线进去容易出来难。所以,我就照些改良了我原来的设计。

变成这样。

所用工具如图所示。

缠上以后的效果。

对比的产品。

--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

用邮件分割和传送大文件,python实现 I

用邮件分割和传送大文件,python实现 I

1. 限制和解决方案

经常有人替我国导演和科幻作者们叫屈,说这样的环境怎么能出好作品呢;也经常有人为自己叫屈,类似他有这样的父母环境怎么能成才呢。不过,我看过一个故事,说法略有不同,名字忘了,应该还是个名篇。

故事里说,有个家伙因为被抢劫,捆得很结实,而又刚刚好能动弹一点,能一跳一跳地走。他被救以后,发现能演小丑什么的,留在马戏团工作。因为绳子约束,力量更大,而且能做很多原来完不成的动作。最后,老板想杀他放出狼来,他做好准备放手一搏,觉得胜券在握。老板娘一刀把他身上的绳子割了,喊"那谁,你快跑啊。"然后就没有然后了。这哥们离了绳子啥也不是,后来是不是被狼咬死,我就忘了。

这个故事告诉我,限制从来不一定是致命的阻碍,有时更可能是个磨砺人的挑战。

包师弟和ZHUMAO聊,说到某单位的网络真是不咋地,下载居然要收费,不过有个漏洞。包师弟说,这个漏洞就是下载邮件的流量不算钱。

这倒是也合理,不然就往网络中心或领导的信箱里成天发大附件就行了。同时,从原理上也说得过去,SMTH的时候,不是我乐意的,相当于接听电话不收费;而POP3的时候,已经是内网了。

ZHUMAO说,这个漏洞可用。他提到,先把大文件切成几份,然后用邮件发给包师递,包师弟根据一定条件收邮件,然后拼起来。

我说:你们应该用PYTHON整。ZHUMAO说:对,你整吧。

于是我就整了。没有写容错部分,一共197行,拿出来讨论一下。

2. 整体框架

整个软件分成两部分,是两个.py文件。一个是发送文件用的,名字叫 zhumao.py,另一个是收文件用的,名字叫 baoyu.py。

2.1 zhumao.py

发文件的zhumao要顺序执行这样一些操作:

* 编码文件

用base64或可打印字符,因为邮件是ASCII文本的,而大部分二进制文件都有ASCII控制字符,比如电影。之所以编码,另一个原因是我不想使用附件,实现的时候更麻烦一些,以后也可以改成用附件。

* 拆分文件

把文件拆成定长的几段,比如10K一段,然后再发送。最后一段可能稍微短一些。

* 标记及百分比,发送

在邮件的subject上做标记,比如 [来自zhumao,好片子] 这样包师弟接收的时候过滤邮件更容易一些。

然后找个SMTH邮件服务器发出去。

* 避免被服务器视为垃圾邮件发送者

邮件服务器可能会因为你一直发一直发认为你是恶意的,所以发一会要 sleep一会儿。对软件性能的影响,就是没有办法的事了。

2.2 baoyu.py

收文件这一端,要执行相反的操作,即顺序执行:

* 检查

用POP3检查所有的邮件头。

* 根据标记过滤,下载并删除

把符合条件的邮件,比如 [来自zhumao,好片子],下载下来,从服务器端删除。在这里,以后应该支持错误检校,出错重传。现在还没有支持,作为原型,就算对付吧,如果1G文件中间有一个坏的,就得重传全部。

* 合并文件

把文件从邮件body中析出来,然后拼成编码的文件。有些邮件服务器会在subject 之后加上乱糟的东西,比如 anti-spam
之类的,这破坏了一个通常的假设,即subject之后一行以后全是正文。这导致析出文件稍微麻烦一些。我为了实现简单,在body的最前面加了标记,后面也加了标记。反正邮件不是用人手,而是用zhumao.py发出的,所以这一部分可以视为
zhumao-baoyu 协议。

* 解码文件

把ascii文件解码为binary。

* 接收百分比

还要显示接收了多少。同时,因为邮件到达顺序可能与发送的不同,所以zhumao.py在发送的时候还在 subject 中还加入了共几包,当前这封邮件是第几包。

2.3 实现

列出上述框架以后,我先写zhumao.py,用 thunderbird 和 gmail 检验发送的内容;然后再写
baoyu.py,此时用已经实现的zhumao.py发送测试用例。因为我不熟悉python,很多语法和底层的机制 (如分割字符串)
,都是一边写一边查的。估计有更优雅的实现方案,不过那就不是我这样的初学者能提供的了。

所以,大牛们读到此处,已经可以评判 zhumao-baoyu 方案了。初学者们请明天再来,我们继续一起学习吧。

此外,这个zhumao-baoyu草稿在计算机网络中也可以视为 smtp-pop3 协议基础上实现的文件传递协议,还可以扩展更多的功能,比如
baoyu 要求列出 zhumao端 提供的文件目录,选择文件下载。在协议之上建立新的协议,VPN中的l2tp、WAN口连接使用的
PPPoE,都与此类似,称为隧道协议。

在隧道协议中,表面上我们谈论的是一件事情,而实际上,我们真正想传递的,往往另有深意。就像年终岁尾,大家喝酒的时候,逼你喝酒的那些人,他表达的是:"你应该表达臣服于我,低个头啥的。"请脑补雄性大猩猩拍胸脯的动作。

突然想起来北京土著喜欢自称为"爷"的习惯,还有四川土著喜欢口头对别人的"婆娘"不敬这两件事,他们可能还会解释为"啊呀,我就是习惯了,没有恶意。"明知对方的感受,不郑重道歉的就是恶意。坏习惯是病,如果能改就改,如果不能改,就得治。我对四川同学说过,你说别人的媳妇啥都行,对我得例外。期待机会哪天对哪位北京同学喊一嗓子,你TM是谁的爷。

终于还是跑题了。

--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

20121217

Linux shell脚本,Linux下的西红柿时间管理法 IV

Linux shell脚本,Linux下的西红柿时间管理法 IV

续 清理

本来以为三次就写完了,用了几天这两个脚本,发现了一点问题,所以还得再说
两句。希望这次就真的结束了。

我习惯不用计算机的时候,扣上盖,然后机器休眠。这个习惯与上述西红柿时间
管理结合在一起产生了一个问题:at任务还在继续,再唤醒机器的时候,时间管
理还在继续,可能正进行到第5分钟,也可能是第12分钟,而我希望重新计时。

重新计时也很简单,再执行个20.sh就行了。这么做带来的问题是,这个新的时间
管理起始点建立了,旧的却没有清除掉,所以可能过不了几分钟,旧的休息时间
就到了。

清除掉旧的任务也容易。比如执行 atq 显示当前的任务为:

~ $ 20.sh
~ $ atq
3890 Mon Dec 17 21:31:00 2012 r young
3891 Mon Dec 17 21:32:00 2012 r young

3890和3891就是当前的两个任务。清除的命令是:

~ $ atrm 3890; atrm 3891
~ $ atq
~ $

任务果然清理干净了。

但是每一次都要atq,然后去读那两个任务号,然后再atrm,挺麻烦的。所以,有
了下述脚本,用于清理旧的时间管理任务。

代码如下:

1 #!/bin/bash
2
3 task=$(atq -q r | cut -f1 )
4 if [ -z "$task" ]; then
5 echo "No task in queue r."
6 exit 0
7 fi
8
9 for t in $task
10 do
11 atrm $t
12 done

第3行,用atq显示任务列表,然后管道给cut,得到第1列,也就是任务号,看起
来的效果就是:

3890
3891

这些数据赋值给了变量 task。

第9行,遍历数组task,对于其中的每个变量 t ,应用atrm操作,相当于:

atrm 3890
atrm 3891

这样,每当我开机的时候,不必再atq看是否有任务,然后再记住任务号什么的,
只要执行 clear_at.sh,旧的任务就清理掉了。

既往不咎,一切重新开始。

--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

20121209

那些年,我们一起喜欢的诺基亚

那些年,我们一起喜欢的诺基亚

我的手机旧得不行了,只好换了个新的。旧的不行的意思,如同现在的小青年所说的,并非拿起来就散架,而仅指"感觉"不那么好了。每天都要充电,下午的时候就会耗干净自动关机,打开通讯录会停在那里几分钟……诸如此类。

这个淘汰掉的手机,买的时候也2000多元,现在不用,甚是心疼。当初买的时候是奔诺基亚去的,立场不坚定,临时决定换成了MOTO,windows操作系统的。于是,两年多来,我经常要对别人说"这不是黑莓,这只是长得像黑莓的摩托罗拉。"

此前,我的手机是诺基亚1110那种直的,小手机。再之前……时光如流水,令人感叹。

我的第一个手机是大学四年级的时候买的。当时在外面打工,我有个BP机,经常会收到"短信"之类的,那都是上帝发来的,表示有活了。然后我要跑到电话亭--有人值守的,和美国电影里的不一样,交上5角钱,把电话打回去。我买手机的主要原因,是电话亭上全写着大字"肆角",但是值守的人总是要收伍角钱。更早的时候,上面的玻璃上写的是"叁角",你猜对了,值守的人一定要收肆角。

我对每次要跟人讨论再被拒绝非常愤怒和疲惫,于是买了一个手机。当时我想的是,反正每个电话5角,到哪里打都是。后来二猫妈提醒我,电话亭是每三分钟5角,手机是每分钟5角,而我的每个电话通常不止一分钟。不过手机当时早就买完了,我只好感叹我的算术有多么的差。

第一个手机是Panasonic的,黑的,有现在两个手机那个厚,纯英文的。纯英文没有造成任何干扰,因为当时没有人给我发短信。倒是Panasonic这个名字,每当我提起来,就有人说,"不就是松下么。"确实就是。不过我用英文不是特意显摆,而是在那手机之前,我对日本的这些公司还分不太清,天天见到手机上写的这个词,就记住了。

后来,还用过一个摩托罗拉的,当时它还没有萌到改名叫MOTO。紫色的,形状像个猪腰子。我记得本来是二猫妈的,女式的。后来联想庆祝飞船上天征文接龙,评委说书人给了我一次一等奖,奖品是个鲜红的联想掀盖手机。联想手机给了二猫妈,换下来猪腰子归我用了不少时间,直到换成诺基亚1110那种。那个联想手机为我对国产品牌的见解积累了一些素材,彩屏的,但是除了彩色,别的跟黑白手机没有任何两样。

那时候,联想好像还不叫Lenovo,就叫联想。中央电视台的广告里,一双手推开两扇窗,外面是蓝天白云,低沉而洪亮的男中音说,"人类失去联想,世界将会怎样。"最终,人类失去了联想,世界也没有怎么样,还是那样。而且,让人类失去联想的,正是Lenovo自己。

我拿着非智能黑白的手机去的芬兰。某次,师姐向我显摆她的智能彩屏手机。她说,她的手机能听歌,我说我有MP3;她说,她的手机能拍照,我说我总随身带个相机;她说,她的手机能看电子书,我说那太对眼儿了,累挺;她说,没事的时候还能打个游戏呢,我说,哪有没事的时候啊。

我当时还不知道诺基亚能砸核桃,不然真应该拿出来跟智能彩屏手机比较一下。

最终,为了能用网络,能gtalk,我换成了MOTO。当google离开中国的时候,我消沉抑郁了挺长时间。后来,gtalk经常联不上,我就成天开着软件,它自动尝试登录,失败,再尝试登录,再失败,再尝试。大部分GPRS流量,都这样消耗掉了。能连上GTALK的朋友几乎看不到我说话,只是大部分时间掉线,偶尔上来下去的折腾。他们告诉我还有QQ和飞信微信这些方式,但是那些都不是我换成MOTO的原因。

我守着MOTO,一共用了两块电池,直到每天充电,通讯录也打不开了。后来,它放弃了我。

最近,我买了诺基亚X2。不错的手机,只是GTALK的时候必须就只GTALK,别的什么也不能干。它不支持多进程。GOOGLE日历也不能用。

还是最近,我又买了诺基亚E71。不错的手机。GTALK能用了。GOOGLE日历还不能用。随机配了张光盘,里面有个软件叫做PC套件。网上大家都说,装个PC套件就好了,可以把手机日历与OUTLOOK同步,然后OUTLOOK与GOOGLE日历同步。

可是,PC套件安装失败,因为证书过期。我刚买的手机,光盘里的软件证书就过期了。网站很难连接,连接了说不对本地区提供下载。有人说,是因为诺基亚重组改生产线什么的。我知道,就是因为Symbian不再能创造价值,被退休了,不再有经费维护。

这些年来,诺基亚陪伴过我们大家,跟我们一起度过这样的一个时代,喧嚣而迅速。但是它最终的命运不过如此。我们把所有的东西都抛在身后,包括我们自己,努力狂奔。我们还要大叫,"我就是这样的。"好像如果不抛掉自己就不再是自己了。

我见到过朋友们换了很多手机,换了电话号码。其中有一些逐渐失去了我的消息,直到他们需要我的那一天。而我,永远失去了其中一些人的消息。每一次换手机或者电话号码,我都群发短信,我相当长时间保留着旧电话号,并让它开机。电话号码,不仅是当你需要别人的时候,更重要的,是别人需要你的时候,它能有效。我一直保持着24小时开机的习惯,我一直在这里。

我见到IT公司们风起云涌,爆炸一样眩目,然后又消失在人们的视线里。我见到各种技术出现和衰落,有人预言在将来的多少年里它会流行得一踏糊涂。请各位根据自己的人生经历自行脑补以上这两段的实现。渐渐的,我不再关注现在,只关注过去和未来。现在如此短暂,实在不值得为此刻的任何欢愉浪费哪怕一个小时的时间。

冬夜越来越长。雪还是下个没完,长春已经不再关注清雪了,反正明天还是要下。路上积了厚厚的一层,黑的白的灰的。路灯下,清洁工人穿得像一群桔红色的熊,伸直胳臂向四下里撒溶雪盐。公路会在几天后融化出灰黑色的路面,人行的路正变成越来越大的雪堆。

这样的冬夜里,我想起小学骑车路过的水泥厂旁边的河和路。那里的雪是一层一层的,一层白,是雪,一层黑,是水泥厂的灰尘。骑车通过的时候,冬天要格外小心,因为路上的冰上全是汽车的车辙。得完全按车辙骑,一不小心骑歪了,就会摔倒。

夏天回通化的时候,我看到那条路已经修得我完全认不出来了,平整宽阔,旁边的水泥厂拆了,立在那儿的是个不错的小区。真是很好,只是我没有与它一起生活的这段时间,它变得令我如此陌生。

很多这样的东西都会弃我们而去,除了冬天这样的小路,除了我的MOTO,还有黑岛游戏小组,还有westwood,还有那些年我们喜欢过的诺基亚。

说起黑岛,起初它并不是游戏小组的名字,而是《丁丁历险记》里的一册。Star Trek
里的库克船长,最初可能是那位真的船长,在凡尔纳的《机器岛》里提到过,他被东南亚或澳大利亚的土著杀了,可能还吃了。不过,他们以另一种方式活了下来。黑岛、库克船长,喜欢它们的那些人长大,变成牛人,然后把它们以另一种形式复活,在自己的作品中生活下去。

《那些花儿》里唱,"她们都老了吧,她们在哪里呀"。她们也许在世界的哪个积满灰尘的角落里哭呢,也许早就死去了。但是,我真的希望,读着这一篇博客的某一位,也许你将来发达了。到那时,请不要忘记陪伴过你的诺基亚。请……把它买下来,请让它的名字在另一种产品中复活,让又一代人会喜欢它。

也许,单纯地为了能让那些我们喜欢的继续或重新陪伴我们,我们不得不努力,既使这努力令我们如此痛苦。


又及。昨天读孟子那段著名的话,"君视臣如草芥,臣视君如寇仇。"原来还有一段在后面。王问,"听说有臣下在离职以后君主死了,臣下还为君主服孝的,这怎么整的啊。"孟子说:"君主在臣下离职以后三年,还给他留着房子;臣下要去哪,送到国境,还派人把臣要去的新地方打探安排好。这样的君主,臣下自然会服孝。像那种人走灯灭,刚说要辞职就收回房子的,还指望臣下服孝呐?"

--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

20121129

Linux shell脚本,Linux下的西红柿时间管理法 III

Linux shell脚本,Linux下的西红柿时间管理法 III

8. 需要的支持技术

我们说到希望从atq指令的输出中,自动计算出还剩多长时间休息,而不是靠用户自己计算。atq的输出是这样的:

1 3444 Tue Nov 27 18:47:00 2012 r young
2 3445 Tue Nov 27 18:48:00 2012 r young

第1行是提醒的任务,第2行是锁屏的任务。这里已经包含了执行任务的时间,即Tue Nov 27 18:47:00
2012,我们要做的是把这段数据抽出来,跟当前时间做减法。

单纯这么一说,似乎任务很简单,但事实要更复杂一些,一会儿你会看到。在看到任务的时候就确定有哪些支持技术,是非常困难的。难到就像,你还没有迈出第一步,就确定以后的路上会遇到哪些大河要跨过,哪些高山要翻越。不知道以后会有什么困难就无从准备,而那些没有做好准备就遇到的困难,正是扼杀成功的原因。怎么办呢?无他,或者,如果我们有经验,走过一次,那就已经知道了;又或者,有个向导带着我们走,他已经走过一次;又或者,干脆现在走一次,然后就知道了。

在没走之前先猜测一下会怎么样,在走的每一步记录,这正是工程师的基本素养:估算和度量。

9. 探索的过程

我们准备写一个shell脚本,运行的时候显示出当前时刻距离atq中的第二行任务还剩多长时间

9.1 解析数据

要从

1 3444 Tue Nov 27 18:47:00 2012 r young
2 3445 Tue Nov 27 18:48:00 2012 r young

中把"Tue Nov 27 18:48:00
2012"单独取出来,是按约定的语法或格式处理字符串,在编译原理里叫作做解析。解析简单的数据的手段很多,比如sed,比如cut。

我这样实现的:
atq -q r | cut -f2 | cut -d' ' -f 1,2,3,4,5 | sort | sed -n 2p

这是由一组管理连起来的进程组成。"|"就是管道,表示前一个进程的输出作为后一个进程的输入。我们一步一步看。这些进程,包括cut,sort,sed,都是字符串处理常用工具,具体的用法和参数我也记不住,常要看手册或者google。

第一步,atq -q r,表示只列出队列r中的任务。执行效果是:

~ $ atq -q r
3502 Thu Nov 29 19:33:00 2012 r young
3503 Thu Nov 29 19:34:00 2012 r young

第二步,cut -f2,表示取出第二个字段。效果相当于下面这两行:

~ $ atq -q r | cut -f2
Thu Nov 29 19:33:00 2012 r young
Thu Nov 29 19:34:00 2012 r young

只去除了3501和3502两个序号。不要小巧这点工作,这是一个很好的开始,并且表明我们能够操作字符串了。

第三步,cut -d' ' -f
1,2,3,4,5,表示取第1、2、3、4、5字段,并且以空格作为分隔符划分字段,效果如下,切掉了后面的队列名和用户名,离目标更近了:

~ $ atq -q r | cut -f2 | cut -d' ' -f 1,2,3,4,5
Thu Nov 29 19:33:00 2012
Thu Nov 29 19:34:00 2012

第四步,sort,排序,默认是由小到大,效果如下:

~ $ atq -q r | cut -f2 | cut -d' ' -f 1,2,3,4,5 | sort
Thu Nov 29 19:33:00 2012
Thu Nov 29 19:34:00 2012

这是为了下一步有确定的输入,以便挑出正确那行。

第五步,sed -n 2p,选择输出第二行,效果如下:

~ $ atq -q r | cut -f2 | cut -d' ' -f 1,2,3,4,5 | sort | sed -n 2p
Thu Nov 29 19:34:00 2012

小结,我们由atq输出的任务

3502 Thu Nov 29 19:33:00 2012 r young
3503 Thu Nov 29 19:34:00 2012 r young

得到了将会锁屏的时间:

Thu Nov 29 19:34:00 2012

这一时间,将用于下一步的做差计算。慢着,任务的时间和当前时间做差,当前时间是什么?

当前时间可以用date获得,效果如下:

~ $ date
Thu Nov 29 19:18:20 2012

9.2 计算时间差

求时间点 Thu Nov 29 19:18:20 2012 和时间点 Thu Nov 29 19:34:00 2012
的差,当然不能把它们直接相减了事。有的同学可能想到了,可以按上面的方法解析出日期、小时、分钟、秒,然后再做减法。这也能解决,不过由于时间相减是个工程中可以想见的常用的功能,所以,应该有现成的解决方案。这也是个原则,凡是常用的功能,一定有常用的方案或者函数。至于什么是"常用的"功能,你常做小项目,就会知道。

去做,就会明白。就像,怎么成为好人,你希望别人如何对你,别人如何做你会感动,按照那个要求去做,那就是好人了,至少会被别人评价为"好人"。

时间相减这个功能的常用方案,我这样实现:

1 task=$(date -d "$task" +%s)
2 now=$(date -d "$(date)" +%s)
3 diff=$(($task-$now))

第一行中,执行了一个指令"date -d <什么东西>
+%s",这代表把<什么东西>里的时间转化为自1970年1月1日起到<什么东西>这个时间,相差了多少秒。为什么是1970年1月1日而不是1949年呢,因为大家可能还记得C语言和UNIX操作系统诞生于1969-1970年。那个<什么东西>就是"Thu
Nov 29 19:18:20 2012"这样的东西。

执行效果是这样的:

~$ date -d "Thu Nov 29 19:18:20 2012" +%s
1354187900

到底多少秒,我们也并不需要关心,一会儿能用来求差就行了。

"task=$(date -d "$task" +%s)"中代替了<什么东西>的,不是固定的时间,像"Thu Nov 29 19:18:20
2012",而是"$task",它表示一个变量,名字叫做task。这个task是这么来的:

task=$(atq -q r | cut -f2 | cut -d' ' -f 1,2,3,4,5 | sort | sed -n 2p
)

这就像在上面三行代码里,也有个变量赋值给task:

task=$(date -d "$task" +%s)

在等号右边的task的值是"Thu Nov 29 19:18:20 2012",在等号左边的task的值是上面的那个秒数 1354187900。

第2行为now赋值为"此刻"date的秒数。
2 now=$(date -d "$(date)" +%s)

第3行求差得到diff,锁屏时刻的秒数 (距1970年元旦 )和此刻的秒数 (距1970
年元量) 的差:

3 diff=$(($task-$now))

这样,我们就得到了,还有多少秒到锁屏时间,虽不够友好,但是离目标又近了一步。

9.3 格式调整

我不希望这样的结果,还剩778秒到休息锁屏时间,虽然这和12分钟58秒没什么本质区别。我希望它这样提示 12:58。

9.3.1 换算

这个好办,对60做除法,商就是分钟数,余数就是秒数。既然这么显然,那shell一定提供了这样的支持技术,果然一goolge就有。其实上面这些,有不少我忘记了或者记不清的,我也都去google了。关键在于,你得知道那东西存在,才能google。

这里[http://www.computing.net/answers/unix/remainder-operator/6820.html]有一段

: Use the % operator. Check below
: --
: 1. expr 5 / 2 gives 2 as Quotient.
: 2. expr 5 % 2 gives 1 as Remainder.

所以,我这样实现:

minute=$((diff/60))
sec=$((diff%60))

又是变量赋值。

9.3.2 条件判断

但是,还有些别的可能,比如只剩下12分5秒的时候,我不希望显示成

还剩12:5

而是希望得到:

还剩12:05

这需要条件判断。查到shell中的条件判断的语法:

if [cond]; then
fi

当然,前提还是,你得确信知道条件判断这种东西是存在的。

我这样实现:

1 if [ "$sec" -lt "10" ]; then
2 sec=0$sec
3 else
4 sec=$sec
5 fi

9.3.3 连接字符串

上面的代码中,第2行中的"0$sec",把常量字符串与变量相连接,就是直接接起来写,这个我也试了一下,如下:

$ a='hello'
$ b='world'
$ c=$a$b
$ echo $c
helloworld

9.3.4 判断空行

还有另一个可能。如果还有不到一分钟就休息了,atq的输出将只有一行,因为提醒音的那个任务已经执行完了。

我们需要判断输出有几行,或者说,我们需要判断空行。goolge得到:

[http://stackoverflow.com/questions/3061036/how-to-find-variable-is-empty-or-in-shell-script]

: In bash at least: if [[ -z "$var" ]]
:
: the command line "man test" is your friend.

最后一行对应的UNIX谚语是:男人是最好的,原文 "man is the
best"。这里的man,不是男人,而是manual的缩写,unix下的一个指令
man,用来查手册的。尽管大家都心知肚名man不是男人的意思,还是有不少unix/linux发行版中的man指令有个等同的指令,名字叫做woman。恩,而且woman和man不仅平等,而且完全一样。

我这样判断空行:

1 if [ -z "$task" ]; then
2 echo "No more than 1 minute left to have a break."
3 exit 0
4 fi

10 bug修正和功能增加

人生总是只有开始,才知道原来后面有这么多苦难;程序总是开跑才发现,原来总有bug存在。王子和公主从此以后过上无忧无虑的幸福生活,这种事只有在童话里才有。

没啥,逢山开路,遇水搭桥,碰到bug就杀掉。

10.1 排序

atq输出的时候,输出我也不知道是怎么个顺序,所以有了上面的sort指令。最初的版本中是没有的。

10.2 只加入指定的队列

虽然还没有出现这样的情况,但是在其他的时候,或者其他的程序,可能也要使用at任务的队列。所以,我改成只选其中一个队列使用。

atq -q r,只显示队列r中的任务。

at ... -q r,向队列r中添加任务。


11. 秘密

表面上看,上面是演示如何实现西红柿时间管理。没错,西红柿时间管理确实很有效,我常用。但是,正如钢琴老师教你弹的那些小曲子也确实挺好听的,但是她教你弹曲子的目的绝对不仅是欣赏这些曲子本身,而是更注重练习曲目时所得到的能力提升。这个小项目也是一样。

以上这些步骤看起来很流畅,先这样,再那样,然后又如何,最后问题解决了。等到你实践的时候可能略有不同。这种差异的来源是因为:我其实不是盲目地探索的,因为学习过其他的语言、做过其他的小项目,所以能够猜到应该有这样的那样的解决方案存在,所以我是有意去寻找每一步的技术和有计划地逼近终点的。换句话说,我经常地猜到了那里应该有这样的技术存在,然后才去google。而google并不能告诉你你不知道的东西。

如同《怎样解题:数学思维的新方法》[http://book.douban.com/subject/2124114/]这本书所说的,教师解题的过程,并不是盲目的,而是假设或计划将会如何,然后朝着那个方向推理和努力。我们作为学生需要体会的,是在观摩教师解题过程中的那些节点和方向。然后可能还要思考,他是怎么知道到这里就会有这个技术了呢?就像故事里讲的,孩子问雕塑师,你先前怎么知道石头里有个女人的呢。

--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

20121127

Linux shell脚本,Linux下的西红柿时间管理法 II

Linux shell脚本,Linux下的西红柿时间管理法 II

4. 架框及已有的技术

我原来的代码非常简单,里面包含了大致的框架和已经利用的技术,如下。

1 #!/bin/bash
2 at now + 20 minutes 2>/dev/null <<EOF
3 aplay -q /usr/lib/openoffice/basis3.2/share/gallery/sounds/horse.wav &
4 EOF
5
6 atq | tail -n 1

以上是计时20分钟的,计时5分钟的基本相同,唯上面的20改为5。

第1行,表示将使用bash作为shell解释执行。

第2行,at指令表示增加一个作业,在某个时间执行,具体的时间是20分钟以后。"2>/dev/null"是错误重定向,即如果有错误信息,输出到null设备,也就是忽略它们。这是为了避免有错误的时候出提示信息。我希望程序出错的时候就死掉。

从第2行的"<<EOF"到第4行的"EOF"之间,是当20分钟到了的时候,计算机应该干点啥。第3行,也就是播放那声巨难听的马叫。

以上,就是主要的框架,手动运行脚本时增加一个at作业,然后到时间的时候放点声什么的提醒我。但是仅仅有音乐不足以打断我,所以向eyefoo学习,我准备让计算机到时间的时候把屏幕锁住。

这就涉及到下一个问题,我需要一些新的技术支持我。这也是做不熟悉的小项目的一个重要技巧:不是按需求-分析-设计-实现这样的瀑布或其变形,而是在做完需求和基本框架以后,要做技术原型测试需要的新技术。

5. 需要的支持技术

需要的支持技术包括:锁屏幕,解除屏幕的锁定,放音乐,算还剩多少时间休息。之所以新技术里需要
放音乐,是因为我发现马叫声太难听了,而eyefoo的那几段mid不错,准备拿来用。

算还剩多少时间这个比较麻烦,后面我们再单独谈,先看其他的。

5.1 锁屏幕和解锁屏幕

google了一下,得到以下结果。

[http://stackoverflow.com/questions/8681662/lock-ubuntu-from-shell-script]
Lock
ssh -X user@server "export DISPLAY=:0; gnome-screensaver;
gnome-screensaver-command -l;
UnLock
ssh -X user@server "export DISPLAY=:0; gnome-screensaver;
gnome-screensaver-command -d

然后我手动试了一下,好使。这里想再补充两点。第一,google不是万能的,使用它的前提是你得知道自己要找什么。所以从需求到分析、能找到需要的技术都很重要,它们帮助你知道要找什么。第二,找到以后试一下很重要。不试你不知道它好使,仅仅网友宣称甚至手册宣称都是没用的。亚里士多德还宣称两个铁球不同时落地呢。你得先试一下。此外,试的时候不要在你正准备做的项目里试,另做一个小的项目,专门试这个技术的。一次只解决一个问题,保持最小系统,都是符合14条原则的。

5.2 放音乐

5.2.1 音乐文件

eyefoo的mid在我的Linux机器上放不出声来,因为我的机器里没有这种乐器库。这个说起来就复杂了,跟mid的原理有关,此处略过。总之,你可以有两种方法做出个新的mid来。一种方法是,找个听音牛的,让她告诉你那个曲子的谱,然后你用lilypond或者cakewalk或者Siblius之类的软件按谱做个mid出来。嘴哼哼也行,在旋律上这没什么差别,所不同者,嘴哼哼的不能用mid格式。另一种方法是,用rosegarden打开这个mid文件,编辑一下,换个乐器试试,我换了三角钢琴。

5.2.2 播放

timidity break2.mid

timidity是个Linux下的midi播放软件,命令行的,可以在shell脚本下调用。这就是为什么那些命令行工具会长久存在的原因,它们为shell脚本提供服务。而GUI编脚本就困难多了。等你看了我后面贴的脚本代码,再对比.net之类写的工具,就会发现脚本真是简单了。

当然,这个也得试一下技术原型。

5.2.3 音量

我发现原有的曲子音量有点小,有的时候预告时间快到了那几声听不到,所以查了一下timidity的参数,-A 是调音量的。

当然,这个也得试一下技术原型。下略。

6. 代码

根据需求、既定的框架、新试完的技术,就有了以下代码:

1 #!/bin/bash
2 tomato_path="~/tools/tomato"
3
4 at now + 24 minutes -q r 2>/dev/null <<EOF
5 timidity -A 800 $tomato_path/prebreak2.mid &
6 EOF
7
8 at now + 25 minutes -q r 2>/dev/null <<EOF
9 timidity -A 800 $tomato_path/break2.mid &
10 gnome-screensaver-command -l
11 sleep 300
12 timidity $tomato_path/unlock.mid &
13 gnome-screensaver-command -d
14 20.sh
15 EOF
16

第2行,定义一个变量名字叫 tomato_path,后面在第5行、第9行、第12行分别引用了一次。

第5行,到24分钟的时候,预报时间快到了;第9行,放声音,下课啦;然后在第11行休息300秒,即5分钟;第12行,播上课铃声。

第10行,到时间了,锁屏幕。输入密码的时间通常足够阻止我继续工作的冲动。

第13行,休息结束,开启屏幕。

第14行,自动地再次运行这个脚本,即开始计时25分钟。

这段代码也可以在 [https://github.com/younggift/tomato.git] 找到。

7. 更多需求

这基本就够用了,但是还有不足。指令atq可以列出任务在什么时间将被执行,像这样:

$ atq
3444 Tue Nov 27 18:47:00 2012 r young
3445 Tue Nov 27 18:48:00 2012 r young

但是,我更想直接快速知道还有多少分钟可以工作,而不是根据当前时间和任务时间计算。所以,我们还希望能用脚本解决这个问是。

未完待续

--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

Linux shell脚本,Linux下的西红柿时间管理法 I

Linux shell脚本,Linux下的西红柿时间管理法 I

1. 西红柿时间管理法是什么

西红柿是一种时间管理方法,用于帮助我们集中注意力的。大致的思路是,集中注意力工作25分钟,在这个期间,拒绝电话、上网、计划外的讨论--一般而言,即使对方是你的老板,告诉他25分钟以后去找他,这样的态度他也容易接受。25分钟以后休息5分钟,无论工作得有多么high,工作有多么重要。花了多少时间不重要,集中注意力才是生产力,因为人的脑力创造性的效果并不与时间成正比。重复以上步骤4次,休息一个较长的时间。

为什么这个时间管理法叫做西红柿呢,因为人们最初使用西方厨房里煮鸡蛋计时器来倒计时25分钟和5分钟。咱们煮蛋的时候一般都是用手表,隔一会看一眼表,差不多到时间了捞出来。这个表面上合理的方法违背了计算机程序设计中的一个比较基础的原则:中断比轮询对CPU的占用率低。不过咱们似乎一向对工作和对生活按两种不同的态度。

西红柿的详细介绍可以参见[http://article.yeeyan.org/view/204108/169539],参考书是[http://book.douban.com/subject/5916234/]。

2. 我为什么要在Linux下写西红柿时间管理工具呢

最初,我写了个非常简单的脚本。大概能实现这样的功能:手动运行一个脚本,到25分钟的时候,机器叫一声,是一声巨难听的马叫,提醒我该休息了;然后手动跑另一个脚本,到5分钟的时候再叫一声。

然后,我遇到了问题。到25分钟的时候,如前所述,我可能干活正high,当时听到马叫的反应就是"啊,时间到了,马上就停",这个"马上",有一次持续达4个小时。我遇到的另一个问题是,开始工作的时候,有时忘记手动运行这个25分钟计时,直到累得不行的时候才想起来,"20分钟怎么这么长啊。"

后来,张和郑两位同学群发了个工具,就是eyefoo[http://eyefoo.com]了。这是个windows下的程序,我需要windows的时候就用它。感觉不错,对比我前面在Linux下遇到的问题,就看出了原来简陋脚本的差距了。

3. 功能需求

第一,我的脚本在25分钟结束的时候提示的"声音还不够大"。需要更强有力的事件阻止我继续工作。这并非你的意志薄弱,而是动物性使然。心理学告诉我们,当我们产生情绪冲动的时候,理智那块的大脑还没来得及得出结论。所以,心理学家又告诉我们,这个时候,延迟和打断就很有效果。你如果特想买某个东西,把它放到购物篮,间隔一段时间,等到付钱的时候,想买的冲动可能已经消失了。基本上,愤怒、想砍人什么的,都可以用这种方式化解。足够强有力的打断,然后一小段延迟。

这种强有力的打断虽然来自我自己,仍然令人不爽。所以,eyefoo做得很好,它提前一会儿告诉你,"快到点了啊。"这人性化多了。

第二,我希望25分钟结束以后,自动计时5分钟,休息5分钟结束以后,自动计时下一轮的25分钟。

第三,我仍然希望它工作在Linux下,而且还用shell来写。

未完待续

--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

20121112

男人都应该这样死去

男人都应该这样死去

如何死去,这并非一个所谓"讨巧"的话题。当今之世,大家都在讨论真正牛的富二代如何娶了年轻貌美的女子,或者嘲笑如何适度地在会议上哽咽才能获得权利从而得到女子,又或者你是不是会弹大提琴或者煮得一手好咖啡从而讨好芳心进而得到女子。总之,如何享受生活。但是,这些都是给那些已经拥有享受生活的资本的人考虑的。还有一些人,需要考虑的是如何离开女子,或者,如何去死。

我前天看了一部新片子《边境风云》,里面就有这样一个男人。他沉默,即使要被活埋的时候也没有吭一声,甚至没有动一动;他明知必死,以死赴之,把未来的生活留给女人。

有人会说,那故事都是电影里的。所以,在现实中,我们看到了另一些故事。

某高校举行运动会,取消了长跑项目,这包括男子5000米。一看到5000这个数字,很多人可能就一哆嗦。因为我们都跑过1000米或者女子800,挺累的。与此相比,5000米更是一个能让人把肺子翻转出来的项目。取消这个项目的原因,是因为怕学生受伤,学生们的态度则是"没意思""时间太长了"。

这样极少有人喜欢这样的项目,我只参加过两次,并且一点也不期待会有下一次。我参加的两次,一次是初中越野,也不知道有多远,反正跑完的时候我呕吐加抽筋;另一次是高中五千或者一万,上场的原因是只要参加并跑完全程,班级就有加分。高中那次,我被很多人扣了圈,这些人里甚至可能还包括倒数第二名。有人可能会问,你这么差劲为什么还要上场呢,答案很简单,因为我们班没有别人乐意上场。每班出场2人,另一位是我们班体委,他跑到第某圈的时候抽筋或岔气退赛了。没有人敢于参加长跑,在我看来整个班都很丢脸,所以上场这种事,只好我来做。虽然成绩糟烂,但是总比弃权来得男人一点,当年我这样想。

今天,讨论这个已经不合时宜,毕竟大家都理解刘翔跟健抻断在伦敦退赛了。但是,学校运动会这种比赛既不会要了你的命,也不会影响你作为终生的体育事业。

取消长跑,已经不再只是身体素质的问题了。5000米,训练和体现男人的坚忍。尤其是在一群玩儿鼠标乐器篮球足球诗歌的男生当中,绕操场跑上十多圈。现在,我们太注重被喝彩,被关注,太期待实时的反应和成绩。如果体验成绩的感觉推迟到明天,就会有一大票人放弃无论那是多么重要的活动。如果结果再有那么一点不确定,离开的人就会更多。

但是,非实时的活动,包括计划、估算、度量,这些正是人类不同于动物之处。正是追求未来的快乐,阻止我们今天做某些事。随心所欲地挥霍,要么,你是非常富有这种东西,要么,你根本就不在乎。或者,你太年轻,还没有学会在乎。

暴雪,从来不是那种在一两分钟甚至一两个小时下一米深雪的天气现象,而是就像现在的外面,持续的一直不停地降雪几天几夜。这可以让吉林省部分学校停课,让黑龙江省在这样寒冷的天气停电。自然的伟力,并不在于突发,而在于积累。我们也需要持久的知识结构的更新,不是以月日作为单位,而是穷尽一生。如果你感到舒服了,看的书做的项目里都是你清楚了解透彻明白的,那么,就是你已经停下来开始腐烂了。成长,从来都是持续地痛苦的过程,成长的停止,不是成熟,而是腐烂。

与持续地学习不同,还有人特别欣赏灵机一动、聪明、灵活,尤其是为自己是这样的人而窃喜。我接下来要讲的故事想说明,所有这些都是没有用的。

我跟赵老师和偶像去唐山的时候,是为了一个钢厂的项目。对方提出一个需求,希望在断电的时候也能记录天车的动作,以便在恢复供电的时候再读出来。大家词穷的时候,我提出一个方案,加一个机械结构,像发条那种东西,停电的时候天车一边走,就一边结发条上弦加劲,等恢复供电,读发条的状态。

方案优秀吧,得意吧?故事没有结束。

赵老师解释说,这种技术早就存在,并且有了名字,叫做机械补偿。能想到这种方案固然说明我灵活、灵机一动、聪明,可是这之后呢,如果不知道机械补偿这个名字,难道要重新从头设计整个这个领域的成果吗?

一位王老师曾经教导我说,优秀的方案有两种。一种是你灵机一动想出来的,一告诉别人别人就会了的那种,那种你千万不能告诉别人;另一种是你即使告诉别人,别人也听不明白。这后一种,他当时举的例子是付里叶变换的某种应用。这一类的应用,往往需要学习你的人也有相同的基本功,这意味着同样长时间的努力。

和这些人类积累很多年的成果相比,那些聪明、灵机一动、灵活,基本都不堪一击。苹果教主乔布斯也不是单凭灵感做出漂亮的工业设计,他甚专门上过字体这门课程。

长期积累,一朝可以使用;甚至,看不到确切的结果,永远也没有直接地应用。忍受这些,拒绝实时的和情绪的反应,使人类从动物中分离出来。所以,我们需要坚忍,无论是过去艰难的时候,还是现在大家都在享受的时候。

长跑不仅需要坚忍,还需要持久。

大家不喜欢长跑的一年原因,是因为乒乓球、篮球、足球、羽毛球还可以交朋友,鲜有听说长跑中上气不接下气的还能发展友谊。我们真的那么渴望友谊,那么需要来自他人的肯定吗。就像很多家长训练孩子的体育运动,除了上述这些,再就是跆拳道、游泳、拉丁舞和国标。还训练孩子声乐、乐器,各种以后会在高档的人群中用到的……他们渴望的不是友谊和美,甚至不是技能,而是人脉。

那么,耐力和心肺功能呢?这些对你生存和长期工作都最重要的部分呢。我们需要阅读很多年,在将来的岁月里。但是,我们并不是把那么多个小时在一天里耗尽,那是不可能的,一天只有24个小时而已。我们只能把一生的阅读分解成很多段,每天几个小时。这需要耐力的训练,而且长期的工作也需要心肺功能。

我曾跟黄同学有一段对话。他和同学比赛做俯卧撑的时候,感觉头几个并不吃力,后面就渐渐不行了。我有做俯卧撑的经验,有一段时间每天100个,一下子就能猜到他的问题。我问,"你做的时候呼吸么?"他说,"得憋着气啊。"

这其实就是问题所在。你在做三五个俯卧撑的时候可以屏息,而在做几十个的时候,你不得不呼吸,而且呼吸,而不是胸肌才是这其中最重要的部分。短跑百米,优秀的运动员可以不呼吸,全靠无氧跑完全程,没有听说哪位可以一口气跑完马拉松的。

我们为什么需要持久?因为大部分结果都需要持久地努力。而不是一时的兴奋。"可以十年不将军,不能一天不拱卒。"你每天拱卒的好处,只有在五年十年以后才逐渐地显现出来。

所以,不计一时得失运筹帷幄的将军才比啊啊地冲上去的莽夫更男人。

其实,我们仍然生活在原始社会,这周围仍然是部落和部落的猎场。有的部落可能一直以来坐山靠水的物产丰富,但是这些都不会永恒,没有什么能够保有他们现在所拥有的。

我们仍然需要每天奔跑十几公里追逐猎物。我们的猎物与我们祖先的似乎不同,但是对于坚忍和持久的要求从来也没有改变。

当我们奔跑时,无聊、枯噪,我们应该如何处理。不知道专业的运动员或者长跑大牛们是如何做的,我每一次在俯卧撑到50个以后的时候,唯一想到的事情就是放弃。为了防止我突然停下来,我保持呼吸,在保持呼吸的同时,注意自己的动作,每一个都仔细观察评估,下一个努力做得更加标准有效。

生活本身,也是这样持久的训练。又不是童话书和过生日,每天哪有那么多的惊喜。不外乎观察评估,希望明天做得更好,也避免当惊喜到来的时候,没有心脏或者能力去承受。

长跑取消的后续里说,"即便如此,在剩下的1500米长跑项目中,不少选手已经体力不支,被同学"架着"离开了跑道。"

这让我又想起,上次承办ACM比赛的时候,有同学说这桌子摆齐工作量太大了。我说了一大顿令人厌恶的话,后来我说,"连桌子都摆不齐,咱们再跟日本人打,还会输。"

不是总有人在期待下一次战争,或者报怨不够硬气么。光嘴上硬气是没有用的,除非你认定自己有资格不需要亲自动手。我希望在下一次战争中,没有一个男人因为无法忍受劳累、饥饿、寒冷、恐惧而投降。我刚刚提到的原因,不是劳累、饥饿、寒冷、恐惧本身,而是不能忍受它们。这种承受的能力,需要长久的训练,而无法凭借一时的热血和激情完成。

男人应该如何死去?

不是在鲁莽的突袭中,而是一直跋涉,沉默、坚忍、持久地,最后死在这样的成长的道路上。


--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

20121107

我们注视的,是相同的世界吗

我们注视的,是相同的世界吗

我经常对于CSDN里的博客如何分类颇感踌躇。比如昨天,我先是在图书馆跟ZHUAMO调了约4个小时代码,然后又跟ZHUMAO去大哥那里做服务器负载均衡的咨询。两个故障在我看来原因是相同的,那么,应该归到系统维护类呢,还是编程类?

先是一大早,跟ZHUMAO通电话,问我一大早感觉如何。我说,当然不好,本来正睡觉,被打断几次,只好起床吃饭。ZHUMAO说,那你还是来吧,不然我还得再打断你几次。

吃了上午饭,我想想,还是去到ZHUMAO现场,与其远程被打断几次,不如现场讨论来得迅速。更何况ZHUMAO为我这样的半残人士准备了可以拖到眼前的那种"臂"式的显示器架,我和他结对编程的环境很是不错。

故事1 程序设计 或者 web

11点,我们开始调代码。故事1开始。

故事1。ZHUMAO打算做一个web程序,包括上传乱糟各种东西的功能。此前几经评估,准备借助 plupload 实现上传。plupload是个支持 flash/html5 等诸多客户端平台的解决方案,我们最需要的特色是 客户端部分可以把一个大的待上传文件拆成若干个小块,在服务端再组装起来,避免通常的大文件上传方案要在服务端分配与文件相同大小内存的问题。plupload 把大文件分成的小块称为 chunk。

我们选定plupload方案以后,我和zhumao,sunqc做了一些准备工作,部署了示例程序,改了一些配置,改了目录权限,以支持 web server 写操作。然后我们传了大文件,小文件,测试成功。昨天之前,zhumao&sunqc两位同学又做了一些工作,把界面改得华丽了很多,测试了传特定格式的文件。

然后,问题来了。

我昨天去的时候,ZHUMAO描述说:plupload有个毛病,上传图片的时候,会把图片大小自动修改了,改成比较小的、质量较低的。

我说:啊。

这几年来,zhumao已经熟悉我的嘴脸了。说有什么毛病,第一件事,我肯定是要看毛病到底啥样。你光说,我是啥也不信。基本上,如果你说吃了砒霜会死,我十有八九会要求你死给我看。这一条,可以参考14条原则里不要相信客户或者任何人那一条。

其实我心里还在想些别的。我在想,这哪是毛病,这明明是特点啊。上传图片一般都是为了在web站点上展示,不需要高质量,而图片压缩以后大大减小上传的文件尺寸,多好啊。就像声学钢琴,特指非三角的那种,正常按键的时候声音比较大;电钢琴如果把音量调小,你正常按键的时候,声音会比较小--某同学,这不是毛病,这是特点,因为声学钢琴不具备这种功能。如果你把电钢琴的声音调到正常,再正常按键,那至少,刚刚提到正常按键声音比较小的问题就消失了。

不过,ZHUMAO是用户及上帝,他的要求都是合理的,而且我确实能够理解,保留完美质量照片的重要性。所以我说:这特性应该能禁用吧,这个就挺像,参数resize。

ZHUMAO说,试了,不好使。删除这个特性,就传不上去照片了。

我说:啊?

于是ZHUMAO又演示一遍。果然,客户端报IO错误多少多少号,服务端没有接收到文件。

我说:哎呀?

后来还有很多技术路线的小插曲,我们还试了一些没用的。再后来,我猜测:不是啥类型的大文件都传不上去了吧?

ZHUMAO说:没有,我们测过。

我说:啊。

于是ZHUMAO开始演示。这一次,失败了。某个图片类型以外的文件,上传也失败了。然后我们又确认,上传小的图片文件时--由于不需要chunk--可以上传成功,上传大的图片文件时--由于需要chunk--上传失败。分界线正在是否大到需要chunk。

所以,这个时候发生了一个重要的变化:1.并不是改了resize参数以后上传图片失败,2.而是目前无论什么类型的文件只要chunk,上传都失败。

同样的现象:改resize上传文件失败,现在变成了不同的原因:不仅是图片,任何文件,甚至不改resize,上传也会失败。此前之所以会误会为改了resize上传就失败,是因为改了resize参数以后,测试的恰好是需要chunk的文件。

批判性思维告诉我们,要注意,如果A与B同时或先后发生,那么,我们不能简单得出A与B的因果关系,除了回归分析,还至少需要考虑到:A是导致B的唯一原因么,A是导致B的全部原因么。甚至,在上述案例中,A根本不是导致B的原因。resize修改,只是暴露出了问题,并非导致问题。

据说西域某小城,国王喜欢杀掉报凶信的人,他显然不能区分暴露问题和导致问题是两回事。我们的文化中讨厌乌鸦,大致也是这个路子。我们甚至讨厌预测不良后果的人。

然后,我跟ZHUMAO开始着手解决为什么不能上传需要chunk的大文件这一问题。所以,以前老师总是教导我们,知道问题是什么,远比知道如何解决重要。是不是还有人记得政治课上的那些题,明明我们背得一大堆好答案,考试的时候唯独不知道问的那道题和哪个答案对应。确定了问题以后,解决起来只是体力活了,我俩拆腾了4个小时里剩下的时间,解决了。resize可以通过把quality改为100保证上传的文件大小不变,甚至还可以把resize参数删除,图片就不在客户端做任何处理。

最初和后来,我们看到的是相同的故障,但是,我们心中所想的已经非常不同。先前是图片,后来是chunk。我们先前与后来,观察的是同一个世界么?

故事2 系统维护

下午15:10,跟ZHUMAO去大哥那里做咨询,故事2开始。

大哥以前想办个乐队来着,这是他的理想。我大一的时候,在迎新晚会上看他和陈师兄弹吉他,唱《青春》。他俩是谁向谁单膝跪下来着,我眼神不好没看清。不过他们不是好基友,那是因为电吉他的拾音器线不够长,跪着的那位直接拿迈克对着吉他。大哥的乐队一直也没办成,成为了IT团队的领袖。我当初也有理想来着。我跟大哥说,等我有了房子,一定要在天花板上装几个啤酒桶,下面接上水龙头,想喝的时候,哗。真过瘾啊。我的理想也没有实现,成了今天的这个样子。

我们,各自先去做谋生的或者让我们能生存下去的事了。那些伟大的理想,让更精于此道的兄弟们去实现吧。有一些人,他们应该能靠乐队活下去,有一些人...真的会有人能靠喝酒活下去么?

昨天下午去拜访的,就是这位大哥了。咨询中间的时候,大哥在电话里说,他还需要来么。我说,当然,你得来,你难道就不想来看看我么,如此难得地见到我的机会。

大哥来的时候,某台服务器正重新启动,后来的解决路线就非常清晰了。我们从头说。我和ZHUMAO没去的时候,故障现象的描述是:当访问量上升,负载增加的时候,服务器会崩溃。

我俩分别在听到这句话的时候问了同一个问题,"什么是崩溃。"

所以,到现场以后,画了整体部署的框图,我们就要求:崩溃一个给我们看看呗。

答复是:不确定什么时候能崩溃。

那崩溃时候的日志呢?

答复是:日志有,不知道什么时候崩溃的。

有位兄弟想起个时间。我们通过他们电话的时间,及ZHUMAO查了其他的一些日志,确定了崩溃时间。再查那个时间的日志--没有任何异常。

ZHUMAO说,我用AB做一个压力测试吧,先给你整"崩溃"一下。开始同学们不同意,后来从了。压力测试几次的结果是,当时服务器似乎死了,但是无一例外地,压力一消除,服务器就能从"崩溃"中自动恢复正常。

而同学们描述的"崩溃",是无法恢复,只能reset各个服务才能解决问题。我断言不是由于压力导致的,不然,压力持续下,reset以后,服务器会不停地在 崩溃-reset-正常-崩溃 之间震荡。而同学们说现象不是这样的。

最难诊断的,就是病人告诉医生,我疼,但是我也不知道哪疼。

这个时候救星来了,有一台服务器登录不上去了,怀疑被黑了。重启,用光盘重置登录密码,重启服务器。这时,大哥进门,好戏来了--网站无法访问了。

以前每次重启服务器或服务以后,据说,网站就恢复了。同学们说,从来也没有这样过,重启服务器也没用。

此处省略半个多小时的分析和实验。我们最后得出结论,至少这一次故障与负载压力之类毫不相关,怀疑此前的那些故障也都与服务器性能无关。这台同时有电信、网通、教育网IP的服务器上面还跑了一个DNS server,它域管理服务器架在网通IP上,而www服务架设在教育网IP上。而且,ZHUMAO说,网通线路不怎么稳定,并用实验证实了。

所以,当某个不幸的家伙要访问www.xxx.net的时候,他先问他的DNS服务器"www.xxx.net的IP是什么啊"。他的DNS服务器不知道,向.net根域服务器提出递归解析请求,.net根域服务器又去问--对了,就是在网通线路上的上述域管理服务器。然后,没问到,因为网通线路质量不好。

所以,全世界都访问www.xxx.net困难。这可以用通过IP而不是域名访问验证,当然,我们也这样做了。

问题清晰以后,解决就方便多了。我们把域管理服务器移到了教育网线路上。说到这里有个插曲。其实这些同学虽然也遇到一些困难,但是还真是挺有专业精神的。我要求修改域管理服务器的地址,那同学问我"不会带来其他的问题吗?"我心想,好问题,这谁能保证啊,然后说,"不能保证。"他越发犹豫,我故意说,"哎呀,就试试呗。"恶作剧的感觉,我都快笑出声了。结果,这位同学转头去看大哥,得到同意以后才操作。就本科生这样的年龄来说,非常专业。

还是说,问题清晰以后,解决本身就方便多了。解决,只是问题诊断的小小延续而已。

先前大哥的同学们猜测系统性能、应该做负载均衡,我和ZHUMAO看到的是DNS解析。大家一起看到故障现象,为什么会定义出不同的问题呢。因为,正如柯南道尔通过福尔摩斯说:"因为我们只看到我们想看到的。"

你所看到的现象,不一定是事实,我所看到的现象,也不一定是。包师兄当年在友谊商场到校医校的路上,问我,"我们如何确定观察的是同一个世界呢。"我当时毫无畏惧地说,"唯物主义者这样证实,我们修改这个世界,你也看到了这个修改,那么这是同一个世界。"后来一些年,我开始动摇。在目录A下建立文件,目录B里这些文件也出现了,你就能保证那是两个相同的目录么。如果有个程序监听目录A,然后复制所有的操作到B呢,而且,将来某一刻,这个监听程序不工作了,这还是两个相同的目录么。或者更简单的,如果换个用户登录,发现A和B不相同呢?包师兄后来去美国继续研究康德的《纯粹理性批判》去了,他本科是物理专业的。我本科是电子的,还在这里,一步没动。

你的世界与我的世界的同一问题,与此类似的,又如何确保我说的正是你所听到的。你点头微笑,示意听懂,我又如何确认你不是在表演,而事实可能是,你用"不想听"过滤了全部内容。

人生不相见,动如参与商。

--------------------

博客会手工同步到以下地址:



20121030

长春-初冬 踏在落叶上的脚步声

长春-初冬 踏在落叶上的脚步声

花了一个小时的时间,我离开轻轨站的时候,还有十分钟就要上课了。所以,我开始奔跑。调整呼吸,三步一吸,三步一呼。快转过阿凡达西兰花雕塑的时候,终于还是呼吸困难了,改为快走。好在到教室的时候,没有迟到。

"时间刚刚好。"说到这个的时候,我总是想起史泰龙演的一个片子,名字叫《炸弹专家》。片子的女主角也特别有名气,是莎朗·斯通。如果这两位你都知道,恭喜你,你老了。在片子里,退体的炸弹专家没事抱只猫站在桥下,列车通过的时候看着猫的眼睛,喃喃自语,"时间刚刚好。"他是在回味和模仿昔日炸桥的英姿。

这段片子回顾,是试图回答经常有同事和同学问我的问题。他们问我,为什么要坐轻轨。到学校,坐轻轨加上两端步行,需要1个小时,如果坐公交车,时间可能短到近一半,还能省一半路费。

我一般回答,"因为坐轻轨能有半个多小时的读书时间,公交车上不能看书。"。现在选择轻轨的原因更多了,比如准时,不会塞车,对腰间盘的要求也低一些。不过,我们选择的时候,往往有表面的原因,还有真正的原因。真正的,最初的原因,是轻轨能让我放松下来,让我自己觉得是去旅行,而不是去工作。

就像史奏龙假装在炸桥一样,让我心情愉悦那么一小会儿。即使只是那么一小会儿。

而且离开轻轨站,还可以钻过铁栅栏上的一个洞,穿过河边的一小片树林。在到达人工铺设的石板路之前,有一片无人管理的林子,杂草丛生,夏天还有植物腐败的气味,深秋的时候则满是踩上去哗哗作响的各色落叶。

我假装,自己是在野外,在森林之中。心情也会愉悦那么一小会儿。

所以,有的时候,我回答同事和同学疑问的时候,会给出大家容易接受我不那么精神病的原因。而真正的原因,不说也罢,独自享受。

这就像为什么我在CSDN这种地方贴了那么多小资文,偶尔还有纯技术类的贴子。表面的原因是我是一个小资的文学中年,兼技术人员。真正的原因是我相信文学的责任正在于此。每个人都应该是作者,描写自己的行业,描述自己的生活,从而沟通各个行业。这可以有效地避免一个什么家伙提到的,未来的世界,人与人沟通的困难之处在于,行业之间和专业之间的隔阂。我们应该向所有别的人描绘我们的专业,及我们的专业给我们的感觉--后者,正是所有人类具有的并且能够沟通的。

这也是为什么写科幻小说的时候,我一直坚持写我的专业,并且尽可能只写我的专业。因为我希望揭示我所理解的,并且希望你也能有同感。

但是这些原因我从未公开谈过,它太过于做作,也充满了令人厌恶的训诫口吻,不足为外人道也。这就像,当Lars听到周老师还是谁说我很严厉的时候,非常纯真地睁大眼睛说,"啊,真的吗?"我当时哈哈大笑,都快停不下来了。

很多事情,我们都给出公开的原因,和内心深处的原因。现在认识我的人中,极少有人见过我喝酒,因为我的本科同学都太优秀了,全跑到世界各地继续牛,没有一个跑回这穷乡僻壤来告诉你们,这家伙当年也喝过。所以,当我评品啥酒啥味的时候,现在的同学说,你知道个啥,你又不喝。

我当然知道,我不喝,但是我喝过。我不喝酒的表面原因是胃实在很差劲,这表面的原因也是真的,至今十多年不能吃米饭只能吃面食,而我一点也不喜欢吃面食而喜欢米饭,从小就是。更深层的原因是,我喜欢喝酒,我太喜欢喝酒了,我享受那瞬间的欢愉,甚至乐意为此付出恶心呕吐和第二天头疼的代价。

但是,你们真的谁想看到我喝醉了撒酒疯呢。

在火车站送Anders夫妇的时候,我给他们翻译大广告牌子上的话,"某某酒,让生活更美好。"他俩说,在丹麦,这样的广告是非法的,因为不是那样。我说,"难道不正是这样么,它让我们感觉更美好。"Anders说,那太短暂了啊。

短暂的快乐,长久的痛苦。这就是有些欢愉所带给我们的。所以,当我判断自己忍受不了它的诱惑的时候,我离它尽可能远一些,不考验自己。

我最近在读《优雅人生》,是格雷斯・霍珀的传说。这位教授是个顶绝牛人,著名的Cobol语言的创始人,这语言在日本、在图书馆的aleph500系统上还在运行着。她还是debug这个词的创造者,她把一只飞蛾从计算机的继电器里夹出来,放在日志本里,并注明,今天在程序中找到一个bug。

没错,她还是女人。40多岁的时候被要求从海军退休,然后因为太需要她了,又重新被招募入伍,又服役了40多年。美国有一艘什么舰是用她的名字命名的。

我开始读这本书的原因,是想知道这位女性有多么牛,并以此激励我的女学生们。她们在程序设计领域普遍受到另眼看待,而我认为这是不公平的。

但是当我开始阅读的时候,我才知道,所有的光荣也不过是表面现象。格蕾斯一度酗酒,有自杀倾向。"伯克利强烈指责了霍珀越来越喜欢利用她的酗酒来作为一种吸引家人和朋友注意的方式的倾向。在她的一次'酒瘾发作'之后,霍珀的身体和心理都处于极其严重的状态,以致她不得不说服她的朋友留下来,直到她恢复为止。因为她的大多数朋友也都是勤奋努力的人,所以听她谈论她的饮酒问题开始妨碍到他们的生产力。根据伯克利所述,一开始的个人问题已经变成了大家的问题,并且威胁到了霍珀最渴望的东西:她周围人的爱和关心。据伯克利所说,更加让人烦忧的是霍珀近来有自杀的倾向,而他认为这是对帮助和关注的渴求。"

看伟大的牛人的这段经历,太令人心酸了。我们直接跳到最后吧,Grace Hopper,美国海军准将,她创造了现代第一个编译器A-0
系统,以及商用电脑编程语言COBOL。她逝世于1992年01月01日,享年85岁。

这样,我们知道,这位牛人后来用理智战胜了酗酒,也战胜了自杀倾向。同时我们也知道,每个牛人都如同我们凡人一样,充满了对痛苦的感受,只是他们克服了这些。

所以,表面的光荣,光荣之下的痛苦;表面的酗酒和自杀倾向,在这些痛苦之下的,对 被关心 的渴求。

说起来,我为什么要写成"被关心",而不写成对"关心"的渴求。因为她所渴望的,不是关心别人,而是被别人关心。

当我们说,"我爱你"的时候,比如对父母,通常表示的意思并非表面的那样,而是"我很享受你对我的爱的表达"。我们并不爱我们的父母,而是被爱。

当我们说,我们热爱计算机专业或者编程的时候,我们也并不是真地如表面表达地那样爱它们,而是爱它们带给我们的荣誉和金钱,是渴求被计算机专业和编程"爱",并享受这份爱带来的世俗中的成果。

爱,是关心他们,而不是被关心。爱,是为这个专业和你所钟爱的领域贡献你的力量,而不是期待它带给你利益。就像在宗教中,爱上帝的人,是奉献自己的人;向菩萨献上金漆或者承诺的人,爱的,不过是他们自己,他们声称所爱的,不过是用来爱自己的工具。

说服 Grace 去真正地爱她的周围的世界从而摆脱眼前巨大痛苦的理由之一,是伯克利对她说:尽管你对于早期计算机的贡献极其卓著,但是你对于这个领域的真正的伟大的贡献,还没有到来。

这是当我踩在长春初冬的落叶上,听着令人舒服的沙沙声的时候,也想对你说的话。未来,真正的痛苦,或者欢乐,还没有到来;贡献和牺牲这些对你们这代人过时了的概念的真正含义,你还远未真正理解,也远未体会它们全部的意义--真正的伟大的痛苦和欢愉。

另一些照片在 [http://www.douban.com/photos/album/80213359/].

--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

20121028

东汤镇生存指南

东汤镇生存指南

进入:

凤凰城火车站外,出租车15元每人,行程半小时,一车人差不多满了就走。出租车没有"出租"二字标志,司机喊"东汤"。小客也有,忘了多少钱了。

退出:

东汤镇上的轿车,打双闪还开得慢的都是。15元每人。或者镇南头的汽车站,每天两次,去沈阳,67元每人。去凤城的,很多。

凤城是辽宁省丹东市下辖的一个市。

住:

我们住宁静,宾馆每人每天120元。后来打听到,这算是不错的。还有60元一人的,不过热的温泉水只有一天两次。不过宁静宾馆的,到了12点以后,热水也告无。所以,最后一次徒步以后,我冻得够呛,又累,又要写PPT,却没有热水澡可泡。

房间朝东,三楼,上午有阳光。有阳光可以坐下来喝咖啡,没有坐过。只用来存酒和海鲜来着。环境头几天挺安静,后几天天擦黑的时候下面广场有老头老太跳舞,关了窗也有点吵。可以忍受。

床还算硬,腰突的人对付着可以睡。屋子很大,大部分都空着。电视坐床上看有些高,累脖子。看来是设计给靠在床头的人用的,眼神好,或者不看字幕。

热温泉水挺热,资料上和告示上建议每天一至两次,每次半小时。能烫死人。

吃:

宾馆包吃三顿,定时开饭,每顿只有微量的肉,有米饭和馒头。年龄比我大很多的素食者估计可以,你一定不行。

基本每顿我们都去买海鲜,拿到宾馆加工,吃饭的时候用。10元加工费。海鲜河鲜都巨便宜,价格我一个也没记住。吃过的记有:螃蟹3种,扇贝,河虾,海虾?,cheng子,蚬子。河蟹很嫩,虾很肥。

海鲜建议用煮的,不要蒸的。蒸的凉的快。要点姜末,我们自备了一瓶醋,每天抱去抱回。

早市上的扇贝10块钱三斤,买过一次,到晚上的时候煮了,死了很多。宁静的南面有个唯一海鲜行,10块钱2斤(?),基本没有死的,也更大一些。基本上海鲜,我们都是在海鲜行买的。不过海鲜行不答应给进大螃蟹,说是太少不值得进。接近周六周日的时候,海鲜行存货似乎多一些。

早市散了以后市场还在,有卖栗子的。加水在爆米花机里炒,味道不错,趁热下酒也好。还有很多卖各种中药的,手写的签插在袋子里,治什么治什么的。栗子三斤起开炒,可以跟别的旅客拼成一锅。

早市上有海鲜来料加工的,没试过。海鲜行也能加工,也没试过。

喝:

每顿吃海鲜我们都配酒。自带红酒一瓶,两顿多点喝光。啤酒对面超市有卖的,我们一直喝哈尔滨小麦王。白酒买了二两56度的二锅头,没喝完。

吃海鲜费酒,多备。现去买影响情绪,海鲜凉得也快。

百事和可口可乐也有,咖啡也有小袋粉末的。宁静宾馆大厅里有咖啡和茶。茶28一壶?,咖啡20一杯。座位朝东侧,我一直期待有阳光的时候坐在那里喝上一杯咖啡,结果后来的上午一直都浓雾,始终没有机会。

行:

基本靠走。

有些小团体似乎请了当地向导,带个锯,游客每人手里一根新拐杖。拐杖市场有卖的,老人拄的那种,可以讲价到10元。

在双河村迷路的时候雇了小面包回东汤,两个人40元。司机说这是白天的价格。

小零件:

镇南头联想专卖店,买了SVGA线,和一根电脑接电视的音频线。用来连接笔记本和宾馆的电视,看电影用。电视效果还行。16:9,大部分屏幕都利用上了。是那种新型的液晶大屏幕的,42英寸(?),不是大后背CRT的。还可以接HDMI线,我的笔记本不支持。

买了一个小钢盆。用来泡温泉的时候往身上浇水,洗干净以后还可以装水果什么的。打算去市场上买个葫芦瓢的,应该有,没遇到。

杂货店(?)买了根绳子,拴阳台上晾衣服用。雾气大,衣服挂外面干得也很慢。

宁静里有乒乓球室,有台子和拍。我们买了一个球,4毛钱,没工夫玩。

其他:

宁静的门口有药店,没试过。有晨光专卖,买了两枝荧光笔,能用。

对面超市买了牙膏和香皂,还有成瓶的洗发精,这些东西都有。洗温泉用不到香皂,因为这里温泉微碱性,跟人体表面的油脂一混,正好就是肥皂了。

还跟宾馆借了两个凳子,在电视下放计算机和吃东西的托盘。还借了两条浴巾,
泡的时候用来裹住水外的部分,免得冷。

--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

夜雾里的大河,这一轮最后的行走

夜雾里的大河,这一轮最后的行走

这是前天的事了,本轮最后一次徒步东汤镇的周边。

吃午饭的时候,宾馆的大姐说,今天你们还去挑战自我吗?她可能是把穿越山地
和长途徒步称为"挑战自我"。我说,是啊,吃完就挑战自我去。大姐说,别再走
丢了。我说,好,回来吃晚饭。

一顿装备,同时等雾散。

向南,这次的目标比较近,单程3.5公里,预计天黑以前回来。向南的公路很快
折向东,过下屯桥以后,向东更加明显。而GPS还没等出镇子就消失了,谷歌纵
横只能根据电话信号定位,精度1900米,在山区,跟没定位差不多。

闫土线19公里处,我们折返,找向南的路。选上一条,走了一段,欣喜的发现,
有一座小桥,桥墩间距很近,桥的两侧河略有落差,形成小瀑布,水声哗哗的。
前方不远,一处河水漫过整个路面,有车压上去,水四下飞溅。

对了,一定是这里。前一天从双河村坐车返回时,虽然车灯下什么也看不清,但
是我听到过河水声。就是这样。于是大胆向里走,越走越远,发现河汊越来越
多,沟渠密布。

二猫妈说:河汊不能作为地标啊。

于是漫过路面的河,有落差的桥,这些都不能作为依据了。有地图,我们却不知
道自己在哪里。在群山中的某处原野上,而四周看起来都差不多。镇子的方向仍
然清晰,可是向南的大河在哪里。

南面的大河叫做瑷河,我们准备沿着向南的,当地人称为"河套"。在东北方言
里,河套就是泛泛的河的意思,河拐弯的地方一般都叫做河套。这条河套将在下
游3.5公里处汇入瑷河,然后漫长的奔流,汇入中朝界河。

清楚这些也没有用,我们仍然不知自己身在何处。在某处河与路分叉的地方,我
们遇到一位老者。他说,向下去河套还有很远,而且根本没有路。我们又试着走
了一段,脚踩出的路终于变成了车辙印,然后消失在玉米地里,只好折返。

沿着河沟返回,路上看到不少烤掉叶子的苞米杆,堆了满田地,不知道是做什么
的。

水网中的河流都曲折蜿蜒,蛇行向落日的方向。拍了一些照片,我希望,这看起
来像一片黑暗中闪得刺眼的缓流。但这不是我想见的大河。

河流曲折的地方,陆地推挤河流形成舌头一样的半岛。二猫妈说,这不就是地图
上像舌头那样的那个地方么,咱们到了。我哈哈大笑,说,所有的河看起来都是
这样的啊。我知道,她应该是已经很累了。

太阳将要落山,火红的暗色,可以直视。雾气上涌,沿着山间的溪谷,沿着水网
中的每一条脉络,汇在这个群山围成的巨大盆地里。田野中的玉米垛开始渐渐模
糊起来。

我把二猫妈送到镇子边的公路上,然后向南折返,选择另一条公路,那就应该是
去大河的方向。因为腰突,此前一直是二猫妈背着装备,衣服和咖啡,而我只背
着相机。这下,我就只背着相机,没有所有装备,穿了抓绒。

太阳落到山后,夜幕以可见的速度开始加深,雾气渐重。月亮开始的时候越
来越亮,后来被雾气模糊,越来越暗,到月至中天的时候,已经像湿气里远处的
路灯。

我背着相机,两支登山杖,大步。没有腰突以前,我独自徒步的时候就是这样的
姿势。几乎没有停留和休息,我得以最快的速度前进,因为天越来越黑了,此处
没有路灯。只有在需要拍照的时候,我才停下来,拍了就走。

很多圆木切成一段一段的堆了很大的面积,孤零零的翻斗车,水泥的大坝和蓝色
的水闸,在夜色里黑色的悬崖和灰白的落石。快门咔嚓。

开始的时候,眼镜被雾气和汗水的蒸气浸湿,很难看清取景器。后来,ISO越来越
高,光圈已经开到最大,快门时间越来越长。为了防止抖动,我不再看取景器,
大致对准方向,把相机紧抵在前额上,然后按下快门。寒鸭那幅,二猫妈后来
说,她喜欢那种冷的色调。其实那不是有意为之,而是当时的真实视野一片模
糊,我的肉眼只能看到似乎在那片沙堆旁边有些鸭子。

盲拍,可能就是这个感觉?

我一直沿着公路,只能期待这是正确的方向。后来在一处叉路口对比了地图,找
到自己的位置。看来,只有稀少的东西才能作为地标,此处路少水多,得以叉路
作为地标。还有2公里左右,公路有一段远离河套,河是弧,路是弦的样子。接下
来会有一座桥,横跨河套。过桥以后,一直向南,河套与瑗河交汇,我的目标,
月光下的大河。

后来的路无惊无险,因为与地图完全吻合。灰白的桥,公路劈山形成的悬崖,我
都在完全看不清的情况下举起相机,咔嚓。预览的时候发现,相机远比我看得清
楚,色调不像是黑夜,而是冬天的暮色里。

过桥以后,是土路,脚下深深浅浅的,两侧应该曾是浅滩,我不敢踏小路半步,
再远处是白桦或者白杨林,黑沉沉的影子。

路的尽头,大河,无声地流淌。没有奔流的声音,月亮已经完全隐没在黑色的浓
雾里,看不到月光下的波涛。大河比我想像得要窄很多,不过也仍然宽得可容渡
船。一艘小得可怜,估计可坐两三人的小木船在河上,一人撑着,慢慢地来来回
回。看来这里还是渡口。可惜天黑得完全看不清到渡口的路,虽然近在咫尺,我
没有过去。

岸边还停着一辆辽A牌照的轿车,司机坐在后排座上,开着门,斜靠在靠背上。
从姿势上看,是一位老者。他既没有抽烟,也没有放音乐。在我印像里,车停在
这里休息的,似乎经常都是烟头闪亮,或者放些忧伤且经典的曲子。而他就是坐
在那里看着我。

有那么一瞬间,我真的在想,这一定是上天派来的老神仙。我想问他很多问题,
倾诉我的愤怒和困惑。

最终我问:老先生,这里是瑗河吗?

老先生说:是啊。

我举起相机,对着深黑的河面。老先生问:这么黑能拍下吗。我说:我也不知
道,不过我得证明我来过啊。

快门咔嚓,我拍的是渡口的撑船人。后来我看到照片,明亮的河面,黑色的剪
影,与我所看到的如此不同。

我最后没有问老先生第二个问题,只是说,打扰你啦,老先生。我想大哭,但是
只是转身迈开大步。四周是广阔的原野,稍远处是四合的群山。我开始大声唱
歌,完全不合我行走的节拍,只是用力的、大声地呼喊。我真希望老人家从远处
叫住我,请我喝一杯。不过,即使那样,我也会拒绝的吧。

我踏步在黑暗里快走,雾气已经浸透了抓绒,浸透了我所有的衣裳,头发和帽子
像水洗一样。远处的公路上,车灯柱在浓雾里无遮无拦地直射出很远,最终消失
在群山黑色的影子里。


--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

赶车惊魂

赶车惊魂

定时器惊醒我的时候,我正在做一个梦。

整个梦非常漫长,但是情节简单。我去救一个吸毒的人,但那是一个陷阱。就像那些廉价的片子,仇敌们都隐蔽在破旧的建筑里,他们的身影和柱子的影子溶在一起。空气里满是灰尘,我口干舌燥,汗如雨下。不像以前的那些梦,没有什么人告诉我敌人的所在,虽然作为旁边者我看到了这一切。当然不出所料,仇敌们抓住了我,尽情嘲弄。一个家伙把他的牛仔帽扣在我的头上,我眼睛一片黑暗,汗水和皮革的湿气。

我深缓慢呼吸,准备突击。然后,定时器响了,刚好一个小时。我用的是蛋式的计时器,这个东西比闹表好的地方在于,睡的不实的时候,想知道时间有没有过完,计时器有没有刚好坏掉,不必强行睁开眼睛,只要能听到咔嗒的声音,就说明一切都还安好。

我抓过定时器,又拧了30分钟,然后再也睡不下去了。

上午去答辩,被听陈述和被提问,这就是从东汤被一个电话召唤回来要做的事。周五晚上接到电话,周日上午答辩。我问,那时候我们回去了吧?二猫妈说,没有,那时候在路上。

然后紧急订票,原定的行程都取消掉,打听和计算第二天的各种时间节点。然后等醒酒,好有能力开始做周日要用的PPT。然后发现我带的笔记本做PPT不方便,只写了大纲,睡觉。这个时候就已经想到,第二天,是非常紧张的一天。但是当时还没有想到紧张的程度。


7:10,宾馆的早餐还没开始。服务员大姐说,你们先吃吧。吃。

7:20,车站,买去沈阳的大巴车票。好像刚开门的样子,三五个人靠在柜台上聊天大笑。昨天来打听的结果,问几点上班,"你们七点半以前来吧,准能买到票。"二猫妈补充,"千万给我们留这两张票啊。"

快客预计8点出发,行程3.5小时,11:30抵达沈阳,就在沈阳北的旁边。我看了地图,700米。前一天晚上,先是准备定12点刚过的火车,2个小时行程。刚一提交,在那一瞬间,订票失败,再一查票没了。只好改成接近下午1点的火车,最慢的K车,比刚刚没买到的车慢了一倍,4个多小时。当时幸庆,也好,总算是买到了。

问那三五个聊天的,"请问在哪买票"。另一头踱出一位大姐,"这儿。"我带着"哪儿"这样的眼神,人跟着她从铁栅栏的窗户一直到柜台。她也靠在柜台上,"就在这儿买",然后把挎包移到身前。"这儿",就是指她这儿,不是地点。

果然有票。一直到发车,一共也就十多个人。人少到几乎不必凭票,凭脸就可以检票了。我和二猫妈没一起上车,乘务员小姐说,"呀,你们不是俩人买票么,我刚才看到哩。"

买完票,先不走,去宾馆退房间,打印发票。昨天说好,7:30,打发票。发票没打出来,一个人拎着行李先去车站,另一个人等发票。宾馆大姐说,"你不是坐到沈阳那车么,你跟司机说,到宁静门口停一下。"然后告诉我,"这又不是火车,能停。"

小雨。我拖着行车去车站。你可能看出来了,车站离宾馆真的很近,半夜的时候大喊一声准能听到。

司机说,"可不能中途停车,你让她快来吧,可以等她一会。"

二猫妈那头也传来消息,发票打不出来了,会邮寄,正赶来的路上。刚挂断这一个电话,又一个本地电话打来,"你们走了没有,我给你把发票送去。"

马上要发车的时候,宾馆的大姐气喘呼呼地上车了,递上发票。如果是吃的,估计那都得是新鲜热乎的。这就是小镇的好处了。

然后,冒着雨,大巴出发了。我问司机,"刚才听说高速封路了,不走高速啥时候能到?"司机答,"那必须走高速,必须走。"

还没到高速,也许刚刚出小镇,我就睡着了。快到沈阳的时候,我醒了,看看表,恩,好,时间刚刚好,一切还在原计划之中。然后我们进了沈阳市区。高楼林立,车声嘈杂。

堵车开始。一条直道,3.5公里。车像蜗牛一样,一步一停;二猫妈开始晕车呕吐,估计几天来疗养的劲头开始消耗了。我考虑了打车,但是一想,这样拥堵,打车也于事无补。徒步?正下着雨呢。

这3.5公里,耗掉了所有的原计划。原来还打算用11:30到发车前的一个半小时吃顿午饭呢。还剩半小时火车就要开了,我们终于抵达,欣喜地看到大楼上的红字,"沈阳北",遥遥在望。

拖着行车,走啊走,到处都是施工的围墙,入口在哪里呢?终于找到一个像入口的地方,凹进去一块,往里一看,是一块牌子。沈阳北北广场施工,请从南广场检票上车。

我看了一眼天,阴着,找不到太阳,判别不了方向,这南广场在哪呢?问一位大姐,她用手一指,坐车,直达。

挤。乘客和司机互骂。"上这么多人了你倒是走啊,赶火车呐。""你以为就拉你一个人啊。"对了,沈阳北站北广场直达南广场的公交视普通公交免费携带行李为一名乘客,收一元钱。不过我不吱声,心想,快开吧快开吧,我还没打印纸票呢。

开车。红灯。开车。红灯。开车。红灯。终于转弯了。我心里估计着已经走了多远,默念着如果赶不上这班车就惨了,下面的票更不好买,要赶回去继续做PPT,打车到长春?


到了。大家挤下车,没有一个人喊"急什么啊",看来大家都赶火车。买票的时候谁想到还要绕个大圈才能上车呢。

我一看临时售票点排队老长,冲向候车室,售票点就应该在那个方向。没有。折回来,直接插到队伍的最前面,跟后面几个抱拳,几位对不起啦,让我先打票吧,火车马上就开了。

打票。扫身份证,一张,换身份证,又一张。我的眼镜上全是汗水蒸腾起来的雾。抓起票和身份证们,转身抱拳,谢谢几位啦啊。跑。

凭票和身份证进门,挤在别人的身后,挤在别人的身前。安检,挤过去等着行李出来。候车室在哪里,哪个口,那个显示哪个口对应哪个车次的牌子在哪里?没带望远镜,眯着眼睛到处撒摸。

队伍,看队伍,因为应该正在检票。就在眼前。冲过去,行了,安全了。二猫妈说,还好,还有十五分钟。我说,听说提前五分钟停止检票。而且,幸亏检票口是在眼前,不然,既找不到,也没有体力跑过去。

上车。终于安全了。昨晚幸亏第一次订票失败了,由于大巴晚点和乘火车地点变更,半个小时的时间根本不够折腾。

接下来是4个小时的漫长旅途,节奏舒缓,气氛平静。买的是一个上铺一个下铺。但是下铺没有人来,事实上,整个车厢也没有几个人。卧铺就像包厢一样。我倒杯热水,靠在被垛上,看《银河英雄传说》。比克古将军临就义前对莱因哈特皇帝说,"杨也一样,他可以做你的朋友,但无法成为你的臣下。在你的制度下,只有臣下或者君上,而在我们眼中,只有朋友。"

咣当,咣当。橙皮车从绿叶尚在的辽东奔向已下过两场雪的长春,穿过丘陵和平原,穿过山村和城市,还有墙壁都涂着黄色的小站和现代得科幻一样的都市火车站。

我说:应该隔一段时间安排一次,像小资们说的,坐着绿皮车去旅行,放慢节奏。有一次我没赶上去北京的车,改签到几个小时以后。坐在候车室里,我一直很紧张。但是一躺在硬卧上,我顿时觉得安定下来。有两倍的时间要等待,反正着急车也不会提前到达。这么多的时间,为什么不看书呢。

二猫妈说,对啊。听说俄罗斯的...

我说:对,那是张铁子的理想。我也想坐。不过听说俄罗斯铁路上有抢劫的,过关也特别麻烦。不知道他们接不接受个人旅行呢。

二猫妈说,除了相机和计算机也没啥可抢的。

然后,我慢慢进入梦乡。咣当,咣当,列车不时左右摇摆。

后来,我们到达长春站。转到地下,跟着一个一个的指示牌,走了漫长的路,不断深入地下,最后坐上轻轨。

下轻轨的时候,正是5点半大家下班的高峰,路上挤满了车,根本没有出租车的影子。天上一直飘着小雨,高架桥的影子遮住天空,也遮住霓虹灯。

--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

20121025

登山迷路记

登山迷路记

本来打算今天写个《东汤生存指南》,不过,今天有那么一会儿,我在想,得有命在然后才能写生存指南。

上午大雾,下午开始放晴,但薄雾始终未除。

下午,准备翻山去看大河。带着事先打印好的等高线地图,从笔记本屏幕上用相机翻拍了地形图,确保手机有电,昨天和前天已经试过GPS功能和谷歌纵横,开了racechrono记录轨迹。穿戴好护膝护腰这些盔甲,带好相机,出发。

约13:30,在路上遇到宾馆食堂的大姐,提到我们要去 卧洞沟,看瑷河,大姐说,
"卧洞沟?饿洞沟吧?是在那边。瑷河,可不在那边,在那边呢。"我指的是西,她指的是南。我说,"没问题,瑷河是这么绕的。"

然后,沿前天走过的安家沟进山了。一路上不断检查GPS,检查地图,非常顺畅。而且居然一直有羊肠小道,方向正是我所要的向西,行走方便多了。

先是有人家,然后是很多"自家果园禁止入内",几位这几天见过的大爷大妈从神泉走下来,再后面只剩下了一群羊,赶羊的大叔在锯树枝,可能是当柴禾或者手杖。

很多山丘,错落有致,我们走的小路隐约就从山间穿过,忽左忽右。这条小路一直伴着清凉的溪水声,还有山风掠过干噪的树叶,各种深红和暗绿金山色斑抖动。走走停停,喝热咖啡拍照,好不高兴。

中间爬了一座山,累够呛。淡雾的后面,立陡的山峦墙立在眼前,红黄斑斓交错,偶尔有果园挂在树上的衣服,可能是充作稻草人,还有防火的红旗,其他别无人迹。脚下的山也和对面的一样陡,根本没有路,不知道刚才怎么艰难地几乎直立着爬上来的。后来寻路找到一条略微可以充作小道的,发现下山远没有上山容易,膝关节很吃力,而且需要侧身慢慢下降,左边在前累了,再换成右边在前。始终担心,如果滚下去可就被灌木扎得满身窟隆了。

很快,羊肠小道的主路拐向了北面,而我要向西南。于是决定走另一条小路。小路先是跟着一条小一些的泉水,有时泉水漫过路面,我们就跳左跳右。后来,小路渐渐淹灭在长满刺的灌木和火红叶子里。

虽然没有路了,但是看GPS所去不远,我们决定翻过山梁。有时候,走在阳光里,晒着还挺舒服,有的时候,就走进山的阴影里,冻着。这是一段非常艰难的历程,因为山越来越陡,灌木越来越密,山路似乎还没有出现的趋势,我们开始决定要把咖啡放在最困难的时候喝。

我指着前面天空和山的分界线,"看到吗,那就是山顶了。一百米。"得不断这样鼓劲,我们才能继续爬。而这样的林子里,很难停下来休息。

坡势终于一缓,红的黄的叶子往两边一分,到了山顶。我长舒一口气,哈哈,终于可以看看前面的路了。在山里行走,最大的困难就是看不清前路,GPS和地图的精度又没有那么高,一个一百米的山包就够你爬半天,而地图上连个揪揪都不标出来。如果在山梁走,就得一会上山一会下山,如果在山谷走,就一点也看不到路。

到了山顶,我大呼小叫。放眼望去的时候,我的大呼小叫立马就变了腔调。我说:我现在算是明白抗联的感觉了。

前面还是山。所谓层峦叠障挡在眼前。什么时候是个头啊。那一刻,我突然想到,得有命在,才能写什么生存指南。

然后,我的手机没电了。之前就发现信号不好,电量消耗飞快。关了无线的话,谷歌纵横就开始瞎报我的位置,基本是在出发点附近,就差没像几天前一样一会说我在长春一会说我在东汤了。

手机没电,GPS就没了,racechrono这种东西都成了次要问题。GPS没了,地图就也没了,先前打印的等高线图还在,但是我不知道自己在哪里了。唯一令人感觉安全的是指南针还在,而且还在工作着,它不需要电。

启用二猫妈的手机,谷歌纵横,还有racechrono。所以如果有同学访问我的照片,会发现轨迹是连续的,那是两段拼起来的。伟哉,诺基亚。不费电,能看地图,能GPS。壮哉,诺基亚,更不用提还结实。实在走不出这山,还可以砸个栗子吃,如果能找到栗子的话。

不过我当时根本来不及想这些。当时的想法是:心里一凉。这TM还能走出去了么。不少同学从小生活在平原,一些望过去好几十里,根本不会有我这种担心。再有些同学从小生活在城市,长在城市,丢了以后可以找警察叔叔。即使在西直门立交桥上下不下,也不致于饿死在上面。而我从小生活山区,耳濡目染的很多故事,就包括不少真人真事"走made山",然后几个月后发现饿死的。

好在,此刻我们站在山上,除了山以外,终于又看到些别的。有非常远的地方亮亮的连成一片的,公路,或者是河。我开始后悔没带望远镜,好在单反的镜头也能暂时充任。无奈山间雾大,看了半天也看不清楚。不过,这时看到更远的地方,大河!从宽度和方向上看,一定是它,大河,在三五层山的后面。

计划。先下山,然后沿山谷走,到那条亮的东西那,管它是路还是河,就好走了。这期间,我们又看到了人的痕迹,防火旗一面,隐约的人的声音,很远的狗叫,河谷里的苞米地。

六七十度的陡坡,拄着登山杖,侧身,贴着山的走势,每天步都要踩实。先前那座难爬的山和它相比,只是艰难而已,这一座得用危险来形容。后来路当地人聊的时候,他们说,你们是从那儿爬过来的啊,那也太难走了。

终于到了看起来是人踩出来的路上。我回身拍了不少照片。看起来,就像是一堵墙站在你的后面,而且色彩斑斓。那些斑斓的色彩,全是扎人的灌木,不小心还可能抽在脸上。

发亮的东西不是河,是一条路。我们沿着路走下去。二猫妈达到极限,耍赖决不去看大河了。此时,天气暗下来,山雾就像是暗灰色的,一层层纱一样盖住了山林,模糊了树木。万物逐渐失去色彩,呈现出或暗或亮的调子。

而大河,遥遥无期。

"发亮"的小路两边是一个小村子,却人迹稀少。终于在路上遇到一位大姐,她电话帮我们联系了一辆车。40块钱,返回东汤。我们坐在石桥上,喝了最后一点咖啡。不会再有艰难的时刻了。

我们在夜幕里等车来。月亮上来了,又隐在浓雾里。这位大姐家的小猫很粘人,我考虑要不要买走呢。雾气越来越重,温度开始下降。幸亏在最后半个小时,我们离开了山地,进入有人烟的地方。

那位大姐说,还有半个小时的路能到河沿,那也没啥可看的。我说,"这是什么地方啊。"她说,"这是双河村。"

什么,我隐约记得双河这个地图?赶紧看GPS,看地图。我一直以外我们在胜利还有个什么地名附近,向西走很远才能到大河。检查GPS和地图,确实啊。

但是,我们在双河村。和大河相距只有1.5公里,不是向西,而是向南,前方有土路,不必爬山。我国的GPS是经过修改的,有些GPS模块则没有。简单的说,GPS定位有时完全准确,有时可以差出几公里。而在山区,几公里需要翻过几座山。不知不觉,我们在GPS的引导下向西实际比估计地多走出很远,已经快要到达大河的拐弯了。我先前就知道大河是弯着绕过这片区域的,准备斜着插过去--现在,我们走了直角。

只需再向南1.5公里,如果天色还微明,如果我们还有一点体力,如果再有一点热咖啡。

如果。大河,我几乎听到它的白色浪涛的声音。我还从地图上知道,那里有一座大桥或者大坝,上游的河水深绿,下游苍白,像是瀑布奔流,声壮河谷。黯淡的月光下,隐在浓雾里的大河,该发出怎样雷鸣般的震吼。

如果。

我们坐上返回东汤的面包车,发现决定不徒步返回是正确的。徒步返回不仅仅是一个小时以上的走路行程,还有,此处根本没有路灯,在这样的黑夜里恐怕只有靠嗅觉才能判断方向了。再加上GPS不准,我们不可能在正确的地方突然左转90度进入另一条主路。

车一直很颠簸,很多沟坎的样子,我的腰间盘刚刚可以承受。哗哗的声音,时而有河漫过路面。昏黄的车灯,跳动着。中间遇到一辆货车载在路边,拖拉机正从车厢卸苞米,准备拖出来。我们的车从旁绕过的时候,一侧身陷进了沟里,连忙开左边车门把我们这俩乘客拽出去。

几个小伙子准备把面包从沟里抬起半边,司机去发动车,又下来了,好像不行。我想搭把手推车。二猫妈说,你那腰椎行么。我很惭愧,说,那我使小点劲吧。我问面包司机,你这是后轮驱动啊。他说,恩纳。没有锁死?没有。我远远地站旁边了。这样的车,一侧驱动轮抬起的时候,另一侧驱动轮会失去动力。而我,连参与推车都不能,还是别障事了。

拖拉机的车灯抖啊抖地开过山梗,过来拽我们的这辆车。我想起我爸提到,他的车陷在农田还是山里的时候,还用马车拽过,车一启动轰油门,马就吓得停下来,然后车还是出不去。

拖拉机三下五除二就把面包拉出来,司机喊,上车吧。又是昏黄的车灯,右边是一条挺大的河,我能看到黑沉沉的河面,但那不是瑷河,就是某个河套。

看到了镇子的灯光,回到宾馆,刚好赶上晚饭的尾声,迅速把海鲜和酒拿下来,开吃,压惊。遇到好几伙宾馆的服务员和客人说,我们以为你们丢了呢,一会就要给你们打电话了。我哈哈大笑说,是啊,我们是丢了。

起初错了一小点地方,后来我们又走了很久。最近的时候,距离想去的大河仅仅1.5公里。但是我们迷失在浩瀚的森林中,不知身在何处。

--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]

20121024

重阳登高

重阳登高

长春连下了两天大雪,东汤仍然还是深秋。在长春去趟单位要单程一个小时,在东汤无论买什么东西,都只有那么几分种的路程--当然,或者买不到,现在我还没有遇到买不到的东西。

去买血肠和耳朵的时候,听到顾客跟老板说,"你不知道今天是重阳吗?"我原来也不知道,还问了一句,重阳节是要吃肉么。重阳节,据说要登高。今天我登高了。

上午,爬起来吃完饭,穿好护膝护腰,带好相机和登山杖,出发去登高。表面上的理由是某处有山泉水,要打回来煮茶。茶叶是没有的,只带了咖啡;还有一张手绘的极草的地图,后来证明足够清晰,尤其是沿途有不少人拎着壶,还有推着自行车,载着各种容器。跟着走就是了。

没几步路就到了。一块大石头,上面红漆的阴文,"神泉"。谁题的字就不知道了,石头也不知道是哪位出钱立的。泉水从一根塑料管里出来,塑料管后面是水呢抹的基座,基座嵌在山里,和我们走的小路只隔一条小溪。打了半壶。

不过我们没有先去打水,而是先超过泉水,继续向上走。沿路看到不少小路通往山上,但是都不能走。立着一块牌子,一般地,上面写着"自家果园,禁止入内"。有的是不允许采野菜,有的是完全不准入内,通常声称罚款500元。红漆白牌子,有的漆色已褪,不过内容大致可以想到。

看着小路两侧山色绚丽,却不能接近,令人不甘。所以,继续向前,向前。后来到了没有路的地方,这就可以上山了。上山的途中才发现,其实这里估计也是谁家的果园,因为排列非常整齐的种了半山坡的板栗。地上还有剥落的板栗的外皮,像一个个小小的刺猬,散落在草丛里。

走几步,喘上一会。上山的时候尚好,下山的时候膝盖尤其吃力。不过,几天的温泉浴还是有效果,比在通化冰瀑布下山时两腿快打不了弯好多了。

虽然累,但是登山及远望,心情确实愉悦起来。

我端着相机不停地拍照。远山红黄纷呈,一簇一团点染在暗绿的底色上,有的地方还夹杂着亮白色的树枝,不知那是核桃还是白桦。白桦,白杨,核桃,柞树,板栗。安家沟的一棵树下堆满柴禾,树干沉黑树叶落尽,镇上街道两侧的银杏树下正盖着一层厚而软的银杏叶,还有随意扔在路边树下的璞玉。我的相机终于没电。

我说,如果有一天,再也看不清这些远山近树,该多么痛苦啊。二猫妈说,其实也没有什么,就是看得更不清楚了,还是能看到一团团的颜色的。我说,当我戴上硬质隐形眼镜的时候,能非常容易地看到很多细节,那种感觉真是令人高兴啊。

其实我想说的,不仅是这些。我小时候听说过一个盲人,大家评价他非常能干,令人敬佩。他经常给别的盲人讲火车是什么样的,蓝天白云绿树青草的样子。他小的时候曾经有短暂的时候是明眼人。

我真的难以想像,在以后那些日子里,他如何做到可以忍受生存。在那些明媚的阳光之后,知道此后绝无希望地永远沉在黑暗之中。靠读罗素和康德,解释这个世界为什么会是这样,应该如何,还是读SICP,在内心再创造一个世界,还是,摆个小摊,随便堆放上一葫芦,写上"不买勿动",然后坐在那里呆呆地望着街道。

--------------------

博客会手工同步到以下地址:

[http://giftdotyoung.blogspot.com]

[http://blog.csdn.net/younggift]