<?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>Allen.M成长的路</title>
	<atom:link href="http://blog.allenm.me/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.allenm.me</link>
	<description>冷静的思考是解决问题的最佳方式</description>
	<lastBuildDate>Sun, 01 Apr 2012 09:00:21 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>python中函数参数的默认值和List, dict</title>
		<link>http://blog.allenm.me/2012/03/python-default-parameter-value-with-list-or-dict/</link>
		<comments>http://blog.allenm.me/2012/03/python-default-parameter-value-with-list-or-dict/#comments</comments>
		<pubDate>Fri, 30 Mar 2012 15:42:19 +0000</pubDate>
		<dc:creator>allenm</dc:creator>
				<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://blog.allenm.me/?p=721</guid>
		<description><![CDATA[Python 的函数定义中，有种带有默认值的参数的语法，例如： def foo( p = [] ): print p 如果我们调用此函数的时候，没有传入参数 p ,那 p 就用默认值。 接下来，我们看看下面这段代码会得到什么结果： def foo( p = [] ): p.append('a') print p foo() foo() 最开始，直觉告诉我，会得到结果： ['a'] ['a'] 但是实际结果是: ['a'] ['a','a'] 原来对于这种形式定义的带默认值的参数，参数的默认值是在函数定义的时候初始化的，当我们使用了 mutable 的对象的时候，我们中途改变了这个对象，在后面的函数调用中，它就不再是写在代码里的那个默认值。显然这样是很混乱的，我们不应该这样做。 python 官方文档也解释了这个事情，并且给出了解决方案，当我们需要一个 mutable 的对象作为默认值的时候，我们可以这样做： &#8230; <a href="http://blog.allenm.me/2012/03/python-default-parameter-value-with-list-or-dict/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Python 的函数定义中，有种带有默认值的参数的语法，例如：</p>
<pre class="brush:py">def foo( p = [] ):
    print p</pre>
<p>如果我们调用此函数的时候，没有传入参数 p ,那 p 就用默认值。</p>
<p>接下来，我们看看下面这段代码会得到什么结果：</p>
<pre class="brush:py">def foo( p = [] ):
    p.append('a')
    print p

foo()
foo()</pre>
<p>最开始，直觉告诉我，会得到结果：</p>
<pre>['a']
['a']</pre>
<p>但是实际结果是:</p>
<pre>['a']
['a','a']</pre>
<p>原来对于这种形式定义的带默认值的参数，参数的默认值是在函数定义的时候初始化的，当我们使用了 mutable 的对象的时候，我们中途改变了这个对象，在后面的函数调用中，它就不再是写在代码里的那个默认值。显然这样是很混乱的，我们不应该这样做。<br />
<a href="http://docs.python.org/reference/compound_stmts.html#function-definitions" target="_blank"> python 官方文档</a>也解释了这个事情，并且给出了解决方案，当我们需要一个 mutable 的对象作为默认值的时候，我们可以这样做：</p>
<pre class="brush:py">
def foo( p = None ):
    if p is None:
        p = []
    p.append('a')
    print p
</pre>
<p>这样每次都是生成一个新的，就没问题了。为了证实，带默认值的参数确实是在函数定义的时候初始化的，我们可以使用 id(p) 这个函数来查看这个变量的 identity , 可以看到，如果不传参数，让函数使用默认值，每次的 id 都是一样的。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.allenm.me/2012/03/python-default-parameter-value-with-list-or-dict/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>解放你的 ALT(CMD)+TAB 键吧</title>
		<link>http://blog.allenm.me/2012/02/free-your-alt-tab-key/</link>
		<comments>http://blog.allenm.me/2012/02/free-your-alt-tab-key/#comments</comments>
		<pubDate>Tue, 28 Feb 2012 14:39:44 +0000</pubDate>
		<dc:creator>allenm</dc:creator>
				<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://blog.allenm.me/?p=717</guid>
		<description><![CDATA[做前端开发的童鞋们，最常敲的一组键就是 alt(cmd)+tab 然后紧接着是 F5 或者 ctrl(cmd) + r 了吧。这是在干什么？写好一段样式看看效果啊。 那我们能不能边写样式，边让浏览器自动加载最新的 css 呢？当然是可以的了，业界已经有很多这样的工具了。比如国内前段时间曾经成功推广过的 F5 ，还有国外的 live.js xrefresh 等工具。 但是这些工具都没有适合我的。F5 需要用它提供的 HTTP 服务，但是对于一个大型站点来说，静态资源都是单独管理的，页面上一般都写的绝对 URL 使用 cookie free 的域名或者 CDN 的域名。为了开发方便，我们一般会用 apache 在本地搭一个 style 环境，像我们现在，因为经常需要跨应用访问 css, js 这些，本地环境不一定有这些文件，还需要用 url rewrite 把这些文件 rewrite 到一个公共环境去。这些复杂功能都是 &#8230; <a href="http://blog.allenm.me/2012/02/free-your-alt-tab-key/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>做前端开发的童鞋们，最常敲的一组键就是 alt(cmd)+tab 然后紧接着是 F5 或者 ctrl(cmd) + r 了吧。这是在干什么？写好一段样式看看效果啊。</p>
<p>那我们能不能边写样式，边让浏览器自动加载最新的 css 呢？当然是可以的了，业界已经有很多这样的工具了。比如国内前段时间曾经成功推广过的 F5 ，还有国外的 live.js xrefresh 等工具。</p>
<p>但是这些工具都没有适合我的。F5 需要用它提供的 HTTP 服务，但是对于一个大型站点来说，静态资源都是单独管理的，页面上一般都写的绝对 URL 使用 cookie free 的域名或者 CDN 的域名。为了开发方便，我们一般会用 apache 在本地搭一个 style 环境，像我们现在，因为经常需要跨应用访问 css, js 这些，本地环境不一定有这些文件，还需要用 url rewrite 把这些文件 rewrite 到一个公共环境去。这些复杂功能都是 F5 所不能提供的。live.js 只能对 css 和 page 同域才有效，而且还不支持 @import ，xrefresh 也需要使用它提供的 HTTP 服务。而且这些工具都有一个共同点，是都需要往页面插入一段它的 js 。</p>
<p>于是，我就自己造了一个，优先满足我的需求，那就是要做到服务器无关，编辑器无关。然后要支持 css 和 page 不同域，支持 @import 。而我平时又使用 chrome 开发，那就写一个 chrome 插件好了。而且由于使用了浏览器插件技术，所以我也可以做到不在页面插入任何 JS，不改变任何 DOM 结构，尽量保证安全，不影响页面功能。</p>
<p>现在这个项目的源码托管在 github ：<a href="https://github.com/allenm/css-auto-reload" target="_blank">https://github.com/allenm/css-auto-reload</a> , 欢迎各位提 BUG和建议，或者来写一个其他浏览器的插件。</p>
<p>如果你和我一样喜欢使用 chrome 开发，那就直接来这里 <a href="https://chrome.google.com/webstore/detail/fiikhcfekfejbleebdkkjjgalkcgjoip" target="_blank">https://chrome.google.com/webstore/detail/fiikhcfekfejbleebdkkjjgalkcgjoip</a> 安装，使用很简单，只要点击插件图标，就会点亮图标，表示正在对当前标签页进行监控，再次点击会关闭监控。</p>
<p>详细介绍和使用说明可以看上面 github 项目的介绍。另外我还录了一段操作视频，你可以先看看，再决定要不要试试这个工具。</p>
<p>&nbsp;<br />
<object width="480" height="400" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"><param name="src" value="http://player.youku.com/player.php/sid/XMzU3MDc5NzI0/v.swf" /><param name="allowfullscreen" value="true" /><param name="quality" value="high" /><param name="allowscriptaccess" value="always" /><embed width="480" height="400" type="application/x-shockwave-flash" src="http://player.youku.com/player.php/sid/XMzU3MDc5NzI0/v.swf" allowfullscreen="true" quality="high" allowscriptaccess="always" /></object></p>
<p>如果使用后觉得好用，确实对你有所帮助，不要忘记向你身边的 web developer 们介绍下哦，有心情的话，可以去 chrome web store 上面给我个好评哦。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.allenm.me/2012/02/free-your-alt-tab-key/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>jQuery deferred 对象的 promise 方法</title>
		<link>http://blog.allenm.me/2012/01/jquery_deferred_promise_method/</link>
		<comments>http://blog.allenm.me/2012/01/jquery_deferred_promise_method/#comments</comments>
		<pubDate>Sun, 01 Jan 2012 07:17:39 +0000</pubDate>
		<dc:creator>allenm</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[Jquery]]></category>

		<guid isPermaLink="false">http://blog.allenm.me/?p=695</guid>
		<description><![CDATA[jQuery 从 1.5 版本引入了 deferred 对象，这是一个基于 CommonJS Promises/A 的设计，为了方便异步操作，大家都知道，在 js 中，异步代码是非常的多。 这篇博客不是来详细讲解 $.Dererred 的，阮一峰 的博客里有一篇博客详细介绍了这个。但是在这篇博客中，关于 promise() 这个方法的讲解却是错误的，我发现这个是因为我徒弟去学习这个的时候，看了这篇文章，然后我让他给我讲述的时候，发现了这个错误。所以我想写篇 blog 来说明下。 update(2012.1.2):  我针对此问题给一峰发了 email, 他已经针对下面的问题进行了更新，下面的引用来自他最初的版本。现在他博客中对 promise() 的讲解是正确的，如果想了解整个  Deferred 对象，建议直接移步他的博客中学习。同时感谢阮一峰发现的我这篇博客中的一个小错误，最后面的那段代码，现在已经修复。 下面是引用自阮一峰的博客: 这里有两个地方需要注意。 首先，最后一行不能直接返回dtd，必须返回dtd.promise()。原因是jQuery规定，任意一个deferred对象有三种执行状态&#8212;-未完成，已完成和已失败。如果直接返回dtd，$.when()的默认执行状态为”已完成”，立即触发后面的done()方法，这就失去回调函数的作用了。dtd.promise()的目的，就是保证目前的执行状态&#8212;-也就是”未完成”&#8212;-不变，从而确保只有操作完成后，才会触发回调函数。 下面是 jQuery 的官方文档： The deferred.promise() method allows an asynchronous function to prevent other code from &#8230; <a href="http://blog.allenm.me/2012/01/jquery_deferred_promise_method/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>jQuery 从 1.5 版本引入了 deferred 对象，这是一个基于 <a href="http://wiki.commonjs.org/wiki/Promises/A">CommonJS Promises/A</a> 的设计，为了方便异步操作，大家都知道，在 js 中，异步代码是非常的多。</p>
<p>这篇博客不是来详细讲解 $.Dererred 的，<a href="http://www.ruanyifeng.com/home.html" target="_blank">阮一峰</a> 的博客里有<a href="http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html" target="_blank">一篇博客</a>详细介绍了这个。但是在这篇博客中，关于 promise() 这个方法的讲解却是错误的，我发现这个是因为我徒弟去学习这个的时候，看了这篇文章，然后我让他给我讲述的时候，发现了这个错误。所以我想写篇 blog 来说明下。</p>
<p><span style="color: #ff9900;">update(2012.1.2):  <span style="color: #000000;">我针对此问题给一峰发了 email, 他已经针对下面的问题<a href="http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html" target="_blank">进行了更新</a>，下面的引用来自他最初的版本。现在他博客中对 promise() 的讲解是正确的，如果想了解整个  Deferred 对象，建议直接<a href="http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html" target="_blank">移步他的博客</a>中学习。同时感谢阮一峰发现的我这篇博客中的一个小错误，最后面的那段代码，现在已经修复。</span></span></p>
<p>下面是引用自<a href="http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html" target="_blank">阮一峰的博客</a>:</p>
<blockquote><p>这里有两个地方需要注意。</p>
<p>首先，最后一行不能直接返回dtd，必须返回<a href="http://api.jquery.com/deferred.promise/" target="_blank">dtd.promise()</a>。原因是jQuery规定，任意一个deferred对象有三种执行状态&#8212;-未完成，已完成和已失败。如果直接返回dtd，$.when()的默认执行状态为”已完成”，立即触发后面的done()方法，这就失去回调函数的作用了。dtd.promise()的目的，就是保证目前的执行状态&#8212;-也就是”未完成”&#8212;-不变，从而确保只有操作完成后，才会触发回调函数。</p></blockquote>
<p>下面是 <a href="http://api.jquery.com/deferred.promise/" target="_blank">jQuery 的官方文档</a>：</p>
<blockquote><p>The <code>deferred.promise()</code> method allows an asynchronous function to prevent other code from interfering with the progress or status of its internal request. The Promise exposes only the Deferred methods needed to attach additional handlers or determine the state (<code>then</code>,<code>done</code>, <code>fail</code>, <code>always</code>,<code>pipe</code>, <code>progress</code>, and <code>state</code>), but not ones that change the state (<code>resolve</code>, <code>reject</code>, <code>progress</code>, <code>resolveWith</code>, <code>rejectWith</code>, and <code>progressWith</code>).</p></blockquote>
<p>也就是说，deferred.promise() 只是阻止其他代码来改变这个 deferred 对象的状态。可以理解成，通过 deferred.promise() 方法返回的 deferred promise 对象，是没有 resolve ,reject, progress , resolveWith, rejectWith , progressWith 这些可以改变状态的方法，你只能使用 done, then ,fail 等方法添加 handler 或者判断状态。</p>
<p>deferred.promise() 改变不了 deferred 对象的状态，作用也不是保证目前的状态不变，它只是保证你不能通过 deferred.promise() 返回的 deferred promise 对象改变 deferred 对象的状态。如果我们这个地方直接返回 dtd，也是可以工作的，.done 的处理函数还是会等到 dtd.resolve() 之后才会执行.</p>
<p>具体在那篇博客的例子, 如果我们把代码改成如下的形式：</p>
<pre class="brush: js">var dtd = $.Deferred(); // 新建一个deferred对象
var wait = function(dtd){
    var tasks = function(){
        alert("执行完毕！");
        dtd.resolve(); // 改变deferred对象的执行状态
    };
    setTimeout(tasks,5000);
    return dtd;
};
$.when(wait(dtd))
.done(function(){ alert("哈哈，成功了！"); })
.fail(function(){ alert("出错啦！"); });</pre>
<p>这样的执行结果和先前返回 dtd.promise 的结果是一样的。</p>
<p>差别在什么地方呢？如果我们把 $.when 的这块的代码改成这样的：</p>
<pre class="brush: js">var d = wait(dtd);
$.when(d)
.done(function(){ alert("哈哈，成功了！"); })
.fail(function(){ alert("出错啦！"); });
d.resolve();</pre>
<p>我们会发现 alert(“哈哈，成功了！”) 会立即执行，“执行完毕”却需要5秒后才弹出来。</p>
<p>但是如果我们 wait 函数最后是 return dtd.promise() 这里 d.resolve() 就会报错了，因为对象 d 不存在 resolve() 方法。</p>
<p>同样如果我们把代码改成:</p>
<pre class="brush: js">var dtd = $.Deferred(); // 新建一个deferred对象
var wait = function(dtd){
    var tasks = function(){
　　     alert("执行完毕！");
　　     dtd.resolve(); // 改变deferred对象的执行状态
　　 };
　　 setTimeout(tasks,5000);
　　 return dtd.promise();
};
dtd.resolve();
$.when( wait(dtd))
.done(function(){ alert("哈哈，成功了！"); })
.fail(function(){ alert("出错啦！"); });</pre>
<p>我们也可以发现 alert(“哈哈，成功了！”) 会立即执行，因为 dtd 这个 deferred 对象在被传入 wait 之前，已经被 resolve() 了，而 deferred 对象一旦被 resolve 或者 reject 之后，状态是不会改变的。</p>
<p>然后我们再把 $.wait 这块的代码改成:</p>
<pre class="brush: js">$.when( wait(dtd))
.done(function(){ alert("哈哈，成功了！"); })
.fail(function(){ alert("出错啦！"); });
dtd.resolve();</pre>
<p>我们也会发现 alert(“哈哈，成功了！”); 被立即执行，虽然 wait(dtd) 执行的时候， dtd 还没有被 resolve，而且 wait 方法返回的是 dtd.promise(), 但是 dtd 这个原始的 deferred 对象是暴露在外面的，我们还是可以从外面改变它的状态。</p>
<p>于是，如果我们真的不想让其他代码能改变 wait 方法内部的 deferred 对象的状态，那我们应该写成这样：</p>
<pre class="brush: js">var wait = function(){
    var dtd = $.Deferred(); // 新建一个deferred对象
    var tasks = function(){
        alert("执行完毕！");
　　     dtd.resolve(); // 改变deferred对象的执行状态
　　 };
　　 setTimeout(tasks,5000);
　　 return dtd.promise();
};
$.when( wait())
.done(function(){ alert("哈哈，成功了！"); })
.fail(function(){ alert("出错啦！"); });</pre>
<p>也就是不要把 deferred 直接暴露出来，最后返回 deferred.promise() ，让其他地方的代码只能添加 handler 。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.allenm.me/2012/01/jquery_deferred_promise_method/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>2011个人总结</title>
		<link>http://blog.allenm.me/2011/12/2011_review/</link>
		<comments>http://blog.allenm.me/2011/12/2011_review/#comments</comments>
		<pubDate>Sat, 31 Dec 2011 16:39:37 +0000</pubDate>
		<dc:creator>allenm</dc:creator>
				<category><![CDATA[未分类]]></category>

		<guid isPermaLink="false">http://blog.allenm.me/?p=690</guid>
		<description><![CDATA[在开始写这篇博客的时候，还有20分钟就要到2012了。我觉得我还是需要来总结一下的，仔细回顾一下这一年我做了什么，什么做好了，什么没做好。 首先，打开了一年前这个时间写下的日志， 先看了下希望能做到的事情。第一条，购入一台Mac，这个完成了，在3月份买入的，这个投资现在看来是值得的。第二条，做了，但是做的不够好，开始有意识的节流，但是积蓄还是很少，这个来年继续做吧。第三条，尝试读了心理学的，还尝试读了小说，第一次读完一个长篇小说《1Q84》。第四条，几乎没做，不过在这个夏天，还是通过游泳、瑜伽、普拉提成功减肥10斤左右。第五条，这一年我总共写了8篇博客，太少了。第六条，我还是单身。 这一年，我做了什么呢？现在想起来，好像还真是充满坎坷呢。是本命年的缘故吗？不，我从来不信这个，连红内裤都没穿。这也许就是成长路上必须经历的吧。先是信心满满的开始做一个大项目，和团队合作的很愉快，但是在项目一期快完成的时候，项目却被停了，所有的努力都白费了，和失去了自己心爱的东西是一样的感觉。不过不管怎么样，也是有收获的，比如在技术上的积累，以及认识了一些朋友。 这个半途而废的项目结束之后，就开始做了很长一段时间小需求，还遇到了几个非常不靠谱的人，然后发了几次脾气，被投诉了几次。那段时间还被老大拉去谈话，说我这个要改。哎，我也不想为了这些事情去和别人吵架，但是每次遇到这些不靠谱的人的时候，我就很难忍住，总觉得和他们合作太浪费我的生命了。 不过还好，这样的日子不算太长，接下来由于架构调整，就去做我的阿里这个产品线了。下半年的大部分日子都在做这个，状态不错，主要是这个产品线的其他同事都比较靠谱，和靠谱的人合作，心情和效率都会很不错。接下来还要继续在这个产品线，我也有一些关于这个产品线的前端方面的规划，手头项目忙完，会好好整理一下。 下半年，还有一个项目对我的锻炼也蛮大，是 web IM 项目，这个项目前期，我就想了很多，然后我想根据需求想了一整套设计方案，来适应当前的应用场景和未来的应用场景，然后去给项目组其他成员讲这些，得到了一致认同。不过悲剧的是，项目中途遇到了一些技术难题（主要不是我负责的这块），然后当时很难搞定，就暂停了，这个我也有一部分这人，在项目前期，没有认真考察这些技术的可靠性，就想当然的开始编码了。还好现在这些已经有了进展，不过是其他同事在跟进，我实在是抽不出时间了。 好了，工作上的事情就到此为止，再回顾下生活上有什么进展吧。 首先，到现在我还是单身，好像也从来没怎么去努力摆脱这个现状，这个要批评自己了，2012要好好努力，哪怕世界毁灭，也希望能有一个心爱的人和我一起欣赏最后的风景。 一个人在外，每次有朋友来杭州都特别高兴，今年在杭州还是见了不少朋友，也是你们，让我在杭州的生活增添了不少色彩。 今年去了上海，去了南京，去找老朋友们玩，每次都玩的很开心，和这些老朋友们相聚，总是会回忆起学校的美好时光。遗憾的是，一直说的要去苏州的，甚至有次酒店都定好了，结果由于一些原因没有去，就再也没去过了，现在苗苗都走了，更不会去了。 另外今年还和同事们一起去了徽杭古道，一起去了舟山溗泗，一起去了西塘，每次都玩的很开心，感谢有这么一群可爱的同事们。去徽杭古道让我体验了一下睡帐篷的感觉。去溗泗我第一次下海水游泳，第一次尝到了海水的味道。西塘是我去的第一个江南古镇，虽然我觉得最好玩的是晚上大家在酒店玩狼人。 2012, 我要见更多的老朋友，去更多的地方看看，也要带爸妈来杭州看看。 2012，我要继续减肥，为了自己的健康，希望不再有脂肪肝。 2012，我要阅读更多种类的书籍，来完善自己。 2012，我要学会更合理的消费，开源节流。 2012，我要继续写博客，继续分享我认为值得分享的东西。 2012，我要在技术上精益求精，大胆尝试新技术，让新技术能和产品完美结合起来。 2012，我要学会控制自己的情绪，但是对待事情要同样的认真。 2012，我不要再一直一个人过。]]></description>
			<content:encoded><![CDATA[<p>在开始写这篇博客的时候，还有20分钟就要到2012了。我觉得我还是需要来总结一下的，仔细回顾一下这一年我做了什么，什么做好了，什么没做好。</p>
<p>首先，打开了一年前这个时间写下的<a title="Hello,2011" href="http://blog.allenm.me/2011/01/hello-2011/" target="_blank">日志</a>， 先看了下希望能做到的事情。第一条，购入一台Mac，这个完成了，在3月份买入的，这个投资现在看来是值得的。第二条，做了，但是做的不够好，开始有意识的节流，但是积蓄还是很少，这个来年继续做吧。第三条，尝试读了心理学的，还尝试读了小说，第一次读完一个长篇小说《1Q84》。第四条，几乎没做，不过在这个夏天，还是通过游泳、瑜伽、普拉提成功减肥10斤左右。第五条，这一年我总共写了8篇博客，太少了。第六条，我还是单身。</p>
<p>这一年，我做了什么呢？现在想起来，好像还真是充满坎坷呢。是本命年的缘故吗？不，我从来不信这个，连红内裤都没穿。这也许就是成长路上必须经历的吧。先是信心满满的开始做一个大项目，和团队合作的很愉快，但是在项目一期快完成的时候，项目却被停了，所有的努力都白费了，和失去了自己心爱的东西是一样的感觉。不过不管怎么样，也是有收获的，比如在技术上的积累，以及认识了一些朋友。</p>
<p>这个半途而废的项目结束之后，就开始做了很长一段时间小需求，还遇到了几个非常不靠谱的人，然后发了几次脾气，被投诉了几次。那段时间还被老大拉去谈话，说我这个要改。哎，我也不想为了这些事情去和别人吵架，但是每次遇到这些不靠谱的人的时候，我就很难忍住，总觉得和他们合作太浪费我的生命了。</p>
<p>不过还好，这样的日子不算太长，接下来由于架构调整，就去做我的阿里这个产品线了。下半年的大部分日子都在做这个，状态不错，主要是这个产品线的其他同事都比较靠谱，和靠谱的人合作，心情和效率都会很不错。接下来还要继续在这个产品线，我也有一些关于这个产品线的前端方面的规划，手头项目忙完，会好好整理一下。</p>
<p>下半年，还有一个项目对我的锻炼也蛮大，是 web IM 项目，这个项目前期，我就想了很多，然后我想根据需求想了一整套设计方案，来适应当前的应用场景和未来的应用场景，然后去给项目组其他成员讲这些，得到了一致认同。不过悲剧的是，项目中途遇到了一些技术难题（主要不是我负责的这块），然后当时很难搞定，就暂停了，这个我也有一部分这人，在项目前期，没有认真考察这些技术的可靠性，就想当然的开始编码了。还好现在这些已经有了进展，不过是其他同事在跟进，我实在是抽不出时间了。</p>
<p>好了，工作上的事情就到此为止，再回顾下生活上有什么进展吧。</p>
<p>首先，到现在我还是单身，好像也从来没怎么去努力摆脱这个现状，这个要批评自己了，2012要好好努力，哪怕世界毁灭，也希望能有一个心爱的人和我一起欣赏最后的风景。</p>
<p>一个人在外，每次有朋友来杭州都特别高兴，今年在杭州还是见了不少朋友，也是你们，让我在杭州的生活增添了不少色彩。</p>
<p>今年去了上海，去了南京，去找老朋友们玩，每次都玩的很开心，和这些老朋友们相聚，总是会回忆起学校的美好时光。遗憾的是，一直说的要去苏州的，甚至有次酒店都定好了，结果由于一些原因没有去，就再也没去过了，现在苗苗都走了，更不会去了。</p>
<p>另外今年还和同事们一起去了徽杭古道，一起去了舟山溗泗，一起去了西塘，每次都玩的很开心，感谢有这么一群可爱的同事们。去徽杭古道让我体验了一下睡帐篷的感觉。去溗泗我第一次下海水游泳，第一次尝到了海水的味道。西塘是我去的第一个江南古镇，虽然我觉得最好玩的是晚上大家在酒店玩狼人。</p>
<p>2012, 我要见更多的老朋友，去更多的地方看看，也要带爸妈来杭州看看。</p>
<p>2012，我要继续减肥，为了自己的健康，希望不再有脂肪肝。</p>
<p>2012，我要阅读更多种类的书籍，来完善自己。</p>
<p>2012，我要学会更合理的消费，开源节流。</p>
<p>2012，我要继续写博客，继续分享我认为值得分享的东西。</p>
<p>2012，我要在技术上精益求精，大胆尝试新技术，让新技术能和产品完美结合起来。</p>
<p>2012，我要学会控制自己的情绪，但是对待事情要同样的认真。</p>
<p>2012，我不要再一直一个人过。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.allenm.me/2011/12/2011_review/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Mac 在无法启动的情况下备份数据</title>
		<link>http://blog.allenm.me/2011/11/backup-data-from-disk-error-mac/</link>
		<comments>http://blog.allenm.me/2011/11/backup-data-from-disk-error-mac/#comments</comments>
		<pubDate>Sat, 26 Nov 2011 14:40:29 +0000</pubDate>
		<dc:creator>allenm</dc:creator>
				<category><![CDATA[未分类]]></category>

		<guid isPermaLink="false">http://blog.allenm.me/?p=684</guid>
		<description><![CDATA[上周，我的 MBP 悲剧的突然出现了无法启动的情况，启动的时候，出现一个进度条，然后这个进度条走不完，就会被关机。阅读说明书上的方法，先进从 recovery 盘启动，用磁盘工具检查硬盘，可以发现磁盘错误，但是尝试紧急恢复总是失败，然后又尝试用系统盘进入磁盘工具检查硬盘，结果一样，可以看到错误，但是无法修复。这个时候，我决定格式化硬盘重装系统了，但是数据还没备份出来呢，这个时候也没办法进入系统，没办法挂载这块有问题的硬盘。后来经过其他人的提示，想到了 single-user mode ，试了下，还真成功备份出数据来了。不过有一些技巧，下面记录下在 single-user mode 环境下，如果挂载移动硬盘用来转移数据。 1，连接好移动硬盘，然后启动 Mac 到 single-user mode （启动的时候按住 command + s ），记住，一定要在启动前连接好移动硬盘，中途插上，我试了好几次都没成功。 2，按照提示，输入 /sbin/mount -uw / 和 /sbin/fsck -fy 两个命令用来用读写模式挂载硬盘和检查磁盘。这个时候，如果你的情况和我一样，这个时候 /sbin/fsck -fy 应该会报出错误，但是没关系，接着往下操作。 3，执行 ls /Volumes 这个命令将显示所有被挂载的磁盘，你的移动硬盘或者U盘很可能还没在这里显示，那就说明还没有被挂载。没关系，如果没被挂载，我们先在这里创建一个挂载点。例如： mkdir /Volumes/usb 4，我们需要确定挂载的移动存储设备的磁盘编号： ls &#8230; <a href="http://blog.allenm.me/2011/11/backup-data-from-disk-error-mac/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>上周，我的 MBP 悲剧的突然出现了无法启动的情况，启动的时候，出现一个进度条，然后这个进度条走不完，就会被关机。阅读说明书上的方法，先进从 recovery 盘启动，用磁盘工具检查硬盘，可以发现磁盘错误，但是尝试紧急恢复总是失败，然后又尝试用系统盘进入磁盘工具检查硬盘，结果一样，可以看到错误，但是无法修复。这个时候，我决定格式化硬盘重装系统了，但是数据还没备份出来呢，这个时候也没办法进入系统，没办法挂载这块有问题的硬盘。后来经过其他人的提示，想到了 single-user mode ，试了下，还真成功备份出数据来了。不过有一些技巧，下面记录下在 single-user mode 环境下，如果挂载移动硬盘用来转移数据。</p>
<p>1，连接好移动硬盘，然后启动 Mac 到 single-user mode （启动的时候按住 command + s ），记住，一定要在启动前连接好移动硬盘，中途插上，我试了好几次都没成功。</p>
<p>2，按照提示，输入<br />
<code>/sbin/mount -uw /</code><br />
和<br />
<code>/sbin/fsck -fy </code><br />
两个命令用来用读写模式挂载硬盘和检查磁盘。这个时候，如果你的情况和我一样，这个时候 /sbin/fsck -fy 应该会报出错误，但是没关系，接着往下操作。</p>
<p>3，执行<br />
<code>ls /Volumes</code><br />
这个命令将显示所有被挂载的磁盘，你的移动硬盘或者U盘很可能还没在这里显示，那就说明还没有被挂载。没关系，如果没被挂载，我们先在这里创建一个挂载点。例如：<br />
<code>mkdir /Volumes/usb</code></p>
<p>4，我们需要确定挂载的移动存储设备的磁盘编号：<br />
<code>ls /dev/disk*</code><br />
一般情况下，移动存储设备的编号在最后面，例如 /dev/disk1s1 </p>
<p>5，现在，挂载移动存储设备到刚才创建的挂载点，执行如下命令：<br />
<code>/sbin/mount_msdos /dev/disk1s1 /Volumes/usb</code><br />
由于我的硬盘格式是 FAT，如果你使用的硬盘或者U盘格式不是这个，可以在 /sbin/ 这个目录里找到对应的 mount 工具，执行命令。</p>
<p>6，如果挂载成功，你现在可以通过运行：<br />
<code>ls /Volumes/usb</code><br />
查看移动存储设备内的文件了。</p>
<p>7，可以尝试从机器内的硬盘复制文件到移动存储设备了：<br />
<code>cp /Users/your_user_name/Documents/somefile /Volumes/usb/</code><br />
如果成功，那么就可以把你的重要数据备份出来了。</p>
<p>这个方式是参考自：<a href="http://www.macsage.com/mounting-usb-drive-in-single-user-mode/" title="mounting-usb-drive-in-single-user-mode" target="_blank">http://www.macsage.com/mounting-usb-drive-in-single-user-mode/</a></p>
<p>另外，如果你有办法在 single-user mode 下搞定网络问题，那么也可以通过 SSH，FTP等方法来备份，single-user mode 下面还是有蛮多的 UNIX 标准工具。</p>
<p>如果你的 Mac 硬盘遇到和我一样的问题，希望这个文章能帮到你。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.allenm.me/2011/11/backup-data-from-disk-error-mac/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>WebSocket Protocol 介绍与实现</title>
		<link>http://blog.allenm.me/2011/10/websocket-protocol-overview-and-implement/</link>
		<comments>http://blog.allenm.me/2011/10/websocket-protocol-overview-and-implement/#comments</comments>
		<pubDate>Fri, 28 Oct 2011 15:37:49 +0000</pubDate>
		<dc:creator>allenm</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[WEB]]></category>
		<category><![CDATA[websocket]]></category>

		<guid isPermaLink="false">http://blog.allenm.me/?p=673</guid>
		<description><![CDATA[今天在方凳会上分享了 websocket protocol以及简单实现，PPT 和代码都放出来，有兴趣的可以围观 Websocket protocol overview View more presentations from allenmeng 然后用 python 简单的实现了 websocket server，代码如下。在网上找的很多代码，都不再兼容 websocket draft 10, 因为 websocket 的草案进化太快，下面的代码是按照 draft10 写的。 chrome 14+ , firefox 7/8 都没有问题。 关于 websocket 草案，请阅读 http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10 &#160; 另外推荐一个 Python 的 websocket &#8230; <a href="http://blog.allenm.me/2011/10/websocket-protocol-overview-and-implement/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>今天在方凳会上分享了 websocket protocol以及简单实现，PPT 和代码都放出来，有兴趣的可以围观</p>
<div id="__ss_9925432" style="width: 425px;">
<p><strong style="display: block; margin: 12px 0 4px;"><a title="Websocket protocol overview" href="http://www.slideshare.net/allenmeng/websocket-9925432" target="_blank">Websocket protocol overview</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/9925432" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" width="425" height="355"></iframe></p>
<div style="padding: 5px 0 12px;">View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/allenmeng" target="_blank">allenmeng</a></div>
</div>
<p>然后用 python 简单的实现了 websocket server，代码如下。在网上找的很多代码，都不再兼容 websocket draft 10, 因为 websocket 的草案进化太快，下面的代码是按照 draft10 写的。 chrome 14+ , firefox 7/8 都没有问题。</p>
<p>关于 websocket 草案，请阅读 <a href="http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10" target="_blank">http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-10</a></p>
<p>&nbsp;</p>
<p>另外推荐一个 Python 的 websocket server <a href="http://www.tavendo.de/autobahn/home.html" target="_blank">http://www.tavendo.de/autobahn/home.html</a>, 基于 twisted 的异步模型。</p>
<p><script src="https://gist.github.com/1322534.js"> </script></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.allenm.me/2011/10/websocket-protocol-overview-and-implement/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>修复 MOTO milestone 电源键失灵（教程）</title>
		<link>http://blog.allenm.me/2011/09/fix-milestone-power-button/</link>
		<comments>http://blog.allenm.me/2011/09/fix-milestone-power-button/#comments</comments>
		<pubDate>Sun, 25 Sep 2011 06:29:24 +0000</pubDate>
		<dc:creator>allenm</dc:creator>
				<category><![CDATA[生活]]></category>
		<category><![CDATA[milestone]]></category>
		<category><![CDATA[moto]]></category>
		<category><![CDATA[电源键]]></category>
		<category><![CDATA[维修]]></category>

		<guid isPermaLink="false">http://blog.allenm.me/?p=663</guid>
		<description><![CDATA[教程在后面，请先让我吐会槽　:) 去年９月份买的MOTO Milestone，８月份的时候，突然出现了电源键失灵的情况，按下去没有回馈，机器也没反应，好在Milestone 是有滑盖的，滑开键盘也可以点亮屏幕，完成解锁动作。至于开机，平时很少有这样的需求，万一不小心关机，可以用数据线连接电脑，会激活手机，完成开机。 结果中秋节的时候，去南京找两个朋友完，早上出门后，突然不知道怎么回事关机了，然后由于没有背电脑，就开不了机了，还约了一个高中同学下午见面的，这下才觉得非常不能忍受这个按键坏掉了。想到淘宝上的卖家承诺的一年保修，打算尝试下。 联系了店铺的客服，客服直接让我把手机给他们寄过去维修，态度还蛮好，我就放心的把手机按照规定写好字条给他们寄了过去，大约一周后，收到了寄回来的手机，确实修复了这个按键。但是用了会儿后发现，手机振动失效了，拿下电池观察了下，发现里程碑的振动器是可以从电池仓看到的，发现被一小块海绵堵住了，估计是维修人员技术太次，没注意留在机器里的，我自己用个回形针把它勾出来了，就好了。 修好后第二天，按键又坏掉鸟。。。两天大概按了２０次左右吧，因为已经养成解说推开键盘的习惯了。晚上亲眼看见一个金属碗状的原件从手机里掉出来，当时就先把这个原件保存下来，第二天联系售后，售后说肯定是我排线坏了什么的，我说这个按键明显按下去没有回馈了，和好的时候是不一样的，售后说要想修可以再寄回来，费用还是 AA。随后此售后还说我怀疑他们的修理能力，笑话，这种维修质量，智商没问题的人都会怀疑你们吧。我哪儿再敢寄回去呢，于是决定自己动手，丰衣足食。 首先，在网上搜索了下 milestone 拆机图，找到了这个链接　http://moto.zol.com.cn/167/295_1663342.html 当然，要拆掉机器，你肯定需要工具才行，手机的螺丝钉和常见的不一样，需要专业的工具，所以你还需要这样的工具（我这个是很早前买的，就是为了拆各种电子设备的） 有了此工具，你就可以方便的按照上面帖子，开始拆机了，不要被那个拆机教程吓到了，我们只是拆开外壳就可以完成按键的维修了，不需要大卸八块。 拆掉后盖，就可以拿掉所有实体按键了，其实按键的远离很简单，下面板子上有两个未接触起来的触头，实体按键和这个板子中间隔了一个碗状的金属片，按下按键的时候，这个碗状的金属片会把下面两个触头链接起来。 下面是我的维修的时候的图片。 那个黄色的东西就是我说的碗状的金属片了，最后一张图，是正常的音量键上的。找到原因，就好维修了，立马下楼去超市买了双面胶，回来把那个金属片固定在它应该在的位置上，接上电池，测试OK，然后装上后盖，就可以用了。 需要特别注意的地方：电池仓下面的那个喇叭外面的黄色金属条，很软很软哦，小心点拆，我的就被我撕裂了。。。 如果你的那个金属碗状物都找不到了，试试求助淘宝，看看能不能买到这个玩意儿吧。 下次再也不相信淘宝上的 JS了。爆下这个JS的店铺名：南京大学生手机网，下次再也不在这个店铺买了。 &#160; &#160; &#160; &#160;]]></description>
			<content:encoded><![CDATA[<p>教程在后面，请先让我吐会槽　:)</p>
<p>去年９月份买的MOTO Milestone，８月份的时候，突然出现了电源键失灵的情况，按下去没有回馈，机器也没反应，好在Milestone 是有滑盖的，滑开键盘也可以点亮屏幕，完成解锁动作。至于开机，平时很少有这样的需求，万一不小心关机，可以用数据线连接电脑，会激活手机，完成开机。</p>
<p>结果中秋节的时候，去南京找两个朋友完，早上出门后，突然不知道怎么回事关机了，然后由于没有背电脑，就开不了机了，还约了一个高中同学下午见面的，这下才觉得非常不能忍受这个按键坏掉了。想到淘宝上的卖家承诺的一年保修，打算尝试下。</p>
<p>联系了店铺的客服，客服直接让我把手机给他们寄过去维修，态度还蛮好，我就放心的把手机按照规定写好字条给他们寄了过去，大约一周后，收到了寄回来的手机，确实修复了这个按键。但是用了会儿后发现，手机振动失效了，拿下电池观察了下，发现里程碑的振动器是可以从电池仓看到的，发现被一小块海绵堵住了，估计是维修人员技术太次，没注意留在机器里的，我自己用个回形针把它勾出来了，就好了。</p>
<p>修好后第二天，按键又坏掉鸟。。。两天大概按了２０次左右吧，因为已经养成解说推开键盘的习惯了。晚上亲眼看见一个金属碗状的原件从手机里掉出来，当时就先把这个原件保存下来，第二天联系售后，售后说肯定是我排线坏了什么的，我说这个按键明显按下去没有回馈了，和好的时候是不一样的，售后说要想修可以再寄回来，费用还是 AA。随后此售后还说我怀疑他们的修理能力，笑话，这种维修质量，智商没问题的人都会怀疑你们吧。我哪儿再敢寄回去呢，于是决定自己动手，丰衣足食。</p>
<p>首先，在网上搜索了下 milestone 拆机图，找到了这个链接　<a href="http://moto.zol.com.cn/167/295_1663342.html" target="_blank">http://moto.zol.com.cn/167/295_1663342.html</a></p>
<p>当然，要拆掉机器，你肯定需要工具才行，手机的螺丝钉和常见的不一样，需要专业的工具，所以你还需要这样的工具（我这个是很早前买的，就是为了拆各种电子设备的）<a href="http://blog.allenm.me/wp-content/uploads/2011/09/IMG_20110925_140448.jpg"><img class="alignnone size-large wp-image-664" title="IMG_20110925_140448" src="http://blog.allenm.me/wp-content/uploads/2011/09/IMG_20110925_140448-1024x764.jpg" alt="" width="640" height="477" /></a></p>
<p>有了此工具，你就可以方便的按照上面帖子，开始拆机了，不要被那个拆机教程吓到了，我们只是拆开外壳就可以完成按键的维修了，不需要大卸八块。</p>
<p>拆掉后盖，就可以拿掉所有实体按键了，其实按键的远离很简单，下面板子上有两个未接触起来的触头，实体按键和这个板子中间隔了一个碗状的金属片，按下按键的时候，这个碗状的金属片会把下面两个触头链接起来。</p>
<p>下面是我的维修的时候的图片。</p>
<p><a href="http://blog.allenm.me/wp-content/uploads/2011/09/P1040987.jpg"><img class="alignnone size-large wp-image-665" title="P1040987" src="http://blog.allenm.me/wp-content/uploads/2011/09/P1040987-1024x768.jpg" alt="" width="640" height="480" /></a><a href="http://blog.allenm.me/wp-content/uploads/2011/09/P1040986.png"><img class="alignnone size-full wp-image-667" title="P1040986" src="http://blog.allenm.me/wp-content/uploads/2011/09/P1040986.png" alt="" width="1000" height="750" /></a></p>
<p><a href="http://blog.allenm.me/wp-content/uploads/2011/09/P1040988.png"><img class="alignnone size-full wp-image-668" title="P1040988" src="http://blog.allenm.me/wp-content/uploads/2011/09/P1040988.png" alt="" width="1000" height="750" /></a><a href="http://blog.allenm.me/wp-content/uploads/2011/09/P1040989.jpg"><img class="alignnone size-large wp-image-666" title="P1040989" src="http://blog.allenm.me/wp-content/uploads/2011/09/P1040989-1024x768.jpg" alt="" width="640" height="480" /></a></p>
<p>那个黄色的东西就是我说的碗状的金属片了，最后一张图，是正常的音量键上的。找到原因，就好维修了，立马下楼去超市买了双面胶，回来把那个金属片固定在它应该在的位置上，接上电池，测试OK，然后装上后盖，就可以用了。</p>
<p>需要特别注意的地方：电池仓下面的那个喇叭外面的黄色金属条，很软很软哦，小心点拆，我的就被我撕裂了。。。</p>
<p>如果你的那个金属碗状物都找不到了，试试求助淘宝，看看能不能买到这个玩意儿吧。</p>
<p>下次再也不相信淘宝上的 JS了。爆下这个JS的店铺名：南京大学生手机网，下次再也不在这个店铺买了。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.allenm.me/2011/09/fix-milestone-power-button/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>localStorage in HTML5(2)</title>
		<link>http://blog.allenm.me/2011/04/localstorage-in-html5-2/</link>
		<comments>http://blog.allenm.me/2011/04/localstorage-in-html5-2/#comments</comments>
		<pubDate>Mon, 04 Apr 2011 10:12:15 +0000</pubDate>
		<dc:creator>allenm</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[未分类]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[localstorage]]></category>

		<guid isPermaLink="false">http://blog.allenm.me/?p=647</guid>
		<description><![CDATA[上一篇博客简单的介绍了下 localStorage，并且对各个浏览器的存储空间大小做了简单的测试。在上篇博客到这篇博客期间，世界也发生了很多变化，IE9 和 firefox4 正式版都发布了。于是我也对这两个新的浏览器进行了测试，关于 localStorage 的， IE9 和 IE8 表现一致，FF4 和 FF3.6 表现一致，和上篇博客中介绍的一样，FF4 在 Mac 下和 WIN 下表现仍然不一致，参考上篇博客。同时，给出我写的测试存储空间大小的页面，你可以自己来试试：http://lab.allenm.me/html5/storage/maxtest.html 除了最基本的和使用 cookie 一样使用 localStorage，我们还能用它来做什么呢？ 如果你看过 localStorage 的文档，你应该注意到了我们在改变 localStorage 中存储的数据的时候，会触发一个 storage 事件： interface StorageEvent : Event { readonly attribute DOMString key; readonly &#8230; <a href="http://blog.allenm.me/2011/04/localstorage-in-html5-2/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>上一篇博客简单的介绍了下 localStorage，并且对各个浏览器的存储空间大小做了简单的测试。在上篇博客到这篇博客期间，世界也发生了很多变化，IE9 和 firefox4 正式版都发布了。于是我也对这两个新的浏览器进行了测试，关于 localStorage 的， IE9 和 IE8 表现一致，FF4 和 FF3.6 表现一致，和上篇博客中介绍的一样，FF4 在 Mac 下和 WIN 下表现仍然不一致，参考上篇博客。同时，给出我写的测试存储空间大小的页面，你可以自己来试试：<a href="http://lab.allenm.me/html5/storage/maxtest.html" target="_blank">http://lab.allenm.me/html5/storage/maxtest.html</a></p>
<p>除了最基本的和使用 cookie 一样使用 localStorage，我们还能用它来做什么呢？</p>
<p>如果你看过 localStorage 的文档，你应该注意到了我们在改变 localStorage 中存储的数据的时候，会触发一个 storage 事件：</p>
<pre>interface <dfn id="storageevent">StorageEvent</dfn> : Event {
  readonly attribute DOMString <a title="dom-StorageEvent-key" href="http://dev.w3.org/html5/webstorage/#dom-storageevent-key">key</a>;
  readonly attribute any <a title="dom-StorageEvent-oldValue" href="http://dev.w3.org/html5/webstorage/#dom-storageevent-oldvalue">oldValue</a>;
  readonly attribute any <a title="dom-StorageEvent-newValue" href="http://dev.w3.org/html5/webstorage/#dom-storageevent-newvalue">newValue</a>;
  readonly attribute DOMString <a title="dom-StorageEvent-url" href="http://dev.w3.org/html5/webstorage/#dom-storageevent-url">url</a>;
  readonly attribute <a href="http://dev.w3.org/html5/webstorage/#storage-0">Storage</a> <a title="dom-StorageEvent-storageArea" href="http://dev.w3.org/html5/webstorage/#dom-storageevent-storagearea">storageArea</a>;
  void <a title="dom-StorageEvent-initStorageEvent" href="http://dev.w3.org/html5/webstorage/#dom-storageevent-initstorageevent">initStorageEvent</a>(in DOMString typeArg, in boolean canBubbleArg, in boolean cancelableArg, in DOMString keyArg, in any oldValueArg, in any newValueArg, in DOMString urlArg, in <a href="http://dev.w3.org/html5/webstorage/#storage-0">Storage</a> storageAreaArg);
};</pre>
<p>&nbsp;</p>
<p>既然我们可以知道此“源”下的localStorage 中的某个字段的值发生了变化，那我们就可以在前端做到跨页面通信，这个是有意义的。 你想想看，在我们目前的WEB应用中，经常会发生这样的事情：在淘宝或者其他电商网站购物，点击购买某个物品，会在页面上购物车中显示。然后在新的 tab 页中打开其他物品的页面，也点击购买，新的页面当然会显示你购买的所有物品，但是旧的页面中的购物车却并不会主动更新这个数据。以前的技术并不是不可以实现这个，只是相对来说成本较大，没有必要。利用 localStorage ，我们就可以只使用前端技术来同步这个数据，成本极小。</p>
<p>我写了一个简单的利用 storage 事件来做前端层面的夸页面数据同步，请在支持 localStorage 的浏览器中打开两个此页面：<a href="http://lab.allenm.me/html5/storage/" target="_blank">http://lab.allenm.me/html5/storage/</a> ，然后在任意一个中输入任意字符，再看看另外一个页面中有什么变化。</p>
<p>我们知道 localStorage 中，我们只可以保存字符串。但是有些时候，我们需要保存一些结构比较复杂的数据，字符串不适合做这种工作，自己再制定一种特殊的规则来利用字符串保存这些数据，也是不明智的选择。因为我们已经有了 <a href="http://json.org/js.html" target="_blank">JSON</a> 这个事实上的标准了啊。要让 localStorage 支持 JSON 的存储也比较容易，我们只需要自己再封装一层就OK了。现代浏览器已经原生支持 JSON 的解析，JSON.parse() 用来把字符串解析成 JSON 对象，JSON.stringify() 用来把 JSON 对象编码成字符串格式。有了这两个方法，我们只需要在存储的时候，编码，获取数据的时候，解码就可以实现用 JSON 来存储数据了。具体封装这里就不给出代码了。</p>
<p>即使有些不够现代的浏览器不支持 JSON.parse() 和 JSON.stringify() 也没关系，因为我们还有开源的 js 实现的 JSON 的解析器和编码器：<a href="https://github.com/douglascrockford/JSON-js" target="_blank">老道的 JSON-js</a>。</p>
<p>localStorage 还有一个孪生兄弟，叫 sessionStorage，他们的用法基本一致，同属于 WEB Storage, 只是保存的数据的生命周期有区别，详情请<a href="http://dev.w3.org/html5/webstorage/#the-sessionstorage-attribute" target="_blank">阅读这里</a>。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.allenm.me/2011/04/localstorage-in-html5-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>localStorage in HTML5（1）</title>
		<link>http://blog.allenm.me/2011/03/localstorage-in-html5-1/</link>
		<comments>http://blog.allenm.me/2011/03/localstorage-in-html5-1/#comments</comments>
		<pubDate>Sun, 13 Mar 2011 15:35:21 +0000</pubDate>
		<dc:creator>allenm</dc:creator>
				<category><![CDATA[javascript]]></category>
		<category><![CDATA[WEB]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[localstorage]]></category>

		<guid isPermaLink="false">http://blog.allenm.me/?p=644</guid>
		<description><![CDATA[HTML5 中的 localStorage 我相信 web developer 们，都听说过了吧。目前 chrome,firefox,opera,safari, IE8 都支持此属性，注意 IE8 也支持，那就是说，如果你的网站用户不是太低端，起码有一半以上的用户的浏览器是支持 localStorage 特性的。各个浏览器分配给每个“源(region)”的 localStorage 空间至少为 5M（具体数值请看稍后讨论），对于想开始使用 HTML5 的人们来说，这个是个不错的开始。 localStorage 使用方式也非常简单，有 setItem, getItem, removeItem,key, clear 5个方法，和 length 一个属性。定义如下： interface Storage { readonly attribute unsigned long length; DOMString key(in unsigned long &#8230; <a href="http://blog.allenm.me/2011/03/localstorage-in-html5-1/">继续阅读 <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>HTML5 中的 localStorage 我相信 web developer 们，都听说过了吧。目前 chrome,firefox,opera,safari, IE8 都支持此属性，注意 IE8 也支持，那就是说，如果你的网站用户不是太低端，起码有一半以上的用户的浏览器是支持 localStorage 特性的。各个浏览器分配给每个“源(region)”的 localStorage 空间至少为 5M（具体数值请看稍后讨论），对于想开始使用 HTML5 的人们来说，这个是个不错的开始。</p>
<p>localStorage 使用方式也非常简单，有 setItem, getItem, removeItem,key, clear 5个方法，和 length 一个属性。定义如下：</p>
<pre>interface <dfn id="storage-0">Storage</dfn> {
  readonly attribute unsigned long <a title="dom-Storage-length" href="http://dev.w3.org/html5/webstorage/#dom-storage-length">length</a>;
  DOMString <a title="dom-Storage-key" href="http://dev.w3.org/html5/webstorage/#dom-storage-key">key</a>(in unsigned long index);
  getter any <a title="dom-Storage-getItem" href="http://dev.w3.org/html5/webstorage/#dom-storage-getitem">getItem</a>(in DOMString key);
  setter creator void <a title="dom-Storage-setItem" href="http://dev.w3.org/html5/webstorage/#dom-storage-setitem">setItem</a>(in DOMString key, in any value);
  deleter void <a title="dom-Storage-removeItem" href="http://dev.w3.org/html5/webstorage/#dom-storage-removeitem">removeItem</a>(in DOMString key);
  void <a title="dom-Storage-clear" href="http://dev.w3.org/html5/webstorage/#dom-storage-clear">clear</a>();
};</pre>
<p>localStorage 中都是以 key/value 的形式来存储数据的，存储的数据类型都是字符串，如果需要其他类型，需要自行转换。我们可以使用 setItem 方法来存储数据，例如 localStorage.setItem(&#8216;foo&#8217;,'test data&#8217;); 这样来存储一个 key 为 foo 的数据，然后可以使用 getItem 来读取 value 值，即 localStorage.getItem(&#8216;foo&#8217;); 如果 setItem 的时候，key 已经存在，则修改保存的数据为最新的数据，如果不存在，则新建 key。执行 removeItem() 可以删除已经存储的数据，比如localStorage.removeItem(&#8216;foo&#8217;) 可以删除 key 为 foo 的数据。执行 clear() 会清除此“源”下的所有数据。key() 方法可以获取第 n 个数据的 key 值，例如 localStorage.key(0) 可以获取到第 0 个 key/value 对 的 key 值。这个配合 length 属性可以遍历出所有存储的值。length 属性返回已经存储的数据的条数。</p>
<p>上面简单的介绍了下 localStorage 的用法，然后我们来讨论各个浏览器分配了多少空间给 localStorage。</p>
<p>在各个浏览器中，只有 opera 可以清楚的看到用了多少空间，当这个容量到达 5M 的时候，浏览器就会提示用户是否增加容量，如果用户点击了拒绝，那此后就不会再提示，如果不删除这些数据，将不能再存储，抛出错误。如果用户点击了允许，那将获得以前两倍的空间，等到达了新的上限后，又会弹出提示，以 5M -&gt; 10M -&gt; 20M -&gt; 40M 这样递增。</p>
<p>另外 IE8 的 localStorage 对象，有个 remainingSpace 的属性，可以查看剩余的可用空间，在 IE 中执行 alert(localStorage.remainingSpace) 可以看到 IE8 有5M 的最大存储空间。如果达到最大值，会抛出错误，不清除数据前将不能继续存储。</p>
<p>其他浏览器我还没找到办法查看最大容量，但是我用同样的脚本在不同的浏览器里跑，等到达最大值后，查看存储的键值对的数量，结果如下：opera 可以存储 1482 条记录，chrome 和 safari 可以存储1986条，MAC下的 firefox 3.6  可以存储3970条，IE8 下可以存储 3786条。WIN 下的 firefox 3.6 一直没得到结果，一直没有抛出错误，好像是无限的一样。（以上浏览器都是使用的截止到今天的最新的正式版）。 win 下的 firefox 3.6 的问题还有待验证，我使用的环境是虚拟机下的 windows7 系统。</p>
<p>从 IE8 的 remainingSpace 属性可以看出默认最大容量也是 5M ，和 opear 相同，但是存储的条目数量却相差很大，猜测可能是使用了压缩算法，因为存储的都是字符串，压缩率还是非常可观的。chrome 和 safari 具体的最大容量，从这里也没办法推断出来，不过既然 opera 存储的条目数最少，那我们就认为至少可以存储 5M 的数据吧。</p>
<p>有了 5M 这个数量，我们就可以判断哪些数据适合用这个来存储，哪些不适合。毕竟现在如果存储满了后，还没有什么好办法来清除一些不再使用的数据，因为我们从代码里不容易判断哪些是用户很少用到的。最好使用这个 feature 来实现一些用户体验加强的东西，而不是来实现关键性的东西。</p>
<p>另外在 IE8 以下的版本，我们可以使用其他技术来代替，比如 IE 特有的 userData，或者 flash store 。可以考虑封装一下，暴露出统一的接口给用户（ developer）使用。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.allenm.me/2011/03/localstorage-in-html5-1/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>2011春运，该怎么买火车票？</title>
		<link>http://blog.allenm.me/2011/01/way-to-home-at-spring-festival/</link>
		<comments>http://blog.allenm.me/2011/01/way-to-home-at-spring-festival/#comments</comments>
		<pubDate>Sat, 22 Jan 2011 17:06:04 +0000</pubDate>
		<dc:creator>allenm</dc:creator>
				<category><![CDATA[生活]]></category>

		<guid isPermaLink="false">http://blog.allenm.me/?p=639</guid>
		<description><![CDATA[又到了年关了，在外辛辛苦苦一年的游子们终于可以回家看看爹娘，看看家乡。可是春运啊，一票难求，那个什么部说的什么时候解决一票难求的新闻，实在是没法让心信，早就不相信此类新闻了。 可是家要回，票要买。那要怎么买呢？我在买火车票前一个星期的时候，写了一个自动抓取 58 同城和百姓网上的转让信息的脚本，然后放在 VPS 上。用 cron 定时每10分钟执行一次，在买票的那两天，我甚至提高到3分钟一次。具体脚本怎么写，我就不说了，没什么技术含量。抓回 HTML 用正则匹配有用的信息，和上次抓回来的比较，有更新，就发个 email 通知就可以了。可是效果怎么样呢？信息获取的到是蛮及时，可是，打过去绝大部分都是黄牛，而且都是低等黄牛，开口就加300 ，票面钱才 300 呢。一到这个时候，58 同城，赶集网，百姓网上的这些转让信息基本全部是黄牛，所以我没有靠这个买到票。不排除有真正是行程原因走不了的，但是一个个的试，太累了。 那怎么办？尝试电话订票吧，现在基本全国各地都开通了电话订票，电话订票也是有技巧的，要在发售时间前10分钟左右打进去才有可能定到票，比如杭州12点发售，那就11.50的时候就打进去，打不进就一直重拨，加上海的区号重播，打进去后，先不要选择，随便按按无关紧要的听听，看准时间，到了12点，马上开始操作订票，我看到有几个老乡这样订到了票。如果你回家的线路不是太紧张，就更容易了，同事有下午4点半打进去定到了卧铺的。我因为各种原因错过了订票的最佳时机，基本20分钟后就订不到武汉方向的了，没有通过此方式定到票。 其实最容易买到票的方法，是找黄牛。。没办法，虽然大家都恨黄牛，但是这个时候，还是黄牛管用啊，要找靠谱的黄牛，每个公司都会流传一些口碑很好的黄牛吧，就找他们就对了，加的钱也不多，票也靠谱，这次我的大多数同事都是这样定到的。 对于上班族来说，去排队买票是最不划算的事情了，大半夜就要去排队，还不知道要排多少个小时，耗时耗体力，不划算，可能还要请假，有请假损失的钱还不如花钱买黄牛票了。 我这次的票，是一个人买的黄牛票，后来买到了时间更合适的黄牛票，然后转手的。 综上所述，买火车票，要多方面行动，电话订票，黄牛票，转让票都要兼顾，有票了不妨先拿下，有更好的可以转手，这个时间的票很好转。另外要多和老乡们交流，一般大公司会有老乡群什么的，大家在一起交流车票信息，有利于找到更靠谱的车票。 什么时候才能解决春运问题，不敢想，还是自己努力挣钱，直接飞机回去吧，不用这么痛苦。 买票搞的身心疲惫，白天的工作时间都用来买票了，现在要开始加班把这些补回来，要不然项目完不成了。真杯具。]]></description>
			<content:encoded><![CDATA[<p>又到了年关了，在外辛辛苦苦一年的游子们终于可以回家看看爹娘，看看家乡。可是春运啊，一票难求，那个什么部说的什么时候解决一票难求的新闻，实在是没法让心信，早就不相信此类新闻了。</p>
<p>可是家要回，票要买。那要怎么买呢？我在买火车票前一个星期的时候，写了一个自动抓取 58 同城和百姓网上的转让信息的脚本，然后放在 VPS 上。用 cron 定时每10分钟执行一次，在买票的那两天，我甚至提高到3分钟一次。具体脚本怎么写，我就不说了，没什么技术含量。抓回 HTML 用正则匹配有用的信息，和上次抓回来的比较，有更新，就发个 email 通知就可以了。可是效果怎么样呢？信息获取的到是蛮及时，可是，打过去绝大部分都是黄牛，而且都是低等黄牛，开口就加300 ，票面钱才 300 呢。一到这个时候，58 同城，赶集网，百姓网上的这些转让信息基本全部是黄牛，所以我没有靠这个买到票。不排除有真正是行程原因走不了的，但是一个个的试，太累了。</p>
<p>那怎么办？尝试电话订票吧，现在基本全国各地都开通了电话订票，电话订票也是有技巧的，要在发售时间前10分钟左右打进去才有可能定到票，比如杭州12点发售，那就11.50的时候就打进去，打不进就一直重拨，加上海的区号重播，打进去后，先不要选择，随便按按无关紧要的听听，看准时间，到了12点，马上开始操作订票，我看到有几个老乡这样订到了票。如果你回家的线路不是太紧张，就更容易了，同事有下午4点半打进去定到了卧铺的。我因为各种原因错过了订票的最佳时机，基本20分钟后就订不到武汉方向的了，没有通过此方式定到票。</p>
<p>其实最容易买到票的方法，是找黄牛。。没办法，虽然大家都恨黄牛，但是这个时候，还是黄牛管用啊，要找靠谱的黄牛，每个公司都会流传一些口碑很好的黄牛吧，就找他们就对了，加的钱也不多，票也靠谱，这次我的大多数同事都是这样定到的。</p>
<p>对于上班族来说，去排队买票是最不划算的事情了，大半夜就要去排队，还不知道要排多少个小时，耗时耗体力，不划算，可能还要请假，有请假损失的钱还不如花钱买黄牛票了。</p>
<p>我这次的票，是一个人买的黄牛票，后来买到了时间更合适的黄牛票，然后转手的。</p>
<p>综上所述，买火车票，要多方面行动，电话订票，黄牛票，转让票都要兼顾，有票了不妨先拿下，有更好的可以转手，这个时间的票很好转。另外要多和老乡们交流，一般大公司会有老乡群什么的，大家在一起交流车票信息，有利于找到更靠谱的车票。</p>
<p>什么时候才能解决春运问题，不敢想，还是自己努力挣钱，直接飞机回去吧，不用这么痛苦。</p>
<p>买票搞的身心疲惫，白天的工作时间都用来买票了，现在要开始加班把这些补回来，要不然项目完不成了。真杯具。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.allenm.me/2011/01/way-to-home-at-spring-festival/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

