tag:blogger.com,1999:blog-114384392024-02-28T13:53:45.300+08:00Joe這個地方,記錄著我生活中的點點滴滴…
老的時候,就可以抱著孫子看著這blog說「你看,爺爺當初也蠢過!」joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.comBlogger225125tag:blogger.com,1999:blog-11438439.post-33909979336408064382015-11-22T00:50:00.001+08:002015-11-22T00:50:40.785+08:00[Docker] Push Error<h1 id="docker-push-error">[Docker] Push Error</h1>
<blockquote>
<p>這篇同步發佈在我的<a href="http://blog.joecwu.com/2015/11/docker-push-error.html">Blog</a>和<a href="https://gist.github.com/joecwu/85d31be6b0d3d1edd936">Gist</a>。</p>
</blockquote>
<h2 id="背景">背景</h2>
<p>上一篇<a href="http://blog.joecwu.com/2015/11/docker-private-registory.html">Docker Private Registory</a>提到,在公司架了Docker Registory,基於安全考量,Port當然是沒有對外開放,而平常在家裡要連回公司,就是使用VPN連到公司來存取公司內部的Services。</p>
<p>由於目前草創初期,CI還沒架設起來,所以目前是使用local build & publish到Docker Repository。</p>
<h2 id="問題">問題</h2>
<p>今天在家裡改完了一些Code,要把build上傳到公司的Docker Registry的時候,發現了下面的錯誤:</p>
<pre class="prettyprint"><code class=" hljs mathematica">Joes-MBP:admin-backend-api joecwu$ docker push <span class="hljs-list">{host}</span>:<span class="hljs-list">{port}</span>/xxx/admin-backend-api:<span class="hljs-number">0.1</span><span class="hljs-number">.17</span>
The push refers to a repository [<span class="hljs-list">{host}</span>:<span class="hljs-list">{port}</span>/xxx/admin-backend-api] (len: <span class="hljs-number">1</span>)
Sending image list
<span class="hljs-keyword">Put</span> http://<span class="hljs-list">{host}</span>:<span class="hljs-list">{port}</span>/v1/repositories/xxx/admin-backend-api/: dial tcp: lookup <span class="hljs-list">{host}</span> on <span class="hljs-number">192.168</span><span class="hljs-number">.70</span><span class="hljs-number">.254</span>:<span class="hljs-number">53</span>: read udp <span class="hljs-number">192.168</span><span class="hljs-number">.70</span><span class="hljs-number">.254</span>:<span class="hljs-number">53</span>: i/o timeout</code></pre>
<p>明明已經連到公司的VPN了,IP也ping得到,<code>192.168.70.254</code>是gateway,也都能正常連到他,為什麼會有這樣的錯誤?</p>
<h2 id="解法">解法</h2>
<p>這讓我想到了在公司有一台開發機,是使用無線網卡連公司的網路,有時無線網卡會不穩,網路會斷掉再重連,而這時這台開發機裡所架設的docker-machine會無法從外部連到,必需重新啟動docker-machine(也就是virtual box的VM),讓VM的網路組態重新更新之後才能正常存取。</p>
<p>因此簡單的把我的Mac上的docker-machine restart,之後這個問題就解決了,就能正常的上傳build嘍!</p>joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-20847652026400312622015-11-07T17:22:00.001+08:002015-11-07T17:28:24.158+08:00[Docker] Private Registry<h1 id="docker-private-registry">[Docker] Private Registry</h1>
<blockquote>
<p>這篇同步發佈在我的<a href="http://blog.joecwu.com/2015/11/docker-private-registry.html">Blog</a>和<a href="https://gist.github.com/joecwu/0ee2e4512715dbf511ca">Gist</a>。</p>
</blockquote>
<h2 id="前言">前言</h2>
<p>最近開始run startup,非常忙碌,沒什麼時間寫blog,但是有些難找的東西,還是要記錄一下,看看能不能幫到別人。</p>
<p>之前主要專注在backend,現在自己要負責所有技術的東西,最近一直在看front-end的新技術<strong>們</strong>,真的多到看不完耶,除了dev,ops的東西也要一併處理,所以就有這篇文章的出現…</p>
<p>不熟Docker的朋友們,請先閱讀這篇<a href="https://philipzheng.gitbooks.io/docker_practice/content/">Docker – 從入門到實踐</a>。</p>
<p>Docker這麼紅、這麼方便,一定要用的啊!但除了用Docker Hub(公共repostiry)上了image,我自己寫開發的app,不可能放出去,所以會要架自己的Docker Registry來放,以方便內部佈置與自動化機制的建置。</p>
<h2 id="背景">背景</h2>
<p>以下是我的環境 <br>
<strong>Docker Registry:</strong> Synology DS415+ with latest docker-registry version <br>
<strong>Docker Client:</strong> Mac OSX 10.11.1 with Docker 1.8.3 <br>
<strong>Docker Publish Env:</strong> SBT Native Packager</p>
<h2 id="private-docker-registry">Private Docker Registry</h2>
<p>安裝Private Docker Registry很簡單,官方就有<code>registry</code>的image,直接抓下來用就行! 網路上也有很多文章教你怎麼用,這裡就不多說了。</p>
<p>但我遇到的問題就是,預設Docker Registry是”安全的”,也就是他會要求你走TLS,這樣對於沒有certificate的使用者,就無法用了。</p>
<p>我試著要從sbt-native-packager使用<code>docker:publish</code>的時候,發生了下面的錯誤,一度以為是我的Registry沒灌好…</p>
<pre class="prettyprint"><code class=" hljs mel">[<span class="hljs-keyword">error</span>] unable to ping registry endpoint https:<span class="hljs-comment">//192.168.1.2:6000/v0/</span>
[<span class="hljs-keyword">error</span>] v2 ping attempt failed with <span class="hljs-keyword">error</span>: Get https:<span class="hljs-comment">//192.168.1.2:6000/v2/: EOF</span>
[<span class="hljs-keyword">error</span>] v1 ping attempt failed with <span class="hljs-keyword">error</span>: Get https:<span class="hljs-comment">//192.168.1.2:6000/v1/_ping: EOF</span>
[<span class="hljs-keyword">trace</span>] Stack <span class="hljs-keyword">trace</span> suppressed: run last docker:publish <span class="hljs-keyword">for</span> the full output.
[<span class="hljs-keyword">error</span>] (docker:publish) Nonzero exit value: <span class="hljs-number">1</span>
[<span class="hljs-keyword">error</span>] Total time: <span class="hljs-number">9</span> s, completed Nov <span class="hljs-number">6</span>, <span class="hljs-number">2015</span> <span class="hljs-number">7</span>:<span class="hljs-number">59</span>:<span class="hljs-number">57</span> PM</code></pre>
<p>但是後來眼尖的發現,他連的是<code>https</code>…</p>
<h2 id="insecure-registry">Insecure Registry</h2>
<p>那我們就讓他”不安全”吧!</p>
<p>官方有寫這篇<a href="https://docs.docker.com/registry/insecure/">Insecure Registry</a>,提到兩個方式:</p>
<ol>
<li>直接用 <code>DOCKER_OPTS="--insecure-registry myregistrydomain.com:5000"</code> 告訴你的docker daemon不要去檢查registry的安全性,好處是很簡單的設定,壞處是非常不安全,而且你要設定每一個docker daemon (就是每一台要連registry的機器都要設)。</li>
<li>使用自己簽的certificate。這個東西有點複雜,下次再來研究。</li>
</ol>
<p>ps: 本來嘗試要從sbt-native-package下手,但官方說法是這應該要從docker daemon下手,他們也無能為力。,</p>
<h2 id="動手做">動手做</h2>
<p>這邊我要做的是#1的solution,但是發現在Mac上好像跟官方說的方式不太一樣,後來查了<a href="https://github.com/docker/docker-registry/issues/1005">這篇</a>,才找到這個方法來解決。</p>
<p>修改Mac內的docker-machine</p>
<pre class="prettyprint"><code class="language-bash hljs ">Joes-MBP:admin-backend-api joecwu$ docker-machine ssh default
<span class="hljs-comment">## .</span>
<span class="hljs-comment">## ## ## ==</span>
<span class="hljs-comment">## ## ## ## ## ===</span>
/<span class="hljs-string">""</span><span class="hljs-string">""</span><span class="hljs-string">""</span><span class="hljs-string">""</span><span class="hljs-string">""</span><span class="hljs-string">""</span><span class="hljs-string">""</span><span class="hljs-string">""</span><span class="hljs-string">"\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\_______/
_ _ ____ _ _
| |__ ___ ___ | |_|___ \ __| | ___ ___| | _____ _ __
| '_ \ / _ \ / _ \| __| __) / _` |/ _ \ / __| |/ / _ \ '__|
| |_) | (_) | (_) | |_ / __/ (_| | (_) | (__| < __/ |
|_.__/ \___/ \___/ \__|_____\__,_|\___/ \___|_|\_\___|_|
Boot2Docker version 1.8.3, build master : af8b089 - Mon Oct 12 18:56:54 UTC 2015
Docker version 1.8.3, build f4bf5c7
docker@default:~$ sudo vi /var/lib/boot2docker/profile</span></code></pre>
<p><code>/var/lib/boot2docker/profile</code> 內,增加一行 <code>--insecure-registry 192.168.1.2:6000</code></p>
<pre class="prettyprint"><code class=" hljs ruby"><span class="hljs-constant">EXTRA_ARGS</span>=<span class="hljs-string">'
--label provider=virtualbox
--insecure-registry 192.168.1.2:6000
'</span>
<span class="hljs-constant">CACERT</span>=<span class="hljs-regexp">/var/lib</span><span class="hljs-regexp">/boot2docker/ca</span>.pem
<span class="hljs-constant">DOCKER_HOST</span>=<span class="hljs-string">'-H tcp://0.0.0.0:2376'</span>
<span class="hljs-constant">DOCKER_STORAGE</span>=aufs
<span class="hljs-constant">DOCKER_TLS</span>=auto
<span class="hljs-constant">SERVERKEY</span>=<span class="hljs-regexp">/var/lib</span><span class="hljs-regexp">/boot2docker/server</span>-key.pem
<span class="hljs-constant">SERVERCERT</span>=<span class="hljs-regexp">/var/lib</span><span class="hljs-regexp">/boot2docker/server</span>.pem</code></pre>
<p>重新啟動docker-machine</p>
<pre class="prettyprint"><code class=" hljs lasso">Joes<span class="hljs-attribute">-MBP</span>:admin<span class="hljs-attribute">-backend</span><span class="hljs-attribute">-api</span> joecwu$ docker<span class="hljs-attribute">-machine</span> stop default
Joes<span class="hljs-attribute">-MBP</span>:admin<span class="hljs-attribute">-backend</span><span class="hljs-attribute">-api</span> joecwu$ docker<span class="hljs-attribute">-machine</span> start default
Starting VM<span class="hljs-attribute">...</span>
Started machines may have <span class="hljs-literal">new</span> IP addresses<span class="hljs-built_in">.</span> You may need <span class="hljs-keyword">to</span> re<span class="hljs-attribute">-run</span> the <span class="hljs-string">`docker-machine env`</span> command<span class="hljs-built_in">.</span></code></pre>
<h2 id="result">Result</h2>
<p>Run <code>docker:publish</code></p>
<pre class="prettyprint"><code class=" hljs r">> docker:publish
[info] Wrote ........./admin-backend-api_2.11-<span class="hljs-number">0.1</span><span class="hljs-number">.0</span>.pom
[info] Sending build context to Docker daemon <span class="hljs-number">557.1</span> kB
[info] Sending build context to Docker daemon <span class="hljs-number">1.114</span> MB
[info] Step <span class="hljs-number">7</span> : CMD
[info] ---> Using cache
[info] ---> 48923d750c11
[info] Successfully built 48923d750c11
[info] Built image <span class="hljs-number">192.168</span><span class="hljs-number">.1</span><span class="hljs-number">.2</span>:<span class="hljs-number">6000</span>/kiri/admin-backend-api:<span class="hljs-number">0.1</span><span class="hljs-number">.0</span>
[info] The push refers to a repository [<span class="hljs-number">192.168</span><span class="hljs-number">.1</span><span class="hljs-number">.2</span>:<span class="hljs-number">6000</span>/kiri/admin-backend-api] (len: <span class="hljs-number">1</span>)
[info] Sending image list
[info] Pushing repository <span class="hljs-number">192.168</span><span class="hljs-number">.1</span><span class="hljs-number">.2</span>:<span class="hljs-number">6000</span>/kiri/admin-backend-api (<span class="hljs-number">1</span> tags)
<span class="hljs-keyword">...</span>
[info] 48923d750c11: Pushing
[info] 48923d750c11: Image successfully pushed
[info] Pushing tag <span class="hljs-keyword">for</span> rev [48923d750c11] on {http://<span class="hljs-number">192.168</span><span class="hljs-number">.1</span><span class="hljs-number">.2</span>:<span class="hljs-number">6000</span>/v1/repositories/kiri/admin-backend-api/tags/<span class="hljs-number">0.1</span><span class="hljs-number">.0</span>}
[info] Published image <span class="hljs-number">192.168</span><span class="hljs-number">.1</span><span class="hljs-number">.2</span>:<span class="hljs-number">6000</span>/kiri/admin-backend-api:<span class="hljs-number">0.1</span><span class="hljs-number">.0</span></code></pre>
<pre class="prettyprint"><code class="language-bash hljs ">Joes-MacBook-Pro:~ joecwu$ curl -i http://<span class="hljs-number">192.168</span>.<span class="hljs-number">1.2</span>:<span class="hljs-number">6000</span>/v1/search
HTTP/<span class="hljs-number">1.1</span> <span class="hljs-number">200</span> OK
Server: gunicorn/<span class="hljs-number">19.1</span>.<span class="hljs-number">1</span>
Date: Sat, <span class="hljs-number">07</span> Nov <span class="hljs-number">2015</span> <span class="hljs-number">08</span>:<span class="hljs-number">51</span>:<span class="hljs-number">54</span> GMT
Connection: keep-alive
Expires: -<span class="hljs-number">1</span>
Content-Type: application/json
Pragma: no-cache
Cache-Control: no-cache
Content-Length: <span class="hljs-number">99</span>
{<span class="hljs-string">"num_results"</span>: <span class="hljs-number">1</span>, <span class="hljs-string">"query"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"results"</span>: [{<span class="hljs-string">"description"</span>: <span class="hljs-string">""</span>, <span class="hljs-string">"name"</span>: <span class="hljs-string">"kiri/admin-backend-api"</span>}]}</code></pre>joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-35944602256092551302015-09-06T07:13:00.001+08:002015-09-06T07:14:27.794+08:00[Scala In Depth] Scala Case Classes<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>[Scala In Depth] Scala Case Classes</title>
<link rel="stylesheet" href="http://yandex.st/highlightjs/7.5/styles/github.min.css">
<script src="http://yandex.st/highlightjs/7.5/highlight.min.js"></script>
</head>
<body><h1 id="scala-in-depth-scala-case-classes">[Scala In Depth] Scala Case Classes</h1>
<blockquote>
<p>這篇同步發佈在我的<a href="http://blog.joecwu.com/2015/09/scala-in-depth-scala-case-classes.html">Blog</a>和<a href="https://gist.github.com/joecwu/8bdaf1c09a684eccaa62">Gist</a>。</p>
</blockquote>
<p>這篇文章,基本上是參考這篇<a href="http://www.alessandrolacava.com/blog/scala-case-classes-in-depth/">Scala Case Classes In Depth</a>來寫的,閱讀吸收後以我的例子與描述方式以中文寫下。</p>
<h2 id="大家對case-class基本的認識">大家對Case Class基本的認識</h2>
<ul>
<li>定義一個簡單的類型(class)並在宣告的時候直接定義好有哪些參數。</li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs javascript"><span class="hljs-keyword">case</span> <span class="hljs-keyword">class</span> User(region: <span class="hljs-built_in">String</span>, id: <span class="hljs-built_in">String</span>, name: <span class="hljs-built_in">String</span>)</code></pre>
<ul>
<li>可以簡單的用來建立某個類型(class)的物件,因為case class已經實作了apply,所以可省略<code>new</code>這個宣告方式,來建立新物件。</li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs fsharp"><span class="hljs-keyword">val</span> joe = User(<span class="hljs-string">"TW"</span>,<span class="hljs-string">"123"</span>,<span class="hljs-string">"Joe"</span>)
joe: User = User(TW,<span class="hljs-number">123</span>,Joe)</code></pre>
<ul>
<li>每個參數的宣告都被加上了<code>val</code>的前綴(prefix),也就是這個class基本上每個property都是immutable(不能被修改的)。</li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs fsharp"><span class="hljs-keyword">val</span> region = joe.region
<span class="hljs-comment">// 下面這行在compile會錯誤</span>
joe.region = <span class="hljs-string">"US"</span>
<console>:<span class="hljs-number">23</span>: error: reassignment <span class="hljs-keyword">to</span> <span class="hljs-keyword">val</span></code></pre>
<ul>
<li>當然有一些基本的implementation,像是<code>hashCode</code>, <code>euqals</code>和<code>toString</code>…等,而在scala中,<code>==</code>基本上就是執行<code>equal</code>,所以在case class用<code>==</code>去比較的時候,是用整個結構會去比的(而非比reference)。</li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs javascript">scala> val joe2 = User(<span class="hljs-string">"TW"</span>,<span class="hljs-string">"123"</span>,<span class="hljs-string">"Joe"</span>)
joe2: User = User(TW,<span class="hljs-number">123</span>,Joe)
scala> joe == joe2
res: <span class="hljs-built_in">Boolean</span> = <span class="hljs-literal">true</span>
scala> val joe3 = User(<span class="hljs-string">"TW"</span>,<span class="hljs-string">"124"</span>,<span class="hljs-string">"Joe"</span>)
joe3: User = User(TW,<span class="hljs-number">124</span>,Joe)
scala> joe == joe3
res54: <span class="hljs-built_in">Boolean</span> = <span class="hljs-literal">false</span></code></pre>
<ul>
<li>要複製的時候,可以使用<code>copy</code>,若有要修改的屬性,再copy當中宣告即可</li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs avrasm">scala> joe<span class="hljs-preprocessor">.copy</span>(region=<span class="hljs-string">"US"</span>)
<span class="hljs-label">res:</span> User = User(US,<span class="hljs-number">123</span>,Joe)</code></pre>
<ul>
<li>有實作<code>unapply</code>,所以在pattern matching可以直接使用。</li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs applescript">scala> val User(region,<span class="hljs-property">id</span>,<span class="hljs-property">name</span>) = joe
region: String = TW
<span class="hljs-property">id</span>: String = <span class="hljs-number">123</span>
<span class="hljs-property">name</span>: String = Joe
scala> joe match {
| case User(_,<span class="hljs-property">id</span>,_) => println(s<span class="hljs-string">"id:[$id]"</span>)
| }
<span class="hljs-property">id</span>:[<span class="hljs-number">123</span>]</code></pre>
<ul>
<li>如果在宣告case class的時候,並沒有要給任何的參數,就像是定義<a href="https://en.wikipedia.org/wiki/Algebraic_data_type">ADT(Algebraic Data Type)</a>的時候,我們有可能會宣告到一個沒有任何參數的class,這時候可以用<code>case object</code>來宣告。</li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs scala"><span class="hljs-keyword">sealed</span> <span class="hljs-class"><span class="hljs-keyword">trait</span> <span class="hljs-title">Life</span>[+<span class="hljs-title">T</span>]</span>
<span class="hljs-class"><span class="hljs-keyword">case</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Alive</span>[<span class="hljs-title">T</span>]<span class="hljs-params">(value: T)</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Life</span>[<span class="hljs-title">T</span>]</span>
<span class="hljs-keyword">case</span> <span class="hljs-class"><span class="hljs-keyword">object</span> <span class="hljs-title">Dead</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Life</span>[<span class="hljs-title">Nothing</span>]</span>
scala> <span class="hljs-keyword">def</span> check(life:Life[User]) = life <span class="hljs-keyword">match</span> {
| <span class="hljs-keyword">case</span> Alive(user) => println(user.name)
| <span class="hljs-keyword">case</span> Dead => println(<span class="hljs-string">"dead"</span>)
| }
check: (life: Life[User])Unit
scala> check(Alive(joe))
Joe
scala> check(Dead)
dead</code></pre>
<h2 id="一些case-class進階的認識">一些case class進階的認識</h2>
<ul>
<li>如果你需要建立一個function,而這個function要傳入所有產生這個class的參數,最後要產生這個class的object的話,你可以使用<code>apply</code></li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs cmake">// 這裡的 _ 是因為要把apply這個<span class="hljs-keyword">function</span>指派給變數來用,如果不加上 _ 的話,會被當成是要執行這個<span class="hljs-keyword">function</span>而又因為後面沒有帶所需要的參數造成compile錯誤。
scala> val userCreator = User.apply _
userCreator: (<span class="hljs-keyword">String</span>, <span class="hljs-keyword">String</span>, <span class="hljs-keyword">String</span>) => User = <function3>
scala> val uerica = userCreator(<span class="hljs-string">"TW"</span>,<span class="hljs-string">"66"</span>,<span class="hljs-string">"Uerica"</span>)
uerica: User = User(TW,<span class="hljs-number">66</span>,Uerica)</code></pre>
<ul>
<li><code>curried</code>,如果你要把上面這個用法,拆成是curry的話,可以使用<code>curried</code>的方式,把這些參數給拆開來,方便組合使用。</li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs cmake">scala> val curriedUser = User.curried
curriedUser: <span class="hljs-keyword">String</span> => (<span class="hljs-keyword">String</span> => (<span class="hljs-keyword">String</span> => User)) = <function1>
// 上面其實就變成了一種這樣 (region: <span class="hljs-keyword">String</span>)(id: <span class="hljs-keyword">String</span>)(name: <span class="hljs-keyword">String</span>) : User 的<span class="hljs-keyword">function</span>
scala> val twUserCreator = curriedUser(<span class="hljs-string">"TW"</span>)
twUserCreator: <span class="hljs-keyword">String</span> => (<span class="hljs-keyword">String</span> => User) = <function1>
scala> val samael = twUserCreator(<span class="hljs-string">"111"</span>)(<span class="hljs-string">"Samael"</span>)
samael: User = User(TW,<span class="hljs-number">111</span>,Samael)</code></pre>
<ul>
<li><code>tupled</code>,前面提到的<code>apply</code>是建立一個function並傳入對應class properties數量的參數,而若想要傳入的是一個<code>tuple</code>,就可以使用<code>tupled</code>。</li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs lasso">scala<span class="hljs-subst">></span> User<span class="hljs-built_in">.</span>tupled
res67: ((<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>)) <span class="hljs-subst">=></span> User <span class="hljs-subst">=</span> <span class="hljs-subst"><</span>function1<span class="hljs-subst">></span>
<span class="hljs-comment">//上面這個與之前的apply不同,多了一組刮號,因為這傳入的是tuple</span>
scala<span class="hljs-subst">></span> val tupledJoe <span class="hljs-subst">=</span> (<span class="hljs-string">"TW"</span>,<span class="hljs-string">"123"</span>,<span class="hljs-string">"Joe"</span>)
tupledJoe: (<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>) <span class="hljs-subst">=</span> (TW,<span class="hljs-number">123</span>,Joe)
scala<span class="hljs-subst">></span> User<span class="hljs-built_in">.</span>tupled(tupledJoe)
res: User <span class="hljs-subst">=</span> User(TW,<span class="hljs-number">123</span>,Joe)</code></pre>
<ul>
<li><code>unapply</code>,當我們需要一個function,是傳入某個類型的物件,然後希望回傳的是<code>Option[TupleN[A1, A2, ..., AN]]</code>,將N個參數分別包成tuple,然後用Option包起來(這邊用Option有可能是因為要handle這物件可能不存在的情況),這種時候就能直接使用<code>unapply</code>。</li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs vbnet">scala> val toOptionOfTuple = User.unapply _
toOptionOfTuple: User => <span class="hljs-keyword">Option</span>[(<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>)] = <function1>
scala> toOptionOfTuple(joe)
res: <span class="hljs-keyword">Option</span>[(<span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>)] = Some((TW,<span class="hljs-number">123</span>,Joe))</code></pre>
<h2 id="當使用curried的形式來建立一個case-class時">當使用<code>curried</code>的形式來建立一個case class時…</h2>
<p>這篇文章提到了一點,就是我們可以用<code>curried</code>的形式來建立一個case class,就像是下面的例子。</p>
<pre class="prettyprint"><code class="language-Scala hljs scala">scala> <span class="hljs-class"><span class="hljs-keyword">case</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Person</span><span class="hljs-params">(fingerPrint: Long)</span><span class="hljs-params">(name: String, dress: String)</span></span>
defined <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span></span>
scala> <span class="hljs-keyword">val</span> j = Person(<span class="hljs-number">123123</span>l)(<span class="hljs-string">"Joe"</span>,<span class="hljs-string">"Suit"</span>)</code></pre>
<p>至於<strong>什麼時候要這樣用?</strong>以及<strong>該怎麼用?用了會發生什麼事?</strong>,我們分別來說明。</p>
<h3 id="什麼時候要這樣用">什麼時候要這樣用?</h3>
<p>如果真的有一種情況,就是在你的設計需求上,希望一個物件的比對是只依照某個部份的property,例如我的例子是只要指紋是一樣的,就是同一個人,不論他的名字、裝扮如何。</p>
<pre class="prettyprint"><code class="language-Scala hljs fsharp">scala> <span class="hljs-keyword">val</span> j = Person(<span class="hljs-number">123123</span>l)(<span class="hljs-string">"Joe"</span>,<span class="hljs-string">"Suit"</span>)
scala> <span class="hljs-keyword">val</span> q = Person(<span class="hljs-number">123123</span>l)(<span class="hljs-string">"Andy"</span>,<span class="hljs-string">"Casual"</span>)
scala> j==q
res: Boolean = <span class="hljs-keyword">true</span></code></pre>
<h3 id="該怎麼用用了會發生什麼事">該怎麼用?用了會發生什麼事?</h3>
<p><code>curried</code>的部份,並沒有實作前面提到case class的那些特性,也就是說,下面這幾點都會有問題:</p>
<ul>
<li>沒有實作<code>val</code>的前綴,所以不能直接存取這些properties</li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs applescript">scala> j.<span class="hljs-property">name</span>
<console>:<span class="hljs-number">24</span>: <span class="hljs-keyword">error</span>: value <span class="hljs-property">name</span> <span class="hljs-keyword">is</span> <span class="hljs-keyword">not</span> a member <span class="hljs-keyword">of</span> Person
j.<span class="hljs-property">name</span>
^</code></pre>
<p>所以我們必須自己加上<code>val</code>的宣告</p>
<pre class="prettyprint"><code class="language-Scala hljs scala">scala> <span class="hljs-class"><span class="hljs-keyword">case</span> <span class="hljs-keyword">class</span> <span class="hljs-title">Person</span><span class="hljs-params">(fingerPrint: Long)</span><span class="hljs-params">(val name: String, val dress: String)</span></span>
defined <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Person</span></span>
scala> <span class="hljs-keyword">val</span> j = Person(<span class="hljs-number">123123</span>l)(<span class="hljs-string">"Joe"</span>,<span class="hljs-string">"Suit"</span>)
j: Person = Person(<span class="hljs-number">123123</span>)
scala> j.name
res: String = Joe</code></pre>
<ul>
<li>當然用<code>copy</code>的時候,也就知道後面<code>curried</code>的部份也沒有實作<code>copy</code>,所以你必需帶所有的參數。</li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs applescript">scala> j.<span class="hljs-keyword">copy</span>()(<span class="hljs-property">name</span> = <span class="hljs-string">"David"</span>)
<console>:<span class="hljs-number">25</span>: <span class="hljs-keyword">error</span>: <span class="hljs-keyword">not</span> enough arguments <span class="hljs-keyword">for</span> method <span class="hljs-keyword">copy</span>: (<span class="hljs-property">name</span>: String, dress: String)Person.
Unspecified value parameter dress.
j.<span class="hljs-keyword">copy</span>()(<span class="hljs-property">name</span> = <span class="hljs-string">"David"</span>)
^
scala> j.<span class="hljs-keyword">copy</span>()(<span class="hljs-property">name</span> = <span class="hljs-string">"David"</span>, dress = <span class="hljs-string">"Dirty"</span>)
res80: Person = Person(<span class="hljs-number">123123</span>)</code></pre>
<ul>
<li>其他的像是<code>tupled</code>當然也都不能用嘍!</li>
</ul>
<h2 id="因為case-class繼承product這個trait而所得到的能力">因為case class繼承<code>Product</code>這個<code>trait</code>而所得到的能力</h2>
<ul>
<li><code>def productArity: Int</code>,這個function可以得到這個case class的object有多少個properties。</li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs avrasm">scala> joe<span class="hljs-preprocessor">.productArity</span>
<span class="hljs-label">res:</span> Int = <span class="hljs-number">3</span>
// 這<span class="hljs-number">3</span>個就是region, id, name</code></pre>
<ul>
<li><code>def productElement(n: Int): Any</code>,取得某個指定的Element。<strong>注意:這裡的回傳type是Any哦!</strong></li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs avrasm">scala> joe<span class="hljs-preprocessor">.productElement</span>(<span class="hljs-number">2</span>)
<span class="hljs-label">res:</span> Any = Joe</code></pre>
<ul>
<li><code>def productIterator: Iterator[Any]</code>,把每個properties iterate出來。 <br>
<strong>這裡提醒一些不熟scala的朋友,iterator這裡若用map會發現怎麼沒有被執行到,要先<code>toList</code>或是用foreach才會執行,這是因為iterator的特性。</strong></li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs avrasm">scala> joe<span class="hljs-preprocessor">.productIterator</span><span class="hljs-preprocessor">.foreach</span>(println)
TW
<span class="hljs-number">123</span>
Joe</code></pre>
<ul>
<li><code>def productPrefix: String</code>,以字串的形式取得case class object的型態。</li>
</ul>
<pre class="prettyprint"><code class="language-Scala hljs avrasm">scala> joe<span class="hljs-preprocessor">.productPrefix</span>
<span class="hljs-label">res:</span> String = User</code></pre></body>
</html>joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-50973364053691843122015-08-27T02:59:00.001+08:002015-08-27T03:00:00.408+08:00[ScaVa->Scala] Scalaz Stream 串流好朋友 part 2<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>[ScaVa->Scala] Scalaz Stream 串流好朋友 part 2</title>
<link rel="stylesheet" href="http://yandex.st/highlightjs/7.5/styles/github.min.css">
<script src="http://yandex.st/highlightjs/7.5/highlight.min.js"></script>
</head>
<body><h1 id="scava-scala-scalaz-stream-串流好朋友-part-2">[ScaVa->Scala] Scalaz Stream 串流好朋友 part 2</h1>
<blockquote>
<p>這篇同步發佈在我的<a href="http://blog.joecwu.com/2015/08/scava-scala-scalaz-stream-part-2.html">Blog</a>和<a href="https://gist.github.com/joecwu/fd28b678585f89c746b0">Gist</a>。</p>
</blockquote>
<h2 id="前情提要">前情提要</h2>
<p>請看<a href="http://blog.joecwu.com/2015/08/scava-scala-scalaz-stream-part-1.html">[ScaVa->Scala] Scalaz Stream 串流好朋友 part 1</a>或<a href="https://gist.github.com/joecwu/525aaf0b9b886eb68b74">Gist版本</a>。</p>
<h2 id="怎麼使用process">怎麼使用Process?</h2>
<h3 id="使用monad的功能map-flatmap">使用Monad的功能<code>map</code>, <code>flatMap</code></h3>
<p>首先,<code>Process</code>是Monad,所以Monad使用上的特性也是<code>Process</code>好用的特色,因此<code>map</code>, <code>flatMap</code>…等這些Moand的特性都能使用。</p>
<pre class="prettyprint"><code class="language-Scala hljs avrasm">case class Article(id:String,title:String,body:String)
val articles : Process[Task,Article] = Process(Article(<span class="hljs-string">"1"</span>,<span class="hljs-string">"Hi"</span>,<span class="hljs-string">"Scalaz Process"</span>))
//articles: scalaz<span class="hljs-preprocessor">.stream</span><span class="hljs-preprocessor">.Process</span>[scalaz<span class="hljs-preprocessor">.concurrent</span><span class="hljs-preprocessor">.Task</span>,Article] = Emit(WrappedArray(Article(<span class="hljs-number">1</span>,Hi,Scalaz Process)))
scala> articles<span class="hljs-preprocessor">.map</span>{println(_)}
Article(<span class="hljs-number">1</span>,Hi,Scalaz Process)
//scalaz<span class="hljs-preprocessor">.stream</span><span class="hljs-preprocessor">.Process</span>[scalaz<span class="hljs-preprocessor">.concurrent</span><span class="hljs-preprocessor">.Task</span>,Unit] = Emit(Vector(()))
scala> articles<span class="hljs-preprocessor">.flatMap</span>{ a=> Process(a<span class="hljs-preprocessor">.id</span>) }<span class="hljs-preprocessor">.runLog</span><span class="hljs-preprocessor">.run</span>
//IndexedSeq[String] = Vector(<span class="hljs-number">1</span>)</code></pre>
<h3 id="processscan"><code>Process.scan</code></h3>
<p>在Stream的處理中,蠻常有機會是會要參考到<strong>前一個值</strong>,也就是<strong>causal function</strong>,也就是以之前的值與目前的值來處理的function,<code>Process.scan</code>就是Process中實作的<strong>causal function</strong>,他的使用方式就像是<code>fold</code>一樣,我們會定義一個function,傳入兩個參數,分別是之前運算完的結果,和當下的值。</p>
<pre class="prettyprint"><code class="language-Scala hljs perl">val nums : Process[Task,Int] = Process.range(<span class="hljs-number">0</span>,<span class="hljs-number">10</span>)
// nums.runLog.run
// IndexedSe<span class="hljs-string">q[Int]</span> = Vector(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span>)
val sum = nums.scan(<span class="hljs-number">0</span>)( (past,present) => past+present )
// sum.runLog.run
//IndexedSe<span class="hljs-string">q[Int]</span> = Vector(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>, <span class="hljs-number">6</span>, <span class="hljs-number">10</span>, <span class="hljs-number">15</span>, <span class="hljs-number">21</span>, <span class="hljs-number">28</span>, <span class="hljs-number">36</span>, <span class="hljs-number">45</span>)</code></pre>
<p>先代入起始值<code>0</code>給<code>scan</code>當作第一個past,然後<code>scan</code>會將 (0,0), (0,1), (1,2), (3,3), (6,4)…分別代入<code>(past,present) => past+present</code>這個function中,所以最後的值就會是第一個0與所有的0到9的總合。</p>
<h3 id="將stream結合起來的好工具-wye">將Stream結合起來的好工具 - <code>wye</code></h3>
<p>要將Stream結合起來的作法有很多,這裡介紹一個叫作<a href="https://github.com/scalaz/scalaz-stream/blob/master/src/main/scala/scalaz/stream/wye.scala"><code>wye</code></a>的工具,他裡面實作了許多能將Stream結合的各種function,像是<code>merge</code>, <code>either</code>, <code>yip</code>(這就像是<code>zip</code>一樣), <code>unboundedQueue</code>, <code>boundedQueue</code>, <code>timedQueue</code>…</p>
<pre class="prettyprint"><code class="language-Scala hljs perl">scala> val p1 : Process[Task,String] = Process(<span class="hljs-string">"1"</span>,<span class="hljs-string">"2"</span>,<span class="hljs-string">"3"</span>,<span class="hljs-string">"4"</span>)
scala> val p2 : Process[Task,String] = Process(<span class="hljs-string">"a"</span>,<span class="hljs-string">"b"</span>,<span class="hljs-string">"c"</span>,<span class="hljs-string">"d"</span>)
scala> p1.wye(p2)(wye.merge).runLog.run
res: IndexedSe<span class="hljs-string">q[String]</span> = Vector(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, a, b, c, d)
scala> p1.wye(p2)(wye.either).runLog.run
res: IndexedSe<span class="hljs-string">q[scalaz.\/[String,String]</span>] = Vector(\/-(a), \/-(b), \/-(c), \/-(d), -\/(<span class="hljs-number">1</span>), -\/(<span class="hljs-number">2</span>), -\/(<span class="hljs-number">3</span>), -\/(<span class="hljs-number">4</span>))
scala> p1.wye(p2)(wye.yip).runLog.run
res: IndexedSe<span class="hljs-string">q[(String, String)]</span> = Vector((<span class="hljs-number">1</span>,a), (<span class="hljs-number">2</span>,b), (<span class="hljs-number">3</span>,c), (<span class="hljs-number">4</span>,d))</code></pre>
<p>其中有一個很實用的是<code>dynamic</code>,他的interface是<code>def dynamic[I,I2](f: I => wye.Request, g: I2 => wye.Request): Wye[I,I2,ReceiveY[I,I2]]</code>,他讓你去決定當收到 左邊 或 右邊 的stream傳入的值的時候,要怎麼去處理,並且最後決定下一個是要拿 左邊(<code>wye.Request.L</code>) 或是 右邊(<code>wye.Request.R</code>)的。</p>
<pre class="prettyprint"><code class="language-Scala hljs coffeescript"><span class="hljs-regexp">//</span> define the process logic <span class="hljs-keyword">for</span> wye.dynamic, here <span class="hljs-keyword">is</span> always change to the other side.
val w = wye.dynamic<span class="hljs-function"><span class="hljs-params">( (_:Any) => wye.Request.R, (_:Any) => wye.Request.L)</span>
<span class="hljs-title">scala</span>> <span class="hljs-title">p1</span>.<span class="hljs-title">wye</span><span class="hljs-params">(p2)(w)</span>.<span class="hljs-title">runLog</span>.<span class="hljs-title">run</span>
<span class="hljs-title">res</span>: <span class="hljs-title">IndexedSeq</span>[<span class="hljs-title">scalaz</span>.<span class="hljs-title">stream</span>.<span class="hljs-title">ReceiveY</span>[<span class="hljs-title">Any</span>,<span class="hljs-title">Any</span>]] = <span class="hljs-title">Vector</span><span class="hljs-params">(ReceiveL(<span class="hljs-number">1</span>), ReceiveR(a), ReceiveL(<span class="hljs-number">2</span>), ReceiveR(b), ReceiveL(<span class="hljs-number">3</span>), ReceiveR(c), ReceiveL(<span class="hljs-number">4</span>), ReceiveR(
d))</span>
<span class="hljs-title">p1</span>.<span class="hljs-title">wye</span><span class="hljs-params">(p2)(w)</span>.<span class="hljs-title">runLog</span>.<span class="hljs-title">run</span>.<span class="hljs-title">filter</span><span class="hljs-params">( _.isR )</span>
<span class="hljs-title">res</span>: <span class="hljs-title">IndexedSeq</span>[<span class="hljs-title">scalaz</span>.<span class="hljs-title">stream</span>.<span class="hljs-title">ReceiveY</span>[<span class="hljs-title">Any</span>,<span class="hljs-title">Any</span>]] = <span class="hljs-title">Vector</span><span class="hljs-params">(ReceiveR(a), ReceiveR(b), ReceiveR(c), ReceiveR(d))</span>
<span class="hljs-title">scala</span>> <span class="hljs-title">p1</span>.<span class="hljs-title">wye</span><span class="hljs-params">(p2)(w)</span>.<span class="hljs-title">runLog</span>.<span class="hljs-title">run</span>.<span class="hljs-title">map</span><span class="hljs-params">(_ match {
| <span class="hljs-reserved">case</span> ReceiveY.ReceiveR(x) => <span class="hljs-string">"R:"</span>+x
| <span class="hljs-reserved">case</span> ReceiveY.ReceiveL(x) => <span class="hljs-string">"L:"</span>+x
| })</span>.<span class="hljs-title">map</span><span class="hljs-params">(x=>println(s<span class="hljs-string">"got $x"</span>))</span>
<span class="hljs-title">got</span> <span class="hljs-title">L</span>:1
<span class="hljs-title">got</span> <span class="hljs-title">R</span>:<span class="hljs-title">a</span>
<span class="hljs-title">got</span> <span class="hljs-title">L</span>:2
<span class="hljs-title">got</span> <span class="hljs-title">R</span>:<span class="hljs-title">b</span>
<span class="hljs-title">got</span> <span class="hljs-title">L</span>:3
<span class="hljs-title">got</span> <span class="hljs-title">R</span>:<span class="hljs-title">c</span>
<span class="hljs-title">got</span> <span class="hljs-title">L</span>:4
<span class="hljs-title">got</span> <span class="hljs-title">R</span>:<span class="hljs-title">d</span></span></code></pre>
<p>至於其他的<code>unboundedQueue</code>, <code>boundedQueue</code>, <code>timedQueue</code>…等別的用法,就請參考<a href="https://github.com/scalaz/scalaz-stream/blob/master/src/main/scala/scalaz/stream/wye.scala"><code>wye</code>的原始碼</a>嘍!</p>
<h2 id="reference">Reference</h2>
<ul>
<li><a href="https://www.chrisstucchio.com/blog/2014/scalaz_streaming_tutorial.html">Scalaz Stream - a Functional Reactive Programming Tutorial</a></li>
</ul></body>
</html>joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-73274716535185096962015-08-26T04:15:00.001+08:002015-08-27T03:03:58.245+08:00[ScaVa->Scala] Scalaz Stream 串流好朋友 part 1<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>[ScaVa->Scala] Scalaz Stream 串流好朋友 part 1</title>
<link rel="stylesheet" href="http://yandex.st/highlightjs/7.5/styles/github.min.css">
<script src="http://yandex.st/highlightjs/7.5/highlight.min.js"></script>
</head>
<body><h1 id="scava-scala-scalaz-stream-串流好朋友-part-1">[ScaVa->Scala] Scalaz Stream 串流好朋友 part 1</h1>
<blockquote>
<p>這篇同步發佈在我的<a href="http://blog.joecwu.com/2015/08/scava-scala-scalaz-stream-part-1.html">Blog</a>和<a href="https://gist.github.com/joecwu/525aaf0b9b886eb68b74">Gist</a>。</p>
</blockquote>
<h2 id="何時用到stream串流">何時用到Stream(串流)?</h2>
<p>一提到Stream(串流),第一個想到的就是影音的類型,這種應用面是非常的普遍也很容易理解。</p>
<p>而我第一次在project中想嘗試使用Streaming的時候,一直有個困擾,我的protocol是HTTP+JSON,我就是要等到整個payload都收下來了,才能Deserialize成Json object啊,這樣stream對我的好處是什麼?</p>
<p>前陣子有同事提到一個例子,說Java8的Performance比Scala好很多! <br>
仔細發現,其實他在測試時用到的是Java8的Stream,但是卻拿Scala一般的Collection來比,就好比下面這樣的結果。(最後當然是幫Scala版本加個toStream兩個的差距就差不多了。)</p>
<pre class="prettyprint"><code class="language-Scala hljs coffeescript">def measure<span class="hljs-function"><span class="hljs-params">(f:()=>Any)</span>={
<span class="hljs-title">val</span> <span class="hljs-title">s</span>=<span class="hljs-title">System</span>.<span class="hljs-title">currentTimeMillis</span>
<span class="hljs-title">f</span><span class="hljs-params">()</span>
<span class="hljs-title">println</span><span class="hljs-params">(s<span class="hljs-string">"elapsed: ${System.currentTimeMillis-s}ms"</span>)</span>
}
<span class="hljs-title">scala</span>> <span class="hljs-title">measure</span>{ <span class="hljs-params">()</span> =></span> (<span class="hljs-number">1</span> to <span class="hljs-number">20000000</span>).toStream.filter(_%<span class="hljs-number">2</span>==<span class="hljs-number">0</span>).filter(_><span class="hljs-number">200</span>).head }
<span class="hljs-attribute">elapsed</span>: <span class="hljs-number">1</span>ms
scala> measure{ <span class="hljs-function"><span class="hljs-params">()</span> =></span> (<span class="hljs-number">1</span> to <span class="hljs-number">20000000</span>).filter(_%<span class="hljs-number">2</span>==<span class="hljs-number">0</span>).filter(_><span class="hljs-number">200</span>).head }
<span class="hljs-attribute">elapsed</span>: <span class="hljs-number">983</span>ms</code></pre>
<p>一看就知道這是一個不公平的結果!!! 一個是乖乖把所有的結果整理完,然後往後傳,通通filter過之後,只取第一個結果,另一個是streaming(串流)的方式,把資料用”流”的方式一步步的流過filter與head,當第一個match的結果出現之後就結束了。</p>
<p>但這個例子讓我們知道,原來stream除了從合適的protocol處理就能有幫助之外,其實就算在系統內部的資料傳遞與處理的過程中,在適當的使用下,一樣是能提升效率的。</p>
<h2 id="streaming的選擇">Streaming的選擇</h2>
<p>最近Streaming的處理方式愈來愈紅,Akka在上個月(2015.07)也正式Release <a href="http://akka.io/news/2015/07/15/akka-streams-1.0-released.html">Akka Streams & Http Experimental 1.0</a>,而Twitter Util也有提供<a href="http://schd.ws/hosted_files/finaglecon2015/d1/Streaming%20HTTP%20with%20Finatra%20and%20AsyncStream.pdf">AsyncStream</a>,結合在<a href="http://twitter.github.io/finatra/">Finatra</a>上使用,看起來也不錯!</p>
<p>不過今天主角是Scalaz Stream,主要參考這篇<a href="https://www.chrisstucchio.com/blog/2014/scalaz_streaming_tutorial.html">Scalaz Stream - a Functional Reactive Programming Tutorial</a>。</p>
<p>以下來簡單的介紹一下Scalaz Stream的用法</p>
<h2 id="scalaz-stream">Scalaz Stream</h2>
<h3 id="什麼是process">什麼是Process?</h3>
<p>Scalaz Stream中,最重要的核心物件就是<code>Process</code>,這個<code>Process[F[_], X]</code>主要是定義了串流中的物件為<code>X</code>型態,並且透過<code>F[_]</code>這個Monad來包裝他,而在實際的使用上,通常會使用Scalaz的Task (請參考我上一篇寫的<a href="http://blog.joecwu.com/2015/08/scava-scala-scalaz-task-scala-future.html">[ScaVa->Scala] Scalaz Task 取代Scala Future來進行非同步處理的另一個選擇</a>)。</p>
<p><code>Process</code>提供了一些<code>run</code>的方式,並且透過<code>F[_]</code>這個effect system來包裝他,可以想像<code>F[_]</code>是要處理這些<code>X</code>型態值的driver。</p>
<pre class="prettyprint"><code class="language-Scala hljs python">trait Process[F[_], X] {
...
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">run</span><span class="hljs-params">(implicit m: Monad[F])</span>:</span> F[Unit]
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">runLast</span><span class="hljs-params">(implicit m: Monad[F])</span>:</span> F[X]
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">runLog</span><span class="hljs-params">(implicit m: Monad[F])</span>:</span> F[IndexedSeq[X]]
}</code></pre>
<p>在使用上的觀念要知道<code>Process</code>是個Stream,所以他的值會是一直”流”進來的,當使用<code>run</code>的時候,他回傳的是<code>F[Unit]</code>,所以他是忽略你的回傳值,而主要的使用是用<code>F[_]</code>的特性來處理這些值,例如使用<code>Task</code>時,就可以使用他的<code>timed</code>, <code>handleWith</code>, <code>onFinished</code>之類的function。</p>
<p>而使用<code>runLast</code>的時候,會執行整個串流,一直到最後一個值並只回傳最後一個值。</p>
<p>使用<code>runLog</code>會將整所有的值都包在<code>IndexedSeq[X]</code>裡面,讓你可以一口氣取得所有串流中的值,這也是最耗記憶體的,就是把所有的結果都收集起來。</p>
<p>若以<code>List</code>monad來當作<code>F[_]</code>,就會像以下這樣的例子:</p>
<pre class="prettyprint"><code class="language-Scala hljs mathematica">scala> val p: Process[<span class="hljs-keyword">List</span>,Int] = Process.range(<span class="hljs-number">0</span>,<span class="hljs-number">10</span>)
scala> p.run
res5: <span class="hljs-keyword">List</span>[Unit] = <span class="hljs-keyword">List</span>(())
scala> p.runLast
res10: <span class="hljs-keyword">List</span>[Option[Int]] = <span class="hljs-keyword">List</span>(Some(<span class="hljs-number">9</span>))
scala> p.runLog
res11: <span class="hljs-keyword">List</span>[IndexedSeq[Int]] = <span class="hljs-keyword">List</span>(Vector(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">6</span>, <span class="hljs-number">7</span>, <span class="hljs-number">8</span>, <span class="hljs-number">9</span>))</code></pre>
<h3 id="產生process">產生Process</h3>
<p>這裡舉幾種產生Process方式的例子:</p>
<h4 id="1-要把現有的值包成process">1. 要把現有的值包成Process</h4>
<pre class="prettyprint"><code class="language-Scala hljs fsharp"><span class="hljs-keyword">val</span> p = Process(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>)
<span class="hljs-comment">//p: scalaz.stream.Process0[Int] = Emit(WrappedArray(1, 2, 3, 4, 5))</span></code></pre>
<p>如果你直接嘗試去<code>run</code>這個<code>p</code>,會得到以下的錯誤:</p>
<pre class="prettyprint"><code class="language-Scala hljs applescript">scala> p.<span class="hljs-command">run</span>
<console>:<span class="hljs-number">16</span>: <span class="hljs-keyword">error</span>: could <span class="hljs-keyword">not</span> find implicit value <span class="hljs-keyword">for</span> parameter C: scalaz.Catchable[F2]
p.<span class="hljs-command">run</span>
^</code></pre>
<p>因為他缺少了driver,也就是<code>F[_]</code>,所以他不知道該怎麼去處理他,這時候他的型態是<code>Process0</code>,只是個wrapper,所以你可以直接<code>toList</code>取得你要的值,或是告訴他你的driver是什麼。</p>
<pre class="prettyprint"><code class="language-Scala hljs avrasm">val p = Process(<span class="hljs-number">1</span>,<span class="hljs-number">2</span>,<span class="hljs-number">3</span>,<span class="hljs-number">4</span>,<span class="hljs-number">5</span>):Process[Task,Int]
//p: scalaz<span class="hljs-preprocessor">.stream</span><span class="hljs-preprocessor">.Process</span>[scalaz<span class="hljs-preprocessor">.concurrent</span><span class="hljs-preprocessor">.Task</span>,Int] = Emit(WrappedArray(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>))
p<span class="hljs-preprocessor">.runLog</span><span class="hljs-preprocessor">.run</span>
//IndexedSeq[Int] = Vector(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>)</code></pre>
<h4 id="2-使用scalazstreamio來產生">2. 使用<code>scalaz.stream.io</code>來產生</h4>
<p><code>scalaz.stream.io</code>有將一些io的操作包裝起來,讓你方便直接使用,例如讀檔案:</p>
<pre class="prettyprint"><code class="language-Scala hljs vhdl">val lns: <span class="hljs-keyword">Process</span>[Task,<span class="hljs-typename">String</span>] = io.linesR(<span class="hljs-string">"inputfile.txt"</span>)</code></pre>
<h4 id="3-使用taskasync來包裝你的執行動作再透過processeval來產生">3. 使用<code>Task.async</code>來包裝你的執行動作,再透過<code>Process.eval</code>來產生</h4>
<p>這種用法,很適合將你本來要進行的處理(一些java/scala library的存取、或是對server的request)給包成<code>Task</code>,再透過Process來將這裡面的結果包成Stream。</p>
<pre class="prettyprint"><code class="language-Scala hljs r">val f: Task[A] = Task.async { <span class="hljs-keyword">...</span> } //Do something to create an object
val evalF: Process[Task,A] = Process.eval(f)</code></pre>
<p>這類型的有<code>eval</code>,<code>repeat</code>,<code>repeatEval</code>,<code>suspend</code>等…</p>
<h4 id="4-使用scalazstreamasyncqueue">4. 使用<code>scalaz.stream.async.Queue</code></h4>
<p><code>scalaz.stream</code>實作了<code>Queue</code>來讓你從一邊把串流的值給不斷的塞進去,而另一邊可以直接以<code>Process</code>來接收這些串流的值。</p>
<pre class="prettyprint"><code class="language-Scala hljs scala"><span class="hljs-keyword">import</span> scalaz.stream._
<span class="hljs-keyword">val</span> q = async.unboundedQueue[String]
<span class="hljs-keyword">while</span> (<span class="hljs-keyword">true</span>) {
<span class="hljs-keyword">val</span> inputString = readFromTheNetwork()
q.enqueueOne( inputString ).run
}
<span class="hljs-comment">//...elsewhere...</span>
<span class="hljs-keyword">val</span> stringsFromTheNetwork: Process[Task,String] = q.dequeue</code></pre>
<h4 id="5-另外一種方式-signal">5. 另外一種方式 - <code>signal</code></h4>
<p>這裡的<code>signal</code>跟<code>queue</code>不同的地方是,這個的implementation是針對signal,所以他保證你能得到最後的值,但中間過程中若有許多次的變動,不一定每次都會拿得到,若你是希望每一個過程都要拿得到的話,要使用<code>queue</code>。</p>
<pre class="prettyprint"><code class="language-Scala hljs vala">val <span class="hljs-keyword">signal</span> = <span class="hljs-keyword">async</span>.<span class="hljs-keyword">signal</span>[Boolean]
val signalChanges: Process[Task,Boolean] = <span class="hljs-keyword">signal</span>.discrete
<span class="hljs-comment">//Thread 1</span>
<span class="hljs-keyword">signal</span>.<span class="hljs-keyword">set</span>(<span class="hljs-literal">true</span>).run <span class="hljs-comment">// Time = 1</span>
<span class="hljs-keyword">signal</span>.<span class="hljs-keyword">set</span>(<span class="hljs-literal">true</span>).run <span class="hljs-comment">// Time = 2</span>
<span class="hljs-keyword">signal</span>.<span class="hljs-keyword">set</span>(<span class="hljs-literal">false</span>).run <span class="hljs-comment">//Time = 3</span>
...
<span class="hljs-comment">//Thread 2</span>
signalChanges.map(x => {
println(<span class="hljs-string">""</span> + x + <span class="hljs-string">" -> "</span> + System.currentTimeMillis)
}).run.run
<span class="hljs-comment">// Will print:</span>
<span class="hljs-comment">// true -> 1</span>
<span class="hljs-comment">// false -> 3</span></code></pre>
<h4 id="6-processawakeevery定時產生process的通知">6. <code>Process.awakeEvery</code>定時產生<code>Process</code>的通知</h4>
<pre class="prettyprint"><code class="language-Scala hljs avrasm">import scala<span class="hljs-preprocessor">.concurrent</span><span class="hljs-preprocessor">.duration</span>._
val clock = Process<span class="hljs-preprocessor">.awakeEvery</span>(<span class="hljs-number">1</span> seconds)</code></pre>
<h2 id="nest">Nest</h2>
<p>[ScaVa->Scala] Scalaz Stream 串流好朋友 part 2 <a href="http://blog.joecwu.com/2015/08/scava-scala-scalaz-stream-part-2.html">Blog</a>或<a href="https://gist.github.com/joecwu/fd28b678585f89c746b0">Gist</a>。</p>
<h2 id="reference">Reference</h2>
<ul>
<li><a href="https://www.chrisstucchio.com/blog/2014/scalaz_streaming_tutorial.html">Scalaz Stream - a Functional Reactive Programming Tutorial</a></li>
<li><a href="http://stackoverflow.com/questions/22923535/running-scalaz-streams-process-gives-could-not-find-implicit-value-for-paramete">StackOverflow - Running scalaz-stream’s Process gives could not find implicit value for parameter C: scalaz.Catchable[F2]?</a></li>
</ul></body>
</html>joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-35073392427207220572015-08-24T05:01:00.001+08:002015-08-24T05:01:42.007+08:00情人節 台中三日遊這次情人節,特別請了兩天假(星期四和五)避開人潮,與小柔到台中放鬆一下,玩個三天兩夜。<br />
本來有考慮玩到四天,不過因為有颱風要來(雖然最後好像只是擦身而過),所以最後只有三天兩夜。<br />
這次的行程都是小柔幫忙找的,其實找了很多個點,也建了Google MyMap,但因為太隨興了,很多點沒有跑到,辛苦小柔了。<br />
<h3>
Day 1 紙箱王 -> 碧根行館 -> 逢甲夜市</h3>
第一天我們大約中午從台北出發,先買了簡單的早餐在車上吃,接下來就直接出發到我們的第一個景點-紙箱王(其實也跑錯了,跑到了他的餐廳,但還是有蠻多很特別的紙箱製的作品)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-wN85Ypwu938/VdjMB126DUI/AAAAAAAE-Os/1EXfBBaVyA0/s1600/20150820_102_2413.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-wN85Ypwu938/VdjMB126DUI/AAAAAAAE-Os/1EXfBBaVyA0/s320/20150820_102_2413.JPG" width="320" /></a><a href="http://2.bp.blogspot.com/-s_REFI45_9s/VdjMEGTTZJI/AAAAAAAE-O4/PB1LWkdeOB0/s1600/20150820_102_2414.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-s_REFI45_9s/VdjMEGTTZJI/AAAAAAAE-O4/PB1LWkdeOB0/s320/20150820_102_2414.JPG" width="320" /></a><a href="http://3.bp.blogspot.com/-09owI5DXP90/VdjMHgr1sYI/AAAAAAAE-PA/dJKUJtJpSkQ/s1600/20150820_102_2415.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-09owI5DXP90/VdjMHgr1sYI/AAAAAAAE-PA/dJKUJtJpSkQ/s320/20150820_102_2415.JPG" width="320" /></a><a href="http://1.bp.blogspot.com/-9ZTHZ3OY4t4/VdjMMnF_0oI/AAAAAAAE-PQ/dffGccse4_8/s1600/20150820_102_2417.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://1.bp.blogspot.com/-9ZTHZ3OY4t4/VdjMMnF_0oI/AAAAAAAE-PQ/dffGccse4_8/s320/20150820_102_2417.JPG" width="320" /></a><a href="http://2.bp.blogspot.com/-P2WEytSFBXI/VdjMgaF3BsI/AAAAAAAE-QQ/ejppOA9mScw/s1600/20150820_102_2424.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-P2WEytSFBXI/VdjMgaF3BsI/AAAAAAAE-QQ/ejppOA9mScw/s320/20150820_102_2424.JPG" width="320" /></a><a href="http://3.bp.blogspot.com/-Hl_nDmMyVI8/VdjMXH2AreI/AAAAAAAE-P0/VNFIeZQEixQ/s1600/20150820_102_2421.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-Hl_nDmMyVI8/VdjMXH2AreI/AAAAAAAE-P0/VNFIeZQEixQ/s320/20150820_102_2421.JPG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
再來旁邊剛好有大魯閣,跑去上個廁所又順便玩了一下遊樂設施!</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-m7cKmZFqOlI/VdjMs2CIZWI/AAAAAAAE-RE/k0YcYaasHdQ/s1600/20150820_102_2430.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-m7cKmZFqOlI/VdjMs2CIZWI/AAAAAAAE-RE/k0YcYaasHdQ/s320/20150820_102_2430.JPG" width="320" /></a></div>
<br />
算算時間差不多可以check-in了,我們就直接到碧根行館,其實本來想換到Hotel 7,但是是透過Booking.com,而免費取消的時間過了,只好住這間了。我們是Booking.com的特惠價格專案,一晚1999元,所以飯店跟我們說沒有附車位,只好花200元停在他們的特約停車場,大約走路7~8分鐘。(就在Hotel 7旁邊)<br />
<br />
其實碧根行館就在逢甲大門口,夜市裡面! 我們逛一逛還可以先回去休息一下放個東西再繼續出來逛,地點真的滿分沒話說!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-lW-KzslynnU/VdjMxfrLxaI/AAAAAAAE-Rc/v2kFKBv-OVo/s1600/20150820_102_2432.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-lW-KzslynnU/VdjMxfrLxaI/AAAAAAAE-Rc/v2kFKBv-OVo/s320/20150820_102_2432.JPG" width="320" /></a><a href="http://4.bp.blogspot.com/-m4W14YDOhWs/VdjMz5VlUMI/AAAAAAAE-Ro/muQaG49W0pQ/s1600/20150820_102_2433.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://4.bp.blogspot.com/-m4W14YDOhWs/VdjMz5VlUMI/AAAAAAAE-Ro/muQaG49W0pQ/s320/20150820_102_2433.JPG" width="320" /></a><a href="http://1.bp.blogspot.com/-aVvxYLzPzg4/VdjM2FAk2gI/AAAAAAAE-R0/egndi0wuetg/s1600/20150820_102_2434.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://1.bp.blogspot.com/-aVvxYLzPzg4/VdjM2FAk2gI/AAAAAAAE-R0/egndi0wuetg/s320/20150820_102_2434.JPG" width="320" /></a><a href="http://3.bp.blogspot.com/-I_YWgCXyfPE/VdjNjLfUwXI/AAAAAAAE-Ug/ZXXVYay4s38/s1600/20150820_102_2453.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-I_YWgCXyfPE/VdjNjLfUwXI/AAAAAAAE-Ug/ZXXVYay4s38/s320/20150820_102_2453.JPG" width="320" /></a><a href="http://2.bp.blogspot.com/-VmxAH0Nz0E8/VdjNu2hQD5I/AAAAAAAE-VQ/t-QLlWAztmc/s1600/20150820_102_2458.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-VmxAH0Nz0E8/VdjNu2hQD5I/AAAAAAAE-VQ/t-QLlWAztmc/s320/20150820_102_2458.JPG" width="320" /></a></div>
<br />
這是從房間窗戶往外面的畫面,對面就是i-bike站!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-pJtppay-Rrc/VdjN10s45UI/AAAAAAAE-Vo/o5O9QT23l50/s1600/20150820_102_2461.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://1.bp.blogspot.com/-pJtppay-Rrc/VdjN10s45UI/AAAAAAAE-Vo/o5O9QT23l50/s640/20150820_102_2461.JPG" width="640" /></a></div>
<br />
晚上就是瘋逛的逛逢甲夜市了!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-3NeIe-3B-Rg/VdjNFDBMkLI/AAAAAAAE-Sk/ABU9Kv6nYOg/s1600/20150820_102_2440.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://1.bp.blogspot.com/-3NeIe-3B-Rg/VdjNFDBMkLI/AAAAAAAE-Sk/ABU9Kv6nYOg/s640/20150820_102_2440.JPG" width="640" /></a></div>
<br />
這棉花糖做的有夠醜!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-LCyHpVYj_oA/VdjNMVJ40II/AAAAAAAE-TI/zALcnOYFoD4/s1600/20150820_102_2443.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://1.bp.blogspot.com/-LCyHpVYj_oA/VdjNMVJ40II/AAAAAAAE-TI/zALcnOYFoD4/s640/20150820_102_2443.JPG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
逢甲夜市的小吃們!這個雞排真的很好吃耶!</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-6QIee7Wy96Q/VdjNOUiWMYI/AAAAAAAE-TQ/ifdApK3a_zo/s1600/20150820_102_2444.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://1.bp.blogspot.com/-6QIee7Wy96Q/VdjNOUiWMYI/AAAAAAAE-TQ/ifdApK3a_zo/s320/20150820_102_2444.JPG" width="320" /></a><a href="http://3.bp.blogspot.com/-sC2M5AbMPfk/VdjNTCiJfnI/AAAAAAAE-Tg/lazP4CS0-u0/s1600/20150820_102_2446.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-sC2M5AbMPfk/VdjNTCiJfnI/AAAAAAAE-Tg/lazP4CS0-u0/s320/20150820_102_2446.JPG" width="320" /></a><a href="http://2.bp.blogspot.com/-hHjE3b3cbMU/VdjNctDRmCI/AAAAAAAE-UE/65OzBb1rvOY/s1600/20150820_102_2448.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-hHjE3b3cbMU/VdjNctDRmCI/AAAAAAAE-UE/65OzBb1rvOY/s320/20150820_102_2448.JPG" width="320" /></a><a href="http://2.bp.blogspot.com/-E2o2G0eqEUM/VdjNZowzJyI/AAAAAAAE-T0/1e08KHiTS0g/s1600/20150820_102_2449.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-E2o2G0eqEUM/VdjNZowzJyI/AAAAAAAE-T0/1e08KHiTS0g/s320/20150820_102_2449.JPG" width="320" /></a><a href="http://3.bp.blogspot.com/-dG0o_OM5Bts/VdjNb_A7LCI/AAAAAAAE-T8/nPm4gOiNJg8/s1600/20150820_102_2450.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-dG0o_OM5Bts/VdjNb_A7LCI/AAAAAAAE-T8/nPm4gOiNJg8/s320/20150820_102_2450.JPG" width="320" /></a><a href="http://3.bp.blogspot.com/-0zPVBPi_uUc/VdjON1ZCMtI/AAAAAAAE-W8/YGWHNqJSrww/s1600/20150820_102_2468.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-0zPVBPi_uUc/VdjON1ZCMtI/AAAAAAAE-W8/YGWHNqJSrww/s320/20150820_102_2468.JPG" width="320" /></a><a href="http://3.bp.blogspot.com/-6Kp_j0v2ve4/VdjOWdNnqqI/AAAAAAAE-Xg/Ao9HnrW0xr0/s1600/20150820_102_2474.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-6Kp_j0v2ve4/VdjOWdNnqqI/AAAAAAAE-Xg/Ao9HnrW0xr0/s320/20150820_102_2474.JPG" width="320" /></a></div>
<br />
不小心逛到一間拼圖店,1000片的拉拉熊拼圖居然只要500元,加上木框999元,當然就直接買了!(這時候飯店近的優點馬上體會到,不用走太遠就可以把東西拿回去放。)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-7dFxP09t3f4/VdjOOxR6qgI/AAAAAAAE-XE/UTH5gUzK7mg/s1600/20150820_102_2471.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://2.bp.blogspot.com/-7dFxP09t3f4/VdjOOxR6qgI/AAAAAAAE-XE/UTH5gUzK7mg/s640/20150820_102_2471.JPG" width="640" /></a></div>
<br />
<h3>
Day2 無為草堂 -> 精明一街 -> 輕井澤 -> 沐蘭</h3>
<div class="separator" style="clear: both; text-align: left;">
第二天check-out的時候也差不多中午了,我們就直接出到去無為草堂吃午餐。</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiozdiuqy6JCm_8ykiwysXhdTz1Ja3CrlRd_8TFPHJUqvP8q8kMt9nStbDflzqWIR2Fshg0E1KB1WWXjVu8REqLqNlpHn5UrM4louDQdk3fqwPdvR7DWX26itbbfIraFhfXpKoMAQ/s1600/IMAG5669.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiozdiuqy6JCm_8ykiwysXhdTz1Ja3CrlRd_8TFPHJUqvP8q8kMt9nStbDflzqWIR2Fshg0E1KB1WWXjVu8REqLqNlpHn5UrM4louDQdk3fqwPdvR7DWX26itbbfIraFhfXpKoMAQ/s640/IMAG5669.jpg" width="640" /></a></div>
<br />
餐點很好吃! 五穀米也很健康的感覺!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj7HB3-6U7INZ-ZUsNbnB0FTSZqu4Ok1BfHQlvwB52DfYz50LHqpGKUyL109xpHnFNe1ZStqUkMgU-7lKvCC4_xImI_DdrHVAVcmRoJCVumKZKY6z5XqrmQO13NwKh_f3lpxFccQ/s1600/IMAG5660.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj7HB3-6U7INZ-ZUsNbnB0FTSZqu4Ok1BfHQlvwB52DfYz50LHqpGKUyL109xpHnFNe1ZStqUkMgU-7lKvCC4_xImI_DdrHVAVcmRoJCVumKZKY6z5XqrmQO13NwKh_f3lpxFccQ/s320/IMAG5660.jpg" width="320" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjW-Cvj9kiVidyttkluLu09mpVIGIvMlAwy_qfMuvLY635x4DFQP-Xh5fyFkrA2cmSVwyz8BHZmIr4zBQnn_9Fg4-BNCPezFRUoSKVwKx6EX0nNmYHJE0WwrLfTHeYBvJU6Vcc6w/s1600/IMAG5663.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjW-Cvj9kiVidyttkluLu09mpVIGIvMlAwy_qfMuvLY635x4DFQP-Xh5fyFkrA2cmSVwyz8BHZmIr4zBQnn_9Fg4-BNCPezFRUoSKVwKx6EX0nNmYHJE0WwrLfTHeYBvJU6Vcc6w/s320/IMAG5663.jpg" width="320" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTx19bIUuy6DEHRdzKQICIkd47y3GR3tL0-IoH2uFk-igGQjMVjy6H34OKa6qzDnjAFrempOVA87RcPan_lRRYhl3zA3EA0k4sY_dvi0Hhs9f26LPNqXF4y4ih_bhj_kehJ26f8Q/s1600/IMAG5664.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTx19bIUuy6DEHRdzKQICIkd47y3GR3tL0-IoH2uFk-igGQjMVjy6H34OKa6qzDnjAFrempOVA87RcPan_lRRYhl3zA3EA0k4sY_dvi0Hhs9f26LPNqXF4y4ih_bhj_kehJ26f8Q/s320/IMAG5664.jpg" width="320" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrpuvrAqklGCdjwdjW__iuUrv0ZKZTiWxRTmYTwXMdShtQ1Ap7Pa7EvzR_kRrqDDGUVjQxqT6HIdo0FYg7yWagqSw7XvW1cGZ1nYvEEyTkCo6X-PIhaDfoGWZ-mO9U8r83r0BbYg/s1600/IMAG5665.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhrpuvrAqklGCdjwdjW__iuUrv0ZKZTiWxRTmYTwXMdShtQ1Ap7Pa7EvzR_kRrqDDGUVjQxqT6HIdo0FYg7yWagqSw7XvW1cGZ1nYvEEyTkCo6X-PIhaDfoGWZ-mO9U8r83r0BbYg/s320/IMAG5665.jpg" width="320" /></a></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
裡面的風格真的很讚,可以花20元跟櫃台買一大杯的魚飼料,小柔餵魚餵得很開心!</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-BAIffhmMmlQ/VdjOYog4oiI/AAAAAAAE-Xo/h-rOx5Cwr7M/s1600/20150821_102_2475.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://1.bp.blogspot.com/-BAIffhmMmlQ/VdjOYog4oiI/AAAAAAAE-Xo/h-rOx5Cwr7M/s320/20150821_102_2475.JPG" width="320" /></a><a href="http://4.bp.blogspot.com/-LcgAsjHwFss/VdjOdS_1PeI/AAAAAAAE-X4/2ueEPKUQXG4/s1600/20150821_102_2477.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://4.bp.blogspot.com/-LcgAsjHwFss/VdjOdS_1PeI/AAAAAAAE-X4/2ueEPKUQXG4/s320/20150821_102_2477.JPG" width="320" /></a><a href="http://3.bp.blogspot.com/-S6zJof0kCrA/VdjOf2b60dI/AAAAAAAE-YE/CTLGWJtmzJI/s1600/20150821_102_2478.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-S6zJof0kCrA/VdjOf2b60dI/AAAAAAAE-YE/CTLGWJtmzJI/s320/20150821_102_2478.JPG" width="320" /></a><a href="http://2.bp.blogspot.com/-wAm3duZ0ay8/VdjPzn97pAI/AAAAAAAE-cw/pjyHSUfDZuk/s1600/20150821_102_2512.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-wAm3duZ0ay8/VdjPzn97pAI/AAAAAAAE-cw/pjyHSUfDZuk/s320/20150821_102_2512.JPG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
精明一街沒想像中的好逛,而且我出來玩的時候,又因為有一些事在處理,很常時間用手機,還跟學長通電話講了好一陣子,委曲小柔在旁邊等我。</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-Sf5-7qn-WjY/VdjR1k-41PI/AAAAAAAE-d8/IvIzLnyCFQY/s1600/20150821_102_2517.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-Sf5-7qn-WjY/VdjR1k-41PI/AAAAAAAE-d8/IvIzLnyCFQY/s320/20150821_102_2517.JPG" width="320" /></a><a href="http://2.bp.blogspot.com/-TmedxR3rzmA/VdjR6fYEqYI/AAAAAAAE-eQ/qTpaq2bQACU/s1600/20150821_102_2519.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-TmedxR3rzmA/VdjR6fYEqYI/AAAAAAAE-eQ/qTpaq2bQACU/s320/20150821_102_2519.JPG" width="320" /></a><a href="http://3.bp.blogspot.com/-hZiPCTUU1Y4/VdjSKXQV7hI/AAAAAAAE-fQ/zFbFUlD_3Xo/s1600/20150821_102_2526.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-hZiPCTUU1Y4/VdjSKXQV7hI/AAAAAAAE-fQ/zFbFUlD_3Xo/s320/20150821_102_2526.JPG" width="320" /></a><a href="http://3.bp.blogspot.com/-lH5SucRSxXc/VdjSPXMe-_I/AAAAAAAE-fY/p6lH4Zxoeds/s1600/20150821_102_2528.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-lH5SucRSxXc/VdjSPXMe-_I/AAAAAAAE-fY/p6lH4Zxoeds/s320/20150821_102_2528.JPG" width="320" /></a><a href="http://4.bp.blogspot.com/-JZdWFa5rqro/VdjSF5igm5I/AAAAAAAE-e8/qebAqjpSHZA/s1600/20150821_102_2524.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://4.bp.blogspot.com/-JZdWFa5rqro/VdjSF5igm5I/AAAAAAAE-e8/qebAqjpSHZA/s320/20150821_102_2524.JPG" width="320" /></a></div>
<br />
小柔找到一間自己手作點心的烘焙教室,我們都很有興趣,但因為時間不夠,所以沒辦法體驗,只好下次再找機會來。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-3edFs4MZ4cI/VdjSZBbKeqI/AAAAAAAE-gE/N5WMbjE6_HY/s1600/20150821_102_2532.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-3edFs4MZ4cI/VdjSZBbKeqI/AAAAAAAE-gE/N5WMbjE6_HY/s320/20150821_102_2532.JPG" width="320" /></a><a href="http://3.bp.blogspot.com/-eRxrNkiasKU/VdjSeDF2-kI/AAAAAAAE-gY/buDQOq4UE6o/s1600/20150821_102_2534.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-eRxrNkiasKU/VdjSeDF2-kI/AAAAAAAE-gY/buDQOq4UE6o/s320/20150821_102_2534.JPG" width="320" /></a><a href="http://3.bp.blogspot.com/-AvxA5F7nW4A/VdjSlZEahCI/AAAAAAAE-vw/3NL-p9AkciU/s1600/20150821_102_2537.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-AvxA5F7nW4A/VdjSlZEahCI/AAAAAAAE-vw/3NL-p9AkciU/s320/20150821_102_2537.JPG" width="320" /></a></div>
<br />晚上跟以前同學碰面吃飯,超久沒聯絡的修哥,謝謝他請我們吃輕井澤,聊了蠻多,期待下次的聚會。<br />
<br />
吃完飯後,就去沐蘭Check-in,之前旅展買的住宿休息劵+免費升等券,入住楓舞B,星期五晚上入住要再加600元,總共3千初頭,還蠻划算的。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-Wy9XgCGRMNI/VdjTmasIThI/AAAAAAAE-lg/v5wrKq9LHXY/s1600/20150821_102_2564.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://1.bp.blogspot.com/-Wy9XgCGRMNI/VdjTmasIThI/AAAAAAAE-lg/v5wrKq9LHXY/s640/20150821_102_2564.JPG" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-oAb1Rv50ccg/VdjSzkMjhTI/AAAAAAAE-hk/6WkMM01fh0I/s1600/20150821_102_2543.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-oAb1Rv50ccg/VdjSzkMjhTI/AAAAAAAE-hk/6WkMM01fh0I/s320/20150821_102_2543.JPG" width="320" /></a><a href="http://4.bp.blogspot.com/-HqZFJKKCzi4/VdjS8euON_I/AAAAAAAE-iM/YA_8yYc0Leg/s1600/20150821_102_2544.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://4.bp.blogspot.com/-HqZFJKKCzi4/VdjS8euON_I/AAAAAAAE-iM/YA_8yYc0Leg/s320/20150821_102_2544.JPG" width="320" /></a></div>
<br />
<br />
房間很大很漂亮!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-HiGmCMJ48s4/VdjS8wYZb3I/AAAAAAAE-iU/GZ7K-hQjknM/s1600/20150821_102_2547.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://4.bp.blogspot.com/-HiGmCMJ48s4/VdjS8wYZb3I/AAAAAAAE-iU/GZ7K-hQjknM/s640/20150821_102_2547.JPG" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-oQvCxutcmkk/VdjS_g6rnvI/AAAAAAAE-ig/H1JwTFS8sLs/s1600/20150821_102_2548.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-oQvCxutcmkk/VdjS_g6rnvI/AAAAAAAE-ig/H1JwTFS8sLs/s320/20150821_102_2548.JPG" width="320" /></a><a href="http://2.bp.blogspot.com/-zwbek2nk9xg/VdjTEZmg7hI/AAAAAAAE-i8/-Wrpqa8X3Nc/s1600/20150821_102_2550.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-zwbek2nk9xg/VdjTEZmg7hI/AAAAAAAE-i8/-Wrpqa8X3Nc/s320/20150821_102_2550.JPG" width="320" /></a><a href="http://1.bp.blogspot.com/-QhA2E-NFkmA/VdjTLw5iDLI/AAAAAAAE-jg/Mj4J3AdKB44/s1600/20150821_102_2553.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://1.bp.blogspot.com/-QhA2E-NFkmA/VdjTLw5iDLI/AAAAAAAE-jg/Mj4J3AdKB44/s320/20150821_102_2553.JPG" width="320" /></a><a href="http://4.bp.blogspot.com/-qztTLmrVpcM/VdjTVQniByI/AAAAAAAE-kI/XR4uSUbU9-U/s1600/20150821_102_2557.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://4.bp.blogspot.com/-qztTLmrVpcM/VdjTVQniByI/AAAAAAAE-kI/XR4uSUbU9-U/s320/20150821_102_2557.JPG" width="320" /></a><a href="http://4.bp.blogspot.com/-y7BfWcy2mrk/VdjTarfr1WI/AAAAAAAE-ko/NmIiFf_4X_o/s1600/20150821_102_2559.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://4.bp.blogspot.com/-y7BfWcy2mrk/VdjTarfr1WI/AAAAAAAE-ko/NmIiFf_4X_o/s320/20150821_102_2559.JPG" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<h3>
Day 3 宮原眼科 -> 清水財伯米糕 -> 高美濕地 -> 西湖休息站 -> 回家</h3>
這次去台中車站旁的宮原眼科,運氣很好的在旁邊找到路邊停車格 (雖然也繞了三圈,但居然在星期六的中午找到路邊停車格,Lucky!)<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-Bd1pIMRwrpE/VdjT0pbK_4I/AAAAAAAE-mk/D-crwLo1aMg/s1600/20150822_102_2570.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://1.bp.blogspot.com/-Bd1pIMRwrpE/VdjT0pbK_4I/AAAAAAAE-mk/D-crwLo1aMg/s640/20150822_102_2570.JPG" width="640" /></a></div>
<br />
滿滿的人要排冰淇淋,我個人是還好,小柔那個來也不能吃冰,所以就不排了!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-1ZBQlBw1DXA/VdjT7lQO8OI/AAAAAAAE-nE/ue0xquFi93M/s1600/20150822_102_2573.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://1.bp.blogspot.com/-1ZBQlBw1DXA/VdjT7lQO8OI/AAAAAAAE-nE/ue0xquFi93M/s320/20150822_102_2573.JPG" width="320" /></a><a href="http://1.bp.blogspot.com/-zsrq7N4gxlg/VdjT90mk2wI/AAAAAAAE-nM/hRfDF-cBOwY/s1600/20150822_102_2574.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://1.bp.blogspot.com/-zsrq7N4gxlg/VdjT90mk2wI/AAAAAAAE-nM/hRfDF-cBOwY/s320/20150822_102_2574.JPG" width="320" /></a></div>
<br />
伴手禮的店,我們買了小柔哥哥最喜歡吃的乳酪蛋糕,剛好他今天生日,帶回去給他吃。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-nUYx_zOJBSQ/VdjUFAY2q_I/AAAAAAAE-no/luR0R107Hf0/s1600/20150822_102_2577.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-nUYx_zOJBSQ/VdjUFAY2q_I/AAAAAAAE-no/luR0R107Hf0/s320/20150822_102_2577.JPG" width="320" /></a><a href="http://1.bp.blogspot.com/-HOcgpStRzE0/VdjUHfjO0_I/AAAAAAAE-nw/V6EfyOqVwtw/s1600/20150822_102_2578.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://1.bp.blogspot.com/-HOcgpStRzE0/VdjUHfjO0_I/AAAAAAAE-nw/V6EfyOqVwtw/s320/20150822_102_2578.JPG" width="320" /></a></div>
<br />
接下來出發往清水走,先去吃個有名的米糕!不錯!醬汁很香很夠味!<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-oTQwPZb0FFc/VdjUbC0rgRI/AAAAAAAE-os/kpWwTdVkqlI/s1600/20150822_102_2585.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://1.bp.blogspot.com/-oTQwPZb0FFc/VdjUbC0rgRI/AAAAAAAE-os/kpWwTdVkqlI/s640/20150822_102_2585.JPG" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZTixH35lMM3z84y6sePVtVuBzQqFaKnd_E9YXzsTagnbfV2XuHaLS2osr76v_6Auq4KFvHpYMrzquTuUj-iQEyPMC90D0qMYwVMuaemkLPtMgdHKu7usvy5IaPmVr-leaGJ9SCg/s1600/IMAG5671.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZTixH35lMM3z84y6sePVtVuBzQqFaKnd_E9YXzsTagnbfV2XuHaLS2osr76v_6Auq4KFvHpYMrzquTuUj-iQEyPMC90D0qMYwVMuaemkLPtMgdHKu7usvy5IaPmVr-leaGJ9SCg/s640/IMAG5671.jpg" width="640" /></a></div>
<br />
本來的計劃是小柔想要去高美濕地抓蛤蠣,但太久沒來了,不知道現在已經在進行生態保護,架了個高高的步道,人不能下去…,我們還帶了網子過去… (不過看到旁邊有人拿著路邊攤在賣的小朋友挖沙組,他應該比我們還嘔!路邊攤還在賣那個實在是詐欺啊!)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-bk3DO8OEJoQ/VdjUf_9jWQI/AAAAAAAE-pI/0pQmF5Az_pg/s1600/20150822_102_2588.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://4.bp.blogspot.com/-bk3DO8OEJoQ/VdjUf_9jWQI/AAAAAAAE-pI/0pQmF5Az_pg/s320/20150822_102_2588.JPG" width="320" /></a><a href="http://1.bp.blogspot.com/-pdYO_YPUPqQ/VdjUsYXKrEI/AAAAAAAE-p0/52sqGhD7l_8/s1600/20150822_102_2593.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://1.bp.blogspot.com/-pdYO_YPUPqQ/VdjUsYXKrEI/AAAAAAAE-p0/52sqGhD7l_8/s320/20150822_102_2593.JPG" width="320" /></a><a href="http://1.bp.blogspot.com/-lYSyNxAuApU/VdjUx0WmFPI/AAAAAAAE-qI/1FCRqJOPw2o/s1600/20150822_102_2595.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://1.bp.blogspot.com/-lYSyNxAuApU/VdjUx0WmFPI/AAAAAAAE-qI/1FCRqJOPw2o/s320/20150822_102_2595.JPG" width="320" /></a><a href="http://3.bp.blogspot.com/-W9YcEMh_AmM/VdjU5DJ4xhI/AAAAAAAE-qg/6gh0uiacolc/s1600/20150822_102_2598.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-W9YcEMh_AmM/VdjU5DJ4xhI/AAAAAAAE-qg/6gh0uiacolc/s320/20150822_102_2598.JPG" width="320" /></a><a href="http://2.bp.blogspot.com/-AdCgR0FiuNY/VdjVNbhCAkI/AAAAAAAE-rs/iGzo1kByTkA/s1600/20150822_102_2606.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-AdCgR0FiuNY/VdjVNbhCAkI/AAAAAAAE-rs/iGzo1kByTkA/s320/20150822_102_2606.JPG" width="320" /></a></div>
<br />
不過這次看到滿滿的螃蟹跟一群一群的魚苗,這裡生態的保護真的有做有差。<br />
結束清水高美濕地的曬太陽行程後,就要出發回台北了,路上經過西湖休息站,因為太想睡覺,就先在這裡休息一下。<br />
<br />
西湖休息站有讓我驚訝,覺得不比清水差啊!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-FYph5CMWD9I/VdjVdO76VaI/AAAAAAAE-sk/cbe-4pi4Ze0/s1600/20150822_102_2612.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-FYph5CMWD9I/VdjVdO76VaI/AAAAAAAE-sk/cbe-4pi4Ze0/s320/20150822_102_2612.JPG" width="320" /></a><a href="http://2.bp.blogspot.com/-6sQIlUpV8CM/VdjVXuYqZSI/AAAAAAAE-sQ/c1sQilWiylk/s1600/20150822_102_2610.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-6sQIlUpV8CM/VdjVXuYqZSI/AAAAAAAE-sQ/c1sQilWiylk/s320/20150822_102_2610.JPG" width="320" /></a></div>
<br />
有人說怎麼會有奶頭…我就進來幫奶頭餅拍了幾張照…<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-yhn1im72qkM/VdjVh07YBXI/AAAAAAAE-ss/pdhVJV5jD4I/s1600/20150822_102_2614.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://1.bp.blogspot.com/-yhn1im72qkM/VdjVh07YBXI/AAAAAAAE-ss/pdhVJV5jD4I/s320/20150822_102_2614.JPG" width="320" /></a><a href="http://3.bp.blogspot.com/-keBF6ESmQM4/VdjVmWsgt4I/AAAAAAAE-tE/9iOk4ppgr_A/s1600/20150822_102_2615.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-keBF6ESmQM4/VdjVmWsgt4I/AAAAAAAE-tE/9iOk4ppgr_A/s320/20150822_102_2615.JPG" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-Rfgm2pQx6aE/VdjVp9TKbOI/AAAAAAAE-tQ/qX939TNqFGk/s1600/20150822_102_2617.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://2.bp.blogspot.com/-Rfgm2pQx6aE/VdjVp9TKbOI/AAAAAAAE-tQ/qX939TNqFGk/s640/20150822_102_2617.JPG" width="640" /></a></div>
<br />
童心未泯的小柔!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-mscTFZ5zIOY/VdjVvYiLX5I/AAAAAAAE-tk/p22-7BCoons/s1600/20150822_102_2619.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://1.bp.blogspot.com/-mscTFZ5zIOY/VdjVvYiLX5I/AAAAAAAE-tk/p22-7BCoons/s640/20150822_102_2619.JPG" width="640" /></a></div>
<br />出發前買了新東陽的熊厚呷鹽酥雞,熱的時候還不錯,但冷了就蠻難吃的(有些感覺油溫夠高的冷了還是會好吃)。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-CjMHF_axKcw/VdjV0NUZCwI/AAAAAAAE-t0/Tmq6xfqirf8/s1600/20150822_102_2621.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://3.bp.blogspot.com/-CjMHF_axKcw/VdjV0NUZCwI/AAAAAAAE-t0/Tmq6xfqirf8/s640/20150822_102_2621.JPG" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-s-1B9u4XP4U/VdjV2TkhwvI/AAAAAAAE-t8/X7m0iIXN4KU/s1600/20150822_102_2622.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://4.bp.blogspot.com/-s-1B9u4XP4U/VdjV2TkhwvI/AAAAAAAE-t8/X7m0iIXN4KU/s640/20150822_102_2622.JPG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
簡簡單單的三天台中行,走著非常輕鬆的行程,但感覺很不滿足,覺得不久之後應該又要再來一趟了!<br />
<br />
<br />
<br />
<br />
<br />joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0台灣台中市24.1477358 120.673648223.2209853 119.3827547 25.0744863 121.9645417tag:blogger.com,1999:blog-11438439.post-68039071442460750652015-08-19T05:50:00.001+08:002015-08-19T05:51:16.980+08:00[ScaVa->Scala] Scalaz Task 取代Scala Future來進行非同步處理的另一個選擇<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>[ScaVa->Scala] Scalaz Task 取代Scala Future來進行非同步處理的另一個選擇</title>
<link rel="stylesheet" href="http://yandex.st/highlightjs/7.5/styles/github.min.css">
<script src="http://yandex.st/highlightjs/7.5/highlight.min.js"></script>
</head>
<body><h1 id="scava-scala-scalaz-task-取代scala-future來進行非同步處理的另一個選擇">[ScaVa->Scala] Scalaz Task 取代Scala Future來進行非同步處理的另一個選擇</h1>
<blockquote>
<p>這篇同步發佈在我的<a href="http://blog.joecwu.com/2015/08/scava-scala-scalaz-task-scala-future.html">Blog</a>和<a href="https://gist.github.com/joecwu/d0bbf8ebf5998cfb04fc">Gist</a>。</p>
</blockquote>
<h2 id="scala的future用起來有什麼問題">Scala的Future用起來有什麼問題?</h2>
<p>在Scala中,我們要處理asynchronous computations的時候應該都知道有Future這個好用的東西,但Future monad常讓我在進行error handling的時候有點困擾,我本來的回傳值若是有”成功”或”失敗”兩種case的時候,我們可以用<a href="http://blog.joecwu.com/2015/07/scava-scala-scalaz-either.html">Scalaz的disjuction</a>或是<a href="http://blog.joecwu.com/2015/07/scava-scala-scalaz-validation-either-scalactic.html">Scalactic的Or</a>來處理,但是加上Future後的結果會變成:</p>
<pre><code>// Scalaz Disjunction
getName1() : Future[Exception \/ String]
res: Future[scalaz.\/[Exception,String]]
// Scalactic
getName2() : Future[String Or One[Exception]]
res: Future[org.scalactic.Or[String,org.scalactic.Every[Exception]]]
</code></pre>
<p>這樣有什麼問題呢? <br>
- 本來在Future中執行的computation,有可能有”成功”或”失敗”(就是Disjunction或Or所傳回來的) <br>
- Future的處理過程,也有可能有”成功”或”失敗”</p>
<pre><code>// Scalaz
getName1().onComplete{ resp =>
resp match {
case Success(nameOrError) => nameOrError match {
case Right(name) => name
case Left(ex) => // handle error from computation
}
case Failure(ex) => // handle error from future process
}
}
// Scalactic
getName2().onComplete{ resp =>
resp match {
case Success(nameOrError) => nameOrError match {
case Good(name) => name
case Bad(One(ex)) => // handle error from computation
}
case Failure(ex) => // handle error from future process
}
}
</code></pre>
<p>這樣在處理的時候,要分兩層去處理,先去處理Future的失敗狀況,再去處理拿到的值裡面的失敗狀況。</p>
<h2 id="scalaz-task">Scalaz Task</h2>
<p>Scalaz的concurrent模組 (不是包在Scalaz的core哦! 所以要使用的要另外載入這個模組) 有提供Task這個好用的東西,他可以取代Future並提供一些比Future還好用的東西。</p>
<p>底下是一些Scalaz Task中的特性,我稍微列幾點,其它的請參考 <a href="http://timperrett.com/2014/07/20/scalaz-task-the-missing-documentation/">Scalaz Task - the missing documentation</a>。</p>
<h3 id="taskapply"><code>Task.apply</code></h3>
<pre><code>def getName(fail:Boolean) : Task[String] = {
Task{ fail ? {throw new Exception("error")} | "joe" }
}
getName(false).attemptRun
res: scalaz.\/[Throwable,String] = \/-(joe)
getName(false).attemptRun.getOrElse("noName")
res: String = joe
</code></pre>
<p>這裡的Task跟Future有點不一樣的是,在apply的時候,Task是lazy的,也就是你必須使用<code>run</code>或是<code>attemptRun</code>之類的,才會讓他真的去執行,但是<code>run</code>就跟Option的<code>get</code>一樣,是危險的! 不建議這樣直接使用。</p>
<h3 id="tasknow-與-taskfail"><code>Task.now</code> 與 <code>Task.fail</code></h3>
<pre><code>Task.now("joe")
res: scalaz.concurrent.Task[String]
</code></pre>
<p>這個應該就是applicative的pure吧,直接把native型態的值,轉成Functor型態的值。</p>
<pre><code>Task.fail(new Exception("err"))
res: scalaz.concurrent.Task[Nothing]
</code></pre>
<p>這裡要注意的是,fail這裡定義的回傳型態就是<code>Task[Nothing]</code>,所以如果你要指定某個型態的Task的話,可以用下面這種方式來試。</p>
<pre><code>Task[String](throw new Exception("err"))
res: scalaz.concurrent.Task[String]
</code></pre>
<p>另外,Task可以使用<code>or</code>來串接多個Task,而他的邏輯就是or,也就是有值的話就會回傳值,若通通都是錯誤的話,他會回傳最後一個Exception。</p>
<pre><code>Task.fail(new Exception("err")) or Task.now("joe")
res: scalaz.concurrent.Task[String]
</code></pre>
<h3 id="taskasync"><code>Task.async</code></h3>
<p><code>async</code>是幫你把callback API包成monadic API,讓你在處理一些callback API的時候還能functional programming啊~</p>
<pre><code> def async[A](register: ((Throwable \/ A) => Unit) => Unit): Task[A] =
new Task(Future.async(register))
</code></pre>
<p>這裡可以看到,async吃一個命名為register的function,這個register function傳入的值是另一個匿名的function,然後回傳型態是Unit;這個匿名的function傳入型態是<code>Throwable \/ A</code>,他的回傳也是Unit。</p>
<p>這東西真的很棒,我們有時難免會使用到Java開發的Library,而總是會有一些callback的介面要去實作,透過async包起來之後,就可以再享受到Monad的好處。</p>
<p>以下的範例,是來自<a href="http://timperrett.com/2014/07/20/scalaz-task-the-missing-documentation/">Scalaz Task - the missing documentation</a>,這裡以Java的AsyncHttpClient為例,告訴我們如果包裝一個callback API成為Task,進而就可以使用Monad的flatMap這樣的function。</p>
<pre><code>asyncHttp.prepareGet("http://google.com", new AsyncCompletionHandler[Response] {
def onComplete(r: Response) = ...
def onError(e: Throwable) = ...
})
def get(s: String) =
Task.async(k => asyncHttp.prepareGet(s, toHandler(k)))
def toHandler[A](k: (Throwable \/ A)) = new AsyncCompletionHandler[A] {
def onComplete(r: Response) = k(...)
def onError(e: Throwable) = k(...)
}
// usage:
get("http://google.com").flatMap(response => ...)
</code></pre>
<h3 id="taskgatherunordered-taskreduceunordered"><code>Task.gatherUnordered</code>, <code>Task.reduceUnordered</code></h3>
<p><code>gatherUnordered</code>是<code>reduceUnordered</code>針對回傳型態是List[T]的implementation,而<code>gatherUnordered</code>就像是Scala Future的<code>Future.traverse</code>或<code>Future.sequence</code>,他能幫你將List of Tasks的回傳值給合併起來,例如</p>
<pre><code>val tasks = (1 |-> 5).map(n => Task{n})
Task.gatherUnordered(tasks).run
res: List[Int] = List(1,3,4,2,5)
// 注意回傳的結果不是照順序的,因為是平行處理的
</code></pre>
<p>而<code>reduceUnordered</code>就是當你回傳的結果不是List而是要其他的型態的時候,可以自己implement。</p>
<h3 id="taskonfinish"><code>Task.onFinish</code></h3>
<p>這個<code>onFinish</code>的回傳值是<code>Option[Throwable] => Task[Unit]</code>可以讓你針對處理結束時進行handle,例如想要close一些resource等。</p>
<h3 id="tasktimed"><code>Task.timed</code></h3>
<p>這東西很好用!就是幫你handle timeout,之前在寫Future的時候,必需使用<code>Await</code>來處理timeout的狀況,而且寫起來蠻麻煩的,使用<code>timed</code>寫起來就簡單多了,而且有錯誤的話(會丟<code>java.util.concurrent.TimeoutException</code>),直接在原本Task回傳的Disjunction中就可以handle了。</p>
<pre><code>import scala.concurrent.duration._
Task { Thread.sleep(1000); "Yo" }.timed(100 millis).attemptRun
res: scalaz.\/[Throwable,String] = -\/(java.util.concurrent.TimeoutException)
</code></pre>
<h3 id="taskhandlewith"><code>Task.handleWith</code></h3>
<p>這就像是使用<code>onFailure</code>來處理Scala的Future一樣,看你要針對某些類型的exception做什麼樣特別的處理。</p>
<pre><code>Task[String] { throw new Exception("yo") }.handleWith{
case Exception(ex) => // do something
}
</code></pre>
<h2 id="reference">Reference</h2>
<ul>
<li><a href="http://timperrett.com/2014/07/20/scalaz-task-the-missing-documentation/">Scalaz Task - the missing documentation</a></li>
</ul></body>
</html>joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-27908455898947915992015-08-14T03:11:00.001+08:002015-08-14T03:13:56.139+08:00[ScaVa->Scala] Scalaz Writer Monad<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>[ScaVa->Scala] Scalaz Writer Monad</title>
<link rel="stylesheet" href="http://yandex.st/highlightjs/7.5/styles/github.min.css">
<script src="http://yandex.st/highlightjs/7.5/highlight.min.js"></script>
</head>
<body><h1 id="scava-scala-scalaz-writer-monad">[ScaVa->Scala] Scalaz Writer Monad</h1>
<blockquote>
<p>這篇同步發佈在我的<a href="http://blog.joecwu.com/2015/08/scava-scala-scalaz-writer-monad.html">Blog</a>和<a href="https://gist.github.com/joecwu/1fb2c619836161cac354">Gist</a>。</p>
</blockquote>
<p>之前一篇 <a href="http://blog.joecwu.com/2015/08/scalaread-monaddependency-injection.html">[ScaVa->Scala] Scala中使用Reader Monad來實現Dependency Injection</a> ,裡面提到了Scalaz中的Reader Monad,有Reader當然也要有個Writer呀!!</p>
<h2 id="使用情境">使用情境</h2>
<p>Writer Monad在scalaz的source code裡的註解是<code>Computations that log a value</code> <br>
假設今天有一個需求,是要進行一個有多個步驟的處理,而這個處理的過程我們需要Log起來,也就是在每個步驟加上對應的記錄,並且在處理完成之後,要能把過程印在畫面上,在許多個步驟在處理時,這些Log要怎麼收集呢?</p>
<p>或許可以寫File或是塞DB啊!要能同時處理多個Request, 就是給不同的id產生不同的file,然後把log都寫進去,最後完成時,再把檔案讀出來(或是查db)回傳出去。但這樣寫File的I/O其實很浪費,用DB的話更浪費了。所以如果資料量小小的,我們存在記憶體裡就好了,但是在這種implement上,怎麼寫比較方便呢?其實用tuple可以做到(第一個放這個步驟處理完真正的回傳值,第二個放對應的描述log),但是每個步驟都要把結果串在一起,寫起來很辛苦,這時候就可以用上Writer Monad。</p>
<h2 id="writer-monad">Writer Monad</h2>
<p><code>Writer</code>其實是<code>WriterT</code>的別名(alias),並且指定WriterT中的第一個型態<code>scalaz.Id</code>是scalaz的<a href="http://eed3si9n.com/learning-scalaz/Id.html">Identity Monad</a>。</p>
<h3 id="writer">Writer</h3>
<pre><code>type Writer[W, A] = WriterT[Id, W, A]
object Writer {
def apply[W, A](w: W, a: A): WriterT[Id, W, A] = WriterT[Id, W, A]((w, a))
}
</code></pre>
<p>WriterT這邊主要裡面有個<code>run</code>,他就是幫你把這兩個值(一個是你原本的值,另一個是你要寫的log)包在一起成tuple,然後放進Identity Monad,另外就是written和value了,分別是你所<strong>write</strong>的log,和本來要回傳的value。</p>
<h3 id="writert">WriterT</h3>
<pre><code>sealed trait WriterT[F[+_], +W, +A] { self =>
val run: F[(W, A)]
def written(implicit F: Functor[F]): F[W] =
F.map(run)(_._1)
def value(implicit F: Functor[F]): F[A] =
F.map(run)(_._2)
}
</code></pre>
<h2 id="舉個例子">舉個例子</h2>
<p>我有四個動作: <br>
1. 用名字查出User的Id <br>
2. 用Id查這個User的State <br>
3. 用Id再查User的Age <br>
4. 最後做個Foo的Check</p>
<pre><code>def searchUserId(name:String)=123.set(Vector(s"search user with name:[$name] found id:[123]"))
def getState(id:Int)="alive".set(Vector("state is alive"))
def getAge(id:Int)=18.set(Vector("age is 18"))
def checkFoo(state:String,age:Int)=(age>=18)?"Old Foo".set(Vector(s"age older then 18 is Old Foo."))|"Young Foo".set(Vector(s"age younger than 18 is Young Foo."))
val foo = for{
uid <- searchUserId("Joe")
state <- getState(uid)
age <- getAge(uid)
foo <- checkFoo(state,age)
} yield foo
foo: scalaz.WriterT[scalaz.Id.Id,scala.collection.immutable.Vector[String],String] = WriterT((Vector(search user with name:[Joe] found id:[123], state is alive, age is 18, age older then 18 is Old Foo.),Old Foo))
foo.value
scalaz.Id.Id[String] = Old Foo
foo.written
scalaz.Id.Id[scala.collection.immutable.Vector[String]] = Vector(search user with name:[Joe] found id:[123], state is alive, age is 18, age older then 18 is Old Foo.)
</code></pre>
<p>可以看到,因為是monad,所以我這邊透過for comprehension來把這些動作串起來,最後產生了<code>foo</code>,而他的<code>value</code>就是最後處理完成的結果,而<code>written</code>就是我每個過程中附加上來的log,是不是簡單好用呢?</p>
<h2 id="有關效能的注意事項">有關效能的注意事項</h2>
<p>當你要把一個Monoid(在我們的例子用的Monoid是Vector)放在Writer Monad裡的時候,要注意performance的考量。Learning-Scalaz的文章裡有做了個測試,若是用List的話,花的時間會是Vector的兩倍哦!</p>
<blockquote>
<p>Reference <br>
- <a href="http://eed3si9n.com/learning-scalaz/Writer.html">Learning-Scalaz Writer</a> <br>
- <a href="http://eed3si9n.com/learning-scalaz/Id.html">Learning-Scalaz Id</a></p>
</blockquote></body>
</html>joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-27361607133592650332015-08-12T04:10:00.001+08:002015-08-12T04:12:18.891+08:00[ScaVa->Scala] Introduction to Scala Development<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>[ScaVa->Scala] Introduction to Scala Development</title>
<link rel="stylesheet" href="http://yandex.st/highlightjs/7.5/styles/github.min.css">
<script src="http://yandex.st/highlightjs/7.5/highlight.min.js"></script>
</head>
<body><h1 id="scava-scala-introduction-to-scala-development">[ScaVa->Scala] Introduction to Scala Development</h1>
<h2 id="前言">前言</h2>
<p>這件文件是在公司內部向一些新踏入Scala領域的同事們介紹所使用的資料,因此適合有程式開發經驗,並且想Scala領域中的朋友們。 <br>
底下列了一些學習Scala的資源、並列出一些我們自己開發常用到的Libraries並適合新手來學習使用的。 <br>
最底下有兩各sample projects,以<strong>縮網址</strong>為題目來分別實作一個library與提供REST服務的web application。</p>
<h2 id="scala-introduction">Scala Introduction</h2>
<h3 id="learning-scala">Learning Scala</h3>
<ul>
<li><p><a href="http://docs.scala-lang.org/tutorials/scala-for-java-programmers.html">Scala for Java Programmer</a></p></li>
<li><p><a href="https://www.youtube.com/watch?v=grvvKURwGNg&feature=youtu.be">Scala for the Intrigued</a></p></li>
<li><p><a href="http://danielwestheide.com/scala/neophytes.html">The Neophyte’s Guide to Scala</a></p></li>
<li><p><a href="http://scala-exercises.47deg.com/">Scala Excercises</a> - The easy way to learn Scala.</p></li>
<li><p><a href="https://www.youtube.com/watch?v=2yfq_xHcVV0&feature=youtu.be">Intro to ScalaTest</a></p></li>
</ul>
<h3 id="functional-programming">Functional Programming</h3>
<p><a href="https://gist.github.com/cb372/b1bad150e0c412fb7364">Category theory jargon cheat sheet</a></p>
<ul>
<li>Functor supports <code>map</code>.</li>
<li>Applicative functor extends functor and adds <code>pure</code> and <code><*></code>.</li>
<li>Monad extends applicative and adds <code>flatMap</code> (a.k.a <code>bind</code>).</li>
<li>Semigroup supports <code>append</code>.</li>
<li>Monoid extends Semigroup and adds <code>zero</code>.</li>
</ul>
<h3 id="scala-libraries-frameworks-and-software">Scala Libraries, Frameworks and Software.</h3>
<p>Check most popular scala libraries at GitHub - <a href="https://github.com/lauris/awesome-scala">awesome-scala</a>.</p>
<p>Common use libraries in our development.</p>
<ul>
<li><p>Distributed System</p>
<ul><li><a href="http://akka.io/">Akka</a> — A toolkit and runtime for building highly concurrent, distributed, and fault tolerant event-driven applications.</li></ul></li>
<li><p>Database</p>
<ul><li><a href="https://github.com/sksamuel/elastic4s">Elastic4s</a> — A scala DSL / reactive client for Elasticsearch</li>
<li><a href="https://github.com/ReactiveMongo/ReactiveMongo">ReactiveMongo</a> — Reactive Scala Driver for MongoDB.</li>
<li><a href="https://github.com/etaty/rediscala">rediscala</a> — Non-blocking, Reactive Redis driver for Scala (with Sentinel support)</li></ul></li>
<li><p>Web Framework</p>
<ul><li><a href="https://github.com/playframework/playframework">Play</a> — Makes it easy to build scalable, fast and real-time web applications with Java & Scala.</li>
<li><a href="https://github.com/scalatra/scalatra">Scalatra</a> — Tiny Scala high-performance, async web framework, inspired by Sinatra.</li>
<li><a href="https://github.com/spray/spray">Spray</a> — A suite of scala libraries for building and consuming RESTful web services on top of Akka.</li>
<li><a href="https://github.com/twitter/finatra">Finatra</a> — A sinatra-inspired web framework for scala, running on top of Finagle.</li>
<li><a href="http://sockoweb.org/">Socko</a> — An embedded Scala web server powered by Netty networking and Akka processing.</li></ul></li>
<li><p>HTTP client</p>
<ul><li><a href="https://github.com/dispatch/reboot">Dispatch</a> — Library for asynchronous HTTP interaction. It provides a Scala vocabulary for Java’s <a href="https://github.com/AsyncHttpClient/async-http-client">async-http-client</a>.</li>
<li><a href="http://spray.io/">Spray</a> — Actor-based library for http interaction.</li></ul></li>
<li><p>Json</p>
<ul><li><a href="https://github.com/json4s/json4s">json4s</a> — Project aims to provide a single AST to be used by other scala json libraries.</li>
<li><a href="https://github.com/FasterXML/jackson-module-scala">jackson-module-scala</a> — Add-on module for Jackson to support Scala-specific datatypes.</li></ul></li>
<li><p>Config</p>
<ul><li><a href="https://github.com/typesafehub/config">config</a> — Configuration library for JVM languages <a href="http://typesafe.com">http://typesafe.com</a>. (Akka embedded this config module.)</li></ul></li>
<li><p>Logger</p>
<ul><li><a href="https://github.com/bmc/grizzled-slf4j">Grizzled-SLF4J</a> — A simple, Scala-friendly front-end to SLF4J.</li></ul></li>
<li><p>Testing</p>
<ul><li><a href="https://github.com/scalatest/scalatest">ScalaTest</a> — A testing tool for Scala and Java developers.</li>
<li><a href="http://gatling-tool.org/">Gatling</a> – Async Scala-Akka-Netty based Stress Tool.</li></ul></li>
<li><p>Extensions</p>
<ul><li><a href="https://github.com/scalaz/scalaz">Scalaz</a> — An extension to the core Scala library for functional programming.</li>
<li><a href="https://github.com/scala/async">Scala Async</a> — An asynchronous programming facility for Scala.</li>
<li><a href="http://www.scalactic.org/">Scalactic</a> — Small library of utilities related to quality that helps keeping code clear and correct. (ScalaTest embedded this lib.)</li></ul></li>
</ul>
<h2 id="development-environment">Development Environment</h2>
<h3 id="scala">Scala</h3>
<h3 id="sbt-simple-build-tool">SBT (Simple Build Tool)</h3>
<p><a href="http://www.scala-sbt.org/">http://www.scala-sbt.org/</a></p>
<p>Package Plugins <a href="http://www.scala-sbt.org/release/docs/Community-Plugins.html">http://www.scala-sbt.org/release/docs/Community-Plugins.html</a></p>
<ul>
<li>sbt-native-packager: <a href="https://github.com/sbt/sbt-native-packager">https://github.com/sbt/sbt-native-packager</a></li>
<li>sbt-assembly: <a href="https://github.com/sbt/sbt-assembly">https://github.com/sbt/sbt-assembly</a></li>
<li>sbt-onejar (Packages your project using One-JAR™): <a href="https://github.com/sbt/sbt-onejar">https://github.com/sbt/sbt-onejar</a></li>
</ul>
<h3 id="ide-intellij-idea">IDE - Intellij Idea</h3>
<p>You’re welcome to use any text editor or IDE what you like. e.g. vim, TextMate, Sublime, Notepad++, cloud9…</p>
<p>However my favorite IDE for Scala development is <a href="https://www.jetbrains.com/idea/">Intellij Idea</a>, which is most powerful IDE for scala development.</p>
<h3 id="directory-structure">Directory Structure</h3>
<p>Ref: <a href="http://www.scala-sbt.org/0.13/tutorial/Directories.html">SBT Directory Structure</a></p>
<p>source code</p>
<pre><code>src/
main/
resources/
<files to include in main jar here>
scala/
<main Scala sources>
java/
<main Java sources>
test/
resources
<files to include in test jar here>
scala/
<test Scala sources>
java/
<test Java sources>
</code></pre>
<p>sbt build definition files</p>
<pre><code>build.sbt
project/
Build.scala
</code></pre>
<h2 id="others">Others</h2>
<ul>
<li>Markdown</li>
<li>Git</li>
<li>Chef</li>
</ul>
<h1 id="demo">Demo</h1>
<ul>
<li><p>URL Shortener <br>
<a href="https://github.com/joecwu/shortener">URL Shortener</a></p></li>
<li><p>URL Shortener - Socko-Web implementation <br>
<a href="https://github.com/joecwu/shortener-sockoweb">Shortener-Sockoweb</a></p></li>
</ul></body>
</html>joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-25589433161677039742015-08-11T05:07:00.001+08:002015-08-12T03:56:36.562+08:00[ScaVa->Scala] Scala中使用Reader Monad來實現Dependency Injection<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>[ScaVa->Scala] Scala中使用Reader Monad來實現Dependency Injection</title>
<link rel="stylesheet" href="http://yandex.st/highlightjs/7.5/styles/github.min.css">
<script src="http://yandex.st/highlightjs/7.5/highlight.min.js"></script>
</head>
<body><h1 id="scava-scala-scala中使用reader-monad來實現dependency-injection">[ScaVa->Scala] Scala中使用Reader Monad來實現Dependency Injection</h1>
<blockquote>
<p>此篇文章同時發步於<a href="http://blog.joecwu.com/2015/08/scalaread-monaddependency-injection.html">Blog</a>與<a href="https://gist.github.com/joecwu/3e1461d7fb1df268c482">Gist</a></p>
</blockquote>
<h2 id="前言">前言</h2>
<p>上週寫了一篇<a href="http://blog.joecwu.com/2015/08/url-shortener.html">老闆說大家來寫個URL Shortener</a>,裡面的 <a href="https://gist.github.com/joecwu/ff4dd622c7e570fd12f2#file-blog-shortener-design-concept-md">Design Concept</a>使用了Implicit來做DI(Dependency Injection),也就是把DBClient設計成可從外部指定。</p>
<p>但是其實在Scala中使用Functional Programming的特性實現DI的方式不只這一種,在這種想要把DBClient抽取出來而使用<code>Implicit</code>的方式,會有以下兩點要考慮的:</p>
<ol>
<li>所有使用到DBClient的function,全都要加上<code>(implicit dbClient:DBClient)</code>這樣的描述,如果外層沒有要用到,而內層有用到,外層還是要加上這樣的描述。</li>
<li>Implicit的概念上應該比較是”使用者可忽略”的,但是DBClient在這邊其實並不是一個需要被忽略的,而只是為了減少大量重覆的code。</li>
</ol>
<p>所以在這邊我們要嘗試另一個Reader Monad的方式,來實現DI。</p>
<h2 id="reader-monad">Reader Monad</h2>
<p>有關Reader Monad,這兩篇文章寫得很清楚:</p>
<ul>
<li><a href="http://blog.yunglinho.com/blog/2012/04/22/dependency-injection-in-scala/">Dependency Injection in Scala (中文)</a></li>
<li><a href="http://blog.originate.com/blog/2013/10/21/reader-monad-for-dependency-injection/">Scrap Your Cake Pattern Boilerplate: Dependency Injection Using the Reader Monad</a></li>
</ul>
<p>裡面寫到的不止是Reader Monad,包含了Scala中常用到的Cake Pattern,以及轉換成使用Reader Monad的好處。</p>
<p>這裡舉個例子,這是本來使用implicit的方式,在updateUserName的function裡,其實並沒有用到DBClient,但是他呼叫的getUser和setUser有使用到,所以他也要寫這個implicit的宣告:</p>
<pre><code>case class User(id:Int,name:String)
case class DBClient(conn:String) {
def getUser(id:Int):User = User(id,"USER"+id)
def setUser(user:User):Boolean = {true}
}
object User{
def getUser(id:Int)(implicit db:DBClient) = {
db.getUser(id)
}
def setUser(user:User)(implicit db:DBClient) = {
db.setUser(user)
}
def updateUserName(id:Int,name:String)(implicit db:DBClient) = {
val user = getUser(id)
val newUser = user.copy(name=name)
setUser(user)
}
}
object TestApp{
implicit val dbClient = DBClient("Test")
def main() {
val user = User.getUser(123)
User.updateUserName(123,"Yo")
}
}
</code></pre>
<p>但若使用ReaderMonad的話(這裡的Reader是使用scalaz):</p>
<pre><code>case class User(id:Int,name:String)
case class DBClient(conn:String) {
def getUser(id:Int):User = User(id,"USER"+id)
def setUser(user:User):Boolean = {true}
}
object User{
def getUser(id:Int) = Reader((db:DBClient) => {
db.getUser(id)
})
def setUser(user:User) = Reader((db:DBClient) =>{
db.setUser(user)
})
def updateUserName(id:Int,newName:String) = {
for{
user <- getUser(id)
result <- setUser(user.copy(name=newName))
} yield result
}
}
object TestApp{
val dbClient = DBClient("Test")
def main() {
val user = run(User.getUser(123))
run(User.updateUserName(123,"Yo"))
}
private def run[A](reader: Reader[DBClient, A]): A = {
reader(dbClient)
}
}
</code></pre>
<p>這邊可以看到一個有趣的東西,User裡的getUser和setUser因為使用Reader Monad,所以他就有了Monad的特性 (關於Monad可參考之前寫的這兩篇: <a href="http://blog.joecwu.com/2015/07/scava-scala-monad.html">[ScaVa->Scala] 什麼是Monad?</a>和<a href="http://blog.joecwu.com/2015/08/scava-scala-functor-applicative-monad.html">Category theory(範疇論)之什麼是Functor, Applicative, Monad, Semigroup, Monoid?</a>)。</p>
<p>因此我們在updateUserName這裡,可以直接使用for comprehension的方式把他們串在一起,當然有Monad的特性在很多地方使用上都會很方便。</p>
<p>在外面使用上,其實<code>getUser</code>、<code>setUser</code>、<code>updateUserName</code>,這些function的回傳值都是一個”Function”,這個function要傳入的是DBClient,回傳的是他們本來要回傳的值,只是這個function是使用Reader Monad包起來。</p>
<p>我們對於所有這些同樣型態的Reader Monad,可以定義個統一的處理方式,在這裡就是<code>run</code>,其實這個run就是一個general的handler,甚至可以做一些轉成Json或是error handling的處理,很方便的!</p>
<h2 id="shortener">Shortener</h2>
<p>Shortener也更新至0.2.0,以Reader Monad來implement Shortener使用DBClient的部份。</p>
<pre><code>trait Shortener {
def shorter(url:String)(implicit tracerInfo: TracerInfo) : Reader[DBClient, String Or BaseException]
def taller(short:String)(implicit tracerInfo: TracerInfo) : Reader[DBClient, String Or BaseException]
}
</code></pre>
<p>詳細的程式請至<a href="https://github.com/joecwu/shortener/tree/0.2.0">GitHub</a>上面看嘍。</p></body>
</html>joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-66720355827109683602015-08-08T20:56:00.001+08:002015-08-11T02:45:19.423+08:00Category theory(範疇論)之什麼是Functor, Applicative, Monad, Semigroup, Monoid?<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>[ScaVa->Scala] 什麼是Functor, Applicative, Monad, Semigroup, Monoid?</title>
<link rel="stylesheet" href="http://yandex.st/highlightjs/7.5/styles/github.min.css">
<script src="http://yandex.st/highlightjs/7.5/highlight.min.js"></script>
</head>
<body><h1 id="category-theory範疇論之什麼是functor-applicative-monad-semigroup-monoid">Category theory(範疇論)之什麼是Functor, Applicative, Monad, Semigroup, Monoid?</h1>
<blockquote>
<p>這篇同步發佈在我的<a href="http://blog.joecwu.com/2015/08/scava-scala-functor-applicative-monad.html">Blog</a>和<a href="https://gist.github.com/joecwu/5e44e5e540cfce2d6c24">Gist</a>。</p>
</blockquote>
<p>之前曾經寫過一篇 <a href="http://blog.joecwu.com/2015/07/scava-scala-monad.html">什麼是Monad?</a> ,裡面提到了對於Monad的解釋,而今天進一步解釋這些在Functional Programming中常見到的詞:Functor, Applicative, Monad, Semigroup, Monoid。 <br>
透過放在一起比較,讓我們更清楚這些之間的差別與關係。</p>
<h2 id="functor">Functor</h2>
<p>在提到Functor之前,請先了解一下scala中map的作用,map可以讓你傳入一個function,而透過這個function是可以從F[A]轉換成F[B],這裡的F不管他(就是代表外面的包裝不會變),而裡面的A型態轉成B型態。</p>
<p>例如:</p>
<pre><code>val a = List(1,2,3)
val b = a.map( x => x.toString )
</code></pre>
<p>這裡面的 <code>x=>x.toString</code> 是一個scala Function1[Int,String]的implementation,也就是一個<code>(x:Int):String</code>傳入Int,回傳String的function。</p>
<p>這裡的<code>a</code>的型態會是List[Int],而<code>b</code>是List[String],所以map就是把F[A]轉成F[B],轉的方式就是你傳入的function。</p>
<p>再回來說Functor的定義:</p>
<ul>
<li>Identity:一個類型,他有提供F[A]->F[B]的function(在Scala裡就像是map)。</li>
<li>Composition:這個類型,他有所提供上述條件的function(也就是map),具有組合(composition)的特性。</li>
</ul>
<p>第一點沒問題,就是剛才舉的例子。 <br>
第二點,什麼是”組合的特性”? </p>
<pre><code>val f1 = (x:Int)=>x+1
f1: Int => Int = <function1>
val f2 = (x:Int)=>x*2
f2: Int => Int = <function1>
scala> List(1,2,3).map(f1).map(f2)
res8: List[Int] = List(4, 6, 8)
scala> List(1,2,3).map(f2 compose f1)
res9: List[Int] = List(4, 6, 8)
scala> List(1,2,3).map(f1 andThen f2)
res10: List[Int] = List(4, 6, 8)
</code></pre>
<p><strong>註:注意這裡的compose是 <code>f2 compose f1</code></strong></p>
<p>就是說,.map(a).map(b) 會等於 .map(b compose a) 或是 .map(a andThen b)</p>
<h2 id="applicative">Applicative</h2>
<p>而接下來介紹的Applicative,是Functor的延伸,加上了以下兩點的特性。</p>
<ul>
<li><code>pure</code>,這個表示能將一個值或是一個function,包進F[]中,像是<code>List(1) 或 Some(1)</code></li>
<li>Homomorphism:提供了能把一堆function分別套給F[]裡的每個值運算,然後結果還是包在F[]裡的特性。</li>
<li>Interchange:就是a*b=b*a這種交換性嘍(不過運算子是針對Applicative的)。</li>
</ul>
<p>第一、三點比較沒問題。我們直接來解釋第二點。 <br>
舉個例來說,在上面的例子我們有個<code>List(1,2,3)</code>並且我們有<code>f1</code>和<code>f2</code>,如果我們想把f1和f2套用到List的每個值中,在Scala的作法可以用for comprehensive:</p>
<pre><code>for{
x <- List(1,2,3)
y <- f1(x)
z <- f2(z)
} yield (z)
</code></pre>
<p>套用scalaz的<code><*></code>這個運算子,可以讓F[A]吃F[(A)=>B],也就是</p>
<pre><code>List(1,2,3) <*> List(f1,f2)
</code></pre>
<p>他把1,2,3這些值分別套到f1,f2中。</p>
<p>再一個比較簡單的例子我們有<code>List(1,2,3)</code>和<code>List(2,4,6)</code>,想要把他相乘,用for comprehensive</p>
<pre><code>scala> for{
| a <- List(1,2,3)
| b <- List(2,4,6)
| } yield (a*b)
res0: List[Int] = List(2, 4, 6, 4, 8, 12, 6, 12, 18)
</code></pre>
<p>若用scalaz的<code>|@|</code>的運算子,則可以寫成</p>
<pre><code>(List(1,2,3) |@| List(2,4,6)) {(_*_)}
</code></pre>
<p>List和Option都是Applicative Functor的例子,可以用這兩個的特性來思考一下!</p>
<h2 id="monad">Monad</h2>
<p>Monad就是Applicative的延伸,加上<code>bind</code>的特性,像是這樣:</p>
<pre><code>trait Monad[M[_]] {
def bind[A, B](m: M[A], f: A => M[B]): M[B]
}
</code></pre>
<p>其實在scala也就是<code>flatMap</code>,舉個例子</p>
<pre><code>val a : List[Int] = List(1,3,5)
val f : (Int)=>List[Int] = (i:Int)=>List(i+1,i+2)
val result : List[Int] = a.flatMap(f)
result: List[Int] = List(2, 3, 4, 5, 6, 7)
</code></pre>
<p>若不用flatMap的話,你拿到的會是<code>List(List(2,3),List(4,5),List(6,7))</code>,flatMap把你把他整理好了!</p>
<h2 id="semigroup">Semigroup</h2>
<p><code>A semigroup is anything that supports appending.</code></p>
<p>這句話簡潔明瞭! <br>
數字2和3可以被append,(用+的就是5,用*的就是6),所以數字是semigroup。 <br>
List和Option也能append,所以他們也是semigroup。 <br>
這裡要注意的定義是:</p>
<ul>
<li>Closure:當F這個型態是semigroup的時候,若A, B是屬於F型態,A+B之後也必須是F型態。</li>
<li>Associative:就像是1 * ( 2 * 3 ) 和 ( 1 * 2 ) * 3 是一樣的。</li>
</ul>
<p>在scalaz中,semigroup的append運算子是<code>|+|</code>,所以我們可以這樣加:</p>
<pre><code>List(1,2,3) |+| List(4,5,6)
res: List[Int] = List(1, 2, 3, 4, 5, 6)
</code></pre>
<p>或是</p>
<pre><code>1.some |+| 2.some
res: Option[Int] = Some(3)
</code></pre>
<p>Associative的例子就像這樣:</p>
<pre><code>scala> List(1) |+| List(2) |+| List(3)
res1: List[Int] = List(1, 2, 3)
scala> List(1) |+| ( List(2) |+| List(3) )
res2: List[Int] = List(1, 2, 3)
scala> ( List(1) |+| List(2) ) |+| List(3)
res3: List[Int] = List(1, 2, 3)
</code></pre>
<h2 id="monoid">Monoid</h2>
<p>Monoid是semigroup加上<code>zero</code></p>
<p>這個zero的特性是</p>
<ol>
<li>不管是原本的型態的值加上這個zero</li>
<li>或是zero加上原本的型態的值</li>
</ol>
<p>結果都會是原來的值</p>
<p>就像是5+0 = 5, 0就是數字加法中的zero <br>
而5*1=5, 1就是數字乘法中的zero <br>
List的zero就會是Nil</p>
<p>所以當要建立自己的Monoid的時候,要注意到這個特性。</p>
<blockquote>
<p>Reference <br>
- <a href="https://gist.github.com/cb372/b1bad150e0c412fb7364">Category theory jargon cheat sheet</a> <br>
- <a href="http://www.codedata.com.tw/social-coding/haskell-tutorial-25-functor/">CodeData Haskell Tutorial</a> <br>
- <a href="http://stackoverflow.com/questions/19880207/examples-of-applicative-functor-usage-in-scala">Examples of Applicative Functor usage in Scala</a> <br>
- <a href="http://eed3si9n.com/learning-scalaz/Functor+Laws.html">learning Scalaz - Functor Laws</a></p>
<p>Written with <a href="https://stackedit.io/">StackEdit</a>.</p>
</blockquote></body>
</html>joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-82565305406506870452015-08-07T05:05:00.000+08:002015-08-07T05:26:30.639+08:00[敗家] 美光Micron Crucial MX200 SSD 500GB M.2 直上 Windows 10<h3>
電腦的Bottleneck</h3>
去年(2014)6月份的時候,將電腦大升級,主機板、CPU、Ram、顯示卡、Power…全換了!<br />
就是硬碟沒換,用原來的WD VelociRaptor 1萬轉的 300GB硬碟。<br />
想當初是用SCSI硬碟換成這顆萬轉硬碟的,心想還能撐好一陣子才對。<br />
但其實Windows體驗指數已經告訴我現在SSD才是王道…<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY9d1DJMTK3Y5WO59CTtgmCnF7eLagMDkPnVow0jnOVMbYQSXKyBZ0jpJy10XZvr5funD9YRX-7g-Dg4cQ_tFzzWdKrAwUlpWm72yziIxRnR5KaZOFR_yTlGXflYRlq6R6iBC6pA/s1600/Windows%25E8%25B7%2591%25E5%2588%2586_%25E6%258F%259B%25E7%25A1%25AC%25E7%25A2%259F%25E5%2589%258D.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY9d1DJMTK3Y5WO59CTtgmCnF7eLagMDkPnVow0jnOVMbYQSXKyBZ0jpJy10XZvr5funD9YRX-7g-Dg4cQ_tFzzWdKrAwUlpWm72yziIxRnR5KaZOFR_yTlGXflYRlq6R6iBC6pA/s640/Windows%25E8%25B7%2591%25E5%2588%2586_%25E6%258F%259B%25E7%25A1%25AC%25E7%25A2%259F%25E5%2589%258D.PNG" width="640" /></a></div>
<br />
<span style="background-color: #fce5cd;">…萬轉的硬碟居然是拖累整個系統的老鼠屎!(測試環境為Windows 8)</span><br />
<br />
300GB的硬碟,也不知灌了什麼東西…居然快吃滿了!(模擬市民3+一堆資料片好像就7,80GB)<br />
最近打算灌個Vistual Studio 2015,但硬碟空間不夠,經過一番考慮,決定換新硬碟了!<br />
<h3>
SSD我來了!</h3>
當初的主機板買的時候,剛好是M.2規則剛出,MSI Z97 Gaming 3剛就好是早期有支持的那一批,所以這次的選購,就以M.2規則為主。<br />
<br />
本來的300G都不夠了,所以250G的就不考慮了,直接找500G左右的,上網查了查,就選定這顆…<br />
<br />
<span style="font-size: large;"><b style="background-color: #fff2cc;">美光Micron Crucial MX200 SSD 500GB M.2</b></span><br />
<br />
PCHome 24小時好朋友,給他6490元後他就幫我送來了!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG98eWbfilTDx45dQDMIa-m_oYk4d9jXmjXVLB3Urz6C7n6CxIw6-VPx10WDfSpyBF0pfsqF8QdvC3ZXicT2CNWAEijWglqq7PRuh06SfzeFKBrBTMMmFfm4bdhyphenhyphenxEOxusirf9lA/s1600/IMAG5603.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG98eWbfilTDx45dQDMIa-m_oYk4d9jXmjXVLB3Urz6C7n6CxIw6-VPx10WDfSpyBF0pfsqF8QdvC3ZXicT2CNWAEijWglqq7PRuh06SfzeFKBrBTMMmFfm4bdhyphenhyphenxEOxusirf9lA/s640/IMAG5603.jpg" width="640" /></a></div>
<br />
拿到這個箱子的時候,輕得以為他忘了裝貨進來…<br />
打開後,真的是很過度包裝!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-U5IyH7vE6U2fZ99HU4hQ5IiHgQ4oyFDofq9829gK0IHKhVQE3SjWyLB17LLWHpMIngBvAwIjybcaPkcoe4xbCh-BHGcZR0z2Bqh7yPO3vCqiX5Q5N98Q9FJ7EAX-fH6oJPfpmw/s1600/IMAG5605.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-U5IyH7vE6U2fZ99HU4hQ5IiHgQ4oyFDofq9829gK0IHKhVQE3SjWyLB17LLWHpMIngBvAwIjybcaPkcoe4xbCh-BHGcZR0z2Bqh7yPO3vCqiX5Q5N98Q9FJ7EAX-fH6oJPfpmw/s640/IMAG5605.jpg" width="640" /></a></div>
<br />
跟兔斯基合照一下!小小薄薄一片要價很匪…<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiOPR3I7SxwwcilaJy2u3JfQgGyKm1oE04BYH4AnPX-yXkk08CKADMaNjlbi5V0aAfhlT_nviqj3HtMvMWmgOU-DmWFguNuuzjvh9qW7gBh7F0koklumNUDjHL_INynmv_frbXdA/s1600/IMAG5606.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiOPR3I7SxwwcilaJy2u3JfQgGyKm1oE04BYH4AnPX-yXkk08CKADMaNjlbi5V0aAfhlT_nviqj3HtMvMWmgOU-DmWFguNuuzjvh9qW7gBh7F0koklumNUDjHL_INynmv_frbXdA/s640/IMAG5606.jpg" width="360" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<h3>
升級嘍!</h3>
MSI Z97 Gaming 3的M.2插槽就在CPU與PCI插槽中間的位置,他本來就有鎖一個小螺絲,但搞了半天,居然找不到那麼小的螺絲起子,只好用尖嘴鉗小心的把他轉鬆,用手轉下來。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxPTJWrYl1FuH-5KLQqfOmv-PUSzJik6zR8fdRzeZtybFELhvhnBaD4LnoEc0Ocj4gDjlQBLAqzvfBuOtLl-ibloaSq-YZdRepdTcDMevlGBIDV8T-04XQ84MJIRjkkHOw0we5Ww/s1600/IMAG5608.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxPTJWrYl1FuH-5KLQqfOmv-PUSzJik6zR8fdRzeZtybFELhvhnBaD4LnoEc0Ocj4gDjlQBLAqzvfBuOtLl-ibloaSq-YZdRepdTcDMevlGBIDV8T-04XQ84MJIRjkkHOw0we5Ww/s640/IMAG5608.jpg" width="640" /></a></div>
<br />
裝上去之後,用手把那個短小的縲絲轉上去也花了好大一番功夫…<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCAiGnfc2dtuR4UIHNFII_u8vRzTsj4fH82GpmFjN8NM6ynKwN7gXbnmTepP52m2O7HsLu2Ij1nMPm7xCBl27hQE68jeKZuA6K0KdFXOQK_2FLrMitpRd8LgDeingCw3R8KL3ZjQ/s1600/IMAG5609.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCAiGnfc2dtuR4UIHNFII_u8vRzTsj4fH82GpmFjN8NM6ynKwN7gXbnmTepP52m2O7HsLu2Ij1nMPm7xCBl27hQE68jeKZuA6K0KdFXOQK_2FLrMitpRd8LgDeingCw3R8KL3ZjQ/s640/IMAG5609.jpg" width="640" /></a></div>
<br />
<h3>
裝好直接灌Windows 10</h3>
本來預計颱風假可以好好的弄電腦,誰知道突然公佈不放假了…= =<br />
默默的繼續灌系統+一堆應用程式…<br />
<br />
Windows 10本身把這個效能體驗指數的功能拔掉了,要灌回來的話可以參考<a href="http://forum.gamer.com.tw/C.php?bsn=60030&snA=398470" target="_blank">這篇</a>。<br />
<br />
沒想到在Windows 10這麼看好我的顯示卡!給了9.9分!但…硬碟怎麼還是最慢的!! 不過已經比之前好超多的了!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9w1bn9_lPAgH8kZxdKORW_nZYG92Y3TbU1tBmsqkE6VwQV-KDBXmU2xgHcD9N19aFOZ-MA8mnWKMmTLITcTtZTj4U-tRrBya2_-R5emnBJW3W4rZmah7D-pYEIRKcJoOBu59fVQ/s1600/Windows_Score.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="404" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9w1bn9_lPAgH8kZxdKORW_nZYG92Y3TbU1tBmsqkE6VwQV-KDBXmU2xgHcD9N19aFOZ-MA8mnWKMmTLITcTtZTj4U-tRrBya2_-R5emnBJW3W4rZmah7D-pYEIRKcJoOBu59fVQ/s640/Windows_Score.PNG" width="640" /></a></div>
<br />
簡單的跑了分數,確認沒有太大的落差!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX_lXpw7DN_d9RVQS-yU3HiuWSywjdqE62NwOC8ct0UH3T_0hX2PMkkNoT1YZoVvlDbWWoEsQ0eqNoZlchiRTiztCBfdkMqhqhkQ6Ds73_ERj3-KnBtguVQDkQvaf-BkCpnEEg2g/s1600/disk_1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="365" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX_lXpw7DN_d9RVQS-yU3HiuWSywjdqE62NwOC8ct0UH3T_0hX2PMkkNoT1YZoVvlDbWWoEsQ0eqNoZlchiRTiztCBfdkMqhqhkQ6Ds73_ERj3-KnBtguVQDkQvaf-BkCpnEEg2g/s400/disk_1.PNG" width="400" /></a></div>
<br />
美光有推出個Momentum的模式,可以拿一些記憶體來當Cache Layer,加速硬碟的存取,Sequential access最快可快到10倍!<br />
但是Windows 10上面要安裝的時候,一直失敗,查了一下好像很多人都有這樣的問題,應該是在Windows 10上面的支援度有問題,就只好等他修好了!<br />
<br />
<h3>
目前系統規格</h3>
<div>
<ul>
<li>主機板:MSI Z97 Gaming 3</li>
<li>CPU:Intel Core i7-4790 3.6GHz</li>
<li>記憶體:Kingston HyperX DDR3-1600 8GB x 2 雙通道</li>
<li>顯示卡:MSI AMD Radeon R9-270 Gaming</li>
<li>硬碟:Micron Crucial MX200 SSD 500GB M.2</li>
</ul>
<div>
<br /></div>
</div>
<h3>
感想</h3>
<br />
<ul>
<li>從HD升到SSD再加上系統升上Windows 10真的變好快啊!封印被解開了!</li>
<li>PCHome真是壞朋友…</li>
<li>嘸蝦米在Windows App模式下的不支援度真的很弱…我在Android和Mac上都花錢買官方版的了,拜託Windows也做出個能讓我花錢支持一下的版本吧…</li>
<li>把Visual Studio 2015灌了下去,發現功能好多啊!真威!(快四年沒用VS了…)</li>
<li>這篇 <a href="http://technews.tw/2015/08/05/i-havent-opened-my-macbook-since-windows-10-came-out/" target="_blank">MacBook 用戶:自從用了 Windows 10,再也沒碰 MacBook</a> 的作者到底收了MS多少錢…可以把Windows 10吹的這麼神!是跟Windows 8比起來好許多了,但身為一個開發人員,它還是無法跟Mac比…</li>
</ul>
<br />
<br />
<br />joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-79954696130924378022015-08-06T03:21:00.000+08:002015-08-11T05:01:17.121+08:00老闆說大家來寫個URL Shortener<h3>前言</h3><div>老闆心血來潮,說大家來寫個URL Shortener吧!</div><div>URL Shortener 就是縮網址嘛!同事Penny說 "就寫個code去call Google縮網址"…</div><div>為了<strike>避免被海陸退伍並修練各種武術的老闆宰了</strike>當作練習、並且幫Blog找題材這種一石二鳥的事,當然還是正經的做了!</div><div><br />
</div><h3>設計</h3><div>縮網址的功能,初步的構想如下:</div><div><ul><li>吃URL,吐轉換過的結果(TinyURL)。</li>
<li>吃TinyURL,吐轉回去的結果(原始URL)。</li>
<li>轉換的過程可能有一些不同的實作方式,但第一個想到的,就是Hash。</li>
<li>URL與TinyURL的對照,需要有個地方存起來。</li>
<li>Error Handling的方式之前都寫過<a href="http://blog.joecwu.com/2015/07/scava-scala-scalaz-either.html" target="_blank">scalaz-either</a>, <a href="http://blog.joecwu.com/2015/07/scava-scala-scalaz-validation.html" target="_blank">scalaz-validation</a>和<a href="http://blog.joecwu.com/2015/07/scava-scala-scalaz-validation-either-scalactic.html" target="_blank">scalactic</a>了,好歹也拿一個來用吧!</li>
<li>這個之後可以包裝成Web Services。</li>
</ul><div><br />
</div><h3>程式的架構</h3></div><div>這裡在GitLab上有寫了,我就直接貼上來~</div><script src="https://gist.github.com/joecwu/ff4dd622c7e570fd12f2.js"></script> <!--<div class="gistLoad" data-id="ff4dd622c7e570fd12f2" id="gist-ff4dd622c7e570fd12f2"><br />
<a href="https://gist.github.com/joecwu/ff4dd622c7e570fd12f2">載入原始碼</a></div>--> <br />
<h3>成果</h3>原始碼在這邊!<br />
<a href="https://github.com/joecwu/shortener/tree/0.1.1" target="_blank">https://github.com/joecwu/shortener/tree/0.1.1</a><br />
<br />
同樣的依照之前寫過的<a href="http://blog.joecwu.com/2015/07/librarysonatype-nexus-repostiroy.html" target="_blank">發佈library到Sonatype repository</a>的方式,也把shortner這個版本放上去嘍!<br />
<br />
<script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"></script>joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-37423702089436246632015-08-05T01:48:00.000+08:002015-08-05T01:48:50.796+08:00[閃光] 下班回家後看到心暖暖的字條<h3>
這篇很閃,請自行斟酌</h3>
晚上下班回家後,看到桌上有條字條!咦!居然是小柔留給我的!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga9mQgnGgxs8nxRRt2Ysdc5lfkM-WQtNO7kYle154VHVRsivmVhPiudSYBxsg4cEdyOW8tzSrZKKfVX_DTWgUTWwBaiHTAmrUOiqmJYHerFq0wue1AI5-w7JARP-hECEbCgF6UMA/s1600/IMAG5600.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga9mQgnGgxs8nxRRt2Ysdc5lfkM-WQtNO7kYle154VHVRsivmVhPiudSYBxsg4cEdyOW8tzSrZKKfVX_DTWgUTWwBaiHTAmrUOiqmJYHerFq0wue1AI5-w7JARP-hECEbCgF6UMA/s640/IMAG5600.jpg" width="640" /></a></div>
<br />
這個麵包是我前一天下班時買回家的,因為小柔超喜歡吃菠蘿麵包,但是當時只剩一個 (平常我都會買個4、5個),就只買了一個菠蘿麵包和其他幾種麵包回家。<br />
<br />
下班時回到家看到這個好貼心的紙條,好感動!居然是把自己最喜歡吃的留給我!<br />
<br />
讓我想到小柔有時在我上班時離開我家,都會把棉被折好好的(我都不折棉被的),把房間整理乾淨,讓我下班回家的時候能有好心情,這麼貼心的舉動真的很感謝小柔!<br />
<br />
這麼貼心的老婆要去哪裡找啊!快娶回家!joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-54483887172270922492015-08-03T23:00:00.000+08:002015-08-15T03:07:06.299+08:00[敗家] 兔斯基 無線滑鼠<h3>
滑鼠滑鼠好重要</h3>
一直以來都買logitech的滑鼠,但是用個一、二年後就開始發現滑鼠按鍵會怪怪的,點一下會變成連點,或是點下去不太靈敏。<br />
<br />
每天用滑鼠這麼長的時間,這個工具不靈光會讓做事效率下降很多,加上小柔也跟我說他的羅技滑鼠的滾輪也壞了,所以就上網查了查除了羅技還有哪個選擇比較好…<br />
<br />
<h3>
找到兔斯基</h3>
<div>
在PCHome查了查,滑鼠五花八門,除了羅技也不知別的牌子好不好用,但突然被一個造型給吸引!! i2 Tuzki 兔斯基,這也太可愛了吧!完全被外型所吸引!</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwe7gTVA_gqphpg7B-r03bYW6K3y3mgzmOI3hfJvkNa3jzuNsB_yryh2wwX3Rx2V91OFYnyDABV5hsTxngNSNinKc3tNBjA37_6i3X97aPpMXO4iOgPhupWep_cG2-G3FyFKSbnw/s1600/Screen+Shot+2015-08-04+at+4.29.03+AM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="342" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwe7gTVA_gqphpg7B-r03bYW6K3y3mgzmOI3hfJvkNa3jzuNsB_yryh2wwX3Rx2V91OFYnyDABV5hsTxngNSNinKc3tNBjA37_6i3X97aPpMXO4iOgPhupWep_cG2-G3FyFKSbnw/s640/Screen+Shot+2015-08-04+at+4.29.03+AM.png" width="640" /></a></div>
<div>
<br /></div>
<div>
而且價錢沒很貴,如果真的很不好用的話,這個價錢還能接受!(或是就用PCHome的優點之一把他退貨!!)</div>
<div>
<br /></div>
<div>
另外他也有搭配的滑鼠墊也好可愛!默默的就買了兩組…</div>
<div>
<br /></div>
<h3>
收到新滑鼠</h3>
<div>
24小時內就收到了!先來看看滑鼠墊!</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinypTpq4EBtAbBL5bxoXs4cO4bq_TG-AGDv63Bkj8_JZpkc9f_0MWIb1hOUMMZ8cH0Jwqigoco3ltEGSsY0WmfRWZuiG47MxLtj-rRiNN3yz6cidyREYtRYD46MfndrL-A9k6lqA/s1600/IMAG5595.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinypTpq4EBtAbBL5bxoXs4cO4bq_TG-AGDv63Bkj8_JZpkc9f_0MWIb1hOUMMZ8cH0Jwqigoco3ltEGSsY0WmfRWZuiG47MxLtj-rRiNN3yz6cidyREYtRYD46MfndrL-A9k6lqA/s640/IMAG5595.jpg" width="640" /></a></div>
<br />
再來是滑鼠!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiX8CF2GlqmC9HJA8WNJVCkJkydyfaLrljMdVHJQrOyQJ0mwcdHzyP2O2COgKriQC7Yl6FMt_pFB5DQQWahNy8Q66N-V5nPdmsR6q6Ty6mpJ0v4imh3DpVVOj61HT6pzbNO7TZFcQ/s1600/IMAG5596.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiX8CF2GlqmC9HJA8WNJVCkJkydyfaLrljMdVHJQrOyQJ0mwcdHzyP2O2COgKriQC7Yl6FMt_pFB5DQQWahNy8Q66N-V5nPdmsR6q6Ty6mpJ0v4imh3DpVVOj61HT6pzbNO7TZFcQ/s640/IMAG5596.jpg" width="640" /></a></div>
<br />
拆封後的近照!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEAorWP2QAQsH36oA8EmlQDSt4mDChKWUXDXhn2i9JIC2Urhm1yWHxu99TBNIXsoOv3ePHauZQxqWV5Pm6L2uMuZkVLBzGxd-PFVx4u3ubEwgnZ7bxlqg6VQcLW_oZxinHxInrjg/s1600/IMAG5597.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEAorWP2QAQsH36oA8EmlQDSt4mDChKWUXDXhn2i9JIC2Urhm1yWHxu99TBNIXsoOv3ePHauZQxqWV5Pm6L2uMuZkVLBzGxd-PFVx4u3ubEwgnZ7bxlqg6VQcLW_oZxinHxInrjg/s640/IMAG5597.jpg" width="640" /></a></div>
<div>
<br /></div>
<h3>
使用心得</h3>
<div>
<ul>
<li>真的很可愛!外形比想像中圓圓的可愛!</li>
<li>滑鼠墊的質感很好!</li>
<li>他的材質我不是很喜歡,感覺是用久了(或是太陽曬久了)會變黏黏的那種材質。</li>
<li>高Dpi真的很靈敏!這個大加分,左右鍵同時按超過三秒可以切換Dpi(500-1000-1500-1750四段)。</li>
<li>自動省電的功能,要恢復使用時,必須要按按鍵或是滾動滾輪才能叫醒滑鼠…這點蠻不習慣的,羅技的一拿起來就能直接用了,這個多一個步驟有點討厭。</li>
<li>只裝一個4號電池,本來的羅技M525是裝兩顆3號,讓我嚴重懷疑這個電力能撐多…但這也要用一陣子才能知道了。</li>
</ul>
</div>
<div>
<span style="background-color: #fff2cc; color: #cc0000; font-size: large;">[2015.8.15更新] 用了沒幾天後,就發現旁邊藍色的地方"脫膜"...品質真的不行啊…</span><br />
<br />
<br /></div>
<div>
<br /></div>
joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-78352860404626824762015-08-01T23:30:00.000+08:002015-08-11T02:14:59.412+08:00[大自然小孩] 坪林 清泉水頭營地 瘋狂抓蝦!<h3>
準備出發</h3>
最近迷上抓蝦!買了<a href="http://blog.joecwu.com/2015/07/led-headlight.html" target="_blank">頭燈</a>、<a href="http://blog.joecwu.com/2015/07/wading-shoes.html" target="_blank">溯溪鞋</a>,今天又買了蝦籠、蝦網和香米糠!<br />
蝦籠不只可以放在溪裡當陷阱抓蝦,其實也可以背在身上放抓到的蝦。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0sqtWWFSjYYOwUiF-89sxRsfUXcY3mRISUO2UCquVhwLo00j-HSkxp6nLGXtdd_9MI9SorlzR8KjlltiwXWd_TeTIsRHBVmRHYX_mxfwVOnEJsFv4fg0Xue5wv7YjLIj99iUk8w/s1600/IMAG5565.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0sqtWWFSjYYOwUiF-89sxRsfUXcY3mRISUO2UCquVhwLo00j-HSkxp6nLGXtdd_9MI9SorlzR8KjlltiwXWd_TeTIsRHBVmRHYX_mxfwVOnEJsFv4fg0Xue5wv7YjLIj99iUk8w/s640/IMAG5565.jpg" width="360" /></a></div>
<br />
至於香米糠,是為了做放在蝦籠裡的餌,上網查了一下別人的教學,拿一點飯(增加黏性)和香米糠揑成一個球,上鍋子煎了一下就成這樣的餌了!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTvsfUKMHL86zKTBN1sYv2g9iLZkWBjBQT48usVhqxif4XObc3YlFmjcRkMKJxWQ-SrjvrBdICzCSbdw1F6OB0sbUEkI_bmLtbJ5szzZPwtfR9wiptxTT-6LnzKITdfbcf5NfDlQ/s1600/IMAG5569.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTvsfUKMHL86zKTBN1sYv2g9iLZkWBjBQT48usVhqxif4XObc3YlFmjcRkMKJxWQ-SrjvrBdICzCSbdw1F6OB0sbUEkI_bmLtbJ5szzZPwtfR9wiptxTT-6LnzKITdfbcf5NfDlQ/s640/IMAG5569.jpg" width="640" /></a></div>
<br />
蝦網的話我沒拍照片,下面這張是在網路上找的,大約就是這種樣子,主要是網格比較大,溪流有時蠻快的,一般的網子受力面積大、阻力太大,會比較沒那麼靈活,蝦網用起來會比較好一些。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglrzGyQt9zZo4-Ki-VTIYSo2F67sX_UUd2BAifpN9BGnGMwp72n0OVECADxcCOdDfIGCKQ8USKWXTA26M960jMeoxqrzSNmZ7hKwhHoBhyphenhyphenuB_b_iNgqZTQ3X8Eb5096LDMmO8nBg/s1600/%25E8%259D%25A6%25E7%25B6%25B2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEglrzGyQt9zZo4-Ki-VTIYSo2F67sX_UUd2BAifpN9BGnGMwp72n0OVECADxcCOdDfIGCKQ8USKWXTA26M960jMeoxqrzSNmZ7hKwhHoBhyphenhyphenuB_b_iNgqZTQ3X8Eb5096LDMmO8nBg/s400/%25E8%259D%25A6%25E7%25B6%25B2.jpg" width="400" /></a></div>
<br />
<h3>
清泉水頭營地</h3>
<div>
這次的目的地,也是坪林,星期六的下午四點從內湖出發,塞車塞到爆,實在不懂都下午四點了還有一堆人要去宜蘭?! 塞了40分鐘才進到國道5號,又塞了20分鐘才到坪林交流道。下坪林之後沒什麼車,很快的就到我們的目的地 - 清泉水頭營地!</div>
<div>
本來想找個不用付錢的,但找不到方便停車的地方,而且貪圖方便,我們就還是進來這裡了!每人100元,我們2個人付了200塊(含停車費)。</div>
<iframe allowfullscreen="" frameborder="0" height="600" src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d1299.0981551461548!2d121.75051472334096!3d24.95353782133918!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x345d563b0685a60f%3A0xfb8f9e099d671155!2z5riF5rOJ5rC06aCt54ef5Zyw!5e0!3m2!1szh-TW!2stw!4v1438498947703" style="border: 0;" width="800"></iframe>
<br />
<br />
進去停好車之後,看了一下四周的環境,廁所浴室當然都有,另外露營的地方都有蓋鐵皮屋,不怕下雨還蠻不錯的!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-1MvuHFXdhBc/Vb0vnoTrvTI/AAAAAAAE9DI/1jJt_xZeP8g/s1600/20150801_102_2370.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://3.bp.blogspot.com/-1MvuHFXdhBc/Vb0vnoTrvTI/AAAAAAAE9DI/1jJt_xZeP8g/s640/20150801_102_2370.JPG" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-UBvH74Cj120/Vb0vxFv7PAI/AAAAAAAE9Do/q6y9zV9V7Lk/s1600/20150801_102_2374.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://2.bp.blogspot.com/-UBvH74Cj120/Vb0vxFv7PAI/AAAAAAAE9Do/q6y9zV9V7Lk/s640/20150801_102_2374.JPG" width="640" /></a></div>
<br />
旁邊這是"粗石斛吊橋",這裡有一片地方,底下是個好大好大的石頭地,所以在石頭上水很淺(但應該是會滑,不過有穿溯溪鞋就比較無感),石頭上因為水流有沖出一些小溝,裡面也會有一些魚蝦。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-XGmMXm2pYYA/Vb0vsVyfN2I/AAAAAAAE9DY/83h-XZ1Ea6g/s1600/20150801_102_2372.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://1.bp.blogspot.com/-XGmMXm2pYYA/Vb0vsVyfN2I/AAAAAAAE9DY/83h-XZ1Ea6g/s640/20150801_102_2372.JPG" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-FY0w2UWlflg/Vb0vu8SJeyI/AAAAAAAE9Dg/xEXtKxTZCn8/s1600/20150801_102_2373.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://3.bp.blogspot.com/-FY0w2UWlflg/Vb0vu8SJeyI/AAAAAAAE9Dg/xEXtKxTZCn8/s640/20150801_102_2373.JPG" width="640" /></a></div>
<br />
<h3>
開始抓蝦嘍!</h3>
<div>
在旁邊找了一塊石頭,把我們的東西安置好,再來把餌放進蝦籠裡,準備放蝦籠!</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-IqGwPEryaSg/Vb0vzftC_aI/AAAAAAAE9Dw/08i6nYpcm_A/s1600/20150801_102_2375.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://3.bp.blogspot.com/-IqGwPEryaSg/Vb0vzftC_aI/AAAAAAAE9Dw/08i6nYpcm_A/s640/20150801_102_2375.JPG" width="640" /></a></div>
<br />
一轉頭就發現小柔已經衝出去了…<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-0_H75UGPc-Q/Vb0v1k53MYI/AAAAAAAE9D4/OoVZ0si1X-M/s1600/20150801_102_2376.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://2.bp.blogspot.com/-0_H75UGPc-Q/Vb0v1k53MYI/AAAAAAAE9D4/OoVZ0si1X-M/s640/20150801_102_2376.JPG" width="640" /></a></div>
<br />
有上網作功課,蝦籠要放的話,要照魚蝦逆流而遊的習性來放,讓餌的味道被水流往下衝,然後讓蝦子游進來吃。(下圖水流是由右往左←,而蝦籠的入口是在左邊)<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-bNXqDfRH2r0/Vb0v8XjByiI/AAAAAAAE9EQ/mb4L2hi8tL8/s1600/20150801_102_2379.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://1.bp.blogspot.com/-bNXqDfRH2r0/Vb0v8XjByiI/AAAAAAAE9EQ/mb4L2hi8tL8/s640/20150801_102_2379.JPG" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-9IZcpdZlNV4/Vb0wC4jSjQI/AAAAAAAE9Es/oip9hGWL0No/s1600/20150801_102_2382.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://3.bp.blogspot.com/-9IZcpdZlNV4/Vb0wC4jSjQI/AAAAAAAE9Es/oip9hGWL0No/s640/20150801_102_2382.JPG" width="640" /></a></div>
<br />
由於我們也大約是5點半多左右到達,很快就天暗了,這時頭燈就派上用場了!(真的很亮!)<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-kViMvKYygys/Vb0wOyvjuOI/AAAAAAAE9Fc/YVadqomuOq4/s1600/20150801_102_2387.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://2.bp.blogspot.com/-kViMvKYygys/Vb0wOyvjuOI/AAAAAAAE9Fc/YVadqomuOq4/s640/20150801_102_2387.JPG" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-KgjOu5cn5ds/Vb0wRCKW3FI/AAAAAAAE9Fk/CfJQ-xovI7Y/s1600/20150801_102_2388.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://1.bp.blogspot.com/-KgjOu5cn5ds/Vb0wRCKW3FI/AAAAAAAE9Fk/CfJQ-xovI7Y/s640/20150801_102_2388.JPG" width="640" /></a></div>
<br />
<h3>
戰利品</h3>
<div>
這次又發生一個插曲,小柔本來用網子抓到了一隻很大的魚 (下圖的藍色桶子口徑有超過30公分,所以那隻魚有超過15公分長!) 但是過了一陣子之後…那隻不見了!不可能被蝦子吃掉啊!唯一的解釋…只能想像他是自己跳出去了吧…</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-uqROPwKBLZs/Vb0wbMT4ySI/AAAAAAAE9GI/761O11bvXzM/s1600/20150801_102_2392.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://3.bp.blogspot.com/-uqROPwKBLZs/Vb0wbMT4ySI/AAAAAAAE9GI/761O11bvXzM/s640/20150801_102_2392.JPG" width="640" /></a></div>
<br />
這次抓到的魚兒們! (最大隻的不見了,太小隻的就放生了,其實要走之前這些魚也都放了回去!)<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnomUA9T2XH-RRuUxrrk-dqejZ9gXD6DyYjsXUcD9d8zRBdK_j-1Cr-a_4VKCuST6-0O-Gu3t_rzd1NmbEgPT8RrweoFt99_Om3KK8NLLREtxt4hBVV3R8PNJInKK1uLs489nOVg/s1600/IMAG5571.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnomUA9T2XH-RRuUxrrk-dqejZ9gXD6DyYjsXUcD9d8zRBdK_j-1Cr-a_4VKCuST6-0O-Gu3t_rzd1NmbEgPT8RrweoFt99_Om3KK8NLLREtxt4hBVV3R8PNJInKK1uLs489nOVg/s640/IMAG5571.jpg" width="360" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiM0rC1DnL8tysgVZmNIecZqyEzZMPChCJqCoCOFM6uQjL3Fe9_5f1LKRVuG02L-hSe29xjJKf5mOANl6sLsQ_ijIhNuxeLMojAnW9pr2yxILTHFlqSU4xvD3Py0L7QLnsPJE6GIQ/s1600/IMAG5573.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiM0rC1DnL8tysgVZmNIecZqyEzZMPChCJqCoCOFM6uQjL3Fe9_5f1LKRVuG02L-hSe29xjJKf5mOANl6sLsQ_ijIhNuxeLMojAnW9pr2yxILTHFlqSU4xvD3Py0L7QLnsPJE6GIQ/s640/IMAG5573.jpg" width="360" /></a></div>
<br />
蝦子們就沒這麼幸運了!這次抓的蝦子有超過7、80隻,不知有沒有接近100隻! (我們抓到晚上12點才離開…)<br />
不過大部份都蠻小隻,少數幾隻最大的也才10公分左右吧,不知秋天會不會長比較大…<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA565pJ2fJVFAwyzhyHOzt7o0NwCGkpW6EeG56EBUQUsfEeWy2rHvcS2yvpX9Kq60SISMIIFMzhZhCcxGBGZLp68g2jkv9rVyrChjQqZF5OFi8DWNbxOtB-LWrmeHAWDScjsLKCQ/s1600/IMAG5574.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA565pJ2fJVFAwyzhyHOzt7o0NwCGkpW6EeG56EBUQUsfEeWy2rHvcS2yvpX9Kq60SISMIIFMzhZhCcxGBGZLp68g2jkv9rVyrChjQqZF5OFi8DWNbxOtB-LWrmeHAWDScjsLKCQ/s640/IMAG5574.jpg" width="360" /></a></div>
<br />
臨走前把魚放生的影片。<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/s_vi/tH-VMVgyWwI/default.jpg?sqp=CLSs960F&rs=AOn4CLAoT7rrcqZQ3P1ZQpkuMDdQUEBAtA" frameborder="0" height="532" src="https://www.youtube.com/embed/tH-VMVgyWwI?feature=player_embedded" width="640"></iframe></div>
<br />
<br />
<h3>
後續</h3>
回家後真的不知該怎麼處理他們…把太小隻的撈起來養,剩下的就幫他們洗洗澡…<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0v1b58L-Adol7FhSZsn9o7nxvZYnMT27Pn_LN-U5uM9WOhbxCguu9tTOpluCQTDkXYSW-sflIEwHY9NiUqpch2fCoBNU249YePdSJHbhP6SvJdwcG-hjj5xL1NC6jagB5ovlrDw/s1600/IMAG5575.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0v1b58L-Adol7FhSZsn9o7nxvZYnMT27Pn_LN-U5uM9WOhbxCguu9tTOpluCQTDkXYSW-sflIEwHY9NiUqpch2fCoBNU249YePdSJHbhP6SvJdwcG-hjj5xL1NC6jagB5ovlrDw/s640/IMAG5575.jpg" width="640" /></a></div>
<br />
然後加一點蒜跟油爆香之後…<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8zQgKknAaSkhFqi-uw9x_5NCihrgXj09HIiITrZ420I_tm96e6p5jZ3EFtARg_G-Kk4agEWduzWbMSklVpQvUthy11sEE8ZkoSx4CoakQGhEoJD4y12vmWWAi99N5zhax0vb6tQ/s1600/IMAG5577.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8zQgKknAaSkhFqi-uw9x_5NCihrgXj09HIiITrZ420I_tm96e6p5jZ3EFtARg_G-Kk4agEWduzWbMSklVpQvUthy11sEE8ZkoSx4CoakQGhEoJD4y12vmWWAi99N5zhax0vb6tQ/s640/IMAG5577.jpg" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
下酒很適合啊!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6XsScaoXrO05ckRd03Ww9OmwZZyoRtcndr3Qpc9RGZaiwAkd04peVYo_Eeuk4FZcNN1hG96YMrqFPfLIW7kil16fbsDFZjEaNzmyO5N0LTQmwkGKk-HOE18-d8DD_OVJQnbmkaQ/s1600/IMAG5579.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6XsScaoXrO05ckRd03Ww9OmwZZyoRtcndr3Qpc9RGZaiwAkd04peVYo_Eeuk4FZcNN1hG96YMrqFPfLIW7kil16fbsDFZjEaNzmyO5N0LTQmwkGKk-HOE18-d8DD_OVJQnbmkaQ/s640/IMAG5579.jpg" width="640" /></a></div>
<br />
<h3>
心得</h3>
<ul>
<li>頭燈戴久了會不舒服,不知是重量的原因還是頭被勒住的關係,一陣子還是要休息一下。</li>
<li>溯溪鞋真的好好用!C/P值最高!但腳泡在水裡(鞋子裡會積水)泡久了也是有點不舒服。</li>
<li>補蝦籠只抓到小小蝦五隻左右,下次再研究要怎麼放比較合適。</li>
<li>蝦子會往後跑,所以抓蝦時網子要在牠後面等牠!(前面可以用另個網子來趕)</li>
<li>其實蝦子看到燈光,還是會慢慢退、躲起來的嘛!</li>
<li>抓蝦抓累了,把頭燈關掉,頭抬起來看到滿天的星星,放鬆一下,很不錯的!</li>
</ul>
<br />
<br />
<br />
<br />
<br />joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0232台灣新北市坪林區清泉水頭營地24.9529953 121.7503891-3.5283236999999978 80.441795100000007 53.4343143 163.0589831tag:blogger.com,1999:blog-11438439.post-76272029548730859952015-07-31T02:59:00.000+08:002015-07-31T02:59:00.973+08:00神來一筆 有趣的釣魚簡訊<h3>
Phishing SMS Message</h3>
本來在Study一些別的東西要來寫網誌,但突然在Facebook看到朋友po的一個圖片,我就分心了…<br />
所以今天的主題就改了一下!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIBceSoIgJdHWLVvs1_npz_L9z20i-32phrkRcdIVuGr02JC7PnCCnn4jwLF_MnFEDHMNvB9-7ljOS5c5aNgF6xFjqWxQaO4UDFjz7wF3gCgZ6vuHbz-HsivG0LLH7Kcedg9BbAA/s1600/phishingMsg.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgIBceSoIgJdHWLVvs1_npz_L9z20i-32phrkRcdIVuGr02JC7PnCCnn4jwLF_MnFEDHMNvB9-7ljOS5c5aNgF6xFjqWxQaO4UDFjz7wF3gCgZ6vuHbz-HsivG0LLH7Kcedg9BbAA/s640/phishingMsg.jpg" width="640" /></a></div>
<div style="text-align: center;">
<span style="color: #999999; font-size: x-small;">(幫搜尋引擎轉成文字:http://cht.tw/h/10dvj)</span></div>
<br />
<span style="background-color: #fff2cc; font-size: large;"><b>愈不能玩就愈想玩!</b></span><br />
<br />
每次看到這種就很想點下去啊!~ 但還是不要太衝動得好!<br />
在家是用Windows,不像Mac有一些習慣的好用工具,但還是勉勉強強進行下去。<br />
<h3>
1. 這個網址是什麼?</h3>
家裡的電腦是Windows,好多習慣的工具都沒有(連telnet client都沒灌XD)<br />
猜想這個網址應該不會有太大的問題,但還是先把browser的javascript, cookie...等都先disable (這邊我用的是Chrome的<a href="https://chrome.google.com/webstore/detail/web-developer/bfbameneiokkgbdmiekhjnmfkcnldhhm" target="_blank">Web Developer</a>這個plugin),然後去連這個網址,果然發現只是個中華電信的Download頁面。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGK2Aa7-p6uYkhOO8BgAp1G0y6yq_rD99y5Znn7EIsKTBCUXvDEhH7yGVmL6kEcpfUNZymZyYpNmglbNg120h8nYHRzlko18oK_vhCtBxzrUIwJgdGsrPQ0P4TegeUU9nyhE0AAA/s1600/phishingDownloadPage.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGK2Aa7-p6uYkhOO8BgAp1G0y6yq_rD99y5Znn7EIsKTBCUXvDEhH7yGVmL6kEcpfUNZymZyYpNmglbNg120h8nYHRzlko18oK_vhCtBxzrUIwJgdGsrPQ0P4TegeUU9nyhE0AAA/s640/phishingDownloadPage.PNG" width="640" /></a></div>
<h3>
2. 處理下載的apk</h3>
照片還apk咧!這麼累~ 跟我中午吃飯時跟同事聊天提到要寫一個 WhereIsPenny.apk 差不多蠢嘛!<br />
<br />
寫過Android的人就知道,寫在client的code是沒有什麼密秘的!一切都是透明公開的!<br />
所以我們就來看看這個公開的下載包裡面是什麼東西!<br />
<br />
首先apk就是個壓縮檔嘛!就改個附檔名變成.zip,解開來看看,再來找個工具把classes.dex轉成jar。(但是這樣一些AndroidManifest.xml會是binary的,不能直接閱讀,所以其實也有<a href="http://ibotpeaches.github.io/Apktool/" target="_blank">Apktool</a>可以幫你處理apk)<br />
<br />
來看看他的AndroidManifest.xml<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxDl3RIJEr2b4YMScbFNo7r2yO7jyzBGD6atXSyeKMTw9n55PeLS6ThKbcONNj-4KYz5hDGSGT43bAqqp7OkgUGlCwZUWyyvYhIHsxTNfi26LFhXoc6FrDrEpU69UPq09U9ux4ig/s1600/phishingManifest.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="336" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxDl3RIJEr2b4YMScbFNo7r2yO7jyzBGD6atXSyeKMTw9n55PeLS6ThKbcONNj-4KYz5hDGSGT43bAqqp7OkgUGlCwZUWyyvYhIHsxTNfi26LFhXoc6FrDrEpU69UPq09U9ux4ig/s640/phishingManifest.PNG" width="640" /></a></div>
<br />
原來他叫自己"System 設備管理器"啊!然後執行下去8成就會先跳出要取得Device Admin的畫面吧!<br />
看到SMS_RECEIVED大概就猜得到他要幹嘛了…<br />
<br />
這個App的名稱叫"系統服務"…<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFUbYFYc1zBdDRE0PDFCCEDz-G9AXhSabdBL_gPP6QavEy70XwQ4p0-Z-tNqkvZ0xV56d0B7wccFQd1rwlLGoGHT74pP7v1H0k1uhOew1m-xGEfyxhIGJe6ANUPjKYl1o75o0Vcw/s1600/phishingString.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="172" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjFUbYFYc1zBdDRE0PDFCCEDz-G9AXhSabdBL_gPP6QavEy70XwQ4p0-Z-tNqkvZ0xV56d0B7wccFQd1rwlLGoGHT74pP7v1H0k1uhOew1m-xGEfyxhIGJe6ANUPjKYl1o75o0Vcw/s640/phishingString.PNG" width="640" /></a></div>
<br />
<h3>
3. 來看看他的source code…</h3>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_vgH07TAq_z2cQJ0Ghw1tK7fZ1xPeq9Y8hq5fz1nGSOPPTwjjB3VEl3dFa5gacWCze8RvVcQJrYSWZ0SemvSV_x9VdTv9vBmWCWF9lFaVShQh-3VbvcO1oB1wKjqKa53bqxMhcg/s1600/phishingMain.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_vgH07TAq_z2cQJ0Ghw1tK7fZ1xPeq9Y8hq5fz1nGSOPPTwjjB3VEl3dFa5gacWCze8RvVcQJrYSWZ0SemvSV_x9VdTv9vBmWCWF9lFaVShQh-3VbvcO1oB1wKjqKa53bqxMhcg/s640/phishingMain.PNG" width="600" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj24JLpeGqe7u5-M1b2pmEs5YrmdbLoaxIeKciOVT3X1r2ZJ7E8ORQnZf_wqf7tnmLPG-IXcWi3qVo1bX6TFW9HCP6WAgv-xJGHOQo4neZ2xI_x_eO3dKRz3TMktT9tWBWhgexmBg/s1600/phishingSendMsg.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="622" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj24JLpeGqe7u5-M1b2pmEs5YrmdbLoaxIeKciOVT3X1r2ZJ7E8ORQnZf_wqf7tnmLPG-IXcWi3qVo1bX6TFW9HCP6WAgv-xJGHOQo4neZ2xI_x_eO3dKRz3TMktT9tWBWhgexmBg/s640/phishingSendMsg.PNG" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd34yxaiBp3PR4Xp4lx3KWEU5RpPSCb18VHs8gVsYV9JNnwe8ZpfC_LSrbf2Ves0amwuLG7BdpuNMbLjzj1gYaW-aFBsS4Rl0C6k0vpNaaxijZJRXnb33ytU4Xqbl3NiOqPAw20A/s1600/%25E7%2585%25A7%25E7%2589%2587apk_decompiler.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd34yxaiBp3PR4Xp4lx3KWEU5RpPSCb18VHs8gVsYV9JNnwe8ZpfC_LSrbf2Ves0amwuLG7BdpuNMbLjzj1gYaW-aFBsS4Rl0C6k0vpNaaxijZJRXnb33ytU4Xqbl3NiOqPAw20A/s400/%25E7%2585%25A7%25E7%2589%2587apk_decompiler.PNG" width="400" /></a></div>
<br />
簡單看了一下難閱讀的Code,應該大自上就是先取得Device Admin的權限,然後送個SMS告訴0987712963這個號碼說成功安裝了,之後再把你手機所有收到的SMS轉發一份到這個號碼…<br />
<h3>
結論</h3>
<div>
...</div>
<div>
...</div>
<div>
...</div>
<div>
...</div>
<div>
...</div>
<span style="background-color: #fce5cd; font-size: large;"><b>沒有出軌的照片嘛!白忙一場…</b></span>joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-36129237085265197412015-07-30T02:57:00.002+08:002015-07-30T03:01:18.295+08:00[敗家] 溯溪鞋這兩天發的文章都是跟"<span style="background-color: #d9ead3;"><b>當大自然的小孩</b></span>"有關的敗家文。<br />
昨天收到LED頭燈後,今天是溯溪鞋!<br />
<br />
這是我跟小柔第一雙同款同色的"<span style="background-color: #f4cccc;"><b>情侶鞋</b></span>"!一定要發文紀念一下!<br />
<br />
根據常常趴趴照、跟溪邊很熟的同事Roger的忠告,第一個要買的不應該是頭燈,是溯溪鞋!<br />
因為在溪邊安全最重要!一雙好的溯溪鞋可以帶你上天堂~<br />
<br />
其實在買頭燈的同時我也已經下訂了,事前作了簡單的功課,簡單來說我的考量是:<br />
<br />
<ol>
<li>長版還是短版</li>
<li>有釘還是沒釘</li>
</ol>
<div>
針對#1,有人的提議是看行動的方便性,長版包覆性較高,可以保護比較多的部位,避免被刮傷。但是個人覺得短版比較好看! XD</div>
<div>
針對#2,有人說你去溯溪的話,千萬不要買有釘的,不然沒人敢讓你踩肩膀…,我們應該不會那麼激烈,偶爾還可以玩一下猜拳踩腳的遊戲(誤),所以選了有釘的!</div>
<br />
<br />
在露天拍賣找了一雙基本有釘短版的,售價是<b>380元</b>,好便宜啊!<br />
<br />
突然想起之前去龍洞跳水,租一次溯溪鞋要50元…借個7,8次就能買一雙了!<br />
<br />
接下來就來開箱吧!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL0CbogH8oSKso_nLdZj1fgXCbaRyJ2Ioci4Xl56RGOGAgAp5_wPJ1K1PyCOWlQS87EEVG9BkVXa3V0Q2TahkqGIBVN7yuFciIyYBKL6JrXiTbzlXJQpchvYsDszJvnysyVEhNLw/s1600/IMAG5550.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhL0CbogH8oSKso_nLdZj1fgXCbaRyJ2Ioci4Xl56RGOGAgAp5_wPJ1K1PyCOWlQS87EEVG9BkVXa3V0Q2TahkqGIBVN7yuFciIyYBKL6JrXiTbzlXJQpchvYsDszJvnysyVEhNLw/s640/IMAG5550.jpg" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh716DopZj4oYzW4_P8d_VARgyMsZg3dub5QK4ubcFfrz7GhsR9AoUk_wxSfXpMX_NLlEJv3qeulX4mJWTmCxNpM9hpTuopJE4erX1WxFXXsxXK5lNayPijaHIsAL12OsT_bGP1zQ/s1600/IMAG5551.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh716DopZj4oYzW4_P8d_VARgyMsZg3dub5QK4ubcFfrz7GhsR9AoUk_wxSfXpMX_NLlEJv3qeulX4mJWTmCxNpM9hpTuopJE4erX1WxFXXsxXK5lNayPijaHIsAL12OsT_bGP1zQ/s640/IMAG5551.jpg" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyB9v9Lw_UavSgplYDTAix3Bfhl2z6m5uAVrRuFOAUUTSLNyYhoyRWbfKQwPbIBDdo_tlz6PSK7nrQ_EuxVzfa9LBhLhCpI3QSXorDQ8o7a6Py0VgipZWPc7NuIdQSd2rg6mgE-Q/s1600/IMAG5552.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyB9v9Lw_UavSgplYDTAix3Bfhl2z6m5uAVrRuFOAUUTSLNyYhoyRWbfKQwPbIBDdo_tlz6PSK7nrQ_EuxVzfa9LBhLhCpI3QSXorDQ8o7a6Py0VgipZWPc7NuIdQSd2rg6mgE-Q/s640/IMAG5552.jpg" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwOhNaAxHRMNlu1Zbg9nr6wn4XqsiaDGBsBgM7TghXfgkOI-nm2HIkwxCWVoxbQOVtwi5ZB-5XYyITEmYgNzzemaTXcZkGNPqdlg9Bu7cADUd3s39rIT02p7hhUbk6TLcgvvdiXA/s1600/IMAG5553.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwOhNaAxHRMNlu1Zbg9nr6wn4XqsiaDGBsBgM7TghXfgkOI-nm2HIkwxCWVoxbQOVtwi5ZB-5XYyITEmYgNzzemaTXcZkGNPqdlg9Bu7cADUd3s39rIT02p7hhUbk6TLcgvvdiXA/s640/IMAG5553.jpg" width="640" /></a></div>
<br />
釘子看起來沒有很厲害,但用手摸的時候發現其實有些角度的切割還蠻利的,加上身體的重量壓下去,被踩到應該很爽…<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6kOGkMsKUVw43rljjViOpoa6knvmOnLegi9BVBsIVSzs3xWyA0HGD1yYypZ7sIKDKMwddjLuxLpWeBDFdg6BgNsRS8i-NlxfInn8ukwE9KLwXbSvc3_Z9Pn0s3-cXVu3QVVpN2g/s1600/IMAG5554.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi6kOGkMsKUVw43rljjViOpoa6knvmOnLegi9BVBsIVSzs3xWyA0HGD1yYypZ7sIKDKMwddjLuxLpWeBDFdg6BgNsRS8i-NlxfInn8ukwE9KLwXbSvc3_Z9Pn0s3-cXVu3QVVpN2g/s640/IMAG5554.jpg" width="640" /></a></div>
<br />
穿起來的樣子,後面的尺寸標記是膠片,不是紙張哦!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLnEadgAJtd6-bM6k5-APlXyHYxM2tXGXtYn7eRYNWut0iIVgVXeDy-ACjLiISftlWj0SAVTAqToDuU9ml3ldB3lM6RMHG-wFs6xxV0xkIEXu_3Vi9cOkXWwMXlkTUlK2xd0T2aA/s1600/IMAG5555.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLnEadgAJtd6-bM6k5-APlXyHYxM2tXGXtYn7eRYNWut0iIVgVXeDy-ACjLiISftlWj0SAVTAqToDuU9ml3ldB3lM6RMHG-wFs6xxV0xkIEXu_3Vi9cOkXWwMXlkTUlK2xd0T2aA/s640/IMAG5555.jpg" width="360" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvbKh6bunJQkI3gOHmEiwEoRW64N5LmKT7UQrBpkhQN5dDQEwEHyoYGG2D1oU8Eqb2Ct9HuawXu1WbGjHCY6WNw2lsWwjdWXfh4N3edYXSycZr3IFXmTKcQzZNqWMFuDjgLVAQXQ/s1600/IMAG5556.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvbKh6bunJQkI3gOHmEiwEoRW64N5LmKT7UQrBpkhQN5dDQEwEHyoYGG2D1oU8Eqb2Ct9HuawXu1WbGjHCY6WNw2lsWwjdWXfh4N3edYXSycZr3IFXmTKcQzZNqWMFuDjgLVAQXQ/s640/IMAG5556.jpg" width="360" /></a></div>
<br />
情侶鞋!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgHMEIBGcRpo2pFLafM1HiHFZBq2ruqn-DW5DL3QLuaeFbvKI2iKZpPip_OiCY0rHiz1GKG6rfui7syxthHpZL9JDjYyARFp40og1ngtx6MlGSAEXS69PmLMX5S_xFdxr8vuwu9w/s1600/IMAG5557.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgHMEIBGcRpo2pFLafM1HiHFZBq2ruqn-DW5DL3QLuaeFbvKI2iKZpPip_OiCY0rHiz1GKG6rfui7syxthHpZL9JDjYyARFp40og1ngtx6MlGSAEXS69PmLMX5S_xFdxr8vuwu9w/s640/IMAG5557.jpg" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyOUudbFtqJn4Y9FaUo3b0A1dyVSQlN3YFYtBoH2kHkygYPR7cAOke7z8hyUKariYJNHGIN3VMHkOo7cb1cBHpMcBVejoyoYdxflghdkAV4J4iG3rg01tWC_0koMoMjUDnDanjfA/s1600/IMAG5559.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyOUudbFtqJn4Y9FaUo3b0A1dyVSQlN3YFYtBoH2kHkygYPR7cAOke7z8hyUKariYJNHGIN3VMHkOo7cb1cBHpMcBVejoyoYdxflghdkAV4J4iG3rg01tWC_0koMoMjUDnDanjfA/s640/IMAG5559.jpg" width="640" /></a></div>
<br />
同樣的一句話,就等假日去溪邊玩耍時,再來試試好不好用!<br />
<br />
<br />
<br />joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-48009411178133423512015-07-29T03:04:00.000+08:002015-07-29T03:04:49.914+08:00[敗家] LED頭燈<h3>
我要買很亮的頭燈</h3>
星期日到坪林用手電筒克難的抓蝦、加上一直被旁邊露營的人用頭燈閃瞎好幾次後,回來就上網做了點功課,訂了頭燈。我要閃瞎蝦子!<br />
今天上班前去便利商店拿到貨,所以就來個簡單的開箱。<br />
<br />
<h3>
頭燈的挑選</h3>
<h4>
LED燈炮</h4>
一開始我是在PCHome購物查了一下,先是看到LED燈炮的不同規格…不了解他的差異,查了一下基本上就是:<br />
<br />
V5>V4>V3>V2>U5>U4>U3><span style="font-size: large;"><span style="background-color: #fff2cc;">U2</span>><span style="background-color: #fff2cc;">T6</span></span>>T5>T4>T3>T2>S6>S5>S4>S3>S2>Q5>Q4>Q3>Q2<br />
<br />
至於L2是啥?<br />
<blockquote class="tr_bq">
<blockquote class="tr_bq">
<i>L2全稱XM-L2,</i></blockquote>
<blockquote class="tr_bq">
<i>指的是一種LED形狀,</i></blockquote>
<blockquote class="tr_bq">
<i>是XML形狀的升級版,</i></blockquote>
<blockquote class="tr_bq">
<i>不一定比XML的亮。</i></blockquote>
</blockquote>
總之…L2不代表亮度,只是個銷售手法。<br />
<div>
<br /></div>
<div>
但在PCHome24小時購物一定是比較貴的,先有個概念後,再進去露天拍賣找,這時候心裡已經打好主意,我要買U2的!!! </div>
<h4>
電池</h4>
<div>
電池大都是18650鋰電池,拿出我近十年前買的軍用手電筒,也是用這一個型號的電池。</div>
<div>
所以我的選擇最好是跟我的手電筒一樣用18650鋰電池 (這個規格較普遍且C/P值高)。</div>
<div>
另外要注意的是,<span style="background-color: #fff2cc;"><span style="color: #cc0000; font-size: large;">保護板</span></span>,這個東西可以防止鋰電池被放電放過頭到壞掉。</div>
<div>
有些價錢會有一點差距,要注意是不是電池用便宜的(沒保護板的)而造成的價差。</div>
<h4>
另外的考量</h4>
<div>
在找尋的過程中,發現有一款是可以裝在自行車上用的,我有時會騎腳踏車上下班,晚上基本上就是摸黑回家,似乎有點危險!(別人看不到我啊~)</div>
<div>
所以這次挑選時,就選了一款是能裝腳踏車上,又能當頭燈的兩用款。</div>
<div>
<br /></div>
<h3>
開箱嘍</h3>
<div>
到公司後,就先拍幾張開箱照!</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhR8SkOpHzvO_c-g17Vqk6Jdh5wKdqfyg_Wojp4seMyBdhFFK2HE8hOm9f92GO-pJMIICnuMzowA-PvhYwRF7PHYzXc0DgoLK1Gu_33pi5lON29mrDEkqcZJYEu_Nt1onwhL81AMw/s1600/IMAG5537.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhR8SkOpHzvO_c-g17Vqk6Jdh5wKdqfyg_Wojp4seMyBdhFFK2HE8hOm9f92GO-pJMIICnuMzowA-PvhYwRF7PHYzXc0DgoLK1Gu_33pi5lON29mrDEkqcZJYEu_Nt1onwhL81AMw/s640/IMAG5537.jpg" width="640" /></a></div>
<br />
這次我買的是這兩款,<br />
<a href="http://goods.ruten.com.tw/item/show?21408068718443" target="_blank">美國大眼蛙XML-L2三星保護板大全配伸縮調焦強光頭燈</a> (藍色那個) 500元<br />
<a href="http://goods.ruten.com.tw/item/show?21406266858727" target="_blank">美國XM-L U2 LED 2用頭燈旋轉調光</a> (紅色的,可自行車、頭燈兩用的) 650元<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6sYSrr-09ixrezmEvj8b4xcx8kVKAIAM44HMiSN39e5BYiK_XigIxcAxj0d3JQpO5L_xRTy8IjJvpaw-SBBq5Yf-RcteILjxTBftUbSmptk3ejvn83cPZWTK3uuVtVgVCWmYJ4A/s1600/IMAG5538.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6sYSrr-09ixrezmEvj8b4xcx8kVKAIAM44HMiSN39e5BYiK_XigIxcAxj0d3JQpO5L_xRTy8IjJvpaw-SBBq5Yf-RcteILjxTBftUbSmptk3ejvn83cPZWTK3uuVtVgVCWmYJ4A/s640/IMAG5538.jpg" width="640" /></a></div>
<br />
先開單純頭燈組的。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheKLl18Qu7JshQj-2Xtiy3oXcLgyNIHzgGnOgHI7x3pByF59qurrAlyRz3ydAVFlrFjTdMi2Naer7tVCfS_FFjqFR_ZaH34iLs0JVJbZk0PMEyi3JKgp9TvpquHrWSck-wdUOXUA/s1600/IMAG5540.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheKLl18Qu7JshQj-2Xtiy3oXcLgyNIHzgGnOgHI7x3pByF59qurrAlyRz3ydAVFlrFjTdMi2Naer7tVCfS_FFjqFR_ZaH34iLs0JVJbZk0PMEyi3JKgp9TvpquHrWSck-wdUOXUA/s640/IMAG5540.jpg" width="360" /></a></div>
<br />
他的電池座是直接固定在頭帶的後面,有簡單的防潑水蓋子 (網站上是寫<i><b>產品為生活防水不可落水或淋雨以免損壞</b></i>),兩個全新的18650電池,裝上去後閃亮亮!亮度很滿意!網拍上是標L2,實際上亮度不輸U2。<br />
藍色的頭可以伸縮調焦,外表的玻璃面是球面的,球到幾乎是半圓了。<br />
這個頭燈可以往下調角度,有4段,最底就往下調個50~60度這樣。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg62NEJYN_DOjieD6CpThm5iNji9LCib8aeXA1GGq-dVXh7y3ZSRAorl142H8thADWe00ANanCis-O7X26od9_xmXQewsyfEOdHoN1nK6ZCFmyW0Q1XVA3kiL3HuDy3JnRxomhzEw/s1600/IMAG5541.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg62NEJYN_DOjieD6CpThm5iNji9LCib8aeXA1GGq-dVXh7y3ZSRAorl142H8thADWe00ANanCis-O7X26od9_xmXQewsyfEOdHoN1nK6ZCFmyW0Q1XVA3kiL3HuDy3JnRxomhzEw/s640/IMAG5541.jpg" width="640" /></a></div>
<br />
再來是第二款兩用的頭燈,這款標的就是U2了,後面藍色的電池是四顆18650並聯+串接的,一開始在公司簡單的試燈的時候,發現很不亮,後來才發現是沒電,回家充滿電之後,一樣超亮!<br />
但這款的電池要用他附的一個套袋裝著,騎車時直接固定在車的骨架上還ok,但頭戴時掛後面會覺得電池有點重…(畢竟是4顆)<br />
頭燈固定的方式,是用強力塑膠圈,把圈圈兩頭分別勾在燈上的勾子上,然後繞過要固定的車架或是頭燈帶上圓圓的那個燈座。<br />
在頭燈帶上固定上去後,要調角度還蠻方便的,就自由的轉(燈架上會有小刻度來固定)<br />
PS. 頭燈網站上是寫說防水IP65,但因為電池的關係,我覺得<span style="background-color: #fff2cc;"><b>我才不敢把這電池弄到水</b></span>啊!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoEb9ogYyI3i1iG4NPMNkbBsVHZp8vytTH8NI6gjseCBU8DUDX50xdP2cYg6Zb2EB1Nv3sUiuZOu9dIQAqdF-e7z1UJ_uVqfaBh2Pvr6IlgzN9tGx-FQzu6nEJAGkKrto3r3NjUg/s1600/IMAG5542.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoEb9ogYyI3i1iG4NPMNkbBsVHZp8vytTH8NI6gjseCBU8DUDX50xdP2cYg6Zb2EB1Nv3sUiuZOu9dIQAqdF-e7z1UJ_uVqfaBh2Pvr6IlgzN9tGx-FQzu6nEJAGkKrto3r3NjUg/s640/IMAG5542.jpg" width="640" /></a></div>
<br />
兩個頭燈的近照<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUiNNS0s-4KiB6GfZhaVxHDCigeAo9Jk5z-YYU6NzgPGh2rj5ILzFbjBo7rLgsz46r92PaQOvFqcY0rTJPbbxXtwDbzPBgYbmylQ48JcY0NaLsvBbmQtteTiGcUcMos_MMScvizA/s1600/IMAG5544.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUiNNS0s-4KiB6GfZhaVxHDCigeAo9Jk5z-YYU6NzgPGh2rj5ILzFbjBo7rLgsz46r92PaQOvFqcY0rTJPbbxXtwDbzPBgYbmylQ48JcY0NaLsvBbmQtteTiGcUcMos_MMScvizA/s640/IMAG5544.jpg" width="640" /></a></div>
<br />
下班時裝在腳踏車上的樣子!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNk9YIfxyk2L0eBL9JjpoZ0fKQxj1nUL5m98FC9UHVaZt4oPjn8GzVcqBAPqdQLDsY4TGBZtCHMJ-_pxoGUNIKpImF9e0-3QTcSrGZ2899OyJdhImTGikIZGkJWcZVtk5HVPpP-A/s1600/IMAG5546.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNk9YIfxyk2L0eBL9JjpoZ0fKQxj1nUL5m98FC9UHVaZt4oPjn8GzVcqBAPqdQLDsY4TGBZtCHMJ-_pxoGUNIKpImF9e0-3QTcSrGZ2899OyJdhImTGikIZGkJWcZVtk5HVPpP-A/s640/IMAG5546.jpg" width="360" /></a></div>
<br />
晚上在蠻亮的路燈下,U2的燈還是能有這麼亮的效果!(最後一張手很抖請見諒)<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgojqbwZn-Lx0JXtq0pGyV2eEUfLzi4GGcIvnFN9UdzYFj5llPnO1cFhRquPW6_Lk29V_fJmM5o49ofG4oKB80lXdSq1A5XQ12asCrDs29MqaFA4WO4GR2fIqIk8FI-r4iUh0Rh-Q/s1600/IMAG5548.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgojqbwZn-Lx0JXtq0pGyV2eEUfLzi4GGcIvnFN9UdzYFj5llPnO1cFhRquPW6_Lk29V_fJmM5o49ofG4oKB80lXdSq1A5XQ12asCrDs29MqaFA4WO4GR2fIqIk8FI-r4iUh0Rh-Q/s640/IMAG5548.jpg" width="360" /></a></div>
<div>
<br /></div>
<h3>
結論</h3>
<div>
真的要買"頭燈",會推薦買藍色的那個,一整組的、旁邊由燈接到後面電池的線也是彈簧型的,不會有整線的問題,當頭燈用戴起來比較方便。</div>
<div>
拆封的時候也覺得藍色的包裝比較好。</div>
<div>
<br /></div>
<div>
但頭燈這東西畢竟不是天天拿出來用的,所以自行車兩用款其實還是有他可取的地方!</div>
<div>
<br /></div>
<div>
實際上使用的情況,就等週末有去找蝦子的時候才知道嘍!</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-66292066307257457702015-07-28T01:22:00.001+08:002015-08-11T01:56:03.347+08:00Scala Dispatch 處理Gzip Json<h3>
Scala HTTP Client</h3>
在開發Scala的專案的時候,當我們需要使用HTTP Client時,有許多不同的選擇:<br />
<br />
<ul style="box-sizing: border-box; color: #333333; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 16px; line-height: 25.6000003814697px; margin-bottom: 16px; margin-top: 0px; padding: 0px 0px 0px 2em;">
<li style="box-sizing: border-box;"><a href="https://github.com/dispatch/reboot" style="box-sizing: border-box; color: #4078c0; text-decoration: none;">Dispatch</a> — Library for asynchronous HTTP interaction. It provides a Scala vocabulary for Java’s<a href="https://github.com/AsyncHttpClient/async-http-client" style="box-sizing: border-box; color: #4078c0; text-decoration: none;">async-http-client</a>.</li>
<li style="box-sizing: border-box;"><a href="https://github.com/ngocdaothanh/netcaty" style="box-sizing: border-box; color: #4078c0; text-decoration: none;">Netcaty</a> - Simple net test client/server for Netty and Scala lovers.</li>
<li style="box-sizing: border-box;"><a href="https://github.com/eed3si9n/scalaxb" style="box-sizing: border-box; color: #4078c0; text-decoration: none;">Scalaxb</a> — An XML data-binding tool for Scala that supports W3C XML Schema (xsd) and Web Services Description Language (wsdl) as the input file.</li>
<li style="box-sizing: border-box;"><a href="http://spray.io/" style="box-sizing: border-box; color: #4078c0; text-decoration: none;">Spray</a> — Actor-based library for http interaction.</li>
<li style="box-sizing: border-box;"><a href="https://github.com/softprops/tubesocks" style="box-sizing: border-box; color: #4078c0; text-decoration: none;">Tubesocks</a> — Library supporting bi-directional communication with websocket servers.</li>
<li style="box-sizing: border-box;"><a href="https://github.com/scalaj/scalaj-http" style="box-sizing: border-box; color: #4078c0; text-decoration: none;">scalaj-http</a> – Simple scala wrapper for HttpURLConnection (including OAuth support).</li>
<li style="box-sizing: border-box;"><a href="https://github.com/finagle/finch" style="box-sizing: border-box; color: #4078c0; text-decoration: none;">Finch.io</a> — Purely Functional REST API atop of <a href="https://github.com/twitter/finagle" style="box-sizing: border-box; color: #4078c0; text-decoration: none;">Finagle</a>.</li>
<li style="box-sizing: border-box;"><a href="https://github.com/stackmob/newman" style="box-sizing: border-box; color: #4078c0; text-decoration: none;">Newman</a> — A REST DSL that tries to take the best from Dispatch, Finagle and Apache HttpClient. See <a href="https://www.paypal-engineering.com/2014/02/13/hello-newman-a-rest-client-for-scala/" style="box-sizing: border-box; color: #4078c0; text-decoration: none;">here</a> for rationale.</li>
</ul>
<div>
<span style="color: #333333; font-family: Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif;"><span style="line-height: 25.6000003814697px;">我個人在幾個Projects中,是使用Dispatch這個輕量的Asynchronous HTTP Client,並搭配<a href="https://github.com/json4s/json4s" target="_blank">json4s</a>來處理Json。</span></span></div>
<h3>
<span style="color: #333333; font-family: Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif;"><span style="line-height: 25.6000003814697px;">在Dispatch中如何處理Gzip Encoding?</span></span></h3>
<div>
<span style="color: #333333; font-family: Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif;"><span style="line-height: 25.6000003814697px;">Dispatch簡單好用也很輕量,但就因為太輕量了,並沒有支援Gzip的處理,今天這篇就來解釋我在使用Dispatch時是怎麼處理Gzip Encoding的。</span></span></div>
<h4>
<span style="color: #333333; font-family: Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif;"><span style="line-height: 25.6000003814697px;">Gzip Json Response</span></span></h4>
<div>
<span style="color: #333333; font-family: Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif;"><span style="line-height: 25.6000003814697px;">使用Dispatch,可以透過很簡單的就取得HTTP response的結果:</span></span></div>
<script src="https://gist.github.com/joecwu/5a7ed0cc1ee4daa9d0c5.js?file=blog-Scala-Dispatch-sample.scala"></script>
<!--<div class="gistLoad" data-file="blog-Scala-Dispatch-sample.scala" data-id="5a7ed0cc1ee4daa9d0c5" id="gist-5a7ed0cc1ee4daa9d0c5">
<a href="https://gist.github.com/joecwu/5a7ed0cc1ee4daa9d0c5#file-blog-Scala-Dispatch-sample-scala">載入原始碼</a></div>-->
<div>
<br />
但若是想handle gzip的response呢?<br />
這邊我們依照as.String的實作方式,寫了一個GzipJson,來判斷回傳的Header中的Content-Encoding是不是Gzip,然後再做相對應的處理:<br />
<script src="https://gist.github.com/joecwu/5a7ed0cc1ee4daa9d0c5.js?file=blog-Scala-Dispatch-gzip-json.scala"></script>
<!--<div class="gistLoad" data-file="blog-Scala-Dispatch-gzip-json.scala" data-id="5a7ed0cc1ee4daa9d0c5" id="gist-5a7ed0cc1ee4daa9d0c5">
<a href="https://gist.github.com/joecwu/5a7ed0cc1ee4daa9d0c5#file-blog-Scala-Dispatch-gzip-json-scala">載入原始碼</a></div>-->
<br />
在使用GzipJson處理Dispatch的response就只要像下面這樣的用方即可:
<br />
<script src="https://gist.github.com/joecwu/5a7ed0cc1ee4daa9d0c5.js?file=blog-Scala-Dispatch-gzip-json-response.scala"></script>
<!--<div class="gistLoad" data-file="blog-Scala-Dispatch-gzip-json-response.scala" data-id="5a7ed0cc1ee4daa9d0c5" id="gist-5a7ed0cc1ee4daa9d0c5">
<a href="https://gist.github.com/joecwu/5a7ed0cc1ee4daa9d0c5#file-blog-Scala-Dispatch-gzip-json-response-scala">載入原始碼</a><br
<br /></div>/>-->
</div>
<div>
<h4>
<span style="color: #333333; font-family: Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif;"><span style="line-height: 25.6000003814697px;">Gzip Json Request</span></span></h4>
</div>
<div>
<span style="color: #333333; font-family: Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif;"><span style="line-height: 25.6000003814697px;">但是在Request中要傳入Gzip的payload呢?</span></span><br />
<span style="color: #333333; font-family: Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif;"><span style="line-height: 25.6000003814697px;">這邊實作了GzipHelper,並定義implicit function來讓使用上更方便:</span>
</span><br />
<script src="https://gist.github.com/joecwu/5a7ed0cc1ee4daa9d0c5.js?file=blog-Scala-Dispatch-gzip-helper.scala"></script>
<!--<div class="gistLoad" data-file="blog-Scala-Dispatch-gzip-helper.scala" data-id="5a7ed0cc1ee4daa9d0c5" id="gist-5a7ed0cc1ee4daa9d0c5">
<span style="color: #333333; font-family: Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif;"><a href="https://gist.github.com/joecwu/5a7ed0cc1ee4daa9d0c5#file-blog-Scala-Dispatch-gzip-helper-scala">載入原始碼</a></span></div>-->
<span style="color: #333333; font-family: Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif;"><span style="line-height: 25.6000003814697px;">實際上傳送gzip的payload方式如下:</span></span><br />
<script src="https://gist.github.com/joecwu/5a7ed0cc1ee4daa9d0c5.js?file=blog-Scala-Dispatch-gzip-json-request.scala"></script>
<!--<div class="gistLoad" data-file="blog-Scala-Dispatch-gzip-json-request.scala" data-id="5a7ed0cc1ee4daa9d0c5" id="gist-5a7ed0cc1ee4daa9d0c5">
<a href="https://gist.github.com/joecwu/5a7ed0cc1ee4daa9d0c5#file-blog-Scala-Dispatch-gzip-json-request-scala">載入原始碼</a></div>-->
<span style="color: #333333; font-family: Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif;"><span style="line-height: 25.6000003814697px;"><br /></span></span></div>
<div>
<h3>
<span style="color: #333333; font-family: Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif;"><span style="line-height: 25.6000003814697px;">參考資料</span></span></h3>
</div>
<div>
<ul>
<li><span style="color: #333333; font-family: Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif;"><span style="line-height: 25.6000003814697px;"><a href="https://github.com/lauris/awesome-scala#http" target="_blank">GitHub Awesome-Scala</a></span></span></li>
<li><span style="color: #333333; font-family: Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif;"><a href="http://stackoverflow.com/questions/15800393/decode-a-streaming-gzip-response-in-scala-dispatch#" target="_blank">[stackoverflow] Decode a streaming GZIP response in Scala Dispatch?</a></span></li>
</ul>
</div>
<script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"></script>joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-30220631795105240912015-07-27T05:21:00.000+08:002015-07-27T05:22:53.907+08:00Synology DS412+ 記憶體升級<h3>
背景</h3>
自從買了Synology DS412+之後,頭腦變清楚了、考試都考100分呢!<br />
一直以來都用得很開心,但是從<a href="http://blog.joecwu.com/2015/07/synology-docker-gitlab.html" target="_blank">安裝Docker與GitLab套件</a>之後,發現GitLab跑得有夠慢…<br />
觀察了之後,發現記憶體好像不太夠?上網查了才發現原來可以自己升級記憶體!<br />
(其實也是這次才發現…原來412+的Ram只有1G...<br />
<br />
<h3>
作功課</h3>
上網查了<a href="http://www.mobile01.com/topicdetail.php?f=494&t=3075655" target="_blank">[整理] Synology NAS 相容 RAM Module 整理</a>,知道可以升級Ram之後,就打算來升級,突然想到中壢的朱先生曾跟我說他有一條多的Notebook的Ram,就問了他還在不在,然後跟他約了週末拿這條Ram。全新未拆封!謝謝朱先生!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3yy5i2Cit0cfIxxSO3xdV_lB4FmVTC_PCXMoOC6bQjmtmwM8tTjAwDR1SC2RGcVg_Y0GUaVA4t5vf5genhyphenhyphenrCu1IFgditpKkEKFvxrYyanT1fwsVtaeAj5FEN4bysf23P-Evqaw/s1600/IMAG5529.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3yy5i2Cit0cfIxxSO3xdV_lB4FmVTC_PCXMoOC6bQjmtmwM8tTjAwDR1SC2RGcVg_Y0GUaVA4t5vf5genhyphenhyphenrCu1IFgditpKkEKFvxrYyanT1fwsVtaeAj5FEN4bysf23P-Evqaw/s640/IMAG5529.jpg" width="640" /></a></div>
<br />
但是拿回來後,發現這是條DDR 1600的記憶體,到底我的NAS是支援到哪種RAM?<br />
查了一下<a href="http://forum.synology.com/wiki/index.php/What_kind_of_CPU_does_my_NAS_have" target="_blank">What kind of CPU does my NAS have</a>,發現我的CPU是Intel Atom D2700 Dualcore (2C/4T) 2.13GHz x86 Processor,支援的記憶體是<a href="http://ark.intel.com/products/59683" target="_blank">DDR3 800/1066</a>…哇咧!<br />
<br />
再上網查了一下到底能不能用…查不到!但應該能降頻跑吧?<br />
身為一個喜歡嘗試、不怕死的人,先裝再說吧!<br />
<br />
<h3>
更換前</h3>
<div>
可以看到,在更換前,我的記憶體使量率達81%,而GitLab在記憶體的使用上,幾乎是不夠用的!這也是他速度非常慢的原因。</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhz-CMv38b3k2hkg8X0xOjMmf28_51epyKuH0OjxZE_Dq_OvFn0chKYaBwlR3NaSVVwlIMh7gROF1eC_TebmoJXwNUzXHKpA-W2W3gHz-CBww0szdIGsrlAZ0xa6wE6b4mk2erPMA/s1600/Synology_memory_usage.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="532" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhz-CMv38b3k2hkg8X0xOjMmf28_51epyKuH0OjxZE_Dq_OvFn0chKYaBwlR3NaSVVwlIMh7gROF1eC_TebmoJXwNUzXHKpA-W2W3gHz-CBww0szdIGsrlAZ0xa6wE6b4mk2erPMA/s640/Synology_memory_usage.PNG" width="640" /></a></div>
<br />
<h3>
開始換記憶體</h3>
<div class="separator" style="clear: both; text-align: center;">
</div>
接下來就要開始換記憶體了!<br />
怎麼拆? 本來我是查到這個<a href="http://www.mobile01.com/topicdetail.php?f=494&t=2835026" target="_blank">[分享] 我終於把 Synology DS412+ 給拆了</a>,但後來找到這個影片描述的更清楚:<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/iWc-awYKmf0/0.jpg" frameborder="0" height="532" src="https://www.youtube.com/embed/iWc-awYKmf0?feature=player_embedded" width="640"></iframe></div>
<br />
在跟Ram合照完之後,就要來動工了!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyjUSj8pVzR2ZjWDf-LnZ51dGxyA1FXSEygOe0pVR5NA7ED79QY3saaKvbFQAc2rwlgyO0W2ohmWv8OYk4IXyt2RuCFCDGGjasHnSI27bVC3DhbdxYc-JpgW3sFvIjA-lZciAN4w/s1600/IMAG5530.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyjUSj8pVzR2ZjWDf-LnZ51dGxyA1FXSEygOe0pVR5NA7ED79QY3saaKvbFQAc2rwlgyO0W2ohmWv8OYk4IXyt2RuCFCDGGjasHnSI27bVC3DhbdxYc-JpgW3sFvIjA-lZciAN4w/s640/IMAG5530.jpg" width="360" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK-UW_SHw5vzPnpEwKn1r6zqUIARLoB8STIC_ZwIDqNuX9kYkhHDMeRD86v4H9g-qJ08W5TlSniDDqDI2Au5SEgItrjJSjVUxIw6yKLTJSyjw6cNhsDvSHh9qOlQPXhESB2EccMw/s1600/IMAG5532.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgK-UW_SHw5vzPnpEwKn1r6zqUIARLoB8STIC_ZwIDqNuX9kYkhHDMeRD86v4H9g-qJ08W5TlSniDDqDI2Au5SEgItrjJSjVUxIw6yKLTJSyjw6cNhsDvSHh9qOlQPXhESB2EccMw/s640/IMAG5532.jpg" width="640" /></a></div>
<br />
的確在一開始拆殼的時候會花了比較多的時間(不敢太用力嘛…)<br />
拆開了就順便把滿滿的灰塵給清一清。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGKNxBSbx3Lsr6NfdKo-V580p52CuqBBg1YI71yo5spgUGk00rUSxGSCGb2fBfDGSos8G4C4ETFzdvfp8aUTtKxnPJNhvN7_Nx6d3X5osdJ7kgkjFPtciOK9aHKinlaZn3KlaGlw/s1600/IMAG5533.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGKNxBSbx3Lsr6NfdKo-V580p52CuqBBg1YI71yo5spgUGk00rUSxGSCGb2fBfDGSos8G4C4ETFzdvfp8aUTtKxnPJNhvN7_Nx6d3X5osdJ7kgkjFPtciOK9aHKinlaZn3KlaGlw/s640/IMAG5533.jpg" width="360" /></a></div>
<br />
<h3>
Ram升級了,試運轉</h3>
終於裝好了之後,把NAS裝回去,先開機試一下…<br />
<span style="color: blue;"><span style="background-color: #cfe2f3;">藍燈一直閃…</span><span style="background-color: #cfe2f3; font-size: large;">藍燈一直閃…<b>藍燈一直閃…</b></span><span style="background-color: #cfe2f3; font-size: x-large;"><b>藍燈一直閃…</b></span></span><br />
<br />
等了一分多鐘還在閃!!! 可能是不支援吧…<br />
又強制關機,重新開機,還是一直藍燈後,我就放棄,把原來的RAM裝回去了…<br />
<br />
但裝回去開機時,又一直閃,上網查了一下…<br />
一查之下,查到了這篇<a href="https://www.synology.com/zh-tw/knowledgebase/faq/366" target="_blank">請問為何我無法完成安裝 Synology 產品,而且 LED 燈一直不斷閃爍?</a><br />
想嚇死誰啊!只是裝個不確定能用的RAM,怎麼可能燒掉!<br />
就等查要怎麼處理時…突然NAS嗶了一聲!開完機了… = =<br />
靠! 太久沒重開機,不知道應來閃藍燈只是正常的開機過程…要閃個2、3分鐘才會開好…<br />
<br />
我就默默的再拆一次,再把新的RAM裝上去,這次等了3,4分鐘後,終於開好機了!<br />
<br />
<h3>
升級到DDR3 1600 4G的Synology 412+</h3>
<div>
開完機看了一下,RAM的使用率只有32%,Docker也很夠用,GitLab試了一下發現速度終於正常了!</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg55spX7f096tzlIW9YY28bKdq2HTnbODagCoxMp0bKPDsqYww1lHozxH6ZfSV7yCuBw6XdLPRR7_HU4E4TW-aBO_QGSBbfYav6ZixI1wDU9A230Bolmlin3EsJJR8a1N5w5Wdi8w/s1600/Synology_memory_usage2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg55spX7f096tzlIW9YY28bKdq2HTnbODagCoxMp0bKPDsqYww1lHozxH6ZfSV7yCuBw6XdLPRR7_HU4E4TW-aBO_QGSBbfYav6ZixI1wDU9A230Bolmlin3EsJJR8a1N5w5Wdi8w/s640/Synology_memory_usage2.PNG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<h3>
結論</h3>
原來DDR3-1600 4G的RAM可以用在Synology DS412+!<br />
原廠1G的RAM掰掰嘍!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi__rZvq8aZtv8EZZaSY9gE4UN9pLM039n9OcV9crQv9iAwZjIKFbGkqIa8lCe8WUuhWrK1_Zdc0oNqhhN2IE-2nxU7kYSbnd3R00Y9mHOMuNyNCZTgRPAwiDns3S5CmwwESvGaVA/s1600/IMAG5534.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi__rZvq8aZtv8EZZaSY9gE4UN9pLM039n9OcV9crQv9iAwZjIKFbGkqIa8lCe8WUuhWrK1_Zdc0oNqhhN2IE-2nxU7kYSbnd3R00Y9mHOMuNyNCZTgRPAwiDns3S5CmwwESvGaVA/s640/IMAG5534.jpg" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnPLzoG9xGrpYbG3e3SuPfAHJBcHZOSyA0IY1joEns1sjFJ0TpJlRY3AVCt2S2-k67IDH-rG7ZWsffDF4LVkuUbChDp8UoYmjNb1reLn3Mw840ooIC45mml9HFqT3zmCE3sG1kZg/s1600/IMAG5535.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnPLzoG9xGrpYbG3e3SuPfAHJBcHZOSyA0IY1joEns1sjFJ0TpJlRY3AVCt2S2-k67IDH-rG7ZWsffDF4LVkuUbChDp8UoYmjNb1reLn3Mw840ooIC45mml9HFqT3zmCE3sG1kZg/s640/IMAG5535.jpg" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<h3>
參考資料</h3>
<ul>
<li><a href="http://www.mobile01.com/topicdetail.php?f=494&t=3075655" target="_blank">[整理] Synology NAS 相容 RAM Module 整理</a></li>
<li><a href="http://forum.synology.com/wiki/index.php/What_kind_of_CPU_does_my_NAS_have" target="_blank">What kind of CPU does my NAS have</a></li>
<li><a href="https://www.youtube.com/watch?v=iWc-awYKmf0" target="_blank">Synology 412+ 拆解影片</a></li>
<li><a href="http://www.mobile01.com/topicdetail.php?f=494&t=2835026" target="_blank">[分享] 我終於把 Synology DS412+ 給拆了</a></li>
<li><a href="https://www.synology.com/zh-tw/knowledgebase/faq/366" target="_blank">請問為何我無法完成安裝 Synology 產品,而且 LED 燈一直不斷閃爍?</a></li>
</ul>
joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-54965889005790567622015-07-27T01:23:00.000+08:002015-07-27T23:03:04.161+08:00[散步日] 坪林 大溪地 抓魚抓蝦餵蟲記自從跟小柔在一起一年左右的時候,我們就訂了每個月的最後一個星期六是<span style="background-color: #fff2cc;"><b>散步日</b></span>,這個散步日是一個把時間留給對方、跟對方好好聊天論討一些不同話題的日子,<b style="background-color: #fff2cc;">散步日</b>的目的當然就是希望能讓兩人的感情變得更好!<br />
<br />
今天的散步日的晚上,我們有一個比較特別的活動,就是去坪林抓蝦!<br />
<h3>
大溪地渡假村</h3>
至於要去哪抓蝦比較好?之前有問過常去抓蝦的同事Roger,他說他很常去坪林,所以就Google了一下,找到"大溪地"營地,晚上大約六點左右到大溪地,天色還是很亮的,下面這張照片是離開時補拍的,所以很黑…<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD4DP8pFLM68Z7Wrjq6ZQmRqfWqjMPkVKoldjSgf1FVnw9Uaz0hqsmWkOIKeNrhty1L9t0ODFPW78PYbyfyAtuOBtI68_1KI3s60kDCWcY9WWPRuaGVB6pbSOKSv8ItlJeRl4OKQ/s1600/IMAG5525.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD4DP8pFLM68Z7Wrjq6ZQmRqfWqjMPkVKoldjSgf1FVnw9Uaz0hqsmWkOIKeNrhty1L9t0ODFPW78PYbyfyAtuOBtI68_1KI3s60kDCWcY9WWPRuaGVB6pbSOKSv8ItlJeRl4OKQ/s640/IMAG5525.jpg" width="360" /></a></div>
<br />
一進去就有個阿姨來攔車,要收入場費,很客氣的問了我們,因為他們場地的規則就是一進來每個人要100元的入場費,停車一台車也是100元,我們兩人就要300元,但我們只是要抓抓蝦,而且又那麼晚了,有問我們能不能接受。<br />
<br />
因為人生地不熟的,想使用他們的衛浴設備,而且想說很多人在旁露營發生什麼時也才有得求救!當下很ok的就付錢入場了。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-7XjeHDVoJm8/VbObrVVxoII/AAAAAAAE8dE/PZRUOUIznZk/s1600/20150725_102_2349.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://4.bp.blogspot.com/-7XjeHDVoJm8/VbObrVVxoII/AAAAAAAE8dE/PZRUOUIznZk/s640/20150725_102_2349.JPG" width="640" /></a></div>
<br />
我們到的時候裡面已經有好多人,營地上也搭滿了帳篷,裡面就是延著溪,靠近門口的地方比較深,進去一點比較淺,阿姨建議我們這種生手,先在淺一點的地方比較安全!而且我們也沒有頭燈,只有手電筒,想說還是不要去太深的地方好了。(她一度有說他的頭燈如果沒有要巡場的時候可以借我們用,但後來我們也沒去找她借。)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-2V3upwrs494/VbObxbM4LyI/AAAAAAAE8dY/cLFEz4U_VVE/s1600/20150725_102_2351.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="180" src="http://4.bp.blogspot.com/-2V3upwrs494/VbObxbM4LyI/AAAAAAAE8dY/cLFEz4U_VVE/s320/20150725_102_2351.JPG" width="320" /></a><a href="http://2.bp.blogspot.com/-BVdLRGDA2vg/VbOb0M_-sxI/AAAAAAAE8dg/X7I8_DPL6Ds/s1600/20150725_102_2352.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://2.bp.blogspot.com/-BVdLRGDA2vg/VbOb0M_-sxI/AAAAAAAE8dg/X7I8_DPL6Ds/s320/20150725_102_2352.JPG" width="320" /></a><a href="http://1.bp.blogspot.com/-g-IRxH76iAE/VbOb7wsspqI/AAAAAAAE8d8/9-0oVQvgzPA/s1600/20150725_102_2355.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://1.bp.blogspot.com/-g-IRxH76iAE/VbOb7wsspqI/AAAAAAAE8d8/9-0oVQvgzPA/s320/20150725_102_2355.JPG" width="320" /></a><a href="http://4.bp.blogspot.com/-F7G0YeTK7OQ/VbOb-jua23I/AAAAAAAE8eE/l9IIEUZWlKw/s1600/20150725_102_2356.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://4.bp.blogspot.com/-F7G0YeTK7OQ/VbOb-jua23I/AAAAAAAE8eE/l9IIEUZWlKw/s320/20150725_102_2356.JPG" width="320" /></a><a href="http://1.bp.blogspot.com/-xO6dDqTxvKQ/VbOcDhhhphI/AAAAAAAE8eY/AIbiDUqDpLI/s1600/20150725_102_2358.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://1.bp.blogspot.com/-xO6dDqTxvKQ/VbOcDhhhphI/AAAAAAAE8eY/AIbiDUqDpLI/s320/20150725_102_2358.JPG" width="320" /></a><a href="http://3.bp.blogspot.com/-mLT0gzyHSD0/VbOcGKKUFLI/AAAAAAAE8eg/B3dN--S437M/s1600/20150725_102_2359.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="180" src="http://3.bp.blogspot.com/-mLT0gzyHSD0/VbOcGKKUFLI/AAAAAAAE8eg/B3dN--S437M/s320/20150725_102_2359.JPG" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<h3 style="clear: both; text-align: left;">
開始抓蝦嘍!</h3>
<div class="separator" style="clear: both; text-align: left;">
一看到水裡有魚之後,小柔就拿著網子就衝過去了!而且意料之外的是,天還沒黑就有看到小蝦子,然後又意料之外的好抓!蝦子的反應真的慢慢的,蠻容易抓的!</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-FTkL1eXYpzc/VbOcIW_JB0I/AAAAAAAE8eo/B8sdL6dCMFo/s1600/20150725_102_2360.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://2.bp.blogspot.com/-FTkL1eXYpzc/VbOcIW_JB0I/AAAAAAAE8eo/B8sdL6dCMFo/s640/20150725_102_2360.JPG" width="640" /></a></div>
<br />
之前買的洗車用水桶派上了用場!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-7m_cB6XMQs8/VbOcmraqrKI/AAAAAAAE8fg/3AtnZVKKxOs/s1600/20150725_102_2367.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://1.bp.blogspot.com/-7m_cB6XMQs8/VbOcmraqrKI/AAAAAAAE8fg/3AtnZVKKxOs/s640/20150725_102_2367.JPG" width="640" /></a></div>
<br />
沒有準備頭燈,只有一支手電筒,但人總是會找到生存的方式,一手拿網子、一手拿手電筒+樹枝來趕蝦子,一樣能很順利的抓到蝦!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZ42N7Y2TAWmRszXOwfmRy_HcEYHVXhXeEeSvNzzb4K-6f8kx1Cx96uZ_qrWqJAUmGlKzKfMmPzsOMRTWb5pxwfM5t7zr8MsQN2EEDD-M8ePy11EjnhmuOc1Ndy52ZUnDUy_gwuQ/s1600/IMAG5514.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZ42N7Y2TAWmRszXOwfmRy_HcEYHVXhXeEeSvNzzb4K-6f8kx1Cx96uZ_qrWqJAUmGlKzKfMmPzsOMRTWb5pxwfM5t7zr8MsQN2EEDD-M8ePy11EjnhmuOc1Ndy52ZUnDUy_gwuQ/s640/IMAG5514.jpg" width="360" /></a></div>
<br />
抓著抓著天就愈來愈黑了!附上一段現場錄的影片。<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/CQEJnSsLigw/0.jpg" frameborder="0" height="532" src="https://www.youtube.com/embed/CQEJnSsLigw?feature=player_embedded" width="640"></iframe><br />
<h3>
戰利品</h3>
因為在比較淺的地方(而且都固定在同個地方),大部份都是抓到小蝦!難得有一隻特別大的,抓到時好爽!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0zb61gfNN3n41AqyXUeFZ69yD1yMF8sP2zstb2ASVUEa7N-IKMbwvpq3N5L-_X3vdWE8tOYilEVMZo6ugtLv3ZuS1aU6r_SilgFuhspsbPbeQHc-2y3nJr3r2KDJVriQWIRqITQ/s1600/IMAG5519.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0zb61gfNN3n41AqyXUeFZ69yD1yMF8sP2zstb2ASVUEa7N-IKMbwvpq3N5L-_X3vdWE8tOYilEVMZo6ugtLv3ZuS1aU6r_SilgFuhspsbPbeQHc-2y3nJr3r2KDJVriQWIRqITQ/s640/IMAG5519.jpg" width="640" /></a></div>
<br />
魚很難抓,因為動作很快,但是在兩人合力之下,居然用網子抓到一隻大的苦花<span style="background-color: #fff2cc;">(經Roger指認應該是馬口魚!)</span>,這個爽度比抓到大蝦還開心!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6P7rjhnsfUWMhalEfdLdHtq51fWHuqvAUXe_3LDiE7snYm-hDmOy7G3ZumlABdIXlobN5d0SvUv6DWx3m2IkwmyWh4MzVHvCkWrTNn4EjR7S6zziST6u3d5BsgoiH3w9JhQFkkg/s1600/IMAG5521.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6P7rjhnsfUWMhalEfdLdHtq51fWHuqvAUXe_3LDiE7snYm-hDmOy7G3ZumlABdIXlobN5d0SvUv6DWx3m2IkwmyWh4MzVHvCkWrTNn4EjR7S6zziST6u3d5BsgoiH3w9JhQFkkg/s640/IMAG5521.jpg" width="640" /></a></div>
<br />
<h3>
插曲</h3>
<div class="separator" style="clear: both; text-align: left;">
默默的發現蝦子會往上爬,想逃走…</div>
<div class="separator" style="clear: both; text-align: left;">
我就把畫面用手機拍了下來,但看到照片的時候,突然驚了一下!啊底下那條魚是怎麼回事?在給我裝死嗎?</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYPbgJGh1EpJ17BC7KiXwXwo48qsQTpB3ykjBvilEoX9f_H9msuBopQbeL2KpT20oDqqErtZjqN-2kCIlMHpWiQUes_cj_XOnoja5ZII0dRiKWwvH1kYDbP87bqPQIUoHUXkI1vg/s1600/IMAG5523.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYPbgJGh1EpJ17BC7KiXwXwo48qsQTpB3ykjBvilEoX9f_H9msuBopQbeL2KpT20oDqqErtZjqN-2kCIlMHpWiQUes_cj_XOnoja5ZII0dRiKWwvH1kYDbP87bqPQIUoHUXkI1vg/s640/IMAG5523.jpg" width="360" /></a></div>
<br />
趕快打開手電筒,用樹枝戳了他,發現他真的死了!<br />
5分鐘前還好好的在那邊游泳,怎麼突然就掛了!<br />
<br />
然後仔細的看了一下…咦!之前抓的另一隻比較大一點的魚怎麼不見了?<br />
到底是被其他的蝦子聯手幹掉的,還是這條苦花吞了另一條魚被噎死了 (我外行人嘛,有比較智障的想法請專業的人見諒!),實在不知道怎麼回事…<br />
<br />
最後抓到晚上快九點,應該有抓了四、五十隻魚蝦們,在回去之前我們就把所有的戰利品又放回了溪裡,下次再來抓他們! XD<br />
<br />
註:回家後就上網做了點功課、訂了頭燈!不久後可能就有開箱文了吧!<br />
<br />
<br />joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0232台灣新北市坪林區鶯子瀨路2之1號大溪地坪林渡假村24.912736 121.7090373999999424.909135499999998 121.70399489999994 24.9163365 121.71407989999994tag:blogger.com,1999:blog-11438439.post-12621209367977319012015-07-25T04:21:00.001+08:002015-08-11T01:58:31.478+08:00[ScaVa->Scala] 什麼是Monad?<h2>
什麼是Monad?</h2>
<div>
我一直不想寫這篇! 因為這很難解釋…我自己查個半天網路上的解釋看的都眼花了。</div>
<div>
<br /></div>
<div>
不信? 你看看Wiki上的定義:</div>
<div>
<br /></div>
<div>
<span style="background-color: #eeeeee; color: #222222; font-family: arial, sans-serif; font-size: x-small; line-height: 15.6000003814697px;">Monad,單元(unit)的拉丁語,來自範疇論的一種技術,其已經被採用作為處理在功能性程序設計語言中狀態的一種方式,其使用 monads 來構建包含必須以特定順序來執行的操作程序。Monads 在功能性程序設計中的主要應用是表達輸入/輸出和改變狀態而不使用帶來副作用的語言。一個 monad 由三部分組成:增加一個現有類型的意思,從原始類型的值中創建一個新類型默認值的意思,和對與新的類型一起工作的舊的類型的基本應用程序操作符的一個替代。</span></div>
<div>
<br /></div>
<div>
………看得懂有鬼! (不然就是我的語言理解能力太差)</div>
<div>
<br /></div>
<div>
若是以實例來了解Monad之後,再回來看這段文字,其實勉強可以猜出他的描述。</div>
<div>
<br /></div>
<div>
網路上找到的一些例子中,在Scala裡最常舉的例子就是Option和Future了,接下來我試著以我的了解來解釋。</div>
<div>
<ul>
<li>Monad是一種Pattern,而他的目的,當然是想讓程式寫起來更簡單、看起來也更簡單,所以他把一些多餘的程式碼給省略,這也是Functional Programming的程式寫起來很精簡易讀的幫手之一。</li>
<li>Monad讓你把原來型態的物件多包起來,所以會看到M[T],這個M就是某一種Monad,而T是你原來物件的型態,像是Option[String],就是Option的Monad而裡面的型態是String。</li>
<li>Monad雖然幫你把他包起來,但還是能讓你處理原來的型態,甚至能轉換成另一個型態,使用map或flatMap之類的可以把M[A] 轉成 M[B],就像是Option[String]可以轉成Option[Int],而你只要寫"怎麼轉"就行了。</li>
<li>Monad在轉型之後的M[B]當然還是個Monad,可以繼續不斷的以Monad的特性處理下去。</li>
</ul>
</div>
<h3>
Option Monad</h3>
<div>
寫過程式的人都一定知道NullPointException,有跟潮流的人也知道現在的趨勢是不要再亂丟null了。</div>
<div>
早期寫C#就有Nullable<t>的型態、Swift也有Optional,現在Java 8也有Optional<t>的型態,在Scala中的Option主要的目的也是一樣,就是幫你把null包起來,然後可以進行下面這些的動作。</t></t></div>
<div>
<ul>
<li>可以透過 .isEmpty問問他是不是空值</li>
<li>isDefined看看他是不是有值</li>
<li>get去抓他實際的值</li>
<li>getOrElse抓值的同時如果值不存在順便回傳預設值。</li>
</ul>
</div>
但是若這樣在寫code的時候,就會像以下這樣:
<br />
<script src="https://gist.github.com/joecwu/79c93ae3768bac2116c0.js?file=blog-Scala-Monad-1.scala"/></script>
<!--<div class="gistLoad" data-file="blog-Scala-Monad-1.scala" data-id="79c93ae3768bac2116c0" id="gist-79c93ae3768bac2116c0">
<a href="https://gist.github.com/joecwu/79c93ae3768bac2116c0#file-blog-Scala-Monad-1-scala">載入原始碼</a></div>-->
<br />
這樣寫起來還是很麻煩啊! 一堆的if/else要判斷!
<br />
<div>
所以Option Monad提供的map, flatMap其實就幫你把if/else這些處理掉了! 你直接在map裡給他一個你要把Type A轉成Type B的實作就行了!</div>
<div>
<script src="https://gist.github.com/joecwu/79c93ae3768bac2116c0.js?file=blog-Scala-Monad-2.scala"/></script>
<!--<div class="gistLoad" data-file="blog-Scala-Monad-2.scala" data-id="79c93ae3768bac2116c0" id="gist-79c93ae3768bac2116c0">
<a href="https://gist.github.com/joecwu/79c93ae3768bac2116c0#file-blog-Scala-Monad-2-scala">載入原始碼</a></div>-->
<br /></div>
<h3>
Future Monad</h3>
<div>
Future就是個未來嘛! 他也是一個Monad,所以他也能讓你在不管Future的情況下,針對裡面的東西做處理(或轉成別的型態)。</div>
<div>
<br /></div>
<div>
就好像是傳入一個function,而這個function定義的是"等你拿到這個值的時候,把這個值怎樣怎樣的處理",你的function只要專心的定義拿到值要怎麼處理就行。</div>
<br />
<script src="https://gist.github.com/joecwu/79c93ae3768bac2116c0.js?file=blog-Scala-Monad-3.scala"/></script>
<!--<div class="gistLoad" data-file="blog-Scala-Monad-3.scala" data-id="79c93ae3768bac2116c0" id="gist-79c93ae3768bac2116c0">
<a href="https://gist.github.com/joecwu/79c93ae3768bac2116c0#file-blog-Scala-Monad-3-scala">載入原始碼</a></div>-->
<br />
看完了這些解釋,是否對Monad有些了解了呢? 這時候再去看一開始wiki那段文言文,應該比較有感覺了吧!<br />
<script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"></script>joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-12679819531806644052015-07-24T02:08:00.000+08:002015-07-24T21:20:14.448+08:00[敗家] Panasonic MS-N53-S 廚餘機<h2>
去日本要帶什麼回來?</h2>
今年(2015)六月的時候,跟小柔一起去東京玩,大家都會去日本搬些3C、電器回來,吹風機、水波爐、Macbook…不過這次我的目標是"廚餘機"!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCHkMz9kvoNWwVHuEyWqvkw3tOHJ5szTBDrzKQaWiVIiZZrClzQ1eANZuePHNIbnISxTy1iCIvNi1O2iDGu_LdTOHSARyylcyCiQP9kqPFe6Utx_qoxv6SNveeMMQY5B39vWTa4Q/s1600/IMAG4989.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCHkMz9kvoNWwVHuEyWqvkw3tOHJ5szTBDrzKQaWiVIiZZrClzQ1eANZuePHNIbnISxTy1iCIvNi1O2iDGu_LdTOHSARyylcyCiQP9kqPFe6Utx_qoxv6SNveeMMQY5B39vWTa4Q/s640/IMAG4989.jpg" width="362" /></a></div>
<br />
我們家會種菜,所以我媽媽平常就有在"堆肥",把廚餘丟進一個大箱子裡,讓他自然的腐爛、發酵,所以就養了一堆蛆…和有一堆叫不出名字的小蟲…,我都快崩潰了!<br />
<br />
所以要去日本前就做好了功課,什麼爐都不搬了,我就要搬一台廚餘機回來!<br />
這台Panasonic MS-N53在台灣水貨的價錢大約要18000~20000以上,網路上查了日本的售價後有便宜到48399日幣左右(以當時的匯率x0.2526大約是12,200多台幣)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_TbTF1YVwIv1_WQCUPcFTRpkgkj-u77FEKFjUx-w-0zA_lzRSekj0GTQenhcAfcImuCR_rjbe99o_cXqP8sNZ6z2fgZE4tAJUEpmjsPoFEVZSRgwkKOKgsu_yCw6DBNz5nJ2CWQ/s1600/panasonic-ms-n53.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="406" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg_TbTF1YVwIv1_WQCUPcFTRpkgkj-u77FEKFjUx-w-0zA_lzRSekj0GTQenhcAfcImuCR_rjbe99o_cXqP8sNZ6z2fgZE4tAJUEpmjsPoFEVZSRgwkKOKgsu_yCw6DBNz5nJ2CWQ/s640/panasonic-ms-n53.png" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
我比較隨興,所以想說價錢網路上查到了,應該就差不多這樣,現場找到價差不要太大的買買就行!<br />
誰知道……<span style="background-color: #fff2cc;"><span style="font-size: large;">到了日本才發現跟我想的不一樣!</span></span><br />
<br />
小柔很貼心,知道這是我來日本的蠻重要的一個目標,所以第一天到的時候,晚上就陪我去有樂町的BicCamera,想不到…看到的標價是<span style="background-color: #f4cccc;"><span style="font-size: large;"><b>76,000日幣(約19,200台幣)</b></span></span>,哇咧! 啊我在台灣買不就好了?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEho-ncmhaszytOx3J4N_rR71ujx7yq1U1zctL5BadJWnnOgF4l1AiZWpEqYrgqj-bhL5AICh8HR0MbHNJJ4JiNlSgrw6rSfzmCQsZCoZ2s_tXZHJ0Vu_O3xpZkjtoBJ-lcSS440qA/s1600/IMAG5293.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEho-ncmhaszytOx3J4N_rR71ujx7yq1U1zctL5BadJWnnOgF4l1AiZWpEqYrgqj-bhL5AICh8HR0MbHNJJ4JiNlSgrw6rSfzmCQsZCoZ2s_tXZHJ0Vu_O3xpZkjtoBJ-lcSS440qA/s640/IMAG5293.jpg" width="360" /></a></div>
<br />
當下我覺得還好,就沒太在意,想說到時候再去別間看看就好了…想不到,隔天到阿美橫町的時候看到某間連鎖電器也有去找,但沒賣,不然就是看到的價錢居然都差不多…有的也要6萬多日幣。<br />
<br />
晚上回飯店就開始擔心了…半夜不睡覺上網查不知從網路訂來不來得及,也傳訊息問在日本的朋友,後來得知可以殺價!<br />
<br />
第三天跑去新宿,先是在山田電機找到了終於覺得可以接受的價錢(56,440日幣)了,不過還沒殺價,就想說先去晃晃別間,沒找到更好的再回來問。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijvXBeWNxKLhY4U2RJ_5lKMMsGt8KcajZwVMRDLL-BQ4WbWubblzIi4R-qoAxGLw9vQV3vzeYxDmxcrHeY3UFmo-HpcOrsLeRjkGaUesRvNF1s7q7iPHeKP2ZINX_eBWm6OPAS8w/s1600/IMAG5346.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijvXBeWNxKLhY4U2RJ_5lKMMsGt8KcajZwVMRDLL-BQ4WbWubblzIi4R-qoAxGLw9vQV3vzeYxDmxcrHeY3UFmo-HpcOrsLeRjkGaUesRvNF1s7q7iPHeKP2ZINX_eBWm6OPAS8w/s640/IMAG5346.jpg" width="360" /></a></div>
<br />
找了另一間BicCamera發現沒貨,最後和小柔分頭行動,小柔去藥妝店,我去路邊的好像也是山田電機的LABI,發現也是個日幣76,000(打個叉叉)的高價,想說隨口殺個價,若可以殺到跟上一間差不多的價錢,也就能接受了啦…<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5nQPmI1rxo6VL1gxiR4g61urkkjSHoZaURgqMnx2HtfUc_FmIzMCVPob2-u-Xvf9rA6stZyD7x5vcSDC-_AKNKTvpw_SPHhVXdg4HzLw8XGtI31FQ2FNNYmTNmS6FUpzBRbpN4g/s1600/IMAG5356.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5nQPmI1rxo6VL1gxiR4g61urkkjSHoZaURgqMnx2HtfUc_FmIzMCVPob2-u-Xvf9rA6stZyD7x5vcSDC-_AKNKTvpw_SPHhVXdg4HzLw8XGtI31FQ2FNNYmTNmS6FUpzBRbpN4g/s640/IMAG5356.jpg" width="360" /></a></div>
<br />
<br />
當下找隨便抓了個路過的店員,(他好像很想落跑,但沒想到還是被我抓到),問了他這台的價錢,他就說等一下,就跑去問別人了… 等了三分鐘回來跟我說 72,000日幣哦! 我就拿手機給他看我第一張未稅48,399日幣的圖片,他思考了一下,拿了計算機按了按,又叫我等一下,這次去了5分鐘才回來,最後說他只能算我未稅54,000之類的(有點忘了確切的價格),我想了幾秒想說應該就這樣吧! 我不想再走路了…就跟他說"好! 我要!"<br />
<br />
他又跑去找別人,然後另一個人要幫忙拿貨,他就陪我站著等,等超久的!! 應該有快10分鐘…然後很乾啊! 我就只好跟他亂聊,(他英文也沒很好,就用簡單的單字溝通,日本口音也很重)<br />
<br />
我:這個賣得怎麼樣呀? 好不好啊?<br />
<br />
他說:這個很好啊! 是日本製的! (廢話)<br />
<br />
我:日本很多人買這個嗎?<br />
<br />
他說:很少,大概才不到3%的人會買吧,因為家裡很小,沒有地方種東西。<br />
<br />
我:哦哦~是哦~<br />
<br />
他又說:很環保、很好!如果他家空間大的話、有花園的話,他也會想買。<br />
<br />
總之就是乾聊了10分鐘之後…另個店員提著我的廚餘機過來,帶我去櫃台結帳!!<br />
<br />
我也不知為什麼最後刷卡的總金額是 <span style="background-color: #fff2cc;"><span style="font-size: large;"><b>48,380日幣(12,220台幣)</b></span></span> !<br />
可能是刷信用卡又有什麼折扣之類的吧…<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-3JljySs-qp0/VaFv06JQi-I/AAAAAAAE6sI/nwM2_fsDVjQ/s1600/20150621_101_1998.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://1.bp.blogspot.com/-3JljySs-qp0/VaFv06JQi-I/AAAAAAAE6sI/nwM2_fsDVjQ/s640/20150621_101_1998.JPG" width="640" /></a></div>
<br />
我請他們幫我包裝成可以手提的,當天外面有飄小雨(雖然我過去的時候雨已經停了),但是他還是很貼心的幫我先把外面的束帶剪掉,用塑膠袋整個包起來、貼起來,再重新用束帶+兩個手提的握把給包裝起來。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-6XXmLJuMwzU/VaF4TRBLiSI/AAAAAAAE64M/bc6rSAXC2ZE/s1600/20150621_101_1999.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="http://3.bp.blogspot.com/-6XXmLJuMwzU/VaF4TRBLiSI/AAAAAAAE64M/bc6rSAXC2ZE/s640/20150621_101_1999.JPG" width="640" /></a></div>
<br />
然後我就提著這個13多公斤重的箱子去找小柔要逛新宿,後來發現完全不行啊!這超重的!<br />
還好日本車站寄物櫃真的好好用,塞進去就可以繼續去玩耍!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8loGw3inZwpPT-1y-IIf67XKLNVIU5t1jguOaAILH5HbftzVstt4eUpzLSyI9SZyqX1qpr6hrSDPBD13LL3fU3laTT4_P9QtWk7BjyLoHu4XYi8hQmVbcV0O5Wn5lBBy3NEhSXQ/s1600/20150621_101_2004.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="466" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8loGw3inZwpPT-1y-IIf67XKLNVIU5t1jguOaAILH5HbftzVstt4eUpzLSyI9SZyqX1qpr6hrSDPBD13LL3fU3laTT4_P9QtWk7BjyLoHu4XYi8hQmVbcV0O5Wn5lBBy3NEhSXQ/s640/20150621_101_2004.JPG" width="640" /></a></div>
<br />
<h2>
開箱嘍!</h2>
回到台灣後就馬上開箱啦!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZQyl1jEd4z5M2cucioNqJfuuUvXE7fuGpMYMPIvbFJhAl5CSzQrIwRJLXDiiSOhfqa33e_vadK14lFZV1vIUN1ifyhgRRlLcoQjNqCMAZ0kUcbhTIvNp1Li0vEp4RTsQhKKyhmg/s1600/DSC_7311.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZQyl1jEd4z5M2cucioNqJfuuUvXE7fuGpMYMPIvbFJhAl5CSzQrIwRJLXDiiSOhfqa33e_vadK14lFZV1vIUN1ifyhgRRlLcoQjNqCMAZ0kUcbhTIvNp1Li0vEp4RTsQhKKyhmg/s400/DSC_7311.JPG" width="265" /></a></div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7hahbs0YrR6Qf3eCQBcazhDQBfW8L5m2l4RWZ088f_QhVd5fz8HSLe304wtjqwuFnrxe85C1n7h_vDS7B9aiKgZ3TKXnUDVVcAClSdqRPOVukB7UJjgvCY1SxFM6nCr23NJHa4Q/s1600/DSC_7312.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7hahbs0YrR6Qf3eCQBcazhDQBfW8L5m2l4RWZ088f_QhVd5fz8HSLe304wtjqwuFnrxe85C1n7h_vDS7B9aiKgZ3TKXnUDVVcAClSdqRPOVukB7UJjgvCY1SxFM6nCr23NJHa4Q/s320/DSC_7312.JPG" width="320" /></a><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmf95Ot8LkSl0Oh_ZetYV3ntbOQWgR02PgEFaXguqnRoyjD1sCFObUU3cKZNGCCkw2_aiD3Vb1cfc9sGNCH1a8WGVkr7E6jtSak2Kr-UAQVpt8pnMFpD3fgSgxT4kS7yVUIECPCA/s1600/DSC_7317.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmf95Ot8LkSl0Oh_ZetYV3ntbOQWgR02PgEFaXguqnRoyjD1sCFObUU3cKZNGCCkw2_aiD3Vb1cfc9sGNCH1a8WGVkr7E6jtSak2Kr-UAQVpt8pnMFpD3fgSgxT4kS7yVUIECPCA/s320/DSC_7317.JPG" width="320" /></a><br />
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJuiz6AIyTnX3TZTwSMx5gASlu6sZy5vt3XEE-M11gBb3oqv2CUH0C5zqCfmKEoNTpfvo5bCvUxbo9QRHpShw6G29UoHmKvWleHY1n8P7OZX2PkLcfIfg1e6yvjsPE3jPWON42tQ/s1600/DSC_7319.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJuiz6AIyTnX3TZTwSMx5gASlu6sZy5vt3XEE-M11gBb3oqv2CUH0C5zqCfmKEoNTpfvo5bCvUxbo9QRHpShw6G29UoHmKvWleHY1n8P7OZX2PkLcfIfg1e6yvjsPE3jPWON42tQ/s320/DSC_7319.JPG" width="212" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQPHJW0qm-1kDOaaHuW-L1Y7M1qVVCp5KoxLCpnGyQzK7k3ay-oS0XhsbvtUiffwrl3Y-mwIgEnjx0JifJpFZSqAg80GjvdazRSqihsynRNYj99qtb0cQ8XV0kGDMHyM5SBm_lZA/s1600/DSC_7323.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQPHJW0qm-1kDOaaHuW-L1Y7M1qVVCp5KoxLCpnGyQzK7k3ay-oS0XhsbvtUiffwrl3Y-mwIgEnjx0JifJpFZSqAg80GjvdazRSqihsynRNYj99qtb0cQ8XV0kGDMHyM5SBm_lZA/s320/DSC_7323.JPG" width="212" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTyPTcDxdI7F34qHFIFDRRkhWtHFbxsqvUTm8-4ECHvR1fkjKqtYfUIfd294Y-Ey-2WaZ5PozkVVM4LDTToR7VXG1BANK5GNcJzBEzqE4oUiQrJXw7iClU1cF07qfBrX0gQdiHUg/s1600/DSC_7324.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTyPTcDxdI7F34qHFIFDRRkhWtHFbxsqvUTm8-4ECHvR1fkjKqtYfUIfd294Y-Ey-2WaZ5PozkVVM4LDTToR7VXG1BANK5GNcJzBEzqE4oUiQrJXw7iClU1cF07qfBrX0gQdiHUg/s320/DSC_7324.JPG" width="212" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhioUJzDXYg-JVTFC0Whlzi11APbhdvRab2oPaQnJGSFD5A6Jrw36I6dNK-rM_eXUVfXBeQ0EzDLqnN73_zUJRA_Ug9ZaYx3DC4Bynb3dHlvyx5Ljxsf9hKISiIFE_5QETP5UfNMg/s1600/DSC_7325.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhioUJzDXYg-JVTFC0Whlzi11APbhdvRab2oPaQnJGSFD5A6Jrw36I6dNK-rM_eXUVfXBeQ0EzDLqnN73_zUJRA_Ug9ZaYx3DC4Bynb3dHlvyx5Ljxsf9hKISiIFE_5QETP5UfNMg/s320/DSC_7325.JPG" width="212" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuy3u06bCjeNd-QDpz2N0917LjiYD5fEfJXVQLbGVeOhRHNXViKM2dZhF6OyJS7Qah3PgV4g1vfkKPGMaZ3D51GK0-z7i1fZeF-zzNvjdOPMME09RqVEIF-ivzBsLudgID3L8izQ/s1600/DSC_7326.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuy3u06bCjeNd-QDpz2N0917LjiYD5fEfJXVQLbGVeOhRHNXViKM2dZhF6OyJS7Qah3PgV4g1vfkKPGMaZ3D51GK0-z7i1fZeF-zzNvjdOPMME09RqVEIF-ivzBsLudgID3L8izQ/s320/DSC_7326.JPG" width="212" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4mem9UXnbmKUWkrM5lHBF_4aOl_D8eaqVwDvmVDPu4ckVfpwVocAMtIN-xgNITB6Swb3YsWszM9tAdaP4DJw5LFCoAUtiAnYtozKVy4KMZm6KIM0pmhpv-CM5_-9YBcEzDY_0Qg/s1600/DSC_7332.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4mem9UXnbmKUWkrM5lHBF_4aOl_D8eaqVwDvmVDPu4ckVfpwVocAMtIN-xgNITB6Swb3YsWszM9tAdaP4DJw5LFCoAUtiAnYtozKVy4KMZm6KIM0pmhpv-CM5_-9YBcEzDY_0Qg/s320/DSC_7332.JPG" width="212" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtu90SRj23Hechq44la2C2JVx1FE7Wm5VYUL0tm2xg6TjEmslN6iq-UupfoGf9Jlji6WTg8dpuspgo_MBniWgBUJ3Hjl5415Yrrynxr1E8q75Uyr_Rc_dRoG8-oSg6y3e-AxJuQw/s1600/DSC_7333.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtu90SRj23Hechq44la2C2JVx1FE7Wm5VYUL0tm2xg6TjEmslN6iq-UupfoGf9Jlji6WTg8dpuspgo_MBniWgBUJ3Hjl5415Yrrynxr1E8q75Uyr_Rc_dRoG8-oSg6y3e-AxJuQw/s320/DSC_7333.JPG" width="212" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYlqnjOEMiEWEKGpR3xngMYDnGIWJF8DqNT4enejYtlln53O_pR0vmr0q7cSWE2p5mE_FRAFmtiSdY9imyzK8V2h7I9YNavTLouivmcsYXQDN-8Tt29wob0zHc0PGF3Il6qgy4hQ/s1600/DSC_7327.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYlqnjOEMiEWEKGpR3xngMYDnGIWJF8DqNT4enejYtlln53O_pR0vmr0q7cSWE2p5mE_FRAFmtiSdY9imyzK8V2h7I9YNavTLouivmcsYXQDN-8Tt29wob0zHc0PGF3Il6qgy4hQ/s320/DSC_7327.JPG" width="212" /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhULccirRp-VXtNvWgHXuMEniQSZSGkfmhnFJeQwCLZUWJkLtQlyLyoOegyipmqqkNnsoB8wi94SoNRE-tCEUyeC0G4lq6pNDiZaqP1F-N7IJ9vxI1a49wnxApnVt_E0K_UM7GQ4w/s1600/DSC_7335.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhULccirRp-VXtNvWgHXuMEniQSZSGkfmhnFJeQwCLZUWJkLtQlyLyoOegyipmqqkNnsoB8wi94SoNRE-tCEUyeC0G4lq6pNDiZaqP1F-N7IJ9vxI1a49wnxApnVt_E0K_UM7GQ4w/s320/DSC_7335.JPG" width="212" /></a><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO4qpd9CEvJ6DQgtHfGhjbEoje9ao_vqBYRw8WKpGj54HEDMydSyqS11WROpb01rFyCd99frkdkW3hoI-yJs1cloLkdMCYBUCMf0BClCuw_MHX9G9oOfQ_QrsZz_FwzB-gnPsCeg/s1600/IMAG5399.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO4qpd9CEvJ6DQgtHfGhjbEoje9ao_vqBYRw8WKpGj54HEDMydSyqS11WROpb01rFyCd99frkdkW3hoI-yJs1cloLkdMCYBUCMf0BClCuw_MHX9G9oOfQ_QrsZz_FwzB-gnPsCeg/s640/IMAG5399.jpg" width="360" /></a></div>
<br />
<br />
晚上睡覺前,把我家狗狗挑食不吃放到壞掉的飯+荔枝皮、果殼+少量其他廚餘丟了進去,按下開始運轉後就去睡覺,隔天早上起來廚餘就變成有淡淡香氣的"乾貨"了!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRpHp1k_H1mtXreMYykyYpmWW6voYsfW4p9b5tNlTBlEZl0rIk1sPlnU5tI8MNKoEsHFVjVNVtWqP0LpwhvVQdShDrtXRQ0iYprec9UP7wUpsdDF4piidlSfudh_tskWI9JWExxA/s1600/IMAG5409.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjRpHp1k_H1mtXreMYykyYpmWW6voYsfW4p9b5tNlTBlEZl0rIk1sPlnU5tI8MNKoEsHFVjVNVtWqP0LpwhvVQdShDrtXRQ0iYprec9UP7wUpsdDF4piidlSfudh_tskWI9JWExxA/s640/IMAG5409.jpg" width="640" /></a></div>
<br />
體積差不多變成原本的7~8分之1,網路有說可以少到變10分之1,當然也是要看你放的是什麼東西。<br />
<br />
我家目前還是比較少開火,廚餘的量不會很多,所以目前是用個有密封蓋的塑膠桶放在冰箱,一但累積滿了,就丟去餵他吃!<br />
<br />
這台有個功能,是"不要那麼乾",好像是更適合拿來做堆肥,但試過一次,發現真的還是有點濕濕的,而且會有點臭,所以現在都是用標準模式,讓他把廚餘給烘乾!<br />
<br />
<br />
<br />joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0tag:blogger.com,1999:blog-11438439.post-81110130313961111002015-07-23T03:42:00.001+08:002015-08-11T01:48:22.798+08:00[ScaVa->Scala] Scalaz Validation與Either(Disjunction)的另個選擇 - Scalactic Or<h2>
前言</h2>
之前寫過了Scalaz的Either(Disjunction)與Validation兩篇,今天老闆看到我的blog後,跟我說"寫一下Scalactic啊!",所以我就來寫了!!<br />
<br />
<h2>
Scalactic</h2>
Scalactic這個東西,是從ScalaTest發展出來的,為了能方便直接"單獨"使用在Production的環境,當然ScalaTest裡面有包含了完整的Scalactic,如果你有使用ScalaTest的話,可以直接使用Scalactic。<br />
<br />
至於Scalaz和Scalactic的差異,細節可以參考這個影片(<a href="https://newcircle.com/s/post/1704/comparing_functional_error_handling_in_scalaz_and_scalactic" target="_blank">Comparing Functional Error Handling in Scalaz and Scalactic</a>),簡單來說,有些觀念上的不同(沒有誰對誰錯),想讓使用上更明暸簡單,不用分Disjunction和Validation兩種型態,提供更單純的型態,而且在描述上可以更直覺。<br />
<br />
概念上大自整理如下:<br />
<h3>
Or與其子類別Good與Bad</h3>
<span style="background-color: #eeeeee;"><a href="http://doc.scalatest.org/2.2.4/index.html#org.scalactic.Or" target="_blank">sealed abstract class Or[+G, +B] extends AnyRef</a></span><br />
<br />
<span style="background-color: #eeeeee;"><a href="http://doc.scalatest.org/2.2.4/index.html#org.scalactic.Good" target="_blank">final case class Good[+G, +B](g: G) extends Or[G, B] with Product with Serializable</a></span><br />
<br />
<span style="background-color: #eeeeee;"><a href="http://doc.scalatest.org/2.2.4/index.html#org.scalactic.Bad" target="_blank">final case class Bad[+G, +B](b: B) extends Or[G, B] with Product with Serializable</a></span><br />
<br />
Or就像是Either或Disjunction,因為Scalactic直接定義了Good和Bad,所以比Scala原生的Either用起來簡單,也比Disjunction看起來清楚。<br />
<br />
而且Or的Bad子類別可以讓你累積errors,就像是Scalaz的Validation的功能一樣,比較有趣的是,開發的人覺得左邊的才是Good,右邊的是Bad,跟Scalaz的Validation相反。<span style="color: #38761d; font-size: x-small;">(分明就是讓大家用習慣後很難換去用另一種嘛!!!)</span><br />
<h3>
Every與其子類別One與Many</h3>
<span style="background-color: #eeeeee;"><a href="http://doc.scalatest.org/2.2.4/index.html#org.scalactic.Every" target="_blank">sealed abstract class Every[+T] extends PartialFunction[Int, T]</a></span><br />
<span style="background-color: #eeeeee;"><br /></span>
<span style="background-color: #eeeeee;"><a href="http://doc.scalatest.org/2.2.4/index.html#org.scalactic.One" target="_blank">final case class One[+T](loneElement: T) extends Every[T] with Product with Serializable</a></span><br />
<br />
<span style="background-color: #eeeeee;"><a href="http://doc.scalatest.org/2.2.4/index.html#org.scalactic.Many" target="_blank">final case class Many[+T](firstElement: T, secondElement: T, otherElements: T*) extends Every[T] with Product with Serializable</a></span><br />
<br />
Every是一個有順序性的、不可修改的、不能是空的元素的集合,One是繼承他,但裡面只有一個值,Many也繼承他,而裡面是兩個以上的值。<br />
<br />
這裡的定義,其實就是為了讓Or裡的Bad可以是單一值與多值,就像是Validation中的accumulating errors的實作Non-Empty-List一樣,不過Scalactic是把這兩種合在一起(都叫Every),而不像Scalaz的Validation與ValidationNel(其實是<span style="color: #999999;">Validation[NonEmptyList[E]]</span>)是兩種不同的型態。<br />
<h3>
Validation與其子類別Pass與Fail</h3>
<span style="background-color: #eeeeee;"><a href="http://doc.scalatest.org/2.2.4/index.html#org.scalactic.Validation" target="_blank">sealed trait Validation[+E] extends AnyRef</a></span><br />
<br />
<span style="background-color: #eeeeee;"><a href="http://doc.scalatest.org/2.2.4/index.html#org.scalactic.Pass$" target="_blank">object Pass extends Validation[Nothing] with Product with Serializable</a></span><br />
<br />
<span style="background-color: #eeeeee;"><a href="http://doc.scalatest.org/2.2.4/index.html#org.scalactic.Fail" target="_blank">case class Fail[E](error: E) extends Validation[E] with Product with Serializable</a></span><br />
<br />
在使用Scalaz的Validation或是Either時,在用for或filter的時候,我們會不知道他是什麼型態,所以寫起來還要去判斷型態再來處理,這樣其實蠻麻煩的。<br />
<br />
而Scalactic在使用Or型態的for或是filter的時候,讓你透過Closure在裡面可以回傳Pass或是Fail。可以把Validation想像成是Option,而Pass其實是None,Fail的時候才有值,這樣用起來不是更簡單嗎?<br />
<h3>
Accumulation</h3>
這裡面實作了accumulating errors的一些方法,包含了withGood, when, combined, validatedBy, zip,就是幫你把上面提到的Or, Every, Validation做轉換、或混在一起用的時候的工具。
<br />
以下是使用Scalactic試寫的一段HTTP Request參數驗證 (亂寫的,邏輯不要太認真,主要是看用法)<br />
<br />
<script src="https://gist.github.com/joecwu/410810c895dc98614083.js"></script>
<!--<div class="gistLoad" data-id="410810c895dc98614083" id="gist-410810c895dc98614083">
<a href="https://gist.github.com/joecwu/410810c895dc98614083">載入原始碼</a></div>-->
<br />
<h2>
參考資料</h2>
<ul>
<li><a href="http://www.scalactic.org/" target="_blank">Scalactic</a></li>
<li><a href="https://newcircle.com/s/post/1704/comparing_functional_error_handling_in_scalaz_and_scalactic" target="_blank">Comparing Functional Error Handling in Scalaz and Scalactic</a></li>
</ul>
<br />
<script src="https://cdn.rawgit.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"></script>joewuhttp://www.blogger.com/profile/01792922286479074811noreply@blogger.com0