<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[Blog of Felix021]]></title> 
<link>http://www.felix021.com/blog/index.php</link> 
<description><![CDATA[如果方向错了，停下来就是前进]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[Blog of Felix021]]></copyright>
<ttl>10</ttl>
<item>
    <title><![CDATA[在VC6.0下用GDI+画图]]></title> 
    <link>http://www.felix021.com/blog/read.php?0</link>
    <description>
<![CDATA[ 
	1. 下载gdi+的sdk，安装。当然，可以简化一点，从这里[ <a href="http://download.csdn.net/down/1645798/huohuo1120" target="_blank">http://download.csdn.net/down/1645798/huohuo1120</a> ]下载gdiplus所需文件包，解压并导入到vc6（将include和lib目录加入vc6的配置中）<br/><br/>2. 在VC6中创建一个Win32 Application，选择“一个简单的Win32程序”。假设项目名是main<br/><br/>3. 在StdAfx.h中加入<div class="code">#include &lt;winbase.h&gt;<br/>#define UNICODE<br/>#include &lt;comdef.h&gt;<br/>#ifndef ULONG_PTR <br/>#define ULONG_PTR unsigned long* <br/>#include &lt;GdiPlus.h&gt;<br/>using namespace Gdiplus; <br/>#endif </div><br/>4. 在main.cpp的WinMain前面生命全局的两个GDI变量<div class="code">GdiplusStartupInput gdiplusStartupInput;<br/>ULONG_PTR&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;  gdiplusToken;</div><br/>5. 在程序退出之前的地方加上<div class="code">GdiplusShutdown(gdiplusToken);</div><br/>6. 画图<br/><br/>6.1 创建一个Bitmap对象<div class="code">Bitmap *pBitmap = new Bitmap(width, height, PixelFormat24bppRGB);</div><br/>6.2 从Bitmap中获取Graphics对象<div class="code">Graphics *g = Graphics::FromImage(pBitmap);</div><br/>6.3 使用各种东西的组合来搞g，比如Pen, Brush, Region, Rect, PointF, Font……<div class="code">Pen pen_black(Color(255, 0, 0, 0), 3);<br/>g-&gt;DrawLine(&amp;pen_black, 0, 0, 100, 100);</div>更具体的说明和各种例子可以在这里找到：GDI+ SDK参考（翻译版本） <a href="http://download.csdn.net/source/642128" target="_blank">http://download.csdn.net/source/642128</a><br/><br/>7. 保存文件，这个比较麻烦<br/><div class="code">bool GetEncoderClsid(const WCHAR* format, CLSID* pClsid)<br/>&#123;<br/>&nbsp;  UINT num, size;<br/>&nbsp;  Gdiplus::GetImageEncodersSize(&amp;num, &amp;size);<br/>&nbsp;  Gdiplus::ImageCodecInfo* pImageCodecInfo = (Gdiplus::ImageCodecInfo*)(malloc(size));<br/>&nbsp;  Gdiplus::GetImageEncoders(num, size, pImageCodecInfo);<br/>&nbsp;  bool found = false;<br/>&nbsp;  for (UINT ix = 0; !found &amp;&amp; ix &lt; num; ++ix) &#123;<br/>&nbsp; &nbsp;  if (0 == _wcsicmp(pImageCodecInfo&#91;ix&#93;.MimeType, format) == 0) &#123;<br/>&nbsp; &nbsp; &nbsp;  *pClsid = pImageCodecInfo&#91;ix&#93;.Clsid;<br/>&nbsp; &nbsp; &nbsp;  found = true;<br/>&nbsp; &nbsp;  &#125;<br/>&nbsp;  &#125;<br/>&nbsp;  free(pImageCodecInfo);<br/>&nbsp;  return found;<br/>&#125;<br/>......<br/><br/>CLSID encoder;<br/>GetEncoderClsid(L&quot;mime/bmp&quot;, &amp;encoder);<br/>pb-&gt;Save(L&quot;result.bmp&quot;, &amp;encoder, NULL); </div>
]]>
    </description>
    <pubDate>Wed, 28 Jul 2010 16:50:44 +0000</pubDate> 
    <category><![CDATA[程序设计]]></category>
    <author>felix021 &lt;i[#at]felix021.com&gt;</author>
    <guid>http://www.felix021.com/blog/read.php?0</guid> 
</item>
<item>
    <title><![CDATA[errno: Thread-Local Storage]]></title> 
    <link>http://www.felix021.com/blog/read.php?1898</link>
    <description>
<![CDATA[ 
	在ISO C规范中有有一个很诡异的东西，那就是传说中的errno，一个有左值的int。当库函数出错的时候，它很可能会被设置为非0值；且没有任何一个库函数或系统调用会把它置为0。<br/><br/>刚接触到errno，可能会认为这是个在errno.h中用<div class="code">int errno;</div>定义的整型。但是一旦开始写多线程的程序，再看到errno的时候，就会抑郁了。如果两个线程调用库函数都出错，那errno怎么办...?<br/><br/>幸而，ISO C并没有规定，errno必须是一个int，如果看errno的manpage (man errno) 会看到：<div class="quote"><div class="quote-title">引用</div><div class="quote-content">errno may be a macro.&nbsp; errno is thread-local; setting it in one thread does not affect its value in any other thread.</div></div>实际上GNU的glibc也就是这么实现的，(通常)在/usr/include/bits/errno.h里头：<div class="code">#define errno (*__errno_location ()) </div><br/>于是errno就是个有左值的int了。至于这个__errno_location，在glibc的源码的 csu/errno-loc.c 里头：<div class="code">int *<br/>#if ! USE___THREAD<br/>weak_const_function<br/>#endif<br/>__errno_location (void)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br/>&#123;<br/>&nbsp; return &amp;errno;<br/>&#125;</div><br/>而这里的真正的errno，在 csu/errno.c 里头：<div class="code">__thread int errno;</div><br/>由于包含的都是errno.h，所以对于用户程序而言，可见的只有errno.h中的&quot;errno&quot;，实际上是(*(__errno_location())，而__errno_location()返回的是errno.c中的errno的地址。可真绕啊。可是偏偏又不能把 __thread int errno; 放在errno.h中，为什么呢？其实原因很简单也很复杂——C语言真是个纠结的语言。<br/><br/>最后，解释一下“__thread”修饰符：__thread defines number to be a thread local variable. 定义thread-local的变量。详情参见Thread-local_storage的wiki页：<a href="http://en.wikipedia.org/wiki/Thread-local_storage" target="_blank">http://en.wikipedia.org/wiki/Thread-local_storage</a>
]]>
    </description>
    <pubDate>Tue, 27 Jul 2010 14:50:29 +0000</pubDate> 
    <category><![CDATA[操作系统]]></category>
    <author>felix021 &lt;i[#at]felix021.com&gt;</author>
    <guid>http://www.felix021.com/blog/read.php?1898</guid> 
</item>
<item>
    <title><![CDATA[把字符串变成文件流]]></title> 
    <link>http://www.felix021.com/blog/read.php?1897</link>
    <description>
<![CDATA[ 
	0. int fd[2];<br/>1. pipe(fd) 打开一个管道<br/>2. fork或者pthread<br/>3. 往fd[0]写字符串<br/>4. 从fd[1]读取，或者可以fdopen(fd[1])，获得一个文件指针，读取文件。
]]>
    </description>
    <pubDate>Wed, 21 Jul 2010 15:15:35 +0000</pubDate> 
    <category><![CDATA[随手记下]]></category>
    <author>felix021 &lt;i[#at]felix021.com&gt;</author>
    <guid>http://www.felix021.com/blog/read.php?1897</guid> 
</item>
<item>
    <title><![CDATA[svn(subversion)的hook]]></title> 
    <link>http://www.felix021.com/blog/read.php?1896</link>
    <description>
<![CDATA[ 
	纯粹记录一下。看不懂的绕行吧..<br/><div class="code">$ mkdir repos<br/>$ svnadmin create repos<br/>$ ls repos/<br/>conf&nbsp; db&nbsp; format&nbsp; hooks&nbsp; locks&nbsp; README.txt<br/>$ ls repos/hooks/<br/>post-commit.tmpl&nbsp; post-revprop-change.tmpl&nbsp; pre-commit.tmpl&nbsp; pre-revprop-change.tmpl&nbsp; start-commit.tmpl<br/>post-lock.tmpl&nbsp; &nbsp; post-unlock.tmpl&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pre-lock.tmpl&nbsp; &nbsp; pre-unlock.tmpl<br/>$ cd repos/hooks<br/>$ cp post-commit.tmpl post-commit<br/>$ chmod +x post-commit<br/>$ vi post-commit <br/>……</div><br/>当客户端COMMIT成功以后，post-commit会被执行，调用时会传入两个参数，$1是repos的绝对路径，$2是REV，此次提交的版本号。<br/><br/>可以配合rsync用于分发各种东西。
]]>
    </description>
    <pubDate>Tue, 20 Jul 2010 10:57:21 +0000</pubDate> 
    <category><![CDATA[软件]]></category>
    <author>felix021 &lt;i[#at]felix021.com&gt;</author>
    <guid>http://www.felix021.com/blog/read.php?1896</guid> 
</item>
<item>
    <title><![CDATA[SO_REUSEADDR]]></title> 
    <link>http://www.felix021.com/blog/read.php?1895</link>
    <description>
<![CDATA[ 
	前一阵和momo讨论到他的基于UDP的某个系统的设计时遇到这样一个问题：在一个局域网中有多台机器，有个消息是通过UDP广播发出的，且每台机器有多个进程需要监听同一个UDP端口，应该怎么办？<br/><br/>由于所知有限，当时我给的解决方案是，使用类似observer模式来建立一个稍复杂的服务（其实就是个转发，但是UDP进程数量未知）。后来momo发现，其实只要通过setsockopt设置SO_REUSEADDR属性之后，多个程序就可以绑定同一个端口了。<br/><br/>虽然问题是解决了，但是SO_REUSEADDR并没有上面提到的那么简单，因为momo遇到的问题正好是UDP广播/多播。否则上述模型就不适用了。这里有一篇文章，对其有更详细的注解，虽然是摘自《UNIX网络编程》的，但是给出了例子，很值得学习。<br/><br/>SO_REUSEADDR例解：<a href="http://www.cppblog.com/ace/archive/2006/04/29/6446.aspx" target="_blank">http://www.cppblog.com/ace/archive/2006/04/29/6446.aspx</a><br/>unix网络编程 第一卷：<a href="http://wenku.baidu.com/view/99a6cc38376baf1ffc4fad6f.html" target="_blank">http://wenku.baidu.com/view/99a6cc38376baf1ffc4fad6f.html</a><br/><br/>
]]>
    </description>
    <pubDate>Mon, 19 Jul 2010 13:49:21 +0000</pubDate> 
    <category><![CDATA[网络]]></category>
    <author>felix021 &lt;i[#at]felix021.com&gt;</author>
    <guid>http://www.felix021.com/blog/read.php?1895</guid> 
</item>
<item>
    <title><![CDATA[有时候……洄游]]></title> 
    <link>http://www.felix021.com/blog/read.php?1894</link>
    <description>
<![CDATA[ 
	昨天去了一趟百度大厦。是从城铁西二旗下车走过去的，方向跟1.26号离职时正好相反。还记得那天的天空，当我走出百度大厦的时候，背后是不那么暖的太阳，抬头是清冷的月亮。跟上一次也反过来的，是在前台登记的时候，我和阿牛的名字在来访者和被访者的位置上对调了，我也贴上那个Baidu Friend的胸贴。到F3-CE去转了一下，没有看到加班的同事，不过上次离开时留下的魔方还在，以及工位上一只不能用的水性笔，挂着的“百年好合”——同事结婚时发的很精致的喜糖包装。把魔方拧好。<br/><br/>预期的中午是个简单的小聚，和阿牛、Sandy聊聊天。不过最后有7个人，包括Kid、Maner，计科8的Ding同学，以及cs研的一位师兄。Sandy还提了一个小蛋糕过来，说是要为我补过生日（情何以堪...）。在辉煌国际的一家快餐店，以比较便宜的价格吃得很开心。蛋糕比较神奇，除了上面用果酱（？）涂写的felix之外，正好有七朵奶油花，七个人。于是蛋糕切起来就很容易了。<br/><br/>下午在阿牛的工位上坐了一会儿，执行来百度大厦的主要目标之一：拷电影。上次离职前从电影协会的FTP里拷了好多电影，每一部都很经典。可惜电影协会的FTP已经换了，此Mission暂时搁置。给阿牛的X201测了3DMark2001，得分8700+，集显。顺便给我的本本也测了一下，9500+，独显……<br/><br/>近四点，HJ也过来了。此行的另一个主要目的，和HJ、Maner打球吃饭。于是到1L去打乒乓球。在中央空调的机器下面，风好大。不过还是打得很开心。其实还是第一次在百度大厦打乒乓球，虽然在里头2个多月……脱了凉鞋，那里的地板脚感很好。然后到汉王那边的蜀香阁，点了几样菜。下午过的很开心。<br/><br/>晚上去参观阿牛的住处。回龙观，龙博苑。离地铁站还算近。房子有点儿旧，不过还算宽敞，家具齐全。挺好。晚上借宿一宿，那个席梦思上没有铺床单，跟我当时在天露园住得一样。<br/><br/>有时候……生活挺单调的，挺混乱的。需要一点调剂，一些慰藉。
]]>
    </description>
    <pubDate>Sun, 18 Jul 2010 14:55:13 +0000</pubDate> 
    <category><![CDATA[随手记下]]></category>
    <author>felix021 &lt;i[#at]felix021.com&gt;</author>
    <guid>http://www.felix021.com/blog/read.php?1894</guid> 
</item>
<item>
    <title><![CDATA[一个经济学问题]]></title> 
    <link>http://www.felix021.com/blog/read.php?1893</link>
    <description>
<![CDATA[ 
	记总收益为T，价格为P，售出量为Q，则 T = P * Q。如果P上升10%，Q下降10%，那么T应当如何变化？<br/><br/>答：不变。<br/><br/>---分割线 以上是问题---<br/><br/>第一次看到这个的时候很郁闷，110%P * 90%Q 显然应该是0.99T &lt; T，怎么会不变呢？昨天在看到经济学原理第四章的时候又遇到了中点法计算比例，突然茅塞顿开。<br/><br/>中点法计算比例：假设价格由P1变化到P2，通常我们会用(P2 - P1) / P1 * 100%来计算变动的比例；如果由P2变动到P1，则是(P1 - P2) / P2 * 100%。由于分母变了，分子不变，所以看起来应该是没啥区别的变动，反映到变动比例的时候差别就很大了。比如3-&gt;4是33.33%, 4-&gt;3是25%，多纠结。于是经济学中通常采用这样的计算方法：<div class="quote"><div class="quote-title">引用</div><div class="quote-content">变动比例 = (P2 - P1) / ((P1 + P2) / 2) * 100%</div></div>这样如论从哪个方向变动，比例都是固定的了。<br/><br/>回到最上面的问题，如果P下降了10%，实际上，下降后的P1 = P * 9/11，Q上升了10%，则Q1 = Q * 11/9。所以T1 = P1 * Q1 = P * Q = T。总收益果然不变。<br/><br/>p.s. (P - P1) / ((P + P1) / 2) = 10%&nbsp;  ==&gt; P1 = P * 9 / 11
]]>
    </description>
    <pubDate>Wed, 14 Jul 2010 02:21:51 +0000</pubDate> 
    <category><![CDATA[学习]]></category>
    <author>felix021 &lt;i[#at]felix021.com&gt;</author>
    <guid>http://www.felix021.com/blog/read.php?1893</guid> 
</item>
<item>
    <title><![CDATA[facebook javascript sdk 杂记2]]></title> 
    <link>http://www.felix021.com/blog/read.php?1892</link>
    <description>
<![CDATA[ 
	在不是用iframe测试iframe app的时候（就是在新窗口打开iframe的url）可以在地址栏执行<div class="code">javascript:FB.api(&#123; method: &#039;Auth.revokeAuthorization&#039; &#125;);</div>来取消所有已经取得的权限，包括Basic Info、Bookmark，当刷新apps.facebook.com/xxxx的时候会要求重新认证。再未重新认证时如果在非iframe的方式测试FB.ui(&#123;method:'bookmark.add'&#125;, cb)会出现<div class="quote"><div class="quote-title">引用</div><div class="quote-content">An error occurred with APP_NAME. Please try again later.<br/>API Error Code: 200<br/>API Error Description: Permissions error<br/>Error Message: Permissions error</div></div>用这种方式（注：$是jQuery里头的函数）javascript:$('#id')[0].style.visibility='hidden'; 可以让某个元素不可见，但是再次改为visible时不会需要重新载入。IE8、FF3.5、Chrome5测试通过。<br/><br/>FB.login(cb, &#123;perms:'perm1,perm2,...'&#125;) 给cb的参数response的属性perms 【如function cb(response)&#123; alert(response.perms); &#125;】 包含的是所有授权的perms列表，逗号分隔；无论这次login方法请求的perms是多少个。
]]>
    </description>
    <pubDate>Thu, 08 Jul 2010 14:55:01 +0000</pubDate> 
    <category><![CDATA[网络]]></category>
    <author>felix021 &lt;i[#at]felix021.com&gt;</author>
    <guid>http://www.felix021.com/blog/read.php?1892</guid> 
</item>
<item>
    <title><![CDATA[facebook javascript sdk的拆分设计]]></title> 
    <link>http://www.felix021.com/blog/read.php?1891</link>
    <description>
<![CDATA[ 
	facebook的javascript sdk因为需要完成比较多的功能，因此体积比较大（50K左右）。<br/><br/>如果每次都完整载入，必然会导致浪费过多带宽，因此缓存是必要的；但是缓存会导致BUG fix或者function enhancement无法即时更新到客户端。二者之间的矛盾调和可以用调整缓存时间来解决，但是这种解决方案并不够好，尤其是灵活性不够，有时候lib一天更新几次，有时候十天半个月甚至更久都不更新，这种解决方案的适应性就不够了。<br/><br/>facebook用的解决方案是，将sdk进行拆分，变成两块，第一块是loader，约2KB，缓存时间1小时；第二块是lib，约50KB，缓存时间一个月。开发者只需要用script标签载入loader即可，由loader来载入lib。lib的路径是带有版本号的，当facebook更新了lib以后，只需要修改loader中lib的版本。由于版本号不同了，路径也不同了，因此浏览器会重新请求新版本的lib。<br/><br/>该思路摘自facebook的wiki：<a href="http://wiki.developers.facebook.com/index.php/FeatureLoader.js.php" target="_blank">http://wiki.developers.facebook.com/index.php/FeatureLoader.js.php</a><br/><br/>p.s. 这个是旧版的SDK。
]]>
    </description>
    <pubDate>Thu, 08 Jul 2010 07:20:24 +0000</pubDate> 
    <category><![CDATA[网络]]></category>
    <author>felix021 &lt;i[#at]felix021.com&gt;</author>
    <guid>http://www.felix021.com/blog/read.php?1891</guid> 
</item>
<item>
    <title><![CDATA[facebook javascript sdk 杂记1]]></title> 
    <link>http://www.felix021.com/blog/read.php?1890</link>
    <description>
<![CDATA[ 
	在初始化FB对象之前必须要有一个id=fb-root的元素, 比如<div class="quote"><div class="quote-title">引用</div><div class="quote-content">&lt;div id=&quot;fb-root&quot;&gt;&lt;/div&gt;</div></div>可以用同步或者异步的方式初始化FB对象。<br/>同步：在head里头加入&lt;script src=&quot;<a href="http://connect.facebook.net/en_US/all.js&quot;&gt;" target="_blank">http://connect.facebook.net/en_US/all.js&quot;&gt;</a>，最好在&lt;/body&gt;标签之前加入FB.init方法，这样可以保证网页的其他模块都已经正常载入。<br/>异步：适合在&lt;body&gt;标签之后加入，这样可以和网页其他元素并行载入。参见：<a href="http://developers.facebook.com/docs/reference/javascript/" target="_blank">http://developers.facebook.com/docs/reference/javascript/</a><br/><br/>如果调用FB.init时指定了xfbml:true，那么当前页面中的XFBML元素都会被转换；如果没有指定，那么可以调用FB.XFBML.parse()，或者指定一个元素FB.XFBML.parse(document.getElementById(&#039;ooxx&#039;));<br/><br/>FB.login(cb, &#123;perms: &#039;perm1,perm2...&#039;&#125;)方法用于获取用户权限，会有个Popup提示用户选择 允许 或 不允许。用户选择后会执行cb函数，给一个response对象，包含用户授权的权限列表（逗号分隔）。权限列表见<a href="http://developers.facebook.com/docs/authentication/permissions" target="_blank">http://developers.facebook.com/docs/authentication/permissions</a>。可以通过FQL在permissions查所有的权限，包括查询用户是否添加了书签(bookmarked)。<br/><br/>FB.Event.subscribe(EventName, cb)方法用于订阅当前页面的某些事件，比如fb:like事件可以用FB.Event.subscribe(&#039;edge.create&#039;, callbackFunc)来订阅。当事件出现时会调用回调函数cb，给出事件对应的参数。<br/><br/>FB.Data.query方法用于执行FQL语句。FQL语句不能有换行，不能SELECT *，WHERE子句必须是能够索引的。查询是异步的，会立即返回一个query对象。query对象有wait方法，传入一个回调函数，当执行完毕后会调用该函数，传入一个数组，数组的每一行是一个查询结果对象，对象的每个属性就是SELECT出来的东西，比如SELECT id, url from object_url WHERE url=&quot;<a href="http://www.felix021.com&quot;" target="_blank">http://www.felix021.com&quot;</a>，回调函数可以获得rows[0].id rows[0].url。<br/><br/>可以在 <a href="http://developers.facebook.com/docs/reference/rest/fql.query" target="_blank">http://developers.facebook.com/docs/reference/rest/fql.query</a> 测试FQL语句的执行。permissions这个表看似只列出了两个字段，但是实际上PERMISSION_NAME这个字段是泛指所有可以在<a href="http://developers.facebook.com/docs/authentication/permissions" target="_blank">http://developers.facebook.com/docs/authentication/permissions</a>页面查到的权限名称，<strong>而且还包括bookmarked、tab_added两个不是权限的名称（很诡异吧？）</strong>，详见<a href="http://wiki.developers.facebook.com/index.php/Permissions_(FQL)" target="_blank">http://wiki.developers.facebook.com/index.php/Permissions_(FQL)</a>。<br/><br/>FB.ui方法可以用于显示一些对话框（iFrame或者Popup）。比如FB.ui(&#123;method:&#039;bookmark.add&#039;&#125;, cb)可以用于显示添加书签（FB对应的APP）的iFrame，在添加成功/失败后会调用cb函数，传参response，response.bookmarked=0或1表示失败或成功。<br/><br/>可以在 <a href="http://fbrell.com/examples" target="_blank">http://fbrell.com/examples</a> 看到更详细的例子，直接测试js的sdk。<br/><br/>FB的js的SDK里面 console/index.html 是个很不错的example合集，下面附上我自己写的一些example<br/><a href="attachment.php?fid=402" target="_blank">attachment.php?fid=402</a>
]]>
    </description>
    <pubDate>Wed, 07 Jul 2010 11:51:21 +0000</pubDate> 
    <category><![CDATA[网络]]></category>
    <author>felix021 &lt;i[#at]felix021.com&gt;</author>
    <guid>http://www.felix021.com/blog/read.php?1890</guid> 
</item>

</channel>
</rss>