Cody Bloghttps://blog.codylab.com/2021-06-22T09:47:01+08:002017 黃金海岸馬拉松2017-07-05T00:00:00+08:002021-06-22T08:49:09+08:00Cody Liutag:blog.codylab.com,2017-07-05:/running-gold-coast-marathon.md/<p><img alt="start" src="http://i.imgur.com/Ax92g95.jpg"></p>
<p>2017.7.2 黃金海岸馬拉松是我的第四馬,也是我海外的第二馬。2017年黃金海岸馬拉松全馬人數大約6千人,相比於我的上一場海外馬-東京馬的2萬多人,算是比較小型的賽事,不用人擠人又可以享受 IAAF Road Race 認證金牌規格賽事。這個賽事最大的特色就是全程 42 公里幾乎都是沿著海岸線跑,可以邊跑邊欣賞海岸線的美景。</p>
<p><img alt="gold-coast" src="http://i.imgur.com/1b7MTEY.jpg"></p>
<p>這次比賽前一個月的練習跑量大約是150公里。雖然不多,但我的目標就是希望比2014東京馬5:56記錄進步,然後不要受傷。賽前狀況都還不錯,沒有特別酸痛或是受傷的情況,我也臉書上面宣告我的目標成績為 5:30:
<img alt="target-530" src="http://i.imgur.com/K2OTopl.jpg"></p>
<p>黃金海岸馬拉松的賽道相當平坦,補給方面大約2.5公里就有一個水站或是水+運動飲料站,直到30公里才會有能量膠的補給。只是接近中午的時侯會有很大的太陽,氣溫偏熱。</p>
<p><img alt="route" src="http://i.imgur.com/3gEqZmU.jpg"></p>
<p><img alt="start" src="http://i.imgur.com/4sP8P6p.jpg">
依照賽前填的預估時間,我被分配到最後一區 ZONE D</p>
<p><img alt="start-2" src="http://i.imgur.com/o0cIqHJ.jpg">
槍響之後沿著人群慢慢前進</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Ll3pYO8yc38" frameborder="0" allowfullscreen></iframe>
<p><img alt="che-ming" src="http://i.imgur.com/dk2si4s.jpg">
這次跟從凱恩斯來的新朋友哲明一起出發,這天也剛好是他的生日,他說他想要黃金海岸馬拉松來當成他的生日禮物,這是他的初馬。</p>
<p><img alt="start" src="http://i.imgur.com/xks1dQR.jpg">
我們一開始設定一公里7分鐘的速度前進,跑著跑著,看著5小時的紅色配速員的氣球連我們愈來愈近。我評估了一下自己的狀況,呼吸都還很輕鬆,於是我們開始跟著5小時晶片時間的配速姐。</p>
<p><img alt="teresa-500" src="http://i.imgur.com/Ani87V9l.jpg"></p>
<p>配速姐出發沿路都放著音樂,蠻有激勵人心的效果</p>
<!--<iframe width="560" height="315" src="https://www.youtube.com/embed/hWPZmENwcBk" frameborder="0" allowfullscreen></iframe>-->
<p><img alt="8k" src="http://i.imgur.com/yqmICv6l.jpg"></p>
<p>第一個折返點</p>
<p><img alt="start" src="http://i.imgur.com/wXXsHQq.jpg"></p>
<p><img alt="turning-point" src="http://i.imgur.com/tdHEcwe.jpg"></p>
<p>沿路幾乎沒有私人補給,跟台灣、東京馬的賽事不同。這就是馬拉松文化的差異,澳洲民眾會很熱心幫你吶喊加油,不過沒有食物補給的習慣。整路我只有看到在 Suffers Paradise 看到有女生拿可樂跟巧克力分送給跑者。不過因為我事前就知道會有這樣的情況,出發前就準備了6條GU能量膠帶在身上。</p>
<p><img alt="marathon-man" src="http://i.imgur.com/CPpaLil.jpg">
澳洲人的跑馬數量的記錄保持者<a href="http://www.marathonman.com.au/about-trent/results/">Trent Morrow</a>,這是他的第313馬,他曾在2013年,單年跑了161場全馬的驚人記錄。</p>
<p><img alt="cheer-4" src="http://i.imgur.com/5diECRT.png"></p>
<p>賽道旁邊有很多加油的名眾,因為號碼布上面有自己的名字,所以很多人會直接喊你的名字幫你加油。 像是 Cody!! Keep going !!</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/qFWu6-PJAy0" frameborder="0" allowfullscreen></iframe>
<p><img alt="cheer-1" src="http://i.imgur.com/z4pBefC.jpg">
<img alt="cheer-3" src="http://i.imgur.com/1ih1OWB.jpg"></p>
<p><img alt="x" src="http://i.imgur.com/rxvpIOl.jpg"></p>
<p>26 K 之後天氣愈來愈熱,</p>
<p><img alt="justin" src="http://i.imgur.com/fzWu8wz.jpg"></p>
<p>連配速哥都沒辦法維持均速停了下來。最後晶片時間的配速姐幫忙了槍聲時間的配速哥,幫忙他完成接下來的配速。</p>
<p><img alt="img" src="http://i.imgur.com/LEOdLDi.jpg"></p>
<p>而在這邊真的愈來愈難跑,因為我就把手機收了起來 …</p><p><img alt="start" src="http://i.imgur.com/Ax92g95.jpg"></p>
<p>2017.7.2 黃金海岸馬拉松是我的第四馬,也是我海外的第二馬。2017年黃金海岸馬拉松全馬人數大約6千人,相比於我的上一場海外馬-東京馬的2萬多人,算是比較小型的賽事,不用人擠人又可以享受 IAAF Road Race 認證金牌規格賽事。這個賽事最大的特色就是全程 42 公里幾乎都是沿著海岸線跑,可以邊跑邊欣賞海岸線的美景。</p>
<p><img alt="gold-coast" src="http://i.imgur.com/1b7MTEY.jpg"></p>
<p>這次比賽前一個月的練習跑量大約是150公里。雖然不多,但我的目標就是希望比2014東京馬5:56記錄進步,然後不要受傷。賽前狀況都還不錯,沒有特別酸痛或是受傷的情況,我也臉書上面宣告我的目標成績為 5:30:
<img alt="target-530" src="http://i.imgur.com/K2OTopl.jpg"></p>
<p>黃金海岸馬拉松的賽道相當平坦,補給方面大約2.5公里就有一個水站或是水+運動飲料站,直到30公里才會有能量膠的補給。只是接近中午的時侯會有很大的太陽,氣溫偏熱。</p>
<p><img alt="route" src="http://i.imgur.com/3gEqZmU.jpg"></p>
<p><img alt="start" src="http://i.imgur.com/4sP8P6p.jpg">
依照賽前填的預估時間,我被分配到最後一區 ZONE D</p>
<p><img alt="start-2" src="http://i.imgur.com/o0cIqHJ.jpg">
槍響之後沿著人群慢慢前進</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Ll3pYO8yc38" frameborder="0" allowfullscreen></iframe>
<p><img alt="che-ming" src="http://i.imgur.com/dk2si4s.jpg">
這次跟從凱恩斯來的新朋友哲明一起出發,這天也剛好是他的生日,他說他想要黃金海岸馬拉松來當成他的生日禮物,這是他的初馬。</p>
<p><img alt="start" src="http://i.imgur.com/xks1dQR.jpg">
我們一開始設定一公里7分鐘的速度前進,跑著跑著,看著5小時的紅色配速員的氣球連我們愈來愈近。我評估了一下自己的狀況,呼吸都還很輕鬆,於是我們開始跟著5小時晶片時間的配速姐。</p>
<p><img alt="teresa-500" src="http://i.imgur.com/Ani87V9l.jpg"></p>
<p>配速姐出發沿路都放著音樂,蠻有激勵人心的效果</p>
<!--<iframe width="560" height="315" src="https://www.youtube.com/embed/hWPZmENwcBk" frameborder="0" allowfullscreen></iframe>-->
<p><img alt="8k" src="http://i.imgur.com/yqmICv6l.jpg"></p>
<p>第一個折返點</p>
<p><img alt="start" src="http://i.imgur.com/wXXsHQq.jpg"></p>
<p><img alt="turning-point" src="http://i.imgur.com/tdHEcwe.jpg"></p>
<p>沿路幾乎沒有私人補給,跟台灣、東京馬的賽事不同。這就是馬拉松文化的差異,澳洲民眾會很熱心幫你吶喊加油,不過沒有食物補給的習慣。整路我只有看到在 Suffers Paradise 看到有女生拿可樂跟巧克力分送給跑者。不過因為我事前就知道會有這樣的情況,出發前就準備了6條GU能量膠帶在身上。</p>
<p><img alt="marathon-man" src="http://i.imgur.com/CPpaLil.jpg">
澳洲人的跑馬數量的記錄保持者<a href="http://www.marathonman.com.au/about-trent/results/">Trent Morrow</a>,這是他的第313馬,他曾在2013年,單年跑了161場全馬的驚人記錄。</p>
<p><img alt="cheer-4" src="http://i.imgur.com/5diECRT.png"></p>
<p>賽道旁邊有很多加油的名眾,因為號碼布上面有自己的名字,所以很多人會直接喊你的名字幫你加油。 像是 Cody!! Keep going !!</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/qFWu6-PJAy0" frameborder="0" allowfullscreen></iframe>
<p><img alt="cheer-1" src="http://i.imgur.com/z4pBefC.jpg">
<img alt="cheer-3" src="http://i.imgur.com/1ih1OWB.jpg"></p>
<p><img alt="x" src="http://i.imgur.com/rxvpIOl.jpg"></p>
<p>26 K 之後天氣愈來愈熱,</p>
<p><img alt="justin" src="http://i.imgur.com/fzWu8wz.jpg"></p>
<p>連配速哥都沒辦法維持均速停了下來。最後晶片時間的配速姐幫忙了槍聲時間的配速哥,幫忙他完成接下來的配速。</p>
<p><img alt="img" src="http://i.imgur.com/LEOdLDi.jpg"></p>
<p>而在這邊真的愈來愈難跑,因為我就把手機收了起來,打算專心維持自己的速度。</p>
<p><img alt="tired" src="http://i.imgur.com/OAdN7ph.jpg"></p>
<p>30 K 之後,就遇到了撞牆期,大腿開始緊繃,感覺應該快要抽筋,於是就開始放慢速度,也就跟不上配速員了。最後的 12K 真的很難跑,開始改變策略,先穩定自己的速度,慢慢跑完全程。</p>
<p><img alt="tired" src="http://i.imgur.com/St0zeaH.jpg"></p>
<p>最後以晶片時間 5:06:30 完成,順利地達到我賽前設定的5小時30分的目標!</p>
<p><img alt="finish" src="http://i.imgur.com/WqVbDEn.jpg">
<img alt="finish" src="http://i.imgur.com/0CzmkZY.jpg"></p>
<h2>時間</h2>
<p><img alt="result" src="http://i.imgur.com/GmBelLk.jpg">
<img alt="split-time" src="http://i.imgur.com/kByqvey.jpg"></p>
<p>前面30K 都可以維持一公里7分鐘的速度。30~35剩下7:30,35~42只剩下8分速。這次跑完的狀態真的很好,相較之前跑完受傷鐵腿的完全不能走路的,這次只有腳指瘀青,跟輕微的擦傷。</p>
<p><img alt="finish-1" src="http://i.imgur.com/0w7G1zG.jpg"></p>
<h2>賽前的準備</h2>
<h3>能量膠 GEL</h3>
<p>這次大家都推薦 GU Roctane AUD 4/包</p>
<p><img alt="GU Roctane" src="http://i.imgur.com/bQ57Gxs.png"></p>
<p>我總共吃了6包,分別是 8K,15K,20K,25K,30K,35K。</p>
<h3>運動貼布</h3>
<p>保護膝蓋,貼上運動膠布,我的貼法是 Full Knee Support</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/v2xYUxXrjxk" frameborder="0" allowfullscreen></iframe>
<p>當地的 Bulletin 報紙也在隔天刊出了所有選手的成績,看到自己的名字列在上面還蠻有趣的。</p>
<p><img alt="newspaper" src="http://i.imgur.com/JjDrBEOl.jpg">
<img alt="newspaper" src="http://i.imgur.com/h0LFfm6.jpg">
<img alt="newspaper" src="http://i.imgur.com/iYINeaH.jpg">
<img alt="newspaper" src="http://i.imgur.com/1mcPHru.jpg"></p>
<p>iTaiwan 團體的兩位主辦人夫婦,感謝你們為台灣跑者盡心盡力</p>
<p><img alt="hill-venus" src="http://i.imgur.com/6P35bcC.jpg">
<img alt="sam" src="http://i.imgur.com/nFn7olv.jpg">
<img alt="flag2" src="http://i.imgur.com/0NtFtwy.jpg">
<img alt="flag" src="http://i.imgur.com/iqX0VBj.jpg"></p>
<h2>特別感謝</h2>
<p>最後想特別感謝 Justin Russ 跟 Teresa Cheung 兩位 5 小時的配速員,沒有你們的穩定配速跟中途持續的鼓勵,我應該沒辦法這麼順利完成這場馬拉松。</p>
<p><img alt="Justin Russ" src="http://i.imgur.com/kx24DL2.jpg">
<img alt="Teresa Cheung" src="http://i.imgur.com/J66hfoA.jpg"></p>
<p><img alt="metal" src="http://i.imgur.com/UkvsQ3g.jpg"></p>
<p>下一次朝向 4:30 的目標前進吧。</p>Data Sharing between Fragments and Activity2017-04-21T00:00:00+08:002018-03-30T04:40:30+08:00Cody Liutag:blog.codylab.com,2017-04-21:/activity-fragment-communication.md/<p>Source: <a href="https://goo.gl/5yQEGz">Data Sharing between Fragments and Activity in Android - Stack Overflow</a></p>
<h2>Activity -> Fragment [prefered]</h2>
<p>In your activity : create a bundle and use:</p>
<div class="highlight"><pre><span></span><code>fragment.setArguments(bundle)
</code></pre></div>
<p>In your fragment : use Bundle bundle:</p>
<div class="highlight"><pre><span></span><code>getArguments()
</code></pre></div>
<h2>Activity -> Fragment</h2>
<p>In your fragment : create a public method</p>
<div class="highlight"><pre><span></span><code>public void methodForActivity(...) {
...
}
</code></pre></div>
<p>In your activity : call an active fragment public method :</p>
<div class="highlight"><pre><span></span><code>getSupportFragmentManager().findFragmentById(R.id.your_fragment).publicMethod(args)
</code></pre></div>
<h2>Fragment -> Activity [prefered]</h2>
<p>In your fragment, create an interface with getter and setter methods to hold the interface reference which will be implemented by the activity.</p>
<p>In your activity, implement the interface, and using the setter method to pass self …</p><p>Source: <a href="https://goo.gl/5yQEGz">Data Sharing between Fragments and Activity in Android - Stack Overflow</a></p>
<h2>Activity -> Fragment [prefered]</h2>
<p>In your activity : create a bundle and use:</p>
<div class="highlight"><pre><span></span><code>fragment.setArguments(bundle)
</code></pre></div>
<p>In your fragment : use Bundle bundle:</p>
<div class="highlight"><pre><span></span><code>getArguments()
</code></pre></div>
<h2>Activity -> Fragment</h2>
<p>In your fragment : create a public method</p>
<div class="highlight"><pre><span></span><code>public void methodForActivity(...) {
...
}
</code></pre></div>
<p>In your activity : call an active fragment public method :</p>
<div class="highlight"><pre><span></span><code>getSupportFragmentManager().findFragmentById(R.id.your_fragment).publicMethod(args)
</code></pre></div>
<h2>Fragment -> Activity [prefered]</h2>
<p>In your fragment, create an interface with getter and setter methods to hold the interface reference which will be implemented by the activity.</p>
<p>In your activity, implement the interface, and using the setter method to pass self refernece to fragments.</p>
<h2>Fragment -> Activity</h2>
<p>In your activity : Create public getter and setter or other methods</p>
<p>In your fragment : called public activity getter, setter or other methods using :</p>
<div class="highlight"><pre><span></span><code>getActivity().getSomething()
</code></pre></div>British English Pronounciation Notes2017-04-21T00:00:00+08:002017-09-16T08:00:07+08:00Cody Liutag:blog.codylab.com,2017-04-21:/english-british/<p>The followings are notes from <a href="https://www.youtube.com/playlist?list=PLD6B222E02447DC07">BBC - The sounds of British English</a>. I listed all the example words so that we can reference it quickly if we have a doubt about the pronouciation.</p>
<h2>Short Vowel</h2>
<h3><a href="https://youtu.be/MAk-XtHsyzM">ɒ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/MAk-XtHsyzM" frameborder="0" allowfullscreen></iframe>
<p>lot, odd, wash</p>
<h3><a href="https://youtu.be/TNFKG0yvDx4">ɪ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/TNFKG0yvDx4" frameborder="0" allowfullscreen></iframe>
<p>kit, bid, hymn, minute.</p>
<h3><a href="https://youtu.be/eJ7dM_LU9t4">ʊ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/eJ7dM_LU9t4" frameborder="0" allowfullscreen></iframe>
<p>foot, put, good.</p>
<h3><a href="https://youtu.be/PZwKFFp7V50">ʌ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>strut, mud, love, blood <br>
ʌ, æ: undle, ankle; bunk, bank; but, bat; cup, cap; swum, swam</p>
<h3><a href="https://youtu.be/hLN1cdSTDo8">ɛ or e</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>dress, head, bed, many
ɛ, ɪ: bed, bid; medal, middle, dead, did, fell, fill, pen, pin
ɛ, eɪ: bed, bay</p>
<h3><a href="https://youtu.be/qVhaIHk88a8">æ or a</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>trap, stamp, back, lap, dad</p>
<h3><a href="https://youtu.be/wg0P0oYkniE">ə - schwa</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>a, the, of …</p><p>The followings are notes from <a href="https://www.youtube.com/playlist?list=PLD6B222E02447DC07">BBC - The sounds of British English</a>. I listed all the example words so that we can reference it quickly if we have a doubt about the pronouciation.</p>
<h2>Short Vowel</h2>
<h3><a href="https://youtu.be/MAk-XtHsyzM">ɒ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/MAk-XtHsyzM" frameborder="0" allowfullscreen></iframe>
<p>lot, odd, wash</p>
<h3><a href="https://youtu.be/TNFKG0yvDx4">ɪ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/TNFKG0yvDx4" frameborder="0" allowfullscreen></iframe>
<p>kit, bid, hymn, minute.</p>
<h3><a href="https://youtu.be/eJ7dM_LU9t4">ʊ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/eJ7dM_LU9t4" frameborder="0" allowfullscreen></iframe>
<p>foot, put, good.</p>
<h3><a href="https://youtu.be/PZwKFFp7V50">ʌ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>strut, mud, love, blood <br>
ʌ, æ: undle, ankle; bunk, bank; but, bat; cup, cap; swum, swam</p>
<h3><a href="https://youtu.be/hLN1cdSTDo8">ɛ or e</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>dress, head, bed, many
ɛ, ɪ: bed, bid; medal, middle, dead, did, fell, fill, pen, pin
ɛ, eɪ: bed, bay</p>
<h3><a href="https://youtu.be/qVhaIHk88a8">æ or a</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>trap, stamp, back, lap, dad</p>
<h3><a href="https://youtu.be/wg0P0oYkniE">ə - schwa</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>a, the, of, that</p>
<h2>Long Vowel</h2>
<h3><a href="https://youtu.be/RZmGzSb-6OM">iː</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>fleece, sea, machine
i, ɪ: litre, litter; cheap, chip, feet, fit; he's, his; peach, pitch; sheep, ship</p>
<h3><a href="https://youtu.be/mnKEGLuEzV4">uː</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>goose, two, blue, group</p>
<h3><a href="https://youtu.be/uDHMuMQdBNw">ɑː</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>father, start, hard</p>
<h3><a href="https://www.youtube.com/watch?v=KHllC40_u1Q">ɔː</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>thought, law, north, war</p>
<h3><a href="https://youtu.be/mnKEGLuEzV4">ʊː</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<h3><a href="https://youtu.be/hLN1cdSTDo8">ɛ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<h3><a href="https://youtu.be/zSJJWHymEPw">əː or ɜː</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>nurse, stir, learn, refer</p>
<h2>Diphthongs, Doubled Vowel</h2>
<h3><a href="https://youtu.be/vC0h4S0YPJc">ɪə</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>ear, hear, near: uk:nɪər, us:nɪr, weary.</p>
<h3><a href="https://youtu.be/nHSqluHrD-U">ʊə</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>tour, pure, cure</p>
<h3><a href="https://youtu.be/Hb8COxAtl14">aɪ, æɪ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>eye, price, high, try</p>
<h3><a href="https://youtu.be/lFRrEI85IcM">ɔɪ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>boy, choice, noise</p>
<h3><a href="https://youtu.be/r1BRCG0P9C8">əʊ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/" frameborder="0" allowfullscreen></iframe>
<p>boat, show, know
əʊ, ɔː coat, caught; dough, door;
sew, saw; flow, floor</p>
<h3><a href="https://youtu.be/9WDnVMQIaTs">aʊ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/9WDnVMQIaTs" frameborder="0" allowfullscreen></iframe>
<p>mouth, now, fowl
aʊ, əʊ: couch, coach; clown, clone; loud, load; found, phoned</p>
<h3><a href="https://youtu.be/0J7-5maJJIk">ɛː or eə</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/0J7-5maJJIk" frameborder="0" allowfullscreen></iframe>
<p>square, fair, pair, air
ɛː, æ: dared, dad; glared, glad; Mary, marry</p>
<h3><a href="https://youtu.be/5FMPlqlFt9g">eɪ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/5FMPlqlFt9g" frameborder="0" allowfullscreen></iframe>
<p>face, day, break.
eɪ, iː: ate, eat; faced, feast; great greet; mate, meet</p>
<h2>Voiceless Consonants</h2>
<h3><a href="https://youtu.be/rgWse3tloTw">ŋ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/rgWse3tloTw" frameborder="0" allowfullscreen></iframe>
<p>rung, anger, thanks
ŋ, n: rung, run; tongue, ton; wing, win; robbing, robin; singer, sinner</p>
<h3><a href="https://youtu.be/qkgucMjv4T0">n</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/qkgucMjv4T0" frameborder="0" allowfullscreen></iframe>
<p>nice, funny, son, none
n, ŋ(much further back in the mounth):
son, sung; pin, ping; ran, rang; thin, thing; wind, winged</p>
<h3><a href="https://youtu.be/0Te4Us8Tsv8">m</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/0Te4Us8Tsv8" frameborder="0" allowfullscreen></iframe>
<p>more, hammer, sum, mine
m, n, ŋ: sum, son, sung; rum, run, rung</p>
<h3><a href="https://youtu.be/_Fi9E6Yw-qg">j</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/_Fi9E6Yw-qg" frameborder="0" allowfullscreen></iframe>
<p>yet, use, yellow, useful
ju: bueaty, few, cute, accuse</p>
<h3><a href="https://youtu.be/AZRREr7DqqM">p</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/AZRREr7DqqM" frameborder="0" allowfullscreen></iframe>
<p>pack, pan, copy, happen,
hop, pop
p, b: pack, back, punch, bunch</p>
<h3><a href="https://youtu.be/0T1QYByMxrs">t</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/0T1QYByMxrs" frameborder="0" allowfullscreen></iframe>
<p>tin, button, get, tight
t, d: tin, din; to, do; town, down; eight, aid; bet, bed</p>
<h3><a href="https://youtu.be/NF92RdZC6wE">ʃ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/NF92RdZC6wE" frameborder="0" allowfullscreen></iframe>
<p>ship, sure, nation, fish, shush,</p>
<h3><a href="https://youtu.be/PykxZ5kkrjs">tʃ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/PykxZ5kkrjs" frameborder="0" allowfullscreen></iframe>
<p>choke, teacher, match, church
tʃ, dʒ: choke, joke; chunk, junk; rich, ridge; lunch, lunge;</p>
<h3><a href="https://youtu.be/d1jyIpAmLe8">k</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/d1jyIpAmLe8" frameborder="0" allowfullscreen></iframe>
<p>came, lucky, sick, clock
k, g: came, game; back, bag; cage, gauge; calories, galleries.</p>
<h3><a href="https://youtu.be/vE12RFyH-hY">f</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/vE12RFyH-hY" frameborder="0" allowfullscreen></iframe>
<p>fat, coffee, rough, fluff
f, v: fan, van; leaf, leave; off, of; rifle, rival;</p>
<h3><a href="https://youtu.be/QtH3vRXmvvo">s</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/QtH3vRXmvvo" frameborder="0" allowfullscreen></iframe>
<p>soon, mister, hiss, cease
s, z: hiss, his; course, cause; place, plays; gross, grows</p>
<h3><a href="https://youtu.be/b4Aj3k65HSo">θ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/b4Aj3k65HSo" frameborder="0" allowfullscreen></iframe>
<p>thin, throw, thumb, author, healthy, birth
, path.</p>
<h2>Voiced Consonants</h2>
<h3><a href="https://youtu.be/yP7aCKO6bTE">b</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/yP7aCKO6bTE" frameborder="0" allowfullscreen></iframe>
<p>back, bag, hobby, habit, job, bob
b, p: back, pack; bare, pair; cab, cap; symbol, simple;</p>
<h3><a href="https://youtu.be/qA5ZYC89oso">d</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/qA5ZYC89oso" frameborder="0" allowfullscreen></iframe>
<p>dame, ladder, odd, did
d, t: dame, tame; doom, tomb, medal, metal; heard, hurt</p>
<h3><a href="https://youtu.be/bTxeAiBF61I">ʒ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/bTxeAiBF61I" frameborder="0" allowfullscreen></iframe>
<p>leisure, pleasure, vision, beige</p>
<h3><a href="https://youtu.be/0IeQmGdo7gQ">dʒ</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/0IeQmGdo7gQ" frameborder="0" allowfullscreen></iframe>
<p>joke, lodger, bridge, judge
dʒ, tʃ: joke, choke, junk, chunk, lunge, lunch; surge, search
search</p>
<h3><a href="https://youtu.be/9eAqj9EfeK0">g</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/9eAqj9EfeK0" frameborder="0" allowfullscreen></iframe>
<p>glue, struggle, bag, gig
g, k: glue, clue; ghost, coast;log, lock;
pig, pick;</p>
<h3><a href="https://youtu.be/mO04G0v5a_c">v</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/mO04G0v5a_c" frameborder="0" allowfullscreen></iframe>
<p>very, heavy, move, verve
v, f: vault, fault; believe, belief; live, life;
v, b; very, berry; vet, bet; vote, boat;
vowel, bowel;</p>
<h3><a href="https://youtu.be/tu1t3Fn5Lw8">ð</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/tu1t3Fn5Lw8" frameborder="0" allowfullscreen></iframe>
<p>then, this, there, that, other, smooth,</p>
<h3><a href="https://youtu.be/o1ZvmX80t7Q">z</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/o1ZvmX80t7Q" frameborder="0" allowfullscreen></iframe>
<p>zero, music, buzz, roses
z, s: buzz, bus; rise, rice; zip, sip;
lazy, lacy;</p>
<h3><a href="https://youtu.be/DM_gN6imoC8">h</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/DM_gN6imoC8" frameborder="0" allowfullscreen></iframe>
<p>hear, hot, hello, ahead, height, hedge, how</p>
<h3><a href="https://youtu.be/CwWLgmMk0Z0">l</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/CwWLgmMk0Z0" frameborder="0" allowfullscreen></iframe>
<p>light, valley, bell, level
l, r: light, right; led, red; clash, crash; climb, crime; lice, rice; lock, rock;</p>
<h3><a href="https://youtu.be/Lxuo14hjP_8">r</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Lxuo14hjP_8" frameborder="0" allowfullscreen></iframe>
<p>right, wrong, sorry, arranges
r, l: wrong, long; roayl, loyal; misread, misled; pirate; pilot; pray, play;
r linking</p>
<h3><a href="https://youtu.be/Lxuo14hjP_8">w</a></h3>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Lxuo14hjP_8" frameborder="0" allowfullscreen></iframe>
<p>wet, one, when, beware, quick, queen
w, v: worse, verse; while, vile; west, vast; wary, vary;</p>
<h3>Distinguish ʒ(yogh) from dʒ</h3>
<ul>
<li><a href="https://youtu.be/bTxeAiBF61I">BBC - ʒ</a></li>
<li><a href="https://youtu.be/Gy9ak4sIWdI">EnglishCentral - ʒ</a></li>
<li><a href="https://youtu.be/j97p-_Xp8cc">American English Daily - ʒ</a></li>
<li>
<p><a href="https://youtu.be/0IeQmGdo7gQ">BBC - dʒ</a></p>
</li>
<li>
<p>ʃ: ship, sure, nation, fish, shush; sciencing sound</p>
</li>
<li>ʒ: leisure, pleasure, vision, beige</li>
<li>tʃ: choke, teacher, match, church</li>
<li>dʒ: joke, lodger, bridge, judge</li>
<li>ʃ -> ʒ; tʃ -> dʒ</li>
<li>dƷ can't extending; viƷƷƷƷƷən can extending.</li>
</ul>
<h2>Reference</h2>
<ul>
<li><a href="https://www.youtube.com/playlist?list=PLcetZ6gSk96-ayXj5thbTpbh2vHWpP08o">Pronunciation - Tim's Pronunciation Workshop</a></li>
</ul>Pass an object between activities on Android2017-04-09T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2017-04-09:/parcel-pass-object/<p>Passing an object from between activities needs some extra efforts, there are at least three ways to archive this goal:</p>
<ol>
<li>Using a serializable interface</li>
<li>Using a parcelable interface</li>
<li>Using Google's Gson library to convert from an object to a JSON string</li>
</ol>
<h2>Scenario</h2>
<p>For instance, passing two strings to another activity could be archived like this:</p>
<div class="highlight"><pre><span></span><code>Intent intent = new Intent(context, SecondActivity.class);
intent.putExtra(KEY_DOG_NAME, dogName);
intent.putExtra(KEY_DOG_OWNER, dogOwnerName);
</code></pre></div>
<p>If there are too many parameters, we can encapsulate them into a dog object:</p>
<div class="highlight"><pre><span></span><code>public class Dog {
private String mName;
private String mOwner;
public Dog(String name, String owner) {
this …</code></pre></div><p>Passing an object from between activities needs some extra efforts, there are at least three ways to archive this goal:</p>
<ol>
<li>Using a serializable interface</li>
<li>Using a parcelable interface</li>
<li>Using Google's Gson library to convert from an object to a JSON string</li>
</ol>
<h2>Scenario</h2>
<p>For instance, passing two strings to another activity could be archived like this:</p>
<div class="highlight"><pre><span></span><code>Intent intent = new Intent(context, SecondActivity.class);
intent.putExtra(KEY_DOG_NAME, dogName);
intent.putExtra(KEY_DOG_OWNER, dogOwnerName);
</code></pre></div>
<p>If there are too many parameters, we can encapsulate them into a dog object:</p>
<div class="highlight"><pre><span></span><code>public class Dog {
private String mName;
private String mOwner;
public Dog(String name, String owner) {
this.mName = name;
this.mOwner = owner;
}
...
}
</code></pre></div>
<p>However, Only primitive types, serializable and parcelable could be transferred to another activity. In the following, I will demonstrate how to get these done with examples.</p>
<h2>Serializable</h2>
<div class="highlight"><pre><span></span><code><span class="n">public</span> <span class="k">class</span> <span class="n">SerializableDog</span> <span class="k">extends</span> <span class="n">Dog</span> <span class="n">implements</span> <span class="n">Serializable</span> <span class="p">{</span>
<span class="n">private</span> <span class="nb nb-Type">String</span> <span class="n">mName</span><span class="p">;</span>
<span class="n">private</span> <span class="nb nb-Type">String</span> <span class="n">mOwner</span><span class="p">;</span>
<span class="n">public</span> <span class="n">SerializableDog</span><span class="p">(</span><span class="nb nb-Type">String</span> <span class="n">name</span><span class="p">,</span> <span class="nb nb-Type">String</span> <span class="n">owner</span><span class="p">)</span> <span class="p">{</span>
<span class="n">super</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">owner</span><span class="p">);</span>
<span class="n">this</span><span class="o">.</span><span class="n">mName</span> <span class="o">=</span> <span class="n">name</span><span class="p">;</span>
<span class="n">this</span><span class="o">.</span><span class="n">mOwner</span> <span class="o">=</span> <span class="n">owner</span><span class="p">;</span>
<span class="p">}</span>
<span class="err">@</span><span class="n">Override</span>
<span class="n">public</span> <span class="nb nb-Type">String</span> <span class="n">getName</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">mName</span><span class="p">;</span>
<span class="p">}</span>
<span class="err">@</span><span class="n">Override</span>
<span class="n">public</span> <span class="nb nb-Type">String</span> <span class="n">getOwnerName</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">mOwner</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>Here is an example that a SerialzableDog class extends Serializable. Please note that we need to define the data fields must be defined here.</p>
<h2>Parcel</h2>
<p><a href="https://goo.gl/Ieh8YM">Parcel</a> is a container for a message(data and object reference) that can be sent through an IBinder. Here is a basic example:</p>
<div class="highlight"><pre><span></span><code><span class="k">public</span><span class="w"> </span><span class="k">class</span><span class="w"> </span><span class="n">ParcelableDog</span><span class="w"> </span><span class="n">extends</span><span class="w"> </span><span class="n">Dog</span><span class="w"> </span><span class="n">implements</span><span class="w"> </span><span class="n">Parcelable</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="nv">@Override</span><span class="w"></span>
<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="nc">int</span><span class="w"> </span><span class="n">describeContents</span><span class="p">()</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="err">}</span><span class="w"></span>
<span class="w"> </span><span class="nv">@Override</span><span class="w"></span>
<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">void</span><span class="w"> </span><span class="n">writeToParcel</span><span class="p">(</span><span class="n">Parcel</span><span class="w"> </span><span class="k">out</span><span class="p">,</span><span class="w"> </span><span class="nc">int</span><span class="w"> </span><span class="n">flags</span><span class="p">)</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="k">out</span><span class="p">.</span><span class="n">writeString</span><span class="p">(</span><span class="n">getName</span><span class="p">());</span><span class="w"></span>
<span class="w"> </span><span class="k">out</span><span class="p">.</span><span class="n">writeString</span><span class="p">(</span><span class="n">getOwnerName</span><span class="p">());</span><span class="w"></span>
<span class="w"> </span><span class="err">}</span><span class="w"></span>
<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="k">static</span><span class="w"> </span><span class="n">final</span><span class="w"> </span><span class="n">Parcelable</span><span class="p">.</span><span class="n">Creator</span><span class="o"><</span><span class="n">ParcelableDog</span><span class="o">></span><span class="w"> </span><span class="n">CREATOR</span><span class="w"></span>
<span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Parcelable</span><span class="p">.</span><span class="n">Creator</span><span class="o"><</span><span class="n">ParcelableDog</span><span class="o">></span><span class="p">()</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">ParcelableDog</span><span class="w"> </span><span class="n">createFromParcel</span><span class="p">(</span><span class="n">Parcel</span><span class="w"> </span><span class="ow">in</span><span class="p">)</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">ParcelableDog</span><span class="p">(</span><span class="ow">in</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="err">}</span><span class="w"></span>
<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">ParcelableDog</span><span class="err">[]</span><span class="w"> </span><span class="n">newArray</span><span class="p">(</span><span class="nc">int</span><span class="w"> </span><span class="k">size</span><span class="p">)</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">ParcelableDog</span><span class="o">[</span><span class="n">size</span><span class="o">]</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="err">}</span><span class="w"></span>
<span class="w"> </span><span class="err">}</span><span class="p">;</span><span class="w"></span>
<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">ParcelableDog</span><span class="p">(</span><span class="n">Parcel</span><span class="w"> </span><span class="ow">in</span><span class="p">)</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="n">super</span><span class="p">(</span><span class="ow">in</span><span class="p">.</span><span class="n">readString</span><span class="p">(),</span><span class="w"> </span><span class="ow">in</span><span class="p">.</span><span class="n">readString</span><span class="p">());</span><span class="w"></span>
<span class="w"> </span><span class="err">}</span><span class="w"></span>
<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">ParcelableDog</span><span class="p">(</span><span class="n">String</span><span class="w"> </span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">owner</span><span class="p">)</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="n">super</span><span class="p">(</span><span class="n">name</span><span class="p">,</span><span class="w"> </span><span class="n">owner</span><span class="p">);</span><span class="w"></span>
<span class="w"> </span><span class="err">}</span><span class="w"></span>
<span class="err">}</span><span class="w"></span>
</code></pre></div>
<h2>Gson</h2>
<p>Using <a href="https://github.com/google/gson">Gson</a>, you don't need to modify the existing object implementation.</p>
<p>Serialize an object to JSON string:</p>
<div class="highlight"><pre><span></span><code>String dogJson = new Gson().toJson(new Dog("Dodo", "Cody"));
startActivity(SecondActivity.newIntent(this, dogJson));
</code></pre></div>
<p>Deserialize JSON string to a basic object:</p>
<div class="highlight"><pre><span></span><code><span class="nv">String</span> <span class="nv">dogGson</span> <span class="o">=</span> <span class="nv">getIntent</span><span class="ss">()</span>.<span class="nv">getStringExtra</span><span class="ss">(</span><span class="nv">KEY_DOG_GSON</span><span class="ss">)</span><span class="c1">;</span>
<span class="k">if</span><span class="ss">(</span><span class="nv">dogGson</span> <span class="o">!=</span> <span class="nv">null</span><span class="ss">)</span>{
<span class="nv">Gson</span> <span class="nv">gson</span> <span class="o">=</span> <span class="nv">new</span> <span class="nv">Gson</span><span class="ss">()</span><span class="c1">;</span>
<span class="nv">Dog</span> <span class="nv">dog</span> <span class="o">=</span> <span class="nv">gson</span>.<span class="nv">fromJson</span><span class="ss">(</span><span class="nv">dogGson</span>, <span class="nv">Dog</span>.<span class="nv">class</span><span class="ss">)</span><span class="c1">;</span>
}
</code></pre></div>
<h2>Conclusion</h2>
<ol>
<li>Serializable is easier to implement than parcel</li>
<li>Parcel is faster, but it is only available on Android and <a href="https://goo.gl/xzyINb">it is not appropriate to save into a file</a>.</li>
<li>Parcel array could be passed via intent</li>
<li>Gson is the most straightforward way to use. No modification needed to existed classes</li>
</ol>
<h2>Github</h2>
<p>I have created a <a href="https://github.com/cwliu/demo-parcel">github repo</a> for the demo codes used in the above.</p>
<p><img alt="activity-1" src="https://i.imgur.com/3ZAm9ZKl.png">
<img alt="activity-2" src="https://i.imgur.com/AqsfNThl.png"></p>
<h2>Reference</h2>
<ul>
<li><a href="https://goo.gl/DZspiO">Stack Overflow Discussion</a></li>
<li><a href="http://www.parcelabler.com/">parcelabler - Android Parcelable implementation creator</a></li>
</ul>Parsing JSON string on Android2016-10-07T00:00:00+08:002017-05-31T07:58:16+08:00Cody Liutag:blog.codylab.com,2016-10-07:/android-json/<p>Given a json string, you could convert it to either <code>JSONObject(str)</code> or <code>JSONArray(str)</code>. For example, This json response is from weather forecaset server:</p>
<div class="highlight"><pre><span></span><code>http://api.openweathermap.org/data/2.5/forecast/daily?zip=545%2Ctw&mode=json&units=metric&cnt=7&appid=aa032e548c67daa9cd1bc64eec737960
</code></pre></div>
<p>The response json format is like this:</p>
<p><img alt="json" src="https://i.imgur.com/KFAewvX.png"></p>
<p>If you want to get the first max temperature value: <code>17.06</code>:</p>
<div class="highlight"><pre><span></span><code> JSONObject weather = new JSONObject(weatherJsonStr);
JSONArray daysWeather = weather.getJSONArray("list");
JSONObject dayWeather = daysWeather.getJSONObject(0);
JSONObject dayTemperature = dayWeather.getJSONObject("temp");
int maxTemp = dayTemperature.getDouble("max");
</code></pre></div>
<p>Note that there may has a <code>JSONException</code> when the json tring …</p><p>Given a json string, you could convert it to either <code>JSONObject(str)</code> or <code>JSONArray(str)</code>. For example, This json response is from weather forecaset server:</p>
<div class="highlight"><pre><span></span><code>http://api.openweathermap.org/data/2.5/forecast/daily?zip=545%2Ctw&mode=json&units=metric&cnt=7&appid=aa032e548c67daa9cd1bc64eec737960
</code></pre></div>
<p>The response json format is like this:</p>
<p><img alt="json" src="https://i.imgur.com/KFAewvX.png"></p>
<p>If you want to get the first max temperature value: <code>17.06</code>:</p>
<div class="highlight"><pre><span></span><code> JSONObject weather = new JSONObject(weatherJsonStr);
JSONArray daysWeather = weather.getJSONArray("list");
JSONObject dayWeather = daysWeather.getJSONObject(0);
JSONObject dayTemperature = dayWeather.getJSONObject("temp");
int maxTemp = dayTemperature.getDouble("max");
</code></pre></div>
<p>Note that there may has a <code>JSONException</code> when the json tring is invalid, you need to add <code>try-catch</code> for this.</p>
<p>public class WooliesCrawler {</p>
<div class="highlight"><pre><span></span><code><span class="k">static</span> <span class="k">class</span> <span class="n">Product</span><span class="p">{</span>
<span class="n">private</span> <span class="nb nb-Type">int</span> <span class="n">mStockCode</span><span class="p">;</span>
<span class="n">private</span> <span class="nb nb-Type">String</span> <span class="n">mName</span><span class="p">;</span>
<span class="n">private</span> <span class="nb nb-Type">float</span> <span class="n">mPrice</span><span class="p">;</span>
<span class="n">private</span> <span class="nb nb-Type">float</span> <span class="n">mWasPrice</span><span class="p">;</span>
<span class="n">private</span> <span class="nb nb-Type">float</span> <span class="n">mCupPrice</span><span class="p">;</span>
<span class="n">private</span> <span class="nb nb-Type">String</span> <span class="n">mCupMeasure</span><span class="p">;</span>
<span class="n">private</span> <span class="n">boolean</span> <span class="n">mIsAvailable</span><span class="p">;</span>
<span class="n">public</span> <span class="n">Product</span><span class="p">(</span><span class="nb nb-Type">String</span> <span class="n">name</span><span class="p">,</span> <span class="nb nb-Type">int</span> <span class="n">stockCode</span><span class="p">,</span> <span class="nb nb-Type">float</span> <span class="n">price</span><span class="p">,</span> <span class="nb nb-Type">float</span> <span class="n">wasPrice</span><span class="p">,</span> <span class="nb nb-Type">float</span> <span class="n">cupPrice</span><span class="p">,</span> <span class="nb nb-Type">String</span> <span class="n">cupMeasure</span><span class="p">,</span> <span class="n">boolean</span> <span class="n">isAvailable</span><span class="p">)</span> <span class="p">{</span>
<span class="n">mStockCode</span> <span class="o">=</span> <span class="n">stockCode</span><span class="p">;</span>
<span class="n">mName</span> <span class="o">=</span> <span class="n">name</span><span class="p">;</span>
<span class="n">mPrice</span> <span class="o">=</span> <span class="n">price</span><span class="p">;</span>
<span class="n">mWasPrice</span> <span class="o">=</span> <span class="n">wasPrice</span><span class="p">;</span>
<span class="n">mCupPrice</span> <span class="o">=</span> <span class="n">cupPrice</span><span class="p">;</span>
<span class="n">mCupMeasure</span> <span class="o">=</span> <span class="n">cupMeasure</span><span class="p">;</span>
<span class="n">mIsAvailable</span> <span class="o">=</span> <span class="n">isAvailable</span><span class="p">;</span>
<span class="p">}</span>
<span class="err">@</span><span class="n">Override</span>
<span class="n">public</span> <span class="nb nb-Type">String</span> <span class="n">toString</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="nb nb-Type">String</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="s2">"</span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2">"</span><span class="p">,</span> <span class="n">mStockCode</span><span class="p">,</span> <span class="n">mName</span><span class="p">,</span> <span class="n">mWasPrice</span><span class="p">,</span> <span class="n">mPrice</span><span class="p">,</span> <span class="n">mIsAvailable</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">public</span> <span class="k">static</span> <span class="n">void</span> <span class="n">downloadProducts</span><span class="p">(</span><span class="n">final</span> <span class="n">Context</span> <span class="n">context</span><span class="p">,</span> <span class="n">final</span> <span class="nb nb-Type">int</span> <span class="n">pageNumber</span><span class="p">){</span>
<span class="n">RequestQueue</span> <span class="n">queue</span> <span class="o">=</span> <span class="n">Volley</span><span class="o">.</span><span class="n">newRequestQueue</span><span class="p">(</span><span class="n">context</span><span class="p">);</span>
<span class="nb nb-Type">int</span> <span class="n">groupId</span> <span class="o">=</span> <span class="mi">1018</span><span class="p">;</span>
<span class="n">final</span> <span class="nb nb-Type">int</span> <span class="n">pageSize</span> <span class="o">=</span> <span class="mi">100</span><span class="p">;</span>
<span class="nb nb-Type">String</span> <span class="n">urlFormat</span> <span class="o">=</span> <span class="s2">"https://www.woolworths.com.au/apis/ui/Product/Specials/half-price?GroupID=</span><span class="si">%s</span><span class="s2">&pageNumber=</span><span class="si">%s</span><span class="s2">&pageSize=</span><span class="si">%s</span><span class="s2">"</span><span class="p">;</span>
<span class="nb nb-Type">String</span> <span class="n">url</span> <span class="o">=</span> <span class="nb nb-Type">String</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">urlFormat</span><span class="p">,</span> <span class="n">groupId</span><span class="p">,</span> <span class="n">pageNumber</span><span class="p">,</span> <span class="n">pageSize</span><span class="p">);</span>
<span class="n">StringRequest</span> <span class="n">request</span> <span class="o">=</span> <span class="n">new</span> <span class="n">StringRequest</span><span class="p">(</span><span class="n">Request</span><span class="o">.</span><span class="n">Method</span><span class="o">.</span><span class="n">GET</span><span class="p">,</span> <span class="n">url</span><span class="p">,</span>
<span class="n">new</span> <span class="n">Response</span><span class="o">.</span><span class="n">Listener</span><span class="o"><</span><span class="nb nb-Type">String</span><span class="o">></span><span class="p">()</span> <span class="p">{</span>
<span class="err">@</span><span class="n">Override</span>
<span class="n">public</span> <span class="n">void</span> <span class="n">onResponse</span><span class="p">(</span><span class="nb nb-Type">String</span> <span class="n">response</span><span class="p">)</span> <span class="p">{</span>
<span class="n">List</span><span class="o"><</span><span class="n">Product</span><span class="o">></span> <span class="n">productList</span> <span class="o">=</span> <span class="n">new</span> <span class="n">ArrayList</span><span class="o"><></span><span class="p">();</span>
<span class="nb nb-Type">String</span> <span class="n">text</span> <span class="o">=</span> <span class="n">response</span><span class="p">;</span>
<span class="n">try</span> <span class="p">{</span>
<span class="n">JSONObject</span> <span class="n">root</span> <span class="o">=</span> <span class="n">new</span> <span class="n">JSONObject</span><span class="p">(</span><span class="n">text</span><span class="p">);</span>
<span class="n">JSONArray</span> <span class="n">items</span> <span class="o">=</span> <span class="n">root</span><span class="o">.</span><span class="n">getJSONArray</span><span class="p">(</span><span class="s2">"Items"</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="nb nb-Type">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">items</span><span class="o">.</span><span class="n">length</span><span class="p">();</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="n">JSONObject</span> <span class="n">itemList</span> <span class="o">=</span> <span class="p">(</span><span class="n">JSONObject</span><span class="p">)</span> <span class="n">items</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">i</span><span class="p">);</span>
<span class="n">JSONArray</span> <span class="n">products</span> <span class="o">=</span> <span class="n">itemList</span><span class="o">.</span><span class="n">getJSONArray</span><span class="p">(</span><span class="s2">"Products"</span><span class="p">);</span>
<span class="n">JSONObject</span> <span class="n">productJson</span> <span class="o">=</span> <span class="p">(</span><span class="n">JSONObject</span><span class="p">)</span> <span class="n">products</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="nb nb-Type">String</span> <span class="n">name</span> <span class="o">=</span> <span class="n">productJson</span><span class="o">.</span><span class="n">getString</span><span class="p">(</span><span class="s2">"Name"</span><span class="p">);</span>
<span class="nb nb-Type">int</span> <span class="n">stockCode</span> <span class="o">=</span> <span class="n">productJson</span><span class="o">.</span><span class="n">getInt</span><span class="p">(</span><span class="s2">"Stockcode"</span><span class="p">);</span>
<span class="nb nb-Type">float</span> <span class="n">price</span> <span class="o">=</span> <span class="p">(</span><span class="nb nb-Type">float</span><span class="p">)</span> <span class="n">productJson</span><span class="o">.</span><span class="n">getDouble</span><span class="p">(</span><span class="s2">"Price"</span><span class="p">);</span>
<span class="nb nb-Type">float</span> <span class="n">wasPrice</span> <span class="o">=</span> <span class="p">(</span><span class="nb nb-Type">float</span><span class="p">)</span> <span class="n">productJson</span><span class="o">.</span><span class="n">getDouble</span><span class="p">(</span><span class="s2">"WasPrice"</span><span class="p">);</span>
<span class="nb nb-Type">String</span> <span class="n">cupMeasure</span> <span class="o">=</span> <span class="n">productJson</span><span class="o">.</span><span class="n">getString</span><span class="p">(</span><span class="s2">"CupMeasure"</span><span class="p">);</span>
<span class="nb nb-Type">float</span> <span class="n">cupPrice</span> <span class="o">=</span> <span class="p">(</span><span class="nb nb-Type">float</span><span class="p">)</span> <span class="n">productJson</span><span class="o">.</span><span class="n">getDouble</span><span class="p">(</span><span class="s2">"CupPrice"</span><span class="p">);</span>
<span class="n">boolean</span> <span class="n">isAvailable</span> <span class="o">=</span> <span class="n">productJson</span><span class="o">.</span><span class="n">getBoolean</span><span class="p">(</span><span class="s2">"IsAvailable"</span><span class="p">);</span>
<span class="n">Product</span> <span class="n">product</span> <span class="o">=</span> <span class="n">new</span> <span class="n">Product</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">stockCode</span><span class="p">,</span> <span class="n">price</span><span class="p">,</span> <span class="n">wasPrice</span><span class="p">,</span> <span class="n">cupPrice</span><span class="p">,</span> <span class="n">cupMeasure</span><span class="p">,</span> <span class="n">isAvailable</span><span class="p">);</span>
<span class="n">productList</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">product</span><span class="p">);</span>
<span class="n">Timber</span><span class="o">.</span><span class="n">d</span><span class="p">(</span><span class="n">product</span><span class="o">.</span><span class="n">toString</span><span class="p">());</span>
<span class="p">}</span>
<span class="k">if</span><span class="p">(</span><span class="n">items</span><span class="o">.</span><span class="n">length</span><span class="p">()</span> <span class="o">==</span> <span class="n">pageSize</span><span class="p">){</span>
<span class="n">downloadProducts</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">pageNumber</span><span class="o">+</span><span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span> <span class="n">catch</span> <span class="p">(</span><span class="n">JSONException</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
<span class="n">e</span><span class="o">.</span><span class="n">printStackTrace</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="n">new</span> <span class="n">Response</span><span class="o">.</span><span class="n">ErrorListener</span><span class="p">()</span> <span class="p">{</span>
<span class="err">@</span><span class="n">Override</span>
<span class="n">public</span> <span class="n">void</span> <span class="n">onErrorResponse</span><span class="p">(</span><span class="n">VolleyError</span> <span class="n">error</span><span class="p">)</span> <span class="p">{</span>
<span class="n">Timber</span><span class="o">.</span><span class="n">e</span><span class="p">(</span><span class="n">error</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="n">queue</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">request</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>}</p>How to storing api keys in Android2016-10-07T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2016-10-07:/keep-api-secret/<p>You SHALL not save api key into version control system, but how can you manage your API keys?</p>
<p>There are some approaches had been discussed <a href="http://stackoverflow.com/questions/14570989/best-practice-for-storing-private-api-keys-in-android">here</a>. One is to saving the api key in <code>gradle.properties</code>. Before add secret to this file. you need add <code>gradle.properties</code> to <code>.gitignore</code> file. If you already commited this file to your git. remove <code>gradle.properties</code> from git first by this command:</p>
<div class="highlight"><pre><span></span><code>git rm --cache gradle.properties
</code></pre></div>
<p>Next, Open your gradle.properties and appmend a new line:</p>
<div class="highlight"><pre><span></span><code>yourapikey="THIS IS API TOKEN"
</code></pre></div>
<p>Modify <code>build.gradle</code> and add <code>buildConfigField</code> for your api key </p>
<div class="highlight"><pre><span></span><code>android {
compileSdkVersion …</code></pre></div><p>You SHALL not save api key into version control system, but how can you manage your API keys?</p>
<p>There are some approaches had been discussed <a href="http://stackoverflow.com/questions/14570989/best-practice-for-storing-private-api-keys-in-android">here</a>. One is to saving the api key in <code>gradle.properties</code>. Before add secret to this file. you need add <code>gradle.properties</code> to <code>.gitignore</code> file. If you already commited this file to your git. remove <code>gradle.properties</code> from git first by this command:</p>
<div class="highlight"><pre><span></span><code>git rm --cache gradle.properties
</code></pre></div>
<p>Next, Open your gradle.properties and appmend a new line:</p>
<div class="highlight"><pre><span></span><code>yourapikey="THIS IS API TOKEN"
</code></pre></div>
<p>Modify <code>build.gradle</code> and add <code>buildConfigField</code> for your api key </p>
<div class="highlight"><pre><span></span><code>android {
compileSdkVersion 24
...
buildTypes {
...
buildTypes.each {
it.buildConfigField 'String', 'YOU_API_KEY', yourapikey
}
}
}
</code></pre></div>
<p>After gradle sync finished. BuildConfigVariable is auto generated to </p>
<div class="highlight"><pre><span></span><code>public final class BuildConfig {
...
public static final String YOU_API_KEY = "12345";
}
</code></pre></div>
<p>Using <code>BuildConfig.OPENWEATHER_API_KEY</code> to reference the api key.</p>
<div class="highlight"><pre><span></span><code>Uri.Builder urlBuilder = new Uri.Builder();
urlBuilder.scheme("http");
urlBuilder.authority("www.helloworld.com");
urlBuilder.appendQueryParameter("key", BuildConfig.YOU_API_KEY);
</code></pre></div>
<p>That's it!</p>Permission model in Android 6.02016-10-07T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2016-10-07:/permission-model/<p>在 Android 6.0 之後,有了新的 <a href="http://developer.android.com/intl/zh-tw/training/permissions/requesting.html">permission model</a>, 安裝 App 的權限可以不用在 Google Play 安裝的時侯就授權。而是等到使用者要使用這個功能的時侯,再詢問使用者。而權限分成兩種: <a href="https://goo.gl/wG4uwm">normal permission</a> 跟 dangerous permission 兩種。 normal permission 可以直接在 AndroidManifest.xml 直接定義,不會詢問使用者就可以直接取得權限,像是<code>android.permission.INTERNET</code>權限就屬於此類,主要是跟使用者的隱私比較無關的功能。如果想使用權限是屬於那一類的話,可以參考<a href="https://developer.android.com/reference/android/Manifest.permission.html?hl=zh-tw">這個清單</a>。</p>
<h2>檢查權限</h2>
<p>首先都要先檢查是否有這個權限:</p>
<div class="highlight"><pre><span></span><code>ContextCompat.checkSelfPermission(Context context, String permission)
</code></pre></div>
<p>例如,檢查是否有寫入行事曆的權限</p>
<div class="highlight"><pre><span></span><code><span class="n">ContextCompat</span><span class="p">.</span><span class="n">checkSelfPermission</span><span class="p">(</span><span class="n">thisActivity</span><span class="p">,</span> <span class="n">Manifest</span><span class="p">.</span><span class="n">permission</span><span class="p">.</span><span class="n">WRITE_CALENDAR</span><span class="p">);</span>
</code></pre></div>
<p>回傳值有兩種可能: <code>PERMISSION_GRANTED(0)</code> 和 <code>PERMISSION_DENIED(-1)</code></p>
<h2>範例程式1: 請求單一權限</h2>
<div class="highlight"><pre><span></span><code><span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">REQUEST_PERMISSION</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kd">private</span> <span class="kt">boolean</span> <span class="nf">checkPermission</span><span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">Build</span><span class="p">.</span><span class="na">VERSION</span><span class="p">.</span><span class="na">SDK_INT</span> <span class="o">>=</span> <span class="n">Build</span><span class="p">.</span><span class="na">VERSION_CODES</span><span class="p">.</span><span class="na">M</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">final</span> <span class="n">String</span> <span class="n">permission</span> <span class="o">=</span> <span class="n">Manifest</span><span class="p">.</span><span class="na">permission</span><span class="p">.</span><span class="na">PERMISSION_YOU_WANT</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">checkSelfPermission</span><span class="p">(</span><span class="n">permission</span><span class="p">)</span> <span class="o">!=</span> <span class="n">PackageManager</span><span class="p">.</span><span class="na">PERMISSION_GRANTED</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">shouldShowRequestPermissionRationale</span><span class="p">(</span><span class="n">permission</span><span class="p">))</span> <span class="p">{</span>
<span class="n">AlertDialog</span><span class="p">.</span><span class="na">Builder</span> <span class="n">builder</span> <span class="o">=</span> <span class="k">new</span> <span class="n">AlertDialog</span><span class="p">.</span><span class="na">Builder</span><span class="p">(</span><span class="k">this …</span></code></pre></div><p>在 Android 6.0 之後,有了新的 <a href="http://developer.android.com/intl/zh-tw/training/permissions/requesting.html">permission model</a>, 安裝 App 的權限可以不用在 Google Play 安裝的時侯就授權。而是等到使用者要使用這個功能的時侯,再詢問使用者。而權限分成兩種: <a href="https://goo.gl/wG4uwm">normal permission</a> 跟 dangerous permission 兩種。 normal permission 可以直接在 AndroidManifest.xml 直接定義,不會詢問使用者就可以直接取得權限,像是<code>android.permission.INTERNET</code>權限就屬於此類,主要是跟使用者的隱私比較無關的功能。如果想使用權限是屬於那一類的話,可以參考<a href="https://developer.android.com/reference/android/Manifest.permission.html?hl=zh-tw">這個清單</a>。</p>
<h2>檢查權限</h2>
<p>首先都要先檢查是否有這個權限:</p>
<div class="highlight"><pre><span></span><code>ContextCompat.checkSelfPermission(Context context, String permission)
</code></pre></div>
<p>例如,檢查是否有寫入行事曆的權限</p>
<div class="highlight"><pre><span></span><code><span class="n">ContextCompat</span><span class="p">.</span><span class="n">checkSelfPermission</span><span class="p">(</span><span class="n">thisActivity</span><span class="p">,</span> <span class="n">Manifest</span><span class="p">.</span><span class="n">permission</span><span class="p">.</span><span class="n">WRITE_CALENDAR</span><span class="p">);</span>
</code></pre></div>
<p>回傳值有兩種可能: <code>PERMISSION_GRANTED(0)</code> 和 <code>PERMISSION_DENIED(-1)</code></p>
<h2>範例程式1: 請求單一權限</h2>
<div class="highlight"><pre><span></span><code><span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">REQUEST_PERMISSION</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="kd">private</span> <span class="kt">boolean</span> <span class="nf">checkPermission</span><span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">Build</span><span class="p">.</span><span class="na">VERSION</span><span class="p">.</span><span class="na">SDK_INT</span> <span class="o">>=</span> <span class="n">Build</span><span class="p">.</span><span class="na">VERSION_CODES</span><span class="p">.</span><span class="na">M</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">final</span> <span class="n">String</span> <span class="n">permission</span> <span class="o">=</span> <span class="n">Manifest</span><span class="p">.</span><span class="na">permission</span><span class="p">.</span><span class="na">PERMISSION_YOU_WANT</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">checkSelfPermission</span><span class="p">(</span><span class="n">permission</span><span class="p">)</span> <span class="o">!=</span> <span class="n">PackageManager</span><span class="p">.</span><span class="na">PERMISSION_GRANTED</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">shouldShowRequestPermissionRationale</span><span class="p">(</span><span class="n">permission</span><span class="p">))</span> <span class="p">{</span>
<span class="n">AlertDialog</span><span class="p">.</span><span class="na">Builder</span> <span class="n">builder</span> <span class="o">=</span> <span class="k">new</span> <span class="n">AlertDialog</span><span class="p">.</span><span class="na">Builder</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="n">builder</span><span class="p">.</span><span class="na">setMessage</span><span class="p">(</span><span class="s">"We need you to grant permission"</span><span class="p">);</span>
<span class="n">builder</span><span class="p">.</span><span class="na">setPositiveButton</span><span class="p">(</span><span class="n">android</span><span class="p">.</span><span class="na">R</span><span class="p">.</span><span class="na">string</span><span class="p">.</span><span class="na">ok</span><span class="p">,</span> <span class="k">new</span> <span class="n">DialogInterface</span><span class="p">.</span><span class="na">OnClickListener</span><span class="p">()</span> <span class="p">{</span>
<span class="nd">@TargetApi</span><span class="p">(</span><span class="n">Build</span><span class="p">.</span><span class="na">VERSION_CODES</span><span class="p">.</span><span class="na">M</span><span class="p">)</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onClick</span><span class="p">(</span><span class="n">DialogInterface</span> <span class="n">dialog</span><span class="p">,</span> <span class="kt">int</span> <span class="n">which</span><span class="p">)</span> <span class="p">{</span>
<span class="n">requestPermissions</span><span class="p">(</span><span class="k">new</span> <span class="n">String</span><span class="o">[]</span><span class="p">{</span><span class="n">permission</span><span class="p">},</span> <span class="n">REQUEST_PERMISSION</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">requestPermissions</span><span class="p">(</span><span class="k">new</span> <span class="n">String</span><span class="o">[]</span><span class="p">{</span><span class="n">permission</span><span class="p">},</span> <span class="n">REQUEST_PERMISSION</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onRequestPermissionsResult</span><span class="p">(</span><span class="kt">int</span> <span class="n">requestCode</span><span class="p">,</span> <span class="nd">@NonNull</span> <span class="n">String</span><span class="o">[]</span> <span class="n">permissions</span><span class="p">,</span> <span class="nd">@NonNull</span> <span class="kt">int</span><span class="o">[]</span> <span class="n">grantResults</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">super</span><span class="p">.</span><span class="na">onRequestPermissionsResult</span><span class="p">(</span><span class="n">requestCode</span><span class="p">,</span> <span class="n">permissions</span><span class="p">,</span> <span class="n">grantResults</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">requestCode</span> <span class="o">==</span> <span class="n">REQUEST_PERMISSION</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">grantResults</span><span class="p">.</span><span class="na">length</span> <span class="o">></span> <span class="mi">0</span> <span class="o">&&</span> <span class="n">grantResults</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">==</span> <span class="n">PackageManager</span><span class="p">.</span><span class="na">PERMISSION_GRANTED</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Has permission Todo</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="c1">// No permission</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<h2>範例程式2: 請求多個權限</h2>
<div class="highlight"><pre><span></span><code><span class="kd">private</span> <span class="kt">boolean</span> <span class="nf">checkPermissions</span><span class="p">(</span><span class="n">Context</span> <span class="n">context</span><span class="p">,</span> <span class="n">String</span><span class="p">...</span> <span class="n">permissions</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">Build</span><span class="p">.</span><span class="na">VERSION</span><span class="p">.</span><span class="na">SDK_INT</span> <span class="o">>=</span> <span class="n">Build</span><span class="p">.</span><span class="na">VERSION_CODES</span><span class="p">.</span><span class="na">M</span> <span class="o">&&</span> <span class="n">context</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">permission</span> <span class="p">:</span> <span class="n">permissions</span><span class="p">)</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">requestCode</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">permission</span><span class="p">.</span><span class="na">equals</span><span class="p">(</span><span class="n">android</span><span class="p">.</span><span class="na">Manifest</span><span class="p">.</span><span class="na">permission</span><span class="p">.</span><span class="na">USE_SIP</span><span class="p">))</span> <span class="p">{</span>
<span class="n">requestCode</span> <span class="o">=</span> <span class="n">REQUEST_SIP_PERMISSION</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">permission</span><span class="p">.</span><span class="na">equals</span><span class="p">(</span><span class="n">android</span><span class="p">.</span><span class="na">Manifest</span><span class="p">.</span><span class="na">permission</span><span class="p">.</span><span class="na">RECORD_AUDIO</span><span class="p">))</span> <span class="p">{</span>
<span class="n">requestCode</span> <span class="o">=</span> <span class="n">REQUEST_RECORD_AUDIO_PERMISSION</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">context</span><span class="p">.</span><span class="na">checkSelfPermission</span><span class="p">(</span><span class="n">permission</span><span class="p">)</span> <span class="o">!=</span> <span class="n">PackageManager</span><span class="p">.</span><span class="na">PERMISSION_GRANTED</span><span class="p">)</span> <span class="p">{</span>
<span class="n">Log</span><span class="p">.</span><span class="na">d</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"checkPermissions: requestCode"</span> <span class="o">+</span> <span class="n">requestCode</span><span class="p">);</span>
<span class="n">requestPermissions</span><span class="p">(</span><span class="k">new</span> <span class="n">String</span><span class="o">[]</span><span class="p">{</span><span class="n">permission</span><span class="p">},</span> <span class="n">requestCode</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onRequestPermissionsResult</span><span class="p">(</span><span class="kt">int</span> <span class="n">requestCode</span><span class="p">,</span> <span class="nd">@NonNull</span> <span class="n">String</span><span class="o">[]</span> <span class="n">permissions</span><span class="p">,</span> <span class="nd">@NonNull</span> <span class="kt">int</span><span class="o">[]</span> <span class="n">grantResults</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">super</span><span class="p">.</span><span class="na">onRequestPermissionsResult</span><span class="p">(</span><span class="n">requestCode</span><span class="p">,</span> <span class="n">permissions</span><span class="p">,</span> <span class="n">grantResults</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">requestCode</span> <span class="o">==</span> <span class="n">REQUEST_SIP_PERMISSION</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">grantResults</span><span class="p">.</span><span class="na">length</span> <span class="o">></span> <span class="mi">0</span> <span class="o">&&</span> <span class="n">grantResults</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">==</span> <span class="n">PackageManager</span><span class="p">.</span><span class="na">PERMISSION_GRANTED</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Has permission Todo</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="c1">// No permission</span>
<span class="kd">final</span> <span class="n">String</span> <span class="n">permission</span> <span class="o">=</span> <span class="n">android</span><span class="p">.</span><span class="na">Manifest</span><span class="p">.</span><span class="na">permission</span><span class="p">.</span><span class="na">USE_SIP</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">shouldShowRequestPermissionRationale</span><span class="p">(</span><span class="n">permission</span><span class="p">))</span> <span class="p">{</span>
<span class="n">AlertDialog</span><span class="p">.</span><span class="na">Builder</span> <span class="n">builder</span> <span class="o">=</span> <span class="k">new</span> <span class="n">AlertDialog</span><span class="p">.</span><span class="na">Builder</span><span class="p">(</span><span class="n">getContext</span><span class="p">());</span>
<span class="n">builder</span><span class="p">.</span><span class="na">setMessage</span><span class="p">(</span><span class="s">"We need you to grant SIP permission"</span><span class="p">);</span>
<span class="n">builder</span><span class="p">.</span><span class="na">setPositiveButton</span><span class="p">(</span><span class="n">android</span><span class="p">.</span><span class="na">R</span><span class="p">.</span><span class="na">string</span><span class="p">.</span><span class="na">ok</span><span class="p">,</span> <span class="k">new</span> <span class="n">DialogInterface</span><span class="p">.</span><span class="na">OnClickListener</span><span class="p">()</span> <span class="p">{</span>
<span class="nd">@TargetApi</span><span class="p">(</span><span class="n">Build</span><span class="p">.</span><span class="na">VERSION_CODES</span><span class="p">.</span><span class="na">M</span><span class="p">)</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onClick</span><span class="p">(</span><span class="n">DialogInterface</span> <span class="n">dialog</span><span class="p">,</span> <span class="kt">int</span> <span class="n">which</span><span class="p">)</span> <span class="p">{</span>
<span class="n">requestPermissions</span><span class="p">(</span><span class="k">new</span> <span class="n">String</span><span class="o">[]</span><span class="p">{</span><span class="n">permission</span><span class="p">},</span> <span class="n">REQUEST_SIP_PERMISSION</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="n">builder</span><span class="p">.</span><span class="na">show</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">requestCode</span> <span class="o">==</span> <span class="n">REQUEST_RECORD_AUDIO_PERMISSION</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">grantResults</span><span class="p">.</span><span class="na">length</span> <span class="o">></span> <span class="mi">0</span> <span class="o">&&</span> <span class="n">grantResults</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">==</span> <span class="n">PackageManager</span><span class="p">.</span><span class="na">PERMISSION_GRANTED</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Has permission Todo</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="c1">// No permission</span>
<span class="kd">final</span> <span class="n">String</span> <span class="n">permission</span> <span class="o">=</span> <span class="n">android</span><span class="p">.</span><span class="na">Manifest</span><span class="p">.</span><span class="na">permission</span><span class="p">.</span><span class="na">RECORD_AUDIO</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">shouldShowRequestPermissionRationale</span><span class="p">(</span><span class="n">permission</span><span class="p">))</span> <span class="p">{</span>
<span class="n">AlertDialog</span><span class="p">.</span><span class="na">Builder</span> <span class="n">builder</span> <span class="o">=</span> <span class="k">new</span> <span class="n">AlertDialog</span><span class="p">.</span><span class="na">Builder</span><span class="p">(</span><span class="n">getContext</span><span class="p">());</span>
<span class="n">builder</span><span class="p">.</span><span class="na">setMessage</span><span class="p">(</span><span class="s">"We need you to grant audio record permission"</span><span class="p">);</span>
<span class="n">builder</span><span class="p">.</span><span class="na">setPositiveButton</span><span class="p">(</span><span class="n">android</span><span class="p">.</span><span class="na">R</span><span class="p">.</span><span class="na">string</span><span class="p">.</span><span class="na">ok</span><span class="p">,</span> <span class="k">new</span> <span class="n">DialogInterface</span><span class="p">.</span><span class="na">OnClickListener</span><span class="p">()</span> <span class="p">{</span>
<span class="nd">@TargetApi</span><span class="p">(</span><span class="n">Build</span><span class="p">.</span><span class="na">VERSION_CODES</span><span class="p">.</span><span class="na">M</span><span class="p">)</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onClick</span><span class="p">(</span><span class="n">DialogInterface</span> <span class="n">dialog</span><span class="p">,</span> <span class="kt">int</span> <span class="n">which</span><span class="p">)</span> <span class="p">{</span>
<span class="n">requestPermissions</span><span class="p">(</span><span class="k">new</span> <span class="n">String</span><span class="o">[]</span><span class="p">{</span><span class="n">permission</span><span class="p">},</span> <span class="n">REQUEST_SIP_PERMISSION</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="n">builder</span><span class="p">.</span><span class="na">show</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>有了這個權限架構可以更保護使用者的隱私,不用讓使用者在一開始安裝 App 就必須答應所有的權限要求。</p>Send HTTP Request in Android2016-10-06T00:00:00+08:002017-05-23T12:48:57+08:00Cody Liutag:blog.codylab.com,2016-10-06:/android-http-request/<p>In the most of time, you could just use HTTP library like <code>Volley</code> or <code>OkHTTP</code>. If you want to use native Android function call for some reasons, you should use <code>HttpURLConnection</code>. <code>HttpClient</code> has been deprecated since Android 6.0(sdk 23).</p>
<p>For <a href="http://developer.android.com/reference/java/net/HttpURLConnection.html">HttpURLConnection</a>
, there is an excellent code snippet on <a href="https://gist.github.com/udacityandroid/d6a7bb21904046a91695">here</a></p>
<p>Note: Android don't allow network request happened on main UI thread. If you did this, a <code>android.os.NetworkOnMainThreadException</code> exception will be thrown out. Put them in AsyncTask or Service instead.</p>
<p>Build Url:</p>
<div class="highlight"><pre><span></span><code>Uri.Builder builder = Uri.parse(FORECAST_BASE_URL).buildUpon();
urlBuilder.scheme("http");
urlBuilder.authority("api.openweathermap.org");
urlBuilder …</code></pre></div><p>In the most of time, you could just use HTTP library like <code>Volley</code> or <code>OkHTTP</code>. If you want to use native Android function call for some reasons, you should use <code>HttpURLConnection</code>. <code>HttpClient</code> has been deprecated since Android 6.0(sdk 23).</p>
<p>For <a href="http://developer.android.com/reference/java/net/HttpURLConnection.html">HttpURLConnection</a>
, there is an excellent code snippet on <a href="https://gist.github.com/udacityandroid/d6a7bb21904046a91695">here</a></p>
<p>Note: Android don't allow network request happened on main UI thread. If you did this, a <code>android.os.NetworkOnMainThreadException</code> exception will be thrown out. Put them in AsyncTask or Service instead.</p>
<p>Build Url:</p>
<div class="highlight"><pre><span></span><code>Uri.Builder builder = Uri.parse(FORECAST_BASE_URL).buildUpon();
urlBuilder.scheme("http");
urlBuilder.authority("api.openweathermap.org");
urlBuilder.appendEncodedPath("data/2.5/forecast/daily");
urlBuilder.appendQueryParameter("zip", zip);
urlBuilder.appendQueryParameter("mode", "json");
urlBuilder.appendQueryParameter("units", "metric");
urlBuilder.appendQueryParameter("cnt", Integer.toString(numberOfDays));
urlBuilder.appendQueryParameter("appid", BuildConfig.OPENWEATHER_API_KEY);
</code></pre></div>
<p>Use this url object to send http request and get json response back:</p>
<div class="highlight"><pre><span></span><code><span class="nv">String</span> <span class="nv">resultString</span> <span class="o">=</span> <span class="nv">null</span><span class="c1">;</span>
<span class="nv">URL</span> <span class="nv">url</span> <span class="o">=</span> <span class="nv">new</span> <span class="nv">URL</span><span class="ss">(</span><span class="nv">urlString</span><span class="ss">)</span><span class="c1">;</span>
<span class="o">//</span> <span class="nv">Create</span> <span class="nv">the</span> <span class="nv">request</span> <span class="nv">to</span> <span class="nv">OpenWeatherMap</span>, <span class="nv">and</span> <span class="nv">open</span> <span class="nv">the</span> <span class="nv">connection</span>
<span class="nv">urlConnection</span> <span class="o">=</span> <span class="ss">(</span><span class="nv">HttpURLConnection</span><span class="ss">)</span> <span class="nv">url</span>.<span class="nv">openConnection</span><span class="ss">()</span><span class="c1">;</span>
<span class="nv">urlConnection</span>.<span class="nv">setRequestMethod</span><span class="ss">(</span><span class="s2">"</span><span class="s">GET</span><span class="s2">"</span><span class="ss">)</span><span class="c1">;</span>
<span class="nv">urlConnection</span>.<span class="k">connect</span><span class="ss">()</span><span class="c1">;</span>
<span class="o">//</span> <span class="nv">Read</span> <span class="nv">the</span> <span class="nv">input</span> <span class="nv">stream</span> <span class="nv">into</span> <span class="nv">a</span> <span class="nv">String</span>
<span class="nv">InputStream</span> <span class="nv">inputStream</span> <span class="o">=</span> <span class="nv">urlConnection</span>.<span class="nv">getInputStream</span><span class="ss">()</span><span class="c1">;</span>
<span class="nv">StringBuffer</span> <span class="nv">buffer</span> <span class="o">=</span> <span class="nv">new</span> <span class="nv">StringBuffer</span><span class="ss">()</span><span class="c1">;</span>
<span class="k">if</span> <span class="ss">(</span><span class="nv">inputStream</span> <span class="o">==</span> <span class="nv">null</span><span class="ss">)</span> {
<span class="o">//</span> <span class="nv">Nothing</span> <span class="nv">to</span> <span class="k">do</span>.
<span class="nv">forecastJsonStr</span> <span class="o">=</span> <span class="nv">null</span><span class="c1">;</span>
}
<span class="nv">reader</span> <span class="o">=</span> <span class="nv">new</span> <span class="nv">BufferedReader</span><span class="ss">(</span><span class="nv">new</span> <span class="nv">InputStreamReader</span><span class="ss">(</span><span class="nv">inputStream</span><span class="ss">))</span><span class="c1">;</span>
<span class="nv">String</span> <span class="nv">line</span><span class="c1">;</span>
<span class="k">while</span> <span class="ss">((</span><span class="nv">line</span> <span class="o">=</span> <span class="nv">reader</span>.<span class="nv">readLine</span><span class="ss">())</span> <span class="o">!=</span> <span class="nv">null</span><span class="ss">)</span> {
<span class="nv">buffer</span>.<span class="nv">append</span><span class="ss">(</span><span class="nv">line</span><span class="ss">)</span><span class="c1">;</span>
}
<span class="k">if</span> <span class="ss">(</span><span class="nv">buffer</span>.<span class="nv">length</span><span class="ss">()</span> <span class="o">==</span> <span class="mi">0</span><span class="ss">)</span> {
<span class="o">//</span> <span class="nv">Stream</span> <span class="nv">was</span> <span class="nv">empty</span>. <span class="nv">No</span> <span class="nv">point</span> <span class="nv">in</span> <span class="nv">parsing</span>.
<span class="nv">forecastJsonStr</span> <span class="o">=</span> <span class="nv">null</span><span class="c1">;</span>
}
<span class="nv">resultString</span> <span class="o">=</span> <span class="nv">buffer</span>.<span class="nv">toString</span><span class="ss">()</span><span class="c1">;</span>
</code></pre></div>
<h2>Reference</h2>
<ul>
<li>Nice comparision article: <a href="https://goo.gl/C6S1K8">Android HTTP library: Handle HTTP, JSON, Images</a></li>
</ul>初級日文學習回顧2016-09-29T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2016-09-29:/naganuma-learning-retro/<p><img alt="a-1" src="http://i.imgur.com/oBGfZR8.jpg"></p>
<h2>學一個新的語言</h2>
<p>今年7月到9月,我到了東京長沼日本語學校學習初級日文。除了上課的200個小時,加上課餘復習,這3個月的時間我至少投入了400小時在日文學習上。</p>
<p>第一次到外國學語言,也是第一次我在國外住了3個月。語言學校學習的好處就基本上整天都是全日語的環境。因為我們是初級班,大家會的日文很有限,一開始的下課,大家還是都用英文來聊天,但隨著學習到的日文愈來愈多,也就發現大家慢慢可以用日文來溝通了。</p>
<p>到語言學校學習可以很容易進入說日語的環境。學習新語言的過程其實就是要不斷的模仿、犯錯、修正。而語言學校則是一個安全、比較沒有壓力的環境,例如學到購物的日文時,就可以到學校的咖啡廳練習。在有系統的教學框架下按步就班學習,絕對會自己在學來得有效率。</p>
<p>不過上語言學校最大的缺點就是很貴。但換個角度想,也是因為自己投入了這些金錢跟時間。代表自己有這個決心來學習一個新的語言。所以我的心態就是既然來了,就好好學習,不要浪費。一個月約2萬5台幣的學費,換算下來每一堂課大約是400台幣的學費。班上的部份同學會在課堂上睡覺、或者是翹課。我是覺得蠻可惜的,也可能是因為花的不是自己的錢,所以比較無所謂吧。最後3個月下來,我每堂課都有出席。</p>
<p><img alt="record" src="https://i.imgur.com/ANlPLUN.png"></p>
<p>最後學期成績順利過關(70分及格)</p>
<p><img alt="成績" src="http://i.imgur.com/EhArh9Y.jpg"></p>
<h2>到志工會話教室學日文</h2>
<p><img alt="vulunteer" src="https://i.imgur.com/ILfi70o.png"></p>
<p>除了語言學校,我也有到日文教室上課。日本各地有<a href="http://www.tnvn.jp/guide/">志工的日本語教室(ボランティア日本語教室)</a>可以參加。基本上都是免費,或是付場地費幾百塊日幣,就可以跟日本人會話交流,練習在語言學校學到的內容,也可以交到除了語言學校以外的朋友。我的小組是一位日本老師,跟一位日本女大學生的助教。學生則是有來自澳洲、印度等地的學生。</p>
<p><img alt="vulunteer" src="http://i.imgur.com/cYW5Zlf.jpg"></p>日本語長沼學校初級班 資訊分享2016-09-23T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2016-09-23:/naganuma-info/<h2>簡介</h2>
<p>位於東京澀谷的日本語<a href="http://www.naganuma-school.ac.jp/tw/">長沼學校</a>是東京是最有名的語言學校之一。長沼學校創立於1948年,至今有近70年左右的歷史。</p>
<p>我上的<a href="http://www.naganuma-school.ac.jp/tw/courses/regular.html">日語綜合課程</a>中的最基礎的課程,也就是從50音開始教起的初級班。班上有些同學是連五十音都不會就來上課。因為老師都有受過專業訓練,所以即使班上同學很多連50音都不會,也都可以進行<strong>全日語</strong>的授課。老師會透過手勢、表情表達、道具來教學,如果日文完全不會也不用擔心。</p>
<p>這次我是使用了短期滯在的90天簽證入境日本,一共上了三個月的課程。我把一些學校的資訊記錄在這邊,供未來有興趣到長沼學日文的同學參考。</p>
<h2>如何報名</h2>
<ol>
<li>填寫長沼線上的<a href="https://www.naganuma-school.ac.jp/tw/inquiry/form.php">表單</a></li>
<li>收到學校承辦人員的回覆之後,會傳送填寫個人資料檔案,再用電子郵件回傳回去。</li>
<li>學校承辦人員會寄匯款請求書,再拿這個請求書到銀行匯款即可。</li>
</ol>
<p>基本上要報名長沼的話,可以不用透過代辦,因為長沼校方有懂中文的窗口,如果不會日文的話,可以透過 Email 直接用中文跟校方聯繫。</p>
<h2>關於學費</h2>
<p>會有<strong>課本</strong>跟<strong>學費</strong>二筆費用,以短期三個月為例:</p>
<ol>
<li>
<p>初級班課本的費用約8千多日幣</p>
</li>
<li>
<p>單一學期三個月的學費約25萬日幣左右,其它課程費可參考<a href="http://www.naganuma-school.ac.jp/tw/courses/regular.html">官網</a></p>
</li>
</ol>
<p><img alt="tuition" src="https://i.imgur.com/g5ywvAr.png"></p>
<h2>初級教材</h2>
<p>長沼的初級課程是採用學校自編的教材<strong>「いつでもどこでも話せる日本語(隨時隨地開口說日語」</strong>:
<img alt="課本" src="https://i.imgur.com/HWgQDqh.png"></p>
<p>其實這本書,台灣大新出版社也有<a href="http://www.books.com.tw/products/0010546745">出版</a>,不過跟我在日本上課的版本不一樣,學校在今年七月出了新版的課本。</p>
<ol>
<li>課本: 包含上課會使用到會話、文型、單字,另外有提供會話的 MP3 檔案給同學下載</li>
<li>單字文法書: 依照學生的母語,有英文、繁體中文、簡體中文... 等版本可供選擇</li>
<li>作業本: 因為每天都有作業,用活頁夾的方式,方便把前一天作業抽出來交給老師批改</li>
</ol>
<h2>入學考試</h2>
<p>長沼的班級分成<strong>上午班(9:00~12:30)</strong>跟<strong>下午班(13:30~17:00)</strong>,一般是上午班比較熱門,因為下午可以安排其它的事情,像是打工或是出遊等等。長沼在報名的時侯沒辦法保證是上午班或是下午班。上午班跟下午班的名單基本上是按照入學考試後分班順序。所以如果偏好上午班的話,第一天記得要提早到學校。表定是上午9點~11點報到,但是如果想挑上午班或是下午班的話,建議當天8點半前就到學校 …</p><h2>簡介</h2>
<p>位於東京澀谷的日本語<a href="http://www.naganuma-school.ac.jp/tw/">長沼學校</a>是東京是最有名的語言學校之一。長沼學校創立於1948年,至今有近70年左右的歷史。</p>
<p>我上的<a href="http://www.naganuma-school.ac.jp/tw/courses/regular.html">日語綜合課程</a>中的最基礎的課程,也就是從50音開始教起的初級班。班上有些同學是連五十音都不會就來上課。因為老師都有受過專業訓練,所以即使班上同學很多連50音都不會,也都可以進行<strong>全日語</strong>的授課。老師會透過手勢、表情表達、道具來教學,如果日文完全不會也不用擔心。</p>
<p>這次我是使用了短期滯在的90天簽證入境日本,一共上了三個月的課程。我把一些學校的資訊記錄在這邊,供未來有興趣到長沼學日文的同學參考。</p>
<h2>如何報名</h2>
<ol>
<li>填寫長沼線上的<a href="https://www.naganuma-school.ac.jp/tw/inquiry/form.php">表單</a></li>
<li>收到學校承辦人員的回覆之後,會傳送填寫個人資料檔案,再用電子郵件回傳回去。</li>
<li>學校承辦人員會寄匯款請求書,再拿這個請求書到銀行匯款即可。</li>
</ol>
<p>基本上要報名長沼的話,可以不用透過代辦,因為長沼校方有懂中文的窗口,如果不會日文的話,可以透過 Email 直接用中文跟校方聯繫。</p>
<h2>關於學費</h2>
<p>會有<strong>課本</strong>跟<strong>學費</strong>二筆費用,以短期三個月為例:</p>
<ol>
<li>
<p>初級班課本的費用約8千多日幣</p>
</li>
<li>
<p>單一學期三個月的學費約25萬日幣左右,其它課程費可參考<a href="http://www.naganuma-school.ac.jp/tw/courses/regular.html">官網</a></p>
</li>
</ol>
<p><img alt="tuition" src="https://i.imgur.com/g5ywvAr.png"></p>
<h2>初級教材</h2>
<p>長沼的初級課程是採用學校自編的教材<strong>「いつでもどこでも話せる日本語(隨時隨地開口說日語」</strong>:
<img alt="課本" src="https://i.imgur.com/HWgQDqh.png"></p>
<p>其實這本書,台灣大新出版社也有<a href="http://www.books.com.tw/products/0010546745">出版</a>,不過跟我在日本上課的版本不一樣,學校在今年七月出了新版的課本。</p>
<ol>
<li>課本: 包含上課會使用到會話、文型、單字,另外有提供會話的 MP3 檔案給同學下載</li>
<li>單字文法書: 依照學生的母語,有英文、繁體中文、簡體中文... 等版本可供選擇</li>
<li>作業本: 因為每天都有作業,用活頁夾的方式,方便把前一天作業抽出來交給老師批改</li>
</ol>
<h2>入學考試</h2>
<p>長沼的班級分成<strong>上午班(9:00~12:30)</strong>跟<strong>下午班(13:30~17:00)</strong>,一般是上午班比較熱門,因為下午可以安排其它的事情,像是打工或是出遊等等。長沼在報名的時侯沒辦法保證是上午班或是下午班。上午班跟下午班的名單基本上是按照入學考試後分班順序。所以如果偏好上午班的話,第一天記得要提早到學校。表定是上午9點~11點報到,但是如果想挑上午班或是下午班的話,建議當天8點半前就到學校。這樣比較容易選到上午班。另外如果想直接從最基礎的50音課程開始上的話,也可以直接跟學校說不要考試,這樣可以節省時間,也可以比較容易選到上午班。</p>
<h2>課程內容</h2>
<p>三個月會把第一冊上完,會學到的文型包含如下:</p>
<p><img alt="文型1" src="https://i.imgur.com/G5wSkXG.png">
<img alt="文型2" src="https://i.imgur.com/WONa4r5.png">
<img alt="文型3" src="https://i.imgur.com/Ekuhjqn.png"></p>
<p>可以參考後面課本的文型來了解</p>
<p>初級班共有四個等級的班 A-1, A-2, B-1, B-2</p>
<ul>
<li>A-1班: 初級第1冊的第1課開始上</li>
<li>A-2班: 初級第1冊的第15課開始上</li>
<li>B-1班: 初級第2冊的第23課開始上</li>
<li>B-2班: 初級第2冊的中間開始上</li>
</ul>
<p>但可能學校會因為學生人數有不同的安排也說不定。</p>
<p>以下是其中一課的內容: </p>
<p><img alt="課文" src="https://i.imgur.com/EAU25r2.png">
<img alt="課文2" src="https://i.imgur.com/GOTP9wj.png">
<img alt="課文3" src="https://i.imgur.com/VVb7Vud.png">
<img alt="課文4" src="https://i.imgur.com/VpCFhWm.png"></p>
<h2>長沼校園</h2>
<p>長沼有個優點是有自己獨立的校園,所以有一些資源可以在課後使用。像是圖書室、電腦教室、自習室、咖啡廳等等。</p>
<p><img alt="enterence" src="http://i.imgur.com/8JvQfMo.jpg"></p>
<p><img alt="pic" src="http://i.imgur.com/b5Gq35S.jpg">
中庭: 圖為日本夏天傳統活動,矇眼切西瓜(すいか割り大会)</p>
<p><img alt="building-2" src="http://i.imgur.com/GhzGmwB.jpg">
長沼一共有三棟大樓,這棟是初級班上課的地方。</p>
<p><img alt="classroom" src="http://i.imgur.com/aCDWJDX.jpg">
教室: 白板跟老師上課使用的木桌
<img alt="classroom2" src="http://i.imgur.com/kbHrvxP.jpg">
教室: 座位的排例是圓弧,同學之間彼此都可以看到彼此,方便同學之間彼此練習對話</p>
<p><img alt="電腦教室" src="http://i.imgur.com/8EeVzGL.jpg">
電腦教室</p>
<p><img alt="hall" src="http://i.imgur.com/z9JjrW9.jpg">
一樓大廳,可以在這邊聊天、吃午餐、自習寫作業的地方</p>
<h2>關於老師</h2>
<p>我們班有二位主要的老師輪流上課,然後在學期中也有其它的老師會來上課,大部份的時侯,
一天會有2~3位老師上課,整個學期下來大約有8位左右的老師有上過我們的初級班。</p>
<p><img alt="谷津老師" src="http://i.imgur.com/XIHVv9Wl.jpg"> <br>
我們的班導谷津老師:很能理解同學的問題,尤其大家的日文都不好,所以就算用爛日文發問,谷津老師教學經驗很多,幾乎一下就知道你想問的是什麼,並能馬上回答你。</p>
<p><img alt="山城老師" src="http://i.imgur.com/1A8Zgozl.jpg"> <br>
山城老師: 大家上山城老師的課都很歡樂,老師很能掌握上課愉快的氣氛,課餘也會常常關心同學,解答同學學習的問題</p>
<h2>同學組成</h2>
<p>在長沼就讀的學生中,還是台灣人最多。
<img alt="長沼" src="http://i.imgur.com/m6jTG5J.jpg">
<em>取自長沼官網</em></p>
<p>我們班上的同學大多是 20 ~ 30 歲為主。 基本上可以分成三種類型的學生: </p>
<p><img alt="上課的實景" src="http://i.imgur.com/k2TxvKE.jpg">
<img alt="上課" src="http://i.imgur.com/G6Gqfv6.jpg"></p>
<ol>
<li>因為工作關係而來的,像是班上同學有包裝公司的設計師、大使館外交官、報社的送報生。像這種同學的學費都是由公司支出的</li>
<li>因為要上日本專門學校、大學而來的,先來語言學校提升自己的日文能力</li>
<li>因為興趣,班上也有幾位同學是只來唸一個月,算是來過暑假來玩的。這類的同學大多是唸短期的,之後就會回到自己的學校或是工作崗位上</li>
</ol>
<p>所以同學會來來去去,大部份的時間班上同學是12~14位。有出現過的同學包含: 五位台灣人、三位印度人、三位大陸人、二位泰國人、一位澳洲人、一位印尼人、一位香港人。</p>
<h2>上課時間</h2>
<p>以上午班為例: </p>
<ul>
<li>09:00 ~ 09:45 第一節課 </li>
<li>09:45 ~ 09:55 休息</li>
<li>09:55 ~ 10:40 第二節課 </li>
<li>10:40 ~ 10:50 休息</li>
<li>10:50 ~ 11:35 第三節課</li>
<li>11:35 ~ 11:45 休息</li>
<li>11:45 ~ 12:30 第四節課</li>
</ul>
<p>每一天會有4節45分鐘的教學,課堂之間會有10分鐘的休息時間。每天的第3堂課,會教新的進度。而第 1、2 堂課則是復習前一天上的內容。
<img alt="intro" src="https://i.imgur.com/oo2V0xO.png">
<img alt="review " src="https://i.imgur.com/G8mwLLS.png">
<em>取自長沼的youtbue</em></p>
<p>另外,幾乎每天都有回家作業要寫,隔天再交還給班導批改,老師會再隔日發回。
<img alt="作業" src="http://i.imgur.com/q1rEixq.jpg">
三個月下來的作業也是厚厚一本</p>
<p>而第4節課通常會小考,學期前1/3會學習平假片跟片假名,而後2/3則是學習漢字。</p>
<p>長沼是有留級制度的。幾課學習完會有小考,不會列入學期成績。學期中有期中考(聽力、筆試)跟期末考(聽力、筆試、口試),如果不到70分的話,就會被留級。必須在這個程度重新再學習一次,基本上是重覆是1個半月左右的課程。期中考、期末考前老師會安排綜合復習的課程,會著重在文法的復習上。</p>
<p><img alt="schedule" src="http://i.imgur.com/Ab4i6gl.jpg">
這個是我們某一週的行程表,可以看得出來,除了復習外,每天是以教新的一課的速度前進。</p>
<h2>教學方式</h2>
<p>關於長沼初級班如何教學可以直接參考長沼在 youtube 的影片: </p>
<iframe width="560" height="315" src="http://www.youtube.com/embed/xUVLuv2IGNQ" frameborder="0" allowfullscreen></iframe>
<p>長沼使用一套稱為"問答法"的教學方式,初級班大部份的情況下是不唸課文的。課本主要是用來當你想比較有系統知道,現在練習的文型、單字是什麼時侯可以參考者看。有些同學甚至也都常不帶課本來學校 XD。整堂課下來的練習都是跟老師、同學問答為主,老師也是希望你盡量不要依靠課本,一開始的時侯,會常常叫你把課本蓋起來,專心看他上課。另外,老師在教學上也是很少板書,板書大多是在文法、考卷復習的時侯才會比較多。</p>
<p>長沼主要的教學原理就是<strong>營造出兒童學習語言</strong>的過程。先聽再說,著重模仿,老師會一直重覆發問,透過反覆練習,讓自己可以習慣這種講法。但是學新的語法,練習的時侯一定都會有錯誤,所以長沼的老師會立刻糾正你,並叫你重新講一次,直到完全正確為止。在其它的學習環境,老師也許為了教學的流暢度,不會每個學生的錯誤都抓,但是在長沼,有錯就會馬上被糾正。因為當老師跟某位同學問答的時侯,其它的同學也都正在聽,在學習。所以這時侯的正確性就顯得很重要。</p>
<p>在長沼的學習流程大概如下:</p>
<ol>
<li>聽老師說,透過聲音、跟老師表演的情境來了解這句話是什麼意思</li>
<li>模仿老師的句子,試著透過回答老師的問句,來重覆老師所說的話來學習</li>
<li>反覆練習養成習慣</li>
<li>聲音跟意義的結合,可以說出句子而不透過母語思考</li>
<li>可以跟據自己的需要說出完整的句字</li>
</ol>
<p>例如在 youtubue 影片中,那堂課學習 あげます(給)、もらいます(得到) 的句型練習,透過道具、圖片,營造出情境。然後老師自己先說例句:</p>
<p>老師: いま、フォードさんにブレゼントをあげました (現在,我給Fordo先生禮物)
<a href="https://youtu.be/xUVLuv2IGNQ?t=3m40s">video</a></p>
<p>這時侯,我們就會思考,老師說這句話是代表什麼意思。此時老師只會演、並重覆,不會解釋。我們則是透過看到眼前的情境跟聽到的聲音來學習。然後老師就會使用問答法,來讓學生練習。問答法包含下列4個順序:</p>
<ol>
<li>提問,使用 はい 回答的問題。並讓同學重覆完整問題。</li>
<li>同1. 但是使用 いいえ 回答
. A ですか B ですか,問句變長,讓同學選擇其中一個正確答案,並重覆回答。</li>
<li>疑問詞提問: これは何ですか。讓同學理解疑問詞</li>
</ol>
<p>1 ~ 4 的實習操作流程可參考這個<a href="https://youtu.be/xUVLuv2IGNQ?t=10m6s">影片</a></p>
<p>以上都是老師問,學生回答。再難一點的話,老師會基於 A 說了什麼來問 B 同學,看 B 同學是否可以理解。另外也會讓同學有提問的能力,老師叫 A 同學 問 B 同學,這時侯老師就只引導而不介入,一問一答都由同學完成。</p>
<h2>最後</h2>
<p>我個人是還蠻推薦的長沼的初級班,老師們都很熱心,親切。雖然下課只有10分鐘,老師也都會主動關心同學剛才的課程是否有不懂的地方。除了口說之外,學校也很蠻注重寫作的,每天都有小考,考聽寫跟漢字。</p>
<p>如果程度不好的話,也完全不用怕。因為班上有很多連50音都不會的人也來上課,畢竟是最初級班。初級班的師資跟教材都是很不錯的,只要不要缺課、每天記得復習、作業都有按時做。三個月後一定可以感受到自己的日文程度有所進步的。</p>
<h2>更多關於長沼的資訊</h2>
<ul>
<li><a href="http://cocodor.logdown.com/posts/244809-tokyo-japan-language-school-naganuma-school-january-2015-three-month-short-term-application-tips">東京日本語學校長沼學校-2015年1月短期 申請心得</a></li>
</ul>Notes of using Django in Azure App Service2016-08-22T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2016-08-22:/azure-django/<h2>DebugConsole</h2>
<p>There is an debug conolse that you can exectue some commands for Django related tasks. The debug console is:</p>
<div class="highlight"><pre><span></span><code>https://{YOUR_PROJECT_NAME}.scm.azurewebsites.net/DebugConsole
</code></pre></div>
<h2>Migrate django database in Azure</h2>
<ol>
<li>
<p>Go to D:\home\site\wwwroot directory</p>
</li>
<li>
<p>Exceute migrate command</p>
<p>D:\home\site\wwwroot>
.\env\Scripts\python.exe manage.py migrate</p>
</li>
</ol>
<h2>Create super user</h2>
<div class="highlight"><pre><span></span><code><span class="n">echo</span> <span class="s2">"from django.contrib.auth.models import User; User.objects.create_superuser('admin', 'admin@email.com', 'your_password')"</span> <span class="o">|</span> <span class="n">python</span> <span class="n">manage</span><span class="o">.</span><span class="n">py</span> <span class="n">shell</span>
</code></pre></div>
<!--
// echo "from users import EmailUser; EmailUser.objects.create_superuser('admin@localhost', 'admin@localhost', 'your_password')" | .\env\Scripts\python.exe manage.py shell
-->
<blockquote></blockquote>
<h2>Adjest timezone</h2>
<p>Go to <a href="https://portal.azure.com">azure portal</a>, </p>
<p><a href="https://i.imgur.com/5h2nfQB.png">WEBSITE_TIME_ZONE</a></p>
<p>Set <code>WEBSITE_TIME_ZONE</code> to anyvalue defined in here: https://technet.microsoft.com/en-us/library/cc749073(v=ws.10).aspx …</p><h2>DebugConsole</h2>
<p>There is an debug conolse that you can exectue some commands for Django related tasks. The debug console is:</p>
<div class="highlight"><pre><span></span><code>https://{YOUR_PROJECT_NAME}.scm.azurewebsites.net/DebugConsole
</code></pre></div>
<h2>Migrate django database in Azure</h2>
<ol>
<li>
<p>Go to D:\home\site\wwwroot directory</p>
</li>
<li>
<p>Exceute migrate command</p>
<p>D:\home\site\wwwroot>
.\env\Scripts\python.exe manage.py migrate</p>
</li>
</ol>
<h2>Create super user</h2>
<div class="highlight"><pre><span></span><code><span class="n">echo</span> <span class="s2">"from django.contrib.auth.models import User; User.objects.create_superuser('admin', 'admin@email.com', 'your_password')"</span> <span class="o">|</span> <span class="n">python</span> <span class="n">manage</span><span class="o">.</span><span class="n">py</span> <span class="n">shell</span>
</code></pre></div>
<!--
// echo "from users import EmailUser; EmailUser.objects.create_superuser('admin@localhost', 'admin@localhost', 'your_password')" | .\env\Scripts\python.exe manage.py shell
-->
<blockquote></blockquote>
<h2>Adjest timezone</h2>
<p>Go to <a href="https://portal.azure.com">azure portal</a>, </p>
<p><a href="https://i.imgur.com/5h2nfQB.png">WEBSITE_TIME_ZONE</a></p>
<p>Set <code>WEBSITE_TIME_ZONE</code> to anyvalue defined in here: https://technet.microsoft.com/en-us/library/cc749073(v=ws.10).aspx</p>
<h2>Create Django Project</h2>
<p><img alt="azure" src="https://i.imgur.com/LIGa4SY.png"></p>
<p>https://azure.microsoft.com/en-us/documentation/articles/web-sites-python-create-deploy-django-app/</p>
<ol>
<li>
<p>Create Azure Django App (+ New) ></p>
</li>
<li>
<p>Set <code>enable git deployment</code> / Config <code>credentials</code></p>
</li>
<li>
<p>Get git clone url, ex: <code>https://cm1admin@cm1-django.scm.azurewebsites.net:443/cm1-django.git</code></p>
</li>
<li>
<p>git push</p>
</li>
</ol>
<h2>Set static file</h2>
<p>Edit your <code>web.config</code> in repository root folder:</p>
<p>In the following cases, we map <code>/static</code> and <code>/uploads</code> to <code>static</code> and <code>uploads</code> in repository </p>
<div class="highlight"><pre><span></span><code><span class="nt"><rewrite></span>
<span class="nt"><rules></span>
<span class="nt"><rule</span> <span class="na">name=</span><span class="s">"Static Files"</span> <span class="na">stopProcessing=</span><span class="s">"true"</span><span class="nt">></span>
<span class="nt"><conditions></span>
<span class="nt"><add</span> <span class="na">input=</span><span class="s">"true"</span> <span class="na">pattern=</span><span class="s">"false"</span> <span class="nt">/></span>
<span class="nt"></conditions></span>
<span class="nt"></rule></span>
<span class="nt"><rule</span> <span class="na">name=</span><span class="s">"Configure Python"</span> <span class="na">stopProcessing=</span><span class="s">"true"</span><span class="nt">></span>
<span class="nt"><match</span> <span class="na">url=</span><span class="s">"(.*)"</span> <span class="na">ignoreCase=</span><span class="s">"false"</span> <span class="nt">/></span>
<span class="nt"><conditions></span>
<span class="nt"><add</span> <span class="na">input=</span><span class="s">"{REQUEST_URI}"</span> <span class="na">pattern=</span><span class="s">"^/(static|uploads)/.*"</span> <span class="na">ignoreCase=</span><span class="s">"true"</span> <span class="na">negate=</span><span class="s">"true"</span> <span class="nt">/></span>
<span class="nt"></conditions></span>
<span class="nt"><action</span> <span class="na">type=</span><span class="s">"Rewrite"</span> <span class="na">url=</span><span class="s">"handler.fcgi/{R:1}"</span> <span class="na">appendQueryString=</span><span class="s">"true"</span> <span class="nt">/></span>
<span class="nt"></rule></span>
<span class="nt"></rules></span>
<span class="nt"></rewrite></span>
</code></pre></div>Notes of using Django in Azure App Service2016-08-22T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2016-08-22:/azure-django-deploy-setup/<ul>
<li><a href="https://goo.gl/AbBZNJ">在 Azure 中使用 Django 建立 Web 應用程式</a></li>
</ul>
<p><img alt="enable-git-deployment" src="https://i.imgur.com/7smudN6.png"></p>
<p><img alt="enable-log" src="https://i.imgur.com/rN3YPei.png"></p>使用 linphone 函式庫發生 exc_bad_access 的除錯經驗2016-07-01T00:00:00+08:002018-03-24T05:35:44+08:00Cody Liutag:blog.codylab.com,2016-07-01:/ios-linphone-exc-bad-access/<p><img alt="exc_bad_access" src="http://i.imgur.com/epeolml.png"></p>
<p>在叫用 linphone 的函式庫時,發生 <code>exc_bad_access</code>的錯誤,因為這個錯誤往往發生的地方跟掛掉的地方是不一樣的,所以比較難除錯。</p>
<h2>EXC_BAD_ACCESS</h2>
<p>是因為對已經釋放的記憶體進行了非法操作,程式會直接 Crash,無法用 error handle catch 來處理。</p>
<p><img alt="exc_bad_access" src="https://i.imgur.com/Z1198IW.png"></p>
<h2>Crash 片段</h2>
<p><img alt="zombie" src="https://i.imgur.com/CUtZpok.png"></p>
<p>記錄發生 crash 的地方不只有一處,共同的特色就是都是掛在 linphone 的函式庫:</p>
<p>發生位置1 <code>linphone_core_iterate()</code>: </p>
<div class="highlight"><pre><span></span><code><span class="err">@</span><span class="n">objc</span> <span class="k">func</span> <span class="n">iterate</span><span class="p">(){</span>
<span class="n">let</span> <span class="n">lc</span> <span class="o">=</span> <span class="n">LinphoneManager</span><span class="o">.</span><span class="n">getLc</span><span class="p">()</span>
<span class="k">if</span> <span class="n">lc</span> <span class="o">!=</span> <span class="n">nil</span><span class="p">{</span>
<span class="n">linphone_core_iterate</span><span class="p">(</span><span class="n">lc</span><span class="p">);</span> <span class="o">/*</span> <span class="n">first</span> <span class="n">iterate</span> <span class="n">initiates</span> <span class="n">registration</span> <span class="o">*/</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>發生位置2 <code>linphone_core_iterate()</code>: </p>
<div class="highlight"><pre><span></span><code><span class="k">if</span> <span class="nv">let</span> <span class="nv">phone</span> <span class="o">=</span> <span class="nv">phoneNumber</span>, <span class="nv">lc</span> <span class="o">=</span> <span class="nv">LinphoneManager</span>.<span class="nv">lc</span> {
<span class="nv">nameLabel</span>.<span class="nv">text</span> <span class="o">=</span> <span class="nv">calleeName</span><span class="o">!</span>
<span class="nv">linphone_core_invite</span><span class="ss">(</span><span class="nv">lc</span>, <span class="nv">phone</span><span class="ss">)</span>
}
</code></pre></div>
<h2>透 Debug build 測試</h2>
<p>因為預設從 linphone 網站下載的 iphone sdk 是沒有 debug symbol 的,所以在發生 crash 的時侯,只能看到看組合語言:
<img alt="acc" src="https://i.imgur.com/YQQIst3.png">
<img alt="EXC_I386_GPFLT" src="https://i.imgur.com/eWVoO0y.png"></p>
<p>雖然有 linphone 的函式名稱,但是對於問題的幫助不大。所以我就直接 build 一個 有 debug symbol 的 liblinphone-sdk,build debug sdk 步驟記錄在<a href="https://blog.codylab.com/ios-build-linphone-iphone-sdk/">另一篇</a>。</p>
<p>經過有 debug build 的協助之後, crash 的資訊從原本的組合語言變成了 c 語言 …</p><p><img alt="exc_bad_access" src="http://i.imgur.com/epeolml.png"></p>
<p>在叫用 linphone 的函式庫時,發生 <code>exc_bad_access</code>的錯誤,因為這個錯誤往往發生的地方跟掛掉的地方是不一樣的,所以比較難除錯。</p>
<h2>EXC_BAD_ACCESS</h2>
<p>是因為對已經釋放的記憶體進行了非法操作,程式會直接 Crash,無法用 error handle catch 來處理。</p>
<p><img alt="exc_bad_access" src="https://i.imgur.com/Z1198IW.png"></p>
<h2>Crash 片段</h2>
<p><img alt="zombie" src="https://i.imgur.com/CUtZpok.png"></p>
<p>記錄發生 crash 的地方不只有一處,共同的特色就是都是掛在 linphone 的函式庫:</p>
<p>發生位置1 <code>linphone_core_iterate()</code>: </p>
<div class="highlight"><pre><span></span><code><span class="err">@</span><span class="n">objc</span> <span class="k">func</span> <span class="n">iterate</span><span class="p">(){</span>
<span class="n">let</span> <span class="n">lc</span> <span class="o">=</span> <span class="n">LinphoneManager</span><span class="o">.</span><span class="n">getLc</span><span class="p">()</span>
<span class="k">if</span> <span class="n">lc</span> <span class="o">!=</span> <span class="n">nil</span><span class="p">{</span>
<span class="n">linphone_core_iterate</span><span class="p">(</span><span class="n">lc</span><span class="p">);</span> <span class="o">/*</span> <span class="n">first</span> <span class="n">iterate</span> <span class="n">initiates</span> <span class="n">registration</span> <span class="o">*/</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>發生位置2 <code>linphone_core_iterate()</code>: </p>
<div class="highlight"><pre><span></span><code><span class="k">if</span> <span class="nv">let</span> <span class="nv">phone</span> <span class="o">=</span> <span class="nv">phoneNumber</span>, <span class="nv">lc</span> <span class="o">=</span> <span class="nv">LinphoneManager</span>.<span class="nv">lc</span> {
<span class="nv">nameLabel</span>.<span class="nv">text</span> <span class="o">=</span> <span class="nv">calleeName</span><span class="o">!</span>
<span class="nv">linphone_core_invite</span><span class="ss">(</span><span class="nv">lc</span>, <span class="nv">phone</span><span class="ss">)</span>
}
</code></pre></div>
<h2>透 Debug build 測試</h2>
<p>因為預設從 linphone 網站下載的 iphone sdk 是沒有 debug symbol 的,所以在發生 crash 的時侯,只能看到看組合語言:
<img alt="acc" src="https://i.imgur.com/YQQIst3.png">
<img alt="EXC_I386_GPFLT" src="https://i.imgur.com/eWVoO0y.png"></p>
<p>雖然有 linphone 的函式名稱,但是對於問題的幫助不大。所以我就直接 build 一個 有 debug symbol 的 liblinphone-sdk,build debug sdk 步驟記錄在<a href="https://blog.codylab.com/ios-build-linphone-iphone-sdk/">另一篇</a>。</p>
<p>經過有 debug build 的協助之後, crash 的資訊從原本的組合語言變成了 c 語言,地點是在<code>submodules/linphone/coreapi/vtables.c</code>檔案: </p>
<p><img alt="NOTIFY_IF_EXIST" src="https://i.imgur.com/fZj7CMw.png"></p>
<p>NOTIFY_IF_EXIST 是一個 macro,執行 event 的 notify: </p>
<div class="highlight"><pre><span></span><code><span class="cp">#define NOTIFY_IF_EXIST(function_name, ...) \</span>
<span class="n">MSList</span><span class="o">*</span> <span class="n">iterator</span><span class="p">;</span> <span class="err">\</span>
<span class="n">VTableReference</span> <span class="o">*</span><span class="n">ref</span><span class="p">;</span> <span class="err">\</span>
<span class="n">bool_t</span> <span class="n">has_cb</span> <span class="o">=</span> <span class="kr">FALSE</span><span class="p">;</span> <span class="err">\</span>
<span class="n">for</span> <span class="p">(</span><span class="n">iterator</span><span class="o">=</span><span class="n">lc</span><span class="o">-></span><span class="n">vtable_refs</span><span class="p">;</span> <span class="n">iterator</span><span class="o">!=</span><span class="n">NULL</span><span class="p">;</span> <span class="n">iterator</span><span class="o">=</span><span class="n">iterator</span><span class="o">-></span><span class="n">next</span><span class="p">)</span><span class="err">\</span>
<span class="nf">if</span> <span class="p">((</span><span class="n">ref</span><span class="o">=</span><span class="p">(</span><span class="n">VTableReference</span><span class="o">*</span><span class="p">)</span><span class="n">iterator</span><span class="o">-></span><span class="n">data</span><span class="p">)</span><span class="o">-></span><span class="n">valid</span> <span class="o">&&</span> <span class="p">(</span><span class="n">lc</span><span class="o">-></span><span class="n">current_vtable</span><span class="o">=</span><span class="n">ref</span><span class="o">-></span><span class="n">vtable</span><span class="p">)</span><span class="o">-></span><span class="n">function_name</span><span class="p">)</span> <span class="p">{</span><span class="err">\</span>
<span class="n">lc</span><span class="o">-></span><span class="n">current_vtable</span><span class="o">-></span><span class="n">function_name</span><span class="p">(</span><span class="n">__VA_ARGS__</span><span class="p">);</span><span class="err">\</span>
<span class="n">has_cb</span> <span class="o">=</span> <span class="kr">TRUE</span><span class="p">;</span><span class="err">\</span>
<span class="p">}</span><span class="err">\</span>
<span class="nf">if</span> <span class="p">(</span><span class="n">has_cb</span><span class="p">)</span> <span class="n">ms_message</span><span class="p">(</span><span class="s">"Linphone core [%p] notifying [%s]"</span><span class="p">,</span><span class="n">lc</span><span class="p">,</span><span class="err">#</span><span class="n">function_name</span><span class="p">)</span>
</code></pre></div>
<p>我開始思考,這邊有什麼變數是已經釋放了?於是我找到了關鍵字<code>current_vtable</code>,回頭看到自己的 LinphoneCoreTable 是放在 class property 中: </p>
<p><img alt="bug" src="https://i.imgur.com/QgmGnhw.png"></p>
<p>哈,賓果!推斷是因為 linphone 函式使用到這個已經釋放的 object,把程式修改成用 struct static 專門來放 global variables:</p>
<p><img alt="struct" src="https://i.imgur.com/vHtX5Z5.png"></p>
<p>再次執行! Problem Solved !!</p>
<h2>結論</h2>
<p>我本身比較少 C/C++ 的除錯經驗,因為這個 bug 足足花了15個小時才找到問題,把除錯的經驗記錄於此。除錯過程中,盡量讓自己有更多的資訊可以下判斷,像是掛載 debug symbol 就是一例。在 swift 呼叫 c 的 library 時,有些物件的 life cycle 要特別留意,是不是可能會讓外部的 library 呼叫到自己已經釋放的 object。下次遇到這個問題,應該要先把跟外部函式庫有關聯的<strong>變數</strong>列出來,一一檢視是否釋放的時機過早。我想效率會比較好。</p>
<h2>註1: 嘗試過的解法</h2>
<p>在用 debug symbol 前,其實嘗試了許多無用的解法:</p>
<ul>
<li>Linphone core 物件是 nil? -> 不是這個原因</li>
<li>懷疑可能是 liblinphone 的 bug,故升級 liblinphone 的版本到從3.9.1升級到最新版3.13.9 -> 無效</li>
<li>把 linphonecore 從 class static properties 改成 struct static variable -> 無效</li>
<li>使用 <code>XCode Profiler</code> -> 看不出問題</li>
<li>使用 <code>linphone_core_invite</code> 相關的函式放到 background thread -> 無效</li>
<li>DismissViewControllerAnimated() 造成 EXC_Bad_ACCESS <a href="http://goo.gl/5f3V2Z">ref</a> -> 無效</li>
<li>嘗試把 debug optimization level 調成 -Os,讓 debug,release 的情況一致
<img alt="level" src="https://i.imgur.com/JOvis5fl.png"></li>
<li>嘗試 build 一個簡單的 linphone sample proejct </li>
</ul>
<h2>註2: NSZombie</h2>
<p><img alt="NSZombie1" src="https://i.imgur.com/rKF5g9p.png"></p>
<p><img alt="NSZombie2" src="https://i.imgur.com/A8YyocF.png"></p>
<p>NSZombie 原本是設計讓你除錯用的,卻因為我把這個功能開啟,反而造成本地端不會 Crash,上傳到 testflight 的 release 版本就會 crash。在這個 Case 中, NSZombie 沒有辦法找到問題,也許是因為 Crash 的點的是發生在外部函式庫中?</p>Build liblinphone-sdk for iOS2016-06-30T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2016-06-30:/ios-build-linphone-iphone-sdk/<h3>Install git, homebrew</h3>
<p>install git, homebew if you have no one.</p>
<h3>Clone ios-linphone</h3>
<div class="highlight"><pre><span></span><code>$ git clone git://git.linphone.org/linphone-iphone.git --recursive
</code></pre></div>
<p>Remember add <code>--recursive</code> to download submodule</p>
<h3>Excute .prepare.py</h3>
<p>$ ./prepare.py</p>
<p>You may need execute this command many time until you install all dependecies.</p>
<p>In my case, I installed these tools: </p>
<div class="highlight"><pre><span></span><code>$ brew install imagemagick doxygen cmake intltool yasm automake coreutils wget optipng nasm
$ brew install intltool
</code></pre></div>
<p>If it works, you will get the following message:</p>
<div class="highlight"><pre><span></span><code><span class="o">--</span><span class="w"> </span><span class="n">Configuring</span><span class="w"> </span><span class="n">done</span><span class="w"></span>
<span class="o">--</span><span class="w"> </span><span class="n">Generating</span><span class="w"> </span><span class="n">done</span><span class="w"></span>
<span class="o">--</span><span class="w"> </span><span class="n">Build</span><span class="w"> </span><span class="n">files</span><span class="w"> </span><span class="n">have</span><span class="w"> </span><span class="n">been</span><span class="w"> </span><span class="n">written</span><span class="w"> </span><span class="k">to</span><span class="err">:</span><span class="w"> </span><span class="o">/</span><span class="n">Users</span><span class="o">/</span><span class="n">cwliu</span><span class="o">/</span><span class="n">Dev</span><span class="nv">@Local</span><span class="o">/</span><span class="n">WiAdvance</span><span class="o">/</span><span class="mi">1603</span><span class="n">_GoodWox</span><span class="o">/</span><span class="n">liblinphone</span><span class="o">/</span><span class="n">linphone</span><span class="o">-</span><span class="n">iphone</span><span class="o">/</span><span class="k">WORK</span><span class="o">/</span><span class="n">ios</span><span class="o">-</span><span class="n">armv7 …</span></code></pre></div><h3>Install git, homebrew</h3>
<p>install git, homebew if you have no one.</p>
<h3>Clone ios-linphone</h3>
<div class="highlight"><pre><span></span><code>$ git clone git://git.linphone.org/linphone-iphone.git --recursive
</code></pre></div>
<p>Remember add <code>--recursive</code> to download submodule</p>
<h3>Excute .prepare.py</h3>
<p>$ ./prepare.py</p>
<p>You may need execute this command many time until you install all dependecies.</p>
<p>In my case, I installed these tools: </p>
<div class="highlight"><pre><span></span><code>$ brew install imagemagick doxygen cmake intltool yasm automake coreutils wget optipng nasm
$ brew install intltool
</code></pre></div>
<p>If it works, you will get the following message:</p>
<div class="highlight"><pre><span></span><code><span class="o">--</span><span class="w"> </span><span class="n">Configuring</span><span class="w"> </span><span class="n">done</span><span class="w"></span>
<span class="o">--</span><span class="w"> </span><span class="n">Generating</span><span class="w"> </span><span class="n">done</span><span class="w"></span>
<span class="o">--</span><span class="w"> </span><span class="n">Build</span><span class="w"> </span><span class="n">files</span><span class="w"> </span><span class="n">have</span><span class="w"> </span><span class="n">been</span><span class="w"> </span><span class="n">written</span><span class="w"> </span><span class="k">to</span><span class="err">:</span><span class="w"> </span><span class="o">/</span><span class="n">Users</span><span class="o">/</span><span class="n">cwliu</span><span class="o">/</span><span class="n">Dev</span><span class="nv">@Local</span><span class="o">/</span><span class="n">WiAdvance</span><span class="o">/</span><span class="mi">1603</span><span class="n">_GoodWox</span><span class="o">/</span><span class="n">liblinphone</span><span class="o">/</span><span class="n">linphone</span><span class="o">-</span><span class="n">iphone</span><span class="o">/</span><span class="k">WORK</span><span class="o">/</span><span class="n">ios</span><span class="o">-</span><span class="n">armv7</span><span class="o">/</span><span class="n">cmake</span><span class="w"></span>
<span class="nl">INFO</span><span class="p">:</span><span class="w"> </span><span class="n">You</span><span class="w"> </span><span class="n">can</span><span class="w"> </span><span class="n">now</span><span class="w"> </span><span class="n">run</span><span class="w"> </span><span class="s1">'make'</span><span class="w"> </span><span class="k">to</span><span class="w"> </span><span class="n">build</span><span class="p">.</span><span class="w"></span>
<span class="p">...</span><span class="w"></span>
</code></pre></div>
<h3>Make</h3>
<div class="highlight"><pre><span></span><code>$ ./prepare.py -c <span class="o">&&</span> ./prepare.py <span class="o">&&</span> make
</code></pre></div>
<p>Or build debug version: </p>
<div class="highlight"><pre><span></span><code>$ ./prepare.py -c <span class="o">&&</span> ./prepare.py --debug <span class="o">&&</span> make
</code></pre></div>
<h3>Result</h3>
<p>The output will be in <code>liblinphone-sdk</code> folder</p>
<p><img alt="result" src="https://i.imgur.com/8UZvycf.png"></p>Using Haneke for Image Cache in Swift2016-06-22T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2016-06-22:/ios-haneke/<p>如果要在 iOS 上,圖片是從網路下載回來的話,勢必要需要做快取,以避免每一次顯示都要重新載入,今天要介紹一套叫 <a href="https://github.com/Haneke/HanekeSwift">Haneke</a>的 Swift Library, Haneke 是使用 extension 的方法讓 UIImageView 多了一些方法可以做快取。</p>
<p>首先, 安裝可以透過 <a href="https://goo.gl/7MiE6l">CocoPods</a>,這邊不多詳述。使用之前記得要先 import: </p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">Haneke</span>
</code></pre></div>
<p>如果想顯示一張網路上的圖片: http://i.imgur.com/thfn9Ml.jpg,最簡單用法就是</p>
<div class="highlight"><pre><span></span><code>imageView.hnk_setImageFromURL("http://i.imgur.com/thfn9Ml.jpg")
</code></pre></div>
<p>它就會幫你做完下載、快取、重載的動作,相當的方便。另外,若想刪除所有的 image ache,可執行: </p>
<div class="highlight"><pre><span></span><code>Haneke.Shared.imageCache.removeAll()
</code></pre></div>
<p>另外比較進階的用法,像是有一些圖片需要帶 HTTP Header 才有權限存取的話,這邊以加一個 Authorization 的 header 為例,先新增一個自訂的 NetworkFetcher</p>
<div class="highlight"><pre><span></span><code><span class="n">public</span> <span class="k">class</span> <span class="n">BearerHeaderNetworkFetcher</span><span class="o"><</span><span class="n">T</span><span class="p">:</span> <span class="n">DataConvertible</span><span class="o">></span> <span class="p">:</span> <span class="n">NetworkFetcher</span><span class="o"><</span><span class="n">T</span><span class="o">></span> <span class="p">{</span>
<span class="k">var</span> <span class="n">token</span><span class="p">:</span> <span class="nb nb-Type">String</span>
<span class="n">public</span> <span class="n">override</span> <span class="k">var</span> <span class="n">session</span> <span class="p">:</span> <span class="n">NSURLSession</span> <span class="p">{</span>
<span class="n">let</span> <span class="n">configuration</span> <span class="o">=</span> <span class="n">NSURLSessionConfiguration</span><span class="o">.</span><span class="n">defaultSessionConfiguration</span><span class="p">()</span>
<span class="n">configuration</span><span class="o">.</span><span class="n">HTTPAdditionalHeaders</span> <span class="o">=</span> <span class="p">[</span>
<span class="s2">"Authorization"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">token</span>
<span class="p">];</span>
<span class="k">return</span> <span class="n">NSURLSession</span><span class="p">(</span><span class="n">configuration</span><span class="p">:</span> <span class="n">configuration</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">override</span> <span class="n">init</span><span class="p">(</span><span class="n">URL</span> <span class="p">:</span> <span class="n">NSURL</span><span class="p">)</span> <span class="p">{</span>
<span class="bp">self</span><span class="o">.</span><span class="n">token …</span></code></pre></div><p>如果要在 iOS 上,圖片是從網路下載回來的話,勢必要需要做快取,以避免每一次顯示都要重新載入,今天要介紹一套叫 <a href="https://github.com/Haneke/HanekeSwift">Haneke</a>的 Swift Library, Haneke 是使用 extension 的方法讓 UIImageView 多了一些方法可以做快取。</p>
<p>首先, 安裝可以透過 <a href="https://goo.gl/7MiE6l">CocoPods</a>,這邊不多詳述。使用之前記得要先 import: </p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">Haneke</span>
</code></pre></div>
<p>如果想顯示一張網路上的圖片: http://i.imgur.com/thfn9Ml.jpg,最簡單用法就是</p>
<div class="highlight"><pre><span></span><code>imageView.hnk_setImageFromURL("http://i.imgur.com/thfn9Ml.jpg")
</code></pre></div>
<p>它就會幫你做完下載、快取、重載的動作,相當的方便。另外,若想刪除所有的 image ache,可執行: </p>
<div class="highlight"><pre><span></span><code>Haneke.Shared.imageCache.removeAll()
</code></pre></div>
<p>另外比較進階的用法,像是有一些圖片需要帶 HTTP Header 才有權限存取的話,這邊以加一個 Authorization 的 header 為例,先新增一個自訂的 NetworkFetcher</p>
<div class="highlight"><pre><span></span><code><span class="n">public</span> <span class="k">class</span> <span class="n">BearerHeaderNetworkFetcher</span><span class="o"><</span><span class="n">T</span><span class="p">:</span> <span class="n">DataConvertible</span><span class="o">></span> <span class="p">:</span> <span class="n">NetworkFetcher</span><span class="o"><</span><span class="n">T</span><span class="o">></span> <span class="p">{</span>
<span class="k">var</span> <span class="n">token</span><span class="p">:</span> <span class="nb nb-Type">String</span>
<span class="n">public</span> <span class="n">override</span> <span class="k">var</span> <span class="n">session</span> <span class="p">:</span> <span class="n">NSURLSession</span> <span class="p">{</span>
<span class="n">let</span> <span class="n">configuration</span> <span class="o">=</span> <span class="n">NSURLSessionConfiguration</span><span class="o">.</span><span class="n">defaultSessionConfiguration</span><span class="p">()</span>
<span class="n">configuration</span><span class="o">.</span><span class="n">HTTPAdditionalHeaders</span> <span class="o">=</span> <span class="p">[</span>
<span class="s2">"Authorization"</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">token</span>
<span class="p">];</span>
<span class="k">return</span> <span class="n">NSURLSession</span><span class="p">(</span><span class="n">configuration</span><span class="p">:</span> <span class="n">configuration</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">override</span> <span class="n">init</span><span class="p">(</span><span class="n">URL</span> <span class="p">:</span> <span class="n">NSURL</span><span class="p">)</span> <span class="p">{</span>
<span class="bp">self</span><span class="o">.</span><span class="n">token</span> <span class="o">=</span> <span class="s2">""</span>
<span class="n">super</span><span class="o">.</span><span class="n">init</span><span class="p">(</span><span class="n">URL</span><span class="p">:</span> <span class="n">URL</span><span class="p">)</span>
<span class="p">}</span>
<span class="n">convenience</span> <span class="n">init</span><span class="p">(</span><span class="n">URL</span> <span class="p">:</span> <span class="n">NSURL</span><span class="p">,</span> <span class="n">token</span><span class="p">:</span> <span class="nb nb-Type">String</span><span class="p">)</span> <span class="p">{</span>
<span class="bp">self</span><span class="o">.</span><span class="n">init</span><span class="p">(</span><span class="n">URL</span><span class="p">:</span> <span class="n">URL</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">token</span> <span class="o">=</span> <span class="n">token</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>使用的方法就要改呼叫 <code>hnk_setImageFromFetcher()</code></p>
<div class="highlight"><pre><span></span><code>let url = NSURL(string: "https://YOUR_URL")
let fetcher = BearerHeaderNetworkFetcher<UIImage>(URL: url!, token: token)
imageView.hnk_setImageFromFetcher(fetcher)
</code></pre></div>
<h2>Reference</h2>
<ul>
<li><a href="https://goo.gl/mthnwA">Fetch with custom headers · Issue #128 · Haneke/HanekeSwift</a></li>
<li><a href="https://goo.gl/Y2wP4i">Haneke/HanekeSwift: A lightweight generic cache for iOS written in Swift with extra love for images.</a></li>
</ul>在iOS/Swift中使用 liblinphone 函式庫2016-05-12T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2016-05-12:/ios-liblinphone-setup/<p>本文記錄了我在 ios 上面使用 <a href="http://www.linphone.org/technical-corner/liblinphone/overview">Liblinphone</a> 的過程。 </p>
<p>基於 Github <a href="https://goo.gl/wQX6Zx">basefx/linphone-swift</a> 上面的這個專案,<a href="http://goo.gl/P9YHud">StackOverflow 討論</a> 為基礎來修改的。另外,我把這篇的結果也放到 github 上面給大家參考: <a href="https://github.com/cwliu/linphone-swift-demo">https://github.com/cwliu/linphone-swift-demo</a></p>
<h2>把 linphone iOS 加入 Swift 的 Project</h2>
<p>下載 liblinphone SDK: <a href="http://www.linphone.org/releases/ios/liblinphone-iphone-sdk-latest.zip">http://www.linphone.org/releases/ios/liblinphone-iphone-sdk-latest.zip</a></p>
<p>解壓縮之後,裡面是一個<code>liblinphone-sdk</code>的資料夾,把這個資料夾複製到 swift 的專案之中。</p>
<h3>新增 objective-c bridging header</h3>
<p>因為 liblinphone 是 c 的 library,所以要在 swift 的專案中使用的話,要設定<code>bridging header</code>。在 <code>Project Navigator</code>中新增一個 .h Header 設定一個檔名,例如 <code>linphone-swift-demo-Bridging.h</code>。並在 project setting 的 Build Settings > Swift Compiler - Code Generation 中設定<code>Objective-C Bridging Header</code>為這個檔案:</p>
<p>linphonedemo3/bridge.h</p>
<p><img alt="http://i.imgur.com/N5UbxNy.png" src="http://i.imgur.com/N5UbxNy.png"></p>
<p>在這個檔案中加入以下的內容: </p>
<div class="highlight"><pre><span></span><code><span class="c1">#import "linphone/lpconfig.h"</span>
<span class="c1">#import "linphone/linphonecore.h …</span></code></pre></div><p>本文記錄了我在 ios 上面使用 <a href="http://www.linphone.org/technical-corner/liblinphone/overview">Liblinphone</a> 的過程。 </p>
<p>基於 Github <a href="https://goo.gl/wQX6Zx">basefx/linphone-swift</a> 上面的這個專案,<a href="http://goo.gl/P9YHud">StackOverflow 討論</a> 為基礎來修改的。另外,我把這篇的結果也放到 github 上面給大家參考: <a href="https://github.com/cwliu/linphone-swift-demo">https://github.com/cwliu/linphone-swift-demo</a></p>
<h2>把 linphone iOS 加入 Swift 的 Project</h2>
<p>下載 liblinphone SDK: <a href="http://www.linphone.org/releases/ios/liblinphone-iphone-sdk-latest.zip">http://www.linphone.org/releases/ios/liblinphone-iphone-sdk-latest.zip</a></p>
<p>解壓縮之後,裡面是一個<code>liblinphone-sdk</code>的資料夾,把這個資料夾複製到 swift 的專案之中。</p>
<h3>新增 objective-c bridging header</h3>
<p>因為 liblinphone 是 c 的 library,所以要在 swift 的專案中使用的話,要設定<code>bridging header</code>。在 <code>Project Navigator</code>中新增一個 .h Header 設定一個檔名,例如 <code>linphone-swift-demo-Bridging.h</code>。並在 project setting 的 Build Settings > Swift Compiler - Code Generation 中設定<code>Objective-C Bridging Header</code>為這個檔案:</p>
<p>linphonedemo3/bridge.h</p>
<p><img alt="http://i.imgur.com/N5UbxNy.png" src="http://i.imgur.com/N5UbxNy.png"></p>
<p>在這個檔案中加入以下的內容: </p>
<div class="highlight"><pre><span></span><code><span class="c1">#import "linphone/lpconfig.h"</span>
<span class="c1">#import "linphone/linphonecore.h"</span>
<span class="c1">#import "linphone/linphonecore_utils.h"</span>
</code></pre></div>
<h2>修改 Search Paths:</h2>
<p>為了能讓 swift 專案能夠找到這些指定的 *.h header 檔案, 修改 <code>Build Settings > Search Paths</code>: </p>
<ol>
<li><code>User Header Search Path</code> 加入 $(SRCROOT)/liblinphone-sdk/apple-darwin/include</li>
</ol>
<p><img alt="user-header-search-path" src="http://i.imgur.com/WVFWEBC.png"></p>
<ol>
<li><code>Always Search User Paths</code> 設為 <code>Yes</code></li>
</ol>
<p><img alt="Always Search User Paths" src="http://i.imgur.com/DY44SuJ.png"></p>
<h3>修改 Linked Frameworks and Libraries</h3>
<p>先在程式碼任意的地方呼叫 linphone 的函式,例如加上:</p>
<div class="highlight"><pre><span></span><code> linphone_core_set_log_file(nil)
</code></pre></div>
<p>這時侯就可以先嘗試 Build看看,會發生很多 Error,這是正常的,會發生很多 <code>Undefined symbols for architecture</code>,要解決這個問題。</p>
<p>到 Project 設定頁中的 <code>General > Linked Frameworks and Libraries</code>,點選左下角的 <code>+</code> 鍵 ,點選<code>Add Other...</code>。先把 <code>liblinphone-sdk/apple-darwin/lib</code> 跟 <code>linphone-trial/liblinphone-sdk/apple-darwin/lib/mediastreamer</code> 這兩個資料夾中的所有 <em>.a static library 檔加入。另外再加入以下的 </em>.tbd 檔跟 Framework:</p>
<p><img alt="Link Binary With Libraries" src="http://i.imgur.com/KMajEVv.png"></p>
<h2>設定 linphonerc config</h2>
<p>把 linphonerc、linphonerc-factory 這兩個檔案加到 project navigation 中,
linphonerc 跟 linphonerc-factory 的內容可參考<a href="https://github.com/basefx/linphone-swift/blob/master/linphonerc">這裡</a>跟<a href="https://github.com/basefx/linphone-swift/blob/master/linphonerc-factory">這裡</a>。</p>
<h2>執行</h2>
<p>liblinphone 的使用方法這邊就先不多談,可參考: <a href="https://github.com/cwliu/linphone-swift-demo/blob/master/linphone-trial/LinphoneManager.swift">LinphoneManager.swift</a>,裡面有示範要如何撥打電話、接聽電話跟使用 call back 來得知 liblinphone 的一些狀態,像是註冊是否成功或是失敗等等。</p>
<h2>結論</h2>
<p>liblinphone 基本上可以直接使用 swift 開發是沒問題的,只要透過 bridging header 檔案即可使用。只是過程中可能會用到<code>COpaquePointer</code>來跟 linphone 物件溝通就是了。</p>
<h2>更多</h2>
<ul>
<li><a href="http://goo.gl/laUtPf">Liblinphone in C 官方文件</a></li>
<li><a href="http://goo.gl/hCahBO">Liblinphone 整合步驟討論</a></li>
<li><a href="http://goo.gl/YVKuRP">Linphone-iOS-移植 - 简书</a></li>
<li><a href="https://goo.gl/v1gOHn">官方 linphone-iphone github </a></li>
</ul>Set environment variable in Azure App Services2016-05-09T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2016-05-09:/azure-env/<p>找了一下才知道要如何在 後台設定,設定的位置在 <code>Application settings</code> 中</p>
<p><img alt="app-settings" src="http://i.imgur.com/ufdjCmY.png"></p>使用 Liblinphone Android SDK 撥打 SIP 電話2016-03-31T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2016-03-31:/liblinphone/<h2>前言</h2>
<p>如果想在 Android 上開發 <a href="http://www.siptutorial.net/SIP/index.html">SIP</a> 應用的話,可以考慮 Linphone 推出的 SDK 叫 <a href="http://www.linphone.org/technical-corner/liblinphone/overview">liblinphone</a>,這是一套開源的 SIP 套件,採用 GPLv2 授權,目前由<em>Belledonne Communications</em>公司所維護。</p>
<p>這篇簡單介紹一下在 Android 上面開發 Linphone 的關鍵步驟</p>
<h2>下載 liblinphone SDK for Android</h2>
<p>此時最新的版本是 2.5.0: https://www.linphone.org/releases/android/linphone-android-sdk-latest.zip</p>
<p>解開下載回來的 zip:</p>
<div class="highlight"><pre><span></span><code>├── armeabi
│ └── liblinphone-armeabi.so
├── armeabi-v7a
│ ├── libffmpeg-linphone-arm.so
│ └── liblinphone-armeabi-v7a.so
├── linphone.jar
└── x86
├── libffmpeg-linphone-x86.so
└── liblinphone-x86.so
</code></pre></div>
<p>包含了 linphone.jar 跟其它的 so 檔案。這是因為 liblinphone 底層主要還是由 C/C++ 語言組成,而透過用 jni 的方式來讓 java 程式可以使用。</p>
<h2>Android Studio 設定</h2>
<p>在預設的 build.gradle 之中,因為都有包含</p>
<div class="highlight"><pre><span></span><code><span class="nv">dependencies</span> {
<span class="nv">compile</span> <span class="nv">fileTree</span><span class="ss">(</span><span class="k">include</span>: [<span class="s1">'</span><span class="s">*.jar</span><span class="s1">'</span>], <span class="nv">dir</span>: <span class="s1">'</span><span class="s">libs</span><span class="s1">'</span><span class="ss">)</span>
}
</code></pre></div>
<p>所以最簡單的方式就是把 linphone.jar 放到 <code>libs</code> 資料夾中(跟 …</p><h2>前言</h2>
<p>如果想在 Android 上開發 <a href="http://www.siptutorial.net/SIP/index.html">SIP</a> 應用的話,可以考慮 Linphone 推出的 SDK 叫 <a href="http://www.linphone.org/technical-corner/liblinphone/overview">liblinphone</a>,這是一套開源的 SIP 套件,採用 GPLv2 授權,目前由<em>Belledonne Communications</em>公司所維護。</p>
<p>這篇簡單介紹一下在 Android 上面開發 Linphone 的關鍵步驟</p>
<h2>下載 liblinphone SDK for Android</h2>
<p>此時最新的版本是 2.5.0: https://www.linphone.org/releases/android/linphone-android-sdk-latest.zip</p>
<p>解開下載回來的 zip:</p>
<div class="highlight"><pre><span></span><code>├── armeabi
│ └── liblinphone-armeabi.so
├── armeabi-v7a
│ ├── libffmpeg-linphone-arm.so
│ └── liblinphone-armeabi-v7a.so
├── linphone.jar
└── x86
├── libffmpeg-linphone-x86.so
└── liblinphone-x86.so
</code></pre></div>
<p>包含了 linphone.jar 跟其它的 so 檔案。這是因為 liblinphone 底層主要還是由 C/C++ 語言組成,而透過用 jni 的方式來讓 java 程式可以使用。</p>
<h2>Android Studio 設定</h2>
<p>在預設的 build.gradle 之中,因為都有包含</p>
<div class="highlight"><pre><span></span><code><span class="nv">dependencies</span> {
<span class="nv">compile</span> <span class="nv">fileTree</span><span class="ss">(</span><span class="k">include</span>: [<span class="s1">'</span><span class="s">*.jar</span><span class="s1">'</span>], <span class="nv">dir</span>: <span class="s1">'</span><span class="s">libs</span><span class="s1">'</span><span class="ss">)</span>
}
</code></pre></div>
<p>所以最簡單的方式就是把 linphone.jar 放到 <code>libs</code> 資料夾中(跟 src 資料夾平行),並在 src -> main 資料夾中開一個 jniLibs 來放置 所有的 *.so 檔案,最後整個檔案結構就會變成: </p>
<div class="highlight"><pre><span></span><code>├── libs
│ └── linphone.jar
└── src
└── main
└── jniLibs
├── armeabi
│ └── liblinphone-armeabi.so
├── armeabi-v7a
│ ├── libffmpeg-linphone-arm.so
│ └── liblinphone-armeabi-v7a.so
└── x86
├── libffmpeg-linphone-x86.so
└── liblinphone-x86.so
</code></pre></div>
<p>這樣就完成了設置,雖然不像大部份 Library 可以只加一行到 gradle 就可以完成載入,但透過這樣的說明應該還是可以很快地設定完成的。</p>
<h2>Linephone 重要類別</h2>
<p>開始使用 Linphone 前,先了解一下重要類別</p>
<p><code>LinphoneCore</code>: 每一個 application 都要有一個 LinphoneCore 物件,是個 Singleton 物件,在做任何 SIP 操作都是透過這個物件,可以透過 <code>LinphoneCoreFactory</code> 來產生 LinphoneCore。</p>
<p><code>LinphoneCoreListener</code>: 重要的 callbacks 當使用者註冊跟撥打/接通電話都會執行這些 callbacks,讓我們的應用程式可以做出像對應的動作,像是當有來電的時侯,應該要怎麼回應。</p>
<p><code>org.linphone.LinphoneManager</code>: 雖然 LinPhone library 裡面有自帶一個 LinphoneManager,看 api 好像可以幫你做很多事,不過我建議不要用這 LinPhoneManager,直接忽略他,因為裡面連接一些外部聲音、圖檔資源是找不到的,很多網路上的 code snippet 都有用到這個。這個類別我猜測是給 Linephone app 使用的,而非開放給外部使用。</p>
<h2>打開 Debug log</h2>
<p>對於 SIP protocol 不熟的人,可能完全不曉得 linphone 到底怎麼運作,我強烈建議一開始就把 debug 打開,會跑出很多訊息,加上這個設置對於剛開始了解整個 linphone 流程會有很有幫助。</p>
<div class="highlight"><pre><span></span><code>LinphoneCoreFactory.instance().setDebugMode(true, "YOURNAME");
</code></pre></div>
<h2>建立 LinePhoneCore</h2>
<p>透過<code>LinphoneCoreFactory</code>建立</p>
<div class="highlight"><pre><span></span><code>mLinphoneCore = LinphoneCoreFactory.instance().createLinphoneCore(youLinphoneCoreListener, context);
//optional setting based on your needs
mLinphoneCore.setMaxCalls(3);
mLinphoneCore.setNetworkReachable(true);
mLinphoneCore.enableVideo(false, false);
</code></pre></div>
<p>用完時記得釋放資源</p>
<div class="highlight"><pre><span></span><code>try {
mLinphoneCore.destroy();
} catch (RuntimeException e) {
e.printStackTrace();
} finally {
mLinphoneCore = null;
}
</code></pre></div>
<h2>撥打電話</h2>
<p>要撥打電話前,首先要跟SIP Server 註冊帳號,大致的流程如下</p>
<div class="highlight"><pre><span></span><code><span class="n">String</span> <span class="n">identity</span> <span class="o">=</span> <span class="s">"sip:"</span> <span class="o">+</span> <span class="n">account</span> <span class="o">+</span> <span class="s">"@"</span> <span class="o">+</span> <span class="n">domain</span><span class="p">;</span>
<span class="n">proxyConfig</span> <span class="o">=</span> <span class="n">linphoneCore</span><span class="p">.</span><span class="n">createProxyConfig</span><span class="p">(</span><span class="n">identity</span><span class="p">,</span> <span class="n">domain</span><span class="p">,</span> <span class="n">null</span><span class="p">,</span> <span class="nb">true</span><span class="p">);</span>
<span class="n">proxyConfig</span><span class="p">.</span><span class="n">setExpires</span><span class="p">(</span><span class="mi">300</span><span class="p">);</span>
<span class="n">linphoneCore</span><span class="p">.</span><span class="n">addProxyConfig</span><span class="p">(</span><span class="n">proxyConfig</span><span class="p">);</span>
<span class="n">LinphoneAuthInfo</span> <span class="n">authInfo</span> <span class="o">=</span> <span class="n">LinphoneCoreFactory</span><span class="p">.</span><span class="n">instance</span><span class="p">().</span><span class="n">createAuthInfo</span><span class="p">(</span>
<span class="n">account</span><span class="p">,</span> <span class="n">password</span><span class="p">,</span> <span class="n">null</span><span class="p">,</span> <span class="n">domain</span><span class="p">);</span>
<span class="n">linphoneCore</span><span class="p">.</span><span class="n">addAuthInfo</span><span class="p">(</span><span class="n">authInfo</span><span class="p">);</span>
<span class="n">linphoneCore</span><span class="p">.</span><span class="n">setDefaultProxyConfig</span><span class="p">(</span><span class="n">proxyConfig</span><span class="p">);</span>
</code></pre></div>
<p>撥打電話的流程</p>
<div class="highlight"><pre><span></span><code><span class="n">LinphoneCall</span> <span class="n">call</span> <span class="o">=</span> <span class="n">linphoneCore</span><span class="p">.</span><span class="na">invite</span><span class="p">(</span><span class="n">account</span><span class="p">);</span>
<span class="kt">boolean</span> <span class="n">isConnected</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="kt">long</span> <span class="n">iterateIntervalMs</span> <span class="o">=</span> <span class="mi">50L</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">call</span> <span class="o">==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="n">Log</span><span class="p">.</span><span class="na">d</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"Could not place call to"</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">Log</span><span class="p">.</span><span class="na">d</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"Call to: "</span> <span class="o">+</span> <span class="n">account</span><span class="p">);</span>
<span class="k">while</span> <span class="p">(</span><span class="n">mIsCalling</span><span class="p">)</span> <span class="p">{</span>
<span class="n">linphoneCore</span><span class="p">.</span><span class="na">iterate</span><span class="p">();</span>
<span class="k">try</span> <span class="p">{</span>
<span class="n">Thread</span><span class="p">.</span><span class="na">sleep</span><span class="p">(</span><span class="n">iterateIntervalMs</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">call</span><span class="p">.</span><span class="na">getState</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">LinphoneCall</span><span class="p">.</span><span class="na">State</span><span class="p">.</span><span class="na">CallEnd</span><span class="p">)</span>
<span class="o">||</span> <span class="n">call</span><span class="p">.</span><span class="na">getState</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">LinphoneCall</span><span class="p">.</span><span class="na">State</span><span class="p">.</span><span class="na">CallReleased</span><span class="p">))</span> <span class="p">{</span>
<span class="n">mIsCalling</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">call</span><span class="p">.</span><span class="na">getState</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">LinphoneCall</span><span class="p">.</span><span class="na">State</span><span class="p">.</span><span class="na">StreamsRunning</span><span class="p">))</span> <span class="p">{</span>
<span class="n">isConnected</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="c1">// do your stuff</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">call</span><span class="p">.</span><span class="na">getState</span><span class="p">().</span><span class="na">equals</span><span class="p">(</span><span class="n">LinphoneCall</span><span class="p">.</span><span class="na">State</span><span class="p">.</span><span class="na">OutgoingRinging</span><span class="p">))</span> <span class="p">{</span>
<span class="c1">// do your stuff</span>
<span class="p">}</span>
<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">InterruptedException</span> <span class="n">var8</span><span class="p">)</span> <span class="p">{</span>
<span class="n">Log</span><span class="p">.</span><span class="na">d</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"Interrupted! Aborting"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">LinphoneCall</span><span class="p">.</span><span class="na">State</span><span class="p">.</span><span class="na">CallEnd</span><span class="p">.</span><span class="na">equals</span><span class="p">(</span><span class="n">call</span><span class="p">.</span><span class="na">getState</span><span class="p">()))</span> <span class="p">{</span>
<span class="n">Log</span><span class="p">.</span><span class="na">d</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"Terminating the call"</span><span class="p">);</span>
<span class="n">linphoneCore</span><span class="p">.</span><span class="na">terminateCall</span><span class="p">(</span><span class="n">call</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>最簡單的方式就是直接從<code>org.linphone.core.LinphoneCoreListener</code>裡的<code>callState()</code>來了解撥打的流程。撥打電話一共會經過下列的 states:</p>
<p>OutgoingInit、OutgoingProgress、OutgoingRinging、Connected、StreamsRunning、CallEnd、Released</p>
<h2>接聽電話</h2>
<p>接聽電話很簡單,當上面註冊完之後,當有 sip 電話打進來時會進入 callState() 的 callback,偵測有來電的程式片段如下: </p>
<div class="highlight"><pre><span></span><code><span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">callState</span><span class="p">(</span><span class="n">LinphoneCore</span> <span class="n">core</span><span class="p">,</span> <span class="n">LinphoneCall</span> <span class="n">call</span><span class="p">,</span> <span class="n">LinphoneCall</span><span class="p">.</span><span class="na">State</span> <span class="n">state</span><span class="p">,</span> <span class="n">String</span> <span class="n">s</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span><span class="p">(</span><span class="n">state</span><span class="p">.</span><span class="na">equals</span><span class="p">(</span><span class="n">LinphoneCall</span><span class="p">.</span><span class="na">State</span><span class="p">.</span><span class="na">IncomingReceived</span><span class="p">))</span> <span class="p">{</span>
<span class="c1">// YOU HAVE AN INCOMING CALL </span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>當決定要接的時侯,執行片段如下: </p>
<div class="highlight"><pre><span></span><code><span class="n">List</span> <span class="n">address</span> <span class="o">=</span> <span class="n">LinphoneUtils</span><span class="p">.</span><span class="na">getLinphoneCalls</span><span class="p">(</span><span class="n">mLc</span><span class="p">);</span>
<span class="n">Iterator</span> <span class="n">contact</span> <span class="o">=</span> <span class="n">address</span><span class="p">.</span><span class="na">iterator</span><span class="p">();</span>
<span class="k">while</span> <span class="p">(</span><span class="n">contact</span><span class="p">.</span><span class="na">hasNext</span><span class="p">())</span> <span class="p">{</span>
<span class="n">mLinephoneCall</span> <span class="o">=</span> <span class="p">(</span><span class="n">LinphoneCall</span><span class="p">)</span> <span class="n">contact</span><span class="p">.</span><span class="na">next</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span><span class="n">LinphoneCall</span><span class="p">.</span><span class="na">State</span><span class="p">.</span><span class="na">IncomingReceived</span> <span class="o">==</span> <span class="n">mLinephoneCall</span><span class="p">.</span><span class="na">getState</span><span class="p">())</span> <span class="p">{</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">mLinephoneCall</span> <span class="o">==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="n">Log</span><span class="p">.</span><span class="na">e</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"Couldn\'t find incoming call"</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">LinphoneCallParams</span> <span class="n">params</span> <span class="o">=</span> <span class="n">mLc</span><span class="p">.</span><span class="na">createDefaultCallParameters</span><span class="p">();</span>
<span class="n">params</span><span class="p">.</span><span class="na">enableLowBandwidth</span><span class="p">(</span><span class="kc">false</span><span class="p">);</span>
<span class="n">LinphoneAddress</span> <span class="n">address1</span> <span class="o">=</span> <span class="n">mLinephoneCall</span><span class="p">.</span><span class="na">getRemoteAddress</span><span class="p">();</span>
<span class="n">Log</span><span class="p">.</span><span class="na">d</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"Find a incoming call, number: "</span> <span class="o">+</span> <span class="n">address1</span><span class="p">.</span><span class="na">asStringUriOnly</span><span class="p">());</span>
<span class="k">try</span> <span class="p">{</span>
<span class="n">mLc</span><span class="p">.</span><span class="na">acceptCallWithParams</span><span class="p">(</span><span class="n">mLinephoneCall</span><span class="p">,</span> <span class="n">params</span><span class="p">);</span>
<span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">LinphoneCoreException</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
<span class="n">Log</span><span class="p">.</span><span class="na">e</span><span class="p">(</span><span class="n">TAG</span><span class="p">,</span> <span class="s">"Accept Call exception: "</span><span class="p">,</span> <span class="n">e</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>掛斷電話的片段如下: </p>
<div class="highlight"><pre><span></span><code><span class="k">if</span> <span class="p">(</span><span class="n">mLinephoneCall</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="n">mLc</span><span class="p">.</span><span class="na">terminateCall</span><span class="p">(</span><span class="n">mLinephoneCall</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>或是直接拒聽 </p>
<div class="highlight"><pre><span></span><code><span class="n">mLc</span><span class="p">.</span><span class="na">declineCall</span><span class="p">(</span><span class="n">mLinephoneCall</span><span class="p">,</span> <span class="n">Reason</span><span class="p">.</span><span class="na">Declined</span><span class="p">);</span>
</code></pre></div>
<h2>結論</h2>
<p>整個 SIP 最簡單的<code>註冊</code>、<code>撥號</code>、<code>接聽</code>的關鍵流程如上。因為 linphone 是 opensource 的,所以如果想了解 linphone 的更多細節流程,除了直接看<a href="http://www.linphone.org/docs/liblinphone-javadoc/">API 說明文件</a>之外,最好的方法就直接看 <a href="https://play.google.com/store/apps/details?id=org.linphone">linephone app</a> 的 <a href="https://github.com/BelledonneCommunications/linphone-android">source code</a>,而對岸也有高手發表一系列的
<a href="http://xzhoumin.blog.163.com/blog/#m=0&t=1&c=fks_085066084083084067084094081095080086089075085087085069">liblinphone 教程</a>,也很完整,值得參考。</p>
<p>PS: 在用 linphone 之前有個小插曲,原本是用 android 內建的 <a href="http://developer.android.com/intl/zh-tw/guide/topics/connectivity/sip.html">sip library</a>的,只是這個 Library 竟然在最新的 samsung 手機不支援,所以就改用其它的 solution,最後採用 linphone。</p>
<!--
## 其它連結
- [基于linphone实现视频通话小结_百度文库](http://wenku.baidu.com/view/29976bc3aa00b52acfc7ca58.html)
## 取得上線狀態
section 3.2 of RFC 4480
`Managing Buddies and buddy list and presence` 有說明
<div class="highlight"><pre><span></span><code><span class="nv">LinphoneFriend</span>[] <span class="nv">friends</span> <span class="o">=</span> <span class="nv">LinphoneManager</span>.<span class="nv">getLc</span><span class="ss">()</span>.<span class="nv">getFriendList</span><span class="ss">()</span><span class="c1">;</span>
<span class="k">if</span> <span class="ss">(</span><span class="o">!</span><span class="nv">ContactsManager</span>.<span class="nv">getInstance</span><span class="ss">()</span>.<span class="nv">isContactPresenceDisabled</span><span class="ss">()</span> <span class="o">&&</span> <span class="nv">friends</span> <span class="o">!=</span> <span class="nv">null</span><span class="ss">)</span> {
<span class="nv">friendStatus</span>.<span class="nv">setVisibility</span><span class="ss">(</span><span class="nv">View</span>.<span class="nv">VISIBLE</span><span class="ss">)</span><span class="c1">;</span>
<span class="nv">PresenceActivityType</span> <span class="nv">presenceActivity</span> <span class="o">=</span> <span class="nv">friends</span>[<span class="mi">0</span>].<span class="nv">getPresenceModel</span><span class="ss">()</span>.<span class="nv">getActivity</span><span class="ss">()</span>.<span class="nv">getType</span><span class="ss">()</span><span class="c1">;</span>
<span class="k">if</span> <span class="ss">(</span><span class="nv">presenceActivity</span> <span class="o">==</span> <span class="nv">PresenceActivityType</span>.<span class="nv">Online</span><span class="ss">)</span> {
<span class="nv">friendStatus</span>.<span class="nv">setImageResource</span><span class="ss">(</span><span class="nv">R</span>.<span class="nv">drawable</span>.<span class="nv">led_connected</span><span class="ss">)</span><span class="c1">;</span>
} <span class="k">else</span> <span class="k">if</span> <span class="ss">(</span><span class="nv">presenceActivity</span> <span class="o">==</span> <span class="nv">PresenceActivityType</span>.<span class="nv">Busy</span><span class="ss">)</span> {
<span class="nv">friendStatus</span>.<span class="nv">setImageResource</span><span class="ss">(</span><span class="nv">R</span>.<span class="nv">drawable</span>.<span class="nv">led_error</span><span class="ss">)</span><span class="c1">;</span>
} <span class="k">else</span> <span class="k">if</span> <span class="ss">(</span><span class="nv">presenceActivity</span> <span class="o">==</span> <span class="nv">PresenceActivityType</span>.<span class="nv">Away</span><span class="ss">)</span> {
<span class="nv">friendStatus</span>.<span class="nv">setImageResource</span><span class="ss">(</span><span class="nv">R</span>.<span class="nv">drawable</span>.<span class="nv">led_inprogress</span><span class="ss">)</span><span class="c1">;</span>
} <span class="k">else</span> <span class="k">if</span> <span class="ss">(</span><span class="nv">presenceActivity</span> <span class="o">==</span> <span class="nv">PresenceActivityType</span>.<span class="nv">Offline</span><span class="ss">)</span> {
<span class="nv">friendStatus</span>.<span class="nv">setImageResource</span><span class="ss">(</span><span class="nv">R</span>.<span class="nv">drawable</span>.<span class="nv">led_disconnected</span><span class="ss">)</span><span class="c1">;</span>
} <span class="k">else</span> {
<span class="nv">friendStatus</span>.<span class="nv">setImageResource</span><span class="ss">(</span><span class="nv">R</span>.<span class="nv">drawable</span>.<span class="nv">call_quality_indicator_0</span><span class="ss">)</span><span class="c1">;</span>
}
}
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="n">addFriend</span><span class="p">(</span><span class="n">LinphoneFriend</span><span class="w"> </span><span class="n">lf</span><span class="p">)</span><span class="w"></span>
<span class="n">LinphoneFriend</span><span class="w"> </span><span class="n">friend</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">LinphoneCoreFactory</span><span class="p">.</span><span class="n">instance</span><span class="p">().</span><span class="n">createLinphoneFriend</span><span class="p">(</span><span class="n">sipUri</span><span class="p">);</span><span class="w"></span>
<span class="n">friend</span><span class="p">.</span><span class="n">edit</span><span class="p">();</span><span class="w"></span>
<span class="n">friend</span><span class="p">.</span><span class="n">enableSubscribes</span><span class="p">(</span><span class="k">false</span><span class="p">);</span><span class="w"></span>
<span class="n">friend</span><span class="p">.</span><span class="n">setRefKey</span><span class="p">(</span><span class="n">contact</span><span class="p">.</span><span class="n">getID</span><span class="p">());</span><span class="w"></span>
<span class="n">friend</span><span class="p">.</span><span class="n">done</span><span class="p">();</span><span class="w"></span>
<span class="nl">sip</span><span class="p">:</span><span class="n">joe</span><span class="nv">@sip</span><span class="p">.</span><span class="n">linphone</span><span class="p">.</span><span class="n">org</span><span class="w"></span>
<span class="n">getPresenceModel</span><span class="p">()</span><span class="w"></span>
</code></pre></div>
了解 SUBSCRIBE
https://andrewjprokop.wordpress.com/2013/06/21/sip-subscribe-notify-and-publish/
I/WiAdvance: channel [0x9f042000]: keep alive sent to [UDP://210.202.37.33:5060]
-->使用 Style 或 Theme 修改 Android 元件的外觀2016-02-19T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2016-02-19:/style-theme/<h2>前言</h2>
<p>在 Android 中有 <em>style</em> 跟 <em>theme</em> 兩種不同方式來設定元件的外觀</p>
<h2>Style</h2>
<p>在 <code>res/values/styles.xml</code> 新增一個 style 標籤,讓View的背景顯示為深藍色:</p>
<div class="highlight"><pre><span></span><code><span class="nt"><resources></span>
...
<span class="nt"><style</span> <span class="na">name=</span><span class="s">"BeatBoxButton"</span><span class="nt">></span>
<span class="nt"><item</span> <span class="na">name=</span><span class="s">"android:background"</span><span class="nt">></span>@color/dark_blue<span class="nt"></item></span>
<span class="nt"></style></span>
<span class="nt"></resources></span>
</code></pre></div>
<p>使用方式則是在想套用這個 stytle 的 view 物件上加上 style 屬性:</p>
<div class="highlight"><pre><span></span><code><span class="o"><</span><span class="n">Button</span><span class="w"></span>
<span class="w"> </span><span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="n">style</span><span class="o">=</span><span class="ss">"@style/BeatBoxButton.Bold"</span><span class="o">/></span><span class="w"></span>
</code></pre></div>
<p>這麼做的好處就是當應用程式如果有很多 button,若是要換別的顏色的話,就只要更新 style 就好了。</p>
<h3>Style inheritance</h3>
<p>另外 style 跟 class 一樣有繼承的使用方式</p>
<p>方法一:</p>
<p>加上 parent 的屬性:</p>
<div class="highlight"><pre><span></span><code><span class="nt"><style</span> <span class="na">name=</span><span class="s">"MyButtonStrong"</span> <span class="na">parent=</span><span class="s">"MyBoxButton"</span><span class="nt">></span>
<span class="nt"><item</span> <span class="na">name=</span><span class="s">"android:textStyle"</span><span class="nt">></span>bold<span class="nt"></item></span>
<span class="nt"></style></span>
</code></pre></div>
<p>方法二:</p>
<p>在 Parent 的名稱後面直接加上 <code>.</code>,例如: "MyButton.Bold"</p>
<div class="highlight"><pre><span></span><code><span class="nt"><style</span> <span class="na">name=</span><span class="s">MyBoxButton.Bold"</span><span class="nt">></span>
<span class="nt"><item</span> <span class="na">name=</span><span class="s">"android:textStyle"</span><span class="nt">></span>bold<span class="nt"></item></span>
<span class="nt"></style></span>
</code></pre></div>
<p>兩這種方法都可以達到 style inheritance 的效果</p>
<h2>Theme</h2>
<p>針對整體性的 style,如果 app 有 …</p><h2>前言</h2>
<p>在 Android 中有 <em>style</em> 跟 <em>theme</em> 兩種不同方式來設定元件的外觀</p>
<h2>Style</h2>
<p>在 <code>res/values/styles.xml</code> 新增一個 style 標籤,讓View的背景顯示為深藍色:</p>
<div class="highlight"><pre><span></span><code><span class="nt"><resources></span>
...
<span class="nt"><style</span> <span class="na">name=</span><span class="s">"BeatBoxButton"</span><span class="nt">></span>
<span class="nt"><item</span> <span class="na">name=</span><span class="s">"android:background"</span><span class="nt">></span>@color/dark_blue<span class="nt"></item></span>
<span class="nt"></style></span>
<span class="nt"></resources></span>
</code></pre></div>
<p>使用方式則是在想套用這個 stytle 的 view 物件上加上 style 屬性:</p>
<div class="highlight"><pre><span></span><code><span class="o"><</span><span class="n">Button</span><span class="w"></span>
<span class="w"> </span><span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="n">style</span><span class="o">=</span><span class="ss">"@style/BeatBoxButton.Bold"</span><span class="o">/></span><span class="w"></span>
</code></pre></div>
<p>這麼做的好處就是當應用程式如果有很多 button,若是要換別的顏色的話,就只要更新 style 就好了。</p>
<h3>Style inheritance</h3>
<p>另外 style 跟 class 一樣有繼承的使用方式</p>
<p>方法一:</p>
<p>加上 parent 的屬性:</p>
<div class="highlight"><pre><span></span><code><span class="nt"><style</span> <span class="na">name=</span><span class="s">"MyButtonStrong"</span> <span class="na">parent=</span><span class="s">"MyBoxButton"</span><span class="nt">></span>
<span class="nt"><item</span> <span class="na">name=</span><span class="s">"android:textStyle"</span><span class="nt">></span>bold<span class="nt"></item></span>
<span class="nt"></style></span>
</code></pre></div>
<p>方法二:</p>
<p>在 Parent 的名稱後面直接加上 <code>.</code>,例如: "MyButton.Bold"</p>
<div class="highlight"><pre><span></span><code><span class="nt"><style</span> <span class="na">name=</span><span class="s">MyBoxButton.Bold"</span><span class="nt">></span>
<span class="nt"><item</span> <span class="na">name=</span><span class="s">"android:textStyle"</span><span class="nt">></span>bold<span class="nt"></item></span>
<span class="nt"></style></span>
</code></pre></div>
<p>兩這種方法都可以達到 style inheritance 的效果</p>
<h2>Theme</h2>
<p>針對整體性的 style,如果 app 有 100 個按扭,那麼要在每一個按扭都加上 style 的話,那就太麻煩了。所以 Android 有另一種 Theme 的機制,可以一次修改所有元件的外觀。</p>
<p>在 AndroidManifest.xml,預設會使用 <code>@style/AppTheme</code> 這個 tehme:</p>
<div class="highlight"><pre><span></span><code><span class="o"><</span><span class="n">application</span><span class="w"></span>
<span class="w"> </span><span class="p">...</span><span class="w"></span>
<span class="w"> </span><span class="nl">android</span><span class="p">:</span><span class="n">theme</span><span class="o">=</span><span class="ss">"@style/AppTheme"</span><span class="o">></span><span class="w"></span>
</code></pre></div>
<p>代表我們這個 App 是使用 <code>AppTheme</code> 的 theme</p>
<h3>範例1,修改整個 Application button 的樣式</h3>
<p>比如說我想要修改全部 button 的 style。修改 styles.xml:</p>
<div class="highlight"><pre><span></span><code><span class="c"><!-- Base application theme. --></span>
<span class="nt"><style</span> <span class="na">name=</span><span class="s">"AppTheme"</span> <span class="na">parent=</span><span class="s">"Theme.AppCompat.Light.DarkActionBar"</span><span class="nt">></span>
...
<span class="nt"><item</span> <span class="na">name=</span><span class="s">"android:buttonStyle"</span><span class="nt">></span>@style/BeatBoxButtonTheme<span class="nt"></item></span>
<span class="nt"></style></span>
<span class="c"><!-- theme way--></span>
<span class="nt"><style</span> <span class="na">name=</span><span class="s">"BeatBoxButtonTheme"</span> <span class="na">parent=</span><span class="s">"@android:style/Widget.Holo.Light.Button"</span><span class="nt">></span>
<span class="nt"><item</span> <span class="na">name=</span><span class="s">"android:background"</span><span class="nt">></span>@color/dark_blue<span class="nt"></item></span>
<span class="nt"><item</span> <span class="na">name=</span><span class="s">"android:textStyle"</span><span class="nt">></span>bold<span class="nt"></item></span>
<span class="nt"></style></span>
</code></pre></div>
<p>這樣所有的按鈕就會自動套用 style 而不用一個一個設定了,這就是使用 Theme 的好處 :)</p>
<h3>範例2,修改整個 Application text 的樣式</h3>
<div class="highlight"><pre><span></span><code><span class="nt"><style</span> <span class="na">name=</span><span class="s">"AppTheme"</span>
<span class="err"><item</span> <span class="na">name=</span><span class="s">"android:textColor"</span><span class="nt">></span>@color/black<span class="nt"></item></span>
<span class="nt"></style></span>
<span class="nt"><style</span> <span class="na">name=</span><span class="s">"button"</span> <span class="na">parent=</span><span class="s">"@style/Widget.AppCompat.Button"</span><span class="nt">></span>
<span class="c"><!--<item name="android:background">@android:color/white</item>--></span>
<span class="c"><!--<item name="android:textColor">@color/blue</item>--></span>
<span class="c"><!--<item name="android:textSize">16sp</item>--></span>
<span class="nt"></style></span>
</code></pre></div>
<h2>Reference</h2>
<ul>
<li><a href="http://developer.android.com/guide/topics/ui/themes.html">Styles and Themes | Android Developers</a></li>
</ul>解決開啟 android emulator 記憶體用量不足的問題2016-02-18T00:00:00+08:002018-03-30T04:39:47+08:00Cody Liutag:blog.codylab.com,2016-02-18:/hax-memory-excced/<p>最近 Android 2.0 新推出 Emulator 比過去的效能好很多,所以就從用 Genymotion 改回用 Google 的 Emulator,但是在開發的時侯,發生一個小問題,在我的 Mac 上面沒辦法同時間開多個 Emulator,會出現以下錯誤訊息:</p>
<blockquote>
<p>emulator: The memory needed by this VM exceeds the driver limit.
HAX is not working and emulator runs in emulation mode</p>
</blockquote>
<p>在 OSX 的解決方案如下:</p>
<p>找到 Android SDK 裡面的 <code>android-sdk-macosx/extras/intel/Hardware_Accelerated_Execution_Manager</code> 資料夾裡面有一個 <code>HAXM installation</code>執行檔,可以重新安裝 HAXM(Intel Hardware Accelerated Execution Manager),增加記憶體用量:</p>
<div class="highlight"><pre><span></span><code>$ ./HAXM<span class="se">\ </span>installation -m <最大記憶體使用量>
</code></pre></div>
<p>例如,我想同時間開啟 Nexus 5X,跟 Nexus 5P。這兩支各別都是 1.5 GB的記憶體使用量,所以需要把 HAX 增加到 3072MB:</p>
<div class="highlight"><pre><span></span><code>$ ./HAXM<span class="se">\ </span>installation -m <span class="m">3072</span>
</code></pre></div>
<p>安裝完成之後就可以同時開兩個 Android emulator 了:</p>
<p><img alt="nexus5x-neux5p" src="http://i.imgur.com/jJdbnGul.png"></p>在 Genymotion 的 Android 6.0 Marshmallow 裝置上安裝 Google Apps2016-01-15T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2016-01-15:/genymotion/<p><img alt="genymotion" src="http://i.imgur.com/teP6juM.png"></p>
<p>Android Studio 官方有 AVD(Android Virtual Device),運作在 QEMU 的 Emulator 之上,使用上效率不好,所以近期開發 Android 都是使用 <a href="https://www.genymotion.com/">Genymotion</a> 這套 Android emulator(仿真器)上。Genymotion 是基於 VirtualBox 基礎上,而 Genymotion 上的 virtual device 預設沒有Google Play、Google Maps 等 Google Apps。如果想要在上面裝 Google Apps,需要以下額外的設定: </p>
<p>註: 如果要安裝 gapps 在 Genymotion 推出的 <code>PREVIEW - Google Nexus 5X - 6.0.0</code> 或 <code>PREVIEW - Google Nexus 5P - 6.0.0</code>話,則需要額外的步驟:</p>
<ol>
<li>安裝 <a href="http://www.mirrorcreator.com/files/0ZIO8PME/Genymotion-ARM-Translation_v1.1.zip_links">Genymotion-ARM-Translation_v1.1.zip</a>,重啟裝置</li>
</ol>
<p><img alt="install-1" src="http://i.imgur.com/UZfF996l.png"></p>
<p><img alt="install-2" src="http://i.imgur.com/U8qStNvl.png"></p>
<ol>
<li>安裝 <a href="https://www.androidfilehost.com/?fid=96042739161891406 - gapps-L-4-21-15.zip">gapps-L-4-21-15.zip</a></li>
<li>先登入 Google 帳號</li>
<li>安裝 <a href="https://www.androidfilehost.com/?fid=24052804347835438 - benzo-gapps-M-20151011-signed-chroma-r3.zip">benzo-gapps-M-20151011-signed-chroma-r3.zip</a>,重啟裝置</li>
</ol>
<p><img alt="google-play" src="http://i.imgur.com/uhP04jal.png"></p>
<p>這樣就有 Google Play 可以用了</p>
<!--
首先,下載 [Genymotion-ARM-Translation.zip](http://www.mirrorcreator.com/files/0ZIO8PME/Genymotion-ARM-Translation_v1.1.zip_links),並且安裝:
1. Genymotion-ARM-Translation_v1.1.zip,拖拉到 VM 中來執行安裝
2. 執行 `adb reboot` 重新啟動 VM
下載 Android 對應版本的[Google Apps](http://opengapps.org/),以 Android 6.0 為例,下載了 open_gapps-arm-6.0-pico-20160114.zip
接著把 `gapps-xx-xxxxxxxx-signed.zip` 拖拉到 VM 中中途會問是否 flash it ,選擇 Yes
4. 再次執行 `adb reboot`,重新啟動 VM
## 參考
- [Genymotion with Google Play Services](https://gist.github.com/wbroek/9321145),
-->用 awscli 刪除 AWS 的 Bucket2015-12-31T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-12-31:/aws-cli/<p>最近需要把 AWS 上面的 bucket 裡面的大量檔案刪除,步驟如下:</p>
<h2>安裝 awscli</h2>
<div class="highlight"><pre><span></span><code>$ pip install awscli
</code></pre></div>
<h2>設定 AWS 的 Configuration</h2>
<div class="highlight"><pre><span></span><code>$ aws configure
</code></pre></div>
<h2>Empty bucket</h2>
<div class="highlight"><pre><span></span><code>aws s3 rm s3://<YOUR_BUCKET_NAME> --recursive
</code></pre></div>
<h2>Delete bucket</h2>
<div class="highlight"><pre><span></span><code><span class="n">aws</span> <span class="n">s3</span> <span class="n">rb</span> <span class="nl">s3:</span><span class="c1">//<YOUR_BUCKET_NAME> --force --region ap-northeast-1</span>
</code></pre></div>不廢話 App 成長指南 筆記2015-12-02T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-12-02:/app-guide-admob/<p><img alt="growth" src="http://i.imgur.com/7MVdEQSl.jpg"></p>
<h2>成長的秘密</h2>
<p>讓少數的使用者熱愛你的產品,而不是擁有一堆對這個產品漠不關心的使用者</p>
<blockquote>
<p>It’s better to make something a small number of people love than something a large number of people don’t care about.”
-Paul Buchheit</p>
</blockquote>
<p>在擴展產品之前,你必須專注在<code>user engagment</code>,讓這個 App 會吸引使用者的注意。</p>
<p><img alt="cover" src="http://i.imgur.com/sEDT2Y2l.png"></p>
<h2>成長指標</h2>
<p>首先要找到一個適合的 App 的成長指標,可透過下列的兩個問題來尋找:</p>
<ol>
<li>那一個指標可以證明這個 App 的確有解決使用者的問題?</li>
<li>這個指標的發生的頻率多久才是對使用者有意義的?</li>
</ol>
<p>例如: 遊戲(天) < 天氣(天) < 手電筒(月) < 旅行(月)</p>
<p>你就不應該期待一個平常的使用者會每天都開手電筒的 App.</p>
<h2>持續改善</h2>
<p>當找到使用者參與指標(User engagement metric)的之後,
就可以用這些資料來改善 App。一般來說可以從 Google Analytics 和 Mixpanel 開始。當產品做了一些修正的時侯,持續關注使用者參與指標,確保 App 是往正確的道路上</p>
<p>如果想更深入了解,可參考:<a href="https://services.google.com/fb/forms/admobappgrowthguide/?utm_source=blog&utm_medium=blog-post&utm_campaign=NET-User-Engagement-Campaign">AdMob No-Nonsense Guide to Growing Your Mobile App</a></p>Postgresql 常用的指令2015-12-02T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-12-02:/postgresql-cli/<p>最近一年比較常使用 postgresql 資料庫系統,這篇把一些常用的指令整理一下:</p>
<h2>安裝 postgresql server</h2>
<p>In Ubuntu:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get update
$ sudo apt-get install postgresql postgresql-contrib
</code></pre></div>
<p>In OSX,使用 homebrew: </p>
<div class="highlight"><pre><span></span><code>$ brew upgrade postgresql
</code></pre></div>
<h2>建立 DB</h2>
<div class="highlight"><pre><span></span><code>$ initdb ~/pgdata
</code></pre></div>
<h2>啟動 postgresql server</h2>
<div class="highlight"><pre><span></span><code>$ pg_ctl -D ~/pgdata start
</code></pre></div>
<h2>連線到指定的 DB</h2>
<div class="highlight"><pre><span></span><code>$ psql -h localhost -p <span class="m">5432</span> -d docker -U docker --password
</code></pre></div>
<h2>備份資料庫</h2>
<p>把 database 匯出成一個 sql 文字檔案</p>
<div class="highlight"><pre><span></span><code>$ pg_dump -U <span class="o">{</span>user-name<span class="o">}</span> <span class="o">{</span>source_db<span class="o">}</span> -f <span class="o">{</span>dumpfilename.sql<span class="o">}</span> -h <span class="o">{</span>host<span class="o">}</span> -p <span class="o">{</span>port<span class="o">}</span>
</code></pre></div>
<h2>匯入資料庫</h2>
<p>從 sql 文字檔案匯入到 database</p>
<div class="highlight"><pre><span></span><code>$ psql -U <span class="o">{</span>user-name<span class="o">}</span> -d <span class="o">{</span>desintation_db<span class="o">}</span> -f <span class="o">{</span>dumpfilename.sql<span class="o">}</span>
</code></pre></div>
<h2>刪掉資料庫</h2>
<div class="highlight"><pre><span></span><code>$ dropdb <span class="o">{</span>database_name<span class="o">}</span>
</code></pre></div>看影片練聽力!推薦7個英文媒體網站2015-11-29T00:00:00+08:002017-09-16T08:05:11+08:00Cody Liutag:blog.codylab.com,2015-11-29:/english-news/<p><img alt="cover" src="http://i.imgur.com/5XLbdk1l.jpg">
整理了一下,可以用來學英文聽力的新聞媒體網站</p>
<h2>科技新聞</h2>
<ul>
<li><a href="http://techcrunch.com/video/crunchreport/">Tech Crunch Report</a>: 以矽谷創業新聞為主,我最常看的新聞來源之一,每個工作日約3~5分鐘</li>
<li><a href="http://www.theverge.com/video">Verge</a>: 美國科技媒體</li>
</ul>
<h2>國內新聞媒體</h2>
<ul>
<li><a href="https://www.youtube.com/user/FTVEnglishNews/videos">民視英語影音新聞</a>: 有英文稿,政治新聞為主</li>
<li><a href="http://www.icrt.com.tw/info_list01.php?&mlevel1=6&mlevel2=15&mlevel3=1">ICRT EZ News</a>: MP3,有文字稿,國內外新聞,</li>
</ul>
<h2>外國新聞媒體</h2>
<ul>
<li><a href="http://www.voanews.com/">VOA News</a></li>
<li><a href="http://edition.cnn.com/studentnews">CNN 10</a>: [5] 週一到週五有十分鐘的新聞影片,有字幕</li>
<li><a href="http://video.foxnews.com/">Fox</a>: 美國媒體]</li>
<li><a href="http://news.discovery.com/videos">Discovery News</a>: 科技、動物、生活知識</li>
<li><a href="http://www.abc.net.au/">ABC</a>: 澳洲新聞</li>
<li><a href="http://www.bbc.co.uk/">BBC</a>: 英國新聞</li>
</ul>
<h2>英文學習網站</h2>
<ul>
<li><a href="https://tw.voicetube.com/">VoiceTube</a>: 很多 YouTube 的影片加上字幕以供學習</li>
<li><a href="http://www.englishcentral.com/videos">EnglishCentral</a>: 很多不同的主題</li>
<li><a href="https://www.ted.com/">TED</a>: 很多影片都有英文字幕以供學習</li>
</ul>日本達摩翁的故鄉 - 群馬縣高崎市2015-11-19T00:00:00+08:002017-08-21T07:58:51+08:00Cody Liutag:blog.codylab.com,2015-11-19:/travel-takasaki-daruma/<p><img alt="cover" src="http://i.imgur.com/0MeylTg.jpg"></p>
<h2>群馬縣高崎市</h2>
<p>高崎是是群馬縣西南方的一個人口近40萬的城市,以日本達摩翁聞名。</p>
<p><img alt="takasaki-map" src="http://i.imgur.com/2tWt808.png"></p>
<p>高崎 JR 車站、商店隨處可見各式各樣的達摩翁擺設。</p>
<p><img alt="daruma" src="http://i.imgur.com/irUdCBpl.png"></p>
<p>從東京搭乘新幹線到高崎車程約一個小時。我們是從東京出發,搭乘北陸新幹線的淺間(Asama) 611號列車。
<img alt="asama611" src="http://i.imgur.com/oLnnppv.png">
<img alt="asama611-2" src="http://i.imgur.com/03LZJpY.png"></p>
<p>淺間號列車是以聳立在群馬縣和長野縣間的淺間山為名:
<img alt="asama-mountain" src="http://i.imgur.com/PhD9ric.png">
<img alt="新幹線-ticket" src="http://i.imgur.com/n1SUJmVm.png"></p>
<p>高崎市離輕井澤新幹線車程只有15分鐘,許多遊玩輕井澤的旅客也會選擇住在住宿費用比較便宜的高崎市。</p>
<h2>免費市區單車</h2>
<p>在高崎市的行程原本是打算用公車+步行來完成的,但在路上意外看到有免費的市區單車,那就想說不如就改成單車之旅吧。</p>
<p><img alt="bike-stand" src="http://i.imgur.com/ywHcXdxl.png">
<img alt="bike" src="http://i.imgur.com/nEkbzZTl.png"></p>
<p>租借方式很簡單,就像台灣大賣場的推車一樣,塞入100元硬幣,就可以騎走了,對於觀光客而言可說非常的方便。
<img alt="coin" src="http://i.imgur.com/XzDkjZPl.png"></p>
<p>目前在市區共有15個租借點:</p>
<p><img alt="bike-map" src="http://i.imgur.com/jHI1DOsl.png"></p>
<p>租借時間只有從 AM9:00 到 PM10:00,而在租借時間之外,腳踏車會被鎖上鐵鍊的。</p>
<h2>達摩的故鄉</h2>
<p>高崎開往長野原草津口的路上,我們搭了<strong>草津3號</strong>,在車上買了全國知名的日本鐵道便當: <strong>達摩茶飯便當</strong></p>
<p><img alt="達摩便當-拼圖" src="http://i.imgur.com/Cx77xYil.png">
<img alt="Top6-達摩茶飯便當" src="http://i.imgur.com/t0RPwY8.png">
<a href="https://visit-japan.jp/shindo/railway/ekiben.html">來源</a></p>
<p>回台灣之後,這個達摩就成我的零錢存錢筒,是一個相當實用的記念品。</p>
<p>在高崎市,我們就騎著單車,往達摩翁工廠<strong>大門屋</strong>方向慢慢騎去
<img alt="route" src="http://i.imgur.com/ihkanU4l.png"></p>
<p><img alt="park" src="http://i.imgur.com/XJVv5Pl.jpg">
<img alt="dog" src="http://i.imgur.com/ck817y6l.jpg"></p>
<h2>大門屋</h2>
<p><img alt="大門屋" src="http://i.imgur.com/e6ulcVH.png">
<img alt="大門屋" src="http://i.imgur.com/faM4nbC.png"></p>
<p>達摩點睛的說明
<img alt="Q&A" src="http://i.imgur.com/hMlCDRB.png">
達摩翁可幫助你完成願望,當你許願的時侯,先點上左眼。待願望完成之時,就再點上右眼,並把達摩翁帶回達磨寺焚化供奉。</p>
<p>當然,我們也不忘帶了幾尊達摩翁回家
<img alt="daruma-at-station" src="http://i.imgur.com/FgYYSs0l.jpg"></p>
<h2>高崎可可大飯店</h2>
<p><img alt="coco-grand-tripadvisor" src="http://i.imgur.com/YncdVMU.png"></p>
<p>這次在高崎市住的是高崎可可大飯店(Hotel Coco Grand Takasaki),雙人房一晚約14000日幣。在 Trip Adavisor 有極高的評價。下次會想再來</p>
<p><img alt="coco-grand-restrant" src="http://i.imgur.com/AqzEkd2.jpg"></p>
<p>餐點資訊:</p>
<ol>
<li>早餐 Buffet: 1200 日幣</li>
<li>午餐套餐: 1800 ~ 2000 日幣</li>
</ol>台中也可以搭 Uber 了,立即獲得免費乘車優惠2015-11-18T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-11-18:/uber-taichung/<h3><a href="https://get.uber.com/invite/uber_taiwan">點此連結立即獲得免費乘車優惠</a></h3>
<p><a href="https://get.uber.com/invite/uber_taiwan"><img alt="Uber-taichung" src="http://i.imgur.com/f0q56lc.png"></a></p>
<p>Uber 在上週正式進軍台中,上線的初期打出三趙三折的超殺優惠。我也馬上試用了,附上搭乘記錄: </p>
<p><img alt="收據" src="http://i.imgur.com/KvajYwo.png"></p>
<p>台中市區的車資對照表如下: </p>
<p><img alt="taichung-fare" src="http://i.imgur.com/h11qUrS.png"></p>
<p>目前台中只有開放平價車種的 UberX 菁英優步,想搭 UberBLACK 尊榮優步還需要等一陣子。</p>
<h3><a href="https://get.uber.com/invite/uber_taiwan">點此連結立即獲得免費乘車優惠</a></h3>使用 imgur 來當 blog 圖床2015-11-17T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-11-17:/imgur-imgbed/<p>這個 Cody Lab Blog 的圖片都是放在 <a href="imgur.com">imgur</a> 的雲端圖片服務,用了一陣子,感覺還不錯。
使用 imgur 來當圖床有以下優點:</p>
<ol>
<li>圖片不會被刪除,即使瀏覽量很低 <a href="https://goo.gl/u7AIAf">[1]</a></li>
<li>桌面版可以使用<a href="https://chrome.google.com/webstore/detail/imgur-extension-by-metron/ehoopddfhgaehhmphfcooacjdpmbjlao">Chrome 的 Extension</a>,可支援直接 copy & paste 跟拖拉上傳。</li>
<li>預設圖片上傳都是私密的,除非知道圖片網址,否則無法瀏覽</li>
<li>可以直接用網址來控制圖片的大小</li>
<li>完全免費</li>
</ol>
<p>目前 imgur 支援六種不同尺寸的縮圖:
<img alt="imgur-url" src="http://i.imgur.com/Y36YLPe.png"></p>
<p>例如有一張圖片是存放在: http://i.imgur.com/y4UZ1mx.jpg,如果想要不同尺寸的話,就直接在.jpg副檔名前面加上參數, </p>
<p>Huge thumbnail 1024x1024 http://i.imgur.com/y4UZ1mx<strong>h</strong>.jpg
<img alt="img" src="http://i.imgur.com/y4UZ1mxh.jpg"></p>
<p>Large thumbnail 640x640 http://i.imgur.com/y4UZ1mx<strong>l</strong>.jpg <br>
<img alt="img" src="http://i.imgur.com/y4UZ1mxl.jpg"></p>
<p>Medium thumbnail 320x320 http://i.imgur.com/y4UZ1mx<strong>m</strong>.jpg <br>
<img alt="img" src="http://i.imgur.com/y4UZ1mxm.jpg"></p>
<p>Small thumbnail 160x160 http://i.imgur.com/y4UZ1mx<strong>t</strong>.jpg <br>
<img alt="img" src="http://i.imgur.com/y4UZ1mxt.jpg"></p>
<p>Big square 160x160: http://i.imgur.com/y4UZ1mx<strong>b</strong>.jpg <br>
<img alt="img" src="http://i.imgur.com/y4UZ1mxb.jpg"></p>
<p>Small square 90x90: http://i.imgur.com/y4UZ1mx<strong>s …</strong></p><p>這個 Cody Lab Blog 的圖片都是放在 <a href="imgur.com">imgur</a> 的雲端圖片服務,用了一陣子,感覺還不錯。
使用 imgur 來當圖床有以下優點:</p>
<ol>
<li>圖片不會被刪除,即使瀏覽量很低 <a href="https://goo.gl/u7AIAf">[1]</a></li>
<li>桌面版可以使用<a href="https://chrome.google.com/webstore/detail/imgur-extension-by-metron/ehoopddfhgaehhmphfcooacjdpmbjlao">Chrome 的 Extension</a>,可支援直接 copy & paste 跟拖拉上傳。</li>
<li>預設圖片上傳都是私密的,除非知道圖片網址,否則無法瀏覽</li>
<li>可以直接用網址來控制圖片的大小</li>
<li>完全免費</li>
</ol>
<p>目前 imgur 支援六種不同尺寸的縮圖:
<img alt="imgur-url" src="http://i.imgur.com/Y36YLPe.png"></p>
<p>例如有一張圖片是存放在: http://i.imgur.com/y4UZ1mx.jpg,如果想要不同尺寸的話,就直接在.jpg副檔名前面加上參數, </p>
<p>Huge thumbnail 1024x1024 http://i.imgur.com/y4UZ1mx<strong>h</strong>.jpg
<img alt="img" src="http://i.imgur.com/y4UZ1mxh.jpg"></p>
<p>Large thumbnail 640x640 http://i.imgur.com/y4UZ1mx<strong>l</strong>.jpg <br>
<img alt="img" src="http://i.imgur.com/y4UZ1mxl.jpg"></p>
<p>Medium thumbnail 320x320 http://i.imgur.com/y4UZ1mx<strong>m</strong>.jpg <br>
<img alt="img" src="http://i.imgur.com/y4UZ1mxm.jpg"></p>
<p>Small thumbnail 160x160 http://i.imgur.com/y4UZ1mx<strong>t</strong>.jpg <br>
<img alt="img" src="http://i.imgur.com/y4UZ1mxt.jpg"></p>
<p>Big square 160x160: http://i.imgur.com/y4UZ1mx<strong>b</strong>.jpg <br>
<img alt="img" src="http://i.imgur.com/y4UZ1mxb.jpg"></p>
<p>Small square 90x90: http://i.imgur.com/y4UZ1mx<strong>s</strong>.jpg <br>
<img alt="img" src="http://i.imgur.com/y4UZ1mxs.jpg"></p>
<p>也就是只要用網址就可以控制圖片的大小了,對於 blog 來說相當方便。</p>使用 Bower 來管理 web 函式庫套件2015-11-08T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-11-08:/bower/<p><img alt="bower" src="http://i.imgur.com/GFlma5U.jpg"></p>
<p><a href="http://bower.io/">Bower</a> 是 frontend 常用來管理 package 的套件。比如說要使用 <code>jquery</code>,就可以透過 bower,來安裝。</p>
<h1>安裝</h1>
<div class="highlight"><pre><span></span><code>$ npm install -g bower
</code></pre></div>
<p>註: 如果權限不足的話,記得加上 sudo </p>
<h1>初始化</h1>
<div class="highlight"><pre><span></span><code>$ bower init
</code></pre></div>
<p>bower 是透過 bower.json 來管理 dependecy,所以一開始要先透過這個指令來新增 bower.json,過程會問一些問題,可以按 enter 直接用預設的即可。</p>
<h1>搜尋,以 jQuery 為例</h1>
<div class="highlight"><pre><span></span><code>$ bower search jquery
</code></pre></div>
<p>輸出: </p>
<div class="highlight"><pre><span></span><code>Search results:
jQuery https://github.com/jquery/jquery.git
jquery https://github.com/jquery/jquery-dist.git
jquery.x https://github.com/jljLabs/jquery.x.git
jquery.Q https://github.com/jsbuzz/jQuery_Q.git
</code></pre></div>
<p>列出可以使用的 repository </p>
<h1>安裝,以 jQuery 為例</h1>
<div class="highlight"><pre><span></span><code>$ bower install jquery
</code></pre></div>
<p>安裝完之後,目錄會出現 bower_components 來存放 jquery 的檔案:</p>
<div class="highlight"><pre><span></span><code>.
└── bower_components
└── jquery
</code></pre></div>
<p>安裝 jquery,並把 jquery 加到 bower …</p><p><img alt="bower" src="http://i.imgur.com/GFlma5U.jpg"></p>
<p><a href="http://bower.io/">Bower</a> 是 frontend 常用來管理 package 的套件。比如說要使用 <code>jquery</code>,就可以透過 bower,來安裝。</p>
<h1>安裝</h1>
<div class="highlight"><pre><span></span><code>$ npm install -g bower
</code></pre></div>
<p>註: 如果權限不足的話,記得加上 sudo </p>
<h1>初始化</h1>
<div class="highlight"><pre><span></span><code>$ bower init
</code></pre></div>
<p>bower 是透過 bower.json 來管理 dependecy,所以一開始要先透過這個指令來新增 bower.json,過程會問一些問題,可以按 enter 直接用預設的即可。</p>
<h1>搜尋,以 jQuery 為例</h1>
<div class="highlight"><pre><span></span><code>$ bower search jquery
</code></pre></div>
<p>輸出: </p>
<div class="highlight"><pre><span></span><code>Search results:
jQuery https://github.com/jquery/jquery.git
jquery https://github.com/jquery/jquery-dist.git
jquery.x https://github.com/jljLabs/jquery.x.git
jquery.Q https://github.com/jsbuzz/jQuery_Q.git
</code></pre></div>
<p>列出可以使用的 repository </p>
<h1>安裝,以 jQuery 為例</h1>
<div class="highlight"><pre><span></span><code>$ bower install jquery
</code></pre></div>
<p>安裝完之後,目錄會出現 bower_components 來存放 jquery 的檔案:</p>
<div class="highlight"><pre><span></span><code>.
└── bower_components
└── jquery
</code></pre></div>
<p>安裝 jquery,並把 jquery 加到 bower.json 中的 dependency(--save)</p>
<div class="highlight"><pre><span></span><code>$ bower install jquery --save
</code></pre></div>
<p>可以看到 jquery 就會加到 bower.json 之中</p>
<div class="highlight"><pre><span></span><code>$ less bower.json
<span class="o">{</span>
...
<span class="s2">"dependencies"</span>: <span class="o">{</span>
<span class="s2">"jquery"</span>: <span class="s2">"~2.1.4"</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div>
<!--## .bowerrc 設定檔
- 參考網頁: [Configuration · Bower](http://bower.io/docs/config/)
Ex 1: 修改 js 要放的目錄
{
"directory": "app/components/"
}
## 進階用法 Bower plugin & grunt
https://github.com/yatskevich/grunt-bower-task
{
"name": "simple-bower",
"version": "0.0.0",
"dependencies": {
"jquery": "~1.8.3",
"bootstrap-sass": "*",
"requirejs": "*"
},
"exportsOverride": {
"bootstrap-sass": {
"js": "js/*.js",
"scss": "lib/*.scss",
"img": "img/*.png"
},
"requirejs": {
"js": "require.js"
}
}
}
-->犬胰臟炎治療記錄2015-10-15T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-10-15:/dog-pancreatitis-dodo/<p><img alt="dodo-head" src="http://i.imgur.com/9DAx6oGl.jpg"></p>
<p>家裡的小狗多多得了胰臟炎,是一個危險性很高的疾病,最後多多順利出院了,把治療過程記錄於此。</p>
<h3>10/09(五) Day 1</h3>
<p>多多早上六點多開始大吐,帶去豐東獸醫就診,診斷後發現有發燒,並且糞便採集時有看到梨形鞭毛蟲,診斷為梨形鞭毛蟲所造成的嘔吐,醫生建議禁食禁水一天。</p>
<p>帶回家後續還是持續嘔吐。</p>
<p><img alt="嘔吐" src="http://i.imgur.com/eXRstphm.jpg"></p>
<p>白色泡泡帶有黃色的膽汁</p>
<p>一整天都<strong>極度口渴</strong>,<strong>沒有精神</strong>,散步一下子就想回家。下午有尿尿跟大便,測試食慾給了少許潔牙骨,會想吃。但<strong>整天都沒有沒有睡覺,一躺下來,就馬上換位置睡,常常呈伸懶腰的姿勢</strong>。</p>
<p>晚上一直想去廁所喝水,跟平常不會去的陽台趴著。一直敲碗討水喝,看著很不忍心,最後還是零星給了一點水,卻造成更多的嘔吐,喝水後約一個小時就完全吐出來,甚至吐的比喝的量還多。最後到了凌晨五點,才在沙發躺著休息。</p>
<p>深感事態嚴重,所以天亮後。決定換一家醫院再做診斷</p>
<h3>10/10(六) Day 2</h3>
<p>早上九點先到興緣,但因國慶日休診。之後先帶到公園大小便,有小便、有大便姿勢但是大不出來。回程經過漢口路的台大獸醫,看到只有醫師一人在做手術,感覺似乎人手不夠,故先行離開換另一家。十點許,到達之前有看過的德愛中西醫動物醫院,由游醫知主診,描述完病況並給醫師看嘔吐的圖片。</p>
<p><img alt="看診1" src="http://i.imgur.com/P2p2KNbl.png"></p>
<p>醫生表示這嘔吐很嚴重,再吐下去,會傷害到胃。一開始診斷為急性腸胃炎。隨後在醫師的建議下開始做一連串的檢查,其中包含血檢、腹部超音波、X光。</p>
<p>腹部超音波、X光沒有發現有異物阻塞。</p>
<p><img alt="報告1" src="http://i.imgur.com/Lz1saXE.jpg">
<img alt="報告2" src="http://i.imgur.com/UZiyg4q.jpg"></p>
<p>血檢報告大部份指數都正常,唯獨<strong>檢測胰臟炎的 cPL 測試為異常,因此醫生確診多多得了急性胰臟炎</strong>。這是危險性很高的疾病,所以在醫師的建議之下,立即住院治療。打了抗生素、善德定(Sandostatin),並掛點滴,禁食禁水。過程中 X-Ray 跟 腹部超音波由陳醫師負責,過程多多不太舒服,所以對醫生們很凶,陳醫師跟助手們還是很有耐心完成檢驗。</p>
<p>下午六時,去探望多多,感覺精神不錯,看到我會叫,想抓門出來。頭套上面一塊吐過的痕跡,代表還有在吐。</p>
<h3>10/11 …</h3><p><img alt="dodo-head" src="http://i.imgur.com/9DAx6oGl.jpg"></p>
<p>家裡的小狗多多得了胰臟炎,是一個危險性很高的疾病,最後多多順利出院了,把治療過程記錄於此。</p>
<h3>10/09(五) Day 1</h3>
<p>多多早上六點多開始大吐,帶去豐東獸醫就診,診斷後發現有發燒,並且糞便採集時有看到梨形鞭毛蟲,診斷為梨形鞭毛蟲所造成的嘔吐,醫生建議禁食禁水一天。</p>
<p>帶回家後續還是持續嘔吐。</p>
<p><img alt="嘔吐" src="http://i.imgur.com/eXRstphm.jpg"></p>
<p>白色泡泡帶有黃色的膽汁</p>
<p>一整天都<strong>極度口渴</strong>,<strong>沒有精神</strong>,散步一下子就想回家。下午有尿尿跟大便,測試食慾給了少許潔牙骨,會想吃。但<strong>整天都沒有沒有睡覺,一躺下來,就馬上換位置睡,常常呈伸懶腰的姿勢</strong>。</p>
<p>晚上一直想去廁所喝水,跟平常不會去的陽台趴著。一直敲碗討水喝,看著很不忍心,最後還是零星給了一點水,卻造成更多的嘔吐,喝水後約一個小時就完全吐出來,甚至吐的比喝的量還多。最後到了凌晨五點,才在沙發躺著休息。</p>
<p>深感事態嚴重,所以天亮後。決定換一家醫院再做診斷</p>
<h3>10/10(六) Day 2</h3>
<p>早上九點先到興緣,但因國慶日休診。之後先帶到公園大小便,有小便、有大便姿勢但是大不出來。回程經過漢口路的台大獸醫,看到只有醫師一人在做手術,感覺似乎人手不夠,故先行離開換另一家。十點許,到達之前有看過的德愛中西醫動物醫院,由游醫知主診,描述完病況並給醫師看嘔吐的圖片。</p>
<p><img alt="看診1" src="http://i.imgur.com/P2p2KNbl.png"></p>
<p>醫生表示這嘔吐很嚴重,再吐下去,會傷害到胃。一開始診斷為急性腸胃炎。隨後在醫師的建議下開始做一連串的檢查,其中包含血檢、腹部超音波、X光。</p>
<p>腹部超音波、X光沒有發現有異物阻塞。</p>
<p><img alt="報告1" src="http://i.imgur.com/Lz1saXE.jpg">
<img alt="報告2" src="http://i.imgur.com/UZiyg4q.jpg"></p>
<p>血檢報告大部份指數都正常,唯獨<strong>檢測胰臟炎的 cPL 測試為異常,因此醫生確診多多得了急性胰臟炎</strong>。這是危險性很高的疾病,所以在醫師的建議之下,立即住院治療。打了抗生素、善德定(Sandostatin),並掛點滴,禁食禁水。過程中 X-Ray 跟 腹部超音波由陳醫師負責,過程多多不太舒服,所以對醫生們很凶,陳醫師跟助手們還是很有耐心完成檢驗。</p>
<p>下午六時,去探望多多,感覺精神不錯,看到我會叫,想抓門出來。頭套上面一塊吐過的痕跡,代表還有在吐。</p>
<h3>10/11(日) Day 3</h3>
<p>醫院休診,交由醫師照顧,沒有探視
<img alt="休診" src="http://i.imgur.com/z1W6k44l.png"></p>
<h3>10/12(一) Day 4</h3>
<p>早上九點看多多,醫生說沒有吐了,有嘗試給多多喝水,但是沒有喝。觀察喝水、吃東西會不會吐,然後排便正不正常,距上一次大便已有三天。早上游醫師看診時表示,體溫正常,肚子也比較放鬆了。最後陳醫師打針,更換點滴針頭。</p>
<p><img alt="散步" src="http://i.imgur.com/Cs6409v.png"></p>
<p>晚上探望,感覺有比較好了。醫生說有開始喝水、進食了。帶出去外面有尿尿,但仍然還是沒有大便,情況持續好轉中。</p>
<h3>10/13(二) Day 5</h3>
<p>早上九點到診所,發現沒有打點滴,原來是因為多多的腳因為點滴針移位,所以腳腫起來,醫師昨天晚上沒有讓多多打點滴,讓多多的腳休息一陣子。今天早上散步的時侯,有尿尿,並且也終於有大便,大便狀態陳醫師說雖然稍軟,但有大出來很不錯。</p>
<p>隨後上了點滴的針,打善得定,打點滴時不太順利,因為多多會一直動。看到多多的腳都是點滴針,真的很可憐。看診時量體溫,發現有輕微發燒 39.4 度,陳醫師說病情偶有反覆情況,會再持續量測體溫。</p>
<p><img alt="住院" src="http://i.imgur.com/MnyccUw.jpg"></p>
<p>晚上探訪多多,移到樓下,一有風吹草動其它鄰居就開始狂吠,還是很兇,不太讓人餵藥。散步的時侯有尿尿,沒有大便。游醫師說明天週三晚上即可出院。</p>
<h3>10/14(三) Day 6</h3>
<p>早上帶多多去上廁所,沒有小便。觸下腹部會痛。晚上到醫院時,體溫正常,醫生說可以出院了。帶了三天份的中藥回家。預計三天後回診,一週後再做一次 cPL 測試,看<strong>a犬胰臟特異脂肪酶指數</strong>是否恢復正常。出院後的飼料就先改成用 <strong>LF22 皇家處方飼料</strong>,先避食食物中大部份的油脂。 </p>
<p><img alt="LF22" src="http://i.imgur.com/WgEFS2zl.jpg"></p>
<p>帶回家之後現在又是一條活龍了,玩累了休息的模樣</p>
<p><img alt="Sleep" src="http://i.imgur.com/P6ARftbl.jpg">
<img alt="Imgur" src="http://i.imgur.com/MlrYw51l.png"></p>
<h3>10/24(六) Day 16</h3>
<p>二週後,再回醫院再做一次 CPL 檢查,指數恢復正常:
<img alt="cpl-2nd" src="http://i.imgur.com/Cfkoigj.png"></p>
<p>游醫師說可以不用吃 LF22 ,可改成一般的飼料,整個療程到這邊告一個段落。</p>犬胰臟炎介紹2015-10-14T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-10-14:/dog-pancreatitis-intro/<h2>註: 本人非獸醫專業,資訊皆為網路收集而來,請您在做任何決定之前務必先您的獸醫討論,當懷疑有胰臟炎時,請務必儘早送醫,因為胰臟炎是會造成生命危險的疾病。</h2>
<h2>胰臟(Pancreas)位在就在十二指腸旁特化具分泌性的腺體器官:</h2>
<p><img alt="pancreas" src="http://i.imgur.com/F3fqhXk.jpg">
<img alt="pancreas" src="http://i.imgur.com/dO2T1U2.jpg"></p>
<p>它主要有兩項功能:</p>
<ol>
<li>分泌內分泌如胰島素、升醣素等</li>
<li>分泌消化酵素如蛋白酶、脂肪酶、澱粉酶等。</li>
</ol>
<h2>胰臟炎(Pancreatitis)</h2>
<p><img alt="Imgur" src="http://i.imgur.com/oHUVKMU.png"></p>
<p>當分泌消化酵素的細胞受某種刺激或傷害時,這些酵素被活化且漏出產生自我消化破壞作用甚至不斷外漏更進一步將腸管、胃、脂肪、肝及腎臟等消化破壞即產生胰臟炎,更嚴重者這些消化酵素進入循環系統,引發瀰漫性血管内凝血(DIC)肺栓塞、大量細胞壞死、心室性心率不整等最後導致休克、死亡。</p>
<h2>危險族群</h2>
<p>胰臟炎最常發生於過重、中老年狗的身上。一般來說,母犬的發生比率通常較公犬高。其他動物之胰臟炎較不易發生,但老年動物偶而會發生</p>
<h2>臨床症狀</h2>
<p>嘔吐、食慾不振、口渴、腹痛、、精神不好、發燒、呼吸急促</p>
<p>喘氣不讓人碰腹部。嘔吐、下痢、腹痛、精神委靡為主。其症狀的呈現通常是非常嚴重的,比如說下痢可能帶血,甚至直接以血痢的方式呈現;剛開始發生時,嘔吐現象在頻率及嘔吐量上來說可能就非常嚴重,甚至一般門診常開的止吐藥物完全沒有效果。但也有碰過有些狗狗的症狀主要表現為食慾減退,初期完全沒有吐或下痢,直到病程的後期才開始吐血拉血。</p>
<p><img alt="Imgur" src="http://i.imgur.com/J89lreG.png"></p>
<h2>診斷</h2>
<p>近期大多獸醫院改用 <a href="http://www.idexx.com.tw/smallanimal/inhouse/snap/cpl.html">SNAP™ cPL測試(犬胰臟脂肪酶)</a>,早期是以血清中的 Lipase 及 Amylase 的數值上升來判斷胰臟炎。cPL 確準度比用 Lipase 跟 Amylase 高。</p>
<h2>治療</h2>
<p>支持療法,止吐,止痛,打點滴,抗生素。</p>
<p>或是以下可能的特效藥:</p>
<ol>
<li>善得錠(Sandostatin)</li>
<li>蛋白酶中和劑(FOY)</li>
<li>新鮮冷凍血清(FFP)</li>
</ol>
<h2>癒後飲食</h2>
<p>胰臟炎容易復發,所以建議癒後吃處方飼料必須,飲食上的原則為低脂肪、低蛋白、高寡醣的食物可降低胰臟的負擔。</p>
<ol>
<li>吃處方飼料</li>
<li>可補充芹菜紅蘿蔔汁</li>
</ol>Continuous Delivery 持續交付 @ Agile Taichung 2015/92015-09-21T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-09-21:/continuous-delivery/<p>今天在 Agile Taichung 分享自己學習 Continuous Delivery 的心得</p>
<p><img alt="agile.taichung." src="http://imgur.com/6T5axdXl.jpg"></p>
<p>聚會的投影片如下: </p>
<iframe src="http://www.slideshare.net/slideshow/embed_code/key/nDlxLYBn5HcARp" width="600" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen></iframe>
<p>另外,我覺得直接聽大師講最快,我的投影片主要都是參考 Jez Humble 跟 Martin Flower 大師們的 Talk內容。下面兩個 youtube,是我覺得講 CD 講的很清楚</p>
<iframe width="560" height="315" src="http://www.youtube.com/embed/aoMfbgF2D_4" frameborder="0" allowfullscreen></iframe>
<p>Martin Fowler 在 XCONF 談 Continuous Delivery</p>
<iframe width="560" height="315" src="http://www.youtube.com/embed/ZLBhVEo1OG4" frameborder="0" allowfullscreen></iframe>
<p>Jez Humble 在 Spark 2013 談 Continuous Delivery</p>
<p>最後則是用一張圖視覺化所有 CD 重要的觀念:</p>
<p><img alt="condinuous-delivery" src="http://i.imgur.com/oWBYQ4ol.jpg"></p>使用 GA 自定廣告活動區分流量來源2015-09-09T00:00:00+08:002021-06-22T08:49:09+08:00Cody Liutag:blog.codylab.com,2015-09-09:/google-analytics-advertising-url/<p>Google Analytics(GA) 提供了<a href="https://goo.gl/y18EMz">自訂廣告活動</a>功能,可以追蹤廣告在不同媒介成效如何。以 Asus 為例,我們可以看到 ASUS 的粉絲團就有埋 GA 的自定廣告活動:</p>
<p><img alt="asus store" src="http://i.imgur.com/S5VcLmKl.png"></p>
<p>裡面 goo.gl 的短網址背後的網址其實是:</p>
<p><a href="http://store.asus.com/tw/item/201508AM130002265">http://store.asus.com/tw/item/201508AM130002265</a>?
utm_campaign=outlet&utm_source=AsusStoreFB&utm_medium=social&utm_content=150909_VX207DE</p>
<p>裡面可以看到幾個參數:</p>
<ul>
<li>utm_campaign=outlet</li>
<li>utm_source=AsusStoreFB</li>
<li>utm_medium=social</li>
<li>utm_content=150909_VX207DE</li>
</ul>
<p><code>campaign</code> 是這個廣告活動的名稱,而 <code>source/medium</code> 則依需求使用,<code>utm_content</code>,ASUS 這邊則是設定產品的型號,這些欄位之後在 GA 都是可以獨立查詢的主維度。</p>
<p>再舉個例子,如果我想推出一個廣告,分別想把產品頁面,分別使用 QR-Code 或是 Link 的方式散佈出去。比較快又穩妥的方法是可以用GA的 <a href="https://support.google.com/analytics/answer/1033867">URL builder</a> 小工具分別產生下列兩個連結:</p>
<p>http://<YOUR_WEB_SITE>/?utm_source=Facebook%20&utm_medium=Link&utm_campaign=Test%20Ad%20Link</p>
<p>http://<YOUR_WEB_SITE>/??utm_source=Email%20&utm_medium=QR%20Code&utm_campaign=Test%20Ad%20Link</p>
<p>在這邊我只需設定四個必填的欄位: 網址,來源,媒介,跟名稱。使用者透過這個連結訪問的結果就可以顯示在 GA 的報表上了,如下圖:</p>
<p><img alt="GA" src="http://i.imgur.com/NWHAA0Gl.png"></p>
<p>也可以直接選廣告活動(Campaign),就可以看到這次廣告的整體流量 …</p><p>Google Analytics(GA) 提供了<a href="https://goo.gl/y18EMz">自訂廣告活動</a>功能,可以追蹤廣告在不同媒介成效如何。以 Asus 為例,我們可以看到 ASUS 的粉絲團就有埋 GA 的自定廣告活動:</p>
<p><img alt="asus store" src="http://i.imgur.com/S5VcLmKl.png"></p>
<p>裡面 goo.gl 的短網址背後的網址其實是:</p>
<p><a href="http://store.asus.com/tw/item/201508AM130002265">http://store.asus.com/tw/item/201508AM130002265</a>?
utm_campaign=outlet&utm_source=AsusStoreFB&utm_medium=social&utm_content=150909_VX207DE</p>
<p>裡面可以看到幾個參數:</p>
<ul>
<li>utm_campaign=outlet</li>
<li>utm_source=AsusStoreFB</li>
<li>utm_medium=social</li>
<li>utm_content=150909_VX207DE</li>
</ul>
<p><code>campaign</code> 是這個廣告活動的名稱,而 <code>source/medium</code> 則依需求使用,<code>utm_content</code>,ASUS 這邊則是設定產品的型號,這些欄位之後在 GA 都是可以獨立查詢的主維度。</p>
<p>再舉個例子,如果我想推出一個廣告,分別想把產品頁面,分別使用 QR-Code 或是 Link 的方式散佈出去。比較快又穩妥的方法是可以用GA的 <a href="https://support.google.com/analytics/answer/1033867">URL builder</a> 小工具分別產生下列兩個連結:</p>
<p>http://<YOUR_WEB_SITE>/?utm_source=Facebook%20&utm_medium=Link&utm_campaign=Test%20Ad%20Link</p>
<p>http://<YOUR_WEB_SITE>/??utm_source=Email%20&utm_medium=QR%20Code&utm_campaign=Test%20Ad%20Link</p>
<p>在這邊我只需設定四個必填的欄位: 網址,來源,媒介,跟名稱。使用者透過這個連結訪問的結果就可以顯示在 GA 的報表上了,如下圖:</p>
<p><img alt="GA" src="http://i.imgur.com/NWHAA0Gl.png"></p>
<p>也可以直接選廣告活動(Campaign),就可以看到這次廣告的整體流量:</p>
<p><img alt="GA" src="http://i.imgur.com/CVGfXIy.png"></p>
<p>今天上了張秉祖老師的GA課程學到了這個技巧,老師一直在課堂上強調要活用 GA 包含三件事:</p>
<ol>
<li>正確安裝追蹤程式碼</li>
<li>有效區分流量來源</li>
<li>制定合理的目標,並持續追踨</li>
</ol>
<p>GA 雖然免費,但其實是一個蠻複雜的系統,大部份的人以為GA就只要安裝追蹤程式碼就可以快樂看報表了。但其實這樣還遠遠不夠,像是執行的廣告行銷,就要務必確保不同的管道進來的流量能夠被區隔,這樣才看得出來那邊的預算是有效的,那邊的預算是浪費的。而老師也提到每個公司都應該要制定目標組合,例如要到達那一個頁面、事件代表達成目標,有了這些目標,就可以做更細的分析來評估在怎樣的條件下達成目標的效果比較好,進而降低行銷的成本,甚至可以建立一個以數據為決策基礎的組織文化。</p>使用 Airbnb 住宿心得2015-09-04T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-09-04:/airbnb-discount-share/<p><a href="https://goo.gl/ZoLSrX"><img alt="airbnb" src="http://i.imgur.com/cCvnh1tl.png"></a></p>
<p>最近一年來,當我有住宿需求時,幾乎都是選擇 <a href="https://goo.gl/ZoLSrX">Airbnb</a>。而在住台北的 Airbnb 才發現,其實目前會在台灣用 Airbnb 的國人還是佔少數。Airbnb 是一個媒合房東與旅客的平台,可以讓一些房東可以把有空的房間出租給需要的人。重點是 Airbnb上的價格很合理,像是在東京市區例如澀谷,不用三千塊就可以住到整套房間包含廚房、洗衣機等等,很適合想省錢住宿的背包客。</p>
<p>似乎大部份不敢用 Airbnb 的原因之一是因為擔心安全性。不敢住在陌生人的家裡。如果想要有多一些隱私的話,可以選擇<strong>整套房屋</strong>的房型,雖然價格會比較貴一些。</p>
<p><img alt="type " src="https://www.evernote.com/l/ABCYlCKb1vBMHa_7ETYANTHK9ndcj-kdMGMB/image.png"></p>
<p>如果出國玩,想跟當地人有多一些交流的話,其實跟房東同住也蠻有趣的,像是我在名古屋時是與房東同住。房東養了一隻貓,很親人,會主動跟你玩,整個住宿體驗中最深刻的記憶點。</p>
<p><img alt="koji'scat テンプラ" src="https://lh3.googleusercontent.com/SoT0Slm0d-p1lOb8nX4SQn9oQCqAN4NLCFcqIYnIpALw=w500"></p>
<p>另外就是要注意房間的評價,其實只要選評價多而且內容是好的,基本上就不會踩到地雷。大家留評論雖然都很客氣,注意一下留言,就可以知道這房間有什麼缺點、清潔度如何等等。</p>
<p><img alt="評價" src="https://www.evernote.com/l/ABCinx87Im9AL4umK-cWReLxa2iM7CW43FsB/image.png"></p>
<p>對我而言,出國玩如果可以少帶一些行李,像是衣服是最好不過的了。所以我出國住 Airbnb 必定選那種有洗衣機的房間,這樣就可以少帶很多衣服。</p>
<h2>與房東的溝通</h2>
<p>跟一般旅館很不一樣的是,訂 AirBnB 通常在入住前就會跟房東會有好幾次的溝通,討論入住事宜,Airbnb的訊息會從Email,Mobile App,簡訊通知。有什麼問題,房東通常都會很樂意協助,像是詢問一些旅遊資訊:
<img alt="旅行" src="https://www.evernote.com/l/ABCWpkFQkNhLg4Q3XoH6o1VpC_6PSYDed8IB/image.png"></p>
<p>或是請房東先代收包裹。
<img alt="vitalie" src="https://www.evernote.com/l/ABBuXNSvPE5Fuo70mcQTzTxRIOSQ6wg48fIB/image.png"></p>
<p>所以房東某種程度上就變成你的旅遊當地旅遊顧問,透過 Airbnb 很容易連絡到房東,而大部份的房東也都會馬上透過 Airbnb 的 app 回應給你</p>
<p><img alt="travel-pln" src="https://www.evernote.com/l/ABBLQzn0eLtJUoi7pAMvG6JI_fc7easEozAB/image.png"></p>
<p>另外 Airbnb 上面的房間大部份都會提供 Pocket Wifi,這樣讓出國玩可以省下一筆租用上網費用。</p>
<p><img alt="pocket" src="https://www.evernote.com/l/ABDjEsEk43lMD7vaN1_4KOeVMRsIsUkgRI8B/image.png"></p>
<p><img alt="Pocket Wifi" src="https://lh3.googleusercontent.com/qoqBvlwI-A5Lcw891RqbxhJxFmQa6r_Tn36l2XHSd_Qrkzgy4Vnq2lmFqdrPXB03AGO-SDEi2zYbx3thSm4OlORXoMX2dckBtshKXhO1vTuVl1b4yJgV89Rc1CHoRxMo04pgAPbv2iTbBCL4WZG8okHzIAGxZ2CTyUSE5Woa4hH6rCVX-VdkIHKcHMNsetoR4nX3D523ccHmr5hAvKPD2KiJHuIN7bp3clBLr6mRbwDl585OfKveNkScCcxP7Is-Cti6K1gyXQlhWdUkfKVytmDr1avDsItCAG55CZm3EnEeMmCsUCLYbz9CIzLci2TmX11pP_yfsezpgs7zTK9j2brk1k8U6sILk_3Dfd3WffNhiCgb0qTcoQxi67y16zZRdyXiHTty6DGmvkEOoCskIcgLvMDPHVRuR_PAJfT6iHqgXgDXLbIxJw9M6x-ZEtw6g035MMKrlZhH363e9K6U8OX7w0ci-YOOeY28CoI2-qt1XjbfFt_eO1oCxloAjZDgHEE-kXoPfdTbh0p3EF4qoGpk=w200"></p>
<h2>實際住宿分享</h2>
<p>東京迪士尼旁邊的公寓,二個人一晚1974元,<a href="https://www.airbnb.com.tw/rooms/4800152">Link</a></p>
<p><img alt="disney" src="https://www.evernote.com/l/ABCqGyxm7rpDd4dFVBHiBrnKbNWLSPAtzxQB/image.png">
<img alt="disney" src="https://www.evernote.com/l/ABB8WDEImN5JEYu4Q0y_A5pAcguVqx9z3doB/image.png"></p>
<p>日本六本木 Hills 旁的公寓,二個人一晚2284元,<a href="https://www.airbnb.com.tw/rooms/3431627">Link</a></p>
<p><img alt="hills" src="https://www.evernote.com/l/ABDWg0nMD6RCH4Vxmvt9jdRCcOlTVNpzmK8B/image.png"></p>
<p><img alt="hills2" src="https://www.evernote.com/l/ABA3JxcRjtZLcIS0Hf3p_HdOl_4VPvaXDJ4B/image.png"></p>
<p>可以知道如果要住旅館,要有這樣的大小與設備,肯定是不只這樣的價錢的。</p>
<h2>最後</h2>
<p>目前 Airbnb 估值已經來到 250 億美金(2015/6 …</p><p><a href="https://goo.gl/ZoLSrX"><img alt="airbnb" src="http://i.imgur.com/cCvnh1tl.png"></a></p>
<p>最近一年來,當我有住宿需求時,幾乎都是選擇 <a href="https://goo.gl/ZoLSrX">Airbnb</a>。而在住台北的 Airbnb 才發現,其實目前會在台灣用 Airbnb 的國人還是佔少數。Airbnb 是一個媒合房東與旅客的平台,可以讓一些房東可以把有空的房間出租給需要的人。重點是 Airbnb上的價格很合理,像是在東京市區例如澀谷,不用三千塊就可以住到整套房間包含廚房、洗衣機等等,很適合想省錢住宿的背包客。</p>
<p>似乎大部份不敢用 Airbnb 的原因之一是因為擔心安全性。不敢住在陌生人的家裡。如果想要有多一些隱私的話,可以選擇<strong>整套房屋</strong>的房型,雖然價格會比較貴一些。</p>
<p><img alt="type " src="https://www.evernote.com/l/ABCYlCKb1vBMHa_7ETYANTHK9ndcj-kdMGMB/image.png"></p>
<p>如果出國玩,想跟當地人有多一些交流的話,其實跟房東同住也蠻有趣的,像是我在名古屋時是與房東同住。房東養了一隻貓,很親人,會主動跟你玩,整個住宿體驗中最深刻的記憶點。</p>
<p><img alt="koji'scat テンプラ" src="https://lh3.googleusercontent.com/SoT0Slm0d-p1lOb8nX4SQn9oQCqAN4NLCFcqIYnIpALw=w500"></p>
<p>另外就是要注意房間的評價,其實只要選評價多而且內容是好的,基本上就不會踩到地雷。大家留評論雖然都很客氣,注意一下留言,就可以知道這房間有什麼缺點、清潔度如何等等。</p>
<p><img alt="評價" src="https://www.evernote.com/l/ABCinx87Im9AL4umK-cWReLxa2iM7CW43FsB/image.png"></p>
<p>對我而言,出國玩如果可以少帶一些行李,像是衣服是最好不過的了。所以我出國住 Airbnb 必定選那種有洗衣機的房間,這樣就可以少帶很多衣服。</p>
<h2>與房東的溝通</h2>
<p>跟一般旅館很不一樣的是,訂 AirBnB 通常在入住前就會跟房東會有好幾次的溝通,討論入住事宜,Airbnb的訊息會從Email,Mobile App,簡訊通知。有什麼問題,房東通常都會很樂意協助,像是詢問一些旅遊資訊:
<img alt="旅行" src="https://www.evernote.com/l/ABCWpkFQkNhLg4Q3XoH6o1VpC_6PSYDed8IB/image.png"></p>
<p>或是請房東先代收包裹。
<img alt="vitalie" src="https://www.evernote.com/l/ABBuXNSvPE5Fuo70mcQTzTxRIOSQ6wg48fIB/image.png"></p>
<p>所以房東某種程度上就變成你的旅遊當地旅遊顧問,透過 Airbnb 很容易連絡到房東,而大部份的房東也都會馬上透過 Airbnb 的 app 回應給你</p>
<p><img alt="travel-pln" src="https://www.evernote.com/l/ABBLQzn0eLtJUoi7pAMvG6JI_fc7easEozAB/image.png"></p>
<p>另外 Airbnb 上面的房間大部份都會提供 Pocket Wifi,這樣讓出國玩可以省下一筆租用上網費用。</p>
<p><img alt="pocket" src="https://www.evernote.com/l/ABDjEsEk43lMD7vaN1_4KOeVMRsIsUkgRI8B/image.png"></p>
<p><img alt="Pocket Wifi" src="https://lh3.googleusercontent.com/qoqBvlwI-A5Lcw891RqbxhJxFmQa6r_Tn36l2XHSd_Qrkzgy4Vnq2lmFqdrPXB03AGO-SDEi2zYbx3thSm4OlORXoMX2dckBtshKXhO1vTuVl1b4yJgV89Rc1CHoRxMo04pgAPbv2iTbBCL4WZG8okHzIAGxZ2CTyUSE5Woa4hH6rCVX-VdkIHKcHMNsetoR4nX3D523ccHmr5hAvKPD2KiJHuIN7bp3clBLr6mRbwDl585OfKveNkScCcxP7Is-Cti6K1gyXQlhWdUkfKVytmDr1avDsItCAG55CZm3EnEeMmCsUCLYbz9CIzLci2TmX11pP_yfsezpgs7zTK9j2brk1k8U6sILk_3Dfd3WffNhiCgb0qTcoQxi67y16zZRdyXiHTty6DGmvkEOoCskIcgLvMDPHVRuR_PAJfT6iHqgXgDXLbIxJw9M6x-ZEtw6g035MMKrlZhH363e9K6U8OX7w0ci-YOOeY28CoI2-qt1XjbfFt_eO1oCxloAjZDgHEE-kXoPfdTbh0p3EF4qoGpk=w200"></p>
<h2>實際住宿分享</h2>
<p>東京迪士尼旁邊的公寓,二個人一晚1974元,<a href="https://www.airbnb.com.tw/rooms/4800152">Link</a></p>
<p><img alt="disney" src="https://www.evernote.com/l/ABCqGyxm7rpDd4dFVBHiBrnKbNWLSPAtzxQB/image.png">
<img alt="disney" src="https://www.evernote.com/l/ABB8WDEImN5JEYu4Q0y_A5pAcguVqx9z3doB/image.png"></p>
<p>日本六本木 Hills 旁的公寓,二個人一晚2284元,<a href="https://www.airbnb.com.tw/rooms/3431627">Link</a></p>
<p><img alt="hills" src="https://www.evernote.com/l/ABDWg0nMD6RCH4Vxmvt9jdRCcOlTVNpzmK8B/image.png"></p>
<p><img alt="hills2" src="https://www.evernote.com/l/ABA3JxcRjtZLcIS0Hf3p_HdOl_4VPvaXDJ4B/image.png"></p>
<p>可以知道如果要住旅館,要有這樣的大小與設備,肯定是不只這樣的價錢的。</p>
<h2>最後</h2>
<p>目前 Airbnb 估值已經來到 250 億美金(2015/6),是未上市的公司估值排行的第三名,僅次於小米跟Uber,也是當今 O2O 成功的典範。雖然 Airbnb 名下沒有什麼房產,但是公司價值已經跟傳統旅館希爾頓萬豪相當了。建議還沒有試過 Airbnb 的人可以找個機會試試看,感受一下 Airbnb 的魅力。</p>
<h3><a href="https://goo.gl/ZoLSrX">透過我的邀請,立即領取 Airbnb 25美金 的訂房現金折扣</a></h3>聊聊 窮遊的「行程助手」2015-07-26T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-07-26:/product-qyer-plan-app/<p>我一直覺得做推薦旅遊行程是一個困難的題目,最主要的原因是每個人的喜好不同,很難推薦出一個讓大家都滿意的行程。最近窮遊上線了一個<a href="https://play.google.com/store/apps/details?id=com.qyer.android.plan&hl=zh_TW">行程助手的 App</a>,而 36Kr 也對此寫了一篇<a href="http://36kr.com/p/5035751.html">評論</a>,文章裡面提到窮遊網的PM說:</p>
<blockquote>
<p>行程计划是一件复杂的事情,因为产品就变得复杂,这和用户的易用性是矛盾的。因为功能越多,用户就越难上手,而恰好小白用户是数量最多的一群人。梅子希望穷游行程助手能够让资深用户觉得好用(因为穷游汇集了用户群中相对资深的一帮游客),同时小白也很容易上手,比如优化智能推荐的功能(这个功能有时候对于资深用户来说其实是很鸡肋的)</p>
</blockquote>
<p>因為窮游已經擁有海量的用戶做為基礎,並有他們提供POI資料以及評論。</p>
<h2>行動應用</h2>
<p>另外一個值得關注的點就是行程助手 App 做了什麼事情適合用在手機端的應用情境: </p>
<h3>問路卡</h3>
<p>一般人都是用 Google Map 找路,但總有找不到路的時侯,這邊設計了<code>問路卡模式</code>,把景點轉成大字體並配合當地的語言,方便找路人問路</p>
<p><img alt="晴空塔" src="https://lh3.googleusercontent.com/FhyFqC4EvDX2zzd1ttswqzarjqDmEkwOVUOjmwK60rdB=w1920-h1080-no"></p>
<h3>下一站</h3>
<p>給定一個景點之後,知道大家之後會去那邊</p>
<p><img alt="日本-淺草之後" src="https://lh3.googleusercontent.com/xWRhRm4v7UXnZDwOsrUwJ00zyQFsUfPmgIgmOrEdu0mA=h500"></p>
<p><img alt="附近景點建議" src="https://lh3.googleusercontent.com/oMe_tGkxV1fAHrC3mzEJbApngeRHbm-zOpA3jk_3xiR8=h500"></p>
<p>任何一個產品前,定義好目標客群絕對是超級重要的。對於大部份的 Startup 來說,在初期資源有限的情況下,不需要一開始就討好每個族群,而應該比較找容易成功的族群。假如要自己收集 POI 的景點資料,那麼我們就要問自己,到底是這些POI是要給新手旅遊用戶,還是資深旅遊玩家使用?因為POI所需要的資訊就很可能完全不一樣,而建立一個 POI 的成本,就會直接影響之後運營等等。</p>
<!--
- 口袋地陪
- 人員問題
- TA 問題
-->聊聊 口袋地陪2015-07-20T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-07-20:/product-pocket-dipei/<p>最近看到不少在中國有趣的旅遊新點子,口袋地陪就是其中一個例子:</p>
<blockquote>
<p>口袋地陪目前不是一个手机 app,而是一个依托于微信的服务号,每天50元可以提供9个小时的实时咨询。当游客需要一个线上地陪时,通过服务号预约下单,选择出行需求,口袋地陪系统会为其派发一个最适合的地陪人员。旅游过程中,地陪随时在线,与游客通过微信(时下最频繁的沟通工具)保持联系,时刻了解并满足游客的需求。</p>
</blockquote>
<p><img alt="口袋地陪的畫面" src="https://lh3.googleusercontent.com/PLba33VQwwqtp7lzE-PGZmwD1AGGJPA9QNzDJrrQ9VNP=w700-h414-no"></p>
<blockquote>
<p>例如,当你迷路在东京站 300 多个出口时,拍一张照片,地陪就能根据你的当前位置告诉你目的地应该如何走;当你在一家餐厅看不懂菜单,服务员又不会讲英文,拍一张菜单的照片,地陪会立刻为你翻译成中文;当你想在大阪购买最实用最便宜的电饭煲,地陪会将推荐商城和导航信息直接发给你。</p>
<p>窮游、攜程等網站只能滿足遊客旅行前的攻略、機票酒店預定,無法顧及到旅行過程中的售後環節。口袋地陪彌補的正是這一塊市場的空缺</p>
</blockquote>
<p>口袋地陪主打的是旅遊中的服務,目前這塊還是藍海。讓我驚訝的是口袋地陪選用微信而不是自己打造一個 App。我想最主要的原因應該是降低使用者入門的門檻,畢竟下載一個 App 在大部份的情況都是太麻煩了。另外一個就是在確認需求前,節省 App 開發的成本。在人們已經習慣的平台上面交流,如果是用在台灣,那想必就是 LINE 了。</p>How to use Android Snackbar2015-07-02T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-07-02:/snackbar-en.html<p>I created a small toy to demo Android snackbar featrue, you can find the project on <a href="https://goo.gl/ARYKIm">cwliu/Try_Snackbar</a></p>
<p><img alt="snackbar demo" src="https://lh6.googleusercontent.com/-f-MwKyeimbc/VZO-dX_CSGI/AAAAAAAHE9w/ZgKBEamZsyg/w366/"></p>
<h2>Setup</h2>
<p>In app build.gradle, add design support library:</p>
<div class="highlight"><pre><span></span><code>dependencies {
...
compile 'com.android.support:design:22.2.0'
}
</code></pre></div>
<h2>Show snackbar</h2>
<p>Just like the toast usage, </p>
<div class="highlight"><pre><span></span><code><span class="nv">Snackbar</span>.<span class="nv">make</span><span class="ss">(</span><span class="nv">view</span>, <span class="s2">"</span><span class="s">Hello world</span><span class="s2">"</span>,<span class="nv">Snackbar</span>.<span class="nv">LENGTH_LONG</span><span class="ss">)</span>.<span class="k">show</span><span class="ss">()</span><span class="c1">;</span>
</code></pre></div>
<h2>Set snackbar action</h2>
<div class="highlight"><pre><span></span><code><span class="n">snackbar</span><span class="p">.</span><span class="n">setAction</span><span class="p">(</span><span class="ss">"Undo"</span><span class="p">,</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="k">View</span><span class="p">.</span><span class="n">OnClickListener</span><span class="p">()</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="nv">@Override</span><span class="w"></span>
<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">void</span><span class="w"> </span><span class="n">onClick</span><span class="p">(</span><span class="k">View</span><span class="w"> </span><span class="n">v</span><span class="p">)</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">Do</span><span class="w"> </span><span class="n">something</span><span class="w"></span>
<span class="w"> </span><span class="err">}</span><span class="w"></span>
<span class="err">}</span><span class="p">);</span><span class="w"></span>
</code></pre></div>
<h2>Integrate snackbar to floating action button</h2>
<div class="highlight"><pre><span></span><code><span class="nv">coordinator_layout</span> <span class="o">=</span> <span class="nv">findViewById</span><span class="ss">(</span><span class="nv">R</span>.<span class="nv">id</span>.<span class="nv">coordinatorlayout</span><span class="ss">)</span><span class="c1">;</span>
<span class="nv">Snackbar</span>.<span class="nv">make</span><span class="ss">(</span><span class="nv">coordinator_layout</span>, <span class="s2">"</span><span class="s">Hi</span><span class="s2">"</span>, <span class="nv">Snackbar</span>.<span class="nv">LENGTH_LONG</span><span class="ss">)</span>.<span class="k">show</span><span class="ss">()</span><span class="c1">;</span>
</code></pre></div>
<h2>Customize snackbar styling</h2>
<p>In stylings.xml, </p>
<div class="highlight"><pre><span></span><code><span class="nt"><style</span> <span class="na">name=</span><span class="s">"Widget.Design.Snackbar"</span> <span class="na">parent=</span><span class="s">"android:Widget …</span></code></pre></div><p>I created a small toy to demo Android snackbar featrue, you can find the project on <a href="https://goo.gl/ARYKIm">cwliu/Try_Snackbar</a></p>
<p><img alt="snackbar demo" src="https://lh6.googleusercontent.com/-f-MwKyeimbc/VZO-dX_CSGI/AAAAAAAHE9w/ZgKBEamZsyg/w366/"></p>
<h2>Setup</h2>
<p>In app build.gradle, add design support library:</p>
<div class="highlight"><pre><span></span><code>dependencies {
...
compile 'com.android.support:design:22.2.0'
}
</code></pre></div>
<h2>Show snackbar</h2>
<p>Just like the toast usage, </p>
<div class="highlight"><pre><span></span><code><span class="nv">Snackbar</span>.<span class="nv">make</span><span class="ss">(</span><span class="nv">view</span>, <span class="s2">"</span><span class="s">Hello world</span><span class="s2">"</span>,<span class="nv">Snackbar</span>.<span class="nv">LENGTH_LONG</span><span class="ss">)</span>.<span class="k">show</span><span class="ss">()</span><span class="c1">;</span>
</code></pre></div>
<h2>Set snackbar action</h2>
<div class="highlight"><pre><span></span><code><span class="n">snackbar</span><span class="p">.</span><span class="n">setAction</span><span class="p">(</span><span class="ss">"Undo"</span><span class="p">,</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="k">View</span><span class="p">.</span><span class="n">OnClickListener</span><span class="p">()</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="nv">@Override</span><span class="w"></span>
<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">void</span><span class="w"> </span><span class="n">onClick</span><span class="p">(</span><span class="k">View</span><span class="w"> </span><span class="n">v</span><span class="p">)</span><span class="w"> </span><span class="err">{</span><span class="w"></span>
<span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">Do</span><span class="w"> </span><span class="n">something</span><span class="w"></span>
<span class="w"> </span><span class="err">}</span><span class="w"></span>
<span class="err">}</span><span class="p">);</span><span class="w"></span>
</code></pre></div>
<h2>Integrate snackbar to floating action button</h2>
<div class="highlight"><pre><span></span><code><span class="nv">coordinator_layout</span> <span class="o">=</span> <span class="nv">findViewById</span><span class="ss">(</span><span class="nv">R</span>.<span class="nv">id</span>.<span class="nv">coordinatorlayout</span><span class="ss">)</span><span class="c1">;</span>
<span class="nv">Snackbar</span>.<span class="nv">make</span><span class="ss">(</span><span class="nv">coordinator_layout</span>, <span class="s2">"</span><span class="s">Hi</span><span class="s2">"</span>, <span class="nv">Snackbar</span>.<span class="nv">LENGTH_LONG</span><span class="ss">)</span>.<span class="k">show</span><span class="ss">()</span><span class="c1">;</span>
</code></pre></div>
<h2>Customize snackbar styling</h2>
<p>In stylings.xml, </p>
<div class="highlight"><pre><span></span><code><span class="nt"><style</span> <span class="na">name=</span><span class="s">"Widget.Design.Snackbar"</span> <span class="na">parent=</span><span class="s">"android:Widget"</span><span class="nt">></span>
<span class="nt"><item</span> <span class="na">name=</span><span class="s">"android:background"</span><span class="nt">></span>#00FF00<span class="nt"></item></span>
<span class="nt"></style></span>
</code></pre></div>
<p>For more styling options, couldrefer to <code>/build/intermediates/exploded-aar/com.android.support/design/22.2.0/res/values/values.xml</code></p>
<h2>Reference</h2>
<ul>
<li><a href="https://goo.gl/4RV4kB">Snackbars | Google Design Guidelines</a></li>
<li><a href="http://goo.gl/1PwJuc">Snackbar | Developers Reference</a></li>
<li><a href="https://www.youtube.com/watch?v=puhfMX8jb9c">Snackbar | Android Development Patterns S2 Ep 1)</a></li>
</ul>元大寶來臺灣高股息基金(0056)週轉率與選股方法2015-05-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-05-01:/0056-ground-rules/<p>台灣國內指數股票型基金(ETF),最有名的兩檔就是元大寶來台灣卓越50基金(0050)跟元大寶來臺灣高股息基金(0056),0050選股方式很直覺,就是挑選台股市值最大的50檔股票,選股基準可參考此<a href="http://www.ftse.com/products/downloads/FTSE_TWSE_Taiwan_Index_Series.pdf">文件</a>,指數會在3/6/9/12月每季更新。至於 0056的指數如何選股?!在元大寶來的網站的基金說明是寫:</p>
<blockquote>
<p>成分股是由臺灣50指數及臺灣中型100指數成分股中符合流動性測試標準,挑選未來一年預測現金股利殖利率最高的30檔股票作為成分股</p>
</blockquote>
<p>我想大部份的人應該對於<code>預測</code>感到困惑。於是我就去FTSE把0056的選股基準文件<a href="http://www.ftse.com/products/downloads/FTSE_TWSE_Taiwan_Dividend_Plus_Index.pdf">(英)</a>/<a href="http://www.twse.com.tw/ch/products/download/TWSETwIndex05.pdf">(中)</a>找了出來,想了解一下如何選股。</p>
<p>0056 所追蹤的指數英文名稱為<code>FTSE TWSE TAIWAN DIVIDEND+ INDEX</code>,每年3/9月會更新成份股,其成份股的比重都很相近,以2015/5/17的資料為例,其中最高的為微星佔4.63%,而最低的則是美律為1.88%。另外買ETF除了內扣成本率之外,也需要關注其週轉率,對於0056最常被唸的就是其週轉率比0050高上許多,0056的年週轉率從<a href="http://www.sitca.org.tw/ROC/Industry/IN2302.aspx?pid=IN2232_01">投信投顧公會的資料</a>顯示:</p>
<table>
<thead>
<tr>
<th>年度</th>
<th align="right">買進週轉率</th>
<th align="right">賣出週轉率</th>
</tr>
</thead>
<tbody>
<tr>
<td>2012</td>
<td align="right">50.41%</td>
<td align="right">45.18%</td>
</tr>
<tr>
<td>2013</td>
<td align="right">54.19%</td>
<td align="right">51.17%</td>
</tr>
<tr>
<td>2014</td>
<td align="right">48.35%</td>
<td align="right">44.71%</td>
</tr>
</tbody>
</table>
<p>差不多接近 50%,相較於元大寶來台灣卓越50基金(0050)</p>
<table>
<thead>
<tr>
<th>年度</th>
<th align="right">買進週轉率</th>
<th align="right">賣出週轉率</th>
</tr>
</thead>
<tbody>
<tr>
<td>2012</td>
<td align="right">5.01%</td>
<td align="right">0.18%</td>
</tr>
<tr>
<td>2013</td>
<td align="right">8.23%</td>
<td align="right">5.99%</td>
</tr>
<tr>
<td>2014</td>
<td align="right">5.08%</td>
<td align="right">1.38%</td>
</tr>
</tbody>
</table>
<p>0056的週轉率是偏高許多的,以這樣的週轉率可推知,0056平均持有的股票時間約2年左右。</p>
<p>關於選股方法,是使用公式計算出預測的現金股利殖利率排名,因為每次計算的結果現金股利殖利率各股的變動很大。FTSE為了減少週轉率,使用週轉率緩衝(Turnover buffer …</p><p>台灣國內指數股票型基金(ETF),最有名的兩檔就是元大寶來台灣卓越50基金(0050)跟元大寶來臺灣高股息基金(0056),0050選股方式很直覺,就是挑選台股市值最大的50檔股票,選股基準可參考此<a href="http://www.ftse.com/products/downloads/FTSE_TWSE_Taiwan_Index_Series.pdf">文件</a>,指數會在3/6/9/12月每季更新。至於 0056的指數如何選股?!在元大寶來的網站的基金說明是寫:</p>
<blockquote>
<p>成分股是由臺灣50指數及臺灣中型100指數成分股中符合流動性測試標準,挑選未來一年預測現金股利殖利率最高的30檔股票作為成分股</p>
</blockquote>
<p>我想大部份的人應該對於<code>預測</code>感到困惑。於是我就去FTSE把0056的選股基準文件<a href="http://www.ftse.com/products/downloads/FTSE_TWSE_Taiwan_Dividend_Plus_Index.pdf">(英)</a>/<a href="http://www.twse.com.tw/ch/products/download/TWSETwIndex05.pdf">(中)</a>找了出來,想了解一下如何選股。</p>
<p>0056 所追蹤的指數英文名稱為<code>FTSE TWSE TAIWAN DIVIDEND+ INDEX</code>,每年3/9月會更新成份股,其成份股的比重都很相近,以2015/5/17的資料為例,其中最高的為微星佔4.63%,而最低的則是美律為1.88%。另外買ETF除了內扣成本率之外,也需要關注其週轉率,對於0056最常被唸的就是其週轉率比0050高上許多,0056的年週轉率從<a href="http://www.sitca.org.tw/ROC/Industry/IN2302.aspx?pid=IN2232_01">投信投顧公會的資料</a>顯示:</p>
<table>
<thead>
<tr>
<th>年度</th>
<th align="right">買進週轉率</th>
<th align="right">賣出週轉率</th>
</tr>
</thead>
<tbody>
<tr>
<td>2012</td>
<td align="right">50.41%</td>
<td align="right">45.18%</td>
</tr>
<tr>
<td>2013</td>
<td align="right">54.19%</td>
<td align="right">51.17%</td>
</tr>
<tr>
<td>2014</td>
<td align="right">48.35%</td>
<td align="right">44.71%</td>
</tr>
</tbody>
</table>
<p>差不多接近 50%,相較於元大寶來台灣卓越50基金(0050)</p>
<table>
<thead>
<tr>
<th>年度</th>
<th align="right">買進週轉率</th>
<th align="right">賣出週轉率</th>
</tr>
</thead>
<tbody>
<tr>
<td>2012</td>
<td align="right">5.01%</td>
<td align="right">0.18%</td>
</tr>
<tr>
<td>2013</td>
<td align="right">8.23%</td>
<td align="right">5.99%</td>
</tr>
<tr>
<td>2014</td>
<td align="right">5.08%</td>
<td align="right">1.38%</td>
</tr>
</tbody>
</table>
<p>0056的週轉率是偏高許多的,以這樣的週轉率可推知,0056平均持有的股票時間約2年左右。</p>
<p>關於選股方法,是使用公式計算出預測的現金股利殖利率排名,因為每次計算的結果現金股利殖利率各股的變動很大。FTSE為了減少週轉率,使用週轉率緩衝(Turnover buffer),規則如下:</p>
<blockquote>
<p>非成份股票上升到第15名以內,則納入指數
成份股下降到46名之後,則從指數移除</p>
</blockquote>
<p>經過上述的計算,如果少於30檔,則按排名從非成份股補足30檔股票,若多於30檔,則按排名,從最低分的成份股排除至30檔股票。另外,避免一次變動太快,所以每半年最多5增5減,以近期來看:</p>
<table>
<thead>
<tr>
<th>時間</th>
<th align="left">新增</th>
<th align="left">刪除</th>
</tr>
</thead>
<tbody>
<tr>
<td>2014/4</td>
<td align="left">京元電(2449)、國建(2501)、聯強(2347)、潤泰新(9945)、力成(6239)</td>
<td align="left">聯電(2303)、寶成(9904)、台化(1326)、台塑(1301)</td>
</tr>
<tr>
<td>2014/9</td>
<td align="left">微星(2377)、技嘉(2376)、英業達(2356)、統一實(9907)、潤泰全(2915)</td>
<td align="left">國建(2501)、東聯(1710)、F-TPK(3673)、華固(2548)</td>
</tr>
<tr>
<td>2015/3</td>
<td align="left">裕日車(2227),正崴(2392),美律(2439),開發金(2883),中碳(1723)</td>
<td align="left">中鼎(9933)、台橡(2103)、統一實(9907)、創見(2451)、興富發(2542)</td>
</tr>
</tbody>
</table>
<p>可見每次幾乎都是5增5減,換句話說,30檔裡面,只有20檔會留在榜內,每半年會換1/3左右,由此可知這是造成 0056 年週轉率接近 50% 的主因。</p>
<p><img alt="fomula" src="http://i.imgur.com/trRVuAcl.png"></p>
<ul>
<li>p: 成交價</li>
<li>s: 發行股數</li>
<li>f/d: 調整的公眾流通係數</li>
<li>c: 股利預測係數</li>
</ul>
<p>裡面最主要其中 <code>ci</code> 是股利係數,0056是專業機構 Thomson Reuters 的資料庫取得預測未來股殖利率,或是由FTSE資料庫中篩選過去最佳股殖利率,很可惜的這個數據並沒沒有公開,也就是分析師要給多大的權重,就直接影響到股票所穫得的權重。這個數值對於一般投資人而言,沒辦法知道詳細的細節。</p>
<p>因為週轉率比較高,所以也直接影響了交易成本: </p>
<table>
<thead>
<tr>
<th>股票</th>
<th>交易成本</th>
<th>內扣成本率</th>
</tr>
</thead>
<tbody>
<tr>
<td>0050</td>
<td>0.02%</td>
<td>0.43%</td>
</tr>
<tr>
<td>0056</td>
<td>0.24%</td>
<td>0.73%</td>
</tr>
</tbody>
</table>
<p>由以上的週轉率數據,在以長期投資的角度而言, 或許 0050 會比 0056 來得理想些。</p>Vagrant 筆記2015-05-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-05-01:/vagrant/<h2>安裝 Vagrant (以 VritualBox 為例)</h2>
<ol>
<li>VirtualBox </li>
<li>VirtualBox Extension Pack
(Oracle_VM_VirtualBox_Extension_Pack-4.3.26-98988.vbox-extpack)</li>
<li>Vagrant (vagrant_1.7.2.dmg)</li>
</ol>
<h2>新增一個 VM</h2>
<p><strong>官方 Box 列表</strong>要知道有那些 Vagrant box 的話,可以到此<a href="https://atlas.hashicorp.com/boxes/search">瀏覽</a></p>
<p>新增一個 VM </p>
<div class="highlight"><pre><span></span><code>$ mkdir <project_name>
$ <span class="nb">cd</span> <project_name>
$ vagrant init <span class="o">[</span>box-name<span class="o">]</span>
</code></pre></div>
<p>例子:
$ vagrant init ubuntu/vivid64 </p>
<h1>Vagrant Box</h1>
<p>列出已下載的 vagrant box list:</p>
<div class="highlight"><pre><span></span><code>$ vagrant box list
</code></pre></div>
<p>新增 box 到 Vagrant,以 ubuntu 15.04 為例: </p>
<div class="highlight"><pre><span></span><code>$ vagrant box add ubuntu/vivid64
</code></pre></div>
<p>手機修改 <code>Vagrantfile</code> 指定使用那一個 VM Box </p>
<div class="highlight"><pre><span></span><code><span class="nv">Vagrant</span>.<span class="nv">configure</span><span class="ss">(</span><span class="s2">"</span><span class="s">2</span><span class="s2">"</span><span class="ss">)</span> <span class="k">do</span> <span class="o">|</span><span class="nv">config</span><span class="o">|</span>
<span class="nv">config</span>.<span class="nv">vm</span>.<span class="nv">box</span> <span class="o">=</span> <span class="s2">"</span><span class="s">ubuntu/vivid64</span><span class="s2">"</span>
<span class="k">end</span>
</code></pre></div>
<h1>啟動</h1>
<p>啟動指定名稱</p>
<div class="highlight"><pre><span></span><code>$ vagrant up <NAME>
</code></pre></div>
<p>也可以全部啟動: </p>
<div class="highlight"><pre><span></span><code>$ vagrant up
</code></pre></div>
<h1>登入</h1>
<div class="highlight"><pre><span></span><code>$ vagrant ssh
</code></pre></div>
<p>若有多個 VM,就要指定名稱</p>
<div class="highlight"><pre><span></span><code>$ vagrant ssh <NAME>
</code></pre></div>
<p>Guest …</p><h2>安裝 Vagrant (以 VritualBox 為例)</h2>
<ol>
<li>VirtualBox </li>
<li>VirtualBox Extension Pack
(Oracle_VM_VirtualBox_Extension_Pack-4.3.26-98988.vbox-extpack)</li>
<li>Vagrant (vagrant_1.7.2.dmg)</li>
</ol>
<h2>新增一個 VM</h2>
<p><strong>官方 Box 列表</strong>要知道有那些 Vagrant box 的話,可以到此<a href="https://atlas.hashicorp.com/boxes/search">瀏覽</a></p>
<p>新增一個 VM </p>
<div class="highlight"><pre><span></span><code>$ mkdir <project_name>
$ <span class="nb">cd</span> <project_name>
$ vagrant init <span class="o">[</span>box-name<span class="o">]</span>
</code></pre></div>
<p>例子:
$ vagrant init ubuntu/vivid64 </p>
<h1>Vagrant Box</h1>
<p>列出已下載的 vagrant box list:</p>
<div class="highlight"><pre><span></span><code>$ vagrant box list
</code></pre></div>
<p>新增 box 到 Vagrant,以 ubuntu 15.04 為例: </p>
<div class="highlight"><pre><span></span><code>$ vagrant box add ubuntu/vivid64
</code></pre></div>
<p>手機修改 <code>Vagrantfile</code> 指定使用那一個 VM Box </p>
<div class="highlight"><pre><span></span><code><span class="nv">Vagrant</span>.<span class="nv">configure</span><span class="ss">(</span><span class="s2">"</span><span class="s">2</span><span class="s2">"</span><span class="ss">)</span> <span class="k">do</span> <span class="o">|</span><span class="nv">config</span><span class="o">|</span>
<span class="nv">config</span>.<span class="nv">vm</span>.<span class="nv">box</span> <span class="o">=</span> <span class="s2">"</span><span class="s">ubuntu/vivid64</span><span class="s2">"</span>
<span class="k">end</span>
</code></pre></div>
<h1>啟動</h1>
<p>啟動指定名稱</p>
<div class="highlight"><pre><span></span><code>$ vagrant up <NAME>
</code></pre></div>
<p>也可以全部啟動: </p>
<div class="highlight"><pre><span></span><code>$ vagrant up
</code></pre></div>
<h1>登入</h1>
<div class="highlight"><pre><span></span><code>$ vagrant ssh
</code></pre></div>
<p>若有多個 VM,就要指定名稱</p>
<div class="highlight"><pre><span></span><code>$ vagrant ssh <NAME>
</code></pre></div>
<p>Guest <code>/vagrant</code> 目錄 會和 Host 的 Vagrant project 目錄互連</p>
<h1>查看</h1>
<p>查看 project 目前 vagrant machine 的狀態</p>
<div class="highlight"><pre><span></span><code>$ vagrant status
</code></pre></div>
<h1>休眠/關機</h1>
<p>把 VM 休眠:</p>
<div class="highlight"><pre><span></span><code>$ vagrant spend
</code></pre></div>
<p>把 VM 關機:</p>
<div class="highlight"><pre><span></span><code>$ vagrant halt
</code></pre></div>
<p>把 VM 刪除: </p>
<div class="highlight"><pre><span></span><code>$ vagrant destroy --force
</code></pre></div>
<h1>Provision</h1>
<div class="highlight"><pre><span></span><code><span class="o">$</span> <span class="n">vagrant</span> <span class="n">up</span>
<span class="o">$</span> <span class="n">vagrant</span> <span class="n">reload</span> <span class="o">--</span><span class="n">provision</span>
</code></pre></div>
<h1>Vagrantfile</h1>
<div class="highlight"><pre><span></span><code>Synced_Folder
node.vm.synced_folder ".", SYNCED_FOLDER
</code></pre></div>
<h2>參考教學文件</h2>
<ul>
<li><a href="https://docs.vagrantup.com/v2/">Getting start官方版</a></li>
<li><a href="http://goo.gl/8BwvKO">Vagrant Tutorial(1)雲端研發人員,你也需要虛擬機! by William Yeh | CodeData</a></li>
</ul>Java verify Error(unchecked exception)2015-04-09T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-04-09:/java-verify-error-unchecked-exception/<p>前幾天,在 Google Play Console 收到了二個從使用者回報的 Crash Log,分別是從 Android 5.1 和 4.4 版本所回報的,Android 5.1 的 Traceback:</p>
<div class="highlight"><pre><span></span><code><span class="o">...</span>
<span class="nt">Caused</span> <span class="nt">by</span><span class="o">:</span> <span class="nt">java</span><span class="p">.</span><span class="nc">lang</span><span class="p">.</span><span class="nc">NoClassDefFoundError</span><span class="o">:</span> <span class="nt">Failed</span> <span class="nt">resolution</span> <span class="nt">of</span><span class="o">:</span> <span class="nt">Lcom</span><span class="o">/</span><span class="nt">adobe</span><span class="o">/</span><span class="nt">xmp</span><span class="o">/</span><span class="nt">XMPMetaFactory</span><span class="o">;</span>
<span class="o">...</span>
</code></pre></div>
<p>Android 4.4 的 Traceback</p>
<div class="highlight"><pre><span></span><code>...
Caused by: java.lang.VerifyError: com/drew/metadata/xmp/XmpReader
...
</code></pre></div>
<p>我花了一些時間把 tracecode 希望可以找到是那邊發生的,但是一直找不到。最後發現,這邊丟出來的 Error 是 <code>unchecked exceptions</code> 也就是預期是程式有 Bug,所以不會由 Try-catch 來 handle 這種 error。這種 Error 需要丟出來讓外界來把這個 bug 修掉。這個問題是因為我們有用到一個 thirdparty 的 Library 叫 <code>metadata-extractor</code> 其中包含了兩個 jar 檔: <code>metadata-extractor-x.x.x.jar</code> 和 <code>xmpcore-x.x.x.jar</code>。我們因故漏放了<code>xmpcore-x.x.x.jar</code>,導致在處理 xmp 相關的圖檔出現這個錯誤。最後緊急把<code>xmpcore-x.x …</code></p><p>前幾天,在 Google Play Console 收到了二個從使用者回報的 Crash Log,分別是從 Android 5.1 和 4.4 版本所回報的,Android 5.1 的 Traceback:</p>
<div class="highlight"><pre><span></span><code><span class="o">...</span>
<span class="nt">Caused</span> <span class="nt">by</span><span class="o">:</span> <span class="nt">java</span><span class="p">.</span><span class="nc">lang</span><span class="p">.</span><span class="nc">NoClassDefFoundError</span><span class="o">:</span> <span class="nt">Failed</span> <span class="nt">resolution</span> <span class="nt">of</span><span class="o">:</span> <span class="nt">Lcom</span><span class="o">/</span><span class="nt">adobe</span><span class="o">/</span><span class="nt">xmp</span><span class="o">/</span><span class="nt">XMPMetaFactory</span><span class="o">;</span>
<span class="o">...</span>
</code></pre></div>
<p>Android 4.4 的 Traceback</p>
<div class="highlight"><pre><span></span><code>...
Caused by: java.lang.VerifyError: com/drew/metadata/xmp/XmpReader
...
</code></pre></div>
<p>我花了一些時間把 tracecode 希望可以找到是那邊發生的,但是一直找不到。最後發現,這邊丟出來的 Error 是 <code>unchecked exceptions</code> 也就是預期是程式有 Bug,所以不會由 Try-catch 來 handle 這種 error。這種 Error 需要丟出來讓外界來把這個 bug 修掉。這個問題是因為我們有用到一個 thirdparty 的 Library 叫 <code>metadata-extractor</code> 其中包含了兩個 jar 檔: <code>metadata-extractor-x.x.x.jar</code> 和 <code>xmpcore-x.x.x.jar</code>。我們因故漏放了<code>xmpcore-x.x.x.jar</code>,導致在處理 xmp 相關的圖檔出現這個錯誤。最後緊急把<code>xmpcore-x.x.x.jar</code>加回來解決了這個問題。</p>
<h2>Unchecked exception 的例子</h2>
<p>包含 RuntimeException, Error, 跟他們的子類別,例如: NullPointerException.</p>
<blockquote>
<p>Here's the bottom line guideline:
If a client can reasonably be expected to recover from an exception, make it a checked exception.
If a client cannot do anything to recover from the exception, make it an unchecked exception.</p>
</blockquote>
<h2>Reference</h2>
<ul>
<li><a href="https://docs.oracle.com/javase/tutorial/essential/exceptions/runtime.html">Unchecked Exceptions — The Controversy (The Java™ Tutorials > Essential Classes > Exceptions)</a></li>
<li><a href="http://teddy-chen-tw.blogspot.tw/2011/05/checked-or-unchecked-exceptions-1.html">搞笑談軟工: Checked or unchecked exceptions (1)</a></li>
</ul>AWS IAM 修改使用者帳號密碼2015-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-01-01:/aws-change-password/<p>在 User Group 加上以下的 Inline Policy : </p>
<div class="highlight"><pre><span></span><code>{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": [
"iam:ChangePassword",
"iam:GetAccountPasswordPolicy"
],
"Resource": "*"
}
}
</code></pre></div>
<p><img alt="inline policy" src="http://i.imgur.com/28vW7kL.png"></p>
<h3>Reference: http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_passwords_enable-user-change.html</h3>實現免密碼 ssh 登入遠端主機2015-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-01-01:/cmd-ssh-copy-id/<h2>建立 RSA 的 Key</h2>
<p>如果之前沒有建立過 RSA 的 key,就可以先建一把: </p>
<div class="highlight"><pre><span></span><code>$ ssh-keygen
</code></pre></div>
<p>過程直接一直按 enter 即可</p>
<h2>Copy ssh public to remote</h2>
<p>RSA 由一組 public key 跟 private 組成,為了要能實現免密碼登入 remote machine 必須安裝 public key (id_rsa.pub) 到 remote machine:</p>
<div class="highlight"><pre><span></span><code>$ ssh-copy-id -i ~/.ssh/id_rsa.pub cody@172.24.22.63
</code></pre></div>
<h2>執行免密碼登入</h2>
<div class="highlight"><pre><span></span><code>$ ssh cody@172.24.22.63
</code></pre></div>
<p><strong>Note</strong>:
當發生 <code>/usr/bin/ssh-copy-id: ERROR: No identities found</code> 的錯誤時,記得加上 <code>-i</code> 參數指定 public key 的位置,例如: </p>
<div class="highlight"><pre><span></span><code>$ ssh-copy-id -i ~/.ssh/id_rsa.pub mitra@172.24.22.63
</code></pre></div>
<h2>Reference:</h2>
<ul>
<li><a href="http://www.thegeekstuff.com/2008/11/3-steps-to-perform-ssh-login-without-password-using-ssh-keygen-ssh-copy-id/">3 Steps to Perform SSH Login Without Password Using ssh-keygen & ssh-copy-id</a></li>
</ul>怦然心動的人生整理魔法 22015-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-01-01:/gtd-storage-magic-2/<p><img alt="book-cover" src="http://i.imgur.com/nTcGsa1.png"></p>
<h2>先做好整理的基本功</h2>
<p>以「能否讓自己心動」為前題,把讓自己不心動的東西丟掉。這也是本書<a href="http://blog.codylab.com/storage-magic/">第一集</a>的重點。要先做好這一步,後續的<code>整理</code>才有意義,成功率也可以大幅增加。</p>
<h2>區分整理</h2>
<ul>
<li>不要把整理跟打掃混為一談,整理是面對<strong>物品</strong>,而打掃則是面對<strong>污垢</strong>。</li>
<li>整理可以長久做一次,並減少打掃的困難度。</li>
<li>而整理收納就是要<strong>決定物品的家</strong>。</li>
</ul>
<h2>私人能量景點</h2>
<ul>
<li>擁有自己的私人空間做,放置讓自己心動的小物做為能量景點</li>
</ul>
<h2>收納技巧</h2>
<ul>
<li>收納四原則: 折疊、直立、集中、隔成四方形</li>
<li>直立的目的是為了可以看清楚每一件物品的位置</li>
</ul>
<h2>整理的順序</h2>
<ol>
<li>衣服</li>
<li>書籍</li>
<li>文件</li>
<li>小東西</li>
<li>紀念品</li>
</ol>
<h2>廚房收納</h2>
<ul>
<li>只要做飯的人認為家裡的廚房是一個可以開心做菜的空間,就是最好的狀態</li>
<li>廚房收納要以<strong>容易清理</strong>為前提而不是<strong>容易拿取</strong>。</li>
</ul>
<h2>製作一本回憶相簿</h2>
<ul>
<li>對面大量的數位照片,挑出自己心動的照片會比刪掉拍不好的照片來得有效率的多</li>
</ul>把靜態網站架設在 Amazon S3 上2015-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2015-01-01:/s3-static-website/<p>以下是把 S3 的 Bucket 設定成 Static Website 的關鍵步驟: </p>
<ol>
<li>
<p>在 Bucket 設定中,把 "Enable website hosting" 功能啟動</p>
<p><img alt="enable static web" src="http://i.imgur.com/uonS7RPl.png"></p>
</li>
<li>
<p>Edit Bucket Policy Editor</p>
<p><img alt="permission" src="http://i.imgur.com/h7O3WI0.png"></p>
<p><img alt="img" src="http://i.imgur.com/97f4P6F.png"></p>
<p>輸入以下內容</p>
<div class="highlight"><pre><span></span><code>{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<YOUR_BUCKET_NAME>/*"
}
]
}
</code></pre></div>
<p>最後即可在 Endpoint 看到該 bucket 所對應的網址</p>
<p><img alt="endpint" src="http://i.imgur.com/EYzjUlN.png"></p>
</li>
</ol>2014 日本東京馬拉松2014-12-12T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-12-12:/tokyo-marathon-2014/<p>至今在台灣參加了十幾場的路跑賽事。但是讓自己衝擊最深刻的還是今年二月到日本參加的東京馬拉松,參加馬拉松的心態其實也不是想跟誰拼個輸贏,大多是想感受現場的氣氛。而在東京街頭,你會很懷疑是從那邊冒出那麼多的民眾。全線42公里,真的不跨張,全線都站滿了應援團的民眾,就算只是剛從起點出發,都會有種似乎快到終點,接受英雄式的歡呼的感覺。所以即使是只有6度左右的寒冷天氣,還是讓人一開始起跑就熱血沸騰!</p>
<p><img alt="起跑" src="https://lh4.googleusercontent.com/-REr3_643i04/VA7A3xQd0cI/AAAAAAAFWX4/CYmhF14naEQ/w1832-h1036-no/IMAG2655.jpg"></p>
<p><img alt="沿線民眾" src="https://lh6.googleusercontent.com/-czXgKzsukAY/VBVQJ-0kS1I/AAAAAAAGnQE/S4DXAcOT5JI/w1832-h1036-no/IMAG2670.jpg"></p>
<p><img alt="沿線民眾2" src="https://lh3.googleusercontent.com/-Qgs4lQuKhfs/VBVQMK7qiUI/AAAAAAAFwGo/nagB30qMo6c/w1584-h1184-no/Photo%2B2014-2-23%2B9%2B29%2B35.jpg"></p>
<p><img alt="東京鐵塔" src="https://lh5.googleusercontent.com/ztiCa8W7Y96IM3bJ4UQ4ITG_ePmXKM8UfNs4X7a5bCqp=w670-h1184-no"></p>
<p>總結整個東京馬的三大重點就是: <strong>Cosplay</strong>,<strong>補給</strong>,<strong>日本人對於賽事的態度</strong></p>
<h2>Cosplay</h2>
<p>東京馬的一大亮點就是超超超多有趣的Cosplay。日本真的是Cosplay大國,除了跑者會打扮成各種人物之外,路邊的應援團也有很多人都精心打扮。即使是穿著簡單的蕃茄,也都會受到民眾熱情的加油 「Tomedo 頑張って」。發現日本正在流行一款吉祥物船梨精(ふなっしー),是個讓很多小朋友政太,蘿莉為之瘋狂的水果。Cosplay台灣人也沒有缺席,三太子也一整個超吸晴的。熱情的民眾,讓人敞開心胸,這輩子也從來沒跟那麼多人自拍過,整個玩開了。</p>
<p><img alt="三太子" src="https://lh6.googleusercontent.com/-7PbYbNvfkrw/VBVP9ckfo2I/AAAAAAAFwFo/uL7GbrYS99k/w670-h1184-no/IMAG2641.jpg"></p>
<p><img alt="ふなっしー" src="https://lh3.googleusercontent.com/-2KJP778JdK4/VBVQVqmtwOI/AAAAAAAFwHQ/sI9gs6eflC4/w670-h1184-no/IMAG2700.jpg"></p>
<p><img alt="茄子" src="https://lh4.googleusercontent.com/-Zr1yFDqen_8/VBVQA55xX_I/AAAAAAAFwF4/xTA26D2fLvM/w670-h1184-no/IMAG2642.jpg"></p>
<p><img alt="Banana" src="https://lh5.googleusercontent.com/-EKKKvC4W_w4/VBVQZOBntpI/AAAAAAAGoA4/Ru9uXJ-KUJY/w1834-h1040-no/IMAG2710.jpg"></p>
<p><img alt="Sumo" src="https://lh5.googleusercontent.com/-yd6qNT5Ndu0/VBVQ7ZIiYSI/AAAAAAAGoDI/C677qosNRgY/w1834-h1040-no/IMAG2781.jpg"></p>
<p><img alt="水手服" src="https://lh3.googleusercontent.com/-KJaofUr5SQg/VA7FYjwdxWI/AAAAAAAGoPE/9Nfj4uwZr9g/w1832-h1036-no/IMAG3026.jpg"></p>
<p><img alt="小偷" src="https://lh4.googleusercontent.com/-DXLHUX2JyKU/VBVRJjdUsiI/AAAAAAAFwK4/QgfBKVQGamU/w1834-h1040-no/IMAG2812.jpg"></p>
<p><img alt="老外" src="https://lh4.googleusercontent.com/-GFXyFSOWO7c/VBVP3HMqfrI/AAAAAAAFwFQ/uef30Oc0fww/w670-h1184-no/IMAG2625.jpg"></p>
<p><img alt="馬力歐" src="https://lh3.googleusercontent.com/-CVla1Kia2rw/VBVtnokqYEI/AAAAAAAFyCs/E95V7kj1qvM/w1584-h1184-no/Photo%2B2014-2-23%2B10%2B23%2B52.jpg"></p>
<p><img alt="耶穌" src="https://lh3.googleusercontent.com/-8q890msQZSE/VA-2fhv537I/AAAAAAAFatI/7WIXdF7lndU/w1576-h1184-no/P1000632.JPG"></p>
<p><img alt="米尼" src="https://lh4.googleusercontent.com/-EUY0HBJfwrI/VA7CCdtfQlI/AAAAAAAFWeA/4wjmy7Db8Qk/"></p>
<p><img alt="LEGO" src="https://lh6.googleusercontent.com/-J1-aoBWJSfE/VBjZStD74AI/AAAAAAAGDAQ/o2jN5Hr1WpM/"></p>
<p><img alt="Mario Family" src="https://lh6.googleusercontent.com/-O8rnkvv22-w/VBVuIfjy8FI/AAAAAAAFyEk/8YbvIBEQMCE/w1584-h1184-no/Photo%2B2014-2-23%2B10%2B37%2B20.jpg"></p>
<p><img alt="Rangers" src="https://lh5.googleusercontent.com/-yA9d7k-0Dzc/VBVux4TXuwI/AAAAAAAFyHE/-pbgLZ9_y9E/w1584-h1184-no/Photo%2B2014-2-23%2B11%2B14%2B45.jpg"></p>
<p><img alt="飯團" src="https://lh5.googleusercontent.com/-Wi0DSoEegLc/VBVRrRMWmkI/AAAAAAAFwNg/B4CvDzHiZ0o/w1834-h1040-no/IMAG2953.jpg"></p>
<p><img alt="皮卡丘" src="https://lh5.googleusercontent.com/-pfiHRqmoVq8/VBVR_u2B-SI/AAAAAAAFwPI/4YafmmAikUw/w1834-h1040-no/IMAG3015.jpg"></p>
<p><img alt="鬼" src="https://lh5.googleusercontent.com/-CrgdcBrQPkU/VBVR9z2T3lI/AAAAAAAGoQs/ouaD2f8xDOY/w1832-h1036-no/IMAG3014.jpg"></p>
<p><img alt="日本武士" src="https://lh3.googleusercontent.com/-mPqBtPRx2o4/VBVSP6f-QzI/AAAAAAAFwQY/7sE2kxHaWNY/w1834-h1040-no/IMAG3054.jpg"></p>
<p><img alt="吹Tuba大叔" src="https://lh6.googleusercontent.com/-InAO32K8Tt0/VBVQtwykORI/AAAAAAAGnQo/2Q4K-G1Pszs/w1832-h1036-no/IMAG2749.jpg"></p>
<p><img alt="ET" src="https://lh6.googleusercontent.com/-xnH3tS8JLuA/VBVQ5f2-6BI/AAAAAAAFwJw/aj_jcIqizoE/w884-h1184-no/Photo%2B2014-2-23%2B11%2B08%2B44.jpg"></p>
<h2>補給</h2>
<p>東京馬的補給非常齊全,即使跑在後段班也完全不用擔心會有吃不到東西的問題。</p>
<p><img alt="官方-紅豆麵包" src="https://lh4.googleusercontent.com/-MK2fW4d5OaU/VBVR1xieyPI/AAAAAAAGnRc/GKshTae9bh4/"></p>
<p><img alt="官方-巧克力" src="https://lh4.googleusercontent.com/-rcRVok7gJIk/VBVR0Tus2JI/AAAAAAAGnQ8/6aqRkEShXe0/"></p>
<p><img alt="香蕉" src="https://lh4.googleusercontent.com/-IHii_JE8s5s/VA7DfZM_SgI/AAAAAAAGn14/GZravDuONuo/w1832-h1036-no/IMAG2863.jpg"></p>
<p>{% youtube MPaRrcQ3Ld4 %}</p>
<p><img alt="白酒" src="https://lh3.googleusercontent.com/-11hZAO9oMa0/VBVSZAkakbI/AAAAAAAFwRA/OIpNyIkkSpI/w620-h1096-no/IMAG3070_%E7%99%BD%E9%85%92.jpg"></p>
<p>跑馬還有白酒可以喝 ~</p>
<p><img alt="熱咖啡" src="https://lh6.googleusercontent.com/-98vZ8iesFfM/VBVRxoWpP6I/AAAAAAAFwOA/0pTyBI7vRhY/"></p>
<p>熱咖啡</p>
<p><img alt="蛋糕卷" src="https://lh4.googleusercontent.com/-lKupqiuaLGo/VA7DgtfCavI/AAAAAAAGn1k/ZHJMygxdZ4s/w1832-h1036-no/IMAG2868.jpg"></p>
<p><img alt="Amino Value" src="https://lh4.googleusercontent.com/-frNk3VjygD4/VBVvIHJdLyI/AAAAAAAFyIc/a4ipQZO2fUE/w1584-h1184-no/Photo%2B2014-2-23%2B11%2B35%2B21.jpg">
在國內跑馬界評價很高的運動飲料,大家都叫他橘水。</p>
<p><img alt="草莓" src="https://lh3.googleusercontent.com/-A7KQwXWgDdM/VBVRadl7I9I/AAAAAAAFwMQ/-jmDEYshQOM/w1832-h1036-no/IMAG2888.jpg"></p>
<p><img alt="民眾提供的橘粉" src="https://lh4.googleusercontent.com/-J4Z64koUnvY/VBVQUMOxrII/AAAAAAAGnQQ/HanJZSOXMj8/w1832-h1036-no/IMAG2694.jpg"></p>
<p>在比賽的中後段,沿路開始出現很多民眾提供冷凍、酸痛噴劑。讓我的關節肌肉舒緩很多</p>
<p><img alt="噴劑" src="https://lh4.googleusercontent.com/-OvdgWYwSqlU/VBVSB5N2p-I/AAAAAAAGoQo/WGJRb5XyqKA/w1832-h1036-no/ZOE_0096.jpg"></p>
<p><img alt="母女" src="https://lh5.googleusercontent.com/-veMJgMQjU2g/VBVSFEkCf4I/AAAAAAAGoQ8/hcK7QooTqsQ/w1832-h1036-no/IMAG3020.jpg"></p>
<p><img alt="巧克力棒" src="https://lh5.googleusercontent.com/-0Pgaic6Cn0w/VBVSIT7hzJI/AAAAAAAGoRI/uh6LYt6O2Cw/w1832-h1036-no/IMAG3037.jpg"></p>
<h2>態度</h2>
<p>日本對於舉大型馬拉松賽事的態度真的很讓人佩服,東京馬的賽道就是在東京市區跑一條十字:</p>
<p><img alt="賽道" src="https://lh5.googleusercontent.com/-fI7I6il1Bco/VIsG4qPVZVI/AAAAAAAGoV4/hbVJVsH-gqI/w922-h1096-no/tokyo0.png"></p>
<p>整個市區可以封道,也代表東京市民可以容忍交通的不便,沿路的各個補給站都配置了大量的志工: </p>
<p><img alt="水站" src="https://lh3.googleusercontent.com/-vrI_h_E_yWc/VA7EmT3yJhI/AAAAAAAGoUc/A4LTbylVdc4/w1832-h1036-no/IMAG2968.jpg"></p>
<p><img alt="終點寄物" src="https://lh3.googleusercontent.com/-Y1xVDPSOr-0/VA7GfMtP5bI/AAAAAAAGoRw/boVUGqYw2cs/w1832-h1036-no/IMAG3109.jpg"></p>
<p>地鐵配置了大量的廣告宣傳,讓民眾知道這個活動,以及可能造成的交通不便</p>
<p><img alt="地鐵廣告" src="https://lh3.googleusercontent.com/-cOIxhqhsdjo/VA7GjLm7uAI/AAAAAAAFW1o/mfxAUrib5I4/w1832-h1036-no/IMAG3145.jpg"></p>
<p><img alt="地鐵廣告2" src="https://lh4.googleusercontent.com/-pBETwy4LnE0/VA7Gh4dE_dI/AAAAAAAFW1g/xgQLkgIT0Y0/w670-h1184-no/IMAG3144.jpg"></p>
<p>最後進入終點之後,工作人員親手披上毛巾跟獎牌: </p>
<p><img alt="終點" src="https://lh3.googleusercontent.com/-E-8FfI9OvbA/VBVSeJbcAkI/AAAAAAAFwRY/_VYtJ-t7Hc8/w1584-h1184-no/Photo%2B2014-2-23%2B15%2B34%2B49.jpg"></p>
<p><img alt="獎牌" src="https://lh5.googleusercontent.com/-KwjTescALAA/VBVSgT6wS7I/AAAAAAAFwRg/2ZzxzQlSx8A/w1468-h1096-no/Photo%2B2014-2-23%2B15%2B36%2B06.jpg"></p>
<p>在前一天的 Expo,大會有提供很有用的小冊子,可以讓親友團知道如果預計幾小時完賽的話,幾公里會在那個地鐵站出現,要在那個地鐵站等侯</p>
<p><img alt="手冊" src="https://lh5.googleusercontent.com/-yloAde0A8do/VA7GmI3ZoNI/AAAAAAAGoQg/1IqVyc9V-uY/w1832-h1036-no/IMAG3400.jpg"></p>
<h3>後記</h3>
<p>最後195公尺,果真是最慢長的,因為跟本捨不得進入終點阿</p>
<p><img alt="最後195公尺" src="https://lh6.googleusercontent.com/-mwDFPJiRgos/VBVvltzJEnI/AAAAAAAFyKU/xQRyrKcaQ1Q/w1584-h1184-no/Photo%2B2014-2-23%2B15%2B20%2B06.jpg"></p>
<p><img alt="捨不得進終點" src="https://lh5.googleusercontent.com/-IKBjiWGr_cY/VBVvpKO-ZsI/AAAAAAAFyKk/ftxHl5TwI0I/w1584-h1184-no/Photo%2B2014-2-23%2B15%2B21%2B40.jpg"></p>
<p><img alt="Alvin" src="https://lh5.googleusercontent.com/-EK5qQkIwQp4/VA-2pz7eySI/AAAAAAAFatg/fNbRZ54QEUE/w1576-h1184-no/P1000655.JPG">
跟推抗的T社同事合照</p>
<p>如同跑馬界常流傳的一句話,「跑馬拉松沒有奇蹟,只有累積。」東京馬是我第二個全馬,成績為5小時56分,速度大致上用7分半速來跑,我每個水站/運動飲料站都會停下來,看到有趣的補給也會停下來吃吃喝喝,跟民眾擊掌等等。</p>
<div class="highlight"><pre><span></span><code>距離 大會時間 晶片時間 分段時間 日本時間
5km 00:52:10 (0:36:11) 0:36:11 10:02:10 …</code></pre></div><p>至今在台灣參加了十幾場的路跑賽事。但是讓自己衝擊最深刻的還是今年二月到日本參加的東京馬拉松,參加馬拉松的心態其實也不是想跟誰拼個輸贏,大多是想感受現場的氣氛。而在東京街頭,你會很懷疑是從那邊冒出那麼多的民眾。全線42公里,真的不跨張,全線都站滿了應援團的民眾,就算只是剛從起點出發,都會有種似乎快到終點,接受英雄式的歡呼的感覺。所以即使是只有6度左右的寒冷天氣,還是讓人一開始起跑就熱血沸騰!</p>
<p><img alt="起跑" src="https://lh4.googleusercontent.com/-REr3_643i04/VA7A3xQd0cI/AAAAAAAFWX4/CYmhF14naEQ/w1832-h1036-no/IMAG2655.jpg"></p>
<p><img alt="沿線民眾" src="https://lh6.googleusercontent.com/-czXgKzsukAY/VBVQJ-0kS1I/AAAAAAAGnQE/S4DXAcOT5JI/w1832-h1036-no/IMAG2670.jpg"></p>
<p><img alt="沿線民眾2" src="https://lh3.googleusercontent.com/-Qgs4lQuKhfs/VBVQMK7qiUI/AAAAAAAFwGo/nagB30qMo6c/w1584-h1184-no/Photo%2B2014-2-23%2B9%2B29%2B35.jpg"></p>
<p><img alt="東京鐵塔" src="https://lh5.googleusercontent.com/ztiCa8W7Y96IM3bJ4UQ4ITG_ePmXKM8UfNs4X7a5bCqp=w670-h1184-no"></p>
<p>總結整個東京馬的三大重點就是: <strong>Cosplay</strong>,<strong>補給</strong>,<strong>日本人對於賽事的態度</strong></p>
<h2>Cosplay</h2>
<p>東京馬的一大亮點就是超超超多有趣的Cosplay。日本真的是Cosplay大國,除了跑者會打扮成各種人物之外,路邊的應援團也有很多人都精心打扮。即使是穿著簡單的蕃茄,也都會受到民眾熱情的加油 「Tomedo 頑張って」。發現日本正在流行一款吉祥物船梨精(ふなっしー),是個讓很多小朋友政太,蘿莉為之瘋狂的水果。Cosplay台灣人也沒有缺席,三太子也一整個超吸晴的。熱情的民眾,讓人敞開心胸,這輩子也從來沒跟那麼多人自拍過,整個玩開了。</p>
<p><img alt="三太子" src="https://lh6.googleusercontent.com/-7PbYbNvfkrw/VBVP9ckfo2I/AAAAAAAFwFo/uL7GbrYS99k/w670-h1184-no/IMAG2641.jpg"></p>
<p><img alt="ふなっしー" src="https://lh3.googleusercontent.com/-2KJP778JdK4/VBVQVqmtwOI/AAAAAAAFwHQ/sI9gs6eflC4/w670-h1184-no/IMAG2700.jpg"></p>
<p><img alt="茄子" src="https://lh4.googleusercontent.com/-Zr1yFDqen_8/VBVQA55xX_I/AAAAAAAFwF4/xTA26D2fLvM/w670-h1184-no/IMAG2642.jpg"></p>
<p><img alt="Banana" src="https://lh5.googleusercontent.com/-EKKKvC4W_w4/VBVQZOBntpI/AAAAAAAGoA4/Ru9uXJ-KUJY/w1834-h1040-no/IMAG2710.jpg"></p>
<p><img alt="Sumo" src="https://lh5.googleusercontent.com/-yd6qNT5Ndu0/VBVQ7ZIiYSI/AAAAAAAGoDI/C677qosNRgY/w1834-h1040-no/IMAG2781.jpg"></p>
<p><img alt="水手服" src="https://lh3.googleusercontent.com/-KJaofUr5SQg/VA7FYjwdxWI/AAAAAAAGoPE/9Nfj4uwZr9g/w1832-h1036-no/IMAG3026.jpg"></p>
<p><img alt="小偷" src="https://lh4.googleusercontent.com/-DXLHUX2JyKU/VBVRJjdUsiI/AAAAAAAFwK4/QgfBKVQGamU/w1834-h1040-no/IMAG2812.jpg"></p>
<p><img alt="老外" src="https://lh4.googleusercontent.com/-GFXyFSOWO7c/VBVP3HMqfrI/AAAAAAAFwFQ/uef30Oc0fww/w670-h1184-no/IMAG2625.jpg"></p>
<p><img alt="馬力歐" src="https://lh3.googleusercontent.com/-CVla1Kia2rw/VBVtnokqYEI/AAAAAAAFyCs/E95V7kj1qvM/w1584-h1184-no/Photo%2B2014-2-23%2B10%2B23%2B52.jpg"></p>
<p><img alt="耶穌" src="https://lh3.googleusercontent.com/-8q890msQZSE/VA-2fhv537I/AAAAAAAFatI/7WIXdF7lndU/w1576-h1184-no/P1000632.JPG"></p>
<p><img alt="米尼" src="https://lh4.googleusercontent.com/-EUY0HBJfwrI/VA7CCdtfQlI/AAAAAAAFWeA/4wjmy7Db8Qk/"></p>
<p><img alt="LEGO" src="https://lh6.googleusercontent.com/-J1-aoBWJSfE/VBjZStD74AI/AAAAAAAGDAQ/o2jN5Hr1WpM/"></p>
<p><img alt="Mario Family" src="https://lh6.googleusercontent.com/-O8rnkvv22-w/VBVuIfjy8FI/AAAAAAAFyEk/8YbvIBEQMCE/w1584-h1184-no/Photo%2B2014-2-23%2B10%2B37%2B20.jpg"></p>
<p><img alt="Rangers" src="https://lh5.googleusercontent.com/-yA9d7k-0Dzc/VBVux4TXuwI/AAAAAAAFyHE/-pbgLZ9_y9E/w1584-h1184-no/Photo%2B2014-2-23%2B11%2B14%2B45.jpg"></p>
<p><img alt="飯團" src="https://lh5.googleusercontent.com/-Wi0DSoEegLc/VBVRrRMWmkI/AAAAAAAFwNg/B4CvDzHiZ0o/w1834-h1040-no/IMAG2953.jpg"></p>
<p><img alt="皮卡丘" src="https://lh5.googleusercontent.com/-pfiHRqmoVq8/VBVR_u2B-SI/AAAAAAAFwPI/4YafmmAikUw/w1834-h1040-no/IMAG3015.jpg"></p>
<p><img alt="鬼" src="https://lh5.googleusercontent.com/-CrgdcBrQPkU/VBVR9z2T3lI/AAAAAAAGoQs/ouaD2f8xDOY/w1832-h1036-no/IMAG3014.jpg"></p>
<p><img alt="日本武士" src="https://lh3.googleusercontent.com/-mPqBtPRx2o4/VBVSP6f-QzI/AAAAAAAFwQY/7sE2kxHaWNY/w1834-h1040-no/IMAG3054.jpg"></p>
<p><img alt="吹Tuba大叔" src="https://lh6.googleusercontent.com/-InAO32K8Tt0/VBVQtwykORI/AAAAAAAGnQo/2Q4K-G1Pszs/w1832-h1036-no/IMAG2749.jpg"></p>
<p><img alt="ET" src="https://lh6.googleusercontent.com/-xnH3tS8JLuA/VBVQ5f2-6BI/AAAAAAAFwJw/aj_jcIqizoE/w884-h1184-no/Photo%2B2014-2-23%2B11%2B08%2B44.jpg"></p>
<h2>補給</h2>
<p>東京馬的補給非常齊全,即使跑在後段班也完全不用擔心會有吃不到東西的問題。</p>
<p><img alt="官方-紅豆麵包" src="https://lh4.googleusercontent.com/-MK2fW4d5OaU/VBVR1xieyPI/AAAAAAAGnRc/GKshTae9bh4/"></p>
<p><img alt="官方-巧克力" src="https://lh4.googleusercontent.com/-rcRVok7gJIk/VBVR0Tus2JI/AAAAAAAGnQ8/6aqRkEShXe0/"></p>
<p><img alt="香蕉" src="https://lh4.googleusercontent.com/-IHii_JE8s5s/VA7DfZM_SgI/AAAAAAAGn14/GZravDuONuo/w1832-h1036-no/IMAG2863.jpg"></p>
<p>{% youtube MPaRrcQ3Ld4 %}</p>
<p><img alt="白酒" src="https://lh3.googleusercontent.com/-11hZAO9oMa0/VBVSZAkakbI/AAAAAAAFwRA/OIpNyIkkSpI/w620-h1096-no/IMAG3070_%E7%99%BD%E9%85%92.jpg"></p>
<p>跑馬還有白酒可以喝 ~</p>
<p><img alt="熱咖啡" src="https://lh6.googleusercontent.com/-98vZ8iesFfM/VBVRxoWpP6I/AAAAAAAFwOA/0pTyBI7vRhY/"></p>
<p>熱咖啡</p>
<p><img alt="蛋糕卷" src="https://lh4.googleusercontent.com/-lKupqiuaLGo/VA7DgtfCavI/AAAAAAAGn1k/ZHJMygxdZ4s/w1832-h1036-no/IMAG2868.jpg"></p>
<p><img alt="Amino Value" src="https://lh4.googleusercontent.com/-frNk3VjygD4/VBVvIHJdLyI/AAAAAAAFyIc/a4ipQZO2fUE/w1584-h1184-no/Photo%2B2014-2-23%2B11%2B35%2B21.jpg">
在國內跑馬界評價很高的運動飲料,大家都叫他橘水。</p>
<p><img alt="草莓" src="https://lh3.googleusercontent.com/-A7KQwXWgDdM/VBVRadl7I9I/AAAAAAAFwMQ/-jmDEYshQOM/w1832-h1036-no/IMAG2888.jpg"></p>
<p><img alt="民眾提供的橘粉" src="https://lh4.googleusercontent.com/-J4Z64koUnvY/VBVQUMOxrII/AAAAAAAGnQQ/HanJZSOXMj8/w1832-h1036-no/IMAG2694.jpg"></p>
<p>在比賽的中後段,沿路開始出現很多民眾提供冷凍、酸痛噴劑。讓我的關節肌肉舒緩很多</p>
<p><img alt="噴劑" src="https://lh4.googleusercontent.com/-OvdgWYwSqlU/VBVSB5N2p-I/AAAAAAAGoQo/WGJRb5XyqKA/w1832-h1036-no/ZOE_0096.jpg"></p>
<p><img alt="母女" src="https://lh5.googleusercontent.com/-veMJgMQjU2g/VBVSFEkCf4I/AAAAAAAGoQ8/hcK7QooTqsQ/w1832-h1036-no/IMAG3020.jpg"></p>
<p><img alt="巧克力棒" src="https://lh5.googleusercontent.com/-0Pgaic6Cn0w/VBVSIT7hzJI/AAAAAAAGoRI/uh6LYt6O2Cw/w1832-h1036-no/IMAG3037.jpg"></p>
<h2>態度</h2>
<p>日本對於舉大型馬拉松賽事的態度真的很讓人佩服,東京馬的賽道就是在東京市區跑一條十字:</p>
<p><img alt="賽道" src="https://lh5.googleusercontent.com/-fI7I6il1Bco/VIsG4qPVZVI/AAAAAAAGoV4/hbVJVsH-gqI/w922-h1096-no/tokyo0.png"></p>
<p>整個市區可以封道,也代表東京市民可以容忍交通的不便,沿路的各個補給站都配置了大量的志工: </p>
<p><img alt="水站" src="https://lh3.googleusercontent.com/-vrI_h_E_yWc/VA7EmT3yJhI/AAAAAAAGoUc/A4LTbylVdc4/w1832-h1036-no/IMAG2968.jpg"></p>
<p><img alt="終點寄物" src="https://lh3.googleusercontent.com/-Y1xVDPSOr-0/VA7GfMtP5bI/AAAAAAAGoRw/boVUGqYw2cs/w1832-h1036-no/IMAG3109.jpg"></p>
<p>地鐵配置了大量的廣告宣傳,讓民眾知道這個活動,以及可能造成的交通不便</p>
<p><img alt="地鐵廣告" src="https://lh3.googleusercontent.com/-cOIxhqhsdjo/VA7GjLm7uAI/AAAAAAAFW1o/mfxAUrib5I4/w1832-h1036-no/IMAG3145.jpg"></p>
<p><img alt="地鐵廣告2" src="https://lh4.googleusercontent.com/-pBETwy4LnE0/VA7Gh4dE_dI/AAAAAAAFW1g/xgQLkgIT0Y0/w670-h1184-no/IMAG3144.jpg"></p>
<p>最後進入終點之後,工作人員親手披上毛巾跟獎牌: </p>
<p><img alt="終點" src="https://lh3.googleusercontent.com/-E-8FfI9OvbA/VBVSeJbcAkI/AAAAAAAFwRY/_VYtJ-t7Hc8/w1584-h1184-no/Photo%2B2014-2-23%2B15%2B34%2B49.jpg"></p>
<p><img alt="獎牌" src="https://lh5.googleusercontent.com/-KwjTescALAA/VBVSgT6wS7I/AAAAAAAFwRg/2ZzxzQlSx8A/w1468-h1096-no/Photo%2B2014-2-23%2B15%2B36%2B06.jpg"></p>
<p>在前一天的 Expo,大會有提供很有用的小冊子,可以讓親友團知道如果預計幾小時完賽的話,幾公里會在那個地鐵站出現,要在那個地鐵站等侯</p>
<p><img alt="手冊" src="https://lh5.googleusercontent.com/-yloAde0A8do/VA7GmI3ZoNI/AAAAAAAGoQg/1IqVyc9V-uY/w1832-h1036-no/IMAG3400.jpg"></p>
<h3>後記</h3>
<p>最後195公尺,果真是最慢長的,因為跟本捨不得進入終點阿</p>
<p><img alt="最後195公尺" src="https://lh6.googleusercontent.com/-mwDFPJiRgos/VBVvltzJEnI/AAAAAAAFyKU/xQRyrKcaQ1Q/w1584-h1184-no/Photo%2B2014-2-23%2B15%2B20%2B06.jpg"></p>
<p><img alt="捨不得進終點" src="https://lh5.googleusercontent.com/-IKBjiWGr_cY/VBVvpKO-ZsI/AAAAAAAFyKk/ftxHl5TwI0I/w1584-h1184-no/Photo%2B2014-2-23%2B15%2B21%2B40.jpg"></p>
<p><img alt="Alvin" src="https://lh5.googleusercontent.com/-EK5qQkIwQp4/VA-2pz7eySI/AAAAAAAFatg/fNbRZ54QEUE/w1576-h1184-no/P1000655.JPG">
跟推抗的T社同事合照</p>
<p>如同跑馬界常流傳的一句話,「跑馬拉松沒有奇蹟,只有累積。」東京馬是我第二個全馬,成績為5小時56分,速度大致上用7分半速來跑,我每個水站/運動飲料站都會停下來,看到有趣的補給也會停下來吃吃喝喝,跟民眾擊掌等等。</p>
<div class="highlight"><pre><span></span><code>距離 大會時間 晶片時間 分段時間 日本時間
5km 00:52:10 (0:36:11) 0:36:11 10:02:10
10km 01:35:16 (1:19:17) 0:43:06 10:45:16
15km 02:18:26 (2:02:27) 0:43:10 11:28:26
20km 02:56:44 (2:40:45) 0:38:18 12:06:44
25km 03:40:04 (3:24:05) 0:43:20 12:50:04
30km 04:23:31 (4:07:32) 0:43:27 13:33:31
35km 05:07:59 (4:52:00) 0:44:28 14:17:59
40km 05:55:17 (5:39:18) 0:47:18 15:05:17
Finish 06:12:03 (5:56:04) 0:16:46 15:22:03
</code></pre></div>
<p>跑完步當然就是要吃個慶功宴來做個 Happy Ending </p>
<p><img alt="生魚片" src="https://lh4.googleusercontent.com/-2yp0tTlHVKM/VBeV3CweqxI/AAAAAAAF8Tk/-gs_-iQcCsc/w670-h1184-no/IMAG3140.jpg"></p>使用 south 來做 Django database migration2014-08-16T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-08-16:/django-south/<p>一般在 Django 底下更動 model 的時侯,必須使用 <code>syncdb</code> 這個指令,把修改的 model 同步到 database 之中,但是有個限制,就是只有新的 model 才會被更新,已經存在的 model 就不會更動,此時就需要<code>south</code>的幫忙。在 django 1.7 之後,這個 library 正式被整進到 django 之中。不過目前我手頭上的專案還是以 1.6 為主,所以還是要筆記一下。</p>
<h2>初始化 south</h2>
<p>安裝完 south 之後,第一次先執行 <code>syncdb</code> 把 south 相關的<code>south_migrationhistory</code> 新增到資料庫中。</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>./manage.py syncdb
</code></pre></div>
<h2>開始 migration</h2>
<p>首先要介紹的是 <code>schemamigration <APP_NAME> --initial</code>,這個指令會在 app 資料夾下面產生一個 <code>migrations</code> 資料夾。如果是第一次執行的話,裡面的檔名會是 0001_initial.py 開頭,裡面會記錄如何從無到有,把資料表建立起來。</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">forwards</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">orm</span><span class="p">):</span>
<span class="c1"># Adding model 'UserModel'</span>
<span class="n">db</span><span class="o">.</span><span class="n">create_table</span><span class="p">(</span><span class="sa">u</span><span class="s1">'dusers_dmodel'</span><span class="p">,</span> <span class="p">(</span>
<span class="p">(</span><span class="sa">u</span><span class="s1">'id'</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">gf</span><span class="p">(</span><span class="s1">'django.db.models.fields.AutoField'</span><span class="p">)(</span><span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)),</span>
</code></pre></div>
<p>此時可以執行 syncdb 做一下確認</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>python manage.py syncdb …</code></pre></div><p>一般在 Django 底下更動 model 的時侯,必須使用 <code>syncdb</code> 這個指令,把修改的 model 同步到 database 之中,但是有個限制,就是只有新的 model 才會被更新,已經存在的 model 就不會更動,此時就需要<code>south</code>的幫忙。在 django 1.7 之後,這個 library 正式被整進到 django 之中。不過目前我手頭上的專案還是以 1.6 為主,所以還是要筆記一下。</p>
<h2>初始化 south</h2>
<p>安裝完 south 之後,第一次先執行 <code>syncdb</code> 把 south 相關的<code>south_migrationhistory</code> 新增到資料庫中。</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>./manage.py syncdb
</code></pre></div>
<h2>開始 migration</h2>
<p>首先要介紹的是 <code>schemamigration <APP_NAME> --initial</code>,這個指令會在 app 資料夾下面產生一個 <code>migrations</code> 資料夾。如果是第一次執行的話,裡面的檔名會是 0001_initial.py 開頭,裡面會記錄如何從無到有,把資料表建立起來。</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">forwards</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">orm</span><span class="p">):</span>
<span class="c1"># Adding model 'UserModel'</span>
<span class="n">db</span><span class="o">.</span><span class="n">create_table</span><span class="p">(</span><span class="sa">u</span><span class="s1">'dusers_dmodel'</span><span class="p">,</span> <span class="p">(</span>
<span class="p">(</span><span class="sa">u</span><span class="s1">'id'</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">gf</span><span class="p">(</span><span class="s1">'django.db.models.fields.AutoField'</span><span class="p">)(</span><span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">)),</span>
</code></pre></div>
<p>此時可以執行 syncdb 做一下確認</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>python manage.py syncdb
<span class="go">....</span>
<span class="go">Synced:</span>
<span class="go"> > django.contrib.admin</span>
<span class="go">....</span>
<span class="go">Not synced (use migrations):</span>
<span class="go"> - southtut</span>
<span class="gp gp-VirtualEnv">(use ./manage.py migrate to migrate these)</span>
</code></pre></div>
<p>就會發現 app(southtut) 會放到 Not synced。也就是說從此 syncdb 這個指令就不會再去管 southtut 這個 app 了。此時可能會有兩個情況,如果之前已經先執行過 syncdb,而 database 跟 model 已經完全一致的情況下,我們就必須額外跟 south 說,我們已經同步好了,你不需要幫我們做 migration。這時需要用<code>--fake</code>這個指令。來告訴 south,目前我們的 db 是在 migrations 資料夾的那一個版本。</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>python manage.py migrate rango <span class="m">0001</span> --fake
</code></pre></div>
<p>另一個情況是我們沒有對這個 app 同步過,這時就不能用 syncdb 來做,要改用 </p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>python manage.py migrate rango
</code></pre></div>
<p>這時在 south_migrationhistory 這個資料表就會記錄目前這個 app 已經同步到那一個版本</p>
<p>id | app_name | migration | applied
---+------------+------------------+-------------------------------
1 | dusers | 0001_initial | 2014-08-15 10:24:45.694512+08</p>
<p>所以第一次使用的時侯是用 <code>--initial</code>,接下來只要有改變,就可以用<code>--auto</code>。在 model 有修改之後,執行以下指令來建立跟上一個版本的差異資訊到 rango/migrations 資料夾中。</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>./manage.py schemamigration rango --auto
</code></pre></div>
<p>過程當中會詢問你如果有新的欄位,是否要填入一預設值。</p>
<p>最後再使用<code>migrate <APP_NAME></code>,正式修改資料庫schema,並把新的資料填入資料庫:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>./manage.py migrate <span class="o">[</span>APP_NAME<span class="o">]</span>
</code></pre></div>
<h2>回復到之前的版本</h2>
<div class="highlight"><pre><span></span><code>$ python manage.py migrate photo <span class="m">0002</span>
</code></pre></div>
<h2>查看目前那些版本還沒有做 migrate</h2>
<div class="highlight"><pre><span></span><code>$ python manage.py migrate --list
</code></pre></div>
<h2>備註</h2>
<p>如果發生 django.db.utils.DatabaseError: table "XXXXX" already exists,代表目前資料庫的 schema 跟 south_migrationhistory 裡面所記錄的不同。</p>
<p>可以執行:</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>python manage.py migrate dodo --fake
</code></pre></div>
<p>來告訴 south 說,目前資料庫的狀態已經是 migration 資料夾裡面最新的版本了,不需要替我做 migration 的動作。</p>使用 Pyenv 管理多個 Python 版本2014-07-08T00:00:00+08:002021-06-22T08:49:09+08:00Cody Liutag:blog.codylab.com,2014-07-08:/python-pyenv-management/<p><a href="https://github.com/yyuu/pyenv">pyenv</a> 是一個 Python 版本管理器,也可以安裝 <a href="https://github.com/yyuu/pyenv-virtualenv">pyenv-virtualenv</a> 達來支援 virtualenv 的功能。</p>
<h2>安裝 pyenv 和 pyenv-virtualenv</h2>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>git clone https://github.com/yyuu/pyenv.git ~/.pyenv
<span class="gp">$ </span>git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
<span class="gp">$ </span>sudo pip install virtualenv
</code></pre></div>
<p>In Ubuntu:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm
</code></pre></div>
<p>Or, 使用<a href="https://goo.gl/uiUZgk">yyuu/pyenv-installer</a></p>
<p>把下列加到 ~/.bashrc</p>
<div class="highlight"><pre><span></span><code><span class="go">export PYENV_ROOT="$HOME/.pyenv"</span>
<span class="go">export PATH="$PYENV_ROOT/bin:$PATH"</span>
<span class="go">eval "$(pyenv init -)"</span>
</code></pre></div>
<h2>安裝其它版本的 Python</h2>
<p>查看可供安裝的 python 版本</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>pyenv install -l
<span class="go">...</span>
<span class="go">3.4.0</span>
<span class="go">3.4.1</span>
<span class="go">3.4-dev</span>
<span class="go">...</span>
</code></pre></div>
<p>如果想要裝 3.4.1 的話,就使用<code>pyenv install</code></p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>pyenv install <span class="m">3</span>.4.1 …</code></pre></div><p><a href="https://github.com/yyuu/pyenv">pyenv</a> 是一個 Python 版本管理器,也可以安裝 <a href="https://github.com/yyuu/pyenv-virtualenv">pyenv-virtualenv</a> 達來支援 virtualenv 的功能。</p>
<h2>安裝 pyenv 和 pyenv-virtualenv</h2>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>git clone https://github.com/yyuu/pyenv.git ~/.pyenv
<span class="gp">$ </span>git clone https://github.com/yyuu/pyenv-virtualenv.git ~/.pyenv/plugins/pyenv-virtualenv
<span class="gp">$ </span>sudo pip install virtualenv
</code></pre></div>
<p>In Ubuntu:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm
</code></pre></div>
<p>Or, 使用<a href="https://goo.gl/uiUZgk">yyuu/pyenv-installer</a></p>
<p>把下列加到 ~/.bashrc</p>
<div class="highlight"><pre><span></span><code><span class="go">export PYENV_ROOT="$HOME/.pyenv"</span>
<span class="go">export PATH="$PYENV_ROOT/bin:$PATH"</span>
<span class="go">eval "$(pyenv init -)"</span>
</code></pre></div>
<h2>安裝其它版本的 Python</h2>
<p>查看可供安裝的 python 版本</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>pyenv install -l
<span class="go">...</span>
<span class="go">3.4.0</span>
<span class="go">3.4.1</span>
<span class="go">3.4-dev</span>
<span class="go">...</span>
</code></pre></div>
<p>如果想要裝 3.4.1 的話,就使用<code>pyenv install</code></p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>pyenv install <span class="m">3</span>.4.1
</code></pre></div>
<h2>查看已安裝的 Python 版本</h2>
<p>先用<code>pyenv versions</code> 查看目前已安裝 Python 的版本</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>pyenv versions
<span class="go">* system</span>
<span class="go"> 3.4.1</span>
</code></pre></div>
<p>顯示目前預設是 system, 而可以切換到 3.4.1 的版本</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>pyenv global <version> <span class="c1"># set global python version</span>
<span class="gp">$ </span>pyenv <span class="nb">local</span> <version> <span class="c1">#在當前目錄創建一個.python-version,以後進入這個目錄自動切換爲該版本</span>
<span class="gp">$ </span>pyenv shell <version> <span class="c1">#在當前shell的session裏啓用某個Python版本,優先級高於global,local</span>
</code></pre></div>
<h2>查看目前使用的 python 版本</h2>
<p>pyenv 可以設定三種 scope,分別是 global, local 和 shell。shell 是只有當次登入 shell 有效,而 global 則是有修改系統 python 版本的效果, 我最常用的是 local,會更改當下目錄使用的 python 版本。</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>pyenv global
<span class="gp">$ </span>pyenv <span class="nb">local</span>
<span class="gp">$ </span>pyenv shell
</code></pre></div>
<h2>使用 pyenv-virtualenv</h2>
<p>新增一個 virtualenv <code>uber</code></p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>pyenv virtualenv <span class="m">3</span>.4.1 uber
</code></pre></div>
<p>此時會發現多了一個 python</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>pyenv versions
<span class="go"> system</span>
<span class="go"> 3.4.1</span>
<span class="go">* uber (set by /home/cwliu/Downloads/uber/.python-version)</span>
</code></pre></div>
<p>在此目錄使用該 virtualenv</p>
<div class="highlight"><pre><span></span><code><span class="gp">$ </span>pyenv <span class="nb">local</span> uber
</code></pre></div>Install Juniper on Ubuntu 14.042014-06-20T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-06-20:/juniper/<p>On Ubuntu 14.04, install Juniper VPN</p>
<div class="highlight"><pre><span></span><code>$ update-alternatives --display java
</code></pre></div>
<h2>Requirement</h2>
<div class="highlight"><pre><span></span><code><span class="mf">64</span> <span class="n">bit</span> <span class="n">Mozilla</span> <span class="n">Firefox</span> <span class="n">browser</span> <span class="n">is</span> <span class="n">installed</span>
</code></pre></div>
<h2>First, install the 64bit jre/jdk and icedtea</h2>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install openjdk-7-jre icedtea-7-plugin
</code></pre></div>
<h2>Second, install the 32bit jre</h2>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install openjdk-7-jre:i386
</code></pre></div>
<h2>link update-alternatives to /usr/sbin/</h2>
<p>juniper use it in that folder. </p>
<div class="highlight"><pre><span></span><code>$ sudo ln -s /usr/bin/update-alternatives /usr/sbin/
</code></pre></div>日本東京皇居慢跑攻略2014-05-21T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-05-21:/running-raffine-tokyo/<p>今年二月參加了2014日本東京馬拉松,比賽的前一天我到了人稱慢跑天堂的「皇居」,跑了5公里當作是賽前練習。在東京都市叢林裡面能有這一大塊綠地真是難得。而在日本皇居週邊,有不少開設給跑者使用的"Runner station"。跑前可以寄物,跑完可以洗澡,也可以租借衣鞋。所以即使突然心血來潮想到,只要帶錢,二手空空也可以很方便的體驗在皇居慢跑。</p>
<p><img alt="cover" src="http://i.imgur.com/Yg0hK3S.jpg">
行前我花了一些時間找了皇居附近的跑站,最後選擇日比谷附近的<a href="http://www.raffine-rs.com/about/hibiya/index.html">Raffine Running Sytle</a>。這間分店很新,是2014年1月才剛開幕的,而且收費相較於其它跑站,算是比較便宜的,但是設備服務很好,是一間CP值很高的跑站。</p>
<p><img alt="door" src="http://i.imgur.com/ezYHidn.jpg"> <br>
Raffine 在地鐵的日比谷站 A5 出口,走地下通道就可以直達。基本收費方式只要一個銅板價: 500日元,對於觀光客而言,其實很便宜。反正久久來一次,而且跑完步可以洗澡。不用回飯店就可以繼續之後的行程。</p>
<p>一開始需要填寫一張會員表格,包含基本的個人姓名、連絡方式等等。之後他就會給你會員卡跟寄物櫃鑰匙。另外,店內也有各種尺寸的跑鞋、跑衣褲可以租借。</p>
<p><img alt="coin-machine" src="http://i.imgur.com/wiPwqox.jpg"> <br>
租借毛巾,跑衣的自動販賣機,日本人真的超會用自動販賣機,什麼都有</p>
<p><img alt="rental-shoes" src="http://i.imgur.com/kAhdFG7.jpg"> <br>
租鞋子100日元。因為我們是來跑東京馬拉松的,所以衣鞋毛巾都有自備,所以換完衣服之後,就準備出發去跑步囉!</p>
<p><img alt="650m" src="http://i.imgur.com/2j5Boao.jpg"> <br>
從跑站到皇居大約是650公尺,出來之後陸續看到其它日本民眾也要去跑步。</p>
<p><img alt="warm-up" src="http://i.imgur.com/yzqt2Zr.jpg"> <br>
等紅綠燈的時間,做做暖身運動,</p>
<p>不曉得是平常人就那麼多,還是隔天就是日本東京馬拉松大賽的關係,可以看到很多人在皇居跑步,但也不至於到壅擠的程度。每個人都跑超快的,歐巴桑也是。跑皇居的路線一圈大約是5公里左右:</p>
<p><img alt="route" src="http://i.imgur.com/AxpLc8Y.png"> </p>
<p>至於路線,因為跑的人很多,基本上就是跟著別人後面跑就是了,</p>
<p><img alt="view" src="https://lh6.googleusercontent.com/-7h90tMnwtSA/U2hHjOpe3nI/AAAAAAAFLog/x0fjOEUfXVU/w320-h566-no/IMAG2409.jpg">
<img alt="view2" src="https://lh5.googleusercontent.com/-DZJta-WxM-g/U2hHn5yJN5I/AAAAAAAFLqA/2zdGBaULHQg/w995-h563-no/IMAG2424.jpg">
<img alt="view3" src="https://lh6.googleusercontent.com/-O80EdagdI2E/U2hHpPvF0jI/AAAAAAAFLqw/255I0qPLPd0/w995-h563-no/IMAG2426.jpg">
<img alt="view4" src="https://lh3.googleusercontent.com/-QLnr7y6Hd3o/U2hHq-GXTFI/AAAAAAAFLrE/EoJX-JykIbY/w995-h563-no/IMAG2432.jpg">
<img alt="view5" src="https://lh4.googleusercontent.com/-gwKWLrpVBxE/U2hHsZeW7gI/AAAAAAAFLrk/UAXxRA9jZBw/w995-h563-no/IMAG2438.jpg">
<img alt="景-護程河" src="https://lh4.googleusercontent.com/-wkzxURKUEy0/U2hHimntTiI/AAAAAAAFLoU/W7lQKQhd0_4/w995-h563-no/IMAG2408.jpg"></p>
<p><img alt="back" src="https://lh3.googleusercontent.com/-kyttUzTSKkA/U2hH2JPypkI/AAAAAAAFLuo/tCDGwrqcyZc/w995-h563-no/IMAG2468.jpg"> <br>
跑完5公里之後回到跑站,洗澡</p>
<p><img alt="sink" src="https://lh3.googleusercontent.com/-gqJ0H_El8MU/U2hH44RZyMI/AAAAAAAFLvo/xqdCK_pwo2k/w995-h563-no/bathroom2.jpg"></p>
<p><img alt="spin-dryer" src="https://lh4.googleusercontent.com/9Ez4_y83aV6KsvBPJZkSBgF2LVC_FW5uYfy-l2JcePQN=w320-h566-no"> <br>
很貼心的提供脫水機,我就有把衣服先用清水沖過再脫水,避免帶一整天會臭掉</p>
<p><img alt="shower" src="https://lh5.googleusercontent.com/-nNFRPOxt-YE/U2hHg712U4I/AAAAAAAFLns/aZJbWvQ1cDo/w320-h566-no/IMAG2402.jpg"> <br>
<img alt="shower" src="https://lh5.googleusercontent.com/-JUCEMXRH80M/U2hH5HM_U7I/AAAAAAAFLvk/EHyPT5iKJv0/w320-h566-no/bathroom3.jpg"> </p>
<p>大約有十間淋浴間,裡面有供應洗髮精,沐浴乳。 沐浴乳還是那種慕斯的那種,很讚。自助旅行,最有趣的就是可以安排自己有興趣,而一般觀光客不會走的行程。關於皇居跑站,中文的資訊比較少,這篇筆記希望可以有助於之後到日本玩慢跑的旅人們。</p>
<h3>店家資訊</h3>
<ul>
<li><a href="http://www.raffine-rs.com/">Raffine Running Style</a></li>
<li>東京都千代田区有楽町1-5-2 東宝ツインタワービルB1F</li>
<li>TEL: 03-6206-1391</li>
<li>東京メトロ各線・都営地下鉄日比谷駅A5出口直結</li>
<li>JR・東京メトロ有楽町駅より3分 / 東京メトロ丸ノ内線銀座駅より3分 / 東京メトロ銀座線銀座駅より5分</li>
</ul>SSH Tunnel2014-05-09T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-05-09:/ssh-port-forwarding/<p>使 ssh 遠端連線的人很多, 但是 ssh 這個指令其實還有一些很有趣的tunnel用法,可以讓你擺脫一些限制。這邊稍微筆記一下:</p>
<h2>Local port forwarding</h2>
<p>在本地端開一個 port,然後 remote machine 會把封包轉送到指定的位置:</p>
<div class="highlight"><pre><span></span><code>ssh -L <local_port>:<target_host>:<target_port> remote_user@remote_host
</code></pre></div>
<p>例如本地端防火牆只有開 <code>22</code> port, 而封鎖了<code>8080</code> port, 此時可以透過 local port forward 的方式,達到連線到遠端 8080 port。</p>
<div class="highlight"><pre><span></span><code>ssh -L <span class="m">1234</span>:localhost:8080 cwliu@118.100.100.1
</code></pre></div>
<p>這時連到 localhost:1234,就相當於連線到 118.100.100.1:8080,避開防火牆的效果</p>
<!--
ssh -L 1234:proxy.ntu.edu.tw:3128 name@xxx.ntu.edu.tw
-->
<h2>Remote port forwarding (Reverse SSH)</h2>
<p>這邊的<code>-R</code>代表的是 remote 之意,直接舉個例子</p>
<div class="highlight"><pre><span></span><code>ssh -R <span class="m">5900</span>:localhost:22 guest@remote-pc
</code></pre></div>
<p>在遠端 <code>remote-pc</code> 會開一個 5900 port,其流量會導到 localhost 的 22 port。實際的應用是當 local machine 沒有固定 IP 的時侯,可以先建立好此 ssh 連線。就可以讓遠端機器透過 localhost:5900 直接連線回local。</p>
<h2>SOCKS …</h2><p>使 ssh 遠端連線的人很多, 但是 ssh 這個指令其實還有一些很有趣的tunnel用法,可以讓你擺脫一些限制。這邊稍微筆記一下:</p>
<h2>Local port forwarding</h2>
<p>在本地端開一個 port,然後 remote machine 會把封包轉送到指定的位置:</p>
<div class="highlight"><pre><span></span><code>ssh -L <local_port>:<target_host>:<target_port> remote_user@remote_host
</code></pre></div>
<p>例如本地端防火牆只有開 <code>22</code> port, 而封鎖了<code>8080</code> port, 此時可以透過 local port forward 的方式,達到連線到遠端 8080 port。</p>
<div class="highlight"><pre><span></span><code>ssh -L <span class="m">1234</span>:localhost:8080 cwliu@118.100.100.1
</code></pre></div>
<p>這時連到 localhost:1234,就相當於連線到 118.100.100.1:8080,避開防火牆的效果</p>
<!--
ssh -L 1234:proxy.ntu.edu.tw:3128 name@xxx.ntu.edu.tw
-->
<h2>Remote port forwarding (Reverse SSH)</h2>
<p>這邊的<code>-R</code>代表的是 remote 之意,直接舉個例子</p>
<div class="highlight"><pre><span></span><code>ssh -R <span class="m">5900</span>:localhost:22 guest@remote-pc
</code></pre></div>
<p>在遠端 <code>remote-pc</code> 會開一個 5900 port,其流量會導到 localhost 的 22 port。實際的應用是當 local machine 沒有固定 IP 的時侯,可以先建立好此 ssh 連線。就可以讓遠端機器透過 localhost:5900 直接連線回local。</p>
<h2>SOCKS Proxy Forwarding</h2>
<p>主要可以用來保護非信任的網路,當不想讓別人知道自己的 http 連線時, 或是可以避開 IT 網路控管,可以用這個:</p>
<div class="highlight"><pre><span></span><code>ssh -C -D <span class="m">8080</span> cwliu@123.123.123.123
</code></pre></div>
<p>使用 <code>-D</code>參數建立一個 socks proxy,瀏覽器設定 <code>localhost:8080</code> 的 SOCKS v4 proxy 就可以讓出去的 http 連線透過 ssh 安全地到達遠端機器。
<code>-C</code>是把資料先壓縮後再傳送</p>
<!--
可用參數:
-N: 不執行任何指令
-f: 背景執行
-->
<h3>參考資料</h3>
<ul>
<li><a href="https://help.ubuntu.com/community/SSH/OpenSSH/PortForwarding">SSH/OpenSSH/PortForwarding - Community Ubuntu Documentation</a></li>
<li><a href="http://portable.easylife.tw/2043">Reverse SSH Tunnel實際運用,搭配auotssh永不斷線,putty建立反向tunnel :: 綠色工廠 Easylife Blog</a></li>
<li><a href="http://www.thegeekstuff.com/2013/11/reverse-ssh-tunnel/?utm_source=feedburner&utm_medium=email&utm_campaign=Feed%3A+TheGeekStuff+%28The+Geek+Stuff%29">How to Setup Reverse SSH Tunnel on Linux</a></li>
</ul>解決 Geust VM 在 Nested ESXi 網路無法連外的問題2014-05-06T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-05-06:/vmware-nested-esxi-promiscuous/<p>我遇到的情況是在 Ubuntu 13.10 上面安裝 VMware Workstation,在上面安裝了 ESXi 5.5。ESXi 上面的網路是使用 NAT,但是在 ESXi 上面的 VM 卻沒辦法連外 。這邊記錄一下解決的過程,簡單的說: ESXi上的 vSwtich 需要開啟<strong>promiscuous mode</strong>,然後 ,normal user 需要<strong>有權限</strong>寫入 /dev/vmnet</p>
<h2>Promiscuous 是什麼呢?</h2>
<p>在一般的 swtich 設計之下,預設是流通的frame只收到收件者自己的。但是這在 Nested VM 上面會有一些問題,因為 Guest VM 上面的 Mac address 跟 ESXi VM Mac adddress 不同,所以除非 ESXi 能收到 Guest VM 的 frame,不然像是外部的 DHCP 等等協定就沒辦法跟裡面的 VM 互動。而開啟 Promiscuous mode 之後,VM 就會收到其它 interface 的 frame。ESXi 就可以把需要傳送給自己肚子裡面的 VM 按照 vSwitch 的設定轉送過去。而 Promiscuous mode 可以在 ESXi 裡面的 vSwitch/Port group 安全性設定找到。在 5.5.0 一共有三個設定: </p>
<ul>
<li><code>Promiscuous mode …</code></li></ul><p>我遇到的情況是在 Ubuntu 13.10 上面安裝 VMware Workstation,在上面安裝了 ESXi 5.5。ESXi 上面的網路是使用 NAT,但是在 ESXi 上面的 VM 卻沒辦法連外 。這邊記錄一下解決的過程,簡單的說: ESXi上的 vSwtich 需要開啟<strong>promiscuous mode</strong>,然後 ,normal user 需要<strong>有權限</strong>寫入 /dev/vmnet</p>
<h2>Promiscuous 是什麼呢?</h2>
<p>在一般的 swtich 設計之下,預設是流通的frame只收到收件者自己的。但是這在 Nested VM 上面會有一些問題,因為 Guest VM 上面的 Mac address 跟 ESXi VM Mac adddress 不同,所以除非 ESXi 能收到 Guest VM 的 frame,不然像是外部的 DHCP 等等協定就沒辦法跟裡面的 VM 互動。而開啟 Promiscuous mode 之後,VM 就會收到其它 interface 的 frame。ESXi 就可以把需要傳送給自己肚子裡面的 VM 按照 vSwitch 的設定轉送過去。而 Promiscuous mode 可以在 ESXi 裡面的 vSwitch/Port group 安全性設定找到。在 5.5.0 一共有三個設定: </p>
<ul>
<li><code>Promiscuous mode</code>: 預設是 Reject (off)</li>
<li><code>MAC Address Changes</code> 預設是 Accept (on)</li>
<li><code>Forged Transmits</code> 預設是 Accept (on)</li>
</ul>
<p>在執行 Nested VM 的時侯,建議把這三個設定值都設成 <em>Accept</em> 。</p>
<p><img alt="vSwitchSecuritySetting" src="https://lh4.googleusercontent.com/pR3o_KLI29Dspklg9ve8c38_Gf--jqeDJ0EvAP_-ZRta=w523-h216-no"></p>
<p>如果 Host 是 Linux 的話,還是會有問題,因為Workstation 的 promiscuous mode 會需要讀寫 /dev/vmnet* ,而這些 device file 預設只有 root 可以讀寫。所以還需要以下步驟:</p>
<h2>修改 /dev/vmnet 權限</h2>
<p>新增一個 promiscuous group </p>
<div class="highlight"><pre><span></span><code>$ sudo groupadd promiscuous
$ sudo usermod -a -G promiscuous <YOUR_USER_ID>
</code></pre></div>
<p>驗證已經加入成功: </p>
<div class="highlight"><pre><span></span><code>$ getent group promiscuous
promiscuous:x:1001:<YOUR_USER_ID>
</code></pre></div>
<p>接下來修改 /etc/init.d/vmware,加入下列兩行,讓每次開機都自動修改權限。因為每次重開機之後 /dev/vmnet* 會被 reset 成 root 權限</p>
<div class="highlight"><pre><span></span><code> vmwareStartVmnet<span class="o">()</span> <span class="o">{</span>
vmwareLoadModule <span class="nv">$vnet</span>
<span class="s2">"</span><span class="nv">$BINDIR</span><span class="s2">"</span>/vmware-networks --start >> <span class="nv">$VNETLIB_LOG</span> <span class="m">2</span>><span class="p">&</span><span class="m">1</span>
+ chgrp promiscuous /dev/vmnet*
+ chmod g+rw /dev/vmnet*
<span class="o">}</span>
</code></pre></div>
<p>這樣就 ok 了。</p>
<h2>參考資料</h2>
<ul>
<li><a href="http://xmodulo.com/2013/05/how-to-use-virtual-ethernet-adapters-in-promiscuous-mode-on-vmware.html">How to use virtual Ethernet adapters in promiscuous mode on VMware - Linux FAQ</a></li>
</ul>《斷捨離》 筆記2014-01-22T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-01-22:/gtd-discardit-danshari/<p><img alt="斷捨離封面" src="https://lh6.googleusercontent.com/31A_VgHhnLUCXKapSF0RTgOdb8rm12F3YuDFrwR1VOib=w367-h519-no"> </p>
<ul>
<li>「斷」: 斷絕不需要的東西</li>
<li>「捨」: 捨去多餘的廢物</li>
<li>「離」: 脫離對物品的執著</li>
</ul>
<p><img alt="斷捨離" src="https://lh6.googleusercontent.com/-2Yhk_dYMHKM/Ut_bqPH_SrI/AAAAAAAFHv0/adQDGWbpgTc/w600"></p>
<p>從做<strong>斷</strong>和<strong>捨</strong>以達成<strong>離</strong>的狀態</p>
<ul>
<li>選擇物品的訣竅是思考<strong>用得到</strong>。因為<strong>用得到</strong>才有價值,而非<strong>可以用</strong></li>
</ul>
<h2>「三分法則」</h2>
<p><img alt="三分" src="https://lh3.googleusercontent.com/-Zk4ZlZmDKKg/Ut_u-vBA6YI/AAAAAAAFHwI/dMzn0adH7ME/w600"></p>
<p>東西一開始可以先分成三類,像是餐具,器具跟食材。針對每個分類再做三分法,餐具就可以分成「盤子」、「容器」、「飲料容器」</p>
<h2>7 5 1 「總量規制法則」</h2>
<p><img alt="751" src="https://lh5.googleusercontent.com/-nzAVktv3QJ0/Ut_u-uZf2rI/AAAAAAAFHwM/VFGQ7r2Im_w/w600"></p>
<ul>
<li>看不見的收納只能放滿<strong>七</strong>成</li>
<li>看不見的收納只能放滿<strong>五</strong>成(餐具櫃)</li>
<li>展示收納只能放<strong>一</strong>成</li>
</ul>
<p>利用總量限制來挑選自己最喜愛的物品</p>
<blockquote>
<p>物品要使用才有價值 - 斷</p>
<p>物品在此刻需要它的地方才有用處 - 捨</p>
<p>物品要適得其所才顯美麗 - 離</p>
</blockquote>Using Microsoft communicator in Ubuntu with pidgin-sipe plugin2014-01-21T00:00:00+08:002021-06-22T09:47:01+08:00Cody Liutag:blog.codylab.com,2014-01-21:/ubuntu-pidgin-ms-office-communicator/<p>We can install <code>pidgin-sipe</code> to use Microsoft communicator in Ubuntu. Here are the steps:</p>
<ol>
<li>Install sipe plugin</li>
</ol>
<p>sudo apt-get install pidgin-sipe</p>
<ol>
<li>Add account with the new "Office Communicator" type</li>
</ol>
<!--
- How to Disable Pidgin Notifications in Ubuntu - How-To Geek - http://goo.gl/ffZFN
- How to Enable Tray Icon : unity - How do I enable the pidgin system tray icon? - Ask Ubuntu - http://goo.gl/YCwDe
-->馬拉松心率訓練筆記2014-01-20T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-01-20:/running-marathon-heart-rate/<h2>心率訓練</h2>
<p>心跳頻率是身體疲憊情況的重要參考指標。在訓練的時侯,我們可以依照當下的心跳數來決定是否要加速或是放慢速度。另外在<a href="http://www.mr-sport.com.tw/product-test/heart-rate.html">司博特</a>也有提到: </p>
<blockquote>
<p>專業的運動員可以透過早晨的靜止心跳,來觀察自己的身體是否有恢復,假設身體狀況良好時,靜止心跳率約為每分鐘60下,在某次高強度的訓練後,隔天早上睡醒心跳達70下,則代表昨天的疲勞還未完全恢復,今日的練習強度應降低。</p>
</blockquote>
<p>可以知道心率是一個用來決定當下可承受的運動量重要指標。</p>
<h3>最高心跳</h3>
<p>一個人的最高心跳會隨者年紀遞減,一個最簡單的概略<a href="http://thewalkingsite.com/thr.html">算法</a>如下:</p>
<blockquote>
<p>最高心跳 = 220 - 年紀</p>
</blockquote>
<p>如果以一個三十歲的成人來說,他最高心跳約略為 <strong>190</strong></p>
<h3>心跳區間</h3>
<table>
<thead>
<tr>
<th>訓練區間</th>
<th>心跳區間</th>
<th>脂肪/卡路里</th>
<th>心跳(30歲)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Healthy Heart Zone (Warm up/Cool down)</td>
<td>50~60%</td>
<td>85%</td>
<td>95~114</td>
</tr>
<tr>
<td>Fitness Zone (Fat Burning)</td>
<td>60~70%</td>
<td>85%</td>
<td>114~133</td>
</tr>
<tr>
<td>Aerobic Zone (Endurance Training)</td>
<td>70~80%</td>
<td>50%</td>
<td>133~152</td>
</tr>
<tr>
<td>Anaerobic Zone (Performance Training)</td>
<td>80~90%</td>
<td>15%</td>
<td>152~171</td>
</tr>
<tr>
<td>Red Line (Maximum Effort)</td>
<td>90~100%</td>
<td>N/A</td>
<td>N/A</td>
</tr>
</tbody>
</table>
<ul>
<li>Healthy Heart Zone: 暖身用的區間</li>
<li>Fitness Zone : 這個區間有最高的瘦身效率,消耗的卡路里有85%來自脂肪</li>
<li>Aerobic Zone (Endurance Training): 練習心肺耐力的區間</li>
<li>Anaerobic Zone: 增進 …</li></ul><h2>心率訓練</h2>
<p>心跳頻率是身體疲憊情況的重要參考指標。在訓練的時侯,我們可以依照當下的心跳數來決定是否要加速或是放慢速度。另外在<a href="http://www.mr-sport.com.tw/product-test/heart-rate.html">司博特</a>也有提到: </p>
<blockquote>
<p>專業的運動員可以透過早晨的靜止心跳,來觀察自己的身體是否有恢復,假設身體狀況良好時,靜止心跳率約為每分鐘60下,在某次高強度的訓練後,隔天早上睡醒心跳達70下,則代表昨天的疲勞還未完全恢復,今日的練習強度應降低。</p>
</blockquote>
<p>可以知道心率是一個用來決定當下可承受的運動量重要指標。</p>
<h3>最高心跳</h3>
<p>一個人的最高心跳會隨者年紀遞減,一個最簡單的概略<a href="http://thewalkingsite.com/thr.html">算法</a>如下:</p>
<blockquote>
<p>最高心跳 = 220 - 年紀</p>
</blockquote>
<p>如果以一個三十歲的成人來說,他最高心跳約略為 <strong>190</strong></p>
<h3>心跳區間</h3>
<table>
<thead>
<tr>
<th>訓練區間</th>
<th>心跳區間</th>
<th>脂肪/卡路里</th>
<th>心跳(30歲)</th>
</tr>
</thead>
<tbody>
<tr>
<td>Healthy Heart Zone (Warm up/Cool down)</td>
<td>50~60%</td>
<td>85%</td>
<td>95~114</td>
</tr>
<tr>
<td>Fitness Zone (Fat Burning)</td>
<td>60~70%</td>
<td>85%</td>
<td>114~133</td>
</tr>
<tr>
<td>Aerobic Zone (Endurance Training)</td>
<td>70~80%</td>
<td>50%</td>
<td>133~152</td>
</tr>
<tr>
<td>Anaerobic Zone (Performance Training)</td>
<td>80~90%</td>
<td>15%</td>
<td>152~171</td>
</tr>
<tr>
<td>Red Line (Maximum Effort)</td>
<td>90~100%</td>
<td>N/A</td>
<td>N/A</td>
</tr>
</tbody>
</table>
<ul>
<li>Healthy Heart Zone: 暖身用的區間</li>
<li>Fitness Zone : 這個區間有最高的瘦身效率,消耗的卡路里有85%來自脂肪</li>
<li>Aerobic Zone (Endurance Training): 練習心肺耐力的區間</li>
<li>Anaerobic Zone: 增進 VO2 maximum(最大攝氧量), 未訓練的人一般乳酸閾值(lactate threshold)會落在 70%~75%</li>
<li>Red Line: 除非專業選手,大部份的人無法長久停留在這個區間</li>
</ul>
<h3>測量心跳的方式</h3>
<ol>
<li>GPS錶配ANT+心跳帶 ex: Bryton 40H </li>
<li>心跳帶 ex: Mio Alpha </li>
<li>手機+心跳帶 ex: Pafers HR-KIT</li>
</ol>
<!--
## 訓練跑速
1. 賽速跑(Race Pace): N
2. 輕鬆跑(Easy Run): N + 60~90
3. 漸速跑(Tempo Run): N - 30~45
- 換算各距離所需時間可以參考 [Craig's Running Calculator](http://www.fasterrunning.com/oldsite/calculator2.htm)
## 比賽飲食建議
### 比賽前幾天
- 義大利麵
### 比賽當天
- 賽前建議先吃最容易被消化的**蜂蜜蛋糕**或**香蕉**,接著是**果凍狀**的食物,最後才是**飲料**。
- 如果平時有喝咖啡的習慣,賽前不妨喝杯**咖啡**,據研究指出,咖啡因能讓脂肪代謝力提升,減少對肝醣的消耗,這樣能幫助我們在比賽時保持活力。
### 賽後
- 回家後可以多喝**柑橘類**飲品或補充柑橘類水果,特別是**檸檬酸補給素**,它能有效分解體內的疲勞物質
- 為了增加身體的免疫力,建議跑者多喝**雞湯**,裡頭富含胺基酸,不但能強化身體的修復機制,還能消除疲勞。
參考資料:[頂尖選手比賽前後都吃些什麼?](http://www.sportsnote.com.tw/running/view_article.aspx?id=683457f0-4fcf-4de8-afa4-45bb33b92430)
## 敗家清單
- [如何選擇慢跑褲](http://sobakome.pixnet.net/blog/post/36324576-如何選擇慢跑褲?)
### 心跳帶
- [分享 | 心率訓練 | Mr.Sport 司博特](http://mr-sport.com.tw/othersports/heart-rate.html)
- [MIO Alpha - The Pulse Watch without Chest Strap | VitaDock by Medisana](http://www.vitadock.com/vitadock/mio-alpha-the-pulse-watch-without-chest-strap.html)
### GPS錶
- [[錶測] Bryton Cardio 40 一錶跑天下](http://www.sportsnote.com.tw/running/view_article.aspx?id=e470255f-ea85-4fc9-a94e-345b58ffe15a)
- [開箱文--Bryton Cardio 40 GPS運動手錶 (第1頁) - 訓練與慢跑 - Mobile01](http://www.mobile01.com/topicdetail.php?f=558&t=3251239)
### 伸縮袋
- [PChome線上購物- 伸縮袋](http://shopping.pchome.com.tw/?mod=store&func=style_show&SR_NO=DEAO5D)
### 綁鞋帶
- http://www.youtube.com/watch?v=NBI5B1ng1as
馬拉松當天的準備
出門前:記得再上廁所一次/帶透氣膠帶orOK繃帶貼胸
- [跑步生活25問(上)](http://www.k-swiss.com.tw/index.php?option=com_content&view=article&id=127:25&catid=44:running&Itemid=388)
- [跑步生活25問(下)](http://www.k-swiss.com.tw/index.php?option=com_content&view=article&id=128:25-&catid=44:running&Itemid=388)
- [有效率的馬拉松訓練 - 鐵人的終點線 - Yahoo!奇摩部落格](http://tw.myblog.yahoo.com/jw!6KMSWPSaBxYOEVYML3CSzsbRL1g-/article?mid=16)
- [前進馬拉松訓練](http://me.lnes.tp.edu.tw/~htm/hjm/run/%E5%A4%AA%E9%AD%AF%E9%96%A3%E5%9C%8B%E9%9A%9B%E9%A6%AC%E6%8B%89%E6%9D%BE_%E8%A8%93%E7%B7%B4%E8%AA%B2%E7%A8%8B/%E5%89%8D%E9%80%B2%E9%A6%AC%E6%8B%89%E6%9D%BE%E8%A8%93%E7%B7%B4.htm)
# 網誌
- [面向陽光: 20121111第11馬-熱鬧滾滾的田中馬拉松(下) - yam天空部落](http://blog.yam.com/gogoparty/article/58186469)
- [jijiong's life-note: 2012 田中馬拉松路跑賽(我的初馬)](http://www.jijiong.net/2012/11/2012.html)
- [My Love Song! 富邦臺北馬拉松-即使落馬也要拍.avi - YouTube](http://www.youtube.com/watch?v=17LPEGZZpQY)
- [2012太魯閣馬拉松TAROKO GORGE MARATHON未完的挑戰! - YouTube](http://www.youtube.com/watch?v=tDD7dAQN_Ko)
## 姿勢跑法 Pose method
線上教學影片:
- [The Pose Method of Running - YouTube](http://www.youtube.com/watch?v=xZMYoYvCRQU)
- [ 2013 姿勢跑法,Pose Running - YouTube](http://www.youtube.com/watch?v=bOHKjP8fVZw)
## 菜單課表
- [邁向馬拉松成功之路](http://bigfootgogogo.tripod.com/discuss/know3.htm)
-->研發替代役出國管制章註銷流程2014-01-17T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-01-17:/rdss-control-cancellation/<p>聽說役期期滿了不註銷護照上<code>持照人出國應經核準</code>也可以順利出國。像我就比較不放心,還是親自跑一趟外交部領事事務局,把這個章註銷掉。</p>
<h2>需要準備的證件</h2>
<ol>
<li>身分證正本</li>
<li>護照正本</li>
<li>退役證明正本</li>
</ol>
<h2>流程</h2>
<p>我是在台北領事局辦的。先搭電扶梯到三樓,右轉走到底就可以看到內政部的櫃台。把<code>身分證</code>、<code>護照</code>、<code>退役證明</code>交給櫃台人員之後,他會在上面蓋章,如圖:</p>
<p><img alt="兵役管制註銷" src="https://lh5.googleusercontent.com/7KP5UWkWG_0ncYv6U8gPKUsqgc7tL1eFsu6TcJyrMytV=w329-h186-p-no"></p>
<p>接下來會給你一張變更通知書:</p>
<p><img alt="變更通知書" src="https://lh6.googleusercontent.com/-zS84CDVuRHY/Utj1HHmebSI/AAAAAAAFHpw/RSp6fGw_Zxs/w500/IMAG0957.jpg"></p>
<p>然後會請你到旁邊的影印機列印,1張1元。先投錢再列印,需要列印的資料有: </p>
<ol>
<li>護照大頭照頁二張</li>
<li>護照最後一頁被蓋章的那頁二張</li>
<li>退役證明二張</li>
</ol>
<p>把列印好的護照貼到變更通知書,把護照大頭內頁貼在上面,註銷頁貼在下面。最後再交回給內政部的櫃台就完成全部的手續了。</p>
<p>--</p>
<h3>外交部領事事務局:</h3>
<ul>
<li>台北市中正區濟南路1段2之2號3~5樓</li>
<li>服務時間:週一至週五 上午:08:30 — 下午:17:00 (中午不休息)(週六、週日及國定假日不上班)</li>
</ul>
<h3>Reference</h3>
<ul>
<li><a href="https://www.ptt.cc/bbs/RDSS/M.1344833404.A.DB9.html">[資訊] 期滿後的護照註銷戳記處理流程 - 看板 DIRDS - 批踢踢實業坊</a></li>
</ul>人生是永遠的測試版(The Start-up of You) 閱讀筆記2014-01-07T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-01-07:/startup-of-you/<p><img alt="img" src="https://lh4.googleusercontent.com/-Bol1iv3l7uA/UswURCaTcFI/AAAAAAAFHo8/82QC2OmEy24/w560-h310-no/The-Start-up-of-you-Reid-Hoffman-Ben-Casnocha.jpg"></p>
<ul>
<li>精進專業技能是自己的責任,而不是雇主</li>
<li>創業通常是在資訊相對匱乏,時間緊迫、資源受限的條件下做決定...跟我們每個人經營的職業生涯所面臨的情境非常相似</li>
<li>創業精神是人生理念</li>
<li>底特律汽車業的崩解:摧毀那曾經輝煌的城市與產業的改變力量,也可能摧毀你我的職業生涯</li>
<li>矽谷模式:這些公司不只提供了企業創新模式,也提供個人生涯成功所需的創新思維</li>
<li>每個人應該把「完成」當成禁忌字眼,我們都是「在製品」(work-in-process)</li>
<li>創業家生存的基本要件,就是要比競爭對手優秀</li>
<li>創業家的關鍵不在於創業,而是世界觀: 在別人看到阻礙時,發現機會; 在別人避險時,勇於冒險 by 紐約市長 麥可. 彭博</li>
<li>去可以迅速成長的地方: 因為迅速成長才能創造各種機會</li>
<li>關鍵在於提高你巧遇重要人事物的機率</li>
<li>要找機會前,要先找人</li>
</ul>
<h2>競爭優勢</h2>
<ul>
<li>自己的<strong>競爭優勢</strong>是職涯策略的發展基礎,幫你決定該追求什麼機會,也指引你該如何投資自己</li>
<li>無論需求是什麼,除非你對那件事有熱情又很擅長,否則都不會有競爭優勢</li>
<li>競爭優勢主要包含三個部份: 1.資產 2.抱負與價值觀 3.市場實際狀況</li>
</ul>
<h3>1.資產</h3>
<h4>硬性資產</h4>
<p>錢、股票、家當等等。這很重要,因為有錢可以讓你投入財務風險較大的行動,像是辭職不工作半年,專心投入新技能的學習。</p>
<h4>軟性資產</h4>
<p>知識,人脈,聲譽等等。
幫你記得自己有多少無形軟性資產的最好方法就是去參加社交活動。通常你是在遇到別人覺得很難,但是你覺得很簡單的挑戰時,才發現你擁有寶貴的軟性資產。</p>
<ul>
<li>想辦法強化自己的資產組合 </li>
<li>單一資產通常沒有太大的價值,當你結合不同的技能、經驗和人脈時、競爭優勢才會顯視</li>
</ul>
<h3>2.抱負與價值觀</h3>
<p>抱負和價值觀是生涯競爭優勢極重要的一環,因為當你在做<strong>自己在乎</strong>的事情時,不但會更努力,也能做得更好</p>
<h3>3.市場實際狀況</h3>
<ul>
<li>無論產品的外型和功能有多炫,顧客不想要或不需要的產品就是無法賺錢。像是Segway代步車。</li>
<li>不在乎的市場,才不在乎你有多聰明 by 創投家 Marc Andresssen</li>
<li>所有專業人士及職業生涯的成敗,就看雇主、顧客或合夥人<strong>願不願意買你的時間</strong></li>
</ul>
<h2>改寫生涯的方程式: ABZ計畫 …</h2><p><img alt="img" src="https://lh4.googleusercontent.com/-Bol1iv3l7uA/UswURCaTcFI/AAAAAAAFHo8/82QC2OmEy24/w560-h310-no/The-Start-up-of-you-Reid-Hoffman-Ben-Casnocha.jpg"></p>
<ul>
<li>精進專業技能是自己的責任,而不是雇主</li>
<li>創業通常是在資訊相對匱乏,時間緊迫、資源受限的條件下做決定...跟我們每個人經營的職業生涯所面臨的情境非常相似</li>
<li>創業精神是人生理念</li>
<li>底特律汽車業的崩解:摧毀那曾經輝煌的城市與產業的改變力量,也可能摧毀你我的職業生涯</li>
<li>矽谷模式:這些公司不只提供了企業創新模式,也提供個人生涯成功所需的創新思維</li>
<li>每個人應該把「完成」當成禁忌字眼,我們都是「在製品」(work-in-process)</li>
<li>創業家生存的基本要件,就是要比競爭對手優秀</li>
<li>創業家的關鍵不在於創業,而是世界觀: 在別人看到阻礙時,發現機會; 在別人避險時,勇於冒險 by 紐約市長 麥可. 彭博</li>
<li>去可以迅速成長的地方: 因為迅速成長才能創造各種機會</li>
<li>關鍵在於提高你巧遇重要人事物的機率</li>
<li>要找機會前,要先找人</li>
</ul>
<h2>競爭優勢</h2>
<ul>
<li>自己的<strong>競爭優勢</strong>是職涯策略的發展基礎,幫你決定該追求什麼機會,也指引你該如何投資自己</li>
<li>無論需求是什麼,除非你對那件事有熱情又很擅長,否則都不會有競爭優勢</li>
<li>競爭優勢主要包含三個部份: 1.資產 2.抱負與價值觀 3.市場實際狀況</li>
</ul>
<h3>1.資產</h3>
<h4>硬性資產</h4>
<p>錢、股票、家當等等。這很重要,因為有錢可以讓你投入財務風險較大的行動,像是辭職不工作半年,專心投入新技能的學習。</p>
<h4>軟性資產</h4>
<p>知識,人脈,聲譽等等。
幫你記得自己有多少無形軟性資產的最好方法就是去參加社交活動。通常你是在遇到別人覺得很難,但是你覺得很簡單的挑戰時,才發現你擁有寶貴的軟性資產。</p>
<ul>
<li>想辦法強化自己的資產組合 </li>
<li>單一資產通常沒有太大的價值,當你結合不同的技能、經驗和人脈時、競爭優勢才會顯視</li>
</ul>
<h3>2.抱負與價值觀</h3>
<p>抱負和價值觀是生涯競爭優勢極重要的一環,因為當你在做<strong>自己在乎</strong>的事情時,不但會更努力,也能做得更好</p>
<h3>3.市場實際狀況</h3>
<ul>
<li>無論產品的外型和功能有多炫,顧客不想要或不需要的產品就是無法賺錢。像是Segway代步車。</li>
<li>不在乎的市場,才不在乎你有多聰明 by 創投家 Marc Andresssen</li>
<li>所有專業人士及職業生涯的成敗,就看雇主、顧客或合夥人<strong>願不願意買你的時間</strong></li>
</ul>
<h2>改寫生涯的方程式: ABZ計畫</h2>
<ul>
<li>讓單一夢想主導你的存在都是不智的</li>
<li>A計畫: 現在正在做的事,是你目前落實的競爭優勢 </li>
<li>B計畫: 其實就是<strong>Pivot</strong>計畫,最好選擇能夠一腳站穩在原領域,另一腳跨足新領域的選項</li>
<li>Z計畫: 救生艇計劃。讓你不怕失敗感,感積極投入A計劃與B計劃。Z計劃也許是家裡的一個空房間</li>
</ul>
<h2>善用三度連結找盟友</h2>
<ul>
<li>無論你的想法或策略有多了不起,如果你是單打獨鬥,永遠會輸給團隊</li>
<li>你打造的團隊,就是你打造的公司</li>
<li>改變自己的最快方法,就是和那些已經達到你目標的人相處</li>
<li>一群多元的盟友和顧問</li>
</ul>
<h2>風險</h2>
<ul>
<li>積極承擔明智的風險,是把握突破機會的先決條件</li>
<li>卓越的創業家之所以與眾不同,並不是因為他們對風險的接受度高,而是他們審慎評估風險與管理風險的能力</li>
<li>你不應該在毫無資訊下盲目地轉換職業,也不該等到獲得全部的資訊後才行動,否則你會永遠等下去</li>
</ul>
<h1>延伸閱讀</h1>
<ul>
<li><a href="http://www.thestartupofyou.com/">The Start-Up of You</a></li>
<li><a href="http://book.douban.com/subject/6933056/">The Start-up of You (豆瓣)</a></li>
</ul>
<!--
- Netflix的成功跟Blockbuster失敗
-->Angry IP Scaner2014-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-01-01:/angryip/<p><a href="http://goo.gl/IuL9XL">Angry IP Scanner</a> 是一套好用的 IP Scanner 軟體,支援: Windows, Mac or Linux: </p>
<p><img alt="gui" src="http://i.imgur.com/ofZVNix.png"></p>How to apply elastic IP more than 52014-01-01T00:00:00+08:002021-06-22T08:49:09+08:00Cody Liutag:blog.codylab.com,2014-01-01:/aws-apply-elastic-ip/<h1>Apply Elastic IP</h1>
<p>By default, for every ec2 account, you could only have 5 elastic IPs. However, if you want more, you can submit a here:</p>
<h2><a href="https://aws.amazon.com/support/createCase?serviceLimitIncreaseType=sns-limits&type=service_limit_increase&isauthcode=true&code=NzA0MmA8ZgMbK5ypdITUAVlCcKcssRxI9Wi6d0OMbo2KgAoPgFh2PO71QfZ_3WZDGYpLsjaBV9vo4JGJGMjT2fYpIj3KrMAPQO5YAungthpY0GN4G-_TSASmFfrT86jtL-7AMBQ8Vu-gIzHpXyKUL2TZrN5G3qtC6W9FlwM3verh5XU_21ibQchtcz2hmWHUYbYYNha9BjMPVGA-E9_O63V0ym4cAVq7Un1rFlRjXAm1LdATMWL-WQRi3QD8zRNkT9f6r3w_eJuGap_4GkTUIEECmKjnuX74_kA9LkyM5DZ0B9L1QS8z-vo4ZJI-Wd42hQ2ye0P0nkCjVkuc162eomJ9A1pIE7qAbim1-viPrB5jgPO2m3RaNUZbMZhn6J_Tl3Eay62iCTt50gVU1ziYZmguP4TlBnzUkEUw5DVdaOj3SvIZqEmwHxsr88849zuV63HAFWvvuQ2YQ6XbISJPWoC0UJ3qAbyZtP_Wn0IUGlLJtiz44PzA1IpQxSNdwIicjKHfXbRg71GCMdxo2A-nEINL3NW03_lY9Yw4vtruVn_1g7h3Ruvmt1JXVqo4evMTpPRIgpNTOAxyG38R35DOLO-sAj9fiioT_Fn_SB2nkdpF7rPCVv3nDAVy1AgN7aotIvBOYZT7pyUjb635VBjhSjICIX8XBzwwBA0U-VwZ9Da86bzV9Xiek48RMZ4L-diWOEoyEHESRS7KnIFuL1TjpQXup8_afLzVBZPIaijUHtGiOAk6lTAT1t72tay8slkfiuR2eGoxiZOOpo6_Om3BsZ2N-yiIqPlW9OkCdrgnpWHIJmUsNPoZp33JuEKj5R44OOeErhNeuK7TlE5FKcBT72hQPtk2x6DmEVsEZbVuRFnlQMj5lSXZoBQO_KYMtmcBiG_95iGIAIsAn7xpN2H922B9PVVC00dZ9bUSCmolLPtUA2f-cNuZDbv278nM_gDvPXcyUr-XFGBZzjJZsE8cfmXlJh5TbcWQ82HOh7a_CONoqV2goBIPZzzGhYxhUzfGAM4LtNEb5CzSRUUGJuWZfwwd3fyyYmDxYgTIlmckzxjPcQhY1fflAmOWx538cHjTHVaf_7JV55P1CLba8_iYakDuq6fn_R4gqIqjy_s6nik5R1r-tBdZcSHgf_WkaXYD1Smii8U7K7TV61-xP8WKOBzxRUMWbdyyv_10oA">Submit a Case</a></h2>
<p><img alt="screen" src="https://i.imgur.com/orK0T9n.png"></p>
<!-- # SSH 連線進 Instance
In ubuntu
chmod 400 my-pem-file.pem
ssh -i my-pem-file.pem ubuntu@my-instance-address
Others
ssh -i my-pem-file.pem ec2-user@my-instance-address
使用 Password SSH 連線進 Instance 可參考: [Enable Password SSH Access to your Amazon EC2 Linux Instance « Ben's Notepad](http://bensnotepad.com/enable-password-access-to-your-amazon-ec2-linux-instance/)
-->如何寫 Bug Report2014-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-01-01:/bug-report/<p>一個好的 Bug Report 應該要提供明確的資訊,可以讓 Developer 快速重視問題,減少分析問題的成本。而管理階層的人從報告可了解問題的嚴重性,進而決定解決這個Bug時間表。</p>
<h2>Bug Report 應該要有的欄位</h2>
<ol>
<li>標題 <br>
說明要明確,直指問題核心,說明問題發生的模組 </li>
</ol>
<p><strong>不好的標題</strong>: 照片無法上傳 <br>
<strong>比較好的標題</strong>: 當照片尺寸大於10MB,手機無法使用自動上傳照片</p>
<ol>
<li>
<p>問題重現步驟(Steps to reproduce) <br>
除了要找出可以重視問題的Steps之外,還要盡量縮小(narrow down)步驟,找出重現問題的關鍵步驟。通常最後一步會寫"預期的結果"(expected result),實際發生的結果有什麼不同。 </p>
<ol>
<li>安裝 APP</li>
<li>使用 Google 帳號登入</li>
<li>點選登入按鈕 <br>
預期結果: 登入成功,進入活動列表 <br>
實際結果: 登入失敗,出現伺服器連接錯誤 </li>
</ol>
</li>
<li>
<p>嚴重性 <br>
<em>Blocker</em>: 產生無法使用,要<em>立即</em>解決,像是產品無法安裝 <br>
<em>Criticl</em>: 嚴重的問題,需要儘早解決 <br>
<em>Major</em>: 重要的問題,需要在產品上線前解決 <br>
<em>Minor</em>: 次要的問題,不一定要解決,有列入已知問題(kownn Issue)的空間 <br>
<em>Trival</em>: 不直接影響使用者使用,像是打錯字,等等 </p>
</li>
<li>
<p>問題發生的版本號 </p>
</li>
<li>
<p>發生的頻率 <br>
每次/常常/偶爾/很少</p>
</li>
<li>
<p>附件: 錯誤畫面的截圖,相關Log檔案以及任何可以幫助分析問題的檔案</p>
</li>
</ol>
<h3>一些原則</h3>
<ol>
<li>如果測試一次發現多個問題,不要把多個 bug 寫在同一筆issue裡,分開一筆一筆記錄,這樣才可以獨立被解決跟驗證(Verify)</li>
<li>確認這個 bug 是否已經記錄過了? 不要重覆發。</li>
</ol>
<h3>Bug Workflow</h3>
<p>這是一張在網路上找到一個比較簡單的 bug workflow </p>
<p><img alt="img" src="https://lh6.googleusercontent.com/-UHiozVdot50/U_MLiVr5MQI/AAAAAAAFNNM/0v8oFN4oTqg/w1280-h1124-no/flow-chart-new.gif"></p>取得硬碟資訊 blkid2014-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-01-01:/cmd-blkid/<p>每次在編輯 <code>/etc/fstab</code> 的時侯,都會忘了要怎麼取得 disk 的 UUID,其實在 Ubuntu 有個 blkid 的指令可以使用</p>
<div class="highlight"><pre><span></span><code>$ sudo blkid
/dev/sda2: <span class="nv">LABEL</span><span class="o">=</span><span class="s2">"Data"</span> <span class="nv">UUID</span><span class="o">=</span><span class="s2">"357b1cbf-c4d4-47a4-8ce1-5cfd6ac110f7"</span> <span class="nv">TYPE</span><span class="o">=</span><span class="s2">"ext4"</span>
/dev/sda5: <span class="nv">UUID</span><span class="o">=</span><span class="s2">"db9ca73a-c4ba-455d-89b0-e7e6f6d8b67d"</span> <span class="nv">TYPE</span><span class="o">=</span><span class="s2">"swap"</span>
/dev/sdb1: <span class="nv">UUID</span><span class="o">=</span><span class="s2">"69ea78d6-414f-4c2a-bab4-3cbfbf160e0e"</span> <span class="nv">TYPE</span><span class="o">=</span><span class="s2">"ext4"</span>
/dev/sdb5: <span class="nv">UUID</span><span class="o">=</span><span class="s2">"75df4068-f9a8-4e04-af47-7b6165a4716f"</span> <span class="nv">TYPE</span><span class="o">=</span><span class="s2">"swap"</span>
</code></pre></div>nmap 筆記2014-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-01-01:/namp/<p>NAMP 是一套網路掃描的工具</p>
<h2>Nmap</h2>
<div class="highlight"><pre><span></span><code><span class="n">$</span> <span class="n">nmap</span> <span class="n">ip</span>
<span class="n">$</span> <span class="n">nmap</span> <span class="p">[</span><span class="n">ip1</span> <span class="n">ip2</span><span class="p">]</span>
<span class="n">$</span> <span class="n">namp</span> <span class="mf">192.168.10.1</span><span class="o">/</span><span class="mi">24</span>
</code></pre></div>
<p>隨機掃描目標(慎用)</p>
<div class="highlight"><pre><span></span><code>$ nmap -iR <span class="m">3</span>
</code></pre></div>
<h2>Ping</h2>
<p>$ nmap 172.16.21.134 172.16.21.135 -sP</p>
<p>Starting Nmap 6.40 ( http://nmap.org ) at 2014-04-24 09:38 CST
Nmap scan report for 172.16.21.134
Host is up (0.00084s latency).
Nmap done: 2 IP addresses (1 host up) scanned in 1.21 seconds</p>
<h2>Traceroute</h2>
<div class="highlight"><pre><span></span><code># <span class="nv">sudo</span> <span class="nv">nmap</span> <span class="mi">8</span>.<span class="mi">8</span>.<span class="mi">8</span>.<span class="mi">8</span> <span class="o">--</span><span class="nv">traceroute</span>
<span class="nv">Starting</span> <span class="nv">Nmap</span> <span class="mi">6</span>.<span class="mi">40</span> <span class="ss">(</span> <span class="nv">http</span>:<span class="o">//</span><span class="nv">nmap</span>.<span class="nv">org</span> <span class="ss">)</span> <span class="nv">at</span> <span class="mi">2014</span><span class="o">-</span><span class="mi">04</span><span class="o">-</span><span class="mi">24</span> <span class="mi">09</span>:<span class="mi">39</span> <span class="nv">CST</span>
<span class="nv">Nmap</span> <span class="nv">scan</span> <span class="nv">report</span> <span class="k">for</span> <span class="nv">google</span><span class="o">-</span><span class="nv">public</span><span class="o">-</span><span class="nv">dns</span><span class="o">-</span><span class="nv">a</span>.<span class="nv">google …</span></code></pre></div><p>NAMP 是一套網路掃描的工具</p>
<h2>Nmap</h2>
<div class="highlight"><pre><span></span><code><span class="n">$</span> <span class="n">nmap</span> <span class="n">ip</span>
<span class="n">$</span> <span class="n">nmap</span> <span class="p">[</span><span class="n">ip1</span> <span class="n">ip2</span><span class="p">]</span>
<span class="n">$</span> <span class="n">namp</span> <span class="mf">192.168.10.1</span><span class="o">/</span><span class="mi">24</span>
</code></pre></div>
<p>隨機掃描目標(慎用)</p>
<div class="highlight"><pre><span></span><code>$ nmap -iR <span class="m">3</span>
</code></pre></div>
<h2>Ping</h2>
<p>$ nmap 172.16.21.134 172.16.21.135 -sP</p>
<p>Starting Nmap 6.40 ( http://nmap.org ) at 2014-04-24 09:38 CST
Nmap scan report for 172.16.21.134
Host is up (0.00084s latency).
Nmap done: 2 IP addresses (1 host up) scanned in 1.21 seconds</p>
<h2>Traceroute</h2>
<div class="highlight"><pre><span></span><code># <span class="nv">sudo</span> <span class="nv">nmap</span> <span class="mi">8</span>.<span class="mi">8</span>.<span class="mi">8</span>.<span class="mi">8</span> <span class="o">--</span><span class="nv">traceroute</span>
<span class="nv">Starting</span> <span class="nv">Nmap</span> <span class="mi">6</span>.<span class="mi">40</span> <span class="ss">(</span> <span class="nv">http</span>:<span class="o">//</span><span class="nv">nmap</span>.<span class="nv">org</span> <span class="ss">)</span> <span class="nv">at</span> <span class="mi">2014</span><span class="o">-</span><span class="mi">04</span><span class="o">-</span><span class="mi">24</span> <span class="mi">09</span>:<span class="mi">39</span> <span class="nv">CST</span>
<span class="nv">Nmap</span> <span class="nv">scan</span> <span class="nv">report</span> <span class="k">for</span> <span class="nv">google</span><span class="o">-</span><span class="nv">public</span><span class="o">-</span><span class="nv">dns</span><span class="o">-</span><span class="nv">a</span>.<span class="nv">google</span>.<span class="nv">com</span> <span class="ss">(</span><span class="mi">8</span>.<span class="mi">8</span>.<span class="mi">8</span>.<span class="mi">8</span><span class="ss">)</span>
<span class="nv">Host</span> <span class="nv">is</span> <span class="nv">up</span> <span class="ss">(</span><span class="mi">0</span>.<span class="mi">012</span><span class="nv">s</span> <span class="nv">latency</span><span class="ss">)</span>.
<span class="nv">Not</span> <span class="nv">shown</span>: <span class="mi">999</span> <span class="nv">filtered</span> <span class="nv">ports</span>
<span class="nv">PORT</span> <span class="nv">STATE</span> <span class="nv">SERVICE</span>
<span class="mi">53</span><span class="o">/</span><span class="nv">tcp</span> <span class="nv">open</span> <span class="nv">domain</span>
<span class="nv">TRACEROUTE</span> <span class="ss">(</span><span class="nv">using</span> <span class="nv">port</span> <span class="mi">53</span><span class="o">/</span><span class="nv">tcp</span><span class="ss">)</span>
<span class="nv">HOP</span> <span class="nv">RTT</span> <span class="nv">ADDRESS</span>
<span class="mi">1</span> <span class="mi">5</span>.<span class="mi">03</span> <span class="nv">ms</span> <span class="mi">140</span>.<span class="mi">92</span>.<span class="mi">62</span>.<span class="mi">1</span>
<span class="mi">2</span> <span class="mi">2</span>.<span class="mi">25</span> <span class="nv">ms</span> <span class="mi">140</span>.<span class="mi">92</span>.<span class="mi">12</span>.<span class="mi">22</span>
<span class="mi">3</span> <span class="mi">2</span>.<span class="mi">40</span> <span class="nv">ms</span> <span class="mi">140</span>.<span class="mi">92</span>.<span class="mi">12</span>.<span class="mi">30</span>
<span class="mi">4</span> <span class="mi">3</span>.<span class="mi">07</span> <span class="nv">ms</span> <span class="nv">h254</span>.<span class="nv">s98</span>.<span class="nv">ts</span>.<span class="nv">hinet</span>.<span class="nv">net</span> <span class="ss">(</span><span class="mi">168</span>.<span class="mi">95</span>.<span class="mi">98</span>.<span class="mi">254</span><span class="ss">)</span>
<span class="mi">5</span> <span class="mi">20</span>.<span class="mi">43</span> <span class="nv">ms</span> <span class="nv">h102</span>.<span class="nv">s24</span>.<span class="nv">ts</span>.<span class="nv">hinet</span>.<span class="nv">net</span> <span class="ss">(</span><span class="mi">168</span>.<span class="mi">95</span>.<span class="mi">24</span>.<span class="mi">102</span><span class="ss">)</span>
<span class="mi">6</span> <span class="mi">9</span>.<span class="mi">05</span> <span class="nv">ms</span> <span class="nv">tpdt</span><span class="o">-</span><span class="mi">3011</span>.<span class="nv">hinet</span>.<span class="nv">net</span> <span class="ss">(</span><span class="mi">220</span>.<span class="mi">128</span>.<span class="mi">1</span>.<span class="mi">246</span><span class="ss">)</span>
<span class="mi">7</span> <span class="mi">4</span>.<span class="mi">31</span> <span class="nv">ms</span> <span class="nv">tyfo</span><span class="o">-</span><span class="mi">3011</span>.<span class="nv">hinet</span>.<span class="nv">net</span> <span class="ss">(</span><span class="mi">220</span>.<span class="mi">128</span>.<span class="mi">8</span>.<span class="mi">81</span><span class="ss">)</span>
<span class="mi">8</span> <span class="mi">3</span>.<span class="mi">45</span> <span class="nv">ms</span> <span class="nv">tyfo</span><span class="o">-</span><span class="mi">3301</span>.<span class="nv">hinet</span>.<span class="nv">net</span> <span class="ss">(</span><span class="mi">220</span>.<span class="mi">128</span>.<span class="mi">8</span>.<span class="mi">249</span><span class="ss">)</span>
<span class="mi">9</span> <span class="mi">6</span>.<span class="mi">73</span> <span class="nv">ms</span> <span class="mi">74</span>.<span class="mi">125</span>.<span class="mi">49</span>.<span class="mi">158</span>
<span class="mi">10</span> <span class="mi">12</span>.<span class="mi">86</span> <span class="nv">ms</span> <span class="mi">209</span>.<span class="mi">85</span>.<span class="mi">243</span>.<span class="mi">30</span>
<span class="mi">11</span> <span class="mi">8</span>.<span class="mi">06</span> <span class="nv">ms</span> <span class="mi">209</span>.<span class="mi">85</span>.<span class="mi">243</span>.<span class="mi">21</span>
<span class="mi">12</span> ...
<span class="mi">13</span> <span class="mi">13</span>.<span class="mi">71</span> <span class="nv">ms</span> <span class="nv">google</span><span class="o">-</span><span class="nv">public</span><span class="o">-</span><span class="nv">dns</span><span class="o">-</span><span class="nv">a</span>.<span class="nv">google</span>.<span class="nv">com</span> <span class="ss">(</span><span class="mi">8</span>.<span class="mi">8</span>.<span class="mi">8</span>.<span class="mi">8</span><span class="ss">)</span>
<span class="nv">Nmap</span> <span class="nv">done</span>: <span class="mi">1</span> <span class="nv">IP</span> <span class="nv">address</span> <span class="ss">(</span><span class="mi">1</span> <span class="nv">host</span> <span class="nv">up</span><span class="ss">)</span> <span class="nv">scanned</span> <span class="nv">in</span> <span class="mi">8</span>.<span class="mi">06</span> <span class="nv">seconds</span>
</code></pre></div>
<h2>TCP SYN Ping</h2>
<p>當系統把 ICMP PING 關掉的時間可以改試 TCP SYN PING。 </p>
<div class="highlight"><pre><span></span><code>$ nmap -PS135 <span class="m">172</span>.16.21.131
</code></pre></div>
<h2>UDP Ping</h2>
<div class="highlight"><pre><span></span><code># nmap -PU 172.16.21.131
</code></pre></div>
<h2>偵測作業系統</h2>
<div class="highlight"><pre><span></span><code># mmap -O 172.16.21.134
</code></pre></div>
<p>結果不一定準確,實際測試 Windows 7:</p>
<div class="highlight"><pre><span></span><code><span class="err">$</span> <span class="s s-Atom">sudo</span> <span class="s s-Atom">nmap</span> <span class="o">-</span><span class="nv">O</span> <span class="mf">172.16.21.131</span>
<span class="nv">Starting</span> <span class="nv">Nmap</span> <span class="mf">6.40</span> <span class="p">(</span> <span class="nn">http</span><span class="p">:</span><span class="o">//</span><span class="s s-Atom">nmap</span><span class="p">.</span><span class="s s-Atom">org</span> <span class="p">)</span> <span class="s s-Atom">at</span> <span class="mi">2014</span><span class="o">-</span><span class="mi">04</span><span class="o">-</span><span class="mi">24</span> <span class="mi">09</span><span class="s s-Atom">:</span><span class="mi">49</span> <span class="nv">CST</span>
<span class="nv">Nmap</span> <span class="s s-Atom">scan</span> <span class="s s-Atom">report</span> <span class="s s-Atom">for</span> <span class="mf">172.16.21.131</span>
<span class="nv">Host</span> <span class="o">is</span> <span class="nf">up</span> <span class="p">(</span><span class="mf">0.0012</span><span class="s s-Atom">s</span> <span class="s s-Atom">latency</span><span class="p">).</span>
<span class="nv">Not</span> <span class="nn">shown</span><span class="p">:</span> <span class="mi">998</span> <span class="s s-Atom">filtered</span> <span class="s s-Atom">ports</span>
<span class="nv">PORT</span> <span class="nv">STATE</span> <span class="nv">SERVICE</span>
<span class="mi">135</span><span class="o">/</span><span class="s s-Atom">tcp</span> <span class="s s-Atom">open</span> <span class="s s-Atom">msrpc</span>
<span class="mi">3389</span><span class="o">/</span><span class="s s-Atom">tcp</span> <span class="s s-Atom">open</span> <span class="s s-Atom">ms</span><span class="o">-</span><span class="s s-Atom">wbt</span><span class="o">-</span><span class="s s-Atom">server</span>
<span class="nv">MAC</span> <span class="nv">Address</span><span class="s s-Atom">:</span> <span class="mi">00</span><span class="s s-Atom">:</span><span class="mi">0</span><span class="nv">C</span><span class="s s-Atom">:</span><span class="mi">29</span><span class="s s-Atom">:</span><span class="mi">53</span><span class="s s-Atom">:</span><span class="mi">99</span><span class="s s-Atom">:</span><span class="nv">FF</span> <span class="p">(</span><span class="nv">VMware</span><span class="p">)</span>
<span class="nv">Warning</span><span class="s s-Atom">:</span> <span class="nv">OSScan</span> <span class="s s-Atom">results</span> <span class="s s-Atom">may</span> <span class="s s-Atom">be</span> <span class="s s-Atom">unreliable</span> <span class="s s-Atom">because</span> <span class="s s-Atom">we</span> <span class="s s-Atom">could</span> <span class="o">not</span> <span class="s s-Atom">find</span> <span class="s s-Atom">at</span> <span class="s s-Atom">least</span> <span class="mi">1</span> <span class="s s-Atom">open</span> <span class="s s-Atom">and</span> <span class="mi">1</span> <span class="s s-Atom">closed</span> <span class="s s-Atom">port</span>
<span class="nv">Device</span> <span class="nn">type</span><span class="p">:</span> <span class="s s-Atom">general</span> <span class="s s-Atom">purpose</span>
<span class="nv">Running</span><span class="s s-Atom">:</span> <span class="nv">Microsoft</span> <span class="nv">Windows</span> <span class="nv">Vista</span><span class="p">|</span><span class="mi">2008</span><span class="p">|</span><span class="mi">7</span>
<span class="nv">OS</span> <span class="nv">CPE</span><span class="s s-Atom">:</span> <span class="nn">cpe</span><span class="p">:</span><span class="o">/</span><span class="nn">o</span><span class="p">:</span><span class="nn">microsoft</span><span class="p">:</span><span class="s s-Atom">windows_vista::-</span> <span class="nn">cpe</span><span class="p">:</span><span class="o">/</span><span class="nn">o</span><span class="p">:</span><span class="nn">microsoft</span><span class="p">:</span><span class="s s-Atom">windows_vista::sp1</span> <span class="nn">cpe</span><span class="p">:</span><span class="o">/</span><span class="nn">o</span><span class="p">:</span><span class="nn">microsoft</span><span class="p">:</span><span class="s s-Atom">windows_server_2008::sp1</span> <span class="nn">cpe</span><span class="p">:</span><span class="o">/</span><span class="nn">o</span><span class="p">:</span><span class="nn">microsoft</span><span class="p">:</span><span class="s s-Atom">windows_7</span>
<span class="nv">OS</span> <span class="nn">details</span><span class="p">:</span> <span class="nv">Microsoft</span> <span class="nv">Windows</span> <span class="nv">Vista</span> <span class="nv">SP0</span> <span class="s s-Atom">or</span> <span class="nv">SP1</span><span class="p">,</span> <span class="nv">Windows</span> <span class="nv">Server</span> <span class="mi">2008</span> <span class="nv">SP1</span><span class="p">,</span> <span class="s s-Atom">or</span> <span class="nv">Windows</span> <span class="mi">7</span><span class="p">,</span> <span class="nv">Microsoft</span> <span class="nv">Windows</span> <span class="nv">Vista</span> <span class="nv">SP2</span><span class="p">,</span> <span class="nv">Windows</span> <span class="mi">7</span> <span class="nv">SP1</span><span class="p">,</span> <span class="s s-Atom">or</span> <span class="nv">Windows</span> <span class="nv">Server</span> <span class="mi">2008</span>
<span class="nv">Network</span> <span class="nv">Distance</span><span class="s s-Atom">:</span> <span class="mi">1</span> <span class="s s-Atom">hop</span>
<span class="nv">OS</span> <span class="s s-Atom">detection</span> <span class="s s-Atom">performed</span><span class="p">.</span> <span class="nv">Please</span> <span class="s s-Atom">report</span> <span class="s s-Atom">any</span> <span class="s s-Atom">incorrect</span> <span class="s s-Atom">results</span> <span class="s s-Atom">at</span> <span class="nn">http</span><span class="p">:</span><span class="o">//</span><span class="s s-Atom">nmap</span><span class="p">.</span><span class="s s-Atom">org</span><span class="o">/</span><span class="s s-Atom">submit</span><span class="o">/</span> <span class="p">.</span>
<span class="nv">Nmap</span> <span class="nn">done</span><span class="p">:</span> <span class="mi">1</span> <span class="nv">IP</span> <span class="nf">address</span> <span class="p">(</span><span class="mi">1</span> <span class="s s-Atom">host</span> <span class="s s-Atom">up</span><span class="p">)</span> <span class="s s-Atom">scanned</span> <span class="s s-Atom">in</span> <span class="mf">7.06</span> <span class="s s-Atom">seconds</span>
</code></pre></div>
<p>以及 Ubuntu 13.10:</p>
<div class="highlight"><pre><span></span><code>$ sudo nmap -O <span class="m">172</span>.16.21.134
Starting Nmap <span class="m">6</span>.40 <span class="o">(</span> http://nmap.org <span class="o">)</span> at <span class="m">2014</span>-04-24 <span class="m">09</span>:53 CST
Nmap scan report <span class="k">for</span> <span class="m">172</span>.16.21.134
Host is up <span class="o">(</span><span class="m">0</span>.00056s latency<span class="o">)</span>.
Not shown: <span class="m">996</span> closed ports
PORT STATE SERVICE
<span class="m">22</span>/tcp open ssh
<span class="m">80</span>/tcp open http
<span class="m">3260</span>/tcp open iscsi
<span class="m">3306</span>/tcp open mysql
MAC Address: <span class="m">00</span>:0C:29:2C:B2:55 <span class="o">(</span>VMware<span class="o">)</span>
No exact OS matches <span class="k">for</span> host <span class="o">(</span>If you know what OS is running on it, see http://nmap.org/submit/ <span class="o">)</span>.
TCP/IP fingerprint:
OS:SCAN<span class="o">(</span><span class="nv">V</span><span class="o">=</span><span class="m">6</span>.40%E<span class="o">=</span><span class="m">4</span>%D<span class="o">=</span><span class="m">4</span>/24%OT<span class="o">=</span><span class="m">22</span>%CT<span class="o">=</span><span class="m">1</span>%CU<span class="o">=</span><span class="m">33986</span>%PV<span class="o">=</span>Y%DS<span class="o">=</span><span class="m">1</span>%DC<span class="o">=</span>D%G<span class="o">=</span>Y%M<span class="o">=</span>000C29%T
OS:M<span class="o">=</span>53586E8E%P<span class="o">=</span>x86_64-unknown-linux-gnu<span class="o">)</span>SEQ<span class="o">(</span><span class="nv">SP</span><span class="o">=</span><span class="m">105</span>%GCD<span class="o">=</span><span class="m">1</span>%ISR<span class="o">=</span>10F%TI<span class="o">=</span>Z%CI<span class="o">=</span>I
OS:%II<span class="o">=</span>I%TS<span class="o">=</span><span class="m">8</span><span class="o">)</span>OPS<span class="o">(</span><span class="nv">O1</span><span class="o">=</span>M5B4ST11NW7%O2<span class="o">=</span>M5B4ST11NW7%O3<span class="o">=</span>M5B4NNT11NW7%O4<span class="o">=</span>M5B4ST11
OS:NW7%O5<span class="o">=</span>M5B4ST11NW7%O6<span class="o">=</span>M5B4ST11<span class="o">)</span>WIN<span class="o">(</span><span class="nv">W1</span><span class="o">=</span><span class="m">7120</span>%W2<span class="o">=</span><span class="m">7120</span>%W3<span class="o">=</span><span class="m">7120</span>%W4<span class="o">=</span><span class="m">7120</span>%W5<span class="o">=</span><span class="m">71</span>
OS:20%W6<span class="o">=</span><span class="m">7120</span><span class="o">)</span>ECN<span class="o">(</span><span class="nv">R</span><span class="o">=</span>Y%DF<span class="o">=</span>Y%T<span class="o">=</span><span class="m">40</span>%W<span class="o">=</span><span class="m">7210</span>%O<span class="o">=</span>M5B4NNSNW7%CC<span class="o">=</span>Y%Q<span class="o">=)</span>T1<span class="o">(</span><span class="nv">R</span><span class="o">=</span>Y%DF<span class="o">=</span>Y%T<span class="o">=</span><span class="m">4</span>
OS:0%S<span class="o">=</span>O%A<span class="o">=</span>S+%F<span class="o">=</span>AS%RD<span class="o">=</span><span class="m">0</span>%Q<span class="o">=)</span>T2<span class="o">(</span><span class="nv">R</span><span class="o">=</span>N<span class="o">)</span>T3<span class="o">(</span><span class="nv">R</span><span class="o">=</span>N<span class="o">)</span>T4<span class="o">(</span><span class="nv">R</span><span class="o">=</span>Y%DF<span class="o">=</span>Y%T<span class="o">=</span><span class="m">40</span>%W<span class="o">=</span><span class="m">0</span>%S<span class="o">=</span>A%A<span class="o">=</span>Z%F<span class="o">=</span>R%O
OS:<span class="o">=</span>%RD<span class="o">=</span><span class="m">0</span>%Q<span class="o">=)</span>T5<span class="o">(</span><span class="nv">R</span><span class="o">=</span>Y%DF<span class="o">=</span>Y%T<span class="o">=</span><span class="m">40</span>%W<span class="o">=</span><span class="m">0</span>%S<span class="o">=</span>Z%A<span class="o">=</span>S+%F<span class="o">=</span>AR%O<span class="o">=</span>%RD<span class="o">=</span><span class="m">0</span>%Q<span class="o">=)</span>T6<span class="o">(</span><span class="nv">R</span><span class="o">=</span>Y%DF<span class="o">=</span>Y%T<span class="o">=</span><span class="m">40</span>
OS:%W<span class="o">=</span><span class="m">0</span>%S<span class="o">=</span>A%A<span class="o">=</span>Z%F<span class="o">=</span>R%O<span class="o">=</span>%RD<span class="o">=</span><span class="m">0</span>%Q<span class="o">=)</span>T7<span class="o">(</span><span class="nv">R</span><span class="o">=</span>Y%DF<span class="o">=</span>Y%T<span class="o">=</span><span class="m">40</span>%W<span class="o">=</span><span class="m">0</span>%S<span class="o">=</span>Z%A<span class="o">=</span>S+%F<span class="o">=</span>AR%O<span class="o">=</span>%RD<span class="o">=</span><span class="m">0</span>%Q
OS:<span class="o">=)</span>U1<span class="o">(</span><span class="nv">R</span><span class="o">=</span>Y%DF<span class="o">=</span>N%T<span class="o">=</span><span class="m">40</span>%IPL<span class="o">=</span><span class="m">164</span>%UN<span class="o">=</span><span class="m">0</span>%RIPL<span class="o">=</span>G%RID<span class="o">=</span>G%RIPCK<span class="o">=</span>G%RUCK<span class="o">=</span>G%RUD<span class="o">=</span>G<span class="o">)</span>IE<span class="o">(</span><span class="nv">R</span><span class="o">=</span>Y
OS:%DFI<span class="o">=</span>N%T<span class="o">=</span><span class="m">40</span>%CD<span class="o">=</span>S<span class="o">)</span>
Network Distance: <span class="m">1</span> hop
OS detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap <span class="k">done</span>: <span class="m">1</span> IP address <span class="o">(</span><span class="m">1</span> host up<span class="o">)</span> scanned <span class="k">in</span> <span class="m">12</span>.22 seconds
</code></pre></div>
<p>只有 Windows 7 可以被偵測出來,此時可以使用另一個選項 <code>--osscan-guess</code>,nmap會列出可能作業系統的機率</p>
<div class="highlight"><pre><span></span><code>$ sudo nmap -O --osscan-guess localhost
Starting Nmap <span class="m">6</span>.40 <span class="o">(</span> http://nmap.org <span class="o">)</span> at <span class="m">2014</span>-04-24 <span class="m">09</span>:56 CST
Nmap scan report <span class="k">for</span> localhost <span class="o">(</span><span class="m">127</span>.0.0.1<span class="o">)</span>
Host is up <span class="o">(</span><span class="m">0</span>.000070s latency<span class="o">)</span>.
Not shown: <span class="m">997</span> closed ports
PORT STATE SERVICE
<span class="m">631</span>/tcp open ipp
<span class="m">902</span>/tcp open iss-realsecure
<span class="m">4242</span>/tcp open vrml-multi-use
Aggressive OS guesses: Linux <span class="m">3</span>.7 - <span class="m">3</span>.9 <span class="o">(</span><span class="m">98</span>%<span class="o">)</span>, Netgear DG834G WAP or Western Digital WD TV media player <span class="o">(</span><span class="m">96</span>%<span class="o">)</span>, Linux <span class="m">3</span>.8 <span class="o">(</span><span class="m">95</span>%<span class="o">)</span>, Linux <span class="m">3</span>.1 <span class="o">(</span><span class="m">93</span>%<span class="o">)</span>, Linux <span class="m">3</span>.2 <span class="o">(</span><span class="m">93</span>%<span class="o">)</span>, AXIS 210A or <span class="m">211</span> Network Camera <span class="o">(</span>Linux <span class="m">2</span>.6<span class="o">)</span> <span class="o">(</span><span class="m">92</span>%<span class="o">)</span>, Linux <span class="m">3</span>.7 <span class="o">(</span><span class="m">92</span>%<span class="o">)</span>, Linux <span class="m">3</span>.9 <span class="o">(</span><span class="m">91</span>%<span class="o">)</span>, Crestron XPanel control system <span class="o">(</span><span class="m">91</span>%<span class="o">)</span>, Linux <span class="m">2</span>.4.26 <span class="o">(</span>Slackware <span class="m">10</span>.0.0<span class="o">)</span> <span class="o">(</span><span class="m">91</span>%<span class="o">)</span>
No exact OS matches <span class="k">for</span> host <span class="o">(</span>If you know what OS is running on it, see http://nmap.org/submit/ <span class="o">)</span>.
TCP/IP fingerprint:
OS:SCAN<span class="o">(</span><span class="nv">V</span><span class="o">=</span><span class="m">6</span>.40%E<span class="o">=</span><span class="m">4</span>%D<span class="o">=</span><span class="m">4</span>/24%OT<span class="o">=</span><span class="m">631</span>%CT<span class="o">=</span><span class="m">1</span>%CU<span class="o">=</span><span class="m">44228</span>%PV<span class="o">=</span>N%DS<span class="o">=</span><span class="m">0</span>%DC<span class="o">=</span>L%G<span class="o">=</span>Y%TM<span class="o">=</span>53586F
OS:70%P<span class="o">=</span>x86_64-unknown-linux-gnu<span class="o">)</span>SEQ<span class="o">(</span><span class="nv">SP</span><span class="o">=</span><span class="m">105</span>%GCD<span class="o">=</span><span class="m">1</span>%ISR<span class="o">=</span>10D%TI<span class="o">=</span>Z%CI<span class="o">=</span>I%II<span class="o">=</span>I%TS
OS:<span class="o">=</span><span class="m">8</span><span class="o">)</span>OPS<span class="o">(</span><span class="nv">O1</span><span class="o">=</span>MFFD7ST11NW7%O2<span class="o">=</span>MFFD7ST11NW7%O3<span class="o">=</span>MFFD7NNT11NW7%O4<span class="o">=</span>MFFD7ST11NW7%
OS:O5<span class="o">=</span>MFFD7ST11NW7%O6<span class="o">=</span>MFFD7ST11<span class="o">)</span>WIN<span class="o">(</span><span class="nv">W1</span><span class="o">=</span>AAAA%W2<span class="o">=</span>AAAA%W3<span class="o">=</span>AAAA%W4<span class="o">=</span>AAAA%W5<span class="o">=</span>AAAA
OS:%W6<span class="o">=</span>AAAA<span class="o">)</span>ECN<span class="o">(</span><span class="nv">R</span><span class="o">=</span>Y%DF<span class="o">=</span>Y%T<span class="o">=</span><span class="m">40</span>%W<span class="o">=</span>AAAA%O<span class="o">=</span>MFFD7NNSNW7%CC<span class="o">=</span>Y%Q<span class="o">=)</span>T1<span class="o">(</span><span class="nv">R</span><span class="o">=</span>Y%DF<span class="o">=</span>Y%T<span class="o">=</span><span class="m">40</span>
OS:%S<span class="o">=</span>O%A<span class="o">=</span>S+%F<span class="o">=</span>AS%RD<span class="o">=</span><span class="m">0</span>%Q<span class="o">=)</span>T2<span class="o">(</span><span class="nv">R</span><span class="o">=</span>N<span class="o">)</span>T3<span class="o">(</span><span class="nv">R</span><span class="o">=</span>N<span class="o">)</span>T4<span class="o">(</span><span class="nv">R</span><span class="o">=</span>Y%DF<span class="o">=</span>Y%T<span class="o">=</span><span class="m">40</span>%W<span class="o">=</span><span class="m">0</span>%S<span class="o">=</span>A%A<span class="o">=</span>Z%F<span class="o">=</span>R%O<span class="o">=</span>
OS:%RD<span class="o">=</span><span class="m">0</span>%Q<span class="o">=)</span>T5<span class="o">(</span><span class="nv">R</span><span class="o">=</span>Y%DF<span class="o">=</span>Y%T<span class="o">=</span><span class="m">40</span>%W<span class="o">=</span><span class="m">0</span>%S<span class="o">=</span>Z%A<span class="o">=</span>S+%F<span class="o">=</span>AR%O<span class="o">=</span>%RD<span class="o">=</span><span class="m">0</span>%Q<span class="o">=)</span>T6<span class="o">(</span><span class="nv">R</span><span class="o">=</span>Y%DF<span class="o">=</span>Y%T<span class="o">=</span><span class="m">40</span>%
OS:W<span class="o">=</span><span class="m">0</span>%S<span class="o">=</span>A%A<span class="o">=</span>Z%F<span class="o">=</span>R%O<span class="o">=</span>%RD<span class="o">=</span><span class="m">0</span>%Q<span class="o">=)</span>T7<span class="o">(</span><span class="nv">R</span><span class="o">=</span>Y%DF<span class="o">=</span>Y%T<span class="o">=</span><span class="m">40</span>%W<span class="o">=</span><span class="m">0</span>%S<span class="o">=</span>Z%A<span class="o">=</span>S+%F<span class="o">=</span>AR%O<span class="o">=</span>%RD<span class="o">=</span><span class="m">0</span>%Q<span class="o">=</span>
OS:<span class="o">)</span>U1<span class="o">(</span><span class="nv">R</span><span class="o">=</span>Y%DF<span class="o">=</span>N%T<span class="o">=</span><span class="m">40</span>%IPL<span class="o">=</span><span class="m">164</span>%UN<span class="o">=</span><span class="m">0</span>%RIPL<span class="o">=</span>G%RID<span class="o">=</span>G%RIPCK<span class="o">=</span>G%RUCK<span class="o">=</span>G%RUD<span class="o">=</span>G<span class="o">)</span>IE<span class="o">(</span><span class="nv">R</span><span class="o">=</span>Y%
OS:DFI<span class="o">=</span>N%T<span class="o">=</span><span class="m">40</span>%CD<span class="o">=</span>S<span class="o">)</span>
Network Distance: <span class="m">0</span> hops
OS detection performed. Please report any incorrect results at http://nmap.org/submit/ .
Nmap <span class="k">done</span>: <span class="m">1</span> IP address <span class="o">(</span><span class="m">1</span> host up<span class="o">)</span> scanned <span class="k">in</span> <span class="m">11</span>.96 seconds
</code></pre></div>
<h2>zenmap</h2>
<p>GUI 介面的 zenmap</p>NTP note2014-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-01-01:/ntp/<p>使用 ntpd 來跟上行的 server 是不會立即更新時間的。</p>
<h1>新增 NTP Server</h1>
<p>把 server 加到 /etc/ntp.conf</p>
<div class="highlight"><pre><span></span><code>server tick.stdtime.gov.tw
</code></pre></div>
<h1>觀察目前連線的狀態</h1>
<div class="highlight"><pre><span></span><code>~ # ntpq -p
remote refid st t when poll reach delay offset jitter
==============================================================================
118-163-81-62.H 192.168.0.2 2 u 7 64 3 13.063 546.533 61.627
</code></pre></div>Using Perforce Command Line in Linux2014-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-01-01:/perforce-cmd/<h2>Installation (Linux)</h2>
<ol>
<li>
<p>Download P4 binary from http://www.perforce.com/downloads/complete_list</p>
<p>$ wget http://www.perforce.com/downloads/perforce/r11.1/bin.linux26x86_64/p4 (x64)
$ wget http://www.perforce.com/downloads/perforce/r11.1/bin.linux26x86/p4 (x86)</p>
</li>
<li>
<p>Make the downloaded file executable</p>
<p>$ chmod +x p4</p>
</li>
<li>
<p>Print p4 version</p>
<p>$ ./p4 -V</p>
</li>
</ol>
<h2>Perforce client common commands</h2>
<div class="highlight"><pre><span></span><code><span class="o">./</span><span class="n">p4</span> <span class="o">-</span><span class="n">p</span> <span class="mf">10.200</span><span class="o">.</span><span class="mf">19.19</span><span class="p">:</span><span class="mi">1667</span> <span class="o">-</span><span class="n">u</span> <span class="err">`</span><span class="o"><</span><span class="n">YOUR_ACCOUNT</span><span class="o">></span><span class="err">`</span> <span class="n">login</span>
<span class="k">export</span> <span class="n">P4PORT</span><span class="o">=</span><span class="mf">10.200</span><span class="o">.</span><span class="mf">19.19</span><span class="p">:</span><span class="mi">1667</span>
<span class="o">./</span><span class="n">p4</span> <span class="o">-</span><span class="n">u</span> <span class="err">`</span><span class="o"><</span><span class="n">USERNAME</span><span class="o">></span><span class="err">`</span> <span class="o">-</span><span class="n">c</span> <span class="err">`</span><span class="o"><</span><span class="n">WORK_SPACE</span><span class="o">></span><span class="err">`</span> <span class="n">sync</span> <span class="o">-</span><span class="n">f</span>
</code></pre></div>Redis 筆記2014-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-01-01:/redis/<p>啟動 server </p>
<div class="highlight"><pre><span></span><code>$ redis-server
</code></pre></div>
<p>關閉 server</p>
<div class="highlight"><pre><span></span><code>$ redis-server shutdown
</code></pre></div>
<p>測試伺服器是不是正常</p>
<div class="highlight"><pre><span></span><code>$ redis-cli ping
</code></pre></div>
<p>指令伺服器位置 </p>
<div class="highlight"><pre><span></span><code>$ redis-cli -h <HOST> -p <PORT> -a <PASSWORD>
</code></pre></div>
<h1>常用指令</h1>
<p>列出所有的 keys</p>
<div class="highlight"><pre><span></span><code>> key *
</code></pre></div>
<p>清空資料庫</p>
<div class="highlight"><pre><span></span><code>> flushdb
</code></pre></div>
<!--# cache
- EXPIRE
- TTL
- [Redis Quick Start – Redis](http://redis.io/topics/quickstart)
## Persistence storage
[Redis Persistence – Redis](http://redis.io/topics/persistence) -->畫 Sequence Diagram 的線上工具: Web Sequence Diagrams2014-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-01-01:/sequence-diagram/<p><a href="https://www.websequencediagrams.com/#">Web Sequence Diagrams</a>
畫 Sequence diagram 的線上工具,介面很直觀簡單:</p>
<p><img alt="demo" src="https://i.imgur.com/fKFFhCm.png"></p>
<p>用以下的文字即可簡單表達一張 sequence diagram</p>
<div class="highlight"><pre><span></span><code><span class="n">title</span> <span class="n">SIP</span> <span class="n">Account</span> <span class="n">server</span>
<span class="n">Client</span> <span class="o">-></span> <span class="n">API</span> <span class="n">Server</span><span class="o">:</span> <span class="o">/</span><span class="n">api</span><span class="o">/</span><span class="n">v1</span><span class="o">/</span><span class="n">users</span><span class="o">/</span>
<span class="n">API</span> <span class="n">Server</span> <span class="o">-></span> <span class="n">Microsoft</span> <span class="nf">Graph</span> <span class="n">Server</span><span class="o">:</span> <span class="n">Check</span> <span class="n">access_token</span>
<span class="n">Microsoft</span> <span class="nf">Graph</span> <span class="n">Server</span> <span class="o">-></span> <span class="n">API</span> <span class="n">Server</span><span class="o">:</span> <span class="n">Response</span> <span class="n">check</span> <span class="n">result</span>
<span class="n">API</span> <span class="n">Server</span> <span class="o">-></span> <span class="n">Client</span><span class="o">:</span> <span class="n">Response</span> <span class="n">SIP</span> <span class="n">account</span> <span class="n">info</span>
</code></pre></div>
<p>就可以產生出以下的圖檔了:</p>
<p><img alt="xx" src="https://i.imgur.com/R7jJ1ax.png"></p>Execute Sikuli Script at Jython level on Windows 72014-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-01-01:/sikuli/<ol>
<li>
<p>Install JRE 32-bit</p>
</li>
<li>
<p>Install Sikuli </p>
<p>https://launchpad.net/sikuli/sikuli-api/1.0.0/+download/Sikuli-IDE-1.0.0-Win32.zip</p>
</li>
<li>
<p>Set Environment </p>
<p>JYTHONPATH=C:\jython2.5.1\Lib;C:\Sikuli-IDE-1.0.0-Win32\sikuli-script.jar\Lib
CLASSPATH=C:\Sikuli-IDE-1.0.0-Win32\sikuli-script.jar
PATH=C:\Program Files\Java\jre7\bin;C:\jython2.5.1\bin;C:\Sikuli-IDE-1.0.0-Win32\libs
SIKULI_HOME=C:\Sikuli-IDE-1.0.0-Win32</p>
</li>
<li>
<p>Sikuli sciprt </p>
</li>
</ol>
<p>example: </p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">sikuli.Sikuli</span> <span class="kn">import</span> <span class="o">*</span>
<span class="n">doubleClick</span><span class="p">(</span><span class="sa">r</span><span class="s2">"C:\siku.sikuli\1370345639170.png"</span><span class="p">)</span>
</code></pre></div>
<h1>Install Sikuli-IDE on Ubuntu 12.04</h1>
<div class="highlight"><pre><span></span><code>sudo apt-get install sikuli-ide
sudo apt-get install libopencv-*
</code></pre></div>
<h1>Reference :</h1>
<ul>
<li><a href="http://ccaloha.cc/blog/2012/10/16/installation-guide-robotframework-2-dot-7-4-plus-sikuli-plus-databaselibrary-plus-sshlibrary-plus-seleniumlibrary-jybot-and-pybot-in-ubuntu-12-dot-04/">[Installation Guide] RobotFramework 2.7.4 + Sikuli + DatabaseLibrary +SSHLibrary …</a></li></ul><ol>
<li>
<p>Install JRE 32-bit</p>
</li>
<li>
<p>Install Sikuli </p>
<p>https://launchpad.net/sikuli/sikuli-api/1.0.0/+download/Sikuli-IDE-1.0.0-Win32.zip</p>
</li>
<li>
<p>Set Environment </p>
<p>JYTHONPATH=C:\jython2.5.1\Lib;C:\Sikuli-IDE-1.0.0-Win32\sikuli-script.jar\Lib
CLASSPATH=C:\Sikuli-IDE-1.0.0-Win32\sikuli-script.jar
PATH=C:\Program Files\Java\jre7\bin;C:\jython2.5.1\bin;C:\Sikuli-IDE-1.0.0-Win32\libs
SIKULI_HOME=C:\Sikuli-IDE-1.0.0-Win32</p>
</li>
<li>
<p>Sikuli sciprt </p>
</li>
</ol>
<p>example: </p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">sikuli.Sikuli</span> <span class="kn">import</span> <span class="o">*</span>
<span class="n">doubleClick</span><span class="p">(</span><span class="sa">r</span><span class="s2">"C:\siku.sikuli\1370345639170.png"</span><span class="p">)</span>
</code></pre></div>
<h1>Install Sikuli-IDE on Ubuntu 12.04</h1>
<div class="highlight"><pre><span></span><code>sudo apt-get install sikuli-ide
sudo apt-get install libopencv-*
</code></pre></div>
<h1>Reference :</h1>
<ul>
<li><a href="http://ccaloha.cc/blog/2012/10/16/installation-guide-robotframework-2-dot-7-4-plus-sikuli-plus-databaselibrary-plus-sshlibrary-plus-seleniumlibrary-jybot-and-pybot-in-ubuntu-12-dot-04/">[Installation Guide] RobotFramework 2.7.4 + Sikuli + DatabaseLibrary +SSHLibrary + Seleniumlibrary (jybot and pybot)in Ubuntu 12.04 - AlohaCC</a></li>
</ul>Install TeamView 9 in Ubuntu2014-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-01-01:/teamviewer/<h2>Install TeamView Ubuntu 13.10 64-bit</h2>
<div class="highlight"><pre><span></span><code><span class="o">$</span> <span class="n">cd</span> <span class="o">~/</span><span class="n">Downloads</span><span class="o">/</span> <span class="o">&&</span> <span class="n">wget</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">download</span><span class="o">.</span><span class="n">teamviewer</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">download</span><span class="o">/</span><span class="n">version_9x</span><span class="o">/</span><span class="n">teamviewer_linux</span><span class="o">.</span><span class="n">deb</span>
<span class="o">$</span> <span class="n">sudo</span> <span class="n">apt</span><span class="o">-</span><span class="n">get</span> <span class="n">install</span> <span class="n">gdebi</span>
<span class="o">$</span> <span class="n">sudo</span> <span class="n">gdebi</span> <span class="o">~/</span><span class="n">Downloads</span><span class="o">/</span><span class="n">teamviewer_linux</span><span class="o">.</span><span class="n">deb</span>
</code></pre></div>
<h2>讓 TeamView 不要偷偷在背景執行</h2>
<div class="highlight"><pre><span></span><code>sudo teamviewer --daemon disable
</code></pre></div>
<h2>Reference</h2>
<ul>
<li><a href="http://ubuntuhandbook.org/index.php/2013/11/install-teamviewer-9-beta-new-features/">Install TeamViewer 9 Beta in Ubuntu [Great New Features include] | UbuntuHandbook</a></li>
<li><a href="https://play.google.com/store/apps/details?id=com.teamviewer.quicksupport.market">TeamViewer QuickSupport - Google Play Android 應用程式</a></li>
</ul>ThinkPad x2202014-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-01-01:/thinkpad-x220/<p><code>再見了,小黑(2011/5 - 2014/8)。願你在新的主人那邊可以有繼續發揮的空間</code></p>
<p>把小黑賣掉,主要的原因是斷捨離的概念,讓我決定放下。另一方面也是對於 Lenovo 沒辦法在創造出新價值,有點失望。用腳投票,投入蘋果陣營。</p>
<h2>X220 美規機(過保)</h2>
<ul>
<li>CPU : i5 2410m</li>
<li>RAM : 海盜船 16GB (8GB x 2) </li>
<li>硬碟 : SATA 320GB, Masta SSD Intel 320 80GB</li>
<li>螢幕 : 自換 IPS 面板</li>
<li>電池 : 6 cell x1, 9cell x1</li>
<li>電源供應器: 65W 充電器 x1 + 原廠 90W 充電器 x 1</li>
<li>Express Card : </li>
<li>ATM 晶片卡 Smart card reader, 可以ATM轉帳,網路報稅</li>
<li>AKE USB 3.0 ExpressCard : 多二個 USB 3.0 孔</li>
<li>Windows 7 序號</li>
<li>USB 外接鍵盤</li>
</ul>Tmux Notes2014-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2014-01-01:/tmux/<p>Default pefix key <code><Prefix></code> is Ctrl+b</p>
<h1>Installation</h1>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install tmux
</code></pre></div>
<h1>config</h1>
<div class="highlight"><pre><span></span><code>~/.tmux.conf
</code></pre></div>
<p>Reload</p>
<div class="highlight"><pre><span></span><code>$ tmux source-file ~/.tmux.conf
</code></pre></div>
<h1>Attach</h1>
<div class="highlight"><pre><span></span><code>$ tmux attach
</code></pre></div>
<h1>視窗(Windows)</h1>
<ul>
<li>新增一個視窗<code><Prefix>c</code></li>
<li>下一個視窗<code><Prefix>n</code></li>
<li>上一個視窗<code><Prefix>p</code></li>
<li>選單 <code><Prefix>w</code></li>
<li>關視窗<code><Prefix>x</code></li>
</ul>
<h1>Panes</h1>
<ul>
<li>水平分割 <code><Prefix>%</code></li>
<li>垂直分割 <code><Prefix>"</code></li>
<li>Resize <code><Prefix><Meta-Up[Down][Left][Right]></code></li>
<li>Close <code><Prefix>x</code></li>
</ul>
<h1>視窗(Windows)</h1>
<ul>
<li>新增一個視窗<code><Prefix>c</code></li>
<li>下一個視窗<code><Prefix>n</code></li>
<li>上一個視窗<code><Prefix>n</code></li>
<li>選單 <code><Prefix>w</code></li>
<li>關視窗<code><Prefix>x</code></li>
<li>重新命名<code><Prefix>,</code></li>
</ul>
<h1>More</h1>
<ul>
<li><a href="http://www.dayid.org/os/- notes/tm.html">dayid's screen and tmux cheat sheet</a></li>
<li><a href="http://www.openbsd.org/cgi-bin/man.cgi?query=tmux&sektion=1">Manual Pages: tmux(1)</a></li>
<li><a href="https://www.youtube.com/watch?v=wKEGA8oEWXw">▶ tmux Quick Start - YouTube</a>
http://blog.chh.tw/posts/tmux-terminal-multiplexer/</li>
<li><a href="http://josephj.com/entry.php?id=373">進化版 screen - tmux</a></li>
</ul>Using Pafers heart rate monitor on a Android 4.3 phone2013-12-28T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-12-28:/running-heart-rate-ble/<p><img alt="pafers" src="https://lh3.googleusercontent.com/-W8kvIJP66r0/Ur7WLN8cqkI/AAAAAAAFHik/pUcLFUhr8B8/w570-h300-no/HR-KIT.JPG"></p>
<p><strong>For short: You can use <a href="http://www.pafers.com/en/products/hr_kit">PAFERS</a> on <a href="https://play.google.com/store/apps/details?id=com.pribble.htc.ble.hrm&hl=zh_TW">BLE Heart Rate Monitor</a> app without any probelm</strong></p>
<h2>Find a heart rate monitor on Android</h2>
<p>For android phone, it's hard to find a cheap heart rate belt monitor. Some cheap heart rate monitors supprt only ANT+ protocol like <code>Xplova XA-HR2</code> or <code>PAPAGO! ANT+</code>, you need a GPS running watch to conntect with. For smart phones, we can only use a heart rate monitor that supports bluetooth. However, the most of bluetooth heart rate monitors are using bluetooth 4.0 protocol. </p>
<p>Until versoin 4.3, Android supports bluettoth 4.0 and BLE(bluetooth low …</p><p><img alt="pafers" src="https://lh3.googleusercontent.com/-W8kvIJP66r0/Ur7WLN8cqkI/AAAAAAAFHik/pUcLFUhr8B8/w570-h300-no/HR-KIT.JPG"></p>
<p><strong>For short: You can use <a href="http://www.pafers.com/en/products/hr_kit">PAFERS</a> on <a href="https://play.google.com/store/apps/details?id=com.pribble.htc.ble.hrm&hl=zh_TW">BLE Heart Rate Monitor</a> app without any probelm</strong></p>
<h2>Find a heart rate monitor on Android</h2>
<p>For android phone, it's hard to find a cheap heart rate belt monitor. Some cheap heart rate monitors supprt only ANT+ protocol like <code>Xplova XA-HR2</code> or <code>PAPAGO! ANT+</code>, you need a GPS running watch to conntect with. For smart phones, we can only use a heart rate monitor that supports bluetooth. However, the most of bluetooth heart rate monitors are using bluetooth 4.0 protocol. </p>
<p>Until versoin 4.3, Android supports bluettoth 4.0 and BLE(bluetooth low energy). Upgrading my New HTC One to 4.3, I bought <a href="http://www.pafers.com/en/products/hr_kit">PAFERS</a>. For now, most of running apps don't support BLE heart rate monitor. I finally found a compatible android app <a href="https://play.google.com/store/apps/details?id=com.pribble.htc.ble.hrm&hl=zh_TW">BLE Heart Rate Monitor</a>. Although it's not offical support android by Pafers yet, but it works. :)</p>
<h2>Apps screenshots</h2>
<p><img alt="chart" src="https://lh5.googleusercontent.com/-RUB79tH6x3g/Ur7QpxmWLRI/AAAAAAAFHiI/DM95ZztDbLY/w995-h560-no/Screenshot_2013-12-25-12-51-27.png">
<img alt="summary" src="https://lh5.googleusercontent.com/-PEu9vw6mZGc/Ur7QqxxSIUI/AAAAAAAFHiQ/tr-_AsmZ1r8/w318-h565-no/Screenshot_2013-12-25-13-24-01.png"></p>關鍵18分鐘(18 Minutes)筆記2013-12-16T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-12-16:/18-minutes/<p><img alt="18 minutes" src="https://lh5.googleusercontent.com/-Qg1ayFzMuz0/UtdQOHDQGPI/AAAAAAAFHpg/6RdFRtpW4kw/s300-no/18-minutes.jpg"></p>
<p>作者Bregman在這本書提到要如何找到人生的focus,提出了四個原則:</p>
<ol>
<li>Leveraging my Strengths</li>
<li>Embracing my Weaknesses</li>
<li>Asserting my differences</li>
<li>Pursuing my passion</li>
</ol>
<h1>所謂的18分鐘</h1>
<ol>
<li>早晨的規劃(5分鐘): 決定如何讓今天是成功的一天</li>
<li>重新專注(1分鐘/小時): </li>
</ol>
<h1>產生動機的三個秘密</h1>
<p>成就動機理論(Achievement Motivation Theory),又稱三種需要理論(Three Needs Theory),由心理學家<a href="http://en.wikipedia.org/wiki/David_McClelland">大衛·麥克利蘭</a>提出。</p>
<ul>
<li>成就(Achievement): 渴望挑戰與成功</li>
<li>認同(Affiliation): 渴望建立友好的人際關係</li>
<li>權力(Power): 渴望較高地會地位,影響別人與得到自我的尊重</li>
</ul>
<p>當人有機會得到<code>成就</code>、<code>認同</code>、<code>權力</code>。就算沒有一個明確的願景,他們仍然會自動自發。而對於不同個性,對於這三種需要的成份就不太一樣。對以上三種需要分別施以不同的激勵措施:</p>
<ul>
<li>需要<code>成就</code>:及時給與其工作績效的明確反饋信息,使其了解自己是否有所進步;為其設立具有適度挑戰性的目標,避免為其設置特別容易或特別難的任務</li>
<li>需要<code>權力</code>者: 設立具有競爭性和體現較高地位的工作場合和情境</li>
<li>需要<code>認同</code>者: 設立合作而非競爭的工作環境</li>
</ul>
<h2>Inbox three day rule [25]</h2>
<p>定期清理 Todo list 的 Inbox,當一個事項待超過三天就代表他該被處理了,建議是下列四種之一</p>
<ol>
<li>馬上做(Do It immediately)</li>
<li>排定確切的行事曆中(Schedule It)</li>
<li>就直接刪除吧(Let it go),也許他不是那麼重要</li>
<li>丟到 <code>Someday/Maybe</code> List,以後心寫來潮的時侯再挑來做。</li>
</ol>
<h2>節錄</h2>
<ul>
<li>The time to …</li></ul><p><img alt="18 minutes" src="https://lh5.googleusercontent.com/-Qg1ayFzMuz0/UtdQOHDQGPI/AAAAAAAFHpg/6RdFRtpW4kw/s300-no/18-minutes.jpg"></p>
<p>作者Bregman在這本書提到要如何找到人生的focus,提出了四個原則:</p>
<ol>
<li>Leveraging my Strengths</li>
<li>Embracing my Weaknesses</li>
<li>Asserting my differences</li>
<li>Pursuing my passion</li>
</ol>
<h1>所謂的18分鐘</h1>
<ol>
<li>早晨的規劃(5分鐘): 決定如何讓今天是成功的一天</li>
<li>重新專注(1分鐘/小時): </li>
</ol>
<h1>產生動機的三個秘密</h1>
<p>成就動機理論(Achievement Motivation Theory),又稱三種需要理論(Three Needs Theory),由心理學家<a href="http://en.wikipedia.org/wiki/David_McClelland">大衛·麥克利蘭</a>提出。</p>
<ul>
<li>成就(Achievement): 渴望挑戰與成功</li>
<li>認同(Affiliation): 渴望建立友好的人際關係</li>
<li>權力(Power): 渴望較高地會地位,影響別人與得到自我的尊重</li>
</ul>
<p>當人有機會得到<code>成就</code>、<code>認同</code>、<code>權力</code>。就算沒有一個明確的願景,他們仍然會自動自發。而對於不同個性,對於這三種需要的成份就不太一樣。對以上三種需要分別施以不同的激勵措施:</p>
<ul>
<li>需要<code>成就</code>:及時給與其工作績效的明確反饋信息,使其了解自己是否有所進步;為其設立具有適度挑戰性的目標,避免為其設置特別容易或特別難的任務</li>
<li>需要<code>權力</code>者: 設立具有競爭性和體現較高地位的工作場合和情境</li>
<li>需要<code>認同</code>者: 設立合作而非競爭的工作環境</li>
</ul>
<h2>Inbox three day rule [25]</h2>
<p>定期清理 Todo list 的 Inbox,當一個事項待超過三天就代表他該被處理了,建議是下列四種之一</p>
<ol>
<li>馬上做(Do It immediately)</li>
<li>排定確切的行事曆中(Schedule It)</li>
<li>就直接刪除吧(Let it go),也許他不是那麼重要</li>
<li>丟到 <code>Someday/Maybe</code> List,以後心寫來潮的時侯再挑來做。</li>
</ol>
<h2>節錄</h2>
<ul>
<li>The time to judge your successes or failures is never [19]</li>
<li>Do fewer things, select your <code>Big 5</code> annual focus. Focus don't need to be goals [20]</li>
<li>把每一個事項歸類到 Annual Focus。讓每一個Focus達到平衡 [22]</li>
<li>Ignore list. How easily we get distracted and how many distractions we have these days. [23]</li>
<li>To-do list and Ignore list are your map for each day. [23]</li>
<li>To-do list is useful as <code>collection tool</code> [24]</li>
<li>If you really want to get something done, decide <code>when</code> and <code>where</code> you are going to do it [24]</li>
<li>Chime at every hour to retrospect what you did in the last hour [26]</li>
<li>We often do many things right but then fail to repeat them.[27]</li>
<li>Thinking aout what you learned and with whom you should connect. [27]</li>
</ul>
<!--
- Pause Hover Above Your World
- What is this Year About? Find Your Focus
- What is this Day About? Get the Right Things Done
- What is this Moment About? Mastering Distraction
-->Route notes2013-12-16T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-12-16:/route/<h1>不同的目的IP走不同的 Interface</h1>
<div class="highlight"><pre><span></span><code><span class="nv">route</span> <span class="nv">change</span> <span class="mi">10</span>.<span class="mi">1</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="nv">mask</span> <span class="mi">255</span>.<span class="mi">255</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="mi">10</span>.<span class="mi">201</span>.<span class="mi">128</span>.<span class="mi">1</span> <span class="k">if</span> <span class="mi">13</span> <span class="nv">metric</span> <span class="mi">150</span>
<span class="nv">route</span> <span class="nv">add</span> <span class="mi">10</span>.<span class="mi">45</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="nv">mask</span> <span class="mi">255</span>.<span class="mi">255</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="mi">10</span>.<span class="mi">1</span>.<span class="mi">247</span>.<span class="mi">254</span> <span class="k">if</span> <span class="mi">10</span> <span class="nv">metric</span> <span class="mi">1</span>
<span class="nv">route</span> <span class="nv">add</span> <span class="mi">10</span>.<span class="mi">1</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="nv">mask</span> <span class="mi">255</span>.<span class="mi">255</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="mi">10</span>.<span class="mi">1</span>.<span class="mi">247</span>.<span class="mi">254</span> <span class="k">if</span> <span class="mi">10</span> <span class="nv">metric</span> <span class="mi">1</span>
<span class="nv">route</span> <span class="nv">add</span> <span class="mi">10</span>.<span class="mi">28</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="nv">mask</span> <span class="mi">255</span>.<span class="mi">255</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="mi">10</span>.<span class="mi">1</span>.<span class="mi">247</span>.<span class="mi">254</span> <span class="k">if</span> <span class="mi">10</span> <span class="nv">metric</span> <span class="mi">1</span>
<span class="nv">route</span> <span class="nv">add</span> <span class="mi">211</span>.<span class="mi">76</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="nv">mask</span> <span class="mi">255</span>.<span class="mi">255</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="mi">10</span>.<span class="mi">1</span>.<span class="mi">247</span>.<span class="mi">254</span> <span class="k">if</span> <span class="mi">10</span> <span class="nv">metric</span> <span class="mi">1</span>
</code></pre></div>
<h1>Add Route Rule …</h1><h1>不同的目的IP走不同的 Interface</h1>
<div class="highlight"><pre><span></span><code><span class="nv">route</span> <span class="nv">change</span> <span class="mi">10</span>.<span class="mi">1</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="nv">mask</span> <span class="mi">255</span>.<span class="mi">255</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="mi">10</span>.<span class="mi">201</span>.<span class="mi">128</span>.<span class="mi">1</span> <span class="k">if</span> <span class="mi">13</span> <span class="nv">metric</span> <span class="mi">150</span>
<span class="nv">route</span> <span class="nv">add</span> <span class="mi">10</span>.<span class="mi">45</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="nv">mask</span> <span class="mi">255</span>.<span class="mi">255</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="mi">10</span>.<span class="mi">1</span>.<span class="mi">247</span>.<span class="mi">254</span> <span class="k">if</span> <span class="mi">10</span> <span class="nv">metric</span> <span class="mi">1</span>
<span class="nv">route</span> <span class="nv">add</span> <span class="mi">10</span>.<span class="mi">1</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="nv">mask</span> <span class="mi">255</span>.<span class="mi">255</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="mi">10</span>.<span class="mi">1</span>.<span class="mi">247</span>.<span class="mi">254</span> <span class="k">if</span> <span class="mi">10</span> <span class="nv">metric</span> <span class="mi">1</span>
<span class="nv">route</span> <span class="nv">add</span> <span class="mi">10</span>.<span class="mi">28</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="nv">mask</span> <span class="mi">255</span>.<span class="mi">255</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="mi">10</span>.<span class="mi">1</span>.<span class="mi">247</span>.<span class="mi">254</span> <span class="k">if</span> <span class="mi">10</span> <span class="nv">metric</span> <span class="mi">1</span>
<span class="nv">route</span> <span class="nv">add</span> <span class="mi">211</span>.<span class="mi">76</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="nv">mask</span> <span class="mi">255</span>.<span class="mi">255</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="mi">10</span>.<span class="mi">1</span>.<span class="mi">247</span>.<span class="mi">254</span> <span class="k">if</span> <span class="mi">10</span> <span class="nv">metric</span> <span class="mi">1</span>
</code></pre></div>
<h1>Add Route Rule in Ubuntu</h1>
<div class="highlight"><pre><span></span><code>$ sudo route add -net <span class="m">118</span>.163.150.1 netmask <span class="m">255</span>.255.255.255 gw <span class="m">192</span>.168.1.1
</code></pre></div>
<h1>post-up for start-up</h1>
<p>放到 /etc/network/interfaces</p>
<div class="highlight"><pre><span></span><code>post-up route add -net 118.163.150.1 netmask 255.255.255.255 gw 192.168.1.1
</code></pre></div>
<h1>Delete route ruble</h1>
<div class="highlight"><pre><span></span><code>route del -net 118.163.150.1 netmask 255.255.255.255
</code></pre></div>
<h1>Display Route table</h1>
<p>1.
$ ip route show</p>
<ol>
<li>
<p>$ /sbin/route -n</p>
</li>
</ol>
<h1>Add reoute table example</h1>
<div class="highlight"><pre><span></span><code><span class="nv">route</span> <span class="nv">add</span> <span class="mi">10</span>.<span class="mi">22</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="nv">mask</span> <span class="mi">255</span>.<span class="mi">255</span>.<span class="mi">0</span>.<span class="mi">0</span> <span class="mi">10</span>.<span class="mi">1</span>.<span class="mi">247</span>.<span class="mi">254</span> <span class="k">if</span> <span class="mi">10</span> <span class="nv">metric</span> <span class="mi">1</span>
</code></pre></div>2013台北富邦半馬2013-12-15T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-12-15:/taipei-marathon/<p><img alt="kanban" src="https://lh3.googleusercontent.com/-_BdCaUXB480/Uq5VIsAOnSI/AAAAAAAFHOg/YlOdPyFPpyk/w918-h519-no/IMAG0045_1.jpg"></p>
<p>台北富邦馬拉松是我2013的最後一場路跑賽。從2013八月開始路跑,短短半年,繳了不少銀子。總共參與了:一場全馬(田中馬),二場超半馬(葡萄馬、日月潭馬),二場半馬(苗栗馬、富邦馬),以及一些短程路跑(樹林閃光夜跑,新山夢湖路跑賽,貢寮山水鐵道路跑,猴硐懷舊鐵道路跑,動物園路跑)。因為自己的體重不算輕,也跑不快,只能說完全是跑興趣的,跟著大家全民瘋路跑。當然也是訓練自己,讓自己有個動機可以持續運動下去,使自己體態可以健康一些。總結下來半年跑下來,體重減了6公斤,也算是個大收護。</p>
<p><img alt="img" src="https://lh5.googleusercontent.com/HCZg-QkTgAcp3TAUMRCZjFTGuC0P2rBGJ61Vek71I_qa=w778-h519-no"></p>
<p><img alt="rain" src="https://lh6.googleusercontent.com/-2WpAk4EpRCg/Ur7d9inzCWI/AAAAAAAFHjQ/ChdcsVP_TYI/w413-h519-no/%25E5%25AF%258C%25E9%2582%25A6%25E9%25A6%25AC-Allsports-03.png"></p>
<p>自從田中馬之後,膝蓋在跑超過一定距離之後都會疼痛,簡單的Google之後,應該是<code>plica syndrome</code>(皺襞症候群)。經過短暫休養之後,日月潭超半馬還是在7K之後開始疼痛。而富邦半馬則是直到一半約12K才開始輕輕的痛。但還好都可以持續跑下去而不步兵。事實證明跑前的睡眠真的很重要,田中初馬可能就是前一天睡太少,而讓自己受傷。富邦馬全程都下雨,是我第一次雨中跑路跑。富邦馬最開心的就是,只剩下最後三公里的時侯, 進入市區,看到一列幫忙加油打氣的民眾,擊掌後,發現自己還還殘存一些力氣可以加速!最終成績比苗栗半馬進步了15分鐘左右: 2小時35分28秒(7.5 Min/KM)。順利破了自己的半馬最佳記錄。沒進步太多,留一些空間給2014繼續加油 XD。</p>
<p><img alt="certificate" src="https://lh6.googleusercontent.com/-9E2TQQfxF0o/Ur7d8SpMm2I/AAAAAAAFHjI/F3uaq_qfyf0/w369-h519-no/%25E5%25AF%258C%25E9%2582%25A6%25E9%25A6%25AC-%25E5%258A%2589%25E5%2593%25B2%25E7%25B6%25AD%25E8%25AD%2589%25E6%2598%258E.png"></p>
<p><img alt="start" src="https://lh5.googleusercontent.com/-c3mq0X9zKVs/Ur7d50MAAuI/AAAAAAAFHjA/R25tQQ7wWek/w585-h420-no/%25E5%25AF%258C%25E9%2582%25A6%25E9%25A6%25AC-Allsports-01.png"></p>How to build M2Crypto to support AES 256 in CTR mode2013-12-13T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-12-13:/m2crypto-build/<p>M2Cryto library is out of date. The latest version was released on 2011, so there are some new features provided by OpenSSL are missing. For example, If you want to support AES 256 CTR, you need to build M2Crypto by yourself.</p>
<h2>Download M2Crypto source code</h2>
<p>Download the M2Crypto 0.21.1 from <a href="https://pypi.python.org/pypi/M2Crypto">here</a></p>
<h2>Install necessary packages</h2>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install build-essential python-dev swig libssl-dev
</code></pre></div>
<h2>Modify M2Crypto-0.21.1/SWIG/_evp.i</h2>
<p>Near:</p>
<div class="highlight"><pre><span></span><code><span class="nf">%rename</span><span class="p">(</span><span class="n">aes_256_ofb</span><span class="p">)</span> <span class="n">EVP_aes_256_ofb</span><span class="p">;</span>
<span class="k">extern</span> <span class="k">const</span> <span class="n">EVP_CIPHER</span> <span class="o">*</span><span class="nf">EVP_aes_256_ofb</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
</code></pre></div>
<p>Add these two lines:</p>
<div class="highlight"><pre><span></span><code><span class="nf">%rename</span><span class="p">(</span><span class="n">aes_256_ctr</span><span class="p">)</span> <span class="n">EVP_aes_256_ctr</span><span class="p">;</span>
<span class="k">extern</span> <span class="k">const</span> <span class="n">EVP_CIPHER</span> <span class="o">*</span><span class="nf">EVP_aes_256_ctr</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
</code></pre></div>
<h2>Modify M2Crypto-0.21.1/SWIG/_ssl.i</h2>
<p>Remove these …</p><p>M2Cryto library is out of date. The latest version was released on 2011, so there are some new features provided by OpenSSL are missing. For example, If you want to support AES 256 CTR, you need to build M2Crypto by yourself.</p>
<h2>Download M2Crypto source code</h2>
<p>Download the M2Crypto 0.21.1 from <a href="https://pypi.python.org/pypi/M2Crypto">here</a></p>
<h2>Install necessary packages</h2>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install build-essential python-dev swig libssl-dev
</code></pre></div>
<h2>Modify M2Crypto-0.21.1/SWIG/_evp.i</h2>
<p>Near:</p>
<div class="highlight"><pre><span></span><code><span class="nf">%rename</span><span class="p">(</span><span class="n">aes_256_ofb</span><span class="p">)</span> <span class="n">EVP_aes_256_ofb</span><span class="p">;</span>
<span class="k">extern</span> <span class="k">const</span> <span class="n">EVP_CIPHER</span> <span class="o">*</span><span class="nf">EVP_aes_256_ofb</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
</code></pre></div>
<p>Add these two lines:</p>
<div class="highlight"><pre><span></span><code><span class="nf">%rename</span><span class="p">(</span><span class="n">aes_256_ctr</span><span class="p">)</span> <span class="n">EVP_aes_256_ctr</span><span class="p">;</span>
<span class="k">extern</span> <span class="k">const</span> <span class="n">EVP_CIPHER</span> <span class="o">*</span><span class="nf">EVP_aes_256_ctr</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
</code></pre></div>
<h2>Modify M2Crypto-0.21.1/SWIG/_ssl.i</h2>
<p>Remove these two lines, SSLv2 is removed from newer OpenSSL versions.</p>
<div class="highlight"><pre><span></span><code><span class="nf">%rename</span><span class="p">(</span><span class="n">sslv2_method</span><span class="p">)</span> <span class="n">SSLv2_method</span><span class="p">;</span>
<span class="k">extern</span> <span class="n">SSL_METHOD</span> <span class="o">*</span><span class="nf">SSLv2_method</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
</code></pre></div>
<h2>Modify M2Crypto-0.21.1/setup.py</h2>
<p>Modify </p>
<div class="highlight"><pre><span></span><code>m2crypto = Extension(name = 'M2Crypto.__m2crypto',
</code></pre></div>
<p>to </p>
<div class="highlight"><pre><span></span><code>m2crypto = Extension(name = '__m2crypto',
</code></pre></div>
<h2>Build and Install</h2>
<div class="highlight"><pre><span></span><code>$python setup.py build
$sudo python setup.py install
</code></pre></div>
<!--
0. Upgrade OpenSSL to 1.0.1e
$ sudo apt-get remove openssl libssl-dev
$ tar -xvf openssl-w.x.yz.tar.gz
$ cd openssl-w.x.yz
$ ./config --prefix=/usr
$ sudo make install
$ sudo apt-get install libssl-dev
4. M2Crypto-0.21.1/SWIG/setup.py
+ self.openssl = '/opt/openssl'
-->Dropbox CEO Drew Houston 分享成功的三大關鍵2013-12-12T00:00:00+08:002021-06-22T09:44:06+08:00Cody Liutag:blog.codylab.com,2013-12-12:/drew-houston-mit-commencement-speech/<p><img alt="img" src="https://lh5.googleusercontent.com/-ABQCaZC02OI/UqnVwmt8kVI/AAAAAAAFGl0/TkBgW8NTXWY/w614-h346-no/Screenshot+from+2013-12-12+23%253A21%253A04.png"></p>
<p>Dropbox的CEO Drew Houston在MIT的2013畢業典禮,分享他人生小抄(cheat sheet):</p>
<blockquote>
<p>網球,圈子,30000</p>
</blockquote>
<h2>找到你的網球</h2>
<p>只找到喜歡的事物去做是不夠的,你很容易說服你喜歡做這件事。Drew發現很多成功的人士都對一些重要問題著迷(obsessed)。就像小狗追網球一般,因為我也有養過小狗,所以我很能體會狗追球的執着程度。我相信狗追球是一種天性。幾年前,我養的米格魯那時才二個月大剛帶回家時,她就很喜歡追球到處跑,完全不需要教,自己就會。當你把球拿在手上的時侯。眼神是極度專注的,只會盯著你的球看。你的球移到那邊,眼神就跟到那邊,著魔地地堅定不移。當你預備把球丟出時,甚至你的球還沒有離手,她就會忍不住往前衝刺追球。</p>
<p><img alt="img" src="https://lh5.googleusercontent.com/-SNUbN4rWnb0/UqnSEqFq-DI/AAAAAAAFGlo/UDMAZHgnTmg/w320-h566-no/IMAG1662.jpg"></p>
<blockquote>
<p>成功的關鍵1: 用著迷的態度去解決重要的問題</p>
</blockquote>
<h2>找到最適合你的圈子</h2>
<p>好的圈子會迫使你成長,人們通常只與5個人在一起的時間最長,這5個人可能是你的親友或是同事。無論你做什麼,通常頂尖的人才都只在一個地方聚集,到那邊去。找到圈子裡的偶像,那將會是你的優勢。</p>
<blockquote>
<p>成功的關鍵2: 到頂尖的圈子裡</p>
</blockquote>
<h2>人的一生就30000天</h2>
<p>Drew提到人的一生平均只有3萬天。不要嘗試讓你的生活完美,而做一個完美的規劃,完美的規劃跟本不存在。Drew 認為最好的學習,就是實踐。給自己一個去自由冒險的機會並且成長。</p>
<p>而我自己也用 Python 算了一下:</p>
<div class="highlight"><pre><span></span><code>>>>(datetime.datetime.now() - datetime.datetime(1985,10,25)).days
10275
</code></pre></div>
<p>我已經在這世界上超過一萬天了,也就是只剩下2/3不到的時間。</p>
<blockquote>
<p>成功的關鍵3: 嘗試有趣的冒險而非完美的規劃</p>
</blockquote>
<h2>延伸閱讀</h2>
<ul>
<li><a href="http://video.mit.edu/watch/mit-commencement-2013-speeches-24832">演說影片(08:20 ~ 27:17)</a></li>
<li><a href="http://web.mit.edu/newsoffice/2013/commencement-address-houston-0607.html">英文演說講稿</a></li>
<li><a href="http://page.renren.com/chasefuture/note/907453577">簡體演說講稿</a></li>
</ul>
<!--
- [ Drew Houston, Dropbox: Keys to Success - YouTube](http://www.youtube.com/watch?v=5ilyksSI6oY)
-->
<!--
>>> "%.2f %%"%((datetime.datetime.now() - datetime.datetime(1985,10,25)).days/30000.0*100)
'34.25 %'
-->安裝ThinkFan風扇控制軟體2013-12-05T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-12-05:/thinkpad-thinkfan/<h2>安裝 Thinkfan</h2>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install thinkfan
</code></pre></div>
<h2>開啟風扇控制權</h2>
<p>系統預設並不容許直接控制風扇速度,所以需要特別設定<code>thinkpad-acpi</code>的config值: </p>
<div class="highlight"><pre><span></span><code>$ sudo <span class="nb">echo</span> <span class="s2">"options thinkpad_acpi fan_control=1"</span> <span class="p">|</span> sudo tee /etc/modprobe.d/thinkpad_acpi.conf
</code></pre></div>
<p>重新載入<code>thinkpad_acpi</code> driver 套用新的設定值</p>
<div class="highlight"><pre><span></span><code>$ sudo modprobe -rv thinkpad_acpi
$ sudo modprobe -v thinkpad_acpi
</code></pre></div>
<h2>修改 thinkfan 設定檔</h2>
<p>thinkfan 設定檔在 <code>/etc/thinkfan.conf</code>,主要可以設定的要用那些sensor以及設定溫度與轉速的規則。首先先找到溫度量測的檔案:</p>
<div class="highlight"><pre><span></span><code>$ find /sys/devices -type f -name <span class="s2">"temp*_input"</span>
</code></pre></div>
<p>以x220為例,一共找到四個檔:</p>
<div class="highlight"><pre><span></span><code>/sys/devices/virtual/hwmon/hwmon0/temp1_input
/sys/devices/platform/coretemp.0/temp3_input
/sys/devices/platform/coretemp.0/temp1_input
/sys/devices/platform/coretemp.0/temp2_input
</code></pre></div>
<p>把這四行寫入到 <code>/etc/thinkfan.conf</code></p>
<div class="highlight"><pre><span></span><code>sensor /sys/devices/virtual/hwmon/hwmon0/temp1_input
sensor /sys/devices/platform/coretemp.0/temp3_input
sensor /sys …</code></pre></div><h2>安裝 Thinkfan</h2>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install thinkfan
</code></pre></div>
<h2>開啟風扇控制權</h2>
<p>系統預設並不容許直接控制風扇速度,所以需要特別設定<code>thinkpad-acpi</code>的config值: </p>
<div class="highlight"><pre><span></span><code>$ sudo <span class="nb">echo</span> <span class="s2">"options thinkpad_acpi fan_control=1"</span> <span class="p">|</span> sudo tee /etc/modprobe.d/thinkpad_acpi.conf
</code></pre></div>
<p>重新載入<code>thinkpad_acpi</code> driver 套用新的設定值</p>
<div class="highlight"><pre><span></span><code>$ sudo modprobe -rv thinkpad_acpi
$ sudo modprobe -v thinkpad_acpi
</code></pre></div>
<h2>修改 thinkfan 設定檔</h2>
<p>thinkfan 設定檔在 <code>/etc/thinkfan.conf</code>,主要可以設定的要用那些sensor以及設定溫度與轉速的規則。首先先找到溫度量測的檔案:</p>
<div class="highlight"><pre><span></span><code>$ find /sys/devices -type f -name <span class="s2">"temp*_input"</span>
</code></pre></div>
<p>以x220為例,一共找到四個檔:</p>
<div class="highlight"><pre><span></span><code>/sys/devices/virtual/hwmon/hwmon0/temp1_input
/sys/devices/platform/coretemp.0/temp3_input
/sys/devices/platform/coretemp.0/temp1_input
/sys/devices/platform/coretemp.0/temp2_input
</code></pre></div>
<p>把這四行寫入到 <code>/etc/thinkfan.conf</code></p>
<div class="highlight"><pre><span></span><code>sensor /sys/devices/virtual/hwmon/hwmon0/temp1_input
sensor /sys/devices/platform/coretemp.0/temp3_input
sensor /sys/devices/platform/coretemp.0/temp1_input
sensor /sys/devices/platform/coretemp.0/temp2_input
</code></pre></div>
<p>這樣ThinkFan就會取這四個sensor最高溫度來監度</p>
<h2>得到目前風扇的速度</h2>
<div class="highlight"><pre><span></span><code>$ cat /proc/acpi/ibm/fan
status: enabled
speed: <span class="m">4464</span>
level: auto
commands: level <level> <span class="o">(</span><level> is <span class="m">0</span>-7, auto, disengaged, full-speed<span class="o">)</span>
commands: enable, disable
commands: watchdog <timeout> <span class="o">(</span><timeout> is <span class="m">0</span> <span class="o">(</span>off<span class="o">)</span>, <span class="m">1</span>-120 <span class="o">(</span>seconds<span class="o">))</span>
</code></pre></div>
<p>從中也可以了解到如何手動控制風扇,例如手動控制風扇用速度<code>7</code>來跑:</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">echo</span> level <span class="m">7</span> <span class="p">|</span> sudo tee /proc/acpi/ibm/fan
</code></pre></div>
<h2>前景執行 thinkfan</h2>
<p>想知道 thinkfan 執行的過程,可以試著跑前景模式,並每一秒更新一次:</p>
<div class="highlight"><pre><span></span><code>$ sudo thinkfan -n -s <span class="m">1</span>
<span class="nv">sleeptime</span><span class="o">=</span><span class="m">1</span>, <span class="nv">tmax</span><span class="o">=</span><span class="m">49</span>, <span class="nv">last_tmax</span><span class="o">=</span><span class="m">49</span>, <span class="nv">biased_tmax</span><span class="o">=</span><span class="m">49</span> -> <span class="nv">fan</span><span class="o">=</span><span class="s2">"level 0"</span>
<span class="nv">sleeptime</span><span class="o">=</span><span class="m">1</span>, <span class="nv">tmax</span><span class="o">=</span><span class="m">51</span>, <span class="nv">last_tmax</span><span class="o">=</span><span class="m">49</span>, <span class="nv">biased_tmax</span><span class="o">=</span><span class="m">51</span> -> <span class="nv">fan</span><span class="o">=</span><span class="s2">"level 1"</span>
<span class="nv">sleeptime</span><span class="o">=</span><span class="m">1</span>, <span class="nv">tmax</span><span class="o">=</span><span class="m">50</span>, <span class="nv">last_tmax</span><span class="o">=</span><span class="m">51</span>, <span class="nv">biased_tmax</span><span class="o">=</span><span class="m">50</span> -> <span class="nv">fan</span><span class="o">=</span><span class="s2">"level 0"</span>
... 略
</code></pre></div>
<h2>Reference</h2>
<ul>
<li><a href="http://www.cnblogs.com/henryau/archive/2012/03/03/ubuntu_thinkfan.html">[原创] Thinkfan安装配置使用 - HenrYau - 博客园</a></li>
<li><a href="http://overtag.dk/wordpress/2012/03/to-all-my-thinkpad-friends-running-linux/">To all my Thinkpad friends running Linux | Ben Jao Ming</a></li>
</ul>
<h2>備註: Thinkpad X220 在不同 Level 的轉速</h2>
<table>
<thead>
<tr>
<th>Level</th>
<th>RPM</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>2000</td>
</tr>
<tr>
<td>2</td>
<td>3000</td>
</tr>
<tr>
<td>3</td>
<td>3500</td>
</tr>
<tr>
<td>4</td>
<td>3500</td>
</tr>
<tr>
<td>5</td>
<td>4000</td>
</tr>
<tr>
<td>6</td>
<td>4000</td>
</tr>
<tr>
<td>7</td>
<td>4500</td>
</tr>
<tr>
<td>8+</td>
<td>6000 (全速)</td>
</tr>
</tbody>
</table>
<!--
## lm-sensors
如果想知道目前CPU溫度,可以額外安裝 lm-sensors
$ sudo apt-get install lm-sensors
第一次可以先執行`sensors-detect`來掃系統有那些sensor可用。
$ sudo sensors-detect
以x220為例,掃到了`coretemp`,最後一個問題他會問你要不要把`coretemp`加到`/etc/modules`,這樣開機就會自動載入溫度監控程式,`sensors`指令可以看到目前有的sensors,也包括溫度:
$ sensors
acpitz-virtual-0
Adapter: Virtual device
temp1: +56.0°C (crit = +99.0°C)
thinkpad-isa-0000
Adapter: ISA adapter
fan1: 3474 RPM
coretemp-isa-0000
Adapter: ISA adapter
Physical id 0: +57.0°C (high = +86.0°C, crit = +100.0°C)
Core 0: +57.0°C (high = +86.0°C, crit = +100.0°C)
2013/05/12 22:34:48 Core 1: +57.0°C (high = +86.0°C, crit = +100.0°C)
## 參考的 config
(0, 0, 66)
(1, 56, 75)
(2, 68, 78)
(3, 71, 81)
(5, 74, 84)
(7, 77, 87)
(127, 80, 32767)
-->Using vim as a man-page viewer under Linux2013-12-03T08:25:59+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-12-03:/vim-man-viewer/<p>If you use bash, just add the following script in your <code>~/.bashrc</code>:</p>
<div class="highlight"><pre><span></span><code><span class="k">export</span> <span class="n">PAGER</span><span class="o">=</span><span class="s2">"/bin/sh -c </span><span class="se">\"</span><span class="s2">unset PAGER;col -b -x | </span><span class="se">\</span>
<span class="s2"> vim -R -c 'set ft=man nomod nolist' -c 'map q :q<CR>' </span><span class="se">\</span>
<span class="s2"> -c 'map <SPACE> <C-D>' -c 'map b <C-U>' </span><span class="se">\</span>
<span class="s2"> -c 'nmap K :Man <C-R>=expand(</span><span class="se">\\\"</span><span class="s2"><cword></span><span class="se">\\\"</span><span class="s2">)<CR><CR>' -</span><span class="se">\"</span><span class="s2">"</span>
</code></pre></div>
<p>Compare with the original <code>Main</code></p>
<p><img alt="Main" src="https://lh6.googleusercontent.com/-awZYEgbmllOy78HxlrJZW9bEOn2tWHCHodmYq_2hdGC=w995-h551-no"></p>
<p><code>Main</code> in VIM has good looking with syntaxheight.</p>
<p><img alt="Man in VIM" src="https://lh5.googleusercontent.com/-gsOASyvKbp8/Up1EIBUmSoI/AAAAAAAFGjI/rmvTKeyt59I/w928-h566-no/man-vim.png"></p>
<h2>Reference:</h2>
<ul>
<li><a href="http://vim.wikia.com/wiki/Using_vim_as_a_man-page_viewer_under_Unix">Using vim as a man-page viewer under Unix - Vim Tips Wiki</a></li>
</ul>Linux在充放電切換時執行特定指令2013-12-02T08:18:24+08:002021-06-22T08:49:09+08:00Cody Liutag:blog.codylab.com,2013-12-02:/linux-powersaving-run-script/<p>Linux筆電在充放電的時侯可以執行特定指令。例如我們想增加電池的使用時間,可以在電池放電的時侯,把一些較消耗資源的背景程式先暫時暫停,等插回AC電源的時侯再重新開始。這邊以暫停<a href="https://www.insynchq.com/">Insync</a>為例:</p>
<h2>方法一 /etc/pm/power.d</h2>
<p>我們可以放script放到<code>/etc/pm/power.d</code>來達成,當進入電池模式的時侯會帶<code>true</code>參數,而離開電池模式的時侯會帶<code>false</code>參數,只要新增一個檔案,例如<code>/etc/pm/power.d/00-powersaving</code>加入以下內容,實際指令就依照自己的需求修改:</p>
<div class="highlight"><pre><span></span><code>case $1 in
true)
echo "Enable screen power saving"
sudo -u cody insync pause_syncing
;;
false)
echo "Disable screen power saving"
sudo -u cody insync pause_syncing
;;
esac
</code></pre></div>
<p>最後記得再加上執行權限<code>sudo chmod +x /etc/pm/power.d/00-powersaving</code></p>
<h2>方法二 /etc/acpi/power.sh</h2>
<p>Linux 有一個指令 <code>on_ac_power</code>,如果回傳<code>0</code>代表是AC,如果是用電池的話,則回傳<code>1</code>,例如:</p>
<p><strong>On AC Power</strong></p>
<div class="highlight"><pre><span></span><code>$ on_ac_power
$ <span class="nb">echo</span> <span class="nv">$?</span>
<span class="m">0</span>
</code></pre></div>
<p><strong>On Battery</strong></p>
<div class="highlight"><pre><span></span><code>$ on_ac_power
$ <span class="nb">echo</span> <span class="nv">$?</span>
<span class="m">1</span>
</code></pre></div>
<p>所以透過這個指令,我們就可以修改<code>/etc/acpi/power …</code></p><p>Linux筆電在充放電的時侯可以執行特定指令。例如我們想增加電池的使用時間,可以在電池放電的時侯,把一些較消耗資源的背景程式先暫時暫停,等插回AC電源的時侯再重新開始。這邊以暫停<a href="https://www.insynchq.com/">Insync</a>為例:</p>
<h2>方法一 /etc/pm/power.d</h2>
<p>我們可以放script放到<code>/etc/pm/power.d</code>來達成,當進入電池模式的時侯會帶<code>true</code>參數,而離開電池模式的時侯會帶<code>false</code>參數,只要新增一個檔案,例如<code>/etc/pm/power.d/00-powersaving</code>加入以下內容,實際指令就依照自己的需求修改:</p>
<div class="highlight"><pre><span></span><code>case $1 in
true)
echo "Enable screen power saving"
sudo -u cody insync pause_syncing
;;
false)
echo "Disable screen power saving"
sudo -u cody insync pause_syncing
;;
esac
</code></pre></div>
<p>最後記得再加上執行權限<code>sudo chmod +x /etc/pm/power.d/00-powersaving</code></p>
<h2>方法二 /etc/acpi/power.sh</h2>
<p>Linux 有一個指令 <code>on_ac_power</code>,如果回傳<code>0</code>代表是AC,如果是用電池的話,則回傳<code>1</code>,例如:</p>
<p><strong>On AC Power</strong></p>
<div class="highlight"><pre><span></span><code>$ on_ac_power
$ <span class="nb">echo</span> <span class="nv">$?</span>
<span class="m">0</span>
</code></pre></div>
<p><strong>On Battery</strong></p>
<div class="highlight"><pre><span></span><code>$ on_ac_power
$ <span class="nb">echo</span> <span class="nv">$?</span>
<span class="m">1</span>
</code></pre></div>
<p>所以透過這個指令,我們就可以修改<code>/etc/acpi/power.sh</code>把下列 script 加到最前面來達到效果</p>
<div class="highlight"><pre><span></span><code><span class="k">if</span> on_ac_power<span class="p">;</span> <span class="k">then</span>
<span class="c1"># On AC</span>
sudo -u cody insync resume_syncing
<span class="k">else</span>
<span class="c1"># On Batter</span>
sudo -u cody insync pause_syncing
<span class="k">fi</span>
</code></pre></div>
<p>上面兩個方法都可以達到要求,但是實際測試<code>/etc/acpi/power.sh</code>在切換時會重覆執行很多次,所以我個人較偏好方法一。</p>
<h3>Referece:</h3>
<ul>
<li><a href="http://askubuntu.com/questions/55904/how-can-i-run-my-script-automatically-on-ac-switching">11.04 - how can I run my script automatically on ac switching - Ask Ubuntu</a></li>
<li><a href="https://wiki.archlinux.org/index.php/pm-utils#Change_brightness_depending_on_AC_state">pm-utils - ArchWiki</a></li>
</ul>Update ThinkPad BIOS in Linux with a USB disk2013-11-30T23:27:26+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-11-30:/thinkpad-bios/<p>In this post, I recorded my ThinkPad x220 BIOS update steps. In Windows, we can use <a href="http://support.lenovo.com/en_US/detail.page?LegacyDocID=MIGR-77150">BIOS Update Utility</a> provided by Lenovo, but it's only available in Windows platformas. For Ubuntu user like me, we can still update BIOS with a USB disk.</p>
<h3>Download BIOS Update Bootable CD</h3>
<p>The latest version is 1.39(2013/11), Go to lenovo support site:<a href="http://support.lenovo.com/en_US/downloads/detail.page?&LegacyDocID=MIGR-77151">BIOS Update Bootable CD for Windows 8 (32-bit, 64-bit), 7 (32-bit, 64-bit), Vista (32-bit, 64-bit), XP - ThinkPad X220, X220i, X220 Tablet, X220i Tablet</a>, download 8duj25us.iso(31.6 MB) </p>
<h3>Download <code>geteltorito.pl</code> to generate boot image</h3>
<div class="highlight"><pre><span></span><code>$ wget <span class="s1">'http://www …</span></code></pre></div><p>In this post, I recorded my ThinkPad x220 BIOS update steps. In Windows, we can use <a href="http://support.lenovo.com/en_US/detail.page?LegacyDocID=MIGR-77150">BIOS Update Utility</a> provided by Lenovo, but it's only available in Windows platformas. For Ubuntu user like me, we can still update BIOS with a USB disk.</p>
<h3>Download BIOS Update Bootable CD</h3>
<p>The latest version is 1.39(2013/11), Go to lenovo support site:<a href="http://support.lenovo.com/en_US/downloads/detail.page?&LegacyDocID=MIGR-77151">BIOS Update Bootable CD for Windows 8 (32-bit, 64-bit), 7 (32-bit, 64-bit), Vista (32-bit, 64-bit), XP - ThinkPad X220, X220i, X220 Tablet, X220i Tablet</a>, download 8duj25us.iso(31.6 MB) </p>
<h3>Download <code>geteltorito.pl</code> to generate boot image</h3>
<div class="highlight"><pre><span></span><code>$ wget <span class="s1">'http://www.uni-koblenz.de/~krienke/ftp/noarch/geteltorito/geteltorito.pl'</span>
</code></pre></div>
<h3>Generate bootable image from geteltorito.pl</h3>
<div class="highlight"><pre><span></span><code>$ perl geteltorito.pl 8duj10uc.iso > biosupdate.img
</code></pre></div>
<h3>Copy the image to the usb thumdrive</h3>
<div class="highlight"><pre><span></span><code>$ sudo dd <span class="k">if</span><span class="o">=</span>biosupdate.img <span class="nv">of</span><span class="o">=</span>/dev/<your_usb_disk> <span class="nv">bs</span><span class="o">=</span>512K
</code></pre></div>
<h2>Reboot</h2>
<p><img alt="img" src="https://lh3.googleusercontent.com/mj81RJGN3NOwp3fwgG3LJRTxSz7UVPjhT84QOWaC6zHk=w995-h259-no"><br>
Choose <code>Update system program</code> and follow the instructions.</p>
<p><img alt="img" src="https://lh3.googleusercontent.com/gMqX63HkWAabxpysYXVkBmmzCSC63C_VsmRVuTHGn0C9=w995-h312-no"><br>
After upgrading, we can verify the version in BIOS. (UEFI: 1.39 / ECP: 1.24)</p>
<h4>Reference:</h4>
<ul>
<li><a href="http://www.floccinaucinihilipilification.net/blog/2011/10/2/updating-the-bios-of-a-thinkpad-x220-using-linux.html">The Floccinaucinihilipilification Homepage - The Floccinaucinihilipilification Blog - Updating the BIOS of a Thinkpad X220 using Linux</a></li>
</ul>Bash Shell 快速鍵 (emacs-style)2013-11-30T10:57:25+08:002021-06-22T08:49:09+08:00Cody Liutag:blog.codylab.com,2013-11-30:/bash-shell-shortcut/<h2>執行/中斷/輸入</h2>
<ul>
<li>Ctrl-C: 終止正在執行的程式</li>
<li>Ctrl-L: 清除Terminal畫面,同clear指令</li>
<li>Ctrl-Z: 將該工作放到背景中<code>暫停</code>, 使用<code>jobs</code>看工作號碼(job number), <code>fg</code><number> 取回</li>
<li>Ctrl-J: Enter,不用離開鍵盤,還不錯</li>
</ul>
<p>進階</p>
<ul>
<li>Ctrl-D: 離開 Shell</li>
<li>Ctrl-x, Ctrl-e 開啟vim,可一起執行多個指令</li>
<li>Ctrl-V TAB: 輸入 TAB,而不是命令列擴展</li>
<li>Ctrl-V: 加上要輸入特殊字元, ex: Ctrl-V Ctrl-D 會出現 ^D</li>
</ul>
<h2>移動</h2>
<ul>
<li>Ctrl-A: 回到此行最前面(同<code>Home</code>鍵)</li>
<li>Ctrl-E: 到此行的最後面(同<code>End</code>鍵)</li>
<li>Ctrl-F: 游標向後移動一格(不想要用arrow key時可多加利用)</li>
<li>Ctrl-B: 游標向前移動一個(不想要用arrow key時可多加利用)</li>
<li>Alt-B: Back(left) one word</li>
<li>Alt-F: Forward(right) one word</li>
</ul>
<h2>查找</h2>
<ul>
<li>Ctrl-N: 找下個指令(同下箭頭)</li>
<li>Ctrl-P: 找上個指令(同上箭頭)</li>
<li>TAB: 擴展要輸入的檔案到命令列上(上/下箭頭: 開始搜尋過去的命令)</li>
<li>Ctrl-R: 打關鍵字搜尋過去的命令, 搭配 Ctrl-r/Ctrl+Shift+r,可來回尋找</li>
</ul>
<p>進階</p>
<ul>
<li>Ctrl-I: 同 Tab</li>
<li>Ctrl-S: 暫停輸出到畫面上,讓stdout定格(搭配Ctrl-Q使用)</li>
<li>Ctrl-Q …</li></ul><h2>執行/中斷/輸入</h2>
<ul>
<li>Ctrl-C: 終止正在執行的程式</li>
<li>Ctrl-L: 清除Terminal畫面,同clear指令</li>
<li>Ctrl-Z: 將該工作放到背景中<code>暫停</code>, 使用<code>jobs</code>看工作號碼(job number), <code>fg</code><number> 取回</li>
<li>Ctrl-J: Enter,不用離開鍵盤,還不錯</li>
</ul>
<p>進階</p>
<ul>
<li>Ctrl-D: 離開 Shell</li>
<li>Ctrl-x, Ctrl-e 開啟vim,可一起執行多個指令</li>
<li>Ctrl-V TAB: 輸入 TAB,而不是命令列擴展</li>
<li>Ctrl-V: 加上要輸入特殊字元, ex: Ctrl-V Ctrl-D 會出現 ^D</li>
</ul>
<h2>移動</h2>
<ul>
<li>Ctrl-A: 回到此行最前面(同<code>Home</code>鍵)</li>
<li>Ctrl-E: 到此行的最後面(同<code>End</code>鍵)</li>
<li>Ctrl-F: 游標向後移動一格(不想要用arrow key時可多加利用)</li>
<li>Ctrl-B: 游標向前移動一個(不想要用arrow key時可多加利用)</li>
<li>Alt-B: Back(left) one word</li>
<li>Alt-F: Forward(right) one word</li>
</ul>
<h2>查找</h2>
<ul>
<li>Ctrl-N: 找下個指令(同下箭頭)</li>
<li>Ctrl-P: 找上個指令(同上箭頭)</li>
<li>TAB: 擴展要輸入的檔案到命令列上(上/下箭頭: 開始搜尋過去的命令)</li>
<li>Ctrl-R: 打關鍵字搜尋過去的命令, 搭配 Ctrl-r/Ctrl+Shift+r,可來回尋找</li>
</ul>
<p>進階</p>
<ul>
<li>Ctrl-I: 同 Tab</li>
<li>Ctrl-S: 暫停輸出到畫面上,讓stdout定格(搭配Ctrl-Q使用)</li>
<li>Ctrl-Q: 回復輸出到畫面上(恢復Ctrl+S的輸出)</li>
</ul>
<h2>編輯指令</h2>
<ul>
<li>Alt-d: 刪除游標之後的一個單字</li>
<li>Ctrl-D: 移除游標後的一個字元,如果全部刪除的話,就會離開 shell</li>
<li>Ctrl-H: 移除游標前的一個字元,同 backspace</li>
<li>Ctrl-K: 清除游標之後的所有文字</li>
<li>Ctrl-U: 清除游標之前的所有文字</li>
<li>Ctrl-W: 刪除游標之前的最後一個單字</li>
<li>Ctrl-T: 相近兩個字元互換位置, 例如 daet 會修正為 date</li>
<li>ESC-T: 相近最後兩個 "字" 互換位置,例 bee cat 會修正為 cat bee,與 Ctrl+T 類似</li>
</ul>
<h3>Reference</h3>
<ul>
<li><a href="http://blog.longwin.com.tw/2006/09/bash_hot_key_2006/">Bash Shell 快速鍵 - Tsung's Blog</a></li>
<li><a href="http://teohm.github.io/blog/2012/01/04/shortcuts-to-move-faster-in-bash-command-line/">Shortcuts to move faster in Bash command line - teohm.dev</a></li>
</ul>Set hardware clock time2013-11-26T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-11-26:/cmd-hwclock.md/<h2>Display hardware clock time</h2>
<div class="highlight"><pre><span></span><code>$ sudo hwclock
</code></pre></div>
<h2>Set hardware clock to current time</h2>
<div class="highlight"><pre><span></span><code>$ sudo hwclock -w
</code></pre></div>
<h2>Set the System Time from the Hardware Clock.</h2>
<div class="highlight"><pre><span></span><code>$ sudo hwclock -s
</code></pre></div>
<ul>
<li><a href="http://www.thegeekstuff.com/2013/08/hwclock-examples/">7 Linux hwclock Command Examples to Set Hardware Clock Date Time</a></li>
</ul>Install IBM Active Protection System Linux Driver (HDAPS)2013-11-25T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-11-25:/thinkpad-ubuntu-hdaps/<h2>Installation</h2>
<div class="highlight"><pre><span></span><code>$ sudo apt-get update
$ sudo apt-get install tp-smapi-dkms hdapsd
$ <span class="nb">echo</span> <span class="s1">'tp_smapi'</span> <span class="p">|</span> sudo tee -a /etc/modules
$ <span class="nb">echo</span> <span class="s1">'hdapsd'</span> <span class="p">|</span> sudo tee -a /etc/modules
$ sudo modprobe tp_smapi
$ sudo /etc/init.d/hdapsd restart
</code></pre></div>
<h2>Verify if it works</h2>
<div class="highlight"><pre><span></span><code>$ sudo hdapsd
</code></pre></div>
<p>it should display "parking" on console if you move your laptop </p>
<h2>Modify config: /etc/default/hdapsd</h2>
<ul>
<li>sensitivity: default is 15. higher value means less sensitive.</li>
<li>disk: the disk that hdapsd should monitor</li>
</ul>
<h2>Reference :</h2>
<ul>
<li><a href="http://samiux.blogspot.tw/2011/07/howto-lenovo-active-protection-system.html">Samiux's Blog: HOWTO : Lenovo Active Protection System (HDAPS) on Ubuntu 11.04</a></li>
<li><a href="http://www.thinkwiki.org/wiki/HDAPS">HDAPS - ThinkWiki</a></li>
</ul>2013第一屆日月潭環湖馬拉松賽-29K超半馬心得2013-11-17T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-11-17:/sun-moon-lake-marathon/<p><img alt="日月潭" src="http://i.imgur.com/y4UZ1mx.jpg"></p>
<p><img alt="img" src="https://lh5.googleusercontent.com/-ieNr8pxYwHs/UpB9hTonPbI/AAAAAAAFGZE/H0WMcub1YaA/w995-h563-no/IMAG1276.jpg"></p>
<p>距離上次田中馬初馬的挑戰,休息一個星期之後緊接的就是2013日月潭環湖馬拉松。我這次參加的是<strong>29公里超半馬挑戰組</strong>。雖然說這是第一屆,但據我所知日月潭也常有其它單位會在此舉辦路跑,因為路線景色實在是太讚了。主辦單位是<strong>全國EMBA校園馬拉松接力賽組會</strong>,這場給跑友門的感覺就是超級貴,全馬報名費要<strong>1500</strong>,超半馬也要<strong>1200</strong>,比往常的賽事多了500元左右。不過因為是南投在地,又覺得可以跑完日月潭環湖一周是一件很酷的事情,所以我還是給他報名下去了。起點跟終點都是在向山遊客中心</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/-YvCflS5NTSU/UpB7jE-pdsI/AAAAAAAFGV4/cy-VtA8-HYg/w350/IMAG1196.jpg">
<img alt="img" src="https://lh5.googleusercontent.com/-qRCEcTCy9VM/UpB7k3wmskI/AAAAAAAFGWA/p0bCW_4DuFQ/w350/IMAG1197.jpg">
跟戰友Alvin起跑前跟熱氣球拍照。</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/-HOmnKovYxdg/UpB7_y3s2wI/AAAAAAAFGWQ/Wz-I4612NzI/w995-h563-no/IMAG1219.jpg">
全馬組出發!</p>
<p><img alt="img" src="https://lh5.googleusercontent.com/-1xxAAyN0XLU/UpB8D9QtHbI/AAAAAAAFGWc/T8POei6rtEE/w995-h563-no/IMAG1221.jpg">
15分鐘後,超半馬組也出發了!</p>
<p><img alt="img" src="https://lh5.googleusercontent.com/-RqcGdvgiRV4/UpB8PsAeL6I/AAAAAAAFGWk/iv8EJSwwHvk/w995-h563-no/IMAG1224.jpg">
日月潭之前來過很多次,但從來沒有那麼早來過,萬萬沒想到清晨的日月潭那麼厲害。太陽躲在山後,讓山景非常有層次。讓剛起跑的我非常讚歎!忍不住拍了好幾張照片
<img alt="img" src="https://lh4.googleusercontent.com/-qbQn1IhJw0c/UpB8aa8-a9I/AAAAAAAFGXA/nkPp1ilfTes/w995-h563-no/IMAG1231.jpg">
<img alt="img" src="https://lh4.googleusercontent.com/-82Ij1WmKuxo/UpB8WqWN2xI/AAAAAAAFGWs/s9Dqpmk7Ug0/w995-h563-no/IMAG1227.jpg">
很多跑友也都停下腳步拍照留念</p>
<p><img alt="img" src="https://lh5.googleusercontent.com/-9boBF_MNXNE/UpB8ZTZvKqI/AAAAAAAFGW4/lGWyUlths60/w995-h563-no/IMAG1228.jpg">
漂亮的湖光山色
<img alt="img" src="https://lh4.googleusercontent.com/-7SkuYuKfyI8/UpYVGB1c3WI/AAAAAAAFGfY/vCfPlxtraUM/w400/">
<img alt="img" src="https://lh3.googleusercontent.com/-ADM2SZB9hQg/UpB8bP8S1CI/AAAAAAAFGXE/VK-REoc6AJQ/w995-h563-no/IMAG1234.jpg">
<img alt="img" src="https://lh4.googleusercontent.com/-NZaivyb7BFU/UpB8gH3n87I/AAAAAAAFGXM/vKgAYgmG5ko/w995-h563-no/IMAG1244.jpg">
美好的晨跑時光,就在太陽高高昇起後告個段落。我的右膝蓋從7K左右開始抗議。當下就知道這是田中初馬時所受的傷,還沒有完全復原。膝蓋的內側每跑一步就有刺痛感。我趕緊調整跑步的姿勢,讓右腳可以好受一點。並開始期待等下的補給站有肌樂可以止痛一下,可惜路過好幾個補給站都沒有肌樂,只能摸摸鼻子繼續跑下去,終於在16K玄奘寺補給站,看到有止痛噴劑,趕緊拿來噴了好幾下。希望在師父加持之下可以撐下去。這邊也有特色補給品:香菇茶葉蛋
<img alt="img" src="https://lh5.googleusercontent.com/-RHh15aF7B4Y/UpB_xGMdBLI/AAAAAAAFGZk/yF-M79O_q2s/w320-h566-no/IMAG1245.jpg"></p>
<p>賽事的後半段,大多是緩下坡,我原本以為可以開始加速。但雙腳膝蓋開始輪流罷工。雙腿也愈來愈僵硬,此時只能硬撐下去,但速度愈來愈慢,甚至痛到只能步行。找到機會就抬腿拉拉筋。</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/-c935fdDTMxc/UpB81etyXXI/AAAAAAAFGZY/1vA1410q6H0/w995-h563-no/IMAG1252.jpg">
過了20K,完全就是拖著雙腳在走,膝蓋一彎就痛。</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/-7evZdhw8CSQ/UpB8261EJzI/AAAAAAAFGZY/peACXug59rE/w995-h563-no/IMAG1251.jpg">
突然後面出現了警察伯伯緩慢前進。驚!這不是第一名才會有的尊榮前導車嗎?XD 原來這場賽事的交通管制是警察會把跟我們同方向的汽車擋下來緩慢的行進。而有多慢呢?大概就是我那時前進10分速,因此大部份的跑者都可以享受到沒有什麼車流的完美賽道。但是被擋下來的在地人或遊客可就不開心了,甚至有人還對警察咆哮大罵。之後警察才勉強加速一些,而這群車隊也就離我而去了。</p>
<p><img alt="img" src="https://lh5.googleusercontent.com/--KZ4lxlERvU/UpB9OzuJe8I/AAAAAAAFGZY/I6lfcb3NuUA/w995-h563-no/IMAG1255.jpg">
終於到最後的3K,真的是快解脫了。全半跟超半馬也是在此分開。全馬還要左轉台21線,補足13公里到全馬的42公里。當下我真的很慶幸我只需要再跑3K就可以收工。最後的3K是個魔鬼上坡路段。</p>
<p><img alt="img" src="https://lh3.googleusercontent.com/vMJVZobsmXmGWKdWOfV4Inq1aj9JDSHBhrqLtgvQ4JPH=w995-h563-no">
還好沿途開始出現大量的暨大同學志工,幫我們加油打氣。</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/-0-880U9e0Xs/UpB9W4DH3KI/AAAAAAAFGZY/Ky9c0-Vdfg0/w377-h566-no/DSC_1347.JPG"></p>
<p>這時就是一步一步的堅持,雖然只能龜速前進。慢慢吃掉最後的3K。但當開始聽到熱鬧的會場麥克風聲音時,我知道離會場已經很近。志工們也列隊跟我擊掌加油!令人非常的感動,,最後也順利的回到終點。</p>
<p><img alt="img" src="https://lh3.googleusercontent.com/-HGecqkx29Cw/UpB9ZzVHy4I/AAAAAAAFGZY/nUh0b8Ayzsc/w995-h563-no/IMAG1261.jpg">
最後到終點時,全馬計時錶已經來到4小時半。</p>
<p><img alt="img" src="https://lh6.googleusercontent.com/-Oss42kdCLFI/UpB9bQGYUMI/AAAAAAAFGZY/WzaailbqDm0/w995-h563-no/IMAG1262.jpg">
終點有志工妹妹幫忙掛上獎牌。獎牌不同於一般的金屬材質,這場是特別的琉璃材質</p>
<p>這次超半馬也是特別有意義,因為這場是我的好同事Alvin的初馬。他因為膝蓋受傷的關係,已經錯過了好幾場已經報名的全馬賽事,只能選擇棄賽 …</p><p><img alt="日月潭" src="http://i.imgur.com/y4UZ1mx.jpg"></p>
<p><img alt="img" src="https://lh5.googleusercontent.com/-ieNr8pxYwHs/UpB9hTonPbI/AAAAAAAFGZE/H0WMcub1YaA/w995-h563-no/IMAG1276.jpg"></p>
<p>距離上次田中馬初馬的挑戰,休息一個星期之後緊接的就是2013日月潭環湖馬拉松。我這次參加的是<strong>29公里超半馬挑戰組</strong>。雖然說這是第一屆,但據我所知日月潭也常有其它單位會在此舉辦路跑,因為路線景色實在是太讚了。主辦單位是<strong>全國EMBA校園馬拉松接力賽組會</strong>,這場給跑友門的感覺就是超級貴,全馬報名費要<strong>1500</strong>,超半馬也要<strong>1200</strong>,比往常的賽事多了500元左右。不過因為是南投在地,又覺得可以跑完日月潭環湖一周是一件很酷的事情,所以我還是給他報名下去了。起點跟終點都是在向山遊客中心</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/-YvCflS5NTSU/UpB7jE-pdsI/AAAAAAAFGV4/cy-VtA8-HYg/w350/IMAG1196.jpg">
<img alt="img" src="https://lh5.googleusercontent.com/-qRCEcTCy9VM/UpB7k3wmskI/AAAAAAAFGWA/p0bCW_4DuFQ/w350/IMAG1197.jpg">
跟戰友Alvin起跑前跟熱氣球拍照。</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/-HOmnKovYxdg/UpB7_y3s2wI/AAAAAAAFGWQ/Wz-I4612NzI/w995-h563-no/IMAG1219.jpg">
全馬組出發!</p>
<p><img alt="img" src="https://lh5.googleusercontent.com/-1xxAAyN0XLU/UpB8D9QtHbI/AAAAAAAFGWc/T8POei6rtEE/w995-h563-no/IMAG1221.jpg">
15分鐘後,超半馬組也出發了!</p>
<p><img alt="img" src="https://lh5.googleusercontent.com/-RqcGdvgiRV4/UpB8PsAeL6I/AAAAAAAFGWk/iv8EJSwwHvk/w995-h563-no/IMAG1224.jpg">
日月潭之前來過很多次,但從來沒有那麼早來過,萬萬沒想到清晨的日月潭那麼厲害。太陽躲在山後,讓山景非常有層次。讓剛起跑的我非常讚歎!忍不住拍了好幾張照片
<img alt="img" src="https://lh4.googleusercontent.com/-qbQn1IhJw0c/UpB8aa8-a9I/AAAAAAAFGXA/nkPp1ilfTes/w995-h563-no/IMAG1231.jpg">
<img alt="img" src="https://lh4.googleusercontent.com/-82Ij1WmKuxo/UpB8WqWN2xI/AAAAAAAFGWs/s9Dqpmk7Ug0/w995-h563-no/IMAG1227.jpg">
很多跑友也都停下腳步拍照留念</p>
<p><img alt="img" src="https://lh5.googleusercontent.com/-9boBF_MNXNE/UpB8ZTZvKqI/AAAAAAAFGW4/lGWyUlths60/w995-h563-no/IMAG1228.jpg">
漂亮的湖光山色
<img alt="img" src="https://lh4.googleusercontent.com/-7SkuYuKfyI8/UpYVGB1c3WI/AAAAAAAFGfY/vCfPlxtraUM/w400/">
<img alt="img" src="https://lh3.googleusercontent.com/-ADM2SZB9hQg/UpB8bP8S1CI/AAAAAAAFGXE/VK-REoc6AJQ/w995-h563-no/IMAG1234.jpg">
<img alt="img" src="https://lh4.googleusercontent.com/-NZaivyb7BFU/UpB8gH3n87I/AAAAAAAFGXM/vKgAYgmG5ko/w995-h563-no/IMAG1244.jpg">
美好的晨跑時光,就在太陽高高昇起後告個段落。我的右膝蓋從7K左右開始抗議。當下就知道這是田中初馬時所受的傷,還沒有完全復原。膝蓋的內側每跑一步就有刺痛感。我趕緊調整跑步的姿勢,讓右腳可以好受一點。並開始期待等下的補給站有肌樂可以止痛一下,可惜路過好幾個補給站都沒有肌樂,只能摸摸鼻子繼續跑下去,終於在16K玄奘寺補給站,看到有止痛噴劑,趕緊拿來噴了好幾下。希望在師父加持之下可以撐下去。這邊也有特色補給品:香菇茶葉蛋
<img alt="img" src="https://lh5.googleusercontent.com/-RHh15aF7B4Y/UpB_xGMdBLI/AAAAAAAFGZk/yF-M79O_q2s/w320-h566-no/IMAG1245.jpg"></p>
<p>賽事的後半段,大多是緩下坡,我原本以為可以開始加速。但雙腳膝蓋開始輪流罷工。雙腿也愈來愈僵硬,此時只能硬撐下去,但速度愈來愈慢,甚至痛到只能步行。找到機會就抬腿拉拉筋。</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/-c935fdDTMxc/UpB81etyXXI/AAAAAAAFGZY/1vA1410q6H0/w995-h563-no/IMAG1252.jpg">
過了20K,完全就是拖著雙腳在走,膝蓋一彎就痛。</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/-7evZdhw8CSQ/UpB8261EJzI/AAAAAAAFGZY/peACXug59rE/w995-h563-no/IMAG1251.jpg">
突然後面出現了警察伯伯緩慢前進。驚!這不是第一名才會有的尊榮前導車嗎?XD 原來這場賽事的交通管制是警察會把跟我們同方向的汽車擋下來緩慢的行進。而有多慢呢?大概就是我那時前進10分速,因此大部份的跑者都可以享受到沒有什麼車流的完美賽道。但是被擋下來的在地人或遊客可就不開心了,甚至有人還對警察咆哮大罵。之後警察才勉強加速一些,而這群車隊也就離我而去了。</p>
<p><img alt="img" src="https://lh5.googleusercontent.com/--KZ4lxlERvU/UpB9OzuJe8I/AAAAAAAFGZY/I6lfcb3NuUA/w995-h563-no/IMAG1255.jpg">
終於到最後的3K,真的是快解脫了。全半跟超半馬也是在此分開。全馬還要左轉台21線,補足13公里到全馬的42公里。當下我真的很慶幸我只需要再跑3K就可以收工。最後的3K是個魔鬼上坡路段。</p>
<p><img alt="img" src="https://lh3.googleusercontent.com/vMJVZobsmXmGWKdWOfV4Inq1aj9JDSHBhrqLtgvQ4JPH=w995-h563-no">
還好沿途開始出現大量的暨大同學志工,幫我們加油打氣。</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/-0-880U9e0Xs/UpB9W4DH3KI/AAAAAAAFGZY/Ky9c0-Vdfg0/w377-h566-no/DSC_1347.JPG"></p>
<p>這時就是一步一步的堅持,雖然只能龜速前進。慢慢吃掉最後的3K。但當開始聽到熱鬧的會場麥克風聲音時,我知道離會場已經很近。志工們也列隊跟我擊掌加油!令人非常的感動,,最後也順利的回到終點。</p>
<p><img alt="img" src="https://lh3.googleusercontent.com/-HGecqkx29Cw/UpB9ZzVHy4I/AAAAAAAFGZY/nUh0b8Ayzsc/w995-h563-no/IMAG1261.jpg">
最後到終點時,全馬計時錶已經來到4小時半。</p>
<p><img alt="img" src="https://lh6.googleusercontent.com/-Oss42kdCLFI/UpB9bQGYUMI/AAAAAAAFGZY/WzaailbqDm0/w995-h563-no/IMAG1262.jpg">
終點有志工妹妹幫忙掛上獎牌。獎牌不同於一般的金屬材質,這場是特別的琉璃材質</p>
<p>這次超半馬也是特別有意義,因為這場是我的好同事Alvin的初馬。他因為膝蓋受傷的關係,已經錯過了好幾場已經報名的全馬賽事,只能選擇棄賽。這場他要挑戰他的人生初馬。這場他以5小時左右的成績完賽,在有腳傷的情況下,相當厲害。</p>
<p><img alt="img" src="https://lh6.googleusercontent.com/ac1chZpQIWGzJV7yBPFX8qMkjfxrHCaElzKWR9W2Q-wB=w994-h562-no">
我在終點前也補捉到他飛奔進終點的英姿</p>
<p><img alt="img" src="https://lh5.googleusercontent.com/-6uRu3rKwbUQ/UpYVEtKhOmI/AAAAAAAFGfM/Uy6Y2BPV8U0/w600/"> <br>
之後亂入,跟著小跑一段</p>
<p>只要不停下腳步,就一定會離終點愈來愈近。馬拉松賽雖然是個運動比賽,但大多數的人來參加並不是要爭取名次,不是跟別人挑戰,而是跟自己挑戰,並且來享受這場比賽的迷人之處。我雖然沒辦法跑的那麼快,但是可以跟第一名一樣進同樣的終點。</p>
<p><img alt="img" src="https://lh5.googleusercontent.com/-7M0WFsWEfFY/UpB9rBJCpcI/AAAAAAAFGZY/elAIUI7qrc4/w406-h566-no/%25E6%2588%2590%25E7%25B8%25BE.jpg"><br>
最後還是因為練習量不足,所以成績不盡理想。</p>
<hr>
<p>最近附上我實測的路線與高度圖</p>
<p>路線圖</p>
<p><img alt="img" src="https://lh6.googleusercontent.com/-MPFEo9YJ-yk/UpB9rC3J-eI/AAAAAAAFGZY/7XTAbVqO-l8/w871-h566-no/%2540_%25E8%25B7%25AF%25E7%25B7%259A%25E5%259C%2596.png"></p>
<p>高度圖</p>
<p><img alt="img" src="https://lh5.googleusercontent.com/--2jq4neGj-c/UpB9rAzrdWI/AAAAAAAFGZY/qJTsFkh1sL4/w871/%25E9%25AB%2598%25E5%25BA%25A6%25E5%259C%2596.png 871"></p>2013田中馬拉松-初馬42.195公里挑戰2013-11-10T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-11-10:/tianzhong-marathon/<p><img alt="img" src="https://lh6.googleusercontent.com/-E0QYTCPMU5g/UoCFTik77BI/AAAAAAAFGRw/3EATFZKgfmI/w1240/IMAG1088.jpg"></p>
<p>今年也參加了近十場路跑活動, 但是這些都是之前設定為了我的初馬:<strong>田中馬拉松</strong>所做的準備。七月底報名看到同事Alvin在搶報名馬拉松,只是一股湊熱鬧的心態也就跟著報名,那時侯頂多在碧湖公園練習跑個10公里。三個月訓練下來雖然有半馬21K跟超半馬23K賽事的經歷,但是前陣子卻因為意外而導致掌骨骨折。讓自己有個藉口可以鬆懈,中斷練習了二個星期。而自己也大意沒有確實練習長距離30K的LSD。路跑當天還是硬著頭皮上場,面對這場人生初馬。</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/-WPX1JxZWjEo/UoCFSBXX2YI/AAAAAAAFGRM/Jj4BRJ-rEO8/w995-h563-no/IMAG1079.jpg">
出發!</p>
<p><img alt="img" src="https://lh6.googleusercontent.com/-bHsieN1fN08/UoCFSmwfBtI/AAAAAAAFGRU/b8G86H75YB8/w995-h563-no/IMAG1083.jpg">
剛開始出發就被海軍陸戰隊的管樂演奏給感動,</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/k0b9T9mp3jkimoE35dd8xwLWlI6m-yTI7ClrWCISbVow=w995-h563-no">
補給大部份都是水果。</p>
<p><img alt="img" src="https://lh5.googleusercontent.com/-sj4r29YjAis/UoCFWB_cKII/AAAAAAAFGZY/Ax8ZHu-AEzM/w995-h563-no/IMAG1101.jpg"></p>
<p>田中馬的最大特色,就是全鎮鄉民總動員幫選手加油。
<img alt="img" src="https://lh5.googleusercontent.com/-OIbOv3qM9iQ/UoCFcGfjrrI/AAAAAAAFGZY/wz6td352wd4/w995-h564-no/VIDEO0030_0000000000.jpg">
沿途也都可以看到民眾自製加油看板幫忙加油打氣。</p>
<p>但其實這場初馬跑的非常吃力,已經嚴重超過我可以負荷的程度。經過天堂路跟好漢坡的洗禮之後,僅存肌力完全被吃光光。開始整路步兵。</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/-WwWGZXMzb9Y/UoCFXR6GHzI/AAAAAAAFGZY/SljRrwBQJUY/w995-h563-no/IMAG1106.jpg"></p>
<p>到了30多K時,發現後面慢慢的人也就逐漸地變少了。志工也開始騎機車在四周巡迴尋找撐不下的跑者。我就憑著一點點堅持,就算跑不動了,我還是希望可以完成這場初馬。我花了七點多小時才抵達終點,足足比表定的關門時間還晚了快一個小時。很感謝補給站熱情的志工,裁判的耐心等待。完成了這場關門初馬。</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/-22djMOo2bcA/UoCFam7NBXI/AAAAAAAFGZY/INc5SOVpKgc/w995-h563-no/IMAG1120_1.jpg"></p>
<p><img alt="img" src="https://lh6.googleusercontent.com/-SA1q48Wlp6I/UoCFcgm2EuI/AAAAAAAFGZY/sd10tj9MoAY/w320-h566-no/%25E5%2588%259D%25E9%25A6%25AC%25E7%258D%258E.jpg"></p>Upgrade openssl from source code on Ubuntu2013-11-08T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-11-08:/openssl-upgrade/<h2>Remove previous openssl installation</h2>
<div class="highlight"><pre><span></span><code>$ sudo apt-get remove openssl libssl-dev
</code></pre></div>
<h2>Install openssl 1.0.1c from source</h2>
<div class="highlight"><pre><span></span><code>$ tar -xvf openssl-w.x.yz.tar.gz
$ <span class="nb">cd</span> openssl-w.x.yz
$ ./config --prefix<span class="o">=</span>/usr
$ sudo make install
</code></pre></div>2013信義葡萄馬拉松-初超半馬23.2KM心得2013-10-18T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-10-18:/xinyi-grape-marathon/<p>信義葡萄馬拉松今年2013是第三屆舉辦,因為前兩年的好口碑,加上台灣近年風行瘋跑步活動,所以這場葡萄馬報名一下子就被秒殺了。葡萄馬是我最近參加幾場的路賽最在地化的一場。之前有參與幾場路跑活動,感覺像是外來的客人跟這邊借場地辦活動。但是葡萄馬就完全感覺不同,跑葡萄馬可以感受到整個鄉動員起來的感覺,很棒!!</p>
<p><img alt="img" src="img https://lh3.googleusercontent.com/-gA10OgoyQfo/UmETnA_tM9I/AAAAAAAFFuc/RHq8hkI4Jck/w995-h563-no/IMAG0367.jpg"> </p>
<p>![img](img https://lh3.googleusercontent.com/-dX1S8JgA8Z0/UmETgrq_WhI/AAAAAAAFFsM/gGOX1Mk-xXc/w1024/2013100712280700001.JPG %}
轉錄自<a href="http://www.shini.gov.tw/AlbumListC1321.aspx?Class=582b54c2-1166-4e2f-906d-fe2e14a66acb&">信義鄉公所</a></p>
<p><img alt="img" src="img https://lh4.googleusercontent.com/-2ZPoU2Atxjs/UmEToThtrCI/AAAAAAAFFvM/9HqLAGb9BmY/w995-h563-no/IMAG0374.jpg">
現場大約有二十餘頭的烤乳豬。讓跑者跑完可以享用。這些食物都是用號碼布領取的,所以也不用怕跑太慢會吃不到 XD。</p>
<p><img alt="img" src="img https://lh3.googleusercontent.com/-r2RRB-D4bqk/UmET49XdakI/AAAAAAAFF0Q/iTnh2IUTDtc/w1024-no/IMAG0443.jpg">
雖然沒有室內的寄物處,不過主辦單位有準備大塑膠袋讓大家的包包不會濕掉。</p>
<p><img alt="img" src="img https://lh3.googleusercontent.com/-sHUvFBAzCWE/UmETjZ8aHLI/AAAAAAAFFto/SF2s6eFLmL4/w600/2013%25E4%25BF%25A1%25E7%25BE%25A9%25E8%2591%25A1%25E8%2590%2584%25E9%25A6%25AC%25E6%258B%2589%25E6%259D%25BE%25E5%258D%258A%25E9%25A6%25AC%25E8%25B7%25AF%25E7%25B7%259A.jpg">
半馬的路線圖</p>
<p><img alt="img" src="img https://lh4.googleusercontent.com/-MmMLYjjDdK8/UmEY-R0wqdI/AAAAAAAFF7Q/lJPyeD7Dm_U/w725-h297-no/%25E5%258D%258A%25E9%25A6%25AC%25E9%25AB%2598%25E5%25BA%25A6%25E5%259C%2596.png">
半馬的高度圖</p>
<p>基本上路線是前半段都是緩上坡,過了一半之後就開始緩下坡,最後2K會再有個挑戰最後意志力的上坡。</p>
<p><img alt="img" src="img https://lh4.googleusercontent.com/-3w9TnaD4xZw/UmETqWU8GDI/AAAAAAAFFvo/wrqvmEYOm0s/w1024-no/IMAG0379.jpg">
起跑點</p>
<p><img alt="img" src="img https://lh5.googleusercontent.com/-e8vq6wakWk0/UmETosAd3XI/AAAAAAAFFvI/emvedmbwukg/w995-h563-no/IMAG0377.jpg"></p>
<p><img alt="img" src="img https://lh4.googleusercontent.com/-Da3C8vDiAZI/UmETqqj_RmI/AAAAAAAFFvw/-_aacKAR1x4/w1024-h312-no/IMAG0382.jpg">
布農族的長輩用獵槍鳴槍起跑</p>
<p><img alt="img" src="img https://lh3.googleusercontent.com/-louRFS8MShE/UmETsAKQpfI/AAAAAAAFFwE/enRSFP_rkUg/w1024/IMAG0388.jpg">
剛開始出發都還是很平坦的大馬路</p>
<p><img alt="img" src="img https://lh4.googleusercontent.com/-IhV-Zm6sjhg/UmETsXoqD_I/AAAAAAAFFwA/8LDjPAuwjUw/w1024/IMAG0391.jpg">
沿路可以看到很多葡萄園
<img alt="img" src="img https://lh6.googleusercontent.com/-fSDPYlaZdUw/UmETuB4K-tI/AAAAAAAFFwo/I9M-1oIFe3A/w1024/IMAG0395.jpg">
目前看都還綠綠的,11月過後才算盛產</p>
<p><img alt="img" src="img https://lh4.googleusercontent.com/-OwEEtA6mHmM/UmETtCNk7qI/AAAAAAAFFwU/BDr94MXpfF8/w1024/IMAG0393.jpg">
超半馬跟全馬在這邊分開了,路上都有白色的標記</p>
<p><img alt="img" src="img https://lh6.googleusercontent.com/-K_EUPfa83Zw/UmETumU5GbI/AAAAAAAFFws/G35HUA7tuOo/w1024/IMAG0396.jpg">
馬路開始愈來愈小條,往山裡面跑了</p>
<p><img alt="img" src="img https://lh6.googleusercontent.com/-q-2gPTlgOvo/UmETu9P49kI/AAAAAAAFFw8/9eRbATJc2S4/w1024/IMAG0401.jpg">
不知不覺就愈跑愈高,往下看下面的跑者就跟螞蟻一樣小</p>
<p>我發現馬拉松有每場都會遇到一些人會帶狗一起跑,葡萄馬也不例外。
<img alt="img" src="img http://lh4.googleusercontent.com/t5iP17ZEl6-l1QReYval-T2eMXbKTzVLmLnC3LEDdeQe=w1204">
<img alt="img" src="img http://lh6.googleusercontent.com/4A1AxslGNeWY5YRHnUMWVSbPQfnDAhGWGLIG5oV0JSCP=w1024">
小黃跟小白</p>
<p>跑路的中途補給也是很厲害的,葡萄、梅子、蕃茄、香蕉等等</p>
<p><img alt="img" src="img https://lh5.googleusercontent.com/Htb6OEoeQ639i3xlYVEMEacvU0KRHNsaDZ9oJZe4PC1i=w1024">
轉錄自<a href="http://www.shini.gov.tw/AlbumListC1321.aspx?Class=582b54c2-1166-4e2f-906d-fe2e14a66acb&">信義鄉公所</a></p>
<p>不過,像我這種慢行人員,實際吃到的是這樣:
<img alt="img" src="img https://lh3.googleusercontent.com/wJt2mBFQXPCO1Gaq-qcVy5AaPbc6TI_R9QKiozghymBE=w800"> </p>
<p>不過還是吃得很開心。每次進站都是裝一杯葡萄,邊跑邊吃,吃到下一站。</p>
<p><img alt="img" src="img https://lh4.googleusercontent.com/-7Cy24fvLHZw/UmETs7xBAeI/AAAAAAAFFwc/p4yDw9KWDbc/w1204/IMAG0392.jpg">
好吃的葡萄</p>
<p><img alt="img" src="img https://lh4.googleusercontent.com/-9yXBmHnAFJs/UmETxxB-DdI/AAAAAAAFFx8/FjexMOEfh2M/w1024/IMAG0412.jpg">
跑到最高點往下照的景色</p>
<p><img alt="img" src="img http://lh6.googleusercontent.com/-xkyK5UplWn4/UmEUNAXrQNI/AAAAAAAFF4o/lBtnK0ECLpA/w1024/ZOE_0031_1.jpg">
小朋友在路邊加油</p>
<p><img alt="img" src="img https://lh4.googleusercontent.com/-LGCyPyAlezw/UmETz8d2xfI/AAAAAAAFFyc/QWmiZFDBsDM/w1024/IMAG0417.jpg">
後半段都是緩下坡,所以跑起來就比較輕鬆一些</p>
<p><img alt="img" src="img https://lh5.googleusercontent.com/-eZPVT6JTZN0/UmET1WR9K_I/AAAAAAAFFy4/LLx5zVzqCZg/w1024/IMAG0422.jpg">
最後2K的時侯,全馬的Richard也回來了,之前苗栗馬Richard也是跑第一名。目前的實力,跑完半馬,全馬的前段班也差不多回來了。</p>
<p><img alt="img" src="img https://lh4.googleusercontent.com/-kHsxlJ2E7Ow/UmETkiuo_dI/AAAAAAAFFts/YvYayks0aiQ/w1024/AllSport03.png">
<img alt="img" src="img http://lh4.googleusercontent.com/SIci1BHagju1mDwjck3qVXhGaEHrzm7-9ZfayWtC3VuW=w1024">
最終抵達終點前的照片</p>
<p><img alt="img" src="img https://lh4.googleusercontent.com/-lZ2K9nKMdSY/UmET3htMUBI/AAAAAAAFFzw/OhAsajwzD7s/w1024/IMAG0439.jpg">
終點的補給,飲料,熱粥,山豬肉,梅子汁,仙草茶,水,舒跑,毛巾</p>
<p><img alt="img" src="img https://lh5.googleusercontent.com/-FxhbxMG-Hjc/UmFfzfJBqmI/AAAAAAAFF84/vNDRkXc_65o/w1024-h280-no/IMAG0771.jpg">
成績 03:02:04, 總排名 667/1181</p>
<p><img alt="img" src="img https://lh5.googleusercontent.com/-DObaClaCjHI/UmFfw-mgwSI/AAAAAAAFF8w/FzG4di43ShI/w399-h547-no/StXUH63S99dCF6NBDYVM92RY.jpg">
<img alt="img" src="img https://lh4.googleusercontent.com/-xrioL3qjZBo/UmET47Skc_I/AAAAAAAFF0U/7RkbjNXVVDQ/w1024/IMAG0445.jpg">
<img alt="img" src="img https://lh6.googleusercontent.com/-Tb-wzZVISzg/UmET5fTkifI/AAAAAAAFF0c/uLtrCF1lieE/w1024/IMAG0447.jpg">
最後再喝一杯馬拉桑手工啤酒(100元/杯),完美的Ending。</p>Python generate xUnit report for Jenkins2013-07-18T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-07-18:/python-generate-xunit-report-for-jenkins/<p>在日常使用的Test Framework所產出的Test Report並不是標準的 JUnit 格式。所以這使得想要回傳Test Result到Jenkins的時侯,沒辦法把 Test Result 顯示在Jenkins的Build的結果上面。然而產生JUnit report的功能在一般的Test Framework像是nose跟py.test都有,像是nose就有一個plugins是專門在處理這個問題,或者是py.test可以直接使用<code>py.test --junitxml=path</code>來產生。可惜我的工具沒有。所以只好自己弄一個了。在此記錄要如何完成這個任務。</p>
<p>上網 Google了一下有關JUnit XML format到底長怎樣,找到Stackoverflow<a href="http://stackoverflow.com/questions/4922867/junit-xml-format-specification-that-hudson-supports">這篇</a>有討論,基本上可以解決90%的疑問。有關XML的定義可以從.xsd檔中找到,而JUnit的.xsd檔,<a href="https://svn.jenkins-ci.org/trunk/hudson/dtkit/dtkit-format/dtkit-junit-model/src/main/resources/com/thalesgroup/dtkit/junit/model/xsd/junit-4.xsd">這邊</a>可以下載。我使用<a href="http://www.wmhelp.com/xmlpad3.htm">XMLPad</a>來打開,再掛載xsd的schema檔,手動體驗一下 xml 的format,基本上最簡單的的JUnit Report大概是這樣:</p>
<div class="highlight"><pre><span></span><code><span class="nt"><testsuites</span> <span class="na">xsi:noNamespaceSchemaLocation=</span><span class="s">"file:///D:/junit-4.xsd"</span> <span class="na">xmlns:xsi=</span><span class="s">"http://www.w3.org/2001/XMLSchema-instance"</span><span class="nt">></span>
<span class="nt"><testsuite</span> <span class="na">name=</span><span class="s">"INSTALLATION RAT"</span><span class="nt">></span>
<span class="nt"><testcase</span> <span class="na">classname=</span><span class="s">"INS_RAT_0001"</span> <span class="na">name=</span><span class="s">"Test Case Title Sample 1"</span> <span class="na">time=</span><span class="s">"0.046"</span><span class="nt">></span>
<span class="nt"><system-out></system-out></span>
<span class="nt"></testcase></span>
<span class="nt"><testcase</span> <span class="na">classname=</span><span class="s">"INS_RAT_0002"</span> <span class="na">name=</span><span class="s">"Test Case Title Sample 2"</span> <span class="na">time=</span><span class="s">"4.868"</span><span class="nt">></span>
<span class="nt"><failure</span> <span class="na">message=</span><span class="s">"case failed …</span></code></pre></div><p>在日常使用的Test Framework所產出的Test Report並不是標準的 JUnit 格式。所以這使得想要回傳Test Result到Jenkins的時侯,沒辦法把 Test Result 顯示在Jenkins的Build的結果上面。然而產生JUnit report的功能在一般的Test Framework像是nose跟py.test都有,像是nose就有一個plugins是專門在處理這個問題,或者是py.test可以直接使用<code>py.test --junitxml=path</code>來產生。可惜我的工具沒有。所以只好自己弄一個了。在此記錄要如何完成這個任務。</p>
<p>上網 Google了一下有關JUnit XML format到底長怎樣,找到Stackoverflow<a href="http://stackoverflow.com/questions/4922867/junit-xml-format-specification-that-hudson-supports">這篇</a>有討論,基本上可以解決90%的疑問。有關XML的定義可以從.xsd檔中找到,而JUnit的.xsd檔,<a href="https://svn.jenkins-ci.org/trunk/hudson/dtkit/dtkit-format/dtkit-junit-model/src/main/resources/com/thalesgroup/dtkit/junit/model/xsd/junit-4.xsd">這邊</a>可以下載。我使用<a href="http://www.wmhelp.com/xmlpad3.htm">XMLPad</a>來打開,再掛載xsd的schema檔,手動體驗一下 xml 的format,基本上最簡單的的JUnit Report大概是這樣:</p>
<div class="highlight"><pre><span></span><code><span class="nt"><testsuites</span> <span class="na">xsi:noNamespaceSchemaLocation=</span><span class="s">"file:///D:/junit-4.xsd"</span> <span class="na">xmlns:xsi=</span><span class="s">"http://www.w3.org/2001/XMLSchema-instance"</span><span class="nt">></span>
<span class="nt"><testsuite</span> <span class="na">name=</span><span class="s">"INSTALLATION RAT"</span><span class="nt">></span>
<span class="nt"><testcase</span> <span class="na">classname=</span><span class="s">"INS_RAT_0001"</span> <span class="na">name=</span><span class="s">"Test Case Title Sample 1"</span> <span class="na">time=</span><span class="s">"0.046"</span><span class="nt">></span>
<span class="nt"><system-out></system-out></span>
<span class="nt"></testcase></span>
<span class="nt"><testcase</span> <span class="na">classname=</span><span class="s">"INS_RAT_0002"</span> <span class="na">name=</span><span class="s">"Test Case Title Sample 2"</span> <span class="na">time=</span><span class="s">"4.868"</span><span class="nt">></span>
<span class="nt"><failure</span> <span class="na">message=</span><span class="s">"case failed"</span> <span class="na">type=</span><span class="s">"failure"</span><span class="nt">/></span>
<span class="nt"><system-out></system-out></span>
<span class="nt"><system-err></system-err></span>
<span class="nt"></testcase></span>
<span class="nt"></testsuite></span>
<span class="nt"></testsuites></span>
</code></pre></div>
<p>有關一些測試數量,成功數量,失敗數量,我都省略不寫上去,因為我發現Jenkins會自動幫我們算。再來,下面是一小段產生XML Report 的 Sample Code:</p>
<div class="highlight"><pre><span></span><code><span class="k">def</span> <span class="nf">createXUnitReport</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">testResult</span><span class="p">):</span>
<span class="n">lstSuites</span> <span class="o">=</span> <span class="n">testResult</span><span class="o">.</span><span class="n">getTestsuiteList</span><span class="p">()</span>
<span class="n">eleTestsuites</span> <span class="o">=</span> <span class="n">Element</span><span class="p">(</span><span class="s1">'testsuites'</span><span class="p">)</span>
<span class="k">for</span> <span class="n">strSuiteName</span> <span class="ow">in</span> <span class="n">lstSuites</span><span class="p">:</span>
<span class="n">eleTestsuite</span> <span class="o">=</span> <span class="n">SubElement</span><span class="p">(</span><span class="n">eleTestsuites</span><span class="p">,</span> <span class="s1">'testsuite'</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">strSuiteName</span><span class="p">)</span>
<span class="k">for</span> <span class="n">strTestCaseName</span><span class="p">,</span> <span class="n">dicResult</span> <span class="ow">in</span> <span class="n">testResult</span><span class="o">.</span><span class="n">_dicSuites</span><span class="p">[</span><span class="n">strSuiteName</span><span class="p">][</span><span class="s1">'testcases'</span><span class="p">]</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="n">eleTestcase</span> <span class="o">=</span> <span class="n">SubElement</span><span class="p">(</span><span class="n">eleTestsuite</span><span class="p">,</span> <span class="s1">'testcase'</span><span class="p">,</span> <span class="n">classname</span><span class="o">=</span><span class="n">strTestCaseName</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="n">dicResult</span><span class="p">[</span><span class="s1">'title'</span><span class="p">],</span> <span class="n">time</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">tmstafTimeToSeconds</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_getStrTime</span><span class="p">(</span><span class="n">dicResult</span><span class="p">[</span><span class="s1">'elapsedTime'</span><span class="p">],</span> <span class="s2">"00:00:00"</span><span class="p">)))</span>
<span class="k">if</span> <span class="n">dicResult</span><span class="p">[</span><span class="s1">'fails'</span><span class="p">]:</span>
<span class="n">SubElement</span><span class="p">(</span><span class="n">eleTestcase</span><span class="p">,</span> <span class="s1">'failure'</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="s2">"failure"</span><span class="p">,</span> <span class="n">message</span><span class="o">=</span><span class="s2">"case failed"</span><span class="p">)</span>
<span class="k">if</span> <span class="n">dicResult</span><span class="p">[</span><span class="s1">'crashes'</span><span class="p">]:</span>
<span class="n">SubElement</span><span class="p">(</span><span class="n">eleTestcase</span><span class="p">,</span> <span class="s1">'error'</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="s2">"crash"</span><span class="p">,</span> <span class="n">message</span><span class="o">=</span><span class="s2">"case crash"</span><span class="p">)</span>
<span class="c1">#@todo: add system-out / system-err message </span>
<span class="n">result</span> <span class="o">=</span> <span class="n">tostring</span><span class="p">(</span><span class="n">eleTestsuites</span><span class="p">)</span>
<span class="n">f</span> <span class="o">=</span> <span class="n">file</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_strDestDir</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">strJUnitXml</span><span class="p">),</span> <span class="s1">'wb'</span><span class="p">)</span>
<span class="n">f</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="n">f</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</code></pre></div>
<p>當把產生這份Report功能完成之後。我在 Jenkins 驅動遠端測試機器執行測試,跑完之後使用STAF的FS Command把Test Report收回來放在jenkins的workspace中。這樣我就可以有一個最簡單來反應Build的Test Result了。</p>
<p>PS:在JUnit中,Testcase 的結果 Failure 跟 Error 有何不同? Failure 是指因為 assertion 所造成的 Fail,可以當成是寫Tester預期中的Fail,代表待測物行為跟我們預期的結果不行。而Error則是Exception產成的Error,可以當成是<strong>非預期</strong>的錯誤,像是程式噴Exception或是Crash等等。</p>
<h3>Reference :</h3>
<ul>
<li>Apache Ant JUnit XML Schema : <a href="http://goo.gl/EkSeL">http://goo.gl/EkSeL</a></li>
<li><a href="http://stackoverflow.com/questions/4922867/junit-xml-format-specification-that-hudson-supports">JUnit XML Format Specification that Hudson supports - Stack Overflow</a></li>
<li><a href="http://pypi.python.org/pypi/unittest-xml-reporting">http://pypi.python.org/pypi/unittest-xml-reporting</a></li>
<li><a href="http://www.doughellmann.com/PyMOTW/xml/etree/ElementTree/create.html">http://www.doughellmann.com/PyMOTW/xml/etree/ElementTree/create.html</a></li>
</ul>20分鐘了解 CPU 基本運作2013-06-02T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-06-02:/how-cpu-works/<p>這兩天發現了一個不錯的教學影片,用二十分鐘左右的時間介紹CPU的基本運作原理,相當值得一看。</p>
<iframe width="560" height="315" src="http://www.youtube.com/embed/cNN_tTXABUA" frameborder="0" allowfullscreen></iframe>
<p>這個影片主要是來自一本書<a href="http://www.amazon.com/But-How-Know-Principles-Computers/dp/0615303765/ref=sr_1_1?ie=UTF8&qid=1370181735&sr=8-1&keywords=But+how+do+it+know">《But How Do It Know》</a>,天瓏這本代訂購一本賣 946,薄薄的一本,只有2百多頁。這本書虛構了一個Scott CPU來舉例,我看完教學影片做了一些筆記當參考:</p>
<h1>Instruction Set</h1>
<p>CPU 基於最基本的 Instruction Set 來達成複雜的工作。例如:</p>
<ul>
<li><strong>Load</strong> a number from RAM into the CPU</li>
<li><strong>ADD</strong> two numbers toether</li>
<li><strong>STORE</strong> a number from the CPU back out to RAM</li>
<li><strong>COMPARE</strong> one number with another </li>
<li><strong>JUMP IF</strong> <em>Condition</em> to another address in RAM</li>
<li><strong>JUMP</strong> to another address in RAM </li>
<li><strong>OUT</strong>put to a device such as a monitor </li>
<li><strong>IN</strong>put to from a device such as a keyboard</li>
</ul>
<h1>基本元件</h1>
<p>從這個影片中,整理一下一些元件的用途</p>
<h2>Random access memory(RAM)</h2>
<p>其 Random 之意就是代表可以隨意存取某個Addreess的資料。RAM主要分兩部份,Address 和 Data。CPU 可以要求從某個 …</p><p>這兩天發現了一個不錯的教學影片,用二十分鐘左右的時間介紹CPU的基本運作原理,相當值得一看。</p>
<iframe width="560" height="315" src="http://www.youtube.com/embed/cNN_tTXABUA" frameborder="0" allowfullscreen></iframe>
<p>這個影片主要是來自一本書<a href="http://www.amazon.com/But-How-Know-Principles-Computers/dp/0615303765/ref=sr_1_1?ie=UTF8&qid=1370181735&sr=8-1&keywords=But+how+do+it+know">《But How Do It Know》</a>,天瓏這本代訂購一本賣 946,薄薄的一本,只有2百多頁。這本書虛構了一個Scott CPU來舉例,我看完教學影片做了一些筆記當參考:</p>
<h1>Instruction Set</h1>
<p>CPU 基於最基本的 Instruction Set 來達成複雜的工作。例如:</p>
<ul>
<li><strong>Load</strong> a number from RAM into the CPU</li>
<li><strong>ADD</strong> two numbers toether</li>
<li><strong>STORE</strong> a number from the CPU back out to RAM</li>
<li><strong>COMPARE</strong> one number with another </li>
<li><strong>JUMP IF</strong> <em>Condition</em> to another address in RAM</li>
<li><strong>JUMP</strong> to another address in RAM </li>
<li><strong>OUT</strong>put to a device such as a monitor </li>
<li><strong>IN</strong>put to from a device such as a keyboard</li>
</ul>
<h1>基本元件</h1>
<p>從這個影片中,整理一下一些元件的用途</p>
<h2>Random access memory(RAM)</h2>
<p>其 Random 之意就是代表可以隨意存取某個Addreess的資料。RAM主要分兩部份,Address 和 Data。CPU 可以要求從某個 Address 讀出 Data。而RAM的Data又可以分成好幾種類型:
- 指令集
- 數字
- 另一個記憶體位置
- 字元</p>
<h2>Control Unit</h2>
<p>CPU 可以說是電腦的大腦,而 Control Unit 則可以說是CPU的艦長,負責發號司令負責叫ALU運算跟控制暫存器</p>
<h2>Arithmetic Logic Unit(ALU)</h2>
<p>負責實際運算的部份,Input 由 Control Unit 控制,運算完的結果透過 Output 或是 Flags 來讓 Control Unit 知道結果</p>
<h2>BUS(匯流排)</h2>
<p>ALU, Control Unit 和 Register 透過共用的BUS來轉移資料</p>
<h2>Register</h2>
<p>Register(暫存器)在 CPU 裡面扮演重要的腳色,它們讓 ALU 計算出來的數值可以有地方暫時存放,以供之後的運算。而Control unit 會用<code>set wire</code>跟<code>enable wire</code>來控制那些 Register 會被寫入,和輸出:
- set wire: 讓 ALU 計算完的值可以透過 bus(匯流排)來寫入 register
- enable wire: 讓register的值可以輸出到 bus 上 </p>
<p>因為多個 Register 彼此共用一個 bus,為了要讓 ALU 可以讀到兩個Input,會在其中一個Input 加入一個 Temp register,讓這個 register 可以暫時鎖死一個值到 ALU,然後另一個值再從Register中用 enable wire直接打到 ALU上 。</p>
<h3>其它的Register</h3>
<ul>
<li>Instruction register: 把指令的種類輸出到 Control Unit </li>
<li>Instruction address register: 下一個指令所在的 address 輸出到 memory address register</li>
<li>Memory address register: 把 address 輸出到 Memory </li>
</ul>
<h1>參考連結</h1>
<ul>
<li><a href="http://www.youtube.com/watch?v=wOuYLq6vfLE">AMD CPU製作過程中文 - YouTube</a></li>
<li><a href="http://visual6502.org/JSSim/index.html">Visual 6502 in JavaScript</a>, 利用 HTML5 的技術來視覺化 AppleII 使用的 CPU 6502</li>
<li><a href="http://ejournal.stpi.narl.org.tw/NSC_INDEX/Journal/EJ0001/9903/9903-11.pdf">積體電路的發明</a></li>
</ul>Mobile is eating the world2013-06-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-06-01:/trend-mobile-is-eating-the-world/<p>這個投影片還蠻不錯的。用數字說明Mobile是如何正在主宰整個資訊產業</p>
<iframe src="http://www.slideshare.net/slideshow/embed_code/21354744" width="597" height="486" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC;border-width:1px 1px 0;margin-bottom:5px" allowfullscreen webkitallowfullscreen mozallowfullscreen> </iframe>
<div style="margin-bottom:5px"> <strong> <a href="http://www.slideshare.net/bge20/2013-05-bea" title="2013 05 BEA - ’Mobile is eating the World’" target="_blank">2013 05 BEA - ’Mobile is eating the World’</a> </strong> from <strong><a href="http://www.slideshare.net/bge20" target="_blank">Benedict Evans</a></strong> </div>
<h1>其中我看到的一些事實</h1>
<ul>
<li>Smart phone 和 tablets 從 2007 年開始僅花了四年的時間,從於2011年開始每年的銷售的裝置數已超越PC。</li>
<li>PC平均每4~5年更換一次,Mobile device平均每2年更換一次</li>
<li>Mobile相較於PC所擁有的一些優勢: <ul>
<li>知道使用者的所在位置: location based service(LBS),</li>
<li>Apps 之間常常有密切的整合服務: 地址用 Google Map開,影片用 Youtube開, 文章記錄到 Evernote中</li>
<li>Prediction. 因為手機是使用者一天當中長時間持有,用取得使用者的資訊比較多,較容易做出一些預測服務(Ex: <a href="http://www.google.com/landing/now/">Google Now</a>)</li>
<li>其它的像是 NFS, Image recognition 目前似乎還沒有看到什麼殺手級應用</li>
</ul>
</li>
<li>自帶微軟系統的裝置數量直線下滑,微軟在資訊產業的影響力逐漸變小</li>
<li>行動裝置由 Apple 和 Samsung 主導市場</li>
<li>電子閱讀器市場平緩進步: Amazon 營收逐年增加,但淨利卻只有持平</li>
<li>電子商務逐年增加,新創公司常常做商品導購的服務</li>
<li>行動世界的四巨頭: Apple, Google, Facebook, Amazon</li>
</ul>從 Octorpess 搬家到 Pelican2013-05-31T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-05-31:/From-Octopress-To-Pelican/<p>這是一個披著Octopress皮的Pelican. XD</p>
<p>前幾天的參加了<a href="http://tw.pycon.org/2013/zh/">PyConTaiwan</a>後,對於Python的忠誠度又提升了不少。於是就一時興起Survey了一下Python的Blog系統,花了一些時間,從原本Rudy 的 Octopress blog系統轉換到Python的Pelican Blog系統了。Octopress也沒有什麼不好。但是畢竟octopress是一個我沒有接觸過的Ruby語言,當需要做一些調整,想要去看程式碼時,總是沒有比我比較熟悉的Python來得親近。但是,因為Octopress的外觀實在簡單好看,又希望盡量無痛轉移,於是我就選擇了<a href="https://github.com/duilio/pelican-octopress-theme">pelican-octopress-theme</a>,做為我的佈景主題。</p>
<p>從Octopress搬到Pelican,我主要是參考這篇<a href="http://jakevdp.github.io/blog/2013/05/07/migrating-from-octopress-to-pelican/">Migrating from Octopress to Pelican</a>文章,裡面有詳盡的Migrate步驟。</p>
<h2>Pelican 的優點</h2>
<ul>
<li>100% Python</li>
<li>是目前最活躍的Python Blog 之一</li>
<li>是Static Page Blog系統,快,安全。</li>
</ul>
<h2>Deploy 到 Github Page</h2>
<p>Github 的 user page。靜態網頁一定要放在<code>Master</code>branch,而我開了另一個Source branch來放原始的Markdown檔案。使用<a href="http://docs.getpelican.com/en/3.0/tips.html">ghp-import</a>這個工具(沒錯,這也是Python的)可以讓deploy到github上更方便,可以平常就待在source branch來維護原始檔案的更新,而deploy則是透過指令,自動更新到<code>Master</code> branch,指令如下:</p>
<div class="highlight"><pre><span></span><code><span class="n">pelican</span> <span class="o">-</span><span class="n">s</span> <span class="n">pelicanconf</span><span class="o">.</span><span class="n">py</span> <span class="n">content</span><span class="o">/</span> <span class="o">&&</span> <span class="n">ghp</span><span class="o">-</span><span class="kn">import</span> <span class="nn">output</span> <span class="o">-</span><span class="n">b</span> <span class="n">master</span> <span class="o">-</span><span class="n">p</span>
</code></pre></div>
<p>也可以加到<code>Makefile</code>的git,裡面預設是<code>gh-pages</code>,記得改成 <code>master</code></p>
<div class="highlight"><pre><span></span><code><span class="n">github</span><span class="p">:</span> <span class="n">publish</span>
<span class="n">ghp</span><span class="o">-</span><span class="kn">import</span> <span class="nn">output</span> <span class="o">-</span><span class="n">b</span> <span class="n">master</span> <span class="o">-</span><span class="n">p</span>
</code></pre></div>
<p>這樣之後執行<code>make github …</code></p><p>這是一個披著Octopress皮的Pelican. XD</p>
<p>前幾天的參加了<a href="http://tw.pycon.org/2013/zh/">PyConTaiwan</a>後,對於Python的忠誠度又提升了不少。於是就一時興起Survey了一下Python的Blog系統,花了一些時間,從原本Rudy 的 Octopress blog系統轉換到Python的Pelican Blog系統了。Octopress也沒有什麼不好。但是畢竟octopress是一個我沒有接觸過的Ruby語言,當需要做一些調整,想要去看程式碼時,總是沒有比我比較熟悉的Python來得親近。但是,因為Octopress的外觀實在簡單好看,又希望盡量無痛轉移,於是我就選擇了<a href="https://github.com/duilio/pelican-octopress-theme">pelican-octopress-theme</a>,做為我的佈景主題。</p>
<p>從Octopress搬到Pelican,我主要是參考這篇<a href="http://jakevdp.github.io/blog/2013/05/07/migrating-from-octopress-to-pelican/">Migrating from Octopress to Pelican</a>文章,裡面有詳盡的Migrate步驟。</p>
<h2>Pelican 的優點</h2>
<ul>
<li>100% Python</li>
<li>是目前最活躍的Python Blog 之一</li>
<li>是Static Page Blog系統,快,安全。</li>
</ul>
<h2>Deploy 到 Github Page</h2>
<p>Github 的 user page。靜態網頁一定要放在<code>Master</code>branch,而我開了另一個Source branch來放原始的Markdown檔案。使用<a href="http://docs.getpelican.com/en/3.0/tips.html">ghp-import</a>這個工具(沒錯,這也是Python的)可以讓deploy到github上更方便,可以平常就待在source branch來維護原始檔案的更新,而deploy則是透過指令,自動更新到<code>Master</code> branch,指令如下:</p>
<div class="highlight"><pre><span></span><code><span class="n">pelican</span> <span class="o">-</span><span class="n">s</span> <span class="n">pelicanconf</span><span class="o">.</span><span class="n">py</span> <span class="n">content</span><span class="o">/</span> <span class="o">&&</span> <span class="n">ghp</span><span class="o">-</span><span class="kn">import</span> <span class="nn">output</span> <span class="o">-</span><span class="n">b</span> <span class="n">master</span> <span class="o">-</span><span class="n">p</span>
</code></pre></div>
<p>也可以加到<code>Makefile</code>的git,裡面預設是<code>gh-pages</code>,記得改成 <code>master</code></p>
<div class="highlight"><pre><span></span><code><span class="n">github</span><span class="p">:</span> <span class="n">publish</span>
<span class="n">ghp</span><span class="o">-</span><span class="kn">import</span> <span class="nn">output</span> <span class="o">-</span><span class="n">b</span> <span class="n">master</span> <span class="o">-</span><span class="n">p</span>
</code></pre></div>
<p>這樣之後執行<code>make github</code>就可以更新網誌了。</p>
<!--## pygments
在 :::identifier
<code goes here>
-->
<div class="highlight"><pre><span></span><code>
</code></pre></div>Install testlink on CentOS2013-05-12T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-05-12:/install-testlink-on-centos/<p>In this post, I'll try to explain how to install <a href="http://testlink.sourceforge.net/docs/testLink.php">Test link 1.9.3</a> on CentOS 6.2 step by step: </p>
<h2>Using yum to install required packages</h2>
<div class="highlight"><pre><span></span><code>yum install mysql-server php php-mysql php-gd php-ldap
</code></pre></div>
<h2>Modify /etc/php.ini to optimize php configuration for TestLink</h2>
<div class="highlight"><pre><span></span><code>session.gc_maxlifetime = 2400
max_execution_time = 120
</code></pre></div>
<h2>Set up web server and mysql services</h2>
<div class="highlight"><pre><span></span><code> chkconfig httpd on
chkconfig mysqld on
service httpd start
service mysqld start
</code></pre></div>
<h2>Set a password for mysql root user</h2>
<div class="highlight"><pre><span></span><code> mysqladmin -u root password NEWPASSWORD
</code></pre></div>
<h2>Add port 80 to iptables, Add the following rule into /etc/sysconfig/iptables</h2>
<div class="highlight"><pre><span></span><code>-A INPUT -m state --state NEW …</code></pre></div><p>In this post, I'll try to explain how to install <a href="http://testlink.sourceforge.net/docs/testLink.php">Test link 1.9.3</a> on CentOS 6.2 step by step: </p>
<h2>Using yum to install required packages</h2>
<div class="highlight"><pre><span></span><code>yum install mysql-server php php-mysql php-gd php-ldap
</code></pre></div>
<h2>Modify /etc/php.ini to optimize php configuration for TestLink</h2>
<div class="highlight"><pre><span></span><code>session.gc_maxlifetime = 2400
max_execution_time = 120
</code></pre></div>
<h2>Set up web server and mysql services</h2>
<div class="highlight"><pre><span></span><code> chkconfig httpd on
chkconfig mysqld on
service httpd start
service mysqld start
</code></pre></div>
<h2>Set a password for mysql root user</h2>
<div class="highlight"><pre><span></span><code> mysqladmin -u root password NEWPASSWORD
</code></pre></div>
<h2>Add port 80 to iptables, Add the following rule into /etc/sysconfig/iptables</h2>
<div class="highlight"><pre><span></span><code>-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT
</code></pre></div>
<h2>Restart Iptables:</h2>
<div class="highlight"><pre><span></span><code> service iptables restart
</code></pre></div>
<h2>Create a php file at /var/www/html to check if php works properly</h2>
<div class="highlight"><pre><span></span><code> <span class="cp"><?php</span> <span class="nb">phpinfo</span><span class="p">();</span><span class="o">></span>
</code></pre></div>
<p>Expected Screenshot
<img alt="img" src="http://content.screencast.com/users/CodyTW/folders/Jing/media/63a020a5-c31d-4d85-998f-a4e1c59ba58c/2012-04-09_1958.png"></p>
<h2>Download TestLink 1.9.3</h2>
<p>Website: <a href="http://sourceforge.net/projects/testlink/">http://sourceforge.net/projects/testlink/</a> </p>
<div class="highlight"><pre><span></span><code> <span class="n">cd</span> <span class="o">/</span><span class="k">var</span><span class="o">/</span><span class="n">www</span><span class="o">/</span><span class="n">html</span>
<span class="n">wget</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">goo</span><span class="o">.</span><span class="n">gl</span><span class="o">/</span><span class="n">HLuhE</span>
<span class="n">tar</span> <span class="n">zxvf</span> <span class="n">testlink</span><span class="o">-</span><span class="mf">1.9</span><span class="o">.</span><span class="mf">3.</span><span class="n">tar</span><span class="o">.</span><span class="n">gz</span>
<span class="n">mv</span> <span class="n">testlink</span><span class="o">-</span><span class="mf">1.9</span><span class="o">.</span><span class="mi">3</span> <span class="n">testlink</span>
<span class="n">chmod</span> <span class="o">-</span><span class="n">R</span> <span class="mi">755</span> <span class="n">testlink</span>
<span class="n">chmod</span> <span class="o">-</span><span class="n">R</span> <span class="mi">777</span> <span class="n">testlink</span><span class="o">/</span><span class="n">gui</span><span class="o">/</span><span class="n">templates_c</span>
<span class="n">chown</span> <span class="o">-</span><span class="n">R</span> <span class="n">apache</span><span class="p">:</span><span class="n">apache</span> <span class="n">testlink</span>
</code></pre></div>
<h2>Go to TestLink webpage to setup first configuration : http://server_ip/testlink</h2>
<div class="highlight"><pre><span></span><code><span class="mf">1.</span> <span class="n">Click</span> <span class="s">"New Installation"</span>
<span class="n">Screenshot</span> <span class="p">:</span> <span class="err">[</span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">screencast</span><span class="mf">.</span><span class="n">com</span><span class="o">/</span><span class="n">t</span><span class="o">/</span><span class="n">ghllOE4alWj</span><span class="err">]</span><span class="p">(</span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">screencast</span><span class="mf">.</span><span class="n">com</span><span class="o">/</span><span class="n">t</span><span class="o">/</span><span class="n">ghllOE4alWj</span><span class="p">)</span>
<span class="mf">2.</span> <span class="n">Click</span> <span class="s">" I agree to the terms set out in this license."</span>
<span class="mf">3.</span> <span class="n">There</span> <span class="n">is</span> <span class="n">checking</span> <span class="n">report</span><span class="mf">.</span> <span class="kr">To</span> <span class="n">check</span> <span class="kr">if</span> <span class="n">there</span> <span class="n">is</span> <span class="n">no</span> <span class="n">fatal</span> <span class="n">error</span><span class="mf">.</span>
<span class="n">Screenshot</span> <span class="p">:</span> <span class="err">[</span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">screencast</span><span class="mf">.</span><span class="n">com</span><span class="o">/</span><span class="n">t</span><span class="o">/</span><span class="n">niazmypZ6</span><span class="err">]</span><span class="p">(</span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">screencast</span><span class="mf">.</span><span class="n">com</span><span class="o">/</span><span class="n">t</span><span class="o">/</span><span class="n">niazmypZ6</span><span class="p">)</span> <span class="ow">and</span> <span class="n">click</span> <span class="kr">cont</span><span class="n">inue</span>
<span class="mf">4.</span> <span class="n">Here</span><span class="p">,</span> <span class="n">we</span> <span class="n">use</span> <span class="n">MySQL</span><span class="mf">.</span> <span class="n">Use</span> <span class="n">the</span> <span class="n">root</span> <span class="n">password</span> <span class="n">we</span> <span class="n">created</span> <span class="n">before</span><span class="mf">.</span> <span class="n">click</span> <span class="s">"Process TestLink Setup"</span>
<span class="mf">5.</span> <span class="nb">Log</span><span class="n">in</span> <span class="kr">to</span> <span class="n">test</span> <span class="n">link</span> <span class="n">with</span> <span class="n">admin</span><span class="o">/</span><span class="n">admin</span>
</code></pre></div>
<h2>There are some security warning need to be fixed</h2>
<ul>
<li>Change admin default password</li>
<li>Remove Install directory: <code>rm -rf /var/www/html/testlink/install/</code></li>
<li>Modify email settings: <code>cp custom_config.inc.php.example custom_config.inc.php</code></li>
</ul>
<h2>Uncomment the following four variables and modify them to your environment setting.</h2>
<div class="highlight"><pre><span></span><code><span class="err">$</span><span class="n">g_smtp_host</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'10.201.1.123'</span><span class="p">;</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="n">SMTP</span><span class="w"> </span><span class="n">server</span><span class="w"> </span><span class="n">MUST</span><span class="w"> </span><span class="n">BE</span><span class="w"> </span><span class="n">configured</span><span class="w"></span>
<span class="err">$</span><span class="n">g_tl_admin_email</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'tl_admin@testlink'</span><span class="p">;</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">problem</span><span class="o">/</span><span class="n">error</span><span class="w"> </span><span class="n">notification</span><span class="w"></span>
<span class="err">$</span><span class="n">g_from_email</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'testlink@testlink'</span><span class="p">;</span><span class="w"> </span><span class="err">#</span><span class="w"> </span><span class="n">email</span><span class="w"> </span><span class="n">sender</span><span class="w"></span>
<span class="err">$</span><span class="n">g_return_path_email</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s1">'francisco@testlink'</span><span class="p">;</span><span class="w"></span>
</code></pre></div>
<h2>Reference :</h2>
<ol>
<li>TestLink - Installation & Configuration Manual : <a href="http://goo.gl/eFNUo">http://goo.gl/eFNUo</a></li>
<li>Install TestLink : <a href="http://goo.gl/peKDv">http://goo.gl/peKDv</a></li>
<li>在linux 下配置testlink : <a href="http://goo.gl/FnUFd">http://goo.gl/FnUFd</a></li>
<li>测试管理工具TestLink的使用(一)安装篇 : <a href="http://goo.gl/pOaNR">http://goo.gl/pOaNR</a></li>
</ol>一些 New HTC One 的資訊2013-05-05T10:23:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-05-05:/new-htc-one-info/<p>第一次使用HTC的手機,整理一下 New HTC One的相關資訊。感覺這隻真的不錯,全鋁合金機身,而且又是找五月天代言,正港的MIT,一定要支持一下。</p>
<h2>剛拿到手機可以先做的事</h2>
<ul>
<li>
<p>檢查一下沒有沒縫。這隻採鋁合金外,有很漂亮的金屬質感,但是也造成上市初期的良率太低,而傳出多起<a href="http://www.mobile01.com/topicdetail.php?f=566&t=3282065">接縫</a>問題。據說五月後的貨這方面的問題少了很多</p>
</li>
<li>
<p>把舊手機的資料傳輸到新手機 <a href="https://play.google.com/store/apps/details?id=com.htc.dnatransfer.legacy&feature=search_result#?t=W251bGwsMSwxLDEsImNvbS5odGMuZG5hdHJhbnNmZXIubGVnYWN5Il0.">HTC 傳輸工具 - Google Play Android 應用程式</a>
把舊Android手機(支援2.3以上,不一定要HTC)的設定,照片,簡訊等資訊透過無線網路傳輸到NewOne。用官方的方法沒辦法用Pin碼自動配對成功,之後是用新一內建的App:設定精靈。並讓舊手機連到一個特殊的基地台,就Ok了。</p>
</li>
<li>
<p>查詢 IMEI 手機的身份證字號: 撥打 *#06#</p>
</li>
<li>
<p>查詢出廠時間: <a href="http://219.80.249.25/IMEIQuery/IMEIQuery.aspx?ct=zh-CN">HTC Support</a>
需要輸入的<strong>IMEI</strong>跟<strong>S/N</strong>可以在包裝盒裡面的貼紙找到</p>
</li>
<li>
<p>hTC硬體功能測試(HTC function Test v4.01.04g): 撥打 <em>#</em>#3424#<em>#</em>
可以測試hTC的各項硬體功能,建議可以先全部都測過一遍,檢查一下是否正常</p>
</li>
<li>
<p><a href="https://start.htcsense.com/#pairing">HTC 輕鬆上手</a></p>
</li>
</ul>
<h2>DIY</h2>
<ul>
<li>使用包裝盒製作底座 <a href="http://www.mobile01.com/topicdetail.php?f=566&t=3312431&last=43127676">New One 送原廠底座!!! (第1頁) - HTC (Android) - Mobile01</a></li>
</ul>
<h2>特色</h2>
<ul>
<li>BlinkFeed, 即時動態 隨心選擇 <a href="http://www.youtube.com/watch?v=KgXh9lOa6Os">HTC輕鬆玩 - 新HTC One : 豬血糕篇 - YouTube</a></li>
<li>Sense TV, 互動式節目表 <a href="http://www.youtube.com/watch?v=uMBuOVSkevY">HTC輕鬆玩 - 新HTC One : 娘娘篇 - YouTube</a></li>
<li>BoomSound, 雙前置立體揚聲器 <a href="http://www.youtube.com/watch?v=X7eycEci5-c">HTC輕鬆玩 - 新HTC One : 潮貴人篇 - YouTube</a></li>
<li>Sense …</li></ul><p>第一次使用HTC的手機,整理一下 New HTC One的相關資訊。感覺這隻真的不錯,全鋁合金機身,而且又是找五月天代言,正港的MIT,一定要支持一下。</p>
<h2>剛拿到手機可以先做的事</h2>
<ul>
<li>
<p>檢查一下沒有沒縫。這隻採鋁合金外,有很漂亮的金屬質感,但是也造成上市初期的良率太低,而傳出多起<a href="http://www.mobile01.com/topicdetail.php?f=566&t=3282065">接縫</a>問題。據說五月後的貨這方面的問題少了很多</p>
</li>
<li>
<p>把舊手機的資料傳輸到新手機 <a href="https://play.google.com/store/apps/details?id=com.htc.dnatransfer.legacy&feature=search_result#?t=W251bGwsMSwxLDEsImNvbS5odGMuZG5hdHJhbnNmZXIubGVnYWN5Il0.">HTC 傳輸工具 - Google Play Android 應用程式</a>
把舊Android手機(支援2.3以上,不一定要HTC)的設定,照片,簡訊等資訊透過無線網路傳輸到NewOne。用官方的方法沒辦法用Pin碼自動配對成功,之後是用新一內建的App:設定精靈。並讓舊手機連到一個特殊的基地台,就Ok了。</p>
</li>
<li>
<p>查詢 IMEI 手機的身份證字號: 撥打 *#06#</p>
</li>
<li>
<p>查詢出廠時間: <a href="http://219.80.249.25/IMEIQuery/IMEIQuery.aspx?ct=zh-CN">HTC Support</a>
需要輸入的<strong>IMEI</strong>跟<strong>S/N</strong>可以在包裝盒裡面的貼紙找到</p>
</li>
<li>
<p>hTC硬體功能測試(HTC function Test v4.01.04g): 撥打 <em>#</em>#3424#<em>#</em>
可以測試hTC的各項硬體功能,建議可以先全部都測過一遍,檢查一下是否正常</p>
</li>
<li>
<p><a href="https://start.htcsense.com/#pairing">HTC 輕鬆上手</a></p>
</li>
</ul>
<h2>DIY</h2>
<ul>
<li>使用包裝盒製作底座 <a href="http://www.mobile01.com/topicdetail.php?f=566&t=3312431&last=43127676">New One 送原廠底座!!! (第1頁) - HTC (Android) - Mobile01</a></li>
</ul>
<h2>特色</h2>
<ul>
<li>BlinkFeed, 即時動態 隨心選擇 <a href="http://www.youtube.com/watch?v=KgXh9lOa6Os">HTC輕鬆玩 - 新HTC One : 豬血糕篇 - YouTube</a></li>
<li>Sense TV, 互動式節目表 <a href="http://www.youtube.com/watch?v=uMBuOVSkevY">HTC輕鬆玩 - 新HTC One : 娘娘篇 - YouTube</a></li>
<li>BoomSound, 雙前置立體揚聲器 <a href="http://www.youtube.com/watch?v=X7eycEci5-c">HTC輕鬆玩 - 新HTC One : 潮貴人篇 - YouTube</a></li>
<li>Sense Voice, 清晰的通話品質 <a href="http://www.youtube.com/watch?v=ArG7Wv4dcjg">HTC輕鬆玩 - 新HTC One : 老闆篇 - YouTube</a></li>
</ul>
<h2>拍照攝影</h2>
<ul>
<li><a href="http://www.youtube.com/watch?v=f4G3O2VPR0c">新HTC One 以各種速度的播放來製成影片 - YouTube</a></li>
<li><a href="http://www.youtube.com/watch?v=sH2ecU2APdo">新HTC One 拍攝最佳的團體照 - YouTube</a></li>
<li><a href="http://www.youtube.com/watch?v=Gb_UCxbtnYU">新HTC One - 透過單張相片盡現精彩時刻 - YouTube</a></li>
<li><a href="http://www.youtube.com/watch?v=F5lmuRBBEI4">新HTC One 從相片裡移除不要的路人 - YouTube</a></li>
</ul>
<h2>照片大樓</h2>
<div class="highlight"><pre><span></span><code>- [【圖多心得】HTC New One 新一 ultrapixel 隨手拍一個月心得~~~ (第1頁) - HTC (Android) - Mobile01](http://www.mobile01.com/topicdetail.php?f=566&t=3340000&last=43483506)
</code></pre></div>
<h2>評測</h2>
<ul>
<li><a href="http://www.youtube.com/watch?v=u7vsnJ4l1Ro">HTC One 抗刮測試 - YouTube</a></li>
<li><a href="http://mobile.zol.com.cn/366/3661149.html">谁是拍照之王? HTC One比拼三大热门神机_诺基亚 PureView 808_手机Android频道-中关村在线</a></li>
<li><a href="http://www.eprice.com.tw/mobile/talk/124/4862623/1/rv/htc-one-16gb-801e-%E6%96%B0-HTC-One-New-HTC-One-%E6%96%B0%E4%B8%80-M7-review/">2013 四大旗艦智慧手機集合:螢幕與相機比較 (第1頁) - Android 討論區 - ePrice比價王</a></li>
</ul>
<h2>清潔</h2>
<ul>
<li><a href="http://www.mobile01.com/topicdetail.php?f=566&t=3343264&m=s&s=20&r=4&last=43544389">new one上面白色塑料容易髒? (第1頁) - HTC (Android) - Mobile01</a></li>
</ul>
<h2>新聞</h2>
<ul>
<li><a href="http://www.youtube.com/watch?v=r4f7dnAUsEs">20130220 范育禎主播-非凡新聞錢線百分百"宏達電旗艦機王 New hTC one 介紹" - YouTube</a></li>
<li><a href="http://www.youtube.com/watch?v=WrQo-M1iCQ4">【科技這1台】20130329 宏達電NEW HTC One 首日開賣! 6千支預購一空 - YouTube</a></li>
</ul>
<h2>代言人</h2>
<ul>
<li><a href="http://www.youtube.com/watch?v=TYvHNiYRgYE">新 hTC One 上市發表會 五月天熱唱全紀錄 - YouTube</a></li>
<li><a href="http://www.youtube.com/watch?v=r3P1jGaOlbw">2013 王力宏 The new hTC one (BlinkFeed) 廣告(去發現 去改變) - YouTube</a></li>
</ul>
<h2>資料夾結構</h2>
<ul>
<li><a href="http://androidforums.com/htc-one-x-xl/533645-folder-storage-info-101-a.html">Folder/Storage info 101 - Android Forums</a></li>
</ul>sed的s指令筆記2013-04-26T11:11:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-04-26:/sed-substitute-s-command/<h2>s Command</h2>
<p><strong>s</strong>(substitue) 指令是 sed 中最常用的,可以把文件中的字串替換掉。基本的syntax <code>s/RegEx/SubEx/</code>,例如 <code>s/Old/New/</code>:</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">echo</span> <span class="s1">'this is old'</span> > input.txt
$ sed s/old/new/ input.txt
</code></pre></div>
<p>這個sed指令可以把文件中的old字串換成new</p>
<h2>sed 執行流程</h2>
<p>sed不像一般程式語言有 variable 的概念,但是sed有兩個特別的buffer(or workspace)可以讓sed執行較複雜的工作。這兩個buffer稱為<strong>Pattern space</strong>和<strong>Hold space</strong>。sed執行是從input stream中,每次執行一行,流程大致如下:</p>
<ol>
<li>sed從input stream讀一行的內容</li>
<li>把換行符號(trailing newlines)移除</li>
<li>把它放到<strong>pattern sapce</strong></li>
<li>執行指令(上面的例子就是<strong>s</strong> command把old取代成new)</li>
<li>把換行符號(trailing newlines)補回來</li>
<li>sed 把結果印到 output steam</li>
<li>如果還有input的話,就繼續執行step1,否則就結束</li>
</ol>
<p>而pattern space在每一個迴圈都會清除,但是hold space則不會,可參考‘h’, ‘H’, ‘x’, ‘g’, ‘G’指令。</p>
<h2>s 指令的其它選項</h2>
<p>-e: sed script,可以連接多個 sed script,如果只有一個 sed script 則 -e 可以省略。例如:
$ echo 1234567890 …</p><h2>s Command</h2>
<p><strong>s</strong>(substitue) 指令是 sed 中最常用的,可以把文件中的字串替換掉。基本的syntax <code>s/RegEx/SubEx/</code>,例如 <code>s/Old/New/</code>:</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">echo</span> <span class="s1">'this is old'</span> > input.txt
$ sed s/old/new/ input.txt
</code></pre></div>
<p>這個sed指令可以把文件中的old字串換成new</p>
<h2>sed 執行流程</h2>
<p>sed不像一般程式語言有 variable 的概念,但是sed有兩個特別的buffer(or workspace)可以讓sed執行較複雜的工作。這兩個buffer稱為<strong>Pattern space</strong>和<strong>Hold space</strong>。sed執行是從input stream中,每次執行一行,流程大致如下:</p>
<ol>
<li>sed從input stream讀一行的內容</li>
<li>把換行符號(trailing newlines)移除</li>
<li>把它放到<strong>pattern sapce</strong></li>
<li>執行指令(上面的例子就是<strong>s</strong> command把old取代成new)</li>
<li>把換行符號(trailing newlines)補回來</li>
<li>sed 把結果印到 output steam</li>
<li>如果還有input的話,就繼續執行step1,否則就結束</li>
</ol>
<p>而pattern space在每一個迴圈都會清除,但是hold space則不會,可參考‘h’, ‘H’, ‘x’, ‘g’, ‘G’指令。</p>
<h2>s 指令的其它選項</h2>
<p>-e: sed script,可以連接多個 sed script,如果只有一個 sed script 則 -e 可以省略。例如:
$ echo 1234567890 | sed -e 's/1/x/' -e 's/5/x/'
另外也可以用<code>;</code>來連結多個 sed script
$ echo 1234567890 | sed -e 's/1/x/;s/5/x/'</p>
<p>-f: 把結果輸出到另一個檔案</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">echo</span> <span class="s1">'s/1/x/\ns/5/x/'</span> > /tmp/my.sed
$ <span class="nb">echo</span> <span class="m">1234567890</span> <span class="p">|</span> sed -f /tmp/my.sed
</code></pre></div>
<p>-i: in place 直接在該檔操作</p>
<div class="highlight"><pre><span></span><code>$ sed -i s/Bad/Good/ input.txt
</code></pre></div>
<p>-n: 不要輸出結果到 output stream </p>
<h2>flags for s command</h2>
<p>s指令提供了一些flags可以讓執行可以有更多變化,常見的 flag有:</p>
<ul>
<li>i: ignore case </li>
<li>g: global, 同一行中的所有match都替換</li>
<li>n(數字): 只換第n個match</li>
<li>p: print the result if match,常跟 -n(silent)一起用,只顯示有更動的內容</li>
<li>w: write result to file if match,後面要指檔案名稱</li>
<li>e(Execute PatSpace to PatSpace),m(Multi-Line mode matching)少用,略過。</li>
</ul>
<h5>範例</h5>
<div class="highlight"><pre><span></span><code> $ echo old old | sed s/old/new/g
</code></pre></div>
<p>同一行的全部配對都替換掉</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">echo</span> old old <span class="p">|</span> sed s/old/new/2
</code></pre></div>
<p>只替換第2個match,如果沒有加這個flag的話,預設就會是第一個match會被換掉</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">echo</span> -e <span class="s2">"12345\nabcde"</span> <span class="p">|</span> sed -n s/a/x/p
</code></pre></div>
<p>只output有更動行的內容</p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">echo</span> <span class="s2">"this is bad"</span> <span class="p">|</span> sed <span class="s1">'s/bad/good/w out.txt'</span>
</code></pre></div>
<p>把結果輸出到 out.txt</p>
<h2>有關 Delimiter</h2>
<p>除了最常見的<code>/</code>之外,也可以使用<code>:</code>,<code>|</code>,<code>_</code>等分隔符。這在內文剛好出現分隔符的時侯,就可以派上用場。例如可以把<code>$ echo /A/ | sed 's/\/A\//\/B\//'</code>改寫成 <code>$ echo /A/ | sed 's:/A/:/B/:'</code>就顯得清楚多了。</p>
<h2>Reference:</h2>
<ul>
<li><a href="http://www.amazon.com/Definitive-Guide-sed-Reference-ebook/dp/B00BH662PI/ref=sr_1_3?ie=UTF8&qid=1366946178&sr=8-3&keywords=sed">Definitive Guide to sed: Tutorial and Reference: Daniel Goldman, Paolo Bonzini: Amazon.com: Kindle Store</a></li>
<li><a href="http://www.sealinger.com/archives/297/">了解sed的工作原理(pattern space 和 hold space) - Walk in Mindfields</a></li>
<li><a href="http://www.gnu.org/software/sed/manual/html_node/Execution-Cycle.html#Execution-Cycle">Execution Cycle - sed, a stream editor</a></li>
</ul>使用 iconv 轉換檔案編碼2013-01-01T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2013-01-01:/cmd-iconv-big5-to-utf-8.md/<p>iconv 可以轉換編碼, 例如想把 big5 檔換轉到 utf8: </p>
<div class="highlight"><pre><span></span><code>$ iconv -f big5 -t utf8 big5_input.txt -o utf8_output
</code></pre></div>自動化軟體測試的金字塔2012-11-08T07:09:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-11-08:/automation-pyramid/<p><img alt="Automation pyramid" src="https://lh4.googleusercontent.com/-NoFl4D43v24/UrcmgxdfyuI/AAAAAAAFHeU/wNzRs5ir5Dg/w441-h400-no/crispin-test-automation-pyramid.png"></p>
<h3>測試的重點</h3>
<p>軟體測試在敏捷化開發一定會遇到的問題,就是原本很可能都是以“週”為單位完成的Task。如果在一個三週Sprint的情況下,測試工作很可能都要變成以“天“為單位完成的Task,我們要如何能把大部份的測試活動都在短的時間區間完成!?如同 Scrum 大師 Mike Cohn 所說的,我們需要一個健康測試金字塔。把時間投資在<strong>對</strong>的測試活動上。</p>
<p>金字塔有三層,由下而上分別是 Unit Test ,Acceptance Test, GUI Tests。最上面不一定大小的 Manual Tests。這邊傳達的最重要的概念就是,我們應該盡可能地把時間投資在 Unit test 上,理由很簡單,因為 Unit Test 穩定度是最高的,而且最容易被執行。如果一個測試目標能在 Unit tests level 被處理掉的話,我們應該要盡量讓它們在 Unit test level 就發生。而當測試的 Scope 愈來愈大,測試的成本就會愈來愈貴,可能會由白箱測試變黑箱測試,所需要的測試文件就需要更多來傳達資訊。</p>
<p>很可惜地,大部份的測試團隊,剛好相反。投入了大量人力在 Manual tests 之上。也因為有大量的 Tester 在執行 GUI Test、Manual Test 所以 Developer 在相對少的資源下,就只能把大部份可以在 unit test level 就處理掉的任務直接讓給 tester 來完成。</p>
<h3>金字塔 與 三隻小豬的故事</h3>
<p><img alt="三隻小豬" src="https://lh5.googleusercontent.com/-PYQEcmegLJs/UrcmgJuV1tI/AAAAAAAFHeQ/aoH8iGYHDJs/w400-h274-no/20071103100325326364392.jpg"></p>
<p>Patrick Wilson-Welsh 把這個金字塔比喻成三隻小豬的故事。有做過 GUI test 的人應該都知道,我們應該最後才做 GUI test,因為他最 brittle,最容易因為一點點的改變而讓測試不通過。所以 Patrick …</p><p><img alt="Automation pyramid" src="https://lh4.googleusercontent.com/-NoFl4D43v24/UrcmgxdfyuI/AAAAAAAFHeU/wNzRs5ir5Dg/w441-h400-no/crispin-test-automation-pyramid.png"></p>
<h3>測試的重點</h3>
<p>軟體測試在敏捷化開發一定會遇到的問題,就是原本很可能都是以“週”為單位完成的Task。如果在一個三週Sprint的情況下,測試工作很可能都要變成以“天“為單位完成的Task,我們要如何能把大部份的測試活動都在短的時間區間完成!?如同 Scrum 大師 Mike Cohn 所說的,我們需要一個健康測試金字塔。把時間投資在<strong>對</strong>的測試活動上。</p>
<p>金字塔有三層,由下而上分別是 Unit Test ,Acceptance Test, GUI Tests。最上面不一定大小的 Manual Tests。這邊傳達的最重要的概念就是,我們應該盡可能地把時間投資在 Unit test 上,理由很簡單,因為 Unit Test 穩定度是最高的,而且最容易被執行。如果一個測試目標能在 Unit tests level 被處理掉的話,我們應該要盡量讓它們在 Unit test level 就發生。而當測試的 Scope 愈來愈大,測試的成本就會愈來愈貴,可能會由白箱測試變黑箱測試,所需要的測試文件就需要更多來傳達資訊。</p>
<p>很可惜地,大部份的測試團隊,剛好相反。投入了大量人力在 Manual tests 之上。也因為有大量的 Tester 在執行 GUI Test、Manual Test 所以 Developer 在相對少的資源下,就只能把大部份可以在 unit test level 就處理掉的任務直接讓給 tester 來完成。</p>
<h3>金字塔 與 三隻小豬的故事</h3>
<p><img alt="三隻小豬" src="https://lh5.googleusercontent.com/-PYQEcmegLJs/UrcmgJuV1tI/AAAAAAAFHeQ/aoH8iGYHDJs/w400-h274-no/20071103100325326364392.jpg"></p>
<p>Patrick Wilson-Welsh 把這個金字塔比喻成三隻小豬的故事。有做過 GUI test 的人應該都知道,我們應該最後才做 GUI test,因為他最 brittle,最容易因為一點點的改變而讓測試不通過。所以 Patrick 把它比喻成豬大哥的茅草屋。而 Acceptance test 則是豬二哥的木頭屋,因為在 API Lelvel,去掉最難測的GUI,理論上變化的頻率就變少了,會比較堅固。而最後就是豬小弟的 Unit test 磚頭屋。unit test 我們的測試目標scope是最小的,去除最多的 dependency ,讓不穩定的因子降到最低,這個故事也暗示了一點,磚頭屋是最難蓋的,需要最多的人手來幫忙完成。就跟三隻小豬的故事一樣,我們要像豬小弟一樣,長期的耕耘建設,才不會大野狼(Change)一吹,就倒光光。</p>
<!--![Testing-Quadrants](https://lh3.googleusercontent.com/-8iOOVm9cHII/UpQY3XHUo4I/AAAAAAAFGbs/dAj3_SP6K5A/w755-h566-no/test-agile.jpg)
-->Pretotype - 把事情做對之前, 確保做了對的事2012-10-07T19:57:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-10-07:/pretotype/<p>看了GTAC 2011 <a href="http://www.youtube.com/watch?v=X1jWe5rOu3g">Opening Keynote: Test is dead</a>時注意到這本書。查了一下,發現<a href="http://www.amazon.com/Pretotype-It-ebook/dp/B007JLHL78/ref=sr_1_1?ie=UTF8&qid=1349618362&sr=8-1&keywords=pretotype">Amazon的高評價</a>,就馬上買了Kindle版(0.99 Usd)來看。裡面有一些不錯的觀念,在現今軟體業 Startup 風氣盛行的年代,我想值得記錄一下。</p>
<h1>什麼是 Pretotype</h1>
<p>Pretotype 不是 Prototype 的筆誤。這個字是作者 Alberto Savoia 自創的單字。從 Prototype 衍生而來。pre 跟 pro 都有 earier, before 的意思。一般傳統上,我們常常為了證明一些點子是否可行,都會先用少量的成本投入,來測試看看是否值得再繼續投入下去,比如說原型(Prototype),或是POC(Prove of Concept)都是典型的例子。但是Alberto覺得Prototype還是太貴了。能否有一些更快速,省成本的方法來驗證我們做的是對的<em>它</em>。因為找對的<em>它</em>來做是非常重要的,一些常見的統計數據告訴我們:</p>
<ul>
<li>90% 的 Mobile App 不賺錢</li>
<li>80% 的 Startup 把投資者的錢賠了</li>
<li>80% 的 餐廳在一年內就關門大吉</li>
</ul>
<p>所以,愈早知道是否是對的“它”,遠比把“它”做對來得重要的多。</p>
<h3>失敗定律</h3>
<blockquote>
<p>絕大多數的新物事都將會失敗, 即使被完美無瑕地執行</p>
</blockquote>
<p>所以,我們常常在做一些不對的事情而不自知。當然,這邊所謂的對或是不對,其實定義可以很簡單,就是指目標市場的接受度。但是如果市場不買帳,就算他做的很完美,終究會走向失敗之路。Pretotype 是一種讓我們可以少痛一點的方式,即早發見這其實是不對的。而不是花了大把銀子跟青春才發現這不是市場要的。Pretotype 是指一種介於抽象概念(Abstract concept)跟原型(Prototype …</p><p>看了GTAC 2011 <a href="http://www.youtube.com/watch?v=X1jWe5rOu3g">Opening Keynote: Test is dead</a>時注意到這本書。查了一下,發現<a href="http://www.amazon.com/Pretotype-It-ebook/dp/B007JLHL78/ref=sr_1_1?ie=UTF8&qid=1349618362&sr=8-1&keywords=pretotype">Amazon的高評價</a>,就馬上買了Kindle版(0.99 Usd)來看。裡面有一些不錯的觀念,在現今軟體業 Startup 風氣盛行的年代,我想值得記錄一下。</p>
<h1>什麼是 Pretotype</h1>
<p>Pretotype 不是 Prototype 的筆誤。這個字是作者 Alberto Savoia 自創的單字。從 Prototype 衍生而來。pre 跟 pro 都有 earier, before 的意思。一般傳統上,我們常常為了證明一些點子是否可行,都會先用少量的成本投入,來測試看看是否值得再繼續投入下去,比如說原型(Prototype),或是POC(Prove of Concept)都是典型的例子。但是Alberto覺得Prototype還是太貴了。能否有一些更快速,省成本的方法來驗證我們做的是對的<em>它</em>。因為找對的<em>它</em>來做是非常重要的,一些常見的統計數據告訴我們:</p>
<ul>
<li>90% 的 Mobile App 不賺錢</li>
<li>80% 的 Startup 把投資者的錢賠了</li>
<li>80% 的 餐廳在一年內就關門大吉</li>
</ul>
<p>所以,愈早知道是否是對的“它”,遠比把“它”做對來得重要的多。</p>
<h3>失敗定律</h3>
<blockquote>
<p>絕大多數的新物事都將會失敗, 即使被完美無瑕地執行</p>
</blockquote>
<p>所以,我們常常在做一些不對的事情而不自知。當然,這邊所謂的對或是不對,其實定義可以很簡單,就是指目標市場的接受度。但是如果市場不買帳,就算他做的很完美,終究會走向失敗之路。Pretotype 是一種讓我們可以少痛一點的方式,即早發見這其實是不對的。而不是花了大把銀子跟青春才發現這不是市場要的。Pretotype 是指一種介於抽象概念(Abstract concept)跟原型(Prototype)之間的一種新名詞。如果Protoduct是要花幾個星期, 幾個月完成的事情。那麼 Pretotype就是一種手段,能在幾天甚至幾個小時就可以完成一個 Pretotype 讓市場可以回饋。讓我們可以知道,這到底是不是市場要的。</p>
<h1>Pretotype 的經典例子 - IBM 語音辨識 實驗</h1>
<p>在幾十年前, 鍵盤打字只有少數人會,大部份是一些秘書,作家跟程式設計師。其它大部份的人都是用一指神功, 很慢而且沒有效率。所以 IBM 就想開發出一種 speech-to-text (語音辨識)的機器。 讓使用者可以直接講話,然後文字就會神奇地出現在螢幕上面。 這顯然是一筆可能會賺大錢的生意, 但是這是一個困難的問題,IBM勢必要投入多年的研究和花費大量的經費才可能成功。雖然任何人應該都會想要這個功能,但是 IBM 值得賭一把嗎?</p>
<p>於是 IBM 就設計了一個實驗,找了一群自認一定會買的人。讓他們在一個房間,每個人有一台電腦, 螢幕或一個麥克風,但是沒有鍵盤。 IBM 告訴他們,他們己經做好了一個可以語音辨識的機器。只要對著麥克風說話,螢幕就會自動出現文字。但是實際上,跟本沒有這個系統,甚至不是一個 Prototype,其實電腦連接到的是隔壁一群訓練有素的打字員,他們會把聽到的內容直接打在螢幕上。讓測試者以為真的有這個系統。</p>
<p>最後 IBM 學到了什麼?那些說一定會買的人,馬上在幾個小時之後改變了心意。因為:</p>
<ol>
<li>在一整天的講話之後,人們覺得喉嚨很痛。</li>
<li>整個房間很吵雜,不是他們想辦公的環境</li>
</ol>
<p>所以,IBM做出了決定,語音辨識在商業辦公室用途顯然不是一個好點子。所以幾十年後的今天,在辦公室,我們大部份的人仍然使用鍵盤做為主要的輸入方式。</p>
<h1>Pretotype 的例子 - Palm Pilot</h1>
<p><img alt="palm-pilot" src="http://i.imgur.com/o9dJTXh.png"></p>
<p>Pilot 是第一代成功的 PDA (Personal Digital Assistant) 但是他的創造者 Jeff Hawkins 並沒有把這個成功視為理所當然,他一開始設計了一款商用的平板電腦GRiDPad,但是不算成功。他覺得還是太大了,為了不要犯第二次錯誤。他決定試試看可以放進口袋的尺寸。於是他從車庫鋸了木頭,做了一款木制的Palm。之後的幾個月,他都假裝那是一台電腦。 在上面查詢行事曆,電話簿。人們大概都會都覺得他瘋了。最後他回答了他自己的問題:如果我有一台Palm Pilot,我會帶著他並且使用嗎?" 他自己的答案是肯定的 YES ! 於是他才開始研究我們是否可以做得那麼小,或是成本是否值得建造。之後才值得做一個適當的 Prototype。</p>
<blockquote>
<p>Fake It Before You Make it </p>
</blockquote>
<p>Fake 的目的是為了用最小成本,得到最關鍵的使用者回饋。</p>
<h1>Pretotype 的方法</h1>
<ol>
<li>The Mechanical Turk</li>
</ol>
<p><img alt="img" src="http://blogs.scientificamerican.com/guilty-planet/files/2011/07/mechanicalturk.jpg"></p>
<p>使用人代替機器,IBM 語音辨識就是此類型的。實際開發如果會花費太多時間。那不如就直接用聰明的人類先代替最關鍵的部份</p>
<ol>
<li>The Pinocchio</li>
</ol>
<p><img alt="Pinocchio" src="http://i.imgur.com/mllSjNA.jpg"></p>
<p>Pinocchio 就是童話故事小木偶奇偶記的主角,而這種 Pretotype 最適合那些需要考量尺寸,形狀,重量,可攜帶性等等。像是 Palm Pilot。</p>
<ol>
<li>The Minimum Viable Product </li>
</ol>
<p>Minimum viable product (MVP) 是 Eric Ries 所提倡的一種驗證想法的一種方式。只做出最關鍵的功能,非關鍵的功能都捨棄。</p>
<ol>
<li>The Provincial </li>
</ol>
<p>先關注在一小群的使用者上,例如餐聽的APP。那麼就先做單一區域的客群。那麼 Provincial 的 Pretotype 就可能是用人力直接建立。</p>
<ol>
<li>The Fake Door</li>
</ol>
<p>製造一個假的入口,用來測試有多少人對這個有興趣,就像一個釣鉺一樣。例如買個 AdSense,放上宣傳標語,看看有多少人會點擊進來。Fake door 可以使用 <a href="http://www.weebly.com/">webbly</a></p>
<h1>評量</h1>
<h3>Initial Level of Interest (ILI)</h3>
<blockquote>
<p>ILI = 實際動作次數 / 可能動作次數</p>
</blockquote>
<h3>Ongoing Level of Interest (OLI)</h3>
<blockquote>
<p>OLI = 隨著時間的演進,還持續有動作的比例</p>
</blockquote>
<p>其實要評量一個主意是不是“對”的,其實不容易。Alberto提出了兩個公式,<code>ILI</code>跟<code>OLI</code>。<code>ILT</code>目的是測量出有興趣的比例。例如1000個人看了廣告,其中有2個人有興趣點擊廣告,那麼 ILI就是 2/1000 = 0.2%。而另一個 OLI 則是另一個指標來測量這個主意是否能夠長久下去。例如 Active User 平均活動情況等等。</p>
<h1>最後</h1>
<p>在軟體測試裡面有個名詞叫 <code>V&V (Verification and validation)</code>,Verification 就是指是否有把事情做對。而Validation是指是否在做對的事。 而Pretotype其實就是在做 Validation。但是 Pretotype 把 Validation 的重要性顯現出來。並且提供一些方法跟指標。 這本書在網路上都有免費的版本可以下載,而Kindle版目前只有 $2.99。裡面還有提到不少的有趣的實例。是本不錯的小書。</p>
<h1>參考資料</h1>
<ul>
<li>
<p><a href="http://jonathanspeaking.blogspot.tw/2013/06/using-pretotyping-in-project-intiation.html?utm_source=feedly&utm_medium=feed&utm_campaign=Feed:+jonathanspeaking+(Jonathan+Speaking+Software)">專案開始前,Pretotyping 先!</a></p>
</li>
<li>
<p><a href="http://www.pretotyping.org/uploads/1/4/0/9/14099067/pretotype_it_2nd_pretotype_edition-2.pdf">Pretotype free PDF</a></p>
</li>
</ul>Install Jenkins on CentOS 6.32012-09-02T20:41:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-09-02:/install-jenkins-on-centos-6/<h3>安裝 JDK</h3>
<p>CentOS預設的JAVA版本和Jenkins不相容,所以要改安裝 OpenJDK 。可以用 yum search 檢查應該安裝那一個版本:
yum search openjdk
會有 java-1.6.0 跟 java-1.7.0 兩個版本可供安裝,在此我選擇比較新的版本:1.7.0:
yum install java-1.7.0-openjdk -y</p>
<h3>安裝 Jenkins</h3>
<div class="highlight"><pre><span></span><code><span class="n">sudo</span> <span class="n">wget</span> <span class="o">-</span><span class="n">O</span> <span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">yum</span><span class="o">.</span><span class="n">repos</span><span class="o">.</span><span class="n">d</span><span class="o">/</span><span class="n">jenkins</span><span class="o">.</span><span class="n">repo</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">pkg</span><span class="o">.</span><span class="n">jenkins</span><span class="o">-</span><span class="n">ci</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">redhat</span><span class="o">/</span><span class="n">jenkins</span><span class="o">.</span><span class="n">repo</span>
<span class="n">sudo</span> <span class="n">rpm</span> <span class="o">--</span><span class="kn">import</span> <span class="nn">http</span><span class="p">:</span><span class="o">//</span><span class="n">pkg</span><span class="o">.</span><span class="n">jenkins</span><span class="o">-</span><span class="n">ci</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">redhat</span><span class="o">/</span><span class="n">jenkins</span><span class="o">-</span><span class="n">ci</span><span class="o">.</span><span class="n">org</span><span class="o">.</span><span class="n">key</span>
<span class="n">sudo</span> <span class="n">yum</span> <span class="n">install</span> <span class="n">jenkins</span> <span class="o">-</span><span class="n">y</span>
</code></pre></div>
<h3>設定 Jenkins</h3>
<ol>
<li>
<p>修改 iptables : 打開 80 Port,編輯<code>/etc/sysconfig/iptables</code>,把下面的rule加到最後一條
iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT</p>
</li>
<li>
<p>讓 Jenkins 開機自動啟動
chkconfig Jenkins …</p></li></ol><h3>安裝 JDK</h3>
<p>CentOS預設的JAVA版本和Jenkins不相容,所以要改安裝 OpenJDK 。可以用 yum search 檢查應該安裝那一個版本:
yum search openjdk
會有 java-1.6.0 跟 java-1.7.0 兩個版本可供安裝,在此我選擇比較新的版本:1.7.0:
yum install java-1.7.0-openjdk -y</p>
<h3>安裝 Jenkins</h3>
<div class="highlight"><pre><span></span><code><span class="n">sudo</span> <span class="n">wget</span> <span class="o">-</span><span class="n">O</span> <span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">yum</span><span class="o">.</span><span class="n">repos</span><span class="o">.</span><span class="n">d</span><span class="o">/</span><span class="n">jenkins</span><span class="o">.</span><span class="n">repo</span> <span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">pkg</span><span class="o">.</span><span class="n">jenkins</span><span class="o">-</span><span class="n">ci</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">redhat</span><span class="o">/</span><span class="n">jenkins</span><span class="o">.</span><span class="n">repo</span>
<span class="n">sudo</span> <span class="n">rpm</span> <span class="o">--</span><span class="kn">import</span> <span class="nn">http</span><span class="p">:</span><span class="o">//</span><span class="n">pkg</span><span class="o">.</span><span class="n">jenkins</span><span class="o">-</span><span class="n">ci</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">redhat</span><span class="o">/</span><span class="n">jenkins</span><span class="o">-</span><span class="n">ci</span><span class="o">.</span><span class="n">org</span><span class="o">.</span><span class="n">key</span>
<span class="n">sudo</span> <span class="n">yum</span> <span class="n">install</span> <span class="n">jenkins</span> <span class="o">-</span><span class="n">y</span>
</code></pre></div>
<h3>設定 Jenkins</h3>
<ol>
<li>
<p>修改 iptables : 打開 80 Port,編輯<code>/etc/sysconfig/iptables</code>,把下面的rule加到最後一條
iptables -I INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT</p>
</li>
<li>
<p>讓 Jenkins 開機自動啟動
chkconfig Jenkins On</p>
</li>
<li>
<p>編輯 Jenkins URL 的 prefix,這邊是設定使用 <code>http://{your_ip}/jenkins</code> 的方式來存取Jenkins網站,編輯<code>/etc/sysconfig/jenkins</code>加上<code>JENKINS_ARGS="--prefix=/jenkins"</code></p>
</li>
</ol>
<h3>設定Apache</h3>
<p>在這邊我用的方法是使用Apache,並當成<code>Reverse Proxy</code>,把 <code>{IP}/jenknis/</code> 以下的連線轉到 Jenkins Server 預設 Default Port 8080。</p>
<h3>安裝 Apache</h3>
<div class="highlight"><pre><span></span><code>yum install httpd
</code></pre></div>
<h3>設定 <code>/etc/httpd/conf/httpd.conf</code></h3>
<div class="highlight"><pre><span></span><code>ProxyPass /jenkins http://localhost:8080/jenkins
ProxyPassReverse /jenkins http://localhost:8080/jenkins
ProxyRequests Off
<span class="nt"><Proxy</span> <span class="err">http://localhost:8080/jenkins*</span><span class="nt">></span>
Order deny,allow
Allow from all
<span class="nt"></Proxy></span>
</code></pre></div>
<h3>設定 SE-Linux</h3>
<p>開放 apache 的權限
sudo setsebool -P httpd_can_network_connect true</p>
<h3>啟動 Jenkins</h3>
<div class="highlight"><pre><span></span><code>service httpd restart
service jenkins start
</code></pre></div>
<p>這樣最基本的安裝就差不多完成了,打開 Browser 輸入:http://yourip/jenkins
如果一切順利的話,就可以看到 Jenkins老管家的首頁囉:</p>
<p><img alt="img" src="center https://lh6.googleusercontent.com/-Dzoxdn4vUQM/UENiYUHxBII/AAAAAAADdGI/8m52XXZI_z0/s512/Screenshot%2520from%25202012-09-02%252021%253A42%253A18.png"></p>
<h3>Jenkins的重要檔案:</h3>
<ol>
<li>Log 檔的位置:/var/log/jenkins/jenkins.log</li>
<li>設定檔的位置:/etc/sysconfig/jenkins</li>
</ol>Testopia 測試案例管理系統簡介2012-09-02T18:34:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-09-02:/testopia/<h2>Why Testopia ?</h2>
<p>最近想研究一些時下流行的測試案例(Test Case)管理系統,之前有稍微裝一下<a href="http://testlink.sourceforge.net/docs/testLink.php">Test Link</a>來玩看看。因為看到《How Google Tests Software》裡面有提到一點,就是在Gogole裡,如果自動化測試測試沒過的話,會直接自動新增一筆Bug Tacker給相關人員,可見其相當重視自動化測試的品質,讓Automation的Bug提升到跟Product Bug相等重要。這也讓我重新思考 Bug Tracking System 對於Automation們的重要性。所以這讓我注意到另一套 Test Case Management System: Testopia。我覺得Testopia最大的特色,就是他是一套Bug Tracking System: Bugzilla 的延伸套件。也就是如果我們採用了Testopia來當我們的測試案例管理系統的話。也就相當於能直接擁有一套 Bug Tracking System了。這成為我想玩玩看 Testopia 的最大理由 :)</p>
<h2>安裝 Testopia:</h2>
<p>要玩 Testopia 之前要先安裝 Bugzilla,關於 Bugzilla 的安裝,這邊有<a href="/install-bugzilla-centos-6-3-step-step">記錄</a>,安裝 Testopia 其實很簡單,下載 Testopia 的 tarball file : 當下最新的版本是<a href="ftp://ftp.mozilla.org/pub/mozilla.org/webtools/testopia/testopia-2.5-BUGZILLA-4.2.tar.gz">2.5版</a></p>
<ol>
<li>
<p>解壓縮︰ tar zxvf testopia-2.5-BUGZILLA-4.2.tar.gz</p>
</li>
<li>
<p>把裡面的內容丟到 bugzilla 的根目錄,例如 /var/www/html/bugzilla</p>
</li>
<li>
<p>執行 checksetup 的 perl 檔 : ./checksetup.pl</p>
</li>
</ol>
<p>這樣就安裝完成了。</p>
<h2>Testopia 的架構</h2>
<p>Testopia 手冊裡面有一張圖很清楚地表達整個 Testopia 的架構 …</p><h2>Why Testopia ?</h2>
<p>最近想研究一些時下流行的測試案例(Test Case)管理系統,之前有稍微裝一下<a href="http://testlink.sourceforge.net/docs/testLink.php">Test Link</a>來玩看看。因為看到《How Google Tests Software》裡面有提到一點,就是在Gogole裡,如果自動化測試測試沒過的話,會直接自動新增一筆Bug Tacker給相關人員,可見其相當重視自動化測試的品質,讓Automation的Bug提升到跟Product Bug相等重要。這也讓我重新思考 Bug Tracking System 對於Automation們的重要性。所以這讓我注意到另一套 Test Case Management System: Testopia。我覺得Testopia最大的特色,就是他是一套Bug Tracking System: Bugzilla 的延伸套件。也就是如果我們採用了Testopia來當我們的測試案例管理系統的話。也就相當於能直接擁有一套 Bug Tracking System了。這成為我想玩玩看 Testopia 的最大理由 :)</p>
<h2>安裝 Testopia:</h2>
<p>要玩 Testopia 之前要先安裝 Bugzilla,關於 Bugzilla 的安裝,這邊有<a href="/install-bugzilla-centos-6-3-step-step">記錄</a>,安裝 Testopia 其實很簡單,下載 Testopia 的 tarball file : 當下最新的版本是<a href="ftp://ftp.mozilla.org/pub/mozilla.org/webtools/testopia/testopia-2.5-BUGZILLA-4.2.tar.gz">2.5版</a></p>
<ol>
<li>
<p>解壓縮︰ tar zxvf testopia-2.5-BUGZILLA-4.2.tar.gz</p>
</li>
<li>
<p>把裡面的內容丟到 bugzilla 的根目錄,例如 /var/www/html/bugzilla</p>
</li>
<li>
<p>執行 checksetup 的 perl 檔 : ./checksetup.pl</p>
</li>
</ol>
<p>這樣就安裝完成了。</p>
<h2>Testopia 的架構</h2>
<p>Testopia 手冊裡面有一張圖很清楚地表達整個 Testopia 的架構︰</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/3Knl0kkgkxTwFpFlBbhzJ9SGzv1TTCwVTw5NphYpcciO=w691-h566-no"></p>
<p>基本的使用流程如下︰</p>
<ul>
<li>新增一個 Product 以及多個 Components : Administration > Product </li>
<li>新增一個 Test Plan </li>
<li>新增多個 Test Cases : 要注意的是狀態要 CONFIRMED 之後才能被挑選來執行。</li>
<li>新增一個 Build : ex 1001 </li>
<li>新增一個 Environemnt : 這邊的 Environemnt,通常是指一些像是OS,Browser,Hardware等等不同的執行環境。</li>
<li>新增一個 Test Run : 選擇要執行的 Test Plan,以及選擇要跑的Build,挑選 Test Case</li>
<li>執行 Test Run : 把相</li>
<li>產成 Report,在 Test Run 上按右鍵,就可以把相關的的報告展現在 <strong>Dashboard</strong>上面</li>
</ul>
<h2>編輯 Test Case</h2>
<p>一個 Test Case Management System 最重要的就是要很方便新增修改 Test Case,目前我只有少量輸入過,不過感覺還算及格,我曾經有使用過一套Test Case System,是每新增一個 Test Step 就要換頁一次。用起來就頗不方便。另外,官方建議在 Firefox 使用,編輯的介面如下︰</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/-iBM1rcMqs5U/UENQ3FfjLCI/AAAAAAADdF4/4VjuXhcLcNg/s800/Selection_019.png"></p>
<h2>跟 Jenkins 整合 執行自動化測試</h2>
<p>目前 Jenkins 有一個 Testopia 的 Plugin: <a href="https://wiki.jenkins-ci.org/display/JENKINS/Testopia+Plugin">https://wiki.jenkins-ci.org/display/JENKINS/Testopia+Plugin</a>。這個Plugin在設定好之後,在Build Step 只需要指定 RunID,如圖</p>
<p><img alt="img" src="https://lh4.googleusercontent.com/-_HlxQtYhtuI/UrcobWnKd6I/AAAAAAAFHhM/FPQo4Es5Trc/w995-h487-no/Selection_027.png"></p>
<p>目前 1.0 版僅支援三個Environment Variable <code>TESTOPIA_TESTCASE_ID</code> <code>TESTOPIA_TESTCASE_SCRIPT</code> <code>TESTOPIA_TESTCASE_ALIAS</code>。</p>
<p>有了Script名稱,接下來就可依照不同的測試框架,實際執行測試了,這邊只單純echo 出 ID 跟 Script 名稱。至於 Test Report,目前僅支援 TAP 格式。而測試案例跟測結結果的配對是使用<code>TESTOPIA_TESTCASE_ALIAS</code>。舉例,測試通過的TAP︰</p>
<div class="highlight"><pre><span></span><code><span class="mf">1..1</span>
<span class="n">ok</span> <span class="mf">1</span> <span class="n">It</span> <span class="n">is</span> <span class="n">passed</span>
</code></pre></div>
<p>而測試失敗的TAP:</p>
<div class="highlight"><pre><span></span><code><span class="mf">1..1</span>
<span class="ow">not</span> <span class="n">ok</span> <span class="mf">1</span> <span class="n">It</span> <span class="n">is</span> <span class="n">failed</span> <span class="p">,</span> <span class="n">oh</span> <span class="n">no</span> <span class="err">~</span>
</code></pre></div>
<p>例如 Testcase A 的 <code>TESTOPIA_TESTCASE_ALIAS</code> 是 <code>1</code>,那麼我們就可以準備一個1.tap,放在這個 Jenkins Job 的跟目錄裡面,這樣 Jenkins 就可以把測試結果直接回傳回Testopia。</p>
<p>這個是 Jenkins 的結果︰
<img alt="img" src="https://lh5.googleusercontent.com/6GQQT_Lk2xFtDNnXQdGHBrkuZ1Zi01rlVJJab4wXo7Te=w743-h437-no"></p>
<p>這個則是 Testopia 的結果︰</p>
<p><img alt="img" src="https://lh5.googleusercontent.com/-BhbaLhfbauM/UrcobsAkWjI/AAAAAAAFHhU/zzMPP7iZF0U/w785-h233-no/Selection_029.png"></p>
<p>這樣就可以完成透過 Jenkins 來執行 Testpoia 的自動化測試了。</p>
<p>PS : 測試案例必需是有勾選自動化,還必須要有Tester,這才會被Jenkins找到。</p>
<h2>接下來?</h2>
<p>但是要達到更高程度的自動化,其實還少了幾個部份︰</p>
<ol>
<li>
<p>Jenkins 如果看到有新 Build,自動新增 Testopia 的 Build </p>
</li>
<li>
<p>自動複製/新增 Test Run for new build</p>
</li>
<li>
<p>Jenkins 要知道新的 Test Run ID 是多少</p>
</li>
<li>
<p>傳送 Failed test result log 到 Testopia or Bugzilla</p>
</li>
<li>
<p>如果 Automation Fail,自動 Submit 一個 Bug 到 Bugzilla</p>
</li>
</ol>
<p>如果要達到以上幾點,光靠 Jenkins 的 Plug-in 就不夠了。目前有看到 PyZilla 有 Wrap Bugzilla 的 XML-RPC API。而 Testpoia 也有自己的 XMLRPC 可用,看了一下,基本上可以完成大部份任務所需。</p>
<p>所以,還有很多事情可以弄 :)</p>使用 Attributes-Components-Capabilities(ACC) 來制定敏捷測試計劃2012-08-28T15:12:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-08-28:/attributes-components-capabilities-acc/<p>這套方法是記錄在<a href="http://www.amazon.com/Google-Tests-Software-James-Whittaker/dp/0321803027">《How Google Tests Software》</a> 一書之中,我覺得蠻不錯的,分享一下︰</p>
<p>Attributes-Components-Capabilities(ACC) 是Google團隊使用的測試建模的方法,可以視為快速譔寫 Test Plan 的一種方式。據 Jame Whittaker 的講法,一份ACC的完成時間約為 10~30 分鐘,如果達不到,代表自己對於要測的系統不夠了解。</p>
<p>目前 Google 己經把這個方法實現在 Google Test Analytics (GTA) 這套系統之上,更棒的是 GTA 目前己經 Open Source 出來了,而且有一個公開的<a href="https://test-analytics.appspot.com/">沙箱網站</a>,任何人都可以上去快速體驗一下ACC的魅力。</p>
<h2>ACC 內容</h2>
<p>ACC主要的內容就是依照產品的 <code>Attribute</code>(特性), <code>Component</code>(元件), <code>Capability</code> (能力) 的三者,分別依照順序,一步一步來分析我們到底要測什麼,該測什麼,什麼要先測等等問題。下面分別介紹ACC三者的意義︰</p>
<ol>
<li>
<p>Attributes: 產品的特色,是產品的<strong>形容詞</strong>。例如︰快,安全,穩定,好用。這個清單說明為什麼顧客要用我們的產品,而不是其它的競爭者的。</p>
</li>
<li>
<p>Components: 產品的元件,是產品的<strong>名詞</strong>。例如︰資料庫,通知系統,使用者..等等。這個清單列舉出整個系統中的元件,約10個左右為宜。</p>
</li>
<li>
<p>Capability: 產品的功能,是產品的<strong>動詞</strong>。例如︰分享照片給朋友,新增好友,收到朋友訊息通知。</p>
</li>
</ol>
<p>關於 Attribute 跟 Componet,這邊書中是舉Google+為例︰</p>
<h3>Attribute :</h3>
<ul>
<li>Social: Empowers users to share information …</li></ul><p>這套方法是記錄在<a href="http://www.amazon.com/Google-Tests-Software-James-Whittaker/dp/0321803027">《How Google Tests Software》</a> 一書之中,我覺得蠻不錯的,分享一下︰</p>
<p>Attributes-Components-Capabilities(ACC) 是Google團隊使用的測試建模的方法,可以視為快速譔寫 Test Plan 的一種方式。據 Jame Whittaker 的講法,一份ACC的完成時間約為 10~30 分鐘,如果達不到,代表自己對於要測的系統不夠了解。</p>
<p>目前 Google 己經把這個方法實現在 Google Test Analytics (GTA) 這套系統之上,更棒的是 GTA 目前己經 Open Source 出來了,而且有一個公開的<a href="https://test-analytics.appspot.com/">沙箱網站</a>,任何人都可以上去快速體驗一下ACC的魅力。</p>
<h2>ACC 內容</h2>
<p>ACC主要的內容就是依照產品的 <code>Attribute</code>(特性), <code>Component</code>(元件), <code>Capability</code> (能力) 的三者,分別依照順序,一步一步來分析我們到底要測什麼,該測什麼,什麼要先測等等問題。下面分別介紹ACC三者的意義︰</p>
<ol>
<li>
<p>Attributes: 產品的特色,是產品的<strong>形容詞</strong>。例如︰快,安全,穩定,好用。這個清單說明為什麼顧客要用我們的產品,而不是其它的競爭者的。</p>
</li>
<li>
<p>Components: 產品的元件,是產品的<strong>名詞</strong>。例如︰資料庫,通知系統,使用者..等等。這個清單列舉出整個系統中的元件,約10個左右為宜。</p>
</li>
<li>
<p>Capability: 產品的功能,是產品的<strong>動詞</strong>。例如︰分享照片給朋友,新增好友,收到朋友訊息通知。</p>
</li>
</ol>
<p>關於 Attribute 跟 Componet,這邊書中是舉Google+為例︰</p>
<h3>Attribute :</h3>
<ul>
<li>Social: Empowers users to share information and what they’re up to.</li>
<li>Expressive: User can express themselves through the features</li>
<li>Easy: Intuitive. Easy to figure out how to do what you want to do</li>
<li>Relevant: Show only information the user care about</li>
<li>Extensible: Capable of integrating with Google properties and third-party site and application </li>
<li>Private: User’s data won’t be shared.</li>
</ul>
<h3>Components :</h3>
<ul>
<li>Profile: Information and preferences for the logged in user</li>
<li>People: Profiles that the user has connected with.</li>
<li>Stream: A ranked stream of posts, comments, notifications, photos, and so on.</li>
<li>Circles: Groups to put contacts into “friends”,”coworkers”, and so on.</li>
<li>Notifications: Indicators for when you are mentioned in a post </li>
<li>Interest or +1: Indication for user likes</li>
<li>Posts: Buzz posts from the users and their contacts</li>
<li>Comments: Comments on posts, photos, videos, and so on</li>
<li>Photo: Photos uploaded by the users and their contacts</li>
</ul>
<p>當有了Attributes跟Components之後,接下來就是列出目前系統所所擁的功能。而這邊強調的是,每一個功能背後一定要找了一個而且是唯一一個的Attribute,來代表這個功能所要達到的目的。</p>
<h3>Capabilities:</h3>
<p>每一個Capability,說明了一個Compoent產生的動作如何達成一個Attribute,也就是Capability是讓Component跟Attribute產生連結。 所以ACC方法的流程就是我們先想 Attribute,然後再找 Components,最後再依照現有的 Capability 功能來找出對應的 Attribute 跟 Components 分別是什麼。</p>
<p>在 Google 的ACC中,我們可以產生一個二維的表格。來展現Capability,以Google+為例,在此簡化表格,內容是依照目前Google+的功能列舉出來的︰</p>
<p>| Social | Easy | Private
----------|---------|-------|-------|
Profile|分享給朋友自己的個資| 很容易更新自己的個資| 用户可以保密隱私個資
People|使用者可以連結其它使用者 | 容易管理好友 | 用戶可以保密交友圈資料
Photos|1.使用者可以分享照片給其它使用者2.照片可以加上其它使用者的資訊 | 1. 容易上傳照片 2. 容易從別的來源匯入照片 | 照片只給有權限的人公布</p>
<p>橫軸是 Attribute,緃軸是 Compoent,而格子裡面就是 Capability </p>
<p>基本上這個表格產生出來之後,基本上就完成了大部份的內容。接下來可以直接針對每一個Capability使用不同的測試案例設計方法來產生測試案例。另外也可以拿來做 Risk Analysis。</p>
<h2>Risk analysis</h2>
<p>在GTA中,Risk 由兩個因素組成︰Frequency of Failure 跟 Impact 兩者組成。每個 Capability 都可以自己設定該項目的掛掉機率跟掛掉影響。最後就可以產生一個 Risk Heat Map,這邊是我自己在網站上練習的結果,這可以讓我們知道那些Capability是最重要的,可以先開始測試。</p>
<h2>ACC使用要點</h2>
<ul>
<li>要隨時更新,反應最新的現況</li>
<li>要精準表達使用者到底想要什麼</li>
<li>讓測試的重點(風險) 可以借由 Heat map來展現</li>
</ul>
<p>ACC可以視為一種Agile style的Test Plan設計方案,制定速度快,可做風險分析,是測試案例設計的一個好的起點。有現成OpenSource的系統︰GTA,可直接放到Google App Engine上使用。</p>
<h3>延伸閱讀 :</h3>
<ul>
<li><a href="http://googletesting.blogspot.tw/2011/09/10-minute-test-plan.html">The 10 Minute Test Planby James Whittaker</a></li>
<li><a href="http://www.cnblogs.com/liangshi/archive/2012/04/23/2465897.html">测试建模:Google ACC - liangshi - 博客园</a></li>
</ul>How Google Tests Software ?2012-08-22T22:14:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-08-22:/how-google-test/<p>這本書的作者是在軟體測試界很有名的 James Whittaker,以 How to break xxx 系列跟 Exploratory Testing 聞名。這本是他在Google期間完成的著作。可惜他己經在2012年3月左右離開了Google,發表了一篇<a href="http://blogs.msdn.com/b/jw_on_tech/archive/2012/03/13/why-i-left-google.aspx">Why I left google</a>/<a href="http://www.csdn.net/article/2012-03-14/313106">中文翻譯</a>。從微軟到Google,最後又回鍋到微軟了。文中大體的原因就是Google把創新精神丟掉,而只專注在廣告上,不再是一家是以技術優先導向的公司。但是這些還是毫不影響Google在軟體界的王者地位。</p>
<p>Google跟微軟在軟體測試上的策略很不一樣。傳統上,微軟的開發與測試人員比例大概是1:1左右。小弟的公司也是如此。但是Google專職在測試的人員,就明顯少得很多。我想從本書找到,如果專職測試人員少的話,那麼整個軟體開發流程會變的如何?其實,微軟在2008年也有出一本拿自己公司名稱當招牌的測試書 <a href="http://www.amazon.com/How-We-Test-Software-Microsoft/dp/0735624259">How We Test Software at Microsoft</a>,這本有點厚,之後找個機會來看。以目前軟體公司的發展看來,也許之後就會看到一本以 Facebook 為主角的測試書了。</p>
<h3>Ch1. Introduction to Google Software Testing</h3>
<ul>
<li>
<p>在 Google,測試工作是由一個中央的組職稱為 Engineering Productivity 來負責。包含 Developer 跟 Tester tool chain, Release engineer 。從 Unit test 包到 Exploratory testing。</p>
</li>
<li>
<p>Google 在2001年時,約有200位開發工程師,但是只有<em>3</em>位測試工程師,那時開發工程師就必需為自己寫的程試的品質負責。那時TDD跟JUnit才準備流行,所以測試主要以 ad-hoc 為主。</p>
</li>
<li>
<p>James 常給人的忠告︰「不要顧用太多測試員工」,Larry Page︰「Scarcity brings clarity (意指︰在缺乏資源的情況時,會有清楚的目標;銀彈不足,才會想辦法彈無虛發 …</p></li></ul><p>這本書的作者是在軟體測試界很有名的 James Whittaker,以 How to break xxx 系列跟 Exploratory Testing 聞名。這本是他在Google期間完成的著作。可惜他己經在2012年3月左右離開了Google,發表了一篇<a href="http://blogs.msdn.com/b/jw_on_tech/archive/2012/03/13/why-i-left-google.aspx">Why I left google</a>/<a href="http://www.csdn.net/article/2012-03-14/313106">中文翻譯</a>。從微軟到Google,最後又回鍋到微軟了。文中大體的原因就是Google把創新精神丟掉,而只專注在廣告上,不再是一家是以技術優先導向的公司。但是這些還是毫不影響Google在軟體界的王者地位。</p>
<p>Google跟微軟在軟體測試上的策略很不一樣。傳統上,微軟的開發與測試人員比例大概是1:1左右。小弟的公司也是如此。但是Google專職在測試的人員,就明顯少得很多。我想從本書找到,如果專職測試人員少的話,那麼整個軟體開發流程會變的如何?其實,微軟在2008年也有出一本拿自己公司名稱當招牌的測試書 <a href="http://www.amazon.com/How-We-Test-Software-Microsoft/dp/0735624259">How We Test Software at Microsoft</a>,這本有點厚,之後找個機會來看。以目前軟體公司的發展看來,也許之後就會看到一本以 Facebook 為主角的測試書了。</p>
<h3>Ch1. Introduction to Google Software Testing</h3>
<ul>
<li>
<p>在 Google,測試工作是由一個中央的組職稱為 Engineering Productivity 來負責。包含 Developer 跟 Tester tool chain, Release engineer 。從 Unit test 包到 Exploratory testing。</p>
</li>
<li>
<p>Google 在2001年時,約有200位開發工程師,但是只有<em>3</em>位測試工程師,那時開發工程師就必需為自己寫的程試的品質負責。那時TDD跟JUnit才準備流行,所以測試主要以 ad-hoc 為主。</p>
</li>
<li>
<p>James 常給人的忠告︰「不要顧用太多測試員工」,Larry Page︰「Scarcity brings clarity (意指︰在缺乏資源的情況時,會有清楚的目標;銀彈不足,才會想辦法彈無虛發)」</p>
</li>
<li>
<p>Everyone who writes code is tester </p>
</li>
</ul>
<p>問題︰但是人少,所扮演的角色是? </p>
<ul>
<li>
<p>Quality != Test , 不要視測試跟開發為兩個獨立流程。測試應該當成開發流程中的一部份。當測試跟開發完美混合區分不時出來的時侯,Quality的目標就達成了。也就是你不能單單只做開發或是測試。而完全不管另一方。</p>
</li>
<li>
<p>當產品掛掉的時侯,第一個苦主會是找誰寫這個開發者。而不是那個沒抓到Bug的測試者。</p>
</li>
<li>
<p>Quality is more an act of <strong>prevention</strong> than it is <strong>detection</strong> ; Quality is a development issue, not a testing issue.</p>
</li>
</ul>
<p>心得︰大多軟體公司,在找測試人員時,開發能力通常遠不及開發人員。所以常常是自成一國,有自己的Process,跟Schedule,而大體上是用重要的Milesone來跟Developement Prcoess來對齊。所以Testers完全無法融入開發流程的一員。這是團隊人員組成,跟能力配制的問題。如果Developer本身就可以扛下測試的責任時。也許就並不需要那麼多測試人員的。但是這需要Developer本身要有自我的認知,測試的主要責任在自己身上。</p>
<ul>
<li>
<p><strong>Testing must be an unavoidable aspect of development</strong>, and the marriage of development and testing is where quality is achieved</p>
</li>
<li>
<p>Tester in Google, are responsible for making other engineers <strong>more productive and more quality-minded</strong></p>
</li>
<li>
<p>測試者的主要任務是讓開發者更有<strong>效率</strong>的去測試他們自己的產物</p>
</li>
<li>角色1 - Software Engineer (SWE): </li>
<li>Implement functional code</li>
<li>Write design document </li>
<li>Write Test code , 包含 TDD, unit test, <strong>建構與參與大中小的測試 </strong></li>
</ul>
<p>心得: 當公司有花錢找一堆不參與Functional開發的測試人員時,SWE就不可能會花時間寫足夠的測試,因為這些測試是交由測試人員來負責的。所以常常傳統上的共識就變成是 developer 測 unit test,而 tester 測 functional level以上的測試,包含 system testing 跟 integration testing 等等。而 Google 的做法就是讓 Developer 自己來搞,也正好呼應了前面所說的 Scarcity brings clarity。</p>
<ul>
<li>角色2-Software engineer in test (SET):</li>
<li>Focus on <strong>testability</strong> and <strong>general test infrastructure</strong> </li>
<li>Review designs, codes and risk</li>
<li><strong> Refactor </strong> code to make it more testable </li>
<li>Write unit testing <strong>frameworks</strong> and automation.</li>
</ul>
<p>心得︰工作二年來,直到看到這本書我才了解,內心一直想做的事其實就是書中寫的SET。但是現有的Process並沒有定義這樣的Role,這衝突、矛盾的結果,就讓我感覺我想做的事,跟我做的事,很多都是在做白工。因為團隊沒有共識有SET這個Role。我感受到,團隊陣容跟員工能力如果都是Waterfall的思維構成。那麼不管灌入再潮的Mindset,Methodology,再多Agile的行為,CI的規劃。終究會因為這群人是用Wafterwall運作下的所需能力找來的人。他們只能習慣Waterfall的Process,這是他們最舒服的運作模式。所以,不管換什麼工作模式,終究會被打回原形。成功的 Software Process,或許該從找對人來組成適合該Process的團隊組職開始。那群人就應該會很理所當然的以“舒服”的方法運作下去,一切就會很自然吧。</p>
<ul>
<li>角色3-Test Engineer (TE):</li>
<li>Put testing on behalf of the user first</li>
<li>Organize the overall quality practices </li>
<li>interpret test result </li>
<li>drive test execution and build end-to-end test automation </li>
<li>Test Engineer是動態指派到Product Team,跟據需求。</li>
<li>
<p>TE,在Proudct Team,工作約18個月之後,可以自由地轉去其它的Product Team。對於Product短期而言,似乎是損失,因為少了一個熟悉產品的人。但對於TE有正面影響,可以擁用不同產品的測試經驗 (心得︰對於TE有較長遠規劃)。長遠看來,對於Product,也可以擁有不同產品測試經驗的人才。</p>
</li>
<li>
<p>心得︰</p>
<ol>
<li>T公司的QA = 20% SWE + 10% SET + 100% TE</li>
<li>T公司的Developer = 70% SWE + 30% SET + 10% TE</li>
</ol>
</li>
</ul>
<p>比較交集的結果,缺少人專注在SET的任務上。我覺得這就是大部份的Product Automation 弄不起來最主要原因。主要是任務TE的QA們,需要花很多額外的時間,而且使用不同的Codebase (Deverloper 使用 C/C++,QA使用Python)來克服 Testability不好,而需要寫很多跟Product功能相同,但是codebase不同的code。跟一堆 working environment問題。這些問題的正解是SWE跟SET需要擁用相同 Codebase,目標一致,方可有效率地完成任務。而跟本的差界就是在T公司,寫Automation Test主要是QA(其實是TE)的責任。而在Google,這其實主要是Code authors的責任。在Google,專職的Tester,被交附不同的任務,而任務是幫助讓SWE測試更好做,寫出好的<strong>Test code</strong>,讓SWE可以專注在開發 <strong>Feature code</strong> 上面。</p>
<ul>
<li>Build 的種類,依穩定性區分︰</li>
<li>Canary Channel : daily builds, build fails is a chaotic sign , for enginners and managers</li>
<li>Dev Channel : weekly builds, shall passed some set of tests ,for developers day-to-day work</li>
<li>Test Channel : month builds, passes the most sustained testing, for internal dogfood users(狗食這邊是軟體業的黑話,是指用公司最好用自家產品,像是微軟用outlook,Google用Gmail等等) </li>
<li>Beta(Release) Channel : stable test channel builds, pass every <strong> quality bar</strong> the team sets </li>
</ul>
<p>心得︰以測試的角度,我們應該要測<strong>最新</strong>的Build,但是一個不穩定的Build,會讓我們的測試工作受阻,稱為testing blocked,所以我們要有能力知道該拿什麼樣的Build,來做目前測試的目的。理論上,照這種邏輯,我們應該隨時可以拿到這五種Channel的Build。</p>
<ul>
<li>
<p>Crawl, Walk, Run: 先推出 "Minimum useful product" as an initial version,然後再依Feedback來決定下一步要做什麼。其實就是Agile精神。</p>
</li>
<li>
<p>測試的種類,依自動化難度區分,以 small test scope 最小,最容易自動化: </p>
</li>
<li>
<p>small test: </p>
<ul>
<li>moftly by SWE, less often by an SET, hardly ever by TEs </li>
<li>small 會需要很多 mock , fake, stubs。</li>
<li>TEs 有時會執行 small 來幫助 dianose 某個 failure</li>
<li><strong>目的</strong>︰是測試一小段code是不是如預期的行為</li>
</ul>
</li>
<li>
<p>medium test: 大部份是自動化,會有多個 features 交互作用</p>
<ul>
<li>nearest neighbor functions : 彼此有關系的 functions,一次只專注部份一組的 functions 上</li>
<li><strong>目的</strong> 這個 a set of nearest neighbor functions 彼此交互作用是否如預期?</li>
</ul>
</li>
<li>
<p>large test: usually user scenarios, real user data</p>
<ul>
<li>測試執行時間比較久,以使用者為出發點的測試</li>
<li>整體功能面的整合測試</li>
<li>檢驗是否實滿足客戶的需求(Validation)</li>
</ul>
</li>
<li>
<p>三種測試都可能是自動化或是手動,取決的點︰</p>
</li>
<li>自動化︰不需要人類的才智,直覺,判斷,那麼這些就應該自動化</li>
<li>
<p>手動 ︰需要人的評斷,像是UI好不好看,Privacy issue, usability test等等,就應該留在手動測試的領域,Google有做很多手動測試,不管是Script或是Exploratory式的。Recoding technology converts manual tests to automated tests。(一般認為Recoding是過時的技術,沒想到Google還是覺得有他的重要性,可以用來減少 regression test</p>
</li>
<li>
<p>把自動化測試的失敗,跟Bug tracking system 結合。比如在之前的測試成功,但是這次測試失敗,自動Fire bug Tracker,留下記錄,<strong>把Automation fail直接當成Product Defect</strong>,讓Automation bug也視為是Product的Bug。把記錄Email給作者, 知道這次的change是什麼,即早發現 Bug,讓苦主可以盡快休復。</p>
</li>
</ul>Windows 7 安裝 Virtual Smart Card Reader in Workstation 8.02012-08-21T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-08-21:/vmware-virtual-smart-card/<p>VMware Workstation 8.0 有<a href="http://www.vmware.com/pdf/ws80-using.pdf">支援使用 Smart Card Reader</a>的功能,我的 Guest 是 Windows 7 Pro x86,裡面的Virtual Smart Card Reader 就怎麼樣就是裝不起來,顯示驅動程式安裝不成功。 Google 了一下,<a href="http://communities.vmware.com/message/1119067">找到了解法</a>,關鍵字就是 <code>554522.cab</code> 這個 Driver。</p>
<h2>解法︰</h2>
<ol>
<li>下載 Cab 檔︰ <a href="http://www.download.windowsupdate.com/msdownload/update/v3-19990518/cabpool/5545222.cab">Link</a></li>
<li>解開裡面的 usbccid.* 的三個檔案</li>
<li>去 Device Manage,找到那個有驚嘆號的 Smart Card Reader</li>
<li>更新 Driver,手動選擇 Device Type,然後選 Smart Card Driver</li>
</ol>
<p>接下來一直 Next , Next .. 就可以安裝完成了。</p>Install Bugzilla on CentOS 6.3 step by step2012-08-18T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-08-18:/install-bugzilla-centos-6-3-step-step/<h3>Install required packages</h3>
<div class="highlight"><pre><span></span><code>$ yum install perl* httpd* mysql-server* mod_perl-devel -y
</code></pre></div>
<p><strong>Download the <a href="http://www.bugzilla.org/download/">latest bugzilla</a> 4.2.2 (2012/8)</strong></p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">cd</span> /var/www/html
$ wget http://ftp.mozilla.org/pub/mozilla.org/webtools/bugzilla-4.2.2.tar.gz
$ tar zxvf bugzilla-4.2.2.tar.gz
$ mv bugzilla-4.2.2 bugzilla
</code></pre></div>
<h3>Start mysql server</h3>
<div class="highlight"><pre><span></span><code>$ service mysqld start
</code></pre></div>
<h3>Set mysql root password via <em>mysql_secure_installation</em>**</h3>
<div class="highlight"><pre><span></span><code>$ sudo /usr/bin/mysql_secure_installation
</code></pre></div>
<p><strong>Create a DB for bugzilla </strong> mysql login with root</p>
<div class="highlight"><pre><span></span><code>$ mysql -u root -p
> CREATE DATABASE bugs <span class="p">;</span>
> <span class="nb">exit</span>
</code></pre></div>
<h3>Run checksetup script to find needed modules</h3>
<div class="highlight"><pre><span></span><code>$ ./checksetup.pl
</code></pre></div>
<p><strong>Install required modules </strong></p>
<div class="highlight"><pre><span></span><code>$ /usr/bin/perl install-module.pl <span class="p">&</span>ndash …</code></pre></div><h3>Install required packages</h3>
<div class="highlight"><pre><span></span><code>$ yum install perl* httpd* mysql-server* mod_perl-devel -y
</code></pre></div>
<p><strong>Download the <a href="http://www.bugzilla.org/download/">latest bugzilla</a> 4.2.2 (2012/8)</strong></p>
<div class="highlight"><pre><span></span><code>$ <span class="nb">cd</span> /var/www/html
$ wget http://ftp.mozilla.org/pub/mozilla.org/webtools/bugzilla-4.2.2.tar.gz
$ tar zxvf bugzilla-4.2.2.tar.gz
$ mv bugzilla-4.2.2 bugzilla
</code></pre></div>
<h3>Start mysql server</h3>
<div class="highlight"><pre><span></span><code>$ service mysqld start
</code></pre></div>
<h3>Set mysql root password via <em>mysql_secure_installation</em>**</h3>
<div class="highlight"><pre><span></span><code>$ sudo /usr/bin/mysql_secure_installation
</code></pre></div>
<p><strong>Create a DB for bugzilla </strong> mysql login with root</p>
<div class="highlight"><pre><span></span><code>$ mysql -u root -p
> CREATE DATABASE bugs <span class="p">;</span>
> <span class="nb">exit</span>
</code></pre></div>
<h3>Run checksetup script to find needed modules</h3>
<div class="highlight"><pre><span></span><code>$ ./checksetup.pl
</code></pre></div>
<p><strong>Install required modules </strong></p>
<div class="highlight"><pre><span></span><code>$ /usr/bin/perl install-module.pl <span class="p">&</span>ndash<span class="p">;&</span>ndash<span class="p">;</span>all
</code></pre></div>
<h3>Run checksetup script again to generate localconfig file</h3>
<div class="highlight"><pre><span></span><code>$ ./checksetup.pl
</code></pre></div>
<p><strong>Modify localconfig for $db_name, $db_user and $db_pass based on previous settings</strong></p>
<div class="highlight"><pre><span></span><code>$ vi ./localconfig
</code></pre></div>
<p><strong>Run checksetup script to set initial configuration</strong></p>
<div class="highlight"><pre><span></span><code>$ ./checksetup.pl
</code></pre></div>
<p><strong>Apache setup, modify httpd.conf, append the following config :</strong></p>
<div class="highlight"><pre><span></span><code>$ vi /etc/httpd/conf/httpd.conf
<span class="nt"><Directory</span> <span class="err">/var/www/html/bugzilla</span><span class="nt">></span>
AddHandler cgi-script .cgi
Options +Indexes +ExecCGI
DirectoryIndex index.cgi
AllowOverride Limit FileInfo Indexes
<span class="nt"></Directory></span>
</code></pre></div>
<p><strong>Restart Apache </strong></p>
<div class="highlight"><pre><span></span><code>$ service httpd restart
</code></pre></div>
<p><strong>Chkconfig httpd and mysql </strong></p>
<div class="highlight"><pre><span></span><code>$ chkconfig httpd on
$ chkconfig mysqld on
</code></pre></div>
<p><strong>Set iptables for httpd </strong></p>
<div class="highlight"><pre><span></span><code>$ iptables -I INPUT -p tcp <span class="p">&</span>ndash<span class="p">;&</span>ndash<span class="p">;</span>dport <span class="m">80</span> -j ACCEPT
</code></pre></div>
<p>That’s it, Open http://localhost/bugzilla and enjoy it.</p>搭和諧長城號到北京八達嶺長城2012-08-12T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-08-12:/great-wall-beijing/<p><img alt="train" src="http://i.imgur.com/GBnB5Ve.png"></p>
<p>一般旅遊書都是寫從德勝門搭公交中到八達嶺長城。但是問了北京當地友人,其實都覺得搭<a href="http://baike.baidu.com/view/1736959.htm">北京市郊鐵路S2線</a>的<a href="http://baike.baidu.com/view/3213437.htm">和諧長城號</a>是最方便的。而且重點是,單程只需人民幣 "6"元,超便宜的,車程約80分鐘。</p>
<p>預計出發的附近幾天,其實天氣都不太好。但是別人都說「不到長城非好漢」。所以不管風雨多大,還是要衝一下長城。因為當天下午還有安排其它行程,為了可以早去早回,所以我們選了最早的一班動車,AM 6:12 出發。八達嶺長城經過整修之後,現在己經十足的現代化了。上面甚至有永和豆漿大王,肯德基等等速食連鎖。因為天氣關係,所以上長城之後就感覺就像漫步在雲端。整個白濛濛一片,視野不好。希望下次還有機會可以體驗其它風格的長城,像是慕田峪跟司馬台等等。</p>
<p><img alt="img" src="http://i.imgur.com/b6dyHn3l.jpg"></p>
<h3>參考網站:</h3>
<ul>
<li><a href="http://ice2006.pixnet.net/blog/post/30669312-%E3%80%90china%E3%80%91%E6%90%AD%E5%92%8C%E8%AB%A7%E9%95%B7%E5%9F%8E%E8%99%9F%EF%BC%8E%E7%99%BB%E5%85%AB%E9%81%94%E5%B6%BA%E9%95%B7%E5%9F%8E">【CHINA】搭和諧長城號.登八達嶺長城 @ 新南極轉運站 :: 痞客邦 PIXNET :: </a></li>
</ul>在 Ubuntu 修改 ThinkPad 的充電設定2012-08-07T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-08-07:/thinkpad-battery-ubuntu/<p>在 Windows 中我們們可以很容易從 <code>Power Manager Battery Maintenance setting</code>來改變充放電的設定,我習慣低於65%開始充電,然後充到90%就停止。在Ubuntu中,稍微麻煩一些,因為目前沒有GUI的介面來達到這件事。在Ubuntu Brainstorm有提出這個需求,希望未來的版本可以直接從OS層級來解決這個問題。但還好目前有一個專門的API叫<a href="http://www.thinkwiki.org/wiki/Tp_smapi">Tp smapi</a>來達到我的需求。在Ubuntu 12.04下的安裝方法如下:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install tp-smapi-dkms
$ sudo modprobe tp_smapi
</code></pre></div>
<p>成功之後,在 <em>/sys/devices/platform/smapi/ _就會多了很多跟電源設定相關的檔案。而我最在意的莫過於 _stop_charge_thresh</em>,<em>start_charge_thresh</em> 跟_ cycle count_。例如說我想知道電池的cycle count 是多少:</p>
<div class="highlight"><pre><span></span><code>$ cat /sys/devices/platform/smapi/BAT0/cycle_count
<span class="m">130</span>
</code></pre></div>
<p>這台在幾乎天天使用的情況下,從出廠到現在15個月,cycle count 達到 130,不曉得算不算高。希望還能再撐個15個月 :) 查了一下官方的 <a href="http://www.thinkwiki.org/wiki/Tp_smapi">wiki</a>,目前Tp smapi 對 x220只支援 stop_charge_thresh 而不支援 start_charge_thresh。冏。算了,之後應該會支援吧。目前就先防過充就好。設定的方式如下,例如我想充到95%就停止:</p>
<div class="highlight"><pre><span></span><code>sudo sh -c 'echo 95 > /sys/devices/platform/smapi/BAT0/stop_charge_thresh'
</code></pre></div>
<p>稍微實驗了一下,插上電源之後,就真的只充到我想要的 95%</p>
<p>另一個設定則是插上電源之後幾分才開始充電,以避免頻繁的充電</p>
<div class="highlight"><pre><span></span><code>sudo sh …</code></pre></div><p>在 Windows 中我們們可以很容易從 <code>Power Manager Battery Maintenance setting</code>來改變充放電的設定,我習慣低於65%開始充電,然後充到90%就停止。在Ubuntu中,稍微麻煩一些,因為目前沒有GUI的介面來達到這件事。在Ubuntu Brainstorm有提出這個需求,希望未來的版本可以直接從OS層級來解決這個問題。但還好目前有一個專門的API叫<a href="http://www.thinkwiki.org/wiki/Tp_smapi">Tp smapi</a>來達到我的需求。在Ubuntu 12.04下的安裝方法如下:</p>
<div class="highlight"><pre><span></span><code>$ sudo apt-get install tp-smapi-dkms
$ sudo modprobe tp_smapi
</code></pre></div>
<p>成功之後,在 <em>/sys/devices/platform/smapi/ _就會多了很多跟電源設定相關的檔案。而我最在意的莫過於 _stop_charge_thresh</em>,<em>start_charge_thresh</em> 跟_ cycle count_。例如說我想知道電池的cycle count 是多少:</p>
<div class="highlight"><pre><span></span><code>$ cat /sys/devices/platform/smapi/BAT0/cycle_count
<span class="m">130</span>
</code></pre></div>
<p>這台在幾乎天天使用的情況下,從出廠到現在15個月,cycle count 達到 130,不曉得算不算高。希望還能再撐個15個月 :) 查了一下官方的 <a href="http://www.thinkwiki.org/wiki/Tp_smapi">wiki</a>,目前Tp smapi 對 x220只支援 stop_charge_thresh 而不支援 start_charge_thresh。冏。算了,之後應該會支援吧。目前就先防過充就好。設定的方式如下,例如我想充到95%就停止:</p>
<div class="highlight"><pre><span></span><code>sudo sh -c 'echo 95 > /sys/devices/platform/smapi/BAT0/stop_charge_thresh'
</code></pre></div>
<p>稍微實驗了一下,插上電源之後,就真的只充到我想要的 95%</p>
<p>另一個設定則是插上電源之後幾分才開始充電,以避免頻繁的充電</p>
<div class="highlight"><pre><span></span><code>sudo sh -c 'echo 2 > /sys/devices/platform/smapi/BAT0/inhibit_charge_minutes'
</code></pre></div>
<h2>Reference</h2>
<ul>
<li><a href="http://www.thinkwiki.org/wiki/Tp_smapi">Tp smapi - ThinkWiki</a></li>
</ul>
<!--
echo 15 > /sys/devices/platform/smapi/BAT0/inhibit_charge_minutes
[start_change_thres in X220 · Issue #2 · ginkel/tp_smapi](https://github.com/ginkel/tp_smapi/issues/2)
-->香港 HopInn 撲撲旅舍2012-08-06T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-08-06:/hong-kong-hopinn/<p><img alt="Hopinn" src="https://lh5.googleusercontent.com/-OydnjxFoNYw/VBDmpAm6P9I/AAAAAAAFgMY/RKOHRo9nUl0/w1772-h1184-no/P1050896.JPG"></p>
<p><a href="http://blog.codylab.com/beijing-hong-kong-travel/">這趟香港行</a>我選擇的旅舍是在TripAdivor評價頗不賴的<a href="http://www.hopinn.hk/">撲撲旅舍</a>,撲撲在粵語唸起來應該類似Po Po。那時訂房的時侯,是透過它們<a href="http://www.hopinn.hk/">官網</a>聯繫,最後訂下來的房價是雙人房HKD 640一晚。撲撲旅舍有兩家分店,我住的是<strong>加拿芬道店</strong>,這家是後來才開的, 看牌照的資訊,這分店有八間房。選擇撲撲旅舍的一大重點就是交通超便利。離地鐵尖沙咀站走路只有大約3分鐘,很方便。房間是使用磁卡感應進出,進房間總共需要通過兩道感應門,相較於一些旅舍使用傳統的錀匙比較起來令人安心不少。撲撲旅舍整體給人很舒服,一進門就有很沁涼的冷氣迎面而來。前台的服務態度也都很好,笑臉迎人,有問必答。公共空間也設計的蠻不錯的。另外,也有提供公共飲水機可以使用,看起來蠻乾淨的。因為是在香港,所以房間也就當然小小的。我住的是L8房,這間房有兩面對外窗,採光很棒。可以看到香港繁榮的街景,日夜給人的感覺都很不一样。撲撲旅舍位於尖沙咀,從機場搭A21巴士就可以到了,交通超級很方便。</p>
<p><img alt="L8" src="https://lh3.googleusercontent.com/-vTpANh1GNXY/VBDm96atPOI/AAAAAAAFgPg/WB588R_1hAU/w1772-h1184-no/P1050479.JPG"></p>
<p>撲撲旅舍 - 加拿芬道店:香港尖沙咀33 - 35號加拿芬道發利大廈9樓 </p>
<p>網站:<a href="http://www.hopinn.hk/">http://www.hopinn.hk/</a></p>《怦然心動的人生整理魔法》 筆記2012-08-06T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-08-06:/storage-magic/<p><img alt="img" src="https://lh6.googleusercontent.com/-43swuWtDpCI/UsjbkyLQHEI/AAAAAAAFHow/LV08cfJNyWI/w369-h519-no/f3a16192c527d907e9a40485c95e9107aePG55.jpeg"></p>
<p>最近在搬家,無意間注意到這本有關整理的暢銷書,我毫不考慮衝到實體店面買下來了。這本書有大半部份都是在講如何丟東西,所以看完這本書會讓你增加勇氣,丟東西有所依據,按照專家的原則把該丟的東西丟一丟,而丟與不丟的準則很簡單,那就是:只留下讓自己「<strong>心動</strong>」的東西。把東西拿在手上感受一番,如果是不讓你心動的東西,就直接丟了,把自己在乎的東西留下。而整理要一股作氣,以達到最佳的整理完的乾淨況態。作者強調,一旦達到這個狀態就不會再變亂了 。</p>
<h1>整理原則</h1>
<ol>
<li>把不要的東西丟掉(或賣掉),只留下心動的物品。不要捨不得,不心動的事物,如果有需要再買回來就是了</li>
<li>每個物品要有自己的家,不要讓其它雜物入侵他們的家,自然就會整齊</li>
<li>對這些心動的物件們培養感情。有時間就跟它們說說話,感謝他們的出現</li>
</ol>
<h1>收納小技巧</h1>
<ul>
<li>包中有包: 把包包收到包包裡面。因為空的包包裡面的空間都是閒置的,可以用來收納其它比較小的包包。</li>
<li>直立收納: 平躺收納的缺點就是壓在底層的物品都會被忽略,很少會用到,自然也就沒辦法養成心動度。久而久之就會被丟掉。</li>
</ul>
<h1>2016 再次閱讀筆記</h1>
<ul>
<li>整理包含兩個步驟: 1. 留下會讓自己心動的東西 2. 把東西放到指定的位置</li>
<li>整理是節慶,一年頂多一到二次。如果整理做的好,打掃灰塵的清潔工作就會變得很簡單。</li>
<li>整理的順序: 衣物、書籍文件、記念品</li>
<li>按照類別,而不是場所來進行整理。</li>
<li>人的專注力有限,只留下讓自己心動的事物,讓這些心動物品來幫助自己。</li>
<li>當東西減少了,自然心理的壓力也會跟著減少。</li>
<li>書的前半部是跟你說大部份的東西都可以丟</li>
<li>書的後半部是教你如何營造幸福的空間</li>
</ul>
<h1></h1>
<p>把不重要的東西丟掉之後,才曉得自己到底在乎什麼。</p>
<p>可以丟的東西遠比你想象的多。</p>在Python中如何Async的方式呼叫外部程式2012-07-20T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-07-20:/python-creationflags/<p>最近有個需求:使用Python呼叫外部程式,外部程式屬於背景程式類型。也就是我希望python程式結束時不需要等待外部程式結束。Google了一下,找到Stack Overview的<a href="http://stackoverflow.com/questions/3516007/run-process-and-dont-wait">解答</a>,關鍵就是在 subprocess.popen() 使用 creationflags 這個參數,這個方法只有在Windows試驗過,其它的平台就不確定了。比如說我想呼叫notepad:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">subprocess</span>
<span class="n">DETACHED_PROCESS</span> <span class="o">=</span> <span class="mh">0x00000008</span>
<span class="n">subprocess</span><span class="o">.</span><span class="n">Popen</span><span class="p">([</span><span class="s2">"notepad"</span><span class="p">],</span> <span class="n">shell</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">close_fds</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">creationflags</span><span class="o">=</span><span class="n">DETACHED_PROCESS</span><span class="p">)</span>
</code></pre></div>
<p>這樣這支python程式就會自行結束,而不會等notepad了。</p>
<h3>Reference :</h3>
<ul>
<li><a href="http://stackoverflow.com/questions/905189/why-does-sys-exit-not-exit-when-called-inside-a-thread-in-python">http://stackoverflow.com/questions/905189/why-does-sys-exit-not-exit-when-called-inside-a-thread-in-python</a></li>
<li><a href="http://stackoverflow.com/questions/3516007/run-process-and-dont-wait">python - Run Process and Don't Wait - Stack Overflow</a></li>
</ul>北京香港自由行記錄2012-07-07T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-07-07:/beijing-hong-kong-travel/<h2>機票訂購</h2>
<ul>
<li><a href="http://www.backpackers.com.tw/forum/airfare.php">背包客棧自助旅行論壇 - 機票比價</a> :這個網站很讚,可以找到很多便宜的機票,但是要留意便宜機票的限制。</li>
</ul>
<h2>票務訂購</h2>
<ul>
<li>
<p><a href="http://www.ysticket.com/">玉山票務</a>:我是從機票比價網站,找到這家。上網登錄航班需求之後, 會有專人會以Email回覆,相較於一些大的旅行社,例如X獅,沒法直接用EMail連絡客服,我覺得玉山這點還不錯。在上班時間客服回應速度都很快,整體服務算不錯。</p>
</li>
<li>
<p>最後訂到票價是台北-香港-北京來回+香港停留,機票 NTD 7526,稅金 NTD 5327:<strong>12853/人
</strong></p>
</li>
<li>
<p>台北-香港 / CX 403 波音 777-300</p>
</li>
<li>香港-北京 / CX 6880 空中巴士 330-300 </li>
<li>北京-香港 / KA905 空中巴士 330-300 </li>
<li>香港-台北 / CX464 波音 777-300 </li>
</ul>
<h2>訂房</h2>
<p><a href="http://www.tripadvisor.com.tw/">TripAdvisor</a>:這個網站提供很多飯店的評論,也可以連到外面的訂房網站,大陸版本的TripAdvisor叫<a href="http://www.daodao.com/">到到網</a>。</p>
<p>北京的部份一開始就直接鎖定較便宜的青年旅舍,最後透過<a href="http://www.booking.com/">Booking.com</a>預約<a href="http://www.yhachina.com/ls.php?id=187">北京和園國際青年旅舍</a>。這邊發生了一件冏事,因為Booking.com在預定的時侯有叫我輸入信用卡資訊,當下我以為房款會由信用卡支付,所以身上就沒有特別帶北京六個晚上的住宿費。沒想到當天到和園Check-in的時侯,才被告知要付六晚的住宿費+CNY 100的押金,身上的現金馬上噴了大半。還好出國前有開啟國外ATM提款功能,不然現金是鐵定不夠的。</p>
<p>香港地狹人稠,所以房間價格有稍微提高一些來尋找,在TripAdvisor發現這間獲得<strong>2012年旅行者之選獎-最時尚飯店</strong>頭銜的「<a href="http://www.hopinn.hk/">撲撲旅舍</a>」。價位還OK,地點超方便就在尖沙咀地鐵站旁,就馬上下訂這家了。最後果然也沒有讓我失望。服務態度、旅店風格、交通地點、安全性、舒適度等等都讓我之後會想要再住一次。</p>
<h2>實際行程(計畫總改不上變化)</h2>
<p><strong>北京 DAY1
</strong>和園 Check-in > 凯德MALL > 福成肥牛 </p>
<p><strong>北京 DAY2
</strong>護國寺小吃 > 恭王府 > 煙袋斜街 > 三元梅园 > 南鑼鼓巷 …</p><h2>機票訂購</h2>
<ul>
<li><a href="http://www.backpackers.com.tw/forum/airfare.php">背包客棧自助旅行論壇 - 機票比價</a> :這個網站很讚,可以找到很多便宜的機票,但是要留意便宜機票的限制。</li>
</ul>
<h2>票務訂購</h2>
<ul>
<li>
<p><a href="http://www.ysticket.com/">玉山票務</a>:我是從機票比價網站,找到這家。上網登錄航班需求之後, 會有專人會以Email回覆,相較於一些大的旅行社,例如X獅,沒法直接用EMail連絡客服,我覺得玉山這點還不錯。在上班時間客服回應速度都很快,整體服務算不錯。</p>
</li>
<li>
<p>最後訂到票價是台北-香港-北京來回+香港停留,機票 NTD 7526,稅金 NTD 5327:<strong>12853/人
</strong></p>
</li>
<li>
<p>台北-香港 / CX 403 波音 777-300</p>
</li>
<li>香港-北京 / CX 6880 空中巴士 330-300 </li>
<li>北京-香港 / KA905 空中巴士 330-300 </li>
<li>香港-台北 / CX464 波音 777-300 </li>
</ul>
<h2>訂房</h2>
<p><a href="http://www.tripadvisor.com.tw/">TripAdvisor</a>:這個網站提供很多飯店的評論,也可以連到外面的訂房網站,大陸版本的TripAdvisor叫<a href="http://www.daodao.com/">到到網</a>。</p>
<p>北京的部份一開始就直接鎖定較便宜的青年旅舍,最後透過<a href="http://www.booking.com/">Booking.com</a>預約<a href="http://www.yhachina.com/ls.php?id=187">北京和園國際青年旅舍</a>。這邊發生了一件冏事,因為Booking.com在預定的時侯有叫我輸入信用卡資訊,當下我以為房款會由信用卡支付,所以身上就沒有特別帶北京六個晚上的住宿費。沒想到當天到和園Check-in的時侯,才被告知要付六晚的住宿費+CNY 100的押金,身上的現金馬上噴了大半。還好出國前有開啟國外ATM提款功能,不然現金是鐵定不夠的。</p>
<p>香港地狹人稠,所以房間價格有稍微提高一些來尋找,在TripAdvisor發現這間獲得<strong>2012年旅行者之選獎-最時尚飯店</strong>頭銜的「<a href="http://www.hopinn.hk/">撲撲旅舍</a>」。價位還OK,地點超方便就在尖沙咀地鐵站旁,就馬上下訂這家了。最後果然也沒有讓我失望。服務態度、旅店風格、交通地點、安全性、舒適度等等都讓我之後會想要再住一次。</p>
<h2>實際行程(計畫總改不上變化)</h2>
<p><strong>北京 DAY1
</strong>和園 Check-in > 凯德MALL > 福成肥牛 </p>
<p><strong>北京 DAY2
</strong>護國寺小吃 > 恭王府 > 煙袋斜街 > 三元梅园 > 南鑼鼓巷 : 興穆手工、文宇奶酪、阿拉伯大串烤肉、翅對 > 秋栗香 > 海底捞 > 賽足林 </p>
<p><strong>北京 DAY 3
</strong>江边城外巫山烤全鱼 > 千荷大煎餅 > 前門大街 Shopping > 前門星巴克 > 利群烤鴨 > </p>
<p><strong>北京 DAY 4
</strong>前門大街 > 天安門 > 故宮 > 玉堂春色 京味休閒餐廳 </p>
<p><strong>北京 DAY 5
</strong>火燒石 串燒工坊 > 北交大 > 鳥巢、水立方 > 水晶烤肉 </p>
<p><strong>北京 DAY 6
</strong>長城 > 大董烤鴨 > 三里屯 > 永和足疗保健</p>
<p><strong>香港 DAY 1
</strong>北京 > 香港機場 >3HK 3G上網卡(出境層北面) > 城巴A21>撲撲Check-In>翠華餐廳>Jenny Bakery曲奇餅>海港城 Shopping >維多利亞港>天星小輪>文華東方酒店草莓玫瑰果醬 > 洪利粥店茶餐廳 > 許留山</p>
<p><strong>香港 DAY 2
</strong>添好運 > 卓悅藥妝 > 蘭芳園 > 活方商場 Shopping > 黃大仙 > 北角利強雞蛋仔 > Shopping QIPS買文具 > 幻彩詠香江 > 天星小輪 > 星巴克冰室 > 蘭桂坊 > 許留山 > 興記煲仔飯</p>
<p><strong>香港 DAY3
</strong>預辦登機 > 何洪記 > 時代廣場 > 杏花樓 > Shopping > 翠華餐廳 > 回台北</p>研發替代役申請出國旅遊2012-07-05T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-07-05:/rdss-travel-notes/<p>研發替代役在第三階段之後,一年可申請出國旅遊一次。我剛從北京-香港回來,在此小記一下。每年的1/1日重新計算,照規定可出國天數8天,但因為「出境日數」為<strong>出境翌日</strong>開始計算,所以實際可以出國天數為9天。出國的規定每年可能都不一樣,最新規定請參照<a href="http://www.nca.gov.tw/">內政部役政署</a>。</p>
<h2>1. 申請護照(以護照過期而親辦為例)</h2>
<p>位置:外交部領事事務局,台北市濟南路一段二之二號,中午不休息。
費用:正常件 1600</p>
<p>所需文件:
1.二吋照片兩張(<a href="http://www.boca.gov.tw/ct.asp?xItem=1875&ctNode=732&mp=1">需合乎護照規定</a>)
2.身份證正反影本
3.研替身份證正反影本(背面要寫上用人單位資訊), 需要把研替影本貼在申請表後面
4.過期舊護照,剪角後會歸還</p>
<h2>2.請公司HR向研發替代役專案辦公室提出出境申請</h2>
<p>盡早申請,需要告知欲前往的國家、班機、跟日期等基本資訊。這個可以先申請,護照可以之後再補。HR會把你的護照送回內政部,並會蓋上一個章核準出國。HR會給你一張公文:</p>
<p><img alt="img" src="http://i.imgur.com/MI9NQjT.jpg">
這張公文出境時可以隨身帶著,必要時可以提出證明</p>
<h2>3.申請台胞證</h2>
<p>我是找<a href="http://www.sttvisa.com/">簽證通</a>,價格還算實惠。加簽300,新辦含加簽1400。</p>軟體測試人的每日體操2012-06-14T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-06-14:/daily-improvement-testing/<p>之前讀了一本軟體測試的書《<a href="http://book.douban.com/subject/4196675/">贏在測試</a>》,裡面主要以訪談的形式來訪問中國界的軟體測試界的前輩,像是Google的段念,IBM的陳雅麗等。詳細誰講了什麼,我記不清了。但是裡面有前輩提到做軟體測試的人<strong>很容易忘了讓自己持續的進步,而漸漸地失去競爭力</strong>。這也難怪,因為做軟體測試畢竟永遠不是公司內最核心的研發主力,普遍來說技術水平比開發人員要求來得低一些。</p>
<p>之前讀到一篇<a href="http://www.satisfice.com/blog/">James Bach</a>老兄的<a href="http://www.satisfice.com/blog/archives/764">文章</a>,覺得還不錯。James Bach是軟體測試界的名人,他最著名的就是在<a href="http://en.wikipedia.org/wiki/Exploratory_testing">Exploratory Testing</a>的貢獻。有一位軟體測試的菜鳥問他說軟體測試工作者的每日家庭作業是什麼。Bach提出了四點:</p>
<h2>Write every day</h2>
<p>隨身帶筆記本,隨時記下任何對測試的想法</p>
<h2>Watch yourself think ever day</h2>
<p>工作時,當有任何測試的點子,嘗試去追蹤自己的想法。這是一種訓練<a href="http://en.wikipedia.org/wiki/Introspection">Self-observation</a>的方法</p>
<h2>Question something about how you work every day</h2>
<p>問問題,例如:何時需要寫下一個測試,那些步驟需要被記下。而不是只討論那些案例"Passing"或是"Failing"</p>
<h2>Explain testing every day</h2>
<p>解釋測試方法(Methodology),不要只說自己在做黑箱測試,更深入些,並解釋為什麼你去做?</p>使用Trello心得2012-06-12T23:32:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-06-12:/trello/<p>Trello,是一個小團隊任務管理的工具。關於Trello的使用方法,這此就不再多言了,Google一下都可以找到不少介紹,這篇主要是想記錄一下,我親身使用Trello之後觀察到的一些小心得。</p>
<h2>資訊可以快速在成員之間流通</h2>
<p>我能在一個畫面就知道目前Project的最新狀態,相較於使用Email溝通,我能比較自由的方式去更新我目前的狀態,也不用太擔心訊息是否會干擾其它成員。</p>
<h2>有助於形成 Self Organizing Team</h2>
<p>工作的指派可不可以自己決定?在Trello中,我們會希望答案是Yes。傳統工作模式中,可能就是每週一次的指派任務、回報進度。大家都是各做各的。等到一個星期之後,再彼此更新自己的Status。但是在Trello中,我們可以在"一個畫面"就可以知道目前團隊成員正在做什麼,還沒完成什麼。所以當我完成手頭的工作,尋找下一個工作,也許就可以是別人還沒完成的工作。整個氣氛就會變成整個團隊努力把ToDo List中的工作一步一步搬到 Done List中。</p>
<h2>快速完成一小步的成就感</h2>
<p>在使用Trello中,每一張Card的描述應該要被常常更新。如果這個Card任務太大,那我們就應該適時的把它拆解成幾個比較小的Card。當一個人Own了一個Task,好幾天都不動的時侯,我們就會應該讓它活絡一下。使用Trello的一個大好處就是我可以很容易感受到每一天的小小進步,這樣工作會比較有趣。</p>
<h2>有趣其它用法</h2>
<ol>
<li>我們會在上午開一張Card來訂下午茶,回收率很快。</li>
<li>開一個Card來當聊天室或是宣佈一些小事情,Trello的系統設計的很好,Response Time 也讓大家感到驚奇。</li>
</ol>
<h3>三個月之後的更新 2012/8</h3>
<p>我發現團隊不少人都己經常態使用Trello,甚至是自己私人的規劃,像是出國玩,搬家等等。可見Trello系統的魅力。</p>測試案例如何區分 RAT, FAST, TOFT ?2012-05-08T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-05-08:/testcase-categorization/<p>我相信更了解測試案例的分類,可以加速測試案例的設計與開發,並且讓開發人員對於測試目標能更了解。一般而言,測試案例種類至少可分成以下幾種:</p>
<ul>
<li>Release Acceptance Test(RAT)</li>
<li>Functional Acceptance Simple Test(FAST)</li>
<li>Task-Oriented Function Test(TOFT)</li>
<li>Force-Error Test(FET)</li>
<li>Boundary Test</li>
<li>Volume Test</li>
<li>Stress Test</li>
</ul>
<p>之前在學著開測試案例的時侯,前輩有教過各種測試案例種類的差別。網路上也有一些文章<a href="http://roddick.pixnet.net/blog/post/23136052-rat,fast,toft,fet">討論</a>。最容易讓人分不清大概就是RAT和FAST的差別了。RAT跟FAST都是Acceptance Test。就字面上的意思的確讓人很容易分不清。對我而言,其實測試案例就分成兩類,一種是測正常軟體正向的Test case,或是測試Error handle的FET兩種。然後測Positive Test Case 又依照不同的屬性又可以分成 RAT、FAST、TOFT、Boundary、Volume、Stress。但由於一個軟體建構出來之後。一般而言,皆需通過測試案例的測試,才代表其品質有一定程度的保障。然而,什麼先測,什麼後測?當然是重要的先測。而重要性粗分的話,大概可以分成:</p>
<p><strong>RAT > FAST > TOFT = Boundary = FET > Volume = Stress </strong></p>
<p>RAT是用來評斷這個Build是否能被測試,在某些流程中,如果RAT Test cases Fail的話,QA人員可以要求不要測這個Build,繼續測試之前的Build。因為這個Build存在著重大的Defect,無法進行接下來的測試。所以RAT Testcase理論上數量應該很少,例如安裝的部份就一定至少會有一條RAT,畢竟如果軟體都沒辦法安裝起來的話,接下來就沒辦法測試了。</p>
<p>FAST可視為某個Module最重要的TestCase,如果不能Pass的話,很可能就會影響到接下來TOFT沒辦法繼續測試。所以可以把某個Module當中最重要的幾個Testcase挑出來當成FAST。 TOFT基本上只要不是被拿去當RAT跟FAST的Positive Test Case的剩下就可以當Test Case。FET是故意製造出一些情況讓程式出錯,測Error Handle是否有處理得當的Test Case,這種TestCase通常可以找到不少的Defect,因為畢竟Developer會比較容易忽略一些Error Handle Boundary Test專測一些臨界情況 …</p><p>我相信更了解測試案例的分類,可以加速測試案例的設計與開發,並且讓開發人員對於測試目標能更了解。一般而言,測試案例種類至少可分成以下幾種:</p>
<ul>
<li>Release Acceptance Test(RAT)</li>
<li>Functional Acceptance Simple Test(FAST)</li>
<li>Task-Oriented Function Test(TOFT)</li>
<li>Force-Error Test(FET)</li>
<li>Boundary Test</li>
<li>Volume Test</li>
<li>Stress Test</li>
</ul>
<p>之前在學著開測試案例的時侯,前輩有教過各種測試案例種類的差別。網路上也有一些文章<a href="http://roddick.pixnet.net/blog/post/23136052-rat,fast,toft,fet">討論</a>。最容易讓人分不清大概就是RAT和FAST的差別了。RAT跟FAST都是Acceptance Test。就字面上的意思的確讓人很容易分不清。對我而言,其實測試案例就分成兩類,一種是測正常軟體正向的Test case,或是測試Error handle的FET兩種。然後測Positive Test Case 又依照不同的屬性又可以分成 RAT、FAST、TOFT、Boundary、Volume、Stress。但由於一個軟體建構出來之後。一般而言,皆需通過測試案例的測試,才代表其品質有一定程度的保障。然而,什麼先測,什麼後測?當然是重要的先測。而重要性粗分的話,大概可以分成:</p>
<p><strong>RAT > FAST > TOFT = Boundary = FET > Volume = Stress </strong></p>
<p>RAT是用來評斷這個Build是否能被測試,在某些流程中,如果RAT Test cases Fail的話,QA人員可以要求不要測這個Build,繼續測試之前的Build。因為這個Build存在著重大的Defect,無法進行接下來的測試。所以RAT Testcase理論上數量應該很少,例如安裝的部份就一定至少會有一條RAT,畢竟如果軟體都沒辦法安裝起來的話,接下來就沒辦法測試了。</p>
<p>FAST可視為某個Module最重要的TestCase,如果不能Pass的話,很可能就會影響到接下來TOFT沒辦法繼續測試。所以可以把某個Module當中最重要的幾個Testcase挑出來當成FAST。 TOFT基本上只要不是被拿去當RAT跟FAST的Positive Test Case的剩下就可以當Test Case。FET是故意製造出一些情況讓程式出錯,測Error Handle是否有處理得當的Test Case,這種TestCase通常可以找到不少的Defect,因為畢竟Developer會比較容易忽略一些Error Handle Boundary Test專測一些臨界情況,像是變數的最大值跟最小值,然後剛好跨越。所以一些Boundary 有些也是會測到Error Handle的情況。Volume Test、Stress Test 則就不屬於 Functional Testing。</p>Trello : 適合小型軟體開發團隊的工作清單系統2012-05-08T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-05-08:/trello-list-agile-scrum/<p>Trello : <a href="https://trello.com/">https://trello.com/</a></p>
<p>看公司某些Team在實行 Scrum,別的不敢說,學得最像的一定是這種上面貼滿,地下也掉滿的便利貼 Task board:</p>
<p><a href="http://www.infoq.com/resource/articles/agile-kanban-boards/en/resources/Fig1_task-board.jpg"><img alt="img" src="http://www.infoq.com/resource/articles/agile-kanban-boards/en/resources/Fig1_task-board.jpg" title="kanban-boards"></a></p>
<p>Trello就是類似這種清單系統的線上網站。我覺得 Trello 令人驚奇的點就是他可以讓團隊的每一個人可以專注在自己的任務上,也可以同時知道團隊其它人的狀態。Trello UI設計的很簡單,使用上很流暢。讓我一用就決定在日常工作試用看看,並且也說服我的同事們一起使用。</p>
<p><a href="http://cache.lifehacker.com/assets/images/17/2011/09/trello-4.jpg"><img alt="img" src="http://cache.lifehacker.com/assets/images/17/2011/09/trello-4.jpg"></a></p>
<p>Task Board 適用在短時間的任務清單管理上。因為在每一個Scrum中,團隊的任務就是把最左邊的Task努力搬到最右邊,彼此可以互相幫助。如果每個Task分的很細的話,上面也放不了多少Task。所以當達到 MileStone的時侯,就需要適時的 Reset,喘口氣,可以繼續衝下個回合。</p>Jenkins 在不同的 Jobs 傳遞參數2012-04-12T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-04-12:/jenkins-pass-parameter/<p>需求:想讓 Job B 能拿到 Job A 的 Build Number。</p>
<p>在 Jenkins 中每一個Job都有環境變數,可以存取一些像是當下目錄,Build Number 等資訊。但是如果想要存取別的Job的環境變數就要多做一些事情了。</p>
<ol>
<li>
<p>安裝 <a href="https://wiki.jenkins-ci.org/display/JENKINS/EnvInject+Plugin">EnvInject plugin</a></p>
</li>
<li>
<p>在 Job A 新增一個 Build Step,記錄 Build Number 到 properties file</p>
<p>echo "JOBA_BUILD=$BUILD_NUMBER" > build.properties</p>
</li>
<li>
<p>在 Job B 的 Configuration 中</p>
</li>
</ol>
<p>Build Environment > Inject environment variables to the build process
設定剛才的 Properties File Path,
例如 /var/lib/jenkins/jobs/JobB/workspace/build.properties</p>
<p>因為 Step 3 的關係,我們在Job執行過程中可以直接使用 $JOBA_BUILD 來拿到 Job A 的變數。</p>[Python] Class Private 跟 Module Private 的差別2012-03-31T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-03-31:/python-class-private-module-private-different/<p>在Python中雖然有Private variable,但是不像一般程式語言一樣具有強制的效力,如果外界執意要使用還是可以呼叫的到。在<a href="http://stackoverflow.com/questions/1547145/defining-private-module-functions-in-python">這篇</a>StackOverflow有很清楚的解釋其中的差別。</p>
<ul>
<li>
<p><strong>Module private</strong> 是指是以一個下底線 <strong>_</strong> 開頭的變數,例如<strong> _number 或 _getNumber() </strong></p>
</li>
<li>
<p><strong>Class Private </strong>基本上是以二個下底線 __ 開頭,而且不超過一個下底線 _ 結尾的的變數名稱,例如 <strong>__number 或 __getNumber()</strong>,但是<strong><strong>init</strong> </strong>就不是 class private,但這種兩個下底線開頭和結尾叫<a href="http://farmdev.com/src/secrets/magicmethod/index.html"> Magic methods</a>有其特別的用途,但這個不在本文討論範圍。</p>
</li>
</ul>
<h3><strong>Module Private</strong></h3>
<div class="highlight"><pre><span></span><code><span class="c1"># moduleA.py</span>
<span class="k">def</span> <span class="nf">_foo</span><span class="p">():</span>
<span class="k">return</span> <span class="s1">'hi'</span>
<span class="kn">from</span> <span class="nn">moduleA</span> <span class="kn">import</span> <span class="o">*</span>
<span class="nb">print</span> <span class="n">_foo</span><span class="p">()</span>
</code></pre></div>
<p>以此例子來說,我們在 moduleA.py裡面定義了一個 Module private _foo(),因為Python有個規定是在Import的時侯會略過所有以underscore開頭的成員,所以_foo()會被忽略,在執行 print _foo() 的時侯就會發生 Exception:</p>
<div class="highlight"><pre><span></span><code>Traceback (most recent call last):
File "D:\priavte\__init__.py", line 4, in <module>
NameError: name '_foo' is not defined
</code></pre></div>
<p>但是如果執意要用還是可以透過Import __foo,得到想要的結果</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">moduleA</span> <span class="kn">import</span> <span class="n">_foo</span>
<span class="nb">print</span> <span class="n">_foo</span><span class="p">()</span>
</code></pre></div>
<h3>Class Private</h3>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="n">Foo</span>():
<span class="n">__aoo …</span></code></pre></div><p>在Python中雖然有Private variable,但是不像一般程式語言一樣具有強制的效力,如果外界執意要使用還是可以呼叫的到。在<a href="http://stackoverflow.com/questions/1547145/defining-private-module-functions-in-python">這篇</a>StackOverflow有很清楚的解釋其中的差別。</p>
<ul>
<li>
<p><strong>Module private</strong> 是指是以一個下底線 <strong>_</strong> 開頭的變數,例如<strong> _number 或 _getNumber() </strong></p>
</li>
<li>
<p><strong>Class Private </strong>基本上是以二個下底線 __ 開頭,而且不超過一個下底線 _ 結尾的的變數名稱,例如 <strong>__number 或 __getNumber()</strong>,但是<strong><strong>init</strong> </strong>就不是 class private,但這種兩個下底線開頭和結尾叫<a href="http://farmdev.com/src/secrets/magicmethod/index.html"> Magic methods</a>有其特別的用途,但這個不在本文討論範圍。</p>
</li>
</ul>
<h3><strong>Module Private</strong></h3>
<div class="highlight"><pre><span></span><code><span class="c1"># moduleA.py</span>
<span class="k">def</span> <span class="nf">_foo</span><span class="p">():</span>
<span class="k">return</span> <span class="s1">'hi'</span>
<span class="kn">from</span> <span class="nn">moduleA</span> <span class="kn">import</span> <span class="o">*</span>
<span class="nb">print</span> <span class="n">_foo</span><span class="p">()</span>
</code></pre></div>
<p>以此例子來說,我們在 moduleA.py裡面定義了一個 Module private _foo(),因為Python有個規定是在Import的時侯會略過所有以underscore開頭的成員,所以_foo()會被忽略,在執行 print _foo() 的時侯就會發生 Exception:</p>
<div class="highlight"><pre><span></span><code>Traceback (most recent call last):
File "D:\priavte\__init__.py", line 4, in <module>
NameError: name '_foo' is not defined
</code></pre></div>
<p>但是如果執意要用還是可以透過Import __foo,得到想要的結果</p>
<div class="highlight"><pre><span></span><code><span class="kn">from</span> <span class="nn">moduleA</span> <span class="kn">import</span> <span class="n">_foo</span>
<span class="nb">print</span> <span class="n">_foo</span><span class="p">()</span>
</code></pre></div>
<h3>Class Private</h3>
<div class="highlight"><pre><span></span><code><span class="k">class</span> <span class="n">Foo</span>():
<span class="n">__aoo</span> = <span class="mi">123</span>
<span class="n">def</span> <span class="n">__boo</span>(<span class="nb">self</span>):
<span class="k">return</span> <span class="mi">123</span>
<span class="n">def</span> <span class="n">coo</span>(<span class="nb">self</span>):
<span class="k">return</span> <span class="mi">456</span>
<span class="nb">f</span> = <span class="n">Foo</span>()
<span class="nb">print</span> <span class="nb">dir</span>(<span class="nb">f</span>)
<span class="nb">print</span> <span class="nb">f</span>.<span class="n">_Foo__boo</span>()
<span class="nb">print</span> <span class="nb">f</span>.<span class="n">__boo</span>()
</code></pre></div>
<p>可以觀察一下這三個 print 執行的結果,會發現 dir(f)是輸出:
<code>> ['_Foo__aoo', '_Foo__boo', '__doc__', '__module__', 'coo']</code>
_boo被加上_Foo_的Prefix,這種行為稱做 <a href="http://en.wikipedia.org/wiki/Name_mangling#Name_mangling_in_Python">Name Mangling</a>,多加上Class Name在前面。所以透過 f.__boo()就沒辦法直接呼叫,但是透過加上Class Name的Prefix就可以了,例如 print f._Foo__boo()</p>
<h3>總結</h3>
<h5>Module private : _number</h5>
<ol>
<li>達到 Private 的效果:Import 除非明確把 name 打出來,不然 from A import * 時會自動略過所有以一個下底線 _ 開頭的變數</li>
<li>使用時機:在 Module level 下,告知外界,這些變數/函式是Private性質的,不建議外界直接存取</li>
<li>強制使用方式: 直接Import即可,例如: from A import _Number</li>
</ol>
<h5>Class Private : __number</h5>
<ol>
<li>達到 Private 的效果:Class 物件被建立的時侯,所有 __XXX 會被 name mangling成 __ClassName__XXX</li>
<li>使用時機:跟 Module private 一樣,就是表現出這些成員是內部使用的,不建議外界直接存取</li>
<li>強制使用方式: 使用的時侯,加上 Class name 的的 prefix</li>
<li>繼承的時侯,這些被 name mangled 的成員也會被繼承,但是是使用Parent的ClassName的Prefix,要注意一下。
在Python的世界中,Private Variable沒辦法強制讓外界無法使用,透過Naming可以讓別人知道這些Private Variable不應該直接被存取,避免誤用的Bug發生。但是如果執意要呼叫,都還是有方法的。</li>
</ol>Thinkpad X220 擴充記錄2012-03-31T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-03-31:/thinkpad-x220-extension/<p>記錄一下目前跟小黑相關的敗家購買清單: <strong>X220 i5-2410M 美規機 (42872VU) </strong>
1. 為了用桌機也可以跟ThinkPad有一樣的鍵盤體驗:ThinkPad USB Keyboard with TrackPoint
<img alt="img" src="http://i.imgur.com/9GEAk9Cl.jpg"></p>
<ol>
<li>為了Total 8GB的RAM:原廠記憶體 PC-10600 4GB
為了有SSD+HDD雙硬碟:Intel 310 Series 80GB mSATA SSD
<img alt="img" src="http://www.ssdreview.com/media/cache/ssd_datasheet_preview/ssd/photo/intel-310-series-80gb-msata/3d_front.jpg"></li>
</ol>
<p>為了上班可以不用帶變壓器:90W 20V變壓器</p>
<p>為了IPS面板:<a href="http://blog.codylab.com/thinkpad-x220-ips/" title="ThinkPad X220 TN 面板換 IPS 面板過程分享"> IPS 面版 (LP125WH2 SLB1)</a></p>
<p>為了同時外接兩台VGA螢幕:<a href="https://ecvip.pchome.com.tw/?0x4672bd249f582b834ea7f527f7eee545fd17cf935d9452e99de998b6a6b1a4e1aee6a40a425bc200fe606ef58edc51c64464639293ba4824d4a8de56eae1f34d00f9a8b2e858c64fa05e0f613e53af861efd6181707ffd99">VGA to Display 轉接線</a></p>
<p>為了用新的小紅盤Track Point <a href="http://goods.ruten.com.tw/item/show?21104126127984">小紅盤</a></p>
<p>為了可以隨時馬上敗家刺激經濟:[讀卡機 SCM SCR3340 Express Card 54]</p>
<p>直衝16GB :單條 8GB 的RAM * 2 <a href="http://littlenine1221.pixnet.net/blog/post/83986050">Link</a></p>Django 修改 Model 之後要如何更新到 Database2012-03-29T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-03-29:/django-update-model/<p>Django 如果 Model裡面的欄位有更動時,即使執行</p>
<div class="highlight"><pre><span></span><code>$ python manage syncdb
</code></pre></div>
<p>是不會更動已經存在的 database 的 Table。 </p>
<p>在這<a href="http://stackoverflow.com/questions/1985383/update-django-database-to-reflect-changes-in-existing-models">StackOverflow</a>討論串有提到像是用 <a href="http://south.aeracode.org/">South</a>等Migration Tool,但如果Model只是新增一些Optional的欄位時,這真的是用牛刀了。裡面有提到另一個方法,我覺得還不錯簡單,在此記錄一下:</p>
<p>先用 <code>dumpdata</code> 這個指令把DB的資料先輸出成 .json 的格式。要注意的事,這時侯 model.py 必需是舊的 schema</p>
<div class="highlight"><pre><span></span><code>$ python manage.py dumpdata <APP_NAME> >> /tmp/old_data.json
</code></pre></div>
<p>然後先把資料清掉</p>
<div class="highlight"><pre><span></span><code>$ python manage.py sqlclear <APP_NAME> <span class="p">|</span> python manage.py dbshell
</code></pre></div>
<p>此時就可以修改 models.py 修改欄位,執行 syncdb</p>
<div class="highlight"><pre><span></span><code>$ python manage.py syncdb
</code></pre></div>
<p>最後再把 json 格式的 data 載入回來即可</p>
<div class="highlight"><pre><span></span><code><span class="o">$</span> <span class="n">python</span> <span class="n">manage</span><span class="o">.</span><span class="n">py</span> <span class="n">loaddata</span> <span class="n">temp_data</span><span class="o">.</span><span class="n">json</span>
</code></pre></div>Process handle is invalid in Python2012-03-22T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-03-22:/python-handle-is-invalid/<h3>Error</h3>
<div class="highlight"><pre><span></span><code><span class="nv">Tool</span>.<span class="nv">py</span><span class="s2">"</span><span class="s">, line 97, in __funcExecCmd</span>
<span class="nv">intResult</span> <span class="o">=</span> <span class="nv">subprocess</span>.<span class="nv">call</span><span class="ss">(</span><span class="nv">strCmd</span>, <span class="nv">stdout</span><span class="o">=</span><span class="nv">output</span>, <span class="nv">stderr</span><span class="o">=</span><span class="nv">output</span><span class="ss">)</span>
<span class="nv">File</span> <span class="s2">"</span><span class="s">C:\Python26\lib\subprocess.py</span><span class="s2">"</span>, <span class="nv">line</span> <span class="mi">470</span>, <span class="nv">in</span> <span class="nv">call</span>
<span class="k">return</span> <span class="nv">Popen</span><span class="ss">(</span><span class="o">*</span><span class="nv">popenargs</span>, <span class="o">**</span><span class="nv">kwargs</span><span class="ss">)</span>.<span class="k">wait</span><span class="ss">()</span>
<span class="nv">File</span> <span class="s2">"</span><span class="s">C:\Python26\lib\subprocess.py</span><span class="s2">"</span>, <span class="nv">line</span> <span class="mi">616</span>, <span class="nv">in</span> <span class="nv">__init__</span>
<span class="nv">errread</span>, <span class="nv">errwrite</span><span class="ss">)</span> <span class="o">=</span> <span class="nv">self</span>.<span class="nv">_get_handles</span><span class="ss">(</span><span class="nv">stdin</span>, <span class="nv">stdout</span>, <span class="nv">stderr</span><span class="ss">)</span>
<span class="nv">File</span> <span class="s2">"</span><span class="s">C:\Python26\lib\subprocess.py</span><span class="s2">"</span>, <span class="nv">line</span> <span class="mi">724</span>, <span class="nv">in</span> <span class="nv">_get_handles</span>
<span class="nv">p2cread</span> <span class="o">=</span> <span class="nv">self</span>.<span class="nv">_make_inheritable</span><span class="ss">(</span><span class="nv">p2cread</span><span class="ss">)</span>
<span class="nv">File</span> <span class="s2">"</span><span class="s">C:\Python26\lib\subprocess.py</span><span class="s2">"</span>, <span class="nv">line</span> <span class="mi">763</span>, <span class="nv">in</span> <span class="nv">_make_inheritable</span>
<span class="nv">_subprocess</span>.<span class="nv">DUPLICATE_SAME_ACCESS</span><span class="ss">)</span>
<span class="nv">WindowsError</span>: [<span class="nv">Error</span> <span class="mi">6</span>] <span class="nv">The</span> <span class="nv">handle</span> <span class="nv">is</span> <span class="nv">invalid</span>
</code></pre></div>
<h3>Solution</h3>
<p>Add <code>stdin = subprocess.PIPE</code> in <code>subprocess.call()</code></p>Python 多種 Print 函式的用法2012-03-16T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-03-16:/python-print-usage/<p>最簡單的用法:把想Print的內容放在 print 後面</p>
<div class="highlight"><pre><span></span><code>print 'Hello'
</code></pre></div>
<p>輸出結果</p>
<div class="highlight"><pre><span></span><code>Hello
</code></pre></div>
<p>另一個方便的用法,可以把不同資料型態的變數不經過轉型就直接一起print出來:</p>
<div class="highlight"><pre><span></span><code>print 'Hello',2012
</code></pre></div>
<p>也就是可以省下把其它變數都轉成string的麻煩</p>
<p>輸出結果</p>
<div class="highlight"><pre><span></span><code>Hello 2012
</code></pre></div>
<p>想把多個 print 合併在同一行輸出,而不要一個print就斷行一次,就在最後面加上一個逗號: </p>
<div class="highlight"><pre><span></span><code>print 'Execution Result:',
print runSomeThing()
</code></pre></div>
<p>輸出結果:</p>
<div class="highlight"><pre><span></span><code>Execution Result: PASS
</code></pre></div>
<p>另外低階的sys.stdout.write在特定需求也可以使用,比如說我想輸出兩個字串,但是中間不要像 print 函式一樣加一個空白的話,就可以使用這個方法:</p>
<div class="highlight"><pre><span></span><code><span class="kn">import</span> <span class="nn">sys</span>
<span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">"Hello"</span><span class="p">)</span>
<span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="s2">"2012"</span><span class="p">)</span>
</code></pre></div>
<p>輸出結果:</p>
<div class="highlight"><pre><span></span><code>Hello2012
</code></pre></div>Notepad++ 縮排從Tab改成4個Space2012-03-15T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-03-15:/notepad_tab_to_space/<p>用 Notepad++ 開 Python 的 .py 檔案預設是用 tab 來當縮排符號的,與一般程式語言常使用的 space 空白縮排慣例不同。可以從</p>
<div class="highlight"><pre><span></span><code>Settings > Preferences > Language Menu / Tab Settings
</code></pre></div>
<p>調整,把 <code>Replace by space</code> 打勾即可</p>ThinkPad X220 TN 面板換 IPS 面板過程分享2012-02-04T00:00:00+08:002017-05-15T15:48:44+08:00Cody Liutag:blog.codylab.com,2012-02-04:/thinkpad-x220-ips/<p>這個面板是在淘寶買的,賣家是評價最好的那家,現在的價格是 368 RMB含郵寄到台灣,算一算兩千台票有找。寄送過程大概耗時兩天。星期日中午下定,星期二早上就收到了。</p>
<p>第一次買淘寶,是用順豐速運寄的。</p>
<div style="text-align: center;">[![img](http://1.bp.blogspot.com/-DRddqsrZpQ4/Tyz8-9TR5JI/AAAAAAAAKJA/nqxGR9dxreU/s640/IMGP6985.JPG)](http://1.bp.blogspot.com/-DRddqsrZpQ4/Tyz8-9TR5JI/AAAAAAAAKJA/nqxGR9dxreU/s1600/IMGP6985.JPG)</div>
<p>裡面就是層層的保麗龍包裹著,看起來保護還不錯。</p>
<!--more-->
<p><a href="http://2.bp.blogspot.com/-kMLvC9eTwxs/Tyz9AlEiQKI/AAAAAAAAKJI/Uz90iAd-iwo/s1600/IMGP6988.JPG"><img alt="img" src="http://2.bp.blogspot.com/-kMLvC9eTwxs/Tyz9AlEiQKI/AAAAAAAAKJI/Uz90iAd-iwo/s640/IMGP6988.JPG"></a></p>
<p><a href="http://4.bp.blogspot.com/-bz8IrGBVxws/Tyz9CCz4emI/AAAAAAAAKJQ/6OCEnRhy1Qk/s1600/IMGP6989.JPG"><img alt="img" src="http://4.bp.blogspot.com/-bz8IrGBVxws/Tyz9CCz4emI/AAAAAAAAKJQ/6OCEnRhy1Qk/s640/IMGP6989.JPG"></a></p>
<p>IPS 跟 收據合照</p>
<p>接下來就是拆解的過程了,首先當然是要先把電源、電池缷下,螢幕的左右兩角各有一個正方形的塑膠片,要先拿下來</p>
<p><a href="http://2.bp.blogspot.com/-BXaKFSi9198/Tyz9EscXzZI/AAAAAAAAKJY/7w0i9iLkXTs/s1600/IMGP7008.JPG"><img alt="img" src="http://2.bp.blogspot.com/-BXaKFSi9198/Tyz9EscXzZI/AAAAAAAAKJY/7w0i9iLkXTs/s640/IMGP7008.JPG"></a></p>
<p>我是用縫衣針從隙縫塞入,就可以很輕易的把塑膠片挑起,裡面就是兩個螺絲用來固定邊框的。把兩個螺絲都拆下來之後,接下來就可以開始拆螢幕的邊框了</p>
<p><a href="http://3.bp.blogspot.com/-StAYn7ei6LE/Tyz9HbewmkI/AAAAAAAAKJg/kbKQvB8xk48/s1600/IMGP7009.JPG"><img alt="img" src="http://3.bp.blogspot.com/-StAYn7ei6LE/Tyz9HbewmkI/AAAAAAAAKJg/kbKQvB8xk48/s640/IMGP7009.JPG"></a></p>
<p>我是用小號的一字起子,先從螺絲拆解處的小細縫,慢慢把細縫撐開,沿著邊緣一點一點弄。感覺這邊還蠻脆弱的,要小心弄,以免邊框斷掉。</p>
<p><a href="http://1.bp.blogspot.com/-Dmg9_InPsII/Tyz9Ieh_uvI/AAAAAAAAKJo/2OAuOOTIfX4/s1600/IMGP7010.JPG"><img alt="img" src="http://1.bp.blogspot.com/-Dmg9_InPsII/Tyz9Ieh_uvI/AAAAAAAAKJo/2OAuOOTIfX4/s640/IMGP7010.JPG"></a></p>
<p><a href="http://4.bp.blogspot.com/-T5b22xKYXSE/Tyz9Jr1DCaI/AAAAAAAAKJw/-XgW1uh_Blc/s1600/IMGP7011.JPG"><img alt="img" src="http://4.bp.blogspot.com/-T5b22xKYXSE/Tyz9Jr1DCaI/AAAAAAAAKJw/-XgW1uh_Blc/s640/IMGP7011.JPG"></a></p>
<p>弄過一圈之後就可以順利把邊框整個拆起來,舊的TN面板上面有四個螺絲,直接卸下</p>
<p><a href="http://1.bp.blogspot.com/-isG2alDjGTE/Tyz9L_mnz1I/AAAAAAAAKJ4/-lO6_jfT3g8/s1600/IMGP7013.JPG"><img alt="img" src="http://1.bp.blogspot.com/-isG2alDjGTE/Tyz9L_mnz1I/AAAAAAAAKJ4/-lO6_jfT3g8/s640/IMGP7013.JPG"></a></p>
<p><a href="http://4.bp.blogspot.com/-L8Xj2vm03P8/Tyz9Odm38pI/AAAAAAAAKKI/AeCX9QmBmgU/s1600/IMGP7018.JPG"><img alt="img" src="http://4.bp.blogspot.com/-L8Xj2vm03P8/Tyz9Odm38pI/AAAAAAAAKKI/AeCX9QmBmgU/s640/IMGP7018.JPG"></a></p>
<p>此時面板就只剩下排線連接的部份了,排線上面有一個塑膠貼片,先撕起來,然後小心把排線分離。</p>
<p><a href="http://2.bp.blogspot.com/-XRI1rztXWrI/Tyz9NB6Ku5I/AAAAAAAAKKA/1YwG4irr4e8/s1600/IMGP7015.JPG"><img alt="img" src="http://2.bp.blogspot.com/-XRI1rztXWrI/Tyz9NB6Ku5I/AAAAAAAAKKA/1YwG4irr4e8/s640/IMGP7015.JPG"></a></p>
<p>要注意,著力點要放在金屬排扣的部份,不要硬扯排線,應很容易可以把面板完全拆離主機。</p>
<p>然後就可以把新的 IPS 面板裝上,插排線,鎖四個螺絲,壓上黑色塑膠邊框,再鎖上螢幕左右兩角的螺絲,貼回正方形的兩個膠片, 完工!!過程順利的話,新手應該半小時內可以完成,換上IPS的感覺就是開心,這個面板的品質還算不錯,沒有白斑,亮暗點,只是要特別注意的是:</p>
<ol>
<li>
<p>螢幕全黑時下方有小小漏光,不影響使用,跟我的iPad情況一樣。</p>
</li>
<li>
<p>色調偏黃,網路上有校色文檔可以使用,但是我是覺得還好,看一下就習慣了</p>
</li>
<li>
<p>此款的IPS型號是 LP125WH2 SLB1,想要買來換可以用這個Keyword search。</p>
</li>
</ol>
<p> </p>
<p>參考資料:</p>
<ul>
<li>" 想完美取出垫片就先用吹风筒热吹,然后用针挑出来 …</li></ul><p>這個面板是在淘寶買的,賣家是評價最好的那家,現在的價格是 368 RMB含郵寄到台灣,算一算兩千台票有找。寄送過程大概耗時兩天。星期日中午下定,星期二早上就收到了。</p>
<p>第一次買淘寶,是用順豐速運寄的。</p>
<div style="text-align: center;">[![img](http://1.bp.blogspot.com/-DRddqsrZpQ4/Tyz8-9TR5JI/AAAAAAAAKJA/nqxGR9dxreU/s640/IMGP6985.JPG)](http://1.bp.blogspot.com/-DRddqsrZpQ4/Tyz8-9TR5JI/AAAAAAAAKJA/nqxGR9dxreU/s1600/IMGP6985.JPG)</div>
<p>裡面就是層層的保麗龍包裹著,看起來保護還不錯。</p>
<!--more-->
<p><a href="http://2.bp.blogspot.com/-kMLvC9eTwxs/Tyz9AlEiQKI/AAAAAAAAKJI/Uz90iAd-iwo/s1600/IMGP6988.JPG"><img alt="img" src="http://2.bp.blogspot.com/-kMLvC9eTwxs/Tyz9AlEiQKI/AAAAAAAAKJI/Uz90iAd-iwo/s640/IMGP6988.JPG"></a></p>
<p><a href="http://4.bp.blogspot.com/-bz8IrGBVxws/Tyz9CCz4emI/AAAAAAAAKJQ/6OCEnRhy1Qk/s1600/IMGP6989.JPG"><img alt="img" src="http://4.bp.blogspot.com/-bz8IrGBVxws/Tyz9CCz4emI/AAAAAAAAKJQ/6OCEnRhy1Qk/s640/IMGP6989.JPG"></a></p>
<p>IPS 跟 收據合照</p>
<p>接下來就是拆解的過程了,首先當然是要先把電源、電池缷下,螢幕的左右兩角各有一個正方形的塑膠片,要先拿下來</p>
<p><a href="http://2.bp.blogspot.com/-BXaKFSi9198/Tyz9EscXzZI/AAAAAAAAKJY/7w0i9iLkXTs/s1600/IMGP7008.JPG"><img alt="img" src="http://2.bp.blogspot.com/-BXaKFSi9198/Tyz9EscXzZI/AAAAAAAAKJY/7w0i9iLkXTs/s640/IMGP7008.JPG"></a></p>
<p>我是用縫衣針從隙縫塞入,就可以很輕易的把塑膠片挑起,裡面就是兩個螺絲用來固定邊框的。把兩個螺絲都拆下來之後,接下來就可以開始拆螢幕的邊框了</p>
<p><a href="http://3.bp.blogspot.com/-StAYn7ei6LE/Tyz9HbewmkI/AAAAAAAAKJg/kbKQvB8xk48/s1600/IMGP7009.JPG"><img alt="img" src="http://3.bp.blogspot.com/-StAYn7ei6LE/Tyz9HbewmkI/AAAAAAAAKJg/kbKQvB8xk48/s640/IMGP7009.JPG"></a></p>
<p>我是用小號的一字起子,先從螺絲拆解處的小細縫,慢慢把細縫撐開,沿著邊緣一點一點弄。感覺這邊還蠻脆弱的,要小心弄,以免邊框斷掉。</p>
<p><a href="http://1.bp.blogspot.com/-Dmg9_InPsII/Tyz9Ieh_uvI/AAAAAAAAKJo/2OAuOOTIfX4/s1600/IMGP7010.JPG"><img alt="img" src="http://1.bp.blogspot.com/-Dmg9_InPsII/Tyz9Ieh_uvI/AAAAAAAAKJo/2OAuOOTIfX4/s640/IMGP7010.JPG"></a></p>
<p><a href="http://4.bp.blogspot.com/-T5b22xKYXSE/Tyz9Jr1DCaI/AAAAAAAAKJw/-XgW1uh_Blc/s1600/IMGP7011.JPG"><img alt="img" src="http://4.bp.blogspot.com/-T5b22xKYXSE/Tyz9Jr1DCaI/AAAAAAAAKJw/-XgW1uh_Blc/s640/IMGP7011.JPG"></a></p>
<p>弄過一圈之後就可以順利把邊框整個拆起來,舊的TN面板上面有四個螺絲,直接卸下</p>
<p><a href="http://1.bp.blogspot.com/-isG2alDjGTE/Tyz9L_mnz1I/AAAAAAAAKJ4/-lO6_jfT3g8/s1600/IMGP7013.JPG"><img alt="img" src="http://1.bp.blogspot.com/-isG2alDjGTE/Tyz9L_mnz1I/AAAAAAAAKJ4/-lO6_jfT3g8/s640/IMGP7013.JPG"></a></p>
<p><a href="http://4.bp.blogspot.com/-L8Xj2vm03P8/Tyz9Odm38pI/AAAAAAAAKKI/AeCX9QmBmgU/s1600/IMGP7018.JPG"><img alt="img" src="http://4.bp.blogspot.com/-L8Xj2vm03P8/Tyz9Odm38pI/AAAAAAAAKKI/AeCX9QmBmgU/s640/IMGP7018.JPG"></a></p>
<p>此時面板就只剩下排線連接的部份了,排線上面有一個塑膠貼片,先撕起來,然後小心把排線分離。</p>
<p><a href="http://2.bp.blogspot.com/-XRI1rztXWrI/Tyz9NB6Ku5I/AAAAAAAAKKA/1YwG4irr4e8/s1600/IMGP7015.JPG"><img alt="img" src="http://2.bp.blogspot.com/-XRI1rztXWrI/Tyz9NB6Ku5I/AAAAAAAAKKA/1YwG4irr4e8/s640/IMGP7015.JPG"></a></p>
<p>要注意,著力點要放在金屬排扣的部份,不要硬扯排線,應很容易可以把面板完全拆離主機。</p>
<p>然後就可以把新的 IPS 面板裝上,插排線,鎖四個螺絲,壓上黑色塑膠邊框,再鎖上螢幕左右兩角的螺絲,貼回正方形的兩個膠片, 完工!!過程順利的話,新手應該半小時內可以完成,換上IPS的感覺就是開心,這個面板的品質還算不錯,沒有白斑,亮暗點,只是要特別注意的是:</p>
<ol>
<li>
<p>螢幕全黑時下方有小小漏光,不影響使用,跟我的iPad情況一樣。</p>
</li>
<li>
<p>色調偏黃,網路上有校色文檔可以使用,但是我是覺得還好,看一下就習慣了</p>
</li>
<li>
<p>此款的IPS型號是 LP125WH2 SLB1,想要買來換可以用這個Keyword search。</p>
</li>
</ol>
<p> </p>
<p>參考資料:</p>
<ul>
<li>" 想完美取出垫片就先用吹风筒热吹,然后用针挑出来" <<a href="http://51nb.chinaidns.com/forum/thread-1124747-1-1.html">http://51nb.chinaidns.com/forum/thread-1124747-1-1.html</a>></li>
<li>" 把排线拔开时切记要在金属卡扣处用力,而不要捏着屏线拔 <a href="http://ideapad.it168.com/thread-1682015-1-1.html">http://ideapad.it168.com/thread-1682015-1-1.html</a></li>
<li>X220 IPS屏幕和非IPS屏对比照片, 包括校色后的对比照片" <<a href="http://www.xynbnb.com/thread-425711-1-1.html">http://www.xynbnb.com/thread-425711-1-1.html</a>></li>
<li>【原创】X220i 42862KC TN>IPS(LP125WH2 SLB1)换屏手记 : <a href="http://goo.gl/9uy9Y">http://goo.gl/9uy9Y</a></li>
</ul>