Wednesday, August 12, 2009

gnuplot速查

绘制曲线

  1. 绘制预定义的函数:
    plot sin(x)+exp(x)
    除了sin(x)外, 还支持的其他函数包括: abs(x),acos(x),asin(x),atan(x),cos(x),cosh(x),erf(x),exp(x),inverf(x),invnorm(x),log(x),log10(x),norm(x),rand(x),sgn(x),sin(x),sinh(x),sqrt(x),tan(x),tanh(x).
  2. 绘制自定义函数:当预定义的函数不够用的时候,我们可以自己定义函数
    y(x)=x**2+log(x)
    z(x)=x**3-x
    gnuplot还支持?:这种C风格的函数.比如
    f(x) = x < 1 ? 1
         : x < 2 ? 3
                 : 5
    就是f(x) =1 if x<1, =3 if 1<=x<2 =5 otherwise
    然后绘制上述两自定义函数的图像:
    plot y(x), z(x)
    还可以直接这样作:
    plot y(x) = x**2+log(x), y(x), z(x)=x**3-x, z(x)
  3. 从文件中读取数据并绘图:
    使用foo.dat第1列(作为x)和第2列(作为y)来画图
    plot "foo.dat" using 1:2
    使用foo.dat第1列和第2列作为数据,但每2行skip掉一行
    plot "foo.dat" using 1:2 every 2
    使用foo.dat第1列(作为x)和第2列(作为y)做第一条曲线,使用foo.dat第1列(作为x)和第3列(作为y)做第二条曲线
    plot "foo.dat" using 1:2, "foo.dat" using 1:3
    foo.dat第3列作为errobar:
    plot "foo.dat" using 1:2:3 with yerrorbars
    foo.dat的第二列除以第一列作为y值
    plot "foo.dat" using 1:($2/$1)
    foo.dat分为若干个block(block之间用两行回车隔开), 使用第2个block绘图
    plot "foo.dat" index 1 using 1:2
  4. 重绘:
    replot
  5. 指定曲线的名称:
    plot "foo.dat" using 1:2 title "sample curve"

曲线样式设定

  1. 指定曲线种类
    曲线种类包括`lines`, `points`, `linespoints`, `impulses`,
    `dots`, `steps`, `fsteps`, `histeps`, errorbars, `xerrorbars`,
    `yerrorbars`, `xyerrorbars`, errorlines, `xerrorlines`,
    `yerrorlines`, `xyerrorlines`, `boxes`, `filledcurves`, `boxerrorbars`,
    `boxxyerrorbars`, `financebars`, `candlesticks`, `vectors`
    plot "foo.dat" using 1:2 with lines # 用线条画图
    plot "foo.dat" using 1:2 with points # 用点画图
    plot "foo.dat" using 1:2 with linespoints # 用点线结合的方式画图
    plot "foo.dat" using 1:2 with boxes # bar-chart
    plot "foo.dat" using 1:2:(sprintf("%.2f", $2)) with labels # 在图上标注数字
    
    更多的曲线样式比如financebars等 参见Plot Style , errorbars
    plot  "foo.dat" using 1:2:3:4:(width)\
            with boxerror fs pattern 1 #x:mean:min:max:box_width

    给定了曲线样式, 它的还有四种参数可以自行设定:linetype, linewidth, pointtype, pointsize. 可以用test 命令查看所有支持的style.
  2. 指定曲线颜色(linetype)
    plot "foo.dat" using 1:2 with lines linetype 1
    lt(linetype)指定点或者线的颜色-1=black 1=red 2=grn 3=blue 4=purple 5=aqua 6=brn 7=orange 8=light-brn
    或者通过更直接的linecolor方式指定颜色(gnuplot 4.2 or later),比如
    plot "foo.dat" using 1:2 with lines linecolor rgb "red" 
    plot "foo.dat" using 1:2 with lines linecolor  rgb "#ff0000"
  3. 指定曲线宽度(linewidth)
    plot "foo.dat" using 1:2 with lines linewidth 6
  4. 指定marker(pointtype)
    可以单独对每条曲线指定marker size,
    plot "foo.dat" using 1:2 with points pointsize 2
    也可以对所有曲线指定(默认大小为1)
    set pointsize 2
    如果使用points 或者linepoints画曲线的话,这里的piont相当于marker.可以用 pointtype和pointsize指定marker的样式和大小。
    pt指定marker的种类1=diamond 2=+ 3=square 4=X 5=triangle 6=*
  5. 自定义linestyle
    如果觉得在plot语句中使用上述这些曲线修饰太麻烦,有碍观瞻,可以实现设定好一个linestyle, 然后在plot语句中指明使用该种style. 比如
    set style line 1 lt 1 lw 1 lc rgb "red"
    set style line 6 lt 2 lw 3 lc rgb "blue"
    plot sin(x) w l linestyle 1, cos(c) w lp linestyle 2
坐标轴设定

  1. 设定坐标轴名称:
    set xlabel "time(t)"
    set ylabel "A"
    使用LaTeX数学符号:
    set ylabel "{/Symbol f_i}"
  2. 设定坐标轴为logscale:
    set logscale x
    取消logscale的x轴
    unset logscale x
  3. 坐标轴的刻度的格式

    每个刻度值后面加上百分号
    set format x  "%g%%"
    以指数形式表现, 比如10^1, 10^2,10^3而不是10, 100, 1000
    set format x  "10^{%L}"
  4. 设置坐标轴的范围
    set xrange [-3:65]
    set yrange [ 4:14]
    也可以在绘制的时候指定:
    plot [-3:65] sin(x)
  5. 指定坐标轴刻度
    set xtics ("x=1" 1, "x=10" 10, "x=100" 100)
  6. 指定坐标轴刻度间隔宽度
    set xtics 100
  7. 指定坐标轴刻度起始值和间隔
    set xtics 0, 100  #坐标轴小于0的部分就没有刻度了
  8. 去除坐标轴刻度的mirror(x2,y2默认不在x,y上有mirror, 但是x,y默认在x2,y2上有)
    set ytics nomirror  #y坐标轴的tics在y2上没有mirror
  9. 将X坐标值作为日期来显示
    set xdata time
    set timefmt "%s" #输入时间数据形式为time()函数返回值
    set format x "%b/%y" #输出时间数据形式为month/year
图例

  1. 图例的位置可以是"left", "right", "top", "bottom", "outside" 和 "below",
    默认是"right top",
    set key left bottom
    set key outside
    也可以用坐标指定(这里的坐标是指图例中第一行文字和符号之间的中点坐标)
    如果你使用的gnuplot 4.6以下
    set key 100,40
  2. 如果你使用的gnuplot 4.6以上
    set key at 100,40

  • 图例字体大小不能单独设定,使用的是在set term中指定的大小
  • 取消图例
    unset key
  • 输出

    1. 输出显示在屏幕上:
      set term x11
    2. 输出为eps文件(默认输出在stdout上,所以你将看见大批ps指令):
      set term postscript eps enhanced
    3. 输出为png文件(默认输出在stdout上,所以你将看见大量binary被输出):
      set term png
    4. 将输出放在文件上
      如果另存为eps文件
      set output "foo.eps"
      如果另存为png文件
      set output "foo.png"
    图的大小

    1. 设定X轴与Y轴的横纵比例为3:1
      set size ratio 3
    2. 设定整个figure(包括了坐标轴以及边距)的横纵比例为2:1(默认值是1:1)
      set size 2,1
    3. 生成figure的绝对大小是和terminal相关的
    其他

    1. 网格
      set grid
      set grid y
      unset grid
    2. 边框. 边框的设定可见这里. 简单说来就是通过一个掩码来指定用哪几个边框1(bottom), 2(left), 4(top), 8(right)
      unset border # 没有边框
      set border 3 #只留下左边和下边的边框
      
    3. 消除生成的eps周围过多的margin
      $eps2eps input.eps output.eps
    4. 在指定坐标上绘制label
      set label center at 11.5,1.5 "My-Fav-Label!" font ",6"
    5. 读取并执行一个gnuplot文件,比如把一些命令或者设定放在一个文件里
      load "your-gnuplot-file"

    参考:

    [1] 史上最好的gnuplot参考,有木有?
    [2] set命令可以设定的参数
    [3] gnuplot 使用技巧
    [4] 和latex的psfrag配合使用
    [5] Gnuplot tricks: 相当赞的一个帖子
    [6] Gnuplot的demo,可以照着选自己需要的样式

    Tuesday, July 21, 2009

    [Linux]GDB笔记

    本文参考了如下资源
    GDB quick reference: 一个很不错的cheatsheet
    RMS的gdb tutorial
    中文的gdb教程

    1 最基本用法

    最基本的gdb用法可以帮助你找到程序里哪里出现segment fault。首先你要在gcc编译的时候加上-ggdb选项。假定你的程序名叫foo,你可以用如下命令进入gdb开始program进行debug:
    $ gdb foo
    gdb会在你出现段错误的地方停下来,你会看到是哪个程序哪行语句出了问题.
    2 Core Dump

    发现了segment fault的话,还可以使用core dump。这样不但可以很方便的找到出问题的代码. 还可以多次重现这个错误。 首先使用以下的命令允许系统生成core文件.
    $ ulimit -c unlimited
    然后运行你的代码,比如叫foo, 等到segment fault发生并异常退出以后, 你会发现在foo的同一个文件夹下多了一个名字类似core.1234这样的文件。这时候运行如下命令就可以重现案发现场了
    $ gdb foo core.1234

    3 普通用法

    r [arglist]: (重新)运行程序
    b [file:]line, b [file:]function: 设置断点在line或者function
    c, continue: 继续运行程序
    s, step: 单步执行, 进入函数
    n, next: 单步执行, 不进入函数
    finish: 执行完当前frame
    kill: 终止当前程序
    q, Ctrl-d: 退出gdb
    p [expr]: 显示表达式expr. 比如var表示变量var的内容而 &var表示变量var的内存地址
    bt: 显示当前调用栈(call stack)
    set args [arglist]: 设置命令行参数,从而可以直接用r(run)来执行

    4 断点(breakpoit)/观察点(watchpoint)设置与管理

    b [file:]line, b [file:]function: 设置断点在line或者function
    watch [expr]: 设置观察点,一旦表达式expr有变化就停下来. expr通常为一个变量或者内存地址
    rwatch [expr]: 设置观察点,一旦被读就停下程序
    awatch [expr]: 设置观察点,一旦被读或者被写都停下程序
    比如你可以使用awatch *(long*)addr来监视内存地址addr是否被读或者被写
    info breakpoints/watchpoints: 查看当前设置了的断点和观察点, info watchpoints是info breakpoints的alias
    enable/disable/delete [n]: 激活/禁用/删除 编号为[n]的断点/观察点

    5 程序栈

    bt, backtrace: 显示当前调用栈(call stack),比如
    (gdb) bt
    #0  0x000000010005ea07 in init (ctx=0x100622070, opts=@0x10060d078) at Utils.cpp:1678
    #1  0x00000001000149ad in main (argc=3, argv=0x7fff5fbffb30) at main.cpp:591
    frame: 改变frame,比如
    (gdb) frame 1
    #2  0x8048414 in main (argc=1, argv=0xbffffaf4) at test.c:19
    19        x = func1(x);
    info frame: 查看当前frame的信息
    (gdb) info frame
    Stack level 2, frame at 0xbffffa8c:
    eip = 0x8048414 in main (test.c:19); saved eip 0x40037f5c
    called by frame at 0xbffffac8, caller of frame at 0xbffffa5c 
    source language c.
    Arglist at 0xbffffa8c, args: argc=1, argv=0xbffffaf4
    Locals at 0xbffffa8c, Previous frame's sp is 0x0
    Saved registers:
    ebp at 0xbffffa8c, eip at 0xbffffa90
    info locals: 查看当前frame里的局部变量
    (gdb) info locals
    x = 30
    s = 0x8048484 "Hello World!\n"
    info args: 查看当前frame的调用参数
    (gdb) info args
    argc = 1
    argv = (char **) 0xbffffaf4


    6 查看变量/函数, 改变变量值

    如果有一个指针变量it指向一个struct item, 查看这个struct item的内存地址:
    (gdb) p it
    $1 = (item *) 0x100700060
    查看这个struct的内容
    (gdb) p *it
    $2 = {
      next = 0x100700000, 
      prev = 0x0
    }
    如果你有如下数组
    int *array = (int *) malloc (len * sizeof (int));
    你可以这样来查看你的数组
    p *array@len
    有时候你知道一段二进制代码所属的函数和偏移, 查这段对应的源代码:
    list *myfunc+0x16

    改变一个变量a的值为10
    set variable a=10

    7 查看内存

    用命令"x /nfu <addr>"
    n表示要显示的内存单元的个数
    f表示显示方式, 可取如下值
    x 按十六进制格式显示变量。
    d 按十进制格式显示变量。
    u 按十进制格式显示无符号整型。
    o 按八进制格式显示变量。
    t 按二进制格式显示变量。
    a 按十六进制格式显示变量。
    i 指令地址格式
    c 按字符格式显示变量。
    f 按浮点数格式显示变量。
    u表示一个地址单元的长度
    b表示单字节,
    h表示双字节,
    w表示四字节,
    g表示八字节

    8 其他


    info source: 查看当前frame对应的源文件信息

    (gdb) info source
    Current source file is shared_ptr.hpp
    Compilation directory is /usr/local/include/boost/smart_ptr
    Located in /usr/local/include/boost/smart_ptr/shared_ptr.hpp
    Contains 712 lines.
    Source language is c++.
    Compiled with unknown debugging format.
    Does not include preprocessor macro info.
    info threads: 查看当前线程数目以及状态

    (gdb) info threads
           Id   Target Id         Frame
           3    process 35 thread 27  0x34e5 in sigpause ()
           2    process 35 thread 23  0x34e5 in sigpause ()
         * 1    process 35 thread 13  main (argc=1, argv=0x7ffffff8)
             at threadtest.c:68

    Friday, July 10, 2009

    [数学]三个囚徒的问题

    从mitbbs上看到这道题,并查了wiki,觉得挺有意思的. 特别是两个版本细微的差别就会导致结果的不一样.

    版本1
    一个国王决定从3个囚徒A,B以及C中释放一个,处决另外两个.国王告诉A说,处决的犯人中不是A的那个(如果两个都不是A,则随机说一个)是B.A在得知这个信息以后,他被处决的概率是多少?
    SOL: 1/3

    版本2
    一个国王决定从3个囚徒A,B以及C中释放一个,处决另外两个.国王告诉A说,处决的犯人包括B.A在得知这个信息以后,他被处决的概率是多少?
    SOL: 1/2

    用列举法来解释结果:
    国王的决定 版本1国王告诉A版本1可以排除掉版本2可以排除掉
    放A 杀B 杀C B   
    放A 杀B 杀CCx  
    杀A 放B 杀C Cxx
    杀A 放B 杀CCxx
    杀A 杀B 放CB  
    杀A 杀B 放CB  

    Thursday, July 09, 2009

    [TeX]关于Tex, Latex,以及**tex的一个小结

    叫**TeX的东西太多了,我自己对它们的概念也很混淆.所以最近花了一些时间整理一下相关内容,作为笔记加深自己的理解.
    名词解释:其实这里有一个很不错的TeX名词的分类解释:TeX Catalogue
    • TeX: 所有**tex的源头,万物的本源. 它由Knuth爷爷用他自己钟爱的一种和Pascal很像的叫WEB的语言所编写的.由于年代的缘故,它有这样那样的局限性. 比如那个时候Knuth爷爷是为了给自己的巨著TAOCP(被视为Computer Science的圣经)排版所用,因此只考虑了支持英文.所以其输入必须是ascii编码的文本文件,而不能包括多字节的语言比如中文.再比如TeX的输出结果为dvi文件. dvi是"device independent format"的缩写.它使用点阵字体而不是轮廓字体.而点阵字体只有在特定大小的时候才最好看.
      Knuth爷爷拒绝对TeX再做改动,所以人们就对TeX作了各种各样的扩展.
    • pdfTeX: 这是对Knuth的TeX的扩展,用于直接输出为pdf而不是dvi(TeX的输出).除此以外相对于TeX,它可以支持TrueType以及Type 1等轮廓字体.
    • XeTeX: 对TeX最大的改进体现在支持unicode以及OpenType等现代字体. 因此对中文的输入的天然支持的.它的工作过程分为两步:第一步生成extended dvi文件(xdv);第二步再将xdv文件转为pdf文件. xelatex是使用XeTeX引擎来编译latex源文件的工具.
    • luaTeX: 基于pdfTeX和Lua语言的TeX引擎. 同样也支持unicode.
    • Primitive Tex: TeX原始命令.大约有300多个. 有兴趣的可以看一下这里 Primitive Tex.由于它非常的底层,所以一般人不会直接用它,而是用在它基础上的各种宏语言.
    • plain TeX: Knuth自己创建的一种建立在Primitive TeX上的宏语言.大约有600多个命令.
    • 我们来看一下用plain TeX所写的Hello World:
      Hello, World
      \bye
    • ConTeX: TeX的另一种宏包.比如这是ConTeX 写的Hello World例子
      \starttext
      Hello, World
      \stoptext
      你可以在http://live.contextgarden.net/尝试在线编译ConTeX文件
    • LaTeX: TeX的最为著名的一种宏包. LaTeX也是大有来头,它是由Leslie Lamport最初弄出来的.对于一般使用者,它比Knuth自己的plain TeX更加直观方便.版面配置的工作被相当大程度的减轻了,使用者可以更加专注在内容上.因此大获流行,比如很多(还是大多?)学术期刊或者会议都会prefer你用LaTeX来排版提交文稿.
      既然是宏语言,就实际上可以被替换成TeX可以理解的命令.同时你也可以在LaTeX文档中使用Primitive TeX的命令.LaTeX宏的格式定义在latex.fmt这个文件当中.遗憾的是它是一个二进制文件,无法直接阅读. 但是幸运的是我们可以从latex.ltx这个文件中看到我们所熟知的各种环境,比如tabular eqnarray等等.实际上latex.fmt正是从latex.ltx编译而来.
      LaTeX定义的标准命令标准环境
      我们再来看一下用LaTeX写的Hello World程序.
      \documentclass{article}
      \begin{document}
      Hello, World
      \end{document}
    • LaTeX distribution:为了用LaTeX来排版,你需要一系列工具,包括(1)编辑器(比如我用过vi, WinEdt, editplus, textwrangler,gedit,现在主要用emacs)(2)dvi浏览器(或者pdf浏览器)(3)最重要的:一套LaTeX发行.一个LaTeX发行通常要包括如下的程序:
      • tex: 把TeX 文件编译成DVI文件
      • pdftex: 把TeX 文件编译成PDF文件
      • latex: 最常用, 把LaTeX文件编译成DVI文件
      • pdflatex: 把LaTeX编译成PDF文件
      • dvi2ps: 把DVI文件转成PostScript文件
      • dvipdf: 把DVI文件转成PDF文件
      • dvipdfm: dvipdf的改进版本
    • TeX live: LaTeX的一个跨平台的发行版, Win,Mac,Linux等主要平台上都有.
    • MiKTeX: LaTeX在Windows平台上的发行版.在中国大家使用非常广泛的CTeX套装里就使用的是MiKTeX.

    Tuesday, June 16, 2009

    [Latex]Latex Cheating Sheet

    常用环境
    *一个空文档模板:

    \documentclass[10pt,a4paper]{article}
    \usepackage{graphicx}
    \title{Empty Article}
    \author{apc999}
    \date{\today}
    \begin{document}
    \maketitle
    Put your text here
    \end{document}
    


    *改变文档边距
    在tex文档头部引用geometry宏包并加入边距参数:
    \usepackage[top=1.0cm,right=0.5cm,bottom=1.0cm,left=0.5cm]{geometry}


    *插入数学公式
    \begin{eqnarray}
    E=MC^2
    \label{eq:relativity}
    \end{eqnarray}


    *插入图片
    首先需要在tex文档头部引用graphicx这个宏包
    \usepackage{graphicx}
    在需要插入图片的地方:
    \begin{figure}[h]
    \centering
    \includegraphics[width=0.8\textwidth]{foo.eps}
    \caption{caption of figure foo}
    \label{fig:foo}
    \end{figure}


    *插入子图
    首先需要在tex文档头部引用subfigure这个宏包
    \usepackage{subfigure}
    然后在你需要插入图片的地方:
    \begin{figure}
    \centering
    \subfigure[caption of foo]{
    \label{fig:subfigure:foo}
    \includegraphics[width=0.48\textwidth]{foo.eps}}\hfill
    \subfigure[caption of bar]{
    \label{fig:subfigure:bar}
    \includegraphics[width=0.48\textwidth]{bar.eps}}
    \caption{caption of subfigures foo and bar}
    \label{fig:subfigure}
    \end{figure}
    
    ** subfig包用法与subfigure基本一样,就是把\subfigure换成\subfloat
     **小的"花招":子图之间可以用\vline加一条竖线隔开,或者用\hfill,\hspace等命令控制间隔

    *插入表格
    \centering
    \begin{table}[h]
    \begin{tabular}{ll}
    x & x \\
    x & x
    \end{tabular}
    \caption{caption of table foo}
    \label{tab:foo}
    \end{table}
    
    更多table的用法

    *数学环境中大括号
    \begin{eqnarray*}
    y = \left\{ \begin{array}{ll}
    a & \textrm{if $d>c$}\\
    b+x & \textrm{in the morning}\\
    l & \textrm{all day long}
    \end{array} \right.
    \end{eqnarray*}
    
    实际上还有一个更简单的做法--用cases环境. 不过需要amsmath这个package
    \usepackage{amsmath}
    
    \begin{eqnarray*}
    y = \begin{cases}
    a & \textrm{if $d>c$}\\
    b+x & \textrm{in the morning}\\
    l & \textrm{all day long}
    \end{cases}
    \end{eqnarray*}
    


    *贴源代码

    \usepackage[]{listings}
    \lstset{language=Python,tabsize=4}
    \begin{lstlisting}
    import sys
    sys.stdout.write("Hello World")
    \end{lstlisting}

    *引用一段话
    \begin{quote}
    the quoted text
    \end{quote}

    *使用bibtex database file
    \bibliographystyle{xxx} % 使用style文件xxx.bst
    \bibliography{yyy}  %使用reference 数据库文件yyy.bib"
    xxx可以为 IEEE, acm, plain, abbrv等等
    yyy为用户自己定制的bib文件
    参考 BibTeX and bibliography styles


    常用命令
    \appendix: 这个命令本身不产生任何文本, 但是会改变其之后的section的标号
    \hrule 产生一条水平线 http://www.personal.ceu.hu/tex/spacebox.htm
    \gg,\ll 远远大于,远远小于

    Thursday, June 11, 2009

    [Linux]字体配置

    X下有两套字体系统:古老的X11 core font system 以及新的Xft and fontconfig.一般说来我们应该尽可能的使用后者.
    1. Xft是"X FreeType"的缩写。当Xft被使用的时候,字体是由使用这些字体的应用程序来渲染,而不是像在X11 core font system中那样由X server负责渲染.

      在xft中用fontconfig库来决定字体该如何渲染.它包括系统定义的配置/etc/fonts/fonts.conf 以及用户自定义配置~/.fonts.conf.

      如果要自己添加字体,可以把字体文件或目录添加到/usr/local/share/fonts/.网上教程之类的通常是这样做.不过你也可以直接添加到~/fonts/这个路径下,该路径被/etc/fonts/fonts.conf默认的访问.所以你只需要把新添加的字体拷到~/.fonts就好了.比如我就把windows下的C:\WINDOWS\Fontssimsun.ttc以及simshei.ttf文件考到了上述目录下.这样我就可以在linux中使用windows下的宋体,新宋和黑体.

      字体描述:采用如下格式[2]:
      <family>-<size>:<name>=<value>...
      比如
      times-12:bold:slant=italic,oblique

      常用命令:
      • fc-list pattern 显示符合指定条件的可用字体.比如
        "fc-list ":lang=zh-CN" family style weight file"就显示所有系统中可用的简体中文字体的名称,式样,权重以及包含该字体的文件的完全路径.
      • fc-cache option 为fontconfig系统建立字体cache
        "fc-cache -fv"强制(f,force)建立cache(哪怕之前的还up-to-date),v是verbose
    2. X core font system

      字体描述: X logical font description (XLFD)[3][4].
      比如75-dpi, 12-point, Charter font的字体用XLFD格式描述出来便是:
      -bitstream-charter-medium-r-normal--12-120-75-75-p-68-iso8859-1

      常用命令:

      • xfontsel 选定并显示X字体的字符
      • xfd 显示指定X字体的字符
      • xlsfonts 输出匹配给定条件的X字体名称
      • mkfontdir 创建指定(默认当前)目录下X字体索引
      • mkfontscale 创建指定(默认当前)目录下矢量字体索引
    参考
    [1] Installing and Configuring Fonts
    [2] An Xft Tutorial
    [3] X Logical Font Description Conventions
    [4] X logical font description -- wikipedia

    Tuesday, June 09, 2009

    [Latex]支持中文方案2:Xetex

    比较了一下CJK和xetex,这两种最主要的Latex中文解决方案,还是xetex更完美.它可以使用系统中fontconfig支持的中文字体,你可以用
    fc-list :lang=zh
    来查看你当前系统中的中文字体.相比之下,texlive中自带的CJK只能支持区区几种.

    CJK就好比是在Tex基础上为了支持unicode中文而打的补丁,而Xetex则是从根本上就支持unicode.所以应该是更有前途.我觉得可以视xetex为unicode版的tex,而xelatex就是对应着unicode版的latex.使用起来latex的基本语法几乎不用作改动, 你只需要加上若干针对xetex的命令在.tex源文件的前面

    \documentclass{article}
    %需要fontspec这个宏包设置字体
    \usepackage{fontspec}
    %指定文档的字体, 上面fc-list命令列出的中文字体都可以用在底下
    \setmainfont[BoldFont=WenQuanYi Zen Hei]{SimSun}
    %默认字体为SimSun,默认的bold(比如用在section title之类的地方)为文泉译增黑.
    %还可以用\setsansfont, \setmonofont来设置文档的sans 和mono字体.
    
    %针对中文设置下换行
    \XeTeXlinebreaklocale "zh" %使用中文换行
    \XeTeXlinebreakskip = 0pt plus 1pt %
    % OK了,后面就和latex没有两样了
    
    \title{Notes}
    \author{apc999}
    \date{\today}
    \begin{document}
    \maketitle
    \section{中文}
    你好,世界
    \section{数学}
    $$\sum_i x_i$$
    \end{document}

    把上面文件存为helloworld.tex.编译的时候就使用
    xelatex helloworld.tex

    结果如下:

    Xetex在Mac上运行良好.不过在ubuntu 9.04上,我发现Xetex有一个bug.数学环境中的数学符号,比如\sum \alpha无法显示在编译出的pdf文档中.这里是我从网上找到的bug fix:http://www.mail-archive.com/debian-bugs-dist@lists.debian.org/msg631117.html按照这里说的更改以后就好啦!

    Thursday, June 04, 2009

    [Latex]Paper中的作图+Latex相关

    很凌乱的一些东西.在这里做个笔记.
    ====================第一部分 作图. ====================
    作图工具很多,最最基本的包括excel, matlab.就不在这里复述.反正我都不爱用.excel的图太幼齿,matlab太笨拙.这里要提matplotlib以及gnuplot
    (1) matplotlib
    这是python的一个用于科技绘图的库.这个库比较神奇的一点是封装了一系列语法极其类似matlab的绘图函数在pylab这个文件中. 这样只要你安装了matplotlib,在一个python源程序当中import了pylab之后,就可以用诸如plot(X,Y)这样的matlab语法来绘制函数图像.实在是非常方便.
    如果有python 和matlab的基本知识,上手时间几乎为0

    由于图片在Latex文档中编译出来后通常会显得小, 先需要把默认字体增大:
    import pylab
    params = {'backend': 'ps',
    'axes.labelsize': 14,
    'text.fontsize': 10,
    'lines.linewidth':2,
    'legend.fontsize': 16,
    'xtick.labelsize': 14,
    'ytick.labelsize': 14}
    pylab.rcParams.update(params)


    (2) gnuplot
    Unix世界中非常老资格的一个绘图工具.gnuplot的语法简单明了,学习曲线比较平缓.

    gnuplot中有terminal这样一个概念.terminal其实是指输出设备.gnuplot支持接近80种不同的设备(或格式).我们常用的包括x11,png,postscript等等.选择x11的话就可以在X window中显示出我们要绘制的图像;而选择png, postscript的话则是告诉gnuplot你选择png 或者postscript格式的文件作为输出设备. gnuplot允许我们针对不同的输出设备做出统一或者不同的设定. 而且我们可以把设定写在~/.gnuplot当中让每次gnuplot启动的时候自动加载.比如我的设定包括
    set terminal postscript eps enhanced color linewidth 2 font "Helvetica, 20"
    set terminal x11 enhanced font "Helvetica, 15"
    对于输出为eps的文件,我希望它字体大一些,线宽粗一些.通常paper里需要这样设定才能看得清楚.

    绘图的基本用法包括
    画一段sin(x)曲线
    plot sin(x)
    这里x取值范围默认是[-10,10],如果要改变x取值范围
    set xrange [1:10]
    如果要从文件里读入数据,比如用'data.txt'文件中第1列作x第3列作y作图,线段类型为"lines",这个curve取名为data1
    plot 'data.txt' using 1:3 with lines title 'data1', 'data.txt' using 1:3 with lines title 'data2'
    设置xlabel 以及字体(可选)
    set xlabel "time t" font "Arial, 15"
    设置输出文件名, 默认是STDOUT
    set output "data.eps"
    更新/重画
    replot

    (3) ploticus
    一个商用绘图工具,不过好在免费.绘制出来的figure非常精美.但学习曲线非常陡.

    ================第二部分 Latex里插图================
    (1)最基本的用法 无非就是先
    \usepackage{graphicx}

    然后在正文中需要插图的地方,
    \begin{figure}[t]
    \begin{center}
    \showthe\columnwidth % Use this to determine the width of the figure.
    \includegraphics[width=\columnwidth]{fig1.eps}
    \caption{\label{fig:sin_cos} Plot of the sine and cosine functions.}
    \end{center}
    \end{figure}
    如果是pdflatex, 可以支持png等非矢量格式图片

    (2)使用psfrag这个包, 可以在latex文档中对插入的eps图片进行文字替换, 或者字体缩小/放大:
    \begin{figure}[t]
    \begin{center}
    \psfrag{sin(x)}{$\sin(x)$}
    \psfrag{cos(x)}{$\cos(x)$}
    \psfrag{x (radians)}{$x$ (radians)}
    \psfrag{y}{$y$}
    {\footnotesize                  % Replace tick-lables with smaller font.
    \psfrag{1.0}{1.0}
    \psfrag{0.5}{0.5}
    \psfrag{0.0}{0.0}
    \psfrag{-0.5}{-0.5}
    \psfrag{-1.0}{-1.0}
    \psfrag{-8}{-8}
    \psfrag{-6}{-6}
    \psfrag{-4}{-4}
    \psfrag{-2}{-2}
    \psfrag{0}{0}
    \psfrag{2}{2}
    \psfrag{4}{4}
    \psfrag{6}{6}
    \psfrag{8}{8}
    \showthe\columnwidth % Use this to determine the width of the figure.
    \includegraphics[width=\columnwidth]{fig2.eps}
    } % Note that the psfrag commands only work in the top-most environment.
    \caption{\label{fig:sin_cos} Plot of the sine and cosine functions.}
    \end{center}
    \end{figure}

    Friday, May 22, 2009

    [数学]一道关于硬币的概率题

    硬币不知道fair还是不fair,第一次扔是head,第二次让你赌,你赌哪个,概率多少? zz from mitbbs
    SOL: 采用Bayes. 设硬币得到head的概率为p. 因为硬币不一定是fair, 所以这里p实际是一个随机变量. 在没有其他信息的情况下,我们假设p的先验是一个0到1之间的均匀分布,即U[0,1]. 这种情况下, 得到head的概率为:
    P\{head\} = \int_{p=0}^1P{head|p}\mathrm{d}p = \int_{p=0}^1p\mathrm{d}p=\frac{1}{2}

    投掷硬币得到head, 在这种情况下,p的条件概率密度函数f(p|head)就不再是U[0,1]. 这是因为p越大越容易得到head,因此得到head的时候以更大可能观察到比较大的p而不是等概率.f(p|head)的密度由下式求得.注意这里f(p)=1(均匀分布),以及P{head|p} = p.
    f(p|head) =\frac{P\{head|p\}f(p)}{P\{head\}}=2p

    所以给定head情况下,p的点估计:
    \hat{p} = \int_{p=0}^1 2p p\mathrm{d}p = 2/3

    再来一道类似的:6个小孩,3女2男,还有一个性别未知.随机选择6人中的一个,发现是男孩.那么未知的那个小孩是男孩的概率?
    SOL: 假设未知的那个小孩是男孩的概率是p. 假定p=1/2
    选出来的小孩是男孩的概率是
    P{pick a boy}=P{pick a boy|unknown=boy}P{unknown=boy}+P{pick a boy|unknown=girl}P{unknown=girl}
    =3/6*1/2+2/6*1/2=5/12


    P{unknown=boy|pick=boy} = P{pick=boy|unknown=boy}P{unknown=boy}/P{pick a boy}=3/5

    Thursday, May 21, 2009

    [Latex]支持中文方案1:CJK

    update @ 2009/6/9:经过比较我还是觉得用xetex来支持中文更加简单.可以见本blog中的:Xetex起步
    决定写一些中文文档,所以要装Latex的中文支持。在ubuntu上很简单:
    我已经安装过了 texlive-full (没有的请先安装),所以就只需要从源里安装latex-cjk-chinese(只针对中文,如果你还需要日文韩文,请安装latex-cjk-all)。
    然后就可以试一下中文的latex文档了。
    记住用
    \begin{CJK}{编码种类}{字体种类}
    \end{CJK}
    把用到中文的地方包围起来就可以了。这里CJK环境可以换成CJK*环境,区别是CJK环境里中英文间会有空格而CJK*没有。编码种类可以是GB,Big5 也可以是UTF8,取决于你自己的locale设定。我是用的纯英文环境,所以都上的是UTF8。默认情况下字体种类选择不多,可以是gbsn(gb宋体),gkai(gb楷体),bsmi(big5宋体),bkai(big5楷体)
    可以实验一下这个文档:
    \documentclass{article}
    \usepackage{CJK}
    \begin{document}
    \begin{CJK*}{UTF8}{gbsn}
    您好!
    \end{CJK*}
    \end{document}
    

    Thursday, May 14, 2009

    [数学]一道小学应用题

    近日,网友“跳水白菜”在天涯重庆上发帖,希望借网友的智慧,解答出一道小学六年级的数学题。

    “一辆大客车和大货车分别从甲乙两地出发,经过7个小时相遇,然后仍按各自的速度前行,3小时后,大客车距乙地120公里,大货车距甲地 160公里,求甲、乙两地的距离是多少千米?”

    解答出这样一道数学题,在最初回答问题的网友看来,似乎是一件很简单的事情。众多网友都给出了步骤和答案,但大多都采用了2元1次方程式,甚至3元1次方程式。有网友提出了尖锐的问题:小学生是没有学习过2元1次方程式的,更别谈3元1次方程式,这样的题目就不能使用这种方式解答。面对这样的题目,其内容和解答方式雷翻了众多的网友。

    SOL:其实这道题不需要用到方程.我从小就喜欢把那些看似要用解方程才能做出来的题目硬是分步计算出来.这里给出这道题目的分步计算方法:
    甲乙两地距离=甲速*7+乙速*7,同时又有 甲乙两地距离=甲速*3+乙速*3+120+160
    我们可以得知 (甲速+乙速)*4 = 280 => 甲速+乙速 = 70 (公里/小时)
    甲乙两地距离=70*7 = 490 (公里)

    Wednesday, May 13, 2009

    [算法]拳皇友谊赛

    这两天看到的一道蛮好玩的题:
    变态的比赛规则:为了促进各部门员工的交流,百度(baidu)举办了一场全公司范围内的"拳皇友谊赛",负责组织这场比赛的是百度的超级"拳皇"迷W.Z. W.Z不想用传统的淘汰赛或者循环赛的方式,而是自己制定了一个比赛规则。

    由于一些员工(比如同部门或者相临部门员工)平时接触的机会比较多,为了促进不同部门之间的交流,W.Z希望员工自己组成不同组。不同组之间的每两个人都会进行一场友谊赛而同一组内的人则之间不会打任何比赛。

    比如4个人,编号为1--4,如果分为两个组并且1,2一个组,3,4一个组,那么一共需要打四场比赛:1 vs 3,1 vs 4,2 vs 3,2 vs 4. 而如果是1,2,3一组,4单独一组,那么一共需要打三场比赛: 1 vs 4,2 vs 4,3 vs 4.

    很快W.Z意识到,这样的比赛规则可能会让比赛的场数非常多。W.Z想知道如果有N个人,通过上面这种比赛规则,总比赛场数有可能为K场吗?比如3个人,如果只分到一组则不需要比赛,如果分到两组则需要2场比赛,如果分为三组则需要3场比赛。但是无论怎么分都不可能只需要1场比赛。

    相信作为编程高手的你一定知道该怎么回答这个问题了吧? 那么现在请你帮助W.Z吧。

    输入
    每行为一组数据,包含两个数字 N, K

    输出
    对输入的N,K 如果N个员工通过一定的分组方式可能会一共需要K场比赛,则输出"YES",否则
    输出"NO",每组数据占一行。所有的输入输出均为标准输入输出。

    SOL:这道题是一道潜伏很深的动态规划。先建一下模:N个人,如果分成m组,每组x_i人,那么需要打的比赛场数是
    \sum_{i\neq j} x_ix_j
    。所以本题就是给定N,看是否能找到一个组人数划分使得上式等于K。

    做一下变化:
    K=\sum_{i\neq j} x_ix_j = \frac{(x_1+\ldots+x_m)^2-\sum_ix_i^2}{2}=\frac{N^2-\sum_ix_i^2}{2}

    所以这里我们把这道题变成了如何找到m个数使得这m个数的和等于N,平方和等于N^2-2K。

    令T(s)为所有"平方和为s的一组数的和"的集合,即:
    T(s)=\{x_1+\dots+x_m|\forall \sum_ix^2_i=s\}

    所以T(5)={3,5},也就是说5可以分解为1+1+1+1+1也可以分解为1+2^2。
    关于T(s)的递推式为

    T(s)=\left\{\begin{array}{ll}
    (\bigcup_{i=1}^{s/2} (\{t\} \cup T(i))\odot T(s-i)) & i=t^2\\
    \bigcup_{i=1}^{s/2} T(i)\odot T(s-i) & \textrm{otherwise}
    \end{array}
    \right.

    这里定义

    A\odot B = \{ a+b | \forall a\in A, b\in B\}

    边界条件: T(1)={1}

    Friday, May 08, 2009

    [算法]找树的重心

    以前算法课作业做过这道题。今天在网上又碰到了。

    给一个有n个结点的树,每个节点i都有一个正权重w(i),每条边j也有一个正权重c(j). 要求给出一个线性复杂度的算法,找出一个结点u,使得对其他所有结点i,w(i)*L(i)的总和最小,其中,L(i)为i到u路径上的所有边的权重和.

    SOL: 本题贪心就足够了。记sumW为树上所有节点权重和(仅仅节点)以及WC_i[p]为以p为根的第i颗子树中所有节点权值和(仅仅节点)。如果P是重心,则 "sumW>2*WC_i[p]" 对于所有P的子树i成立--所有子树的权重都小于所有节点权重和的一半。为了找到满足这个条件的节点 用贪心就足够了。随便从一个节点开始,看到哪个子树的权重和超过所有节点权重和一半,就往那个子树移动。直到不能移动位置为止。

    Thursday, May 07, 2009

    [Linux]抛弃scim投奔ibus输入法啦

    网上面对于ubuntu大多数人推荐使用scim输入法。我一直用的就是scim-python。无奈它兼容性还是有问题,qt程序底下总是没法用热键切换。最近我的pidgin也老和它冲突。于是上网一搜,发现进来新的ibus输入法很流行。是scim-python的原作者写的。于是就去装了一个下来。对于ubuntu用户,步骤很简单。直接apt-get install ibus就可以了。好像官方源里暂时还没有ibus,我是添加了ppa的源。步骤可以参见这里

    除去ibus这个平台,还需要安装具体的输入法。比如我安装了ibus-pinyin 也就是拼音。还有ibus-table包括了五笔等输入法。由于我是gnome的桌面,还安装了ibus-gtk这个库,后面要用到。

    然后就用im-switch -s ibus把输入法设置为ibus。没有im-switch的可以装一下,这样比较干净。不用再去profile里设置环境变量。然后重启看一下效果吧。这个ibus用起来很舒服, 有种在windows底下用google输入法的感觉。


    另外我是emacs用户,所以一般都把默认的切换热键ctrl+space换成alt+shift。可以在ibus的preference里设置。需要注意的是alt+shift要加上release(键松开)的修饰,不然不行, 不知道为什么。

    Tuesday, April 28, 2009

    [算法]最近看到的几道有意思的题

    1 某机器需要处理n个请求,每个请求都有其运行所需的存储空间(R[i])及运行之后输出所占用的存储空间(O[i]),且O[i]小于r[i]。假设CPU只能同时处理一个请求。现在该机器共有m个存储空间,请设计一个算法来安排这n个请求的处理顺序,使得所有请求都能被处理。并简要说明该算法的正确性。如果无论如何安排也不能处理完这些请求,算法也应能给出判断。SOL: 贪心法, 按照R[i]-O[i]降序排列请求

    2 在一个空间里有m(m为偶数)只老虎,n只兔子,还有一个你,总共m+n+1只东西(什么,你说你不是东西?)每次随机地抽出两只东西发生互动(通常造成可怕的结果),幸存者再放回去。具体规则如下:
    1)老虎和老虎->两相残杀
    2)老虎和兔子->老虎吃掉兔子
    3)兔子和兔子->没事
    4)老虎和你->你成为老虎的美餐
    5)你和兔子->你可以选择放回去或煮了兔子
    问题是:最后你虎口余生(即,出现山中无老虎,猴子称大王的局面)的概率是多少(你需要在兔子问题上作出最优决策使此概率最大)
    SOL: 1/(m+1) 本题最大的trick在于认识到兔子的存在其实根本不影响最后结果,可以直接忽略所有的兔子。剩下m只老虎和一个你。所求概率相当于你排在最后一位的概率。

    3 16个人背后各贴一个数字,每个数字都可能取1到16的任意整数值(即可以重复,可以有数字不出现),每个人可以看到其他人的数字,但看不到自己的,贴好数字之后不可以进行任何形式的交流(诸如使用排队次序传达信息之类的伎俩无效),每人猜一个数字,问事先如何安排可以保证至少有一人猜中自己的数字。
    SOL: 16个人每个人分别猜自己背后的数字,也就是16个人分别猜16个1-16的数字,显然无法保证一定一人猜中。但是如果16个人集中猜同一个1-16的数字X则能保证一定有一个人猜中, 方法是每一个人分别猜一个数,遍历解空间。这里我们这样人为制造出X:X = X1 xor X2 xor X3... xor X16 (X_i是第i个人背后数字).所以这个X对于所有人是一样的.于是可以第i个人可以猜测一个数Yi,这个数Yi满足和其他所有能看见的人背后的数字的xor之和为i.

    Wednesday, April 15, 2009

    [Emacs]调整字体

    update @ 2009/6/09
    对于最新的emacs 23版本,字体描述格式,已经从X Logical Font Description (XLFD)转变为更为简单的fontconfig方式.关于两种字体系统,可以参见本blog里这个帖子.不过为了向前兼容,XLFD依然被支持.比如同是描述13pt的Courier New字体,两种格式分别如下:
    •      XLFD: -*-Courier New-normal-r-*-*-13-*-*-*-c-*-iso8859-1
    •      Fontconfig: Courier New-13
    在emacs 23里,set-default-font已经过时.实际如果在.emacs中使用了set-default-font,普通模式下emacs字体依然正确.但是如果是用daemon模式运行emacs23的client时候, client会不正常的设置字体.解决方法是在set-frame-font,或是使用default-frame-alist来添加字体, 如下
    (add-to-list 'default-frame-alist '(font . "DejaVu Sans Mono-14"))
    这样普通和daemon模式就都可以正确设置字体了.
    对于emacs22以及更早版本的字体设置如下:
    -------------------------------------------------------------------------------
    说实话emacs里要调整个字体什么的还真挺麻烦的。一般的基于GUI的editor都比它来的简单直接。

    1 关于Linux下的字体
    使用xlsfonts来查看系统里有哪些字体
    $xlsfonts
    得到像如下格式的输出
    -adobe-courier-medium-r-normal--17-120-100-100-m-100-iso8859-1
    -dejavu-dejavu sans mono-medium-r-normal--0-0-0-0-c-0-iso8859-1
    每一行都是一种系统支持的字体。每一行的格式参见 Font specification , 简单说来遵循“-maker-family-weight-slant-widthtype-style-pixels-height-horiz-vert-spacing-width-registry-encoding"这样的格式。需要特别指出的是pixels代表的是字体的高度(单位是像素),height代表的是字体在屏幕上的高度*10(单位是磅), pixels和height两个当中通常只指定一个值,另一个用*代替。另外我们注意到列出来的字体当中有些字段为0,这说明这些字体是矢量字体。对于这些字段我们使用的时候需要用数字或者*来替换。

    可以通过xfd来预览你想尝试的字体, 比如
    $xfd -fn "-dejavu-dejavu sans mono-medium-r-normal--16-*-*-*-c-*-iso8859-1"   


    2 回到Emacs
    可以通过M-x set-default-font 然后输入字体名称(如果不知道可以用tab来complete)来设置当前字体。如果需要固定下来,可以在~/.emacs当中加入:
    (set-default-font "-dejavu-dejavu sans mono-medium-r-normal--16-*-*-*-m-*-iso8859-1")

    需要额外指出的是,这里我设置成了dejavu的等宽字体。不过我发现使用了这种字体以后,line spacing显得过大了,所以可以用以下语句来调整:
    (setq-default line-spacing 0)
    另外我这里的emacs有一点小bug所以set-default-font以后会有好几秒钟的延迟,需要在~/.emacs开头加入
    (modify-frame-parameters nil '((wait-for-wm . nil)))


    3 几个字体设置的小tip
    • M-x describe-char 我们可以使用这个命令查看光标所在的字符采用的是什么字体。
    • M-x describe-fontset 这个命令用来查看各个字符集分别采用了什么字体。
    • 在*scratch* buffer中输入(frame-parameter nil 'font) 光标放在行末按C-x C-e就可以看到当前字体
    • Shift + MouseLeftClick可以出来字体选择对话框;
    • M-x describe-font可以查看当前字体描述
    • M-x set-default-font 可以看到可以选择的字体。
    参考:
    [1] http://www.linuxquestions.org/questions/linux-software-2/emacs-changing-default-font-size-and-font-type-489000/
    [2] http://www.yuanma.org/data/2006/0503/article_355.htm
    [3] http://www.gnu.org/software/emacs/windows/Fonts-and-text-translation.html

    Sunday, April 12, 2009

    [Python] Yaml与Json

    Python2.6开始支持Json,见Json库
    Yaml的Python库见PyYaml

    简单说起来:
    1. Python的json库在默认设置下输出的是Yaml语言的子集
    2. 两个库的语法基本一致。不同的是yaml的dump输出的直接为字符串,json的dump还需要指定一个stream object。如果要输出为字符串,得使用dumps

    关于两者详细的关系和区别,这里有一片英文的文章讨论yaml与json的关系

    Saturday, April 11, 2009

    [MacOS] MacOS系统使用经验笔记

    1. 在Finder中找隐藏目录的热键: shift+command+G。默认的finder界面里是不会显示隐藏目录的。所以用上述热键然后手动输入路径
    2. MacOS X中设置环境变量和普通Unix/Linux的方法略有不同。你依然可以像在Unix/Linux 中那样在~/.cshrc(tcsh)或者~/.bashrc(bash)里设置环境变量,对于terminal中的程序完全没有问题。但是对于基于Carbon或者Cocoa的Native Mac程序(比如Carbon Emacs)来说是没有用的。它们不会从shell中继承环境变量。一个方法是把$PATH, $PYTHONPATH等环境变量设置在~/.MacOSX/environment.plist这里。可以用(a) "/Developer/Applications/Utilities/Property List Editor.app"这个工具修改. 也可以(b) 用defaults 命令:
      defaults write ${HOME}/.MacOSX/environment PATH "${HOME}/bin:/usr/bin:/bin:/usr/local/bin"

      为了在系统中使用统一的设置,在~/.cshrc中, 使用如下命令:
      setenv PATH `defaults read ~/.MacOSX/environment PATH` 


      注意: 需要重启以使改变生效
      Updated on Aug 27, 2012: ~/.MacOSX/environment.plist 已经deprecated了. 新的方法是修改/etc/launchd.conf使得所有Unix 环境变量在GUI中可见 参考Accessing the Unix environment from emacs and Cocoa apps in OS X Mountain Lion
    3. 显示Mac里系统相关信息
      查看总体的系统信息
      $ system_profiler
      查看CPU信息
      $ sysctl -a machdep.cpu
      或者
      $ sysctl -n machdep.cpu.brand_string
      Intel(R) Core(TM) i5-2435M CPU @ 2.40GHz
    4. 如果从打开Terminal开始到出现提示符为止的等待时间过长, osxdaily说这是由于系统的login process会读取/private/var/log/asl下所有的系统日志文件.所以我们可以把这些日志删除来加速login过程
      sudo rm -rf /private/var/log/asl/*.asl
    5. 用命令行打印文件
      $ lpstat -a
      GHC6107_BW accepting requests since Sun Oct 28 15:30:42 2012
      GHC9206_BW accepting requests since Mon Oct 29 12:48:11 2012
      GHC9206_COLOR accepting requests since Mon Nov 28 13:00:02 2011
      
      $ lp -d "GHC9206_BW" -o sides=two-sided-long-edge *.pdf
      request id is GHC9206_BW-82 (6 file(s))
    6. 在Lion以及Mountain Lion中关掉ipv6
      $ networksetup -setv6off ethernet
      $ networksetup -setv6off wi-fi

    Saturday, March 28, 2009

    [算法]几个有趣的关于数列的O(1)空间O(n)时间小算法

    1 数列L中有n个整数。其中有k个数字出现了两次,1个数字出现了一次(所以n=2k+1)。找出只出现一次的那个数字。
    解: 将n个数字xor以后,重复出现的就会消失。剩下的就是只出现一次的。

    2 数列L中有n个数。已知其中有一个数字出现了至少 n/2+1次。找出这个数字。
    解: 用链表存储这n个数字。p指向当前考察的数字。p从链表头开始。如果p和p->next的数字相同,p=p->next,如果不同,则将p和p->next一同从链表中删除。当p->next是链表尾的时候,p就是所求数字。

    3 数列L中有n=2k个数字a1,a2,...,an,b1,b2,...,bn。将其变换为a1,b1,a2,b2,...,an,bn。可以将这个问题理解为扑克里的洗牌。
    解: 很难的题目。这里有一篇论文http://webhome.cs.uvic.ca/~jellis/perfect.html。

    Wednesday, March 11, 2009

    [Linux]Wine的一点使用经验

    因为实在受不了Adacious的频繁出问题而分外想念win下的foobar,我装了wine。现在wine加上foobar运行的非常良好。下面记一下安装和使用wine的时候的一些问题。

    安装

    ubuntu上很简单:
    apt-get install wine

    中文支持

    安装了wine以后,在~/.wine底下会有一个driver_c目录,这里是wine心目中的C盘。你可以之后再映射过来正真的D盘阿E盘阿,但这个C盘无法改变(至少我是没找到)。在这个driver_c目录下, 有一个windows/font 目录。可是刚刚装完的时候这里是空的。你可以把你喜欢的windows字体拷过来或是做上符号连接,比如重要的英文字体tahoma.ttf 以及重要的中文字体simsun.ttf。然后键入"wine regedit"调用wine的注册表,修改[HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\FontSubstitutes]。把MS Shell Dlg 以及MS Shell Dlg2的键值由默认的tahoma改为simsun,这样就可以正确的显示中文了

    程序中字体过小

    这是由于dpi值设置的不够大。可以选择在winecfg的Graphics标签里调整dpi值大小(默认是96)。或者继续wine regedit修改[HKEY_CURRENT_CONFIG\Software\Fonts]里的LogPixels键值。LogPixels默认是60(十六进制,也就是十进制的96)。比如我就调整到了120。这样程序里的对话框以及文件选择框之类的的字就足够大了。

    菜单/状态栏/消息框中的字体依然过小

    调整过dpi之后,有可能发现程序里的字是大了,但是菜单之类的字体还是很小。这个问题我google了很久 "Wine", "MenuFont","tiny"之类,看到一些人问但是都没有答案。早先版本的wine可以通过设置win.ini里MenuFontSize等来解决。但新版本的不可以。下午参考着wine源码搞定了这个问题。原来wine会从注册表当中直接读取MenuFont/StatusFont/MessageFont信息。比如MenuFont信息既包括了字体也包括了大小。这几个键值在"[HKEY_CURRENT_USER\Control Panel\Desktop\WindowMetrics"]。但是是用二进制的形式存储的。所以你在user.reg当中可以找到"MenuFont"=hex:f5,ff,ff,ff...这样的字串。如果需要把字体调大,可以把第一个f5弄小一点,比如我调到f2就很好了。

    Wednesday, February 18, 2009

    [Python]可变长参数

    Python支持可变长参数,函数参数中形如*arg这样的就是可变长参数。如果定义了def func(*arg),则可以让接受不同个数的函数,比如func()以及 func("hello", "world")均为合法的函数调用。

    下面这个例子用可变长参数调用func并将可变长参数*arg传递给func。比如test(sleep, 1)就相当于 sleep(1);test(max, 1, -1)就相当于调用max(1,-1)。
    def test(func, *args, **kargs):
        if not callable(func):
            raise RuntimeError, str(func) + ' not a callable object'
        else:
            func(*args, **kargs)

    [Python]Python线程简例

    第一部分:最简单的用法


    Python提供了非常简单的线程用法。最简单的用法只要遵循下面几步:
    1. 定义一个类(比如下面例子里的Job)继承threading.Thread
    2. 在该类中必须实现__init__(初始化)以及run函数(该线程需要执行的代码).注意在__init__当中要调用Thread.__init__。其他成员函数和变量可以自己根据需要添加。
    3. 用start函数启动线程。
    4. (可选)用join函数来阻塞线程直至线程结束。

    若不理解join的作用,可以看如下例子:
    import os
    import time
    from threading import Thread
    class Job(Thread):
    def __init__(self, cmd):
    Thread.__init__(self)
    self.cmd = cmd
    self.starttime = time.time()
    def run(self):
    os.popen(self.cmd)
    print "time %.2fs, job %s is done"%(time.time()-self.starttime,self.cmd)
    jobs = []
    for i in range(1, 5):
    j = Job("sleep %d"%i)
    jobs.append(j)
    j.start()
    for j in jobs:
    j.join()
    print "time %.2fs, job %s returned"%(time.time() - j.starttime, j.cmd)

    运行得到结果:
    time 1.00s, job sleep 1 is done
    time 1.00s, job sleep 1 returned
    time 2.00s, job sleep 2 is done
    time 2.00s, job sleep 2 returned
    time 3.00s, job sleep 3 is done
    time 3.00s, job sleep 3 returned
    time 4.00s, job sleep 4 is done
    time 4.00s, job sleep 4 returned

    如果我们把最后一个循环的顺序该一下,变成倒叙(如下),其余部分不变
    for j in reversed(jobs):
    j.join()
    print "time %.2fs, job %s returned"%(time.time() - j.starttime, j.cmd)
    得到结果:
    time 1.00s, job sleep 1 is done
    time 2.00s, job sleep 2 is done
    time 3.00s, job sleep 3 is done
    time 4.00s, job sleep 4 is done
    time 4.00s, job sleep 4 returned
    time 4.01s, job sleep 3 returned
    time 4.01s, job sleep 2 returned
    time 4.01s, job sleep 1 returned
    所以当你调用join时,仅仅是检查该线程是否以及结束。如果结束则返回;否则阻塞直至结束。
    再来作一点变换, 对join加上参数timeout。 timeout指定调用join后多久停止阻塞。如果没有指定该参数(就像我们前面做得这样),则一直阻塞到线程结束:
    for j in reversed(jobs):
    j.join(0.5)
    print "time %.2fs, job %s returned"%(time.time() - j.starttime, j.cmd)

    我们得到
    time 0.52s, job sleep 1 returned
    time 1.00s, job sleep 1 is done
    time 1.02s, job sleep 2 returned
    time 1.52s, job sleep 3 returned
    time 2.00s, job sleep 2 is done
    time 2.02s, job sleep 4 returned
    time 3.00s, job sleep 3 is done
    time 4.00s, job sleep 4 is done

    第二部分: 一个例子

    在这个例子里面,我们使用指定数目个线程来完成一批任务。就好比1000个矿要采,但我们就只用9个农民轮流去采。

    在这个例子里我们定义了一个Jobs类(乔布斯?)和一个Worker类。Jobs类通过继承Queue来维护一个任务队列。如果要添加新任务,就调用newjob。newjob函数的参数决定了一个任务:它们包括一个名字(name),一个函数入口(func)以及相应的参数(args,kargs)。每个Worker类的实例对应一个线程,当线程开始执行或者idle的时候,就从任务队列中取一个任务,并执行这个任务。完成之后再接着做下一个,周而复始直至所有任务完成(任务队列为空)。
    class Jobs(Queue.Queue):
    def __init__(self):
    Queue.Queue.__init__(self)
    def newjob(self, name, func, *args, **kargs):
    if not callable(func):
    raise RuntimeError, str(func) + ' not a callable object'
    self.put((name, func, args, kargs))
    def do(self, numthreads = 1, debug = True):
    threads = []
    for i in range(numthreads):
    t = Worker("thread%d"%i, self, debug)
    threads.append(t)
    t.start()
    for t in threads:
    t.join()

    class Worker(threading.Thread):
    def __init__(self, name, jobs, debug = False):
    threading.Thread.__init__(self)
    self.name = name
    self.jobs = jobs
    self.debug = debug
    def run(self):
    while not self.jobs.empty():
    try:
    job = self.jobs.get(True, 1)
    (name, func, args, kargs) = job
    except:
    break
    stime = time()
    func(*args, **kargs)
    if self.debug:
    print "%s is done by %s, fin in %.2f s"%(name, self.name, time()-stime

    Wednesday, February 11, 2009

    [Python] Python中的类型与对象

    读了一篇文章Python Types and Objects探讨Python当中的类型与对象。要说这篇文章也算是写的不错,图文并茂的。可是我还是看的迷迷糊糊的。于是又多花了一些时间搞清Python里的关系。

    一切都是对象

    先从简单的说起
    >>>mylist = [1,2,3]
    >>>type(mylist)
    <type 'list'>
    所以这里我们新建了一个list的实例叫mylist。通过内建的type()函数我们可以查看这个实例的类型,返回的结果告诉我们它的类型是list这种内建的类型。
    >>>type(list)
    <type 'type'>
    >>>list.__bases__
    (<type 'object'>,)
    这里我们先查看了list的类型。我们得知list的类型是type,换言之list是type的一个实例。紧接着我们用__bases__属性查看它的父类,得知list其实继承了内建的object。再来
    >>>type(type)
    <type 'type'>
    >>>type.__bases__
    (<type 'object'>,)
    好,现在我们知道type的类型还是type自己,它是自己的一个实例,同时它继承了object。最后:
    >>>type(object)
    <type 'type'>
    >>>type.__bases__
    ()
    从而我们得知,object也是type的一个实例,同时它没有父类。

    总结一下目前的结论:
    • Python当中任何东西都是对象,它都要对应一个类型
    • 为了表达这个类型,Python仍然使用了对象。所以int, list这些类型同时也都是对象。比方你可以用id(int),id(list)得到这些类型的id(其实是这些对象的内存地址)
    • 为了得到统一的解释(每个对象都对应一个类型),便赋予int, list对象以一个type类型。type自己也是一个对象
    • type的类型是自己,这个游戏从而可以结束了。
    • object也是一种类型,可以类比于int, list。但是由于每样东西都是对象,所以int, list, type这些抽象的类型落实到instance以后又都是object派生出来的。
    class 和 type 的统一

    在Python2.2之前,class和type是阳关道和独木桥,互不相干。这种class也被称为老式类(old-style class)。从Python2.2之后开始,class可以被认为是一种用户自定义的类型,也被称为新式类(new-style class)。从地位上来说和list或者dict等类型一样。为兼容起见老式类依然被保留,并认为是一个类默认的类型。如果你要定义一个新式类,该类必须继承object,或者继承一个其他新式类。(注:Python3.0以后将不再支持老式类)

    现在让我们作一下实验,分别定义一个老式类 oldclass和一个新式类 newclass:
    >>>class oldclass:
    ...    def __init__(self):
    ...        pass
    >>>class newclass(object):
    ...    def __init__(self):
    ...        pass

    检验一下:
    >>>oldobj = oldclass()
    >>>newobj = newclass()
    >>>print type(oldobj), oldobj.__class__
    <type 'instance'> <class __main__.oldclass at 0x7f700714da10>
    >>>print type(newobj), newobj.__class__
    <class '__main__.newclass'> <class '__main__.newclass'>

    这里我们可以看到新式类的类型和__class__是统一的。再来检验一下内建的dict:
    >>>print type(dict), dict.__class__
    <type 'type'> <type 'type'>
    我们看到同样的结论。

    本文参考:
    Python Types and Objects
    Data Model

    Tuesday, February 10, 2009

    [Python] CPython1.01源代码阅读笔记(1)

    (未完结)
    简介
    CPython是官方的、使用最广的Python解释器。因为使用C语言实现而得名CPython。非官方的Python解释器还包括JPython(用Java实现)以及PyPy(用Python本身实现)。

    关于CPython源码的阅读,网上我见到相关文章有:
    这两篇侧重点各有不同。前者偏重CPython的词法语法分析,后者偏重解释器的执行机理。我的笔记会和前者重合度较高。事实上我也是参考着前者来的,有部分他略过或是简单提及的地方可能我这里会详细处理。

    CPython 1.01是其官方网站上我能找到的最早的版本。这个版本应该是1994年左右release的。所以还是相当初期的时候,规模比较小,便于学习。
    解压后我们可以看见它的目录结构包括:
    Include/ C源代码的头文件(.h)
    Lib/用Python自己写的Python库文件(.py)
    Python/这里是"编译器"和解释器的源码,Python的核心所在
    Grammar/包括一个Grammar文件,用BNF描述Python语言语法
    Parser/生成pgen这个工具使用Grammar文件

    一个编译器运作,必然离不开词法分析和语法分析,所以我们也从这里入手。
    词法分析:
    所谓词法分析是指将输入的字符流转变为token流。CPython中的token类型被定义在Include/token.h中。比如NAME就是一个token,它对应着关键字以及标识符。"a = b + 10"这个字符流对应的token流为"NAME EQUAL NAME PLUS NUMBER"。

    从字符流到token流的转换在Python/tokenizer.c中完成。tokenizer的核心数据结构是tok_state。它的作用是记录当前tokenizer的状态,比如当前输入缓冲区的起始位置(buf)和终止位置(end)以及当前读取到的字符指针(cur)。

    如果将tok_state看成tokenizer的成员变量们,你会看到tokenizer.c中还定义了下面这些tokenizer的成员函数:
    • tok_new: 创建并返回一个tokenizer实例tok,下面提到的tok都是该tokenizer的实例,可以看成是一个全局的变量。
    • tok_setups(str): 调用tok_new并将返回的tok绑定到一个字符串上。
    • tok_setupf(f): 调用tok_new并将返回的tok绑定到一个文件上(可以是标准输入stdin,以便互交模式)。
    • tok_free(tok): 将tok这个tokenizer实例释放。
    • tok_nextc(tok): 从tok绑定的输入中读取下一个字符并返回。
    • tok_backup(tok, c): 将c放回tok绑定的输入中(tok->cur--)
    • tok_1char(c): 根据单个字符c返回token,比如"<"返回 LESS

    • tok_2char(c1,c2): 根据连续两个字符c1, c2返回token, 比如 "<="返回LESSEQUAL

    • tok_get(tok, p_start, p_end): 根据tok->cur的返回输入的字符流当前位置的token,以供语法分析。

    • tok_dump(int type, char* start, char* end): 打印输出从start到end (均为字符指针)且类型为type的token,以供调试使用。
    这些tok开头的函数当中,真正重要的其实就是tok_get--读取当前token。它会在语法分析中反复被调用。 语法分析: Python的语法分析需要借助Parser/目录下pgen这个工具。据Guido老师自己回忆,从Python release到现在,这个pgen是改动最小的部分了。这部分在我看来实现的很精彩。 先说一下python语法分析的基本原理。pgen实现了一个LL(1)的Parser。pgen的输入对象是Grammar/目录下的Grammar文件。 我们可以看一下Grammar文件里到底是如何定义Python语法的。比如其中最重要的几行包括:
    stmt: simple_stmt | compound_stmt
    simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
    small_stmt: expr_stmt | print_stmt  | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | access_stmt | exec_stmt
    compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
    它表示每个stmt可以是一个simple_stmt也可以是一个compound_stmt。simple_stmt可以是几个small_stmt的同行并列用";"隔开。 small_stmt可以是expr_stmt, print_stmt, del_stmt等简单语句。而compound_stmt则包括if_stmt, while_stmt等需要跨越多行的复合语句。就这样Python用BNF范式定义了最基本的语法。 现在我们有了这个通俗易懂的Grammar文件以后,pgen负责把这个Grammar转换成NFA,然后再转换为相应的DFA,接着再化简这个DFA,最后保存在gramint.c 和gramint.h这两个文件中。如果你觉得很复杂,你只需要记住我们根据Grammar这个文件得到了一个语法规则就可以了。我们现在来看一下一个py交互模式的运作流程以便于理解:
    1. 在pythonmain.c 的realmain()函数中,执行run(stdin, "")
    2. 进入pythonrun.c的run(fp,filename)调用run_tty_loop
    3. 进入pythonrun.c的run_tty_loop(fp, filename),执行如下循环:
      run_tty_loop(fp,filename){
          for (;;) {
              run_tty_1(fp,filename); //不断执行一个“单行”语句
          }
      }
    4. 进入pythonrun.c的run_tty_1(fp, filename),主要执行如下:
      run_tty_1(fp, filename) {
      //gram <- graminit将已生成的Python语法规则放进gram,
      //其实不在这个函数里完成,为了理解的方便我就这样写在这里。     
      //根据语法gram以及输入文件fp生成语法树存放在n中     
      node* n = parsefile(fp, filename, &gram, single_input, ...)
      // 执行以n为根节点的语法树
      v = run_node(n, filename, ...) 
      }
    给定以上的主要流程,我们来接触更加细节的部分。首先我们来看parsetok.c中的parsefile这个函数,它主要功能包括"
    parsefile(fp,filename, g, ...) {
    //初始化err_ret
    //初始化一个tokenizer(词法分析器)tok
    tok = tok_setupf(fp, ...);
    return parsetok(tok, g, ...);
    }
    所以这个函数也相当简单,初始化一个词法分析器然后调用parsetok开始做词法分析。再来看parsetok:
    parsetok(tok, g, ...) {
    ps = newparser(g, start)
    for (;;) {
        type = tok_get(tok, &a, &b);
        addtoken(ps, type, ...);
    }
    delparser(ps);
    }
    所以这里就是用一个for循环不停的调用tok_get抓取下一个token供语法分析使用。语法分析里的状态转移以及移进归约在addtoken中实现。

    Monday, January 19, 2009

    [Python]一个用ssh来远程登录多台机器并执行命令的脚本

    功能类似于multissh。事实上我也抄了这个名字//grin。
    要求安装了pexpect这个包先。
    用法见usage:
    Usage: ./multissh.py -f cmdfile -l username -c cmd -n nodesfile -v -r
    execut cmd on remote hosts (all hosts in ./hosts.txt by default)
    -v verbose
    -r recording hosts on which mission succeeded and failed
    -l username
    -c cmd to be executed remotely
    -n file containing the nodes
    -f file conaining the cmd
    -h show the usage
    就是指定一个文件比如nodes.txt以及命令以后,它可以自动登录到nodes.txt包含的节点里执行命令。可以在源文件里替换进你自己的密码,也可以使用公钥密钥登录不需输入密码。指定了v选项的话得到在远端每台主机上的详细输出。指定了r选项的话记录下那些节点成功那些节点失败。
    我前面的帖子里有关于ansi_color的一个脚本,拿过来可以配合使用得到彩色输出

    使用前可能要根据情况修改prompt变量的定义. 这个变量是关于登录后提示符的正则表达.我根据我自己的几台机器随便写了两个.未必符合你的情况.
    #!/usr/bin/python
    import sys
    import os
    import getopt
    import pexpect
    import re
    try:
        from ansi_color import *
    except ImportError:
        def color_str(s, *args):
            return s
        fg_green = None
        fg_red = None
        fg_blue = None
    
    prompt = "^.*\(.*\):|\[.*@.*\]|\$"
    nl = open("/dev/null", "w")
        
    def _print(s):
        if not single_mode:
            print s    
    
    def do(cmds, hostname, username):
        global verbose, quiet, good_hosts
        #print "executing \"%s\""%(repr(cmds))
        ret = 0
        try:
            sshcmd = 'ssh %s'%(hostname)
            if username != None:
                sshcmd = sshcmd + " -l %s"%username
            s = pexpect.spawn(command=sshcmd, timeout=20)
            if verbose:
                s.logfile_read = sys.stdout
                s.setecho(False)
            else:
                s.logfile_read = s.logfile_send = nl 
                s.setecho(False)
            t = 0
            while t < 3:
                i = s.expect([prompt, pexpect.EOF, pexpect.TIMEOUT,\
                              "Are you sure you want to continue connecting (yes/no)?",\
                              "(P|p)assword:"])
                t += 1
                if i == 0:
                    break
                elif i == 1:
                    _print("End Of File")
                    return 1
                elif i == 2:
                    _print("time out")
                    return 1
                elif i == 3:
                    s.sendline("yes")
                elif i == 4:
                    s.sendline(password)
            if t >= 3:
                return 1
            if cmds:
                for cmd in cmds:        
                    s.sendline(cmd)
                    s.expect(prompt)
            else:
                _print("\nEntering interactive mode, please ^] to escape")
                s.interact()
            s.sendline("exit")
            s.close()
            return 0
        except pexpect.ExceptionPexpect:
            return 1
    
    def print_usage():
        print "Usage:\t ./multissh.py -f cmdfile -l username -c cmd -n nodesfile -v -r"
        print "execut cmd on remote hosts (all hosts in ./hosts.txt by default)"
        print "\t-v verbose"
        print "\t-r recording hosts on which mission succeeded and failed"
        print "\t-l username"
        print "\t-c cmd to be executed remotely"
        print "\t-n file containing the nodes"
        print "\t-f file conaining the cmd"
        print "\t-h show the usage"
        print "\t-p password"
        sys.exit(0)
    
    if __name__ == "__main__":
        try:
            opts, args=getopt.getopt(sys.argv[1:], \
                "l:f:n:c:p:vhrq",["login_name", "cmdfile","nodesfile","command","password","verbose","help","recording","quiet"])
        except getopt.GetoptError, err:
            print str(err)
            print_usage()
        if opts == [] and args == []:
            print_usage()
        if args:
            hosts = [args[0]]
        else:
            hosts = []
    
        cmds = []
        verbose = False
        quiet = False
        username = None
        recording = False
        password = ""
        single_mode = True
        
        for o, ra in opts:
            a = ra.strip("\n")
            if o in ("-h", "--help"):
                print_usage()
            elif o in ("-n", "--nodesfile"):
                hosts = [l.strip(" \t\n") for l in open(a, 'r')]
                single_mode = False
            elif o in ("-c", "--command"):
                cmds = [a]
            elif o in ("-f", "--cmdfile"):
                cmds = [cmd.strip(' \n') for cmd in open(a, 'r')]
            elif o in ("-v",  "--verbose"):
                verbose = True
            elif o in ("-q", "--quiet"):
                quiet = True
            elif o in ("-r", "--recording"):
                recording = True
            elif o in ("-l", "--login_name"):
                username = a
            elif o in ("-p", "--password"):
                password = a
    
        if not hosts:
            _print("using default ./hosts.txt")
            h = open(os.path.join(os.path.expanduser("."), "hosts.txt"),'r')
            hosts = [dst.strip(' \n') for dst in h]
            
        if recording:
            f_good = open("good_hosts.txt","w")
            f_bad = open("bad_hosts.txt","w")
    
        good_hosts =[] 
        bad_hosts =[]
        
        for (i, hostname) in enumerate(hosts):
            _print ("%d/%d: ["%(i+1, len(hosts))+ color_str(hostname, fg_blue)+"]")
            ret = do(cmds, hostname, username)
            if verbose:
                print
            if ret == 1:
                bad_hosts.append(hostname)
                _print("["+color_str("Fail!", fg_red)+"]")
                if recording:
                    print>>f_bad, hostname
                    f_bad.flush()
            else:
                good_hosts.append(hostname) 
                _print ("["+color_str("OK!", fg_green)+"]")
                if recording:
                    print>>f_good, hostname
                    f_good.flush()
                
    
        _print ("%d hosts suceed!"%len(good_hosts))
        sys.exit(ret)

    [Python]执行一个进程并监视是否超时

    用到popen2 module当中的Popen3这个类。用法很简单,创建子进程并立即返回父进程。然后可以用poll()函数检查子进程是否已经结束(未结束的话返回值-1)。
    import popen2
    def _popen(cmd, timeout = 10, num_retry = 3, logfile = sys.stdout):
        i = 0
        is_timeout = False
        while i <= num_retry:
            print "%dth try"%i, cmd
            sys.stdout.flush()
            i += 1
            t0 = time()
            P = popen2.Popen3(cmd, True)
            prompt = False
            while time() < t0 + timeout and P.poll() == -1:
                sleep(0.1)
            sts = P.poll()
            if sts == -1:
                logfile.write(color_str("command [%s] timeout\n"%(cmd), fg_red))
                if i < num_retry:
                    logfile.write(color_str("terminate and try again\n", fg_red))
                logfile.flush()
                is_timeout = True
                os.kill(P.pid, signal.SIGTERM)
            elif sts != 0:
                for l in P.childerr.readlines():
                    logfile.write(l)
                if i < num_retry:
                    logfile.write(color_str("try again\n", fg_red))
                logfile.flush()
                is_timeout = False
            else:
                is_timeout = False
                break
        logfile.write(color_str("return "+str(sts)+"\n", fg_red))
        sys.stdout.flush()
        if is_timeout:
            return (sts, open("/dev/null", "r"))
        else:
            return (sts, P.fromchild)

    按说popen2这个module应该已经deprecated,被subprocess module所取代。不过subprocess.Popen的poll()函数似乎有bug,总是返回None。所以只好还用“古老”的module。

    Saturday, January 10, 2009

    [Latex]MacOS上Latex几个IDE的比较

    工欲善其事,必先利其器。因为要在macbook上用latex写paper,需要在几种latex编辑器的选择里找一种最舒服的。我先后尝试了如下的一些:
    • TexShop。免费的一个编译环境。最大的优点就是免费。打开的文件一多的时候操作起来不方便,因为不能用标签选择文件,使用起来很不舒服。
    • TextMate。是一个综合性的文本编辑器。界面漂亮,使用很友好。但是最大的问题是要钱
    • BBEdit。也很不错的一个文本编辑器。但是要钱。TextWrangler是其免费版,但是功能受限制,不爽。
    • Emacs+AUCTeX。还是这个好,免费,而且界面也可以搞的很漂亮。

    Tuesday, December 23, 2008

    在Thunderbird里导入foxmail的邮件

    之前不小心误删过一个学期的email。邮件服务器是imap的,俺没选本地保存,几个thunderbird客户端就都丢了这些email。后来发现我foxmail底下保存了那些email。就决定导回thunderbird里。步骤如下:
    1 在foxmail里选中这些邮件,选择导出。默认的将每一封email存成eml格式的文件
    2 网上很多做法是借助outlook 来中转。我完全不会摆弄outlook,放弃。但是选择安装了import/export tools这个thunderbird插件。在thunderbird的“本地文件夹”里新建一个文件夹,借助那个插件导入eml文件。用这个新文件夹中转是因为这个插件说不能直接在imap的帐户底下导入。
    3 把新文件夹里的email拖到imap的帐户的inbox里。它就会自己和服务器同步去了。然后就可以把那个新文件夹删了。

    好久不用foxmail,今天用了一下6.5beta,感觉进步不少。界面比thunderbird要出色了。也许哪天就又换回foxmail了吧 呵呵

    Sunday, December 21, 2008

    [Linux]Ubuntu自带pdf阅读器无法显示某些pdf文档的中文问题

    Ubuntu自带的Evince非常小巧和轻量。可是有时候有些中文文档无法正确显示中文。可以通过如下方法尝试解决。首先安装xpdf的中文支持:
    $sudo apt-get install xpdf-chinese-simplified
    $sudo apt-get install xpdf-chinese-traditional

    如果还不行,安装poppler相关软件,好像是用于pdf渲染用的。
    $sudo apt-get install poppler-utils
    $sudo apt-get install poppler-data

    Tuesday, December 09, 2008

    Ubuntu以及MacOS下使用街机模拟器Mame

    Mame是一款经典的街机模拟器。但是由于它是Windows下native的,自然有在Linux和MacOS上的移植。这两天捣鼓了一下这个东西,开始玩合金弹头。
    Ubuntu:
    1 安装sdlmame (linux上的mame版本): sudo apt-get install sdlmame
    2 生成配置文件:sdlmame -creatconfig
    3 到/etc/sdlmame下修改mame.ini。 rompath那行把添加进去自己存放rom的路径。比如我用的就是/home/apc999/.mame/roms。另外如果你是ATI显卡的话, 最好把video那行的opengl改成soft。因为ubuntu下ATI显卡驱动有问题。
    4 把你的rom文件放在你指定的rompath底下,如果下回来就是zip格式的话不用去解压直接放。
    这个时候理论上你可能还是玩不起来游戏,因为很多游戏需要相关的bios文件。我是去国治精品屋下载了“Mame Plus!国治2009版”模拟器。不过这个是运行于windows上的。它包括了很全的bios文件。我们只需要把它roms目录底下的那些zip文件(他们都是bios文件)都考过来,放在你的rompath底下就可以了。
    MacOS:
    安装的是MacMame。然后把那些bios文件考在目录~/Documents/MacMAME User Data/ROMs底下就可以了。

    Sunday, December 07, 2008

    [Python]Python 3.0来了

    经历了3年的开发,Python 3.0 (Py3k)在千呼万唤声中 ,终于在2008年12月3号正式发布了。用Guido同学(Python语言的缔造者)自己的话说,Python这些年经历了迅猛发展,已经开始有点违背了Python的"There's Only One Way To Do It"的哲学理念。Guido同学认为Python之所以有今天正是得益与这一与Perl "There is more than one way to do it"相反的理念。所以他需要做一些“清理门户”的事情。因此,我们就有了Python 3.0这一"里程碑"--Python 3.0不提供向下兼容性。换言之,你的2.x的库或者代码,可能会无法运行在Python 3.x当中。

    Python 3.0当中有哪些变化呢?http://docs.python.org/3.0/whatsnew/3.0.html给出了官方的解释。首先映入眼帘的便是,print的语法被改变了。如今print降格为了普通一介函数,需要用print(file=xxx, str1, str2,...)来调用了。其实我很怀念原先print>>xxx, str1, str2 ...的语法,简洁而一目了然。

    另外我觉得比较大的改变还有
    • dict.keys() dict.values()以及dict.items()不再返回list类型的值。所以如果想要k=d.keys();k.sort() 就得写成 k=sorted(d)
    • range现在像以前的xrange那样来工作(之前range直接返回一个list而xrange是返回一个可以yield同样结果的迭代器,以提高效率)。xrange下岗了。
    • 1/2现在的结果是float了,如果要得到截尾的效果,需要用1//2。这个好,再也不用痛苦的写上a*1.0/b/c了
    • <>下岗了。现在只能用!=了。这点不理解。
    • list.sort()现在可以多一个key 参数。比如list.sort(key=myhash),则myhash为一个1参数1返回的函数,list就依据这个myhash来对其包含的元素排序。乌拉!这点好,不用再去重载cmp函数了。早就盼着这一天了
    • 支持如同ML当中的pattern matching: (a, *rest, b) = range(5)
      可以得到 a=0, rest=[1,2,3], b=4
    • 终于到了我最关心的一点:Python 3.0里提供了函数参数以及返回值的注解功能。比如你可以 定义函数 def foo(para1: "the 1st input", para2: "the 2nd input") -> "final result" 这里使用了字符串作为参数和返回值的注解。或者你可以 def bar(para1: int, para2: list) -> float 这样来用类型定义。不过需要特别指出的是,python解释器本身不对注解做出任何反应。这里注解的作用是提供给第三方来infer参数意义或者做typechecking的。
    说道这里,就稍微走题一下吧。Python是一种Dynamic Typing的语言。变量的类型是在运行期才infer出来,而不像C/C++/Java等Static Typing在编译期就已经决定了。Dynamic Typing的优点在于方便灵活,但如果程序规模一大,纠错就是一个很头疼的事情。Static Typing 很多错误可以在编译期就发现。我自己的一个感觉就是用Java写程序如果“编译”通过了,运行期出错的概率比Python小的多。所以一直都很希望Python能有可选的Static Typing 的功能。事实上,Boo 就是一种Static Typing的Python-like语言,而Cobra 则是提供了可选Static Typing的Python-like语言。关于Python是否需要这一功能,可以看一下Guido同学的帖子"Adding Optional Static Typing to Python"。总体而言可以说Guido同学是反对这一想法的。因为他觉得这会把Python简洁的语法弄的凌乱而丑陋并且对Python解释器的执行速度也是一大考验。回到Python 3.0的注解机制上来,这算是一种折中吧--如果你需要typecheking, OK,我们提供场地,你请用第三方来完成吧,但是后果你自负。好吧,虽然这不是我想要的,但是总比没有强吧。

    Python 3.0究竟会表现如何?时间会告诉我们,让我们拭目以待。

    Sunday, November 30, 2008

    [Python]实现Console下路径输入的补全

    因为要用脚本处理一些log,每次运行都要输入待处理的log的路径。可是我存放的log路径太复杂 log自己名字也很复杂,输入起来很麻烦。就想在python里借用shell的路径补全功能。Python里有readline这个module可以提供补全的基本功能,当然需要你自己给它一个completer(text, state)函数从而使它知道如何去补全。另外还有一个cmd module提供简单的命令行界面。用这两者就可以实现我们需要的功能。
    import cmd
    import string, sys
    import os
    import readline
    class CLI(cmd.Cmd):
    def __init__(self):
    cmd.Cmd.__init__(self, "tab")
    self.prompt = 'input the path:'
    self.path = None
    readline.set_completer_delims('/\\')
    def onecmd(self, path):
    if os.path.exists(path):
    self.path = path
    return path
    else:
    print "%s not exists"%(path)
    return None
    def complete(self, text, state):
    if state == 0:
    origline = readline.get_line_buffer()
    line = origline.lstrip()
    stripped = len(origline) - len(line)
    begidx = readline.get_begidx() - stripped
    endidx = readline.get_endidx() - stripped
    self.completion_matches = self.completepaths(text, line, begidx, endidx)
    try:
    return self.completion_matches[state]
    except IndexError:
    return None
    def completepaths(self, text, line, *ignored):
    (head, tail) = os.path.split(line)
    matches = []
    if head == "":
    p = "."
    else:
    p = head
    if os.path.exists(p):
    filelist = os.listdir(p)
    matches = [f if os.path.isfile(os.path.join(head, f))\
    else f+os.sep for f in filelist if f.startswith(tail)]
    return matches
    def get_path(self):
    self.cmdloop()
    return self.path
    def get_path():
    cli = CLI()
    return cli.get_path()

    这里我们继承了Cmd类。但是重载了complete这个函数。这个函数是在用户按下tab键呼叫补全的时候被调用。
    使用这个小程序只要import这个文件以后直接调用get_path就可以了.
    补充:后来发现了一个小bug已经做了修改。cmd module里面在cmdloop()这个函数里就设定了completer_delims (分隔符)。问题在于默认的分隔符里面有很多合法的linux文件名字符比如 “-”这样会导致tab补全的时候出一些问题。 所以我们需要在这之前设置好。这里我们就在__init__初始化的时候设置成/以及\。

    Tuesday, November 25, 2008

    [Linux]几个常用的网络相关的工具

    • ttcp
      测量两台主机之间的tcp/udp throughput
      实例:
      第一步1: 在receiver 主机上打开ttcp, 进入接收模式
      [receiver:~]$ttcp -r -v -s
      ttcp-r: buflen=8192, nbuf=2048, align=16384/0, port=5001  tcp
      ttcp-r: socket
      第二步2: 在sender端向receiver发送文件测试传输速度
      [sender:~]$ttcp -t receiver < testfile
      ttcp-t: buflen=8192, nbuf=2048, align=16384/0, port=5001 tcp -> receiver
      ttcp-t: socket
      ttcp-t: connect
      ttcp-t: 20197 bytes in 0.03 real seconds = 740.32 KB/sec +++
      ttcp-t: 3 I/O calls, msec/call = 9.09, calls/sec = 112.60
      ttcp-t: 0.0user 0.0sys 0:00real 0% 0i+0d 0maxrss 0+2pf 4+1csw
    • iperf
      iperf也是测量网络throughput的常用工具之一. 用法和ttcp类似.
    • iptables
      iptables是Linux下的软件firewall
      https://help.ubuntu.com/community/IptablesHowTo
      查看当前iptables的设置
      $sudo iptables -L
    • ipfw
      ipfw其实是FreeBSD底下的软件firewall。可以非常方便的用来traffic shaping.
      实例:
      • 如下命令添加一个virtual pipe用于所有inbound的ip traffic。并且设定这个pipe bandwidth为50Kbit/s buffer size为50
        $sudo ipfw add pipe 1 ip from any to any in
        $sudo ipfw pipe 1 config bw 50Kbit/s queue 50
        
      • 如下的命令模拟ADSL:
        sudo ipfw add pipe 3 ip from any to any out
        sudo ipfw add pipe 4 ip from any to any in
        sudo ipfw pipe 3 config bw 128Kbit/s queue 10 delay 1000ms
        sudo ipfw pipe 4 config bw 640Kbit/s queue 30 delay 1000ms
        
      • ipfw除了使用pipe来模拟link,还可以使用queue来模拟队列。等我知道怎么用了再来写。
    • systat
      Freebsd下监视系统的命令,可以显示CPU、I/O、内存、虚拟内存、mbufs、磁盘IO、网络状态等信息等。
      用法:
      systat [-display] [refresh-interval]
      • display 为我们所要显示的信息项目,我们也可以在进入 systat 后通过输入“:display”变更显示项目。可选项:
        pigs 显示目前系统中使用 CPU 最多的行程名称。如果所有行程的 CPU 使用量未满 100%,则多出来的部份显示为 IDLE。icmp 统计目前 ICMP 封包的进出情形。icmp6 显示 IPv6 的 ICMP 封包进出情形。ip 显示 IP 层的封包统计及 UDP 封包信息。ip6 和 IP 一样,但只显示 IPv6 的封包。tcp 显示 TCP 的封包统计。iostat 显示 I/O 状况统计,并分类为各种模式显示。swap 显示目前各个储存空间上的虚拟内存的使用情形。mbufs 显示 mbufs 被使用的状态。vmstat 这是我们最常用的显示模式,它显示了最多的信息,包含 I/O、虚拟内存、mbufs、网络等信息。netstat 显示网络的使用情形。ifstat 显示各个网络适配卡的使用情形。
      • refresh-interval 参数是需要多长时间采样一次系统数据输出到屏幕,单位是秒。
      实例:
      systat -v 1
      我们打开v选项(vmstat的缩写),每隔1s更新一次。
    • netstat 可以用来查看当前网络所有链接, 也可以用来查看路由信息,比如
      $ netstat -nr
      Routing tables
      
      Internet:
      Destination        Gateway            Flags        Refs      Use   Netif Expire
      default            10.1.10.1          UGSc           23       36     en0
      10.1.10/24         link#4             UCS             6        0     en0
      10.1.10.1          0:22:2d:7b:12:fa   UHLWIir        24       22     en0    134
      10.1.10.10         80:ea:96:e4:f6:93  UHLWI           0        7     en0   1190
      10.1.10.11         d8:d1:cb:91:6d:aa  UHLWI           0        0     en0    691
      10.1.10.15         8c:2d:aa:5a:a7:1f  UHLWI           0       58     en0    733

    Monday, November 24, 2008

    emacs与vi常用指令对照

    这个学期的Type Systems需要学习用Twelf这个语言。简单的说是CMU搞出来的一种(目前主要用于教学的)Logic Programming的语言。因为它提供了emacs的mode,会比调server出来运行要方便快捷。再加上Carl一个劲的鼓吹Computer Scientists是使用emacs的而不是vi。我正好用这个机会push自己多练练emacs。在这个帖子里集中记录我常用到的指令以及和vi的对照。毕竟vi短小精悍而且和less之类的指令相通不可能完全不用。
    操作 emacs vi
    文件操作:
    打开文件C-x,C-f,<filename>:sf <filename>
    保存C-x,C-s :w
    退出C-x,C-c:q
    编辑
    选择C-space (设立标记)v (进入visual模式)
    拷贝M-wy
    剪切C-wd
    粘贴C-yP
    撤销上一个指令C-x,uu
    删除一行C-kdd
    拷贝一行
    yy
    移动
    跳至第n行M-g,g,<n>:<n>
    搜索
    找到patternC-S,<pattern><patern>
    其他
    执行n个指令C-u,<n>,<cmd><n> <cmd>

    Thursday, November 20, 2008

    [Python]使用ansi color code 让console五颜六色

    写了一个Python小程序, 用于输出带ansi color code的字符串,使得在支持vt100的终端上能看见五颜六色的输出。

    ESC = chr(27)
    # 字体
    a_default = 0
    a_bold = 1
    a_italic = 3
    a_underline= 4
    # 前景颜色
    fg_black = 30
    fg_red = 31
    fg_green = 32
    fg_yellow = 33
    fg_blue = 34
    fg_magenta = 35
    fg_cyan = 36
    fg_white = 37
    # 后景颜色
    bg_black = 40
    bg_red = 41
    bg_green = 42
    bg_yellow = 43
    bg_blue = 44
    bg_magenta = 45
    bg_cyan = 46
    bg_white = 47

    def color_code(a):
    return ESC+"[%dm"%a

    def color_str(s, *args):
    cs = ""
    for a in args:
    cs += color_code(a)
    cs += s
    cs += color_code(a_default)
    return cs

    用法
    比如你可以用

    print color_str("hello world", fg_red, bg_black, a_bold)

    来生成黑底红字的加粗的hello world

    Wednesday, November 19, 2008

    Screen 小结

    screen在mitbbs的linux版上被称为震版之宝。minhong推荐下我用了一下,果然非常好用。
    这里先占坑。

    基本用法:
    1. 在term下键入screen。会出现一些提示,然后就是先前的shell。这时候与普通shell的唯一区别在于你可以使用ctrl+a d (先按ctrl + a, 然后按d)退出这个screen session。这个session以及在这个session中运行的程序将在没有你的监督下继续运行,哪怕你是远程登录到这台主机上而远程登录又中断了。
    2. 查看当前主机上运行了多少个session, 以及每个session叫什么名字:
      screen -ls
    3. 继续一个离开了的session.如果当前只有一个session,那么直接输入
      screen -r
      如果有多个session, 而你要重入其中的一个:
      screen -r sessionname
    4. 进入一个session后, 键入ctrl+a k 终止当前session. 不像ctrl+a d只是离开这个session, 使用了ctrl+a k之后你就无法再次重入这个session了
    5. screen -S your_fav_name -d your_cmd:新建一个名为your_fav_name的screen会话并执行你的命令.为一个会话起一个名字的好处包括用这个名字来kill掉这个会话,而不用每次都先screen -ls看你这个会话的id.
    注意事项:
    1. 在远程主机上执行screen: 如果你是ssh到远程主机上并直接用screen 执行一个命令,比如:ssh user@host screen cmd,有可能得到Must be connected to a terminal.这个错误。 解决方法:使用 ssh的-t选项
    2. 杀死远端的screen进程:当你远程主机使用screen在执行一个命令的时候,你可以登录到这个主机并resume你的screen会话并用ctrl+a k杀死该会话。但是这样要求手动控制而无法使用脚本。一个解决办法是用: "screen -S sessionid -X quit" 向远端主机发送screen窗口命令cmd 。 比如quit的话就是结束这个session。
    3. detach远端的screen 进程。 比如你回家之前在office的机器上用screen执行一个命令且没有detach。当你从家里登录office机器想resume则会被告知,该session没有被detach你无法直接在家resume进去。可以发送用: "screen -S sessionid -X detach"命令过去将其detach,然后再实现重入。
    4. 输入backspace的时候总是出现“Wuff Wuff!“这样的讨厌提示。以及del/backspace工作不正常。可以参见http://ubuntuforums.org/archive/index.php/t-90910.html .我的经验是设置TERM变量。bash 底下可以alias screen='TERM=screen screen',tcsh底下可以alias screen 'env TERM=screen screen'

    Thursday, November 13, 2008

    [Python]Quine(自产生程式) in Python

    Quine是指一个程序,它的输出为自身的源代码。这个学期的OS课里读到Ken Thompson的paper里说到了这样的一个程序。Ken Thompson在83年因为早年对Unix和C语言的贡献而得到了图灵奖。这篇paper 是他的图灵奖演讲文稿。在paper里他提到他在UC Berkeley念书的时候,同学们都热衷于写这样的程序并相互比赛谁的程序短。并且他还提到,如果你们自己没有写过这样的程序,他强烈建议自己来试一试写这个程序,会比由别人告诉你如何得到这个程序要有收获的多。于是我便没有接着往下读这个paper看Ken是如何完成的而是试图用Python来写一个这样的程序。最后得到了这样的程序:
    M="print 'M='+repr(M)\nprint M"
    print'M='+repr(M)
    print M
    Python来完成这个任务事实上是相当简洁的。因为repr()这个函数帮助我们完成了很多的工作。

    Sunday, November 09, 2008

    SSH一点点经验

    使用~/.ssh/config
    .ssh/config这个文件就是给大家偷懒用的.比如我可以指定:
    Host aaa
            User apc999-majia
            Hostname aaa.foo.bar
    这样只要输入ssh aaa, ssh就自动帮你链接aaa.foo.bar并且使用用户名apc999-majia.
    也可以使用通配符*以及?
    Host aaa*
            User apc999-majia
    在config文件中还可以指定其他许多有用的选项, 参见:config中的选项


    不能使用公钥验证登陆的问题:
    Office的机器从某天开始突然不能允许我用public key来ssh 登陆了。排查了很久:
    (1)首先看public key和private key是不是对的 -- 对的
    (2)检查要登录的机器那端权限设置是不是正确:~/.ssh 应该是0700, ~/.ssh/authorized_keys应该是0600, --对的
    于是使用sshd的debug模式来看一看:
    sudo /usr/sbin/sshd -d -p 2000: 实现一个2000端口的one shot debug mode,
    这样你可以在客户端 ssh -p 2000 HOSTNAME 来尝试一次登陆以提供debug信息。
    然后看sshd的log (/var/log/auth.log) 看到 sshd[9564]: Authentication refused: bad ownership or modes for directory /home/xxxxx 。遂去看了一下$HOME的权限, 原来不知道怎么给了组用户w权限。去掉以后就好了。

    另外本机~/.ssh/config权限应该是600

    登录被要求输入两次密码 (Password, Response)
    这是由于使用了SSH version 1会这样, 比如我们用-1选项手动使用version 1登录
    $ ssh -1 foo.bar.net
    Password:
    Response:
    而使用version 2(选项-2)则是
    $ ssh -2 foo.bar.net
    Password:

    大多数SSH client 默认先使用Protocol 2.但是FreeBSD的/etc/ssh/ssh_config中默认Protocol 1,2. 所以我们可以修改/etc/ssh/ssh_config(如果你有权限)或者~/.ssh/config(只能管你自己),使得
    #Protocol 1,2
    Protocol 2,1

    想看登录时候的详细信息,比如本地和远端主机如何交互:
    ssh -v foo.bar.net
    想看更详细的:
    ssh -vv foo.bar.net
    想看更更详细的:
    ssh -vvv foo.bar.net
    想看更更更详细的:
    请订阅中国电视报

    关掉每次登录前Host Key的检查。就是每次登录一个陌生host前被询问:
    The authenticity of host 'foo.bar.net (1.2.3.4)' can't be established.
    DSA key fingerprint is dc:28:c4:30:85:11:75:8a:61:53:65:1a:a0:50:5e:32.
    Are you sure you want to continue connecting (yes/no)?
    修改~/.ssh/config
    Host *
    StrictHostKeyChecking no
    这个选项默认的是ask,就是每次都询问

    用一台主机做代理登录另目的主机(foo.bar.net):
    修改~/.ssh/config
    Host foo.bar.net
    User bfan
    ProxyCommand ssh foo.bar.net -l 用户名 nc %h 22

    选项 -o BatchMode=yes
    好处是用于脚本批量登录的时候(比如使用我的multissh.py脚本)的时候因为一些系统问题被提问密码,直接当作错误返回。 这样脚本可以当作登录失败重新尝试.

    端口转发(Port Forwarding, Tunneling)
    比如使用了如下命令:
    ssh -L 1234:host2:5678 host1
    那么在登录host1期间,我们的本地主机还会打开一个tcp端口1234并监听,所有1234端口接受到的流量通过安全连接转发给host2的5678端口.
    命令行参数为 -L local_listen_port:destination_host:destination_port
    或者在.ssh/config设置为
    LocalForward local_listen_port destination_host:destination_port
    参考SSH Port Forwarding

    对某台主机不使用Pubkey登录
    如果是一次性的
    ssh -o PubkeyAuthentication=no  your_hostname
    如果是多次性的
    PubkeyAuthentication=no写进~/.ssh/config文件对应的条目中

    环境变量问题
    http://roumenpetrov.info/articles/locale_env_in_ssh_session.html
    我在自己机器上设定环境变量LC_CTYPE=zh_CN.UTF-8, 导致在一些远端服务器上出现一些locale的问题.这是因为/etc/ssh/ssh_config文件中设定了
    SendEnv LANG LC_*
    所以LC_CTYPE环境变量也被送到了远端,导致出现了一些问题. 把LC_*去掉后就好了

    Sunday, November 02, 2008

    [Python]使用Python中的Lambda演算功能:Y-Combinator的Python实现

    最近接触的东西都比较杂。不过感觉好几个方面比较有收获。一是使用PyQt感觉Qt平台的强大和华丽。对我来说它最大的好处是跨平台:我的Mac和Ubuntu都可以很好的支持,程序不用修改就能顺利的运行在不同平台上。二是可以使用Python, 这个好处就不多说了。

    由于这个学期选得Type Systems课,接触了一些Lambda演算和ML语言(想歪的同学请自觉面壁)。前半个学期由于赶paper的缘故都没有花时间在上面,况且前面的内容也不是那么有趣(Constructive Logic算是一个小亮点)。现在讲到了Polymorphism(应该是多态吧?)以后,才发觉这里面的博大精深。Lambda演算是一种与被大家熟知的Turing Machine不同的计算模型,事实上它的历史甚至可以追随到Turing Machine之前。Turing本人也对Lambda演算做出过贡献。比起Turing Machine,Lambda演算在形式上要“简单”,思维更接近数学。但是Lambda演算的计算能力被证明是和Turing Machine的计算能力是等价的。Turing Machine上著名的停机问题也有其Lambda 演算版本。而且这个版本其实由Church比Turing更早提出

    Lambda演算的基本形式为λx.body。 这里可以把x看成一个函数的输入参数,body看成这个函数的返回值。不过与普通编程语言中的函数不同的是, x可以为一个普通的值变量,也可以为一个函数,还可以是一个类型。简简单单的定义却有无穷的变化。比如Church在Lambda演算的基础上重新定义了正整数。还可以在Lambda演算的基础上把布尔类型以及正整数类型推广化。比如List就是一种generalized的正整数。

    Python提供了Lambda算子的功能。下面我就用Python的Lambda算子来实现不动点算子Y-Combinator。有关什么是Y-Combinator可以看一下wiki。简单的说来,给定一个函数g以及不动点算子Y,我们有Y(g) = g(Y(g))。从而我们可以用不动点算子Y来实现g的递归调用。

    Y-Combinator in Python:
    Y = lambda f: (lambda x: f(lambda n:x(x)(n)))(lambda x: f(lambda n:x(x)(n)))


    这样如果你定义了非递归函数,比如阶乘
    g =  lambda factorial, k : 1 if k == 1 else factorial(k-1)*k

    或者更容易理解的方式是这样:

    def g(factorial, k):
    if k == 1:
    return 1
    else:
    return factorial(k-1)*k
    

    就可以用 Y(g) (k) 来递归求k的阶乘。

    Ref: http://siddhi.blogspot.com/2007/08/y-combinator-in-python.html

    Saturday, November 01, 2008

    [Python]Python2.6内建函数(未完)

    Python用了很久了,但一直没有系统的学习一下它的内建函数, 也就是在__built-in__这个module里的函数。这些函数都是在直接默认在namespace中不需要import 任何其它module来获得的。所以可以想象,也是最常用最有用的那部分函数。决定今天补上这个差事。也是为了使自己能够熟系很多不那么常用的功能,写出更加有效率的代码。

    __import__ 最常使用的import函数会调用__import__。python 提供这个内建函数是为了让用户可以改变import的语法,比如提供自己的import 函数

    abs(x) 返回绝对值。按说应该放在math module里面, 但是估计太常用了就放在built-in里面了。同样的还有max, min

    all(iterable), any(iterable) 前者返回True当所有iterable元素为“True”,后者返回True当有一个元素为“True”。装13的话可以这么说,一个是全称量词一个是存在量词。不过要注意的是, 我这里True打了引号是因为不仅仅是Boolean的True值。事实上,在Python当中,False, 0, 空的list [], 空的dict {}, 空的tuple () 以及空字符串 "" 都在某种程度上被认为是False。 比如x取值为上述任何一者的时候, not x 都等于 True。这两个是Python 2.5以后出来的新feature

    basestring() 是str 和unicode的superclass

    bin(x) 输出一个整数的二进制字符串。 比如 bin(9) = ' 0b1001'。 Python 2.6添加的很实用的一个功能。

    bool([x]) 把一个值转换为bool值。规则如上在all, any中所述

    callable(obj) 如果obj为可调用, 返回True, 否则为False。 比如 callable(lambda x: x**2) = True。 callable([1]) = False

    chr(i) 将一个ASCII码转换为对应的字符。ord 为其反函数。 chr(48) = '0', ord('0') = 48。

    cmp(x, y) 比较 x 和y, 如果xy返回正数

    compile 编译一段python的code。比如 a = compile("print \'Hello World\', '', 'exec') 然后就可以用 exec(a)来得到'Hello World'的输出

    complex 创建一个虚数

    delattr(obj, name), setattr(obj, name) 比如 delattr(x, 'foobar') 等同于 del x.foobar

    dict 创建一个dictionary。 类似用法的还有 tuple, list, set。需要提一下的是dict的用法。比如dict({'one':1, 'two':2})是最基本一种,实践中更加简洁方便的一种写法是 a = ['one', 'two']; b = [1, 2], dict(zip(a, b))。 zip是一个非常神奇的函数,用起来好处多多,可以让代码简洁清晰很多.

    Friday, October 24, 2008

    [SVN]设置ignore属性

    1 设置本地,全局ignore属性
    如果想在本地所有工作目录下屏蔽*.o, *.pyc这些临时文件, 可以修改"/etc/subversion/config" (针对所有用户)或是"~/.subversion/config"(仅针对当前用户):
    添加, 或是去掉如下行的注释
    [miscellany]
    global-ignores = *.o *.pyc
    这样不管在哪个工作目录, *.o 以及*.pyc都不会被列出来了.

    2 设置server端,局部(每个目录可以不同)的ignore设置
    进入你希望设置的工作目录,
    svn propset svn:ignore "*.o" .
    然后commit提交之后, 这个目录的svn:ignore属性便被设置成了*.o .

    如果要同时设置多个ignore pattern, 比如 *.pyc *.pyd *.output的, 需要在不同pattern之间用回车隔开, 空格是不成的.所以可以用"\"符号输入多行
    svn propset svn:ignore "*.pyc\
    *.pyd \
    *.o" .
    或者写在文件里, 然后从文件导入:
    svn propset svn:ignore -F .cvsignore .
    或者调用外部editor:
    svn propedit svn:ignore .

    如果希望属性被递归的设置:
    svn propset -R svn:ignore "*.o *.pyc" .

    注意这个改动是server端可见的.也就是说别人的改动也会影响到你.

    Tuesday, October 21, 2008

    [Python]初探PyQt (1)

    因为需要做demo的缘故,要搞一个GUI来显示一些东东。纯粹编程语言的话我肯定是首选Python。但Python的GUI编程我很不熟。很久很久以前用过tkinter来做,感觉不好,widget资源太少。最近用了很多基于Qt平台的东西,包括qterm,以及Python最强大的IDE eric。感觉Qt平台很漂亮资源也很丰富。所以就搞基于Qt的了。Qt是跨操作系统的一个图形界面平台,是挪威Trolltech 公司的产品。但是它提供免费的开源版本可以使用。著名的KDE桌面环境就是基于Qt开发的。Qt是使用C++的,可现在也有很多基于其它语言的binding(应该翻译成绑定么?),比如基于Python的PyQt和基于Ruby的RubyQt。PyQt就是我打算使用的。它允许我们在Python环境里调用Qt平台的API。

    在Ubuntu上安装PyQt很简单,只要 apt-get install python-qt4就可以了。
    在Mac上安装要稍微复杂一些,首先安装Qt4.你可以直接从源码安装,也可以port安装
    port install qt4-mac
    然后编译安装sip,最后才能编译安装PyQt

    然后就可以上手了, 这里有一个很不错的PyQt的tutorial: http://zetcode.com/tutorials/pyqt4/。 同时你可以看到QtGui的所有widget: http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qtgui.html



    QWidget(parent) 初始化控件时候可以指定该控件的parent.这样在parent被delete的时候,该控件也一同被delete
    setGeometry(x,y,width, height). (x,y)是控件左上角坐标 -- (0,0)是左上角, width和height是控件的宽和高.
    resize(width, height) 设定控件的大小
    setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Raised) 设定frame周围边框样式
    QtGui.QApplication.setStyle(QtGui.QStyleFactory.create('cleanlooks')) Typically they include "windows", "motif", "cde", "plastique" and "cleanlooks". Depending on the platform, "windowsxp", "windowsvista" and "macintosh" may be available.

    (待续)

    Sunday, October 19, 2008

    [Linux]挂载ntfs分区

    第一步,查看各个分区的UUID
    sudo blkid
    得到类似如下的输出:
    /dev/sda1: UUID="B03459B334597CF2" LABEL="System" TYPE="ntfs"
    /dev/sda2: UUID="CAEC3646EC362D57" LABEL="Data" TYPE="ntfs"
    /dev/sda3: TYPE="swap" UUID="29e3c192-9a88-4304-be63-7ce425c5f0bc"
    /dev/sda4: UUID="91c8e884-0927-4e5b-847e-383a5a7b4060" TYPE="ext3"
    /dev/sdb1: LABEL="-----------" UUID="40DD-FB39" TYPE="vfat"
    第二步,修改/etc/fstab:
    # /dev/sda1
    UUID=B03459B334597CF2 /mnt/winc ntfs uid=1000,gid=0,umask=000,nls=utf8 0 0
    # /dev/sda2
    UUID=CAEC3646EC362D57 /mnt/wind ntfs uid=1000,gid=0,umask=000,nls=utf8 0 0
    这里设定可以在每次开机的时候将win下的c盘(/dev/sda1)挂载在我的/mnt/winc. 以后uid为我自己(1000是我的uid),gid为root. 其他参数还包括:
    • umask: 设定默认的文件以及目录的权限掩码. 4: read, 2: write, 1: execute. 000就代表给所有人(user, group, other)所有权限. 033的话就是给user rwx权限,group和other只有r权限.
    • dmask, fmask: 分别设定针对目录以及文件的权限掩码.
    • nls (native language support): 加入本地编码(比如我这里是utf8),这样就不会乱码.
    事实上在linux下umask(或者dmask+fmask)的设定就是ntfs分区里所有文件目录的默认权限了.你用chmod去修改也不奏效.

    Ref:
    http://wiki.archlinux.org/index.php/Fstab_%28%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87%29

    Thursday, October 16, 2008

    [Linux]几个常用的Linux命令/工具的用法举例

    这里是我平时常用到的几个linux命令以及比较trick的一些参数,附带简单的使用例子
    文件操作

    • ls
      参数:
      • -h: 以人易读的格式显示文件大小 (比如 1K, 234M, 2G这样)
      • -R: recursively显示子目录下的文件
      • -t: 按修改日期排序(最近修改的靠前)

    • tar
      实例:
      • 例1:把foo这个目录打包并使用gzip压缩,并自动剔出.pyc文件以及version control的文件
        $tar -zcf foo.tar.gz --exclude '*.pyc' --exclude-vcs foo
      • 例2:把foo这个目录打包,但是用lzma压缩(lzma有比gzip的压缩比高,解压快的特点.但是压缩的时候慢)
        $tar -cf foo.tar.lzma --lzma foo
      • 例3:解压foo.tar.gz
        $tar -zxf foo.tar.gz
      • 例4:解压foo.tar.bz2
        $tar -jxf foo.tar.bz2
      • 例5:查看foo.tar.gz包内容
        $tar -tf foo.tar.gz

    • rm
      实例
      • 例1:删除一个叫--foo的文件
        $rm -- --foo
      参数
      • --: 删除以"-"开头的文件

    • find
      实例
      • 例1:找出$HOME 底下(recursively)所有以apc999开头的,owner为apc999的,permission为755的,创建时间为1天以前的文件
        $find ~ -name "apc999*" -user apc999 -perm 755 -mtime 1
      • 摆脱烦人的"permission denied"警告
        $find ~ -name "apc999*" -print 2> /dev/null 
    进程操作

    • ps
      实例
      • 例1:显示当前终端的所有进程:
        $ps
        PID TTY          TIME CMD
        12713 pts/24   00:00:00 tcsh
        12840 pts/24   00:00:00 ps
        
      • 例2: 显示所有当前用户进程(包括使用了其他终端的) x, 显示进程的用户名 u,并用树型表示其父子关系 -H
        $ps ux -H
        USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
        apc999   12713  0.0  0.0  59732  1684 pts/24   Ss   15:11   0:00 -tcsh
        apc999   12839  0.0  0.0  74864  2080 pts/24   R+   15:20   0:00   ps ux -H
        apc999   12637  0.0  0.0  59732  1684 pts/10   Ss   15:07   0:00 -tcsh
        apc999   12760  0.1  0.0  24412  2052 pts/10   S+   15:13   0:00   top
        apc999   12821  0.0  0.0  66196  1144 ?        Ss   15:16   0:00 SCREEN top
        apc999   12822  0.1  0.0  24416  2048 pts/27   Ss+  15:16   0:00   top
        
      参数
      • u 显示进程的用户名
      • x 显示当前用户的所有进程(包括当前用户的其他终端)
      • -A (-e)显示所有进程(包括其他用户)
      • -U Username指定特定用户

    • screen 是一个窗口管理工具帮助你保持一个session在主机上的运行而不受外界因素影响.比如你ssh到一台主机上运行一个程序foo,当你ssh中断的时候, 这个程序foo的运行也将中断.为了让foo的运行不受ssh的影响,screen可以助你一臂之力.这里link是我写的比较详细的介绍
    下载

    • wget其实是强大的下载/抓站工具,默认支持断点续传
      实例
      • 例1:将http://www.example.com/packages/foo.bar 下回来
        wget -r -c http://www.example.com/packages/foo.bar
      • 例2:将http://www.example.com/packages/ 下后缀为zip的文件(不包括子目录中的)全部下回来
        wget -r -np -nd -A.zip http://www.example.com/packages/
        把example.html中所有链接的zip文件下载回来, 只往下找一层
        wget -r -l1 -np -nd -A.zip http://www.example.com/example.html
      • 例3:下载urls.txt 中所有url:
        wget -i urls.txt
      参数
      • -r: 递归下载。如果是http的url,下载http文件当中超链接所引用的url;如果是ftp,下载目录(如同cp 或者scp 的-r参数)
      • -c: 指定断点续传。wget默认选项,只有该文件之前被其它ftp工具所下的时候才有用。
      • -np/-nd: 不在远端遍历父目录/不在本地建立目录结构
      • -l: 递归级数(配合-r使用)
      • -i --input-file: 下载在FILE文件中出现的URLs
      • -t: 重试次数
      • -A, --accept=LIST: 分号分隔的被接受扩展名的列表
      • -R, --reject=LIST: 分号分隔的不被接受的扩展名的列表

    • curl:一个利用URL语法在命令行下工作的文件下载或上传的工具
      实例
      • 例1:将http://www.example.com/packages/foo.bar 下回来,另存为a.bar
        curl -o a.bar http://www.example.com/packages/foo.bar
      • 例2:批量下载
        curl http://any.org/archive[1996-1999]/vol[1-4]/part{a,b,c}.html \
          -o "archive#1_vol#2_part#3.html"
        
    标准输入输出上的文本处理

    • grep
      实例
      • 例1: 查找当前目录下所有文件(recursively)是否包含某一个正则表达式reg_exp,忽略大小写
        $grep -rin reg_exp *
      • 例2: 查找当前目录下所有以foo为extension的文件
        $grep -r --include "*.foo" reg_exp *
      • 例3: 显示匹配行以及上下两行的内容
        $grep -2 reg_exp *
      参数
      • -?: 显示匹配行的上下?行
      • -r: recursive 递归查找
      • -i: ignore case 不敏感大小写
      • --include: filename pattern 根据给定文件名pattern过滤
      • -n: line number 显示行号

    • awk: 在输入的文件或字符串中, 基于给定的规则提取文本.基本用法 awk 'pattern {action}'
      实例
      • 例1:将文件A.txt当中每行用,分割为若干个字段,输出第3个字段
        $awk -F "," '{print $3}' A.txt
      • 例2:检查哪个用户没有设立password
        $awk -F: '$2=="" {printf("%s no password!\n",$1)}' /etc/passwd
      • 例3:统计当前目录下所有.dat文件一共多大(对输入的某一列求和)
        $ls -l *.dat | awk '{ SUM += $5} END { print SUM/1024/1024 }' 
      参数
      • -F: 分割符
      • $1: 得到的第一个字段
      • $NF: 最后一个字段

    • cut: 和awk有一些类似,但用法比awk简单
      实例
      • 例1:将文件/etc/passwd当中每行用:分割为若干个字段,输出第1和第7个字段
        cut -d : -f 1,7 /etc/passwd
      参数
      • -b list: list指定第几第几个byte位置
      • -c list: list指定第几第几个字符位置
      • -f list: list指定第几第几个field位置

    • head/tail: head用来 显示一个文件开头部分, tail 显示一个文件结尾部分
      实例
      • 显示foo.txt的前100行
        head -n 100 foo.txt
      • 显示foo.txt的最后100个byte
        tail -c 100 foo.txt
      参数
      • -n: 行数
      • -c: 字节数
      • -f: 不结束, 不停刷新显示

    • tee: 很有用的小命令--把标准输出的内容复制到制定文件当中
      实例:
      • ls并把显示内容复制到ls_result 这个文件中。
        ls * | tee -a ls_result

    • uniq: 报告或者忽略输入中重复的行
      实例
      • 查看输入中有多少不同内容的行,以及每一行出现的次数
        cat foo | sort | uniq -c

    • diff: 比较两个文件或者目录下的不同
      用来比较两个目录(以及子目录)下文件的不同
      $ diff -r /path1/foo /path2/foo

    • hexdump: 报告或者忽略输入中重复的行
      实例
      • 把二进制文件foo按照16进制字符输出
        $ hexdump  foo 
        0000000 cf fa ed fe 07 00 00 01 03 00 00 80 02 00 00 00
        0000010 12 00 00 00 d8 08 00 00 85 00 20 00 00 00 00 00
        0000020 19 00 00 00 48 00 00 00 5f 5f 50 41 47 45 5a 45
        ...
    用户相关的操作

    • adduser: 添加用户
      增加用户foo
      $ sudo adduser foo
      把用户foo添加到admin当中(可以sudo)
      $ sudo adduser foo admin

    • groups:查看某个用户所属的组
    其他操作

    • time: 给命令计时. 注意有时候shell自带的time功能较弱,要用/usr/bin/time
      实例
      • 给命令cmd计时
        /usr/bin/time -f "%E" cmd arg1 arg2 

    Tuesday, October 07, 2008

    gedit的style以及语法增亮

    (1) 用gedit 在Ubuntu上编辑Latex
    现在很喜欢用gedit在Linux下面编辑Latex文档。它有一个非常好用的latex插件。Windows下面最常用的CTex/WinEdt套装里的基本功能这里也基本都有。说一下步骤:
    1. 虽然这个plugin不是默认的,但是只要下载下来然后把plugins/目录下的内容拷贝到 ~/.gnome2/gedit/plugins底下就可以了。
    2. Ubuntu默认的latex package没有装全,可以apt-get install texlive-full把所有的都拖下来。大概需要1G左右的硬盘空间
    3. 安装rubber: apt-get install rubber。 rubber是linux底下一个非常好用的latex编译工具。用来编译latex文档(足够次数以保证ref显示正确)
    (2) 让gedit漂亮的显示code。
    你已经可以用gedit来修改和编译latex文档了。但是gedit默认的color scheme对于latex的语法增亮支持的不好。事实上gedit 2.19以后的自定义color scheme功能使得用户可以把gedit的GUI和语法增亮设置到漂亮的发指的地步。当然也可以KUSO到发指。比如我就去下了一个Turbo Pascal/C界面的style回来,用起来及其怀旧。不过还是dark color的scheme好看以及省眼睛。自带的Oblivion就很好。 不过这个默认的scheme也对Latex的色彩增量支持不好。我又舍不得gedit的latex plugin。就决定自己动手丰衣足食,打造一个漂亮且对Latex,Python等code友好的color scheme。

    相关知识:gedit的color scheme允许使用用户自定义的xml文件(当然它自己也带了4个风格,Tango,Oblivion等)。其色彩增亮依据的语法定义,借用了gtksourceview的一套东西。

    第一步: 建立自己的风格定义文件。这里命名为APCDarkMate.xml。基本抄了DarkMate这个color scheme,增加了我自己的python和latex语法增亮:

    <name="python:keyword" style="def:keyword">
    <name="python:comment" style="def:comment">
    <name="python:module-handler" style="def:keyword">
    <name="python:builtin-constant" style="def:constant">
    <name="python:builtin-object" style="def:type">
    <name="python:builtin-function" style="def:function">
    <name="python:boolean" style="def:constant">
    <name="python:multiline-string" style="python:comment">
    <name="python:special-variable" style="def:constant">
    <name="latex:keyword" foreground="yellow">
    <name="latex:common-commands" style="latex:keyword">
    <name="latex:command" style="latex:keyword">
    <name="latex:display-math" foreground="green">
    <name="latex:include" style="latex:keyword">



    (待续)

    Sunday, September 28, 2008

    [Python] 一些小tips

    (1) 用isinstance判断变量类型
    >>>A = [1,2,3,4]
    >>>isinstance(A, list)
    


    (2) sort, reverse 以及 sorted, reversed
    A=[3,1,2]
    assert(A.sort() == sorted(A))
    assert(A.reverse() == reversed(A))
    


    (3) 一个简单的命令行progress bar:
    def progress_bar(current, total, width=20):
    i = int (current*width/total)
    sys.stdout.write("\r|" + '*'*i + ' '*(width-i)+"|")
    


    (4) PyYaml最简单的用法
    • 把一个变量A dump到一个文件f中
      A = {1:'a', 2:'b'}
      yaml.dump(A, f)

    • 从外部yaml文件文件load出数据到A
      A=yaml.load(filehandler)
      


    (5) 读取命令行的输入:
    • input(prompt)
    • raw_input(prompt)
    • import getpass
      getpass.getpass(prompt)

    (6) 使用re正则表达式
    import re
    >>>m = re.match(r"(\d+)\s*(M|K)(bit|Byte)", "1024Mbit")
    >>>print m.group(1), m.group(2)+m.group(3)
    1024 Mbit
    

    还可以使用(?P)来acess匹配到的字符串
    m = re.match(r"(?P\d+)\s*(M|K)(bit|Byte)", "1024Mbit")
    >>>print m.group("num"), m.group(2)+m.group(3)
    1024 Mbit
    

    为了提高使用正则表达式的效率, 可以先编译正则表达式, 然后每次用编译出来的正则字符串去匹配
    >>>p = re.compile(r"(\d+)\s*(M|K)(bit|Byte)")
    >>>g = p.match("1024Mbit")
    >>>print g.group(1), g.group(2)+g.group(3)
    1024 Mbit
    


    (7)显示异常的类型和错误信息
    try:
        do what you want
        except:
            print sys.exc_info()[0], sys.exc_info()[1]
    sys.exc_info()[0]: 异常的类型
    sys.exc_info()[1]: 异常的信息

    (8) Python 2.5以后支持with 语句. 用在file object上,就不用close这个文件了
    with open("max_load_vs_k.dat","w") as f:
        do some file operation with f


    (9)Python Search Path
    >>>sys.path
    ['', '/Library/Python/2.6/site-packages/ipython-0.10.1-py2.6.egg', '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python26.zip', '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6', '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/plat-darwin', '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/plat-mac', '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/plat-mac/lib-scriptpackages', '/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python', '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/lib-tk', '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/lib-old', '/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/lib-dynload', '/Library/Python/2.6/site-packages', '/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/PyObjC', '/System/Library/Frameworks/Python.framework/Versions/2.6/Extras/lib/python/wx-2.8-mac-unicode']

    [VI]vim笔记

    常用键
    . 重复上一个命令
    ctrl G 显示当前文件名等信息
    去除^M %s/^M//g
    ^M = ctrl v+ ctrl M

    移动
    w,b 向右/左移动一个单词
    ctrl f,ctrl b 向下/向上翻页
    % 移动至匹配的括号
    fc,Fc 向右/左移动至下一个字符c
    tc,Tc 向右/左移动至一下个字符c

    删除
    dm 删除至移动指令m所到达的地方
    di{, di} 删除当前配对的{}间所有内容
    di(, di) 删除当前配对的()间所有内容


    缩进
    >> Indent line by shiftwidth spaces
    << De-indent line by shiftwidth spaces
    5>> Indent 5 lines
    5== Re-indent 5 lines
    >% Increase indent of a braced or bracketed block (place cursor on brace first)
    =% Reindent a braced or bracketed block (cursor on brace)
    <% Decrease indent of a braced or bracketed block (cursor on brace)
    ]p Paste text, aligning indentation with surroundings
    =i{ Re-indent the 'inner block', i.e. the contents of the block
    =a{ Re-indent 'a block', i.e. block and containing braces
    =2a{ Re-indent '2 blocks', i.e. this block and containing block
    >i{ Increase inner block indent
    <i{ Decrease inner block indent
    Block Visual
    ctrl+v 进入 Block Visual 模式;
    用方向键控制在几行作业;
    I 进入插入模式, 键入插入内容;
    esc返回,这样插入的内容被应用于选中的每一行
    d 删除选中的区域

    如果发现无法实现上述功能,很可能是没有装完全的vim
    在ubuntu或者debian下,可以

    $ sudo apt-get install vim-full

    编辑模式下使用上下左右键
    :set nocp
    或者在${HOME}/.vimrc中加入
    set nocp

    加密码
    vim -x filename
    更换密码:
    vim +X filename

    常用${HOME}/.vimrc的设置
    • set expandtab: 把tab置换为space
    • set ts=4: 设置tabstop为4
    • set tw=0: 设置textwidth。 一行长度超过textwidth的时候会添加line break。为0的话disable这个功能
    • set showmode: 显示当前vi工作在什么模式下
    • set nocompatible: 抛弃和vi兼容性.通常如果在插入等模式下用方向键出来ABCD之类的字母,就这样设置
    • .vimrc中, 如果要注释一行,使用双引号"


    打开多个文件和在其中移动
    使用tab (http://vim.wikia.com/wiki/Using_tab_pages)
    • :tabe filename 在新tab中打开另一个文件
    • :tabs 查看所有tabs
    • :tabc 关闭当前tab
    • :tabc {i} 关闭第i个tab
    • gt 上一个tab
    • gT 下一个tab

    切割屏幕
    :split
    :split filename
    :vsplit
    :vsplit filename
    在窗格间切换
    ctrl-W 上/下


    VIM Quick Reference
    VIM tips and tricks

    Friday, September 12, 2008

    [Python]用Pylab给Paper画图

    之前写paper 画图一般都用Matlab画图。因为Matlab的plot可以生成eps格式的图片。但是最近都是用Python的pylab包来画图。原因是一般用在paper里的eps文件插在paper里通常都显得字比较小,需要调整线宽和字体大小。手动在matlab的figure编辑界面里自然可以修改,但每次都要做同样的工作非常令人厌烦。或者可以在matlab画图的源文件里加上比如 plot(...., "linewidth", 2)之类的语句, 但是当画图的语句一多起来,这样也很麻烦。所以我觉得用pylab来画图更加方便。pylab的绘图语句和matlab有高度的兼容性。另外python强大的文件处理和字符串处理能力正是matlab的软肋。

    使用pylab画图的时候, 可以事先用 rcParams 来改变默认的线宽、图例的字体大小、x,y轴的label和tick的字体大小。

    rcParams['lines.linewidth']=2
    rcParams['legend.fontsize']=16
    rcParams['axes.labelsize']=14
    rcParams['xtick.labelsize']=14
    rcParams['ytick.labelsize']=14

    后面就用普通的plot函数(用法和matlab一样)来画图。再有就是可以用savefig来直接存成eps文件。

    Friday, September 05, 2008

    [Python]用Python开发Firefox扩展:1 准备工作

    - 准备好你的Firefox
    既然是为Firefox做extension,自然少不了用Firefox来调试啊之类的。这样也免不了把它弄崩溃。呵呵 我还在试验helloworld的时候就把Firefox弄得无法启动了。其实Firefox非常体贴的提供了多profile启动的功能。用
    firefox   -ProfileManager
    来启动,这样可以添加、删除firefox的profile。平时我们用的都是default的profile。我们就可以添加一个dev的profile。这样启动的时候firefox会提供选择使用哪个profile。所有对firefox做出的更改,比如字体啊,插件啊,扩展啊,都是限定在你使用的profile内。所以一旦调试的时候出了问题,我们只需要删除相应的profile就好了而不会影响平时的上网和使用。

    Firefox的Profile 文件依据操作系统不同而处于不同的路径下,具体可以参见这里

    - 编译PyXPCOM
    有关编译PyXPCOM请参见这里. 简单说来,你需要从源码编译mozilla套件(而不仅仅是 Firefox)。编译的时候需要在makefile里加入相对应的选项 (ac_add_options --enable-extensions=python/xpcom,default)。做好准备:编译需要很长时间,你可以睡觉前开始。