More servicesWindows Live
HomeHotmailSpacesOneCare
 
MSN
Sign in
 
 
Spaces home  prowyh's spaceProfileFriendsBlogMore Tools Explore the Spaces community

Blog

September 02

轰炸机驾驶员、柔道高手、钓鱼专家、猎虎英雄

 
据俄罗斯国家电视台网站8月31日报道,普京日前与俄罗斯研究人员一同前往俄罗斯一个国家森林公园跟踪研究西伯利亚猛虎的野外生活。正当普京与野生动物研究专家来到一只被束缚的猛虎面前时,这只老虎突然挣脱枷锁,朝随行的电视台工作人员扑去。就在这时,普京迅速拿起麻醉枪向猛兽射去一支麻醉剂,工作人员这才脱险。在虎中弹入睡后,普京亲手为虎戴上装备全球定位系统的项圈,以便科研人员监控它的动向和健康状况。俄罗斯《消息报》甚至报道称,普京离开国家森林公园时,还专门亲吻了那只老虎并说了声:“再见!”
July 21

对象引用与托管指针(object references and managed pointers)

C/C++中的指针是一种非常灵活而强大的引用机制,但同时也非常脆弱,稍有不慎,就会出错。
 
Java完全摈弃了指针的概念,而代之以对象引用(object reference),基本上消灭了由指针而导致的错误。
 
C#借鉴了Java的作法,引入了对象引用的概念,但同时,不像Java做的那么绝,仍然提供了指针的概念。
 
CLR支持三种类型的指针:
 
1) 托管指针(managed pointers)
2) 非托管指针(unmanaged pointers)
3) 非托管函数指针(unmanaged function pointers)
 
托管指针是一种新类型的指针,指向托管堆中的内存区。
非托管指针是传统的C/C++指针,指向非托管内存区。
非托管函数指针也是传统的C/C++指针,指向函数地址。
 
C#中的指针属于非托管指针,在C#中不能直接使用托管指针,但作为 by-ref 参数传递机制的 ref 和 out 机制就是利用托管指针实现的。
 
C#代码:
 
using System;
public class Test
{
public static void Main()
{
int n = 20;
int m;
 
compute(n, out m);
}
private static void compute(int x, out int y)
{
y = x * 2;
}
}
 
编译以后,生成如下 IL 代码(为了简单起见,这里只取compute()方法的 IL 代码):
 
.method private hidebysig static void  compute(int32 x, [out] int32& y) cil managed
{
  // Code size       7 (0x7)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldarg.1
  IL_0002:  ldarg.0
  IL_0003:  ldc.i4.2
  IL_0004:  mul
  IL_0005:  stind.i4
  IL_0006:  ret
} // end of method Test::compute
 
从compute()的 IL 代码即可明显看出,参数 y 的类型即是托管指针 int32&。
 
stind.i4 指令将栈顶的 32 位整数值存储到由次栈顶元素(即参数 y)所指示的内存地址中。
 
上面的C#代码用的是 out 指示符,如果换成 ref 指示符,生成的 IL 代码是一样的,所不同的是,C#编译器会检查 m 的赋值情况,在执行 compute(n, ref m) 之前,m 必须被明确赋值(definite assigned),而对于 out 指示符,m 不需要赋值。
 
托管指针和非托管指针的区别是明显的,托管指针指向的是托管堆中的地址,而非托管指针指向的是非托管内存中的地址。
 
那么,对象引用与托管指针又有什么不同呢?
 
从物理实现的角度看,对象引用也是一种指针,而且是一种托管类型的指针。与托管指针不同,对象引用只能指向对象的起始位置,而不能指向对象内部,也就是说,对象引用指向的是对象的整体,而非局部。
 
而托管指针一般是指向对象内部某个成员的地址。除此之外,托管指针还可以指向求值栈(evaluation stack)中的位置,或静态变量,甚至非托管内存区。
 
July 20

To box or not to box (III)

C#代码:
 
using System;
public class Test
{
public static void Main()
{
object o = 30;
int k = (int)o;
}
}
 
编译以后,生成如下的IL代码:
 
.method public hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       17 (0x11)
  .maxstack  1
  .locals init (object V_0,
           int32 V_1)
  IL_0000:  nop
  IL_0001:  ldc.i4.s   30
  IL_0003:  box        [mscorlib]System.Int32
  IL_0008:  stloc.0
  IL_0009:  ldloc.0
  IL_000a:  unbox.any  [mscorlib]System.Int32
  IL_000f:  stloc.1
  IL_0010:  ret
} // end of method Test::Main
 
其中,局部变量 o 成为 V_0,局部变量 k 成为 V_1。
 
ldc.i4.s 30 指令我们上文已经见过,将 30 推入栈中。
 
box [mscorlib]System.Int32 指令将栈顶元素(30)进行装箱操作,并将对象引用推入栈中。
 
stloc.0 指令将栈顶元素(30装箱后的对象引用)存入 V_0。
 
ldloc.0 将 V_0 推入栈中。
 
unbox 指令有两种形式:unbox valuetype,unbox.any typeTok
 
unbox valuetype 的意思是将装箱的值类型转换为其原初形式(raw form)[1],实际上是返回指向对象中的值的指针(valueTypePtr),并推入栈中。
 
unbox.any typeTok 指令抽取对象中的值(也就是被装箱的值),返回,并推入栈中。
 
由此可见,指令 unbox 和 unbox.any 是不同的:unbox 只是返回指向值的指针,而 unbox.any 则返回实际的值。
 
unbox.any [mscorlib]System.Int32 指令从栈顶元素(对象引用,即 o)所引用的对象中抽取装箱的值(即30),并将其推入栈顶。
 
stloc.1 指令将栈顶元素存入 V_1(即 k)。
 
由此可见,相比装箱操作(boxing)而言,拆箱操作(unboxing)只是取对象中的地址或抽取对象中的值,并不算太费时。
 
[1] 值类型有两种表示:
 
1) 原初形式(raw form) ,当某个值类型嵌入其它对象中时,即以原初形式表示;
2) 装箱形式(boxed form),当某个值类型的数值(data)被装箱到一个对象中时,即以装箱形式表示,此时可以作为一个独立的实体(an independent entity)而存在。
 
July 19

To box or not to box (II)

C#代码:
 
using System;
public class Test
{
public static void Main()
{
int n = 30;
Console.Write("n: {0}", n);
}
}
 
编译以后,将生成如下的IL代码:
 
.method public hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       22 (0x16)
  .maxstack  2
  .locals init (int32 V_0)
  IL_0000:  nop
  IL_0001:  ldc.i4.s   30
  IL_0003:  stloc.0
  IL_0004:  ldstr      "n: {0}"
  IL_0009:  ldloc.0
  IL_000a:  box        [mscorlib]System.Int32
  IL_000f:  call       void [mscorlib]System.Console::WriteLine(string, object)
  IL_0014:  nop
  IL_0015:  ret
} // end of method Test::Main
 
ldc.i4.s num 的意思是 push num onto the stack as int32, short form. 所以 ldc.i4.s 30 的意思是将 30 作为 32 位整数推入栈顶。
stloc.0 的意思是 pop a value from stack into local variable 0.
 
所以 ldc.i4.s 30 和 stloc.0 两条指令执行的结果是完成C#中的赋值(变量定义)语句:
 
int n = 30;
 
这里,局部变量 n 变成了 V_0。
 
ldstr "n: {0}" 指令的意思是将字符串 "n: {0}" 推入栈顶。
 
ldloc.0 的意思是 load local variable 0 onto stack,即将 V_0 的值推入栈顶。(此时由ldstr推入的字符串成为次栈顶元素。)
 
box typeTok 的意思是 convert a boxable value to its boxed form,即将值转换为装箱形式,即引用类型。
box [mscorlib]System.Int32 即是将栈顶的 32 位整数值转换为装箱后的形式,然后返回对象引用,并将此对象引用推入栈顶。
 
call void [mscorlib]System.Console::WriteLine(string, object) 即是以栈顶元素(装箱后的对象引用)和次栈顶元素(由ldstr推入的字符串)为参数,调用WriteLine方法。
 
这段代码唯一不好理解的是由 box 完成的装箱操作。
 
简单说来,box 操作分为三步:
 
1) 创建一个无名的新对象,类似于 new Object();
2) 将要装箱的值(存在于栈顶)从栈顶弹出,拷贝到新创建的对象中;
3) 返回该对象引用,并推入栈顶。
 
如果转换为C的语义,可以这样理解:
 
1) 调用malloc()分配适当大小的内存区;
2) 将值从栈中弹出,拷贝到该内存区;
3) 返回该内存区的地址,并推入栈顶。
 
当然,这只是一个有助于理解的类比,实际的实现并不一定与此相同。
 
由 box 指令的操作可以看出,存在两个比较费时的操作,即1) 创建新对象,以及2) 值的拷贝。
 
由此可见,虽然C#通过 boxing 机制模糊了引用类型和值类型的边界,使得程序员可以写出一致的代码,但 box 操作不可避免地存在着性能损失。所以,应该尽可能地避免 box 操作。
 
July 15

To box or not to box

给定:
 
int n = 30;
 
下面的两条C#语句有什么区别吗?
 
1. System.Console.WriteLine("n: {0}", n);
2. System.Console.WriteLine("n: {0}", n.ToString());
 
当然,这两条语句产生的结果是没有任何区别的:
n: 30
 
既然如此,还有什么可研究的吗?先别急着下结论,研究研究再说。
 
首先,我们来看看WriteLine()的语法格式:
 
public static void WriteLine(string format, Object arg0)
 
从此语法格式可知,WriteLine()的第二个参数要求是Object类型,上述的语句2是满足的,因为n.ToString()的结果是string类型,而string类型就是Object类型;而语句1是不满足的,因为n是值类型(value type),而WriteLine()又没有形如WriteLine(string format, int arg0)的语法,既然如此,那 n 又是如何转换为 Object 类型的呢?(否则编译就会出错:类型不匹配!)
 
C#区分了引用类型(reference type)和值类型(value type)。
 
引用类型涉及到两个实体(当然,对程序员是透明的):对象和对象引用,对象存在于堆(heap)中,而对象引用存在于栈(stack)中。对于一个对象,可以存在若干个对象引用指向该对象;当然也存在不指向任何对象的对象引用,该对象引用的值即为null;对于不存在任何对象引用的对象,即成为GC要回收的对象。
 
而对于值类型,只存在一个实体,即值本身,该实体存在于栈中。
 
由此可见,引用类型和值类型有着很大的区别。这种区别有时候是必要的,如:
 
for (int i = 0; i < 10; i++)
{
// loop statements
}
 
这里的循环控制变量 i 作为值类型,就非常自然而高效。如果 i 也作为引用类型,将大大降低 for 语句的效率。但有的时候却是不必要的,如上述的WriteLine()语句,如果引用类型和值类型不能互相转换,则必须要有类似如下的WriteLine语法:
 
public static void WriteLine(string format, int arg0)
 
而且WriteLine对于所有的值类型都要有类似的语法,这将使得 FCL 非常庞大而笨拙!
 
C#语言通过 box/unbox 设施(机制)比较好地解决了这个问题。使得下述声明
 
public static void WriteLine(string format, Object arg0)
 
适用于所有的数据类型。所以,我们可以写出像
 
WriteLine("n: {0}", n);
 
这样的语句。这里的 n 通过 box 机制自动转换为 Object 类型。通过检查编译器生成的中间代码可以更清楚地看出这一点:
 
  .locals init (int32 V_0)
  IL_0000:  nop
  IL_0001:  ldc.i4.s   30
  IL_0003:  stloc.0
  IL_0004:  ldstr      "n: {0}"
  IL_0009:  ldloc.0
  IL_000a:  box      [mscorlib]System.Int32
  IL_000f:   call      void [mscorlib]System.Console::WriteLine(string, object)
 
从这段 IL 代码中可以看出,n 通过 box 指令转换为了引用类型,然后再调用WriteLine(string, object)方法。
 
从这个例子可以看出,C#中的 box/unbox 机制,就像 using 语句(using statement,非using directive)一样,是一种便用设施(handy facility)。这种便用设施使得程序更加优雅,正因为此,Java语言从5.0开始也引入了 box/unbox 机制。
 
June 01

我的工作空间 (My Workspace)

看来网络广告是真有效果,以前也知道有Microsoft Office Online版本的事情,没怎么在意。今天在spaces.live.com上看到office.live.com的广告,点了一下,就成了Office Live Workspace的用户了。Open-mouthed
 
试用了一下,感觉不错。
 
 
界面做的非常专业,不愧是Microsoft,一上来就是大手笔,比我做的界面强多了…… Hot
 
试比较:
 
 
虽然我认为已经很专业了,但和Microsoft相比,还是差那么一点点。Smile
 
1) 从Microsoft的几个在线系统(spaces.live.com, hotmail.com, msdn.microsoft.com, workspace.office.live.com)来看,Microsoft已经舍弃了HTML中的Button。
 
2) workspace.office.live.com只是一个Workspace,文档的编辑还是利用Office桌面软件,这一方面是Online版的编辑器现在还无法与桌面软件相比(spaces.live.com的编辑器已经足够好了,但从UE的角度来说,还是无法与Word相比),另一方面也是一种策略,Microsoft不可能丢掉Desktop Office这只Cash Bull的!
 
3) 使用workspace.office.live.com需要安装(或打开,enable)几个ActiveX控件,利用这些控件来连接Web与Desktop,这样使得workspace.office.live.com与Desktop Office的交互更加顺畅,而不会太有两张皮的感觉。这恐怕只有Microsoft才能够做到,因为你如果只有Online System,无法与桌面进行顺畅的交互。而如果Microsoft没有IE,要想顺利实现这些也是很难的(甚至是不可能的)。
 
Web的桌面化(Web as Your Desktop)是目前的大趋势,SaaS(Software as a Service)在起着助推器的作用,但完全实现这点目前还有技术上的难度,HTML、DOM还有待于继续完善,JavaScript还很弱(不论是编程模型,还是调试手段,以及执行效率),浏览器对标准的实现程度还是一个问题。
 
May 31

高人与狂人 (What are about the great men)

高人
 
有人对康德诉苦,说读他的这本书(《纯粹理性批判》)苦于手指头太少了,康德惊异地问为什么?回答说,我用每个手指头按住一个子句,十个手指头用完了,你写的这一句还没完。
 
—— 李泽厚著《批判哲学的批判:康德述评》(修订第六版)
 
狂人
 
一日,日机空袭,警报响起,联大的教授和学生四下散开躲避。刘文典跑到中途,忽然想起他“十二万分”佩服的陈寅恪身体嬴弱且目力衰竭,于是便率几个学生折回来搀扶着陈往城外跑去。他强撑着不让学生扶他。大声叫嚷着:“保存国粹要紧!保存国粹要紧!”让学生们搀着陈先走。这时,只见他平素藐视的新文学作家沈从文也在人流中,便顾不得自己气喘如牛,转身呵斥到:“你跑什么跑?我刘某人是在替庄子跑,我要死了,就没人讲《庄子》了!你替谁跑?”
 
刘文典多年潜心研究庄子,出版了十卷本《庄子补正》,陈寅恪为之作序,推崇备至。曾有人向刘氏问起古今治庄子者的得失,他大发感慨,口出狂言道:“在中国真正懂得《庄子》的,只有两个人,一个是庄周,还有一个就是刘某人。”
 
—— 徐百柯著《民国那些人》
 
真正的学者总是会流传一些奇闻轶事,即使被海涅“揶揄”为“没什么生平可说的”康德,也会有使人“会心”的故事,更不用说刘文典那使人“喷饭”的狂狷了。
 
May 29

据说是比尔的千金 (Bill's daughter?)

 
据说是比尔•盖茨的女儿
 

灾区学生烈日下备战高考[组图]

 
5月28日,陕西宁强县一中高三年级学生顶着烈日听英语课
 
 
5月28日,陕西宁强县一中高三年级学生顶着烈日听英语课
 
陕西南部的汉中市宁强县,紧邻四川广元,在此次地震中受灾严重,再加上余震影响,目前中小学尚未复课。随着高考临近,宁强县一中为高三年级1100多名学生建立了帐篷校舍,供他们学习、住宿。由于帐篷闷热,很多课程只能放到帐篷外上,学生们顶着烈日依然认真学习,抓紧时间备战高考。
 
新华社记者 陈钢 摄
 
黄土地的希望!
 
May 27

吉本《罗马帝国衰亡史》

刚收到新一期的《季风书讯》。
 
本期《季风书讯》重点推介英国史学家爱德华·吉本的《罗马帝国衰亡史》:“从本周近五百种新书中选出《罗马帝国衰亡史》,是因为此书实
在重要。”
 
 
吉本花费20年光阴写成煌煌六卷的巨著,并以此书而“成为继希罗多德、修昔底德、塔西佗、马基雅维里等欧洲史家后的又一位史学大家。”
 
此书译者席代岳先生,“在美国,以一人之力,译了十几年,终于完成”!
 
写书难,译书更难。在语义差距甚大的两种语言之间进行转换,实为不易!以一人之力,穷十几年之功,其“愚公移山”之精神实在让人感佩!
 
西方文化,言必称希腊、罗马。如果说文学上通过荷马、埃斯库罗斯,哲学上通过柏拉图、亚里士多德,数学上通过必达哥拉斯、欧几里得,使得我们对希腊多少还知道点的话,对于罗马,恐怕除了其讲拉丁语之外就一无所知了,或许,延续至今的罗马教皇是罗马最伟大的历史成就?!Smile
 
呜呼!
 
May 25

让人不知所以的IE(The Puzzled IE)

IE提供了一些命令用于页面与外部环境的交互,其中Copy命令是将选中的内容拷贝(复制)到剪贴板。可以如下的JavaScript代码实现:
 
function copyToClipboard(obj)
{
var range = document.body.createTextRange();
if (range)
{
range.moveToElementText(obj);
range.select();
var result = range.execCommand("Copy");
}
}
 
出于安全原因,IE会显示一个提示框,以提示用户是否允许复制到剪贴板,如下图。
 
LevenSite Server
 
我们需要根据用户选择“允许”还是“不允许”来给出进一步的提示信息,但却无法得知用户的选择!MSDN说:Returns true if the command is successful. 言外之意就是,如果执行不成功,应该返回false。可测试的结果却是:不管“允许”还是“不允许”,result总是true!
 
execCommand之外,IE还提供了几个用于查询命令执行情况的方法:
bEnabled = object.queryCommandEnabled(sCommand);
bIndeterm = object.queryCommandIndeterm(sCommand);
bDone = object.queryCommandState(sCommand);
bSupported = object.queryCommandSupported(sCommand);
 
但这些方法在这件事情上毫无用处,不管选择“允许”还是“不允许”,这些方法的结果都一样!如与本文目的直接有关的应该是queryCommandState,MSDN说:(This method ) returns a Boolean value that indicates the current state of the command.但不管“允许”还是“不允许”,该方法总是返回false!
 
如何知道用户选择的是"Allow access”还是"Don't allow”?答案是“无法知道”!
 
想当年,我们曾为IE的DHTML举手称庆!也为IE的巨大包容性而“心怀感激”!然而,在“坐稳江山”之后,IE却无可避免地“自满”起来,真是宿命!
 
所以,竞争,才是推动技术进步的不二动力!
 
May 23

LevenSite Server 新版推出 (LevenSite Server 4.0 Standard Edition Released)

在忙活了几个月之后,LevenSite Server新版(4.0)标准版终于可以测试了!
 
 
基于以下几点限制,新版放弃了原来的桌面软件管理方式:
 
1) 桌面软件连接数据库难以跨越防火墙
 
这是C/S软件最大的问题。互联网时代,到处都是防火墙。因为HTTP协议只需要80端口(HTTPS需要443端口),所以不存在被防火墙阻拦的问题(因为一般防火墙都会打开80端口,如果连80端口都封掉,则就真正“与世隔绝”了)。
 
2) 桌面软件难以访问内网的数据库
 
如果数据库服务器“躲”在内网,则以前的桌面软件是访问不到的。
 
新版LevenSite Server充分利用了Web 2.0的Ajax技术和Web Services,将原来的桌面软件功能完全在Web上实现了。下面是后台管理的界面:
 
LevenSite Server
 
目前,SOA是一个讨论的热点,而SOA的核心理念是SaaS(Software as a Service),而SaaS的基础是软件Component化,Component Service化。
 
LevenSite的理念是页面结构化(Page is structured),结构部件化(Structured page is made up of weblets),这样,网站将可以实现功能的剪裁与伸缩。
 
另外,与模板方式不同,LevenSite由于缩小了组成页面的部件的粒度,从而解决了模板页面的“千篇一律”,缺乏个性的问题。
 
May 22

国之殇。。。

 
搜狐,一张图片显水平。
 
 
汶川大地震乃国之殇!
 
 
每一个生命都值得敬畏!
 
 
为死者祈祷,为生者祝福!
 
May 16

今天,打开信箱……(Today, open my mailbox...)

今天,打开信箱,发现一份中国国家地理杂志!
 
美国的《National Geographic》素来享有盛名。《地理知识》自从改版为《中国国家地理(Chinese National Geography)》之后,可读性、观赏性、收藏性都大为提高!
 
以前看过两期,一期讲江南。一句“杏花,春雨,江南”让人无法不生出“未老莫还乡,还乡须断肠”的感叹。一期讲大运河。一次世界运河城市市长论坛,让扬州喊出了“到北京看长城,到扬州看运河”的豪言。中国幅员辽阔,山川秀美,历史久远,《中国国家地理》真是大有可为!
 
这期的《中国国家地理》是河南专辑(上)。
 
讲到河南,就会想起洛阳牡丹,嵩山少林,安阳殷墟,以及那开封府的包大人!安阳、洛阳、开封都曾经作过国家(或朝代)的都城,盛极一时,作为政治运动标志物的“红旗渠”,也曾经展现过“与天斗,其乐无穷”的豪迈与“人定胜天”的狂妄。然而,现在的河南(人),却让很多人摇头,甚至“心有戚戚”焉。
 
曾经遇到一位来上海打工的河南小伙,讲起其遭遇,却是“心有悸悸”焉!……
 
信箱里还有一件“喜事”值得一说,这期中国移动的帐单上,国内漫游费已经降下来了,这是继接听“免费”之后的又一次“惠民”之举(虽然是在重重压力之下的无奈之举)!与此相应的是,电信老大的宽带费用却一直居高不下!电信怎么这么牛呢?很多反微软人士对微软的垄断耿耿于怀,却为什么听不见反电信“垄断”的声音呢?
 
鲁迅先生讲中国历史只有两个朝代:一是欲做奴隶而不得的朝代,一是暂时做稳了奴隶的朝代!思想家就是思想家,是不世出的。
 
还是回到《中国国家地理》,谢谢赠阅(虽然不知何人所赠)!什么时候能看到燕赵大地的专辑呢?对比杏花春雨孕育的才子佳人,风啸水寒唱出的慷慨悲歌,同样构成着中国的历史。
 
大雨落幽燕,白浪涛天!风啸啸兮易水寒,壮士一去不复返……
 
March 29

C# and .NET

The programming language of choice for .NET is C#, which builds on the lessons learned from C (high performance), C++ (object-oriented structure), Java™ (garbage collection, high security), and Visual Basic (rapid development) to create a language ideally suited for developing component-based, n-tier, distributed Windows client and web applications.

C# 3.0 brings greatly enhanced features and a powerful new development environment. It is the crowning achievement of Microsoft’s R&D investment. It is wicked cool.
 
-- Programming C# 3.0 by Jesse Liberty and Donald Xie
March 27

话说UNIX之春秋战国

很久没有光顾UNIX这个百花园了,最近借着做UNIX培训,又徜徉了一把。
    
从87年接触UNIX,到现在已有20年了!想当初为了踏上由UNIX/C开辟出的“新大陆”而秉烛夜战的热情,恍如昨日……
    
不幸的是,由于AT&T的“慷慨”,UNIX source code走出了生她养她的Bell Laboratories,宛如亚当与夏娃走出了伊甸园,而使得地上“爬满”了芸芸众生一样,UNIX从此不再“UNI-X”!
    
潘多拉的盒子一旦打开,世界也就不再安宁。从UI、OSF,到POSIX,再到Open Group,将UNIXes拉拢到一起的尝试一波接一波,但UNIXes仍然“我行我素”,仍然标榜“我最美”!特别是各种庶出之Linux,更是让UNIX这一本已“人满为患”的大家族更加“人声鼎沸”!
    
乱花渐欲迷人眼,现在即使想找一个UNIXes的最小公分母,也不是一件容易的事。如果说dump命令不算UNIX的classical command的话,那cron可是“与生俱来”的,但每个用户的crontab文件以及cron.allow、cron.deny已经“找不着北”了……
    
UNIX的设计理念之一是“统一”,或者说“一致”,如文件,文件是UNIX中特别伟大的概念及实现机制,就是因为其统一的处理方式。再如处理文件的命令,既可以接受作为命令行参数的文件名,也可以从标准输入读,作为过滤器使用,从而为通过管道构建强大的命令组合提供了实现机制。这种“逻辑的一致性”使得UNIX实现一些处理功能时非常优雅!
    
可惜的是,后来人却没能坚持这种优雅的“逻辑一致性”,有些命令让人非常烦恼!
    
chage是一个设置用户帐户/密码有效期的命令,可以方便地更改用户的最近(上次)修改密码的日期:
    
chage -d lastday user
    
但这里lastday要求必须是日期格式,实际上/etc/shadow中的lastday存储的是上次修改密码的日期与1970-1-1的差!而UNIX又没有提供计算两日期之差的命令,这样有时候就非常麻烦,如对于这样的任务:
    
用户peter的密码已失效,如何做才能使peter能够登录而又能够强制其立即修改密码?
    
要使peter能够登录,必须向前推算peter的lastday,而且必须将lastday转换为日期格式,才能用chage命令来设置,下面是完成此任务的Shell Script:
    
# $HOME/bin/enable.sh
######################
# for user whose password have expired,
# enable him/her to login, and force him/her to update password
#
# tested on Turbo Linux
#
# 2008-3-27
######################
#! /bin/bash
 
if [ $# -le 0 ]; then
    echo "usage: $0 user"
    exit 0
fi
 
a=($(cat /etc/shadow | grep "^$1:" | sed "s/::/:0:/g" | tr ":" " "))
maxdays=${a[4]}
inactive=${a[6]}

d=$(expr $maxdays + $inactive - 1)
c=$(expr $(date +"%s") / 86400)
c=$(expr $c - $d)
years=$(expr $c / 365)

days=0
idx=0
while [ $idx -lt $years ]
do
    y=$(expr $idx + 1970)
    days=$(expr $days + 365)
    
    r4=$(expr $y % 4)
    r100=$(expr $y % 100)
    r400=$(expr $y % 400)
    if [ $r4 -eq 0 -a $r100 -ne 0 -o $r4 -eq 0 -a $r400 -eq 0 ]; then
        days=$(expr $days + 1)
    fi
    idx=$(expr $idx + 1)
done
year=$(expr $idx + 1970)

r4=$(expr $year % 4)
r100=$(expr $year % 100)
r400=$(expr $year % 400)
ma=(31 28 31 30 31 30 31 31 30 31 30 31)
if [ $r4 -eq 0 -a $r100 -ne 0 -o $r4 -eq 0 -a $r400 -eq 0 ]; then
    ma[1]=$(expr ${ma[1]} + 1)
fi
 
day=$(expr $c - $days)
idx=0
while [ $day -gt ${ma[$idx]} ]
do
    day=$(expr $day - ${ma[$idx]})
    idx=$(expr $idx + 1)
done

month=$(expr $idx + 1)
chage -d "$year-$month-$day" $1
chage -l $1

该脚本的用法:
# enable.sh peter
 
执行过该命令之后,peter即可登录,而且必须立即更改密码。
 
该脚本之所以如此冗长,是因为要将天数转换为chage要求的日期!也许chage命令的设计/实现者认为chage主要是用来手工设置用户的lastday等参数的,参数取日期形式会更加自然,所以在内部实现了从日期到天数的转换,而将“自然”留给了用户。但对于此例所言之情况,则是“太不自然”了:要写那么冗长的代码将天数转换为日期,而后chage内部再将日期转换为天数!My God!
 
如果chage支持天数形式的-d选项,则enable.sh将会简洁、优雅得多:
 
# $HOME/bin/enable2.sh
######################
# for user whose password have expired,
# enable him/her to login, and force him/her to update password
#
# 2008-3-27
######################
#! /bin/bash
 
if [ $# -le 0 ]; then
    echo "usage: $0 user"
    exit 0
fi
 
a=($(cat /etc/shadow | grep "^$1:" | sed "s/::/:0:/g" | tr ":" " "))
maxdays=${a[4]}
inactive=${a[6]}

d=$(expr $maxdays + $inactive - 1)
chage -d $d $1
chage -l $1
 
可惜,该脚本却是不能执行的。
 
March 23

龙应台:一张考卷做做看

【引者按】教育?!什么是教育?!阅读?!什么是批判阅读?!对照作者的另一篇文章《德国人怎么上历史课》,感觉我们差的不是一点半点!!!

这是一班通识教育的选修课,学生从大一到硕士生都有,课程名称是“批判阅读”。期中时,我给学生的第一次考试,只有一个题目,但是同一个题目分两阶段考。第一阶段的试题很简单:

请仔细阅读以下文本并提出自己对这个文本的看法。赞成或不赞成都请阐述理由。

《甲申文化宣言》

……文明多样性是人类文化存有的基本形态。不同国家和民族的起源、地域环境和历史过程各不相同,而色彩斑斓的人文图景,正是不同文明之间相互解读、辨识、竞争、对话和交融的动力……

我们主张文明对话,以减少偏见、减少敌意,消弥隔阂,消弥误解。我们反对排斥异质文明的狭隘民族主义,更反对以优劣论文明,或者将不同文明之间的关系形容为不可调和的冲突,甚至认为这种冲突将导致灾难性的政治角力和战争。

……我们主张每个国家、民族都有权利和义务保存和发展自己的传统文化;都有权利自主选择接受、不完全接受或在某些具体领域完全不接受外来文化因素;同时也有权利对人类共同面临的文化问题发表自己的意见……我们反对文化沙文主义和文化歧视,并认为此类行为是反文化的。华夏56个民族共同创造的中华文化,至今仍是全体中国人和海外华人的精神家园、情感纽带和身分认同……?

我们接受自由、民主、公正、人权、法治、种族平等、国家主权等价值观。我们确信,中华文化注重人格、注重伦理、注重利他、注重和谐的东方品格和释放和平信息的人文精神,对于思考和消解当今世界个人至上、物欲至上、恶性竞争、掠夺性开发以及种种令人忧虑的现象,对于追求人类的安宁与幸福,必将提供重要的思想启示。

我们呼吁包括中国政府在内的各国政府推行积极有效的文化政策:捍卫世界文明的多样性,理解和尊重异质文明;保护各国、各民族的文化传承;实现公平的多种文化形态的表达与传播;推行公民教育,特别是未成年人的文化、道德教育,以及激励国家、民族和地区间的文化交流。

把学生作答的卷子都收回来;很快地翻一下,果然不出所料,所有的学生都答复“赞成”,而且努力地试图演绎《甲申宣言》的立场。“文化多样”这个标语或概念显然已经成为非常“政治正确”的主流思想。这个时候再发第二阶段的考题:

“政治正确”的东西不一定正确。请详细回答下列问题:

A.“我们主张文明对话,以减少偏见、减少敌意,消弥隔阂,消弥误解。我们反对排斥异质文明的狭隘民族主义,更反对以优劣论文明,或者将不同文明之间的关系形容为不可调和的冲突,甚至认为这种冲突将导致灾难性的政治角力和战争。”

1.何谓“狭隘”的民族主义?与“不狭隘”的民族主义差别何在?“狭隘的民族主义”是否一定“排斥异质文明”?“异质文明”又如何界定?纳粹德国是极端的民族主义者,可是并不排斥来自意大利的“法西斯”内容和仪式。多少共产国家,从苏联到阿尔巴尼亚到越南,曾经既是民族主义者又是国际主义者?或者,有多少国家,有时候是民族主义者,一转身又是国际主义者?也就是说,当“异质文明”符合“狭隘的民族主义”所需时,随时可以被拥抱,因此,不“排斥异质文明”不一定代表心灵的开放和“文明对话”。请提出你的看法。

2.“排斥异质文明”是否一定等同“狭隘的民族主义”?近数年来,欧洲国家最大的辩论之一便是,如何对待伊斯兰文化中某些价值观,譬如所谓“荣誉处死”。在德国和英国都有来自伊斯兰国家的移民妇女被自己的家族杀害,理由是这些妇女违反了某些伊斯兰的“荣誉”观,譬如跟不为家族所认可的男性交往。当这些以基督教价值为主流的国家要对加害者进行审判时,争议的关键就是:所谓“荣誉处死”这种“异质文明”,是不是应该被德国或英国这种基督教国家所“排斥”?如果“排斥”这种“异质文明”,是否就成为“狭隘的民族主义?

事实上,当欧洲知识分子以“文化相对论”的理由来要求容忍“荣誉处死”这种价值时,最强烈的反对声音来自伊斯兰世界内部的知识分子,很多人认为“荣誉处死”根本不能代表伊斯兰文化,而是被曲解滥用了。他们认为,欧洲知识分子所谓对“异质文明”的尊重,落实了反而是对伊斯兰人权的践踏。请阐述你的立场。

3.你是否也反对“以优劣论文明”?是否也反对“将不同文明之间的关系形容为不可调和的冲突,甚至认为这种冲突将导致灾难性的政治角力和战争”?如果否,请解释为何文明可以论“优劣”。如果是,请回答以下问题:

a.在崇尚“荣誉处死”和认为“荣誉处死”就是谋杀的两种文明之中,有没有“优劣”之分?

b.这是否应该被解释为两个“文明”之间的冲突?可不可能,“荣誉处死”这样的议题,在伊斯兰文明内部本身就有争议和冲突?

c.两千五百年前,雅典国王在纪念阵亡将士时,叙述雅典价值和斯巴达价值的差异:“雅典的政府管治尊崇多数而非少数,因此它被称为民主。在生活领域里,我们主张法律之前,人人平等……我们和敌对国的不同更在于,我们是开放的,绝不排斥外国人在本国的学习或观察机会,即使我们的开放可能遭敌对国利用……在教育上,敌对国从人民在襁褓中就开始残酷劳其筋骨,我们却主张个性教育。”请问雅典和斯巴达所代表的两种“文明”间,是否也没有“优劣”之分?

d.英籍作家Rushdie因作品贾祸,被伊朗发出“追杀令”而不得不藏匿多年;丹麦漫画家作品因为被认为亵渎伊斯兰宗教而引起欧洲多国使馆被焚;九一一事件引发全球恐怖行动。请问文明之间的冲突可不可能“导致灾难性的政治角力和战争”?如果这些国际冲突不是“文明”之间的冲突,那么它是什么?

B.“我们主张每个国家、民族都有权利和义务保存和发展自己的传统文化;都有权利自主选择接受、不完全接受或在某些具体领域完全不接受外来文化因素;同时也有权利对人类共同面临的文化问题发表自己的意见。”

1.请问“传统文化”由谁来界定?如果是政府,是统治者吗?如果是民间,是多数族群吗?是权力阶层吗?譬如中国文化中,经世致用的儒家固属传统,主张无为的老庄是不是?即使在儒家思想中,讲究君君臣臣的孔子固属传统,强调“君为轻,社稷为重”的孟子是不是?汉族的史观固属传统,满、蒙、回、藏、苗、瑶、维吾尔的史观算不算?如果“自己的传统”和“自己的传统”之间有矛盾时,请问“每个国家、民族都有权利和义务保存和发展自己的传统文化”这句话如何解释?如何落实?

2.谁有权利来决定“选择接受、不完全接受或在某些具体领域完全不接受外来文化因素”?政府吗?统治者吗?另外,“选择接受”、“不完全接受”、“完全不接受”外来文化的选择依据是什么?宣言中这句话要如何执行?

3.谁能代表一个国家里的全体国民去“对人类共同面临的文化问题发表自己的意见”?政府吗?统治者吗?知识菁英吗?

C.“华夏56个民族共同创造的中华文化,至今仍是全体中国人和海外华人的精神家园、情感纽带和身分认同。”

1.你同意吗?你有权利不同意吗?

2.试界定“海外华人”——是否包括美籍华人或新加坡、马来西亚华人?譬如新加坡人,他们应该把“华夏56个民族”的中华文化当作“身分认同”吗?如果是,他们与同国的马来人如何共处?

3.这一句陈述,和B的陈述有无矛盾?

D.“我们确信,中华文化注重人格、注重伦理、注重利他、注重和谐的东方品格和释放和平信息的人文精神,对于思考和消解当今世界个人至上、物欲至上、恶性竞争、掠夺性开发以及种种令人忧虑的现象,对于追求人类的安宁与幸福,必将提供重要的思想启示。”

1.你是否同意此处对“东方品格”的认定?

2.你是否同意作者的论断?

E.“我们呼吁包括中国政府在内的各国政府推行积极有效的文化政策:捍卫世界文明的多样性,理解和尊重异质文明;保护各国、各民族的文化传承;实现公平的多种文化形态的表达与传播;推行公民教育,特别是未成年人的文化、道德教育,以及激励国家、民族和地区间的文化交流。”

1.“焚书坑儒”是秦始皇“积极而有效的文化政策”。“文字狱”的恐吓与“博学鸿儒”的招安是清朝统治者“积极而有效的文化政策”。纳粹和前苏联都曾有过“积极而有效的文化政策”,同时,文化政策也是培养人才、提升国民素养的手段。你认为,什么是政府可以做的,什么是政府不可以做的?

2.联合国从2003年开始推动“保存及提倡文化多样性宣言”,在2005年10月终于得到154个会员国的签署,只有美国和以色列两个国家投反对票。此“宣言”由加拿大发起,法国主推。加拿大发起之初衷是由于加拿大限制美国杂志进口,被美国告到联合国,指控加国违反世界贸易组织的规定。法国则是强烈的“文化特殊主义”者,认为文化与其它商品不同,必须受到主权国家的保护,譬如,它用政策手段防堵美国影片进入法国市场。此两国遂发起《保存及发扬世界文化多样性宣言》的联署行动,主要目标在防堵美国文化商品的渗透和垄断。意即,在“文化多样性”的背后,其实有极大的商业利益的角力。

2005年联合国《文化宣言》得胜,支持者宣称,尔后各国得以不被美国文化霸权所主宰,文化多样性得以保存。反对者则忧虑,许多国家将以此“宣言”为依据,打着保存“文化多样性”的旗帜,不让国际的电影、杂志、报纸、网络信息进入国内,剥夺人民和全球同步的知识权,造成统治者意识形态的文化垄断。

以此国际背景重新阅读《甲申文化宣言》,请评论其意义所在。

做过第二道考卷之后,学生得到“教训”了,来跟我说:以后知道什么叫“批判阅读”了。

附:

甲申文化宣言

当今,几乎所有的政治家、思想家、科学家、企业家、作家艺术家和人文学者都在关注和谈论全球化。这一显见的世界趋势既推动了人类现代文明特别是科技成就和企业经验的共享,也凸显出国家、民族、地区之间不同文明的差异、分歧和冲突。

鉴于此,我们响应许嘉璐、季羡林、任继愈、杨振宁、王蒙5位发起人的提议,应中华民族文化促进会邀请,于2004(甲申)年93日-5日在北京举行“2004文化高峰论坛”,愿藉此向海内外同胞,向国际社会表达我们的文化主张。

文明多样性是人类文化存有的基本形态。不同国家和民族的起源、地域环境和历史过程各不相同,而色彩斑斓的人文图景,正是不同文明之间相互解读、辨识、竞争、对话和交融的动力。我们期待,经历过全球化的洗礼,原生状态的、相对独立的多样文明将获得更为广泛的参照,更为坚定的认同。文明既属于历史范畴,既已成为不同族群的恒久信仰、行为方式和习俗,则理应受到普遍的尊重。我们主张文明对话,以减少偏见、减少敌意,消弭隔阂、消弭误解。我们反对排斥异质文明的狭隘民族主义,更反对以优劣论文明,或者将不同文明之间的关系形容为不可调和的冲突,甚至认为这种冲突将导致灾难性的政治角力和战争。

文化既涵盖价值观与创造力,也包括知识体系和生活方式。文化多元化对于全球范围的人文生态,犹如生物多样性对于维持物种平衡那样必不可少。我们主张每个国家、民族都有权利和义务保存和发展自己的传统文化;都有权利自主选择接受、不完全接受或在某些具体领域完全不接受外来文化因素;同时也有权对人类共同面临的文化问题发表自己的意见。我们为世界上许多古老民族、经济次发达地区的文化命运深感忧虑。国家不论大小、历史不论长短、国力不论强弱,在文化交往和交流方面均享有平等权利。我们反对文化沙文主义和文化歧视,并认为此类行为是反文化的。

华夏56个民族共同创造的中华文化,至今仍是全体中国人和海外华人的精神家园、情感纽带和身份认同。应当认识,中华文化五千年生生不息、绵延不断的重要原因,在于她是发生于上古时代多个区域、多个民族、多种形态的文化综合体。她不但有自强的力量,而且有兼容的气度、灵变的智慧。当是时也,我们应当与时俱进,反思自己的传统文化,学习和吸收世界各国文化的优长,以发展中国的文化。我们接受自由、民主、公正、人权、法治、种族平等、国家主权等价值观。我们确信,中华文化注重人格、注重伦理、注重利他、注重和谐的东方品格和释放着和平信息的人文精神,对于思考和消解当今世界个人至上、物欲至上、恶性竞争、掠夺性开发以及种种令人忧虑的现象,对于追求人类的安宁与幸福,必将提供重要的思想启示。

我们呼吁包括中国政府在内的各国政府推行积极有效的文化政策:捍卫世界文明的多样性,理解和尊重异质文明;保护各国、各民族的文化传统;实现公平的多种文化形态的表达与传播;推行公民教育,特别是未成年人的文化、道德教育,以及激励国家、民族和地区间的文化交流。

文化价值的体现和文明的进步,还将有待于伟大的创造和成功的实践。我们愿与海内外华人一起,为弘扬中华文化而不懈努力,愿与世界各国人民一起,为促进人类文明与社会发展共同奋斗!

许嘉璐  季羡林  任继愈、杨振宁、王蒙

于广华  于友先  马金凤  马博敏  王 石  王立平  王纪言  王晓棠  白先勇  白淑湘  田爱习  叶嘉瑩  冯骥才  汤一介  李 立  乔 羽  吕厚民  刘厚生  刘国平  刘诗昆  刘效礼  刘梦溪  朱建荣  任晓兵  许倬云  何伟康  何慈全  何超明  吴祖强  陈映真  邵 恩  杨兆麟  苏树辉  杜维明  阿不都热依木·热介甫  阿 米  贡 敏  张信刚  张继刚  尚长荣  庞 朴  周小燕  周文中  周汝昌  周颖南  金坚范  胡 恩  费明仪  高占祥  萧 马  尉天池  黄会林  黄苗子  黄俊杰  曹泽林  梅葆玖  寇世勋  辜正坤  谢 晋  焦 晃  詹建俊  满都大  裘锡圭  熊召政  潘震宙