<?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>微風夕語 &#187; 我的專業</title>
	<atom:link href="http://bone.twbbs.org.tw/blog/archives/category/programming/feed" rel="self" type="application/rss+xml" />
	<link>http://bone.twbbs.org.tw/blog</link>
	<description>在光之翼的守護下訴說著一段段的英雄傳說。</description>
	<lastBuildDate>Fri, 03 Sep 2010 16:00:00 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>[Scala] 轉換非 Big5 至 XML 脫逸字元。</title>
		<link>http://bone.twbbs.org.tw/blog/archives/1512</link>
		<comments>http://bone.twbbs.org.tw/blog/archives/1512#comments</comments>
		<pubDate>Fri, 03 Sep 2010 06:16:57 +0000</pubDate>
		<dc:creator>墳墓 (BrianHsu)</dc:creator>
				<category><![CDATA[我的專業]]></category>

		<guid isPermaLink="false">http://bone.twbbs.org.tw/blog/?p=1512</guid>
		<description><![CDATA[話說前一陣子 Scala 社群裡面在吵 Scala 這個程式語言到底簡單還是難，剛好這幾天在看程式時發現這個讓人想大喊 WTF，然後投稿到 The Daily WTF 上的 Java 函式，所以就拿它來開刀了…… 原本的 Java Code 長的像下面這樣： public static String isNotBig5(String ori) { char[] c = ori.toCharArray(); char[] c1 = new char[1]; StringBuffer sb = new StringBuffer(); for (int i = 0; i &#60; c.length; i++) { c1[0] = c[i]; //System.out.println(c1[0]+" "+(int)c1[0]); // String onechar = [...]]]></description>
			<content:encoded><![CDATA[<p>話說前一陣子 <a href="http://www.scala-lang.org/node/7431">Scala 社群裡面在吵 Scala 這個程式語言到底簡單還是難</a>，剛好這幾天在看程式時發現這個讓人想大喊 WTF，然後投稿到 The Daily WTF 上的 Java 函式，所以就拿它來開刀了……</p>

<p>原本的 Java Code 長的像下面這樣：</p>

<pre class="brush: java">public static String isNotBig5(String ori)
{
    char[] c = ori.toCharArray();
    char[] c1 = new char[1];
    StringBuffer sb = new StringBuffer();
    for (int i = 0; i &lt; c.length; i++) {
        c1[0] = c[i];
        //System.out.println(c1[0]+" "+(int)c1[0]); //
        String onechar = "";
        try {
            onechar = new String( (new String(c1)).getBytes() , "Big5");
        }
        catch (Exception e) {}
        if (onechar.equals("?") &amp;&amp; (int)c[i] != 63) { // ?是正常的"?"
            sb.append("&amp;#");
            sb.append(Integer.toString(c1[0]));
            sb.append(";");
        }
        else {
            sb.append(c1[0]);
        }
    }
    return sb.toString();
}
</pre>

<p>因為這段程式實在醜到一種極緻，完全違反了所有 Clean Code 的原則。老實說，雖然一開始我知道這個函式是幹啥用的，但我完全無法理解這個函式到底在搞什麼鬼（看那和實際用途差了十萬八千里的函式名稱），而且它完全無法在非 Windows 的作業系統上正常使用。</p>

<p>最後，經過一連串的實驗，我終於看出來這個函式的演算法了（雖然他的實作是有問題的），其實這個演算法很簡單：</p>

<ol>
    <li>針對字串裡的每一個字元，做下列的動作
<ol>
    <li>檢查該字元是不是在 Big5 可以表示的範圍內</li>
    <li>如果是，將該字元轉成字串，例如從 &#8216;A&#8217; 到 "A"</li>
    <li>如果不是，將該字元轉成 XML 字元參引，例如 &#8216;喆&#8217; 轉成 "&amp;#21894;"</li>
</ol>
</li>
    <li>將上一個步驟所產生出來的所有字串，合併（連接）成單一字串。</li>
</ol>

<p>所以，為了讓我自己往後好過一點，我用 Scala 照著同樣的演算法幹出了另一個版本，不完美，但我想應該至少清楚很多，以下就是 Scala 版的程式碼，其中 normalizeString 的角色就是原來 Java 版中的 isNotBig5()：</p>

<pre class="brush: scala">def normalizeString (string: String) =
    string.flatMap(escapeNonBig5Character _)

def escapeNonBig5Character (character: Char): String = {

    def isNotBig5 (character: Char) =
        character.toString.getBytes("Big5")(0) == '?' &amp;&amp;
        character != '?'

     // 不是 Big5 的字元就轉成字元參引
     // 不然的話維持原樣
    isNotBig5(character) match {
        case true =&gt; "&amp;#%d;" format(character.toInt)
        case false =&gt; character.toString
    }
}

def example () {
    val content = "我是陶喆\n我是游鍚堃\n這是測試"
    println (normalizeString(content))
}
</pre>

<p>如果你是從 Java 背景來的，那麼注意下面幾點應該就可以看懂這個程式：</p>

<ul>
    <li>String#flatMap 是指針對字串裡的每一個字元，套用一個將字元轉成字串的函式（所以這時計算出的東西會是 Array of String），最後再將此 Array of String 合併成單一的字串。</li>
    <li>escapeNonBig5Character 會將字元轉成字串，規則如下：
<ul>
    <li>如果該字元可以在 Big5 編碼下表示，就維持原樣，但轉成字串，也就是從 &#8216;A&#8217; 轉到 "A"</li>
    <li>如果該字元無法以 Big5 編碼表示，那就將該字元轉成 &amp;#XXXXXX; 的格式</li>
</ul>
</li>
    <li>判斷字元可否在 Big5 下表示的方式：
<ul>
    <li>例用 String#getBytes("BIG5&#8243;) 將其轉碼到 BIG5，如果他本來不是問號，卻變成問號（解析不能），那這個字就無法用 Big5 來表示。</li>
</ul>
</li>
</ul>

<p>老實講，是很簡單的轉換法，但上面那段看了就想大喊 WTF 的程式碼，我不知道為什麼能把這麼簡單的東西給搞到這麼複雜……</p>

<p>至於 Scala 到底難不難？！我想這真的很難說，如果你不知道什麼是 High order function （flatMap 就是一個例子），那麼 Scala 版的可能你也覺得不好懂，但相對的，我每次在寫 Scala 時都覺得真的很像在『用嘴巴寫程式』。</p>

<p>仔細對照一下，你會發現 Scala 的版本非常接近於一開始我們針對 Java 版的演算法所做的『描述』，所以，快點把 Java 給丟了唄（大誤）！</p>

<p>BTW，到目前為止我最認同的是這句話：<a href="http://www.scala-lang.org/node/7431#comment-31046">I don&#8217;t expect a car to be built by average people, but by people with proper engineering background.</a></p>

<p>畢竟當你讓一個專業的來的時候，Scala 難不難根本不是個問題……</p>
]]></content:encoded>
			<wfw:commentRss>http://bone.twbbs.org.tw/blog/archives/1512/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[調教學姐] Gentoo Linux on Aspire Aspire 3820TG.</title>
		<link>http://bone.twbbs.org.tw/blog/archives/1499</link>
		<comments>http://bone.twbbs.org.tw/blog/archives/1499#comments</comments>
		<pubDate>Sun, 22 Aug 2010 13:45:35 +0000</pubDate>
		<dc:creator>墳墓 (BrianHsu)</dc:creator>
				<category><![CDATA[我的專業]]></category>

		<guid isPermaLink="false">http://bone.twbbs.org.tw/blog/?p=1499</guid>
		<description><![CDATA[我現在的工作主力－－學姐機。我現在的工作主力－－學姐機。(View at PicasaWeb) 話說年初的時候買了一台 Acer Aspire TimelineX 3820TG ，也就是我現在用的這台學姐機。 當初看到這台機器的消息時就很高興，雖然並不像 MacBook AIR 那麼輕，但價錢、重量、效能等等，都在我能夠接受的範圍內，而那時候買這台機器，主要的目的就是以下三點。 在 Windows 下用獨立顯卡玩遊戲（雖然最後都沒時間玩） 平時工作時在 Linux 下當開發程式桌機 出門到咖啡廳或研討會時可以用 Linux 上網 當然第一點是沒有什麼大問題的，但問是在第二三項的 Linux，而說到 Linux 的話，對我而言似乎沒有什麼選擇，第一個想到的就是已經用到習慣的 Gentoo 。 但是買了好幾個月，雖然在上面灌了 Gentoo ，但感覺上用下來還是有好幾個不滿意的地方，列舉如下： 我的 ATI 官方 Driver 跑不起來 Xorg 的 ATI Driver 外接螢幕無法工作 電池續航力大約只有 2 到 2.5 個小時左右 老實說這些並不是什麼大問題，但用起來很不爽，因為如果外接螢幕無法工作，那麼簡報時就很麻煩，而電池續航力在像 COSCUP 等研討會上更是勝負的重點！ 而在 COSCUP 會後在噗浪上看到有人聲稱這台 3820TG 在 Linux [...]]]></description>
			<content:encoded><![CDATA[<div class="shashin_image" style="width: 298px; float: right; clear: none;"><a href="http://lh4.ggpht.com/_MdBWjiltj8o/S-VVYbj1qYI/AAAAAAAAIRw/adU9d9kB1l0/P1010852.JPG?imgmax=640" class="highslide" id="thumb3" onclick="return hs.expand(this, { autoplay: false, slideshowGroup: 'groupNone' })"><img src="http://lh4.ggpht.com/_MdBWjiltj8o/S-VVYbj1qYI/AAAAAAAAIRw/adU9d9kB1l0/P1010852.JPG?imgmax=288" alt="我現在的工作主力－－學姐機。" title="我現在的工作主力－－學姐機。" width="288" height="191" /></a><span class="shashin_caption">我現在的工作主力－－學姐機。</span><div class="highslide-caption">我現在的工作主力－－學姐機。(<a href="http://picasaweb.google.com.tw/brianhsu.hsu/NinwAL#5468871200714631554">View at PicasaWeb</a>)</div></div>

<p>話說年初的時候買了一台 Acer Aspire TimelineX 3820TG ，也就是我現在用的這台學姐機。</p>

<p>當初看到這台機器的消息時就很高興，雖然並不像 MacBook AIR 那麼輕，但價錢、重量、效能等等，都在我能夠接受的範圍內，而那時候買這台機器，主要的目的就是以下三點。</p>

<ul>
<li>在 Windows 下用獨立顯卡玩遊戲（雖然最後都沒時間玩）</li>
<li>平時工作時在 Linux 下當開發程式桌機</li>
<li>出門到咖啡廳或研討會時可以用 Linux 上網</li>
</ul>

<p>當然第一點是沒有什麼大問題的，但問是在第二三項的 Linux，而說到 Linux 的話，對我而言似乎沒有什麼選擇，第一個想到的就是已經用到習慣的 Gentoo 。</p>

<p>但是買了好幾個月，雖然在上面灌了 Gentoo ，但感覺上用下來還是有好幾個不滿意的地方，列舉如下：</p>

<ul>
<li>我的 ATI 官方 Driver 跑不起來</li>
<li>Xorg 的 ATI Driver 外接螢幕無法工作</li>
<li>電池續航力大約只有 2 到 2.5 個小時左右</li>
</ul>

<p>老實說這些並不是什麼大問題，但用起來很不爽，因為如果外接螢幕無法工作，那麼簡報時就很麻煩，而電池續航力在像 COSCUP 等研討會上更是勝負的重點！</p>

<p>而在 COSCUP 會後在噗浪上看到有人聲稱這台 3820TG 在 Linux 下面的續航力是可以到五個小時的，所以我就下定決心要研究出來要怎麼調教我的 Gentoo 也能達到類似的續航力。</p>

<p>所以這一篇就是來講我的調教方式（誤），呃，我是說，我的驅動程設定，所使用的核心版本是 gentoo-source-2.6.35-r1。</p>

<p>基本上下面是目前我的學姐機上面可以正常工作的硬體以及驅動程式核心設定名稱，你可以在 Kernel Menu Config 裡面按下 / 後輸入設定名稱尋找他的位置以及相依性。</p>

<ul>
<li>音效卡 Intel HD Audio (CONFIG_SND_HDA_INTEL=m)</li>
<li>乙太網路卡 Atheros L1C (CONFIG_ATL1C=m)</li>
<li>無線網路卡 Atheros 802.11n (CONFIG_ATH9K=m)</li>
<li>讀卡機（理論上是 USB Mass Storage 打開就行了）</li>
</ul>

<p>至於 WebCam 因為沒有在用，所以不確定要用哪個 Driver。</p>

<p>以上都是一些基本的設定，也就是我之前用得很高興的部份，而接下來要解決的就是顯示卡和電池續航力的問題了。</p>

<p>經過一些思考後，可以歸納出其實上述的三個問題，本質上都是相同的－－如何把獨立顯卡給關掉，完全使用內建的 Intel 顯示晶片。</p>

<p>經過許多試誤後，我終於找出正確的 Kernel Configuration 了，請注意，這裡的設定請盡量一模一樣，不然螢幕可能會完全出不來。</p>

<ul>
<li><p>首先是把基本的顯卡設定打開</p>

<ul>
<li>CONFIG_AGP=y</li>
<li>CONFIG_AGP_INTEL=y</li>
</ul></li>
<li><p>打開 DRM 以及 ATI Driver，但不要打開 ATI 的 KMS</p>

<ul>
<li>CONFIG_DRM=y</li>
<li>CONFIG_DRM_RADEON=y</li>
<li>CONFIG_DRM_RADEON_KMS=n</li>
</ul></li>
<li><p>打開 Intel i915 Driver 以及 KMS</p>

<ul>
<li>CONFIG_DRM_I915=y</li>
<li>CONFIG_DRM_I915_KMS=y</li>
</ul></li>
</ul>

<p>基本上有了上面這些設定，你的 Gentoo 現在應該可以正確的在開機的時候抓到 Intel 的顯示晶片，並且在啟動 X 視窗的時候，也自動使用 Intel  顯示晶片。</p>

<p>而因為 i951 的顯示晶片驅動程式已經算挺成熟，外接螢幕也可以很順，用 xrandr &#8211;auto 就會自己設定了。</p>

<p>但這個時候如果使用 acpitool 觀看電池續航力，會發現和使用獨立顯卡時並沒有太大的差距，這是因為我們並沒有把獨立顯卡的電源給切斷。</p>

<p>這個時候需要以下這個核心模組來幫忙。</p>

<ul>
<li># git clone git://github.com/brianhsu/timelinex_acpi.git</li>
<li># cd timelinex_acpi</li>
<li># make install</li>
</ul>

<div class="shashin_image" style="width: 298px; float: right; clear: none;"><a href="http://lh4.ggpht.com/_MdBWjiltj8o/THEmKd6pUmI/AAAAAAAAI6g/L29TUL3lpxg/BatteryLife.jpg?imgmax=640" class="highslide" id="thumb4" onclick="return hs.expand(this, { autoplay: false, slideshowGroup: 'groupNone' })"><img src="http://lh4.ggpht.com/_MdBWjiltj8o/THEmKd6pUmI/AAAAAAAAI6g/L29TUL3lpxg/BatteryLife.jpg?imgmax=288" alt="經過調教後的學姐機續航力。" title="經過調教後的學姐機續航力。" width="288" height="78" /></a><span class="shashin_caption">經過調教後的學姐機續航力。</span><div class="highslide-caption">經過調教後的學姐機續航力。(<a href="http://picasaweb.google.com.tw/brianhsu.hsu/CsRjrD#5508225780521980514">View at PicasaWeb</a>)</div></div>

<p>然後在 X Server 關閉的情況下，用 modprobe timelinex_acpi 來載入這個模組，這個時候核心會顯示 timelinex_acpi: disabled the discrete graphics card  的訊息，可以用 dmesg 觀看。</p>

<p>這個時候再使用 acpitool 看電池續航力，應該會發現可用時間會漸漸地往上飄，這就代表確實把獨立顯卡的電源給觀掉了。</p>

<p>當然，如果你想要讓電池續航力達到四小時左右的話，光是關掉顯示卡可能不夠，還是需要一些額外的設定幫忙，以下是我的設定。</p>

<ul>
<li><p>打開 ACPI CPU 變頻功能</p>

<ul>
<li>CONFIG_CPU_FREQ=y</li>
<li>CONFIG_CPU_FREQ_GOV_PERFORMANCE=m</li>
<li>CONFIG_CPU_FREQ_GOV_POWERSAVE=m</li>
<li>CONFIG_CPU_FREQ_GOV_USERSPACE=y</li>
<li>CONFIG_CPU_FREQ_GOV_ONDEMAND=m</li>
<li>CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m</li>
<li>CONFIG_X86_ACPI_CPUFREQ=m</li>
<li>CONFIG_INTEL_IDLE=m</li>
</ul></li>
<li><p>安裝 sys-power/cpufreqd，並且在電池模式時使用 powersave</p></li>
<li><p>下面是 sys-power/powertop 建議的，但我不知道是不是真的有用</p>

<ul>
<li>CONFIG_PM_RUNTIME=y</li>
<li>CONFIG_PCIEASPM=y</li>
</ul></li>
<li><p>據說 sys-power/powertop 會給很多建議，不過我自己覺得我的學姐機現在的表現已經很不錯了。</p></li>
</ul>

<p>經過以上的設定，基本上我的學姐機總算是可以發揮出他應有的工能了，只是……為什麼我是在 COSCUP 之後才找出這個設定啊！害我兩天下午在 Room 3 只能看著一片黑的螢幕……</p>

<p>最後順道一提，其實這樣的設定還有兩個問題我還沒解決。</p>

<ul>
<li><p>設成內建顯卡後，螢幕亮度不能調了，囧。</p></li>
<li><p>有的時候很明顯會一頓一頓的，看燈後是在讀硬碟，但我不知道是為什麼，有的人說是因為 AHCI 的關係，在 Windows 下也會發生，在 BIOS 調成 IDE 模式就會好，但我還沒試。</p></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://bone.twbbs.org.tw/blog/archives/1499/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows 上架設 Git 伺服器。</title>
		<link>http://bone.twbbs.org.tw/blog/archives/1487</link>
		<comments>http://bone.twbbs.org.tw/blog/archives/1487#comments</comments>
		<pubDate>Tue, 10 Aug 2010 13:42:12 +0000</pubDate>
		<dc:creator>墳墓 (BrianHsu)</dc:creator>
				<category><![CDATA[我的專業]]></category>

		<guid isPermaLink="false">http://bone.twbbs.org.tw/blog/?p=1487</guid>
		<description><![CDATA[到中研院上工一個多月，現在慢慢接手一些東西，主要是一台 Windows 2003 的伺服器，以及一些有些雜亂或是老舊的小工具程式。 要說到雜亂的程式碼的救星，那當然就是版本控制系統啦！也因為這樣，這幾天在規劃的就是要怎麼樣一步一步來整理這些程式碼，以及劃出一條安全的防護線，例如說至少所有的程式碼從此刻起都要進到版本控制系統來控管才行。 雖說這台 Windows 2003 上已經有了 Subversion 的服務存在著，不過你也知道的……習慣了強大的 Git 之後，回去使用 Subversion 真有一種綁手綁腳的感覺。 於是，我想把一些目前是只有我自己在維護的東西，給放到這台伺服器上並且使用 Git 來做管理，並且讓這台 Windows 2003 成為一台 Git Server。 但很不幸的……要在 Windows 上架設 Git Server 好像很麻煩，Google 了一下，幾乎都是教你用 CopSSH 來做，但不知道為什麼，我就是沒辦法試成功。 最後，我發現如果你只是要很簡單的 remote access，而且不在意傳輸過程沒加密的話，以下的步驟可以讓你超簡單在 Windows 上架設 Git Server。以下假設我們將所有 Git 的 repository 集中放在 D:\GitRepo 這個資料夾下。 安裝 msysgit 執行 GIT-bash 在 git bash 裡執行下列指令 mdkir /d/GitRepo [...]]]></description>
			<content:encoded><![CDATA[<p>到中研院上工一個多月，現在慢慢接手一些東西，主要是一台 Windows 2003 的伺服器，以及一些有些雜亂或是老舊的小工具程式。</p>

<p>要說到雜亂的程式碼的救星，那當然就是版本控制系統啦！也因為這樣，這幾天在規劃的就是要怎麼樣一步一步來整理這些程式碼，以及劃出一條安全的防護線，例如說至少所有的程式碼從此刻起都要進到版本控制系統來控管才行。</p>

<p>雖說這台 Windows 2003 上已經有了 Subversion 的服務存在著，不過你也知道的……習慣了強大的 Git 之後，回去使用 Subversion 真有一種綁手綁腳的感覺。</p>

<p>於是，我想把一些目前是只有我自己在維護的東西，給放到這台伺服器上並且使用 Git 來做管理，並且讓這台 Windows 2003 成為一台 Git Server。</p>

<p>但很不幸的……要在 Windows 上架設 Git Server 好像很麻煩，Google 了一下，幾乎都是教你用 CopSSH 來做，但不知道為什麼，我就是沒辦法試成功。</p>

<p>最後，我發現如果你只是要很簡單的 remote access，而且不在意傳輸過程沒加密的話，以下的步驟可以讓你超簡單在 Windows 上架設 Git Server。以下假設我們將所有 Git 的 repository 集中放在 D:\GitRepo 這個資料夾下。</p>

<ol>
    <li>安裝 msysgit</li>
    <li>執行 GIT-bash</li>
    <li>在 git bash 裡執行下列指令
<ol>
    <li>mdkir /d/GitRepo # 建立檔案庫資料夾集散地</li>
    <li>mkdir /d/GitRepo/testRepo</li>
    <li>cd /d/GitRepo/testRepo</li>
    <li>git init # 建立 Git repository</li>
</ol>
</li>
    <li>接著，直接把 D:\GitRepo 用網路芳臨開分享就好啦，權限控管也是在這邊設定</li>
    <li>接著，在 Client 端把你開出的網芳分享掛到 Z: 磁碟機</li>
    <li>然後就可以在 git bash 裡面用 git clone /z/testRepo 來複製這個 repo 了！</li>
    <li>當然，git push/pull 也都是可以用的。</li>
</ol>

<p>就是這樣簡單，我們都想太多了……Git 本來就可以直接對躺在本機檔案系統上的 repo 做 push/pull，所以我們只要能讓遠端的檔案系統看起來像本機的檔案系統就解決了！</p>

<p>夠簡單了吧？可是我不知道為什麼之前都沒人告訴我啊！&gt;_&lt;</p>
]]></content:encoded>
			<wfw:commentRss>http://bone.twbbs.org.tw/blog/archives/1487/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Programming Android in Scala 影片上線。</title>
		<link>http://bone.twbbs.org.tw/blog/archives/1366</link>
		<comments>http://bone.twbbs.org.tw/blog/archives/1366#comments</comments>
		<pubDate>Sat, 01 May 2010 07:36:38 +0000</pubDate>
		<dc:creator>墳墓 (BrianHsu)</dc:creator>
				<category><![CDATA[Scala]]></category>
		<category><![CDATA[我的專業]]></category>

		<guid isPermaLink="false">http://bone.twbbs.org.tw/blog/?p=1366</guid>
		<description><![CDATA[沒有想到 OSDC.tw 2010 的錄影這麼快就出來了！ 因為原本的檔案有點大，所以我把我的部份轉成串流格式，讓他可以在線上觀看。 Get the Flash Player to see this video. var swf = new SWFObject("https://media.dreamhost.com/mp4/player.swf", "mpl", "480", "379", 8); swf.addParam("allowfullscreen", "true"); swf.addParam("allowscriptaccess", "always"); swf.addVariable("file", "http://bone.forestlife.info/scala/scala_480x360.flv"); swf.addVariable("image", "http://bone.forestlife.info/scala/scala_480x360.jpeg"); swf.write("v3700"); 這次的講題是 Pgoramming Android Application in Scala，其實並沒有準備的很好，重新看了一次之後，發現後半部份好像講的有點凌亂。 總之，這算是處女秀了（好害羞啊）！ 接下來的 COSCUP 打算要講的講題是『ScalaTest －－ 連貓都會的 BBD 與單元測試』，繼續宣傳我的 Scala 教義！因為－－JAVA MUST DIE！ 歡迎大家繼續來 COSCUP 繼續捧場吧，特別是如果你每次都不知道單元測試要怎麼做，一定要來聽這場！保證連貓都學得會喲～～XDDD]]></description>
			<content:encoded><![CDATA[<p>沒有想到 OSDC.tw 2010 的錄影這麼快就出來了！</p>

<p>因為原本的檔案有點大，所以我把我的部份轉成串流格式，讓他可以在線上觀看。</p>

<div align="center">
<div id="v3700">
<a href="http://www.macromedia.com/go/getflashplayer">Get the Flash Player</a> to see this video.
</div>
<script type="text/javascript" src="https://media.dreamhost.com/mp4/swfobject.js"></script>
<script type="text/javascript">
var swf = new SWFObject("https://media.dreamhost.com/mp4/player.swf", "mpl", "480", "379", 8);
swf.addParam("allowfullscreen", "true");
swf.addParam("allowscriptaccess", "always");
swf.addVariable("file", "http://bone.forestlife.info/scala/scala_480x360.flv");
swf.addVariable("image", "http://bone.forestlife.info/scala/scala_480x360.jpeg");
swf.write("v3700");
</script>
</div>

<p>這次的講題是 Pgoramming Android Application in Scala，其實並沒有準備的很好，重新看了一次之後，發現後半部份好像講的有點凌亂。</p>

<p>總之，這算是處女秀了（好害羞啊）！</p>

<p>接下來的 COSCUP 打算要講的講題是『ScalaTest －－ 連貓都會的 BBD 與單元測試』，繼續宣傳我的 Scala 教義！因為－－JAVA MUST DIE！</p>

<p>歡迎大家繼續來 COSCUP 繼續捧場吧，特別是如果你每次都不知道單元測試要怎麼做，一定要來聽這場！保證連貓都學得會喲～～XDDD</p>
]]></content:encoded>
			<wfw:commentRss>http://bone.twbbs.org.tw/blog/archives/1366/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>一些連結和碎碎唸。</title>
		<link>http://bone.twbbs.org.tw/blog/archives/1348</link>
		<comments>http://bone.twbbs.org.tw/blog/archives/1348#comments</comments>
		<pubDate>Tue, 16 Mar 2010 23:55:48 +0000</pubDate>
		<dc:creator>墳墓 (BrianHsu)</dc:creator>
				<category><![CDATA[我的專業]]></category>

		<guid isPermaLink="false">http://bone.twbbs.org.tw/blog/?p=1348</guid>
		<description><![CDATA[因為工作的關係，一直沒得寫，補一些最近看到的連結以及想法。 連結： Haskell 教學 雖然 Haskell 不是我的菜，但這一系列的教學影片很棒，講者是 C# 裡 LINQ 的設計者，對於 OO 和 Functional Programming 都有一定的了解。課程很清楚，深入淺出，而且不時會將兩者對比，讓觀眾比較了解兩者在解問題的思維上的不同。 經典名句：I rellay like the DOT operator in OO programming language（因為 IDE 會把所有 method 列出來）. I don&#8217;t know what to type when I use Haskell（因為 IDE 沒得列）. (笑) Clojure / Ruby/ Scala / Go 大亂鬥 還沒看完，不過應該還滿有趣的。 碎碎唸： 覺得不管語言本身是不是 immutable，你只要是在 Java [...]]]></description>
			<content:encoded><![CDATA[<p>因為工作的關係，一直沒得寫，補一些最近看到的連結以及想法。</p>

<p>連結：</p>

<ul>
    <li><a href="http://www.cs.nott.ac.uk/~gmh/book.html#videos">Haskell 教學</a>
<ul>
    <li>雖然 Haskell 不是我的菜，但這一系列的教學影片很棒，講者是 C# 裡 LINQ 的設計者，對於 OO 和 Functional Programming 都有一定的了解。課程很清楚，深入淺出，而且不時會將兩者對比，讓觀眾比較了解兩者在解問題的思維上的不同。</li>
    <li>經典名句：I rellay like the DOT operator in OO programming language（因為 IDE 會把所有 method 列出來）. I don&#8217;t know what to type when I use Haskell（因為 IDE 沒得列）. (笑)</li>
</ul>
</li>
    <li><a href="http://old.nabble.com/-scala--Scala%2C-Ruby%2C-Clojure-and-Go-at-SD-Forum-to27907262.html">Clojure / Ruby/ Scala / Go 大亂鬥</a>
<ul>
    <li>還沒看完，不過應該還滿有趣的。</li>
</ul>
</li>
</ul>

<p>碎碎唸：</p>

<p>覺得不管語言本身是不是 immutable，你只要是在 Java 平台上，你就逃不過 mutable 的命運－－除非你願意放棄幾乎所有原本可以使用的 Java Library，包括標準函式庫（裡面幾乎全部都是 mutable 的東西啊）。</p>

<p>但，如果我要放棄 Java 平台上原有的函式庫，我幹嘛不去用 Haskell / Lisp / Scheme / Erlang 這些就好了呢？發展時間更久，資料齊全，千鎚百鍊，可以用的函式庫也更多，又少了 JVM 的包袱不是嗎？</p>
]]></content:encoded>
			<wfw:commentRss>http://bone.twbbs.org.tw/blog/archives/1348/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Maidroid Reminder 0.1.0 Released!</title>
		<link>http://bone.twbbs.org.tw/blog/archives/1319</link>
		<comments>http://bone.twbbs.org.tw/blog/archives/1319#comments</comments>
		<pubDate>Thu, 18 Feb 2010 09:06:14 +0000</pubDate>
		<dc:creator>墳墓 (BrianHsu)</dc:creator>
				<category><![CDATA[我的專業]]></category>

		<guid isPermaLink="false">http://bone.twbbs.org.tw/blog/?p=1319</guid>
		<description><![CDATA[【簡介】 各位熱愛 ACG 的紳士淑女們大家好，在去年的一整年，是不是為了老是忘記各項活動或是動畫的播放時間而煩惱呢？ 那麼，何不請一位專屬的妹斗桑來做為私人的貼身小秘書，讓她在特定的時間提醒您呢？ Maidroid Reminder 這次請來了米婭和小萌兩位可愛的女僕服務大家，只要把事情交待給這兩位可愛的女僕，時間到了她們兩位就會提醒各位紳士和淑女們喲！ 【畫面】 【特色】 單純的鬧鐘 萌 除了萌還是萌 似乎需要一些恥力才能在公開場合使用（第一次開啟請小心） 【平台】 HTC Magic / Hero / Tatto 其他使用 Android 1.5 以上之手機 【下載】 目前已經放在 Android Market 上『生產應用』類，可直接下載安裝 QR Code 如果您的手機沒有 Android Market，可以直接到以下網址下載安裝 http://bone.twbbs.org.tw/android/MaidroidReminder-0.1.0.apk 【感謝】 感謝 PTT 上的 whatzzz 以及 dicyia 版友的熱情幫助，可愛又容易害羞的米婭是由 whatzzz 作畫，獸耳萌到爆的小萌是 dicyia 版友的作品。 【附註】 程式本身有實作全語音機能，但因為沒有配音員，所以只能暫時借用 koebu 上面的一些配音……orz&#8230; 總之，在此強力徵求兩位可愛角色的配音員，如果您有興趣，歡迎連絡。同樣的，如果有版友有興趣製作其他的角色，也歡迎與我連絡。 【授權】 程式碼的部份採用 [...]]]></description>
			<content:encoded><![CDATA[<h2><strong>【簡介】</strong></h2>

<p>各位熱愛 ACG  的紳士淑女們大家好，在去年的一整年，是不是為了老是忘記各項活動或是動畫的播放時間而煩惱呢？</p>

<p>那麼，何不請一位專屬的妹斗桑來做為私人的貼身小秘書，讓她在特定的時間提醒您呢？</p>

<p>Maidroid Reminder 這次請來了米婭和小萌兩位可愛的女僕服務大家，只要把事情交待給這兩位可愛的女僕，時間到了她們兩位就會提醒各位紳士和淑女們喲！</p>

<h2><strong>【畫面】</strong></h2>

<p><a href="http://picasaweb.google.com/lh/photo/FFLiOLJPlp9q0-JqKVb_Dw?feat=embedwebsite"><img src="http://lh3.ggpht.com/_MdBWjiltj8o/S3zzf8a7EHI/AAAAAAAAIFQ/GGuow0yRjZM/s400/Mia01.jpeg" /></a>
<a href="http://picasaweb.google.com/lh/photo/ghtI5KbPsy8zLb1HSpjD1w?feat=embedwebsite"><img src="http://lh6.ggpht.com/_MdBWjiltj8o/S3zzgCghrCI/AAAAAAAAIFU/mMLYSUPHeMY/s400/Mia02.jpeg" /></a></p>

<h2><strong>【特色】</strong></h2>

<ul>
<li>單純的鬧鐘</li>
<li>萌</li>
<li>除了萌還是萌</li>
<li>似乎需要一些恥力才能在公開場合使用（第一次開啟請小心）</li>
</ul>

<h2><strong>【平台】</strong></h2>

<ul>
<li>HTC Magic / Hero / Tatto</li>
<li>其他使用 Android 1.5 以上之手機</li>
</ul>

<h2><strong>【下載】</strong></h2>

<ul>
<li>目前已經放在 Android Market 上『生產應用』類，可直接下載安裝

<ul>
<li><a href="http://bone.twbbs.org.tw/android/reminderQR.png">QR Code</a></li>
</ul></li>
<li>如果您的手機沒有 Android Market，可以直接到以下網址下載安裝

<ul>
<li><a href="http://bone.twbbs.org.tw/android/MaidroidReminder-0.1.0.apk">http://bone.twbbs.org.tw/android/MaidroidReminder-0.1.0.apk</a></li>
</ul></li>
</ul>

<h2><strong>【感謝】</strong></h2>

<p>感謝 PTT 上的 whatzzz 以及 dicyia 版友的熱情幫助，可愛又容易害羞的米婭是由 whatzzz 作畫，獸耳萌到爆的小萌是 dicyia  版友的作品。</p>

<h2><strong>【附註】</strong></h2>

<p>程式本身有實作全語音機能，但因為沒有配音員，所以只能暫時借用 koebu 上面的一些配音……orz&#8230;</p>

<p>總之，在此強力徵求兩位可愛角色的配音員，如果您有興趣，歡迎連絡。同樣的，如果有版友有興趣製作其他的角色，也歡迎與我連絡。</p>

<h2><strong>【授權】</strong></h2>

<p>程式碼的部份採用 GPL v3 授權，有興趣的朋友可以直接到 GitHub 挖出來看或隨便亂改。</p>
]]></content:encoded>
			<wfw:commentRss>http://bone.twbbs.org.tw/blog/archives/1319/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>自學組合語言的必備良方！</title>
		<link>http://bone.twbbs.org.tw/blog/archives/1301</link>
		<comments>http://bone.twbbs.org.tw/blog/archives/1301#comments</comments>
		<pubDate>Sun, 07 Feb 2010 03:37:18 +0000</pubDate>
		<dc:creator>墳墓 (BrianHsu)</dc:creator>
				<category><![CDATA[我的專業]]></category>

		<guid isPermaLink="false">http://bone.twbbs.org.tw/blog/?p=1301</guid>
		<description><![CDATA[話說其實從大學起就一直都很想學組合語言，但一直都沒能夠成功的進入組語的學習領域。 後來陸陸續續接觸了一些其他的程式語言，玩到 Functional Programming 之後，也漸漸地把學組合語言這件事給拋到腦後了，畢竟光是玩 Functional Programming 就已經玩不玩了說。 只是後來又不小心進到了需要慣 C 的工作領域，重新在 Linux Kerenel 下面打轉，於是學組語這個念頭又回來了－－畢竟，這是可是基礎中的基礎啊，而且追 Kernel 常常追到最後都是組語。 但問題是組語要怎麼學呢？我想一定也有很多想學組語，但和我一樣不得其門而入的朋友有相同的困擾。 以我自己而言，我有莫名其妙、不知道為何會出現的，從 80386 時代遺留下來的組語書籍（還用 PE2 咧），有自己去書局買的 NASM 的書，也有資工系開的組合語言課程的課本，甚至是網路上開放下載的教學書籍。 可是以上沒有任何一本書真正讓我進入組語的世界，理由很簡單－－這些書我怎麼看都覺得不對勁，不知道該如何寫出我的第一隻組語程式。 有的一開始就和你講什麼 MOVL 是幹嘛用的，ADD 又是啥，但卻又沒有一隻完整的程式可以執行試驗－－這樣根本就沒感覺啊！根本就不能從錯誤之中學習啊（例如隨便亂加兩個暫存器會怎樣）！ 有的嘛，遵照古老的傳統，一開始就寫一個 Hello World 給你，然後再告訴你不要管那些 include 的黑魔法，反正程式可以跑就好－－等一下，我學組語就是為了要了解最底層的運作，結果你叫我不要管他？ 總而言之，看這些書的挫敗感真的很大，也因為如此，我一直沒有真正下定決心好好把組合語言給學起來。 一直到前一陣子，我在 Hacking Thursday 的討論區上看到這一本超級棒的書籍－－Programming from the Ground Up，這真的是自學組合語言的好物啊！ 廢話不多說，我們來看書中第一個程式範例： .section .data .section .text .global _start _start: movl $1, %eax [...]]]></description>
			<content:encoded><![CDATA[<p>話說其實從大學起就一直都很想學組合語言，但一直都沒能夠成功的進入組語的學習領域。</p>

<p>後來陸陸續續接觸了一些其他的程式語言，玩到 Functional Programming 之後，也漸漸地把學組合語言這件事給拋到腦後了，畢竟光是玩 Functional Programming 就已經玩不玩了說。</p>

<p>只是後來又不小心進到了需要<a href="http://blog.linux.org.tw/~jserv/archives/001965.html">慣 C </a>的工作領域，重新在 Linux Kerenel 下面打轉，於是學組語這個念頭又回來了－－畢竟，這是可是基礎中的基礎啊，而且追 Kernel 常常追到最後都是組語。</p>

<p>但問題是組語要怎麼學呢？我想一定也有很多想學組語，但和我一樣不得其門而入的朋友有相同的困擾。</p>

<p>以我自己而言，我有莫名其妙、不知道為何會出現的，從 80386  時代遺留下來的組語書籍（還用 PE2 咧），有自己去書局買的 NASM 的書，也有資工系開的組合語言課程的課本，甚至是網路上開放下載的教學書籍。</p>

<p>可是以上沒有任何一本書真正讓我進入組語的世界，理由很簡單－－這些書我怎麼看都覺得不對勁，不知道該如何寫出我的第一隻組語程式。</p>

<p>有的一開始就和你講什麼 MOVL 是幹嘛用的，ADD 又是啥，但卻又沒有一隻完整的程式可以執行試驗－－這樣根本就沒感覺啊！根本就不能從錯誤之中學習啊（例如隨便亂加兩個暫存器會怎樣）！</p>

<p>有的嘛，遵照古老的傳統，一開始就寫一個 Hello World  給你，然後再告訴你不要管那些 include  的黑魔法，反正程式可以跑就好－－等一下，我學組語就是為了要了解最底層的運作，結果你叫我不要管他？</p>

<p>總而言之，看這些書的挫敗感真的很大，也因為如此，我一直沒有真正下定決心好好把組合語言給學起來。</p>

<p>一直到前一陣子，我在 <a href="http://hack.ingday.org/">Hacking Thursday</a> 的討論區上看到這一本超級棒的書籍－－<a href="http://groups.google.com/group/hackingthursday/browse_thread/thread/6cbcc38147f9b990">Programming from the Ground Up</a>，這真的是自學組合語言的好物啊！</p>

<p>廢話不多說，我們來看書中第一個程式範例：</p>

<pre class="brush: asm">.section .data
.section .text
.global  _start

_start:
    movl $1, %eax   # This is the linux kernel system call for exit
    movl $0, %ebx   # This is the status number return to OS
    int  $0x80      # This wake up the kernel to run system call</pre>

<p>三行程式，而且每一行書裡面都解釋的很清楚（是的，包括 System Call 的部份也有說明，雖然經過簡化與譬喻），沒有任何的黑魔法。</p>

<p>同時，你也可以亂改這個程式，例如試著改變 EBX 暫存器的值，讓他返回不同的值給 Shell，又或者亂改 EAX 裡面的值，然後讓他產生 Segmentation Falut 而當掉。</p>

<p>真是太神奇有趣了！這才叫學組語嘛。</p>

<p>我真的很佩服作者可以想出把程式的結束狀態代碼當成輸出這個點子，完全避開了其他書裡面為了要產生輸出而不得不先使用黑魔法的問題。</p>

<p>再舉另一個例子，他的第二隻程式是介紹控制流程和迴圈，要透過他介紹的各種跳躍指令找到一個數列裡的最大值，這隻程式如下：</p>

<pre class="brush: asm">.section .data

items:
    .long 3, 6, 7, 10, 22, 34, 12, 0

.section .text
.global  _start

_start:
    movl $0, %edi             # move 0 to index register
    movl items(,%edi,4), %eax # load the first number
    movl %eax, %ebx           # put it to the EBX (cureent biggest)

start_loop:
    cmpl $0, %eax             # check to see if we've hit the end
    je   loop_exit

    incl %edi                 # increment index by 1
    movl items(,%edi,4), %eax # load next number
    cmpl %ebx, %eax           # compare with current biggest
    jle  start_loop           # jump to start_loop if not bigger
    movl %eax, %ebx           # else move this value as the largest
    jmp  start_loop           # next turn

loop_exit:
    movl $1, %eax             # System Call exit (No. 1)
    int  $0x80                # Singal batman</pre>

<p>同樣的，這隻程式也是利用離開狀態做輸出－－所以你用到的，都是你學過的東西，沒有黑魔法，每一行每一行都可以解釋到底是在做什麼，讓你驗證你是不是真的了解他。</p>

<p>另外，他用的是 GNU as 的語法，這對我而言有以下幾個好處：</p>

<ul>
    <li>這是 Linux Kernel 裡面用的東西，我不用再去熟悉其他語法</li>
    <li>我只要有一台 Linux Box 就可以試著跑書裡的程式</li>
    <li>這意謂著你可以用 GCC 把 C 語言編譯到組合語言，然後和這本書裡面的範例做比對，例如講到 Function 的時候，你就可以寫幾個 C  語言函數來驗證書裡講的東西。</li>
</ul>

<p>所以我一定要大推這一本書的啊～～這本書真的是自學組語的必備良方，只要會一點程式設計，一定可以看得懂的好東西！</p>
]]></content:encoded>
			<wfw:commentRss>http://bone.twbbs.org.tw/blog/archives/1301/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>遞回只應天上有，凡人應當用迴圈。</title>
		<link>http://bone.twbbs.org.tw/blog/archives/1298</link>
		<comments>http://bone.twbbs.org.tw/blog/archives/1298#comments</comments>
		<pubDate>Sat, 06 Feb 2010 14:25:43 +0000</pubDate>
		<dc:creator>墳墓 (BrianHsu)</dc:creator>
				<category><![CDATA[Scala]]></category>
		<category><![CDATA[我的專業]]></category>

		<guid isPermaLink="false">http://bone.twbbs.org.tw/blog/?p=1298</guid>
		<description><![CDATA[距離脫離尼特族接近兩個星期了，工作方面還在努力學習中，大部份的時間都在追別人寫的東西，只有小修小改而已，希望自己也能加快腳步，盡量能夠早點弄熟自己要接手的東西吶。 回到正題，『遞迴只應天上有、凡人應當用迴圈』這句話應該不少人聽過了，我在很久很久以前也寫過一篇『Haskell 真的比較好懂和不容易出錯嗎？』的文章。 不過，事後證明，我錯了。我接觸了 Scala 之後，我認為這句話很有可能是錯的，遞迴加上 Pattern Matching 或許在某些時候真的比較好懂。 直接來看例子吧，這個例子很簡單：給一個 List，請找出最後一個元素。 程式碼如下： def last[T] (list: List[T]): T = list match { case x :: Nil => x // 如果這個值後面沒有東西，他就是目標 case x :: remain => last(remain) // 不然的話繼續處理剩下來的東西 case _ => throw new Exception("opps") // 不可能有這兩種以外的狀況 } 整個程式碼就和用說的一樣簡單容易理解，而另一個遞迴比較好懂的經典例子應該就是費伯納西數列了吧。 def fib (n: Int): Int = { n [...]]]></description>
			<content:encoded><![CDATA[<p>距離脫離尼特族接近兩個星期了，工作方面還在努力學習中，大部份的時間都在追別人寫的東西，只有小修小改而已，希望自己也能加快腳步，盡量能夠早點弄熟自己要接手的東西吶。</p>

<p>回到正題，『遞迴只應天上有、凡人應當用迴圈』這句話應該不少人聽過了，我在很久很久以前也寫過一篇『<a href="http://bone.twbbs.org.tw/blog/archives/941">Haskell 真的比較好懂和不容易出錯嗎？</a>』的文章。</p>

<p>不過，事後證明，我錯了。我接觸了 Scala 之後，我認為這句話很有可能是錯的，遞迴加上 Pattern Matching 或許在某些時候真的比較好懂。</p>

<p>直接來看例子吧，這個例子很簡單：給一個 List，請找出最後一個元素。</p>

<p>程式碼如下：</p>

<pre class="brush: scala">
def last[T] (list: List[T]): T = list match {
    case x :: Nil    => x                 // 如果這個值後面沒有東西，他就是目標
    case x :: remain => last(remain)      // 不然的話繼續處理剩下來的東西
    case _ => throw new Exception("opps") // 不可能有這兩種以外的狀況
}
</pre>

<p>整個程式碼就和用說的一樣簡單容易理解，而另一個遞迴比較好懂的經典例子應該就是費伯納西數列了吧。</p>

<pre class="brush: scala">
def fib (n: Int): Int = {
    n match {
        case 0 => 0                     // 如果是 fib(0) 就是 0
        case 1 => 1                     // 如果是 fib(1) 就是 1
        case x => fib (x-1) + fib (x-2) // 不然的話就是前兩項相加
    }
}
</pre>

<p>幾乎和用嘴巴上數學定義一模一樣。XD</p>

<p>但話說回來，我還是覺得 Haskell  很難懂，理由很簡單－－他只給你一種他認為『對』的方法來做事，但他的『對』不見得在每種情況下都是直覺的。</p>

<p>例如在我之前的那一篇文章裡提到的，『把 List 裡數字加總』這件事，如果是在 Scala 裡，可以分別寫出兩種版本：</p>

<pre class="brush: scala">
def sumByIterate (list: List[Int]): Int = {

    // 一開始計算機上是 0
    var sum: Int = 0

    // 一個個把 List 裡的元素加到計算機上
    for (x <- list) { sum = sum + x }

    // 其實上面那一句你也可以這樣寫
    // list.foreach {x => sum = sum + x}

    // 最後就是結果
    return sum
}
</pre>

<pre class="brush: scala">
def sumByRecursive (list: List[Int]): Int = {
    list match {
        case Nil     => 0
        case x :: xs => x + sumByRecursive(xs)
    }
}
</pre>

<p>我還是覺得 sumByIterate 比較好懂和直覺，三行解決，不用遞回，做的動作就和我們要利用計算機把一個數列給加總一模一樣。</p>

<p>我相信當你要拿計算機加總一個數列的時候，是不會去想『第一個數字再加上其剩下的數字的總合就是答案』這種事，或者去做『從數列最後一個開始往回加』的動作的。</p>

<p>畢竟，加總不就是一個一個把他給打到計算機裡嗎－－正是我們第一個版本做的事情。</p>

<p>所以我還是喜歡 Scala 這類 Multi-Paradigm  的程式語言－－給你一個完整的工具箱，裡面有各種扳手和鉗子，讓你決定哪一種比較合適，而不是只給一個平口老虎鉗，叫你什麼事都要用這隻老虎鉗來做……</p>
]]></content:encoded>
			<wfw:commentRss>http://bone.twbbs.org.tw/blog/archives/1298/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>[Scala] 簡簡單單做 Mock Object 及 BDD 單元測試。</title>
		<link>http://bone.twbbs.org.tw/blog/archives/1288</link>
		<comments>http://bone.twbbs.org.tw/blog/archives/1288#comments</comments>
		<pubDate>Sat, 16 Jan 2010 04:00:10 +0000</pubDate>
		<dc:creator>墳墓 (BrianHsu)</dc:creator>
				<category><![CDATA[Scala]]></category>
		<category><![CDATA[我的專業]]></category>

		<guid isPermaLink="false">http://bone.twbbs.org.tw/blog/?p=1288</guid>
		<description><![CDATA[話說在做單元測試的時候，Mock Object 是很常使用的技巧，可以協助開發者隔離實際的環境，或以人工方式產生錯誤，以加強測試環境的控制。 簡而言之，Mock Object 的精神就是將非你可以控制的部份獨立出來，設計成可以隨時以其他的實作取代。 在 Scala 裡面，要在做單元測試時使用 Mock Object 是相當簡單，只要使用內建的 Trait 就可以很容易的達成 Mock Object 的技巧，而且對於客戶端的使用者而言，並不會感覺到任何使用上的差異。 在這邊，我們使用上次實作的 GeoService 函式庫來做示範，首先先複習一下上次的函式庫（我有做一些小修正，不過介面是一樣的）。 package org.maidroid.utils import scala.io._ import scala.xml.XML import scala.xml.Node import scala.xml.Elem import java.net.URLEncoder case class GeoPlacemark (val query: String, val address: String, val accuracy: Int, val longitude: Double, val latitude: Double) { val longitudeE6 = (longitude [...]]]></description>
			<content:encoded><![CDATA[<p>話說在做單元測試的時候，<a href="http://en.wikipedia.org/wiki/Mock_object">Mock Object</a> 是很常使用的技巧，可以協助開發者隔離實際的環境，或以人工方式產生錯誤，以加強測試環境的控制。</p>

<p>簡而言之，Mock Object 的精神就是將非你可以控制的部份獨立出來，設計成可以隨時以其他的實作取代。</p>

<p>在 Scala 裡面，要在做單元測試時使用 Mock Object 是相當簡單，只要使用內建的 Trait 就可以很容易的達成 Mock Object 的技巧，而且對於客戶端的使用者而言，並不會感覺到任何使用上的差異。</p>

<p>在這邊，我們使用上次實作的 GeoService 函式庫來做示範，首先先複習一下上次的函式庫（我有做一些小修正，不過介面是一樣的）。</p>

<pre class="brush: scala">
package org.maidroid.utils

import scala.io._
import scala.xml.XML
import scala.xml.Node
import scala.xml.Elem
import java.net.URLEncoder

case class GeoPlacemark (val query: String, val address: String, 
                         val accuracy: Int, val longitude: Double,
                         val latitude: Double)
{
    val longitudeE6 = (longitude * 1E6) toInt
    val latitudeE6  = (latitude  * 1E6) toInt
}

class GeoService (val query: String, val locale: String)
{
    private var statusCode   = 0
    private var errorMessage = ""

    val placemarkList: List[GeoPlacemark] = doQuery ()

    def this (query: String) = this (query, "")
    def error = (statusCode, errorMessage)

    private def createGeoPlacemark (node: Node) = 
    {
        val address    = (node \ "address").text
        val accuracy   = (node \ "AddressDetails" \ "@Accuracy").text
        val coordinate = (node \ "Point").text.split (",").toList
        val List (longitude, latitude, _) = coordinate

        GeoPlacemark (query, address, accuracy.toInt, 
                      longitude.toDouble, latitude.toDouble)
    }

    private def loadXML = {
        val url = "http://maps.google.com/maps/geo?" +
                  "q=%s&#038;output=xml&#038;gl=%s".
                  format(URLEncoder.encode(query), locale)

        val source = Source.fromURL (url, "utf-8")
        val iter   = for (line <- source.getLines) yield line

        XML.loadString (iter.mkString)
    }

    private def doQuery () =
    {
        try {
            val xml = loadXML
            this.statusCode = (xml \ "Response" \ "Status" \ 
                               "code").text.toInt

            // code 200 means OK
            if (statusCode != 200) {
                throw new Exception ("Query Faild")
            }

            val placemark   = xml \ "Response" \ "Placemark"
            val addressList = for (node <- placemark) yield 
                                  createGeoPlacemark (node)

            addressList.toList
        } catch {
            case e => errorMessage = e.getMessage
                      Nil
        }
    }
}
</pre>

<p>上述的程式碼中，我們可以發現所謂『非我們所能控制』的部份，就是連到 Google Maps 服務取得 XML 文件的 loadXML  這個函式。</p>

<p>這就是我們要把它隔離的程式碼，所以我們先設計一個 Trait，裡面有一個 loadXML  函式的介面。</p>

<pre class="brush: scala">
trait LoadXML
{
    protected def loadXML: Elem
}
</pre>

<p>在這邊要注意的是，由於這個函式是內部使用，不應該透露給外界，所以我們將其宣告為 protected，這和 Java 的介面裡面只能有 public 不一樣。</p>

<p>接著，我們更改我們的 GeoService 的實作，要改的部份只有兩個：</p>

<ul>
<li>讓 GeoService mix-in LoadXML</li>
<li>將 GeoService#loadXML 的部份改成 override protected</li>
</ul>

<p>完整的程式碼如下：</p>

<pre class="brush: scala">
package org.maidroid.utils

import scala.io._
import scala.xml.XML
import scala.xml.Node
import scala.xml.Elem
import java.net.URLEncoder

trait LoadXML
{
    protected def loadXML: Elem
}

case class GeoPlacemark (val query: String, val address: String, 
                         val accuracy: Int, val longitude: Double,
                         val latitude: Double)
{
    val longitudeE6 = (longitude * 1E6) toInt
    val latitudeE6  = (latitude  * 1E6) toInt
}

class GeoService (val query: String, val locale: String) extends
      LoadXML
{
    private var statusCode   = 0
    private var errorMessage = ""

    val placemarkList: List[GeoPlacemark] = doQuery ()

    def this (query: String) = this (query, "")
    def error = (statusCode, errorMessage)

    private def createGeoPlacemark (node: Node) = 
    {
        val address    = (node \ "address").text
        val accuracy   = (node \ "AddressDetails" \ "@Accuracy").text
        val coordinate = (node \ "Point").text.split (",").toList
        val List (longitude, latitude, _) = coordinate

        GeoPlacemark (query, address, accuracy.toInt, 
                      longitude.toDouble, latitude.toDouble)
    }

    protected def loadXML = {
        val url = "http://maps.google.com/maps/geo?" +
                  "q=%s&#038;output=xml&#038;gl=%s".
                  format(URLEncoder.encode(query), locale)

        val source = Source.fromURL (url, "utf-8")
        val iter   = for (line <- source.getLines) yield line

        XML.loadString (iter.mkString)
    }

    private def doQuery () =
    {
        try {
            val xml = loadXML
            this.statusCode = (xml \ "Response" \ "Status" \ 
                               "code").text.toInt

            // code 200 means OK
            if (statusCode != 200) {
                throw new Exception ("Query Faild")
            }

            val placemark   = xml \ "Response" \ "Placemark"
            val addressList = for (node <- placemark) yield 
                                  createGeoPlacemark (node)

            addressList.toList
        } catch {
            case e => errorMessage = e.getMessage
                      Nil
        }
    }
}
</pre>

<p>什麼？結束了？！別懷疑，真的就只有這樣子而已，這正是 Scala  吸引我的地方，夠方便吧！</p>

<p>在測試開始之前，我們先來做幾個 Mock 來用吧，要做 Mock 很簡單，只要再宣告繼承 LoadXML 的 Trait 即可。在這次的測試中，我們建造了以下三個 Mock。</p>

<ul>
<li>正確的 XML 回傳值</li>
<li>錯誤的 XML 回傳值</li>
<li>執行期間發生連線錯誤的 Exception</li>
</ul>

<pre class="brush: scala">
// 正確的 XML 回傳值
trait MockXML extends LoadXML
{
    override def loadXML = 
    <kml xmlns="http://earth.google.com/kml/2.0">
      <Response>
      <!-- 此處省略，請照抄 Google Maps 傳回值 -->
      </Response>
    </kml>
}

// 錯誤的 XML 格式
trait WrongXML extends LoadXML
{
    override def loadXML = <root />
}

// 連線錯誤 Exception
trait ExceptionXML extends LoadXML
{
    override def loadXML = throw new java.net.ConnectException
}
</pre>

<p>有了這些 Mock 物件之後，就可以著手來寫單元測試了，在這裡所使用的是 <a href="http://www.scalatest.org/">ScalaTest</a> 這個支援多種單元測試風格的 Framework，我們用的是 FlatSpec 這個 Behavior Driven Development 測試。</p>

<p>由於使用 FlatSpec 所寫出的測試都相當直覺，看起來就像英文句子，所以程式碼的部份就不做詳細的解釋了。</p>

<p>在這邊要注意的地方，就是當我們要使用 Mock 的時候，直需要在建立物件時將要使用的 Mock 給 mix-in 進來就好，範例如下。</p>

<pre class="brush: scala">
// 不使用任何 Mock
val noMock = new GeoService ("中央研究院")

// 分別使用上述三種 Mock
val mock1 = new GeoService ("中央研究院") with MockXML
val mock2 = new GeoService ("中央研究院") with WrongXML
val mock3 = new GeoService ("中央研究院") with ExceptionXML
</pre>

<p>知道了上述的規則後，我們就可以使用這三個 Mock 撰寫我們的測試案例了，完整的測試案例如下。</p>

<pre class="brush: scala">
import org.scalatest.FlatSpec
import org.scalatest.matchers.ShouldMatchers
import org.maidroid.utils._

class GeoServiceSpec extends FlatSpec with ShouldMatchers 
{
    // 不使用任何 Mock 物件
    "A GeoService" should "retun a list of GeoPlacemark when successed" in {
        val service = new GeoService ("中央研究院")
        val correct = GeoPlacemark ("中央研究院", 
                                    "115 Taiwan Taipei City Nangang  "+
                                    "District中央研究院", 9, 
                                    121.6122646, 25.0405918)

        service.placemarkList should be === List (correct)

    }

    // 使用 MockXML 以保確取得正確的 XML 回傳值
    it should "has statusCode 200 and no error message when successed" in {
        val service = new GeoService ("中央研究院") with MockXML
        service.error should be === (200, "")
    }

    // 例用 WrongXML Mock 測試當回傳值為不合格式的 XML 時的狀況
    it should "has statusCode 0 and empty list when XML format is wrong" in {
        val service = new GeoService ("中央研究院") with WrongXML

        service.placemarkList should be === Nil
        service.error._1 should be === 0
    }

    // 例用 ExceptionXML 測試發生 Exception 時的行為
    it should "has statusCode 0 and empty list when Exception occurred" in {
        val service = new GeoService ("中央研究院") with ExceptionXML

        service.placemarkList should be === Nil
        service.error._1 should be === 0
    }
}
</pre>

<p>如何？要在 Scala 使用 Mock Object 進行單元測試很方便吧？！請多多利用這個技巧，讓單元測試變得更簡單愉快喲！</p>
]]></content:encoded>
			<wfw:commentRss>http://bone.twbbs.org.tw/blog/archives/1288/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>[Scala] 打造地址反查經緯度的簡易函式庫。</title>
		<link>http://bone.twbbs.org.tw/blog/archives/1275</link>
		<comments>http://bone.twbbs.org.tw/blog/archives/1275#comments</comments>
		<pubDate>Fri, 15 Jan 2010 04:27:54 +0000</pubDate>
		<dc:creator>墳墓 (BrianHsu)</dc:creator>
				<category><![CDATA[我的專業]]></category>

		<guid isPermaLink="false">http://bone.twbbs.org.tw/blog/?p=1275</guid>
		<description><![CDATA[話說 Android 裡的 Googple Maps API 沒有地址反查經緯度的功能，有點小不方便，於是我就自己弄一個簡單的 Scala 函式庫出來了。 這裡簡單介紹一下做法，首先一開始先來定義我們的使用者端介面。在這邊，由於 Google Maps 在查詢地址時返回的是一個列表，所以我們的函式庫也是傳回一個 List。 另外，像很多國家都有『南港』這個地名，為了縮小範圍，我們也定了另一個介面，可以指定查詢的國家。 整體使用的感覺如下： val sinica: List[GeoPlacemark] = new GeoService ("中央研究院") // 預設查詢 val nangang: List[GeoPlacemark] = new GeoService ("南港", "tw") // 指定國家 println (sinica.placemarkList) // 取得『中央研究院』的相關地理資料 println (nangang.placemarkList) // 取得『南港』的地理資料 在上面的程式裡，GeoPlacemark 的部份就是該地址的地理資訊，我們希望這個物件存放下列幾像資訊。 原始查詢字串 Google Maps 幫我們解析出的詳細地址 範圍精確度 經度 緯度 另外，我們也希望能夠有方便的函式可以幫我們把經度和緯度轉換成 GeoPoint 用的 [...]]]></description>
			<content:encoded><![CDATA[<p>話說 Android 裡的 Googple Maps API 沒有地址反查經緯度的功能，有點小不方便，於是我就自己弄一個簡單的 Scala 函式庫出來了。</p>

<p>這裡簡單介紹一下做法，首先一開始先來定義我們的使用者端介面。在這邊，由於 Google Maps 在查詢地址時返回的是一個列表，所以我們的函式庫也是傳回一個 List。</p>

<p>另外，像很多國家都有『南港』這個地名，為了縮小範圍，我們也定了另一個介面，可以指定查詢的國家。</p>

<p>整體使用的感覺如下：</p>

<pre class="brush: scala">
val sinica: List[GeoPlacemark]  = new GeoService ("中央研究院") // 預設查詢
val nangang: List[GeoPlacemark] = new GeoService ("南港", "tw") // 指定國家

println (sinica.placemarkList)  // 取得『中央研究院』的相關地理資料
println (nangang.placemarkList) // 取得『南港』的地理資料
</pre>

<p>在上面的程式裡，GeoPlacemark 的部份就是該地址的地理資訊，我們希望這個物件存放下列幾像資訊。</p>

<ul>
<li>原始查詢字串</li>
<li>Google Maps 幫我們解析出的詳細地址</li>
<li>範圍精確度</li>
<li>經度</li>
<li>緯度</li>
</ul>

<p>另外，我們也希望能夠有方便的函式可以幫我們把經度和緯度轉換成 GeoPoint 用的 microdegree。</p>

<p>由這邊可以看出來，將 GeoPlacemark 設計成 immutable 是比較合理的，因為你不應該手動更改任何查詢回來的經緯度結果。此外，在這邊我們需要的都只是單純的取得物件相關的資料，沒有什麼複雜的動作。</p>

<p>這種資料結構，在 Scala 裡最適合使用 case class 來實作了，我們實作出的程式碼如下。</p>

<pre class="brush: scala">
case class GeoPlacemark (val query: String, val address: String, 
                         val accuracy: Int, val longitude: Double,
                         val latitude: Double)
{
    val longitudeE6 = (longitude * 1E6) toInt
    val latitudeE6  = (latitude  * 1E6) toInt
}
</pre>

<p>在這段程式碼裡，我們宣告了一個 GeoPlacemark 的 case class，建構子傳入的參數剛好就是上面清單列出來的資料。至於 longitudeE6 和 latitudeE6 因為可以直接從傳入的經緯度推算，所以不用放在建構子中，使用 val 變數而不用 def 定義，是因為這樣這兩個計算只會在建立物件時執行一次而已。</p>

<p>別懷疑，就真的只有這樣而已。剩下的 Scala 都幫你搞定了，包括各個變數的 getter 以及相關的 toString() 和 hashCode() 這類東西，而且還可以用在 Pattern Matching 上！</p>

<p>接著來看我們的 GeoService 類別吧！這邊的重點其實不多，只有幾個而已。</p>

<p>首先，我們要從一個網址取回資料時，只要用 Scala.io.Source 就可以了。</p>

<pre class="brush: scala">
val url = "http://maps.google.com/maps/geo?q=%s&#038;output=xml&#038;gl=%s".
          format(query, locale)

val source = Source.fromURL (url, "utf-8")
val iter   = for (line <- source.getLines) yield line
val xml    = XML.loadString (iter.mkString)
</pre>

<p>裡面的 iter 會是一個 Iterator，每次一行，可以使用 iter.mkString 轉成字串，接著再用 scala.xml.XML.loadString 把他轉成 XML 資料結構，夠簡單吧？連 HTTP Connection 都不用建立了。如果只是單純的要抓網頁資料，像是 RSS/ATOM 的話，用內建的 io.Source 類別就很足夠了。</p>

<p>接著要檢查回傳值，如果 Google Maps 成功反解地址的話，會傳回 200。</p>

<pre class="brush: scala">
statusCode = (xml \ "Response" \ "Status" \ "code").text.toInt

// code 200 means OK
if (statusCode != 200) {
    throw new Exception ("Query Failed")
}

val placemark   = xml \ "Response" \ "Placemark"
val addressList = for (node <- placemark) yield 
                      createGeoPlacemark (node)
</pre>

<p>上面的程式碼裡，我們利用類似 XPath 的方式，取得 Status 下的 code 節點的內容，接著轉成整數，如果不是 200 代表查詢失敗。成功的話，把每一個 Placemark 節點丟到 createGeoPlacemark 裡，建立一個 GeoPlacemark 物件的 List。</p>

<pre class="brush: scala">
private def createGeoPlacemark (node: Node) = 
{
    val address    = (node \ "address").text
    val accuracy   = (node \ "AddressDetails" \ "@Accuracy").text
    val coordinate = (node \ "Point").text.split (",").toList
    val List (longitude, latitude, _) = coordinate

    GeoPlacemark (query, address, accuracy.toInt, 
                  longitude.toDouble, latitude.toDouble)
}
</pre>

<p>createGeoPlacemark 沒啥特別的，就是取得 XML 的內容，解析後把他丟給 GeoPlacemark 的建構子，產生 GeoPlacemark 物件而已。</p>

<p>結合上述所有的東西，我們的 GeoService 物件就出來啦。</p>

<pre class="brush: scala">
class GeoService (val query: String, val locale: String)
{
    lazy val placemarkList: List[GeoPlacemark] = doQuery ()

    private var statusCode   = 0
    private var errorMessage = ""

    def this (query: String) = this (query, "")
    def error = (statusCode, errorMessage)

    private def createGeoPlacemark (node: Node, query: String) = 
    {
        val address    = (node \ "address").text
        val accuracy   = (node \ "AddressDetails" \ "@Accuracy").text
        val coordinate = (node \ "Point").text.split (",").toList
        val List (longitude, latitude, _) = coordinate

        GeoPlacemark (query, address, accuracy.toInt, 
                      longitude.toDouble, latitude.toDouble)
    }

    private def doQuery () =
    {
        try {
            val url = "http://maps.google.com/maps/geo?q=%s&#038;output=xml&#038;gl=%s".
                      format(query, locale)

            val source = Source.fromURL (url, "utf-8")
            val iter   = for (line <- source.getLines) yield line
            val xml    = XML.loadString (iter.mkString)

            statusCode = (xml \ "Response" \ "Status" \ "code").text.toInt

            // code 200 means OK
            if (statusCode != 200) {
                throw new Exception ("Query Faild")
            }

            val placemark   = xml \ "Response" \ "Placemark"
            val addressList = for (node <- placemark) yield 
                                  createGeoPlacemark (node, query)

            addressList.toList
        } catch {
            case e => errorMessage = e.getMessage
                      Nil
        }
    }
}
</pre>

<p>這樣我們就完成了一個可以用地址來反查經緯度的函式庫了，夠簡單吧？最後，我們發現 doQuery 看起來有點複雜，其實可以把抓網頁轉成 XML 的部份再寫成另一個 loadXMLFromGoogleMaps 函式，所以來重構一下唄！</p>

<pre class="brush: scala">
class GeoService (val query: String, val locale: String)
{
    lazy val placemarkList: List[GeoPlacemark] = doQuery ()

    private var statusCode   = 0
    private var errorMessage = ""

    def this (query: String) = this (query, "")
    def error = (statusCode, errorMessage)

    private def createGeoPlacemark (node: Node) = 
    {
        val address    = (node \ "address").text
        val accuracy   = (node \ "AddressDetails" \ "@Accuracy").text
        val coordinate = (node \ "Point").text.split (",").toList
        val List (longitude, latitude, _) = coordinate

        GeoPlacemark (query, address, accuracy.toInt, 
                      longitude.toDouble, latitude.toDouble)
    }

    private def loadXMLFromGoogleMaps = {
        val url = "http://maps.google.com/maps/geo?q=%s&#038;output=xml&#038;gl=%s".
                  format(query, locale)

        val source = Source.fromURL (url, "utf-8")
        val iter   = for (line <- source.getLines) yield line
        val xml    = XML.loadString (iter.mkString)

        val statusCode = (xml \ "Response" \ "Status" \ "code").text.toInt

        (xml, statusCode)
    }

    private def doQuery () =
    {
        try {
            val (xml, statusCode) = loadXMLFromGoogleMaps

            // code 200 means OK
            if (statusCode != 200) {
                this.statusCode = statusCode
                throw new Exception ("Query Faild")
            }

            val placemark   = xml \ "Response" \ "Placemark"
            val addressList = for (node <- placemark) yield 
                                  createGeoPlacemark (node)

            addressList.toList
        } catch {
            case e => errorMessage = e.getMessage
                      Nil
        }
    }
}
</pre>

<p>如何？看起來清楚多了吧？</p>
]]></content:encoded>
			<wfw:commentRss>http://bone.twbbs.org.tw/blog/archives/1275/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
