tag:blogger.com,1999:blog-10539276680067204312024-03-05T16:52:57.058+08:0035成群台南,是一個適合人們作夢、寫code、吃美食、敗家、寫文章、悠然過活的地方。newmanhttp://www.blogger.com/profile/02106860573153331504noreply@blogger.comBlogger25125tag:blogger.com,1999:blog-1053927668006720431.post-65148449925993047212014-07-31T09:58:00.000+08:002014-07-31T09:58:00.411+08:00超輕量化JavaScript除錯工具<script src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js"></script><br />
<a href="http://googletesting.blogspot.tw/2008/08/tott-100-and-counting.html">“Debugging sucks. Testing rocks!”</a>,如同Google工程師所說,與測試工作比起來,除錯實在是一件很沒效益的事,尤其是當問題已經發生,頭已經抱著燒的狀況下要除錯更是苦不堪言。倒底測試有多重要呢?Google甚至還開始提倡一個馬桶上的測試活動 "<a href="http://googletesting.blogspot.tw/search/label/TotT">Testing on the Toilet</a>"!不過這篇倒不是要跟大家介紹Google如何逼工程師一邊上廁所一邊測試(有點扯遠了),而是就算已經做好妥善的測試,除錯仍是避免不了的工作,經過上一篇<a href="http://35around.blogspot.tw/2014/07/ie.html">IE你別鬧了</a>的經驗後,發現雖然工作上不常用到JavaScript,但是一旦遇到這方面的問題,除錯過程總是非常惱人,尤其我們還需要把各種瀏覽器版本都檢查過一遍才行。當時正好在網路上看到了一個簡單好用的JavaScript除錯工具– <a href="https://github.com/krasimir/deb.js">Deb.js</a>,雖然說是除錯工具,但更精准地說,Deb.js算是"<strong>將function的參數及結果自動地輸出到Console.log的一個小工具</strong>"。<br />
<br />
<a name='more'></a><br />
還不曉得Deb.js之前,我們常常是靠手工將變數的數值output到console來檢視結果是否符合預期,例如下面這個範例:<br />
<br />
<pre class="prettyprint">var doSomething = function(value) {
console.log('start doSomething,arg:'+value);
return value * 2;
};
console.log(doSomething(42));
</pre><br />
在這個例子中,我們需要知道doSomething這個function執行前後的變化,因此在function執行前以及執行後都將變數的內容都印出來看看,如果牽扯範圍較大,則會繼續把其他function都加上Console輸出,有時候頭腦處於遲鈍狀態,一時抓不出臭蟲,甚至會出現需要暴力地將每一行程式都加上console.log來除錯的窘境 XD。<br />
<div class="se-section-delimiter"></div><br />
<h3><span style="font-size: large;">使用deb.js</span></h3><br />
這時候使用deb.js便可以輕鬆地降低這個困擾,首先我們從gihub上下載<a href="https://github.com/krasimir/deb.js">deb.js專案</a>,在build目錄會看到一個deb.min.js,我們可以直接將它放入自己的專案中。<br />
<br />
<img alt="enter image description here" src="https://farm4.staticflickr.com/3862/14588774759_dd3e3a2517_o.png" title="" /><br />
<br />
接下來在網頁開頭加入script宣告。<br />
<br />
<pre class="prettyprint"><script src="deb.min.js"></script>
</pre><br />
最後我們在每個function後面加入.deb() 就大功告成了。<br />
<br />
<pre class="prettyprint">var calculateSomething = function(cb) {
// ...
}.deb();
</pre><br />
以deb.js專案目錄中的example為例(位於deb專案的/example子目錄),此範例中有一個檢查欄位輸入的javascript,<br />
<br />
<pre class="prettyprint">window.onload = function() {
$('[value="register"]').on('click', function() {
Module.collectData(function(err, data) {
if(err) {
Module.error(err);
} else {
Module.success(data);
}
}.debc('My buggy function'));
});
}
</pre><br />
用瀏覽器開啓範例中的index.html之後,順便也把console視窗打開,(如果是使用Chrome的話,可以在網頁上按滑鼠右鍵點選”檢視元素”功能),畫面上可以看到如下圖的Name及Address輸入欄,我在測試過程輸入了兩次資料,第一次是輸入Name:aaa以及Address:bbb,第二次是Name:xxx,但Address則是留空,這兩次的request的參數傳遞的log則都會出現在下方的Console視窗中,因為該範例是使用.debc()的方式,因此log的格式還會有collapsing的收折效果。<br />
<br />
<img alt="enter image description here" naptha_cursor="region" src="https://farm3.staticflickr.com/2924/14578080959_bc4c9f1641_z.jpg" title="" /><br />
<br />
另外,我們還可以為function定義特殊的label來區別,當log數量很龐大時可以快速找到對應的內容,如範例中指定.debc(‘My buggy function’)的方式,Console 視窗輸出function log的時候也會以此label作為辨識。<br />
<br />
<h3><span style="font-size: large;">檢視stack trace來除錯</span></h3><br />
deb.js也會將function call的stack trace整理在同一組console中,這對除錯相當方便。假設我們將上述範例index.html的My buggy function改成如下(修改第54行的if判斷):<br />
<br />
<pre class="prettyprint linenums:51">window.onload = function() {
$('[value="register"]').on('click', function() {
Module.collectData(function(err, data) {
if(typeof err === 'object') {
Module.error(err);
} else {
Module.success(data);
}
}.debc('My buggy function'));
});
}
</pre><br />
然後嘗試重新輸入一次如下圖參數,這時候會發現出錯了TypeError的錯誤,打開Console可以從中檢視出現錯誤的function以及stack trace內容,原來當兩個欄位都有填寫的狀況下,第53行的err參數是傳遞null進來,因此造成第54行的if判斷為true,後面的err.msg當然就無法執行而造成TypeError了。<br />
<br />
<img alt="enter image description here" src="https://farm4.staticflickr.com/3914/14597838648_e1b09db844_c.jpg" title="" /><br />
<br />
了解了deb.js的使用方式之後,我們只要把專案的所有javasciprt function都加上.deb()方法即可,接下來便可以輕輕鬆鬆在Console中檢視參數傳遞的狀況。由於這隻js只有不到2K的大小(官方稱之為世界上最小的除錯工具),因此也不用擔心因為除錯功能而增加專案的負擔,放心加下去就對了。<br />
<br />
延伸閱讀: <br />
<br />
<a href="http://code.tutsplus.com/tutorials/debjs-the-tiniest-debugger-in-the-world--cms-21565">http://code.tutsplus.com/tutorials/debjs-the-tiniest-debugger-in-the-world–cms-21565</a>Sam Chttp://www.blogger.com/profile/16142383609940270017noreply@blogger.com13tag:blogger.com,1999:blog-1053927668006720431.post-64985825295498001342014-07-24T09:29:00.001+08:002014-07-25T18:51:00.764+08:00在網頁上顯示程式碼 - Code Prettify tool<script src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js"></script><br />
最近開始著手將一些技術相關文章整理至部落格上,由於有些內容是範例程式碼,通常需要在網頁上呈現較易讀的樣式,因此就順手(<strike>湊個篇幅</strike>)在這邊介紹好用的工具。目前大部份的部落格服務也都有提供類似<a href="http://zh.wikipedia.org/wiki/Markdown">Markdown</a>的文章編輯功能,可以將內文直接以Quoto標記,這個Quoto標記背後其實就是利用HTML的<blockquote/>標籤來標示內容。雖然這種摘引的方式可以快速區分程式碼範例和內文的差異,但對程式碼閱讀來說,辨識度仍非常的差。<br />
<br />
<img alt="enter image description here" src="https://farm4.staticflickr.com/3843/14706981975_d4711c16cf.jpg" title="" /><br />
<br />
<h3><span style="font-size: large;"><br />
利用<pre/> 或是 >code/> 語法<br />
</span></h3><br />
因此我們大多直接下海編輯HTML內容,改用<pre/>或是<code/>的標籤來標記程式碼,另一種方式是採用<a href="http://dev.w3.org/html5/spec-author-view/the-code-element.html#the-code-element">HTML5</a>的格式,以<pre/><code class=”language-java> …</code></pre> 的這種將兩個標籤搭配使用的方式。<br />
<a name='more'></a><br />
以上述的程式範例用blockquote標示會顯示如下:<br />
<blockquote class="tr_bq">@Override<br />
public boolean onCreateOptionsMenu(Menu menu) {<br />
// Inflate the menu.<br />
getMenuInflater().inflate(R.menu.my, menu);<br />
return true;<br />
}</blockquote>而用code標示,則顯示如下:<br />
<br />
<code>@Override<br />
public boolean onCreateOptionsMenu(Menu menu) {<br />
// Inflate the menu; this adds items to the action bar if it is present.<br />
getMenuInflater().inflate(R.menu.my, menu);<br />
return true;<br />
}</code><br />
<br />
<h3><span style="font-size: large;"><br />
Google當然也佛心地提供了好用的pretty-print工具<br />
</span></h3><br />
由於語法的顯示格式通常會隨著不同的語言會有所不同,如果想要更忠實地呈現不同的語法樣式,或是想要自由地定義自己想要的格式,不妨試著利用Google的<a href="https://google-code-prettify.googlecode.com/svn/trunk/README.html">Javascript code prettifier</a>工具。code prettifier是一個Javascript + CSS的小工具,使用方法當然就是要直接編寫HTML語法,不過編輯方式算相當簡單,第一步驟是在HTML前面內嵌這個script。<br />
<pre class="prettyprint lang-html"><span style="font-size: x-small;"><script src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js"></script>
</span></pre>接下來直接利用<pre class="prettyprint"/>或是<code class="prettyprint"/>來標記程式碼即可,如此一來,標示的程式碼便會根據run_prettify.js中的script及CSS樣式來顯示不同的格式。<br />
例如: <br />
<br />
<code class="prettyprint"><br />
@Override<br />
public boolean onCreateOptionsMenu(Menu menu) {<br />
// Inflate the menu; this adds items to the action bar if it is present.<br />
getMenuInflater().inflate(R.menu.my, menu);<br />
return true;<br />
}<br />
</code><br />
此外,code prettify tool還會自動偵測語言類型,因此我們無需特別指定,但如果是因為想要顯示較特殊的語言,也可以透過如 <code class="prettyprint lang-*" />的方式直接指定(符號*表示欲指定的程式碼附檔名,如lang-sql)。以下是官方文件所述預設支援的語言種類:<br />
<br />
<blockquote class="tr_bq"><pre class="prettyprint lang-html"><br />
The lang-* class specifies the language file extensions.<br />
File extensions supported by default include<br />
"bsh", "c", "cc", "cpp", "cs", "csh", "cyc", "cv", "htm", "html",<br />
"java", "js", "m", "mxml", "perl", "pl", "pm", "py", "rb", "sh",<br />
"xhtml", "xml", "xsl".<br />
</pre></blockquote><h3><span style="font-size: large;"><br />
顯示不同的主題外觀<br />
</span></h3><br />
code prettify 也設計了幾種不同的主題風格(skin),可根據不同的喜好來置換主題,例如我比較喜歡暗背景搭配亮色字型,則可以選擇如下的desert風格: <br />
<br />
<img alt="enter image description here" src="https://farm6.staticflickr.com/5556/14690650156_6a6d49cf02.jpg" title="" /><br />
<br />
使用方式是在指定的script標籤中加入如下的skin屬性:<br />
<pre class="prettyprint lang-html"><span style="font-size: x-small;"><script src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js?skin=desert"/>
</span></pre>另外還可以選用其他<a href="http://google-code-prettify.googlecode.com/svn/trunk/styles/index.html">各種不同的主題清單</a>。<br />
<h3><span style="font-size: large;"><br />
標示行數<br />
</span></h3><br />
有時候我們會希望透過行數來指明程式碼某一行的內容,此時可以在prettyprint後面加上linenums的設定:<br />
<pre class="prettyprint lang-html"><span style="font-size: x-small;"><pre class="prettyprint linenums:4">...</pre>
</span></pre>其中linemums:4表示該程式碼行數編號從第四行開始編,顯示結果如下:<br />
<pre class="prettyprint linenums:4"><span style="font-size: small;">@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.my, menu);
return true;
}</span>
</pre><h3><span style="font-size: large;"><br />
題外話<br />
</span></h3><br />
不知道何時開始,凡是尋找資訊系統上相關問題時,常常找到Google所提供不錯的解決方案而且都是open source,從規模強大的應用程式框架到這種小而精美如code prettify的小工具都有,以台廠角度來看這件事情,常常會覺得不可思議,先不論有沒有公司會同意花資源去開發這種領域獨特且小眾無盈利的專案,Google公司的高層主管應該也不會細管這些小專案才對,這些小專案可能只是工程師隨手寫來解決自身問題,覺得好用便公開給大家使用,Google本身也很放心地放任工程師以官方名義發表這些產品,這可能是Google之前鼓勵工程師以20%工作時間自由創新的這個制度下的產物。見微知著,若要認真探討企業的成功之道的話,我想公司能夠追求卓越,主要也是企業文化所導致的結果,而非其本身擁有多高超的工程技術或是不傳之秘的研發經驗,若是靠後者所出道,我想我會偏頗地把這一時的成功,推究給運氣。Sam Chttp://www.blogger.com/profile/16142383609940270017noreply@blogger.com0tag:blogger.com,1999:blog-1053927668006720431.post-43874448798438606362014-07-24T01:52:00.000+08:002014-07-24T09:04:04.059+08:00簡單的開箱與改裝 - ThinkPad T540p 有了上一次 <a href="http://35around.blogspot.tw/2014/07/aorus-x7-v2.html" target="_blank">AORUS X7 v2</a> 的經驗之後,這次決定改考慮較穩定的 ThinkPad 與 DELL。不過因為 DELL 三年保固的 Latitude 系列通路實在太少,依所需規格詢價要等 2~3 天,等報價出來如果有多的預算或預算不足,要改規格又要再等,總覺得不是很方便,所以最後就決定試試 C/P 值頗低的 ThinkPad T540p...<br />
<br />
<a name='more'></a>雖說 C/P 值低,但實際看過 T540p 之後覺得其實質感很不錯,而且收集資料時到 Lenovo 網站看了一下說明書,不虧有 IBM 流傳下來的血統,說明實在是很詳細,加上方便的全尺寸鍵盤與三年保固,難怪還是有一定的銷量。<br />
<br />
<h3>
<span style="font-size: x-large;">規格</span></h3>
處理器:Intel® Core™ i7-4700MQ (2.4GHz-3.4GHz)<br />
記憶體:8GB DDR3L 1600, 2 個插槽 (最大 16GB)<br />
顯示卡:NVIDIA® GeForce® GT 730M 1GB<br />
顯示器:15.6" Full HD 1920x1080<br />
儲存裝置:mSATA SSD 16GB + SATA3 HDD 1TB 5400rpm<br />
連接埠:USB(3.0) x2、USB(2.0) x2、 mini-Display port、D-sub、RJ45、四合一讀卡機 (MMC, SD, SDHC, SDXC)、耳機插孔、電源輸入<br />
通訊:802.11 b/g/n、Bluetooth<br />
重量:2.4kg<br />
<br />
<h3>
<span style="font-size: x-large;">開箱</span></h3>
<br />
與 X7 v2 相比,這次箱子小多了,小到讓人懷疑裡頭到底有沒有筆電。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQrOrTnr9SoQ8AaF7SYX-JewEcn3ibengdYF5kNZoaa2yBta8xvcfESuydgtb5n1Qnkf7sShBfa99SGoqktdVhZfRNhGgHMTUDmmnRrtgq4yVvN2fLjivnDHwgw2eM_7EW3KCHulZntxf3/s1600/IMG_20140720_165803.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQrOrTnr9SoQ8AaF7SYX-JewEcn3ibengdYF5kNZoaa2yBta8xvcfESuydgtb5n1Qnkf7sShBfa99SGoqktdVhZfRNhGgHMTUDmmnRrtgq4yVvN2fLjivnDHwgw2eM_7EW3KCHulZntxf3/s1600/IMG_20140720_165803.jpg" height="360" width="640" /></a></div>
<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/AVvXsEgAz_3pX3gnTioo7FM74peFKFkOGdBX4t1WxlDm92QCtJg_mzBg5sRNRphFxJ43QWdOXqrGdtyRXzv93fA_XVpZcYTl99b3gwo_SOSXexoOLSQINJCHZRqxAOEnS1SDJ2S8et6rWD3wwcBL/s1600/IMG_20140720_165821.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAz_3pX3gnTioo7FM74peFKFkOGdBX4t1WxlDm92QCtJg_mzBg5sRNRphFxJ43QWdOXqrGdtyRXzv93fA_XVpZcYTl99b3gwo_SOSXexoOLSQINJCHZRqxAOEnS1SDJ2S8et6rWD3wwcBL/s1600/IMG_20140720_165821.jpg" height="360" 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/AVvXsEhcd4cLT5fBBAECCbscfRQTCyCoBVN9A2HTE6R_JCfomuRcTNET1b6xse00jRFijoSG4G6uW9xWBA-796u8Cf5DXJcIK4kD0XZqQ593vXlezXgtkmoeTojCNX1ZlcoP1e5pQr4EGOJBJMb8/s1600/IMG_20140722_215818.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcd4cLT5fBBAECCbscfRQTCyCoBVN9A2HTE6R_JCfomuRcTNET1b6xse00jRFijoSG4G6uW9xWBA-796u8Cf5DXJcIK4kD0XZqQ593vXlezXgtkmoeTojCNX1ZlcoP1e5pQr4EGOJBJMb8/s1600/IMG_20140722_215818.jpg" height="360" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeQ2vnv4g2ciHEeycMywioeN8YPpIuIlKNaNojaiKMG7eg1zpAGV_gWj020G2JXPwTWfkpiEIAQSvzwaxC9aX5wg4AZSC-5whB6PFqWjWuvygRrPyH74WWrmdRxCgkSF4-1DxqufyGsqcy/s1600/IMG_20140722_215842.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeQ2vnv4g2ciHEeycMywioeN8YPpIuIlKNaNojaiKMG7eg1zpAGV_gWj020G2JXPwTWfkpiEIAQSvzwaxC9aX5wg4AZSC-5whB6PFqWjWuvygRrPyH74WWrmdRxCgkSF4-1DxqufyGsqcy/s1600/IMG_20140722_215842.jpg" height="360" width="640" /></a></div>
<br />
<h3>
<span style="font-size: x-large;">改裝</span></h3>
開箱省略了這麼多就是要趕快進入重點。加裝 RAM 應該是很一般,選擇的是金士頓的 Lenovo 相容記憶體,只剩空盒因為已經裝上去啦,這二張圖右上方的就是加裝的 RAM。這邊不得不再次提到 T540p 說明書的詳細程度,怎麼拆背蓋、插拔零件都寫得很清楚。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJJpbpKRbnn2P46bl0rWf18bAeRbc6GzZxxlXvoYoyHgbbwlCrvOwPgZDl6yy1b_PtqmU1kr6eFMtwRCgbKDMy9BHVa-6XK7PxX4-AEAA-GVSoIllu2M_eQfSYJEXpOoCW53XdLKKjwHrm/s1600/IMG_20140720_170047.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJJpbpKRbnn2P46bl0rWf18bAeRbc6GzZxxlXvoYoyHgbbwlCrvOwPgZDl6yy1b_PtqmU1kr6eFMtwRCgbKDMy9BHVa-6XK7PxX4-AEAA-GVSoIllu2M_eQfSYJEXpOoCW53XdLKKjwHrm/s1600/IMG_20140720_170047.jpg" height="360" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2jrSH7ihIN7gWdRqiHTVoJlgNQa4YWjTKfy3g9tOZJgJhf0DK6Wc8xndTuLe-lO1Yk6lSc8J-kLeTRuaduh252u8KTPUta48KDe7geDkKOiUuGQD-TCj-dJGyDPkdN1rfv5TF2PPtl2vB/s1600/IMG_20140722_215950.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2jrSH7ihIN7gWdRqiHTVoJlgNQa4YWjTKfy3g9tOZJgJhf0DK6Wc8xndTuLe-lO1Yk6lSc8J-kLeTRuaduh252u8KTPUta48KDe7geDkKOiUuGQD-TCj-dJGyDPkdN1rfv5TF2PPtl2vB/s1600/IMG_20140722_215950.jpg" height="360" width="640" /></a></div>
<br />
接下來準備將光碟機換成硬碟,這邊需要硬碟托架,原本想要買<a href="http://shop.lenovo.com/us/en/itemdetails/0B47315/460/FDCD14101F7E452CBBA91660EB85C922" target="_blank">原廠</a>的,不過看起來不只是貴,還被批評的一文不值。於是搜尋之後決定在對岸天貓購買 <a href="http://detail.tmall.com/item.htm?spm=a1z10.1.w4004-5559141963.5.QV23a9&id=36274161934" target="_blank">JEYI H4</a>,介紹上是寫得很漂亮,不過實際上究竟如何呢?初步看起來外觀真的還不錯,也附了齊全的配件。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfU0WPiu13jgNQBW4NORgEQLOTV9PiPVA6xsapKobDLqlQ-SvRhg66x7k9RFYEdYwdAfkQPnLlraOvjB1nbMvZIb-_3wCcC3QV5GtToZEIv-ZrMRKCKPX2khIkKvIyv7vQbFIcH155kWS2/s1600/IMG_20140720_170108.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfU0WPiu13jgNQBW4NORgEQLOTV9PiPVA6xsapKobDLqlQ-SvRhg66x7k9RFYEdYwdAfkQPnLlraOvjB1nbMvZIb-_3wCcC3QV5GtToZEIv-ZrMRKCKPX2khIkKvIyv7vQbFIcH155kWS2/s1600/IMG_20140720_170108.jpg" height="360" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJqCaJs6fzTG0-fhXbDtHw9U9JlllnxoqvHC_Asp8oC3h4H1d6AD1mT6F76lhlXZVA4AYzMfr7PvMRwHgFO4xdF1FEJrRwJYpjrzq2Z1hWqkAEF9RUwAleERL6gxk0ucEhDNd9IGF_C9Ml/s1600/IMG_20140720_170122.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhJqCaJs6fzTG0-fhXbDtHw9U9JlllnxoqvHC_Asp8oC3h4H1d6AD1mT6F76lhlXZVA4AYzMfr7PvMRwHgFO4xdF1FEJrRwJYpjrzq2Z1hWqkAEF9RUwAleERL6gxk0ucEhDNd9IGF_C9Ml/s1600/IMG_20140720_170122.jpg" height="360" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgViH5z4TuYhntjxv9TVK4xg88emKnlurD4Zw_dHKABBb6bpKane05yxJpzDt_OlCGMrgbIlaSejuxdgYLVqNyOvhTwKGWctbo6bPwTQ1hJ4HYWSCBv4y20wnopICc-tbX-a_ChKzfYPm7o/s1600/IMG_20140720_170211.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgViH5z4TuYhntjxv9TVK4xg88emKnlurD4Zw_dHKABBb6bpKane05yxJpzDt_OlCGMrgbIlaSejuxdgYLVqNyOvhTwKGWctbo6bPwTQ1hJ4HYWSCBv4y20wnopICc-tbX-a_ChKzfYPm7o/s1600/IMG_20140720_170211.jpg" height="360" width="640" /></a></div>
<br />
然後是要換上的硬碟 WD Black2 (120GB SSD + 1TB HDD),但其實 SSD 部份的效能測起來並不是很好,只是五年保固還蠻吸引人的,應該是對品質有一定的自信。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8wkQkBFjFTDPYWHv-P5lEISrYn3Y6IhXGndNKKeZRcMN4N3sKezVxZ999-7lImNVbrlzDFjv0mKnZYnAxHvxwewp_WdTcit2iPiMG-vZfPYs6KyrHMoJ12BMaFkmXd_Gb5ERBNYUSVdEP/s1600/IMG_20140722_214159.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8wkQkBFjFTDPYWHv-P5lEISrYn3Y6IhXGndNKKeZRcMN4N3sKezVxZ999-7lImNVbrlzDFjv0mKnZYnAxHvxwewp_WdTcit2iPiMG-vZfPYs6KyrHMoJ12BMaFkmXd_Gb5ERBNYUSVdEP/s1600/IMG_20140722_214159.jpg" height="360" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHr3YGoh-NKiK4vYm-WM8WhsHH2fLmgWEA2HTh2Os6_kC_XyrDPoYR0iGPZrP30Y5j492uxtFjhu5nPcyTnCl57xVZxFkRm0B07oCeCDDyASAHVJMT6bHgWNRHfUFQb3eJShFc7BTfJy2m/s1600/IMG_20140722_214822.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHr3YGoh-NKiK4vYm-WM8WhsHH2fLmgWEA2HTh2Os6_kC_XyrDPoYR0iGPZrP30Y5j492uxtFjhu5nPcyTnCl57xVZxFkRm0B07oCeCDDyASAHVJMT6bHgWNRHfUFQb3eJShFc7BTfJy2m/s1600/IMG_20140722_214822.jpg" height="360" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLKFAriMQ1jSqt6zoUtaAymCmlCQPBJARvlJlVA2_A1mD_p45oIymio-H9PWvlgvKoEvwsEQWvZNcjOlstC2KAxtSo71UUJ5HMgUDSG89aJuOXVzZlli09scd35WaXQj361HZpib_VUlDD/s1600/IMG_20140722_215001.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLKFAriMQ1jSqt6zoUtaAymCmlCQPBJARvlJlVA2_A1mD_p45oIymio-H9PWvlgvKoEvwsEQWvZNcjOlstC2KAxtSo71UUJ5HMgUDSG89aJuOXVzZlli09scd35WaXQj361HZpib_VUlDD/s1600/IMG_20140722_215001.jpg" height="360" width="640" /></a></div>
<br />
然後就是合體啦~將 H4 隨附的矽膠螺絲裝到 Black2 上,接著將 Black2 裝進 H4,最後塞進固定用的矽膠墊片就大功告成了,固定的效果的確還不錯。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKflMYN9iUZ0VrIPNsE9B7UWqWGqGiLmck2w4eohJIEUZsQVTwpCMeu-SFjVNwvOrYiW0KTlQ_FMLD7Vgvp3KrRmp9xPGaz1JM4votfVOXa2IRHjKJI0jmi1daLsvGGdvfH4MIBjdEMduQ/s1600/IMG_20140722_215620.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhKflMYN9iUZ0VrIPNsE9B7UWqWGqGiLmck2w4eohJIEUZsQVTwpCMeu-SFjVNwvOrYiW0KTlQ_FMLD7Vgvp3KrRmp9xPGaz1JM4votfVOXa2IRHjKJI0jmi1daLsvGGdvfH4MIBjdEMduQ/s1600/IMG_20140722_215620.jpg" height="360" width="640" /></a></div>
<br />
依說明書指示將光碟機固定螺絲鬆開,把光碟機頂出來,可以看到光碟機是 Panasonic 的。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0PuS9WqBmsDjEXuihyphenhyphenTnz709YHxwQP_dUJW5VILZsJPI4ILogKA2dPp9mC_XZacHfwR7t1spxeJbLX5ZQ4dsWYH1yFnsp9XlEluE7WQircXB9Y3XWgt2t8M6ptoMhhxOwqqUQza8M0aw0/s1600/IMG_20140722_220040.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0PuS9WqBmsDjEXuihyphenhyphenTnz709YHxwQP_dUJW5VILZsJPI4ILogKA2dPp9mC_XZacHfwR7t1spxeJbLX5ZQ4dsWYH1yFnsp9XlEluE7WQircXB9Y3XWgt2t8M6ptoMhhxOwqqUQza8M0aw0/s1600/IMG_20140722_220040.jpg" height="360" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0Dk9wTY2W-29aRkxsXozkLU8JXj3NT_n-8RDq7hQXJJi6OtDXOuNq1W3fJkegXykS1RtIfUKUAFVggmacty1iq0MH5flpfq63VWr40XgqkVEDmFYITgN3SZXkmiCYgSshSrhRC9R0YRrO/s1600/IMG_20140722_220058.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0Dk9wTY2W-29aRkxsXozkLU8JXj3NT_n-8RDq7hQXJJi6OtDXOuNq1W3fJkegXykS1RtIfUKUAFVggmacty1iq0MH5flpfq63VWr40XgqkVEDmFYITgN3SZXkmiCYgSshSrhRC9R0YRrO/s1600/IMG_20140722_220058.jpg" height="360" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzHyuCXqM01Y5Ged4NmmFTQXx7oOv70jgCflCpcMG8Yj0D6yMz5WRNNZoQdBOBeZmEKAywBVgx622s-Gr-p4e_NlfsPhDR0Fj_ajmBfOJYsnl8SD8y2LkzNQf4azuNbLceEqtbSoGefyz7/s1600/IMG_20140722_220131.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzHyuCXqM01Y5Ged4NmmFTQXx7oOv70jgCflCpcMG8Yj0D6yMz5WRNNZoQdBOBeZmEKAywBVgx622s-Gr-p4e_NlfsPhDR0Fj_ajmBfOJYsnl8SD8y2LkzNQf4azuNbLceEqtbSoGefyz7/s1600/IMG_20140722_220131.jpg" height="360" width="640" /></a></div>
<br />
最後把裝著 Black2 的 H4 塞進去,然後呢,就可以發現並沒有文案寫得這麼美好。除了交接處可以看到明顯的落差,也固定只有綠色燈號,沒有讀取/寫入指示,最糟糕的是號稱土豪金的尾翼,鎖不上原本的螺絲孔,只能靠 H4 兩側的彈簧片固定,實在是有點糟糕...<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjugICHt4tBIFt-vZSN2qfLCjVVgyaBkFminsm2C1fFF4sstXcZmqQpD6sO10ftqsbLWuBIu3FwKCdkdp3QYxuLTujQRSpGHZVznAXN1OvffnVJ8nwsXI2PJt7gEMfG6ds2zUGW5DRwJynH/s1600/IMG_20140722_220850.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjugICHt4tBIFt-vZSN2qfLCjVVgyaBkFminsm2C1fFF4sstXcZmqQpD6sO10ftqsbLWuBIu3FwKCdkdp3QYxuLTujQRSpGHZVznAXN1OvffnVJ8nwsXI2PJt7gEMfG6ds2zUGW5DRwJynH/s1600/IMG_20140722_220850.jpg" height="360" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEvF8qpria2X5eiHk6fiuNdO6efOwQInD-5NO83RxuM7XTN6WRZkWf_Jfm9Yqq0CT6d7eGTUitbrgo86EYDpgcNBTYLtm5cHuaTbSDhAgPBv7XglwlCSE6x-Rc5tHlsgK-VXe2SRdskPPB/s1600/IMG_20140722_224201.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEvF8qpria2X5eiHk6fiuNdO6efOwQInD-5NO83RxuM7XTN6WRZkWf_Jfm9Yqq0CT6d7eGTUitbrgo86EYDpgcNBTYLtm5cHuaTbSDhAgPBv7XglwlCSE6x-Rc5tHlsgK-VXe2SRdskPPB/s1600/IMG_20140722_224201.jpg" height="360" width="640" /></a></div>
<br />
<h3>
<span style="font-size: x-large;">結語</span></h3>
整體而言 T540p 的表現還算讓人滿意,只是硬碟托架在臺灣找到的好像普遍只有通用款,而在中國買專用款除了較為麻煩,品質不穩定如果有瑕疵也難以處理,目前似乎還沒有最佳解...另外就是要注意一下 Black2 不太適合拿來安裝原本 T540p 的還原光碟,一不小心就會把原本的兩個分割合併成一個,建議直接自行安裝作業系統可能會比較理想,不然可能會像筆者一樣重灌系統灌了一整天,只好到了半夜還在趕稿...<br />
<br />
補充說明:<br />
1. 主機中的 16GB mSATA SSD 本來覺得很雞肋,原來說明書中有提到是用於暫存資料,主要是為了 Intel Rapid Start,所以不建議換裝比較大的 SSD 然後把作業系統安裝在這邊,不然會沒有保固。<br />
2. 如果要在雙硬碟實現 Windows + Ubuntu 雙系統,建議步驟是<br />
(1) 先只插要安裝 Windows 的硬碟,安裝或還原 Windows<br />
(2) 將另一個要安裝 Ubuntu 的硬碟裝上<br />
(3) 到 BIOS 把這個新裝上硬碟的開機優先設定比原本的還高<br />
(4) 安裝 Ubuntu<br />
之後就可以由 Ubuntu 的 GRUB 去選要開機進那一個系統。<br />
3. 不過依上面的步驟安裝 Windows 8.1 + Ubuntu,可能會因為 Windows 8.1 的 security boot 限制導致無法開機進 Windows,這時可能會需要修復 bootloader,可以參考 <a href="https://help.ubuntu.com/community/Boot-Repair" target="_blank">Boot-Repair</a> 或 <a href="http://www.rodsbooks.com/refind/" target="_blank">rEFInd</a>,建議先試試 Boot-Repair,筆者試了 rEFInd 確定是可以修復,但是安裝容易移除難,即使重灌系統之後不需要 rEFInd 了,但還是存在 BIOS 開機順序選單中,要另外找方法移除。Kaimhttp://www.blogger.com/profile/07884848500379844161noreply@blogger.com1tag:blogger.com,1999:blog-1053927668006720431.post-5458597787554631932014-07-21T15:16:00.001+08:002014-07-21T15:18:03.394+08:00桌遊簡易開箱文- 禁制的沙漠<h3 id="禁制的沙漠">禁制的沙漠</h3>
<p>新遊戲到貨囉~ 桌遊社每兩個月要補充一次遊戲真的是一件還蠻麻煩的事情(挑選遊戲很困難), 由於社團都還沒有這類型的合作遊戲, 這次就想說來買一下合作類型的遊戲, 當然一開始會考慮是不是要購買Forbidden Island, 不過在查了之後就發現原來同一作者有新作品, 而且機制比原先的更多樣化, 既然這樣那當然就是直接購買這款Forbidden Desert了。 <br>
既然叫Desert,場景當然是沙漠囉, 我們可以從盒子看出美工似乎畫的還蠻好看的, 而且是鐵盒不容易壓壞, 價位也不貴, 才7xx元而已~ 順便打個廣告, 我們跟小古買桌遊目前是打九折, 如果你住台南的可以找我們社團幫忙購買遊戲再面交哦~ :P <br>
<a name='more'></a>
<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimGZfwX2srUFIHvvXipuJ4DuRCNicbGzVKF8I2bed1iSh8xcOKfVcsD2yPhyEQKVhebA9lFly_O0Vd2e_hHayIgMeN2OLlgzKnJfWri_GypFTxQTky6Lz-xkik2i7x27c7sE4nJ8aVYvo/s500/IMAG1218.jpg" alt="enter image description here" title="IMAG1218.jpg"></p>
<p>開啟鐵蓋, 馬上就看到了英文說明書及廣告, 直接丟一旁就好了, 想當然出了一陣子的遊戲一定有好心人幫忙翻中文翻譯, 要開遊戲前再來查一下規則就好了, 感謝BoardGame Geek(稱讚的意味)讓我們快速上手遊戲~~ :D <br>
<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2KWpTqnfQp1mzccIE1gXNXIaKrg4Kd2gCdRQg_p1h8jKJ3OjyOm7gLchfkjO9BMLg_YN2hoiKmnSYSdM_HVPDiNXhFA0XYE-F6_OdxItxXiLxi_X_zjxQF-tkvbtHpK7M-lS4ICRsf_4/s500/" alt="enter image description here" title="IMAG1219.jpg"></p>
<p>遊戲設置大概就如下圖這樣, 我們扮演著飛機失事受困在沙漠中的一行人(<del>準備去打Boss 迪奧</del>) <br>
中間的空間是風暴中心, 每過一回合就會吹起風沙將大家給淹沒在沙堆中。 <br>
<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj64ce2kpo_Ds63CviZ3snMZB2vmtgjVbzQLRuwkDhvVlHcDg51FQH7YHKIRqr_8SlSVHKnkGhKm6ikQI9NZscj2Na4l5pyWBiPysosnRANQFKG_2C6AmbHR_X_Yzoyg5kqfdJJ2KCaUsQ/s500/IMAG1220.jpg" alt="enter image description here" title="IMAG1220.jpg"></p>
<p>為了要逃離這個恐怖的沙漠, 我們需要在消漠中找尋各種道具來幫助我們逃脫, 除了下面六樣輔助道具(手牌)之外, 另外就是4樣飛行船零件需要收集, 道具卡下面三張為每個人每回合都會抽取的風暴卡, 分別為烈陽高照-讓所有人的水下降一格,版塊移動-移動版塊並且堆起一層沙子,風暴來襲-暴風指數上升一格,下回合要抽的風暴卡可能又變多了。 <br>
<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPibb5M0amPG5lZxL8F9GYWBNFF9aYL5RoykHrz5fp4zaHvfluFfhkfRdSXSuF6TQBlFj8xqysQSbxazqgB-XtEJYYLZevhBPmPEXLj5LsUWRr5Iizb7-CxUD6M_F_M1nh8U7B_HDJ338/s500/IMAG1221.jpg" alt="enter image description here" title="IMAG1221.jpg"></p>
<p>這個遊戲也提供了職業的機制, 有六個職業隨機讓大家抽取, 每個職業的能力都不同, 也都相當實用, 如何善加利用各項能力就成了攻略此遊戲的一大重點了。</p>
<p><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2EgLfdYQCdvbimyGD1nP5DHdJEQsuNQTXVpHIyRpwuy47ZTmOoHwVwOTogNAsSbonzrWkjIuDM4XkbmDG9VrooPdArUEql0aeKNqhsm2rWyYyfUg6zDgzWLrjON0Jqg30vG5NnTiYt6c/s500/IMAG1223.jpg" alt="enter image description here" title="IMAG1223.jpg"></p>
<p>遊戲合作的目標就是要挖到四樣重要的飛行船道具, 並且在所有人都渴死之前到達停機坪上, 利用飛行船逃離這個恐怖的沙漠。 <br>
<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxrGy4nFLKsnBZPWRCmlDUoQdoneNITwSQ29XyGqSDAl53XLebaFLg2f_iL9gaV8dSLycAGdK75MwHDe2UyJXHO2I2QXYvGt3VGymg3V2WsDGXLTB98x-cyd1R4_v49OUaoZwV7o4gpcg/s500/IMAG1222.jpg" alt="enter image description here" title="IMAG1222.jpg"></p><div class="se-section-delimiter"></div>
<h3 id="試玩心得">試玩心得</h3>
<p>在可可屋試跑了兩次, 感覺是個輕鬆的合作型遊戲, 當然需要大家合作討論如何走下一步比較好, 交換道具及水也非常重要, 遊戲中只有兩個位置可以挖到水源補充水份, 但是每回合抽2+風暴卡真的讓人很傷, 如果沒有好好規劃躲在通道減少水份喪失或是要趕緊挖沙拿取提示及道具卡, 就會很容易讓大家變成這個沙漠中的一副骷髏, 結果在可可屋試玩的兩次, 一次因為有人說不會那麼衰抽到Sun Beats Down, 硬是要去挖沙, 結果就渴死了 XD <br>
另一次風暴指數上升超快, 雖然收集了兩樣道具, 但是還是在風暴下成了一具屍骨, 我們還是玩最低難度的啊~~~ 結果連一次都沒贏過 XD <br>
不過這樣表示不會只玩過一次就把遊戲收起來, 應該還算不錯啦。結論就是這是一款輕鬆的小遊戲, 如果玩了中重度遊戲累了可以改玩禁忌的沙漠來調適一下也是相當不錯的哦~</p>Anonymoushttp://www.blogger.com/profile/17715762577846106669noreply@blogger.com0tag:blogger.com,1999:blog-1053927668006720431.post-41241029326843016402014-07-20T11:40:00.000+08:002014-07-20T11:44:45.608+08:00簡單的開箱與迅速的關箱 - AORUS X7 v2最近因為工作上的需要 (沒錯,是「工作」,絕對不是為了玩遊戲),計畫購入一台筆電,需求的點為 CPU i7 四核、RAM 16GB,以及硬碟要盡量大,結果發現目前符合這個規格的大部分都是主打電競的系列。在購物網站比較許久之後,原本第一目標是 GIGABYTE 的 P34G v2 (不考慮 msi GS60 是因為上蓋那寫著 GAMING SERIES 的龍魂標誌對我來說好像有點太過顯眼),但是到論壇上做做功課發現好像不管是 GIGABYTE 或 msi,大小問題都不少,甚至要成立專門的問題回報版面,於是居然開始打起 AORUS 的主意。<br />
<br />
AORUS 其實是 GIGABYTE 專推電競的副品牌,但國內論壇好像較少問題回報,雖然知道可能純粹是因為銷量不大,不過心裡想說這麼貴的價格,而且是 Made in Taiwan,總該有對應的品質與品管吧,牙一咬就還是衝了...<br />
<br />
<a name='more'></a><h3>
<span style="font-size: x-large;">
規格</span> (<a href="http://www.aorus.com/x7.aspx" target="_blank">官網</a>)</h3>
<b><br /></b>
處理器:Intel® Core™ i7-4860HQ (2.4GHz-3.6GHz)<br />
記憶體:16GB DDR3L 1866, 4 個插槽 (最大 32GB)<br />
顯示卡:NVIDIA® GeForce® GTX 860M GDDR5 8GB 雙獨立顯示晶片<br />
顯示器:17.3" Full HD 1920x1080<br />
儲存裝置:mSATA SSD 128GB x3 + SATA3 HDD 1TB 7200rpm<br />
連接埠:USB(3.0) x3、USB(2.0) x2、 HDMI、mini-Display port、Surround port、D-sub、RJ45、SD 讀卡機、麥克風插孔、耳機插孔(SPDIF)、電源輸入<br />
通訊:Killer 網路晶片、802.11ac、Bluetooth V4.0<br />
重量:3kg<br />
<br />
可以看到除了高階的規格,輸入、輸出與通訊介面也都一應俱全。<br />
<br />
<h3>
<span style="font-size: x-large;">開箱</span></h3>
<br />
送來時一整箱非常的巨大,打開前還一直猜測到底裡面塞了什麼,原來除了筆電之外,還送了原廠的背包,原本訂購時並沒提到會送背包,所以當下還蠻開心的。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNuXEEtGncZsD55e_Zakr2x4JhveMmPWNsab3cyFVE-LTdpWyfky3v-Sg7a_mwkjDK6KK5f1XNRzBb3iqJf0QJb0scZILMqutDTcOGVP1zlRyuxgB-KQp_d7D7_zAdtpAy3uXaiEze8dtI/s1600/IMG_20140711_190905.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNuXEEtGncZsD55e_Zakr2x4JhveMmPWNsab3cyFVE-LTdpWyfky3v-Sg7a_mwkjDK6KK5f1XNRzBb3iqJf0QJb0scZILMqutDTcOGVP1zlRyuxgB-KQp_d7D7_zAdtpAy3uXaiEze8dtI/s1600/IMG_20140711_190905.jpg" height="360" width="640" /></a></div>
<br />
不過接著馬上發現筆電外箱有拆封過的痕跡,心裡開始疑惑究竟怎麼一回事,畢竟網路購物多少會擔心拿到退貨商品。圖裡可以也可以看到原廠標籤的規格標示。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv0kpORnxReOPzLQaNoC3-WcRS1IJFk_tvXtw3A5zCUGjtkO8CVEdocBHLsGJEqvuxcXsY8L4w0H0Y_hRAA8NF5EbsL10zvH5TJO4v3rFSqHPGZjdHCRWlEEgvbx6m-yUl4kJA65UNZuYE/s1600/IMG_20140711_190934.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjv0kpORnxReOPzLQaNoC3-WcRS1IJFk_tvXtw3A5zCUGjtkO8CVEdocBHLsGJEqvuxcXsY8L4w0H0Y_hRAA8NF5EbsL10zvH5TJO4v3rFSqHPGZjdHCRWlEEgvbx6m-yUl4kJA65UNZuYE/s1600/IMG_20140711_190934.jpg" height="360" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_oqZZOlSTxbe0DB7rfnPSBpu9aKoBtMQlAGOoTAits7TtpJSWwYKRTUvLfxfEEGAkNJEqeF7zFAnRURoDUvjpAVSaH1stxzXvcHO3Lwxc-Y5kfgyw81JvlcJyKWSoRHN-S3IDtc7eQbpF/s1600/IMG_20140711_190951.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_oqZZOlSTxbe0DB7rfnPSBpu9aKoBtMQlAGOoTAits7TtpJSWwYKRTUvLfxfEEGAkNJEqeF7zFAnRURoDUvjpAVSaH1stxzXvcHO3Lwxc-Y5kfgyw81JvlcJyKWSoRHN-S3IDtc7eQbpF/s1600/IMG_20140711_190951.jpg" height="640" width="360" /></a></div>
<br />
猶豫許久後來還是決定拆了,原來裡面還有另一個較小的紙箱,而且開口處有貼紙封條表明全新未拆封。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCTIzX59mwWsc5i1wfwpFf60ultPsiUjiB372YVy0YLR4CW0NpDAo_LnplFT9AburJHo0dVPETvEB924WUTr8vhmuln0pehnGeCpafvs_pYqUkYlsYvOTRUu7MBSkjZ63KDZI5Q8XD1VzB/s1600/IMG_20140711_223859.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCTIzX59mwWsc5i1wfwpFf60ultPsiUjiB372YVy0YLR4CW0NpDAo_LnplFT9AburJHo0dVPETvEB924WUTr8vhmuln0pehnGeCpafvs_pYqUkYlsYvOTRUu7MBSkjZ63KDZI5Q8XD1VzB/s1600/IMG_20140711_223859.jpg" height="360" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXii2Hq-ZNIPk0D2BSiTcEsMRS_31x-fYx7qX4PJfaE9ykDr7VONJVIZ_kfcxOAtFDhNUJUHr1U-03LjQEvz8lsNdQmtzFAS3tFeAREdffHFuCwbbEpDF4Hmh4_kjOpKsbZnLBSxxpZsAX/s1600/IMG_20140711_223846.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXii2Hq-ZNIPk0D2BSiTcEsMRS_31x-fYx7qX4PJfaE9ykDr7VONJVIZ_kfcxOAtFDhNUJUHr1U-03LjQEvz8lsNdQmtzFAS3tFeAREdffHFuCwbbEpDF4Hmh4_kjOpKsbZnLBSxxpZsAX/s1600/IMG_20140711_223846.jpg" height="360" width="640" /></a></div>
<br />
打開這個紙箱之後,裡面是個精緻的盒子,有沒有需要包裝得這精美啊!不禁令我想起黑豹傳奇。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgar7wu5OO9MKXw5dO4TRHWO1jLSAkuLO_LgW92EzldRy_MfqbFkUAmTckrVxIuEh8xqR-Vpg9g0nee2EtSibmF76wPrSlIJoc06o1kGeDKLRqsK8xPh-U6pOmGKhHGmjIpPOwQYmukE63W/s1600/IMG_20140711_224027.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgar7wu5OO9MKXw5dO4TRHWO1jLSAkuLO_LgW92EzldRy_MfqbFkUAmTckrVxIuEh8xqR-Vpg9g0nee2EtSibmF76wPrSlIJoc06o1kGeDKLRqsK8xPh-U6pOmGKhHGmjIpPOwQYmukE63W/s1600/IMG_20140711_224027.jpg" height="360" width="640" /></a></div>
<br />
把盒子打開之後,總算看見本體,其實原本筆電外面是還有一層保護袋,不過沒拍到。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXpb3OewGDjnmLXeTWfTQtn3-Pwsq-Vdwn0BiroYOlqIj4D6moQ0aQUY-R3vntLFyaDbo-DJERTefBsZjE9Et3M6RHnobmn-hzGfQ0YXAkDg1gFlngDlZZ01eZVlfaEnPABtAznoE2RRfv/s1600/IMG_20140711_224218.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjXpb3OewGDjnmLXeTWfTQtn3-Pwsq-Vdwn0BiroYOlqIj4D6moQ0aQUY-R3vntLFyaDbo-DJERTefBsZjE9Et3M6RHnobmn-hzGfQ0YXAkDg1gFlngDlZZ01eZVlfaEnPABtAznoE2RRfv/s1600/IMG_20140711_224218.jpg" height="360" width="640" /></a></div>
<br />
將上蓋打開,可以看到有一層棉布鋪在鍵盤上,還放了一張小卡片,讓人覺得很用心。然後觸控板也相當特別有質感,有質感到不太想去用它...開箱到這邊會有雖然很貴,但好像還算值得的感覺。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwz8WmFHGG5u837VdPgvBts2Cz0Nhw7FkUfQceTd29I9FmBYlPzfHTcIozEJqq47lHEB6JffpiSJZx0WepH919Nj7RwA4rriVJ6ycWY51gJc9d8kKohJq-FY_JDxEDPGRCA18yI8cm2JAk/s1600/IMG_20140711_224301.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwz8WmFHGG5u837VdPgvBts2Cz0Nhw7FkUfQceTd29I9FmBYlPzfHTcIozEJqq47lHEB6JffpiSJZx0WepH919Nj7RwA4rriVJ6ycWY51gJc9d8kKohJq-FY_JDxEDPGRCA18yI8cm2JAk/s1600/IMG_20140711_224301.jpg" height="360" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7iRoJKcYL-IsLzzMsddUK5pzQlMB_spzEADKSk-5rti2lFTUb0Sn7DEzsxzcEnxLrZ9hLESyHQzx93pMnHt0AOa2akfrGLvozIAgW5D_4ZtHFJLJ738X8atSBFDxfuBc3nEgAOZfl-PvI/s1600/DSC01575.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7iRoJKcYL-IsLzzMsddUK5pzQlMB_spzEADKSk-5rti2lFTUb0Sn7DEzsxzcEnxLrZ9hLESyHQzx93pMnHt0AOa2akfrGLvozIAgW5D_4ZtHFJLJ738X8atSBFDxfuBc3nEgAOZfl-PvI/s1600/DSC01575.JPG" height="480" 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/AVvXsEhbWvJwptK6w8EwXFJpeMPkxRTifWd3gnl6dw-t0bml-5dbg2m5Zix8gv9ds4_yb8PZ4Xsj1kcv0nm1O9EwZ331D6htid0wPvJjA67ylvTRzxNds5ygQ2b2gatXfwF70ykGRqOJ3DXcx101/s1600/DSC01572.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbWvJwptK6w8EwXFJpeMPkxRTifWd3gnl6dw-t0bml-5dbg2m5Zix8gv9ds4_yb8PZ4Xsj1kcv0nm1O9EwZ331D6htid0wPvJjA67ylvTRzxNds5ygQ2b2gatXfwF70ykGRqOJ3DXcx101/s1600/DSC01572.JPG" height="480" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdZo8S3SqHRPJo_7V7K9FHcR4ssYx-owB1roK5_4zkvFHccjBxpuNqTPi3bJiGAsmfoLkPKToPhMPy40AZWDSIcgoGiE_cvqAVMV1ZMQvoMW63UAt9dbejVNR8YCxtl8Pgo3e5cnA_Kfjl/s1600/DSC01574.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdZo8S3SqHRPJo_7V7K9FHcR4ssYx-owB1roK5_4zkvFHccjBxpuNqTPi3bJiGAsmfoLkPKToPhMPy40AZWDSIcgoGiE_cvqAVMV1ZMQvoMW63UAt9dbejVNR8YCxtl8Pgo3e5cnA_Kfjl/s1600/DSC01574.JPG" height="480" width="640" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivu9w9_pP3SpRJ0f1Mx_DN6rave5ZfbPCpXg2wQqiw8tE3pTostbdFdjwaqp2qWrBn-9pwBs4p7ff_fKYSQTQk5lkS8NlDJw8OIc3Yawi_W0ystp-ep0_Oj1YwSMcWmYUmtPzdD-H1B1CN/s1600/DSC01573.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivu9w9_pP3SpRJ0f1Mx_DN6rave5ZfbPCpXg2wQqiw8tE3pTostbdFdjwaqp2qWrBn-9pwBs4p7ff_fKYSQTQk5lkS8NlDJw8OIc3Yawi_W0ystp-ep0_Oj1YwSMcWmYUmtPzdD-H1B1CN/s1600/DSC01573.JPG" height="480" width="640" /></a></div>
<br />
於是我只好默默地關箱了。<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDzBElI6jvfawErutYJelaRIS_as2bDrpu5h8cN2XAYupKxcKGJU8Vy0q2P_eSL3c7x_fMCEiiEp1JFFXqjwwzllRI3ko9aHo25fycnLshZB1m8kG6BWCQXyevYbakQ36-oyk9e5d-TKld/s1600/DSC01579.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDzBElI6jvfawErutYJelaRIS_as2bDrpu5h8cN2XAYupKxcKGJU8Vy0q2P_eSL3c7x_fMCEiiEp1JFFXqjwwzllRI3ko9aHo25fycnLshZB1m8kG6BWCQXyevYbakQ36-oyk9e5d-TKld/s1600/DSC01579.JPG" height="480" width="640" /></a></div>
<br />
<h3>
<span style="font-size: x-large;">總結</span></h3>
因為只有短暫的開機進 Windows,所以並沒有太多的實際使用心得,整理如下。<br />
<br />
優點<br />
1. 以目前來說,規格可說是最頂級,而且記憶體和儲存裝置都還有擴充的可能性<br />
2. 金屬材質外殼相當有質感<br />
3. 比較同級對手,重量較輕,價格也沒比較貴<br />
4. 包裝精緻<br />
<br />
缺點<br />
1. 品管需要加強<br />
2. 經銷與展示點都少<br />
3. 以這規格來說免不了的就是重跟貴,尤其是重量,除了本體 3kg 之外,變壓器也相當龐大,重量幾近 1kg,攜帶上要有心裡準備Kaimhttp://www.blogger.com/profile/07884848500379844161noreply@blogger.com1tag:blogger.com,1999:blog-1053927668006720431.post-10334889883307794832014-07-19T08:00:00.003+08:002014-07-19T23:22:24.755+08:00輕鬆聊之Hierarchical Clustering<p>上一次我們介紹了<a href="http://35around.blogspot.tw/2014/07/k-means.html">K-means分群演算法</a>,今天來介紹另外一個分群(Clustering)演算法-Hierarchical Clustering,中文好像叫階層分群法。</p>
<p>一般Hierarchical Clustering有兩個方式來產生最後的樹狀結構, </p>
<ul>
<li>聚積(Agglomerative),Bottom-up</li>
<li>分裂(Divisive),Top-down </li>
</ul>
<p>今天介紹的是比較常用的bottom-up的方式,直接來看圖說故事吧。</p>
<a name='more'></a>
<p><img src="https://lh5.googleusercontent.com/dfVgkaSLAimEGrcdeOpoGMv68HdXZfXAYFZcxtMh_ko=s720" alt="flow" title="hc_flow.jpg"></p>
<blockquote>
<p><strong>圖片來源:</strong> <a href="http://online.stanford.edu/course/statistical-learning-winter-2014">Statistical Learning</a> (Stanford Online Course ) </p>
</blockquote>
<p>大概演算法流程如下, </p>
<ol>
<li><p>把每一個點都當成一個叢集(Cluster)</p></li>
<li><p>把最接近的兩個Cluster合併成一個</p></li>
<li><p>重複以上步驟</p></li>
<li><p>直到所有的點都已經合併成一個Cluster</p></li>
</ol>
<p>你可以發現Hierarchical Clustering最後可以表示成一個Tree。</p>
<p>有了樹(Tree )之後,我們就可以開始做砍樹的動作。ㄟ…好不容易把樹種起來了,為什麼要砍掉呢?因為我們的目的不是種樹,是要將資料分群啊。來看一下下面的圖就知道了,左圖是種出來的樹,如果我們在高度9的地方把樹砍掉(中圖),就會得到兩個Cluster。如果刀子從高度5下去(右圖),就會得到3個Culster。所以你要得到K個Culster就自己找下刀點吧。</p>
<p><img src="https://lh5.googleusercontent.com/Gb6adi8Yd16l-7oT8g4WpRiacH3e9V4VGhrXLBalzPc=s720" alt="cut" title="hc_cut.jpg"> </p>
<blockquote>
<p><strong>圖片來源:</strong> <a href="http://online.stanford.edu/course/statistical-learning-winter-2014">Statistical Learning</a> (Stanford Online Course ) </p>
</blockquote>
<p><br></p>
<p>我們在上面的演算法流程2的地方有說到把最近的兩個Cluster給合併起來,眼尖的人可能會發現,既然它是一個Culster的話,那我要怎麼計算兩個Culster的距離呢?大概有以下4個方法。</p>
<ol>
<li><p><strong>Complete</strong>-linkage: 取兩個Cluster中最遠的兩個點</p></li>
<li><p><strong>Single</strong>-linkage: 取兩個Cluster中最近的兩個點</p></li>
<li><p><strong>Average</strong>-linkage: 兩個Cluster之間各點距離總和的平均</p></li>
<li><p><strong>Centriod</strong>-linkage: 取各Cluster的中心點</p></li>
</ol>
<p>至於什麼樣的情況該選擇哪一個計算方式,這也是實際使用上需要克服的一個問題。怎麼測量”距離”(相近程度),也是實務上的一個挑戰。最後就是老問題,到底要切多少塊Culster,我的K應該選擇多少才合理,這個等我有心得後再跟大家分享囉。</p>misgodhttp://www.blogger.com/profile/00933441299043629398noreply@blogger.com0tag:blogger.com,1999:blog-1053927668006720431.post-88017983415385951212014-07-18T08:00:00.001+08:002014-07-18T12:23:04.498+08:00輕鬆聊之K-Means演算法<p>上次跟大家簡單介紹了一下<a href="http://35around.blogspot.tw/2014/07/knn.html">KNN演算法</a>,今天介紹一下很容易跟KNN搞混的K-means演算法,不過兩個其實差蠻多的,只有名字比較像而已。K-means主要講的就是<strong>「物以類聚</strong>」,只要中心思想是相近的,就可以歸在同一類。</p>
<p>K-means是一個<strong>分群(Clustering)</strong>的演算法,不需要有預先標記好的資料(<strong>unlabeled data</strong>),屬於<strong>非監督式學習(Unsupervised learning)</strong>。主要是用來做常常被使用在資料分群,簡單的說就是把一堆資料根據你判斷相近的邏輯,把這一堆資料分成k群。</p>
<a name='more'></a>
<p>用比較數學(<del>嚇人</del>)的說法就是,追求各個群組內部的均方誤差總和最小。</p><div class="se-section-delimiter"></div>
<p><span class="MathJax_Preview"></span><div class="MathJax_Display" role="textbox" aria-readonly="true" style="text-align: center;"><span class="MathJax" id="MathJax-Element-693-Frame"><nobr><span class="math" id="MathJax-Span-12323" style="width: 14.997em; display: inline-block;"><span style="display: inline-block; position: relative; width: 12.4em; height: 0px; font-size: 121%;"><span style="position: absolute; clip: rect(0.888em 1000.003em 4.371em -0.469em); top: -2.772em; left: 0.003em;"><span class="mrow" id="MathJax-Span-12324"><span class="mi" id="MathJax-Span-12325" style="font-family: MathJax_Math; font-style: italic;">a</span><span class="mi" id="MathJax-Span-12326" style="font-family: MathJax_Math; font-style: italic;">r</span><span class="mi" id="MathJax-Span-12327" style="font-family: MathJax_Math; font-style: italic;">g<span style="display: inline-block; overflow: hidden; height: 1px; width: 0.003em;"></span></span><span class="mi" id="MathJax-Span-12328" style="font-family: MathJax_Math; font-style: italic;">m</span><span class="mi" id="MathJax-Span-12329" style="font-family: MathJax_Math; font-style: italic;">i</span><span class="mi" id="MathJax-Span-12330" style="font-family: MathJax_Math; font-style: italic;">n</span><span class="munderover" id="MathJax-Span-12331" style="padding-left: 0.18em;"><span style="display: inline-block; position: relative; width: 1.479em; height: 0px;"><span style="position: absolute; clip: rect(2.659em 1000.003em 4.43em -0.469em); top: -3.775em; left: 0.003em;"><span class="mo" id="MathJax-Span-12332" style="font-family: MathJax_Size2; vertical-align: 0.003em;">∑</span><span style="display: inline-block; width: 0px; height: 3.781em;"></span></span><span style="position: absolute; clip: rect(1.656em 1000.003em 2.6em -0.528em); top: -1.237em; left: 0.18em;"><span class="texatom" id="MathJax-Span-12333"><span class="mrow" id="MathJax-Span-12334"><span class="mi" id="MathJax-Span-12335" style="font-size: 70.7%; font-family: MathJax_Math; font-style: italic;">i</span><span class="mo" id="MathJax-Span-12336" style="font-size: 70.7%; font-family: MathJax_Main;">=</span><span class="mn" id="MathJax-Span-12337" style="font-size: 70.7%; font-family: MathJax_Main;">1</span></span></span><span style="display: inline-block; width: 0px; height: 2.305em;"></span></span><span style="position: absolute; clip: rect(1.479em 1000.003em 2.423em -0.469em); top: -3.362em; left: 0.593em;"><span class="texatom" id="MathJax-Span-12338"><span class="mrow" id="MathJax-Span-12339"><span class="mi" id="MathJax-Span-12340" style="font-size: 70.7%; font-family: MathJax_Math; font-style: italic;">k</span></span></span><span style="display: inline-block; width: 0px; height: 2.246em;"></span></span></span></span><span class="munderover" id="MathJax-Span-12341" style="padding-left: 0.18em;"><span style="display: inline-block; position: relative; width: 2.069em; height: 0px;"><span style="position: absolute; clip: rect(2.659em 1000.003em 4.43em -0.469em); top: -3.775em; left: 0.298em;"><span class="mo" id="MathJax-Span-12342" style="font-family: MathJax_Size2; vertical-align: 0.003em;">∑</span><span style="display: inline-block; width: 0px; height: 3.781em;"></span></span><span style="position: absolute; clip: rect(1.656em 1000.003em 2.777em -0.528em); top: -1.178em; left: 0.003em;"><span class="texatom" id="MathJax-Span-12343"><span class="mrow" id="MathJax-Span-12344"><span class="msubsup" id="MathJax-Span-12345"><span style="display: inline-block; position: relative; width: 0.77em; height: 0px;"><span style="position: absolute; clip: rect(1.774em 1000.003em 2.423em -0.528em); top: -2.24em; left: 0.003em;"><span class="mi" id="MathJax-Span-12346" style="font-size: 70.7%; font-family: MathJax_Math; font-style: italic;">x</span><span style="display: inline-block; width: 0px; height: 2.246em;"></span></span><span style="position: absolute; top: -2.122em; left: 0.416em;"><span class="mi" id="MathJax-Span-12347" style="font-size: 50%; font-family: MathJax_Math; font-style: italic;">j</span><span style="display: inline-block; width: 0px; height: 2.246em;"></span></span></span></span><span class="mo" id="MathJax-Span-12348" style="font-size: 70.7%; font-family: MathJax_Main;">∈</span><span class="msubsup" id="MathJax-Span-12349"><span style="display: inline-block; position: relative; width: 0.77em; height: 0px;"><span style="position: absolute; clip: rect(1.597em 1000.003em 2.423em -0.469em); top: -2.24em; left: 0.003em;"><span class="mi" id="MathJax-Span-12350" style="font-size: 70.7%; font-family: MathJax_Math; font-style: italic;">S<span style="display: inline-block; overflow: hidden; height: 1px; width: 0.003em;"></span></span><span style="display: inline-block; width: 0px; height: 2.246em;"></span></span><span style="position: absolute; top: -2.122em; left: 0.475em;"><span class="mi" id="MathJax-Span-12351" style="font-size: 50%; font-family: MathJax_Math; font-style: italic;">i</span><span style="display: inline-block; width: 0px; height: 2.246em;"></span></span></span></span></span></span><span style="display: inline-block; width: 0px; height: 2.305em;"></span></span></span></span><span class="texatom" id="MathJax-Span-12352" style="padding-left: 0.18em;"><span class="mrow" id="MathJax-Span-12353"><span class="mo" id="MathJax-Span-12354" style="font-family: MathJax_Main;">|</span></span></span><span class="texatom" id="MathJax-Span-12355"><span class="mrow" id="MathJax-Span-12356"><span class="mo" id="MathJax-Span-12357" style="font-family: MathJax_Main;">|</span></span></span><span class="msubsup" id="MathJax-Span-12358"><span style="display: inline-block; position: relative; width: 1.243em; height: 0px;"><span style="position: absolute; clip: rect(1.656em 1000.003em 2.718em -0.528em); top: -2.535em; left: 0.003em;"><span class="mi" id="MathJax-Span-12359" style="font-family: MathJax_Math; font-style: italic;">X<span style="display: inline-block; overflow: hidden; height: 1px; width: 0.003em;"></span></span><span style="display: inline-block; width: 0px; height: 2.541em;"></span></span><span style="position: absolute; top: -2.063em; left: 0.888em;"><span class="mi" id="MathJax-Span-12360" style="font-size: 70.7%; font-family: MathJax_Math; font-style: italic;">j</span><span style="display: inline-block; width: 0px; height: 2.246em;"></span></span></span></span><span class="mo" id="MathJax-Span-12361" style="font-family: MathJax_Main; padding-left: 0.239em;">−</span><span class="msubsup" id="MathJax-Span-12362" style="padding-left: 0.239em;"><span style="display: inline-block; position: relative; width: 0.888em; height: 0px;"><span style="position: absolute; clip: rect(1.951em 1000.003em 2.955em -0.528em); top: -2.535em; left: 0.003em;"><span class="mi" id="MathJax-Span-12363" style="font-family: MathJax_Math; font-style: italic;">μ</span><span style="display: inline-block; width: 0px; height: 2.541em;"></span></span><span style="position: absolute; top: -2.004em; left: 0.593em;"><span class="mi" id="MathJax-Span-12364" style="font-size: 70.7%; font-family: MathJax_Math; font-style: italic;">i</span><span style="display: inline-block; width: 0px; height: 2.246em;"></span></span></span></span><span class="texatom" id="MathJax-Span-12365"><span class="mrow" id="MathJax-Span-12366"><span class="mo" id="MathJax-Span-12367" style="font-family: MathJax_Main;">|</span></span></span><span class="msubsup" id="MathJax-Span-12368"><span style="display: inline-block; position: relative; width: 0.711em; height: 0px;"><span style="position: absolute; clip: rect(1.833em 1000.003em 3.191em -0.41em); top: -2.772em; left: 0.003em;"><span class="texatom" id="MathJax-Span-12369"><span class="mrow" id="MathJax-Span-12370"><span class="mo" id="MathJax-Span-12371" style="font-family: MathJax_Main;">|</span></span></span><span style="display: inline-block; width: 0px; height: 2.777em;"></span></span><span style="position: absolute; top: -2.772em; left: 0.298em;"><span class="mn" id="MathJax-Span-12372" style="font-size: 70.7%; font-family: MathJax_Main;">2</span><span style="display: inline-block; width: 0px; height: 2.305em;"></span></span></span></span></span><span style="display: inline-block; width: 0px; height: 2.777em;"></span></span></span><span style="border-left-width: 0.004em; border-left-style: solid; display: inline-block; overflow: hidden; width: 0px; height: 4.004em; vertical-align: -1.782em;"></span></span></nobr></span></div><script type="math/tex; mode=display" id="MathJax-Element-693">
arg min \sum_{i=1}^{k}\sum_{x_j \in S_i}||X_j - \mu_i||^2
</script></p>
<p><span class="MathJax_Preview"></span><span class="MathJax" id="MathJax-Element-694-Frame" role="textbox" aria-readonly="true"><nobr><span class="math" id="MathJax-Span-12373" style="width: 17.004em; display: inline-block;"><span style="display: inline-block; position: relative; width: 14.053em; height: 0px; font-size: 121%;"><span style="position: absolute; clip: rect(1.774em 1000.003em 3.191em -0.41em); top: -2.772em; left: 0.003em;"><span class="mrow" id="MathJax-Span-12374"><span class="mo" id="MathJax-Span-12375" style="font-family: MathJax_Main;">(</span><span class="msubsup" id="MathJax-Span-12376"><span style="display: inline-block; position: relative; width: 1.006em; height: 0px;"><span style="position: absolute; clip: rect(1.951em 1000.003em 2.718em -0.469em); top: -2.535em; left: 0.003em;"><span class="mi" id="MathJax-Span-12377" style="font-family: MathJax_Math; font-style: italic;">x</span><span style="display: inline-block; width: 0px; height: 2.541em;"></span></span><span style="position: absolute; top: -2.122em; left: 0.593em;"><span class="mn" id="MathJax-Span-12378" style="font-size: 70.7%; font-family: MathJax_Main;">1</span><span style="display: inline-block; width: 0px; height: 2.305em;"></span></span></span></span><span class="mo" id="MathJax-Span-12379" style="font-family: MathJax_Main;">,</span><span class="msubsup" id="MathJax-Span-12380" style="padding-left: 0.18em;"><span style="display: inline-block; position: relative; width: 1.006em; height: 0px;"><span style="position: absolute; clip: rect(1.951em 1000.003em 2.718em -0.469em); top: -2.535em; left: 0.003em;"><span class="mi" id="MathJax-Span-12381" style="font-family: MathJax_Math; font-style: italic;">x</span><span style="display: inline-block; width: 0px; height: 2.541em;"></span></span><span style="position: absolute; top: -2.122em; left: 0.593em;"><span class="mn" id="MathJax-Span-12382" style="font-size: 70.7%; font-family: MathJax_Main;">2</span><span style="display: inline-block; width: 0px; height: 2.305em;"></span></span></span></span><span class="mo" id="MathJax-Span-12383" style="font-family: MathJax_Main;">,</span><span class="msubsup" id="MathJax-Span-12384" style="padding-left: 0.18em;"><span style="display: inline-block; position: relative; width: 1.006em; height: 0px;"><span style="position: absolute; clip: rect(1.951em 1000.003em 2.718em -0.469em); top: -2.535em; left: 0.003em;"><span class="mi" id="MathJax-Span-12385" style="font-family: MathJax_Math; font-style: italic;">x</span><span style="display: inline-block; width: 0px; height: 2.541em;"></span></span><span style="position: absolute; top: -2.122em; left: 0.593em;"><span class="mn" id="MathJax-Span-12386" style="font-size: 70.7%; font-family: MathJax_Main;">3</span><span style="display: inline-block; width: 0px; height: 2.305em;"></span></span></span></span><span class="mo" id="MathJax-Span-12387" style="font-family: MathJax_Main;">.</span><span class="mo" id="MathJax-Span-12388" style="font-family: MathJax_Main; padding-left: 0.18em;">.</span><span class="mo" id="MathJax-Span-12389" style="font-family: MathJax_Main; padding-left: 0.18em;">.</span><span class="mo" id="MathJax-Span-12390" style="font-family: MathJax_Main; padding-left: 0.18em;">,</span><span class="msubsup" id="MathJax-Span-12391" style="padding-left: 0.18em;"><span style="display: inline-block; position: relative; width: 1.066em; height: 0px;"><span style="position: absolute; clip: rect(1.951em 1000.003em 2.718em -0.469em); top: -2.535em; left: 0.003em;"><span class="mi" id="MathJax-Span-12392" style="font-family: MathJax_Math; font-style: italic;">x</span><span style="display: inline-block; width: 0px; height: 2.541em;"></span></span><span style="position: absolute; top: -2.063em; left: 0.593em;"><span class="mi" id="MathJax-Span-12393" style="font-size: 70.7%; font-family: MathJax_Math; font-style: italic;">n</span><span style="display: inline-block; width: 0px; height: 2.246em;"></span></span></span></span><span class="mo" id="MathJax-Span-12394" style="font-family: MathJax_Main;">)</span><span class="texatom" id="MathJax-Span-12395"><span class="mrow" id="MathJax-Span-12396"><span class="mo" id="MathJax-Span-12397"><span style="font-family: STIXGeneral, 'Arial Unicode MS', serif; font-size: 83%; font-style: normal; font-weight: normal;">為</span></span></span></span><span class="texatom" id="MathJax-Span-12398"><span class="mrow" id="MathJax-Span-12399"><span class="mo" id="MathJax-Span-12400"><span style="font-family: STIXGeneral, 'Arial Unicode MS', serif; font-size: 83%; font-style: normal; font-weight: normal;">給</span></span></span></span><span class="texatom" id="MathJax-Span-12401"><span class="mrow" id="MathJax-Span-12402"><span class="mo" id="MathJax-Span-12403"><span style="font-family: STIXGeneral, 'Arial Unicode MS', serif; font-size: 83%; font-style: normal; font-weight: normal;">定</span></span></span></span><span class="texatom" id="MathJax-Span-12404"><span class="mrow" id="MathJax-Span-12405"><span class="mo" id="MathJax-Span-12406"><span style="font-family: STIXGeneral, 'Arial Unicode MS', serif; font-size: 83%; font-style: normal; font-weight: normal;">的</span></span></span></span><span class="texatom" id="MathJax-Span-12407"><span class="mrow" id="MathJax-Span-12408"><span class="mo" id="MathJax-Span-12409"><span style="font-family: STIXGeneral, 'Arial Unicode MS', serif; font-size: 83%; font-style: normal; font-weight: normal;">資</span></span></span></span><span class="texatom" id="MathJax-Span-12410"><span class="mrow" id="MathJax-Span-12411"><span class="mo" id="MathJax-Span-12412"><span style="font-family: STIXGeneral, 'Arial Unicode MS', serif; font-size: 83%; font-style: normal; font-weight: normal;">料</span></span></span></span><span class="texatom" id="MathJax-Span-12413"><span class="mrow" id="MathJax-Span-12414"><span class="mo" id="MathJax-Span-12415"><span style="font-family: STIXGeneral, 'Arial Unicode MS', serif; font-size: 83%; font-style: normal; font-weight: normal;">集</span></span></span></span><span class="texatom" id="MathJax-Span-12416"><span class="mrow" id="MathJax-Span-12417"><span class="mo" id="MathJax-Span-12418"><span style="font-family: STIXGeneral, 'Arial Unicode MS', serif; font-size: 83%; font-style: normal; font-weight: normal;">合</span></span></span></span></span><span style="display: inline-block; width: 0px; height: 2.777em;"></span></span></span><span style="border-left-width: 0.004em; border-left-style: solid; display: inline-block; overflow: hidden; width: 0px; height: 1.432em; vertical-align: -0.354em;"></span></span></nobr></span><script type="math/tex" id="MathJax-Element-694">(x_1, x_2,x_3...,x_n)為給定的資料集合</script> </p>
<p><span class="MathJax_Preview"></span><span class="MathJax" id="MathJax-Element-695-Frame" role="textbox" aria-readonly="true"><nobr><span class="math" id="MathJax-Span-12419" style="width: 9.743em; display: inline-block;"><span style="display: inline-block; position: relative; width: 8.031em; height: 0px; font-size: 121%;"><span style="position: absolute; clip: rect(1.892em 1000.003em 3.132em -0.469em); top: -2.772em; left: 0.003em;"><span class="mrow" id="MathJax-Span-12420"><span class="mi" id="MathJax-Span-12421" style="font-family: MathJax_Math; font-style: italic;">S<span style="display: inline-block; overflow: hidden; height: 1px; width: 0.062em;"></span></span><span class="mo" id="MathJax-Span-12422" style="font-family: MathJax_Main; padding-left: 0.298em;">=</span><span class="texatom" id="MathJax-Span-12423" style="padding-left: 0.298em;"><span class="mrow" id="MathJax-Span-12424"><span class="msubsup" id="MathJax-Span-12425"><span style="display: inline-block; position: relative; width: 1.125em; height: 0px;"><span style="position: absolute; clip: rect(1.656em 1000.003em 2.718em -0.469em); top: -2.535em; left: 0.003em;"><span class="mi" id="MathJax-Span-12426" style="font-family: MathJax_Math; font-style: italic;">S<span style="display: inline-block; overflow: hidden; height: 1px; width: 0.062em;"></span></span><span style="display: inline-block; width: 0px; height: 2.541em;"></span></span><span style="position: absolute; top: -2.122em; left: 0.652em;"><span class="mn" id="MathJax-Span-12427" style="font-size: 70.7%; font-family: MathJax_Main;">1</span><span style="display: inline-block; width: 0px; height: 2.305em;"></span></span></span></span><span class="mo" id="MathJax-Span-12428" style="font-family: MathJax_Main;">,</span><span class="msubsup" id="MathJax-Span-12429" style="padding-left: 0.18em;"><span style="display: inline-block; position: relative; width: 1.125em; height: 0px;"><span style="position: absolute; clip: rect(1.656em 1000.003em 2.718em -0.469em); top: -2.535em; left: 0.003em;"><span class="mi" id="MathJax-Span-12430" style="font-family: MathJax_Math; font-style: italic;">S<span style="display: inline-block; overflow: hidden; height: 1px; width: 0.062em;"></span></span><span style="display: inline-block; width: 0px; height: 2.541em;"></span></span><span style="position: absolute; top: -2.122em; left: 0.652em;"><span class="mn" id="MathJax-Span-12431" style="font-size: 70.7%; font-family: MathJax_Main;">2</span><span style="display: inline-block; width: 0px; height: 2.305em;"></span></span></span></span><span class="mo" id="MathJax-Span-12432" style="font-family: MathJax_Main;">,</span><span class="mo" id="MathJax-Span-12433" style="font-family: MathJax_Main; padding-left: 0.18em;">…</span><span class="mo" id="MathJax-Span-12434" style="font-family: MathJax_Main; padding-left: 0.18em;">,</span><span class="msubsup" id="MathJax-Span-12435" style="padding-left: 0.18em;"><span style="display: inline-block; position: relative; width: 1.125em; height: 0px;"><span style="position: absolute; clip: rect(1.656em 1000.003em 2.718em -0.469em); top: -2.535em; left: 0.003em;"><span class="mi" id="MathJax-Span-12436" style="font-family: MathJax_Math; font-style: italic;">S<span style="display: inline-block; overflow: hidden; height: 1px; width: 0.062em;"></span></span><span style="display: inline-block; width: 0px; height: 2.541em;"></span></span><span style="position: absolute; top: -2.063em; left: 0.652em;"><span class="mi" id="MathJax-Span-12437" style="font-size: 70.7%; font-family: MathJax_Math; font-style: italic;">k</span><span style="display: inline-block; width: 0px; height: 2.246em;"></span></span></span></span></span></span></span><span style="display: inline-block; width: 0px; height: 2.777em;"></span></span></span><span style="border-left-width: 0.004em; border-left-style: solid; display: inline-block; overflow: hidden; width: 0px; height: 1.218em; vertical-align: -0.282em;"></span></span></nobr></span><script type="math/tex" id="MathJax-Element-695">S = {S_1, S_2, …, S_k}</script>, S為分割的群組集合</p>
<p><span class="MathJax_Preview"></span><span class="MathJax" id="MathJax-Element-696-Frame" role="textbox" aria-readonly="true"><nobr><span class="math" id="MathJax-Span-12438" style="width: 1.184em; display: inline-block;"><span style="display: inline-block; position: relative; width: 0.947em; height: 0px; font-size: 121%;"><span style="position: absolute; clip: rect(1.538em 1000.003em 2.541em -0.528em); top: -2.122em; left: 0.003em;"><span class="mrow" id="MathJax-Span-12439"><span class="msubsup" id="MathJax-Span-12440"><span style="display: inline-block; position: relative; width: 0.888em; height: 0px;"><span style="position: absolute; clip: rect(1.951em 1000.003em 2.955em -0.528em); top: -2.535em; left: 0.003em;"><span class="mi" id="MathJax-Span-12441" style="font-family: MathJax_Math; font-style: italic;">μ</span><span style="display: inline-block; width: 0px; height: 2.541em;"></span></span><span style="position: absolute; top: -2.004em; left: 0.593em;"><span class="mi" id="MathJax-Span-12442" style="font-size: 70.7%; font-family: MathJax_Math; font-style: italic;">i</span><span style="display: inline-block; width: 0px; height: 2.246em;"></span></span></span></span></span><span style="display: inline-block; width: 0px; height: 2.128em;"></span></span></span><span style="border-left-width: 0.004em; border-left-style: solid; display: inline-block; overflow: hidden; width: 0px; height: 1.004em; vertical-align: -0.354em;"></span></span></nobr></span><script type="math/tex" id="MathJax-Element-696">\mu_i</script>是群組<span class="MathJax_Preview"></span><span class="MathJax" id="MathJax-Element-697-Frame" role="textbox" aria-readonly="true"><nobr><span class="math" id="MathJax-Span-12443" style="width: 1.302em; display: inline-block;"><span style="display: inline-block; position: relative; width: 1.066em; height: 0px; font-size: 121%;"><span style="position: absolute; clip: rect(1.243em 1000.003em 2.482em -0.469em); top: -2.122em; left: 0.003em;"><span class="mrow" id="MathJax-Span-12444"><span class="msubsup" id="MathJax-Span-12445"><span style="display: inline-block; position: relative; width: 1.006em; height: 0px;"><span style="position: absolute; clip: rect(1.656em 1000.003em 2.718em -0.469em); top: -2.535em; left: 0.003em;"><span class="mi" id="MathJax-Span-12446" style="font-family: MathJax_Math; font-style: italic;">S<span style="display: inline-block; overflow: hidden; height: 1px; width: 0.062em;"></span></span><span style="display: inline-block; width: 0px; height: 2.541em;"></span></span><span style="position: absolute; top: -2.063em; left: 0.652em;"><span class="mi" id="MathJax-Span-12447" style="font-size: 70.7%; font-family: MathJax_Math; font-style: italic;">i</span><span style="display: inline-block; width: 0px; height: 2.246em;"></span></span></span></span></span><span style="display: inline-block; width: 0px; height: 2.128em;"></span></span></span><span style="border-left-width: 0.004em; border-left-style: solid; display: inline-block; overflow: hidden; width: 0px; height: 1.218em; vertical-align: -0.282em;"></span></span></nobr></span><script type="math/tex" id="MathJax-Element-697">S_i</script>內所有元素<span class="MathJax_Preview"></span><span class="MathJax" id="MathJax-Element-698-Frame" role="textbox" aria-readonly="true"><nobr><span class="math" id="MathJax-Span-12448" style="width: 1.243em; display: inline-block;"><span style="display: inline-block; position: relative; width: 1.006em; height: 0px; font-size: 121%;"><span style="position: absolute; clip: rect(1.538em 1000.003em 2.6em -0.469em); top: -2.122em; left: 0.003em;"><span class="mrow" id="MathJax-Span-12449"><span class="msubsup" id="MathJax-Span-12450"><span style="display: inline-block; position: relative; width: 0.947em; height: 0px;"><span style="position: absolute; clip: rect(1.951em 1000.003em 2.718em -0.469em); top: -2.535em; left: 0.003em;"><span class="mi" id="MathJax-Span-12451" style="font-family: MathJax_Math; font-style: italic;">x</span><span style="display: inline-block; width: 0px; height: 2.541em;"></span></span><span style="position: absolute; top: -2.063em; left: 0.593em;"><span class="mi" id="MathJax-Span-12452" style="font-size: 70.7%; font-family: MathJax_Math; font-style: italic;">j</span><span style="display: inline-block; width: 0px; height: 2.246em;"></span></span></span></span></span><span style="display: inline-block; width: 0px; height: 2.128em;"></span></span></span><span style="border-left-width: 0.004em; border-left-style: solid; display: inline-block; overflow: hidden; width: 0px; height: 1.004em; vertical-align: -0.425em;"></span></span></nobr></span><script type="math/tex" id="MathJax-Element-698">x_j</script>的重心,或叫中心點。</p>
<p>下面這個圖是一個資料根據不同K所分群出來的結果,顏色只是提供辨識分群用。</p>
<p><img src="https://lh4.googleusercontent.com/-Gdyz2KydnZc/U8iN1t81YEI/AAAAAAAAMOo/ILpZPAk3-qo/s720/kmeans1.jpg" alt="enter image description here" title="kmeans1.jpg"></p>
<blockquote>
<p><strong>圖片來源:</strong> <a href="http://online.stanford.edu/course/statistical-learning-winter-2014">Statistical Learning</a> (Stanford Online Course ) </p>
</blockquote>
<p><br></p><div class="se-section-delimiter"></div>
<h3 id="運作流程">運作流程</h3>
<p>我們先來看一下它運作的流程。 </p>
<blockquote>
<ol>
<li>先決定K <br>
k就是最後要分成幾群,如果你希望最後資料分成 3群 ,k就是3。 </li>
<li>在你的資料中,隨機選擇k個點做為群中心(也可以直接從資料挑)。</li>
<li>把每一筆資料標記上離它最近的群中心</li>
<li>根據同一個標記的所有資料,重新計算出群中心。 </li>
<li>如果步驟4算出來的群中心跟原本步驟3不同,則重複步驟3 </li>
</ol>
</blockquote>
<p>上面的步驟可以用下圖來表示, </p>
<p><img src="https://lh5.googleusercontent.com/-HPgqLzTbbUk/U8iTc7mNkmI/AAAAAAAAMO4/BoFWckNlgfY/s720/kmeans_flow.jpg" alt="flow" title="kmeans_flow.jpg"></p>
<blockquote>
<p>圖片來源: <a href="https://class.coursera.org/ml-003/lecture">Machine Learning</a> (By Andrew NG, Coursera) </p>
</blockquote>
<ol>
<li><p>我們要分成兩群<strong>(K=2)</strong>,所以一開始先挑了兩個點<strong>(b)</strong>。</p></li>
<li><p>將資料標記(著色)成距離最近的群中心<strong>(c)</strong>。</p></li>
<li><p>同一個群中心(顏色)的資料重新計算新的中心位置<strong>(d)</strong>。</p></li>
<li><p>同步驟2,做標記(著色的動作)。</p></li>
<li><p>同步驟3,重新計算新的群中心的位置<strong>(f)</strong>。</p></li>
<li><p>再重複步驟2,3 結果群中心位置不變,表示分群完畢。</p></li>
</ol>
<h3 id="注意須知">注意須知</h3>
<p>K-means一開始的亂數選擇群中心,會影響到最後分群的結果,下圖這個就使用K=3跑6次出來的結果,紅色235.8為產生出來的最佳的分群。 <br>
<img src="https://lh5.googleusercontent.com/-woHT2lS_kS0/U8iZH2WZBUI/AAAAAAAAMPI/bwqIFGqpJcY/s720/kmeans_diff.jpg" alt="enter image description here" title="kmeans_diff.jpg"></p>
<blockquote>
<p><strong>圖片來源:</strong> <a href="http://online.stanford.edu/course/statistical-learning-winter-2014">Statistical Learning</a> (Stanford Online Course ) </p>
</blockquote>
<p>關於怎麼避免一開始的選擇影響最後分群品質,這個等我研究有心得再跟大家分享。</p><div class="se-section-delimiter"></div>
<h3 id="後記">後記</h3>
<p>K-means簡單快速的方法被廣泛的使用,但是實際運用上還是有一些問題需要被克服。正所謂萬事起頭難,K-means一開始會先要求你提供K,但是k到底要多少才合理? 這個問題我們有空再來談。下次我們來分享一下不給定K的狀況下,我們要怎麼將資料分群。</p>misgodhttp://www.blogger.com/profile/00933441299043629398noreply@blogger.com2tag:blogger.com,1999:blog-1053927668006720431.post-31911069933624868482014-07-17T23:15:00.004+08:002014-07-18T11:32:11.435+08:00Build software better - Android AAR 類別庫的使用與分享<br />
<h2 id="什麼是aar"><span style="font-size: large;">什麼是AAR</span></h2>AAR檔案是Google為Android開發所設計的一種library格式,全名為Android Archive Library,與Java Jar Library不同的地方是AAR除了java code之外也包含res,也就是一些圖片、文字等資源檔案。會設計這種形式的類別庫是因為Google在Android SDK tool r14之後開始支援<a href="http://developer.android.com/tools/projects/index.html">Library Project</a>的開發方式,這種Library Project可以說是Android APP的半成品,其目標並不是製作成APK來執行,而是提供現成的View/Activiy等一些程式資源給其他開發者使用。而AAR正是這種Library Project編譯後的壓縮檔,壓縮後只需傳遞單一檔案即可分享,可說是相當方便。<br />
<br />
目前熱門的網路服務提供者(如Google、Facebook、Evernotec或是Dropbox等)也大多利用這種形式提供開發者來整合其服務於自己的App中,開發者如果想整合這類的網路服務,例如登入畫面或是張貼文章等,可以直接使用服務商所提供的UI元件,將之內嵌於自己的App頁面上。<br />
<br />
<img alt="enter image description here" src="https://farm6.staticflickr.com/5479/14658635942_6b08878009_z.jpg" title="" /><br />
<br />
<a name='more'></a><br />
<br />
<h2 id="一切從library-project開始"><span style="font-size: large;">一切從Library Project開始</span></h2>在Google還沒有支援AAR檔案之前,我們必須手動複製或匯入每個所需專案目錄到IDE中,以下圖的Facebook android sdk為例,我們可以從<a href="https://developers.facebook.com/docs/android">Facebook developer網站</a>下載SDK壓縮檔,SDK目錄中會有一個名為facebook的android project目錄,開發者可以將此目錄當作自己project的<a href="http://developer.android.com/tools/projects/index.html">library-project</a>,設定完成之後便可以使用該library-project中所定義的view或activity,<br />
<br />
<img alt="enter image description here" src="https://farm4.staticflickr.com/3924/14661109333_8994ebacd5_n.jpg" title="" /><br />
<br />
使用方式通常先是將此facebook目錄匯入Eclipse,成為如下圖的FacebookSDK專案,接下來在自己專案的Java Build Path中將FacebookSDK專案勾選進來成為Library Project。<br />
<br />
<img alt="enter image description here" src="https://farm3.staticflickr.com/2907/14656473771_149271fdf6_c.jpg" title="" /><br />
<br />
然而這種使用方式,常常需要手動搬移目錄,一旦Library有更新,也沒辦法對版本進行有效的管理。因此,改用AAR的方式來存取Library Project就會變得非常好用。<br />
<br />
<h2 id="使用aar之後世界變得不同了"><span style="font-size: large;">使用AAR之後,世界變得不同了</span></h2>因為AAR只在gradle build system有支援,也就是你需要放棄Eclipse改用Android Studio這個新的IDE(對很多電腦效能被Eclipse搞垮的人來說應該算是好事),由於Android gradle project的目錄結構與舊往的不同,因此你將無法直接匯入舊的Eclipse專案,轉換方式可以參考<a href="http://tools.android.com/tech-docs/new-build-system/migrating-from-eclipse-projects">這裡</a>。<br />
<br />
一旦改用Android Studio之後,我們可以發現目錄結構已經不同以往,也多了一些gradle專屬的設定檔案,以上述所提及的Facebook服務整合為例,如果要使用Facebook sdk,我們可以在如下圖的build.gradle設定檔中多加入一個facebook aar的dependencies來源即可(編號1的紅框),其中compile代表此一dependency類別庫將是採static include的方式被包含於APK之中,來源字串則是maven類別庫的URI格式,參考範例如下:<br />
<br />
<pre><code class="prettyprint">compile 'fr.avianey:facebook-android-api:3.14.1@aar'
</code></pre><br />
<img alt="enter image description here" src="https://farm4.staticflickr.com/3884/14669388882_5770bbe889_c.jpg" title="" /><br />
<br />
接下來可以開始編寫程式並直接存取Facebook所提供的API以及Res資源,其他詳細關於如何使用Facebook API可以參考<a href="http://35around.blogspot.tw/2014/07/androidfacebook-api_6.html">此篇</a>文章。編譯過後我們另外可以看到專案下的build目錄產生了facebook-android-api的子目錄(如上圖編號2紅框處),此目錄是由Maven由編譯時期從背景不知不覺幫我們下載下來的。如果以前只有使用傳統Java程式編譯方法,看到這裡常常會驚訝怎麼project dependency會變得這麼簡單?我記得第一次接觸到Maven時候,發現竟然不用上網找類別庫來下載,也不用再手動搬放檔案,直呼這根本是<br />
<br />
『神乎其神 !!』<br />
<br />
<h2 id="中央集中管理類別庫的概念-maven"><span style="font-size: large;">中央集中管理類別庫的概念 - Maven</span></h2>使用者不再需要自行下載類別庫,甚至還可以任意指定所需版本,這背後是如何運作的呢?其實這是Maven Server的功勞,上述的Facebook Android Studio專案之中,專案外部有一個build.gradle設定檔,此檔案記載了Maven repostory的位置來源,如下圖所示,Google將Maven的中央伺服器的位置包裝於此mavenCentral() method中,這是所有android gradle專案的預設值,因此只要Maven central repostory上面所存放的類別庫,我們都可以利用相同的方式指定參考他,當然我們也可以在這個mavenCentral()列表下新增我們自定的其他Maven reposotry server.<br />
<br />
<img alt="enter image description here" src="https://farm3.staticflickr.com/2914/14488191499_7ba05b51de_z.jpg" title="" /><br />
<br />
如果要查詢Maven Central repository上面有哪些類別庫資源可以使用,我們也可以上maven網站上查詢,網址是<a href="http://mvnrepository.com/">http://mvnrepository.com/</a>,例如Facebook SDK類別庫便可以於<a href="http://mvnrepository.com/artifact/fr.avianey/facebook-android-api/3.14.1">http://mvnrepository.com/artifact/fr.avianey/facebook-android-api/3.14.1</a> 這個位置找到(如下圖),網頁內並可以查詢該類別庫於各種支援Maven的build script上的使用方式。<br />
<br />
<img alt="enter image description here" src="https://farm3.staticflickr.com/2900/14671717121_59f0aeaed4.jpg" title="" /><br />
<br />
<h2 id="製作並分享自己的aar檔案"><span style="font-size: large;">製作並分享自己的AAR檔案</span></h2>如果我們也想要製作AAR檔案來分享自己的library project,現在透過gradle的設定便可以輕鬆達成,設定方式為在專案的build.gradle設定檔加入如下的內容:<br />
<br />
<pre><code class="prettyprint">uploadArchives {
repositories {
mavenDeployer {
repository(url: "http://YOUR_MAVEN_REPOSTORY_SERVER/URL"){
authentication(userName: "YOUR_USER_NAME", password: "YOUR_PASSWORD")
}
pom.project {
groupId 'com.yourcompany.lib'
artifactId 'firstAARLib'
version '1.0.0'
packaging 'aar'
}
}
}
}
</code></pre><br />
<br />
設定完成後,我們可以在每次專案編譯完成後再執行如下的command line,gradle便會幫我們把專案編譯出的aar檔案上傳至所指定的maven server上。<br />
<br />
<pre><code class="prettyprint">gradle uploadArchives
</code></pre><br />
如果有使用者想要使用我們上傳的AAR模組,使用方式則是在其專案的build.gradle中的repositories清單中加入我們的上傳的Server URL,範例如下:<br />
<br />
<pre><code class="prettyprint">repositories {
mavenCentral()
maven {
url "http://YOUR_MAVEN_REPOSTORY_SERVER/URL"
}
}</code></pre><br />
如此一來,我們的Android專案便可以模組化地將功能分工合作來完成,模組元件還可以方便地再利用並透過Maven的機制地進行版本管理,一切井然有序之後,便是專案開發效率大爆發的時候了!Sam Chttp://www.blogger.com/profile/16142383609940270017noreply@blogger.com2tag:blogger.com,1999:blog-1053927668006720431.post-83373457483177210252014-07-16T23:43:00.001+08:002014-07-16T23:51:13.000+08:00五條港文學踏查隨筆(3)<h2 id="前情提要">
前情提要</h2>
在看完佛頭港熱鬧的龍舟競賽,讓我們繼續往北,今天要探訪的是總鋪師的著名場景,台南紡織前身的新復興紡織廠,新港墘港旁的老古石街道。<br />
<a name='more'></a><h2 id="路線">
路線</h2>
<strong>媽祖樓</strong> <br />
位於五條港以北的媽祖樓,原地為一工寮,相傳當時有工人遺留湄洲媽祖香火于工寮二樓,每到夜晚會發出紅光指引船隻,民眾認為媽祖顯靈,遂建造廟宇供奉媽祖。<br />
電影總鋪師中的<strong>愛鳳小吃店</strong><a class="footnote" href="https://www.blogger.com/blogger.g?blogID=1053927668006720431#fn:iphone" id="fnref:iphone" title="See footnote">1</a>便位於廟宇旁。<br />
<img alt="愛鳳小吃店" src="http://stars.udn.com/starimages/slide/227767/M_227775-L14956583.jpg" height="426" title="" width="640" /><br />
<blockquote>
圖片來源:<a href="http://stars.udn.com/newstars/slide/SlideCc.do?id=227766">聯合追星網</a></blockquote>
<strong>集福宮</strong> <br />
從媽祖樓出發沿著信義街往兌悅門前進,台南幫侯雨利先生發跡的新復興紡織廠就位於此地,一邊騎著腳踏車環島,一邊分享紅豆湯的<strong>慕紅豆</strong><a class="footnote" href="https://www.blogger.com/blogger.g?blogID=1053927668006720431#fn:red" id="fnref:red" title="See footnote">2</a>也進駐于此。 <br />
集福宮為城外五大姓中黃姓族人所建,廟宇內有「老古石街公議」的殘碑,為當時的調解委員會。<br />
<br />
<strong>兌悅門</strong> <br />
兌悅門是台南現存唯一外城門,其餘外城門皆在日治時市區改正時被拆除了,五條港的填平也是在市區改正時發生。 <br />
<img alt="兌悅門" src="http://culture.tainan.gov.tw/ufiles/historic/gmap_m2000105.jpg" height="480" title="" width="640" /> <br />
旁有石獅公廟,據稱是兌悅門造型如弓,直對安平,安平為鎮煞氣,立了兩尊石將軍(今藏於安平天后宮),為了反制石將軍,方立了石獅公來對抗。<br />
<br />
信義街為老古石街,是一條相當美麗的街道,千萬不能錯過喲!<br />
<br />
最後附上謝銘祐老師的歌曲「阮兜住佇屎溝墘」,新港墘又稱屎溝墘,當初為運送水肥的港道。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/vpikOGtodYQ?feature=player_embedded' frameborder='0'></iframe></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<i>(待續...)</i></div>
<br />
<div class="footnotes">
<hr />
<ol>
<li id="fn:iphone">總鋪師其他場景,請參照臺南市觀光旅遊局製作的<a href="http://tour.tainan.gov.tw/news.aspx?sn=25645">總鋪師場景地圖</a> <a class="reversefootnote" href="https://www.blogger.com/blogger.g?blogID=1053927668006720431#fnref:iphone" title="Return to article">↩</a></li>
<li id="fn:red"><a href="http://ohredbeans.pixnet.net/blog/post/90892284-%E8%B3%87%E5%8A%A9%E6%86%A8%E4%BA%BA%E4%B8%89%E8%BC%AA%E8%BB%8A%E7%92%B0%E5%B3%B6%E5%88%86%E4%BA%AB%E7%B4%85%E8%B1%86%E6%B9%AF%E8%A8%88%E7%95%AB%EF%BD%9E%E6%8F%AA%E6%82%A8%E5%81%9A">慕紅豆</a>唐大可的環島分享愛 <a class="reversefootnote" href="https://www.blogger.com/blogger.g?blogID=1053927668006720431#fnref:red" title="Return to article">↩</a></li>
</ol>
</div>
Anonymoushttp://www.blogger.com/profile/05724782384274251086noreply@blogger.com0tag:blogger.com,1999:blog-1053927668006720431.post-56954052726246676152014-07-15T23:37:00.001+08:002014-07-16T23:51:12.997+08:00五條港文學踏查隨筆(2)<h2 id="前情提要">
前情提要</h2>
五條港見證了清代貿易之繁華,也見證了台江內海逐漸淤積,滄海桑田。隨著府城人口增長,築城取代一開始的木柵,大井頭從碼頭邊變成街市,城外的五條港開始展現風華。郊商、碼頭苦力和酒家女,多少故事在這發生。<br />
<a name='more'></a><div class="se-section-delimiter">
</div>
<h2 id="路線">
路線</h2>
<strong>寶美樓</strong> <br />
民族路圓環邊,今法國臺北婚紗,便是日治時台南聞名的酒家,「北有江山樓,南有寶美樓」中的寶美樓。今日寶美樓仍存日治時期四層樓建築,兩側最上方,還可以看到寶美樓的刻字。<br />
<strong>「水仙宮外是儂家,來往估船慣吃茶;笑指郎身是錢樹,好風吹到便開花。」</strong>~ 陳肇興《赤崁竹枝詞》 <br />
從詩詞中也可看見,五條港在商貿發達之後,酒家青樓也伴之而生,而日治之後,更是許多大型酒家與特種娛樂的聚集之地,現今的宮後街也是昔日的風花地。<br />
<strong>景福祠</strong> <br />
景福祠是台南唯一列為古蹟的土地公廟,現在被市場包圍,橫於門口的人和街、普濟街為昔日的杉行街,為當時的杉行和棺材店聚集處,也有「杉行街的扛轎,吃飽閑閑等死」的俗諺。 <br />
景福祠位於佛頭港三條支流(王宮港、媽祖港、關帝港)匯集之處,亦稱佛頭港土地廟。在嘉慶年間失火重建,內有碑文註明附近店家高度不得高於廟宇。現在的街市,也都不高,巷弄也相當窄小,在店裡買東西,可以聽到對面店家的殺價聲。 <br />
有個有趣的故事是這樣的,當時有間杉行街上有間小吃店和棺材行相對,棺材行每天看著小吃店生意興隆,人來人往,自己卻門口羅雀,內心有點淡淡的哀傷。有天棺材店老闆,終於受不了了,在小吃店生意正好時,他拿起撢子,清著棺材灰塵,嘴裡一邊唸著「出去,出去」,希望那些棺材趕快出去,也希望對面的人潮趕快散去。對面小吃店老闆聽了就覺得有點礙耳,心裡想『老傢伙這不是在觸我霉頭嗎』,所以他也跟著嚷了起來「來來,該逮該逮(自己裝自己裝)」,又氣了棺材店老闆個半死。<br />
<strong>聚福宮</strong> <br />
位於民族路上的聚福宮,跟待會要介紹的崇福宮,都是城外五大姓中蔡姓族人所建。府城俗諺「蔡拼蔡,神主牌摃摃破」,就是剛剛提到佛頭港為杉木轉運處,碼頭苦力爭奪搬運地盤時,雙方人馬大打出手的雙蔡對抗。<br />
<strong>崇福宮</strong> <br />
佛頭港為五條港中較為寬者,也是昔日龍舟競賽舉辦的地方。 <br />
<strong>「佛頭港裏鬥龍舟,擁擠行人到岸頭。曾記昔年逢驟雨,倉皇紅粉跌中流。」</strong>~ 許南英《臺灣竹枝詞》 <br />
詩詞中可以看見,龍舟賽事為當時府城一大盛事,觀看人群眾多,大家躲雨時,還有小姐不慎落水的盛況。<br />
<em>(待續…)</em>Anonymoushttp://www.blogger.com/profile/05724782384274251086noreply@blogger.com0tag:blogger.com,1999:blog-1053927668006720431.post-28077069090942950282014-07-14T18:27:00.001+08:002014-07-14T21:04:36.511+08:00UI Test Script for Android - 以Puzzle And Dragons自動轉珠為範例 (下)<h3 id="pad自動轉珠">
PAD自動轉珠</h3>
在最後一篇文章當然就要來講最重要的, 怎麼做到自動轉珠<br />
<del>(主題明明就是UI Test Script, 什麼時候副標題變成重點了)</del><br />
想要達到自動轉珠, 我們可以把事情分成兩個部分: <br />
1. 如何分析遊戲盤面上的珠子 <br />
2. 如何透過盤面的狀況來自動轉珠<br />
<br />
<a name='more'></a>
<h3 id="分析遊戲盤面">
分析遊戲盤面</h3>
<img alt="enter image description here" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3x4QURRTjOPbtzHpjXNV44b76l4jhqt-blW48c-xetMKkvgSFnMHqJiRIjwpuFtFbxGC9o5bK8GcBqNyhjjzYDjPqBwary57c2ModTVHt56mIhU9p5RTQ0zWdEB1yzSX0339XG1hlTqQ/s0/6x5_ori.png" title="6x5_ori.png" /><br />
當你進到遊戲看到上面的盤面時, 首先當然是要根據他是哪個種類的珠子做分類, 做完分類我們才有辦法針對它們來產生自動轉珠的路徑。 <br />
那麼, 該怎麼做呢? 什麼方法會比較有效率呢? <br />
方法一: 一開始不用想太多, 就用最簡單的方法吧, 反正我們有FindImage的API,那就對每一個珠子去做template matching, 那就可以把盤面資訊全部解析出來了吧。不過, 這個想法當然沒什麼問題, 不過這樣做似乎不是一個很有效率的方法, 所以再想看看別的方法吧。既然每個珠子的顏色都差很多, 那麼用顏色來判斷應該是個好方法吧? 不過一個珠子範圍那麼大, 你要怎麼算整個區域的顏色來做比對咧? 算平均值應該就可以求出珠子的顏色範圍吧! 基於這個想法, 所以我們就得到了方法二囉。<br />
方法二: 盤面其實是一個6*5的map, 所以我們可以直接將上面的圖片縮小到6*5的大小, 那麼我們就簡單的可以取得如下圖所示的一個6*5的顏色矩陣, 然後就能發現用人眼就可以簡單的分別出不同的色塊了。<br />
<img alt="enter image description here" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGORoGtOBJbz7nlsMwc9w0GjYSLdQb2lorE1n8x4F0Gjl1r4CpkQJ-cIiCP8dOSw6lANm-xETaLpRYFSFCiYygvzhoSaxrcDMsTzBP8RyDJgMXp1XMbCFBMZvjdEznukhLr8fCjtw7THw/s0/6x5_small.png" title="6x5_small.png" /><br />
當然, 電腦不像人眼那麼強大, 可以簡單的分辨出哪幾個區域是屬於同一區塊的, 電腦只能知道這個顏色代表的值為何, 相信有做過影像處理的人都會直覺想到, 該是<a href="http://en.wikipedia.org/wiki/HSL_and_HSV">HSV</a> ( Hue,Saturation,Value 色相,飽和度,明度 ) 出場的時候了。 <br />
為什麼要用HSV, 用下面的範例來做個解釋吧, 對人眼來說, 下面的這兩個顏色就人眼來說會被視為相似的, 但是對 電腦來說沒辦法利用RGB的值簡單的將他們歸類為同一類, 只能知道Blue的值會比Red,Green來得高, 但是一旦我們將RGB轉成HSV之後, 你會發現紅色字體(色相)數值的部分相當接近, 我們就可以透過這個數值來做為分類的標準了。<br />
<span class="fragment"><span style="background-color: #37a4ff;"> </span>RGB=(055,164,255)</span> <br />
<span class="fragment"><span style="background-color: #86c6dc;"> </span>RGB=(134,198,220)</span><br />
<span class="fragment"><span style="background-color: #37a4ff;"> </span>HSV=(<span style="color: red;">207</span>,078,100)</span><br />
<span class="fragment"><span style="background-color: #86c6dc;"> </span>HSV=(<span style="color: red;">195</span>,039,086)</span><br />
<br />
<br />
<h3 id="透過盤面來自動轉珠">
透過盤面來自動轉珠</h3>
<img alt="enter image description here" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQCVpKOiEgRXq2ZcMOMEIiH7ZkOwHqgz4XdzxFvFO5XMnlcIQNa1U4d0Pzmv2ljHGfkCh8NlZS1nki7_Gb-GsJ-4W3T0bmEtloLS4ERKtddd-jDlbDWYenETCLGe31S9wgwHFzv9DhR4Y/s0/howto.png" title="howto.png" /> <br />
<br />
<br />
既然我們已經將遊戲盤面給數值化了, 那麼就可以開始來撰寫自動轉珠的路徑了, 但是要怎麼樣才可以算出高Combo的路徑或是傷害最高的路徑呢? 首先我們要知道PAD裡面傷害計畫的公式: <br />
基礎攻擊力 x 消珠倍率(+寶珠強化) x COMBO倍率 x 隊長技和主動技倍率 = 寵物傷害 (資料來源: ptt.cc)<br />
接下來是最重要的演算法的部分, 如何設計一個好的演算法來求得傷害最高的路徑, 說真的, 我覺得要想到一個很好的演算法頗困難的, 還好目前的電腦cpu都還蠻強的, 加上其實盤面並不會很大, 只有6*5的大小, 所以在這邊我直接使用BFS方式來求解。實作的方式為: 針對盤面上的每一個珠子, 計算它可以往外前進的八個方向, 每走一步之後就計算目前盤面可以消除區域, 並計算落下之後是否造成下次的消除, 再代入上述的公式, 並且設定一個珠子最多可以走幾步, 最後就我們就可以得到每一個起始珠子走過的路徑的Combo數及攻擊力的權重表格, 透過這個表格我們就可以取到一個攻擊力最高的路徑了, 下面為pseudocode:<br />
<pre class="prettyprint prettyprinted"><code><span class="kwd">for</span><span class="pln"> row</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> col</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pln">
solutions</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Solution</span><span class="pun">(</span><span class="pln">cursor</span><span class="pun">(</span><span class="pln">row</span><span class="pun">,</span><span class="pln"> col</span><span class="pun">));</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> solutions</span><span class="pun">.</span><span class="pln">isEmpty</span><span class="pun">()</span><span class="pln">
solution </span><span class="pun">=</span><span class="pln"> solutions</span><span class="pun">.</span><span class="pln">pop</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> solution</span><span class="pun">.</span><span class="pln">depth </span><span class="pun">>=</span><span class="pln"> MAX_DEPTH
</span><span class="kwd">continue</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> move</span><span class="pun">=</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pln">
newSolution </span><span class="pun">=</span><span class="pln"> moveOrbs</span><span class="pun">(</span><span class="pln">solution</span><span class="pun">,</span><span class="pln"> move</span><span class="pun">)</span><span class="pln">
calculateWeight</span><span class="pun">(</span><span class="pln">newSolution</span><span class="pun">)</span><span class="pln">
solutions</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">newSolution</span><span class="pun">)</span></code></pre>
在取得一個路徑之後, 我們就可以透過之前講過的API- Drag來移動珠子了。後來發現其實網路上還蠻多自動轉珠的演算法, 不過實作方法大致上都差不多, 有興趣的人可以去研究一下原始碼: <a href="https://github.com/kennytm/pndopt">pndopt</a>。<br />
中間其實省略過不少過程, 不過大方向都已經提出來了 XD <br />
總之, 最後就用自動轉珠的影片來做個結尾吧~(用SCR Screen Recorder Free 預設的設定錄下來的, 有點頓)<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dxoV-pWK06djjCdDyahoH0c7utkRXTX93GqMtRX8AxoV6Tb3ivI9S54TU8goXDVMSwIbt5QmVaeMceGUKx2' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<br />
<br />
<br />Anonymoushttp://www.blogger.com/profile/17715762577846106669noreply@blogger.com0tag:blogger.com,1999:blog-1053927668006720431.post-1527027110174157842014-07-13T08:00:00.002+08:002014-07-18T14:31:02.933+08:00輕鬆聊之KNN演算法<p>今天來簡單介紹一下KNN演算法,全名叫<strong>K-nearest neighbors algorithm</strong>。KNN可以說是機器學習(Machine Learning)中最簡單的演算法,簡單到我連Sample Code都不想寫給你看(<del>其實是懶</del>),只要記住下面這五個字,<strong>「西瓜偎大邊」</strong>就可以完全了解這個演算法的奧義。</p>
<p>讓我們來想想一個情況,有一天晚上俊傑騎著機車正在回家的路上,不小心捲進了一群飆車族的械鬥,他環視了一下發現總共有三群飆車族,身上的衣服分別是黃、灰、紅。他已經在車陣之中,而且處境非常的危險,所以俊傑有兩條路可以選 <br>
<a name='more'></a></p>
<ol>
<li><p>不加入任何陣營,來一個打一個,以一擋百。 </p></li>
<li><p>選擇加入某個陣營 </p></li>
</ol>
<p>基本上選了1就沒什麼好討論了,所以我們先假設他選2好了。俊傑本身就是個識時務的人,所以他看了一下<strong>離他最近</strong>的7個人(k=7),發現有黃色衣服的有4個,灰色有2個,紅色有一個,所以他當下立刻從包包來出一件黃色外套(不要問為什麼他剛好有黃色外套),加入黃色陣營,這就是所謂的<strong>「西瓜偎大邊」</strong>。從這個故事我們了解,俊傑本身應該是有學過KNN演算法的。</p>
<p>KNN屬於機器學習中的監督式學習(<strong>Supervised learning</strong>),不過一般來說監督式學習是透過資料訓練(<strong>training</strong>)出一個<strong>model</strong>,但是在KNN其實並沒有做training的動作。KNN一般用來做資料的分類,如果你已經有一群分好類別的資料,後來加進去點就可以透過KNN的方式指定新增加資料的分類。K表示一個常數,簡單的來說就是KNN就是看離你最近的K的點,然後看哪個類別的點最多就把自己也當成那個類別。你如果只看3個點,就是3NN囉。</p>
<p>下面這張圖,k=8所以周遭有6綠2紅,那個黑點理所當然就變成綠色的。</p>
<p><img src="http://omicsonline.org/ArchiveJCSB/2009/August/03/images/JCSB2.219Figure7.gif" alt="KNN圖示" title=""></p>
<p>KNN演算法雖然非常的簡單直覺,但是其實準確度還蠻高的,是一個蠻實用的演算法。不過實際使用上還是有一些難題在,例如</p>
<ol>
<li><p>好K讓你上天堂,K要多少最合適,怎麼樣挑一個好K。(其實是有一些常用的方法)</p></li>
<li><p>怎麼算出資料的”距離”,例如座標距離、顏色相近程度、字詞重疊程度…等,這個會跟你的資料還有分類方法有關。 (這個要問施主你了)</p></li>
<li><p>每次都要掃描全部的資料算出距離,才能知道最近的k筆資料是什麼,需要相對高的記憶體跟計算時間。 (有其他加強版的演算法)</p></li>
</ol>
<p>關於上面3點,未來有機會再來聊聊吧(<del>很明顯是芭樂票</del>)。</p>
<p>簡單來說,KNN就是讓你透過一群已經標記好類別的資料,來針對未分類的資料做分類的工具。 </p>
<p>那如果只有一群尚未分類的資料,我們要怎麼將他分類呢?這邊就是非監督式學習(<strong>Unsupervised learning</strong>)中的<strong>K-Means</strong>的故事了,有機會再聊囉…</p>
<p><strong>[更新: 20140708]</strong> <br>
<a href="http://35around.blogspot.tw/2014/07/k-means.html">輕鬆聊之K-Means演算法</a></p>misgodhttp://www.blogger.com/profile/00933441299043629398noreply@blogger.com3tag:blogger.com,1999:blog-1053927668006720431.post-85123648322893994212014-07-12T03:47:00.001+08:002014-07-14T10:05:26.211+08:00[開箱文] ASUS Padfone S - 4G LTE<p>就在2014/07/09 ASUS 發表了搭配有 4G LTE 的 <a href="http://www.asus.com/tw/Phones/ZenFone_5_A500KL/">ZenFone 5 (A500KL)</a>也順便發表了新的頂級機種,也是 Padfone 的系列機種 - <strong><a href="http://www.asus.com/tw/Phones/ASUS_PadFone_S/">Padfone S</a></strong>,依照傳統當然也可以跟需額外購買的平板合體,而且這次的發表會也包含周邊配備,像是<a href="http://www.asus.com/tw/Tablet_Mobile_Accessories/ASUS_PW200F_Wireless_Charging_Stand/">無線充電器</a>和<a href="http://www.asus.com/tw/Tablet_Mobile_Accessories/Padfone_S_Station_TriCover/">PadFone 專業折疊式護套</a>。</p>
<p>由於今年的 4G 元年,今年 6 月各大電信商也紛紛開通 4G 的服務,但台灣的頻段分成了好幾部分,也個別的販售,導致各家電信商所支援的頻段是有所不同,也就是說想要用某某電信商的 4G 服務要先注意您手上的手機裝置是否有支援此頻段。為了避免手機無法配合使用者所使用電信商提供的頻段,繼 HTC 之後,也推出了支援全頻段的手機,讓使用者不需要擔心,只要是在台灣使用,只要搭配電信商就能夠使用 4G 喔!</p>
<p>而且這樣的頂級規格手機,除了幾家手機商跳樓大拍賣,一般價格都不太親民,這次的 Padfone S 竟然只要 <strong>9999</strong> ,低於萬元的 4G LTE 手機真得頗有競爭力,另外在發表會之後馬上就可以透過華碩線上商店購買,並號稱隔日送達,之前華碩 Zenfone 的出貨不順讓許多使用者等了好一陣子,有種看得到吃不到的怨念,這次針對 Padfone S 的供貨就改善了非常多,值得鼓勵!</p>
<a name='more'></a>
<p>在開箱之前來看看 Padfone S 的硬體規格,詳細的規格可以到<a href="http://www.asus.com/tw/Phones/ASUS_PadFone_S/specifications/">官網</a>查看!</p>
<ul>
<li>平台 : Android 4.4 (KitKat ) with ZenUI</li>
<li>重量 : 150 g (含電池)</li>
<li>CPU : QualcommSnapdragon 801 MSM8974AB (Quad Core @ 2.3GHz)</li>
<li>RAM : 2 GB</li>
<li>網路 : 3G (WCDMA : 900/1900/2100) 4G (FDD-LTE : 700/800/900/1800/1900/2100/2600*)</li>
<li>電池 : 2300 mAh</li>
<li>相機 : 背面鏡頭 1300 萬畫素, PixelMaster,正面鏡頭 200 萬畫素</li>
<li>特異功能 : <br>
<ul><li>PadFone S 手機防150cm自然落摔:各表面於高度150cm進行重力落摔(無額外施力),三次落摔於平滑鋼板後機台使用仍不受影響。 </li>
<li>PadFone S 手機生活防潑水達IPX2等級:背蓋完整密合狀態下各表面傾斜15度角進行10分鐘滴水測試(相等於每秒3mm的雨量),機台使用仍不受影響。 </li></ul></li>
</ul>
<p>以上看起來大致上都是頂級規格,真要說的話就是電池容量少了點,不然就更趨完美了!</p>
<h1 id="開箱">開箱</h1>
<p>首先來看看盒子外觀,左側有一圈一圈的標識出支援的功能 <br>
<img alt="盒子外觀" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYNROkU0iqOovh9ZBgDFwpIlFiPlTRyFzs9Uvo-Sfkod6-rMSfR0xW5ODwYPBQIJVHv8bAztRQKydDHYCSwQeumYEqkXaRf0uX4SmQ3B_529oOAkTe2V6zaU_tBz_goelZp4ezvl0Cvq0/s1600/IMG_1086.JPG" height="480" width="640"></p>
<p>把盒子拉出來後 <br>
<img alt="拉開PadfoneS盒子" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1Eijkt3760ZsRI1iHznW1cn5gLBp8Y94ABZRNhU_H0cGHn3e2uRbsludOcmHlZs8rlhaEjF-aDvBEd4jn7ldCRzacdTHDRmTCQVuef7-_9KpE9XZP56o-JkUR2OMGY1xcsMCTCOQkpxw/s1600/IMG_1087.JPG" height="480" width="640"></p>
<p>盒子裡面所有的東西,從左邊盒子和保證書,上面耳機,中間變壓器和 USB 轉接線,右下角就是我們的主角 Padfone S <br>
<img alt="盒子內部配備" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh35lEF_W0hER-oRB_3fFg6uAyPD2wwmjk-q4xgeICE9YhhivgZi7anca8_X54ldN9P4TZoUY5xwBy6RFTisMML0xoUpdZ4yc_xm0RhmJsxc7KYLpmmpq3sG6rfSHua-W3PbBbLAF6o50Q/s1600/IMG_1088.JPG" height="480" width="640"></p>
<p>翻到背面看一看,可以看出其實殼的顏色並不是全黑,黑裡會透出一絲絲的紅色也就是官網所提到的<strong>黑耀紅</strong> <br>
<img alt="背殼" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhcjX1cDlm3CtVy2KO4Ffp9WxEdBY88NU6qiMc8AQsZD2vSKkNcTrWNDGl0WEevCxVwaYVEDEXzY7vE9K_stQLMfOSey3MrIfsQ5aC9JhSpoQ-mvJDA_ErvHVr3iF6_AHDnk2-x9AFkCvc/s1600/IMG_1090.JPG" height="640" width="480"></p>
<p>近身一看,左邊大圈是鏡頭旁邊就是補光燈,另外一排一排的孔是喇叭,是說喇叭做在這邊還蠻特別的 <br>
<img alt="鏡頭捕光燈喇叭" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZME0v4eYny7tBPLUpelQR6WtvDFb_rkq-m5csiyrUAVbAGcr1S0EMNLMehuV8CcN9GxYp9RIVNS4sXucTql_pr5NIEAvZsFRzdFo15IJQlT_hG_3ynTBeFareWlOEDEjEBm8NfwOg6kM/s1600/IMG_1091.JPG" height="480" width="640"></p>
<p>右邊側邊的按鈕,由上往下是電源和音量鍵,搭配上金屬絲的外觀,質感提升!! <br>
<img alt="側邊按鈕" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2b8GV6TRBCLB0pyFpyOl6xsUHu7Fnvx3ELkj9tltLw07W9I446PtlPHcweTwcQRKyyov5bd9MKxb6rJyiytrQjMD48ZGQzMwblVs7oMmnFRd6O4RIb9j8PEz3irO4bFVv9tgrTdjcxUs/s1600/IMG_1093.JPG" height="480" width="640"></p>
<p>底部的充電接孔和跟平板的接孔是都可以相容的,不用擔心配件的問題,右邊降噪功能的小孔 <br>
<img alt="手機底部" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVUgN0dpSEDtYK387MaVvlEzZ-rU8cy-aT1LUrOJAhBt8pTjPbbHANhsqoU-RINNyZzIJuW66DTo6QiCdHnAZpRvWhAzEs5R2LFHAbAmSsY-1Vw4S7w3VoTC4eJNYinyXFwQxtxuhxl40/s1600/IMG_1094.JPG" height="480" width="640"></p>
<p>頭部的話側邊則是 3.5 mm 耳機孔,和降噪功能的孔,平面上則是前鏡頭和話筒 <br>
<img alt="手機頂部" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJAsFY5Njv6rrdhbYJHQe6R6PonWMfwi0iiERNERZ5hR8DCGp0By7UiVqFzKvc87TPUeealUu1wZrIKXhvcBfZJEeY9XK46Ts8mfJQatMp31Inu7dsgFDGMGtTlnM_4brWp2_Qy2y5cfA/s1600/IMG_1095.JPG" height="480" width="640"></p>
<p>把電源鍵和音量鍵設計在右邊應該是讓左手持手機的使用者們,能夠輕易的按這兩個鈕 <br>
<img alt="手機側邊-右邊" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikt8QCZ5V8O3WSxL6YZdwmvNIcxke6xmoftcVipd3QB0NuykHIs68pDRXxEK6dwnZS7OHza1VA1XAHFCHuns2CvUMaHRkAKZJDLOsWpVZTyPHqvJC4T0fzxRpnCEbZ51GnLYeQBx_HaL8/s1600/IMG_1096.JPG" height="480" width="640"></p>
<p>背蓋打開後,電池不能變換, SIM 卡和 SD 卡都在右邊 <br>
<img alt="背蓋打開" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXcFnwVOl44-Hg7Pxdwkj_PLNDs6gFXd3Fcn9QBoJgqYSOvIkV83zY6PHjtyttZDH_ufS8X9w2Nl596x1kFXu6NyrajyeC2xFG3yKPMY5nwFOLnShbvNI4mJ4OzVMAYCMHnwPc0ifIdXw/s1600/IMG_1097.JPG" height="480" width="640"></p>
<p>開機設定 <br>
<img alt="開機第一次設定" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj7AQKFKCBy4Gv0jRJJcRdENUorqt3YPN9NT2pzJsD14dvgWhyiEuLqLq1nYD0d6ZlXpc_Ct9GBJexSE-VF6E5ju1w-mJtNA08Aiu00FO-JuAS1Y0hNfFdi9dy-1b_qAT2FRdVWDIKVbas/s1600/IMG_1101.JPG" height="640" width="480"></p>
<p>到第一次設定的第二不選擇輸入法時,發現有大量的輸入法可以使用!很不錯喔!接著就一路照著設定按到底吧! <br>
<img alt="輸入法" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgyyafT0kcKE8om0u5ZgRknLTZOL_8EUBZo07zePsG1x6YNS9xwAW1IrsX8ul4PFqqgBaFhHihejxWRSdeDyLnpLMGhQZMAdzzcIiQ3zU5_pB9SU4ALRV0D63G26mQNlbHQeYlYuUlEZf0/s1600/IMG_1102.JPG" height="640" width="480"></p>
<h1 id="zenui-相機">ZenUI - 相機</h1>
<p>PS <em>沒有測試文 純粹流覽介紹 UI</em> 官網有詳細的<a href="http://www.asus.com/tw/Phones/ASUS_PadFone_S/PixelMaster/">圖文介紹</a></p>
<p>手機除了打電話,玩遊戲,傳 Line , 用社交 App 以外,相機的功能也非常重要,當然各家廠商也都不例外的在相機部分下過功夫,接下來就來看看有哪些設定可以使用 <br>
攝影模式 <br>
<img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYcDLmWVIiT3oA1EhPJ16UtBykOcAWpPuyGWJho17mE5hJGwIEFwoAGd0uaWzGckS7nla0V3bDpwtW8e3GgfGSO4oQfHs-UpFoLa2xCSdx65eTbXnSyhG4nqzoMF1SwmJAxDOVzJSOPfQ/s1600/Screenshot_2014-07-10-22-55-51.png" height="640" width="360"></p>
<p>拍照模式,選擇很多,微縮模型,智慧移除,景深效果,團體微笑,GIF 動畫,不少實用的模式讓使用者拍起照來格外的簡單 <br>
<img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjL5NEQCWy2yKtVO16v7EXjhGsmeQvIkJ8D0H3tMj0O-ZKpITGAj3l1n2wVIO5kUvshIwJEBheFV3n1Yfoj6FDBtCzNDAxGpYNqOeyGXesBUDrlxSV9JbZyOHFe0l7QNx5GhucU9p21cVQ/s1600/Screenshot_2014-07-10-22-55-58.png" height="640" width="360"> <br>
<img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyCLrDyt0OM2rVwvqoaymGjK3VlHZB_818nS5Av65ma8QyzTYJv30u6cVmcvErzSPtP398IKu3XQ3lMIDLqUPS0oYNC_xZZc8tMn37Wtst-1dSlaA-vUPmYqTq4gbemm7A578qQ53kBds/s1600/Screenshot_2014-07-10-22-56-04.png" height="640" width="360"></p>
<p>白平衡設定,左到右分別是自動 / 陰天 / 日光 / 螢光燈 / 白熾燈 <br>
<img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhatldAugLSaOr0IV8d_ioy92tDm3L5lBZX5xBatbnhpJQ10S7TCVj__3KHu3BM0o3JxG_KODioApSEJNlSH7lab-HQlfwa50Xu5uidpuwqvPyjKu7Qmj2lCleE0hpBo3_u_kV97IuYlUQ/s1600/Screenshot_2014-07-10-22-57-10.png" height="640" width="360"></p>
<p>ISO 設定,自動 / 50 / 100 / 200 / 400 / 800 <br>
<img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga05UoRVoqokBeiKB4l46JytEZFD_LpAsQsW8pWE8LRpkE-oCUW615beUgd6ElW4QklRT7hZtnNVGl3J8eVDwXt5GtUZLO9s_YFX3JlGteWACK8q-6yo3SfkzIeMZ8kpGljMJESjWPiDc/s1600/Screenshot_2014-07-10-22-57-14.png" height="640" width="360"></p>
<p>相機解析度設定,最可以到 1300 萬畫素,而且也可以選擇 4:3 或 16:9 的比例 <br>
<img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh6c3As92OQnIa0GbRmxzlA44wgzS3OTsE3BWBCMXtLkZxnr6HhSRC_M_ZkiLYVHTVa1u09mlE87-zMTzrLjs_rIeLWdveqjjJFW5ZBgUWc9rSwPlFsqj5Ncl_ASVlNP9CoAcxF8gWFeYo/s1600/Screenshot_2014-07-10-22-57-35.png" height="640" width="360"></p>
<p>錄影的品質,有支援到 <strong>4K</strong> ! <br>
<img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZCNoQMrU0Wi8IG78vxA4VBVxDpW6XOm3HJwwjTASihTRko12n8dPBU5L4-uowtQ6JFi18QQUzMhH0l0BR20fbSUn7kae_UQ2pgPchZy6IxLzXQml8o1SbchhyphenhyphenN5zwPk0XC79EJfmTkKM/s1600/Screenshot_2014-07-10-22-58-08.png" height="640" width="360"></p>
<p>也整合了自動上傳的功能,自家的支援度百分百 <br>
<img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWj5nwp9BQSutkvvELUzE9eeMphvVGVsiQgp7PxfzkcgMuncpi_b5gODUc6UcgCXxznSGVwpnWh-N6n8LlavFKsW2ecfOG5F5kV0CyjIRbRBIq2iTvcjxgSCInl7WTyzmF7LaDLhnlkFE/s1600/Screenshot_2014-07-10-22-58-49.png" height="640" width="360"></p>
<p>也有許多種特效可以選擇,其中鉛筆類似 PaperCamera 將拍攝出來的圖改用鉛筆去重繪邊界的部分,有素描的感覺 <br>
<img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3famAK1x0ciOlQwm9LqzoTS0M4nrSbJ8h6q6JcaAxH_0x2_WfWrJV6U4z3qZTFjyG5_-mDZbEt38nisgGqcVhyphenhyphenytGyPvuaP4C7AN_vZBkH3dhqlFrM0cx-ejDCD6jFKRzldklhjDEj7M/s1600/Screenshot_2014-07-10-22-59-36.png" height="640" width="360"> <br>
<img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisIERy32FGeDOoM1MDCoWGR203v7GbllEYrtzwEb4XqVNLEp7WbjYcrZ-DsyX3St_w0y7QYTxOulYjvFAm7KSGQ6vRNGmRZD8ZoHXzyNyDniIrKIQ0ouWwodFWqB5PXE9PGaLjeoTpyJc/s1600/Screenshot_2014-07-10-22-59-41.png" height="640" width="360"></p>
<h1 id="zenui-asus-apps">ZenUI - ASUS APPS</h1>
<p>之前有用過 Asus 手機的使用者們對他們家的手機也有一些瞭解,Asus 也提供了許多自己加入的應用程式,有些還真不錯用 <br>
<img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinDZo0UwNUcI8qg5FSg7tBlxZ9wRdapHFPhkIGCyEkBjHVmCMBqXmZgXVw8SCBtOpZ8Ad32LC8UM_MCYHg1-58GnoAktUoUa2J_6V41cwfIV5Zr8UeSfVW6Mwhhy0cS-Gd7iETtBLMe-E/s1600/Screenshot_2014-07-10-23-01-40.png" height="640" width="360"></p>
<p>將通知列拉下也有許多快捷程式可以使用,這很多家手機製造商都會有快捷程式的功能,但這邊想提一下最左下角的那兩個功能 <br>
- 切換成 一般模式 / 閱讀模式 <br>
- 即時辭典 <br>
<img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEim_htmO6HtZxEICTJ1E3j5a9YsfqESyQ7pu0xvNDQqmD2xYfqrxKA5bBlABEYa5BPKV87htCa4WkdD2o-o9sNp0lQfpsEEQV9fVyuQKd-_C89Fmgv2Y5n5Fty7X_QDB9rfiYQg1_imCdw/s1600/Screenshot_2014-07-10-23-02-17.png" height="640" width="360"></p>
<ul>
<li>當切換到閱讀模式時,會看見畫面會舖蓋上一層淡黃色的圖層,效果像是濾藍光的眼鏡,讓眼睛在長時間的閱讀下比較舒服</li>
<li>當開始即時辭典時,畫面邊邊會出現一個圖案,如下圖 A|a ,先點一下來啟動,在你想要查的字上面劃過去,就會自動偵測該單字並將結果顯示在下圖中的視窗中,這功能在大部分的軟體都可以運作得很不錯,可以說是相當的實用</li>
</ul>
<p><img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1qlMWJXAQvB2JkqlUNMK2s_EottjcX9UGIQYuDZQxtV0Z5brE1_zhjfrZTIegSP7Qg5sh5okL_8oiIkpCGt_V541I_BHZCoXEP_LwJVdqAvga_KcuD-m85_h_0Opz2bEdN-YmhjeSbr0/s1600/Screenshot_2014-07-10-23-02-48.png" height="640" width="360"> <br>
<img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmDXnl-bKX_DIQmZr6yiPij_kNOPl3KwpdeAYlMr0gXheE6bSUmwde4KU3oUVb8GvnzykKHojlOk-A-cGkl1QG0a3kXmHES2_dIT3de4TASWNnnPv2Tc2QVfxWUyOabMD4KFA_APjTjPA/s1600/Screenshot_2014-07-10-23-04-52.png" height="640" width="360"></p>
<h1 id="設定">設定</h1>
<p>由於這次的手機其電池容量的相對小讓整體使用時間變短,為了延長使用時間,加入了智慧省電的功能,並能夠依據情境自訂省電模式 <br>
<img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGFIsJsaLB_ZszzYMDhCLawPLm-Mbfg4aUpAWAhjycyGuTgUUJmXWMfE6NNPQd8V_VzacvPdI2TJWr3ZH8h7DgmMzrehXbfNXOC8ppgPJsD3srtvzg9w2LK32LJkuoKhHKE0aWQp0ZtXU/s1600/Screenshot_2014-07-10-23-08-44.png" height="640" width="360"> <br>
自訂省電模式中,可以根據不同情境改變其亮度變化,不過也只能設定亮度而已,能夠自訂的選項稍嫌不夠,看起來還有進步的空間! <br>
<img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_-HBwbq5FFx4LqD1k3m2jzmsUP83KbbWJFmoumFb6HTTDatVnBTiAagwM7_he0vDSNxDLgQtyVuxdptLSs24AmI_jxL-p5B7kYOvEQaYqMeygzDpENn7-gpNYXOZfTxfo8x26iDKTpRQ/s1600/Screenshot_2014-07-10-23-09-12.png" height="640" width="360"></p>
<h1 id="所有硬體規格明細">所有硬體規格明細</h1>
<p>更詳細的資料在 <a href="https://drive.google.com/file/d/0B_48xBE_jKgjRkZqcVdFSXh3bUk/edit?usp=sharing">這裡</a> <br>
<img alt="" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOnsMPgItNH-CexMZ-IMtCL9CzlhMf9iScn49rg3eCGT9I1fQJCxNmYW47uuFugr-bBc5unliKZmZsTU0rTngoSPkUZ0-Wuk3J6Fg6eqpzPPfiJzV7tJK4ksVIQEOhmwvnPF42_9cS3TE/s1600/Screenshot_2014-07-10-23-11-29.png" height="640" width="360"></p>
<h1 id="最後">最後</h1>
<p>如果是想要買一台可以使用 4G LTE 服務的手機又不想花超過萬元,這台可以說是很不錯的選擇,畢竟可以省去不少找是否符合該電信商頻段的時間,又可以擁有頂級的硬體規格,最重要的是有現貨:),接下來也可以期待搭配的電信商方案價,有可能有不錯的便宜可以撿!</p>
<p>缺點的話,因為單純是就硬體上的標準來看,只能說他的電池容量小了點,還有它的背蓋有點不好拆,若要拔 SIM 卡或 SD 卡都還得先掀開被蓋的話,的確是有點不方便,但其實這影響並不是很大!</p>
<p>若還有測試或實際拍照圖也會隨時更新上來!</p>newmanhttp://www.blogger.com/profile/02106860573153331504noreply@blogger.com0tag:blogger.com,1999:blog-1053927668006720431.post-47534065693159506162014-07-11T23:43:00.001+08:002014-07-16T23:51:12.995+08:00五條港文學踏查隨筆(1)<h2 id="前情提要">
前情提要</h2>
每年博物館日,各大博物館都會舉行相對應的博物館慶祝活動,而台灣文學館的博物館玩文學,今年府城文學踏查路線「五條港穿越」,就是小弟一直很有興趣的<b>五條港</b>!!! <br />
研究所時賃居於南沙宮附近,散步範圍就是水仙宮、神農街,只是當時完全被府城小吃給征服,夏日總在國華街流連。離開之後才會想起當時常路過得廟宇,都有段歷史故事,回頭挖掘才會覺得自己錯過了多少。<br />
<a name='more'></a><h2 id="五條港">
五條港</h2>
<ul>
<li><a href="http://zh.wikipedia.org/wiki/%E4%BA%94%E6%A2%9D%E6%B8%AF_%28%E8%87%BA%E5%8D%97%29#.E6.96.B0.E6.B8.AF.E5.A2.98.E6.B8.AF" title="新港墘港">新港墘港(屎溝墘港)</a></li>
<li><a href="http://zh.wikipedia.org/wiki/%E4%BA%94%E6%A2%9D%E6%B8%AF_%28%E8%87%BA%E5%8D%97%29#.E4.BD.9B.E9.A0.AD.E6.B8.AF" title="佛頭港">佛頭港</a></li>
<li><a href="http://zh.wikipedia.org/wiki/%E4%BA%94%E6%A2%9D%E6%B8%AF_%28%E8%87%BA%E5%8D%97%29#.E5.8D.97.E5.8B.A2.E6.B8.AF" title="南勢港">南勢港</a></li>
<li><a href="http://zh.wikipedia.org/wiki/%E4%BA%94%E6%A2%9D%E6%B8%AF_%28%E8%87%BA%E5%8D%97%29#.E5.8D.97.E6.B2.B3.E6.B8.AF" title="南河港">南河港</a></li>
<li><a href="http://zh.wikipedia.org/wiki/%E4%BA%94%E6%A2%9D%E6%B8%AF_%28%E8%87%BA%E5%8D%97%29#.E5.AE.89.E6.B5.B7.E6.B8.AF" title="安海港">安海港</a></li>
</ul>
<h2 id="路線">
路線</h2>
<b>大井頭 -> 大西門、擔仔麵 -> 水仙宮、三益堂 -> 寶美樓 -> 景福祠 -> 聚福宮 -> 崇福宮 -> 媽祖樓 -> 集福宮、兌悅門 -> 全臺開基藥王廟、金華府 -> 接官亭、風神廟、西羅殿 -> 南沙宮 -> 開山宮</b><br />
這段路線,如果是資訊人大概會覺得如此蜿蜒曲折,一點都不符合最短路徑呀!(在台南的大日頭下,這根本就是整人呀) <br />
其實,規劃者的原意則是順著原本五條港的脈絡,一道道港口去探尋,也透過這樣的追尋,見證了歷史與人文的變遷。<br />
<img alt="大井頭" src="http://cloud.culture.tw/e_upload_ccacloud/case/DA09602000411/702be275-e973-4bc3-843b-8aae0d9f0fde.jpg" title="" /> <br />
路線始於大井頭(民權路與永福路交接口紅綠燈下),據說鄭和下西洋時,王景弘曾在此汲水。此井原本在碼頭邊,隨著台江內海的淤積,而逐漸形成街市。<br />
沿著民權路往西門路方向走一點,今金格蛋糕至宮後街部份就是昔日的大西門,大西門外也就是昔日碼頭,貨物至此卸貨,再運至倉庫,城門外也就是碼頭工人聚集之處。<br />
<blockquote>
<b>城外五大姓</b><br />
<table>
<thead>
<tr>
<th style="text-align: center;">姓氏</th>
<th style="text-align: center;">主要聚落</th>
<th style="text-align: center;">信仰中心</th>
<th style="text-align: center;">供奉</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center;">黃</td>
<td style="text-align: center;">新港墘港</td>
<td style="text-align: center;">集福宮</td>
<td style="text-align: center;">玄天上帝</td>
</tr>
<tr>
<td style="text-align: center;">蔡</td>
<td style="text-align: center;">佛頭港</td>
<td style="text-align: center;">聚福宮、崇福宮</td>
<td style="text-align: center;">玄天上帝</td>
</tr>
<tr>
<td style="text-align: center;">盧</td>
<td style="text-align: center;">南河港</td>
<td style="text-align: center;">南沙宮</td>
<td style="text-align: center;">黃包府千歲</td>
</tr>
<tr>
<td style="text-align: center;">郭</td>
<td style="text-align: center;">南河港</td>
<td style="text-align: center;">西羅殿</td>
<td style="text-align: center;">廣澤尊王</td>
</tr>
<tr>
<td style="text-align: center;">許</td>
<td style="text-align: center;">南勢港</td>
<td style="text-align: center;">金華府</td>
<td style="text-align: center;">關聖帝君</td>
</tr>
</tbody></table>
</blockquote>
<img alt="五條港五姓爭雄" src="http://www.nmth.gov.tw/Portals/0/epaper/watchtw_tw16/img/e_page/16/special_017.jpg" title="" /><br />
<blockquote>
<i>圖片來源</i>:<a href="http://www.nmth.gov.tw/Portals/0/epaper/watchtw_tw16/edm_c_p17.html">五條港五姓爭雄</a> </blockquote>
<img alt="水仙宮" src="http://cloud.culture.tw/e_upload_ccacloud/case/DA09602000374/16b25c36-8745-4913-8227-7427598bed44.jpg" height="480" title="" width="640" /> <br />
水仙宮主祀水仙尊王(大禹),也就是海神,來祈求航行平安。而配祀的就是奡王、楚王(項羽)、伍大夫(伍子胥)、屈大夫(屈原)等五位,俗稱「一帝二王二大夫」。三郊總部三益堂亦在此。<br />
溫馨習俗 - 避債戲 <br />
<b>「本來國寶自流通,每到年終妙手空;海外無臺堪避債,大家看劇水仙宮。」</b>~ 許南英《臺灣竹枝詞》 <br />
每到除夕,郊商會在除夕下午搭台演戲,一直到大年初一早上,讓躲債的人可以過個好年。如果有討債的硬要來討,反而會引起群情激憤XD<br />
<h3 id="待續">
<i>(待續…)</i></h3>
Anonymoushttp://www.blogger.com/profile/05724782384274251086noreply@blogger.com1tag:blogger.com,1999:blog-1053927668006720431.post-72942550251285291642014-07-10T09:36:00.003+08:002014-07-10T10:24:12.730+08:00IE 你別鬧了<p><a href="https://coderwall.com">coderwall</a> 是一個讓程式開發者上去分享技術心得的一個網站,以前會員登錄的時候可以填寫你熟悉哪些技術讓大家參考,不過coderwall的管理員發現大家都懶得填,統計下來幾乎有一半以上的會員只留空白,後來他們想到一個絕招,就是讓系統自動幫大家填寫預設的skill,預設值有兩個:</p><p>”Loving IE6”、”Visual Basic”。</p><p>這下好了,“老天勒~這是在污辱我嗎?”(我自己亂加的獨白),結果幾乎超過九成的會員看到後馬上跳出來認真填寫自己的skill並且把上面這兩個移除。</p><p><img src="https://farm4.staticflickr.com/3879/14370361180_9b2fcc1e4b_c.jpg" alt="enter image description here" title=""></p><p>會寫這件事,是因為最近公司有個工程師跑來向我反應IE上一個的script不能用,<br />
“拜託一定要支援IE啊!” “我們這邊大家都用IE耶!” 這樣子相當困擾地向我抱怨。<br />
後來發現firefox、chrome、safari都沒問題,唯獨就那個IE。真希望他可以上網看到這篇文章。</p><p>不過對IE最困擾的應該是屬於開發政府部門系統的外包廠商了,合約中常註明系統需支援IE某版本含以上,這痛苦的不是一直要支援新的IE版本,而是系統要一直支援舊版本的IE,因此一些外包廠商的規格還會出現ASP(不是ASP.NET喔)等現在久沒聽到的技術,簡直是無止盡的夢魘啊!</p><br />
<p>以上。</p><br />
<hr><ul><li><a href="https://coderwall.com/blog/2012-02-23-hating-on-IE6#disqus_thread">coderwall 的hating on IE6的blog</a></li>
<li>最後還是把IE不相容的問題解決了,看來是IE對大家用.html()來render網頁很有意見。-><a href="http://stackoverflow.com/questions/412734/jquery-html-attribute-not-working-in-ie">jquery html attribute not working on IE</a></li>
<li>為了要小心跟IE相處,我們可以更有效率地為自己寫的JavaScript除錯,<a href="https://github.com/krasimir/deb.js">deb.js library</a>很好用,下此有機會再來介紹這個library.</li>
</ul>Sam Chttp://www.blogger.com/profile/16142383609940270017noreply@blogger.com0tag:blogger.com,1999:blog-1053927668006720431.post-75452237234300904282014-07-09T10:40:00.001+08:002014-07-09T14:11:03.250+08:00UI Test Script for Android - 以Puzzle And Dragons自動轉珠為範例 (中)<h3 id="script-language">
Script Language</h3>
既然是要寫個auto test script, 當然一樣需要有一個script language, 這邊有兩個選擇, 一是你可以選擇自己寫一個, 或是直接使用現有的語言來使用, 以現在都在講求速率的年代來說, 我們當然不會選擇前者了, 而使用現有的script language, 到底要使用什麼語言比較好咧? 比較常見的腳本語言像是Ruby, Lua, Python, 優缺點的比較有興趣的人可以看看這篇文章: <a href="http://blog.csdn.net/gzlaiyonghao/article/details/1674808">Python、Lua和Ruby——脚本大P.K.</a> , 在這裡我選擇使用了遊戲界常用的輕量化及高效能的Lua來使用。 <br />
<br />
<a name='more'></a><br />
不過單純使用Lua的話, 一定沒有辦法完全符合我們的要求, 我們需要在Lua中建立新的API讓使用者可以透過它來達到與手機端溝通的功能,例如Touch, Drag, StartActivity …等各種指令, 所以我使用<a href="http://luaj.org/luaj/README.html">LuaJ</a>這個library, 它可以很輕鬆的在Lua中新增一些API供使用者來呼叫並執行我們想要的功能, 有關LuaJ的設定在此就不多說, 只簡單講解一下在Java中新增API的方法, 假設你要在Lua中建立一個function touch(x, y):<br />
<pre class="prettyprint prettyprinted"><code><span class="pln"> </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Manager</span><span class="pln"> </span><span class="kwd">extends</span><span class="pln"> </span><span class="typ">TwoArgFunction</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="lit">@Override</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="typ">LuaValue</span><span class="pln"> call</span><span class="pun">(</span><span class="typ">LuaValue</span><span class="pln"> modname</span><span class="pun">,</span><span class="pln"> </span><span class="typ">LuaValue</span><span class="pln"> env</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="typ">LuaValue</span><span class="pln"> library </span><span class="pun">=</span><span class="pln"> tableOf</span><span class="pun">();</span><span class="pln">
library</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"Touch"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Touch</span><span class="pun">());</span><span class="pln">
env</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"Manager"</span><span class="pun">,</span><span class="pln"> library</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Touch</span><span class="pln"> </span><span class="kwd">extends</span><span class="pln"> </span><span class="typ">TwoArgFunction</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="lit">@Override</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="typ">LuaValue</span><span class="pln"> call</span><span class="pun">(</span><span class="typ">LuaValue</span><span class="pln"> lv1</span><span class="pun">,</span><span class="pln"> </span><span class="typ">LuaValue</span><span class="pln"> lv2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> x </span><span class="pun">=</span><span class="pln"> lv1</span><span class="pun">.</span><span class="pln">checkint</span><span class="pun">();</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> y </span><span class="pun">=</span><span class="pln"> lv2</span><span class="pun">.</span><span class="pln">checkint</span><span class="pun">();</span><span class="pln">
</span><span class="com">// send touch event to device via IChimpDevice</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="kwd">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Send touch event to device"</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">boolean</span><span class="pln"> ret </span><span class="pun">=</span><span class="pln"> </span><span class="typ">ActionExecutor</span><span class="pun">.</span><span class="pln">execute</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">TouchAction</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">));</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ret</span><span class="pun">)?</span><span class="pln"> </span><span class="typ">LuaBoolean</span><span class="pun">.</span><span class="pln">TRUE</span><span class="pun">:</span><span class="typ">LuaBoolean</span><span class="pun">.</span><span class="pln">FALSE</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code></pre>
首先先建立一個class Manager, 用來管理各個新API, 在Manager中的call裡, 我們將新API-Touch註冊進library中, 並且設進Manager這一個變數,接著實作一個Touch class, TwoArgFunction為LuaJ的class, 代表你這一個Touch需要有兩個參數lv1及lv2, 我們透過.checkint()將他轉換回java中的integer, 並且將Touch event送到手機端。 <br />
完成class Manager的實作之後, 我們就可以嘗試著在Lua中呼叫實作完成的function Touch, 程式碼如下:<br />
<pre class="prettyprint prettyprinted"><code><span class="pln"> </span><span class="kwd">require</span><span class="pln"> </span><span class="str">'com.around35.lua.Manager'</span><span class="pln">
</span><span class="typ">Manager</span><span class="pun">.</span><span class="typ">Touch</span><span class="pun">(</span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">)</span></code></pre>
接著試著從java project中讀取上面的檔案, 就可以發現我們成功呼叫了Touch function了:<br />
<pre class="prettyprint prettyprinted"><code><span class="pln"> </span><span class="com">// Run lua script from java</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> runLuaScript</span><span class="pun">(</span><span class="typ">File</span><span class="pln"> file</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> file </span><span class="pun">!=</span><span class="pln"> </span><span class="kwd">null</span><span class="pln"> </span><span class="pun">&&</span><span class="pln"> file</span><span class="pun">.</span><span class="pln">exists</span><span class="pun">()</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="typ">Globals</span><span class="pln"> globals </span><span class="pun">=</span><span class="pln"> </span><span class="typ">JsePlatform</span><span class="pun">.</span><span class="pln">standardGlobals</span><span class="pun">();</span><span class="pln">
</span><span class="typ">LuaValue</span><span class="pln"> chunk </span><span class="pun">=</span><span class="pln"> globals</span><span class="pun">.</span><span class="pln">loadfile</span><span class="pun">(</span><span class="pln">file</span><span class="pun">.</span><span class="pln">getAbsolutePath</span><span class="pun">());</span><span class="pln">
</span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
chunk</span><span class="pun">.</span><span class="pln">call</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pun">(</span><span class="typ">Exception</span><span class="pln"> e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="typ">System</span><span class="pun">.</span><span class="kwd">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">e</span><span class="pun">.</span><span class="pln">toString</span><span class="pun">());</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code></pre>
之後我們想要新增API時, 只要建立新的class並且將它加進Manager中的library, 就可以在Lua中使用了。 <br />
以下是後來新增的API:<br />
<pre class="prettyprint prettyprinted"><code><span class="pln"> library</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"Touch"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Touch</span><span class="pun">());</span><span class="pln">
library</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"Wait"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Wait</span><span class="pun">());</span><span class="pln">
library</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"Sleep"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Sleep</span><span class="pun">());</span><span class="pln">
library</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"Click"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">PressImage</span><span class="pun">());</span><span class="pln">
library</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"Drag"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">PathDrag</span><span class="pun">());</span><span class="pln">
library</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"Type"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Type</span><span class="pun">());</span><span class="pln">
library</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"PressSysKey"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">PressSysKey</span><span class="pun">());</span><span class="pln">
library</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"Find"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">ObjectFinder</span><span class="pun">());</span><span class="pln">
library</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"FindAll"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">ObjectsFinder</span><span class="pun">());</span><span class="pln">
library</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"FindImage"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">FindImage</span><span class="pun">());</span><span class="pln">
library</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"StartActivity"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">StartActivity</span><span class="pun">());</span><span class="pln">
library</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"Capture"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">SaveImage</span><span class="pun">());</span><span class="pln">
library</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"Shell"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Shell</span><span class="pun">());</span><span class="pln">
library</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"AdbPull"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">AdbPull</span><span class="pun">());</span><span class="pln">
library</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span><span class="str">"AdbPush"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">AdbPush</span><span class="pun">());</span></code></pre>
至於API內部的實作方法, 除了需要圖形辨識外的API, 都可以從IChimpDevice的interface中得知如何實作, 在這邊就不多做介紹了。<br />
<div class="se-section-delimiter">
</div>
<h3 id="圖形辨識">
圖形辨識</h3>
在上一段落所列出來的API中, 讓我們在這一個段落為大家講解一下FindImage/Click這些API的實作吧! <br />
如果我們想要點擊下面這一個dialog中的ok button, 我們要怎麼做呢? <br />
<img alt="confirm mail/friend requset" src="https://dl.dropboxusercontent.com/u/4064196/images/pad_project/dialog.png" title="" /><br />
<img alt="ok button" src="https://dl.dropboxusercontent.com/u/4064196/images/pad_project/dialog_ok.png" title="" /><br />
有學過影像處理的人應該都很熟悉OpenCV這一個影像處理函式庫, 沒錯!要在一個圖像中尋找裡面的另一個sub-image,我們可以使用OpenCV中所提供的<a href="http://docs.opencv.org/doc/tutorials/imgproc/histograms/template_matching/template_matching.html">template matching</a>, 詳細底層運作方法可以參考網址內介紹, 講解的相當完整, 下列為實作的source code:<br />
<pre class="prettyprint prettyprinted"><code><span class="pln"> </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">boolean</span><span class="pln"> findImage</span><span class="pun">(</span><span class="pln">opencv_core</span><span class="pun">.</span><span class="typ">IplImage</span><span class="pln"> src</span><span class="pun">,</span><span class="pln"> opencv_core</span><span class="pun">.</span><span class="typ">IplImage</span><span class="pln"> </span><span class="kwd">template</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
opencv_core</span><span class="pun">.</span><span class="typ">IplImage</span><span class="pln"> result </span><span class="pun">=</span><span class="pln"> matchTemplate</span><span class="pun">(</span><span class="pln">src</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">template</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">double</span><span class="pun">[]</span><span class="pln"> maxVal </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="kwd">double</span><span class="pun">[</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
opencv_core</span><span class="pun">.</span><span class="typ">CvPoint</span><span class="pln"> maxLoc </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> opencv_core</span><span class="pun">.</span><span class="typ">CvPoint</span><span class="pun">();</span><span class="pln">
cvMinMaxLoc</span><span class="pun">(</span><span class="pln">result</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> maxVal</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> maxLoc</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">);</span><span class="pln">
cvReleaseImage</span><span class="pun">(</span><span class="pln">result</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> maxVal</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">>=</span><span class="pln"> THRESHOLD</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> opencv_core</span><span class="pun">.</span><span class="typ">IplImage</span><span class="pln"> matchTemplate</span><span class="pun">(</span><span class="pln">opencv_core</span><span class="pun">.</span><span class="typ">IplImage</span><span class="pln"> src</span><span class="pun">,</span><span class="pln"> opencv_core</span><span class="pun">.</span><span class="typ">IplImage</span><span class="pln"> tmp</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
opencv_core</span><span class="pun">.</span><span class="typ">IplImage</span><span class="pln"> result </span><span class="pun">=</span><span class="pln"> cvCreateImage</span><span class="pun">(</span><span class="pln">
cvSize</span><span class="pun">(</span><span class="pln">src</span><span class="pun">.</span><span class="pln">width</span><span class="pun">()-</span><span class="pln">tmp</span><span class="pun">.</span><span class="pln">width</span><span class="pun">()+</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> src</span><span class="pun">.</span><span class="pln">height</span><span class="pun">()-</span><span class="pln">tmp</span><span class="pun">.</span><span class="pln">height</span><span class="pun">()+</span><span class="lit">1</span><span class="pun">),</span><span class="pln"> IPL_DEPTH_32F</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
cvMatchTemplate</span><span class="pun">(</span><span class="pln">src</span><span class="pun">,</span><span class="pln"> tmp</span><span class="pun">,</span><span class="pln"> result</span><span class="pun">,</span><span class="pln"> CV_TM_CCORR_NORMED</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> result</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></code></pre>
透過OpenCV的matchTemplate, 我們就可以取到ok button在src image裡最匹配的位置, 然後我們判斷相似度如果大於等於THRESHOLD,那麼我們就可以視為找到了ok button。再配合上一章節開放的FindImage, 我們就可以在Lua Script中判斷ok button是否存在畫面上, 並且針對它做點擊或其他動作。<br />
Java part:<br />
<pre class="prettyprint prettyprinted"><code><span class="pln"> </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">FindImage</span><span class="pln"> </span><span class="kwd">extends</span><span class="pln"> </span><span class="typ">OneArgFunction</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="lit">@Override</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="typ">LuaValue</span><span class="pln"> call</span><span class="pun">(</span><span class="typ">LuaValue</span><span class="pln"> arg1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="typ">LuaString</span><span class="pln"> imageId </span><span class="pun">=</span><span class="pln"> arg1</span><span class="pun">.</span><span class="pln">checkstring</span><span class="pun">();</span><span class="pln">
</span><span class="typ">IplImage</span><span class="pln"> screen </span><span class="pun">=</span><span class="pln"> </span><span class="typ">OpenCVUtils</span><span class="pun">.</span><span class="pln">createFromBufferedImage</span><span class="pun">(</span><span class="pln">
</span><span class="typ">JavaMonkey</span><span class="pun">.</span><span class="pln">getInstance</span><span class="pun">().</span><span class="pln">takeSnapshot</span><span class="pun">().</span><span class="pln">getBufferedImage</span><span class="pun">());</span><span class="pln">
</span><span class="typ">IplImage</span><span class="pln"> </span><span class="kwd">template</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> cvLoadImage</span><span class="pun">(</span><span class="typ">CommonUtils</span><span class="pun">.</span><span class="pln">getFileName</span><span class="pun">(</span><span class="pln">imageId</span><span class="pun">.</span><span class="pln">toString</span><span class="pun">()));</span><span class="pln">
</span><span class="kwd">boolean</span><span class="pln"> ret </span><span class="pun">=</span><span class="pln"> </span><span class="typ">OpenCVUtils</span><span class="pun">.</span><span class="pln">findImage</span><span class="pun">(</span><span class="pln">screen</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">template</span><span class="pun">);</span><span class="pln">
screen</span><span class="pun">.</span><span class="pln">release</span><span class="pun">();</span><span class="pln">
cvReleaseImage</span><span class="pun">(</span><span class="kwd">template</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ret</span><span class="pun">)?</span><span class="pln"> </span><span class="typ">LuaBoolean</span><span class="pun">.</span><span class="pln">TRUE</span><span class="pun">:</span><span class="typ">LuaBoolean</span><span class="pun">.</span><span class="pln">FALSE</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code></pre>
Lua part:<br />
<pre class="prettyprint prettyprinted"><code><span class="pln"> </span><span class="kwd">require</span><span class="pln"> </span><span class="str">'com.around35.lua.Manager'</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="typ">Manager</span><span class="pun">.</span><span class="typ">FindImage</span><span class="pun">(</span><span class="str">'ok_button'</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">then</span><span class="pln">
</span><span class="kwd">print</span><span class="pun">(</span><span class="str">'find ok button'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">end</span></code></pre>
如果我們想要點擊找到的ok button要怎麼做呢, 眼尖的人會發現在cvMinMaxLoc中有一個maxLoc參數, 是的, 在呼叫cvMinMaxLoc之後我們就可以取得最相似圖片的Position(x, y), 所以我們就可以利用這個位置來做點擊按鈕的動作了。 <br />
Java part:<br />
<pre class="prettyprint prettyprinted"><code><span class="pln"> </span><span class="typ">IplImage</span><span class="pln"> screen </span><span class="pun">=</span><span class="pln"> </span><span class="typ">OpenCVUtils</span><span class="pun">.</span><span class="pln">createFromBufferedImage</span><span class="pun">(</span><span class="typ">JavaMonkey</span><span class="pun">.</span><span class="pln">getInstance</span><span class="pun">().</span><span class="pln">takeSnapshot</span><span class="pun">().</span><span class="pln">getBufferedImage</span><span class="pun">());</span><span class="pln">
</span><span class="typ">IplImage</span><span class="pln"> </span><span class="kwd">template</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> cvLoadImage</span><span class="pun">(</span><span class="typ">CommonUtils</span><span class="pun">.</span><span class="pln">getFileName</span><span class="pun">(</span><span class="pln">imageId</span><span class="pun">.</span><span class="pln">toString</span><span class="pun">()));</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> offsetX </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">template</span><span class="pun">.</span><span class="pln">width</span><span class="pun">()</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> offsetY </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">template</span><span class="pun">.</span><span class="pln">height</span><span class="pun">()</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">double</span><span class="pun">[]</span><span class="pln"> maxVal </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="kwd">double</span><span class="pun">[</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
</span><span class="typ">CvPoint</span><span class="pln"> maxLoc </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">CvPoint</span><span class="pun">();</span><span class="pln">
</span><span class="typ">IplImage</span><span class="pln"> result </span><span class="pun">=</span><span class="pln"> </span><span class="typ">OpenCVUtils</span><span class="pun">.</span><span class="pln">matchTemplate</span><span class="pun">(</span><span class="pln">screen</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">template</span><span class="pun">);</span><span class="pln">
cvMinMaxLoc</span><span class="pun">(</span><span class="pln">result</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> maxVal</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">,</span><span class="pln"> maxLoc</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> maxVal</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">>=</span><span class="pln"> THRESHOLD </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">TouchEvent</span><span class="pun">(</span><span class="pln">maxLoc</span><span class="pun">.</span><span class="pln">x</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> offsetX</span><span class="pun">,</span><span class="pln"> maxLoc</span><span class="pun">.</span><span class="pln">y</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> offsetY</span><span class="pun">).</span><span class="pln">execute</span><span class="pun">(</span><span class="pln">device</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></code></pre>
Lua part:<br />
<pre class="prettyprint prettyprinted"><code><span class="pln"> </span><span class="kwd">require</span><span class="pln"> </span><span class="str">'com.around35.lua.Manager'</span><span class="pln">
</span><span class="typ">Manager</span><span class="pun">.</span><span class="typ">Click</span><span class="pun">(</span><span class="str">'ok_button'</span><span class="pun">)</span></code></pre>
完成這個段落後, 我們就可以透過一些基本指令來撰寫簡單的auto test程式了, 下面為一個簡單的範例-進到龍族拼圖中並觀看第一封信:<br />
<pre class="prettyprint prettyprinted"><code><span class="pln"> </span><span class="kwd">require</span><span class="pln"> </span><span class="str">'com.around35.lua.Manager'</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">StartPAD</span><span class="pun">()</span><span class="pln">
</span><span class="typ">Shell</span><span class="pun">(</span><span class="str">'am start -n jp.gungho.padHT/jp.gungho.padHT.AppDelegate'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Sleep</span><span class="pun">(</span><span class="lit">15.0</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">
</span><span class="kwd">function</span><span class="pln"> </span><span class="typ">PressOk</span><span class="pun">()</span><span class="pln">
</span><span class="pun">--</span><span class="pln"> wait ok button </span><span class="kwd">for</span><span class="pln"> </span><span class="lit">50</span><span class="pln"> seconds
</span><span class="typ">Wait</span><span class="pun">(</span><span class="str">'ok'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">)</span><span class="pln">
</span><span class="pun">--</span><span class="pln"> find all ok </span><span class="kwd">and</span><span class="pln"> press all of them
</span><span class="kwd">for</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="typ">FindImage</span><span class="pun">(</span><span class="str">'ok'</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">then</span><span class="pln">
Click</span><span class="pun">(</span><span class="str">'ok'</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Sleep</span><span class="pun">(</span><span class="lit">5.0</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">else</span><span class="pln">
</span><span class="kwd">break</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">
</span><span class="kwd">end</span><span class="pln">
</span><span class="typ">StartPAD</span><span class="pun">()</span><span class="pln">
</span><span class="pun">--</span><span class="pln"> wait the title </span><span class="str">'puzzle & dragons'</span><span class="pln"> appears </span><span class="kwd">for</span><span class="pln"> </span><span class="lit">20</span><span class="pln"> seconds
</span><span class="typ">Wait</span><span class="pun">(</span><span class="str">'puzzle'</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Sleep</span><span class="pun">(</span><span class="lit">2.0</span><span class="pun">)</span><span class="pln">
</span><span class="pun">--</span><span class="pln"> click the screen
</span><span class="typ">Touch</span><span class="pun">(</span><span class="lit">312</span><span class="pun">,</span><span class="lit">462</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Sleep</span><span class="pun">(</span><span class="lit">5.0</span><span class="pun">)</span><span class="pln">
</span><span class="typ">PressOk</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="typ">FindImage</span><span class="pun">(</span><span class="str">'mail'</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">then</span><span class="pln">
</span><span class="typ">Click</span><span class="pun">(</span><span class="str">'read_mail'</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">end</span></code></pre>
不過大家看到這邊一定有個疑問, 每台手機的解析度不是都不一樣嗎, 那同樣的script如果跑在不一樣的手機上面能不能使用呢? 這個答案是Yes也是No, Script本身當然不需要做修改, 但是圖片辨識的部分如果是利用template matching的話, 受限於他的實作方法, 所以只能在同樣解析度的手機上辨識成功, 大家一定都會想說: 這樣不是很麻煩嗎, 你總不可能每一種解析度都再去抓一次圖吧。對於這個問題, 其實是有解法的, 這一個方法就是<a href="http://en.wikipedia.org/wiki/Scale-invariant_feature_transform">SIFT(Scale-invariant feature transform)</a>, SIFT可以將圖片中的區域特徵點計算出來, 並且透過這些特徵點來判斷sub-image是否存在於原始圖像中, 即使是旋轉或是縮放過的圖像也可以比對出來, 是個相當強大的演算法, 有興趣的人可以研究看看囉。<br />
待續Anonymoushttp://www.blogger.com/profile/17715762577846106669noreply@blogger.com0tag:blogger.com,1999:blog-1053927668006720431.post-5021730343950123082014-07-08T08:00:00.001+08:002014-07-08T18:03:30.190+08:00[心得] 超效率時間整理術<p>年輕時最大的本錢就是<strong>時間</strong>,年紀漸長後最缺乏的也是<strong>時間</strong>。財富沒了還有機會賺回來,健康沒了也許還是有機會可以恢復,但是時間卻是人生唯一不可逆的資產。而時間也是這世界給予人們最公平的東西,每個人的一天都是24小時,端看你如何去運用。</p>
<p>現在人的事情太多,總覺得時間不夠用,所以坊間一直有許多教人管理時間的書,當然最有名的就屬<a href="http://www.amazon.com/Getting-Things-Done-Stress-Free-Productivity/dp/0142000280">Get Thing Done</a>這本書了。這本書所講的管理方法,一般稱為GTD,目前有很多工具不管是桌面軟體、Web app還是Mobile app都可以找到一堆GTD的工具。關於GTD的部份就不在此多論述,有興趣的人可以去google查詢<strong>GTD</strong>這個關鍵字。 <br>
<a name='more'></a> <br>
<img src="http://im1.book.com.tw/image/getImage?i=http://www.books.com.tw/img/001/050/48/0010504862.jpg&w=348&h=348" alt="封面" title=""></p>
<p>今天主要來分享一下,最近看過的一本書,書名叫”<strong>就是愛偷懶!超效率時間整理術</strong>“,其實好像很久以前就看過了,最近又重新看了一遍。作者本身就是對時間沒有概念,事情總在最後一刻才匆匆忙忙趕完,工作效率總是一團亂。而這本書用<strong>漫畫</strong>的方式,詼諧幽默的呈現了作者本身管理時間的問題,透過什麼樣的方式去改善。這本書我覺得比較著重在觀念的部份,比起一般坊間教條式的說明或是強調特定工具的應用來說,對於一般讀者反而更能夠有感受。</p>
<p>要學習理財之前,要先知道自己的錢都花在什麼地方。當然,如果要學習時間管理,也要知道自己的時間都花在什麼地方上。所以紀錄每天什麼時間做了什麼事,可以說是時間管理的第一步。</p>
<p>以下列一些書上提出的觀念。</p>
<ol>
<li><p>彙整待辦事項 </p>
<ul><li>把<strong>同類</strong>的待辦事項彙整起來,例如都需要上網或用到電腦的工作,就一起做完。都要去超商買東西,就順便把未繳的帳單繳一繳。</li>
<li>把<strong>有關</strong>的待辦事項彙整起來,如收到mail之後就立刻回覆。</li>
<li>把<strong>時段相近</strong>的待辦事項彙整起來</li></ul>
<p>透過彙整的方式,讓這些事情變成一個SET的方式,一次處理掉。例如書上所提早上SET就是起床、上廁所、倒垃圾、量體重、沖澡、早餐的米先泡水、看報紙(8:00)。一口氣把彙整的事情解決掉,掛心的待辦事項就會大幅減少。透過待辦事項的彙整,也可以讓你的視野更清晰,不在感覺工作像是一團亂。</p></li>
<li><p>無論多棒的點子,也不能想到就立刻身體力行去做,而是應該先以事後可以回想起來的方式紀錄起來。就像你處理目前工作時,突然想到一件事情需要去google查,這時候應該先將想查的東西紀錄起來,然後專心完成目前的工作。</p></li>
<li><p>在意的或是無可避免的待辦事項,要立刻處理,避免一個心懸在那裡。</p></li>
<li><p>避免坐立難安的等待。例如你發了一封信給某人,如果短時間內沒收到回應,為了避免等待心理導致坐立難安,這時間應該要將事情紀錄到一個未完成的項目,上面寫著幾點後再確認看看。不要讓自己處在等待的狀況。</p></li>
<li><p>時間密度,人的專注力是有限的,效率也會隨著時間下降,所以當你感覺到效率不佳的時候,可以透過不同工作的轉換或是一些環境上的轉換,例如是聽個音樂喝個咖啡,來提昇工作時間的密度。</p></li>
</ol>
<p>這本書以漫畫的方式輕鬆呈現,沒有什麼長篇大論而且內容有趣又實用,這本書簡單易懂,有興趣的人可以去看一下。</p>misgodhttp://www.blogger.com/profile/00933441299043629398noreply@blogger.com1tag:blogger.com,1999:blog-1053927668006720431.post-76976213051384101292014-07-07T08:00:00.000+08:002014-07-07T10:09:44.312+08:00[投影片] Regular Expression 101<p><strong>Regular Expression</strong>(正規表示式)或簡寫<strong>Regex</strong>,是一個滿有趣的東西。一般的程式設計師都聽過,也可能有用過,大部分都是找範例剪剪貼貼湊出式子。實際上我很少遇到自稱熟Regular Expression的人。或許是因為Regular Expression是由一堆符號組成,看起來有點複雜讓人望之卻步,但是其實只要花個兩三天的時間好好的認識它跟稍微練習一下,之後你會感受到百倍的回報。 </p>
<h3 id="為什麼學regex">為什麼學Regex</h3>
<a name='more'></a>
<p>拜網路與資訊技術快速的發展,每年總是不斷有新名詞、新語言或是新技術產生,身為一個資訊產業的工作者,總是會必須不斷學習新的東西,但是很多技術也隨著時間而慢慢淘汰消失。從投資報酬的角度來看,學習Regex絕對是一個穩賺不賠的投資。</p>
<p>Regex的概念始於1956年,而真正流行起來是在1968年(我都還沒出生),到現在仍然廣泛的應用在不同的語言跟工具中。在資訊領域中,有什麼工具是可以歷經50年以上還可以歷久不衰,而且不受到個別程式語言興衰的影響,讓你<strong>Learn Once, Write Everywhere</strong>(<em>註: 好啦! 其實也沒那麼美好,不同語言有不同的擴充跟支援</em>)。 </p>
<p>下面分享我在學習Regex時所作的投影片,主要透過例子來學習Regex的一些基礎入門。 </p>
<p><a href="http://misgod.github.io/slides/regex101.html">投影片原始位置</a></p>
<p><iframe src="//misgod.github.io/slides/regex101.html" allowfullscreen="" frameborder="0" height="480" width="800"></iframe> </p>misgodhttp://www.blogger.com/profile/00933441299043629398noreply@blogger.com0tag:blogger.com,1999:blog-1053927668006720431.post-1486243640589750302014-07-06T14:06:00.001+08:002014-07-06T14:12:15.894+08:00在Android上使用Facebook API<p>要在Android上使用Facebook的API,可以使用Facebook Android SDK,使用上其實不太困難,不過要設定一開始的環境還蠻搞剛的,所以稍微將步驟紀錄一下。 </p><div class="se-section-delimiter"></div>
<h3 id="開始設定">開始設定</h3>
<ol>
<li><p><a href="https://developers.facebook.com/resources/facebook-android-sdk-current.zip">下載</a>最新版的Facebook Android SDK,根據你的IDE放到project裡面。 <br>
或是直接使用別人包好的aar</p>
<blockquote>
<p>compile ‘fr.avianey:facebook-android-api:+@aar’</p>
</blockquote></li>
<li><p>產生Key hash (修改紅字部份)</p>
<blockquote>
<p>keytool -exportcert -alias <span style="color:red">androiddebugkey</span> -keystore <span style="color:red">~/.android/debug.keystore</span> | openssl sha1 -binary | openssl base64 </p>
</blockquote></li>
</ol>
<p><a name='more'></a> <br>
3. 到<a href="http://developers.facebook.com/">Facebook開發者網站</a>,登入後點選右上角的照片,然後選擇<strong>Developer Settings</strong>。</p>
<ol>
<li><p>切換到<strong>Sample App</strong>的頁面,填入你步驟2得到的<strong>Key Hash</strong>,可以同時填入多個keyhash,然後按Save。</p></li>
<li><p>建立一個Facebook App</p>
<ol><li><p>前往<a href="https://developers.facebook.com/apps">這裡</a>,還沒註冊過開發者的話要先點Register Now,完成註冊動作。 </p></li>
<li><p>點選最上面的<strong>Apps > Create a New App</strong>,完成App註冊的動作。</p></li>
<li><p>完成後畫面上會顯示<strong>App ID</strong>跟<strong>App Secret</strong> </p></li></ol></li>
<li><p>點選左方的<strong>Settings</strong>,然後點選右方下面的 <strong>+Add Platform</strong>,選<strong>Android</strong>。</p>
<blockquote>
<ul><li>填入你的Android app的<strong>packaga name</strong></li>
<li>填入你的<strong>Activity class name</strong>,非必要</li>
<li>步驟2產生的的<strong>Key Hash</strong> </li>
<li>打開<strong>Single Sign On</strong></li></ul>
</blockquote></li>
<li><p>Android App的設定</p>
<ol><li><p>在你的Android App的<strong>res/string.xml</strong>,加上 </p>
<pre style="" class="prettyprint prettyprinted"><code><span class="tag"><string</span><span class="pln"> </span><span class="atn">name</span><span class="pun">=</span><span class="atv">"app_id"</span><span class="tag">></span><span class="pln">你的App ID(步驟5)</span><span class="tag"></string></span></code></pre></li>
<li><p>然後在<strong>AndroidManifest.xml</strong> 加上 <strong>use-permission</strong>跟<strong>metadata</strong></p>
<pre style="" class="prettyprint prettyprinted"><code><span class="tag"><uses-permission</span><span class="pln"> </span><span class="atn">android:name</span><span class="pun">=</span><span class="atv">"android.permission.INTERNET"</span><span class="tag">/></span><span class="pln">
</span><span class="tag"><application</span><span class="pln"> ...</span><span class="tag">></span><span class="pln">
...略...
</span><span class="tag"><meta-data</span><span class="pln"> </span><span class="atn">android:name</span><span class="pun">=</span><span class="atv">"com.facebook.sdk.ApplicationId"</span><span class="pln"> </span><span class="atn">android:value</span><span class="pun">=</span><span class="atv">"@string/app_id"</span><span class="tag">/></span><span class="pln">
</span><span class="tag"></application></span></code></pre></li>
<li><p>新增<strong>LoginActivity</strong>在你的<strong>AndroidManifest.xml</strong></p>
<pre style="" class="prettyprint prettyprinted"><code><span class="tag"><activity</span><span class="pln"> </span><span class="atn">android:name</span><span class="pun">=</span><span class="atv">"com.facebook.LoginActivity"</span><span class="tag">/></span></code></pre></li></ol></li>
<li><p>測試Facebook登入</p>
<ul><li>把下面這段code放到你的MainActivity <strong>onCreate</strong>的最後面。</li></ul>
<pre style="" class="prettyprint prettyprinted"><code class="language-java"><span class="com">// start Facebook Login</span><span class="pln">
</span><span class="typ">Session</span><span class="pun">.</span><span class="pln">openActiveSession</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Session</span><span class="pun">.</span><span class="typ">StatusCallback</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">// callback when session changes state</span><span class="pln">
</span><span class="lit">@Override</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> call</span><span class="pun">(</span><span class="typ">Session</span><span class="pln"> session</span><span class="pun">,</span><span class="pln"> </span><span class="typ">SessionState</span><span class="pln"> state</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Exception</span><span class="pln"> exception</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">session</span><span class="pun">.</span><span class="pln">isOpened</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">// make request to the /me API</span><span class="pln">
</span><span class="typ">Request</span><span class="pun">.</span><span class="pln">newMeRequest</span><span class="pun">(</span><span class="pln">session</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Request</span><span class="pun">.</span><span class="typ">GraphUserCallback</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="com">// callback after Graph API response with user object</span><span class="pln">
</span><span class="lit">@Override</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> onCompleted</span><span class="pun">(</span><span class="typ">GraphUser</span><span class="pln"> user</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Response</span><span class="pln"> response</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">user </span><span class="pun">!=</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="typ">Toast</span><span class="pun">.</span><span class="pln">makeText</span><span class="pun">(</span><span class="pln">getApplicationContext</span><span class="pun">(),</span><span class="pln"> </span><span class="str">"Hello "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> user</span><span class="pun">.</span><span class="pln">getName</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">"!"</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Toast</span><span class="pun">.</span><span class="pln">LENGTH_LONG</span><span class="pun">).</span><span class="pln">show</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}).</span><span class="pln">executeAsync</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span></code></pre>
<ul><li>加上<strong>onActivityResult</strong></li></ul>
<pre style="" class="prettyprint prettyprinted"><code><span class="lit">@Override</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> onActivityResult</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> requestCode</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> resultCode</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Intent</span><span class="pln"> data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">super</span><span class="pun">.</span><span class="pln">onActivityResult</span><span class="pun">(</span><span class="pln">requestCode</span><span class="pun">,</span><span class="pln"> resultCode</span><span class="pun">,</span><span class="pln"> data</span><span class="pun">);</span><span class="pln">
</span><span class="typ">Session</span><span class="pun">.</span><span class="pln">getActiveSession</span><span class="pun">().</span><span class="pln">onActivityResult</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">,</span><span class="pln"> requestCode</span><span class="pun">,</span><span class="pln"> resultCode</span><span class="pun">,</span><span class="pln"> data</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></code></pre></li>
</ol>
<p><br></p>
<p><strong>如果可以看到Facebook登入權限的要求,然後登入看到Toast,那就是成功了。</strong></p>misgodhttp://www.blogger.com/profile/00933441299043629398noreply@blogger.com0tag:blogger.com,1999:blog-1053927668006720431.post-39033353401883914552014-07-05T22:36:00.000+08:002014-07-05T22:58:43.952+08:00如何發佈 App 到 Google Play - 建造出 APK 檔案<h2 id="前言">前言</h2>
<p>當完成一個 App 時,想分享給大家使用時,或許可以透過幾種方式分享給大家</p>
<ul>
<li>將 Apk 檔案放到網站上讓任何人下載到手機上安裝或將檔案傳送給朋友</li>
<li>將 App(Apk 檔案) 發佈到 Google Play 商店</li>
</ul>
<p>但相對安全也是比較有系統性的當然是放到 Google Play 商店上,而且還有許多優點: <br>
<a name='more'></a></p>
<ul>
<li>發佈時 <br>
<ul><li>可以有不同階段性的測試版本 Alpha / Beta / Release</li>
<li>協助翻譯</li>
<li>設定可下載的國家 / 電信商 / 手機</li>
<li>給予不同國家的使用者有相對應語系的簡介或圖片</li>
<li>檢驗 Apk 是否符合預期,例如 versionCode 是否有比前一個版本大,簽署的 keystore 是否有符合規定</li>
<li>是否要營利,付費與否,程式內部購買,廣告</li></ul></li>
<li>統計 <br>
<ul><li>透過管理介面看到各項數據統計,安裝人數、安裝使用者來源、安裝使用者 Android 版本…等等</li>
<li>財報</li>
<li>當機或 ANR 的報告</li>
<li>使用者的評論、感想、建議,也有不錯的回覆系統,跟使用者搭上橋梁</li></ul></li>
</ul>
<p>以上種種優點不只可以讓你輕易的管理你的 App,也能夠讓你的 App 得到最好的建議與回饋。那既然要放到 Google Play 上,當然也就要好好的遵守 Google Play 所訂的遊戲規定。今天來談談幾個比較關鍵的規定!</p><div class="se-section-delimiter"></div>
<h2 id="build-出你的-apk-然後發佈到-google-play">Build 出你的 APK 然後發佈到 Google Play</h2>
<p>在開發的過程中要生成一個 App 是非常容易的。</p>
<p>在 Android Studio 中點 <strong>Run->Run ‘android’</strong> 就會自動產生一個 Apk 檔案並安裝進手機中,也可以在目前工作目錄下<strong>{<span>$</span>ProjectFolder}/android/build/outputs/apk/{<span>$</span>ProjectName}.apk</strong> 找到所產生出來的 apk 檔案</p>
<blockquote>
<p>PS. 由 Eclipse build 出來的 apk 則在<strong>{<span>$</span>ProjectFolder}/bin/{<span>$</span>ProjectName}.apk</strong></p>
</blockquote>
<p>接著馬上把它發佈到 Google Play Developer Console 的時候就會發生錯誤,也表示要上傳到 Google Play 商店並不那麼的容易需要動一些手腳,來看看發生了哪些錯誤</p>
<ul>
<li>要在 AndroidManifest.xml 中設定 android:debuggable 設成 false </li>
<li>要用自己的憑證來簽署這個 apk</li>
<li>第三個錯誤是因為 Google Play 上面已經有個同樣 package name 的 App</li>
</ul>
<p><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUjKxRfiNBK_tqkMWCozMaq5OzV1ca0INE2mjDsk4oFNCQN_ff-S32voukpvOUAyyi4M8sGS6pe4NNL284JBKP6hjLKwg7Qv70KVp3kx0iPMvpgqK6V_PUX-_RbFUXvLI-jQZjefk1wME/s320/build_app_error_uploading_non_signed_apk.png" alt="Fail to publish Apk file" title=""></p><div class="se-section-delimiter"></div>
<h2 id="解決問題">解決問題</h2>
<h4 id="問題1">問題1</h4>
<p>從錯誤提示中給的<a href="http://developer.android.com/tools/device.html#setting-up">連結</a>可以看到可以直接在 AndroidManifest.xml 中設定</p>
<pre class="prettyprint prettyprinted"><code class="language-Java"><span class="pln">android</span><span class="pun">:</span><span class="pln">debuggable</span><span class="pun">=</span><span class="str">"false"</span></code></pre>
<p>讓 Android 系統無法針對你的 App 偵錯,達成停用偵錯功能,但新增這行以後你會發現 Lint(*1) 會顯示錯誤 (ID : AndroidLintHardcodedDebugMode(*2)) </p>
<blockquote>
<p>Avoid hardcoding the debug mode; leaving it out allows debug and release builds to automatically assign one</p>
</blockquote>
<p>從錯誤提示來看,就是不要 hardcode 而是在決定要 build 成哪種 apk 的時候系統就會自動切換設定,要切換的話只要在 Android Studio 畫面的左下方有個 <strong>Build Variants</strong> 的 tab 點開來後可以選擇要生成 release / debug 版本的 apk 了 <br>
<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJV1r26hDXBQgKzcZCcj8Rpr2PMslSauSP_Yy_i4QsU-1CqWCqf-POTZ7JjuJaPH2cBe0OaZMGf_0XNMQIb3BywYhycYg232ROBPNVoVg7rZMSihg0BLp68HacFiEhxGmVsiSgRm_5tsk/s320/build_app_build_variants.png" alt="Android Sudio - Build Variants" title=""></p><div class="se-section-delimiter"></div>
<h4 id="問題2">問題2</h4>
<p>主要是因為我們在測試開發時期的 keystore 若沒有去變動的話其實都是用 debug.keystore (~/.andriod/debug.keystore),當然也可以手動去更改要簽署的 keystore 為何(看個人需求,有些 App 需要系統的權限,就要簽署系統的 keystore),從</p>
<blockquote>
<p><strong>File->Project Structure</strong> 點開後,選擇你的 <strong>module</strong> 再選右邊的 <strong>Signing</strong> tab 就可以去更改不同的 keystore <br>
<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXwT9xYNCX8UXM4CKhrQzq8dhKLB9ehS7hZ8t-t7PqHYGA6ObiaHN7iTxVEA_62AidCn5emOaHl76Ft41gFAa7uDPijMzvszIpftcKwy5PK7HGminXGsawP_skuhsvNf2zVj7TOTk1GxM/s320/build_app_debug_signing.png" alt="Debug Signing" title=""></p>
</blockquote>
<p>而這個錯誤就是要要求開發者要簽署自己的憑證,那憑證怎麼來呢?直接使用 keytool 指令來產生,在執行時,keysize 一定要用 2048 bit(太少 bit 已經不安全),若要上 Google Play 其憑證的有效日期一定要<strong>晚於2033/10/22</strong>,不然一定會發佈失敗也就是建議 validity 至少要填 10000</p><div class="se-section-delimiter"></div>
<pre class="prettyprint prettyprinted"><code class="language-bash"><span class="pln">keytool </span><span class="pun">-</span><span class="pln">genkey </span><span class="pun">-</span><span class="pln">v </span><span class="pun">-</span><span class="pln">keystore release</span><span class="pun">-</span><span class="pln">mine</span><span class="pun">.</span><span class="pln">keystore
</span><span class="pun">-</span><span class="kwd">alias</span><span class="pln"> alias_name </span><span class="pun">-</span><span class="pln">keyalg RSA </span><span class="pun">-</span><span class="pln">keysize </span><span class="lit">2048</span><span class="pln"> </span><span class="pun">-</span><span class="pln">validity </span><span class="lit">10000</span></code></pre>
<p><a href="http://docs.oracle.com/javase/6/docs/technotes/tools/windows/keytool.html">KeyTool 更多的資訊</a></p>
<p>產生出來的 keystore 就是你自己的憑證了!只要 Project Structure 選擇你的 module 再點選 release(如下圖,沒有的話可以自己新增),再將 Key Alias / Key Password / Key path / Store Password 填到對應的欄位,圖例為35around.keystore <br>
<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjc91bEPGC7lPsTUKwn2NDjeRvJIxYbEjQrcz_pQHRfCZlb4qcmRvxpoWHfedLG827h7xd1JfYJXQgdQEbH3bUGgX-xHgPuyP_3BXzUK5_agR_0_CJR7TROHWBTYVzKbXMvNxiHt3gis3c/s320/build_app_release_signing.png" alt="Release Signing" title=""></p>
<p>或者是在 build.gradle 裡面寫,也可以設定不同的版本使用不同的 keystore</p>
<pre class="prettyprint prettyprinted"><code class="language-Java"><span class="pln">android </span><span class="pun">{</span><span class="pln">
signingConfigs </span><span class="pun">{</span><span class="pln">
release </span><span class="pun">{</span><span class="pln">
storeFile file</span><span class="pun">(</span><span class="str">'yourKeyStoreFilePath'</span><span class="pun">)</span><span class="pln">
keyAlias </span><span class="str">'yourKeyAlias'</span><span class="pln">
keyPassword </span><span class="str">'yourKeyPassword'</span><span class="pln">
storePassword </span><span class="str">'yourStorePassword'</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
debug </span><span class="pun">{</span><span class="pln">
storeFile file</span><span class="pun">(</span><span class="str">'yourDebugKeyStoreFilePath'</span><span class="pun">)</span><span class="pln">
</span><span class="pun">...</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code></pre>
<h4 id="問題3">問題3</h4>
<p>將 package name 改成沒有人用過得就可以了!</p>
<h2 id="最後">最後</h2>
<p>以上問題都解決以後,在 Android Studio IDE 中點 <strong>Build->Generate Signed APK…</strong> 按照著步驟走就會看到要選 keystore 的畫面,填完選下一步 <br>
<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9zdTBGgTk70px68DrIHzK8LwZd4oGFzpenmwq5qWXQTy_pLqyON8XVfSD_JBv6lzhDZIZg7Mw-IwVrfhM2ccPCDwOFf7rbpViSILPbwMtF5aTm46SZ7EQmkb2QdWwlEodTpjzFqVCFQ0/s320/build_app_wizard_keystore.png" alt="Generate Signed APK Wizard - KeyStore" title=""> <br>
接著是選擇要不要跑 ProGuard 和設定輸出的 APK 檔案,最後點 <strong>Finish</strong> <br>
<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEie7egVUhjJuRg3i7I-3A14U9kXpbcTrjEwp4_eGA_qF0x5Ebx0qAgWxWObEy2HF8NFAn-MeAqO9Ff24qGdKoY97PX9eHXecdL4sOugx3keQEi2cCcsZTKdMuPLkkDPHBsT1fu8lX6GpHM/s320/build_app_wizard_proguard.png" alt="Generate Signed APK Wizard - " title=""> <br>
再等個一下 APK 檔案就產生了!也就可以把檔案發佈到 Google Play 上了!</p>
<h2 id="eclipse呢">Eclipse呢?</h2>
<p>簡單的步驟如下: <br>
1.在專案點右鍵 <strong>Andriod Tools->Export Unsigned Application Package</strong> 選擇 APK 檔案路徑 <br>
2.簽署你的 APK</p>
<pre class="prettyprint prettyprinted"><code class="language-bash"><span class="pln">jarsigner </span><span class="pun">-</span><span class="pln">verbose </span><span class="pun">-</span><span class="pln">sigalg SHA1withRSA </span><span class="pun">-</span><span class="pln">digestalg SHA1 </span><span class="pun">-</span><span class="pln">keystore </span><span class="pun">{</span><span class="pln">$my</span><span class="pun">-</span><span class="pln">release</span><span class="pun">-</span><span class="pln">key</span><span class="pun">.</span><span class="pln">keystore</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="pln">$my_application</span><span class="pun">.</span><span class="pln">apk</span><span class="pun">}</span><span class="pln"> alias_name</span></code></pre>
<p>3.壓縮並校準你的 APK</p>
<pre class="prettyprint prettyprinted"><code class="language-bash"><span class="pln">zipalign </span><span class="pun">-</span><span class="pln">v </span><span class="lit">4</span><span class="pln"> </span><span class="pun">{</span><span class="pln">$my_unaligned_application</span><span class="pun">.</span><span class="pln">apk</span><span class="pun">}</span><span class="pln"> </span><span class="pun">{</span><span class="pln">$my_protect_application</span><span class="pun">.</span><span class="pln">apk</span><span class="pun">}</span></code></pre>
<p>接著就可以上傳你的 APK 了! <br>
詳細的可以參考 <a href="http://developer.android.com/tools/publishing/app-signing.html#signapp">簽署你的APK</a></p>
<p>PS. <br>
1. 要在 Android Studio 跑 Lint 的測試,點選 <strong>Analyze->Inspect Code->OK</strong> 後就會跑出一大串分析結果其中一個就是 Anrodid Lint <br>
2. ID 為 AndroidLintHardcodedDebugMode 的描述 </p>
<blockquote>
<p>Checks for hardcoded values of android:debuggable in the manifest It’s best to leave out the android:debuggable attribute from the manifest. If you do, then the tools will automatically insert android:debuggable=true when building an APK to debug on an emulator or device. And when you perform a release build, such as Exporting APK, it will automatically set it to false. If on the other hand you specify a specific value in the manifest file, then the tools will always use it. This can lead to accidentally publishing your app with debug information.</p>
</blockquote>newmanhttp://www.blogger.com/profile/02106860573153331504noreply@blogger.com9tag:blogger.com,1999:blog-1053927668006720431.post-3495605817374263582014-07-04T11:51:00.000+08:002014-07-04T13:24:51.383+08:00UI Test Script for Android - 以Puzzle And Dragons自動轉珠為範例 (上)<br />
<h3>
<b>前言</b></h3>
當你每次寫完程式,接著手動測試程式時, 是不是覺得每次都在做同樣的事情而感覺到自己的小宇宙快要被燃燒殆盡了? 在有這種心情產生之後, 公司前輩就會出來對你說:<strike>你不是還有肝嗎 </strike>寫一下auto test吧 交給你囉~ ^_< 實際上去學一下auto test (例如android上的MonkeyRunner), 大概我是個懶人的關係啦, 單純使用當然是可以用啦, 但是不覺得每次要改個小動作都很麻煩,不直覺嗎? 難道沒有比較簡單一點的東西可以做到auto test嗎?最好是可以簡單到連一般人都會寫這個東西不是很好嗎? 這個答案就是 <span style="color: red;"><a href="http://www.sikuli.org/">SIKULI</a><span style="color: black;"> 。</span></span><br />
<a name='more'></a><span style="color: red;"><br /></span>
<br />
<h3>
SIKULI簡介</h3>
<span style="color: red;"><span style="color: black;"><span style="color: red;"><span style="color: black;">S</span></span>ikuli是個新的程式語言概念, 當時看到就覺得是很有趣的東西, 雖然一直都沒有實際嘗試過, 不過感覺上相當友善</span></span>,跟一般寫程式很大的不同點在於,他可以透過圖片辨識的方式,讓你可以清楚的了解你想操作的物件及動作, 舉個例子來說:<br />
一般程式可能長成這樣:<br />
<code>
button = vc.findViewById("id/save_button") <br />
button.touch() </code><br />
<br />
Sikuli script則是:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2C-FcecLdlGHrv3_K6dBejx2dFossaiBbQS3vMSRtGG117Xx7wFOosM5P7jODM_oe-0hFh46DoatwhLasn0FncxTFzxP-crKD__yt88oQSf0zh0UGI4tQFsS5NK4h0mbfvpt17JU-JJE/s1600/click_save.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2C-FcecLdlGHrv3_K6dBejx2dFossaiBbQS3vMSRtGG117Xx7wFOosM5P7jODM_oe-0hFh46DoatwhLasn0FncxTFzxP-crKD__yt88oQSf0zh0UGI4tQFsS5NK4h0mbfvpt17JU-JJE/s1600/click_save.png" /></a></div>
<br />
<br />
<br />
是不是看起來簡單很多, 你甚至不需要知道原本在手機裡面按鈕的id叫什麼<br />
引用作者<a href="http://blog.vgod.tw/">vgod</a>的一段話, 「Sikuli最重要的革命是程式碼的可讀性(readability)和易用性(usability)。」<br />
雖然不清楚對沒寫過程式的人來說是不是馬上就能上手,不過Sikuli IDE設計的也很簡單易懂,對於未接觸過程式的人門檻相對降低了許多<br />
<br />
<h3>
for Android</h3>
想要在android上使用Sikuli,目前大部分的作法都是透過pc上的screencast,接著再用原本的方法,抓圖判斷及執行。不過實際上當初在想弄一個auto test script時,雖然知道有Sikuli那個概念的東西,但是我不知道Sikuli的名字,google也沒查到Sikuli(我該學習一下正確的keyword搜尋了)。所以就抱著學習一下的心態,自己就來實作一下android上的auto test script language吧。<br />
<br />
首先,先列一下我們需要哪些東西:<br />
<br />
1. IDE界面<br />
2. 與android手機端的溝通(screen capture, key/mouse event ... etc)<br />
3. Script language <br />
4. 圖形辨識系統<br />
<br />
<h3>
IDE界面</h3>
因為只是個實驗性質的程式, 界面就不要求美觀, 所以就直接用Netbean拉一拉畫面就直接拿來用了, 在這邊就不多說了, 直接看看醜醜的界面吧 XD<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgofdu2xPCyJqTUvs_tOm_1JbKkWleUxIOufRutPRYeyshMv3F_tE8z1lIiBP9gRK87c7oQPNBCOG0FyvXutIJAO8v32zzs_c8s4BZ895M97L7qQ7bkhL-slkeZI8VabFLCPsFMzTg546k/s1600/appscreen1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgofdu2xPCyJqTUvs_tOm_1JbKkWleUxIOufRutPRYeyshMv3F_tE8z1lIiBP9gRK87c7oQPNBCOG0FyvXutIJAO8v32zzs_c8s4BZ895M97L7qQ7bkhL-slkeZI8VabFLCPsFMzTg546k/s1600/appscreen1.png" height="320" width="312" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyPsCTpKzEBDyAVOhgX224CtvhxFMuJxVIr_qe1L9CbHPD37ToNRFo5pJO0EbLwPyt3NpcFofliXpd749r6ZWL0g2wMAVkH9NquVcRP-WA8fEaxXIWMHbBGO8xLuA4bmYYE3wtz4UQWVs/s1600/appscreen1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><br /></a></div>
<h3>
與Android手機端的溝通</h3>
<b>版本一 - python + java</b><br />
在最早期為了要快速見到成果,所以與手機端溝通的方法是將script輸出成monkey recorder格式,並且直接餵給monkey runner中的monkey playback來達到執行使用者輸入指令的動作。 以下是執行的python程式:<br />
<pre><code>
def execute(device, line):
line = line.strip()
if not len(line) or line.startswith('#'):
return
cmd, argv = line.split('|')
try:
rest = eval(argv)
except:
print("error")
return
print('run command=' + cmd)
CMD_MAP[cmd](device, rest)
def main():
if len(sys.argv) >= 2:
command = sys.argv[1]
device = MonkeyRunner.waitForConnection()
f = open(sys.argv[2], 'r')
for line in f.readlines():
execute(device, line)
f.close()
</code></pre>
<br />
不過這個作法對於<strike>想要擴充功能來說不是很方便</strike>(事實上是對python的熟悉度沒那麼高),加上每次從程式要執行script都需要透過System.exec去執行python,並且waitForConnection(),中間所產生的時間消耗比想像中的來的還要高,所以後來轉向了第二個方法。<br />
<br />
<b>版本二 - java <complete id="goog_15451480">+ ichimpchat.jar </complete></b><b></b><br />
透過google搜尋了一下,我們可以發現MonkeyRunner底層其實就是透過ChimpChat來實現的,所以我們也可以如法泡製,看一下ChimpChat的source code,可以發現一些常用的touch, press之類的指令,下面為一部分的source code:<br />
<pre><code>
public interface IChimpDevice {
IChimpImage takeSnapshot();
void touch(int x, int y, TouchPressType type);
void press(String keyName, TouchPressType type);
void drag(int startx, int starty, int endx, int endy, int steps, long ms);
String shell(String cmd);
boolean installPackage(String path);
boolean removePackage(String packageName);
void startActivity(@Nullable String uri, @Nullable String action,
@Nullable String data, @Nullable String mimeType,
Collection<string> categories, Map<string object=""> extras, @Nullable String component,
int flags);
void broadcastIntent(@Nullable String uri, @Nullable String action,
@Nullable String data, @Nullable String mimeType,
Collection<string> categories, Map<string object=""> extras, @Nullable String component,
int flags);
Map<string object=""> instrument(String packageName,
Map<string object=""> args);
void wake();
}
</string></string></string></string></string></string></code>
</pre>
有了這一個jar檔後,我們就可以來開發java與手機端溝通的程式了,ChimpChat的用法相當簡單:<br />
1. 連結device並取得IChimpDevice的instance <br />
<pre><code>
TreeMap<string string=""> options = new TreeMap<string string="">();
options.put("backend", "adb");
options.put("adbLocation", path);
mChimpchat = ChimpChat.getInstance(options);
mDevice = mChimpchat.waitForConnection(TIMEOUT, ".*");
</string></string></code></pre>
<br />
2. 透過IChimpDevice送指令到手機端<br />
<pre><code>
// touch x, y
mDevice.touch(x, y, TouchPressType.DOWN);
// start activity
String action = "android.intent.action.MAIN";
Collection< String> categories = new ArrayList< String> ();
categories.add ("android.intent.category.LAUNCHER");
String componentName = packageName +"/" + className;
mDevice.startActivity(null, action, null, null, categories, new HashMap<string object="">(), componentName, 0);
// Drag
mDevice.drag(startx, starty, endx, endy, steps, timeMs);
</string></code></pre>
<br />
如此一來對手機端ui的操作透過IChimpDevice就能夠簡單的達成了<br />
<br />
<strike>富奸</strike> 待續Anonymoushttp://www.blogger.com/profile/17715762577846106669noreply@blogger.com0tag:blogger.com,1999:blog-1053927668006720431.post-60735048562495545032014-07-03T10:16:00.000+08:002014-07-25T18:51:32.338+08:00壓縮JavaScript的好工具 - Closure Compiler<br />
<div style="text-align: center;"><img alt="enter image description here" src="https://farm4.staticflickr.com/3842/14509760734_76fdcfca6d_o.gif" title="" /></div><h3 id="一切都是為了使用者體驗"><strong><br />
</strong></h3><h3 id="一切都是為了使用者體驗"><strong><span style="font-size: large;">一切都是為了使用者體驗</span></strong></h3><div><strong><span style="font-size: large;"><br />
</span></strong></div>大家滑手機的時候一定最討厭界面卡頓的感覺,圖片或內容可以晚點呈現(甚至跳過也沒關係),但爽快地滑動界面是神聖不可侵犯的使用者特權,只要可以暢快地讓人滑手機就是好App了。我有時候覺得這已經完全改變了我們的世界,例如我家巷口那原本繁忙的早餐店,現在已經鮮少聽到顧客等待早餐製作的不耐抱怨聲,因為大部份的等待時間已經被滑手機給撫慰了,反而覺得“咦!最近老闆煎蛋餅的時間變快了啊 ^^? ”。<br />
因此在偉大的使用者經驗的考量下,無論是Web或APP開發,大家最怕的就是網路塞車或是大量I/O下造成操作的遲鈍,因為使用者通常只要愉悅的瀏覽被打斷幾次,很可能就直接按下home鍵離開了。<br />
<h3 id="如何提升網路服務的效率"><strong><br />
</strong></h3><h3 id="如何提升網路服務的效率"><strong><span style="font-size: large;">如何提升網路服務的效率</span></strong></h3><div><strong><span style="font-size: large;"><br />
</span></strong></div>Web Design更是受到此一嚴峻的考驗,在先天限制下,Web的運作效能本來就無法跟native application相比,更何況其完整內容+部分程式需要先透過網路傳輸到使用者端的裝置上,雖說為了避免操作上的遲鈍,UI的設計通常會將厚重的動作以非同步的背景方式處理(例如資料查詢或是圖片的下載),但是如果是連UI本身的程式(JavaScript)都需要花大量時間從伺服器下載,那就真的無藥可救了,無論我們提供如何良好的UI設計,使用者都只有等待的份。<br />
為了快速有效地利用頻寬來提供良好的服務,服務提供者通常會先針對其JavaScript進行壓縮來避免上述的問題,希望能在使用者開啟網頁的時候,重要資料可以以最快速的方式下載到瀏覽器上。Google在這方面提供了一個相當實用的壓縮工具:<a href="https://developers.google.com/closure/">Closure Compiler</a><br />
<br />
<a name='more'></a><br />
<h3 id="closure-compiler"><strong><br />
</strong></h3><h3 id="closure-compiler"><strong><span style="font-size: large;">Closure Compiler</span></strong></h3><div><strong><span style="font-size: large;"><br />
</span></strong></div>Closure Compiler是一個JavaScript壓縮器,除了將多餘的空格換行符號及註解移除之外,也會檢視多餘的程式變數,甚至也會會像Java的<a href="http://proguard.sourceforge.net/index.html#">obfuscate</a>處理一樣,將過長的名稱轉換成一個簡短的名字,Clouse Compiler有許多種使用方式,其中一種是直接在<a href="http://closure-compiler.appspot.com/home">網頁</a>上Compile你的JavaScript,如下圖所示,頁面工具分成左右兩部分,在左方欄位貼上Script內容後按下Compile按鈕,便可以於右方得到處理後的內容。<br />
<br />
<img alt="http://closure-compiler.appspot.com/home" height="417" src="https://farm4.staticflickr.com/3894/14508909304_2a6b11f1b8_c.jpg" title="" width="640" /><br />
<br />
以下Compile前的原始JavaScript範例:<br />
<pre class="prettyprint prettyprinted"><code class="language-javascript"> // ADD YOUR CODE HERE
function hello(name) {
var useless_variable = 'test'
alert('Hello, ' + name);
}
hello('New user');
</code></pre><br />
Compile後的結果為:<br />
<pre class="prettyprint prettyprinted"><code class="language-javascript">function hello(a){alert("Hello, "+a)}hello("New user");</code></pre>嘗試著執行上方這個範例,我們可以發現Compile後,第三行的useless_variable變數會直接被移除,其餘的註解及空格符號也會被拿掉,剩下來才是真正有用的Script,結果已經簡潔許多。<br />
<br />
以Github上的cocos2d-html5專案為例,專案目錄的cocos2d目錄下面共有161個js檔案,原本大小約為2.4MB,經過Clouse Compiler壓縮後,則變為1.1MB,接下來我們便可以拿這個簡短後的JavaScript進行產品部署作業。<br />
<br />
<blockquote class="tr_bq">$ du -csh ./cocos2d_compiled/ ./cocos2d/<br />
1.0M ./cocos2d_compiled/ (壓縮後檔案)<br />
2.3M ./cocos2d/ (原始檔案)</blockquote><br />
<h3 id="將一切都自動化吧"><strong><br />
</strong></h3><h3 id="將一切都自動化吧"><strong><span style="font-size: large;">將一切都自動化吧!</span></strong></h3><div><strong><span style="font-size: large;"><br />
</span></strong></div>當然我們不用每次編寫JavaScript就親力親為的把內容上傳到上述的網站進行壓縮作業,Clouse Compiler也有提供Command line的執行方式,我們可以從<a href="https://developers.google.com/closure/compiler/docs/gettingstarted_app">這裡</a>Download一個compiler.jar ,透過java的方式便可以針對指定的JavaScrip檔案進行處理。<br />
執行命令的範例如下:<br />
<blockquote class="tr_bq">java -jar compiler.jar --js hello.js --js_output_file hello-compiled.js</blockquote>或者搭配batch or shell script批次把專案的所有JavaScript全都壓縮過一次:<br />
<blockquote class="tr_bq">#!/bin/bash<br />
files="$(find ./myproject -iname *.js)"<br />
for X in $files<br />
do<br />
echo 'processing>>'$X<br />
java -jar compiler.jar --js $X --js_output_file $X<br />
done<br />
<br />
</blockquote>如果本身專案有使用如Jenkins的CI tool (Continuous Integration),便可以將此一步驟整合至專案的建置流程之中,讓專案有條不紊的進行下去。一般來說,我們會希望SCM Server上是完整的JavaScript原始檔以方便日後開發除錯,因此不建議將壓縮過的JavaScript放回SCM Server,所以通常程序會是: <br />
<br />
<strong>Get source code from SCM Server -> Compile JavaScript -> testing -> deploy Project</strong><br />
<br />
一旦將Clouse Compile整合進Jenkins之後,我們便可方便地在每次程式改版時進行壓縮處理,還可以直接在網頁上檢視其結果。<br />
<br />
<img alt="enter image description here" src="https://farm3.staticflickr.com/2910/14368947910_20cbd27204_z.jpg" title="" /><br />
<br />
<h3 id="clouse-tool還能做什麼"><strong><span style="font-size: large;">Clouse tool還能做什麼</span></strong></h3><div><strong><span style="font-size: large;"><br />
</span></strong></div>除了幫忙壓縮JavaScript之外,Google的這一套Clouse tool也有其他非常實用的功能,我們可以拿它來作為Code Review的基礎,透過這個工具來檢視Script中的潛在的issue。<br />
<ul><li><strong>Closure Compiler - A JavaScript optimizer</strong>,也就是此篇文章所介紹的JavaScript壓縮工具</li>
<li><strong>Closure Linter - A JavaScript style checker and style fixer</strong>,Linter是一種靜態程式碼分析工具,可以檢視程式碼中一些容易忽略的錯誤,也可以針對程式碼撰寫風格進行檢查,如果專案團隊有定義共同的coding conventions,便可以透過此種工具好好規範一下大家的寫作性格,畢竟寫程式不像寫詩,次意揮灑的結果通常不易團隊合作啊!</li>
<li><strong>Closure Stylesheets - An enhanced stylesheet</strong> language,此工具可以讓開發者透過用variable、function的方式來編輯網頁layout,這邊稱為.gss檔案,夠過此一工具再轉換成標準的CSS檔案,如此一來,CSS的編輯及管理更具彈性。</li>
</ul>此外,這套工具中還包含下方兩個實用的程式庫,這些功能皆俱有server agnostic的特色,也就是並不相依於特定Server or framework,我們可以拿它來實作於各種Web專案而不用擔心相容問題。<br />
<ul><li><strong>Closure Templates - An easy templating system for both Java & JavaScript</strong> </li>
<li><strong>Closure Library - A comprehensive JavaScript library</strong></li>
</ul><div><b><br />
</b></div><hr />目前無論是哪一種web技術,JavaScript作為網頁效果或是呈現網頁應用程式的方式正被廣泛地使用, 許多受歡迎的Web Framework幾乎都是這種直譯式語言+JavaScript的解決方案。如果我們已經費勁心思設計好應用程式,但只是因為在最後一哩的地方造成使用者體驗不佳,那真是前功盡棄,事倍功半了,現在就趕快為你的web專案建立JavaScript最佳化機制吧!Sam Chttp://www.blogger.com/profile/16142383609940270017noreply@blogger.com0tag:blogger.com,1999:blog-1053927668006720431.post-36187070907167534592014-07-02T10:04:00.000+08:002014-07-03T16:19:37.503+08:00台南古蹟 - Android App<h3>
<span style="font-size: large;"><span style="font-size: x-large;">前言</span> </span></h3>
<span style="font-size: large;">由於台灣本島的城鎮發展由台南(台灣府城)、彰化鹿港及台北(艋舺)開始,有一府二鹿三艋舺之謂,所以古蹟眾多,其中曾為台灣統治中心的<b>台南和台北</b>兩地的古蹟數量均<b>超過百處</b>。 - 引用自 <a href="http://zh.wikipedia.org/wiki/%E5%8F%B0%E7%81%A3%E5%8F%A4%E8%B9%9F%E5%88%97%E8%A1%A8">Wiki台灣古蹟列表</a></span><br />
<span style="font-size: large;"><br />
</span> <span style="font-size: large;">另外根據<a href="http://www.boch.gov.tw/boch/frontsite/cultureassets/announceTypeAction.do?method=doCreateType&menuId=309">文化部文化資產局</a>最新統計全台目前有788筆古蹟(其中國定古蹟90筆,直轄市定古蹟394筆),<b>台南就有132筆佔16.75%,國定古蹟更高達22筆佔全台24.44%</b>。有著如此高比例的台南市,若能有便利的 App 可以利用,更進一步的讓當地居民或觀光客有更友善的城市體驗,一定能讓大家對台南古蹟有更深的了解。</span><br />
<span style="font-size: large;"></span><br />
<a name='more'></a><br />
<br />
<h3>
<span style="font-size: x-large;">黑客松</span></h3>
<span style="font-size: large;"> 在 Open Data 正值發光發熱的元年,台南市市政府舉辦了一場黑客松競賽,讓大家利用由台南市政府提供的 Open Data 來做出手機 App 或相關的網路應用服務,來深刻地結合在地文化與觀光客的連結。</span><br />
<span style="font-size: large;"><br />
</span> <span style="font-size: large;">有了這些 Open Data ,我們團隊為了要讓所有使用者能夠從不同角度去了解各個台南古蹟的歷史.特色和各古蹟之間的關聯性,從而設計出這三大功能。</span><span style="font-size: large;"></span><br />
<ul>
<li><b><span style="font-size: large;">找!古蹟</span></b></li>
<li><b><span style="font-size: large;">玩!古蹟</span></b></li>
<li><b><span style="font-size: large;">懂!古蹟</span></b></li>
</ul>
<table><tbody>
<tr><td><div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMhfoAu6QoQGnTK_6T5Y4w7WMrPfhE48oPNa-H1LTenb-HRFbmu7l8BDcdagx5T31Em-KAiDrnqK6oTOkY6_yVI3dDZgo4FN3dhhMcAUIL2COM0ZFUx1hs535qlQMSyHLzy-6rb-y8biw/s1600/tainan1.webp" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><span style="font-size: large;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMhfoAu6QoQGnTK_6T5Y4w7WMrPfhE48oPNa-H1LTenb-HRFbmu7l8BDcdagx5T31Em-KAiDrnqK6oTOkY6_yVI3dDZgo4FN3dhhMcAUIL2COM0ZFUx1hs535qlQMSyHLzy-6rb-y8biw/s320/tainan1.webp" height="400" width="225" /></span></a></div>
</td></tr>
</tbody></table>
<span style="font-size: large;"> </span> <b><span style="font-size: large;"> </span></b><br />
<b><span style="font-size: large;">找!古蹟</span></b><br />
<span style="font-size: large;"><br />
</span> <span style="font-size: large;"> 既然來到了台南,沒有逛過著名古蹟或吃過好吃的小吃還能自稱來過台南嗎?或是來台南很多次逛過太多次安平古堡,赤嵌樓!想要換換路線去探訪更巷仔內的古蹟嗎?用"找!古蹟"可以幫你快速搜尋或並據你的所在地找出離你最近的古蹟,隨意點一個會顯示更深入的簡介.歷史.近況.外觀等等的資訊,往右邊一滑還可以找到古蹟附近的餐廳,在逛逛古蹟之餘當然不能餓了肚子!</span><br />
<table><tbody>
<tr><td><span style="font-size: large;"><br />
</span> <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTV7h_W_mkncc558PcMTa8JXkA8EXB-GFYVq2xZBKeekSbRyXi_5m9HIaH0FQNY8pARbyn1PgWqMBcEzFgrrmzBldAXo1FE4Uu4npFnah6c_QvYEXWXqv_AvClWQrhMZF5cMGXkgm9Hdc/s1600/tainan2.webp" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><span style="font-size: large;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTV7h_W_mkncc558PcMTa8JXkA8EXB-GFYVq2xZBKeekSbRyXi_5m9HIaH0FQNY8pARbyn1PgWqMBcEzFgrrmzBldAXo1FE4Uu4npFnah6c_QvYEXWXqv_AvClWQrhMZF5cMGXkgm9Hdc/s320/tainan2.webp" height="400" width="225" /></span></a></div>
</td><td><span style="font-size: large;"><br />
</span> <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdfBLZCYgEPYNGd2pDvWarjAlgSNSK__yel2xBcvUWdt1SZc4462B3QG_cgJLfqlkYEMKY9k2uXxATAa7iiHPaa8baK8tGQAxkcwhikpZdEWrThjsA3p5oU_l_NEA_TVrTzz3KywofCe0/s1600/tainan3.webp" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><span style="font-size: large;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdfBLZCYgEPYNGd2pDvWarjAlgSNSK__yel2xBcvUWdt1SZc4462B3QG_cgJLfqlkYEMKY9k2uXxATAa7iiHPaa8baK8tGQAxkcwhikpZdEWrThjsA3p5oU_l_NEA_TVrTzz3KywofCe0/s320/tainan3.webp" height="400" width="225" /></span></a></div>
</td><td><span style="font-size: large;"><br />
</span> <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi88HnMbS_2FOgEWDNYg5IJzxwZapYqdZCB7m4hnElpICRZmXYiv6TzVQc8Mqij12i_KKZ6pjKWzdXmvvo6c9O64L5hXUbXighYf_1DxKGBTJv3bCzfxu3cZI40-pxZyJZ3iICQqwhQRII/s1600/tainan4.webp" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><span style="font-size: large;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi88HnMbS_2FOgEWDNYg5IJzxwZapYqdZCB7m4hnElpICRZmXYiv6TzVQc8Mqij12i_KKZ6pjKWzdXmvvo6c9O64L5hXUbXighYf_1DxKGBTJv3bCzfxu3cZI40-pxZyJZ3iICQqwhQRII/s320/tainan4.webp" height="400" width="225" /></span></a></div>
</td></tr>
</tbody></table>
<span style="font-size: large;"><br />
</span> <b><span style="font-size: large;">玩!古蹟</span></b><br />
<span style="font-size: large;"><br />
</span> <span style="font-size: large;"> 在這個大項裡面,我們設計了任務模式讓各使用者透過不同的任務來了解台南古蹟的關聯性,如其中一個"尋找台南府城",清朝時代台南城牆的設立中包含了高達14座的城門,經過時間的摧殘考驗還有統治者需求演進,最後僅存且變成古蹟只剩大東門,大南門,小西門和兌悅門四座和一些遺跡。在逛古蹟的同時若有著時代背景的引導,必定更具有意義。</span><br />
<span style="font-size: large;"> 此外,點選任一個任務進去也可以點選選單的地圖模式,能經由距離的遠近來規劃一條屬於你的路線,不用煩惱該先去哪裡,把旅遊時間放在規劃要順路吃哪些小吃吧!</span><br />
<table><tbody>
<tr><td><span style="font-size: large;"><br />
</span> <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgqPcQPThYyKq3KCgigU_g37N2Ew_vQTsR_FAVFSiG_wkGcVHfYdnfMUXUhVBCX_bpQCbd-lfP3ydshb5VE2dFtWD-0GLmeXdf2TUK8FrGX0lnF0exNbp1B2iEOJBvFAGl0T2WuTJx2z4/s1600/tainan5.webp" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><span style="font-size: large;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhgqPcQPThYyKq3KCgigU_g37N2Ew_vQTsR_FAVFSiG_wkGcVHfYdnfMUXUhVBCX_bpQCbd-lfP3ydshb5VE2dFtWD-0GLmeXdf2TUK8FrGX0lnF0exNbp1B2iEOJBvFAGl0T2WuTJx2z4/s320/tainan5.webp" height="400" width="225" /></span></a></div>
</td><td><span style="font-size: large;"><br />
</span> <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgYaCUDWZJ4quwPotC9GIzaKbl18iRfLoFwWIwV4gcyWEk5zIh3zMQCiOGXqsuhCDaqAXKUBzx_e_55VtrLeppxNtKBUzli18BO0Fu0mM1KyhB6qqKmQPYbiD6lhDA5Vxr0aMyXT7TMOg/s1600/tainan6.webp" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><span style="font-size: large;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgYaCUDWZJ4quwPotC9GIzaKbl18iRfLoFwWIwV4gcyWEk5zIh3zMQCiOGXqsuhCDaqAXKUBzx_e_55VtrLeppxNtKBUzli18BO0Fu0mM1KyhB6qqKmQPYbiD6lhDA5Vxr0aMyXT7TMOg/s320/tainan6.webp" height="400" width="225" /></span></a></div>
</td><td><span style="font-size: large;"><br />
</span> <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5q0Zs0gMFqlMLWVESj-onkP28GJYdezb0OQPBf_ESqEDiTizeY3ah_9zqML462Otk7uBXjbC6ilo6103YGcfDnyQE3Ors6lsqm2MjIfXhjFpq9j5l-mNn0ilIwImdYdWMFr9O8tKZ62Q/s1600/tainan8.webp" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><span style="font-size: large;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5q0Zs0gMFqlMLWVESj-onkP28GJYdezb0OQPBf_ESqEDiTizeY3ah_9zqML462Otk7uBXjbC6ilo6103YGcfDnyQE3Ors6lsqm2MjIfXhjFpq9j5l-mNn0ilIwImdYdWMFr9O8tKZ62Q/s320/tainan8.webp" height="400" width="225" /></span></a></div>
</td><td><span style="font-size: large;"><br />
</span></td></tr>
</tbody></table>
<span style="font-size: large;"><br />
</span> <b><span style="font-size: large;">懂!古蹟</span></b><br />
<span style="font-size: large;"><br />
</span> <span style="font-size: large;"> 透過簡單的(好像也不簡單)題目來幫助大家對古蹟有更深一層的瞭解,這寓教於樂的方式有沒有讓你有更認識台南一點呢?就需要由使用者您來親身體驗了!</span><br />
<table><tbody>
<tr><td><span style="font-size: large;"><br />
</span> <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitd9fHSwWE_igKKNQh4y5S0bu_94dzsgVkYyNsFLcIzvsnc90iAbNpt04aBbIJ1Ob_SxXgJ6fwSef8vt9eWX4LX35rLxWYtaYiKMF-2dKjGT1TVpV-WlBOZEAOlRkX8-xekWXQIgToj6o/s1600/tainan7.webp" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><span style="font-size: large;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitd9fHSwWE_igKKNQh4y5S0bu_94dzsgVkYyNsFLcIzvsnc90iAbNpt04aBbIJ1Ob_SxXgJ6fwSef8vt9eWX4LX35rLxWYtaYiKMF-2dKjGT1TVpV-WlBOZEAOlRkX8-xekWXQIgToj6o/s320/tainan7.webp" height="400" width="225" /></span></a></div>
</td><td><br /></td></tr>
</tbody></table>
<span style="font-size: large;"></span><br />
<h3>
<span style="font-size: x-large;"> 最後</span><span style="font-size: large;"></span></h3>
<span style="font-size: large;"> 希望大家都能藉由此應用程式得到不同層面的知識,若有任何的意見和建議也都歡迎大家來信討論,希望大家會喜歡!</span><br />
<span style="font-size: large;"><br />
</span> <br />
<h4>
<span style="font-size: large;">附上 Google Play 連結 </span></h4>
<h4>
<span style="font-size: large;"><a href="https://play.google.com/store/apps/details?id=tn.opendata.monument" target="_blank"><img alt="Get it on Google Play" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjK13GNmZEyeIVJBSa95D5P3JZPBiiF5e353YUSV_cYpzTJvy1TfMfGffk2tzBpUyoaEO38sSwPfSmG-87d3UwfxhVXdw0kxfS6G4JUEnMwX9gs5f22UYby4vJIoPfrJxYgbdVtEI2UrRA/s1600/zh-tw_generic_rgb_wo_60.png" /><br />
</a></span></h4>
newmanhttp://www.blogger.com/profile/02106860573153331504noreply@blogger.com0台灣台南市23.1416985 120.2512727999999222.6745015 119.60582579999992 23.6088955 120.89671979999993tag:blogger.com,1999:blog-1053927668006720431.post-52752118898844586262014-07-01T11:06:00.001+08:002014-07-03T16:22:02.353+08:00台南311開發紀錄 (下)<h3 id="台南311之-android-app">台南311之 Android app</h3>
<p>整個台南311的project,我們花最多的時間在於設計一個回報的App。 <br>
接下來介紹我們開發的台南311 app的功能與紀錄開發過程中的心得,懶得打太多直接看影片吧!</p><div class="se-section-delimiter"></div>
<h2 id="先來看操作的畫面">先來看操作的畫面</h2>
<p><span> <br>
<a name='more'></a></span></p>
<iframe src="https://docs.google.com/file/d/0BwtbOddGYgMaejBpYW5RQU9RdVU/preview" width="640" height="385"></iframe>
<p>一開始進去利用地圖的方式呈現你附近回報的問題,大概是最近50筆或90天內(Server端設定)。紅色的圖標代表待處理的問題,綠色的則代表已處理。當然點擊圖標會跳出簡單的問題描述,點擊描述則會進入該筆回報資料的詳細狀況。</p>
<p>地圖下方的”回報問題”按鈕主要考慮到快速回報,所以放了一顆在這裡。更多的功能可從左方可拉出選單,包含以List的方式呈現所有問題,或是你回報的問題(後來沒空實作)。 </p><div class="se-section-delimiter"></div>
<h2 id="回報的流程">回報的流程</h2>
<p><span></span></p>
<iframe src="https://docs.google.com/file/d/0BwtbOddGYgMac21NaEZ3aXQyUEk/preview" width="640" height="385"></iframe>
<p>點選回報問題後,就如同畫面的上的提示五步驟:</p>
<ol>
<li><p>把問題標記在地圖上</p>
<blockquote>
<p>標記地圖時,地圖會先移到你目前的位置,然後你可以透過拖動地圖把箭頭指到發生的地點。拖拉的過程中,地圖會標記出已經回報的問題,這樣可以避免回報到重複的問題。實際使用上在定位時可能同時需要參照衛星照片跟地圖,所以右方有一個可以快速切換地圖模式的按鈕。</p>
</blockquote></li>
<li><p>拍照</p>
<blockquote>
<p>可開啟相機拍照或直接選取已存在的照片</p>
</blockquote></li>
<li><p>描述問題</p>
<blockquote>
<p>為了快速回報,會預先幫忙填好姓名跟email,如果有修改會自動紀錄。</p>
</blockquote></li>
<li><p>上傳並點選確認信(只需要確認一次)</p>
<blockquote>
<p>只需做第一次確認,因為app會自動紀錄密碼。(FixMyStreet的機制)</p>
</blockquote></li>
<li><p>完成回報 </p>
<blockquote>
<p>這一步其實沒有任何操作</p>
</blockquote></li>
</ol>
<h2 id="開發過程的困難">開發過程的困難</h2>
<p><a href="http://www.fixmystreet.com/open311">FixMyStreet號稱支援Open311</a></p>
<p>因為原本就預計使用Open311的API去跟FixMyStreet溝通,但是實際上遇到了一些問題。</p>
<ol>
<li><p>FixMyStreet的Open311 XML format看起來沒什麼問題,不過我們的app使用json format為主要資料格式,發現fixmystreet json format其實是不符合標準的,變成收到API後還要先做資料的處理把他轉成標準的Open311 format,然後才能繼續處理下去。</p></li>
<li><p>FixMyStreet 看起來並沒有支援Open311的post request。也許有但是我們一直試不出來,而且也找不到明確相關的文件,於是礙於時間關係,我們最後直接參考FixMyStreet mobile的做法,發http request去新增。</p></li>
<li><p>FixMyStreet針對API的支援還是有點模糊,像一些post參數都不知道是什麼意思,只能用試的。後續如果要精進,應該要先從API介面下手,直接跟後端的PostgreSql溝通,這樣可以直接避免去修改原本的Perl邏輯。</p></li>
<li><p>Update的資訊還沒空認真研究,不過似乎沒有明確的API。</p></li>
</ol>
<h3 id="最後想法">最後想法</h3>
<p>以快速建立一個可用的問題回報系統的角度來思考,FixMyStreet目前提供的功能跟穩定性,可以說是目前最適合的Solution。比起自己辛苦建立一個回報系統,不如直接使用FixMyStreet這種現行的系統,然後透過實際運作再慢慢客製化讓它更符合台灣使用。</p>
<p>其實不管是FixMyStreet或是Open311,我們真心的覺得這是一個非常有意義的東西,但是還是有太多東西不是我們可以控制的。包含怎麼跟政府合作這一段,其實政府有沒有興趣都不知道…XD,因為黑客松無法有效的將東西報告出來。雖然說FixMyStreet支援email回報,我們大可以直接寄給回報到政府單位的信箱,但是這樣子的模式其實不利於後續的擴充跟整合。</p>
<p>嚴格說起來,我們都是軟體工程師,不是很擅長也不喜歡跟政府打交道,至少我們已經證明這樣的東西是可以work,以現階段來講已經夠了,至於後續會不會繼續發展下去,這個就再說吧。</p>
<p>App的Source在未來的某一天會Open出來,等我有空吧..XD</p>
<p><br></p>
<p>相關文章: <strong><a href="http://35around.blogspot.tw/2014/06/311.html">台南311開發紀錄 (上)</a></strong></p>misgodhttp://www.blogger.com/profile/00933441299043629398noreply@blogger.com0tag:blogger.com,1999:blog-1053927668006720431.post-4442753231410090202014-06-30T14:55:00.001+08:002014-07-04T16:35:40.748+08:00台南311開發紀錄 (上)<h3 id="前言">前言</h3>
<p>在<a href="https://play.google.com/store/apps/details?id=tn.opendata.monument&hl=zh-TW">古蹟app</a>大致完工的時候,大約還剩兩個禮拜多的時間,我們決定做點不一樣的東西,希望能夠把Open311的東西透過這一次的台南黑客松,介紹給台南市政府。不過黑客松只給3分鐘報告,看來我們報告失敗的很徹底,完全沒有得到預期的效果。黑客松都已經過了,中間的過程也懶得再提了,寫下這篇主要是要紀錄一下開發台南311的過程,跟一些還需要被解決的問題。</p>
<p>下面這段是報名2014台南黑客松時,寫下的專案簡介。</p>
<a name='more'></a>
<blockquote>
<p>有感於目前台南市問題回報機制不夠簡便及透明,本團隊期望導入Open311國際標準並利用行動裝置的特性,讓市民可以快速通報問題並追蹤後續處理的進度。 <br>
結合網頁和後端追蹤系統,讓不管電腦或是手機,皆可以關心自己或其他人通報的問題。主要功能有</p>
<ul>
<li>利用手機定位及拍照,快速回報問題(如: 地面坑洞, 號誌燈故障)</li>
<li>列出附近或是最近這段時間內有人回報的問題</li>
<li>追蹤特定問題處理進度</li>
</ul>
<p>預計通報問題類別 (暫定)</p>
<ul>
<li>道路問題</li>
<li>路霸與騎樓佔用</li>
<li>市容整潔 </li>
<li>號誌、路燈故障</li>
<li>其他</li>
</ul>
</blockquote>
<p>簡單來說就是,我們希望做一個Android App,這個app可以透過Open311的標準,讓一般市民在路上看到問題可以在<strong>30秒</strong>內,快速的將問題回報給市政府,讓問題回報變成一種舉手之勞。</p>
<p>可能有人會問,為什麼不用現在市面上的open 311 app呢?基本上根據評分還有個人使用的測試經驗,真的是很不好用,所以我們才會想要試著自己寫一個311 app。 </p><div class="se-section-delimiter"></div>
<h3 id="從open-311開始">從Open 311開始</h3>
<p>一開始的構想來自於一個新聞報導,<a href="http://www.nownews.com/n/2013/04/16/292034">台南市「1999」市民服務專線 不滿意度高達三分之一</a>。我看到這新聞覺得很驚訝,因為我根本不知道台南有1999。於是我在想會不會也有線上回報機制,然後我在台南市政府的網頁找到了<a href="http://cmsweb.tainan.gov.tw/">線上即時服務系統</a>。如果你點進去看你會發現一件事,就是你要有單號才能查詢問題回報的狀況,然後你還找不到回報的頁面。不過,最後我發現了,你要先點網站導覽然後才能看到<strong>1. 線上即時服務系統</strong>,有沒有這麼隱密啊!接下來你會遇到34大項的分類,當然裡面還有很多小項,我一直不懂,這樣設計是要給誰用阿,難道我還要很明確的知道我回報的問題是屬於那一項才行嗎?很明顯這樣的設計是為了責任單位不是為了民眾。就像<strong>佔用道路人行道騎樓</strong>跟<strong>騎樓佔用</strong>就分屬不同兩個大類。</p>
<p>抱怨完回到正題。 </p>
<p><a href="http://wiki.open311.org/GeoReport_v2">Open311 GeoReport v2</a>是一個關於讓地方政府可以收到問題回報的一個標準,一般適用於非緊急的問題。那Open 311跟原本的美國311或是台灣的1999相比有什麼好處?我覺得大概有以下的優勢,也是我覺得目前1999的一些缺點:</p>
<ul>
<li>1999資料不透明,容易造成重複回報的現象,浪費資源。</li>
<li>沒有即時的狀態更新,造成市民以為市政府效率不好 <br>
<ul><li>例如:已通知承包商,預計3日內修復之類的更新。</li></ul></li>
<li>1999是用電話的方式,回報資料不容易數據化,無法做更進一步的分析。</li>
<li>1999必須透過電話描述出問題發生的地點,如果不熟悉附近區域,可能會有問題。</li>
<li>目前線上web回報機制,沒有標記經緯度的功能,一樣有位置描述的問題。</li>
<li>回報問題資料不公開,市民不了解市政府修復了多少問題,只給出數字人民無法信服。</li>
</ul>
<p>其實Open311本身定義的非常的簡單(很陽春),只有6個API而已,所以實作上並不會很困難,但是最大的困難在於沒時間做後端問題追蹤管理系統,於是為了搶時間想說拿Redmine來用,反正只是 demo,透過api去新增issue。大致的架構如下:</p>
<blockquote>
<p>Android -> Open311 API service(Clojure) –> Redmine</p>
</blockquote>
<p>不過真正動手研究後發現,Redmine的API存在單向的問題,新增沒什麼問題,就是查詢的api跟open 311的參數接不太起來。搞了兩三天後確定行不通,於是當機立斷,直接找現成的solution。在Open311的wiki上其實有列了一些Open 311 Server端的資訊,經過一些Survey後,我最後決定使用跟Open311沒什麼關係的<a href="http://www.fixmystreet.com/">FixMyStreet</a>作為後端。</p>
<p>當時選擇FixMyStreet的solution主要有以下的考量</p>
<ul>
<li>OpenSource 不過是用Perl開發的</li>
<li><strong>安裝方便,文件完整</strong>,還一直有在持續maintain</li>
<li>其實比Open311還早,而且運作的不錯</li>
<li>已經在<strong>不同國家</strong>運行,Open311似乎只集中在北美</li>
<li>號稱有<strong>相容Open311</strong> (後來才發現不甚理想) </li>
</ul>
<p><br></p><div class="se-section-delimiter"></div>
<h3 id="fixmystreet-in-台南">FixMyStreet in 台南</h3>
<p>主要紀錄架設FixMyStreet Service中的過程跟一些心得。 </p>
<p><strong>FixMyStree簡介</strong> </p>
<p>FixMyStreet是英國的mySociety這家社會企業的一個<a href="https://github.com/mysociety/fixmystreet">OpenSource</a> Project(AGPL), 是一個web-base的服務,讓一般人可以透過網站回報一些問題,如路面坑洞、路燈號誌故障、塗鴉…之類的地方問題。</p>
<p>FixMyStreet目前提供的功能非常的完整,只需要做點簡單的設定就可以開始基本的運作。不過因為主要是使用Perl開發,所以在後續修改及擴充上上是一個比較棘手的問題。由於目前我的AWS Free Tier已經到期了,所以<a href="http://FixMyStreet.tw">http://FixMyStreet.tw</a>是關閉中的,後續不確定是否會再繼續。</p>
<p><strong>FixMyStreet已經被應用英國以外在其他的國家</strong></p>
<ul>
<li>Australia: FixMyStreet (<a href="http://www.fixmystreet.org.au/">http://www.fixmystreet.org.au/</a>)</li>
<li>Belgium (Brussels-Capital Region only): Fix My Street - (<a href="http://www.fixmystreet.irisnet.be/">http://www.fixmystreet.irisnet.be/</a>)</li>
<li>Canada: FixMyStreet (<a href="http://www.fixmystreet.ca/">http://www.fixmystreet.ca/</a>)</li>
<li>Cyprus: FixCyprus (<a href="http://fixcyprus.com/">http://fixcyprus.com/</a>)</li>
<li>Georgia: <a href="http://chemikucha.ge/">http://chemikucha.ge/</a></li>
<li>Germany: Mark-a-Spot (<a href="http://www.mark-a-spot.org/">http://www.mark-a-spot.org/</a>)</li>
<li>Korea: FixMyStreet (<a href="http://www.fixmystreet.kr">http://www.fixmystreet.kr</a>)</li>
<li>Netherlands: Verbeterdebuurt (<a href="http://www.verbeterdebuurt.nl/">http://www.verbeterdebuurt.nl/</a>)</li>
<li>New Zealand: FixMyStreet (<a href="http://fixmystreet.org.nz/">http://fixmystreet.org.nz/</a>)</li>
<li>Norwegian: Fiksgatami (<a href="http://www.fiksgatami.no/">http://www.fiksgatami.no/</a>) funded by NUUG (Norwegian Unix User Group)</li>
<li>Greece: fixMyGreece (<a href="http://fixmygreece.com/">http://fixmygreece.com/</a>)</li>
<li>Japan: FixMyStreet (<a href="http://www.fixmystreet.jp/">http://www.fixmystreet.jp/</a>)</li>
<li>Sweden: FixaMinGata (<a href="http://www.fixamingata.se/">http://www.fixamingata.se/</a>)</li>
<li>Switzerland: Zurich’s ZueriWieNeu (<a href="https://www.zueriwieneu.ch/">https://www.zueriwieneu.ch/</a>)</li>
<li>Tunisia: FixKairouan (<a href="http://fixkairouan.org/">http://fixkairouan.org/</a>)</li>
</ul>
<p><strong>FixMyStreet 提供的功能</strong> </p>
<p>FixMyStreet Web主要提供的功能如下: </p>
<ol>
<li>查看目前各地方單位的回報</li>
<li>查看你的回報</li>
<li>在地圖上查看回報</li>
<li>透過地圖上標點,上傳照片及問題描述回報問題。</li>
<li>系統會根據回報類別及地圖範圍回報給對應的處理單位</li>
<li>回報者的mail確認</li>
<li>問題追蹤訂閱</li>
<li>區域更新的訂閱</li>
<li>不同方式跟受理單位的後端整合 <br>
<ul><li>mail (預設)</li>
<li>Open 311</li>
<li>參閱: <a href="http://fixmystreet.org/customising/integration/">http://fixmystreet.org/customising/integration/</a></li></ul></li>
</ol>
<p><strong>FixMyStreet 安裝與修改</strong> </p>
<ol>
<li><p>安裝 </p>
<p>關於FixMyStreet的安裝可以直接參考<a href="http://fixmystreet.org/install/">http://fixmystreet.org/install/</a> ,基本上應該就是Step by Step跟著做就對了。我選擇<a href="http://fixmystreet.org/install/ami/">最簡單的方式</a>就是用AWS EC2,直接掛上他們提供的AMI瞬間就完成了。</p></li>
<li><p>中文化 </p>
<p>FixMyStreet目前還沒有中文化,不過他的架構已經是使用gettext的方式,所以只需要修改po檔就可以了。我已經將大部分一般人可以看到的訊息給中文化完,不過因為有些詞不知道怎麼翻譯,例如他們的問題都是回報到Council,但是如果翻成議會感覺怪怪的,所以目前是暫時使用”受理單位”這個模糊的詞彙。目前所有的翻譯還是先放在我folk出來的repository. </p>
<blockquote>
<p>有興趣的人可以參考 <br>
<a href="https://github.com/misgod/fixmystreet/tree/master/locale/zh_TW.UTF-8/LC_MESSAGES">https://github.com/misgod/fixmystreet/tree/master/locale/zh_TW.UTF-8/LC_MESSAGES</a></p>
</blockquote></li>
<li><p>修改<strong>conf/general.yml</strong> <br>
基本上直接參考檔案內的註解就可以了。</p>
<blockquote>
<p>參考台南311的<a href="https://github.com/misgod/fixmystreet/blob/master/conf/general.yml">設定</a> </p>
</blockquote></li>
<li><p>設定回報類別及受理單位的mail</p>
<blockquote>
<p>直接參考<a href="http://fixmystreet.org/customising/fms_and_mapit/">http://fixmystreet.org/customising/fms_and_mapit/</a></p>
</blockquote></li>
<li><p>因為FixMyStreet會去檢查回報者的姓名字元必須大於5,所以這一個限制本身用在台灣是有問題的,所以我有寫信去給mysociety的人,他們說之後會修改。所以在目前這個時間就自己先拿掉檢查。</p>
<blockquote>
<p>修改<a href="https://github.com/misgod/fixmystreet/commit/3d4fe7676dd43a643175df85e0314af9bdf19420">perllib/FixMyStreet/DB/Result/Problem.pm</a> <br>
修改<a href="https://github.com/misgod/fixmystreet/commit/11b6a33b0c4cb5ccbeb7da681bf33998e64d6004">web/js/fixmystreet.js</a></p>
</blockquote></li>
<li><p>Web及CSS的修改(這個我沒做) <br>
FixMyStreet有個機制叫Co-brand讓你可以針對ui或是程式碼做一些客製化。</p>
<blockquote>
<p>參考 <a href="http://fixmystreet.org/customising/">http://fixmystreet.org/customising/</a></p>
</blockquote></li>
</ol>
<p><br><br></p>
<p>相關文章: <a href="http://35around.blogspot.tw/2014/07/311.html">台南311開發紀錄 (下)</a></p>misgodhttp://www.blogger.com/profile/00933441299043629398noreply@blogger.com0