昨天遇到一个问题,用MSXML操作XML时,删除一个子节点,可是死活删不掉。后来想到一个变通的办法,把这个子节点的标志性属性值改掉,这样其他处理过程就认不出这个节点了,就相当于删除了,很黄很暴力。
今天再去定位这个问题时,发现原来那子节点真的被删掉了。进一点试验发现,只要在删除该子节点前,先随便改一下这个子节点的一个属性值,下面的删除操作就正常了,但如果没有那个修改操作,就删不掉,真是怪事!
我当时还以为是不是因为子节点下面还有其他孙子节点,还想是不是要修改一下删除子节点的封装方法,递归地删除掉所有子孙节点呢!看来不必了!
今天在公司看到一个同学在用e,有点好奇,早听闻它有“Windows下的TextMate”之称,以前也下载来装过,只看到界面很简单,功能也很简单,于是就没下文了。今天又有点兴趣,就让同事共享给我再试用一下。
还是老样子,界面上没什么改进,也许比之前我试用时功能上有所增强,但以我目前的眼光看来,它还是太简单了。总的说来,只有一个特色功能,就是 bundles。不过可能TextMate赖以成名的就是bundles了,e就是全盘照抄了,从网上看到,说e的作者和TextMate的作者是老乡,两人协商过,让e可以直接使用TextMate的bundles。所有的人都说,e只有TextMate的一小部分功能,这我也是相信。但是最让人受不了的是,e运行极其不稳定,随便点几下就是挂起,或者崩溃。这么烂的程序居然也来卖,而且听同事说可能卖得还不错,我想这全沾了TextMate的光啊!因为说,它的一切思想,无论是从程序开发的角度,还是用户体验的角度讲,都是很好的,但这一切都是TextMate赐予的,e里唯一有点自己特色的是,用类似异步可插入协议的方式来修改配置。我没用过TextMate,不晓得它在这方面是怎么做的。
看了e后,另外一个同事就说,我们现在的Impeller应该也好卖吧,有语法结构树,有自动完成,有调试执行,我笑!
昨天晚上跑去KTV唱歌,后来唱歌腻了他们就放起的士高来,我是不会蹦迪的,可是看着那些人在那跳得那么起劲,我也有点蠢蠢欲动了,于是去胡乱蹦了几个。结果,今天就显效了,虚脱了,背痛,下午一下就睡着了,好久没在家里睡过午觉了,醒来的时候发现天灰蒙蒙的,还有雨声,还以为睡到天亮了,心里不禁大喊,天呐,我居然从前一天下午睡到第二天早上,还没吃晚饭!后来挣扎着要不要起床,看了一下时间,才18点,心里顿时安定了不少,原来还没到第二天啊,刚刚还郁闷着这周末就不知不觉地让我睡过去了呢!
再说点正儿八经的事。话说我一直想要设计一个基于C++ GUI框架的脚本扩展架构,不过到目前,还没有一个完整的清晰的思路,我只有一个大致的目标。一直想着,这样的架构实现后,只要C++部分实现一些基本的底层支撑,剩下的脚本就可以直接拿出复用,实现所有业务逻辑。为了证明这个架构的通用性,我觉得自己似乎有点儿贪心了。我希望在MFC+XTP的基础上、 WTL+TabbingFramework的基础上,以及wxWidgets的基本上都实现一遍。MFC的是因为工作上的需要,WTL则是因为想写一个 WIND,而wxWidgets的则是想写一个通用的跨平台IDE。今天只想到一点,所有的逻辑处理都应该交由脚本实现,C++部分只提供最基本的底层(原子)操作。
昨天偶然发现,我的程序根本检测不到Excel文档的修改,太让人郁闷,之前完全没料到这个结果啊!后来回想一下也想通了,Excel文档那么复杂的一种文件格式,不使用像txt之类的修改方式,完全是可以理解的。不过理解归理解,问题变得棘手了,怎么才能实现那个需求呢!
今天没写代码,倒是在自己建的wiki上写了几篇文档,有关于设计方案的,也有关于使用说明的。我要开始准备撤退了,出于道义上的,或者说职业道德上的考虑,也是为了让自己以后少被人骚扰,我要输出尽量能解释清楚我目前所做的一切的文档。
写文档也是个很累人的体力活啊,也许是因为几乎从来不写文档,让我觉得很多事情都不知道从何说起。心中很清楚明白其中的每个细节,却不能用文字表达出来,或者说即使能零碎地写些文字出来,却不能有效地串连起来,形成完善的文档。
今天质量部的老大把我叫去,谈了一下之后的计划,我刚好趁此机会明白地告诉他,我对之后的维护性质的工作实在没多少兴趣的,而他居然出乎我意料地说,如果是这样的情况,可以换个人,而且还肯定了我之前所做的,这让我心里比较高兴,哈哈,仰天长笑!
今天做另外一个工具的一点维护工作,需求是通过用户输入的宏名,宏值,类名,函数名以有函数返回值,工具要能自动到指定的文件中找到指定的位置,自动插入生成代码。本来这个需求是上个版本就已经实现了的,今天只是对需求有略微一点修改。可是最大的问题是,今天发现以前实现的这个根本不能用啊,文件是能找到,可是位置却是错的,根本毫无联系。
调试了很久,实现过程是首先利用MSR的greta来找到参考标记,取得标记的位置,然后插入生成的代码。一开始怀疑是取得标记的位置不对,其实冷静地想想,这种可能性几乎不存在。不过我还是傻傻地加入代码,看标记位置取回的字符串内容,毫无疑问,肯定是对的。接着怀疑是Scintilla的插入方法有问题,同样事后想想,这种可能性也微乎其微。不过我也不死心地,加入代码,看该位置的 Scintilla文本,果然已经是不正常的内容了。
正在束手无策之时,突然不知怎的,灵光一闪,可能是因为看到其他一个项目中使用多字节编码的greta,觉得可能是这里引起的问题。greta在匹配文本时,在unicode情况下,一个中文字符和一个英文字符都是一占一个长度,而此时 Scintilla还是以多字节方式处理,一个中文字符占两个长度,所以greta算出的位置对scintilla来说并不能对应上。想通了这一点,立即将工程编译选项切换到多字节方式编译,果然就正常了。
这次遇到这个问题,也能为以后实现相关需求,或者解决类似问题,提供了极大的参考价值。
老大叫我整理一份项目组内成员的C++相关内容的培训计划。我还是兴冲冲地去弄的,不过基本上是参考我自身的情况制订的,内容方面不是我比较熟悉的,就是我比较欠缺但又在工作中比较需要的。
主要分了8大类,分别是C++对象模型、C++模板、STL、Boost、面向对象程序设计、Windows API、MFC、COM。每一类,都又划出好几个培训课程,我还根据自己所了解的,分别给每一类都备注了参考资料,每一类的的参考资料大多只是两三本经典书籍,比如COM类的,我就写了《COM本质论》和《深入解析ATL》,而Windows API类我就写了《Windows程序设计》和《Windows核心编程》,等等。
等我把这份列表发给老大,老大又转给更大的老大,更大的老大则回复说,内容太多了,要分轻重缓急。我觉得很有道理,这样的培训是很耗费资源的,当然应该拣最有用的来。不过他列出的前3位是Windows API、MFC和COM,对于我来说,就有点兴味索然了。虽然这些方面我也远远说不上精通,甚至连熟悉都不够,但我自以为,应付工作上的要求是够了。比 COM举例来说,我虽然排斥COM,但必须用地方还是会用的,我会调用COM服务器,同时我也写过COM组件,我觉得自己够了。
既然不能把这份列表作为组内的培训计划,我看了看,觉得依照这些列出的参考资料,也可作为我自己的增强计划。这8类我都有所了解,在实际工作中也都或多或少地有所运用,但我不禁要考虑,学到什么程度算是够?
我个人倾向于学习和使用一些比较通用的技术,比如STL、Boost之类平台无关的知识我就很有兴趣,而COM则是有点深恶痛绝的感觉,MFC稍微好过一点,不过也不是很喜欢。这不是我研究了这些东西后主动有了喜恶观念,而是不知不觉在一个比较长时间内养成的兴趣倾向,直到后来自己总结的时候才发现这个规律。
其实我根本没多少想法,要尝到什么程度,目前而言,我只好给自己暂订个目标,STL、Boost、C++模板和对象模型,以及面向对象程序开发,是能学多少算多少,而其他的,则是够用就行。
幸亏有Code::blocks和CodeLite两个的源代码可以参考,可以省事不少,不过还是发现,要像现在用MFC一样的比较熟练地使用wxWidgets仍需要先阅读一些基本的资料,当然wxWidgets的manual也是必不可少的。
学习一种新的GUI框架的使用方式,关键还是在于了解并掌握它的消息处理机制。通常见到的GUI系统都是消息驱动的,所有所有的编程框架都不可避免地要有一套自己的消息处理机制,而且这套机制的设计好处,直接影响到整个框架的运行效率和使用效率。
总的说来,我感觉目前wxWidgets已经有点庞杂,好处是有些问题可以有多种解决方案,坏处是增加了学习成本以及降低运行效率。总觉得它不但最终生成的可执行文件体积大,而且运行效率太低。不过似乎用gcc编译出来的代码,运行效率也不如用VC编译出来的。假设能用Intel编译器来编译,是不是运行效率能更高呢?
现在用wxWidgets来写程序,还有个比较麻烦的问题是,跟用MFC开发相比,缺少一个好用的开发工具。以目前凡事都追求效率的情况来讲,写程序早已不是随便找个文本编辑器就能写代码的时代了,不光要有基本的文本编辑能力,其他自动完成、重构、提示、引用跳转、向导等等,无不影响着程序员的心情,以及开发效率。从这方面讲,目前已经没有哪个环境能跟VC+MFC比了。用vc也能写wxWidgets程序,但跟开发MFC程序相比,它缺了各种向导,比如Property视图,可以直接为各种系统消息、命令ID生成对应的函数声明,还有常用类派生的虚函数实现。
不过,总算起步了!
本来计划是明天的,因为冬至要吃饺子,结果F说明天要加班,于是只要提前到了今天。
那几个家伙也够懒的,能睡那么久,不过也让我有点羡慕,因为我到了早上7、8点的时候,就开始睡不着了。
结果等cm0同学过来的时候,已经1点了,然后跑去超市买菜。安排的是中饭吃炒菜,晚饭吃饺子。买了130多的东西,当然不全是吃的,还有cm0买的什么卫生纸之类的东西。F去超市旁的KFC买了鸡米花、圣代、薯条、蛋塔,因为实在不知道我们什么时候才能吃上中饭。
中饭的菜基本上是我弄的,也跟平时我自己弄的一样,一个肉丝、蒲瓜、金针茹、香干丝混炒,一个白灼基围虾。味道自我感觉还是满意的。吃完就已经4点半了。
吃过中饭,就打了一会儿升级,我的手气不是一般的差,不知道那个跟我搭档的cm0有什么感想,哈哈,反正我们一直都是打2,没升过级,而对方已经打到7了。
7点时,开始准备晚饭,即饺子。我没有动手,因为我实在没有经验,就看着他们三个包,份量挺大的,满满一大盆的馅,厚厚的两叠皮。最后吃剩下15个左右,没办法了,只好浪费了,唉,可惜!
另外还剩下鸡汤和鸡肉没动呢!
被另外一个同事说了两次了,说我最近越来越酷了。今天我就问哪里酷了,他说竟然敢当面顶撞王总了。我心中冷笑,多从来不认为公司里这种领导对下属可以指手划脚,颐指气使,我从来只觉得领导也不过是个打工的,只不过与其他下属的工作内容不一样,他的职责不是领导人,而是协调各种资源,包括人力。
不过最近脾气比较坏倒是真的,我完全是被搞烦了,我也顾不上那么多了,气不过我就要反驳。今天早上的站立式会议时,我还对老大出言不逊了,我就直言他们对COM的过度热衷和盲目崇拜。
后来老大找我沟通,说我是不是对现在的项目很有情绪,我说是不爽,而且感觉付出和回报不成比例,付出得太多,回报得太少。
下午在回顾今天发的版本发现的问题后,质量部的人又在那里摆了很久龙门阵,知道我们想要撤出,便在那里说了一通项目的前景,个人的前景,画了好大好大一个饼,呵!
大牛上周从俄罗斯出差回来,今天给了我好大一块巧克力,哈哈!
单从包装外来观察,这块巧克力厚就不止1cm吧,宽不止10cm,长不止 20cm。包装上全是俄文,我也找不出哪里写了具体的体积规格参数,手头也没有尺子可以量一下,反正就是很大一块。中午猫猫还说,大牛把最大的一块给我了,给她的就没有我的大,哈哈,想起这个就觉得开心!
我们公司的人去国外出差,习俗就是带当地的巧克力回来给同事朋友们尝尝。以前吃过那位cm0同学不知道谁给她的德国巧克力,薄薄的一盒,里面是一小条一小条,味道比小卖部的德芙好多了。只可惜我是没什么机会出国出差了,除非赚了钱自己去旅游去。
其实我很喜欢吃巧克力的,只是太容易长胖了,哈哈!
今天终于搞明白为什么昨天构建我的项目要2个小时了,原来是内存耗完了!
本来一直没这种问题的,也就昨天突然发现,我的项目集成构建一次,最多的时候要206分钟,瀑布汗!当时还以为是中间的哪个环节出问题了被阻塞在那里了,看了下进程状态都是好的,主要的时间都花在doxygen生成文档上了。但看看doxygen也是正常的,有条不紊地dot。
其实昨天就已经搞好了,因为当时发现本来2GB的物理内存,又设了2GB的虚拟内存,可是看看整个系统的内存使用量居然也是3GB多。关了一票的没用的进程,包括普通应用程序和系统服务,发现又变快了。
今天重启了系统,同样关掉那些没用的服务和应用程序,再看CruiseControl,终于恢复正常了,15分钟就能完整地执行完一次构建!
唉,服务器资源还是有限啊!
一直沉迷于网络小说,完全属于玩物丧志的类型!今天无聊完,郁闷完,打开VS来,决定先把框架搭起来再说。
总的说来,这是一个需要用外部脚本和配置文件协同扩展才能让业务逻辑正常运行的系统,而C++部分纯粹是为了实现用脚本比较困难的核心功能。虽然想了很久很久了,但一直迟迟没动手,玩物丧志是主因。
另一个不太重要的借口是,没找到好用的开发工具。微软的一个很好的实践是dogfood,很早以前看《微软的秘密》一书时就知道这个了,前些天听那微软的专家交流时,又看到这个,觉得很有趣。像Code::Blocks和CodeLite都是典型的dogfood,使用自己来做为开发工具。而我目前还处于一片空白的阶段,被Visual Assist X惯坏了的我又受不了其他工具的弱智,于是一直停在那里。今天想通了,就用VS来作开发环境好了,先用VC编译一个debug的wxWidgets,要 retail版本时,就写好makefile,用gcc来编译。
这次恢复系统后,只装了个VS2008,这一方面可以让我不至于为众多的选择而分心,同时也减少多版本并存而可能出现的各种奇怪问题。前两天把原本只能用VS2005打开的WIND工程尝试着用VS2008打开,居然没崩溃,高兴之余把用WTL封装了的Scintilla代码也精简了一把,删掉了几千行代码,这下应该更不会崩溃了吧!
前天,公司请MS的人来做交流,我也去听了一下,虽然只听懂了20%~30%,还有有翻译,尽管翻译的水平不咋的,连蒙带猜的大致上也能搞明白他在讲什么。其中让我印象最深感触最深的一个实践,是用wiki记录开发文档,其他人也可以修改文档,有新人加入时,就可以通过wiki进行学习,我深以为然。
昨天,老大提出,我们项目组也要组建公共知识库,也包括开发文档。有个同事提出,他倾向于使用Word文档来进行记录这些内容。这不禁让我开始思考,用wiki和用Word来记录开发文档,各有什么优缺点。
大体说来,我是倾向于用wiki的,因为我觉得wiki的形式更能鼓励人们不断跟着代码变化而自发地更新文档,并且wiki一般自带版本管理功能,使用更方便,另外一方面,开发文档并不需要多丰富多样的格式,有简单的文本和插图一般够用了,而Word文档拥有的其他功能,可算是累赘了,比如要比较两个版本的差异,就相对要麻烦一点点。
说到底,我其实最看重的是wiki形式的约束下,人们会更多地完善文档,我们项目组目前的一大问题是,并没有多少文档,代码中偶尔有几行注释就算是全部的文档了。假如我们也像产品开发人员那样有非常详细的从SRS到HLD,再到LLD,那用wiki和用Word 文档,或者其他什么记录形式,根本没有区别。
今天去把那几个函数重构了,第一印象中用template method pattern是可以解决的,于是翻了下GoF,里面对template method的描述基本没出我的意料之外,还是可以理解的,不过可能是受限于当年的C++技术水平,也可能是其他未道明的原因,GoF中说是在派生类中用覆盖方法实现的。
我却认定了要用callback,因为我想用boost.function和boost.bind,于是三两下就搞好了,果然很简单,而且仔细想想,似乎相比用继承的方法实现,我现在的方案有一个优点是,可以把可变逻辑控制在更小的粒度上。比如本来我是一个算法的几个步骤,其中一个步骤是调用STL中的算法,而该算法需要一个谓词,这个谓词是可变的量,该谓词要被提取出来,这可以通过boost.function和 boost.bind实现得像一个closure一样,在template method的领域内不需要知道谓词的具体实现形式,它只知道它接受一个boost.function,该function接受一个参数,之后返回一个值,至于到底是用functor实现,还是C global function实现,或是C++ class static function实现等等,它不需要关注,因为boost.function会打理好一切。而如果是用继承的方法实现,可能我就需要把那整个调用STL算法的步骤提取出来了,这样粒度就大了,就削弱了原本使用template method的意图和优势了。另外还有一种方案,还是用继承,只把谓词逻辑提取出来,STL算法调用时,用boost.bind来封装,但我想这是行不通的,因为编译期并不知道要调用哪个派生类的方法。
用boost.function和boost.bind实现template method果然安逸,design pattern果然只是一种思想,而不受限于实现,哈哈!
今天整了一天,把原来的一个列表,整成了5个tab页分成的5个列表,每个列表显示不同的内容。
这次是深切体会到当初设计的草率,把许多应该放在文档类中的数据成员和方法都放到视图类去了,结果现在本来还是同一份数据,要给多个视图共享使用时,就需要大量的修改。
不过这样的修改从长远看来,说不定是塞翁失马。不光结构上有调整,在某些接口实现上,也有修改。总的说来,比又前更合理,更简单。
当然一天下来,功能匆匆忙忙实现了,代码实现细节上却没有多加考虑,还是需要后续重构的。比如有一份代码,在4个视图类里各写了一遍,应该是用模板方法可以重构掉的,还有份代码,在2个视图类里各写了一遍。以前遇到这种情况可能会头痛一下,现在有了之前的使用boost.funciton和 boost.bind的经验,应该很自然地能解决了。
本来这个需求并不是最紧急的,但是一方面我自己比较想做,另一方面,它涉及到的面比较广,早弄好,其他部分也方便点。
周日头脑发热,去买了一台PSP2000和一台NDSL,总共花掉2700大洋,我哭丧着脸跟同事说,半个月工资就这么没了。同事则也说还好呢,才半个月工资。我说难道是要想想那些花掉2个月工资的。
买回来,其实没玩多少,因为对我来说,还是有很多方法打发时间的,消磨时间并不是我买它们的主要原因。为了省钱,我没买那些数据线,所以也不能自己下载游戏来玩了,都是铺子里给我装的几个。
简单玩了一下,发现NDS这个机型的机能不足了,确实只能从游戏性上下功夫了。有一个Mario篮球游戏,通过触笔来控制人物进行各种篮球运动中的动作,比如运球、传球、射篮、抢断等等;有一个养宠物狗的游戏,可以通过触笔来做手上的动作,比如挠痒、抚摸等等,还可以通过语音来实现命令的下发,比如呼唤宠物,让宠物做动作。总之,因为有了麦和触摸屏,游戏的方式就改变了,虽然它的色彩不如PSP丰富,运算性能没有PSP强大,但它的游戏趣味性和多样性可以做得比PSP好很多。
PSP的屏幕分辨率高,上面的游戏画面效果真是令人震撼,当然这也跟它的处理能力强悍有密不可分的关系。当然有点让我觉得无趣的是,PSP除了可以玩游戏,还加了太多其他功能上去了,看视频什么的,我觉得完全没必要嘛!
今天去整编辑器了,加上了函数定义的跳转功能,总共大概花了4个小时左右吧,因为没有功能良好的语法解析器支持,所以基本没什么技术含量可言了,就是判断一下当前光标所在位置的单词,假设该单词是一个类的方法名,去数据库中查询一下该方法所在的文件路径和行号,如果有多条记录,则弹出个对话框,列出所有的位置,让用户自己选一个。
下午的时候跟老大说,老大竟然说我做那么快,看来以后得多分点任务。我郁闷!不过做这部分的时候,倒确实有点轻车熟路的感觉。添加对话框,给对话框添加必要的控件,给控制添加必要的消息响应,等等。以及添加新的类,在类中实现该它实现的功能。
不过又想到语法解析器,没有它,做什么都是残废的,唉,什么时候一定要抽时间实现一个。
从学校出来后,重装系统的次数大大减少,自从买了个本本,只是恢复过一次,今天是第二次,当然不算帮别人装的。
为了减少工作量,有些小小的算不上技巧的伎俩。记得第一次恢复是用的光盘,今天拿出光盘,发现读不出来了,大概是光驱的问题,于是直接选择恢复到出厂设置,反正我的恢复光盘中的内容跟出厂设置差不了多少。
选好后,可以去干点别的事,比如我就出去边吃饭边看电视去了,这样不知道总共花了多少时间,最后一直到设置机器名和用户名密码的地方,这时才需要人工介入。首先需要安装中文支持的MUI包,装完跑到控制面板里设置一下语言,使得界面上可以正常显示那些能完善支持中文的软件。
然后是安装那些必备的软件。
对于那些绿色版、免安装版、安装后更改文件夹后仍然可用的软件,则应该放在非系统分区中。这样下次恢复系统了,使用可以直接使用。比较典型的是Foxmail、QQ、Firefox(它要通过命令行参数实现)等等。
对于必须要运行安装程序才能使用的软件,则根据一般建议安装在系统分区,这样在恢复系统时,也能自动清理掉。这样软件包括Visual Studio、Office(虽然现在实际上不装这个了)等等。
接着是安装系统补丁。有个比较省事的办法,是装个360安全卫士,用它一扫描,发现所有的hotfix,自动下载自动安装,又可以去做些其他事情了。我就打了一会儿游戏,还去洗碗,整理床被等等,哈哈。
做完这些,基本上可算是恢复系统了,但实际上要花很多时间,对于我来说,似乎需要6、7个小时才能搞定!
程序终于改得主要的核心功能比较稳定了,这是最让我觉得安心的事了。这个项目无疑是到我投入时间和精力最多的项目了,中间过程也是竭尽全力、绞尽脑汁、使出全身解数,充分发扬拿来主义,使用了好几个第三方的开源代码,大概列数一下就有ACE、Boost、iconv、zlib等。眼下流行的工程方法,开发方法也被我有选择地用了一些,感觉自己的水平确实也有了一定的提高。
但是我还是对项目、对我自己并不满意,随便列举一下。
对系统的总体架构不满意,目前只有客户端,我的想法是至少要是C/S结构的,但是这样无疑会大大增加工作量,这也是眼下的无奈之举。
对系统的性能和稳定性不满意,这是代码规模稍微大了点就出现的问题,而且一直也是无能为力的,这方面要有所改进,可能会涉及到整体架构的变更。
对开发模式不满意,纯粹的乱搞方式,没有完善的流程和规范,敏捷很好,却没有实行起来。
对程序结构和编码能力不满意,有不少看起来很丑陋的设计,有不少看起来很丑陋的代码,这点基本上可以通过开发人员的主观努力慢慢提高的。
对自动化程度不满意,现在可以在每次build时自动修改资源中的版本号,每次commit后又可以通过CruiseControl自动集成最后生成安装文件,但测试却只有少量单元测试,还有崩溃报告每次只是通过邮件发送到邮箱中,照我的理解状况是有一个后台服务可以自动收集这些崩溃报告,然后自动进行分析,把尽量详细明显的分析报告提取出来,而且对于已知问题可以直接提示用户。
对持续集成程度不满意,中间的各种测试、度量功能没有好好地利用起来。比如圈复杂度度量、源代码行数度量、重复代码行度量、PCLint、单元测试等等,有的没做,有的做了却没关注。
对与客户之间的关系非常不满意,开发人员太弱势,对于需求基本上没有拒绝的权力,在我看来做了一些可有可无的功能,还做了一些愚蠢错误的设计,对于版本规划等主动权也不够。
这些是大的几点,有的是可以通过自己努力得以改进的,而有的则会涉及到其他方面的人,则只能听天由命了,呵呵。