<?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>Cai Guanhao</title>
	<atom:link href="http://www.caiguanhao.com/feed" rel="self" type="application/rss+xml" />
	<link>http://www.caiguanhao.com</link>
	<description>Just another WordPress site</description>
	<lastBuildDate>Sat, 18 Feb 2012 11:20:43 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>C：一个不经意的错误</title>
		<link>http://www.caiguanhao.com/archives/174</link>
		<comments>http://www.caiguanhao.com/archives/174#comments</comments>
		<pubDate>Sat, 18 Feb 2012 11:20:43 +0000</pubDate>
		<dc:creator>caiguanhao</dc:creator>
				<category><![CDATA[C]]></category>

		<guid isPermaLink="false">http://www.caiguanhao.com/?p=174</guid>
		<description><![CDATA[在配置curl时因为贪方便犯了一个不经意的错误，用curl下载图片，然后写入某个文件，但是下载完毕后，文件还不完整（图片末端未保存，看到黑边），直至程序关闭才显示完整。期间怀疑过是thread、curl的cleanup、gtk_main_quit等等的问题，最后终于找到是fopen没有fclose，因为偷懒。 不完整的图片文件（文件大小较小，末端有黑边）： 完整的图片文件： 偷懒的代码： 这才没问题： fclose不同curl_easy_cleanup那些的一点是，当fclose了一个不存在的东西就会出现严重错误。 另外有一些如果不简化将会显得很累赘： 简化为： Keywords: C libcurl incomplete download]]></description>
			<content:encoded><![CDATA[<p>在配置curl时因为贪方便犯了一个不经意的错误，用curl下载图片，然后写入某个文件，但是下载完毕后，文件还不完整（图片末端未保存，看到黑边），直至程序关闭才显示完整。期间怀疑过是thread、curl的cleanup、gtk_main_quit等等的问题，最后终于找到是fopen没有fclose，因为偷懒。</p>
<p>不完整的图片文件（文件大小较小，末端有黑边）：<br />
<a href="http://www.caiguanhao.com/thewordpress/wp-content/uploads/2012/02/incomplete.png"><img class="alignnone size-full wp-image-176" title="incomplete" src="http://www.caiguanhao.com/thewordpress/wp-content/uploads/2012/02/incomplete.png" alt="" width="222" height="124" /></a></p>
<p>完整的图片文件：<br />
<a href="http://www.caiguanhao.com/thewordpress/wp-content/uploads/2012/02/complete.png"><img class="alignnone size-full wp-image-175" title="complete" src="http://www.caiguanhao.com/thewordpress/wp-content/uploads/2012/02/complete.png" alt="" width="222" height="124" /></a></p>
<p>偷懒的代码：</p>
<pre class="brush: cpp; title: ; notranslate">
...
curl_easy_setopt(http_handle[i], CURLOPT_WRITEDATA, fopen(filename, &quot;wb&quot;));
...
</pre>
<p>这才没问题：</p>
<pre class="brush: cpp; title: ; notranslate">
...
CURL *http_handle[items_found];
FILE *fp[items_found];
...
while ( ... ) {
	...
	fp[i]=fopen(filename,&quot;wb&quot;);

	http_handle[i] = curl_easy_init();
	...
	curl_easy_setopt(http_handle[i], CURLOPT_WRITEFUNCTION, write_data);
	curl_easy_setopt(http_handle[i], CURLOPT_WRITEDATA, fp[i]);
	...
}
...
for(i=0;i&lt;items_found;i++){
	curl_easy_cleanup(http_handle[i]);
	fclose(fp[i]); //如果不用，直到关闭程序后才会close
}
...
</pre>
<p>fclose不同curl_easy_cleanup那些的一点是，当fclose了一个不存在的东西就会出现严重错误。</p>
<p>另外有一些如果不简化将会显得很累赘：</p>
<pre class="brush: cpp; title: ; notranslate">
size_t write_data (void *ptr, size_t size, size_t nmemb, FILE *stream) {
	size_t written;
	written = fwrite(ptr, size, nmemb, stream);
	return written;
}
</pre>
<p>简化为：</p>
<pre class="brush: cpp; title: ; notranslate">
size_t write_data (void *ptr, size_t size, size_t nmemb, FILE *stream) {
	return fwrite(ptr, size, nmemb, stream);
}
</pre>
<p>Keywords: C libcurl incomplete download</p>
]]></content:encoded>
			<wfw:commentRss>http://www.caiguanhao.com/archives/174/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C：Linux下解决curl太慢（等15秒）的办法</title>
		<link>http://www.caiguanhao.com/archives/170</link>
		<comments>http://www.caiguanhao.com/archives/170#comments</comments>
		<pubDate>Sun, 12 Feb 2012 06:01:35 +0000</pubDate>
		<dc:creator>caiguanhao</dc:creator>
				<category><![CDATA[C]]></category>
		<category><![CDATA[curl]]></category>

		<guid isPermaLink="false">http://www.caiguanhao.com/?p=170</guid>
		<description><![CDATA[Linux（如Ubuntu）下的curl有时会很慢，每次请求都要等待约15秒后才有结果出来，排除了网速慢的原因，很可能是电信DNS解析或者是路由器的问题。网上比较多的做法是设置Header的Expect为空，但这种做法貌似没什么作用，还有一种是设置使用IPV4 curl_easy_setopt(curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); ，可以在终端输入 time curl -4 http://www.caiguanhao.com/custom-homepage/weather/daliang.json 测试以下速度，如果之前是15秒才出结果，用了IPV4应该只需要约5秒的时间。]]></description>
			<content:encoded><![CDATA[<p>Linux（如Ubuntu）下的curl有时会很慢，每次请求都要等待约15秒后才有结果出来，排除了网速慢的原因，很可能是电信DNS解析或者是路由器的问题。网上比较多的做法是设置Header的Expect为空，但这种做法貌似没什么作用，还有一种是设置使用IPV4 <code>curl_easy_setopt(curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);</code> ，可以在终端输入 <code>time curl -4 http://www.caiguanhao.com/custom-homepage/weather/daliang.json</code> 测试以下速度，如果之前是15秒才出结果，用了IPV4应该只需要约5秒的时间。</p>
<pre class="brush: cpp; title: ; notranslate">
#include &lt;curl/curl.h&gt;

...

CURL *curl_handle = NULL;
curl_handle = curl_easy_init();
curl_easy_setopt(curl_handle, CURLOPT_URL, url);

...

curl_easy_setopt(curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);

...

struct curl_slist *slist=NULL;
slist = curl_slist_append(slist, &quot;Expect:&quot;);
curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, slist);

curl_easy_perform(curl_handle);
curl_easy_cleanup(curl_handle);
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.caiguanhao.com/archives/170/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JS+PHP：LastPass的密码强度算法</title>
		<link>http://www.caiguanhao.com/archives/166</link>
		<comments>http://www.caiguanhao.com/archives/166#comments</comments>
		<pubDate>Tue, 07 Feb 2012 16:48:54 +0000</pubDate>
		<dc:creator>caiguanhao</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.caiguanhao.com/?p=166</guid>
		<description><![CDATA[有时需要在网页上验证用户输入的密码的强度，而相类似的PHP代码可用于后台密码强度统计。在Chrome上安装LastPass，然后在Preferences>Extensions>勾选Developer Mode>点击LastPass>点击Inspect active views: background.html，然后在Resources>Scripts>lpfulllib.js下找到这段JS代码。 转为相类似的PHP函数：]]></description>
			<content:encoded><![CDATA[<p>有时需要在网页上验证用户输入的密码的强度，而相类似的PHP代码可用于后台密码强度统计。在Chrome上安装LastPass，然后在Preferences>Extensions>勾选Developer Mode>点击LastPass>点击Inspect active views: background.html，然后在Resources>Scripts>lpfulllib.js下找到这段JS代码。</p>
<p><a href="http://www.caiguanhao.com/thewordpress/wp-content/uploads/2012/02/lasspass-generate-password.png"><img src="http://www.caiguanhao.com/thewordpress/wp-content/uploads/2012/02/lasspass-generate-password.png" alt="" title="lasspass-generate-password" width="289" height="322" class="alignnone size-full wp-image-167" /></a></p>
<pre class="brush: jscript; title: ; notranslate">
function getpasswordstrength(a, b) {
	var c = 0;
	if (a == &quot;&quot; &amp;&amp; b == &quot;&quot;) return 0;
	if (b == a) return 1;
	if (a != &quot;&quot; &amp;&amp; a.indexOf(b) != -1) c -= 15;
	if (a != &quot;&quot; &amp;&amp; b.indexOf(a) != -1) c -= a.length;
	c += b.length;
	if (b.length &gt; 0 &amp;&amp; b.length &lt;= 4) c += b.length;
	else if (b.length &gt;= 5 &amp;&amp; b.length &lt;= 7) c += 6;
	else if (b.length &gt;= 8 &amp;&amp; b.length &lt;= 15) c += 12;
	else if (b.length &gt;= 16) c += 18;
	if (b.match(/[a-z]/)) c += 1;
	if (b.match(/[A-Z]/)) c += 5;
	if (b.match(/\d/)) c += 5;
	if (b.match(/.*\d.*\d.*\d/)) c += 5;
	if (b.match(/[!,@,#,$,%,^,&amp;,*,?,_,~]/)) c += 5;
	if (b.match(/.*[!,@,#,$,%,^,&amp;,*,?,_,~].*[!,@,#,$,%,^,&amp;,*,?,_,~]/)) c += 5;
	if (b.match(/(?=.*[a-z])(?=.*[A-Z])/)) c += 2;
	if (b.match(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/)) c += 2;
	if (b.match(/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!,@,#,$,%,^,&amp;,*,?,_,~])/)) c += 2;
	var d = [],
		e = 0,
		f, h;
	for (f = 0; f &lt; b.length; ++f) {
		h = b.charAt(f);
		if (typeof d[h] == &quot;undefined&quot;) {
			d[h] = 1;
			++e
		}
	}
	if (e == 1) return 2;
	c *= 2;
	if (c &lt; 0) c = 0;
	else if (c &gt; 100) c = 100;
	return c
}
</pre>
<p>转为相类似的PHP函数：</p>
<pre class="brush: php; title: ; notranslate">
function get_password_strength($a=null,$b){
	$c=strlen($b);
	if(isset($b[0])&amp;&amp;strlen(str_replace($b[0],'',$b))==0)return 2;
	if($a==''&amp;&amp;$b=='')return 0;
	if($a==$b)return 1;
	if($a!=''&amp;&amp;strpos($a,$b)!==false)$c-=15;
	if($a!=''&amp;&amp;strpos($b,$a)!==false)$c-=strlen($a);
	if(strlen($b)&gt;0&amp;&amp;strlen($b)&lt;=4)$c+=strlen($b);
	elseif(strlen($b)&gt;=5&amp;&amp;strlen($b)&lt;=7)$c+=6;
	elseif(strlen($b)&gt;=8&amp;&amp;strlen($b)&lt;=15)$c+=12;
	elseif(strlen($b)&gt;=16)$c+=18;
	if(preg_match('/[a-z]/',$b))$c+=1;
	if(preg_match('/[A-Z]/',$b))$c+=5;
	if(preg_match('/\d/',$b))$c+=5;
	if(preg_match('/.*\d.*\d.*\d/',$b))$c+=5;
	if(preg_match('/[!,@,#,$,%,^,&amp;,*,?,_,~]/',$b))$c+=5;
	if(preg_match('/.*[!,@,#,$,%,^,&amp;,*,?,_,~].*[!,@,#,$,%,^,&amp;,*,?,_,~]/',$b))$c+=5;
	if(preg_match('/(?=.*[a-z])(?=.*[A-Z])/',$b))$c+=2;
	if(preg_match('/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])/',$b))$c+=2;
	if(preg_match('/(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!,@,#,$,%,^,&amp;,*,?,_,~])/',$b))$c+=2;
	$c*=2;
	if($c&lt;0)$c=0;elseif($c&gt;100)$c=100;
	return $c;
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.caiguanhao.com/archives/166/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP：为twitter信息添加链接</title>
		<link>http://www.caiguanhao.com/archives/154</link>
		<comments>http://www.caiguanhao.com/archives/154#comments</comments>
		<pubDate>Wed, 01 Feb 2012 06:01:14 +0000</pubDate>
		<dc:creator>caiguanhao</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[twitter]]></category>

		<guid isPermaLink="false">http://www.caiguanhao.com/?p=154</guid>
		<description><![CDATA[思路是提取所有位置，然后排序，先后逐一驳接。]]></description>
			<content:encoded><![CDATA[<pre class="brush: jscript; title: ; notranslate">
//twitter API user timeline JSON 示例：
//主要分为urls、user_mentions和hashtags三类
//各类都有indices，分别是开始和结束的位置，在PHP中需要用mb_substr
//示例URL：https://api.twitter.com/1/statuses/user_timeline.json?screen_name=RTKcn&amp;count=20&amp;include_entities=1&amp;include_rts=1&amp;trim_user=1
    ...
    &quot;entities&quot;: {
      &quot;urls&quot;: [

      ],
      &quot;user_mentions&quot;: [
        {
          &quot;name&quot;: &quot;Fenng&quot;,
          &quot;indices&quot;: [
            8,
            14
          ],
          &quot;id_str&quot;: &quot;1490631&quot;,
          &quot;id&quot;: 1490631,
          &quot;screen_name&quot;: &quot;Fenng&quot;
        }
      ],
      &quot;hashtags&quot;: [

      ]
    },
    ...
</pre>
<p>思路是提取所有位置，然后排序，先后逐一驳接。</p>
<pre class="brush: php; title: ; notranslate">
//排序：
function indices_sort($a,$b){
	if($a[0]==$b[0])return 0;
	return ($a[0]&lt;$b[0])?-1:1;
}
//省略了获取JSON，并转为数组的步骤
$original_text=$tweet['text'];
$um=$tweet['entities']['user_mentions'];
$urls=$tweet['entities']['urls'];
$hts=$tweet['entities']['hashtags'];
$indices=array();
if(is_array($um)){
	foreach($um as $UM){
		//逐一将位置和替换的内容放到一个数组内，其他也如此
		array_push($indices,array(
			$UM['indices'][0],
			$UM['indices'][1],
			&quot;&lt;a href=\&quot;https://twitter.com/#!/$UM[screen_name]\&quot; title=\&quot;$UM[name] [@$UM[screen_name]]\&quot;&gt;{1}&lt;/a&gt;&quot;
		));
	}
}
if(is_array($urls)){
	foreach($urls as $URLS){
		array_push($indices,array(
			$URLS['indices'][0],
			$URLS['indices'][1],
			&quot;&lt;a href=\&quot;$URLS[expanded_url]\&quot;&gt;$URLS[display_url]&lt;/a&gt;&quot;
		));
	}
}
if(is_array($hts)){
	foreach($hts as $HTS){
		array_push($indices,array(
			$HTS['indices'][0],
			$HTS['indices'][1],
			&quot;&lt;a href=\&quot;https://twitter.com/#!/search?q=%23$HTS1\&quot; title=\&quot;#$HTS1\&quot;&gt;{1}&lt;/a&gt;&quot;
		));
	}
}
if(count($indices)&gt;0){
	usort($indices,'indices_sort'); //按开始位置排序
	$formatted_text='';
	$formatted_text.=mb_substr($original_text,0,$indices[0][0],'UTF-8'); //从开端开始到第一个位置
	for($i=0;;$i++){
		if(isset($indices[$i])){
			$formatted_text.=str_replace('{1}',mb_substr($original_text,$indices[$i][0],$indices[$i][1]-$indices[$i][0],'UTF-8'),$indices[$i][2]);
			if(isset($indices[$i+1])){
				$formatted_text.=mb_substr($original_text,$indices[$i][1],$indices[$i+1][0]-$indices[$i][1],'UTF-8');
			}else{
				//最后一个位置到末端，因为要定义UTF-8，长度必须要填，
				//这里不要贪方便填最大值PHP_INT_MAX，否则可能漏掉一个字符
				$formatted_text.=mb_substr($original_text,$indices[$i][1],mb_strlen($original_text)-$indices[$i][1],'UTF-8');
				break; //已完成，退出循环
			}
		}
	}
}else{
	$formatted_text=$original_text; //不需要添加链接
}
</pre>
<p><a href="http://www.caiguanhao.com/thewordpress/wp-content/uploads/2012/02/twitter-link.png"><img src="http://www.caiguanhao.com/thewordpress/wp-content/uploads/2012/02/twitter-link.png" alt="" title="twitter-link" width="391" height="79" class="alignnone size-full wp-image-160" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.caiguanhao.com/archives/154/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP：HTML ENTITIES（&amp;#xxxxx;）转UTF-8</title>
		<link>http://www.caiguanhao.com/archives/148</link>
		<comments>http://www.caiguanhao.com/archives/148#comments</comments>
		<pubDate>Fri, 06 Jan 2012 09:01:31 +0000</pubDate>
		<dc:creator>caiguanhao</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.caiguanhao.com/?p=148</guid>
		<description><![CDATA[一些诸如 &#38;#65311; 的代码叫做HTML ENTITIES，在含UTF-8文本的转换过程中必须要考虑到的，在PHP里面至少有两种简便的方法将其转为正常文字：]]></description>
			<content:encoded><![CDATA[<p>一些诸如 &amp;#65311; 的代码叫做HTML ENTITIES，在含UTF-8文本的转换过程中必须要考虑到的，在PHP里面至少有两种简便的方法将其转为正常文字：</p>
<pre class="brush: php; title: ; notranslate">
// 对于大量文字夹杂HTML-ENTITIES较好，只将HTML-ENTITIES转为UTF-8
// http://php.net/manual/en/function.html-entity-decode.php

$content=html_entity_decode($content,ENT_COMPAT,'UTF-8');

// 将逐一从HTML-ENTITIES转换到UTF-8，正常字符可能会乱码，
// 最好配合正则表达式针对HTML-ENTITIES使用：
// http://php.net/manual/en/function.mb-convert-encoding.php

$content=mb_convert_encoding($content,'UTF-8','HTML-ENTITIES');

//使用正则表达式，使用兼容性高一点的create_function：
$content=preg_replace_callback('/&amp;[^;]+;/',create_function('$matches','return mb_convert_encoding($matches[0],&quot;UTF-8&quot;,&quot;HTML-ENTITIES&quot;);'),$content);
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.caiguanhao.com/archives/148/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PHP：使用Yahoo!天气RSS获取天气信息</title>
		<link>http://www.caiguanhao.com/archives/144</link>
		<comments>http://www.caiguanhao.com/archives/144#comments</comments>
		<pubDate>Thu, 05 Jan 2012 16:50:09 +0000</pubDate>
		<dc:creator>caiguanhao</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.caiguanhao.com/?p=144</guid>
		<description><![CDATA[可以通过获取Yahoo!天气RSS，就可以在自己网页上显示详细的天气信息。详细的说明文档在这里。下面是一些代码对应的文字。]]></description>
			<content:encoded><![CDATA[<p>可以通过获取Yahoo!天气RSS，就可以在自己网页上显示详细的天气信息。详细的说明文档在<a href="http://developer.yahoo.com/weather/">这里</a>。下面是一些代码对应的文字。</p>
<p><a href="http://www.caiguanhao.com/thewordpress/wp-content/uploads/2012/01/weather_screenshot.png"><img class="alignnone size-large wp-image-145" title="weather_screenshot" src="http://www.caiguanhao.com/thewordpress/wp-content/uploads/2012/01/weather_screenshot-576x27.png" alt="" width="576" height="27" /></a></p>
<pre class="brush: php; title: ; notranslate">
// 代码代表的意思
$code=array(
	'0'=&gt;'龙卷风',
	'1'=&gt;'热带风暴',
	'2'=&gt;'飓风',
	'3'=&gt;'大雷雨',
	'4'=&gt;'雷雨',
	'5'=&gt;'雨夹雪',
	'6'=&gt;'雨和雨夹雪',
	'7'=&gt;'雨夹冰雹',
	'8'=&gt;'冻毛毛雨',
	'9'=&gt;'毛毛雨',
	'10'=&gt;'冻雨',
	'11'=&gt;'阵雨',
	'12'=&gt;'阵雨',
	'13'=&gt;'小雪',
	'14'=&gt;'时有小雪',
	'15'=&gt;'吹雪',
	'16'=&gt;'雪',
	'17'=&gt;'冰雹',
	'18'=&gt;'雨雪',
	'19'=&gt;'沙尘',
	'20'=&gt;'雾',
	'21'=&gt;'霾',
	'22'=&gt;'烟雾',
	'23'=&gt;'劲风',
	'24'=&gt;'大风',
	'25'=&gt;'冷',
	'26'=&gt;'多云',
	'27'=&gt;'晚上多云',
	'28'=&gt;'白天多云',
	'29'=&gt;'晚上局部多云',
	'30'=&gt;'白天局部多云',
	'31'=&gt;'晚上清爽',
	'32'=&gt;'晴天',
	'33'=&gt;'晚上晴朗',
	'34'=&gt;'白天晴朗',
	'35'=&gt;'雨夹冰雹',
	'36'=&gt;'热',
	'37'=&gt;'局部雷雨',
	'38'=&gt;'偶有雷雨',
	'39'=&gt;'偶有雷雨',
	'40'=&gt;'偶有阵雨',
	'41'=&gt;'大雪',
	'42'=&gt;'偶有阵雪',
	'43'=&gt;'大雪',
	'44'=&gt;'部分多云',
	'45'=&gt;'雷阵雨',
	'46'=&gt;'阵雪',
	'47'=&gt;'局部雷阵雨',
	'3200'=&gt;'无法使用'
);

// 根据角度判断风向（wind direction）
function degtodir($wd){
	if(is_numeric($wd))$wd=$wd%360;
	switch(true){
	case(348.75&lt;$wd||$wd&lt;=11.25):return&quot;北&quot;; // N
	case(11.25&lt;$wd&amp;&amp;$wd&lt;=33.75):return&quot;东北偏北&quot;; // NNE
	case(33.75&lt;$wd&amp;&amp;$wd&lt;=56.25):return&quot;东北&quot;; // NE
	case(56.25&lt;$wd&amp;&amp;$wd&lt;=78.75):return&quot;东北偏东&quot;; // ENE
	case(78.75&lt;$wd&amp;&amp;$wd&lt;=101.25):return&quot;东&quot;; // E
	case(101.25&lt;$wd&amp;&amp;$wd&lt;=123.75):return&quot;东南偏东&quot;; // ESE
	case(123.75&lt;$wd&amp;&amp;$wd&lt;=146.25):return&quot;东南&quot;; // SE
	case(146.25&lt;$wd&amp;&amp;$wd&lt;=168.75):return&quot;东南偏南&quot;; // SSE
	case(168.75&lt;$wd&amp;&amp;$wd&lt;=191.25):return&quot;南&quot;; // S
	case(191.25&lt;$wd&amp;&amp;$wd&lt;=213.75):return&quot;西南偏南&quot;; // SSW
	case(213.75&lt;$wd&amp;&amp;$wd&lt;=236.25):return&quot;西南&quot;; // SW
	case(236.25&lt;$wd&amp;&amp;$wd&lt;=258.75):return&quot;西南偏西&quot;; // WSW
	case(258.75&lt;$wd&amp;&amp;$wd&lt;=281.25):return&quot;西&quot;; // W
	case(281.25&lt;$wd&amp;&amp;$wd&lt;=303.75):return&quot;西北偏西&quot;; // WNW
	case(303.75&lt;$wd&amp;&amp;$wd&lt;=326.25):return&quot;西北&quot;; // NW
	case(326.25&lt;$wd&amp;&amp;$wd&lt;=348.75):return&quot;西北偏北&quot;; // NNW
	default:return null;
	}
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.caiguanhao.com/archives/144/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuery：快速汉字转拼音</title>
		<link>http://www.caiguanhao.com/archives/135</link>
		<comments>http://www.caiguanhao.com/archives/135#comments</comments>
		<pubDate>Thu, 29 Dec 2011 08:25:25 +0000</pubDate>
		<dc:creator>caiguanhao</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://www.caiguanhao.com/?p=135</guid>
		<description><![CDATA[首先用正则表达式（/[\u4e00-\u9fa5]/g）找出汉字，然后逐一在汉字列表（simp_chinese_chars）中查找，得出各汉字位于列表的位置（simp_chinese_chars.indexOf(w)），然后通过switch&#8230;case&#8230;得出对应的拼音，再按“Case”选项（switch(options['case'])），输出小写、大写或者首字母大写的写法。因为IE浏览器的问题，会将object里面的case误以为是switch里面的case，所以要将object里面的case加上引号，引用的时候也不能用options.case，而要用options['case']。 得出每个字的拼音后，在通过连字符（options.hyphen）将其连接。得出转换后的字符串之后，再检查标点符号和全角符号，可以选择删除（remove）、转换（replace）或者保留（ignore/reserve）。最后免不了字符串最后的连字符，顺便把它删除掉。因为IE浏览器，所以不能用substr取负数，所以用了slice。 这个插件可以对DOM或者字符串生效。当对象是DOM时，可以按每个DOM执行，然后结果分配给任意其他DOM（设置target），插件会自动检测使用val()还是html()，因为使用val()的只有input、textarea和select。当对象是字符串时就要新建一个prototype，如下： 注意options要加上一个中括号，示意options只是arguments的其中一员。字符串的时候，target也是有效的。 展望：可能会新增其他版本，如包含所有中文字、包含声调的拼音等等。但是代码的大前提还是简洁、快速、优雅。 30日，新增了 jquery-hanzi2pinyin.all.js ，包含了简繁体中文和带声调的拼音，新的DEMO也可以两个版本互换定制。 用法如下： 源代码：jquery-hanzi2pinyin.simp.js 下载hanzi2pinyin.zip On GitHub / DEMO]]></description>
			<content:encoded><![CDATA[<p>首先用正则表达式（/[\u4e00-\u9fa5]/g）找出汉字，然后逐一在汉字列表（simp_chinese_chars）中查找，得出各汉字位于列表的位置（simp_chinese_chars.indexOf(w)），然后通过switch&#8230;case&#8230;得出对应的拼音，再按“Case”选项（switch(options['case'])），输出小写、大写或者首字母大写的写法。因为IE浏览器的问题，会将object里面的case误以为是switch里面的case，所以要将object里面的case加上引号，引用的时候也不能用options.case，而要用options['case']。</p>
<p>得出每个字的拼音后，在通过连字符（options.hyphen）将其连接。得出转换后的字符串之后，再检查标点符号和全角符号，可以选择删除（remove）、转换（replace）或者保留（ignore/reserve）。最后免不了字符串最后的连字符，顺便把它删除掉。因为IE浏览器，所以不能用substr取负数，所以用了slice。</p>
<p>这个插件可以对DOM或者字符串生效。当对象是DOM时，可以按每个DOM执行，然后结果分配给任意其他DOM（设置target），插件会自动检测使用val()还是html()，因为使用val()的只有input、textarea和select。当对象是字符串时就要新建一个prototype，如下：</p>
<pre class="brush: jscript; title: ; notranslate">
String.prototype.hanzi2pinyin=function(options){
	return $.fn.hanzi2pinyin.apply(this,[options]);
};
</pre>
<p>注意options要加上一个中括号，示意options只是arguments的其中一员。字符串的时候，target也是有效的。</p>
<p>展望：可能会新增其他版本，如包含所有中文字、包含声调的拼音等等。但是代码的大前提还是简洁、快速、优雅。</p>
<p>30日，新增了 jquery-hanzi2pinyin.all.js ，包含了简繁体中文和带声调的拼音，新的DEMO也可以两个版本互换定制。</p>
<p>用法如下：</p>
<pre class="brush: jscript; title: ; notranslate">
$('#zh,#case,#hyphen,#pm,#fc').bind('keyup change',function(){
	$('#zh').hanzi2pinyin({
		target: '#py, #py2, #py3, #py4',
		'case': $('#case').val(),
		hyphen: $('#hyphen').val(),
		punctuation_marks: $('#pm').val(),
		fullwidth_chars: $('#fc').val()
	});
	$('#py5').text($('#sh').text().hanzi2pinyin({
		'case': 'proper'
	}));
	$('#code').text(&quot;.hanzi2pinyin({\r\n\ttarget: '',\r\n\t'case': '&quot; + $('#case').val() +
	&quot;',\r\n\thyphen: '&quot; + $('#hyphen').val() + &quot;',\r\n\tpunctuation_marks: '&quot; + $('#pm').val() +
	&quot;',\r\n\tfullwidth_chars: '&quot; + $('#fc').val() + &quot;'\r\n}&quot;);
}).trigger('keyup');
</pre>
<p>源代码：<a href="http://www.caiguanhao.com/hanzi2pinyin/jquery-hanzi2pinyin.simp.js">jquery-hanzi2pinyin.simp.js</a></p>
<p><a href='http://www.caiguanhao.com/thewordpress/wp-content/uploads/2011/12/hanzi2pinyin.zip'>下载hanzi2pinyin.zip</a></p>
<p>On <a href="https://github.com/caiguanhao/jquery-hanzi2pinyin">GitHub</a> / <a href="http://www.caiguanhao.com/hanzi2pinyin/demo.html">DEMO</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.caiguanhao.com/archives/135/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Apache：创建多个站点</title>
		<link>http://www.caiguanhao.com/archives/129</link>
		<comments>http://www.caiguanhao.com/archives/129#comments</comments>
		<pubDate>Sun, 25 Dec 2011 14:38:44 +0000</pubDate>
		<dc:creator>caiguanhao</dc:creator>
				<category><![CDATA[Apache]]></category>

		<guid isPermaLink="false">http://www.caiguanhao.com/?p=129</guid>
		<description><![CDATA[通常在本地计算机上创建网站作测试用时，会遇到诸如 http://localhost/projecta 之类的网址，但如果换用更自由的 http://projecta 不是更好吗？ 设置假的主机名 可以在系统的hosts文件中设置假的主机名，Windows的位于 C:\Windows\System32\drivers\etc，而Linux的位于 /etc/hosts，通过用记事本等编辑文本工具打开并添加： 保存后可以通过 ping 命令查看是否生效。 配置Apache 配置Apache就要打开Apache安装目录下的 httpd.conf 编辑，Windows的可在开始菜单中可以轻易找到一项&#8221;Edit the Apache httpd.conf Configuration File&#8221;，能快速打开该文件。 下面以Windows为例（对于Linux只是路径写法不同），http://localhost/ 将访问位于 D:/projectb 的网站，http://projecta/ 则是访问位于 C:/projecta 的网站，如此类推： 设置完成后，重启Apache服务即可查看是否生效（另外最好同时清理浏览器缓存等内容）。上述内容对于Apache 2.x有效，对于1.x，NameVirtualHost 可省略，&#60;VirtualHost projecta&#62; 可写成 &#60;VirtualHost *&#62;。 参考：Setting Up Multiple Apache Local Web Sites On Your Computer (1.3.x) and 2.0.x Ubuntu/Debian 在Ubuntu/Debian上apache的配置文件分配在多个文件中，包括ports.conf和sites-available文件夹内的文件，所以设置apache会有点不同。 如创建一个网址为http://mysite/的在/home/user/mysite的网站，首先 sudo nautilus /etc/apache2/sites-available ，在sites-available下创建一个文件，以“mysite”命名，输入 [...]]]></description>
			<content:encoded><![CDATA[<p>通常在本地计算机上创建网站作测试用时，会遇到诸如 <code>http://localhost/projecta</code> 之类的网址，但如果换用更自由的 <code>http://projecta</code> 不是更好吗？</p>
<h3>设置假的主机名</h3>
<p>可以在系统的hosts文件中设置假的主机名，Windows的位于 <code>C:\Windows\System32\drivers\etc</code>，而Linux的位于 <code>/etc/hosts</code>，通过用记事本等编辑文本工具打开并添加：</p>
<pre class="brush: plain; title: ; notranslate">
127.0.0.1 projecta
# 诸如此类，每行一个 ...
</pre>
<p>保存后可以通过 <code>ping</code> 命令查看是否生效。</p>
<h3>配置Apache</h3>
<p>配置Apache就要打开Apache安装目录下的 <code>httpd.conf</code> 编辑，Windows的可在开始菜单中可以轻易找到一项&#8221;Edit the Apache httpd.conf Configuration File&#8221;，能快速打开该文件。</p>
<p>下面以Windows为例（对于Linux只是路径写法不同），<code>http://localhost/</code> 将访问位于 <code>D:/projectb</code> 的网站，<code>http://projecta/</code> 则是访问位于 <code>C:/projecta</code> 的网站，如此类推：</p>
<pre class="brush: plain; title: ; notranslate">
&lt;Directory &quot;D:/projectb&quot;&gt;
    Options Indexes FollowSymLinks
    AllowOverride All
    Order allow,deny
    Allow from all
&lt;/Directory&gt;

&lt;Directory &quot;C:/projecta&quot;&gt;
    Options Indexes FollowSymLinks
    AllowOverride All
    Order allow,deny
    Allow from all
&lt;/Directory&gt;

NameVirtualHost 127.0.0.1:*

&lt;VirtualHost projecta&gt;
DocumentRoot &quot;C:/projecta&quot;
ServerName projecta
&lt;/VirtualHost&gt;

&lt;VirtualHost localhost&gt;
DocumentRoot &quot;D:/projectb&quot;
ServerName localhost
&lt;/VirtualHost&gt;
</pre>
<p>设置完成后，重启Apache服务即可查看是否生效（另外最好同时清理浏览器缓存等内容）。上述内容对于Apache 2.x有效，对于1.x，<code>NameVirtualHost</code> 可省略，<code>&lt;VirtualHost projecta&gt;</code> 可写成 <code>&lt;VirtualHost *&gt;</code>。</p>
<p>参考：<a href="http://www.heritage-tech.net/336/setting-up-multiple-apache-local-web-sites-on-your-computer/">Setting Up Multiple Apache Local Web Sites On Your Computer</a> (1.3.x) and <a href="http://www.heritage-tech.net/624/using-local-virtualhosts-on-apache-20x/">2.0.x</a></p>
<h4>Ubuntu/Debian</h4>
<p>在Ubuntu/Debian上apache的配置文件分配在多个文件中，包括ports.conf和sites-available文件夹内的文件，所以设置apache会有点不同。</p>
<p>如创建一个网址为http://mysite/的在/home/user/mysite的网站，首先 <code>sudo nautilus /etc/apache2/sites-available<br />
</code>，在sites-available下创建一个文件，以“mysite”命名，输入</p>
<pre class="brush: plain; title: ; notranslate">
&lt;VirtualHost *:80&gt;
    ServerName mysite
    DocumentRoot /home/user/mysite
    &lt;Directory /home/user/mysite/&gt;
    Options Indexes FollowSymLinks MultiViews
    AllowOverride All
    &lt;/Directory&gt;
&lt;/VirtualHost&gt;
</pre>
<p>打开sites-available的default文件，然后为其定义多一个 <code>ServerName localhost</code>，完成后<code>sudo a2ensite mysite</code>，再用 <code>sudo /etc/init.d/apache2 restart</code> 重启一下。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.caiguanhao.com/archives/129/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>jQuery：繁简转换</title>
		<link>http://www.caiguanhao.com/archives/120</link>
		<comments>http://www.caiguanhao.com/archives/120#comments</comments>
		<pubDate>Mon, 19 Dec 2011 06:46:45 +0000</pubDate>
		<dc:creator>caiguanhao</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://www.caiguanhao.com/?p=120</guid>
		<description><![CDATA[一般JS的繁简转换的原理是列出所有繁简中文字型不同的字，然后在网页注意查找这些字，然后替换掉。当然这样机械式的转换不会转出什么好的结果，如前面的面就会转成面条的面（麵）。 下载simp_trad.zip，包含simp_trad.json]]></description>
			<content:encoded><![CDATA[<p>一般JS的繁简转换的原理是列出所有繁简中文字型不同的字，然后在网页注意查找这些字，然后替换掉。当然这样机械式的转换不会转出什么好的结果，如前面的面就会转成面条的面（麵）。</p>
<pre class="brush: jscript; title: ; notranslate">
//传统的：
var s=&quot;万与丑专业丛东丝丢两严丧个丬丰临为丽举么义乌乐 ... &quot;;
var t=&quot;萬與醜專業叢東絲丟兩嚴喪個爿豐臨為麗舉麼義烏樂 ... &quot;;

//我的做法：

//simp_trad.json：
// {&quot;\u4e07&quot;:&quot;\u842c&quot;,&quot;\u4e0e&quot;:&quot;\u8207&quot;,&quot;\u4e11&quot;:&quot;\u919c&quot;, ... }

//用jQuery：
var dx,dy;
$.getJSON('simp_trad.json',function(d){
	dx=d;
	dy=new Array();
	$.each(d,function(a,b){
		dy[b]=a;
	});
	/* 示例 */
	$('title, body &gt; *').each(function(){
		switch(true){
			case !!$(this).html():
				$(this).html(simp_to_trad($(this).html()));
		}
	});
});
function simp_to_trad(input){
	if(input.match(/[\u4e00-\u9fa5]/g)){
		input=input.replace(/[\u4e00-\u9fa5]/g,function(w){
			return dx[w]||w;
		});
	}
	return input;
}
function trad_to_simp(input){
	if(input.match(/[\u4e00-\u9fa5]/g)){
		input=input.replace(/[\u4e00-\u9fa5]/g,function(w){
			return dy[w]||w;
		});
	}
	return input;
}
</pre>
<p>下载<a href='http://www.caiguanhao.com/thewordpress/wp-content/uploads/2011/12/simp_trad.zip'>simp_trad.zip</a>，包含simp_trad.json</p>
]]></content:encoded>
			<wfw:commentRss>http://www.caiguanhao.com/archives/120/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>krpano+JS：在网页中创建hotspot的思路</title>
		<link>http://www.caiguanhao.com/archives/109</link>
		<comments>http://www.caiguanhao.com/archives/109#comments</comments>
		<pubDate>Fri, 25 Nov 2011 15:50:06 +0000</pubDate>
		<dc:creator>caiguanhao</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[krpano]]></category>

		<guid isPermaLink="false">http://www.caiguanhao.com/?p=109</guid>
		<description><![CDATA[krpano之中默认为虚拟漫游创建hotspot（热点）的工具是一个叫editor.swf的插件，只要在xml文档中添加一行 &#60;plugin name="editor" url="plugins/editor.swf" /&#62; 即可（在虚拟漫游的时候还可以添加 keep="true" 参数）。 这个工具对于少量全景图的，或者不常用作在网上展示的虚拟漫游而言是好的，它的缺点是每次创建hotspot的时候都要选择文件，复制代码时不是只复制hotspot的代码，而是整个xml代码一起复制，而且自动生成的hotspot代码很累赘，一些不常用的参数也列出来，难免遇到麻烦。 特别是在网页程序上，如果靠editor.swf拷贝hotspot的代码，这样做，效率未免太低了。 如果要在一个网上的虚拟漫游管理平台中快速生成hotspot代码，只能通过krpano所支持的Flash和JavaScript之间的交互功能。在网页上可以用JS控制Flash，在Flash上也可以控制网页中的JS行为。 首先，网页上加载了krpano viewer，并且指定了ID（krpanoSWFObject），如 embedpano({swf:"pano.swf", id:"krpanoSWFObject", xml:"pano.xml", target:"pano", wmode:"transparent"}); 并利用全局参数定义 var krpano=$('#krpanoSWFObject')[0]; 这样会方便很多。 当网页要执行创建hotspot的动作，就要用 krpano.call(); 调用 krpano viewer (Flash) 中的函数 addhotspot(); 。 移动newhotspot： 然后可以根据各种参数自定义hotspot，可以简化地得到hotspot代码。上述hla和vla等参数都是可以通过监控krpano相关参数获得。 预览]]></description>
			<content:encoded><![CDATA[<p>krpano之中默认为虚拟漫游创建hotspot（热点）的工具是一个叫editor.swf的插件，只要在xml文档中添加一行 <code>&lt;plugin name="editor" url="plugins/editor.swf" /&gt;</code> 即可（在虚拟漫游的时候还可以添加 <code>keep="true"</code> 参数）。</p>
<p>这个工具对于少量全景图的，或者不常用作在网上展示的虚拟漫游而言是好的，它的缺点是每次创建hotspot的时候都要选择文件，复制代码时不是只复制hotspot的代码，而是整个xml代码一起复制，而且自动生成的hotspot代码很累赘，一些不常用的参数也列出来，难免遇到麻烦。</p>
<p>特别是在网页程序上，如果靠editor.swf拷贝hotspot的代码，这样做，效率未免太低了。</p>
<p><a href="http://www.caiguanhao.com/thewordpress/wp-content/uploads/2011/11/editor_swf.png"><img class="alignnone size-full wp-image-111" title="editor.swf" src="http://www.caiguanhao.com/thewordpress/wp-content/uploads/2011/11/editor_swf.png" alt="" width="507" height="399" /></a></p>
<p>如果要在一个网上的虚拟漫游管理平台中快速生成hotspot代码，只能通过krpano所支持的Flash和JavaScript之间的交互功能。在网页上可以用JS控制Flash，在Flash上也可以控制网页中的JS行为。</p>
<p>首先，网页上加载了krpano viewer，并且指定了ID（krpanoSWFObject），如<br />
<code>embedpano({swf:"pano.swf", id:"krpanoSWFObject", xml:"pano.xml", target:"pano", wmode:"transparent"});</code><br />
并利用全局参数定义 <code>var krpano=$('#krpanoSWFObject')[0];</code> 这样会方便很多。</p>
<p>当网页要执行创建hotspot的动作，就要用 <code>krpano.call();</code> 调用 krpano viewer (Flash) 中的函数 <code>addhotspot();</code> 。</p>
<pre class="brush: jscript; title: ; notranslate">
// 创建一个叫newhotspot的hotspot，然后为newhotspot载入white样式
// white(hotspot_ani_white)是krpano的一个hotspot样式
krpano.call(&quot;addhotspot(newhotspot); hotspot[newhotspot].loadstyle(white)&quot;);

// 初始位置设在 (hla,vla) 的位置
krpano.set(&quot;hotspot[newhotspot].ath&quot;,hla);
krpano.set(&quot;hotspot[newhotspot].atv&quot;,vla);

// 设置鼠标拖动newhotspot的行为，触发网页上的repo()（重新定位）函数
krpano.set(&quot;hotspot[newhotspot].ondown&quot;,&quot;js(repo(1))&quot;);
krpano.set(&quot;hotspot[newhotspot].onup&quot;,&quot;js(repo(0))&quot;);
</pre>
<p>移动newhotspot：</p>
<pre class="brush: jscript; title: ; notranslate">
// repo(1):
// 监控
repoI=setInterval(function(){
	// 鼠标在viewer上的坐标转换为球面坐标
	krpano.call(&quot;screentosphere(mouse.x, mouse.y, mouseath, mouseatv)&quot;);

	// 将newhotspot的坐标设置为球面坐标
	mah=parseFloat(krpano.get('mouseath')%360).toFixed(2);
	mav=parseFloat(krpano.get('mouseatv')).toFixed(2);
	krpano.set(&quot;hotspot[newhotspot].ath&quot;,mah);
	krpano.set(&quot;hotspot[newhotspot].atv&quot;,mav);
},10);

// repo(0):
// 停止监控
clearInterval(repoI);
</pre>
<p>然后可以根据各种参数自定义hotspot，可以简化地得到hotspot代码。上述hla和vla等参数都是可以通过监控krpano相关参数获得。</p>
<p>预览</p>
<p><a href="http://www.caiguanhao.com/thewordpress/wp-content/uploads/2011/11/panomanager-hotspot.png"><img class="alignnone size-large wp-image-115" title="panomanager hotspot" src="http://www.caiguanhao.com/thewordpress/wp-content/uploads/2011/11/panomanager-hotspot-576x380.png" alt="" width="576" height="380" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.caiguanhao.com/archives/109/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

