2009年4月16日 星期四

.htaccess 与 Unix 换行符

.htaccess是一个很好的工具,尤其对于静态网站。

我的网站是全静态的,原来是把RSS放在了/rss/目录下,后来改成了直接放在根目录,但是又不想每次更新都要去同步两边的文件,所以想把原来/rss/下的RSS Feed重定向到根目录下的RSS Feed,我在.htaccess文件中写了这两句:


Redirect /rss.xml http://blog.yypig.net/rss.xml
Redirect /atom.xml http://blog.yypig.net/atom.xml

但是一放到网站上,就出现了500 Internal Server Error,但是如果只有一行就可以了,百思不得其解,以为一个文件里面只能出现一个Redirect语句。后来看到了这个链接 ,恍然大悟,原来只是换行符的问题,如果服务器是Unix的,一定要用Unix换行符,改了之后一切正常。

.htaccess其实功能很强大,最近就通过它的URL Rewrite功能,把公司的动态网页的URL全部变成由目录和文件名组成的貌似静态网页的结构,以类似“服务.html”代替“index.php?cat=2&item=1”,据说这样对搜索引擎比较友好。

2009年3月17日 星期二

Zim Wiki 的中文乱码问题的解决办法

Zim 是一款桌面维基软件,可以当桌面笔记来用,小众软件推荐的 ,由于是用perl+gtk写成的,所以在Windwos下的安装非常麻烦,不过已经有人做了Windows的包,在这里 。刚开始用,不知道好不好用。不过首先发现的问题是日期乱码,而且发现在它的release note里面明明写了加上了简体中文翻译,但是界面还是英文的,设置里面好像也没有办法改,正想把它扔了,不过有点不甘心,发扬了开源的DIY精神,终于找到办法了。

在安装目录的bin下,有个zim文件,这是个perl脚本,也是Zim的主运行文件。在32至34行:


# i18n initialization
$Zim::CODESET = 'utf-8';
$Zim::LANG = '';

把它改成:


# i18n initialization
$Zim::CODESET = 'gbk';
$Zim::LANG = 'zh_CN';

重新打开Zim,就是中文界面,而且日期不会乱码。

2009年1月14日 星期三

Windows XP的无线桥接

目前大部分的笔记本都是有两块网卡,一块是普通网卡,一块是无线网卡。一般有网口的地方会用普通网卡,通过网线连接上网,以获得较好的性能,没有网口的地方,会用无线上网。通常情况下,即使在同一个局域网里面,如果手工配置IP地址,必须为这两个不同的链接配置不同的IP地址,因为windows不允许为两个不同的适配器配置相同的IP地址。在特殊情况下,例如,使用电驴并在路由器上做了端口映射,于是需要在两种情况下都使用相同的IP地址,又不想每次都重新手工配置,这个时候可以用Windows自带的桥接模式来解决这个问题。

在网络连接的文件夹中,选中“本地连接”和“无线网络连接”,击右键,选择“桥接”。这个时候将创建一个新的连接,叫“网络桥”(MAC Birdge Miniport)。这时候就可以手工为“网路桥”配置IP地址了。这样配置后,发现当接上网线时,上网是没有任何问题的,但是一旦拔开网线,改用无线上网,就上不去了,但是无线网卡显示的是连接上的状态。百思不得其解。Google了一下,发现了这两个连接:

Windows XP Home Networking: Building Network Bridges
Bridge May Not Work With a Non-Promiscuous Mode Network Adapter

其中,提到了一个东西:“Promiscuous Mode”。原来,网卡工作在普通状态时,只接收属于自己的MAC地址的以太网包。只有当工作在“Promiscuous Mode”时,才不加限制地接收所有的以太网包。大部分的普通网卡都可以工作在“Promiscuous Mode”,可能为了安全起见,大部分的无线网卡都不能工作在“Promiscuous Mode”下。当Windows创建桥接模式时,实际上在系统里面创建了一个虚拟的新的网卡,这个新的网卡有自己的MAC地址,桥里面的所有网卡都以这个新的MAC地址发送以太网包,回送的以太网包自然也是发给这个新的MAC地址,由于普通网卡支持“Promiscuous Mode”,所以可以接收到不属于自己的新的MAC地址以太网包,所以通讯正常,无线网卡会抛弃掉所有不属于自己MAC地址的包,所以在桥接模式下收不到任何发回来的以太网包,自然就不能正常工作了。Windows XP提供了一个解决办法,叫ForceCompatibilityMode(强制兼容模式),在命令行(cmd)下,打入netsh bridge show a,可以看到已经桥接的各个网卡的编号和是否启用强制兼容模式,如果无线网卡显示“已停用”或者“未知”,应记住无线网卡的编号,并在命令行下打入:netsh bridge set a X e,其中X是无线网卡的编号,以启用强制兼容模式。

这个兼容模式的原理是这样的,一旦某个网卡启用了这个模式,当从这个网口向外发送以太网包时,将改写以太网包,把源地址换成网卡自己的MAC地址,并记住这个转换,回复的以太网包的目标地址也是网卡的MAC地址,这样网卡就不会丢弃这个包,当这个收到这个回复包后,再根据原来的记忆,把目标地址换回原来的地址,和IP层的NAT的原理类似。

通过这样设置以后,当拔掉网线,启用无线网络连接后,依然可以上网,并且IP地址不变,整个过程自动完成。

2008年9月15日 星期一

Google Chrome中如何使用365key提交网摘?

365key自从被收购了之后,越做越糟糕,但是由于它的“将网摘共享到我的网站”上的功能做得比较能适合我的需要,所以一直在用它。它的右键收藏功能在Firefox 3.0之后就没办法使用,所以只能退而使用“书签”的方式提交网摘。“书签”方式就是把一段用于提交网摘的Javascript保存成书签,需要提交网摘时,选择相应书签,运行Javascript就OK了,兼容性比较好。当开始使用Google Chrome之后,也想用这种方法来提交网摘,但是发现有一个Bug:选中的文本无法作为摘要提交。原来的代码是这样的:

javascript:d=document;t=d.selection?(d.selection.type!='None'?d.selection.createRange().text:''):(d.getSelection?d.getSelection():'');void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();
其中采用的两种获得选择文本的方法:document.getSelection()或者document.selection.createRange().text,在Google Chrome中都失效了。通过研究,发现在Google Chrome中,获得选择文本的方法为:window.getSeleciton()。所以将代码更改如下:

javascript:d=document;t=window.getSelection();void(keyit=window.open('http://www.365key.com/storeit.aspx?t='+escape(d.title)+'&u='+escape(d.location.href)+'&c='+escape(t),'keyit','scrollbars=no,width=475,height=575,left=75,top=20,status=no,resizable=yes'));keyit.focus();
结果测试一下可以了,需要的人可以把提交天天网摘(P)(弹出窗口方式)拖到书签栏。

另外,提交网摘网页里面,分类已经在很久以前就不行了,估计也是Javascript的兼容问题,希望365Key可以改一改。

2008年8月9日 星期六

在Blogger的经典模板(Classic Templates)中添加分类(Labels)列表

我的另外一个Blog,是用Blogger的FTP功能发布的,只能使用Classic Templates,常规是不能列出分类(Labels)列表的,不象用Blogspot发布的,可以用新的Layout,用“分类”控件实现。

参考了著名的Blogspot Hacker phydeaux3 的文章《Automatic List of Labels for Blogger Classic Templates / FTP》。摸索出了适合中文的方法,介绍如下。

首先是如何列出所有的Labels。Blogger所提供的一个叫“metafeed”的功能可以实现这个,地址是:

http://www.blogger.com/feeds/USERID/blogs/BLOGID

其中,USERID和BLOGID,可以在Blogger的控制面板中查到,所有对于用户级别的设置的链接中,可以看到USERID,所有关于特定Blog的设置的链接,都可以找到BLOGID。这个地址支持标准的GData的接口,所以可以通过在后面添加参数实现其他功能。这个地址其实是个Feed,所以原来的格式是atom。Javascript处理XML比较困难,所以要把它转化成Javascript比较容易处理的JSON格式,而且选用GData的json-in-script的方式,以便把它嵌入到网页中作为Javascript运行。所以可以采用:

http://www.blogger.com/feeds/USERID/blogs/BLOGID?alt=json-in-script&callback=listLabels

其中listLabels是回调函数,参数就是JSON描述的对象,通过在回调函数中对JSON对象的处理,就可以列出所有的Labels。由于www.blogger.com在G~F~W外面,回传的东西里面都是Labels,一旦Labels包括某些关键字,后果可想而知,好在Google的大部分服务都提供https,所以最终采用的链接是:

https://www.blogger.com/feeds/USERID/blogs/BLOGID?alt=json-in-script&callback=listLabels
列出所有的Labels还是不够,关键要解决每个Label所对应的链接是什么。对于全部是英文或者数字的Label,链接就是http://BLOGURL/Labels/后面加Label名称再加上html扩展名,但是一旦Label包含有中文就不是这样了,假如全部是中文,Label名称要进行base64编码,假如Label包括中文和英文或数字,那么Label名称里面的英文保持原文,每个中文要转为“=XX=YY=ZZ”,其中,XXYYZZ为16进制表示的中文字的Unicode编码。在参考了这个连接里面的Base64 Javascript实现后,最终的脚本为:

<script type="text/javascript">
//<![CDATA[
var Base64 = {

    // private property
    _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

    // public method for encoding
    encode : function (input) {
        var output = "";
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var i = 0;
        var go = false;
        /* 判断是否包括数字和字母 */
        if (input.match(/[A-Za-z0-9\+\/\=]/g)){
            go = true;
        }
        input = Base64._utf8_encode(input);

        while (i < input.length) {
            /* 如果包括数字和字母,按特殊方式处理,否则用base64编码 */
            if (go){
                chr1 = input.charCodeAt(i++);
                if (chr1<127){
                    output = output +input.charAt(i-1);
                    continue;
                }
                output = output + '=' + chr1.toString(16).toUpperCase();
                continue;
            }

            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output = output +
            this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
            this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

        }
        /* 将结果中的斜杠替换成两个下划线 */
        output = output.replace(/\//g,"__");
        return output;
    },


    // private method for UTF-8 encoding
    _utf8_encode : function (string) {
        string = string.replace(/\r\n/g,"\n");
        var utftext = "";

        for (var n = 0; n < string.length; n++) {

            var c = string.charCodeAt(n);

            if (c < 128) {
                utftext += String.fromCharCode(c);
            }
            else if((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }

        return utftext;
    }

};

function listLabels(root){
    var baseURL = 'http://blog.yypig.net/labels/';
    var baseHeading = "Labels";
    var isFTP = true;
    var entry = root.entry;
    var category = entry.category;
    labelSort = new Array();
    for(p in category){
        labelSort[labelSort.length] = [category[p].term];
    }
    //labelSort.sort();
    for (var r=0; r < labelSort.length; r++){
        document.write('<a href="'+baseURL+Base64.encode(labelSort[r]+'')+'.html" >');
        document.write(labelSort[r]+'');
        document.write('</a>, ');
    }

}

//]]>
</script>
<script type="text/javascript" src="https://www.blogger.com/feeds/USERID/blogs/BLOGID?alt=json-in-script&callback=listLabels" ></script>

2008年5月3日 星期六

纪念一下

据说,今天是BASIC语言诞生的日子:

上世纪50年代,Dartmouth 大学的数学家 John G. Kemeny 和 Thomas E. Kurtz觉得当时的 Fortran、Algol 太复杂,所以在 1956 年开始着手开发易于使用的语言。
于 1964年5月1日凌晨4点在 GE-225 主机成功运行第一个 BASIC 程序。从此 BASIC 迅速风靡。两位 BASIC 之父后来又成立公司开发了 True BASIC。



值得一提的是,Kemeny 后来成为了 Dartmouth 大学的校长,并在 1972 年实行男女同校制(该校两百多年来都是 all-male)。

我的第一门语言也是APPLE II上的BASIC语言。当年在潮州金山中学的电脑室里面学习的,是兴趣小组,感谢杜舒加老师,是他引导我进入了这个领域,每天都是下午放学以后,我们就到电脑室上机,杜老师会一直陪伴我们到六点钟才关机房回家。他还制作了一个十章的练习题,从易到难,从最简单的打印星型图案,到最难的需要用到事件驱动的模拟加油站汽车加油,中间还有八皇后问题,四色问题等等经典题目,帮助我们走入了编程的领域。

2007年10月17日 星期三

忽悠,接着忽悠

第一次看到汉语编程就是感觉到是忽悠,因为任何一个写过程序的人都肯定会说,汉语编程有何意义?程序语言本质上不是人说的语言,是code(代码)而不是language,所以何必分英语汉语,就像有没有汉语数学这个概念?sin(x)非要写成正弦(甲)?但是后来看到了他们“做”出来的IDE,还有点佩服这帮人,以为是一帮理想主义者,为了推行这个理念,竟然不辞辛苦地开发出一个IDE出来。今天看了徽剑的这篇文章,才知道又是一个大忽悠。不过也不得不佩服他们的“智慧”,选了一个大家都不怎么熟悉的Forth语言来改,IDE也是拿开源的改出来的。不过在这片神奇的土地上,还有什么不可能的事情呢?

Update:2007/10/26

仔细重新看了徽剑的文章,发现原来汉语编程也分骗子理想主义者,我之前看到的其实是易语言的IDE,感觉做得不错,如果真的是理想主义者自己的辛苦开发出来的,还是要致以崇高敬意,毕竟也是辛苦劳动的成果。但是,我还是不赞同汉语编程。

相关链接: