[转载]Flash务实主义——Loading

mikel阅读(1353)

[转载]Flash务实主义——Loading « 岩屋(乐在其中).

加载形式

FLASH加载文件有两种常规方式:一种是URLLoader,可以加载文本、二进制数据或 URL 编码变量形式的数据,然后转换成简单的文本形式或值对字符串形式;一种是Loader,可以将加载的图像文件转换成BitmapData,也可以解析 SWF文件。(Socket, LocalConnection这些非常用类不在讨论范围)

加载的资源应被统一管理以方便调用和重用,管理方式一般有两种:一种是将资源全部打包进SWF;一种是加载分散资源通过配置进行管理。我将对这两种管理方式进行介绍。

资源打包成SWF

在编辑FLA文件时,我们可以导入各种图片,并为其设置链接名。除手工逐个操作外,我们可以借助JSFL进行自动化处理(请参考http://bbs.9ria.com/thread-31730-1-1.html)。

由此生成SWF后,再用Loader加载。这时候我们需要的不再是舞台上的内容,而是SWF应用域里包含资源的类。可以用Loader的 contentLoaderInfo.applicationDomain.getDefinition()方法来获得这个类,并实例化。如果在执行加载 方法时第二个参数LoaderContext设置成了ApplicationDomain.currentDomain,使得被加载的SWF与主SWF共 享同一应用域,那么直接使用getDefinitionByName ()方法也可以获得这个类。

通过new的方式就可以实例化获得的BitmapData或MovieClip类,然后使用。因此项目中要想得到一个资源,只要知道它的链接名即可。链接名是自行设定的有意义的名字,完全可以当做资源的唯一ID。

需要注意的是,new的过程就是图片解压缩的过程。处于Class状态时,图片占用的内存和SWF文件中这个图片占用的磁盘空间一致,而一旦通过 new解压成无压缩的BitmapData后,占用的内存会急剧增加。不管是PNG、JPG,还是矢量动画,new之后的体积都会比原来大得多,因此不要 随便将资源实例化后暂存。这个实例化过程理所当然是比较费时的,可能会出现卡的现象,但预先实例化,内存占用上是有很大区别的。

此外,如果选择设置LoaderContext使得全部资源加载到同一个域的话,有冲突的链接名是以先来先到的原则处理,即如果两个资源链接名相同,以先加载的对象为准。

打包成SWF有一个优点,SWF可以让JPEG支持透明通道。一般来说,JPEG压缩率高而不支持透明通道,PNG压缩率低支持透明通道。将PNG导入FLA然后设置成JPEG压缩后,就能在压缩的同时保留透明通道,可以让支持透明通道的图片体积大大减小。

打包成SWF后,加载快且易于管理,是推荐方式。但这种做法限定你必须一次性加载所有资源,不能按需加载,有一定的局限性。比较适合加载UI皮肤,以及需要立即显示的图标等等。

还有一点需要注意:SWF舞台上的内容,即使不显示出来也会消耗资源,因此请务必保证在发布时舞台为空。

资源分散加载

如果文件要按需加载,或者不希望用SWF打包增加维护成本,或者有大量文本以致于不能用FLA导入,那我们只能逐个文件加载。

因为资源可能处于不同目录,命名也不规范,也会有扩展名,这样的路径在代码中作为ID存在是不合适的。所以一般都会有一个文本配置文件,将这些文件路径和一个名称对应起来,并提供给模块加载。加载完成后则是通过这个名称来获取资源。

不要直接用Loader加载文件

不同文件有不同的加载方式,文本和二进制文件只能通过URLLoader加载,而PNG、JPG、SWF等文件则可以通过Loader和 URLLoader两种方式加载。如果资源需要长期保存,建议全部用URLLoader方式加载,在需要获取资源时,再通过Loader的 loadBytes方法解析已经加载的二进制数据,之后再显示。

这样做目的是为了节省内存,因为Loader加载的资源会自动实例化(解码),PNG、JPG会展开成无压缩的BitmapData,SWF舞台的 内容也会全部实例化,他们会占用大量内存。先用URLLoader将他们作为二进制数据加载,需要时再解码实例化,就不会出现这个问题。

并发加载

多文件加载还有一个问题:浏览器对并发下载数有限制,而这个限制和Flash Player的机制有冲突,所以一般情况下Flash Player同时发起的加载请求数最好不要超过5个, 否则加载事件可能会失效。为了解决这个问题,大部分人的解决方案都是采取队列加载,一次只加载一个文件。这在文件数量较小、单文件体积较大时并没有问题, 但是当文件数量多、单文件体积小时,由于每次加载完一个文件后,重新请求下一个文件时需要等待服务器响应一段时间才开始加载,这样会浪费很多带宽,文件数 量多时这个缺陷不能忽略,最多可能消耗2至3倍的加载时间。

为了解决这个问题,我们需要一种特殊的队列加载模块,可以同时加载,但是同时加载的文件数量不能超过某个值。基本思路就是在加载完一个文件后,检查正在进行加载的文件数量,小于定值就取队列中的下一个地址新建加载,否则就什么都不做。

BulkLoader(http://code.google.com/p/bulk-loader),

LoaderMax(http://www.greensock.com/loadermax

都提供了这个功能,当然我的GhostCat也通过AssetManager(复合QueueLoadOper实现)提供了这个功能。复杂度实际上并没有比线性加载高多少。

这样做,加载时等待服务器返回时依然有文件在下载,多个加载过程会平衡消耗带宽,带宽就不会被浪费。一般同时加载数量为2就足够了。但如果你的文件特别零散,使得两个文件同时等待返回的几率也很高,也可以考虑设置2以上的值。

哈希表缓存

当加载文件数量特别大的时候(诸如数百个),注意不要只使用数组保存。你可以创建一个Dictionary,然后将名称作为键加载内容作为值,做一个哈希表,以后都直接通过名称从这个哈希表取值,会比遍历数组查找名称快很多。

使用ZIP或其他打包形式

如果你不喜欢SWF这种打包方式,也可以选择ZIP打包,详情请阅读http://nochump.com/blog/archives/15

ZIP的优点是可以用winrar打开,不需要借助专门的工具,缺点则是解压需要时间。当然,你也可以考虑用二进制自定义一个封装格式,这样也能加密资源文件,但这需要你自己编写一个管理工具。当然,这也不算特别麻烦。

使用ShareObject缓存

虽然有浏览器缓存,但实际上这种缓存持续不了几天,因为浏览器一向都有最大缓存限制。一般你看几个视频,这个缓存空间就消耗得差不多了。为了不让 Flash加载的文件缓存被冲洗掉,你可以将加载的文件的二进制数据(Loader是 contentLoaderInfo.bytes,URLLoader则要用二进制方式加载获取其data属性)保存在ShareObject里,并添加 版本号以便更新,下次加载就直接取这个数据。这个操作会请求大量ShareObject空间,因此FLASH会弹出提示让用户确认。如果你担心用户不确 认,可以在游戏其他地方向用户说明情况并要求他们点击确认按钮。

现在不少游戏都采用了这种做法,效果还是可以的。

显示总体加载进度

我们可能在开始时会加载多个文件。比起每加载一个文件显示一次进度条从0%到100%的过程,显然是显示所有文件总体的加载进度,只进行一次从0% 到100%的过程更具有实际意义。但是FLASH做这件事情并不太容易,因为它想要获得一个文件的大小就必须去加载它,而这个加载需要时间,你没有办法从 一开始就立即获得所有文件的大小。

实现的方法只有一个,就是在程序中或者配置中写死所有文件的总大小,然后根据所有文件已经加载字节数的总和来计算和显示进度。

至于这个总和如何获得,可以在程序中写上trace,实际加载运行一次便能获得实际所有文件大小总和,也可以做专门工具计算,也可以用操作系统来直 接查看总和,总之方法不是问题。而且,即使这个值不准确也无大碍,因为加载流程依然是按加载完所有文件作为依据,而这个进度只是用来显示,就算不准也不过 是未到100%就结束或者到了100%也要等待一段时间才能结束。这无伤大雅。

之前所说的类库都提供了这样的功能。

主SWF加载问题

SWF必须加载完所有类后才能开始运行并显示图像,这样一来,第一个主SWF加载自己时就无法显示加载进度。解决这个问题有两种办法:

一种办法很老但是实用,就是创建一个小SWF先显示出来,专门用来加载主SWF,主SWF加载完毕后它就完成了使命。实际上这并不麻烦也是最稳定的一种方案。

另一种方式是利用Frame元标签。在主SWF类名上面添加

[Frame(factoryClass="加载类类名")]

即可指定一个类作为加载类,它会在主SWF未加载完之前显示。这个类是一个两帧MovieClip,当它自己加载完毕后,就可以反射出主SWF的内容并实例化。

可以看这篇文章:http://www.bit-101.com/blog/?p=946

而我自己的加载类模板则是这个,可以作为参考:

http://code.google.com/p/ghostcat/source/browse/trunk/GhostCat/src/ghostcat/util/load/RootLoaderBase.as

[转载]Js单元测试-分块延迟加载

mikel阅读(918)

[转载]Js单元测试-分块延迟加载 – zaohe – 博客园.

简介:

JS的单元测试之前写的不多,应用到项目中的更少,对待单元测试的看法,不同的程序员有不同的观点,个人感觉当项目组大了,人员流动比较频繁的时候,单元测试还是很有必要的,下面是针对前面博客中的分块延迟加载做的单元测试(感觉陌生的朋友可以先看完前面的2篇文章再来看这一篇,关联性比较大),请各位指正。

测试框架:

使用的测试框架是jasmine,一个非常简单易用的测试框架

describe(‘测试集合‘,function(){ //测试Suit

it(‘用例描述’,function(){ //测试用例1

……..

});

it(‘用例描述’,function(){}); //测试用例2

it(‘用例描述’,function(){}); //测试用例3

});

测试结果:

代码结构:

代码主要分为3部分:初始化、定位测试以及加载图片

分析以及测试用例:

1. 初始化:验证延迟加载的图片,src属性和自定义的属性是否一致。

2. 定位测试:

1) 分块处于视图中

2) 分块部分处于视图中,上部隐藏

3) 分块部分处于视图中,下部隐藏

4) 分块处于视图外,在当前视图上面

5) 分块处于视图外,在当前视图下面,但是在用户指定的额外区域内

6) 分块处于视图外,在当前视图下面,不在用户指定的额外区域内

3. 加载测试:

1) 测试当前区块在初始化时就在用户视图内

2) 滚动到当前区块,测试加载结果

测试代码示例:

1) 初始化测试:

var lazy3 = new HomeApp.groupLazyLoad({renderTo:’J_l3′,placeholder:url});

describe(‘初始化测试‘,function(){

it(‘当前区块在视图内的初始化测试‘,function(){

var viewportHeight = DOM.viewportHeight(),

container3 = S.one(‘#J_l3’),

off3 = DOM.offset(container3);

window.scrollTo(0,off3.top);   //滚动到区块

lazy3.initLazyLoad();                  //初始化

expect(true).toEqual(!lazy3.loaded); //验证是否已经初始化过

expect(0).toEqual(lazy3.lazyloadImgs.length);//未初始化图片数组是否为空

});

});

2) 定位测试(对应上面的测试用例 2-5

it(‘滚动向上,当前区块滚动出视图,不超过附加范围时‘,function(){

var container2 = S.one(‘#J_l2’),

off2 = DOM.offset(container2),

append = lazy2.APPEND_WINDOW_HEIGHT;

window.scrollTo(0,off2.top – viewportHeight -append +1);

expect(true).toEqual(lazy2._isInView());

});

3) 测试加载图片

it(‘移到当前区块,测试图片已经加载‘,function(){

var finished =false;

runs(function(){

//注册事件

lazy2.on(‘afterLoad’,loaded);

//移到区块范围

window.scrollTo(0,off2.top);

});

//等待加载完成

waitsFor(function(){

return finished;

},’未完成!‘,1200);

runs(function(){

var imgs = S.all(‘img’,’#J_l2′);

S.each(imgs,function(img){ //测试图片src恢复正常

expect(url).not.toEqual(img.getAttribute(‘src’));

});

lazy2.un(‘afterLoad’,loaded);

});

function loaded (){

finished =true;

}

});

这个用例比较复杂一点,我们在JS控制Dom过程中有些情况我们明确,函数何时执行,何时结束,特别是有些动作由事件触发。这时候需要在动作完成后通知我们,回调函数在这时候显然不合适,因此可以提供事件,也便于其他人的扩展使用。

测试心得:

前端的单元测试事实上比想象中更容易写,能做的测试也足够多,因此在一些提供给其他人使用的组件最好能够提供单元测试,便于改进和测试,后面还要写一篇能更加体现出单元测试强大的文章,大家一起不断学习不断进步。

Demo 下载

[转载]如何快速掌握一门编程语言

mikel阅读(886)

[转载]如何快速掌握一门编程语言 – 临河羡鱼 – 博客园.

学习程序设计语言是程序员看家的功夫,许多程序员边编边学,没有止境,可以说是“活到老学到老”。在语言面前,程序员永远是学生。然而,程序设计语 言是一个不断发展的技术,从机器语言到汇编语言,从低级语言到高级语言,从面向过程语言到面向对象语言,从C/S语言到B/S语言,从非垮平台语言到跨平 台跨系统语言,从纯语言到开发平台工具,真的是目不暇接。这些革命性的技术浪潮推动着程序员不断地学习新的语言以适应其发展,否则程序员将被淘汰于大浪之 后。

学习新的语言有两类人员,一类是从来没有程序设计语言基础的、没有编过程序的人;另一类是已经掌握了一门或一门以上语言,正想要学习更高版本语言或新的语言的人。对于第一类的人我且称之为新手。

新 手要学习一门程序语言,那是一张白纸,可以画出最新最美的图画,同样也可以画得乱七八糟没有美感。新手第一语言对其今后的影响是巨大的,如果学得好,则自 信心大增,对今后的发展非常有利。如果学得不好,学不下去,则对其职业生涯打击很大。新手面对众多的语言往往无从下手,第一不知道学那种语言为好,第二, 不知道如何学习,第三不知道能不能学好!
就目前而言,学习java,C#,今后想学后台学C语言都是不错的选择,OOP便于处学者快速掌握,但对 自学者来言,目前关于C#的视频太少,大多是.NET的视频,拖一下控件再讲讲特性.不利与初学者掌握C#.我就吃过这方面的亏.现在关于C的视频很多. 而且讲的很好.完全可以学完.net后再来看C,了解一下C与其他语言的不同和相同之处.有利加对OOP的认识.

只要想学,只要有职业压力,没有学不好的,只有学不到最好的

我的建议要特别注重两个要点:一是基础,二是动手能力。学语言首先要看书,然后要动手。那些认为光看书就能学会语言的是很幼稚的想法。而那种光注重编程而不注重读书的,将来一定是动手能力强而水平低的。

1) 新手不要急于求成,要把时间放长一点,先把基础知识学好,基础越扎实,今后编程水平就有可能越高。看书至少要花三个月时间。

看书主要选择计算机原理、程序设计原理,以及所学语言的相关书籍(如入最好是入门类,不要刻意地选哪本好不好,对初学者来说都是好的)三类书籍。

2) 看书中肯定要遇到各种不懂的概念,而且各种概念之间的关系也不容易理解和掌握,许多新手望而生畏,读不下去。这个时候一定要学会坚持,坚持读下去,反复读 下去,对实在不懂的概念要注意收集牢记在心。这个时候最好不要找人去解答,最好在把所有的书籍反复看完3遍之后,再去找人解答,这样就可以加深对这个问题 的理解,而且解答者也愿意回答,如果一有问题就去问,一是解答者失去了耐心,另一方面自己没有印象,容易产生依赖性。

3) 有了一定基础知识之后,就要自己去想办法安装编程环境。如何按照编程环境的要点我在《程序员需要那些具备最基础的知识和技能》中有关“流程”中已经讲过了,这里就不在赘述。

4) 开发环境安装完成后,新手就可以编写显示“hello word!”程序了。

编写这个程序目的主要是学习主程序的作用,主程序的参数入口,简单的赋值语句,显示功能调用,退出程序语句。通过这个程序完成,新手可以对编写程序流程的切声体会。

5) 接下来可以学习算术运算编程。试一试算术表达式编写,简单的可以编写一个计算器示例;复杂些可以编写一个显示日历的程序(输入年份,显示这个年份的日历),在这个阶段主要是学习函数以及函数的调用,算术运算、条件语句、循环语句、显示功能等。这些都是编程的基础。

6) 完成算术运算的学习后,可以编写更复杂的完整的程序。例如可以编写一个学生信息管理。其功能为:接受一个学生信息(例如,学号、学生姓名、班级、年龄)并把它保存在计算机中,并提供增加、删除、修改、查询功能。信息保存形式可以是文本文件,也可以是数据库。

这个阶段主要是学习变量、数据存放、文件操作、数据库操作、程序完整性等,这也是编程的基础。

7) 完成上述学习之后,程序员要学会回头梳理一下自己编过的程序,梳理一下自己已经学过的概念。可以对自己以前的程序做修改,学会不断提高自己编程水平的意识。

8) 在这着过程中若遇到问题,先看帮助。帮助不行,最好是找懂的人询问,不要自己死抠,浪费时间。上网查询也可以,但是不如问人比较直接。看书是不能解决问题的,切记!

9) 在这些都完成之后,程序员可以有目的,针对自己将要开发的内容进行相应的技术学习和准备了。

10) 编写程序的时间估计需要2-3个月。一般而言,一个新手学习一门语言需要半年左右的时间。有的可能要少一点,有的可能会多一点。但是,无论如何,最终的结果是程序员对语言有了初步的了解,可以用语言编写简单的程序了。

[转载]腾讯微博Android客户端开发——1.OAuth认证介绍

mikel阅读(1130)

[转载]腾讯微博Android客户端开发——1.OAuth认证介绍 – coolszy – 博客园.

腾讯微博是一个由腾讯推出,提供微型博客服务的类Twitter网站。在腾讯官方的软件 或网站中发布微博我们需要输入QQ号和密码,同样如果我们自己开发客户端给用户使用,我们也需要用户提供QQ号和密码,这就留下了安全隐患。不发分子可以 在程序中留下后门,获取QQ号和密码,从而进行违法操作。为了保护QQ用户的利益,提高微博开放平台的安全指数,腾讯微博API采用OAuth协议为第三 方提供接入服务,遵循[RFC-5849]规范。目前OAuth最新版本为OAuth2.0,腾讯微博API使用OAuth 1.0A版本。OAuth官网地址:http://www.oauth.net/

OAuth是什么

OAuth协议为用户资源的授权提供了一个安全的、开放而又简易的标准。与以往的授权方式不同之处是OAuth的授权不会使第三方触及到用户的帐号 信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此OAuth是安全的。同时,任何第三方都可以使用 OAuth认证服务,任何服务提供商都可以实现自身的OAuth认证服务,因而OAuth是开放的。业界提供了OAuth的多种实现如 PHP,JavaScript,Java,Ruby等各种语言开发包,大大节约了程序员的时间,因而OAuth是简易的。目前互联网很多服务如Open API,很多大头公司如Google,Yahoo,Microsoft等都提供了OAuth认证服务,这些都足以说明OAuth标准逐渐成为开放资源授权 的标准。

在官方网站的首页,可以看到下面这段简介:

An open protocol to allow secure API authorization in a simple and standard method from desktop and web applications.

大概意思是说OAuth是一种开放的协议,为桌面程序或者基于BS的web应用提供了一种简单的,标准的方式去访问需要用户授权的API服务。 OAuth类似于Flickr Auth、Google’s AuthSub[1]、Yahoo’s BBAuth、 Facebook Auth等。

OAuth认证授权具有以下特点:

1. 简单:不管是OAuth服务提供者还是应用开发者,都很容易于理解与使用;

2. 安全:没有涉及到用户密钥等信息,更安全更灵活;

3. 开放:任何服务提供商都可以实现OAuth,任何软件开发商都可以使用OAuth;

OAuth的认证流程

具体每步执行信息如下:

A. 第三方软件(我们自己开发的软件)向OAuth服务提供商请求未授权的Request Token。向Request Token URL发起请求,请求需要带上的以下参数:

B. OAuth服务提供商同意使用者的请求,并向其颁发未经用户授权的oauth_token与对应的oauth_token_secret,并返回给使用者:

C. 使用者向OAuth服务提供商请求用户授权的Request Token。向User Authorization URL发起请求,请求带上上步拿到的未授权的token与其密钥:

D. OAuth服务提供商将引导用户授权。该过程可能会提示用户,你想将哪些受保护的资源授权给该应用。此步可能会返回授权的Request Token也可能不返回。在腾讯认证过程中此过程会定位到腾讯的授权页面,要求用户输入QQ号和密码,然后选择同意或者拒绝对应用授权。授权成功后客户端 应用会在网页中给出授权码,用户需要手工将验证码输入到应用中才能完成授权流程。返回参数:

E. Request Token 授权后,使用者将向Access Token URL发起请求,将上步授权的Request Token换取成Access Token。请求的参数:

F. OAuth服务提供商同意使用者的请求,并向其颁发Access Token与对应的密钥,并返回给使用者。

G. 使用者以后就可以使用上步返回的Access Token访问用户授权的资源。

注:Access Token和Access Token Secret永远不会过期,直到用户撤销应用授权或腾讯回收您的app访问权限才会失效。

从上面的步骤可以看出,用户始终没有将其用户名与密码等信息提供给使用者(第三方软件),从而更安全。

OAuth相关术语

了解认证流程后,我们顺便了解下OAuth的一些术语的定义:

OAuth相关的三个URL

Request Token URL: 获取未授权的Request Token服务地址;

User Authorization URL: 获取用户授权的Request Token服务地址;

Access Token URL: 用授权的Request Token换取Access Token的服务地址;

OAuth相关的参数定义:

oauth_consumer_key: 使用者的ID,OAuth服务的直接使用者是开发者开发出来的应用。所以该参数值的获取一般是要去OAuth服务提供商处注册一个应用,再获取该应用的oauth_consumer_key。

oauth_consumer_secret:oauth_consumer_key对应的密钥。

oauth_signature_method: 请求串的签名方法,应用每次向OAuth三个服务地址发送请求时,必须对请求进行签名。签名的方法有:HMAC-SHA1、RSA-SHA1与PLAINTEXT等三种。

oauth_signature: 用上面的签名方法对请求的签名。

oauth_timestamp: 发起请求的时间戳,其值是距1970 00:00:00 GMT的秒数,必须是大于0的整数。本次请求的时间戳必须大于或者等于上次的时间戳。

oauth_nonce: 随机生成的字符串,用于防止请求的重放,防止外界的非法攻击。

oauth_version: OAuth的版本号,可选,其值必须为1.0。

OAuth HTTP响应代码:

HTTP 400 Bad Request 请求错误

Unsupported parameter 参数错误

Unsupported signature method 签名方法错误

Missing required parameter 参数丢失

Duplicated OAuth Protocol Parameter 参数重复

HTTP 401 Unauthorized 未授权

Invalid Consumer Key 非法key

Invalid / expired Token 失效或者非法的token

Invalid signature 签名非法

Invalid / used nonce 非法的nonce

本节课程视频下载:http://u.115.com/file/aq86f6t2

[转载]Flash Builder4.5 + BladeDS + Java 集成实例

mikel阅读(1258)

[转载]Flash Builder4.5 + BladeDS + Java 集成实例 – 2012 – 博客园.

这两天调研一个基于Flex的一个项目和JAVA的集成相关问题,网上有一些资料,不过版本不太一样,而且描述不是很全。

本文把这些内容总结一下,并把例子代码放到了网站上。

Flex是和Silverlight竞争的技术,之所以选择Flex,是由于项目的已经积累基于Flex的内容,后续的项目为了利用和发展因此在这个基础上继续进行。

工具、下载列表和安装
Eclipse 3.6.1 eclipse-jee-helios-SR2-win32.zip

http://www.eclipse.org/downloads/download.php?file=/technology/epp/downloads/release/helios/SR2/eclipse-jee-helios-SR2-win32.zip

BladeDS 3 http://opensource.adobe.com/wiki/display/blazeds/Downloads

http://flexorg.wip3.adobe.com/blazeds/3.0.x/20776/blazeds-bin-3.3.0.20776.zip

Tomcat 6 http://apache.etoak.com/tomcat/tomcat-6/v6.0.32/bin/apache-tomcat-6.0.32-windows-x86.zip
Flash Builder 4.5 http://d.subject.csdn.net/fd_a.php?f=FlashBuilder_4_LS10.exe

安装步骤:

Eclipse tomcat 软件解压到约定的目录即可运行;Flash Builder安装即可

安装完成后,运行$**\Adobe\Adobe Flash Builder 4.5\utilities\Adobe Flash Builder 4.5 Plug-in Utility.exe 安装eclipse的插件

实例

建立Web项目

其他的步骤和http://www.horochovec.com/2010/03/29/flash-builder-flex-sdk-4-java-blazeds-tutorial/ 设置一样,把blazeDS的内容加入到这个项目中,修改web.xml,添加Java类实现服务

image

建立Flex项目

类似如下建立Flex项目

image

其他的参考:http://www.horochovec.com/2010/03/29/flash-builder-flex-sdk-4-java-blazeds-tutorial/ 设计页面和服务端的交互

只要设置了正确的路径可以直接Debug 这些Flex和Java项目,参考如下:

image

以上的代码参考:

http://cid-56b433ad3d1871e3.office.live.com/self.aspx/.Public/Flex-blazeDs-java-sample.rar

参考:

http://www.horochovec.com/2010/03/29/flash-builder-flex-sdk-4-java-blazeds-tutorial/

[转载]js图片延迟加载如何实现

mikel阅读(896)

[转载]js图片延迟加载如何实现 – 新志 – 博客园.

这里延迟加载的意思是,拖动滚动条时,在图片出现在浏览器显示区域后才加载显示。

大概的实现方式是:

在页面的load没有触发之前,把所有的指定id的元素内的img放入到imgs中,将所有的图片的src值放入到一个新建的_src属性中,把src设置为指定的显示图片。

然后,在document.body的scroll事件触发时,循环计算imgs中的img元素位置是否正好在浏览器显示框范围内,如果是,则将img元素的_src属性的值赋给src,这样图片就能显示出来。

这里比较麻烦地方是,如何计算img的位置,获得元素的相对于页面的绝对位置。通常是用offsetLeft和offsetTop,但这两个属性是 元素的offsetParent指向的元素的相对位置, 如果offsetParent所指的元素是设置了浮动的或使用绝对定位,那么offsetLeft来获得绝对位置就不正确呢。

在这里我是将元素的所有父级元素的offsetTop之和来获得文档绝对位置的。

1         //取元素的页面绝对 X位置
 2         var getLeft = function(El){
 3             var left = 0;
 4             do{
 5                 left += El.offsetLeft;
 6             }while((El = El.offsetParent).nodeName != 'BODY');
 7             return left;
 8         };
 9         //取元素的页面绝对 Y位置
10         var getTop = function(El){
11             var top = 0;
12             do{
13                 top += El.offsetTop;
14             }while((El = El.offsetParent).nodeName != 'BODY');
15             return top;
16         };

在设置窗口的scroll事件时,ie使用是document.documentElement,而其他的浏览器都使用document。

接下来是要获得浏览器显示窗口现对于文档的位置,用了下面的代码来计算

1 //读取滚动条的位置和浏览器窗口的显示大小
2             var top = isGoo ? document.body.scrollTop : document.documentElement.scrollTop,
3                 left = isGoo ? document.body.scrollLeft :document.documentElement.scrollLeft,
4                 width = document.documentElement.clientWidth,
5                 height = document.documentElement.clientHeight;

谷歌浏览器要通过body来获得scrollTop,而其他浏览器通过documentElement。

最后迭代判断img的位置,并显示图片

//对所有图片进行批量判断是否在浏览器显示区域内
for(var i=0 ; i < imgs.length; i++){ var _top = getTop(imgs[i]),_left = getLeft(imgs[i]); //判断图片是否在显示区域内 if( _top >= top &&
_left >= left &&
_top <= top+height && _left <= left+width){ var _src = imgs[i].getAttribute('_src'); //如果图片已经显示,则取消赋值 if(imgs[i].src !== _src){ imgs[i].src = _src; } } } [/js]

[转载]250多个Jquery各式各样的插件

mikel阅读(1189)

[转载]250多个Jquery各式各样的插件 – 黑客很黑 – 博客园.

收藏250多个JQuery插件,包括文件上传,表单验证,表单选取框,输入框,日期,时间,颜色选取,投票,搜索,编辑器,多媒体,视频,flash,图片相关,google地图,游戏,表格,统计图,边框,圆角,背景,文字和超链接,鼠标提示和菜单导航,幻灯特效和翻转,拖放插件,XML,JSON,浏览器,对话框,确认框,CSS,AJAX以及一些其它的JQuery插件。

文件上传(File upload)
Ajax File Upload .
jQUploader .
Multiple File Upload plugin .
jQuery File Style .
Styling an input type file .
Progress Bar Plugin .

表单验证(Form Validation)
jQuery Validation .
Auto Help .
Simple jQuery form validation .
jQuery XAV – form validations .
jQuery AlphaNumeric .
Masked Input .
TypeWatch Plugin .
Text limiter for form fields .
Ajax Username Check with jQuery .

表单-选取框(Form – Select Box stuff)
jQuery Combobox .
jQuery controlled dependent (or Cascadign) Select List .
Multiple Selects .
Select box manipulation .
Select Combo Plugin .
jQuery – LinkedSelect
Auto-populate multiple select boxes .
Choose Plugin (Select Replacement) .

表单基本、输入框、选择框等(Form Basics, Input Fields, Checkboxes etc.)
jQuery Form Plugin .
jQuery-Form .
jLook Nice Forms .
jNice .
Ping Plugin .
Toggle Form Text .
ToggleVal .
jQuery Field Plugin .
jQuery Form’n Field plugin .
jQuery Checkbox manipulation .
jTagging .
jQuery labelcheck .
Overlabel .
3 state radio buttons .
ShiftCheckbox jQuery Plugin .
Watermark Input .
jQuery Checkbox (checkboxes with imags) .
jQuery SpinButton Control .
jQuery Ajax Form Builder .
jQuery Focus Fields .
jQuery Time Entry .

时间、日期和颜色选取(Time, Date and Color Picker)
jQuery UI Datepicker .
jQuery date picker plugin .
jQuery Time Picker .
Time Picker .
ClickPick .
TimePicker .
Farbtastic jQuery Color Picker Plugin .
Color Picker by intelliance.fr .

投票插件(Rating Plugins)
jQuery Star Rating Plugin .
jQuery Star Rater .
Content rater with ASP.NET, ajax and jQuery .
Half-Star Rating Plugin .

搜索插件(Search Plugins)
jQuery Suggest .
jQuery Autocomplete .
jQuery Autocomplete Mod .
jQuery Autocomplete by AjaxDaddy .
jQuery Autocomplete Plugin with HTML formatting .
jQuery Autocompleter .
AutoCompleter (Tutorial with PHP&MySQL) .
quick Search jQuery Plugin .

编辑器(Inline Edit & Editors)
jTagEditor .
WYMeditor .
jQuery jFrame .
Jeditable – edit in place plugin for jQuery .
jQuery editable .
jQuery Disable Text Select Plugin .
Edit in Place with Ajax using jQuery .
jQuery Plugin – Another In-Place Editor .
TableEditor .
tEditable – in place table editing for jQuery .

多媒体、视频、Flash等(Audio, Video, Flash, SVG, etc)
jMedia – accessible multi-media embedding .
JBEdit – Ajax online Video Editor .
jQuery MP3 Plugin .
jQuery Media Plugin .
jQuery Flash Plugin .
Embed QuickTime .
SVG Integration .

图片(Photos/Images/Galleries)
ThickBox .
jQuery lightBox plugin .
jQuery Image Strip .
jQuery slideViewer .
jQuery jqGalScroll 2.0 .
jQuery – jqGalViewII .
jQuery – jqGalViewIII .
jQuery Photo Slider .
jQuery Thumbs – easily create thumbnails .
jQuery jQIR Image Replacement .
jCarousel Lite .
jQPanView .
jCarousel .
Interface Imagebox .
Image Gallery using jQuery, Interface & Reflactions .
simple jQuery Gallery .
jQuery Gallery Module .
EO Gallery .
jQuery ScrollShow .
jQuery Cycle Plugin .
jQuery Flickr .
jQuery Lazy Load Images Plugin .
Zoomi – Zoomable Thumbnails .
jQuery Crop – crop any image on the fly .
Image Reflection .

Google地图(Google Map)
jQuery Plugin googlemaps .
jMaps jQuery Maps Framework .
jQmaps .
jQuery & Google Maps .
jQuery Maps Interface forr Google and Yahoo maps .
jQuery J Maps – by Tane Piper .

游戏(Games)
Tetris with jQuery .
jQuery Chess .
Mad Libs Word Game .
jQuery Puzzle .
jQuery Solar System (not a game but awesome jQuery Stuff) .

表格等(Tables, Grids etc.)
UI/Tablesorter .
jQuery ingrid .
jQuery Grid Plugin .
Table Filter – awesome! .
TableEditor .
jQuery Tree Tables .
Expandable “Detail” Table Rows .
Sortable Table ColdFusion Costum Tag with jQuery UI .
jQuery Bubble .
TableSorter .
Scrollable HTML Table .
jQuery column Manager Plugin .
jQuery tableHover Plugin .
jQuery columnHover Plugin .
jQuery Grid .
TableSorter plugin for jQuery .
tEditable – in place table editing for jQuery .
jQuery charToTable Plugin .
jQuery Grid Column Sizing .
jQuery Grid Row Sizing .

统计图(Charts, Presentation etc.)
jQuery Wizard Plugin.
jQuery Chart Plugin .
Bar Chart .

边框、圆角、背景(Border, Corners, Background)
jQuery Corner .
jQuery Curvy Corner .
Nifty jQuery Corner .
Transparent Corners .
jQuery Corner Gallery .
Gradient Plugin .

文字和超链接(Text and Links)
jQuery Spoiler plugin .
Text Highlighting .
Disable Text Select Plugin .
jQuery Newsticker .
Auto line-height Plugin .
Textgrad – a text gradient plugin .
LinkLook – a link thumbnail preview .
pager jQuery Plugin .
shortKeys jQuery Plugin .
jQuery Biggerlink .
jQuery Ajax Link Checker .

鼠标提示(Tooltips)
jQuery Plugin – Tooltip .
jTip – The jQuery Tool Tip .
clueTip .
BetterTip .
Flash Tooltips using jQuery .
ToolTip .

菜单和导航(Menus, Navigations)
jQuery Tabs Plugin – awesome!. [demo nested tabs .]
another jQuery nested Tab Set example (based on jQuery Tabs Plugin) .
jQuery idTabs .
jdMenu – Hierarchical Menu Plugin for jQuery .
jQuery SuckerFish Style .
jQuery Plugin Treeview .
treeView Basic .
FastFind Menu .
Sliding Menu .
Lava Lamp jQuery Menu .
jQuery iconDock .
jVariations Control Panel .
ContextMenu plugin .
clickMenu .
CSS Dock Menu .
jQuery Pop-up Menu Tutorial .
Sliding Menu .
http://stilbuero.de/jquery/tabs_3/

幻灯、翻转等(Accordions, Slide and Toggle stuff)
jQuery Plugin Accordion .
jQuery Accordion Plugin Horizontal Way .
haccordion – a simple horizontal accordion plugin for jQuery .
Horizontal Accordion by portalzine.de .
HoverAccordion .
Accordion Example from fmarcia.info .
jQuery Accordion Example .
jQuery Demo – Expandable Sidebar Menu .
Sliding Panels for jQuery .
jQuery ToggleElements .
Coda Slider .
jCarousel .
Accesible News Slider Plugin .
Showing and Hiding code Examples .
jQuery Easing Plugin .
jQuery Portlets .
AutoScroll .
Innerfade .

拖放插件(Drag and Drop)
UI/Draggables .
EasyDrag jQuery Plugin .
jQuery Portlets .
jqDnR – drag, drop resize .
Drag Demos .

XML XSL JSON Feeds
XSLT Plugin .
jQuery Ajax call and result XML parsing .
xmlObjectifier – Converts XML DOM to JSON .
jQuery XSL Transform .
jQuery Taconite – multiple Dom updates .
RSS/ATOM Feed Parser Plugin .
jQuery Google Feed Plugin .

浏览器(Browserstuff)
Wresize – IE Resize event Fix Plugin .
jQuery ifixpng .
jQuery pngFix .
Link Scrubber – removes the dotted line onfocus from links .
jQuery Perciformes – the entire suckerfish familly under one roof .
Background Iframe .
QinIE – for proper display of Q tags in IE .
jQuery Accessibility Plugin .
jQuery MouseWheel Plugin .

对话框、确认窗口(Alert, Prompt, Confirm Windows)
jQuery Impromptu .
jQuery Confirm Plugin .
jqModal .
SimpleModal .
CSSjQuery Style Switcher .
JSS – Javascript StyleSheets .
jQuery Rule – creation/manipulation of CSS Rules .
jPrintArea .

DOM、AJAX和其它jQuery插件(DOM, Ajax and other jQuery plugins)
FlyDOM .
jQuery Dimenion Plugin .
jQuery Loggin .
Metadata – extract metadata from classes, attributes, elements .
Super-tiny Client-Side Include Javascript jQuery Plugin .
Undo Made Easy with Ajax .
JHeartbeat – periodically poll the server .
Lazy Load Plugin .

[转载]Android中文合集 最终版

mikel阅读(1300)

[转载]Android中文合集 最终版 – 农民伯伯 – 博客园.

前言

本合集包含Android 141章节的API和12篇开发者指南,包含以往历次发布的合集内容。Android中文翻译组是一个非盈利性质的开源组织,聚一批开发人员、大学生、研究生等Android爱好者,利用业余时间对Android相关的API及开发者指南等进行翻译,至今已超过200人报名参与,欢迎加入,联系Mailover140@gmail.com关于翻译组的更多介绍,请看这里

声明

欢迎转载,但请保留文章原始出处:)

博客园:http://www.cnblogs.com/

Android中文翻译组:http://goo.gl/6vJQl

正文

一、截图

二、介绍

本次合集采用客户端为载体,模拟chm界面风格整理并发布。主要特点为可自动更新内容,因此本客户端可合集的终极版本,以后不再发布chm格式的合集,下面是关于客户端的一些介绍:

2.1  特点介绍

2.1.1  自动更新内容

软件启动时,客户端会检测是否联网,在联网的情况下再检测是否有新的内容可更新,有的话就直接下载到本地缓存。

2.1.2  与chm格式比较

同样具备chm的离线使用能力。不必像以往一样需要等一个月才能有新的合集,也能减少多个版本的合集导致的混乱问题。同样也没有chm打不开的问题(少量用户反映)。方便修补误翻、漏翻的内容。

2.1.3  整合资源

右上角图标方便展示译者介绍、博客以及示例代码下载、在线中文地址、WORD原稿下载。

2.2  使用方法

2.2.1  准备

客户端需要Microsoft .NET Framework 2.0,WIN7的朋友不需要安装,XP可能需要,点这里下载安装。

2.2.2  下载客户端zip包(文章末尾),解压到任意目录,双击AndroidBox.exe运行即可。经常使用的话可以右键AndroidBox.exe快捷方式到桌面,甚至是启动项。

2.2.3  关闭

点击客户端右上角关闭按钮默认操作是隐藏到右下角,右键右下角客户端图标,退出即可。

2.2.4  更新

内容更新是无提醒模式自动进行更新,下载到本地;客户端更新为自动检测,检测到更新情况下提示用户操作。

2.2.5  信箱

图中3的位置,有内容更新时会显示黄色小灯的图标,点开可以看到更新的章节内容,可直接链接查看。

2.3  兼容系统

Windows XP (32bit / 64bit)

Windows 7 (32bit / 64bit)

Windows Server 2003 (32bit)

三、共享

无论你是个人还是团队,不管是否加入我们,如果翻译Android官方相关文章,请与我们分享进度,把你翻译的章节发邮箱到over140@gmail.com ,以免重复翻译。我们的进度:这里(以“进度_”开头的Excel文件)。

四、招募组员

文档翻译员,要求:

1. 有耐心,这是一场持久战,需要大家的坚持。

2. 有态度,认真对待每一篇译稿。

3. 会英语,至少在翻译工具的帮助下能读懂英文原文。

[]审核员,要求:

1.  脾气好,审稿过程中需要和组员沟通,需要好脾气来沟通。

2.  技术好,工作经验2年以上,Android经验半年以上,对技术有自己的理解。

3.  英语好,英语6级以上,有相关翻译经验更佳。


五、 下载

AndroidBox-Beta0.3.zip

结束

客户端虽功能不多,但业余开发时间仍然非常紧张,有BUG还请大家及时反馈到over140@gmail.com,感谢大家支持。虽然我们翻译整理速度很慢,但每个脚印都是有价值,相信开源的力量!

[转载]tudou(土豆)、youku(优酷)API(有相应的dll [C#])

mikel阅读(1594)

[转载]tudou(土豆)、youku(优酷)API(有相应的dll [C#]) – SeaSunK – 博客园.

相信网上有不少的相关介绍;

先说一下怎么获取tudou的视频:

先给一个官方API,注:需要登录:

登录后去到我的应用,没的当然要创建了,主要是为了拿appkey

imageimageimage

我归纳一下:

土豆的视频分三类(普通、豆单、剧集),可以从他们提供的API里可清晰知道;

image

开发文档栏有具体说明;

普通视频的URL是这样的:www.tudou.com/programs/view/xSGVQG5Vi_M/或者www.tudou.com/programs/view/M9Ke35fBnDk/?tid=-1&aid=12667&pid=41010111&oid=100173&isNielson=0

而它的AP要求是这样的

image

主要是图中的itemCode;很幸运:普通的视频URL里就可以知道这个itemcode,聪明的你一看就知道了,就是跟在/view/__ 后面的,如上面URL里的xSGVQG5Vi_MM9Ke35fBnDk,这两个都是itemcode;

为什么上面说幸运呢,因为豆单的和剧集的就没那么好运了!在2011-06-01(呃。。。今天是6.1哦~~)为止,我还没有看到能够直接通过它的API直接拿到相关的信息;(豆单与剧集是列表形式的视频);

看下列表视频的URL:www.tudou.com/playlist/p/l12302700.html或者http://www.tudou.com/playlist/p/a66454i82719708.html或者http://www.tudou.com/playlist/p/a66506.html

说到这里,他们的API估计还没做好,因为我发现点问题,看图:

image

看绿色的框框,他们提供的API里一个是写着playlistid,而示例则是playlistCode,重点是如果API是不包括playlistCode的话根本是访问不通的,会提示

4001 : Required String parameter ‘playlistCode’ is not present

image

那这个playlistCode怎么拿到呢??(注:是最原始的URL,就是上面给的那些URL例子,因为在视频里的分享我们是可以拿到playlistCode,后面我会讲一下)

后来我查看了所有的API都没办法,因为最基本的需要就是playlistCode;

最后实在没办法了,就用了最原始的方法(分析其网页原码了,然后用正则匹配出来),后来看了原码后发现都提供了itemcode了,所以我就直接拿这个itemcode挺不是更好,也不用要拿playlistCode后还要定位某个视频(因为是列表啊);

image

拿到这个itemCode后就可以利用普通视频的API来拿相关信息了,测试结果还是挺理想的,当然这样就会向tudou请求两次了;

请求它的API时format选择了JSON,结果:

[json]
{“multiResult”:{“results”:[{“description”:”test”,”tags”:”test”,”itemId”:1000232,”channelId”:1,”mediaType”:”视频”,”totalTime”:20100,”pubDate”:”2006-04-27″,”title”:”test”,”picUrl”:”http://i1.tdimg.com/001/000/232/p.jpg”,”itemUrl”:”http://www.tudou.com/programs/view/yg8CVootoAc/”,”itemCode”:”yg8CVootoAc”,”ownerName”:”yumihhh”,”ownerNickname”:”yumihhh”,”outerPlayerUrl”:”http://www.tudou.com/v/yg8CVootoAc/v.swf”,”ownerId”:262809,”picChoiceUrl”:[“http://image2.tudou.com/data/imgs/i/001/000/232/m15.jpg”,”http://image2.tudou.com/data/imgs/i/001/000/232/m30.jpg”],”secret”:false}]}}
[/json]

上面提到的分享拿playlistCode

image

如果有人能知道列表视频的直接API,请告诉我,谢谢~~

youku的其实差不多

如果想通过youku官方提供的API就不可行了,因为我看了也是要APPKEY,关键是要合作方的,没免费注册~~或许我没看到吧,反正找不到;

不过我知道一个入口是:

http://v.youku.com/player/getPlayList/VideoIDS/XMjcxOTg0NTcy

注意这个XMjcxOTg0NTcy

youku的分类:

普通:http://v.youku.com/v_show/id_XMjcxOTU3OTk2.html

列表:http://v.youku.com/v_playlist/f6164011o1p0.html

列表的我还是通过分析其网页的原码拿这个VideoId;

image

贴个youku的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;

namespace DCC.UI.Common
{
public class YouKuApiHelper
{
private string videoApiUrl = "http://v.youku.com/player/getPlayList/VideoIDS/{0}";
private string _url;
public YouKuApiHelper(string url)
{
this._url = url;
}

private bool GetVideoId(ref string videoId)
{
Regex regShow = new Regex(@"^http:\/\/v\.youku\.com\/v_show\/id_([\w\d+_-]*)\.html|^http:\/\/v\.youku\.com\/v_show\/id_([\w\d+_-]*)=\.html", RegexOptions.IgnoreCase);
Match mShow = regShow.Match(_url);
if (mShow.Success)
{
videoId = mShow.Groups[1].Value;//Groups[0]為整個匹配對象(這裡是_url),Groups[1]才是第一個括號裡匹配的
return true;
}
else
{
Regex regList = new Regex(@"^http:\/\/v\.youku\.com\/v_playlist", RegexOptions.IgnoreCase);
if (regList.IsMatch(_url))
{
try
{
WebClient webClient = new WebClient();
string youkuHtml = Encoding.ASCII.GetString(webClient.DownloadData(_url));
Regex regHtml = new Regex(@"(?is)var\s+(videoId2)+?\s*=\s*'([\w-]+)'\s*;", RegexOptions.IgnoreCase);
Match mHtml = regHtml.Match(youkuHtml);
if (mHtml.Success)
{
videoId = mHtml.Groups[2].Value;
return true;
}
}
catch (Exception ex)
{
return false;
}
}
}
return false;
}
///
/// 根據youku的視頻URL分析再請求其API獲取視頻信息
///
///
public string GetVideoInfo()
{
try
{
string videoId = string.Empty;
if (GetVideoId(ref videoId))
{
WebClient webClient = new WebClient();
string videoInfo = Encoding.ASCII.GetString(webClient.DownloadData(string.Format(videoApiUrl, videoId)));
return videoInfo;
}
else
{ return "error"; }
}
catch (Exception ex)
{
return "error";
}
}
}

tudou Api源码下载(VS2010)

[转载]首页优化-图片延迟加载

mikel阅读(961)

[转载]首页优化-图片延迟加载 – zaohe – 博客园.

简介:

为了提高用户体验,多图片的长页面需要使用延迟加载技术,对这方面的论述,Kissy中有很经典的论述,感兴趣的朋友可以去这里了解一下(http://docs.kissyui.com/kissy/docs/datalazyload/index.html),我先简单的介绍一下,然后讨论如何改进并用于项目中。

分析:

1. Img 更换 src方案:<img data-ls-src=”真正的路径”,src=”load图片的路径”/>

优点:实现简单,不更改页面Dom结构。

缺点:图片数量大时,效率不够好;ie6ie7下替换SRC时有Bug存在。

2. textarea 延迟方案:

优点:JS效率高,分块加载

缺点:需要更改Dom结构,需要限定textarea包围区域的高度宽度,使用不够方便。

3. Kissy的实现方式:1,2两种方案都支持

1-1 延迟加载示例图

如上图所示,加载图片时有一个阀值,所有阀值以上的图片全部加载。

优点:实现简单

缺点:对一些用户行为支持不够,例如用户直接将滚动条拉到页面底部。

4. 首页分析 (lp.taobao.com)

1) 首页的长度比较长 4000*1000 以上

2) 分块展示,分为10块,1个首屏,2个滚屏,7个通用楼层

3) 每个分块比较短,不超过一屏

5. 首页延迟方案:

1) 分块加载图片

2) 滚屏中,在切换帧时触发加载

实现:

1) 打开页面,默认只显示首屏。

2) 当滚动条滚动到当前分块时(可以附加一些像素,是图片提前加载),加载当前分块

3) 7个楼层添加额外的优化,因为是同一种实现,提供一个管理器,当用户在某一个楼层上停留时间超过5秒,即可以加载未加载的楼层。

总结:

在首页的延迟加载优化过程中,尝试过多种方式。

1) 最初使用的是Kissy默认的替换src方案,发现在ie下,用户刷新页面时,会定位到上次滚动到得位置,此时用户体验特别差;

2) 尝试过textarea方案,UI体验也不好;

3) 改进了kissy的方案,不使用阀值,而是只在用户视图区域内加载图片,无法分块控制;

4) 最后分块加载图片,同时也处理了楼层初始化

改进的kissy方案和分块延迟加载的代码,连同对其的单元测试一起在后面的博客中会跟大家讨论。