用户名:
密   码:




      



    访问统计

     RSS 1.0


     


    2006-08-03
    Tag:Linux debian ubuntu



     发表于 11:15:50  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2006-04-29
    Tag:Linux Top

    top

    1.作用
    top命令用来显示执行中的程序进程,使用权限是所有用户。

    2.格式
    top [-] [d delay] [q] [c] [S] [s] [i] [n]

    3.主要参数
    d:指定更新的间隔,以秒计算。
    q:没有任何延迟的更新。如果使用者有超级用户,则top命令将会以最高的优先序执行。
    c:显示进程完整的路径与名称。
    S:累积模式,会将己完成或消失的子行程的CPU时间累积起来。
    s:安全模式。
    i:不显示任何闲置(Idle)或无用(Zombie)的行程。
    n:显示更新的次数,完成后将会退出top。

    4.说明
    top命令是Linux系统管理的一个主要命令,通过它可以获得许多信息。这里我们结合图1来说明它给出的信息。

    图1 top命令的显示

    在图1中,第一行表示的项目依次为当前时间、系统启动时间、当前系统登录用户数目、平均负载。第二行显示的是所有启动的进程、目前运行的、挂起 (Sleeping)的和无用(Zombie)的进程。第三行显示的是目前CPU的使用情况,包括系统占用的比例、用户使用比例、闲置(Idle)比例。第四行显示物理内存的使用情况,包括总的可以使用的内存、已用内存、空闲内存、缓冲区占用的内存。第五行显示交换分区使用情况,包括总的交换分区、使用的、空闲的和用于高速缓存的大小。第六行显示的项目最多,下面列出了详细解释。
    PID(Process ID):进程标示号。
    USER:进程所有者的用户名。
    PR:进程的优先级别。
    NI:进程的优先级别数值。
    VIRT:进程占用的虚拟内存值。
    RES:进程占用的物理内存值。
    SHR:进程使用的共享内存值。
    S:进程的状态,其中S表示休眠,R表示正在运行,Z表示僵死状态,N表示该进程优先值是负数。
    %CPU:该进程占用的CPU使用率。
    %MEM:该进程占用的物理内存和总内存的百分比。
    TIME+:该进程启动后占用的总的CPU时间。
    Command:进程启动的启动命令名称,如果这一行显示不下,进程会有一个完整的命令行。
    top命令使用过程中,还可以使用一些交互的命令来完成其它参数的功能。这些命令是通过快捷键启动的。
    <空格>:立刻刷新。
    P:根据CPU使用大小进行排序。
    T:根据时间、累计时间排序。
    q:退出top命令。
    m:切换显示内存信息。
    t:切换显示进程和CPU状态信息。
    c:切换显示命令名称和完整命令行。
    M:根据使用内存大小进行排序。
    W:将当前设置写入~/.toprc文件中。这是写top配置文件的推荐方法。

    可以看到,top命令是一个功能十分强大的监控系统的工具,对于系统管理员而言尤其重要。但是,它的缺点是会消耗很多系统资源。


     发表于 09:48:53  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2006-04-24
    Tag:redhat Linux update APT

    如何用APT维护Red Hat Enterprise Linux (RHEL)zt
    作者: 月下刀客  发布日期: 2005-11-18    查看数: 269   出自: http://www.linuxsky.net
    作者:Fenng
    日期:11-Nov-2004 
    出处:http://www.dbanotes.net
    版本:V0.031


    --------------------------------------------------------------------------------


    内容简介
    如何用APT(Advanced Packaging Tool)维护Red Hat Enterprise Linux (RHEL),提供对个别RHEL的用户无法升级的问题的解决办法。关键词:APT,Linux,升级,Red Hat Enterprise Linux,RHEL,YUM,RPM,依赖性

    几句前言
    Linux系统维护中令管理员很头疼的就是软件包之间的依赖性了,往往是你要安装A软件,但是编译的时候告诉你X软件安装之前需要B软件,而当你安装Y软件的时候,又告诉你需要Z库了--好不容易安装好Z库,发现版本还有问题......可能很多朋友都有过这个经历。其实开源社区早就对这个问题尝试进行解决了,不同的发行版推出了各自的工具,比如Yellow Dog的YUM ,Debian的APT(Advanced Packaging Tool)等。而这些软件也被开源软件爱好者们逐渐移植到别的发行版上。

    Redhat企业版Linux的的升级往往给管理员们带来不少问题:网站下载速度太慢,不够安全,当然了,更多的人是无法更新的--版权问题。经过一段时间的比较 ,感觉使用APT维护RHEL有着特殊的便利性。 (有的朋友可能会说,yum 也不错阿!是的,yum在很多时候表现的确不错,不过如果使用的Linux是RHEL的话,很难找到适合yum的资料库,"巧妇难为无米之炊"。) 现在把具体方法介绍给大家作为参考。

    APT基本介绍
    Debian GNU/Linux 是APT的缔造者。初衷是利用工具来解决软件安装时候的依赖性问题。其工作原理大致为:用户安装APT客户端工具,查寻APT服务器端的资料库(repositories)上的RPM软件包信息,并分析软件包之间的依赖性然后下载并进行安装。

    安装与配置
    首先让我们安装APT工具:

    # wget http://redhat.uni-klu.ac.at/el3/apt.i386.rpm
    # rpm -Uvh apt.i386.rpm
    安装够简单吧? 我们要编辑配置文件:
    #vi /etc/apt/sources.list.d/dag.list
    添加如下内容(资料库相关的信息):
    rpm http://afs.caspur.it/ afs/italia/project/linux/cern/slc302/i386/apt os updates extras
    rpm http://redhat.uni-klu.ac.at redhat/dag/el3/i386 dag
    rpm-src http://redhat.uni-klu.ac.at redhat/dag/el3/i386 dag
    rpm http://apt.sw.be redhat/el3/en/i386 dag
    rpm-src http://apt.sw.be redhat/el3/en/i386 dag
    注: 第一条http://afs.caspur.it/ 的资料库几乎就是Redhat官方站点的内容。在写这篇文章的时候还是有效的。如果要尝试更新Kernel,还可以在第一条后面添加 kernel26 .

    如果需要更多Java相关软件,则:
    #vi /etc/apt/sources.list.d/jpackage.list
    (这一步是可选的)添加如下内容:
    rpm http://redhat.uni-klu.ac.at redhat/jpackage/redhat-es-3/i386 free devel
    rpm-src http://redhat.uni-klu.ac.at redhat/jpackage/redhat-es-3/i386 free devel
    rpm http://redhat.uni-klu.ac.at redhat/jpackage/redhat-es-3/generic free devel
    rpm-src http://redhat.uni-klu.ac.at redhat/jpackage/redhat-es-3/generic free devel
    如果要更新KDE的话(这一步可选的):
    #vi /etc/apt/sources.list.d/kde.list
    考虑添加如何内容:
    rpm http://apt.kde-redhat.org apt/fedora/3.0 stable
    rpm http://apt.kde-redhat.org apt/fedora/all stable
    rpm http://apt.kde-redhat.org apt/kde-redhat/3.0 stable unstable
    rpm http://apt.kde-redhat.org apt/kde-redhat/all stable unstable
    当然,这些内容是经过笔者验证的,都是可用的。从一些站点上下载的list 似乎都多多少少有点问题。
    注: 如果您发现上述的资料库失效或者是有什么更好的资料库。烦请通知我: DBAnotes@gmail.com .

    使用简介
    使用相对来说比较简单:

    #apt-get update
    #apt-get upgrade
    #apt-get check //检查依赖性
    #apt-get -f install // 解决依赖性问题
    如果要安装某工具,比如说iftop,可以这样:
    #apt-cache search iftop
    #apt-get install iftop
    apt自动解决依赖性问题,方便得很。
    要注意的是需要导入相应资料库的签名。在相关站点下载GPG key之后,用如下命令导入即可:

    #rpm --import TheKey_youDownload
    如果有耐心看到这里的话,可以发现盗版的用户或者是用RHEL进行测试的朋友可以通过这个进行升级了--要不然RHEL的up2date 总是要你输入认证信息的。

    参考信息


    APT-howto - http://www.debian.org/doc/manuals/apt-howto/index.en.html

    其他版本的APT使用问题和一些使用技巧请参考这里:

    http://dag.wieers.com/home-made/apt/FAQ.php
    http://www2.uni-klu.ac.at/support/Redhat
    http://linuxwiki.de/apt/RedHat

    =============

    本文作者
    Fenng,某美资公司DBA,业余时间混迹于各数据库相关的技术论坛且乐此不疲。目前关注如何利用ORACLE数据库有效地构建企业应用。对Oracle tuning、troubleshooting有一点研究。
    个人技术站点:http://www.dbanotes.net/ 。可以通过电子邮件 dbanotes@gmail.com 联系到他。

     发表于 10:01:02  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2006-04-09
    Tag:subversion SVN

    用 Subversion 构建版本控制环境

    developerWorks
    文档选项
    <>
    将此页作为电子邮件发送

    将此页作为电子邮件发送


    最新推荐

    Java 应用开发源动力 - 下载免费软件,快速启动开发


    刘冬 , Java自由人

    2005 年 9 月

    本文将介绍如何通过 Subversion 来构建小组开发过程中最为重要的版本控制环境,包括Subversion 环境的安装配置以及如何通过各种有效的客户端工具来提高工作的效率。

    一. 首先我们先来认识一下 Subversion

    Subversion 项目的初衷是为了替换现在开源社区最为流行的版本控制软件 CVS,在 CVS的功能的基础上有很多的提升同时也能较好的解决 CVS 系统的一些不足,这些提升主要包括以下的一些方面:

    1. 目录、文件以及改名等元数据的版本化
    不同于 CVS 只关心文件的内容以及文件是否存在,所有文件、目录的相关操作都是被版本化的,例如文件的改名、拷贝等等;

    2. 提交操作是真正的原子操作
    在 Subversion 中,提交操作是不可分割的,修订版本号是基于每次提交操作而非文件。提交日志被附加在每个修订版本中,而不是像 CVS 一样冗余的进行存储;

    3. 可通过 Apache 服务器提供基于 WebDAV/DeltaV 协议的支持
    该功能可使 Subversion 通过 Apache Web 服务器使资源库更加灵活的在网上进行共享,使其在互操作性上大大优于 CVS;

    4. 可独立运行
    当你不想使用 Apache 2.x 时候,你也可以使用 Subversion,它可以以守护进程或者是Windows 下的服务方式独立运行;

    5. 分支(Branching)与标签(Tagging)操作是轻量级的;

    6. 客户服务器端分层库结构设计;

    7. 资源库可以采用数据库(BerkeleyDB)或者是使用特定格式的文件进行存储;

    8. 更有效的对二进制文件进行处理。

    更多的特性可以参照 Subversion 提供的文档(http://subversion.tigris.org/)



    回页首


    二. Subversion版本控制环境在Windows系统下的安装

    在Windows下安装最为方便的办法就是下载安装程序,你可以到下面这个地址下载最新的二进制压缩版本svn-win32-1.2.3.zip ,地址是: http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91 把该文件解压到一个目录,假定为 D:\subversion。

    接下来新建一个存放项目的资源库目录,例如:D:\repository\project1,执行下面命令对这个项目目录进行初始化: D:\subversion\bin> svnadmin create D:\repository\project1

    Subversion会在D:\repository\project1目录下生成很多的子目录以及文件,接下来我们需要设置该项目的用户信息以及项目的基本信息,打开D:\repository\project1\conf\passwd文件,去掉[users]的注释,并添加用户如下:


    
    ### This file is an example password file for svnserve.
    ### Its format is similar to that of svnserve.conf. As shown in the
    ### example below it contains one section labelled [users].
    ### The name and password for each user follow, one account per line.
    
    [users]
    admin = admin1234
    liudong = liudong123
    

    Subversion使用了明码存储用户的口令,这应该算是它的一个不足。

    接下来打开conf\svnserve.conf修改如下


    
    [general]
    anon-access = read
    auth-access = write
    password-db = passwd
    realm = project1
    

    在做完这些基本的设置后就可以启动 Subversion 了,当然最好的方式就是让 Subversion 做为一个服务来运行,我们可以通过一个第三方的工具 SVNService 让 Subversion 以 Windows 服务的方式运行。

    到 http://dark.clansoft.dk/~mbn/svnservice/ 下载SVNService.zip并把它解压到{Subversion}\bin目录下,通过运行 svnservice -install -d -r D:\repository\project1 ,执行的结果显示:SVNService installed. 这时候你可以在服务控制台中看到名为SVNService的服务,启动它就可以了,如果你不想用服务的方式启动Subversion,你可以运行svnserve -d来启动Subversion。

    要卸载SVNService服务,只需要运行 SVNService -remove 即可。

    至此,Subversion已经安装成功,我们将在接下来的一节中介绍如何通过各种客户端对资源库进行操作。





    回页首


    三. Subversion 各种客户端的使用

    一个版本控制软件好不好不仅在于服务器端是否提供足够强大的功能,同时有没有足够友好的客户端也是非常重要的。

    Subversion 本身提供一个基于命令行的工具 svn,基本上所有的操作都可以通过这个工具来完成,但是用户操作界面不太友好。不过我们可以先使用这个工具来验证一下我们之前安装的 Subversion 服务是否已经正常工作。接下来我们先随便导入一个项目,并对这个项目的某些文件进行简单的修改、提交并重新导出项目,通过这些基本的操作先来体验一下Subversion。(为了操作方便你最好把{subversion}\bin目录加到系统的PATH环境变量中)

    1. 导入项目

    转到你的项目所在的目录,执行下面命令来提交整个项目
    svn import . svn://localhost/project1 -m "initial import" --username liudong --password liudong123
    其中[.]表示当前目录,你也可以指定项目的绝对路径。

    2. 检出项目
    为了验证刚才导入的项目,我们转到一个新的目录下,执行
    svn checkout svn://localhost/project1 --username liudong -password liudong123
    就可以在当前目录下生成一个project1的项目目录,目录中的内容就是我们刚才所提交的所有文件。

    3. 提交修改后的文件
    修改项目中的任何一个文件,使用命令来提交所作的修改:
    svn commit ReadMe.txt -m "modified" --username liudong -password liudong123

    4. 获取最新的版本
    当项目组的其他成员修改并提交了某个文件,你可以通过下面命令来获取到该文件的最新的版本:
    svn update -r HEAD ReadMe.txt --username liudong -password liudong123

    上面四个是版本控制环境中最最基本的操作,不过这样的操作环境你肯定觉得麻烦,对于使用Eclipse环境进行开发的朋友来讲,接下来我们介绍一个Eclipse的插件Subclipse,该插件提供对Subversion服务的操作支持。你可以单独下载该插件的压缩包进行本地更新或者通过Eclipse Update进行远程安装,远程安装的URL是 http://subclipse.tigris.org/update ,相信大家对Eclipse Update已经了如指掌,这里不再罗嗦。

    检查一下插件有没有安装成功吧,打开菜单Windows->Preferences->Team检查是否有SVN节点,点击SVN即可看到该插件的设置界面如下图所示:



    保持默认的设置即可,接下来我们通过该插件将一个项目导入到Subversion服务器中,右击项目名->Team->Share Project…打开项目共享对话框,对话框有两个选择,一是Eclipse内置的对CVS的支持,还有另外一个就是我们刚装上的SVN。选择SVN进入服务器设置界面,入下图



    需要填写的是服务器的URL以及用户名和口令,服务器的URL不需要填写项目名称,点击下一步按钮进入项目名称设置



    在这里可以看到Subclipse会自动给URL加上项目的名称。点击结束按钮将出现提交对话框如下图



    选择你所需要提交的文件或者目录点击OK按钮即可完成项目的导入。接下来的很多操作跟CVS很类似,但是又比CVS的功能强大得多,随便右击一个文件打开Team的上下文菜单如下:



    通过该菜单我们可以看到CVS有的功能在这上面都有,而且还包括可以对文件进行加锁和解锁操作,同时还有可以设置文件的属性,可以通过SVN Properties视图查看某个文件的属性



    与CVS不同的是当文件被修改后SVN插件显示的是一个星号的小图标。同样的,当有些文件你并不想添加到资源库中的时候,你也可以像CVS一样把该文件添加到svn:ignore。Subclipse插件还有更多其他的功能这里不一一介绍了,大家可以在使用的过程中去发掘。

    以上介绍的针对使用Eclipse开发环境的人员,但是项目组的一些其他成员例如网页设计师,他们怎么来方便的使用Subversion呢?因此接下来我们介绍一个集成在Windows Shell的客户端工具TortoiseSVN (http://tortoisesvn.tigris.org/),利用这个工具也可以非常简单的进行资源库的操作。TortoiseSVN的安装非常简单,直接运行安装程序,按照默认方式安装即可,安装完毕需要重新启动系统。

    如果没什么意外的话,随便右击一个文件即可看到上下文菜单多了一个菜单项是TortoiseSVN,如果是文件夹还会有另外一个项是SVN Checkout…。在使用之前你可以根据自己的喜欢对TortoiseSVN进行一些设置,右击任一文件选择TortoiseSVN->Settings即可打开设置对话框如下:



    TortoiseSVN的一个非常有用的工具就是资源库浏览器,在桌面空白位置单击鼠标右键选择TortoiseSVN->Repo-Browser即可打开资源库浏览器如下图所示:



    通过该浏览器你可以浏览资源库中的所有项目以及项目中每一个文件的信息。但是怎么做一些日常的操作呢,例如提交、更新等等?

    首先我们先看如何从资源库中检出(CheckOut)一个已有的项目,在空白处单击鼠标右键选择SVN Checkout…菜单项



    输入存放项目的文件夹以及项目对应的SVN的URL地址如上图,点击OK按钮后TortoiseSVN会显示详细的进度信息



    转到存放项目的文件夹即可看到整个项目的所有文件已经被检出,而且图标已经被替换成TortoiseSVN的图标,如下图所示:



    这个时候你就可以随意的修改文件,并在修改后右击所修改的文件即可进行提交或者更新操作。

    以上介绍的三种不同的Subversion客户端已经可以满足大部分用户的要求,同时三者也可以互为补充。另外Subversion也可以与Apache HTTP服务器结合提供基于WebDAV协议的服务,其在共享方面远远超过了CVS,有兴趣的读者可以阅读Subversion的文档进行配置。

    对正在使用CVS的用户来讲,也可以通过一个名为cvs2svn的工具来将已有的项目移植到Subversion中,该工具可以在http://cvs2svn.tigris.org/ 下载。





    回页首


    参考资料



     发表于 21:00:26  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2006-03-20
    Tag:Google 网站

    Google这个公司现在已经是“家大业大”了,他们总是隔三岔五地推出一些新鲜的服务,让业界跟着也兴奋一把。不过历年来Google所发展出来的服务和软件实在太多了,究竟他们已经有了什么服务?现在就来看看吧。

      Add to Google

      这是一个提供网页信息的站点,主要的功能是把自己的主页介绍给Google让他收录,而时间上较长,起码一两个月才会被Google收录,但是一旦收了你的主页,知名度会更快地上升。

      Blogger

      Google提供的Blog服务,现在已经有中文版本了,大家可以上去安个家,把地址写到本文评论让大家去浏览。

      Froogle

      这是一个专业的引擎,可以输入你想要购买的东西,然后得到符合关键词的结果出来,可以比较一下各个购物网站不同的价格,挑选最合适的地方进行购买。

      Gmail

      Gmail是是Google提供的当前最流行的免费邮件服务,提供了超过2GB的储存空间。

      Google AdSense

      Google提供的广告服务,你是否遇到有不知来源的IP经常恶意点击你的广告,而你无法知道IP所以无法禁止,你是否想知道你的广告在哪个或者哪些页面点击率最高,而又不受渠道数量的限制,它主要针对Google Adsense的规则,在不违反规则的前提下为用户提供及时详细的广告点击统计信息。

      Google AdWords

      Google提供给商家的特殊广告站点,只要有人点击这里就会按一定规则向商家收费,算是网络上的分类广告。

      Google Alerts

      这是一个新闻定制站点,可以通过邮箱定制你需要的内容,然后得到相关的讯息。

      Google Analytics

      Google推出的免费提供的网站统计服务,只需要简单注册,即可帮助站长分析自己的站点情况,而且里面的内容非常详细,不光小网站有用,大网站更是可以作为一个参考的指标。

      Google Answers

      Google的问答站点,可以回答你很多不知道的问题,类似的还有百度出的百度知道,现在这个站点开始进入收费模式,你可以悬赏进行问题答案的购买。

      Google Base

      这个服务相对于Google其它服务的专业化,或许显得比较杂乱,里面也是可以让我们提交不同的信息给Google,让它出现在Google的搜索里面。

      Google Blog Search

      这是一个针对Google博客的搜索服务,专门收集其中的海量信息。

      Google Book Search

      Google的书籍搜索服务,其实也是Google引擎的一个小延伸而已,不过在这里搜索到的结果比较专业和集中。

      Google Catalogs

      Google做的邮购搜索服务,对于国人来说好象用处并不是特别地大。

      Google Code

      Google用来推广及发展开源软件的一个服务,一个适合程序员的源代码公开站点

      Google Compute

      Google的网格计算,可以将一些超大规模的计算量分散到全球不同国家地区的电脑上,以尽快得到结果,这是些有益全球的计算,希望有电脑的朋友都参加。

      Google Desktop

      这是一个放置在桌面上的工具条,在这个工具条里可提供新闻,天气,Email等小程序,了解最新的信息。

      Google Directory

      Goolge制作的超大型人工分类目录,让网页根据重要性来排列。目录搜索服务可满足那些想要浏览某特定主题下相关信息的用户。

      Google Earth

      这项服务提供了地球上大部分地区的卫星图片查询,尤其是大城市的图片更加地多,让你如宇航员一般身临其境,足不出户也可了解世界各地。

      Google Groups

      Google提供的群组服务。利用它你可以创建邮件列表、阅读新闻或者是和志同道合的用户分享你感兴趣的东西。

      Google Homepage

      是Google提供的主页服务,你可以定制它,它提供了天气、新闻、占卜等各种各样的服务。

      Google Image Search

      Google的图片搜索,几乎是Google最早的服务了,这是它的图片搜索页面,相信大家都用过吧,图片搜索的精确度还是不错的。

      Google Labs

      Google实验室的一些服务链接,从这里可以看到它们又有什么天才的发明。

      Google Local

      Google本地搜索,通过这一服务,用户可以使用关键字搜索在特定的城市查找某一类型的公司,并在电子地图上显示这些公司的具体位置。这项服务现在有了中国版本

      Google Maps

      Google地图搜索服务,让你浏览到世界各地的地图、公路等信息,比较上面提到的卫星地图来说,比较传统。

      Google Mobile

      Google手机上网用户的服务,只要手机能连上这外网站,即可象用PC一样搜索图片、关键字等信息。

      Google Movie Showtimes

      Google提供的电影上映时间搜索服务,只要输入一个地方的邮政编码或地址,就可以搜索到当地的电影院及电影的上映时间。

      Google News

      Google新闻站点,将最新的新闻呈现在大家的眼前,上面的所有新闻都是由Google特定的电脑自动聚合的。

      Google Page

      Google推出的免费个人主页服务,用户可以在这里获得一个100M大小的免费主页空间。

      Google Reader

      Google的在线RSS阅读器,Reader依靠RSS和Atom技术,可帮助用户及时获得信息,用户不必自己检查更新喜欢的站点,Google Reader可以帮你。

      Google Ridefinder

      美国12个城市的公交车和出租车的相关搜索。

      Google Scholar

      学术文章搜索引擎,高年级学生的必备,尤其一些经常需要撰写一些论文的朋友。

      Google Send to Phone

      利用网络发送手机短信的服务,感觉上没什么特别。

      Google Sitemap

      Google的Sitemaps计划,旨在对网站信息搜索进行加速,增强索引能力。Google称:“这种协作搜索系统将进一步提高覆盖和刷新速度,使用户使用Google索此功能实现最优化。”Google呼吁网站管理员在网站服务器中放置Sitemaps格式的文件。这样,Google的搜索引擎就可以看到那些网页在网站内,那些网页内容被修改了。

      Google SMS

      GOOGLE SMS服务,是通过SMS查找特定信息的一项技术。它可以提供驾车服务,在无线产品中支持SMS。

      Google Suggest

      这是一个猜测你意图的测试站,当用户关键词搜索框中输入文字时,下拉清单将显示候补搜索单词或短语一览。还将显示找到的各单词或短语的网页数。从候补中选择单词或短语便可搜索。

      Google Talk

      Google推出的即时在线聊天工具,当时挺火爆的,业内很多人都说能跟各大即时聊天工具一拼,可是现在没多少个人用了,影响较低。

      Google Toolbar

      Google的搜索工具条,上面有很多实用功能,搜索、拦截弹出窗口、查看网页PR值等等一大堆。

      Google Video

      这又是一个新的尝试,Google推出的视频搜索内容丰富,不过国内用户好象会受到一定的限制。

      Google Web Accelerator

      可以加速网页的载入,尤其是对付一些我们网络访问较慢的外国网站更是好用

      Google Web Search

      Google网站默认的搜索服务。

      Hello

      Hello即时聊天工具,是一个极小的即时通信客户端,它和Google的看图软件Picasa一起工作,能让你和亲人好友分享图片。

      Picasa

      超强的图片管理显示的软件,得益于其高效的图片管理模式,我们可将电脑里所有的图片都让它归类,分析。它现在已是免费软件,大家可以让ACDSee下岗了。


     发表于 13:09:07  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2006-02-21
    Javascript的IE和Firefox兼容性汇编
    Tag:JavaScript firefox ie 兼容

    以下以 IE 代替 Internet Explorer,以 MF 代替 Mozzila Firefox

    1. document.form.item 问题
        (1)现有问题:
            现有代码中存在许多 document.formName.item("itemName") 这样的语句,不能在 MF 下运行
        (2)解决方法:
            改用 document.formName.elements["elementName"]
        (3)其它
            参见 2

    2. 集合类对象问题
        (1)现有问题:
            现有代码中许多集合类对象取用时使用 (),IE 能接受,MF 不能。
        (2)解决方法:
            改用 [] 作为下标运算。如:document.forms("formName") 改为 document.forms["formName"]。
            又如:document.getElementsByName("inputName")(1) 改为 document.getElementsByName("inputName")[1]
        (3)其它

    3. window.event
        (1)现有问题:
            使用 window.event 无法在 MF 上运行
        (2)解决方法:
            MF 的 event 只能在事件发生的现场使用,此问题暂无法解决。可以这样变通:
            原代码(可在IE中运行):
                <input type="button" name="someButton" value="提交" onclick="java script:gotoSubmit()"/>
                ...
                <script language="java script">
                    function gotoSubmit() {
                        ...
                        alert(window.event);    // use window.event
                        ...
                    }
                </script>

            新代码(可在IE和MF中运行):
                <input type="button" name="someButton" value="提交" onclick="java script:gotoSubmit(event)"/>
                ...
                <script language="java script">
                    function gotoSubmit(evt) {
                        evt = evt ? evt : (window.event ? window.event : null);
                        ...
                        alert(evt);             // use evt
                        ...
                    }
                </script>
            此外,如果新代码中第一行不改,与老代码一样的话(即 gotoSubmit 调用没有给参数),则仍然只能在IE中运行,但不会出错。所以,这种方案 tpl 部分仍与老代码兼容。

    4. HTML 对象的 id 作为对象名的问题
        (1)现有问题
            在 IE 中,HTML 对象的 ID 可以作为 document 的下属对象变量名直接使用。在 MF 中不能。
        (2)解决方法
            用 getElementById("idName") 代替 idName 作为对象变量使用。

    5. 用idName字符串取得对象的问题
        (1)现有问题
            在IE中,利用 eval(idName) 可以取得 id 为 idName 的 HTML 对象,在MF 中不能。
        (2)解决方法
            用 getElementById(idName) 代替 eval(idName)。

    6. 变量名与某 HTML 对象 id 相同的问题
        (1)现有问题
            在 MF 中,因为对象 id 不作为 HTML 对象的名称,所以可以使用与 HTML 对象 id 相同的变量名,IE 中不能。
        (2)解决方法
            在声明变量时,一律加上 var ,以避免歧义,这样在 IE 中亦可正常运行。
            此外,最好不要取与 HTML 对象 id 相同的变量名,以减少错误。
        (3)其它
            参见 问题4

    7. event.x 与 event.y 问题
        (1)现有问题
            在IE 中,event 对象有 x, y 属性,MF中没有。
        (2)解决方法
            在MF中,与event.x 等效的是 event.pageX。但event.pageX IE中没有。
            故采用 event.clientX 代替 event.x。在IE 中也有这个变量。
            event.clientX 与 event.pageX 有微妙的差别(当整个页面有滚动条的时候),不过大多数时候是等效的。

            如果要完全一样,可以稍麻烦些:
            mX = event.x ? event.x : event.pageX;
            然后用 mX 代替 event.x
        (3)其它
            event.layerX 在 IE 与 MF 中都有,具体意义有无差别尚未试验。


    8. 关于frame
       (1)现有问题
             在 IE中 可以用window.testFrame取得该frame,mf中不行
       (2)解决方法
             在frame的使用方面mf和ie的最主要的区别是:
    如果在frame标签中书写了以下属性:
    <frame src="/xx.htm" id="frameId" name="frameName" />
    那么ie可以通过id或者name访问这个frame对应的window对象
    而mf只可以通过name来访问这个frame对应的window对象
    例如如果上述frame标签写在最上层的window里面的htm里面,那么可以这样访问
    ie: window.top.frameId或者window.top.frameName来访问这个window对象
    mf: 只能这样window.top.frameName来访问这个window对象

    另外,在mf和ie中都可以使用window.top.document.getElementById("frameId")来访问frame标签
    并且可以通过window.top.document.getElementById("testFrame").src = 'xx.htm'来切换frame的内容
    也都可以通过window.top.frameName.location = 'xx.htm'来切换frame的内容
    关于frame和window的描述可以参见bbs的‘window与frame’文章
    以及/test/js/test_frame/目录下面的测试
    ----adun 2004.12.09修改

    9. 在mf中,自己定义的属性必须getAttribute()取得
    10.在mf中没有  parentElement parement.children  而用
                   parentNode parentNode.childNodes
       childNodes的下标的含义在IE和MF中不同,MF使用DOM规范,childNodes中会插入空白文本节点。
      一般可以通过node.getElementsByTagName()来回避这个问题。
       当html中节点缺失时,IE和MF对parentNode的解释不同,例如
       <form>
       <table>
            <input/>
       </table>
       </form>
       MF中input.parentNode的值为form, 而IE中input.parentNode的值为空节点

      MF中节点没有removeNode方法,必须使用如下方法 node.parentNode.removeChild(node)

    11.const 问题
      (1)现有问题:
         在 IE 中不能使用 const 关键字。如 const constVar = 32; 在IE中这是语法错误。
      (2)解决方法:
         不使用 const ,以 var 代替。

    12. body 对象
       MF的body在body标签没有被浏览器完全读入之前就存在,而IE则必须在body完全被读入之后才存在

    13. url encoding
    在js中如果书写url就直接写&不要写&amp;例如var url = 'xx.jsp?objectName=xx&amp;objectEvent=xxx';
    frm.action = url那么很有可能url不会被正常显示以至于参数没有正确的传到服务器
    一般会服务器报错参数没有找到
    当然如果是在tpl中例外,因为tpl中符合xml规范,要求&书写为&amp;
    一般MF无法识别js中的&amp;


    14. nodeName 和 tagName 问题
      (1)现有问题:
         在MF中,所有节点均有 nodeName 值,但 textNode 没有 tagName 值。在 IE 中,nodeName 的使用好象
         有问题(具体情况没有测试,但我的IE已经死了好几次)。
      (2)解决方法:
         使用 tagName,但应检测其是否为空。

    15. 元素属性
       IE下 input.type属性为只读,但是MF下可以修改


    16. document.getElementsByName() 和 document.all[name] 的问题
      (1)现有问题:
         在 IE 中,getElementsByName()、document.all[name] 均不能用来取得 div 元素(是否还有其它不能取的元素还不知道)。

     发表于 22:50:08  阅读全文  |  评论(1)  |  Trackback(0)  | 编辑
     
    2006-02-14
    Tag:prototype JavaScript

    /*prototype 1.3.1 版本和之前的 1.2.0 版本有了不少改进,并增加了新的功能:
    1. 增加了事件注册管理
    2. 增加了空间定位的常用函数
    3. 改善了 xmlhttp 的封装
    4. 移除了 Effect.js,交给 Rico 或者 script.aculo.us 这些扩展库类实现。
    5. bug 修复
    代码:
    */
    /**
    * 定义一个全局对象, 属性 Version 在发布的时候会替换为当前版本号
    */
    var Prototype = {
    Version: '1.3.1',
    // 一个空方法,其后的代码常会用到,先前的版本该方法被定义于 Ajax 类中。
    emptyFunction: function() {}
    }
    /**
    * 创建一种类型,注意其属性 create 是一个方法,返回一个构造函数。
    * 一般使用如下
    *   var X = Class.create(); 返回一个类型,类似于 java 的一个Class实例。
    * 要使用 X 类型,需继续用 new X()来获取一个实例,如同 java 的 Class.newInstance()方法。
    *
    * 返回的构造函数会执行名为 initialize 的方法, initialize 是 Ruby 对象的构造器方法名字。
    * 此时initialize方法还没有定义,其后的代码中创建新类型时会建立相应的同名方法。
    *
    */
    var Class = {
    create: function() {
      return function() {
        this.initialize.apply(this, arguments);
      }
    }
    }

    /**
    * 创建一个对象,从变量名来思考,本意也许是定义一个抽象类,以后创建新对象都 extend 它。
    * 但从其后代码的应用来看, Abstract 更多是为了保持命名空间清晰的考虑。
    * 也就是说,我们可以给 Abstract 这个对象实例添加新的对象定义。
    */
    var Abstract = new Object();

    Object.extend = function(destination, source) {
    for (property in source) {
      destination[property] = source[property];
    }
    return destination;
    }
    /**
    * 获取参数对象的所有属性和方法,有点象多重继承。但是这种继承是动态获得的。
    * 如:
    *   var a = new ObjectA(), b = new ObjectB();
    *   var c = a.extend(b);
    * 此时 c 对象同时拥有 a 和 b 对象的属性和方法。但是与多重继承不同的是,c instanceof ObjectB 将返回false。
    *
    * 旧版本的该方法定义如下:
    * Object.prototype.extend = function(object) {
    *   for (property in object) {
    *       this[property] = object[property];
    *   }
    *   return this;
    * }
    *
    * 新的形式新定义了一个静态方法 Object.extend,这样做的目的大概是为了使代码更为清晰
    */
    Object.prototype.extend = function(object) {
    return Object.extend.apply(this, [this, object]);
    }

    /**
    * 这个方法很有趣,它封装一个javascript函数对象,返回一个新函数对象,新函数对象的主体和原对象相同,但是bind()方法参数将被用作当前对象的对象。
    * 也就是说新函数中的 this 引用被改变为参数提供的对象。
    * 比如:
    *   <input type="text" id="aaa" value="aaa">
    *   <input type="text" id="bbb" value="bbb">
    *   .................
    *   <script>
    *       var aaa = document.getElementById("aaa");
    *       var bbb = document.getElementById("bbb");
    *       aaa.showValue = function() {alert(this.value);}
    *       aaa.showValue2 = aaa.showValue.bind(bbb);
    *   </script>
    * 那么,调用aaa.showValue 将返回"aaa", 但调用aaa.showValue2 将返回"bbb"。
    *
    * apply 是ie5.5后才出现的新方法(Netscape好像很早就支持了)。
    * 该方法更多的资料参考MSDN http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthApply.asp
    * 阅读其后的代码就会发现,bind 被应用的很广泛,该方法和 Object.prototype.extend 一样是 Prototype 的核心。
    * 还有一个 call 方法,应用起来和 apply 类似。可以一起研究下。
    */
    Function.prototype.bind = function(object) {
    var __method = this;
    return function() {
      __method.apply(object, arguments);
    }
    }
    /**
    * 和bind一样,不过这个方法一般用做html控件对象的事件处理。所以要传递event对象
    * 注意这时候,用到了 Function.call。它与 Function.apply 的不同好像仅仅是对参数形式的定义。
    */
    Function.prototype.bindAsEventListener = function(object) {
    var __method = this;
    return function(event) {
      __method.call(object, event || window.event);
    }
    }
    /**
    * 将整数形式RGB颜色值转换为HEX形式
    */
    Number.prototype.toColorPart = function() {
    var digits = this.toString(16);
    if (this < 16) return '0' + digits;
    return digits;
    }
    /**
    * 典型 Ruby 风格的函数,将参数中的方法逐个调用,返回第一个成功执行的方法的返回值
    */
    var Try = {
    these: function() {
      var returnValue;

      for (var i = 0; i < arguments.length; i++) {
        var lambda = arguments[i];
        try {
        returnValue = lambda();
        break;
        } catch (e) {}
      }

      return returnValue;
    }
    }
    /*--------------------------------------------------------------------------*/

    /**
    * 一个设计精巧的定时执行器
    * 首先由 Class.create() 创建一个 PeriodicalExecuter 类型,
    * 然后用对象直接量的语法形式设置原型。
    *
    * 需要特别说明的是 rgisterCallback 方法,它调用上面定义的函数原型方法bind, 并传递自己为参数。
    * 之所以这样做,是因为 setTimeout 默认总以 window 对象为当前对象,也就是说,如果 registerCallback 方法定义如下的话:
    *   registerCallback: function() {
    *       setTimeout(this.onTimerEvent, this.frequency * 1000);
    *   }
    * 那么,this.onTimeoutEvent 方法执行失败,因为它无法访问 this.currentlyExecuting 属性。
    * 而使用了bind以后,该方法才能正确的找到this,也就是PeriodicalExecuter的当前实例。
    */
    var PeriodicalExecuter = Class.create();
    PeriodicalExecuter.prototype = {
    initialize: function(callback, frequency) {
      this.callback = callback;
      this.frequency = frequency;
      this.currentlyExecuting = false;
      this.registerCallback();
    },

    registerCallback: function() {
      setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
    },

    onTimerEvent: function() {
      if (!this.currentlyExecuting) {
        try {
        this.currentlyExecuting = true;
        this.callback();
        } finally {
        this.currentlyExecuting = false;
        }
      }
    }
    }

    /*--------------------------------------------------------------------------*/

    /**
    * 这个函数就 Ruby 了。我觉得它的作用主要有两个
    * 1. 大概是 document.getElementById(id) 的最简化调用。
    * 比如:$("aaa") 将返回 aaa 对象
    * 2. 得到对象数组
    * 比如: $("aaa","bbb") 返回一个包括id为"aaa"和"bbb"两个input控件对象的数组。
    */
    function $() {
    var elements = new Array();

    for (var i = 0; i < arguments.length; i++) {
      var element = arguments[i];
      if (typeof element == 'string')
        element = document.getElementById(element);

      if (arguments.length == 1)
        return element;

      elements.push(element);
    }

    return elements;
    }

    /**
    * 为兼容旧版本的浏览器增加 Array 的 push 方法。
    */
    if (!Array.prototype.push) {
    Array.prototype.push = function() {
        var startLength = this.length;
        for (var i = 0; i < arguments.length; i++)
        this[startLength + i] = arguments[i];
      return this.length;
    }
    }

    /**
    * 为兼容旧版本的浏览器增加 Function 的 apply 方法。
    */
    if (!Function.prototype.apply) {
    // Based on code from http://www.youngpup.net/
    Function.prototype.apply = function(object, parameters) {
      var parameterStrings = new Array();
      if (!object)   object = window;
      if (!parameters) parameters = new Array();
     
      for (var i = 0; i < parameters.length; i++)
        parameterStrings[i] = 'parameters[' + i + ']';
     
      object.__apply__ = this;
      var result = eval('object.__apply__(' +
        parameterStrings.join(', ') + ')');
      object.__apply__ = null;
     
      return result;
    }
    }

    /**
    * 扩展 javascript 内置的 String 对象
    */
    String.prototype.extend({
    /**
      * 去掉字符串中的<html>标签
      */
    stripTags: function() {
      return this.replace(/<\/?[^>]+>/gi, '');
    },
    /**
      * 这个方法很常见,通常的实现都是用正则表达式替换特殊字符为html规范定义的命名实体或者十进制编码,比如:
      * string.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
      * 而这里的实现借用浏览器自身的内部替换,确实巧妙。
      */
    escapeHTML: function() {
      var div = document.createElement('div');
      var text = document.createTextNode(this);
      div.appendChild(text);
      return div.innerHTML;
    },
      /**
      * 同上
      */
    unescapeHTML: function() {
      var div = document.createElement('div');
      div.innerHTML = this.stripTags();
      return div.childNodes[0].nodeValue;
    }
    });
    /**
    * 定义 Ajax 对象, 静态方法 getTransport 方法返回一个 XMLHttp 对象
    */
    var Ajax = {
    getTransport: function() {
      return Try.these(
        function() {return new ActiveXObject('Msxml2.XMLHTTP')},
        function() {return new ActiveXObject('Microsoft.XMLHTTP')},
        function() {return new XMLHttpRequest()}
      ) || false;
    }
    }
    /**
    * 我以为此时的Ajax对象起到命名空间的作用。
    * Ajax.Base 声明为一个基础对象类型
    * 注意 Ajax.Base 并没有使用 Class.create() 的方式来创建,我想是因为作者并不希望 Ajax.Base 被库使用者实例化。
    * 作者在其他对象类型的声明中,将会继承于它。
    * 就好像 java 中的私有抽象类
    */
    Ajax.Base = function() {};
    Ajax.Base.prototype = {
    /**
      * extend (见上) 的用法真是让人耳目一新
      * options 首先设置默认属性,然后再 extend 参数对象,那么参数对象中也有同名的属性,那么就覆盖默认属性值。
      * 想想如果我写这样的实现,应该类似如下:
      setOptions: function(options) {
        this.options.methed = options.methed? options.methed : 'post';
        ..........
      }
      我想很多时候,java 限制了 js 的创意。
      */
    setOptions: function(options) {
      this.options = {
        method:     'post',
        asynchronous: true,
        parameters:   ''
      }.extend(options || {});
    },
    /**
      * 如果 xmlhttp 调用返回正确的HTTP状态值,函数返回ture, 反之false。
      * xmlhttp 的 readyState 属性不足以准确判断 xmlhttp 远程调用成功,该方法是readyState判断的一个前提条件
      */
    responseIsSuccess: function() {
      return this.transport.status == undefined
        || this.transport.status == 0
        || (this.transport.status >= 200 && this.transport.status < 300);
    },
    /**
      * 如果 xmlhttp 调用返回错误的HTTP状态值,函数返回ture, 反之false。
      */
    responseIsFailure: function() {
      return !this.responseIsSuccess();
    }
    }
    /**
    * Ajax.Request 封装 XmlHttp
    */
    Ajax.Request = Class.create();

    /**
    * 定义四种事件(状态), 参考
    */
    Ajax.Request.Events =
    ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

    /**
    * 相比先前的版本,对于 xmlhttp 的调用和返回值处理分离得更为清晰
    */
    Ajax.Request.prototype = (new Ajax.Base()).extend({
    initialize: function(url, options) {
      this.transport = Ajax.getTransport();
      this.setOptions(options);
      this.request(url);
    },

     /**
      * 新增加 request 方法封装 xmlhttp 的调用过程。
      */
    request: function(url) {
      var parameters = this.options.parameters || '';
      if (parameters.length > 0) parameters += '&_=';

      try {
        if (this.options.method == 'get')
        url += '?' + parameters;

        this.transport.open(this.options.method, url,
        this.options.asynchronous);

        if (this.options.asynchronous) {
        this.transport.onreadystatechange = this.onStateChange.bind(this);
        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
        }

        this.setRequestHeaders();

        var body = this.options.postBody ? this.options.postBody : parameters;
        this.transport.send(this.options.method == 'post' ? body : null);

      } catch (e) {
      }
    },

    /**
      * 新增加的 setRequestHeaders 方法允许添加自定义的http header
      */
    setRequestHeaders: function() {
      var requestHeaders =
        ['X-Requested-With', 'XMLHttpRequest',
        'X-Prototype-Version', Prototype.Version];

      if (this.options.method == 'post') {
        requestHeaders.push('Content-type',
        'application/x-www-form-urlencoded');

        /* Force "Connection: close" for Mozilla browsers to work around
        * a bug where XMLHttpReqeuest sends an incorrect Content-length
        * header. See Mozilla Bugzilla #246651.
        */
        if (this.transport.overrideMimeType)
        requestHeaders.push('Connection', 'close');
      }

      /**
      * 其后的 apply 方法的调用有些奇技淫巧的意味
      * 从上下文中我们可以分析出 this.options.requestHeaders 是调用者自定义的http header数组。
      * requestHeaders 也是一个数组,将一个数组中的元素逐个添加到另一个元素中,直接调用
      * requestHeaders.push(this.options.requestHeaders)
      * 是不行的,因为该调用导致 this.options.requestHeaders 整个数组作为一个元素添加到 requestHeaders中。
      * javascript的Array对象还提供一个concat 的方法表面上满足要求,但是concat实际上是创建一个新数组,将两个数组的元素添加到新数组中。
      * 所以,下面的代码也可以替换为
      * requestHeaders = requestHeaders.concat(this.options.requestHeaders);
      * 很显然,作者不喜欢这样的代码方式
      * 而 apply 方法的语法 apply([thisObj[,argArray]]) 本身就要求第二个参数是一个数组或者arguments对象。
      * 所以巧妙的实现了 concat 函数的作用。
      * 令人拍案叫绝啊!
      */
      if (this.options.requestHeaders)
        requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);

      for (var i = 0; i < requestHeaders.length; i += 2)
        this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
    },


    onStateChange: function() {
      var readyState = this.transport.readyState;
      /**
      * 如果不是 Loading 状态,就调用回调函数
      */
      if (readyState != 1)
        this.respondToReadyState(this.transport.readyState);
    },

    /**
      * 回调函数定义在 this.options 属性中,比如:
        var option = {
          onLoaded : function(req) {...};
          ......
        }
        new Ajax.Request(url, option);
      */
    respondToReadyState: function(readyState) {
      var event = Ajax.Request.Events[readyState];

      /**
      * 新增的回调函数处理,调用者还可以在options中定义 on200, onSuccess 这样的回调函数
      * 在 readyState 为完成状态的时候调用
      */
      if (event == 'Complete')
        (this.options['on' + this.transport.status]
        || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
        || Prototype.emptyFunction)(this.transport);

      (this.options['on' + event] || Prototype.emptyFunction)(this.transport);

      /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
      if (event == 'Complete')
        this.transport.onreadystatechange = Prototype.emptyFunction;
    }
    });

    /**
    * Ajax.Updater 用于绑定一个html元素与 XmlHttp调用的返回值。类似与 buffalo 的 bind。
    * 如果 options 中有 insertion(见后) 对象的话, insertion 能提供更多的插入控制。
    */
    Ajax.Updater = Class.create();
    Ajax.Updater.ScriptFragment = '(?:<script.*?>)((\n|.)*?)(?:<\/script>)';

    Ajax.Updater.prototype.extend(Ajax.Request.prototype).extend({
    initialize: function(container, url, options) {

      /**
      * containers 就是被绑定的 html 对象,xmlhttp的返回值被赋给该对象的 innerHTML 属性。
      * 相比新版本,containers 根据container参数定义 success 和 failure 引用,如果它们被定义的话,根据xmlhttp调用是否成功来选择
      * 更新对象,假想调用可能如下:
      * var c = {success: $("successDiv"), failure: $("failureDiv")};
      * new Ajax.Updater(c, url, options);
      * 那么调用成功则 successDiv 显示成功信息或者数据,反之 failureDiv 显示错误信息
      */
      this.containers = {
        success: container.success ? $(container.success) : $(container),
        failure: container.failure ? $(container.failure) :
        (container.success ? null : $(container))
      }

      this.transport = Ajax.getTransport();
      this.setOptions(options);

      var onComplete = this.options.onComplete || Prototype.emptyFunction;
      this.options.onComplete = (function() {
        this.updateContent();
        onComplete(this.transport);
      }).bind(this);

      this.request(url);
    },

    updateContent: function() {
      var receiver = this.responseIsSuccess() ?
        this.containers.success : this.containers.failure;

      var match   = new RegExp(Ajax.Updater.ScriptFragment, 'img');
      var response = this.transport.responseText.replace(match, '');
      var scripts = this.transport.responseText.match(match);

      if (receiver) {
        if (this.options.insertion) {
        new this.options.insertion(receiver, response);
        } else {
        receiver.innerHTML = response;
        }
      }

      if (this.responseIsSuccess()) {
        if (this.onComplete)
        setTimeout((function() {this.onComplete(
          this.transport)}).bind(this), 10);
      }

      /**
      * 如果调用者在传入的options参数中定义 evalScripts=true,同时xmlhttp返回值的html中包含<script>标签的话,执行该脚本
      */
      if (this.options.evalScripts && scripts) {
      /**
        * 注意前二十行左右还有一个 match 的声明
        * var match   = new RegExp(Ajax.Updater.ScriptFragment, 'img');
        * 和此处的区别就是,正则表达式匹配标记多一个 "g"。
        * 多个g, 所以 scripts 是一个数组,数组中每个元素是一段 <script>...</script> 文本。
        * 没有g, scripts[i].match(match)[1] 匹配的就是 <script>标记中的 script 代码。
        * 关于正则表达式,请参考javascript的相关资料。
        */
        match = new RegExp(Ajax.Updater.ScriptFragment, 'im');
        setTimeout((function() {
        for (var i = 0; i < scripts.length; i++)
          eval(scripts[i].match(match)[1]);
        }).bind(this), 10);
      }
    }
    });

    /**
    * 定期更新器
    */
    Ajax.PeriodicalUpdater = Class.create();
    Ajax.PeriodicalUpdater.prototype = (new Ajax.Base()).extend({
    initialize: function(container, url, options) {
      this.setOptions(options);
      this.onComplete = this.options.onComplete;

      this.frequency = (this.options.frequency || 2);
      // decay 可能是一个时间调整因素
      this.decay = 1;

      this.updater = {};
      this.container = container;
      this.url = url;

      this.start();
    },

    start: function() {
      this.options.onComplete = this.updateComplete.bind(this);
      this.onTimerEvent();
    },

    stop: function() {
      this.updater.onComplete = undefined;
      clearTimeout(this.timer);
      (this.onComplete || Ajax.emptyFunction).apply(this, arguments);
    },

    updateComplete: function(request) {
      if (this.options.decay) {
        this.decay = (request.responseText == this.lastText ?
        this.decay * this.options.decay : 1);

        this.lastText = request.responseText;
      }
      this.timer = setTimeout(this.onTimerEvent.bind(this),
        this.decay * this.frequency * 1000);
    },

    onTimerEvent: function() {
      this.updater = new Ajax.Updater(this.container, this.url, this.options);
    }
    });

    /**
    * 根据 class attribute 的名字得到对象数组,支持 multiple class
    *
    */
    document.getElementsByClassName = function(className) {
    var children = document.getElementsByTagName('*') || document.all;
    var elements = new Array();

    for (var i = 0; i < children.length; i++) {
      var child = children[i];
      var classNames = child.className.split(' ');
      for (var j = 0; j < classNames.length; j++) {
        if (classNames[j] == className) {
        elements.push(child);
        break;
        }
      }
    }

    return elements;
    }

    /*--------------------------------------------------------------------------*/

    /**
    * Element 就象一个 java 的工具类,主要用来 隐藏/显示/销除 对象,以及获取对象的简单属性。
    *
    */
    if (!window.Element) {
    var Element = new Object();
    }

    Object.extend(Element, {
    /**
      * 切换 显示/隐藏
      */
    toggle: function() {
      for (var i = 0; i < arguments.length; i++) {
        var element = $(arguments[i]);
        element.style.display =
        (element.style.display == 'none' ? '' : 'none');
      }
    },

    hide: function() {
      for (var i = 0; i < arguments.length; i++) {
        var element = $(arguments[i]);
        element.style.display = 'none';
      }
    },

    show: function() {
      for (var i = 0; i < arguments.length; i++) {
        var element = $(arguments[i]);
        element.style.display = '';
      }
    },

    /**
      * 从父节点中移除
      */
    remove: function(element) {
      element = $(element);
      element.parentNode.removeChild(element);
    },
     
    getHeight: function(element) {
      element = $(element);
      return element.offsetHeight;
    },

    /**
      * 是否拥有 class 属性值
      */
    hasClassName: function(element, className) {
      element = $(element);
      if (!element)
        return;
      var a = element.className.split(' ');
      for (var i = 0; i < a.length; i++) {
        if (a[i] == className)
        return true;
      }
      return false;
    },

    /**
      * 为对象添加 class 属性值
      */
    addClassName: function(element, className) {
      element = $(element);
      Element.removeClassName(element, className);
      element.className += ' ' + className;
    },

    /**
      * 为对象移除 class 属性值
      */
    removeClassName: function(element, className) {
      element = $(element);
      if (!element)
        return;
      var newClassName = '';
      var a = element.className.split(' ');
      for (var i = 0; i < a.length; i++) {
        if (a[i] != className) {
        if (i > 0)
          newClassName += ' ';
        newClassName += a[i];
        }
      }
      element.className = newClassName;
    },

    // removes whitespace-only text node children
    cleanWhitespace: function(element) {
      var element = $(element);
      for (var i = 0; i < element.childNodes.length; i++) {
        var node = element.childNodes[i];
        if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
        Element.remove(node);
      }
    }
    });

    /**
    * 为 Element.toggle 做了一个符号连接,大概是兼容性的考虑
    */
    var Toggle = new Object();
    Toggle.display = Element.toggle;

    /**
    * 动态插入内容的实现,MS的Jscript实现中对象有一个(insertAdjacentHTML)  方法
    * 这里算是一个对象形式的封装。
    */
    Abstract.Insertion = function(adjacency) {
    this.adjacency = adjacency;
    }

    Abstract.Insertion.prototype = {
    initialize: function(element, content) {
      this.element = $(element);
      this.content = content;
     
      if (this.adjacency && this.element.insertAdjacentHTML) {
        this.element.insertAdjacentHTML(this.adjacency, this.content);
      } else {
        /**
        * gecko 不支持 insertAdjacentHTML 方法,但可以用如下代码代替
        */
        this.range = this.element.ownerDocument.createRange();
      /**
        * 如果定义了 initializeRange 方法,则实行,这里相当与定义了一个抽象的 initializeRange 方法
        */
        if (this.initializeRange) this.initializeRange();
        this.fragment = this.range.createContextualFragment(this.content);
      /**
        * insertContent 也是一个抽象方法,子类必须实现
        */
        this.insertContent();
      }
    }
    }
    /**
    * prototype 加深了我的体会,就是写js 如何去遵循 Don’t Repeat Yourself (DRY) 原则
    * 上文中 Abstract.Insertion 算是一个抽象类,定义了名为 initializeRange 的一个抽象方法
    * var Insertion = new Object() 建立一个命名空间
    * Insertion.Before|Top|Bottom|After 就象是四个java中的四个静态内部类,而它们分别继承于Abstract.Insertion,并实现了initializeRange方法。
    */
    var Insertion = new Object();
    /**
    * 将内容插入到指定节点的前面, 与指定节点同级
    */
    Insertion.Before = Class.create();
    Insertion.Before.prototype = (new Abstract.Insertion('beforeBegin')).extend({
    initializeRange: function() {
      this.range.setStartBefore(this.element);
    },

    insertContent: function() {
      this.element.parentNode.insertBefore(this.fragment, this.element);
    }
    });
    /**
    * 将内容插入到指定节点的第一个子节点前,于是内容变为该节点的第一个子节点
    */
    Insertion.Top = Class.create();
    Insertion.Top.prototype = (new Abstract.Insertion('afterBegin')).extend({
    initializeRange: function() {
      this.range.selectNodeContents(this.element);
      this.range.collapse(true);
    },

    insertContent: function() {
      this.element.insertBefore(this.fragment, this.element.firstChild);
    }
    });
    /**
    * 将内容插入到指定节点的最后,于是内容变为该节点的最后一个子节点
    */
    Insertion.Bottom = Class.create();
    Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({
    initializeRange: function() {
      this.range.selectNodeContents(this.element);
      this.range.collapse(this.element);
    },

    insertContent: function() {
      this.element.appendChild(this.fragment);
    }
    });
    /**
    * 将内容插入到指定节点的后面, 与指定节点同级
    */
    Insertion.After = Class.create();
    Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({
    initializeRange: function() {
      this.range.setStartAfter(this.element);
    },

    insertContent: function() {
      this.element.parentNode.insertBefore(this.fragment,
        this.element.nextSibling);
    }
    });
    /**
    * 针对 页面元素对象(一般都是表单控件)的工具类,提供一些简单静态方法
    * 这些方法显然常用在表单处理中
    * 注意 Field 这种声明方式类似于 java 声明一个静态的 singleton 工具类
    * 等同于 :
    *   var Field = new Object();
    *   Field.extend({...});
    *
    * 后文中的 Form, Event, Position 对象声明方式如出一辙
    */
    var Field = {
    /**
      * 清除参数引用的对象的值
      */
    clear: function() {
      for (var i = 0; i < arguments.length; i++)
        $(arguments[i]).value = '';
    },
    /**
      * 使参数引用对象获取焦点
      */
    focus: function(element) {
      $(element).focus();
    },
      /**
      * 判断参数引用对象是否有非空值,如为空值,返回false, 反之true
      */
    present: function() {
      for (var i = 0; i < arguments.length; i++)
        if ($(arguments[i]).value == '') return false;
      return true;
    },
    /**
      * 使选中参数引用对象
      */
    select: function(element) {
      $(element).select();
    },
    /**
      * 使参数引用对象处于可编辑状态
      */
    activate: function(element) {
      $(element).focus();
      $(element).select();
    }
    }
    /**
    * 表单工具类
    */
    var Form = {
    /**
      * 将表单元素序列化后的值(其实就是 name=value 形式的名值配对)组合成 QueryString 的形式
      */
    serialize: function(form) {
      var elements = Form.getElements($(form));
      var queryComponents = new Array();
     
      for (var i = 0; i < elements.length; i++) {
        var queryComponent = Form.Element.serialize(elements[i]);
        if (queryComponent)
        queryComponents.push(queryComponent);
      }
     
      return queryComponents.join('&');
    },
    /**
      * 得到表单的所有元素对象
      */
    getElements: function(form) {
      var form = $(form);
      var elements = new Array();

      for (tagName in Form.Element.Serializers) {
        var tagElements = form.getElementsByTagName(tagName);
        for (var j = 0; j < tagElements.length; j++)
        elements.push(tagElements[j]);
      }
      return elements;
    },
    /**
      * 根据 type 和 name 过滤得到表单中符合的 <input> 对象
      */
    getInputs: function(form, typeName, name) {
      var form = $(form);
      var inputs = form.getElementsByTagName('input');
     
      if (!typeName && !name)
        return inputs;
       
      var matchingInputs = new Array();
      for (var i = 0; i < inputs.length; i++) {
        var input = inputs[i];
        if ((typeName && input.type != typeName) ||
          (name && input.name != name))
        continue;
        matchingInputs.push(input);
      }

      return matchingInputs;
    },
    /**
      * 将指定表单的元素置于不可用状态
      */
    disable: function(form) {
      var elements = Form.getElements(form);
      for (var i = 0; i < elements.length; i++) {
        var element = elements[i];
        element.blur();
        element.disabled = 'true';
      }
    },
    /**
      * 将指定表单的元素置于可用状态
      */
    enable: function(form) {
      var elements = Form.getElements(form);
      for (var i = 0; i < elements.length; i++) {
        var element = elements[i];
        element.disabled = '';
      }
    },
    /**
      * 使表单的第一个非 hidden 类型而且处于可用状态的元素获得焦点
      */
    focusFirstElement: function(form) {
      var form = $(form);
      var elements = Form.getElements(form);
      for (var i = 0; i < elements.length; i++) {
        var element = elements[i];
        if (element.type != 'hidden' && !element.disabled) {
        Field.activate(element);
        break;
        }
      }
    },
    /*
      * 重置表单
      */
    reset: function(form) {
      $(form).reset();
    }
    }
    /**
    * 表单元素工具类
    */
    Form.Element = {
    /**
      * 返回表单元素的值先序列化, 其实就是 name=value 形式的名值配对
      */
    serialize: function(element) {
      var element = $(element);
      var method = element.tagName.toLowerCase();
      var parameter = Form.Element.Serializers[method](element);
     
      if (parameter)
        return encodeURIComponent(parameter[0]) + '=' +
        encodeURIComponent(parameter[1]);            
    },
    /**
      * 返回表单元素的值
      */
    getValue: function(element) {
      var element = $(element);
      var method = element.tagName.toLowerCase();
      var parameter = Form.Element.Serializers[method](element);
     
      if (parameter)
        return parameter[1];
    }
    }
    /**
    * prototype 的所谓序列化其实就是将表单的名字和值组合成一个数组
    */
    Form.Element.Serializers = {
    input: function(element) {
      switch (element.type.toLowerCase()) {
        case 'submit':
        case 'hidden':
        case 'password':
        case 'text':
        return Form.Element.Serializers.textarea(element);
        case 'checkbox':
        case 'radio':
        return Form.Element.Serializers.inputSelector(element);
      }
      return false;
    },
    /**
      * 单/多选框 由此方法处理序列化
      */
    inputSelector: function(element) {
      if (element.checked)
        return [element.name, element.value];
    },
    /**
      * textarea 由此方法处理序列化
      */
    textarea: function(element) {
      return [element.name, element.value];
    },
    /**
      * select 下拉列表由此方法处理序列化
      */
    select: function(element) {
      var value = '';
      if (element.type == 'select-one') {
        var index = element.selectedIndex;
        if (index >= 0)
        value = element.options[index].value || element.options[index].text;
      } else {
    /**
        * 支持 select-mulitple 的下拉列表,返回的数组的第二个元素,是一个值数组
        */
        value = new Array();
        for (var i = 0; i < element.length; i++) {
        var opt = element.options[i];
        if (opt.selected)
          value.push(opt.value || opt.text);
        }
      }
      return [element.name, value];
    }
    }
    /**
    * Form.Element.getValue 会经常用到,所以做了一个快捷引用
    * 取得某个表单控件的值,可以简化调用为 $F("username"),真是方便啊
    */
    var $F = Form.Element.getValue;
    /**
    * Abstract.TimedObserver 也没有用 Class.create() 来创建,和Ajax.Base 意图应该一样
    * Abstract.TimedObserver 顾名思义,是套用Observer设计模式来跟踪指定表单元素,
    * 当表单元素的值发生变化的时候,就执行回调函数
    *
    * 我想 Observer 与注册onchange事件相似,不同点在于 onchange 事件是在元素失去焦点的时候才激发。
    * 同样的与 onpropertychange 事件也相似,不过它只关注表单元素的值的变化,而且提供timeout的控制。
    *
    * 除此之外,Observer 的好处大概就在与更面向对象,另外可以动态的更换回调函数,这就比注册事件要灵活一些。
    * Observer 应该可以胜任动态数据校验,或者多个关联下拉选项列表的连动等等
    *
    */
    Abstract.TimedObserver = function() {}

    /**
    * 这个设计和 PeriodicalExecuter 一样,bind 方法是实现的核心
    */
    Abstract.TimedObserver.prototype = {
    initialize: function(element, frequency, callback) {
      this.frequency = frequency;
      this.element   = $(element);
      this.callback = callback;
     
      this.lastValue = this.getValue();
      this.registerCallback();
    },


    registerCallback: function() {
      setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
    },

    onTimerEvent: function() {
      var value = this.getValue();
      if (this.lastValue != value) {
        this.callback(this.element, value);
        this.lastValue = value;
      }
    }
    }

    /**
    * Form.Element.Observer 监视指定表单域的值是否变化
    */
    Form.Element.Observer = Class.create();
    Form.Element.Observer.prototype = (new Abstract.TimedObserver()).extend({
    getValue: function() {
      return Form.Element.getValue(this.element);
    }
    });

    /**
    * Form.Element.Observer 监视指定表单所有控件的值是否有变化
    */
    Form.Observer = Class.create();
    Form.Observer.prototype = (new Abstract.TimedObserver()).extend({
    getValue: function() {
      return Form.serialize(this.element);
    }
    });

    /*--------------------------------------------------------------------------*/

    /**
    * EventObserver 相比上面的 TimedObserver,是更具主动性的一种监测
    * 它直接为表单控件(根据 type 的不同) 注册相应的事件处理, 只要发现某个控件值发生改变,就执行回调函数
    */
    Abstract.EventObserver = function() {}
    Abstract.EventObserver.prototype = {
    initialize: function(element, callback) {
      this.element = $(element);
      this.callback = callback;
     
      this.lastValue = this.getValue();
      if (this.element.tagName.toLowerCase() == 'form')
        this.registerFormCallbacks();
      else
        this.registerCallback(this.element);
    },

    onElementEvent: function() {
      var value = this.getValue();
      if (this.lastValue != value) {
        this.callback(this.element, value);
        this.lastValue = value;
      }
    },

    registerFormCallbacks: function() {
      var elements = Form.getElements(this.element);
      for (var i = 0; i < elements.length; i++)
        this.registerCallback(elements[i]);
    },

    registerCallback: function(element) {
      if (element.type) {
        switch (element.type.toLowerCase()) {
        /**
        * checkbox 和 radio 类型的控件注册 onclick 事件处理
        */
        case 'checkbox':
        case 'radio':
          element.target = this;
          element.prev_onclick = element.onclick || Prototype.emptyFunction;
        /**
          * 相信这里有改进的空间,应该使用其后的 Event对象提供的注册管理功能来统一注册
          */
          element.onclick = function() {
            this.prev_onclick();
            this.target.onElementEvent();
          }
          break;

        /**
        * 其他类型的控件注册 onchange 事件处理
        */
        case 'password':
        case 'text':
        case 'textarea':
        case 'select-one':
        case 'select-multiple':
          element.target = this;
          element.prev_onchange = element.onchange || Prototype.emptyFunction;
          element.onchange = function() {
            this.prev_onchange();
            this.target.onElementEvent();
          }
          break;
        }
      }  
    }
    }

    /**
    * 监视指定表单控件
    */
    Form.Element.EventObserver = Class.create();
    Form.Element.EventObserver.prototype = (new Abstract.EventObserver()).extend({
    getValue: function() {
      return Form.Element.getValue(this.element);
    }
    });

    /**
    * 监视指定表单所有控件
    */
    Form.EventObserver = Class.create();
    Form.EventObserver.prototype = (new Abstract.EventObserver()).extend({
    getValue: function() {
      return Form.serialize(this.element);
    }
    });

    /**
    * 封装事件处理的静态工具对象
    */
    if (!window.Event) {
    var Event = new Object();
    }

    Object.extend(Event, {
    KEY_BACKSPACE: 8,
    KEY_TAB:     9,
    KEY_RETURN:   13,
    KEY_ESC:     27,
    KEY_LEFT:   37,
    KEY_UP:     38,
    KEY_RIGHT:   39,
    KEY_DOWN:   40,
    KEY_DELETE:   46,

    element: function(event) {
      return event.target || event.srcElement;
    },

    isLeftClick: function(event) {
      return (((event.which) && (event.which == 1)) ||
            ((event.button) && (event.button == 1)));
    },
    /**
      * click事件时鼠标以页面为基准的x坐标值, 考虑到了滚动条导致的位移差
      */
    pointerX: function(event) {
      return event.pageX || (event.clientX +
        (document.documentElement.scrollLeft || document.body.scrollLeft));
    },
    /**
      * click事件时鼠标以页面为基准的y坐标值, 考虑到了滚动条导致的位移差
      */
    pointerY: function(event) {
      return event.pageY || (event.clientY +
        (document.documentElement.scrollTop || document.body.scrollTop));
    },
    /**
      * 停止冒泡(参见 http://www.quirksmode.org/js/events_order.html) 和阻止浏览器执行与事件相关的默认动作
      * 比如
      * <a href="http://www.google.com" onclick="Event.stop(event);">google</a>
      * 那么点击该连接,页面并不会执行转向
      */
    stop: function(event) {
      if (event.preventDefault) {
        event.preventDefault();
        event.stopPropagation();
      } else {
        event.returnValue = false;
      }
    },
    // find the first node with the given tagName, starting from the
    // node the event was triggered on; traverses the DOM upwards
    /**
      * 找到事件元素的父级元素中,最接近事件元素且等同于指定标签名的父元素。
      * 如果到达顶级元素(HTML),那么就返回顶级元素
      */
    findElement: function(event, tagName) {
      var element = Event.element(event);
      while (element.parentNode && (!element.tagName ||
        (element.tagName.toUpperCase() != tagName.toUpperCase())))
        element = element.parentNode;
      return element;
    },
    /**
      * 其后的代码封装了事件的注册和反注册,避免ie的内存泄露的bug
      * 参见 http://javascript.weblogsinc.com/entry/1234000267034921/
      */
    observers: false,
      /**
      * this.observers 的数据格式是一个二维数组,二维的数组分别四个元素分别是
      * [注册事件对象,事件名,事件处理函数,事件处理模式布尔值]
      */
    _observeAndCache: function(element, name, observer, useCapture) {
      if (!this.observers) this.observers = [];
      if (element.addEventListener) {
        this.observers.push([element, name, observer, useCapture]);
        element.addEventListener(name, observer, useCapture);
      } else if (element.attachEvent) {
        this.observers.push([element, name, observer, useCapture]);
        element.attachEvent('on' + name, observer);
      }
    },

    unloadCache: function() {
      if (!Event.observers) return;
      for (var i = 0; i < Event.observers.length; i++) {
      /**
        * 这里与 Ajax.Request 对象设置 request header 的代码异曲同工
        */
        Event.stopObserving.apply(this, Event.observers[i]);
        Event.observers[i][0] = null;
      }
      Event.observers = false;
    },
    /**
      * 注册对象的事件处理,并记录到cache中
      */
    observe: function(element, name, observer, useCapture) {
      var element = $(element);
      useCapture = useCapture || false;
     
      if (name == 'keypress' &&
        ((navigator.appVersion.indexOf('AppleWebKit') > 0)
        || element.attachEvent))
        name = 'keydown';
     
      this._observeAndCache(element, name, observer, useCapture);
    },

    /**
      * 取消对象已注册的事件处理
      */
    stopObserving: function(element, name, observer, useCapture) {
      var element = $(element);
      useCapture = useCapture || false;
     
      if (name == 'keypress' &&
        ((navigator.appVersion.indexOf('AppleWebKit') > 0)
        || element.detachEvent))
        name = 'keydown';
     
      if (element.removeEventListener) {
        element.removeEventListener(name, observer, useCapture);
      } else if (element.detachEvent) {
        element.detachEvent('on' + name, observer);
      }
    }
    });
    /* prevent memory leaks in IE */
    /**
    * 页面onload 的时候取消所有事件注册,避免ie内存泄漏的bug
    */
    Event.observe(window, 'unload', Event.unloadCache, false);
    /**
    * Position 对象也是常用的工具类,提供了获取元素在页面上位置的函数,Drag&Drop的效果一定常会用到
    * 具体的应用参考 script.aculo.us 基于prototype 的实现,尤其是dragdrop.js。
    */
    var Position = {

    // set to true if needed, warning: firefox performance problems
    // NOT neeeded for page scrolling, only if draggable contained in
    // scrollable elements
    includeScrollOffsets: false,

    // must be called before calling withinIncludingScrolloffset, every time the
    // page is scrolled
    prepare: function() {
      this.deltaX = window.pageXOffset
              || document.documentElement.scrollLeft
              || document.body.scrollLeft
              || 0;
      this.deltaY = window.pageYOffset

              || document.documentElement.scrollTop
              || document.body.scrollTop
              || 0;
    },

    /**
      * 当对象所处的页面有滚动条是,计算位移
      */
    realOffset: function(element) {
      var valueT = 0, valueL = 0;
      do {
        valueT += element.scrollTop || 0;
        valueL += element.scrollLeft || 0;
        element = element.parentNode;
      } while (element);
      return [valueL, valueT];
    },

    /**
      * 计算出对象在页面上的位置
      */
    cumulativeOffset: function(element) {
      var valueT = 0, valueL = 0;
      do {
        valueT += element.offsetTop || 0;
        valueL += element.offsetLeft || 0;
        element = element.offsetParent;
      } while (element);
      return [valueL, valueT];
    },

    // caches x/y coordinate pair to use with overlap
    /**
      * 判断一个坐标是否在指定元素的空间范围中
      * 比如你想判断鼠标点击点的坐标是否在某个层或窗口
      */
    within: function(element, x, y) {
      if (this.includeScrollOffsets)
        return this.withinIncludingScrolloffsets(element, x, y);
      this.xcomp = x;
      this.ycomp = y;
      this.offset = this.cumulativeOffset(element);
      return (y >= this.offset[1] &&
            y < this.offset[1] + element.offsetHeight &&
            x >= this.offset[0] &&
            x < this.offset[0] + element.offsetWidth);
    },
    withinIncludingScrolloffsets: function(element, x, y) {
      var offsetcache = this.realOffset(element);
      this.xcomp = x + offsetcache[0] - this.deltaX;
      this.ycomp = y + offsetcache[1] - this.deltaY;
      this.offset = this.cumulativeOffset(element);
      return (this.ycomp >= this.offset[1] &&
            this.ycomp < this.offset[1] + element.offsetHeight &&
            this.xcomp >= this.offset[0] &&
            this.xcomp < this.offset[0] + element.offsetWidth);
    },
    // within must be called directly before
    /**
      * 调用该方法时,确保首先调用了within方法
      * 如果x,y坐标位于element的空间范围中,那么返回一个小于1的标示位置的值,比如0.5标示该坐标位于element空间的中线上
      */
    overlap: function(mode, element) {
      if (!mode) return 0;
      if (mode == 'vertical')
        return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
        element.offsetHeight;
      if (mode == 'horizontal')
        return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
        element.offsetWidth;
    },
    /**
      * 复制源对象的空间数据到目的对象。
      * 常用的地方:拖缀一个层到新地方时,常常动态构造和该层同样大小的虚层。
      */
    clone: function(source, target) {
      source = $(source);
      target = $(target);
      target.style.position = 'absolute';
      var offsets = this.cumulativeOffset(source);
      target.style.top   = offsets[1] + 'px';
      target.style.left   = offsets[0] + 'px';
      target.style.width = source.offsetWidth + 'px';
      target.style.height = source.offsetHeight + 'px';
    }
    }

    http://3rgb.com/b/?act=viewthread&threadid=407


     发表于 22:36:19  阅读全文  |  评论(1)  |  Trackback(0)  | 编辑
     
    2006-01-25
    Tag:VC 风险投资

    创业者融资指南――与风险投资者会面之前应该做哪些准备工作?

     

    有些创业者并不熟悉如何向机构投资者进行融资来发展事业。创业者一般用个人投资来组建公司,并且支持随后的公司发展计划,这些个人投资可以来自公司创立者自己、朋友、家庭等,有时也来自银行或者政府。

     

    风险投资现在是一种越来越重要的融资方式,特别是在高科技公司这样的高成长性行业。但不幸的是,许多创业者并不知道如何与机构投资者打交道,如何向他们介绍一个投资机会,也不知道从他们那里除了获得融资之外还能获得些什么。

     

    在开始一项投资的分析和谈判阶段,创业者通常对风险投资者的情况会有很多问题。为了解释清楚风险投资者如何进行投资的工作方式,本文整理出一个清单和相应的说明,这个清单不一定完整,但是对创业者会有一些指导,以帮助他们如何准备投资建议书,以及如何与风险投资者打交道。

     

    在投资过程中的关键问题和步骤包括如下:

    向风险投资进行融资的目的是为了发展一个商业机会。

    站在投资者的角度考虑问题,并对自己的投资建议书提出批评。

    了解你的听众。

    准备好一份商业计划书(business plan),以及一份执行摘要(executive summary)。

    对自己的商业机会进行估值,并准备好谈判底线。

    融资有成本的,要花费时间和金钱。

    可能会需要有经验的法律帮助。

    准备好做路演。

    准备好开始谈判,并且对你的公司进行外部审查。

    准备好公司治理结构的改变。

    理解创业者、首席执行官(CEO),以及股东之间的区别。


     

    向风险投资进行融资的目的是为了发展一个商业机会。

     

    为一个新项目融资有很多方法。银行对于紧急的资金需求来说,有时是个很好的选择,但是融资成本比较昂贵。如果创业者能够提供实际的担保,比如固定资产或者应收款项,银行才有可能借钱给创业者。

     

    而风险投资者不同。他们获得来自第三方的资本,承受适当的风险,投资给高成长性的商业机会和公司,当这些公司在市场上获得成功时有公司规模可能扩张好多倍,从而当资本能够流动性的时候就能使初始投资获得非常吸引人的回报。风险投资通常不需要担保,但是需要签订保护性条款,并且需要创业者分一部分公司管理权给风险投资。不要期望获得免费的资本,融资通常都需要付出成本。

     

    站在投资者的角度考虑问题,并对自己的投资建议书提出批评。

     

    投资者选择投资建议书时脑子里通常至少有3个关键要素:一个强大的管理团队、一个在快速发展的市场和行业中的好公司、以及一个清晰的未来愿景。所以创业者在敲开潜在投资者的门之前最好做好准备能够证明这3个关键要素。

     

    风险投资者可能还会问几个关键问题。是否同时在找其它投资者?团队对于公司发展的愿景是否意见一致?是否能够建立需要的销售渠道?是否有明确的计划来达到目标?需要从投资者这里获得什么?需要钱用于什么?这个过程需要创业者在向机构投资者提出融资申请之前做好准备工作。

     

    有很多工具能够创业者帮助回答这些问题,因此最好在与投资者交谈之前就试着回答好这些问题。还有很多信息和参考书指导创业者如何写出有条理的商业计划书,在互联网上做个简单的搜索就可以搜出这些信息。记住,投资者每天都分析无数计划书,他们手上会有很多类似的项目。为什么要选你的,而不是别人更有条理的计划书?

     

    了解你的听众。

     

    一个好的商业机会总能找到投资者。有很多基金和个人都愿意投资于好的商业机会。但也并不是所有投资者都愿意这样做。根据对交易和风险方面的不同偏好,投资者有很多不同类型,包括:朋友和家庭的资金、天使投资者、政府种子资金、早期风险投资、后期风险投资、私有股权投资等。


     

    另外根据风险投资公司与其资产组合中公司打交道的方式,投资者也可被不同类型。有些风险投资公司在这方面非常主动,会介入其资产组合中公司的日常决策,帮助建立关系网、销售、以及财务。另一些风险投资公司与其资产组合中公司联系很少,对公司运营尽量少进行干涉。一般来说,后一种倾向于投资于较多的项目,而较少关注每个项目公司的运营问题。对于创业者来说,预先了解潜在投资者的情况,以及是哪种类型,是很重要的。

     

    准备好一份商业计划书(business plan),以及一份执行摘要(executive summary)。

     

    融资的第一步应该是与潜在投资者建立联系。现在你已经瞄准了一个行业,并且知道了谁会对你的建议书感兴趣,下面要做的就是联系他们。你手上必须要有一份关于你公司的执行摘要,主要内容应该包括:这个商业机会的要点(你做什么)、市场细分(你的客户是谁)、以及为什么你会成功(你相对竞争对手有什么优势)。执行摘要通常是个四页(或者更少)的文件,不包括任何保密内容,可以通过电子邮件发给潜在投资者。

     

    执行摘要应该同时也是商业计划书的前两页,用来给读者一个指引。一份商业计划书应该描述公司的整个发展策略,包括:管理团队、市场策略、产品定义、竞争环境、投资计划、现金需求等。商业计划书不需要100页那么长,但是必须内容丰富,并且明确说明你的竞争优势。

     

    在商业计划书里面,你需要解释清楚这个商业机会是什么,你将给市场提供什么样的解决方案,你将如何执行你的策略,以及你为什么会成功。图片、数据、表格可以帮助你表达你的观点。

     

    商业计划书里面最重要的部分是财务预测。投资者在寻找成长性机会,但是不代表会盲目的夸大对成长性的期望。风险投资者通常会做出资金的预测,与你的数字进行对比,因此你需要做好资金的预测,并且准备好用事实回答他们将提出的问题。

     

    保证你的商业计划书具有严密性的一种很好的方式是:按照自底向上的方式来组织计划书(从你手头的资源推导出潜在的收入),并且按照自顶向下的方式来怀疑计划书(从整个目标市场规模推导出你的市场份额)。这种方式将使计划书有一种逻辑上的严密性。

     

    商业计划书的预测将会在谈判中被使用,并且将会投资之后的业务目标指导。创业者,作为公司管理者,将会按照这个预算下达到的业绩来被评价。

     

    请注意在收到任何机密信息之前,可以签一个保密协议。你当然不希望你的商业计划书被提供给第三方,用这种法律保证的方式,你可以保护自己的权利。。

     

    关于商业计划书,做好准备回答投资者下面这些问题:

     管理团队:介绍你的团队,背景和工作经验。

     预测:结合现在的情况,对未来五年的预测。

     客户:谁使你现在的客户?

     商业模式:你如何销售,以什么价格?你的目标市场细分?

     主要竞争对手:谁是你的目标行业细分中的主要玩家?

     策略和战术:你为什么会成功。你的差异化是什么?

     收益的使用:解释如何使用融来的资金。

     投资者:谁是本轮投资的其它投资者?

     

    对自己的商业机会进行估值,并准备好谈判底线。

     

    投资者用来对潜在交易进行估值的技术没有多少变化。你应该自己预先做好准备,给你的公司估值。这将会避免因为你和投资者的期望不同而导致的没完没了的谈判。投资者通常使用比较法来对你的公司进行估值,也就是说用类似公司的价值作为参考,(这里的类似公司是相同细分市场里面的公司,如果是公开上市公司就用其市值,或者用被并购时的交易价值)。另一种常用的估值方法是现金流预测折扣法,每个投资者都有自己的风险因子,用来作为在这一方法中折扣。你可以自己先用这些方法来估算一下。

     

    通常有这样一个误解:开始的时候先做一个较高的估值来申请融资,之后才能够达成一个适中的协议价值。这样做通常会使你失去很多潜在投资者,因为他们会认为这么高的一个估值,与自己的期望值相差太大,很难达成协议。所以比较好的方法是:开一个你认为是合适的价格,然后坚持住这个价格。一般来说这个价格已经会高于投资者的心理价位了,因为创业者与财务投资者所感受到的风险往往是不同的。

     

    融资有成本的,要花费时间和金钱。

     

    与互联网泡沫高点时期相比,现在的投资者会花费更多的时间在项目考察过程上,包括:与客户交谈、做背景调查、访问目标公司、寻找外部推荐人等。成功的项目通常一轮考察要持续大约4个月,有时甚至要长达1年。

     

    许多投资者由投资委员会来做出批准决定,在交易的不同阶段,只有获得批准通过,交易团队才能继续进行下一步。下面是两个这种批准的例子:第一个批准通常发生在初始调查结束之后,但是在投资者拿出投资条款表(term sheet)之前;第二个批准通常发生在谈判之后,以及各方开始交流最终合同文件草案之前。在这两次对批准进行审核的委员会会议上(或者甚至进行调查之中),交易都可能被终止。

     

    创业公司应该明白他们的所有花费都是为了融到资金,因此所有法律、审计、以及其它费用都将由创业公司支付。交易费用通常也由创业公司来支付。然而,如果交易没有成功,或者服务提供者是由风险投资者雇用的,费用也可能会由投资者来支付。

     

    可能会需要有经验的法律帮助。

     

    律师将会帮助创业者与潜在投资者的法律代表打交道。你和律师的交流和合作将帮助你更好的融到自己。当雇用你的律师时,需要确保他有很强的公司法律专业知识,最好是以前有过风险投资交易方面的经验。同时,律师的专业建议对于保护你的知识产权也很重要。

     

    尽管投资者往往强调法律帮助的重要性,创业者应该自己和投资者谈好商业方面的问题(估值、股权分配、资产流动性偏好等)。这种谈判产生的文件被称为投资条款表(term sheet)。这个投资条款表背后的思想就是用简单的语言描述交易各方的权利和义务。一旦你与投资者达成了协议,律师的任务就是确认投资条款表中的所有条款完整表达了你们的协议,然后以法律文件的形式写出来。投资条款表是写这些文件草案的指导书,因此是比较简化的,实际的交易文件将包括各方的权利和义务方面的更多细节。

     

    准备好做路演。

     

    接下来就是实际的融资了,准备好与投资者的见面。你必须就你的商业计划书做演讲,参加会议、并且介绍将和你一起执行这个项目的团队。记住,团队中的某个人将作为随后融资过程的领导者,通常公司创立者中的一个将作为首席执行官(CEO),或者首席财务官(CFO),花费很多时间来做融资工作(通常是其100%的时间)。你也许必须重复几十次讲你们的故事,但是这些时间花的值得。保持乐观和主动,如果你不知道什么时候,不要回避,就说你不知道好了,也不要过度的推销你的投资建议书。

     

    准备好开始谈判,并且对你的公司进行外部审查。

     

    拿着你的商业计划书,并且经过一些讨论之后,投资者会拿出一个投资条款表出来,上面写了些他们需要的条款,从而可以继续下面的投资过程。一般来说对于这个投资条款表,可以有一段时间让双方来谈判,继续对投资条款表进行更新,从而达成一致,最后形成一个最终版本。

     

    一旦每个人都同意了这些条款,尽职审查的过程就开始了。如果你已经准备好了相关的合同文件,并且更新了所有法律和税务文件,这个过程可以被大大加快。许多公司准备好一份尽职审查书,以及所有需要的文件的一份拷贝,当投资者需要时就提供给他,这样做可以表现出一种专业性的沟通方式。有时需要雇用独立的审计师和律师,通常由创业公司支付其费用,用来评估所有的公司潜在负债(人事、税务等方面)。这些分析中如果由对公司不利的结果,一般通过谈判的方式进行沟通,尽可能减少对现有投资者产生负债的影响,

     

     

    准备好公司治理结构的改变。

     

    如果这是你第一次把你的公司所有权分配给别人,你需要意识到:即使你仍然持有大多数股份,投资者通常也将会对公司治理结构和透明度做重大的调整。现在公司创立者是在为股东工作了,而不仅仅是为自己。

     

    投资者会试图构造一个平衡的董事会,他们能够充分的发表观点和获取信息。他们会要求得到董事会席位,并建立某种特权,从而保证能做关键的决策,或者对某些事务具有否决权。这些做法的理念就是为了当公司策略发生改变,但其没有董事会多数席位时,能够保护其投资权益,记住是你在过去做了一个商业计划书,而所有投资者都批准了你的计划,并决定给了你投资,现在你该保证他们的权益了。

     

    理解创业者、首席执行官(CEO),以及股东之间的区别。

     

    创业者和CEO之间有重要区别,在刚开始的时候确实比较难注意到,但随着时间的流逝,公司决策将不再会基于简单的创业冲动,而变得越来越结构化和流程化,并且需要各个股东的批准。

     

    通常好的创业者做决策很快,有点倾向于把决策权集中在自己手里。这在商业发展的早期当然是至关重要的,但是当公司成熟之后,这将会危害一个健全公司的发展。发展到一定阶段,就需要一个CEO,由董事授权来管理公司,同时向董事会汇报工作。有时在公司发展过程中,公司创立者也可能离开管理岗位,这些情况下,创立者仍然会通过董事会来介入决策制定,而把日常管理交给专业管理团队。

     

    同样很重要的是需要理解:虽然股东对于公司发展有着同样的利益,但是他们应该较少接入公司日常运营。他们必须给执行管理团队充分的自由度和授权来执行商业计划。

     

    最后一点:融资仅仅是一个开始。目标是发展和开拓一个商业机会,从而能够为股东创造出很高的价值。资金仅仅是成功方程式的一个部分,关键的是:建立一个有着同样愿景理念的团队,然后向着这个愿景开展有效的工作。这一点不光对雇员是这样要求,寻找谁来投资的时候也需要这样要求,要确保投资者有相同的愿景和价值观,并且能够真正帮助发展你的公司。

     


     发表于 15:44:43  阅读全文  |  评论(1)  |  Trackback(0)  | 编辑
     
    2006-01-16
    Tag:Java Blog

    收集了一些基于Java的Blog系统,有时间再研究。

    Roller:http://www.rollerweblogger.org/page/project

    国外运用想当广泛的一套BLOG系统。


    DLOG4J: http://dlog4j.sourceforge.net/

    国人开发的,已经申报SourceForge项目 中文官方站: http://www.javayou.com


    TM: http://www.terac.com

    http://blog.xintiantang.com/andy/


     发表于 11:32:16  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2006-01-11
    Tag:WMP MediaPlayer JavaScript Realone

    常用网页播放器代码
    我们在网页上看到的播放器无外乎WMP/RealOne/Macromedia Flash Player,其他的无非是面板不同,或者添加了其他控件,对于计算机上安装的一些播放器也都是编码和解码器的整合,其最核心的编码和解码技术是相同的。例如:网络上最流行的windows media流(asf,wma,wmv格式...),Real流(rm,rmvb...),还有MPEG系列编码格式(MP4/MP3格式...)
    Windows Media Video 是微软推出的一种流媒体格式,它是在“同门”的ASF(Advanced Stream Format)格式升级延伸来得.在同等视频质量下,WMV格式的体积非常小,因此很适合在网上播放和传输。Windows Media Player9兼容所有格式的WMV,官方编码器是Windows Media Encoder ,但是如果你想转制 高质量的wmv文件,那您一定要有超大的内存来处理数据...
    无意中发现CASTPOST的播放器可以自己定义大小,对于WMV格式的在线播放可以说已经足够快了,然后就费了好大劲把一些精彩的短片和一些经典的MTV转化WMV格式放了上来,尽管现在不能下载了,但是只要不是连接人数过多,播放起来还是很流畅的^_^
     
    WMP加入了ActiveX解码器控件,不仅可以放曲子,还能放Flash和其它视频文件 
    <object align=middle classid="CLSID:22d6f312-b0f6-11d0-94ab-0080c74c7e95" class=OBJECT id=MediaPlayer width=196 height=196>
         <param name=ShowStatusBar value=0>
           <param name=Filename value="http://202.116.*.*/video/story/chinese/hynh/b.wmv">
            <embed type=application/x-oleobject codebase="http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701" >
         </embed>
    </object>
     想用WMP连续播放请参照ASX元文件使用讲解:使用ASX播放列表吧

    上面的这个播放器是老式的那种,***版本!新式播放器是在MediaPlayer9.0以后出现的,也就是说只有装了9.0或9.0以上的播放器才能正常使用的。


    下面是新式播放器代码,相对以前的来说要简单很多:
    <object id="player" height="64" width="260" classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6">
        <param NAME="AutoStart" VALUE="-1">
        <!--是否自动播放-->
        <param NAME="Balance" VALUE="0">
        <!--调整左右声道平衡,同上面旧播放器代码-->
        <param name="enabled" value="-1">
        <!--播放器是否可人为控制-->
        <param NAME="EnableContextMenu" VALUE="-1">
        <!--是否启用上下文菜单-->
        <param NAME="url" value="/blog/1.wma">
        <!--播放的文件地址-->
        <param NAME="PlayCount" VALUE="1">
        <!--播放次数控制,为整数-->
        <param name="rate" value="1">
        <!--播放速率控制,1为正常,允许小数,1.0-2.0-->
        <param name="currentPosition" value="0">
        <!--控件设置:当前位置-->
        <param name="currentMarker" value="0">
        <!--控件设置:当前标记-->
        <param name="defaultFrame" value="">
        <!--显示默认框架-->
        <param name="invokeURLs" value="0">
        <!--脚本命令设置:是否调用URL-->
        <param name="baseURL" value="">
        <!--脚本命令设置:被调用的URL-->
        <param name="stretchToFit" value="0">
        <!--是否按比例伸展-->
        <param name="volume" value="50">
        <!--默认声音大小0%-100%,50则为50%-->
        <param name="mute" value="0">
        <!--是否静音-->
        <param name="uiMode" value="mini">
        <!--播放器显示模式:Full显示全部;mini最简化;None不显示播放控制,只显示视频窗口;invisible全部不显示-->
        <param name="windowlessVideo" value="0">
        <!--如果是0可以允许全屏,否则只能在窗口中查看-->
        <param name="fullScreen" value="0">
        <!--开始播放是否自动全屏-->
        <param name="enableErrorDialogs" value="-1">
        <!--是否启用错误提示报告-->
        <param name="SAMIStyle" value>
        <!--SAMI样式-->
        <param name="SAMILang" value>
        <!--SAMI语言-->
        <param name="SAMIFilename" value>
        <!--字幕ID-->
    </object>


    RealOne播放器代码:
    <object id="vid" classid="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA" width=427 height=300>
    <param name="_ExtentX" value="11298">
    <param name="_ExtentY" value="7938">
    <param name="AUTOSTART" value="-1">
    <param name="SHUFFLE" value="0">
    <param name="PREFETCH" value="0">
    <param name="NOLABELS" value="-1">
    <param name="SRC" value="rtsp://211.89.225.1/encoder/cnr3";>
    <param name="CONTROLS" value="Imagewindow">
    <param name="CONSOLE" value="clip1">
    <param name="LOOP" value="0">
    <param name="NUMLOOP" value="0">
    <param name="CENTER" value="0">
    <param name="MAINTAINASPECT" value="0">
    <param name="BACKGROUNDCOLOR" value="#000000">
    </object> <object id="vid2" classid="clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA" width=427 height=30>
    <param name="_ExtentX" value="11298">
    <param name="_ExtentY" value="794">
    <param name="AUTOSTART" value="-1">
    <param name="SHUFFLE" value="0">
    <param name="PREFETCH" value="0">
    <param name="NOLABELS" value="-1">
    <param name="SRC" value="rtsp://211.89.225.1/encoder/cnr3";>
    <param name="CONTROLS" value="ControlPanel">
    <param name="CONSOLE" value="clip1">
    <param name="LOOP" value="0">
    <param name="NUMLOOP" value="0">
    <param name="CENTER" value="0">
    <param name="MAINTAINASPECT" value="0">
    <param name="BACKGROUNDCOLOR" value="#000000">
    </object>
     
    看着很多很复杂的样子,其实就是多了些播放器参数,可以不要...

    Real Player 网页播放器 参数含义

    参数:autostart 属性:True或是False 作用:指定是否自动播放指定的源文件
    参数:backgroundcolor 属性:任何用符号“#”开头的16进制数值或是任何预定义的颜色作用:指定图像窗口的背景颜色
    参数:center 属性:True或是False 作用:指定片断使用初始编码大小播放,并且在图像窗口的中央。
    参数:classid 属性:"clsid:CFCDAA03-8BE4-1lcf-B84B0020AFBBCCFA:** 作用:用于指定ActiveX控件的唯一的字符串标示,可以认出嵌入的RealPalyer播放器。
    参数:console 属性:任何字符串作用:可以将各种不同的RealPlayer控制聚集在网页上,这样它们可以交互使用或是保持独立,而且互相不影响
    参数:controls 属性:ImageWindow,All,ControlPanel,PlavButton,PlayOnlyButton, PauseButton,StopButton,FFCtrl,RWCtrl,MuteCtrl,MuteVolume,VolumeSlider,PositionSlider,TACCtrl,HomeCtrl,InfoVolumePanel,InfoPanel,StatusBar,StatusField,PositionField 作用:可以让你指定那些控制是可见的。
    参数:height 属性:任何整数值作用:指定RealPlayer元素的高度,单位:像素
    参数:id 属性:任何字符串作用:为标签中的RealPlayer元素指定名字。
    参数:imagestatus 属性:True或是False 作用:指定是否在图像窗口中显示状态信息,默认值是true
    参数:loop 属性:True或是False 作用:可以让你指定片断是否无限循环
    参数:maintainaspect 属性:True或是False 作用:默认RealPlayer拉伸所有的片断来充满整个图像窗口。
    参数:name 属性:任何字符串作用:为标签中的RealPlayer元素指定名字(在标签中使用id)
    参数:nojava 属性:True或是False 作用:避免启动Java虚拟机
    参数:nolabels 属性:True或是False 作用:可以禁止显示标题或是版权信息(realplayer5.0以上时,它是垃圾...)
    参数:nologo 属性:True或是False 作用:避免RealPlayer启动时在图像窗口中显示
    参数:numloop 属性:任何整数值作用:让你能够指定文件片循环的次数,不需要参数loop
    参数:prefetch 属性:True或是False 作用:指定在播放前,RealPlayer是否可以获得流描述信息,默认值是False
    参数:region 属性:任何字符串作用:同SMIL一起使用。允许你指定使用HTML代替SMIL
    参数:scriptcallbacks 属性:用逗号分割的列表作用:指定浏览器的回调监控(好高级的东东!)
    参数:shuffle 属性:True或是False 作用:同多文件片的ram文件或是SMIL文件一起使用。可以让RealPlayer随机播放列表中的文件
    参数:src 属性:任何合法的相对或是完整的URL 作用:指定播放的文件或是源文件的地址
    参数:type 属性:字符串作用:为嵌入插件指定MIME类型
    参数:width 属性:任何整数值作用:指定RealPlayer元素的宽度

    RealPlayer的一些函数、方法和过程

    这是 Real Player ActiveX Control Library (Version 1.0) 的所有函数与方法,有兴趣可以研究一下。

    function GetSource: WideString;
    procedure SetSource(const lpszNewValue: WideString);
    function GetConsole: WideString;
    procedure SetConsole(const lpszNewValue: WideString);
    function GetControls: WideString;
    procedure SetControls(const lpszNewValue: WideString);
    function GetNoLabels: WordBool;
    procedure SetNoLabels(bNewValue: WordBool);
    function GetAutoStart: WordBool;
    procedure SetAutoStart(bNewValue: WordBool);
    function GetAutoGotoURL: WordBool;
    procedure SetAutoGotoURL(bNewValue: WordBool);
    function GetVolume: Smallint;
    procedure SetVolume(nVol: Smallint);
    function GetMute: WordBool;
    procedure SetMute(bMute: WordBool);
    function GetLoop: WordBool;
    procedure SetLoop(bVal: WordBool);
    function GetImageStatus: WordBool;
    procedure SetImageStatus(bEnable: WordBool);
    function GetPacketsTotal: Integer;
    function GetPacketsReceived: Integer;
    function GetPacketsOutOfOrder: Integer;
    function GetPacketsMissing: Integer;
    function GetPacketsEarly: Integer;
    function GetPacketsLate: Integer;
    function GetBandwidthAverage: Integer;
    function GetBandwidthCurrent: Integer;
    procedure DoPlayPause;
    procedure DoStop;
    procedure DoNextItem;
    procedure DoPrevItem;
    function CanPlayPause: WordBool;
    function CanStop: WordBool;
    function HasNextItem: WordBool;
    function HasPrevItem: WordBool;
    function HasNextEntry: WordBool;
    function HasPrevEntry: WordBool;
    procedure DoNextEntry;
    procedure DoPrevEntry;
    procedure AboutBox;
    procedure EditPreferences;
    procedure HideShowStatistics;
    function IsStatisticsVisible: WordBool;
    procedure DoGotoURL(const url: WideString; const target: WideString);
    procedure DoPlay;
    procedure DoPause;
    function GetPosition: Integer;
    function GetPlayState: Integer;
    function GetLength: Integer;
    function GetTitle: WideString;
    function GetAuthor: WideString;
    function GetCopyright: WideString;
    function GetClipWidth: Integer;
    function GetClipHeight: Integer;
    function CanPlay: WordBool;
    function CanPause: WordBool;
    procedure SetPosition(lPosition: Integer);
    function GetNumLoop: Integer;
    procedure SetNumLoop(lVal: Integer);
    function GetCenter: WordBool;
    procedure SetCenter(bVal: WordBool);
    function GetNoLogo: WordBool;
    procedure SetNoLogo(bVal: WordBool);
    function GetMaintainAspect: WordBool;
    procedure SetMaintainAspect(bVal: WordBool);
    function GetBackgroundColor: WideString;
    procedure SetBackgroundColor(const pVal: WideString);
    function GetStereoState: WordBool;
    function GetLiveState: WordBool;
    function GetShowStatistics: WordBool;
    procedure SetShowStatistics(bVal: WordBool);
    function GetShowPreferences: WordBool;
    procedure SetShowPreferences(bVal: WordBool);
    function GetShowAbout: WordBool;
    procedure SetShowAbout(bVal: WordBool);
    function GetOriginalSize: WordBool;
    procedure SetOriginalSize;
    function GetDoubleSize: WordBool;
    procedure SetDoubleSize;
    function GetFullScreen: WordBool;
    procedure SetFullScreen;
    function GetEnableContextMenu: WordBool;
    procedure SetEnableContextMenu(bVal: WordBool);
    function GetEnableOriginalSize: WordBool;
    procedure SetEnableOriginalSize(bVal: WordBool);
    function GetEnableDoubleSize: WordBool;
    procedure SetEnableDoubleSize(bVal: WordBool);
    function GetEnableFullScreen: WordBool;
    procedure SetEnableFullScreen(bVal: WordBool);
    function GetEnableMessageBox: WordBool;
    procedure SetEnableMessageBox(bVal: WordBool);
    procedure SetTitle(const pVal: WideString);
    procedure SetAuthor(const pVal: WideString);
    procedure SetCopyright(const pVal: WideString);
    function GetWantKeyboardEvents: WordBool;
    procedure SetWantKeyboardEvents(bWantsEvents: WordBool);
    function GetWantMouseEvents: WordBool;
    procedure SetWantMouseEvents(bWantsEvents: WordBool);
    function GetNumEntries: Smallint;
    function GetCurrentEntry: Smallint;
    function GetEntryTitle(uEntryIndex: Smallint): WideString;
    function GetEntryAuthor(uEntryIndex: Smallint): WideString;
    function GetEntryCopyright(uEntryIndex: Smallint): WideString;
    function GetEntryAbstract(uEntryIndex: Smallint): WideString;
    procedure SetCanSeek(bCanSeek: WordBool);
    function GetCanSeek: WordBool;
    function GetBufferingTimeElapsed: Integer;
    function GetBufferingTimeRemaining: Integer;
    function GetConnectionBandwidth: Integer;
    function GetPreferedLanguageString: WideString;
    function GetPreferedLanguageID: Integer;
    function GetUserCountryID: Integer;
    function GetNumSources: Smallint;
    function GetSourceTransport(nSourceNum: Smallint): WideString;
    function GetWantErrors: WordBool;
    procedure SetWantErrors(bVal: WordBool);
    function GetShuffle: WordBool;
    procedure SetShuffle(bVal: WordBool);
    function GetVersionInfo: WideString;
    function GetLastMessage: WideString;
    function GetLastErrorSeverity: Integer;
    function GetLastErrorRMACode: Integer;
    function GetLastErrorUserCode: Integer;
    function GetLastErrorUserString: WideString;
    function GetLastErrorMoreInfoURL: WideString;
    procedure SetPreFetch(bVal: WordBool);
    function GetPreFetch: WordBool;
    procedure SetRegion(const pVal: WideString);
    function GetRegion: WideString;
    function GetIsPlus: WordBool;
    function GetConsoleEvents: WordBool;
    procedure SetConsoleEvents(bVal: WordBool);
    function GetDRMInfo(const pVal: WideString): WideString;
    property ControlInterface: IRealAudio read GetControlInterface;
    property DefaultInterface: IRealAudio read GetControlInterface;


    网页中WMP视频控制之使用指南

    □播放方法和属性
        除播放、暂停、停止外,媒体播放器还可用下面的属性:
        扫描(Scanning)——与录像机的快进快倒功能类似;
        搜索(Seeking)——直接移到剪辑中标记的特定上演时间;

    □播放
        媒体播放器提供了两种技术来指定要播放的媒体名称(剪辑),你可以设置 FileName 属性,或调用 Open 方法。 如果 AutoStart 属性的值是 true 的话,当 FileName 属性被设置成该电影剪辑的 URL 后,该电影剪辑将开始播放;否则电影剪辑不会开始播放, 除非你调用 Play 方法。 Open 方法开始播放是异步的,它不象 Play 方法要等到其他的进程结束后才开始播放。
        媒体播放器提供了下面的类似录像机的属性和方法来控制流媒体的播放:
        Play、Stop、Pause 方法,来开始、停止、暂停流媒体。
        PlayCount 属性,设置文件播放的次数。
        AutoRewind 属性,确定当停止播放时是否返回到电影剪辑的开始部分。

    □音频控制
        媒体播放器提供了下面的属性来管理音频:
        Balance 属性,确定左右音箱的声音平衡;
        Volume 属性,用来加大或降低音量;
        Mute 属性,用来关闭或打开声音;
        ※你可以将 ShowAudioControls 属性设为 true 来在控制栏添加处理声音的控件。

    □扫描
        媒体播放器提供了下面的属性用以扫描:
        FastForward 方法,快进;
        FastReverse 方法,快倒;
        Rate属性,改变播放速率;
        ※要想使电影剪辑能被扫描,必须将 CanScan 和 AllowScan 属性设为 true。

    □搜索
        用于搜索的属性有:
        MarkerCount 属性,指剪辑中标记的总数量;
        CurrentMaker、GetMarkerName、GetMarkerTime 方法,用于返回标记信息;
        MarkerHit 事件,当遇到标记时触发;
        CurrentPosition 属性,当前位置(用秒度量),可用来将播放头移到剪辑中指定的点;
        PositionChange 事件,当设置 CurrentPosition 属性时触发;
        ※要想搜索到任意的时间,必须将 CanSeek 属性设为 true,要想搜索到标记点,必须将 CanSeekToMarkers 属性设为 true。

    □媒体播放器的外观界面
        在网页中,你可以通过相关属性来控制媒体播放器的哪些部分出现,哪些部分不出现。
    媒体播放器包括如下元素:
        Video Display Panel:视频显示面板;
        Video Border:视频边框;
        Closed Captioning Display Panel;字幕显示面板;
        Track Bar;搜索栏;
        Control Bar with Audio and Position Controls:带有声音和位置控制的控制栏;
        Go To Bar:转到栏;
        Display Panel:显示面板;
        Status Bar:状态栏;
        下面的属性用来决定显示哪一个元素:
        ShowControls 属性:是否显示控制栏(包括播放控件及可选的声音和位置控件);
        ShowAudioControls 属性:是否在控制栏显示声音控件(静音按钮和音量滑块);
        ShowPositionControls 属性:是否在控制栏显示位置控件(包括向后跳进、快退、快进、向前跳进、预览播放列表中的每个剪辑);
        ShowTracker 属性:是否显示搜索栏;
        ShowDisplay 属性:是否显示显示面板(用来提供节目与剪辑的信息);
        ShowCaptioning 属性:是否显示字幕显示面板;
        ShowGotoBar 属性:是否显示转到栏;
        ShowStatusBar 属性:是否显示状态栏;

    □播放列表
        媒体播放器提供下面的方法来访问播放列表中的剪辑:
        Next 方法,跳到节目(播放列表)中的下一个剪辑;
        Previous 方法,跳回到节目中的上一个剪辑;
        媒体播放器的一个特性是能够预览节目中的每一个剪辑,使用如下属性:
        PreviewMode 属性,决定媒体播放器当前是否处于预览模式;
        CanPreview 属性,决定媒体播放器能否处于预览模式;
        在windows 媒体元文件中,可以为每一个剪辑指定预览时间——PREVIEWDURATION,如果没有指定,那么默认的预览时间是10秒钟。
        你也可以用Windows 媒体元文件来添加 watermarks 与 banners,元文件也支持插入广告时的无间隙流切换。

    □节目信息
        使用 GetMediaInfoString 方法可以返回相关剪辑或节目的如下信息:
        文件名:File name
        标题:Title
        描述:Description
        作者:Author
        版权:Copyright
        级别:Rating
        URLs:logo icon、watermark、banner的地址
        剪辑信息可以放在媒体文件中,也可以放在Windows 媒体元文件中,或者两者都放。如果在元文件中指定了剪辑信息,那么用 GetMediaInfoString 方法返回的就是元文件中的信息,而不会返回剪辑中包含的信息。
        在元文件中,附加信息可以放置在每一个剪辑或节目的 PARAM标签中。你可以为每个剪辑添加任意多个 PARAM 标签,用来存储自定义的信息或链接到相关站点。在 PARAM 标签中的信息可以通过 GetMediaParameter 方法来访问。
        下面的属性返回有关大小和时间的信息:
        ImageSourceHeight、ImageSourceWidth:返回图像窗口的显示尺寸;
        Duration 属性,返回剪辑的长度(秒), 要检测这个属性是否包含有效的数值,请检查IsDurationValid 属性。(对于广播的视频,其长度是不可预知的)。

    □字幕
        你可以用 .smi 文件来为你的节目添加字幕。媒体播放器支持下面的属性来处理字幕:
        SAMIFileName 属性,指定 .smi 文件的名字;
        SAMILang 属性,指定字幕的语言(如果没有指定则使用第一种语言);
        SAMIStyle 属性,指定字幕的文字大小和样式;
        ShowCaptioning 属性,决定是否显示字幕显示面板;

    □脚本命令
        伴随音频、视频流,你可以在流媒体文件中加入脚本命令。脚本命令是多媒体流中与特定时间同步的多对Unicode串。第一个串标识待发命令的类型,第二个串指定要执行的命令。
    当流播放到与脚本相关的时间时,控件会向网页发送一个 ScriptCommand事件,然后由事件处理进程来响应这个事件。脚本命令字符串会作为脚本命令事件的参数传递给事件处理器。
        媒体播放器会自动处理下面类型的内嵌脚本命令:
        1)URL型命令:当媒体播放器控件收到一个URL型的命令时,指定的URL会被装载到用户的默认浏览器。如果媒体播放器嵌在一个分帧的HTML文件中,URL页可以装载到由脚本命令指定的帧内。如果脚本命令没有指定一个帧,将由 DefaultFrame 属性决定将 URL 页装入哪一帧。
        你可以通过设置 InvokeURLs 属性来决定是否自动处理 URL 型的脚本命令。如果这个属性的值为 false ,媒体播放器控件将忽视 URL型命令。但是脚本命令事件仍会触发,这就允许你有选择地处理 URL 型命令。
        URL 型命令指定的是 URL 的相对地址。基地址是由 BaseURL属性指定的。媒体播放器控件传送的脚本命令事件的命令参数是链接好的地址。
        2)FILENAME型命令:当媒体播放器控件收到一个FILENAME型的命令时,它将 FileName属性设置为脚本命令提供的文件,之后媒体播放器会打开这个文件开始播放。 媒体播放器控件总是自动处理 FILENAME 型命令,不象 URL 型命令,它们不能被禁止。
        3)TEXT型命令:当媒体播放器控件收到一个 TEXT型的命令时,它会将命令的内容显示在控件的字幕窗口。内容可以是纯文本的,也可以是 HTML。
        4)EVENT型命令:当媒体播放器控件收到一个 EVENT型的命令时,它会在媒体元文件中搜索 EVENT 元素的 NAME 属性。如果 NAME 属性与脚本命令中的第二个字符串匹配,媒体播放器控件就执行包含在 EVENT 元素中的条目。
        5)OPENEVENT型命令:当媒体播放器控件收到一个 OPENEVENT型的命令时,它会在媒体元文件中检查 EVENT 元素,并打开匹配的标题,但不播放,直到收到来自 EVENT型命令的同名真实事件。

    □捕捉键盘和鼠标事件
        EnableContextMenu 与 ClickToPlay 属性为用户提供了在图像窗口进行操作的方法。
    如果 EnableContextMenu 属性为 true ,在图像窗口右击鼠标可以打开关联菜单,如果将ClickToPlay 属性设为 true ,用户可以单击图像窗口进行播放与暂停的切换。
        要接收鼠标移动和单击事件,请将 SendMouseMoveEvents 和 SendMouseClickEvents 属性设为 true 。鼠标事件有:
        MouseDown,当用户按下鼠标时产生;
        MouseUp,当用户释放鼠标时产生;
        MouseMove,当用户移动鼠标时产生;
        Click,当用户在媒体播放器上单击鼠标按钮时产生;
        DbClick,当用户在媒体播放器上双击鼠标按钮时产生;
        要接收键盘事件,请将 SendKeyboardEvents 属性设为 true 。键盘事件有:
        KeyDown,当用户按下一个键时产生;
        KeyUp,当用户释放一个键时产生;
        KeyPress,当用户按下并释放一个键时产生;

    □监测流状态与网络链接
        流状态属性包括:
        PlayState:播放状态;
        OpenState:打开状态;
        Bandwidth:带宽;
        支持的事件有:
        OpenStateChange:打开状态改变(仅当SendOpenStateChangeEvents属性为true时触发)
        PlayStateChange:播放状态改变(仅当SendPlayStateChangeEvents属性为true时触发)
        EndOfStream:流结束时触发;
        NewStream:打开新流时触发;
        网络接收属性包括:
        ReceptionQuality:接收质量;
        ReceivedPackets:已经收到的包;
        LostPackets:丢失的包;
        监测缓冲的属性有:
        BufferingTime:缓冲时间;
        BufferingCount:缓冲次数;
        BufferingProgress:缓冲进程;
        Buffering:缓冲事件;

    □错误处理
        媒体播放器提供了内建的错误处理功能——在对话框或状态栏显示错误信息。 另外,你可以自己添加错误处理程序。如果 SendErrorEvents 属性设置为 true,将不会显示错误框,而是发送错误事件;如果 SendErrorEvents 属性设置为 false,将显示错误框,而是发送错误事件。
        媒体播放器支持下面的错误处理事件:
        Error 事件,指有危险性错误发生;
        Warning 事件,指发生了非危险性的错误;
        当你的应用程序接收到一个错误事件,你可以检测下面的属性来确定具体的错误信息:
        HasError:检测目前的媒体播放器是否有错误;
        ErrorCode:提供与该类型错误相关的代码值;
        ErrorDescription:提供错误的描述信息;
        ErrorCorrection:指定媒体播放器对该类型的错误进行校正;

    □播放CD
        媒体播放器将 CD 看作(在每个音轨的开头具有标记的)单一音频流。 要在网页中使用CD,你需要将 FileName 属性设为 CDAUDIO:,必须带有冒号,如下所示:
    <HTML>
    <HEAD><TITLE>CD Audio Playback Example</TITLE></HEAD>
    <BODY>
    <OBJECT ID="MediaPlayer"
        CLASSID="CLSID:22d6f312-b0f6-11d0-94ab-0080c74c7e95"
        WIDTH="320"
        HEIGHT="508"
        STYLE="position:absolute; left:0px; top:70px;"    >
        <PARAM NAME="FileName" VALUE="cdaudio:">
        <PARAM NAME="AutoStart" VALUE="0">
        <PARAM NAME="ShowControls" VALUE="1">
        <PARAM NAME="ShowStatusBar" VALUE="1">
        <PARAM NAME="ShowDisplay" VALUE="1">
    </OBJECT>
    </BODY>
    </HTML>


     发表于 12:45:46  阅读全文  |  评论(1)  |  Trackback(1)  | 编辑
     
    2006-01-02
    Tag:awstats apache Log Analysis

    awstats简易安装文档

    step 1 安装

    1、 安装apache2.2.0

     tar jxvf httpd-2.2.0 tar.bz2
      cd httpd-2.2.0 


      vi config.sh
    #!/bin/bash
    HTTPD_ROOT="/usr/local/apps/apache2"

    ./configure --prefix=$HTTPD_ROOT \
    --enable-so \
    --enable-rewrite \
    --enable-info \
    --enable-cgid \
    --enable-mime-magic \
    --enable-vhost-alias \
    --enable-deflate \
    --enable-expires \
    --with-mpm=prefork


    sh config.sh
    make
    make install

    2 、安装awstats6.5

    tar zxvf awstats-6.5.tar.gz
    mv awstats-6.5 /usr/apps/local/awstats

    step 2 配置

    1、apache配置

    vi /usr/local/apps/apache2/conf/httpd.conf


        DocumentRoot /usr/local/apps/awstats/wwwroot/
        ServerName irunnet.com
        ErrorLog "/usr/local/apps/apache2/logs/irunnet-error_log"
        CustomLog "/usr/local/apps/apache2/logs/irunnet-access_log" combined

    [root@mail bin]# ./apachectl stop
    [root@mail bin]# ./apachectl start

    2、awstats配置

    A、运行配置脚本生成awstats的配置文件
       cd /usr/local/apps/awstats/tools
       perl awstats_configure.pl 
       >> 默认生成的配置文件会放在/etc/awstats/下面,名称为awstats.www.irunnet.com.conf

      >>默认安装后重启apache

    [root@mail bin]# ./apachectl stop
    [root@mail bin]# ./apachectl start

    B、编辑/etc/awstats/awstats.www.irunnet.com.conf

       >>1 设置web server的logfile位置
           编辑LogFile为web server的log文件位置
           LogFile=/usr/local/apps/apache2/logs/irunnet-access_log
          [确认和httpd.conf中的log文件保证一致,httpd.conf中log: logs/irunnet-access_log]
       >>2 设置要分析的服务日志类型
           LogType=W 
           w表示为WEB日志
       >>3 设置日志格式
           LogFormat=1
           1表示采用NCSA apache combined/ELF/XLF log format
       >>4 设置所要分析网站域名
           SiteDomain=www.irunnet.com
           HostAliases="irunnet.com  61.162.XXX.YYY localhost"

          >>5 设置awstats的数据库存放目录
           DirData="/usr/local/apps/awstats/data"[data需要手动建立]
       >>6 设置DirCgi
           DirCgi="/usr/local/apps/awstats/wwwroot/cgi-bin"

            DirIcons="/icon/"[这里icon是DocumentRoot /usr/local/awstats/wwwroot/下]

    C、awstats权限修改
    [root@irunnet awstats]# cd /usr/apps/local/apps
    [root@irunnet apps]# chown -R root:root awstats
    [root@irunnet apps]# chmod -R 755 awstats

    [root@irunnet apps]# cd awstats

    [root@irunnet awstats]# mkdir data

    [root@irunnet awstats]#chown -R nobody data[nobdy为apache运行用户]
    [root@irunnet awstats]#chmod -R 755 data

    [root@irunnet awstats]#cd wwwroot/cgi-bin
    [root@irunnet cgi-bin]# perl awstats.pl -config=www.irunnet.com -update -lang=cn

    [root@irunnet cgi-bin]# perl awstats.pl -config=www.irunnet.com -output -staticlinks -lang=cn>awstats.www.irunnet.com.html
     [root@irunnet cgi-bin]# chmod 777 /usr/local/apps/awstats/wwwroot/cgi-bin/*.pl

    D、修改etc/awstats/awstats.www.irunnet.com.conf
    AllowToUpdateStatsFromBrowser=1

    step 3 测试

    http://www.irunnet.com/awstats/awstats.pl?config=www.irunnet.com

    参考资料
    AWStats
    http://awstats.sourceforge.net/

    日志分析工具
    http://directory.google.com/Top/Computers/Software/Internet/Site_Management/Log_Analysis/

    商业日志统计/分析工具
    http://directory.google.com/Top/Computers/Software/Internet/Site_Management/Log_Analysis/Commercial/

    多站点的日志合并统计:
    http://www.chedong.com/tech/rotate_merge_log.html

    日志统计对于分析搜索引擎对站点的影响具有非常重要的意义
    http://www.chedong.com/tech/google.html

    AWStats 本身也包含了很多插件,包括将多个站点的统计再次汇总输出,IIS日志时间转换,URL的标题映射等http://awstats.sourceforge.net/awstats_contrib.html


     发表于 23:10:55  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2005-12-31
    Tag:oscache Java web CACHE

    http://www.52blog.net/user1/38241/archives/2005/278846.shtml
     发表于 14:29:06  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2005-12-30
    Tag:Tag Lucene Java

    Tag图是采用了Tag作为文章管理工具的网站经常需要呈现的一种视图。利用Lucene的优异性能,可以出色的完成这一功能。

    生成一个Tag图,首先需要知道用于一共使用了哪些Tag,其次需要知道每个Tag被使用的次数。

    对于这两个功能,都可以使用Lucene.Index.IndexReader.Terms方法。这个方法返回索引目录下所有Term,以及他们在全部文档中被使用的次数。这就为我们生成Tag提供了必要的基础。但是Terms方法返回的TermEnum的排序算法是按照FieldName,text的方式排序的,而不是按照docfreq排序的,所以需要还实现一个排序算法。

    首先是索引的结构。我设计了如下的索引结构:

    docurl:文档的url

    contents:文档的内容,以便全文索引

    doctags:文档相关的所有tags.tag以空格或逗号作为分割,可以使用单独的Analyzer进行解析。可以参考Analyzer以及PerFieldAnalyzerWrapper两个类。
    排序算法,使用一个链表作为保存Tag的形式。它的两个方法GetList(int top)和Top(int freq)可以帮助我们设定Tag图中需要包含的Tag。TermFreq是每个Tag的数据内容。TermFreq.term是Tag的内容。TermFreq.freq是被使用的次数,这样就可以设定Tag的显示样式了。链表通过一个SortedList作为帮助信息,以便提高排序的效率。经过测试,这个排序算法对200M的TermFreq只需要11秒的时间。

      1 internal class TermFreq
      2         {
      3             public string term;
      4             public int freq = 0;
      5         }
      6         internal class TermFreqCompare : System.Collections.IComparer
      7         {
      8             #region IComparer 成员
      9 
     10             public int Compare(object x, object y)
     11             {
     12                 TermFreq f1 = x as TermFreq;
     13                 TermFreq f2 = y as TermFreq;
     14                 int compareResult = f1.freq.CompareTo(f2.freq);
     15                 //if(compareResult==0) return f2.term.CompareTo(f1.term);
     16                 return compareResult;
     17             }
     18 
     19             #endregion
     20 
     21         }
     22         internal class TermFreqSortedList
     23         {
     24             private Element root;
     25             private System.Collections.IComparer comparer;
     26             private System.Collections.SortedList list;
     27             internal class Element
     28             {
     29                 public Element prev;
     30                 public Element next;
     31                 public TermFreq current;
     32             }
     33             public TermFreqSortedList(System.Collections.IComparer comparer)
     34             {
     35                 root = new Element();
     36                 root.current = new TermFreq();
     37                 this.comparer = comparer;
     38                 list = new System.Collections.SortedList();
     39             }
     40             private Element GetStartElement(int freq)
     41             {
     42                 Element ele = null;
     43                 if(list.ContainsKey(freq))
     44                 {
     45                     ele = list[freq] as Element;
     46                 }
     47                 else
     48                 {
     49                     list.Add(freq,null);
     50                     int index = list.IndexOfKey(freq)-1;
     51                     if(index<0) ele = list[0as Element;
     52                     else ele = list[index] as Element;
     53                 }
     54                 return ele;
     55             }
     56             public void Add(TermFreq o)
     57             {
     58                 Element ele = GetStartElement(o.freq);
     59                 if(ele==null) ele = root;
     60                 Element oEle = new Element();
     61                 oEle.current = o;
     62                 list[oEle.current.freq] = oEle;
     63                 while(ele !=null)
     64                 {
     65                     int compareResult = comparer.Compare(ele.current,oEle.current);
     66                     if(compareResult>0)
     67                     {
     68                         if(ele.next==null)
     69                         {
     70                             ele.next = oEle;
     71                             oEle.prev = ele;
     72                             break;
     73                         }
     74                         else if(comparer.Compare(ele.next.current,oEle.current)<0)
     75                         {
     76                             ele.next.prev = oEle;
     77                             oEle.next = ele.next;
     78                             ele.next = oEle;
     79                             oEle.prev = ele;
     80                             break;
     81                         }
     82                         else
     83                         {
     84                             ele = ele.next;
     85                             continue;
     86                         }
     87                     }
     88                     else if(compareResult<0)
     89                     {
     90                         if(ele.prev==null)
     91                         {
     92                             ele.prev = oEle;
     93                             oEle.next = ele;
     94                             root = oEle;
     95                             break;
     96                         }
     97                         else if(comparer.Compare(ele.prev.current,oEle.current)>0)
     98                         {
     99                             ele.prev.next = oEle;
    100                             oEle.prev = ele.prev;
    101 
    102                             ele.prev = oEle;
    103                             oEle.next = ele;
    104                             break;
    105                         }
    106                         else
    107                         {
    108                             ele = ele.prev;
    109                             continue;
    110                         }
    111                     }
    112                     if(ele.prev!=null)
    113                     {
    114                         ele.prev.next = oEle;
    115                         oEle.prev = ele.prev;
    116                     }
    117                     else
    118                     {
    119                         root = oEle;
    120                     }
    121                     oEle.next = ele;
    122                     ele.prev = oEle;
    123                     break;
    124                 }
    125             }
    126             public System.Collections.ArrayList GetList(int top)
    127             {
    128                 System.Collections.ArrayList list = new System.Collections.ArrayList();
    129                 Element ele = root;
    130                 int i=0;
    131                 while((i++)<top)
    132                 {
    133                     list.Add(ele.current);
    134                     if(ele.next == null)
    135                     {
    136                         return list;
    137                     }
    138                     ele = ele.next;
    139                 }
    140                 return list;
    141             }
    142             public System.Collections.ArrayList Top(int freq)
    143             {
    144                 System.Collections.ArrayList list = new System.Collections.ArrayList();
    145                 Element ele = root;
    146                 while(ele.current.freq >= freq)
    147                 {
    148                     list.Add(ele.current);;
    149                     if(ele.next==null)
    150                         return list;
    151                     ele = ele.next;
    152                 }
    153                 return list;
    154             }
    155         }

    文档生成的代码:

    1 Document doc = new Document();        
    2 doc.Add(Field.Keyword("docurl", docurl));
    3 doc.Add(Field.Text("contents",contents));
    4 //storeTermVector==true.这样我们以后就可以通过TermFreqVector来访问tag在每个文档中被标注的次数了,以便生成单个文档的Tag图
    5 doc.Add(Field.Text("doctags", reader,true));

    测试代码:

     1 Lucene.Net.Index.TermEnum enu = reader.Terms(new Term("contents","_"));
     2                 TermFreqSortedList list = new TermFreqSortedList(new TermFreqCompare());
     3                 
     4                 while(enu.Next())
     5                 {
     6                     Lucene.Net.Index.Term t = enu.Term();
     7                     
     8                     TermFreq f = new TermFreq();
     9                     f.freq = enu.DocFreq();
    10                     f.term = t.Text();
    11                     list.Add(f);
    12                 }
    13                 for(System.Collections.IEnumerator ienu = list.GetList(5).GetEnumerator();ienu.MoveNext();)
    14                 {
    15                     TermFreq ff = ienu.Current as TermFreq;
    16                     
    17                     Console.WriteLine(string.Format("Term:{0}.\t\t\tDocFreq:{1}",
    18                         ff.term,
    19                         ff.freq));
    20                 }
    21                 for(System.Collections.IEnumerator ienu = list.Top(3).GetEnumerator();ienu.MoveNext();)
    22                 {
    23                     TermFreq ff = ienu.Current as TermFreq;
    24                     
    25                     Console.WriteLine(string.Format("Term:{0}.\t\t\tDocFreq:{1}",
    26                         ff.term,
    27                         ff.freq));
    28                 }

     发表于 18:17:56  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2005-12-28
    Tag:JavaScript prototype

    覆盖版本 1.3.1

    1. Prototype是什么?

    或许你还没有用过它, prototype.js 是一个由Sam Stephenson写的JavaScript包。这个构思奇妙编写良好的一段兼容标准的一段代码将承担创造胖客户端, 高交互性WEB应用程序的重担。轻松加入Web 2.0特性。

    如果你最近体验了这个程序包,你很可能会发现文档并不是它的强项之一。像所有在我之前的开发者一样,我只能一头扎进prototype.js的源代码中并且试验其中的每一个部分。 我想当我学习他的时候记写笔记然后分享给其他人将会很不错。

    我也一起提供了这个包的对象,类,方法和扩展的 非官方参考

    2. 通用性方法

    这个程序包里面包含了许多预定义的对象和通用性方法。编写这些方法的明显的目的就是为了减少你大量的重复编码和惯用法。

    2.1. 使用 $()方法

    $() 方法是在DOM中使用过于频繁的 document.getElementById() 方法的一个便利的简写,就像这个DOM方法一样,这个方法返回参数传入的id的那个元素。

    比起DOM中的方法,这个更胜一筹。你可以传入多个id作为参数然后 $() 返回一个带有所有要求的元素的一个 Array 对象。下面的例子会向你描述这些。

    <HTML>
    <HEAD>
    <TITLE> Test Page </TITLE>
    <script src="prototype-1.3.1.js"></script>
    
    <script>
        function test1()
        {
            var d = $('myDiv');
            alert(d.innerHTML);
        }
    
        function test2()
        {
            var divs = $('myDiv','myOtherDiv');
            for(i=0; i<divs.length; i++)
            {
                alert(divs[i].innerHTML);
            }
        }
    </script>
    </HEAD>
    
    <BODY>
        <div id="myDiv">
            <p>This is a paragraph</p>
        </div>
        <div id="myOtherDiv">
            <p>This is another paragraph</p>
        </div>
    
        <input type="button" value=Test1 onclick="test1();"><br>
        <input type="button" value=Test2 onclick="test2();"><br>
    
    </BODY>
    </HTML>

    这个方法的另一个好处就是你可以传入id字符串或者元素对象自己,这使得在创建可以传入任何形式参数的方法的时候, 它变得非常有用。

    2.2. 使用$F()方法

    $F()方法是另一个非常受欢迎的简写。它可以返回任何输入表单控件的值,如文本框或下拉框。 这个方法可以传入元素的id或者元素自己。

    <script>
        function test3()
        {
            alert(  $F('userName')  );
        }
    </script>
    
    <input type="text" id="userName" value="Joe Doe"><br> 
    <input type="button" value=Test3 onclick="test3();"><br>

    2.3. 使用Try.these()方法

    Try.these() 方法使得实现当你想调用不同的方法直到其中的一个成功正常的这种需求变得非常容易, 他把一系列的方法作为参数并且按顺序的一个一个的执行这些方法直到其中的一个成功执行,返回成功执行的那个方法的返回值。

    在下面的例子中, xmlNode.text在一些浏览器中好用,但是xmlNode.textContent在另一些浏览器中正常工作。 使用Try.these()方法我们可以得到正常工作的那个方法的返回值。

    <script>
    function getXmlNodeValue(xmlNode){
        return Try.these(
            function() {return xmlNode.text;},
            function() {return xmlNode.textContent;)
            );
    }
    </script>

    3. Ajax 对象

    上面提到的共通方法非常好,但是面对它吧,它们不是最高级的那类东西。它们是吗?你很可能自己编写了这些甚至在你的脚本里面有类似功能的方法。但是这些方法只是冰山一角。

    我很肯定你对prototype.js感兴趣的原因很可能是由于它的AJAX能力。所以让我们解释当你需要完成AJAX逻辑的时候,这个包如何让它更容易。

    Ajax 对象是一个预定义对象,由这个包创建,为了封装和简化编写AJAX 功能涉及的狡猾的代码。 这个对象包含一系列的封装AJAX逻辑的类。我们来看看它们的一些。

    3.1. 使用 Ajax.Request

    如果你不使用任何的帮助程序包,你很可能编写了整个大量的代码来创建XMLHttpRequest对象并且异步的跟踪它的进程, 然后解析出响应 然后处理它。当你不需要支持多于一种类型的浏览器时你会感到非常的幸运。

    为了支持 AJAX 功能。这个包定义了 Ajax.Request 类。

    假如你有一个应用程序可以通过url http://yoursever/app/get_sales?empID=1234&year=1998与服务器通信。它返回下面这样的XML 响应。

    <?xml version="1.0" encoding="utf-8" ?>
    <ajax-response>
        <response type="object" id="productDetails">
            <monthly-sales>
                <employee-sales>
                    <employee-id>1234</employee-id>
                    <year-month>1998-01</year-month>
                    <sales>$8,115.36</sales>
                </employee-sales>
                <employee-sales>
                    <employee-id>1234</employee-id>
                    <year-month>1998-02</year-month>
                    <sales>$11,147.51</sales>
                </employee-sales>
            </monthly-sales>
        </response>
    </ajax-response>

    Ajax.Request对象和服务器通信并且得到这段XML是非常简单的。下面的例子演示了它是如何完成的。

    <script>
        function searchSales()
        {
            var empID = $F('lstEmployees');
            var y = $F('lstYears');
            var url = 'http://yoursever/app/get_sales';
            var pars = 'empID=' + empID + '&year=' + y;
           var myAjax = new Ajax.Request(
                        url,
                        {method: 'get', parameters: pars, onComplete: showResponse}
                        );
    
        }
    
        function showResponse(originalRequest)
        {
            //put returned XML in the textarea
            $('result').value = originalRequest.responseText;
        }
    </script>
    
    <select id="lstEmployees" size="10" onchange="searchSales()">
        <option value="5">Buchanan, Steven</option>
        <option value="8">Callahan, Laura</option>
        <option value="1">Davolio, Nancy</option>
    </select>
    <select id="lstYears" size="3" onchange="searchSales()">
        <option selected="selected" value="1996">1996</option>
        <option value="1997">1997</option>
        <option value="1998">1998</option>
    </select>
    <br><textarea id=result cols=60 rows=10 ></textarea>

    你看到传入 Ajax.Request构造方法的第二个对象了吗? 参数{method: 'get', parameters: pars, onComplete: showResponse} 表示一个匿名对象的真实写法。他表示你传入的这个对象有一个名为 method 值为 'get'的属性,另一个属性名为 parameters 包含HTTP请求的查询字符串,和一个onComplete 属性/方法包含函数showResponse

    还有一些其它的属性可以在这个对象里面定义和设置,如 asynchronous,可以为truefalse 来决定AJAX对服务器的调用是否是异步的(默认值是 true)。

    这个参数定义AJAX调用的选项。在我们的例子中,在第一个参数通过HTTP GET命令请求那个url,传入了变量 pars包含的查询字符串, Ajax.Request 对象在它完成接收响应的时候将调用showResponse 方法。

    也许你知道, XMLHttpRequest在HTTP请求期间将报告进度情况。这个进度被描述为四个不同阶段:Loading, Loaded, Interactive, 或 Complete。你可以使 Ajax.Request 对象在任何阶段调用自定义方法 ,Complete 是最常用的一个。想调用自定义的方法只需要简单的在请求的选项参数中的名为 onXXXXX 属性/方法中提供自定义的方法对象。 就像我们例子中的 onComplete 。你传入的方法将会被用一个参数调用,这个参数是 XMLHttpRequest 对象自己。你将会用这个对象去得到返回的数据并且或许检查包含有在这次调用中的HTTP结果代码的 status 属性。

    还有另外两个有用的选项用来处理结果。我们可以在onSuccess 选项处传入一个方法,当AJAX无误的执行完后调用, 相反的,也可以在onFailure选项处传入一个方法,当服务器端出现错误时调用。正如onXXXXX 选项传入的方法一样,这两个在被调用的时候也传入一个带有AJAX请求的XMLHttpRequest对象。

    我们的例子没有用任何有趣的方式处理这个 XML响应, 我们只是把这段XML放进了一个文本域里面。对这个响应的一个典型的应用很可能就是找到其中的想要的信息,然后更新页面中的某些元素, 或者甚至可能做某些XSLT转换而在页面中产生一些HTML。

    更完全的解释,请参照 Ajax.Request 参考Ajax选项参考

    3.2. 使用 Ajax.Updater

    如果你的服务器的另一端返回的信息已经是HTML了,那么使用这个程序包中 Ajax.Updater 类将使你的生活变得更加得容易。用它你只需提供哪一个元素需要被AJAX请求返回的HTML填充就可以了,例子比我写说明的更清楚。

    <script>
        function getHTML()
        {
            var url = 'http://yourserver/app/getSomeHTML';
            var pars = 'someParameter=ABC';
    
             var myAjax = new Ajax.Updater('placeholder', url, {method: 'get', parameters: pars});
    
        }
    </script>
    
    <input type=button value=GetHtml onclick="getHTML()">
    <div id="placeholder"></div>

    你可以看到,这段代码比前面的例子更加简洁,不包括 onComplete 方法,但是在构造方法中传入了一个元素id。 我们来稍稍修改一下代码来描述如何在客户端处理服务器段错误成为可能。

    我们将加入更多的选项, 指定处理错误的一个方法。这个是用 onFailure 选项来完成的。

    我们也指定了一个 placeholder 只有在成功请求之后才会被填充。为了完成这个目的我们修改了第一个参数从一个简单的元素id到一个带有两个属性的对象, success (一切OK的时候被用到) 和 failure (有地方出问题的时候被用到) 在下面的例子中没有用到failure属性,而仅仅在 onFailure 处使用了 reportError 方法。

    <script>
        function getHTML()
        {
            var url = 'http://yourserver/app/getSomeHTML';
            var pars = 'someParameter=ABC';
            var myAjax = new Ajax.Updater(
                        {success: 'placeholder'},
                        url,
                        {method: 'get', parameters: pars, onFailure: reportError});
    
        }
    
        function reportError(request)
        {
            alert('Sorry. There was an error.');
        }
    </script>
    
    <input type=button value=GetHtml onclick="getHTML()">
    <div id="placeholder"></div>
    

    如果你的服务器逻辑是返回JavaScript 代码而不是单纯的 HTML 标记, Ajax.Updater对象可以执行那段JavaScript代码。为了使这个对象对待响应为JavaScript,你只需在最后参数的对象构造方法中简单加入evalScripts: true属性。

    更完全的解释,请参照 Ajax.Updater 参考Ajax选项参考

    4. prototype.js参考

    4.1. JavaScript 类的扩展

    prototype.js 包中加入功能的一种途径就是扩展已有的JavaScript 类。

    4.2. 对 Object 类的扩展

    Table 1. Object 类的扩展

    方法类别参数描述
    extend(destination, source)staticdestination: 任何对象, source: 任何对象用从 sourcedestination复制所有属性和方法的方式 来提供一种继承机制。
    extend(object)instance任何对象用从传入的 object 中复制所有属性和方法的方式 来提供一种继承机制。

    4.3. 对 Number 类的扩展

    Table 2. Number 类的扩展

    方法类别参数描述
    toColorPart()instance(none)返回数字的十六进制描述, 当在HTML中转换为RGB颜色组件到HTML中使用的颜色。

    4.4. 对 Function 类的扩展

    Table 3. 对 Function 类的扩展

    方法类别参数描述
    bind(object)instanceobject: 拥有这个方法的对象返回预先绑定在拥有该函数(=方法)的对象上的函数实例, 返回的方法将和原来的方法具有相同的参数。
    bindAsEventListener(object)instanceobject: 拥有这个方法的对象返回预先绑定在拥有该函数(=方法)的对象上的函数实例, 返回的方法将把当前的事件对象作为它的参数。

    让我们看看这些扩展的具体例子。

    <input type=checkbox id=myChk value=1> Test?
    <script>
        //declaring the class
        var CheckboxWatcher = Class.create();
    
        //defining the rest of the class implmentation
        CheckboxWatcher.prototype = {
    
           initialize: function(chkBox, message) {
                this.chkBox = $(chkBox);
                this.message = message;
                //assigning our method to the event
                this.chkBox.onclick = this.showMessage.bindAsEventListener(this);
           },
    
           showMessage: function(evt) {
              alert(this.message + ' (' + evt.type + ')');
           }
        };
    
    
        var watcher = new CheckboxWatcher('myChk', 'Changed');
    </script>

    4.5. 对 String 类的扩展

    Table 4. String 类的扩展

    方法类别参数描述
    stripTags()instance(none)返回一个把所有的HTML或XML标记都移除的字符串。
    escapeHTML()instance(none)返回一个把所有的HTML标记回避掉的字符串。
    unescapeHTML()instance(none)escapeHTML()相反。

    4.6. 对 document DOM 对象的扩展

    Table 5. document DOM 对象的扩展

    方法类别参数描述
    getElementsByClassName(className)instanceclassName: 关联在元素上的CSS类名返回给定的具有相同的CSS类名的所有元素。

    4.7. 对 Event 对象的扩展

    Table 6. Event 对象的扩展

    属性类型描述
    KEY_BACKSPACENumber8: 常量,退格(Backspace)键的代码。
    KEY_TABNumber9: 常量,Tab键的代码。
    KEY_RETURNNumber13: 常量,回车键的代码。
    KEY_ESCNumber27: 常量, Esc键的代码。
    KEY_LEFTNumber37: 常量,左箭头键的代码。
    KEY_UPNumber38: 常量,上箭头键的代码。
    KEY_RIGHTNumber39: 常量,右箭头键的代码。
    KEY_DOWNNumber40: 常量,下箭头键的代码。
    KEY_DELETENumber46: 常量,删除(Delete)键的代码。
    observers:Array缓存的观察者的列表,这个对象内部具体实现的一部分。

    Table 7. Event 对象的扩展

    方法类别参数描述
    element(event)staticevent: 事件对象返回引发这个事件的元素。
    isLeftClick(event)staticevent: 事件对象如果鼠标左键单击返回true。
    pointerX(event)staticevent: 事件对象返回在页面上x坐标。
    pointerY(event)staticevent: 事件对象返回在页面上y坐标。
    stop(event)staticevent: 事件对象用这个方法来中止事件的默认行为来使事件的传播停止。
    findElement(event, tagName)staticevent: 事件对象, tagName: 指定标记的名字向 DOM 树的上位查找,找到第一个给定标记名称的元素, 从这个元素开始触发事件。
    observe(element, name, observer, useCapture)staticelement: 对象或者对象id, name: 事件名 (如 'click', 'load', etc), observer: 处理这个事件的方法, useCapture: 如果true, 在捕捉到事件的阶段处理事件 那么如果 false在bubbling 阶段处理。加入一个处理事件的方法。
    stopObserving(element, name, observer, useCapture)staticelement: 对象或者对象id, name: 事件名 (如 'click', 'load', etc), observer: 处理这个事件的方法, useCapture: 如果true, 在捕捉到事件的阶段处理事件 那么如果 false在bubbling 阶段处理。删除一个处理实践的方法。
    _observeAndCache( element, name, observer, useCapture)static 私有方法,不用管它。
    unloadCache()static(none)私有方法,不用管它。清除内存中的多有观察着缓存。

    让我们看看怎样用这个对象加入处理 window 对象的load事件的处理方法。

    <script>
        Event.observe(window, 'load', showMessage, false);
    
        function showMessage() {
          alert('Page loaded.');
        }
    </script>

    4.8. 在 prototype.js中定义的新对象和类

    另一个这个程序包帮助你的地方就是提供许多既支持面向对象设计理念又有共通功能的许多对象。

    4.9. PeriodicalExecuter 对象

    这个对象提供一定间隔时间上重复调用一个方法的逻辑。

    Table 8. PeriodicalExecuter 对象

    方法类别参数描述
    [ctor](callback, interval)constructorcallback: 没有参数的方法, interval: 秒数创建这个对象的实例将会重复调用给定的方法。

    Table 9. PeriodicalExecuter 对象

    属性类型描述
    callbackFunction()被调用的方法,该方法不会被传入参数。
    frequencyNumber以秒为单位的间隔。
    currentlyExecutingBoolean表示这个方法是否正在执行。

    4.10. Prototype 对象

    Prototype 没有太重要的作用,只是声明了该程序包的版本 。

    Table 10. The Prototype object

    属性类型描述
    VersionString包的版本。
    emptyFunctionFunction()空方法对象。

    4.11. Class 对象

    在这个程序包中 Class 对象在声明其他的类时候被用到 。用这个对象声明类使得新类支持 initialize() 方法,他起构造方法的作用。

    看下面的例子

    //declaring the class
    var MySampleClass = Class.create();
    //defining the rest of the class implmentation
    MySampleClass.prototype = {
    
       initialize: function(message) {
            this.message = message;
       },
    
       showMessage: function(ajaxResponse) {
          alert(this.message);
       }
    };
    
    //now, let's instantiate and use one object
    var myTalker = new MySampleClass('hi there.');
    myTalker.showMessage(); //displays alert

    Table 11. Class 对象

    方法类别参数描述
    create(*)instance(any)定义新类的构造方法。

    4.12. Ajax 对象

    这个对象被用作其他提供AJAX功能的类的根对象。

    Table 12. Ajax 对象

    方法类别参数描述
    getTransport()instance(none)返回新的XMLHttpRequest 对象。

    4.13. Ajax.Base

    这个类是其他在Ajax对象中定义的类的基类。

    Table 13. Ajax.Base 类

    方法类别参数描述
    setOptions(options)instanceoptions: AJAX 选项设定AJAX操作想要的选项。
    responseIsSuccess()instance(none)返回 true 如果AJAX操作成功,否则为 false
    responseIsFailure()instance(none)responseIsSuccess() 相反。

    4.14. Ajax.Request

    继承自 Ajax.Base

    封装 AJAX 操作

    Table 14. Ajax.Request

    属性类型类别描述
    EventsArraystatic在AJAX操作中所有可能报告的事件/状态的列表。这个列表包括: 'Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'
    transportXMLHttpRequestinstance携带AJAX操作的 XMLHttpRequest 对象。

    Table 15. Ajax.Request

    方法类别参数描述
    [ctor](url, options)constructorurl: 请求的url, options: AJAX 选项创建这个对象的一个实例,它将在给定的选项下请求url。 重要:如果选择的url受到浏览器的安全设置,他会一点作用也不起。 很多情况下,浏览器不会请求与当前页面不同主机(域名)的url。 你最好只使用本地url来避免限制用户配置他们的浏览器(谢谢Clay)
    request(url)instanceurl: AJAX 请求的url这个方法通常不会被外部调用。已经在构造方法中调用了。
    setRequestHeaders()instance(none)这个方法通常不会被外部调用。 被这个对象自己调用来配置在HTTP请求要发送的HTTP报头。
    onStateChange()instance(none)这个方法通常不会被外部调用。 当AJAX请求状态改变的时候被这个对象自己调用。
    respondToReadyState(readyState)instancereadyState: 状态数字 (1 到 4)这个方法通常不会被外部调用。 当AJAX请求状态改变的时候被这个对象自己调用。

    4.15. options 参数对象

    AJAX操作中一个重要的部分就是 options 参数。 本质上没有options类。任何对象都可以被传入,只要带有需要的属性。通常会只为了AJAX调用创建匿名类。

    Table 16. options 参数对象

    属性类型Default描述
    methodArray'post'HTTP 请求方式。
    parametersString''在HTTP请求中传入的url格式的值列表。
    asynchronousBooleantrue指定是否做异步 AJAX 请求。
    postBodyStringundefined在HTTP POST的情况下,传入请求体中的内容。
    requestHeadersArrayundefined和请求一起被传入的HTTP头部列表, 这个列表必须含有偶数个项目, 任何奇数项目是自定义的头部的名称, 接下来的偶数项目使这个头部项目的字符串值。 例子:['my-header1', 'this is the value', 'my-other-header', 'another value']
    onXXXXXXXXFunction(XMLHttpRequest)undefined在AJAX请求中,当相应的事件/状态形成的时候调用的自定义方法。 例如 var myOpts = {onComplete: showResponse, onLoaded: registerLoaded};. 这个方法将被传入一个参数, 这个参数是携带AJAX操作的 XMLHttpRequest对象。
    onSuccessFunction(XMLHttpRequest)undefined当AJAX请求成功完成的时候调用的自定义方法。 这个方法将被传入一个参数, 这个参数是携带AJAX操作的 XMLHttpRequest对象。
    onFailureFunction(XMLHttpRequest)undefined当AJAX请求完成但出现错误的时候调用的自定义方法。 这个方法将被传入一个参数, 这个参数是携带AJAX操作的 XMLHttpRequest对象。
    insertionFunction(Object, String)null为了把返回的文本注入到一个元素中而执行的方法。 这个方法将被传入两个参数,要被更新的对象并且只应用于 Ajax.Updater的响应文本 。
    evalScriptsBooleanundefined, false决定当响应到达的时候是否执行其中的脚本块,只在 Ajax.Updater 对象中应用。
    decayNumberundefined, 1决定当最后一次响应和前一次响应相同时在 Ajax.PeriodicalUpdater 对象中的减漫访问的次数, 例如,如果设为2,后来的刷新和之前的结果一样, 这个对象将等待2个设定的时间间隔进行下一次刷新, 如果又一次一样, 那么将等待4次,等等。 不设定这个只,或者设置为1,将避免访问频率变慢。

    4.16. Ajax.Updater

    继承自 Ajax.Request

    当请求的url返回一段HTML而你想把它直接放置到页面中一个特定的元素的时候被用到。 如果url的返回<script> 的块并且想在接收到时就执行它的时候也可以使用该对象。含有脚本的时候使用 evalScripts 选项。

    Table 17. Ajax.Updater

    属性类型类别描述
    ScriptFragmentStringstatic可以判断是否为脚本的正则表达式。
    containersObjectinstance这个对象包含两个属性:AJAX请求成功执行的时候用到 containers.success , 否则的话用到 containers.failure

    Table 18. Ajax.Updater

    方法类别参数描述
    [ctor](container, url, options)constructorcontainer:可以是元素的id, 也可以是元素自己, 或者可以是带有2个属性的对象 - object.success AJAX请求成功的时候用到的元素(或者id) 否则用到object.failure 中设定的元素(或id) ,url: 请求的url, options: AJAX 选项创建一个用给定的选项请求给定的url的一个实例。
    updateContent()instance(none)这个方法通常不会被外部调用。 当响应到达的时候,被这个对象自己调用。 它会用HTML更新适当的元素或者调用在 insertion 选项中传入的方法-这个方法将被传入两个参数, 被更新的元素和响应文本。

    4.17. Ajax.PeriodicalUpdater

    继承自 Ajax.Base

    这个类重复生成并使用 Ajax.Updater 对象来刷新页面中的一个元素。或者执行 Ajax.Updater 可以执行的其它任务。更多信息参照 Ajax.Updater 参考

    Table 19. Ajax.PeriodicalUpdater

    属性类型类别描述
    containerObjectinstance这个值将直接传入Ajax.Updater的构造方法。
    urlStringinstance这个值将直接传入Ajax.Updater的构造方法。
    frequencyNumberinstance两次刷新之间的间隔 (不是频率) ,以秒为单位。 默认2秒。 This 当调用 Ajax.Updater 对象的时候,这个数将和当前的 decay 相乘。
    decayNumberinstance重负执行任务的时候保持的衰败水平。
    updaterAjax.Updaterinstance最后一次使用的 Ajax.Updater 对象
    timerObjectinstance通知对象该下一次更新时用到的JavaScript 计时器。

    Table 20. Ajax.PeriodicalUpdater

    方法类别参数描述
    [ctor](container, url, options)constructorcontainer:可以是元素的id, 也可以是元素自己, 或者可以是带有2个属性的对象 - object.success AJAX请求成功的时候用到的元素(或者id) 否则用到object.failure 中设定的元素(或id) ,url: 请求的url, options: AJAX 选项创建一个用给定的选项请求给定的url的一个实例。
    start()instance(none)这个方法通常不会被外部调用。 对象为了开始周期性执行任务的时候调用的方法。
    stop()instance(none)这个方法通常不会被外部调用。 对象为了停止周期性执行任务的时候调用的方法。
    updateComplete()instance(none)这个方法通常不会被外部调用。 被当前的 Ajax.Updater 使用,当一次请求结束的时候,它被用作计划下一次请求。
    onTimerEvent()instance(none)这个方法通常不会被外部调用。当到下一次更新时被内部调用。

    4.18. Element 对象

    这个对象提供在操作DOM中元素时使用的功能性方法。

    Table 21. Element 对象

    方法类别参数描述
    toggle(elem1 [, elem2 [, elem3 [...]]])constructorelemN: 元素对象或id切换每一个传入元素的可视性。
    hide(elem1 [, elem2 [, elem3 [...]]])instanceelemN: 元素对象或id用设定它的 style.display'none'来隐藏每个传入的元素。
    show(elem1 [, elem2 [, Slem3 [...]]])instanceelemN: 元素对象或id用设定它的 style.display ''来显示每个传入的元素。
    remove(element)instanceelement: 元素对象或id从document对象中删除指定的元素。
    getHeight(element)instanceelement: 元素对象或id返回元素的 offsetHeight
    addClassName( element, className)instanceelement: 元素对象或id, className: CSS类名向元素的类名中加入给定的类名。
    hasClassName( element, className)instanceelement: 元素对象或id, className: CSS类名返回 true 如果元素的类名中含有给定的类名
    removeClassName( element, className)instanceelement: 元素对象或id, className: CSS类名从元素的类名中删除给定的类名。
    cleanWhitespace( element )instanceelement: 元素对象或id删除该元素的所有只含有空格的子节点。

    4.19. Abstract 对象

    这个对象是这个程序包中其他类的根。它没有任何属性和方法。在这个对象中定义的类可以被视为传统的抽象类。

    4.20. Abstract.Insertion

    这个类被用作其他提供动态内容插入功能的类的基类,它像一个抽象类一样被使用。

    Table 22. Abstract.Insertion

    方法类别参数描述
    [ctor](element, content)constructorelement: 元素对象或id, content: 被插入的HTML创建一个可以帮助插入动态内容的对象。

    Table 23. Abstract.Insertion

    属性类型类别描述
    adjacencyStringstatic, parameter这个参数指定相对于给定元素,内容将被放置的位置。 可能的值是: 'beforeBegin', 'afterBegin', 'beforeEnd', 和 'afterEnd'.
    elementObjectinstance与插入物做参照元素对象。
    contentStringinstance被插入的 HTML 。

    4.21. Insertion 对象

    这个对象是其他类似功能的根。它没有任何属性和方法。在这个对象中定义的类仍然可以被视为传统的抽象类。

    4.22. Insertion.Before

    继承自 Abstract.Insertion

    在给定元素开始标记的前面插入HTML。

    Table 24. Insertion.Before

    方法类别参数描述
    [ctor](element, content)constructorelement: 元素对象或id, content: 被插入的HTML继承自 Abstract.Insertion. 创建一个可以帮助插入动态内容的对象。

    下面的代码

    <br>Hello, <span id="person" style="color:red;">Wiggum. How's it going?</span>
    
    <script> new Insertion.Before('person', 'Chief '); </script>

    将把 HTML 变为

    <br>Hello, Chief <span id="person" style="color:red;">Wiggum. How's it going?</span>

    4.23. Insertion.Top

    继承自 Abstract.Insertion

    在给定元素第一个子节点位置插入 HTML。内容将位于元素的开始标记的紧后面。

    Table 25. Insertion.Top

    方法类别参数描述
    [ctor](element, content)constructorelement: 元素对象或id, content: 被插入的HTML继承自 Abstract.Insertion. 创建一个可以帮助插入动态内容的对象。

    下面的代码

    <br>Hello, <span id="person" style="color:red;">Wiggum. How's it going?</span>
    
    <script> new Insertion.Top('person', 'Mr. '); </script>

    将把 HTML 变为

    <br>Hello, <span id="person" style="color:red;">Mr. Wiggum. How's it going?</span>

    4.24. Insertion.Bottom

    继承自 Abstract.Insertion

    在给定元素最后一个子节点位置插入 HTML。内容将位于元素的结束标记的紧前面。

    Table 26. Insertion.Bottom

    方法类别参数描述
    [ctor](element, content)constructorelement: 元素对象或id, content: 被插入的HTML继承自 Abstract.Insertion. 创建一个可以帮助插入动态内容的对象。

    下面的代码

    <br>Hello, <span id="person" style="color:red;">Wiggum. How's it going?</span>
    
    <script> new Insertion.Bottom('person', " What's up?"); </script>

    将把 HTML 变为

    <br>Hello, <span id="person" style="color:red;">Wiggum. How's it going? What's up?</span>

    4.25. Insertion.After

    继承自 Abstract.Insertion

    在给定元素结束标记的后面插入HTML。

    Table 27. Insertion.After

    方法类别参数描述
    [ctor](element, content)constructorelement: 元素对象或id, content: 被插入的HTML继承自 Abstract.Insertion. 创建一个可以帮助插入动态内容的对象。

    下面的代码

    <br>Hello, <span id="person" style="color:red;">Wiggum. How's it going?</span>
    
    <script> new Insertion.After('person', ' Are you there?'); </script>

    将把 HTML 变为

    <br>Hello, <span id="person" style="color:red;">Wiggum. How's it going?</span> Are you there?

    4.26. Field 对象

    这个对象提供操作表单中的输入项目的功能性方法。

    Table 28. Field 对象

    方法类别参数描述
    clear(field1 [, field2 [, field3 [...]]])instancefieldN: 元素对象或id清除传入表单中项目元素的值。
    present(field1 [, field2 [, field3 [...]]])instancefieldN: 元素对象或id只有在所有的表单项目都不为空时返回 true
    focus(field)instancefieldN: 元素对象或id移动焦点到给定的表单项目。
    select(field)instancefieldN: 元素
     发表于 22:31:55  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2005-12-28
    Tag:MySQL mysqldump Data

    MySQL有很多可以导入数据的方法,然而这些只是数据传输中的一半,另外的一般是从MySQL数据库中导出数据。有许多的原因我们需要导出数据。一个重要的原因是用于备份数据库。数据的造价常常是昂贵的,需要谨慎处理它们。经常地备份可以帮助防止宝贵数据地丢失;另外一个原因是,也许您希望导出数据来共享。 在这个信息技术不断成长的世界中,共享数据变得越来越常见。

       比方说Macmillan USA维护护着一个将要出版的书籍的大型数据库。这个数据库在许多书店之间共享,这样他们就知道哪些书将会很快出版。医院越来越走向采用无纸病历记录,这样这些病历可以随时跟着你。世界变得越来越小,信息也被共享得越来越多。有很多中导出数据得方法,它们都跟导入数据很相似。因为,毕竟,这些都只是一种透视得方式。从数据库导出的数据就是从另一端导入的数据。这里我们并不讨论其他的数据库各种各样的导出数据的方法,您将学会如何用MySQL来实现数据导出。
      
      使用mysqldump:
      
      (mysqldump命令位于mysql/bin/目录中)

      mysqldump工具很多方面类似相反作用的工具mysqlimport。它们有一些同样的选项。但mysqldump能够做更多的事情。它可以把整个数据库装载到一个单独的文本文件中。这个文件包含有所有重建您的数据库所需要的SQL命令。这个命令取得所有的模式(Schema,后面有解释)并且将其转换成DDL语法(CREATE语句,即数据库定义语句),取得所有的数据,并且从这些数据中创建INSERT语句。这个工具将您的数据库中所有的设计倒转。因为所有的东西都被包含到了一个文本文件中。这个文本文件可以用一个简单的批处理和一个合适SQL语句导回到MySQL中。这个工具令人难以置信地简单而快速。决不会有半点让人头疼地地方。
      
      因此,如果您像装载整个数据库Meet_A_Geek的内容到一个文件中,可以使用下面的命令:

      bin/mysqldump –p Meet_A_Geek > MeetAGeek_Dump_File.txt
      
      这个语句也允许您指定一个表进行dump(备份/导出/装载?)。如果您只是希望把数据库Meet_A_Geek中的表Orders中的整个内容导出到一个文件,可以使用下面的命令:

      bin/mysqldump –p Meet_A_Geek Orders >MeetAGeek_Orders.txt
      
      这个非常的灵活,您甚至可以使用WHERE从句来选择您需要的记录导出到文件中。要达到这样的目的,可以使用类似于下面的命令:

      bin/mysqldump –p –where="Order_ID > 2000" Meet_A_Geek Orders > Special_Dump.txt
      
      mysqldump工具有大量的选项,部分选项如下表:

      选项/Option 作用/Action Performed

      --add-drop-table

      这个选项将会在每一个表的前面加上DROP TABLE IF EXISTS语句,这样可以保证导回MySQL数据库的时候不会出错,因为每次导回的时候,都会首先检查表是否存在,存在就删除

      --add-locks

      这个选项会在INSERT语句中捆上一个LOCK TABLE和UNLOCK TABLE语句。这就防止在这些记录被再次导入数据库时其他用户对表进行的操作
      
      -c or - complete_insert

      这个选项使得mysqldump命令给每一个产生INSERT语句加上列(field)的名字。当把数据导出导另外一个数据库时这个选项很有用。

      --delayed-insert 在INSERT命令中加入DELAY选项

      -F or -flush-logs 使用这个选项,在执行导出之前将会刷新MySQL服务器的log.

      -f or -force 使用这个选项,即使有错误发生,仍然继续导出

      --full 这个选项把附加信息也加到CREATE TABLE的语句中

      -l or -lock-tables 使用这个选项,导出表的时候服务器将会给表加锁。

      -t or -no-create- info

      这个选项使的mysqldump命令不创建CREATE TABLE语句,这个选项在您只需要数据而不需要DDL(数据库定义语句)时很方便。
      
      -d or -no-data 这个选项使的mysqldump命令不创建INSERT语句。

      在您只需要DDL语句时,可以使用这个选项。

      --opt 此选项将打开所有会提高文件导出速度和创造一个可以更快导入的文件的选项。

      -q or -quick 这个选项使得MySQL不会把整个导出的内容读入内存再执行导出,而是在读到的时候就写入导文件中。

      -T path or -tab = path 这个选项将会创建两个文件,一个文件包含DDL语句或者表创建语句,另一个文件包含数据。DDL文件被命名为table_name.sql,数据文件被命名为table_name.txt.路径名是存放这两个文件的目录。目录必须已经存在,并且命令的使用者有对文件的特权。
      
      -w "WHERE Clause" or -where = "Where clause "

      如前面所讲的,您可以使用这一选项来过筛选将要放到 导出文件的数据。
      
      假定您需要为一个表单中要用到的帐号建立一个文件,经理要看今年(2004年)所有的订单(Orders),它们并不对DDL感兴趣,并且需要文件有逗号分隔,因为这样就很容易导入到Excel中。 为了完成这个人物,您可以使用下面的句子

      bin/mysqldump –p –where "Order_Date >='2000-01-01'"
      –tab = /home/mark –no-create-info –fields-terminated-by=, Meet_A_Geek Orders

      这将会得到您想要的结果。
      
      schema:模式

      The set of statements, expressed in data definition language, that completely describe the structure of a data base.

      一组以数据定义语言来表达的语句集,该语句集完整地描述了数据库的结构。
      
      SELECT INTO OUTFILE :

      如果您觉得mysqldump工具不够酷,就使用SELECT INTO OUTFILE吧, MySQL同样提供一个跟LOAD DATA INFILE命令有相反作用的命令,这就是SELECT INTO OUTFILE 命令,这两个命令有很多的相似之处。首先,它们有所有的选项几乎相同。现在您需要完成前面用mysqldump完成的功能,可以依照下面的步骤进行操作:
      
      1. 确保mysqld进程(服务)已经在运行

      2. cd /usr/local/mysql

      3. bin/mysqladmin ping ;// 如果这个句子通不过,可以用这个:mysqladmin -u root -p ping

      mysqladmin ping用于检测mysqld的状态,is alive说明正在运行,出错则可能需要用户名和密码。

      4. 启动MySQL 监听程序.

      5. bin/mysql –p Meet_A_Geek;// 进入mysql命令行,并且打开数据库Meet_A_Geek,需要输入密码

      6. 在命令行中,输入一下命令:

      SELECT * INTO OUTFILE '/home/mark/Orders.txt'
      FIELDS
      TERMINATED BY = ','
      FROM Orders
      WHERE Order_Date >= '2000-01-01'
      
      在你按了Return(回车)之后,文件就创建了。这个句子就像一个规则的SELECT语句,只是把想屏幕的输出重定向到了文件中。这意味这您可以使用JOIN来实现多表的高级查询。这个特点也可以被用作一个报表产生器。
      
      比方说,您可以组合这一章中讨论的方法来产生一个非常有趣的查询,试试这个:
      
      在mysql目录建立一个名为Report_G.rpt 的文本文件,加入下面的行:

      USE Meet_A_Geek;
      INSERT INTO Customers (Customer_ID, Last_Name, First_Name)
      VALUES (NULL, "Kinnard", "Vicky");
      INSERT INTO Customers (Customer_ID, Last_Name, First_Name)
      VALUES (NULL, "Kinnard", "Steven");
      INSERT INTO Customers (Customer_ID, Last_Name, First_Name)
      VALUES (NULL, "Brown", "Sam");
      SELECT Last_Name INTO OUTFILE '/home/mark/Report.rpt'
      FROM Customers WHERE Customer_ID > 1;

      然后确认 mysql进程在运行,并且您在mysql目录中, 输入下面的命令:

      bin/mysql < Report_G.rpt检查您命名作为输出的文件,这个文件将会包含所有您在Customers表中输入的顾客的姓。 如您所见,您可以使用今天学到的导入/导出(import/export)的方法来帮助得到报表。


     发表于 10:05:53  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2005-12-27
    Tag:apache 配置 config httpd.conf

    Apache2 httpd.conf 中文版
    #
    # 基于 NCSA 服务的配置文件。
    #
    #这是Apache服务器主要配置文件。
    #它包含服务器的影响服务器运行的配置指令。
    #参见<URL:http://httpd.ache.org/doc-2.0/>以取得关于这些指令的详细信息
    #
    #不要只是简单的阅读这些指令信息而不去理解它。
    #这里只是做了简单的说明,如果你没有参考在线文件,你就会被警告。
    #
    #这些配置指令被分为下面三个部分:
    #1. 控制整个Apache服务器行为的部分(即全局环境变量)
    #2. 定义主要或者默认服务参数的指令,也为所有虚拟主机提供默认的设置参数
    #3. 虚拟主机的设置参数
    #
    #配置和日志文件名:如果你指定的文件名以“/”开始(win32下以“dirver:/”),
    #服务器将使用绝对路径,如果文件名不是以“/”开始的,那么它将把ServerRoot
    #的值附加在文件名的前面,例如,对“logs/foo.log",如果ServerRoot的值
    #为“/usr/local/apache2”,则该文件应为“/usr/local/apache2/logs/foo.log”
    #
    ##第一区:全局环境参数
    #
    #这里设置的参数将影响整个Apache服务器的行为;
    #例如Apache能够处理的并发请求的数量等。
    #
    #ServerRoot:指出服务器保存其配置、出错和日志文件等的根目录。
    #
    #注意!如果你想要将它指定为NFS或其它网络上的位置,
    #请一定要去阅读与LockFile有关的文档(可能在
    #<URL:http://httpd.apache.org/docs-2.0/mod/mpm_common.html#lockfile>)。
    #这将会使你自己也能解决很多问题。
    #
    #路径的结尾不要添加斜线。
    #
    ServerRoot "/usr/loacl/apache2"
    #
    #串行访问的锁文件必须保存在本地磁盘上
    #
    <IfModule !mpm_winnt.c>
    <IfModule !mpm_neware.c>
    #LockFile logs/accept.lock
    </IfModule>
    </IfModule>

    #ScoreBoardFile:用来保存内部服务进程信息的文件。
    #如果未指明(默认),记分板(scoreboard)将被保存在一个匿名的共享内存段中,
    #并且它不能被第三方软件所使用。
    #如果指定了,要确保不能使用两个Apache使用同一个记分板文件,
    #这个记分板文件必须保存在本地磁盘上。
    #
    <IfModule !mpm_netware.c>
    <IfModule !perchild.c>
    #ScoreBoardFile logs/apache_runtime_status
    <IfModule>
    <IfModule>

    #
    #PidFile:记录服务器启动进程号的文件。
    #
    <IfModule !mpm_neware.c>
    PidFile logs/httpd.pid
    </IfModule>

    #
    #Timeout:接收和发送前超时秒数
    #
    Timeout 300

    #
    #KeepAlive:是否允许稳固的连接(每个连接有多个请求),
    #设为"Off"则停用。
    #
    KeepAlive On

    #
    #MaxKeepAliveRequests:在稳固连接期间允许的最大请求数,
    #设为0表示无限制接入。
    #我们推荐你将其设为一个较大的值,以便提高性能
    MaxKeepAliveRequests 100

    #
    #KeepAliveTimeout:在同一个连接上从同一台客户上接收请求的秒数
    #
    KeepAliveTimeout 15

    ##
    ##Server-Pool大小设定(针对MPM的)
    ##

    # prefork MPM
    # StartServers:启动时服务器启动的进程数
    # MinSpareServers:保有的备用进程的最小数目
    # MaxSpareServers:保有的备用进程的最大数目
    # MaxClients:服务器允许启动的最大进程数
    # MaxRequestsPerChild:一个服务进程允许的最大请求数
    <IfModule prefork.c>
    StartServers 5
    MinSpareServers 5
    MaxSpareServers 10
    MaxClients 150
    MaxRequestPerChild 0
    </IfModule>

    # worker MPM
    # StartServers:服务器启动时的服务进程数目
    # MaxClients:允许同时连接的最大用户数目
    # MinSpareThreads:保有的最小工作线程数目
    # MaxSpareThreads:允许保有的最大工作线程数目
    # ThreadsPerChild:每个服务进程中的工作线程常数
    # MaxRequestsPerChild:服务进程中允许的最大请求数目
    <IfModule worker.c>
    StartServers 2
    MaxClients 150
    MinSpareThreads 25
    MaxSpareThreads 75
    ThreadsPerChild 25
    MaxRequestsPerChild 0
    </IfModule>

    # perchild MPM
    # NumServers:服务进程数量
    # StartThreads:每个服务进程中的起始线程数量
    # MinSpareThreads:保有的最小线程数量
    # MaxSpareThreads:保有的最大线程数量
    # MaxThreadsPerChild:每个服务进程允许的最大线程数
    # MaxRequestsPerChild:每个服务进程允许连接的最大数量
    <IfModule perchild.c>
    NumServers 5
    StartThreads 5
    MinSpareThreads 5
    MaxSpareThreads 10
    MaxThreadsPerChild 20
    MaxRequestsPerChild 0
    </IfModule>

    # WinNT MPM
    # ThreadsPerChild:服务进程中工作线程常数
    # MaxRequestsPerChild:服务进程允许的最大请求数
    <IfModule mpm_winnt.c>
    ThreadsPerChild 250
    MaxRequestsPerChild 0
    </IfModule>

    # BeOS MPM
    # StartThreads:服务器启动时启动的线程数
    # MaxClients:可以启动的最大线程数(一个线程等于一个用户)
    # MaxRequestsPerThread:每个线程允许的最大请求数
    <IfModule beos.c>
    StartThreads 10
    MaxClients 50
    MaxRequestsPerThread 10000
    </IfModule>

    # NetWare MPM
    # ThreadStachSize:为每个工作线程分配的堆栈尺寸
    # StartThreads:服务器启动时启动的线程数
    # MinSpareThreads:用于处理实发请求的空闲线程数
    # MaxSpareThreads:空闲线程的最大数量
    # MaxThreads:在同一时间活动的最大线程数
    # MaxRequestPerChild:一个线程服务请求的最大数量,
    # 推荐将其设置为0,以实现无限制的接入
    <IfModule mpm_netware.c>
    ThreadStackSize 65536
    StartThreads 250
    MinSpareThreads 25
    MaxSpareThreads 250
    MaxThreads 1000
    MaxRequestPerChild 0
    </IfModule>

    # OS/2 MPM
    # StartServers:启动的服务进程数量
    # MinSpareThreads:每个进程允许的最小空闲线程
    # MaxSpareThreads:每个进程允许的最大空闲线程
    # MaxRequestsPerChild:每个服务进程允许的最大连接数
    <IfModule mpmt_os2.c>
    StartServers 2
    MinSpareThreads 5
    MaxSpareThreads 10
    MaxRequestsPerChild 0
    </IfModule>

    #
    # Listen:允许你绑定Apache服务到指定的IP地址和端口上,以取代默认值
    # 参见<VirtualHost>指令
    # 使用如下命令使Apache只在指定的IP地址上监听,
    # 以防止它在IP地址0.0.0.0上监听
    #
    # Listen 12.34.56.78:80

    Listen 80

    #
    # 动态共享支持(DSO)
    #
    # 为了能够使用那些以DSO模式编译的模块中的函数,你必须有相应的“LoadModule”行,
    # 因此,在这里包含了这些指令,以便能在使用它之前激活。
    # 那些静态编译的模块不需要在这里列出 (即以“httpd -l”列出的模块)
    #
    # 示例:
    # LoadModule foo_module modules/mod_foo.so
    #

    #
    # ExtendedStatus:当调用“server-status”时,控制Apache是产生“全”状态
    # 信息(ExtendedStatus On),还是产生基本信息(ExtendedStatus Off)。
    # 默认为off
    #
    # ExtendedStatus On

    ### 第二区:“主”服务配置
    #
    # 这一区建立被 “主” 服务器用的指令值,以回应那些不被 <VirtualHost>
    # 定义处理的任何请求。
    # 这些数值也提供默认值给后面定义的<VirtualHost>容器。
    # 如果<VirtualHost>中有定义,那么这里定义的指令值将被
    # <VirtualHost>中的定义所覆盖。
    #

    <IfModule !mpm_winnt.c>
    <IfModule !mpm_neware.c>
    #
    # 如果你想使httpd以另外的用户或组来运行,你必须在开始时以root方式启动
    # 然后再将它切换为你想要使用的用户或组。
    #
    # User/Group:运行httpd的用户和组
    # 在SCO (ODT3)上使用“User nouser”和“Group nogroup”
    # 在HPUX上,你可能不能以nobody身份使用共享内存,建议创建一个www用户。
    # 注意一些核心(kernel)在组ID大于60000时拒绝setgid(Group)或semctl(IPC_SET),
    #节在这些系统上不要使用“Group #-1”。
    #
    User nobody
    Group #-1
    </IfModule>
    </IfModule>

    #
    # ServerAdmin:你的邮件地址,当发生问题时Apache将向你发出邮件。
    # 作为一个出错文档,这个地址显示在server-generated页上,
    # 例如:admin@your-domain.com
    #
    ServerAdmin admin@your-domain.com

    #
    # ServerName指定Apache用于识别自身的名字和端口号。
    # 通常这个值是自动指定的,但是我们推荐你显式的指定它以防止启动时出错
    #
    # 如果你为你的主机指定了一个无效的DNS名,server-generated重定向将不能工作。
    # 参见UseCanonicalName指令
    #
    # 如果你的主机没有注册DNS名,在这里键入它的IP地址
    # 无论如何,你必须使用它的IP地址来提供服务,
    # 这里使用一种容易理解的方式重定向服务
    ServerName localhost:80

    #
    # UseCanonicalName:决定Apache如何构造URLS和 SERVER_NAME 和 SERVER_PORT 的指令。
    # 当设置为 “Off”时,Apache会使用用户端提供的主机名和端口号。
    # 当设置为“On”,Apache会使用ServerName指令的值。
    #
    UseCanonicalName Off

    #
    # DocumentRoot:你的文档的根目录。默认情况下,所有的请求从这个目录进行应答。
    # 但是可以使用符号链接和别名来指向到其他的位置。
    #
    DocumentRoot "/home/redhat/public_html"

    #
    # Apache可以存取的每个目录都可以配置存取权限(包括它的子目录)。
    #
    # 首先,我们配置一个高限制的特征。

    # 这将禁止访问文件系统所在的目录,并添加你希望允许访问的目录块。
    # 如下所示
    <Directory />
    Order Deny,Allow
    Deny from all
    </Directory>

    #
    # 注意从这里开始你一定要明确地允许哪些特别的特征能够被使用。
    # - 所以,如果Apache没有象你所期待的那样工作的话,
    # 请检查你是否在下面明确的指定它可用。
    #

    #
    # 这将改变到你设置的DocumentRoot
    #
    <Directory "/home/redhat/public_html">

    #
    # Options:这个指令的值可以是“None”,“All”,或者下列选项的任意组合:
    # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
    #
    # 注意,“MultiViews”必须被显式的指定,“Options All”不能为你提供这个特性。
    #
    # 这个指令既复杂又重要,请参见
    #“http://httpd.apache.org/docs-2.0/mod/core.html#optioins”以取得更多的信息。
    #
    Options FollowSymLinks

    #
    # AllowOverride控制那些被放置在.htaccess文件中的指令。
    # 它可以是“All”,“None”,或者下列指令的组合:
    # Options FileInfo AuthConfig Limit
    #
    AllowOverride None

    #
    # 控制谁可以获得服务。
    #
    Order allow,deny
    Allow from all

    </Directory>

    #
    # UserDir:指定在得到一个~user请求时将会添加到用户home目录后的目录名。
    #

    UserDir public_html

    # 为防止在UserDir指令上的漏洞,对root用户设置
    # 象“./”这样的UserDir是非常有用的。
    # 如果你使用Apache 1.3或以上版本,我们强烈建议你
    # 在你的服务器配置文件中包含下面的行

    UserDir disabled root

    #
    # 下面是一个使用UserDir指令使一个站点的目录具有只读属性的示例:
    #
    # <Directory /home/*/public_html>
    # AllowOverride FileInfo AuthConfig Limit Indexes
    # Options MultiViews Indexes SymLinksIfOwnerMatch IncludeNoExec
    # <Limit GET POST OPTIONS PROPFIND>
    # Order allow,deny
    # Allow from all
    # </Limit>
    # <LimitExcept GET POST OPTIONS PROPFIND>
    # Order deny,allow
    # Deny from all
    # </LimitExcept>
    # </Directory>

    #
    # DirectoryIndex:定义请求是一个目录时,Apache向用户提供服务的文件名
    #
    # index.html.var文件(一个类型映象文件)用于提供一个文档处理列表,
    # 出于同样的目的,也可以使用MultiViews选项,但是它会非常慢。
    #
    DirectoryIndex index.php index.html index.html.var

    #
    # AccessFileName:在每个目录中查询为目录提供附加配置指令的文件的文件名。
    # 参见AllowOverride指令。
    #
    AccessFileName .htaccess

    #
    # 下面的行防止.htaccess和.htpasswd文件被Web客户查看。
    #
    <Files ~ "^\.ht">
    Order allow,deny
    Deny from all
    </Files>

    #
    # Typeconfig:定义在哪里查询mime.types文件。
    #
    TypeConfig conf/mime.types

    #
    # DefaultType:定义当不能确定MIME类型时服务器提供的默认MIME类型。
    # 如果你的服务主要包含text或HTML文档,“text/plain”是一个好的选择;
    # 如果大多是二进制文档,诸如软件或图像,你应使用
    # “application/octer-stream”来防止浏览器象显示文本那样显示二进制文件。
    #
    DefaultType text/plain

    #
    # mod_mime_magic允许服务器从自己定义自己类型的文件中使用不同的线索(hints),
    # 这个MIMEMagicFile指令定义hints定义所在的文件。
    #
    <IfModule mod_mime_magic.c>
    MIMEMagicFile conf/magic
    </IfModule>

    #
    # HostnameLookups:指定记录用户端的名字还是IP地址,例如,本指令为on时
    # 记录主机名,如www.apache.org;为off时记录IP地址,204.62.129.132。
    # 默认值为off,这要比设为on好得多,因为如果设为on则每个用户端请求都将会
    # 至少造成对 nameserver 进行一次查询。
    #
    HostnameLookups Off

    #
    # EnableMMAP:控制是否进行内存转储(如果操作系统支持的话)。
    # 默认为on,如果你的服务器安装在网络文件系统上(NFS),请关闭它。
    # 在一些系统上,关闭它会提升系统性能(与文件系统类型无关);
    # 具体情况请参阅http://httpd.apache.org/docs-2.0/mod/core.html#enablemmap
    #
    # EnableMMAP off

    #
    # EnableSendfile:控制是否使用sendfile kernel支持发送文件
    # (如果操作系统支持的话)。默认为on,如果你的服务器安装在网络文件系统
    # (NFS)上,请你关闭它。
    # 参见http://httpd.apache.org/docs-2.0/mod/core.html#enablesendfile
    #
    # EnableSendfile off

    #
    # ErrorLog:错误日志文件定位。
    # 如果你没有在<VirtualHost>内定义ErrorLog指令,这个虚拟主机的错误信息
    # 将记录在这里。如果你在那儿定义了ErrorLog,这些错误信息将记录在你所
    # 定义的文件里,而不是这儿定义的文件。
    #
    ErrorLog logs/error_log

    #
    # LogLevel:控制记录在错误日志文件中的日志信息数量。
    # 可能的值包括:debug,info,notice,warn,error,crit,alert,emerg。
    #
    LogLevel warn

    #
    # 下面的指令为CustomLog指令定义格式别名。
    #
    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%h %l %u %t \"%r\" %>s %b" common
    LogFormat "%{Referer}i -> %U" referer
    LogFormat "%{User-agent}i" agent

    # 你需要安装了mod_logio.c模块才能使用%I和%O。
    # LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio

    #
    # 指定接入日志文件的定位和格式(一般日志格式)。
    # 如果你没有在<VirtualHost>内定义这个指令,传输信息将记录在这里,
    # 如果你定义了这个指令,则记录在你指定的位置,而不是这儿定义的位置。
    #
    CustomLog logs/access_log common

    #
    # 如果你想要记录agent和referer信息,可以使用下面的指令
    #
    # CustomLog logs/referer_log referer
    # CustomLog logs/agent_log agent

    #
    # 如果你想要使用一个文件记录access,agent和referer信息,
    # 你可以如下定义这个指令:
    #
    # CustomLog logs/access_log combined

    #
    # ServerTokens
    # 这个指令定义包含在HTTP回应头中的信息类型。默认为“Full”,
    # 这表示在回应头中将包含模块中的操作系统类型和编译信息。
    # 可以设为列各值中的一个:
    # Full | OS | Minor | Minimal | Major | Prod
    # Full传达的信息最多,而Prod最少。
    #
    ServerTokens Full

    #
    # 随意的添加包含服务器版本和虚拟主机名字一行信息到server-generated输出页中
    # (内部错误文档,FTP目录列表,mod_status和mod_info输出等等,除了CGI错误
    # 或自定义的错误文档以外)。
    # 设为“EMail”将包含一个指向ServerAdmin的mailto:连接。
    # 可以为如下值:On | Off | EMail
    #
    ServerSignature On

    #
    # Aliases:在这时添加你需要的别名,格式如下:
    # Alias 别名 真实名
    #
    # 注意,如果你在别名的未尾包含了“/”,那么在URL中也需要包含“/”。
    # 因此,“/icons”不是这个示例中的别名。
    # 如果别名中以“/”结尾,那么真实名也必须以“/”结尾,
    # 如果别名中省略了结尾的“/”,那么真实名也必须省略。
    #
    # 我们使用别名“/icons/”来表示FancyIndexed目录列表,如果你不使用、
    # FancyIndexing,你可以注释掉它。
    #
    # Alias /icons/ "/usr/local/apache2/icons/"

    # <Directory "/usr/local/apache2/icons">
    # Options Indexes MultiViews
    # AllowOverride None
    # Order allow,deny
    ## Allow from all
    # </Directory>

    #
    # 这将改变ServerRoot/manual。这个别名提供了手册页所在的位置,
    # 即使你改变了你的DocumentRoot。如果你对有无手册页并不在意的话,
    # 你可以注释掉它。
    #
    Alias /manual "/usr/loacl/apache2/manual"

    <Directory "/usr/local/apache2/manual">
    Options Indexes FollowSymLinks MultiViews IncludesNoExec
    AddOutputFilter Includes html
    Order allow,deny
    Allow from all
    </Directory>

    #
    # ScriptAlias:指定包含服务脚本的目录。
    # ScriptAliases 本质上与Aliases一样,除了这里的文档在请求时做为程序处理处理以外。
    # 尾部的“/”规则与Alias一样
    #
    ScriptAlias /cgi-bin/ "/usr/loacl/apache2/cgi-bin/"

    # 这里是添加php 4支持的指令
    AddType application/x-httpd-php .php
    LoadModule php4_module modules/libphp4.so

    <IfModule mod_cgid.c>
    #
    # 添加mod_cgid.c设置,mod_cgid提供使用cgid进行通讯的UNIX套接字的
    # 脚本接口路径。
    #
    # Scriptsock logs/cgisock
    </IfModule>

    #
    # 将"/usr/local/apache2/cgi-bin"改为你的ScriptAliased指定的CGI目录,
    # 如果你配置了的话。
    #
    <Directory "/usr/local/apache2/cgi-bin">
    AllowOverride None
    Options None
    Order allow,deny
    Allow from all
    </Directory>

    #
    # Redirect允许你告诉客户端使用存在于服务器名字空间中的文档,
    # 而不是现在的,这帮助客户定位那些改变了位置的文档。
    # 例如:
    # Redirect permanent /foo http://www.example.com/bar

    #
    # 控制server-generated目录列表显示的指令
    #

    #
    # IndexOptions:控制server-generated目录列表显示特征。
    #
    IndexOptions FancyIndexing VersionSort

    #
    # AddIcon* 指令告诉服务器不同扩展名的图象文件如何显示,
    # 只适用于FancyIndexed指令
    #
    AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip
    AddIconByType (TXT,/icons/text.gif) text/*
    AddIconByType (IMG,/icons/image2.gif) image/*
    AddIconByType (SND,/icons/sound2.gif) audio/*
    AddIconByType (VID,/icons/movie.gif) video/*

    AddIcon /icons/binary.gif .bin .exe
    AddIcon /icons/binhex.gif .hqx
    AddIcon /icons/tar.gif .tar
    AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv
    AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip
    AddIcon /icons/a.gif .ps .ai .eps
    AddIcon /icons/layout.gif .html .shtml .htm .pdf
    AddIcon /icons/text.gif .txt
    AddIcon /icons/c.gif .c
    AddIcon /icons/p.gif .pl .py
    AddIcon /icons/f.gif .for
    AddIcon /icons/dvi.gif .dvi
    AddIcon /icons/uuencoded.gif .uu
    AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl
    AddIcon /icons/tex.gif .tex
    AddIcon /icons/bomb.gif core

    AddIcon /icons/back.gif ..
    AddIcon /icons/hand.right.gif README
    AddIcon /icons/folder.gif ^^DIRECTORY^^
    AddIcon /icons/blank.gif ^^BLANKICON^^

    #
    # DefaultIcon 为那些没有显式定义图标的文件提供处理
    #
    DefaultIcon /icons/unknown.gif

    #
    # AddDescription允许你在server-generated索引后放置一个简短的说明。
    # 只对FancyIndexed指令有效。
    # 格式:AddDescription "说明" 文件名
    #
    # AddDescription "GZIP compressed document" .gz
    # AddDescription "tar archive" .tar
    # AddDescription "GZIP compressed tar archive" .tgz

    #
    # ReadmeName指定服务器默认查找的README文件的名字,并添加到目录列表中
    #
    # HeaderName指定目录列表前缀文件的文件名
    ReadmeName README.html
    HeaderName HEADER.html

    #
    # IndexIgnore指定目录索引忽略并且不包含在列表中的文件名集合,
    # 支持shell类型的通配符。
    #
    IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t

    #
    # AddEncoding允许你在信息传送中使用(Mosaic/X 2.1+)解压缩信息,
    # 注意:不是所有的浏览器都支持这个选项。
    # 尽管名字相似,但是下列的指令与上面的FancyIndexing定制指令不同。
    #
    AddEncoding x-compress Z
    AddEncoding x-gzip gz tgz

    #
    # DefaultLanguage和AddLanguage允许你指定文档的语言。
    # 这使你可以让用户用容易理解的语言浏览文档。
    #
    # 指定默认的语言,这意味着所有没有指定语言的包都将使用该语言。
    # 多数情况下,你也许并不想设置它,除非你确信这样做是正确的。
    # 通常,不使用确定的语言比使用错误的语言要好。
    #
    # DefaultLanguage nl
    #
    # 注意1:作为语言关键字的词缀毫无疑问是不能一样的--采用波兰
    # 文的文档(网络标准语言代码是pl)将希望使用“AddLanguage pl .po”
    # 来避免与perl脚本的一般词缀产生二义性。
    #
    # 注意2: 下面的例子举例说明在一些范例中语言的二字符缩写与它的国家
    # 的二字符缩写不相同,例如 “Danmark/dk” 和 “Danmark/da” 的比较.
    #
    # 注意3: 在 “ltz” 的情况下我们使用三字符词缀,违犯了 RFC的规定,
    # 运行中将修复它并使用RFC1766标准取得参考数据。
    #
    # Danish (da) - Dutch (nl) - English (en) - Estonian (et)
    # French (fr) - German (de) - Greek-Modern (el)
    # Italian (it) - Norwegian (no) - Norwegian Nynorsk (nn) - Korean (ko)
    # Portugese (pt) - Luxembourgeois* (ltz)
    # Spanish (es) - Swedish (sv) - Catalan (ca) - Czech(cz)
    # Polish (pl) - Brazilian Portuguese (pt-br) - Japanese (ja)
    # Russian (ru) - Croatian (hr)
    #
    AddLanguage da .dk
    AddLanguage nl .nl
    AddLanguage en .en
    AddLanguage et .et
    AddLanguage fr .fr
    AddLanguage de .de
    AddLanguage he .he
    AddLanguage el .el
    AddLanguage it .it
    AddLanguage ja .ja
    AddLanguage pl .po
    AddLanguage ko .ko
    AddLanguage pt .pt
    AddLanguage nn .nn
    AddLanguage no .no
    AddLanguage pt-br .pt-br
    AddLanguage ltz .ltz
    AddLanguage ca .ca
    AddLanguage es .es
    AddLanguage sv .sv
    AddLanguage cz .cz
    AddLanguage ru .ru
    AddLanguage tw .tw
    AddLanguage zh-tw .tw
    AddLanguage hr .hr

    # LanguagePriority允许你在会话过程中优先使用一些语言。
    #
    # 以优先次序递减的方式列出它们。我们或多或少地采用按字母排列顺序的方式
    # 排列它们。也许你想要改变这个顺序。
    LanguagePriority en da nl et fr de el it ja ko no pl pt pt-br ltz ca es sv tw

    #
    # ForceLanguagePriority 允许你为MULTIPLE CHOICES(Prefer)[在通讯的情况下]
    # 或NOT ACCEPTABLE(Fallback)[没有可接受的语言匹配的情况]提供一个结果页。
    #
    ForceLanguagePriority Prefer Fallback

    #
    # 为发送出的所有页指定默认的字符集,这总是一个好主意,并且为你的
    # web站点的国际化打开了大门,这不正是你曾经想要的吗。同样地,指定
    # 默认字符集有一些小的损害,如一个使用iso-8859-1(latin1)标准命令
    # 的页面,除非以别的方式指定例如你仅仅以显式方式声明它。
    # 也有一些与那些总是鼓励你使用默认字符集的javascropt和URL语法有关
    # 的浏览器安全原因。
    #
    #AddDefaultCharset ISO-8859-1
    AddDefaultCharse GB2312

    #
    # 一般以文件扩展名的方式使用字符集。也许你想要避免与语言扩展发生
    # 碰撞,除非你在每次改变后都做了很好的测试。
    # 参见http://www.iana.org/assignments/character-sets以取得字符集
    # 的名字列表和它们各自的RFCs。
    #
    AddCharset ISO-8859-1 .iso8859-1 .latin1
    AddCharset ISO-8859-2 .iso8859-2 .latin2 .cen
    AddCharset ISO-8859-3 .iso8859-3 .latin3
    AddCharset ISO-8859-4 .iso8859-4 .latin4
    AddCharset ISO-8859-5 .iso8859-5 .latin5 .cyr .iso-ru
    AddCharset ISO-8859-6 .iso8859-6 .latin6 .arb
    AddCharset ISO-8859-7 .iso8859-7 .latin7 .grk
    AddCharset ISO-8859-8 .iso8859-8 .latin8 .heb
    AddCharset ISO-8859-9 .iso8859-9 .latin9 .trk
    AddCharset ISO-2022-JP .iso2022-jp .jis
    AddCharset ISO-2022-KR .iso2022-kr .kis
    AddCharset ISO-2022-CN .iso2022-cn .cis
    AddCharset Big5 .Big5 .big5
    # 对于俄语,使用了多个字符集(如何使用主要依靠客户端):
    AddCharset WINDOWS-1251 .cp-1251 .win-1251
    AddCharset CP866 .cp866
    AddCharset KOI8-r .koi8-r .koi8-ru
    AddCharset KOI8-ru .koi8-uk .ua
    AddCharset ISO-10646-UCS-2 .ucs2
    AddCharset ISO-10646-UCS-4 .ucs4
    AddCharset UTF-8 .utf8


    # 下面的字符集没有映射到一个特定的标准(iso)上,但是它们在浏览器
    # 中被广泛的支持。注意那些大写字母。
    # (它不应该,但是它是为兼容一些浏览器而做)
    #
    # 参见http://www.iana.org/assianments/character-sets以取得
    # 它们的列表。但是浏览器支持较少。
    #
    AddCharset GB2312 .gb2312 .gb
    AddCharset utf-7 .utf7
    AddCharset utf-8 .utf8
    AddCharset big5 .big5 .b5
    AddCharset EUC-TW .euc-tw
    AddCharset EUC-JP .euc-jp
    AddCharset EUC-KR .euc-kr
    AddCharset shift_jis .sjis

    #
    # AddType允许你为指定的文件类型添加或覆盖mime.types文件中配置的MIME
    #
    AddType application/x-tar .tgz
    AddType image/x-icon .ico

    #
    # AddHandler允许你映射确定的文件扩展名到“handlers”:
    # 与文件类型无关的行为。这既能编译到服务器中也可以添加到Action指令
    # 中(看下面)。
    # 为了在ScriptAliased指令指定的以外使用CGI脚本:
    #(要使它可用,你还需要在Options中添加“ExecCGI”。
    #
    # AddHandler cgi-script .cgi

    #
    # 对于那些包含他们自己的HTTP头的文件
    #
    # AddHandler send-as-is asis

    #
    # 对于server-parsed imagemap文件:
    #
    # AddHandler imap-file map

    #
    # agemap 文件:
    #
    #AddHandler imap- 文件映像

    #
    # 对于类型映像:(转移资源)
    #(这是默认的设定以允许Apache的“It Worked”页能多种语言分发)。
    #
    AddHandler type-map var

    #
    # 过滤器允许你在将它发送到客户端前进行处理。
    #
    # 为了在服务器端分析包含(SSI)的.shtml文档:
    # (要执行这个指令,你还需要在Options指令中添加“Includes”。)
    #
    # AddType text/html .shtml
    # AddOutputFilter INCLUDES .shtml

    #
    # Action让你定义当调用匹配的媒体文件时将要执行的脚本。这将减少
    # 那些经常使用的CGI脚本的URL路径名的重复输入。
    # 格式:Action media/type /cgi-script/location
    # 格式:Action handler-name /cgi-script/location
    #

    #
    # 可配置的错误应答有三种风格:
    # 1)plain text 2)local redirects 3) external redirects
    #
    # 一些示例:
    # ErrorDocument 500 "The server made a boo boo."
    # ErrorDocument 404 /missing.html
    # ErrorDocument 404 "/cgi-bin/missing_handler.pl"
    # ErrorDocument 402 http://www.example.com/subscription_info.html
    #

    #
    # 综合应用这些指令,我们可以创建一个国际化的出错应答。
    #
    # 我们使用Alias来重定向任意/error/HTTP_<error>.html.var应答到
    # 我们的多语言错误消息集合。使用正确的文本替代它。
    #
    # 通过加入下面的行,你就能够改变这些消息的显示,而不必改变
    # HTTP_<error>.html.var文件。
    #
    # Alias /error/include/ "/your/include/path/"
    #
    # 以将/usr/local/apache2/error/include/下的文件拷贝到/your/inclue/path/下
    # 开始,你可以创建你自己的文件集合,甚至是其于每个虚拟主机的。
    # 不管你的ServerSignature如何设置,默认的包含文件将显示你的
    # Aapche版本号和你的ServerAdmin邮件地址
    #
    # 国际化的错误文档需要mod_alias,mod_include和mod_negotiation三个
    # 模块。要激活它们,取消下面30行的注释符号

    # Alias /error/ "/usr/local/apache2/error/"
    #
    # <Directory "/usr/local/apache2/error">
    # AllowOverride None
    # Options IncludesNoExec
    # AddOutputFilter Includes html
    # AddHandler type-map var
    # Order allow,deny
    # Allow from all
    # LanguagePriority en de es fr it nl sv
    # ForceLanguagePriority Prefer Fallback
    # </Directory>
    #
    # ErrorDocument 400 /error/HTTP_BAD_REQUEST.html.var
    # ErrorDocument 401 /error/HTTP_UNAUTHORIZED.html.var
    ErrorDocument 403 /error.php
    # ErrorDocument 404 /error/HTTP_NOT_FOUND.html.var
    # ErrorDocument 405 /error/HTTP_METHOD_NOT_ALLOWED.html.var
    # ErrorDocument 408 /error/HTTP_REQUEST_TIME_OUT.html.var
    # ErrorDocument 410 /error/HTTP_GONE.html.var
    # ErrorDocument 411 /error/HTTP_LENGTH_REQUIRED.html.var
    # ErrorDocument 412 /error/HTTP_PRECONDITION_FAILED.html.var
    # ErrorDocument 413 /error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var
    # ErrorDocument 414 /error/HTTP_REQUEST_URI_TOO_LARGE.html.var
    # ErrorDocument 415 /error/HTTP_SERVICE_UNAVAILABLE.html.var
    # ErrorDocument 500 /error/HTTP_INTERNAL_SERVER_ERROR.html.var
    # ErrorDocument 501 /error/HTTP_NOT_IMPLEMENTED.html.var
    # ErrorDocument 502 /error/HTTP_BAD_GATEWAY.html.var
    # ErrorDocument 503 /error/HTTP_SERVICE_UNAVAILABLE.html.var
    # ErrorDocument 506 /error/HTTP_VARIANT_ALSO_VARIES.html.var

    #
    # 下面的命令更改标准的HTTP应答行为以处理己知的浏览器问题。
    #
    BrowserMatch "Mozilla/2" nokeepalive
    BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
    BrowserMatch "RealPlayer 4\.0" force-response-1.0
    BrowserMatch "Java/1\.0" force-response-1.0
    BrowserMatch "JDK/1\.0" force-response-1.0

    #
    # 下面命令关闭对那些没有尾部“/”的目录的非GET请求的重定向,
    # 这些命令修复了微软的采用DAV方法不能正确处理重定向的WEB文件夹的问题。
    # Apple下的DAV文件系统和Gnome下的VFS对DAV的支持也是采用这样的方法
    # 进行处理的。
    #
    BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
    BrowserMatch "^WebDrive" redirect-carefully
    BrowserMatch "^WebDAVFS/1.[012]" redirect-carefully
    BrowserMatch "^gnome-vfs" redirect-carefully

    #
    # 允许你使用URL:http://servername/server-status来通过mod_status生
    # 成并报告服务器状态信息。改变.example.com为你自己的域名。
    #
    # <Location /server-status>
    # SetHandler server-status
    # Order deny,allow
    # Deny from all
    # Allow from .example.com
    # </Location>

    #
    # 允许使用URL:http://servername/server-info来远程报告服务器配置信息
    # (需要mod_info.c支持)。改变“.example.com”为你自己的域名。
    #
    # <Location /server-info>
    # SetHandler server-info
    # Order deny,allow
    # Deny from all
    # Allow from .example.com
    # </Location>

    #
    # 代理服务器命令,去掉下面的行使代理服务可用。
    #
    # <IfModule mod_proxy.c>
    # ProxyRequests On
    # <Proxy *>
    # Order deny,allow
    # Deny from all
    # Allow from .example.com
    # </Proxy>

    #
    # 安装或关闭HTTP/1.1“通道”头处理。
    # (“Full”添加服务器版本信息,“Block”移掉所有输出“通道”头信息。
    # 可以设为下面各选项之一:Off | On | Full | Block
    #
    # ProxyVia On

    # 最好为代理服务安装高速缓冲,去掉下面几行的注释符号:
    # (没有CacheRoot则不缓冲)
    #
    # CacheRoot "/usr/local/apache2/proxy"
    # CacheSize 5
    # CacheGcInterval 4
    # CacheMaxExpire 24
    # CacheLastModifiedFactor 01
    # CacheDefaultExpire 1
    # NoCache a-domain.com another-domain.edu joes.garage-sale.com

    # </IfModule>
    # 代理命令结束。

    #
    # 附加的特定模块配置。
    #
    <IfModule mod_ssl.c>
    Include conf/ssl.conf
    </IfModule>

    ## 第三区:虚拟主机
    #
    # VirtualHost:你可以通过设置虚拟主机容器以实现在你的主机上保有多个
    # 域名/主机名。大多数配置信息只使用基于名字的虚拟主机,因此服务器
    # 不必担心IP地址的问题,下面的命令以*号代替虚拟主机名。
    #
    # 在你试着配置你的虚拟主机以前,请参见
    # URL:http://httpd.apache.org/docs-2.0/vhosts/>以取得更多的信息。
    #
    # 你可以使用命令行选项“-S”来检验你的虚拟主机配置。

    #
    # 使用基于名字的虚拟主机。
    #
    # NameVirtualHost *

    #
    # 虚拟主机示例:
    # 几乎所有的Apache命令都可以在虚拟主机容器中使用。
    # 第一个虚拟主机区是用于向服务名未知的请求进行应答的配置。
    #
    # <VirtualHost *>
    # ServerAdmin webmaster@dummy-host.example.com
    # DocumentRoot /www/docs/dummy-host.example.com
    # ServerName dummy-host.example.com
    # ErrorLog logs/dummy-host.example.com-error_log
    # CustomLog logs/dummy-host.example.com-access_log commom
    # </virtualHost>

     发表于 14:56:15  阅读全文  |  评论(0)  |  Trackback(1)  | 编辑
     
    2005-12-27
    Tag:注册表 Registry 菜单 MENU

    REGEDIT4

    ;恢复IE的标题及主页
    [HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main]
    "Window Title"="Internet Explorer"
    "Start Page"="about:blank"
    "Local Page"="about:blank"
    "Search Page"="about:blank"
    "First Home Page"=-
    "ChannelsFirstURL"=-
    "ChannelsURL"=-
    "Search Bar"=-
    "Default_Search_URL"=-
    "Default_Page_URL"=-

    [HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Main]
    "Window Title"="Internet Explorer"
    "Start Page"="about:blank"
    "Default_Page_URL"="about:blank"
    "Default_Search_URL"= "about:blank"
    "Local Page"="about:blank"
    "Search Page"="about:blank"


    ;清除IE的“分级审查”密码
    [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\Ratings]
    "Key"=-


    ;恢复右键菜单功能(多种)
    [HKEY_CURRENT_USER\Software\Policies\Microsoft\Internet Explorer\Restrictions]
    "NoBrowserContextMenu"=dword:00000000

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoChangeStartMenu"=dword:00000000

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoTrayContextMenu"=dword:00000000

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoViewContextMenu"=dword:00000000

    ;解除IE的“Internet选项”及其对话框中所有属性设置的禁用
    [HKEY_CURRENT_USER\Software\Policies\Microsoft\Internet Explorer\Restrictions]
    "NoBrowserOptions"=dword:00000000

    [HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Internet Explorer\Restrictions]
    "NoBrowserOptions"=dword:00000000

    [-HKEY_CURRENT_USER\Software\Policies\Microsoft\Internet Explorer\Control Panel]


    ;解除资源管理器“文件夹选项”的禁用
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoFolderOptions"=dword:00000000


    ;解除“开始”菜单中的各种屏蔽
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoRun"=dword:00000000
    "NoFind"=dword:00000000
    "NoClose"=dword:00000000
    "NoFavoritesMenu"=dword:00000000
    "NoSetFolders"=dword:00000000
    "NoRecentDocsMenu"=dword:00000000
    "NoLogOff"=hex:00,00,00,00

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\WinOldApp]
    "NoRealMode"=dword:00000000

    ;解除“显示属性”及“任务栏属性”的禁用
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]
    "NoDispCPL"=dword:00000000
    "NoDisp BackgroundPage"=dword:00000000
    "NoDispAppearancePage"=dword:00000000
    "NoDispScrSavPage"=dword:00000000
    "NoDispSettingsPage"=dword:00000000

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoSetTaskbar"=dword:00000000


    ;解除注册表编辑器的禁用
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]
    "DisableRegistryTools"=dword:00000000


    ;解除“我的电脑”中驱动器的隐藏
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoDrives"=hex:00,00,00,00


    ;解除桌面的隐藏
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoDesktop"=dword:00000000


    ;解除MS-DOS窗口的限制
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\WinOldApp]
    "Disabled"=dword:00000000

    ;解除系统属性中“设备管理器”及“性能”的屏蔽
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System]
    "NoDevMgrPage"=dword:00000000
    "NoFileSysPage"=dword:00000000
    "NoVirtMemPage"=dword:00000000


    ;解除“网络属性”的禁用及其设置项的屏蔽
    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoNetSetup"=dword:00000000

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Network]
    "NoEntireNetwork"=dword:00000000
    "NoNetSetupIDPage"=dword:00000000
    "NoNetSetupSecurityPage"=dword:00000000
    "NoWorkgroupContents"=dword:00000000
    "NoFileSharingControl"=dword:00000000




    ;取消系统启动时的对话框
    [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Winlogon]
    "LegalNoticeCaption"=""
    "LegalNoticeText"=""

    ;恢复桌面上IE、“我的文档”等系统级图标
    [HKEY_LOCAL_MACHINE\Software\CLASSES\CLSID\{871C5380-42A0-1069-A2EA-08002B30309D
    }\ShellFolder]
    "Attributes"=dword:00000024

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Documents]
    "HideMyDocsFolder"=-

    [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\explorer\Desktop\NameSpace\{450d8fba-ad25-11d0-98a8-0800361b1103}]
    @="我的文档"

    [HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\explorer\Desktop\NameSpace\{645FF040-5081-101B-9F08-00AA002F954E}]
    @="回收站"

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer]
    "NoNetHood"=dword:00000000


    ;清除“按Web页方式查看活动桌面”里的网址
    [-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Desktop\Components]

    [HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer]
    "ShellState"=-


    ;恢复任务栏中的日期格式
    [HKEY_CURRENT_USER\Control Panel\International]
    "sTimeFormat"="H:mm:ss"
    "s1159"="上午"
    "s2359"="下午"
    "iTime"="0"
    "iTLZero"="1"
    "sTime"=":"


    ;清除IE右键里多余的菜单
    [-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt]


    ;去掉IE“工具”菜单里多余的选项
    [-HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Extensions]

    [-HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer\Extensions]



    ;允许导入REG文件
    [HKEY_LOCAL_MACHINE\Software\Classes\.reg]
    @="regfile"
    [HKEY_LOCAL_MACHINE\Software\Classes\regfile\shell\open\command]
    @="regedit.exe \"%1\""

    ;解除IE的“文件”等菜单里的各项屏蔽
    [-HKEY_CURRENT_USER\Software\Policies\Microsoft\Internet Explorer\Restrictions]

    [-HKEY_LOCAL_MACHINE\Software\Policies\Microsoft\Internet Explorer\Restrictions]


    ;恢复Outlook Express的标题
    [HKEY_CURRENT_USER\Software\Microsoft\Outlook Express]
    "WindowTitle"=""

     发表于 14:53:20  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2005-12-27
    Tag:Linux 进程管理 process

    在Linux系统里,当前正在运行的程序实例称为进程。比如,当你启动Apache的时候,系统会为它分配一个进程ID。然后就可以用这个ID监视和控制这个程序。   

      进程监视和控制是任何Linux系统管理员的核心任务。一个管理员可以终止("kill")、重启一个进程,甚至可以为它指定一个不同的优先级。标准的Linux命令"ps""top"通常用于查看当前的进程列表。下面我来说明如何用这些命令和其它命令来管理Linux系统中的进程。   

      用ps监视进程 

      一个监视Linux的标准工具就是"ps",它是进程状态的简称。这个命令返回正在运行的程序的信息。这些信息可能包括程序是在哪个用户名下运行的,使用了多少CPU以及运行了多长时间。如果你要手工终止程序或者确定是哪个程序让系统变慢时,这些信息是很有用的。   

      如果你只是键入了"ps"这个命令,那么只能列出运行在当前终端下的进程。下面的例子是通过远程shell运行"ps"输出的结果: 

      $ ps 

      PID TTY TIME CMD 

      4684 pts/14 00:00:00 bash 

      27107 pts/14 00:00:00 ps   

      从输出可以看出,分配给这个用户/终端的进程只有Bash shell和ps命令本身。你还可以看到为每个进程列出的PID(进程ID)和TTY、TIME和CMD。TTY指明这个进程正在运行在哪个终端上,TIME指明了这个进程已经使用了多少CPU时间,CMD则是启动这个进程的命令名称。   

      用户可以看到,标准的ps命令只能列出基本的信息。要想获得Linux系统上运行的进程的详细信息,你必须加入一些命令行参数。   

      加入ps常用的aux参数后可以显示其他用户启动的进程(a)、查看系统中属于自己的进程(x)以及启动这个进程的用户和它启动的时间(u)。   

      现在还有其它更多的信息,增加了USER、 %CPU、%MEM、 VSZ、RSS、STAT和START这几个域。现在我们来看一下这些信息是什么含义。   

       首先,用户可以看到所有的进程,而不仅仅是运行在终端上的那些。USER域指明了是哪个用户启动了这个命令。很多进程和系统一起启动,而且会把根或者一些系统帐号列为USER。当然,其它一些进程是单独运行的。这个信息本身就可以帮助你缩小问题范围。假如某个用户启动了脚本,占用了服务器大量的I/O。如果能马上找到是谁在运行这个程序,那么就可以大大加快解决问题的速度。   

      %CPU、 %MEM、VSZ和RSS这几个域都与系统资源有关。首先,用户可以查看某个进程占用了多少CPU。这个信息是实时显示的,所以很难用ps捕捉峰值。可能用户会发现,为了找到引发问题的那个进程需要不停地运行ps命令。   

      除了CPU使用情况,还可以看到内存使用及其VSZ(虚拟内存大小)和RSS(常驻集大小)。VSZ表示如果一个程序完全驻留在内存的话需要占用多少内存空间,而RSS指明了当前实际占用了多少内存。如果能够了解一个进程当前占用了多少内存,那么就可以确定这个进程是在正常运行还是出现了异常。程序通常都会消耗比正常情况更多的内存和CPU。虽然程序员都在尽力确保代码正确地使用资源,但是有时候还是要由管理员来决定终止还是重启进程。   

      用户可能会注意到在ps aux命令的输出结果里,大部分TTY域有个""。这是因为这些程序或者在系统启动的时候就开始运行了,或者是由初始化脚本(init script)启动的。这些进程没有控制终端,所以作了标记。另外,linux-sanity-check命令有一个TTY的值为pts/14。这个命令是远程连接运行的,有与其关联的一个终端。当你的机器开放了多条连接,而你又想确定某个命令运行在哪个窗口的时候,这个信息是很有用的。   

      STAT显示了进程当前的状态。在我们的例子里,很多进程处在睡眠状态,STAT域里的"S"指明了这一状态。这仅仅表明这些进程在等待某些事件发生--可能是用户输入或者系统资源的可用性。linux-sanity-check命令则有一个R状态,这个状态表明进程当前正在运行。有时候你可以浏览一下这个列表然后找那些R状态的进程。如果大部分进程处在睡眠状态而又有问题发生,那么只关注那些正在运行的进程是最好的方法。那种状态不一定能说明发生了问题,但是有时候如果进程运行的时间过长可能意味着发生了某些深层次的问题。 


     发表于 14:30:42  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2005-12-26
    Tag:Java XML SAX

    从来都只熟练DOM,很少用SAX。这次碰到一个巨型的XML文本要处理,迫不得已要研究一些SAX,其实也不复杂。还是用sample说话吧。

    1、从文件系统获取文件的过程:

    InputSource is=new InputSource(new FileReader("D:/temp/data.txt"));
      ParserAdapter pa=new ParserAdapter(new XMLReaderAdapter());
      MySaxHandler handler=new MySaxHandler("item");
      pa.setContentHandler(handler);
      pa.parse(is);
      System.out.println(handler.getElementCount()+" elements matched.");

    // 其中MySaxHandler 是一个自定义的类,继承DefaultHandler类,我覆盖了几个方法:

    // 构建器,记住要计算的元素的名字

    public MySaxHandler(String countElementName) {
      this.countElementName=countElementName;
     }

    // 元素开始的时间,判断名字是不是等于指定的,是则自增1

    public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {

      if (localName.equals(countElementName)) {
       elecount++;
       dataPointer=0;
      }
      //System.out.println("elementLocalName="+localName);
     }

    // 返回最后统计结果的

    public int getElementCount() {
      return elecount;
     }

    基本上就上面那样了。对统计已经足够了。另外还有一个关键的方法:

     public void characters(char[] ch, int start, int length) throws SAXException {
      if (dataPointer>=0) {
        System.out.println(new String(ch,start,length));
      }

    这个方法实际表示element体内的文本内容,要注意文本内容可能分多次提供的,就是这个方法会被调用多次,要得到全部内容,参考上面那样前后连接起来即可。(当然前提是你要对当前是在哪个element里面要心中有数)


     发表于 18:37:37  阅读全文  |  评论(1)  |  Trackback(0)  | 编辑
     
    2005-12-23
    Tag:JavaScript HTML 相册 自动播放 ALBUM

    写了个SlideShow的原型,利用image的complete,判断图片是否调用完全,调用完全以后才显示,否则是LOADING的图片,还考虑的是
    1.每调用一张图片之前先出现loading的过程,
    2.调用图片中不会因为网速和图片过大而未显示全,直接跳到下一张,要按顺序一张一张播放.
    3.第一次 播放的时候,因为调用图片会慢一点,重新播放是调用CACHE里的,速度就快了

    代码如下:
    在线运行演示

    <html>
    <head>
    <title>SlideShow</title>
    <script language="JavaScript1.1">
    <!--
    var yourImages = new Array("http://blog.donews.com/images/blog_donews_com/dodo/79382/o_5540320040330075952.jpg","http://www.iqoo.com/tupian/%D0%C7%D7%F9%B1%DA%D6%BD/iqoo_1113__aries.jpg","http://blog.donews.com/images/blog_donews_com/dodo/79382/o_5540320040330081327.jpg","http://blog.donews.com/images/blog_donews_com/dodo/79382/o_5540320040330081426.jpg")

    var currCount=0 
    var stop=false

    function getimg(n){
    preImages= new Image()
    preImages.src = yourImages[n]
    }


    function autoPlay(){
    if(currCount!=yourImages.length){
    document.getElementById("img").style.display="none"
    getimg(currCount)
    document.getElementById("loadingbar").style.display="block"
    setTimeout("loadingImg()",1000)
    }
    else{
    currCount=0;
    if (confirm("播放完毕,是否重新播放?")){
    return autoPlay()
    }
    }
    }

    function loadingImg(){

    if (preImages.complete) {
      document.getElementById("img").src="http://blog.donews.com/images/blog_donews_com/dodo/49134/o_pix.gif"
      document.getElementById("loadingbar").style.display="none"
      
      document.getElementById("img").style.display="block"
      
      document.getElementById("img").src=yourImages[currCount]
      currCount=currCount+1
      }
    setTimeout("autoPlay()",4000)
    }

    //-->
    </script>

    </head>

    <body bgcolor="#FFFFFF">
    <div style="width:700px">
    <center>
    <a href="javascript:autoPlay()">自动播放</a><br><br>
    <div id="loadingbar"  style="display:none;"><img src=http://blog.donews.com/images/blog_donews_com/dodo/49134/o_loading.gif></div>
    <img id="img" src=http://blog.donews.com/images/blog_donews_com/dodo/49134/o_pix.gif >

    <center>
    </div>

    </body>
    </html>


     发表于 09:52:57  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2005-12-22
    Tag:cron crontab Linux

    cron 是一个可以用来根据时间、日期、月份、星期的组合来调度对重复任务的执行的守护进程。

    cron 假定系统持续运行。如果当某任务被调度时系统不在运行,该任务就不会被执行。要调度一次性的任务,请参阅第 37.2 节

    要使用 cron 服务,你必须安装了 vixie-cron RPM 软件包,而且必须在运行 crond 服务。要判定该软件包是否已安装,使用 rpm -q vixie-cron 命令。要判定该服务是否在运行,使用 /sbin/service crond status 命令。

    37.1.1. 配置 cron 任务

    cron 的主配置文件是 /etc/crontab,它包括下面几行:

    SHELL=/bin/bash
    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    MAILTO=root
    HOME=/
    
    # run-parts
    01 * * * * root run-parts /etc/cron.hourly
    02 4 * * * root run-parts /etc/cron.daily
    22 4 * * 0 root run-parts /etc/cron.weekly
    42 4 1 * * root run-parts /etc/cron.monthly

    前四行是用来配置 cron 任务运行环境的变量。SHELL 变量的值告诉系统要使用哪个 shell 环境(在这个例子里是 bash shell);PATH 变量定义用来执行命令的路径。cron 任务的输出被邮寄给 MAILTO 变量定义的用户名。如果 MAILTO 变量被定义为空白字符串(MAILTO=""),电子邮件就不会被寄出。HOME 变量可以用来设置在执行命令或脚本时使用的主目录。

    /etc/crontab 文件中的每一行都代表一项任务,它的格式是:

    minute   hour   day   month   dayofweek   command

    • minute — 分钟,从 0 到 59 之间的任何整数

    • hour — 小时,从 0 到 23 之间的任何整数

    • day — 日期,从 1 到 31 之间的任何整数(如果指定了月份,必须是该月份的有效日期)

    • month — 月份,从 1 到 12 之间的任何整数(或使用月份的英文简写如 jan、feb 等等)

    • dayofweek — 星期,从 0 到 7 之间的任何整数,这里的 0 或 7 代表星期日(或使用星期的英文简写如 sun、mon 等等)

    • command — 要执行的命令(命令可以是 ls /proc >> /tmp/proc 之类的命令,也可以是执行你自行编写的脚本的命令。)

    在以上任何值中,星号(*)可以用来代表所有有效的值。譬如,月份值中的星号意味着在满足其它制约条件后每月都执行该命令。

    整数间的短线(-)指定一个整数范围。譬如,1-4 意味着整数 1、2、3、4。

    用逗号(,)隔开的一系列值指定一个列表。譬如,3, 4, 6, 8 标明这四个指定的整数。

    正斜线(/)可以用来指定间隔频率。在范围后加上 /<integer> 意味着在范围内可以跳过 integer。譬如,0-59/2 可以用来在分钟字段定义每两分钟。间隔频率值还可以和星号一起使用。例如,*/3 的值可以用在月份字段中表示每三个月运行一次任务。

    开头为井号(#)的行是注释,不会被处理。

    如你在 /etc/crontab 文件中所见,它使用 run-parts 脚本来执行 /etc/cron.hourly/etc/cron.daily/etc/cron.weekly/etc/cron.monthly 目录中的脚本,这些脚本被相应地每小时、每日、每周、或每月执行。这些目录中的文件应该是 shell 脚本。

    如果某 cron 任务需要根据调度来执行,而不是每小时、每日、每周、或每月地执行,它可以被添加到 /etc/cron.d 目录中。该目录中的所有文件使用和 /etc/crontab 中一样的语法。范例请参见例 37-1

    # record the memory usage of the system every monday 
    # at 3:30AM in the file /tmp/meminfo
    30 3 * * mon cat /proc/meminfo >> /tmp/meminfo
    # run custom script the first day of every month at 4:10AM
    10 4 1 * * /root/scripts/backup.sh

    例 37-1. crontab 的例子

    根用户以外的用户可以使用 crontab 工具来配置 cron 任务。所有用户定义的 crontab 都被保存在 /var/spool/cron 目录中,并使用创建它们的用户身份来执行。要以某用户身份创建一个 crontab 项目,登录为该用户,然后键入 crontab -e 命令,使用由 VISUALEDITOR 环境变量指定的编辑器来编辑该用户的 crontab。该文件使用的格式和 /etc/crontab 相同。当对 crontab 所做的改变被保存后,该 crontab 文件就会根据该用户名被保存,并写入文件 /var/spool/cron/username 中。

    cron 守护进程每分钟都检查 /etc/crontab 文件、etc/cron.d/ 目录、以及 /var/spool/cron 目录中的改变。如果发现了改变,它们就会被载入内存。这样,当某个 crontab 文件改变后就不必重新启动守护进程了。

    37.1.2. 控制对 cron 的使用

    /etc/cron.allow/etc/cron.deny 文件被用来限制对 cron 的使用。这两个使用控制文件的格式都是每行一个用户。两个文件都不允许空格。如果使用控制文件被修改了,cron 守护进程(crond)不必被重启。使用控制文件在每次用户添加或删除一项 cron 任务时都会被读取。

    无论使用控制文件中的规定如何,根用户都总是可以使用 cron。

    如果 cron.allow 文件存在,只有其中列出的用户才被允许使用 cron,并且 cron.deny 文件会被忽略。

    如果 cron.allow 文件不存在,所有在 cron.deny 中列出的用户都被禁止使用 cron。

    37.1.3. 启动和停止服务

    要启动 cron 服务,使用 /sbin/service crond start 命令。要停止该服务,使用 /sbin/service crond stop 命令。推荐你在引导时启动该服务。


     发表于 09:45:41  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2005-12-21
    Tag:Linux Fedora

    一台旧机装了好多次都不成功,google一下原来因为RedHat对旧款CD-ROM的驱动支持很差。只好从硬盘装了。

    用了Grub for Dos也是不成,后来用第一张碟上的一个iso映象烧了张启动盘,启动之后再选择从硬盘安装。OK!搞定了。


     发表于 09:36:36  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2005-12-20
    Tag:Linux Fedora redhat install

    从硬盘安装Fedora Core 4

    由于我的IBM240没有光驱,所以安装Fedora Core 4我选择硬盘安装,但Fedora Core 4跟redhat 9.0的硬盘安装方法有所不同,redhat不需要要安装其他软件,只要把光盘的某个目录拷贝出,然后dos下启动就可以安装,但到了Fedora Core 已经没了类似的目录,所以硬盘安装模式有点变化。

    1:首先当然是下载Fedora Core 4的光盘镜像了,很多地方可以下载,这里提供一个

    ftp://mirror.switch.ch/mirror/fedor...-i386-disc1.iso
    ftp://mirror.switch.ch/mirror/fedor...-i386-disc2.iso
    ftp://mirror.switch.ch/mirror/fedor...-i386-disc3.iso
    ftp://mirror.switch.ch/mirror/fedor...-i386-disc4.iso

    2:把CD1的isolinux目录解压到c:下

    3:下载Grub For Dos
    ftp://ftp2.linuxeden.com/tools/grub_for_dos-0.2.0pre13.tar.gz
    解压把里面的文件和文件夹剪切出,放在解压后目录的外边.此时的路径为:C:boot

    4:修改boot.ini
    最后面添加这么一行
    C:grldr="GRUB For Dos

    保存退出

    5:修改C:bootgrubmenu.lst

    添加这么几行

    title Install-Fedora Core 4
    kernel (hd0,0)/isolinux/vmlinuz
    initrd (hd0,0)/isolinux/initrd.img

    注意:我的C盘这里是hd0,0表示第一个ide硬盘第一个分区,大家可根据自己的需要修改硬盘参数

    ok,重新启动系统,会看到GRUB For Dos 菜单,选择后,在安装媒介选择硬盘安装就行。


     发表于 16:53:27  阅读全文  |  评论(2)  |  Trackback(0)  | 编辑
     
    2005-12-20
    Tag:HTML JavaScript Stylesheet

    想在HTML里面通过DOM用JavaScript操作,弄了半天无法将弄好的style节点插入document里面去。后来用排除法,惊奇地发现把style改个别的名字就部出错了。

    查了一下手册,原来样式表的处理是用专门的方法做的,它并不是一个通用的普通Element,Document提供了方法createStyleSheet()来生成一个StyleSheet对象,这个对象再有addRule等其它方法来操作。


     发表于 14:53:03  阅读全文  |  评论(0)  |  Trackback(0)  | 编辑
     
    2005-12-20
    Tag:JavaScript Web2.0 Drag-Drop 拖放

    花了三天时间研究http://www.netvibes.com,之前已经稍微研究过http://script.aculo.us

    很想把netvibes的模块拖放功能抽取出来作为己用,但是看了好久它的js代码,因为和他们整个设计交织在一起了,抽出来非常困难。

    不过也不是完全没有收获,我“盗取”了几个封装ajax调用的方法,还有一堆判断浏览器之类的实用工具函数。对于那个拖动模块时出现的定位用的虚线框,我也基本知道它的设计思想了。就是用一个ghostModule,根据被拖动模块的坐标,动态调整它出现的位置。

    等有时间,我用scriptaculous的拖放函数库做一套通用的模块拖用js脚本。


     发表于 09:00:31  阅读全文  |  评论(3)  |  Trackback(0)  | 编辑
     
    分页共1页 1