<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
     xmlns:atom="http://www.w3.org/2005/Atom">
<atom:link href="http://dallas.example.com/rss.xml"
           rel="self"
           type="application/rss+xml" />
<channel>
<title><![CDATA[TSOST]]></title>
<link><![CDATA[http://allo.ave7.net]]></link>
<description><![CDATA[时空之滨]]></description>
<language><![CDATA[zh-CN]]></language>
<copyright><![CDATA[TSOST Version 6.0. By AlloVince. Copyright TSOST 2001-2008.INC]]></copyright>
<item>
<title><![CDATA[对应Yslow的网站速度优化方法略谈]]></title>
<link><![CDATA[http://allo.ave7.net/blog/view/110]]></link>
<description><![CDATA[
			<div class="toc" style="float:right;">
			<div style="text-align:center;"><b>目录</b> [<a href="javascript:;" onclick="var toc = document.getElementById('menu99705900');if(toc.style.display == 'none'){toc.style.display='block';this.innerHTML='折叠'}else{toc.style.display='none';this.innerHTML='展开'}">折叠</a>]</div>
			<div  id="menu99705900">
<ol>
	<li><a href="#toc_99150400">1. Make fewer HTTP requests / 减少Http请求数</a></li>
	<li><a href="#toc_99158800">2. Use a CDN / 使用CDN</a></li>
	<li><a href="#toc_99237800">3. Add an Expires header / 为文件头指定Expires</a></li>
	<li><a href="#toc_99247500">4. Gzip components / 启用Gzip压缩</a></li>
	<li><a href="#toc_99352000">5. Put CSS at the top / 将Css文件放在头部</a></li>
	<li><a href="#toc_99362200">6. Put JS at the bottom / 将Js文件放在底部</a></li>
	<li><a href="#toc_99410600">7. Avoid CSS expressions / 避免CSS expressions</a></li>
	<li><a href="#toc_99410900">8. Make JS and CSS external / 将Js和Css文件独立</a></li>
	<li><a href="#toc_99436600">9. Reduce DNS lookups / 减少DNS查询</a></li>
	<li><a href="#toc_99446600">10. Minify JS / 压缩Js文件</a></li>
	<li><a href="#toc_99496900">11. Avoid redirects / 避免重定向</a></li>
	<li><a href="#toc_99498600">12. Remove duplicate scripts / 移除重复的脚本</a></li>
	<li><a href="#toc_99528100">13. Configure ETags / 配置ETags</a></li>
</ol></div>
			</div><p>Yahoo!曾经针对网站速度体验提出了34条宝贵的准则《<a rel="external" href="http://developer.yahoo.com/performance/rules.html">Best Practices for Speeding Up Your Web Site</a>》，而<a rel="external" href="https://addons.mozilla.org/zh-CN/firefox/addon/5369">Yslow</a>正是按照这些准则，评测一个网站在速度体验上的优化程度的Firefox插件，将34条精简为更加直观的13条，并针对每一条给出从F~A的评分以及最终的总分。</p>
<p>当然从评测得到的只能是一个分数以及建议，如何改进还是要靠自己，这里要谈的就是实实在在的如何针对每一条进行优化：</p>
<h4 id="toc_99150400" style="text-align:center;">1. Make fewer HTTP requests / 减少Http请求数</h4>
<p>一个网页不可避免的要引入大量的外部文件：Javascript、css、背景图片……由于Http协议的无状态性，用户的每一次访问，都会重新向服务器请求所有文件，而大量Http请求的累加，正是影响网站速度的最主要原因。</p>
<p>所以这里的解决方法只有一个：合并。最理想的情况莫过于一个网页只包含一个css，一个js，一张背景图。</p>
<p>合并Js和Css文件很好理解，背景图片要怎么合并？这里采用的主要方法是CSS Sprites，简单说就是把所有的图片拼接成一张大图，在不同的Css里指定背景图坐标来显示不同图片。具体可以参考Dave Shea的<a rel="external" href="http://alistapart.com/articles/sprites">Image Slicing’s Kiss of Death</a>一文，还有网站提供了<a rel="external" href="http://spritegen.website-performance.org/">在线的CSS Sprites服务</a>，只需要上传小图片，就可以获得拼接后的大图以及相应坐标。</p>
<p>不过在当前越来越多动辄包含10余个文件的开发框架面前，减少Http请求数也变得越来越难。一直都认为所谓框架，给出的应该是一整套完善的开发思想，从服务器配置到数据库设计甚至是到UI体验乃至SEO，但现在很多Framework总是各自为战，后台与前端脱节，只在自己的一片领域里提供一定程度上的方便，没有考虑到最终产品的统合，甚至连基本的代码侵入性问题没有处理好（这里点名批评dojo，恨不得在所有的html标签上印上dojo的章子），不能不说是一种遗憾。</p>
<p>所以如果网站中采用框架的话，在框架的选择面前，建议多采用轻量级，侵入性低的框架，也是为了日后产品的优化维护着想。</p>
<h4 id="toc_99158800" style="text-align:center;">2. Use a CDN / 使用CDN</h4>
<p>CDN(Content delivery network)内容分发网络，能够智能根据网络节点情况选择服务节点，大型网站部署时尤为重要。不过这属于硬件级别的解决方案，我们没有条件配置CDN的时候，可以自行设置忽略这一项评测。</p>
<p>在Firefox地址栏键入about:config，然后新建一个字符串，名称为extensions.firebug.yslow.cdnHostnames，值为所要评测网站的域名，多个设置用逗号分隔。例如我的设置就是allo.ave7.net,localhost</p>
<h4 id="toc_99237800" style="text-align:center;">3. Add an Expires header / 为文件头指定Expires</h4>
<p>Expires是浏览器Cache机制的一部分，浏览器的缓存取决于Header中的四个值： Cache-Control， Expires， Last-Modified， ETag。这个项目的考评主要针对Cache-Control和Expires。</p>
<p>具体的Cache原理不是本文所涉及的，有兴趣的同学可以看看<a rel="external" href="http://www.mnot.net/cache_docs/">Caching Tutorial</a>一文。为了优化这个选项，我们所要做的是对站内所有的文件有针对性的设置Cache-Control和Expires，这里基于Apache主机举例：</p>
<p>首先开启<a rel="external" href="http://httpd.apache.org/docs/2.0/mod/mod_headers.html">mod_header</a>模块，在httpd.conf中取消</p>
<pre class="sql">
LoadModule headers_module modules/mod_headers.so
</pre>
<p>一行的注释。然后对于图片，文件等不会经常更新的文件设置一个比较长的过期时间</p>
<pre class="sql">
&lt;FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$"&gt;
Header set Expires "Thu, 15 Apr 2010 20:00:00 GMT"
&lt;/FilesMatch&gt;
</pre>
<p>对于Cache-Control可以设置的更加细致一些，这里我对图片，文件设置了1周，对XML，TXT设置了5小时，对html和php文件只设置了1小时。</p>
<pre class="sql">
&lt;FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$"&gt;
Header set Cache-Control "max-age=604800, public"
&lt;/FilesMatch&gt;

&lt;FilesMatch "\.(xml|txt)$"&gt;
Header set Cache-Control "max-age=18000, public, must-revalidate"
&lt;/FilesMatch&gt;

&lt;FilesMatch "\.(html|htm|php)$"&gt;
Header set Cache-Control "max-age=3600, must-revalidate"
&lt;/FilesMatch&gt;
</pre>
<p>另外Expires也可以通过开启<a rel="external" href="http://httpd.apache.org/docs/2.0/mod/mod_expires.html">mod_expires</a>来实现，这里不再举例。</p>
<h4 id="toc_99247500" style="text-align:center;">4. Gzip components / 启用Gzip压缩</h4>
<p>HTTP/1.1支持接收服务器端经过<a rel="external" href="http://www.gzip.org/">Gzip</a>压缩的数据，在Apache2中，可以开启<a rel="external" href="http://httpd.apache.org/docs/2.0/mod/mod_deflate.html">mod_deflate</a>实现。</p>
<p>同样去掉注释</p>
<pre class="sql">
LoadModule deflate_module modules/mod_deflate.so
</pre>
<p>然后对所有文本类文件添加Gzip处理</p>
<pre class="sql">
DeflateCompressionLevel 3
&lt;FilesMatch "\.(php|htm|html|js|css)$"&gt;
SetOutputFilter DEFLATE
&lt;/FilesMatch&gt;
</pre>
<h4 id="toc_99352000" style="text-align:center;">5. Put CSS at the top / 将Css文件放在头部</h4>
<p>很好理解的一条，主要是为了避免最后加载Css引起的浏览器白屏，改善用户体验。</p>
<h4 id="toc_99362200" style="text-align:center;">6. Put JS at the bottom / 将Js文件放在底部</h4>
<p>同样很容易理解，为了让DOM先行加载。</p>
<h4 id="toc_99410600" style="text-align:center;">7. Avoid CSS expressions / 避免CSS expressions</h4>
<p>CSS expressions可以轻易的引起浏览器假死，也不在W3C规范内，不只是避免，最好完全不要用。</p>
<h4 id="toc_99410900" style="text-align:center;">8. Make JS and CSS external / 将Js和Css文件独立</h4>
<p>将Js和Css文件单独做成外部文件加载，一则可以功能复用，二则可以生成缓存，当然这一条和第一条要互相参照找出最好的解决方案才是。</p>
<h4 id="toc_99436600" style="text-align:center;">9. Reduce DNS lookups / 减少DNS查询</h4>
<p>外部文件分散于多个服务器，连接每台服务器都会做一次DNS查询，这一条是针对多服务器的部署。</p>
<h4 id="toc_99446600" style="text-align:center;">10. Minify JS / 压缩Js文件</h4>
<p>压缩Js文件，Yahoo!官方推荐的工具是<a rel="external" href="http://crockford.com/javascript/jsmin">JSMin</a>和<a rel="external" href="http://developer.yahoo.com/yui/compressor/">YUI Compressor</a>。</p>
<h4 id="toc_99496900" style="text-align:center;">11. Avoid redirects / 避免重定向</h4>
<p>每一次的重定向都会重新发送Header请求。所以在Apache下，无比强大的<a rel="external" href="http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html">mod_rewrite</a>是必须要学的。</p>
<h4 id="toc_99498600" style="text-align:center;">12. Remove duplicate scripts / 移除重复的脚本</h4>
<p>开发中没有规划好，会出现页面中重复引用一个文件的情况，IE中即便是重复引用也会重新向服务器发送一次请求。</p>
<h4 id="toc_99528100" style="text-align:center;">13. Configure ETags / 配置ETags</h4>
<p>在第三条中已经对浏览器缓存机制中的Cache-Control和Expires进行了配置，这一条评测的是另外两个：Last-Modified和ETag</p>
<p>简单的说，即使设置了文件的期限，浏览器在访问资源时往往会因为Last-Modified和ETag而重新下载整个资源，所以简单的做法是关闭Last-Modified和ETag</p>
<p>在Apache中做如下配置</p>
<pre class="sql">
FileETag None

&lt;FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css)$"&gt;
Header unset Last-Modified
&lt;/FilesMatch&gt;
</pre>
<p>最后看看优化后的成果</p>
<p><img src="http://allo.ave7.net/photo/picasa/allovince/5220926002522558673/5233542371077548434/" alt="Yslow优化结果" /><img src="http://allo.ave7.net/photo/picasa/allovince/5220926002522558673/5234540292955979634/" alt="Yslow优化结果2" /></p>
]]></description>
<pubDate><![CDATA[Tue, 12 Aug 08 08:21:11 +0000]]></pubDate>
</item>
<item>
<title><![CDATA[使用Google Ajax Search with Jsonp 构建纯Javascript站内搜索]]></title>
<link><![CDATA[http://allo.ave7.net/blog/view/109]]></link>
<description><![CDATA[
			<div class="toc" style="float:right;">
			<div style="text-align:center;"><b>目录</b> [<a href="javascript:;" onclick="var toc = document.getElementById('menu99953100');if(toc.style.display == 'none'){toc.style.display='block';this.innerHTML='折叠'}else{toc.style.display='none';this.innerHTML='展开'}">折叠</a>]</div>
			<div  id="menu99953100">
<ol>
	<li><a href="#toc_99719200">最简单的Google Jsonp搜索</a></li>
	<li><a href="#toc_99819100">最简单的Google Jsonp本地搜索</a></li>
	<li><a href="#toc_99946600">更多问题</a></li>
</ol></div>
			</div><p>利用<a rel="external" href="http://code.google.com/apis/ajaxsearch/">Google AJAX Search</a>可以很快的建立起一个本地搜索，关于构建的方法，Google docs里已经有详细的讲述，也并非本文的重点。</p>
<p>利用Google的函数库，不可避免的要嵌入远端文件，数据样式也是经过处理後的。有些时候，由于种种条件限制，我们需要更加灵活轻便的解决方案，这时候就需要借助Google Ajax Search中的<a rel="external" href="http://www.json.org/">Jsonp</a>协议。</p>
<h4 id="toc_99719200" style="text-align:left;">最简单的Google Jsonp搜索</h4>
<p>在<a rel="external" href="http://code.google.com/apis/ajaxsearch/documentation/#fonje">Flash and other Non-Javascript Environments</a>一节中，可以了解到，如果对</p>
<p>http://ajax.googleapis.com/ajax/services/search/web?v=1.0</p>
<p>发送Get请求，就能返回相应的Jsonp格式数据，比起标准API来，这里的数据不携带任何冗余信息，可以很方便的处理和调用。例如使用JQuery，短短几行代码就可以实现Ajax的搜索引擎。</p>
<p>首先当然要有一个搜索表单</p>
<pre class="xml">
&lt;form class="googlesearch" action="http://www.google.com/search" onsubmit="search(this);return false;"&gt;
	&lt;div id="search_box"&gt;
			&lt;input id="searchvalue" value="" name="q" /&gt;
			&lt;input id="searchsubmit" type="submit" value="搜索" /&gt;
	&lt;/div&gt;
&lt;/form&gt;
</pre>
<p>然后是表单提交时调用的Js函数</p>
<pre class="jscript">
function search(form){
	$.ajax({
		url:'http://ajax.googleapis.com/ajax/services/search/web?v=1.0&amp;q=' + encodeURIComponent(form.q.value),
		dataType : 'jsonp',
		success: function(json){
			var res = '';
			for(var i in json.responseData.results){
				for(var j in json.responseData.results[i]){
					res = res + j + ':' + json.responseData.results[i][j] + "\n";
				}
			}
			alert(res);
		}
	});
}
</pre>
<p>可以查看做好的<a rel="external" href="http://allo.ave7.net/lab/google_ajax_search_json/google_ajax_search_with_jsonp.html">Demo</a>，点击搜索，会弹出google的返回的搜索结果。</p>
<h4 id="toc_99819100" style="text-align:left;">最简单的Google Jsonp本地搜索</h4>
<p>仅仅这些，还不能满足一个构成本地搜索的条件。在标准API中，可以通过</p>
<pre class="jscript">
var siteSearch = new GwebSearch();
siteSearch.setUserDefinedLabel("allo.ave7.net");
siteSearch.setUserDefinedClassSuffix("siteSearch");
</pre>
<p>来实现对特定域名"allo.ave7.net"的检索，jsonp中怎么实现相同的功能？只能通过增加查询关键词"site:allo.ave7.net"来达到目的。即在上文的url部分改为</p>
<pre class="jscript">
url:'http://ajax.googleapis.com/ajax/services/search/web?v=1.0&amp;q=' + encodeURIComponent(form.q.value) + '+site%3Aallo.ave7.net',
</pre>
<p>来看看最简单的本地搜索：<a rel="external" href="http://allo.ave7.net/lab/google_ajax_search_json/google_local_search_with_jsonp.html">Demo</a>。在这个Demo里，所有检索出的数据都限定在域名allo.ave7.net里。</p>
<h4 id="toc_99946600" style="text-align:left;">更多问题</h4>
<p>就像前面的本地搜索一样，开发往往要需要很多可以设置的参数，比起标准API来，Jsonp只能通过url传达设定，能预设的参数不够丰富。具体的参数可以参看<a rel="external" href="http://code.google.com/intl/en/apis/ajaxsearch/documentation/reference.html#_intro_fonje">Flash and other Non-Javascript Environments</a>一节，需要注意的一些问题有：</p>

<ul>
	<li>分页的实现：Jsonp只返回前4页以及总记录数，事实上如果发送第四页以后的请求，仍然能够获得正确的回应，只是分页函数要自己写了。</li>
	<li>每页的条目数：这个设定比较苛刻，只能通过rsz=small/large来获得每页4条/8条的数据，可能是Jsonp最不方便之处了。</li>
	<li>结果的过滤：Google Web搜索会自动过滤一些可能重复的项目，留意观察一下google的搜索参数，是通过filter=0/1开关的。但在Jsonp的响应中，对第一页的请求，过滤是关闭的，第二页以后则又自动打开了。不算是大问题，但会让分页的现实变得很奇怪。虽然文档中提到可以通过safe=active/moderate/off来改变过滤，但写入这个参数后并没有影响到检索结果。希望知情人士告知问题所在。</li>
</ul><p>最后将allo.ave7.net的本地搜索单独抽出做成<a rel="external" href="http://allo.ave7.net/lab/google_ajax_search_json/google_search_with_jsonp_advance.html">Demo</a>，也可以下载本次的<a rel="external" href="http://cid-01e48df64f8bd957.skydrive.live.com/embedrowdetail.aspx/Source/searchjson.7z">全部源代码</a>。</p>
]]></description>
<pubDate><![CDATA[Thu, 07 Aug 08 06:32:57 +0000]]></pubDate>
</item>
<item>
<title><![CDATA[七街改造计划]]></title>
<link><![CDATA[http://allo.ave7.net/blog/view/108]]></link>
<description><![CDATA[<p>有改造7街的想法很久了，但到现在仍然只是一个模糊的概念，没有在脑子里形成一套可行的方案，在这里全部提出来一方面理清自己的思路，并供参考：</p>
<h4 id="toc_00043700" style="text-align:left;">为什么要有七街？</h4>
<p>当初也曾妄想过借这一块地方挖挖金子，或许也能像疼逊性浪那样一飞冲天，功成名就。但事实上我们做不到，高访问量伴随而来的就是乌烟瘴气的环境。</p>
<p>我是个很恋旧的人，直至现在，也仍然在怀念网络刚刚兴起时的互联网环境，那个时候很多小白，很多菜鸟，当然我也是其中之一，但大家至少都会心存感激，互相尊重。</p>
<p>而如今网络几乎就是我生活的一部分，在这个脑残体、DDD横飞的年代，我无力改变大环境，也无力改变人心。但至少，能自己开垦出一亩三分地，土地平旷，屋舍俨然，阡陌交通，鸡犬相闻。开辟一块干净舒适的地方，让自己和朋友每天能心情愉快的交流，此为七街关闭注册以来的唯一初衷。</p>
<h4 id="toc_00139000" style="text-align:left;">现在的七街有什么？</h4>

<ol>
	<li>品味和个性。末日扉页、每日一歌、同人音乐、七街志……都能说明七街有自己独特的品味和受众群体，我们无需迎合大众，而是要更加张扬自己的个性。</li>
	<li>研发实力。有强大程序员葛阁坐镇，不需要借用任何现有的程序，不受任何制约，只要是好的Idea都可以转换为实实在在的程序。</li>
	<li>团队和TeamWork。某年某月某日某人灵光一现，20天之后一本100页从零开始完全原创的网络杂志就已经摆在了面前，没有任何约束，也没有任何金钱和荣誉作为报酬，但每个人都尽己所能的贡献了力量，没有听到一声不情愿或者抱怨。七街有自己的团队，只要我们想做，就一定能做到。</li>
</ol><h4 id="toc_00145900" style="text-align:left;">我想把七街建设成什么样？</h4>
<p>1.包容性。与现有的各种网络流行服务相整合。例如我来七街之前，已经有了自己的Blog，自己的网络硬盘，聊天工具等等，可以通过简单输入用户ID，将自己已有的网络生活与七街想结合，并可以无缝过渡到七街提供的更优秀的服务。</p>
<p>这些服务可能包括：</p>

<ul>
	<li>一个经过改造的Wordpress Blog托管（用户单点登录，简单聚合，自动升级更新，附送七街二级域名），或者是一个可高度自定义的个人主页</li>
	<li>一个兼容饭否、twitter等微博客并具备聊天吐槽功能的服务</li>
	<li>一个与Lastfm交互，记录用户音乐喜好，能从freedb自动获得歌曲CD信息，以及歌词信息，用户间可以交流下载的音乐社区系统</li>
	<li>一个与各大书站、豆瓣等交互，能自动采集信息，wiki方式的图书交流社区</li>
	<li>一个用于专题建设以及资料整理的网站构建系统</li>
</ul><p>2.以人为本。而是通过程序本身对用户的行为进行引导，避免繁琐的规章制度。用户所有的数据精简为两个参数：贡献度和索取度，并由此赋予用户相应的权限。</p>
]]></description>
<pubDate><![CDATA[Mon, 04 Aug 08 03:21:10 +0000]]></pubDate>
</item>
<item>
<title><![CDATA[非定期唠叨]]></title>
<link><![CDATA[http://allo.ave7.net/blog/view/107]]></link>
<description><![CDATA[<p><span style="color:#FF6600;">◎</span> 用Wiki方式写博客实在是很享受的事情，将以前的很多老文也用Wiki语法重新整理过，清爽许多。每次打开Blog总要满足的检查一下华丽的<a rel="external" href="http://validator.w3.org/check?uri=referer">W3C Strict</a>认证，以及<a rel="external" href="http://chrispederick.com/work/web-developer/">Web developer</a>三个绿油油的对钩，PageRank在blog正式启用3个月后也由0直接跳为了3。YD的程序员葛阁总是不自觉的想让自己的眼前的东西变得顺眼，这是职业病，得治！</p>
<p><span style="color:#0080ff;">口</span> 订了志方あきこ的新作PCゲーム「うみねこのなく頃に」テーマソング</p>

<ul>
	<li><img src="http://allo.ave7.net/photo/picasa/allovince/5228404734189758337/5228420217851913378/" alt="PCゲーム「うみねこのなく頃に」テーマソング うみねこのなく頃に" /></li>
	<li>2008/8/15 （コミケ初日先行発売）</li>
	<li>品番：KNIL-0003</li>
	<li>定価（税込） 1,500円</li>
</ul><p>想不到志方あきこ会参与寒蝉的相关物，清冷妖异的试听与寒蝉诡异的世界观确实是相得益彰，大期待。</p>
<p><span style="color:#ff0000;">×</span> 还以为只有央视会拍主旋律，没想到「利家と松」比之是丝毫不弱啊，本剧详细讲述了与历史形象谬之千里的高大全主角前田利家的光辉一生。其实想想也明白，能在几大势力中左右逢源并渔翁得利，最终攀到权利顶峰的人，又怎么可能为了坚持原则不惜牺牲一切。更不用说非但没提历史上利家娶了五个侧室，反而大谈其对爱情的忠贞。</p>
<p>不过反町隆史的織田信長还是很出彩的，对照正在播放的「ロト6で3億2千万当てた男」里唯唯诺诺的形象尤其欢乐。</p>
<p><span style="color:#008000">△</span> 貌似已经很久没有写过轻松点的东西了，整天迷惘的纠结于那些有所谓的和无所谓的，或者YY一些有意义和没意义的，忽然觉得自己也有些不认识自己了。</p>
<p>恩，应该改变些什么了。</p>
]]></description>
<pubDate><![CDATA[Thu, 31 Jul 08 05:41:19 +0000]]></pubDate>
</item>
<item>
<title><![CDATA[基于Picasa、PHP、AJAX的图片REST架构的简单实现 番外篇]]></title>
<link><![CDATA[http://allo.ave7.net/blog/view/106]]></link>
<description><![CDATA[<p>好吧，其实为什么完结了还能再出续集这个问题无需太过深究，就像PB里面的Sara，可以死了再活，活了再死，全凭导演一句话口牙。</p>
<p>回到正题，之前的简单REST实现只能算是一个模型，很难实用到真正的开发中去，瓶颈在于模型中所有远端服务器的数据都先读入到Web服务器，通过PHP脚本处理后再返回客户端。这是一个常规的也是通用的解决方案，因为远端服务器有可能做各种各样的功能限制：检测用户身份，限制访问来源等等，而这些限制都可以通过强大的Curl进行破解。</p>
<p>但终究考虑到服务器资源的占用，这样的实现是不切实际的，既然Picasa已经提供了足够丰富的接口，那么用纯Javascript也能实现近似的效果。当然这样一来作为完全客户端的实现，也就和REST没有任何关系了，所以作为番外篇，仅供参考。</p>
<p>说了这么多，看看完全客户端的实现能做出什么东西来：<a rel="external" href="http://allo.ave7.net/lab/photo_restjs/index.html">点击查看DEMO</a></p>
<p>Demo中首先显示图片未加载的loading，当图片数据从Picasa加载之后，Loading画面被替换为实际图像的缩略图，并且点击会有Lightbox的特效。</p>
<p>首先通过Url_Rewrite将所有的请求转发到loading图片</p>
<pre class="jscript">
RewriteEngine On
RewriteRule   ^photo\/picasa\/.* loading.gif
</pre>
<p>而完成所有页面效果的，只需要14行代码：</p>
<pre class="jscript">
$("img").each(function(){
	var src = $(this).attr("src").split("/");
	var aim = $(this);
	$.ajax({
		url:  "http://picasaweb.google.com/data/entry/api/user/" + src[0] + '/albumid/' + src[1] + '/photoid/' + src[2] + '?alt=json',
		dataType : 'jsonp',
		success: function(json){
			var id = 'photo' + src[1] + src[2];
			var title = json.entry.summary.$t ? json.entry.summary.$t : json.entry.title.$t;
			aim.attr("alt",title).attr("src",json.entry.media$group.media$thumbnail[1].url).wrap('&lt;a class="thickbox" id="' + id + '" href="'+ json.entry.media$group.media$content[0].url + '?imgmax=800' + '" rel="album_' + src[1] + '" title="' + title + '"&gt;&lt;/a&gt;');
			tb_init('#'+ id); //apply thickbox effact to this photo
		}
	});
});
</pre>
<p>大致的实现与<a href="http://allo.ave7.net/blog/view/105">完结篇</a>里的代码区别不大，但这里却是完全依赖于Picasa强大API的：</p>

<ul>
	<li>Picasa支持Jsonp！通过向API设置alt=json可以取得Json格式数据，尽管没有在文档中找到关于可以返回Json数据的描述，但这确确实实是可行的。</li>
	<li>Picasa支持外链！准确的说Picasa对于缩略图的外链是没有限制的，而这里所谓的缩略图，事实上能支持最高达800像素规格的图片（参看<a rel="external" href="http://code.google.com/apis/picasaweb/reference.html#Parameters">Picasa Web Albums query parameters reference</a>），对于网页图片浏览来说，已经足够了。</li>
</ul><p>基于以上两点，可以简单通过Js，就能搭建起各种Picasa的扩展应用，同理也可以适用到Flickr以及其他提供Jsonp接口的网络相册。不过这个基于Js的方案也有很大缺点，如果用户禁用了Javascript，就什么也看不到了。</p>
<p>最后仍然是本次实现的<a rel="external" href="http://cid-01e48df64f8bd957.skydrive.live.com/embedrowdetail.aspx/Source/photorestjs.7z">Code Download</a></p>
]]></description>
<pubDate><![CDATA[Wed, 30 Jul 08 04:07:45 +0000]]></pubDate>
</item>
<item>
<title><![CDATA[基于Picasa、PHP、AJAX的图片REST架构的简单实现 完结篇]]></title>
<link><![CDATA[http://allo.ave7.net/blog/view/105]]></link>
<description><![CDATA[<p>一如既往的前情提要：</p>

<ul>
	<li><a href="http://allo.ave7.net/blog/view/98">基于Picasa、PHP、AJAX的图片REST架构的简单实现(1)</a></li>
	<li><a href="http://allo.ave7.net/blog/view/99">基于Picasa、PHP、AJAX的图片REST架构的简单实现(2)</a></li>
	<li><a href="http://allo.ave7.net/blog/view/104">基于Picasa、PHP、AJAX的图片REST架构的简单实现(3)</a></li>
</ul><p>现在，服务器端的架设终于全部结束了，我们可以向服务器端同一个URL发送不同的Header请求，从而得到不同的反馈，REST简单说来也就是这么一回事。但很遗憾，URL只有一个，而且现在的浏览器并没有智能到可以通过超链接携带Header信息。我们只能通过附加手段达到目的，这个附加手段毫无疑问就是最后一位主角：Ajax。</p>
<h4 id="toc_00727500" style="text-align:center;">Step.3 客户端通过Ajax发送不同的Header请求</h4>
<p>准确的说我们利用的是<a rel="external" href="http://www.w3.org/TR/XMLHttpRequest/">XMLHttpRequest</a>对象，来对服务器发送不同的header请求。在W3C的定义中，不仅能够找到GET、POST，XMLHttpRequest支持的header类型一共包括</p>

<ul>
	<li>GET</li>
	<li>POST</li>
	<li>HEAD</li>
	<li>PUT</li>
	<li>DELETE</li>
	<li>OPTIONS</li>
</ul><p>这些Methods早在1999年就被定义于<a rel="external" href="http://www.ietf.org/rfc/rfc2616">RFC2616</a>里，到今天终于有了用武之地，真是可喜可贺。</p>
<pre class="jscript">
var client = new XMLHttpRequest();
client.open("GET", "test.txt", true);
client.send();
</pre>
<p>这就是一个最简单的通过XMLHttpRequest发送请求的例子，同理可以将GET替换为其他Method。如果再加上监听状态变化的readystatechange，以及获得反馈的responseXXX，你会发现Ajax原来就是这么一回事。</p>
<p>这里为了使演示更加简单，使用JQuery的Ajax应用，以下是客户端代码:</p>
<pre class="jscript">
	$("img").each(function(){
		var src = $(this).attr("src");
		var aim = $(this);
		$.ajax({
			type: "GET",
			url: src,
			dataType : 'json',
			success: function(json){
				var title= "&lt;p&gt;这是一张名为「" + json.title + "」的相片&lt;br /&gt;拍摄于：" + json.date + "&lt;br /&gt;你可以访问：" + json.full + "来获得这张照片的全图。&lt;/p&gt;";
				aim.after(title);
				aim.attr("alt",json.title);
			}
		});
		return false;
	});
</pre>
<p>这段代码遍历页面的所有图片，然后对这张图片的URL发送Get请求。发送的请求被我们编写的服务器端接收并取得对应的Json数据并返回，最终在客户端显示出来。</p>
<p>至此，这个最简单的图片REST架构便完成了，或许花这么大功夫最终只显示出一张图片来，还称之为构架，实在是小题大作。但最终能剔除所有冗余信息并实现HTML代码的最简化，我自己是玩的不亦乐乎的。</p>
<p>最后附上<a rel="external" href="http://cid-01e48df64f8bd957.skydrive.live.com/embedrowdetail.aspx/Source/photorest.7z">全部代码下载</a>，也可以<a rel="external" href="http://allo.ave7.net/lab/photo_rest/">在线查看</a>。</p>
<h5 id="toc_00913400" style="text-align:center;">付录：HTTP-Header最高绝技之翻墙术</h5>
<p>其实在国内有很多AV国的网站上不了，并不是GFW的功劳，而网站为了避免拦截正常的访问，也很少会去封IP段。那么究竟为什么很多XX站不能访问呢，在HTTP-Header中，有一个叫Accept-Language的字段负责描述用户的系统语言，国内的Accept-Language值一般都是zh-cn,zh，AV国的很多网站都是通过识别这个值来区别用户。</p>
<p>那么很简单，更改Accept-Language伪装成AV国用户就可以了。</p>

<ul>
	<li>Firefox下，地址栏访问about:config，然后搜索intl.accept_languages，将值由zh-cn,zh改为ja即可。</li>
	<li>IE下，工具——Internet选项——语言——将列表里的语言全部删除即可。</li>
</ul><p>恩恩，这也只是一个技术问题，大家回去自行研究吧。</p>
]]></description>
<pubDate><![CDATA[Thu, 24 Jul 08 07:49:47 +0000]]></pubDate>
</item>
<item>
<title><![CDATA[基于Picasa、PHP、AJAX的图片REST架构的简单实现(3)]]></title>
<link><![CDATA[http://allo.ave7.net/blog/view/104]]></link>
<description><![CDATA[<p style="text-indent:0px">前情提要：<a href="http://allo.ave7.net/blog/view/98">基于Picasa、PHP、AJAX的图片REST架构的简单实现(1)</a><br />
<a href="http://allo.ave7.net/blog/view/99">基于Picasa、PHP、AJAX的图片REST架构的简单实现(2)</a><br />
</p>
<p>之前我们从远端获得了图片信息，但是这些和REST还是不沾边的。访问同一个URL，要想获得不同的信息，以目前的软硬件条件，最好的实现方法还是对HTTP Headers进行处理。所以这次的话题是——</p>
<h4 id="toc_01115900" style="text-align:center;">Step.2 服务器端接受不同的HTTP Headers返回不同的信息</h4>
<p>既然是服务器端，我们仍然采用PHP实现。</p>
<p>PHP对于Header信息的处理是很丰富的，常见的Header都已经存放在预定义变量$_SERVER中了。如果你对什么是Header还没有概念，可以在Firefox中安装一个<a rel="external" href="https://addons.mozilla.org/en-US/firefox/addon/3829">Live HTTP Headers</a>自行体验一下。</p>
<p>现在问题是：如此之多的Header，到底选择哪个或者哪几个来进行分析？用户的客户端语言，浏览器，IP等等，都是可以进行发挥的。这里为了简单说明问题，选择REQUEST_METHOD，HTTP_REFERER以及HTTP_X_REQUESTED_WITH来进行演示。</p>
<p>简单说明这三个参数：</p>

<ul>
	<li>REQUEST_METHOD是页面的请求方法，也是目前REST实现的核心。</li>
	<li>HTTP_REFERER包含了用户的访问来源，一般是用户前一个访问的URL</li>
	<li>HTTP_X_REQUESTED_WITH则代表这是一个Xmlhttprequest请求，可以简单的看成是Ajax请求。</li>
</ul><p>以下就是个人的随意发挥了，我所约定的有效服务器反馈包括：</p>

<ul>
	<li>因为不涉及更新等操作，页面的请求方法只限于GET</li>
	<li>如果HTTP_REFERER存在，即说明用户在网页中或者通过链接点击访问照片，服务器返回照片的缩略图。</li>
	<li>如果HTTP_REFERER不存在，说明用户直接通过URL访问图片，服务器返回照片的全图。</li>
	<li>如果HTTP_X_REQUESTED_WITH存在，则说明用户在通过Ajax访问图片，这时返回一个Json格式的照片信息</li>
</ul><p>形象一点用实例说明的话：</p>
<p><a rel="external" href="http://allo.ave7.net/lab/photo_rest/photo/picasa/allovince/5213571636180988625/5213571644436936978">点击链接</a>会看到照片的缩略图，将这张照片的地址粘贴到浏览器地址栏直接访问的话，会看到照片的大图。而在<a rel="external" href="http://allo.ave7.net/lab/photo_rest/demo2.html">Demo</a>中，点击下面的按钮，则可以看到发送Ajax请求到同一个地址时的反馈。</p>
<p>最后还是附上服务器端的代码</p>
<pre class="php">
require_once 'XML/Unserializer.php';

$Unserializer = &amp;new XML_Unserializer();
$options = array('parseAttributes'   =&gt; true);
$Unserializer-&gt;setOptions($options);

if($userid &amp;&amp; $albumid &amp;&amp; $photoid) {
	$xml = "http://picasaweb.google.com/data/feed/api/user/".$_GET['userid']."/albumid/".$_GET['albumid']."/photoid/".$_GET['photoid'];
	$status = $Unserializer-&gt;unserialize($xml,true);
	//XML文件解析出错, 报错并退出
	if (PEAR::isError($status)) {
	   die($status-&gt;getMessage());
	   exit;
	}
	//如果是一个AJAX访问，返回JSON描述
	elseif($_SERVER['REQUEST_METHOD'] == 'GET' &amp;&amp; $_SERVER['HTTP_X_REQUESTED_WITH']){
		$pic = $Unserializer-&gt;getUnserializedData();
		$part = explode('.',$pic['media:group']['media:content']['url']);
		$json = json_encode(array(
			'title' =&gt; $pic['media:group']['media:description']['_content'] ? $pic['media:group']['media:description']['_content'] : $pic['title']['_content'],
			'date' =&gt; gmdate("F d Y H:i:s",strtotime($pic['updated'])),
			'ext' =&gt; $part[count($part) -1],
			'full' =&gt; $pic['media:group']['media:content']['url']
		));
		echo "($json)";
	}
	//HTTP_REFERER有无的区分
	elseif($_SERVER['REQUEST_METHOD'] == 'GET' &amp;&amp; $_SERVER['HTTP_REFERER']) {
		$pic = $Unserializer-&gt;getUnserializedData();
		header("Content-Type: image/jpeg");
		curl_exec(curl_init($pic['icon']));
	}
	elseif($_SERVER['REQUEST_METHOD'] == 'GET' &amp;&amp; !$_SERVER['HTTP_REFERER']) {
		$pic = $Unserializer-&gt;getUnserializedData();
		header("Content-Type: ".$pic['media:group']['media:content']['type']);
		curl_exec(curl_init($pic['media:group']['media:content']['url']));
	}
}
</pre>
]]></description>
<pubDate><![CDATA[Wed, 23 Jul 08 08:11:44 +0000]]></pubDate>
</item>
<item>
<title><![CDATA[PHP Wiki语法解析类]]></title>
<link><![CDATA[http://allo.ave7.net/blog/view/103]]></link>
<description><![CDATA[<p>出于很多考虑，终于还是扔掉了<a rel="external" href="http://pear.php.net/">Pear</a>的<a rel="external" href="http://pear.php.net/package/Text_Wiki/redirected">Text_wiki</a>改用自己写的Wiki语法解析，专用于本<a href="http://allo.ave7.net/av_framework">Framework</a>。比起Text_wiki来改善，或者说是按自己的习惯改变了很多方面:</p>

<ol>
	<li>语法上综合了<a rel="external" href="http://wikipedia.org/">wikipedia</a>和<a rel="external" href="http://c2.com/cgi/wiki?PukiWiki">puki wiki</a>。</li>
	<li>支持html标记插入。</li>
	<li>生成的代码通过W3C Strict验证。</li>
	<li>即使不做解析，也是一篇表意良好，格式工整的text文档，而不像很多乍看上去如天书一般的Wiki语法</li>
	<li>解析速度比Text_wiki快</li>
	<li>加入了很多方便的特殊标记。</li>
</ol><p>目前只是发布前的演示，正式版将附加在Framework中发布，有兴趣的同学可以索取源代码。那么，实验开始：</p>
<h3 id="toc_01389200" style="text-align:center;">Title Test</h3>
<p>Wiki代码：</p>
<pre>
=h1=
==h2==
===h3===
====h4====
=====h5=====
======h6======
=======h7=======
</pre>
<p>转换结果：</p>
<h1 id="toc_01490200" style="text-align:center;">h1</h1>
<h2 id="toc_01495200" style="text-align:center;">h2</h2>
<h3 id="toc_01500000" style="text-align:center;">h3</h3>
<h4 id="toc_01505200" style="text-align:center;">h4</h4>
<h5 id="toc_01510500" style="text-align:center;">h5</h5>
<h6 id="toc_01515900" style="text-align:center;">h6</h6>
<h6 id="toc_01524000" style="text-align:center;">=h7=</h6>
<hr />
<h3 id="toc_01531500" style="text-align:center;">Table Test</h3>
<p>Wiki代码：</p>
<pre>
! 1 ! 2 ! 3 ! 4 ! 5 !
! 1 | 2 | 3 | 4 | 5 |
! 1  2 !| 3 | 4 | 5 |
! 1  2 || 3 | 4 | 5 |
! 1 | 2  3 || 4 | 5 |
! 1 | 2 | 3  4 || 5 |
! 1 | 2 | 3 | 4  5 ||
! 1  2  3 !!| 4 | 5 |
! 1 | 2  3  4 ||| 5 |
! 1 | 2 | 3  4  5 |||
! 1  2  3  4 !!!| 5 |
! 1 | 2  3  4  5 ||||
! 1  2  3  4  5 |||||

! ---------- ! ----------- ! ---------- !
!left        |        right|   middle   |
</pre>
<p>转换结果：</p>

<table><tbody>
<tr>
	<th  align="center">1</th>
	<th  align="center">2</th>
	<th  align="center">3</th>
	<th  align="center">4</th>
	<th  align="center">5</th>
</tr>
<tr>
	<th  align="center">1</th>
	<td  align="center">2</td>
	<td  align="center">3</td>
	<td  align="center">4</td>
	<td  align="center">5</td>
</tr>
<tr>
	<th colspan="2" align="center">1  2</th>
	<td  align="center">3</td>
	<td  align="center">4</td>
	<td  align="center">5</td>
</tr>
<tr>
	<td colspan="2" align="center">1  2</td>
	<td  align="center">3</td>
	<td  align="center">4</td>
	<td  align="center">5</td>
</tr>
<tr>
	<th  align="center">1</th>
	<td colspan="2" align="center">2  3</td>
	<td  align="center">4</td>
	<td  align="center">5</td>
</tr>
<tr>
	<th  align="center">1</th>
	<td  align="center">2</td>
	<td colspan="2" align="center">3  4</td>
	<td  align="center">5</td>
</tr>
<tr>
	<th  align="center">1</th>
	<td  align="center">2</td>
	<td  align="center">3</td>
	<td colspan="2" align="center">4  5</td>
</tr>
<tr>
	<th colspan="3" align="center">1  2  3</th>
	<td  align="center">4</td>
	<td  align="center">5</td>
</tr>
<tr>
	<th  align="center">1</th>
	<td colspan="3" align="center">2  3  4</td>
	<td  align="center">5</td>
</tr>
<tr>
	<th  align="center">1</th>
	<td  align="center">2</td>
	<td colspan="3" align="center">3  4  5</td>
</tr>
<tr>
	<th colspan="4" align="center">1  2  3  4</th>
	<td  align="center">5</td>
</tr>
<tr>
	<th  align="center">1</th>
	<td colspan="4" align="center">2  3  4  5</td>
</tr>
<tr>
	<td colspan="5" align="center">1  2  3  4  5</td>
</tr>
</tbody></table>

<table><tbody>
<tr>
	<th  align="center">----------</th>
	<th  align="center">-----------</th>
	<th  align="center">----------</th>
</tr>
<tr>
	<th  align="left">left</th>
	<td  align="right">right</td>
	<td  align="center">middle</td>
</tr>
</tbody></table>
<hr />
<h3 id="toc_01843200" style="text-align:center;">Paragraph Test</h3>
<p>Wiki代码：</p>
<pre>
//Remark will not be parse
This is a normal paragraph.

This is another normal paragraph.

This is a paragraph with newline of br mark.
This is a paragraph with newline of br mark.
This is a paragraph with newline of br mark.
</pre>
<p>转换结果：</p>
<p>This is a normal paragraph.</p>
<p>This is another normal paragraph.</p>
<p style="text-indent:0px">This is a paragraph with newline of br mark.<br />
This is a paragraph with newline of br mark.<br />
This is a paragraph with newline of br mark.<br />
</p>
<hr />
<h3 id="toc_01915900" style="text-align:center;">Blockquote Test</h3>
<p>Wiki代码：</p>
<pre>
> Blockquote Level1
>> Blockquote Level2
>> Blockquote Level2
>>> Blockquote Level3
>>> Blockquote Level3
</pre>
<p>转换结果：</p>
<blockquote>
	<p>Blockquote Level1</p>
	<blockquote>
		<p>Blockquote Level2</p>
		<p>Blockquote Level2</p>
		<blockquote>
			<p>Blockquote Level3</p>
			<p>Blockquote Level3</p>
		</blockquote>
	</blockquote>
</blockquote>
<hr />
<h3 id="toc_01998800" style="text-align:center;">List Test</h3>
<p>Wiki代码：</p>
<pre>
* ul list level1
** ul list level2
** ul list level2
*** ul list level3
**** ul list level4
**** ul list level4
* ul list level1
** ul list level2
* ul list level1

# ol list level1
## ol list level2
## ol list level2
### ol list level3
#### ol list level4
#### ol list level4
# ol list level1
## ol list level2
# ol list level1
</pre>
<p>转换结果：</p>

<ul>
	<li>ul list level1<ul>
		<li>ul list level2</li>
		<li>ul list level2<ul>
			<li>ul list level3<ul>
				<li>ul list level4</li>
				<li>ul list level4</li>
			</ul></li>
		</ul></li>
	</ul></li>
	<li>ul list level1<ul>
		<li>ul list level2</li>
	</ul></li>
	<li>ul list level1</li>
</ul>
<ol>
	<li>ol list level1<ol>
		<li>ol list level2</li>
		<li>ol list level2<ol>
			<li>ol list level3<ol>
				<li>ol list level4</li>
				<li>ol list level4</li>
			</ol></li>
		</ol></li>
	</ol></li>
	<li>ol list level1<ol>
		<li>ol list level2</li>
	</ol></li>
	<li>ol list level1</li>
</ol><hr />
<h3 id="toc_02205100" style="text-align:center;">Advance Test</h3>
<p>Wiki代码：</p>
<pre>
Wiki Parser can identify a url [http://allo.ave7.net/] or an image [http://www.ave7.net/logo.gif] with [http://allo.ave7.net/|account].
You can also use &lt;i&gt;&lt;b&gt;Html Marks&lt;/b&gt;&lt;/i&gt; inline.
How forcibly specify this is a url [link:http://www.ave7.net/logo.gif] or an image 
[img:http://allo.ave7.net/photo/picasa/allovince/5220926002522558673/5220926248939178194|photo].
</pre>
<p>转换结果：</p>
<p style="text-indent:0px">Wiki Parser can identify a url <a rel="external" href="http://allo.ave7.net/">http://allo.ave7.net/</a> or an image <img src="http://www.ave7.net/logo.gif" alt="http://www.ave7.net/logo.gif" /> with <a rel="external" href="http://allo.ave7.net/">account</a>.<br />
You can also use <i><b>Html Marks</b></i> inline.<br />
How forcibly specify this is a url <a rel="external" href="http://www.ave7.net/logo.gif">http://www.ave7.net/logo.gif</a> or an image<br />
<img src="http://allo.ave7.net/photo/picasa/allovince/5220926002522558673/5220926248939178194" alt="photo" />.<br />
</p>
]]></description>
<pubDate><![CDATA[Fri, 18 Jul 08 05:05:19 +0000]]></pubDate>
</item>
<item>
<title><![CDATA[Vim配置外一篇(中文化、输入法、代码补全等)]]></title>
<link><![CDATA[http://allo.ave7.net/blog/view/102]]></link>
<description><![CDATA[
			<div class="toc" style="float:right;">
			<div style="text-align:center;"><b>目录</b> [<a href="javascript:;" onclick="var toc = document.getElementById('menu02767900');if(toc.style.display == 'none'){toc.style.display='block';this.innerHTML='折叠'}else{toc.style.display='none';this.innerHTML='展开'}">折叠</a>]</div>
			<div  id="menu02767900">
<ol>
	<li><a href="#toc_02288300">多语言平台下的中文化实现</a></li>
	<li><a href="#toc_02439000">IME输入法切换设置</a></li>
	<li><a href="#toc_02439200">代码自动补全</a></li>
	<li><a href="#toc_02494700">自定义快捷键</a></li>
	<li><a href="#toc_02500100">至懒人</a></li>
	<li><a href="#toc_02594100">至更懒的人</a></li>
</ol></div>
			</div><p>Vim不愧是地球上最强的文本编辑器之一（不加之一恐怕Emacs用户会有意见- -），用Vim就像用Foobar一样，必须先调教一番，使之很好的符合自己的习惯才能达到最高的效率。</p>
<p>之前（前情提要：<a href="http://allo.ave7.net/blog/view/91">非中文系统下Gvim中文化解决方法</a>）提到了Vim在其他语言Win32平台下的中文化实现，这里再做一些补充修订：</p>
<h4 id="toc_02288300" style="text-align:center;">多语言平台下的中文化实现</h4>
<p>首先是编码设置</p>
<pre class="sql">
"设置内核为UTF-8
set enc=utf-8
"设置解码顺序,这个顺序经测试可以很好的识别UTF-8,JIS,GBK
set fencs=utf-8,ucs-bom,shift-jis,gb18030,gbk,gb2312,cp936
</pre>
<p>然后设置界面</p>
<pre class="sql">
"语言设置
set langmenu=zh_CN.UTF-8
language message zh_CN.UTF-8
set guifont=NSimSun:h10
set helplang=cn
source $VIMRUNTIME/delmenu.vim
source $VIMRUNTIME/menu.vim
</pre>
<p>注意这里需要下载Vim的<a rel="external" href="http://vcd.gro.clinux.org">中文文档</a></p>
<h4 id="toc_02439000" style="text-align:center;">IME输入法切换设置</h4>
<p>在Win32环境下，Vim总是会自作聪明的自动切换到IME输入法。如果想要关闭自动切换，只需要设置</p>
<pre class="sql">
set iminsert=0 imsearch=0
</pre>
<p>即可，但由于Vim提供了判断IME输入是否打开的multi_byte_ime，我们就可以更加智能的加一些处理</p>
<pre class="sql">
if has('multi_byte_ime')
	"未开启IME时光标背景色
	hi Cursor guifg=bg guibg=Orange gui=NONE
	"开启IME时光标背景色
	hi CursorIM guifg=NONE guibg=Skyblue gui=NONE
	" 关闭Vim的自动切换IME输入法(插入模式和检索模式)
	set iminsert=0 imsearch=0
	" 插入模式输入法状态未被记录时，默认关闭IME
	"inoremap &lt;silent&gt; &lt;ESC&gt; &lt;ESC&gt;:set iminsert=0&lt;CR&gt;
endif
</pre>
<p>以上设置可以记忆IME开启状态，并用不同的光标颜色提示当前输入法</p>
<h4 id="toc_02439200" style="text-align:center;">代码自动补全</h4>
<p>实现代码补全需要插件<a rel="external" href="http://ctags.sourceforge.net/">Ctags</a>,将下载的Ctags解压到任意文件夹，然后将Ctags目录追加到环境变量里，之后我们进入项目所在根目录，运行Ctags -R，Ctags会解析所有项目文件并生成一个类似索引的tags文件，然后Vim运行补全时会从tags文件中取得数据。</p>
<p>当然如果更新了类函数定义，也要再次运行Ctags重新生成一次索引，这没有Eclipse那样华丽而且智能，但相比较那些专用IDE的体积和启动速度，Vim的表现仍然非常出色。</p>
<p>默认的代码补全快捷键是Ctrl+X Ctrl+O，可以使用插件<a rel="external" href="http://www.vim.org/scripts/script.php?script_id=1643">SuperTab</a>将快捷键与Tab键合并</p>
<h4 id="toc_02494700" style="text-align:center;">自定义快捷键</h4>
<p>Normal模式下可以很方便的用nmap设定自定义快捷键，不过可惜的是键盘上的键位也已经被占用的七七八八了。仅列举自己常用的两个作为例子：</p>
<pre class="sql">
nmap mm :%s/\r//g&lt;cr&gt;
</pre>
<p>双击m键可以删除Win下生成的多余换行符CR（在Vim中可以看到蓝色的^M）</p>
<pre class="sql">
nmap tt :%s/^\([\s　]\+\)/    /g&lt;cr&gt;:%s/^更新时间.*\d$//g&lt;cr&gt;:%s/&lt;a href.*&lt;\/a&gt;$//g&lt;cr&gt;:%s/\([\s　]*\n\)\+/\r\r/&lt;cr&gt;
</pre>
<p>这个就比较复杂一点，双击t键实现对在起点下载的TXT文本进行排版并删除里面多余的广告等。</p>
<p>最终效果截图</p>
<p><img src="http://allo.ave7.net/photo/picasa/allovince/5220926002522558673/5220926248939178194" alt="Vim of AlloVince" /></p>
<h4 id="toc_02500100" style="text-align:center;">至懒人</h4>
<p>好吧，贴出自己的配置，如果只想复制粘贴的同学可以各取所需，不过注意配置对应的插件</p>
<pre class="sql">
set nocompatible
source $VIMRUNTIME/vimrc_example.vim
source $VIMRUNTIME/mswin.vim
behave mswin

"设置工作目录为当前编辑文件的目录
set bsdir=buffer
set autochdir

"编码设置
set enc=utf-8
set fencs=utf-8,ucs-bom,shift-jis,gb18030,gbk,gb2312,cp936

"语言设置
set langmenu=zh_CN.UTF-8
language message zh_CN.UTF-8
set guifont=NSimSun:h10
set helplang=cn
source $VIMRUNTIME/delmenu.vim
source $VIMRUNTIME/menu.vim

"禁止生成临时文件
set nobackup

"搜索忽略大小写
set ignorecase 

"搜索逐字符高亮
set incsearch

"行内替换
set gdefault

"始终显示行号
set nu!

"Tab键的宽度
set shiftwidth=4
set tabstop=4

"配色方案
colorscheme rainbow_fruit

"输入法设置
if has('multi_byte_ime')
	"未开启IME时光标背景色
	hi Cursor guifg=bg guibg=Orange gui=NONE
	"开启IME时光标背景色
	hi CursorIM guifg=NONE guibg=Skyblue gui=NONE
	" 关闭Vim的自动切换IME输入法(插入模式和检索模式)
	set iminsert=0 imsearch=0
	" 插入模式输入法状态未被记录时，默认关闭IME
	"inoremap &lt;silent&gt; &lt;ESC&gt; &lt;ESC&gt;:set iminsert=0&lt;CR&gt;
endif

"自动缩进
set ai!

"与Windows共享剪贴板
set clipboard+=unnamed

"Ctags的默认索引(需要插件Ctags)
set tags=$VIMRUNTIME/tags
"添加类型检测
filetype plugin indent on
"智能补全
"set completeopt=longest,menu


"快捷键调用WinManager(需要插件WinManager)
let g:winManagerWindowLayout='FileExplorer'
nmap ff :WMToggle&lt;cr&gt;
nmap mm :%s/\r//g&lt;cr&gt;
"规范行首空格&lt;cr&gt;去除多余字符&lt;cr&gt;删除空白行&lt;cr&gt;规范行数
nmap tt :%s/^\([\s　]\+\)/    /g&lt;cr&gt;:%s/^更新时间.*\d$//g&lt;cr&gt;:%s/&lt;a href.*&lt;\/a&gt;$//g&lt;cr&gt;:%s/\([\s　]*\n\)\+/\r\r/&lt;cr&gt;

"通过ctrl+方向键切换窗口(需要插件MiniBufExplorer)
let g:miniBufExplMapCTabSwitchBufs = 1
let g:miniBufExplMapWindowNavArrows = 1
</pre>
<h4 id="toc_02594100" style="text-align:center;">至更懒的人</h4>
<p>好吧，我放下载就是了…… <a rel="external" href="http://cid-01e48df64f8bd957.skydrive.live.com/embedrowdetail.aspx/Soft/Vim.7z">点击我</a>试试本Blog新增的下载功能吧，下载后解压到D:根目录，将Ctags目录（D:\Vim\vim71\plugin\ctags）加入环境变量即可</p>
]]></description>
<pubDate><![CDATA[Tue, 08 Jul 08 06:24:51 +0000]]></pubDate>
</item>
<item>
<title><![CDATA[官方同步插件Weave0.2 for Firefox3试用简评]]></title>
<link><![CDATA[http://allo.ave7.net/blog/view/101]]></link>
<description><![CDATA[<p><a rel="external" href="https://services.mozilla.com/">Weave</a>是Mozilla官方推出的浏览器同步项目，目前Firefox的同步插件<a rel="external" href="http://www.google.com/tools/firefox/browsersync/">Google Browser Sync</a>已经停止了开发，所以Firefox3.0中尚没有可用的同步插件，而Weave0.2的推出给FF3带来了一点希望。</p>
<p>安装，重启，试用……一个小时后我对Weave0.2的表现只有四个字可以形容：“惨不忍睹”。</p>
<p>首先是不友好，账户注册完毕到数据上传是完全没有问题的，但如果要下载同步数据，需要从邮件激活Weave服务，否则会一直提示连接服务器超时。基本的提示信息都起不到相应的向导作用，很难相信这是面向普通用户的产品。</p>
<p>然后是速度，Weave的同步不是像Google Browser Sync那样即时通信，而是退出FF后执行，而服务器又慢到不能忍，每次退出都要停顿30秒至数分钟，最可怕的是如果强行中断同步则会驻留一个 Firefox进程在内存中，真怀疑这不是官方插件，而是官方病毒- -|||</p>
<p>对于真正的同步功能也很难让人满意，用作测试的数据是1000个左右的书签，但同步过程中浏览器却严重拖慢，连正常的浏览都无法进行。不知道是服务器速度影响还是插件本身缺陷。</p>
<p>虽然Weave的野心很大，在预定开发的功能里还能看到插件同步等等让人浮想联翩的词汇，但在一个勉强能用的版本出现之前，需要同步功能的同学还是老老实实用FF2.0+Google Browser Sync吧</p>
<p>另外补充一个Firefox3 css hack之JQuery版</p>
<pre class="jscript">
$.browser.mozilla &amp;&amp; parseFloat($.browser.version) &gt; 1.8
</pre>
<p>用js获得的FF3的版本并不是软件开发版本3.0，而是Gecko内核版本1.9，很有意思</p>
]]></description>
<pubDate><![CDATA[Thu, 03 Jul 08 05:30:28 +0000]]></pubDate>
</item>
</channel>
</rss>