联想 Lenovo Windows Vista 简体中文 旗舰版 Ultimate BT 下载 T6x X6x 适用

联想 Lenovo Windows Vista 简体中文旗舰版

Ultimate 版本

Key:24J6Q-YJJBG-V4K4Q-2J8HY-8HBQQ

MD5: b23a4481075a76dd5632255af1064b4e

ISO 镜像大小:2.45 G

拥有 SLIC 信息的 ThinkPad 不需要输入 Key ,安装完即激活。

BT 下载的是一系列 RAR 压缩的文件,从

LENOVO_VISTA_CHS_RDVD_UM.part01.rar

LENOVO_VISTA_CHS_RDVD_UM.part53.rar

一共 53 个文件,直接双击 LENOVO_VISTA_CHS_RDVD_UM.part01.rar 即可解压,生成 LENOVO_VISTA_CHS_RDVD_UM.ISO 这个文件,大小是 2,633,132,032 字节。

在 BT 下载的文件夹里,还有一个 LENOVO_VISTA_CHS_RDVD_UM.sfv 文件和 SFVChecker.rar,解压这个压缩包,用里面的软件,装载 LENOVO_VISTA_CHS_RDVD_UM.sfv,即可检查那 53 个RAR 文件是否完整。

最后,可以用 MD5 文件校验器,检查 ISO 是否是开始提到的那个 MD5。

BT 种子: LENOVO_VISTA_CHS_RDVD_UM.torren

请用右键另存下载!

Godaddy 主机 最新优惠码 hosting promo code

今天给我的 Godaddy Deluxe Plan 主机续费一年,原价是 $75.44,上网找了一个优惠码,当在 Godaddy 消费超过 $75 时,可以优惠 $20 !折合成人民币将近 160 块钱!最后的实际花费是 $55.44,按 7.6 的汇率,换成人民币是 421.344 。

我记得,以前在国内的主机服务商,300 M 一年的价格是 ¥300。

我的 Godaddy,可以配置无限个域名,注意,是每个域名一个独立的网站!总空间是 100G,流量限制是 1TB,只有 400 多块钱!

那个比较值,大家自己合计合计吧。

下面是一些优惠码,都是大额度的哦:

gdbb776
可以 $5.99 续费域名(com, net)

gdm0938m
任何单据超过 $75 节省 15%,大约是 560 元人民币节省 85 元人民币

gdm0934h
整体优惠,特别是虚拟主机优惠幅度达到 35% 值得注意

cjchost20
购买所有主机产品优惠 20%

cjc20off75
购买 $75 及以上可以优惠 $20(我这次续费就是用的这个优惠码!)

cjctenof
购买 $50 及以上可以优惠 $10

cjcfiveoff
购买 $30 及以上可以优惠 $5

cjc695dom
$6.95 .COM 注册,续费,转移

gdm0931
9月22日优惠券,.mobi 域名 $9.9,比国内便宜了一大半,比较难得,其他产品输入这个代码也可以打折的,比如 .info 域名 $2.99

注意!

在填入优惠码的时候,要去掉前后的空格, 你在复制这些字符的时候,Windows 很有可能把后面的空格也带上了,有空格的优惠码,Godaddy 会视为无效的!

FreeBSD 公钥 Public Key SSH 登录 SecureCRT

用过几个版本的 FreeBSD,4.11、5.4、6.0、6.1 和 6.2,发现登录方式改了好几次。

都是用 SecureCRT 进行 ssh 登录,有的版本每次都要输入密码,有的就不用。

只知道随系统一起的 ssh 版本不同,但一直没弄明白怎么回事,就是觉得每次输入密码太麻烦了。

查了几次 Google 和 百度,也没太看明白。

今天决心好好查查,并实践一下。

刚装了 FreeBSD 6.2。

sshd 连接注意:
1    默认启用公钥认证及密码认证(Secure Shell Client 登录不了,用 SecureCRT 5.0 没问题)
2    不允许 root 登录(必须先建立一个用户,而且是 wheel 组的,登录后再 su 到 root)

在线更改 SSHD 默认端口:
vi /etc/ssh/sshd_config
/etc/rc.d/sshd restart
做这一步的目的,就是把默认的 22 端口改成其他的,可以减少被攻击的可能性。

使用 SSH PUBLIC KEY

假设用户名是 leakon

方法一(由 FreeBSD 生成密钥对)

1 在FreeBSD中执行
ssh-keygen -t dsa

可得到
/home/leakon/.ssh/id_dsa
/home/leakon/.ssh/id_dsa.pub

2 可以用 WinSCP 下载这个两个文件到本地,保存到
C:\Documents and Settings\leakon\Application Data\VanDyke\

这是 SecureCRT 在 Windows 的 leakon 用户的程序数据文件夹中生成的目录

3 打开会话选项,在 分类 中选择 SSH2,在右边的 身份验证 中选择 公钥(PublicKey),然后点击旁边的 属性(Properites),选择 使用会话公钥设置(Use session public key setting),在 使用身份文件(Use identify file) 的输入框中,选择刚才下载回来的 id_dsa,注意,id_dsa 和 id_dsa.pub 要保存在一起(两个文件取名任意,但必须符合 somekey 和 somekey.pub)

4 按照 /etc/ssh/sshd_config 中指定的公钥文件名 AuthorizedKeysFile .ssh/authorized_keys,修改本地公钥文件名,在FreeBSD中执行
cd /home/leakon/.ssh/
mv id_dsa.pub authorized_keys

至此,方法一大功告成,重新用 SecureCRT 连接一下试试,直接就登录好了吧!

方法二(由SecureCRT生成密钥对)

1 设置好用户名后,用刚才方法一的第 3 步,打开那个对话框,这个时候,要单击 创建身份文件(Create Identify File),然后下一步,选择 DSA,生成 Identity 和 Identity.pub 两个文件

2 把 Identity.pub 上传到 FreeBSD 的 /home/leakon/.ssh 目录下

3 在 FreeBSD 中执行
ssh-keygen -X -f Identity.pub > authorized_keys

取消sshd密码认证方式

vi /etc/ssh/sshd_config
PasswordAuthentication no
/etc/rc.d/sshd restart

硬盘 137G 容量限制 48bit LBA 寻址

最近正好要给我的笔记本换个硬盘,以前的 40G 真的不够用了,我会用 VMWare 装几个系统,比如 FreeBSD,Ubuntu 等,可是这么点硬盘,根本装不了。

由于我的笔记本比较老,是第一代迅驰,Banias 核心的 PM 1.4GHz + 855PM + 2100 无线网卡,以前听说老的芯片组最大只支持 137G 的硬盘,我想买个 160G 的,不知道我这个能不能支持。

上网查了一下,收集到一些信息,整理了一下,供大家参考吧。

其中,硬盘寻址方式的计算方法,还是值得学习一下的。

“137GB容量限制”是怎么回事?

早些时候出产的主板大多使用28bit LBA硬盘寻址方式,而LBA方式是指以逻辑块方式使用硬盘的,其中每个逻辑块的大小是512字节。于是在28位LBA硬盘寻址方式下,逻辑块数目的理论极限是2的28次方即268435456块,每块乘以512字节,则硬盘的理论容量极限就是:268435456(块)*512(字节)=137,438,953,472字节=137GB。当然,这也是由于以前人们使用的硬盘的大小通常都较小,主板的发展脚步要落后于硬盘的发展,后来到了硬盘已经超过137GB大小的时候,主板生产规则还停留在采用28bit LBA硬盘寻址的时代,于是137GB容量限制的就来了!

显然,对于硬盘生产厂家来说,解决这个137G容量极限的方法其实是非常简单的,只要使用更高的硬盘寻址位数就可以了。目前所有容量超过137G的IDE/ATA硬盘,使用的都是48位LBA寻址方式,而48位LBA寻址方式的理论容量极限是144,115,188,075,855,872字节=144,000,000 GB!

那如何判断你的主板时候支持48位LBA寻址方式呢?

可以使用Everest软件检查你的存储控制器是否支持48位 LBA。

运行软件,在左侧设备列表中选择”存储器→ATA”项,然后就可以从右侧窗口中找到是否支持48位 LBA的信息了。

Everest

趣谈 Unicode 编码

这是一篇程序员写给程序员的趣味读物。所谓趣味是指可以比较轻松地了解一些原来不清楚的概念,增进知识,类似于打RPG游戏的升级。整理这篇文章的动机是两个问题:

问题一:
使用Windows记事本的“另存为”,可以在GBK、Unicode、Unicode big endian和UTF-8这几种编码方式间相互转换。同样是txt文件,Windows是怎样识别编码方式的呢?

我很早前就发现Unicode、Unicode big endian和UTF-8编码的txt文件的开头会多出几个字节,分别是FF、FE(Unicode),FE、FF(Unicode big endian),EF、BB、BF(UTF-8)。但这些标记是基于什么标准呢?

问题二:
最近在网上看到一个ConvertUTF.c,实现了UTF-32、UTF-16和UTF-8这三种编码方式的相互转换。对于 Unicode(UCS2)、GBK、UTF-8这些编码方式,我原来就了解。但这个程序让我有些糊涂,想不起来UTF-16和UCS2有什么关系。
查了查相关资料,总算将这些问题弄清楚了,顺带也了解了一些Unicode的细节。写成一篇文章,送给有过类似疑问的朋友。本文在写作时尽量做到通俗易懂,但要求读者知道什么是字节,什么是十六进制。

0、big endian和little endian
big endian和little endian是CPU处理多字节数的不同方式。例如“汉”字的Unicode编码是6C49。那么写到文件里时,究竟是将6C写在前面,还是将49写在前面?如果将6C写在前面,就是big endian。还是将49写在前面,就是little endian。

“endian”这个词出自《格列佛游记》。小人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian)敲开,由此曾发生过六次叛乱,其中一个皇帝送了命,另一个丢了王位。

我们一般将endian翻译成“字节序”,将big endian和little endian称作“大尾”和“小尾”。

1、字符编码、内码,顺带介绍汉字编码
字符必须编码后才能被计算机处理。计算机使用的缺省编码方式就是计算机的内码。早期的计算机使用7位的ASCII编码,为了处理汉字,程序员设计了用于简体中文的GB2312和用于繁体中文的big5。

GB2312(1980年)一共收录了7445个字符,包括6763个汉字和682个其它符号。汉字区的内码范围高字节从B0-F7,低字节从A1-FE,占用的码位是72*94=6768。其中有5个空位是D7FA-D7FE。

GB2312支持的汉字太少。1995年的汉字扩展规范GBK1.0收录了21886个符号,它分为汉字区和图形符号区。汉字区包括21003个字符。2000年的GB18030是取代GBK1.0的正式国家标准。该标准收录了27484个汉字,同时还收录了藏文、蒙文、维吾尔文等主要的少数民族文字。现在的PC平台必须支持GB18030,对嵌入式产品暂不作要求。所以手机、MP3一般只支持GB2312。

从ASCII、GB2312、GBK到GB18030,这些编码方法是向下兼容的,即同一个字符在这些方案中总是有相同的编码,后面的标准支持更多的字符。在这些编码中,英文和中文可以统一地处理。区分中文编码的方法是高字节的最高位不为0。按照程序员的称呼,GB2312、GBK到GB18030 都属于双字节字符集 (DBCS)。

有的中文Windows的缺省内码还是GBK,可以通过GB18030升级包升级到GB18030。不过GB18030相对GBK增加的字符,普通人是很难用到的,通常我们还是用GBK指代中文Windows内码。

这里还有一些细节:

GB2312的原文还是区位码,从区位码到内码,需要在高字节和低字节上分别加上A0。

在DBCS中,GB内码的存储格式始终是big endian,即高位在前。

GB2312的两个字节的最高位都是1。但符合这个条件的码位只有128*128=16384个。所以GBK和GB18030的低字节最高位都可能不是1。不过这不影响DBCS字符流的解析:在读取DBCS字符流时,只要遇到高位为1的字节,就可以将下两个字节作为一个双字节编码,而不用管低字节的高位是什么。

2、Unicode、UCS和UTF
前面提到从ASCII、GB2312、GBK到GB18030的编码方法是向下兼容的。而Unicode只与ASCII兼容(更准确地说,是与ISO-8859-1兼容),与GB码不兼容。例如“汉”字的Unicode编码是6C49,而GB码是BABA。

Unicode也是一种字符编码方法,不过它是由国际组织设计,可以容纳全世界所有语言文字的编码方案。Unicode的学名是”Universal Multiple-Octet Coded Character Set”,简称为UCS。UCS可以看作是”Unicode Character Set”的缩写。

根据维基百科全书(http://zh.wikipedia.org/wiki/)的记载:历史上存在两个试图独立设计Unicode的组织,即国际标准化组织(ISO)和一个软件制造商的协会(unicode.org)。ISO开发了ISO 10646项目,Unicode协会开发了Unicode项目。

在1991年前后,双方都认识到世界不需要两个不兼容的字符集。于是它们开始合并双方的工作成果,并为创立一个单一编码表而协同工作。从Unicode2.0开始,Unicode项目采用了与ISO 10646-1相同的字库和字码。

目前两个项目仍都存在,并独立地公布各自的标准。Unicode协会现在的最新版本是2005年的Unicode 4.1.0。ISO的最新标准是10646-3:2003。

UCS规定了怎么用多个字节表示各种文字。怎样传输这些编码,是由UTF(UCS Transformation Format)规范规定的,常见的UTF规范包括UTF-8、UTF-7、UTF-16。

IETF的RFC2781和RFC3629以RFC的一贯风格,清晰、明快又不失严谨地描述了UTF-16和UTF-8的编码方法。我总是记不得IETF是Internet Engineering Task Force的缩写。但IETF负责维护的RFC是Internet上一切规范的基础。

3、UCS-2、UCS-4、BMP

UCS有两种格式:UCS-2和UCS-4。顾名思义,UCS-2就是用两个字节编码,UCS-4就是用4个字节(实际上只用了31位,最高位必须为0)编码。下面让我们做一些简单的数学游戏:

UCS-2有2^16=65536个码位,UCS-4有2^31=2147483648个码位。

UCS-4根据最高位为0的最高字节分成2^7=128个group。每个group再根据次高字节分为256个plane。每个plane根据第3个字节分为256行 (rows),每行包含256个cells。当然同一行的cells只是最后一个字节不同,其余都相同。

group 0的plane 0被称作Basic Multilingual Plane, 即BMP。或者说UCS-4中,高两个字节为0的码位被称作BMP。

将UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。在UCS-2的两个字节前加上两个零字节,就得到了UCS-4的BMP。而目前的UCS-4规范中还没有任何字符被分配在BMP之外。

4、UTF编码

UTF-8就是以8位为单元对UCS进行编码。从UCS-2到UTF-8的编码方式如下:

UCS-2编码(16进制) UTF-8 字节流(二进制)
0000 – 007F 0xxxxxxx
0080 – 07FF 110xxxxx 10xxxxxx
0800 – FFFF 1110xxxx 10xxxxxx 10xxxxxx

例如“汉”字的Unicode编码是6C49。6C49在0800-FFFF之间,所以肯定要用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将6C49写成二进制是:0110 110001 001001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。

读者可以用记事本测试一下我们的编码是否正确。

UTF-16以16位为单元对UCS进行编码。对于小于0×10000的UCS码,UTF-16编码就等于UCS码对应的16位无符号整数。对于不小于0×10000的UCS码,定义了一个算法。不过由于实际使用的UCS2,或者UCS4的BMP必然小于0×10000,所以就目前而言,可以认为 UTF-16和UCS-2基本相同。但UCS-2只是一个编码方案,UTF-16却要用于实际的传输,所以就不得不考虑字节序的问题。

5、UTF的字节序和BOM
UTF-8以字节为编码单元,没有字节序的问题。UTF-16以两个字节为编码单元,在解释一个UTF-16文本前,首先要弄清楚每个编码单元的字节序。例如收到一个“奎”的Unicode编码是594E,“乙”的Unicode编码是4E59。如果我们收到 UTF-16字节流“594E”,那么这是“奎”还是“乙”?

Unicode规范中推荐的标记字节顺序的方法是BOM。BOM不是“Bill Of Material”的BOM表,而是Byte Order Mark。BOM是一个有点小聪明的想法:

在UCS编码中有一个叫做”ZERO WIDTH NO-BREAK SPACE”的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输字符”ZERO WIDTH NO-BREAK SPACE”。

这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。因此字符”ZERO WIDTH NO-BREAK SPACE”又被称作BOM。

UTF-8不需要BOM来表明字节顺序,但可以用BOM来表明编码方式。字符”ZERO WIDTH NO-BREAK SPACE”的UTF-8编码是EF BB BF(读者可以用我们前面介绍的编码方法验证一下)。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。

Windows就是使用BOM来标记文本文件的编码方式的。

6、进一步的参考资料
本文主要参考的资料是 “Short overview of ISO-IEC 10646 and Unicode” (http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html)。

我还找了两篇看上去不错的资料,不过因为我开始的疑问都找到了答案,所以就没有看:

“Understanding Unicode A general introduction to the Unicode Standard” (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter04a)
“Character set encoding basics Understanding character set encodings and legacy encodings” (http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&item_id=IWS-Chapter03)
我写过UTF-8、UCS-2、GBK相互转换的软件包,包括使用Windows API和不使用Windows API的版本。以后有时间的话,我会整理一下放到我的个人主页上(http://fmddlmyy.home4u.china.com)。

我是想清楚所有问题后才开始写这篇文章的,原以为一会儿就能写好。没想到考虑措辞和查证细节花费了很长时间,竟然从下午1:30写到9:00。希望有读者能从中受益。

解读UTF8编码

在网络中有很多地方都有采用UTF8编码,由于要编写与邮件服务端有关的程序,而邮件服务端有些地方用到了UTF8编码,所以对它有了初步的认识!

它其实和Unicode是同类,就是在编码方式上不同!
首先UTF8编码后的大小是不一定,不像Unicode编码后的大小是一样的!

我们先来看Unicode的编码:一个英文字母 “a” 和 一个汉字 “好”,编码后都是占用的空间大小是一样的,都是两个字节!

而UTF8编码:一个英文字母“a” 和 一个汉字 “好”,编码后占用的空间大小就不样了,前者是一个字节,后者是三个字节!

现在就让我们来看看UTF8编码的原理吧:
因为一个字母还有一些键盘上的符号加起来只用二进制七位就可以表示出来,而一个字节就是八位,所以UTF8就用一个字节来表式字母和一些键盘上的符号。然而当我们拿到被编码后的一个字节后怎么知道它的组成?它有可能是英文字母的一个字节,也有可能是汉字的三个字节中的一个字节!所以,UTF8是有标志位的!

当要表示的内容是 7位 的时候就用一个字节:0******* 第一个0为标志位,剩下的空间正好可以表示ASCII 0-127 的内容。

当要表示的内容在 8 到 11 位的时候就用两个字节:110***** 10****** 第一个字节的110和第二个字节的10为标志位。

当要表示的内容在 12 到 16 位的时候就用三个字节:1110***** 10****** 10******    和上面一样,第一个字节的1110和第二、三个字节的10都是标志位,剩下的空间正好可以表示汉字。

以此类推:
四个字节:11110**** 10****** 10****** 10******
五个字节:111110*** 10****** 10****** 10****** 10******
六个字节:1111110** 10****** 10****** 10****** 10****** 10******
……………………………………………………………………………….

明白了没有?
编码的方法是从低位到高位

现在就让我们来看看实例吧!

红色为标志位
其它着色为了显示其,编码后的位置

unicode

Perl 变量魔法

先来看一段 Perl 脚本:

sub showVars {

my $name = “first”;
print $name . “\t at ” . \$name . “\n”;
for(my $i = 0; $i < 2; $i++) { my $name = "loop_" . $i; if (1 < 3) { print $name . "\t at " . \$name . "\n"; my $name = "if_A"; print $name . "\t at " . \$name . "\n"; { my $name = "blank"; print $name . "\t at " . \$name . "\n"; } print $name . "\t at " . \$name . "\n"; } if (1 < 4) { print $name . "\t at " . \$name . "\n"; my $name = "if_B"; print $name . "\t at " . \$name . "\n"; } print $name . "\t at " . \$name . "\n"; } print $name . "\t at " . \$name . "\n"; } sub showVars_2 { my $name = "first"; print $name . "\t at " . \$name . "\n"; for(my $i = 0; $i < 2; $i++) { $name = "loop_" . $i; if (1 < 3) { print $name . "\t at " . \$name . "\n"; $name = "if_A"; print $name . "\t at " . \$name . "\n"; { $name = "blank"; print $name . "\t at " . \$name . "\n"; } print $name . "\t at " . \$name . "\n"; } if (1 < 4) { print $name . "\t at " . \$name . "\n"; $name = "if_B"; print $name . "\t at " . \$name . "\n"; } print $name . "\t at " . \$name . "\n"; } print $name . "\t at " . \$name . "\n"; } showVars(); print "--------------\n"; showVars_2();

这里面有 2 个函数,两者之间的区别,就是变量的定义方式不同。

第一个函数,多次使用 my 声明变量。Perl 会在每一个局部区域内,比如说大括号 {} 内,实现一个命名空间。
也就是说,在不同的代码段,相同的变量名,实际上指向了不同的内存地址。
第一个函数体内,首先声明了一个变量 $name,他的作用域是整个函数,但在 for 循环体内,又用 my 声明了 $name 变量,因为 for 是一个封闭的结构,在 {} 里面就可以产生一个新的命名空间,此时 $name 指向了一个新的内存地址。这一点可以在后面的输出结果中看到。

由此,引发一个值得思考的问题:
如果在循环体内部用 my 去声明变量,那么循环执行多少次,就会有多少个变量的副本,这会浪费很多内存空间。
这一点是跟其他类 C 语言是有很大区别的。
所以,如果你要想利用 Perl 的命名空间,那么只要多注意代码段的作用范围,编程的时候能感受到 Perl 十分强大的便利性。
需要注意的,就是避免在循环体中使用 my 声明,浪费内存空间不说,还会影响程序的性能。

说了半天,还是看一看实际的结果吧:

$ perl show_vars.pl
first at SCALAR(0x182fb10)
loop_0 at SCALAR(0x182fbb8)
if_A at SCALAR(0x182fc24)
blank at SCALAR(0x182fc84)
if_A at SCALAR(0x182fc24)
loop_0 at SCALAR(0x182fbb8)
if_B at SCALAR(0x182fd5c)
loop_0 at SCALAR(0x182fbb8)
loop_1 at SCALAR(0x182fd5c)
if_A at SCALAR(0x182fc84)
blank at SCALAR(0x276164)
if_A at SCALAR(0x182fc84)
loop_1 at SCALAR(0x182fd5c)
if_B at SCALAR(0x182fc24)
loop_1 at SCALAR(0x182fd5c)
first at SCALAR(0x182fb10)
————–
first at SCALAR(0x182fe88)
loop_0 at SCALAR(0x182fe88)
if_A at SCALAR(0x182fe88)
blank at SCALAR(0x182fe88)
blank at SCALAR(0x182fe88)
blank at SCALAR(0x182fe88)
if_B at SCALAR(0x182fe88)
if_B at SCALAR(0x182fe88)
loop_1 at SCALAR(0x182fe88)
if_A at SCALAR(0x182fe88)
blank at SCALAR(0x182fe88)
blank at SCALAR(0x182fe88)
blank at SCALAR(0x182fe88)
if_B at SCALAR(0x182fe88)
if_B at SCALAR(0x182fe88)
if_B at SCALAR(0x182fe88)

电子书 下载 Web2.0 PHP Javascript Ajax pdf eBooksBoard ebook

这里有最新的电子书下载!

Javascript Ajax

这是前一段时间发现的一个网站,里面都是技术类的电子书,可以随意下载。

注意,这里的电子书都保存在 rapidshare.com,这是一个免费存储文件的地方。

选中一本书下载的时候,会跳到一个英文的宣传页面,只要点击下面的 ‘free’ 按钮,就会打开一个选择服务器的页面,输入验证码后就可以下载了。

因为是免费存放的文件,下载速度可能比较慢,但基本上都可以下载。

看见好书,就别再犹豫了,搞不好过一段时间就没有免费下载了。

网站地址:http://www.ebooksboard.com/

Google Docs 发布 Google Presentation 演示文稿 在线 PowerPoint

Google Presentation正式发布,这样,Google Docs 就完整的整合Google Document,Google Spreadsheet和Google Presentation这三款产品。

Google Presentation

简单的试用了Google Presentation,使用方法和Google Document,Google Spreadsheet基本类似,支持在线协作,支持右键操作,支持模板更换(提供了十五种模板供选择),点击右上角的“Start Presentation”可以在线播放Presentation,基本上具备了Powerpoint常用的功能。

总的来说使用体验还算不错,Google Docs使用的比较多,一方面主要是其与Gmail的整合,另外一个使用比较多的功能那就是在线协作了。大家可以去尝试一下:)

链接:http://docs.google.com/

PHP Perl 关联数组 哈希表 Hash Table

关联数组,又称为哈希表(hash table),是一种非常好用的数据结构。

在程序中,我们可能会遇到需要消重的问题,举一个最简单的模型:

有一份用户名列表,存储了 10000 个用户名,没有重复项;
还有一份黑名单列表,存储了 2000 个用户名,格式与用户名列表相同;
现在需要从用户名列表中删除处在黑名单里的用户名,要求用尽量快的时间处理。

这个问题是一个小规模的处理量,如果实际一点,2 个表都可能很大,比如有 2 亿条记录。

我最开始想到的方法,就是做一个嵌套的循环,设用户名表有 M 条记录,黑名单列表有 N 条记录,那么,循环的次数是 M * N 次!
PHP 版代码:

$nameM) {
foreach($arrayN as $nameN) {
if ($nameM == $nameN) {
// 本行执行了 M * N 次!
unset($arrayM[$keyM]);
}
}
}
return $arrayM;
?>

另一种方式,利用数组索引。

PHP 是一种弱类型的语言,不像 C 语言那样有严格的变量类型限制。C 语言的数组,每一个元素的类型必须一致,而且索引都是从 0 开始。
PHP 的数组,可以用字符串作为索引,也称为关联数组。
数组索引,有一个天然的限制就是不会重复,而且访问的时候不需要查找,可以直接定位。

还是刚才的那个问题,我们采用另一种办法。

把黑名单列表的用户名组织到一个数组里,数组的索引就是用户名。

然后,遍历用户列表的时候,只需直接用 isset 查询那个用户名是否存在即可。

PHP 版代码:

$nameM) {
if (isset($arrayHash[$nameM])) {
// 本行执行了 M 次!
unset($arrayM[$keyM]);
}
}
return $arrayM;
?>

可以看到,优化过的代码,循环次数是 M + N 次。

假如 M 和 N 都是 10000,优化前,循环了 1 亿次;优化后,只循环了 20000 次,差了 5000 倍!
如果第二个程序耗时 1 秒,则第一个程序需要将近一个半小时!

最近在做 Perl 的开发,Perl 在处理文本的时候有很高的效率,同样,它也支持关联数组!

只是语法和 PHP 的那种类 C 的方式有很大不同,以第二段代码为例,Perl 版的实现:


#!/usr/bin/perl
my %arrayHash;
for(my $i = 0; $i < @arrayN; ++$i) { $arrayHash{$arrayN[$i]} = 1; } for(my $i = 0; $i < @arrayM; ++$i) { if ($arrayHash{$arrayM[$i]}) { $arrayM[$i] = undef; } }

Perl 的数组是 @ 开头,哈希是以 % 开头,unset 实际上就是 undef。
Perl 的哈希和数组都是有具体类型的,而且向函数传递变量的时候要传引用,我刚学时间不长,快被搞晕了。

不过,现在刚刚实现了一个以 hash 方式进行 IP 位置查找的算法,平均比较次数大概在 3 次左右,比传统的折半查找方式少了很多次,它大概需要 8 次以上的比较。

刚刚做了一个小的性能测试,对 10 万个 IP 进行查找,在我的台式机上,耗时 15 秒,平均每秒 7500 次,感觉还不错,呵呵。

不过,还是喜欢 PHP 的数组,真的很强大!

God Bless PHP!

Linux FreeBSD date 函数 昨天日期 yesterday

写 shell 脚本的时候,需要用到昨天的日期(yesterday, lastday),Linux 和 FreeBSD 虽说都是 *nix 系统,但一个简单的 date 函数居然用法都不一样。

例如,今天是 2007-9-14

FreeBSD:
输入:date -v -1d +%Y%m%d
输出:20070913

Linux:
输入:date –date=’yesterday’ +%Y%m%d
输出:20070913

看到这里,会发现,Linux 的局限性,他只能输出昨天的,但前天和大前天的之类的日期就没办法了。

我还是比较喜欢 FreeBSD