<?xml version="1.0" encoding="GBK" ?>
<rss version="2.0" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dcterms="http://purl.org/dc/terms/">
 <channel>
  	  <title><![CDATA[NullPoint Exception]]></title>
	  <link>http://ync.blog.163.com</link>
	  <description><![CDATA[ ]]></description>
	  <language>zh-CN</language>
	  <pubDate>Thu, 3 Jul 2008 21:54:34 +0800</pubDate>
	  <lastBuildDate>Thu, 3 Jul 2008 21:54:34 +0800</lastBuildDate>
	  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
	  <generator><![CDATA[NetEase Space]]></generator>
	  <managingEditor><![CDATA[ync]]></managingEditor>
	  <webMaster><![CDATA[ync]]></webMaster>
		  <ttl>120</ttl>
	  <image>
	  	<title><![CDATA[NullPoint Exception]]></title>
	  	<url>http://ava.blog.163.com/photo/MBdI2kaZBdqvuPVHflJBFw==/1762877779138861175.jpg</url>
	  	<link>http://ync.blog.163.com</link>
	  </image>
  <item>
  	<title><![CDATA[Appetime的PIPS系列手表]]></title>	
    <link>http://ync.blog.163.com/blog/static/31003200731710360228</link>
    <description><![CDATA[<div>
                                    Appetime的PIPS系列手表，以不同的水果为设计灵感，外观特点鲜明、新颖时尚。手表机芯均由精工电子在日本生产、表带采用高档聚酯塑胶材料。<br> <p align="center"><img alt="" src="http://www.uplife.com.cn/picture/temp/c3cbee5a-2139-4d5a-ae51-01a3a480fc50.jpg">&nbsp;</p><p align="center">时尚女生最爱appetime水果腕表</p><p align="center"><img alt="" src="http://www.uplife.com.cn/picture/temp/7573c1e9-9de8-4c98-a43a-91c80b5a2454.jpg">&nbsp;</p><p align="center">时尚女生最爱appetime水果腕表</p>
                        <div   style="margin: 10px 0px; clear: both; line-height: 25px; font-size: 14px;">
                            <p align="center"><img alt="" src="http://www.uplife.com.cn/picture/temp/3695ae70-3173-462b-8402-a066eed99e40.jpg">&nbsp;</p><p align="center">时尚女生最爱appetime水果腕表</p><p align="center"><img alt="" src="http://www.uplife.com.cn/picture/temp/ad624520-b46b-4896-a1e8-7f4c5a948c45.jpg">&nbsp;</p><p align="center">时尚女生最爱appetime水果腕表</p><div   style="margin: 10px 0px; clear: both; line-height: 25px; font-size: 14px;">
                            <p align="center"><img alt="" src="http://www.uplife.com.cn/picture/temp/754ee427-08c0-4220-94a8-7a69f27e4bba.jpg">&nbsp;</p><p align="center">时尚女生最爱appetime水果腕表</p><p align="center"><img alt="" src="http://www.uplife.com.cn/picture/temp/51e10974-8ec1-47e8-bb03-5448f1612749.jpg">&nbsp;</p><p align="center">时尚女生最爱appetime水果腕表</p><div   style="margin: 10px 0px; clear: both; line-height: 25px; font-size: 14px;">
                            <p align="center"><img alt="" src="http://www.uplife.com.cn/picture/temp/be6ba367-45f2-4a57-98c1-f86c70ce5351.jpg">&nbsp;</p><p align="center">时尚女生最爱appetime水果腕表</p><p align="center"><img alt="" src="http://www.uplife.com.cn/picture/temp/05e3a712-1568-427b-9de7-c3ee0857e8d6.jpg">&nbsp;</p><p align="center">时尚女生最爱appetime水果腕表</p>
                        </div>
                        </div>
                        </div><br></div>]]></description>
	    <author><![CDATA[ync]]></author>
	    <comments>http://ync.blog.163.com/blog/static/31003200731710360228</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://ync.blog.163.com/blog/static/31003200731710360228</guid>
    <pubDate>Tue, 17 Apr 2007 10:36:00 +0800</pubDate>
    <dcterms:modified>2007-04-17T10:36:00+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[从java5出来以后,我就没认真做过java了,只知道java5有一些新特性,今天翻出来了解了一下.以下部分是转载]]></title>	
    <link>http://ync.blog.163.com/blog/static/310032007222111318603</link>
    <description><![CDATA[<div>如果你对Java各个版本的代号感兴趣，就像这里的"Tiger"，可以参考如下网址：<a href="http://java.sun.com/j2se/codenames.html">http://java.sun.com/j2se/codenames.html</a>。透露一点：Java下一个版本（6.0）的代号是"Mustang"野马，再下一个版本（7.0）的代号是"Dolphin"海豚。<br><br>1.3.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;概述<br>J2SE(TM)&nbsp;5.0引入了很多激进的语言元素变化，这些变化或多或少减轻了我们开发人员的一些编码负担，其中的大部分也必然会被应用到即将发布的J2EE(TM)&nbsp;5.0中。主要的新特性包括：<br><br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;泛型<br><br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;增强的for循环<br><br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;自动装箱和自动拆箱<br><br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;类型安全的枚举<br><br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;可变长度参数<br><br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;静态引入<br><br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;元数据（注解）<br><br>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;C风格的格式化输出<br><br>&nbsp;<br><br>这当中，泛型、枚举和注解可能会占用较大的篇幅，而其余的因为用法直截了当，抑或相对简单，我就稍作介绍，剩下的留给读者去思考、去探索了。<br><br>1.4.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;泛型<br>泛
型这个题目相当大，大到完全可以就这个话题写一本书。有关Java是否需要泛型和如何实现泛型的讨论也早就在Java社群广为流传。终于，我们在J2SE
(TM)&nbsp;5.0中看到了它。也许目前Java对泛型的支持还算不上足够理想，但这一特性的添加也经足以让我们欣喜一阵了。<br><br>&nbsp;<br><br>在
接下来的介绍中，我们会了解到：Java的泛型虽然跟C++的泛型看上去十分相似，但其实有着相当大的区别，有些细节的东西也相当复杂（至少很多地方会跟
我们的直觉背道而驰）。可以这样说，泛型的引入在很大程度上增加了Java语言的复杂度，对初学者尤其是个挑战。下面我们将一点一点往里挖。<br><br>&nbsp;<br><br>首先我们来看一个简单的使用泛型类的例子：<br><br>ArrayList&lt;Integer&gt;&nbsp;aList&nbsp;=&nbsp;new&nbsp;ArrayList&lt;Integer&gt;();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;aList.add(new&nbsp;Integer(1));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;...<br><br>&nbsp;&nbsp;&nbsp;&nbsp;Integer&nbsp;myInteger&nbsp;=&nbsp;aList.get(0);<br><br>我
们可以看到，在这个简单的例子中，我们在定义aList的时候指明了它是一个直接受Integer类型的ArrayList，当我们调用
aList.get(0)时，我们已经不再需要先显式的将结果转换成Integer，然后再赋值给myInteger了。而这一步在早先的Java版本中
是必须的。也许你在想，在使用Collection时节约一些类型转换就是Java泛型的全部吗？远不止。单就这个例子而言，泛型至少还有一个更大的好
处，那就是使用了泛型的容器类变得更加健壮：早先，Collection接口的get()和Iterator接口的next()方法都只能返回
Object类型的结果，我们可以把这个结果强制转换成任何Object的子类，而不会有任何编译期的错误，但这显然很可能带来严重的运行期错误，因为在
代码中确定从某个Collection中取出的是什么类型的对象完全是调用者自己说了算，而调用者也许并不清楚放进Collection的对象具体是什么
类的；就算知道放进去的对象“应该”是什么类，也不能保证放到Collection的对象就一定是那个类的实例。现在有了泛型，只要我们定义的时候指明该
Collection接受哪种类型的对象，编译器可以帮我们避免类似的问题溜到产品中。我们在实际工作中其实已经看到了太多的
ClassCastException，不是吗？<br><br>&nbsp;<br><br>泛型的使用从这个例子看也是相当易懂。我们在定义ArrayList
时，通过类名后面的&lt;&gt;括号中的值指定这个ArrayList接受的对象类型。在编译的时候，这个ArrayList会被处理成只接受该类或
其子类的对象，于是任何试图将其他类型的对象添加进来的语句都会被编译器拒绝。<br><br>&nbsp;<br><br>那么泛型是怎样定义的呢？看看下面这一段示例代码：（其中用E代替在实际中将会使用的类名，当然你也可以使用别的名称，习惯上在这里使用大写的E，表示Collection的元素。）<br><br>public&nbsp;class&nbsp;TestGenerics&lt;E&gt;&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Collection&lt;E&gt;&nbsp;col;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;doSth(E&nbsp;elem)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;col.add(elem);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;...<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br><br>在
泛型的使用中，有一个很容易有的误解，那就是既然Integer是从Object派生出来的，那么ArrayList&lt;Integer&gt;当然
就是ArrayList&lt;Object&gt;的子类。真的是这样吗？我们仔细想一想就会发现这样做可能会带来的问题：如果我们可以把
ArrayList&lt;Integer&gt;向上转型为ArrayList&lt;Object&gt;，那么在往这个转了型以后的
ArrayList中添加对象的时候，我们岂不是可以添加任何类型的对象（因为Object是所有对象的公共父类）？这显然让我们的
ArrayList&lt;Integer&gt;失去了原本的目的。于是Java编译器禁止我们这样做。那既然是这样，ArrayList&lt;
Integer&gt;以及ArrayList&lt;String&gt;、ArrayList&lt;Double&gt;等等有没有公共的父类呢？
有，那就是ArrayList&lt;?&gt;。?在这里叫做通配符。我们为了缩小通配符所指代的范围，通常也需要这样写：
ArrayList&lt;?&nbsp;extends&nbsp;SomeClass&gt;，这样写的含义是定义这样一个类ArrayList，比方说
SomeClass有SomeExtendedClass1和SomeExtendedClass2这两个子类，那么ArrayList&lt;?
&nbsp;extends&nbsp;SomeClass&gt;就是如下几个类的父类：ArrayList&lt;SomeClass&gt;、
ArrayList&lt;SomeExtendedClass1&gt;和ArrayList&lt;SomeExtendedClass2&gt;。<br><br>&nbsp;<br><br>接
下来我们更进一步：既然ArrayList&lt;?&nbsp;extends&nbsp;SomeClass&gt;是一个通配的公用父类，那么我们可不可以往声明为
ArrayList&lt;?&nbsp;extends&nbsp;SomeClass&gt;的ArrayList实例中添加一个SomeExtendedClass1的
对象呢？答案是不能。甚至你不能添加任何对象。为什么？因为ArrayList&lt;?&nbsp;extends&nbsp;SomeClass&gt;实际上代表了所有
ArrayList&lt;SomeClass&gt;、ArrayList&lt;SomeExtendedClass1&gt;和
ArrayList&lt;SomeExtendedClass2&gt;三种ArrayList，甚至包括未知的接受SomeClass其他子类对象的
ArrayList。我们拿到一个定义为ArrayList&lt;?&nbsp;extends&nbsp;SomeClass&gt;的ArrayList的时候，我们并
不能确定这个ArrayList具体是使用哪个类作为参数定义的，因此编译器也无法让这段代码编译通过。举例来讲，如果我们想往这个ArrayList中
放一个SomeExtendedClass2的对象，我们如何保证它实际上不是其他的如ArrayList&lt;
SomeExtendedClass1&gt;，而就是这个ArrayList&lt;SomeExtendedClass2&gt;呢？（还记得吗？
ArrayList&lt;Integer&gt;并非ArrayList&lt;Object&gt;的子类。）怎么办？我们需要使用泛型方法。泛型方
法的定义类似下面的例子：<br><br>public&nbsp;static&nbsp;&lt;T&nbsp;extends&nbsp;SomeClass&gt;&nbsp;void&nbsp;add&nbsp;(Collection&lt;T&gt;&nbsp;c,&nbsp;T&nbsp;elem)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;c.add(elem);<br><br>}<br><br>其
中T代表了我们这个方法期待的那个最终的具体的类，相关的声明必须放在方法签名中紧靠返回类型的位置之前。在本例中，它可以是SomeClass或者
SomeClass的任何子类，其说明&lt;T&nbsp;entends&nbsp;SomeClass&gt;放在void关键字之前（只能放在这里）。这样我们就可以
让编译器确信当我们试图添加一个元素到泛型的ArrayList实例中时，可以保证类型安全。<br><br>&nbsp;<br><br>Java泛型的最大特点在于它是在语言级别实现的，区别于C#&nbsp;2.0中的CLR级别。这样的做法使得JRE可以不必做大的调整，缺点是无法支持一些运行时的类型甄别。一旦编译，它就被写死了，能提供的动态能力相当弱。<br><br>&nbsp;<br><br>个
人认为泛型是这次J2SE(TM)&nbsp;5.0中引入的最重要的语言元素，给Java语言带来的影响也是最大。举个例子来讲，我们可以看到，几乎所有的
Collections&nbsp;API都被更新成支持泛型的版本。这样做带来的好处是显而易见的，那就是减少代码重复（不需要提供多个版本的某一个类或者接口以
支持不同类的对象）以及增强代码的健壮性（编译期的类型安全检查）。不过如何才能真正利用好这个特性，尤其是如何实现自己的泛型接口或类供他人使用，就并
非那么显而易见了。让我们一起在使用中慢慢积累。<br><br>1.5.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;增强的for循环<br>你是否已经厌倦了每次写for循环时都要写上那些机械的代码，尤其当你需要遍历数组或者Collection，如：（假设在Collection中储存的对象是String类型的）<br><br>public&nbsp;void&nbsp;showAll&nbsp;(Collection&nbsp;c)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(Iterator&nbsp;iter&nbsp;=&nbsp;c.iterator();&nbsp;iter.hasNext();&nbsp;)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println((String)&nbsp;iter.next());<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br><br>&nbsp;<br><br>public&nbsp;void&nbsp;showAll&nbsp;(String[]&nbsp;sa)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;sa.length;&nbsp;i++)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(sa[i]);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br><br>这
样的代码不仅显得臃肿，而且容易出错，我想我们大家在刚开始接触编程时，尤其是C/C++和Java，可能多少都犯过以下类似错误的一种或几种：把for
语句的三个表达式顺序弄错；第二个表达式逻辑判断不正确（漏掉一些、多出一些、甚至死循环）；忘记移动游标；在循环体内不小心改变了游标的位置等等。为什
么不能让编译器帮我们处理这些细节呢？在5.0中，我们可以这样写：<br><br>public&nbsp;void&nbsp;showAll&nbsp;(Collection&nbsp;c)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(Object&nbsp;obj&nbsp;:&nbsp;c)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println((String)&nbsp;obj);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br><br>&nbsp;<br><br>public&nbsp;void&nbsp;showAll&nbsp;(String[]&nbsp;sa)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(String&nbsp;str&nbsp;:&nbsp;sa)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(str);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br><br>这
样的代码显得更加清晰和简洁，不是吗？具体的语法很简单：使用":"分隔开，前面的部分写明从数组或Collection中将要取出的类型，以及使用的临
时变量的名字，后面的部分写上数组或者Collection的引用。加上泛型，我们甚至可以把第一个方法变得更加漂亮：<br><br>public&nbsp;void&nbsp;showAll&nbsp;(Collection&lt;String&gt;&nbsp;cs)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(String&nbsp;str&nbsp;:&nbsp;cs)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(str);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br><br>有
没有发现：当你需要将Collection&lt;String&gt;替换成String[]，你所需要做的仅仅是简单的把参数类型
"Collection&lt;String&gt;"替换成"String[]"，反过来也是一样，你不完全需要改其他的东西。这在J2SE(TM)
&nbsp;5.0之前是无法想象的。<br><br>&nbsp;<br><br>对于这个看上去相当方便的新语言元素，当你需要在循环体中访问游标的时候，会显得很别扭：
比方说，当我们处理一个链表，需要更新其中某一个元素，或者删除某个元素等等。这个时候，你无法在循环体内获得你需要的游标信息，于是需要回退到原先的做
法。不过，有了泛型和增强的for循环，我们在大多数情况下已经不用去操心那些烦人的for循环的表达式和嵌套了。毕竟，我们大部分时间都不会需要去了解
游标的具体位置，我们只需要遍历数组或Collection，对吧？<br><br>1.6.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;自动装箱/自动拆箱<br>所谓装箱，就是
把值类型用它们相对应的引用类型包起来，使它们可以具有对象的特质，如我们可以把int型包装成Integer类的对象，或者把double包装成
Double，等等。所谓拆箱，就是跟装箱的方向相反，将Integer及Double这样的引用类型的对象重新简化为值类型的数据。<br><br>&nbsp;<br><br>在J2SE
(TM)&nbsp;5.0发布之前，我们只能手工的处理装箱和拆箱。也许你会问，为什么需要装箱和拆箱？比方说当我们试图将一个值类型的数据添加到一个
Collection中时，就需要先把它装箱，因为Collection的add()方法只接受对象；而当我们需要在稍后将这条数据取出来，而又希望使用
它对应的值类型进行操作时，我们又需要将它拆箱成值类型的版本。现在，编译器可以帮我们自动地完成这些必要的步骤。下面的代码我提供两个版本的装箱和拆
箱，一个版本使用手工的方式，另一个版本则把这些显而易见的代码交给编译器去完成：<br><br>public&nbsp;static&nbsp;void&nbsp;manualBoxingUnboxing(int&nbsp;i)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;ArrayList&lt;Integer&gt;&nbsp;aList&nbsp;=&nbsp;new&nbsp;ArrayList&lt;Integer&gt;();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;aList.add(0,&nbsp;new&nbsp;Integer(i));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;a&nbsp;=&nbsp;aList.get(0).intValue();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("The&nbsp;value&nbsp;of&nbsp;i&nbsp;is&nbsp;"&nbsp;+&nbsp;a);<br><br>}<br><br>&nbsp;<br><br>public&nbsp;static&nbsp;void&nbsp;autoBoxingUnboxing(int&nbsp;i)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;ArrayList&lt;Integer&gt;&nbsp;aList&nbsp;=&nbsp;new&nbsp;ArrayList&lt;Integer&gt;();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;aList.add(0,&nbsp;i);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;a&nbsp;=&nbsp;aList.get(0);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("The&nbsp;value&nbsp;of&nbsp;i&nbsp;is&nbsp;"&nbsp;+&nbsp;a);<br><br>}<br><br>看
到了吧，在J2SE(TM)&nbsp;5.0中，我们不再需要显式的去将一个值类型的数据转换成相应的对象，从而把它作为对象传给其他方法，也不必手工的将那个代
表一个数值的对象拆箱为相应的值类型数据，只要你提供的信息足够让编译器确信这些装箱/拆箱后的类型在使用时是合法的：比方讲，如果在上面的代码中，如果
我们使用的不是ArrayList&lt;Integer&gt;而是ArrayList或者其他不兼容的版本如ArrayList&lt;
java.util.Date&gt;，会有编译错误。<br><br>&nbsp;<br><br>当然，你需要足够重视的是：一方面，对于值类型和引用类型，在资源的占用上有相当大的区别；另一方面，装箱和拆箱会带来额外的开销。在使用这一方便特性的同时，请不要忘记了背后隐藏的这些也许会影响性能的因素。<br><br>1.7.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;类型安全的枚举<br>在介绍J2SE(TM)&nbsp;5.0中引入的类型安全枚举的用法之前，我想先简单介绍一下这一话题的背景。<br><br>&nbsp;<br><br>我们知道，在C中，我们可以定义枚举类型来使用别名代替一个集合中的不同元素，通常是用于描述那些可以归为一类，而又具备有限数量的类别或者概念，如月份、颜色、扑克牌、太阳系的行星、五大洲、四大洋、季节、学科、四则运算符，等等。它们通常看上去是这个样子：<br><br>typedef&nbsp;enum&nbsp;{SPRING,&nbsp;SUMMER,&nbsp;AUTUMN,&nbsp;WINTER}&nbsp;season;<br><br>实质上，这些别名被处理成int常量，比如0代表SPRING，1代表SUMMER，以此类推。因为这些别名最终就是int，于是你可以对它们进行四则运算，这就造成了语意上的不明确。<br><br>&nbsp;<br><br>Java
一开始并没有考虑引入枚举的概念，也许是出于保持Java语言简洁的考虑，但是使用Java的广大开发者对于枚举的需求并没有因为Java本身没有提供而
消失，于是出现了一些常见的适用于Java的枚举设计模式，如int&nbsp;enum和typesafe&nbsp;enum，还有不少开源的枚举API和不开源的内部实
现。<br><br>&nbsp;<br><br>我大致说一下int&nbsp;enum模式和typesafe&nbsp;enum模式。所谓int&nbsp;enum模式就是模仿C中对enum的实现，如：<br><br>public&nbsp;class&nbsp;Season&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;final&nbsp;int&nbsp;SPRING&nbsp;=&nbsp;0;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;final&nbsp;int&nbsp;SUMMER&nbsp;=&nbsp;1;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;final&nbsp;int&nbsp;AUTUMN&nbsp;=&nbsp;2;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;final&nbsp;int&nbsp;WINTER&nbsp;=&nbsp;3;<br><br>}<br><br>这种模式跟C中的枚举没有太多本质上的区别，C枚举的局限它基本上也有。而typesafe&nbsp;enum模式则要显得健壮得多：<br><br>public&nbsp;class&nbsp;Season&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;final&nbsp;String&nbsp;name;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Season(String&nbsp;name)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.name&nbsp;=&nbsp;name;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;String&nbsp;toString()&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;name;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;final&nbsp;Season&nbsp;SPRING&nbsp;=&nbsp;new&nbsp;Season("spring");<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;final&nbsp;Season&nbsp;SUMMER&nbsp;=&nbsp;new&nbsp;Season("summer");<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;final&nbsp;Season&nbsp;AUTUMN&nbsp;=&nbsp;new&nbsp;Season("autumn");<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;final&nbsp;Season&nbsp;WINTER&nbsp;=&nbsp;new&nbsp;Season("winter");<br><br>}<br><br>后
一种实现首先通过私有的构造方法阻止了对该类的继承和显式实例化，因而我们只可能取得定义好的四种Season类别，并且提供了方便的toString
()方法获取有意义的说明，而且由于这是一个完全意义上的类，所以我们可以很方便的加入自己的方法和逻辑来自定义我们的枚举类。<br><br>&nbsp;<br><br>最终，Java决定拥抱枚举，在J2SE(TM)&nbsp;5.0中，我们看到了这一变化，它所采用的设计思路基本上就是上面提到的typesafe&nbsp;enum模式。它的语法很简单，用一个实际的例子来说，要定义一个枚举，我们可以这样写：<br><br>public&nbsp;enum&nbsp;Language&nbsp;{CHINESE,&nbsp;ENGLISH,&nbsp;FRENCH,&nbsp;HUNGARIAN}<br><br>接
下来我们就可以通过Language.ENGLISH来使用了。呃…这个例子是不是有点太小儿科了，我们来看一个复杂点的例子。使用Java的类型安全枚
举，我们可以为所有枚举元素定义公用的接口，然后具体到每个元素本身，可以针对这些接口实现一些特定的行为。这对于那些可以归为一类，又希望能通过统一的
接口访问的不同操作，将会相当方便。通常，为了实现类似的功能，我们需要自己来维护一套继承关系或者类似的枚举模式。这里借用Java官方网站上的一个例
子：<br><br>public&nbsp;enum&nbsp;Operation&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;PLUS&nbsp;&nbsp;&nbsp;{&nbsp;double&nbsp;eval(double&nbsp;x,&nbsp;double&nbsp;y)&nbsp;{&nbsp;return&nbsp;x&nbsp;+&nbsp;y;&nbsp;}&nbsp;},<br><br>&nbsp;&nbsp;&nbsp;&nbsp;MINUS&nbsp;&nbsp;{&nbsp;double&nbsp;eval(double&nbsp;x,&nbsp;double&nbsp;y)&nbsp;{&nbsp;return&nbsp;x&nbsp;-&nbsp;y;&nbsp;}&nbsp;},<br><br>&nbsp;&nbsp;&nbsp;&nbsp;TIMES&nbsp;&nbsp;{&nbsp;double&nbsp;eval(double&nbsp;x,&nbsp;double&nbsp;y)&nbsp;{&nbsp;return&nbsp;x&nbsp;*&nbsp;y;&nbsp;}&nbsp;},<br><br>&nbsp;&nbsp;&nbsp;&nbsp;DIVIDE&nbsp;{&nbsp;double&nbsp;eval(double&nbsp;x,&nbsp;double&nbsp;y)&nbsp;{&nbsp;return&nbsp;x&nbsp;/&nbsp;y;&nbsp;}&nbsp;};<br><br>&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Do&nbsp;arithmetic&nbsp;op&nbsp;represented&nbsp;by&nbsp;this&nbsp;constant<br><br>&nbsp;&nbsp;&nbsp;&nbsp;abstract&nbsp;double&nbsp;eval(double&nbsp;x,&nbsp;double&nbsp;y);<br><br>}<br><br>在这个枚举中，我们定义了四个元素，分别对应加减乘除四则运算，对于每一种运算，我们都可以调用eval()方法，而具体的方法实现各异。我们可以通过下面的代码来试验上面这个枚举类：<br><br>public&nbsp;static&nbsp;void&nbsp;main(String&nbsp;args[])&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;double&nbsp;x&nbsp;=&nbsp;Double.parseDouble(args[0]);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;double&nbsp;y&nbsp;=&nbsp;Double.parseDouble(args[1]);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(Operation&nbsp;op&nbsp;:&nbsp;Operation.values())&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(x&nbsp;+&nbsp;"&nbsp;"&nbsp;+&nbsp;op&nbsp;+&nbsp;"&nbsp;"&nbsp;+&nbsp;y&nbsp;+&nbsp;"&nbsp;=&nbsp;"&nbsp;+&nbsp;op.eval(x,&nbsp;y));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br><br>怎么样，使用枚举，我们是不是能够很方便的实现一些有趣的功能？其实说穿了，Java的类型安全枚举就是包含了有限数量的已生成好的自身实例的一种类，这些现成的实例可以通过类的静态字段来获取。<br><br>1.8.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;可变长度参数<br>顾
名思义，可变长度参数就是指在方法的参数体中，只要定义恰当，我们可以使用任意数量的参数，类似于使用数组。在J2SE(TM)&nbsp;5.0中，一个新的语法
被引入，就是在参数类型名称后面加上"..."，表示该方法可以接受多个该类型的参数。需要说明的是可变长度参数必须放在参数列表的最后，且一个方法只能
包含一个这样的参数。在方法体内部，这样的参数被当作数组处理，看上去代码应该类似这个样子：<br><br>public&nbsp;String&nbsp;testVararg(String...&nbsp;args)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;StringBuilder&nbsp;sb&nbsp;=&nbsp;new&nbsp;StringBuilder();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(String&nbsp;str&nbsp;:&nbsp;args)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sb.append(str);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;sb.toString();<br><br>}<br><br>这
样的方法签名跟你写成testVararg(String[]&nbsp;args)的区别在于：在调用时，你不再需要传入一个包装好的String数组，你只需要
简单的写一连串String参数，以逗号隔开即可，就如同这个方法正好有一个重载的版本是接受那么多个String参数一样。<br><br>1.9.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;静态引入<br>所谓静态引入就是指除了引入类之外，我们现在又多了一种选择：引入某个类的静态字段。如：<br><br>import&nbsp;static&nbsp;java.lang.Math.PI;<br><br>或者<br><br>import&nbsp;static&nbsp;java.lang.Math.*;<br><br>这
样我们在接下来的代码中，当我们需要使用某个被引入的静态字段时，就不用再写上前面的类名了。当然，出现名字冲突时，跟原来的类引入一样，还是需要前缀以
示区分。我个人认为这个新语言元素意义不大。当引入太多静态字段后，代码会变得难以阅读和维护。由于静态字段的名字通常不如类名那么具有描述性，我认为原
先在静态字段前写上类名才是更好的选择。不过，毕竟每个人的喜好和需求不同，如果你觉得它对你有用，既然提供了，那么就用咯。<br><br>1.10.&nbsp;&nbsp;元数据（注解）<br>注解是J2SE(TM)&nbsp;5.0引入的重要语言元素，它所对应的JSR是JSR&nbsp;175，我们先来看看JSR&nbsp;175的文档对注解的说明：<br><br>&nbsp;<br><br>注解不会直接影响程序的语义，而开发和部署工具则可以读取这些注解信息，并作相应处理，如生成额外的Java源代码、XML文档、或者其他将与包含注解的程序一起使用的物件。<br><br>&nbsp;<br><br>在之前的J2SE版本中，我们已经使用到了一部分早期的注解元素，如@deprecated等。这些元素通常被用于产生HTML的Javadoc。在J2SE(TM)&nbsp;5.0中，注解被正式引入，且推到了Java历史上前所未有的高度。<br><br>&nbsp;<br><br>现
在，注解不仅仅被用来产生Javadoc，更重要的，注解使得代码的编译期检查更加有效和方便，同时也增强了代码的描述能力。有一些注解是随着J2SE
(TM)&nbsp;5.0一起发布的，我们可以直接使用。除此之外，我们也可以很方便的实现自定义的注解。在此基础上，很多以前我们只能靠反射机制来完成的功能也
变得更加容易实现。<br><br>&nbsp;<br><br>我们来看现成的有哪些有用的注解：<br><br>&nbsp;<br><br>首先是@Override，这个注解被使用在方法上，表明这个方法是从其父类继承下来的，这样的写法可以很方便的避免我们在重写继承下来的方法时，不至于不小心写错了方法签名，且悄悄的溜过了编译器，造成隐蔽性相当高的bug。<br><br>&nbsp;<br><br>其次是@Deprecated，表明该项（类、字段、方法）不再被推荐使用。<br><br>&nbsp;<br><br>还有一个@SuppressWarnings，表明该项（类、字段、方法）所涵盖的范围不需要显示所有的警告信息。这个注解需要提供参数，如unchecked等等。<br><br>&nbsp;<br><br>下面我通过一个例子向大家说明这些现成的注解的用法：<br><br>public&nbsp;class&nbsp;Main&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;@Deprecated<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;String&nbsp;str;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;static&nbsp;void&nbsp;main(String[]&nbsp;args)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new&nbsp;SubMain().doSomething();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;doSomething()&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Done.");<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br><br>&nbsp;<br><br>class&nbsp;SubMain&nbsp;extends&nbsp;Main&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;@Override<br><br>&nbsp;&nbsp;&nbsp;&nbsp;@SuppressWarnings("unchecked",&nbsp;"warning")<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;doSomething()&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;java.util.ArrayList&nbsp;aList&nbsp;=&nbsp;new&nbsp;java.util.ArrayList();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;aList.add(new&nbsp;Integer(0));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Done&nbsp;by&nbsp;SubMain.");<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br><br>当然，我们也完全可以写自己的注解。注解定义的语法是@interface关键字。J2SE(TM)&nbsp;5.0支持三种形式的注解：不带参数的标记注解、带一个参数的注解和带多个参数的完整注解。下面分别举例说明：<br><br>&nbsp;<br><br>标记注解，类似@Deprecated，如：<br><br>@interface&nbsp;SomeEmptyAnnotation&nbsp;{}<br><br>单个参数的注解，如：<br><br>@interface&nbsp;MySingleElementAnnotation&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;value();<br><br>}<br><br>以及多个参数的注解，如：<br><br>@interface&nbsp;MyAnnotationForMethods&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;index();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;info();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;developer()&nbsp;default&nbsp;"Sean&nbsp;GAO";<br><br>}<br><br>&nbsp;<br><br>我
们可以看到，注解的定义跟interface的定义相当类似，我们还可以指定默认值。对于这些注解，我们也可以为其添加注解，所谓“注解的注解”。比方
讲，我们通常会使用@Target指定注解的作用对象，以及用@Retention指定注解信息写入的级别，如源代码、类文件等等。举个例子：<br><br>@Target(ElementType.METHOD)<br><br>@Retention(RetentionPolicy.SOURCE)<br><br>public&nbsp;@interface&nbsp;SignedMethod&nbsp;{<br><br>}<br><br>在使用时，我们需要在注解名称前面写上@，然后()中指定参数值，如：<br><br>@MyAnnotationForMethods&nbsp;(<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index&nbsp;=&nbsp;1,&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;info&nbsp;=&nbsp;"This&nbsp;is&nbsp;a&nbsp;method&nbsp;to&nbsp;test&nbsp;MyAnnotation.",<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;developer&nbsp;=&nbsp;"Somebody&nbsp;else"<br><br>)<br><br>public&nbsp;void&nbsp;testMethod1()&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;...<br><br>}<br><br>注
解的最大作用在于它在源代码的基础上增加了有用的信息，使得源代码的描述性更强。这些信息可以被代码之外的工具识别，从而可以很方便的增加外部功能，以及
减少不必要的相关代码/文件的维护。这里我想简单提一个超出J2SE(TM)&nbsp;5.0范畴的话题：在未来的EJB&nbsp;3.0规范中会有相当多的对注解的应
用，让我们预览一下将来的无状态会话bean用注解来定义会是什么样子：<br><br>@Stateless&nbsp;public&nbsp;class&nbsp;BookShelfManagerBean&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;addBook(Book&nbsp;aBook)&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;business&nbsp;logic&nbsp;goes&nbsp;here...<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;Collection&nbsp;getAllBooks()&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;business&nbsp;logic&nbsp;goes&nbsp;here...<br><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;...<br><br>}<br><br>我们甚至不用写任何接口和部署描述符，这些工作将完全由外部工具通过读取注解加上反射来完成，这不是很好吗？<br><br>1.11.&nbsp;&nbsp;C风格格式化输出<br>Java总算也有类似C的printf()风格的方法了，方法名同样叫作printf()，这一特性依赖于前边提到的可变长度参数。举个例子来说，我们现在可以写：<br><br>System.out.printf("%s&nbsp;has&nbsp;a&nbsp;value&nbsp;of&nbsp;%d.%n",&nbsp;someString,&nbsp;a);<br><br>&nbsp;<br><br>怎么样，看上去还不错吧？需要注意的是Java为了支持多平台，新增了%n标示符，作为对\n的补充。有关Java格式化输出的具体语法，请参考java.util.Formatter的API文档。<br><br>1.12.&nbsp;&nbsp;结语<br>在
这一篇介绍性的文章中，我们一起领略了J2SE&nbsp;5.0带来的新的语言元素，不知道大家是否也跟笔者一样，感受到了这些新特性在提高我们的开发效率上所作
的巨大努力。其实不只是语言元素，J2SE(TM)&nbsp;5.0的发布在其他很多方面都作了不小的改进，包括虚拟机、新的API类库等等，性能和功能上都有大
幅提升。<br><br>&nbsp;<br><br>对于主要靠J2EE吃饭的朋友来讲，也许真正意义上要在工作中充分利用这些新的元素，恐怕要等主流的J2EE服务器都支持J2EE(TM)&nbsp;5.0的那一天了，对此我充满期待。</div>]]></description>
	    <author><![CDATA[ync]]></author>
	    <comments>http://ync.blog.163.com/blog/static/310032007222111318603</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://ync.blog.163.com/blog/static/310032007222111318603</guid>
    <pubDate>Thu, 22 Mar 2007 11:13:18 +0800</pubDate>
    <dcterms:modified>2007-03-22T11:13:18+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[模板引擎SMARTY]]></title>	
    <link>http://ync.blog.163.com/blog/static/31003200721421711615</link>
    <description><![CDATA[<div><blockquote>用PHP实现MVC开发模式的逻辑层和表示层有多种模板引擎可供选择，但是官方引擎SMARTY诞生后，选择就有了变化。它的理
念和实现都是相当"前卫"的。本文主要讨论SMARTY之于其他模板引擎的不同特点，简要介绍了该引擎的安装及使用，并用一个小的测试案例对比了
SMARTY和PHPLIB template的速度和易用性。</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 ><span >一、MVC需要模板</span></a></p>
      <p>MVC最早是在SmallTalk语言的开发过程中总结出的一种设计模式，MVC分别代表了"模型"、"视图"和"控制"，目的就是让不同的开发角色在大中型项目中各司其职。在网络应用程序的开发中，可以用下图来表示各概念之间的关系。
</p>
      <p>
        <img alt="" src="http://www-128.ibm.com/developerworks/cn/linux/l-smart/images/image006.gif">
      </p>
      <p>该图展示了一个简单的WEB应用程序，用户在浏览器上看到信息是数据库服务器上的内容，但在这之前经过了应用服务器加工。开发人员负责的就是建立数据结构、处理数据的逻辑以及表示数据的方法。
</p>
      <p>96年CGI在中国开始流行的时候，早期的WEB程序员都是从HTML开始自学成材的，在PERL中print一行行的
HTML并不是一件难事，但是随着网络的一步步提速，页面大小也从当初的二、三十K暴涨了十倍。写CGI程序就产生了一个迫切的要求：分开PERL和
HTML源码。于是，社会进步体现在开发小组内部的分工上。由于美工和程序员对互相的工作并不是十分熟悉，在进行合作的过程中需要用一种约定的"语言"进
行交流。
</p>
      <p>这种语言并不是我们的母语或者英语，术语叫做"模板"，逻辑和表示依靠它联系。它是结合了HTML和脚本语言特征的一种
表达方式。通过这种方式，表示层可以按照用户所希望的格式来显示经过逻辑层处理过的数据。如果你有Windows平台下MFC的开发经验,那么一定会很熟
悉Document/Document
Template/View的封装，这就是一个很典型的MVC例子。对于Web应用来说，个人认为J2EE中的EJB/servlets/JSP是最强大
的，当然还有简洁优美的Structs。另一个很有名的实现就是COM/DCOM+ASP，这个组合在我国是最多人使用的。
</p>
      <p>通过几种MVC实现在WEB应用程序里的对比，可以得到一个关于模板的概念：一组插入了HTML的脚本或者说是插入了脚本HTML，通过这种插入的内容来表示变化的数据。下面给出一个模板文件的例子，这个模板经过处理后在浏览器里显示"Hello, world!"
</p>
       
      <table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td ><pre >&lt;html&gt;<br>   &lt;head&gt;<br>      &lt;title&gt;$greetings&lt;/title&gt;<br>   &lt;/head&gt;<br>   &lt;body&gt;<br>      $greetings<br>   &lt;body&gt;<br>&lt;/html&gt;<br></pre></td></tr></tbody></table><br> 
      <p>这里暂且省略处理方式，在后面做专门对比讨论。</p>
      <br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%"><br><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8"></td></tr></tbody></table><table  align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%"><br><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a href="http://www-128.ibm.com/developerworks/cn/linux/l-smart/#main" ><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><a ><span >二、为什么选SMARTY?</span></a></p>
      <p>对PHP
来说，有很多模板引擎可供选择，比如最早的PHPLIB template和后起之秀Fast
template，经过数次升级，已经相当成熟稳定。如果你对目前手中的模板引擎很满意，那么......也请往下看，相信你作为一个自由软件爱好者或者
追求效率和优雅的开发者，下面的SMARTY介绍多少会有点意思。
</p>
      <p>除了个人偏好的影响，我一直倾向于使用官方标准的实现，比如APACHE的XML引擎Axis。好处就是可以获得尽可能好的兼容性(比如早期MFC对于Win3x的兼容性就比其它的应用程序框架好，当然现在各种版本都很完善了)。SMARTY发布之前我一直使用的是
        <b>PEAR</b>
中的Integrated Template eXtension。这个引擎和PHPLIB template、Fast
template几乎是兼容的，从模板的语法到对模板的处理同出一辙：都是将模板读入内存然后调用parse()函数，用数据对预置的标记进行替换。 </p>
      <p>下面看看SMARTY是怎么做的。接到request后，先判断是否第一次请求该url，如果是，将该
url所需的模板文件"编译"成php脚本，然后redirect；如果不是，就是说该url的模板已经被"编译"过了，检查不需要重编译后可以马上
redirect，重编译条件可以自己设定为固定时限，默认的是模板文件被修改。
</p>
      <p>怎么样，看起来是不是有点眼熟？想起来了──这不就是JSP的原理嘛！的确，这种"编译"用在PHP这样的解释性脚本引擎上显得匪夷所思，但是仔细想想，JAVA不也是由JVM解释执行的吗？这就叫"没有做不到，只有想不到"。
</p>
      <p>既然谈到了JAVA，就再对PHP的未来发表一点看法。PHP官方网站上宣布了要在2003年年底发布PHP5.0版。这
个版本拥有很多崭新的特性：比如异常处理，命名空间，更加面向对象等等。可以说越来越向JAVA靠拢，SMARTY也是新特性之一，使得PHP更适用于大
中型项目的开发。但是似乎离我当初选择它的原因──灵巧易用──越来越远了。但就一个软件的生存周期来看，PHP正处在成长期，开发者赋予它更多的功能，
以期能胜任商业应用是利大于弊的。作为PHP的忠实用户，肯定不希望PHP总是被人指责"能力不足"吧？
</p>
      <p>为什么选择SMARTY，仅仅因为它很像JSP？当然有更为充分的理由。首先，除了第一次编译的成本比较高之外，只要不
修改模板文件，编译好的cache脚本就随时可用，省去了大量的parse()时间；其次SMARTY像PHP一样有丰富的函数库，从统计字数到自动缩
进、文字环绕以及正则表达式都可以直接使用；如果觉得不够，比如需要数据结果集分页显示的功能，SMARTY还有很强的扩展能力，可以通过插件的形式进行
扩充。
</p>
      <p>事实胜于雄辩。我设计了一个测试程序，通过速度和开发难度这两个因素对比了一下SMARTY和PHPLIB template，选PHPLIB template的原因是在patrick的文章
        <a href="http://www-128.ibm.com/developerworks/cn/linux/sdk/php/template/evaluate/index.html">《在PHP世界中选择最合适的模板》</a>中有一个PHPLIB template对Fast template的竞赛，结果PHPLIB template大获全胜，这使得SMARTY有了一个很好的对手。在测试之前，先谈一下在安装过程中需要注意的问题。
      </p>
      <br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%"><br><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8"></td></tr></tbody></table><table  align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%"><br><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a href="http://www-128.ibm.com/developerworks/cn/linux/l-smart/#main" ><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><a ><span >三、可能遇到的问题</span></a></p>
      <p>在SMARTY的
        <a href="http://smarty.php.net/" target="_blank">官方网站</a>上，有详尽的用户手册，可以选择在线HTML和PDF格式的版本。这里就不再涉及手册上已有的内容，只是把初次使用可能遇到的问题做个解释。
      </p>
      <p>第一个问题就很要命：提示说找不到所需文件？并不是每一个人都按照SMARTY默认目录结构来写应用的。这里需要手工指定，假设目录结构如下：
</p>
      <p>
        <img alt="" src="http://www-128.ibm.com/developerworks/cn/linux/l-smart/images/image008.gif">
      </p>
      <p>
就需要在index.php里指定目录结构：</p>
       
      <table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td ><pre >$smart-&gt;template_dir = "smarty/templates/";<br>$smart-&gt;compile_dir = "smarty/templates_c/";<br>$smart-&gt;config_dir = "smarty/configs/";<br>$smart-&gt;cache_dir = "smarty/cache/";<br></pre></td></tr></tbody></table><br> 
      <p>第一个问题解决了，紧接着就是第二个：我刚用Dreamweaver生成的漂亮模板怎么不能用？并不是模板文件有什么问题，而是因为SMARTY默认的标记分隔符是{}，不巧的是Javascript肯定包含这个标记。好在我们可以用任意字符当作分隔符，再加上这两句：
</p>
       
      <table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td ><pre >$smart-&gt;left_delimiter = "{/";<br>$smart-&gt;right_delimiter = "/}";<br></pre></td></tr></tbody></table><br> 
      <p>这下安装就基本完成，没问题了。</p>
      <br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%"><br><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8"></td></tr></tbody></table><table  align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%"><br><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a href="http://www-128.ibm.com/developerworks/cn/linux/l-smart/#main" ><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><a ><span >四、反衬和类比</span></a></p>
      <p>先
构思一下对测试的设计。主要的评比因素当然是速度了。为了进行速度测试，采取了算术平均数的作法。在测试页面中重复将页面生成N遍，再对比总页面生成时
间。另一个重要因素是易用性(至于扩展性不用比较已经有结果了)，所以使用的模板不能太小。我用的是我个人主页的的页面，一个用Firework+
Dreamweaver生成的HTML文件，大小约7K。其中的变量设置也采取最常用的区块，在PHPLIB
template里叫block,而SMARTY则称section。别小看这称呼的不同，易用性标准分两块：模板文件和脚本文件的语法是否简明易用。
</p>
      <p>
        <img alt="" src="http://www-128.ibm.com/developerworks/cn/linux/l-smart/images/image010.jpg">
      </p>
      <p>下面就深入到测试中来。先看看两种模板文件的语法：蓝条左边是PHPLIB template的模板，右边属于SMARTY。个人偏好是不一样的，所以这里不作评论。着重对比一下脚本里的处理语句，先看PHPLIB template的:
</p>
       
      <table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td ><pre >$tpl-&gt;set_file('phplib', 'bigfile.htm');<br>$tpl-&gt;set_block('phplib', 'row', 'rows');<br>for ($j = 0; $j &lt; 10; $j++){<br>        $tpl-&gt;set_var('tag' ,"$j");<br>        $tpl-&gt;parse('rows', 'row', true);<br>}<br>$tpl-&gt;parse('out', 'phplib');<br>$tpl-&gt;p('out');<br></pre></td></tr></tbody></table><br> 
      <p>下面是SMARTY的：</p>
       
      <table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td ><pre >$smart-&gt;assign('row',$row);<br>$smart-&gt;display('bigfile.htm');<br></pre></td></tr></tbody></table><br> 
      <p>SMARTY只用了tags和row两个变量，而
PHPLIB
template则多了模板文件的handler，还有一个莫名其妙的out。说实在的这个out我当初学的时候就不知道为什么要存在，现在看起来，还是
别扭。为什么SMARTY少那么多处理语句呢？答案是工作由引擎完成了。如果你喜欢钻研源程序，可以发现在
Smarty_compiler.class.php里有一个名叫_compile_tag()的函数，由它负责把section这个标签转换成php语
句。这不是一个普通的标签，它带有参数和数据，节省了脚本编程的工作量，而模板标签上的工作量相差又不大，可以判定在易用性上SMARTY高出一畴。
</p>
      <p>下面该轮到我们最关注的速度了，毕竟对于一个熟练的web开发者来说，掌握再困难的工具不过是时间问题，何况模板引擎这
种学习曲线平缓的技术。而速度则是web应用程序的生命，尤其是模板引擎使用在并发访问量很大的站点上，这点就更重要了。测试开始前，我觉得PHPLIB
template会在这一环节上胜出，因为它经历了很多次升级，已经基本没有什么bug,而且SMARTY的引擎个头太大，不像它的对手只有两个文件。
</p>
      <p>果然，测试结果如下图，PHPLIB template有25%的速度优势：
</p>
      <p>
        <img alt="" src="http://www-128.ibm.com/developerworks/cn/linux/l-smart/images/image012.gif">
      </p>
      <p>但不会一直这样，我又按了一次刷新，这次得到了不一样的结果：</p>
      <p>
        <img alt="" src="http://www-128.ibm.com/developerworks/cn/linux/l-smart/images/image014.gif">
      </p>
      <p>PHPLIB
基本没变化，但是SMARTY提高了25%的速度。继续刷新，得到的都是类似于第二次的结果：SMARTY比PHPLIB template
快上近10%。我想这就是编译型比解释型快的原理了。SMARTY引擎本身就很大，加上还要把模板编译成php文件，速度当然比不上小巧的PHPLIB
template。但这只是第一次的情况。第二次接到请求的时候，SMARTY发现该模板已经被编译过了，于是最耗时的一步被跳过了，而对手还要按部就班
地进行查找和替换工作。这是编译原理里讲到的很经典的"用空间换时间"例子。
</p>
      <br><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td><img src="http://www.ibm.com/i/v14/rules/blue_rule.gif" alt="" height="1" width="100%"><br><img alt="" src="http://www.ibm.com/i/c.gif" border="0" height="6" width="8"></td></tr></tbody></table><table  align="right" cellpadding="0" cellspacing="0"><tbody><tr align="right"><td><img src="http://www.ibm.com/i/c.gif" alt="" height="4" width="100%"><br><table border="0" cellpadding="0" cellspacing="0"><tbody><tr><td valign="middle"><img src="http://www.ibm.com/i/v14/icons/u_bold.gif" alt="" border="0" height="16" width="16"><br></td><td align="right" valign="top"><a href="http://www-128.ibm.com/developerworks/cn/linux/l-smart/#main" ><b>回页首</b></a></td></tr></tbody></table></td></tr></tbody></table><br><br><p><a ><span >五、结论</span></a></p>
      <p>结论就是如果你已经爱上SMARTY了，那么还等什么呢？当然并不是说它就全能，就如同我用MVC模式来写我的个人网站，非但没有减少工作量，反而总是要为不同层次间的耦合劳神。
</p>
      <p>SMARTY不适合什么呢？举个手册里的经典例子：天气预报网站。我还想到一个：股市大盘。在这种网站上用SMARTY会由于经常的重编译而效率偏低，还是PHPLIB template更为适合。
</p>
      <p>本文并不是为了对比两种引擎，而是为了说明SMARTY的优势。使用它最有意义之处在于它是PHP新体系的一部份，作为一
支独立的力量，除了.NET和JAVA
ONE这两大体系之外，大中型web开发还有别的选择。这对于GNU项目来说，其意义无异于刘邓大军千里跃进大别山。
</p>
    <br><br><p><a ><span >参考资料 </span></a></p>
      <ul><li>SMARTY官方站点：
          <a href="http://smarty.php.net/" target="_blank">smarty.php.net</a>
        <br><br></li><li>王晨：
          <a href="http://www-128.ibm.com/developerworks/cn/linux/sdk/php/template/evaluate/index.html" target="_blank">《在PHP世界中选择最合适的模板》</a>，IBM DeveloperNetwork
        <br><br></li><li>本文中测试程序下载：
          <a href="http://www-128.ibm.com/developerworks/cn/linux/l-smart/testsuite.tar.bz2" target="_blank">test.tar.bz2</a>
        <br></li></ul>
    <br><br><p><a ><span >关于作者</span></a></p><table border="0" cellpadding="0" cellspacing="0" width="100%"><tbody><tr><td colspan="3"><img alt="" src="http://www.ibm.com/i/c.gif" height="5" width="100%"></td></tr><tr align="left" valign="top"><td><br></td><td><img alt="" src="http://www.ibm.com/i/c.gif" height="5" width="4"></td><td width="100%"><p>于博翔，笔名于莱，来自对外经济贸易大学信息学院。GNU痴迷者，喜欢练习各种编程语言，研究各种体系框架。有个人网站
        <a href="http://www.postwebpro.com/" target="_blank">www.postwebpro.com</a>。欢迎来信交流:
        <a href="mailto:yulair@postwebpro.com?cc=">yulair@postwebpro.com</a>
      </p></td></tr></tbody></table></div>]]></description>
	    <author><![CDATA[ync]]></author>
	    <comments>http://ync.blog.163.com/blog/static/31003200721421711615</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://ync.blog.163.com/blog/static/31003200721421711615</guid>
    <pubDate>Wed, 14 Mar 2007 14:17:11 +0800</pubDate>
    <dcterms:modified>2007-03-14T14:17:11+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[猪来了。]]></title>	
    <link>http://ync.blog.163.com/blog/static/3100320070143211293</link>
    <description><![CDATA[<div><P>
</P><pre>
{/ o&nbsp; o /}&nbsp;&nbsp; {/ .&nbsp; . /}&nbsp;&nbsp; {/ ︿︿ /}<BR>&nbsp;( (oo) )&nbsp;&nbsp;&nbsp;&nbsp; ( (oo) )&nbsp;&nbsp;&nbsp;&nbsp; ( (oo) ) <BR>&nbsp; ︶ ︶︶&nbsp;&nbsp;&nbsp;&nbsp; ︶ ︶ ︶&nbsp;&nbsp;&nbsp;&nbsp; ︶ ︶ ︶ <BR>&nbsp; 标准猪&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 小眼猪&nbsp;&nbsp;&nbsp; 眉开眼笑的猪<BR>╭︿︿︿╮&nbsp;&nbsp;&nbsp; ╭︿︿︿╮&nbsp; ╭︿︿︿╮<BR>{/ $&nbsp; $ /}&nbsp;&nbsp;&nbsp; {/ @&nbsp; @ /}&nbsp; {/-■■-/}<BR>&nbsp;( (oo) )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( (oo) )&nbsp;&nbsp;&nbsp; ( (oo) )<BR>&nbsp;︶ ︶ ︶&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ︶︶︶&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ︶︶︶ <BR>财迷心窍猪&nbsp;&nbsp;&nbsp; 头晕目眩猪&nbsp;&nbsp;&nbsp; 酷酷猪</P>
<P>╭︿︿︿╮&nbsp; ╭︿︿︿╮&nbsp;&nbsp;&nbsp;╭︿︿︿╮<BR>{/ 0&nbsp; 0 /}&nbsp; {/ X&nbsp; o /}&nbsp;&nbsp;&nbsp;{/ ·· /}<BR>&nbsp;( (qp) )&nbsp;&nbsp;&nbsp; ( (oo) )&nbsp;&nbsp;&nbsp;&nbsp; ( (00）) <BR>&nbsp; ︶︶︶&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ︶︶︶&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ︶︶︶&nbsp; <BR>&nbsp; 生气猪&nbsp;&nbsp;&nbsp;&nbsp; 独眼龙猪&nbsp;&nbsp;&nbsp; 张大鼻孔猪</P>
<P>╭︿︿︿╮&nbsp;&nbsp; ╭︿︿︿╮&nbsp; ╭︿︿︿╮<BR>{/ #&nbsp; # /}&nbsp;&nbsp; {/-◎◎-/}&nbsp; {/ -&nbsp; - /} <BR>&nbsp;( (oo) )&nbsp;&nbsp;&nbsp;&nbsp; ( (oo) )&nbsp;&nbsp;&nbsp; ( (..) ) <BR>&nbsp; ︶︶︶&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ︶︶︶&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ︶︶︶&nbsp; <BR>&nbsp;&nbsp; 茫然猪&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 戴眼镜猪&nbsp; 悠闲自在猪</P>
<P>╭︿︿︿╮&nbsp; ╭︿︿︿╮&nbsp;&nbsp;&nbsp; ╭︿︿︿╮ <BR>{/-●●-/}&nbsp; {/-★★-/}&nbsp;&nbsp;&nbsp; {/-⊙⊙-/} <BR>&nbsp;( (oo) )&nbsp;&nbsp;&nbsp; ( (oo) )&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ( (oo) ) <BR>&nbsp; ︶︶︶&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ︶︶︶&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ︶︶︶ <BR>&nbsp; 墨镜猪&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 时髦猪&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 目瞪口呆猪 <BR>
</P></pre>
</P></div>]]></description>
	    <author><![CDATA[ync]]></author>
	    <comments>http://ync.blog.163.com/blog/static/3100320070143211293</comments>
    <slash:comments>1</slash:comments>
    <guid isPermaLink="true">http://ync.blog.163.com/blog/static/3100320070143211293</guid>
    <pubDate>Mon, 1 Jan 2007 16:32:11 +0800</pubDate>
    <dcterms:modified>2007-01-01T17:26:40+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[笑话几则]]></title>	
    <link>http://ync.blog.163.com/blog/static/3100320061131114123864</link>
    <description><![CDATA[<div>两只青蛙相爱了，结婚后生了一个蛤嫫，公青蛙见状大怒说：贱人，怎么回事 母青蛙哭着说：他爹，认识你之前我整过容。 <BR>&nbsp;&nbsp; 小驴问老驴：为啥咱们天天吃干草，而奶牛顿顿精饲料 老驴叹到：咱爷们比不了，我们是靠跑腿吃饭，人家是靠胸脯吃饭！ <BR>&nbsp;&nbsp; 鸭子和螃蟹赛跑,一起到达终点，难分胜负，裁判说：你们来个剪刀石头布吧 鸭子大怒：妈的，算计我?我一出是布，他总是剪刀。 <BR>&nbsp;&nbsp; 狗对熊说：嫁给我吧,嫁给我你会幸福。熊说：才不嫁呢，嫁给你只会生狗熊，我要嫁给猫，生熊猫那才尊贵呢! <BR>&nbsp;&nbsp; 老鳖调戏河蚌，被咬，老鳖忍痛拖着河蚌来回爬，青蛙见了敬佩的说：乖乖，鳖哥混大了，出入都加着公文包。 <BR>&nbsp;&nbsp; 蜜蜂狂追蝴蝶，蝴蝶却嫁给了蜗牛。蜜蜂不解：他哪里比我好 蝴蝶回答：人家好歹有自己的房子，哪像你住在集体宿舍 </div>]]></description>
	    <author><![CDATA[ync]]></author>
	    <comments>http://ync.blog.163.com/blog/static/3100320061131114123864</comments>
    <slash:comments>1</slash:comments>
    <guid isPermaLink="true">http://ync.blog.163.com/blog/static/3100320061131114123864</guid>
    <pubDate>Sun, 31 Dec 2006 11:41:23 +0800</pubDate>
    <dcterms:modified>2006-12-31T11:41:23+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[用PHP构建一个简易监视引擎(1)]]></title>	
    <link>http://ync.blog.163.com/blog/static/310032006111473247333</link>
    <description><![CDATA[<div><P>&nbsp; 没仔细看这篇文章：） 第一感觉挺不错的。</P>  <P>&nbsp; 也没仔细玩过php，现在感觉挺喜欢php的：）</P>  <P>&nbsp; 转过来备个份。</P>  <P>&nbsp;&nbsp; <A href="http://www.souzz.net">http://www.souzz.net</A> 2006-10-28 文章出处：天极开发</P>  <P>&nbsp;&nbsp;&nbsp;<STRONG>摘要</STRONG>：<FONT face=仿宋_GB2312>在本文中，让我们共同探讨基于PHP语言构建一个基本的服务器端监视引擎的诸多技巧及注意事项，并给出完整的源码实现。</FONT></P>  <P>　　<B>一. 更改工作目录的问题</B><BR><BR>　　当你编写一个监视程序时，让它设置自己的工作目录通常更好些。这样以来，如果你使用一个相对路径读写文件，那么，它会根据情况自动处理用户期望存放文件的位置。总是限制程序中使用的路径尽管是一种良好的实践；但是，却失去了应有的灵活性。因此，改变你的工作目录的最安全的方法是，既使用chdir()也使用chroot()。</P>  <P>　　chroot()可用于PHP的CLI和CGI版本中，但是却要求程序以根权限运行。chroot()实际上把当前进程的路径从根目录改变到指定的目录。这使得当前进程只能执行存在于该目录下的文件。经常情况下，chroot()由服务器作为一个"安全设备"使用以确保恶意代码不会修改一个特定的目录之外的文件。请牢记，尽管chroot()能够阻止你访问你的新目录之外的任何文件，但是，任何当前打开的文件资源仍然能够被存取。例如，下列代码能够打开一个日志文件，调用chroot()并切换到一个数据目录；然后，仍然能够成功地登录并进而打开文件资源：<BR><BR>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>＜?php<BR>$logfile = fopen("/var/log/chroot.log"， "w");<BR>chroot("/Users/george");<BR>fputs($logfile， "Hello From Inside The Chroot n");<BR>?＞</TD></TR></TBODY></TABLE><BR>　　如果一个应用程序不能使用chroot()，那么你可以调用chdir()来设置工作目录。例如，当代码需要加载特定的代码（这些代码能够在系统的任何地方被定位时），这是很有用的。注意，chdir()没有提供安全机制来防止打开未授权的文件。<BR><BR>　　<B>二. 放弃特权</B><BR><BR>　　当编写Unix守护程序时，一种经典的安全预防措施是让它们放弃所有不需要的特权；否则，拥有不需要的特权容易招致不必要的麻烦。在代码(或PHP本身)中含有漏洞的情况下，通过确保一个守护程序以最小权限用户身份运行，往往能够使损失减到最小。<BR><BR>　　一种实现此目的的方法是，以非特权用户身份执行该守护程序。然而，如果程序需要在一开始就打开非特权用户无权打开的资源(例如日志文件，数据文件，套接字，等等)的话，这通常是不够的。<BR><BR>　　如果你以根用户身份运行，那么你能够借助于posix_setuid()和posiz_setgid()函数来放弃你的特权。下面的示例把当前运行程序的特权改变为用户nobody所拥有的那些权限：<BR><BR>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>$pw=posix_getpwnam('nobody');<BR>posix_setuid($pw['uid']);<BR>posix_setgid($pw['gid']);</TD></TR></TBODY></TABLE><BR>　　就象chroot()一样，任何在放弃特权之前被打开的特权资源都会保持为打开，但是不能创建新的资源。<BR><STRONG>三. 保证排它性<BR><BR></STRONG>　　你可能经常想实现：一个脚本在任何时刻仅运行一个实例。为了保护脚本，这是特别重要的，因为在后台运行容易导致偶然情况下调用多个实例。 <BR><BR>　　保证这种排它性的标准技术是，通过使用flock()来让脚本锁定一个特定的文件(经常是一个加锁文件，并且被排它式使用)。如果锁定失败，该脚本应该输出一个错误并退出。下面是一个示例：<BR><BR>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>$fp=fopen("/tmp/.lockfile"，"a");<BR>if(!$fp || !flock($fp， LOCK_EX | LOCK_NB)) {<BR>　fputs(STDERR， "Failed to acquire lock n");<BR>　exit; <BR>}<BR></TD></TR></TBODY></TABLE></P>  <P><BR>　　注意，有关锁机制的讨论涉及较多内容，在此不多加解释。<BR><STRONG>三. 保证排它性<BR><BR></STRONG>　　你可能经常想实现：一个脚本在任何时刻仅运行一个实例。为了保护脚本，这是特别重要的，因为在后台运行容易导致偶然情况下调用多个实例。 <BR><BR>　　保证这种排它性的标准技术是，通过使用flock()来让脚本锁定一个特定的文件(经常是一个加锁文件，并且被排它式使用)。如果锁定失败，该脚本应该输出一个错误并退出。下面是一个示例：<BR><BR>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>$fp=fopen("/tmp/.lockfile"，"a");<BR>if(!$fp || !flock($fp， LOCK_EX | LOCK_NB)) {<BR>　fputs(STDERR， "Failed to acquire lock n");<BR>　exit; <BR>}<BR></TD></TR></TBODY></TABLE></P>  <P><BR>　　注意，有关锁机制的讨论涉及较多内容，在此不多加解释。<BR><STRONG>四. 构建监视服务<BR><BR></STRONG>　　在这一节中，我们将使用PHP来编写一个基本的监视引擎。因为你不会事先知道怎样改变，所以你应该使它的实现既灵活又具可能性。<BR>该记录程序应该能够支持任意的服务检查(例如，HTTP和FTP服务)并且能够以任意方式(通过电子邮件，输出到一个日志文件，等等)记录事件。你当然想让它以一个守护程序方式运行；所以，你应该请求它输出其完整的当前状态。<BR><BR>　　一个服务需要实现下列抽象类：<BR><BR>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>abstract class ServiceCheck {<BR>　const FAILURE = 0;<BR>　const SUCCESS = 1;<BR>　protected $timeout = 30;<BR>　protected $next_attempt;<BR>　protected $current_status = ServiceCheck::SUCCESS;<BR>　protected $previous_status = ServiceCheck::SUCCESS;<BR>　protected $frequency = 30;<BR>　protected $description;<BR>　protected $consecutive_failures = 0;<BR>　protected $status_time;<BR>　protected $failure_time;<BR>　protected $loggers = array();<BR>　abstract public function __construct($params);<BR>　public function __call($name， $args)<BR>　{<BR>　　if(isset($this-＞$name)) {<BR>　　　return $this-＞$name;<BR>　　}<BR>　}<BR>　public function set_next_attempt()<BR>　{<BR>　　$this-＞next_attempt = time() + $this-＞frequency;<BR>　}<BR>　public abstract function run();<BR>　public function post_run($status)<BR>　{<BR>　　if($status !== $this-＞current_status) {<BR>　　　$this-＞previous_status = $this-＞current_status;<BR>　　}<BR>　　if($status === self::FAILURE) {<BR>　　　if( $this-＞current_status === self::FAILURE ) {<BR>　　　　$this-＞consecutive_failures++;<BR>　　　}<BR>　　　else {<BR>　　　　$this-＞failure_time = time();<BR>　　　}<BR>　　}<BR>　　else {<BR>　　　$this-＞consecutive_failures = 0;<BR>　　}<BR>　　$this-＞status_time = time();<BR>　　$this-＞current_status = $status;<BR>　　$this-＞log_service_event();<BR>　} <BR>　public function log_current_status()<BR>　{<BR>　　foreach($this-＞loggers as $logger) {<BR>　　　$logger-＞log_current_status($this);<BR>　　}<BR>　}<BR>　private function log_service_event()<BR>　{<BR>　　foreach($this-＞loggers as $logger) {<BR>　　　$logger-＞log_service_event($this);<BR>　　}<BR>　}<BR>　public function register_logger(ServiceLogger $logger)<BR>　{<BR>　　$this-＞loggers[] = $logger;<BR>　}<BR>}</TD></TR></TBODY></TABLE><BR>上面的__call()重载方法提供对一个ServiceCheck对象的参数的只读存取操作：<BR><BR>　　· timeout-在引擎终止检查之前，这一检查能够挂起多长时间。<BR><BR>　　· next_attempt-下次尝试连接到服务器的时间。<BR><BR>　　· current_status-服务的当前状态：SUCCESS或FAILURE。<BR><BR>　　· previous_status-当前状态之前的状态。<BR><BR>　　· frequency-每隔多长时间检查一次服务。<BR><BR>　　· description-服务描述。<BR><BR>　　· consecutive_failures-自从上次成功以来，服务检查连续失败的次数。<BR><BR>　　· status_time-服务被检查的最后时间。<BR><BR>　　· failure_time-如果状态为FAILED，则它代表发生失败的时间。<BR><BR>　　这个类还实现了观察者模式，允许ServiceLogger类型的对象注册自身，然后当调用log_current_status()或log_service_event()时调用它。<BR><BR>　　这里实现的关键函数是run()，它负责定义应该怎样执行检查。如果检查成功，它应该返回SUCCESS；否则返回FAILURE。<BR><BR>　　当定义在run()中的服务检查返回后，post_run()方法被调用。它负责设置对象的状态并实现记入日志。<BR><BR>　　ServiceLogger接口：指定一个日志类仅需要实现两个方法：log_service_event()和log_current_status()，它们分别在当一个run()检查返回时和当实现一个普通状态请求时被调用。<BR><BR>　　该接口如下所示：<BR><BR>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>interface ServiceLogger {<BR>　public function log_service_event(ServiceCheck$service);<BR>　public function log_current_status(ServiceCheck$service);<BR>}</TD></TR></TBODY></TABLE><BR>　　最后，你需要编写引擎本身。该想法类似于在前一节编写简单程序时使用的思想：服务器应该创建一个新的进程来处理每一次检查并使用一个SIGCHLD处理器来检测当检查完成时的返回值。可以同时检查的最大数目应该是可配置的，从而可以防止对系统资源的过渡使用。所有的服务和日志都将在一个XML文件中定义。<BR><BR>　　下面是定义该引擎的ServiceCheckRunner类：<BR><BR>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>class ServiceCheckRunner {<BR>　private $num_children;<BR>　private $services = array();<BR>　private $children = array();<BR>　public function _ _construct($conf， $num_children)<BR>　{<BR>　　$loggers = array();<BR>　　$this-＞num_children = $num_children;<BR>　　$conf = simplexml_load_file($conf);<BR>　　foreach($conf-＞loggers-＞logger as $logger) {<BR>　　　$class = new Reflection_Class("$logger-＞class");<BR>　　　if($class-＞isInstantiable()) {<BR>　　　　$loggers["$logger-＞id"] = $class-＞newInstance();<BR>　　　}<BR>　　　else {<BR>　　　　fputs(STDERR， "{$logger-＞class} cannot be instantiated. n");<BR>　　　　exit;<BR>　　　}<BR>　　}<BR>　　foreach($conf-＞services-＞service as $service) {<BR>　　　$class = new Reflection_Class("$service-＞class");<BR>　　　if($class-＞isInstantiable()) {<BR>　　　　$item = $class-＞newInstance($service-＞params);<BR>　　　　foreach($service-＞loggers-＞logger as $logger) {<BR>　　　　　$item-＞register_logger($loggers["$logger"]);<BR>　　　　}<BR>　　　　$this-＞services[] = $item;<BR>　　　}<BR>　　　else {<BR>　　　　fputs(STDERR， "{$service-＞class} is not instantiable. n");<BR>　　　　exit;<BR>　　　}<BR>　　}<BR>　}<BR>　private function next_attempt_sort($a， $b){<BR>　　if($a-＞next_attempt() == $b-＞next_attempt()) {<BR>　　　return 0;<BR>　　}<BR>　　return ($a-＞next_attempt() ＜ $b-＞next_attempt())? -1 : 1;<BR>　}<BR>　private function next(){<BR>　　usort($this-＞services，array($this，'next_attempt_sort'));<BR>　　return $this-＞services[0];<BR>　}<BR>　public function loop(){<BR>　　declare(ticks=1);<BR>　　pcntl_signal(SIGCHLD， array($this， "sig_child"));<BR>　　pcntl_signal(SIGUSR1， array($this， "sig_usr1"));<BR>　　while(1) {<BR>　　　$now = time();<BR>　　　if(count($this-＞children)＜ $this-＞num_children) {<BR>　　　　$service = $this-＞next();<BR>　　　　if($now ＜ $service-＞next_attempt()) {<BR>　　　　　sleep(1);<BR>　　　　　continue;<BR>　　　　}<BR>　　　　$service-＞set_next_attempt();<BR>　　　　if($pid = pcntl_fork()) {<BR>　　　　　$this-＞children[$pid] = $service;<BR>　　　　} <BR>　　　　else {<BR>　　　　　pcntl_alarm($service-＞timeout());<BR>　　　　　exit($service-＞run());<BR>　　　　}<BR>　　　} <BR>　　} <BR>　}<BR>　public function log_current_status(){<BR>　　foreach($this-＞services as $service) {<BR>　　　$service-＞log_current_status();<BR>　　}<BR>　}<BR>　private function sig_child($signal){<BR>　　$status = ServiceCheck::FAILURE;<BR>　　pcntl_signal(SIGCHLD， array($this， "sig_child"));<BR>　　while(($pid = pcntl_wait($status， WNOHANG)) ＞ 0){<BR>　　　$service = $this-＞children[$pid];<BR>　　　unset($this-＞children[$pid]);<BR>　　　if(pcntl_wifexited($status) &amp;&amp; pcntl_wexitstatus($status) ==ServiceCheck::SUCCESS) <BR>　　　{<BR>　　　　$status = ServiceCheck::SUCCESS;<BR>　　　}<BR>　　　$service-＞post_run($status);<BR>　　}<BR>　}<BR>　private function sig_usr1($signal){<BR>　　pcntl_signal(SIGUSR1， array($this， "sig_usr1"));<BR>　　$this-＞log_current_status();<BR>　}<BR>}</TD></TR></TBODY></TABLE><BR>　　这是一个很复杂的类。其构造器读取并分析一个XML文件，创建所有的将被监视的服务，并创建记录它们的日志程序。<BR><BR>　　loop()方法是该类中的主要方法。它设置请求的信号处理器并检查是否能够创建一个新的子进程。现在，如果下一个事件(以next_attempt时间CHUO排序)运行良好，那么一个新的进程将被创建。在这个新的子进程内，发出一个警告以防止测试持续时间超出它的时限，然后执行由run()定义的测试。<BR><BR>　　还存在两个信号处理器：SIGCHLD处理器sig_child()，负责收集已终止的子进程并执行它们的服务的post_run()方法；SIGUSR1处理器sig_usr1()，简单地调用所有已注册的日志程序的log_current_status()方法，这可以用于得到整个系统的当前状态。<BR><BR>　　当然，这个监视架构并不没有做任何实际的事情。但是首先，你需要检查一个服务。下列这个类检查是否你从一个HTTP服务器取回一个"200 Server OK"响应：<BR><BR>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>class HTTP_ServiceCheck extends ServiceCheck{<BR>　public $url;<BR>　public function _ _construct($params){<BR>　　foreach($params as $k =＞ $v) {<BR>　　　$k = "$k";<BR>　　　$this-＞$k = "$v";<BR>　　}<BR>　}<BR>　public function run(){<BR>　　if(is_resource(@fopen($this-＞url， "r"))) {<BR>　　　return ServiceCheck::SUCCESS;<BR>　　}<BR>　　else {<BR>　　　return ServiceCheck::FAILURE;<BR>　　}<BR>　}<BR>}</TD></TR></TBODY></TABLE><BR>　　与你以前构建的框架相比，这个服务极其简单，在此恕不多描述。<BR>上面的__call()重载方法提供对一个ServiceCheck对象的参数的只读存取操作：<BR><BR>　　· timeout-在引擎终止检查之前，这一检查能够挂起多长时间。<BR><BR>　　· next_attempt-下次尝试连接到服务器的时间。<BR><BR>　　· current_status-服务的当前状态：SUCCESS或FAILURE。<BR><BR>　　· previous_status-当前状态之前的状态。<BR><BR>　　· frequency-每隔多长时间检查一次服务。<BR><BR>　　· description-服务描述。<BR><BR>　　· consecutive_failures-自从上次成功以来，服务检查连续失败的次数。<BR><BR>　　· status_time-服务被检查的最后时间。<BR><BR>　　· failure_time-如果状态为FAILED，则它代表发生失败的时间。<BR><BR>　　这个类还实现了观察者模式，允许ServiceLogger类型的对象注册自身，然后当调用log_current_status()或log_service_event()时调用它。<BR><BR>　　这里实现的关键函数是run()，它负责定义应该怎样执行检查。如果检查成功，它应该返回SUCCESS；否则返回FAILURE。<BR><BR>　　当定义在run()中的服务检查返回后，post_run()方法被调用。它负责设置对象的状态并实现记入日志。<BR><BR>　　ServiceLogger接口：指定一个日志类仅需要实现两个方法：log_service_event()和log_current_status()，它们分别在当一个run()检查返回时和当实现一个普通状态请求时被调用。<BR><BR>　　该接口如下所示：<BR><BR>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>interface ServiceLogger {<BR>　public function log_service_event(ServiceCheck$service);<BR>　public function log_current_status(ServiceCheck$service);<BR>}</TD></TR></TBODY></TABLE><BR>　　最后，你需要编写引擎本身。该想法类似于在前一节编写简单程序时使用的思想：服务器应该创建一个新的进程来处理每一次检查并使用一个SIGCHLD处理器来检测当检查完成时的返回值。可以同时检查的最大数目应该是可配置的，从而可以防止对系统资源的过渡使用。所有的服务和日志都将在一个XML文件中定义。<BR><BR>　　下面是定义该引擎的ServiceCheckRunner类：<BR><BR>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>class ServiceCheckRunner {<BR>　private $num_children;<BR>　private $services = array();<BR>　private $children = array();<BR>　public function _ _construct($conf， $num_children)<BR>　{<BR>　　$loggers = array();<BR>　　$this-＞num_children = $num_children;<BR>　　$conf = simplexml_load_file($conf);<BR>　　foreach($conf-＞loggers-＞logger as $logger) {<BR>　　　$class = new Reflection_Class("$logger-＞class");<BR>　　　if($class-＞isInstantiable()) {<BR>　　　　$loggers["$logger-＞id"] = $class-＞newInstance();<BR>　　　}<BR>　　　else {<BR>　　　　fputs(STDERR， "{$logger-＞class} cannot be instantiated. n");<BR>　　　　exit;<BR>　　　}<BR>　　}<BR>　　foreach($conf-＞services-＞service as $service) {<BR>　　　$class = new Reflection_Class("$service-＞class");<BR>　　　if($class-＞isInstantiable()) {<BR>　　　　$item = $class-＞newInstance($service-＞params);<BR>　　　　foreach($service-＞loggers-＞logger as $logger) {<BR>　　　　　$item-＞register_logger($loggers["$logger"]);<BR>　　　　}<BR>　　　　$this-＞services[] = $item;<BR>　　　}<BR>　　　else {<BR>　　　　fputs(STDERR， "{$service-＞class} is not instantiable. n");<BR>　　　　exit;<BR>　　　}<BR>　　}<BR>　}<BR>　private function next_attempt_sort($a， $b){<BR>　　if($a-＞next_attempt() == $b-＞next_attempt()) {<BR>　　　return 0;<BR>　　}<BR>　　return ($a-＞next_attempt() ＜ $b-＞next_attempt())? -1 : 1;<BR>　}<BR>　private function next(){<BR>　　usort($this-＞services，array($this，'next_attempt_sort'));<BR>　　return $this-＞services[0];<BR>　}<BR>　public function loop(){<BR>　　declare(ticks=1);<BR>　　pcntl_signal(SIGCHLD， array($this， "sig_child"));<BR>　　pcntl_signal(SIGUSR1， array($this， "sig_usr1"));<BR>　　while(1) {<BR>　　　$now = time();<BR>　　　if(count($this-＞children)＜ $this-＞num_children) {<BR>　　　　$service = $this-＞next();<BR>　　　　if($now ＜ $service-＞next_attempt()) {<BR>　　　　　sleep(1);<BR>　　　　　continue;<BR>　　　　}<BR>　　　　$service-＞set_next_attempt();<BR>　　　　if($pid = pcntl_fork()) {<BR>　　　　　$this-＞children[$pid] = $service;<BR>　　　　} <BR>　　　　else {<BR>　　　　　pcntl_alarm($service-＞timeout());<BR>　　　　　exit($service-＞run());<BR>　　　　}<BR>　　　} <BR>　　} <BR>　}<BR>　public function log_current_status(){<BR>　　foreach($this-＞services as $service) {<BR>　　　$service-＞log_current_status();<BR>　　}<BR>　}<BR>　private function sig_child($signal){<BR>　　$status = ServiceCheck::FAILURE;<BR>　　pcntl_signal(SIGCHLD， array($this， "sig_child"));<BR>　　while(($pid = pcntl_wait($status， WNOHANG)) ＞ 0){<BR>　　　$service = $this-＞children[$pid];<BR>　　　unset($this-＞children[$pid]);<BR>　　　if(pcntl_wifexited($status) &amp;&amp; pcntl_wexitstatus($status) ==ServiceCheck::SUCCESS) <BR>　　　{<BR>　　　　$status = ServiceCheck::SUCCESS;<BR>　　　}<BR>　　　$service-＞post_run($status);<BR>　　}<BR>　}<BR>　private function sig_usr1($signal){<BR>　　pcntl_signal(SIGUSR1， array($this， "sig_usr1"));<BR>　　$this-＞log_current_status();<BR>　}<BR>}</TD></TR></TBODY></TABLE><BR>　　这是一个很复杂的类。其构造器读取并分析一个XML文件，创建所有的将被监视的服务，并创建记录它们的日志程序。<BR><BR>　　loop()方法是该类中的主要方法。它设置请求的信号处理器并检查是否能够创建一个新的子进程。现在，如果下一个事件(以next_attempt时间CHUO排序)运行良好，那么一个新的进程将被创建。在这个新的子进程内，发出一个警告以防止测试持续时间超出它的时限，然后执行由run()定义的测试。<BR><BR>　　还存在两个信号处理器：SIGCHLD处理器sig_child()，负责收集已终止的子进程并执行它们的服务的post_run()方法；SIGUSR1处理器sig_usr1()，简单地调用所有已注册的日志程序的log_current_status()方法，这可以用于得到整个系统的当前状态。<BR><BR>　　当然，这个监视架构并不没有做任何实际的事情。但是首先，你需要检查一个服务。下列这个类检查是否你从一个HTTP服务器取回一个"200 Server OK"响应：<BR><BR>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>class HTTP_ServiceCheck extends ServiceCheck{<BR>　public $url;<BR>　public function _ _construct($params){<BR>　　foreach($params as $k =＞ $v) {<BR>　　　$k = "$k";<BR>　　　$this-＞$k = "$v";<BR>　　}<BR>　}<BR>　public function run(){<BR>　　if(is_resource(@fopen($this-＞url， "r"))) {<BR>　　　return ServiceCheck::SUCCESS;<BR>　　}<BR>　　else {<BR>　　　return ServiceCheck::FAILURE;<BR>　　}<BR>　}<BR>}</TD></TR></TBODY></TABLE><BR>　　与你以前构建的框架相比，这个服务极其简单，在此恕不多描述。</P>  <P>上面的__call()重载方法提供对一个ServiceCheck对象的参数的只读存取操作：<BR><BR>　　· timeout-在引擎终止检查之前，这一检查能够挂起多长时间。<BR><BR>　　· next_attempt-下次尝试连接到服务器的时间。<BR><BR>　　· current_status-服务的当前状态：SUCCESS或FAILURE。<BR><BR>　　· previous_status-当前状态之前的状态。<BR><BR>　　· frequency-每隔多长时间检查一次服务。<BR><BR>　　· description-服务描述。<BR><BR>　　· consecutive_failures-自从上次成功以来，服务检查连续失败的次数。<BR><BR>　　· status_time-服务被检查的最后时间。<BR><BR>　　· failure_time-如果状态为FAILED，则它代表发生失败的时间。<BR><BR>　　这个类还实现了观察者模式，允许ServiceLogger类型的对象注册自身，然后当调用log_current_status()或log_service_event()时调用它。<BR><BR>　　这里实现的关键函数是run()，它负责定义应该怎样执行检查。如果检查成功，它应该返回SUCCESS；否则返回FAILURE。<BR><BR>　　当定义在run()中的服务检查返回后，post_run()方法被调用。它负责设置对象的状态并实现记入日志。<BR><BR>　　ServiceLogger接口：指定一个日志类仅需要实现两个方法：log_service_event()和log_current_status()，它们分别在当一个run()检查返回时和当实现一个普通状态请求时被调用。<BR><BR>　　该接口如下所示：<BR><BR></P>  <P>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>interface ServiceLogger {<BR>　public function log_service_event(ServiceCheck$service);<BR>　public function log_current_status(ServiceCheck$service);<BR>}</TD></TR></TBODY></TABLE></P>  <P><BR>　　最后，你需要编写引擎本身。该想法类似于在前一节编写简单程序时使用的思想：服务器应该创建一个新的进程来处理每一次检查并使用一个SIGCHLD处理器来检测当检查完成时的返回值。可以同时检查的最大数目应该是可配置的，从而可以防止对系统资源的过渡使用。所有的服务和日志都将在一个XML文件中定义。<BR><BR>　　下面是定义该引擎的ServiceCheckRunner类：<BR><BR></P>  <P>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>class ServiceCheckRunner {<BR>　private $num_children;<BR>　private $services = array();<BR>　private $children = array();<BR>　public function _ _construct($conf， $num_children)<BR>　{<BR>　　$loggers = array();<BR>　　$this-＞num_children = $num_children;<BR>　　$conf = simplexml_load_file($conf);<BR>　　foreach($conf-＞loggers-＞logger as $logger) {<BR>　　　$class = new Reflection_Class("$logger-＞class");<BR>　　　if($class-＞isInstantiable()) {<BR>　　　　$loggers["$logger-＞id"] = $class-＞newInstance();<BR>　　　}<BR>　　　else {<BR>　　　　fputs(STDERR， "{$logger-＞class} cannot be instantiated. n");<BR>　　　　exit;<BR>　　　}<BR>　　}<BR>　　foreach($conf-＞services-＞service as $service) {<BR>　　　$class = new Reflection_Class("$service-＞class");<BR>　　　if($class-＞isInstantiable()) {<BR>　　　　$item = $class-＞newInstance($service-＞params);<BR>　　　　foreach($service-＞loggers-＞logger as $logger) {<BR>　　　　　$item-＞register_logger($loggers["$logger"]);<BR>　　　　}<BR>　　　　$this-＞services[] = $item;<BR>　　　}<BR>　　　else {<BR>　　　　fputs(STDERR， "{$service-＞class} is not instantiable. n");<BR>　　　　exit;<BR>　　　}<BR>　　}<BR>　}<BR>　private function next_attempt_sort($a， $b){<BR>　　if($a-＞next_attempt() == $b-＞next_attempt()) {<BR>　　　return 0;<BR>　　}<BR>　　return ($a-＞next_attempt() ＜ $b-＞next_attempt())? -1 : 1;<BR>　}<BR>　private function next(){<BR>　　usort($this-＞services，array($this，'next_attempt_sort'));<BR>　　return $this-＞services[0];<BR>　}<BR>　public function loop(){<BR>　　declare(ticks=1);<BR>　　pcntl_signal(SIGCHLD， array($this， "sig_child"));<BR>　　pcntl_signal(SIGUSR1， array($this， "sig_usr1"));<BR>　　while(1) {<BR>　　　$now = time();<BR>　　　if(count($this-＞children)＜ $this-＞num_children) {<BR>　　　　$service = $this-＞next();<BR>　　　　if($now ＜ $service-＞next_attempt()) {<BR>　　　　　sleep(1);<BR>　　　　　continue;<BR>　　　　}<BR>　　　　$service-＞set_next_attempt();<BR>　　　　if($pid = pcntl_fork()) {<BR>　　　　　$this-＞children[$pid] = $service;<BR>　　　　} <BR>　　　　else {<BR>　　　　　pcntl_alarm($service-＞timeout());<BR>　　　　　exit($service-＞run());<BR>　　　　}<BR>　　　} <BR>　　} <BR>　}<BR>　public function log_current_status(){<BR>　　foreach($this-＞services as $service) {<BR>　　　$service-＞log_current_status();<BR>　　}<BR>　}<BR>　private function sig_child($signal){<BR>　　$status = ServiceCheck::FAILURE;<BR>　　pcntl_signal(SIGCHLD， array($this， "sig_child"));<BR>　　while(($pid = pcntl_wait($status， WNOHANG)) ＞ 0){<BR>　　　$service = $this-＞children[$pid];<BR>　　　unset($this-＞children[$pid]);<BR>　　　if(pcntl_wifexited($status) &amp;&amp; pcntl_wexitstatus($status) ==ServiceCheck::SUCCESS) <BR>　　　{<BR>　　　　$status = ServiceCheck::SUCCESS;<BR>　　　}<BR>　　　$service-＞post_run($status);<BR>　　}<BR>　}<BR>　private function sig_usr1($signal){<BR>　　pcntl_signal(SIGUSR1， array($this， "sig_usr1"));<BR>　　$this-＞log_current_status();<BR>　}<BR>}</TD></TR></TBODY></TABLE></P>  <P><BR>　　这是一个很复杂的类。其构造器读取并分析一个XML文件，创建所有的将被监视的服务，并创建记录它们的日志程序。<BR><BR>　　loop()方法是该类中的主要方法。它设置请求的信号处理器并检查是否能够创建一个新的子进程。现在，如果下一个事件(以next_attempt时间CHUO排序)运行良好，那么一个新的进程将被创建。在这个新的子进程内，发出一个警告以防止测试持续时间超出它的时限，然后执行由run()定义的测试。<BR><BR>　　还存在两个信号处理器：SIGCHLD处理器sig_child()，负责收集已终止的子进程并执行它们的服务的post_run()方法；SIGUSR1处理器sig_usr1()，简单地调用所有已注册的日志程序的log_current_status()方法，这可以用于得到整个系统的当前状态。<BR><BR>　　当然，这个监视架构并不没有做任何实际的事情。但是首先，你需要检查一个服务。下列这个类检查是否你从一个HTTP服务器取回一个"200 Server OK"响应：<BR><BR></P>  <P>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>class HTTP_ServiceCheck extends ServiceCheck{<BR>　public $url;<BR>　public function _ _construct($params){<BR>　　foreach($params as $k =＞ $v) {<BR>　　　$k = "$k";<BR>　　　$this-＞$k = "$v";<BR>　　}<BR>　}<BR>　public function run(){<BR>　　if(is_resource(@fopen($this-＞url， "r"))) {<BR>　　　return ServiceCheck::SUCCESS;<BR>　　}<BR>　　else {<BR>　　　return ServiceCheck::FAILURE;<BR>　　}<BR>　}<BR>}</TD></TR></TBODY></TABLE></P>  <P><BR>　　与你以前构建的框架相比，这个服务极其简单，在此恕不多描述。</P>  <P>&nbsp;</P>  <P><STRONG>五. 示例ServiceLogger进程<BR><BR></STRONG>　　下面是一个示例ServiceLogger进程。当一个服务停用时，它负责把一个电子邮件发送给一个待命人员：<BR><BR>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>class EmailMe_ServiceLogger implements ServiceLogger {<BR>　public function log_service_event(ServiceCheck$service)<BR>　{<BR>　　if($service-＞current_status ==ServiceCheck::FAILURE) {<BR>　　　$message = "Problem with{$service-＞description()} r n";<BR>　　　mail('oncall@example.com'， 'Service Event'，$message);<BR>　　　if($service-＞consecutive_failures() ＞ 5) {<BR>　　　　mail('oncall_backup@example.com'， 'Service Event'， $message);<BR>　　　}<BR>　　}<BR>　}<BR>　public function log_current_status(ServiceCheck$service){<BR>　　return;<BR>　}<BR>}</TD></TR></TBODY></TABLE><BR>　　如果连续失败五次，那么该进程还把一个消息发送到一个备份地址。注意，它并没有实现一个有意义的log_current_status()方法。<BR><BR>　　无论何时象如下这样改变一个服务的状态，你都应该实现一个写向PHP错误日志的ServiceLogger进程：<BR><BR>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>class ErrorLog_ServiceLogger implements ServiceLogger {<BR>　public function log_service_event(ServiceCheck$service)<BR>　{<BR>　　if($service-＞current_status() !==$service-＞previous_status()) {<BR>　　　if($service-＞current_status() ===ServiceCheck::FAILURE) {<BR>　　　　$status = 'DOWN';<BR>　　　}<BR>　　　else {<BR>　　　　$status = 'UP';<BR>　　　}<BR>　　　error_log("{$service-＞description()} changed status to $status");<BR>　　}<BR>　}<BR>　public function log_current_status(ServiceCheck$service)<BR>　{<BR>　　error_log("{$service-＞description()}: $status");<BR>　}<BR>}</TD></TR></TBODY></TABLE><BR>　　该log_current_status()方法意味着，如果进程发送一个SIGUSR1信号，它将把其完整的当前状态复制到你的PHP错误日志中。<BR>　　 <BR>　　该引擎使用如下的一个配置文件：<BR><BR>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>＜config＞<BR>　＜loggers＞<BR>　　＜logger＞<BR>　　　＜id＞errorlog＜/id＞<BR>　　　＜class＞ErrorLog_ServiceLogger＜/class＞<BR>　　＜/logger＞<BR>　　＜logger＞<BR>　　　＜id＞emailme＜/id＞<BR>　　　＜class＞EmailMe_ServiceLogger＜/class＞<BR>　　＜/logger＞<BR>　＜/loggers＞<BR>　＜services＞<BR>　　＜service＞<BR>　　　＜class＞HTTP_ServiceCheck＜/class＞<BR>　　　＜params＞<BR>　　　　＜description＞OmniTI HTTP Check＜/description＞<BR>　　　　＜url＞http://www.omniti.com＜/url＞<BR>　　　　＜timeout＞30＜/timeout＞<BR>　　　　＜frequency＞900＜/frequency＞<BR>　　　＜/params＞<BR>　　　＜loggers＞<BR>　　　　＜logger＞errorlog＜/logger＞<BR>　　　　＜logger＞emailme＜/logger＞<BR>　　　＜/loggers＞<BR>　　＜/service＞<BR>　＜service＞<BR>　＜class＞HTTP_ServiceCheck＜/class＞<BR>　＜params＞<BR>　　＜description＞Home Page HTTP Check＜/description＞<BR>　　＜url＞http://www.schlossnagle.org/~george＜/url＞<BR>　　＜timeout＞30＜/timeout＞<BR>　　＜frequency＞3600＜/frequency＞<BR>　＜/params＞<BR>　＜loggers＞<BR>　　＜logger＞errorlog＜/logger＞<BR>　＜/loggers＞<BR>＜/service＞<BR>＜/services＞<BR>＜/config＞</TD></TR></TBODY></TABLE><BR>　　当传递这个XML文件时，ServiceCheckRunner的构造器对于每一个指定的日志实例化一个日志记录程序。然后，它相应于每一个指定的服务实例化一个ServiceCheck对象。<BR><BR>　　注意 该构造器使用Reflection_Class类来实现该服务和日志类的内在检查-在你试图实例化它们之前。尽管这是不必要的，但是它很好地演示了PHP 5中新的反射（Reflection）API的使用。除了这些类以外，反射API还提供一些类来实现对PHP中几乎任何内部实体(类，方法或函数)的内在检查。<BR><BR>　　为了使用你构建的引擎，你仍然需要一些包装代码。监视程序应该会禁止你试图两次启动它-你不需要对每一个事件建立两份消息。当然，该监视程序还应该接收包括下列选项在内的一些选项：<BR><BR>  <TABLE cellSpacing=0 cellPadding=0 width="90%" align=center border=1>  <TBODY>  <TR>  <TD width="11%">选项</TD>  <TD width="89%">描述</TD></TR>  <TR>  <TD width="11%">[-f]</TD>  <TD width="89%">引擎的配置文件的一个位置，默认是monitor.xml。</TD></TR>  <TR>  <TD width="11%">[-n] </TD>  <TD width="89%">引擎允许的子进程池的大小，默认是5。</TD></TR>  <TR>  <TD width="11%">[-d] </TD>  <TD width="89%">一个停用该引擎的守护功能的标志。在你编写一个把信息输出到stdout或stderr的调试ServiceLogger进程时，这是很有用的。</TD></TR></TBODY></TABLE><BR>　　下面是最终的监视程序脚本，它分析选项，保证排它性并且运行服务检查：<BR><BR>  <TABLE borderColor=#cccccc width="90%" align=center bgColor=#e7e9e9 border=1>  <TBODY>  <TR>  <TD>require_once "Service.inc";<BR>require_once "Console/Getopt.php";<BR>$shortoptions = "n:f:d";<BR>$default_opts = array('n' =＞ 5， 'f' =＞'monitor.xml');<BR>$args = getOptions($default_opts， $shortoptions，null);<BR>$fp = fopen("/tmp/.lockfile"， "a");<BR>if(!$fp || !flock($fp， LOCK_EX | LOCK_NB)) {<BR>　fputs($stderr， "Failed to acquire lock n");<BR>　exit;<BR>}<BR>if(!$args['d']) {<BR>　if(pcntl_fork()) {<BR>　　exit;<BR>　}<BR>　posix_setsid();<BR>　if(pcntl_fork()) {<BR>　　exit;<BR>　}<BR>}<BR>fwrite($fp， getmypid());<BR>fflush($fp);<BR>$engine = new ServiceCheckRunner($args['f']，$args['n']);<BR>$engine-＞loop();</TD></TR></TBODY></TABLE><BR>　　注意，这个示例使用了定制的getOptions()函数。<BR><BR>　　在编写一个适当的配置文件后，你可以按如下方式启动该脚本：<BR><BR>　　＞ ./monitor.php -f /etc/monitor.xml<BR><BR>　　这可以保护并继续监视直到机器被关掉或该脚本被杀死。<BR><BR>　　这个脚本相当复杂，但是仍然存在一些容易改进的地方，这些只好留给读者作为练习之用：<BR><BR>　　· 添加一个重新分析配置文件的SIGHUP处理器以便你能够在不启动服务器的情况下改变配置。<BR><BR>　　· 编写一个能够登录到一个数据库的ServiceLogger以用于存储查询数据。<BR><BR>　　· 编写一个Web前端程序以为整个监视系统提供一种良好的GUI</P>  <P><BR>&nbsp;</P></div>]]></description>
	    <author><![CDATA[ync]]></author>
	    <comments>http://ync.blog.163.com/blog/static/310032006111473247333</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://ync.blog.163.com/blog/static/310032006111473247333</guid>
    <pubDate>Thu, 14 Dec 2006 19:32:47 +0800</pubDate>
    <dcterms:modified>2006-12-14T19:34:30+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[分手信跟回信,不知是哪兩個天才~~]]></title>	
    <link>http://ync.blog.163.com/blog/static/31003200611100382588</link>
    <description><![CDATA[<div><BR><BR>Dear<BR><BR>想向你辭去情人的職務，<BR><BR>任職一年多來，在崗位上我努力學習，克盡職守，<BR><BR>對你噓寒問暖，小心翼翼，揣測你的需要，滿足你各方面需求。<BR><BR>在感情提供你慰藉，讓你有被愛的感覺；<BR><BR>在行動上，等待、接送、陪伴、更只是基本工作。<BR><BR>雖不經手財務，卻要負起所有買單重責；<BR><BR>三不五時還要送禮討你歡心。<BR><BR>一個稱職的情人要溫柔體貼，還要心胸寬闊。<BR><BR>聽你提及對別的男人的大方及讚賞，不可以醋勁大發。<BR><BR>剛任職之時不知如何拿捏，犯了幾次錯誤竟敢與你鬧情緒<BR><BR>幾度你想把我開除，後來在我保證不再犯的前提下，<BR><BR>你勉強再給我觀察期。<BR><BR>這些時日以來，幾經思索，感謝你給我這次機會。<BR><BR>但我確實不適任此職位，想向你申請調回朋友部門。<BR><BR>看你對那部門同仁有說有笑，三不五時還會請他們小聚一番<WBR>，有點羨慕他們：<BR><BR>上班時間彈性，不用隨call隨到，不用接送，<BR><BR>不用買單，不用送禮，不用面對你冷漠一面，<BR><BR>可看到你陽光似的笑容，聽到你幽默言談。<BR><BR>而我雖佔了情人的缺，除了責任加重卻沒任何特殊待遇；<BR><BR>沒有甜言蜜語，沒有多一點關心，沒有禮物，沒有...<BR><BR>決定辭去這職務，至於你是否願讓我調部門，<BR><BR>一切尊重你的裁決.....<BR><BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 一個盡心盡力的員工 &nbsp; 敬上<BR><BR>女生的回覆<BR><BR>Dear<BR><BR>關於您轉調部門的提議，經過董事家長會開會討論，以下決議事項向<WBR>您說明:<BR><BR>因您當初面試時的職務為情人，標準與要求一開始就跟朋友不同，<BR><BR>雖然試用期間你的表現不好差點被開除，<BR><BR>但念在你苦苦哀求且信誓旦旦的說明你可以改進與昇任，才予以留任<WBR>。<BR><BR>情人屬於正職工作，與兼職的朋友部門不同，當然責任與工作相對也<WBR>比較多，<BR><BR>但是薪資及福利保證優於朋友部門，<BR><BR>情人有按摩、親親、抱抱、陪睡、陪同參予家庭聚會與煮宵夜的紅利<WBR>與福利，<BR><BR>還有很好的升遷管道，可以升為老公、爸爸、阿公...等<WBR>，這些絕對都是朋友部門所沒<BR>有的。<BR><BR>最後，因目前朋友部門沒有職缺，情人又是重要職務，<BR><BR>因此在未尋獲新人或職務代理人並完成交接前，<BR><BR>先將您轉調到備胎部門，這個部門的人員不需要每天面對老闆<WBR>，應該可以暫時讓您的<BR>責任跟壓力不那麼大。<BR><BR>等情人職務有人可以交接時，可再將您轉調到地下情人部門，<BR><BR>當然若屆時朋友部門有缺也可轉調到朋友部門，或是您要離職也可以<WBR>，當然自動離職<BR>是沒有遣散費的。<BR><BR>謝謝您一年多來的努力...<BR><BR>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 董事會成員代表敬上<BR></div>]]></description>
	    <author><![CDATA[ync]]></author>
	    <comments>http://ync.blog.163.com/blog/static/31003200611100382588</comments>
    <slash:comments>1</slash:comments>
    <guid isPermaLink="true">http://ync.blog.163.com/blog/static/31003200611100382588</guid>
    <pubDate>Sun, 10 Dec 2006 00:38:02 +0800</pubDate>
    <dcterms:modified>2006-12-10T00:38:02+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[php 一段正则表达式的诡异问题。。]]></title>	
    <link>http://ync.blog.163.com/blog/static/31003200611841616337</link>
    <description><![CDATA[<div><P><FONT face=Verdana size=1>首先说明一下我写这个正则表达式的用途：</FONT></P>  <P><FONT face=Verdana size=1>这个正则表达式是检测一段html代码里面的&lt;img&gt;标签的src属性，如果发现src属性不是一个绝对路径格式的url（即不是</FONT><A href="http://www.xxx.com/xxx.jpg"><FONT face=Verdana size=1>http://www.xxx.com/xxx.jpg</FONT></A><FONT face=Verdana size=1>格式），那么就给他补全。如果已经是这个格式，就抛开不管。</FONT></P>  <P><FONT face=Verdana size=1>我写的表达式如下：</FONT></P>  <P><BR><FONT style="BACKGROUND-COLOR: #800000" face=Verdana color=#ffffff size=1>$srcRegex = '/(src=)([ '|"]?)([^ s '"][^http: / /])([ '|"]?)/i';</FONT></P>  <P><FONT face=Verdana size=1>下面是使用该表达式做补全工作<BR><FONT style="BACKGROUND-COLOR: #800000" color=#ffffff>$replaceMent = ' 1 2'.$bbsRoot.' 3 4';<BR>$src = preg_replace($srcRegex,$replaceMent,$src);</FONT></FONT></P>  <P><FONT style="BACKGROUND-COLOR: #ffffff" face=Verdana color=#ff0000 size=1>可恶，网易博客竟然连 反斜线 都过滤了。。。看图吧</FONT></P>  <P><FONT face=Verdana color=#ff0000 size=1><A href="http://ync.blog.163.com/album/prevPhoto.do?photoId=_fks_29PqZlf0bhx2ynhViDYabQ==" target=_blank><IMG src="http://blog.163.com/photo/SAUAxSd6jYutvxlPex6xBA==/5699023853460748237.jpg"></A></FONT></P>  <P><FONT face=Verdana size=1>实际效果是这样的：</FONT></P>  <P><FONT face=Verdana size=1>对于这样的img： &lt;img src="abc/def.jpg"&gt;</FONT></P>  <P><FONT face=Verdana size=1>可以按照我的目的进行，</FONT></P>  <P><FONT face=Verdana size=1>但是对于这个img：&lt;img src="abc_def/ghi.jpg"&gt;</FONT></P>  <P><FONT face=Verdana size=1>则不行，如果在abc_def前面加上/或者../，即变成&lt;img src="/abc_def/ghi.jpg"&gt;或者&lt;img src="../abc_def/ghi.jpg"&gt;也能按照我的目的进行。。。。。</FONT></P>  <P><FONT face=Verdana size=1></FONT>&nbsp;</P>  <P><FONT face=Verdana size=1>找了半天不知道为啥。如果谁能解决这个问题，请帮俺一下：） 多谢～～</FONT></P></div>]]></description>
	    <author><![CDATA[ync]]></author>
	    <comments>http://ync.blog.163.com/blog/static/31003200611841616337</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://ync.blog.163.com/blog/static/31003200611841616337</guid>
    <pubDate>Fri, 8 Dec 2006 16:16:16 +0800</pubDate>
    <dcterms:modified>2006-12-08T16:49:03+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[2006年最低调变态的精品语录 ]]></title>	
    <link>http://ync.blog.163.com/blog/static/3100320061021695886</link>
    <description><![CDATA[<div><SPAN ><BR>　　 <BR>　　2.小时侯，我家里很穷，没钱买自行车，我只好每天打的上学。初中的时候，因为我成绩太突出，学校领导留我多读了两年。初中毕业后，高中的校长觉得我很有前途，就多收了我三万。高三的时候，班主任认为我已经有独立生存的能力，于是让我退了学。 <BR>　　 <BR>　　3.某鲜花店的广告：今日本店的玫瑰售价最为低廉，甚至可以买几朵送给太太。 　　 <BR><BR>　　4.我和超人的唯一区别是把内裤穿在里面了！　 <BR>　　 <BR>　　5.避孕的效果：不成功，便成“人”。 <BR>　　 <BR>　　6.我不是随便的人！但随便起来就不是人！ <BR>　　 <BR>　　7.虽然你是暴牙！别自悲，暴牙很好！暴牙可以刨地瓜，下雨可以遮下巴，喝茶可以隔茶渣，野餐可以当刀叉，你说暴牙是不是顶呱呱！ <BR>　　 <BR>　　8.家庭顺治、生活康熙、人品雍正、事业乾隆、万事嘉庆、前途道光、财富咸丰、内外同治、千秋光绪、万众宣统！ <BR>　　 <BR>　　9.我是一颗葱，站在风雨中，谁敢拿我沾大酱，X他老祖宗！走过南~闯过北~厕所后面喝过水，火车道上压过腿，还和傻子亲过嘴。上过山、打过虎~少林寺上练过武，左青龙，右白虎，常拿别人当二百五，还拿释迦摩尼喂老虎！金字塔上跳过舞,耶稣头上打过鼓. <BR>　　 <BR>　　10.我身在江湖,江湖却没有关于我的传说!　 <BR>　　 <BR>　　11.关于丁字裤：以前，脱下内裤看屁股；现在，拔开屁股看内裤…… <BR>　　 <BR>　　12.走别人的路,让别人无路可走! <BR>　　 <BR>　　13.我就像一只趴在玻璃上的苍蝇,前途一片光明,而我却找不到出路. <BR>　　 <BR>　　14.浑人落魄江湖行，东西南北分不清。撞到墙角浑不觉，躺在地上数星星! <BR>　　 <BR>　　15.??女人如衣服，兄弟如手足。回想起?，我竟然七手八?的裸奔了19年！ <BR>　　 <BR>　　16.宿舍的弟兄决定对舍友实施以下惩罚：让其抱着贴满老中医广告的电线杆，饱含热泪充满深情的大声呐喊：我的病终于有救了啊！ <BR>　　 <BR>　　17.“什么叫乐观派的人？”“这个……就像茶壶一样，屁股都烧得红红的，他还有心情吹口哨！” <BR>　　 <BR>　　18、你瞧你吧！看背影急煞千军万马；转过头吓退百万雄师。还看什么看,就是说你! <BR>　　 <BR>　　19、男人长的帅有个屁用呀？到银行能用脸刷卡吗？ <BR>　　 <BR>　　20、你唱歌绝对不会把狼引来，真的――你只会把狼吓跑。 <BR><BR>　　21、此人已死、有事烧纸。 <BR><BR>　　22、炮轰的脑袋还梳个雷劈的逢。 <BR>　　 <BR>　　23、我不会讲话，一见人多就结结巴巴，像羊拉屎一样，不合你的胃口请多多包涵。 <BR><BR><BR><BR><BR>1.人的一生就象在拉屎,有时你已经很努力了可出来的只是一个屁. <BR>　　 <BR>　　2.小时侯，我家里很穷，没钱买自行车，我只好每天打的上学。初中的时候，因为我成绩太突出，学校领导留我多读了两年。初中毕业后，高中的校长觉得我很有前途，就多收了我三万。高三的时候，班主任认为我已经有独立生存的能力，于是让我退了学。 <BR>　　 <BR>　　3.某鲜花店的广告：今日本店的玫瑰售价最为低廉，甚至可以买几朵送给太太。 　　 <BR><BR>　　4.我和超人的唯一区别是把内裤穿在里面了！　 <BR>　　 <BR>　　5.避孕的效果：不成功，便成“人”。 <BR>　　 <BR>　　6.我不是随便的人！但随便起来就不是人！ <BR>　　 <BR>　　7.虽然你是暴牙！别自悲，暴牙很好！暴牙可以刨地瓜，下雨可以遮下巴，喝茶可以隔茶渣，野餐可以当刀叉，你说暴牙是不是顶呱呱！ <BR>　　 <BR>　　8.家庭顺治、生活康熙、人品雍正、事业乾隆、万事嘉庆、前途道光、财富咸丰、内外同治、千秋光绪、万众宣统！ <BR>　　 <BR>　　9.我是一颗葱，站在风雨中，谁敢拿我沾大酱，X他老祖宗！走过南~闯过北~厕所后面喝过水，火车道上压过腿，还和傻子亲过嘴。上过山、打过虎~少林寺上练过武，左青龙，右白虎，常拿别人当二百五，还拿释迦摩尼喂老虎！金字塔上跳过舞,耶稣头上打过鼓. <BR>　　 <BR>　　10.我身在江湖,江湖却没有关于我的传说!　 <BR>　　 <BR>　　11.关于丁字裤：以前，脱下内裤看屁股；现在，拔开屁股看内裤…… <BR>　　 <BR>　　12.走别人的路,让别人无路可走! <BR>　　 <BR>　　13.我就像一只趴在玻璃上的苍蝇,前途一片光明,而我却找不到出路. <BR>　　 <BR>　　14.浑人落魄江湖行，东西南北分不清。撞到墙角浑不觉，躺在地上数星星! <BR>　　 <BR>　　15.??女人如衣服，兄弟如手足。回想起?，我竟然七手八?的裸奔了19年！ <BR>　　 <BR>　　16.宿舍的弟兄决定对舍友实施以下惩罚：让其抱着贴满老中医广告的电线杆，饱含热泪充满深情的大声呐喊：我的病终于有救了啊！ <BR>　　 <BR>　　17.“什么叫乐观派的人？”“这个……就像茶壶一样，屁股都烧得红红的，他还有心情吹口哨！” <BR>　　 <BR>　　18、你瞧你吧！看背影急煞千军万马；转过头吓退百万雄师。还看什么看,就是说你! <BR>　　 <BR>　　19、男人长的帅有个屁用呀？到银行能用脸刷卡吗？ <BR>　　 <BR>　　20、你唱歌绝对不会把狼引来，真的――你只会把狼吓跑。 <BR><BR>　　21、此人已死、有事烧纸。 <BR><BR>　　22、炮轰的脑袋还梳个雷劈的逢。 <BR>　　 <BR>　　23、我不会讲话，一见人多就结结巴巴，像羊拉屎一样，不合你的胃口请多多包涵。</SPAN> <BR></div>]]></description>
	    <author><![CDATA[ync]]></author>
	    <comments>http://ync.blog.163.com/blog/static/3100320061021695886</comments>
    <slash:comments>2</slash:comments>
    <guid isPermaLink="true">http://ync.blog.163.com/blog/static/3100320061021695886</guid>
    <pubDate>Tue, 21 Nov 2006 18:09:05 +0800</pubDate>
    <dcterms:modified>2006-11-21T18:09:06+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[广州最好的糖水铺]]></title>	
    <link>http://ync.blog.163.com/blog/static/310032006102092447190</link>
    <description><![CDATA[<div><P>广州人四季喜爱饮糖水。认为经煲制某些药材、豆类、生果、面制食品加上糖而成的糖水，有清润消暑、生津益身之功效。 </P>
<P></P>
<P>糖水品种名目繁多：豆类的有红豆沙、绿豆沙、眉豆沙；糊类的有芝麻糊、杏仁糊、花生糊、凤凰奶糊；药材类的有百合糖水、莲子糖水、清补凉糖水；还有炖蛋、炖木瓜、番薯糖水、麻蓉汤丸、蛋奶、姜汁撞奶、糖西米、豆浆、豆腐花等。 </P>
<P></P>
<P>并非只有文明路的百花甜品店要排队，分布在广州各区的一些著名甜品屋也有同样情况。</P>
<P></P>
<P><B>荔湾区：南信甜品专家</B> </P>
<P>地址：广州第十甫路47号 </P>
<P>价格：3.00元-6.00元 </P>
<P>营业时间：6:00-23:00 </P>
<P></P>
<P><B>仁信牛奶老铺</B> </P>
<P>地址：上九路名汇大厦 </P>
<P>价格：4.00元-10.00元 </P>
<P>营业时间：10:00-23:30 </P>
<P></P>
<P><B>天河区：杏花楼</B> </P>
<P>地址：体育西路 </P>
<P>价格：8元-12元 </P>
<P></P>
<P><B>东山区：清爽甜品店</B> </P>
<P></P>
<P>德政中路 </P>
<P></P>
<P><B>海珠区：汤丸王</B> </P>
<P>地址：江南西路41号 </P>
<P>价格：3.00元-6.00元 </P>
<P>营业时间：7:30-1:00 </P>
<P></P>
<P><B>越秀区：百花甜品</B> </P>
<P>地址：文明路201号 </P>
<P>价格：2.50元-5.50元 </P>
<P>营业时间：8:00-1:00 </P>
<P></P>
<P><B>芳村区：永记沙湾甜品 </B></P>
<P>东漖北路合兴苑99号之七 </P>
<P>价格：1.00元-5.00元 </P>
<P>营业时间：6:00-凌晨1:00 </P>
<P></P>
<P><B>番禺区：沁芳园</B> </P>
<P>地址：番禺区沙湾镇南村大巷涌戏院对面（总店） </P>
<P>价格：1.50元-8.00元 </P>
<P>营业时间：9:30-凌晨1:00 </P>
<P></P>
<P><B>白云区：开记甜品店</B> </P>
<P>地址：景泰直街41号（八分店）芳村明心路128号（二分店） </P>
<P>营业时间：6:00-凌晨2:30 </P>
<P>价格：2.5元-5元 </P>
<P></P>
<P><B>糖水之最</B> </P>
<P></P>
<P>价钱最贵： 燕窝雪蛤糖水68元到300元 </P>
<P>最有特色： 姜撞奶 </P>
<P>最为经典： 蕃薯糖水 </P>
<P>最受欢迎： 香芋西米露 </P></div>]]></description>
	    <author><![CDATA[ync]]></author>
	    <comments>http://ync.blog.163.com/blog/static/310032006102092447190</comments>
    <slash:comments>1</slash:comments>
    <guid isPermaLink="true">http://ync.blog.163.com/blog/static/310032006102092447190</guid>
    <pubDate>Mon, 20 Nov 2006 21:24:47 +0800</pubDate>
    <dcterms:modified>2006-11-20T21:24:47+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[最近在研究JAVASCRIPT 呵呵]]></title>	
    <link>http://ync.blog.163.com/blog/static/310032006101511959564</link>
    <description><![CDATA[<div><P>&nbsp;&nbsp;&nbsp; 从接触写代码开始,就一直对CSS和JAVASCRIPT有不小的兴趣,但是也就是从那时候开始,到现在,都没有认证研究过.前不久辞职了,最近又帮以前朋友做个网站,其中需要做一个下拉菜单,突然就引发了我研究JAVASCRIPT的兴趣:)</P>
<P>&nbsp;</P>
<P>&nbsp;&nbsp; 于是干脆一不做二不休,在网上down了一本 javascript - The Definive Guide , 5th Edition 下来研究.</P>
<P>&nbsp;</P>
<P>&nbsp;&nbsp; 今天看到了prototype 和 object部分.做点心得记录:) 以后的日子,如果有可能,我会将写程序当成我的爱好,而不是我吃饭的工具.所以这里也就当是我的一段历程吧.希望我真能如愿以偿,将写程序当成爱好来做.</P>
<P>&nbsp;</P>
<P>&nbsp;&nbsp;&nbsp;prototype是干吗的？看个例子</P>
<P>&nbsp;</P>
<P>&nbsp; function Rectangle(w, h) {<BR>&nbsp;&nbsp;&nbsp; this.width = w;<BR>&nbsp;&nbsp;&nbsp; this.height = h;<BR>&nbsp;&nbsp;&nbsp; this.area = function( ) { return this.width * this.height; }<BR>&nbsp; }</P>
<P>&nbsp; 这里定义了一个 Rectangle 类。调用的语法如下：</P>
<P>&nbsp; // How big is a sheet of U.S. Letter paper in square inches?<BR>&nbsp; var r = new Rectangle(8.5, 11);<BR>&nbsp; var a = r.area( );</P>
<P>&nbsp;</P>
<P>&nbsp; 这个是一般的面向对象语言里的做法，比如java。但是在javascript里面不推荐这样做。原因如下：</P>
<P>&nbsp; 这个Rectangle类，定义了3个属性、方法 width , height , area 。每次new一个Rectangle的时候，都要为这3个属性开辟内存空间，特别是其中的area属性(这里可以看成是一个属性，虽然他实际上是一个方法) ，对于每个Rectangle都是一样的（都是调用function () {return this.width*this.height;}函数)，所以，没有必要为每个Rectangle都new一个area属性。可以将这个属性存在一个公共的地方，供所有Rectangle都来调用他。那么这个公共地方就是prototype。</P>
<P>&nbsp; 呵呵，不知道这样说清楚没有。。。。暂且就这样吧，等我从整体上明白javascript的架构之后，再来修改这里。或者请达人们指点一下：）</P>
<P></P>
<P>&nbsp; 为了存放这些常量，或者是共享的方法，javascript为每个类都自动继承了prototype属性（至于是怎么继承的，从哪里继承的我还没弄清楚。。。如果有机会研究javascript的源代码，或者是能得到达人指点，将是一件不错的事情）。而且，可以将类的共享方法或者常量存放在这里。这样，任何一个类的实例，都会继承这些方法或常量。</P>
<P>&nbsp;</P>
<P>&nbsp; 尝试下面一段代码，可以说明这个问题。</P>
<P>&nbsp; // The constructor function initializes those properties that<BR>&nbsp; // will be different for each instance.<BR>&nbsp; function Rectangle(w, h) {<BR>&nbsp;&nbsp;&nbsp; this.width = w;<BR>&nbsp;&nbsp;&nbsp; this.height = h;<BR>&nbsp; }<BR><BR>&nbsp; // The prototype object holds methods and other properties that<BR>&nbsp; // should be shared by each instance.<BR>&nbsp; Rectangle.prototype.area = function( ) { return this.width * this.height; }</P>
<P>&nbsp; var r = new Rectangle(2, 3);<BR>&nbsp; document.write(r.hasOwnProperty("width"));&nbsp;&nbsp; // true: width is a direct property of r<BR>&nbsp; document.write(r.hasOwnProperty("area"));&nbsp;&nbsp;&nbsp; // false: area is an inherited property of r<BR>&nbsp; document.write("area" in r);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // true: "area" is a property of r<BR>&nbsp; </P>
<P>&nbsp;&nbsp; 另外，javascript执行的时候，是这样一个过程</P>
<P>&nbsp;</P>
<P>&nbsp;&nbsp; 当你调用一个对象o的p方法时(即o.p()时)，javascript解析器首先会在类里面寻找p方法，如果找到了，则执行这个方法，如果没找到，则会将请求发送给这个对象所在类，在该类的prototype里面寻找p方法。如果找到了，则执行之。e文原文如下：</P>
<P>&nbsp;</P>
<P>&nbsp;&nbsp; When you read property <TT>p</TT> of an object <TT>o</TT>, JavaScript first checks to see if <TT>o</TT> has a property named <TT>p</TT>. If it does not, it next checks to see if the prototype object of <TT>o</TT> has a property named <TT>p</TT>. This is what makes prototype-based inheritance work.</P>
<P>&nbsp;</P>
<P>&nbsp;&nbsp; 这是调用、读取对象属性时的执行过程。但是在写对象属性，改变对象方法的时候。这个过程就不同了。</P>
<P>&nbsp;&nbsp; </P>
<P>&nbsp;&nbsp; 如果你想改变对象o的属性p的值，而这时o里面没有p属性，那么请求并不会向上传递给prototype，而是解析器会给你直接在o对象里面创建一个新的p属性。而此时如果刚刚好，你的对象的prototype也有一个p属性的话，那么这个新的p属性会覆盖prototype的p属性。这时如果执行读取操作，会直接返回o.p的值。为什么呢？因为prototype里面的咚咚是归所有类的实例共享的。如果某个实例拥有改变prototype里面属性的权力的话，会影响到其他的实例。从而发生混乱。。。</P>
<P>&nbsp;</P>
<P>&nbsp;&nbsp; e文原文如下：</P>
<P>&nbsp;</P>
<P>&nbsp;&nbsp;&nbsp; </P>
<P><TT property the of value set to try you suppose did: it if happen would what consider why, see To object. prototype use not does JavaScript hand, other on property, a write>o.p</TT> when the object <TT>o</TT> does not have a property named <TT>p</TT>. Further suppose that JavaScript goes ahead and looks up the property <TT>p</TT> in the prototype object of <TT>o</TT> and allows you to set the property of the prototype. Now you have changed the value of <TT>p</TT> for a whole class of objectsnot at all what you intended.</P>
<P><TT property the set you not write If them. when values, read only occurs inheritance>p</TT> in an object <TT>o</TT> that inherits that property from its prototype, what happens is that you create a new property <TT>p</TT> directly in <TT>o</TT>. Now that <TT>o</TT> has its own property named <TT>p</TT>, it no longer inherits the value of <TT>p</TT> from its prototype. When you read the value of <TT>p</TT>, JavaScript first looks at the properties of <TT>o</TT>. Since it finds <TT>p</TT> defined in <TT>o</TT>, it doesn't need to search the prototype object and never finds the value of <TT>p</TT> defined there. We sometimes say that the property <TT>p</TT> in <TT>o</TT> "shadows" or "hides" the property <TT>p</TT> in the prototype object. Prototype inheritance can be a confusing topic. <A href="mk:@MSITStore:D:\ace\javascipt5@chinahtml\OReilly.JavaScript.The.Definitive.Guide.5th.Edition.Aug.2006.chm::/0596101996/jscript5-CHP-9-SECT-2.html#jscript5-CHP-9-FIG-1">Figure 9-1</A> illustrates the concepts discussed here.</P>
<P></P>
<P>&nbsp;</P>
<P>&nbsp;&nbsp; 最后：</P>
<P>&nbsp;</P>
<P>&nbsp;&nbsp; </P>Because prototype properties are shared by all objects of a class, it generally makes sense to use them to define only properties that are the same for all objects within the class. This makes prototypes ideal for defining methods. Other properties with constant values (such as mathematical constants) are also suitable for definition with prototype properties. If your class defines a property with a very commonly used default value, you might define this property and its default value in a prototype object. Then, the few objects that want to deviate from the default value can create their own private, unshared copies of the property and define their own nondefault values. </div>]]></description>
	    <author><![CDATA[ync]]></author>
	    <comments>http://ync.blog.163.com/blog/static/310032006101511959564</comments>
    <slash:comments>1</slash:comments>
    <guid isPermaLink="true">http://ync.blog.163.com/blog/static/310032006101511959564</guid>
    <pubDate>Wed, 15 Nov 2006 01:19:59 +0800</pubDate>
    <dcterms:modified>2006-11-15T01:23:39+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[世界名牌手表系列排名 比较老的资料.]]></title>	
    <link>http://ync.blog.163.com/blog/static/310032006101435427753</link>
    <description><![CDATA[<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在如今手机替代手表的年代，男人们的品性也是日趋同质化了，不想做流行产品的代言人，就来研究一下世界名表的文化吧，也许某一天，从你口道出来的名表差异，就象可以品出名酒的不同，才属于真正的名流。<BR>　　<BR>　　世界名牌手表系列排名(虽然有点旧)<BR>　　<BR>　　百达斐丽（Patek Philippe - PP）、<BR>　　<BR>　　江诗丹顿（Vaucheron Constaint - VC）、<BR>　　<BR>　　爱彼（Audermars Piguet - AP）、<BR>　　<BR>　　积家（Jaeger Le-Coultre - JLC）、<BR>　　<BR>　　宝玑（Breguet - BG）、<BR>　　<BR>　　宝珀（Blancpain）<BR>　　<BR>　　万国（International Watch Company - IWC）、<BR>　　<BR>　　劳力士（Rolex）<BR>　　<BR>　　伯爵（Piaget － PG）、<BR>　　<BR>　　卡地亚（Cartier）、<BR>　　<BR>　　当然，这也只是一家之言，关于世界名表的争论从来就没有停止过。<BR>　　<BR>　　第一名，当然是百达斐丽，英文缩写就是PP。勿庸置疑是全世界公认最好的品牌，号称“手表中的蓝血贵族”。PP不以复杂的机芯或者华丽的外观见长，甚至在其男装表的外壳上很少镶嵌任何钻石或者宝石，但是它始终坚持自制机芯，限量生产，天生就具有一种儒雅内敛的贵族气质。所以，PP不是有钱就可以佩戴的，那些戴着黄澄澄的金戒指和金项链、经常出入桑拿和卡拉OK的“土财主”根本不配拥有PP。佩戴者应当是有一定的气质和风度，谈吐文雅，具有“贵族气”的成功人士才可以佩戴。PP对与大号的戒指、手链和项链等珠宝具有“免疫力”，把这些东东和PP放在一起总是不协调的，所以在戴PP时应当避免再佩戴这些俗气的东西。PP的价位都在人民币10万元以上，作为入门级的3919也得11万左右。<BR><BR>　　第二名，江诗丹顿，VC。它好就好在机芯和外壳工艺极为出色，而且一贯限量生产，特别是VC的Malte款的镂空表，简直就是一件艺术品！<BR>　　　　<BR>　　第三名，爱彼，AP。一贯以高调的姿态出现，最经典的款式是“皇家橡树”(Royal Oak),特点是规则的八角形表壳，八个角上分别有八颗装饰性的螺丝，显得非常粗犷，极有男性气息。AP的价位较高，一般只在亨得利或者英皇珠宝有售，“皇家橡树”有一款不锈钢的男装表售价7.8万元；其全18K黄金加表盘镶钻的售价达45万余元。当然，还有更规的，谁叫AP是经典中的经典呢，连世界最著名的动作片巨星阿诺德.施瓦辛格都是AP最忠实的拥趸，他在其主演的影片《终结者3》中佩戴的正是在AP特别定做的新款腕表。<BR>　　　<BR>　　第四名，本人认为应属积家，JLC。JLC以纯机械机芯制造著称于世，甚至其它的著名品牌也用过它的机芯。JLC的101机芯是世界上最小的纯机械机芯，用它做出来的女士珠宝腕表甚至曾经是英国女王伊丽莎白二世在自己加冕庆典上的穿戴。<BR>　　　　<BR>　　第五名，宝玑，BG。号称“表王”，主要是因为其创始人路易.宝玑先生有着太多的关于腕表的第一次发明，比如创世纪的陀飞轮（Tourbillon）和“宝玑指针”等等。所有款式均用18K黄金以上的贵金属制造外壳，以鳄鱼皮表带为主，而且表盘通常以镀银处理，非常漂亮。只是有一点点的遗憾，就是外形款式有点儿保守，大多为圆形表盘，缺乏变化。但是，无论如何都是世界级的名表！<BR>　　　　<BR>　　第六名，宝珀（Blancpain），缩写是JB。这个牌子让本人推崇恐怕会招致一大批“表行家”们的臭骂，因为伯爵都没有上榜呢，而大家都很喜欢伯爵嘛!嘿嘿！其实宝珀有它的不足，就是它的外观几乎没有变化，一直只生产圆形表壳的手表，而且以皮带表居多，显得过于保守、传统，似乎和时尚根本挂不上勾。但是，宝珀却是仅有的几个从来都只生产机械表而没有石英电子表的品牌，宝珀的口号就是“只做机械表”。要知道，即使是积家这样的品牌都不曾免俗呐！宝珀还是现存历史最久的、最古老的腕表品牌，建于1735年。而现在在用于市场销售的腕表中，宝珀特别设计制造的款式－“1735”以636万元人民币的价格傲立当世，这款表穷极了制表大师们的智慧，据称当世只有3到5位大师可以制造类似复杂功能的腕表，要买到它除了有超级富豪的家底之外，还得提前至少3年预订才可以，也就是说不是一般的大富豪就可以买得到的。<BR>　　　　<BR>　　第七名，万国，IWC。这有点私心的成分，只因为万国的口号就是“只做男人的腕表”，嘿嘿！美眉们可千万别说俺“大男子主义”哦。万国虽由美国工程师琼斯（Jones）创立，但是却是百分之百的纯正瑞士血统。因为它的工厂就设在瑞士的沙斐豪森小城。万国的机芯品质没的说，外形设计更是具有自己的特色。首先是以圆形表壳为主，其次是大表盘，乍一看很普通，其实朴实中见功夫，风格非常适合男士佩戴，特别是IT业或者其他从事工程方面的男士佩戴。它的经典款式如达芬奇（Da Vinci）、葡萄牙（Portuguese）和波涛斐诺（Portofino）都是非常具有个性的腕表，不张扬却极有气派。<BR>　　　　<BR>　　第八名，劳力士。许多暴发户非常喜欢它。其实，一个腕表为社会各阶层人士认知和欢迎也不是它自己的错呀。但是，如果说机芯的品质和耐用可靠，劳力士无疑是最出色的，简直可以当成传家之物留给子子孙孙。虽然劳力士几乎从来都不制造复杂功能的腕表，但是它的经久耐用、走时精准却是出了名的，而且一直是二手表市场里的宠儿，保值功能极佳。<BR>　　　　<BR>　　第九名，伯爵。若单以价格而言，伯爵绝对是前3名的，不过，本人之所以不太看得上它，是因为它的高价格主要是靠运用了大量的钻石和宝石镶嵌，以及市场运作（还不如叫炒作更好）所造成的。伯爵自己不擅长做机芯，通常用别家的机芯，但是在外壳设计和用料上却特别下功夫、舍本钱。<BR>　　　　<BR>　　第十名，卡地亚。前10名里唯一非瑞士品牌，虽然创自法国，但是工厂却在瑞士，而且用瑞士顶级的机芯。没什么更多可说的，卡地亚被以前的英国威尔士亲王成为“国王的珠宝商，珠宝商中的国王”，以皇室珠宝起家的路易.卡地亚先生在1904年把他的好友－法裔巴西巨商山度士.杜蒙的请求变成了世界上第一款最成功的腕表“山度士”（Santos），于是卡地亚奠定了今日世界著名腕表品牌的地位......2004年卡地亚为纪念“山度士”表问世100周年发行了“山度士100”和“山度士－杜蒙”（超薄）黄金/不锈钢款腕表。另外还有灵感得于第一次世界大战时美军坦克的“坦克”（Tank）还有卡地亚的另一杰作－帕夏，据说源于上世纪30年代一位摩洛哥王国的地方大员，他的官衔是“帕夏”，在北非柏柏尔语的意思是“总督”，因为他酷爱游泳，所以他请求卡地亚专门为其制造一款防水性能极佳的腕表，于是“帕夏”就问世了......卡地亚的价位差别也很大，最便宜的是“坦克”（Tank）的不锈钢款，3万元左右；贵的几十万不等。<BR>　　　　<BR>　　第十一名，芝珀，GP。瑞士传统品牌，既恪守传统品质，又不乏创新，最经典的是其“法拉利”，结合了赛车与腕表的优良品质于一身，完美的结合。价格也不低，通常在5万元以上，但在二手市场上表现就一般了，价差较大。本人见过一块18K黄金男装腕表，可能款式老了些，才卖人民币8,000元！呵呵！<BR>　　　　<BR>　　第十二名，毫不犹豫，当属雅典（Ulysse Nardin）。说心里话，本人觉得这样的翻译实在巧妙，可能来自香港人。这个牌子的创始人Ulysse Nardin27岁就有了自己的制表作坊，而它一向以生产航海表著称。雅典的腕表以功能复杂，样式变化多端见长，最经典的一款叫“成吉思汗三问表”，每当闹时之时，表盘上的类似浮雕的蒙古骑士（也许就是成吉思汗的形象吧）会“纵马驰骋”，活灵活现，做工非常精细，体现了雅典表精湛的工艺水平。<BR>　　　　<BR>　　第十三名，朗格（A. Lange Soehn）。少见的非瑞士品牌，它是地道的东部德国产品，曾经因前东德的专制统治而消失过，但两德统一后再度焕发青春。朗格坚持只做机械贵金属腕表，使得它的品质和价位都据高不下，一般均在10万元以上，而且国内一般商场买不到。<BR>　　<BR>　　第十四名，真利时（Zenith）。瑞士品牌，以复杂功能时计著称，多用贵金属作外壳，皮带表居多，是比较传统的腕表，品质一流。<BR>　　　　<BR>　　第十五名，肖邦（Chopard），瑞士品牌，以女装钻石表著称，特别是“快乐钻石”（Happy Diamond），是窈窕淑女的最爱。窃以为其实际佩戴效果要好于满是珠光宝气的伯爵......哎呀，又挨了一块板儿砖！<BR>　　　　<BR>　　第十六名，沛纳海（Panerai）。意大利品牌，总部位于佛落伦萨，生产厂却在瑞士。纳海的专业潜水表了，防水深度均在300米以下，一直就是包括意大利海军在内的许多国家军队专用潜水表。最近几年才刚刚面向民用市场，通过拍卖老款军用潜水表而大造声势，加盟瑞士著名的奢侈品集团历峰集团（Richmont）更是其明智之举。沛纳海在外形上比较保守，很少变化，但它强调了防水性能和结实耐用的特性，此外其调校柄头处采用了独有专利技术的设计，用一个带鹅颈形拉杆的护圈盖住柄头，防止水压过高导致水流从柄头处渗入表芯，确实非常独到，是沛纳海的标志性设计。<BR>　　　　<BR>　　第十七名，名士（Baume &amp; Mercier）。瑞士品牌，以儒和典雅著称，其汉普顿（Hampton）系列和里维埃拉（Riviera）系列都是经典款式，价位一般在数万元至十几、几十万元不等。<BR>　　　　<BR>　　独立制表人发展的品牌倒更有兴趣，一来这种腕表数量有限，弥足珍贵；二来它凝聚了独特的个性风格和技术，非常具有收藏价值。<BR>　　　　<BR>　　1. 弗兰克.穆勒（Franck Mueller － FM）。最近几年炒得最火爆的个性品牌，一切都源于这位大师独具个性的设计、制作。夸张、拉长的酒桶形外壳和各种色彩的鳄鱼皮表带是其招牌性的设计，而其“疯狂时间（Crazy Hours）”系列的独特设计更是开创了腕表设计的先河。在“疯狂时间”的表盘上，延续传统几百年的1到12点的时间刻度被完全打乱，腕表的指针以跳时的方式指示时间。这种看似疯狂的表盘实际上凝聚了大师超人的智慧和超前的设计理念，充满了超人的智慧。英超联赛“红魔”曼联队的当红前锋鲁尼在去年生日时就收到其女朋友送的生日礼物－一块价值1.5万英镑的弗兰克.穆勒腕表。<BR>　　　　<BR>　　2. 帕玛强尼（Parmigiani Fleuier － PF）。这位大师据说原为百达斐丽的著名设计师，后来在百达斐丽之下开始制造自己名字的品牌腕表。帕玛强尼也多采用酒桶形外壳，但其形状较为偏矩形一些，而且无论表盘还是外壳边缘均采用雕花式的处理方法，工艺非常精湛。它所使用的机芯是无可挑剔的，品质绝对一流，而且多采用贵重金属制作，所以价格不菲，一般甚至比百达斐丽还贵，而且许多是限量生产的。<BR>　　<BR>　　3. 豪爵（Roger Dubuis － RD）。以生长贵重金属外壳、复杂功能机芯著称的腕表。一直数量稀少，是拍卖会上的焦点。价格同样高的令人瞠目。<BR>　　　　<BR>　　4. 尊达（Gerald Genta － GG）。提起这个品牌也许许多国人并不熟悉，而如果提到大师70年代为爱彼（Audermars Piquet）设计制作的“皇家橡树（Royal Oak）”也许不少人是耳熟能详的。90年代初，尊达建立了自己的独立品牌，经过15年的努力，已成为国际超一流的个人腕表品牌。2004年，尊达为纪念品牌建立15周年，推出了Octo Line系列复杂功能腕表，仍然采用其独特的“双椭圆形”外壳设计，制作了陀飞轮、陀飞轮万年历以及8天超级动力储存等不同风格的名贵腕表，均采用名贵金属如黄金、白金、玫瑰金和钽金属等制造，体现了一种超凡脱俗的贵族气质和上乘品味。<BR>　　<BR>　　5. 丹尼诺夫（Daniel Roth － DR）。同样是一位国际顶级的腕表大师，制作复杂功能的名贵腕表，其外形设计与尊达颇有些类似，采用“双椭圆形”设计，同样的稀少和名贵。<BR>　　<BR>　　6. 斐力德夫（Philippe Defour － PD）。毋庸多言，又一位世界级的大师自己的品牌，数量稀少、价格昂贵。　<BR>　　<BR>　　7. NHC。以其品牌人兼制作人卡巴莱斯的全名缩写命名，其最独到的创造就是在表盘设计上首先采用了指针设计，也就是舍弃了传统的各种指针，用表面上圆盘的小窗格的转动指示时间，并且采用了跳时设计，还是一句评价－数量稀少、价格昂贵。<BR>　　<BR>　　8. 矫大羽（Kiu Tai Yuk）。全世界华人的骄傲，这位出生于中国江苏省苏州市一个普通工人家庭的制表大师从小就充满了天赋和智慧，80年代初移居香港后逐渐从事钟表销售和收藏领域，并且自己独立制作复杂功能的腕表，其制作的属于第三代陀飞轮的“神行天仪飞轮”腕表成为永恒的经典，并成为全亚洲第一位也是迄今为止唯一一位同时获得瑞士官方和美国官方双认证的腕表独立制作大师。大师每年毕毫其一年的功力制作仅一块复杂功能腕表，足见其珍贵难得！虽然大师的作品为世界各地收藏家所追逐，但大师本人却坚持作品非卖。大师唯一的一块被拍卖的腕表竟拍得80万港币的天价！大师的成功充分证明了大师本人一直坚持的信念－钟表是中国人首先发明的，中国人一样能够做出世界上最复杂、最先进和最名贵的时计来！<BR>　　　　<BR>　　其它有特色的名表<BR>　　<BR>　　1. 欧米茄（OMEGA）。是目前在中国大陆最红火的瑞士腕表了。主要靠的是比较悠久的历史、可靠的品质和大力的市场推广、宣传。欧米茄早期的产品还是非常出色的，它也是最早进入中国大陆的国外腕表品牌。其最辉煌的时期无疑是60、70年代，作为第一块随航天员进入太空的腕表，欧米茄一时名声大噪，在全球范围内确立了其“第一航天腕表”的地位，而且欧米茄还是最早和最出色的天文台表。在欧美，高价表就是高价做、高价卖，低价表就是为了满足工薪阶层而制作的，如果价差巨大反而会有“两头不讨好”的结果，可是，在中国大陆，无论是爆发的富豪还是普通老百姓，对欧米茄都趋之若骛......<BR>　　　<BR>　　2. 浪琴（LONGINES）。以柔和儒雅为风格的瑞士品牌。客观地说，浪琴是比较适合一般白领阶层的腕表，不张扬但是非常有风度，连已故的美国影坛巨星奥黛丽.赫本和亨弗里.鲍嘉都是它的代言人了。尤其是浪琴的超薄腕表，非常细腻、贴身，价格也不贵，一般在6、7千元左右。它的“舰队（FLEET）”系列也很不错，特别是玫瑰金加鳄鱼皮表带的款式，颇有豪华腕表的风范，售价也只不过约3万元左右，很值得购买。<BR>　　<BR>　　3. 豪雅（TAG HEUER）。是瑞士运动腕表的先锋品牌，品质一流，而且领导运动表的潮流。无论是机芯水准还是外观设计都很不错，价格属于中上，如果以运动表来定位则绝对算高的了。<BR>　　<BR>　　4. 天梭（TISSOT）。是从一个家庭小作坊起家的瑞士著名品牌。TISSOT家族父子两代人只为了打发冬季农闲的时光而建立的这个小作坊今天已经发展成世界著名的腕表生产商了，真让人感到瑞士的钟表奇迹确实很神奇！天梭被欧洲人认为是非常适合白领阶层佩戴的腕表，外观精美、设计新颖，而且价格很便宜。天梭一般只做低廉材质的腕表，只是前几年出过一款18K黄金的方形腕表，售价也只有2万多元，而一般的也就1、2千元搞定了。还有一款叫“T-TOUCH”的，非常独特，采用触摸式表盘，体现了天梭先进的现代科技，当然，这块表是石英机芯的......<BR>　　<BR>　　5. 梅花（TITONI）。也是一个家族式企业，建立于1919年瑞士的格林肯小镇。梅花一向以朴实无华但精密可靠的品质闻名，是性能价格比最出色的瑞士腕表。个人见解，窃以为如果讲腕表的档次或者收藏的价值，至少最基本的先决条件就是纯粹完全的机械机芯，石英机芯腕表不存在档次的问题，戴坏了就算了，也别指望它能保值甚至升值。梅花是一个非常坚持自身独立传统的腕表厂商，虽然其实力无法与江诗丹顿、伯爵、欧米茄这些大厂商相比，但是却至今仍坚持着自己独立制表商的阵地！<BR>　　<BR>　　6. 众多其它品牌，如英纳格（ENICAR）、罗马（ROAMER）、雷蒙威（RAYMONDWEIL）等等，没什么更多可说的，只是腕表而已，既无突出的缺点，也没什么可以夸赞的。<BR>　　　<BR>　　 还有一些也不错。当然可以记不得，但要知道：<BR>　　<BR>　　1. 格拉苏蒂（GLASHUTTE ORIGINAL - GO）。与朗格（A. LANGE &amp; SOEHN）一样，都产自德国东部靠近马格德堡的格拉苏蒂小镇。这两个品牌均代表着德国制表行业的最高水准，也让世人知晓不是只有瑞士人才会制造高品质的时计的。GO制表的路线和朗格基本相同，即只做机械表，但是略有差异的是，GO不只做贵重金属外壳腕表，也做不锈钢外壳的产品，因此某些款式的价格相对较为便宜一些，但是大多数也在数万元以上。<BR>　　<BR>　　2. 尊皇（JUVENIA）。以女式珠宝腕表见长，设计比较新颖、富有创意，善于运用大量的钻石和宝石，基本上不太适合男士......呵呵！不过，本人见过一款尊皇特别制作的“陀飞轮”（TOURBILLON）男装腕表，18K黄金表壳、镂空式设计、黑色鳄鱼皮带，非常漂亮，不过价格不菲，而且镂空表只适于收藏，不太适于日常佩戴。<BR>　　<BR>　　3. 君皇（CONCORD）。很不张扬的瑞士名表，以制作贵重金属腕表为主，市场策略比较传统，但是品质却一流，而且外观设计很漂亮，本人曾经见过一款玫瑰金黑色鳄鱼皮带的君皇，真的非常PP！其价格也比较高亢，与GO等品牌差不多，而且不是大多数商场见得着的。<BR>　　<BR>　　4. 波威（BOVET）。古老的瑞士品牌，曾经是晚清王公贵人们的宠儿，那时是以其怀表著称的。有很多年了，大概将近大半个世纪，波威在中国大陆消失，直到去年才又杀回中国市场。波威有一个非常独到的设计，就是它的调校柄头不像其它所有腕表那样设置在表盘的两侧，而是放在表盘12点上方正中的位置，也就是上表耳的位置上，这样乍一看是一只腕表，可是其柄头的设计却取自怀表的设计方式。此外，波威的表面经常运用比较古典的设计，比如运用非常弥足珍贵的珐琅面、珍珠母贝面或者云母面，时间刻度也采用复古设计，比如运用中国古代12时辰汉字标示等等，体现了一种复古典雅的气质。波威的价格非常昂贵，甚至超过了大多数高档腕表，一般在十几万元以上，上百万元的也很正常。<BR>　　<BR>　　5. 帝后（DELNEAU）。一个在国内非常非常不知名的品牌，本人了解也不多。但是，据说这个牌子从不批量生产，也从来不在任何商业机构售卖，而是只接受客户量身定做的订货方式，而且其客户非富即贵，大多是欧洲、亚洲的王室成员或者超级富豪。帝后根据客户个人的要求，专门为客户设计款式，并按照客户的喜好和需求在外壳上镶嵌不同的钻石和各种宝石，每年的产量不过数百至千余块，可见是非同一般的品牌。<BR>　　<BR>　　6. 宝茄丽（BULGARI）。其实是一个著名的珠宝品牌，后来改做腕表，把其擅长的珠宝镶嵌那一套东东放到外壳制作上来，不高档也得高档啊，呵呵！<BR>　　<BR>　　7. 宝齐莱（BUCHERER）。和BULGARI的情况大同小异，总之不是原来就做腕表的，属于半路出家者。本人在某大商场的腕表柜台见过它的几款玫瑰金皮带表，真的非常漂亮诱人，价位一般在7、8万元以上。<BR>　　<BR>　　8. 蒂芬妮（TIFFANY）。世界著名的珠宝商品牌，后来进入了腕表市场，本身的价位还不算太离谱，数万元以上吧，不过世界第一名表百达斐丽为它特别制作的限量表“百达斐丽－蒂芬妮”（PATEK PHILIPPE.TIFFANY）却价值不菲，玫瑰金款要20几万元搞定！<BR>　　<BR>　　9. 万宝龙（MONTBLANC）。原本是世界著名的钢笔制造商，最经典的就是“大班”钢笔和“皇家波希米亚”系列镶钻宝石钢笔了。大约7、8年前开始涉足腕表制造，并加盟了奢侈品巨头历峰集团。本身这个牌子是德国的，但是其腕表厂却设在瑞士，因此它的手表也是SWISS MADE。万宝龙的“时光行者”（TIME WALKER）系列非常不错，价位一般在1、2万元左右，比较适合事业有成的白领阶层人士。<BR>　　<BR>　　10. 登喜路（DUNHILL）。英国著名的男士服装品牌，还兼做皮具、打火机和烟草等男士用品，后来也加入了腕表制造商的行列。一切得益于它出色的英国设计师TOM BOLT，这位土生土长的伦敦人从小就喜欢赛车和腕表，他把对赛车的狂热融入到腕表设计中去，为登喜路设计了许多非常新颖独特的腕表。<BR>　　<BR>　　 如果有人提到以下款式，也不要没有听说过。<BR>　　<BR>　　1. 豪利时（Oris）。瑞士老牌表厂，以生长运动表见长，最近的杰作之一是著名的F1车王迈克尔.舒马赫的弟弟拉尔夫.舒马赫的F1纪念表。此外，豪利时也制作一些高档贵重金属材质的复杂功能腕表。<BR>　　<BR>　　2. 艾美（Maurice Lacroix － ML）。一个新兴的品牌，最近几年才在腕表界大放异彩，2002年曾被瑞士某专业杂志评为世界第一品牌名表，甚至在大名鼎鼎的百达斐丽之前。它没有悠久的历史和传统，没有显赫的家族声誉，但是却有着先进的技术和时尚的设计。最具有杀伤力的是它的价位，最便宜的六、七千元人<BR>　　民币就搞定，贵一点的也只不过数万元而已。但是，其品质和使用的材料却绝非等闲，而且款式非常新颖、漂亮。台湾著名的“情歌王子”张信哲－阿哲（他是我最喜欢的歌手之一）是艾美的形象代言人。<BR>　　<BR>　　3. .杜彼－萧登（Dubbey &amp; Schaldenbrand）。瑞士的老牌表厂，纯手工制作，得益于其“拯救者”－瑞士著名的机芯收藏家辛妮特女士。辛妮特女士在60、70年代日本电子表风行全球之际，从当时惨淡经营的一些瑞士传统手工表厂收购了一大批传统机芯，并在机械表复兴之时以全新的外壳设计再度推出，大获成功。其酒桶形的外观已成为标志性形状。价位在2万元以上，但大多在10万上下。<BR>　　<BR>　　4. 依波路（E.Borel）。瑞士老牌。一向以低调行事，不事张扬。最近曾经推出酒桶形鳄鱼皮带的玫瑰金纪念表，价位一般在数万元之间。<BR>　　<BR>　　5. 瑞士时计（Chronoswiss）。传统的瑞士品牌，最突出的是其超大的表冠柄头和复杂的时计功能。<BR>　　<BR>　　6. 玉宝（Ebel）。珠宝品牌，兼做腕表，客户针对女性群体，以手势腕表著称。<BR>　　<BR>　　7. 雅盖卓时（Jaquet Droz）。以大师名字命名的古老的传统时计品牌，不仅制作腕表，其时钟亦为难得一见的精品。是收藏界的珍品，拍卖会的焦点。<BR>　　<BR>　　8. 百年灵（Breitling）。是航空腕表的领航人，是美国空军的宠儿，当然它是纯粹的瑞士血统。价位在万元以上，倒也没有太过奢侈的名贵表款。<BR>　　<BR>　　9. 汉密尔顿（Hamilton）。腕表领域里少见的非瑞士、非欧洲品牌，地道的美国货。虽然没有瑞士腕表那么大的名气，而且价位也偏低，但是历史却不短，而且品质一流。<BR>　　<BR>　　10. 富利时（Fortis）。和欧米茄相似，同为航天表中之先驱，所不同的是，欧米茄是航天员在太空舱里佩戴的；而富利时是前苏联宇航员在太空里佩戴过的 </div>]]></description>
	    <author><![CDATA[ync]]></author>
	    <comments>http://ync.blog.163.com/blog/static/310032006101435427753</comments>
    <slash:comments>8</slash:comments>
    <guid isPermaLink="true">http://ync.blog.163.com/blog/static/310032006101435427753</guid>
    <pubDate>Tue, 14 Nov 2006 15:54:27 +0800</pubDate>
    <dcterms:modified>2006-11-16T15:41:07+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[劳力士（ROLEX）]]></title>	
    <link>http://ync.blog.163.com/blog/static/310032006101433122243</link>
    <description><![CDATA[<div><P style="LINE-HEIGHT: 150%"><FONT size=1>&nbsp;&nbsp;&nbsp; 汉斯·怀斯道夫1881年出生在德国的一座城市。1905年，他和一个姓戴维斯的英国人合伙在伦敦创办了“怀斯道夫与戴维公司”，开始经营钟表业务。1908年7月2日，怀斯道夫在瑞士册了劳力士（ROLEX）商标。世界钟表业从此多了一个奢侈品牌，并出现了一次又一次里程碑式的创新。 </FONT>
</P><P style="LINE-HEIGHT: 150%"><FONT size=1>&nbsp;&nbsp;&nbsp; 1914年，劳力士的一款腕表获得英国乔治天文台颁发的A级证书，这是权威天文台对钟表精确度的最高级别认可。这一殊荣使得劳力士身价倍增，此后数十年，劳力士成为了“精确”的代名词。 </FONT>
</P><P style="LINE-HEIGHT: 150%"><FONT size=1>&nbsp;&nbsp;&nbsp; 第一次世界大战结束后的1926年，劳力士推出了世界上第一只防水防尘表。1927年，一位英国女游泳运动员戴着这种防水表横渡英吉利海峡。在水中整整浸泡了15个小时后，那只劳力士表仍旧分秒不差，运转如常。当时，这件事被英国媒体称为“制表技术最伟大的胜利”。劳力士由此奠定了在手表防水技术上的领先地位。 </FONT>
</P><P style="LINE-HEIGHT: 150%"><FONT size=1>&nbsp;&nbsp;&nbsp; 1929年的经济危机打击了瑞士，但劳力士却没受影响。它在这一时期发明了一种自动上链的机制，造出了后来风靡一时的“恒动”表。给钟表业带来了一场革命。这种自动表的中轴有一个摆铊，能把手腕摆动的轻微动作转换为手表的动力，因而无需人工上链。这在当时被公认为最精确可靠的手表自动上链技术。1945年劳力士推出全球首只可以自动转换日期的手表，1956年推出了具备星期显示功能的日历表。 </FONT>
</P><P style="LINE-HEIGHT: 150%"><FONT size=1>&nbsp;&nbsp;&nbsp; 劳力士手表一向以专业功能见长，因此深得全世界专业人士的推崇。1955年劳力士发明飞行员手表，以便人们在不同时区测量精确的时间。同年，劳力士为深海潜水员研制的潜水表问世，其防水深度达到100米。 </FONT>
</P><P style="LINE-HEIGHT: 150%"><FONT size=1>&nbsp;&nbsp;&nbsp; 目前，劳力士专业手表主要有以下几类：探险家型（EXPLORER)，附带24小时红色辅助针，以方便探险爱好者辨别日夜。潜航者型（SUBMARINER），防水深度超过300米。游艇名士型（YACHT　MASTER），配有可旋转外圈，方便计算时差。格林尼治型（GMT　MASTER），其可转动外圈及24小时指针，不仅同时显示两个时区时间，更可将时针独立移动至另一时区，而毋须移动分针及秒针。宇宙计型（COSMOGRAPH），为一款多功能手表，能满足工程、运动及商业等多种需要。 </FONT>
</P><P style="LINE-HEIGHT: 150%"><FONT size=1>&nbsp;&nbsp;&nbsp; 劳力士最初使用的标志是一只五指伸开的手掌，寓意其产品完全靠手工精制，后来逐渐演变为现在人们所熟知的皇冠，展现着劳力士在制表业的帝王之气。在国际市场上，一只普通劳力士手表的价位从1000美元到15000美元不等。虽然价格不菲，但人们还是认为物有所值。这不仅由于劳力士的品质精良，而且因为它具有独特的投资价值。劳力士古董表的“抗跌”能力极强，2002年在日内瓦举行的一次拍卖会上，一只越南末代皇帝保大戴过的1952年款劳力士万年历金表，曾以34.2万瑞士法郎（当时约合23.54万美元）天价拍出。 </FONT>
</P><P style="LINE-HEIGHT: 150%"><FONT size=1>&nbsp;&nbsp;&nbsp; 在上世纪的机械表时代，劳力士一直是全球手表业的领头羊。时至今日，超卓的工艺与技术依旧使得劳力士保持着手表业的翘楚地位。目前，劳力士在全球20多个大城市设有分公司，年产量达到约80万只，销售额稳居瑞士钟表业龙头地位。</FONT></P></div>]]></description>
	    <author><![CDATA[ync]]></author>
	    <comments>http://ync.blog.163.com/blog/static/310032006101433122243</comments>
    <slash:comments>4</slash:comments>
    <guid isPermaLink="true">http://ync.blog.163.com/blog/static/310032006101433122243</guid>
    <pubDate>Tue, 14 Nov 2006 15:31:22 +0800</pubDate>
    <dcterms:modified>2006-11-14T15:31:22+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[document.body 和 document.documentElement]]></title>	
    <link>http://ync.blog.163.com/blog/static/310032006101101214954</link>
    <description><![CDATA[<div><P>用document.body.scrollTop，在声明&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "<A href="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><FONT size=2>http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd</FONT></A>"&gt;<BR>&lt;html xmlns="<A href="http://www.w3.org/1999/xhtml"><FONT size=2>http://www.w3.org/1999/xhtml</FONT></A>"&gt;时会失效，总显示为0 </P>
<P></P>
<P>使用document.documentElement.scrollTop，才会获得正确的值。</P>
<P>相反，如果不做声明的话，document.documentElement.scrollTop反而会显示为0。</P>
<P></P>
<P><FONT style="BACKGROUND-COLOR: #ffffcc">&lt;body style="border:10px solid red"&gt;&lt;br /&gt;<BR>&lt;input type=button value=test 滚动条高度为:"+document.body.scrollHeight+"\r页面边界高度为:"+document.body.offsetHeight+"\r滚动的偏移量为(距上边界)"+document.body.scrollTop)&gt;&lt;p&gt;&lt;br /&gt;<BR>&lt;img height=1000 width=1&gt;&lt;br /&gt;<BR>&lt;/body&gt;</FONT></P>
<P>顺便再存一下这个图吧，总是挺难记清楚</P>
<P><IMG style="DISPLAY: block; MARGIN: 0px auto 10px; TEXT-ALIGN: center" alt=10e85a15ddb.jpg src="http://img93.pp.sohu.com/images/blog/2006/9/28/10/11/10e85a15ddb.jpg" border=0></P></div>]]></description>
	    <author><![CDATA[ync]]></author>
	    <comments>http://ync.blog.163.com/blog/static/310032006101101214954</comments>
    <slash:comments>0</slash:comments>
    <guid isPermaLink="true">http://ync.blog.163.com/blog/static/310032006101101214954</guid>
    <pubDate>Sat, 11 Nov 2006 00:12:14 +0800</pubDate>
    <dcterms:modified>2006-11-11T00:21:13+08:00</dcterms:modified>
  </item>    
  <item>
  	<title><![CDATA[CSS 以前没弄清楚的一些东西:)]]></title>	
    <link>http://ync.blog.163.com/blog/static/31003200610411927329</link>
    <description><![CDATA[<div><H3>3.定义字体</H3>
<P>　　web标准推荐如下字体定义方法：</P><SPAN SPAN }>&lt; 宋体,sans-serif; Helvetica, Arial, Lucida, Verdana, Grande?, ?Lucida : font-family {&gt; 
<UL>
<LI>字体按照所列出的顺序选用。如果用户的计算机含有Lucida Grande字体，文档将被指定为Lucida Grande。没有的话，就被指定为Verdana字体，如果也没有Verdana，就指定为Lucida字体，依此类推，； 
</LI><LI>Lucida Grande字体适合Mac OS X； 
</LI><LI>Verdana字体适合所有的Windows系统； 
</LI><LI>Lucida适合UNIX用户 
</LI><LI>"宋体"适合中文简体用户; 
</LI><LI>如果所列出的字体都不能用，则默认的sans-serif字体能保证调用; </LI></UL>
<H3>4.群选择器</H3>
<P>　　当几个元素样式属性一样时，可以共同调用一个声明，元素之间用逗号分隔，：<SPAN SPAN }>&lt; : { ; 12px font-size li td, p,&gt; </SPAN></P>
<H3>5.派生选择器</H3>
<P>　　可以使用派生选择器给一个元素里的子元素定义样式，例如这样：</P>
<P><SPAN SPAN : {>&lt; normal；} font-weight italic; font-style strong&gt;</SPAN></P>
<P>　　就是给li下面的子元素strong定义一个斜体不加粗的样式。</P>
<H3>6.id选择器</H3>
<P>　　用CSS布局主要用层"div"来实现，而div的样式通过"id选择器"来定义。例如我们首先定义一个层</P>
<P><SPAN SPAN div&gt;>&lt; &gt;&lt;&gt;</SPAN></P>
<P>　　然后在样式表里这样定义：</P>
<P><SPAN SPAN #666;}>&lt; #FEFEFE;COLOR: 0px;BACKGROUND: {MARGIN:&gt;</SPAN></P>
<P>　　其中"menubar"是你自己定义的id名称。注意在前面加"#"号。</P>
<P>　　id选择器也同样支持派生，例如：</P>
<P><SPAN SPAN }>&lt; : { 10px; margin-top right; text-align p&gt;</SPAN></P>
<P>　　这个方法主要用来定义层和那些比较复杂，有多个派生的元素。</P>
<H3>6.类别选择器</H3>
<P>　　在CSS里用一个点开头表示类别选择器定义，例如：</P>
<P><SPAN SPAN : ;}>&lt; ;font-size:14px #f60 {color&gt;</SPAN></P>
<P>　　在页面中，用class="类别名"的方法调用：</P>
<P><SPAN SPAN span&gt;>&lt; &gt;14px大小的字体&lt;&gt;</SPAN></P>
<P>　　这个方法比较简单灵活，可以随时根据页面需要新建和删除。</P>
<P>&nbsp;</P>
<H3>7.定义链接的样式</H3>
<P>　　CSS中用四个伪类来定义链接的样式，分别是：a:link、a:visited、a:hover和a : active，例如：</P>
<P><SPAN : ;}><BR #c00 ;color none ;text-decoration bold>a:visited {font-weight : bold ;text-decoration : none ;color : #c30 ;}<BR>a:hover {font-weight : bold ;text-decoration : underline ;color : #f60 ;}<BR>a:active {font-weight : bold ;text-decoration : none ;color : #F90 ;} </SPAN></P>
<P>　　以上语句分别定义了"链接、已访问过的链接、鼠标停在上方时、点下鼠标时"的样式。注意，必须按以上顺序写，否则显示可能和你预想的不一样。记住它们的顺序是“LVHA”。</P>
<P>&nbsp;</P>
<H3>
</H3><H3>&nbsp;</H3></H3></SPAN>


<H3>3.定义字体</H3>
<P>　　web标准推荐如下字体定义方法：</P><SPAN SPAN }>&lt; 宋体,sans-serif; Helvetica, Arial, Lucida, Verdana, Grande?, ?Lucida : font-family {&gt; 
<UL>
<LI>字体按照所列出的顺序选用。如果用户的计算机含有Lucida Grande字体，文档将被指定为Lucida Grande。没有的话，就被指定为Verdana字体，如果也没有Verdana，就指定为Lucida字体，依此类推，； 
</LI><LI>Lucida Grande字体适合Mac OS X； 
</LI><LI>Verdana字体适合所有的Windows系统； 
</LI><LI>Lucida适合UNIX用户 
</LI><LI>"宋体"适合中文简体用户; 
</LI><LI>如果所列出的字体都不能用，则默认的sans-serif字体能保证调用; </LI></UL>
<H3>4.群选择器</H3>
<P>　　当几个元素样式属性一样时，可以共同调用一个声明，元素之间用逗号分隔，：<SPAN SPAN }>&lt; : { ; 12px font-size li td, p,&gt; </SPAN></P>
<H3>5.派生选择器</H3>
<P>　　可以使用派生选择器给一个元素里的子元素定义样式，例如这样：</P>
<P><SPAN SPAN : {>&lt; normal；} font-weight italic; font-style strong&gt;</SPAN></P>
<P>　　就是给li下面的子元素strong定义一个斜体不加粗的样式。</P>
<H3>6.id选择器</H3>
<P>　　用CSS布局主要用层"div"来实现，而div的样式通过"id选择器"来定义。例如我们首先定义一个层</P>
<P><SPAN SPAN div&gt;>&lt; &gt;&lt;&gt;</SPAN></P>
<P>　　然后在样式表里这样定义：</P>
<P><SPAN SPAN #666;}>&lt; #FEFEFE;COLOR: 0px;BACKGROUND: {MARGIN:&gt;</SPAN></P>
<P>　　其中"menubar"是你自己定义的id名称。注意在前面加"#"号。</P>
<P>　　id选择器也同样支持派生，例如：</P>
<P><SPAN SPAN }>&lt; : { 10px; margin-top right; text-align p&gt;</SPAN></P>
<P>　　这个方法主要用来定义层和那些比较复杂，有多个派生的元素。</P>
<H3>6.类别选择器</H3>
<P>　　在CSS里用一个点开头表示类别选择器定义，例如：</P>
<P><SPAN SPAN : ;}>&lt; ;font-size:14px #f60 {color&gt;</SPAN></P>
<P>　　在页面中，用class="类别名"的方法调用：</P>
<P><SPAN SPAN span&gt;>&lt; &gt;14px大小的字体&lt;&gt;</SPAN></P>
<P>　　这个方法比较简单灵活，可以随时根据页面需要新建和删除。</P>
<P>&nbsp;</P>
<H3>7.定义链接的样式</H3>
<P>　　CSS中用四个伪类来定义链接的样式，分别是：a:link、a:visited、a:hover和a : active，例如：</P>
<P><SPAN : ;}><BR #c00 ;color none ;text-decoration bold>a:visited {font-weight : bold ;text-decoration : none ;color : #c30 ;}<BR>a:hover {font-weight : bold ;te