乐者为王

Do one thing, and do it well.

用Rails 2.3打造简单记账应用(1)

我们先来定义一下什么是最简单的记账应用:

  1. 可以输入花钱的记录;
  2. 可以修改输入了的记录;
  3. 可以删除输入了的记录;
  4. 可以显示所有的记录。

下面我们就开始动手吧!

1
2
3
rails -d mysql qianbao
cd qianbao
rake db:create  # 在这之前要把数据库用户名和密码填写到config/database.yml中

从Rails 2.0开始,scaffold就从核心中移除了,不过可以直接作为script/generate对象来使用,所以现在scaffold的语法是这样子的:

1
script/generate scaffold model_name [field:type field:type]

具体细节可以使用script/generate scaffold命令查看。

1
2
3
script/generate scaffold entry amount:decimal tags:string comment:text
rake db:migrate
script/server

打开浏览器输入并访问http://localhost:3000/entries

怎么样,一个简单的记账应用是不是已经做好了。

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

在Windows Server 2008下安装Android SDK 2.0

SDK Setup.exe在Windows Server 2008上是无法执行的,看Readme文档知道可以用命令行的方式更新。不过不带参数执行时抛出了下面的错误:

1
2
3
Starting Android SDK Updater
SWT folder 'lib\x86_64' does not exist.
Please set ANDROID_SWT to point to the folder containing swt.jar for your platform.

查看tools/android.bat代码后发现有个bug,在拷贝代码时没有考虑x86_64平台的问题。找到如下代码:

1
xcopy lib\x86 %tmpdir%\lib\x86 /I /E /C /G /R /Y /Q > nul

把它改成

1
xcopy %swt_path% %tmpdir%\%swt_path% /I /E /C /G /R /Y /Q > nul

或者也可以在环境变量中添加ANDROID_SWT,使它指向lib\x86_64\swt.jar文件的位置。

10块钱破解指纹考勤

前段时间报名参加了驾驶员培训,结果发现了一个破解指纹识别的好办法。现在什么都讲高科技,驾驶员培训当然也不例外,在训练中就采用指纹考勤机来记录学员上车的时间,达不到规定时间的学员就不能参加考试。参加培训的都知道,经常会有学员因故缺席训练。那怎么能让学员不在也可以计算时间呢?这不,教练们只花了不到10元钱就搞定了这个问题。

材料:

  • 玻璃胶(硅酮密封胶)一瓶
  • 橡皮泥一盒

将橡皮泥搓到有点发硬的时候压平,然后在光滑的一面按上手指印,将玻璃胶挤入到手指印中,抹平,然后放置在阴凉处一段时间就行了。就这么简单!

如何在过了60天后再激活Windows Server 2008

登录系统后,会出现一个激活窗口,告诉你激活已过期,要接着使用的话就必须先激活。并提供几种激活的方式。选择第二项即Buy a new product key online,会弹出如下窗口:

点击确定,这时就会打开浏览器。在浏览器中选择打开文件菜单,找到cmd.exe文件,右键点击Run as administrator,然后执行slmgr.vbs -rearm指令,接着重启计算机就可以了。

DataWindow的数据缓冲区

在PowerBuilder中,DataWindow是用来存储和操纵数据的对象。在每个DataWindow对象中都有4个二维表作为数据缓冲区来存储数据。用户在DataWindow中对数据的操作实际上都是将数据在这几个缓冲区中进行修改和移动,最后在用户提交数据库时,系统根据这四个缓冲区中的信息形成SQL的INSERT、UPDATE、DELETE等语句。这四个缓冲区是:

Primary Buffer

这个缓冲区是存放填充窗口中DataWindow控件的数据的,调用DataWindow控件的Retrieve()函数和InsertRow()函数可以将数据填入这个缓冲区中。当使用有关DataWindow删除和过滤函数时,相应记录将从这一缓冲区中删除。而在执行DataWindow的Update()函数时,PowerBuilder将查看这一缓冲区中的记录以形成INSERT和UPDATE语句。

Delete Buffer

这个缓冲区保存的是用DeleteRow()函数从Primary Buffer中删除的记录,执行Update()函数时,系统根据这一缓冲区的记录形成DELETE语句。

Filter Buffer

这个缓冲区存储的是从Original Buffer使用Filter()函数过滤到Primary Buffer中后剩余的记录。

Original Buffer

这一缓冲区存储的是DataWindow最初执行Retrieve()函数时得到的全部记录。当提交数据库时,根据Primary Buffer生成的UPDATE语句和根据Delete Buffer生成的DELETE语句都要依据这一缓冲区来构造这些SQL语句中的WHERE子句。

Original Buffer由PowerBuilder内部维护,PowerBuilder所提供的任何函数都无法改变它的值,不过通过PowerBuilder所提供的GetItem系列函数可以读出DataWindow最初从数据库中查到的原始值。通过这些函数我们可以编程实现所谓的Undo功能,并且得到在使用乐观锁时形成提交数据库的WHERE子句。如果你当前使用的DataWindow没有设置修改的权力,你将不能对Delete Buffer和Original Buffer进行操作,而且当调用Update()时也将引起系统错误。

Primary Buffer和Delete Buffer都有行级和列级的状态值,这个状态值是一个枚举类型。在提交时由该行的状态值来决定是否要产生SQL语句,其中Primary Buffer产生的是INSERT和UPDATE语句,而Delete Buffer产生的是DELETE语句。我们用GetItemStatus()函数和SetItemStatus()函数可以对这一状态值进行操纵。这一枚举状态有以下四种:

1
2
3
4
NotModified! —— 指定单元的数据和原始数据相同,没有发生改变。
DataModified! —— 指定单元的数据和原始数据不同,发生了改变。
New! —— 该数据行是新增加的,但数据没有发生改变(数据为空或缺省值)。
NewModified! —— 该数据行是新增加的,且数据已发生改变(用户键盘输入或调用SetItem()函数)。

在上面的这四个值中,NotModifed!和DataModified!可以表示行和列的状态,而New!和NewModified!只可以表示行的状态。

让我们来看一个实例。有这样一张表,表中有3个字段,其中item是主键。

1
2
3
item CHAR(5)
name CHAR(20)
quantity INT

在代码中我们查询这张表的记录,得到以下的这些信息,它们被存储在Primary Buffer和Origianal Buffer中。

在窗口中,我们过滤掉数量为0的行,并且加上一个空行:

1
2
3
dw_1.SetFilter("quantity=0")
dw_1.Filter()
dw_1.InsertRow()

这时Primary Buffer的状态为:

在Filter Buffer中的记录为:

用户在新插入行中输入数据,删除了第3行数据,并修改了第2行数据。当他离开这个DataWindow时,Primary Buffer和Delete Buffer的状态如下:

这时执行dw_1.Update()函数,系统将基于这两个缓冲区生成SQL语句。

在Primary Buffer中,状态为NotModified!和New!的行将被忽略而不产生SQL语句。状态为DataModified!的行将产生UPDATE语句,状态为NewModified!的行将产生INSERT语句,在Delete Buffer中的行将产生DELETE语句。使用DataWindow的Reset()函数和Retrieve()函数以及改变DataObject属性时,系统将重置这几个缓冲区。

利用WHOIS协议查询域名信息

域名信息的查询原理非常简单,主要是基于RFC 954(RFC 812已被废弃)提供的WHOIS协议。WHOIS服务器是一个基于“查询/响应”的TCP事务服务器,用户程序通过访问WHOIS服务器,从WHOIS数据库中查询得到我们所需要的内容。其主要过程有以下三步:

  1. 在TCP服务端口43连接WHOIS服务主机;
  2. 发送一个命令,以回车换行符结尾;
  3. 接受相应命令的返回信息,一旦输出结束,服务器将关闭连接。

命令的格式非常简单。可以直接输入域名(例如example.com)查询相关域名信息;也可以使用help得到详细的帮助信息。以下是查询的代码:

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
wxString Whois::Lookup(wxString& host, wxString& szAddress)
{
    char szQuery[512];
    char szBuffer[512];
    wxString szResult;

    strcpy(szQuery, szAddress);
    strcat(szQuery, "\r\n");

    wxIPV4address addr;
    addr.Hostname(host);
    addr.Service(43);

    wxSocketClient socket;
    socket.Connect(addr, false);
    socket.WaitOnConnect(30);

    if (socket.IsConnected())
    {
        socket.Write(szQuery, strlen(szQuery));
        szResult = "";
        while (true)
        {
            // Clear buffer before each iteration
            memset(szBuffer, 0, 512);

            // Try to receive some data
            socket.Read(szBuffer, 500);
            if (socket.LastCount() <= 0)
            {
                break;
            }
            szResult += szBuffer;
        }
    }
    else
    {
        szResult = wxT("Failed! Unable to connect\n");
    }
    socket.Close();

    return wxString::FromUTF8(szResult);
}

常用的WHOIS服务器:

1
2
3
4
5
.cn=whois.cnnic.net.cn
.com=whois.internic.com
.net=whois.internic.com
.name=www.whois.name
.cc=whois.nic.cc

FreeMind在Windows Server 2008中不能运行的问题

在Windows Server 2008下安装FreeMind后不能运行(0.8.1和0.9.0-RC4均是如此),使用的JRE是1.6.0_13。网上有的解决方法是在环境变量中添加jre\bin的路径。但是我不想这样做,想试试别的方法。

后来,从FreeMind的bug2750047中得到了启示,将javaw.exe拷贝到FreeMind的安装目录下就可以打开了。不过导致这个问题的原因目前还不清楚,因为在System32目录下确实有javaw.exe这个文件存在。不知道是不是因为安装的是64位版本的缘故。

允许客户端远程连接Lunarpages上的MySQL数据库

Lunarpages虚拟主机上的MySQL服务默认仅有本机能访问。只有在cPanel中向某IP地址或地址段或者所有地址开放访问权限后,才可以从外部用客户端连接数据库。

如果想允许任何主机的访问,直接在Host处填写百分号%,然后Add Host即可。如果只想特定主机访问,就输入客户端机器的IP地址。

客户端远程连接时使用的地址就是虚拟空间的地址,可以通过ping域名得到。

Git笔记之rebase --onto

有的时候,可能需要修改某个已提交commit。如果是修改最近提交的commit,可以使用git commit --amend命令;如果是修改更早提交的commit,可以使用git rebase -i HEAD~n。不过这个命令有个缺陷,就是不能修改最早提交的那个commit。假设有如下提交历史:

1
C1--C2--C3--C4

要修改C4可以使用git commit --amend;要修改C2、C3或C4可以使用git rebase -i HEAD~n;但是如果要修改C1呢?这就需要rebase --onto出场了。下面就来实例讲解如何使用rebase --onto命令。

因为要修改C1这个commit,所以先在它之上创建临时分支tb:

1
git checkout -b tb C1

然后就可以在tb分支上做想要的修改,改完之后用下面的命令提交更改的内容:

1
git commit -a --amend

这时查看tb分支的提交历史,可以发现SHA1值已经发生了变化(master分支的SHA1值仍然不变):

1
C1'

接着可以把修改后的内容和master分支合并:

1
git rebase --onto tb C1 master

表示把master分支上从C1之后的所有commit重新apply到tb分支最新的commit之后。

这里有两点要注意:一个是C1处的开闭问题,rebase --onto的机制是左开右闭,也就是说上述命令只会apply三个提交C2、C3和C4;第二个是rebase --onto之后tb分支的提交历史没有改变,还是只有一个提交C1’,当前分支也切换到了master,并且所有commit的SHA1值都发生了改变。

1
C1'--C2'--C3'--C4'

最后就是正常的rebase --continue流程了。

Git笔记之分割提交

在rebase命令的交互模式下,你可以对历史提交中的任意提交进行分割操作,即把某个提交分割成多个提交。具体做法如下:

  1. 使用git rebase -i <commit>^开启rebase的交互模式,这里的<commit>是你想去分割的那个提交;
  2. 用动作edit标记你想分割的提交;
  3. 回到编辑提交的界面后,执行git reset HEAD^重置索引内容,使HEAD指向上个提交,把要分割的提交中的内容释放回工作目录;
  4. 现在你可以添加、修改或删除工作目录中的文件了,然后使用add -p和commit提交你想包含的任何内容;
  5. 重复第4步创建多个提交;
  6. 分割完成后使用git rebase --continue继续后续的工作。

至此,提交就被分割成功了。