RSS 2.0 Feed
拥抱变化
摘要:开源的CMS基本上是php的天下,选择时主要看 授权模式,不过很多人不关心这个插件和模版的数量,开发社区是否活跃。有更多的人参与你才能源源不断地获得资源中文的支持系统需求,支持那些数据库,这会影响对空间的选择扩展性,不过不是所有的人都有能力和兴趣自己做扩展  Mambo 曼波  http://www.mamboserver.com/http://www.mambors.org/http://www.mamboforge.net 中文站点:http://www.mambochina.net/http://www.mambo.cn  Mambo是一个老牌的opensource建站程序,获得过“最佳开源方案”,“年度最佳自由软件项目”等很多奖, 国外比较热门,但是在中国不够 热,中文支持比较弱,中文资源相对来说不够多。    Joomla 逐浪http://www.joomla.org/ 中文站点:http://www.mambo.cn/http://www.joomla.org.cn/ Mambo的分支,Mambo核心开发团队另起炉灶的产品。,2005年度最佳Linux开放源码系统奖  (八卦来自bbs.joomla.org.cn) 曼波开源核心开发团队致社区的公开信 致社区的公开信 --曼波开源核心开发团队 越来越多的人关注曼波开源项目,曼波商会 ( Mambo Foundation Inc *) 应运而生,它的初衷是为了更好的发展曼波。 我们,曼波核心开发团队,一致认为: 1、所谓开源项目,是致力于开发一个免费的和开放源码的软件的人们,组成一个团队而服务社会的行为。 2、开源项目体现协作精神,并享受协作过程带来的乐趣。它存储社区的信息反馈,提供好的管理,允许商业机构放心地投资于它的开发。 开源项目对任何人都敞开大门,欢迎那些能贡献价值和愿意在社区一起工作的人加入。 我们,曼波开发团队,认真关注曼波商会及其和社区的关系。我们坚信,曼波的未来,应该由使用者的需求以及开发者的能力所掌握。然而, 曼波商会却受Miro公司所控制,因此商会同社区之间的自由协作将变得不再现实。 1、曼波商会组建之初,并没有听取曼波核心开发团队们的意见。我们、社区成员,对曼波的管理和未来的发展方向,没有任何的发言权。由开 发团队组成的曼波筹委会和 Miro 公司的代表,联合组成曼波商会,并成立第一届理事会。但 Miro公司的CEO Peter Lamont完全将商会置于自 己的控制之下,在没有和开发团队的两名代表,Andrew Eddie和Brian Teeman商议的情况下,擅自任命了理事会成员。 2、尽管Lanmont先生向曼波筹委会许诺把Mambo的版权转移给商会,但Miro公司现在拒绝这么做。 我们将要做的是:在GNU规范下继续开发和改善这个获多项大奖的开源软件。我们希望Miro公司及曼波商会一路走好,很遗憾,我们不能够再和 他们继续合作。 我们听取了软件自由法律中心关于这次事件的建议,将很快就近期发展计划发布更多的信息。 2005年8月17日,曼波开发团队: Andrew Eddie Emir Sakic Andy Miller Rey Gigataras Mitch Pirtle Tim Broeker Alex Kempkens Arno Zijlstra Jean-Marie Simonet Levis Bisson Andy Stewart Peter Russell Brad Baker Brian Teeman Michelle Bisson Trijnie Wanders Rey Gigataras Shayne Bartlett Nick Annies Johan Janssens The name Joomla! is a phonetic spelling for the Swahili word "Jumla", which means "all together" or "as a whole"Swahili -- 斯瓦希里人,穆斯林民族中的主要一支,居住在东非从索马里到莫桑比克的沿海和岛屿上。斯瓦希里语作为坦桑尼亚官方语言的斯 瓦希里班图语,在东非或中东非被广泛地用作通用交际语言。 drupalhttp://drupal.org/ Drupal模块功能一览http://www.verydummy.com/drupal_demo/node/8 一些Drupal中文网站供参考http://www.todaylog.com/node/44 PhpNukehttp://www.phpnuke.org/ 中文站点:http://www.postnuke.cn/http://www.postnuke.ws/ 老牌的CMS工具了,最早的php cms工具,用户很多,能找到很多phpnuke搭建的中文站点。最新的版本是7.9,功能很丰富,社区也很活跃。 postnukewww.postnuke.com 中文站点:http://www.postnuke.cn phpnuke的分支,目标是在更少代码,更少的服务器负担,更多模版地情况下实现phpNuke的功能,Postnuke在显示上和php-nuke非常相似,但 是postnuke功能更多。 XOOPShttp://sourceforge.net/projects/xoopshttp://www.xoops.org/ 中文站点:http://xoops.org.cn/ PostNuke的分支,最近很流行,插件很多,中文支持得也不错,模块组合的能力强大,wordpress,osCommerce, ipb等很多工具都可以整合成 为XOOPS的模块。 (www.xoops.org.cn/)XOOPS - eXtensible......[阅读全文]

posted @ | Feedback (21) | Filed Under [ 拥抱变化 ]

摘要:每天一段郭德刚,祛火消痰防寒,相声回归现实,设计也倒退到以前 面向对象往回走,削减对象之间的关系,变成各自独立的实体。比如company和order,order不再是company的一个属性,order和company各自独立,对外提供服务。company.getorder的职责迁移到order,order.getorderby(order.companyid) framework简化,不再无所不包,只是把各个模块连接起来,提供objectfactory,MessageBus,模块间数据传递等基本功能。 web页面,asp.net提供了很大的便利,但是也有不方便的地方,从page control再回到font control,所有的事件处理都统一成action,动态生成webcontrol,或者干脆放弃一些webcontrol,不过一些数据绑定数据控件还是要利用它们的强大功能 数据库访问,在很多情况下,activeobject模式简单,而且用起来很方便,在很多不是很复杂的情况下能充分发挥出优点来。 对于代码,什么设计原则都不是重要的,最重要的是可测试,有了测试做基础,才有了不断改进,不断变化的可能性。...[阅读全文]

posted @ | Feedback (1) | Filed Under [ 拥抱变化 ]

摘要:单例模式   使用对象时最基本的事情就是要首先创建对象的实例,一般情况下,这是一件极其简单的事情,就是用new运算符来创建某个对象的实例,简单的人们都不想提及。然而有时候你会发现创建对象的实例也不是那么简单。   比如有一些类,在整个程序运行期间只允许一个实例,或者我们说如果有多个实例存在程序逻辑会变得难以控制,很可能遭遇错误,比如对程序所需要的资源如连接池之类的做集中管理。   或者从逻辑上讲,在整个程序运行期间可以只有一个实例,当然也可以创建多个实例,这对程序逻辑没有影响,但是实施强制单一对象实例的代价要远低于带来的收益。   全部强制对象单一机制有些多余,我们要比较实施强制措施的代价,而不同的实施方案代价和收益是不同的。   最原始方案的就是全局变量,程序开始运行时初始化这个全局变量,代码中每一个使用该类的地方都引用这个全局变量。   全局变量一个缺点是有些对象实例实际上很可能根本不会用到,而初始化又恰恰要花点时间。没有办法做到延迟加载,当然有聪明的人会说一样可以实现延迟加载,设置一个函数,每次通过这个函数来获得这个全局变量的引用,在函数里面会判断该全局变量的状态,如果没有初始化才作初始化的动作。实际上根本的缺点在于当这样的情况变得越来越多的时候,逻辑变得很复杂,代码变得难以控制,职责变得很不明确。   那么我们开始重构,将类的单一实例以及类初始化的职责封装起来,然后提供一个全局的访问点让其他的代码能够访问到这个单一的类的实例。简单的实现方式可能如下: public sealed class Singleton {         static Singleton instance = null;         private Singleton () {}         public static Singleton Instance()         {                 if (instance==null) {instance = new Singleton (); }                 return instance;         } }   这里把Singleton类的构造函数设置为private是为了其他类不能直接用new方法来创建多个Singleton的实例并使用它,而是提供了一个全局的访问接口Instance()方法,其他的代码只能通过访问Instance方法来获得一个Singleton类的实例。在Instance()中会判断instance是否已经创建,如果没有创建的话才去创建一个实例出来。   练习题:为什么instance要声明为static类型的变量。   简单测试之后发现可以Singleton类这样的设计实现了我们的意图,那么我们再检查Singleton的代码 如果多个线程同时调用Instance()方法,而这时instance还没有被创建,这时会怎么样呢,怎样保持线程同步?   我们可以对Singleton做一点改造,用lock来强制线程同步 public sealed class SingletonLock {     static SingletonLock instance=null;     static readonly object padlock = new object();             private SingletonLock() {}     public static SingletonLock Instance()     {         lock (padlock)         {             if (instance==null) {instance = new SingletonLock();}             return instance;         }     } }   每次强制线程同步是很耗费资源的,而实际上只有第一次访问Instance()才需要强制线程同步以确保只创建一个实例,那么可以在锁定线程之前先判断instance是否为null,如果为null才调用lock锁定线程。 public static SingletonLock Instance() {     if(instance==null)     {         lock (padlock)         {             if (instance==null)        ......[阅读全文]

posted @ | Feedback (8) | Filed Under [ 拥抱变化 Dot Net ]

摘要:Template Method使用了对象继承,而继承是一种很强的对象和对象之间的耦合关系,底层模块还是依赖于高层模块,比如子类要知道哪些abstract method要重写,哪些hook method可以做扩展,哪些基类资源可以利用。   strategy模式使用对象之间的组合关系来代替继承,进一步减弱高层模块和底层模块之间的依赖,让底层独立于高层,使其完全符合更符合DIP的原则, 这样底层代码不需要了解高层代码是怎么工作的,高层也不需要知道底层的实现细节, 相对于Template Method模式来说strategy模式革命的更彻底一些。   还拿Report来作一个简单的例子。 Report的输出可以是Html格式的,可以是Word格式的,也可以是PDF格式的,我们可以定义一个Interface:IReportPublisher,在IReportPublisher中定义高层模块和低层模块之间的调用协议。(或者说Contract)   Interface IReportPublisher {public void Publish()}   HTMLReportPublisher : IReportPublisher WordReportPublisher : IReportPublisher PDFReportPublisher : IReportPublisher   Report {       Public void GenerateReport() {       …       reportPublisher = MyContext.GetService(…)       reportPublisher.Publish(reportData)       … } }   当然实现strategy模式也有代价,将Template Method改造成strategy模式后,架构中层次变复杂了,一些Template Method模式原有的特性就没有办法利用了,比如子类可以调用基类一些资源。   应用任何一种模式都会有代价,学习模式时,明白为什么这么做比明白怎么实现更重要,了解模式带来的收益的同时也要了解你要付出的代价。模式也是一直随着技术的发展在发展的,有些模式在慢慢消亡,有些新的模式出现,有些模式被新的编程语言天然支持,有些模式的形式发生了变化,Gof的《设计模式》里的一些观点现在来说已经是有些过时了。   strategy模式和Template Method模式的对比还体现了面向对象的另一个思想,解决对象之间的协作问题应用对象组合优先于对象继承。在面向对象的初期,人们非常看重对象继承,继承一个类,就可以重用该类的代码,把很多类的代码抽取到一个基类中就可以去掉代码重复,创建一个子类,改变一点点就能创造出一个能实现新功能的类出来,通过继承我们可以建立完整的软件结构分类,每一层都可以重用该层以上的代码,这看起来很美好,到后来人们才慢慢发现继承非常容易被过度使用,而过度使用带来的收益比代价要高的多,所以我们减少对继承的使用,用组合和委托来代替继承。   strategy模式和Template Method模式都面对一个问题,在运行时怎么创建某个子类或者某个实现了某个interface的类的实例,那就涉及关于创建对象实例的模式:Singleton模式和Factory模式。...[阅读全文]

posted @ | Feedback (0) | Filed Under [ 拥抱变化 Dot Net ]

摘要:template method模式和strategy模式   template method模式和strategy模式都是关注对象的行为的,按照依赖倒置的方法来分离抽象和具体的实现,但是两者的实现方法不同。template method模式应用了面向对象中继承的思想,而strategy模式则应用了委托的思想,从template method模式和strategy模式中也可以看到面向对象世界中abstract类和interface的异同。实际上这两种模式我们经常会用到,只是可能没有意识到而已。   Template method的常见用法是将运算的骨架放在基类中,然后将某些具体的算法放到子类里面实现,这样就可以使得子类不改变算法的结构即可重定义该算法的某些特定步骤。   Template method的一个例子:Report服务。 假定系统中有一系列Report,Booking Report, Billing Report, Aging Report…。这些Report参数不一样,界面不一样,逻辑不一样,但是也有一些有共同点,验证权限,结果输出,Report载入步骤等等。那么为了避免重复代码,有一个较好的可扩充的结构,我们把这些共同点extract到一个基类中ReportBase,简单示例如下: public class ReportBase {     public void OpenReport(string reportId)     {         if(UserIsInRole()==true)         {             Initialize();             LoadSavedReport();         }     }       private void Initialize()     {         InitializeControl();         SetDefaultValue();     }       protected abstract void InitializeControl()     {     }       protected abstract void LoadSavedReport ()     {     }     protected virtual void SetDefaultValue ()     {     } } 在ReportBase中定义了OpenReport()的逻辑,先验证用户权限,然后初始化Report的页面上的控件,设置缺省值,载入用保存的Report。对于每个具体的report来说,界面和参数是不同的,要实现InitializeControl()和LoadSavedReport()方法。   ReportBase.OpenReport()是一个Template,定义了算法的每一步,并且允许子类提供其中某些步的具体实现。   我们可以看到Template Method的主要特点是,将各个子类中不变的行为提取到基类中实现,可变的部分留给子类自己实现,而且基类中定义了一个相对稳定的结构,也就是一个模版Template,模版中的某些步骤留待子类来实现,基类还可以控制子类的扩展,允许某些子类在某些点上作扩展。对于基类来说意义在于控制整个结构,减少重复代码,对于子类来说意义在于不改变算法的机构可以方便的提供一种实现。     从Template Method中可以看到Framework和控制反转的精神,不是每个具体做事情的子类调用所需的Library完成某个行为,而是提供具体实现,让高层的代码来调用。 (Hollywood Principle: 当高层的模块依赖低层的模块时,由高层的模块决定何时以及如何调用底层模块,也就是说高层模块对底层模块讲:Don’t call me, we’ll call you)   当然Template Method模式和strategy模式在现在看来都已经是很自然的都东西。   应用Template Method需要先对代码逻辑作分析,哪些放到基类,哪些留给子类,当然这属于OO世界最基本的东西。如果现有的代码重构到Template Method可以参考《Refactoring》Dealing with Generalization一章。   应用Template Method需要注意的是基类需要指明那些行为是子类必须重定义的,哪些行为是允许子类重定义的(Abstract method和Hook Method),具体到C#的语法就是abstract和virtual定义。而且需要仔细评估那些子类必须重定义的行为,避免子类中需要做过多的重定义工作。对于可以允许子类重定义的行为来说好比提供了一个hook,在基类中通常是一个空操作,允许子类在这一点上扩展基类的行为。   另外一点需要注意的是继承属于很强的耦合关系,过多的继承关系会使系统变得僵化难以变化,往往会用对象的组合来代替继承。   一个替代继承的模式是strategy模式。   参考 《Head.First.Design.Patterns].Head.First.Design.Patterns》 《敏捷软件开发 原则、模式与实践》 面向对象设计的基本原则...[阅读全文]

posted @ | Feedback (5) | Filed Under [ 拥抱变化 ]

摘要:很久没有更新了。 系统升级要从FileMaker导出数据,公司服务器上找了一个免装版本,折腾了一下午也没有找到好的方法,在绝望关头冒着风险安装了一个盗版的FileMaker,原来如此简单,用FileMaker的自带的ODBC驱动设置好DSN,FileMaker里面选共享数据库,就可以一切解决了。最后老老实实找出公司买的FileMaker光盘从头开始。记录一下也算是自己乱走捷径和先入为主的一个教训。 我们这边有四个 Program Analyst,三个Business Analyst,其中两个来自加拿大,按照计划过了春节之后,我们的系统要陆续推广到东南亚,中国大陆,香港,台湾,澳大利亚,印度和俄罗斯,还有现有系统各种花样的Support工作,如何应对各种用户也是很劳神的事情,韩国的新系统刚刚上线,定了一个2G内存的IBMT42,准备春节背回家随时候命做Support,明年的工作对我们是一个巨大考验,协调和控制需要仔细的评估,最重要的是主动的精神。 附加老板教育语录 你觉得不高兴就不要做,不是非要靠这个养家糊口,不要为我担心,少了谁公司一样发展。现在公司最清闲的是我,要向我学习。不要加班,生活和工作不应该overlap,下午6点钟,关灯断电把你们赶走。不要埋怨别人,不要怪别人影响了项目,应该主动,你认为不对,那么你和他们吵过架吗, 如果这是你自己的公司,你会允许别人那么做吗。自己把设计交出去,把项目控制交出去,把主动权都交出去那么遇到问题就谁都不要埋怨。不要等别人来安排任务,不要等别人来抱怨,要有积极的精神去发现问题解决问题。...[阅读全文]

posted @ | Feedback (21) | Filed Under [ 拥抱变化 ]

摘要:性能的题目大多是涉及封底估算的。对于性能的风险,最初选择方案是就要做出一个评估,不然后期会带来很多麻烦,当然最初的估算不要求面面俱到,十分精确。但是需要有数字出来,而不是“我觉得应该不会有问题”之类的答案。估算主要集中在资源的占用,时间复杂度,数据增长对于性能的影响。估算不仅对于选择合适的算法和数据结构有帮助,而且对于选择硬件也会有影响,比如内存,网络带宽等等。 作性能调整时需要注意的一点时,要用数据为依据,分析哪一个环节最值得去突破,而不是仅仅靠猜想,所以profiler工具是需要的,如果程序中用到层超类型,gateway之类的,数据收集会方便一点。 对于第一题, 有些公交车的刷卡设备是会显示一天的刷卡总额的,可以作为验证估算结果的参考。几个算法题目在给出方案时应该也估算一下方案的时间复杂度和空间复杂度。电话号码的题目当然最好是线性扫描一次后就给出排序结果,可以利用电话号码本身的特性。变位词问题一个关键的地方是如如何判断两个词是变位词,对单词进行合适的编码有助于变位词的判断。求整数数组连续区间的和的最大值的题目最好是遍历一次就能把结果找出来,会用到性能优化的一个原则:利用已有计算结果。这几个问题在《编程珠玑》中有详细的讨论。 sql题目和性能没太大关系,主要是说明对索引列操作性能不一定就一定好。viewstate的问题需要注意两个方面:估算对存储空间的要求和viewstate信息丢失的处理。 编写正确的程序中的1,2题中涉及怎样处理错误,第3题中所列的都是可能发生的。一个月至少28天这一个有点抬杠的味道,这和现有历法施行的第一个月有关。第4提是讲要根据行为来确定继承关系,而不是属性。第6题只要去想就会想出很多简单方法,有一点要注意,不一定要procedure的文档,测试代码和procedure写在一起。 团队的问题仁者见仁,智者见智。发布的几个问题曾经是我们的面试题目,总之自动化是根本。还有一点,顺利的发布除了技术因素之外,还有一些非技术因素,比如备份,与用户的沟通等等。...[阅读全文]

posted @ | Feedback (3) | Filed Under [ 拥抱变化 ]

摘要:性能 1:估算上班所乘公交车一天的客流量和营运收入,如果你上班乘公交车的 2:根据你的程序的应用状况,比如同时在线人数,平均停留时间等等估算对性能和配置的要求 3:性能调整的第一条原则,不要做性能调整,第二条要有一个分析评估工具,针对你的系统搭建一个profiler平台,找出系统化中对性能影响最严重的模块 4:文本文件存储一个地区的电话号码,8位整数,要求排序输出,怎么样是综合性能最优的方案。 5:给定一本英语单词字典,找出所有的变位词集。比如pots,stop,tops相互之间会都是由另一个单词的各个字母改变序列构成的,这些词相互之间就是变位词。 6:找出整数数组连续区间的和的最大值数组x[0]...x[n],y=x[j] + ... + x[k],0<=j<=k<=n,求y的最大值 7:asp.net中可以为了提高性能,可以把viewstate放到server端,有哪些方式,有哪些隐患。 8.SELECT MIN(column1), MAX(column1)  FROM Table1和SELECT MIN(column1) FROM Table1SELECT MAX(column1) FROM Table1 哪一个更快,假设column1有索引 编写正确的程序 1:防错性程序设计虽然常常被誉为有较好的编码风格,但它却隐瞒了错误。比如:if (y != 0){ z = x / y;}实际上,逻辑上讲y不应该为0,如果是0说明运算中间有错误 那么怎么样处理这两者之间的矛盾。 2:The pragmatic programmer讲到一条原则——死程序不说谎,如果程序有错误,就报错,中止运行。怎么理解和防错性程序设计之间关系 3.下面这些不可能的事件中,那些可能发生(The pragmatic programmer)一个月至少28天stat(".", &sb)==1在c++中,a=2; b=3; if(a+b != 5) exit(1);内角和不等于180的三角形没有60秒的一分钟java中,(a+1) <= a 4:企业不同类别/级别的员工要做不同的事情,建模时,可以采用manager从employee继承下来之类的结构,也可以employee类包含属性job之类的结构,他们应用起来有什么不同 5:重构中,有许多相对的重构方法,比如把函数拆开和合并,用表达式替代变量用变量替代表达式,将字段在类的继承结构中上移下移,那么这些相对的操作他们背后的相同点是什 6:表述一个针对存储过程的程序的思路,实现类似ndoc和nunit的功能 团队 1:在团队会议上,有的人常常不是积极地发言,怎么样来调动每个人的积极性,达到头脑风暴的效果 2:项目后期程序员会夸大做某个更改所需要的时间,来抵制更改。 3:一个小的团队,团队中成员之间的沟通常常会有些问题,需要你来做桥梁还是通过某些方式来增强他们的交流发布 发布 1:发布最重要的是,利用nant等工具,实现将程序source control中自动获取最新版本代码,备份,编译并且部署到几个服务器上去。 2:b/s结构的程序,不允许长时间停止运行,要升级程序,怎样将影响减到最小。 3:程序代码修改后,要部署到5台不同环境上,怎样自动化部署和测试的流程 ...[阅读全文]

posted @ | Feedback (14) | Filed Under [ 拥抱变化 ]

摘要:设计的普遍规律,不只单讲如何设计类,向上到整个组件的设计,向下到类中单个方法的设计   单一职责原则——SRP 就一个类而言,应该仅有一个引起它的变化的原因   原则 最简单,最单纯的事情最容易控制,最有效类的职责简单而且集中,避免相同的职责分散到不同的类之中,避免一个类承担过多的职责减少类之间的耦合当需求变化时,只修改一个地方 组件 每个组件集中做好一件事情组件的颗粒度发布的成本可重用的成本   方法 避免写臃肿的方法Extract Method   重构 Move Field/Move ClassExtract Method/Extract Class   最简单的,也是最难以掌握的原则   实例分析 Olite 开放封闭原则——OCP 软件实体(类,模块,函数)应该是可以扩展的,但是不可修改的   原则   对扩展是开放的,当需求改变时我们可以对模块进行扩展,使其具有新的功能对更改是封闭的,对模块扩展时,不需要改动原来的代码面对抽象而不是面对细节,抽象比细节活的更长僵化的设计——如果程序中一处改动产生连锁反应。 方法 条件case   if/else 语句   重构 Replace Type Code With ClassReplace Type Code With State/StrategyReplace Conditional with polymorphism   实例 插件数据驱动的OrderCycle   Liskov替换原则 LSP 子类型必须能够替换它的基类型 原则 主要针对继承的设计原则所有派生类的行为功能必须和客户程序对其基类所期望的保持一致。派生类必须满足基类和客户程序的约定IS-A是关于行为方式的,依赖客户程序的调用方式   重构 Extract Supper Class   实例 长方形和正方形   依赖倒置原则DIP a:高层模块不应依赖于底层模块,两者都应该依赖于抽象b:抽象不应该依赖于细节,细节应该依赖于抽象   原则 如何解释倒置高层依赖底层,重用变得困难,而最经常重用的就是framework和各个独立的功能组件高层依赖底层,底层的改动直接反馈到高层,形成依赖的传递 面向接口的编程   实例 Ioc模式DomainObject / DomianObjectDataService   参考 《敏捷软件开发 原则、模式与实践》   http://microhelper.blogdriver.com/microhelper/432102.html...[阅读全文]

posted @ | Feedback (20) | Filed Under [ 拥抱变化 ]

摘要:sumtec同志也想翻译DDD呀,想翻译DDD的人还真多。 《领域驱动设计——软件核心复杂性应对之道》清华出版社在制作,umlchina上面已经有广告了。陈大峰,张泽鑫译,问了一下umlchina,最早年底才能面市的说,有对DDD兴趣的话还是先慢慢啃英文版吧。如果想先了解更多,可以看看豆豆他爹的生活随笔,豆豆他爹是审稿者之一。  ...[阅读全文]

posted @ | Feedback (0) | Filed Under [ 拥抱变化 ]

Full 拥抱变化 Archive