<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
 <channel>
  <title>Raymond的狗屋</title>
  <link>http://raymondchen625.blogbus.com</link>
  <description><![CDATA[]]></description>
  <generator> by blogbus.com </generator>
  <lastBuildDate>Thu, 01 Jan 1970 07:00:00 +0700</lastBuildDate>
  <image>
									<url>http://public.blogbus.com/profile/head.gif</url>
									<title>Raymond的狗屋</title>
									<link>http://raymondchen625.blogbus.com</link>
								</image>  <item>
   <title>Debian的版本</title>
   <description><![CDATA[<br><!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="http://raymondchen625.blogbus.com/logs/2372222.html">top 命令解释</a> 2006-04-29</div><div><a href="http://raymondchen625.blogbus.com/logs/2338403.html">如何用APT维护Red Hat Enterprise Linux (RHEL) zt</a> 2006-04-24</div><div><a href="http://raymondchen625.blogbus.com/logs/1754809.html">Linux系统里的进程管理</a> 2005-12-27</div><div><a href="http://raymondchen625.blogbus.com/logs/1752433.html">crontab 使用说明</a> 2005-12-22</div><div><a href="http://raymondchen625.blogbus.com/logs/1752429.html">Fedora 4不支持旧CD-ROM</a> 2005-12-21</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fraymondchen625.blogbus.com%2Flogs%2F2967427.html&title=Debian%E7%9A%84%E7%89%88%E6%9C%AC">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://raymondchen625.blogbus.com/logs/2967427.html</link>
   <author></author>
   <pubDate>Thu, 03 Aug 2006 11:15:50 +0800</pubDate>
  </item>
  <item>
   <title>top 命令解释</title>
   <description><![CDATA[<p>top</p><p>1.作用<br />top命令用来显示执行中的程序进程，使用权限是所有用户。</p><p>2.格式<br />top [－] [d delay] [q] [c] [S] [s] [i] [n]</p><p>3.主要参数<br />d：指定更新的间隔，以秒计算。<br />q：没有任何延迟的更新。如果使用者有超级用户，则top命令将会以最高的优先序执行。<br />c：显示进程完整的路径与名称。<br />S：累积模式，会将己完成或消失的子行程的CPU时间累积起来。<br />s：安全模式。<br />i：不显示任何闲置(Idle)或无用(Zombie)的行程。<br />n：显示更新的次数，完成后将会退出top。</p><p>4.说明<br />top命令是Linux系统管理的一个主要命令，通过它可以获得许多信息。这里我们结合图1来说明它给出的信息。</p><p>图1 top命令的显示</p><p>在图1中，第一行表示的项目依次为当前时间、系统启动时间、当前系统登录用户数目、平均负载。第二行显示的是所有启动的进程、目前运行的、挂起 (Sleeping)的和无用(Zombie)的进程。第三行显示的是目前CPU的使用情况，包括系统占用的比例、用户使用比例、闲置(Idle)比例。第四行显示物理内存的使用情况，包括总的可以使用的内存、已用内存、空闲内存、缓冲区占用的内存。第五行显示交换分区使用情况，包括总的交换分区、使用的、空闲的和用于高速缓存的大小。第六行显示的项目最多，下面列出了详细解释。<br />PID（Process ID）：进程标示号。<br />USER：进程所有者的用户名。<br />PR：进程的优先级别。<br />NI：进程的优先级别数值。<br />VIRT：进程占用的虚拟内存值。<br />RES：进程占用的物理内存值。<br />SHR：进程使用的共享内存值。<br />S：进程的状态，其中S表示休眠，R表示正在运行，Z表示僵死状态，N表示该进程优先值是负数。<br />%CPU：该进程占用的CPU使用率。<br />%MEM：该进程占用的物理内存和总内存的百分比。<br />TIME＋：该进程启动后占用的总的CPU时间。<br />Command：进程启动的启动命令名称，如果这一行显示不下，进程会有一个完整的命令行。<br />top命令使用过程中，还可以使用一些交互的命令来完成其它参数的功能。这些命令是通过快捷键启动的。<br />&lt;空格&gt;：立刻刷新。<br />P：根据CPU使用大小进行排序。<br />T：根据时间、累计时间排序。<br />q：退出top命令。<br />m：切换显示内存信息。<br />t：切换显示进程和CPU状态信息。<br />c：切换显示命令名称和完整命令行。<br />M：根据使用内存大小进行排序。<br />W：将当前设置写入~/.toprc文件中。这是写top配置文件的推荐方法。</p><p>可以看到，top命令是一个功能十分强大的监控系统的工具，对于系统管理员而言尤其重要。但是，它的缺点是会消耗很多系统资源。</p><!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="http://raymondchen625.blogbus.com/logs/2967427.html">Debian的版本</a> 2006-08-03</div><div><a href="http://raymondchen625.blogbus.com/logs/2338403.html">如何用APT维护Red Hat Enterprise Linux (RHEL) zt</a> 2006-04-24</div><div><a href="http://raymondchen625.blogbus.com/logs/1754809.html">Linux系统里的进程管理</a> 2005-12-27</div><div><a href="http://raymondchen625.blogbus.com/logs/1752433.html">crontab 使用说明</a> 2005-12-22</div><div><a href="http://raymondchen625.blogbus.com/logs/1752429.html">Fedora 4不支持旧CD-ROM</a> 2005-12-21</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fraymondchen625.blogbus.com%2Flogs%2F2372222.html&title=top+%E5%91%BD%E4%BB%A4%E8%A7%A3%E9%87%8A">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://raymondchen625.blogbus.com/logs/2372222.html</link>
   <author></author>
   <pubDate>Sat, 29 Apr 2006 09:48:53 +0800</pubDate>
  </item>
  <item>
   <title>如何用APT维护Red Hat Enterprise Linux (RHEL) zt</title>
   <description><![CDATA[<table cellspacing="4" cellpadding="4" width="100%" border="0"><tbody><tr><td class="title" align="center">如何用APT维护Red Hat Enterprise Linux (RHEL)zt</td></tr><tr><td align="center" bgcolor="#c0c0c0" height="1"></td></tr><tr><td align="center">作者: 月下刀客  发布日期: 2005-11-18    查看数:<script language="JavaScript" src="http://www.linuxsky.net/function.php?action=view&tid=1638&views=269" type="text/JavaScript"></script> 269   出自: http://www.linuxsky.net</td></tr><tr><td><table style="TABLE-LAYOUT: fixed; WORD-WRAP: break-word" cellspacing="2" cellpadding="2" width="100%" border="0"><tbody><tr><td class="message" id="zoom">作者：Fenng <br />日期：11-Nov-2004　<br />出处：http://www.dbanotes.net<br />版本：V0.031<br /><br /><br />--------------------------------------------------------------------------------<br /><br /><br />内容简介<br />如何用APT(Advanced Packaging Tool)维护Red Hat Enterprise Linux (RHEL)，提供对个别RHEL的用户无法升级的问题的解决办法。关键词：APT,Linux，升级，Red Hat Enterprise Linux，RHEL，YUM，RPM，依赖性 <br /><br />几句前言<br />Linux系统维护中令管理员很头疼的就是软件包之间的依赖性了，往往是你要安装A软件，但是编译的时候告诉你X软件安装之前需要B软件，而当你安装Y软件的时候，又告诉你需要Z库了--好不容易安装好Z库，发现版本还有问题......可能很多朋友都有过这个经历。其实开源社区早就对这个问题尝试进行解决了，不同的发行版推出了各自的工具，比如Yellow Dog的YUM ,Debian的APT(Advanced Packaging Tool)等。而这些软件也被开源软件爱好者们逐渐移植到别的发行版上。<br /><br />Redhat企业版Linux的的升级往往给管理员们带来不少问题：网站下载速度太慢，不够安全，当然了，更多的人是无法更新的--版权问题。经过一段时间的比较 ，感觉使用APT维护RHEL有着特殊的便利性。 (有的朋友可能会说，yum 也不错阿！是的，yum在很多时候表现的确不错，不过如果使用的Linux是RHEL的话,很难找到适合yum的资料库，&quot;巧妇难为无米之炊&quot;。) 现在把具体方法介绍给大家作为参考。 <br /><br />APT基本介绍<br />Debian GNU/Linux 是APT的缔造者。初衷是利用工具来解决软件安装时候的依赖性问题。其工作原理大致为：用户安装APT客户端工具，查寻APT服务器端的资料库（repositories）上的RPM软件包信息，并分析软件包之间的依赖性然后下载并进行安装。 <br /><br />安装与配置<br />首先让我们安装APT工具:<br /><br /># wget http://redhat.uni-klu.ac.at/el3/apt.i386.rpm<br /># rpm -Uvh apt.i386.rpm <br />安装够简单吧? 我们要编辑配置文件： <br />#vi /etc/apt/sources.list.d/dag.list <br />添加如下内容（资料库相关的信息）: <br />rpm http://afs.caspur.it/ afs/italia/project/linux/cern/slc302/i386/apt os updates extras<br />rpm http://redhat.uni-klu.ac.at redhat/dag/el3/i386 dag<br />rpm-src http://redhat.uni-klu.ac.at redhat/dag/el3/i386 dag<br />rpm http://apt.sw.be redhat/el3/en/i386 dag<br />rpm-src http://apt.sw.be redhat/el3/en/i386 dag <br />注: 第一条http://afs.caspur.it/ 的资料库几乎就是Redhat官方站点的内容。在写这篇文章的时候还是有效的。如果要尝试更新Kernel，还可以在第一条后面添加　kernel26 . <br /><br />如果需要更多Java相关软件，则： <br />#vi /etc/apt/sources.list.d/jpackage.list <br />(这一步是可选的)添加如下内容: <br />rpm http://redhat.uni-klu.ac.at redhat/jpackage/redhat-es-3/i386 free devel<br />rpm-src http://redhat.uni-klu.ac.at redhat/jpackage/redhat-es-3/i386 free devel<br />rpm http://redhat.uni-klu.ac.at redhat/jpackage/redhat-es-3/generic free devel<br />rpm-src http://redhat.uni-klu.ac.at redhat/jpackage/redhat-es-3/generic free devel<br />如果要更新KDE的话(这一步可选的): <br />#vi /etc/apt/sources.list.d/kde.list <br />考虑添加如何内容: <br />rpm http://apt.kde-redhat.org apt/fedora/3.0 stable<br />rpm http://apt.kde-redhat.org apt/fedora/all stable<br />rpm http://apt.kde-redhat.org apt/kde-redhat/3.0 stable unstable<br />rpm http://apt.kde-redhat.org apt/kde-redhat/all stable unstable <br />当然，这些内容是经过笔者验证的，都是可用的。从一些站点上下载的list 似乎都多多少少有点问题。 <br />注: 如果您发现上述的资料库失效或者是有什么更好的资料库。烦请通知我: DBAnotes@gmail.com . <br /><br />使用简介<br />使用相对来说比较简单: <br /><br />#apt-get update<br />#apt-get upgrade<br />#apt-get check //检查依赖性<br />#apt-get -f install // 解决依赖性问题 <br />如果要安装某工具，比如说iftop,可以这样: <br />#apt-cache search iftop<br />#apt-get install iftop <br />apt自动解决依赖性问题，方便得很。 <br />要注意的是需要导入相应资料库的签名。在相关站点下载GPG key之后，用如下命令导入即可: <br /><br />#rpm --import TheKey_youDownload <br />如果有耐心看到这里的话，可以发现盗版的用户或者是用RHEL进行测试的朋友可以通过这个进行升级了--要不然RHEL的up2date 总是要你输入认证信息的。 <br /><br />参考信息<br /><br /><br />APT-howto - http://www.debian.org/doc/manuals/apt-howto/index.en.html <br /><br />其他版本的APT使用问题和一些使用技巧请参考这里：<br /><br />http://dag.wieers.com/home-made/apt/FAQ.php <br />http://www2.uni-klu.ac.at/support/Redhat<br />http://linuxwiki.de/apt/RedHat<br /><br />=============<br /><br />本文作者<br />Fenng，某美资公司DBA，业余时间混迹于各数据库相关的技术论坛且乐此不疲。目前关注如何利用ORACLE数据库有效地构建企业应用。对Oracle tuning、troubleshooting有一点研究。<br />个人技术站点:http://www.dbanotes.net/ 。可以通过电子邮件 dbanotes@gmail.com 联系到他。</td></tr></tbody></table></td></tr></tbody></table><!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="http://raymondchen625.blogbus.com/logs/1752423.html">转贴： 从硬盘安装Fedora Core 4</a> 2005-12-20</div><div><a href="http://raymondchen625.blogbus.com/logs/2967427.html">Debian的版本</a> 2006-08-03</div><div><a href="http://raymondchen625.blogbus.com/logs/2372222.html">top 命令解释</a> 2006-04-29</div><div><a href="http://raymondchen625.blogbus.com/logs/1754809.html">Linux系统里的进程管理</a> 2005-12-27</div><div><a href="http://raymondchen625.blogbus.com/logs/1752433.html">crontab 使用说明</a> 2005-12-22</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fraymondchen625.blogbus.com%2Flogs%2F2338403.html&title=%E5%A6%82%E4%BD%95%E7%94%A8APT%E7%BB%B4%E6%8A%A4Red+Hat+Enterprise+Linux+%28RHEL%29+zt">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://raymondchen625.blogbus.com/logs/2338403.html</link>
   <author></author>
   <pubDate>Mon, 24 Apr 2006 10:01:02 +0800</pubDate>
  </item>
  <item>
   <title>用 Subversion 构建版本控制环境</title>
   <description><![CDATA[<table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr valign="top"><td width="100%"><h1>用 Subversion 构建版本控制环境</h1><img class="display-img" height="6" src="http://www.ibm.com/i/c.gif" width="1" /></td><td class="no-print" width="192"><img height="18" alt="developerWorks" src="http://www-128.ibm.com/developerworks/cn/i/dw.gif" width="192" /></td></tr></tbody></table><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr valign="top"><td width="10"><img height="1" src="http://www.ibm.com/i/c.gif" width="10" /></td><td width="100%"><table class="no-print" cellspacing="0" cellpadding="0" width="160" align="right" border="0"><tbody><tr><td width="10"><img height="1" src="http://www.ibm.com/i/c.gif" width="10" /></td><td><table cellspacing="0" cellpadding="0" width="150" border="0"><tbody><tr><td class="v14-header-1-small">文档选项</td></tr></tbody></table><table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="no-padding" width="150"><table cellspacing="0" cellpadding="0" width="143" border="0"><><img height="1" src="http://www.ibm.com/i/c.gif" width="8" /> <form name="email" action="https://www-128.ibm.com/developerworks/secure/email-it.jsp"><input type="hidden" name="body" /><input type="hidden" name="subject" /><input type="hidden" name="lang" /><script language="JavaScript" type="text/javascript"></script> </form></><tbody><tr valign="top"><td width="8"><img height="1" src="http://www.ibm.com/i/c.gif" width="8" /></td><td width="16"><img height="16" alt="将此页作为电子邮件发送" src="http://www.ibm.com/i/v14/icons/em.gif" width="16" vspace="3" /></td><td width="122"><p><a class="smallplainlink" href="javascript:document.email.submit();"><b><font color="#5c81a7" size="2">将此页作为电子邮件发送</font></b></a></p></td></tr><noscript /></tbody></table></td></tr></tbody></table><!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- 03/20/06 updated by gretchen --><br /><table cellspacing="0" cellpadding="0" width="150" border="0"><tbody><tr><td class="v14-header-2-small">最新推荐</td></tr></tbody></table><table class="v14-gray-table-border" cellspacing="0" cellpadding="0" border="0"><tbody><tr><td class="no-padding" width="150"><table cellspacing="0" cellpadding="0" width="143" border="0"><tbody><tr valign="top"><td width="8"><img height="1" src="http://www.ibm.com/i/c.gif" width="8" /></td><td><img height="16" src="http://www.ibm.com/i/v14/icons/fw_bold.gif" width="16" vspace="3" border="0" /></td><td width="125"><p><a class="smallplainlink" href="http://www-128.ibm.com/developerworks/cn/kickstart/"><font color="#5c81a7" size="2">Java 应用开发源动力 － 下载免费软件，快速启动开发</font></a> </p></td></tr></tbody></table></td></tr></tbody></table><!--END RESERVED FOR FUTURE USE INCLUDE FILES--><br /></td></tr></tbody></table><p><a href="http://www-128.ibm.com/developerworks/cn/opensource/os-subversion/#author"><font color="#996699">刘冬 </font></a>, Java自由人<br /></p><p>2005 年 9 月 </p><blockquote>本文将介绍如何通过 Subversion 来构建小组开发过程中最为重要的版本控制环境，包括Subversion 环境的安装配置以及如何通过各种有效的客户端工具来提高工作的效率。</blockquote><!--START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --><!--END RESERVED FOR FUTURE USE INCLUDE FILES--><p><a name="N10040"><span class="atitle"><font face="Arial" size="4">一． 首先我们先来认识一下 Subversion</font></span></a></p><p>Subversion 项目的初衷是为了替换现在开源社区最为流行的版本控制软件 CVS，在 CVS的功能的基础上有很多的提升同时也能较好的解决 CVS 系统的一些不足，这些提升主要包括以下的一些方面：</p><p>1． 目录、文件以及改名等元数据的版本化<br />不同于 CVS 只关心文件的内容以及文件是否存在，所有文件、目录的相关操作都是被版本化的，例如文件的改名、拷贝等等；</p><p>2． 提交操作是真正的原子操作<br />在 Subversion 中，提交操作是不可分割的，修订版本号是基于每次提交操作而非文件。提交日志被附加在每个修订版本中，而不是像 CVS 一样冗余的进行存储；</p><p>3． 可通过 Apache 服务器提供基于 WebDAV/DeltaV 协议的支持<br />该功能可使 Subversion 通过 Apache Web 服务器使资源库更加灵活的在网上进行共享，使其在互操作性上大大优于 CVS；</p><p>4． 可独立运行<br />当你不想使用 Apache 2.x 时候，你也可以使用 Subversion，它可以以守护进程或者是Windows 下的服务方式独立运行；</p><p>5． 分支（Branching）与标签（Tagging）操作是轻量级的；</p><p>6． 客户服务器端分层库结构设计；</p><p>7． 资源库可以采用数据库（BerkeleyDB）或者是使用特定格式的文件进行存储；</p><p>8． 更有效的对二进制文件进行处理。</p>更多的特性可以参照 Subversion 提供的文档（http://subversion.tigris.org/） <br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="659" /><br /><img height="6" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><img height="4" src="http://www.ibm.com/i/c.gif" width="69" /><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="middle"><img height="16" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/opensource/os-subversion/#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N10069"><span class="atitle"><font face="Arial" size="4">二． Subversion版本控制环境在Windows系统下的安装</font></span></a></p><p>在Windows下安装最为方便的办法就是下载安装程序，你可以到下面这个地址下载最新的二进制压缩版本svn-win32-1.2.3.zip ，地址是： http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=91 把该文件解压到一个目录，假定为 D:\subversion。</p><p>接下来新建一个存放项目的资源库目录，例如：D:\repository\project1，执行下面命令对这个项目目录进行初始化： D:\subversion\bin&gt; svnadmin create D:\repository\project1</p><p>Subversion会在D:\repository\project1目录下生成很多的子目录以及文件，接下来我们需要设置该项目的用户信息以及项目的基本信息，打开D:\repository\project1\conf\passwd文件，去掉[users]的注释，并添加用户如下：</p><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section">
<font face="Lucida Console">### 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
</font></code></pre></td></tr></tbody></table><br /><p>Subversion使用了明码存储用户的口令，这应该算是它的一个不足。</p><p>接下来打开conf\svnserve.conf修改如下</p><br /><table cellspacing="0" cellpadding="5" width="100%" bgcolor="#eeeeee" border="1"><tbody><tr><td><pre><code class="section">
<font face="Lucida Console">[general]
anon-access = read
auth-access = write
password-db = passwd
realm = project1
</font></code></pre></td></tr></tbody></table><br /><p>在做完这些基本的设置后就可以启动 Subversion 了，当然最好的方式就是让 Subversion 做为一个服务来运行，我们可以通过一个第三方的工具 SVNService 让 Subversion 以 Windows 服务的方式运行。</p><p>到 http://dark.clansoft.dk/~mbn/svnservice/ 下载SVNService.zip并把它解压到{Subversion}\bin目录下，通过运行 svnservice -install -d -r D:\repository\project1 ，执行的结果显示：SVNService installed. 这时候你可以在服务控制台中看到名为SVNService的服务，启动它就可以了，如果你不想用服务的方式启动Subversion，你可以运行svnserve -d来启动Subversion。</p><p>要卸载SVNService服务，只需要运行 SVNService -remove 即可。</p><p>至此，Subversion已经安装成功，我们将在接下来的一节中介绍如何通过各种客户端对资源库进行操作。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="659" /><br /><img height="6" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><img height="4" src="http://www.ibm.com/i/c.gif" width="69" /><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="middle"><img height="16" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/opensource/os-subversion/#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="N1009C"><span class="atitle"><font face="Arial" size="4">三． Subversion 各种客户端的使用</font></span></a></p><p>一个版本控制软件好不好不仅在于服务器端是否提供足够强大的功能，同时有没有足够友好的客户端也是非常重要的。</p><p>Subversion 本身提供一个基于命令行的工具 svn，基本上所有的操作都可以通过这个工具来完成，但是用户操作界面不太友好。不过我们可以先使用这个工具来验证一下我们之前安装的 Subversion 服务是否已经正常工作。接下来我们先随便导入一个项目，并对这个项目的某些文件进行简单的修改、提交并重新导出项目，通过这些基本的操作先来体验一下Subversion。（为了操作方便你最好把{subversion}\bin目录加到系统的PATH环境变量中）</p><p>1． 导入项目</p><p>转到你的项目所在的目录，执行下面命令来提交整个项目 <br />svn import . svn://localhost/project1 -m &quot;initial import&quot; --username liudong --password liudong123<br />其中[.]表示当前目录，你也可以指定项目的绝对路径。</p><p>2． 检出项目<br />为了验证刚才导入的项目，我们转到一个新的目录下，执行<br />svn checkout svn://localhost/project1 --username liudong -password liudong123<br />就可以在当前目录下生成一个project1的项目目录，目录中的内容就是我们刚才所提交的所有文件。</p><p>3． 提交修改后的文件<br />修改项目中的任何一个文件，使用命令来提交所作的修改：<br />svn commit ReadMe.txt -m &quot;modified&quot; --username liudong -password liudong123</p><p>4． 获取最新的版本<br />当项目组的其他成员修改并提交了某个文件，你可以通过下面命令来获取到该文件的最新的版本：<br />svn update -r HEAD ReadMe.txt --username liudong -password liudong123</p><p>上面四个是版本控制环境中最最基本的操作，不过这样的操作环境你肯定觉得麻烦，对于使用Eclipse环境进行开发的朋友来讲，接下来我们介绍一个Eclipse的插件Subclipse，该插件提供对Subversion服务的操作支持。你可以单独下载该插件的压缩包进行本地更新或者通过Eclipse Update进行远程安装，远程安装的URL是 <a href="http://subclipse.tigris.org/update"><font color="#5c81a7">http://subclipse.tigris.org/update</font></a> ，相信大家对Eclipse Update已经了如指掌，这里不再罗嗦。</p><p>检查一下插件有没有安装成功吧，打开菜单Windows-&gt;Preferences-&gt;Team检查是否有SVN节点，点击SVN即可看到该插件的设置界面如下图所示：</p><br /><img height="495" src="http://www-128.ibm.com/developerworks/cn/opensource/os-subversion/images/image001.jpg" width="544" border="0" /> <br /><p>保持默认的设置即可，接下来我们通过该插件将一个项目导入到Subversion服务器中，右击项目名-&gt;Team-&gt;Share Project…打开项目共享对话框，对话框有两个选择，一是Eclipse内置的对CVS的支持，还有另外一个就是我们刚装上的SVN。选择SVN进入服务器设置界面，入下图</p><br /><img height="408" src="http://www-128.ibm.com/developerworks/cn/opensource/os-subversion/images/image003.jpg" width="461" border="0" /> <br /><p>需要填写的是服务器的URL以及用户名和口令，服务器的URL不需要填写项目名称，点击下一步按钮进入项目名称设置</p><br /><img height="408" src="http://www-128.ibm.com/developerworks/cn/opensource/os-subversion/images/image005.jpg" width="461" border="0" /> <br /><p>在这里可以看到Subclipse会自动给URL加上项目的名称。点击结束按钮将出现提交对话框如下图</p><br /><img height="505" src="http://www-128.ibm.com/developerworks/cn/opensource/os-subversion/images/image007.jpg" width="538" border="0" /> <br /><p>选择你所需要提交的文件或者目录点击OK按钮即可完成项目的导入。接下来的很多操作跟CVS很类似，但是又比CVS的功能强大得多，随便右击一个文件打开Team的上下文菜单如下：</p><br /><img height="470" src="http://www-128.ibm.com/developerworks/cn/opensource/os-subversion/images/image009.jpg" width="197" border="0" /> <br /><p>通过该菜单我们可以看到CVS有的功能在这上面都有，而且还包括可以对文件进行加锁和解锁操作，同时还有可以设置文件的属性，可以通过SVN Properties视图查看某个文件的属性</p><br /><img height="259" src="http://www-128.ibm.com/developerworks/cn/opensource/os-subversion/images/image011.jpg" width="455" border="0" /> <br /><p>与CVS不同的是当文件被修改后SVN插件显示的是一个星号的小图标。同样的，当有些文件你并不想添加到资源库中的时候，你也可以像CVS一样把该文件添加到svn:ignore。Subclipse插件还有更多其他的功能这里不一一介绍了，大家可以在使用的过程中去发掘。</p><p>以上介绍的针对使用Eclipse开发环境的人员，但是项目组的一些其他成员例如网页设计师，他们怎么来方便的使用Subversion呢？因此接下来我们介绍一个集成在Windows Shell的客户端工具TortoiseSVN (<a href="http://tortoisesvn.tigris.org/"><font color="#996699">http://tortoisesvn.tigris.org/</font></a>)，利用这个工具也可以非常简单的进行资源库的操作。TortoiseSVN的安装非常简单，直接运行安装程序，按照默认方式安装即可，安装完毕需要重新启动系统。</p><p>如果没什么意外的话，随便右击一个文件即可看到上下文菜单多了一个菜单项是TortoiseSVN，如果是文件夹还会有另外一个项是SVN Checkout…。在使用之前你可以根据自己的喜欢对TortoiseSVN进行一些设置，右击任一文件选择TortoiseSVN-&gt;Settings即可打开设置对话框如下：</p><br /><img height="417" src="http://www-128.ibm.com/developerworks/cn/opensource/os-subversion/images/image013.jpg" width="659" border="0" /> <br /><p>TortoiseSVN的一个非常有用的工具就是资源库浏览器，在桌面空白位置单击鼠标右键选择TortoiseSVN-&gt;Repo-Browser即可打开资源库浏览器如下图所示：</p><br /><img height="480" src="http://www-128.ibm.com/developerworks/cn/opensource/os-subversion/images/image015.jpg" width="631" border="0" /> <br /><p>通过该浏览器你可以浏览资源库中的所有项目以及项目中每一个文件的信息。但是怎么做一些日常的操作呢，例如提交、更新等等？</p><p>首先我们先看如何从资源库中检出(CheckOut)一个已有的项目，在空白处单击鼠标右键选择SVN Checkout…菜单项</p><br /><img height="313" src="http://www-128.ibm.com/developerworks/cn/opensource/os-subversion/images/image017.jpg" width="456" border="0" /> <br /><p>输入存放项目的文件夹以及项目对应的SVN的URL地址如上图，点击OK按钮后TortoiseSVN会显示详细的进度信息</p><br /><img height="441" src="http://www-128.ibm.com/developerworks/cn/opensource/os-subversion/images/image019.jpg" width="554" border="0" /> <br /><p>转到存放项目的文件夹即可看到整个项目的所有文件已经被检出，而且图标已经被替换成TortoiseSVN的图标，如下图所示：</p><br /><img height="429" src="http://www-128.ibm.com/developerworks/cn/opensource/os-subversion/images/image021.jpg" width="599" border="0" /> <br /><p>这个时候你就可以随意的修改文件，并在修改后右击所修改的文件即可进行提交或者更新操作。</p><p>以上介绍的三种不同的Subversion客户端已经可以满足大部分用户的要求，同时三者也可以互为补充。另外Subversion也可以与Apache HTTP服务器结合提供基于WebDAV协议的服务，其在共享方面远远超过了CVS，有兴趣的读者可以阅读Subversion的文档进行配置。</p><p>对正在使用CVS的用户来讲，也可以通过一个名为cvs2svn的工具来将已有的项目移植到Subversion中，该工具可以在<a href="http://cvs2svn.tigris.org/"><font color="#5c81a7">http://cvs2svn.tigris.org/</font></a> 下载。</p><br /><table cellspacing="0" cellpadding="0" width="100%" border="0"><tbody><tr><td><img height="1" src="http://www.ibm.com/i/v14/rules/blue_rule.gif" width="659" /><br /><img height="6" src="http://www.ibm.com/i/c.gif" width="8" border="0" /></td></tr></tbody></table><table class="no-print" cellspacing="0" cellpadding="0" align="right"><tbody><tr align="right"><td><img height="4" src="http://www.ibm.com/i/c.gif" width="69" /><br /><table cellspacing="0" cellpadding="0" border="0"><tbody><tr><td valign="middle"><img height="16" src="http://www.ibm.com/i/v14/icons/u_bold.gif" width="16" border="0" /><br /></td><td valign="top" align="right"><a class="fbox" href="http://www-128.ibm.com/developerworks/cn/opensource/os-subversion/#main"><b><font color="#996699">回页首</font></b></a></td></tr></tbody></table></td></tr></tbody></table><br /><br /><p><a name="resources"><span class="atitle"><font face="Arial" size="4">参考资料 </font></span></a></p><ul><li><a href="http://subversion.tigris.org/"><font color="#996699">Subversion的官方网站</font></a><br /><br /></li><li><a href="http://subclipse.tigris.org/"><font color="#5c81a7">Subclipse插件</font></a><br /><br /></li><li><a href="http://tortoisesvn.tigris.org/"><font color="#996699">TortoiseSVN</font></a><br /><br /></li><li><a href="http://www.eclipse.org/"><font color="#5c81a7">Eclipse官方网站</font></a><br /></li></ul><br /></td></tr></tbody></table><!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="/logs/2967427.html">Debian的版本</a> 2006-08-03</div><div><a href="/logs/2372222.html">top 命令解释</a> 2006-04-29</div><div><a href="/logs/2338403.html">如何用APT维护Red Hat Enterprise Linux (RHEL) zt</a> 2006-04-24</div><div><a href="/logs/1761387.html">prototype.js开发笔记</a> 2005-12-28</div><div><a href="/logs/1752433.html">crontab 使用说明</a> 2005-12-22</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fraymondchen625.blogbus.com%2Flogs%2F2232779.html&title=%E7%94%A8+Subversion+%E6%9E%84%E5%BB%BA%E7%89%88%E6%9C%AC%E6%8E%A7%E5%88%B6%E7%8E%AF%E5%A2%83">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://raymondchen625.blogbus.com/logs/2232779.html</link>
   <author></author>
   <pubDate>Sun, 09 Apr 2006 21:00:26 +0800</pubDate>
  </item>
  <item>
   <title>Google服务和软件大全</title>
   <description><![CDATA[<div class="postTitle"><a href="http://blog.donews.com/ciw/archive/2006/03/16/771278.aspx"><font color="#0066ff">Google服务和软件大全</font></a> </div><div class="postText"><font face="Arial" size="2">Google这个公司现在已经是“家大业大”了，他们总是隔三岔五地推出一些新鲜的服务，让业界跟着也兴奋一把。不过历年来Google所发展出来的服务和软件实在太多了，究竟他们已经有了什么服务？现在就来看看吧。<br /></font><p><font face="Arial" size="2">　　</font><a href="http://www.google.com/intl/zh-CN/add_url.html" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Add to Google</font></strong></a></p><p><font face="Arial" size="2">　　这是一个提供网页信息的站点，主要的功能是把自己的主页介绍给Google让他收录，而时间上较长，起码一两个月才会被Google收录，但是一旦收了你的主页，知名度会更快地上升。</font></p><p><font face="Arial" size="2">　　</font><a href="http://www.blogger.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Blogger</font></strong></a></p><p><font face="Arial" size="2">　　Google提供的Blog服务，现在已经有中文版本了，大家可以上去安个家，把地址写到本文评论让大家去浏览。</font></p><p><font face="Arial" size="2">　　</font><a href="http://www.froogle.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Froogle</font></strong></a></p><p><font face="Arial" size="2">　　这是一个专业的引擎，可以输入你想要购买的东西，然后得到符合关键词的结果出来，可以比较一下各个购物网站不同的价格，挑选最合适的地方进行购买。</font></p><p><font face="Arial" size="2">　　</font><a href="http://mail.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Gmail</font></strong></a></p><p><font face="Arial" size="2">　　Gmail是是Google提供的当前最流行的免费邮件服务，提供了超过2GB的储存空间。</font></p><p><font face="Arial" size="2">　　</font><a href="http://www.google.com/adsense" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google AdSense</font></strong></a></p><p><font face="Arial" size="2">　　Google提供的广告服务，你是否遇到有不知来源的IP经常恶意点击你的广告，而你无法知道IP所以无法禁止，你是否想知道你的广告在哪个或者哪些页面点击率最高，而又不受渠道数量的限制，它主要针对Google Adsense的规则，在不违反规则的前提下为用户提供及时详细的广告点击统计信息。</font></p><p><font face="Arial" size="2">　　</font><a href="http://adwords.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google AdWords</font></strong></a></p><p><font face="Arial" size="2">　　Google提供给商家的特殊广告站点，只要有人点击这里就会按一定规则向商家收费，算是网络上的分类广告。</font></p><p><font face="Arial" size="2">　　</font><a href="http://www.google.com/alerts" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Alerts</font></strong></a></p><p><font face="Arial" size="2">　　这是一个新闻定制站点，可以通过邮箱定制你需要的内容，然后得到相关的讯息。</font></p><p><font face="Arial" size="2">　　</font><a href="http://www.google.com/analytics" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Analytics</font></strong></a></p><p><font face="Arial" size="2">　　Google推出的免费提供的网站统计服务，只需要简单注册，即可帮助站长分析自己的站点情况，而且里面的内容非常详细，不光小网站有用，大网站更是可以作为一个参考的指标。</font></p><p><font face="Arial" size="2">　　</font><a href="http://answers.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Answers</font></strong></a></p><p><font face="Arial" size="2">　　Google的问答站点，可以回答你很多不知道的问题，类似的还有百度出的百度知道，现在这个站点开始进入收费模式，你可以悬赏进行问题答案的购买。</font></p><p><font face="Arial" size="2">　　</font><a href="http://base.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Base</font></strong></a></p><p><font face="Arial" size="2">　　这个服务相对于Google其它服务的专业化，或许显得比较杂乱，里面也是可以让我们提交不同的信息给Google，让它出现在Google的搜索里面。</font></p><p><font face="Arial" size="2">　　</font><a href="http://blogsearch.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Blog Search</font></strong></a></p><p><font face="Arial" size="2">　　这是一个针对Google博客的搜索服务，专门收集其中的海量信息。</font></p><p><font face="Arial" size="2">　　</font><a href="http://books.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Book Search</font></strong></a></p><p><font face="Arial" size="2">　　Google的书籍搜索服务，其实也是Google引擎的一个小延伸而已，不过在这里搜索到的结果比较专业和集中。</font></p><p><font face="Arial" size="2">　　</font><a href="http://catalogs.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Catalogs</font></strong></a></p><p><font face="Arial" size="2">　　Google做的邮购搜索服务，对于国人来说好象用处并不是特别地大。</font></p><p><font face="Arial" size="2">　　</font><a href="http://code.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Code</font></strong></a></p><p><font face="Arial" size="2">　　Google用来推广及发展开源软件的一个服务，一个适合程序员的源代码公开站点</font></p><p><font face="Arial" size="2">　　</font><a href="http://toolbar.google.com/dc/offerdc.html" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Compute</font></strong></a></p><p><font face="Arial" size="2">　　Google的网格计算，可以将一些超大规模的计算量分散到全球不同国家地区的电脑上，以尽快得到结果，这是些有益全球的计算，希望有电脑的朋友都参加。</font></p><p><font face="Arial" size="2">　　</font><a href="http://desktop.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Desktop</font></strong></a></p><p><font face="Arial" size="2">　　这是一个放置在桌面上的工具条，在这个工具条里可提供新闻，天气，Email等小程序，了解最新的信息。</font></p><p><font face="Arial" size="2">　　</font><a href="http://dir.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Directory</font></strong></a></p><p><font face="Arial" size="2">　　Goolge制作的超大型人工分类目录，让网页根据重要性来排列。目录搜索服务可满足那些想要浏览某特定主题下相关信息的用户。</font></p><p><font face="Arial" size="2">　　</font><a href="http://earth.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Earth</font></strong></a></p><p><font face="Arial" size="2">　　这项服务提供了地球上大部分地区的卫星图片查询，尤其是大城市的图片更加地多，让你如宇航员一般身临其境，足不出户也可了解世界各地。</font></p><p><font face="Arial" size="2">　　</font><a href="http://groups.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Groups</font></strong></a></p><p><font face="Arial" size="2">　　Google提供的群组服务。利用它你可以创建邮件列表、阅读新闻或者是和志同道合的用户分享你感兴趣的东西。</font></p><p><font face="Arial" size="2">　　</font><a href="http://www.google.com/ig" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Homepage</font></strong></a></p><p><font face="Arial" size="2">　　是Google提供的主页服务，你可以定制它，它提供了天气、新闻、占卜等各种各样的服务。</font></p><p><font face="Arial" size="2">　　</font><a href="http://images.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Image Search</font></strong></a></p><p><font face="Arial" size="2">　　Google的图片搜索，几乎是Google最早的服务了，这是它的图片搜索页面，相信大家都用过吧，图片搜索的精确度还是不错的。</font></p><p><font face="Arial" size="2">　　</font><a href="http://labs.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Labs</font></strong></a></p><p><font face="Arial" size="2">　　Google实验室的一些服务链接，从这里可以看到它们又有什么天才的发明。</font></p><p><font face="Arial" size="2">　　</font><a href="http://local.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Local</font></strong></a></p><p><font face="Arial" size="2">　　Google本地搜索，通过这一服务，用户可以使用关键字搜索在特定的城市查找某一类型的公司，并在电子地图上显示这些公司的具体位置。这项服务现在有了</font><a href="http://bendi.google.com/" target="_blank"><font face="Arial" color="#0066ff" size="2">中国版本</font></a><font face="Arial" size="2">。 </font></p><p><font face="Arial" size="2">　　</font><a href="http://maps.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Maps</font></strong></a></p><p><font face="Arial" size="2">　　Google地图搜索服务，让你浏览到世界各地的地图、公路等信息，比较上面提到的卫星地图来说，比较传统。</font></p><p><font face="Arial" size="2">　　</font><a href="http://mobile.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Mobile</font></strong></a></p><p><font face="Arial" size="2">　　Google手机上网用户的服务，只要手机能连上这外网站，即可象用PC一样搜索图片、关键字等信息。</font></p><p><font face="Arial" size="2">　　</font><a href="http://www.google.com/movies" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Movie Showtimes</font></strong></a></p><p><font face="Arial" size="2">　　Google提供的电影上映时间搜索服务，只要输入一个地方的邮政编码或地址，就可以搜索到当地的电影院及电影的上映时间。</font></p><p><font face="Arial" size="2">　　</font><a href="http://news.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google News</font></strong></a></p><p><font face="Arial" size="2">　　Google新闻站点，将最新的新闻呈现在大家的眼前，上面的所有新闻都是由Google特定的电脑自动聚合的。</font></p><p><font face="Arial" size="2">　　</font><a href="http://pages.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Page</font></strong></a></p><p><font face="Arial" size="2">　　Google推出的免费个人主页服务，用户可以在这里获得一个100M大小的免费主页空间。</font></p><p><font face="Arial" size="2">　　</font><a href="http://reader.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Reader</font></strong></a></p><p><font face="Arial" size="2">　　Google的在线RSS阅读器，Reader依靠RSS和Atom技术，可帮助用户及时获得信息，用户不必自己检查更新喜欢的站点，Google Reader可以帮你。</font></p><p><font face="Arial" size="2">　　</font><a href="http://labs.google.com/ridefinder" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Ridefinder</font></strong></a></p><p><font face="Arial" size="2">　　美国12个城市的公交车和出租车的相关搜索。</font></p><p><font face="Arial" size="2">　　</font><a href="http://scholar.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Scholar</font></strong></a></p><p><font face="Arial" size="2">　　学术文章搜索引擎，高年级学生的必备，尤其一些经常需要撰写一些论文的朋友。</font></p><p><font face="Arial" size="2">　　</font><a href="http://toolbar.google.com/firefox/extensions/sendtophone/index.html" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Send to Phone</font></strong></a></p><p><font face="Arial" size="2">　　利用网络发送手机短信的服务，感觉上没什么特别。</font></p><p><font face="Arial" size="2">　　</font><a href="https://www.google.com/webmasters/sitemaps/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Sitemap</font></strong></a></p><p><font face="Arial" size="2">　　Google的Sitemaps计划，旨在对网站信息搜索进行加速，增强索引能力。Google称：“这种协作搜索系统将进一步提高覆盖和刷新速度，使用户使用Google索此功能实现最优化。”Google呼吁网站管理员在网站服务器中放置Sitemaps格式的文件。这样，Google的搜索引擎就可以看到那些网页在网站内，那些网页内容被修改了。</font></p><p><font face="Arial" size="2">　　</font><a href="http://sms.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google SMS</font></strong></a></p><p><font face="Arial" size="2">　　GOOGLE SMS服务，是通过SMS查找特定信息的一项技术。它可以提供驾车服务，在无线产品中支持SMS。</font></p><p><font face="Arial" size="2">　　</font><a href="http://www.google.com/webhp?complete=1&hl=en" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Suggest</font></strong></a></p><p><font face="Arial" size="2">　　这是一个猜测你意图的测试站，当用户关键词搜索框中输入文字时，下拉清单将显示候补搜索单词或短语一览。还将显示找到的各单词或短语的网页数。从候补中选择单词或短语便可搜索。</font></p><p><font face="Arial" size="2">　　</font><a href="http://talk.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Talk</font></strong></a></p><p><font face="Arial" size="2">　　Google推出的即时在线聊天工具，当时挺火爆的，业内很多人都说能跟各大即时聊天工具一拼，可是现在没多少个人用了，影响较低。</font></p><p><font face="Arial" size="2">　　</font><a href="http://toolbar.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Toolbar</font></strong></a></p><p><font face="Arial" size="2">　　Google的搜索工具条，上面有很多实用功能，搜索、拦截弹出窗口、查看网页PR值等等一大堆。</font></p><p><font face="Arial" size="2">　　</font><a href="http://video.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Video</font></strong></a></p><p><font face="Arial" size="2">　　这又是一个新的尝试，Google推出的视频搜索内容丰富，不过国内用户好象会受到一定的限制。</font></p><p><font face="Arial" size="2">　　</font><a href="http://webaccelerator.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Web Accelerator</font></strong></a></p><p><font face="Arial" size="2">　　可以加速网页的载入，尤其是对付一些我们网络访问较慢的外国网站更是好用</font></p><p><font face="Arial" size="2">　　</font><a href="http://web.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Google Web Search</font></strong></a></p><p><font face="Arial" size="2">　　Google网站默认的搜索服务。</font></p><p><font face="Arial" size="2">　　</font><a href="http://www.hello.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Hello</font></strong></a></p><p><font face="Arial" size="2">　　Hello即时聊天工具，是一个极小的即时通信客户端，它和Google的看图软件Picasa一起工作，能让你和亲人好友分享图片。</font></p><p><font face="Arial" size="2">　　</font><a href="http://picasa.google.com/" target="_blank"><strong><font face="Arial" color="#0066ff" size="2">Picasa</font></strong></a></p><p><font face="Arial" size="2">　　超强的图片管理显示的软件，得益于其高效的图片管理模式，我们可将电脑里所有的图片都让它归类，分析。它现在已是免费软件，大家可以让ACDSee下岗了。</font></p></div><!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="/logs/1958751.html">Javascript的IE和Firefox兼容性汇编</a> 2006-02-21</div><div><a href="/logs/1826833.html">基于Java的Blog系统</a> 2006-01-16</div><div><a href="/logs/1809689.html">常用网页播放器代码</a> 2006-01-11</div><div><a href="/logs/1754809.html">Linux系统里的进程管理</a> 2005-12-27</div><div><a href="/logs/1751443.html">Java的SAX使用的简单Sample</a> 2005-12-26</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fraymondchen625.blogbus.com%2Flogs%2F2098865.html&title=Google%E6%9C%8D%E5%8A%A1%E5%92%8C%E8%BD%AF%E4%BB%B6%E5%A4%A7%E5%85%A8">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://raymondchen625.blogbus.com/logs/2098865.html</link>
   <author></author>
   <pubDate>Mon, 20 Mar 2006 13:09:07 +0800</pubDate>
  </item>
  <item>
   <title>Javascript的IE和Firefox兼容性汇编</title>
   <description><![CDATA[<tr></tr><td valign="top"></td><div class="subhead"><b>Javascript的IE和Firefox兼容性汇编</b></div></td /></tr /><tr></tr><td class="content" valign="top"></td><table width="200" align="right" border="0"><tbody><tr><td></td></tr></tbody></table><p>以下以 IE 代替 Internet Explorer，以 MF 代替 Mozzila Firefox<br /><br />1. document.form.item 问题<br />    (1)现有问题：<br />        现有代码中存在许多 document.formName.item(&quot;itemName&quot;) 这样的语句，不能在 MF 下运行<br />    (2)解决方法：<br />        改用 document.formName.elements[&quot;elementName&quot;]<br />    (3)其它<br />        参见 2<br /><br />2. 集合类对象问题<br />    (1)现有问题：<br />        现有代码中许多集合类对象取用时使用 ()，IE 能接受，MF 不能。<br />    (2)解决方法：<br />        改用 [] 作为下标运算。如：document.forms(&quot;formName&quot;) 改为 document.forms[&quot;formName&quot;]。<br />        又如：document.getElementsByName(&quot;inputName&quot;)(1) 改为 document.getElementsByName(&quot;inputName&quot;)[1]<br />    (3)其它<br /><br />3. window.event<br />    (1)现有问题：<br />        使用 window.event 无法在 MF 上运行<br />    (2)解决方法：<br />        MF 的 event 只能在事件发生的现场使用，此问题暂无法解决。可以这样变通：<br />        原代码(可在IE中运行)：<br />            &lt;input type=&quot;button&quot; name=&quot;someButton&quot; value=&quot;提交&quot; onclick=&quot;java script:gotoSubmit()&quot;/&gt;<br />            ...<br />            &lt;script language=&quot;java script&quot;&gt;<br />                function gotoSubmit() {<br />                    ...<br />                    alert(window.event);    // use window.event<br />                    ...<br />                }<br />            &lt;/script&gt;<br /><br />        新代码(可在IE和MF中运行)：<br />            &lt;input type=&quot;button&quot; name=&quot;someButton&quot; value=&quot;提交&quot; onclick=&quot;java script:gotoSubmit(event)&quot;/&gt;<br />            ...<br />            &lt;script language=&quot;java script&quot;&gt;<br />                function gotoSubmit(evt) {<br />                    evt = evt ? evt : (window.event ? window.event : null);<br />                    ...<br />                    alert(evt);             // use evt<br />                    ...<br />                }<br />            &lt;/script&gt;<br />        此外，如果新代码中第一行不改，与老代码一样的话(即 gotoSubmit 调用没有给参数)，则仍然只能在IE中运行，但不会出错。所以，这种方案 tpl 部分仍与老代码兼容。<br /><br />4. HTML 对象的 id 作为对象名的问题<br />    (1)现有问题<br />        在 IE 中，HTML 对象的 ID 可以作为 document 的下属对象变量名直接使用。在 MF 中不能。<br />    (2)解决方法<br />        用 getElementById(&quot;idName&quot;) 代替 idName 作为对象变量使用。<br /><br />5. 用idName字符串取得对象的问题<br />    (1)现有问题<br />        在IE中，利用 eval(idName) 可以取得 id 为 idName 的 HTML 对象，在MF 中不能。<br />    (2)解决方法<br />        用 getElementById(idName) 代替 eval(idName)。<br /><br />6. 变量名与某 HTML 对象 id 相同的问题<br />    (1)现有问题<br />        在 MF 中，因为对象 id 不作为 HTML 对象的名称，所以可以使用与 HTML 对象 id 相同的变量名，IE 中不能。<br />    (2)解决方法<br />        在声明变量时，一律加上 var ，以避免歧义，这样在 IE 中亦可正常运行。<br />        此外，最好不要取与 HTML 对象 id 相同的变量名，以减少错误。<br />    (3)其它<br />        参见 问题4<br /><br />7. event.x 与 event.y 问题<br />    (1)现有问题<br />        在IE 中，event 对象有 x, y 属性，MF中没有。<br />    (2)解决方法<br />        在MF中，与event.x 等效的是 event.pageX。但event.pageX IE中没有。<br />        故采用 event.clientX 代替 event.x。在IE 中也有这个变量。<br />        event.clientX 与 event.pageX 有微妙的差别（当整个页面有滚动条的时候），不过大多数时候是等效的。<br /><br />        如果要完全一样，可以稍麻烦些：<br />        mX = event.x ? event.x : event.pageX;<br />        然后用 mX 代替 event.x<br />    (3)其它<br />        event.layerX 在 IE 与 MF 中都有，具体意义有无差别尚未试验。<br /><br /><br />8. 关于frame<br />   (1)现有问题<br />         在 IE中 可以用window.testFrame取得该frame，mf中不行<br />   (2)解决方法<br />         在frame的使用方面mf和ie的最主要的区别是：<br />如果在frame标签中书写了以下属性：<br />&lt;frame src=&quot;/xx.htm&quot; id=&quot;frameId&quot; name=&quot;frameName&quot; /&gt;<br />那么ie可以通过id或者name访问这个frame对应的window对象<br />而mf只可以通过name来访问这个frame对应的window对象<br />例如如果上述frame标签写在最上层的window里面的htm里面，那么可以这样访问<br />ie： window.top.frameId或者window.top.frameName来访问这个window对象<br />mf： 只能这样window.top.frameName来访问这个window对象<br /><br />另外，在mf和ie中都可以使用window.top.document.getElementById(&quot;frameId&quot;)来访问frame标签<br />并且可以通过window.top.document.getElementById(&quot;testFrame&quot;).src = 'xx.htm'来切换frame的内容<br />也都可以通过window.top.frameName.location = 'xx.htm'来切换frame的内容<br />关于frame和window的描述可以参见bbs的‘window与frame’文章<br />以及/test/js/test_frame/目录下面的测试<br />----adun 2004.12.09修改<br /><br />9. 在mf中，自己定义的属性必须getAttribute()取得<br />10.在mf中没有  parentElement parement.children  而用<br />               parentNode parentNode.childNodes<br />   childNodes的下标的含义在IE和MF中不同，MF使用DOM规范，childNodes中会插入空白文本节点。<br />  一般可以通过node.getElementsByTagName()来回避这个问题。<br />   当html中节点缺失时，IE和MF对parentNode的解释不同，例如<br />   &lt;form&gt;<br />   &lt;table&gt;<br />        &lt;input/&gt;<br />   &lt;/table&gt;<br />   &lt;/form&gt;<br />   MF中input.parentNode的值为form, 而IE中input.parentNode的值为空节点<br /><br />  MF中节点没有removeNode方法，必须使用如下方法 node.parentNode.removeChild(node)<br /><br />11.const 问题<br />  (1)现有问题:<br />     在 IE 中不能使用 const 关键字。如 const constVar = 32; 在IE中这是语法错误。<br />  (2)解决方法:<br />     不使用 const ，以 var 代替。<br /><br />12. body 对象<br />   MF的body在body标签没有被浏览器完全读入之前就存在，而IE则必须在body完全被读入之后才存在<br /><br />13. url encoding<br />在js中如果书写url就直接写&amp;不要写&amp;amp;例如var url = 'xx.jsp?objectName=xx&amp;amp;objectEvent=xxx';<br />frm.action = url那么很有可能url不会被正常显示以至于参数没有正确的传到服务器<br />一般会服务器报错参数没有找到<br />当然如果是在tpl中例外，因为tpl中符合xml规范，要求&amp;书写为&amp;amp;<br />一般MF无法识别js中的&amp;amp;<br /><br /><br />14. nodeName 和 tagName 问题<br />  (1)现有问题：<br />     在MF中，所有节点均有 nodeName 值，但 textNode 没有 tagName 值。在 IE 中，nodeName 的使用好象<br />     有问题（具体情况没有测试，但我的IE已经死了好几次）。<br />  (2)解决方法：<br />     使用 tagName，但应检测其是否为空。<br /><br />15. 元素属性<br />   IE下 input.type属性为只读，但是MF下可以修改<br /><br /><br />16. document.getElementsByName() 和 document.all[name] 的问题<br />  (1)现有问题：<br />     在 IE 中，getElementsByName()、document.all[name] 均不能用来取得 div 元素（是否还有其它不能取的元素还不知道）。</p></td /></tr /><!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="http://raymondchen625.blogbus.com/logs/1927089.html">prototype 1.3 源码解读</a> 2006-02-14</div><div><a href="http://raymondchen625.blogbus.com/logs/1809689.html">常用网页播放器代码</a> 2006-01-11</div><div><a href="http://raymondchen625.blogbus.com/logs/1761387.html">prototype.js开发笔记</a> 2005-12-28</div><div><a href="http://raymondchen625.blogbus.com/logs/1752442.html">相册的自动播放效果SlideShow (ZT)</a> 2005-12-23</div><div><a href="http://raymondchen625.blogbus.com/logs/1752421.html">DOM 中 StyleSheet的处理</a> 2005-12-20</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fraymondchen625.blogbus.com%2Flogs%2F1958751.html&title=Javascript%E7%9A%84IE%E5%92%8CFirefox%E5%85%BC%E5%AE%B9%E6%80%A7%E6%B1%87%E7%BC%96">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://raymondchen625.blogbus.com/logs/1958751.html</link>
   <author></author>
   <pubDate>Tue, 21 Feb 2006 22:50:08 +0800</pubDate>
  </item>
  <item>
   <title>prototype 1.3 源码解读</title>
   <description><![CDATA[<p>/*prototype 1.3.1 版本和之前的 1.2.0 版本有了不少改进,并增加了新的功能： <br />1. 增加了事件注册管理 <br />2. 增加了空间定位的常用函数 <br />3. 改善了 xmlhttp 的封装 <br />4. 移除了 Effect.js，交给 Rico 或者 script.aculo.us 这些扩展库类实现。 <br />5. bug 修复 <br />代码: <br />*/<br />/** <br />* 定义一个全局对象, 属性 Version 在发布的时候会替换为当前版本号 <br />*/ <br />var Prototype = { <br />Version: '1.3.1', <br />// 一个空方法，其后的代码常会用到，先前的版本该方法被定义于 Ajax 类中。 <br />emptyFunction: function() {} <br />} <br />/** <br />* 创建一种类型，注意其属性 create 是一个方法，返回一个构造函数。 <br />* 一般使用如下 <br />*   var X = Class.create(); 返回一个类型，类似于 java 的一个Class实例。 <br />* 要使用 X 类型，需继续用 new X()来获取一个实例，如同 java 的 Class.newInstance()方法。 <br />* <br />* 返回的构造函数会执行名为 initialize 的方法， initialize 是 Ruby 对象的构造器方法名字。 <br />* 此时initialize方法还没有定义，其后的代码中创建新类型时会建立相应的同名方法。 <br />* <br />*/ <br />var Class = { <br />create: function() { <br />  return function() { <br />    this.initialize.apply(this, arguments); <br />  } <br />} <br />} </p><p>/** <br />* 创建一个对象，从变量名来思考，本意也许是定义一个抽象类，以后创建新对象都 extend 它。 <br />* 但从其后代码的应用来看， Abstract 更多是为了保持命名空间清晰的考虑。 <br />* 也就是说，我们可以给 Abstract 这个对象实例添加新的对象定义。 <br />*/ <br />var Abstract = new Object(); </p><p>Object.extend = function(destination, source) { <br />for (property in source) { <br />  destination[property] = source[property]; <br />} <br />return destination; <br />} <br />/** <br />* 获取参数对象的所有属性和方法，有点象多重继承。但是这种继承是动态获得的。 <br />* 如： <br />*   var a = new ObjectA(), b = new ObjectB(); <br />*   var c = a.extend(b); <br />* 此时 c 对象同时拥有 a 和 b 对象的属性和方法。但是与多重继承不同的是，c instanceof ObjectB 将返回false。 <br />* <br />* 旧版本的该方法定义如下： <br />* Object.prototype.extend = function(object) { <br />*   for (property in object) { <br />*       this[property] = object[property]; <br />*   } <br />*   return this; <br />* } <br />* <br />* 新的形式新定义了一个静态方法 Object.extend，这样做的目的大概是为了使代码更为清晰 <br />*/ <br />Object.prototype.extend = function(object) { <br />return Object.extend.apply(this, [this, object]); <br />} </p><p>/** <br />* 这个方法很有趣，它封装一个javascript函数对象，返回一个新函数对象，新函数对象的主体和原对象相同，但是bind()方法参数将被用作当前对象的对象。 <br />* 也就是说新函数中的 this 引用被改变为参数提供的对象。 <br />* 比如： <br />*   &lt;input type=&quot;text&quot; id=&quot;aaa&quot; value=&quot;aaa&quot;&gt; <br />*   &lt;input type=&quot;text&quot; id=&quot;bbb&quot; value=&quot;bbb&quot;&gt; <br />*   ................. <br />*   &lt;script&gt; <br />*       var aaa = document.getElementById(&quot;aaa&quot;); <br />*       var bbb = document.getElementById(&quot;bbb&quot;); <br />*       aaa.showValue = function() {alert(this.value);} <br />*       aaa.showValue2 = aaa.showValue.bind(bbb); <br />*   &lt;/script&gt; <br />* 那么，调用aaa.showValue 将返回&quot;aaa&quot;, 但调用aaa.showValue2 将返回&quot;bbb&quot;。 <br />* <br />* apply 是ie5.5后才出现的新方法(Netscape好像很早就支持了)。 <br />* 该方法更多的资料参考MSDN <a onclick="function anonymous()
{
return newin('http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthApply.asp')
}" href="http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthApply.asp">http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthApply.asp</a> <br />* 阅读其后的代码就会发现，bind 被应用的很广泛，该方法和 Object.prototype.extend 一样是 Prototype 的核心。 <br />* 还有一个 call 方法，应用起来和 apply 类似。可以一起研究下。 <br />*/ <br />Function.prototype.bind = function(object) { <br />var __method = this; <br />return function() { <br />  __method.apply(object, arguments); <br />} <br />} <br />/** <br />* 和bind一样，不过这个方法一般用做html控件对象的事件处理。所以要传递event对象 <br />* 注意这时候，用到了 Function.call。它与 Function.apply 的不同好像仅仅是对参数形式的定义。 <br />*/ <br />Function.prototype.bindAsEventListener = function(object) { <br />var __method = this; <br />return function(event) { <br />  __method.call(object, event || window.event); <br />} <br />} <br />/** <br />* 将整数形式RGB颜色值转换为HEX形式 <br />*/ <br />Number.prototype.toColorPart = function() { <br />var digits = this.toString(16); <br />if (this &lt; 16) return '0' + digits; <br />return digits; <br />} <br />/** <br />* 典型 Ruby 风格的函数，将参数中的方法逐个调用，返回第一个成功执行的方法的返回值 <br />*/ <br />var Try = { <br />these: function() { <br />  var returnValue; </p><p>  for (var i = 0; i &lt; arguments.length; i++) { <br />    var lambda = arguments[i]; <br />    try { <br />    returnValue = lambda(); <br />    break; <br />    } catch (e) {} <br />  } </p><p>  return returnValue; <br />} <br />} <br />/*--------------------------------------------------------------------------*/ </p><p>/** <br />* 一个设计精巧的定时执行器 <br />* 首先由 Class.create() 创建一个 PeriodicalExecuter 类型， <br />* 然后用对象直接量的语法形式设置原型。 <br />* <br />* 需要特别说明的是 rgisterCallback 方法，它调用上面定义的函数原型方法bind, 并传递自己为参数。 <br />* 之所以这样做，是因为 setTimeout 默认总以 window 对象为当前对象，也就是说，如果 registerCallback 方法定义如下的话： <br />*   registerCallback: function() { <br />*       setTimeout(this.onTimerEvent, this.frequency * 1000); <br />*   } <br />* 那么，this.onTimeoutEvent 方法执行失败，因为它无法访问 this.currentlyExecuting 属性。 <br />* 而使用了bind以后，该方法才能正确的找到this，也就是PeriodicalExecuter的当前实例。 <br />*/ <br />var PeriodicalExecuter = Class.create(); <br />PeriodicalExecuter.prototype = { <br />initialize: function(callback, frequency) { <br />  this.callback = callback; <br />  this.frequency = frequency; <br />  this.currentlyExecuting = false; <br />  this.registerCallback(); <br />}, </p><p>registerCallback: function() { <br />  setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); <br />}, </p><p>onTimerEvent: function() { <br />  if (!this.currentlyExecuting) { <br />    try { <br />    this.currentlyExecuting = true; <br />    this.callback(); <br />    } finally { <br />    this.currentlyExecuting = false; <br />    } <br />  } <br />} <br />} </p><p>/*--------------------------------------------------------------------------*/ </p><p>/** <br />* 这个函数就 Ruby 了。我觉得它的作用主要有两个 <br />* 1. 大概是 document.getElementById(id) 的最简化调用。 <br />* 比如：$(&quot;aaa&quot;) 将返回 aaa 对象 <br />* 2. 得到对象数组 <br />* 比如: $(&quot;aaa&quot;,&quot;bbb&quot;) 返回一个包括id为&quot;aaa&quot;和&quot;bbb&quot;两个input控件对象的数组。 <br />*/ <br />function $() { <br />var elements = new Array(); </p><p>for (var i = 0; i &lt; arguments.length; i++) { <br />  var element = arguments[i]; <br />  if (typeof element == 'string') <br />    element = document.getElementById(element); </p><p>  if (arguments.length == 1) <br />    return element; </p><p>  elements.push(element); <br />} </p><p>return elements; <br />} </p><p>/** <br />* 为兼容旧版本的浏览器增加 Array 的 push 方法。 <br />*/ <br />if (!Array.prototype.push) { <br />Array.prototype.push = function() { <br />    var startLength = this.length; <br />    for (var i = 0; i &lt; arguments.length; i++) <br />    this[startLength + i] = arguments[i]; <br />  return this.length; <br />} <br />} </p><p>/** <br />* 为兼容旧版本的浏览器增加 Function 的 apply 方法。 <br />*/ <br />if (!Function.prototype.apply) { <br />// Based on code from <a onclick="function anonymous()
{
return newin('http://www.youngpup.net/')
}" href="http://www.youngpup.net/">http://www.youngpup.net/</a> <br />Function.prototype.apply = function(object, parameters) { <br />  var parameterStrings = new Array(); <br />  if (!object)   object = window; <br />  if (!parameters) parameters = new Array(); <br />  <br />  for (var i = 0; i &lt; parameters.length; i++) <br />    parameterStrings[i] = 'parameters[' + i + ']'; <br />  <br />  object.__apply__ = this; <br />  var result = eval('object.__apply__(' + <br />    parameterStrings.join(', ') + ')'); <br />  object.__apply__ = null; <br />  <br />  return result; <br />} <br />} </p><p>/** <br />* 扩展 javascript 内置的 String 对象 <br />*/ <br />String.prototype.extend({ <br />/** <br />  * 去掉字符串中的&lt;html&gt;标签 <br />  */ <br />stripTags: function() { <br />  return this.replace(/&lt;\/?[^&gt;]+&gt;/gi, ''); <br />}, <br />/** <br />  * 这个方法很常见，通常的实现都是用正则表达式替换特殊字符为html规范定义的命名实体或者十进制编码，比如： <br />  * string.replace(/&amp;/g, &quot;&amp;&quot;).replace(/&lt;/g, &quot;&lt;&quot;).replace(/&gt;/g, &quot;&gt;&quot;); <br />  * 而这里的实现借用浏览器自身的内部替换，确实巧妙。 <br />  */ <br />escapeHTML: function() { <br />  var div = document.createElement('div'); <br />  var text = document.createTextNode(this); <br />  div.appendChild(text); <br />  return div.innerHTML; <br />}, <br />  /** <br />  * 同上 <br />  */ <br />unescapeHTML: function() { <br />  var div = document.createElement('div'); <br />  div.innerHTML = this.stripTags(); <br />  return div.childNodes[0].nodeValue; <br />} <br />}); <br />/** <br />* 定义 Ajax 对象, 静态方法 getTransport 方法返回一个 XMLHttp 对象 <br />*/ <br />var Ajax = { <br />getTransport: function() { <br />  return Try.these( <br />    function() {return new ActiveXObject('Msxml2.XMLHTTP')}, <br />    function() {return new ActiveXObject('Microsoft.XMLHTTP')}, <br />    function() {return new XMLHttpRequest()} <br />  ) || false; <br />} <br />} <br />/** <br />* 我以为此时的Ajax对象起到命名空间的作用。 <br />* Ajax.Base 声明为一个基础对象类型 <br />* 注意 Ajax.Base 并没有使用 Class.create() 的方式来创建，我想是因为作者并不希望 Ajax.Base 被库使用者实例化。 <br />* 作者在其他对象类型的声明中，将会继承于它。 <br />* 就好像 java 中的私有抽象类 <br />*/ <br />Ajax.Base = function() {}; <br />Ajax.Base.prototype = { <br />/** <br />  * extend (见上) 的用法真是让人耳目一新 <br />  * options 首先设置默认属性，然后再 extend 参数对象，那么参数对象中也有同名的属性，那么就覆盖默认属性值。 <br />  * 想想如果我写这样的实现，应该类似如下： <br />  setOptions: function(options) { <br />    this.options.methed = options.methed? options.methed : 'post'; <br />    .......... <br />  } <br />  我想很多时候，java 限制了 js 的创意。 <br />  */ <br />setOptions: function(options) { <br />  this.options = { <br />    method:     'post', <br />    asynchronous: true, <br />    parameters:   '' <br />  }.extend(options || {}); <br />}, <br />/** <br />  * 如果　xmlhttp 调用返回正确的HTTP状态值，函数返回ture,　反之false。 <br />  * xmlhttp　的 readyState 属性不足以准确判断 xmlhttp　远程调用成功，该方法是readyState判断的一个前提条件 <br />  */ <br />responseIsSuccess: function() { <br />  return this.transport.status == undefined <br />    || this.transport.status == 0 <br />    || (this.transport.status &gt;= 200 &amp;&amp; this.transport.status &lt; 300); <br />}, <br />/** <br />  * 如果　xmlhttp 调用返回错误的HTTP状态值，函数返回ture,　反之false。 <br />  */ <br />responseIsFailure: function() { <br />  return !this.responseIsSuccess(); <br />} <br />} <br />/** <br />* Ajax.Request 封装 XmlHttp <br />*/ <br />Ajax.Request = Class.create(); </p><p>/** <br />* 定义四种事件(状态)， <a onclick="function anonymous()
{
return newin('http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/readystate_1.asp')
}" href="http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/readystate_1.asp">参考</a> <br />*/ <br />Ajax.Request.Events = <br />['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; </p><p>/** <br />*　相比先前的版本，对于　xmlhttp 的调用和返回值处理分离得更为清晰 <br />*/ <br />Ajax.Request.prototype = (new Ajax.Base()).extend({ <br />initialize: function(url, options) { <br />  this.transport = Ajax.getTransport(); <br />  this.setOptions(options); <br />  this.request(url); <br />}, </p><p>　/** <br />  * 新增加 request 方法封装 xmlhttp　的调用过程。 <br />  */ <br />request: function(url) { <br />  var parameters = this.options.parameters || ''; <br />  if (parameters.length &gt; 0) parameters += '&amp;_='; </p><p>  try { <br />    if (this.options.method == 'get') <br />    url += '?' + parameters; </p><p>    this.transport.open(this.options.method, url, <br />    this.options.asynchronous); </p><p>    if (this.options.asynchronous) { <br />    this.transport.onreadystatechange = this.onStateChange.bind(this); <br />    setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); <br />    } </p><p>    this.setRequestHeaders(); </p><p>    var body = this.options.postBody ? this.options.postBody : parameters; <br />    this.transport.send(this.options.method == 'post' ? body : null); </p><p>  } catch (e) { <br />  } <br />}, </p><p>/** <br />  * 新增加的 setRequestHeaders 方法允许添加自定义的http header <br />  */ <br />setRequestHeaders: function() { <br />  var requestHeaders = <br />    ['X-Requested-With', 'XMLHttpRequest', <br />    'X-Prototype-Version', Prototype.Version]; </p><p>  if (this.options.method == 'post') { <br />    requestHeaders.push('Content-type', <br />    'application/x-www-form-urlencoded'); </p><p>    /* Force &quot;Connection: close&quot; for Mozilla browsers to work around <br />    * a bug where XMLHttpReqeuest sends an incorrect Content-length <br />    * header. See Mozilla Bugzilla #246651. <br />    */ <br />    if (this.transport.overrideMimeType) <br />    requestHeaders.push('Connection', 'close'); <br />  } </p><p>  /** <br />  * 其后的 apply 方法的调用有些奇技淫巧的意味 <br />  * 从上下文中我们可以分析出 this.options.requestHeaders 是调用者自定义的http header数组。 <br />  * requestHeaders 也是一个数组，将一个数组中的元素逐个添加到另一个元素中，直接调用 <br />  * requestHeaders.push(this.options.requestHeaders) <br />  * 是不行的，因为该调用导致 this.options.requestHeaders 整个数组作为一个元素添加到 requestHeaders中。 <br />  * javascript的Array对象还提供一个concat 的方法表面上满足要求，但是concat实际上是创建一个新数组，将两个数组的元素添加到新数组中。 <br />  * 所以，下面的代码也可以替换为 <br />  * requestHeaders = requestHeaders.concat(this.options.requestHeaders); <br />  * 很显然，作者不喜欢这样的代码方式 <br />  * 而 apply 方法的语法 apply([thisObj[,argArray]]) 本身就要求第二个参数是一个数组或者arguments对象。 <br />  * 所以巧妙的实现了 concat 函数的作用。 <br />  * 令人拍案叫绝啊! <br />  */ <br />  if (this.options.requestHeaders) <br />    requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); </p><p>  for (var i = 0; i &lt; requestHeaders.length; i += 2) <br />    this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); <br />}, </p><p><br />onStateChange: function() { <br />  var readyState = this.transport.readyState; <br />  /** <br />  * 如果不是 Loading 状态，就调用回调函数 <br />  */ <br />  if (readyState != 1) <br />    this.respondToReadyState(this.transport.readyState); <br />}, </p><p>/** <br />  * 回调函数定义在 this.options 属性中，比如: <br />    var option = { <br />      onLoaded : function(req) {...}; <br />      ...... <br />    } <br />    new Ajax.Request(url, option); <br />  */ <br />respondToReadyState: function(readyState) { <br />  var event = Ajax.Request.Events[readyState]; </p><p>  /** <br />  * 新增的回调函数处理，调用者还可以在options中定义 on200, onSuccess 这样的回调函数 <br />  * 在 readyState 为完成状态的时候调用 <br />  */ <br />  if (event == 'Complete') <br />    (this.options['on' + this.transport.status] <br />    || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] <br />    || Prototype.emptyFunction)(this.transport); </p><p>  (this.options['on' + event] || Prototype.emptyFunction)(this.transport); </p><p>  /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ <br />  if (event == 'Complete') <br />    this.transport.onreadystatechange = Prototype.emptyFunction; <br />} <br />}); </p><p>/** <br />* Ajax.Updater 用于绑定一个html元素与 XmlHttp调用的返回值。类似与 buffalo 的 bind。 <br />* 如果 options 中有 insertion(见后) 对象的话, insertion 能提供更多的插入控制。 <br />*/ <br />Ajax.Updater = Class.create(); <br />Ajax.Updater.ScriptFragment = '(?:&lt;script.*?&gt;)((\n|.)*?)(?:&lt;\/script&gt;)'; </p><p>Ajax.Updater.prototype.extend(Ajax.Request.prototype).extend({ <br />initialize: function(container, url, options) { </p><p>  /** <br />  * containers 就是被绑定的 html 对象，xmlhttp的返回值被赋给该对象的 innerHTML 属性。 <br />  * 相比新版本，containers 根据container参数定义 success 和 failure 引用，如果它们被定义的话，根据xmlhttp调用是否成功来选择 <br />  * 更新对象，假想调用可能如下： <br />  * var c = {success: $(&quot;successDiv&quot;), failure: $(&quot;failureDiv&quot;)}; <br />  * new Ajax.Updater(c, url, options); <br />  * 那么调用成功则 successDiv 显示成功信息或者数据，反之 failureDiv 显示错误信息 <br />  */ <br />  this.containers = { <br />    success: container.success ? $(container.success) : $(container), <br />    failure: container.failure ? $(container.failure) : <br />    (container.success ? null : $(container)) <br />  } </p><p>  this.transport = Ajax.getTransport(); <br />  this.setOptions(options); </p><p>  var onComplete = this.options.onComplete || Prototype.emptyFunction; <br />  this.options.onComplete = (function() { <br />    this.updateContent(); <br />    onComplete(this.transport); <br />  }).bind(this); </p><p>  this.request(url); <br />}, </p><p>updateContent: function() { <br />  var receiver = this.responseIsSuccess() ? <br />    this.containers.success : this.containers.failure; </p><p>  var match   = new RegExp(Ajax.Updater.ScriptFragment, 'img'); <br />  var response = this.transport.responseText.replace(match, ''); <br />  var scripts = this.transport.responseText.match(match); </p><p>  if (receiver) { <br />    if (this.options.insertion) { <br />    new this.options.insertion(receiver, response); <br />    } else { <br />    receiver.innerHTML = response; <br />    } <br />  } </p><p>  if (this.responseIsSuccess()) { <br />    if (this.onComplete) <br />    setTimeout((function() {this.onComplete( <br />      this.transport)}).bind(this), 10); <br />  } </p><p>  /** <br />  * 如果调用者在传入的options参数中定义 evalScripts=true，同时xmlhttp返回值的html中包含&lt;script&gt;标签的话，执行该脚本 <br />  */ <br />  if (this.options.evalScripts &amp;&amp; scripts) { <br />  /** <br />    * 注意前二十行左右还有一个 match 的声明 <br />    * var match   = new RegExp(Ajax.Updater.ScriptFragment, 'img'); <br />    * 和此处的区别就是，正则表达式匹配标记多一个 &quot;g&quot;。 <br />    * 多个g, 所以 scripts 是一个数组，数组中每个元素是一段 &lt;script&gt;...&lt;/script&gt; 文本。 <br />    * 没有g, scripts[i].match(match)[1] 匹配的就是 &lt;script&gt;标记中的 script 代码。 <br />    * 关于正则表达式，请参考javascript的相关资料。 <br />    */ <br />    match = new RegExp(Ajax.Updater.ScriptFragment, 'im'); <br />    setTimeout((function() { <br />    for (var i = 0; i &lt; scripts.length; i++) <br />      eval(scripts[i].match(match)[1]); <br />    }).bind(this), 10); <br />  } <br />} <br />}); </p><p>/** <br />* 定期更新器 <br />*/ <br />Ajax.PeriodicalUpdater = Class.create(); <br />Ajax.PeriodicalUpdater.prototype = (new Ajax.Base()).extend({ <br />initialize: function(container, url, options) { <br />  this.setOptions(options); <br />  this.onComplete = this.options.onComplete; </p><p>  this.frequency = (this.options.frequency || 2); <br />  // decay 可能是一个时间调整因素 <br />  this.decay = 1; </p><p>  this.updater = {}; <br />  this.container = container; <br />  this.url = url; </p><p>  this.start(); <br />}, </p><p>start: function() { <br />  this.options.onComplete = this.updateComplete.bind(this); <br />  this.onTimerEvent(); <br />}, </p><p>stop: function() { <br />  this.updater.onComplete = undefined; <br />  clearTimeout(this.timer); <br />  (this.onComplete || Ajax.emptyFunction).apply(this, arguments); <br />}, </p><p>updateComplete: function(request) { <br />  if (this.options.decay) { <br />    this.decay = (request.responseText == this.lastText ? <br />    this.decay * this.options.decay : 1); </p><p>    this.lastText = request.responseText; <br />  } <br />  this.timer = setTimeout(this.onTimerEvent.bind(this), <br />    this.decay * this.frequency * 1000); <br />}, </p><p>onTimerEvent: function() { <br />  this.updater = new Ajax.Updater(this.container, this.url, this.options); <br />} <br />}); </p><p>/** <br />* 根据 class attribute 的名字得到对象数组，支持 multiple class <br />* <br />*/ <br />document.getElementsByClassName = function(className) { <br />var children = document.getElementsByTagName('*') || document.all; <br />var elements = new Array(); </p><p>for (var i = 0; i &lt; children.length; i++) { <br />  var child = children[i]; <br />  var classNames = child.className.split(' '); <br />  for (var j = 0; j &lt; classNames.length; j++) { <br />    if (classNames[j] == className) { <br />    elements.push(child); <br />    break; <br />    } <br />  } <br />} </p><p>return elements; <br />} </p><p>/*--------------------------------------------------------------------------*/ </p><p>/** <br />* Element 就象一个 java 的工具类，主要用来 隐藏/显示/销除 对象，以及获取对象的简单属性。 <br />* <br />*/ <br />if (!window.Element) { <br />var Element = new Object(); <br />} </p><p>Object.extend(Element, { <br />/** <br />  * 切换 显示/隐藏 <br />  */ <br />toggle: function() { <br />  for (var i = 0; i &lt; arguments.length; i++) { <br />    var element = $(arguments[i]); <br />    element.style.display = <br />    (element.style.display == 'none' ? '' : 'none'); <br />  } <br />}, </p><p>hide: function() { <br />  for (var i = 0; i &lt; arguments.length; i++) { <br />    var element = $(arguments[i]); <br />    element.style.display = 'none'; <br />  } <br />}, </p><p>show: function() { <br />  for (var i = 0; i &lt; arguments.length; i++) { <br />    var element = $(arguments[i]); <br />    element.style.display = ''; <br />  } <br />}, </p><p>/** <br />  * 从父节点中移除 <br />  */ <br />remove: function(element) { <br />  element = $(element); <br />  element.parentNode.removeChild(element); <br />}, <br />  <br />getHeight: function(element) { <br />  element = $(element); <br />  return element.offsetHeight; <br />}, </p><p>/** <br />  * 是否拥有 class 属性值 <br />  */ <br />hasClassName: function(element, className) { <br />  element = $(element); <br />  if (!element) <br />    return; <br />  var a = element.className.split(' '); <br />  for (var i = 0; i &lt; a.length; i++) { <br />    if (a[i] == className) <br />    return true; <br />  } <br />  return false; <br />}, </p><p>/** <br />  * 为对象添加 class 属性值 <br />  */ <br />addClassName: function(element, className) { <br />  element = $(element); <br />  Element.removeClassName(element, className); <br />  element.className += ' ' + className; <br />}, </p><p>/** <br />  * 为对象移除 class 属性值 <br />  */ <br />removeClassName: function(element, className) { <br />  element = $(element); <br />  if (!element) <br />    return; <br />  var newClassName = ''; <br />  var a = element.className.split(' '); <br />  for (var i = 0; i &lt; a.length; i++) { <br />    if (a[i] != className) { <br />    if (i &gt; 0) <br />      newClassName += ' '; <br />    newClassName += a[i]; <br />    } <br />  } <br />  element.className = newClassName; <br />}, </p><p>// removes whitespace-only text node children <br />cleanWhitespace: function(element) { <br />  var element = $(element); <br />  for (var i = 0; i &lt; element.childNodes.length; i++) { <br />    var node = element.childNodes[i]; <br />    if (node.nodeType == 3 &amp;&amp; !/\S/.test(node.nodeValue)) <br />    Element.remove(node); <br />  } <br />} <br />}); </p><p>/** <br />* 为 Element.toggle 做了一个符号连接，大概是兼容性的考虑 <br />*/ <br />var Toggle = new Object(); <br />Toggle.display = Element.toggle; </p><p>/** <br />* 动态插入内容的实现，MS的Jscript实现中对象有一个(<a onclick="function anonymous()
{
return newin('http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/insertadjacenthtml.asp')
}" href="http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/insertadjacenthtml.asp">insertAdjacentHTML</a>)  方法<br />* 这里算是一个对象形式的封装。 <br />*/ <br />Abstract.Insertion = function(adjacency) { <br />this.adjacency = adjacency; <br />} </p><p>Abstract.Insertion.prototype = { <br />initialize: function(element, content) { <br />  this.element = $(element); <br />  this.content = content; <br />  <br />  if (this.adjacency &amp;&amp; this.element.insertAdjacentHTML) { <br />    this.element.insertAdjacentHTML(this.adjacency, this.content); <br />  } else { <br />    /** <br />    * gecko 不支持 insertAdjacentHTML 方法，但可以用如下代码代替 <br />    */ <br />    this.range = this.element.ownerDocument.createRange(); <br />  /** <br />    * 如果定义了 initializeRange 方法，则实行，这里相当与定义了一个抽象的 initializeRange 方法 <br />    */ <br />    if (this.initializeRange) this.initializeRange(); <br />    this.fragment = this.range.createContextualFragment(this.content); <br />  /** <br />    * insertContent 也是一个抽象方法，子类必须实现 <br />    */ <br />    this.insertContent(); <br />  } <br />} <br />} <br />/** <br />* prototype 加深了我的体会，就是写js 如何去遵循　Don’t Repeat Yourself (DRY) 原则 <br />* 上文中 Abstract.Insertion 算是一个抽象类，定义了名为　initializeRange 的一个抽象方法 <br />* var Insertion = new Object()　建立一个命名空间 <br />* Insertion.Before|Top|Bottom|After 就象是四个java中的四个静态内部类，而它们分别继承于Abstract.Insertion，并实现了initializeRange方法。 <br />*/ <br />var Insertion = new Object(); <br />/** <br />* 将内容插入到指定节点的前面, 与指定节点同级 <br />*/ <br />Insertion.Before = Class.create(); <br />Insertion.Before.prototype = (new Abstract.Insertion('beforeBegin')).extend({ <br />initializeRange: function() { <br />  this.range.setStartBefore(this.element); <br />}, </p><p>insertContent: function() { <br />  this.element.parentNode.insertBefore(this.fragment, this.element); <br />} <br />}); <br />/** <br />* 将内容插入到指定节点的第一个子节点前，于是内容变为该节点的第一个子节点 <br />*/ <br />Insertion.Top = Class.create(); <br />Insertion.Top.prototype = (new Abstract.Insertion('afterBegin')).extend({ <br />initializeRange: function() { <br />  this.range.selectNodeContents(this.element); <br />  this.range.collapse(true); <br />}, </p><p>insertContent: function() { <br />  this.element.insertBefore(this.fragment, this.element.firstChild); <br />} <br />}); <br />/** <br />* 将内容插入到指定节点的最后，于是内容变为该节点的最后一个子节点 <br />*/ <br />Insertion.Bottom = Class.create(); <br />Insertion.Bottom.prototype = (new Abstract.Insertion('beforeEnd')).extend({ <br />initializeRange: function() { <br />  this.range.selectNodeContents(this.element); <br />  this.range.collapse(this.element); <br />}, </p><p>insertContent: function() { <br />  this.element.appendChild(this.fragment); <br />} <br />}); <br />/** <br />* 将内容插入到指定节点的后面, 与指定节点同级 <br />*/ <br />Insertion.After = Class.create(); <br />Insertion.After.prototype = (new Abstract.Insertion('afterEnd')).extend({ <br />initializeRange: function() { <br />  this.range.setStartAfter(this.element); <br />}, </p><p>insertContent: function() { <br />  this.element.parentNode.insertBefore(this.fragment, <br />    this.element.nextSibling); <br />} <br />}); <br />/** <br />* 针对 页面元素对象(一般都是表单控件)的工具类，提供一些简单静态方法 <br />* 这些方法显然常用在表单处理中 <br />* 注意 Field 这种声明方式类似于 java 声明一个静态的 singleton 工具类 <br />* 等同于 : <br />*   var Field = new Object(); <br />*   Field.extend({...}); <br />* <br />* 后文中的 Form, Event, Position 对象声明方式如出一辙 <br />*/ <br />var Field = { <br />/** <br />  * 清除参数引用的对象的值 <br />  */ <br />clear: function() { <br />  for (var i = 0; i &lt; arguments.length; i++) <br />    $(arguments[i]).value = ''; <br />}, <br />/** <br />  * 使参数引用对象获取焦点 <br />  */ <br />focus: function(element) { <br />  $(element).focus(); <br />}, <br />  /** <br />  * 判断参数引用对象是否有非空值，如为空值，返回false, 反之true <br />  */ <br />present: function() { <br />  for (var i = 0; i &lt; arguments.length; i++) <br />    if ($(arguments[i]).value == '') return false; <br />  return true; <br />}, <br />/** <br />  * 使选中参数引用对象 <br />  */ <br />select: function(element) { <br />  $(element).select(); <br />}, <br />/** <br />  * 使参数引用对象处于可编辑状态 <br />  */ <br />activate: function(element) { <br />  $(element).focus(); <br />  $(element).select(); <br />} <br />} <br />/** <br />* 表单工具类 <br />*/ <br />var Form = { <br />/** <br />  * 将表单元素序列化后的值(其实就是 name=value 形式的名值配对)组合成 QueryString 的形式 <br />  */ <br />serialize: function(form) { <br />  var elements = Form.getElements($(form)); <br />  var queryComponents = new Array(); <br />  <br />  for (var i = 0; i &lt; elements.length; i++) { <br />    var queryComponent = Form.Element.serialize(elements[i]); <br />    if (queryComponent) <br />    queryComponents.push(queryComponent); <br />  } <br />  <br />  return queryComponents.join('&amp;'); <br />}, <br />/** <br />  * 得到表单的所有元素对象 <br />  */ <br />getElements: function(form) { <br />  var form = $(form); <br />  var elements = new Array(); </p><p>  for (tagName in Form.Element.Serializers) { <br />    var tagElements = form.getElementsByTagName(tagName); <br />    for (var j = 0; j &lt; tagElements.length; j++) <br />    elements.push(tagElements[j]); <br />  } <br />  return elements; <br />}, <br />/** <br />  * 根据 type 和 name 过滤得到表单中符合的 &lt;input&gt; 对象 <br />  */ <br />getInputs: function(form, typeName, name) { <br />  var form = $(form); <br />  var inputs = form.getElementsByTagName('input'); <br />  <br />  if (!typeName &amp;&amp; !name) <br />    return inputs; <br />    <br />  var matchingInputs = new Array(); <br />  for (var i = 0; i &lt; inputs.length; i++) { <br />    var input = inputs[i]; <br />    if ((typeName &amp;&amp; input.type != typeName) || <br />      (name &amp;&amp; input.name != name)) <br />    continue; <br />    matchingInputs.push(input); <br />  } </p><p>  return matchingInputs; <br />}, <br />/** <br />  * 将指定表单的元素置于不可用状态 <br />  */ <br />disable: function(form) { <br />  var elements = Form.getElements(form); <br />  for (var i = 0; i &lt; elements.length; i++) { <br />    var element = elements[i]; <br />    element.blur(); <br />    element.disabled = 'true'; <br />  } <br />}, <br />/** <br />  * 将指定表单的元素置于可用状态 <br />  */ <br />enable: function(form) { <br />  var elements = Form.getElements(form); <br />  for (var i = 0; i &lt; elements.length; i++) { <br />    var element = elements[i]; <br />    element.disabled = ''; <br />  } <br />}, <br />/** <br />  * 使表单的第一个非 hidden 类型而且处于可用状态的元素获得焦点 <br />  */ <br />focusFirstElement: function(form) { <br />  var form = $(form); <br />  var elements = Form.getElements(form); <br />  for (var i = 0; i &lt; elements.length; i++) { <br />    var element = elements[i]; <br />    if (element.type != 'hidden' &amp;&amp; !element.disabled) { <br />    Field.activate(element); <br />    break; <br />    } <br />  } <br />}, <br />/* <br />  * 重置表单 <br />  */ <br />reset: function(form) { <br />  $(form).reset(); <br />} <br />} <br />/** <br />* 表单元素工具类 <br />*/ <br />Form.Element = { <br />/** <br />  * 返回表单元素的值先序列化, 其实就是 name=value 形式的名值配对 <br />  */ <br />serialize: function(element) { <br />  var element = $(element); <br />  var method = element.tagName.toLowerCase(); <br />  var parameter = Form.Element.Serializers[method](element); <br />  <br />  if (parameter) <br />    return encodeURIComponent(parameter[0]) + '=' + <br />    encodeURIComponent(parameter[1]);             <br />}, <br />/** <br />  * 返回表单元素的值 <br />  */ <br />getValue: function(element) { <br />  var element = $(element); <br />  var method = element.tagName.toLowerCase(); <br />  var parameter = Form.Element.Serializers[method](element); <br />  <br />  if (parameter) <br />    return parameter[1]; <br />} <br />} <br />/** <br />* prototype 的所谓序列化其实就是将表单的名字和值组合成一个数组 <br />*/ <br />Form.Element.Serializers = { <br />input: function(element) { <br />  switch (element.type.toLowerCase()) { <br />    case 'submit': <br />    case 'hidden': <br />    case 'password': <br />    case 'text': <br />    return Form.Element.Serializers.textarea(element); <br />    case 'checkbox': <br />    case 'radio': <br />    return Form.Element.Serializers.inputSelector(element); <br />  } <br />  return false; <br />}, <br />/** <br />  * 单/多选框 由此方法处理序列化 <br />  */ <br />inputSelector: function(element) { <br />  if (element.checked) <br />    return [element.name, element.value]; <br />}, <br />/** <br />  * textarea 由此方法处理序列化 <br />  */ <br />textarea: function(element) { <br />  return [element.name, element.value]; <br />}, <br />/** <br />  * select 下拉列表由此方法处理序列化 <br />  */ <br />select: function(element) { <br />  var value = ''; <br />  if (element.type == 'select-one') { <br />    var index = element.selectedIndex; <br />    if (index &gt;= 0) <br />    value = element.options[index].value || element.options[index].text; <br />  } else { <br />/** <br />    * 支持 select-mulitple 的下拉列表，返回的数组的第二个元素，是一个值数组 <br />    */ <br />    value = new Array(); <br />    for (var i = 0; i &lt; element.length; i++) { <br />    var opt = element.options[i]; <br />    if (opt.selected) <br />      value.push(opt.value || opt.text); <br />    } <br />  } <br />  return [element.name, value]; <br />} <br />} <br />/** <br />* Form.Element.getValue 会经常用到，所以做了一个快捷引用 <br />* 取得某个表单控件的值，可以简化调用为 $F(&quot;username&quot;)，真是方便啊 <br />*/ <br />var $F = Form.Element.getValue; <br />/** <br />* Abstract.TimedObserver 也没有用 Class.create() 来创建，和Ajax.Base 意图应该一样 <br />* Abstract.TimedObserver 顾名思义，是套用Observer设计模式来跟踪指定表单元素， <br />* 当表单元素的值发生变化的时候，就执行回调函数 <br />* <br />* 我想　Observer 与注册onchange事件相似，不同点在于 onchange 事件是在元素失去焦点的时候才激发。 <br />* 同样的与 onpropertychange 事件也相似，不过它只关注表单元素的值的变化，而且提供timeout的控制。 <br />* <br />* 除此之外，Observer 的好处大概就在与更面向对象，另外可以动态的更换回调函数，这就比注册事件要灵活一些。 <br />* Observer 应该可以胜任动态数据校验，或者多个关联下拉选项列表的连动等等 <br />* <br />*/ <br />Abstract.TimedObserver = function() {} </p><p>/** <br />* 这个设计和 PeriodicalExecuter 一样，bind 方法是实现的核心 <br />*/ <br />Abstract.TimedObserver.prototype = { <br />initialize: function(element, frequency, callback) { <br />  this.frequency = frequency; <br />  this.element   = $(element); <br />  this.callback = callback; <br />  <br />  this.lastValue = this.getValue(); <br />  this.registerCallback(); <br />}, </p><p><br />registerCallback: function() { <br />  setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); <br />}, </p><p>onTimerEvent: function() { <br />  var value = this.getValue(); <br />  if (this.lastValue != value) { <br />    this.callback(this.element, value); <br />    this.lastValue = value; <br />  } <br />} <br />} </p><p>/** <br />* Form.Element.Observer 监视指定表单域的值是否变化 <br />*/ <br />Form.Element.Observer = Class.create(); <br />Form.Element.Observer.prototype = (new Abstract.TimedObserver()).extend({ <br />getValue: function() { <br />  return Form.Element.getValue(this.element); <br />} <br />}); </p><p>/** <br />* Form.Element.Observer 监视指定表单所有控件的值是否有变化 <br />*/ <br />Form.Observer = Class.create(); <br />Form.Observer.prototype = (new Abstract.TimedObserver()).extend({ <br />getValue: function() { <br />  return Form.serialize(this.element); <br />} <br />}); </p><p>/*--------------------------------------------------------------------------*/ </p><p>/** <br />* EventObserver 相比上面的 TimedObserver，是更具主动性的一种监测 <br />* 它直接为表单控件(根据 type 的不同) 注册相应的事件处理, 只要发现某个控件值发生改变，就执行回调函数 <br />*/ <br />Abstract.EventObserver = function() {} <br />Abstract.EventObserver.prototype = { <br />initialize: function(element, callback) { <br />  this.element = $(element); <br />  this.callback = callback; <br />  <br />  this.lastValue = this.getValue(); <br />  if (this.element.tagName.toLowerCase() == 'form') <br />    this.registerFormCallbacks(); <br />  else <br />    this.registerCallback(this.element); <br />}, </p><p>onElementEvent: function() { <br />  var value = this.getValue(); <br />  if (this.lastValue != value) { <br />    this.callback(this.element, value); <br />    this.lastValue = value; <br />  } <br />}, </p><p>registerFormCallbacks: function() { <br />  var elements = Form.getElements(this.element); <br />  for (var i = 0; i &lt; elements.length; i++) <br />    this.registerCallback(elements[i]); <br />}, </p><p>registerCallback: function(element) { <br />  if (element.type) { <br />    switch (element.type.toLowerCase()) { <br />    /** <br />    * checkbox 和 radio 类型的控件注册 onclick 事件处理 <br />    */ <br />    case 'checkbox': <br />    case 'radio': <br />      element.target = this; <br />      element.prev_onclick = element.onclick || Prototype.emptyFunction; <br />    /** <br />      * 相信这里有改进的空间，应该使用其后的 Event对象提供的注册管理功能来统一注册 <br />      */ <br />      element.onclick = function() { <br />        this.prev_onclick(); <br />        this.target.onElementEvent(); <br />      } <br />      break; </p><p>    /** <br />    * 其他类型的控件注册 onchange 事件处理 <br />    */ <br />    case 'password': <br />    case 'text': <br />    case 'textarea': <br />    case 'select-one': <br />    case 'select-multiple': <br />      element.target = this; <br />      element.prev_onchange = element.onchange || Prototype.emptyFunction; <br />      element.onchange = function() { <br />        this.prev_onchange(); <br />        this.target.onElementEvent(); <br />      } <br />      break; <br />    } <br />  }   <br />} <br />} </p><p>/** <br />* 监视指定表单控件 <br />*/ <br />Form.Element.EventObserver = Class.create(); <br />Form.Element.EventObserver.prototype = (new Abstract.EventObserver()).extend({ <br />getValue: function() { <br />  return Form.Element.getValue(this.element); <br />} <br />}); </p><p>/** <br />* 监视指定表单所有控件 <br />*/ <br />Form.EventObserver = Class.create(); <br />Form.EventObserver.prototype = (new Abstract.EventObserver()).extend({ <br />getValue: function() { <br />  return Form.serialize(this.element); <br />} <br />}); </p><p>/** <br />* 封装事件处理的静态工具对象 <br />*/ <br />if (!window.Event) { <br />var Event = new Object(); <br />} </p><p>Object.extend(Event, { <br />KEY_BACKSPACE: 8, <br />KEY_TAB:     9, <br />KEY_RETURN:   13, <br />KEY_ESC:     27, <br />KEY_LEFT:   37, <br />KEY_UP:     38, <br />KEY_RIGHT:   39, <br />KEY_DOWN:   40, <br />KEY_DELETE:   46, </p><p>element: function(event) { <br />  return event.target || event.srcElement; <br />}, </p><p>isLeftClick: function(event) { <br />  return (((event.which) &amp;&amp; (event.which == 1)) || <br />        ((event.button) &amp;&amp; (event.button == 1))); <br />}, <br />/** <br />  * click事件时鼠标以页面为基准的x坐标值, 考虑到了滚动条导致的位移差 <br />  */ <br />pointerX: function(event) { <br />  return event.pageX || (event.clientX + <br />    (document.documentElement.scrollLeft || document.body.scrollLeft)); <br />}, <br />/** <br />  * click事件时鼠标以页面为基准的y坐标值, 考虑到了滚动条导致的位移差 <br />  */ <br />pointerY: function(event) { <br />  return event.pageY || (event.clientY + <br />    (document.documentElement.scrollTop || document.body.scrollTop)); <br />}, <br />/** <br />  * 停止冒泡(参见 <a onclick="function anonymous()
{
return newin('http://www.quirksmode.org/js/events_order.html')
}" href="http://www.quirksmode.org/js/events_order.html">http://www.quirksmode.org/js/events_order.html</a>) 和阻止浏览器执行与事件相关的默认动作 <br />  * 比如 <br />  * &lt;a href=&quot;<a onclick="function anonymous()
{
return newin('http://www.google.com')
}" href="http://www.google.com/">http://www.google.com</a>&quot; onclick=&quot;Event.stop(event);&quot;&gt;google&lt;/a&gt; <br />  * 那么点击该连接，页面并不会执行转向 <br />  */ <br />stop: function(event) { <br />  if (event.preventDefault) { <br />    event.preventDefault(); <br />    event.stopPropagation(); <br />  } else { <br />    event.returnValue = false; <br />  } <br />}, <br />// find the first node with the given tagName, starting from the <br />// node the event was triggered on; traverses the DOM upwards <br />/** <br />  * 找到事件元素的父级元素中，最接近事件元素且等同于指定标签名的父元素。 <br />  * 如果到达顶级元素(HTML)，那么就返回顶级元素 <br />  */ <br />findElement: function(event, tagName) { <br />  var element = Event.element(event); <br />  while (element.parentNode &amp;&amp; (!element.tagName || <br />    (element.tagName.toUpperCase() != tagName.toUpperCase()))) <br />    element = element.parentNode; <br />  return element; <br />}, <br />/** <br />  * 其后的代码封装了事件的注册和反注册，避免ie的内存泄露的bug <br />  * 参见 <a onclick="function anonymous()
{
return newin('http://javascript.weblogsinc.com/entry/1234000267034921/')
}" href="http://javascript.weblogsinc.com/entry/1234000267034921/">http://javascript.weblogsinc.com/entry/1234000267034921/</a> <br />  */ <br />observers: false, <br />  /** <br />  * this.observers 的数据格式是一个二维数组，二维的数组分别四个元素分别是 <br />  * [注册事件对象，事件名，事件处理函数，事件处理模式布尔值] <br />  */ <br />_observeAndCache: function(element, name, observer, useCapture) { <br />  if (!this.observers) this.observers = []; <br />  if (element.addEventListener) { <br />    this.observers.push([element, name, observer, useCapture]); <br />    element.addEventListener(name, observer, useCapture); <br />  } else if (element.attachEvent) { <br />    this.observers.push([element, name, observer, useCapture]); <br />    element.attachEvent('on' + name, observer); <br />  } <br />}, </p><p>unloadCache: function() { <br />  if (!Event.observers) return; <br />  for (var i = 0; i &lt; Event.observers.length; i++) { <br />  /** <br />    * 这里与 Ajax.Request 对象设置 request header 的代码异曲同工 <br />    */ <br />    Event.stopObserving.apply(this, Event.observers[i]); <br />    Event.observers[i][0] = null; <br />  } <br />  Event.observers = false; <br />}, <br />/** <br />  * 注册对象的事件处理，并记录到cache中 <br />  */ <br />observe: function(element, name, observer, useCapture) { <br />  var element = $(element); <br />  useCapture = useCapture || false; <br />  <br />  if (name == 'keypress' &amp;&amp; <br />    ((navigator.appVersion.indexOf('AppleWebKit') &gt; 0) <br />    || element.attachEvent)) <br />    name = 'keydown'; <br />  <br />  this._observeAndCache(element, name, observer, useCapture); <br />}, </p><p>/** <br />  * 取消对象已注册的事件处理 <br />  */ <br />stopObserving: function(element, name, observer, useCapture) { <br />  var element = $(element); <br />  useCapture = useCapture || false; <br />  <br />  if (name == 'keypress' &amp;&amp; <br />    ((navigator.appVersion.indexOf('AppleWebKit') &gt; 0) <br />    || element.detachEvent)) <br />    name = 'keydown'; <br />  <br />  if (element.removeEventListener) { <br />    element.removeEventListener(name, observer, useCapture); <br />  } else if (element.detachEvent) { <br />    element.detachEvent('on' + name, observer); <br />  } <br />} <br />}); <br />/* prevent memory leaks in IE */ <br />/** <br />* 页面onload 的时候取消所有事件注册，避免ie内存泄漏的bug <br />*/ <br />Event.observe(window, 'unload', Event.unloadCache, false); <br />/** <br />* Position 对象也是常用的工具类，提供了获取元素在页面上位置的函数，Drag&amp;Drop的效果一定常会用到 <br />* 具体的应用参考 script.aculo.us 基于prototype 的实现，尤其是dragdrop.js。 <br />*/ <br />var Position = { </p><p>// set to true if needed, warning: firefox performance problems <br />// NOT neeeded for page scrolling, only if draggable contained in <br />// scrollable elements <br />includeScrollOffsets: false, </p><p>// must be called before calling withinIncludingScrolloffset, every time the <br />// page is scrolled <br />prepare: function() { <br />  this.deltaX = window.pageXOffset <br />          || document.documentElement.scrollLeft <br />          || document.body.scrollLeft <br />          || 0; <br />  this.deltaY = window.pageYOffset </p><p>          || document.documentElement.scrollTop <br />          || document.body.scrollTop <br />          || 0; <br />}, </p><p>/** <br />  * 当对象所处的页面有滚动条是，计算位移 <br />  */ <br />realOffset: function(element) { <br />  var valueT = 0, valueL = 0; <br />  do { <br />    valueT += element.scrollTop || 0; <br />    valueL += element.scrollLeft || 0; <br />    element = element.parentNode; <br />  } while (element); <br />  return [valueL, valueT]; <br />}, </p><p>/** <br />  * 计算出对象在页面上的位置 <br />  */ <br />cumulativeOffset: function(element) { <br />  var valueT = 0, valueL = 0; <br />  do { <br />    valueT += element.offsetTop || 0; <br />    valueL += element.offsetLeft || 0; <br />    element = element.offsetParent; <br />  } while (element); <br />  return [valueL, valueT]; <br />}, </p><p>// caches x/y coordinate pair to use with overlap <br />/** <br />  * 判断一个坐标是否在指定元素的空间范围中 <br />  * 比如你想判断鼠标点击点的坐标是否在某个层或窗口 <br />  */ <br />within: function(element, x, y) { <br />  if (this.includeScrollOffsets) <br />    return this.withinIncludingScrolloffsets(element, x, y); <br />  this.xcomp = x; <br />  this.ycomp = y; <br />  this.offset = this.cumulativeOffset(element); <br />  return (y &gt;= this.offset[1] &amp;&amp; <br />        y &lt; this.offset[1] + element.offsetHeight &amp;&amp; <br />        x &gt;= this.offset[0] &amp;&amp; <br />        x &lt; this.offset[0] + element.offsetWidth); <br />}, <br />withinIncludingScrolloffsets: function(element, x, y) { <br />  var offsetcache = this.realOffset(element); <br />  this.xcomp = x + offsetcache[0] - this.deltaX; <br />  this.ycomp = y + offsetcache[1] - this.deltaY; <br />  this.offset = this.cumulativeOffset(element); <br />  return (this.ycomp &gt;= this.offset[1] &amp;&amp; <br />        this.ycomp &lt; this.offset[1] + element.offsetHeight &amp;&amp; <br />        this.xcomp &gt;= this.offset[0] &amp;&amp; <br />        this.xcomp &lt; this.offset[0] + element.offsetWidth); <br />}, <br />// within must be called directly before <br />/** <br />  * 调用该方法时，确保首先调用了within方法 <br />  * 如果x,y坐标位于element的空间范围中，那么返回一个小于1的标示位置的值，比如0.5标示该坐标位于element空间的中线上 <br />  */ <br />overlap: function(mode, element) { <br />  if (!mode) return 0; <br />  if (mode == 'vertical') <br />    return ((this.offset[1] + element.offsetHeight) - this.ycomp) / <br />    element.offsetHeight; <br />  if (mode == 'horizontal') <br />    return ((this.offset[0] + element.offsetWidth) - this.xcomp) / <br />    element.offsetWidth; <br />}, <br />/** <br />  * 复制源对象的空间数据到目的对象。 <br />  * 常用的地方：拖缀一个层到新地方时，常常动态构造和该层同样大小的虚层。 <br />  */ <br />clone: function(source, target) { <br />  source = $(source); <br />  target = $(target); <br />  target.style.position = 'absolute'; <br />  var offsets = this.cumulativeOffset(source); <br />  target.style.top   = offsets[1] + 'px'; <br />  target.style.left   = offsets[0] + 'px'; <br />  target.style.width = source.offsetWidth + 'px'; <br />  target.style.height = source.offsetHeight + 'px'; <br />} <br />}</p><p /><p><a href="http://3rgb.com/b/?act=viewthread&threadid=407">http://3rgb.com/b/?act=viewthread&amp;threadid=407</a></p><!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="http://raymondchen625.blogbus.com/logs/1761387.html">prototype.js开发笔记</a> 2005-12-28</div><div><a href="http://raymondchen625.blogbus.com/logs/1958751.html">Javascript的IE和Firefox兼容性汇编</a> 2006-02-21</div><div><a href="http://raymondchen625.blogbus.com/logs/1809689.html">常用网页播放器代码</a> 2006-01-11</div><div><a href="http://raymondchen625.blogbus.com/logs/1752442.html">相册的自动播放效果SlideShow (ZT)</a> 2005-12-23</div><div><a href="http://raymondchen625.blogbus.com/logs/1752421.html">DOM 中 StyleSheet的处理</a> 2005-12-20</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fraymondchen625.blogbus.com%2Flogs%2F1927089.html&title=prototype+1.3+%E6%BA%90%E7%A0%81%E8%A7%A3%E8%AF%BB">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://raymondchen625.blogbus.com/logs/1927089.html</link>
   <author></author>
   <pubDate>Tue, 14 Feb 2006 22:36:19 +0800</pubDate>
  </item>
  <item>
   <title>转贴 创业者融资指南――与风险投资者会面之前应该做哪些准备工作</title>
   <description><![CDATA[<p class="MsoNormal"><b><span style="COLOR: black; FONT-FAMILY: 宋体">创业者融资指南――与风险投资者会面之前应该做哪些准备工作？</span></b><b><span lang="EN-US" style="COLOR: black"><p /></span></b></p><p class="MsoNormal"><span lang="EN-US" style="COLOR: black"><p> </p></span></p><p class="MsoNormal"><span style="COLOR: black; FONT-FAMILY: 宋体">有些创业者并不熟悉如何向机构投资者进行融资来发展事业。创业者一般用个人投资来组建公司，并且支持随后的公司发展计划，这些个人投资可以来自公司创立者自己、朋友、家庭等，有时也来自银行或者政府。</span><span lang="EN-US" style="COLOR: black"><p /></span></p><p class="MsoNormal"><span lang="EN-US" style="COLOR: black"><p> </p></span></p><p class="MsoNormal"><span style="COLOR: black; FONT-FAMILY: 宋体">风险投资现在是一种越来越重要的融资方式，特别是在高科技公司这样的高成长性行业。但不幸的是，许多创业者并不知道如何与机构投资者打交道，如何向他们介绍一个投资机会，也不知道从他们那里除了获得融资之外还能获得些什么。</span><span lang="EN-US" style="COLOR: black"><p /></span></p><p class="MsoNormal"><span lang="EN-US" style="COLOR: black"><p> </p></span></p><p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: 宋体">在开始一项投资的分析和谈判阶段，创业者通常对风险投资者的情况会有很多问题。为了解释清楚风险投资者如何进行投资的工作方式，本文整理出一个清单和相应的说明，这个清单不一定完整，但是对创业者会有一些指导，以帮助他们如何准备投资建议书，以及如何与风险投资者打交道。</span><span lang="EN-US" style="COLOR: black"><p /></span></p><p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US" style="COLOR: black"><p> </p></span></p><p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="COLOR: black; FONT-FAMILY: 宋体">在投资过程中的关键问题和步骤包括如下：</span><span lang="EN-US" style="COLOR: black"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 18pt"><span lang="EN-US" style="COLOR: black">• </span><span style="COLOR: black; FONT-FAMILY: 宋体">向风险投资进行融资的目的是为了发展一个商业机会。</span><span lang="EN-US" style="COLOR: black"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span lang="EN-US" style="COLOR: black">• </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">站在投资者的角度考虑问题，并对自己的投资建议书提出批评。</span><span lang="EN-US" style="COLOR: black"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span lang="EN-US" style="COLOR: black">• </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">了解你的听众。</span><span lang="EN-US" style="COLOR: black"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span lang="EN-US" style="COLOR: black">• </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">准备好一份商业计划书（</span><span lang="EN-US" style="COLOR: black">business plan</span><span style="COLOR: black; FONT-FAMILY: 宋体">），以及一份执行摘要（</span><span lang="EN-US" style="COLOR: black">executive summary</span><span style="COLOR: black; FONT-FAMILY: 宋体">）。</span><span lang="EN-US" style="COLOR: black"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span lang="EN-US" style="COLOR: black">• </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">对自己的商业机会进行估值，并准备好谈判底线。</span><span lang="EN-US" style="COLOR: black"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span lang="EN-US" style="COLOR: black">• </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">融资有成本的，要花费时间和金钱。</span><span lang="EN-US" style="COLOR: black"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span lang="EN-US" style="COLOR: black">• </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">可能会需要有经验的法律帮助。</span><span lang="EN-US" style="COLOR: black"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span lang="EN-US" style="COLOR: black">• </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">准备好做路演。</span><span lang="EN-US" style="COLOR: black"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span lang="EN-US" style="COLOR: black">• </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">准备好开始谈判，并且对你的公司进行外部审查。</span><span lang="EN-US" style="COLOR: black"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span lang="EN-US" style="COLOR: black">• </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">准备好公司治理结构的改变。</span><span lang="EN-US" style="COLOR: black"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span lang="EN-US" style="COLOR: black">• </span></span><span style="COLOR: black; FONT-FAMILY: 宋体">理解创业者、首席执行官（</span><span lang="EN-US" style="COLOR: black">CEO</span><span style="COLOR: black; FONT-FAMILY: 宋体">），以及股东之间的区别。</span><span lang="EN-US" style="COLOR: black"><p /></span></p><span lang="EN-US" style="FONT-SIZE: 10.5pt; COLOR: black; FONT-FAMILY: 'Times New Roman'"><br style="PAGE-BREAK-BEFORE: auto" clear="all" /></span><div class="Section2"><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><b><span style="COLOR: black; FONT-FAMILY: 宋体">向风险投资进行融资的目的是为了发展一个商业机会。</span></b><b><span lang="EN-US" style="COLOR: black"><p /></span></b></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">为一个新项目融资有很多方法。银行对于紧急的资金需求来说，有时是个很好的选择，但是融资成本比较昂贵。如果创业者能够提供实际的担保，比如固定资产或者应收款项，银行才有可能借钱给创业者。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">而风险投资者不同。他们获得来自第三方的资本，承受适当的风险，投资给高成长性的商业机会和公司，当这些公司在市场上获得成功时有公司规模可能扩张好多倍，从而当资本能够流动性的时候就能使初始投资获得非常吸引人的回报。风险投资通常不需要担保，但是需要签订保护性条款，并且需要创业者分一部分公司管理权给风险投资。不要期望获得免费的资本，融资通常都需要付出成本。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><b><span style="COLOR: black; FONT-FAMILY: 宋体">站在投资者的角度考虑问题，并对自己的投资建议书提出批评。</span></b><b><span lang="EN-US"><p /></span></b></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">投资者选择投资建议书时脑子里通常至少有</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体">个关键要素：一个强大的管理团队、一个在快速发展的市场和行业中的好公司、以及一个清晰的未来愿景。所以创业者在敲开潜在投资者的门之前最好做好准备能够证明这</span><span lang="EN-US">3</span><span style="FONT-FAMILY: 宋体">个关键要素。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">风险投资者可能还会问几个关键问题。是否同时在找其它投资者？团队对于公司发展的愿景是否意见一致？是否能够建立需要的销售渠道？是否有明确的计划来达到目标？需要从投资者这里获得什么？需要钱用于什么？这个过程需要创业者在向机构投资者提出融资申请之前做好准备工作。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">有很多工具能够创业者帮助回答这些问题，因此最好在与投资者交谈之前就试着回答好这些问题。还有很多信息和参考书指导创业者如何写出有条理的商业计划书，在互联网上做个简单的搜索就可以搜出这些信息。记住，投资者每天都分析无数计划书，他们手上会有很多类似的项目。为什么要选你的，而不是别人更有条理的计划书？</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><b><span style="COLOR: black; FONT-FAMILY: 宋体">了解你的听众。</span></b><b><span lang="EN-US" style="COLOR: black"><p /></span></b></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">一个好的商业机会总能找到投资者。有很多基金和个人都愿意投资于好的商业机会。但也并不是所有投资者都愿意这样做。根据对交易和风险方面的不同偏好，投资者有很多不同类型，包括：朋友和家庭的资金、天使投资者、政府种子资金、早期风险投资、后期风险投资、私有股权投资等。</span><span lang="EN-US"><p /></span></p></div><span lang="EN-US" style="FONT-SIZE: 10.5pt; FONT-FAMILY: 'Times New Roman'"><br style="PAGE-BREAK-BEFORE: auto" clear="all" /></span><p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">另外根据风险投资公司与其资产组合中公司打交道的方式，投资者也可被不同类型。有些风险投资公司在这方面非常主动，会介入其资产组合中公司的日常决策，帮助建立关系网、销售、以及财务。另一些风险投资公司与其资产组合中公司联系很少，对公司运营尽量少进行干涉。一般来说，后一种倾向于投资于较多的项目，而较少关注每个项目公司的运营问题。对于创业者来说，预先了解潜在投资者的情况，以及是哪种类型，是很重要的。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><b><span style="COLOR: black; FONT-FAMILY: 宋体">准备好一份商业计划书（</span></b><b><span lang="EN-US" style="COLOR: black">business plan</span></b><b><span style="COLOR: black; FONT-FAMILY: 宋体">），以及一份执行摘要（</span></b><b><span lang="EN-US" style="COLOR: black">executive summary</span></b><b><span style="COLOR: black; FONT-FAMILY: 宋体">）。</span></b><b><span lang="EN-US"><p /></span></b></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-FAMILY: 宋体">融资的第一步应该是与潜在投资者建立联系。现在你已经瞄准了一个行业，并且知道了谁会对你的建议书感兴趣，下面要做的就是联系他们。你手上必须要有一份关于你公司的执行摘要，主要内容应该包括：这个商业机会的要点（你做什么）、市场细分（你的客户是谁）、以及为什么你会成功（你相对竞争对手有什么优势）。执行摘要通常是个四页（或者更少）的文件，不包括任何保密内容，可以通过电子邮件发给潜在投资者。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">执行摘要应该同时也是商业计划书的前两页，用来给读者一个指引。一份商业计划书应该描述公司的整个发展策略，包括：管理团队、市场策略、产品定义、竞争环境、投资计划、现金需求等。商业计划书不需要</span><span lang="EN-US">100</span><span style="FONT-FAMILY: 宋体">页那么长，但是必须内容丰富，并且明确说明你的竞争优势。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">在商业计划书里面，你需要解释清楚这个商业机会是什么，你将给市场提供什么样的解决方案，你将如何执行你的策略，以及你为什么会成功。图片、数据、表格可以帮助你表达你的观点。</span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">商业计划书里面最重要的部分是财务预测。投资者在寻找成长性机会，但是不代表会盲目的夸大对成长性的期望。风险投资者通常会做出资金的预测，与你的数字进行对比，因此你需要做好资金的预测，并且准备好用事实回答他们将提出的问题。</span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">保证你的商业计划书具有严密性的一种很好的方式是：按照自底向上的方式来组织计划书（从你手头的资源推导出潜在的收入），并且按照自顶向下的方式来怀疑计划书（从整个目标市场规模推导出你的市场份额）。这种方式将使计划书有一种逻辑上的严密性。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">商业计划书的预测将会在谈判中被使用，并且将会投资之后的业务目标指导。创业者，作为公司管理者，将会按照这个预算下达到的业绩来被评价。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span style="FONT-FAMILY: 宋体">请注意在收到任何机密信息之前，可以签一个保密协议。你当然不希望你的商业计划书被提供给第三方，用这种法律保证的方式，你可以保护自己的权利。。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">关于商业计划书，做好准备回答投资者下面这些问题：</span><span lang="EN-US"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span style="FONT-FAMILY: 宋体">•</span></span><span>&nbsp;</span><span style="FONT-FAMILY: 宋体">管理团队：介绍你的团队，背景和工作经验。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span style="FONT-FAMILY: 宋体">•</span></span><span>&nbsp;</span><span style="FONT-FAMILY: 宋体">预测：结合现在的情况，对未来五年的预测。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span style="FONT-FAMILY: 宋体">•</span></span><span>&nbsp;</span><span style="FONT-FAMILY: 宋体">客户：谁使你现在的客户？</span><span lang="EN-US"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span style="FONT-FAMILY: 宋体">•</span></span><span>&nbsp;</span><span style="FONT-FAMILY: 宋体">商业模式：你如何销售，以什么价格？你的目标市场细分？</span><span lang="EN-US"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span style="FONT-FAMILY: 宋体">•</span></span><span>&nbsp;</span><span style="FONT-FAMILY: 宋体">主要竞争对手：谁是你的目标行业细分中的主要玩家？</span><span lang="EN-US"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span style="FONT-FAMILY: 宋体">•</span></span><span>&nbsp;</span><span style="FONT-FAMILY: 宋体">策略和战术：你为什么会成功。你的差异化是什么？</span><span lang="EN-US"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span style="FONT-FAMILY: 宋体">•</span></span><span>&nbsp;</span><span style="FONT-FAMILY: 宋体">收益的使用：解释如何使用融来的资金。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal" style="MARGIN-LEFT: 36pt; TEXT-INDENT: -18pt"><span dir="ltr"><span style="FONT-FAMILY: 宋体">•</span></span><span>&nbsp;</span><span style="FONT-FAMILY: 宋体">投资者：谁是本轮投资的其它投资者？</span><span lang="EN-US"><p /></span></p><p class="MsoNormal" style="TEXT-ALIGN: left" align="left"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><b><span style="COLOR: black; FONT-FAMILY: 宋体">对自己的商业机会进行估值，并准备好谈判底线。</span></b><b><span lang="EN-US"><p /></span></b></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">投资者用来对潜在交易进行估值的技术没有多少变化。你应该自己预先做好准备，给你的公司估值。这将会避免因为你和投资者的期望不同而导致的没完没了的谈判。投资者通常使用比较法来对你的公司进行估值，也就是说用类似公司的价值作为参考，（这里的类似公司是相同细分市场里面的公司，如果是公开上市公司就用其市值，或者用被并购时的交易价值）。另一种常用的估值方法是现金流预测折扣法，每个投资者都有自己的风险因子，用来作为在这一方法中折扣。你可以自己先用这些方法来估算一下。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">通常有这样一个误解：开始的时候先做一个较高的估值来申请融资，之后才能够达成一个适中的协议价值。这样做通常会使你失去很多潜在投资者，因为他们会认为这么高的一个估值，与自己的期望值相差太大，很难达成协议。所以比较好的方法是：开一个你认为是合适的价格，然后坚持住这个价格。一般来说这个价格已经会高于投资者的心理价位了，因为创业者与财务投资者所感受到的风险往往是不同的。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><b><span style="COLOR: black; FONT-FAMILY: 宋体">融资有成本的，要花费时间和金钱。</span></b><b><span lang="EN-US"><p /></span></b></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">与互联网泡沫高点时期相比，现在的投资者会花费更多的时间在项目考察过程上，包括：与客户交谈、做背景调查、访问目标公司、寻找外部推荐人等。成功的项目通常一轮考察要持续大约</span><span lang="EN-US">4</span><span style="FONT-FAMILY: 宋体">个月，有时甚至要长达</span><span lang="EN-US">1</span><span style="FONT-FAMILY: 宋体">年。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">许多投资者由投资委员会来做出批准决定，在交易的不同阶段，只有获得批准通过，交易团队才能继续进行下一步。下面是两个这种批准的例子：第一个批准通常发生在初始调查结束之后，但是在投资者拿出投资条款表（</span><span lang="EN-US">term sheet</span><span style="FONT-FAMILY: 宋体">）之前；第二个批准通常发生在谈判之后，以及各方开始交流最终合同文件草案之前。在这两次对批准进行审核的委员会会议上（或者甚至进行调查之中），交易都可能被终止。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">创业公司应该明白他们的所有花费都是为了融到资金，因此所有法律、审计、以及其它费用都将由创业公司支付。交易费用通常也由创业公司来支付。然而，如果交易没有成功，或者服务提供者是由风险投资者雇用的，费用也可能会由投资者来支付。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><b><span style="COLOR: black; FONT-FAMILY: 宋体">可能会需要有经验的法律帮助。</span></b><b><span lang="EN-US"><p /></span></b></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">律师将会帮助创业者与潜在投资者的法律代表打交道。你和律师的交流和合作将帮助你更好的融到自己。当雇用你的律师时，需要确保他有很强的公司法律专业知识，最好是以前有过风险投资交易方面的经验。同时，律师的专业建议对于保护你的知识产权也很重要。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">尽管投资者往往强调法律帮助的重要性，创业者应该自己和投资者谈好商业方面的问题（估值、股权分配、资产流动性偏好等）。这种谈判产生的文件被称为投资条款表（</span><span lang="EN-US">term sheet</span><span style="FONT-FAMILY: 宋体">）。这个投资条款表背后的思想就是用简单的语言描述交易各方的权利和义务。一旦你与投资者达成了协议，律师的任务就是确认投资条款表中的所有条款完整表达了你们的协议，然后以法律文件的形式写出来。投资条款表是写这些文件草案的指导书，因此是比较简化的，实际的交易文件将包括各方的权利和义务方面的更多细节。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><b><span style="COLOR: black; FONT-FAMILY: 宋体">准备好做路演。</span></b><b><span lang="EN-US"><p /></span></b></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">接下来就是实际的融资了，准备好与投资者的见面。你必须就你的商业计划书做演讲，参加会议、并且介绍将和你一起执行这个项目的团队。记住，团队中的某个人将作为随后融资过程的领导者，通常公司创立者中的一个将作为首席执行官（</span><span lang="EN-US">CEO</span><span style="FONT-FAMILY: 宋体">），或者首席财务官（</span><span lang="EN-US">CFO</span><span style="FONT-FAMILY: 宋体">），花费很多时间来做融资工作（通常是其</span><span lang="EN-US">100</span><span style="FONT-FAMILY: 宋体">％的时间）。你也许必须重复几十次讲你们的故事，但是这些时间花的值得。保持乐观和主动，如果你不知道什么时候，不要回避，就说你不知道好了，也不要过度的推销你的投资建议书。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><b><span style="COLOR: black; FONT-FAMILY: 宋体">准备好开始谈判，并且对你的公司进行外部审查。</span></b><b><span lang="EN-US"><p /></span></b></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">拿着你的商业计划书，并且经过一些讨论之后，投资者会拿出一个投资条款表出来，上面写了些他们需要的条款，从而可以继续下面的投资过程。一般来说对于这个投资条款表，可以有一段时间让双方来谈判，继续对投资条款表进行更新，从而达成一致，最后形成一个最终版本。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">一旦每个人都同意了这些条款，尽职审查的过程就开始了。如果你已经准备好了相关的合同文件，并且更新了所有法律和税务文件，这个过程可以被大大加快。许多公司准备好一份尽职审查书，以及所有需要的文件的一份拷贝，当投资者需要时就提供给他，这样做可以表现出一种专业性的沟通方式。有时需要雇用独立的审计师和律师，通常由创业公司支付其费用，用来评估所有的公司潜在负债（人事、税务等方面）。这些分析中如果由对公司不利的结果，一般通过谈判的方式进行沟通，尽可能减少对现有投资者产生负债的影响，</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><b><span style="COLOR: black; FONT-FAMILY: 宋体">准备好公司治理结构的改变。</span></b><b><span lang="EN-US"><p /></span></b></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">如果这是你第一次把你的公司所有权分配给别人，你需要意识到：即使你仍然持有大多数股份，投资者通常也将会对公司治理结构和透明度做重大的调整。现在公司创立者是在为股东工作了，而不仅仅是为自己。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">投资者会试图构造一个平衡的董事会，他们能够充分的发表观点和获取信息。他们会要求得到董事会席位，并建立某种特权，从而保证能做关键的决策，或者对某些事务具有否决权。这些做法的理念就是为了当公司策略发生改变，但其没有董事会多数席位时，能够保护其投资权益，记住是你在过去做了一个商业计划书，而所有投资者都批准了你的计划，并决定给了你投资，现在你该保证他们的权益了。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><b><span style="COLOR: black; FONT-FAMILY: 宋体">理解创业者、首席执行官（</span></b><b><span lang="EN-US" style="COLOR: black">CEO</span></b><b><span style="COLOR: black; FONT-FAMILY: 宋体">），以及股东之间的区别。</span></b><b><span lang="EN-US"><p /></span></b></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">创业者和</span><span lang="EN-US">CEO</span><span style="FONT-FAMILY: 宋体">之间有重要区别，在刚开始的时候确实比较难注意到，但随着时间的流逝，公司决策将不再会基于简单的创业冲动，而变得越来越结构化和流程化，并且需要各个股东的批准。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">通常好的创业者做决策很快，有点倾向于把决策权集中在自己手里。这在商业发展的早期当然是至关重要的，但是当公司成熟之后，这将会危害一个健全公司的发展。发展到一定阶段，就需要一个</span><span lang="EN-US">CEO</span><span style="FONT-FAMILY: 宋体">，由董事授权来管理公司，同时向董事会汇报工作。有时在公司发展过程中，公司创立者也可能离开管理岗位，这些情况下，创立者仍然会通过董事会来介入决策制定，而把日常管理交给专业管理团队。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">同样很重要的是需要理解：虽然股东对于公司发展有着同样的利益，但是他们应该较少接入公司日常运营。他们必须给执行管理团队充分的自由度和授权来执行商业计划。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><p class="MsoNormal"><span style="FONT-FAMILY: 宋体">最后一点：融资仅仅是一个开始。目标是发展和开拓一个商业机会，从而能够为股东创造出很高的价值。资金仅仅是成功方程式的一个部分，关键的是：建立一个有着同样愿景理念的团队，然后向着这个愿景开展有效的工作。这一点不光对雇员是这样要求，寻找谁来投资的时候也需要这样要求，要确保投资者有相同的愿景和价值观，并且能够真正帮助发展你的公司。</span><span lang="EN-US"><p /></span></p><p class="MsoNormal"><span lang="EN-US"><p> </p></span></p><!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="/logs/2338403.html">如何用APT维护Red Hat Enterprise Linux (RHEL) zt</a> 2006-04-24</div><div><a href="/logs/2232779.html">用 Subversion 构建版本控制环境</a> 2006-04-09</div><div><a href="/logs/1809689.html">常用网页播放器代码</a> 2006-01-11</div><div><a href="/logs/1780976.html">awstats简易安装文档</a> 2006-01-02</div><div><a href="/logs/1761387.html">prototype.js开发笔记</a> 2005-12-28</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fraymondchen625.blogbus.com%2Flogs%2F1860245.html&title=%E8%BD%AC%E8%B4%B4+%E5%88%9B%E4%B8%9A%E8%80%85%E8%9E%8D%E8%B5%84%E6%8C%87%E5%8D%97%E2%80%95%E2%80%95%E4%B8%8E%E9%A3%8E%E9%99%A9%E6%8A%95%E8%B5%84%E8%80%85%E4%BC%9A%E9%9D%A2%E4%B9%8B%E5%89%8D%E5%BA%94%E8%AF%A5%E5%81%9A%E5%93%AA%E4%BA%9B%E5%87%86%E5%A4%87%E5%B7%A5%E4%BD%9C">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://raymondchen625.blogbus.com/logs/1860245.html</link>
   <author></author>
   <pubDate>Wed, 25 Jan 2006 15:44:43 +0800</pubDate>
  </item>
  <item>
   <title>基于Java的Blog系统</title>
   <description><![CDATA[<p>收集了一些基于Java的Blog系统，有时间再研究。</p><p /><p>Roller：<a href="http://www.rollerweblogger.org/page/project">http://www.rollerweblogger.org/page/project</a></p><p>国外运用想当广泛的一套BLOG系统。</p><p><br />DLOG4J： <a href="http://dlog4j.sourceforge.net/">http://dlog4j.sourceforge.net/</a></p><p>国人开发的，已经申报SourceForge项目 中文官方站： <a href="http://www.javayou.com">http://www.javayou.com</a></p><p><br />TM： <a href="http://www.terac.com">http://www.terac.com</a><br /><br /><a href="http://blog.xintiantang.com/andy/">http://blog.xintiantang.com/andy/</a></p><!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="http://raymondchen625.blogbus.com/logs/1771924.html">OSCache使用指南</a> 2005-12-31</div><div><a href="http://raymondchen625.blogbus.com/logs/1768310.html">Lucene与Tag图</a> 2005-12-30</div><div><a href="http://raymondchen625.blogbus.com/logs/1751443.html">Java的SAX使用的简单Sample</a> 2005-12-26</div><div><a href="/logs/2967427.html">Debian的版本</a> 2006-08-03</div><div><a href="/logs/1927089.html">prototype 1.3 源码解读</a> 2006-02-14</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fraymondchen625.blogbus.com%2Flogs%2F1826833.html&title=%E5%9F%BA%E4%BA%8EJava%E7%9A%84Blog%E7%B3%BB%E7%BB%9F">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://raymondchen625.blogbus.com/logs/1826833.html</link>
   <author></author>
   <pubDate>Mon, 16 Jan 2006 11:32:16 +0800</pubDate>
  </item>
  <item>
   <title>常用网页播放器代码</title>
   <description><![CDATA[<p><table class="fixedTable blogpost" cellspacing="0" width="100%" border="0"><tbody><tr><td class="ellipse"><span class="bvTitle" id="subjcns!1pDKmZKazZO_0FZ63E4NFDDA!2250"><strong>常用网页播放器代码</strong></span></td></tr><tr><td class="bvh8"><strong></strong></td></tr><tr><td id="msgcns!1pDKmZKazZO_0FZ63E4NFDDA!2250"><div><font color="#ff0000"><strong>我们在网页上看到的播放器无外乎WMP/RealOne/Macromedia Flash Player,其他的无非是面板不同，或者添加了其他控件，对于计算机上安装的一些播放器也都是编码和解码器的整合，其最核心的编码和解码技术是相同的。例如：网络上最流行的windows media流(asf,wma,wmv格式...)，Real流(rm,rmvb...)，还有MPEG系列编码格式(MP4/MP3格式...)</strong></font></div><div>Windows Media Video 是微软推出的一种流媒体格式，它是在“同门”的ASF（Advanced Stream Format）格式升级延伸来得.在同等视频质量下，WMV格式的体积非常小，因此很适合在网上播放和传输。Windows Media Player9兼容所有格式的WMV,官方编码器是Windows Media Encoder ，但是如果你想转制 高质量的wmv文件，那您一定要有超大的内存来处理数据... <br />无意中发现CASTPOST的播放器可以自己定义大小，对于WMV格式的在线播放可以说已经足够快了,然后就费了好大劲把一些精彩的短片和一些经典的MTV转化WMV格式放了上来,尽管现在不能下载了，但是只要不是连接人数过多，播放起来还是很流畅的^_^ </div><div><strong><font color="#ff0000"></font></strong> </div><div><strong><font color="#ff0000">WMP</font></strong>加入了ActiveX解码器控件，不仅可以放曲子，还能放Flash和其它视频文件 </div><div>&lt;object align=middle classid=&quot;CLSID:22d6f312-b0f6-11d0-94ab-0080c74c7e95&quot; class=OBJECT id=MediaPlayer width=196 height=196&gt;<br />     &lt;param name=ShowStatusBar value=0&gt;<br />       &lt;param name=Filename value=&quot;http://202.116.*.*/video/story/chinese/hynh/b.wmv&quot;&gt;<br />        &lt;embed type=application/x-oleobject codebase=&quot;http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=5,1,52,701&quot; &gt;<br />     &lt;/embed&gt;</div><div>&lt;/object&gt;</div><div> 想用WMP连续播放请参照ASX元文件使用讲解：<a href="http://spaces.msn.com/members/weiaipiaobo/Blog/cns!1pDKmZKazZO_0FZ63E4NFDDA!785.entry" target="_blank"><font color="#049baa">使用ASX播放列表吧</font></a><br /></div><div><p>上面的这个播放器是老式的那种，***版本！新式播放器是在MediaPlayer9.0以后出现的，也就是说只有装了9.0或9.0以上的播放器才能正常使用的。</p><p /><hr /><p /><p>下面是新式播放器代码，相对以前的来说要简单很多：<br />&lt;object id=&quot;player&quot; height=&quot;64&quot; width=&quot;260&quot; classid=&quot;CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6&quot;&gt;<br />    &lt;param NAME=&quot;AutoStart&quot; VALUE=&quot;-1&quot;&gt;<br />    &lt;!--是否自动播放--&gt;<br />    &lt;param NAME=&quot;Balance&quot; VALUE=&quot;0&quot;&gt;<br />    &lt;!--调整左右声道平衡,同上面旧播放器代码--&gt;<br />    &lt;param name=&quot;enabled&quot; value=&quot;-1&quot;&gt;<br />    &lt;!--播放器是否可人为控制--&gt;<br />    &lt;param NAME=&quot;EnableContextMenu&quot; VALUE=&quot;-1&quot;&gt;<br />    &lt;!--是否启用上下文菜单--&gt;<br />    &lt;param NAME=&quot;url&quot; value=&quot;/blog/1.wma&quot;&gt;<br />    &lt;!--播放的文件地址--&gt;<br />    &lt;param NAME=&quot;PlayCount&quot; VALUE=&quot;1&quot;&gt;<br />    &lt;!--播放次数控制,为整数--&gt;<br />    &lt;param name=&quot;rate&quot; value=&quot;1&quot;&gt;<br />    &lt;!--播放速率控制,1为正常,允许小数,1.0-2.0--&gt;<br />    &lt;param name=&quot;currentPosition&quot; value=&quot;0&quot;&gt;<br />    &lt;!--控件设置:当前位置--&gt;<br />    &lt;param name=&quot;currentMarker&quot; value=&quot;0&quot;&gt;<br />    &lt;!--控件设置:当前标记--&gt;<br />    &lt;param name=&quot;defaultFrame&quot; value=&quot;&quot;&gt;<br />    &lt;!--显示默认框架--&gt;<br />    &lt;param name=&quot;invokeURLs&quot; value=&quot;0&quot;&gt;<br />    &lt;!--脚本命令设置:是否调用URL--&gt;<br />    &lt;param name=&quot;baseURL&quot; value=&quot;&quot;&gt;<br />    &lt;!--脚本命令设置:被调用的URL--&gt;<br />    &lt;param name=&quot;stretchToFit&quot; value=&quot;0&quot;&gt;<br />    &lt;!--是否按比例伸展--&gt;<br />    &lt;param name=&quot;volume&quot; value=&quot;50&quot;&gt;<br />    &lt;!--默认声音大小0%-100%,50则为50%--&gt;<br />    &lt;param name=&quot;mute&quot; value=&quot;0&quot;&gt;<br />    &lt;!--是否静音--&gt;<br />    &lt;param name=&quot;uiMode&quot; value=&quot;mini&quot;&gt;<br />    &lt;!--播放器显示模式:Full显示全部;mini最简化;None不显示播放控制,只显示视频窗口;invisible全部不显示--&gt;<br />    &lt;param name=&quot;windowlessVideo&quot; value=&quot;0&quot;&gt;<br />    &lt;!--如果是0可以允许全屏,否则只能在窗口中查看--&gt;<br />    &lt;param name=&quot;fullScreen&quot; value=&quot;0&quot;&gt;<br />    &lt;!--开始播放是否自动全屏--&gt;<br />    &lt;param name=&quot;enableErrorDialogs&quot; value=&quot;-1&quot;&gt;<br />    &lt;!--是否启用错误提示报告--&gt;<br />    &lt;param name=&quot;SAMIStyle&quot; value&gt;<br />    &lt;!--SAMI样式--&gt;<br />    &lt;param name=&quot;SAMILang&quot; value&gt;<br />    &lt;!--SAMI语言--&gt;<br />    &lt;param name=&quot;SAMIFilename&quot; value&gt;<br />    &lt;!--字幕ID--&gt;<br />&lt;/object&gt;</p><p /><hr /><p /></div><div><strong><font color="#ff0000">RealOne</font></strong>播放器代码：</div><div>&lt;object id=&quot;vid&quot; classid=&quot;clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA&quot; width=427 height=300&gt;<br />&lt;param name=&quot;_ExtentX&quot; value=&quot;11298&quot;&gt;<br />&lt;param name=&quot;_ExtentY&quot; value=&quot;7938&quot;&gt;<br />&lt;param name=&quot;AUTOSTART&quot; value=&quot;-1&quot;&gt;<br />&lt;param name=&quot;SHUFFLE&quot; value=&quot;0&quot;&gt;<br />&lt;param name=&quot;PREFETCH&quot; value=&quot;0&quot;&gt;<br />&lt;param name=&quot;NOLABELS&quot; value=&quot;-1&quot;&gt;<br />&lt;param name=&quot;SRC&quot; value=&quot;rtsp://211.89.225.1/encoder/cnr3&quot;;&gt;<br />&lt;param name=&quot;CONTROLS&quot; value=&quot;Imagewindow&quot;&gt;<br />&lt;param name=&quot;CONSOLE&quot; value=&quot;clip1&quot;&gt;<br />&lt;param name=&quot;LOOP&quot; value=&quot;0&quot;&gt;<br />&lt;param name=&quot;NUMLOOP&quot; value=&quot;0&quot;&gt;<br />&lt;param name=&quot;CENTER&quot; value=&quot;0&quot;&gt;<br />&lt;param name=&quot;MAINTAINASPECT&quot; value=&quot;0&quot;&gt;<br />&lt;param name=&quot;BACKGROUNDCOLOR&quot; value=&quot;#000000&quot;&gt;<br />&lt;/object&gt; &lt;object id=&quot;vid2&quot; classid=&quot;clsid:CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA&quot; width=427 height=30&gt;<br />&lt;param name=&quot;_ExtentX&quot; value=&quot;11298&quot;&gt;<br />&lt;param name=&quot;_ExtentY&quot; value=&quot;794&quot;&gt;<br />&lt;param name=&quot;AUTOSTART&quot; value=&quot;-1&quot;&gt;<br />&lt;param name=&quot;SHUFFLE&quot; value=&quot;0&quot;&gt;<br />&lt;param name=&quot;PREFETCH&quot; value=&quot;0&quot;&gt;<br />&lt;param name=&quot;NOLABELS&quot; value=&quot;-1&quot;&gt;<br />&lt;param name=&quot;SRC&quot; value=&quot;rtsp://211.89.225.1/encoder/cnr3&quot;;&gt;<br />&lt;param name=&quot;CONTROLS&quot; value=&quot;ControlPanel&quot;&gt;<br />&lt;param name=&quot;CONSOLE&quot; value=&quot;clip1&quot;&gt;<br />&lt;param name=&quot;LOOP&quot; value=&quot;0&quot;&gt;<br />&lt;param name=&quot;NUMLOOP&quot; value=&quot;0&quot;&gt;<br />&lt;param name=&quot;CENTER&quot; value=&quot;0&quot;&gt;<br />&lt;param name=&quot;MAINTAINASPECT&quot; value=&quot;0&quot;&gt;<br />&lt;param name=&quot;BACKGROUNDCOLOR&quot; value=&quot;#000000&quot;&gt;<br />&lt;/object&gt;</div><div>  <hr /></div><div>看着很多很复杂的样子，其实就是多了些播放器参数，可以不要...</div><div><p>Real Player 网页播放器 参数含义</p><p>参数：autostart 属性：True或是False 作用：指定是否自动播放指定的源文件 <br />参数：backgroundcolor 属性：任何用符号“#”开头的16进制数值或是任何预定义的颜色作用：指定图像窗口的背景颜色 <br />参数：center 属性：True或是False 作用：指定片断使用初始编码大小播放，并且在图像窗口的中央。 <br />参数：classid 属性：&quot;clsid：CFCDAA03-8BE4-1lcf-B84B0020AFBBCCFA:** 作用：用于指定ActiveX控件的唯一的字符串标示，可以认出嵌入的RealPalyer播放器。 <br />参数：console 属性：任何字符串作用：可以将各种不同的RealPlayer控制聚集在网页上，这样它们可以交互使用或是保持独立，而且互相不影响 <br />参数：controls 属性：ImageWindow，All，ControlPanel，PlavButton，PlayOnlyButton， PauseButton,StopButton，FFCtrl，RWCtrl，MuteCtrl，MuteVolume，VolumeSlider，PositionSlider,TACCtrl，HomeCtrl，InfoVolumePanel，InfoPanel，StatusBar，StatusField，PositionField 作用：可以让你指定那些控制是可见的。 <br />参数：height 属性：任何整数值作用：指定RealPlayer元素的高度，单位:像素 <br />参数：id 属性：任何字符串作用：为标签中的RealPlayer元素指定名字。 <br />参数：imagestatus 属性：True或是False 作用：指定是否在图像窗口中显示状态信息，默认值是true <br />参数：loop 属性：True或是False 作用：可以让你指定片断是否无限循环 <br />参数：maintainaspect 属性：True或是False 作用：默认RealPlayer拉伸所有的片断来充满整个图像窗口。 <br />参数：name 属性：任何字符串作用：为标签中的RealPlayer元素指定名字(在标签中使用id) <br />参数：nojava 属性：True或是False 作用：避免启动Java虚拟机 <br />参数：nolabels 属性：True或是False 作用：可以禁止显示标题或是版权信息(realplayer5.0以上时，它是垃圾...) <br />参数：nologo 属性：True或是False 作用：避免RealPlayer启动时在图像窗口中显示 <br />参数：numloop 属性：任何整数值作用：让你能够指定文件片循环的次数，不需要参数loop <br />参数：prefetch 属性：True或是False 作用：指定在播放前，RealPlayer是否可以获得流描述信息，默认值是False <br />参数：region 属性：任何字符串作用：同SMIL一起使用。允许你指定使用HTML代替SMIL <br />参数：scriptcallbacks 属性：用逗号分割的列表作用：指定浏览器的回调监控（好高级的东东！） <br />参数：shuffle 属性：True或是False 作用：同多文件片的ram文件或是SMIL文件一起使用。可以让RealPlayer随机播放列表中的文件 <br />参数：src 属性：任何合法的相对或是完整的URL 作用：指定播放的文件或是源文件的地址 <br />参数：type 属性：字符串作用：为嵌入插件指定MIME类型 <br />参数：width 属性：任何整数值作用：指定RealPlayer元素的宽度</p><p>RealPlayer的一些函数、方法和过程</p><p>这是 Real Player ActiveX Control Library (Version 1.0) 的所有函数与方法，有兴趣可以研究一下。</p><p>function GetSource: WideString;<br />procedure SetSource(const lpszNewValue: WideString);<br />function GetConsole: WideString;<br />procedure SetConsole(const lpszNewValue: WideString);<br />function GetControls: WideString;<br />procedure SetControls(const lpszNewValue: WideString);<br />function GetNoLabels: WordBool;<br />procedure SetNoLabels(bNewValue: WordBool);<br />function GetAutoStart: WordBool;<br />procedure SetAutoStart(bNewValue: WordBool);<br />function GetAutoGotoURL: WordBool;<br />procedure SetAutoGotoURL(bNewValue: WordBool);<br />function GetVolume: Smallint;<br />procedure SetVolume(nVol: Smallint);<br />function GetMute: WordBool;<br />procedure SetMute(bMute: WordBool);<br />function GetLoop: WordBool;<br />procedure SetLoop(bVal: WordBool);<br />function GetImageStatus: WordBool;<br />procedure SetImageStatus(bEnable: WordBool);<br />function GetPacketsTotal: Integer;<br />function GetPacketsReceived: Integer;<br />function GetPacketsOutOfOrder: Integer;<br />function GetPacketsMissing: Integer;<br />function GetPacketsEarly: Integer;<br />function GetPacketsLate: Integer;<br />function GetBandwidthAverage: Integer;<br />function GetBandwidthCurrent: Integer;<br />procedure DoPlayPause;<br />procedure DoStop;<br />procedure DoNextItem;<br />procedure DoPrevItem;<br />function CanPlayPause: WordBool;<br />function CanStop: WordBool;<br />function HasNextItem: WordBool;<br />function HasPrevItem: WordBool;<br />function HasNextEntry: WordBool;<br />function HasPrevEntry: WordBool;<br />procedure DoNextEntry;<br />procedure DoPrevEntry;<br />procedure AboutBox;<br />procedure EditPreferences;<br />procedure HideShowStatistics;<br />function IsStatisticsVisible: WordBool;<br />procedure DoGotoURL(const url: WideString; const target: WideString);<br />procedure DoPlay;<br />procedure DoPause;<br />function GetPosition: Integer;<br />function GetPlayState: Integer;<br />function GetLength: Integer;<br />function GetTitle: WideString;<br />function GetAuthor: WideString;<br />function GetCopyright: WideString;<br />function GetClipWidth: Integer;<br />function GetClipHeight: Integer;<br />function CanPlay: WordBool;<br />function CanPause: WordBool;<br />procedure SetPosition(lPosition: Integer);<br />function GetNumLoop: Integer;<br />procedure SetNumLoop(lVal: Integer);<br />function GetCenter: WordBool;<br />procedure SetCenter(bVal: WordBool);<br />function GetNoLogo: WordBool;<br />procedure SetNoLogo(bVal: WordBool);<br />function GetMaintainAspect: WordBool;<br />procedure SetMaintainAspect(bVal: WordBool);<br />function GetBackgroundColor: WideString;<br />procedure SetBackgroundColor(const pVal: WideString);<br />function GetStereoState: WordBool;<br />function GetLiveState: WordBool;<br />function GetShowStatistics: WordBool;<br />procedure SetShowStatistics(bVal: WordBool);<br />function GetShowPreferences: WordBool;<br />procedure SetShowPreferences(bVal: WordBool);<br />function GetShowAbout: WordBool;<br />procedure SetShowAbout(bVal: WordBool);<br />function GetOriginalSize: WordBool;<br />procedure SetOriginalSize;<br />function GetDoubleSize: WordBool;<br />procedure SetDoubleSize;<br />function GetFullScreen: WordBool;<br />procedure SetFullScreen;<br />function GetEnableContextMenu: WordBool;<br />procedure SetEnableContextMenu(bVal: WordBool);<br />function GetEnableOriginalSize: WordBool;<br />procedure SetEnableOriginalSize(bVal: WordBool);<br />function GetEnableDoubleSize: WordBool;<br />procedure SetEnableDoubleSize(bVal: WordBool);<br />function GetEnableFullScreen: WordBool;<br />procedure SetEnableFullScreen(bVal: WordBool);<br />function GetEnableMessageBox: WordBool;<br />procedure SetEnableMessageBox(bVal: WordBool);<br />procedure SetTitle(const pVal: WideString);<br />procedure SetAuthor(const pVal: WideString);<br />procedure SetCopyright(const pVal: WideString);<br />function GetWantKeyboardEvents: WordBool;<br />procedure SetWantKeyboardEvents(bWantsEvents: WordBool);<br />function GetWantMouseEvents: WordBool;<br />procedure SetWantMouseEvents(bWantsEvents: WordBool);<br />function GetNumEntries: Smallint;<br />function GetCurrentEntry: Smallint;<br />function GetEntryTitle(uEntryIndex: Smallint): WideString;<br />function GetEntryAuthor(uEntryIndex: Smallint): WideString;<br />function GetEntryCopyright(uEntryIndex: Smallint): WideString;<br />function GetEntryAbstract(uEntryIndex: Smallint): WideString;<br />procedure SetCanSeek(bCanSeek: WordBool);<br />function GetCanSeek: WordBool;<br />function GetBufferingTimeElapsed: Integer;<br />function GetBufferingTimeRemaining: Integer;<br />function GetConnectionBandwidth: Integer;<br />function GetPreferedLanguageString: WideString;<br />function GetPreferedLanguageID: Integer;<br />function GetUserCountryID: Integer;<br />function GetNumSources: Smallint;<br />function GetSourceTransport(nSourceNum: Smallint): WideString;<br />function GetWantErrors: WordBool;<br />procedure SetWantErrors(bVal: WordBool);<br />function GetShuffle: WordBool;<br />procedure SetShuffle(bVal: WordBool);<br />function GetVersionInfo: WideString;<br />function GetLastMessage: WideString;<br />function GetLastErrorSeverity: Integer;<br />function GetLastErrorRMACode: Integer;<br />function GetLastErrorUserCode: Integer;<br />function GetLastErrorUserString: WideString;<br />function GetLastErrorMoreInfoURL: WideString;<br />procedure SetPreFetch(bVal: WordBool);<br />function GetPreFetch: WordBool;<br />procedure SetRegion(const pVal: WideString);<br />function GetRegion: WideString;<br />function GetIsPlus: WordBool;<br />function GetConsoleEvents: WordBool;<br />procedure SetConsoleEvents(bVal: WordBool);<br />function GetDRMInfo(const pVal: WideString): WideString;<br />property ControlInterface: IRealAudio read GetControlInterface;<br />property DefaultInterface: IRealAudio read GetControlInterface;</p><p /><hr /><p /><p>网页中WMP视频控制之使用指南</p><p>□播放方法和属性<br />    除播放、暂停、停止外，媒体播放器还可用下面的属性：<br />    扫描(Scanning)——与录像机的快进快倒功能类似；<br />    搜索(Seeking)——直接移到剪辑中标记的特定上演时间；</p><p>□播放<br />    媒体播放器提供了两种技术来指定要播放的媒体名称(剪辑)，你可以设置 FileName 属性，或调用 Open 方法。 如果 AutoStart 属性的值是 true 的话，当 FileName 属性被设置成该电影剪辑的 URL 后，该电影剪辑将开始播放；否则电影剪辑不会开始播放， 除非你调用 Play 方法。 Open 方法开始播放是异步的，它不象 Play 方法要等到其他的进程结束后才开始播放。<br />    媒体播放器提供了下面的类似录像机的属性和方法来控制流媒体的播放：<br />    Play、Stop、Pause 方法，来开始、停止、暂停流媒体。<br />    PlayCount 属性，设置文件播放的次数。<br />    AutoRewind 属性，确定当停止播放时是否返回到电影剪辑的开始部分。</p><p>□音频控制<br />    媒体播放器提供了下面的属性来管理音频：<br />    Balance 属性，确定左右音箱的声音平衡；<br />    Volume 属性，用来加大或降低音量；<br />    Mute 属性，用来关闭或打开声音；<br />    ※你可以将 ShowAudioControls 属性设为 true 来在控制栏添加处理声音的控件。</p><p>□扫描<br />    媒体播放器提供了下面的属性用以扫描：<br />    FastForward 方法，快进；<br />    FastReverse 方法，快倒；<br />    Rate属性，改变播放速率；<br />    ※要想使电影剪辑能被扫描，必须将 CanScan 和 AllowScan 属性设为 true。</p><p>□搜索<br />    用于搜索的属性有：<br />    MarkerCount 属性，指剪辑中标记的总数量；<br />    CurrentMaker、GetMarkerName、GetMarkerTime 方法，用于返回标记信息；<br />    MarkerHit 事件，当遇到标记时触发；<br />    CurrentPosition 属性，当前位置(用秒度量)，可用来将播放头移到剪辑中指定的点；<br />    PositionChange 事件，当设置 CurrentPosition 属性时触发；<br />    ※要想搜索到任意的时间，必须将 CanSeek 属性设为 true，要想搜索到标记点，必须将 CanSeekToMarkers 属性设为 true。</p><p>□媒体播放器的外观界面<br />    在网页中，你可以通过相关属性来控制媒体播放器的哪些部分出现，哪些部分不出现。<br />媒体播放器包括如下元素：<br />    Video Display Panel：视频显示面板；<br />    Video Border：视频边框；<br />    Closed Captioning Display Panel；字幕显示面板；<br />    Track Bar；搜索栏；<br />    Control Bar with Audio and Position Controls：带有声音和位置控制的控制栏；<br />    Go To Bar：转到栏；<br />    Display Panel：显示面板；<br />    Status Bar：状态栏；<br />    下面的属性用来决定显示哪一个元素：<br />    ShowControls 属性：是否显示控制栏（包括播放控件及可选的声音和位置控件）；<br />    ShowAudioControls 属性：是否在控制栏显示声音控件（静音按钮和音量滑块）；<br />    ShowPositionControls 属性：是否在控制栏显示位置控件（包括向后跳进、快退、快进、向前跳进、预览播放列表中的每个剪辑）；<br />    ShowTracker 属性：是否显示搜索栏；<br />    ShowDisplay 属性：是否显示显示面板（用来提供节目与剪辑的信息）；<br />    ShowCaptioning 属性：是否显示字幕显示面板；<br />    ShowGotoBar 属性：是否显示转到栏；<br />    ShowStatusBar 属性：是否显示状态栏；</p><p>□播放列表<br />    媒体播放器提供下面的方法来访问播放列表中的剪辑：<br />    Next 方法，跳到节目（播放列表）中的下一个剪辑；<br />    Previous 方法，跳回到节目中的上一个剪辑；<br />    媒体播放器的一个特性是能够预览节目中的每一个剪辑，使用如下属性：<br />    PreviewMode 属性，决定媒体播放器当前是否处于预览模式；<br />    CanPreview 属性，决定媒体播放器能否处于预览模式；<br />    在windows 媒体元文件中，可以为每一个剪辑指定预览时间——PREVIEWDURATION,如果没有指定，那么默认的预览时间是10秒钟。<br />    你也可以用Windows 媒体元文件来添加 watermarks 与 banners，元文件也支持插入广告时的无间隙流切换。</p><p>□节目信息<br />    使用 GetMediaInfoString 方法可以返回相关剪辑或节目的如下信息：<br />    文件名：File name<br />    标题：Title<br />    描述：Description<br />    作者：Author<br />    版权：Copyright<br />    级别：Rating<br />    URLs：logo icon、watermark、banner的地址<br />    剪辑信息可以放在媒体文件中，也可以放在Windows 媒体元文件中，或者两者都放。如果在元文件中指定了剪辑信息，那么用 GetMediaInfoString 方法返回的就是元文件中的信息，而不会返回剪辑中包含的信息。<br />    在元文件中，附加信息可以放置在每一个剪辑或节目的 PARAM标签中。你可以为每个剪辑添加任意多个 PARAM 标签，用来存储自定义的信息或链接到相关站点。在 PARAM 标签中的信息可以通过 GetMediaParameter 方法来访问。<br />    下面的属性返回有关大小和时间的信息：<br />    ImageSourceHeight、ImageSourceWidth：返回图像窗口的显示尺寸；<br />    Duration 属性，返回剪辑的长度(秒)， 要检测这个属性是否包含有效的数值，请检查IsDurationValid 属性。(对于广播的视频，其长度是不可预知的)。</p><p>□字幕<br />    你可以用 .smi 文件来为你的节目添加字幕。媒体播放器支持下面的属性来处理字幕：<br />    SAMIFileName 属性，指定 .smi 文件的名字；<br />    SAMILang 属性，指定字幕的语言(如果没有指定则使用第一种语言)；<br />    SAMIStyle 属性，指定字幕的文字大小和样式；<br />    ShowCaptioning 属性，决定是否显示字幕显示面板；</p><p>□脚本命令<br />    伴随音频、视频流，你可以在流媒体文件中加入脚本命令。脚本命令是多媒体流中与特定时间同步的多对Unicode串。第一个串标识待发命令的类型，第二个串指定要执行的命令。<br />当流播放到与脚本相关的时间时，控件会向网页发送一个 ScriptCommand事件，然后由事件处理进程来响应这个事件。脚本命令字符串会作为脚本命令事件的参数传递给事件处理器。<br />    媒体播放器会自动处理下面类型的内嵌脚本命令：<br />    1)URL型命令：当媒体播放器控件收到一个URL型的命令时，指定的URL会被装载到用户的默认浏览器。如果媒体播放器嵌在一个分帧的HTML文件中，URL页可以装载到由脚本命令指定的帧内。如果脚本命令没有指定一个帧，将由 DefaultFrame 属性决定将 URL 页装入哪一帧。<br />    你可以通过设置 InvokeURLs 属性来决定是否自动处理 URL 型的脚本命令。如果这个属性的值为 false ，媒体播放器控件将忽视 URL型命令。但是脚本命令事件仍会触发，这就允许你有选择地处理 URL 型命令。<br />    URL 型命令指定的是 URL 的相对地址。基地址是由 BaseURL属性指定的。媒体播放器控件传送的脚本命令事件的命令参数是链接好的地址。<br />    2)FILENAME型命令：当媒体播放器控件收到一个FILENAME型的命令时，它将 FileName属性设置为脚本命令提供的文件，之后媒体播放器会打开这个文件开始播放。 媒体播放器控件总是自动处理 FILENAME 型命令，不象 URL 型命令，它们不能被禁止。<br />    3)TEXT型命令：当媒体播放器控件收到一个 TEXT型的命令时，它会将命令的内容显示在控件的字幕窗口。内容可以是纯文本的，也可以是 HTML。<br />    4)EVENT型命令：当媒体播放器控件收到一个 EVENT型的命令时，它会在媒体元文件中搜索 EVENT 元素的 NAME 属性。如果 NAME 属性与脚本命令中的第二个字符串匹配，媒体播放器控件就执行包含在 EVENT 元素中的条目。<br />    5)OPENEVENT型命令：当媒体播放器控件收到一个 OPENEVENT型的命令时，它会在媒体元文件中检查 EVENT 元素，并打开匹配的标题，但不播放，直到收到来自 EVENT型命令的同名真实事件。</p><p>□捕捉键盘和鼠标事件<br />    EnableContextMenu 与 ClickToPlay 属性为用户提供了在图像窗口进行操作的方法。<br />如果 EnableContextMenu 属性为 true ，在图像窗口右击鼠标可以打开关联菜单，如果将ClickToPlay 属性设为 true ，用户可以单击图像窗口进行播放与暂停的切换。<br />    要接收鼠标移动和单击事件，请将 SendMouseMoveEvents 和 SendMouseClickEvents 属性设为 true 。鼠标事件有：<br />    MouseDown，当用户按下鼠标时产生；<br />    MouseUp，当用户释放鼠标时产生；<br />    MouseMove，当用户移动鼠标时产生；<br />    Click，当用户在媒体播放器上单击鼠标按钮时产生；<br />    DbClick，当用户在媒体播放器上双击鼠标按钮时产生；<br />    要接收键盘事件，请将 SendKeyboardEvents 属性设为 true 。键盘事件有：<br />    KeyDown，当用户按下一个键时产生；<br />    KeyUp，当用户释放一个键时产生；<br />    KeyPress，当用户按下并释放一个键时产生；</p><p>□监测流状态与网络链接<br />    流状态属性包括：<br />    PlayState：播放状态；<br />    OpenState：打开状态；<br />    Bandwidth：带宽；<br />    支持的事件有：<br />    OpenStateChange：打开状态改变(仅当SendOpenStateChangeEvents属性为true时触发)<br />    PlayStateChange：播放状态改变(仅当SendPlayStateChangeEvents属性为true时触发)<br />    EndOfStream：流结束时触发；<br />    NewStream：打开新流时触发；<br />    网络接收属性包括：<br />    ReceptionQuality：接收质量；<br />    ReceivedPackets：已经收到的包；<br />    LostPackets：丢失的包；<br />    监测缓冲的属性有：<br />    BufferingTime：缓冲时间；<br />    BufferingCount：缓冲次数；<br />    BufferingProgress：缓冲进程；<br />    Buffering：缓冲事件；</p><p>□错误处理<br />    媒体播放器提供了内建的错误处理功能——在对话框或状态栏显示错误信息。 另外，你可以自己添加错误处理程序。如果 SendErrorEvents 属性设置为 true，将不会显示错误框，而是发送错误事件；如果 SendErrorEvents 属性设置为 false，将显示错误框，而是发送错误事件。<br />    媒体播放器支持下面的错误处理事件：<br />    Error 事件，指有危险性错误发生；<br />    Warning 事件，指发生了非危险性的错误；<br />    当你的应用程序接收到一个错误事件，你可以检测下面的属性来确定具体的错误信息：<br />    HasError：检测目前的媒体播放器是否有错误；<br />    ErrorCode：提供与该类型错误相关的代码值；<br />    ErrorDescription：提供错误的描述信息；<br />    ErrorCorrection：指定媒体播放器对该类型的错误进行校正；</p><p>□播放CD<br />    媒体播放器将 CD 看作（在每个音轨的开头具有标记的）单一音频流。 要在网页中使用CD，你需要将 FileName 属性设为 CDAUDIO:，必须带有冒号，如下所示：<br />&lt;HTML&gt;<br />&lt;HEAD&gt;&lt;TITLE&gt;CD Audio Playback Example&lt;/TITLE&gt;&lt;/HEAD&gt;<br />&lt;BODY&gt;<br />&lt;OBJECT ID=&quot;MediaPlayer&quot;<br />    CLASSID=&quot;CLSID:22d6f312-b0f6-11d0-94ab-0080c74c7e95&quot;<br />    WIDTH=&quot;320&quot; <br />    HEIGHT=&quot;508&quot;<br />    STYLE=&quot;position:absolute; left:0px; top:70px;&quot;    &gt;<br />    &lt;PARAM NAME=&quot;FileName&quot; VALUE=&quot;cdaudio:&quot;&gt;<br />    &lt;PARAM NAME=&quot;AutoStart&quot; VALUE=&quot;0&quot;&gt;<br />    &lt;PARAM NAME=&quot;ShowControls&quot; VALUE=&quot;1&quot;&gt;<br />    &lt;PARAM NAME=&quot;ShowStatusBar&quot; VALUE=&quot;1&quot;&gt;<br />    &lt;PARAM NAME=&quot;ShowDisplay&quot; VALUE=&quot;1&quot;&gt;<br />&lt;/OBJECT&gt;<br />&lt;/BODY&gt;<br />&lt;/HTML&gt;</p></div></td></tr></tbody></table></p><!--sp--><div class="relpost"><br/><h3>随机文章：</h3><div><a href="http://raymondchen625.blogbus.com/logs/1958751.html">Javascript的IE和Firefox兼容性汇编</a> 2006-02-21</div><div><a href="http://raymondchen625.blogbus.com/logs/1927089.html">prototype 1.3 源码解读</a> 2006-02-14</div><div><a href="http://raymondchen625.blogbus.com/logs/1761387.html">prototype.js开发笔记</a> 2005-12-28</div><div><a href="http://raymondchen625.blogbus.com/logs/1752442.html">相册的自动播放效果SlideShow (ZT)</a> 2005-12-23</div><div><a href="http://raymondchen625.blogbus.com/logs/1752421.html">DOM 中 StyleSheet的处理</a> 2005-12-20</div></div><div class="addfav"><br />收藏到：<span class= "delicious"><a href="http://delicious.com/save?url=http%3A%2F%2Fraymondchen625.blogbus.com%2Flogs%2F1809689.html&title=%E5%B8%B8%E7%94%A8%E7%BD%91%E9%A1%B5%E6%92%AD%E6%94%BE%E5%99%A8%E4%BB%A3%E7%A0%81">Del.icio.us</a></span></div><br /><br /><div class="sysmsg"><b><a href="http://www.blogbus.com" target="_blank">博客大巴，你的个人传媒早班车</a></b></div><br /><br />]]></description>
   <link>http://raymondchen625.blogbus.com/logs/1809689.html</link>
   <author></author>
   <pubDate>Wed, 11 Jan 2006 12:45:46 +0800</pubDate>
  </item>
 </channel>
</rss>
