给ClueMapper加上LDAP验证功能
一、什么是ClueMapper?
关于ClueMapper(官方网站:http://www.cluemapper.org)是什么东东,还是直接翻译它自己的文档吧:ClueMapper是一套基于WEB的、用于软件或者软件项目管理的应用程序,目前使用Trac来管理单个项目,同时增加了新建Trac实例、支持配置SVN等功能(ClueMapper is a web-based application for managing software and software-based consulting projects. Currently it uses Trac to handle individual projects but adds the ability to create new trac instances, svn configurations, etc.)简而言之:ClueMapper是一个基于Trac的(最新版使用的Trac版本是:Trac-0.11.1)、并且可新增Trac实例的多项目管理软件,并且支持SVN。因为基于Trac,所以ClueMapper也是Python语言环境下运行的软件。
ClueMapper的认证机制并没有延用Trac的机制,而是自己独立做了一系列的改进,主要是加入了repoze.who这个WSGI中间件,这样的话就意味着,只要repoze.who支持的登录方式,ClueMapper都支持,比如basicauth、htpasswd等。
然而不幸的是,在repoze.who支持的诸多认证方式中,恰恰没有ldap的验证支持,这就使得我们必须对ClueMapper的代码进行改进,以加进Ldap的认证支持进去。
二、安装和准备
1、安装ClueMapper
关于ClueMapper的安装,只简单的介绍几句,参照ClueMapper的安装文档可以很快上手:
去SVN取得CueMapper的源代码,编译即可。当然,在编译之前,需要先确定是否安装了Python的libxslt和sqlite3支持:
- svn co http://www.cluemapper.org/svn/buildout/trunk cluemapper
- cd cluemapper
- python bootstrap.py
- bin/buildout
buildout的过程会稍微慢一点,因为要下载一些包,等到Buildout完成,运行:
./bin/clue-server
不出意外的话,应该会看到如下提示:
2010-02-22 15:39:14,245 INFO [cluemapper] ClueMapper v0.8.4dev-r0-20100222 starting...
2010-02-22 15:39:14,246 INFO [cluemapper] Using configuration at 'etc/cluemapper/cluemapper.ini'
2010-02-22 15:39:14,246 INFO [cluemapper] Listening on ALL INTERFACES, port 8080
2010-02-22 15:39:14,246 INFO [cluemapper] Browse at http://127.0.0.1:8080
此时ClueMapper监听在8080端口。当然,如果系统的Python环境是2.6以上版本,则会碰到类似“DeprecationWarning: the md5 module is deprecated; use hashlib instead import md5”的Warning,这是因为Python2.6以后,不建议直接import md5模块的原因所导致,如果要去掉这个warning,只需要在所有import md5的地方,将之替换为import hashlib模块即可:
hashlib的MD5 Hash函数用法:
- import hashlib
- _s = hashlib.md5("hash string").hexdigest();
2、安装LDAP
其实自己编译安装ldap,是最靠谱的方法,虽然之前写过介绍Ubuntu下使用apt-get install方法安装ldap的文章,但个人其实非常反感apt-get安装的方式,更喜欢手动Configure安装(貌似是BSD系技术人员的通病?呵呵),安装Ldap之前,需要先安装BDB,我推荐使用BDB做为LDAP的支援数据库。
- wget ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/openldap-2.4.21.tgz
- tar xzvf openldap-2.4.21.tgz
- ./configure --prefix=/var/iapps/ldap
- make && make depend
- make install
配置ldap的Conf文件:
- $sudo vi /var/iapps/ldap/etc/openldap/slapd.conf
在头部加上:
- include /var/iapps/ldap/etc/openldap/schema/core.schema
- # added by handaoliang...
- include /var/iapps/ldap/etc/openldap/schema/cosine.schema
- include /var/iapps/ldap/etc/openldap/schema/misc.schema
- include /var/iapps/ldap/etc/openldap/schema/inetorgperson.schema
- include /var/iapps/ldap/etc/openldap/schema/openldap.schema
- include /var/iapps/ldap/etc/openldap/schema/nis.schema
在最后加上:
- database bdb
- suffix "dc=handaoliang,dc=com"
- rootdn "cn=Manager,dc=handaoliang,dc=com"
- # Cleartext passwords, especially for the rootdn, should
- # be avoid. See slappasswd(8) and slapd.conf(5) for details.
- # Use of strong authentication encouraged.
- rootpw iloveyou
- # The database directory MUST exist prior to running slapd AND
- # should only be accessible by the slapd and slap tools.
- # Mode 700 recommended.
- directory /var/iapps/ldap/var/openldap-data
- # Indices to maintain
- index objectClass eq
启动Ldap:
- $sudo /var/iapps/ldap/libexec/slapd
导入用户,测试Ldap安装成功。
3、安装repoze.who的ldap扩展:
安装repoze.who的ldap扩展之前,需要先安装python-ldap(http://pypi.python.org/pypi/python-ldap/2.3.10):
- wget -c http://pypi.python.org/packages/source/p/python-ldap/python-ldap-2.3.10.tar.gz
- tar -xzvf python-ldap-2.3.10.tar.gz
- python setup.py install
安装成功,写一段代码测试一下用Python来连Ldap:
- #!/usr/bin/python
- #-*- coding:utf-8 -*-
- import ldap
- try:
- conn = ldap.open("localhost")
- conn.protocol_version = ldap.VERSION3
- username = "Manager"
- password = "{SSHA}2JPeP6Y+3/N2n8orp+jwKZj1TN310DBw"
- conn.simple_bind(username,password)
- except ldap.LDAPError, e:
- print e
- baseDN = "ou=People,dc=handaoliang,dc=com"
- searchScope = ldap.SCOPE_SUBTREE
- retrieveAttributes = ["cn","userPassword","loginShell","uid"]
- searchFilter = "cn=dev"
- try:
- ldap_result_id = conn.search(baseDN,searchScope,searchFilter,retrieveAttributes)
- result_set = []
- while 1:
- result_type, result_data = conn.result(ldap_result_id, 0)
- if result_data == []:
- break
- else:
- if result_type == ldap.RES_SEARCH_ENTRY:
- result_set.append(result_data)
- #print result_set[0][0][1]['o'][0]
- print result_set
- except ldap.LDAPError, e:
- print e
返回正确结果,说明环境已经没有问题。然后安装repoze.who的ldap扩展,注意这里不从源码包里运行setup.py安装,而是直接把源码包里的ldap代码拷贝到ClueMapper的repoze.who eggs里,这样的话就避免了安装在Python的系统Libs里,因而方便修改它的源文件,后面会讲到:
到这里下载:http://pypi.python.org/pypi/repoze.who.plugins.ldap/1.0,取得1.0版本的tar.gz包,并解压:
- tar xzvf repoze.who.plugins.ldap-1.0.tar.gz
- cp -r repoze.who.plugins.ldap-1.0/repoze/who/plugins/ldap/ /home/handaoliang/cluemapper/eggs/repoze.who-1.0.18-py2.6.egg/repoze/who/plugins/
运行bin下面的python脚本:
$./bin/python
进入到python命令行:
- from repoze.who.plugins import ldap as repoze_ldap
- help(repoze_ldap)
如果import没有出错,并且看到File为:/home/handaoliang/cluemapper/eggs/repoze.who-1.0.5-py2.6.egg/repoze/who/plugins/ldap/__init__.py,则说明安装成功。
三、对repoze.who.plugins.ldap和ClueMapper的验证文件进行修改:
1、对repoze.who.plugins.ldap的修改:
先是repoze.who的ldap扩展,此时需要编辑/home/handaoliang/cluemapper/eggs/repoze.who-1.0.5-py2.6.egg/repoze/who/plugins/ldap/plugins.py文件:
查找:import ldap
在下面加上一句:ldap.set_option(ldap.OPT_REFERRALS, 0),变成:
- import ldap
- ldap.set_option(ldap.OPT_REFERRALS, 0)
查找:self.ldap_connection.simple_bind_s(dn, password)
将下面的return dn注释掉,改成:return identity['login']
修改后的代码如下:
- try:
- self.ldap_connection.simple_bind_s(dn, password)
- # The credentials are valid!
- # bug fixed by handaoliang...Return userid but not dn.
- return identity['login']
- #return dn
- except ldap.LDAPError,e:
- #by handaoliang:catched this error:
- #sys.stderr.write("%s\n" % e)
- return None
2、对ClueMapper的验证文件进行修改,编辑src/ClueMapper/src/clue/secure/auth.py文件:
- $vi /home/handaoliang/cluemapper/src/ClueMapper/src/clue/secure/auth.py
查找:from repoze.who.plugins import basicauth,在后面把repoze.who.plugins.ldap包含进来:
- from repoze.who.plugins import basicauth
- #added by handaoliang
- from repoze.who.plugins import ldap as repoze_ldap
查找:assert passwdfile,在后面加上如下语句:
- #added by handaoliang
- #LDAP Config
- LDAP_BASE_HOST = 'ldap://localhost'
- LDAP_BASE_DN = 'ou=People,dc=handaoliang,dc=com'
- #Add Plugins to repoze.who.
- ldap_auth = repoze_ldap.LDAPAuthenticatorPlugin(LDAP_BASE_HOST,LDAP_BASE_DN)
修改authenticators = [('ldap_auth', ldap_auth)]为authenticators = [('htpasswd', passwd),('ldap_auth', ldap_auth)]
- #Modified by handaoliang..
- #authenticators = [('ldap_auth', ldap_auth)]
- authenticators = [('htpasswd', passwd),('ldap_auth', ldap_auth)]
重新启动ClueMapper,访问:http://localhost:8080/此时即应该可以使用LDAP的账号密码登录。
您可以从这里下载到经过我修改的源码包:http://www.handaoliang.com/tools/fix_cluemapper.tar.gz
您可参照里面的README文件来进行安装:
#-*- coding:utf-8 -*-
INSTALL:
1.把auth.py放到$ClUEMAPPER_PATH/src/ClueMapper/src/clue/secure下面,覆盖原文件,覆盖前请备份原文件。
2.修改LDAP配置(编辑auth.py):
A.更改LDAP_BASE_HOST为LDAP数据库的HSOT连接,如ldap://localhost
B.更改LDAP_BASE_DN为LDAP的Base dn
C.保存文件。
3.将ldap文件夹拷贝到repoze.who-1.0.5-py2.6.egg下的repoze/who/plugins下面。其它的无须更改。
==============================
参考文档:
http://code.gustavonarea.net/repoze.who.plugins.ldap/Using.html
http://www.packtpub.com/article/installing-and-configuring-the-python-ldap-library-and-binding-to-an-ldap-directory
http://wiki.pylonshq.com/display/pylonscookbook/Authentication+and+Authorization+with+%60repoze.who%60
http://www.openldap.org/doc/admin24/quickstart.html
Ubuntu下配置LDAP
一、安装
ubuntu的源里面有openldap,只是不叫这个名字,执行如下命令可以安装
- handaoliang@laohan-ubuntu:~/work$ sudo apt-get install slapd ldap-utils db4.6-util
二、创建根目录密码:
- handaoliang@laohan-ubuntu:~/work$ slappasswd
- New password:
- Re-enter new password:
- {SSHA}kNDZz98aqP5BiU0KcRZ+19NC3ElnXLld
三.设置ldap信息
编辑/etc/ldap/lapd.conf文件,部分信息修改如下
- # 域名前缀
- suffix "dc=handaoliang,dc=com"
- # rootdn directive for specifying a superuser on the database. This is needed
- # for syncrepl.
- #rootdn的名字和密码,此处用明文,在luma客户端里面也同样用明文。
- rootdn "cn=admin,dc=handaoliang,dc=com"
- rootpw {SSHA}kNDZz98aqP5BiU0KcRZ+19NC3ElnXLld
- #此处是设置节点cn=admin,dc=handaoliang,dc=com下的用户可以自己修改密码。
- access to attrs=userPassword,shadowLastChange
- by dn="cn=admin,dc=handaoliang,dc=com" write
- by anonymous auth
- by self write
- by * none
- #此处设置cn=admin,dc=handaoliang,dc=com节点下的用户可以自己修改属性。
- access to *
- by dn="cn=admin,dc=handaoliang,dc=com" write
- by self write
- by * read
四、在当前目录下创建一个根用户ldif文件(注意:ldif文件的格式要求特别严格,错一个空格都不行):
handaoliang@laohan-ubuntu:~/work$ touch admin.ldif
handaoliang@laohan-ubuntu:~/work$ vi admin.ldif
加入如下配置:
- dn: dc=handaoliang,dc=com
- objectClass: dcObject
- objectClass: organizationalUnit
- dc: handaoliang
- ou: handaoliang dot com
- dn: cn=admin,dc=handaoliang,dc=com
- objectClass: simpleSecurityObject
- objectClass: organizationalRole
- cn: admin
- userPassword: secret
- description: ldap administrator
- dn: ou=people,dc=handaoliang,dc=com
- objectClass: organizationalUnit
- ou: people
- dn: ou=groups,dc=handaoliang,dc=com
- objectClass: organizationalUnit
- ou: groups
五、导入配置:
将openldap原来的数据库中的数据清空,并导入上面的ldif:
- handaoliang@laohan-ubuntu:~/work$ sudo dpkg-reconfigure slapd
- handaoliang@laohan-ubuntu:~/work$ sudo ldapadd -x -W -c -D "cn=admin,dc=handaoliang,dc=com" -f ~/handaoliang/admin.ldif
六、重新启动LDAP的守护进程
handaoliang@laohan-ubuntu:~/work$ sudo /etc/init.d/slapd restart
给VirtualBox安装Ubuntu环境下的VBOXADDITIONS
在给VirtualBox虚拟机的Ubuntu升级之后,原来安装的VBoxAdditions会失效,导致鼠标不能直接在Windows和Ubuntu之间切换。经过实践发现重新安装VBoxAdditions可以解决此问题:
步骤:
一、升级之后,按“右Ctrl”键切换出来,选取“设备”菜单上的“安装增强功能”。此时Ubuntu桌面上会出现一个VBOXADDITIONS_3光盘镜像。
二、打开一个终端,切换到ROOT权限:sudo su -
三、先安装build-essential和linux-header文件,具体操作是:
A、输入"aptitude install build-essential "安装build-essential文件。
B、输入"aptitude search linux-header"打开linux-header文件。
四、进入光盘,输入"cd /media/cdrom"。这里有一个SH脚本,可以用来安装VBoxAddition。
五、通过sh VBoxLinuxAdditions-x86.run help会看到相关帮助:
The following options are recognized:
all -- install all components of the Guest Additions
kernel-module -- only install the core components in the Linux kernel
vfs-module -- install the shared folder component
drm-module -- install the direct rendering kernel module
control -- install the VBoxControl command line interface
service -- install the guest service component
x11 -- install guest drivers for the X Window System
六、直接敲入:sh VBoxLinuxAdditions-x86.run,此时SH脚本执行,安装成功会有提示。
七、重启Ubuntu系统,shutdown -r now,重启之后就会发现鼠标已经可以自由切换了。
NodeJS探索
一、什么是NodeJS?
第一眼看到这个词,估计你和我一样,以为它不过是一个JavaScript框架吧?如果是,那么首先恭喜你,说明你的思维是正常的。其次鄙视你:凭什么带JS的就一定是JavaScript框架?你丫做技术的吧?最看不起你们这帮做技术的了,跟姓韩的那谁似的,没一点文化。
生活经验告诉我们,牛人往往都不怎么正常,正常人往往都成不了牛人。比如说NodeJS的发明者,这家伙就曾叫嚣说:其实JavaScript更适合做服务器端的并发编程。估计很多人听到这话都笑了,嗯,原谅我的可耻,我也笑了。令人欣慰的是上帝没有笑。当年上帝说要光,于是就有人脱了个精光。今天,上帝说我相信这个人能成,于是这个人还真成了,他弄了这么个东西:NodeJS--基于V8引擎的,使用事件驱动模型而不是复杂的多线程来获得可伸缩性,类似Ruby的EventMachine和Python的Twisted的轻量级WEBServer。
是不是很有意思?这意味着什么我想大伙都清楚吧?嗯,如果这东东真的可用,那就是说,以后前段后端都可以都用JavaScript来编程了,这对于JS程序员来说,真是一个莫大的福音,因为你们再也不用看着那帮做后台的孙子的脸色干活了,可以翻身做后端了。
好,废话到此,那接下来就请跟着我,开始NodeJS的探索之旅。
二、安装!
安装前先从NodeJS的官方网站下载其源代码:
- [root@www source]# wget http://s3.amazonaws.com/four.livejournal/20091028/node-v0.1.15.tar.gz
- [root@www source]# tar xzvf node-v0.1.15.tar.gz
- [root@www source]# cd node-v0.1.15
安装NodeJS很简单,一般情况下,Linux下常用的三步走即可。但需要注意的是:NodeJS需要2.3以上版本Python的支持,否则安装无法继续。
打开tools/waf-light,看到如下代码:
- #!/usr/bin/env python
- # encoding: utf-8
- # Thomas Nagy, 2005-2009
- # ...
- import os, sys
- if sys.hexversion<0x203000f: raise ImportError("Waf requires Python >= 2.3")
从以上代码我们知道,在安装脚本中,在Python脚本的头部指定了#!/usr/bin/env python,这就使得如果你的系统安装了自带的Python程序,则有可能由于版本不够高而无法安装。比如我的系统,是把Python2.5安装在了/usr/local/python252,同时未删除系统自带的低版本Python,此时如果configure,则会出错。
好吧,那我们建一个软连接:
- [root@www source]# sh
- [root@www source]# cd /usr/local/sbin/
- [root@www source]# ln -s /usr/local/python252/bin/python2.5 python
- [root@www source]# python
- [root@www source]# exit
此时执行的/usr/bin/env python,即可使用我们自己编译的Python。
PS.直接建软连接就可以了,这里之所以到sh环境下,是为了看一下sh环境。
执行configure,安装nodejs:
- [root@www source]# ./configure --prefix=/var/iapps/nodejs
- [root@www source]# make && make install
三、初次试用:
一切顺利,安装完成,写个脚本试试:
- #!/var/iapps/nodejs/bin/node
- var sys = require("/sys.js"), http = require("/http.js");
- http.createServer(function (req, res) {
- setTimeout(function () {
- res.sendHeader(200, {"Content-Type": "text/plain"});
- res.sendBody("Hello,This is Laohan(www.handaoliang.com)!");
- res.finish();
- }, 2000);
- }).listen(8000);
- sys.puts("Server running at http://127.0.0.1:8000/");
我相信,对于JavaScript程序员来说,这语法真是太熟悉了,除了第一、第二行之外。无论如何,我们要开始我们的梦想之旅了,那么接下来我们将example.js设置成可执行并运行它:
- [root@www source]# chmod +x example.js
- [root@www source]# ./example.js
此时屏幕显示:Server running at http://127.0.0.1:8000/
访问:http://127.0.0.1:8000/,如果看到页面输出:Hello,This is Laohan(www.handaoliang.com)!,那么恭喜你,安装成功了,接下来就需要发挥你自己的聪明才智,去实现各种强大的功能了。很激动人心吧?
后面将为大家深入分析NodeJS,敬请期待。
原创文章,转载请注明出处!
映射Windows文件到Linux
The following steps show you how to mount windows files in linux. Suppose your linux is fedora core. In your linux terminal, type commands:
以下几步将教您如何映射windows文件到linux,假设您的linux是fedora core,你可以在终端上输入:
1. su
Then type your root password.
输入密码。
2. uname -r -p
This shows you your linux kernel version.
这个命令显示你的linux内核版本。
3. Go to this website http://linux-ntfs.sourceforge.net/rpm/fedora3.html. Download the right rpm file that matches your kernel version and processor type (e.g. x86 or x86-64). Put the downloaded rpm in a temporary directory. Then cd to that directory.
到这个网站:http://linux-ntfs.sourceforge.net/rpm/fedora3.html下载符合内核版本的RPM包,把它放在临时下载文件夹里,然后进入这个文件夹。
4. rpm -ivh *.rpm
Type ‘y’ if asked.
安装RPM包,如果询问“yes or no”,输入“y”
5. su -
6. mkdir /mnt/windows
7. /sbin/fdisk -l
This shows you the HPFS/NTFS partition identifier.
显示HPFS/NTFS分区标识符。
8. vi /etc/fstab
If you do not have vi, you could use emacs /etc/fstab
编辑/etc/fstab文件,如果你没有装VI,你可以合用emacs来编辑/etc/fstab文件。
9. In the first row of the opened file fstab, insert the following line
在fstab文件的第一行,插入如下语句:
/dev/hda1 /mnt/windows ntfs ro,defaults,umask=0222 0 0
10. If your partition identifier is not “/dev/hda1″, replace “/dev/hda1″ with the right identifier showed in step 7.
如果分区标识不是“/dev/hda1”,那么根据实际情况将“/dev/hda1”替换成您的硬盘标识符。
11. Close the terminal. Reboot.
关掉终端,重启。
You are done. All the files in MS Windows can be read from /mnt/windows.
OK,不出意外的话,所有的Windows文件都可以在/mnt/windows里查看到。
———————————————-
老韩注:没啥技术含量的一篇小文章,有几点需要备注一下:
1、http://linux-ntfs.sourceforge.net/rpm/fedora3.html这个页面现在已经转向到http://www.linux-ntfs.org/,同时,文中所讲的软件现在叫:ntfs-3g,网站是:http://www.ntfs-3g.org/,从这里可以下载到它的最新版本。在我为写这篇文章而进行测试时下载的是.tgz源代码包。
2、编译的过程当中需要有fuse的支持,fuse可以从:http://fuse.sourceforge.net/下载到,顺便说一下Fuse这个东东:Fuse最初是为了支持AVFS而开发的轻量级文件系统实现工具,使用它,只需要100行左右的代码,就可以轻松地实现一个小文件系统,比如这段代码就实现了一个hello world的小文件系统。
- /*
- FUSE: Filesystem in Userspace
- Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
- This program can be distributed under the terms of the GNU GPL.
- See the file COPYING.
- */
- #include <fuse.h>
- #include <stdio.h>
- #include <string.h>
- #include <errno.h>
- #include <fcntl.h>
- static const char *hello_str = "Hello World!\n";
- static const char *hello_path = "/hello";
- static int hello_getattr(const char *path, struct stat *stbuf)
- {
- int res = 0;
- memset(stbuf, 0, sizeof(struct stat));
- if(strcmp(path, "/") == 0) {
- stbuf->st_mode = S_IFDIR | 0755;
- stbuf->st_nlink = 2;
- }
- else if(strcmp(path, hello_path) == 0) {
- stbuf->st_mode = S_IFREG | 0444;
- stbuf->st_nlink = 1;
- stbuf->st_size = strlen(hello_str);
- }
- else
- res = -ENOENT;
- return res;
- }
- static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
- off_t offset, struct fuse_file_info *fi)
- {
- (void) offset;
- (void) fi;
- if(strcmp(path, "/") != 0)
- return -ENOENT;
- filler(buf, ".", NULL, 0);
- filler(buf, "..", NULL, 0);
- filler(buf, hello_path + 1, NULL, 0);
- return 0;
- }
- static int hello_open(const char *path, struct fuse_file_info *fi)
- {
- if(strcmp(path, hello_path) != 0)
- return -ENOENT;
- if((fi->flags & 3) != O_RDONLY)
- return -EACCES;
- return 0;
- }
- static int hello_read(const char *path, char *buf, size_t size, off_t offset,
- struct fuse_file_info *fi)
- {
- size_t len;
- (void) fi;
- if(strcmp(path, hello_path) != 0)
- return -ENOENT;
- len = strlen(hello_str);
- if (offset < len) {
- if (offset + size > len)
- size = len - offset;
- memcpy(buf, hello_str + offset, size);
- } else
- size = 0;
- return size;
- }
- static struct fuse_operations hello_oper = {
- .getattr = hello_getattr,
- .readdir = hello_readdir,
- .open = hello_open,
- .read = hello_read,
- };
- int main(int argc, char *argv[])
- {
- return fuse_main(argc, argv, &hello_oper);
- }
编译完这个小程序之后,它的使用方法是:
- ~/fuse/example$ mkdir /tmp/fuse
- ~/fuse/example$ ./hello /tmp/fuse
- ~/fuse/example$ ls -l /tmp/fuse
- total 0
- -r--r--r-- 1 root root 13 Jan 1 1970 hello
- ~/fuse/example$ cat /tmp/fuse/hello
- Hello World!
- ~/fuse/example$ fusermount -u /tmp/fuse
- ~/fuse/example$
Fuse自从变成一个独立的项目之后,有很多其它的项目都在用它,如:OWFS等,具体可以查看这个页面:http://fuse.sourceforge.net/wiki/index.php/FileSystems,在使用这些项目的软件之前要先安装Fuse。