2007年05月31日

今天有幸参加了Google Developer Day活动,说实话就是想去看一看Guido,如果有机会呢就拍张照片什么的,同时可以和CPUG的朋友见个面。路上坐的公车,出来不算晚但到时人真是挺多啊。全天活动分为两个地方,开始是在三层,然后Keynote讲完就要到二层去,分为两个会场。我坐在中间的位置,正好前面坐着张成,很巧。

先是由李开复做发言词,其中他提问到有多少人学了Python,看到有不少人举手。后来看到CSDN的采访稿说了大部分人就是奔着Guido去的,看来不假。接着是一位印度籍(可能是,看长相,也没记住名字)的进行主题发言,基本上就是对Google的介绍和一些核心技术的介绍,如GFS和BigTable。不过他发单不清楚,反正我是没听懂几句。

主题发言之后,大家分为两组进入两个分会场。我则是进入Linux & Open Source分会场,人挺多,就走到前面正好看到Zoom.Quiet坐在了第一排,于是就坐在一起。后来看到IceBird大家就一起了。

先是由Jon Trowbridge进行Google & Open Source的介绍。他介绍了Google的硬件环境,开源软件的使用性况,以及Google是如何回馈开源社区的,如Summer Of Code活动。他的发音是纯正的美语,很好听,大部分还可以听懂。主持人是Google的技术总监周杰(音),他说到提问的前5名可以有奖品,结果问题不断,搞得Jon很激动,但也严重影响了演讲的进度,以至于有人提出建议先让问题等一等。其中很有趣的一个问题就是:Why you are so excited? 听得大家纷纷大笑。老外的演讲的确很生动,很精彩。

中午饭是挺让人失望的。应该算是汉堡吧,中间夹着一个狮子头,不好吃,还有根香蕉,没有餐巾纸。凑和吧,只吃了一半,没吃完。其间碰上郭勇,DreamingK,QiangningHong等人。

下午开始前与郭勇在门口聊天,后来又碰上魏忠等,正聊着,看见Guido走了进来,于是大家眼前一亮,说要和他拍个照。于是我上前问是否可以和Guido拍照。Guido很热情,于是我们许多人都和Guido来了一个两人合影。运气好啊。后来围过来的人是越来越多,想合影都难啊。我们发现得早,算是运气。Zoom.Quiet还拿着CPUG的标志让在场的CPUG成员一起与Guido合影,不过不知道是谁拍的,照片不知道是否拿得到手啊。

接下来的就是一个论坛关于Linux & Open Source在中国的发展。Guido的发言相对较少,其中有人问到哪种开源版权的问题,他说喜欢BSD:Simple is better. 很符合Pythonic的思想。

之后由Mike Schroepfer进行了Firefox的介绍,特别是关于Firefox的开发,代码审查,Firefox 3的特性作了介绍。

下面的重点就是Guido了。在开始前大家有热烈的鼓掌,看来创始人在人们心目中的地位的确不同啊。他好象嗓子不好总咳嗽。他主要还是介绍Python的情况,象为什么创建Python,Python的几个版本,Python 3K的一些特点。其中他多次谈到Django,希望这可以激发大家学习Django的兴趣。

最后由苏哲讲述了i18n和l10n的开发,长了不少见识。结束后碰上麦田守望者和Nick Chen。

最后的鸡尾酒会没参加,直接回家了。

记了个流水帐。

这就是我有幸和Guido的合影, :P

Many people know that Guido like django, that’s right! Today Google
Developer Day is held in Beijing, and Guido also made a Python
introduction. In his talk he said at least 4 times that he likes
Django. And I’m very excited about this. And I think maybe it’s a
great opportunity for Django development in China, and I hope more and
more people would like to learn Django from now.

2007年05月28日

今天看到 Russell 发的一个提议是关于实现用的newforms的widgets时如何处理Media的问题。这一点就目前django来说的确不是很方便。在以前我也写过关于在app中实现对于静态文件的支持,也是由于这一点。由于不象PHP那样以实际的目录来运行,django其实是在一种映射出来的url方式下来工作的,而且考虑到效率的问题,静态文件一般是不处理的。

在这个讨论中,Russell主要提议是对newform中要用到的css和js等静态文件进行处理。在我看来这只是静态文件中处理的一部分而已,最好是从完整的html页面来考虑,如何处理静态文件,如何在各个组件中方便地与页面进行集成。如果有一种通用的页面模式,并且各个组件可以方便将静态文件导入并在合适的位置进行生成才足够方便,但这样一来现有的模板就太简单,一种是重新设置新的模板处理,另一种是可以考虑通过js来动态插入静态链接,如css和js等。在django中的处理还主要是以静态html方式为主,但是我认为这只是最简单的一种,而且也不是很强大,对于复杂的处理则能力不足。应该多结合ajax技术进行。当然从web的整合处理来说,也许分成前端设计和后端设计更好。django目前已经包含了许多的前端设计,但是没有使用ajax毕竟不是很cool。

讨论中另一个问题就是有人提出不要引入过多的css之类的文件,而是需要进行自动合并,这是一个更加复杂的问题。

[讨论链接]

2007年05月12日

在最新的 UliPad 我新增了一个STC(StyledTextCtrl)事件的处理 EVT_STC_AUTOCOMP_SELECTION,这个事件会在自动完成弹出列表中选择后,将要插入字符串到编辑器中时发出的。不过这个事件是当你调用了AutoCompShow来显示弹出列表才会激活的,如果你使用的是UserListShow这个方法,那么STC会在选中某项后发出EVT_STC_USERLISTSELECTION事件。不过对于EVT_STC_AUTOCOMP_SELECTION事件,好象它只是一个通知,你没有办法取消它的处理。在不知道这个新的事件之前,UliPad的InputAssistant对于列表的处理不完整。原本是有一个功能是当用户从列表中选择一项后,将根据这个值去查找acp文件中的autovalues段,这项值将作为key值来查找,如果有匹配的项,那么将根据它的值进行处理。这样可以做一些更复杂的操作。但由于没有这个事件,我无法得知何时需要进行这样的处理。而在InputAssistant处理中,的确有几处没有使用UserListShow而是使用AutoCompShow,因此只要是使用AutoCompShow的地方都存在这个问题。虽然我想试图将所有的AutoCompShow改为UserListShow,但是由于两者的调用不同,无法实现我的要求。象AutoCompShow可以指定已经匹配的字符长度,而UserListShow则不行。

而有了这个事件,我就可以在这个事件中通过CallAfter来异步处理选中事件。不过在开始造成了 UliPad 的一些Bug,后来检查是由于wxPython版本的问题。我开发使用的是2.8.3.0,而低于这个版本的没有这个方法。所以后来又加了判断,版本大于等于2.8.3.0的可以对这个事件进行处理。这样的话,弹出列表如果希望有完整的功能,需要在2.8.3.0下运行才可以。

2007年05月11日

Thanks Kibleur C. (http://kib2.webfactional.com/) for his wxSnip package, and I’v ported it into UliPad, you can get the lastest code from svn (http://cvs.woodpecker.org.cn/svn/woodpecker/ulipad/trunk). But wxSnip is not very suit for UliPad, because UliPad has its own InputAssistant functionality, so I changed wxSnip code and made it more suitable for UliPad. The source file in UliPad is named mixins/SnipMixin.py. And I made a SnipMixin class, it receives a `editor` argument, and not like in wxSnipEdit.py it’s  SnipEditor. So I can merge this class into my own StyledTextCtrl object. And I also don’t need the adding template string process, because InputAssistant functionality can do this, but I indeed fixed the indent bug when adding template string according wxSnipEdit. And I trigger the process of snippet field outside the SnipMixin class, so I bind the key_down event in my own editor class but not in SnipEditor class. So there are two method which I need to call:

start(self, tpl, start, end)

this function will be invoked after adding template string, and it comes from insertSnippet() method of SnipEditor, and it’ll auto invoke the nextField() method.

nextField(self, pos)

this function will be invoked after you pressing the trigger keystroke Ctrl+] now.

And the snippet template is defined in a ACP(Auto Completion Pattern) file, you can find in conf folder of UliPad. Each syntax has such a file, such as Python.acp. For now, I made some example in python.acp, you can see:

[autore]
(^\s*)def<space> = \\1def ${1:method_name}(${2:}):\n\t”’${3:}”’\n\t${0}
(^\s*)cdef<space> = \\1def ${1:method_name}(self, ${2:}):\n\t”’${3:}”’\n\t${0}

The acp file is a ini-like file. If the value is quoted by double-quoter("), then it’s just like a python string. If there is not, it just like a raw string. Notice, if there is a ‘,’ in the string, you should quote it by double-quoter, just like:

"ab,cd"

If you don’t quote it, it’ll be treate as a list. So you’ll see a popup list when the pattern is matched. And for keys, there are some special character representations just like: <space> (‘ ‘), <equal> (‘=’), <div> (‘/’), <square> (‘[‘), etc

2007年05月08日

在很早 UliPad 已经支持微软的TTS库了,因为我使用了 pyTTS 模块。不过正如网上许多人说的,微软的TTS发音真是太差了,以至于我开发了在UliPad中阅读的功能我也没有兴趣去使用它。不过最近看到一个关于 NeoSpeech 的介绍,如果你上网会搜出许多来,大多数都是讲如何与Babylon词典结合一起使用的说明。我平时使用灵格斯词霸(因为它免费),原以为用不了。但后来发现NeoSpeech是符合TTS标准的,因此灵格斯也是可以使用的。只要在语音选项中设置一下就行了。至于语音库哪里下载,上网搜吧,很多。因此我想UliPad也应该可以使用这么出色的语音引擎才是啊。于是试了一下,没有问题。只不过原来UliPad不能设置角色,现在我加上了。于是在UliPad中你就可以选中或不选文本进行阅读了。

另外,在 http://www.nextup.com/TextAloud/ 上下载TextAloud软件,有可以用于浏览器的插件进行阅读,这样非常方便。

在UliPad中使用语音引擎的方法见以前我写的说明[语音朗读插件],同时我增加了一个设置的菜单。要注意如果你以前用过UliPad请先将plugins目录下的pytts目录删除。我将pytts改名为了tts_plugin,为了避免目录冲突。然后在插件管理中选中tts_plugin,然后重启就行了。

2007年05月02日

静态文件在 django 中并不是非常简单的事情。由于URL与文件目录并不是相同的东西,因此在处理 Django 中的静态文件时要同时考虑两个东西,一个就是静态文件的URL表示,另一个就是如果将静态文件的URL与实际的文件路径相对应起来。而在 Django 中标准的处理静态文件的方式是通过webserver,通过ReWrite规则,将一个URL的表示映射为实际的目录。因此这种做法要求我们将静态文件集中管理,比如都放在某个media目录下,分为css, js, images等子目录,并且将整个项目所用到的所有静态文件都分别放在这个目录下。这样做的好处主要是为了方便映射。但同时造成一个问题:一个APP它应该是相对自包含的,如有自已的Model,有自已的templates目录,有自已的templatetags目录。但唯独到了静态文件这块,由于这种集中管理的要求无法分散到各自的目录下,使得管理起来变得麻烦和复杂。

那么为什么会这样?我思考了一段时间。有一个叫ToscaWidgets的项目,它说是可以将静态文件,如css,js与python代码一起打包来使用,虽然我一直没有研究过它的代码,但是我猜想与web server的处理方式有关。比如它已经在TurboGears和Pylons中使用了,它们都支持真正的wsgi的方式,因此可以在底层解析时根据url的不同进行静态文件的处理。而Django的哲学或者说是设计方式不同,它不使用真正的wsgi作为底层的机制,它使用自已的Middleware来处理。当然,如果我们在Middleware来处理一样是可以的,但之所以Django不这样做是因为它认为:web server的机制应该会更出色,而django在这方面并不擅长,因此它并不建议由django来做。我想当网站处于生产状态这样是最合理的,但是当你在开发时,这样并不方便,特别是对于重用性并不友好。因此在django中实现象其它的框架一样的分布式的静态资源的管理我认为很有必要。这样开发时可以使用分布式,但在生产部署时采用集中式。

那么怎么做呢?首先我的想法是将静态文件分布到以APP为单位的单元中。可以有两种处理方式:一种方式是开发时继续使用django已经提供了的一个供开发使用的静态文件服务的view模块,不过它不支持在APP中查找静态文件,因此我做了改造,当按原来的方式找不到静态文件时,就去遍历每个APP下的固定目录。这样的话,这种方式是在urls.py中配置即可。同时APP下的固定目录可以在设置urls.py时指定。另一种方式则是做成一个Middleware。前一种我已经实现,后一种没有实现,大同小异。

以openbookplatform中的具体实现为例,在urls.py中的配置为:

(r’^site_media/(.*)$’, ‘utils.staticview.serve’, {’document_root’: settings.SITE_MEDIA, ‘app_media_folder’:'media’}),

staticview.server是我改造后的方法。它除了需要一个与以前的方法一样的document_root参数外,还可以传入一个app_media_folder的方法,这里为media,这样当以前的方式找不到静态文件时,会去每个已经安装的APP下的media目录下去查找相匹配的文件。

然后在你需要放置静态文件的APP下,按照上面app_media_folder的设置创建相应的目录,如果需要子目录也一起创建。这样你也可以创建一个只有静态文件存在的APP。

当在生产运行时,只要再有一个简单的工具将所有APP下的静态目录拷贝到指定的目录下即可。这个工具我还没有开发,但是应该是很简单的。这样生产部署时只要运行这个工具即可。再修改下urls.py的配置将静态文件的处理pattern注释掉就行了。