<?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/"
	xmlns:series="http://unfoldingneurons.com/"
	>

<channel>
	<title>我是妖怪</title>
	<atom:link href="http://www.dualface.com/index.php/feed" rel="self" type="application/rss+xml" />
	<link>http://www.dualface.com</link>
	<description>Fire and Motion</description>
	<lastBuildDate>Sat, 04 Sep 2010 03:33:17 +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>从程序设计上减少不必要的并发更新冲突</title>
		<link>http://www.dualface.com/index.php/archives/1042</link>
		<comments>http://www.dualface.com/index.php/archives/1042#comments</comments>
		<pubDate>Sat, 04 Sep 2010 03:10:57 +0000</pubDate>
		<dc:creator>dualface</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[ActiveRecord]]></category>
		<category><![CDATA[DataMapper]]></category>
		<category><![CDATA[ORM]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.dualface.com/?p=1042</guid>
		<description><![CDATA[有多个请求更新同一条数据库记录时，就可能出现冲突。
比如在农场游戏中，有一块地现在种植了20朵玫瑰。同一时间玩家A采集了2朵，玩家B采集3朵，玩家C采集了4朵。此时三个请求一起到达，对数据库的更新就很可能出现问题。

我们使用如下的代码：

// player_id: 玩家ID
// field_inx: 某一块地的索引
// pick: 要采集的量
$field = Field::find_one(array(&#039;player_id&#039; =&#62; $player_id, &#039;field_inx&#039; =&#62; $field_inx));
if ($field-&#62;quantity &#60; $pick)
{
    .... 土地的作物剩余数量不足
    return ...;
}

$field-&#62;quantity -= $pick;
$field-&#62;save();

假设玩家A采集2朵时，$field 读取出来的 quantity 值是 20，则 save() 后，quantity 的新值是 18。如果在处理玩家A的请求时，程序执行到 save() 之前，服务器就开始处理玩家B采集3朵的请求，则玩家B读取到的 quantity 值将是玩家A更新前的值。两个请求谁最后调用save()，数据库中就是哪个请求写入的值。最终结果是两个玩家分别采集了 2 朵和 3 朵，但剩余数量却不是 15 朵。
要避免此问题，一种常见的解决办法就是使用数据库事务。
当开启事务后，代码如下：

// $adapter 是数据库访问对象
$adapter-&#62;begin(); // 开启事务

// player_id: 玩家ID
// field_inx: 某一块地的索引
// [...]]]></description>
		<wfw:commentRss>http://www.dualface.com/index.php/archives/1042/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>从单元测试生成 API 文档</title>
		<link>http://www.dualface.com/index.php/archives/448</link>
		<comments>http://www.dualface.com/index.php/archives/448#comments</comments>
		<pubDate>Sat, 28 Aug 2010 06:27:42 +0000</pubDate>
		<dc:creator>dualface</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[TDD]]></category>

		<guid isPermaLink="false">http://www.dualface.com/?p=448</guid>
		<description><![CDATA[写单元测试和写文档一样是枯燥的事情，尤其是 API 文档需要尽可能详细的描述每一个 API 的用途和用法。如果细想一下，就会发现单元测试的代码不就是最好的 API 用法示例吗？
假设有下面的单元测试代码：

class RepositoryTest extends TestCase
{
    /**
     * 根据模型定义的存储域选择存储源
     *
     * @api Repository::set_dispatcher()
     * @api Repository::select_storage()
     */
    function test_select_storage()
    {
   [...]]]></description>
		<wfw:commentRss>http://www.dualface.com/index.php/archives/448/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>在 PHP 中 unset 对象属性</title>
		<link>http://www.dualface.com/index.php/archives/441</link>
		<comments>http://www.dualface.com/index.php/archives/441#comments</comments>
		<pubDate>Wed, 25 Aug 2010 20:47:27 +0000</pubDate>
		<dc:creator>dualface</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.dualface.com/?p=441</guid>
		<description><![CDATA[直接上代码：

&#60;?php

class Test
{
	public $value;

	function __get($prop)
	{
	    echo &#039;    &#039; . __METHOD__ . &#34;: {$prop}\n&#34;;
	}

	function __set($prop, $value)
	{
	    echo &#039;    &#039; . __METHOD__ . &#34;: {$prop} = {$value}\n&#34;;
	}
}

$t = new Test();
$t-&#62;value = 1;
echo &#34;before unset.\n\n&#34;;
$t-&#62;value = 2;
echo &#34;after unset:\n&#34;;

// unset 掉对象的属性后，__set() 和 __get() 方法就生效了
unset($t-&#62;value);
$t-&#62;value = 3;
$x = [...]]]></description>
		<wfw:commentRss>http://www.dualface.com/index.php/archives/441/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>修改OS X Snow Leopard的TIME_WAIT设定</title>
		<link>http://www.dualface.com/index.php/archives/437</link>
		<comments>http://www.dualface.com/index.php/archives/437#comments</comments>
		<pubDate>Tue, 17 Aug 2010 12:40:42 +0000</pubDate>
		<dc:creator>dualface</dc:creator>
				<category><![CDATA[Apple's]]></category>

		<guid isPermaLink="false">http://www.dualface.com/?p=437</guid>
		<description><![CDATA[在本机装了nginx和php5.3，准备测试一下。用ab一跑就会出现下面的错误：

apr_poll: The timeout specified has expired (70007)
Total of 16384 requests completed

此时用netstat -an即可发现大量的TIME_WAIT连接。

造成这种情况的原因有几点：
1、OS X有两个默认设置：

net.inet.ip.portrange.hifirst: 49152
net.inet.ip.portrange.hilast: 65535

因此ab创建请求时可用的端口只能在上述范围。
2、nginx使用了短连接方式，所以会造成大量处于TIME_WAIT状态的连接。这些连接默认需要15秒才会关闭，所以ab在创建到1638x个连接的时候，就再也没有可用的端口了。
要解决上述问题，最简单的方法就是修改TIME_WAIT状态连接的生存期。TIME_WAIT的设定在OS X中是net.inet.tcp.msl，使用下列命令即可查看和修改：

mac$ sysctl net.inet.tcp.msl
net.inet.tcp.msl: 15000

修改则使用：

mac$ sudo sysctl -w net.inet.tcp.msl=1000

修改完成后重新执行ab就能得到期望的结果了：

Server Software:        nginx/0.7.67
Server Hostname:        127.0.0.1
Server Port:            9090

Document Path: [...]]]></description>
		<wfw:commentRss>http://www.dualface.com/index.php/archives/437/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>悲剧的谷歌地图</title>
		<link>http://www.dualface.com/index.php/archives/431</link>
		<comments>http://www.dualface.com/index.php/archives/431#comments</comments>
		<pubDate>Tue, 20 Jul 2010 05:14:40 +0000</pubDate>
		<dc:creator>dualface</dc:creator>
				<category><![CDATA[生活就是折腾]]></category>

		<guid isPermaLink="false">http://www.dualface.com/?p=431</guid>
		<description><![CDATA[很有创意啊，哈哈。



- 围观地址已实效 -
]]></description>
		<wfw:commentRss>http://www.dualface.com/index.php/archives/431/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Apple港行在国内的保修必须拿到过关证明</title>
		<link>http://www.dualface.com/index.php/archives/425</link>
		<comments>http://www.dualface.com/index.php/archives/425#comments</comments>
		<pubDate>Tue, 13 Jul 2010 06:14:24 +0000</pubDate>
		<dc:creator>dualface</dc:creator>
				<category><![CDATA[Apple's]]></category>

		<guid isPermaLink="false">http://www.dualface.com/?p=425</guid>
		<description><![CDATA[淘宝上卖Apple港行产品的卖家，都会说自己的产品是全国联保的。
但我打电话给Apple大陆售后服务中心咨询后，确认香港购买的Apple产品必须提供保修卡（在产品包装盒里）和海关出具的过关证明才能保修。而要拿到海关的过关证明，必然需要缴纳关税，这样一来价格比起国内行货优势就不大了。
为了赚取更多利润，许多商家都会告诉你他们的商品提供香港发票，可以全国联保，而故意忽略掉过关证明的事情。这纯粹是一种欺骗，而且大部分所谓的香港发票其实都是假的。
所以想要省钱，干脆直接买水货，所谓的港行联保大都是骗人的。而要确保售后保障，那就买大陆行货。大陆行货只要有保修卡、三包证明和销售发票即可保修。
当然了，除非是像我这么运气差的，不然Apple产品有质量问题的机率还是很小 -_-#
]]></description>
		<wfw:commentRss>http://www.dualface.com/index.php/archives/425/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>使用Mac OS X的安全睡眠（更智能的睡眠+休眠模式）</title>
		<link>http://www.dualface.com/index.php/archives/423</link>
		<comments>http://www.dualface.com/index.php/archives/423#comments</comments>
		<pubDate>Mon, 12 Jul 2010 20:42:38 +0000</pubDate>
		<dc:creator>dualface</dc:creator>
				<category><![CDATA[Apple's]]></category>

		<guid isPermaLink="false">http://www.dualface.com/?p=423</guid>
		<description><![CDATA[其实，OS X和Windows一样是支持休眠功能的。也就是将计算机当前的工作状态（主要就是内存中的数据）保存到硬盘上的一个特殊文件中，下次开机时直接读取这个文件来还原状态。所以从休眠状态恢复时，可以回到休眠时的工作环境，包括所有已经打开的应用程序和文件。这对于长期工作时需要开n多应用的我来说简直太方便了。但是用了一段时间Mac Mini，发现Mac Mini没有提供休眠功能。google一番，才知道Apple把这个功能给隐藏了。
OS X菜单里面是没有“休眠”的，只有“睡眠”。睡眠与休眠的区别在于睡眠不会将计算机的工作状态存储到硬盘，而是仍然保留在内存中。睡眠后仅仅是关闭计算机中不需要使用的硬件设备，同时将CPU置于睡眠模式，但此时仍然需要消耗电力。一旦睡眠中切断电源就没法恢复工作状态了。不过，睡眠的好处也很明显，就是不需要把内存数据存入硬盘，因此进入睡眠的速度特别快，恢复也特别快。
OS X提供了一种“安全睡眠”功能，将睡眠和休眠功能结合起来。当进入安全睡眠时，OS X首先把工作状态存储到硬盘，然后将计算机转入睡眠状态。如果睡眠中电源没有中断，则恢复时就不需要读取硬盘。如果安全睡眠的过程中电源中断了，下一次开机则会从硬盘恢复工作状态。
要知道OS X是否启用了安全睡眠，在终端窗口输入：

pmset -g &#124; grep hibernate

结果输出：

hibernatemode	3
hibernatefile	/var/vm/sleepimage

如果 hibernatemode 的值为3，就表示已经启用了安全睡眠模式。如果是0，则需要通过下面的命令启用安全睡眠模式：

sudo pmset -a hibernatemode 3

设定好后，重新启动一下系统，下次进入睡眠时就会选择安全睡眠模式了。
]]></description>
		<wfw:commentRss>http://www.dualface.com/index.php/archives/423/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>连续拿了两个iPod，屏幕都有亮点，我擦</title>
		<link>http://www.dualface.com/index.php/archives/418</link>
		<comments>http://www.dualface.com/index.php/archives/418#comments</comments>
		<pubDate>Fri, 09 Jul 2010 14:47:59 +0000</pubDate>
		<dc:creator>dualface</dc:creator>
				<category><![CDATA[生活就是折腾]]></category>

		<guid isPermaLink="false">http://www.dualface.com/?p=418</guid>
		<description><![CDATA[在淘宝上买了个iPod Touch 8G，拿回来一用，发现屏幕有一个亮点 -_-#
寄回去商家给换了一个，再一看，还是有一个亮点，我擦了。。。
]]></description>
		<wfw:commentRss>http://www.dualface.com/index.php/archives/418/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Opera for Mac就是个茶几</title>
		<link>http://www.dualface.com/index.php/archives/416</link>
		<comments>http://www.dualface.com/index.php/archives/416#comments</comments>
		<pubDate>Thu, 01 Jul 2010 19:05:50 +0000</pubDate>
		<dc:creator>dualface</dc:creator>
				<category><![CDATA[Apple's]]></category>

		<guid isPermaLink="false">http://www.dualface.com/?p=416</guid>
		<description><![CDATA[装上了最新的Opera 10.60，打开一个中文网站，瞬间悲剧了。
如此丑陋的字体，即便修改Opera的设定也无法改变。。。Orz
回收站才是Opera for Mac的归宿啊。
]]></description>
		<wfw:commentRss>http://www.dualface.com/index.php/archives/416/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>cocos2d HOWTO系列之：如何创建帧动画</title>
		<link>http://www.dualface.com/index.php/archives/406</link>
		<comments>http://www.dualface.com/index.php/archives/406#comments</comments>
		<pubDate>Sun, 20 Jun 2010 08:46:40 +0000</pubDate>
		<dc:creator>dualface</dc:creator>
				<category><![CDATA[Apple's]]></category>
		<category><![CDATA[cocos2d]]></category>
		<category><![CDATA[Game]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://www.dualface.com/?p=406</guid>
		<description><![CDATA[在cocos2d中，大部分动画都是预先渲染好的位图。然后通过快速轮换来给玩家一种动态的感觉。例如下面的一系列位图，快速轮换时就是一朵随风而动的雏菊。
按照下面的步骤就可以很容易的创建帧动画：

创建包含各个帧的png图片
将png图片序列合并为一个png
生成CCSpriteSheet需要的.plist
在游戏中使用CCSprite显示动画


创建包含各个帧的png图片
要创建动画，Flash是一个非常好用的工具。而Flash提供了将帧动画导出为png图片序列的功能。假设我们的动画已经用Flash制作完成，保存成名为Flower9001的元件。现在打开包含这个元件的.fla文件，按照下列步骤生成png图片序列。
将元件拖放到画布上，调整好元件大小。然后修改元件类型为“Graphics”：

接下来按照元件的帧数，在时间轴上添加相同的帧数。最终结果如下：

预览一下可以看到动态花卉后，就可以使用Flash的File->Export->Export Movie功能将动画导出为png图片序列：

导出类型应该选为PNG Sequence，并选择Include为“Minimum Image Area”，选择Colors为“24 bit with alpha channel”：

导出完成后，可以得到一系列的png图片，文件名为Flower0001.png到Flower0063.png：

将png图片序列转换为CCSpriteSheet需要的格式
将PNG图片序列合并为一个PNG图片，需要用到Zwoptex这个软件。这个软件的最新版不但变成了收费版，而且改动了.plist文件的格式，无法直接在cocos2d中使用。
所以这里使用0.4b10版，不但功能一样，而且生成的.plist可以供cocos2d直接载入：Zwoptex 0.4b10 下载。
启动Zwoptex，新建一个.zss文件，然后将刚刚创建好的png图片全部拖放到Zwoptex窗口中：

设定Zwoptex的Layout面板中的Sort On选项为“Name”，再调整Canvas面板中的Width和Height为合适的大小，确保能够容纳所有的png图片。设定后，点击Layout面板中的Apply按钮，可以自动调整png图片的布局，最终需要确保没有重叠的图片：

调整完成后。点击Export面板中的Save .png和Save .plist按钮，分别生成合并后的png图片，以及所有帧的.plist文件。
导出的png图片命名为Flower.png，.plist文件命名为Flower.plist。
在cocos2d中使用CCSpriteSheet创建动画
在XCode中新建基于cocos2d的项目，命名为Make Sprite Anim。并将Flower.png和Flower.plist导入Resources群组中。
新建Config.h文件，内容为：

// 花卉动画的帧数
#define FLOWER_SPRITE_SHEET_CAPACITY 63

并确保HelloWorldScene.m和FlowerSprite.m文件的开头用#import &#8220;Config.h&#8221;导入Config.h文件。
修改HelloWorldScene.m文件，将init方法改为：

-(id) init
{
    self = [super init];
    if (self) {
        // 将花朵的png图片序列和plist载入场景
        CCSpriteFrameCache *cache = [CCSpriteFrameCache sharedSpriteFrameCache];
 [...]]]></description>
		<wfw:commentRss>http://www.dualface.com/index.php/archives/406/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
<!-- This Quick Cache file was built for (  www.dualface.com/index.php/feed ) in 0.76468 seconds, on Sep 10th, 2010 at 6:22 pm UTC. -->
<!-- This Quick Cache file will automatically expire ( and be re-built automatically ) on Sep 10th, 2010 at 7:22 pm UTC -->