第1 页 共8页12345»...末页 »

November 18th, 2008你喜欢写程序吗?

你喜欢写程序吗?我问过同行很多次,但是还没有碰到过哪个人干脆的回答:我喜欢。相反,说不喜欢的却有很多人。我有个大学同学说:我不喜欢计算机,不喜欢写程序,是爸妈让我来学计算机的。有的同行说:没办法,在大学学了这个专业,所以就做这一行了,其实我不喜欢写程序。我得到的最多的答案是:程序员工资高呀,我才不喜欢写程序,如果我有其他方式挣钱,我就不做程序员了。我知道我接触到的这些人是这个行业的极小部分,我期望剩下的那绝大部分中能有很多人会喜欢写程序,否则,我们这个国家的软件行业就永远没有出头之日。我们这个国家的程序员中不缺少梦想一夜暴富的投机者,也不缺少沽名钓誉的学术骗子,更不缺少为求生计混日子的人,但我们非常缺少充满激情热爱写程序的人。

不能选择自己的生活是可怜的,为了点钱把每天三分之一的时间用来做自己不喜欢做的是事是可悲的。如果你是个程序员,却并不能再程序代码中找到快乐,我劝你还是做些别的吧,你的人生不应该在这里。

而我要自豪的说,我热爱我的行业,我喜欢让指尖在键盘上跳动,让思维在代码间流动,让创造力在CPU的脉动中体现。

Share/Save/Bookmark

September 26th, 2008数据迁移经验

做关系型数据库数据迁移的时候,为了加快速度,要注意以下几点。

充分利用数据库的能力

关系型数据库被设计成善于做查找,比较,排序等操作。在大数据量的时候,重新写个程序去对数据做查找排序等,效率往往比不过数据库。所以在数据迁移的时 候,应该尽量将此类操作交给数据库来完成。另外数据库往往都有自己的一些工具,比如导入导出工具,如果你的迁移过程要做类似的工作,也应当交给数据库来完 成。假如你要取出数据库里的一些数据,将格式做些转换,再插入到另一个数据库。你可以写个程序读一条,转换一条,写一条,但是这样很慢,还不如把数据导出 成csv等文件,然后再对文本处理生成新的另一个数据库的导入文件,然后再用另一个数据库的导入工具导入。我曾经做过这样的工作,将数据从sql server 2000迁移到 mysql,要对数据做些简单的格式转换,前一种方案用时40分钟,而后一种只要一分钟。

减少IO操作

现代计算机的CPU,总线和内存的速度都远超过各种IO的速度,所以减少IO操作就可以大幅提升数据迁移时的速度。使用连接池重复使用连接,减少新建连接 的次数可以减少IO操作。使用缓存将可能会被多次查询的数据缓存起来,减少查询数据库次数,可以显著减少IO操作。将中间结果缓存到内存或临时表中,非常 有用。最近在工作中遇到的数据迁移,通过大量的应用内存缓存,成功的将数据迁移时间有原来的近一周缩短到一个小时。

注意索引

也许你在做数据迁移时的很多查询操作是平时用不到的,所以并没有适合于做迁移查询的索引,那么你一定要记得在迁移前加上它。同样,需要被插入数据的表的索引还是先删掉吧,迁移完后再加上。

经常维护数据

不完整的数据,在迁移过程中是最让人头痛的。平时经常清理数据中的垃圾,如果垃圾成山了,数据迁移将是恶梦。

Share/Save/Bookmark

在jboss下,如果包含ejb的jar,和要通过local接口访问ejb的war不被打包成一个ear来部署,会遇到问题。如果你的war中包含了ejb3的local接口的class,那么war在通过jndi取得ejb的引用试图将其转化成接口类型时会抛ClassCastException。而如果war中不包含local接口的class,则会抛class not found的异常。这都是由讨厌的classloader问题导致的。每个放到jboss的deploy目录里的部署单元都有自己的独立的classloader树,这两棵树在jvm的classloader里是平级的。如果war和ejb jar里都包含了某个ejb的local接口的class时,那么同一个类就分别存在于两棵classloader树中。通过jndi取得的引用的类型是ejb jar中的local接口的类型,将其转化成war里的那个local接口类型时就出错了,因为它们不是同一个类。而classloader是不能访问同级的其他的classloader下的类的,所以如果war里不包含接口的class,有会因找不到class而出错。

这种时候就是使用ear的时候,位于同一个ear里ejb jar的classloader是war的classloader的父classloader。这样,只需要部署一份接口类,war也能访问到它,因为子classloader能访问父classloader载入的类。

Share/Save/Bookmark

当你用jsf的<h:selectOneMenu />之类的控件选择实体时,小心你的实体的equals方法,否则你可能就会遇到”value is not valid”的验证错误。比如,如果你的页面里有这样一段:

<h:selectOneMenu value="#{fooAction.foo}">
    <s:selectItems value="#{fooList.resultList}" var="foo" label="#{foo.name}"/>
    <s:convertEntity />
</h:selectOneMenu>

你的Foo实体类的equals方法又是这样写的:

public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    final Foo other = (Area) obj;
    if (id == null) {
        if (other.id != null)
            return false;
    } else if (!id.equals(other.id))
        return false;
    return true;
}

很好,你很可能就有机会遭遇seam下这个神奇的value is not valid验证问题了。到底原因何在?原因就在于seam不仅使用了jsf还使用了hibernate,而你的equals方法没有考虑到被对比的双方可 能一个是实体类,另一个可能是被hibernate动态增强过的类。JSF在客户端提交表单后,会验证客户端选中的元素是否是当初服务端给他的那些元素。 所以,JSF会拿经converter得到的实体与当初的集合里的实体一一调用equals方法对比,如果找不到一个在集合中的实体与提交来的一样,就报 错。如果集合里的对象是hibernate 延迟加载时的一个stub,那正常的对象和这个stub对比时就可能出错。对于上面的例子,getClass() != obj.getClass() 会为真,而 other.id != null 也可能为真。怎么办?改写equals方法,如下:

public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (!getClass().isAssignableFrom(obj.getClass()))
        return false;
    final Area other = (Area) obj;
    if (id == null) {
        if (other.getId() != null)
            return false;
    } else if (!id.equals(other.getId()))
        return false;
    return true;
}

isAssignableFrom方法对子类调用时一样为真。other.getId()时,则会初始化stub,取出id的值。

还有一种更简单的方法,那就是不要让用户选择实体,而是选择实体的id,那就没这个问题了。

Share/Save/Bookmark

InfoQ是一个很不错的技术网站,内容不是很多,但是都很精。前两天头看到InfoQ的Qclub要在杭州和支付宝联合搞一次活动。主讲人是支付宝的首席架构师程立。抱着讨教经验的想法,我们决定参加这次活动。

活动在7月26日下午在杭州支付宝的一个会议室内举行。来得人不多,只有五十来人,但是气氛非常好。最重头的,也是此行的目的就是要听程立介绍关于支付宝的架构和如何实现SOA。听了之后觉得不虚此行,非常有借鉴意义。

从程立的表述来看,SOA不是空洞的哲学,而是实在的准则。支付宝的面向服务不仅体现在企业信息系统内部,也体现在每一个企业应用。他把一个支付宝的企业系统的发展分为三个阶段。

第一个阶段他们以少数的人,从做应用的角度来做支付宝。早先他们选用spring来做中间的业务层,将业务层再细分为很多层次,这些层次的功能都由 spring bean来提供。后来,spring beans的数量太多,达到数千个,不仅难以管理,也难以使用。尽管开发者可以完全遵循分层的规则把beans分成一组组的,但是由于系统上并没有提供杜 绝开发人员自由调用bean的能力,还是会发生成有些开发人员把层次搞乱的事情。所以在应用级别上,他们提出把beans组成组件,让组件提供服务,把不 能被直接调用的beans隐藏起来。在应用级别上,这也是SOA的一种思想。他们最终采用了OSGI来做为组件基础。

第二个阶段,就是做企业级的平台。一个企业可能有很多的业务模块,一个业务流程可能就要很多的业务模块参与进去。运用SOA的方式,就是把各个相对独立的 业务模块以服务的方式暴露出去,再用ESB来把所有的服务集成起来供上层的企业应用使用,在一个企业之内实现各个业务模块之间的SOA。

第三个阶段,是做开放的面向行业的平台。为了和其他的企业和作,为了给培养整个行业生态圈,最终支付宝走向了开放。这个时候,支付宝以REST或WS方式将支付宝的服务暴露出去。

如果以这三个阶段来评估我现在公司的状况的话,我们正处在第一个阶段,还有很长的路要走。

支付宝的SOA实践并非是死板的照抄SOA标准做法,其中最引人注目的就是他们对事务的处理。如果完全按照WS-Transaction的方式来做,性能 达不到需求,他们就根据业务需要自定义了一套事务管理机制。一个业务流程里的事务原则上来说要满足ACID原则,但是实际中可以根据业务功能的重要度,把 某些功能做成不满足ACID只要满足BaSE就可以。这里的BASE的英文描述我记不得了,意思就是在满足基本业务可用的条件下,在某些业务流程上放宽对 隔离性和一致性的要求,实现最终一致性。如果把满足ACID的叫刚性事务,那么BaSE就是柔性事务。支付宝做到可以通过配置指定一个流程中哪些服务时要 在刚性事务中的,哪些是柔性事务的。估计这个要深入研究事务,才能实现这样的功能。

讨论的时候,还有人提到支付宝如何处理有状态服务在分布式环境下一致性问题,结果程立给出的答案是,支付宝的服务没有状态。看来REST里的服务端无状态原则在SOA中也非常有用,可以简化服务。

这次活动很有收获,看到支付宝在SOA上面的成功,给了我们信心。

Share/Save/Bookmark

如果说软件开发有什么真理的话,我想,那一定就是SOC(Separation of concerns,中文翻译叫关注点分离)。SOC原则,就是在软件开发中,通过各种手段,将问题的各个关注点分开。我已经记不得第一次在什么时候什么地方听说这一原则的,当时看一下就忘掉了。可是随着对软件开发的体会的加深,SOC这个概念不断的在我的脑海中浮现,以致于我把它当作软件开发的真理!

问题太过于复杂,要解决问题需要关注的点太多,而程序员的能力是有限的,不能同时关注于问题的各个方面。正如程序员的记忆力相对于计算机知识来说那么有限一样,程序员解决问题的能力相对于要解决的问题的复杂性也是一样的非常有限。计算机知识太多而且不断进化,计算机程序也太复杂,而且还在不断的复杂化。记得有一本记算机图书中,用这样一个例子来对比程序和传统行业复杂性的差别有多大,说一架精密的波音客机,所有的部件加在一起,总共只有2万个,而GCC编译器,光全局变量就有40万之多,可见程序有多复杂。另一方面,人类的注意力所能同时关注的点又是相当的少的。举个简单的例子,一般人很难同时左右手分别划圆划方,就是因为我们的大脑很难同时关注于两只手,让两只手分别做自己的事。因此,做为普通人的程序员面对这种复杂性时,必须采用某些方法把问题分解成若干部分,这样程序员可以同一时刻只关注于问题的某些方面或部分,如果分解后的部分还是太复杂,那就再划分下去,直到使复杂问题变成一个个的简单问题。这就是关注点分离原则。这一准则,并不是计算机界的发明,只不过在计算机界显得更加的重要。

实现关注点分离的方法主要有两种,一种是标准化,另一种是抽象与包装。

标准化就是制定一套标准,让使用者都遵守它,将人们的行为统一起来,这样使用标准的人就不用担心别人会有很多种不同的实现,使自己的程序不能和别人的配合。Java EE就是一个标准的大集合。如果所有的应用服务器的开发者和应用的开发者都按照标准来做,那么应用开发者就不用关心不同的应用服务器有什么差别,服务器的开发者也不用担心应用开发者开发的应用有什么差别。每个开发都只需要关注于标准本身和他所在做的事情就行了。就像是开发镙丝钉的人只专注于开发镙丝钉就行了,而不用关注镙帽是怎么生产的,反正镙帽和镙丝钉按标来就一定能合得上。也就是因为标准具有这样的威力,所有计算机界有很多标准。

不断地把程序的某些部分抽像差包装起来,也是实现关注点分离的好方法。一旦一个函数被抽像出来并实现了,那么使用函数的人就不用关心这个函数是如何实现的,同样的,一旦一个类被抽像并实现了,类的使用者也不用再关注于这个类的内部是如何实现的。诸如组件,分层,面向服务,等等这些概念都是在不同的层次上做抽像和包装,以使得使用者不用关心它的内部实现细节。

每一个程序员都应当理解SOC,并在实践中遵循这一真理。当你在编程的过程中,一时搞不清程序的每一个细节,你可以只关注于主干,把程序的主干写出来,再逐一关注没个分支。这是一种自上而下的方法。如果主干也搞不清,那可以先关注于分支,写出分支,再不断地组合这些分支成为主干,这是一种自下而上的方法。时刻考虑着,是不是要把这一段程序抽像成一个方法,或者类,是不是那样会更好。如果不这样去想去做,要么面对问题无从下手,写不出什么来,要么只会写出面条似的拖沓冗长的代码。不会用SOC,摆在面前的永远是复杂得不能解决的问题。

Share/Save/Bookmark

July 23rd, 2008不读不是好程序员

在大学的时候开始学编程,做程序员这行当也不过三年,但是多少还是有一些对这个行当的感想。我想,如果说我比和我同时起步的同行们在这一行当做得要好一些的话,那就是因为我读过的计算机的资料在数量和质量上要比别人多一些。要想做程序员这一行当,一定要多读资料。

日常的软件开发任务,很少是重复的,因为需求和软件技术都是在不断的变化。这个行业不能像传统行业那样,一旦找到了解决问题的好办法,就可以如何炮制一千遍。比方说,木匠学会做一种椅子,那么以后他再做同样的椅子,只要严格按照之前成功的方式来做就行了。人们对软件的需求和对椅子的需求要多样化得多。而用来解决问题的软件技术,也在不断的推陈出新,飞速地变化。一个程序员,无论他的记忆力多么好,也不可能记得下所有软件开发工具的使用方法,所有程序库的API,所有标准协议的细节,等等。一个程序员,总是要面对自己的未知领域,所以当面对未知时,最快捷的方式,就是直接读书,读文档,学习前人的经验。

然而,可供我们读的资料的质量,也是参差不齐,不加选择的读,不仅进步得慢,还有可能会读到错语的信息。有一类书,一定要读,就是计算机领域里的哲学一样的书,它们研讨的是这个行当里可能再过数十年也不会过时的学问。在这里我严重推荐《代码大全》,非常的棒。你可以找到很多教习具体技术的书,却很少有专注于编码这门技术本身的书,而它就是其中之一,而且是相当的优秀的。还有一类资料,也是一定要读的,就算不能完全理解,不能读得完,但是寻找到自己感兴趣的看一看,也会让你受益匪浅,比如HTTP协议的RFC等。众多的网络编程书藉都会说到GET POST的差别,说GET时参数放到地址栏中,POST的时参数不会出现在地址栏中,但是却不会告诉你到底这些参数被放到了什么地方,等等。研读这些行业的经典资料,虽然乏味,却大有裨益!再有一类,就是那些具体技术本身的文档资料,在使用到的时候,也是要读的。比如, spring的自带的手册,非常的出色,比很多的入门资料写得都要好。不仅介绍了spring本身的东西,还会简单明了的介绍诸如AOP, 事务,等相关和知识。看到论坛上很多人发贴和spring hibernate等相关的问题,我就会想,他们一定没有读过这些软件的自带的手册。如果一个程序员所读的东西,都是别人在论坛里的只言片语,那永远都没有机会系统地认识技术,快速成长。

英语阅读能力影响程序员能力。唉,我也不愿下这样的结论,但是目前的情况来看,这个地球上的大部分的计算机技术资料确实都是英文的。如果不提升英语能力,想在这个行业赶到世界的水来,永远不可能。

我还会在这个行业做下去,所以,我还得读。

Share/Save/Bookmark

2.6版本的wordpress出现有好久了,一直等c-panel里的那个fantasito什么的出现可以升级wordpress的链接,可是至今还没有出现。昨晚终于忍不住要手动升级了。吸引我去升级wordpress的原因很简单,因为听说它支持google gears了!太棒了,可以离线写blog 了吗? 花了那么久才装好,但是发现,我错了,原来wordpress 2.6只是用google gears来减少后台下载文件,根本不能离线编辑,很失望。加速不是我想要的,能够自由的离线编辑和同步才是重要的。唉,不知道下一个版本会不会有这样的功能。

Share/Save/Bookmark

July 17th, 2008在seam中使用spring

选择seam并不代表要放弃spring, 两者并不互斥,相反,可以很好的协作。seam对spring提供了很好的兼容性。那么在seam里如何使用spring里的代码呢?

POJO代码的重用

正如spring管理的bean是POJO一样,seam管理的组件,也是POJO的,而且连ejb3也是POJO的,所以直接的重用以前用在 spring里的代码的方法,就是直接重用POJO了。以前我们就applicationContext.xml来配置bean,现在只需要换一个语法就 能把spring的POJO bean变成seam的component。例如,对于spring的bean:

<bean id=”testBean” class=”org.test.TestBean”>
<property name=”stringProperty” value=”this is a string” />
<property name=”intProperty” value=”3″ />
<property name=”anotherBean” ref=”anotherBean” />
</bean>

对应到seam里就是:

<component name=”testBean” class=”org.test.TestBean”>
<property name=”stringProperty”>this is a string</property>
<property name=”intProperty”>3</property>
<property name=”anotherBean”>#{anotherBean}</property>
</component>

大部分的POJO可能这就可以搞定了。但是要注意:
假如这个POJO依赖于spring容器,比如它实现了spring的bean生命周期回调方法,类似于  afterPropertiesSet() , 那么你也得让seam去模仿spring容器,在适应的时候,去调用这些回调方法。比如:

public class TestBeanAdapter extends TestBean {
@Create
public void afterPropertiesSet() {
super.afterPropertiesSet();
}
}


通JSF EL Resolver来桥接

只要实现了EL Resolver, 并在faces-config.xml里注册它,那么在JSF里使用EL表达式时,就会自动地调用EL Resolver来寻找这个EL表达式对应的对象等。seam当然实现了它自己的Resolver,而spring也实了这个Resolver,如果把它 们都注册上,那么JSF EL 将变成seam与spring的一座桥梁。用下面代码注册spring EL Resolver:

<faces-config>
<application>         
<el-resolver>
org.springframework.web.jsf.el.SpringBeanFacesELResolver 
</el-resolver>
</application>
</faces-config>

如果你定义了spring bean testBean, 那么在seam组件里,你就可以通过 @In(”#{testBean}”) 来注入spring的bean。但是要记住,这种方法获得的对象,完全是由spring负责组装的地地道道的spring的bean, 所以它不具有seam component具有功能,比如双向注入,和seam的上下文完美一体,延长的持久化上下文(extended persistence context)。

seam里的spring

最完美的方案,我想你也想到了,就是让seam来管理spring容器,并加入seam的增强功能。这是可以做得到的,并且已经做到了,感谢spring的灵活性,和seam开发者们的努力。像下面那样在conponents.xml里加入spring名称空间:

<components xmlns=”http://jboss.com/products/seam/components”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:spring=”http://jboss.com/products/seam/spring”
xsi:schemaLocation=”
http://jboss.com/products/seam/components
http://jboss.com/products/seam/components-2.0.xsd
http://jboss.com/products/seam/spring
http://jboss.com/products/seam/spring-2.0.xsd”>
<!– component declarations –>
</components>

现在你可以在components.xml里使用<spring:context-loader />了:

<spring:context-loader>
<spring:config-locations>
<value>classpath:spring-beans-persistence.xml</value>
<value>classpath:spring-beans-service.xml</value>
</spring:config-locations>
</spring:context-loader>

好了,现在当你启动seam时,seam便会到你指定的位置去寻找spring的配置,并起动一个spring容器。为了能让seam知道要如何增强 spring里的bean,我们需要在spring那边做一些手脚。在spring的配置文件里加入seam的名称空间如下:

<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:seam=”http://jboss.com/products/seam/spring-seam”
xsi:schemaLocation=”
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://jboss.com/products/seam/spring-seam
http://jboss.com/products/seam/spring-seam-2.0.xsd”>
<!– bean definitions –>
</bean>

这样,你就可以在spring的配置文件里使用以下三种元素来定义如何增强spring bean了:

  1. <seam:conponent />  把一个spring bean变成seam component
  2. <seam:instance> 向一个spring bean里注入seam component
  3. <seam:configure-scopes> 定义一些默认的配置

看看下面的使用举例,我想你根本不需要解释就明白了:

<bean id=”aBean” class=”org.test.TestBean” scope=”prototype”>
<property name=”aString” value=”a string” />
<seam:component name=”testBean” scope=”CONVERSATION” auto-create=”true” />
</bean>

<bean id=”anotherBean” class=”org.test.AnotherBean” scope=”prototype”>
<property name=”aBean”>
<seam:instance name=”testBean” />
</property>
</bean>

<seam:configure-scopes default-auto-create=”true”/>

spring的 aBean在seam里被叫做 testBean, 并且它在 conversation scope里,spring的anotherBean在创建它时,会把testBean注入进去。非常简单吧?

但是,在使用过程中,要注意,seam不能对spring通过jdk 动态代理增强过的类进行再增强,所以如果要让一个spring的bean参予到seam里来,就不要对它使用动态代理的方式来实现AOP,你需要在spring的配置文件里做如下配置:

<aop:config proxy-target-class=”true”>
……
</aop:config>

好了,至此,在seam中使用spring的方法就介绍完了。

Share/Save/Bookmark

July 12th, 2008Seam增强了JSF

Seam采用的JSF作为表现层技术,但是标准的jsf有很多的不足之处。

1. JSF对POST方法的http request的依赖太强了,只有POST请求的数据才能直接绑定到后台的组件上,GET方法的则不可以。
2. 根据JSF的规范,当收到一个GET请求后,JSF走完RESTORE VIEW PHARSE 就会直接到RENDER RESPONSE PHARSE,而不会做INVOKE APPLICATION,所以GET方法的请求不能触发业务逻辑。

这些限定让JSF在某些方面不太方便,比如书签功能。因为浏览器的书签都是记下当前页的URL,而不会记下POST请求里的参数。SEAM虽然采用了JSF,但是加入了Page parameter 和 page action,弥补了JSF在这方面的缺陷。

Page parameter是将GET请求时的参数直接绑定到组件上的技术。Page action则是在生成页面之前调用业务逻辑的技术。这两者的配置都可以在WEB-INF/pages.xml或者 *.page.xml里完成。比如:

    <page view-id="/calculator.jsp" action="#{calculator.calculate}">
       <param name="x" value="#{calculator.lhs}"/>
       <param name="y" value="#{calculator.rhs}"/>
       <param name="op" converter="#{operatorConverter}" value="#{calculator.op}"/>
    </page>

上 面的配置,会让用GET方法访问/calculator.jsp时的参数x, y, op分别绑定到calculator的lhs, rhs和op属性上,然后执行calculator的calculate()方法。如果你只需要在页面上传递参数,而并不需要绑定到某个组件上,只需要写成:

    <page view-id="/calculator.jsp" >
        <param name="result" />
    </page>

这样以GET方法传来的名为result的参数将继续以result为名字在Page Scope内传递下去。

Page action 还可以按条件执行:

    <page view-id="/calculator.jsp" >
       <param name="x" value="#{calculator.lhs}"/>
       <param name="y" value="#{calculator.rhs}"/>
       <param name="op" converter="#{operatorConverter}" value="#{calculator.op}"/>
       <action execute="#{calculator.calculate}" if="#{calculator.op != null}" />
    </page>

除了在pages.xml, *.page.xml里配置,还可以用seam的组件s:link s:button来实现指定page action,例如:

     <s:link view="/calculator.jsp" action="#{calculator.calculate}" ></s:link>

这 样,当这个链接被点击后,会引发一个对/calculator.jsp的GET请求,并且在生成/calculator.jsp页面之前执行 #{calculator.calculate} 方法。如果用普通的h:commandLink的话,则会提交表单,引发POST请求。

使用page action时要注意,在处理POST请求的时候,page action会在INVOKE APPLICATION PHARSE之后执行。

Share/Save/Bookmark


第1 页 共8页12345»...末页 »
© 2007 涂0实验室 | iKon Wordpress Theme by Windows Vista Administration | Powered by Wordpress