乐者为王

Do one thing, and do it well.

使用USB在ThinkPad X60上安装Ubuntu 8.04

昨天晚上开始在我的本本上安装Ubuntu 8.04。本本是80G的硬盘,自带有一个XP Home操作系统。现在我想把Ubuntu装在C盘下,也就是不要XP了,并且不想再保留ThinkPad出厂时用来做HPA的隐藏分区,因此可以给Ubuntu使用的主分区就有了四个。分区方案如下:

1
2
3
4
5
Device     Type  MountPoint  Size
/dev/sda1  ext3  /boot       197M
/dev/sda2  swap  /swap       1028M
/dev/sda3  ext3  /home       48800M
/dev/sda4  ext3  /           29997M

Linux至少需要两个分区,一个是根分区,一个是交换分区,这样还剩下两个主分区可以使用。因为/home相当于Windows系统中的My Documents,所以准备给它单独分个区。剩下的一个主分区就给/boot挂载点。分配单独的分区给/boot是有必要的,因为/boot包含了操作系统的内核和在启动系统过程中所要用到的文件,这样就算工作分区出了问题,只要这个分区没有问题,系统照样可以启动。

安装步骤:

  1. 准备一个至少1G优盘;
  2. 下载Ub8convert2.exe。运行这个文件,将会获得一个Ubuntu8目录;
  3. 下载ubuntu-8.04-desktop-i386.iso,将它放到Ubuntu8目录下;
  4. 运行Ubuntu8目录下的fixu8.bat脚本(注意:fixu.bat采用的是utf-8编码,需要重新编辑该文件中的盘符);
  5. 现在就可以使用U盘来安装Ubuntu了。

注意:如果内存小于512M,那么最好分配两倍内存容量的swap分区。否则只要2的n次方就可以了。

[SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property

使用Tomcat 6.0.16搭配Eclipse创建Dynamic Web Project后,在项目上按右键,选择Run As -> Run on Server方式启动Tomcat服务器。在Console工作台中就会出现如下的红色警告信息,让人不爽。

1
2
3
4
5
2008-6-4 21:49:00 org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.j2ee.server:cont' did not find a matching property.
2008-6-4 21:49:00 org.apache.catalina.core.AprLifecycleListener init
2008-6-4 21:49:00 org.apache.coyote.http11.Http11Protocol init
INFO: Initializing Coyote HTTP/1.1 on http-8080

在网上查找答案,有的说将Tomcat的版本换成6.0.14就可以了;还有的说在建立Dynamic Web Project时把“Dynamic Web Module”选项后面的版本号由2.5改成2.4也行。不过这些回答好像都不能真正地解决问题。只能自己想办法了。

实际上出现SetPropertiesRule警告的原因是因为Tomcat在server.xml的Context节点中不支持source属性:

1
<Context docBase="xxx" path="/cont" source="org.eclipse.jst.j2ee.server:cont" />

解决方法是在Server的配置界面中选中“Publish module contexts to separate XML files”选项。

《Java和JavaScript关于日期计算上的差异》阅读笔记

下面是Java和JavaScript关于日期计算上的差异作者给出的结论:

当进行日期计算的时候,当前日期的月份必须是大月,并且是在这个月的最后一天也就是31号,比如2008-3-31号,当给这个日期加上一个月,得到的日期是个小月就会出现这样的情况。比如在2008-3-31这天加上一月,那因该是4月份,4月就是小月,那Java就是4月30号,JavaScript 就是5月1号,相差一天。当加上2月后,就是5月,5月是大月,那么计算的结果都是5月31号。

不过这样的结论还是不能让人明白Java和JavaScript计算日期时相差的一天是怎么来的。

下面是我对Java和JavaScript日期计算差异的一些理解:

2008-2-29加上12个月,那么就是2009-2-29,但2009年是非闰年,它的2月份只有28天,这样就多出来的一天。如何处理这多出来的一天呢?Java和JavaScript做出了不同的理解。Java认为,既然2009年的2月只有28天,那么那多出来的一天就是多余的,应该丢弃,所以Java的计算结果是2009-2-28;而JavaScript则认为这多出来的一天不能丢弃,应该也加上去。那么2009-2-28号加上一天就是2009-3-31号。

同样的,2008-3-31加上一个月在Java中的结果是2008-4-30号,而在JavaScript中则是2008-5-1号。那如果加上的是两个月呢?2008-3-31加上两个月是2008-5-31号,是有效的日期,所以Java和JavaScript的计算结果都是2008-5-31号。

结论是,当进行日期计算时,如果结果日期的date值超出了该月的最大天数值,那么在Java中就会将该date值设为该月的最大天数值;而JavaScript则不但会将该date值设为该月的最大天数值,还会再加上超出的天数值。例如:2009-1-31号加上一个月,Java的结果就是2009-2-28号,JavaScript的结果则是2009-3-3号,2009-2-28加多出来的3 = 31 - 28天。

完成了wxWidgets Wizard for Visual Studio 2005/2008的安装程序

两个晚上的时间,一边查资料一边学习,同时编写和测试安装脚本,最终完成了wxWidgets Wizard for Visual Studio 2005/2008的安装程序。现在不用配置就可以使用wxWidgets Wizard的代码框架生成功能了。安装制作程序采用的是Inno Setup,完整的安装脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#define SrcImgsDir '..\VCWizards\images'
#define SrcHtmlDir '..\VCWizards\html\1033'
#define SrcScptDir '..\VCWizards\scripts\1033'
#define SrcTempDir '..\VCWizards\templates\1033'
#define TgtImgsDir 'VCWizards\AppWiz\wxWidgets\Application\images'
#define TgtHtmlDir 'VCWizards\AppWiz\wxWidgets\Application\html\1033'
#define TgtScptDir 'VCWizards\AppWiz\wxWidgets\Application\scripts\1033'
#define TgtTempDir 'VCWizards\AppWiz\wxWidgets\Application\templates\1033'

[Setup]
AppName=wxWidgets Application Wizard
AppVerName=wxWidgets Wizard 1.0.0
AppPublisher=dohkoos
DefaultDirName={pf32}\Microsoft Visual Studio 9.0\VC
DirExistsWarning=no
;Uninstallable=no
UninstallFilesDir={app}\VCWizards\AppWiz\wxWidgets
UninstallDisplayIcon={app}\VCProjects\wxAppWiz.ico
Compression=lzma
SolidCompression=yes

[Files]
Source: ..\VCProjects\wxAppWiz.ico; DestDir: {app}\VCProjects
Source: ..\VCProjects\wxAppWiz.vsz; DestDir: {app}\VCProjects
Source: ..\VCProjects\wxWidgets\wxWidgets.vsdir; DestDir: {app}\VCProjects\wxWidgets
Source: {#SrcImgsDir}\*.gif; DestDir: {app}\{#TgtImgsDir}
Source: {#SrcHtmlDir}\*.htm; DestDir: {app}\{#TgtHtmlDir}
Source: {#SrcHtmlDir}\*.css; DestDir: {app}\{#TgtHtmlDir}
Source: {#SrcScptDir}\*.js; DestDir: {app}\{#TgtScptDir}
Source: {#SrcTempDir}\*.h; DestDir: {app}\{#TgtTempDir}
Source: {#SrcTempDir}\*.cpp; DestDir: {app}\{#TgtTempDir}
Source: {#SrcTempDir}\readme.txt; DestDir: {app}\{#TgtTempDir}
Source: {#SrcTempDir}\root.manifest; DestDir: {app}\{#TgtTempDir}
Source: {#SrcTempDir}\Templates.inf; DestDir: {app}\{#TgtTempDir}

[Code]
procedure CurStepChanged(CurStep: TSetupStep);
var
    i: Integer;
    Signature: String;
    ConfigLine: String;
    ConfigFile: String;
    ConfigFileLines: TArrayOfString;
begin
    if CurStep = ssPostInstall then begin
        Signature := 'wxWidgets';
        ConfigLine := 'wxWidgets|{1B027A40-8F43-11D0-8D11-00A0C91BC942}|#1043|70' + #13#10;
        ConfigFile := ExpandConstant('{app}\VCProjects\vc.vsdir');
        LoadStringsFromFile(ConfigFile, ConfigFileLines);
        for i := 0 to GetArrayLength(ConfigFileLines) - 1 do begin
            if (Pos(Signature, ConfigFileLines[i]) > 0) then abort;
        end;
        SaveStringToFile(ConfigFile, ConfigLine, True);
    end;
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
    i: Integer;
    j: Integer;
    Signature: String;
    ConfigFile: String;
    ConfigFileLines, NewConfigFileLines: TArrayOfString;
begin
    if CurUninstallStep = usUninstall then begin
        Signature := 'wxWidgets';
        ConfigFile := ExpandConstant('{app}\VCProjects\vc.vsdir');
        LoadStringsFromFile(ConfigFile, ConfigFileLines);
        SetArrayLength(NewConfigFileLines, GetArrayLength(ConfigFileLines) - 1);
        j := 0;
        for i := 0 to GetArrayLength(ConfigFileLines) - 1 do begin
            if (Pos(Signature, ConfigFileLines[i]) > 0) then begin
                continue;
            end else begin
                NewConfigFileLines[j] := ConfigFileLines[i];
                j := j + 1;
            end;
        end;
        SaveStringsToFile(ConfigFile, NewConfigFileLines, False);
    end;
end;

代码下载:https://github.com/dohkoos/wxwizard

如何命名你的项目的10个技巧

英文原文:http://www.wynia.org/wordpress/2006/06/22/10-tips-for-how-to-name-your-project/

这是我在几年前写的系列文章中的一篇,但是我想再分享一下。给那些开始产品和服务的人们,他们需要一些说明,以便于理解、发音或正确拼写产品和服务的名字,我想该文章的价值就如同我第一次写它的时候一样。

如何(以及避免那样)命名你的项目

  1. 如果你考虑的名字是直接取自科幻或奇幻作品,不必费心了。这些名字在软件中作为命名源的比例非常大。不仅是你想出有独创性名字的机会相当小,而且大部分作品中的角色和地方的名字都被商标化了,你要冒着被起诉的危险。
  2. 如果你考虑的名字来自于希腊、罗马或北欧神话,再试一次。我们已经有了足够多的被称为“Mercury”变体的邮件相关软件。
  3. 在Google上搜索被提议的名字。你得到的结果越少越好。如果没有结果,那么就是它。
  4. 不要试图通过轻微拼错单词得到唯一名字。把新窗口文件系统程序叫做Phat32只会以用户沮丧的看着“fat32”在搜索引擎中的结果而告终。
  5. 如果你的产品名称不能在电视上用50秒或60秒说完,你或许走在了错误的道路上。如果你希望任何人在工作环境使用你的产品,这尤其适用。没有人会去推荐一个产品给他们的工友,如果他们会遭到性骚扰起诉只是为了说出产品的名称。
  6. 如果你的产品名称根本不能被发音,你就完全得不到口碑的好处。同样,如果没人知道如何去发音它,他们就非常有可能不会试着大声的说着它去询问关于它的问题,等等。你怎么说MySQL? PostgreSQL? GNU? 在地球上的几乎所有口语都是基于某类辅音/元音音节。在辅音和元音之间交替是一个相当好的方式保证别人能够发音它。
  7. 越短越好。
  8. 查看.com域名是否有效。如果不是,那就证明有人比你先想到了这个名称,并且正在使用它或接近使用它。即使你不打算使用域名也要做这一步。
  9. 不要让你产品中固有的局限性成为名称的一部分。把你的产品名称叫做LinProduct或WinProduct预先的就永远阻止你发布任一类的跨平台版本。
  10. 不要使用你自己的名字来命名开源产品。如果项目在你不再参与开发后仍然活着,项目要么是重命名,要么就是你的名字可能会被使用在你意想不到的地方。

2017/5/3更新

从长远来看,造个新词是取名的最好方式。虽然在创造新词后把它投放市场,它的认知度很有可能会低迷一段时间。但如果你能成功创造一个新词,并且可以用日常用语来介绍和解释,那么你就拥有了它。它变成了一个不会和任何其它名字混淆,并且不会被竞争者侵占的重要区分资产。在最好的情况下,你最终会定义一个全新的类别——Levis、Nike、eBay、QQ。

延长Windows Server 2008的评估期限

今天,对正在使用的Windows Server 2008做了一次延长评估期限的操作。

  1. Click Start, and then click Command Prompt.
  2. Type slmgr.vbs -dli, and then press ENTER to check the current status of your evaluation period.
  3. To reset the evaluation period, type slmgr.vbs -rearm, and then press ENTER.
  4. Restart the computer.

This resets the evaluation period to 60 days.

在做完延长操作后终于明白了网上关于“当您重置当前60天评估期,丢失以前60天评估期上保留任何时间”译文的意思,也即上面“This resets the evaluation period to 60 days”的意思。它是指不管你当前剩余的评估时间是多少,重置之后都会变成60天。例如,我在重置前的评估期还剩有25天,在重置后就变成了60天,并不是加上60天,变成85天。因此,要想最大化总的评估时间,最好到接近评估时间末尾时再重置评估期。

完整的KB可以查看这里

使用ANTLR构建PowerScript语法分析器(6)

构建完表达式的语法规则后就可以开始分析语句(statement)的语法规则。不过在这之前还需要先修复两个小缺陷:没有识别日期、时间和内建常量的词法规则。

在PowerScript中,日期的格式是0000-00-00,年份是4位数从1000到3000,月份从01到12,天数从01到31;时间是24小时格式00:00:00:000000,秒的小数部分可有可无,最多能有6位数字,所以时间范围是从00:00:00到23:59:59:999999。内建常量则以字母开头,字母数字组合,以“!”符号结束的字符串。

根据这些描述我们可以得到日期、时间和内建常量的词法规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
DATE_LITERAL    // 1996-09-26
    : '1'..'3' '0'..'9' '0'..'9' '0'..'9' '-' '0'..'1' '0'..'9' '-' '0'..'3' '0'..'9'
      {
          System.out.println("date>" + getText());
      }
    ;

TIME_LITERAL    // 00:00:00:000000
    : '0'..'2' '0'..'9' ':' '0'..'5' '0'..'9' ':' '0'..'5' '0'..'9'
      ( '.' '0'..'9'
      | '0'..'9' '0'..'9'
      | '0'..'9' '0'..'9' '0'..'9'
      | '0'..'9' '0'..'9' '0'..'9' '0'..'9'
      | '0'..'9' '0'..'9' '0'..'9' '0'..'9' '0'..'9'
      | '0'..'9' '0'..'9' '0'..'9' '0'..'9' '0'..'9' '0'..'9'
      )?
      {
          System.out.println("time>" + getText());
      }
    ;

ENUM_LITERAL
    : Letter (Letter|'0'..'9')* '!'
      {
          System.out.println("enum>" + getText());
      }
    ;

使用ANTLR构建PowerScript语法分析器(5)

基本表达式的语法规则构建完毕,那么表达式的语法规则构建就颇为简单了。使用ANTLR构建PowerScript语法分析器(4)中已经说过表达式是由运算元和运算符复合组成。所以在编写表达式语法规则前先要分析下PowerScript的运算符以及它们的优先级。

PowerScript支持四种类型的运算符,分别是:

  • 针对数字数据类型的算术运算符,执行算术计算;
  • 针对所有类型的关系运算符,比较数字,文本和布尔值;
  • 针对布尔类型的逻辑运算符,执行布尔值上的关系运算符
  • 针对字符串类型连接运算符,连接字符串和二进制大对象。

算术运算符

Operator Meaning
+ Addition
- Subtraction
* Multiplication
/ Division
^ Exponentiation

关系运算符

Operator Meaning
= Equals
> Greater than
< Less than
<> Not equal
>= Greater than or equal
<= Less than or equal

逻辑运算符

Operator Meaning
NOT Logical negation
AND Logical and
OR Logical or

连接运算符

Operator Meaning
+ Concatenate

运算符优先级

Operator Purpose
( ) Grouping (see note below on overriding)
+, - Unary plus and unary minus (indicates positive or negative number)
^ Exponentiation
*, / Multiplication and division
+, - Addition and subtraction; string concatenation
=, >, <, <=, >=, <> Relational operators
NOT Negation
AND Logical and
OR Logical or

清楚运算符和优先级后,该如何表示这些表达式的语法关系呢?有个标准的分析表达式的递归定义可以套用,大部分表达式都遵循这个模式:

1
2
thisLevelExpression
    : nextHigherPrecedenceExpression (OPERATOR nextHigherPrecedenceExpression)*

现在我们就可以根据PowerScript的运算符优先级写出表达式的语法规则了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
expression
    : logical_or_expression
    ;

logical_or_expression
    : logical_and_expression ('or' logical_and_expression)*
    ;

logical_and_expression
    : logical_not_expression ('and' logical_not_expression)*
    ;

logical_not_expression
    : 'not'? relational_expression
    ;

relational_expression
    : additive_expression (('='|'>'|'<'|'<>'|'>='|'<=') additive_expression)*
    ;

additive_expression
    : multiplicative_expression (('+'|'-') multiplicative_expression)*
    ;

multiplicative_expression
    : exponentive_expression (('*'|'/') exponentive_expression)*
    ;

exponentive_expression
    : unary_expression ('^' unary_expression)*
    ;

unary_expression
    : ('+'|'-')? primary_expression
    ;

使用ANTLR构建PowerScript语法分析器(4)

到目前为止,PowerScript的词法分析已经完成的差不多了,接下来就要开始实现它的语法规则。我们准备先从表达式(expression)开始下手,因为它是语法规则中最核心的部分。

简单的来说,表达式是计算的最小单元,是可以被计算产生值的代码的任何部分。一般是由一个或多个运算元和通常是一个运算符构成,运算元本身也可以是表达式。这样层层递归嵌套,直到被称为基本表达式(primary expression)的最简单部分。

基本表达式包含有标志符、字面量(literal)、字段存取、函数调用和数组存取等,圆括号括起的表达式通常也被认为是基本表达式。以下是它们的大致表现形式:

1
2
3
4
5
6
rating
'This is a string'
x.y
f(x)
a[x]
(x)

在PowerScript中调用函数和事件的语法如下:

1
{ objectname. } { ancestorname :: } { type } { calltype } { when } name ( { argumentlist } )

其中,花括号中的项表示可以有可以无。type有两个值function和event,calltype有两个值static和dynamic,when有两个值trigger和post,并且type,calltype和when的顺序可以任意调换。如果ancestorclass是当前对象的直接父类的话,那么可以使用super关键字代替。

这里是收集的一些基本表达式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
this.ls_array[1]
this.event pfc_addrow()
this.event rowfocuschanged(ll_row)
this.event post doubleclicked(xpos, ypos, row, dwo)
this.uo_1.function hallo()
post function column_order_update_from_grid()
event ue_process()

close(parent)
parent.enabled
parent.hide()
parent.event ue_postconstructor()
parent.function static trigger wf_process( )
parent.post uf_process_item ()

super::create
super::event clicked()
super::event clicked(xpos, ypos, row, dwo)
super::of_remove_tail(anv_tailnode)
super::event trigger selectionchanging(oldindex, newindex)

iu_tab_postings.post of_enable_sort(dw_main, dw_detail, false)
lw_sheet.dynamic event pfc_close()
w_main.event doubleclicked(flags, xpos, ypos)
dw_main.event pfc_retrieve()
cb_ok.event trigger clicked()
cb_ok.triggerevent(clicked!)

有了以上的这些信息,我们就可以很容易地得到基本表达式的语法规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
expression_list
    : expression (',' expression)*
    ;

expression
    : primary_expression
    ;

primary_expression
    : '(' expression ')'
    | (object_name '.')* (ancestor_name '::')? call_specifier* IDENTIFIER identifier_suffix?
    | literal
    | '::'? object_name
    ;

object_name
    : 'this'
    | 'parent'
    | IDENTIFIER
    ;

ancestor_name
    : 'super'
    | IDENTIFIER
    ;

call_specifier
    : 'function'
    | 'event'
    | 'static'
    | 'dynamic'
    | 'trigger'
    | 'post'
    ;

identifier_suffix
    : arguments ('.' IDENTIFIER arguments)*    // cascaded calling
    | '[' expression_list? ']'
    ;

arguments
    : '(' expression_list? ')'
    ;

literal
    : STRING_LITERAL
    | INTEGER_LITERAL
    | FLOAT_LITERAL
    | BOOLEAN_LITERAL
    | LINE_COMMENT
    | BLOCK_COMMENT
    ;

不过,如果到这里就开始用ANTLR工具生成词法分析器和语法分析器的话,你会得到一堆的警告信息。要消除这些警告需要在语法文件头部添加:

1
2
3
options {
    backtrack=true;
}

它的作用是告诉ANTLR在LL(*)语法分析失败的时候要去尝试匹配其它选项。

Cannot launch the remote parser because port 49153 is already in use

在Windows Server 2008中使用ANTLRWorks调试语法时,总是提示说什么端口49153已被占用。使用netstat -an发现这个端口正在被别的进程监听着,虽然知道问题原因,但是不知道如何解决。后来从如果AntlrWorks的Debug报错“当前端口已被占用”,可能是防火墙的原因得到启示:AntlrWorks是可以修改远程调试端口的。不过我没有像该文作者介绍的那样将调试端口改成49253,因为那样可能需要设置防火墙。而是直接将之设置到了一个不在使用的端口49151上。

设置调试端口的路径如下:

File -> Preferences -> Debugger -> Default local port