纯CSS实现三角形,兼容性良好

今天在网上看到文章介绍了一些CSS实现各种图形的方法,特别记下这个比较实用的CSS三角形的实现方法,纯CSS2,兼容性非常的好,所以分享给大家:

<!DOCTYPE html>
<html lang="zh_CN">
	<head>
  		<meta charset="utf-8" />
		<title>test</title>
		<style type="text/css">
			.test{
				width:0; 
				height:0; 
				border:10px solid; 
				border-color:#666 #fff #fff #fff;
			}
		</style>
	</head>

	<body>
		<div class="test"></div>
	</body>
</html>

适用于下拉菜单三角形提示、按钮、指示性图标等。

[翻译]Jade模板引擎中文API,适合入门

Jade是一款高性能简洁易懂的模板引擎,Jade是Haml的Javascript实现,在服务端(NodeJS)及客户端均有支持。

功能
客户端支持
超强的可读性
灵活易用的缩进
块扩展
代码默认经过编码处理以增强安全性
编译及运行时的上下文错误报告
命令行编译支持
HTML5模式(使用!!!5文档类型)
可选的内存缓存
联合动态和静态标记类
利用过滤器解析树的处理
支持 Express JS
利用each透明的循环objects,arrays甚至不可枚举对象
块注释
不需要标记前缀
AST过滤器
过滤器
:sass 需要安装sass.js
:less 需要安装less.js
:markdown 需要安装markdown-js或node-discount
:cdata
:coffeescript 需要安装coffee-script
Vim语法文件
TextMate包
Screencasts
其它语言实现
php
Scala
Ruby
安装
通过npm:

npm install jade

浏览器支持
可以通过下面命令将jade编译为客户端浏览器兼容的文件:

$ make jade.js

或者,如果你已经通过npm安装了uglifyjs(npminstalluglify-js),可以通过下面的命令同时创建两个文件:

$ make jade.min.js

公开API

var jade = require('jade');
 
// 渲染字符串
jade.render('.saecn.com 字符串', { options: 'here' });
 
// 渲染文件
jade.renderFile('path/to/saecn.com.jade', { options: 'here' }, function(err, html){
   // 这里的options是可选的
   // 回调函数可以作为第二个参数
});
 
// 编译一个函数
var fn = jade.compile('string of jade', options);
fn.call(scope, locals);

Options

执行作用域(this)scope
本地变量对象locals
处理异常及缓存时使用filename
通过文件名将Javascript缓存在内存中cache
输出生成的标记和函数体debug
替换jade默认编译引擎compiler
语法
行尾

在解析前会将 CRLF 和 CR 转换为 LF.

标记

标记是一行的第一个单词:

html

会被转换为 <html></html>

标记也可以有id:

div#container

这将被渲染成

<div id=”container”></div>

如何处理类?

div.user-details

渲染为: <div class=”user-details”></div>

多个class?并且还有id?

div#foo.bar.baz

渲染为:<div id=”foo” class=”bar baz”></div>

总写div确实很烦人,可以省略之:

#foo
.bar

输出: <div id=”foo”></div><div class=”bar”></div>

标记文本

只需要将文本内容放在标记后面:

p wahoo!

渲染为

<p>wahoo!</p>

.

酷,但是如何处理大段文本呢?

p
| foo bar baz
| rawr rawr
| super cool
| go jade go

渲染为

<p>foo bar baz rawr…..</p>

内插法?是的,这两种类型的文本都可以使用内插法,如果我们传入{ locals: { name: ‘一回’, email: ‘xianlihua[at]gmail.com’ }},可以这样做:

#user #{name} <#{email}>

输出:

<div id=”user”>一回 &lt;saecn[at]gmail.com&gt;</div>

出于某种原因需要输出#{}?转义之:

p \#{Saecn, 关注Javascript技术}

这样就得到了:

<p>#{Saecn, 关注Javascript技术}</p>

也可以使用反转义变量!{html},下面的代码将输出script标记:

– var html = “
| !{html}

包含文本的嵌套标记也可以使用文本块:

label
| Username:
input(name=’user[name]’)

或者直接使用标记文本:

label Username:
input(name=’user[name]’)

只接受纯文本的标记,如script,style,以及textarea不需要开头的|字符,例如:

html
head
title Saecn, 关注Web前端技术
script
if (foo) {
bar();
} else {
baz();
}

再次作为替代方案,我们可以使用点号’.’来表示一个文本块,例如:

p.
foo asdf
asdf
asdfasdfaf
asdf
asd.

输出:

   <p>foo asdf
    asdf
      asdfasdfaf
      asdf
    asd
    .
    </p>

如果点号’.’与标记之间有空格,Jade解析其会忽略它,将其作为文本处理:

p .

输出:

<p>.</p>

注释

单行注释当前看起来与Javascript一致,即“//”,单行注释的内容必须放在同一行上:

// 一些段落
p foo
p bar

将会输出:

<!– 一些段落 –>
<p>foo</p>
<p>bar</p>

Jade也支持非缓冲注释,只需增加一个横杠:

//- 该行注释将不会被输出到解析后的页面中
p foo
p bar

输出:

foo

<p>bar</p>

块注释

块注释会依据缩进进行处理:

body
//
#content
h1 Saecn,关注Web前端技术

输出:

<body>
<!–
<div id=”content”>
<h1>Saecn,关注Web前端技术</h1>
</div>
–>
</body>

Jade也支持条件注释,例如:

body
/if IE
a(href=’http://www.mozilla.com/en-US/firefox/’) Get Firefox

输出:

<body>
<!–[if IE]>
<a href=”http://www.mozilla.com/en-US/firefox/”>Get Firefox</a>
<![endif]–>
</body>

嵌套

Jade支持通过嵌套来以自然的方式定义标记:

ul
li.first
a(href=’#’) foo
li
a(href=’#’) bar
li.last
a(href=’#’) baz

块扩展

块扩展允许创建单行的简洁嵌套标记,下面的示例与上例输出相同:

ul
li.first: a(href=’#’) foo
li: a(href=’#’) bar
li.last: a(href=’#’) baz

特性

目前Jade支持’(‘和’)’的特性定界符。

a(href=’/login’, title=’View login page’) Login

另外我们也可以使用冒号(:)来作为分割符:

a(href: ‘/login’, title: ‘注册成为Saecn.com会员’) Login

Boolean特性也被支持:

input(type=”checkbox”, checked)

值为变量的Boolean特性只有在值为true时输出:

input(type=”checkbox”, checked: someValue)

分拆在多行也能正常解析:

input(type=’checkbox’,
name=’agreement’,
checked)

文档类型

利用!!!来增加页面的文档类型:

!!!

将会输出过渡型文档类型,然而:

!!! 5

将会输出HTML5的文档类型,下面是默认定义的文档类型,这也可以很容易的被扩展:

var doctypes = exports.doctypes = {
‘5’: ‘‘,
‘xml’: ‘‘,
‘default’: ‘‘,
‘transitional’: ‘‘,
‘strict’: ‘‘,
‘frameset’: ‘‘,
‘1.1’: ‘‘,
‘basic’: ‘‘,
‘mobile’: ‘‘
};

要修改默认值只需改变:

jade.doctypes.default = ‘whatever you want’;

过滤器
过滤器以冒号(:)作为前缀,如 :markdown 将会对文本进行函数处理,(一回注:类似Smarty的变量调节器),本页开始处列出了目前Jade支持的过滤器。

body
:markdown
Woah! jade _and_ markdown, very **cool**
we can even link to [Saecn](http://www.saecn.com)

渲染后:

<body><p>Woah! jade <em>and</em> markdown, very <strong>cool</strong> we can even link to <a href="http://www.saecn.com">Saecn</a></p></body>

过滤器也可以处理解析树,通常过滤器可以正常处理文本块,但是通过传入规则的块过滤器可以做任何它能做的。

body
conditionals:
if role == ‘admin’
p You are amazing
else
p Not so amazing

代码
Jade目前支持三种类型的可执行代码,第一种以-为前缀,不会被缓冲:

– var foo = ‘bar’;

这可被用于条件或循环:

– for (var key in obj)
p= obj[key]

由于Jade的缓冲技术,下面的代码是有效的:

– if (foo)
ul
li yay
li foo
li worked
– else
p oh no! you are not in saecn.com

甚至详细的迭代循环:

– if (items.length)
ul
– items.forEach(function(item){
li= item
– })

任何你希望的都可以实现!

接下来我们转义了缓冲代码,用于缓冲返回值,以等号(=)作为前缀:

– var foo = ‘bar’
= foo
h1= foo

输出: bar

bar

. 被’=’缓冲的代码会默认经过转义以增强安全性,要输出为转义的值需要使用 !=:

p!= aVarContainingMoreHTML

一个允许使用”vanilla”Javascript的例外,是 – each 标记,其表现形式为:

– each VAL[, KEY] in OBJ

实现循环数组的例子:

– var items = [“one”, “two”, “three”]
– each item in items
li= item

输出:

<li>one</li>
<li>two</li>
<li>three</li>

循环对象的键和值:

– var obj = { foo: ‘bar’ }
– each val, key in obj
li #{key}: #{val}

这会输出 <li>foo: bar</li>

也可以进行嵌套循环:

– each user in users
– each role in user.roles
li= role

当一个属性为undefined,Jade会输出空串,例如:

textarea= user.signature

近期的Jade版本会输出空字符串而不是undefined:

<textarea></textarea>

命令行工具:bin/jade
输出html到标准输出(stdout):

jade examples/*.jade --pipe

生成 examples/*.html :

jade examples/*.jade

传入参数:

jade examples/layout.jade --options '{ locals: { title: "Saecn" }}'

超快速搭建Ubuntu下Nodejs的开发环境

Nodejs很火,在Ubuntu下搭建它的开发环境尝尝鲜,有一个捷径,它能让系统自动帮你安装所需要的东西,我们生成一段shell脚本,让它来完成以下工作: 安装git下最新的node,node包管理器,Forever和Cloud9IDE工具(可选),mongodb 10gen;脚本的正常运行需要比较新板的Ubuntu,而且需要联网,因为它会连接网络去下载所有的依赖包顺序安装。

#!/bin/sh  
# Update System  
echo 'System Update'  
apt-get update  
echo 'Update completed'  
apt-get install libssl-dev git-core pkg-config build-essential curl  
# Clone Node.js  
echo 'Clone Node.js'  
cd /usr/src  
git clone https://github.com/joyent/node  
echo 'Node.js clone completed'  
# Install Node.js  
echo 'Install Node.js'  
cd node  
./configure && make && make install  
echo 'Node.js install completed'  
# Install Node Package Manager  
echo 'Install Node Package Manager'  
curl http://npmjs.org/install.sh | sh  
echo 'NPM install completed'  
# Install Forever  
echo 'Install Forever'  
npm install forever  
echo 'Forever install completed'  
# Install Cloud9IDE  
echo 'Install Cloud9IDE'  
git clone git://github.com/ajaxorg/cloud9.git  
echo 'Cloud9IDE install completed'  
# Install MongoDB  
echo 'Install MongoDB'  
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 7F0CEB10  
echo "deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen" >> /etc/apt/sources.list  
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 7F0CEB10  
sudo apt-get update  
sudo apt-get install mongodb-10gen  
echo 'MongoDB install completed.'

安装方法:

$ cd ~/  
$ nano -w node.sh

把以上代码粘贴到node.sh文件里,ctrl+o 保存,ctrl+x 退出nano。如果你没有安装nano,请google一下安装吧。
然后执行脚本:

$ chmod a+x node.sh && sudo ./node.sh

如果网速足够快,一会功夫即可完成安装。等安装完毕,我们来个测试:

mkdir node_project  
cd node_project  
nano -w server.js

粘贴以下著名的代码:

var http = require('http');  
http.createServer(function (req, res) {  
  res.writeHead(200, {'Content-Type': 'text/plain'});  
  res.end('Hello World\n');  
}).listen(1337, "127.0.0.1");  
console.log('Server running at http://127.0.0.1:1337/');

ctrl+o 保存,ctrl+x 退出nano,尝试跑它 :

node server.js

在浏览器中打开 :http://127.0.0.1:1337,看到久违的Hello World了吧?

[收藏]Ubuntu常用命令大全

今天心血来潮安装Ubuntu 12嘿嘿,不过是虚拟机安装的,第一次接触的是Server版,命令行操作头疼啊,恶补一下常用命令吧!

查看软件xxx安装内容
#dpkg -L xxx

查找软件
#apt-cache search 正则表达式
查找文件属于哪个包
#dpkg -S filename apt-file search filename

查询软件xxx依赖哪些包
#apt-cache depends xxx

查询软件xxx被哪些包依赖
#apt-cache rdepends xxx

增加一个光盘源
#sudo apt-cdrom add

系统升级
#sudo apt-get update
#sudo apt-get upgrade
#sudo apt-get dist-upgrade

清除所以删除包的残余配置文件
#dpkg -l |grep ^rc|awk ‘{print $2}’ |tr [””n”] [” “]|sudo xargs dpkg -P –

编译时缺少h文件的自动处理
#sudo auto-apt run ./configure

查看安装软件时下载包的临时存放目录
#ls /var/cache/apt/archives

备份当前系统安装的所有包的列表
#dpkg –get-selections | grep -v deinstall > ~/somefile

从上面备份的安装包的列表文件恢复所有包
#dpkg –set-selections < ~/somefile sudo dselect 清理旧版本的软件缓存 #sudo apt-get autoclean 清理所有软件缓存 #sudo apt-get clean 删除系统不再使用的孤立软件 #sudo apt-get autoremove 查看包在服务器上面的地址 #apt-get -qq –print-uris install ssh | cut -d"’ -f2 系统 查看内核 #uname -a 查看Ubuntu版本 #cat /etc/issue 查看内核加载的模块 #lsmod 查看PCI设备 #lspci 查看USB设备 #lsusb 查看网卡状态 #sudo ethtool eth0 查看CPU信息 #cat /proc/cpuinfo 显示当前硬件信息 #lshw 硬盘 查看硬盘的分区 #sudo fdisk -l 查看IDE硬盘信息 #sudo hdparm -i /dev/hda 查看STAT硬盘信息 #sudo hdparm -I /dev/sda 或 #sudo apt-get install blktool #sudo blktool /dev/sda id 查看硬盘剩余空间 #df -h #df -H 查看目录占用空间 #du -hs 目录名 优盘没法卸载 #sync fuser -km /media/usbdisk 内存 查看当前的内存使用情况 #free -m 进程 查看当前有哪些进程 #ps -A 中止一个进程 #kill 进程号(就是ps -A中的第一列的数字) 或者 killall 进程名 强制中止一个进程(在上面进程中止不成功的时候使用) #kill -9 进程号 或者 killall -9 进程名 图形方式中止一个程序 #xkill 出现骷髅标志的鼠标,点击需要中止的程序即可 查看当前进程的实时状况 #top 查看进程打开的文件 #lsof -p ADSL 配置 ADSL #sudo pppoeconf ADSL手工拨号 #sudo pon dsl-provider 激活 ADSL #sudo /etc/ppp/pppoe_on_boot 断开 ADSL #sudo poff 查看拨号日志 #sudo plog 如何设置动态域名 #首先去http://www.3322.org申请一个动态域名 #然后修改 /etc/ppp/ip-up 增加拨号时更新域名指令 sudo vim /etc/ppp/ip-up #在最后增加如下行 w3m -no-cookie -dump 网络 根据IP查网卡地址 #arping IP地址 查看当前IP地址 #ifconfig eth0 |awk ‘/inet/ {split($2,x,”:”);print x[2]}’ 查看当前外网的IP地址 #w3m -no-cookie -dumpwww.edu.cn|grep-o‘[0-9]"{1,3"}".[0-9]"{1,3"}".[0-9]"{1,3"}".[0-9]"{1,3"}’ #w3m -no-cookie -dumpwww.xju.edu.cn|grep-o’[0-9]"{1,3"}".[0-9]"{1,3"}".[0-9]"{1,3"}".[0-9]"{1,3"}’ #w3m -no-cookie -dump ip.loveroot.com|grep -o’[0-9]"{1,3"}".[0-9]"{1,3"}".[0-9]"{1,3"}".[0-9]"{1,3"}’ 查看当前监听80端口的程序 #lsof -i :80 查看当前网卡的物理地址 #arp -a | awk ‘{print $4}’ ifconfig eth0 | head -1 | awk ‘{print $5}’ 立即让网络支持nat #sudo echo 1 > /proc/sys/net/ipv4/ip_forward
#sudo iptables -t nat -I POSTROUTING -j MASQUERADE

查看路由信息
#netstat -rn sudo route -n

手工增加删除一条路由
#sudo route add -net 192.168.0.0 netmask 255.255.255.0 gw 172.16.0.1
#sudo route del -net 192.168.0.0 netmask 255.255.255.0 gw 172.16.0.1

修改网卡MAC地址的方法
#sudo ifconfig eth0 down 关闭网卡
#sudo ifconfig eth0 hw ether 00:AA:BB:CC:DD:EE 然后改地址
#sudo ifconfig eth0 up 然后启动网卡

统计当前IP连接的个数
#netstat -na|grep ESTABLISHED|awk ‘{print $5}’|awk -F: ‘{print $1}’|sort|uniq -c|sort -r -n
#netstat -na|grep SYN|awk ‘{print $5}’|awk -F: ‘{print $1}’|sort|uniq -c|sort -r -n

统计当前20000个IP包中大于100个IP包的IP地址
#tcpdump -tnn -c 20000 -i eth0 | awk -F “.” ‘{print $1″.”$2″.”$3″.”$4}’ | sort | uniq -c | sort -nr | awk ‘ $1 > 100 ‘

屏蔽IPV6
#echo “blacklist ipv6″ | sudo tee /etc/modprobe.d/blacklist-ipv6

服务
添加一个服务
#sudo update-rc.d 服务名 defaults 99

删除一个服务
#sudo update-rc.d 服务名 remove

临时重启一个服务
#/etc/init.d/服务名 restart

临时关闭一个服务
#/etc/init.d/服务名 stop

临时启动一个服务
#/etc/init.d/服务名 start

设置
配置默认Java使用哪个
#sudo update-alternatives –config java

修改用户资料
#sudo chfn userid

给apt设置代理
#export http_proxy=http://xx.xx.xx.xx:xxx

修改系统登录信息
#sudo vim /etc/motd

中文
转换文件名由GBK为UTF8
#sudo apt-get install convmv convmv -r -f cp936 -t utf8 –notest –nosmart *

批量转换src目录下的所有文件内容由GBK到UTF8
#find src -type d -exec mkdir -p utf8/{} “; find src -type f -exec iconv -f GBK -t UTF-8 {} -o utf8/{} “; mv utf8/* src rm -fr utf8

转换文件内容由GBK到UTF8
#iconv -f gbk -t utf8 $i > newfile

转换 mp3 标签编码
#sudo apt-get install python-mutagen find . -iname “*.mp3” -execdir mid3iconv -e GBK {} “;

控制台下显示中文
#sudo apt-get install zhcon 使用时,输入zhcon即可

文件
快速查找某个文件
#whereis filename
#find 目录 -name 文件名

查看文件类型
#file filename

显示xxx文件倒数6行的内容
#tail -n 6 xxx

让tail不停地读地最新的内容
#tail -n 10 -f /var/log/apache2/access.log

查看文件中间的第五行(含)到第10行(含)的内容
#sed -n ‘5,10p’ /var/log/apache2/access.log

查找包含xxx字符串的文件
#grep -l -r xxx .

全盘搜索文件(桌面可视化)
gnome-search-tool

查找关于xxx的命令
#apropos xxx man -k xxx

通过ssh传输文件
#scp -rp /path/filenameusername@remoteIP:/path
#将本地文件拷贝到服务器上
#scp -rpusername@remoteIP:/path/filename/path
#将远程文件从服务器下载到本地

查看某个文件被哪些应用程序读写
#lsof 文件名

把所有文件的后辍由rm改为rmvb
#rename ’s/.rm$/.rmvb/’ *

把所有文件名中的大写改为小写
#rename ‘tr/A-Z/a-z/’ *

删除特殊文件名的文件,如文件名:–help.txt
#rm — –help.txt 或者 rm ./–help.txt

查看当前目录的子目录
#ls -d */. 或 echo */.

将当前目录下最近30天访问过的文件移动到上级back目录
#find . -type f -atime -30 -exec mv {} ../back “;

将当前目录下最近2小时到8小时之内的文件显示出来
#find . -mmin +120 -mmin -480 -exec more {} “;

删除修改时间在30天之前的所有文件
#find . -type f -mtime +30 -mtime -3600 -exec rm {} “;

查找guest用户的以avi或者rm结尾的文件并删除掉
#find . -name ‘*.avi’ -o -name ‘*.rm’ -user ‘guest’ -exec rm {} “;

查找的不以java和xml结尾,并7天没有使用的文件删除掉
#find . ! -name *.java ! -name ‘*.xml’ -atime +7 -exec rm {} “;

统计当前文件个数
#ls /usr/bin|wc -w

统计当前目录个数
#ls -l /usr/bin|grep ^d|wc -l

显示当前目录下2006-01-01的文件名
#ls -l |grep 2006-01-01 |awk ‘{print $8}’

FTP
上传下载文件工具-filezilla
#sudo apt-get install filezilla

filezilla无法列出中文目录?
站点->字符集->自定义->输入:GBK

本地中文界面
1)下载filezilla中文包到本地目录,如~/
2)#unrar x Filezilla3_zhCN.rar
3) 如果你没有unrar的话,请先安装rar和unrar
#sudo apt-get install rar unrar
#sudo ln -f /usr/bin/rar /usr/bin/unrar
4)先备份原来的语言包,再安装;实际就是拷贝一个语言包。
#sudo cp /usr/share/locale/zh_CN/filezilla.mo /usr/share/locale/zh_CN/filezilla.mo.bak
#sudo cp ~/locale/zh_CN/filezilla.mo /usr/share/locale/zh_CN/filezilla.mo
5)重启filezilla,即可!

解压缩
解压缩 xxx.tar.gz
#tar -zxvf xxx.tar.gz

解压缩 xxx.tar.bz2
#tar -jxvf xxx.tar.bz2

压缩aaa bbb目录为xxx.tar.gz
#tar -zcvf xxx.tar.gz aaa bbb

压缩aaa bbb目录为xxx.tar.bz2
#tar -jcvf xxx.tar.bz2 aaa bbb

解压缩 RAR 文件
1) 先安装
#sudo apt-get install rar unrar
#sudo ln -f /usr/bin/rar /usr/bin/unrar
2) 解压
#unrar x aaaa.rar

解压缩 ZIP 文件
1) 先安装
#sudo apt-get install zip unzip
#sudo ln -f /usr/bin/zip /usr/bin/unzip
2) 解压
#unzip x aaaa.zip

Nautilus
显示隐藏文件
Ctrl+h

显示地址栏
Ctrl+l

特殊 URI 地址
* computer:/// – 全部挂载的设备和网络
* network:/// – 浏览可用的网络
* burn:/// – 一个刻录 CDs/DVDs 的数据虚拟目录
* smb:/// – 可用的 windows/samba 网络资源
* x-nautilus-desktop:/// – 桌面项目和图标
*file:///- 本地文件
* trash:/// – 本地回收站目录
* ftp:// – FTP 文件夹
* ssh:// – SSH 文件夹
* fonts:/// – 字体文件夹,可将字体文件拖到此处以完成安装
* themes:/// – 系统主题文件夹

查看已安装字体
在nautilus的地址栏里输入”fonts:///“,就可以查看本机所有的fonts

程序
详细显示程序的运行信息
#strace -f -F -o outfile

日期和时间

设置日期
#date -s mm/dd/yy

设置时间
#date -s HH:MM

将时间写入CMOS
#hwclock –systohc

读取CMOS时间
#hwclock –hctosys

从服务器上同步时间
#sudo ntpdate time.nist.gov
#sudo ntpdate time.windows.com

控制台

不同控制台间切换
Ctrl + ALT + ← Ctrl + ALT + →

指定控制台切换
Ctrl + ALT + Fn(n:1~7)

控制台下滚屏
SHIFT + pageUp/pageDown

控制台抓图
#setterm -dump n(n:1~7)

数据库
mysql的数据库存放在地方
#/var/lib/mysql

从mysql中导出和导入数据
#mysqldump 数据库名 > 文件名 #导出数据库
#mysqladmin create 数据库名 #建立数据库
#mysql 数据库名 < 文件名 #导入数据库 忘了mysql的root口令怎么办 #sudo /etc/init.d/mysql stop #sudo mysqld_safe –skip-grant-tables #sudo mysqladmin -u user password ‘newpassword” #sudo mysqladmin flush-privileges 修改mysql的root口令 #sudo mysqladmin -uroot -p password ‘你的新密码’ 其它 下载网站文档 #wget -r -p -np -khttp://www.21cn.com · r:在本机建立服务器端目录结构; · -p: 下载显示HTML文件的所有图片; · -np:只下载目标站点指定目录及其子目录的内容; · -k: 转换非相对链接为相对链接。 如何删除Totem电影播放机的播放历史记录 #rm ~/.recently-used 如何更换gnome程序的快捷键 点击菜单,鼠标停留在某条菜单上,键盘输入任意你所需要的键,可以是组合键,会立即生效; 如果要清除该快捷键,请使用backspace vim 如何显示彩色字符 #sudo cp /usr/share/vim/vimcurrent/vimrc_example.vim /usr/share/vim/vimrc 如何在命令行删除在会话设置的启动程序 #cd ~/.config/autostart rm 需要删除启动程序 如何提高wine的反应速度 #sudo sed -ie ‘/GBK/,/^}/d’ /usr/share/X11/locale/zh_CN.UTF-8/XLC_LOCALE #chgrp [语法]: chgrp [-R] 文件组 文件… [说明]: 文件的GID表示文件的文件组,文件组可用数字表示, 也可用一个有效的组名表示,此命令改变一个文件的GID,可参看chown。 -R 递归地改变所有子目录下所有文件的存取模式 [例子]: #chgrp group file 将文件 file 的文件组改为 group #chmod [语法]: chmod [-R] 模式 文件… 或 chmod [ugoa] {+|-|=} [rwxst] 文件… [说明]: 改变文件的存取模式,存取模式可表示为数字或符号串,例如: #chmod nnnn file , n为0-7的数字,意义如下: 4000 运行时可改变UID 2000 运行时可改变GID 1000 置粘着位 0400 文件主可读 0200 文件主可写 0100 文件主可执行 0040 同组用户可读 0020 同组用户可写 0010 同组用户可执行 0004 其他用户可读 0002 其他用户可写 0001 其他用户可执行 nnnn 就是上列数字相加得到的,例如 chmod 0777 file 是指将文件 file 存取权限置为所有用户可读可写可执行。 -R 递归地改变所有子目录下所有文件的存取模式 u 文件主 g 同组用户 o 其他用户 a 所有用户 + 增加后列权限 - 取消后列权限 = 置成后列权限 r 可读 w 可写 x 可执行 s 运行时可置UID t 运行时可置GID [例子]: #chmod 0666 file1 file2 将文件 file1 及 file2 置为所有用户可读可写 #chmod u+x file 对文件 file 增加文件主可执行权限 #chmod o-rwx 对文件file 取消其他用户的所有权限 #chown [语法]: chown [-R] 文件主 文件… [说明]: 文件的UID表示文件的文件主,文件主可用数字表示, 也可用一个有效的用户名表示,此命令改变一个文件的UID,仅当此文件的文件主或超级用户可使用。 -R 递归地改变所有子目录下所有文件的存取模式 [例子]: #chown mary file 将文件 file 的文件主改为 mary #chown 150 file 将文件 file 的UID改为150 Ubuntu命令行下修改网络配置 以eth0为例 1. 以DHCP方式配置网卡 编辑文件/etc/network/interfaces: #sudo vi /etc/network/interfaces 并用下面的行来替换有关eth0的行: # The primary network interface - use DHCP to find our address auto eth0 iface eth0 inet dhcp 用下面的命令使网络设置生效: #sudo /etc/init.d/networking restart 当然,也可以在命令行下直接输入下面的命令来获取地址 #sudo dhclient eth0 2. 为网卡配置静态IP地址 编辑文件/etc/network/interfaces: #sudo vi /etc/network/interfaces 并用下面的行来替换有关eth0的行: # The primary network interface auto eth0 iface eth0 inet static address 192.168.3.90 gateway 192.168.3.1 netmask 255.255.255.0 network 192.168.3.0 broadcast 192.168.3.255 将上面的ip地址等信息换成你自己就可以了. 用下面的命令使网络设置生效: #sudo /etc/init.d/networking restart 3. 设定第二个IP地址(虚拟IP地址) 编辑文件/etc/network/interfaces: #sudo vi /etc/network/interfaces 在该文件中添加如下的行: auto eth0:1 iface eth0:1 inet static address 192.168.1.60 netmask 255.255.255.0 network x.x.x.x broadcast x.x.x.x gateway x.x.x.x 根据你的情况填上所有诸如address,netmask,network,broadcast和gateways等信息. 用下面的命令使网络设置生效: #sudo /etc/init.d/networking restart 4. 设置主机名称(hostname) 使用下面的命令来查看当前主机的主机名称: #sudo /bin/hostname 使用下面的命令来设置当前主机的主机名称: #sudo /bin/hostname newname 系统启动时,它会从/etc/hostname来读取主机的名称. 5. 配置DNS 首先,你可以在/etc/hosts中加入一些主机名称和这些主机名称对应的IP地址,这是简单使用本机的静态查询. 要访问DNS 服务器来进行查询,需要设置/etc/resolv.conf文件. 假设DNS服务器的IP地址是192.168.3.2, 那么/etc/resolv.conf文件的内容应为: search test.com nameserver 192.168.3.2 安装AMP服务 如果采用Ubuntu Server CD开始安装时,可以选择安装,这系统会自动装上apache2,php5和mysql5。下面主要说明一下如果不是安装的Ubuntu server时的安装方法。 用命令在Ubuntu下架设Lamp其实很简单,用一条命令就完成。在终端输入以下命令: #sudo apt-get install apache2 mysql-server php5 php5-mysql php5-gd #phpmyadmin 装好后,mysql管理员是root,无密码,通过http://localhost/phpmyadmin就可以访问mysql了 修改 MySql 密码 终端下输入: #mysql -u root #mysql> GRANT ALL PRIVILEGES ON *.* TO root@localhost IDENTIFIED BY “123456″;
’123456‘是root的密码,可以自由设置,但最好是设个安全点的。
#mysql> quit; 退出mysql

apache2的操作命令
启动:#sudo /etc/init.d/apache2 start
重启:#sudo /etc/init.d/apache2 restart
关闭:#sudo /etc/init.d/apache2 stop
apache2的默认主目录:/var/www/

原文地址:http://www.blogjava.net/bukebushuo/archive/2009/08/27/283427.html

[扫盲]css中使用的中文转化码

是不是在CSS文件中定义个性中文字体而烦恼呢?现在就告诉你一个方法吧!

有一种快速获得字体 Unicode 编码的方法,如果你使用火狐的 Firebug 插件,直接在控制台中输入 escape(‘黑体’),就可以得到黑体的 Unicode 编码,但需要经过处理才可以使用到 CSS 文件中来,请看下图所示:

201103171204317592

于此获得到了 “%u9ED1%u4F53″,将其改写为 “\9ED1\4F53″ 即可写入 CSS 文件。

这样或许还是有些小麻烦,那也没关系,芒果这里有一份比较完整的表格,自己查吧。

中文名 Unicode
新细明体 \65B0\7EC6\660E\4F53
细明体 \7EC6\660E\4F53
标楷体 \6807\6977\4F53
黑体 \9ED1\4F53
宋体 \5B8B\4F53
新宋体 \65B0\5B8B\4F53
仿宋 \4EFF\5B8B
楷体 \6977\4F53
仿宋_GB2312 \4EFF\5B8B_GB2312
楷体_GB2312 \6977\4F53_GB2312
微软正黑体 \5FAE\x8F6F\6B63\9ED1\4F53
微软雅黑 \5FAE\8F6F\96C5\9ED1

原文转自:http://appwycom.w08.ivip.cn/?p=316

基于jQuery的五子棋等多子棋游戏插件

今天早上一来呢就将多子棋插件版本更新到V0.1.1,主要原因是昨晚回家完了一下,发现这个游戏在某种特定的情况下会失去判断输赢的情况,接下来就列一下这个插件的详细信息:

/******************************************
* 多子棋插件
*
* @作者 :听涛设计
* @版权 :Copyright (c) 2013 听涛TinTao.
* @网址 :http://www.saecn.com
* @更新 : 2013-05-08
* @版本 :Version 0.1.1
*
******************************************/

主要功能:

1.可以实现多子棋游戏效果;

2.可以自由设定多少棋子连成串可以赢;

3.可以设置游戏画布的宽高;

游戏源码已经更新到GitHub:https://github.com/jactorew/wzGame

DEMO可以移步:jQuery五子棋游戏

欢迎大家多多指正多提意见。

游戏缺点:

UI素材来自互联网,没有独立的CSS样式文件,对于修改皮肤比较困难。

[学习]深入理解struts2的执行流程、工作原理

Struts2框架本身大致可以分为3个部分:核心控制器FilterDispatcher、业务控制器Action和用户实现的企业业务逻辑组件。核心控制器FilterDispatcher是Struts 2框架的基础,包含了框架内部的控制流程和处理机制。业务控制器Action和业务逻辑组件是需要用户来自己实现的。用户在开发Action和业务逻辑组件的同时,还需要编写相关的配置文件,供核心控制器FilterDispatcher来使用。
Struts 2的工作流程相对于Struts 1要简单,与WebWork框架基本相同,所以说Struts 2是WebWork的升级版本。

基本简要流程如下:
1、客户端浏览器发出HTTP请求。
2、根据web.xml配置,该请求被FilterDispatcher接收。
3、根据struts.xml配置,找到需要调用的Action类和方法, 并通过IoC方式,将值注入给Aciton。
4、Action调用业务逻辑组件处理业务逻辑,这一步包含表单验证。
5、Action执行完毕,根据struts.xml中的配置找到对应的返回结果result,并跳转到相应页面。
6、返回HTTP响应到客户端浏览器。

Struts工作机制?为什么要使用Struts?
工作机制:
Struts的工作流程:
在web应用启动时就会加载初始化ActionServlet,ActionServlet从
struts-config.xml文件中读取配置信息,把它们存放到各种配置对象
当ActionServlet接收到一个客户请求时,将执行如下流程.
-(1)检索和用户请求匹配的ActionMapping实例,如果不存在,就返回请求路径无效信息;
-(2)如果ActionForm实例不存在,就创建一个ActionForm对象,把客户提交的表单数据保存到ActionForm对象中;
-(3)根据配置信息决定是否需要表单验证.如果需要验证,就调用ActionForm的validate()方法;
-(4)如果ActionForm的validate()方法返回null或返回一个不包含ActionMessage的ActuibErrors对象, 就表示表单验证成功;
-(5)ActionServlet根据ActionMapping所包含的映射信息决定将请求转发给哪个Action,如果相应的 Action实例不存在,就先创建这个实例,然后调用Action的execute()方法;
-(6)Action的execute()方法返回一个ActionForward对象,ActionServlet在把客户请求转发给 ActionForward对象指向的JSP组件;
-(7)ActionForward对象指向JSP组件生成动态网页,返回给客户;

为什么要用:
JSP、Servlet、JavaBean技术的出现给我们构建强大的企业应用系统提供了可能。但用这些技术构建的系统非常的繁乱,所以在此之上,我们需要一个规则、一个把这些技术组织起来的规则,这就是框架,Struts便应运而生。

基于Struts开发的应用由3类组件构成:控制器组件、模型组件、视图组件

Struts的validate框架是如何验证的?
在struts配置文件中配置具体的错误提示,再在FormBean中的validate()方法具体调用。

说下Struts的设计模式 
MVC模式: web应用程序启动时就会加载并初始化ActionServler。用户提交表单时,一个配置好的ActionForm对象被创建,并被填入表单相应的数据,ActionServler根据Struts-config.xml文件配置好的设置决定是否需要表单验证,如果需要就调用ActionForm的 Validate()验证后选择将请求发送到哪个Action,如果Action不存在,ActionServlet会先创建这个对象,然后调用 Action的execute()方法。Execute()从ActionForm对象中获取数据,完成业务逻辑,返回一个ActionForward对象,ActionServlet再把客户请求转发给ActionForward对象指定的jsp组件,ActionForward对象指定的jsp生成动态的网页,返回给客户。

struts1和struts2的区别其实并不是太大,两者的区别:

 

Action 类:

◆Struts1要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口。
◆Struts 2 Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去实现 常用的接口。Action接口不是必须的,任何有execute标识的POJO对象都可以用作Struts2的Action对象。

 

线程模式:

◆Struts1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。
◆Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题)

 

Servlet 依赖: 

◆Struts1 Action 依赖于Servlet API ,因为当一个Action被调用时HttpServletRequest 和 HttpServletResponse 被传递给execute方法。
◆Struts 2 Action不依赖于容器,允许Action脱离容器单独被测试。如果需要,Struts2 Action仍然可以访问初始的request和response。但是,其他的元素减少或者消除了直接访问HttpServetRequest 和 HttpServletResponse的必要性。

 

可测性: 

◆测试Struts1 Action的一个主要问题是execute方法暴露了servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测试)。
◆Struts 2 Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。

 

捕获输入: 

◆Struts1 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经常创建多余的类捕获输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存在的JavaBean(仍然会导致有冗余的javabean)。
◆ Struts 2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种ModelDriven 特性简化了taglib对POJO输入对象的引用。

 

表达式语言:

◆Struts1 整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。
◆Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--”Object Graph Notation Language” (OGNL).

 

 绑定值到页面(view):

◆ Struts 1使用标准JSP机制把对象绑定到页面中来访问。
◆Struts 2 使用 “ValueStack”技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重用页面(view)。

 

类型转换:

◆Struts 1 ActionForm 属性通常都是String类型。Struts1使用Commons-Beanutils进行类型转换。每个类一个转换器,对每一个实例来说是不可配置的。
◆Struts2 使用OGNL进行类型转换。提供基本和常用对象的转换器。

 

校验:

◆Struts 1支持在ActionForm的validate方法中手动校验,或者通过Commons Validator的扩展来校验。同一个类可以有不同的校验内容,但不能校验子对象。

◆Struts2支持通过validate方法和XWork校验框架来进行校验。XWork校验框架使用为属性类类型定义的校验和内容校验,来支持chain校验子属性

 

Action执行的控制: 

◆Struts1支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。
◆Struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用

转自:http://hi.baidu.com/m_mayi

教你在Seajs中如何使用Jquery和Jquery的插件

最近了解到seajs的模块化js开发不错,拿来一看,呵呵,傻眼了。seajs做原生javascript开发还不错,就是像我这样的jquery控木有办法了。在细心翻阅了seajs官方文档后发现,原来seajs提供有配置jquery的方法,于是乎博主就开始照着文档开始配置,结果是文件下载下来了,但是全部报错,咋个回事呢???代码如下:

seajs.config({
plugins: ['shim'],

alias: {
'jquery': {
src: './lib/jquery.1.8.2.min.js',
exports:'jQuery'
},

'jquery.ui.core': {
src: './lib/jquery.ui/jquery.ui.core.min.js',
deps: ['jquery']
}
}
});

看起来不应该是这里的问题,完全按照官方文档写的啊! 纠结了半天查阅了无数资料后,终于发现另一种在seajs中使用jquery和jquery插件的方法:

var $ = require('jquery');
require('./lib/jquery.ui/jquery.ui.core.min')($);

这个方法必须将所有的jquery和插件重新封装一次

define(function(require,exports,moudles){
return function(jQuery){
(function(){/*code*/})(jQuery);
}

})

这下就完美解决了,不过这种方法加载的jquery和插件只能在这个文件内部使用,相当于局部变量,页面和其他无依赖的js不能使用,好处是插件与框架间无干扰。

[收藏]交互设计的流程

2013041221

最近整理了下自己关于交互设计具体工作方法流程的资料,也是在项目中的一点心得,一点感触,谨写出来,与大家一起分享下。

ps:因为各家公司情况不一样,所以,里面的具体步骤,也是根据各家略有调整,但大的方法应该基本一样的。

我们大概从两大块来介绍,首先是具体的交互设计流程,还有就是在这个过程中要用到的具体工具及方法方式。

2013041222

交互设计流程中,基本按照以下3步骤进行:

2013041223

第一:初步的需求分析

在初步的需求分析当中,你需要做的是什么呢?

1、与需求方沟通,获取最直接的信息来源;

2、与PM沟通,了解产品的信息重点(PM负责产品的整个规划运筹,了解这些信息,有助于架构整理设计方向的筹划)

3、尽可能的方式,了解一些项目目标、背景、原因等方面的外部因素(在一些项目中,可能是由公司高层来决定项目的方向,所以尽可能的去了解多方的需求)

这个过程中,可能是在产品规划的时候,去参会了解,或者是在更前期的头脑风暴中了解产品大致的方向,有很多不确定及变化因素,这个时候,项目还没有真正的到交互设计阶段,但交互设计师要积极参与到项目中去,在前期就对项目有所了解。

忌讳,这样……….

1、需求拿来即做。——需求没有经过初步分析过滤,交互设计师拿来就开始进行。导致的最终结果:交互设计师直接沦为产品经理讨论产品方向的工具。

应该怎么做?——交互设计师应该基于前期的参与了解,及个人的经验(有必要甚至可以叫上对应产品线的用研分析师一起),对这个产品进行初步的判断,这个产品的可行性及合理性,如果根本不合理,这个产品就可以返回进行产品重新规划中………

2、需求不加分析。——需求没有经过中级的分析,交互设计师就开始着手进行。导致的最终结果,交互设计师陷入汪洋的产品规划讨论中。

应该怎么做?——基于前一步的判断,产品比较合理,可以接收进行。但是,这个产品给过来的需求,缺失了哪方面的东西,这些东西在我们具体架构中起着重要的作用。交互设计师应该对这个产品进行中级的分析,提取我们需要的东西,让需求方进行提前准备。

ps:其实在有些公司,如果有比较强大的PM的总体把控组织的话,这个初步需求分析,可能会在立项及相关的沟通中解决掉。但在PM不够强大的时候,IA其实分担着这部分工作,而且这个过程中,发现交互设计师的前期判断沟通还是很重要的。以上两种情况,在项目中也见到有人遇到类似的情况,在前期纠结了1个月,还是裹足不前,其实,这些在前期的分析中都可以避免掉。

第二:具体架构设计

前提:需求方已经确定通过了产品前期规划,并且具体的需求已经80%完备,就可以开始着手进入到具体的架构设计阶段了。

一定要记得:Think first,Design next!

其实,在做一个需求或者产品的时候,我们动手做的时间只占了10%——20%,80%——90%的时间在前面的阶段。

前期遇到一个“手机定时提醒”的一个需求,当时对应人员的处理,只是根据需求方的描述在具体页面加一个输入框及链接,而没有分析对应的业务需求及相关任务联系,导致只做出来了20%的东西,漏掉了80%的东西,反复修改调整了4次。

20130412242013041225

只见树木,不见森林,在具体的元素中迷失了…………..

1、详细需求分析阶段

确定着手做具体的产品了,就需要进行详细的需求分析阶段了,在这个阶段,我们需要做的:

1、梳理需求,找到最核心最真实的业务场景、功能。

2、了解业务功能逻辑,有助于进行交互流程设计

3、对信息进行初步的整理、筛选、分析

倾听业务的心声,分析讨论业务的逻辑、目的、内容,梳理业务特殊需求及模拟用户的逻辑。

2、任务流程阶段(Task Flow )

任务流程是根据前期PM提出的业务逻辑流程,根据用户的操作及心理模型搭建出来的任务流程图,任务流程图,是梳理主流程任务,了解核心功能目的,清楚不同的场景,业务流程直接关系着页面流程及场景页面的设计!

2013041226

3、页面流程(Page Flow )

页面流程,是架构必须的步骤,它能从整理角度把握整个架构,是整个架构的网站地图(sitmap),包括页面的整个流转,页面的入口、出口等。

2013041227

在架构图交付物中,页面流程也是整个框架的第一步。

4、线框图(Wire frames)

在线框图中,基于前面的分析准备,为了展示信息结构、功能设置、用户操作使用习惯,我们要在里面做哪些呢?

1、展示主要的内容、功能

2、对整体的布局、结构进行考虑

3、考虑信息的位置、顺序

4、用不同的字体字号、颜色(黑白灰色)展示出其层次、轻重

在做具体的线框图中,一般按照这3个小步骤进行,其实,这种先后顺序在小的修改及项目中,可以一起进行,但涉及到较复杂的大项目,还是按照先后顺序好些,不然,把它们混杂在一起,往往容易遗漏很多东西。

第一步:最正常的状态展示——线框图

2013041228

根据8/2原则,展示出80%用户能看到的最正常场景,确保它的信息操作顺畅、一致性。这样做,容易使你抓住主要用户,排除其他干扰信息,思路明了清晰;有助于能先从整体角度把握产品框架、流程,不至于陷入小细节的纠结中………..

第二步:全场景的状态展示——线框图

2013041229

把正常场景设计出来以后,就要进行分模块的全场景架构设计了,如果场景甚多,建议,先列出全部清单,在逐个进行设计。上面示意图为购物车1、2的场景展示,其中只是列出了部分,因为属于操作型页面,所以要把全部的状态展示出来,整体有30多种,所以,用这种方式,就不怕漏掉了。

第三步:交互说明文档——线框图

交互说明文档,是基于全场景架构设计出来之后,最终要交互出来的交付件,这个文档更倾向于给具体的前端开发及后台开发人员的。里面主要包括的内容有:

1、异常状态(报错、提示位置、最长字符、报错文案场景)

2、全部页面跳转(链接、button、弹出框、新出窗口、原页刷新……)

3、列显示最多条目、输入框最多字数、

4、点击的交互前后展示状态,点击中的交互形式……

ps:在做架构中,会发现很多人在一些事情上迷失掉,花费了很多的时间,所以这些也是在交互设计中需要注意的问题:

1、精美细致并不重要!——把真正的视觉涂色交给UI去做吧,他们更专业。(但架构展示要易于理解主次、信息层级的排布)

2、选择性价比较高的工具——不要把时间花在学习工具上,工具只是辅助想法的实现,是为了提高我们工作效率。

3、从最简单的开始,逐渐补充细节——要培养全局观,再注重细节修改。

20130412210

4、线框图不是“画”出来的,而是想出来的,是确认出来的——在做的过程中,多沟通,多交流。

第三:检查纠错

最终我们的交互架构,怎么确保产品符合用户的需求呢?这就需要我们架构后的检查纠错步骤。对架构的检查纠错,可以分两种:

1、基础自我检查。

这是做完架构之后自己的纠错检查。

包括:这是什么网站?(名称、logo、说明);我在哪儿?(网站定位、面包屑、导航、操作入口明确);有什么?(导航、目录、分类);能回吗?(返回、新开窗口、导航、面包屑);相同功能、文案统一、表达一致吗?

2、原型测试验证。

最终做出来的架构,需要设定一定的场景或者任务流,找用户进行测试,是否能按照正常的用户心智模型进行。——任务排查

20130412211

交互设计的工具和方法

工具:

纸和笔、Axure、Endawer / Mindmap/ conceptdraw、OmniGraffle

20130412212

方法:

概念图、可用性测试、卡片分类、角色模型、故事版、任务走查、任务流程、页面流程、交互设计说明等

[收藏]敏捷开发之Scrum扫盲篇

现在敏捷开发是越来越火了,人人都在谈敏捷,人人都在学习Scrum和XP…

 

为了不落后他人,于是我也开始学习Scrum,今天主要是对我最近阅读的相关资料,根据自己的理解,用自己的话来讲述Scrum中的各个环节,主要目的有两个,一个是进行知识的总结,另外一个是觉得网上很多学习资料的讲述方式让初学者不太容易理解;所以我决定写一篇扫盲性的博文,同时试着也与园内的朋友一起分享交流一下,希望对初学者有帮助。

 

 什么是敏捷开发?

敏捷开发(Agile Development)是一种以人为核心、迭代、循序渐进的开发方法。

怎么理解呢?首先,我们要理解它不是一门技术,它是一种开发方法,也就是一种软件开发的流程,它会指导我们用规定的环节去一步一步完成项目的开发;而这种开发方式的主要驱动核心是人;它采用的是迭代式开发;

 

为什么说是以人为核心?

我们大部分人都学过瀑布开发模型,它是以文档为驱动的,为什么呢?因为在瀑布的整个开发过程中,要写大量的文档,把需求文档写出来后,开发人员都是根据文档进行开发的,一切以文档为依据;而敏捷开发它只写有必要的文档,或尽量少写文档,敏捷开发注重的是人与人之间,面对面的交流,所以它强调以人为核心。

 

什么是迭代?

迭代是指把一个复杂且开发周期很长的开发任务,分解为很多小周期可完成的任务,这样的一个周期就是一次迭代的过程;同时每一次迭代都可以生产或开发出一个可以交付的软件产品。

 

关于Scrum和XP

前面说了敏捷它是一种指导思想或开发方式,但是它没有明确告诉我们到底采用什么样的流程进行开发,而Scrum和XP就是敏捷开发的具体方式了,你可以采用Scrum方式也可以采用XP方式;Scrum和XP的区别是,Scrum偏重于过程,XP则偏重于实践,但是实际中,两者是结合一起应用的,这里我主要讲Scrum。

 

什么是Scrum?

Scrum的英文意思是橄榄球运动的一个专业术语,表示“争球”的动作;把一个开发流程的名字取名为Scrum,我想你一定能想象出你的开发团队在开发一个项目时,大家像打橄榄球一样迅速、富有战斗激情、人人你争我抢地完成它,你一定会感到非常兴奋的。

而Scrum就是这样的一个开发流程,运用该流程,你就能看到你团队高效的工作。

 

【Scrum开发流程中的三大角色】

产品负责人(Product Owner)

主要负责确定产品的功能和达到要求的标准,指定软件的发布日期和交付的内容,同时有权力接受或拒绝开发团队的工作成果。

 

流程管理员(Scrum Master)

主要负责整个Scrum流程在项目中的顺利实施和进行,以及清除挡在客户和开发工作之间的沟通障碍,使得客户可以直接驱动开发。

 

开发团队(Scrum Team)

主要负责软件产品在Scrum规定流程下进行开发工作,人数控制在5~10人左右,每个成员可能负责不同的技术方面,但要求每成员必须要有很强的自我管理能力,同时具有一定的表达能力;成员可以采用任何工作方式,只要能达到Sprint的目标。

 

 

Scrum流程图

ScrumModel

 

//————————

下面,我们开始讲具体实施流程,但是在讲之前,我还要对一个英文单词进行讲解。

什么是Sprint?

Sprint是短距离赛跑的意思,这里面指的是一次迭代,而一次迭代的周期是1个月时间(即4个星期),也就是我们要把一次迭代的开发内容以最快的速度完成它,这个过程我们称它为Sprint。

 

如何进行Scrum开发?

1、我们首先需要确定一个Product Backlog(按优先顺序排列的一个产品需求列表),这个是由Product Owner 负责的;

2、Scrum Team根据Product Backlog列表,做工作量的预估和安排;

3、有了Product Backlog列表,我们需要通过 Sprint Planning Meeting(Sprint计划会议) 来从中挑选出一个Story作为本次迭代完成的目标,这个目标的时间周期是1~4个星期,然后把这个Story进行细化,形成一个Sprint Backlog;

4、Sprint Backlog是由Scrum Team去完成的,每个成员根据Sprint Backlog再细化成更小的任务(细到每个任务的工作量在2天内能完成);

5、在Scrum Team完成计划会议上选出的Sprint Backlog过程中,需要进行 Daily Scrum Meeting(每日站立会议),每次会议控制在15分钟左右,每个人都必须发言,并且要向所有成员当面汇报你昨天完成了什么,并且向所有成员承诺你今天要完成什么,同时遇到不能解决的问题也可以提出,每个人回答完成后,要走到黑板前更新自己的 Sprint burn down(Sprint燃尽图);

6、做到每日集成,也就是每天都要有一个可以成功编译、并且可以演示的版本;很多人可能还没有用过自动化的每日集成,其实TFS就有这个功能,它可以支持每次有成员进行签入操作的时候,在服务器上自动获取最新版本,然后在服务器中编译,如果通过则马上再执行单元测试代码,如果也全部通过,则将该版本发布,这时一次正式的签入操作才保存到TFS中,中间有任何失败,都会用邮件通知项目管理人员;

7、当一个Story完成,也就是Sprint Backlog被完成,也就表示一次Sprint完成,这时,我们要进行 Srpint Review Meeting(演示会议),也称为评审会议,产品负责人和客户都要参加(最好本公司老板也参加),每一个Scrum Team的成员都要向他们演示自己完成的软件产品(这个会议非常重要,一定不能取消);

8、最后就是 Sprint Retrospective Meeting(回顾会议),也称为总结会议,以轮流发言方式进行,每个人都要发言,总结并讨论改进的地方,放入下一轮Sprint的产品需求中;

 

 

下面是运用Scrum开发流程中的一些场景图:

2010-10-17_202447

上图是一个 Product Backlog 的示例。

 

2010-10-17_202749

上图就是每日的站立会议了,参会人员可以随意姿势站立,任务看板要保证让每个人看到,当每个人发言完后,要走到任务版前更新自己的燃尽图。

2010-10-17_202812

任务看版包含 未完成、正在做、已完成 的工作状态,假设你今天把一个未完成的工作已经完成,那么你要把小卡片从未完成区域贴到已完成区域。
2010-10-17_202832

每个人的工作进度和完成情况都是公开的,如果有一个人的工作任务在某一个位置放了好几天,大家都能发现他的工作进度出现了什么问题(成员人数最好是5~7个,这样每人可以使用一种专用颜色的标签纸,一眼就可以从任务版看出谁的工作进度快,谁的工作进度慢)

 

 

2010-10-17_202709

上图可不是扑克牌,它是计划纸牌,它的作用是防止项目在开发过程中,被某些人所领导。

怎么用的呢?比如A程序员开发一个功能,需要5个小时,B程序员认为只需要半小时,那他们各自取相应的牌,藏在手中,最后摊牌,如果时间差距很大,那么A和B就可以讨论A为什么要5个小时…

return top