醉里且贪欢笑,要愁那得工夫。近来始觉古人书,信着全无是处。 昨夜松边醉倒,问松“我醉何如”。只疑松动要来扶,以手推松曰:“去”!

2007年4月27日星期五

YUM指南

yum是什么


  • yum = Yellow dog Updater, Modified

  • 主要功能是更方便的添加/删除/更新RPM包.
  • 它能自动解决包的倚赖性问题.
  • 它能便于管理大量系统的更新问题

yum特点


  • 可以同时配置多个资源库(Repository)
  • 简洁的配置文件(/etc/yum.conf
  • 自动解决增加或删除rpm包时遇到的倚赖性问题
  • 使用方便
  • 保持与RPM数据库的一致性

yum安装



  • CentOS自带(yum-*.noarch.rpm)

 #rpm -ivh yum-*.noarch.rpm

  • 在第一次启用yum之前首先需要导入系统的RPM-GPG-KEY:

 #rpm --import /usr/share/doc/centos-release-3(4)/RPM-GPG-KEY-CentOS-3(4)

yum指令


  • 注:当第一次使用yum或yum资源库有更新时,yum会自动下载所有所需的headers放置于/var/cache/yum目录下,所需时间可能较长.


rpm包的更新


  • 检查可更新的rpm包

 #yum check-update

  • 更新所有的rpm包

 #yum update 

  • 更新指定的rpm包,如更新kernel和kernel source


 #yum update kernel kernel-source 

  • 大规模的版本升级,与yum update不同的是,连旧的淘汰的包也升级

 #yum upgrade 




rpm包的安装和删除


  • 安装rpm包,如xmms-mp3


 #yum install xmms-mp3 

  • 删除rpm包,包括与该包有倚赖性的包

 #yum remove licq 

  • 注:同时会提示删除licq-gnome,licq-qt,licq-text

yum暂存(/var/cache/yum/)的相关参数


  • 清除暂存中rpm包文件


 #yum clean packages 

  • 清除暂存中rpm头文件

 #yum clearn headers 

  • 清除暂存中旧的rpm头文件

 #yum clean oldheaders 

  • 清除暂存中旧的rpm头文件和包文件

 #yum clearn 或#yum clearn all 


  • 注:相当于yum clean packages + yum clean oldheaders




包列表


  • 列出资源库中所有可以安装或更新的rpm包

 #yum list 

  • 列出资源库中特定的可以安装或更新以及已经安装的rpm包


 #yum list mozilla 
#yum list mozilla*

  • 注:可以在rpm包名中使用匹配符,如列出所有以mozilla开头的rpm包

  • 列出资源库中所有可以更新的rpm包

 #yum list updates 

  • 列出已经安装的所有的rpm包

 #yum list installed 

  • 列出已经安装的但是不包含在资源库中的rpm包


 #yum list extras 

  • 注:通过其它网站下载安装的rpm包

rpm包信息显示(info参数同list)


  • 列出资源库中所有可以安装或更新的rpm包的信息

 #yum info 

  • 列出资源库中特定的可以安装或更新以及已经安装的rpm包的信息


 #yum info mozilla 
#yum info mozilla*

  • 注:可以在rpm包名中使用匹配符,如列出所有以mozilla开头的rpm包的信息

  • 列出资源库中所有可以更新的rpm包的信息

 #yum info updates 

  • 列出已经安装的所有的rpm包的信息

 #yum info installed 

  • 列出已经安装的但是不包含在资源库中的rpm包的信息


 #yum info extras 

  • 注:通过其它网站下载安装的rpm包的信息

搜索rpm包


  • 搜索匹配特定字符的rpm包

 #yum search mozilla 

  • 注:在rpm包名,包描述等中搜索


  • 搜索有包含特定文件名的rpm包

 #yum provides realplay 

增加资源库


  • 例如:增加rpm.livna.org作为资源库

  • 安装Livna.org rpms GPG key

 #rpm --import http://rpm.livna.org/RPM-LIVNA-GPG-KEY 


  • 检查GPG Key

 # rpm -qa gpg-pubkey* 

  • 显示Key信息

 #rpm -qi gpg-pubkey-a109b1ec-3f6e28d5 

  • (注:如果要删除Key,使用#rpm -e gpg-pubkey-a109b1ec-3f6e28d5)

2007年4月26日星期四

多个文件中查找替换字符串


任务
:在一个目录下做替换动作 "editor" 全部替换成 "emacs"

方案:用EMACS分为三步:

1)标记(mark)目标文件

  • 忽略

2)查找替换


  • M-x dired-do-query-replace-regexp
  • Query replace regexp in marked files :
  • editor (被替换字符串)
  • Query replace regexp in marked files String with:
  • emacs(替换字符串)
  • y 替换当前
  • !替换所有
  • n忽略当前
  • C-g取消操作

3)保存文件


  • M-x ibuffer
  • * u (标记所有没有保存的文件)
  • S (保存)

2007年4月25日星期三

慢慢改变的生活

对新知识,新方法的追求,以及源力的暗吸引,将是生活乐趣的导向.

EMACS NOTES

符号 C- 意思是按住 Ctrol 键


M- 意指 Meta 键 (键盘上若无Meta 键,则可以ALT ESC 键来取而代之)


DEL 意指退格键 (不是 删除(Delete) key)

RET 意指回车键

SPC 意指空格键

ESC 意指Escape键


TAB 意指Tab键


像 "C-M-" (or "M-C") 这样连在一起的意味着同时按住 Control 和 Meta 键不放.


用方向键
C-p 、 C-b 、 C-f 和 C-n 这四个命令。它们的功能和方向键是一样的,如下图所示:

上一行 C-p (Prev line)
.
.
.
向左移 C-b .... 。.... 向右移 C-f (Forward character)
(Backward ) .
.
.
下一行 C-n (Next line)

“P N B F”四个字母分别代表了四个词,用这四个词记忆这些组合键会更容易:
P 代表 previous(上一行),
N 代表 next(下一行),
B 代表 backward(回
退),
F 则代表 forward(前进)


进入Emacs
要进入GNU Emacs,只需键入它的名字 emacs
离开Emacs
挂起Emacs: C-z
永久离开Emacs C-x C-c

文件
读取文件到Emacs C-x C-f
保存文件到磁盘 C-x C-s
保存所有文件 C-x s
插入其它文件的内容到当前缓冲 C-x i
用将要读取的文件替换当前文件 C-x C-v
将当前缓冲写入指定的文件 C-x C-w
Version control checkin/checkout C-x C-q

取得帮助
进入帮助系统很简单,只需要输入C-h(或F1)并跟随要获取帮助的对象,初次使用Emacs的用户可以输入C-h t进入使用手册
离开帮助窗口 C-x 1
滚动帮助窗口 C-M-v
匹配:显示与字符a串匹配的命令 C-h a
显示一个键的功能 C-h c
详细描述一个功能 C-h f
取得详细模式的信息 C-h m

错误恢复
取消当前要执行的命令 C-g
恢复系统崩溃后丢失的文件 M-x recover-file
撤销更新 C-x u或C-_
使缓冲回复到初始内容 M-x revert-buffer
Redraw garbaged scree n C-l
增量查找(Incremental Search)
向前查找 C-s
向后查找 C-r
规则表达式查找 C-M-s
反向规则表达式查找 C-M-r
选择前一个查找字符串 M-p
选择下一个查找字符串 M-n
退出增量查找 RET
取消上一个字符的作用 DEL(Backspace)
退出当前查找模式 C-g
在查找的过程中可重复使用C-s和C-r来改变查找方向

移动(Motion)
向前一个字符 C-f
向后一个字符 C-b
向前一个字 M-f
向后一个字 M-b
向上一行 C-p
向下一行 C-n
到行首 C-a
到行尾 C-e
到句首 M-a
到句尾 M-e
到段首 M-{
到段尾 M-}
到页首 C-x [
到页尾 C-x ]
到表达式首部 C-M-f
到表达式尾部 C-M-b
到函数首部 C-M-a
到函数尾部 C-M-e
到缓冲首部 M-<
到缓冲尾部 M->
滚动到下一屏 C-v
滚动到上一屏 M-v
滚动到右边一屏(内容向左移动) C-x <
滚动到左边一屏(内容向右移动) C-x >
滚动当前行到屏幕中央 C-u C-l

Killing和Deleting
向前delete字符 C-d
向后delete字符 DEL(Backspace)
向前delete到字首 M-d
向后delete到字尾 M-DEL(Backspace)
向前delete到行首 M-0 C-k
向后delete到行尾 C-k
向前delete到句首 C-x DEL(Backspace)
向后delete到句尾 M-k
向前delete到表达式首部 M-- C-M-k
向后delete到表达式尾部 C-M-k
Kill区域 C-w
拷贝区域到Kill Ring M-w
Kill到下一个给定字符出现的位置 M-z <char>
拉回(yank)上次kill的内容 C-y
用更早kill的内容取代拉回的上次kill的内容 M-y

标记(Marking)
标记当前位置 C-SPC或C-@
以字符为单位使用移动命令动态标记区域 C-x C-x
以字为单位使用移动命令动态标记区域 M-@
标记一段 M-h
标记一页 C-x C-p
标记一个表达式 C-M-@
标记一个函数 C-M-h
标记整个缓冲区 C-x h

Query Replace
交互式地替换一个文本串 M-%
交互式地替换一个规则表达式 M-x query-replace-regexp
替换当前的并移动到下一处 SPE
替换当前的但不移动到下一处 ,
不替换当前的并移动到下一处 L(Backspace)
替换所有剩下的符合条件的文本 !
退出替换模式 RET
进入递归的编辑模式 C-r
退出递归的编辑模式 C-M-c

多窗口(Multiple Windows)
(When two commands are shown,the second is for “other frame”)
删除所有其它窗口 C-x 1
上下分割当前窗口 C-x 2 C-x 5 2
左右分割当前窗口 C-x 3
删除当前窗口 C-x 0 C-x 5 0
滚动其它窗口 C-M-v
切换光标到另一个窗口 C-x o
选择另一个窗口中的缓冲 C-x 4 b C-x 5 b
显示另一个窗口中的缓冲 C-x 4 C-o C-x 5 C-o
在另一窗口中查找并打开文件 C-x 4 f C-x 5 f
在另一窗口中以只读方式打开文件 C-x 4 r C-x 5 r
在另一窗口中运行dired命令 C-x 4 d C-x 5 d
在另一窗口中查找tag C-x 4 . C-x 5 .
增加窗口高度 C-x ^
减小窗口宽度 C-x {
增加窗口宽度 C-x }
格式(Formatting)
缩进当前行(与模式相关) TAB
缩进区域(与模式相关) C-M-
缩进表达式(与模式相关) C-M-q
Indent region rigidly arg. Columns C-x TAB
在光标后插入一个新的行 C-o
静态地将一行下移 C-M-o
删除光标附近的空行(留下一行) C-x C-o
与上一行合并成一行 M-^
删除光标附近的所有空格 M-
删除光标附近的空格(留下一格) M-SPC
Fill paragraph M-q
Set fill column C-x f
设置每一行开始的前缀 C-x .
设置字体 M-g

Case Change
将一个字设置为大写 M-u
将一个字设置为小写 M-l
将一个字首字母设置为大写 M-c
将一个区域设置为大写 C-x C-u
将一个区域设置为小写 C-x C-l

The Minibuffer
(the following keys are defined in the minibuffer)
最大程度地补全命令 TAB
补全命令中的一个字 SPC
完成并执行一个命令 RET
列出命令所有可能的后续部分 ?
列出在当前命令之前输入的命令 M-p
列出在当前命令之后输入的命令 M-n
用规则表达式在命令历史记录中向后搜寻 M-r
用规则表达式在命令历史记录中向前搜寻 M-s
重复执行上一条命令 C-x ESC ESC

缓冲(Buffer)
选择另一个缓冲 C-x b
列出所有的缓冲 C-x C-b
Kill一个缓冲 C-x k

置换(Transposing)
字符置换 C-t
字置换 M-t
行置换 C-x C-t
表达式置换 C-M-t

拼写检查(Spelling Check)
对当前的字进行拼写检查 M-$
检查区域内所有的字 M-x ispell-origin
检查缓冲内所有的字 M-x ispell-buffer

标记 (Tags)
查找标记 M-.
查找标记下一次出现的位置 C-u M-.
指定一个新的标记文件 M-x visit-tags-table
Regexp search on all files in tabs table M-x tags-search
在所有文件中执行查询-替换 M-x tags-query-replace
继续进行上一次标记查找或查询-替换 M-,

Shells
执行一个shell命令 M-!
在一个区域上执行sheel命令 M-|
通过shell命令过滤区域 C-u M-|
在窗口中启动一个shell M-x shell

矩形(Rectangles)
拷贝一个矩形到寄存器 C-x r r
Kill矩形 C-x r k
拉回矩形 C-x r y
打开一个矩形, 将文本移动至右边 C-x r o
清空矩形 C-x r c
为矩形中每一行加上一个字符串前缀 C-x r t

规则表达式(Regular Expressions)
除换行符外的所有单个字符 .
零个或多个重复 *
一个以上的重复 +
零个或一个重复 ?
转译字符
选择(or) |
分组 (…)
与第n个组相同的文本 n
At work break b
Not at work break B

寄存器(Register)
存储区域到寄存器 C-x r s
插入矩形内容到缓冲 C-x r i
存储光标位置到寄存器 C-x r SPC <num>
跳跃到寄存器中存储的光标位置 C-x r j <num>

键盘宏(Keyboard Macros)
开始定义一个键盘宏 C-x (
结束键盘宏的定义 C-x )
执行上一次定义的键盘宏 C-x e
追加到上一个键盘宏 C-u C-x (
为上一个键盘宏命名 M-x name-last-kbd-macro
在缓冲中插入Lisp M-x insert-kbd-macro


Tags
Tags 是一个显为人知的功能? 所以我想提一下. 这不是emacs发明的, 而是vi 原本的特异功能. emacs只是发扬光大而已.

假设你有一个目录, 里面是一个程式的原始码, 比如说, tin 的原始码, 放在 ~/tin-1.3beta 下面. 你想看它们.

首先, 叫emacs cd到该目录:  M-x cd

然后, 建立tag table. tag table 就是一张对照表, 记录哪个符号(variable/function call) 对映到哪个档案的哪个地方. 有这张表, emacs可以让我们快速的在程式码内游走. 一般这张表是一个档案, 叫作TAGS (大写)

  M-! etags *.c

M-! 是执行external shell command的意思. etags就是emacs的建表程式. 你只要告诉它你的source code在那里即可.

vi的话是使用ctags这个程式, 它建出来的档名叫tags (小写). 因为我们介绍emacs, 所以不管它.

然后, 怎么看程式? 你知道所有的C 程式都是由main()开始, 所以你想找到main()在哪个档案. 这时只要按 M-. 然后emacs会问你tag table在哪里. 因为我们已经cd到该目录, 直接按enter就好了. 然后输入main, emacs就会把你带到main(){ ... }去.

如果 你看到某个程式片断呼叫一个你没看过的函式, 你可以把游标移到该函式的名字上, M-. ENTER 就搞定了.

如果 emacs找错了 (比如有变数和函式同名, emacs跳到变数去), 那你可以用 C-u M-. 找下一个.

在编辑程式码的时候, M-SPC 很有用, 它会把游标附近的空白缩成一个. 在其它地方也有效.

拼写检查

当然只是针对英文。

Ispell

选中一块区域,或者对整个编辑缓冲区进行拼写检查: M-x ispell-buffer RET, 这时会打开ispell缓冲区,C-h可以查看一些拼写检查的帮助信息。

检查单词。在一个单词上执行M-$,会对这个单词进行拼写检查。

单词拼写补全。在一个未拼完的单词后执行ESC TAB(M-TAB)。

只要启用过Ispell, 他就将一直在后台运行。M-x ispell-kill-ispell,可以杀死这个进程。

感觉很好用。

flyspell

一个扩展,可以在编辑的时候直接进行拼写检查,也就是spell-check on the fly。它也是利用Ispell。

M-x flyspell-mode RET
Tips

改变buffer的只读属性

M-x toggle-read-only

在C模式下输入tab

C-q TAB : 对TAB不做解释,直接输入

2007年4月12日星期四

SVN (subversion) 目录权限(转)

实现精细的目录访问权限控制










(终于提交正稿了,从开始动笔到现在提交正稿,由于私人原因,整整经过了半年时间方才结束,惭愧!对于那些因为本文的错误而走了弯路的网友们,本人深表歉意。
非常感谢各位读者的关注,在这半年时间里面,正是各位的支持,才让我鼓起勇气,持续着将文章写完。
本人其实就是个业余爱好者,不是专业人士,因此文章里面的错误在所难免,希望各位斧正,以免让我混淆视听。)



================
Subversion之路
================
----------------------------
实现精细的目录访问权限控制
----------------------------


:作者: 郑新星
:联系: zhengxinxing <AT> gmail <DOT> com
:状态: 正稿
:版本: 1.0
:修订: $Id: The.Road.to.Subversion_authz.rst 1749 2006-12-05 08:05:59Z zhengxinxing $
:版权: 作者保留对本文的一切修改、发布等权力。任何人想要转载本文部分或全部内容时,必须保留包括作者、联系、状态、版本、修订、版权,共六项信息,并给出出处。对本文的参考引用,则不受限制。

:关键词: Subversion 目录访问 权限

:献辞:

仅以本文,献给中国广大的自由软件爱好者们

:摘要:

本文从一个实际的例子入手,介绍了如何利用 Subversion 自带的目录管理功能,来实现对项目目录的精细访问权限的控制。同时描述了在配置的过程中,需要注意的一些地方,如对中文的处理等。


.. section-numbering::
.. contents:: 目 录
:backlinks: top



前言
====

Subversion 权限简介
-------------------

在 Subversion 的使用当中,存在“认证”、“授权”两个概念。认证,即 authentication,是指用户名与密码的认证。授权,即 authorization ,是指某用户对某个目录是否具备读、写权限的一种审核。这两者配合作用,就组成了 Subversion 的整个帐户管理体系。

在实际的工作当中,我们有时候会遇见需要控制项目目录的访问权限的情况,比如说对项目的一些关键模块进行限制,仅允许少数授权人士才可以修改等。由于项目的目录本身就是作为版本库的一个部分被 Subversion 所收管,所以我们无法利用操作系统的帐户权限体系,来实现授权控制。因此,这个问题就只有让svn自己来解决了。

Subversion 提供了面向目录的帐户权限管理功能,通过它,我们就可以很精确地实现项目目录的访问控制。不过在 1.2 及其以前的版本,我们只能利用 mod_authz_svn.so 模块,结合 Apache 服务器来实现目录访问控制,这对于对 Apache 的配置与使用不是很熟悉的人来说,就不是很方便了。而Subversion终于在 1.3 版本上,在 svnserve.exe 服务器里面添加了这一功能,方便了很多人。


其他信息
--------

本文面向那些 Subversion 的管理员,或者任何对 Subversoin 有兴趣的人们。本文假定读者对Subversion有一定的了解,因此不打算对所有涉及到的安装、使用,做一个细节性的描述。若对于文章中描述的其他细节方面有所疑问,请访问“参考文献”一节里面的参考资料。如果你对本文任何地方有什么意见,或者发现本文有着大大小小的错误,请联系 zhengxinxing <AT> gmail <DOT> com 。


本文是基于 Subversion 1.3.2、MS Windows 2003 Server Edition 平台来编写的,且 Subversion 服务器是利用 svnserve.exe 来架设的。不过,本文讲述到的绝大多数内容,都是不仅与操作系统平台无关,而且与是采用 svnserve(.exe) 还是使用 Apache 来作为 Subversion 服务器也基本无关。因此为免罗嗦,本文就以 svnserve(.exe) 为例进行描述,而略过 Apache 服务器相关的内容,有兴趣的读者可以参考其他文章来在 Apache 服务器下实现类似的功能。

本文是利用 reST 格式来编写的,如果你对它感兴趣,请访问 http://docutils.sourceforge.net/rst.html 。如果想要看到更好的html格式,你可以通篇复制本文到一个文本文件里,然后利用 docutils 的 rst2html.py 脚本编译它,当然,首先你必须安装 python。

本文的获得方式:

- 原始发布点: http://iusesvn.com/bbs/thread-6-1-1.html
- 完整源文件,请利用 svn 命令来获取,命令为 ``svn co svn://cvs.woodpecker.org.cn/woodpecker/zqlib/tangle/michael.zheng/road2svn``
- HTML版式文件,请访问 http://zhengxinxing.googlepages. ... bversion_authz.html (推荐) 或 http://swjr.blog.com.cn/archives ... version1authz.shtml



致谢
====

非常感谢 iusesvn.com 站的站长 PCplayer ,他在本文编写过程中,给我提出了很多宝贵的意见与建议。

感谢 woodpecker.org.cn 提供的 Subversion 空间,让更多的人可以通过 svn 获得本文件。

感谢 google 公司提供的免费主页空间,让我可以放置完全定制的 HTML 文件。


实战
====

本章先直接给出需求及其最终的结果,如果你觉得对配置有什么疑问,或者看不懂,请不要着急,我会在后面的章节详细描述的。


背景假设
--------

厦门央瞬公司是一家电子元器件设备供应商,其中有个ARM部门,专门负责ARM芯片的方案设计、销售,并在北京、上海各设立了一个办事处。对于工作日志,原先采用邮件方式发给经理,但是这种方式有个缺点,那就是不具备连续性,要看以前的日志必须一封一封邮件去查看,很麻烦。于是就想到利用 Subversion, 让员工在自己电脑上编辑日志,然后利用svn传送回来,既方便员工自己编写日志,又方便对日志的归档处理,而且提交日志的时候只需要执行一下 svn commit 即可,比发送邮件还要简单的多。

- svn服务器相关信息

- 服务器地址: 192.168.0.1
- 服务器OS: MS Windows 2000 Server Edition 中文版
- 用于存放日志的代码库本地目录: ``D:\svn\arm``

- arm部门文档的目录结构如下::

arm 部门名称
├─diary 工作日志目录
│ ├─headquarters 总部工作日志目录
│ ├─beijing 北京办日志目录
│ └─shanghai 上海办日志目录
├─ref 公司公共文件参考目录
└─temp 临时文件目录

- 人员情况

- morson,公司总经理,不习惯使用电脑,更喜欢传统的纸与笔,以及面对面的交流
- michael,arm事业部的部门经理,没事的时候喜欢弄点儿新技术,用svn来管理日志,就是他想出来的主意
- scofield,北京办人员,老员工,为人油滑难管
- lincon,上海办人员,老员工,大老实人一个
- linda,总部协调员、秘书,文笔不错,长得也不错
- rory,单片机技术员,技术支持

- 访问权限需求分析

- 允许总经理、部门经理读取所有文件。顺便给他们开放写权限,以便体现对他们职位的尊重,虽然对于某些文件来说,他们若拥有“写”权限其实也没什么用处
- 除部门经理外,所有其他人员,均只能看到本办事处人员工作日志
- 不允许匿名访问
- ref目录只允许经理和秘书读写,对其他人只读
- temp目录人人都可以随意读写


使用 svnserve.exe 作为 Subversion 服务器
----------------------------------------
本节描述如何利用 svnserve.exe 来作为代码库服务器端,实现上述功能。至于另外一种代码库服务器端,即利用 Apache 结合 mod_dav_svn.so 来实现的代码库服务器端,由于其对于本文叙述的内容“实现精细的目录访问权限控制”而言,与前者没有太大的区别,故而略过不提。它们二者只是在初次安装、配置方面存在一些不同,有兴趣的读者,可以参考其他文档,重新实验下述步骤。


启动 Subversion 服务
````````````````````
在服务器端,打开一个命令行窗口,用CD命令进入 Subversion 安装目录下的 bin 目录,运行如下指令::

svnserve -d -r d:\svn

其中的 -d 参数表示 svnserve.exe 将会作为一个服务程序运行在后台,而 -r 参数表示将 ``D:\svn`` 目录指定为代码库的根目录。这样,当客户端使用类似 svn://192.168.0.1/foo 这样内容的 URL 来访问服务器时候,其所访问到的真实代码库,其实就是 ``D:\svn\foo``

用上述命令行方式启动的 svn 服务有个小缺点,就是在本试验过程中,服务器端必须要一直开着那个运行了上述命令的DOS窗口,不能关闭它。如果不想看到这个窗口,可以将 svnserve 安装成 windows 的一个 services,安装方式请参考其他文章。


建立代码库
``````````
在服务器端的 ``D:\svn`` 目录下,建立一个名为 arm 的代码库,命令如下::

D:\svn>svnadmin create arm

使用上述命令之后,如果不出问题的话,在 ``D:\svn`` 目录下就会多出一个叫做 ``arm`` 的目录,其下具备 conf、dav、hooks、locks、db 等子目录或文件,此即 **一个名为arm的代码库** 。从此,通过 ``svn://192.168.0.1/arm`` 这样的 URL,我们就可以对这个代码库进行访问了。接下来就要进入本文的正题了,也就是权限配置部分了。

其实进入 ``arm\conf`` 目录你就会发现,它下面已经存在三个写了一些帮助信息和示例的配置文件,以帮助用户尽早掌握其配置方法。这三个默认的配置文件分别是 svnserve.conf、passwd、authz 。其中后两者没有后缀,对于 windows 系统的用户来说,看起来总是有些怪异,所以在接下来的章节里面,我将它们两个都给添加了个 conf 后缀,以便管理。


编辑代码库基础配置文件
``````````````````````
在服务器端,编辑代码库的 ``arm\conf\svnserve.conf`` 文件,如下::

[general]
password-db = passwd.conf
anon-access = none
auth-access = write
authz-db = authz.conf


管理用户帐号
````````````
在服务器端,新建 ``arm\conf\passwd.conf`` 文件,如下::

[users]
morson = ShowMeTheMoney
michael = mysecretpassword
scofield = hellolittilekiller
lincon = asyouknows111
rory = 8809117
linda = IlikeWorldCup2006


建立目录访问权限控制文件
````````````````````````
在服务器端,新建 ``arm\conf\authz.conf`` 文件,内容如下::

[groups]
g_vip = morson
g_manager = michael
g_beijing = scofield
g_shanghai = lincon
g_headquarters = rory, linda
g_docs = linda

[arm:/]
@g_manager = rw
* = r

[arm:/diary/headquarters]
@g_manager = rw
@g_headquarters = rw
@g_vip = r
* =

[arm:/diary/beijing]
@g_manager = rw
@g_beijing = rw
@g_vip = r
* =

[arm:/diary/shanghai]
@g_manager = rw
@g_shanghai = rw
@g_vip = r
* =

[arm:/ref]
@g_manager = rw
@g_docs = rw
* = r

[arm:/temp]
* = rw


导入代码
````````
在客户机 ``F:\temp`` 目录下,建立好前述“背景假设”一节中描述的目录结构,然后用命令 ``F:\temp>svn import arm svn://192.168.0.1/arm --username michael --password mysecretpassword`` 导入整个目录结构。

这条指令的精确意思是,将 arm 目录下面的所有东西,导入到那个名叫 arm 的代码库中去。如果你不指定源目录,则 svn 会默认将当前目录作为源目录。比如说,你处于 ``F:\temp`` 目录下的时候,直接执行 ``svn import svn://192.168.0.1/arm`` ,那么当你取出你的代码的时候,你会发现,居然多了一层名为 arm 的目录。结果,你就必须使用类似 ``svn://192.168.0.1/arm/arm`` 这样怪异的URL,才能够正确访问到你的代码们。

这一点粗看好像不是特别重要,不过联想到前述的目录授权规则,可都是按照标准的项目目录结构来设计的。突然之间,你项目的根目录之上,多出了一个名为 arm 的目录,那么我们的所有目录授权规则,基本上都要全部改过了,否则除了根目录,你永远会得到一个莫名其妙的“access denied”。由于 Subversion 在这一步骤上的界面不够人性化,因此这是初学者很容易弄混的地方之一。


测试
````
在服务器上,打开一个 DOS Prompt 窗口,输入如下指令::

svn co svn://127.0.0.1/arm --no-auth-cache --username rory --password 8809117

我们应该得到如下目录结构::

arm
├─diary
│ └─headquarters
├─ref
└─temp

然后修改ref目录下任意文件并提交,服务器将会报错“Access denied”,Bingo!


深入
====

本章将详细介绍前一章所涉及的两个配置文件, svnserve.conf 和 authz.conf,通过对配置逐行的描述,来阐明其中的一些细节含义。除此之外的其他配置、安装等内容,不是本文重点,读者若有什么疑问,请参考后面“参考文献”中列出的一些文档。

这里首先要注意一点,任何配置文件的有效配置行,都 **不允许存在前置空格** ,否则程序可能会出错,给你一个 ``Option expected`` 的提示。也就是说,如果你直接从本文的纯文本格式中拷贝了相关的配置行过去,需要手动将前置的4个空格全部删除。当然了,如果你觉得一下子要删除好多行的同样数目的前置空格是一件苦差使,那么也许 UltraEdit 的“Column Mode”编辑模式,可以给你很大帮助。


svnserve.conf
-------------

``arm\conf\svnserve.conf`` 文件,是 svnserve.exe 这个服务器进程的配置文件,我们逐行解释如下。

首先,我们告诉 svnserve.exe,用户名与密码放在 passwd.conf 文件下。当然,你可以改成任意的有效文件名,比如默认的就是 passwd::

password-db = passwd.conf

接下来这两行的意思,是说只允许经过验证的用户,方可访问代码库。 那么哪些是“经过验证的”用户呢?噢,当然,就是前面说那些在 passwd.conf 文件里面持有用户名密码的家伙。这两行的等号后面,目前只允许 read write none 三种值,你如果想实现一些特殊的值,比如说“read-once”之类的,建议你自己动手改源代码,反正它也是自由软件::

anon-access = none
auth-access = write

接下来就是最关键的一句呢,它告诉 svnserve.exe,项目目录访问权限的相关配置是放在 authz.conf 文件里::

authz-db = authz.conf

当然,svn 1.3.2 引入本功能的时候,系统默认使用 authz 而不是 authz.conf 作为配置文件。不过可能由于鄙人是处女座的,据说有着强烈的完美主义情结,看着 svnserve.conf 有后缀而 passwd 和 authz 没有就是不爽,硬是要改了。

上述的 passwd.conf 和 authz.conf 两个文件也可以作为多个代码库共享使用,我们只要将它们放在公共目录下,比如说放在 ``D:\svn`` 目录下,然后在每个代码库的 svnserve.conf 文件中,使用如下语句::

password-db = ..\..\passwd.conf
authz-db = ..\..\authz.conf

或者::

password-db = ../../passwd.conf
authz-db = ../../authz.conf

这样就可以让多个代码库共享同一个用户密码、目录控制配置文件,这在有些情况下是非常方便的。


authz.conf 之用户分组
---------------------

``arm\conf\authz.conf`` 文件的配置段,可以分为两类, ``[group]`` 是一类,里面放置着所有用户分组信息。其余以 ``[arm:/]`` 开头的是另外一类,每一段就是对应着项目的一个目录,其目录相关权限,就在此段内设置。

首先,我们将人员分组管理,以便以后由于人员变动而需要重新设置权限时候,尽量少改动东西。我们一共设置了5个用户分组,分组名称统一采用 ``g_`` 前缀,以方便识别。当然了,分组成员之间采用逗号隔开::

[groups]
# 任何想要查看所有文档的非本部门人士
g_vip = morson

# 经理
g_manager = michael

# 北京办人员
g_beijing = scofield

# 上海办人员
g_shanghai = lincon

# 总部一般员工
g_headquarters = rory, linda

# 小秘,撰写文档
g_docs = linda

注意到没有, linda 这个帐号同时存在“总部”和“文档员”两个分组里面,这可不是我老眼昏花写错了,是因为 Subversion 允许我这样设置。它意味着,这个家伙所拥有的权限,将会比他的同事 rory 要多一些,这样的确很方便。具体多了哪些呢?请往下看!


authz.conf 之项目根目录
-----------------------

接着,我们对项目根目录做了限制,该目录只允许arm事业部的经理才能修改,其他人都只能眼巴巴的看着::

[arm:/]
@g_manager = rw
* = r

- ``[arm:/]`` 表示这个目录结构的相对根节点,或者说是 arm 项目的根目录。其中的 arm 字样,其实就是代码库的名称,即前面用 svnadmin create 命令创建出来的那个 arm。

- 这里的 ``@`` 表示接下来的是一个组名,不是用户名。因为目前 g_manager 组里面只有一个 michael,你当然也可以将 ``@g_manager = rw`` 这一行替换成 ``michael = rw`` ,而表达的意义完全一样。

- ``*`` 表示“除了上面提到的那些人之外的其余所有人”,也就是“除了部门经理外的其他所有人”,当然也包括总经理那个怪老头

- ``* = r`` 则表示“那些人只能读,不能写”


authz.conf 之项目子目录
-----------------------

然后,我们要给总部人员开放日志目录的读写权限::

[arm:/diary/headquarters]
@g_manager = rw
@g_headquarters = rw
@g_vip = r
* =

这个子目录的设置有些特色,因为从需求分析中我们知道,这个子目录的权限范围要比其父目录小,它不允许除指定了的之外其他任何人访问。在这段设置中,我们需要注意以下几点:

- 我敢打赌,设计svn的家伙们,大部分都是在类 unix 平台下工作,所以他们总喜欢使用 ``/`` 来标识子目录,而完全忽视在 MS Windows 下是用 ``\`` 来做同样的事情。所以这儿,为了表示 ``diary\headquarters`` 这个目录,我们必须使用 ``[arm:/diary/headquarters]`` 这样的格式。当然如果你一定要用 ``\`` ,那么唯一的结果就是,Subversion 会将你的这部分设置置之不理,全当没看到。

- 这里最后一行的 ``* =`` 表示,除了经理、总部人员、特别人士之外,任何人都被禁止访问本目录。这一行是否可以省略呢?不行,因为 **权限具备继承性** ,子目录会自动拥有父目录的权限。若没有这一行,则所有帐号都可以读取 ``/diary/headquarters`` 目录下的文件。因为虽然我们并没有设置这个目录的父目录权限,可是默认的规则使得 ``/diary`` 目录的权限与根目录完全一样,从而让其余帐号获得对 ``/diary/headquarters`` 目录的 r 权限。所以简单来说, ``* =`` 这一句的目的,就是割断权限继承性,使得管理员可以定制某个目录及其子目录的权限,从而完全避开其父目录权限设置的影响。

- 之所以这儿需要将 ``@g_vip = r`` 一句加上,就是因为存在上述这个解释。如果说你没有明确地给总经理授予读的权力,则他会和其他人一样,被 ``* =`` 给排除在外。

- 如果众位看官中间,有谁玩过防火墙配置的话,可能会感觉上述的配置很熟悉。不过这里有一点与防火墙配置不一样,那就是各个配置行之间,没有 **先后顺序** 一说。也就是说,如果我将本段配置的 ``* =`` 这一行挪到最前面,完全不影响整个配置的最终效果。

接下来我们看看这一段::

[arm:/ref]
@g_manager = rw
@g_docs = rw
* = r

这里的主要看点,就是 g_docs 组里面包含了一个 linda 帐号,她也同时在 g_headquarters 组里面出现,这就意味着, linda 将具备对 ``/ref`` 和 ``diary\headquarters`` 两个目录的读写权限。


authz.conf 之目录表示法
-----------------------
在前面的描述中,我们都采用 ``[repos:/some/dir]`` 这样的格式来表示项目的某个目录,比如上一小节中的 ``[arm:/diary/headquarters]`` 。而实际上,Subversion 允许你采用 ```[/some/dir]`` 这样的格式,即不指定代码库的方式来表示目录,此时的目录就匹配所有项目。

对于使用 svnserve 的用户来说,只有当 svnserve 运行的时候使用了 ``-r`` 参数,并且让多个代码库共享同一个目录权限文件(即 authz.conf 或 authz)时,不指明代码库名称才有可能惹麻烦。一般情况下,我们对每个代码库都会独立使用配置文件,毕竟每个项目的目录结构,都有很大不同,混在一起意义不大。因此一般来说,为简洁起见,都可以不指明代码库名称。本文全都指明了代码库名称,主要是为了将来扩展成同一个配置文件,以方便配合 Apache 服务器。

对于使用 Apache 的用户来说,它们二者可有着很大的不同,因为此时往往习惯于使用一个公共的目录权限配置文件。如果你使用了 SVNParentPath 指令,则指定版本库的名字是很重要的,因为假若你使用后者,那么 ``[/some/dir]`` 部分就会与所有代码库项目的 ``[/some/dir]`` 目录匹配。如果你使用 SVNPath 指令,则这两种表示方式就没有什么区别了,毕竟只有一个版本库。


authz.conf 的其他注意点
-----------------------

1. 父目录的 ``r`` 权限,对子目录 ``w`` 权限的影响

把这个问题专门提出来,是因为在1.3.1及其以前的版本里面,有个bug,即某个帐号为了对某个子目录具备写权限,则必须对其父目录具备读权限。因此现在使用了1.3.2及其更高的版本,就方便了那些想在一个代码库存放多个相互独立的项目的管理员,来分配权限了。比如说央舜公司建立一个大的代码库用于存放所有员工日志,叫做 diary,而arm事业部只是其中一个部门,则可以这样做::

[diary:/]
@g_chief_manager = rw

[diary:/arm]
@g_arm_manager = rw
@g_arm = r

这样,对于所有arm事业部的人员来说,就可以将 svn://192.168.0.1/diary/arm 这个URL当作根目录来进行日常操作,而完全不管它其实只是一个子目录,并且当有少数好奇心比较强的人想试着 checkout 一下 svn://192.168.0.1/diary 的时候,马上就会得到一个警告“Access denied”,哇,太酷了。


2. 默认权限

如果说我对某个目录不设置任何权限,会怎样?马上动手做个试验,将::

[diary:/]
@g_chief_manager = rw

改成::

[diary:/]
# @g_chief_manager = rw

这样就相当于什么都没有设置。在我的 svn 1.3.2 版本上,此时是禁止任何访问。也就是说,如果你想要让某人访问某目录,你一定要显式指明这一点。这个策略,看起来与防火墙的策略是一致的。



3. 只读权限带来的一个小副作用

若设置了::

[arm:/diary]
* = r

则 Subversion 会认为,任何人都不允许改动 diary 目录,包括删除、 **改名** ,和 **新增** 。

也就是说,如果你在项目初期创建目录时候,一不小心写错目录名称,比如因拼写错误写成 dairy,以后除非你改动 authz.conf 里面的这行设置,否则无法利用 svn mv 命令将错误的目录更正。


4. anon-access 属性对目录权限的影响

你想将你的代码库开放给所有人访问,于是你就开放了匿名访问权限,在 svnserve.conf 文件中添加一行: ``anon-access=read`` 。可是对于部分目录,你又不希望别人看到,于是针对那些特别目录,你在 authz.conf 里面进行配置,添加了授权访问的人,并添加了 ``* =`` 标记。你认为一切OK了,可是你缺发现,那个特别目录却无法访问了,总是提示 ``Not authorized to open root of edit operation`` 或者 ``未授权打开根进行编辑操作`` 。你再三检查你配置的用户名与密码,确认一切正确,还是无法解决问题。

原来,Subversion 有个小 bug ,当 ``anon-access=read`` 并且某个目录有被设置上 ``* =`` 标记,则会出现上述问题。这个 bug 在当前最新版本上(v1.4)还存在,也许在下一版本内可以被改正吧。

解决的办法是,在 svnserve.conf 中,将 anon-access 设置成 none 。



改进
====

对中文目录的支持
----------------

上午上班的时候,Morson 来到 Michael 的桌子前面,说道:“你是否可以将我们的北京办、上海办目录,改成用中文的,看着那些拼音我觉得很难受?” Michael 心想,还好这两天刚了解了一些与 unicode 编码相关的知识,于是微笑地回答:“当然可以,你明天下午就可以看到中文目录名称了。”

1. 使用 svn mv 指令,将原来的一些目录改名并 commit 入代码库,改名后的目录结构如下::

arm
├─工作日志
│ ├─总部人员
│ ├─北京办
│ └─上海办
├─公司公共文件参考目录
└─临时文件存放处

2. 修改代码库的 authz.conf 文件,将相应目录逐一改名

3. UTF-8 格式的 authz.conf 文件,以及 BOM

将配置文件转换成 UTF-8 格式之后,Subversion 就能够正确识别中文字符了。但是这里需要注意一点,即必须保证 UTF-8 文件不包含 BOM 。BOM 是 Byte Order Mark 的缩写,指 UNICODE 文件头部用于指明高低字节排列顺序的几个字符,通常是 ``FF FE`` ,而将之用 UTF-8 编码之后,就是 ``EF BB BF`` 。由于 UTF-8 文件本身不存在字节序问题,所以对 UTF-16 等编码方式有重大意义的 BOM,对于 UTF-8 来说,只有一个作用——表明这个文件是 UTF-8 格式。由于 BOM 会给文本处理带来很多难题,所以现在很多软件都要求使用不带 BOM 的 UTF-8 文件,特别是一些处理文本的软件,如 PHP、 UNIX 脚本文件等,svn 也是如此。

目前常用的一些文本编辑工具中,MS Windows 自带的“记事本”里面,“另存为”菜单保存出来的 UTF-8 格式文件,会自动带上 BOM 。新版本 UltraEdit 提供了选项,允许用户选择是否需要 BOM,而老版本的不会添加 BOM。请各位查看一下自己常用的编辑器的说明文件,看看它是否支持这个功能。

对于已经存在 BOM 的 UTF-8 文件,比如说就是微软“记事本”弄出来的,我们可以利用 UltraEdit 来将 BOM 去掉。方法是,首先利用“UTF-8 TO ASCII”菜单将文件转换成本地编码,通常是GB2312码,然后再使用“ASCII TO UTF-8(UNICODE Editing)”来转换到 UTF-8 即可。当然,这么操作之前,你肯定得先保证,你的 UltraEdit 保存出来的 UTF-8 文件的确是不带 BOM 的。

Subversion 为什么讨厌 BOM 呢?我不知道,毕竟我也只是一个普通用户,不是开发人员。如果你感兴趣,并且英文够好的话,不妨参考一下这个讨论: http://subversion.tigris.org/ser ... ers&msgNo=51334

参考文献
========
- Subversion官方文档, http://svnbook.red-bean.com
- Subversion 1.3变更记录, http://subversion.tigris.org/svn_1.3_releasenotes.html
- Subversion FAQ, http://subversion.tigris.org/faq.html
- UTF-8 常见问题, http://unicode.org/faq/utf_bom.html

YOUTUBE 引用方法

引入对象脚本即可

A Global Warning...

2007年4月10日星期二

SVM 简易入门(转)

piaip's Using (lib)SVM
Tutorial

piaip 的 (lib)SVM 簡易入門

piaip at csie dot ntu dot edu dot tw,

Hung-Te Lin

Fri Apr 18 15:04:53 CST 2003

$Id: svm_tutorial.html,v 1.12 2005/10/26 06:12:40 piaip Exp piaip $
原作:林弘德,轉載請保留原出處



Why this tutorial is here



我一直覺得 SVM 是個很有趣的東西,不過也一直沒辦法 (mostly 衝堂)
去聽林智仁老師
的 Data mining 跟 SVM 的課;
後來看了一些網路上的文件跟聽 kcwu 講了一下
libsvm
的用法後,就想整理一下,算是對於並不需要知道完整 SVM
理論的人提供使用
libsvm
的入門。 原始 libsvm 的 README 跟 FAQ 也是很好的文件,
不過你可能要先對 svm 跟流程有點了解才看得懂 (我在看時有這樣的感覺);
這篇入門就是為了從零開始的人而寫的。


I've been considering SVM as an interesting and useful tool
but couldn't attend the "Data mining and SVM" course
by prof. cjline about it (mostly due to scheduling conflicts). After reading
some materials on the internet and discussing
libsvm
with some of my classmates and friends
, I wanted to provide some notes here as a tutorial for those who do not need to know the
complete theory behind SVM theory to use
libsvm
. The original README and FAQ files that comes with libsvm are good documents
too. But you may need to have some basic knowledge of SVM and its
workflow (that's how I felt when I was reading them).
This tutorial is specificly for those starting from zero.




後來還有一些人提供意見,所以在此要感謝:

I must thank these guys who provided feedback and helped me make this tutorial:




kcwu, biboshen, puffer, somi



不過請記得底下可能有些說法不一定對,但是對於只是想用 SVM
的人來說我覺得這樣說明會比較易懂。

Remember that some aspect below may not be correct.
But for those who just wish to "USE" SVM, I think
the explanation below is easier to understand.



這篇入門原則上是給會寫基本程式的人看的,也是給我自己一個備忘,
不用太多數學底子,也不用對 SVM 有任何先備知識。

This tutorial is basically for people who already know how to program.
It's also a memo to myself.
Neither too much mathmatics nor prior SVM knowledge is required.




還看不懂的話有三個情形, 一是我講的不夠清楚, 二是你的常識不足,
三是你是小白 ^^;

If you still can't understand this tutorial, there are three possibilities:
1. I didn't explain clearly enough,
2. You lack sufficient common knowledge,
3. You don't use your brain properly ^^;



我自己是以完全不懂的角度開始的,這篇入門也有不少一樣不懂 SVM 的人
看過、而且看完多半都有一定程度的理解,所以假設情況一不會發生,
那如果不懂一定是後兩個情況 :P 也所以, 有問題別問我。

Since I begin writing this myself with no understanding of the subject,
ans this document has been read by many people who also didn't understand SVM
but gained a certain level of understanding after reading it,
possibility 1 can be ruled out.
Thus if you can't understand it you must belong to the latter two categories,
:P thus even if you have any questions after reading this, don't ask me.



SVM: What is it and what can it do for me?




SVM, Support Vector Machine

, 簡而言之它是個起源跟類神經網路有點像的東西,
不過現今最常拿來就是做分類 (classification)。
也就是說,如果我有一堆已經分好類的東西
(可是分類的依據是未知的!) ,那當收到新的東西時,
SVM 可以預測 (predict) 新的資料要分到哪一堆去。


SVM, Support Vector Machine

, is something that has similar roots with neural networks.
But recently it has been widely used in Classification.
That means, if I have some sets of things classified
(But you know nothing about HOW I CLASSIFIED THEM, or say
you don't know the rules used for classification)
,
when a new data comes, SVM can PREDICT which
set it should belong to.



聽起來是很神奇的事(如果你覺得不神奇,請重想一想這句話代表什麼:
分類的依據是未知的!,還是不神奇的話就請你寫個程式
解解看這個問題), 也很像要 AI 之類的高等技巧... 不過 SVM 基於
統計學習理論 可以在合理的時間內漂亮的解決這個問題。


It sounds marvelous and would seem to require advanced techniques like AI searching
or some time-consuming complex computation. But SVM used
some Statistical Learning Theory to solve this problem
in reasonable time.



以圖形化的例子來說明(by SVMToy),
像假定我在空間中標了一堆用顏色分類的點,
點的顏色就是他的類別, 位置就是他的資料, 那 SVM
就可以找出區隔這些點的方程式, 依此就可以分出一區區的區域;
拿到新的點(資料) 時, 只要對照該位置在哪一區就可以(predict)
找出他應該是哪一顏色(類別)了:

Now we explain with a graphical example(by SVMToy),
I marked lots of points with different colors on a plane,
the color of each point is its "class" and the location is its data.
SVM can then find equations to split these points and with
these equations we can get colored regions. When a new point(data) comes,
we can find (predict) what color (class) a point should be just by using the point's location (data)










原始資料分佈
Original Data
SVM找出來的區域
SVM Regions
SVM Easy Sample: Before SVM Ease Sample: After
SVM Sample: Before SVM Sample: After



當然 SVM 不是真的只有畫圖分區那麼簡單, 不過看上面的例子應該可以了解
SVM 大概在作什麼.

Of course SVM is not really just about painting and marking regions, but
with the example above you should should be able to get some idea about what SVM is
doing.



要對 SVM 再多懂一點點,可以參考 cjlin 在 data mining 課的
slides: pdf or
ps


底下我試著在不用看那個 slide 的情況
解釋及使用 libsvm。

To get yourself more familiar with SVM, you may refer to
the slides cjlin used in his Data Mining course :
pdf or
ps .

I'm going to try to explain and use libSVM without those slides.




所以, 我們可以把 SVM 當個黑盒子,
資料丟進去讓他處理然後我們再來用就好了.

Thus we can consider SVM as a black box. Just push data into
SVM and use the output.



How do I get SVM?



林智仁(cjlin)老師
libsvm
當然是最完美的工具.


Chih-Jen Lin's
libsvm
is of course the best tool you can ever find.


Download libsvm


下載處:
Download Location:




libsvm.zip or
libsvm.tar.gz



.zip 跟 .tar.gz 基本上是一樣的, 只是看你的 OS; 習慣上 Windows 用
.zip 比較方便 (因為有 WinZIP, 不過我都用 WinRAR), UNIX 則是用 .tar.gz


Contents in the .zip and .tar.gz are the same. People using Windows
usually like to use .zip files because they have WinZIP, which I always
replace with WinRAR. UNIX users mostly prefer .tar.gz



Build libsvm



解開來後, 假定是 UNIX 系統, 直接打 make 就可以了; 編不出來的話請
詳讀說明和運用常識. 因為這是 tutorial, 所以我不花時間細談, 而且
會編不出來的情形真是少之又少, 通常一定是你的系統有問題或你太笨了.
其他的子目錄可以不管, 只要 svm-train, svm-scale, svm-predict
三個執行檔有編出來就可以了.


After you extracted the archives, just type make if
you are using UNIX. You may ignore some of the subdirectories.
We only need these executable files:
svm-train, svm-scale, and svm-predict




Windows 的用戶要自己重編當然也是可以, 不過已經有編好的 binary 在裡面了:
請檢查 windows 子目錄, 應該會有
svmtrain.exe, svmscale.exe, svmpredict.exe, svmtoy.exe .


Windows users may rebuild from source if you want, but there're already some
prebuilt binaries in the archive: just check your "windows" subdirectory and
you should find
svmtrain.exe, svmscale.exe, svmpredict.exe, and svmtoy.exe .



Using SVM


libsvm 有很多種用法, 這篇 tutorial
只打算講簡單的部分.

libsvm has lots of functions. This tutorial will only
explain the easier parts (mostly classification with default
model).




The programs



解釋一下幾個主要執行檔的作用: (UNIX/Windows 下檔名稍有不同,
請用常識理解我在講哪個)

I'm going to describe how to use the most important
executables here.
The filenames are a little bit different under Unix and Windows,
apply common sense to see which I'm referring to.




svmtrain


Train (訓練) data. 跑 SVM 被戲稱為 "開火車"
也是由於這個程式名而來.
train 會接受特定格式的輸入, 產生一個 "Model" 檔. 這個
model 你可以想像成 SVM 的內部資料, 因為 predict 要 model
才能 predict, 不能直接吃原始資料. 想想也很合理, 假定 train
本身是很耗時的動作, 而 train 好可以以某種形式存起內部資料,
那下次要 predict 時直接把那些內部資料 load 進來就快多了.

Use your data for training.
Running SVM is often referred to as 'driving
trains' by its non-native English speaking authors because of this program.
svmtrain accepts some specifically format which will be
explained below and then generate a 'Model' file.
You may think of a 'Model' as a storage format for the internal data of SVM.
This should appear very reasonable after some thought,
since training with data is a time-consuming process, so we
'train' first and store the result enabling the 'predict' operation to go much faster.


svmpredict



依照已經 train 好的 model, 再加上給定的輸入 (新值), 輸出
predict (預測) 新值所對應的類別 (class).

Output the predicted class of the new input data
according to a pre-trained model.


svmscale



Rescale data. 因為原始資料可能範圍過大或過小, svmscale
可以先將資料重新 scale (縮放) 到適當範圍.

Rescale data. The original data maybe too huge or small
in range, thus we can rescale them to the proper range so that
training and predicting will be faster.


File Format



檔案格式要先交代一下. 你可以參考 libsvm 裡面附的 "heart_scale":


This is the input file format of SVM. You may also
refer to the file "heart_scale" which is bundled in
official libsvm source archive.



[label] [index1]:[value1] [index2]:[value2] ...

[label] [index1]:[value1] [index2]:[value2] ...

.


.


一行一筆資料,如
One record per line, as:



+1 1:0.708 2:1 3:1 4:-0.320 5:-0.105 6:-1



label


或說是 class, 就是你要分類的種類,通常是一些整數。

Sometimes referred to as 'class', the class (or set) of your classification.
Usually we put integers here.

index



是有順序的索引,通常是放連續的整數。

Ordered indexes. usually continuous integers.

value


就是用來 train 的資料,通常是一堆實數。

The data for training. Usually lots of real (floating point)
numbers.




每一行都是如上的結構, 意思就是: 我有一排資料, 分別是
value1, value2, .... valueN, (而且它們的順序已由 indexN
分別指定),這排資料的分類結果就是 label。

Each line has the structure described above. It means,
I have an array(vector) of data(numbers): value1,
value2, .... valueN (and the order of the values are specified by the respective index),
and the class (or the result) of this array is label.



或許你會不太懂,為什麼會是 value1,value2,.... 這樣一排呢?
這牽涉到 SVM 的原理。 你可以這樣想(我沒說這是正確的),
它的名字就叫 Support "Vector" Machine, 所以輸入的
training data 是 "Vector"(向量), 也就是一排的
x1, x2, x3, ... 這些值就是 valueN,而 x[n]
的 n 就是 由 indexN 指定。 這些東西又稱為 "attribute"。




真實的情況是, 大部份時候我們給定的資料可能有很多
"特徵(feature)" 或說 "屬性(attribute)",所以輸入會是
一組的。 舉例來說,以前面畫點分區的例子

來說,我們不是每個點都有 X 跟 Y 的座標嗎? 所以它就有
兩種 attribute。 假定我有兩個點: (0,3) 跟 (5,8)
分別在 label(class) 1 跟 2 ,那就會寫成

1 1:0 2:3

2 1:5 2:8


同理,空間中的三維座標就等於有三組 attribute。

Maybe it's confusing to you: why value, value2, ...?
The reason is usually the input data to the problem you
were trying to solve involves lots of 'features',
or say 'attributes', so the input will be a set (or
say vector/array). Take the

Marking points and find region
example described
above, we assumed each point has coordinates X and Y
so it has two attributes (X and Y). To describe
two points (0,3) and (5,8) as having labels(classes) 1 and 2, we
will write them as:

1 1:0 2:3

2 1:5 2:8


And 3-dimensional points will have 3 attributes.




這種檔案格式最大的好處就是可以使用 sparse matrix,
或說有些 data 的 attribute 可以不存在。

This kind of fileformat has the advantage that
we can specify a sparse matrix, ie. some attribute
of a record can be omitted.


To Run libsvm



來解釋一下 libsvm 的程式怎麼用。 你可以先拿 libsvm 附的
heart_scale 來做輸入,底下也以它為例:

Now I'll show you how to use libsvm. You may use
the heart_scale file in the libsvm source archive
as input, as I'll do in this example:




看到這裡你應該也了解,使用 SVM 的流程大概就是:

You should have a sense that using libsvm
is basically:




  1. 準備資料並做成指定格式

    (有必要時需 svmscale)

    Prepare data in specified format
    and svmscale it if necessary.


  2. 用 svmtrain 來 train 成 model


    Train the data to create a model with svmtrain.


  3. 對新的輸入,使用 svmpredict 來 predict 新資料的 class

    Predict new input data with svmpredict and
    get the result.


svmtrain



svmtrain 的語法大致就是:

The syntax of svmtrain is basically:

svmtrain [options] training_set_file
[model_file]


training_set_file 就是之前的格式,而 model_file 如果不給就會
叫 [training_set_file].model。 options 可以先不要給。




The format of training_set_files is described above.
If the model_file is not specified, it'll be
[training_set_file].model by default. Options can be
ignored at first.


下列程式執行結果會產生 heart_scale.model
檔:(螢幕輸出不是很重要,沒有錯誤就好了)

The following command will generate the heart_scale.model file.
The screen output may be ignored if there were no errors.


./svm-train heart_scale

optimization finished, #iter = 219


nu = 0.431030

obj = -100.877286, rho = 0.424632

nSV = 132, nBSV = 107

Total nSV = 132

svmpredict




svmpredict 的語法是 :

The syntax to svm-predict is:


svmpredict test_file model_file
output_file

test_file 就是我們要 predict 的資料。它的格式跟
svmtrain 的輸入,也就是 training_set_file 是一樣的!
不過每行最前面的 label 可以省略 (因為 predict 就是要
predict 那個 label)。 但如果 test_file 有 label
的值的話, predict 完會順便拿 predict 出來的值跟 test_file
裡面寫的值去做比對,這代表: test_file 寫的 label
是真正的分類結果,拿來跟我們 predict 的結果比對就可以
知道 predict 有沒有猜對了。

test_file is the data the we are going to 'predict'.
Its format is almost exactly the same as the training_set_file, which we fed as input
to svmtrain. But we can skip the leading label

(Because 'predict' will output the label). Somehow
if test_file has labels, after predicting svm-predict
will compare the predicted label with the label written
in test_file. That means, test_file has the real (or
correct) result of classification, and after comparing
with our predicted result we can know whether the
prediction is correct or not.



也所以,我們可以拿原 training set 當做 test_file再丟給
svmpredict 去 predict (因為格式一樣),看看正確率有多高,
方便後面調參數。

So we can use the original training_set_file as test_file
and feed it to svmpredict for prediction (nothing different
in file format) and see how high the accuracy is so
we can optimize the arguments.



其它參數就很好理解了: model_file 就是 svmtrain 出來
的檔案, output_file 是存輸出結果的檔案。


Other arguments should be easy to figure out now:
model_file is the model trained by svmtrain, and
output_file is where we store the output result.



輸出的格式很簡單,每行一個 label,對應到你的 test_file
裡面的各行。

Format of output is simple. Each line contains a label
corresponding to your test_file.




下列程式執行結果會產生 heart_scale.out:

The following commands will generate heart_scale.out:


./svm-predict heart_scale heart_scale.model
heart_scale.out


Accuracy = 86.6667% (234/270) (classification)

Mean squared error = 0.533333 (regression)


Squared correlation coefficient = 0.532639(regression)



As you can see,我們把原輸入丟回去 predict,
第一行的 Accuracy 就是預測的正確率了。
如果輸入沒有 label 的話,那就是真的 predict 了。

As you can see, after we 'predict'ed the original
input, we got 'Accuracy=86.6667%" on first line as
accuracy of prediction. If we don't put labels
in input, the result is real prediction.




看到這裡,基本上你應該已經可以利用 svm 來作事了:
你只要寫程式輸出正確格式的資料,交給 svm 去 train,
後來再 predict 並讀入結果即可。

Now you can use SVM to do whatever you want!
Just write a program to output its data in the correct format,
feed the data to SVM for training, then predct and read the output.



Advanced Topics



後面可以說是一些稍微進階的部份,我可能不會講的很清楚,
因為我的重點是想表達一些觀念和解釋一些你看相關文件時
很容易碰到的名詞。

These are a little advanced and I may not
explain very clearly. Because I just want to help you
get familiar with some of the terminology and ideas that
you'll encounter when you read other (lib)SVM documents.



Scaling



svm-scale 目前不太好用,不過它有其必要性。因為
適當的scale有助於參數的選擇(後述)還有解svm的速度。

svmscale 會對每個 attribute 做scale。
範圍用 -l, -u 指定, 通常是[0,1]或是[-1,1]。
輸出在 stdout。

另外要注意的(常常會忘記)是 testing data 和
training data要一起scale。

而 svm-scale 最難用的地方就是沒辦法指定
testing data/training data(不同檔案)
然後一起scale。



svm-scale is not easy to use right now, but it is important.
Scaling aids the choosing of arguments (described below)
and the speed of solving SVM.

svmscale rescales all atrributes with the specified (by
-l, -u) range, usually [0,1] or [-1,1].

Please keep in mind that testing data and
training data MUST BE SCALED WITH THE SAME RANGE. Don't
forget to scale your testing data before you predict.

We can't specify the testing and training data file together
and scale them in one command, that's why svm-scale is not
so easy to use right now.



Arguments



前面提到,在 train 的時候可以下一些參數。(直接執行
svm-train 不指定輸入檔與參數會列出所有參數及語法說明)
這些參數對應到原始 SVM 公式的一些參數,所以會影響
predict 的正確與否。

舉例來說,改個 c=10:

./svm-train -c 10 heart_scale

再來 predict ,正確率馬上變成 92.2% (249/270)。




We know that we can use some arguments when
we were training data (Running svm-train without
any input file or arguments will cause it to print its list syntax help and complete
arguments). These arguments corresponds to
some arguments in original SVM equations so they
will affect the accuracy of prediction.

Let's use c=10 as an example:

./svm-train -c 10 heart_scale

If you predict again now, the accuracy will be
92.2% (249/270).


Cross Validation




一般而言, SVM 使用的方式(在決定參數時)常是這樣:


  1. 先有已分好類的一堆資料

  2. 亂數拆成好幾組 training set

  3. 用某組參數去 train 並 predict 別組看正確率


  4. 正確率不夠的話,換參數再重複 train/predict



Mostly people use SVM while following this workflow:

  1. Prepare lots of pre-classified (correct) data

  2. Split them into several training sets randomly.


  3. Train with some arguments and predict other sets of
    data to calculate the accuracy.

  4. Change the arguments and repeat until
    we get good accuracy.




等找到一組不錯的參數後,就拿這組參數來建 model
並用來做最後對未知資料的 predict。
這整個過程叫 cross validation
也就是交叉比對。


When we got some nice arguments, we will then
use them to train the model and use the model for final
prediction (on unknown test data).
This whole process is called cross validation .



在我們找參數的過程中,可以利用 svmtrain 的內建
cross validation 功能來幫忙:

-v n: n-fold cross validation

n 就是要拆成幾組,像 n=3 就會拆成三組,然後先拿
1跟2來 train model 並 predict 3 以得到正確率;
再來拿 2跟 3 train 並 predict 1,最後 1,3 train 並
predict 2。其它以此類推。


In the process of experimenting with the arguments, we can use
the built-in support for validation of svmtrain:

-v n: n-fold cross validation

n is how many sets to split your input data. Specifing n=3
will split data into 3 sets; train the model with data set 1 and 2
first then predict data set 3 to get the accuracy, then train
with data set 2 and 3 and predict data set 1, finally train 1,3 and
predict 2, ... ad infinitum.



如果沒有交叉比對的話,很容易找到只在特定輸入時好的
參數。像前面我們 c=10 得到 92.2%,不過拿 -v 5 來看看:
./svm-train -v 5 -c 10 heart_scale

...


Cross Validation Accuracy = 80.3704%

平均之後才只有 80.37%,比一開始的 86 還差。

If we don't use cross validation, sometimes we may
be fooled by some arguments only good for some special
input. Like the example we used above, c=10 has 92.2%.
If we do so with -v 5:
./svm-train -v 5 -c 10 heart_scale

...

Cross Validation Accuracy = 80.3704%


After the prediction results is averaged with cross validation we have only 80.37% accuracy,
even worse than with the original argument (86%).



What arguments rules?



通常而言,比較重要的參數是
gamma (-g)
cost (-c)
。而 cross validation (-v) 的參數常用 5。


Generally speaking, you will only modify two
important arguments when you are using training with data:
gamma (-g) and
cost (-c) . And
cross validation (-v) is usually set to 5.



cost 預設值是 1, gamma 預設值是 1/k ,k 等於輸入
資料筆數。 那我們怎麼知道要用多少來當參數呢?

用 試 的


是的,別懷疑,就是 Try 參數找比較好的值。


cost is 1 by default, and gamma has default value = 1/k ,
k = number of input records. Then how do we know
what value to choose as arguments?

T R Y

Yes. Just by trial and error.



Try 參數的過程常用 exponential
指數成長的方式來增加與減少參數的數值,
也就是 2^n (2 的 n 次方)。

When experimenting with arguments, the value usually
increases and decreases in exponential order.
i.e., 2^n.



因為有兩組參數,所以等於要 try n*n=n^2 次。
這個過程是不連續的成長,所以可以想成我們在一個
X-Y 平面上指定的範圍內找一群格子點 (grid
如果你不太明白,想成方格紙或我們把平面上所有
整數交點都打個點,就是那樣),每個格子點的 X 跟
Y 經過換算 (如 2^x, 2^y) 就拿去當 cost 跟 gamma
的值來 cross validation。

Because we have two important arguments, we
have to try n*n=n^2 times. The whole process
is discontinous and can be thought of as finding the
grid points on a specified region
(range) of the X-Y plane (Think of marking
all integer interception points on a paper).
Convert each grid point's X and Y coordinate
to exponential values (like 2^x, 2^y) then
we can use them as value of cost and gamme
for cross validation.



所以現在你應該懂得 libsvm 的 python 子目錄下面
有個 grid.py 是做啥的了: 它把上面的過程自動化,
在你給定的範圍內呼叫 svm-train 去 try 所有的參數值。
python 是一種語言,在這裡我不做介紹,因為我會了 :P
(just a joke,真正原因是 -- 這是 libsvm 的 tutorial)。
grid.py 還會把結果 plot 出來,方便你尋找參數。
libsvm 有很多跟 python 結合的部份,由此可見 python
是強大方便的工具。很多神奇的功能,像自動登入多台
機器去平行跑 grid等等都是 python 幫忙的。不過
SVM 本身可以完全不需要 python,只是會比較方便。


So look for 'grid.py' in the 'python' subdirectory
inside the libsvm archive. You should know what it does
now: automatically execute the procedure above,
try all argument values by calling svm-train within
the region specified by you. Python is a programming
language which I'm not going to explain here.
grid.py will also plot the result graphically to help you
look for good arguments. There're also many parts
of libsvm powered by python, like
logging into several hosts and running grids at
the same time parallel. Keep in mind that libsvm can
be used without python entirely. Python just only
helped us to do thinks quickly.


跑 grid (基本上用 grid.py 跑當然是最方便,不過
如果你不懂 python 而且覺得很難搞,那你要自己產生
參數來跑也是可以的) 通常好的範圍是

[c,g]=[2^-10,2^10]*[2^-10,2^10]

另外其實 grid 用 [-8,8] 也很夠了。

Running for grids (it's more convenient to just use grid.py
but it's also ok if you don't) you may choose the
range as

[c,g]=[2^-10,2^10]*[2^-10,2^10]


Usually [-8,8] is enough for grids.


Regression



另一個值得一提的是 regression。

簡單來說,前面都是拿 SVM 來做分類 (classification),
所以 label 的值都是 discrete data、或說已知的固定值。
而 regression 則是求 continuous 的值、或說未知的值。
你也可以說,一般是 binary classification,
而 regression是可以預測一個實數。

比如說我知道股市指數受到某些因素影響, 然後我想預測股市..
股市的指數就是我們的 label, 那些因素量化以後變成
attributes。 以後蒐集那些 attributes 給 SVM 它就會
預測出指數(可能是沒出現過的數字),這就要用 regression。
那樂透開獎的號碼呢? 因為都是固定已知的數字,
很明顯我們應該用一般 SVM 的 classification 來 predict。
(註:這是真實的例子 -- llwang 就寫過這樣的東西)

所以說 label 也要 scale, 用
svm-scale -y lower upper

但是比較糟糕的情況是 grid.py 不支援 regression ,
而且cross validation 對 regression 也常常不是很有效。

總而言之,regression 是非常有趣的東西,不過也是比較
進階的用法。 在這裡我們不細談了,有興趣的人請再
參考 SVM 與 libsvm 的其它文件。



The other important issue is "Regression".

To explain briefly, we only used SVM to do
classification in this tutorial. The type
of label we used are always discrete data (ie. a known
fixed value). "Regression" in this context means to predict labels with continuous
values (or unknown values). You can think of
classification as predictions with only binary outcomes, and regression
as predictions that output real (floating point) numbers.

Thus to predict lottery numbers (since they
are always fixed numbers) you should use classification,
and to predict the stock market you need regression.

The labels must also be scaled when you
use regression, by svm-scale -y lower upper


However grid.py does not support regression,
and cross validation sometimes does not work well
with regression.

Regression is interesting but also advanced.
Please refer to other documents for details.



Epilogue


到此我已經簡單的說明了 libsvm 的使用方式,
更完整的用法請參考 libsvm 的說明跟
cjlin 的網站
SVM 的相關文件,或是去上 cjlin 的課。
Here we have already briefly explained
the libsvm software. For complete usage guides please refer
to documents inside the libsvm archive,
cjlin's website,
SVM-related documents, or go take cjlin's course if
you are a student at National Taiwan University :)



對於 SVM 的新手來說,

libsvmtools
有很多好東西。像 SVM for dummies
就是很方便觀察 libsvm 流程的東西。
Take a glance at

libsvmtools
especially "SVM for dummies" there.
Those are good tools for SVM newbies that helps in observing
libsvm workflow.


Copyright



All rights reserved by

Hung-Te Lin (林弘德, piaip),


Website:
piaip at ntu csie
,2003.


All HTML/text typed within VIM on Solaris.


Style sheet from W3C Core StyleSheets.

Original URL:
http://www.csie.ntu.edu.tw/~r91034/svm/svm_tutorial.html

2007年4月6日星期五

Good Dot Gnus Dot El


(setq gnus-select-method '(nntp "news.yaako.com"))
(setq mm-text-html-renderer 'w3m)
(setq mm-discouraged-alternatives '("text/html" "text/richtext"))
;; or news.yaako.com
(setq gnus-default-subscribed-newsgroups
'("gnu.emacs.help"
"comp.lang.c++"
"comp.lang.c"
"comp.lang.lisp"
"comp.lang.java.programmer"
"cn.comp.os.linux"
"comp.lang.ruby"
"sci.math"
"comp.text.tex"
"alt.usage.english"
"gnu.emacs.gnus"
"comp.emacs"
"gnu.emacs.sources"
))

(setq mail-sources
'((pop :server "pop.21cn.com" ;;
:user "dealover" ;;
:port "pop3"
:password nil))) ;;
(setq gnus-secondary-select-methods '((nnfolder "")))
(setq user-full-name "QinGW") ;;
(setq user-mail-address "dealover@21cn.com") ;;
(setq smtpmail-auth-credentials
'(("smtp.21cn.com" ;;
25
"dealover" ;;
nil))) ;;
(setq smtpmail-default-smtp-server "smtp.21cn.com")
(setq smtpmail-smtp-server "smtp.21cn.com")
(setq message-send-mail-function 'smtpmail-send-it)
(setq gnus-message-archive-group
'((if (message-news-p)
"nnfolder:mail:sent.news"
"nnfolder:mail.sent.mail")))
(setq gnus-use-cache 'passive)
(setq nnmail-expiry-wait 3)
(require 'bbdb)
(bbdb-initialize 'gnus 'message)
(setq bbdb-user-mail-names
(regexp-opt '("dealover@21cn.com"
"QinGW@sina.com")))
(setq bbdb-complete-name-allow-cycling t)
(setq bbdb-use-pop-up nil)

配置 DOT EMACS

(set-language-environment 'Chinese-GB)
(set-keyboard-coding-system 'euc-cn)
(set-clipboard-coding-system 'euc-cn)
(set-terminal-coding-system 'euc-cn)
(set-buffer-file-coding-system 'euc-cn)
(set-selection-coding-system 'euc-cn)
(modify-coding-system-alist 'process "*" 'euc-cn)
(setq default-process-coding-system
'(euc-cn . euc-cn))
(setq-default pathname-coding-system 'euc-cn)
;;(require 'ido)
;; (ido-mode t)
;;;color-theme
(load-file "/home/dealover/emacs/color-theme.el")
;;(color-theme-comidia)
(setq x-select-enable-clipboard t)
;;
(setq default-directory "~/newtkzplab")
;; tootbar nill
(tool-bar-mode nil)
(scroll-bar-mode nil)
(mouse-avoidance-mode 'animate)
;; match parentheses
(show-paren-mode t)
(setq show-paren-style 'parentheses)
;; set default mode is text-mode
(setq default-major-mode 'text-mode)
(add-hook 'text-mode-hook 'turn-on-auto-fill)
;n;prevent jump when page scrolling
(setq scroll-margin 3
scroll-conservatively 10000)
;;;set timestamp
(setq time-stamp-active t)
(setq time-stamp-warn-inactive t)
(setq time-stamp-format "%:y-%02m-%02d %3a %02H:%02M:%02S K.T")
;;pmwiki
(add-to-list 'load-path "~/emacs/pmwiki-mode")
(autoload 'pmwiki-open "pmwiki-mode" "PmWiki online edit." t)
;; $(A;r(B (require 'pmwiki-mode)

(setq pmwiki-author "QinGW") ;; http://www.emacs.cn/Profiles
(setq pmwiki-wikiword-pattern "[A-Z][A-Za-z0-9]+") ;; Pagename $(A:M(B PageName $(A6<8_aaotj>#;(B
(setq pmwiki-page-uri "http://www.emacs.cn/Main/EmacsSandbox")
(setq pmwiki-uri-transforms
(list '("http://www.emacs.cn\\(/[A-Z]\\|/?\\?\\)"
"http://www.emacs.cn"
"http://www.emacs.cn/index.php")))

;;;; optional
;; (add-hook 'pmwiki-mode-hooks 'turn-off-auto-fill)
;; (add-hook 'pmwiki-mode-hooks
;; 'pmwiki-delayed-hook-longlines-mode-on)
;; (add-hook 'pmwiki-save-before-hooks 'longlines-mode-off)
;; (add-to-list 'auto-mode-alist '("\\.pmwiki\\'" . pmwiki-mode)
;;;auctex
(load "auctex.el" nil t t)
(load "preview-latex.el" nil t t)
(setq TeX-auto-save t)
(setq TeX-parse-self t)
(setq-default TeX-master nil)
(add-to-list 'load-path "~/emacs/cjk")
(autoload 'CJK-insert-space "cjkspace"
"Insert tildes appropriately in CJK document." t)
(defun my-LaTeX-mode-hook ()
"Key definitions for LaTeX mode."
(define-key LaTeX-mode-map " " 'CJK-insert-space)
)
(add-hook 'LaTeX-mode-hook 'my-LaTeX-mode-hook)
;;; cc -mode
(require 'cc-mode)
(c-set-offset 'inline-open 0)
(c-set-offset 'friend '-)
(c-set-offset 'substatement-open 0)

(defun my-c-mode-common-hook()
(setq tab-width 4 indent-tabs-mode nil)
;;; hungry-delete and auto-newline
(c-toggle-auto-hungry-state 1)
;;偌瑩隅砱
(define-key c-mode-base-map [(control \`)] 'hs-toggle-hiding)
(define-key c-mode-base-map [(return)] 'newline-and-indent)
(define-key c-mode-base-map [(f7)] 'compile)
(define-key c-mode-base-map [(meta \`)] 'c-indent-command)

;; (define-key c-mode-base-map [(tab)] 'hippie-expand)
(define-key c-mode-base-map [(tab)] 'my-indent-or-complete)
(define-key c-mode-base-map [(meta ?/)] 'semantic-ia-complete-symbol-menu)

;; C++ LANGUAGE
(setq c-macro-shrink-window-flag t)
(setq c-macro-preprocessor "cpp")
(setq c-macro-cppflags " ")
(setq c-macro-prompt-flag t)
(setq hs-minor-mode t)
(setq abbrev-mode t)
)
(add-hook 'c-mode-common-hook 'my-c-mode-common-hook)
(load-file "~/emacs/klaralv.el")
(add-hook 'c++-mode-hook
(lambda ()
(define-key c++-mode-map [(f5)] 'kdab-insert-header)
(define-key c++-mode-map [(shift f5)] 'kdab-insert-forward-decl)
(define-key c++-mode-map [(control f5)] 'kdab-lookup-qt-documentation)))
(load-file "~/emacs/xscheme.el")
;;(load-file "~/emacs/quack.el")
;;(require 'quack)
;;(setq quack-default-program "guile")
;;(setq quack-fontify-style nil)
;;quack.el
;;(autoload 'run-scheme "quack" "Quack scheme editing mode" t)
;;(autoload 'scheme-mode "quack" "Quack scheme editing mode" t)

(add-to-list 'load-path "/usr/local/share/emacs/site-lisp/muse/")
(require 'muse-mode) ; load authoring mode
(require 'muse-html) ; load publishing styles I use
(require 'muse-latex)
(require 'muse-texinfo)
(require 'muse-docbook)
(require 'muse-project)
(setq muse-project-alist
'(("website" ; my various writings
("~/Pages" :default "index")
(:base "html" :path "~/public_html")
(:base "pdf" :path "~/public_html/pdf"))))
(setq muse-file-extension nil
muse-mode-auto-p t)
(add-hook 'find-file-hooks 'muse-mode-maybe)

(add-hook 'write-file-hooks (function (lambda ()
(set-lastmodified-tag) )))

(defun set-lastmodified-tag ()
"Insert current date after Last Modified: "
(interactive)
(let ((tostr (concat "Last Modified: " (current-time-string) ".")))
(save-excursion
(goto-char (point-min))
(while (re-search-forward "\\Last Modified:\\([A-Za-z0-9: ]*\\)?\\." nil t)
(replace-match tostr nil t)))))
;;; display time
(setq display-time-24hr-format t)
(setq display-time-format "%m/%d(%a) %R")
(setq display-time-day-and-date t)
(display-time)

;; calculator
(autoload 'calculator "calculator" "Run the pocket calculator." t)
(global-set-key "\C-c\C-m" 'calculator)
;;;move up or down all line
(global-set-key [(meta up)] 'move-line-up)
(global-set-key [(meta down)] 'move-line-down)

(defun move-line (&optional n)
"Move current line N (1) lines up/down leaving point in place."
(interactive "p")
(when (null n)
(setq n 1))
(let ((col (current-column)))
(beginning-of-line)
(next-line 1)
(transpose-lines n)
(previous-line 1)
(forward-char col)))
(defun move-line-up (n)
"Moves current line N (1) lines up leaving point in place."
(interactive "p")
(move-line (if (null n) -1 (- n))))

(defun move-line-down (n)
"Moves current line N (1) lines down leaving point in place."
(interactive "p")
(move-line (if (null n) 1 n)))
;;;control o move new line
(global-set-key [(control o)] 'vi-open-next-line)

(defun vi-open-next-line (arg)
"Move to the next line (like vi) and then opens a line."
(interactive "p")
(end-of-line)
(open-line arg)
(next-line 1)
(indent-according-to-mode))

;;;match and move parenthesis

(global-set-key "%" 'match-paren)
(defun match-paren (arg)
"Go to the matching parenthesis if on parenthesis otherwise insert %."
(interactive "p")
(cond ((looking-at "\\s\(") (forward-list 1) (backward-char 1))
((looking-at "\\s\)") (forward-char 1) (backward-list 1))
(t (self-insert-command (or arg 1)))))

;;;copy current line when nothing to be selected

(defadvice kill-ring-save (before slickcopy activate compile)
"When called interactively with no active region, copy a single line instead."
(interactive
(if mark-active (list (region-beginning) (region-end))
(list (line-beginning-position)
(line-beginning-position 2)))))

(defadvice kill-region (before slickcut activate compile)
"When called interactively with no active region, kill a single line instead."
(interactive
(if mark-active (list (region-beginning) (region-end))
(list (line-beginning-position)
(line-beginning-position 2)))))

;;;;
(defun my-c++-mode-hook()
(setq tab-width 4 indent-tabs-mode nil)
(c-set-style "stroustrup")
;; (define-key c++-mode-map [f3] 'replace-regexp)
)
;; The per developer location of the source tree for project-x
(setq javasrc_top "")
(add-to-list 'load-path (expand-file-name "~/emacs/jde/lisp"))
(add-to-list 'load-path (expand-file-name "~/emacs/cedet/common"))
(load-file (expand-file-name "~/emacs/cedet/common/cedet.el"))
(add-to-list 'load-path (expand-file-name "~/emacs/elib"))

;;(load-file "~/emacs/completion-ui.el")
(add-to-list 'load-path
"~/emacs/ecb-2.32")
(require 'ecb)
;;; erc
(add-to-list 'load-path "~/emacs/erc-5.1.2")
(require 'erc)
;;;w3m
(add-to-list 'load-path "~/emacs/emacs-w3m")
(require 'w3m)

(setq browse-url-browser-function 'w3m-browse-url)
(setq w3m-icon-directory "/usr/share/emacs-w3m/icon")
(autoload 'w3m-browse-url "w3m" "Ask a WWW browser to show a URL." t)
(global-set-key "\C-xm" 'browse-url-at-point)
;;multi-mode
(load-file "~/emacs/multi-mode.el")
(autoload 'multi-mode
"multi-mode"
"Allowing multiple major modes in a buffer."
t)
;; Configure JSP Mode
(defun jsp-mode () (interactive)
(multi-mode 1
'html-mode
'("<%--" indented-text-mode) '("<%@" indented-text-mode) '("<%=" html-mode) '("<%" jde-mode) '("%>" html-mode)
'("")
(hippie-expand nil)
(indent-for-tab-command))
)

(global-set-key [(control tab)] 'my-indent-or-complete)


(autoload 'senator-try-expand-semantic "senator")

(setq hippie-expand-try-functions-list
'(
senator-try-expand-semantic
try-expand-dabbrev
try-expand-dabbrev-visible
try-expand-dabbrev-all-buffers
try-expand-dabbrev-from-kill
try-expand-list
try-expand-list-all-buffers
try-expand-line
try-expand-line-all-buffers
try-complete-file-name-partially
try-complete-file-name
try-expand-whole-kill
)
)

(setq cscope-do-not-update-database t)

(global-set-key "%" 'match-paren)

(defun match-paren (arg)
"Go to the matching paren if on a paren; otherwise insert %."
(interactive "p")
(cond ((looking-at "\\s\(") (forward-list 1) (backward-char 1))
((looking-at "\\s\)") (forward-char 1) (backward-list 1))
(t (self-insert-command (or arg 1)))))
(add-to-list 'load-path "~/hacking/lisp/slime/") ; your SLIME directory
(setq inferior-lisp-program "/usr/local/bin/sbcl") ; your Lisp system
(require 'slime)
(slime-setup)

(load-file "~/emacs/psvn.el")
;;; psvn
(setq svn-status-prefix-key '[(hyper s)])
(require 'psvn)
(define-key svn-log-edit-mode-map [f6] 'svn-log-edit-svn-diff)

(load-file "~/emacs/history.el")
(require 'history)

(load-file "~/emacs/xcscope.el")
(require 'xcscope)

;; Enabling various SEMANTIC minor modes. See semantic/INSTALL for more ideas.
;; Select one of the following
(semantic-load-enable-code-helpers)
;; (semantic-load-enable-guady-code-helpers)
;; (semantic-load-enable-excessive-code-helpers)

;; Enable this if you develop in semantic, or develop grammars
;; (semantic-load-enable-semantic-debugging-helpers)
(global-set-key [(f8)] 'speedbar)
(global-set-key [(f9)] 'svn-status)

(custom-set-faces
;; custom-set-faces was added by Custom.
;; If you edit it by hand, you could mess it up, so be careful.
;; Your init file should contain only one such instance.
;; If there is more than one, they won't work right.
)

(put 'scroll-left 'disabled nil)


(put 'dired-find-alternate-file 'disabled nil)

;;emms

;;;; EMMS
;; ------
(add-to-list 'load-path "~/emacs/emms")
(require 'emms-setup)
(emms-devel)

;; players
(setq emms-player-mpg321-command-name "mpg123"
emms-player-mplayer-command-name "mplayer"
emms-player-list '(emms-player-mplayer
emms-player-mplayer-playlist
emms-player-ogg123
emms-player-mpg321))

;; coding
(setq emms-info-mp3info-coding-system 'gbk
emms-lyrics-coding-system 'gbk
emms-cache-file-coding-system 'utf-8)

;; files
(setq emms-source-file-default-directory "~/music/songs"
emms-lyrics-dir "~/music/lyrics")

;; mode line format
(setq emms-mode-line-format "[ %s ]"
emms-lyrics-display-format "%s"
emms-playing-time-display-format "%s")

(setq global-mode-string
'("" appt-mode-string
display-time-string " "
battery-mode-line-string " "
erc-modified-channels-object
emms-mode-line-string " "
emms-playing-time-string " "
emms-lyrics-mode-line-string " "))

;; faces
(set-face-foreground 'emms-playlist-selected-face "magenta")
(set-face-foreground 'emms-playlist-track-face "green")

(setq emms-source-file-directory-tree-function
'emms-source-file-directory-tree-find)

(add-hook 'emms-player-started-hook 'emms-show)

(setq emms-playlist-sort-prefix "S")

(define-key emms-playlist-mode-map (kbd "S s") 'emms-playlist-sort-by-score)

(global-set-key (kbd "") 'emms-playlist-mode-go-popup)

(defun emms-playlist-mode-jump ()
"Jump to the directory of track at point in `emms-playlist-buffer'."
(interactive)
(dired
(file-name-directory
(emms-track-get (emms-playlist-track-at) 'name))))

;; (global-set-key (kbd "C-c e t") 'emms-play-directory-tree)
(global-set-key (kbd "C-c e x") 'emms-start)
(global-set-key (kbd "C-c e v") 'emms-stop)
(global-set-key (kbd "C-c e n") 'emms-next)
(global-set-key (kbd "C-c e p") 'emms-previous)
(global-set-key (kbd "C-c e o") 'emms-show)
(global-set-key (kbd "C-c e h") 'emms-shuffle)
;; (global-set-key (kbd "C-c e e") 'emms-play-file)
(global-set-key (kbd "C-c e SPC") 'emms-pause)
(global-set-key (kbd "C-c e f") 'emms-no-next)
(global-set-key (kbd "C-c e a") 'emms-add-directory-tree)

(global-set-key (kbd "C-c e r") 'emms-toggle-repeat-track)
(global-set-key (kbd "C-c e R") 'emms-toggle-repeat-playlist)
(global-set-key (kbd "C-c e m") 'emms-lyrics-toggle-display-on-minibuffer)
(global-set-key (kbd "C-c e M") 'emms-lyrics-toggle-display-on-modeline)

(global-set-key (kbd "C-c e ") (lambda () (interactive) (emms-seek -10)))
(global-set-key (kbd "C-c e ") (lambda () (interactive) (emms-seek +10)))
(global-set-key (kbd "C-c e ") (lambda () (interactive) (emms-seek -60)))
(global-set-key (kbd "C-c e ") (lambda () (interactive) (emms-seek +60)))

(global-set-key (kbd "C-c e s u") 'emms-score-up-playing)
(global-set-key (kbd "C-c e s d") 'emms-score-down-playing)
(global-set-key (kbd "C-c e s o") 'emms-score-show-playing)

;;ssh tramp
(require 'tramp)
(setq tramp-default-method "ssh")
(setq tramp-default-user "root")
;;;tabbar
;;(load-file "~/emacs/tabbar.el")
;;(require 'tabbar)
;;(tabbar-mode)
;;(global-set-key (kbd "C-=") 'tabbar-backward-group)
;;涴撓曆腔醴腔岆堂隅辦豎瑩涴欴憩褫眕眻諉蚚辦豎瑩懂紱酕賸﹝
;;(global-set-key (kbd "C--") 'tabbar-forward-group)
;;祥徹羶衄楷珋衄竭湮蚚揭ㄛ垀眕蛁庋賸﹝
;;(global-set-key (kbd "C-0") 'tabbar-backward)
;;(global-set-key (kbd "C-9") 'tabbar-forward)
;;;dictionary
(autoload 'dictionary-search "dictionary"
"Ask for a word and search it in all dictionaries" t)
(autoload 'dictionary-match-words "dictionary"
"Ask for a word and search all matching words in the dictionaries" t)
(autoload 'dictionary-lookup-definition "dictionary"
"Unconditionally lookup the word at point." t)
(autoload 'dictionary "dictionary"
"Create a new dictionary buffer" t)
;;autosearch had been canceled
(autoload 'dictionary-mouse-popup-matching-words "dictionary"
"Display entries matching the word at the cursor"t )
(autoload 'dictionary-popup-matching-words "dictionary"
"Display entries matching the word at the point" t)
(autoload 'dictionary-tooltip-mode "dictionary"
"Display tooltips for the current word" t)
(autoload 'global-dictionary-tooltip-mode "dictionary"
"Enable/disable dictionary-tooltip-mode for all buffers" t)
(global-set-key [mouse-3] 'dictionary-mouse-popup-matching-words)
(global-set-key [(control c)(d)] 'dictionary-lookup-definition)
(global-set-key [(control c)(s)] 'dictionary-search)
(global-set-key [(control c)(m)] 'dictionary-match-words)
;; choose a dictionary server
(setq dictionary-server "qingw.com")
(setq line-number-mode t)
(put 'narrow-to-region 'disabled nil)

(put 'downcase-region 'disabled nil)

(put 'upcase-region 'disabled nil)
(set-register ?s '(file . "/home/dealover/newtkzplab/app01/src/HelloWorld.java"))
(set-register ?p '(file . "/home/dealover/newtkzplab/app02/src/China.c"))