麦田守望者's profile异想空间PhotosBlogListsMore Tools Help

Blog


    10/26/2009

    与rc有关的几个重要文件

    OpenBSD uses an rc(8) style startup. This uses a few key files for startup.

    • /etc/rc - 主脚本。不应该编辑它。
    • /etc/rc.conf - /etc/rc使用的配置文件,用于为系统设置启动参数。
    • /etc/rc.conf.local - 配置文件。此文件中的设置会覆盖掉/etc/rc.conf中的相同的设置值,因此不该直接编辑它。当升级你的系统的时候,这很重要。
    • /etc/netstart - 用于初始化网络的脚本。不应该编辑它。
    • /etc/rc.local - 用于本地管理的脚本。特定于守护进程或者主机的信息放在这个文件中。
    • /etc/rc.securelevel - 脚本文件,它执行那些必须在安全级别变动之前执行的命令。参看 init(8)
    • /etc/rc.shutdown - 在关机的时候执行的脚本文件。关机前你想要做的任何事情都可以放在这个文件里。参看 rc.shutdown(8)

    以上摘自OpenBSD FAQ。在理解了它们各自的用途之后,需要注意使用它们的注意事项。

    10/22/2009

    在命令行中调节音量

    在命令行调节音量使用mixerctl,方法如下:

    $ mixerctl outputs.master=200,200

    其中,两个数值200,分别代表的是左右声道的音量,中间用一个逗号分隔。其取值范围是0到255。不加任何参数执行mixerctl,能够看到系统当前的音频配置参数。

    8.25 - Why is my clock off by several hours?

    By default, OpenBSD assumes your hardware clock set to UTC (Universal Coordinated Time) rather than local time, assumed by some other operating systems, which can cause problems when multi-booting.

    Many other operating systems, can be configured to do the same, which avoids this problem altogether.

    If having the hardware clock set to UTC is a problem, you can change the default behavior of OpenBSD using config(8). For example, to configure OpenBSD to use a hardware clock set to US/Eastern (5 hours behind UTC, so 300 minutes):

    # config -ef /bsd
    OpenBSD 4.6 (GENERIC.MP) #89: Thu Jul 9 21:32:39 MDT 2009
    deraadt@i386.openbsd.org:/usr/src/sys/arch/i386/compile/GENERIC.MP
    Enter 'help' for information
    ukc> timezone 300
    timezone = 300, dst = 0
    ukc> quit
    Saving modified kernel.

    See options(4) and search for option "TIMEZONE=value" for more information.

    以上是从OpenBSD FAQ中摘录的。config命令用于更改时区。对于北京时间,使用如下命令行修改时区:

    ukc> timezone -480

    timezone的参数是以分钟为单位。因此,八小时为480分钟。quit之后,重启心爱的OpenBSD,date一下。看,时间变过来了。

    10/21/2009

    OpenBSD的rc脚本是如何工作的(摘录)

    The main files a system administrator should concentrate on are /etc/rc.conf (for guidance), /etc/rc.conf.local (for changes), /etc/rc.local and /etc/rc.shutdown. To get a look of how the rc(8) procedure works, here is the flow:

    After the kernel is booted, /etc/rc is started:

    • Filesystems are checked.
    • Default configuration variables are read in from /etc/rc.conf, then local changes to those variables are read from /etc/rc.conf.local. Settings in rc.conf.local will override those in rc.conf.
    • Filesystems are mounted
    • Clears out /tmp and preserves any editor files
    • Configures the network via /etc/netstart
      • Configures your interfaces up.
      • Sets your hostname, domainname, etc.
    • Starts system daemons
    • Performs various other checks (quotas, savecore, etc)
    • Local daemons are run, via /etc/rc.local
    9/10/2009

    对getcwd函数的一例应用的不解

    OpenBSD源代码树的pwd.c中,有这样一个代码片段:

    int main(int argc, char *argv[])
    {
    /* 省略其他代码 */

    char *p;

    if ((p = getcwd(NULL, (size_t)0)) == NULL)
    err(1, "getcwd");
    (void)printf("%s\n", p);
    exit(0);
    }

    该段代码的目的是获得当前工作目录,并打印出来。请注意getcwd的调用方式。根据OpenBSD Maunalgetcwd函数的描述:如果给第一个参数传递NULL的话,getcwd会在某个地方分配内存空间,存放当前目录的字符串,并返回指向这个字符串的指针。调用方应该在稍后调用free,释放字符串占用的内存空间。然而,在上述从OpenBSD源代码中摘抄的代码片段,并没有调用free。
    不清楚代码的作者为何这样写。疏忽遗漏了,还是getcwd函数的行为有其特殊性?如果看到这的读者你了解内幕,请赐教,不胜感激!

    8/29/2009

    听歌也很简单

    听MP3你用什么软件?我用VLC。不过,我还用更高效、易用的mpg321。mpg321是一个命令行程序,没有任何用户界面。这就使得mpg321非常的高效,占用非常之少的系统资源。安装mpg321同样很容易。如果使用Debian或者Ubuntu,那么sudo apt-get install mpg321;如果使用BSD Unix,那么可以使用他们各自的软件包管理系统安装;或者干脆从源代码编译。看你的喜好了。

    播放MP3:

    mpg321 file1.mp3

    播放多个MP3:

    mpg321 file1.mp3 file2.mp3 singer/famous-song.mp3

    打乱顺序播放:

    mpg321 -z file1.mp3 file2.mp3 singer/famous-song.mp3

    man mpg321会显示完整的使用参考。

    mpg321可以被用在shell脚本中。发挥一下想象力,是否能够把它用到什么特别有意思的地方呢。

    BTW:mpg321不是Windows环境中的产物。想在Windows下使用的话,你可以搜一搜试试看。

    8/27/2009

    IATTopic.queryCatalog

    IATTopic接口声明了queryCatalog方法:

    def queryCatalog(REQUEST=None, **kw):
    """Invoke the catalog using our criteria to augment any passed
    in query before calling the catalog.
    """

    利用这个方法,我们能够以编程的方式控制提供了IATTopic接口的对象的搜索行为。最典型的是Plone的标准内容类型Collection,在更早期的Plone版本中其称作Smart Folder。Collection这个名字可以看作是面向用户的名字,非常清晰直观的反映了它的功能。在Plone内部,Collection类型实际上是一个ATTopic类,其portal_type是Topic,archetype_name是Collection。言归正传,看一看能用这个接口方法做什么。

    在ATTopic类实现中,丰富了queryCatalog方法的参数:

    def queryCatalog(self, REQUEST=None, batch=False, b_size=None,
    full_objects=False, **kw):
    pass

    利用这些参数,能完成如下任务:

    1、在已经设置了搜索条件的基础上,附加其它额外的条件。将任何额外的搜索条件,按照ZCatalog的规范组合成一个字典对象,传递给kw参数。关于ZCatalog的参考,《The Zope2 Book》的Searching and Catagorizing Content章节有详细的介绍。

    2、按批次返回特定数量的对象集合,即分页。batch参数指明是否按批次返回搜索结果,b_size说明返回的结果集的大小。除了这两个参数,还需要在context.REQUEST对象中设定b_start。b_start指明,在完整的搜索结果结合中,从第几个对象开始返回b_size数量的对象集合。和数组的下标一样,b_start的值从0计起。

    在这种情况下,queryCatalog方法返回的是一个 ZTUtils.Batch.Batch对象。Batch对象实现了__getitem__和__len__方法。同时,还提供了previous和 next属性,用于前后双向跌代下一个Batch对象。如果到头了,则previous和next会相应的被置为None。

    3、返回的对象集合中,包含每一个完整的对象。full_objects参数指明,调用每一个Brain对象的getObject方法,从ZODB中获取完整的对象。此种做法可能会影响Plone的运行性能。

    举个例子:

    在当前上下文中存在一个Collection对象,其ID为search。想要搜索EffectiveDate在2009年1月1日以来的Page对象,并且按照EffectiveDate排序,显示头10个对象。

    from DateTime import DateTime
    qc = {}
    qc['portal_type'] = 'Document'
    qc['effective'] = { 'query': DateTime('2009/1/1'), 'range': 'min' }
    qc['sort_on'] = 'effective'
    qc['sort_limit'] = 10
    qc['sort_order'] = 'descending'
    context.search.queryCatalog(**qc)[0:10]

    如果想要分页显示所有Page对象,每一页显示20个,显示第2页:

    qc = {}
    qc['portal_type'] = 'Document'
    qc['sort_on'] = 'effective'
    qc['sort_order'] = 'descending'
    # 这一行很重要。如果缺少这一行,则会始终从搜索到的第一个对象开始返回结果
    context.REQUEST.set('b_start', (2 - 1) * 20)
    context.search.queryCatalog(batch=True, b_size=20, **qc)
    7/31/2009

    解决psycopg2导入错误

    psycopg2版本:2.0.11

    Zope版本:2.10.7-final

    在上述环境中创建一个ZPsycopgDA数据连接对象的时候,会出现ImportError异常,提示psycopg version mismatch (imported 2.0.11 (dt dec ext pq3))。

    解决办法:在ZPsycopgDA目录中,修改DA.py文件的119行:

    - if psycopg2.__version__[:5] not in ALLOWED_PSYCOPG_VERSIONS:
    + if psycopg2.__version__.split(' ')[0] not in ALLOWED_PSYCOPG_VERSIONS:

    导致这个错误的原因是,2.0.11版本的psycopg2的__version__属性会返回“2.0.11 (dt dec ext pq3)”,只有按照空格打断字符串并取得第一元素,才能正确获得版本号。


    7/30/2009

    解锁Plone对象

    如果某个对象被上了锁,导致没法对其进行操作,可以用wl_clearLocks方法为其解锁:

    obj = getattr(context, 'obj_id')
    obj.wl_clearLocks()

    至于对象为何以及在什么条件下会被上锁,我尚不清楚。如果您清楚,感谢指点一二。

    7/29/2009

    content_status_modify方法在哪里定义的?

    寻寻觅觅,在源码中始终不见content_status_modify方法的踪迹。你知道吗?请告诉我。谢谢!

    BaseFolder对象的manage_addFolder方法

    BaseFolder位于Products.Archetypes.BaseFolder.py

    在Python脚本对象中,可以使用manage_addFolder方法创建一个Folder对象。从ATFolder继承下来的容器对象,都包含了这个方法。当在自定义的容器对象上调用manage_addFolder方法的时候,要明确地给type_name参数传递一个字符串值Folder。例如:

    context.manage_addFolder(id = 'objid', title = 'Object's title', type_name = 'Folder')

    然而,不要被这个方法的字面意思所蒙蔽。只要给type_name参数传递了正确的portal_type值,还可以用它创建其他类型的内容对象。例如:

    context.manage_addFolder(id = 'objid', title = 'title', type_name = 'Document')
    context.manage_addFolder(id = 'objid', title = 'title', type_name = 'Image')

    这里“正确的”含义有二。一是,type_name的值必须是已经注册的对象的portal_type值;二是,指定的portal_type必须是当前容器被允许容纳的对象类型中的一种。

    实际上,manage_addFolder在做了一系列准备工作后调用invokeFactory方法,而invokeFactory最终调用portal_types对象的constructContent方法创建对象。如果很清楚自己要做些什么,也可以直接调用invokeFactory和constructContent方法。

    7/22/2009

    IObjectManager接口中的几个有用的方法

    IObjectManager位于OFS.interfaces.py文件中。IObjectManager接口定义了一个容器类需要实现的方法。其中有几个方法很有用。

    def hasObject(id):
        """ Indicate whether the folder has an item by ID. """

    def manage_delObjects(ids=[], REQUEST=None):
        """Delete a subordinate object

           The objects specified in 'ids' get deleted.
        """

    def __getitem__(key):
        """
        """

    • hasObject方法接受一个参数,该参数表示某个对象的id,hasObject方法会判断该对象是否存在于容器中。
    • manage_delObjects方法用于在容器中删除一组对象。删除的依据是ids参数,这是一个列表对象,其中包括将要被删除的对象的id。
    • __getitem__方法使得提供了IObjectManager接口的对象可以像字典对象那样获得容器中的某个对象。

    IObjectManager接口还提供了诸如superValues、objectItems、objectValues等其他方法用于访问容器中的对象。

    Plone的ATFolder对象通过继承和实现IATFolder接口,也提供了IObjectManager接口的功能。因此,在Plone中,以编程的方式对一个ATFolder对象施加更多的控制就变得容易许多。通过对CMFCore和CMFPlone的探索得知,还有许多其他更高层的接口可以利用。

    7/12/2009

    在portal_catalog中按照分类搜索使用Subject关键字

    当以编程方式通过portal_catalog工具搜索具有特定分类属性的内容对象的时候,使用Subject关键字。请注意首字母大写。在ZMI中,portal_catalog的Indexes页中存在一个类型为KeywordIndex,名称为Subject的索引。这就是我们所需要的。

    7/11/2009

    (dynamic view)和(selected layout)

    Plone提供了一种机制,允许开发者给实现了IATFolder接口的内容类型提供不同的显示视图(Views),而用户则可以通过Display菜单设置内容类型的动态视图。作为内容类型的开发者,特别需要留意“(dynamic view)”和“(selected layout)”的使用。即在某个内容类型的GenericSetup配置文件中,必须确保下面的两行正确出现:

    <alias from="(Default)" to="(dynamic view)" />
    <alias from="view" to="(selected layout)" />

    如果,选择Display菜单中的视图没有任何作用的话,那么可以看看这两个配置值是否正确出现。


    5/9/2009

    在基于Debian的Linux中安装OpenOffice.org 3.1.0

    我在自己的Debian 5.0 (lenny)中成功安装了OpenOffice.org 3.1.0,步骤简单,在这里与大家分享。

    1. 下载OpenOffice.org 3.1.0。下载地址:http://download.openoffice.org/other.html#en-US
    2. 删除系统中已经存在的OpenOffice。使用命令:sudo apt-get remove openoffice*。留意:不要落下openoffice后面的星号。
    3. 解压缩下载后的文件OOo_3.1.0_LinuxIntel_install_en-US_deb.tar.gz,并进入解压后的目录OOO310_m11_native_packed-4_en-US.9399/DEBS
    4. 安装目录中的所有deb包,使用命令:sudo dpkg -i *.deb
    5. 进入OOO310_m11_native_packed-4_en-US.9399/DEBS/desktop-integration,同样使用dpkg命令安装该目录中唯一的deb包。使用命令:sudo dpkg -i openoffice.org3.1-debian-menus_3.1-9393_all.deb

    如果一切顺利,到这已经可以使用新版本的OpenOffice了。

    在安装新版本OpenOffice之前,我一直使用2.4.2版本,并且Java环境运行良好。由于每台计算机几乎不可能有完全一致的系统环境,因此我不确保上述步骤在您的系统中100%运行无误。仅供参考。

    另外,可以参考一篇图文并茂地讲解OpenOffice的文章(英文)。

    5/5/2009

    理解Browser View之多适配器

    视图组件是命名的多适配器。其作用于的对象是HTTP Request对象和提供某个特定接口的对象实例。在视图组件的configure.zcml文件中声明page的时候,page元素就描述了这一概念。例如:

    <browser:page
      for="..interface.IReport"
      class="report_view.py"
      name="view"
      template="report_view.pt"
      permission="zope2.View"
    />

    属性name指出,我们声明了一个名字叫做view的视图。for指出只有当请求一个提供了IReport接口的对象的时候,才会调用这个视图。当然,发出请求的用户必须具有permission属性指定的权限才行。

    用编程方式获得这个视图对象,能够更直观地体会到多适配器的概念:

    from zope.component import getMultiAdapter
    from zope.publisher.browser import TestRequest
    # 假设该Report类实现了IReport接口
    from myproject import Report

    report = Report()
    request = TestRequest()
    view = getMultiAdapter((report, request), name=u"view")
    view()



    cctv.com与IE结下因缘

    如果想在cctv.com上看直播,那么必须安装Windows和IE。cctv.com剥夺了所有不用IE和Windows的人看视频的权力。

    4/24/2009

    自定义内容类型的Title

    基于Archetype框架开发内容类型,由于它们继承自BaseContent或者ATContentType,因此自然也就提供了IMinimalDublinCore接口。该接口中定义了Title方法,用于获取内容类型对象的title值。这样,自定义内容类型的Title就非常轻松了。示例代码如下:

    from Products.ATContentTypes.content.base import ATCTContent
    from Products.CMFCore import permissions
    from AccessControl import ClassSecurityInfo

    class MyContent(ATCTContent):
    """ Demo content type for demonstrating
    how to custom this content type's Title
    """

    security = ClassSecurityInfo()

    security.declareProtected(permissions.View, "Title")
    def Title(self):
    """ return the custom title """
    return "My custom title"

    该示例代码省略了部分与主题无关的内容。有一点需要留意,即一定要给Title方法声明保护级别。

    2/23/2009

    吼一嗓子,Zope文档有更新了

    其实也没什么可多说的。《The Zope Book》和《The Zope Developers Guide》终于有重大更新了。请留意Zope.org中的Documentation部分。