<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>army8735</title>
	<atom:link href="http://army8735.org/feed" rel="self" type="application/rss+xml" />
	<link>http://army8735.org</link>
	<description>我可以A，我也可以-A，我可以同时A和-A。</description>
	<lastBuildDate>Fri, 25 Nov 2011 04:07:52 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>基于interactive机制的onload次序测试</title>
		<link>http://army8735.org/2011/11/25/1048.html</link>
		<comments>http://army8735.org/2011/11/25/1048.html#comments</comments>
		<pubDate>Fri, 25 Nov 2011 03:50:18 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[amd]]></category>
		<category><![CDATA[commonjs]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=1048</guid>
		<description><![CDATA[接上篇。ie下错位几率相对而言有些大，于是基于interactive特性进行改善。这其实反而是走回老路了～
在意想之中的是，ie下十万分之一几率的错位果然降了，而且降到了没有一个错误……webkit内核依旧保持极低概率，奇怪的是firefox在上两次中从未出现错误的先提下，这次爆出了十位数的错位。
ie6
&#8220;BbAa&#8221; &#8220;162339&#8243;
&#8220;Aa&#8221; &#8220;858130&#8243;
&#8220;Bb&#8221; &#8220;859823&#8243;
&#8220;AaBb&#8221; &#8220;1551704&#8243;
ie7
&#8220;BbAa&#8221; &#8220;40125&#8243;
&#8220;Aa&#8221; &#8220;208591&#8243;
&#8220;Bb&#8221; &#8220;208680&#8243;
&#8220;AaBb&#8221; &#8220;376486&#8243;
ie8
&#8220;BbAa&#8221; &#8220;113878&#8243;
&#8220;Bb&#8221; &#8220;622694&#8243;
&#8220;Aa&#8221; &#8220;625345&#8243;
&#8220;AaBb&#8221; &#8220;1131155&#8243;
ie9
&#8220;BbAa&#8221; &#8220;24716&#8243;
&#8220;Aa&#8221; &#8220;113455&#8243;
&#8220;Bb&#8221; &#8220;113505&#8243;
&#8220;AaBb&#8221; &#8220;201967&#8243;
ie10
&#8220;BbAa&#8221; &#8220;1&#8243;
&#8220;BbAa&#8221; &#8220;8&#8243;
&#8220;Aa&#8221; &#8220;25&#8243;
&#8220;Bb&#8221;...]]></description>
			<content:encoded><![CDATA[<p>接<a href="http://army8735.org/2011/11/19/1041.html" target="_blank">上篇</a>。ie下错位几率相对而言有些大，于是基于interactive特性进行改善。这其实反而是走回老路了～</p>
<p>在意想之中的是，ie下十万分之一几率的错位果然降了，而且降到了没有一个错误……webkit内核依旧保持极低概率，奇怪的是firefox在上两次中从未出现错误的先提下，这次爆出了十位数的错位。</p>
<div><span style="color: #ff0000;">ie6</span></div>
<div>&#8220;BbAa&#8221;<span style="white-space: pre;"> </span>&#8220;162339&#8243;</div>
<div>&#8220;Aa&#8221;<span style="white-space: pre;"> </span>&#8220;858130&#8243;</div>
<div>&#8220;Bb&#8221;<span style="white-space: pre;"> </span>&#8220;859823&#8243;</div>
<div>&#8220;AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;1551704&#8243;</div>
<div><span style="color: #ff0000;">ie7</span></div>
<div>&#8220;BbAa&#8221;<span style="white-space: pre;"> </span>&#8220;40125&#8243;</div>
<div>&#8220;Aa&#8221;<span style="white-space: pre;"> </span>&#8220;208591&#8243;</div>
<div>&#8220;Bb&#8221;<span style="white-space: pre;"> </span>&#8220;208680&#8243;</div>
<div>&#8220;AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;376486&#8243;</div>
<div><span style="color: #ff0000;">ie8</span></div>
<div>&#8220;BbAa&#8221;<span style="white-space: pre;"> </span>&#8220;113878&#8243;</div>
<div>&#8220;Bb&#8221;<span style="white-space: pre;"> </span>&#8220;622694&#8243;</div>
<div>&#8220;Aa&#8221;<span style="white-space: pre;"> </span>&#8220;625345&#8243;</div>
<div>&#8220;AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;1131155&#8243;</div>
<div><span style="color: #ff0000;">ie9</span></div>
<div>&#8220;BbAa&#8221;<span style="white-space: pre;"> </span>&#8220;24716&#8243;</div>
<div>&#8220;Aa&#8221;<span style="white-space: pre;"> </span>&#8220;113455&#8243;</div>
<div>&#8220;Bb&#8221;<span style="white-space: pre;"> </span>&#8220;113505&#8243;</div>
<div>&#8220;AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;201967&#8243;</div>
<div><span style="color: #ff0000;">ie10</span></div>
<div>&#8220;BbAa&#8221;<span style="white-space: pre;"> </span>&#8220;1&#8243;</div>
<div>&#8220;BbAa&#8221;<span style="white-space: pre;"> </span>&#8220;8&#8243;</div>
<div>&#8220;Aa&#8221;<span style="white-space: pre;"> </span>&#8220;25&#8243;</div>
<div>&#8220;Bb&#8221;<span style="white-space: pre;"> </span>&#8220;29&#8243;</div>
<div>&#8220;AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;43&#8243;</div>
<div><span style="color: #ff0000;">webkit</span></div>
<div>&#8220;ABab&#8221;<span style="white-space: pre;"> </span>&#8220;1&#8243;</div>
<div>&#8220;AbBa&#8221;<span style="white-space: pre;"> </span>&#8220;2&#8243;</div>
<div>&#8220;BAab&#8221;<span style="white-space: pre;"> </span>&#8220;3&#8243;</div>
<div>&#8220;BbAa&#8221;<span style="white-space: pre;"> </span>&#8220;53189&#8243;</div>
<div>&#8220;Bb&#8221;<span style="white-space: pre;"> </span>&#8220;261443&#8243;</div>
<div>&#8220;Aa&#8221;<span style="white-space: pre;"> </span>&#8220;261880&#8243;</div>
<div>&#8220;AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;470557&#8243;</div>
<div><span style="color: #ff0000;">ff</span></div>
<div>&#8220;ABab&#8221;<span style="white-space: pre;"> </span>&#8220;2&#8243;</div>
<div><span style="color: #ff00ff;">&#8220;AbBa&#8221;<span style="white-space: pre;"> </span>&#8220;85&#8243;</span></div>
<div>&#8220;BbAa&#8221;<span style="white-space: pre;"> </span>&#8220;5707&#8243;</div>
<div>&#8220;Aa&#8221;<span style="white-space: pre;"> </span>&#8220;36962&#8243;</div>
<div>&#8220;Bb&#8221;<span style="white-space: pre;"> </span>&#8220;36998&#8243;</div>
<div>&#8220;AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;68004&#8243;</div>
<div><span style="color: #ff0000;">opera</span></div>
<div>&#8220;ABab&#8221;<span style="white-space: pre;"> </span>&#8220;5&#8243;</div>
<div>&#8220;Bb&#8221;<span style="white-space: pre;"> </span>&#8220;3124&#8243;</div>
<div>&#8220;Aa&#8221;<span style="white-space: pre;"> </span>&#8220;3221&#8243;</div>
<div>&#8220;AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;6360&#8243;</div>
<div><span style="color: #ff0000;">other</span></div>
<div>&#8220;Bb&#8221;<span style="white-space: pre;"> </span>&#8220;1&#8243;</div>
<div>&#8220;BbAa&#8221;<span style="white-space: pre;"> </span>&#8220;1&#8243;</div>
<div>&#8220;Bb&#8221;<span style="white-space: pre;"> </span>&#8220;2&#8243;</div>
<div>&#8220;AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;2&#8243;</div>
<div>&#8220;Aa&#8221;<span style="white-space: pre;"> </span>&#8220;3&#8243;</div>
<div>&#8220;AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;5&#8243;</div>
<div>&#8220;AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;5&#8243;</div>
<div>&#8220;BbAa&#8221;<span style="white-space: pre;"> </span>&#8220;11&#8243;</div>
<div>&#8220;BbAa&#8221;<span style="white-space: pre;"> </span>&#8220;21&#8243;</div>
<div>&#8220;Aa&#8221;<span style="white-space: pre;"> </span>&#8220;76&#8243;</div>
<div>&#8220;Bb&#8221;<span style="white-space: pre;"> </span>&#8220;82&#8243;</div>
<div>&#8220;Bb&#8221;<span style="white-space: pre;"> </span>&#8220;92&#8243;</div>
<div>&#8220;Aa&#8221;<span style="white-space: pre;"> </span>&#8220;95&#8243;</div>
<div>&#8220;AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;134&#8243;</div>
<div>&#8220;AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;175&#8243;</div>
<p><span style="color: #ff0000;">8420947</span></p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2011/11/25/1048.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>错位交换算法被pass</title>
		<link>http://army8735.org/2011/11/19/1041.html</link>
		<comments>http://army8735.org/2011/11/19/1041.html#comments</comments>
		<pubDate>Sat, 19 Nov 2011 04:07:15 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[数据结构、算法]]></category>
		<category><![CDATA[amd]]></category>
		<category><![CDATA[commonjs]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=1041</guid>
		<description><![CDATA[接上篇。尽管已经降到了十万分之一级别的几率，但并发下浏览器的不靠谱行为依旧存在。IE6-8下依旧为主要因素，这与使用者人数多也有关，基数大所以数量高。另外2次幂延迟算法对于单线程情况（aA）是能够完全纠正的，这点值得欣慰。
并发时，abAB、aABb、aAbB、ABba、abBA、AbBa、aBbA、aBAb几种情况按几率依次递减，想要完美解决必须全部纠正。在2次幂延迟算法纠正后，前面3个已经正确，但后面的还是错误的，它们可以统一概括为：ABba。结果原本应该赋给A的a跑到B的身上，互相错位了，所以要进行错位交换。
理论上前期不可能再进行处理了，我耗了很久发现前期处理是个悖论，剩下的可能只有运行时决定。
在运行时：
use(['a', 'b'], function(a, b) {
	a.methodA();
	b.methodB();
});
在错位情况下，a不具有methodA方法b才具有，b也反之。此时会抛异常。简单的做法是运行时try，捕捉到异常后交换错位的arguments再运行一次。看起来似乎不错，实际陷阱重重。
首先methodA和methodB可能方法名相同，甚至逻辑极为相似。这样就不会异常但运行结果是错的。这个概率很低。
然后这是在2个参数的情况下，2个以上排列比例太多，交换次数很恐怖，不切实际。
还有这只有1级递归，也就是a和b互相颠倒而已。如果a有依赖或b有依赖，所造成的错位可能有很多，那它们之间互相递归交换非常恐怖，根本不可能实现。
即使可以通过的define进行包裹一层，抽出factory返回的方法名来提升判断callback的参数顺序准确度，但依然不能解决上述所有问题。所以最后错位交换算法被pass。
IE下，通过getInteractiveScript的方法，可能提升并发准确度到百万分之一的级别，有待验证。
]]></description>
			<content:encoded><![CDATA[<p>接<a href="http://army8735.org/2011/11/18/1034.html" target="_blank">上篇</a>。尽管已经降到了十万分之一级别的几率，但并发下浏览器的不靠谱行为依旧存在。IE6-8下依旧为主要因素，这与使用者人数多也有关，基数大所以数量高。另外2次幂延迟算法对于单线程情况（aA）是能够完全纠正的，这点值得欣慰。</p>
<p>并发时，abAB、aABb、aAbB、ABba、abBA、AbBa、aBbA、aBAb几种情况按几率依次递减，想要完美解决必须全部纠正。在2次幂延迟算法纠正后，前面3个已经正确，但后面的还是错误的，它们可以统一概括为：ABba。结果原本应该赋给A的a跑到B的身上，互相错位了，所以要进行错位交换。</p>
<p>理论上前期不可能再进行处理了，我耗了很久发现前期处理是个悖论，剩下的可能只有运行时决定。</p>
<p>在运行时：</p>
<pre class="brush:js">use(['a', 'b'], function(a, b) {
	a.methodA();
	b.methodB();
});</pre>
<p>在错位情况下，a不具有methodA方法b才具有，b也反之。此时会抛异常。简单的做法是运行时try，捕捉到异常后交换错位的arguments再运行一次。看起来似乎不错，实际陷阱重重。</p>
<p>首先methodA和methodB可能方法名相同，甚至逻辑极为相似。这样就不会异常但运行结果是错的。这个概率很低。</p>
<p>然后这是在2个参数的情况下，2个以上排列比例太多，交换次数很恐怖，不切实际。</p>
<p>还有这只有1级递归，也就是a和b互相颠倒而已。如果a有依赖或b有依赖，所造成的错位可能有很多，那它们之间互相递归交换非常恐怖，根本不可能实现。</p>
<p>即使可以通过的define进行包裹一层，抽出factory返回的方法名来提升判断callback的参数顺序准确度，但依然不能解决上述所有问题。所以最后错位交换算法被pass。</p>
<p>IE下，通过getInteractiveScript的方法，可能提升并发准确度到百万分之一的级别，有待验证。</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2011/11/19/1041.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>改进load机制后的onload次序测试</title>
		<link>http://army8735.org/2011/11/18/1034.html</link>
		<comments>http://army8735.org/2011/11/18/1034.html#comments</comments>
		<pubDate>Fri, 18 Nov 2011 03:47:19 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[amd]]></category>
		<category><![CDATA[commonjs]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=1034</guid>
		<description><![CDATA[接上篇，之前用的加载script机制有问题，同时赋予了onload = onreadystatechange，这在同时支持的浏览器（ie9）下有影响，新的方法分开对待。
other success
BAba		1
Bb		1
BbAa		1
AaBb		1
BbAa		1
BAba		1
BbAa		1
Aa		2
AaBb		2
Bb		3
Aa		3
BAba		4
ABab		4
Aa		6
BbAa		6
ABab		6
Bb		8
ABab		12
AaBb		17
Bb		23
AaBb		26
ABab		30
Aa		32
Aa		76
Bb		102
ABab		155
ie7 success
ab		1
bAa		1
a		1
BaAb		61
ABba		83
BAba		12481
BbAa		26430
AaBb		69314
Aa		201493
Bb		202091
ABab		295501
ie6 success
aBb		1
AbBa		22
BAab		89
BAba		50511
BbAa		106465
AaBb		287284
Bb		835892
Aa		836129
ABab		1227774
webkit success
ABba		2
BaAb		7
BbAa		51452
Bb		254856
Aa		255189
AaBb		454364
FF success
BAba		2
ABab		109
BbAa		5512
Bb		35757
Aa		36034
AaBb		65577
ie10 success
BbAa		4
BAba		7
AaBb		12
Bb		35
Aa		45
ABab		59
opera success
ABab		6
Bb		3077
Aa		3092
AaBb		5990
ie9 success
BaAb		8
AbBa		8
BbAa		7968
BAba		17482
AaBb		26081
Bb		109073
Aa		109478
ABab		166921
ie8 success
AbBa		16
BAab		80
BAba		31761
BbAa		84319
AaBb		241514
Bb		616614
Aa		617047
ABab		874323
出现了onload抢先exec的现象且顺序不一致，比如 CcaABb，总数：123
B		1
BaAb		7
BaAb		8
AbBa		8
AbBa		16
AbBa		22
BaAb		61
顺序不一致，比如 CcAbBa，总数：381
ab		1
aBb		1
B		1
bAa		1
a		1
ABba		2
BaAb		7
BaAb		8
AbBa		8
AbBa		16
AbBa		22
BaAb		61
BAab		80
ABba		83
BAab		89
几率381/8226030 =0.000046316388342857974，主要集中在IE6-IE8。
]]></description>
			<content:encoded><![CDATA[<p>接<a href="http://army8735.org/2011/11/17/1028.html" target="_blank">上篇</a>，之前用的加载script机制有问题，同时赋予了onload = onreadystatechange，这在同时支持的浏览器（ie9）下有影响，新的方法分开对待。</p>
<div id="_mcePaste"><span style="color: #ff0000;">other success</span></div>
<div id="_mcePaste">BAba		1</div>
<div id="_mcePaste">Bb		1</div>
<div id="_mcePaste">BbAa		1</div>
<div id="_mcePaste">AaBb		1</div>
<div id="_mcePaste">BbAa		1</div>
<div id="_mcePaste">BAba		1</div>
<div id="_mcePaste">BbAa		1</div>
<div id="_mcePaste">Aa		2</div>
<div id="_mcePaste">AaBb		2</div>
<div id="_mcePaste">Bb		3</div>
<div id="_mcePaste">Aa		3</div>
<div id="_mcePaste">BAba		4</div>
<div id="_mcePaste">ABab		4</div>
<div id="_mcePaste">Aa		6</div>
<div id="_mcePaste">BbAa		6</div>
<div id="_mcePaste">ABab		6</div>
<div id="_mcePaste">Bb		8</div>
<div id="_mcePaste">ABab		12</div>
<div id="_mcePaste">AaBb		17</div>
<div id="_mcePaste">Bb		23</div>
<div id="_mcePaste">AaBb		26</div>
<div id="_mcePaste">ABab		30</div>
<div id="_mcePaste">Aa		32</div>
<div id="_mcePaste">Aa		76</div>
<div id="_mcePaste">Bb		102</div>
<div id="_mcePaste">ABab		155</div>
<div id="_mcePaste"><span style="color: #ff0000;">ie7 success</span></div>
<div id="_mcePaste">ab		1</div>
<div id="_mcePaste">bAa		1</div>
<div id="_mcePaste">a		1</div>
<div id="_mcePaste">BaAb		61</div>
<div id="_mcePaste">ABba		83</div>
<div id="_mcePaste">BAba		12481</div>
<div id="_mcePaste">BbAa		26430</div>
<div id="_mcePaste">AaBb		69314</div>
<div id="_mcePaste">Aa		201493</div>
<div id="_mcePaste">Bb		202091</div>
<div id="_mcePaste">ABab		295501</div>
<div id="_mcePaste"><span style="color: #ff0000;">ie6 success</span></div>
<div id="_mcePaste">aBb		1</div>
<div id="_mcePaste">AbBa		22</div>
<div id="_mcePaste">BAab		89</div>
<div id="_mcePaste">BAba		50511</div>
<div id="_mcePaste">BbAa		106465</div>
<div id="_mcePaste">AaBb		287284</div>
<div id="_mcePaste">Bb		835892</div>
<div id="_mcePaste">Aa		836129</div>
<div id="_mcePaste">ABab		1227774</div>
<div id="_mcePaste"><span style="color: #ff0000;">webkit success</span></div>
<div id="_mcePaste">ABba		2</div>
<div id="_mcePaste">BaAb		7</div>
<div id="_mcePaste">BbAa		51452</div>
<div id="_mcePaste">Bb		254856</div>
<div id="_mcePaste">Aa		255189</div>
<div id="_mcePaste">AaBb		454364</div>
<div id="_mcePaste"><span style="color: #ff0000;">FF success</span></div>
<div id="_mcePaste">BAba		2</div>
<div id="_mcePaste">ABab		109</div>
<div id="_mcePaste">BbAa		5512</div>
<div id="_mcePaste">Bb		35757</div>
<div id="_mcePaste">Aa		36034</div>
<div id="_mcePaste">AaBb		65577</div>
<div id="_mcePaste"><span style="color: #ff0000;">ie10 success</span></div>
<div id="_mcePaste">BbAa		4</div>
<div id="_mcePaste">BAba		7</div>
<div id="_mcePaste">AaBb		12</div>
<div id="_mcePaste">Bb		35</div>
<div id="_mcePaste">Aa		45</div>
<div id="_mcePaste">ABab		59</div>
<div id="_mcePaste"><span style="color: #ff0000;">opera success</span></div>
<div id="_mcePaste">ABab		6</div>
<div id="_mcePaste">Bb		3077</div>
<div id="_mcePaste">Aa		3092</div>
<div id="_mcePaste">AaBb		5990</div>
<div id="_mcePaste"><span style="color: #ff0000;">ie9 success</span></div>
<div id="_mcePaste">BaAb		8</div>
<div id="_mcePaste">AbBa		8</div>
<div id="_mcePaste">BbAa		7968</div>
<div id="_mcePaste">BAba		17482</div>
<div id="_mcePaste">AaBb		26081</div>
<div id="_mcePaste">Bb		109073</div>
<div id="_mcePaste">Aa		109478</div>
<div id="_mcePaste">ABab		166921</div>
<div id="_mcePaste"><span style="color: #ff0000;">ie8 success</span></div>
<div id="_mcePaste">AbBa		16</div>
<div id="_mcePaste">BAab		80</div>
<div id="_mcePaste">BAba		31761</div>
<div id="_mcePaste">BbAa		84319</div>
<div id="_mcePaste">AaBb		241514</div>
<div id="_mcePaste">Bb		616614</div>
<div id="_mcePaste">Aa		617047</div>
<div id="_mcePaste">ABab		874323</div>
<div id="_mcePaste"><span style="color: #000080;"><strong>出现了onload抢先exec的现象且顺序不一致，比如 CcaABb，总数：123</strong></span></div>
<div id="_mcePaste">B		1</div>
<div id="_mcePaste">BaAb		7</div>
<div id="_mcePaste">BaAb		8</div>
<div id="_mcePaste">AbBa		8</div>
<div id="_mcePaste">AbBa		16</div>
<div id="_mcePaste">AbBa		22</div>
<div id="_mcePaste">BaAb		61</div>
<div id="_mcePaste"><span style="color: #000080;"><strong>顺序不一致，比如 CcAbBa，总数：381</strong></span></div>
<div id="_mcePaste">ab		1</div>
<div id="_mcePaste">aBb		1</div>
<div id="_mcePaste">B		1</div>
<div id="_mcePaste">bAa		1</div>
<div id="_mcePaste">a		1</div>
<div id="_mcePaste">ABba		2</div>
<div id="_mcePaste">BaAb		7</div>
<div id="_mcePaste">BaAb		8</div>
<div id="_mcePaste">AbBa		8</div>
<div id="_mcePaste">AbBa		16</div>
<div id="_mcePaste">AbBa		22</div>
<div id="_mcePaste">BaAb		61</div>
<div id="_mcePaste">BAab		80</div>
<div id="_mcePaste">ABba		83</div>
<div id="_mcePaste">BAab		89</div>
<div><span style="color: #ff0000;">几率381/8226030 =0.000046316388342857974，主要集中在IE6-IE8。</span></div>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2011/11/18/1034.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>采用2次幂延迟算法的onload次序测试</title>
		<link>http://army8735.org/2011/11/17/1028.html</link>
		<comments>http://army8735.org/2011/11/17/1028.html#comments</comments>
		<pubDate>Thu, 17 Nov 2011 02:53:17 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[数据结构、算法]]></category>
		<category><![CDATA[amd]]></category>
		<category><![CDATA[commonjs]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=1028</guid>
		<description><![CDATA[接上篇。另外对于基础性原理不清楚的请查看射雕的介绍：http://lifesinger.wordpress.com/2011/11/11/get-url-in-module-loader/
通过1周的海量数据多次测试与研究，我和射雕发现了所有浏览器下都有的共同bug：onload事件先于script标签的加载发生。这个结论直接表明，目前所有对于script的onload的侦听都不是完美的！一旦有了这个低几率问题，那些莫名的错误会让人十分困惑。
介于此，我尝试使用2^ delay的算法来延迟onload的运行。它的理论基础来源于抑制网络风暴的算法：即onload先检查script的exec，没有时延迟2 ^ 0单位时间后再检查、再没有延迟2 ^ 1、2 ^ 2……以此类推。
在昨天的海量观测数据下面，结果是惊喜的。没有1次发生了error，全部正确。但是依然存在低几率次序打乱的情况，这是接下来要着手解决的问题（或者干脆忽略掉）。
最后祝福下Firefox和IE10，你们的顺序是100%正确的。
other success
AaBb		1
BbAa		1
Aa		1
AaBb		1
Bb		1
BAba		1
ABab		1
BbAa		1
BAba		1
ABab		1
Aa		1
AaBb		2
BbAa		3
Aa		3
BAba		3
Bb		4
Aa		5
BbAa		8
ABab		11
Bb		12
ABab		23
AaBb		23
Aa		26
AaBb		28
Bb		28
Aa		91
Bb		97
ABab		171
opera success
BbAa		1
BAab		1
ABba		1
BaAb		1
ABab		28
Bb		2742
Aa		2783
AaBb		5484
ie8 success
ABba		2
AbBa		8
BAab		17
BaAb		29
BAba		30901
BbAa		82405
AaBb		233970
Bb		599658
Aa		600632
ABab		853122
webkit success
ABba		2
BAab		2
BaAb		4
AbBa		5
BbAa		50606
Aa		246173
Bb		246419
AaBb		441956
ie10 success
BAba		2
AaBb		8
BbAa		9
Aa		29
Bb		31
ABab		36
ie9 success
AbBa		2
BaAb		4
BAab		30
ABba		159
BAba		8915
BbAa		15603
AaBb		35080
Aa		104627
Bb		105027
ABab		149314
ie7 success
AbBa		8
BaAb		12
BAab		35
ABba		81
BAba		11900
BbAa		25614
AaBb		66317
Aa		193519
Bb		193970
ABab		282723
ie6 success
ABba		10
AbBa		14
BAab		21
BaAb		57
BAba		50272
BbAa		104528
AaBb		275505
Bb		811928
Aa		813622
ABab		1189557
FF success
ABab		90
BbAa		5578
Bb		34745
Aa		34866
AaBb		63339
]]></description>
			<content:encoded><![CDATA[<p>接<a href="http://army8735.org/2011/11/10/1019.html" target="_blank">上篇</a>。另外对于基础性原理不清楚的请查看射雕的介绍：<a href="http://lifesinger.wordpress.com/2011/11/11/get-url-in-module-loader/">http://lifesinger.wordpress.com/2011/11/11/get-url-in-module-loader/</a></p>
<p>通过1周的海量数据多次测试与研究，我和射雕发现了所有浏览器下都有的共同bug：onload事件先于script标签的加载发生。这个结论直接表明，目前所有对于script的onload的侦听都不是完美的！一旦有了这个低几率问题，那些莫名的错误会让人十分困惑。</p>
<p>介于此，我尝试使用2^ delay的算法来延迟onload的运行。它的理论基础来源于抑制网络风暴的算法：即onload先检查script的exec，没有时延迟2 ^ 0单位时间后再检查、再没有延迟2 ^ 1、2 ^ 2……以此类推。</p>
<p>在昨天的海量观测数据下面，结果是惊喜的。没有1次发生了error，全部正确。但是依然存在低几率次序打乱的情况，这是接下来要着手解决的问题（或者干脆忽略掉）。</p>
<p>最后祝福下Firefox和IE10，你们的顺序是100%正确的。</p>
<div id="_mcePaste"><span style="color: #ff0000;">other success</span></div>
<div id="_mcePaste">AaBb		1</div>
<div id="_mcePaste">BbAa		1</div>
<div id="_mcePaste">Aa		1</div>
<div id="_mcePaste">AaBb		1</div>
<div id="_mcePaste">Bb		1</div>
<div id="_mcePaste">BAba		1</div>
<div id="_mcePaste">ABab		1</div>
<div id="_mcePaste">BbAa		1</div>
<div id="_mcePaste">BAba		1</div>
<div id="_mcePaste">ABab		1</div>
<div id="_mcePaste">Aa		1</div>
<div id="_mcePaste">AaBb		2</div>
<div id="_mcePaste">BbAa		3</div>
<div id="_mcePaste">Aa		3</div>
<div id="_mcePaste">BAba		3</div>
<div id="_mcePaste">Bb		4</div>
<div id="_mcePaste">Aa		5</div>
<div id="_mcePaste">BbAa		8</div>
<div id="_mcePaste">ABab		11</div>
<div id="_mcePaste">Bb		12</div>
<div id="_mcePaste">ABab		23</div>
<div id="_mcePaste">AaBb		23</div>
<div id="_mcePaste">Aa		26</div>
<div id="_mcePaste">AaBb		28</div>
<div id="_mcePaste">Bb		28</div>
<div id="_mcePaste">Aa		91</div>
<div id="_mcePaste">Bb		97</div>
<div id="_mcePaste">ABab		171</div>
<div id="_mcePaste"><span style="color: #ff0000;">opera success</span></div>
<div id="_mcePaste">BbAa		1</div>
<div id="_mcePaste">BAab		1</div>
<div id="_mcePaste">ABba		1</div>
<div id="_mcePaste">BaAb		1</div>
<div id="_mcePaste">ABab		28</div>
<div id="_mcePaste">Bb		2742</div>
<div id="_mcePaste">Aa		2783</div>
<div id="_mcePaste">AaBb		5484</div>
<div id="_mcePaste"><span style="color: #ff0000;">ie8 success</span></div>
<div id="_mcePaste">ABba		2</div>
<div id="_mcePaste">AbBa		8</div>
<div id="_mcePaste">BAab		17</div>
<div id="_mcePaste">BaAb		29</div>
<div id="_mcePaste">BAba		30901</div>
<div id="_mcePaste">BbAa		82405</div>
<div id="_mcePaste">AaBb		233970</div>
<div id="_mcePaste">Bb		599658</div>
<div id="_mcePaste">Aa		600632</div>
<div id="_mcePaste">ABab		853122</div>
<div id="_mcePaste"><span style="color: #ff0000;">webkit success</span></div>
<div id="_mcePaste">ABba		2</div>
<div id="_mcePaste">BAab		2</div>
<div id="_mcePaste">BaAb		4</div>
<div id="_mcePaste">AbBa		5</div>
<div id="_mcePaste">BbAa		50606</div>
<div id="_mcePaste">Aa		246173</div>
<div id="_mcePaste">Bb		246419</div>
<div id="_mcePaste">AaBb		441956</div>
<div id="_mcePaste"><span style="color: #ff0000;">ie10 success</span></div>
<div id="_mcePaste">BAba		2</div>
<div id="_mcePaste">AaBb		8</div>
<div id="_mcePaste">BbAa		9</div>
<div id="_mcePaste">Aa		29</div>
<div id="_mcePaste">Bb		31</div>
<div id="_mcePaste">ABab		36</div>
<div id="_mcePaste"><span style="color: #ff0000;">ie9 success</span></div>
<div id="_mcePaste">AbBa		2</div>
<div id="_mcePaste">BaAb		4</div>
<div id="_mcePaste">BAab		30</div>
<div id="_mcePaste">ABba		159</div>
<div id="_mcePaste">BAba		8915</div>
<div id="_mcePaste">BbAa		15603</div>
<div id="_mcePaste">AaBb		35080</div>
<div id="_mcePaste">Aa		104627</div>
<div id="_mcePaste">Bb		105027</div>
<div id="_mcePaste">ABab		149314</div>
<div id="_mcePaste"><span style="color: #ff0000;">ie7 success</span></div>
<div id="_mcePaste">AbBa		8</div>
<div id="_mcePaste">BaAb		12</div>
<div id="_mcePaste">BAab		35</div>
<div id="_mcePaste">ABba		81</div>
<div id="_mcePaste">BAba		11900</div>
<div id="_mcePaste">BbAa		25614</div>
<div id="_mcePaste">AaBb		66317</div>
<div id="_mcePaste">Aa		193519</div>
<div id="_mcePaste">Bb		193970</div>
<div id="_mcePaste">ABab		282723</div>
<div id="_mcePaste"><span style="color: #ff0000;">ie6 success</span></div>
<div id="_mcePaste">ABba		10</div>
<div id="_mcePaste">AbBa		14</div>
<div id="_mcePaste">BAab		21</div>
<div id="_mcePaste">BaAb		57</div>
<div id="_mcePaste">BAba		50272</div>
<div id="_mcePaste">BbAa		104528</div>
<div id="_mcePaste">AaBb		275505</div>
<div id="_mcePaste">Bb		811928</div>
<div id="_mcePaste">Aa		813622</div>
<div id="_mcePaste">ABab		1189557</div>
<div id="_mcePaste"><span style="color: #ff0000;">FF success</span></div>
<div id="_mcePaste">ABab		90</div>
<div id="_mcePaste">BbAa		5578</div>
<div id="_mcePaste">Bb		34745</div>
<div id="_mcePaste">Aa		34866</div>
<div id="_mcePaste">AaBb		63339</div>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2011/11/17/1028.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>onload次序测试</title>
		<link>http://army8735.org/2011/11/10/1019.html</link>
		<comments>http://army8735.org/2011/11/10/1019.html#comments</comments>
		<pubDate>Thu, 10 Nov 2011 04:48:03 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[amd]]></category>
		<category><![CDATA[commonjs]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=1019</guid>
		<description><![CDATA[问题的起源是这样的：
假设加载有2个脚本A和B，而a和b则是附加在各自脚本上的onload侦听。众所周知的，IE下A加载完成exec后a并不是保证立刻触发的，非IE下正常。但是，倘若前提是A的加载完成和B的加载完成顺序确定，即A-&#62;B，那么a-&#62;b的顺序能不能得到保证？即：有可能是AaBb、ABab，但绝不可能有ABba。
自己测是发现不了问题，但显然范围太小不足以说明情况，所以我借助土豆的某个次要页面流量，做了个大范围精度测试。
目标：测出IE6、7、8、9下面的顺序情况。
理由：懂的入。
用例：用户有25%的几率加载a.js、25%的几率加载b.js、剩余50%全部加载，以此模拟出各种可能被缓存的情况——即可能先缓存a，然后再加载a和b。
数据结构：第一位的0和1标明页面是否发生error，是的话1，否的话0；后面大写字母是script标签被加载exec时记录，小写字母是其onload触发时记录；再后面数字是次数。
结果：近千万份数据，可能因对浏览器ua的判断稍稍有些误差。
error
ie6
&#8220;1Aab&#8221; &#8220;3410&#8243;
&#8220;1a&#8221; &#8220;2979&#8243;
&#8220;1b&#8221; &#8220;2901&#8243;
&#8220;1Bba&#8221; &#8220;1575&#8243;
&#8220;1Bab&#8221; &#8220;136&#8243;
&#8220;1Aba&#8221; &#8220;61&#8243;
&#8220;1&#8243; &#8220;56&#8243;
&#8220;1Aa&#8221; &#8220;12&#8243;
&#8220;1A&#8221; &#8220;10&#8243;
&#8220;1ab&#8221; &#8220;9&#8243;
&#8220;1Bb&#8221; &#8220;7&#8243;
&#8220;1ABab&#8221; &#8220;4&#8243;
&#8220;1AB&#8221; &#8220;1&#8243;
ie7
&#8220;1b&#8221; &#8220;771&#8243;
&#8220;1a&#8221; &#8220;743&#8243;
&#8220;1Aab&#8221; &#8220;738&#8243;
&#8220;1Bba&#8221; &#8220;376&#8243;
&#8220;1&#8243; &#8220;108&#8243;
&#8220;1Bab&#8221; &#8220;23&#8243;
&#8220;1Aba&#8221;...]]></description>
			<content:encoded><![CDATA[<p>问题的起源是这样的：</p>
<p>假设加载有2个脚本A和B，而a和b则是附加在各自脚本上的onload侦听。众所周知的，IE下A加载完成exec后a并不是保证立刻触发的，非IE下正常。但是，倘若前提是A的加载完成和B的加载完成顺序确定，即A-&gt;B，那么a-&gt;b的顺序能不能得到保证？即：有可能是AaBb、ABab，但绝不可能有ABba。</p>
<p>自己测是发现不了问题，但显然范围太小不足以说明情况，所以我借助土豆的某个次要页面流量，做了个大范围精度测试。</p>
<p>目标：测出IE6、7、8、9下面的顺序情况。</p>
<p>理由：懂的入。</p>
<p>用例：用户有25%的几率加载a.js、25%的几率加载b.js、剩余50%全部加载，以此模拟出各种可能被缓存的情况——即可能先缓存a，然后再加载a和b。</p>
<p>数据结构：第一位的0和1标明页面是否发生error，是的话1，否的话0；后面大写字母是script标签被加载exec时记录，小写字母是其onload触发时记录；再后面数字是次数。</p>
<p>结果：近千万份数据，<span style="color: #000000;">可能因对浏览器ua的判断稍稍有些误差。</span></p>
<p><span style="color: #ff0000;">error</span></p>
<p><span style="color: #0000ff;">ie6</span></p>
<p>&#8220;1Aab&#8221;<span style="white-space: pre;"> </span>&#8220;3410&#8243;</p>
<p>&#8220;1a&#8221;<span style="white-space: pre;"> </span>&#8220;2979&#8243;</p>
<p>&#8220;1b&#8221;<span style="white-space: pre;"> </span>&#8220;2901&#8243;</p>
<p>&#8220;1Bba&#8221;<span style="white-space: pre;"> </span>&#8220;1575&#8243;</p>
<p>&#8220;1Bab&#8221;<span style="white-space: pre;"> </span>&#8220;136&#8243;</p>
<p>&#8220;1Aba&#8221;<span style="white-space: pre;"> </span>&#8220;61&#8243;</p>
<p>&#8220;1&#8243;<span style="white-space: pre;"> </span>&#8220;56&#8243;</p>
<p>&#8220;1Aa&#8221;<span style="white-space: pre;"> </span>&#8220;12&#8243;</p>
<p>&#8220;1A&#8221;<span style="white-space: pre;"> </span>&#8220;10&#8243;</p>
<p>&#8220;1ab&#8221;<span style="white-space: pre;"> </span>&#8220;9&#8243;</p>
<p>&#8220;1Bb&#8221;<span style="white-space: pre;"> </span>&#8220;7&#8243;</p>
<p>&#8220;1ABab&#8221;<span style="white-space: pre;"> </span>&#8220;4&#8243;</p>
<p>&#8220;1AB&#8221;<span style="white-space: pre;"> </span>&#8220;1&#8243;</p>
<p><span style="color: #0000ff;">ie7</span></p>
<p>&#8220;1b&#8221;<span style="white-space: pre;"> </span>&#8220;771&#8243;</p>
<p>&#8220;1a&#8221;<span style="white-space: pre;"> </span>&#8220;743&#8243;</p>
<p>&#8220;1Aab&#8221;<span style="white-space: pre;"> </span>&#8220;738&#8243;</p>
<p>&#8220;1Bba&#8221;<span style="white-space: pre;"> </span>&#8220;376&#8243;</p>
<p>&#8220;1&#8243;<span style="white-space: pre;"> </span>&#8220;108&#8243;</p>
<p>&#8220;1Bab&#8221;<span style="white-space: pre;"> </span>&#8220;23&#8243;</p>
<p>&#8220;1Aba&#8221;<span style="white-space: pre;"> </span>&#8220;15&#8243;</p>
<p>&#8220;1Bb&#8221;<span style="white-space: pre;"> </span>&#8220;10&#8243;</p>
<p>&#8220;1Aa&#8221;<span style="white-space: pre;"> </span>&#8220;3&#8243;</p>
<p>&#8220;1ABab&#8221;<span style="white-space: pre;"> </span>&#8220;1&#8243;</p>
<p><span style="color: #0000ff;">ie8</span></p>
<p>&#8220;1Aab&#8221;<span style="white-space: pre;"> </span>&#8220;2460&#8243;</p>
<p>&#8220;1a&#8221;<span style="white-space: pre;"> </span>&#8220;2050&#8243;</p>
<p>&#8220;1b&#8221;<span style="white-space: pre;"> </span>&#8220;1887&#8243;</p>
<p>&#8220;1Bba&#8221;<span style="white-space: pre;"> </span>&#8220;1290&#8243;</p>
<p>&#8220;1&#8243;<span style="white-space: pre;"> </span>&#8220;322&#8243;</p>
<p>&#8220;1Bab&#8221;<span style="white-space: pre;"> </span>&#8220;95&#8243;</p>
<p>&#8220;1Aba&#8221;<span style="white-space: pre;"> </span>&#8220;39&#8243;</p>
<p>&#8220;1Aa&#8221;<span style="white-space: pre;"> </span>&#8220;20&#8243;</p>
<p>&#8220;1Bb&#8221;<span style="white-space: pre;"> </span>&#8220;11&#8243;</p>
<p>&#8220;1ABab&#8221;<span style="white-space: pre;"> </span>&#8220;1&#8243;</p>
<p><span style="color: #0000ff;">ie9</span></p>
<p>&#8220;1Aab&#8221;<span style="white-space: pre;"> </span>&#8220;372&#8243;</p>
<p>&#8220;1a&#8221;<span style="white-space: pre;"> </span>&#8220;321&#8243;</p>
<p>&#8220;1b&#8221;<span style="white-space: pre;"> </span>&#8220;285&#8243;</p>
<p>&#8220;1Bba&#8221;<span style="white-space: pre;"> </span>&#8220;218&#8243;</p>
<p>&#8220;1Bab&#8221;<span style="white-space: pre;"> </span>&#8220;10&#8243;</p>
<p>&#8220;1Aba&#8221;<span style="white-space: pre;"> </span>&#8220;6&#8243;</p>
<p>&#8220;1&#8243;<span style="white-space: pre;"> </span>&#8220;1&#8243;</p>
<p>&#8220;1Bb&#8221;<span style="white-space: pre;"> </span>&#8220;1&#8243;</p>
<p><span style="color: #ff0000;">success</span></p>
<p><span style="color: #0000ff;">ie6</span></p>
<p>&#8220;0ABab&#8221;<span style="white-space: pre;"> </span>&#8220;1591785&#8243;</p>
<p>&#8220;0Bb&#8221;<span style="white-space: pre;"> </span>&#8220;1093518&#8243;</p>
<p>&#8220;0Aa&#8221;<span style="white-space: pre;"> </span>&#8220;1093213&#8243;</p>
<p>&#8220;0AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;373421&#8243;</p>
<p>&#8220;0BbAa&#8221;<span style="white-space: pre;"> </span>&#8220;137775&#8243;</p>
<p>&#8220;0BAba&#8221;<span style="white-space: pre;"> </span>&#8220;79495&#8243;</p>
<p>&#8220;0ABba&#8221;<span style="white-space: pre;"> </span>&#8220;4&#8243;</p>
<p>&#8220;0ab&#8221;<span style="white-space: pre;"> </span>&#8220;1&#8243;</p>
<p>&#8220;0aBb&#8221;<span style="white-space: pre;"> </span>&#8220;1&#8243;</p>
<p>&#8220;0BaAb&#8221;<span style="white-space: pre;"> </span>&#8220;1&#8243;</p>
<p><span style="color: #0000ff;">ie7</span></p>
<p>&#8220;0ABab&#8221;<span style="white-space: pre;"> </span>&#8220;371165&#8243;</p>
<p>&#8220;0Aa&#8221;<span style="white-space: pre;"> </span>&#8220;257674&#8243;</p>
<p>&#8220;0Bb&#8221;<span style="white-space: pre;"> </span>&#8220;257001&#8243;</p>
<p>&#8220;0AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;88582&#8243;</p>
<p>&#8220;0BbAa&#8221;<span style="white-space: pre;"> </span>&#8220;33734&#8243;</p>
<p>&#8220;0BAba&#8221;<span style="white-space: pre;"> </span>&#8220;20710&#8243;</p>
<p>&#8220;0ABba&#8221;<span style="white-space: pre;"> </span>&#8220;108&#8243;</p>
<p>&#8220;0BAab&#8221;<span style="white-space: pre;"> </span>&#8220;23&#8243;</p>
<p>&#8220;0BaAb&#8221;<span style="white-space: pre;"> </span>&#8220;2&#8243;</p>
<p><span style="color: #0000ff;">ie8</span></p>
<p>&#8220;0ABab&#8221;<span style="white-space: pre;"> </span>&#8220;1108442&#8243;</p>
<p>&#8220;0Aa&#8221;<span style="white-space: pre;"> </span>&#8220;794383&#8243;</p>
<p>&#8220;0Bb&#8221;<span style="white-space: pre;"> </span>&#8220;792879&#8243;</p>
<p>&#8220;0AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;313784&#8243;</p>
<p>&#8220;0BbAa&#8221;<span style="white-space: pre;"> </span>&#8220;108791&#8243;</p>
<p>&#8220;0BAba&#8221;<span style="white-space: pre;"> </span>&#8220;54147&#8243;</p>
<p>&#8220;0ABba&#8221;<span style="white-space: pre;"> </span>&#8220;4&#8243;</p>
<p>&#8220;0BaAb&#8221;<span style="white-space: pre;"> </span>&#8220;1&#8243;</p>
<p><span style="color: #0000ff;">ie9</span></p>
<p>&#8220;0ABab&#8221;<span style="white-space: pre;"> </span>&#8220;188309&#8243;</p>
<p>&#8220;0Aa&#8221;<span style="white-space: pre;"> </span>&#8220;132499&#8243;</p>
<p>&#8220;0Bb&#8221;<span style="white-space: pre;"> </span>&#8220;131587&#8243;</p>
<p>&#8220;0AaBb&#8221;<span style="white-space: pre;"> </span>&#8220;44003&#8243;</p>
<p>&#8220;0BbAa&#8221;<span style="white-space: pre;"> </span>&#8220;19110&#8243;</p>
<p>&#8220;0BAba&#8221;<span style="white-space: pre;"> </span>&#8220;12620&#8243;</p>
<p>&#8220;0ABba&#8221;<span style="white-space: pre;"> </span>&#8220;211&#8243;</p>
<p>&#8220;0BAab&#8221;<span style="white-space: pre;"> </span>&#8220;40&#8243;</p>
<p>补张同事做的图：<a href="http://army8735.org/wp-content/uploads/2011/11/111.jpg"><img class="aligncenter size-full wp-image-1026" title="111" src="http://army8735.org/wp-content/uploads/2011/11/111.jpg" alt="" width="1149" height="619" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2011/11/10/1019.html/feed</wfw:commentRss>
		<slash:comments>28</slash:comments>
		</item>
		<item>
		<title>基于amd规范的自动化版本及智能依赖构建系统实验报告</title>
		<link>http://army8735.org/2011/09/06/1006.html</link>
		<comments>http://army8735.org/2011/09/06/1006.html#comments</comments>
		<pubDate>Tue, 06 Sep 2011 08:08:36 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[amd]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=1006</guid>
		<description><![CDATA[实验前提是了解amd规范：http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition，国内很多社区或个人或公司或开源项目都已有一些具体实现，不再赘述。
另外，这里只有概念，不涉及具体算法和代码。
版本控制
土豆网现有的js版本控制逻辑是为每个更新发布的js文件自动更新版本号，它以下划线+版本号数字为文件名结尾（不包括后缀名）：

而在amd中，我们自己实现的异步加载模块机制，譬如说是个use方法，需要使用a.js这个模块。那么不可能每更新一次a.js，所有使用到它的地方都手动改为use(&#8216;a_2.js&#8217;)。
实际情况是：源代码里一直写的是use(&#8216;a.js&#8217;)，至于版本控制，它是在服务器端自动追加的：

红色字体部分需要特殊解释一下，它并不是正则替换掉所有use(&#8216;a.js&#8217;)的地方，而是做了一个映射或者说路由。以a.js为key、a_2.js为value存入一个HashMap中，然后use(&#8216;a.js&#8217;)方法执行时读取到映射关系，将key转换为value后再加载。
这样做的好处是既不影响规范的id语义，又屏蔽了版本号对开发人员的细节可见度，甚至当迫不得已时想使用某个古老版本亦可：use(&#8216;a_1.js&#8217;)——因为匹配不到映射关系，所以会直接加载a_1.js这个模块。
智能依赖构建
有时候一个页面上的js要使用到多个模块，为了节省请求数量，我们希望将多个模块合并到这一个js中。为此引入了@import语法，它以注释形式出现在文件头部，服务器端构建工具会自动将导入的js文件合并到一起。这个过程是递归的，也就是说会导入可能所有需要导入的子孙文件。
事实上，这个方法早已屡见不鲜，很多构建工具都是这样做的，只是大部分都是客户端构建，由开发人员手动打包文件后发布。将这一过程移植到服务器端可省却许多不必要的麻烦。
值得一提的是，打包构建会影响到版本映射时的逻辑。譬如我们use(&#8216;a.js&#8217;)，但a.js已经被导入到当前文件中了，因此映射逻辑会忽视掉它——这个id的模块已经存在，不会再去异步加载了，映射还有什么用呢？
更进一步
手动导入其实不仅仅限于导入依赖或者导入模块，导入其它不相关的东西都行。有时候，在使用一个模块时，这个模块有依赖、依赖的模块还会继续依赖……我们希望一下子全部导入所有依赖到这个文件，而不想手动@import。较好的做法是增加一个关键字比如@build，它会递归将所有依赖打包到一个文件中。
这个步骤我还没有做。
是否需要final
经过讨论有这样一个观点：a.js被b.js和c.js所依赖，a.js更新后原本b和c都会自动追加版本映射（如果是导入则自动更新导入），但是c并不想随之自动更新，c想等自己文件有更新后才去更新导入和依赖的东西，因此需要增加一个@final关键字指定。
经过思考我觉得它带来的好处和带来的坏处一样多：构建和版本映射系统将变得复杂； 阅读维护上增加歧义；等c下次更新时你可能已经忘记了依赖的哪些模块上次没有自动更新。所以这个指令还是不要的好，每次更新一个模块后，所有依赖和导入的都随之自动更新，由测试人员在测试环境根据文件列表全部测试到位。
实际上我们也应该这样做，一个底层的被大量依赖的模块必须经过严格的测试，它被设计成被大量依赖的说明它是全局性的，即使不存在于amd中也是被写成全局代码，在更新时一样要测试到位。
允许并存
开发人员手动合并还存在一种冲突现象：这个页面用到了a.js和b.js，一个人改了a另外一个人改了b，他俩在发布测试环境时会互相覆盖对方的结果。服务器端智能构建可以很好的解决这一问题：一个人发a的源文件而另外一个人发b的源文件，同时在测试环境测试；a测试完成后a发布上线即可，不会发布到b，反之亦然。
甚至某个模块想要设计时也可以是“平滑过渡”的。试想由于某些原因，底层模块a要升级了，但并不是所有地方都兼容新版本，此时我们可以新建个底层模块a2作为新版本，兼容的地方手动替换a2，不兼容的继续使用a。这得益于模块化的松耦合特性。
单元测试
有了模块化之后，单元测试便有了前提。具体怎么测试就不探讨了，这是属于测试人员的范畴。至于为什么说有了前提，那是因为所有模块文件都是异步加载的，在线上环境可能被合并构建成了一个文件，但是只要将全部js代理成源代码（源代码里只写了类似@import的东西，并没有合并，合并是在服务器端最后发布做的），所有导入都变成异步加载了，这有利于分离调试并定位错误。
]]></description>
			<content:encoded><![CDATA[<p>实验前提是了解amd规范：<a href="http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition">http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition</a>，国内很多社区或个人或公司或开源项目都已有一些具体实现，不再赘述。</p>
<p>另外，这里只有概念，不涉及具体算法和代码。</p>
<h3>版本控制</h3>
<p>土豆网现有的js版本控制逻辑是为每个更新发布的js文件自动更新版本号，它以<span style="color: #ff0000;">下划线+版本号数字</span>为文件名结尾（不包括后缀名）：</p>
<p><a href="http://army8735.org/wp-content/uploads/2011/09/1.png"><img class="aligncenter size-full wp-image-1009" title="1" src="http://army8735.org/wp-content/uploads/2011/09/1.png" alt="" width="370" height="237" /></a></p>
<p>而在amd中，我们自己实现的异步加载模块机制，譬如说是个use方法，需要使用a.js这个模块。那么不可能每更新一次a.js，所有使用到它的地方都手动改为<span style="color: #ff0000;">use(&#8216;a_2.js&#8217;)</span>。</p>
<p>实际情况是：源代码里一直写的是<span style="color: #ff0000;">use(&#8216;a.js&#8217;)</span>，至于版本控制，它是在服务器端自动追加的：</p>
<p><a href="http://army8735.org/wp-content/uploads/2011/09/2.png"><img class="aligncenter size-full wp-image-1010" title="2" src="http://army8735.org/wp-content/uploads/2011/09/2.png" alt="" width="475" height="416" /></a></p>
<p>红色字体部分需要特殊解释一下，它并不是正则替换掉所有use(&#8216;a.js&#8217;)的地方，而是做了一个映射或者说路由。以<span style="color: #ff0000;">a.js</span>为key、<span style="color: #ff0000;">a_2.js</span>为value存入一个HashMap中，然后use(&#8216;a.js&#8217;)方法执行时读取到映射关系，将key转换为value后再加载。</p>
<p>这样做的好处是既不影响规范的id语义，又屏蔽了版本号对开发人员的细节可见度，甚至当迫不得已时想使用某个古老版本亦可：<span style="color: #ff0000;">use(&#8216;a_1.js&#8217;)</span>——因为匹配不到映射关系，所以会直接加载a_1.js这个模块。</p>
<h3>智能依赖构建</h3>
<p>有时候一个页面上的js要使用到多个模块，为了节省请求数量，我们希望将多个模块合并到这一个js中。为此引入了<span style="color: #ff0000;">@import</span>语法，它以注释形式出现在文件头部，服务器端构建工具会自动将导入的js文件合并到一起。这个过程是递归的，也就是说会导入可能所有需要导入的子孙文件。</p>
<p>事实上，这个方法早已屡见不鲜，很多构建工具都是这样做的，只是大部分都是客户端构建，由开发人员手动打包文件后发布。将这一过程移植到服务器端可省却许多不必要的麻烦。</p>
<p>值得一提的是，打包构建会影响到版本映射时的逻辑。譬如我们use(&#8216;a.js&#8217;)，但a.js已经被导入到当前文件中了，因此映射逻辑会忽视掉它——这个id的模块已经存在，不会再去异步加载了，映射还有什么用呢？</p>
<h3>更进一步</h3>
<p>手动导入其实不仅仅限于导入依赖或者导入模块，导入其它不相关的东西都行。有时候，在使用一个模块时，这个模块有依赖、依赖的模块还会继续依赖……我们希望一下子全部导入所有依赖到这个文件，而不想手动@import。较好的做法是增加一个关键字比如<span style="color: #ff0000;">@build</span>，它会递归将所有依赖打包到一个文件中。</p>
<p>这个步骤我还没有做。</p>
<h3>是否需要final</h3>
<p>经过讨论有这样一个观点：a.js被b.js和c.js所依赖，a.js更新后原本b和c都会自动追加版本映射（如果是导入则自动更新导入），但是c并不想随之自动更新，c想等自己文件有更新后才去更新导入和依赖的东西，因此需要增加一个<span style="color: #ff0000;">@final</span>关键字指定。</p>
<p>经过思考我觉得它<strong>带来的好处和带来的坏处一样多</strong>：构建和版本映射系统将变得复杂； 阅读维护上增加歧义；等c下次更新时你可能已经忘记了依赖的哪些模块上次没有自动更新。所以这个指令还是不要的好，每次更新一个模块后，所有依赖和导入的都随之自动更新，由测试人员在测试环境根据文件列表全部测试到位。</p>
<p>实际上我们也应该这样做，一个底层的被大量依赖的模块必须经过严格的测试，它被设计成被大量依赖的说明它是全局性的，即使不存在于amd中也是被写成全局代码，在更新时一样要测试到位。</p>
<h3>允许并存</h3>
<p>开发人员手动合并还存在一种冲突现象：这个页面用到了a.js和b.js，一个人改了a另外一个人改了b，他俩在发布测试环境时会互相覆盖对方的结果。服务器端智能构建可以很好的解决这一问题：一个人发a的源文件而另外一个人发b的源文件，同时在测试环境测试；a测试完成后a发布上线即可，不会发布到b，反之亦然。</p>
<p>甚至某个模块想要设计时也可以是“平滑过渡”的。试想由于某些原因，底层模块a要升级了，但并不是所有地方都兼容新版本，此时我们可以新建个底层模块a2作为新版本，兼容的地方手动替换a2，不兼容的继续使用a。这得益于模块化的松耦合特性。</p>
<h3>单元测试</h3>
<p>有了模块化之后，单元测试便有了前提。具体怎么测试就不探讨了，这是属于测试人员的范畴。至于为什么说有了前提，那是因为所有模块文件都是异步加载的，在线上环境可能被合并构建成了一个文件，但是只要将全部js代理成源代码（源代码里只写了类似@import的东西，并没有合并，合并是在服务器端最后发布做的），所有导入都变成异步加载了，这有利于分离调试并定位错误。</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2011/09/06/1006.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>改进了下jq的html5form插件</title>
		<link>http://army8735.org/2011/08/23/1000.html</link>
		<comments>http://army8735.org/2011/08/23/1000.html#comments</comments>
		<pubDate>Tue, 23 Aug 2011 07:13:56 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[form]]></category>
		<category><![CDATA[html5]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=1000</guid>
		<description><![CDATA[以前写过一个旧版本的，现在做了不少变化，最主要修改是分离出2个文件：html5formcore.js和html5form.js。前者用以模拟不支持的低版本浏览器行为，后者则是在其基础上与ui相关的部分。另外也增加了submit类型的各种属性，取消了浏览器默认的表现行为。
以下便是2个版本，第一个没有ui，第二个基于前者小弄了个ui上去。说明和源码都在链接页面里。
http://army8735.org/Ai/test/html5formcore.html
http://army8735.org/Ai/test/html5form.html
&#8212;
已经修改为晚绑定，这意味着即使元素是后添加进来的，也可以完全模拟html5元素的特性。另外改写使得其对jq1.4版本也有兼容。
]]></description>
			<content:encoded><![CDATA[<p>以前写过一个旧版本的，现在做了不少变化，最主要修改是分离出2个文件：html5formcore.js和html5form.js。前者用以模拟不支持的低版本浏览器行为，后者则是在其基础上与ui相关的部分。另外也增加了submit类型的各种属性，取消了浏览器默认的表现行为。</p>
<p>以下便是2个版本，第一个没有ui，第二个基于前者小弄了个ui上去。说明和源码都在链接页面里。</p>
<p><a href="http://army8735.org/Ai/test/html5formcore.html">http://army8735.org/Ai/test/html5formcore.html</a></p>
<p><a href="http://army8735.org/Ai/test/html5form.html">http://army8735.org/Ai/test/html5form.html</a></p>
<p>&#8212;</p>
<p>已经修改为晚绑定，这意味着即使元素是后添加进来的，也可以完全模拟html5元素的特性。另外改写使得其对jq1.4版本也有兼容。</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2011/08/23/1000.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>jssc5.1中的匹配模式</title>
		<link>http://army8735.org/2011/08/17/991.html</link>
		<comments>http://army8735.org/2011/08/17/991.html#comments</comments>
		<pubDate>Wed, 17 Aug 2011 09:59:47 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[jssc]]></category>
		<category><![CDATA[jssc5]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=991</guid>
		<description><![CDATA[预览：http://jssc.googlecode.com/svn/trunk/jssc5/bin/index.html
下载：http://code.google.com/p/jssc/downloads/list
源码：http://jssc.googlecode.com/svn/trunk/jssc5/src/
好久不动，都生疏了。离上次5.1alpha版有好几个月了，今天释出beta版，添加了Python语法。
之前说过5.1版本最大的变动是使得添加新的语法变得更加容易，老的5.0版每个新语言都得写个词法分析器太累了，于是乎花大精力修改这一部分，添加了“匹配模式”类，用以方便添加新语法解析。
匹配模式的概念
简单地说，匹配模式就是描述某个语言基本词法单元（Token）的规则。以javascript举例，需要高亮的Token大致有注释、字符串、正则表达式、数字、关键字。其中关键字属于Word中的保留字。注释的匹配模式就是以/*开头*/结尾的代码、字符串是指引号之间的内容等等。
现有的几种匹配模式
所有匹配模式都实现IMatch接口，我目前定义了以下几种：CharacterSet、CompleteEqual、LinearSearch、LinearParse、IDMatch、RegularMatch。
CharacterSet 是个字符集匹配，它定义了Token以什么字符集为开头并以什么字符集为组成内容。比如js中的Word是以下划线、美元符号、字母为开头，下划线、美元符号、字母和数字为组成内容。出于初期设计的原因，字符集不能完全自定义，只能使用已经定义的若干常量。这个缺陷会在以后考虑。
CompleteEqual 是最简单的全等匹配，只有完全相等时才会匹配成功。在js中我用全等来查找花括号和圆括号，因为它们要参与计算深度（折叠功能）。
LinearSearch 线性查找，寻找以什么字符串为开头和结尾的内容。js中注释是以此实现的。注释是以/*开头*/结尾、或者//开头行末结尾。
LinearParse 线性分析和线性查找很像，只是它多了判断转义的逻辑，性能稍稍差一些。js中字符串是以此实现的。字符串以引号开始引号结束，但是结尾的引号可能存在转义的情况，字符串中也可能出现转义符，需要特殊对待。
IDMatch ID匹配和线性查找也有点相似，它定义了以什么字符串为开头，然后匹配一个正则表达式结果。js中并没有直接用到，但其实注释部分也可以用它来实现：以//为开头，匹配的正则表达式是//[^\n]*。至于为什么不用ID匹配来实现呢，那是因为正则的消耗比较大，为性能考虑才使用的线性查找。事实上只要是能用线性查找替换的地方，都应该这样做。
RegularMatch 看名字就知道这是终极解决方案了，和IDMatch的差异也只在于定义开头也是个正则。最消耗的方案。我根本没有用到它，放在那里有备无患而已。
ecmascript的示例
以下是用来解析js、as等语言的定义类文件：
package lexer.rule {
	/**
	 * ...
	 * @author army8735
	 */
	import lexer.*;
	import lexer.depth.*;
	import lexer.match.*;

	public class EcmascriptRule...]]></description>
			<content:encoded><![CDATA[<p>预览：<a href="http://jssc.googlecode.com/svn/trunk/jssc5/bin/index.html">http://jssc.googlecode.com/svn/trunk/jssc5/bin/index.html</a></p>
<p>下载：<a href="http://code.google.com/p/jssc/downloads/list">http://code.google.com/p/jssc/downloads/list</a></p>
<p>源码：<a href="http://jssc.googlecode.com/svn/trunk/jssc5/src/">http://jssc.googlecode.com/svn/trunk/jssc5/src/</a></p>
<p>好久不动，都生疏了。离上次5.1alpha版有好几个月了，今天释出beta版，添加了Python语法。</p>
<p>之前说过5.1版本最大的变动是使得添加新的语法变得更加容易，老的5.0版每个新语言都得写个词法分析器太累了，于是乎花大精力修改这一部分，添加了“匹配模式”类，用以方便添加新语法解析。</p>
<h3>匹配模式的概念</h3>
<p>简单地说，匹配模式就是描述某个语言基本词法单元（Token）的规则。以javascript举例，需要高亮的Token大致有注释、字符串、正则表达式、数字、关键字。其中关键字属于Word中的保留字。注释的匹配模式就是以/*开头*/结尾的代码、字符串是指引号之间的内容等等。</p>
<h3>现有的几种匹配模式</h3>
<p>所有匹配模式都实现IMatch接口，我目前定义了以下几种：CharacterSet、CompleteEqual、LinearSearch、LinearParse、IDMatch、RegularMatch。</p>
<p><span style="color: #ff0000;">CharacterSet</span> 是个字符集匹配，它定义了Token以什么字符集为开头并以什么字符集为组成内容。比如js中的Word是以下划线、美元符号、字母为开头，下划线、美元符号、字母和数字为组成内容。出于初期设计的原因，字符集不能完全自定义，只能使用已经定义的若干常量。这个缺陷会在以后考虑。</p>
<p><span style="color: #ff0000;">CompleteEqual</span> 是最简单的全等匹配，只有完全相等时才会匹配成功。在js中我用全等来查找花括号和圆括号，因为它们要参与计算深度（折叠功能）。</p>
<p><span style="color: #ff0000;">LinearSearch</span> 线性查找，寻找以什么字符串为开头和结尾的内容。js中注释是以此实现的。注释是以/*开头*/结尾、或者//开头行末结尾。</p>
<p><span style="color: #ff0000;">LinearParse</span> 线性分析和线性查找很像，只是它多了判断转义的逻辑，性能稍稍差一些。js中字符串是以此实现的。字符串以引号开始引号结束，但是结尾的引号可能存在转义的情况，字符串中也可能出现转义符，需要特殊对待。</p>
<p><span style="color: #ff0000;">IDMatch</span> ID匹配和线性查找也有点相似，它定义了以什么字符串为开头，然后匹配一个正则表达式结果。js中并没有直接用到，但其实注释部分也可以用它来实现：以//为开头，匹配的正则表达式是//[^\n]*。至于为什么不用ID匹配来实现呢，那是因为正则的消耗比较大，为性能考虑才使用的线性查找。事实上只要是能用线性查找替换的地方，都应该这样做。</p>
<p><span style="color: #ff0000;">RegularMatch</span> 看名字就知道这是终极解决方案了，和IDMatch的差异也只在于定义开头也是个正则。最消耗的方案。我根本没有用到它，放在那里有备无患而已。</p>
<h3>ecmascript的示例</h3>
<p>以下是用来解析js、as等语言的定义类文件：</p>
<pre class="brush:as3">package lexer.rule {
	/**
	 * ...
	 * @author army8735
	 */
	import lexer.*;
	import lexer.depth.*;
	import lexer.match.*;

	public class EcmascriptRule extends LanguageRule {

		public function EcmascriptRule() {
			var keywords:Array = "if else for break case continue function true use \
switch default do while int float double long short char null public super in false \
abstract boolean Boolean byte class const debugger delete static void synchronized this import \
enum export extends final finally goto implements protected throw throws transient \
instanceof interface native new package private try typeof var volatile Vector with \
document window return Function String Date Array Object RegExp Event Math Number \
decodeURI decodeURIComponent encodeURI encodeURIComponent escape isFinite isNaN namespace \
isXMLName parseFloat parseInt trace uint unescape XML XMLList undefined Infinity NaN".split(" ");
			super(keywords, true);

			addMatch(new CompleteEqual(Token.DEPTH, "{", LanguageLexer.IS_PERL_REG));
			addMatch(new CompleteEqual(Token.DEPTH, "}", LanguageLexer.IS_PERL_REG));
			addMatch(new CompleteEqual(Token.DEPTH, "[", LanguageLexer.IS_PERL_REG));
			addMatch(new CompleteEqual(Token.DEPTH, "]", LanguageLexer.IS_PERL_REG));
			addMatch(new CompleteEqual(Token.DEPTH, "(", LanguageLexer.IS_PERL_REG));
			addMatch(new CompleteEqual(Token.DEPTH, ")", LanguageLexer.NOT_PERL_REG));
			addMatch(new LinearSearch(Token.COMMENT, "//", "\n", false));
			addMatch(new LinearSearch(Token.COMMENT, "/*", "*/", true));
			addMatch(new LinearParse(Token.STRING, "'", "'", true, LanguageLexer.IS_PERL_REG));
			addMatch(new LinearParse(Token.STRING, "\"", "\"", true, LanguageLexer.IS_PERL_REG));
			addMatch(new CharacterSet(Token.ID, [
				CharacterSet.LETTER,
				CharacterSet.UNDERLINE,
				CharacterSet.DOLLAR
			], [
				CharacterSet.LETTER,
				CharacterSet.UNDERLINE,
				CharacterSet.DOLLAR,
				CharacterSet.DIGIT
			], LanguageLexer.NOT_PERL_REG));

			addDep(new TokenDepth(Token.DEPTH, "{", "}"));
			addDep(new TokenDepth(Token.DEPTH, "[", "]"));
			addDep(new TokenDepth(Token.DEPTH, "(", ")"));
		}

	}

}</pre>
<p>super()构造函数的2个参数分别为保留字数组和语言本身是否支持Perl风格的正则表达式（perl风格的判别被直接集成在了父层解析器中）。</p>
<p>可以看到下方一系列的addMatch()方法，它按照出现顺序来添加匹配模式并排序优先级，先出现的匹配模式具有高优先级。</p>
<p>addDep()方法则是解析深度用的，有兴趣的可以看看——它也很容易被猜出来是怎么做的。</p>
<h3>python的示例</h3>
<p>python语言可能是比较特殊的例子了，因为它的深度折叠不是靠Token识别，而是看每行开始的空格？！我对python语法不大了解，所以简单搜索写了下，这也能体现出添加新语法文件方便多了的特性。</p>
<pre class="brush:as3">package lexer.rule {
	/**
	 * ...
	 * @author army8735
	 */
	import lexer.*;
	import lexer.depth.*;
	import lexer.match.*;

	public class PythonRule extends LanguageRule {

		public function PythonRule() {
			var keywords:Array = "and assert break class continue def del elif else \
except exec finally for from global if import in is lambda not or pass print raise \
return try yield while __import__ abs all any apply basestring bin bool buffer callable \
chr classmethod cmp coerce compile complex delattr dict dir divmod enumerate eval \
execfile file filter float format frozenset getattr globals hasattr hash help hex id \
input int intern isinstance issubclass iter len list locals long map max min next \
object oct open ord pow print property range raw_input reduce reload repr reversed \
round set setattr slice sorted staticmethod str sum super tuple type type unichr \
unicode vars xrange zip".split(" ");
			super(keywords, true);

			addMatch(new LinearSearch(Token.COMMENT, "#", "\n", false));
			addMatch(new LinearSearch(Token.STRING, "'''", "'''", true, LanguageLexer.IS_PERL_REG));
			addMatch(new LinearSearch(Token.STRING, '"""', '"""', true, LanguageLexer.IS_PERL_REG));
			addMatch(new LinearParse(Token.STRING, "'", "'", true, LanguageLexer.IS_PERL_REG));
			addMatch(new LinearParse(Token.STRING, "\"", "\"", true, LanguageLexer.IS_PERL_REG));
			addMatch(new CharacterSet(Token.ID, [
				CharacterSet.LETTER,
				CharacterSet.UNDERLINE
			], [
				CharacterSet.LETTER,
				CharacterSet.UNDERLINE,
				CharacterSet.DIGIT
			], LanguageLexer.NOT_PERL_REG));
		}

	}

}</pre>
<p>python的深度解析直接内嵌集成了，所以没有出现addDep()。其中的疏漏欢迎指出。</p>
<p>想要添加新的语法文件更加欢迎，即使不了解as或者flash的，你也只需告诉我组成规则即可，譬如：python代码的注释部分需要高亮，它由#开头到行末结尾；java的Word由字母下划线开头、字母下划线数字组成……</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2011/08/17/991.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>突然间看到刚毕业时写的web socket game</title>
		<link>http://army8735.org/2011/03/28/965.html</link>
		<comments>http://army8735.org/2011/03/28/965.html#comments</comments>
		<pubDate>Mon, 28 Mar 2011 13:39:48 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[as、flex]]></category>
		<category><![CDATA[其它]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=965</guid>
		<description><![CDATA[


感慨万千啊，mmorpg，聊天、任务、战斗……刚开始随即夭折，只保留有这2段视频和1张截图了。《Fantasy Sky》——纪念那些逝去的代码，还有青春。
]]></description>
			<content:encoded><![CDATA[<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="336" height="264" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="src" value="/wp-content/uploads/2011/03/fs.swf" /><embed type="application/x-shockwave-flash" width="336" height="264" src="/wp-content/uploads/2011/03/fs.swf"></embed></object></p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="240" height="160" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="src" value="/wp-content/uploads/2011/03/test.swf" /><embed type="application/x-shockwave-flash" width="240" height="160" src="/wp-content/uploads/2011/03/test.swf"></embed></object></p>
<p><a href="http://army8735.org/wp-content/uploads/2011/03/temp-233.jpg"><img class="aligncenter size-full wp-image-968" title="temp-233" src="http://army8735.org/wp-content/uploads/2011/03/temp-233.jpg" alt="" width="253" height="176" /></a></p>
<p>感慨万千啊，mmorpg，聊天、任务、战斗……刚开始随即夭折，只保留有这2段视频和1张截图了。《Fantasy Sky》——纪念那些逝去的代码，还有青春。</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2011/03/28/965.html/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>jquery的html5form插件</title>
		<link>http://army8735.org/2011/02/28/950.html</link>
		<comments>http://army8735.org/2011/02/28/950.html#comments</comments>
		<pubDate>Mon, 28 Feb 2011 10:16:19 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[html5form]]></category>
		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=950</guid>
		<description><![CDATA[http://www.matiasmancini.com.ar/jquery-plugin-ajax-form-validation-html5.html
前阵子在这个地址发现了jq的html5form插件，api设计得不错，功能上稍有欠缺，于是乎借鉴了思想重新写了一个：
http://army8735.org/Ai/html5form.html
暂时提取了较为常用的html5表单属性做成了jq插件，样式自己先凑合的，如此可以节省和统一大量的重复校验和表现工作。那些错误以及提示信息均为新生成的绝对定位节点。
input类型有：email、url、number、date、time、search、color几种类型，这些类型根据不同浏览器的支持表现各不相同。

比如number在webkit下支持非常好，输入框尾部有微调按钮；
color和date在opera下支持非常好，直接内置弹出一个选择框用鼠标点一下即可选择； 在不支持的比如ie下，它会默认解读为type=”text”，无任何影响。

较为常用的属性有：placeholder、autofocus、novalid、required、pattern、maxlength。

placeholder在chrome下支持最好，占位符和输入文字自动用2种颜色表示，其它的webkit用同一种颜色表示；
autofocus也是chrome支持最好，ie等需模拟，多个autofocus将以最后一个为准；
novalid指明这个表单无需验证便可提交；
required表明这个input必须填写；
pattern是自定义正则验证，比如示例中自定义的中文输入框，必须输入中文；
maxlength指定最大输入文字长度，在webkit中超过了就无法输入（safari没校验输入法，chrome没校验回车），其它的不行。textarea上使用了这一属性，在输入时会自动提示长度；
step、max、min等均为新特性，高级浏览器中会体现到，低级浏览器中不出现，渐进增强吧。

这些属性可以组合起来使用，用firebug查看下源码，看看input上的属性即可理解。
&#8212;
API： $(‘form’).html5form(callback);
Callback: 一个回调function，可省略，在form的submit通过html5校验之后触发，this指向form本身，返回值为form.submit的返回值（return false阻止默认提交行为）。
源码，还只是个雏形：
(function() {

	var body = $(document.body),
		PLACE_HOLDER_CLASS = 'td_placeholder',
		ERROR_CLASS = 'td_error',
		TIP_CLASS = 'td_tip',
		TYPE_VALID = {
			'url': {
				pattern: /^[a-zA-z]+:\/\/[^\s]*$/,
				message: 'url格式不合法'
			},
			'email':...]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.matiasmancini.com.ar/jquery-plugin-ajax-form-validation-html5.html" target="_blank">http://www.matiasmancini.com.ar/jquery-plugin-ajax-form-validation-html5.html</a></p>
<p>前阵子在这个地址发现了jq的html5form插件，api设计得不错，功能上稍有欠缺，于是乎借鉴了思想重新写了一个：</p>
<p><a href="http://army8735.org/Ai/html5form.html" target="_blank">http://army8735.org/Ai/html5form.html</a></p>
<p>暂时提取了较为常用的html5表单属性做成了jq插件，样式自己先凑合的，如此可以节省和统一大量的重复校验和表现工作。那些错误以及提示信息均为新生成的绝对定位节点。</p>
<p>input类型有：email、url、number、date、time、search、color几种类型，这些类型根据不同浏览器的支持表现各不相同。</p>
<ul>
<li>比如number在webkit下支持非常好，输入框尾部有微调按钮；</li>
<li>color和date在opera下支持非常好，直接内置弹出一个选择框用鼠标点一下即可选择； 在不支持的比如ie下，它会默认解读为type=”text”，无任何影响。</li>
</ul>
<p>较为常用的属性有：placeholder、autofocus、novalid、required、pattern、maxlength。</p>
<ul>
<li>placeholder在chrome下支持最好，占位符和输入文字自动用2种颜色表示，其它的webkit用同一种颜色表示；</li>
<li>autofocus也是chrome支持最好，ie等需模拟，多个autofocus将以最后一个为准；</li>
<li>novalid指明这个表单无需验证便可提交；</li>
<li>required表明这个input必须填写；</li>
<li>pattern是自定义正则验证，比如示例中自定义的中文输入框，必须输入中文；</li>
<li>maxlength指定最大输入文字长度，在webkit中超过了就无法输入（safari没校验输入法，chrome没校验回车），其它的不行。textarea上使用了这一属性，在输入时会自动提示长度；</li>
<li>step、max、min等均为新特性，高级浏览器中会体现到，低级浏览器中不出现，渐进增强吧。</li>
</ul>
<p>这些属性可以组合起来使用，用firebug查看下源码，看看input上的属性即可理解。</p>
<p>&#8212;</p>
<p>API： $(‘form’).html5form(callback);</p>
<p>Callback: 一个回调function，可省略，在form的submit通过html5校验之后触发，this指向form本身，返回值为form.submit的返回值（return false阻止默认提交行为）。</p>
<p>源码，还只是个雏形：</p>
<pre class="brush:js">(function() {

	var body = $(document.body),
		PLACE_HOLDER_CLASS = 'td_placeholder',
		ERROR_CLASS = 'td_error',
		TIP_CLASS = 'td_tip',
		TYPE_VALID = {
			'url': {
				pattern: /^[a-zA-z]+:\/\/[^\s]*$/,
				message: 'url格式不合法'
			},
			'email': {
				pattern: /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/,
				message: 'email格式不合法'
			},
			'number': {
				pattern: /^\d+$/,
				message: '这不是一个数字'
			},
			'date': {
				pattern: /^\d{2,4}-\d{1,2}-\d{1,2}$/,
				message: '日期格式不合法'
			},
			'time': {
				pattern: /^\d{1,2}:\d{1,2}(:\d{1,2}(\.\d{1,3})?)?$/,
				message: '时间格式不合法'
			},
			'color': {
				pattern: /^#[a-z\d]{3,6}$/,
				message: '颜色格式不合法'
			}
		},
		tipBox,
		tpl = [
			'&lt;table class="td_mesbox" cellspacing="0" cellpadding="0"&gt;&lt;tbody&gt;',
				'&lt;tr&gt;',
					'&lt;td class="round left_top"&gt;&lt;/td&gt;',
					'&lt;td class="line top"&gt;&lt;/td&gt;',
					'&lt;td class="round right_top"&gt;&lt;/td&gt;',
				'&lt;/tr&gt;&lt;tr&gt;',
					'&lt;td class="left"&gt;&lt;/td&gt;',
					'&lt;td class="center"&gt;',
						'&lt;div class="container"&gt;&lt;%=text%&gt;&lt;/div&gt;',
					'&lt;/td&gt;',
					'&lt;td class="right"&gt;&lt;/td&gt;',
				'&lt;/tr&gt;&lt;tr&gt;',
					'&lt;td class="round left_bottom"&gt;&lt;/td&gt;',
					'&lt;td class="line bottom"&gt;&lt;/td&gt;',
					'&lt;td class="round right_bottom"&gt;&lt;/td&gt;',
				'&lt;/tr&gt;',
			'&lt;/tbody&gt;&lt;/table&gt;'
		].join('');

	function showError(node, message) {
		var s = $$.render(tpl, { text: message }),
			box = $('&lt;div&gt;').addClass(ERROR_CLASS).html(s).hide().appendTo(body),
			pos = getPos(node, box);
		//最初的坐标保存起来
		box.data('html5form_left', pos.left).data('html5form_top', pos.top);
		//以及对:input的引用
		box.data('html5form_node', node);
		//设置位置
		box.css({
			left: pos.left + 'px',
			top: pos.top + 'px'
		}).fadeIn(200).click(function() {
			node.focus().val(node.val());
		});
		shake(box);
		return box;
	}
	function hideError(box) {
		clearShake(box);
		box.remove();
	}
	function shake(box) {
		clearShake(box);
		var offset = 1,
			count = 0;
		//颤动动画存在自身的interval变量上
		box.data('html5form_interval', setInterval(function() {
			if(count++ &gt; 10) {
				clearShake(box);
			}
			box.css({
				left: box.data('html5form_left') + offset + 'px',
				top: box.data('html5form_top') + offset + 'px'
			});
			offset *= -1;
		}, 50));
	}
	function clearShake(box) {
		var interval = box.data('html5form_interval');
		if(interval) {
			clearInterval(interval);
		}
	}
	function showTip(node, current, maxLength) {
		if(!tipBox) {
			var s = $$.render(tpl, { text: '' });
			tipBox = $('&lt;div&gt;').addClass(TIP_CLASS).html(s);
		}
		//focus时显示并设置位置
		if(node) {
			tipBox.hide().appendTo(body);
			var pos = getPos(node, tipBox);
			tipBox.css({
				left: pos.left + 'px',
				top: pos.top + 'px'
			}).fadeIn(200);
		}
		else {
			tipBox.show();
		}
		//更新说明
		current = current &gt; maxLength ? '&lt;strong&gt;' + current + '&lt;/strong&gt;' : current;
		tipBox.find('div.container').html(current + ' / ' + maxLength);
	}
	function hideTip() {
		if(tipBox) {
			tipBox.hide();
		}
	}
	function getPos(node, box) {
		var left = node.offset().left + node.outerWidth() + 10,
			top = node.offset().top;
		//不够放在node后面的时候，放在前面，top暂不考虑，很少遇到
		if(left + box.outerWidth() &gt; body.innerWidth()) {
			left = Math.max(1, node.offset().left - box.outerWidth() - 10);
		}
		return {
			left: left,
			top: top
		};
	}

	$.fn.html5form = function(cb) {
		this.each(function() {
			var form = $(this),
				novalidate = !$.isUndefined(form.attr('novalidate')),
				inputs = form.find(':input:visible:not(:button, :submit, :radio, :checkbox)'),
				input = document.createElement('input'),
				autofocus = 'autofocus' in input,
				placeholder = 'placeholder' in input,
				required = 'required' in input,
				maxlength = 'maxlength' in input,
				validArray = [];

			//有novalidate属性的话无需验证表单
			if(novalidate) {
				return;
			}

			inputs.each(function(index) {
				var item = $(this),
					type = (this.getAttribute('type') || '').toLowerCase(),
					interval;
				//placeholder占位符
				if(!placeholder &amp;&amp; this.getAttribute('placeholder') != null) {
					var ph = item.attr('placeholder'),
						place; //开关，标明input当前是否是占位符状态。
					//占位符为空字符串无效
					if(ph.length) {
						function focus() {
							//打开状态下认为是占位符
							if(place) {
								item.val('').removeClass(PLACE_HOLDER_CLASS);
							}
						}
						function blur() {
							//离开时如有输入数据开关关闭，否则打开
							if(item.val() == '') {
								item.val(ph).addClass(PLACE_HOLDER_CLASS);
								place = true;
							}
							else {
								place = false;
							}
						}
						item.focus(focus).blur(blur);
						//初始化判断，因为ie和ff会在刷新页面后可能autocomplete遗留表单数据，此时占位符就成为遗留的默认数据；也可能在js执行前有用户输入。唯一的缺点是假如在js执行前用户输入的和占位符相同，会被误认为占位符，可忽视。
						if(ph == item.val() || item.val() == '') {
							place = true;
							item.val(ph).addClass(PLACE_HOLDER_CLASS);
						}
					}
				}
				//maxlength
				var maxLength = parseInt(this.getAttribute('maxlength'));
				if(!isNaN(maxLength)) {
					function input() {
						showTip(null, item.val().length, maxLength);
					}
					item.focus(function() {
						if(!validArray[index]) {
							showTip(item, item.val().length, maxLength);
						}
					}).blur(function() {
						hideTip();
						var v = item.val().length;
						if(!validArray[index] &amp;&amp; v &gt; maxLength) {
							validArray[index] = showError(item, '最多只允许输入&lt;strong&gt;' + maxLength + '&lt;/strong&gt;个字符');
						}
					});
					//input事件除了ie都支持，可以用onpropertychange代替
					if(window.addEventListener) {
						this.addEventListener('input', input, false);
					}
					else if(window.attachEvent) {
						this.attachEvent('onpropertychange', input);
					}
				}
				//autofocus自动聚焦
				if(!autofocus &amp;&amp; this.getAttribute('autofocus') != null) {
					item.focus();
				}
				//required
				if(this.getAttribute('required') != null) {
					item.blur(function() {
						if(validArray[index]) {
							shake(validArray[index]);
						}
						else if($.trim(item.val()) == '') {
							validArray[index] = showError(item, '此项必填');
						}
					});
				}

				//默认的校验
				var typeValid = TYPE_VALID[type];
				if(this.nodeName.toLowerCase() == 'input' &amp;&amp; typeValid) {
					item.blur(function() {
						if(validArray[index]) {
							shake(validArray[index]);
						}
						else {
							var v = item.val().trim();
							if(v.length &amp;&amp; !typeValid.pattern.test(v)) {
								validArray[index] = showError(item, typeValid.message || '格式不正确');
							}
						}
					});
				}
				//number类型另附验证范围
				if(type == 'number') {
					var max = parseFloat(item.attr('max')),
						min = parseFloat(item.attr('min'));
					if(!isNaN(max) || !isNaN(min)) {
						item.blur(function() {
							if(validArray[index]) {
								shake(validArray[index]);
							}
							else {
								var v = item.val().trim();
								if(v.length) {
									v = parseFloat(v);
									if(!isNaN(max) &amp;&amp; v &gt; max) {
										validArray[index] = showError(item, '超出范围，不能大于' + max);
									}
									if(!isNaN(min) &amp;&amp; v &lt; min) {
										validArray[index] = showError(item, '超出范围，不能小于' + max);
									}
								}
							}
						});
					}
				}
				//自定义pattern
				var pattern = this.getAttribute('pattern');
				if(pattern != null &amp;&amp; pattern.length) {
					pattern = new RegExp(pattern);
					item.blur(function() {
						if(validArray[index]) {
							shake(validArray[index]);
						}
						else {
							var v = item.val().trim();
							if(v.length &amp;&amp; !pattern.test(v)) {
								validArray[index] = showError(item, '格式不正确');
							}
						}
					});
				}

				//所有的:input输入时都要隐藏可能存在的错误提示框
				function removeErrorInput() {
					var error = validArray[index];
					if(error) {
						hideError(error);
						validArray[index] = null;
					}
				}
				if(window.addEventListener) {
					this.addEventListener('input', removeErrorInput, false);
				}
				else {
					this.attachEvent('onpropertychange', removeErrorInput);
				}
			});

			form.submit(function() {
				inputs.blur(); //全部触发可能存在的校验
				var validResult = true,
					first;
				validArray.forEach(function(item) {
					if(item) {
						validResult = false;
						shake(item);
						//focus到第一个错误:input
						if(!first) {
							first = true;
							item.data('html5form_node').focus();
						}
					}
				});
				//本身通过html5校验，如有传入callback，返回callback的值
				if(validResult &amp;&amp; $.isFunction(cb)) {
					validResult = cb.call(this) !== false;
				}
				return validResult;
			});
		});
		return this;
	}

})();</pre>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2011/02/28/950.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>jQuery.getScript两个不如意的地方</title>
		<link>http://army8735.org/2011/02/14/944.html</link>
		<comments>http://army8735.org/2011/02/14/944.html#comments</comments>
		<pubDate>Mon, 14 Feb 2011 10:41:29 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[async]]></category>
		<category><![CDATA[charset]]></category>
		<category><![CDATA[getscript]]></category>
		<category><![CDATA[jquery]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=944</guid>
		<description><![CDATA[getScript: function( url, callback ) {
	return jQuery.get(url, null, callback, "script");
},
以上是jq的getScript源代码，只提供了个url和callback，但是遗漏了2个很有特性的参数：charset和async。前者会在页面与script脚本编码不同的时候用到，后者则是个很犀利的特性。
奇怪的是，在jq底层的ajax方法中，却能找到charset的设置：
ajax: function( origSettings ) {
	//...
	if ( s.dataType === "script" &#38;&#38; type...]]></description>
			<content:encoded><![CDATA[<pre class="brush:js">getScript: function( url, callback ) {
	return jQuery.get(url, null, callback, "script");
},</pre>
<p>以上是jq的getScript源代码，只提供了个url和callback，但是遗漏了2个很有特性的参数：charset和async。前者会在页面与script脚本编码不同的时候用到，后者则是个很犀利的特性。</p>
<p>奇怪的是，在jq底层的ajax方法中，却能找到charset的设置：</p>
<pre class="brush:js">ajax: function( origSettings ) {
	//...
	if ( s.dataType === "script" &amp;&amp; type === "GET" &amp;&amp; remote ) {
		var head = document.getElementsByTagName("head")[0] || document.documentElement;
		var script = document.createElement("script");
		if ( s.scriptCharset ) {
			script.charset = s.scriptCharset;
		}
	//...
	}
	//...
}</pre>
<p>不得不抱怨一下，getScript为何不多传入个可省略参数，用来指定charset？</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2011/02/14/944.html/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>as3版的opencv（人脸识别）</title>
		<link>http://army8735.org/2011/02/09/937.html</link>
		<comments>http://army8735.org/2011/02/09/937.html#comments</comments>
		<pubDate>Wed, 09 Feb 2011 07:18:53 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[as、flex]]></category>
		<category><![CDATA[opencv]]></category>
		<category><![CDATA[人脸识别]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=937</guid>
		<description><![CDATA[http://www.francois-tarlier.com/blog/marilena-opencv-port-to-actionscript-3-as3-flash/
无意间发现的，一个叫做Ohtsuka Masakazu的家伙（看名字像是日籍人士），将著名的opencv改写出一个as3版。
而后，另外一个人改进了它，主要是优化性能：http://www.quasimondo.com/archives/000687.php#000687
我做了个测试，的确对人脸识别得挺准的。只是图片太大时会抛出异常，而且根据不同的设置不同的图片识别速度也不一样。用我的2张老照片试试：




是否某些sns的相册系统或者其它的地方也可以考虑下呢？
]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.francois-tarlier.com/blog/marilena-opencv-port-to-actionscript-3-as3-flash/">http://www.francois-tarlier.com/blog/marilena-opencv-port-to-actionscript-3-as3-flash/</a></p>
<p>无意间发现的，一个叫做<a href="http://translate.google.fr/translate?prev=_t&amp;hl=fr&amp;ie=UTF-8&amp;u=http%3A%2F%2Fmaaash.jp%2Fas3%2Fas3marilena-object-detection-in-as3%2F&amp;sl=ja&amp;tl=en&amp;history_state0=" target="_blank">Ohtsuka Masakazu</a>的家伙（看名字像是日籍人士），将著名的opencv改写出一个as3版。</p>
<p>而后，另外一个人改进了它，主要是优化性能：<a href="http://www.quasimondo.com/archives/000687.php#000687">http://www.quasimondo.com/archives/000687.php#000687</a></p>
<p>我做了个测试，的确对人脸识别得挺准的。只是图片太大时会抛出异常，而且根据不同的设置不同的图片识别速度也不一样。用我的2张老照片试试：</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="550" height="400"><param value="/wp-content/uploads/2011/02/face.swf" name="movie"><param value="url=/wp-content/uploads/2011/02/1.jpg" name="flashvars"><embed type="application/x-shockwave-flash" flashvars="url=/wp-content/uploads/2011/02/1.jpg" src="/wp-content/uploads/2011/02/face.swf" width="550" height="400"><br />
</object></p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="550" height="400"><param value="/wp-content/uploads/2011/02/face.swf" name="movie"><param value="url=/wp-content/uploads/photo.jpg" name="flashvars"><embed type="application/x-shockwave-flash" flashvars="url=/wp-content/uploads/photo.jpg" src="/wp-content/uploads/2011/02/face.swf" width="550" height="400"><br />
</object></p>
<p>是否某些sns的相册系统或者其它的地方也可以考虑下呢？</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2011/02/09/937.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>土豆网招聘前端开发工程师</title>
		<link>http://army8735.org/2011/01/27/924.html</link>
		<comments>http://army8735.org/2011/01/27/924.html#comments</comments>
		<pubDate>Thu, 27 Jan 2011 10:41:41 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[其它]]></category>
		<category><![CDATA[前端]]></category>
		<category><![CDATA[土豆网]]></category>
		<category><![CDATA[招聘]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=924</guid>
		<description><![CDATA[我们在寻找两名志同道合的前端开发工程师
我们：
-      秉持小而精的团队建设理念
-      致力于探索和实践更先进的前端开发模式
-      快乐并高效地工作
 
需要你有以下基本特性：
-  积极主动的做事态度
-  乐观开放的心态
-  团队合作精神
-  必要时能承受较大的工作压力
- 良好的沟通能力
 
-      前端开发工程师
工作年限：1年
 
技能和经验要求：
-  熟悉 html,CSS
-  熟悉 Javascript
-  熟悉 photoshop
-  了解...]]></description>
			<content:encoded><![CDATA[<p><span style="color: #003300;">我们在寻找两名志同道合的前端开发工程师</span></p>
<p><span style="color: #003300;">我们：</span></p>
<p><span style="color: #003300;">-      秉持小而精的团队建设理念</span></p>
<p><span style="color: #003300;">-      致力于探索和实践更先进的前端开发模式</span></p>
<p><span style="color: #003300;">-      快乐并高效地工作</span></p>
<p><span style="color: #003300;"> </span></p>
<p><span style="color: #003300;">需要你有以下基本特性：</span></p>
<p><span style="color: #003300;">-  积极主动的做事态度</span></p>
<p><span style="color: #003300;">-  乐观开放的心态</span></p>
<p><span style="color: #003300;">-  团队合作精神</span></p>
<p><span style="color: #003300;">-  必要时能承受较大的工作压力</span></p>
<p><span style="color: #003300;">- 良好的沟通能力</span></p>
<p><span style="color: #003300;"> </span></p>
<p><span style="color: #003300;">-      前端开发工程师</span></p>
<p><span style="color: #003300;">工作年限：1年</span></p>
<p><span style="color: #003300;"> </span></p>
<p><span style="color: #003300;">技能和经验要求：</span></p>
<p><span style="color: #003300;">-  熟悉 html,CSS</span></p>
<p><span style="color: #003300;">-  熟悉 Javascript</span></p>
<p><span style="color: #003300;">-  熟悉 photoshop</span></p>
<p><span style="color: #003300;">-  了解 主流JS库（熟悉 jQuery为佳）</span></p>
<p><span style="color: #003300;">-  较丰富的项目开发经验（提供访问地址）</span></p>
<p><span style="color: #003300;"> </span></p>
<p><span style="color: #003300;">工作职责：</span></p>
<p><span style="color: #003300;">-  土豆网项目开发</span></p>
<p><span style="color: #003300;"><br />
==========================================</span></p>
<p><span style="color: #003300;"><br />
</span></p>
<p><span style="color: #003300;"> </span></p>
<p><span style="color: #003300;">-      前端开发工程师 高级javascript程序员</span></p>
<p><span style="color: #003300;">工作年限：4年</span></p>
<p><span style="color: #003300;"> </span></p>
<p><span style="color: #003300;">-  精通javascript，包含但不限于以下方面：</span></p>
<p><span style="color: #003300;">-  语言特性</span></p>
<p><span style="color: #003300;">-  设计模式</span></p>
<p><span style="color: #003300;">-  开发框架</span></p>
<p><span style="color: #003300;">-  优化</span></p>
<p><span style="color: #003300;">-  测试</span></p>
<p><span style="color: #003300;">-  有自己成熟的前端解决方案，给出实践项目（提供访问地址）</span></p>
<p><span style="color: #003300;">-  对于各种前端问题有丰富的经验</span></p>
<p><span style="color: #003300;">-  开阔的视野，对相关技术持续研究和关注</span></p>
<p><span style="color: #003300;">-  具备其他语言的开发经验</span></p>
<p><span style="color: #003300;">工作职责：</span></p>
<p><span style="color: #003300;">-  土豆网开发</span></p>
<p><span style="color: #003300;">-  前端架构改进</span></p>
<p><span style="color: #003300;">-  前端技术推广</span></p>
<p><strong>请不要吝啬你的网速，发邮件：</strong><a href="mailto:army8735@gmail.com" target="_self">army8735@gmail.com</a></p>
<p>工作地点：上海</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2011/01/27/924.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>发现个sina围脖的bug</title>
		<link>http://army8735.org/2011/01/24/922.html</link>
		<comments>http://army8735.org/2011/01/24/922.html#comments</comments>
		<pubDate>Mon, 24 Jan 2011 06:31:38 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[用户体验设计]]></category>
		<category><![CDATA[sina]]></category>
		<category><![CDATA[微博]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=922</guid>
		<description><![CDATA[转发一条围脖时，不慎点错了，点到了它上面一条围脖的转发按钮上——这情况应该很常见，眼花手抖脚抽筋儿。常在河边走，哪有不湿鞋的呢？
于是乎，删除，重发。提示信息出来了：啥啥啥不能太贪心，只能发一条。可我已经将刚才的删除了……
猜测之：为防止用户恶意刷重复的内容（比如小广告），每条最新发的围脖（或几条）会被缓存下来；再发新的围脖时，先检缓存中是否有，命中则给予提示不能重复。
可惜这个业务逻辑没有考虑完备，删除上一篇再重发并没有清除记录，于是造成了这一现象。
以上。
]]></description>
			<content:encoded><![CDATA[<p>转发一条围脖时，不慎点错了，点到了它上面一条围脖的转发按钮上——这情况应该很常见，眼花手抖脚抽筋儿。常在河边走，哪有不湿鞋的呢？</p>
<p>于是乎，删除，重发。提示信息出来了：啥啥啥不能太贪心，只能发一条。可我已经将刚才的删除了……</p>
<p>猜测之：为防止用户恶意刷重复的内容（比如小广告），每条最新发的围脖（或几条）会被缓存下来；再发新的围脖时，先检缓存中是否有，命中则给予提示不能重复。</p>
<p>可惜这个业务逻辑没有考虑完备，删除上一篇再重发并没有清除记录，于是造成了这一现象。</p>
<p>以上。</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2011/01/24/922.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>慎用ExternalInterface的优化</title>
		<link>http://army8735.org/2011/01/02/913.html</link>
		<comments>http://army8735.org/2011/01/02/913.html#comments</comments>
		<pubDate>Sun, 02 Jan 2011 08:56:31 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[as、flex]]></category>
		<category><![CDATA[前端开发]]></category>
		<category><![CDATA[externalinterface]]></category>
		<category><![CDATA[优化]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=913</guid>
		<description><![CDATA[http://flashteam.tencent.com/post/18/externalinterface-and-javascript/
tencent的flashteam发布过2篇关于ExternalInterface的详解以及优化，着实给广大人民群众带来了不少利益。但是其中有点隐患。比如文中所说的__flash__escapeXML优化：一是少了对&#38;符号的转义，这个一般情况下的确可以省略，因为很少字符串数据中会出现&#38;amp;符号，但是一旦出现就会被转化为&#38;；二是可怜的&#38;lt;被写成了&#38;lg;，说实话我为了这个bug郁闷了几个星期才发现是字母拼错了……
加入&#38;的解析，不能直接加在正则替换callback中，因为某些隐秘的情况下会出现重复转义&#38;的情况，而且非常难查。所以5次转义最好情况也只能被优化为2次：
//覆盖flash默认通信方法，提高性能
window.__flash__escapeXML = function(s) {
	var keywords = {
		"\"" : "&#38;quot;",
		"&#60;" : "&#38;lt;",
		"&#62;" : "&#38;gt;",
		"\"" : "&#38;apos;"
	};
	return s.replace(/&#38;/g, "&#38;amp;").replace(/(['"&#60;&#62;])/g, function(a, b) {
		var...]]></description>
			<content:encoded><![CDATA[<p><a href="http://flashteam.tencent.com/post/18/externalinterface-and-javascript/">http://flashteam.tencent.com/post/18/externalinterface-and-javascript/</a></p>
<p>tencent的flashteam发布过2篇关于<span style="color: #ff0000;">ExternalInterface</span>的详解以及优化，着实给广大人民群众带来了不少利益。但是其中有点隐患。比如文中所说的<span style="color: #ff0000;">__flash__escapeXML</span>优化：一是少了对<span style="color: #ff0000;">&amp;</span>符号的转义，这个一般情况下的确可以省略，因为很少字符串数据中会出现<span style="color: #ff0000;">&amp;amp;</span>符号，但是一旦出现就会被转化为<span style="color: #ff0000;">&amp;</span>；二是可怜的<span style="color: #ff0000;">&amp;lt;</span>被写成了<span style="color: #ff0000;">&amp;lg;</span>，说实话我为了这个bug郁闷了几个星期才发现是字母拼错了……</p>
<p>加入&amp;的解析，不能直接加在正则替换callback中，因为某些隐秘的情况下会出现重复转义&amp;的情况，而且非常难查。所以5次转义最好情况也只能被优化为2次：</p>
<pre class="brush:js">//覆盖flash默认通信方法，提高性能
window.__flash__escapeXML = function(s) {
	var keywords = {
		"\"" : "&amp;quot;",
		"&lt;" : "&amp;lt;",
		"&gt;" : "&amp;gt;",
		"\"" : "&amp;apos;"
	};
	return s.replace(/&amp;/g, "&amp;amp;").replace(/(['"&lt;&gt;])/g, function(a, b) {
		var c = keywords[b];
		return c ? c : a;
	});
};</pre>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2011/01/02/913.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>好笑的API风格</title>
		<link>http://army8735.org/2010/12/26/906.html</link>
		<comments>http://army8735.org/2010/12/26/906.html#comments</comments>
		<pubDate>Sun, 26 Dec 2010 08:46:15 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[前端开发]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=906</guid>
		<description><![CDATA[http://hax.javaeye.com/blog/850778
回帖时突然想到了：
所有dom原生API都是和此文表述一致。比如addEventLister、removeEventLister；没见过eventLister()根据参数个数确定是add还是remove。
相反，jq当中语法风格都是这样。
问题就变成了，为什么会有这两种相反情况的出现？
不知为何我很想笑……
请去原帖参与讨论。
]]></description>
			<content:encoded><![CDATA[<p><a href="http://hax.javaeye.com/blog/850778" target="_blank">http://hax.javaeye.com/blog/850778</a></p>
<p>回帖时突然想到了：</p>
<blockquote><p>所有dom原生API都是和此文表述一致。比如addEventLister、removeEventLister；没见过eventLister()根据参数个数确定是add还是remove。</p>
<p>相反，jq当中语法风格都是这样。</p>
<p>问题就变成了，为什么会有这两种相反情况的出现？</p></blockquote>
<p>不知为何我很想笑……</p>
<p>请去原帖参与讨论。</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2010/12/26/906.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jssc5.0.5添加i18n以及下一代构想</title>
		<link>http://army8735.org/2010/12/24/892.html</link>
		<comments>http://army8735.org/2010/12/24/892.html#comments</comments>
		<pubDate>Fri, 24 Dec 2010 05:04:26 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[jssc]]></category>
		<category><![CDATA[前端开发]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=892</guid>
		<description><![CDATA[http://jssc.googlecode.com/svn/trunk/jssc5/bin/index.html
已经可以看到添加了不少语言了，找翻译可真够受罪的。通过flashvars中传递lang=param来设置语系，比如说：lang=chinese。
还有检测时添加了对textarea节点的检查，最初也是有的，后来为了标准只检测pre节点，现在发现textarea还是有优势的，比如html代码在pre节点中得转义&#60;号，textarea则不需要。控制权还是交给用户为妙。
另外删除了关于按钮，右上角只保留复制功能，协议改成了MIT。github和google code并存：https://github.com/army8735/jssc
最近始终在考虑5.0的结构设计问题，lexer之间父子继承的关系真可谓一坨坨的：

想要添加新语种十分麻烦，因为要实现这个语言的lexer才行。虽说当初设计的两大目的是准确性和速度性能，但是忽略了易配置性，罪过罪过。UNIX上的Lex做得很不错，每种语言用描述自己的规则文件来定义，值得借鉴，这样即使不懂如何实现lexer的人只要通过配置自己所需的语言规则，也能添加语法种类。
下一代的jssc要提炼出一个lexer核心，这样其它地方也能用这个核心，不必重复实现。现在的做法耦合太严重，解析过程和生成html的逻辑死死绑在一起，当然唯一的好处是性能最快。解耦后将略微损失一些性能，但总体时间复杂度还是O（n）的，再加上加入缓冲区的概念，性能不是问题，最终结果得要远远大于失的。
至于版本号么，5.1？5.5？6.0？算了，还是别学chrome了……
最后，昨天看见syntaxhighlighter更新到3.x了，开源竞争激烈啊，不过准确性和速度性还是不能比的。习惯性地祭出js校验代码（前一部分是我编的，后一部分来源于hax），还是没有根本性的改变：
//javascript
var reg = /**//[\/][/][*]([\S\s]*?)(?:[*][/;\[\]]&#124;$)&#124;[\/][/g;//](.*)&#124;"((?:\\\\&#124;\\"&#124;[^"///])*)"&#124;'((?:\\\\&#124;\\'&#124;[^'\//;])*)'/gm; ''; /\d/.test(1);
reg = 12;
reg = 2 / 1 /**///
/**///
/reg/ 1;
var num1 = 0.541;
function f(test) {
...]]></description>
			<content:encoded><![CDATA[<p><a href="http://jssc.googlecode.com/svn/trunk/jssc5/bin/index.html" target="_blank">http://jssc.googlecode.com/svn/trunk/jssc5/bin/index.html</a></p>
<p>已经可以看到添加了不少语言了，找翻译可真够受罪的。通过flashvars中传递lang=param来设置语系，比如说：lang=chinese。</p>
<p>还有检测时添加了对textarea节点的检查，最初也是有的，后来为了标准只检测pre节点，现在发现textarea还是有优势的，比如html代码在pre节点中得转义&lt;号，textarea则不需要。控制权还是交给用户为妙。</p>
<p>另外删除了关于按钮，右上角只保留复制功能，协议改成了MIT。github和google code并存：<a href="https://github.com/army8735/jssc" target="_blank">https://github.com/army8735/jssc</a></p>
<p>最近始终在考虑5.0的结构设计问题，lexer之间父子继承的关系真可谓一坨坨的：</p>
<p><a href="http://army8735.org/wp-content/uploads/2010/12/jssc5project.png"><img class="aligncenter size-full wp-image-893" title="jssc5project" src="http://army8735.org/wp-content/uploads/2010/12/jssc5project.png" alt="" width="319" height="737" /></a></p>
<p>想要添加新语种十分麻烦，因为要实现这个语言的lexer才行。虽说当初设计的两大目的是准确性和速度性能，但是忽略了易配置性，罪过罪过。UNIX上的Lex做得很不错，每种语言用描述自己的规则文件来定义，值得借鉴，这样即使不懂如何实现lexer的人只要通过配置自己所需的语言规则，也能添加语法种类。</p>
<p>下一代的jssc要提炼出一个lexer核心，这样其它地方也能用这个核心，不必重复实现。现在的做法耦合太严重，解析过程和生成html的逻辑死死绑在一起，当然唯一的好处是性能最快。解耦后将略微损失一些性能，但总体时间复杂度还是O（n）的，再加上加入缓冲区的概念，性能不是问题，最终结果得要远远大于失的。</p>
<p>至于版本号么，5.1？5.5？6.0？算了，还是别学chrome了……</p>
<p>最后，昨天看见<a href="http://alexgorbatchev.com/SyntaxHighlighter/" target="_blank">syntaxhighlighter</a>更新到3.x了，开源竞争激烈啊，不过准确性和速度性还是不能比的。习惯性地祭出js校验代码（前一部分是我编的，后一部分来源于<a href="http://hax.javaeye.com/" target="_blank">hax</a>），还是没有根本性的改变：</p>
<pre class="brush:js">//javascript
var reg = /**//[\/][/][*]([\S\s]*?)(?:[*][/;\[\]]|$)|[\/][/g;//](.*)|"((?:\\\\|\\"|[^"///])*)"|'((?:\\\\|\\'|[^'\//;])*)'/gm; ''; /\d/.test(1);
reg = 12;
reg = 2 / 1 /**///
/**///
/reg/ 1;
var num1 = 0.541;
function f(test) {
    return (test/*
    /* //
    ' "
    { ;
    \*/ &amp;&amp; // /* // " ' { ; \
    test &amp;&amp;
    " /* // \
    \" ' \
    { ;" &amp;&amp;
    ' /* // \
    " \' \
    { ;' &amp;&amp;
    test);
}</pre>
<p><a href="http://army8735.org/wp-content/uploads/2010/12/sh3.png"><img class="aligncenter size-full wp-image-897" title="sh3" src="http://army8735.org/wp-content/uploads/2010/12/sh3.png" alt="" width="1059" height="324" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2010/12/24/892.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>使用惰性载入函数改写swfobject</title>
		<link>http://army8735.org/2010/12/21/877.html</link>
		<comments>http://army8735.org/2010/12/21/877.html#comments</comments>
		<pubDate>Tue, 21 Dec 2010 02:34:29 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[swfobject]]></category>
		<category><![CDATA[惰性函数]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=877</guid>
		<description><![CDATA[http://code.google.com/p/swfobject/
swfobject是目前比较通用的嵌入flash的js库，很多库自己实现的插件也无一例外借鉴了它。不过我的日常工作中很少用到静态方式嵌入flash，都是动态方式调用，因此许多代码是冗余的；而且swfobject虽然针对不同浏览器进行了分支判断，但没有进行“惰性化”，性能没有最优。
举个例子，判断flash的版本，swfobject会在初始化的时候进行，即使没有使用它。很多人会进行改写，使之成为“首次使用时初始化”。我之前也是如此：
(function() {

var SHOCKWAVE_FLASH = 'Shockwave Flash',
	FLASH_MIME_TYPE = 'application/x-shockwave-flash',
	SHOCKWAVE_FLASH_AX = 'ShockwaveFlash.ShockwaveFlash',
	version;

function getVersion() {
	var d,
		ver = [0, 0, 0];
	if(!$.isUndefined(navigator.plugins) &#38;&#38; $.isObject(navigator.plugins[SHOCKWAVE_FLASH])) {
		d...]]></description>
			<content:encoded><![CDATA[<p><a href="http://code.google.com/p/swfobject/">http://code.google.com/p/swfobject/</a></p>
<p>swfobject是目前比较通用的嵌入flash的js库，很多库自己实现的插件也无一例外借鉴了它。不过我的日常工作中很少用到静态方式嵌入flash，都是动态方式调用，因此许多代码是冗余的；而且swfobject虽然针对不同浏览器进行了分支判断，但没有进行“惰性化”，性能没有最优。</p>
<p>举个例子，判断flash的版本，swfobject会在初始化的时候进行，即使没有使用它。很多人会进行改写，使之成为“<strong>首次使用时初始化</strong>”。我之前也是如此：</p>
<pre class="brush:js">(function() {

var SHOCKWAVE_FLASH = 'Shockwave Flash',
	FLASH_MIME_TYPE = 'application/x-shockwave-flash',
	SHOCKWAVE_FLASH_AX = 'ShockwaveFlash.ShockwaveFlash',
	version;

function getVersion() {
	var d,
		ver = [0, 0, 0];
	if(!$.isUndefined(navigator.plugins) &amp;&amp; $.isObject(navigator.plugins[SHOCKWAVE_FLASH])) {
		d = navigator.plugins[SHOCKWAVE_FLASH].description;
		if (d &amp;&amp; !(!$.isUndefined(navigator.mimeTypes) &amp;&amp; navigator.mimeTypes[FLASH_MIME_TYPE] &amp;&amp; !navigator.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+
			d = d.replace(/^.*\s+(\S+\s+\S+$)/, '$1');
			ver[0] = parseInt(d.replace(/^(.*)\..*$/, '$1'), 10);
			ver[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, '$1'), 10);
			ver[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, '$1'), 10) : 0;
		}
	}
	else if(!$.isUndefined(window.ActiveXObject)) {
		try {
			var a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
			if(a) { // a will return null when ActiveX is disabled
				d = a.GetVariable('$version');
				if (d) {
					d = d.split(' ')[1].split(',');
					ver = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
				}
			}
		}
		catch(e) {}
	}
	return ver;
}

TUI.getVersion = function() {
	if(!version) {
		version = getVersion();
	}
	return version;
}

})();</pre>
<p>这样做的好处是在第一次获取版本时才去初始化，因为ActiveX的消耗很厉害，而以后再次获取的时候取单例version，避免再次初始化。</p>
<p>但是这不是最优的方案，因为即使这样，每次获取版本的时候还会进行一次if判断，检查是否有初始化过程，访问父层作用域的变量。理想情况应该是直接返回版本，改写方案如下：</p>
<pre class="brush:js">(function() {

var SHOCKWAVE_FLASH = 'Shockwave Flash',
	FLASH_MIME_TYPE = 'application/x-shockwave-flash',
	SHOCKWAVE_FLASH_AX = 'ShockwaveFlash.ShockwaveFlash';

function getVersion() {
	var d,
		ver = [0, 0, 0];
	if(!$.isUndefined(navigator.plugins) &amp;&amp; $.isObject(navigator.plugins[SHOCKWAVE_FLASH])) {
		d = navigator.plugins[SHOCKWAVE_FLASH].description;
		if (d &amp;&amp; !(!$.isUndefined(navigator.mimeTypes) &amp;&amp; navigator.mimeTypes[FLASH_MIME_TYPE] &amp;&amp; !navigator.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+
			d = d.replace(/^.*\s+(\S+\s+\S+$)/, '$1');
			ver[0] = parseInt(d.replace(/^(.*)\..*$/, '$1'), 10);
			ver[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, '$1'), 10);
			ver[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, '$1'), 10) : 0;
		}
	}
	else if(!$.isUndefined(window.ActiveXObject)) {
		try {
			var a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
			if(a) { // a will return null when ActiveX is disabled
				d = a.GetVariable('$version');
				if (d) {
					d = d.split(' ')[1].split(',');
					ver = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
				}
			}
		}
		catch(e) {}
	}
	return ver;
}

TUI.getVersion = function() {
	var version = getVersion();
	this.getVersion = function() {
		return version;
	};
	return version;
}

})();</pre>
<p>第一次调用时初始化，并且覆盖本身的方法，使之成为直接返回的函数，省略了外部的version变量以及if判断。甚至可以将getVersion方法移到TUI.getVersion中，这便是<strong>惰性函数</strong>。</p>
<p>这个操作比较简单，分支较少，还体现不出来优势，不如嵌入swf等操作明显，以下是全貌：</p>
<pre class="brush:js">(function() {

	var SHOCKWAVE_FLASH = 'Shockwave Flash',
		FLASH_MIME_TYPE = 'application/x-shockwave-flash',
		SHOCKWAVE_FLASH_AX = 'ShockwaveFlash.ShockwaveFlash';

	function getVersion() {
		var d,
			ver = [0, 0, 0];
		if(!$.isUndefined(navigator.plugins) &amp;&amp; $.isObject(navigator.plugins[SHOCKWAVE_FLASH])) {
			d = navigator.plugins[SHOCKWAVE_FLASH].description;
			if (d &amp;&amp; !(!$.isUndefined(navigator.mimeTypes) &amp;&amp; navigator.mimeTypes[FLASH_MIME_TYPE] &amp;&amp; !navigator.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+
				d = d.replace(/^.*\s+(\S+\s+\S+$)/, '$1');
				ver[0] = parseInt(d.replace(/^(.*)\..*$/, '$1'), 10);
				ver[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, '$1'), 10);
				ver[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, '$1'), 10) : 0;
			}
		}
		else if(!$.isUndefined(window.ActiveXObject)) {
			try {
				var a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
				if(a) { // a will return null when ActiveX is disabled
					d = a.GetVariable('$version');
					if (d) {
						d = d.split(' ')[1].split(',');
						ver = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
					}
				}
			}
			catch(e) {}
		}
		return ver;
	}
	function createSwf(attrs, params, node) {
		//ie下需考虑原有节点就是个object（flash）的情况，强行覆盖会致使flash无法正常播放。移除原object再插入新div节点，再动态插入flash到新div节点中。也可防止内存泄漏
		if(node.tagName.toLowerCase() == 'object') {
			var newDiv = document.createElement('div');
			node.parentNode.insertBefore(newDiv, node);
			removeObject(node);
			createHtml(attrs, params, newDiv);
		}
		else {
			createHtml(attrs, params, node);
		}
	}
	function createHtml(attrs, params, node) {
		if($.browser.msie) {
			createHtml = createInIe;
		}
		else {
			createHtml = createInNormal;
		}
		createHtml(attrs, params, node);
	}
	function createInIe(attrs, params, node) {
		var att = '',
			par = '';
		for(var i in attrs) {
			if(attrs[i] != Object.prototype[i]) { //需过滤掉一些潜在因素为prototype添加属性
				if(i.toLowerCase() == 'data') {
					params.movie = attrs[i];
				}
				else if(i.toLowerCase() == 'class') {
					att += ' class="' + attrs[i] + '"';
				}
				else if(i.toLowerCase() != 'classid') {
					att += ' ' + i + '="' + attrs[i] + '"';
				}
			}
		}
		for(var j in params) {
			if(params[j] != Object.prototype[j]) { //同上
				par += '&lt;param name="' + j + '" value="' + params[j] + '"/&gt;';
			}
		}
		node.outerHTML = '&lt;object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' + att + '&gt;' + par + '&lt;/object&gt;';
	}
	function createInNormal(attrs, params, node) {
		var o = document.createElement('object');
		o.setAttribute('type', FLASH_MIME_TYPE);
		for(var m in attrs) {
			if(attrs[m] != Object.prototype[m]) { //同上
				if(m.toLowerCase() == 'class') {
					o.setAttribute('class', attrs[m]);
				}
				else if(m.toLowerCase() != "classid") { //过滤掉IE特有属性
					o.setAttribute(m, attrs[m]);
				}
			}
		}
		for(var n in params) {
			if(params[n] != Object.prototype[n] &amp;&amp; n.toLowerCase() != 'movie') { //同上
				createObjParam(o, n, params[n]);
			}
		}
		node.parentNode.replaceChild(o, node);
	}
	function createObjParam(el, pName, pValue) {
		var p = document.createElement('param');
		p.setAttribute('name', pName);
		p.setAttribute('value', pValue);
		el.appendChild(p);
	}

	function removeObject(obj, cb) {
		//ie下需移除object上的function，以免内存泄漏。移除需要在readyState为4后进行，无法侦听，只能用定时器
		if($.browser.msie) {
			removeObject = removeObjectInIe;
		}
		else {
			removeObject = removeObjectInNormal;
		}
		removeObject(obj, cb);
	}
	function removeObjectInIe(obj, cb) {
		obj.style.display = 'none';
		(function(){
			if(obj.readyState == 4) {
				for(var i in obj) {
					if($.isFunction(obj[i])) {
						obj[i] = null;
					}
				}
				if($.isFunction(cb)) {
					cb();
				}
				return;
			}
			setTimeout(arguments.callee, 100);
		})();
	}
	function removeObjectInNormal(obj, cb) {
		obj.parentNode.removeChild(obj);
		if($.isFunction(cb)) {
			cb();
		}
	}

	TUI.mix({
		/**
		 * @public 获取flash对象
		 * @param {string} 对象id
		 */
		getItem: function(id){
			return $.browser.msie ? window[id] : document[id];
		},

		/**
		 * @public 改写swfobject设置flash对象
		 * @param {string} swf对象的url
		 * @param {string} 动态写入的node的id
		 * @param {int} width
		 * @param {int} height
		 * @param {object} flashvars
		 * @param {object} param标签参数
		 * @param {object} object标签参数
		 */
		setItem: function(url, id, width, height, flashvars, params, attrs) {
			var node = document.getElementById(id),
				p = {},
				a = {};
			if(node) {
				//将url、width、height混入attrs中，防止原配置参数被修改：这是个很隐蔽的引用修改bug
				$.extend(true, a, attrs, {
					data: url,
					width: width + '',
					height: height + ''
				});
				//没有设置id则继承原有dom元素的id
				if(!a.id) {
					a.id = id;
				}
				$.extend(true, p, params);
				p.flashvars = $.param(flashvars);
				createSwf(a, p, node);
				return this.getItem(a.id);
			}
		},

		/**
		 * @public 移除flash对象
		 * @param {string/object} 对象id或对象本身
		 * @param {func} 移除后的回调函数
		 */
		removeItem: function(id, cb) {
			var obj = $.isString(id) ? document.getElementById(id) : id;
			if (obj &amp;&amp; obj.nodeName.toUpperCase() == 'OBJECT') {
				removeObject(obj, cb);
			}
		},

		/**
		 * @public 获取flash版本，单例闭包
		 * @return {array} 3位长度的版本号
		 */
		version: function() {
			var version = getVersion();
			this.version = function() {
				return version;
			}
			return version;
		}
	}, 'swf');

})();</pre>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2010/12/21/877.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>jssc 5.0.4</title>
		<link>http://army8735.org/2010/12/17/873.html</link>
		<comments>http://army8735.org/2010/12/17/873.html#comments</comments>
		<pubDate>Fri, 17 Dec 2010 02:37:58 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[jssc]]></category>
		<category><![CDATA[前端开发]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=873</guid>
		<description><![CDATA[http://code.google.com/p/jssc/
昨天偶然同学使用发现ie下无法显示，maxthon下却行，很是郁闷。最后发现是object标签上的visibility:hidden导致，真没想到。于是乎连忙修正之，并用compiler压缩js部分的代码，这样整体又稍稍减少了0.2k。
成员中增加了lubin1119，来尝试编写sas的解析，我本人倒是希望加入python的解析，随后便是拖延很久的缓冲式解析方法，用以支持超多行数代码高亮。看来又要变动不少了。
]]></description>
			<content:encoded><![CDATA[<p><a href="http://code.google.com/p/jssc/">http://code.google.com/p/jssc/</a></p>
<p><a href="http://code.google.com/p/jssc/"></a>昨天偶然同学使用发现ie下无法显示，maxthon下却行，很是郁闷。最后发现是object标签上的visibility:hidden导致，真没想到。于是乎连忙修正之，并用compiler压缩js部分的代码，这样整体又稍稍减少了0.2k。</p>
<p>成员中增加了<a href="http://code.google.com/u/lubin1119/" target="_blank">lubin1119</a>，来尝试编写sas的解析，我本人倒是希望加入python的解析，随后便是拖延很久的缓冲式解析方法，用以支持超多行数代码高亮。看来又要变动不少了。</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2010/12/17/873.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>预防串行异步中的循环回路</title>
		<link>http://army8735.org/2010/12/12/864.html</link>
		<comments>http://army8735.org/2010/12/12/864.html#comments</comments>
		<pubDate>Sun, 12 Dec 2010 13:54:37 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[串行异步]]></category>
		<category><![CDATA[循环回路]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=864</guid>
		<description><![CDATA[上篇中外链的一篇分享：http://limu.javaeye.com/blog/840159提到了依赖循环的问题，即模块互相依赖形成了死循环。
举例说明：a-&#62;b、b-&#62;c、c-&#62;a。这种依赖是没法执行的，如果运行的话会引发无限死循环，必须预防。可以考虑的方案无非定义时检测（链接中limu中的方案），或者使用时检测，两者大同小异。
伪代码：
//检测是否有循环依赖
function checkRecursion(list) {
	var history = {},
		stack;
	//遍历需要异步加载的模块列表，每个模块深度遍历检测自己的依赖，出现过的说明此回路已检测过无需重复，记录在history中
	list.forEach(function(mod) {
		stack = [];
		if(!history[mod.name]) {
			history[mod.name] = 1;
			scanRecursion(mod, {});
		}
	});
	//每个模块深度遍历过程中，边记录边遍历，发现重复的说明出现循环回路，报异常
	function scanRecursion(mod, has) {
		if(mod &#38;&#38; mod.deps) {
			stack.push(mod.name);
			mod.deps.forEach(function(dep) {
				if(has[dep])...]]></description>
			<content:encoded><![CDATA[<p>上篇中外链的一篇分享：<a href="http://limu.javaeye.com/blog/840159" target="_blank">http://limu.javaeye.com/blog/840159</a>提到了依赖循环的问题，即模块互相依赖形成了死循环。</p>
<p>举例说明：a-&gt;b、b-&gt;c、c-&gt;a。这种依赖是没法执行的，如果运行的话会引发无限死循环，必须预防。可以考虑的方案无非定义时检测（链接中limu中的方案），或者使用时检测，两者大同小异。</p>
<p>伪代码：</p>
<pre class="brush:js">//检测是否有循环依赖
function checkRecursion(list) {
	var history = {},
		stack;
	//遍历需要异步加载的模块列表，每个模块深度遍历检测自己的依赖，出现过的说明此回路已检测过无需重复，记录在history中
	list.forEach(function(mod) {
		stack = [];
		if(!history[mod.name]) {
			history[mod.name] = 1;
			scanRecursion(mod, {});
		}
	});
	//每个模块深度遍历过程中，边记录边遍历，发现重复的说明出现循环回路，报异常
	function scanRecursion(mod, has) {
		if(mod &amp;&amp; mod.deps) {
			stack.push(mod.name);
			mod.deps.forEach(function(dep) {
				if(has[dep]) {
					throw new Error('InfiniteLoop of dependence: ' + stack.join('-&gt;'));
				}
				has[dep] = 1;
				history[dep] = 1;
				scanRecursion(module[dep], has);
			});
			//自身完成后需清除
			has[mod.name] = 0;
			stack.pop();
		}
	}
}</pre>
<p>我用的是使用时检测，防止出现死循环回路，代码都在上面了，没啥好说的。传入的list即是下面3个模块组成的列表，准备一次性并发请求的。做了个测试，成功地抛出了一个详细定位的异常：</p>
<pre class="brush:js">$$.def('a', 'a.js', 'b');
$$.def('b', 'b.js', 'c');
$$.def('c', 'c.js', 'a');

$$.use('a');</pre>
<p><span style="color: #ff0000;">错误： InfiniteLoop of dependence: a-&gt;b-&gt;c-&gt;a</span></p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2010/12/12/864.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>js中的并行异步和串行异步</title>
		<link>http://army8735.org/2010/12/12/855.html</link>
		<comments>http://army8735.org/2010/12/12/855.html#comments</comments>
		<pubDate>Sun, 12 Dec 2010 08:02:51 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[串行异步]]></category>
		<category><![CDATA[并行异步]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=855</guid>
		<description><![CDATA[从按需装载到并行异步，再至递归依赖和串行异步，javascript的潜力也在被开发者们尽情地挖掘。最初是谁先提出来这个的？老道？这个周末也尝试实现了下，这种思维模式的确很让人受到启发。
按需装载
数年前web2.0刚刚起步之时，按需装载首先被提出，这个思维比较简单：只有当用到某个js（确切说法应该是模块）时才会去装载它。举个例子而言，根据cookie确定用户有没有登录，有的话才去ajax请求用户信息并且显示在页面上的某个地方，没有的话不请求也不显示。这是很普遍的技术了，没什么好多说的。
并行异步
随后请求被细分，可能我要执行某个操作的时候，需要加载2个甚至多个js的情况，那么这个加载过程肯定是并行的。没理由先加载一个成功再加载另外一个再成功后才能执行操作——这是浪费时间。
并行异步中唯一要解决的就是同时并发2个请求时，客户端如何判断2个请求全部加载执行完成。很简单，为这个操作设一个计数器，值为依赖请求的个数（如2）。每个依赖请求加载成功后回调计数器自减，当计数器归零时说明全部加载完成。
这个算法很简单，但是需要考虑交叉的情况。即操作1请求了模块a和模块b，操作2请求了模块b和模块c的时候，共用一个模块b的请求要写好。
递归依赖
还有更复杂的情况。比如操作1依赖模块a和b，操作2依赖模块b和c，但是模块c依赖模块d，这该如何是好？
此时需要递归计算依赖，将每个操作所需要的依赖统统找出来，再并发异步即可。
串行异步
好了，真正的难点来了，如果还记得计算机操作系统中的线程的概念的话，这里将触及到类似线程睡眠的东西。
操作1依赖模块a和b，操作2依赖模块b和c，c又依赖d，d再依赖a。这可不是简单的一次性并发请求的问题了。试问：假如使用并发异步的话，模块d可能在模块a之前被加载进来并执行，那么这将会是个错误，用户会在他的浏览器上看到一个大大的叉。
但是我们又不想死板地先加载a，等a加载完成后再去并发。我们想实现串行异步，这该如何呢？
很简单，在d加载完成后先“审时度势”，查看下a有没有加载并执行好。当a已经好了的时候，我们尚可无所顾忌地执行d；而当尚未完成时将d休眠，并且在a的加载成功回调函数中加入一个新的回调：去唤醒d。
完成了这部，可算是实现了串行异步的一半了。还有另一半，即是串行异步的交叉，多个模块依赖多个模块并且彼此之间有交叉的情况出现，这和上面并发异步的交叉类似，需要递归计算并使用计数器。原理就说到这里，具体的实现就不贴了。
因为这些将是“达克斯”可能在d2上的演讲提到的东西，暂且保密。
防止死循环
http://limu.javaeye.com/blog/840159
提到的死循环很给力，虽然属设计上的失误，但合作开发难免会出现，应预防之。抽空补上。
附：已补上，下一篇就是。
]]></description>
			<content:encoded><![CDATA[<p>从按需装载到并行异步，再至递归依赖和串行异步，javascript的潜力也在被开发者们尽情地挖掘。最初是谁先提出来这个的？老道？这个周末也尝试实现了下，这种思维模式的确很让人受到启发。</p>
<h3>按需装载</h3>
<p>数年前web2.0刚刚起步之时，按需装载首先被提出，这个思维比较简单：只有当用到某个js（确切说法应该是模块）时才会去装载它。举个例子而言，根据cookie确定用户有没有登录，有的话才去ajax请求用户信息并且显示在页面上的某个地方，没有的话不请求也不显示。这是很普遍的技术了，没什么好多说的。</p>
<h3>并行异步</h3>
<p>随后请求被细分，可能我要执行某个操作的时候，需要加载2个甚至多个js的情况，那么这个加载过程肯定是并行的。没理由先加载一个成功再加载另外一个再成功后才能执行操作——这是浪费时间。</p>
<p>并行异步中唯一要解决的就是同时并发2个请求时，客户端如何判断2个请求全部加载执行完成。很简单，为这个操作设一个计数器，值为依赖请求的个数（如2）。每个依赖请求加载成功后回调计数器自减，当计数器归零时说明全部加载完成。</p>
<p>这个算法很简单，但是需要考虑交叉的情况。即操作1请求了模块a和模块b，操作2请求了模块b和模块c的时候，共用一个模块b的请求要写好。</p>
<h3>递归依赖</h3>
<p>还有更复杂的情况。比如操作1依赖模块a和b，操作2依赖模块b和c，但是模块c依赖模块d，这该如何是好？</p>
<p>此时需要递归计算依赖，将每个操作所需要的依赖统统找出来，再并发异步即可。</p>
<h3>串行异步</h3>
<p>好了，真正的难点来了，如果还记得计算机操作系统中的线程的概念的话，这里将触及到类似<strong>线程睡眠</strong>的东西。</p>
<p>操作1依赖模块a和b，操作2依赖模块b和c，c又依赖d，d再依赖a。这可不是简单的一次性并发请求的问题了。试问：假如使用并发异步的话，模块d可能在模块a之前被加载进来并执行，那么这将会是个<strong>错误</strong>，用户会在他的浏览器上看到一个大大的叉。</p>
<p>但是我们又不想死板地先加载a，等a加载完成后再去并发。我们想实现串行异步，这该如何呢？</p>
<p>很简单，在d加载完成后先“审时度势”，查看下a有没有加载并执行好。当a已经好了的时候，我们尚可无所顾忌地执行d；而当尚未完成时将d休眠，并且在a的加载成功回调函数中加入一个新的回调：去唤醒d。</p>
<p>完成了这部，可算是实现了串行异步的一半了。还有另一半，即是串行异步的交叉，多个模块依赖多个模块并且彼此之间有交叉的情况出现，这和上面并发异步的交叉类似，需要递归计算并使用计数器。原理就说到这里，具体的实现就不贴了。</p>
<p>因为这些将是<a href="http://www.limboy.com/" target="_blank">“达克斯”</a>可能在d2上的演讲提到的东西，暂且保密。</p>
<h3>防止死循环</h3>
<p><a href="http://limu.javaeye.com/blog/840159">http://limu.javaeye.com/blog/840159</a></p>
<p>提到的死循环很给力，虽然属设计上的失误，但合作开发难免会出现，应预防之。抽空补上。</p>
<p>附：已补上，<a href="http://army8735.org/2010/12/12/864.html" target="_blank">下一篇</a>就是。</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2010/12/12/855.html/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>flash在ie下点击会更改title的bug</title>
		<link>http://army8735.org/2010/12/01/850.html</link>
		<comments>http://army8735.org/2010/12/01/850.html#comments</comments>
		<pubDate>Wed, 01 Dec 2010 08:54:57 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[as、flex]]></category>
		<category><![CDATA[前端开发]]></category>
		<category><![CDATA[flash]]></category>
		<category><![CDATA[ie]]></category>
		<category><![CDATA[title]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=850</guid>
		<description><![CDATA[http://bugs.adobe.com/jira/browse/FP-240
不多说，回复中有个解决办法，利用jQuery的live（为所有可能的object对象绑定侦听）：
$(document).ready(function(){
  gPageTitle = $("title").html();
  $("object").live("mouseenter mouseleave mousedown mouseup",function(){
    document.title = gPageTitle;
  });
});
想触发对object的wmode属性还有要求。
]]></description>
			<content:encoded><![CDATA[<p><a href="http://bugs.adobe.com/jira/browse/FP-240">http://bugs.adobe.com/jira/browse/FP-240</a></p>
<p>不多说，回复中有个解决办法，利用jQuery的live（为所有可能的object对象绑定侦听）：</p>
<pre class="brush:js">$(document).ready(function(){
  gPageTitle = $("title").html();
  $("object").live("mouseenter mouseleave mousedown mouseup",function(){
    document.title = gPageTitle;
  });
});</pre>
<p>想触发对object的wmode属性还有要求。</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2010/12/01/850.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>发现一个基于MIT的as3的高效MD5实现</title>
		<link>http://army8735.org/2010/11/30/846.html</link>
		<comments>http://army8735.org/2010/11/30/846.html#comments</comments>
		<pubDate>Tue, 30 Nov 2010 06:04:54 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[as、flex]]></category>
		<category><![CDATA[as3]]></category>
		<category><![CDATA[md5]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=846</guid>
		<description><![CDATA[com.adobe.crypto官方库的md5算法性能实在不敢恭维，算个10m的byteArray在我机子上跑了大概12s！我勒个去，这可怎么叫人活。随后找到个by.blooddy.crypto，提升了2个数量级的性能！
作者博客：http://va.lent.in/blog/2010/06/23/100x-times-faster-md5-and-more/
更新的博客：http://va.lent.in/blog/2010/07/10/more-on-faster-md5/
下载地址：http://www.blooddy.by/en/crypto/
我实际测试了下，10M的东西大概用了100ms左右，的确至少提升了100倍，作者此言非虚也！只是这个swc必须在flash cs5下编译才能成功，我用cs4调试半天老是报Main方法异常，郁闷很久才发现为什么。
]]></description>
			<content:encoded><![CDATA[<p>com.adobe.crypto官方库的md5算法性能实在不敢恭维，算个10m的byteArray在我机子上跑了大概12s！我勒个去，这可怎么叫人活。随后找到个by.blooddy.crypto，提升了2个数量级的性能！</p>
<p>作者博客：<a href="http://va.lent.in/blog/2010/06/23/100x-times-faster-md5-and-more/">http://va.lent.in/blog/2010/06/23/100x-times-faster-md5-and-more/</a></p>
<p>更新的博客：<a href="http://va.lent.in/blog/2010/07/10/more-on-faster-md5/">http://va.lent.in/blog/2010/07/10/more-on-faster-md5/</a></p>
<p>下载地址：<a href="http://www.blooddy.by/en/crypto/">http://www.blooddy.by/en/crypto/</a></p>
<p>我实际测试了下，10M的东西大概用了100ms左右，的确至少提升了100倍，作者此言非虚也！只是这个swc必须在flash cs5下编译才能成功，我用cs4调试半天老是报Main方法异常，郁闷很久才发现为什么。</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2010/11/30/846.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>google compiler 很强大</title>
		<link>http://army8735.org/2010/11/28/840.html</link>
		<comments>http://army8735.org/2010/11/28/840.html#comments</comments>
		<pubDate>Sun, 28 Nov 2010 14:27:43 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[compiler]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=840</guid>
		<description><![CDATA[用过一段时间JSA，也用过很久的YUIc，当然compiler也早早地接触了。
在使用js模板渲染时，为了可读性经常会如下写：
var tpl = [
	'&#60;div&#62;',
		'&#60;div&#62;&#60;%=someVars%&#62;&#60;/div&#62;',
	'&#60;/div&#62;'
].join('');
TUI.renderTpl(tpl, {
	someVars: '...'
});
内容多时，array.join()也会耗时。记得compiler可以合并字符串拼接，但不知道它居然还可以解析语义将这条声明也给优化了！
var tpl="&#60;div&#62;&#60;div&#62;&#60;%=someVars%&#62;&#60;/div&#62;&#60;/div&#62;";
不得不说，google的东西就是好！而且校验功能也比javascript lint准确多了，只是出现类似的注释时候，会显示警告，应该忽略掉它们的：
/**
 * @public 定义/执行action，和action无先后顺序
 * @param {function} key
 * @param {boolean} 如果已经do过，再次do是否重复此action列表，默认false
 */
WARNING...]]></description>
			<content:encoded><![CDATA[<p>用过一段时间JSA，也用过很久的YUIc，当然compiler也早早地接触了。</p>
<p>在使用js模板渲染时，为了可读性经常会如下写：</p>
<pre class="brush:js">var tpl = [
	'&lt;div&gt;',
		'&lt;div&gt;&lt;%=someVars%&gt;&lt;/div&gt;',
	'&lt;/div&gt;'
].join('');
TUI.renderTpl(tpl, {
	someVars: '...'
});</pre>
<p>内容多时，array.join()也会耗时。记得compiler可以合并字符串拼接，但不知道它居然还可以解析语义将这条声明也给优化了！</p>
<pre class="brush:js">var tpl="&lt;div&gt;&lt;div&gt;&lt;%=someVars%&gt;&lt;/div&gt;&lt;/div&gt;";</pre>
<p>不得不说，google的东西就是好！而且校验功能也比javascript lint准确多了，只是出现类似的注释时候，会显示警告，应该忽略掉它们的：</p>
<pre class="brush:js">/**
 * @public 定义/执行action，和action无先后顺序
 * @param {function} key
 * @param {boolean} 如果已经do过，再次do是否重复此action列表，默认false
 */</pre>
<pre class="brush:text">WARNING - Parse error. missing opening (
 * @param {function} key
                   ^
0 error(s), 1 warning(s)</pre>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2010/11/28/840.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>第5届D2前端技术论坛开始报名</title>
		<link>http://army8735.org/2010/11/19/838.html</link>
		<comments>http://army8735.org/2010/11/19/838.html#comments</comments>
		<pubDate>Fri, 19 Nov 2010 10:27:53 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[未分类]]></category>
		<category><![CDATA[d2]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=838</guid>
		<description><![CDATA[
推广下～
有人qq上问我土豆那位yy是男的还是女的，我后悔说真话了。
]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.d2forum.org/d2/5/" target="_blank"><img src="http://www.d2forum.org/d2/5/assets/img/d2_180x250.jpg" alt="第五届 D2前端技术论坛 (12月18日·杭州)" width="180" height="250" /></a></p>
<p>推广下～</p>
<p>有人qq上问我土豆那位yy是男的还是女的，我后悔说真话了。</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2010/11/19/838.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>提取改写了TUI.use，使其支持依赖加载css以及多文件同时依赖。</title>
		<link>http://army8735.org/2010/11/07/824.html</link>
		<comments>http://army8735.org/2010/11/07/824.html#comments</comments>
		<pubDate>Sun, 07 Nov 2010 04:04:48 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[前端开发]]></category>
		<category><![CDATA[依赖]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=824</guid>
		<description><![CDATA[从TUI.panel依赖想到的，panel的文件都在全局里面，每次修改都需上全局，修改测试起来都太麻烦。
TUI.use也只是单文件依赖加载，没有多文件也没有css依赖加载。
另一种角度考虑panel使用，将css和js分别都提取出来为单独的文件，在需要使用的时候，先mask掉page，然后异步加载这两个文件，完成后callback执行。
小知识：土豆前端静态文件版本管理系统很完善，每个静态文件发布时会在文件名（不包含扩展名）后自动增加_数字，这使得历史记录查询对比以及回退成为了可能。在需要异步加载所依赖的文件时，需要用use取得带版本号的完整url才可。
伪代码：
var module = {}, //模块库，用以类似YUI.use异步加载css或js模块
	modules = {}, //多个模块同时加载时记录的callback

TUI.mix({
	/**
	 * @public 字符串是否以指定sub结尾
	 * @param {string} str需要确定的字符串
	 * @return {string} 结尾
	 */
	endWith:...]]></description>
			<content:encoded><![CDATA[<p>从TUI.panel依赖想到的，panel的文件都在全局里面，每次修改都需上全局，修改测试起来都太麻烦。</p>
<p>TUI.use也只是单文件依赖加载，没有多文件也没有css依赖加载。</p>
<p>另一种角度考虑panel使用，将css和js分别都提取出来为单独的文件，在需要使用的时候，先mask掉page，然后异步加载这两个文件，完成后callback执行。</p>
<blockquote><p>小知识：土豆前端静态文件版本管理系统很完善，每个静态文件发布时会在文件名（不包含扩展名）后自动增加<span style="color: #ff0000;">_数字</span>，这使得历史记录查询对比以及回退成为了可能。在需要异步加载所依赖的文件时，需要用use取得带版本号的完整url才可。</p></blockquote>
<p>伪代码：</p>
<pre class="brush:js">var module = {}, //模块库，用以类似YUI.use异步加载css或js模块
	modules = {}, //多个模块同时加载时记录的callback

TUI.mix({
	/**
	 * @public 字符串是否以指定sub结尾
	 * @param {string} str需要确定的字符串
	 * @return {string} 结尾
	 */
	endWith: function(str, sub){
		return str.lastIndexOf(sub) == str.length - sub.length;
	},

	/**
	 * @public 注册单个模块文件方法
	 * @param {string} js的url
	 * @param {boolean} 是否延迟加载，即是在use调用的时候加载还是domready时加载
	 */
	join: function(url, noLazy) {
		var res = /(.+)_\d+\.(js|css)/.exec(url),
			key = res[1] + '.' + res[2],
			mod = module[key] || {};
		mod.name = key;
		mod.url = url;
		mod.cb = [];
		module[key] = mod;
		//若指定第2个参数为true，则立刻加载，否则use时加载
		if(noLazy) {
			this.use(key);
		}
	},

	/**
	 * @public 注册多个模块文件方法
	 * @param {array} 模块列表
	 * @param {boolean} 是否延迟加载，即是在use调用的时候加载还是domready时加载
	 */
	joins: function(list, noLazy) {
		var that = this;
		list.forEach(function(item) {
			that.join(item, noLazy);
		});
	},

	/**
	 * @public 异步使用单个css或js文件方法，
	 * @param {string} 文件的url不带版本号
	 * @param {function} 加载成功后的调用函数
	 */
	use: function(key, cb) {
		var mod = module[key],
			that = this;
		//必须先join注册
		if(!mod) {
			return;
		}
		if($.isFunction(cb)) {
			mod.cb.push(cb);
		}
		//尚未加载成功时
		if(!mod.loaded &amp;&amp; !mod.loading) {
			mod.loading = true;
			$(function() {
				if(that.endWith(key, '.js')) {
					that.getScript(mod.url, {
						charset: mod.charset,
						callback: function(){
							mod.loaded = true;
							mod.cb.forEach(function(cb) {
								cb();
							});
						}
					});
				}
				else if(that.endWith(key, '.css')) {
					that.getCss(mod.url, function() {
						mod.loaded = true;
						mod.cb.forEach(function(cb) {
							cb();
						});
					});
				}
				module[key] = mod;
			});
		}
		//已经加载完成了这个js文件，直接执行cb
		else if($.isFunction(cb)) {
			cb();
		}
	},

	/**
	 * @public 异步使用多个css或js文件方法，
	 * @param {array} url列表
	 * @param {function} 加载成功后的调用函数
	 */
	uses: function(keys, cb) {
		//所有mod必须先join注册
		for(var i = keys.length - 1; i &gt; -1; i--) {
			if(!module[keys[i]]) {
				return;
			}
		}
		var k = keys.join(''),
			mods = modules[k] || [],
			that = this;
		if($.isFunction(cb)) {
			mods.push(cb);
		}
		modules[k] = mods;
		keys.forEach(function(mod) {
			that.use(mod);
		});
		//定时侦听所有模块，全部加载完成后执行cb列表
		var interval = setInterval(function() {
			var fin = true;
			keys.forEach(function(mod) {
				if(!module[mod].loaded) {
					fin = false;
					return fin;
				}
			});
			if(fin) {
				mods.forEach(function(item) {
					item();
				});
				clearInterval(interval);
			}
		}, 50);
	},

	/**
	 * @public 异步加载js文件方法
	 * @param {string} js的url
	 * @param {object} 选项传入charset和callback
	 */
	getScript: function(url, op) {
		var s = this.create('script'),
			head = this.tag('head')[0],
			done = false;
		s.type = "text/javascript";
		s.async = true; //for firefox3.6
		if($.isFunction(op)) {
			op = { callback: op };
		}
		op = op || {};
		if(op.charset) {
			s.charset = op.charset;
		}
		s.src = url;
		s.onload = s.onreadystatechange = function(){
			if (!done &amp;&amp; (!this.readyState || this.readyState == "loaded" || this.readyState == "complete")) {
				done = true;
				//防止ie内存泄漏
				s.onload = s.onreadystatechange = null;
				head.removeChild(s);
				if(op.callback) {
					op.callback();
				}
			}
		};
		head.appendChild(s);
	},

	/**
	 * @public 异步加载css文件方法
	 * @param {string} css的url
	 * @param {function} callback
	 */
	getCss: function(url, cb) {
		var that = this;
		$.ajax({
			url: url,
			success: function(data) {
				var s = that.create('style'),
					head = that.tag('head')[0];
				s.type = 'text/css';
				//ie和其它要分开对待
				if(s.styleSheet) {
					s.styleSheet.cssText = data;
				}
				else {
					s.appendChild(document.createTextNode(data));
				}
				head.appendChild(s);
				if(cb) {
					cb();
				}
			}
		});
	}
});</pre>
<p>实际使用时，是这样：</p>
<pre class="brush:js">//这会在模板上jion
TUI.joins(['out_1.css', 'out_1.js']);
//真正执行
TUI.uses(['out.css', 'out.js'], function() {
	alert(1);
});</pre>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2010/11/07/824.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>安装eric5.0.3失败……</title>
		<link>http://army8735.org/2010/11/06/822.html</link>
		<comments>http://army8735.org/2010/11/06/822.html#comments</comments>
		<pubDate>Sat, 06 Nov 2010 07:24:50 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=822</guid>
		<description><![CDATA[IDLE用得实在难受，而我又不喜欢eclipse，目前支持python3.1的也只有eric了。pyqt4.8.1安装好了，eric5也提示完成，然后双击.bat……没反应……
我勒个去，google下发现也有相同的例子存在，虽然小版本号和我的不一致。有其它的啥IDE用啊……
]]></description>
			<content:encoded><![CDATA[<p>IDLE用得实在难受，而我又不喜欢eclipse，目前支持python3.1的也只有eric了。pyqt4.8.1安装好了，eric5也提示完成，然后双击.bat……没反应……<br />
我勒个去，google下发现也有相同的例子存在，虽然小版本号和我的不一致。有其它的啥IDE用啊……</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2010/11/06/822.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>更新了JAcld</title>
		<link>http://army8735.org/2010/11/03/817.html</link>
		<comments>http://army8735.org/2010/11/03/817.html#comments</comments>
		<pubDate>Wed, 03 Nov 2010 10:45:17 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[JAcld]]></category>
		<category><![CDATA[前端开发]]></category>
		<category><![CDATA[大写锁定提示]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=817</guid>
		<description><![CDATA[两点修改：

国产加壳浏览器延迟初始化，防止报异常。这点要感谢阿里的工程师们：http://www.aliued.cn/?p=3169
记录了scrollTop的值，防止要验证的input输入框在聚焦、验证切换焦点过程中发生的滚动条位移。

暂且放在土豆的passport测试系统上交给测试工程师测试，hoho，我在占测试mm的小便宜么～～
function(js, swf, target, tip) {
	var isIE = (navigator.appName.indexOf("Microsoft") != -1);
	var isWebkit = (navigator.userAgent.indexOf("AppleWebKit") != -1);
	var cssCompat = document.compatMode == "CSS1Compat";
	var...]]></description>
			<content:encoded><![CDATA[<p>两点修改：</p>
<ol>
<li>国产加壳浏览器延迟初始化，防止报异常。这点要感谢阿里的工程师们：<a href="http://www.aliued.cn/?p=3169">http://www.aliued.cn/?p=3169</a></li>
<li>记录了scrollTop的值，防止要验证的input输入框在聚焦、验证切换焦点过程中发生的滚动条位移。</li>
</ol>
<p>暂且放在土豆的passport测试系统上交给测试工程师测试，hoho，我在占测试mm的小便宜么～～</p>
<pre class="brush:js">function(js, swf, target, tip) {
	var isIE = (navigator.appName.indexOf("Microsoft") != -1);
	var isWebkit = (navigator.userAgent.indexOf("AppleWebKit") != -1);
	var cssCompat = document.compatMode == "CSS1Compat";
	var doc = cssCompat ? document.documentElement : document.body;
	var bDetecting = false, bCapsLock;
	var oSwf, oTarget, oTip, sDisplay;

	function $(id) {
		return document.getElementById(id);
	}
	function getSwf(name) {
		if(isIE) {
			return window[name];
		}
		else {
			return document[name];
		}
	}
	function addEvent(oNode, sType, fn) {
		if(window.addEventListener) {
			oNode.addEventListener(sType, fn, false);
		}
		else if(window.attachEvent) {
			oNode.attachEvent("on" + sType, fn);
		}
	}
	function show() {
		oTip.style.display = sDisplay;
	}
	function hide() {
		oTip.style.display = "none";
	}
	function scrollTop(v) {
		if(typeof v !== "undefined") {
			doc.scrollTop = v;
			if(!doc.scrollTop) document.body.scrollTop = v;
		}
		return window.pageYOffset || doc.scrollTop;
	}

	var jacld = {
		exec: function() {
			oSwf = getSwf(swf);
			oTarget = $(target);
			oTip = $(tip);
			//加载的swf、指定的检测对象、提示框缺一不可
			if(!oSwf || !oTarget || !oTip) {
				return;
			}
			//记住原先的tip的display
			sDisplay = oTip.style.display || "block";
			this.init();
		},
		init: function() {
			//除webkit外的其它浏览器
			addEvent(oTarget, "focus", function() {
				//防止循环死机
				if(bDetecting) {
					bDetecting = false;
					return;
				}
				var v = scrollTop();
				bDetecting = true;
				oSwf.focus();
				oSwf.detect();
				//模拟线程同步，使其最后执行
				setTimeout(function() {
					oTarget.focus();
					scrollTop(v);
				}, 0);
			});
			addEvent(oTarget, "blur", function() {
				if(bDetecting) {
					return;
				}
				hide();
			});
			addEvent(oTarget, "keydown", function(event) {
				event = event || window.event;
				var keyCode = event.keyCode;
				var v = scrollTop();
				//不在检测并且案件是capslock时才进行
				if(!bDetecting &amp;&amp; keyCode == 20) {
					bDetecting = true;
					oSwf.focus();
					oSwf.detect();
					oTarget.focus();
					scrollTop(v);
				}
			});
		},
		isCapsLock: function(b) {
			if(b) show();
			else hide();
		}
	}

	window[js] = jacld;
}</pre>
<p>主要是在flash聚焦之前记录scrollTop的值，离开后再主动设定回来。过程会有瞬间的闪烁，修改最终版完成后会传至<a href="http://code.google.com/p/jacld/" target="_blank">google code</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2010/11/03/817.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>360和tt浏览器对flash跨域的支持都不好</title>
		<link>http://army8735.org/2010/10/20/813.html</link>
		<comments>http://army8735.org/2010/10/20/813.html#comments</comments>
		<pubDate>Wed, 20 Oct 2010 10:12:15 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[JAcld]]></category>
		<category><![CDATA[前端开发]]></category>
		<category><![CDATA[大写锁定提示]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=813</guid>
		<description><![CDATA[http://logintest.tudou.com/login.do?noreg=ok
土豆的passport系统使用了jacld来提供密码输入框大写锁定提示功能——一款基于flash的东东。由于存放flash的域名和页面域名不一致，所以导致了跨域问题。
不过很简单，flash也是支持跨域的。jacld代码中也加入了Security.allowDomain(&#8220;*&#8221;)并且嵌入时allowScriptAccess被设置为了always。在所有主流浏览器下都没问题。
可惜的是，360和tt虽然是基于ie的，但是跨域方面却没有做好。倘若使用debugger版本会报SecurityError: Error #2060: 安全沙箱冲突的异常，普通版本自然会因此失效。
为了防止报错，只能捕获这一异常并防止它干扰用户了。很是可惜。
]]></description>
			<content:encoded><![CDATA[<p><a href="http://logintest.tudou.com/login.do?noreg=ok" target="_blank">http://logintest.tudou.com/login.do?noreg=ok</a></p>
<p>土豆的passport系统使用了<a href="http://code.google.com/p/jacld/" target="_blank">jacld</a>来提供密码输入框大写锁定提示功能——一款基于flash的东东。由于存放flash的域名和页面域名不一致，所以导致了跨域问题。</p>
<p>不过很简单，flash也是支持跨域的。jacld代码中也加入了<span style="color: #ff0000;">Security.allowDomain(&#8220;*&#8221;)</span>并且嵌入时<span style="color: #ff0000;">allowScriptAccess</span>被设置为了<span style="color: #ff0000;">always</span>。在所有主流浏览器下都没问题。</p>
<p>可惜的是，360和tt虽然是基于ie的，但是跨域方面却没有做好。倘若使用debugger版本会报<span style="color: #ff0000;">SecurityError: Error #2060: 安全沙箱冲突</span>的异常，普通版本自然会因此失效。</p>
<p>为了防止报错，只能捕获这一异常并防止它干扰用户了。很是可惜。</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2010/10/20/813.html/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>百度偶像几处可以更好的地方</title>
		<link>http://army8735.org/2010/09/28/801.html</link>
		<comments>http://army8735.org/2010/09/28/801.html#comments</comments>
		<pubDate>Tue, 28 Sep 2010 03:30:19 +0000</pubDate>
		<dc:creator>army</dc:creator>
				<category><![CDATA[as、flex]]></category>
		<category><![CDATA[前端开发]]></category>
		<category><![CDATA[用户体验设计]]></category>

		<guid isPermaLink="false">http://army8735.org/?p=801</guid>
		<description><![CDATA[在百度偶像内测的时候我得到了邀请码并且也试用了一阵子，目前偶像已进入beta阶段，我给我的一些坛子好友们也发了些邀请，过程中遇到几个细节上可以更完善的地方。于是乎一一述来。
先贴一曲：


如上图，外链的播放器这一点的确很让人享用，但是当歌名太长的时候，文字信息就会超出显示到外边。普通的桌面MP3播放器等，经常会有那种“文字滚动”的效果，即一行之类显示不完全，会让文字慢慢向左方滚动，如此展示完整。我在想偶像是否也可以用类似的或者其它的方式来解决这个问题呢？
再是外链链接方面，比如点击上图中的人名“西国の海妖”，应该是打开这位歌手的主页的，偶像确实也这样做了。但是遗憾的是，链接地址写的是相对地址，那么外链播放器这个链接也太……总之是个很低级的失误……
还有上传方面。我发现偶像在很多方面使用了flash，比如邀请注册的复制code那里，这与我们土豆很像，基本认定了这样一个准则：使用或浏览网站的用户一定是安装了必需版本的flash的。那么在上传方面，批量上传歌曲这种功能的出现就显得很人性化了。譬如从别的站点迁移过来的用户，有许多首歌要上传，一首首点岂不是要累死？以flash做个“高级上传”的页面功能，便可简化许多。
最后是歌词敏感过滤方面，比如我的lrc中如是填写：[01:18.99]上那繁盛帝国的荣耀与辉煌 转眼成荒芜坟场，会提示包含敏感词不能通过。仔细检查，原来是[01:18.99]这里有问题，难道是18.9被认为九月十八号比较敏感？类似的[02:08.96]也会报错，希望验证时对于lrc的[]时间部分可以忽略，毕竟一首歌那么多时间点，一一排查起来很恐怖。敏感提示的话最好也给个范围什么的，我用二分查找都很累……
]]></description>
			<content:encoded><![CDATA[<p>在百度偶像内测的时候我得到了邀请码并且也试用了一阵子，目前偶像已进入beta阶段，我给我的一些坛子好友们也发了些邀请，过程中遇到几个细节上可以更完善的地方。于是乎一一述来。</p>
<p>先贴一曲：</p>
<p><object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" width="360" height="150" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="align" value="middle" /><param name="src" value="http://o.baidu.com/static/flash/WidgetPlayer.swf?v=3.2&amp;tid=2948" /><embed type="application/x-shockwave-flash" width="360" height="150" src="http://o.baidu.com/static/flash/WidgetPlayer.swf?v=3.2&amp;tid=2948" align="middle"></embed></object></p>
<p><a href="http://army8735.org/wp-content/uploads/2010/09/ox.jpg"><img class="aligncenter size-full wp-image-802" title="ox" src="http://army8735.org/wp-content/uploads/2010/09/ox.jpg" alt="" width="384" height="154" /></a></p>
<p>如上图，外链的播放器这一点的确很让人享用，但是当歌名太长的时候，文字信息就会超出显示到外边。普通的桌面MP3播放器等，经常会有那种“文字滚动”的效果，即一行之类显示不完全，会让文字慢慢向左方滚动，如此展示完整。我在想偶像是否也可以用类似的或者其它的方式来解决这个问题呢？</p>
<p>再是外链链接方面，比如点击上图中的人名“<a href="http://o.baidu.com/people/index?uid=235206396" target="_blank">西国の海妖</a>”，应该是打开这位歌手的主页的，偶像确实也这样做了。但是遗憾的是，链接地址写的是相对地址，那么外链播放器这个链接也太……总之是个很低级的失误……</p>
<p>还有上传方面。我发现偶像在很多方面使用了flash，比如邀请注册的复制code那里，这与我们土豆很像，基本认定了这样一个准则：<strong>使用或浏览网站的用户一定是安装了必需版本的flash的</strong>。那么在上传方面，批量上传歌曲这种功能的出现就显得很人性化了。譬如从别的站点迁移过来的用户，有许多首歌要上传，一首首点岂不是要累死？以flash做个“高级上传”的页面功能，便可简化许多。</p>
<p>最后是歌词敏感过滤方面，比如我的lrc中如是填写：<strong>[01:18.99]上那繁盛帝国的荣耀与辉煌 转眼成荒芜坟场</strong>，会提示包含敏感词不能通过。仔细检查，原来是<strong>[01:18.99]</strong>这里有问题，难道是18.9被认为九月十八号比较敏感？类似的<strong>[02:08.96]</strong>也会报错，希望验证时对于lrc的[]时间部分可以忽略，毕竟一首歌那么多时间点，一一排查起来很恐怖。敏感提示的话最好也给个范围什么的，我用二分查找都很累……</p>
]]></content:encoded>
			<wfw:commentRss>http://army8735.org/2010/09/28/801.html/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

