<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>StephenChan&#039;s Tech Space</title>
	<atom:link href="http://blog.endlesscode.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.endlesscode.com</link>
	<description>Stay Hungry. Stay Foolish.</description>
	<lastBuildDate>Tue, 25 Oct 2011 01:15:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>基于coroutine的gevent</title>
		<link>http://blog.endlesscode.com/2011/10/22/gevent-lib/</link>
		<comments>http://blog.endlesscode.com/2011/10/22/gevent-lib/#comments</comments>
		<pubDate>Sat, 22 Oct 2011 13:13:51 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=1209</guid>
		<description><![CDATA[coroutine也是一种并发模型，但不同于thread和callback，它的所有task都是可以在一个线程里面执行，然后可以通过在一个task里面主动放弃执行来切换到另一个task执行，它的调度是程序级的，不像thread是系统级的调度。gevent就是一个基于coroutine的python网络开发框架，不像twisted那样集成了很多库和协议，gevent非常精简，当然文档也很少，在性能上的话，看了PyCon上的视频，对比了twisted和其他的几个库，在内存的性能上非常地优秀，代码简洁而且也支持多核。 做了个相当简单的ChatService，有登录、群发消息、退出这3个消息，协议就是用简单的json了，有时间再试试xmpp看看。&#8221;monkey.patch_all()&#8221; 这个调用就把python原生的一些socket对象和方法替换成非阻塞的异步调用，写起来感觉还是很方便。 #!/usr/bin/env python #-*- coding:utf-8 -*- import sys import simplejson from gevent import monkey; monkey.patch_all(); from gevent.server import StreamServer from common import Protocol, gen_pro_data, parse_pro_data class ChatService: def __init__(self): self._clients = {} self._handlers = { Protocol.Connect : self.connect, &#8230; <a href="http://blog.endlesscode.com/2011/10/22/gevent-lib/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>coroutine也是一种并发模型，但不同于thread和callback，它的所有task都是可以在一个线程里面执行，然后可以通过在一个task里面主动放弃执行来切换到另一个task执行，它的调度是程序级的，不像thread是系统级的调度。gevent就是一个基于coroutine的python网络开发框架，不像twisted那样集成了很多库和协议，gevent非常精简，当然文档也很少，在性能上的话，看了PyCon上的视频，对比了twisted和其他的几个库，在内存的性能上非常地优秀，代码简洁而且也支持多核。</p>
<p>做了个相当简单的ChatService，有登录、群发消息、退出这3个消息，协议就是用简单的json了，有时间再试试xmpp看看。&#8221;monkey.patch_all()&#8221; 这个调用就把python原生的一些socket对象和方法替换成非阻塞的异步调用，写起来感觉还是很方便。</p>
<p><span id="more-1209"></span></p>
<pre class="brush:python">#!/usr/bin/env python
#-*- coding:utf-8 -*-

import sys
import simplejson
from gevent import monkey; monkey.patch_all();
from gevent.server import StreamServer
from common import Protocol, gen_pro_data, parse_pro_data

class ChatService:
    def __init__(self):
        self._clients = {}
        self._handlers = {
            Protocol.Connect : self.connect,
            Protocol.SendMsg : self.sendmsg,
            Protocol.Quit : self.quit,
        }

    def connect(self, sock, data):
        userinfo = self._clients.get(sock, None)
        if userinfo: return
        self._clients[sock] = data['name']
        print "New User : %s" % (data['name'],)

    def sendmsg(self, sock, data):
        msg = gen_pro_data(data)
        for s, u in self._clients.items():
            if sock != s:
                s.send(msg)

    def quit(self, sock, data=None):
        if sock in self._clients:
            print "User [%s] quit." % (self._clients[sock],)
            del self._clients[sock]
            sock.close()

    def process(self, sock, promsg):
        cmd = promsg['cmd']
        func = self._handlers[cmd]
        func(sock, promsg)

# server chat service
chatservice = ChatService()

def serve(sock, addr):
    while True:
        try:
            length = ord(sock.recv(1))
            content = sock.recv(length)
            # protocol :  length + json({'cmd' : 'sendmsg', 'msg' : 'hallo'})
            promsg = parse_pro_data(content)
            chatservice.process(sock, promsg)
        except:
            chatservice.quit(sock)
            break

if __name__ == "__main__":
    host = sys.argv[1]
    port = int(sys.argv[2])
    print "Start chat server on %s:%s" % (host, port)
    try:
        chatserver = StreamServer((host, port), serve)
        chatserver.serve_forever()
    except:
        chatserver.kill()</pre>
<p>写了一个简单的测试，创建了5000个连接，然后定时发消息，服务器也没显得有什么压力。</p>
<pre class="brush:python">def test():
    import gevent
    from gevent.pool import Pool

    def robot(idx, host, port):
        # client chat service
        chatservice = ChatService(host, port)
        chatservice.connect("user%s" % (idx,))
        while True:
            chatservice.sendmsg("hallo from %s" % (idx,))
            gevent.sleep(3)
    host = sys.argv[1]
    port = int(sys.argv[2])
    count = 5000
    pool = Pool(5000)
    for i in range(count):
        pool.spawn(robot, i, host, port)
    pool.join()</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2011/10/22/gevent-lib/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Shell的知识点整理</title>
		<link>http://blog.endlesscode.com/2011/10/15/code-snippet-of-shell/</link>
		<comments>http://blog.endlesscode.com/2011/10/15/code-snippet-of-shell/#comments</comments>
		<pubDate>Sat, 15 Oct 2011 14:52:08 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=1169</guid>
		<description><![CDATA[这几天抽了点时间看了一下《Advanced Bash-Scripting Guide》， 之前一直觉得shell这门脚本很有意思，虽然用得不多，但感觉shell这门脚本似乎有点粗糙，但看了abs-guide之后就觉得shell还是很强大的，很多高级特性之前都没曾接触过，平时也用得不算很多。浏览了一下abs-guide之后做了一些简单的笔记，方便以后查看，每个&#8221;echo ===&#8221;之间就是代码片段，在bash version 3.2.48下测试过，点解高亮区的&#8221;view source&#8221;可以直接复制所有代码。 #--------------- Begin #!/usr/bin/bash for arg in "Hello World What The Fuck" do echo $arg done echo "==================================" FILES="/usr/bin/accept /usr/sbin/pwck /usr/sbin/chroot /usr/badblocks /sbin/ypbind" for file in $FILES do if [ ! -e "$file" &#8230; <a href="http://blog.endlesscode.com/2011/10/15/code-snippet-of-shell/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>这几天抽了点时间看了一下《Advanced Bash-Scripting Guide》， 之前一直觉得shell这门脚本很有意思，虽然用得不多，但感觉shell这门脚本似乎有点粗糙，但看了abs-guide之后就觉得shell还是很强大的，很多高级特性之前都没曾接触过，平时也用得不算很多。浏览了一下abs-guide之后做了一些简单的笔记，方便以后查看，每个&#8221;echo ===&#8221;之间就是代码片段，在bash version 3.2.48下测试过，点解高亮区的&#8221;view source&#8221;可以直接复制所有代码。</p>
<p><span id="more-1169"></span></p>
<pre class="brush:bash">#--------------- Begin
#!/usr/bin/bash

for arg in "Hello World What The Fuck"
do
    echo $arg
done

echo "=================================="

FILES="/usr/bin/accept
/usr/sbin/pwck
/usr/sbin/chroot
/usr/badblocks
/sbin/ypbind"

for file in $FILES
do
    if [ ! -e "$file" ]
    then
        echo "$file does not exist."; echo
        continue
    fi
    ls -l $file | awk '{ print $8 "     file size:  " $5 }'
done

echo "=================================="

for file in *
do
    echo $file
done

echo "=================================="

NUMBERS="1 3 5 7 9 25.3"

for num in `echo $NUMBERS`
do
    echo -n "$num"
done

echo "=================================="

PASSWD_FILE=/etc/passwd
n=1
for name in $(awk 'BEGIN{FS=":"}{print $1}' &lt; "$PASSWD_FILE")
do
    echo "USER #$n = $name"
    let "n += 1"
done

echo "=================================="

echo `seq 10`

echo "=================================="

for ((a=1, b=2; a &lt;= 10; a++, b++))
do
    echo $((a-b))
    echo $[$a-$b]
done

echo "=================================="

ROOT_UID=0
E_NOTROOT=87
E_XCD=86 #can't change directory?

#root check
if [ "$UID" -ne "$ROOT_UID" ]
then
    echo "Must be root to run this script."
    exit $E_NOTROOT
fi
cd /var/log || {
    echo "Cannot change to necessary directory." &gt;&amp;2
    exit $E_XCD;
}

echo "=================================="

let "t2 = ((a = 9, 15 / 3))"

echo "=================================="

# ` -&gt; command substitution
# pdftk is a useful tool for pdf files
`pdftk f1.pdf,f2.pdf cat output combined.pdf`

echo "=================================="

# ${parameter-default}, ${parameter:-default}, return but not set
var1=1
var2=2
#var3 is unset
echo ${var1-$var2}  # 1
echo ${var3-$var2}  # 2
echo "\${var3}=${var3}"      # ${var3}=
# ${parameter=default}, ${parameter:=default}, return and set var default
echo ${var4=$var1}  # 1
echo $var4
echo "\${var4}=${var4}"     # ${var4}=1

echo "=================================="

args=$# # num of args
lastarg=${!args} # or lastarg=${!#}
echo "Last arg is ${lastarg}"
echo "Listing args with \"\$*\":"
for arg in "$*"
do
    echo "Arg #$index = $arg"       # all in one line
    let "index+=1"
done

echo "Listing args with \"\$@\":"
for arg in "$@"
do
    echo "Arg #$index = $arg"       # seperate every arg in new line
    let "index+=1"
done

echo "=================================="

# space should be quoted or escaped
echo {file1,file2}*\ :{\ A," B",' C'}
# file1* : A file1* : B file1* : C file2* : A file2* : B file2* : C

echo "=================================="

echo {a..z}
echo {0..3}

echo "=================================="

# both stdout &amp; stderr
`ls &amp;&gt; a.txt`
# stdout -&gt; stderr
`ls &gt;&amp;2`

echo "=================================="

dt=$(date +%m-%d-%Y)
echo $dt
a=$(ls -l)
echo $a # all in same line
echo "$(ls -l)" # Quoting , don't suppress in one line

echo "=================================="

shift  # shift 3, shift 3 positions
echo $1 # value of $2
echo $2 # nothings echoes, move not copy

echo "=================================="

exit $? # $? reads the exit status of the last command executed

echo "=================================="

if [ 0 ]
then
    echo "0 is true."
else
    echo "0 is false."
fi      # 0 is true.

if [ ]
then
    echo "NULL is true."
else
    echo "NULL is false."
fi      # NULL is false.

echo "=================================="

# page58, if test operators
# if, elif, else
if [ 0 ]
then
    # command
    echo "if statement"
elif [ 1 ]
then
    # command
    echo "elif statement"
else
    # default-command
    echo "else statement"
fi

echo "=================================="

type test
type '['
type '[['

echo "=================================="

# test/[ considers its arguments as comparison expressions or file tests
# and returns an exit status corresponding to the result of the comparison (0 for true, 1 for false)
[ 0 ]
echo $?     # 0/true
[ ]
echo $?     # 1/false

echo "=================================="

# The (( )) construct expands and evaluates an arithmetic expression.
# If the expression evaluates as zero, it returns an exit status of 1, or "false".
# A non-zero expression returns an exit status of 0, or "true".
# This is in marked contrast to using the test and [ ] constructs previously discussed.
((0))
echo $?     # 1/false
(( 5 &gt; 4))
echo $?     # 0/true

echo "=================================="

# A number preceded by a 0 is octal (base 8).
# A number preceded by 0x is hexadecimal (base 16).
# A number with an embedded # evaluates as BASE#NUMBER
a=021 # 8*2+1
b=0x21 # 16*2+1
c=4#21  # 4*2+1

echo "=================================="

# Double-parentheses ((..))  construct is also a mechanism for
# allowing C-style manipulation of variables in Bash, for example, (( var++ )).
(( a = 23 ))
(( a++ ))
(( t = a&lt;45?7:11 ))
let --a

echo "=================================="

ROOTUSER_NAME=root
username=`id -nu`
if [ "$username" = "$ROOTUSER_NAME" ]
then
    echo "Root!"
else
    echo "Not Root!"
fi

echo "=================================="

# $!, PID (process ID) of last job run in background
# Forces completion of an ill-behaved program.
# Useful, for example, in init scripts.
# possibly_hanging_job &amp; { eval 'kill -9 $!' &amp;&gt; /dev/null; }
`wget http://www.facebook.com &amp;`
{ eval 'kill -9 $!' &amp;&gt; /dev/null; echo "kill finished."; }

echo "=================================="

declare -i number=3
declare | grep HOME

echo "=================================="

echo $RANDOM
num=2
echo $((RANDOM % num))

echo "=================================="

# page 115
stringZ=abcABC123ABCabc
echo ${#stringZ}                # 15
echo `expr "$stringZ" : '.*'`

echo "=================================="

var1=unset
previous=$var1
# Four conditions on "while", but only the last one (exit status) controls loop.
while   echo "previous-variable = $previous"
        echo
        previous=$var1
        [ "$var1" != end ]
do
    echo "Input variable #1 (end to exit) "
    read var1
    echo "variable #1 = $var1"
done

echo "=================================="

t=0
condition() {
    ((t++))
    if [ $t -lt 5 ]
    then
        # like exit status
        return 0
    else
        return 1
    fi
}
# condition can be a function
while condition
do
    echo "Still going: t = $t"
done

echo "=================================="

END_CONDITION=end
# loop as long as the condition is false
until [ "$var1" = "$END_CONDITION" ]
do
    echo "Input variable #1 "
    echo "($END_CONDITION to exit)"
    read var1
    echo "variable #1 = $var1"
    echo
done

echo "=================================="

for outer in I II III IV V
do
    echo "$outer "
    for inner in 1 2 3 4 5
    do
        if [ $inner -eq 3 ]
        then
            # break can also optionally take a parameter
            continue 2
        fi
        echo  "$inner "
    done
done # Output : I 1 2 II 1 2 III 1 2 IV 1 2 V 1 2 

echo "=================================="

# case statement
while [ $# -gt 0 ]; do
    case "$1" in
        -d|--debug)
                DEBUG=1
                echo "Debug On."
                ;;
        -c|--conf)
                CONFILE="$2"
                shift
                if [ ! -f $CONFILE]; then
                    echo "Error: Supplied file doesn't exist!"
                    exit $ERROR_OF_FILE_NOT_FOUND
                fi
                ;;
    esac
    shift
done

echo "=================================="

# select statement, "select var [in list]"
# select uses the $PS3 prompt by default
# if [in list] omitted, use cmd line args or func args instead
PS3="Choose your favorite vegetable:"
echo
choice_of() {
    select vegetable
    # [in list] omitted, so 'select' uses arguments passed to function.
    do
        echo
        echo "Your fav veggie is $vegetable."
        echo "Yuck!"
        echo
        break
    done
}
choice_of beans rice carrots radishes tomatoes spinach

echo "=================================="

# cmd substitution, will invoke a subshell
file_listing=`ls -al`
echo $file_listing

file_listing2=$(ls -al)
echo $file_listing2

for arg in `echo a b`; do
    echo $arg
done        # a b in 2 lines

for arg in "`echo a b`"; do
    echo $arg
done        # ab in single line

echo "=================================="

declare -r PI=3.14159265358979
echo $PI
printf "PI is %1.12f\n" $PI
read var1 var2
echo $var1
echo $var2
read
echo "You just input : $REPLY"

echo "=================================="

echo "List of all users:"
OIFS=$IFS;
IFS=:
while read name passwd uid gid fullname ignore
do
    echo "$name ($fullname)"
done &lt; /etc/passwd

echo "=================================="

arr0=( 10 11 12 13 14 15)
arr1=( 20 21 22 23 24 25)
choose_array() {
    eval array_member=\${arr${array_number}[element_number]}
    echo "Element $element_number of arr$array_number is $array_member."
}
array_number=0
element_number=3
choose_array

echo "=================================="

a='$b'
b='$c'
c=d
# each invocation of eval forces a re-evaluation of its arguments
echo $a         # $b
eval echo $a    # $c
eval eval echo $a   # d

echo "=================================="

echo "Positional parameters before set \'uname -a\' :"
echo "Command-line argument #1 = $1"
echo "Command-line argument #2 = $2"
echo "Command-line argument #3 = $3"
# set `Command` can reset the positional parameters that a script
# sees as the result of a command
set `uname -a`
echo "Positional parameters after set \`uname -a\' : "
echo "Field #1 of 'uname -a' = $1"
echo "Field #2 of 'uname -a' = $2"
echo "Field #3 of 'uname -a' = $3"

echo "=================================="

# using set with -- option explicitly assigns the contents of a variable
# to the positional parameters. If no variable follows the --,
# it unsets the positional parameters.
var="one two three four five"
set -- $var
echo $1
echo $2
echo $3

echo "=================================="

usage() {
    echo "Usage:..."
    exit 0
}
flag=false
list=""
set -- $(getopt ahl: "$@")
while [ $# -gt 0 ]
do
    case "$1" in
        -h ) usage;;
        -a ) flag=true;;
        -l ) list="$2"; echo $list; shift;;
        -- ) shift; break;;
        -* ) echo "$0: unrecognized option $1" 1&gt;&amp;2; usage;;
        *  ) break;;
    esac
    shift
done

echo "=================================="

usage() {
    echo "Usage:..."
    exit 0
}
flag=false
list=""
while getopts ":ahl:" Option
do
    case $Option in
        a )
            flag=true;
            echo "Option a : [OPTIND=${OPTIND}]";;
        h )
            echo "Option h : [OPTIND=${OPTIND}]";
            usage;;
        l )
            echo "Option l : [OPTIND=${OPTIND}]";
            list=$OPTARG; echo $list; break;;
        * ) echo "Unrecognized option. $Option";;
    esac
done

echo "$OPTIND"
shift $(($OPTIND -1))
# $1 now references the first non-option item supplied on the command-line
#+ if one exists.
echo $1

echo "=================================="

# same effect as the #include directive in a C program
# var_in_file1=wtf in file1.sh
source file1.sh
echo $var_in_file1

echo "=================================="

# Using the exec builtin, the shell does not fork,
# and the command exec'ed replaces the shell.
exec echo "Exiting \"$0\"."
echo "This echo will never echo."
exit 99

echo "=================================="

# caller is useful in debugging
function2() {
    caller 1
}
function1() {
    function2
    caller 0
}
function1
echo "wtf"
caller 0

echo "=================================="

# true returns a successful(0) exit status
# but does nothing else
# false does the same, but return (1)
true
echo $?     # 0
# endless loop, alias for ":"
while true
do
    echo "wtf"
    sleep 2
    #cmd1
    #cmd2
done

echo "=================================="

# page 204
jobs
disown
bg
fg
wait

echo "=================================="

# external cmd, page 210
`cat`
`tac`
`chattr`
# ...

echo "=================================="

# here documents, simlilar to
# interactive-program &lt; command-file,
# where command-file contains contents
# between "this_is_a_mark_string"
wall &lt;&lt;'this_is_a_mark_string'
Do u know who i am?
this_is_a_mark_string
# - option can supress leading tabs(but not spcaes)
# Quoting or escaping the "limit string" at the head of a here document
# disables parameter substitution within its body
var1=wth
cat &lt;&lt;-MARK_OF_STR
	what the fuck? $var1
MARK_OF_STR

echo "=================================="

# file descriptor
echo 1234567890 &gt; file_name     # write string to "file_name"
exec 3&lt;&gt; file_name              # open "file_name" and assign fd 3 to it
read -n 4 &lt; &amp;3                   # read only 4 chars
# builtin echo do not support -n
printf . &gt;&amp;3                    # write a decimal point there
exec 3&gt;&amp;-                       # close fd 3
cat file_name                   # 1234.67890
# n&lt; &amp;-          close input fd n
# 0&lt;&amp;-, &lt;&amp;-     close stdin
# n&gt;&amp;-          close output fd n
# 1&gt;&amp;-, &gt;&amp;-     close stdout
# child process inhreit open fd, close it if no need

echo "=================================="

# There is no method of 'declaring" the function like C
func1               # error, func1 not defined
declare -f func1    # not help
func1               # still error

echo "=================================="

file=/etc/passwd
pattern=hallo
return_value=""
file_excerpt() {
    echo "Pattern : $1"
    local i=0
    while read line
    do
        echo $line
        ((i++))
        if [ $i -eq 5 ];then
            # custom pre-defined return value
            return_value=(1 2 3)
            # max return value, positive int 255
            return 0
        fi
    done
} &lt; $file

file_excerpt $pattern
echo "Return value is : ${return_value[1]}"

echo "=================================="

# must set this option, else script will not expand aliases
shopt -s expand_aliases
alias llm='ls -al | more'
llm
echo
unalias llm
llm         # error, unalias already

echo "=================================="

# bash permits array operations on variables
# even if the variables are not explicitly declared as arrays.
string=abcd1234
arr_str=("what" "the" "fuck")
echo ${string[*]}           # abcd1234
echo ${arr_str[*]}          # what the fuck
echo ${string[@]}           # abcd1234
echo ${arr_str[@]}          # what the fuck
echo ${#string[@]}          # 1, length
echo ${#arr_str[@]}         # 3

echo "=================================="

# page 416
# many of the standard string operations work on arrays
arrayZ=( one two three four five)
echo ${arrayZ[@]:0}
echo ${arrayZ[@]:1}
echo ${arrayZ[@]:1:3}
echo ${arrayZ[@]/ive/XYZ}
# ...

echo "=================================="

# combine 2 array
arr1=(one two three)
arr2=(four five six)
combined=(${arr1[@]} ${arr2[*]})
echo ${combined[*]}

echo "=================================="

arr1=(
    VAR1=value1
    VAR2=value2
    VAR3=value3
)
arr2=(
    v1="test"
    v2="VAR1=value1 VAR2=value2 VAR3=value3"
    v3=${arr1[*]}
)

test_for_2d_array() {
    t="arr2[*]"
    local ${!t}
    echo "${!t}"        # v1=test v2=VAR1=value1 VAR2=value2 VAR3=value3 v3=VAR1=value1 VAR2=value2 VAR3=value3
    echo "${v1}"        # test
    echo "${v2}"        # VAR1=value1
    echo "${VAR2}"      # value2
    echo "${VAR3}"      # value3
    echo "${v3}"        # VAR1=value1
}

test_for_2d_array

echo "=================================="

# indirect reference
a=b
b=hallo
eval res=\$$a
echo "$res"     # hallo

echo "=================================="

# trap specifies an action on receipt of a signal,
# useful for debugging
trap 'echo "omg"'  EXIT
while true
do
    sleep 2
    echo "hallo"
done

echo "=================================="

# The DEBUG argument to trap causes a specified action to execute
# "after" every command in a script, useful for tracing variables
trap 'echo "TRACE&gt; \$variable = \"$variable\""' DEBUG
variable=29
echo "Just init \$variable to $variable."

echo "=================================="

# trap '' SIGNAL disables SIGNAL for the remainder of the script
# This is useful to protect a critical portion of some uninterruptable actions
trap '' 2       # Signal 2 is Control-C, now disabled
sleep 2
cd
ls
sleep 2
# command...
trap 2          # Reenables Control-C

echo "=================================="

#--------------- End</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2011/10/15/code-snippet-of-shell/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>在Debian搭建SVN</title>
		<link>http://blog.endlesscode.com/2011/10/07/set-up-svn-in-debian/</link>
		<comments>http://blog.endlesscode.com/2011/10/07/set-up-svn-in-debian/#comments</comments>
		<pubDate>Fri, 07 Oct 2011 13:14:49 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=1143</guid>
		<description><![CDATA[今天在Linode买的vps上搭了个svn，简单记录一下过程和遇到的问题。 先说遇到的问题吧，基本上就是 1. &#8220;Could not open the requested SVN filesystem&#8221;; 2. &#8220;Server sent unexpected return value (403 Forbidden) in response to OPTIONS &#8220;. 第一个问题是因为开始没有搞清楚创建一个和多个svn repository的区别，而第二个是因为权限设置的问题。 svn服务器比较重要的涉及安全的问题就是用户认证、访问授权以及传输加密。根据官方的介绍，搭建svn有几种方式，各有优劣，我用的是Apache + mod_dav_svn＋Basic Auth。 具体流程如下，以多个为例，单个的只是参数的差别： 1. 安装所需软件 apt-get install subversion subversion-tools apache2 libapache2-svn 2. 创建存放的路径 &#8230; <a href="http://blog.endlesscode.com/2011/10/07/set-up-svn-in-debian/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>今天在Linode买的vps上搭了个svn，简单记录一下过程和遇到的问题。</p>
<p>先说遇到的问题吧，基本上就是<br />
1. &#8220;Could not open the requested SVN filesystem&#8221;;<br />
2. &#8220;Server sent unexpected return value (403 Forbidden) in response to OPTIONS &#8220;.</p>
<p>第一个问题是因为开始没有搞清楚创建一个和多个svn repository的区别，而第二个是因为权限设置的问题。</p>
<p>svn服务器比较重要的涉及安全的问题就是用户认证、访问授权以及传输加密。根据官方的介绍，搭建svn有几种方式，各有优劣，我用的是Apache + mod_dav_svn＋Basic Auth。 具体流程如下，以多个为例，单个的只是参数的差别：</p>
<h3>1. 安装所需软件</h3>
<pre class="brush:shell">apt-get install subversion subversion-tools apache2 libapache2-svn</pre>
<h3>2. 创建存放的路径</h3>
<pre class="brush:shell">#路径任意
#注意的是这是多个svn repositories的根目录
mkdir -p /home/svn/repos
#设置apache访问的权限, www-data是apache默认的user和group
chown -R www-data.www-data /home/svn/repos</pre>
<p><span id="more-1143"></span></p>
<h3>3. Apache访问权限设置</h3>
<p>可以写在&#8221;/etc/apache2/sites-available/default&#8221;里面，不过我是独立写在另一个文件，然后在&#8221;/etc/apache2/sites-enabled/&#8221;里面加个软链接。</p>
<pre class="brush:plain">NameVirtualHost *:8080
Listen 8080
&lt;VirtualHost *:8080&gt;
    ErrorLog /home/svn/logs/error.log
    CustomLog /home/svn/logs/access.log combined
    &lt;Location /&gt;
        DAV svn
        #SVNParentPath是指定是的多个svn repository的根目录，如果只设定一个，可以用SVNPath来指定；
        #如果想设置多个的但用了SVNPath就会出现第一个问题了
        SVNParentPath /home/svn/repos
        AuthType Basic
        AuthName "Subversion Repository"
        #dav_svn.passwd是设定认证的user和password，等下介绍
        AuthUserFile /etc/apache2/dav_svn.passwd
        Require valid-user
    &lt;/Location&gt;
&lt;/VirtualHost&gt;</pre>
<p>&lt;Location/&gt;节点的内容可以参考&#8221;/etc/apache2/mods-available/dav_svn.conf&#8221;，这里设置了8080端口来访问svn，并且指定了error和access这2个log的位置，设定的时候注意给apache有权限访问就可以了，也可以用chown来设定logs目录的拥有者为www-data.www-data。</p>
<h3>4. 在dav_svn.passwd设定认证的user和password</h3>
<pre class="brush:shell">#首次创建文件的时候用-c，后面添加则用-d，不然-c会把之前的覆盖掉；按提示输入密码即可
htpasswd -c /etc/apache2/dav_svn.passwd endlesscode</pre>
<h3>5. 设置访问目录的权限</h3>
<p>目录的权限配置是在&#8221;/etc/apache2/dav_svn.authz&#8221;这个文件里面，</p>
<pre class="brush:plain">[groups]
admin=stephenchan, otheradmin
user=endlesscode, otheruser

[repository:/]
*=
@admin=rw

[repository:/test]
endlesscode=rw

[repository:/demo]
endlesscode=rw</pre>
<p>因为设置的是多个repositories的，所以在设定访问的目录的时候也是分开设置的。这里我在&#8221;/home/svn/repos&#8221;目录下创建了demo和test这2个svn repository，分别设置了rw权限。&#8221;*=&#8221;这个是将所有的用户权限清空，&#8221;*&#8221;代表所有用户。</p>
<p>要注意的是，如果只设定单个的repository，应该直接使用&#8221;[/path/to/dir]&#8220;而不是用&#8221;[repository:/project/path/to/dir]&#8220;这种方式，否则会无效，并可能出现开始说的第二个问题。</p>
<h3>6. 创建svn repository</h3>
<p>写个脚本来创建就比较方便了</p>
<pre class="brush:shell">#!/bin/bash
# create_svn.sh
echo "create svn repos : "$1
mkdir $1
svnadmin create $1
chown -R www-data:www-data $1</pre>
<h3>7. 测试</h3>
<p>初次创建的revision是0的，可以&#8221;svn co http://hostname:8080/demo&#8221;来checkout下来，然后修改一下，再commit上去就变成1了。</p>
<p>虽然基本搭起来，但是传输加密这个还没有弄，还有post-commit，email这些都没有设置，找个时间再弄吧。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2011/10/07/set-up-svn-in-debian/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>VirtualBox拷贝vdi丢失eth0</title>
		<link>http://blog.endlesscode.com/2010/11/19/lost-eth0-in-copied-vdi/</link>
		<comments>http://blog.endlesscode.com/2010/11/19/lost-eth0-in-copied-vdi/#comments</comments>
		<pubDate>Thu, 18 Nov 2010 17:21:52 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[Unix/Linux]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=1111</guid>
		<description><![CDATA[今天用VirtualBox的工具去拷贝虚拟机vdi文件的时候，在拷贝出来的vdi文件中找不到eth0。 # debian lenny VBoxManage clonevdi old.vdi new.vdi 拷贝成功，但当打开new.vdi的时候就出现eth0找不到了。原来是使用VBoxManage的时候不但会为新的vdi文件产出新的UUID，还会为其分配一个新的mac地址，以避免冲突，这样在debian中就会把新的mac地址设置为eth1，结果就杯具了。 解决方法有2个，其实差不多： 在new.vdi中，修改/etc/udev/rules.d/70-persistent-net.rules，一般会有eth0和eth1两行，把eth0那行去掉，然后将eth1改成eth0。 把/etc/udev/rules.d/70-persistent-net.rules中的内容直接删除，然后重启，让系统自动去检测网卡，然后重新生成该文件。其实在copy之前就可以删掉了，这样所有copy出来的都不用修改了，让系统自己去检测。 /etc/udev/rules.d/70-persistent-net.rules这个文件是在网卡有变动的时候才会变化的，里面记录着网卡的信息，虽然VBoxManage会为new.vdi创建新的网卡，但是debian的行为是把这个网卡作为新增的网卡记录在/etc/udev/rules.d/70-persistent-net.rules中，而没有进行调整，所以使用的还是有冲突的eth0。]]></description>
			<content:encoded><![CDATA[<p>今天用VirtualBox的工具去拷贝虚拟机vdi文件的时候，在拷贝出来的vdi文件中找不到eth0。</p>
<pre class="brush:bash"># debian lenny
VBoxManage clonevdi old.vdi new.vdi</pre>
<p>拷贝成功，但当打开new.vdi的时候就出现eth0找不到了。原来是使用VBoxManage的时候不但会为新的vdi文件产出新的UUID，还会为其分配一个新的mac地址，以避免冲突，这样在debian中就会把新的mac地址设置为eth1，结果就杯具了。</p>
<p>解决方法有2个，其实差不多：</p>
<ul>
<li>在new.vdi中，修改<strong>/etc/udev/rules.d/70-persistent-net.rules</strong>，一般会有eth0和eth1两行，把eth0那行去掉，然后将eth1改成eth0。</li>
<li>把<strong>/etc/udev/rules.d/70-persistent-net.rules</strong>中的内容直接删除，然后重启，让系统自动去检测网卡，然后重新生成该文件。其实在copy之前就可以删掉了，这样所有copy出来的都不用修改了，让系统自己去检测。</li>
</ul>
<p><strong>/etc/udev/rules.d/70-persistent-net.rules</strong>这个文件是在网卡有变动的时候才会变化的，里面记录着网卡的信息，虽然VBoxManage会为new.vdi创建新的网卡，但是debian的行为是把这个网卡作为新增的网卡记录在<strong>/etc/udev/rules.d/70-persistent-net.rules</strong>中，而没有进行调整，所以使用的还是有冲突的eth0。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/11/19/lost-eth0-in-copied-vdi/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>最近也Objective-C了</title>
		<link>http://blog.endlesscode.com/2010/11/08/objective-c-recently/</link>
		<comments>http://blog.endlesscode.com/2010/11/08/objective-c-recently/#comments</comments>
		<pubDate>Sun, 07 Nov 2010 18:28:01 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[Mac/iOS]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=1072</guid>
		<description><![CDATA[还是换回原来的主题了，Apple风格的那个主题在显示上还是有不少问题。Objective-C接触了2个多星期，写一下上手体验。 内存管理初体验 最近看了看objective-c，主要是要理解好objective-c的内存管理机制，其他的和c/c++差别就不大了。虽然objective-c 2.0提供了gc，但是要写出高效的程序当然要靠自己去管理好内存，特别是在移动设备上。在接触内存管理的时候google了几篇文章，都说得不清楚，后来看了看官方的文档，才在使用上有了比较清晰的理解。其实归根结底是理解下面这2种初始化的区别：（以NSString为例） NSString *string1 = [[NSString alloc] initWithString:@"Hello World!"]; NSString *string2 = [NSString stringWithString:@"Hello World!"]; string1是需要自己调用release（和创建在同一作用域释放）或者autorelease（string1作为函数返回值的时候），因为用alloc创建的对象是说明一种拥有关系（own，即retain count相应为加1，copy/retain也是），而string2则不是拥有关系，则自己不用调用release。因此，@property中的三个属性，assign/retain/copy也就更好理解了。 assign是弱引用，retain count不变化； retain就是强引用，声明拥有关系，retain count加1； copy就是拷贝新的对象并引用到拷贝上。 而内存池（autoreleasepool），我总觉得是为了string2这种创建对象的方法和string1作为返回值的场合而存在的。 因为对于string2这样的创建对象方法，其实也就是在initWithString之后再调用一次autorelease而已； 而在string1作为返回值的场合，不能release了再返回也不能返回了再release，所以需要托管给内存池来管理。 而在Cocoa在每一个事件循环的生命周期都保证会有一个内存池创建和销毁，这样对象的管理机制就完美了。 Objective-C不难用 因为使用python习惯了，一下写回c，就像回到了原始社会一样。用了几天才发现，其实Objective-C在Foundation框架上提供了很多相当方便的类以及类的方法，足以让我找回写python的那种方便性。比如简单地从网上抓取一个文本文件存为字符串： NSURL *url = [[NSURL alloc] initWithString:addr]; NSString *content = [NSString &#8230; <a href="http://blog.endlesscode.com/2010/11/08/objective-c-recently/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>还是换回原来的主题了，Apple风格的那个主题在显示上还是有不少问题。Objective-C接触了2个多星期，写一下上手体验。</p>
<h3>内存管理初体验</h3>
<p>最近看了看objective-c，主要是要理解好objective-c的内存管理机制，其他的和c/c++差别就不大了。虽然objective-c 2.0提供了gc，但是要写出高效的程序当然要靠自己去管理好内存，特别是在移动设备上。在接触内存管理的时候google了几篇文章，都说得不清楚，后来看了看官方的文档，才在使用上有了比较清晰的理解。其实归根结底是理解下面这2种初始化的区别：（以NSString为例）</p>
<pre class="brush:c++">NSString *string1 = [[NSString alloc] initWithString:@"Hello World!"];
NSString *string2 = [NSString stringWithString:@"Hello World!"];</pre>
<p>string1是需要自己调用release（和创建在同一作用域释放）或者autorelease（string1作为函数返回值的时候），因为用alloc创建的对象是说明一种拥有关系（own，即retain count相应为加1，copy/retain也是），而string2则不是拥有关系，则自己不用调用release。因此，@property中的三个属性，assign/retain/copy也就更好理解了。</p>
<ul>
<li>assign是弱引用，retain count不变化；</li>
<li>retain就是强引用，声明拥有关系，retain count加1；</li>
<li>copy就是拷贝新的对象并引用到拷贝上。</li>
</ul>
<p><span id="more-1072"></span>而内存池（autoreleasepool），我总觉得是为了string2这种创建对象的方法和string1作为返回值的场合而存在的。</p>
<ul>
<li>因为对于string2这样的创建对象方法，其实也就是在initWithString之后再调用一次autorelease而已；</li>
<li>而在string1作为返回值的场合，不能release了再返回也不能返回了再release，所以需要托管给内存池来管理。</li>
</ul>
<p>而在Cocoa在每一个事件循环的生命周期都保证会有一个内存池创建和销毁，这样对象的管理机制就完美了。</p>
<h3>Objective-C不难用</h3>
<p>因为使用python习惯了，一下写回c，就像回到了原始社会一样。用了几天才发现，其实Objective-C在Foundation框架上提供了很多相当方便的类以及类的方法，足以让我找回写python的那种方便性。比如简单地从网上抓取一个文本文件存为字符串：</p>
<pre class="brush:c++">        NSURL *url = [[NSURL alloc] initWithString:addr];
        NSString *content = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:NULL];
        [url release];</pre>
<p>很简单，世上不是缺少美，而是缺少发现美的眼光。当然，想折腾或者获取更具体的连接信息也可以使用NSURLRequest和NSURLConnection。</p>
<h3>Vim还是Xcode？</h3>
<p>用了快2个星期Xcode，我已经很不习惯这样有GUI的IDE了，于是用回了Vi来写，目前只是写了几个简单的Mac OS的程序，因此用Vi写返而更顺手，在生成的时候使用xcodebuild命令：</p>
<pre class="brush:bash">xcodebuild -configuration Debug ＃默认是Release的</pre>
<p>由于调试是使用NSLog这种打log的方式，所以还没有使用gdb。不过这样输出的错误信息也是很详细的，并不比Xcode来得麻烦。目前发现有个不方便的地方就是添加文件，是需要在Xcode上添加的，似乎要在工程的信息文件里增加新文件的信息，不然build的时候会出现新文件没被加进项目的错误。</p>
<p>Mac的开发资料实在是少，国内的网上书店都没有怎么引进，倒是iPhone的开发资料多。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/11/08/objective-c-recently/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>第三季度</title>
		<link>http://blog.endlesscode.com/2010/10/08/3rd-quarter/</link>
		<comments>http://blog.endlesscode.com/2010/10/08/3rd-quarter/#comments</comments>
		<pubDate>Fri, 08 Oct 2010 12:47:57 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[My Life]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=1061</guid>
		<description><![CDATA[好几个月都没有写技术总结了，这几个月状态都不那么好，各种烦心事和身体不适，无法专注地去做好一件事情。代码也写得甚少，比不上在大学的时候写得那么频繁。这几个月懒惯了思维也有点僵硬了。有些计划也不得不推迟了，相当惭愧。 小病了几次也让我不能再像以前随意地透支那么多时间了。从大学开始，都习惯了晚睡，哪怕是工作了，也是一直捣鼓到深夜3点多才去休息，是习惯了深夜的那种清静的环境，可以让人专注地看书做总结写代码，经过了这么长时间的一段狂躁的生活，人可能也累了。 这几个月把时间耗得最多的是在游戏上，去美服玩了一个多月，也去台服玩了一个多月，对别人而言是一种娱乐，但对自己而言当然是浪费时间。毕竟烦躁的时候总需要找些东西来消磨时间。体验了一下国外的游戏气氛，用“仓廪实则知礼节”来形容3地的差异是最贴切不过了。 这段时间也在想如何去规划自己的时间，毕竟也不能一直这样狂躁的生活习惯。 去香港买了个Mac Pro，可以用简约来形容我用Mac的体验，当然也不缺乏一些炫的用户体验，只是个人不太喜欢，一般都关掉。从Ubuntu过渡到Mac还是没有什么困难。 之前麻烦主管帮我配置了几个ssh accounts，想捣鼓一下hadoop，但现在还没有什么进展，深感惭愧。 博客换了一个Mac风格的主题，把顺带的顶部banner图片和侧栏的部分widgets去掉了，简洁很多，文字有shadow的效果，不过还可以接受。 第四季度也来了，千里之行，始于足下。 今天刘晓波也获得了诺贝尔和平奖，为中国人争口气了啊。]]></description>
			<content:encoded><![CDATA[<p>好几个月都没有写技术总结了，这几个月状态都不那么好，各种烦心事和身体不适，无法专注地去做好一件事情。代码也写得甚少，比不上在大学的时候写得那么频繁。这几个月懒惯了思维也有点僵硬了。有些计划也不得不推迟了，相当惭愧。</p>
<p>小病了几次也让我不能再像以前随意地透支那么多时间了。从大学开始，都习惯了晚睡，哪怕是工作了，也是一直捣鼓到深夜3点多才去休息，是习惯了深夜的那种清静的环境，可以让人专注地看书做总结写代码，经过了这么长时间的一段狂躁的生活，人可能也累了。</p>
<p>这几个月把时间耗得最多的是在游戏上，去美服玩了一个多月，也去台服玩了一个多月，对别人而言是一种娱乐，但对自己而言当然是浪费时间。毕竟烦躁的时候总需要找些东西来消磨时间。体验了一下国外的游戏气氛，用“仓廪实则知礼节”来形容3地的差异是最贴切不过了。</p>
<p>这段时间也在想如何去规划自己的时间，毕竟也不能一直这样狂躁的生活习惯。</p>
<p>去香港买了个Mac Pro，可以用简约来形容我用Mac的体验，当然也不缺乏一些炫的用户体验，只是个人不太喜欢，一般都关掉。从Ubuntu过渡到Mac还是没有什么困难。</p>
<p>之前麻烦主管帮我配置了几个ssh accounts，想捣鼓一下hadoop，但现在还没有什么进展，深感惭愧。</p>
<p>博客换了一个Mac风格的主题，把顺带的顶部banner图片和侧栏的部分widgets去掉了，简洁很多，文字有shadow的效果，不过还可以接受。</p>
<p>第四季度也来了，千里之行，始于足下。</p>
<p>今天刘晓波也获得了诺贝尔和平奖，为中国人争口气了啊。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/10/08/3rd-quarter/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>读过《观止》</title>
		<link>http://blog.endlesscode.com/2010/08/11/reading-showstopper/</link>
		<comments>http://blog.endlesscode.com/2010/08/11/reading-showstopper/#comments</comments>
		<pubDate>Tue, 10 Aug 2010 17:19:30 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[Reading]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=1047</guid>
		<description><![CDATA[今晚总算把《观止》看完了，看得比较快，基本上是当叙事小说一样看。这个书名看起来像文艺书，但实际上是讲述Windows NT这个操作系统的创造史。为什么Windows NT这么出色，因为在当时它的诞生改变了人们对操作系统的看法，它引入了现在我们看起来很理所当然但当时还没有的技术：抢占式的多任务处理、可安装在通用的硬件平台、支持32位内存寻址、支持大容量文件并具有容错功能的NTFS（NT File System）等等。当然这些系统功能并没有在书上描述，这本书从头到尾都是在讲述整个NT团队是如此在艰苦的进度压力和技术压力之下花了将近5年时间创造出NT。 这个NT团队的领导人就是Dave Cutler，性格独断脾气火爆，技术牛B，现在来说就是一个传奇的程序员，当他领导NT团队的时候已经是个快50岁的人了。有个小插曲或者会更令人记住他是谁，就是当他招聘小秘的时候会问一个问题“How do u think about the word &#8216;fuck&#8217;?&#8221;，只有那个回答了&#8221;Its my favorite word”的MM才拿到了offer。 从1988年10月开始到正式发布的1993年7月23日，历时接近5年时间，团队从开始的20多人到最后的200多人，在这5年时间里面NT团队面对的是各种功能需求的增加、遥遥无期的进度、不断冒出的bug，还有其他非技术问题，如家庭和爱人，可以说是可歌可泣，NT团队的每个成员为Windows NT奉献太多了。 虽然看得比较快，但是一些体会还是想记录一下，以后有时间再翻出来看或者也会有不同的体会。 从本来只有一个内核开发的团队，到后面慢慢增加了图形开发小组和网络开发小组，整个团队大部分人都是物理和数学出身，毕竟从理科出身的容易投入到计算机行业，加上当时计算机行业还远没现在这么热门。由于当时NT的目标定得比较高，因此很多迎合市场的需求都被添加到功能列表中，并要求兼容以前的DOS和Windows程序，不停地添加功能需求以及保证兼容性基本上就直接导致了进度问题，由于领导的Dave Cutler是个基本上为了NT放弃了家庭的人，因此给NT的团队带来的直接影响就是在进度压力之下的疯狂加班，纵然如此，但是在微软的给予的高股票期权和Cutler的压迫之下，团队的成员也是能积极高效地工作，其实这里，我还觉得有个原因是在这种环境之下驱动大家去工作的，就是大家都希望能够创造出一个出色的产品，虽然工作辛苦，但是这种渴望创造的欲望也是驱动团队成员努力工作的一个原因。 程序员、测试员和构建员是组成NT团队的主要3个角色，在那个年代，测试员和构建员的地位并不高，但是慢慢程序不断地被挑出bug并不断地被完善，越显得测试员和构建员的重要性。相比于目前自己所做的项目，哪怕是相差20年，目前我们项目的流程还是比不上那时的NT团队。每个程序员的commit都是基于不会导致构建失败的前提下，当然构建的时机可能是即时也可能是固定某个时候，但是每个程序员的commit都是使构建能正常进行的，整个流程都是井然有序地进行。而且，更让我欣赏NT团队的是，在项目的后期，Dave Cutler甚至是长期定居在构建实验室，来专门看每个程序员提交的各种代码，来保证程序代码的质量，那么多不知道他怎么看得过来。对于程序员犯的错误，Dave Cutler可是不留情面地批评，或者正是这种领导的压迫之下反而提高了团队成员的代码严谨，或者可以说是领导威严的作用。 团队规模变大，可能就增加了成员之间对技术问题的冲突，但是正如书上说，这种冲突有时候会激发对程序代码的改进，其实倒觉得这种冲突是来源于对自己代码逻辑的自信，或者说是个性鲜明，和提倡中庸之道的国内还是有点区别。 到了项目后期，真的可以算得上夺命狂奔，因为有了deadline，所以对bug的分类控制、暂停新功能需求的加入、不停的压力测试、客户的bug反馈和beta版的多次发布等等，各个成员都日以继夜地修正各种showstopper和一等级的bug。 最后Windows NT发布了，微软就站在了操作系统的顶峰了。而从始自终，Gates都没有对NT团队有什么干预，只是定期了解开发进度和进行产品的测试，给了NT团队很大的自由度。 《观止》这本书虽然只是描述了整个NT的创造史，其实更像一本项目管理的书。]]></description>
			<content:encoded><![CDATA[<p>今晚总算把《观止》看完了，看得比较快，基本上是当叙事小说一样看。这个书名看起来像文艺书，但实际上是讲述Windows NT这个操作系统的创造史。为什么Windows NT这么出色，因为在当时它的诞生改变了人们对操作系统的看法，它引入了现在我们看起来很理所当然但当时还没有的技术：抢占式的多任务处理、可安装在通用的硬件平台、支持32位内存寻址、支持大容量文件并具有容错功能的NTFS（NT File System）等等。当然这些系统功能并没有在书上描述，这本书从头到尾都是在讲述整个NT团队是如此在艰苦的进度压力和技术压力之下花了将近5年时间创造出NT。</p>
<p>这个NT团队的领导人就是Dave Cutler，性格独断脾气火爆，技术牛B，现在来说就是一个传奇的程序员，当他领导NT团队的时候已经是个快50岁的人了。有个小插曲或者会更令人记住他是谁，就是当他招聘小秘的时候会问一个问题“How do u think about the word &#8216;fuck&#8217;?&#8221;，只有那个回答了&#8221;Its my favorite word”的MM才拿到了offer。</p>
<p>从1988年10月开始到正式发布的1993年7月23日，历时接近5年时间，团队从开始的20多人到最后的200多人，在这5年时间里面NT团队面对的是各种功能需求的增加、遥遥无期的进度、不断冒出的bug，还有其他非技术问题，如家庭和爱人，可以说是可歌可泣，NT团队的每个成员为Windows NT奉献太多了。<span id="more-1047"></span></p>
<p>虽然看得比较快，但是一些体会还是想记录一下，以后有时间再翻出来看或者也会有不同的体会。</p>
<p>从本来只有一个内核开发的团队，到后面慢慢增加了图形开发小组和网络开发小组，整个团队大部分人都是物理和数学出身，毕竟从理科出身的容易投入到计算机行业，加上当时计算机行业还远没现在这么热门。由于当时NT的目标定得比较高，因此很多迎合市场的需求都被添加到功能列表中，并要求兼容以前的DOS和Windows程序，不停地添加功能需求以及保证兼容性基本上就直接导致了进度问题，由于领导的Dave Cutler是个基本上为了NT放弃了家庭的人，因此给NT的团队带来的直接影响就是在进度压力之下的疯狂加班，纵然如此，但是在微软的给予的高股票期权和Cutler的压迫之下，团队的成员也是能积极高效地工作，其实这里，我还觉得有个原因是在这种环境之下驱动大家去工作的，就是大家都希望能够创造出一个出色的产品，虽然工作辛苦，但是这种渴望创造的欲望也是驱动团队成员努力工作的一个原因。</p>
<p>程序员、测试员和构建员是组成NT团队的主要3个角色，在那个年代，测试员和构建员的地位并不高，但是慢慢程序不断地被挑出bug并不断地被完善，越显得测试员和构建员的重要性。相比于目前自己所做的项目，哪怕是相差20年，目前我们项目的流程还是比不上那时的NT团队。每个程序员的commit都是基于不会导致构建失败的前提下，当然构建的时机可能是即时也可能是固定某个时候，但是每个程序员的commit都是使构建能正常进行的，整个流程都是井然有序地进行。而且，更让我欣赏NT团队的是，在项目的后期，Dave Cutler甚至是长期定居在构建实验室，来专门看每个程序员提交的各种代码，来保证程序代码的质量，那么多不知道他怎么看得过来。对于程序员犯的错误，Dave Cutler可是不留情面地批评，或者正是这种领导的压迫之下反而提高了团队成员的代码严谨，或者可以说是领导威严的作用。</p>
<p>团队规模变大，可能就增加了成员之间对技术问题的冲突，但是正如书上说，这种冲突有时候会激发对程序代码的改进，其实倒觉得这种冲突是来源于对自己代码逻辑的自信，或者说是个性鲜明，和提倡中庸之道的国内还是有点区别。</p>
<p>到了项目后期，真的可以算得上夺命狂奔，因为有了deadline，所以对bug的分类控制、暂停新功能需求的加入、不停的压力测试、客户的bug反馈和beta版的多次发布等等，各个成员都日以继夜地修正各种showstopper和一等级的bug。</p>
<p>最后Windows NT发布了，微软就站在了操作系统的顶峰了。而从始自终，Gates都没有对NT团队有什么干预，只是定期了解开发进度和进行产品的测试，给了NT团队很大的自由度。</p>
<p>《观止》这本书虽然只是描述了整个NT的创造史，其实更像一本项目管理的书。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/08/11/reading-showstopper/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>香港游记</title>
		<link>http://blog.endlesscode.com/2010/08/10/journey-to-hk/</link>
		<comments>http://blog.endlesscode.com/2010/08/10/journey-to-hk/#comments</comments>
		<pubDate>Mon, 09 Aug 2010 16:15:47 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[My Life]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=1033</guid>
		<description><![CDATA[上周5去香港玩了3天，本来是想昨晚就写一下的，但是10点多回到来和同学吃了个宵夜就晚了。 周5早上7点半就醒了，然后去匆匆地坐地铁去火车站，坐传说中的河蟹号到罗湖，其实这还是挺快的，河蟹号一个小时就从广州到罗湖了，不过第一次过境，还是花了点时间，到香港之后，再从地铁和公交到西环，这里也花了1.5个小时了，不过香港的公交比广州的舒服多了，没有广州挤得那么厉害，而且，小公巴如果满人了司机是不会让人再上来的。 Day 1： 第一天到阿清那已经1点多了，两个人就去附近吃了个性价比还算可以的餐厅吃了个扒，然后接下来就去港大了。港大的正门没有像一些大学那些有气势，相对来说还是比较小的，而且港大也是建在半山腰的，从西环那里上去都是坐电梯上去的。参观了一下港大，中山像、莲花池、月明池，不过有个雕塑还是纪念敏感词事件的，叫国殇之柱。就是下面这个，照得不太好，要侧着脖子看。 接着下午就去了黄大仙，我和阿清都求了个事业签，那个解签的说我的是中下签，最近2个月事业不顺，要跳槽就趁早，我听得都蒙了。然后她说阿清下下签，阿清一听，皱了皱眉头，“哼？”的一声，那个解签的又说阿清会有贵人相助，不用太担心，这个有点搞笑，后来还叫我们去求个护符，看来这个中下/下下-&#62; 护符是个固定的模式。 之后我们就去了一趟铜锣湾，商业街那是非常地热闹，不过我们也只是去买了几件衣服基本没有买什么了，毕竟逛商业街的确不应该是2个男的应该做的事情。 晚上就去了金紫荆广场，那里游客也不少，其实金紫荆广场也没有什么大的看点，就只有一个金色的紫荆花雕像。接下来就坐游轮去星光大道那边，星光大道那里都是一些明星的手印，一些较为出名的就比较多人围观，比如刘德华、成龙等等，我也照了几个，下面这张是刘德华的，嘻嘻。基本上去了星光大道就回去了，本来还想去兰桂坊的，但逛了大半天太累了。 Day 2： 因为第一天玩得太累了，因此第二天睡到很晚才起来，所以上午也就没有去什么地方玩，由于同学下午要去上课，我也背着个书包又做了一回学生。上的这门课是Network Security，professor是全程用英语讲课，不过港式英语口音太怪了。讲到Security Model的时候提到一个牛B的模型“Chinese Wall”，“Prevent information flow that will result in conflict of interest”，这个GFW都已经算是一个安全模型了。 晚上本来还想去一趟兰桂坊的，但是由于下大雨，两个人只能回去看电影玩星际了。这一天基本上没有怎么出去外面玩。 Day 3： 今天也是睡到很晚才起来，所以行程都是从下午开始。因为晚上要回广州，所以下午能计划的比较少，就去坐了一下山顶缆车，不过由于是周日，人那是相当地多。去到了山顶，俯视全香港，那景色是相当地让人看起来舒服： 晚上去大快活把晚餐消灭了，不过刚好赶上下午茶时间，所以价格还是相当地便宜，两个人70HK$已经吃得非常赞了，米线、蜜汁鸡比、西多士还有红豆冰，消费没有原来想象中那么高。 结束 总的来说，玩得还算不错，因为是借宿在同学家，因此也省了一笔，而且这3天阿清都是带我去一些性价比相当高的地方吃饭，光是吃扒都吃了2天，囧，港大饭堂的、华人餐厅、中环的餐厅，吃扒吃到牙都累了，不过凡是能点西多士的地方我都会点这个。衣服以我们这边的消费水平来讲是比较贵，但以香港那边的消费水平来看其实也是一般般。没有去海洋公园和迪士尼，两个男的去这两个景点还真是没有意思。]]></description>
			<content:encoded><![CDATA[<p>上周5去香港玩了3天，本来是想昨晚就写一下的，但是10点多回到来和同学吃了个宵夜就晚了。</p>
<p>周5早上7点半就醒了，然后去匆匆地坐地铁去火车站，坐传说中的河蟹号到罗湖，其实这还是挺快的，河蟹号一个小时就从广州到罗湖了，不过第一次过境，还是花了点时间，到香港之后，再从地铁和公交到西环，这里也花了1.5个小时了，不过香港的公交比广州的舒服多了，没有广州挤得那么厉害，而且，小公巴如果满人了司机是不会让人再上来的。</p>
<h2>Day 1：</h2>
<p>第一天到阿清那已经1点多了，两个人就去附近吃了个性价比还算可以的餐厅吃了个扒，然后接下来就去港大了。港大的正门没有像一些大学那些有气势，相对来说还是比较小的，而且港大也是建在半山腰的，从西环那里上去都是坐电梯上去的。参观了一下港大，中山像、莲花池、月明池，不过有个雕塑还是纪念敏感词事件的，叫国殇之柱。就是下面这个，照得不太好，要侧着脖子看。<img class="aligncenter size-medium wp-image-1034" title="IMG_2631" src="http://blog.endlesscode.com/wp-content/uploads/2010/08/IMG_2631-300x200.jpg" alt="IMG_2631" width="300" height="200" /></p>
<p><span id="more-1033"></span>接着下午就去了黄大仙，我和阿清都求了个事业签，那个解签的说我的是中下签，最近2个月事业不顺，要跳槽就趁早，我听得都蒙了。然后她说阿清下下签，阿清一听，皱了皱眉头，“哼？”的一声，那个解签的又说阿清会有贵人相助，不用太担心，这个有点搞笑，后来还叫我们去求个护符，看来这个中下/下下-&gt; 护符是个固定的模式。</p>
<p>之后我们就去了一趟铜锣湾，商业街那是非常地热闹，不过我们也只是去买了几件衣服基本没有买什么了，毕竟逛商业街的确不应该是2个男的应该做的事情。</p>
<p>晚上就去了金紫荆广场，那里游客也不少，其实金紫荆广场也没有什么大的看点，就只有一个金色的紫荆花雕像。接下来就坐游轮去星光大道那边，星光大道那里都是一些明星的手印，一些较为出名的就比较多人围观，比如刘德华、成龙等等，我也照了几个，下面这张是刘德华的，嘻嘻。<img class="aligncenter size-medium wp-image-1038" title="IMG_2667" src="http://blog.endlesscode.com/wp-content/uploads/2010/08/IMG_2667-300x200.jpg" alt="IMG_2667" width="300" height="200" />基本上去了星光大道就回去了，本来还想去兰桂坊的，但逛了大半天太累了。</p>
<h2>Day 2：</h2>
<p>因为第一天玩得太累了，因此第二天睡到很晚才起来，所以上午也就没有去什么地方玩，由于同学下午要去上课，我也背着个书包又做了一回学生。上的这门课是Network Security，professor是全程用英语讲课，不过港式英语口音太怪了。讲到Security Model的时候提到一个牛B的模型“Chinese Wall”，“Prevent information flow that will result in conflict of interest”，这个GFW都已经算是一个安全模型了。</p>
<p>晚上本来还想去一趟兰桂坊的，但是由于下大雨，两个人只能回去看电影玩星际了。这一天基本上没有怎么出去外面玩。</p>
<h2>Day 3：</h2>
<p>今天也是睡到很晚才起来，所以行程都是从下午开始。因为晚上要回广州，所以下午能计划的比较少，就去坐了一下山顶缆车，不过由于是周日，人那是相当地多。<img class="aligncenter size-medium wp-image-1039" title="IMG_2675" src="http://blog.endlesscode.com/wp-content/uploads/2010/08/IMG_2675-300x200.jpg" alt="IMG_2675" width="300" height="200" />去到了山顶，俯视全香港，那景色是相当地让人看起来舒服：</p>
<p><img class="aligncenter size-large wp-image-1040" title="IMG_2680" src="http://blog.endlesscode.com/wp-content/uploads/2010/08/IMG_2680-1024x682.jpg" alt="IMG_2680" width="1024" height="682" />晚上去大快活把晚餐消灭了，不过刚好赶上下午茶时间，所以价格还是相当地便宜，两个人70HK$已经吃得非常赞了，米线、蜜汁鸡比、西多士还有红豆冰，消费没有原来想象中那么高。</p>
<p><img class="aligncenter size-medium wp-image-1042" title="IMG_2683" src="http://blog.endlesscode.com/wp-content/uploads/2010/08/IMG_2683-300x200.jpg" alt="IMG_2683" width="300" height="200" /></p>
<h2>结束</h2>
<p>总的来说，玩得还算不错，因为是借宿在同学家，因此也省了一笔，而且这3天阿清都是带我去一些性价比相当高的地方吃饭，光是吃扒都吃了2天，囧，港大饭堂的、华人餐厅、中环的餐厅，吃扒吃到牙都累了，不过凡是能点西多士的地方我都会点这个。衣服以我们这边的消费水平来讲是比较贵，但以香港那边的消费水平来看其实也是一般般。没有去海洋公园和迪士尼，两个男的去这两个景点还真是没有意思。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/08/10/journey-to-hk/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>写在毕业一年后</title>
		<link>http://blog.endlesscode.com/2010/07/01/one-year-after-graduation/</link>
		<comments>http://blog.endlesscode.com/2010/07/01/one-year-after-graduation/#comments</comments>
		<pubDate>Wed, 30 Jun 2010 16:14:00 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[My Life]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=1009</guid>
		<description><![CDATA[不经不觉毕业也一年了，走得太匆忙，并没有和大家留下什么伤感的回忆。 从入职到现在，除了觉得时间过得很快之外，就是觉得自己没有把握好时间，或者毕业后各方面的原因学习动力和激情也比不上在学校的时候。 回头看看这一年…… 09年的下半年，大部分时间是投入在研究fopen这个Facebook开源SNS，由于这是搭建在Linux平台并用php和c++写的，Linux和php这两方面对我来说都不太熟悉，折腾了好长的一段时间。fopen并没有原本所期待那样能够真正地投入到正式的产品使用，更多的，它只是Facebook的一个超级简化版，而且文档也相当地不完整，整个fopen依赖的库文件也很多，我当时也没能弄明白这些库文件是做什么的。在改写JavaScript的部分，虽然代码逻辑是比较清晰，但是像它那样的逻辑重写1000的JavaScript代码都要10多秒，不知道它在正式投入使用的时候是怎么提升解析速度的，又或者是正式产品中是使用了C++重写或者利用其他的一些缓存技术。在OpenAPI部分，那时候还弄不明白那个timestamp和callback的参数作用，后来才明白timestamp是用于防止replay attack，而callback是为了使用jsonp的，只怪当时知识面太窄了。虽然最后也用python实现了类似的JavaScript Parser和OpenAPI以及JavaScript client lib，但实际上需要完善的空间实在太多，只是时间无法安排过来。、 09年11月份开始的时候封闭开发了好长一段时间，封闭开发最大的体会就是环境很安静，但人能够很集中精神地开发，效率的确高很多。其实这段时间最大的收获是在美林的时候认识了老邓，他是云风带领的那个工作室的成员，他把我带进了函数式编程的世界，跟我讲了很多除了c++、java、.net之外的其他语言情况，比如lisp、squeak、haskell、erlang等等，还跟我讲了计算机世界里面一些有意思的事情和人物，并介绍了好几本书给我。作为刚毕业的新人，老员工知识和经验的分享正是新人所需要的。 从新年放假回来后，前2个月是主要是完成一些比较琐碎的东西，开发一些平台上的小功能和修复一些bug。后2个月主要是开发一些营销活动，进度非常赶，这些活动项目时效比较短，我只是加班把这些活动项目做出来，但是我没有时间把这些项目做得好，我自己是个追求完美的人，作品写得这么挫却又无可奈何心里面是何等的不爽。我觉得公司的营销同事制定营销推广计划的时候应该和开发人员先协商进度安排以及项目上线的各方面可行性，而不是把计划定好了，然后有什么进度压力就直接推给开发人员。 Python写了一年多，但是我觉得在同一届入职的同事里面，掌握得最差的应该是我了。在Python花的时间的确是太少了，我仍然需要阅读更多关于Python方面的资料和写更多的代码，pythonic是我的目标。JavaScript方面在实际上项目倒是提高了不少，对闭包和作用域链的理解，一些IE的hack，页面脚本的加载顺序等等，Firebug的脚本调试作用也相当的强大和方便。总的来说，各方面都有一定的提高，不过前端的css的样式设置我依然觉得很痛苦。虽然平时都是在Linux环境下开发，但是我对Linux的理解还是相当地肤浅，Shell编程和Linux C的提高是我的下一个目标，Linux下的很多命令，如iptables、tr、sort、awk等等只是略懂一二，我觉得太多的Linux常识我需要去补充。 从自己每个月写的blog数量基本上可以反映出自己在当月的工作繁忙程度以及自身的状态。6月份的状态算是上半年中最好的了，放下了一些纠结让自己更能专注。我很怀念在学校那种为了完成一个作业或者项目连续好多个晚上搞得通宵，不分昼夜专注地去做，工作之后很难有这种机会了。前几天和大学的同事吃饭，也是舍友，他说他想花5年的时间给自己充电再去微软，他当初在百度和微软实习过，只是有点可惜。前段时间回到学校，也得知有位同学正准备出国。感慨大家都很有目标，也同时为了自己的目标而在努力地奋斗。一生何求，我也得要为自己定个目标。 胡扯了一下就写了2个小时，时间是只能靠自己把握的，这是个和青春竞争的人生阶段。]]></description>
			<content:encoded><![CDATA[<p>不经不觉毕业也一年了，走得太匆忙，并没有和大家留下什么伤感的回忆。</p>
<p>从入职到现在，除了觉得时间过得很快之外，就是觉得自己没有把握好时间，或者毕业后各方面的原因学习动力和激情也比不上在学校的时候。</p>
<p>回头看看这一年……</p>
<p>09年的下半年，大部分时间是投入在研究fopen这个Facebook开源SNS，由于这是搭建在Linux平台并用php和c++写的，Linux和php这两方面对我来说都不太熟悉，折腾了好长的一段时间。fopen并没有原本所期待那样能够真正地投入到正式的产品使用，更多的，它只是Facebook的一个超级简化版，而且文档也相当地不完整，整个fopen依赖的库文件也很多，我当时也没能弄明白这些库文件是做什么的。在改写JavaScript的部分，虽然代码逻辑是比较清晰，但是像它那样的逻辑重写1000的JavaScript代码都要10多秒，不知道它在正式投入使用的时候是怎么提升解析速度的，又或者是正式产品中是使用了C++重写或者利用其他的一些缓存技术。在OpenAPI部分，那时候还弄不明白那个timestamp和callback的参数作用，后来才明白timestamp是用于防止replay attack，而callback是为了使用jsonp的，只怪当时知识面太窄了。虽然最后也用python实现了类似的JavaScript Parser和OpenAPI以及JavaScript client lib，但实际上需要完善的空间实在太多，只是时间无法安排过来。、</p>
<p>09年11月份开始的时候封闭开发了好长一段时间，封闭开发最大的体会就是环境很安静，但人能够很集中精神地开发，效率的确高很多。其实这段时间最大的收获是在美林的时候认识了老邓，他是云风带领的那个工作室的成员，他把我带进了函数式编程的世界，跟我讲了很多除了c++、java、.net之外的其他语言情况，比如lisp、squeak、haskell、erlang等等，还跟我讲了计算机世界里面一些有意思的事情和人物，并介绍了好几本书给我。作为刚毕业的新人，老员工知识和经验的分享正是新人所需要的。<span id="more-1009"></span></p>
<p>从新年放假回来后，前2个月是主要是完成一些比较琐碎的东西，开发一些平台上的小功能和修复一些bug。后2个月主要是开发一些营销活动，进度非常赶，这些活动项目时效比较短，我只是加班把这些活动项目做出来，但是我没有时间把这些项目做得好，我自己是个追求完美的人，作品写得这么挫却又无可奈何心里面是何等的不爽。我觉得公司的营销同事制定营销推广计划的时候应该和开发人员先协商进度安排以及项目上线的各方面可行性，而不是把计划定好了，然后有什么进度压力就直接推给开发人员。</p>
<p>Python写了一年多，但是我觉得在同一届入职的同事里面，掌握得最差的应该是我了。在Python花的时间的确是太少了，我仍然需要阅读更多关于Python方面的资料和写更多的代码，pythonic是我的目标。JavaScript方面在实际上项目倒是提高了不少，对闭包和作用域链的理解，一些IE的hack，页面脚本的加载顺序等等，Firebug的脚本调试作用也相当的强大和方便。总的来说，各方面都有一定的提高，不过前端的css的样式设置我依然觉得很痛苦。虽然平时都是在Linux环境下开发，但是我对Linux的理解还是相当地肤浅，Shell编程和Linux C的提高是我的下一个目标，Linux下的很多命令，如iptables、tr、sort、awk等等只是略懂一二，我觉得太多的Linux常识我需要去补充。</p>
<p>从自己每个月写的blog数量基本上可以反映出自己在当月的工作繁忙程度以及自身的状态。6月份的状态算是上半年中最好的了，放下了一些纠结让自己更能专注。我很怀念在学校那种为了完成一个作业或者项目连续好多个晚上搞得通宵，不分昼夜专注地去做，工作之后很难有这种机会了。前几天和大学的同事吃饭，也是舍友，他说他想花5年的时间给自己充电再去微软，他当初在百度和微软实习过，只是有点可惜。前段时间回到学校，也得知有位同学正准备出国。感慨大家都很有目标，也同时为了自己的目标而在努力地奋斗。一生何求，我也得要为自己定个目标。</p>
<p>胡扯了一下就写了2个小时，时间是只能靠自己把握的，这是个和青春竞争的人生阶段。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/07/01/one-year-after-graduation/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>zz Dojo Javascript 编程规范</title>
		<link>http://blog.endlesscode.com/2010/06/25/zz-coding-convention-of-javascript/</link>
		<comments>http://blog.endlesscode.com/2010/06/25/zz-coding-convention-of-javascript/#comments</comments>
		<pubDate>Fri, 25 Jun 2010 05:46:58 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=977</guid>
		<description><![CDATA[虽然这说是Dojo的编程规范，但实际上大部分都是普遍应用的规范，所以就当是JavaScript的编程规范转载过来了 前言 相当不错的 Javascript 编程风格规范，建议大家采用此规范编写 Javascript。原文链接： http://dojotoolkit.org/developer/StyleGuide 。 翻译（Translated by）：i.feelinglucky{at}gmail.com from http://www.gracecode.com ，转载请注明出处、作者和翻译者，谢谢配合。 本文地址： http://code.google.com/p/grace/wiki/DojoStyle 。 序 Any violation to this guide is allowed if it enhances readability. 所有的代码都要变成可供他人容易阅读的。 快读参考 核心 API 请使用下面的风格： 结构 规则 注释 模块 小写 不要使用多重语义（Never multiple words） 类 骆驼 &#8230; <a href="http://blog.endlesscode.com/2010/06/25/zz-coding-convention-of-javascript/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div style="width:80%;border:1px dotted #000000;padding:5px;text-align:center;margin:5px auto;">虽然这说是Dojo的编程规范，但实际上大部分都是普遍应用的规范，所以就当是JavaScript的编程规范转载过来了</div>
<h2>前言</h2>
<p style="max-width: 65em;">相当不错的 Javascript 编程风格规范，建议大家采用此规范编写 Javascript。原文链接： <a rel="nofollow" href="http://dojotoolkit.org/developer/StyleGuide">http://dojotoolkit.org/developer/StyleGuide</a> 。</p>
<p style="max-width: 65em;">翻译（Translated by）：i.feelinglucky{at}gmail.com from <a style="color: #0000cc;" rel="nofollow" href="http://www.gracecode.com">http://www.gracecode.com</a> ，转载请注明出处、作者和翻译者，谢谢配合。</p>
<p style="max-width: 65em;">本文地址： <a rel="nofollow" href="http://code.google.com/p/grace/wiki/DojoStyle">http://code.google.com/p/grace/wiki/DojoStyle</a> 。</p>
<h2>序</h2>
<p style="max-width: 65em;">Any violation to this guide is allowed if it enhances readability.</p>
<p style="max-width: 65em;">所有的代码都要变成可供他人容易阅读的。</p>
<h2>快读参考</h2>
<p style="max-width: 65em;">核心 API 请使用下面的风格：</p>
<table style="border-collapse: separate;" border="0">
<tbody>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;"><strong>结构</strong></td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;"><strong>规则</strong></td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;"><strong>注释</strong></td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">模块</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">小写</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">不要使用多重语义（Never multiple words）</td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">类</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">骆驼</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;"></td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">公有方法</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">混合</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">其他的外部调用也可以使用 lower_case()，这样的风格</td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">公有变量</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">混合</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;"></td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">常量</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">骆驼 或 大写</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;"></td>
</tr>
</tbody>
</table>
<p style="max-width: 65em;">下面的虽然不是必要的，但建议使用：</p>
<table style="border-collapse: separate;" border="0">
<tbody>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;"><strong>结构</strong></td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;"><strong>规则</strong></td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">私有方法</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">混合，例子：<tt style="font-size: 13px;">_mixedCase</tt></td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">私有变量</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">混合，例子：<tt style="font-size: 13px;">_mixedCase</tt></td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">方法（method）参数</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">混合，例子：<tt style="font-size: 13px;">_mixedCase, mixedCase</tt></td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">本地（local）变量</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">混合，例子：<tt style="font-size: 13px;">_mixedCase, mixedCase</tt></td>
</tr>
</tbody>
</table>
<p><span id="more-977"></span></p>
<h2>命名规范</h2>
<ol style="max-width: 65em; padding-left: 40px;">
<li>变量名称 <em>必须为</em> 小写字母。</li>
<li>类的命名使用骆驼命名规则，例如：
<pre class="brush:javascript">Account, EventHandler</pre>
</li>
<li>常量 <em>必须</em> 在对象（类）或者枚举变量的前部声明。枚举变量的命名必须要有实际的意义，并且其成员 <em>必须</em> 使用骆驼命名规则或使用大写：</li>
<pre class="brush:javascript">var NodeTypes = {
    Element : 1,
    DOCUMENT: 2
}</pre>
<li>简写单词 <em>不能使用</em> 大写名称作为变量名：</li>
<pre class="brush:javascript">getInnerHtml(), getXml(), XmlDocument</pre>
<li>方法的命令 <em>必须</em> 为动词或者是动词短语：</li>
<pre class="brush:javascript">obj.getSomeValue()</pre>
<li>公有类的命名 <em>必须</em> 使用混合名称（mixedCase）命名。</li>
<li>CSS 变量的命名 <em>必须</em> 使用其对应的相同的公共类变量。</li>
<li>私有类的变量属性成员 <em>必须</em> 使用混合名称（mixedCase）命名，并前面下下划线（<tt style="font-size: 13px;">_</tt>）。例如：</li>
<pre class="brush:javascript">var MyClass = function(){
   var _buffer;
   this.doSomething = function(){
   };
}</pre>
<li>变量如果设置为私有，则前面 <em>必须</em> 添加下划线。</li>
<pre class="brush:javascript">this._somePrivateVariable = statement;</pre>
<li>通用的变量 <em>必须</em> 使用与其名字一致的类型名称：</li>
<pre class="brush:javascript">setTopic(topic) // 变量 topic 为 Topic 类型的变量</pre>
<li>所有的变量名 <em>必须</em> 使用英文名称。</li>
<li>变量如有较广的作用域（large scope），必须使用全局变量；此时可以设计成一个类的成员。相对的如作用域较小或为私有变量则使用简洁的单词命名。</li>
<li>如果变量有其隐含的返回值，则避免使用其相似的方法：</li>
<pre class="brush:javascript">getHandler(); // 避免使用 getEventHandler()</pre>
<li>公有变量必须清楚的表达其自身的属性，避免字义含糊不清，例如：</li>
<pre class="brush:javascript">MouseEventHandler，而非 MseEvtHdlr。</pre>
<p>请再次注意这条规定，这样做得的好处是非常明显的。它能明确的表达表达式所定义的含义。例如：</p>
<pre class="brush:javascript">dojo.events.mouse.Handler // 而非 dojo.events.mouse.MouseEventHandler</pre>
<li>类/构造函数 <em>可以使用</em> 扩展其基类的名称命名，这样可以正确、迅速的找到其基类的名称：</li>
<pre class="brush:javascript">EventHandler
UIEventHandler
MouseEventHandler</pre>
<p>基类可以在明确描述其属性的前提下，缩减其命名：</p>
<pre class="brush:javascript">MouseEventHandler as opposed to MouseUIEventHandler.</pre>
</ol>
<h2>特殊命名规范</h2>
<ol style="max-width: 65em; padding-left: 40px;">
<li>术语 &#8220;get/set&#8221; 不要和一个字段相连，除非它被定义为私有变量。</li>
<li>前面加 &#8220;is&#8221; 的变量名 <em>应该</em> 为布尔值，同理可以为 &#8220;has&#8221;, &#8220;can&#8221; 或者 &#8220;should&#8221;。</li>
<li>术语 &#8220;compute&#8221; 作为变量名应为已经计算完成的变量。</li>
<li>术语 &#8220;find&#8221; 作为变量名应为已经查找完成的变量。</li>
<li>术语 &#8220;initialize&#8221; 或者 &#8220;init&#8221; 作为变量名应为已经实例化（初始化）完成的类或者其他类型的变量。</li>
<li>UI （用户界面）控制变量应在名称后加控制类型，例如： leftComboBox, TopScrollPane。</li>
<li>复数必须有其公共的名称约定（原文：Plural form MUST be used to name collections）。</li>
<li>带有 &#8220;num&#8221; 或者 &#8220;count&#8221; 开头的变量名约定为数字（对象）。</li>
<li>重复变量建议使用 &#8220;i&#8221;, &#8220;j&#8221;, &#8220;k&#8221; （依次类推）等名称的变量。</li>
<li>补充用语必须使用补充词，例如： get/set, add/remove, create/destroy, start/stop, insert/delete, begin/end, etc.</li>
<li>能缩写的名称尽量使用缩写。</li>
<li>避免产生歧义的布尔变量名称，例如：</li>
<pre class="brush:javascript">isNotError, isNotFound 为非法</pre>
<li>错误类建议在变量名称后加上 &#8220;Exception&#8221; 或者 &#8220;Error&#8221;。</li>
<li>方法如果返回一个类，则应该在名称上说明返回什么；如果是一个过程，则应该说明做了什么。</li>
</ol>
<h2>文件</h2>
<ol style="max-width: 65em; padding-left: 40px;">
<li>缩进请使用 4 个空白符的制表位。</li>
<li>如果您的编辑器支持 文件标签_（file tags），请加添如下的一行使我们的代码更容易阅读：
<pre class="brush:javascript">// vim:ts=4:noet:tw=0:
//译注：老外用 VIM 编辑器比较多，此条可以选择遵循。</pre>
</li>
<li>代码折叠必须看起来是完成并且是合乎逻辑的：
<pre class="brush:javascript">var someExpression = Expression1
    + Expression2
    + Expression3;

var o = someObject.get(
    Expression1,
    Expression2,
    Expression3
);

//注：表达式的缩进与变量声明应为一致的。
//注：函数的参数应采用明确的缩进，缩进规则与其他块保持一致。</pre>
</li>
</ol>
<h2>变量</h2>
<ol style="max-width: 65em; padding-left: 40px;">
<li>变量必须在声明初始化以后才能使用，即便是 NULL 类型。</li>
<li>变量不能产生歧义。</li>
<li>相关的变量集应该放在同一代码块中，非相关的变量集不应该放在同一代码块中。</li>
<li>变量应该尽量保持最小的生存周期。</li>
<li>循环/重复变量的规范：
<ul>
<li>只有循环控制块的话，则必须使用 FOR 循环。</li>
</ul>
<ul>
<li>循环变量应该在循环开始前就被初始化；如使用 FOR 循环，则使用 FOR 语句初始化循环变量。</li>
</ul>
<ul>
<li>&#8220;do &#8230; while&#8221; 语句是被允许的。</li>
</ul>
<ul>
<li>&#8220;break&#8221; 和 &#8220;continue&#8221; 语句仍然允许使用（但请注意）。</li>
</ul>
</li>
<li>条件表达式
<ul>
<li>应该尽量避免复杂的条件表达式，如有必要可以使用临时布尔变量。</li>
</ul>
<ul>
<li>The nominal case SHOULD be put in the &#8220;if&#8221; part and the exception in the &#8220;else&#8221; part of an &#8220;if&#8221; statement.</li>
</ul>
<ul>
<li>应避免在条件表达式中加入块。</li>
</ul>
</li>
<li>杂项
<ul>
<li>尽量避免幻数（Magic numbers），他们应该使用常量来代替。</li>
</ul>
<ul>
<li>浮点变量必须指明小数点后一位（即使是 0）。</li>
</ul>
<ul>
<li>浮点变量必须指明实部，即使它们为零（使用 0. 开头）。</li>
</ul>
</li>
</ol>
<h2>布局</h2>
<h3>块</h3>
<ol style="max-width: 65em; padding-left: 40px;">
<li>普通代码段 <em>应该</em> 看起来如下：</li>
<pre class="brush:javascript">while (!isDone){
    doSomething();
    isDone = moreToDo();
}</pre>
<li>IF 语句 <em>应该</em> 看起来像这样：</li>
<pre class="brush:javascript">if (someCondition){
    statements;
} else if (someOtherCondition){
    statements;
} else {
    statements;
}</pre>
<li>FOR 语句 <em>应该</em> 看起来像这样：</li>
<pre class="brush:javascript">for (initialization; condition; update){
    statements;
}</pre>
<li>WHILE 语句 <em>应该</em> 看起来像这样：</li>
<pre class="brush:javascript">while (!isDone) {
    doSomething();
    isDone = moreToDo();
}</pre>
<li>DO &#8230; WHILE 语句 <em>应该</em> 看起来像这样：</li>
<pre class="brush:javascript">do {
    statements;
} while (condition);</pre>
<li>SWITCH 语句 <em>应该</em> 看起来像这样：</li>
<pre class="brush:javascript">switch (condition) {
case ABC:
    statements;
    //  fallthrough
case DEF:
    statements;
    break;
default:
    statements;
    break;
}</pre>
<li>TRY &#8230; CATCH 语句 <em>应该</em> 看起来像这样：</li>
<pre class="brush:javascript">try {
    statements;
} catch(ex) {
    statements;
} finally {
    statements;
}</pre>
<li>单行的 IF &#8211; ELSE，WHILE 或者 FOR 语句也 <em>必须</em> 加入括号，不过他们可以这样写：</li>
<pre class="brush:javascript">if (condition){ statement; }
while (condition){ statement; }
for (intialization; condition; update){ statement; }</pre>
</ol>
<h3>空白</h3>
<ol style="max-width: 65em; padding-left: 40px;">
<li>操作符 <em>建议</em> 使用空格隔开（包括三元操作符）。</li>
<li>下面的关键字 <em>避免使用</em> 空白隔开：
<ul style="max-width: 65em; padding-left: 40px;">
<li>break</li>
<li>catch</li>
<li>continue</li>
<li>do</li>
<li>else</li>
<li>finally</li>
<li>for</li>
<li>function （如果为匿名函数，例如：var foo = function(){}; ）</li>
<li>if</li>
<li>return</li>
<li>switch</li>
<li>this</li>
<li>try</li>
<li>void</li>
<li>while</li>
<li>with</li>
</ul>
</li>
<li>下面的关键字必须使用空白隔开：
<ul style="max-width: 65em; padding-left: 40px;">
<li>case</li>
<li>default</li>
<li>delete</li>
<li>function （如果为申明，例如：function foo(){}; ）</li>
<li>in</li>
<li>instanceof</li>
<li>new</li>
<li>throw</li>
<li>typeof</li>
<li>var</li>
</ul>
</li>
<li><strong>逗号（,）</strong> <em>建议</em> 使用空白隔开。</li>
<li><strong>冒号（:）</strong> <em>建议</em> 使用空白隔开。</li>
<li><strong>点（.）</strong> 在后部 <em>建议</em> 使用空白隔开。</li>
<li><strong>点（.）</strong> <em>避免</em> 在前部使用空白。</li>
<li><strong>函数调用和方法</strong> <em>避免</em> 使用空白，例如：<tt style="font-size: 13px;"> doSomething(someParameter); // 而非 doSomething (someParameter)</tt></li>
<li><strong>逻辑块</strong> 之间使用空行。</li>
<li><strong>声明</strong> <em>建议</em> 对齐使其更容易阅读。</li>
</ol>
<h3>注释</h3>
<ol style="max-width: 65em; padding-left: 40px;">
<li>生涩的代码就 <em>没有必要</em> 添加注释了，首先您需要 <strong>重写</strong> 它们。</li>
<li>所有的注释请使用英文。</li>
<li>从已解决的方案到未开发的功能，注释 <em>必须</em> 与代码相关。</li>
<li>大量的变量申明后 <em>必须</em> 跟随一段注释。</li>
<li>注释需要说明的是代码段的用处，尤其是接下来的代码段。</li>
<li>注释 <em>没有必要</em> 每行都添加。</li>
</ol>
<h2>文档</h2>
<p style="max-width: 65em;">下面提供了一些基本的函数或者对象的描述方法：</p>
<ul style="max-width: 65em; padding-left: 40px;">
<li><strong>总结（summary）</strong>: 简短的表述此函数或者对象实现的目的</li>
<li><strong>描述（description）</strong>: 对于此函数或者类的简短的描述</li>
<li><strong>返回（return）</strong>: 描述此函数返回什么（并不包括返回类型）</li>
</ul>
<h3>基本函数信息</h3>
<pre class="brush:javascript">function(){
    // summary: Soon we will have enough treasure to rule all of New Jersey.
    // description: Or we could just get a new roomate.
    //          Look, you go find him.  He don't yell at you.
    //          All I ever try to do is make him smile and sing around
    //          him and dance around him and he just lays into me.
    //          He told me to get in the freezer 'cause there was a carnival in there.
    // returns:  Look, a Bananarama tape!
}</pre>
<h3>对象函数信息</h3>
<p style="max-width: 65em;">没有返回值描述</p>
<pre class="brush:javascript">{
    // summary: Dingle, engage the rainbow machine!
    // description:
    //          Tell you what, I wish I was--oh my g--that beam,
    //          coming up like that, the speed, you might wanna adjust that.
    //          It really did a number on my back, there. I mean, and I don't
    //          wanna say whiplash, just yet, cause that's a little too far,
    //          but, you're insured, right?
}</pre>
<h3>函数的声明</h3>
<p style="max-width: 65em;">在有的情况下，对于函数的调用和声明是隐义（invisible）的。在这种情况下，我们没有办法在函数中加入说明等（供程序调用）。如果您遭遇了这种情况，您可以使用一个类来封装函数。</p>
<p style="max-width: 65em;">注：此此方法只能在函数没有初始化的参数情况下。如过不是，则它们会被忽略。</p>
<pre class="brush:javascript">dojo.declare(
    "foo",
    null,
    {
        // summary: Phew, this sure is relaxing, Frylock.
        // description:
        //              Thousands of years ago, before the dawn of
        //              man as we knew him, there was Sir Santa of Claus: an
        //              ape-like creature making crude and pointless toys out
        //              of dino-bones, hurling them at chimp-like creatures with
        //              crinkled hands regardless of how they behaved the
        //              previous year.
        // returns: Unless Carl pays tribute to the Elfin Elders in space.
    }
);</pre>
<h3>参数</h3>
<ol style="max-width: 65em; padding-left: 40px;">
<li>简单类型</li>
<p>简单的类型的参数可以直接在函数参数定义中注释说明。</p>
<pre class="brush:javascript">function(/*String*/ foo, /*int*/ bar)...</pre>
<li>可变类型参数<br />
下面是几个修饰符供参考：</p>
<ul style="max-width: 65em; padding-left: 40px;">
<li><strong>?</strong> 可选参数</li>
<li><strong>&#8230;</strong> 说面参数范围不确定</li>
<li><strong><a></a></strong> 数组</li>
</ul>
<pre class="brush:javascript">function(/*String?*/ foo, /*int...*/ bar, /*String[]*/ baz)...</pre>
</li>
<li>全局参数描述</li>
<p>如果你想增加一个描述，你可以将它们移至初始化块。<br />
基本信息格式为： *关键字* 描述字段（*key* Descriptive sentence）<br />
参数和变量的格式为： *关键字* ~*类型*~ 描述字段（ *key* ~*type*~ Descriptive sentence）<br />
注： *关键字* 和 ~*类型*~ 可以使用任何字母和数字表述。</p>
<pre class="brush:javascript">function (foo, bar) {
    // foo: String
    //      used for being the first parameter
    // bar: int
    //      used for being the second parameter
}</pre>
</ol>
<h3>变量</h3>
<p style="max-width: 65em;">由于实例变量、原型变量和外部变量的声明是一致的，所以有很多的方法声明、修改变量。具体的如何定义和定位应在变量最先出现的位置指明变量的名称、类型、作用域等信息。</p>
<pre class="brush:javascript">function foo() {
    // myString: String
    // times: int
    //        How many times to print myString
    // separator: String
    //        What to print out in between myString*
    this.myString = "placeholder text";
    this.times = 5;
}

foo.prototype.setString = function (myString) {
    this.myString = myString;
}

foo.prototype.toString = function() {
    for(int i = 0; i &lt; this.times; i++) {
        dojo.debug(this.myString);
        dojo.debug(foo.separator);
        }
}
foo.separator = "=====";</pre>
<h4>对象中的变量注释</h4>
<p style="max-width: 65em;">应使用和对象值和方法一致的标注方式，比如在他们声明的时候：</p>
<pre class="brush:javascript">{
    // key: String
    //      A simple value
    key: "value",
    // key2: String
    //      Another simple value
}</pre>
<h3>返回值</h3>
<p style="max-width: 65em;">因为函数可以同时返回多个不同（类型）的值，所以应每个返回值之后加入返回类型的注释。注释在行内注释即可，如果所有的返回值为同一类型，则指明返回的类型；如为多个不同的返回值，则标注返回类型为&#8221;mixed&#8221;。</p>
<pre class="brush:javascript">function() {
    if (arguments.length) {
        return "You passed argument(s)"; // String
    } else {
        return false; // Boolean
    }
}</pre>
<h3>伪代码（有待讨论）</h3>
<p style="max-width: 65em;">有时候您需要在函数或者类中添加对于此函数和类的功能性流程描述。如果您打算这样做，您可以使用 <tt style="font-size: 13px;">/*======== </tt>（= 字符最好出现 5 次或者更多），这样做的好处就是可以不用将这些东西加入代码（译注：原作者的意思可能为代码管理系统）。</p>
<p style="max-width: 65em;">这样看起来在 <tt style="font-size: 13px;">/*===== </tt>和 <tt style="font-size: 13px;">=====*/ </tt>会有非常长的一段注释，等待功能调整完毕以后就可以考虑是否删除。</p>
<pre class="brush:javascript">/*=====
module.pseudo.kwArgs = {
        // url: String
    //          The location of the file
    url: "",
    // mimeType: String
    //          text/html, text/xml, etc
    mimeType: ""
}
=====*/

function(/*module.pseudo.kwArgs*/ kwArgs){
    dojo.debug(kwArgs.url);
        dojo.debug(kwArgs.mimeType);
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/06/25/zz-coding-convention-of-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

