<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.2.3" -->
<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/"
	>

<channel>
	<title>idv2</title>
	<link>http://tech.idv2.com</link>
	<description>关注Web开发技术，关注Internet。</description>
	<pubDate>Sun, 20 Apr 2008 02:41:01 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.2.3</generator>
	<language>en</language>
			<item>
		<title>制作安全网站的checklist</title>
		<link>http://tech.idv2.com/2008/04/19/secure-website-checklist/</link>
		<comments>http://tech.idv2.com/2008/04/19/secure-website-checklist/#comments</comments>
		<pubDate>Sat, 19 Apr 2008 13:26:19 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
		
		<category><![CDATA[Web开发]]></category>
<category>secure</category><category>web</category><category>xss</category>
		<guid isPermaLink="false">http://tech.idv2.com/2008/04/19/secure-website-checklist/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p><a href="http://www.fcicq.net/wp">fcicq</a>最近在<a href="http://www.ipa.go.jp">IPA</a>上看到一篇安全相关的文章，
它的最末尾有个checklist，于是催我把它翻译了。前几天比较忙，周末没什么事儿了，就翻译一下吧。</p>
<p><a href="http://www.ipa.go.jp/security/english/benchmark_system.html">原文</a>的标题是<strong>如何让网站更安全</strong>。
这里仅翻译文章最后的一个checklist。</p>
<p><strong>2008/4/20更新：</strong>fcicq倒是神速啊，马上就把具体的应用策略扔出来了 <img alt=":D" src="images/face/bigsmile.png" />
参考：<a href="http://www.fcicq.net/wp/?p=612">PHP 实践 Security Checklist</a></p>
<!-- end Pukiwiki generated code--><!-- begin Pukiwiki generated code--><p>标有 (*) 的检查项目表示该项是针对相关问题的根本解决方法，应当尽最大努力去完成这些内容。
未标 (*) 的项目，表示该项并不能完全消除安全隐患，只是说通过这种方法可以避免发生安全问题。
最后一条似乎没什么意思，不翻译了。</p>
<ol class="list1" style="padding-left:16px;margin-left:16px"><li>SQL注射
<ol class="list2" style="padding-left:16px;margin-left:16px"><li>(*) 在组合SQL语句时要使用SQL变量绑定功能</li>
<li>(*) 如果数据库不提供变量绑定，那么需要对构成SQL的所有变量进行转义</li>
<li>不要将错误信息原封不动地显示在浏览器中。</li>
<li>为访问数据库的用户设置适当的权限。</li></ol></li>
<li>操作系统命令行注射
<ol class="list2" style="padding-left:16px;margin-left:16px"><li>(*) 避免使用能启动shell命令的语言</li>
<li>使用的语言如果允许启动shell命令，则需要对该功能的参数种的所有变量进行检查，确保只包含合法的操作</li></ol></li>
<li>不检查路径名参数/目录遍历
<ol class="list2" style="padding-left:16px;margin-left:16px"><li>(*) 不要将外部传进来的参数直接作为文件名来使用</li>
<li>(*) 将打开文件的操作限制在固定的目录中，并禁止文件名中包含路径</li>
<li>为Web服务器上的文件设置正确的访问权限</li>
<li>检查文件名</li></ol></li>
<li>会话管理的问题
<ol class="list2" style="padding-left:16px;margin-left:16px"><li>(*) 用难以推测的内容作为会话ID</li>
<li>(*) 不要在URL中保存会话ID</li>
<li>(*) 为https协议中使用的cookie设置secure属性</li>
<li>(*) 登录成功后生成新的会话</li>
<li>(*) 登录成功后，在会话ID之外再生成一个秘密信息，每次访问页面时都检查之</li>
<li>不使用固定值作为会话ID</li>
<li>将会话ID保存到Cookie中时，要设置有效期限</li></ol></li>
<li>跨站脚本攻击(XSS)
<ul class="list2" style="padding-left:16px;margin-left:16px"><li>不允许输入HTML内容时的解决方法
<ol class="list3" style="padding-left:16px;margin-left:16px"><li>(*) 输出到页面上的所有内容都要转义</li>
<li>(*) 输出URL时仅允许以“http://”或“https://”开头的URL</li>
<li>(*) 不要动态生成&lt;script&gt;...&lt;/script&gt;的内容</li>
<li>(*) 不要从外部网站读入样式表</li>
<li>检查输入内容</li></ol></li>
<li>允许输入HTML内容时的解决方法
<ol class="list3" style="padding-left:16px;margin-left:16px"><li>(*) 解析输入的HTML内容，生成解析树，然后提取其中的非脚本部分</li>
<li>使用脚本删除输入的HTML内容中的相关字符串</li></ol></li>
<li>通用解决方法
<ol class="list3" style="padding-left:16px;margin-left:16px"><li>(*) 应答的HTTP头重指定Content-Type的charset属性</li>
<li>为避免Cookie情报泄漏，应禁止Trace方法，并对所有Cookie设置HttpOnly属性</li></ol></li></ul></li>
<li>跨站请求伪造(CSRF)
<ol class="list2" style="padding-left:16px;margin-left:16px"><li>(*) 所有页面都通过POST来访问，在前一页面的hidden中随机生成一个信息，提交后的页面检查该信息，正确时才予以执行</li>
<li>(*) 执行业务之前再次要求输入密码</li>
<li>(*) 确认Referer是否正确，只有正确时才执行</li>
<li>执行重要操作时，向预先设置的邮件地址中发送邮件</li></ol></li>
<li>HTTP头注射
<ol class="list2" style="padding-left:16px;margin-left:16px"><li>(*) 不直接输出HTTP头，而使用运行环境提供的头信息输出API</li>
<li>(*) 无法使用API时，要禁止输入的头信息中的换行</li>
<li>删除所有外部输入中的换行</li></ol></li>
<li>邮件盗用(通过某种手段使邮件发送到攻击者指定的地址)
<ol class="list2" style="padding-left:16px;margin-left:16px"><li>(*) 不使用外部参数作为邮件头信息</li>
<li>必须用外部参数设置头信息时，要删除其中的危险字符。</li></ol></li></ol>
<!-- end Pukiwiki generated code-->

]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p><a href="http://www.fcicq.net/wp">fcicq</a>最近在<a href="http://www.ipa.go.jp">IPA</a>上看到一篇安全相关的文章，
它的最末尾有个checklist，于是催我把它翻译了。前几天比较忙，周末没什么事儿了，就翻译一下吧。</p>
<p><a href="http://www.ipa.go.jp/security/english/benchmark_system.html">原文</a>的标题是<strong>如何让网站更安全</strong>。
这里仅翻译文章最后的一个checklist。</p>
<p><strong>2008/4/20更新：</strong>fcicq倒是神速啊，马上就把具体的应用策略扔出来了 <img alt=":D" src="images/face/bigsmile.png" />
参考：<a href="http://www.fcicq.net/wp/?p=612">PHP 实践 Security Checklist</a></p>
<!-- end Pukiwiki generated code--><!-- begin Pukiwiki generated code--><p>标有 (*) 的检查项目表示该项是针对相关问题的根本解决方法，应当尽最大努力去完成这些内容。
未标 (*) 的项目，表示该项并不能完全消除安全隐患，只是说通过这种方法可以避免发生安全问题。
最后一条似乎没什么意思，不翻译了。</p>
<ol class="list1" style="padding-left:16px;margin-left:16px"><li>SQL注射
<ol class="list2" style="padding-left:16px;margin-left:16px"><li>(*) 在组合SQL语句时要使用SQL变量绑定功能</li>
<li>(*) 如果数据库不提供变量绑定，那么需要对构成SQL的所有变量进行转义</li>
<li>不要将错误信息原封不动地显示在浏览器中。</li>
<li>为访问数据库的用户设置适当的权限。</li></ol></li>
<li>操作系统命令行注射
<ol class="list2" style="padding-left:16px;margin-left:16px"><li>(*) 避免使用能启动shell命令的语言</li>
<li>使用的语言如果允许启动shell命令，则需要对该功能的参数种的所有变量进行检查，确保只包含合法的操作</li></ol></li>
<li>不检查路径名参数/目录遍历
<ol class="list2" style="padding-left:16px;margin-left:16px"><li>(*) 不要将外部传进来的参数直接作为文件名来使用</li>
<li>(*) 将打开文件的操作限制在固定的目录中，并禁止文件名中包含路径</li>
<li>为Web服务器上的文件设置正确的访问权限</li>
<li>检查文件名</li></ol></li>
<li>会话管理的问题
<ol class="list2" style="padding-left:16px;margin-left:16px"><li>(*) 用难以推测的内容作为会话ID</li>
<li>(*) 不要在URL中保存会话ID</li>
<li>(*) 为https协议中使用的cookie设置secure属性</li>
<li>(*) 登录成功后生成新的会话</li>
<li>(*) 登录成功后，在会话ID之外再生成一个秘密信息，每次访问页面时都检查之</li>
<li>不使用固定值作为会话ID</li>
<li>将会话ID保存到Cookie中时，要设置有效期限</li></ol></li>
<li>跨站脚本攻击(XSS)
<ul class="list2" style="padding-left:16px;margin-left:16px"><li>不允许输入HTML内容时的解决方法
<ol class="list3" style="padding-left:16px;margin-left:16px"><li>(*) 输出到页面上的所有内容都要转义</li>
<li>(*) 输出URL时仅允许以“http://”或“https://”开头的URL</li>
<li>(*) 不要动态生成&lt;script&gt;...&lt;/script&gt;的内容</li>
<li>(*) 不要从外部网站读入样式表</li>
<li>检查输入内容</li></ol></li>
<li>允许输入HTML内容时的解决方法
<ol class="list3" style="padding-left:16px;margin-left:16px"><li>(*) 解析输入的HTML内容，生成解析树，然后提取其中的非脚本部分</li>
<li>使用脚本删除输入的HTML内容中的相关字符串</li></ol></li>
<li>通用解决方法
<ol class="list3" style="padding-left:16px;margin-left:16px"><li>(*) 应答的HTTP头重指定Content-Type的charset属性</li>
<li>为避免Cookie情报泄漏，应禁止Trace方法，并对所有Cookie设置HttpOnly属性</li></ol></li></ul></li>
<li>跨站请求伪造(CSRF)
<ol class="list2" style="padding-left:16px;margin-left:16px"><li>(*) 所有页面都通过POST来访问，在前一页面的hidden中随机生成一个信息，提交后的页面检查该信息，正确时才予以执行</li>
<li>(*) 执行业务之前再次要求输入密码</li>
<li>(*) 确认Referer是否正确，只有正确时才执行</li>
<li>执行重要操作时，向预先设置的邮件地址中发送邮件</li></ol></li>
<li>HTTP头注射
<ol class="list2" style="padding-left:16px;margin-left:16px"><li>(*) 不直接输出HTTP头，而使用运行环境提供的头信息输出API</li>
<li>(*) 无法使用API时，要禁止输入的头信息中的换行</li>
<li>删除所有外部输入中的换行</li></ol></li>
<li>邮件盗用(通过某种手段使邮件发送到攻击者指定的地址)
<ol class="list2" style="padding-left:16px;margin-left:16px"><li>(*) 不使用外部参数作为邮件头信息</li>
<li>必须用外部参数设置头信息时，要删除其中的危险字符。</li></ol></li></ol>
<!-- end Pukiwiki generated code-->
<br />
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2008/04/19/secure-website-checklist/feed/</wfw:commentRss>
		</item>
		<item>
		<title>[PBP]代码布局(4)</title>
		<link>http://tech.idv2.com/2008/03/27/pbp-code-layout-4/</link>
		<comments>http://tech.idv2.com/2008/03/27/pbp-code-layout-4/#comments</comments>
		<pubDate>Thu, 27 Mar 2008 13:30:16 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
		
		<category><![CDATA[Perl编程]]></category>
<category>pbp</category><category>perl</category>
		<guid isPermaLink="false">http://tech.idv2.com/2008/03/27/pbp-code-layout-4/</guid>
		<description><![CDATA[今天继续翻译代码布局的这一部分。有些很明显的条目，就不翻译了，看看代码就应该明白是什么意思。<!-- begin Pukiwiki generated code--><div class="contents">
<a id="contents_5"></a>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li><a href="#content_5_0">  2.13 段落</a></li>
<li><a href="#content_5_1">  2.14 Else语句</a></li>
<li><a href="#content_5_2">  2.15 垂直对齐</a></li>
<li><a href="#content_5_3">  2.16 截断过长的行</a></li>
<li><a href="#content_5_4">  2.17 不在结尾的表达式</a></li></ul>
</div>

<h2 id="content_5_0">2.13 段落</h2>
<p><strong>代码要分段。</strong></p>
<p>段落就是完成特定任务的语句的集合。文学上的段落是表达一个观点的一些句子，而编程中的段落则是完成算法的一步的语句。</p>
<p>应当将代码分段，然后在各个段落之间加一个空行。另外，在每段的开始处添加一行注释可以增加可读性。</p>

<h2 id="content_5_1">2.14 Else语句</h2>
<p><strong>别拥抱else。</strong></p>
<p>所谓的“拥抱”是指下面这个样子：</p>
<pre>} else {</pre>
<p>而“不拥抱”则为：</p>
<pre>}
else {</pre>
<p>“拥抱”能节省一行，但它从另一个方面降低了代码的可读性。被“拥抱”的else和相应的if以及结束括号不在同一列上，较难辩认。</p>
<p>更重要的是，else本意是区分出动作的另一方面，而“拥抱”会降低这种区别。</p>
<p>此外，将else单独写在一行，你可以很轻易地复制else部分，而不用担心多复制括号。</p>

<h2 id="content_5_2">2.15 垂直对齐</h2>
<p><strong>将同类的项目垂直对齐。</strong></p>
<p>这一条好像没有什么必要去翻译了，大家都能看明白。</p>
<pre>my @months = qw(
    January   February   March
    April     May        June
    July      August     September
    October   November   December
);

my %expansion_of = (
    q{it's}    =&gt; q{it is},
    q{we're}   =&gt; q{we are},
    q{didn't}  =&gt; q{did not},
    q{must've} =&gt; q{must have},
    q{I'll}    =&gt; q{I will},
);</pre>

<h2 id="content_5_3">2.16 截断过长的行</h2>
<p><strong>在运算符之前断行。</strong></p>
<p>当表达式过长时，人们通常喜欢在运算符之后断行，并为第二行之后的部分添加一层缩进。如：</p>
<pre>push @steps, $steps[-1] +
    $radial_velocity * $elapsed_time +
    $orbital_velocity * ($phase + $phase_shift) -
    $DRAG_COEFF * $altitude;</pre>
<p>其理由是，行尾的运算符看起来像一个“连续行”的标记，
暗示着这一行并未结束。</p>
<p>这个想法的确不错，但有个很严重的问题。人们很少去注意一行的最右端。
程序中绝大部分提示语义的元素（如关键字）都写在一行的左侧。
更为重要的是，代码的结构暗示——如缩进——也占据了左侧这个最重要的位置。
表达式第二行之后的缩进很容易给人造成错觉。</p>
<p>解决方法之一，就是在运算符之前断行。这样能保证接下来的每一行都以运算符开始，
与Perl中其他的代码迥然不同，这样读者看到这一行马上就能意识到它是前一行未结束的部分。</p>
<p>第二行之后的缩进也很重要。不应简单地缩进一层，而是应当与表达式的起始列对齐。
这样最终的代码如下所示：</p>
<pre>push @steps, $steps[-1]
             + $radial_velocity * $elapsed_time
             + $orbital_velocity * ($phase + $phase_shift)
             - $DRAG_COEFF * $altitude
             ;</pre>
<p>这种格式能从视觉上很好地区分开push的两个参数。</p>

<h2 id="content_5_4">2.17 不在结尾的表达式</h2>
<p><strong>对语句中间的表达式进行重构。</strong></p>
<p>上一条仅适用于表达式位于语句结尾的情况。如果表达式出现在语句的中间，
那么最好对其进行重构，将表达式赋给另一个变量。例如：</p>
<pre>my $next_step = $steps[-1]
                + $radial_velocity * $elapsed_time
                + $orbital_velocity * ($phase + $phase_shift)
                - $DRAG_COEFF * $altitude
                ;
add_step( \@steps, $next_step, $elapsed_time);</pre>
<p>这种写法要远远好于下面这种写法：</p>
<pre>add_step( \@steps, $steps[-1]
                   + $radial_velocity * $elapsed_time
                   + $orbital_velocity * ($phase + $phase_shift)
                   - $DRAG_COEFF * $altitude
                   , $elapsed_time);</pre>
<!-- end Pukiwiki generated code-->

]]></description>
			<content:encoded><![CDATA[今天继续翻译代码布局的这一部分。有些很明显的条目，就不翻译了，看看代码就应该明白是什么意思。<!-- begin Pukiwiki generated code--><div class="contents">
<a id="contents_6"></a>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li><a href="#content_6_0">  2.13 段落</a></li>
<li><a href="#content_6_1">  2.14 Else语句</a></li>
<li><a href="#content_6_2">  2.15 垂直对齐</a></li>
<li><a href="#content_6_3">  2.16 截断过长的行</a></li>
<li><a href="#content_6_4">  2.17 不在结尾的表达式</a></li></ul>
</div>

<h2 id="content_6_0">2.13 段落</h2>
<p><strong>代码要分段。</strong></p>
<p>段落就是完成特定任务的语句的集合。文学上的段落是表达一个观点的一些句子，而编程中的段落则是完成算法的一步的语句。</p>
<p>应当将代码分段，然后在各个段落之间加一个空行。另外，在每段的开始处添加一行注释可以增加可读性。</p>

<h2 id="content_6_1">2.14 Else语句</h2>
<p><strong>别拥抱else。</strong></p>
<p>所谓的“拥抱”是指下面这个样子：</p>
<pre>} else {</pre>
<p>而“不拥抱”则为：</p>
<pre>}
else {</pre>
<p>“拥抱”能节省一行，但它从另一个方面降低了代码的可读性。被“拥抱”的else和相应的if以及结束括号不在同一列上，较难辩认。</p>
<p>更重要的是，else本意是区分出动作的另一方面，而“拥抱”会降低这种区别。</p>
<p>此外，将else单独写在一行，你可以很轻易地复制else部分，而不用担心多复制括号。</p>

<h2 id="content_6_2">2.15 垂直对齐</h2>
<p><strong>将同类的项目垂直对齐。</strong></p>
<p>这一条好像没有什么必要去翻译了，大家都能看明白。</p>
<pre>my @months = qw(
    January   February   March
    April     May        June
    July      August     September
    October   November   December
);

my %expansion_of = (
    q{it's}    =&gt; q{it is},
    q{we're}   =&gt; q{we are},
    q{didn't}  =&gt; q{did not},
    q{must've} =&gt; q{must have},
    q{I'll}    =&gt; q{I will},
);</pre>

<h2 id="content_6_3">2.16 截断过长的行</h2>
<p><strong>在运算符之前断行。</strong></p>
<p>当表达式过长时，人们通常喜欢在运算符之后断行，并为第二行之后的部分添加一层缩进。如：</p>
<pre>push @steps, $steps[-1] +
    $radial_velocity * $elapsed_time +
    $orbital_velocity * ($phase + $phase_shift) -
    $DRAG_COEFF * $altitude;</pre>
<p>其理由是，行尾的运算符看起来像一个“连续行”的标记，
暗示着这一行并未结束。</p>
<p>这个想法的确不错，但有个很严重的问题。人们很少去注意一行的最右端。
程序中绝大部分提示语义的元素（如关键字）都写在一行的左侧。
更为重要的是，代码的结构暗示——如缩进——也占据了左侧这个最重要的位置。
表达式第二行之后的缩进很容易给人造成错觉。</p>
<p>解决方法之一，就是在运算符之前断行。这样能保证接下来的每一行都以运算符开始，
与Perl中其他的代码迥然不同，这样读者看到这一行马上就能意识到它是前一行未结束的部分。</p>
<p>第二行之后的缩进也很重要。不应简单地缩进一层，而是应当与表达式的起始列对齐。
这样最终的代码如下所示：</p>
<pre>push @steps, $steps[-1]
             + $radial_velocity * $elapsed_time
             + $orbital_velocity * ($phase + $phase_shift)
             - $DRAG_COEFF * $altitude
             ;</pre>
<p>这种格式能从视觉上很好地区分开push的两个参数。</p>

<h2 id="content_6_4">2.17 不在结尾的表达式</h2>
<p><strong>对语句中间的表达式进行重构。</strong></p>
<p>上一条仅适用于表达式位于语句结尾的情况。如果表达式出现在语句的中间，
那么最好对其进行重构，将表达式赋给另一个变量。例如：</p>
<pre>my $next_step = $steps[-1]
                + $radial_velocity * $elapsed_time
                + $orbital_velocity * ($phase + $phase_shift)
                - $DRAG_COEFF * $altitude
                ;
add_step( \@steps, $next_step, $elapsed_time);</pre>
<p>这种写法要远远好于下面这种写法：</p>
<pre>add_step( \@steps, $steps[-1]
                   + $radial_velocity * $elapsed_time
                   + $orbital_velocity * ($phase + $phase_shift)
                   - $DRAG_COEFF * $altitude
                   , $elapsed_time);</pre>
<!-- end Pukiwiki generated code-->
<br />
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2008/03/27/pbp-code-layout-4/feed/</wfw:commentRss>
		</item>
		<item>
		<title>[CSS]如何使用margin和padding？</title>
		<link>http://tech.idv2.com/2008/03/20/css-margin-padding/</link>
		<comments>http://tech.idv2.com/2008/03/20/css-margin-padding/#comments</comments>
		<pubDate>Wed, 19 Mar 2008 16:18:51 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
		
		<category><![CDATA[Web开发]]></category>
<category>css</category><category>design</category>
		<guid isPermaLink="false">http://tech.idv2.com/2008/03/20/css-margin-padding/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p>margin和padding的意义相信大家都很清楚，可是在具体应用中，
到底应该使用哪一个，就比较难于判断了。
<a href="http://coliss.com/articles/build-websites/operation/css/901.html">这篇文章</a>
说得挺清楚的，在这里翻译一下，供参考。</p>
<p><strong>何时应当使用margin</strong></p>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li>需要在border外侧添加空白时。</li>
<li>空白处不需要背景（色）时。</li>
<li>上下相连的两个盒子之间的空白，需要相互抵消时。如15px + 20px的margin，将得到20px的空白。</li></ul>
<p><strong>何时应当时用padding</strong></p>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li>需要在border内测添加空白时。</li>
<li>空白处需要背景（色）时。</li>
<li>上下相连的两个盒子之间的空白，希望等于两者之和时。如15px + 20px的padding，将得到35px的空白。</li></ul>
<p><strong>浏览器兼容性问题</strong></p>
<p>在IE 5.x、IE6中，为float的盒子指定margin时，左侧margin可能会变成两倍的宽度。
通过改用padding或指定盒子为display:inline可以解决。</p>
<!-- end Pukiwiki generated code-->

]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p>margin和padding的意义相信大家都很清楚，可是在具体应用中，
到底应该使用哪一个，就比较难于判断了。
<a href="http://coliss.com/articles/build-websites/operation/css/901.html">这篇文章</a>
说得挺清楚的，在这里翻译一下，供参考。</p>
<p><strong>何时应当使用margin</strong></p>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li>需要在border外侧添加空白时。</li>
<li>空白处不需要背景（色）时。</li>
<li>上下相连的两个盒子之间的空白，需要相互抵消时。如15px + 20px的margin，将得到20px的空白。</li></ul>
<p><strong>何时应当时用padding</strong></p>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li>需要在border内测添加空白时。</li>
<li>空白处需要背景（色）时。</li>
<li>上下相连的两个盒子之间的空白，希望等于两者之和时。如15px + 20px的padding，将得到35px的空白。</li></ul>
<p><strong>浏览器兼容性问题</strong></p>
<p>在IE 5.x、IE6中，为float的盒子指定margin时，左侧margin可能会变成两倍的宽度。
通过改用padding或指定盒子为display:inline可以解决。</p>
<!-- end Pukiwiki generated code-->
<br />
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2008/03/20/css-margin-padding/feed/</wfw:commentRss>
		</item>
		<item>
		<title>[Perl]认清上下文环境</title>
		<link>http://tech.idv2.com/2008/03/18/perl-context-env/</link>
		<comments>http://tech.idv2.com/2008/03/18/perl-context-env/#comments</comments>
		<pubDate>Mon, 17 Mar 2008 16:33:12 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
		
		<category><![CDATA[Perl编程]]></category>
<category>perl</category>
		<guid isPermaLink="false">http://tech.idv2.com/2008/03/18/perl-context-env/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p>今天在写代码时遇到一个很奇怪的问题。我写的这样一个函数：</p>
<pre>sub parse {
  my $self = shift;
  my $header = shift;
  my $charset = shift;
  
  # 其它处理
  # ...
}</pre>
<p>至于如何调用，则是先通过 MIME::Parser 模块解析邮件，
然后调用解析结果中的 MIME::Head::get 函数来获得邮件头的值，
再将其结果传递给 parse 函数：</p>
<pre>print $self-&gt;parse($head-&gt;get(&quot;Cc&quot;), &quot;GB2312&quot;);</pre>
<p>通常都没有问题，在parse函数中，$header取到 Cc 邮件头，而 $charset 取到 &quot;GB2312&quot;；
但当一封邮件中不存在Cc时，就会出现一件怪事：
$header 变量竟然取到了第二个参数 &quot;GB2312&quot; 的值！</p>
<p>在 parse 中将 @_ 打出来，发现当Cc邮件头取不到时，第一个参数就“消失”了，
参数列表就变成了 (&quot;GB2312&quot;)。按照常理，参数列表应该是 (undef, &quot;GB2312&quot;)才对啊。</p>
<p>百思不得其解中，偶然看到 MIME::Head::get 的文档中这样说：</p>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li>If a numeric INDEX is given, returns the occurence at that index, or undef if not present:</li>
<li>If no INDEX is given, but invoked in a scalar context, then INDEX simply defaults to 0:</li>
<li>If no INDEX is given, and invoked in an array context, then all occurences of the field are returned:</li></ul>
<p>上面的调用属于没有 INDEX 的情况，莫非parse函数的参数列表提供了一个列表环境，
导致MIME::Head::get返回了一个数组？</p>
<p>于是强制为它提供一个标量环境，结果就正常地得到了 (undef, &quot;GB2312&quot;)。</p>
<pre>print $self-&gt;parse(scalar $head-&gt;get(&quot;Cc&quot;), &quot;GB2312&quot;);</pre>
<p>看来果然是上下文环境造成的问题。parse函数的第一个参数期待一个常量，
而函数的参数列表却是一个列表环境，再加上MIME::Head::get在列表环境中返回数组，
这样就会导致两种错误：</p>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li>如果不存在Cc，则参数列表为(&quot;GB2312&quot;)，$header = &quot;GB2312&quot;；</li>
<li>如果存在多个Cc，则参数列表为(&quot;Cc-val1&quot;, &quot;Cc-val2&quot;, &quot;Cc-val3&quot;, &quot;GB2312&quot;), $charset=&quot;Cc-val2&quot;。</li></ul>
<p>两种情况都十分荒谬。</p>
<p>对Perl的上下文不熟悉的人，这里可要特别注意啊。</p>
<!-- end Pukiwiki generated code-->

]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p>今天在写代码时遇到一个很奇怪的问题。我写的这样一个函数：</p>
<pre>sub parse {
  my $self = shift;
  my $header = shift;
  my $charset = shift;
  
  # 其它处理
  # ...
}</pre>
<p>至于如何调用，则是先通过 MIME::Parser 模块解析邮件，
然后调用解析结果中的 MIME::Head::get 函数来获得邮件头的值，
再将其结果传递给 parse 函数：</p>
<pre>print $self-&gt;parse($head-&gt;get(&quot;Cc&quot;), &quot;GB2312&quot;);</pre>
<p>通常都没有问题，在parse函数中，$header取到 Cc 邮件头，而 $charset 取到 &quot;GB2312&quot;；
但当一封邮件中不存在Cc时，就会出现一件怪事：
$header 变量竟然取到了第二个参数 &quot;GB2312&quot; 的值！</p>
<p>在 parse 中将 @_ 打出来，发现当Cc邮件头取不到时，第一个参数就“消失”了，
参数列表就变成了 (&quot;GB2312&quot;)。按照常理，参数列表应该是 (undef, &quot;GB2312&quot;)才对啊。</p>
<p>百思不得其解中，偶然看到 MIME::Head::get 的文档中这样说：</p>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li>If a numeric INDEX is given, returns the occurence at that index, or undef if not present:</li>
<li>If no INDEX is given, but invoked in a scalar context, then INDEX simply defaults to 0:</li>
<li>If no INDEX is given, and invoked in an array context, then all occurences of the field are returned:</li></ul>
<p>上面的调用属于没有 INDEX 的情况，莫非parse函数的参数列表提供了一个列表环境，
导致MIME::Head::get返回了一个数组？</p>
<p>于是强制为它提供一个标量环境，结果就正常地得到了 (undef, &quot;GB2312&quot;)。</p>
<pre>print $self-&gt;parse(scalar $head-&gt;get(&quot;Cc&quot;), &quot;GB2312&quot;);</pre>
<p>看来果然是上下文环境造成的问题。parse函数的第一个参数期待一个常量，
而函数的参数列表却是一个列表环境，再加上MIME::Head::get在列表环境中返回数组，
这样就会导致两种错误：</p>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li>如果不存在Cc，则参数列表为(&quot;GB2312&quot;)，$header = &quot;GB2312&quot;；</li>
<li>如果存在多个Cc，则参数列表为(&quot;Cc-val1&quot;, &quot;Cc-val2&quot;, &quot;Cc-val3&quot;, &quot;GB2312&quot;), $charset=&quot;Cc-val2&quot;。</li></ul>
<p>两种情况都十分荒谬。</p>
<p>对Perl的上下文不熟悉的人，这里可要特别注意啊。</p>
<!-- end Pukiwiki generated code-->
<br />
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2008/03/18/perl-context-env/feed/</wfw:commentRss>
		</item>
		<item>
		<title>[PBP]代码布局(3)</title>
		<link>http://tech.idv2.com/2008/03/11/pbp-code-layout-3/</link>
		<comments>http://tech.idv2.com/2008/03/11/pbp-code-layout-3/#comments</comments>
		<pubDate>Mon, 10 Mar 2008 16:54:31 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
		
		<category><![CDATA[Perl编程]]></category>
<category>pbp</category><category>perl</category>
		<guid isPermaLink="false">http://tech.idv2.com/2008/03/11/pbp-code-layout-3/</guid>
		<description><![CDATA[继续翻译Perl最佳实践的2.9～2.12。<!-- begin Pukiwiki generated code--><div class="contents">
<a id="contents_11"></a>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li><a href="#content_11_0">  2.9 行长度</a></li>
<li><a href="#content_11_1">  2.10 缩进</a></li>
<li><a href="#content_11_2">  2.11 制表符(Tab)</a></li>
<li><a href="#content_11_3">  2.12 代码块</a></li></ul>
</div>

<hr class="full_hr" />
<h2 id="content_11_0">2.9 行长度</h2>
<p><strong>保持行长度为78字符。</strong></p>
<p>虽然以现在的高分辨率显示器已完全可以在一行中显示300个字符，
但还是建议保持每行不超过78个字符。
这不仅仅是出于显示上的考虑，更为重要的一个理由是，
通过邮件发送代码片段时，78字符的行长度可以保证在回复邮件时
代码不至于被换行。</p>
<p>在vi中可以设置以下选项，使其自动换行：</p>
<pre>set textwidth=78</pre>
<p>在Emacs中可以用以下命令达到同样目的：</p>
<pre>(setq fill-column 78)
(setq auto-fill-mode t)</pre>

<h2 id="content_11_1">2.10 缩进</h2>
<p><strong>使用四列的缩进。</strong></p>
<p>对于缩进的争论更多，不同的程序员会给出不同的答案：2、3、4或者8列。</p>
<p>早期的大牛们倾向于使用8列的缩进，理由是许多打印机和终端的默认TAB宽度
仍为8字符，因此使用8字符缩进可以保证在任何地方看到的效果都一样。</p>
<p>但是的确（年轻人们会这样想），8列的缩进非常难看，并且很难阅读。
他们觉得缩进不能超过2到3个字符。小的缩进可以在有限的显示器上显示更多层次的
嵌套；也能减少阅读时视线水平移动的距离。</p>
<p>但问题是，过小的缩进对于上年纪和视力不好的人来说，很难用肉眼
分辨出缩进的层次。</p>
<p>最合适的缩进宽度还是4列，对于两种人来说都是个能够接受的平衡点吧。</p>

<h2 id="content_11_2">2.11 制表符(Tab)</h2>
<p><strong>使用空格缩进，不要用Tab。</strong></p>
<p>Tab不适合用于缩进，即使你已经设置编辑器的Tab宽度为4列。
Tab在打印时与显示时的效果不同（打印时通常会变成8列宽），
另外将代码粘贴到字处理程序（如Word）中时也是如此。
甚至在其他人的编辑器上查看代码时，如果他的Tab设置与你不同，
看到的效果也不一样。</p>
<p>所以不要使用Tab键进行缩进，至少不要同时混合使用Tab和空格。</p>

<h2 id="content_11_3">2.12 代码块</h2>
<p><strong>不要在一行中书写两条语句。</strong></p>
<p>一行写两条或多条语句，会非常难于理解：</p>
<pre>RECORD:
while (my $record = &lt;$inventory_file&gt;) {
    chomp $record; next RECORD if $record eq $EMPTY_STR;
    my @fields = split $FIELD_SEPARATOR, $record; update_sales(\@fields);$count++;
}</pre>
<p>你已经通过K&amp;R括号风格节约了许多空间了，把这些空间用在增强代码可读性上吧：</p>
<pre>RECORD:
while (my $record = &lt;$inventory_file&gt;) {
    chomp $record;
    next RECORD if $record eq $EMPTY_STR;
    my @fields = split $FIELD_SEPARATOR, $record;
    update_sales(\@fields);
    $count++;
}</pre>
<p>即使是 map 或 grep 内部的语句，如果超过一条语句，那么也应该写在各自独立的行上。</p>
<!-- end Pukiwiki generated code-->

]]></description>
			<content:encoded><![CDATA[继续翻译Perl最佳实践的2.9～2.12。<!-- begin Pukiwiki generated code--><div class="contents">
<a id="contents_12"></a>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li><a href="#content_12_0">  2.9 行长度</a></li>
<li><a href="#content_12_1">  2.10 缩进</a></li>
<li><a href="#content_12_2">  2.11 制表符(Tab)</a></li>
<li><a href="#content_12_3">  2.12 代码块</a></li></ul>
</div>

<hr class="full_hr" />
<h2 id="content_12_0">2.9 行长度</h2>
<p><strong>保持行长度为78字符。</strong></p>
<p>虽然以现在的高分辨率显示器已完全可以在一行中显示300个字符，
但还是建议保持每行不超过78个字符。
这不仅仅是出于显示上的考虑，更为重要的一个理由是，
通过邮件发送代码片段时，78字符的行长度可以保证在回复邮件时
代码不至于被换行。</p>
<p>在vi中可以设置以下选项，使其自动换行：</p>
<pre>set textwidth=78</pre>
<p>在Emacs中可以用以下命令达到同样目的：</p>
<pre>(setq fill-column 78)
(setq auto-fill-mode t)</pre>

<h2 id="content_12_1">2.10 缩进</h2>
<p><strong>使用四列的缩进。</strong></p>
<p>对于缩进的争论更多，不同的程序员会给出不同的答案：2、3、4或者8列。</p>
<p>早期的大牛们倾向于使用8列的缩进，理由是许多打印机和终端的默认TAB宽度
仍为8字符，因此使用8字符缩进可以保证在任何地方看到的效果都一样。</p>
<p>但是的确（年轻人们会这样想），8列的缩进非常难看，并且很难阅读。
他们觉得缩进不能超过2到3个字符。小的缩进可以在有限的显示器上显示更多层次的
嵌套；也能减少阅读时视线水平移动的距离。</p>
<p>但问题是，过小的缩进对于上年纪和视力不好的人来说，很难用肉眼
分辨出缩进的层次。</p>
<p>最合适的缩进宽度还是4列，对于两种人来说都是个能够接受的平衡点吧。</p>

<h2 id="content_12_2">2.11 制表符(Tab)</h2>
<p><strong>使用空格缩进，不要用Tab。</strong></p>
<p>Tab不适合用于缩进，即使你已经设置编辑器的Tab宽度为4列。
Tab在打印时与显示时的效果不同（打印时通常会变成8列宽），
另外将代码粘贴到字处理程序（如Word）中时也是如此。
甚至在其他人的编辑器上查看代码时，如果他的Tab设置与你不同，
看到的效果也不一样。</p>
<p>所以不要使用Tab键进行缩进，至少不要同时混合使用Tab和空格。</p>

<h2 id="content_12_3">2.12 代码块</h2>
<p><strong>不要在一行中书写两条语句。</strong></p>
<p>一行写两条或多条语句，会非常难于理解：</p>
<pre>RECORD:
while (my $record = &lt;$inventory_file&gt;) {
    chomp $record; next RECORD if $record eq $EMPTY_STR;
    my @fields = split $FIELD_SEPARATOR, $record; update_sales(\@fields);$count++;
}</pre>
<p>你已经通过K&amp;R括号风格节约了许多空间了，把这些空间用在增强代码可读性上吧：</p>
<pre>RECORD:
while (my $record = &lt;$inventory_file&gt;) {
    chomp $record;
    next RECORD if $record eq $EMPTY_STR;
    my @fields = split $FIELD_SEPARATOR, $record;
    update_sales(\@fields);
    $count++;
}</pre>
<p>即使是 map 或 grep 内部的语句，如果超过一条语句，那么也应该写在各自独立的行上。</p>
<!-- end Pukiwiki generated code-->
<br />
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2008/03/11/pbp-code-layout-3/feed/</wfw:commentRss>
		</item>
		<item>
		<title>[PBP]代码布局(2)</title>
		<link>http://tech.idv2.com/2008/03/08/pbp-code-layout-2/</link>
		<comments>http://tech.idv2.com/2008/03/08/pbp-code-layout-2/#comments</comments>
		<pubDate>Sat, 08 Mar 2008 08:46:05 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
		
		<category><![CDATA[Perl编程]]></category>
<category>pbp</category><category>perl</category>
		<guid isPermaLink="false">http://tech.idv2.com/2008/03/08/pbp-code-style-2/</guid>
		<description><![CDATA[停止已久的《Perl Best Practices》翻译今天重新开始了。继续讲代码布局。<!-- begin Pukiwiki generated code--><div class="contents">
<a id="contents_13"></a>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li><a href="#content_13_0">  2.5 键和索引</a></li>
<li><a href="#content_13_1">  2.6 运算符</a></li>
<li><a href="#content_13_2">  2.7 分号</a></li>
<li><a href="#content_13_3">  2.8. 逗号</a></li></ul>
</div>

<hr class="full_hr" />
<h2 id="content_13_0">2.5 键和索引</h2>
<p><strong>复杂的键或者索引要与他们周围的括号分开。</strong></p>
<p>访问嵌套数据（例如散列中散列其中再有数组）时，很容易产生相当长并且非常复杂的表达式，
极难阅读。例如：</p>
<pre>$candidates[$i] = $incumbent{$candidates[$i]{get_region( )}};</pre>
<p>像上面这样把所有内容都挤在一起很不容易看懂，也很难看出某个括号到底属于哪一层。</p>
<p>除非索引是简单的数据，否则都应该在索引和括号之间加入空格，以增强可读性：</p>
<pre>$candidates[$i] = $incumbent{ $candidates[$i]{ get_region( ) } };</pre>
<p>这里的决定因素不仅仅是复杂性，也包括表达式的整体长度。
如果索引的名字太长，那么即使它是一个单一的值，也最好加上空格。
例如：</p>
<pre>print $incumbent{ $largest_gerrymandered_constituency };</pre>
<p>这种写法明显要好于下面这种：</p>
<pre>print $incumbent{$largest_gerrymandered_constituency};</pre>

<h2 id="content_13_1">2.6 运算符</h2>
<p><strong>用空格让二元运算符更醒目。</strong></p>
<p>过长的表达式，若将各个部分都挤在一起，将非常读懂：</p>
<pre>my $displacement=$initial_velocity*$time+0.5*$acceleration*$time**2;
my $price=$coupon_paid*$exp_rate+(($face_val+$coupon_val)*$exp_rate**2);</pre>
<p>应当为二元运算符留出一点活动空间，即使这样会导致代码换行也是值得的：</p>
<pre>my $displacement
    = $initial_velocity * $time  +  0.5 * $acceleration * $time**2;</pre>
<pre>my $price
    = $coupon_paid * $exp_rate  +  ($face_val + $coupon_paid) * $exp_rate**2;</pre>
<p>另外，也可以根据运算符的优先顺序来调整空格的数量，例如低优先级的运算符两侧
添加更多的空格，以从视觉上将其与那些高优先级的运算符分开。而像 ** 这样的
高优先级运算符，则甚至可以两侧不加任何空格。</p>

<h2 id="content_13_2">2.7 分号</h2>
<p><strong>每条语句之后都要写分号。</strong></p>
<p>C程序员可能对这一条没什么话说。这一条是因为在perl中，分号是<strong>语句分隔符</strong>，
而不是语句结束符。因此，一个代码快的最后一行代码后是无须加分号的。例如下面的代码
是完全正确的：</p>
<pre>while (my $line = &lt;&gt;) {
    chomp $line;

    if ( $line =~ s{\A (\s*) -- (.*)}{$1#$2}xms ) {
        push @comments, $2
    }

    print $line
}</pre>
<p>但问题是，随着开发的进行，可能会需要在最后一行之前添加一些代码。
如果没有注意到前面的 print $line 没有分号，就有可能会变成这个样子：</p>
<pre>    print $line
    $src_len += length;</pre>
<p>更要命的是上面这段代码不会产生编译错误，因为Perl会把它们当成一条语句，相当于：</p>
<pre>    print $line ($src_len += length);</pre>
<p>因此，为避免这种错误的发生，还是老老实实地加上分号吧。</p>
<pre>while (my $line = &lt;&gt;) {
    chomp $line;

    if ( $line =~ s{\A (\s*) -- (.*)}{$1#$2}xms ) {
        push @comments, $2;
    }

    print $line;
}</pre>
<p>但有一种情况例外，那就是在使用grep或者map时，其内部的代码块最好省略分号：</p>
<pre>my @sqrt_results
    = map { sqrt $_ } @results;</pre>
<p>而无须写成这样：</p>
<pre>my @sqrt_results
    = map { sqrt $_; } @results;</pre>
<p>map或grep不会发生前述的问题，因为map、grep中的代码快通常只有一行代码。
如果你的map或grep代码块中包含多于一句代码，那只能说明这里不适合使用map或者grep。</p>

<h2 id="content_13_3">2.8. 逗号</h2>
<p><strong>多行的列表的每一行末尾都要加逗号。</strong></p>
<p>例如，下面例子最后一行的'Doc'后面也要加上逗号：</p>
<pre>my @dwarves = (
    'Happy',
    'Sleepy',
    'Dopey',
    'Sneezy',
    'Grumpy',
    'Bashful',
    'Doc',
);</pre>
<p>因为这样很容易通过sort命令对列表进行排序，而且添加新值时
也不会因为忘记逗号而出错。
如果Doc后面不加逗号，那么排序后就变成了</p>
<pre>my @dwarves = (
    'Bashful',
    'Doc'
    'Dopey',
    'Grumpy',
    'Happy',
    'Sleepy',
    'Sneezy',
);</pre>
<!-- end Pukiwiki generated code-->

]]></description>
			<content:encoded><![CDATA[停止已久的《Perl Best Practices》翻译今天重新开始了。继续讲代码布局。<!-- begin Pukiwiki generated code--><div class="contents">
<a id="contents_14"></a>
<ul class="list1" style="padding-left:16px;margin-left:16px"><li><a href="#content_14_0">  2.5 键和索引</a></li>
<li><a href="#content_14_1">  2.6 运算符</a></li>
<li><a href="#content_14_2">  2.7 分号</a></li>
<li><a href="#content_14_3">  2.8. 逗号</a></li></ul>
</div>

<hr class="full_hr" />
<h2 id="content_14_0">2.5 键和索引</h2>
<p><strong>复杂的键或者索引要与他们周围的括号分开。</strong></p>
<p>访问嵌套数据（例如散列中散列其中再有数组）时，很容易产生相当长并且非常复杂的表达式，
极难阅读。例如：</p>
<pre>$candidates[$i] = $incumbent{$candidates[$i]{get_region( )}};</pre>
<p>像上面这样把所有内容都挤在一起很不容易看懂，也很难看出某个括号到底属于哪一层。</p>
<p>除非索引是简单的数据，否则都应该在索引和括号之间加入空格，以增强可读性：</p>
<pre>$candidates[$i] = $incumbent{ $candidates[$i]{ get_region( ) } };</pre>
<p>这里的决定因素不仅仅是复杂性，也包括表达式的整体长度。
如果索引的名字太长，那么即使它是一个单一的值，也最好加上空格。
例如：</p>
<pre>print $incumbent{ $largest_gerrymandered_constituency };</pre>
<p>这种写法明显要好于下面这种：</p>
<pre>print $incumbent{$largest_gerrymandered_constituency};</pre>

<h2 id="content_14_1">2.6 运算符</h2>
<p><strong>用空格让二元运算符更醒目。</strong></p>
<p>过长的表达式，若将各个部分都挤在一起，将非常读懂：</p>
<pre>my $displacement=$initial_velocity*$time+0.5*$acceleration*$time**2;
my $price=$coupon_paid*$exp_rate+(($face_val+$coupon_val)*$exp_rate**2);</pre>
<p>应当为二元运算符留出一点活动空间，即使这样会导致代码换行也是值得的：</p>
<pre>my $displacement
    = $initial_velocity * $time  +  0.5 * $acceleration * $time**2;</pre>
<pre>my $price
    = $coupon_paid * $exp_rate  +  ($face_val + $coupon_paid) * $exp_rate**2;</pre>
<p>另外，也可以根据运算符的优先顺序来调整空格的数量，例如低优先级的运算符两侧
添加更多的空格，以从视觉上将其与那些高优先级的运算符分开。而像 ** 这样的
高优先级运算符，则甚至可以两侧不加任何空格。</p>

<h2 id="content_14_2">2.7 分号</h2>
<p><strong>每条语句之后都要写分号。</strong></p>
<p>C程序员可能对这一条没什么话说。这一条是因为在perl中，分号是<strong>语句分隔符</strong>，
而不是语句结束符。因此，一个代码快的最后一行代码后是无须加分号的。例如下面的代码
是完全正确的：</p>
<pre>while (my $line = &lt;&gt;) {
    chomp $line;

    if ( $line =~ s{\A (\s*) -- (.*)}{$1#$2}xms ) {
        push @comments, $2
    }

    print $line
}</pre>
<p>但问题是，随着开发的进行，可能会需要在最后一行之前添加一些代码。
如果没有注意到前面的 print $line 没有分号，就有可能会变成这个样子：</p>
<pre>    print $line
    $src_len += length;</pre>
<p>更要命的是上面这段代码不会产生编译错误，因为Perl会把它们当成一条语句，相当于：</p>
<pre>    print $line ($src_len += length);</pre>
<p>因此，为避免这种错误的发生，还是老老实实地加上分号吧。</p>
<pre>while (my $line = &lt;&gt;) {
    chomp $line;

    if ( $line =~ s{\A (\s*) -- (.*)}{$1#$2}xms ) {
        push @comments, $2;
    }

    print $line;
}</pre>
<p>但有一种情况例外，那就是在使用grep或者map时，其内部的代码块最好省略分号：</p>
<pre>my @sqrt_results
    = map { sqrt $_ } @results;</pre>
<p>而无须写成这样：</p>
<pre>my @sqrt_results
    = map { sqrt $_; } @results;</pre>
<p>map或grep不会发生前述的问题，因为map、grep中的代码快通常只有一行代码。
如果你的map或grep代码块中包含多于一句代码，那只能说明这里不适合使用map或者grep。</p>

<h2 id="content_14_3">2.8. 逗号</h2>
<p><strong>多行的列表的每一行末尾都要加逗号。</strong></p>
<p>例如，下面例子最后一行的'Doc'后面也要加上逗号：</p>
<pre>my @dwarves = (
    'Happy',
    'Sleepy',
    'Dopey',
    'Sneezy',
    'Grumpy',
    'Bashful',
    'Doc',
);</pre>
<p>因为这样很容易通过sort命令对列表进行排序，而且添加新值时
也不会因为忘记逗号而出错。
如果Doc后面不加逗号，那么排序后就变成了</p>
<pre>my @dwarves = (
    'Bashful',
    'Doc'
    'Dopey',
    'Grumpy',
    'Happy',
    'Sleepy',
    'Sneezy',
);</pre>
<!-- end Pukiwiki generated code-->
<br />
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2008/03/08/pbp-code-layout-2/feed/</wfw:commentRss>
		</item>
		<item>
		<title>[Perl]关于use的执行时机</title>
		<link>http://tech.idv2.com/2008/03/07/use-timing/</link>
		<comments>http://tech.idv2.com/2008/03/07/use-timing/#comments</comments>
		<pubDate>Fri, 07 Mar 2008 12:51:40 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
		
		<category><![CDATA[其他]]></category>
<category>perl</category>
		<guid isPermaLink="false">http://tech.idv2.com/2008/03/07/use-timing/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p>最近遇到的一个任务是要将散落在系统各个文件中的 use lib '/opt/mysoft/lib'; 这样的绝对路径引用改成相对路径，
以便整个系统能够轻易地移动到其他的目录中。系统是工作在Apache2 + mod_perl 下的，cgi程序位于 /opt/mysoft/cgi-bin 下。</p>
<p>初看起来似乎很容易：</p>
<pre>use lib '../lib';    # 错误！</pre>
<p>但实际尝试一下就会发现，这里的 '..' 似乎找错了位置。当前目录并不是cgi程序所在的 /opt/mysoft/cgi-bin。
经过一番实验后，发现在 use lib 时，当前目录居然是在 / 下！这样这条路就走不通了。</p>
<p>另一个想法是通过 $0 获取到CGI程序的路径，再根据此路径来找到 lib 目录不就可以了么？</p>
<pre>$dir = dirname $0;
use lib &quot;$dir/../lib&quot;;     # 错误！

print &quot;$_\n&quot; for @INC;</pre>
<p>实际运行就会发现，这一招也行不通。原因是use lib是在编译时执行的。编译时代码并没有被执行，
因此 $dir 变量为空（甚至都不存在），于是就成了 use lib &quot;/../lib&quot;，当然不正确了。
这样看来 use lib 似乎必须要书写完整路径了。</p>
<p><a href="http://search.cpan.org/~rgarcia/perl-5.10.0/lib/lib_pm.PL">CPAN文档的解释</a>如下：</p>
<pre>lib - manipulate @INC at compile time</pre>
<p>实际上 use lib 可以理解为 BEGIN { unshift @INC, '/opt/mysoft/lib'; }。
BEGIN段的内容在这一段编译结束后立即执行。</p>
<p>回到本来的问题上，如何能避免在系统中使用绝对路径？
其实使用mod_perl的功能一次性地指定好@INC，那么在CGI和pm模块中就无需再use lib了。</p>
<p>在mod_perl的官方文档中有关于<a href="http://perl.apache.org/docs/2.0/user/config/config.html#Adjusting_C__INC_">如何调整@INC</a>的说明。</p>
<p>一种方法是在 startup.pl 中书写完整路径：</p>
<pre>use lib '/opt/mysoft/lib';</pre>
<p>令一种方法是直接在httpd.conf中修改@INC：</p>
<pre>PerlSwitches -I/opt/mysoft/lib</pre>
<p>这样虽然不能完全避免绝对路径，但至少在产品代码中可以不再使用 use lib 了。</p>
<hr class="full_hr" />
<p>同样地，use 也是在编译时执行的。（<a href="http://perldoc.perl.org/functions/use.html">参考</a>）use Module;相当于</p>
<pre>BEGIN { require Module; Module-&gt;import( LIST ); }</pre>
<p>程序代码中的所有use指令都会在代码执行前被执行，因此use不论放在哪里，效果都是一样的。因此</p>
<pre>if ($use_first_lib) {
  use FirstLib;
  ...
}
else {
  use SecondLib;
  ...
}</pre>
<p>这样的代码是毫无用处的，不论$use_first_lib的值如何，FirstLib和SecondLib都会被加载。</p>
<!-- end Pukiwiki generated code-->

]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p>最近遇到的一个任务是要将散落在系统各个文件中的 use lib '/opt/mysoft/lib'; 这样的绝对路径引用改成相对路径，
以便整个系统能够轻易地移动到其他的目录中。系统是工作在Apache2 + mod_perl 下的，cgi程序位于 /opt/mysoft/cgi-bin 下。</p>
<p>初看起来似乎很容易：</p>
<pre>use lib '../lib';    # 错误！</pre>
<p>但实际尝试一下就会发现，这里的 '..' 似乎找错了位置。当前目录并不是cgi程序所在的 /opt/mysoft/cgi-bin。
经过一番实验后，发现在 use lib 时，当前目录居然是在 / 下！这样这条路就走不通了。</p>
<p>另一个想法是通过 $0 获取到CGI程序的路径，再根据此路径来找到 lib 目录不就可以了么？</p>
<pre>$dir = dirname $0;
use lib &quot;$dir/../lib&quot;;     # 错误！

print &quot;$_\n&quot; for @INC;</pre>
<p>实际运行就会发现，这一招也行不通。原因是use lib是在编译时执行的。编译时代码并没有被执行，
因此 $dir 变量为空（甚至都不存在），于是就成了 use lib &quot;/../lib&quot;，当然不正确了。
这样看来 use lib 似乎必须要书写完整路径了。</p>
<p><a href="http://search.cpan.org/~rgarcia/perl-5.10.0/lib/lib_pm.PL">CPAN文档的解释</a>如下：</p>
<pre>lib - manipulate @INC at compile time</pre>
<p>实际上 use lib 可以理解为 BEGIN { unshift @INC, '/opt/mysoft/lib'; }。
BEGIN段的内容在这一段编译结束后立即执行。</p>
<p>回到本来的问题上，如何能避免在系统中使用绝对路径？
其实使用mod_perl的功能一次性地指定好@INC，那么在CGI和pm模块中就无需再use lib了。</p>
<p>在mod_perl的官方文档中有关于<a href="http://perl.apache.org/docs/2.0/user/config/config.html#Adjusting_C__INC_">如何调整@INC</a>的说明。</p>
<p>一种方法是在 startup.pl 中书写完整路径：</p>
<pre>use lib '/opt/mysoft/lib';</pre>
<p>令一种方法是直接在httpd.conf中修改@INC：</p>
<pre>PerlSwitches -I/opt/mysoft/lib</pre>
<p>这样虽然不能完全避免绝对路径，但至少在产品代码中可以不再使用 use lib 了。</p>
<hr class="full_hr" />
<p>同样地，use 也是在编译时执行的。（<a href="http://perldoc.perl.org/functions/use.html">参考</a>）use Module;相当于</p>
<pre>BEGIN { require Module; Module-&gt;import( LIST ); }</pre>
<p>程序代码中的所有use指令都会在代码执行前被执行，因此use不论放在哪里，效果都是一样的。因此</p>
<pre>if ($use_first_lib) {
  use FirstLib;
  ...
}
else {
  use SecondLib;
  ...
}</pre>
<p>这样的代码是毫无用处的，不论$use_first_lib的值如何，FirstLib和SecondLib都会被加载。</p>
<!-- end Pukiwiki generated code-->
<br />
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2008/03/07/use-timing/feed/</wfw:commentRss>
		</item>
		<item>
		<title>pidgin不能输入的问题</title>
		<link>http://tech.idv2.com/2008/03/06/pidgin-input-error/</link>
		<comments>http://tech.idv2.com/2008/03/06/pidgin-input-error/#comments</comments>
		<pubDate>Thu, 06 Mar 2008 09:02:15 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
		
		<category><![CDATA[Linux应用]]></category>
<category>gentoo</category><category>im</category><category>linux</category><category>pidgin</category>
		<guid isPermaLink="false">http://tech.idv2.com/2008/03/06/pidgin-input-error/</guid>
		<description><![CDATA[最近发现gentoo下pidgin经常会不能输入，表现在输入法切换不出来，甚至无法输入英文字母。没办法只能重启pidgin。不过今天突然发现了问题的所在。那就是，从聊天窗口用Alt-Tab键切换到好友列表窗口，再用Alt-Tab切换回来，这时一切键盘输入就都不管用了。解决方法也很简单：再用Alt-Tab切换一次，就行了。另外为避免出现这种情况，建议没事儿时把好友列表窗口关掉。
]]></description>
			<content:encoded><![CDATA[<p>最近发现gentoo下pidgin经常会不能输入，表现在输入法切换不出来，甚至无法输入英文字母。没办法只能重启pidgin。不过今天突然发现了问题的所在。那就是，从聊天窗口用Alt-Tab键切换到好友列表窗口，再用Alt-Tab切换回来，这时一切键盘输入就都不管用了。解决方法也很简单：再用Alt-Tab切换一次，就行了。另外为避免出现这种情况，建议没事儿时把好友列表窗口关掉。</p>
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2008/03/06/pidgin-input-error/feed/</wfw:commentRss>
		</item>
		<item>
		<title>ntfs-3g+fuse试用</title>
		<link>http://tech.idv2.com/2008/03/05/try-ntfs-3g-fuse/</link>
		<comments>http://tech.idv2.com/2008/03/05/try-ntfs-3g-fuse/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 14:20:49 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
		
		<category><![CDATA[Linux应用]]></category>
<category>gentoo</category><category>linux</category><category>ntfs</category><category>windows</category>
		<guid isPermaLink="false">http://tech.idv2.com/2008/03/05/try-ntfs-3g-fuse/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p>前几天的<a href="http://tech.idv2.com/2008/03/02/gentoo-installl-memo/">这篇文章</a>被
<a href="http://www.fcicq.net/wp/">fcicq</a>同学挑毛病，建议不要使用内核自带的ntfs，
而是使用ntfs-3g+fuse。查了一下，ntfs-3g可以完美支持ntfs分区的读写操作，
的确要比内核自带的ntfs好得多。</p>
<p>试试看。安装方法不难，直接emerge即可，它会自动安装 sys-fs/fuse：</p>
<pre># emerge ntfs-3g</pre>
<p>我用的是gentoo 2007.0，内核版本2.6.23-gentoo-r8，还需要编译内核的FUSE支持：</p>
<pre># cd /usr/src/linux
# make menuconfig
勾选 File systems ---&gt;  &lt;M&gt; Filesystem in Userspace support
# make modules_install
＃ modprobe fuse</pre>
<p>之后当然可以再打开 /etc/modules.autoload.d/kernel-2.6，把fuse加进去。</p>
<p>然后就可以mount ntfs分区了：</p>
<pre># mount -t ntfs-3g -o locale=zh_CN.UTF-8,silent /dev/sda6 /mnt/wine</pre>
<p>进入分区后试试读写，均没有问题。</p>
<p>后来看了看ntfs-3g的<a href="http://www.ntfs-3g.org/support.html#posixfilenames1">官方主页的FAQ</a>，
发现竟然允许大小写不同的同名文件，还有特殊字符（如\、?等Windows中不允许的字符）。
作者的理由是NTFS支持POSIX风格的文件名，也支持DOS、Windows格式的文件名，
为保持最大的兼容性，ntfs-3g就选择了POSIX——所以就出现上面这种现象了。
尝试者建立 ABC、abc、ab?c、abc\d等文件，均建立成功，重新启动到windows下试图打开这几个文件，
结果出现了问题：ABC正常打开，但一旦保存，ABC就会丢失，只剩下abc（因为同名），估计有可能需要chkdsk了；
ab?c、abc\d文件无法保存、改名和删除。只能回到linux下面操作。</p>
<p>看来作者又是一个十足的协议派……为保险起见，还是先ro吧。</p>
<p>最后的/etc/fstab为：</p>
<pre>/dev/sda6       /mnt/wine    ntfs-3g    auto,ro,locale=zh_CN.UTF-8,silent    0  0</pre>
<!-- end Pukiwiki generated code-->

]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p>前几天的<a href="http://tech.idv2.com/2008/03/02/gentoo-installl-memo/">这篇文章</a>被
<a href="http://www.fcicq.net/wp/">fcicq</a>同学挑毛病，建议不要使用内核自带的ntfs，
而是使用ntfs-3g+fuse。查了一下，ntfs-3g可以完美支持ntfs分区的读写操作，
的确要比内核自带的ntfs好得多。</p>
<p>试试看。安装方法不难，直接emerge即可，它会自动安装 sys-fs/fuse：</p>
<pre># emerge ntfs-3g</pre>
<p>我用的是gentoo 2007.0，内核版本2.6.23-gentoo-r8，还需要编译内核的FUSE支持：</p>
<pre># cd /usr/src/linux
# make menuconfig
勾选 File systems ---&gt;  &lt;M&gt; Filesystem in Userspace support
# make modules_install
＃ modprobe fuse</pre>
<p>之后当然可以再打开 /etc/modules.autoload.d/kernel-2.6，把fuse加进去。</p>
<p>然后就可以mount ntfs分区了：</p>
<pre># mount -t ntfs-3g -o locale=zh_CN.UTF-8,silent /dev/sda6 /mnt/wine</pre>
<p>进入分区后试试读写，均没有问题。</p>
<p>后来看了看ntfs-3g的<a href="http://www.ntfs-3g.org/support.html#posixfilenames1">官方主页的FAQ</a>，
发现竟然允许大小写不同的同名文件，还有特殊字符（如\、?等Windows中不允许的字符）。
作者的理由是NTFS支持POSIX风格的文件名，也支持DOS、Windows格式的文件名，
为保持最大的兼容性，ntfs-3g就选择了POSIX——所以就出现上面这种现象了。
尝试者建立 ABC、abc、ab?c、abc\d等文件，均建立成功，重新启动到windows下试图打开这几个文件，
结果出现了问题：ABC正常打开，但一旦保存，ABC就会丢失，只剩下abc（因为同名），估计有可能需要chkdsk了；
ab?c、abc\d文件无法保存、改名和删除。只能回到linux下面操作。</p>
<p>看来作者又是一个十足的协议派……为保险起见，还是先ro吧。</p>
<p>最后的/etc/fstab为：</p>
<pre>/dev/sda6       /mnt/wine    ntfs-3g    auto,ro,locale=zh_CN.UTF-8,silent    0  0</pre>
<!-- end Pukiwiki generated code-->
<br />
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2008/03/05/try-ntfs-3g-fuse/feed/</wfw:commentRss>
		</item>
		<item>
		<title>驱动导致xorg不能启动</title>
		<link>http://tech.idv2.com/2008/03/04/xorg-failure-caused-by-drivers/</link>
		<comments>http://tech.idv2.com/2008/03/04/xorg-failure-caused-by-drivers/#comments</comments>
		<pubDate>Tue, 04 Mar 2008 13:21:08 +0000</pubDate>
		<dc:creator>charlee</dc:creator>
		
		<category><![CDATA[Linux应用]]></category>
<category>gentoo</category><category>linux</category><category>nvidia</category>
		<guid isPermaLink="false">http://tech.idv2.com/2008/03/04/xorg-failure-caused-by-drivers/</guid>
		<description><![CDATA[<!-- begin Pukiwiki generated code--><p>今天在配置nvidia的显卡时出现了一个很头疼的问题。</p>
<p>按照<a href="http://www.gentoo.org/doc/zh_cn/nvidia-guide.xml">官方网站上的文章</a>，
一步步地顺利地安装好了显卡驱动：</p>
<pre># 先配置内核，详情参考官方文档，省略
# USE=gtk emerge nvidia-drivers
# modprobe nvidia
# update-modules
# eselect opengl set nvidia
# 然后修改xorg.conf，略
# startx</pre>
<p>结果startx时出现了这样的错误：</p>
<pre>Backtrace:
0: X(xf86SigHandler+0x84) [0x80cca34]
1: [0xffffe420]
2: X(main+0x2af) [0x807067f]
3: /lib/libc.so.6(__libc_start_main+0xd8) [0xb7db5838]
4: X(FontFileCompleteXLFD+0xa1) [0x806fb81]

Fatal server error:
Caught signal 11.  Server aborting</pre>
<p>查了半天资料未得到结果，后来想起我曾经安装过nVidia官方网站提供的驱动，
会不会是和portage的驱动冲突呢？于是卸载掉官方驱动：</p>
<pre># sh NVIDIA-Linux-x86-169.09-pkg1.run --uninstall</pre>
<p>然后重新emerge：</p>
<pre># emerge nvidia-drivers</pre>
<p>这样就可以顺利地启动X了。</p>
<!-- end Pukiwiki generated code-->
]]></description>
			<content:encoded><![CDATA[<!-- begin Pukiwiki generated code--><p>今天在配置nvidia的显卡时出现了一个很头疼的问题。</p>
<p>按照<a href="http://www.gentoo.org/doc/zh_cn/nvidia-guide.xml">官方网站上的文章</a>，
一步步地顺利地安装好了显卡驱动：</p>
<pre># 先配置内核，详情参考官方文档，省略
# USE=gtk emerge nvidia-drivers
# modprobe nvidia
# update-modules
# eselect opengl set nvidia
# 然后修改xorg.conf，略
# startx</pre>
<p>结果startx时出现了这样的错误：</p>
<pre>Backtrace:
0: X(xf86SigHandler+0x84) [0x80cca34]
1: [0xffffe420]
2: X(main+0x2af) [0x807067f]
3: /lib/libc.so.6(__libc_start_main+0xd8) [0xb7db5838]
4: X(FontFileCompleteXLFD+0xa1) [0x806fb81]

Fatal server error:
Caught signal 11.  Server aborting</pre>
<p>查了半天资料未得到结果，后来想起我曾经安装过nVidia官方网站提供的驱动，
会不会是和portage的驱动冲突呢？于是卸载掉官方驱动：</p>
<pre># sh NVIDIA-Linux-x86-169.09-pkg1.run --uninstall</pre>
<p>然后重新emerge：</p>
<pre># emerge nvidia-drivers</pre>
<p>这样就可以顺利地启动X了。</p>
<!-- end Pukiwiki generated code--><br />
]]></content:encoded>
			<wfw:commentRss>http://tech.idv2.com/2008/03/04/xorg-failure-caused-by-drivers/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
