百度空间 | 百度首页 
 
文章列表
 
您正在查看 "Uliweb" 分类下的文章

2009-11-05 12:52

感谢张教主的帮助,不过现在还有一点点小问题,因为有些包还没装上。不过首页已经可以访问了。uliweb已经在张教主的stdyun上部署成功了。几点事项:

域名(我去的9host.cn申请的,. com.cn 只要3块钱,续费要50元)
有了域名要设置对应的IP(IP为:119.88.56.193),具体见张教主的说明(同时要注意修改9host的DNS时要使用IE浏览器。 )   

http://groups.google.com/group/python-cn/browse_thread/thread/3b00351b97b6690a#
然后runcgi.py需要将后缀改为.fcgi。 不过这个我要再更新一下uliweb。

回头我会写一个更详细的uliweb在stdyun上的部署说明。

声明,因为我使用的是免费试用,因此可能用的时间不会太长

类别:Uliweb | 评论(0) | 浏览()
 
2009-11-04 12:46

在经过对beaker中的session替换之后,我终于又把cache给替换掉了。完全是自个儿重写。一方面它可以象一个dict一样工作,同时可以通过put, get来调用。使用这两个函数的好处就是可以有更多的参数。目前这个类在uliweb/lib/weto/cache.py中。

创建cache

import weto.cache

cache = weto.cache.Cache()

这样可以创建一个cache。因为没有指定Cache类的初始化参数,因此会自动以file格式创建cache。如果需要指定其它的格式和参数,可以设置:

storage_type, options, expiry_time

这三个参数。storage是类型,目前只支持'file', 'dbm', 'database',分别对应三种不同的存储类型。

options则根据不同的类型有所区别,比如'file'类型需要传入'data_dir',用以指定cache保存的路径。而'database'则需要指明要使用的表名和数据库连接的一些信息。

expiry_time是指定缺省的超时时间。这是当你在put时没有指定超时时间时使用的,在调用put时可以单独设定。

cache.get(key)

这样的调用,如果key不存在,或超时则会引发一个异常抛出CacheKeyException异常。

如果不想引发异常,则可以:

cache.get(key, default)

其中default不能为None,这样当key不存在,则不会引发异常,返回default值。如果为None,则同get(key)的效果。

cache.put(key, value, expire=None)

这样可以设置一个cache。如果expire没有传入则使用缺省的超时时间。时间以秒为单位。

同时为了方便函数的封装,还提供了

cache.cache(key=None, expire=None)

这个decorator。例如:

@cache.cache(expire=15) 
def f(*args, **kwargs):

@cache.cache(key, expire=15) 
def f(*args, **kwargs):

这两种都是可以的,区别在于前一个没有key参数,那它将根据函数名和参数来生成一个key,而后面则是由用户主动指定了一个key。

在进行上进的改造之后,原来的beaker就删除了,这样uliweb中不再使用beaker了。同时对原uliweb.contrib.cache进行了修改,去掉了middle_cache.py,而采用让用户自行调用的机制。同时为了同app的配置功能相结合和方便用户使用,在uliweb/utils/cache.py中编写了一个get_cache()的函数,同时对Cache类的增加了page方法。

get_cache()可以自动从settings中找到相应的配置。目前主通过两个secion来控制的:

[CACHE]和[CACHE_STORAGE],前者用来控制cache的类型和超时时间。后者是用来针对每一种类型来设置与存储相关的配置信息。在调用get_cache()时,你还可以传入一些参数,它的原型是:

def get_cache(cache_setting_name='CACHE', cache_storage_setting_name='CACHE_STORAGE'):

即可以指明使用其它的配置名,这样就可以在你的settings.ini中存放不同的cache的配置,通过get_cache来使用不同的cache机制。

为什么要对Cache进行扩展,Cache.cache原来是针对函数本身和它的参数,但是这样对于view有一点问题。有些view可能通过QUERY_STRING来处理不同的传入参数,因此在url上它们不同,但是在view函数上是完全一样,因此这种只根据函数本身和参数是有问题的。因此扩展的page这个decorator使用了request.url值,它是一个完整的访问路径,包括了QUERY_STRING信息。因此为了生成静态cache,可以使用改造后的Cache类。当你调用get_cache()时返回的cache对象已经是使用了这个新的Cache类了。

所以为了方便和更适合在Uliweb环境下使用,可以使用uliweb.utils.cache的get_cache()函数。例如:

  1 
2
3
4
5
6
from uliweb.utils.cache import get_cache()
cache = get_cache() #使用缺省的settings.ini设置。因此需要加入uliweb.contrib.cache这个app
@cache.cache(expire=15)
@expose('/index')
def index():
return {}

现在我把uliwebproject也添加了cache的支持,不过发现的问题是,不能简单的使用@cache.page()来对view方法进行处理。原因是:

在view方法中有对cookie的处理,采用cache的方式会屏蔽掉这块处理

因此在uliwebproject中并不是使用的decorator的方式,而是在view中对可以cache化的部分进行了手工处理,如:

  1 
2
3
4
5
6
7
8
9
10
11
12
cache = get_cache()
@cache.cache(_f)
def f():
content = file(_f).read()
if render:
content = to_html(template(content, env=application.get_view_env()))
else:
content = to_html(content)
return application.template('show_document.html', locals())

response.write(f())
return response
完全是手工来处理了。
类别:Uliweb | 评论(0) | 浏览()
 
2009-11-02 22:16

性能与功能的确有些矛盾。因为开发uliweb更多是从功能上考虑,因此在性能上我一直没有太仔细测试和分析过。最近找了一个主机部署了一下,别人告诉我刷新一下CPU占用很高,于是我想有机会的确还是要好好搞一下。于是加了一些跟踪,发现了一些问题:

1. get_apps() 的问题

因为uliweb是采用app方式来组织,而且app是允许使用python的包形式。在启动时,为了查找app下的settings.ini和config.ini等信息,使用的是pkgresource的resource_filename,它是要导入才可以的。但是一个导入可能会使得加载变慢。这块的确有些问题。为了查找包的目录,因此要导入,但是后面的处理未必会使用这个包,显得有些浪费。因此我修改了这块处理。如果包是由a.b.c这样形式构成的,我会只导入a,后面两个直接根据a的目录生成一个路径。这样只要保证a的__init__.py中没有太多的耗时的代码就可以了。这样优化后减少了一些时间。

2. pytz的问题

因为uliweb的ORM会处理时区的问题,而且我写了一个utils/date.py模块专门来处理时区转换。因此在启动时,为了省事,我自动导入了date.py模块,它会自动导入pytz模块。但是我发现pytz的导入非常慢。这样造成整个uliweb的启动变慢。因此这块我直接去掉了,让用户自已来处理好了。

3. 可能会引起问题的地方。app的__init__.py文件。因为考虑有些bind的代码会写在__init__.py中,因此在启动app时会自动导入所有app。因此如果有app在这里写了很耗时的代码会影响整个uliweb的启动速度。也许你会认为不好,不过uliweb已经提供了许多静态化的方法,如:bind和expose可以静态化,即在settings.ini中进行配置,这样__init__.py中可以是空的。

这里的问题主要是由于方便性考虑产生的:采用自动化的方式,减少用户的导入或初始化的工作,结果使得处理范围扩大化,影响启动效率。

注意我说的主要是启动时的效率,一旦启动不退出,效率要好一些。

因此uliweb如果每次都是重新启动必然会造成性能下降,比较好的方式还是驻留式,不要每次启动。象mod_wsgi, fastcgi应该是可以支持的。是不是自带一个web server采用反向代理会更好呢?象java一样。

类别:Uliweb | 评论(0) | 浏览()
 
2009-10-18 21:32

今天开发了一个新的uliwiki的项目,不错是今天,我是照着 http://code.google.com/p/django-wikiapp/ 这个项目来做的,不过象界面,象处理许多都是重写的.因为原来的项目功能挺多,我目前还实现不了,比如:comment, tagging, notification, feed等.目前只是实现了一个基本的wiki的功能,用户认证还没有.但是wiki的功能基本上都全了:

比如生成WikiWord链接,同时支持象[wiki:name message]的wikiword方式.

使用reStructuredText格式(目前只支持这一种)

编辑,删除,版本管理,恢复旧版本,查看旧版本.

其中版本管理我做得比较简单,我是每次保留全部内容,而不是增量内容,主要是为了方便生成版本差异.而django-wikiapp是保存的增量内容,因此处理上要复杂一些.

同时通过研究django-wikiapp发现了  http://code.google.com/p/google-diff-match-patch/ 这个好东西,可以用来生成比较后的结果,并且还可以生成patch.

下面上几张图,看下效果:

这是进入的首页面.

这是某个页面的编辑页面

这是版本信息,先选中不同的版本,然后点上面的Compare按钮可以显示下面的比较结果.

这是使用了google-diff-match-patch显示的结果,还不错.

现在uliwiki的地址在  http://code.google.com/p/uliwiki/  有兴趣可以试试和完善它.

类别:Uliweb | 评论(12) | 浏览()
 
2009-10-18 10:41

原文: http://j-lite.net/blog/2009/10/17/i-have-a-dream

以下是我的回复:

我也不是为了争uliweb要比django强大,我也说了uliweb有自已的优势,而且我认为比django强的,但django也有它的优势。而且我也在邮件列表中多次声明,每个框架代表一种哲学,不同的哲学引来不同的用户,所以我离开django也可以说是我的哲学与django的哲学区别越来越多造成的。

至于造轮的问题,因此我还是建议你有时间多了解一下uliweb。在今年9.5日的大会上我列举了自已创建的轮子的例子,比如:

整个核心的处理完全是自已写的,它是一个框架的灵魂,负责整个框架的启动,组件管理(app管理),配置管理,request和response处理,middleware的处理,这是每个框架不同于其它框架的核心,是无法复制的。如果只是简单的复制,那么这个框架存在的意义就没有了。其中整个app的详细支持是借鉴了django的思路,但是由我完善的。还有象view的处理,借鉴了web2py的思路,但是自已实现的。详细代码可以见uliweb.core.SimpleFrame.py.

还有许多的模块是我自已写的:

1. web2py的模板,已经被我改造增加了象编译文件目录支持,自定义tag支持,block的支持,这些都是原模板没有了,已经是uliweb化的组件了。
2.dispatch模块,完全是自已写的,实现类似于django signal的功能。但是整个实现是从ulipad发展来的,没有照搬任何人的东西。
3.i18n也是自已写的,是从ulipad发展来的。
4.weto是在我发现beaker这个session库有问题之后重写的,完全是uliweb的东西。
5.contrib下的所有组件都是我自已写的。
6.pyini完全是自已构思创造出来的,用于处理uliweb的配置文件。
7.orm这块是从头一点点构建的,也是一个框架很重要的部分。
8.form库也是自已一点点写的。
9.url映射的处理机制是使用了werkzeug的route为基础实现的,但是只是使用了它的基本功能,主要功能是uliweb实现的。

一个框架主要完成的功能其实不外乎:url处理,request, response,view,orm,组件管理,配置管理,提供一些实用的扩展。因此,你可以看到,从架构设计,从组件的实现,许多方面都有uliweb自已的实现,甚至完全是uliweb自已的实现。因此从web2py,从django,从werkzeug,从sqlalchemy更多不是简单的引用,而是思想的借鉴,是更多的封装。

所以,许多东西并不是简单了解就好象明白的。这是我想要澄清的地方。别人不认可uliweb没关系,很正常。但是我只是希望,评论一个东西首先要对它多少深入地了解一下,哪怕与作者交流一下也好,而是不看些表面。不仅从合理客观的角度来谈论一件事,更是不会误导别人。所以uliweb绝不是简单地组装出来的一个东西,它有自已特性甚至独一无二的东西。许多人一谈uliweb,就是从重装造轮的角度,但是他们并不了解许多uliweb上的设计的东西,也基本上没有在技术细节上的讨论,谈得很泛泛。这样对谁都不是公平的。

你所说的框架其实目前pylons和tg都差不多,而uliweb也是可以,django也是可以,只不过pylons和tg可能从组件上可以直接选择,而uliweb,django是可以自已定制开发,不能直接使用。而且你所说的更接近于某些人更偏重于自已去建,比如这篇文章:

http://pythonpaste.org/webob/do-it-yourself.html

自已建是没有问题。因此框架更多是给那些不希望,甚至不能够自已来做这件事的人准备的。但是自已建,可能需要了解的东西更多,正如我在构建uliweb过程中,我学到了比以前简单使用框架更多的东西,我甚至做了许多以前不知道自已还可以做的事情。各有各的乐趣。

类别:Uliweb | 评论(7) | 浏览()
 
2009-10-17 11:09
根据邮件列表中的回复加工

1. 提出问题:

使用webob在处理通过fancyupload上传的文件,发现会系统挂起,但只要先把request.body读出来就没有问题。因此在uliweb中,将原来使用的webob去除,改成了werkzeug来处理了。

2. qiangninghong的试验:

因为limodou反应的这个问题认为是cgi模块有bug导致的,所以很重要。今天晚上稍稍有点时间,写了一个测试程序来验证一下,但是发现似乎没有这样的情况?

测试代码在这里 http://code.google.com/p/hongqnlib/source/browse/

就是照着 FancyUpload 的 Attach File demo 页面 ( http://digitarald.de/project/fancyupload/3-0/showcase/attach-a-file/ ) 翻译了一下。运行 server.py 后,访问 http://localhost:5002/ ,上传了几个文件,都没有出现挂住的情况啊?

难道是我的这个测试有什么问题?请 limodou 帮忙看看。

3. 我的试验:

我把你的程序改了一下:

  1 
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import os
import mimetypes
import time
import socket
from hashlib import md5
import simplejson as json
import webob, webob.exc
from paste.urlparser import StaticURLParser
from paste.cascade import Cascade
import logging
from paste import fileapp


def app(environ, start_response):
request = webob.Request(environ)
if request.method == 'GET':
filename = request.path_info.lstrip('/')
response = fileapp.FileApp(filename)
else:
# logging.error( repr(request.body))
filedata = request.POST['Filedata']
r = dict(status='1', name=filedata.filename)
text = filedata.file.read()
r['hash'] = md5(text).hexdigest()
if request.params.get('response') == 'xml':
response = webob.Response(content_type='text/xml')
print >>response.body_file, '<response>'
for k, v in r.items():
print >>response.body_file, \
"<%(k)s><![CDATA[%(v)s]]></%(k)s>" % locals()
print >>response.body_file, '</response>'
else:
response = webob.Response(content_type='application/json',
body=json.dumps(r))
return response(environ, start_response)

#static_app = StaticURLParser('/static')
#app = Cascade([static_app, app], (404, 405))

if __name__ == '__main__':
from wsgiref.simple_server import make_server
server = make_server('localhost', 5002, app)
server.serve_forever()
分析如下:

1. 使用你的程序的确没有问题,使用我改的程序就有问题
2. 两个差别在于你在调用处理前使用了一个StaticURLParser,而我改后的程序是不使用它,在app中自已处理。这样的目的并不是使用StaticURLParser不行,而是这样的做法其实是在app处理前多了一层处理,那么这层处理会影响后面的处理,掩盖问题的发生。
3. 在我的例子中,只要把#        logging.error( repr(request.body))这行的注释去了,程序就正常。
4. 原因就是,只要你想办法在执行request.POST['Filedata']之前执行了象request.body之类的代码,这样会引起对body的整个读取,这时读取是按Content-Length来处理的,并且会放在缓冲区中,因此后续的处理就是从这个缓冲区来的了,因此缓冲区最后有没有回车换行是没有关系的。而使用flash控件上传文件,文件体示例如下:

ERROR:root:'------------ei4GI3ei4Ef1Ef1GI3ei4Ij5GI3GI3\r\nContent-Disposition:
form-data; name="Filename"\r\n\r\na.c\r\n------------ei4GI3ei4Ef1Ef1GI3ei4Ij5GI3G
I3\r\nContent-Disposition: form-data; name="Filedata";
filename="a.c"\r\nContent-Type:
application/octet-stream\r\n\r\n#include
<stdio.h>\r\n\r\n------------ei4
GI3ei4Ef1Ef1GI3ei4Ij5GI3GI3\r\nContent-Disposition: form-data;
name="Upload"\r\n\r\nSubmit
Query\r\n------------ei4GI3ei4Ef1Ef1GI3ei4Ij5GI3GI3--'

可以看到,最后是没有\r\n的。这不是浏览器的问题,是flash组件本身的问题,相关的flash的类本身的问题。但其实也不算一个问题,因为cgi的处理是基于multipart的boundary需要以\r\n结束这个假设,但这种假设在某些情况下有问题。相应的cgi的代码如下(从cgi.py中找到的703行):

  1 
2
3
4
5
6
7
8
def read_lines_to_eof(self):
"""Internal: read lines until EOF."""
while 1:
line = self.fp.readline(1<<16)
if not line:
self.done = -1
break
self.__write(line)
就是这个readline造成的,如果没有\r\n它根本不会返回。

因此前面的问题就是,如果不先执行request.body,则后面的request.POST['Filedata']会从流中进行读取,而不是缓冲区中,但flash正好又不返回\r\n,因此server在使用readline就停处了,造成挂起,进而引发浏览器的flash控件的超时。

而你的例子使用了StaticURLParser,可能会进行request.body的读取,所以掩盖了这个问题。当然它到底怎么做的,我没有继续深究。因此我改了你的程序,就是为了不让其它的因素干扰,问题就暴露出来了。
类别:Uliweb | 评论(2) | 浏览()
 
2009-10-15 21:38
最近一段时间一直在忙着ORM的优化,其中有几点:

1.增加__table_args__的配置。它和__tablename__一样是定义在Model类中的,可以用来增加在执行Table时添加新的一些参数,如果你使用mysql,可以如下定义:

  1 
2
class Todo(Model):
__table_args__ = dict( mysql_engine='InnoDB', mysql_charset='utf8')
这样将在建表时,向Table中添加这样的信息。上面的代码将以InnoDB和utf8编码来创建todo表。

2.增加OnInit类方法的调用。这个方法是交给用户来定义的,可以用来执行在执行完Table之后的一些初始化操作,它将在建表之前。比如:

  1 
2
3
@classmethod
def OnInit(cls):
Index('my_indx', cls.c.title, cls.c.owner, unique=True)
这样将创建以title, owner的索引,并且索引不允许重复。目前只支持索引的创建。对于简单的索引,是可以在定义Field时直接设置index=True来创建的,并不需要这种方式。这种方式可以认为就是为了创建多个字段的联合索引。

3.考虑缺省order_by的实现。但是想用户完全可以在Model中定义相应的方法来实现,类似于django的Manager的东西,比如:

  1 
2
3
4
class Todo(Model):
@classmethod
def files(cls):
return cls.all().order_by(cls.c.title.desc())
然后在使用时可以通过Todo.files()来返回按title降序排列的结果。所以使用这种方法倒是不一定要支持缺省order_by的配置项。不过有这个配置项的好处就是当需要实现通用的查询时,它可以自动生效。不过也可以考虑把结果集当成一个参数传给配置功能,总之还是有方法。

4.最重要的一个特性。增加表的注册,并且注册的表不一定是一个Model,而是一个模块名的形式,如以下两种都是正确的注册方式:

  1 
2
set_model(Model, tablename='user')
set_model('uliweb.contrib.auth.models.User', tablename='user')
这样注册之后,你就可以通过使用真正的表名来得到对应的Model类对象了。通过:

  1 
User = get_model('user')
这种方式首先可以使用在关系的定义中,如:

  1 
2
Reference('user')
ManyToMany('user')
对于关系定义,它可以根据表名自动导入对应的Model。而对于在程序中想直接使用某个Model,则可以通过get_model()来获取。

但是这种get_model()的方式要依赖于set_model()的注册过程。注册有几种方式:

1. 在导入Model文件时,随着Model的class的创建自动会调用set_model()来注册,因此只要正常导入相应的模块,就可以使用get_model()方法了。这种情况下,对通常的开发没有什么影响,用户甚至不必使用这种方式。

2. 由框架来注入。也就是uliweb来实现。这种方式首先要求将Model信息写入到settings.ini中,比如:

  1 
2
[MODELS]
user = 'uliweb.contrib.auth.models.User'
这样当uliweb在启动时可以自动采集注册信息。然后在orm这个app的__init__.py中执行真正的注册工作,通过调用set_model()方法。这时,注册的就不是Model了,而是字符串形式的信息。

然后在某个地方,如views.py中使用get_model()或导入models.py时,就可以自动生效了。

你可能会问,这有什么用呢?一般不都是直接导入来使用吗?完全够用了。

的确,一般的程序的确是根本用不上。但是Uliweb是一个框架,它要考虑代码的复用和替换的问题。考虑一下,在你的models.py可能需要对User表进行处理,那么你会去导入它。但是有可能这个User表不适合你的应用了,你怎么办?并且这个User表不是你自已写的,而是框架或别人提供的,别人可能还要依赖于这个表。因此简单的直接修改并不一定是好办法,因为它可能不受你的控制。重新写一个可能是好办法,但是因为直接导入的原因,比如你是通过:
from uliweb.contrib.auth.models import User
这可是直接hard code了,所以重新写必然还要修改导入的代码。那么要解决这个问题,可以采用的一种办法就是将外部依赖的内容配置化,和java中的注入依赖有些象。也就是我在定义自已的东西时,可能需要外部的东西,那么我并不直接导入,而是通过一种获取的方式来得到。这样工并不需要知道外部的组件的实际位置,这件事由框架来完成。因此uliweb现在实现的get_model就是为了实现这一配置化而设计的。

其实现在,象bind,expose都已经是可以配置化的了,都可以放在settings.ini中。如果完全配置化,将可以减少启动时的导入处理,并且替换会很容易。
类别:Uliweb | 评论(0) | 浏览()
 
2009-10-15 20:18

pyini.py是处理Uliweb的settings.ini的模块,今天向它添加了三个新的方法:set_var, get_var, del_var,它们的特点集中在第一个参数,它可以是'/'分开的字符串,如:'DEFAULT/flag',它相当于:

s = ini.add('DEFAULT') 
s['flag'] = True 

注意,它只支持一层的'/'切分,如:'DEFAULT/flag/name'相当于 'DEFAULT'和'flag/name'。

类别:Uliweb | 评论(0) | 浏览()
 
2009-10-15 07:45

原文:  http://j-lite.net/blog/2009/09/28/lets-talk-about-uliweb

回复如下:

首先感谢对Uliweb的批评。 以下要澄清:

1. 其实所有的框架都是大杂烩,django也不利外。而且别人做好的东西,如果没有什么问题,拿过来用当然就可以了。特别象是框架,它更多的是提供管理模式和一些工具,本身就是个大杂烩。

2. 大一统是不可能的,正如世界上有那么多可以统一的东西为什么没有统一,如:语言,操作系统,数据库?因为多样性才是这个世界的特点。更因为人们总有不同的思念和需求。

3. 为什么不向django和web2py做贡献?贡献我的确做过,如果你去查django和web2py相关的内容,应该还有我的名字。但是有些东西是不可调合的,比如对设计的一些看法,对一些组件的使用,这些东西我建议过,他们并不接受。所以只有以自已的方式来构造。

重新构造也是一个很痛苦的过程,但是可以让造出来的东西完全按自已的意愿发展,也是一种不错的选择。更有一些人不建议使用框架,而是使用组件,为什么,就是不想被框架所束缚。

而你所说的插件系统,就是uliweb实现的一个目标。uliweb的app的功能要比django还要彻底。如果有兴趣欢迎与我交流。

类别:Uliweb | 评论(4) | 浏览()
 
2009-10-13 22:21

原文如下:

Congratulations,

Uliweb, one of your products, has been added to Softpedia's database of
software programs for Linux. It is featured with a description text,
screenshots, download links and technical details on this page:
http://linux.softpedia.com/get/Internet/HTTP-WWW-/Uliweb-51417.shtml

The description text was created by our editors, using sources such as
text from your product's homepage, information from its help system, the
PAD file (if available) and the editor's own opinions on the program
itself.



If you feel that having your product listed on Softpedia is not a benefit
for you or simply need something changed or updated, please contact us via
email at webmaster@softpedia.com and we will work with you to fix any
problem you may have found with the product's listing.

--
Sincerely,
The Softpedia Team

不知道算不算好事。不过Uliweb还有许多需要完善的地方,我才把0.0.1a2发布上去,过会就收到了。

类别:Uliweb | 评论(4) | 浏览()
 
     
 
 
文章分类
 
 
 
Uliweb(95)
 
Python(13)
 
Ulipad(11)
 
Web(3)
 
 
 
     
 
文章存档
 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
最新文章评论
   
 
 

期待ulicms~
 

噢,正好看到前几天有人问相同的问题,你已经回答过了。谢谢!
 
 
     


©2009 Baidu