2008/12/11

Mapping remote TCP port to local via HTTPS Proxy

上次说的Perl代码供大家参考

功能:把远端的应用服务端口通过HTTPS代理服务器映射成本地端口。这对于那些不支持HTTPS代理的TCP应用还有点儿小用处! :D


#!/usr/bin/env perl
#
# Use remote HTTPS PROXY to tunnel the remote service to local!
# Author: Yi Zhao
#   Blog: linuxyz.blogspot.com
#
# Based on original "ssltunnel.pl" by Alex Hornby <alex@hornby.org.uk>
# $Id: ssltunnel.pl,v 1.17 2003/06/10 14:54:16 alex Exp $
#
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.
#

package httpsproxy;

use strict;
my $VERSION=1.0;

use IO::File;
use IO::Select;
use IO::Socket;
use Net::SSL;
use Getopt::Long;
use MIME::Base64;

my %options = (
    proxyport=>443,
    reproxyport=>8080,
    localaddr=>"127.0.0.1",
    localport=>8080,
);

sub usage
{
    print STDERR <<EOF;
usage: perl httpsproxy.pl [options] [remote-host:port]
Tunnels a TCP/IP connection through an http proxy using SSL.

WARNING: Only use this if you have the proxy administrator\'s permission
WARNING: The authors of this package offer no warranty

options:
    --help                        This help
    --proxyhost 1.2.3.4           Mandatory proxy host port (default 443)
    --proxyport 443               Optional proxy host port (default 443)
    --proxyuser <username>        Optional proxy user name
    --proxypasswd pass            Optional proxy pass word
    --useragent agent             Optional user agent name
    --reproxyhost 1.2.3.4         Optional intermediate http proxy host
    --reproxyport 123             Optional intermediate http proxy host port (default 8080)
    --reproxyuser <username>      Optional intermediate http proxy user name
    --reproxypasswd pass          Optional intermediate http proxy pass word
    --localaddr 1.2.3.4           Optional local addr to listen on (default 127.0.0.1)
    --localport 123               Optional local port to listen on (default 8080)

e.g. To run a local http proxy to the remote HTTPS proxy

./httpsproxy.pl --proxyhost 10.1.1.80 \
  --proxyport 443 --localport 80  www.abc.com:80

EOF
    exit(1);
}

# Parse command line arguments
sub parseArgs
{
    GetOptions(\%options, qw/dumpfile=s
                   proxyhost=s proxyport=i proxyuser=s proxypasswd=s useragent=s
                   reproxyhost=s reproxyport=i reproxyuser=s reproxypasswd=s reuseragent=s
                   localaddr=s localport=i
                   debug! help!
                   log-file=s pidfile=s/);

    if ( $options{help} ) {
        usage();
    }

    for (@ARGV) {
        if (m/^([^:]*):(.*)$/) {
            $options{desthost} = $1;
            $options{destport} = int($2) || getservbyname($2, 'tcp') || die "unknown port";
            print "Mapping $options{desthost}:$options{destport} as $options{localaddr}:$options{localport}\n";
        }
    }
    
    if ( !defined($options{proxyhost}) ) {
        print STDERR "error: You must give a proxyhost\n";
        usage();
    }
}

# This is really inefficient, but we only use it for reading the proxy response
# so that does not really matter.
sub xgetline($)
{
    my $proxy = shift;
    my $val="";
    my $buf;
    do {
        $proxy->read($buf, 1);
        $val .= $buf;
    } until ($buf eq "\n");

    $val;
}

sub httpProxy
{
    my ( $proxy, $desthost, $destport, $proxyuser, $proxypasswd ) = @_;
    # Force flushing of socket buffers

    # The actual connect
    $proxy->print("CONNECT " .  $desthost . ":" .
                      $destport . " HTTP/1.0\r\n");
    if ( $options{debug} ) {
        print STDERR "CONNECT " .  $desthost . ":" .
                      $destport . " HTTP/1.0\n";
    }

    # Basic auth if needed
    if ( $proxyuser ) {
        my $auth = encode_base64(
            $proxyuser . ":" . $proxypasswd);
        $proxy->print("Proxy-authorization: Basic $auth\r\n");
        if ( $options{debug} ) {
            print STDERR "Proxy-authorization: Basic $auth"
        }
    }

    # User agent name if needed
    if ( $options{useragent} ) {
        $proxy->print("User-Agent: " . $options{useragent} . "\r\n");
        if ( $options{debug} ) {
            print STDERR "User-Agent: " . $options{useragent} . "\n";
        }
    }

    # end of headers
    $proxy->print("\r\n");

    my $status;

    # Wait for HTTP status code, bail out if you don't get back a 2xx code.
    #$_ = $proxy->getline();
    #$_ = $proxy->getchunk();
    $_ = xgetline($proxy);
    next if /^[\r]*$/;
    ($status) = (split())[1];
    die("Received a bad status code \"$status\" from proxy server\n$_")
        if ( int($status/100) != 2 );

    while($_ = xgetline($proxy)) {
        chomp;   # Strip <LF>
        last if /^[\r]*$/;                # Empty line or a single <CR> left

        if ( $options{debug} ) {
            print STDERR "Got extra data [$_]\n";
        }
    }

    return $status;
}

sub connectProxy
{
    if ( $options{reproxyhost} ) {
        # proxy support
        $ENV{HTTPS_PROXY} = qq(http://$options{reproxyhost}:$options{reproxyport});

        # proxy_basic_auth
        $ENV{HTTPS_PROXY_USERNAME} = $options{reproxyuser} if $options{reproxyuser};
        $ENV{HTTPS_PROXY_PASSWORD} = $options{reproxypass} if $options{reproxypass};
    }

    # debugging (SSL diagnostics)
    $ENV{HTTPS_DEBUG} = $options{debug} ? 1 : 0;
  
    my $proxy = new Net::SSL (
        PeerAddr => $options{proxyhost},
        PeerPort => $options{proxyport},
        Proto => 'tcp',
    );

    die "Error connecting to proxy host $options{proxyhost} " .
        "port $options{proxyport}: $!\n" unless $proxy;

    # Force flushing of socket buffers
    $proxy->autoflush(1);

    # only if the remote host are speficied
    httpProxy($proxy, $options{desthost}, $options{destport},
        $options{proxyuser}, $options{proxypasswd} )
    if ( $options{desthost} );

    return $proxy;
}

sub connectLocal
{
    my $listen = new IO::Socket::INET (
        Listen=> 5,
        LocalAddr => $options{localaddr},
        LocalPort => $options{localport},
        Proto => 'tcp',
        Reuse => 1,
    );

    die "can't listen on " . $options{localaddr} . ":"
        . $options{localport} unless $listen;

    print STDERR "Accepting network clients on " .
        $options{localaddr} . ":" .$options{localport} . "\n";

    my %client2proxy;
    my %proxy2client;

    my $s = IO::Select->new();
    $s->add($listen);

    my $dumpfh;
    if ( $options{dumpfile} ) {
        $dumpfh = new IO::File($options{dumpfile}, "w")
            or die "could not open dump file $_";
        $dumpfh->autoflush(1);
    }

    while ( 1 ) {
        my @res = IO::Select::select($s, undef, undef, 3600);
        if ( @res == 0 ) {
            print STDERR "got select error\n";
            last;
        }
        my ($read, $write, $error) = @res;

        # Check for disconnect
        for my $fh ( @$error ) {
            print STDERR "socket $fh is in error\n";
            $s->remove($fh);
            exit();
        }

        # Process handles ready to read;
        for my $fh ( @$read  ) {

            if ( $fh == $listen ) {
                my $client = $listen->accept();
                $client->autoflush(1);
                $s->add($client);
                my $proxy = connectProxy();
                $s->add($proxy);
                print STDERR "New connection from " . $client->peerhost() . "\n";
                $client2proxy{$client} = $proxy;
                $proxy2client{$proxy} = $client;
            } else {
                my $destfh;
                my $isclient = 0;
                if ( exists( $client2proxy{$fh} ) ) {
                    $destfh = $client2proxy{$fh};
                    $isclient = 1;
                } elsif ( exists( $proxy2client{$fh} ) ) {
                    $destfh = $proxy2client{$fh};
                }

                my $num = sysread($fh, $_, 4096);
                if ( $num) {
                    syswrite($destfh, $_, $num);
                    # Optional dump of traffic
                    if ( $dumpfh ) {
                        if ($isclient) {
                            $dumpfh->print("client[$_]\n");
                        } else {
                            $dumpfh->print("proxy[$_]\n");
                        }
                    }
                } else {
                    $s->remove($fh);
                    $s->remove($destfh);
                    if ( $isclient ) {
                        print STDERR "client disconnected\n";
                        delete($client2proxy{$fh});
                        delete($proxy2client{$destfh});
                    } else {
                        print STDERR "proxy disconnected\n";
                        delete($client2proxy{$destfh});
                        delete($proxy2client{$fh});
                    }
                    close($fh);
                    close($destfh);

                    if(%proxy2client == 0 ) {
                        print STDERR "last client disconnected\n";
                    }
                }
            }
        }
    }
}

parseArgs();
connectLocal();

0;

__END__

copy and paste in VIM

VIM have multiple clipboard which allows you copy and save different content at the same time. The register can be any of {a-zA-Z0-9.%#:-"}. It is really interesting thing which I never notice before.

"{a-zA-Z0-9.%#:-"} Use register {a-zA-Z0-9.%#:-"} for next delete, yank
or put (use uppercase character to append with
delete and yank) ({.%#:} only work with put).

:reg[isters] Display the contents of all numbered and named
registers. {not in Vi}

:reg[isters] {arg} Display the contents of the numbered and named
registers that are mentioned in {arg}. For example:

["x]y{motion} Yank {motion} text [into register x]. When no
characters are to be yanked (e.g., "y0" in column 1),
this is an error when 'cpoptions' includes the 'E'
flag.

["x]p Put the text [from register x] after the cursor
[count] times. {Vi: no count}


I forgot there is another register *, it is as same as the system clipboard. So you can yank some text into register *, it will be in the system clipboard also. :D

2008/12/04

Apache HTTPD as Proxy server

由于条件限制,平时网络只能用http代理,其他任何应用都必须通过这个代理。可是这个代理只能支持http以及https应用,不支持CONNECT remote-host:443以外的其他端口,除了浏览网页根本不能用于其它代理。
为此,用Apache自建了一个HTTPS代理,这样就能够利用这个二次代理做一些其他的应用。

Apache HTTPD 真是强悍啊!首先在 httpd.conf 打开mod_proxy;
然后添加下面的语句:


ProxyRequests On
ProxyVia On

Order deny,allow
Deny from all
Allow from .mydomain.com



赶紧试验一下SSH! TLS握手都完成了,貌似就应该能工作了不?

可是实际上不行!:(

每次用 CONNECT 方法来连接服务器的时候总是被403踢下来。感觉应该是访问控制的问题,于是改成没有访问控制;再试过一样403 Forbidden~~~~ 郁闷啊!

看了半天Apache的文档才发现,原来还有一个 AllowCONNECT 指令,并且缺省只打开443和563端口,难怪连22 端口的时候被踢~~~~~

赶紧加上这句:
AllowCONNECT 21 22 23 80 443
再试,Working... 高喊:“Apache 太强悍了~~~”

题外话:这个二次代理的转换程序是用Perl写的,目前还有些小问题,啥时候时候搞好了也放上来!

2008/10/08

健康饮食

说壹千来道壹万,健康生活是正道,
怎么才能活的好?健康饮食最重要。
一日三餐都要吃,早餐万万别省掉!
少吃主食多吃菜,精肉蛋奶不能少,
少食多餐勤运动,零食一定要戒掉。
饮食起居有规律,利国利民身体好!


附食物结构金字塔一个

2008/09/27

关于Google Chrome以及Android

Google Android 对于Google这种依靠高增长率赚钱的公司,如何保持高的增长率是很关键的,Android对于Google来说是开拓新的增长点,这跟当年Microsoft进入报表生成软件领域是一个道理。进入这样的领域所花费的投资,对于Google而言绝对可以忽略,效果则是明显的,就算失败了也不会有什么损失。当然了这次Google跳得有点儿远~~~ 当然了,Google 只用了一年多的时间就能做成这样确实还是很强悍的,虽然大多数东西都是基于已有的技术开发~~~

Google Chrome的感觉有些奇怪,浏览器领域在此之前基本已经尘埃落定,IE保持老大地位,firefox作为老而保持sexy的形象,老三大量的IE内核的克隆产品,然后是Opera以及Safari。从本质上来说,Google应该是不关心浏览器的,但是Microsoft开始进入Google的领域,说实话,谁都要提防Microsoft自说字画的搞乱浏览器市场。Google培育Mozilla就是这样的目的,可以说只要Mozilla没有走到绝对优势的地位,Google就不会停止对Mozilla的支持。当然了这次Google自己赤膊上阵恐怕也抱着同样的目的,那就是:在浏览器市场纠缠Microsoft,增加话语权,同时让Microsoft走到W3C的标准圈子内,不论是Microsoft的Silverlight,还是Adobe的Flash/Flex/Air。 对Google来说,都不是他想看到的,对于Google这种Internet信息服务提供者来说,最好在客户端领域是群雄争霸,决不能一枝独秀。另一方面Chrome真正目的应该是成为Google的桌面应用平台,看看Chrome强调的JavaScript速度,独立进程管理,哪个都像是在给桌面应用开发作准备。

总的来说,Google作为后来者,她要做的就是不断搞出新的东西,不断进入新的Internet或者信息服务相关的外延领域。不论成功或失败,总要在别人的家里打仗才好。

2008/09/26

VIM Tips

I am running in a English version Windows XP in office. The default encoding of the OS is english! While I still want to be able to work with some Chinese document in VIM, how can I make it happen?
That's simple, put this line into your vimrc file
set guifont=Bitstream\ Vera\ Sans\ Mono:h10:cANSI
set guifontwide=NSimSun:h11:cGB2312

VIM will be using NSimSun to display the Chinese characters. :)
And "Bitstream Vera Sans Mono" to be used for ANSI characters.

Indeed this option can be set locally for each individual files by using the VIM modeline
vim:ts=4:sw=4:expandtab:enc=utf8
All the VIM option can be changed locally. Don't forget to put this modeline into the comments :D

VIM is fantastic cool~~~

2008/09/23

强力推荐JavaScript 高级教程

超级牛人 John Resig (在 Mozilla.org 工作,jQuery的作者) 捉刀制作!!! Web 开发必读~~~

Learning Advanced JavaScript
1) Our Goal
2) Defining Functions
3) Named Functions
4) Functions as Objects
5) Context
6) Instantiation
7) Flexible Arguments
8) Closures
9) Temporary Scope
10) Function Prototypes
11) Instance Type
12) Inheritance
13) Built-in Prototypes
14) Enforcing Function Context
15) Bonus: Function Length

2008/08/28

逐鹿蓝天

《逐鹿蓝天》 —— 美国民航业的经营管理

Web 2.0

以前一直对所谓的 Web2.0 不敢冒, 主要还是因为对 Web2.0 的概念不了解。 今天在 西西河 看到铁手老大的帖子: 对Web2.0的描述简明扼要,重点突出,很有感觉

一般而言,谈论WEB2.0时,我们的概念基本上是,1、用户贡献的内容。2、方便的交互环境。和以前的网站概念不同,WEB2.0主要是依靠用户的参 与。用户的直接参与和内容提供,这是大家都能看到的WEB2.0的核心要素。好的WEB2.0,是在于能够有比较清楚的定位,吸引特定的人群,并在技术上 方便用户的参与。比如MYSPACE更注重社交功能,三教九流,五花八门都可以找到或者建立自己的朋友圈子,内容并不重要。
从这个意义上说,digg.com del.icio.us 才有那么点儿Web2.0的意思。 :)

2008/08/25

重温 shell 编程的 变量操作

Shell编程的时候,总会觉得字符串的处理很麻烦! 其实人家也觉得麻烦,ksh/bash中自有一套办法来帮助你,只是很多时候我们都不知道或者没注意而已!
特别是有正则表达式

The character $ is used to introduce substitutable parameters.

${parameter}

The shell reads all the characters from ${ to the matching } as part of the same word even if it contains braces or metacharacters. The value, if any, of the parameter is substituted. The braces are required when parameter is followed by a letter, digit, or underscore that is not to be interpreted as part of its name, when the variable name contains a .. The braces are also required when a variable is subscripted unless it is part of an Arithmetic Expression or a Conditional Expression. If parameter is one or more digits then it is a positional parameter. A positional parameter of more than one digit must be enclosed in braces. If parameter is * or @, then all the positional parameters, starting with $1, are substituted (separated by a field separator character). If an array vname with subscript * or @ is used, then the value for each of the elements is substituted, separated by the first character of the value of IFS.


${#parameter}

If parameter is * or @, the number of positional parameters is substituted. Otherwise, the length of the value of the parameter is substituted.


${#vname[*]}
${#vname[@]}

The number of elements in the array vname is substituted.


${!vname}

Expands to the name of the variable referred to by vname. This will be vname except when vname is a name reference.


${!vname[subscript]}

Expands to name of the subscript unless subscript is * or @. When subscript is *, the list of array subscripts for vname is generated. For a variable that is not an array, the value is 0 if the variable is set. Otherwise it is null. When subscript is @, same as above, except that when used in double quotes, each array subscript yields a separate argument.


${!prefix*}

Expands to the names of the variables whose names begin with prefix.


${parameter:-word}

If parameter is set and is non-null then substitute its value; otherwise substitute word.


${parameter:=word}

If parameter is not set or is null then set it to word; the value of the parameter is then substituted. Positional parameters may not be assigned to in this way.


${parameter:?word}

If parameter is set and is non-null then substitute its value; otherwise, print word and exit from the shell (if not interactive). If word is omitted then a standard message is printed.


${parameter:+word}

If parameter is set and is non-null then substitute word; otherwise substitute nothing.

In the above, word is not evaluated unless it is to be used as the substituted string, so that, in the following example, pwd is executed only if d is not set or is null:

print ${d:-$(pwd)}

If the colon ( : ) is omitted from the above expressions, then the shell only checks whether parameter is set or not.


${parameter:offset:length}
${parameter:offset}

Expands to the portion of the value of parameter starting at the character (counting from 0) determined by expanding offset as an arithmetic expression and consisting of the number of characters determined by the arithmetic expression defined by length. In the second form, the remainder of the value is used. If A negative offset counts backwards from the end of parameter.
Note that one or more blanks is required in front of a minus sign to prevent the shell from interpreting the operator as :-. If parameter is * or @, or is an array name indexed by * or @, then offset and length refer to the array index and number of elements respectively. A negative offset is taken relative to one greater than the highest subscript for indexed arrays. The order for associate arrays is unspecified.



${parameter#pattern}
${parameter##pattern}

If the shell pattern matches the beginning of the value of parameter, then the value of this expansion is the value of the parameter with the matched portion deleted; otherwise the value of this parameter is substituted. In the first form the smallest matching pattern is deleted and in the second form the largest matching pattern is deleted. When parameter is @, *, or an array variable with subscript @ or *, the substring operation is applied to each element in turn.



${parameter%pattern}
${parameter%%pattern}

If the shell pattern matches the end of the value of parameter, then the value of this expansion is the value of the parameter with the matched part deleted; otherwise substitute the value of parameter. In the first form the smallest matching pattern is deleted and in the second form the largest matching pattern is deleted. When parameter is @, *, or an array variable with subscript @ or *, the substring operation is applied to each element in turn.



${parameter/pattern/string}
${parameter//pattern/string}
${parameter/#pattern/string}
${parameter/%pattern/string}

Expands parameter and replaces the longest match of pattern with the given string. Each occurrence of \n in string is replaced by the portion of parameter that matches the n-th sub-pattern. In the first form, only the first occurrence of pattern is replaced. In the second form, each match for pattern is replaced by the given string. The third form restricts the pat-
tern match to the beginning of the string while the fourth form restricts the pattern match to the end of the string. When string is null, the pattern will be deleted and the / in front
of string may be omitted. When parameter is @, *, or an array variable with subscript @ or *, the substitution operation is applied to each element in turn. In this case, the string portion of word will be re-evaluated for each element.

邓稼先传

缅怀一下~~~~ 做个书签!

http://www.tektalk.cn/2008/07/28/%E9%82%93%E7%A8%BC%E5%85%88%E4%BC%A0/

学海无涯

在西西河看到的!
做学问难啊! 做学问还要打好基础~~~
斗争要有理有利有节!!!

【原创】化学博士后的经历(1)---隐忧
【原创】化学博士后的经历(2)---艰难
【原创】化学博士后的经历(3)---醒悟
【原创】化学博士后的经历(4)---反击前哨战
【原创】化学博士后的经历(5)---当众摊牌
【原创】化学博士后的经历(6)---舌战
【原创】化学博士后的经历(7)---终于轻松了
【原创】化学博士后的经历(8)---最后的不厚道

2008/08/24

看看什么叫做工作中的有理有利有节

看看萨老的原创:原载于 西西河

【原创】东瀛坑熊记 上
【原创】东瀛坑熊记 下
【原创】东瀛坑熊记 中

香农极限 带宽计算公式

今天在西西河看到了 有人讲香农公式 http://www.ccthere.com/article/696151
不禁要感慨这人太牛了。给我们呈现了一种物理学中简单的美~~~

具体来说
  • If S/N >> 1, then
 C \approx 0.332 \cdot B \cdot \mathrm{SNR (in \ dB)}
where
\mathrm{SNR (in \ dB)} = 10\log_{10}{S \over N}
  • Similarly, if S/N <<>
 C \approx 1.44 \cdot B \cdot {S \over N}
In this low-SNR approximation, capacity is independent of bandwidth if the noise is white, of spectral density N0 watts per hertz, in which case the total noise power is B \cdot N_0.
 C \approx 1.44  \cdot {S \over N_0}

2008/08/21

苏联笑话

火车停了
话说列宁,斯大林,赫鲁晓夫,勃列日涅夫,戈尔巴乔夫五人同坐一列社会主义号火车前进, 突然火车停了,车长过来报告,前面铁路断了,列宁:"说发动一次星期六义务劳动把它修好",斯大林一瞪眼:"一定有阶级敌人搞破坏,抓起来枪毙",赫若有 所思 "前面不通,就倒车吧",勃列日涅夫:"找几个人下车摇火车就行了,乘客感到车在动就以为在前进",只有戈尔巴桥夫最绝:"把火车拆了,每人扛一件零件前 进, 到有铁轨的地方再装起来"于是拆了火车, ...


斯大林的烟斗
斯大林喜欢夜间工作,有一次他凌晨 3点迷迷糊糊就睡着了,把最喜欢的烟斗忘在了沙发缝里。第二天早上起来发现找不到烟斗了,就让贝利亚去处理这件事。第二天贝利亚揭露出了一个“利用偷烟斗 进行暗杀活动的托洛茨基组织”,10多名罪犯全被枪决,但是还是没找到那个烟斗。最后是苏斯洛夫坐这个沙发觉得塥的慌,打开一看才找到的。


赫鲁晓夫与猪
赫 鲁晓夫喜欢以农业专家自居。一次参观某集体农庄养猪场,发现一头病歪歪的小猪。农庄主席解释说这猪从小营养不良,养僵了。赫鲁晓夫当即说,把这猪抱到我 家,保证两个月养肥还给你们。赫氏回家怎么摆弄那猪也不长。情急下决定把猪处理掉。他在傍晚时分将猪放入婴儿车,准备推到莫斯科河边抛掉。谁知半路上偏偏 遇上米高扬。 “赫鲁晓夫同志,散步哪。” “啊……出来走走……” “这是谁啊?” “哦,是我……小外孙。” “我看看。哦,多好的孩子,长得真像他外祖父!”


赫鲁哓夫视察
赫鲁哓夫有一次视察农场,在参观到猪圈时,记者拍了照。回到报社后,想以赫鲁哓夫同志和猪的标题发表在真理报上。苏斯洛夫说这样会影响领导形象。结果,第二天,苏联人民手里拿到的真理报上的标题是:赫鲁哓夫同志视察农场(左起等三位为赫鲁哓夫同志)。


当时你再干什么
赫鲁晓夫在苏共二十大揭露斯大林的暴行时,台下有人递条子上去。赫鲁晓夫当场宣读了条子的内容:“当时你在干什么?”。然後问道:“这是谁写的,请站出来!”。连问三次,台下一直没有人站出来。于是赫鲁晓夫说:“现在让我来回答你吧,当时我就坐在你的位置上。”


两面派
原 苏联共产党中央第一书记赫鲁晓夫(1891--1971年)在愤怒遣责联合国阻挠苏调停刚果战后独立危机的行为不久,又向联合国秘书长哈马金尔德发去一封 礼节性的邀请书,请他参加苏联的国宴。赫鲁晓夫非常热情地欢迎哈马金尔德的到来。有人问他,为什么对前不久遣责过的人表现得如此热忱。赫鲁晓夫反问道: “你知道我国高加索地区人民的传统习惯吗?敌人在你家里作客,与你分享面包和食盐时,你要殷勤款待;一旦敌人跨出了你的家门,你就可以豁断他的喉管。”


勃列日涅夫的糊涂母亲
勃列日涅夫偏爱住非常豪华的住房,在郊外有好几处很奢侈的别墅。有一次,他把他的老妈接到城里来,骄傲地把自己的别墅展示给她看。谁知他的老妈一点也不高兴。勃列日涅夫很奇怪,问为什么。他妈答道:孩子,你住这么好的房子,要是共产党执政,你可怎么办呀……


勃列日涅夫论苏联民主
勃 列日涅夫当政时期,美国总统尼克松访问苏联。在记者招待会上,尼克松想借机宣扬美国式的民主,于是说:“在我们美国言论自由,任何人都可以在白宫前,大 骂:‘尼 克松是王八蛋!’肯定没有警察来抓他。” 勃列日涅夫不动声色平静的说:“在苏联同样也是言论自由,任何人也都可以在克里 姆林宫前大骂:‘尼克松是王八蛋’同样也没有警察来抓他!”


马克思主义者勃烈日捏夫
斯大林逝世后的 苏联,一直由精通马列的苏斯洛夫做意识形态的最高权威。搬倒赫鲁晓夫不久,地位还不是很稳固。苏斯洛夫为勃烈日捏夫写好了一片苏共中央全会的发言稿,其中 有几段引用的马克思的经典语句,但是在勃烈日捏夫在会上读时却跳过这些段落,让苏斯洛夫一脑子问号。会后去勃烈日捏夫家做客时才有机会问,勃烈日捏夫说 “你说他们会相信我读过马克思的书吗?如果我能引用出马克思话,柯锡金、谢列平他们都会笑的”


勃列日涅夫穿鞋
勃列日涅夫上班秘书对他说:“列昂尼德·伊利奇,您的皮鞋一只是棕色的,一只是红色的” 勃列日涅夫:这有什么奇怪,我家里还有一双也是这样的。

2008/08/15

Open Souce 的版权终于得以正名

Jacobsen v. Katzer:开源运动的一个重大胜利 http://www.cnbeta.com/articles/62360.htm
Jacobsen v. Katzer 的诉讼 http://en.wikipedia.org/wiki/Jacobsen_v._Katzer

案件大致情况是:
2006年,Bob Jacobsen起诉Matt Katzer,声称后者的软件没有遵守开源协议,标明源代码的出处和作者,要求法院认定这是侵犯著作权行为。但是,当时的旧金山联邦地区法院驳回了这个请 求,认为这只是“违反契约”(a breach of the licensing agreement),而不是“侵犯著作权”(copyright infringement)。 在美国通常“违法契约”诉讼人只能申请经济上的补偿, 而“侵犯著作权”则可以申请禁止令要求侵权人停止损害。
2008年8月,美国联邦上诉法院(Court of Appeals for the Federal Circuit)判决:“‘开源协议’ 是一种著作权协议,违反协议就是侵权行为。” 法官还表示 "Open source licensing has become a widely used method of creative collaboration that serves to advance the arts and sciences in a manner and at a pace that few could have imagined just a few decades ago,"

对于实行判例法系的美国,这将是法律体系对开源版权的确认!

PC Magazine 的报道: http://www.pcmag.com/article2/0,2817,2328027,00.asp

研究的精神

兴趣是最好的老师, 世界上没有完美的系统,电子车票系统也是如此。 这个PDF里讲述了一个MIT的三位学生发现了波士顿地铁电子车票系统的漏洞的故事。 国内的这种研究的精神似乎少了一些! 我们的教育导向太死板了!

2008/08/14

低价 PC or 低功耗 PC

随着Intel Atom的诞生, 低价PC或者低功耗PC的大潮开始涌动了! 回过头来说,低功耗PC也许还不错,但是低价PC这也许又不是Intel真正想要给我们这些消费者的! 看看 ccthere.com 上的文章!
特别是下面的这段文字:
“Intel每年销售1亿多片CPU,销售额为350-400亿美元,平均每片价格为200多美元,毛利润150美元以上。假设Intel为低成本电脑推 出价格为20美元左右的CPU,毛利润为每片5美元左右,每年销售2亿片,销售额为40亿美元,毛利润为10亿美元。如果这2亿片低成本芯片的销售不影响 原来的1亿多片的芯片销售,则Intel是愿意做的;但如果由于这2亿片低成本芯片的销售使得其他处理器的销售减少了2000万片,则Intel销售额减 少40亿美元,利润减少30亿美元。”(《龙芯之火,可以燎原》,2007年12月)
市场经济,利益至上 Intel Atom 的低功耗,低廉的价格,低下的性能都是Intel所期望的! Intel从一开始就没有打算用 Atom 来作为低价PC的CPU来销售,她的目标是低功耗PC。以至于Atom在这个领域内热卖的时候,Intel不但没有增加产量,而是控制产量提高售价,因为Intel比谁都清楚Atom的毛利太低,卖的太多不赚钱,既然它热卖那就索性提价提高毛利!

AMD也有他自己的应对策略。AMD比不了Intel,她没有太多的研发实验室,没有太多的工厂,不能像Intel那样同时搞很多的不同设计,既然不能用新的对应的产品和你比,那就用已经有的老产品改头换面来跟你比,反正最终的效果是一样的。 当然了,不是在低价PC,AMD的价格已经够低了; 只能在低功耗方面做文章, 这个Mini-780G就是一个不错的模式!
“功耗吗确实是你Intel Atom低,但是我的总功耗也不高,也就是个70/80W(比Atom高30W),但是性能比你强1倍,1080p完全没问题,不像你720p都吭吭哧哧的!为了看高清又有谁会在乎多点这一个灯泡呢?”
博弈啊!!!

2008/08/07

How to Write a Good Technical Documentation

Writing good documentation always hard! But you can make it better.

DO:

  • Fully understand the situation, and know the 5 W's:
    "Who, What, Where, When, and Why".

  • KISS: Keep It Simple and Stupid
  • Write agenda before you start

  • Keep the technical integrity
  • Add reference links for all the shared knowledge

  • Use diagram to show the complex logical
  • Use table to show the structured information
  • Compare the different design alternatives
  • Use bulletin and numbered list to express the idea

  • Write a good looking document
  • Have a good template
  • Use named style to control the format
  • Always do spelling/grammar check
  • Tidy your documentation

  • Ask for comments from others
  • Track changes between the reversions

DON'T:
  • Write long sentence or paragraph
  • Be afraid to delete some pieces
  • Be afraid to reconstruct sections
  • Be afraid to spend more time

Miscellanea:
  • Ask for others' help, and help others
  • Eats your own dog food
    Read it once more when you feel it were finished

2008/07/15

The smallest C program to print the biggest prime number

这个世界上,令人敬仰的人太多了~~~~ Fabrice Bellard 就是一个这个就是他的小程序,用来计算目前已知的最大质数的程序一共只有475字节,是一个一行程序。
可以通过任何C编译器编译。



int m=754974721,N,t[1<<24],a,*p,i,e=16804127,j,s,c,U;f(d){for(s=1<<24;s/=2;d=d*1
LL*d%m)if(s<N)for(p=t;p<t+N;p+=s)for(i=s,c=1;i;i--)a=*p+p[s],p[s]=(m+*p-p[s])*1L
L*c%m,*p++=a%m,c=c*1LL*d%m;for(j=0;i<N-1;){for(s=N/2;!((j^=s)&s);s/=2);if(++i<j)
a=t[i],t[i]=t[j],t[j]=a;}}main(){*t=2;U=N=1;while(e/=2){N*=2;U=U*1LL*(m+1)/2%m;f
(362);for(p=t;p<t+N;p++)*p=*p*1LL**p%m*U%m;f(415027540);for(a=0,p=t;p<t+N;)a+=*p
<<(e&1),*p++=a%10,a/=10;}while(!*--p);t[0]--;while(p>=t)printf("%d",*p--);}


格式化之后,它看起来这样:


#include <stdio.h>
#include <stdlib.h>

int m=754974721,N,t[1<<24],a,*p,i,e=16804127,j,s,c,U;
f(int d){
for(s=1<<24;s/=2;d=d*1LL*d%m)
if(s<N)
for(p=t;p<t+N;p+=s)
for(i=s,c=1;i;i--)
a=*p+p[s],p[s]=(m+*p-p[s])*1LL*c%m,*p++=a%m,c=c*1LL*d%m;
for(j=0;i<N-1;){
for(s=N/2;!((j^=s)&s);s/=2);
if(++i<j)
a=t[i],t[i]=t[j],t[j]=a;
}
}
main(){
*t=2;
U=N=1;
while(e/=2){
N*=2;
U=U*1LL*(m+1)/2%m;
f(362);
for(p=t;p<t+N;p++) *p=*p*1LL**p%m*U%m;
f(415027540);
for(a=0,p=t;p<t+N;) a+=*p<<(e&1),*p++=a%10,a/=10;
}
while(!*--p);
t[0]--;
while(p>=t)printf("%d",*p--);
}




计算输出的结果有 9M 之巨。
另外说一句,这个哥哥 72年出生,今年36岁。

2008/06/27

RPC forever / 永远的 RPC

I put the RPC (Remote Procedure Call) as title, but it didn't exactly talking about the RPC. :) Sorry! Indeed it is talking about the distribution computing, but this one is too large, sometimes, it just causes confusing. ;)
When the computer networks born in 1970s, distribution computing was coming in the vision, from that time to now. Variety of RPC/IPC mechanism were invited into the world. I think at least some of them are very familiar with you:
  • BSD Socket
  • telnet
  • FTP
  • SMTP/POP3/IMAP
  • NNTP
  • RSH/RLOGIN
  • ONC-RPC / DEC-RPC
  • NFS
  • HTTP
  • XMPP
  • SSH
  • CORBA/IIOP/GIOP
  • DCOM/COM
  • Java/RMI
  • SOAP/Web Service
  • XML-RPC
  • JSON
And so one! In the computer worlds, people do the similar things time and time again.
Because the IT industry always need the fresh blood!!!
Something else changed, you also want to change yours. :)

人都是喜新厌旧的!

2008/06/10

iPhone 3G is coming! 智能手机们都该洗洗睡了

Apple (TM) iPhone (TM) 3G 版本 Zippy 2008年6月9日在旧金山发布。


看看这次 Steve Jobs 给我们带来了什么? 8G内存的版本价格为 $199 = ¥1400 : 3G UMTS, Wifi, Apple's design.
我看所有高高在上智能手机都该洗洗睡了!

Apple 打得起这个价格战, 早就有分析人士估计过 iPhone的成本价格, 不过一百多刀。 那还是市面上的元器件价格, 就凭Apple的议价能力,还有进一步的利润空间。 即便保持当前的这个价格水平, Apple 仍旧能有 40%左右的毛利。 而iPhone 的研发成本早就通过第一批 iPhone $499 的暴利赚个八九不离十。 目前Apple要做的就是铆足力气,甩开所有潜在的竞争对手, 进而利用 iPhone 这个平台展开其他的增值业务。 最直接的说就是进入企业应用市场,iPhone 直接支持Microsoft Exchange Server, 支持iChat, BlackBerry 这次真的危了!

但从所谓高端智能手机这个层面来说,$199 的价格,不但让 Nokia, BlackBerry, SonyEricsson, Samsung, Motorola, LG 等厂商汗颜,恐怕就连那些国内的黑手机,山寨兄弟们也要卧倒一大片了。

市场规律就是这样, 技术优势总是属于后来者的, 就看你能不能把握了!

2008/06/05

不得不说的 Safari + WebKit

WebKit 引擎的发展在 Apple 的催动下,简直是一日千里。 随着 Safari for WindowsXP 的发布,M$ Windows用户也能感受一把 WebKit 的快感。

感觉上 Safari 本身并没有什么特别之处, 从应用程序框架的角度来说远不如 Mozilla Firefox 来的灵活。但是 WebKit 引擎确实不得不让人刮目相看。简单来说,WebKit 有如下的优势:
1, 浏览速度快
特别是 SquirrelFish 的 JavaScript 引擎发布之后,Safari简直跟飞一样。 而且下载的速度也巨快!

2,字体渲染效果好
所有的字体显示都采用了 anti-aliasing, 当然不是所有人都喜欢这样的字体效果,八成会说它显示的模糊。不过目前来说确实能够和内嵌点阵字体的SimSun一争高下。

3, 标准
当前的 Safari 3.1.1 + WebKit r34367 可以顺利通过所有的 acidtests, 特别是 Acidtest3 这个高难度动作, WebKit 不但可以全部完成而且运行飞快:< 2s 令人惊叹啊!

4, 超炫的 Web Inspector
Safari 内置的 Inspector 简直就是一个综合的 Web 应用集成开发工具。

不过也有些缺点:
1, Plugin 支持的问题还比较多
基本能工作,但是不稳定!

2,第三方应用太少

3, Safari 的 tab 功能一般

2008/05/13

Using :vimgrep inside VIM

Grep is really power tool under the UNIX domain. From Vim 7, an internal `grep` was provided by Vim.

Using `:vimgrep` is fairly easy, just in command mode, type in
:vim[grep][!] /{pattern}/[g][j] {file} ...
The `grep` result will be put into the `quickfix` list. The `:cnext`, and `:cprevious` can be used to navigate the `quickfix` list.

Let's do something to help us! Put this into your ~/.vimrc file.
" We can navigate the list by using the  and 
map <F3> :cnext
map <S-F3> :cprevious

After that, you will be able to use the <F3> and <shift>-<F3> navigate the `quickfix` list easily. :D

2008/05/09

Tip for trouble shooting the VIM syntax highlight

It is easy to do a VIM syntax highlight file, while it is a little difficult for you to do the trouble shooting, especially when you do a recursive pattern match with `contains`, `nextgroup` keywords.

Here is a small tip can help you a little bit.

put this into your ".vimrc" file

" display the syntax name under the cursor
map <F12> :echo synIDattr(synIDtrans(synID(line("."), col("."), 1)), "name")

For the next time, when you met some syntax highlight error, you can key in <F12> at the error place, VIM will tell you "what kind syntax ID that it is thing under the given position".

Keep fun! :)

2008/04/08

必须了解的"时间管理"原则

1、相等分配。任何人都没有足够的时间,然而每一个人又拥有自己的全部时间。这就是著名的“时间悖论”。时间是一种被相等地分配给所有人的资源。

2、错误的感觉。管理者的时间很少花费在他自己想要花费的地方。这种想法捉弄了时间的所有者,使他错误地认为,他的时间正用于该用的地方。

3、时间分析。每日活动记录至少持续一周,每过15分钟填写一次,这作为有效时间分析的基础是必要的。这种活动至少每半年应该重复一次,以免回复低劣的时间管理方式。

4、预料。事先有所准备的活动一般来说比事后补救的活动更为有效。小洞不补,大洞吃苦。避免发生以外的最好办法就是预料可能发生的以外事件,并为其制订应急措施。我们假定,如果事情要出错,那就无法避免。

5、计划。绝大多数难题都是由未经认真考虑的行动引起的。在制定有效的计划中每花费一小时,在实施计划中就可能节省3-4小时,并会得到更好的结果。如果你没有认真作计划,那么实际上你正计划着失败。

6、每日计划。每日计划对于有效地利用个人时间是必不可少的,它应该于前一天下午或当天开始时制订出来,并与近期的目标和活动相一致。

7、目标。较有效的结果一般是通过对既定目标的刻意追求来达到的,而不是依靠机会。目标管理的基本概念就来源于这个已被证实的原则。

8、优先次序。应该按照优先次序对各项任务进行时间预算或分配。不同的是很多管理人员花费时间的数量往往与他们任务的重要性成反比。

9、最后时限。给自己规定最后时限并实行自我约束,持之以恒就能帮助管理者克服优柔寡断、犹豫不决和拖延的弊病。

10、集中。在人们有组织的努力中,少数关键性的努力(大约20%)通常能够产生绝大多数结果(大约80%)。这条原则也称为“20/80定律”。有效的管理人员,总是把他们的努力集中在能够产生重大结果的那些“关键性的少数活动上”。

11、效能与效率。假如执行的是错误任务的话,或者把任务放在错误的时间里去执行,以及毫无目的的行动,无论效率怎样高,最终都将导致无效的结果。效率可以理解为正确地做工作。效能可以理解为正确地做正确的工作。所谓有效的活动,就是指用最少的资源,包括时间,来得到最大的效果。

12、活动与效果。管理人员往往忽视目标,或者忘记预期的效果,而把精力完全集中在活动上。终日忙忙碌碌渐渐成为他们的目标。这些管理人员趋向于活动型而不是效果型。他们不是去支配工作,而是往往被工作所左右。他们把动机误作成就,把活动误作效果。

13、最佳效果。用最小的努力获得最大的收益,这就是最佳效果。

14、不切实际的时间预算。管理人员往往对完成任务所需要的时间抱乐观态度。他们也往往希望别人能够更快地完成任务。所以有了墨菲的第二定律“每件事情做起来都比原来想象的要多花时间”。可见,管理人员更倾向于自己接受和期望别人做出不切实际的时间预算。

15、实现的可能性。预期事件出现的可能性直接伴随实现它的有计划的努力而增加。

16、紧急任务专制。管理人员常常处于紧急任务与重要任务互相推挤的状态中。紧急任务要求立即行动,就使得他们没有时间来考虑重要任务。管理人员就是这样不知不觉地被紧急任务所左右,并承受着时间的无休无止的重压,这使他们忽视了搁置重要任务所带来的更为严重的长期的后果。

17、危机管理(反应过度)。管理人员往往低估问题,不善预料问题的复杂性,或者遇到所有问题都反应过度,彷佛碰到危机。这种危机管理和消防式工作的倾向往往造成过分忧虑,削弱判断力,导致仓促决策和浪费时间精力。

18、选择忽略(有限反应)。对各种问题和需求的反应要切合实际,并要受制于情况的需要。有些问题如果你置之不理,他们消失了。通过有选择地忽略那些可以自行解决的问题,大量的时间和精力就可以保存起来,用于更有用的工作。

19、机动性。安排个人时间的程度上应有机动性,以便于应付个人无法控制的力量。总之,时间安排不要过满,也不要过松。

20、问题分析。不区分问题的原因和现象,结果必然丢失实质性问题,而把时间和精力耗费在表面问题上。

2008/04/07

Intel Atom

当初 Intel 在 2006年6月,果断地卖掉了移动处理器 XScale 以及相关业务,就给人一种感觉—— Intel 要有新的动作了! 在蛰伏了一年零十个月之后 Intel 带着 Atom(原子)处理器, 又重新回到了手持移动计算领域!

Atom 处理器与 XScale 处理器不同,XScale 是一个基于ARM5 的高端智能手机以及PDA的处理器,它是一颗基于ARM架构的RISC处理器,在这单生意中 Intel 不过是一个购买了 ARM Ltd. 公司专利的生产商。而 Atom 的则是 Intel 自家的x86架构,在x86架构占据统治地位的PC领域,Intel可谓顺风顺水!这一次 Intel 利用自己 45nm的先进生产工艺, 把x86带入了 Mobile Internet Devices (MIDs) 领域。

于此相呼应的, Microsoft 已经延长了 Windows XP 的支持时间到 2010年, 这纯粹是为了 x86 的 MID 设备加料啊~~~

看看 Intel Atom 都带了些啥:

• Supports Hyper-Threading Technology 2-threads
• Support for IA 32-bit architecture
• Intel® Virtualization Technology (Intel® VT)
• Intel® Streaming SIMD Extensions 2 and 3 (Intel® SSE2 and Intel® SSE3) and Supplemental Streaming SIMD Extensions 3 (SSSE3) support

俨然是一个 Pentium4!

2008/04/02

Wireshark 1.0 released

In my mind, Wireshark ( and its predecessor -- Ethereal) kept in version 0.9x.x for a very long time. Now the Wireshark v1.0 were release finally at Mar 31, 2008. Check the http://www.wireshark.org/news/20080331.html for details.

2008/01/08

Oracle Database PL/SQL User's Guide and Reference

非常不错的PL/SQL的介绍,文字虽然不多,但是足可以让你对PL/SQL的基本功能和语法有了大致的了解。抽象水平非常高啊~~~

下回打印一份随身携带阅读!

2007/07/13

2007/06/21

Installation Debian/Ubuntu over SSH

By using the debootstrap, it is possible for us to install the Debian or Ubuntu inside an Linux machine without a booting from Floppy/CD/USB/Net. It is really funny.

2007/05/07

Yahoo! UI Library (YUI)

Yahoo! UI Library (YUI) an BSD licensed JavaScript UI library released by Yahoo!.

I play with it for a while, at the first glance, it looks like a Dojo Toolkit. But unlike the Dojo, all the functions are very well documented with JSDoc. For all the sub-modules, full/debug/min versions are provided for purposes. But it only provides a subset features of Dojo. :)

So YUI is:
  • Well documented;
  • Well organized object hierarchy;
  • Less features

2007/05/06

Perl 5.8 PerlIO feature

With the new PerlIO feature and Unicode support in Perl 5.8, it is possible to do the internal encoding change with only a few lines of code.

Please check the code below. It will be able to read the GBK input from STDIN and convert it to UTF-8 to STDOUT. :)


#!/usr/bin/perl -W

use encoding "gbk", STDOUT => "utf8";
while(<>){print};


Power and Simple. :D

又长了一岁~~~

又长了一岁,为自己庆祝一下! :D

2007/04/09

Waltzing with Bears

最近每天坐在城铁上,就会翻看几页 《与熊共舞》 其中第14章,风险发现的详细过程 ,里面对企业里使人们对风险三缄其口的原因。 说起来这确实是很普遍存在的。

因为在这些企业里,有一些根深蒂固的不成文的规定:
  1. 不要成为有消极想法的人;
  2. 不要指出问题,除非你有解决办法;
  3. 不要说任何事可能是一个问题,除非你能证明它是;
  4. 不要做拆台的人;
  5. 不要明确指出问题,
说起来大致如此......

2007/02/28

Erlang 的运行时更新

Erlang 作为电信级开发语言,在设计之初就有了在运行时自动更新程序,也就是不停机打patch的能力。 首先这种功能对于电信级别的程序来说,是非常必要的,如果不能做到这个5个9基本上就是空谈了。

然而对于传统的使用C/C++或者Java开发的程序而言,全面支持这种能力是非常复杂的,这种复杂性主要是有由于C/C++ 语言的自身特性所决定的。由C语言开发的程序的运行态,在地址空间中一般都具有4个以上的sections:
  1. text/代码段 就是程序本身
  2. data/数据段 用来保存全局变量,静态变量,以及未初始化的变量;
  3. stack/程序堆栈 用来保存当前线程的临时变量 对于C/C++ 来说它保存了程序的运行状态;
  4. heap/堆 用来保存程序运行中分配的临时变量;

text 在连接程序完成之后就确定的,对于同一份源程序产生的都是完全一样的。
data 在程序的连接完成之后,它在内存中的位置也已经确定,但是内容可能会随运行态改变。
stack 和 heap 则是完全动态的,而一个运行程序的stack数量和他所具有的thread数量相对应。基本上可以认为这两个段不能够采用认可以预定义——简单替换的方式进行更新,它们的内容对于非运行系统而言是不可知的。

因此为一个处在正在运行中的应用打补丁,需要:
  1. 不改变text代码段中的函数的入口地址。因为在stack中会保存这些函数的入口地址,如果改变了它们的地址,必将导致程序跑飞。
  2. 不能改变text代码段中所有已有函数的参数或者调用方式。
  3. 不能在中间增加数据段中全局变量。因为这将改变已有的全局变量的地址,使代码引用错误的变量。
  4. 不能简单替换数据段中的变量内容,即不能随意修改源程序中非const全局变量的内容。
然而对于C/C++程序而言,如果需要不停机打patch,这是最基本的要求。而在实际工作中,很难要求所有的fix都满足上面的要求! 其实也能做,但是代价太高了~~~。

Erlang 只有代码段,没有数据段,所有数据都动态,实现这样的功能确实要简单很多。而且 Erlang 又是已虚拟机的方式运行,替换代码段的难度又有所降低。

对于 Erlang 而言,运行时程序更新,这样的功能就算是水到渠成吧!

2007/02/11

关于 Erlang

在国内小程序员的圈子里,高水平的不多,但是跟风的水平还是不低的,C/C++, VB, Delphi, Java, C#, Perl, Python, PHP, Lua, JavaScript, Rudy, Haskell, Erlang...... 随风而来。不才也跟了一把风 Erlang 了一把! 说起这个 Erlang 真正令我感兴趣的地方是——它是由 Ericsson 开发出来的用于电信级应用程序开发的语言。说来惭愧现在也算是在电信圈子里面(当然不在Ericsson) 讨生活的菜鸟吧! 不由自主地对别人如何做同样的东西有兴趣。 算起来也在上面画了N个小时了,有点感受也记录下来总也不算是枉费了这些时间。

首先,Erlang 诞生于于1980年代,在 Ericsson Computer Science Laboratory,虽然没有官方的说明,当时我个人感觉,Erlang的根本源于LISP,虽然语法上作了一些变化,但是语言的本质上确是不可回避的LISP风骨:函数语言,自动内存管理,原子概念,LIST/表操作,不一而足,虽然从语法上作了一些改变,摒弃了繁复的"()", 引入了 "->", ",", ";", "." 这样只是更加突出了函数的定义和使用时的方便性。

其次,为了函数语言能够在工程实践中具有实际应用,Erlang在语言层次上引入了许多辅助的功能。1)Erlang从语法层次上定义了一种引入副作用(side effect)的方法进程间消息的发送—— Pid ! Message , 与接收 Receive。这与 Erlang 虚拟机的轻量级进程相结合,无疑是提供了一个颇具工程价值的强悍的函数式语言;2)引入的模块(module),函数输出/输入定义(export/import),引入宏; 3)增强的 Term 匹配; 4)引入异常处理机制(try/catch),5)引入 tuple 以及 record 数据类型。
不过坦白的讲,除了第一点进程间消息的发送与接受具有些实质上的意义之外,异常及其处理机制,tuple数据类型,感觉上却有些画蛇添足之感,这些变化只是让程序设计的复杂性有所增加,并没有什么实质性的提高。
特别是异常这样的东西,很有可能是受了这些年 C++/Java语言的毒害吧,就结构化程序而言,我们还可以异常可以简化程序的正常流程,增加可读性。可是对于函数式语言除了需要多些try/catch这样的另类语法,我们又得到了什么呢?赫赫,只能是仁者见仁智者见智了!

还有,Erlang/OTP 为程序开发人员提供了一个相当完善的,可以李可使用的程序库 OTP。在当前的这个软件开发时代。一个高质量,高易用性的 library 对于语言的发展有着非常大的推动作用,Java语言,也正是凭借着功能丰富,充分文档化的Java API在当今程序设计领域占据着重要地位的。对于一个电信设备专用语言而言,OTP已经为我们提供了,SNMP Agent, CORBA, CORBA IDL, CORBA Event, 数据库。确实极大的方便了设备开发人员的工作。

再就是 Erlang 的 soft real-time 特性。 以及 Erlang 的虚拟机。基本上可以认为Erlang编译出来的程序式平台无关的, Erlang设计的程序可以运行在Linux/Windows/Solaris平台。 这样就可以构造 Linux + Erlang 德超强组合。也算是开拓了电信设备设计的一种新思路吧!

Ericsson 会把这样的东西放出来还真是很有意思的,就如同在 Erlang 的 FAQ 中写的

10.4. Why is Ericsson giving away Erlang?
(The following is my personal impression. I don't speak for Ericsson!)

Nothing to lose: Ericsson's core business is telecommunications products, selling programming tools is not really a business Ericsson is interested in.

Stimulate adoption: Erlang is a great language for many sorts of systems. Releasing a good, free development environment is likely to make Erlang catch on faster.

Generate goodwill: Giving away cool software can only improve Ericsson's image, especially given the current level of media attention around "open software".

2007/02/03

Common Lisp HyperSpec

曾经在研究生阶段上过一门计算机系开设的人工智能基础的课程。
在课程的最后还用clisp完成了一个寻找最佳乘车路线的程序作为课程设计。
当时对clisp真的没什么感觉,就是一堆的括号 (((((...).(...)))))
CLISP 就是 Common List 是 ANSI X3J13 标准化之后的Lisp语言
这也算是我对Lisp的一点儿初步的认识吧!

说起来 LISP 也算是自成一派的人工智能语言, 函数语言的基础。
Lisp之根源中文版
,以及英文原版 The Root of Lisp 可以算是Lisp入门必读了吧!

看到Lisp就会感觉到人类智慧的伟大!
于lisp相比 XML就有点儿太丑陋了!

2007/01/31

Bash新手指南

今天又看到了 BASH 的新手指南,网络上中文的东西越来越多了!
只不过又是翻译作品,希望今后有越来越多的中文原创!

2007/01/30

VIM syntax for JavaScript 0.7.2 released

Today I do update the JavaScript syntax script for VIM to 0.7.2.

Until now PRC 2007.01.30-21:37 my script got:
Rating 332/99, Downloaded by 1684

I do like more feature, but I like the accuracy much more. :D
Without the context based parser, it can't highlight the JavaScript properly.

2007/01/17

Hack the IDLE.DLL of Yahoo Messenger

Yahoo Messenger is very nice IM software. But it used the very old window HOOK functions to detect the user idle time through IDLE.DLL. The idle.dll is a 6k DLL file which created with Microsoft VC 7.1 and linked with MSVCR71.DLL. In this way, the IDLE.DLL will be injected to all the user applications, and hook the message queue of all applications, and it will also injects the MSVCR71.DLL into the user applications. Please refer MSDN for details about the Windows HOOK function.

Yahoo Messenger 是一个很不错的IM软件。但是它是用了一个非常陈旧的Windows Hook功能,因此制造了一个idle.dll 用来来检测用户的发呆时间。这个IDLE.DLL 文件看起来并不大,只有6k,其实它是一个用VC7.1编译产生的动态链接库并且动态链接到MSVCR71.DLL。 由于HOOK函数需要把 IDLE.DLL 注入到所有的用户程序中,MSVCR71.DLL 也会被注入到所有的用户程序中。 而且这个IDLE.DLL 会进入所有用户程序的消息循环。在所有的程序中都有这个 idle.dll 实在是让人不爽。 ;)

Let's check the IDLE.DLL
下面就让我们看看这 IDLE.DLL


C:\Program Files\Yahoo!\Messenger>dumpbin /exports idle.dll
Microsoft (R) COFF/PE Dumper Version 8.00.50727.42
Copyright (C) Microsoft Corporation. All rights reserved.


Dump of file idle.dll

File Type: DLL

Section contains the following exports for idle.dll

00000000 characteristics
450867C8 time date stamp Thu Sep 14 04:19:20 2006
0.00 version
1 ordinal base
3 number of functions
3 number of names

ordinal hint RVA name

1 0 00001016 ?IdleUIGetLastInputTime@@YAKXZ
2 1 000010C3 ?IdleUIInit@@YAHXZ
3 2 0000111C ?IdleUITerm@@YAXXZ

Summary

1000 .data
1000 .rdata
1000 .reloc
1000 .rsrc
1000 .text
1000 Y_IDLE


It has 3 C++ functions defined, and a customized data section "Y_IDLE", I think it is the shared data section which used to store the latest user active time stamp. While what's the function protocol for these 3 function? I found a very good documentation for the C++ name mangling of different compilers at URL http://www.agner.org/optimize/ Calling conventions for different C++ compilers and operating systems
它定义了三个输出函数,同时自定义了一个程序段 Y_IDLE 相比这应该是一个数据段,用来记录从各个应用程序收集到的最新的用户消息发出的时间。 而这三个函数应该是用C++的命名规则输出的,但是这三个函数的原型是什么呢?幸好发现了一个非常好的文档,详细地描述了各种编译器的 C++ name mangling 也就是符号标的转换规则。参见 http://www.agner.org/optimize/ Calling conventions for different C++ compilers and operating systems


In fact, from the Windows 2000, WIN_VER>=0x500 there is a new function GetLastInputInfo in user32.dll, it will provide the Last user input time stamp quickly.
其实从Window2000开始,微软在 User32.dll 就提供了一个新的函数 GetLastInputInfo 它就可以用来返回用户的最后输入的时间。



/**
* This is used to hack the Yahoo Messenger.
* compiled with VC7.1 as:
* cl -W3 -O1sy -LD -MD -D_WIN32_WINNT=0x0500 idle.cpp -Feidle.dll User32.lib
*/

#include

#pragma section("Y_IDLE",read,write)
__declspec(allocate("Y_IDLE"))
int Y_IDLE = 0;

#define DllExport __declspec( dllexport )

DllExport DWORD IdleUIGetLastInputTime()
{
LASTINPUTINFO lii;
lii.cbSize = sizeof(lii);
GetLastInputInfo(&lii);
return lii.dwTime;
}

DllExport INT IdleUIInit()
{
return TRUE;
}

DllExport VOID IdleUITerm()
{
return;
}



This will be able to create a new IDLE.DLL
这样就可以知道一个新的 idle.dll , 而且它也再也不会被注入到其他的程序中了。
替换原来的 IDLE.DLL 还真不错~~~~ 工作正常。


写在后面


在找到 IDLE.DLL 输出函数的原型还真花了些时间。后来才发现其实微软已经给我们提供了一个很方便的工具,那就是随Platform SDK 分发的 Dependency Walker (depends.exe) 里面有一个 Undecorate C++ functions 的功能,我们只需要用Dependency Walker 打开 IDLE.DLL 就可以看到输出函数的原型了。


其实

2006/12/25

最简化的Nmake Makefile


!include <win32.mak>

## Link with MSVCRT and MSVCP
#.cpp.exe:
# cl -nologo -MD -W3 -O1y -EHsc -I. $**

.cpp.exe:
cl -nologo -W3 -O1y -EHsc -I. $**

clean:
del /q /f *.exe *.obj

最简化的GNUMakefile


## GNU Makefile with MinGW/MSYS
## MinGW 下面简化的Makefile 需要 MSYS
## It can be invoked like `mingw32-make hello.exe`
## This will compile the hello.cpp to hello.exe

CXXFLAGS=-I. -O3

## 没有下面这条指令, 后缀通配指令不能识别 .cpp.exe
.SUFFIXES: .exe

.cpp.exe:
g++ -Wall $(CXXFLAGS) -o $@ $<


.PHONY : clean
clean:
rm -f *.exe *.obj *.o

2006/12/09

到这里都一年了~~~

算起来到这里已经一年多了, 中间断断续续当然了也包括一些可观的原因,一共也没有放多少东西上来。
总算还有两片篇幅较长的原创,也算是聊以自慰了。

再接再厉好了!希望自己能够百尺竿头更进一步~~~

2006/12/01

"Hello World" XUL application with XULRunner

Today, I do spend some hours with the XULRunner -- a Mozilla runtime package which can be used to bootstrap XUL+XPCOM applications that are as rich as Firefox and Thunderbird. I will create a "Hello World" XUL application step by step, just to remind myself. I will be very glad if it is also helpful for you. :)
今天,闲暇无事,花了几个小时玩耍了一下 XULRunner -- 一个 Mozill 运行库,以及 XUL+XPCOM 应用程序的启动器,利用它可以构建 Firefox 和 Thunderbird 一样的应用程序。我用它写了一个简单的 "Hello World" XUL 应用程序,在这里我把程序创建的过程一步一步地记录下来,主要是对自己的学习做一个笔记。希望它也能对其他人有所帮助。

About XULRunner

XULRunner is a Mozilla runtime package that can be used to bootstrap XUL+XPCOM applications that are as rich as Firefox and Thunderbird. It will provide mechanisms for installing, upgrading, and uninstalling these applications. XULRunner will also provide libxul, a solution which allows the embedding of Mozilla technologies in other projects and products. [Ref: http://developer.mozilla.org/en/docs/XULRunner]
Main features
  • XPCOM
  • Networking
  • Gecko rendering engine
  • DOM editing and transaction support (no UI)
  • Cryptography
  • XBL (XBL2 planned)
  • XUL
  • SVG
  • XSLT
  • XML Extras (XMLHttpRequest, DOMParser, etc.)
  • Web Services (SOAP)
  • Auto-update support (not yet complete)
  • Type ahead find toolbar
  • History implementation (the places implementation in the 1.9 cycle)
  • Accessibility support
  • IPC services for communication between gecko-based apps (not yet complete)
  • Storage/sqlite interfaces (not yet turned on by default)

Installation

For current 1.8.0.x release, XULRunner only available in ZIP format, you can download it and unzip at any place you want.
Refer: http://developer.mozilla.org/en/docs/XULRunner:Deploying_XULRunner_1.8

Skeletons of a XUL Application

I name my "Hello World" application as HelloWorldApp or helloworldapp,

/HelloWorldApp
/chrome
- app files ...
chrome.manifest
/defaults
/preferences
prefs.js
application.ini
All the folders/files are necessary for a XUL application, "app files..." will be variant, it depends on your application itself.

Define the XUL application.ini

This is the application.ini of the helloworldapp:

[App]
; This field specifies your organization's name. This field is recommended,
; but optional.
Vendor=MozillaTest
;
; This field specifies your application's name. This field is required.
Name=HelloWorldApp
;
; This field specifies your application's version. This field is optional.
Version=0.0.1
;
; This field specifies your application's build ID (timestamp).
; This field is required.
BuildID=20061030
;
; This field specifies a compact copyright notice for your application. This
; field is optional.
Copyright=Copyright (c) 2004 Mozilla.org
;
; This ID is just an example. Every XUL app ought to have it's own unique ID.
; You can use the microsoft "guidgen" or "uuidgen" tools, or go on
; irc.mozilla.org and /msg botbot uuid. This field is optional.
ID={CAB1E5C0-1E38-44c3-B153-754AD72E898B}

[Gecko]
;
; This field is required. It specifies the minimum Gecko version that this
; application requires.
MinVersion=1.8
;
; This field is optional. It specifies the maximum Gecko version that this
; application requires. It should be specified if your application uses
; unfrozen interfaces.
MaxVersion=1.9

You must specify the [App] name. It will be used for XULRunner to find the relevant prefs.js .
App::name 必须要指定,因为它将影响 XULRunner 如何读取 prefs.js 。

Define the prefs.js (helloworldapp-prefs.js) / 定义应用程序的 Preferences.

After the application.ini is defined, it is necessary to have a -prefs.js under ${APP_ROOT}/defaults/preferences
Here is the helloworldapp-prefs.js
定义了 application.ini 之后, 下一步就是指定 -prefs.js , 在这里我们的 是 helloworldapp, 因此我们需要在 ${APP_ROOT}/defaults/preferences目录下面建一个 helloworldapp-prefs.js JavaScript 文件,文件的内容如下:
pref("toolkit.defaultChromeURI", "chrome://helloworldapp/content/helloworld.xul");
pref("general.useragent.extra.helloworldapp", "HelloWorld/0.1");
It define "toolkit.defaultChromeURI" to "chrome://helloworldapp/content/helloworld.xul" .
其中最主要的部分就是定义了,"toolkit.defaultChromeURI" , 它就是 XUL 程序的缺省启动页面。

Setting up chrome.manifest / 设定 chrome.manifest

This file performs the mapping between a chrome:// url and your application files:

这个文件主要用来实现 XUL 程序中使用的 chrome:// scheme 和你自己编写的应用程序文件的对应。


This is the chrome.manifest of "Hello World" application.

Hello World 程序的 chrome.manifest 文件的内容如下:

content helloworldapp file:helloworldapp/
This institution tells XULRunner to look at ${APP_ROOT}/chrome/hellowworldapp/ when it encounters a chrome://helloworldapp/content/ URI. The change of the application name and folder name will impact the URI looking up of XULRunner.
通过这个指令,我们告诉 XULRunner,当程序中 URI 为 chrome:://helloworldapp/content/ 的时候,就到 ${APP_ROOT}/chrome/hellowworldapp/ -- 应用程序的chrome目录下面的helloworldapp 目录下面去寻找相应的文件。 我们也可以相应的改变 上面的语句中的 application name 以及目录的名字,但是这个改变将影响 XULRunner 如何解释以 chrome:// 为类型的 URI 的定位。 进一步的内容可以参考 ITArt 同志的Blog http://itart.wordpress.com/2005/12/05/mozext-ch3/ 第3.6章。

Chromes / 全金属外壳

To make it easy for the development, we are using the plain folder/files for the chrome.
为了方便进行开发和调试,在这直接使用文件和目录来保存 chrome 文件。

Most XUL applications are distributed as a .jar file, rather than a subfolder of chrome/ with all the files scattered about. When you do want to deploy it as a jar:

  1. Zip up your /chrome/applicationName folder, put the applicationName.zip in the /chrome directory.
  2. Rename applicationName.zip to applicationName.jar
  3. Change the chrome.manifest to point to applicationName.jar:
    content applicationName jar:applicationName.jar!/
The "jar:" protocol tells XULRunner that this is a jar file. With "jar:filename.jar!/uri/folder/", XULRunner will look for the resource under the give folder "/uri/folder/" in the JAR file.
"jar:" 协议,用来通知 XULRunner 所需要要得资源文件都被包裹在 JAR 文件中。"jar:filename.jar!/uri/folder/" 为 XULRunner 指名相应的资源需要去 filename.jar 文件的 /uri/folder/ 目录下面寻找。

Build the GUI with XUL / 使用XUL来构建 GUI

In the perfs.js, the toolkit.defaultChromeURI was defined as "chrome://helloworldapp/content/helloworld.xul", it will be the default GUI of this Hello World application.
在 perfs.js 中, 我们将 toolkit.defaultChromeURI 定义为 "chrome://helloworldapp/content/helloworld.xul", 它就是我们这个Hello World 应用程序的缺省 GUI.

The XULRunner looks up the URI -- "chrome://helloworldapp/content/helloworld.xul" at the ${APP_ROOT}/chrome/helloworld/helloworld.xul . So helloworld.xul will be the main GUI file.
对于 URI -- "chrome://helloworldapp/content/helloworld.xul", XULRunner 将会翻译成 ${APP_ROOT}/chrome/helloworld/helloworld.xul 并且试图使用这个XUL文件作为主 GUI 文件。


<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>

<window
id = "helloworldapp"
title = "Hello World!"
width = "300" height = "200"
xmlns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<button label="Hello World" onclick="window.alert('Hello World!');"/>
</window>
This is a very simple XUL file which defined a frame window, and there is only a button on it. When the button is clicked, there will be a prompt alert. It just works like HTML.
这是一个非常简单的XUL文件,它只定义了一个主窗口,在主窗口中只有一个按钮控建,我们还定义了一个onclick事件的JavaScript程序,当按钮被点击就会弹出一个警告窗口,这一部分就和普通的HTML没有什么区别。

Ready and Go / 预备跑

Ok, it is time to go. Open a Command Processor window, cd into the ${APP_ROOT}, assuming the ${APP_ROOT} is "HelloWorld", and it is located within the XULRunner's folder, for me, the XULRunner is installed at "e:\devel\xulrunner". We can launch the Hello World application in this way.
好了,该出发了! 请打开一个命令行窗口,并且进入 XULRunner的安装目录, 比如说 XULRunner 被安装在 e:\devel\xulrunner ,HelloWorld应用程序的目录就在 XULRunner的安装目录中。我们就可以按照下面的命令来运行 HelloWorld。
e:\devel\xulrunner>xulrunner.exe HelloWorld\application.ini 
in other words:
${XULRUNNER_HOME}\xulrunner.exe ${APP_ROOT}\application.ini
当然也可以使用上面的方法来运行,这里 ${XULRUNNER_HOME} 和 ${APP_ROOT} 应该被替换成她们实际的全路径名。

We got it, isn't it?


Have Fun~~~

BlockChain 相关电子书

@copyright of Sam Chadwick   - https://thehub.thomsonreuters.com/groups/bitcoin/blog/2017/09/10/blockchain-paper Blockchain Papers A c...