<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[hSATAC]]></title>
  
  <link href="http://blog.hsatac.net/" />
  <updated>2013-05-19T20:54:10+08:00</updated>
  <id>http://blog.hsatac.net/</id>
  <author>
    <name><![CDATA[hSATAC]]></name>
    
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/hsatac" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="hsatac" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry>
    <title type="html"><![CDATA[TDD Rails]]></title>
    <link href="http://blog.hsatac.net/2013/05/tdd-rails/" />
    <updated>2013-05-19T19:23:00+08:00</updated>
    <id>http://blog.hsatac.net/2013/05/tdd-rails</id>
    <content type="html"><![CDATA[<p>這兩個月到新公司學到了不少東西，對於「寫測試」這件事也有了新的想法。先感謝最近一直和我 pair 的 @ilake，許多觀念和工具都是他帶給我的。</p>

<p>還記得幾年前剛聽到「測試」、「TDD」這些名詞的時候，那時我去 Ruby Tuesday 碰到人就會問一下：「你有在寫測試嗎？」@ihower 跟 @xdite 應該都被我問過這個問題。那時雖然知道寫測試的好處，也大概試過 TDD 的手法，不過總感覺搔不到癢處；再加上那時待的公司也都沒有這個環境，就放置 Play 了。</p>

<p>一直到跟 @ilake pair 過後才知道，問題不在「要不要寫測試」、而是「測試該怎麼寫」。</p>

<!-- more -->


<h3>Why TDD? Why Not?</h3>

<p>我們一般對寫測試和 TDD 會有以下的迷思：</p>

<ul>
<li>TDD 違反人類思考的習慣</li>
<li>寫測試會比較耗時間</li>
<li>沒牽涉到金流等重大功能不需要寫測試</li>
</ul>


<p>先講第一點，<strong>TDD 違反人類思考的習慣？</strong>：其實我們平常寫程式的行為，本來就是寫一點點、然後切過去執行看看、再寫一點點、再切過去執行看看&#8230;&#8230;重複這個循環。</p>

<p>這跟 TDD 的開發模式基本上是一樣的，差別只在於先把想要的結果寫好而已。而且這樣的方式可以強迫你用比較好測試的方式去組織你的程式碼，也就是說你的 code 天生架構就會比較好。</p>

<p><strong>寫測試會比較耗時間嗎？</strong>這邊應該分成整體開發時間和單元開發時間來看。先說整體開發時間，有寫測試可以讓整個 team 都放心改 code ，減低踩雷的機會。與其寫一寫發現之前寫的東西爆炸了再回頭修改，寫測試反而能降低整體開發的時間。</p>

<p>那單元測試時間呢？TDD 寫的 code 比較多，理論上應該會增加單元開發時間，不過只要使用對的工具和 work flow，其實單元開發時間不會增加多少，甚至還有可能更快。開發 Rails 可能寫一寫就要切到瀏覽器看一下行為，但是使用 TDD 我們可以一鍵直接測到我們想測的部份，不用花時間在切換、等待上面。等到整個 feature 開發完成再去瀏覽器做最後確認就好，反而增加了開發效率。</p>

<p><strong>沒牽涉到金流等重大功能不需要寫測試？</strong>：當你享受過 TDD 帶來的好處時其實就不會再有這樣的想法了，不過寫測試的確還有其他的優點。我到 Faria 第一天就能直接上工解 issue 就是因為有測試當我的後盾。測試本身也就是 spec ，能清楚定義你程式的行為。碰到有 bug 的時候就直接寫一個這個 bug 的測試，修到他過了，以後就再也不會碰到那種「咦，這個 bug 不是我以前解過了嗎？怎麼又跑出來了？」的狀況。</p>

<h3>Work Flow</h3>

<p>前面說到只要使用對的工具和 work flow，就能享受到 TDD 的快感。相關的工具和 library 非常多，這邊直接講兩個重點：</p>

<ol>
<li>快速執行測試以及觀看測試結果(一鍵執行)</li>
<li>跑測試本身的速度要快</li>
</ol>


<p>前陣子使用 Sublime Text 2 時，搭配 <a href="https://github.com/maltize/sublime-text-2-ruby-tests">Sublime Text 2 Ruby Tests</a> 這個 plugin，只要按 <code>cmd + shift + r</code> 就可以直接跑當前游標所在測試 <code>cmd + shift + t</code> 跑整個檔案 <code>cmd + shift + e</code> 跑上一次執行的測試。</p>

<p>最近改回 vim 環境則是使用 @ilake 推薦的 <a href="https://github.com/jgdavey/vim-turbux">turbux</a> 和 <a href="https://github.com/jgdavey/tslime.vim">tslime</a> 一樣一鍵執行測試，並送到你選擇的 tmux windows 去執行。詳細的設定可以參考<a href="https://github.com/hSATAC/vimrc">我的 vimrc</a>。</p>

<p>至於跑測試本身的速度要快這點，由於 Rails 環境要 boot 起來其實花的時間真的挺久的，可以使用 <a href="https://github.com/burke/zeus">Zeus</a> 或 <a href="https://github.com/jonleighton/spring">Spring</a> 來加速。</p>

<p>其實以上這兩點都是為了一個目的，就是要「快速拿到你的 feedback」。當你有了這個環境，你寫好測試你就只要一直去 run 他 run 到你的實作通過測試為止。絕對比寫一寫切到瀏覽器看一下來的快速可靠。</p>

<h3>結語</h3>

<p>寫測試的好處真的百百種，說都說不完，而且現在寫測試應該也算是 programmer 的必備技能了。前陣子我發給 <a href="https://github.com/mroth/lolcommits">lolcommits</a> 的 pull request 也被要求補測試才收我的 patch。可預見不遠的將來，甚至是現在，寫測試將會是軟體開發中不可或缺的一個環節。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Diff Puppet Chef]]></title>
    <link href="http://blog.hsatac.net/2013/05/diff-puppet-chef/" />
    <updated>2013-05-14T22:29:00+08:00</updated>
    <id>http://blog.hsatac.net/2013/05/diff-puppet-chef</id>
    <content type="html"><![CDATA[<p>這次和 <a href="https://twitter.com/v1nc3ntlaw">@v1nc3ntlaw </a> 在 Ruby Tuesday 分享的 diff puppet chef 投影片</p>

<script async class="speakerdeck-embed" data-id="2ea36f409ebd01301b2f469a61e096c5" data-ratio="1.33333333333333" src="http://blog.hsatac.net//speakerdeck.com/assets/embed.js"></script>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Migrate AWS AMI across region painlessly]]></title>
    <link href="http://blog.hsatac.net/2013/02/migrate-aws-ami-across-region-painlessly-en/" />
    <updated>2013-02-27T15:45:00+08:00</updated>
    <id>http://blog.hsatac.net/2013/02/migrate-aws-ami-across-region-painlessly-en</id>
    <content type="html"><![CDATA[<p>Recently I need to migrate my infrastructure from Tokyo to Singapore. According to the information I gathered from AWS 201 course, it&#8217;s a little troublesome to migrate AWS AMI between regions.</p>

<p>As <a href="http://alestic.com/2010/10/ec2-ami-copy">Copying EBS Boot AMIs Between EC2 Regions</a> demostrated, we need to mount ebs for each regions and rsync them, than we register the ebs as AMI; Also there&#8217;s <a href="https://cloudyscripts.com/tool/show/5">CloudyScript</a>, it&#8217;s a online tool that does these steps for you.</p>

<p>After some study, I found that it&#8217;s not necessary now. Amazon announced <a href="http://aws.typepad.com/aws/2012/12/ebs-snapshot-copy.html">EBS Snapshot Copy</a> last December. Although you can&#8217;t migrate AMI but we could do so just for some more steps.</p>

<!--more-->


<p>It&#8217;s really simple:</p>

<p>Find the snapshot or your AMI, click <code>Copy Snapshot</code> to copy snapshot to your destinated region.</p>

<p><a href="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_1.png"><img src="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_1.png" alt="1" /></a></p>

<p>Check the <code>Kernel ID</code> field of your AMI.</p>

<p><a href="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_2.png"><img src="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_2.png" alt="2" /></a></p>

<p>Visit <a href="http://thecloudmarket.com/image/aki-ee5df7ef">the cloud market</a> to check AKI&#8217;s description to see which manifest.xml it belongs. For instance: <code>pv-grub-hd0_1.02-x86_64.gz.manifest.xml</code></p>

<p><a href="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_3.png"><img src="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_3.png" alt="3" /></a></p>

<p>Search for <code>pv-grub-hd0_1.02-x86_64.gz.manifest.xml</code> and find the AKI for your destinated region.</p>

<p><a href="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_4.png"><img src="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_4.png" alt="4" /></a></p>

<p>Perform <code>Create Image from Snapshot</code> on your cloned snapshot.</p>

<p><a href="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_5.png"><img src="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_5.png" alt="5" /></a></p>

<p>Select the AKI you just got.</p>

<p><a href="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_6.png"><img src="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_6.png" alt="6" /></a></p>

<p>You don&#8217;t need to rsync anything. It&#8217;s just that easy!</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[無痛跨 region 轉移 AWS AMI]]></title>
    <link href="http://blog.hsatac.net/2013/02/migrate-aws-ami-across-region-painlessly/" />
    <updated>2013-02-27T15:45:00+08:00</updated>
    <id>http://blog.hsatac.net/2013/02/migrate-aws-ami-across-region-painlessly</id>
    <content type="html"><![CDATA[<p>最近要把一些日本的東西轉移到新加坡，根據以前參加 AWS 201 的資料，跨 region 轉移 AMI(Amazon Machine Image) 這件事有點麻煩。</p>

<p>通常找來找去都是用 <a href="http://alestic.com/2010/10/ec2-ami-copy">Copying EBS Boot AMIs Between EC2 Regions</a> 推薦的方法，在兩邊各開一個 ebs mount 起來然後 rsync 再 register 成 AMI…操作起來耗時又複雜；不然就是用 <a href="https://cloudyscripts.com/tool/show/5">CloudyScript</a> 提供的線上工具，不過他其實就只是幫你把上面這些動作自動化而已&#8230;。</p>

<p>弄了一陣子發現，現在根本不需要這些瑣碎的步驟！ Amazone 在去年 12 月就發表了 <a href="http://aws.typepad.com/aws/2012/12/ebs-snapshot-copy.html">EBS Snapshot Copy</a> 可以自由的跨區複製 snapshot! 雖然還不能複製 AMI，不過我們只要手動多幾個步驟就好。</p>

<!--more-->


<p>整個過程很簡單，以下用圖示說明：</p>

<p>先找出你 AMI 的 snapshot, 點選 <code>Copy Snapshot</code> 複製到你要的 region.</p>

<p><a href="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_1.png"><img src="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_1.png" alt="1" /></a></p>

<p>複製完成後，看一下原本的 AMI 資訊，注意 <code>Kernel ID</code> 這個欄位，把他記下來。</p>

<p><a href="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_2.png"><img src="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_2.png" alt="2" /></a></p>

<p>接著我們要使用演算法優化的大絕招 - 查表法。拜訪 <a href="http://thecloudmarket.com/image/aki-ee5df7ef">the cloud market</a> 找出這個 AKI 的 Description 是哪個 manifest.xml ，例如我的就是 <code>pv-grub-hd0_1.02-x86_64.gz.manifest.xml</code></p>

<p><a href="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_3.png"><img src="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_3.png" alt="3" /></a></p>

<p>接著再搜尋 <code>pv-grub-hd0_1.02-x86_64.gz.manifest.xml</code> 並找出你要的 region，記住這個 AKI。</p>

<p><a href="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_4.png"><img src="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_4.png" alt="4" /></a></p>

<p>在已複製好的 snapshot 上右鍵點選 <code>Create Image from Snapshot</code></p>

<p><a href="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_5.png"><img src="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_5.png" alt="5" /></a></p>

<p>Kernel ID 選擇你剛剛查到的 AKI 就可以了！</p>

<p><a href="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_6.png"><img src="http://blog.hsatac.net/images/ami_migrate/migrate_aws_ami_across_region_painlessly_6.png" alt="6" /></a></p>

<p>完全不需要什麼 rsync 啦！無痛跨 region 轉移就這麼簡單！</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Puppet 學習筆記]]></title>
    <link href="http://blog.hsatac.net/2013/02/puppet-study-note/" />
    <updated>2013-02-22T11:38:00+08:00</updated>
    <id>http://blog.hsatac.net/2013/02/puppet-study-note</id>
    <content type="html"><![CDATA[<p>前陣子玩了 Puppet…把一些重點和資源紀錄在這邊…
初學 Puppet 的話很建議看一遍<a href="http://docs.puppetlabs.com/learning/">官方教學</a>，雖然沒有很完整但整個 run 過基礎的概念會有。</p>

<h2>Infrastructure as Code</h2>

<p>Puppet 的概念是 infrastructure as code，那跟以往寫 shell scripts 有何不同&#8230;？</p>

<p>其實基本上是相通的…但概念層次上高了一層。寫 shell script 主要是加速重複性工作、減少人為疏失，但你也很難去 reuse 這些東西。</p>

<p>Puppet 則是往上拉了一層虛擬層，你只要定義你 infrastructure 的狀態，。可以模組化、重用你程式碼，用清楚易懂的 code 描述套件要怎麼裝，設定檔有哪些，每個 server 之間的關係是怎麼樣&#8230;。</p>

<p>Code 就是文件， code 就是你的 infrastructure。不但好寫好讀好維護，更可直接拿來執行。</p>

<!--more-->


<h2>Resource</h2>

<p>Puppet 中最重要的東西、以及最基本的基礎元件叫做 resource，例如 file, package, service 這三個就是最常用的 resource ，你可以透過 resource 來指定你的檔案狀態、套件安裝狀態、服務狀態等等。</p>

<p>Resource 列表和用法可參考：<a href="http://docs.puppetlabs.com/references/latest/type.html">http://docs.puppetlabs.com/references/latest/type.html</a></p>

<p>resource type 要注意大小寫，當作 metaparameters 的時候寫作 <code>Type[title]</code> Type 要大寫。</p>

<h2>Dependencies</h2>

<p>我們會撰寫 manifest 檔案來描述 resource，需要注意的是這些 resource 都是 sync 執行的，並不是順序執行，因此就會有相依性的問題產生。</p>

<p>Puppet 提供了 before / require 關鍵字</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>file {'/tmp/test1':
</span><span class='line'>      ensure  => present,
</span><span class='line'>      content => "Hi.",
</span><span class='line'>      before  => Notify['/tmp/test1 has already been synced.'],
</span><span class='line'>      # (See what I meant about symbolic titles being a good idea?)
</span><span class='line'>    }
</span><span class='line'>
</span><span class='line'>    notify {'/tmp/test1 has already been synced.':}</span></code></pre></td></tr></table></div></figure>


<p>也可以用 chaining 的寫法，以箭頭表示 <- 或 -> 都可以：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>file {'/tmp/test1':
</span><span class='line'>      ensure  => present,
</span><span class='line'>      content => "Hi.",
</span><span class='line'>    }
</span><span class='line'>
</span><span class='line'>    notify {'after':
</span><span class='line'>      message => '/tmp/test1 has already been synced.',
</span><span class='line'>    }
</span><span class='line'>
</span><span class='line'>    File['/tmp/test1'] -> Notify['after']</span></code></pre></td></tr></table></div></figure>


<p>另外有一組「觸發」的關鍵字叫 notify / subscribe ，可以用 &lt;~ 或 ~> 表示，當前面的 Resource 有更新，會通知後面的 resource 執行。</p>

<p>還有一些狀況 Puppet 會自動處理 dependencies 。這叫 Autorequire。</p>

<p>例如你定義了兩個目錄，其中一個目錄在另一個目錄之下，Puppet 很聰明會自動判斷他們的相依性。又例如你定義 user 和這個 user 的 ssh_authorized_key，Puppet 也會自動處理他們的順序。</p>

<h2>Module</h2>

<p>在 Puppet 裡面我們可以寫 class，而 module 就是可重用的 class。放在 modulepath 裡面。</p>

<p>可使用 <code>puppet apply --configprint modulepath</code> 查看 modulepath 設定值。</p>

<p><code>puppet apply --configprint all</code> 可看全部設定。</p>

<p>Module 目錄有固定的格式</p>

<ul>
<li><p><code>/etc/puppet/module/{module_name}/manifests/init.pp</code> 這是 module 的 main file</p></li>
<li><p><code>/etc/puppet/module/{module_name}/manifests/files</code> 使用 <code>puppet://</code> 來 serve file 的時候會抓這下面的檔案。例如 <code>puppet:///module/php/php.conf</code> 就是 <code>`/etc/puppet/module/php/files/php.conf</code>。</p></li>
<li><p><code>/etc/puppet/module/{module_name}/templates/</code> module 若有使用 template 就要放在這。</p></li>
</ul>


<p>寫好 module 後想測試可執行 <code>puppet apply -e "include php"</code> 來測試，想看完整 debug 訊息可加上 <code>-vd</code> 參數 <code>puppet apply -e "include php" -vd</code></p>

<p>除了自己寫的 module 以外也可以使用別人寫好的 module 來加快開發速度。</p>

<p>關於 module 設計的一些基本概念可以參考這篇好文：<a href="http://www.devco.net/archives/2012/12/13/simple-puppet-module-structure-redux.php">Simple Puppet Module Structure Redux</a></p>

<h3>Puppet Forge</h3>

<p>Puppet 提供了一個 module 集中地 <a href="http://forge.puppetlabs.com/">Puppet Forge</a> 可以直接來此搜尋現成的 module。不過根據我的觀察這些 module 大多都是支援 debian/ubuntu 等主流 distro，若使用其他 distro 的可能要考慮自己寫或是 contribute 。</p>

<p>不管怎樣，可以來這裡參考別人寫的 module 收穫會很多。</p>

<p>安裝 Puppet module 可使用以下指令：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>puppet module install puppetlabs-apache --version 0.0.2
</span><span class='line'>puppet module list
</span><span class='line'>puppet module search apache
</span><span class='line'>puppet module uninstall puppetlabs-apache
</span><span class='line'>puppet module upgrade puppetlabs-apache --version 0.0.3</span></code></pre></td></tr></table></div></figure>


<p>更詳細的說明可參考：<a href="http://docs.puppetlabs.com/puppet/latest/reference/modules_installing.html">Modules Installing</a></p>

<h2>Defined Resource Types</h2>

<p>我們可以定義自己的 resource type，透過 <code>define</code> 這個關鍵字。跟 class 用法基本上一樣，但是 define 不支援繼承。有點像是 marco 的功能，例如我們可以定義一個 developer 的 resource，把相關的東西都包在一起：</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>define developer($user = $title, $uid, $ssh_key) {
</span><span class='line'>        $key_seg = split($ssh_key, ' ')
</span><span class='line'>        $ssh_key_title = $key_seg[2]
</span><span class='line'>        $ssh_key_type  = $key_seg[0]
</span><span class='line'>        $ssh_key_hash  = $key_seg[1]
</span><span class='line'>        user {$user:
</span><span class='line'>                ensure => present,
</span><span class='line'>                managehome => true,
</span><span class='line'>                groups => ['wheel', 'users'],
</span><span class='line'>                uid => $uid,
</span><span class='line'>        } ->
</span><span class='line'>        ssh_authorized_key {"${user}_puppet_key":
</span><span class='line'>                ensure => present,
</span><span class='line'>                key => $ssh_key_hash,
</span><span class='line'>                user => $user,
</span><span class='line'>                type => $ssh_key_type,
</span><span class='line'>                name => "${user}_puppet_key",
</span><span class='line'>        } ->
</span><span class='line'>        file {"/home/${user}":
</span><span class='line'>                mode => 0755,
</span><span class='line'>        } ->
</span><span class='line'>        file {"/home/dev/${user}":
</span><span class='line'>                ensure => link,
</span><span class='line'>                target => '/home/$user',
</span><span class='line'>        }
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<h2>Functions</h2>

<p>Puppet 提供了一些函數可運用，可透過 <code>puppet doc --reference function</code> 指令查看，或者至 <a href="http://docs.puppetlabs.com/references/latest/function.html%20function%20list">http://docs.puppetlabs.com/references/latest/function.html function list</a></p>

<h2>Stage</h2>

<p>有些狀況想讓不同 module 在不同的 stage 執行，就可以使用 stage 功能。</p>

<p>預設所有 module 都是 default 在 <code>main</code> stage，所以可以定義其他的 stage 在 main 之前或之後即可。</p>

<p>詳細參考 <a href="http://docs.puppetlabs.com/puppet/latest/reference/lang_run_stages.html">Puppet Run Stages</a></p>

<h2>Puppet 目錄架構</h2>

<ul>
<li><p><code>/etc/puppet/puppet.conf</code> 主要設定檔，可參考<a href="http://docs.puppetlabs.com/guides/configuring.html">官方文件</a></p></li>
<li><p><code>/etc/puppet/modules/</code> 放你寫的 modules</p></li>
<li><p><code>/etc/puppet/manifests/site.pp</code> 放你的 node 描述檔，也就是你每台伺服器要怎樣定義寫在這。</p></li>
</ul>


<h2>Puppet 流程</h2>

<p>Puppet 會把我們撰寫的 manifest 檔案 compile 起來並處理其中的 dependencies 後打成一包，再查詢目前系統的狀態後更改系統到我們定義的狀態，如圖示：</p>

<p><img src="http://docs.puppetlabs.com/learning/images/manifest_to_defined_state_unified.png" alt="manifest to defined state" /></p>

<h3>Master-Agent</h3>

<p>Puppet 可以採用 Master-Agent 架構，一台 master 據說能承載 5000 個 agents。也可以單機跑，也就是類似所謂的 Chef solo。</p>

<p>Master-Agent 的流程如下圖：</p>

<p><img src="http://docs.puppetlabs.com/learning/images/manifest_to_defined_state_split.png" alt="master agent" /></p>

<p>基本架構就是 master 上 run <code>puppetmaster</code> 服務， agent 上 run <code>puppetagent</code> 服務。</p>

<p>也可以手動從 agent 觸發，執行 <code>puppet agent --test -vd</code>。</p>

<h3>Masterless Puppet</h3>

<p>想要使用 masterless puppet 非常容易，只要自己指定你的 modulepath 和你的 site.pp 即可。</p>

<p><code>puppet apply --modulepath ./modules manifests/site.pp</code></p>

<h2>其他參考資料</h2>

<ul>
<li><p><a href="http://docs.puppetlabs.com/guides/troubleshooting.html">Trouble Shooting</a> Puppet 使用上有問題可以先來這邊查查看。</p></li>
<li><p><a href="http://www.puppetcookbook.com/">Puppet CookBook</a> 有許多實用案例</p></li>
<li><p><a href="https://github.com/jordansissel/puppet-examples">Puppet Examples</a> 有很多東西直接看 code 是最快的&#8230;。</p></li>
<li><p>關於 Archlinux 使用 Puppet 相關可參考我上兩篇文章：<a href="http://blog.hsatac.net/2013/02/using-puppet-on-archlinux/">ArchLinux 使用 Puppet 注意事項</a>、<a href="http://blog.hsatac.net/2013/02/bootstrap-archlinux-with-puppet/">使用 Puppet 快速佈署 Archlinux</a></p></li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[ArchLinux 使用 Puppet 注意事項]]></title>
    <link href="http://blog.hsatac.net/2013/02/using-puppet-on-archlinux/" />
    <updated>2013-02-21T14:12:00+08:00</updated>
    <id>http://blog.hsatac.net/2013/02/using-puppet-on-archlinux</id>
    <content type="html"><![CDATA[<p>想在 ArchLinux 使用 Puppet 有一些需要注意的地方，在這邊順便補充一下。</p>

<h2>systemctl 路徑</h2>

<p>Arch 在之前的改版已經把 <code>/bin/systemctl</code> 移到 <code>/usr/bin/systemctl</code> 下，但 Puppet 還是抓 <code>/usr/systemctl</code> 導致找不到 systemd 這個 provider ，這個問題已經在 Puppet 3.1 修改，也可以自己手動 link 一下。</p>

<h2>套件庫需更新到最新版</h2>

<p>Arch 每次都要先 <code>pacman -Syy</code> 一下不然 package 會無法使用。</p>

<p>以上這兩個問題我有寫了一段 module</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class=''><span class='line'># For Archlinux. This issue will be fixed in puppet 3.1
</span><span class='line'>
</span><span class='line'>class archfix {
</span><span class='line'>    file {'/bin/systemctl':
</span><span class='line'>        ensure => link,
</span><span class='line'>        target => '/usr/bin/systemctl',
</span><span class='line'>    }   
</span><span class='line'>    exec {'pacman -Syy':
</span><span class='line'>        path => ["/usr/bin"]
</span><span class='line'>    }   
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<p>在 manifest 中利用 stage 功能先執行 archfix 這個 module 就可以了。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>node 'devm3' {
</span><span class='line'>    stage { 'pre': }
</span><span class='line'>    class {
</span><span class='line'>        "archfix": stage => "pre"; 
</span><span class='line'>    }   
</span><span class='line'>    Stage["pre"] -> Stage["main"]
</span><span class='line'>
</span><span class='line'>  # include other modules...
</span><span class='line'>}</span></code></pre></td></tr></table></div></figure>


<h2>Openrc &amp; Systemd</h2>

<p>ArchLinux 現在還有很多套件同時支援 openrc 的 initscript 和 systemd，Puppet 會偵測到兩個 provider 但是他會選擇用 initscript 。可以在 service resource 指定 <code>provider =&gt; systemd</code> 即可。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[使用 Puppet 快速佈署 Archlinux]]></title>
    <link href="http://blog.hsatac.net/2013/02/bootstrap-archlinux-with-puppet/" />
    <updated>2013-02-19T17:51:00+08:00</updated>
    <id>http://blog.hsatac.net/2013/02/bootstrap-archlinux-with-puppet</id>
    <content type="html"><![CDATA[<p>筆記一下安裝步驟&#8230;。</p>

<h2>Install Archlinux</h2>

<p>由於 Archlinux 本身沒有提供方便的安裝模式、因此我們使用 <a href="https://twitter.com/helmuthdu">@helmuthdu</a> 的快速安裝 script <a href="https://github.com/helmuthdu/aui">AUI</a>，安裝完成後再使用 puppet bootstrap 環境</p>

<ul>
<li>放入 CD 選擇 x64_64 開機</li>
<li>執行 <code>curl hsatac.net/getaui | sh</code></li>
<li>進入 helmuthdu-aui-xxxx 目錄</li>
<li>執行 <code>./aui --ais</code> 進入安裝程式</li>
<li>輸入 1-14 執行全部安裝步驟</li>
</ul>


<p>ps. 如遇特定機種無法使用 grub2 可改用 syslinux bootloader</p>

<h2>Reboot</h2>

<p>安裝完成重開機後後首先設定讓網路能通
可參考<a href="https://wiki.archlinux.org/index.php/Network_Configuration">官方wiki</a></p>

<p>如欲使用 dhcp 可執行 <code>systemctl start dhcpcd</code>
<code>systemctl enable dhcpcd</code> 開機自動執行</p>

<ul>
<li>回到 helmuthdu-aui-xxx 目錄</li>
<li>執行 <code>./aui</code> 繼續安裝</li>
<li>新增使用者步驟必須執行，因後續步驟需用 sudo</li>
<li>AUR helper 選擇 yaourt
(Yaourt 和 packer 大同小異，但因 puppet 使用 yaourt 所以改用。)</li>
<li>後面的 setup 可跳過，或者裝 Basic Setup 即可，這邊都是 桌面環境相關</li>
<li>設定 /etc/resolv.conf</li>
</ul>


<h2>使用 puppet</h2>

<p>puppet 可使用 master-agent 架構或者單機(solo) 安裝，詳見 puppet wiki</p>

<ul>
<li><code>yaourt puppet</code> 安裝 puppet</li>
<li>在 /etc/hosts 設定 puppet master hostname 並在 /etc/puppet/puppet.conf [agent] 區塊設定 <code>server = xxx</code> (hostname 要跟 master hostname 一樣不然憑證不會過)</li>
<li>run <code>puppet agent --test</code> 會出現沒有憑證訊息</li>
<li>回到 puppet master 執行 <code>puppet cert list</code> 會看到待簽署的憑證</li>
<li>執行 <code>puppet cert sign [hostname]</code> 簽署</li>
<li>記得在 master 的 /etc/puppet/manifests/site.pp 設定新的 node 定義</li>
<li>回到 agent 執行 <code>puppet agent --test</code> 進行安裝</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[RWBY]]></title>
    <link href="http://blog.hsatac.net/2013/02/rwby/" />
    <updated>2013-02-15T17:54:00+08:00</updated>
    <id>http://blog.hsatac.net/2013/02/rwby</id>
    <content type="html"><![CDATA[<p>RWBY 第二部預告片 &#8220;White&#8221; 終於推出！</p>

<p>之前看完第一部 &#8220;Red&#8221; 時還沒有特別被萌到，只覺得創意、畫面和音樂都還不錯。不過這次看完 &#8220;White&#8221; 以後整個點都被打到啦！直接去 itunes 收了這兩首 OST…</p>

<p>下一部 &#8220;Black&#8221; 預計在 2013.07 發佈，這樣算來本體推出都要 2014 啦！實在是很大一個坑&#8230;</p>

<iframe width="560" height="315" src="http://www.youtube.com/embed/Vt9vl8iAN5Q" frameborder="0" allowfullscreen></iframe>


<!--more-->




<blockquote><p>Mirror, tell me something.<br/>Tell me who&#8217;s the loneliest of all.</p><p>Mirror, tell me something.<br/>Tell me who&#8217;s the loneliest of all.</p><p>Mirror, locked inside of me.<br/>Tell me can a heart be turned to stone?</p><p>Mirror mirror what&#8217;s behind you?<br/>Save me from the things I see!<br/>I can keep it from the world,<br/>why wont you let me hide from me?</p><p>Mirror, mirror,<br/>tell me something.<br/>Who&#8217;s the loneliest of all?</p><p>I am the loneliest of all.</p></blockquote>


<p>第一部 &#8220;Red&#8221;</p>

<iframe width="560" height="315" src="http://www.youtube.com/embed/pYW2GmHB5xs" frameborder="0" allowfullscreen></iframe>




<blockquote><p>Red like roses fills my dreams and brings me to the place you rest<br/>White is cold and always yearning burdened by a royal test<br/>Black the beast descends from shadows<br/>Yellow beauty burns gold</p></blockquote>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[追蹤 Rubygems require 緩慢紀錄]]></title>
    <link href="http://blog.hsatac.net/2013/01/trace-rubygems-require-slow/" />
    <updated>2013-01-30T10:18:00+08:00</updated>
    <id>http://blog.hsatac.net/2013/01/trace-rubygems-require-slow</id>
    <content type="html"><![CDATA[<p>昨天灌了一台新的機器，正準備用 <a href="http://puppetlabs.com">puppet</a> bootstrap 時卻發現他的 puppet 執行的非常緩慢。追蹤解決問題的過程十分有趣，在這邊紀錄一下。</p>

<p>由於 puppet 執行檔本身是一隻 ruby script，於是開啟了 irb -d 使用 DEBUG 模式直接執行看看該 script 的內容，看看能否看出問題在哪。</p>

<!--more-->


<p>結果是慢在 <code>require 'puppet'</code> 這裡。想說是不是 gempath 的問題，先用 gem env 看一下設定和環境變數，感覺一切正常。在使用 gem 指令的過程中，發現 <code>gem help commands</code> 這個指令也異常緩慢，而且和 puppet 慢的速度感覺是一樣的。使用 <code>time gem help commands</code> 和 <code>time puppet</code>
測量，果然兩邊都是慢 20 秒，感覺之間可能有某些關聯。</p>

<p>一度懷疑是硬碟壞軌，使用 <code>smartctl</code> 顯示硬碟狀況良好，又開始懷疑是 Ruby 1.9.3-p374 的 bug。但是上網搜尋沒有這樣的狀況，拿另一台舊的機器升級 Ruby 1.9.3-p374 也沒有這樣的狀況。看來是機器本身的問題。</p>

<p><code>ruby -d</code> 和 <code>irb -d</code> 都無法提供有用的資訊，只能看出在某個階段會卡住很久，只能往更低階的方向走。</p>

<p>先使用 <code>ltrace</code> 來觀察：</p>

<pre>
# ltrace -r ruby `which gem` help commands
  0.000000 __libc_start_main(0x400860, 4, 0x7fff767d5ce8, 0x4009a0 <unfinished ...>
  0.000301 setlocale(LC_CTYPE, "")                                                                                                            = "en_US.UTF-8"
  0.000577 ruby_sysinit(0x7fff767d5bec, 0x7fff767d5be0, 1, 1)                                                                                 = 0
  0.000319 ruby_init_stack(0x7fff767d5bf8, 0x7fff767d5b30, 0x7fff767d5b30, -1)                                                                = 0
  0.000759 ruby_init(0x7febf8, 0xffffffff, 0, 0)                                                                                              = 0x876f20
  0.005726 ruby_options(4, 0x7fff767d5ce8, 0x877520, 0x7f3c31b59640)                                                                          = 0xad4800
  0.025221 ruby_run_node(0xad4800, 0x7fff767d6fea, 0x877520, 0xad9560
  20.511227 +++ exited (status 0) +++
</pre>


<p>只能看出卡在 ruby_run_node 這邊，再翻出 <code>strace</code> 試試：</p>

<pre>
# strace -rT ruby `which gem` help commands
     0.000051 open("/usr/lib/libresolv.so.2", O_RDONLY|O_CLOEXEC) = 5 <0.000012>
     0.000049 read(5, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\220:\0\0\0\0\0\0"..., 832) = 832 <0.000008>
     0.000049 fstat(5, {st_mode=S_IFREG|0755, st_size=84840, ...}) = 0 <0.000007>
     0.000049 mmap(NULL, 2189960, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 5, 0) = 0x7fd97dd1e000 <0.000009>
     0.000047 mprotect(0x7fd97dd31000, 2097152, PROT_NONE) = 0 <0.000012>
     0.000048 mmap(0x7fd97df31000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 5, 0x13000) = 0x7fd97df31000 <0.000011>
     0.000054 mmap(0x7fd97df33000, 6792, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fd97df33000 <0.000010>
     0.000053 close(5)                  = 0 <0.000007>
     0.000104 mprotect(0x7fd97df31000, 4096, PROT_READ) = 0 <0.000011>
     0.000059 mprotect(0x7fd97e139000, 4096, PROT_READ) = 0 <0.000009>
     0.000048 munmap(0x7fd98213a000, 24363) = 0 <0.000011>
     0.000100 socket(PF_INET, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP) = 5 <0.000013>
     0.000051 connect(5, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("192.168.79.161")}, 16) = 0 <0.000017>
     0.000073 poll([{fd=5, events=POLLOUT}], 1, 0) = 1 ([{fd=5, revents=POLLOUT}]) <0.000009>
     0.000058 sendmmsg(5, {{{msg_name(0)=NULL, msg_iov(1)=[{"\362\36\1\0\0\1\0\0\0\0\0\0\5devm3\0\0\1\0\1", 23}], msg_controllen=0, msg_flags=MSG_EOR|MSG_TRUNC|MSG_DONTWAIT|MSG_FIN|MSG_SYN|MSG_NOSIGNAL|MSG_MORE|MSG_WAITFORONE|0x13a0000}, 23}, {{msg_name(0)=NULL, msg_iov(1)=[{":O\1\0\0\1\0\0\0\0\0\0\5devm3\0\0\34\0\1", 23}], msg_controllen=0, msg_flags=MSG_PROXY|MSG_EOR|MSG_WAITALL|MSG_TRUNC|MSG_DONTWAIT|MSG_SYN|MSG_RST|MSG_WAITFORONE|0x1120000}, 23}}, 2, MSG_NOSIGNAL) = 2 <0.000020>
     0.000081 poll([{fd=5, events=POLLIN}], 1, 5000) = 0 (Timeout) <5.004974>
     5.005030 poll([{fd=5, events=POLLOUT}], 1, 0) = 1 ([{fd=5, revents=POLLOUT}]) <0.000008>
     0.000051 sendmmsg(5, {{{msg_name(0)=NULL, msg_iov(1)=[{"\362\36\1\0\0\1\0\0\0\0\0\0\5devm3\0\0\1\0\1", 23}], msg_controllen=0, msg_flags=MSG_EOR|MSG_TRUNC|MSG_DONTWAIT|MSG_FIN|MSG_SYN|MSG_NOSIGNAL|MSG_MORE|MSG_WAITFORONE|0x13a0000}, 23}, {{msg_name(0)=NULL, msg_iov(1)=[{":O\1\0\0\1\0\0\0\0\0\0\5devm3\0\0\34\0\1", 23}], msg_controllen=0, msg_flags=MSG_PROXY|MSG_EOR|MSG_WAITALL|MSG_TRUNC|MSG_DONTWAIT|MSG_SYN|MSG_RST|MSG_WAITFORONE|0x1120000}, 23}}, 2, MSG_NOSIGNAL) = 2 <0.000015>
     0.000075 poll([{fd=5, events=POLLIN}], 1, 5000^CProcess 7498 detached
 <detached ...>
</pre>


<p>可以很明顯看出是往 192.168.79.161:53 問 devm3 ，結果 timeout 了四次，一次五秒剛好 20 秒。</p>

<p>兇手已經呼之欲出了，就是我 =皿=</p>

<p>當時幫這台新機器改了 hostname 以後，忘記修改 /etc/hosts ，導致他自己不認得自己的 hostname。當然那個會 timeout 的 DNS 也是有問題，不過那是關於 djbdns 的另一個故事了&#8230;。</p>

<p>最後將 /etc/hosts 改回來就完全正常了。可喜可賀。最難抓的 bug 果然都是最愚蠢的&#8230;。</p>

<p>在這邊要感謝 <a href="http://www.tenlong.com.tw/items/9862765674?item_id=481936">Debug Hacks 除錯駭客－極致除錯的技巧與工具</a> 一書的譯者，事實證明寫 scripting language 也是要會一些基礎 debug 技巧的！推薦各位購買這本書。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[RubyConf.tw 2012 流水帳]]></title>
    <link href="http://blog.hsatac.net/2012/12/ruby-conf-taiwan-2012/" />
    <updated>2012-12-09T13:04:00+08:00</updated>
    <id>http://blog.hsatac.net/2012/12/ruby-conf-taiwan-2012</id>
    <content type="html"><![CDATA[<p>今年的 Ruby Conf Taiwan 2012 實在太精彩，太感動了，一定要寫下來紀錄一下。</p>

<h3>前夜祭</h3>

<p>首先是經過 ihower 三年的邀請，今年終於邀請到 Ruby 之父 Matz 來到台灣。由於 Matz 提早到台灣，所以在 Ruby Conf 的前一天晚上也臨時加開了 Matz 見面會，能有這個近距離和大師接觸，聊天，提問的機會實在非常難得。不過也許是這時候大家把問題都問的差不多了，結果隔天 Matz 的 keynote 反而沒什麼人提問(笑)。</p>

<p><img src="http://blog.hsatac.net/images/rubyconftw2012/matz_and_i.jpg" alt="matz and I" /></p>

<!--more-->


<h3>Day 1</h3>

<p>這次場地不是在老地方中研院，而是在天母農訓中心國際會議廳，大家應該都是第一次來這個地方。場地設備算 OK ，不過沒有有線網路可用，然後剛好無線網路又悲劇了，後來大家好像都是靠自己的 3G 上網。午餐也是在這邊有 buffet 可以吃，非常好吃！一般訂便當完全無法相提並論。不過座位稍微矮小狹窄了一點，我這個身高的人坐一整天其實膝蓋很痛⋯⋯。</p>

<p>這個廳比中研院的大廳小，比中研院的小廳大。其實我覺得這樣的配置挺不錯的，不會離講者太遠，互動性比較高，也不會太擁擠。</p>

<p>一早就是 Matz 的 Keynote，同時講了三個主題，非常豐富；接下來是來自新加坡的 Wei Lu 分享 Pair Programming ，台風非常穩健。最令人驚喜的是 Jserv 的 mruby talk！從為什麼他們選擇 mruby 到 ARM 優化的細節，最後 live demo，連 Matz 在台下都聽得連連點頭。</p>

<blockquote class="twitter-tweet"><p>こういうmrubyの話が聞けるのは予想外だったなあ</p>&mdash; Yukihiro Matsumoto (@yukihiro_matz) <a href="https://twitter.com/yukihiro_matz/status/276903947690729472" data-datetime="2012-12-07T04:20:20+00:00">December 7, 2012</a></blockquote>


<script src="http://blog.hsatac.net//platform.twitter.com/widgets.js" charset="utf-8"></script>


<blockquote><p>「聽到這種 mruby 的資訊真是意料之外」</p></blockquote>

<p>下午 godfat 關於 concurrency application servers 的 talk 也很精彩，從實務出發，由淺入深。</p>

<p>這次與會的外國來賓和講者比例非常高，所以很多中文議程講者都臨時決定改用英文分享。其實我是覺得滿好的，身為一個國際性的研討會，盡可能照顧到所有人，讓外國來賓比較有參與感。</p>

<p>結果第一天的議程除了 godfat 以外全部都用英文演說了，恭喜 godfat 得到「Day 1 唯一中文講者」的成就 XD</p>

<h3>Party</h3>

<p>晚上參加了 official party，表定到晚上 12 點，因為我不太喝酒，本來想說去 social 一下就回家了。沒想到真的喝到 12 點才走(爆)</p>

<p>這個場合真的很好，可以很輕鬆的跟新朋友老朋友、各國來賓輕鬆的對談。跟好久不見的 dreamslab ben update 了一下近況；跟 jserv 聊了一下他的新公司；也跟慕凡交換了一下遊戲界甘苦談。</p>

<p>席間我問 Matz：「您去過許多 ruby conf, 這是第一次來 ruby conf taiwan ，您覺得怎麼樣？」</p>

<p>他回答，ruby conf taiwan 規模雖然小，但是質量水準很高，他相當驚訝。又問明年他是否願意再來，他說只要我們有邀請，他就會再來。</p>

<p>能讓 Matz 如此肯定，ihower 跟慕凡辦的真的是太優秀了。</p>

<h3>Day 2</h3>

<p>Day 2 是我原本就期待許久的議程，主要是 dlackty 的 devOps toolbox 會提到 chef，緊接著 thegiive 會介紹 puppet，這兩套工具我 survey 了一陣子，無法決定要用哪套，剛好來聽聽看心得。在兩位 Session 結束後也分別向兩位請教了一些 devOps 上的疑惑。</p>

<p>早上 Gosuke Miyashita 的 talk 也講了很多有趣的東西，例如他們的 <a href="https://github.com/paperboy-sqale/sqale-patches">anti fork bomb patch</a> 和 <a href="https://github.com/mizzy/openssh-script-auth">SSH router 實作</a>，讓我對 paperboy &amp; co. 這家陌生的日本公司有很深刻的印象。</p>

<p>下午 josephku 的 RubyMotion 也講的很精彩。 RubyMotion 也是我關注很久的技術，可以用 ruby 語法寫 iOS 對我這種被逼上梁山的 iOS 開發者來說有很大的吸引力。但是他的資料一直非常少，很訝異 josephku 能掌握並分享這樣一個新穎的技術，QA 時我也提問了兩個問題。會後本想找 josephku 認識一下，但緣鏗一面，希望日後有機會。</p>

<h3>End</h3>

<p>這次 Ruby Conf Taiwan 2012 的 Session 質量非常高，高到連外國來賓都很訝異。</p>

<blockquote class="twitter-tweet"><p>しかし，私が最適化の話とかをして，真面目に最適化の中身の質問を受けるカンファレンスは非常に久しぶりな気がする．台湾凄い．</p>&mdash; _ko1 (@_ko1) <a href="https://twitter.com/_ko1/status/277339165358714880" data-datetime="2012-12-08T09:09:44+00:00">December 8, 2012</a></blockquote>


<script src="http://blog.hsatac.net//platform.twitter.com/widgets.js" charset="utf-8"></script>


<blockquote><p>「不過, 讓我談到最佳化之類的議題、被認真地問最佳化核心部份的問題 conference 似乎非常久沒遇過了, 台灣真厲害。」</p></blockquote>

<p>我覺得這次議程篩選和安排的相當好，各領域的主題都有，展現了 Ruby 的多種可能性；深度也夠，不僅是聽眾收穫豐碩，講者們也能有互動。例如第一天 mruby 的幾位講者和來賓 jserv, matz, 高橋彼此會後也都能有交流。</p>

<p>聽 ihower 說這次篩選主題非常嚴格，有許多 sponser 的投稿都沒能入選，我覺得這樣非常好，贊助歸贊助，會給他們廣告的空間，不過維持大會的水準才是第一要務。</p>

<p>不誇張，這次 Ruby Conf Taiwan 2012 真的是我參加到目前為止台灣研討會裡最棒的一場，感謝 ihower 和慕凡以及所有工作人員的努力！</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[2010 MBP 升級 SSD 與 Fusion Drive]]></title>
    <link href="http://blog.hsatac.net/2012/11/macbook-pro-2010-mid-replace-optical-drive-with-ssd-and-fusion-drive/" />
    <updated>2012-11-26T15:15:00+08:00</updated>
    <id>http://blog.hsatac.net/2012/11/macbook-pro-2010-mid-replace-optical-drive-with-ssd-and-fusion-drive</id>
    <content type="html"><![CDATA[<p>我現在用來開發 iOS 的電腦是公司提供的一台 Macbook Pro 13&#8221; 2010 mid 4G ram。使用上還算堪用，但時不時的 lag 以及 freeze 實在非常挑戰開發者的耐心。尤其當我 Xcode 開著，git 切換 branch 然後 Xcode 重新 index 的時候簡直慘不忍睹。</p>

<p>畢竟電腦還是自己在用，開心順手最重要，所以決定自己投資一點下去升級。因為光碟機很少在用，所以查了一下以前看過的硬碟轉接托架，意外發現非常便宜才 200 多元，還附拆機工具組。參考<a href="http://blog.lyhdev.com/2012/10/apple-macbook-pro-ssd.html">玩物喪誌</a>的心得一樣購買 Jeyi 的硬碟托架以及 Micron M4 7mm 超薄 SSD。別人踩過一次的雷就不用再踩了。</p>

<p>把光碟機拆下，原本的位置裝上 SSD。內裝的硬碟則不動。如果把內裝硬碟裝在硬碟托架的話硬碟的感震偵測會無法作用。拆機安裝部分參考 <a href="http://www.ifixit.com/Guide/MacBook+Pro+13-Inch+Unibody+Mid+2010+Optical+Drive+Replacement/4318/">ifixit</a> 的說明。最需要注意的是螺絲不要滑牙了。</p>

<p>在拆機的過程中也順便把家裡的 Mac mini server 8G 出包版的記憶體拆下與 MBP 的 4G 對調，兩組都是 DDR 3 1066 的規格，對換毫無困難。</p>

<p>裝上以後開機確認是否有抓到及辨識到 SSD 固態硬碟，link speed 也跑到 SATA II 全速。接著使用 Carbon Copy Cloner 先把原本的系統碟備份到外接 USB 硬碟。再改用 USB 硬碟開機，準備做 Fusion Drive。</p>

<p>會使用 Fusion Drive 的原因是 SSD 實在不夠大，原本要自己安排哪些目錄放 SSD，哪些少用放 HD ，但是使用 Fusion Drive 技術的話可以將 SSD 與 HD 變成一顆邏輯磁碟，而系統會自己幫你判斷哪些常用的檔案放在 SSD, 不常用的則移去 HD ，兼顧了速度與容量和便利性，似乎是個不錯的選擇，所以決定試試看。</p>

<p>參考 <a href="http://jollyjinx.tumblr.com/post/34638496292/fusion-drive-on-older-macs-yes-since-apple-has">Fusion drive on older Macs? YES!</a> 的說明做好 Fusion Drive，再用 Carbon Copy Cloner 把外接 USB 硬碟的資料複製回做好的 Fusion Drive。值得一提的是 Fusion Drive 似乎無法製作 Recovery Partition，這部份只好無視他的 warning 。</p>

<p>最後把 Fusion Drive 設為開機碟重開就完成了這次的升級。相關照片和紀錄都放在 <a href="http://www.facebook.com/media/set/?set=a.4857081506317.2196205.1275503618&amp;type=1&amp;l=bb8d23d675">Facebook 相簿</a> 中。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Sentry 簡介投影片]]></title>
    <link href="http://blog.hsatac.net/2012/11/sentry-introduction-slides/" />
    <updated>2012-11-13T11:53:00+08:00</updated>
    <id>http://blog.hsatac.net/2012/11/sentry-introduction-slides</id>
    <content type="html"><![CDATA[<script async class="speakerdeck-embed" data-id="509a1faa3a7976000202bd2c" data-ratio="1.2994923857868" src="http://blog.hsatac.net//speakerdeck.com/assets/embed.js"></script>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[PHP array 相加與 array_merge]]></title>
    <link href="http://blog.hsatac.net/2012/11/php-array-plus-array-versus-array-merge/" />
    <updated>2012-11-06T13:17:00+08:00</updated>
    <id>http://blog.hsatac.net/2012/11/php-array-plus-array-versus-array-merge</id>
    <content type="html"><![CDATA[<p>今天聊到這個問題，喚起我沈睡的記憶…應該寫下來不然兩年後我大概又會忘了。</p>

<p>在 PHP 中 <code>array + array</code> 與 <code>array_merge</code> 的行為是不一樣的，陣列相加的效能會比 <code>array_merge</code> 來的好，但換來的代價是可能不是你預期的行為以及資料流失。</p>

<p>PHP 的陣列可以有 key 也可以沒有 key，也可以兩者混合。不過所謂的沒有 key ，其實他還是有 key ，只是是自動編上去的 int 流水號 key 例如 0,1,2,3&#8230;不管是哪一種，在陣列相加以及 <code>array_merge</code> 的行為都不一樣。</p>

<p>先講一下 <code>array_merge</code> 的行為，<code>array_merge($a, $b)</code> 的話，如果 <code>$a</code> 和 <code>$b</code> 裡面有 key 相同的元素，則會<strong>後蓋前</strong>也就是 <code>$b</code> 的值會蓋掉 <code>$a</code> 的值。那如果是沒有 key (流水號 key)的值，則會以附加在尾端 (append) 的方式合併上去，而所有流水號 key 的 index 則會重排。</p>

<!--more-->


<p>底下是一個簡單的例子：</p>

<figure class='code'><figcaption><span>array_merge</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="cp">&lt;?php</span>
</span><span class='line'><span class="nv">$arr_a</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="o">=&gt;</span><span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;b&#39;</span><span class="o">=&gt;</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="o">=&gt;</span><span class="mi">3</span><span class="p">);</span>
</span><span class='line'><span class="nv">$arr_b</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span><span class="s1">&#39;b&#39;</span><span class="o">=&gt;</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>
</span><span class='line'><span class="nb">var_dump</span><span class="p">(</span><span class="nb">array_merge</span><span class="p">(</span><span class="nv">$arr_a</span><span class="p">,</span> <span class="nv">$arr_b</span><span class="p">));</span>
</span></code></pre></td></tr></table></div></figure>


<p>結果為：</p>

<figure class='code'><figcaption><span>array_merge</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="x">array(5) {</span>
</span><span class='line'><span class="x">  [&quot;a&quot;]=&gt;</span>
</span><span class='line'><span class="x">  int(1)</span>
</span><span class='line'><span class="x">  [&quot;b&quot;]=&gt;</span>
</span><span class='line'><span class="x">  int(1)</span>
</span><span class='line'><span class="x">  [0]=&gt;</span>
</span><span class='line'><span class="x">  int(3)</span>
</span><span class='line'><span class="x">  [1]=&gt;</span>
</span><span class='line'><span class="x">  int(4)</span>
</span><span class='line'><span class="x">  [2]=&gt;</span>
</span><span class='line'><span class="x">  int(5)</span>
</span><span class='line'><span class="x">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>那如果是 <code>array + array</code> 的狀況，在有 key 的值的部分是相反的<strong>前蓋後</strong>，而沒有 key(流水號 key)的部分也會<strong>前蓋後</strong>，流水號 index 不會重排。我們用同樣的例子來觀察：</p>

<figure class='code'><figcaption><span>array + array</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="cp">&lt;?php</span>
</span><span class='line'><span class="nv">$arr_a</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span><span class="s1">&#39;a&#39;</span><span class="o">=&gt;</span><span class="mi">1</span><span class="p">,</span> <span class="s1">&#39;b&#39;</span><span class="o">=&gt;</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="o">=&gt;</span><span class="mi">3</span><span class="p">);</span>
</span><span class='line'><span class="nv">$arr_b</span> <span class="o">=</span> <span class="k">array</span><span class="p">(</span><span class="s1">&#39;b&#39;</span><span class="o">=&gt;</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>
</span><span class='line'><span class="nb">var_dump</span><span class="p">(</span><span class="nv">$arr_a</span> <span class="o">+</span> <span class="nv">$arr_b</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure>


<p>結果為：</p>

<figure class='code'><figcaption><span>array + array</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="x">array(4) {</span>
</span><span class='line'><span class="x">  [&quot;a&quot;]=&gt;</span>
</span><span class='line'><span class="x">  int(1)</span>
</span><span class='line'><span class="x">  [&quot;b&quot;]=&gt;</span>
</span><span class='line'><span class="x">  int(2)</span>
</span><span class='line'><span class="x">  [1]=&gt;</span>
</span><span class='line'><span class="x">  int(3)</span>
</span><span class='line'><span class="x">  [0]=&gt;</span>
</span><span class='line'><span class="x">  int(4)</span>
</span><span class='line'><span class="x">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>由此可知 <code>array + array</code> 和 <code>array_merge</code> 的行為是完全不一樣的，而大多數的情況陣列相加不會是我們想要的結果。請根據使用狀況謹慎選擇。</p>

<p>我只有在一個地方使用過陣列相加，在處理使用者設定的部分，系統有一個預設的設定陣列，使用者也會有使用者自訂的設定陣列，而使用者可能只設了其中幾項，這時把這兩個陣列相加，就可以組合出一個完整的使用者設定陣列，使用者沒設定的部分就由預設值陣列填補。</p>

<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='php'><span class='line'><span class="cp">&lt;?php</span>
</span><span class='line'><span class="o">...</span>
</span><span class='line'><span class="k">static</span> <span class="k">protected</span> <span class="k">function</span> <span class="nf">_fillWithDefault</span><span class="p">(</span><span class="nv">$settings</span><span class="p">)</span>
</span><span class='line'><span class="p">{</span>
</span><span class='line'>  <span class="nb">settype</span><span class="p">(</span><span class="nv">$settings</span><span class="p">,</span> <span class="s2">&quot;array&quot;</span><span class="p">);</span>
</span><span class='line'>  <span class="nv">$defaults</span> <span class="o">=</span> <span class="nx">self</span><span class="o">::</span><span class="na">getDefault</span><span class="p">();</span>
</span><span class='line'>  
</span><span class='line'>  <span class="k">foreach</span><span class="p">(</span><span class="nv">$settings</span> <span class="k">as</span> <span class="nv">$key</span><span class="o">=&gt;</span><span class="nv">$value</span><span class="p">)</span> <span class="p">{</span>
</span><span class='line'>      <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nb">array_key_exists</span><span class="p">(</span><span class="nv">$key</span><span class="p">,</span> <span class="nv">$defaults</span><span class="p">))</span> <span class="nb">unset</span><span class="p">(</span><span class="nv">$settings</span><span class="p">[</span><span class="nv">$key</span><span class="p">]);</span>
</span><span class='line'>  <span class="p">}</span>
</span><span class='line'>  
</span><span class='line'>  <span class="k">return</span> <span class="nv">$settings</span> <span class="o">+</span> <span class="nv">$defaults</span><span class="p">;</span>
</span><span class='line'><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>


<p>當然這個 case 寫成 <code>array_merge($defaults, $settings)</code> 也是可以達到一樣的效果，不過當時我覺得陣列相加效能較好，語意上也不會造成混淆，所以就採用這個寫法。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Obj-C 單元測試非同步連線]]></title>
    <link href="http://blog.hsatac.net/2012/10/obj-c-unit-test-with-asynchronous-request/" />
    <updated>2012-10-30T13:14:00+08:00</updated>
    <id>http://blog.hsatac.net/2012/10/obj-c-unit-test-with-asynchronous-request</id>
    <content type="html"><![CDATA[<p>使用 Xcode 的 OCUnit 來做單元測試網路連線時，由於 OCUnit 不會等 block 執行，所以會直接跳到 pass。一般正常作法應該是用 mock object 來測試，不過總有要實際測試真實連線的時候。這時可以使用以下的 snippet:</p>

<div><script src='https://gist.github.com/3978482.js?file='></script>
<noscript><pre><code>- (void)testLogin
{
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    [[miiiCasaServer getServer] login:@&quot;test@example.com&quot; andPassword:@&quot;password&quot; success:^(AFHTTPRequestOperation *operation, id responseObject) {
        assertThat(responseObject[@&quot;status&quot;], is(@&quot;ok&quot;));
        dispatch_semaphore_signal(semaphore);
    } failure:nil];
    while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW))
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                 beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
    dispatch_release(semaphore);   // You don't need this if your deployment target &gt;= 6.0 and ARC enabled.
}
- (void)testLoginFail
{
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    [[miiiCasaServer getServer] login:@&quot;test@example.com&quot; andPassword:@&quot;wrongpassword&quot; success:nil failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        assertThat([[error userInfo] objectForKey:@&quot;errmsg&quot;], containsString(@&quot;incorrect&quot;));
        assertThatInteger([error code], equalToInt(401));
        dispatch_semaphore_signal(semaphore);
    }];
    while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW))
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                 beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]];
    dispatch_release(semaphore);   // You don't need this if your deployment target &gt;= 6.0 and ARC enabled.
}</code></pre></noscript></div>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[關於我的 Logo]]></title>
    <link href="http://blog.hsatac.net/2012/10/about-my-logo/" />
    <updated>2012-10-21T11:07:00+08:00</updated>
    <id>http://blog.hsatac.net/2012/10/about-my-logo</id>
    <content type="html"><![CDATA[<p>在<a href="http://kvzhuang.blogspot.tw/2012/10/logo.html">莊神的部落格</a>被點名了，再加上我好像也沒講過我 Logo 的故事，只好發文解釋一下。</p>

<p><img src="http://www.loftwork.com/lw-content/users/8399/21a7cb1c760942198a0ace0efe362e78.gif" alt="Logo" /></p>

<!--more-->


<p>這個 Logo 是大學時代一個朋友傳給我的，一看就非常喜歡，比較熟的朋友大概都看得出來，完全能代表我這個人(笑)。所以馬上就拿來當 Logo 使用，一用就用到現在。</p>

<p>不過因為我朋友在網路掃圖掃太凶，他已經不記得這張圖是在哪裡取得，更不用說知道作者了，我一直很想知道這張圖的 license 獲得到原作者的授權，但始終無法找到，這件事就一直掛在我心上。</p>

<p>還好沒過多久，Google 推出了兇惡的「以圖找圖」功能，馬上就用這個功能下去找&#8230;&#8230;沒想到不知道是當初作者網站還沒建立起來、還是還沒索引到，又或者是那時以圖找圖搜尋技術還沒成熟，仍然是無功而返。</p>

<p>時光又過了一兩年，有一天我又突然想起這件事，再試著找看看，沒想到這時很精準的就找到了作者的網站。</p>

<p>作者是日本的 64CAT64 ，他的<a href="http://www.loftwork.com/portfolios/mushi/profile">網站</a>有許多他的作品。</p>

<p>找到作者後馬上寫 email 和他聯繫，解釋了一下我很喜歡這張圖，也用這張圖作為我的代表 Logo 許多年，想得知這張圖的 license ，看是否需要購買還是怎樣。</p>

<p>作者人非常好，只要我沒有拿來營利，他允許我免費使用他這張圖片，他也很高興我喜歡他的圖，只要我找個地方註記圖片作者的 URL 即可。所以後來我在 Blog footer 就加上了作者網站連結。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[同步 git 和 hg 的 repository]]></title>
    <link href="http://blog.hsatac.net/2012/10/sync-git-with-hg/" />
    <updated>2012-10-17T10:20:00+08:00</updated>
    <id>http://blog.hsatac.net/2012/10/sync-git-with-hg</id>
    <content type="html"><![CDATA[<p>最近在玩 go，編輯器主要是使用 vim 搭配 <a href="https://github.com/nsf/gocode">gocode</a>。我習慣用 <a href="https://github.com/tpope/vim-pathogen">pathogen.vim</a> 來管理我的 vim 套件，不過 go 官方附的 vim syntax plugin 和 gocode 提供的 autocompletion plugin 目錄結構都無法直接當成 git submodule 引入我的 vim 設定中。</p>

<p>由於我個人潔癖作祟，不想再用 copy 的方式來管理我的 vim plugins，所以我決定自己把這兩份 plugin 抽出來獨立成各自的 git repositories，就可以當成 git submodule 引用了。</p>

<!--more-->


<p>gocode 的部分很容易，他原本就是 git，只要參考我之前的文章「<a href="http://blog.hsatac.net/2012/04/moving-files-from-one-git-repository-to-another-keeping-commit-history/">把 Git 中的目錄搬到另一個 Git 並保留 Commit</a>」就可以了。不過 go 的部分就沒這麼簡單了。go 的原始碼 host 在 google code 上，採用 hg，因此要想辦法先把他由 hg 轉換成 git 才行。</p>

<p>一開始使用的是 <a href="http://hg-git.github.com/">hg-git</a> 這套，不過在 gexport 這個過程非常緩慢，不知道是這個套件本身有問題還是 go 的 hg repository 太大了。試了兩天之後只好放棄，改用 <a href="http://offbytwo.com/git-hg/">git-hg</a> 這套。這套一樣也是使用 python 寫的，不過效率上就挺不錯的。使用上也很方便，直接 <code>git-hg clone https://code.google.com/p/go/</code> 出來就是 git 的目錄了。</p>

<p>值得一提的是，使用 homebrew 安裝 git-hg 時，由於 git-hg 有 require <a href="http://repo.or.cz/w/fast-export.git">fast-export</a> 這個 submodule，但 homebrew 安裝下來的 fast-export 居然不是最新的，導致無法使用。後來自己到 <code>/usr/local/Cellar/git-hg/HEAD</code> 把 fast-export 這個目錄移除，再 clone 一份新的 fast-export 就可以正常使用了。</p>

<p>我不想弄亂這個目錄，所以我是在 local 端再 clone 一次這個使用 git-hg clone 下來的 repository，再來作 <code>git filter-branch</code> 的動作。另外這個 repository 也順便丟到 github 上當作一個 go 的 git mirror 給有需要的人使用。</p>

<p>產出三個 repositories:</p>

<ul>
<li><p><a href="https://github.com/golangtw/go.vim">https://github.com/golangtw/go.vim</a> go 的 syntax plugin</p></li>
<li><p><a href="https://github.com/golangtw/gocode.vim">https://github.com/golangtw/gocode.vim</a> gocode 的 autocomplete plugin</p></li>
<li><p><a href="https://github.com/golangtw/go">https://github.com/golangtw/go</a> go 的 git mirror</p></li>
</ul>


<p>最後再寫一個 script 每天跑一次 cronjob 自動去 sync 就完成啦！</p>

<div><script src='https://gist.github.com/3903435.js?file='></script>
<noscript><pre><code>#!/bin/sh

# do gocode first
cd /Users/cat/golang.tw/gocode
git pull
git filter-branch -f --subdirectory-filter vim -- --all
git push pathogen master
git fetch
git reset --hard origin/master

# do git-hg sync go
cd /Users/cat/golang.tw/go.git
git-hg pull
git push origin master

# do go.vim

cd /Users/cat/golang.tw/go.vim
git pull
git filter-branch -f --subdirectory-filter misc/vim -- --all
git push github master
git fetch
git reset --hard origin/master
</code></pre></noscript></div>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[8 款我最近常用的 command line 工具]]></title>
    <link href="http://blog.hsatac.net/2012/09/8-command-line-tools-i-have-been-using-lately/" />
    <updated>2012-09-28T13:45:00+08:00</updated>
    <id>http://blog.hsatac.net/2012/09/8-command-line-tools-i-have-been-using-lately</id>
    <content type="html"><![CDATA[<p>介紹八款我最近常用的 command line 工具，對開發很有幫助。</p>

<!--more-->


<h2>1. Mosh</h2>

<h3>說明</h3>

<p>不會斷線的 ssh
<a href="http://mosh.mit.edu/">http://mosh.mit.edu/</a></p>

<h3>安裝</h3>

<p>client 和 server 都需要安裝</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>packer mosh (Archlinux)
</span><span class='line'>yum install mosh (Centos)
</span><span class='line'>brew install mobile-shell (MacOS)</span></code></pre></td></tr></table></div></figure>


<h3>使用</h3>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>mosh ash_wu@myserver.com
</span><span class='line'>mosh myserver.com -- screen -rx</span></code></pre></td></tr></table></div></figure>


<h2>2. Mitmproxy</h2>

<h3>說明</h3>

<p>middleman proxy 可用來 debug , fiddler 的 *nix 版</p>

<p><a href="http://mitmproxy.org">http://mitmproxy.org</a></p>

<h3>安裝</h3>

<p>使用 python 套件管理 pip 安裝</p>

<p>有 https 需求的話則需要安裝他的憑證</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>pip install mitmproxy</span></code></pre></td></tr></table></div></figure>


<h3>使用</h3>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>mitmproxy
</span><span class='line'>mitmdump</span></code></pre></td></tr></table></div></figure>


<h3>擴充</h3>

<p>mitmproxy 提供許多 hook 可以自訂擴充，以 python 編寫即可。可參考我的文章</p>

<p><a href="http://blog.hsatac.net/2012/08/mitmproxy-modify-request-host-and-port-howto/">http://blog.hsatac.net/2012/08/mitmproxy-modify-request-host-and-port-howto/</a></p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>mitmproxy -s test.py</span></code></pre></td></tr></table></div></figure>


<h2>3. pdsh/pdcp/rpdcp</h2>

<h3>說明</h3>

<p>一次大量對許多機器下指令/複製檔案</p>

<h3>安裝</h3>

<p>要使用 pdcp 的話 client 和 server 都要裝</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>packer pdsh (Archlinux)
</span><span class='line'>yum install pdsh (Centos)
</span><span class='line'>brew install pdsh (MacOS)</span></code></pre></td></tr></table></div></figure>


<h3>使用</h3>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>pdsh -w web[01-10],static[7,9-10] ls
</span><span class='line'>pdcp -w ash_wu@dmyserver[1-2].com test.py /home/ash_wu/</span></code></pre></td></tr></table></div></figure>


<h2>4. htop</h2>

<h3>說明</h3>

<p>better top. 可以直接看 process tree, 直接砍掉</p>

<p><a href="http://htop.sourceforge.net/">http://htop.sourceforge.net/</a></p>

<h2>5. goaccess</h2>

<p>看 apache/nginx log</p>

<p><a href="http://goaccess.prosoftcorp.com/">http://goaccess.prosoftcorp.com/</a></p>

<h3>使用</h3>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>goaccess &lt;apache_access_log or nginx_access_log></span></code></pre></td></tr></table></div></figure>


<h2>6. ack, ag</h2>

<h3>說明</h3>

<p>Ack - Better than grep</p>

<p>Ag - Better than Ack</p>

<p>比 grep 更方便好用</p>

<p><a href="http://betterthangrep.com/">http://betterthangrep.com/</a></p>

<p><a href="https://github.com/ggreer/the_silver_searcher">https://github.com/ggreer/the_silver_searcher</a></p>

<h3>安裝</h3>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>packer the_silver_searcher
</span><span class='line'>brew install the_silver_searcher</span></code></pre></td></tr></table></div></figure>


<h3>同場加映</h3>

<p>ack.vim</p>

<p><a href="https://github.com/mileszs/ack.vim">https://github.com/mileszs/ack.vim</a></p>

<p>ag.vim</p>

<p><a href="https://github.com/epmatsw/ag.vim">https://github.com/epmatsw/ag.vim</a></p>

<h2>7. tig</h2>

<p>git CUI client</p>

<p><a href="https://github.com/jonas/tig">https://github.com/jonas/tig</a></p>

<h2>8. bashmarks</h2>

<h3>說明</h3>

<p>快速在目錄間切換</p>

<p><a href="https://github.com/huyng/bashmarks">https://github.com/huyng/bashmarks</a></p>

<h3>安裝</h3>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>git clone git://github.com/huyng/bashmarks.git
</span><span class='line'>make install
</span><span class='line'>source ~/.local/bin/bashmarks.sh from within your ~.bash_profile or ~/.bashrc file</span></code></pre></td></tr></table></div></figure>


<h3>使用</h3>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>s &lt;bookmark_name> - Saves the current directory as "bookmark_name"
</span><span class='line'>g &lt;bookmark_name> - Goes (cd) to the directory associated with "bookmark_name"
</span><span class='line'>p &lt;bookmark_name> - Prints the directory associated with "bookmark_name"
</span><span class='line'>d &lt;bookmark_name> - Deletes the bookmark
</span><span class='line'>l                 - Lists all available bookmarks</span></code></pre></td></tr></table></div></figure>



]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[身體調校聖經]]></title>
    <link href="http://blog.hsatac.net/2012/09/the-4-hours-body/" />
    <updated>2012-09-20T23:23:00+08:00</updated>
    <id>http://blog.hsatac.net/2012/09/the-4-hours-body</id>
    <content type="html"><![CDATA[<p><img src="http://blog.hsatac.net/images/the_4_hours_body/cover.jpg" alt="cover" /></p>

<blockquote><p>⋯⋯《身體調校聖經》所提供的，是對人類重建身體的全新探索，全盤收錄幾百位優異運動員、幾十位醫師，以及幾千小時讓人目瞪口呆的個人實驗智慧；從奧林匹克訓練中心到地下實驗室，從矽谷到南非，作者提摩西．費里斯念茲在茲的改變人生問題是：</p><p>　　對所有關於身體的事情，如何以最小的改變來創造最大的成果？⋯⋯</p></blockquote>


<p>前陣子很紅的《<a href="http://www.books.com.tw/exep/prod/booksfile.php?item=0010541859">身體調校聖經</a>》，看了許多人的心得和推薦以後覺得很有意思，也買了一本。</p>

<p>我的故事很平常，跟大多數人一樣，入伍時有著健康的好身材，退伍就業沒多久就因為天天坐在電腦前缺乏運動而發胖。從 70 kg 暴增到 90 kg。一直都有要減重的念頭，卻遲遲沒有實行。直到看了這本書。</p>

<!--more-->


<p>我覺得這本書給了我兩個很重要的觀念：一個是書中所提的「原宿時刻」。故事不在這邊細說，留給各位買書後自行閱讀。我就和故事的主角一樣，突然領悟到，在生命中我一直對最重要的資產——身體視而不見。下意識去忽略他。我知道我需要減重，我知道我要吃得健康，我知道我要維持運動。可是我總是什麼都不去做，就這樣等著看會不會有什麼神奇的事情發生。我每天在寫程式，學習新技術。不斷磨練自己，不斷改進自己的產品、開發流程。因為我知道每天都進步一點，持久下來就會很可觀。可是對自己身體的態度，我卻偏偏是我最瞧不起的那種人。意識到這點以後，要做改變一點都不困難了。</p>

<p>第二個我覺得很棒的觀點是：「測量」。</p>

<p>我從沒想過自己的身體也可以當玩具。我每個月都在買新玩具，沉迷於新玩具帶給我的刺激。但是陪伴我最久，離我最近的身體我居然沒想過要好好去研究他。書中提供了許多測量的方式和策略，只要有了測量和資料，我就可以分析方法是否有效，要如何改變或是繼續加強。就跟我們平時在優化程式、調校伺服器一樣。這不正是我們最擅長的嗎？</p>

<p>除了帶給我這兩點觀念外，書裡也充滿了許多有用的知識和各種你沒想過/沒聽過的調校方法。真的很值得買一本，偶爾隨手翻翻都好，會有意想不到的收穫。</p>

<p>最後附上我按書中提供的方法，選擇比較適合我生活型態的減重方式，運行一個月以來的成果。</p>

<p>我使用的是「低醣減脂法」。不吃米麥糖奶和水果，只吃菜肉蛋豆；不喝飲料，只喝開水或黑咖啡/無糖茶。每天早上起床一小時內一定吃早餐並且補充蛋白質。每週六是作弊日，可以盡情吃任何想吃的東西。</p>

<p>洗澡時洗冷水澡，並且固定時間測量自己的體重/體脂肪/腰圍等等。</p>

<p>從 8/21 實行到今天結束剛好 30 天整。我的成果：腰圍由 101 cm 縮減到 93 cm；體重從 92.3 kg 減輕到 86 kg。後面附的是我體重曲線圖。</p>

<p><img src="http://blog.hsatac.net/images/the_4_hours_body/weight.png" alt="weight" /></p>

<p>還沒達到我的理想體重，因此我還會再持續好一陣子。以前減重帶給我的只有節制和痛苦。但現在我和我自己的身體玩的不亦樂乎，再也不是一件令人難以忍受的事了。我對自己身體的探索，還會再繼續下去。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[開發 Golang 的 IDEs]]></title>
    <link href="http://blog.hsatac.net/2012/09/golang-ides/" />
    <updated>2012-09-19T00:34:00+08:00</updated>
    <id>http://blog.hsatac.net/2012/09/golang-ides</id>
    <content type="html"><![CDATA[<p>介紹一些開發 Golang 的 IDEs</p>

<p>首先是我慣常使用的 <a href="http://www.sublimetext.com/2">Sublime Text 2</a> 搭配  <a href="https://github.com/disposaboy/gosublime">gosublime</a> 外掛。</p>

<p><img src="http://blog.hsatac.net/images/golang_ides/subl.png" alt="gosublime" /></p>

<!--more-->


<p>以及也是我慣用的 vim + <a href="https://github.com/nsf/gocode/">gocode</a></p>

<p>在 <code>$GOROOT/misc/vim</code> 下已經有提供給 vim 使用的 syntax, indent, plugin 等，全部複製到 <code>~/.vim</code> 下面即可。如果不知道 go 安裝的位置可以使用 <code>go env</code> 來查詢。</p>

<p>按 gocode 的說明安裝完成後就可以在 vim 裡面使用 golang 的 autocompletion 了。</p>

<p><img src="http://blog.hsatac.net/images/golang_ides/vim.png" alt="vim + gocode" /></p>

<p>提了 vim 也不得不提 emacs. Emacs 一樣使用 <code>$GOROOT/misc/emacs</code> 下提供的檔案以及搭配 gocode 做自動完成。</p>

<p><img src="http://blog.hsatac.net/images/golang_ides/emacs.png" alt="emacs + gocode" /></p>

<p>再來介紹一個大陸開發的 <a href="http://code.google.com/p/golangide/">golangide</a> 相當優秀，也是跨三平台版本。安裝就可以使用了，不需要多餘的設定。</p>

<p><img src="http://blog.hsatac.net/images/golang_ides/golangide.png" alt="golangide" /></p>

<p><a href="http://code.google.com/p/goclipse/">goeclipse</a>
Golang 的 Eclipse plugin…Eclipse 現在完全是個萬能 editor.</p>

<p><img src="http://blog.hsatac.net/images/golang_ides/goeclipse.png" alt="goeclipse" /></p>

<p><a href="http://www.zeusedit.com/go.html">zeus</a> 是一個 windows 的 programming editor，也提供了深度支援開發 golang。</p>

<iframe width="560" height="315" src="http://www.youtube.com/embed/CZ5Yl0KnbKs" frameborder="0" allowfullscreen></iframe>




<iframe width="560" height="315" src="http://www.youtube.com/embed/84i7H-E0YUM" frameborder="0" allowfullscreen></iframe>


<p>Zeus 整合的相當好，包括 debugger, build manager, package manager 都有提供，比較有完整 IDE 的感覺。但完整版是要付費購買的。不管如何，選擇一個喜歡，順手合自己意的才是最重要的。</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[自動檢查 git branch 是否 merge 過]]></title>
    <link href="http://blog.hsatac.net/2012/08/git-branching-model-regular-check/" />
    <updated>2012-08-12T12:28:00+08:00</updated>
    <id>http://blog.hsatac.net/2012/08/git-branching-model-regular-check</id>
    <content type="html"><![CDATA[<p>按照一般 <a href="http://nvie.com/posts/a-successful-git-branching-model/">Git branching model</a> 來開發，當團隊人數稍多時，管理 Git branch 會變得有些麻煩。Branch 數量多之外，也很難記得哪些 branches 是已經 merge 進主幹、不再需要可以刪除；或者哪些 branches 沒有 merge 進主幹但已經放棄不用。這時就需要一些自動化的 script 幫助管理。</p>

<!--more-->


<p>本來是想全部用 bash 寫，不過功力不夠，最後還是偷懶用 ruby 了。</p>

<p>這個 script 會先檢查哪些 branches 已經 merge 過，如果沒有特殊理由就可以刪除了。也可以把刪除的動作寫在 script 讓他自動化，不過我這邊選擇保留一些手動的彈性。</p>

<p>再來是檢查哪些 branches 已經開很久了(開超過一個月)，卻又沒有 merge 進主幹，這時管理者可以看一下這些 branches 是否已經不再使用，可以刪除。</p>

<div><script src='https://gist.github.com/3246217.js?file='></script>
<noscript><pre><code>#!/usr/bin/env ruby
require 'rubygems'
require 'active_support'

merged = `cd /home/m/git/repositories/miiicasa.git &amp;&amp; git branch --merged master | grep -v master`
not_merged_cmd = 'cd /home/m/git/repositories/miiicasa.git &amp;&amp; git branch | grep -v master | grep -v support | grep -v qa'
for line in merged.split(&quot;\n&quot;)
  not_merged_cmd += '| grep -v ' + line
end
puts &quot;This is a regular check of miiiCasa.git branches\n&quot;
puts &quot;List below are branches already been merged into [master]:&quot;
puts &quot;Please check if they are still needed, grb delete them otherwise.\n&quot;
puts merged

puts &quot;\n--------------------\n\n&quot;

puts 'List below are branches order than 1 month and have NOT been merged into [master]:'
puts &quot;Please check if they are abandoned or forgotten.&quot;
not_merged = `#{not_merged_cmd}`
for line in not_merged
  date =  /\S+_([0-9]+)_/.match(line)[1]
  puts line if 1.month.ago &gt; Date.parse(date)
end</code></pre></noscript></div>


<p>我們團隊對於 branch 命名有規定，中間一定是八位數字的日期，例如 feature_20120812_sthcool 以便分辨這個 branch 的開創時間。如果沒有這樣的命名規定的話，也可以透過下面這樣的 script 來找出最後 active 的時間。</p>

<figure class='code'><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class=''><span class='line'>for k in `git branch|perl -pe s/^..//`;do echo -e `git show --pretty=format:"%Cgreen%ci %Cblue%cr%Creset" $k|head -n 1`\\t$k;done|sort -r</span></code></pre></td></tr></table></div></figure>

]]></content>
  </entry>
  
</feed>
