<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4389461234607418203</id><updated>2012-01-25T14:34:58.802+08:00</updated><category term='ibus'/><category term='Clutter'/><category term='Framebuffer'/><category term='User Interface'/><category term='推薦好書'/><category term='旅行(Travel)'/><category term='Hacking 心得筆記'/><category term='Desktop'/><category term='NPM'/><category term='sbc8100'/><category term='Open Hardware'/><category term='ULLab'/><category term='Beagleboard'/><category term='ACPI'/><category term='Chewing'/><category term='顧問資詢'/><category term='Socket.IO'/><category term='Autotool'/><category term='Express Web Framwork'/><category term='GNOME'/><category term='GTK'/><category term='MongoDB'/><category term='Embedded System'/><category term='AT Command'/><category term='MIPS'/><category term='Git'/><category term='python'/><category term='8051'/><category term='devkit8000'/><category term='系統研發手札'/><category term='0xdroid'/><category term='哲學'/><category term='Mandice'/><category term='SCIM'/><category term='Android'/><category term='X11'/><category term='組合語言'/><category term='Startup'/><category term='OpenGL'/><category term='patch'/><category term='心情筆記'/><category term='開放原始碼'/><category term='Moblin'/><category term='Emdebian'/><category term='XPUD'/><category term='有趣新構思'/><category term='PL/pgSQL'/><category term='Linux硬體驅動'/><category term='消費經驗'/><category term='無線網路相關'/><category term='Window Manager'/><category term='作業系統實作'/><category term='心得分享、講座'/><category term='WebSocket'/><category term='Debian'/><category term='LXDE'/><category term='Chrome OS'/><category term='C/C++'/><category term='openmoko'/><category term='Dalvik VM'/><category term='GSM/GPRS/HSDPA'/><category term='NodeJS'/><category term='Java'/><category term='Google'/><category term='USB'/><category term='Juice'/><category term='PHP'/><category term='jpeglib'/><category term='E17'/><category term='自由軟體'/><category term='PostgreSQL'/><category term='epaper'/><category term='3D'/><category term='Web 相關技術'/><category term='Linux'/><category term='GStreamer'/><category term='Flat'/><category term='Qt'/><category term='Glib'/><category term='Debug'/><category term='Linux Kernel'/><category term='技術新知'/><category term='手機平台'/><category term='Cluster叢集架構'/><category term='商業'/><category term='Bash'/><category term='Tablet'/><category term='程式心得筆記'/><category term='JavaScript'/><category term='數值方法'/><category term='Webkit'/><category term='Cross-compile'/><category term='MTK'/><title type='text'>Fred's blog</title><subtitle type='html'>Do All Real Creative and Innovative Things</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default?start-index=101&amp;max-results=100'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>291</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-464918745872835857</id><published>2012-01-21T19:10:00.001+08:00</published><updated>2012-01-21T19:10:45.124+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='商業'/><title type='text'>商業操弄，軟體研發人員不喜歡做的事！</title><content type='html'>在國外，許多大型軟體公司林立，老牌軟體商建立了不少現今軟體業仍在使用的遊戲規則。而比較小的軟體外包商、工作室或是個人，也糊裡糊塗依照這些大公司使用的遊戲規則走，甚至是遵守不合時宜的淺規則。然後，軟體業進入了國內，又被代工思維牽著走，軟體業因此哀嚎聲不斷。軟體研發人才不喜歡去操弄商業，卻被商業操弄著。&lt;br /&gt;&lt;br /&gt;身為軟體外包或是軟體客製化的外包商，你是否曾遇過，客戶有很多大大小小的鎖碎要求，不定期會交代過來? 這些修修改改，看似不癢的功能和需求，做起來毫不費功夫，三兩下順手就能完成，卻往往造成雙方驗收標地的分岐，此外，不知不覺中所累積的份量，也讓結案時間遙遙無期，甚至造成軟體產生更多的問題待解決。對於只想當水電工的研發人員，總是在客戶的要求下，修完馬桶順道通水管，又補個土、也打個臘。另外，如果馬桶旁邊剛好有漏水，那你要自認倒楣了，因為客戶也會請你幫忙『順手』解決一下，或認定是你在修馬桶時弄壞的。是吧，令人難過。&lt;br /&gt;&lt;br /&gt;難道研發人員就要這麼可憐嗎？我們做錯了什麼，為何就要這樣被對待？明明是為了提供更好服務，卻累死三軍，又讓人有把柄指著鼻子唸。更慘的是，一旦這些看似不起眼的修修改改，累積成有影響力，讓專案與合約內的需求不完全相符。客戶就有機會利用『與合約不符』的矛盾點，再殺下一城。&lt;br /&gt;&lt;br /&gt;筆者也同是天涯淪落人，曾經不斷思考這問題也同時咒罵著台灣的業界，咒罵他們總不給軟體商有活命的空間。尤其受了委屈後，更是一股惱自命不凡，認為自己無論做什麼樣的事，都應該比一般人收取更多費用，以平心頭之恨。但過些時日後，經過冷靜思考，發現是一開始雙方的互動模式就錯了，或許更仔細檢視這個行業，才能找到改變現況的辦法。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;大多數軟體開發不是演藝事業&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;一直不認為『軟體程式設計師』是演藝事業，所謂『台上一分鐘，台下十年功』不能完全形容軟體開發的工作。雖然，越厲害的研發人員，越能設計好品質的軟體；越是名不經傳的軟體商，也越難生存於業界。許多面向與藝人生態有些相似，但其實完全不是這個樣子。&lt;br /&gt;&lt;br /&gt;因為我們雖練功多年，在專案過程中，卻仍然做很多沒技術性又取代性高的工作，或是『順手工作』這類連項目都寫不出來的事。所以，與演藝事業最大的不同是，我們不是只做一件事：『像巨星一樣站上台吸引全場目光，解決觀眾們長達數十分鐘的無聊時間』，而是因應專案需求，巨星仍然要下海當工讀生或工作人員，甚至是清潔工。所以，大多數軟體研發人員，其實扮演的是『跨年晚會工程的承包商』，不是巨星。許多客戶的額外零碎需求，就像有人在會場中亂扔垃圾需要被收拾，或是突然有人身體不適昏倒需要救護車送醫，這些都無法預期也無法很容易的按工計酬。&lt;br /&gt;&lt;br /&gt;這一切，除非你有將風險成本都算在專案內，更重要的是案子也要夠大，不然相當不容易去完成工作。這也是為什麼許多比較大的軟體商，比較不受影響，因為他們接的案子也夠大，風險成本都能很輕易的被安插進總報價裡面。&lt;br /&gt;&lt;br /&gt;因此，除了這類大型軟體商，多數中小外包商和客戶的想法，其實一開始便有了分岐。很多研發人員真的分不太清楚，自己只是當個明星，還是承包整個工程的承包商。但無論如何，客戶的心中一直很清楚認定：『承接專案的人就是整場晚會的承包商，我們不管你是不是把巨星拿來當小弟用，我們要得到的就是一個成功又圓滿的晚會』。&lt;br /&gt;&lt;br /&gt;一切的痛苦，已經不能責怪是不是當初定需求不夠明確，也不能怪研發人員利用太多『舉手之勞』提供給客戶額外的服務。最後你會發現，想再多的方法與客戶確認需求、利用商業手段與客戶定下契約，或是出動威脅利誘的業務手法與客戶協商，都是頭痛醫頭腳痛醫腳之舉。或許先認清楚自己想要做的角色和可以做的角色，再引入適當的制度，才是突破現況的第一要務。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;我們只想當水電工&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;說明白了，我們只想當個『軟體水電工』，有工就有酬，沒經驗的小工拿一份酬，有經驗的工頭拿雙倍酬，立即解決問題就立即收錢，然後打道回府等下一個工。至於整體工程承包，我們其實一點興趣都沒有。&lt;br /&gt;&lt;br /&gt;只是，當水電工似乎是遙不可及的夢，因為客戶就是自己不能解決或決定，才外包找人解決，他們想要得到的是整個解決方案，而不只是工人。更重要的是，在資訊科技業中，客戶無法看到漏水就能自行判斷要找水電工，而是要先找醫生診斷病情，然後才選擇治療方案和醫療團隊。&lt;br /&gt;&lt;br /&gt;雖然很可惜的是，大多數情況下，軟體研發人員沒辦法只當個『水電工』，但肯定有不少需求，是可以規劃成專業服務，使用水電工的收費方式，若是多加思考，應該能有些斬穫。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;我們也許可以當醫生&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;其實仔細省閱一下醫生的工作，除了要聽取問題、診斷病情、評估可行性和提出處方，必要時要進入手術室開刀和操作儀器去治療病人，就像軟體外包在做的一般，開玩笑的說，我們也許可以稱醫生為『人體工程師』。此外，而客戶基於安心考量，多少也會自行去尋找名醫。這些種種情況，個人認為軟體研發人員其實更像個醫生。&lt;br /&gt;&lt;br /&gt;因為像醫生，所以在簽約進行手術或治療前，我們也必需要做許多評估。但不一樣的是，無論醫生是否有治療成功，醫院總是有錢領，但軟體業則是要摸著鼻子認了。許多軟體外包商，在談案子的階段，最怕的就是不清楚技術上可行與否，或是不知自己有沒有能力達成。所以，多數軟體研發人員在面對不同案子簽約之前，就算不確定是否會得到案子，也都會先做許多評估或提前研究，甚至，必需提前偷跑才能知道可行性。&lt;br /&gt;&lt;br /&gt;不過，面對現在科技產業客戶都追求創新的情勢，這種不確定性的程度更甚也更常見，如果案子接到了還算好，如果沒接到，這種事前研究期的資源浪費，讓更多中小軟體商非常痛苦。更還沒提到，接到案子後如果有不可預期的技術瓶頸（像是配合的硬體平台有嚴重且之前未被發現的 Bug），造成手術失敗或時間拉長的情況。真正的醫療體系或許還有保險可以支付手術費用，但在軟體業，這意味著無法結案，收不到款。&lt;br /&gt;&lt;br /&gt;因為這樣不易收到款的制度，軟體承包商為了結案，屢見不鮮地用盡『各種手段』處理和討好客戶的需求，包括了文章開頭提到的『舉手之勞』和隨之而來的各種問題。導致其開發出來的軟體品質不佳，客戶也得不到最好的成果，常有狗尾續貂的情況發生，講的更難聽些，虎頭蛇尾會更為貼切。&lt;br /&gt;&lt;br /&gt;可憐的是，軟體研發不是人命關天，一切在商言商，客戶們通常不願只付『掛號費』，還可能貨比三家。哪一家能『價格殺的夠低』又拍胸脯『保證全部完成』，哪一家就能搶到案子。如此惡性競爭，更加深擴大了軟體研發人員被劃開的傷口。&lt;br /&gt;&lt;br /&gt;軟體產業沒有軟體健康保險補助，不是所有人都能夠負擔起看醫生、身體檢查和評估的費用，所以在這產業中有錢人才能夠看醫生。不然就是醫生得扛起所有風險和責任，並吸收許多成本，才能去拓展市場。&lt;br /&gt;&lt;br /&gt;或許，要求政府有相應的保險制度不太可能，但更細的分工整合和處方制度，可能是一個可行的思路。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;試圖尋求保障雙方的軟體開發模式&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;客戶和軟體商雙方的拉距戰，就像一個很大的槓桿，一不小心另一邊就飛上了雲端。&lt;br /&gt;&lt;br /&gt;我們可以理解，不能完全怪罪於客戶，畢竟所有人都總是希望得到完整的解決方案、降低風險，又盡可能支付最少的錢。小客戶是預算不高要緊扣，大客戶則是怕付了錢，卻達不到目的，或是得到一堆無法使用的 01 文字。&lt;br /&gt;&lt;br /&gt;但對於軟體研發人員來說，卻也太過不公平，只能全賠和拼命乞討二選一。&lt;br /&gt;&lt;br /&gt;現有的各種手段都無法幫助軟體商突破現況，太多的慣例也惡習累積已久。這也是為什麼，很多以接案起家的新創公司(Startup)，到五、六個人之後，開始碰到瓶頸。因為小案子已經養不起公司，中間的案子不好做，再上去就要一股作氣引進人員到數十人才能做。但人數到這麼多時，大案子的獲利也只是勉勉強強。&lt;br /&gt;&lt;br /&gt;所以，如何想出方法，雙方保障，是不可放棄的目標。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;本文只是先起了個開頭，省視當前情勢。雖然對於實際執行，已經有些初步方案，有空再記錄下來，期望大家共同尋找出一個可行的制度。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-464918745872835857?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/464918745872835857/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2012/01/blog-post_21.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/464918745872835857'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/464918745872835857'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2012/01/blog-post_21.html' title='商業操弄，軟體研發人員不喜歡做的事！'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-7539429172421930586</id><published>2012-01-11T13:17:00.001+08:00</published><updated>2012-01-11T13:35:03.616+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Express Web Framwork'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='NodeJS'/><category scheme='http://www.blogger.com/atom/ns#' term='Web 相關技術'/><title type='text'>NodeJS + Express + i18next 支援多國語系吧！</title><content type='html'>除非是區域性的網站服務，不然在這個網路通全世界的時代，開發網站服務就一定有多國語系的需求。一般來說，i18n 的支援都是由 Web Framework 所提供，但 Express 並沒有支援，所以我們要借助 i18next 這個模組。i18next 可以和 Express 以及 template 很完美的結合，最重要的是，有客戶端支援(clientside support)，若搭配 jquery，我們也可以使前端的 JavaScript 支援多國語系。&lt;br /&gt;&lt;br /&gt;先使用 NPM 安裝 i18next：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;npm install i18next&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;在 express 的應用程式(app.js)中引入使用 i18next：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;var express = require('express');&lt;br /&gt;&lt;b&gt;var i18n = require('i18next');&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;var app = module.exports = express.createServer();&lt;br /&gt;&lt;br /&gt;&lt;b&gt;/* Initializing i18n */&lt;br /&gt;i18n.init();&lt;br /&gt;i18n.registerAppHelper(app);&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;app.configure(function(){&lt;br /&gt;  app.set('views', __dirname + '/views');&lt;br /&gt;  app.set('view engine', 'jade');&lt;br /&gt;  app.use(express.bodyParser());&lt;br /&gt;  &lt;b&gt;app.use(i18n.handle);&lt;/b&gt;&lt;br /&gt;  app.use(express.methodOverride());&lt;br /&gt;  app.use(app.router);&lt;br /&gt;  app.use(express.static(__dirname + '/public'));&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;app.get('/', function(req, res) {&lt;br /&gt;  res.render('index');&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;app.listen(3000);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;接著要在應用程式的目錄下，建立預設的翻譯檔和存放路徑（locales/dev/translation.json）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;{&lt;br /&gt;  "example": {&lt;br /&gt;    "string1": "Hello World!"&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;如果要支援繁體中文(zh-TW)，直接建立相應的翻譯檔（locales/zh-TW/translation.json）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;{&lt;br /&gt;  "example": {&lt;br /&gt;    "string1": "哈囉 世界！"&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;然後就可以在 template 中使用之前所定義的字串(views/index.jade)：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;span= t('example.string1')&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;完成之後，i18next 會自動依照用戶瀏覽器的語系設定，回應相對應的頁面。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;文章一開頭有提到，i18next 可以配合 jquery 使用，有興趣的人可以直接參考『&lt;a href="http://jamuhl.github.com/i18next/"&gt;官方說明&lt;/a&gt;』。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-7539429172421930586?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/7539429172421930586/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2012/01/nodejs-express-i18next.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/7539429172421930586'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/7539429172421930586'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2012/01/nodejs-express-i18next.html' title='NodeJS + Express + i18next 支援多國語系吧！'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-5560914666573214213</id><published>2012-01-07T04:18:00.000+08:00</published><updated>2012-01-07T10:06:47.928+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='顧問資詢'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Embedded System'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><title type='text'>【企業顧問咨詢】為您的產品選擇作業系統解決方案</title><content type='html'>你將為自家的產品，選用什麼樣的作業系統？我想，這年頭，不外乎是 Android。但是，可能不是最佳選擇。&lt;br /&gt;&lt;br /&gt;我想大多數人都會同意，由於智慧型行動裝置的掘起，Google Android 在業界大放異彩，使用 Linux 作業系統核心的 Android，實現了許多華麗的UI，也讓眾多廠商取得入門門票，有機會與 Apple iOS 一爭長短。許多人都相信，未來是 Android 的天下，除了手機要用 Android，電視要 Android，救人一命的醫療器材也要用 Android，所謂的 Android anywhere 是終極目標。&lt;br /&gt;&lt;br /&gt;不過，經過這幾年下來，許多人發現這不過是我們資訊科技業一廂情願，有太多的領域是難以使用 Android，如工控市場等，無論是以穩定、價格、移植維護成本考量的因素，都可能是無法使用 Android 的重點。因此，如今要選擇作業系統解決方案，又變成一個需要思考的難題。&lt;br /&gt;&lt;br /&gt;筆者擔任顧問時，每當面對客戶躊著於這個問題時，我總問他們幾個大問題：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;你們的產品用途是否單一且單純？是否要有讓使用者自行上網安裝其他第三方軟體的擴充性？&lt;/li&gt;&lt;li&gt;你們的產品是否為消費行電子產品？是否需要高可用行和高穩定性？&lt;/li&gt;&lt;li&gt;你們的軟體需要有華麗特效的 UI 嗎？你們現在擁有的人員有哪些開發 UI 程式的經驗？&lt;/li&gt;&lt;li&gt;有網路的需求嗎？如果有，需要哪些需求？Ethernet、Wifi、3G？&lt;/li&gt;&lt;li&gt;計劃中的產品硬體規格？&lt;/li&gt;&lt;li&gt;有多少規模的人可以參與開發？&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;很明顯的，對於手機和行動裝置業者是這樣的答案：（他們都會選用 Android）&lt;br /&gt;&lt;ol&gt;&lt;li&gt;用途不單一，需要讓使用者任意自行上網安裝軟體。&lt;/li&gt;&lt;li&gt;是功能複雜的消費性電子產品，所以客戶多多少少能接受偶爾當機&lt;/li&gt;&lt;li&gt;UI 需要有華麗的特效。開發人員都熟悉並使用 Java 的經驗。&lt;/li&gt;&lt;li&gt;有所有網路的需求。&lt;/li&gt;&lt;li&gt;擁有一定等級以上或是當前最頂級的 ARM 處理器。&lt;/li&gt;&lt;li&gt;最少數十個，多半是上百人甚至上千人的研發人員。&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;如果你是『非手機』和『非行動裝置』業者，你的產品可能不完全具備這些條件。建議您，一旦有任何一點不具備，請慎重考慮是否使用 Android 還是有機會選擇其他的解決方案。&lt;br /&gt;&lt;br /&gt;而當前的解決方案主要常見有三種：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;Android&lt;br /&gt;Linux + Qt Framework&lt;br /&gt;Linux + Own Application&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;限於篇幅，太細節的評估無法一一列舉，也要視實際狀況而定，但這邊有個簡易的初步評估方法可以提供參考：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;檢視產品的用途是否單純&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;如果你的產品用途不單純，應用不單一且不易規範使用範疇，Android 會是你首要的選擇。&lt;br /&gt;&lt;br /&gt;此外，假設你們的產品用途非常單純，又或者是功能並不複雜，建議您可以採用非 Android 的解決方案。理由如下：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;&lt;ol&gt;&lt;li&gt;Android本身有許多公認的問題，運氣好沒事，運氣不好這些問題都需要自行解決，由於可能出問題的範圍相當廣，要確保有足夠資源處理這些問題。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Android有太多版本且隨時可能會有更新和問題修正，再加上上述問題，開發過程中不可能不追加資源去跟進或監視 Android 當前的狀態。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;如果從產品開發開始到開發結束，都需要人力資源去維護和跟隨，這無疑是一種人力上的消耗。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;到此為止還沒提到正題，產品本身應用的開發，在處理好以上問題之後，才開始準備進入正軌。&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;很多人常說，使用 Android 開發產品的時程是 Debug 的時間比寫軟體的時間多，有時甚至多達 10:1 都不為過。對於行動裝置廠商來說，整個系統就是產品的整體，花大量資源去維護可以說是理所當然的，但是對非行動裝置廠商來說，這就是額外的開銷甚至是條不歸路，除非您也想找筆者救火（但是筆者當救火員的日子可能不多了，笑）。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;如果您也正在煩腦選擇作業系統的問題，希望這本文能幫上忙。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-5560914666573214213?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/5560914666573214213/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2012/01/blog-post_07.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5560914666573214213'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5560914666573214213'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2012/01/blog-post_07.html' title='【企業顧問咨詢】為您的產品選擇作業系統解決方案'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-1504757578733292085</id><published>2012-01-06T00:32:00.000+08:00</published><updated>2012-01-11T13:19:48.331+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='MongoDB'/><category scheme='http://www.blogger.com/atom/ns#' term='NodeJS'/><category scheme='http://www.blogger.com/atom/ns#' term='Web 相關技術'/><title type='text'>NodeJS 與 MongoDB 的邂逅</title><content type='html'>雖然 NodeJS 的模組和開發資源相當多，但相關文件卻非常不足或是不完整，多半文獻都只著重於基礎的使用和片斷的說明，如果不去看原始程式碼，使用 NodeJS 來完成實用的網站，會有很大的困難度。對於已經有過 Web 開發經驗的人，轉換使用 NodeJS 不免也需要花一番功夫，過去經驗中許多的常用的功能，都仍要一一花大量時間嘗試才得以解決。而這樣的情況，對於開發者來說相當的糟，也是很多人重新再評估是否使用 NodeJS 的重點因素之一。有道是『一人得道，雞犬升天』，因此筆者未來將嘗試將自己的實際經驗，寫成一篇篇重點功能實作的文章和隨 Copy 即用的範例，減少其他人浪費同樣的時間再摸索。&lt;br /&gt;&lt;br /&gt;開發一個 Web 應用程式，最重要的莫過於資料庫的使用，過去 PHP 有 MySQL 當最佳夥伴，而現在 NodeJS 有 MongoDB 做最佳的組合。MongoDB 是 NoSQL 的代表之一，其採用 JSON/BSON 當做資料儲存和溝通的格式，亦使用 JavaScript 做為 Server-side 的執行程序語言（相當於傳統 RDBMS 的預儲程序），一切設計和習慣與 NodeJS 搭配使用起來，簡直絕配。若你對 MongoDB 的一些基本操作有疑問，可以先參考舊文『&lt;a href="http://fred-zone.blogspot.com/2011/07/mongodb.html"&gt;MongoDB 快速筆記&lt;/a&gt;』。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;使用 MongoDB&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;MongoDB 擁有 NoSQL 的普遍特色，不用預先定義 Schema，所有的 database 和 collection（相當於傳統 RDBMS 的 Table），都會在新增資料後，自動被建立，我們只要專注於使用 NodeJS 操作資料庫即可。&lt;br /&gt;&lt;br /&gt;要在 NodeJS 裡使用 MongoDB，可以安裝 mongodb native driver，若透過 npm 來安裝：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;npm install mongodb&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;然後可以使用 NodeJS 建立 MongoDB connection pool ，做一些基礎的操作：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;var mongodb = require('mongodb');&lt;br /&gt;&lt;br /&gt;var mongodbServer = new mongodb.Server('localhost', 27017, { auto_reconnect: true, poolSize: 10 });&lt;br /&gt;var db = new mongodb.Db('mydb', mongodbServer);&lt;br /&gt;&lt;br /&gt;/* open db */&lt;br /&gt;db.open(function() {&lt;br /&gt;    /* Select 'contact' collection */&lt;br /&gt;    db.collection('contact', function(err, collection) {&lt;br /&gt;        /* Insert a data */&lt;br /&gt;        collection.insert({&lt;br /&gt;            name: 'Fred Chien',&lt;br /&gt;            email: 'cfsghost@gmail.com',&lt;br /&gt;            tel: [&lt;br /&gt;                '0926xxx5xx',&lt;br /&gt;                '0912xx11xx'&lt;br /&gt;            ]&lt;br /&gt;        }, function(err, data) {&lt;br /&gt;            if (data) {&lt;br /&gt;                console.log('Successfully Insert');&lt;br /&gt;            } else {&lt;br /&gt;                console.log('Failed to Insert');&lt;br /&gt;            }&lt;br /&gt;        });&lt;br /&gt;&lt;br /&gt;        /* Querying */&lt;br /&gt;        collection.find({ name: 'Fred Chien' }, function(err, data) {&lt;br /&gt;            /* Found this People */&lt;br /&gt;            if (data) {&lt;br /&gt;                console.log('Name: ' + data.name + ', email: ' + data.email);&lt;br /&gt;            } else {&lt;br /&gt;                console.log('Cannot found');&lt;br /&gt;            }&lt;br /&gt;        });&lt;br /&gt;    });&lt;br /&gt;});&lt;/pre&gt;&lt;/div&gt;註：這是 MongoDB 的基本常識，每當新增一筆資料，MongoDB 會自動幫該筆資料加上 _id 欄位，並給與一個唯一值（格式是 ObjectId），所以我們不需要像過去  使用 SQL Server 一般，自己刻意去定義一個 ID 欄位。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;預設的 ObjectId 範圍太小，改用 UUID 來當資料的唯一 ID&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;如果你過去有過 Web 開發經驗，到這邊肯定會開始有一些疑問欲求解，第一個問題肯定是『ObjectId 的數量極限？』。筆者在此不會回答這問題，因為這答案並不重要，想要準確知道答案，可以去『&lt;a href="http://www.mongodb.org/"&gt;mongodb.org&lt;/a&gt;』尋找答案。&lt;br /&gt;&lt;br /&gt;比起上述問題，相信你應該更想問：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;預設的 ObjectId 適用的範圍？&lt;br /&gt;如果日後資料庫要擴展(Scale)，是否有其他的 ID 解決方案可使用？&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;一般情況， MongoDB 預設的 ObjectId 就相當夠用了，但如果你是要建構大型的 Web Service 或是保留未來的擴充性，可使用 UUID 去代替 ObjectId。不過，因為 MongoDB 本身並不生成 UUID，若是要使用 UUID，就必需先自行產生好 UUID，然後在新增資料時指定生成好的 UUID 給 _id 欄位，讓 MongoDB 改用我們給的 ID 而不使用預設生成的 ObjectId。&lt;br /&gt;&lt;br /&gt;因為要自行產生 UUID，必需先為 NodeJS 安裝模組 node-uuid：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;npm install uuid&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;然後生成 UUID 並在 insert 時使用：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;var uuid = require('node-uuid');&lt;br /&gt;var mongodb = require('mongodb');&lt;br /&gt;&lt;br /&gt;var mongodbServer = new mongodb.Server('localhost', 27017, { auto_reconnect: true, poolSize: 10 });&lt;br /&gt;var db = new mongodb.Db('mydb', mongodbServer);&lt;br /&gt;&lt;br /&gt;/* open db */&lt;br /&gt;db.open(function() {&lt;br /&gt;    /* Select 'contact' collection */&lt;br /&gt;    db.collection('contact', function(err, collection) {&lt;br /&gt;&lt;br /&gt;        /* Generate UUID(16 Bytes) and convert to BinaryData object for mongodb */&lt;br /&gt;        var uuidBinary = new Buffer(uuid.v1({}, []));&lt;br /&gt;        var id = mongodb.BSONPure.Binary(uuidBinary, mongodb.BSONPure.Binary.SUBTYPE_UUID);&lt;br /&gt;&lt;br /&gt;        /* Insert a data with uuid */&lt;br /&gt;        collection.insert({&lt;br /&gt;            _id: id,&lt;br /&gt;            name: 'Fred Chien',&lt;br /&gt;            email: 'cfsghost@gmail.com'&lt;br /&gt;        }, function(err, data) {&lt;br /&gt;            if (data) {&lt;br /&gt;                console.log('Successfully Insert');&lt;br /&gt;            } else {&lt;br /&gt;                console.log('Failed to Insert');&lt;br /&gt;            }&lt;br /&gt;        });&lt;br /&gt;    });&lt;br /&gt;});&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;你可能會發現，在上面的範例程式中，我們將 UUID 轉成 MongoDB BSON 的 BinaryData 格式，這是為了效能考量，因為用純字串當做 Unique ID，在資料庫搜尋上會比 BinaryData Object 慢很多。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;儲存時間戳(Timestamp)&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;關於儲存時間的問題，如果你去各大 MongoDB 討論區詢問或查詢，通常大家都會告訴你不必做這件事，因為每一筆資料被建立後，自動產生的 ObjectId 就包含了建立的時間訊息，我們只要去學習如何從中去解析時間即可。但是，不單只是建立時間，有時我們會為資料加上各種不同的時間戳，如：更新時間等，所以，儲存時間戳還是必要的。&lt;br /&gt;&lt;br /&gt;雖然網路上相關 NodeJS 範例並不多，但 MongoDB 確實有 Timestamp 的資料結構可以用，我們可以這樣使用：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;var uuid = require('node-uuid');&lt;br /&gt;var mongodb = require('mongodb');&lt;br /&gt;&lt;br /&gt;var mongodbServer = new mongodb.Server('localhost', 27017, { auto_reconnect: true, poolSize: 10 });&lt;br /&gt;var db = new mongodb.Db('mydb', mongodbServer);&lt;br /&gt;&lt;br /&gt;/* open db */&lt;br /&gt;db.open(function() {&lt;br /&gt;    /* Select 'contact' collection */&lt;br /&gt;    db.collection('contact', function(err, collection) {&lt;br /&gt;&lt;br /&gt;        /* Generate Timestamp and convert for mongodb */&lt;br /&gt;        var ts = new Date().getTime();&lt;br /&gt;        var i = ts % 1000;&lt;br /&gt;        var t = new mongodb.BSONPure.Timestamp(i, Math.floor(ts * 0.001));&lt;br /&gt;&lt;br /&gt;        /* Insert a data with uuid */&lt;br /&gt;        collection.insert({&lt;br /&gt;            name: 'Fred Chien',&lt;br /&gt;            email: 'cfsghost@gmail.com',&lt;br /&gt;            created: t&lt;br /&gt;        }, function(err, data) {&lt;br /&gt;            if (data) {&lt;br /&gt;                console.log('Successfully Insert');&lt;br /&gt;            } else {&lt;br /&gt;                console.log('Failed to Insert');&lt;br /&gt;            }&lt;br /&gt;        });&lt;br /&gt;    });&lt;br /&gt;});&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;建立資料庫索引(Index)&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;過去有接觸過資料庫的人應該都很清楚，索引(Index)是能優化資料查詢速度的重要功能，MongoDB 同樣也有索引的設計。&lt;br /&gt;&lt;br /&gt;可以在 NodeJS 中，這樣為 name 欄位加上索引：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;collection.createIndex({ name: 1 });&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;到此為止，你應該能開始盡情使用 NodeJS + MongoDB 開發 Web Service 了，開始享受完全的 JavaScript 開發人生吧！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-1504757578733292085?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/1504757578733292085/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2012/01/nodejs-mongodb.html#comment-form' title='3 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1504757578733292085'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1504757578733292085'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2012/01/nodejs-mongodb.html' title='NodeJS 與 MongoDB 的邂逅'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-2895245458453245322</id><published>2012-01-02T03:43:00.000+08:00</published><updated>2012-01-02T04:49:39.777+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><title type='text'>苦其心志，勞其筋骨後，世界末日年快樂！</title><content type='html'>2012 新年快樂！今年格外不同，也是人稱世界末日將來臨的一年，而在這人生將結束的一年，不免開始思考今年的自我期許。 :-)&lt;br /&gt;&lt;br /&gt;回顧去年的風雨，當了一年的『救火隊長』。曾經為了救援朋友的案子，連續三個月，每天平均睡不到一小時，且平均連續工作達72小時以上，如果過程中突然一命嗚乎，一點也不意外。還好，這樣可怕的惡夢，都一一挺了過去，雖然身體似乎出現了點問題，不時陣痛襲來。不過，老天讓我完好的活下來，是祂已經頒發『超級救火員勛章』的最佳證明。&lt;br /&gt;&lt;br /&gt;我總相信，只要有信念和方向，任何困境都是老天賜予的挑戰，每當苦盡甘來，就會有許多更好的機運等著。事實上，當了一年職業救火員不是沒有好處，看到了許多人不為人知面貌，許多業界的問題和盲點，更認清了自己該做的事，也得到了更棒更成熟的點子。甚至，某個程度上，已經不害怕死亡突然降臨。&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;pre&gt;為什麼過的這樣辛苦？為什麼總是孤單的拼命？是否該檢討一下自己？&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;還清楚記得，這一年有些人這樣問過我，我都沒有正面回答，直到現在才有時間靜下來思考這個問題，也自我檢討了一番。&lt;br /&gt;&lt;br /&gt;如果因為負責任而辛苦減壽，為了理想而拼了命和全世界作對，那我真的想不出有任何一點不正確的地方。我只能推論，許多人不願意辛苦，甚至可以『不負責任』去避免辛苦；許多人沒有懷抱理想，所以沒有拼命的目標，只有隨波逐流的生活。&lt;br /&gt;&lt;br /&gt;真的要自我檢討，除了憤世忌俗外，就是我死腦筋的總是依據一件事的『順利和成就』，考量應該做什麼，甚至不是自己的義務，也會執行到底，貫徹著父親所囑付：『幫忙之前叫幫忙，幫忙之後叫責任。』然而，許多人理所當然以為處處都是我的義務和責任，一股惱全加諸於我身上。使我，做會自己勞累不堪，不做則內心不舒服，痛苦萬分。&lt;br /&gt;&lt;br /&gt;而這樣的個性，讓我和傳統做生意一點都不搭軋，因為我永遠不愛也不喜歡打『把對手權利變成對手義務』的拉拒戰。在這樣的商場戰爭下，人人都不想執行自己的義務，只想行使自己的權利，甚至讓對方的權利變成自己的權利。不過，雖然不喜歡，但不代表我不懂，每次回歸原點和原貌來看，就會發現『人有多不要臉』和『許多醜陋的臉孔』的戲碼都正在天天上演，過程中的種種掩飾都讓人不敢相信，任誰看了都會臉紅找洞鑽。&lt;br /&gt;&lt;br /&gt;如果這樣才能不辛苦不孤獨，我寧可苦一輩子。我也永遠不相信，那樣的結黨，能夠有什麼未來。此外，如此彆扭的生意，也不是我所期望的目標。&lt;br /&gt;&lt;br /&gt;過去無數個日子，腦袋從未停止轉動過。啄磨過許多想法，也思考過許多問題，思考中入眠已經是常態。堅信，苦其心志，勞其筋骨，然後，痛痛快快又能無後顧之憂的完成件『應該做的事』，這就是今年的自我期許。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-2895245458453245322?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/2895245458453245322/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2012/01/blog-post.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2895245458453245322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2895245458453245322'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2012/01/blog-post.html' title='苦其心志，勞其筋骨後，世界末日年快樂！'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-1730665112095651505</id><published>2011-12-29T17:14:00.001+08:00</published><updated>2011-12-29T17:26:12.126+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Startup'/><title type='text'>【Startup 談心酸】 當革命情感對上體制</title><content type='html'>我總認為，當別人問起職業，回答『Startup(新創)』是一件很自傲的事。雖然公司不大，但是從兩手空空開始，完成理想的感覺真的是棒呆了！你必需經歷『養活自己』、『勒緊褲帶』、『想破腦袋』還有『革命不怕失敗』的種種過程，最重要的是，伴隨而來的『人的問題』，很有可能成為最後一根稻草，壓垮我們。但每當跨越過每一個階段，彷彿就吃了甜美多汁的果實，相當有滋味。&lt;br /&gt;&lt;br /&gt;常聽到有人說：『先不談成功與否，Startup能做超過一年，就相當不容易了。』，其實是事實，從創業中敗陣下來的人不在少數，敗陣的原因更不勝枚舉，有人是受不了壓力，有人把持不住Cash Flow（現金流），有人經營心態不正確，或是 idea 失敗等等。但是，這些原因真的都比不上『同伴』所造成的打擊。&lt;br /&gt;&lt;br /&gt;如果你不是一個人創業，而是三五好友有志一同，那我要恭喜你，畢竟要能找到方向相同，又有足夠能力的人一起是非常困難的。但是，我也要為你感到遺憾，因為『人的問題』會帶來更多波折和困難，造成創業失敗的比例更高。『同伴』是個雙刃劍，雖能共患難，有革命情感，但也會因決裂而一夕之間毀滅。&lt;br /&gt;&lt;br /&gt;這裡有一個朋友的小故事，相當常見，或許大家都很熟悉其中情節：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;有一群人在學校就是好朋友，而所會的技術也讓他們相當出類拔粹，於是，他們孕釀出創業的想法。為了小試身手，這些人開始共同接一些小案子，並培養革命情感。看似一切很美好，但在過程中問題出現了，有人怠惰（或是能力不足）造成其他人負擔增加，又或者是因此造成案子無法順利結案。好不容易，其他隊員們跳出來『Cover』，讓一切過了關，客戶也付了錢。&lt;br /&gt;&lt;br /&gt;然而，問題才正要發燒，在分配利益時，有人開始提出不滿：『為什麼出包的同伴，可以拿的錢和沒出包的人一樣多？為什麼救火的人，幫出包的人完成不是自己的大部份工作，卻只拿到原本的待遇？』此外，對工作的分配也頗有微詞，有人認為自己做的工作，相對困難許多，應該分到更多的錢。更誇張的是，每一個人都生怕別人多拿或是拿的比自己多。&lt;br /&gt;&lt;br /&gt;還好，為了讓大家不要決裂，盡可能滿足大家的要求，有人跳出來處理這件事，除了自己掏腰包，甚至動用了原本大家講好要保留下來的『公基金』。然後發現，雖然大家都同意切出一部份成為公基金，但心中仍然認定這公基金有一部份是屬於自己的，隨時都可以要回去，有人更不時想動用或拿回這個錢。一旦動用公基金，就會牽動到大夥的神經，引發更多莫明其妙的問題。&lt;br /&gt;&lt;br /&gt;問題並沒有因為時間久而消失，之後的幾次案子，多多少少都出現類似的狀況，磨光了真正想做事的人，其心中的熱情。最終，革命情感不敵絕望，因看不到未來而拆夥。&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;這個劇情也許正在你的團隊中上演，更或者有更多超出這故事內容的問題發生。總而言之，問題出在於每個人都不肯讓自己的利益有任何損傷，也只能看到自己眼前的利益。就算有人出來願意奉獻，也只是減緩問題發酵，並沒有真正解決問題。一旦緩充的空間消耗殆盡，這個團隊就走向末路。&lt;br /&gt;&lt;br /&gt;很多人會說，大家都是好朋友，也都有相同志向，過程中難免會有些問題，我們都可以不用太計較，這樣也有共患難的革命情感。但事實上，人性很難抵抗，已經有太多人實驗過，都證明了『不計較才計較』。只是有人爆發的點比較高，平時看不出來，可是一旦爆發，便天崩地裂跟你沒完。想想看，連親密的親人都可以為了遺產殺紅了眼，更何況只是『普通朋友』。&lt;br /&gt;&lt;br /&gt;最後你會發現，革命情感是解決不了任何事，正確的建立公司體制是最好的方式，雖然很死板無情，但不容任何人有第二句話，也給參與者有人性上的約束，前人所遺留下來的方式，是有其道理的。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-1730665112095651505?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/1730665112095651505/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/12/startup.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1730665112095651505'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1730665112095651505'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/12/startup.html' title='【Startup 談心酸】 當革命情感對上體制'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-6201160083333968898</id><published>2011-12-25T17:21:00.000+08:00</published><updated>2011-12-26T17:56:28.552+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='作業系統實作'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><title type='text'>從 Linux Kernel 出發看！探討 Process 組成結構！</title><content type='html'>對所有電腦使用者而言，執行一支應用程式就像吃蛋糕一樣簡單。對於程式開發者而言，寫支 Hello World Program 並跑起來，也是三十秒內可以完成的事。但是，這樣容易的動作，其實底層有著複雜的機制，否則短短十行程式碼的 Hello World 能夠動起來，真的是奇跡了。想要知曉程式是怎麼被作業系統執行，要追溯到 Process 的機制，在研究過 Linux Kernel 的 Process 相關機制後，一切就將明朗。&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #666666;"&gt;註：在本篇文章內，都將會假設 binary program 已經被作業系統解析並放到記憶體執行，說明只著重於 Process 的部份 。雖然 Process 與 binary program 和其載體息息相關，但本文不會討論 ELF 的細節，有興趣的讀者可以自己去尋找相關文件閱讀。&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;若你是程式開發者，對『Process（程序）』一詞應該不陌生。嚴格來說， Process 就是處於執行狀態的程式，如果參考一些原文書或英文文獻，它們也許會這樣定義：『Process is a program in execution』。所以我們可以認定，Process 的組成，是擁有著『程式執行檔的 binary code + 記錄資料的記憶體』。&lt;br /&gt;&lt;br /&gt;本文將 Process 分成內外兩個角度來探討：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;從 Process 內部，程式執行的觀點&amp;nbsp;&lt;/li&gt;&lt;li&gt;從 Process 外部，也就是作業系統的觀點&amp;nbsp;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;b&gt;程式執行的觀點&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;單純以 Process 內部的角度來看，Process 就是一般的程式碼被放到記憶體執行。曾於舊文『&lt;a href="http://fred-zone.blogspot.com/2010/12/linux.html"&gt;Linux 下程序的記憶體映射&lt;/a&gt;』略為提及，一支程式擁有著數個 segments（區段），並仰賴著這些 segment 來持續運作。大致上來說，每個 segment 有不同的用途：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Code Segment - 存放主要程式&lt;/li&gt;&lt;li&gt;Data Segment -&amp;nbsp;存放已被初始化並賦予值的全域變數&lt;/li&gt;&lt;li&gt;BSS Segment - 紀錄尚未被賦予值的全域變數&lt;/li&gt;&lt;li&gt;Stack Segment(Stack/Heap) - 紀錄 Process 在執行時動態註冊的變數包括 function 中的 local variable&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;對程式本身來說，會動態並隨機使用的是 Stack Segment，程式向作業系統(OS) 要記憶體空間後，就可以在 Stack Segment 讀寫該記憶體空間。而實際上 OS 底層的行為，是配置記憶體， 然後映射到 Stack Segment 供程式使用。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;作業系統的觀點&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;與程式觀點相呼應，作業系統有記憶體管理機制，其建立虛擬記憶體空間，將程式對映進去該空間後，開始執行。作業系統管理著 Process 所擁有的 Segments，為每個 Segment 都配置了『虛擬記憶體區域(VMA, Virtual Memory Area)』。&lt;br /&gt;&lt;br /&gt;在 Linux 之下，我們可以透過 cat /proc/&amp;lt;Process ID&amp;gt;/maps 的方式去取得一個 Process 所用到的記憶體，以下是觀察系統上的 bash（PID=18165）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;$ cat /proc/18165/maps&lt;br /&gt;&lt;b&gt;08048000-0810a000 r-xp 00000000 08:01 1851399 &amp;nbsp; &amp;nbsp;/bin/bash&lt;/b&gt;&lt;br /&gt;&lt;b&gt;0810a000-0810f000 rw-p 000c1000 08:01 1851399 &amp;nbsp; &amp;nbsp;/bin/bash&lt;/b&gt;&lt;br /&gt;0810f000-08114000 rw-p 00000000 00:00 0&lt;br /&gt;&lt;b&gt;08752000-08a46000 rw-p 00000000 00:00 0 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;[heap]&lt;/b&gt;&lt;br /&gt;b737b000-b7396000 r--p 00000000 08:01 28598806 &amp;nbsp; /usr/share/locale/zh_TW/LC_MESSAGES/libc.mo&lt;br /&gt;b7396000-b73a0000 r-xp 00000000 08:01 12755293 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libnss_files-2.13.so&lt;br /&gt;b73a0000-b73a1000 r--p 00009000 08:01 12755293 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libnss_files-2.13.so&lt;br /&gt;b73a1000-b73a2000 rw-p 0000a000 08:01 12755293 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libnss_files-2.13.so&lt;br /&gt;b73a2000-b73b5000 r-xp 00000000 08:01 12755189 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libnsl-2.13.so&lt;br /&gt;b73b5000-b73b6000 r--p 00012000 08:01 12755189 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libnsl-2.13.so&lt;br /&gt;b73b6000-b73b7000 rw-p 00013000 08:01 12755189 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libnsl-2.13.so&lt;br /&gt;b73b7000-b73b9000 rw-p 00000000 00:00 0&lt;br /&gt;b73ca000-b73cc000 r--p 00000000 08:01 28600275 &amp;nbsp; /usr/share/locale/zh_TW/LC_MESSAGES/bash.mo&lt;br /&gt;b73cc000-b73d3000 r--s 00000000 08:01 28666899 &amp;nbsp; /usr/lib/i386-linux-gnu/gconv/gconv-modules.cache&lt;br /&gt;b73d3000-b754a000 r--p 00000000 08:01 28615144 &amp;nbsp; /usr/lib/locale/locale-archive&lt;br /&gt;b754a000-b754b000 rw-p 00000000 00:00 0&lt;br /&gt;b754b000-b7568000 r-xp 00000000 08:01 12755040 &amp;nbsp; /lib/i386-linux-gnu/libtinfo.so.5.9&lt;br /&gt;b7568000-b756a000 r--p 0001c000 08:01 12755040 &amp;nbsp; /lib/i386-linux-gnu/libtinfo.so.5.9&lt;br /&gt;b756a000-b756b000 rw-p 0001e000 08:01 12755040 &amp;nbsp; /lib/i386-linux-gnu/libtinfo.so.5.9&lt;br /&gt;b756b000-b76be000 r-xp 00000000 08:01 12755289 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libc-2.13.so&lt;br /&gt;b76be000-b76bf000 ---p 00153000 08:01 12755289 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libc-2.13.so&lt;br /&gt;b76bf000-b76c1000 r--p 00153000 08:01 12755289 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libc-2.13.so&lt;br /&gt;b76c1000-b76c2000 rw-p 00155000 08:01 12755289 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libc-2.13.so&lt;br /&gt;b76c2000-b76c6000 rw-p 00000000 00:00 0&lt;br /&gt;b76c6000-b76c8000 r-xp 00000000 08:01 12755049 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libdl-2.13.so&lt;br /&gt;b76c8000-b76c9000 r--p 00001000 08:01 12755049 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libdl-2.13.so&lt;br /&gt;b76c9000-b76ca000 rw-p 00002000 08:01 12755049 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libdl-2.13.so&lt;br /&gt;b76ca000-b76ec000 r-xp 00000000 08:01 12755034 &amp;nbsp; /lib/i386-linux-gnu/libncurses.so.5.9&lt;br /&gt;b76ec000-b76ed000 r--p 00021000 08:01 12755034 &amp;nbsp; /lib/i386-linux-gnu/libncurses.so.5.9&lt;br /&gt;b76ed000-b76ee000 rw-p 00022000 08:01 12755034 &amp;nbsp; /lib/i386-linux-gnu/libncurses.so.5.9&lt;br /&gt;b76f4000-b76fd000 r-xp 00000000 08:01 12754995 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libnss_nis-2.13.so&lt;br /&gt;b76fd000-b76fe000 r--p 00008000 08:01 12754995 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libnss_nis-2.13.so&lt;br /&gt;b76fe000-b76ff000 rw-p 00009000 08:01 12754995 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libnss_nis-2.13.so&lt;br /&gt;b76ff000-b7705000 r-xp 00000000 08:01 12755103 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libnss_compat-2.13.so&lt;br /&gt;b7705000-b7706000 r--p 00005000 08:01 12755103 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libnss_compat-2.13.so&lt;br /&gt;b7706000-b7707000 rw-p 00006000 08:01 12755103 &amp;nbsp; /lib/i386-linux-gnu/i686/cmov/libnss_compat-2.13.so&lt;br /&gt;b7707000-b7708000 r--p 00176000 08:01 28615144 &amp;nbsp; /usr/lib/locale/locale-archive&lt;br /&gt;b7708000-b770a000 rw-p 00000000 00:00 0&lt;br /&gt;b770a000-b770b000 r-xp 00000000 00:00 0 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;[vdso]&lt;br /&gt;b770b000-b7726000 r-xp 00000000 08:01 12755299 &amp;nbsp; /lib/i386-linux-gnu/ld-2.13.so&lt;br /&gt;b7726000-b7727000 r--p 0001b000 08:01 12755299 &amp;nbsp; /lib/i386-linux-gnu/ld-2.13.so&lt;br /&gt;b7727000-b7728000 rw-p 0001c000 08:01 12755299 &amp;nbsp; /lib/i386-linux-gnu/ld-2.13.so&lt;br /&gt;&lt;b&gt;bf916000-bf937000 rw-p 00000000 00:00 0 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;[stack]&lt;/b&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;大致上來說可以看到有這些 VMA 的存在（已省略會偏離主題的 VMA）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;08048000-0810a000 &amp;nbsp;  Code&lt;br /&gt;0810a000-0810f000 &amp;nbsp;  Data&lt;br /&gt;08752000-08a46000  &amp;nbsp; Heap&lt;br /&gt;bf916000-bf937000  &amp;nbsp; Stack&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;對於作業系統而言，管理這些記憶體和程式狀態，才是真正的重點。所以，就作業系統核心的角度來看 Process，可以從排程的程式來切入瞭解。翻閱 Linux Kernel&amp;nbsp;原始程式碼的檔案『&lt;a href="http://git.kernel.org/?p=linux/kernel/git/next/linux-next.git;a=blob_plain;f=include/linux/sched.h;hb=HEAD"&gt;include/linux/sched.h&lt;/a&gt;』，Process 的狀態結構被定義在&amp;nbsp;struct task_struct 之中，而其中的 mm 就是記錄著該 Process 的記憶體配置資訊，我們可以從中得到 Process 當前所擁有的全部 VMA 和 Segments 所在位址：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;struct task_struct {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ...&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; struct mm_struct *mm, *active_mm;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ...&lt;br /&gt;};&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;pre&gt;struct mm_struct {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; struct vm_area_struct * mmap; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; /* list of VMAs */&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ...&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; unsigned long start_code, end_code, start_data, end_data;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; unsigned long start_brk, brk, start_stack;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ...&lt;br /&gt;};&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;另外，從『&lt;a href="http://git.kernel.org/?p=linux/kernel/git/next/linux-next.git;a=blob_plain;f=include/linux/mm.h;hb=HEAD"&gt;include/linux/mm.h&lt;/a&gt;』可以找到 VMA 的串列資料結構定義：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;struct vm_area_struct {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; struct mm_struct * vm_mm; &amp;nbsp; &amp;nbsp; &amp;nbsp; /* The address space we belong to. */&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; unsigned long vm_start; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; /* Our start address within vm_mm. */&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; unsigned long vm_end; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; /* The first byte after our end address&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;within vm_mm. */&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ....&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; /* linked list of VM areas per task, sorted by address */&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; struct vm_area_struct *vm_next;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ....&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;若要繼續追查下去，還有動態連結的部份要探討，會牽涉到更多機制，由於篇幅有限，下次有時間再來寫完。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-6201160083333968898?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/6201160083333968898/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/12/linux-kernel-process.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6201160083333968898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6201160083333968898'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/12/linux-kernel-process.html' title='從 Linux Kernel 出發看！探討 Process 組成結構！'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-9084482339625306410</id><published>2011-12-23T13:18:00.001+08:00</published><updated>2011-12-23T13:55:08.153+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Express Web Framwork'/><category scheme='http://www.blogger.com/atom/ns#' term='NodeJS'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Debian'/><category scheme='http://www.blogger.com/atom/ns#' term='Web 相關技術'/><category scheme='http://www.blogger.com/atom/ns#' term='NPM'/><title type='text'>如何在 Debian 建置 NodeJS + Express 環境</title><content type='html'>截至目前為止，只有 Debian Sid(unstable) 提供 Nodejs 和 Express&amp;nbsp;套件可讓使用者直接安裝。但是，在 Server 的環境之下，一般都使用 Debian 5.0/6.0 (Lenny/Squeeze) 穩定版的系統，因此沒有套件可以直接安裝，唯一的方法就是自己下載編譯 Nodejs。還好自己手動安裝的過程並不困難，幾個步驟就可以完成。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;安裝 Nodejs&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;更新系統並安裝編譯 Nodejs 所需的套件：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;sudo apt-get update&lt;br /&gt;sudo apt-get install git-core curl build-essential openssl libssl-dev&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;從 Git Repository 下載 Nodejs 原始碼：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;git clone https://github.com/joyent/node.git&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;進入 Nodejs 原始碼目錄，並切選擇我們要的版本（截至本文，0.6.6 是最新版）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;cd node&lt;br /&gt;git checkout v0.6.6&lt;br /&gt;&lt;br /&gt;# Note: 可以使用&amp;nbsp;git tag 看到 Nodejs 所有的版本列表&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;編譯並安裝 Nodejs （預設會裝到 /usr/local/lib/node）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;./configure&lt;br /&gt;make&lt;br /&gt;sudo make install&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;如果安裝過程中沒有任何問題，就可以使用 node 指令查看 Nodejs 的版本了：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;node -v&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;手動設定公用的 Nodejs Module 路徑：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;echo "NODE_PATH=/usr/local/lib/node_modules" &amp;gt;&amp;gt; .bashrc&lt;br /&gt;&lt;br /&gt;# Note: 如果想讓所有 Server 上的 user 都套用設定，可以放在 /etc/profile&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;安裝 Express Web Framework&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;使用 npm 安裝 express（使用 -g 選項會安裝到公用的目錄&amp;nbsp;/usr/local/lib/node_modules）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;sudo npm install express -g&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Express 通常預設使用 jade template engine，也需要手動安裝：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;sudo npm install jade -g&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;安裝完成後，就可以立即測試 nodejs + express：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;mkdir test&lt;br /&gt;cd test&lt;br /&gt;express&lt;br /&gt;node app.js&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;如果從瀏覽器可以看到畫面，就代表安裝成功：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;http://ServerIP:3000/&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;截至本文，Debian Sid 的 Nodejs 套件還是 0.4.12 版本，如果想要用新的 Nodejs，就要透過本文的方法來安裝。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-9084482339625306410?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/9084482339625306410/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/12/debian-nodejs-express.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/9084482339625306410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/9084482339625306410'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/12/debian-nodejs-express.html' title='如何在 Debian 建置 NodeJS + Express 環境'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-6242517634508437513</id><published>2011-12-20T08:16:00.000+08:00</published><updated>2012-01-11T13:20:26.849+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Express Web Framwork'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='NodeJS'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='Web 相關技術'/><title type='text'>Nodejs + Express 的 Route 流程規劃</title><content type='html'>如大多數人的習慣，往往我們都把 Route 的路徑都定義在 app.js 當中。Express 所提供的眾多範例程式中，雖然有將 Route 抽出來放在 routes 目錄下的實作方式，但也太簡單，只支援一層的設計。這意味著，如果 routes 之下有更多子目錄，放著更多的 route 設定，都是不會被讀取的。&lt;br /&gt;&lt;br /&gt;這邊做了簡單的修改，利用遞迴的做法，掃描所有的子目錄，然後去載入所有的 js 檔案以擴充 Route 的設定。&lt;br /&gt;&lt;br /&gt;以下是 route.js 的程式碼：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;var vm = require('vm');&lt;br /&gt;var fs = require('fs');&lt;br /&gt;&lt;br /&gt;module.exports = function(app) {&lt;br /&gt;  var dir = __dirname + '/routes';&lt;br /&gt;  var context = {&lt;br /&gt;    app: app,&lt;br /&gt;    require: require&lt;br /&gt;  };&lt;br /&gt;  var newContext;&lt;br /&gt;&lt;br /&gt;  /* Initializing Context */&lt;br /&gt;  for (var key in global)&lt;br /&gt;    context[key] = global[key];&lt;br /&gt;&lt;br /&gt;  newContext = vm.createContext(context);&lt;br /&gt;&lt;br /&gt;  /* Loading all routes */&lt;br /&gt;  loadRouteDir(newContext, dir);&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;function loadRouteDir(context, path) {&lt;br /&gt;  /* Scanning files */&lt;br /&gt;  fs.readdirSync(path).forEach(function(file) {&lt;br /&gt;    loadRouteFile(context, path, file);&lt;br /&gt;  });&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;function loadRouteFile(context, path, file) {&lt;br /&gt;  var fullpath = path + '/' + file;&lt;br /&gt;&lt;br /&gt;  fs.stat(fullpath, function(err, stats) {&lt;br /&gt;    if (stats.isFile()) {&lt;br /&gt;      /* Loading route */&lt;br /&gt;      var str = fs.readFileSync(fullpath, 'utf8');&lt;br /&gt;      vm.runInContext(str, context, file);&lt;br /&gt;    } else if (stats.isDirectory()) {&lt;br /&gt;      /* Loading sub-directory */&lt;br /&gt;      loadRouteDir(context, fullpath);&lt;br /&gt;    }&lt;br /&gt;  });&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;在 app.js 中只要這樣使用即可：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;/* app is Express Server  */&lt;br /&gt;require('./route')(app);&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-6242517634508437513?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/6242517634508437513/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/12/nodejs-express-route.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6242517634508437513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6242517634508437513'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/12/nodejs-express-route.html' title='Nodejs + Express 的 Route 流程規劃'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-5147006748348510455</id><published>2011-12-08T08:25:00.001+08:00</published><updated>2011-12-08T10:13:56.597+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='商業'/><category scheme='http://www.blogger.com/atom/ns#' term='openmoko'/><category scheme='http://www.blogger.com/atom/ns#' term='Open Hardware'/><category scheme='http://www.blogger.com/atom/ns#' term='手機平台'/><title type='text'>Openmoko 永遠活在我們的心中</title><content type='html'>還記得 2006 年 12 月業界出現了一個瘋狂的想法：『Openmoko 的開放手機』，但就在 2011 年 12 月滿五年，這家公司(Openmoko, Inc) 也將劃下了一個圓滿的句點。&lt;br /&gt;&lt;br /&gt;回顧過去，Openmoko 不只是單純的軟體層面開放，而是連硬體設計的細節都公開。這對當時的大環境，高端手機技術和 Know-how 都被嚴密掌握在特定公司的時局下，無疑是個瘋狂的舉動。想當然，Openmoko 花了大量錢財與人力物力，還有國內外社群的力量，終於做出了自己的第一代手機原型（參考圖 Neo 1973），爾後又開發出第二代硬體加強版的機種（參考圖 Neo FreeRunner）。&lt;br /&gt;&lt;br /&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://upload.wikimedia.org/wikipedia/commons/7/7a/1112FIC326x550.jpg" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://upload.wikimedia.org/wikipedia/commons/7/7a/1112FIC326x550.jpg" width="188" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Neo 1973&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;還記得，當時大多數人都還是使用功能手機(Feature phone)，智慧型手機(Smart Phone)也還停留在被難用 Windows CE 稱霸的時代，誰也還沒有想到未來會有 iPhone 和 Android Phone，對絕大多數人而言，手機是個神祕且只有少數人可以參與開發的領域。有趣的是，Openmoko 除了做開放的手機之外，也對應用程式(Apps)安裝於手機上的想法有了初步的構想，而這些想法，都觸動了不少軟體開發者和投資人的目光。&lt;br /&gt;&lt;br /&gt;雖然直到最後，Openmoko 的手機還不足以讓一般消費者順暢使用，但許多構想，無論是開放手機，有擴充性的應用程式平台，還是使用 Linux 開發前衛的智慧型手機，都確實已深埋在不少人心中。世界各地的 Hacker 和高手，無一不想擁有這樣一台的開放手機。&lt;br /&gt;&lt;br /&gt;Openmoko 也在教育界扎根，除了提供開發的教育訊練外，也去拜訪了許多大專院校，讓許多原本沒有機會碰到手機開發的學生和技術人員，有機會一睹這神秘的領域。然後，也有不少學校買了 Openmoko 的手機，做為開發教學使用，直至今天，這些手機還是相當好的開發教材，甚至，也已經有不少教授在這上面開發了一系列教材。（如：淡江大學資工系已經將 Openmoko 手機當成 C 語言教學和相關基礎技術的實作平台）&lt;br /&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://upload.wikimedia.org/wikipedia/commons/e/e7/Freerunner02.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://upload.wikimedia.org/wikipedia/commons/e/e7/Freerunner02.png" width="280" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Neo FreeRunner&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;隨著 iPhone 的問市，Google Android 的出現，Openmoko 逐漸失去了媒體焦點，也有不少不為人知的事情，讓公司逐漸縮編並轉型（之後轉做過 WikiReader），以致現在的人，多半都只是耳聞，漸漸忘了當時 Openmoko&amp;nbsp;花大錢招頂級人才，遍布全世界的開發者和分公司，有如全身鍍金般受各界祝福和朝聖的風光。&lt;br /&gt;&lt;br /&gt;就在最旺的時候，筆者曾經有幸為 Openmoko 工作過一陣子，雖然只是在家工作，很少去公司，和裡面的人員甚少當面接觸，但也為曾在那工作感到驕傲。為此，看著 Openmoko 的殞落，聽到 Openmoko 將結束的消息，不免有些震驚和失落感，當年筆者離開時的不悅，瞬間煙消雲散，之中衝突原由已不需要再提及。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;最近筆者回鍋，回去幫忙 Openmoko 做一些案子，原本只打算幫忙不打算談錢，但結果最後被&amp;nbsp;Openmoko 的創始人&amp;nbsp;Sean Moss-Pultz 硬逼著接下案子，成為了 Openmoko 名符其實的最後一個案子外包者，真不知該哭還該笑。&lt;br /&gt;&lt;br /&gt;至於之後會如何？Sean 將回到事業原點，與我們一樣同為新創(Startup)界的一員，落實他全新的想法。在此祝福&amp;nbsp;Sean，能再接再勵，帶著過去的經驗，創出一番新事業。而 Openmoko，將永遠活在我們的心中。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-5147006748348510455?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/5147006748348510455/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/12/openmoko.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5147006748348510455'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5147006748348510455'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/12/openmoko.html' title='Openmoko 永遠活在我們的心中'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-3143903431514190514</id><published>2011-12-03T10:33:00.001+08:00</published><updated>2011-12-05T20:55:56.073+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>Android 問題百出之 2.3.x 的 JavaScript Interface</title><content type='html'>有鑑於 Android 問題太多，只好定了個系列標題『Android 問題百出』當開頭，並將碰到的問題和解決或避開的方法記錄在內。話說回來，筆者個人其實相當討厭 Android，自 Android 出現以來，從未真的投入其中並賺過什麼錢，會接觸，多半是興趣玩弄或是幫一些朋友的公司臨時打工救火。不過，既然是救火，任何千奇百怪的問題或狀況都會遭遇到，甚至還得『限時』解決別人解決不了的問題。&lt;br /&gt;&lt;br /&gt;這次碰到的問題就是 Android 2.3.x Gingerbread 缺少 JavaScript Interface 的實作，如果你的應用程式有自己實作 API 供 JavaScript 程式使用，那這些 API 將會完全失效。而這樣的問題，對於使用 Web 技術（HTML5 + Javascript）的應用程式來說，相當嚴重。&lt;br /&gt;&lt;br /&gt;話說 Android 在 2.3 版本之後，採用了 V8 做為 JavaScript Engine。在快速掃過 Android 關於 WebView 和 WebKit 的程式碼後，發現不幸的是『Google 再次未將程式寫完』。但這一次，不只是功能未完成，而是將原本可以用的功能（在 Android 2.2），變成不能用。這讓筆者非常不能理解，為何 Google 換了 V8 Engine 後，明知功能沒有改完，卻仍將這部份實作隨新版 Android 釋出？然後，絕大多數廠商，在毫無感覺之下，直接繼承了這樣的 Bug。&lt;br /&gt;&lt;br /&gt;對硬體裝置的廠商來說，重新實作這個 JavaScript Interface 支援是最佳的解決辦法，髒一點的方法是將 V8 改回舊的 JSCore。但很可惜的是，就算有人改好了，也沒有廠商願意釋出這部份的程式碼。（所以才會不停有人願意花大錢找筆者這種臨時救火工呀。）&lt;br /&gt;&lt;br /&gt;此外，如果你是一般的應用程式開發者，因為動不了底層，則完全無解。但是，這邊有個 Workaround，可以暫時代替 JavaScript Interface，讓應用程式開發者可以避開這問題（以下假設自定的 JavaScript Interface Class 為 myAPI）。&lt;br /&gt;&lt;br /&gt;定義將會用到的變數：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;/* Define private variable */&lt;br /&gt;private static WebView mWebView;&lt;br /&gt;private static myAPI mJSIF;&lt;br /&gt;private static boolean javascriptInterfaceBroken = false;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;初始化 WebView 時加上 Workaround：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;/* Initializing WebView */&lt;br /&gt;mWebView = (WebView) findViewById(R.id.supermark_dialog);&lt;br /&gt;mWebView.getSettings().setJavaScriptEnabled(true);&lt;br /&gt;&lt;br /&gt;&lt;b&gt;/* Check Android version */&lt;br /&gt;try {&lt;br /&gt;    if (Build.VERSION.RELEASE.contains("2.3.")) {&lt;br /&gt;        javascriptInterfaceBroken = true;&lt;br /&gt;    }&lt;br /&gt;} catch (Exception e) { }&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;/* Create own JavaScript Interface */&lt;br /&gt;mJSIF = new myAPI(mWebView);&lt;br /&gt;&lt;br /&gt;&lt;b&gt;if (!javascriptInterfaceBroken) {&lt;/b&gt;&lt;br /&gt;    mWebView.addJavascriptInterface(mJSIF, "Fred");&lt;br /&gt;&lt;b&gt;} else {&lt;br /&gt;    /* Workaround to add JavaScript Interface to webview for Fucking Android 2.3 */&lt;br /&gt;    mWebView.setWebViewClient(new WebViewClient() {&lt;br /&gt;        @Override&lt;br /&gt;        public void onPageFinished(WebView view, String url) {&lt;br /&gt;            super.onPageFinished(view, url);&lt;br /&gt;            if (javascriptInterfaceBroken) {&lt;br /&gt;                String handleGingerbreadStupidity =&lt;br /&gt;                    "javascript: function do() {window.location='http://Fred:do:null';};" +&lt;br /&gt;                    "javascript: function handler() {" +&lt;br /&gt;                    "this.do=do;" +&lt;br /&gt;                    "}; " +&lt;br /&gt;                    "javascript: var Fred = new handler();";&lt;br /&gt;                view.loadUrl(handleGingerbreadStupidity);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        @Override&lt;br /&gt;        public boolean shouldOverrideUrlLoading(WebView view, String url) {&lt;br /&gt;            if (javascriptInterfaceBroken) {&lt;br /&gt;                if (url.contains("Fred")) {&lt;br /&gt;                    /* Parsing URL */&lt;br /&gt;                    StringTokenizer st = new StringTokenizer(url, ":");&lt;br /&gt;                    st.nextToken();&lt;br /&gt;                    st.nextToken();&lt;br /&gt;                    String function = st.nextToken();&lt;br /&gt;                    String parameter = st.nextToken();&lt;br /&gt;&lt;br /&gt;                    /* Call function */&lt;br /&gt;                    if (function.equals("do")) {&lt;br /&gt;                        mJSIF.do();&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                return true;&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            return false;&lt;br /&gt;        }&lt;br /&gt;    });&lt;br /&gt;}&lt;/b&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;最後，我們還是可以如使用原生的 JavaScript Interface 一般，在 HTML5 + JavaScript 中呼叫自定的 API：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;&amp;lt;script&amp;gt;&lt;br /&gt;window.Fred.do();&lt;br /&gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;簡單來說，就是創造假的 URL 和相應的 Parser，去接收從 JavaScript 傳來的要求。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;如果說一直專心並精通於某樣領域的人稱之為專家，那筆者肯定不是 Android 專家。但是，好在長久來與 Open Source 拼命所練就出來的功夫，無論什麼樣的火，總算都能夠快速找到火源和撲滅，應該可以算是滅火專家吧。 :-D&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-3143903431514190514?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/3143903431514190514/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/12/android-23x-javascript-interface.html#comment-form' title='8 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3143903431514190514'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3143903431514190514'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/12/android-23x-javascript-interface.html' title='Android 問題百出之 2.3.x 的 JavaScript Interface'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-8260364942701193043</id><published>2011-11-27T09:06:00.001+08:00</published><updated>2011-11-27T09:46:35.076+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Express Web Framwork'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='NodeJS'/><category scheme='http://www.blogger.com/atom/ns#' term='Web 相關技術'/><title type='text'>NodeJS + Express 實作檔案上傳</title><content type='html'>『&lt;a href="http://expressjs.com/"&gt;Express Web Framework&lt;/a&gt;』是基於『Connect Middleware Framework』所開發，大部份的常見功能，藉由 Connect 本身支援或 Connect 的第三方(Third-party)模組，就可以實作出來。如果要實作檔案上傳的功能，可以使用第三方模組『&lt;a href="https://github.com/visionmedia/connect-form"&gt;connect-form&lt;/a&gt;』來達成。&lt;br /&gt;&lt;br /&gt;直接透過 npm 安裝需要的模組：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;npm install connect-form&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;在 app.js 中實作：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;var express = require('express');&lt;br /&gt;&lt;b&gt;var form = require('connect-form');&lt;/b&gt;&lt;br /&gt;var app = module.exports = express.createServer();&lt;br /&gt;&lt;br /&gt;app.configure(function(){&lt;br /&gt;  app.set('views', __dirname + '/views');&lt;br /&gt;  app.set('view engine', 'jade');&lt;br /&gt;  app.use(express.bodyParser());&lt;br /&gt;  app.use(express.methodOverride());&lt;br /&gt;  &lt;b&gt;app.use(form({&lt;/b&gt;&lt;br /&gt;    &lt;b&gt;keepExtensions: true,&lt;/b&gt;&lt;br /&gt;    &lt;b&gt;uploadDir: __dirname + '/uploads'&lt;/b&gt;&lt;br /&gt;  &lt;b&gt;}));&lt;/b&gt;&lt;br /&gt;  app.use(app.router);&lt;br /&gt;  app.use(express.static(__dirname + '/public'));&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;app.get('/', function(req, res) {&lt;br /&gt;  res.send('&amp;lt;form method="post" enctype="multipart/form-data"&amp;gt;'&lt;br /&gt;    + '&amp;lt;p&amp;gt;Image: &amp;lt;input type="file" name="image" /&amp;gt;&amp;lt;/p&amp;gt;'&lt;br /&gt;    + '&amp;lt;p&amp;gt;&amp;lt;input type="submit" value="Upload" /&amp;gt;&amp;lt;/p&amp;gt;'&lt;br /&gt;    + '&amp;lt;/form&amp;gt;');&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;app.post('/', function(req, res, next) {&lt;br /&gt;&lt;b&gt;  req.form.complete(function(err, fields, files){&lt;br /&gt;    if (err) {&lt;br /&gt;      next(err);&lt;br /&gt;    } else {&lt;br /&gt;      console.log('\nuploaded %s to %s'&lt;br /&gt;        ,  files.image.filename&lt;br /&gt;        , files.image.path);&lt;br /&gt;      res.redirect('back');&lt;br /&gt;    }&lt;br /&gt;  });&lt;br /&gt;&lt;br /&gt;  req.form.on('progress', function(bytesReceived, bytesExpected){&lt;br /&gt;    var percent = (bytesReceived / bytesExpected * 100) | 0;&lt;br /&gt;    process.stdout.write('Uploading: %' + percent + '\r');&lt;br /&gt;  });&lt;/b&gt;&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;app.listen(3000);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;本文的範例與 express 所提供的是一樣的，只是在 app.configure() 裡多了幾行 app.use()。其實目的只是希望告訴讀者，務必要在 app.router 之前引入 connect-form。原因是在 Express Web Framework 設計上，每次處理 Request 時，會依照 app.use() 所引入的順序去使用模組。&lt;br /&gt;&lt;br /&gt;由於原生的 app.router 並不處理上傳檔案的特殊需求，我們一定要在 Request 經過 app.router 導引並進入 app.post() 所定義的 handler 之前，讓 connect-form 先行遇處理和檢查 Request 是否為上傳檔案，進而擴充功能甚至進一步分析處理。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-8260364942701193043?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/8260364942701193043/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/11/nodejs-express.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/8260364942701193043'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/8260364942701193043'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/11/nodejs-express.html' title='NodeJS + Express 實作檔案上傳'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-7211299374084540210</id><published>2011-11-23T23:12:00.001+08:00</published><updated>2011-11-23T23:51:40.262+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Express Web Framwork'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='NodeJS'/><category scheme='http://www.blogger.com/atom/ns#' term='Web 相關技術'/><title type='text'>在 NodeJS + Express 使用 Cookie-based Session</title><content type='html'>開發網站的人應該對 Session 都不陌生，主要是用於 Client 與 Server 之間的溝通和狀態記錄。底層的實作細節本文就不多說明，若仍不理解他的用途，只要知道它可以讓你在不同頁面之間傳遞資料，像是登入狀態等。&lt;br /&gt;&lt;br /&gt;一般標準的『Express』利用『Connect Middleware Framework』（之後簡稱 Connect）中的模組來實作 Session 的，而預設的方法是使用 MemoryStore 的方式，也就是將 Session 資料存放於記憶體上。若你開發的是中大型的網站，也可以使用 Connect 的第三方模組『&lt;a href="https://github.com/visionmedia/connect-redis"&gt;connect-redis&lt;/a&gt;』，利用『&lt;a href="http://redis.io/"&gt;Redis&lt;/a&gt;』這樣的 Key-Value Database 來存放 Session 的資料。這些在 NodeJS + Express 的各類開發文獻中相當常見，你可以從許多網站上找到使用方法。&lt;br /&gt;&lt;br /&gt;不過，也許你仍不滿足，希望使用近年來興起的 Cookie-based Session，Connect 也有第三方模組『&lt;a href="https://github.com/caolan/cookie-sessions"&gt;cookie-sessions&lt;/a&gt;』可以使用。&lt;br /&gt;&lt;br /&gt;可以直接使用 npm 安裝：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;npm install cookie-sessions&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;在你的 app.js 這樣使用：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;var express = require('express');&lt;br /&gt;&lt;b&gt;var CookieStore = require('cookie-sessions');&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;var app = module.exports = express.createServer();&lt;br /&gt;&lt;br /&gt;app.configure(function(){&lt;br /&gt; app.set('views', __dirname + '/views');&lt;br /&gt; app.set('view engine', 'jade');&lt;br /&gt; app.use(express.bodyParser());&lt;br /&gt; app.use(express.methodOverride());&lt;br /&gt; app.use(express.cookieParser());&lt;br /&gt; &lt;b&gt;app.use(CookieStore({ secret: 'FredChien' }));&lt;/b&gt;&lt;br /&gt; app.use(app.router);&lt;br /&gt; app.use(express.static(__dirname + '/public'));&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;app.get('/', function(req, res) {&lt;br /&gt; &lt;b&gt;req.session = { email: 'cfsghost@gmail.com' };&lt;/b&gt;&lt;br /&gt;&lt;br /&gt; /* Redirect to another page */&lt;br /&gt; res.redirect('/getsession');&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;app.get('/getsession', function(req, res) {&lt;br /&gt; &lt;b&gt;if (req.session)&lt;/b&gt;&lt;br /&gt;  &lt;b&gt;res.end('This is Fred's email address:' + req.session.email);&lt;/b&gt;&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;app.listen(3000);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;其實 NodeJS 還算發展階段，相關資源不算很多，若想要實作過去常用的一些功能，會需要花點功夫請教 Google 大神。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-7211299374084540210?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/7211299374084540210/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/11/nodejs-express-cookie-based-session.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/7211299374084540210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/7211299374084540210'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/11/nodejs-express-cookie-based-session.html' title='在 NodeJS + Express 使用 Cookie-based Session'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-3667799374069067707</id><published>2011-11-19T04:19:00.001+08:00</published><updated>2011-11-19T05:16:13.149+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dalvik VM'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>千萬別相信 Android 上的應用程式</title><content type='html'>或許有些過於危言聳聽，但我們確實得正視這樣的議題：『資料無故從手機中消失』。這是可能發生的問題，原因在於 Android Dalvik VM 的 Garbage Collection 機制太過強大，如果程式開發者在寫程式的過程中都沒注意到這問題，那這肯定是個不定時炸彈。&lt;br /&gt;&lt;br /&gt;話說，寫過 Android Application 的人應該都很習慣了變數宣告後，用完了就不管他，彷彿系統會有無限量供應的記憶體一般。不過，這對『慣C』一族來說，永遠是種荒繆的事，實在無法想像『憑什麼』不用釋放記憶體。其實說穿了，這一切是 VM 裡面的 Garbage Collection 在『Hold 住』場面，他會自動將目前 Reference 數量稀少的記憶體回收，以避免系統記憶體被用光後又不釋放。而所有回收的動作，有一系列『聰明』的演算法，有興趣的人可以自己去找相關資訊閱讀。&lt;br /&gt;&lt;br /&gt;但是別以為 Garbage Collection 可以聰明到百分之百準確知道，什麼東西回收後是對系統或是應用程式無傷的，因為這就算要人腦來判斷，也一定會犯錯。更者，也別以為 Garbage Collection 不太會動當前正在跑的程式，因為只要符合條件，就算是你程式當前不斷在用的變數，也可能消失被回收，導致程式錯亂，就像被鬼憑空抓走一般。&lt;br /&gt;&lt;br /&gt;如果你認為這只是理論，那你就錯了，這問題實際發生在最近筆者幫忙救火的案子裡。詳細情況是，這是瀏覽器相關的案子，當時我們宣告了幾個 Private 變數，然後使該變數在使用者操作觸發後，會被設定了一些數值供接下來的許多運算使用。一般情況下，我們實作的程式都很正常，不過，一旦開到比較複雜或充滿 JavaScript 的網站後，我們的程式彷彿就開始像中邪，完全不照我們的想像去執行，無論怎麼找問題，也找不出個所以然。&lt;br /&gt;&lt;br /&gt;由於問題的發生是過程中變數無故被歸零，而我們又確定沒有任何一段自己的程式會讓他歸零，所以只剩下一種可能：『Garbage Collection 為了因應 WebView 過多的需求，而把變數給回收了。』&lt;br /&gt;&lt;br /&gt;最後，我們將這變數設為 static 以解決這問題。不過，雖然用 static 暫時解決了問題，那也只是減少變數不被回收的機會，並不是最妥當的做法。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;別小看這問題，其實在 Android Framework 中也處處藏滿類似的問題，只是不知道什麼時候會爆出來而已。而這次救火的案子，就倒霉碰到鬼。&lt;br /&gt;&lt;br /&gt;或許多半處於最上層的應用程式開發者，都覺得這些底下的事情，應該極穩定又可信賴，從來就不會在意這些東西，但是這可能會造成重大問題，相關知識還是要多充實。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-3667799374069067707?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/3667799374069067707/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/11/android.html#comment-form' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3667799374069067707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3667799374069067707'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/11/android.html' title='千萬別相信 Android 上的應用程式'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-7541526801068949323</id><published>2011-11-13T17:51:00.001+08:00</published><updated>2011-11-13T21:52:34.622+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='Web 相關技術'/><category scheme='http://www.blogger.com/atom/ns#' term='Socket.IO'/><category scheme='http://www.blogger.com/atom/ns#' term='WebSocket'/><title type='text'>自認帥氣的 WebSocket 簡單命令處理模型</title><content type='html'>最近參與的一個 Project，需要在 WebSocket 下實作許多機制，這著實讓人傷透腦筋。又由於 JavaScript 完全是非同步（asynchronous）的設計概念，若遇到必需等待 Server 回應後才能繼續執行的工作，處理起來可是一件異常麻煩的事。雖然很熟悉運用回調函數（Callback Function）和暱名函數（Anonymous Function)來做，但一層包一層的設計，總讓人覺得進入無限階層的夢境地獄，什麼時候醒來都不知道。&lt;br /&gt;&lt;br /&gt;這是筆者要達成的需求：『發送自己定義的命令去 Server，然後等待 Server 回應，一旦收到 Server 回應就可以繼續往下處理。』&lt;br /&gt;&lt;br /&gt;一般的情況下，多數人都會這樣做（這理使用 Socket.IO 來建立 WebSocket，並和 Server 要當前時間為例）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;/* Define handler to receive response from server */&lt;br /&gt;socket.on('Clock', function(data) {&lt;br /&gt;    /* Do something */&lt;br /&gt;    alert(data);&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;/* Send command to server */&lt;br /&gt;socket.emit('Clock', 'Time');&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;可是，並非每次對 Server 的請求，都希望透過 alert() 跳出結果，我們有時只是想要利用 Server 給的時間做一些其他處理，雖然是下同樣的命令，但後續處理完全不一樣。於是，筆者，設計了這樣的方式，簡單的去處理這種問題：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;var command = {&lt;br /&gt;    'Time': [],&lt;br /&gt;    'Date': []&lt;br /&gt;    /* You can define more commands */&lt;br /&gt;};&lt;br /&gt;socket.on('Clock', function(data) {&lt;br /&gt;    if (command[data.command].length) {&lt;br /&gt;        for (var index in command[data.command])&lt;br /&gt;            command[data.command][index](data.result);&lt;br /&gt;&lt;br /&gt;        command[data.command] = [];&lt;br /&gt;    }&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;/* API to Send command to server */&lt;br /&gt;function sendCommand(domain, cmd, callback) {&lt;br /&gt;    command[cmd].push(callback);&lt;br /&gt;    if (command[data.command].length == 1) {&lt;br /&gt;        socket.emit(domain, cmd);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* New method to send command and show result in alert window */&lt;br /&gt;sendCommand('Clock', 'Time', function(data) {&lt;br /&gt;    alert(data);&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;/* New method to send command and set window title with result */&lt;br /&gt;sendCommand('Clock', 'Time', function(data) {&lt;br /&gt;    window.title = data;&lt;br /&gt;});&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;這邊需要在 Server-side 改變回送的格式，告知 Client 現在回應的結果是屬於哪一個命令：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;data = {&lt;br /&gt;    command: 'Time',&lt;br /&gt;    result: '11:11:11'&lt;br /&gt;};&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;這樣的命令處理模型，適合用在讀取即時性低的公用狀態或常數，因為這種做法只會送出一個命令給 Server，程式在發送命令時就會自動合併當下發出的『同樣要求』，直到 Server 回應後，同時間一併觸發所有相應的 callback function。除了能減少傳送的資料量，也避免與 Server 的溝通等待，提升一些效能。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;若是不希望合並要求，且想要明確等到自己發送的命令回應後，才觸發自己的 callback function，廣泛的做法是建立計數器，但這種方法就不在本文討論的泛疇。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-7541526801068949323?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/7541526801068949323/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/11/websocket.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/7541526801068949323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/7541526801068949323'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/11/websocket.html' title='自認帥氣的 WebSocket 簡單命令處理模型'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-7316025852799509810</id><published>2011-11-09T11:15:00.002+08:00</published><updated>2011-11-09T11:17:10.463+08:00</updated><title type='text'>使用 Jade 快速製作 HTML Template</title><content type='html'>如果你用 NodeJS 和『&lt;a href="http://expressjs.com/"&gt;Express Web Framework&lt;/a&gt;』來寫網站，又參考官方給的範例程式，『&lt;a href="http://jade-lang.com/"&gt;Jade&lt;/a&gt;』應該是你首選的 Template Engine。不過 Jade 相當容易，如果你已經很熟悉 HTML，學習它不會是件難事。&lt;br /&gt;&lt;br /&gt;Jade 用來表示每一個 HTML Tag 的格式：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;&lt;i&gt;&amp;lt;tag&amp;gt;&lt;/i&gt;(&lt;i&gt;&amp;lt;attributes&amp;gt;&lt;/i&gt;) &lt;i&gt;&amp;lt;inner content&amp;gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;或是&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;span class="Apple-style-span" style="font-style: normal;"&gt;&lt;i&gt;&amp;lt;tag&amp;gt;&lt;/i&gt;(&lt;i&gt;&amp;lt;attributes&amp;gt;&lt;/i&gt;)=&amp;nbsp;&lt;i&gt;&amp;lt;inner content&amp;gt;&lt;/i&gt;&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;ex: img(src='/images/logo.jpg')&lt;br /&gt;ex:&amp;nbsp;a(href='http://www.mandice.com/') Mandice&lt;br /&gt;ex: title=&amp;nbsp;This is Jade Example&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;使用縮排描述巢狀結構（ 如同 Python）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;Jade 語法：&lt;br /&gt;html&lt;br /&gt;&amp;nbsp;&amp;nbsp;head&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;title= This is Jade Example&lt;br /&gt;&amp;nbsp;&amp;nbsp;body&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Hello World&lt;br /&gt;&lt;br /&gt;結果：&lt;br /&gt;&amp;lt;html&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;head&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;title&amp;gt;This is Jade Example&amp;lt;/title&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/head&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;body&amp;gt;Hello World&amp;lt;/body&amp;gt;&lt;br /&gt;&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;賦予 Element 一個 ID 有兩種方式：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;div(id='element1')&lt;br /&gt;&lt;br /&gt;或是&lt;br /&gt;&lt;br /&gt;div#element1&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;引入並使用另一個 Jade 檔案：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;div#element1= partial('another.jade')&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;賦予 Tag 有多個&amp;nbsp;Attributes 有兩種方法：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;使用『,』連接多個 Attribute：&lt;br /&gt;img(src='/images/logo.jpg', title='This is a Logo')&lt;br /&gt;&lt;br /&gt;使用換行連接多個：&lt;br /&gt;img(&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;src='/images/logo.jpg'&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;title='This is a Logo'&lt;br /&gt;)&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;建立 div 元素並指定 ID 的特殊例子，可在開頭省略 div：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;#element1(class='test')&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;在配合使用 Jade 時，當然還會碰到傳入值的情況，以及簡單的判斷式，不過這部份就留給實地操作的人自己去發掘了。 Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-7316025852799509810?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/7316025852799509810/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/11/jade-html-template.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/7316025852799509810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/7316025852799509810'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/11/jade-html-template.html' title='使用 Jade 快速製作 HTML Template'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-4647124624940606337</id><published>2011-11-08T08:27:00.000+08:00</published><updated>2011-11-08T11:56:08.886+08:00</updated><title type='text'>我如何看待 NodeJS</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://nodejs.org/logos/monitor.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="242" src="http://nodejs.org/logos/monitor.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;其實，這是篇推薦文，但推薦的角度和坊間很多人不一樣，所以這也是為什麼標題下『我如何看待 NodeJS』。&lt;br /&gt;&lt;br /&gt;誠如大家所知，『&lt;a href="http://nodejs.org/"&gt;NodeJS&lt;/a&gt;』原先被開發出來的目的，是為了解決 Web Server 效能的問題，其採用 Google Chrome/Chromium 使用的『&lt;a href="http://code.google.com/p/v8/"&gt;Google V8 Javascript Engine&lt;/a&gt;』做為直譯器引擎。最特別的是，NodeJS 讓開發者完全可以用 JavaScript 來開發整個伺服器端的所有程式，這意味你可以不用再使用 Python、PHP、Perl、Ruby、ASP 等其他的語言，只需要學會 JavaScript 就可以將網站通通搞定。也因為幾乎所有的 Web 開發者都熟悉 JavaScript，NodeJS 很理所當然的成為一個 Web 圈內受很多人擁護的新技術，在各大 Cloud Hosting 也都開始有支援。&lt;br /&gt;&lt;br /&gt;當然不只是如此， NodeJS 也吸收了各方面的經驗，提供應用程式框架（Framework）讓開發者可以快速開發。平心而論，比其他的語言更能兼固快速開發和效能的問題。&lt;br /&gt;&lt;br /&gt;談到這裡，還是僅止於坊間多數人介紹的內容，筆者認為，如果只是這樣，也未免小覻了 NodeJS。&lt;br /&gt;&lt;br /&gt;事實上，NodeJS 就是 Original JavaScript Without Browser + Libraries，在舊有的 JavaScript 抽離瀏覽器後，再上加上更多 System-level Library 的支援。這讓我們可以重新看待 JavaScript 這個語言，因為它不再只是限於『特定領域』使用，而是提升至『System Level』。&lt;br /&gt;&lt;br /&gt;我們可以這樣認定：『JavaScript 已經可以和 Python 相提並論』。因此，使用 JavaScript 寫一支系統應用程式或是桌面應用程式，已經不再是夢，而是伸手可及。如果你有印像，HP WebOS 就是率先引入 NodeJS 的先行者，讓原本被視為 Web 技術的 JavaScript，跳出舊有框框，進入桌面系統的領域。&lt;br /&gt;&lt;br /&gt;目前，NodeJS 仍持續發展中，許多函式庫支援也被慢慢的被實作出來。有時為了效能考量，我們也可以自己使用 C/C++ 為他開發更多 Library/Module。可以期待，未來 NodeJS 將會更為強大。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-4647124624940606337?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/4647124624940606337/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/11/nodejs.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/4647124624940606337'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/4647124624940606337'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/11/nodejs.html' title='我如何看待 NodeJS'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-6982429377467999730</id><published>2011-11-05T06:48:00.001+08:00</published><updated>2012-01-11T13:20:46.080+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Express Web Framwork'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='NodeJS'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='Socket.IO'/><category scheme='http://www.blogger.com/atom/ns#' term='WebSocket'/><title type='text'>使用 NodeJS + Express + Socket.IO 實作 WebSocket 服務</title><content type='html'>一直處於假標準狀態的 HTML5，過程中一直有變化，讓人無法放心使用。不過到了今年，HTML5 總算進入了準決賽的階段，大部份功能已經確定下來，其中 WebSocket 就是最讓人關切的項目之一，因為這意味著未來 Web 不再只是單次性的觸發服務，而是可以讓使用者端與伺服器長時間處於連線狀態，並進行即時性的資料傳交換。&lt;br /&gt;&lt;br /&gt;關於 WebSocket，彷間許多隨 HTML5 起舞的人，其實都說明不夠清楚，多半只強調能達成 TCP Socket 形式的連線，和無所不能的優點。其實，WebSocket 並非是我們所知的原生 Socket ，而只是一種架構於 HTTP Protocol 上的延伸定義，所以換句話來說，不能直接拿來連線到非 HTTP 以外的通訊協定。&lt;br /&gt;&lt;br /&gt;至於它的做法，就是在瀏覽器向伺服器要資料時，在 Request Header 裡加上『Connection:Upgrade』來告訴伺服器：『我要改變連線形態』。然後伺服器會依照瀏覽器給的 WebSocket 相關標頭（header）和交握用的金鑰（Key），進行認證和改變處理方式。進入 WebSocket 連線的客戶端，就有如在使用 TCP Socket 或 Telnet 一樣，可以隨意在任意時間點傳送資料給伺服器處理，伺服器也可以在這連線下即時回應。所以就某方面來說，這剛好可以含蓋並取代過去 Web 1.0 的 Refresh Page 和 Web 2.0 後的 Long-polling 技術。&lt;br /&gt;&lt;br /&gt;寫過網路程式的人都知道，如何定義 Protocol 才是傷腦筋的事，開啟了一個『類 Socket』意味著我們又回到了過去的年代，要自己解決 Protocol 的定義。不過也已經有現成的 Library 可以使用，許多問題我們已經不用擔心，本文將提到的 Socket.IO 就是其中之一。此外，由於 WebSocket 需要 Client/Server 同時實作，所以，這些 Library 多半都包括了兩部份的實作。&lt;br /&gt;&lt;br /&gt;Server 端，使用 NodeJS + Express web framework + Socket.IO(0.8.6)：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;/* Module dependencies */&lt;br /&gt;var express = require('express');&lt;br /&gt;var io = require('socket.io');&lt;br /&gt;&lt;br /&gt;/* Initializing Express Framework */&lt;br /&gt;var app = module.exports = express.createServer();&lt;br /&gt;app.listen(3000);&lt;br /&gt;&lt;br /&gt;/* Create a Socket.IO instance, to establish WebSocket Service */&lt;br /&gt;var socket = io.listen(app);&lt;br /&gt;socket&lt;br /&gt;    .on('connection', function(client) {&lt;br /&gt;        console.log('A connection was established');&lt;br /&gt;        client&lt;br /&gt;            .on('pretty-girl', function(data) {&lt;br /&gt;                console.log(data);&lt;br /&gt;                socket.emit('ugly-man', 'get out of my way');&lt;br /&gt;            });&lt;br /&gt;&lt;br /&gt;        client.on('disconnect', function() {&lt;br /&gt;            console.log('Server has disconnected');&lt;br /&gt;        });&lt;br /&gt;    });&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Client 端，使用 Socket.IO(0.8.6)：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;socket = io.connect();&lt;br /&gt;socket.on('connect', function() {&lt;br /&gt;    console.log('Client has connected to the server!');&lt;br /&gt;})&lt;br /&gt;socket.on('disconnect', function() {&lt;br /&gt;    console.log('The client has disconnected!');&lt;br /&gt;});&lt;br /&gt;socket.on('ugly-man', function(data) {&lt;br /&gt;    console.log(data);&lt;br /&gt;});&lt;br /&gt;socket.emit('pretty-girl', 'hello!');&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;回到原始的網路溝通，也有許多議題將再次面臨，舉例來說，客戶端(Client)可以同時發送很多道命令給伺服器，但伺服器可能每道命令完成時間有快有慢，以至有些命令是後發卻先完成。那伺服器如何告知客戶端，是哪一道命令完成了？而這種問題非常容易在多功能的服務中見到，尤其是遊戲伺服器。不過，對於過去有過伺服器設計經驗的人，顯然是不用怕。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;備註：使用 Socket.IO 要注意版本的變化，因為各版 API 改動伏度都不小。而且也要注意 Client/Server 要使用同一版本，之前筆者犯錯，在 Client 使用官方提供的 CDN 版本，但在 Server 端使用自己下載的最新版本，結果一直無法讓 WebSocket 成功被建立。&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-6982429377467999730?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/6982429377467999730/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/11/nodejs-express-socketio-websocket.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6982429377467999730'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6982429377467999730'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/11/nodejs-express-socketio-websocket.html' title='使用 NodeJS + Express + Socket.IO 實作 WebSocket 服務'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-3501094879648126670</id><published>2011-10-27T12:11:00.000+08:00</published><updated>2011-10-27T12:11:32.330+08:00</updated><title type='text'>偏好的 JavaScript Class 實作『基本款』</title><content type='html'>&lt;p&gt;最近有一些想法，便和伙伴在空閒時間寫一些 Prototype 的專案，既然是嘗試形態的專案開發，就不必考慮穩定性和熟悉度，也不用顧慮失敗的問題，可以盡情玩弄新的，或是過去不常使用的技術。所以，這次使用了 nodejs + express + HTML5 來開發，大玩 JavaScript。&lt;/p&gt;&lt;p&gt;JavaScript 雖然看起來像 Java，但畢竟它不是真的 Java，很多功能考量以易於使用為優先，所以並不嚴謹，一些功能也因此被拿掉。畢竟，當初被設計出來只是為了讓『網頁動起來』，並沒有考量太多。但是隨著需求大增，而現在我們所看到的 JavaScript ，已經是一層層為了需求而疊出來的產物，其不旦保留與舊的 JavaScript 相容，又要擴充物件導向的現代化語言特性，這也是為什麼使用起來總是沒有一個固定的模式。&lt;/p&gt;&lt;p&gt;筆者過去總苦惱 JavaScript 的寫法變化太大，在過程中跌跌撞撞，雖寫了不少 Code，但總是覺得不順手，非常想尋求一個 JavaScript 設計模式的『基本款』，也希望和開發伙伴們有共同遵循的標準，讓專案更容易維護。&lt;/p&gt;經過和隊友們的一番討論，總算有一些結論：&lt;div&gt;&lt;pre&gt;/* Example Class */&lt;br /&gt;var Example = function() {&lt;br /&gt;    /* Private */&lt;br /&gt;    var Status = 0;&lt;br /&gt;    var doms = {&lt;br /&gt;        object: false;&lt;br /&gt;    };&lt;br /&gt;    var subObject = false;&lt;br /&gt;&lt;br /&gt;    /* Constructor */&lt;br /&gt;    subObject = new OtherClass();&lt;br /&gt;    doms.object = document.createElement('div');&lt;br /&gt;&lt;br /&gt;    /* Public */&lt;br /&gt;    return {&lt;br /&gt;        setStatus: function(_status) {&lt;br /&gt;            Status = _status;&lt;br /&gt;        },&lt;br /&gt;        getStatus: function() {&lt;br /&gt;            return Status;&lt;br /&gt;        },&lt;br /&gt;        getDOMs: function() {&lt;br /&gt;            return doms;&lt;br /&gt;        },&lt;br /&gt;        getOtherClass: function() {&lt;br /&gt;            return subObject;&lt;br /&gt;        },&lt;br /&gt;        Run: function() {&lt;br /&gt;            /* Call own methods */&lt;br /&gt;            this.setStatus(2);&lt;br /&gt;            this.getStatus();&lt;br /&gt;        }&lt;br /&gt;    };&lt;br /&gt;};&lt;/pre&gt;&lt;/div&gt;然後我們可以用這樣的方式使用定義出來的物件：&lt;div&gt;&lt;pre&gt;/* Create a new Example Object */&lt;br /&gt;var ex = new Example();&lt;br /&gt;&lt;br /&gt;/* Set to private variable */&lt;br /&gt;ex.setStatus(1);&lt;br /&gt;&lt;br /&gt;/* Get something from private area */&lt;br /&gt;ex.getDOMs().object;&lt;br /&gt;&lt;br /&gt;/* Using subObject's Methods */&lt;br /&gt;ex.getOtherClass().publicMethods()&lt;/pre&gt;&lt;/div&gt;其實有寫 OO 的人，不管換到哪一種語言，第一時間都會尋找如何實作私有（Private）、公用（Public）和 Class 的寫法，不過，和其他語言不一樣的是， JavaScript 卻有很多種方式可以達成。當然，這邊只是列出我們比較偏好的寫法，供讀者們參考。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-3501094879648126670?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/3501094879648126670/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/10/javascript-class.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3501094879648126670'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3501094879648126670'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/10/javascript-class.html' title='偏好的 JavaScript Class 實作『基本款』'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-3252114719286644302</id><published>2011-10-17T09:15:00.000+08:00</published><updated>2011-10-17T09:27:02.210+08:00</updated><title type='text'>程式開發者之不要過度依賴別人解決問題</title><content type='html'>常有人說，資訊產業變化太快，如果不及時跟上，馬上就落伍了。事實上不全然如此，應該說在這產業是不進則退，至於要不要跟著潮流走，不一定。其實講明了，電腦科學並不是真正的科學，而是種社會學，由於大家的方向和需求多半是一致的，可以很容易預測到未來需要用到的各種技術，或是常有別人已經完成的工具或技術可直接使用，而且研發新技術也不需要像真正科學一樣，我們不需要長篇幅的理論基礎，只要能解決當前問題即可，如何不斷的解決需求和問題才是我們所在意。&lt;br /&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;在之前舊文『程式開發者之萬事起頭難』有提過，開發軟體相當依賴經驗。所以，不管是如何找到解決問題的辦法，都必需要經過實作執行然後吸收，並轉化成程式人員的經驗才有意義。也因此，只要能獲得新的經驗，拓展視野，什麼方法都可以。不過，筆者認為『追著最新的外來技術』和『自己發展技術』兩種途徑最為重要，而且缺一不可。如果用武俠小說的角度來說，就是招式和心法的配合，增加內力的累積。&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;自己發展技術就不用多說，我們能從實地的演練，獲得大量經驗和想法，而且會得到實務考量的觀念。比較需要注意的是『追著最新的外來技術』，因為很多時候，我們面對這些技術的態度，會讓自己無法分辨自己所得到的是『招式』還是『武功』。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;或許很多人以『學了很多招式』而自豪，但面對真正的需求和挑戰時，便無法應對自如，招式套不上去，此時才抱怨『書到用時方恨少』，殊不知是學習新知的態度有問題所造成。因為缺少了質的招式，並不具有太大的意義，而且永遠要追求更新更有用的招式，才不會有招用老的一天。可是，一旦碰到 Google 大神或書裡沒有答案，就完蛋了。記得，學會很多招式或工具，只是『幫助提升工作效率』，相當於大學生會剪剪貼貼罷了，缺少深入的理論和資訊定位分析，或沒有學習問題的根本，並無法累積解決問題能力。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;所以時時都要準備哪一天『如果沒有 Google』，也不要再只是窮追新的 Library 或 open source project。導致一旦沒有其他人供獻這些東西，自己便沒能力完成專案。雖然說要全部都懂是很困難或不可能達成，但要盡量做到，才能得到屬於自己的關鍵技術。以前人說的：『站在巨人肩上』，指的就是追到最新技術後，再發展技術，如果只是使用而沒有再發展，就等於沒有進步可言，遲早會被騎在更高巨人身上的人所打敗。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;程式人員要盡可能快速從『請 Google 幫忙』職業學校畢業，才能當一個稱職的開發者。&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-3252114719286644302?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/3252114719286644302/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/10/blog-post_17.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3252114719286644302'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3252114719286644302'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/10/blog-post_17.html' title='程式開發者之不要過度依賴別人解決問題'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-525079490372185518</id><published>2011-10-15T22:34:00.001+08:00</published><updated>2011-10-15T22:45:21.275+08:00</updated><title type='text'>程式開發者之傻傻搞不清楚技術定位</title><content type='html'>常聽到有人說專案選錯技術而失敗，或是造成什麼嚴重問題，其實這其中，是有很多原因導致選錯技術。不過，對於初入這行業的人來說，所知所見不夠廣，是最主要的問題。&lt;br /&gt;&lt;br /&gt;使用正確的解決方案能讓軟體專案或是產品專案更加順利。所以開發前要做足功課，通盤的瞭解和業界各種大小的動態都不能放過（相信身為程式人員，看英文資訊的能力應該不必擔心），哪怕該技術存在的領域可能與我們當前熟悉的領域相差十萬八千里遠。因為如果視野太狹窄，就看不到更好的技術方案，更沒有機會觸類旁通。有了足夠資訊，如同有了一張地圖，也就有跡可尋自己不足之處和其解決之道。&lt;br /&gt;&lt;br /&gt;有了地圖，便要開始認清方位，身為程式開發者，懂一項技術的優點和極限是絕對必要的，所以一定要了解一件事實：『懂一種技術能做些什麼，並不代表了解該技術只能做些什麼。』瞭解透徹，才能正確的選擇解決方案和確實將目標達成。&lt;br /&gt;&lt;br /&gt;搞清楚各種技術的定位後，便要應用在一個專案開始前，使用所知去選擇解決方案。記得過程中要隨時保持所選擇的技術，在緊急時刻可替換的彈性。專案開始後，切勿將陌生領域的東西寫得太過死硬，要可以容易被切割獨立。因為若是在開發過程中，才發現原先使用的技術可能並不適合在目前的用途上時，可以用另外的技術來彌補或替換。除非，有時間上的壓力或限制，硬是使用不適當的技術完成任務是容易有後遺症的，而且容易傷害到使用者體驗。更重要的是有很大機會達不成目標的標準。&lt;br /&gt;&lt;br /&gt;此外選擇技術的評估，除了應該先有通盤知識為基礎，應該以客觀或是跨時代的角度來做，而不是以自己手上的電腦硬體，或是自己目前正習慣使用的平台或喜好的技術為準。一旦專案有挫折或失敗，才來說當初選錯平台，實在是浪費時間。而且，還可能錯上加錯，因為不是選錯平台而是選錯技術的可能性更大。&lt;br /&gt;&lt;br /&gt;要知道，這個時代是多元的，只熟悉或知曉單一方向技術，是無法有太多創意和實作能力的。解決問題的方法並不需要貫徹技術到底的決心，只要選擇適當即可。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-525079490372185518?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/525079490372185518/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/10/blog-post_15.html#comment-form' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/525079490372185518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/525079490372185518'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/10/blog-post_15.html' title='程式開發者之傻傻搞不清楚技術定位'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-915439468639776331</id><published>2011-10-10T16:13:00.000+08:00</published><updated>2011-10-10T18:38:38.902+08:00</updated><title type='text'>程式開發者之萬事起頭難</title><content type='html'>&lt;span class="Apple-style-span" style="font-family: Verdana;"&gt;&lt;/span&gt;&lt;br /&gt;接觸程式開發也已經十五年有餘，雖然不算多，但也算經歷過不少風雨。於是趕在二十五歲結束前，開始記錄起『程式開發打字工』的種種心得。之後，如同數學家的二十五歲大限，希望『程式開發打字工』將成為興趣與次要的工作，不敢說可以完全放下，但必要動手做時也會不假別人之手。&lt;br /&gt;&lt;br /&gt;首先談到開發一個新的專案，俗話說萬事起頭難，我們馬上會碰到千頭萬緒襲來。而且我們什麼都想做，什麼都想完美，往往還沒開始就已經結束了。此時心神不定，煩燥之時若螢幕上閃過X浪或 Facebxxk 的身影，再來個香蕉動新聞，一整天馬上就過去。&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;寫程式很重要的的一個原則就是：『不要想一次都要做太多功能。』尤其是在初次接觸的領域。因為，光是計劃架構和細節就會先消磨掉大半熱情。甚至開始實作以後，你會因為到處要留後著而難以前進，把自己陷於無法動彈之地。一但沒有動力，也沒有前進的路，該專案將胎死腹中。&lt;br /&gt;&lt;br /&gt;如果有足夠的時間，專案初期不斷打掉重練，是可以接受的。因為這比起日後累積太多量後，才發現不適合再打掉重練而來得好。也不會因為在錯的基礎上開發，而降低開發效率，甚至寫出問題重重的軟體。&lt;br /&gt;&lt;br /&gt;至於『如何才叫太多功能』，這依每個人而定，經驗多寡決定了一個人能快速設計多大規模的架構，並且能在該架構下工作而不會自亂陣腳。同樣類型的程式，如果你有過去的實作經驗，這次肯定有思緒改進或是延用。反之，如果沒有過去的經驗，很難做太長遠的細節規劃，你能靠的只有『過去學會的程式技巧』和『類似經驗』，盡力設計一個勘用的架構罷了，然後經過提早發現問題提早重新來過，盡可能補完整個專案所需。&lt;br /&gt;&lt;br /&gt;當然，除了程式技巧和相關知識，經驗是不通用的，如果碰到不熟悉的專案，還是得從頭累積經驗，從小規模的設計一步步前進。記得不要貪多，一個功能一個功能確實完成，『慢慢來，比較快』。&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-915439468639776331?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/915439468639776331/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/10/blog-post.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/915439468639776331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/915439468639776331'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/10/blog-post.html' title='程式開發者之萬事起頭難'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-4824725177768593150</id><published>2011-10-06T04:05:00.000+08:00</published><updated>2011-10-06T05:46:33.669+08:00</updated><title type='text'>Apple 大軍壓境，電腦王國準備好了嗎？</title><content type='html'>如果沒意外，Apple 將以低價重回戰場，掃蕩剩下的反抗勢力，用升級版的硬體，鞏固現有的防線。那麼，過去的電腦王國，準備好應戰了嗎？顯而易見：『還沒。』&lt;br /&gt;&lt;br /&gt;我們可以期待，接下來手機裝置的局面很可能是三分天下：『Apple、Nokia、Moto』，他們分別背後擁有強悍的軟體公司或團隊支援。雖然 Google 目前沒有說要開始親自投入戰場，但是品牌和代工合體後的 GMoto(Google + Moto Mobility)，難保有一天不會自己殺出條血路。就算是台灣當前的對手 - 『韓國』， Samsung 也擁有著自己的軟體系統。那麼，電腦王國怎麼辦？身為電腦王國的國民，不免擔憂起這樣的局面。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;舊時代王者的現實&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;郭董已經證明，鐵血毛利之下除了逼人跳樓之外，缺少政府『幫助』後，現在才正要開始體現代工產業下應有的利潤和風險。在這薄利又不景氣的時代，比誰和銀行借的錢多，已經不管用了。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;缺少商業模式的資訊產業&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;如果有夠大的商業模式或願景為前提，就算是當年 PC 時代的『大補帖』歪風，都能有掀起錢潮的機會。任何點子和創意，都足以大舉刺激商業發展。&lt;br /&gt;&lt;br /&gt;今天，拼命的生蛋和不停的脫皮，算斤兩的生意，卻已經變成主流。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;硬體廠商心中的不平衡&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;還記得當年 PC 獨霸的年代，微軟一舉跳上枝頭，收盡一切好處。硬體廠商雖然拼命做，扛下所有生產風險，但每台電腦所獲得的利潤逐年降低，直至今天這『毛利』的勢態後咬牙苦撐。反觀微軟靠著數不清的五毛光碟片，賺得荷包滿滿。現在殘存的硬體廠商，誰不恨得牙癢癢？所以只要有機會解決微軟，讓原本應該進微軟進自己口袋，何樂而不為？&lt;br /&gt;&lt;br /&gt;此外，Apple 以一家非硬體製造商的身份，用 iPhone/iPad 打下一片江山，讓所有人失了面子也失了市場。沒有一家廠商不這麼想：『既然 Apple 可以從一家軟體（或稱為系統整合）的公司，跨足到完全不相干的手機產業，那麼，身為硬體製造商的我們，為什麼不能跨界成為 Apple 呢？』&lt;br /&gt;&lt;br /&gt;於是，成為『類 Apple 公司』變成這些傳統 PC 製造商的夢。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Android 滿足了硬體廠商心中的不平衡&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;終於有機會可以自己掌控作業系統，不用再給微軟或任何系統軟體業者半毛錢。各家廠商無一不開始宣布自家有完整的系統技術團隊，可以針對作業系統做任何改進和維護。對硬體商來說，有了一個可以佔有的作業系統後，這不就代表：『我也是 Apple 了嗎？』&lt;br /&gt;&lt;br /&gt;於是，喊出各種軟硬、垂直整合的『口號』。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Open Source 讓所有人忘了自己如何起家而 Apple 以前怎麼失敗&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;還記得當年，Apple 推出了個人電腦，就如同今天的 iPhone/iPad 一般的封閉。爾後，被 IBM 所領導的 PC 大軍所打敗，台灣因而開始有電腦王國的稱號。今天的各家硬體製造商，都是當年聯軍中的一份子，靠著開放的標準和朝共同目標努力而起家。&lt;br /&gt;&lt;br /&gt;二十多年後的今天，這些聯軍將領，確因眼紅於 Apple 的名利雙收，無一不走起與 Apple 相同的路。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;為了創新而創新&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;看到 Apple 投下的原子彈，任誰都會想：『有武力才能當王者。』因此，所有廠商在軍備競賽之下，只看到眼前的船堅炮利，已經看不到『內求』的重要。徒打造出外表亮麗的艦隊，卻沒有經營的觀念，也沒有足以支撐的知識基礎。&lt;br /&gt;&lt;br /&gt;當別人正在突破自己，我們的創新正在煩惱『如何快速現代化』。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;已經沒有進步可言的產品&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;機海策略，可以針對各種客群做攻略。但這樣龐大的研發、製造成本和時效風險，造成商品可以有嚴重問題的『遣規則』。&lt;br /&gt;&lt;br /&gt;如果想要問題獲得改善，『請買下一代』已經變成廠商業務很容易說出口的『官方建議』，更可怕的是，就算買了下一代產品，問題可能依舊。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;把軟體當做隨用即拋的零件&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;硬體的零件，可以壞了直接換新，這批貨用不完下批繼續用。可是軟體卻是壞了不一定有能修，這次用完，下個產品可能放不進去。&lt;br /&gt;&lt;br /&gt;過去的台灣的生存環境太注重個人戰力而缺少團隊協同開發，所以我們常常可以看到個人色彩濃厚的程式碼，然後時效性的因素加碼後，往往會產出他人難以維護，甚至是無法再利用的軟體。&lt;br /&gt;&lt;br /&gt;當沒有實體成本的軟體，變得無法維護和改進時，反而變成日後嚴重的人力成本浪費。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;活在灰色地帶的廠商&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;PC 時代，系統有問題我們可以罵微軟。手機時代，如果用 Android，我們罵 Google 也沒用，因為我們不是 Google 的客戶。罵製造商也沒用，因為很可能是 Android 本身的問題。&lt;br /&gt;&lt;br /&gt;不過，有一種狀況更棘手：『系統被廠商修改後產生的問題，但第一線服務人員為守住戰線，直接推給 Google。』&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;立刻決定！不當對不起自己和後代的廠商！&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;身為後輩，不期望能給予當年聯軍的名將們當頭棒喝，也不認為老大哥們不懂當前困境。只是希望，前輩能留下一條讓後代好走的路，指明一條我們應該走的路。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-4824725177768593150?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/4824725177768593150/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/10/apple.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/4824725177768593150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/4824725177768593150'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/10/apple.html' title='Apple 大軍壓境，電腦王國準備好了嗎？'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-2935396036845932310</id><published>2011-10-01T10:57:00.001+08:00</published><updated>2011-10-01T10:57:51.509+08:00</updated><title type='text'>改善 QML 圖型渲染效能</title><content type='html'>雖然 Nokia 擁抱了 Microsoft，但不可否認，其旗下的 Qt Framework 經過十載演進，也有 Open Source 出來，實在是個好東西。因此，筆者認為 Nokia 的決定並不會影響我們繼續使用 Qt 的意願，長期在 Linux 下並以 Qt 為基礎的 KDE 桌面環境，就足夠證明了&amp;nbsp;Qt 尚未死。&lt;br /&gt;&lt;br /&gt;而最近筆者使用 QML 實做了一些應用程式，發現圖型渲染效能並不是非常好。猜想是和 Android 有相同的問題，於是著手將程式改用 OpenGL 來繪圖，果然，效能立即獲得大幅度改善：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;int main(int argc, char *argv[])&lt;br /&gt;{&lt;br /&gt;    QApplication app(argc, argv);&lt;br /&gt;    QGLWidget *glWidget;&lt;br /&gt;    QGLFormat format = QGLFormat::defaultFormat();&lt;br /&gt;&lt;br /&gt;    /* Create OpenGL Widget to render QML */&lt;br /&gt;    format.setSampleBuffers(false);&lt;br /&gt;    glWidget = new QGLWidget(format);&lt;br /&gt;    glWidget-&amp;gt;setAutoFillBackground(false);&lt;br /&gt;&lt;br /&gt;    /* Create QDeclarativeView to open QML file */&lt;br /&gt;    QDeclarativeView *viewer = new QDeclarativeView;&lt;br /&gt;    viewer-&amp;gt;setViewport(glWidget);&lt;br /&gt;    viewer-&amp;gt;setSource(QUrl::fromLocalFile("main.qml"));&lt;br /&gt;    viewer-&amp;gt;show();&lt;br /&gt;&lt;br /&gt;    return app.exec();&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-2935396036845932310?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/2935396036845932310/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/10/qml.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2935396036845932310'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2935396036845932310'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/10/qml.html' title='改善 QML 圖型渲染效能'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-6713183329875107559</id><published>2011-09-11T05:20:00.000+08:00</published><updated>2011-09-11T05:22:52.017+08:00</updated><title type='text'>Flat Project Demo - An OS for Tablets 平板作業系統</title><content type='html'>無奈，前些日子在 COSCUP 2011 因為 Lightening Talk 時電腦出現異常，展示以失敗告終，耿耿於懷。於是趁著這次中秋假期，將 Flat Project（詳細說明請見前文：&lt;a href="http://fred-zone.blogspot.com/2011/08/flat-project.html"&gt;Flat Project - 從山寨做起，親手打造炫麗的平板系統&lt;/a&gt;）開發至一半的測試影片準備好並上傳至 Youtube。但錄影效果不佳，還請包涵。&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i.ytimg.com/vi/ujJberGChOg/0.jpg" height="266" width="320"&gt;&lt;param name="movie" value="http://www.youtube.com/v/ujJberGChOg?f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;embed width="320" height="266"  src="http://www.youtube.com/v/ujJberGChOg?f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;br /&gt;主要實作了 3D 視窗管理器（Window Manager+Compositor），如果不熟 X11 架構，也可將它視為 Android 上的 SurfaceFlinger，更多深入的技術細節也已經在 COSCUP 2011 &amp;nbsp;Unconference 議程做了粗略說明。藉著這個成果，可輕易將各式應用程式（Firefox+Google Map+OpenGL Application）畫在我們的 3D 物件上，因此可以運用 3D 技術對應用程式做各類特效或翻轉，在本例中，仿 iPad 的『程式啟動/關閉』和『按兩下 Home 鍵』的效果就是這樣完成的。&lt;br /&gt;&lt;br /&gt;此外在影片中可以看到，我們也實作了桌面程式選單和原生的 Google Map 應用程式。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;目前除了正在補上整個環境所需的元件外和完善架構外，完美結合和運行原生的 Android 應用程式也是長期的目標。期望以過去的成果（見舊文：&lt;a href="http://fred-zone.blogspot.com/2010/08/android-is-working-on-x.html"&gt;Android is Working on X&lt;/a&gt;）為基礎，讓 Android JVM 可以被移植並整合進來，使&amp;nbsp;Flat Project 可以執行各式 Linux/Meego 應用程式外，也可以跑 Android App。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-6713183329875107559?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/6713183329875107559/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/09/flat-project-demo-os-for-tablets.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6713183329875107559'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6713183329875107559'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/09/flat-project-demo-os-for-tablets.html' title='Flat Project Demo - An OS for Tablets 平板作業系統'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-1783823387248154581</id><published>2011-09-09T02:08:00.000+08:00</published><updated>2011-09-09T02:08:47.715+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux硬體驅動'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Embedded System'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><category scheme='http://www.blogger.com/atom/ns#' term='patch'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>發瘋的 Qt QWS TTY Keyboard Driver</title><content type='html'>最近接了一個小案子，主要是協助客戶將 Qt 應用程式從舊板子移植到新的硬體上，由於硬體是 Third-party 做，當然所有的驅動程式也是由別人處理，我們並不經手，只和硬體廠商密切合作。&lt;br /&gt;&lt;br /&gt;這次我們碰到了一些 Keyboard 問題，一開始是 Linux driver 缺少 input_sync() 的操作，導致 Qt 無法正確辯別按鍵的『壓放』。接著碰到個更棘手的問題，就是 Qt 送到應用程式的 Key 事件（Event）有很大機率會送錯。這將導致按鍵所觸發的結果，有很大的機會我們無法預期。檢查過 evdev event 和其發出來的 keycode，我們確定了 Linux Driver 是正確的，判斷應該是 Qt 的問題。&lt;br /&gt;&lt;br /&gt;經過一番檢查後，發現是因為 Qt-Embedded 預設使用 TTY Driver(qkbdtty) 去驅動鍵盤，大部份情況下不太會有問題，但因為我們走的是標準的 Linux evdev (/dev/input/eventX)，如果很快速或多重觸發鍵盤按鍵，就有可能讓 Qt 的 TTY Driver 取樣和解析出錯誤的&amp;nbsp;Event 值。最快的解決辦法就是捨棄 Qt TTY Driver，然後改用 Qt &amp;nbsp;LinuxInput Driver(qkbdlinuxinput)。&lt;br /&gt;&lt;br /&gt;不過 qkbdlinuxinput 並不處理 VT，這是與 qkbdtty 最大的差異，此舉會造成板子上的 Console 不正常切換，Debug 用的 Console 會因此壞掉。筆者在此對 QWS Keyboard Driver 做了些修改，讓 tty driver 使用&amp;nbsp;linuxinput driver 的方式去解析 keyboard event，並保留 VT 的處理機制。&lt;br /&gt;&lt;br /&gt;Patch 檔案連結如下：&lt;br /&gt;&lt;a href="http://fred-opensource.googlecode.com/git/patches/qkbdtty_qws.patch"&gt;http://fred-opensource.googlecode.com/git/patches/qkbdtty_qws.patch&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-1783823387248154581?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/1783823387248154581/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/09/qt-qws-tty-keyboard-driver.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1783823387248154581'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1783823387248154581'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/09/qt-qws-tty-keyboard-driver.html' title='發瘋的 Qt QWS TTY Keyboard Driver'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-4464780896479087577</id><published>2011-09-04T00:21:00.002+08:00</published><updated>2011-09-04T00:22:02.081+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><title type='text'>開啟網路蟲洞穿越時空，活用 SSH Tunnel VPN</title><content type='html'>最近去了一趟上海考察，尋找創業發展的機會，但機會暫且不論，此行確實深深體會在中國的網路世界非常不一般。中國和諧的社會實在不容許影響善良風俗的事情存在，許多外來的邪惡，一一被偉大的長城擋在外面。不過，道高一尺魔高一丈，很多人很聰明，懂得翻牆方法，進出自如，多數人使用 Reverse SSH Tunnel（有興趣可參考筆者舊文『&lt;a href="http://fred-zone.blogspot.com/2010/08/reverse-ssh-tunnel.html"&gt;Reverse SSH Tunnel 反向打洞實錄&lt;/a&gt;』）建立一個臨時的 Proxy Server，讓網頁連線繞道而行。&lt;br /&gt;&lt;br /&gt;不過，使用 Proxy Server 的方式只能讓特定的通訊協定能夠不受防火牆的阻擋，如果說要全面性的逃脫網路限制和監控，就要靠 VPN（Virtual Private Network）的方式。VPN 是什麼？簡而言之，就是與遠端的網路環境建立通道，使電腦彷彿真實身處於遠端的內部網路一般。所以 VPN 一旦建立成功，除了可以存取遠方的內部網路，當然亦可以將遠端網路當為中繼站再連到網際網路，換言之，就是可繞過防火牆的一切限制。至於&amp;nbsp;VPN 的建立方法有很多種， 但都不在本文範疇，這邊要說明的是如何用 SSH Tunnel 建立 VPN。&lt;br /&gt;&lt;br /&gt;設定必要的環境變數後，直接執行以下的 Script，就可以和遠端 Server 建立 VPN 連線：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;# Local Network&lt;br /&gt;NETWORK=192.168.16.0&lt;br /&gt;GW=192.168.16.1&lt;br /&gt;&lt;br /&gt;# Server IP Address&lt;br /&gt;SERVER=123.123.123.123&lt;br /&gt;# Server 對外的 Interface&lt;br /&gt;SERVER_IF=eth0&lt;br /&gt;&lt;br /&gt;echo "Creating Connection"&lt;br /&gt;ssh -w 0:0 -f $SERVER "ifconfig tun0 10.0.2.1 netmask 255.255.255.252 pointopoint 10.0.2.2 ; echo 1 &amp;gt; /proc/sys/net/ipv4/ip_forward ;/sbin/iptables -t nat -A POSTROUTING -o $SERVER_IF -j MASQUERADE ;route add -net $NETWORK gw 10.0.2.2 dev tun0"&lt;br /&gt;&lt;br /&gt;echo "Settingi local interface"&lt;br /&gt;ifconfig tun0 10.0.2.2 netmask 255.255.255.252 pointopoint 10.0.2.1&lt;br /&gt;route add -net ${SERVER%.*}.0/24 gw 10.0.2.1 dev tun0&lt;br /&gt;route add $SERVER gw $GW&lt;br /&gt;route add default gw 10.0.2.1 tun0&lt;br /&gt;route del default gw $GW&lt;/pre&gt;&lt;/div&gt;註一：如果不能正確建立連線，請先確認 SSH Port(22) 是否已被防火牆阻擋。&lt;br /&gt;註二：記得修改 /etc/resolv.conf 的 DNS 設定，有些網路是直接在名稱解析做阻擋（如：在中國的網路）。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;SSH 有高度的安全性，透過 SSH 建立 VPN，也可以多少避免網路被當下的網路提供者竊聽。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-4464780896479087577?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/4464780896479087577/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/09/ssh-tunnel-vpn.html#comment-form' title='3 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/4464780896479087577'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/4464780896479087577'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/09/ssh-tunnel-vpn.html' title='開啟網路蟲洞穿越時空，活用 SSH Tunnel VPN'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-5949986940560605239</id><published>2011-08-31T21:55:00.002+08:00</published><updated>2011-09-04T16:31:35.449+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Juice'/><category scheme='http://www.blogger.com/atom/ns#' term='技術新知'/><category scheme='http://www.blogger.com/atom/ns#' term='Desktop'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='X11'/><category scheme='http://www.blogger.com/atom/ns#' term='User Interface'/><title type='text'>新鮮果汁吧！果汁桌面環境(Juice Desktop Environment)！</title><content type='html'>筆者喜愛喝果汁，故為這個新的 Project 取了 Juice 這樣的名稱，意旨一個自己喜愛的桌面環境。在前些日子，因為放棄了 GNOME 而轉向使用 Enlightenment（以下簡稱E17），雖然各方面還算不錯，但在新版 Package 的更新上實在是缺少人在維護。因此，若是使用 Debian 官方版本的 E17 Package，功能非常少，而 E17 官方的 Repository 版本又太舊。其實，原本希望能幫忙打包，但因為種種因素而做罷。&lt;br /&gt;&lt;br /&gt;既然本身需求不高，就發揮今年貫徹執行的土砲精神，在空閒時間動手開發一個合用的桌面環境。目前，已經釋出其中一個 Dock/Panel 元件『&lt;a href="http://code.google.com/p/jushelf/"&gt;JuShelf(Juice Shelf)&lt;/a&gt;』的初步版本，也已經有實作模組(Module)機制，和一種 module。下面是畫面截圖（Screenshot）和最新的展示影片：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-JdIzupyX06s/Tl463GhU-SI/AAAAAAAAA6w/xjst-gHCJAU/s1600/jushelf.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="79" src="http://4.bp.blogspot.com/-JdIzupyX06s/Tl463GhU-SI/AAAAAAAAA6w/xjst-gHCJAU/s320/jushelf.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i.ytimg.com/vi/zmAa6b13fhE/0.jpg"&gt;&lt;param name="movie" value="http://www.youtube.com/v/zmAa6b13fhE?f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;embed width="320" height="266"  src="http://www.youtube.com/v/zmAa6b13fhE?f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;畫面中展示的是 Launch module，能提供圖示讓使用者點擊並啟動應用程式。其中的特效設計是放大圖示然後傾斜，帶有相當的趣味性。&lt;br /&gt;&lt;br /&gt;目前仍然待完成的模組：&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;工作視窗清單(taskbar)&lt;/li&gt;&lt;li&gt;系統狀態顯示區(systray)&lt;/li&gt;&lt;li&gt;時間顯示(Clock)&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;後記&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;目前 Juice 本身還沒有 Project 網站，只是以個人動機為出發點，若是日後有較完整的開發成果，會再補上。此外，Juice 初期打算使用 Compiz 或 Mutter 做為視窗管理器（Window Manager），以及配合一基本的 GNOME 小元件（如同筆者前些日子在整合 E17 和 GNOME 一般）。&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-5949986940560605239?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/5949986940560605239/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/08/juice-desktop-environment.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5949986940560605239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5949986940560605239'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/08/juice-desktop-environment.html' title='新鮮果汁吧！果汁桌面環境(Juice Desktop Environment)！'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-JdIzupyX06s/Tl463GhU-SI/AAAAAAAAA6w/xjst-gHCJAU/s72-c/jushelf.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-2022597570279125087</id><published>2011-08-31T06:46:00.001+08:00</published><updated>2011-08-31T06:48:03.859+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Embedded System'/><category scheme='http://www.blogger.com/atom/ns#' term='epaper'/><category scheme='http://www.blogger.com/atom/ns#' term='Qt'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>針對『電子紙』優化 Qt 繪圖事件</title><content type='html'>最近手上有一些電子紙的案件，指定使用 Qt 做為圖型平台。與一般裝置不一樣的地方，電子紙的更新頻率很低，平均下來每秒頂多刷新一次，相對於 LCD Panel 的每秒 60 次起跳，實在低的可憐。對於專職繪圖的 Qt 而言，要如何壓低刷新的頻率和確認畫面繪圖完成，最後再推入 Display，便是一個重要的課題。&lt;br /&gt;&lt;br /&gt;壓低更新頻率比較單純，透過修改 Framebuffer Driver 就可以達成。此外，也必須利用 setUpdatesEnabled() 和 update() 盡量避免 Qt 連續多次的繪圖需求，合併一次送入 framebuffer，這樣可以減少&amp;nbsp;Qt 來不及畫完和畫面閃爍的問題。&lt;br /&gt;&lt;br /&gt;到此為止只是改善顯示效果和基礎的建置，真正要完成完美的一次推送，通常需要使用電子紙驅動程式所提供的額外 API，它同意我們自己決定何時將 Framebuffer 的資料推送到紙上。&lt;br /&gt;&lt;br /&gt;至於何時該將畫面推送至電子紙上？這時需要針對 QApplication 做一些修改，監聽和自己創造一個新的事件：&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;pre&gt;const QEvent::Type UpdateScreenEvent = (QEvent::Type)1234;&lt;br /&gt;bool Application::notify(QObject *obj, QEvent *e)&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;if (e-&amp;gt;type() == UpdateScreenEvent) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; if (updateScreen) {&lt;br /&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; EPaperDriverCtrl *ctrl = (EPaperDriverCtrl*)EPaperDriverCtrl;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ctrl-&amp;gt;pushFBtoPanel();&lt;br /&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; updateScreen = false;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; return true;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;} else if (e-&amp;gt;type() == QEvent::Paint) {&lt;br /&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; updateScreen = true;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp; QApplication::postEvent(this, new QEvent(UpdateScreenEvent));&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;return QApplication::notify(obj, e);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;原理相當簡單，監聽所有的繪圖事件，然後送一個自定的畫面推送事件，推送事件會在所有繪圖事件完成後被執行。最後再利用 updateScreen 這個旗標來避免多次的推送事件，無論有多少推送要求，都只做一次的推送。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Qt 的優點就不必多說，經過十多年的演進，已成為世上數一數二的圖形化系統，雖然 Nokia 在政治考量上，在未來產品中放棄了使用基於 Qt 的 Meego，但仍不滅 Qt 的威風，因為他早已深入各個大大小小嵌入式系統和桌面系統，我們常聽到的 KDE 便是使用 Qt 的產物。和多數 Open Source Solution 相比，Qt&amp;nbsp;最大的不同是採用了 C++，所以開發速度快捷，又由於長年來在嵌入式系統上的發展，也有很大的彈性和效能，此外 footprint 也相當小。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-2022597570279125087?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/2022597570279125087/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/08/qt.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2022597570279125087'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2022597570279125087'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/08/qt.html' title='針對『電子紙』優化 Qt 繪圖事件'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-1388382223892653556</id><published>2011-08-22T06:35:00.000+08:00</published><updated>2011-08-22T06:35:36.448+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='技術新知'/><category scheme='http://www.blogger.com/atom/ns#' term='Window Manager'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Tablet'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Flat'/><category scheme='http://www.blogger.com/atom/ns#' term='Embedded System'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='心得分享、講座'/><category scheme='http://www.blogger.com/atom/ns#' term='X11'/><category scheme='http://www.blogger.com/atom/ns#' term='User Interface'/><title type='text'>Flat Project - 從山寨做起，親手打造炫麗的平板系統</title><content type='html'>已經過了近兩年，至今仍然沒有一台 PC 廠商做的平板電腦能勝過 iPad，精緻度估且不論，其速度與流暢度，相較之下只能堪稱工程機的程度。其實真正原因不在於這些廠商行銷廣告中的 CPU 『數量』，而是 Android 系統軟體本身處處存在了一些效能上的問題，重點是這些問題不是工程師所在意的，而且吃力又不一定討好，沒人會拿飯碗去賭。另一方面，Android UI 設計永遠就像工程師自我良好的作品，單獨看每一個元件都很漂亮，可是拼裝起來後感覺就是盤剩菜剩飯，就算換了 UI，也不過只是換了封面罷了，換湯不換藥。&lt;br /&gt;&lt;br /&gt;Open Source Project 的開發，最困難的就是修改機制，在很多時候，我們只有能力挖肉，沒能力整骨，畢竟整個 Project 不是我們自己寫的。當然，也因此很多設計是無法加上去的，就算加上去也無法好用。就像現在廠商所提倡的軟硬體垂直整合，雖然我們已經有了硬體與軟體的溝通，但在應用軟體到軟體系統之間，其實更需要有好的垂直整合，否則出現斷層後，就像現在 Android 平板總是說不出的有問題。也難怪有人在罵大多數場商只是把 Open Source Software 隨便放到硬體上就拿出來賣，根本不用心。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;我們何不來自己動手寫一個平板系統？&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;運用現成的 Open Source Project 為基礎，以 iPad 為學習目標，重新打造一個平板用的作業系統。重要的是，品質要能出貨，又有好的擴充性和可用的底層機制，而不只是用套軟體拉一拉 UI 就完事。&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;b&gt;Mandice Flat Project&lt;/b&gt;（&amp;nbsp;&lt;a href="http://code.google.com/p/flat"&gt;http://code.google.com/p/flat&lt;/a&gt;）&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;[&lt;a href="http://code.google.com/p/flat"&gt;Flat Project&lt;/a&gt;] 就是一個這樣的產物，目標是自己動手打造一個開放的平板環境。（目前已經釋出程式碼的子項目是 GrandPa（視窗管理器），是一個仿 iPad 視窗行為的 3D&amp;nbsp;Window Manager。）&lt;br /&gt;&lt;br /&gt;Flat 的起源，[&lt;a href="http://www.mandice.com/"&gt;Mandice&lt;/a&gt;] 是這幾年間與不少大大小小廠商合作過案子，已有不少經驗和成果。所以在今年的 [&lt;a href="http://coscup.org/"&gt;COSCUP 2011&lt;/a&gt;] 活動，筆者一時興起，便把過去案子所開發的各種元件抽出來再開發並陸續釋出，這就是&amp;nbsp;[&lt;a href="http://code.google.com/p/flat"&gt;Flat Project&lt;/a&gt;] 的由來，當然已經移除不應該公開的商業部份。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;順帶一提，今年度 COSCUP 2011 的 Unconference Session 筆者有講如何設計 Window Manager，有興趣的人可以以 GrandPa 做為實例印證。&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-1388382223892653556?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/1388382223892653556/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/08/flat-project.html#comment-form' title='7 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1388382223892653556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1388382223892653556'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/08/flat-project.html' title='Flat Project - 從山寨做起，親手打造炫麗的平板系統'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-9013904973463290682</id><published>2011-07-18T10:53:00.000+08:00</published><updated>2011-07-18T10:53:29.758+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MongoDB'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='Web 相關技術'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>MongoDB 快速筆記</title><content type='html'>這幾年&amp;nbsp;Web Service 的龐大需求，對資料庫的要求是快速且吞吐量大，因此業界開始流行 NoSQL，它省略最花時間的資料庫操作和複雜的結構，用最合人類使用需求的方式在儲存資料，其帶來的好處，當然就是能提供極速的反應和龐大的資料吞吐量。目前最廣為人知的就是 BigTable，Google 提供全世界快速搜尋和各種線上服務，靠的就是這 NoSQL Database。&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;其實 NoSQL Database 的選擇非常多，但本文只是記錄 MongoDB 的操作筆記，因此就不詳述。 有興趣的人，可以去查閱網路上更多的資料。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;選擇 Database：&lt;/div&gt;&lt;div&gt;&lt;pre&gt;use my_database&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;利用 root 新增&amp;nbsp;Database 的管理帳號：&lt;/div&gt;&lt;div&gt;&lt;pre&gt;# 切換到 my_database&lt;br /&gt;use my_database&lt;br /&gt;# 先用 root 帳號認證&lt;br /&gt;db.getSisterDB("admin").auth("root", "rootpassword");&lt;br /&gt;# 新增 frankie 帳號&lt;br /&gt;db.addUser("frankie", "fredpassword");&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;新增 Database 的管理帳號：&lt;/div&gt;&lt;div&gt;&lt;pre&gt;# 切換到 my_database&lt;br /&gt;use my_database&lt;br /&gt;# 先用&amp;nbsp;frankie&amp;nbsp;帳號認證&lt;br /&gt;db.auth("frankie", "fredpassword");&lt;br /&gt;# 新增 zombie 帳號&lt;br /&gt;db.addUser("zombie", "zombiepassword");&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;插入新增資料（Insert）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;# 插入一筆新資料到 users Collection （相當於傳統 SQL 裡的 Table 角色）&lt;br /&gt;db.users.insert({ username: "fred", password: "12345678" })&lt;br /&gt;# 含當前時間&lt;br /&gt;db.users.insert({ username: "fred", password: "12345678", created: new Timestamp() })&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;查詢（Query）：&lt;/div&gt;&lt;div&gt;&lt;pre&gt;# 查詢所有 username 為 fred 的資料&lt;br /&gt;db.users.find({ username: "fred" })&lt;br /&gt;# 查詢單筆&lt;br /&gt;db.users.find_one({ username: "fred" })&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;修改更新資料（Update）：&lt;/div&gt;&lt;div&gt;&lt;pre&gt;# 更新 username 為 fred 的 password 欄位&lt;br /&gt;db.users.update({ username: "fred" }, { $set: { password: "87654321" }})&lt;br /&gt;# 完全取代 username 為 fred 的資料（username 和 password&amp;nbsp;欄位會因此不見，只剩下 email 欄位）&lt;br /&gt;db.users.update({ username: "fred" }, { email: "cfsghost@gmail.com"})&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;刪除資料（Delete）：&lt;/div&gt;&lt;div&gt;&lt;pre&gt;db.users.remove({ username: "fred" })&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-9013904973463290682?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/9013904973463290682/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/07/mongodb.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/9013904973463290682'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/9013904973463290682'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/07/mongodb.html' title='MongoDB 快速筆記'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-1663430681042917567</id><published>2011-07-12T11:06:00.006+08:00</published><updated>2011-07-12T11:25:44.032+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GNOME'/><category scheme='http://www.blogger.com/atom/ns#' term='Window Manager'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='E17'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='X11'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>不想用傻逼 GNOME3 ！好牛逼的雜牌軍替代方案 E17+GNOME/XFCE/Fluxbox Component！</title><content type='html'>好不容易，Linux 桌面經過十多年的演進，GTK+ 和 GNOME 總算進入了 3.0 的時代，向來最愛仗著『使用者之名』做盡任何事的 Ubuntu，也推出了他們的 Unity 介面，試圖重新打造桌面使用者的習慣。可惜的是，這些新的桌面設計雖然帶來了完全不一樣體驗，卻也造成不少使用者操作思維的混亂；更可怕的，這些標新立異的改變，將原本『好不容易』成熟穩定下來的桌面系統，在短時間內，又再次推向重新建立習慣和軟體崩潰的循環地獄。&lt;br /&gt;&lt;br /&gt;網路上一篇討論文章『&lt;a href="http://moto.debian.tw/viewtopic.php?f=27&amp;amp;t=16147"&gt;Linux的桌面為什麼這麼傻逼&lt;/a&gt;』（這篇文章是有心人翻譯的，內有原文連結），對 Linux 桌面環境有很獨道的見解和體驗，其批判性的強烈言詞，可以感覺到這些年作者的沉痛經歷。&lt;br /&gt;&lt;br /&gt;就某方面來說，筆者相當讚同該文的論調，本身就長期使用 Linux 桌面，不時因為各種桌面系統的問題，親自動手去做程式開發或調整，可以說該文道盡筆者心聲。不過最近這一兩年，&amp;nbsp;GNOME 已經可以算是很好用的桌面環境，程式也很穩定，周遭初入 Linux 的朋友們也都可以輕易上手。但高興沒辦法太早，&amp;nbsp;GNOME 3.0 在此時投下了一顆超級炸彈，其更新除了讓許多元件壞東壞西，使用操作和程式開發上完全讓人覺得陌生。&lt;br /&gt;&lt;br /&gt;喔不！我不要再經歷一次『桌面環境的黑暗時代』。我只想穩穩定定且不要有意外的使用著我的作業系統，所以我也拒絕 GNOME3 和 Unity。在一切混亂的情況下，Enlightenment（簡稱 E17） 帶來了一線曙光。&lt;br /&gt;&lt;br /&gt;我對桌面環境的要求其實不高：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;可用性高，穩定度和使用性最好不要與 GNOME 2.0 有太大的差異。&lt;/li&gt;&lt;li&gt;速度快&lt;/li&gt;&lt;li&gt;漂亮又炫麗（最好能夠有 3D 桌面的支援，這讓我覺得我的系統比 Windows 高級）&lt;/li&gt;&lt;li&gt;省系統資源&lt;/li&gt;&lt;li&gt;畫面易客製化（如果能讓我看起來更像個專業&lt;strike&gt;&lt;i&gt;宅男&lt;/i&gt;&lt;/strike&gt;&amp;nbsp;Hacker更好）&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;經過一些拼裝和調整後，這是用 Enlightenment + GNOME Component + Thunar File Manager(XFCE) 組裝的桌面環境其最後樣貌：&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-qUZQc92fmGE/ThuZPU1gF1I/AAAAAAAAA5w/WeFaOWIBCvc/s1600/Screenshot.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="225" src="http://2.bp.blogspot.com/-qUZQc92fmGE/ThuZPU1gF1I/AAAAAAAAA5w/WeFaOWIBCvc/s400/Screenshot.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Debian 使用者，可以照下面步驟拼裝出同樣的桌面環境（當然畫面上的元件排版要依各自喜好自行調整）：&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;去&amp;nbsp;&lt;a href="http://packages.enlightenment.org/"&gt;http://packages.enlightenment.org/&lt;/a&gt;&amp;nbsp;尋找和系統相對應的 Repository（筆者將以 Debian Sid 為例）&lt;/li&gt;&lt;li&gt;在 /etc/apt/sources.list 裡加入：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;&lt;i&gt;deb http://packages.enlightenment.org/debian sid main extras&lt;/i&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;建立 /etc/apt/preferences.d/e17 空白檔案，然後寫入：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;&lt;i&gt;Package: *&lt;br /&gt;Pin: origin packages.enlightenment.org&lt;br /&gt;Pin-Priority: 600&lt;/i&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;下載並加入 E17 的 GPG Key：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;&lt;i&gt;wget http://packages.enlightenment.org/repo.key&lt;br /&gt;sudo apt-key add repo.key&lt;/i&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;更新 Apt 套件清單和安裝 E17 + Compiz 相關 modules：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;&lt;i&gt;sudo apt-get update&lt;br /&gt;sudo apt-get install e17 emodule-ecomorph compiz compiz-fusion-bcop compiz-plugins&amp;nbsp;&lt;/i&gt;&lt;i&gt;compiz-fusion-plugins-extra&amp;nbsp;&lt;/i&gt;&lt;i&gt;compiz-fusion-plugins-main&amp;nbsp;&lt;/i&gt;&lt;i&gt;compiz-fusion-plugins-unsupport compiz-gnome&lt;/i&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;安裝必要的 GNOME Components 和系統常駐程式（登入介面、GTK+環境管理、電源管理、網路管理、自動掛載管理）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;&lt;i&gt;sudo apt-get install gdm3 gnome-settings-daemon gnome-power-manager gnome-screensaver gnome-screenshot network-manager-gnome udisks-glue&lt;/i&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;安裝 XFCE 的 Thunar 檔案管理程式（因為 E17 的不好用，而 GNOME Nautilus 太慢）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;&lt;i&gt;sudo apt-get install thunar&lt;/i&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;安裝 Fluxbox 的 fbautostart（因為 E17 預設不支援 freedesktop.org autostart spec）&lt;br /&gt;&lt;div&gt;&lt;pre&gt;&lt;i&gt;sudo apt-get install fbautostart&lt;/i&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;重新啟動進入至 Enlightenment 桌面環境&lt;/li&gt;&lt;li&gt;設定桌面環境，用滑鼠左鍵點擊桌面空白處，選擇 『Settings』→『Settings Panel』&lt;/li&gt;&lt;ul&gt;&lt;li&gt;設定視窗外觀&lt;/li&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="Apple-style-span"&gt;開啟『Extensions』&lt;/span&gt;&lt;span class="Apple-style-span"&gt;→&lt;/span&gt;&lt;span style="font-weight: normal;"&gt;『Modules』&lt;/span&gt;&lt;/li&gt;&lt;span style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;a href="http://4.bp.blogspot.com/-u2XX1c_mE3A/Thuq06TYLsI/AAAAAAAAA50/o-odfLJjDis/s1600/Screenshot-Module+Settings.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://4.bp.blogspot.com/-u2XX1c_mE3A/Thuq06TYLsI/AAAAAAAAA50/o-odfLJjDis/s200/Screenshot-Module+Settings.png" style="cursor: move;" width="170" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;li&gt;將右方『Loaded Modules』的 Appearance 清空只剩下 Gadgets（如果你的系統沒有 3D 硬體支援不能跑 Compiz&amp;nbsp;，請保留 Bling 並略過下一步驟）&lt;/li&gt;&lt;li&gt;從左方『Available Modules』的 System 找到 Ecomorph 載入（啟動 E17 的 Compiz Module）&lt;/li&gt;&lt;/ol&gt;&lt;li&gt;載入系統小元件&lt;/li&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="Apple-style-span"&gt;開啟『Extensions』&lt;/span&gt;&lt;span class="Apple-style-span"&gt;→&lt;/span&gt;&lt;span style="font-weight: normal;"&gt;『Modules』&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: normal;"&gt;這邊有很多桌面小元件像是工具列、時鐘等等，可依個人喜好載入，若不明白，可以將所有可能需要的元件載入，等桌面版面調整好後再回來卸載（不卸載會吃系統資源）。&lt;br /&gt;&lt;br /&gt;註：有需多元件需要先安裝 Package，可去尋找『emodule-*』套件。&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;li&gt;設定桌面系統程式&lt;/li&gt;&lt;/ul&gt;&lt;ol&gt;&lt;ol&gt;&lt;li&gt;利用&lt;span class="Apple-style-span"&gt;『Apps』&lt;/span&gt;&lt;span class="Apple-style-span"&gt;→&lt;/span&gt;『New Application』新增下列系統程式：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;Name: &lt;i&gt;Autostart Daemon&lt;/i&gt;&lt;br /&gt;Executable: &lt;i&gt;/usr/bin/fbautostart&lt;/i&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;pre&gt;Name: &lt;i&gt;GNOME Settings Daemon&lt;/i&gt;&lt;br /&gt;Executable:&amp;nbsp;&lt;i&gt;gnome-settings-daemon&lt;/i&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;pre&gt;Name: &lt;i&gt;GNOME Screensaver Daemon&lt;/i&gt;&lt;br /&gt;Executable: &lt;i&gt;gnome-screensaver&lt;/i&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;pre&gt;Name:&lt;i&gt;&amp;nbsp;GNOME Power Manager&lt;/i&gt;&lt;br /&gt;Executable:&amp;nbsp;&lt;i&gt;gnome-power-manager&lt;/i&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;pre&gt;Name:&amp;nbsp;&lt;i&gt;Disk Automount Daemon&lt;/i&gt;&lt;br /&gt;Executable:&amp;nbsp;&lt;i&gt;udisks-glue&lt;/i&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;利用&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span"&gt;『Apps』&lt;/span&gt;&lt;/span&gt;→&lt;/span&gt;『Startup Application』將此五項系統程式加到啟動程式清單。&lt;/li&gt;&lt;/ol&gt;&lt;ul&gt;&lt;/ul&gt;&lt;/ol&gt;&lt;li&gt;&lt;span class="Apple-style-span"&gt;重新啟動進入至 Enlightenment 桌面環境，桌面程式安裝完成。&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;到目前為止，你可能覺得桌面空有特效，但預設介面不是很好用。這時可以移除掉系統正下方難用的 Dock，並利用 Shelf 建立喜好的 Dock 或各式工具列，打造合乎自己使用習慣的介面。以筆者的喜好為例：&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;視窗清單 Taskbar&lt;/li&gt;&lt;li&gt;快捷圖示 Ibar&lt;/li&gt;&lt;li&gt;系統程式選單 Starter&lt;/li&gt;&lt;li&gt;時鐘 Clock &amp;amp; TClock&lt;/li&gt;&lt;li&gt;系統常駐程式列&amp;nbsp;Systray（無線網路管理、電源狀態和應用程式常駐）&lt;/li&gt;&lt;li&gt;音量控制 Mixer&lt;/li&gt;&lt;/ul&gt;在之前的螢幕截圖可以看到，筆者將這些元件分成四個 Shelf （中上、中下、右上、右下）擺放。如果你沒有其他想法，也可以照這樣擺放，這樣設定和 GNOME 環境的使用上差異不大。當然，和 GNOME 一樣將這些元件放在同個 bar 上也是可行的。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;後記&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;身為 LXDE 的開發者，不得不承認 Enlightenment 非常輕量和快速，就算沒有 3D 硬體支援，外觀和速度上仍然遠勝所有的桌面環境。如果開著 Compiz 和許多桌面元件，系統記憶體是 300MB 綽綽有餘，且環境整合度相當好。若是再配合上 GNOME 和各家桌面的元件後，可用性和各桌面應用程式的相容性絕不輸給純 GNOME。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;唯一目前已知問題是 E17 的 Place Gadget 和 File Manager 還是使用舊的 HAL 標準（現在的一般標準是使用 udisks），所以這些元件還沒辦法去 Umount 經由標準 Automount 機制的硬碟。因此筆者在這部份暫時使用 XFCE Thunar 來代替，或許過些時間，E17 的開發團隊會修正此問題。&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-1663430681042917567?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/1663430681042917567/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/07/gnome3-e17gnomexfcefluxbox-component.html#comment-form' title='12 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1663430681042917567'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1663430681042917567'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/07/gnome3-e17gnomexfcefluxbox-component.html' title='不想用傻逼 GNOME3 ！好牛逼的雜牌軍替代方案 E17+GNOME/XFCE/Fluxbox Component！'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-qUZQc92fmGE/ThuZPU1gF1I/AAAAAAAAA5w/WeFaOWIBCvc/s72-c/Screenshot.png' height='72' width='72'/><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-5637638640248944215</id><published>2011-07-09T11:26:00.002+08:00</published><updated>2011-07-09T12:54:59.923+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><title type='text'>『假新鮮人』獻給『真新鮮人』的話</title><content type='html'>畢業潮近了，學校又將放出一大群新鮮的人才，而每年這個時候，我總會有許多感觸。過去，是看著年紀相仿的朋友投履歷找工作，近距離觀察新鮮人準備進入職場；現在，則是看著後輩跌跌撞撞，撞出許多可歌可泣的新鮮事。&lt;br /&gt;&lt;br /&gt;一切都很新鮮，我們年少時對未來都有憧憬，畢業後準備進入職場，更是抱有許多夢想。有人想努力內求更上一層樓，有人想賺錢獨立，各有各的目標和想法，人生方向就因此不同。這些美麗的夢，就像小學生寫作文題目『我的座右銘』，開學時人人都可以把自我期許講得頭頭是道，但每當學期末拿模範生或各種獎項的人數來看，便知道起而行的人寥寥可數。&lt;br /&gt;&lt;br /&gt;以年紀來說，我應該算是社會大學的新生，但因為在學時就已經開啟了接案生涯，對社會種種並不陌生，所以嚴格說起，我是『假新鮮人』。這些社會經歷，雖微不足道，卻也讓我開了一些眼界。因此這篇文章，其實是獻給過去十幾歲的自己，也是算一種反省式的認罪，更是對生涯的交代。&lt;br /&gt;&lt;br /&gt;我承認，當年。&lt;br /&gt;&lt;ol&gt;&lt;li&gt;許多案子總讓我提不起興趣，做起來總拖泥帶水。&lt;/li&gt;&lt;li&gt;能夠最後一天做完，我絕不會提前兩天開始做。&lt;/li&gt;&lt;li&gt;一旦工作做不完，最好不要讓我抓到別人的把柄，因為我將有藉口全身而退。&lt;/li&gt;&lt;li&gt;累一天，就好像累一個星期。&lt;/li&gt;&lt;li&gt;別人會如何我不在乎，我在乎的是自己的信用和利益。&lt;/li&gt;&lt;li&gt;因為你們講的問題或臭蟲我都看不到，所以我給的成果完全沒問題。&lt;/li&gt;&lt;li&gt;心裡總是想：『上頭賺很多在口袋裡，應該分我吧。』&lt;/li&gt;&lt;li&gt;管你再急，只要我現在情緒不好，我就不鳥你。&lt;/li&gt;&lt;li&gt;我做到這樣就夠了，反正我東西交了差已經丟了出去，剩下是你們家的事。&lt;/li&gt;&lt;li&gt;不管我做對做錯或做得好不好，只要有做就沒有對不起任何人。&lt;/li&gt;&lt;li&gt;網路神通廣大，讓我得到一堆人云亦云的知識，所以總是任意亂入別人的話題講些人云亦云的假知識。 &lt;/li&gt;&lt;li&gt;我不管其他人說什麼，我認為該這樣做就這樣做，哪怕造成別人的困擾。&lt;/li&gt;&lt;li&gt;只要老闆沒發現，就算我在混，時間也算是賣給老闆。&lt;/li&gt;&lt;li&gt;如果有事情會需要讓我在私人時間做，那就一定是老闆的問題。&lt;/li&gt;&lt;li&gt;總覺得自己做的事最關鍵也最重要，所以自己做一件事抵別人做十件。&lt;/li&gt;&lt;li&gt;我只要做完了事，不管過程或結果有沒有造成別人不便或損失，都不是我的責任，所以賠錢也不干我的事。但是，給我的錢是萬萬不能少。&lt;/li&gt;&lt;/ol&gt;同時，我總有藉口和說詞。&lt;br /&gt;&lt;ol&gt;&lt;li&gt;無論工作有多少，只要不想做就說：『是你們沒評估好我的能力，工作太多或太難，所以我達不成。』&lt;/li&gt;&lt;li&gt;『因為我東西有在最後一刻給了出來，所以 Project 有任何延誤也不干我的事。』&lt;/li&gt;&lt;li&gt;『我已經很努力做了，請不要再亂給我壓力。我需要有休息時間。』&lt;/li&gt;&lt;li&gt;『我拿的錢又不多，這不是我的責任。』&lt;/li&gt;&lt;li&gt;碰到質疑時第一時間不論內容先回：『這不是我的問題，是 OOXX 的問題。』&lt;/li&gt;&lt;li&gt;工作效率差時：『機器太慢，不是我的問題。』&lt;/li&gt;&lt;li&gt;『這東西太無聊，我不想做。』&lt;/li&gt;&lt;li&gt;總是抱怨：『上面都給我一些沒意義的工作，又學不到東西，浪費我時間。』&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;以上是許多年前的我，問題比較多，但在遭逢各種遽變後，開始時時刻刻提醒自己，不要再犯。在此，也向當時與我共事的人說聲抱歉，並請原諒我的不成熟。&lt;br /&gt;&lt;br /&gt;反觀現在的新鮮人，沒自信的人就不用說了，自然是維維諾諾。若是有些才能，普遍性有我當年同樣的不少惡習。另外，這些年下來，私下觀察其他人後，也發現額外的一些問題不在上列，在這就不討論了。&lt;br /&gt;&lt;br /&gt;這次畢業潮，期望『真新鮮人』們一同努力，避免不良惡習，共勉之。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-5637638640248944215?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/5637638640248944215/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/07/blog-post.html#comment-form' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5637638640248944215'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5637638640248944215'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/07/blog-post.html' title='『假新鮮人』獻給『真新鮮人』的話'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-2335762796038502650</id><published>2011-04-26T04:22:00.002+08:00</published><updated>2011-04-26T04:26:12.910+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><title type='text'>不要小看華人呀，Android App 的逆向工程！</title><content type='html'>還記得在某次的 COSCUP 與 Google 的龐教授，交流了一些 Android 方面的意見。由於他專精於 Compiler，我們也對 Dalvik Virtual Machine 的部份有些許的討論。當時感到非常榮幸，也覺得驕傲，因為這樣發光於全球的 Project&amp;nbsp;，也有華人在其中，更難得的是就在眼前。&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;最近空閒時間在研究一些 Android 的實作，煩腦之際，於 Google Code 發現了一個對岸朋友針對 apk 的逆向工程研究，有對 Dalvik VM 做了一系列的研究和說明，並開發了一支 apk 反組譯工具&amp;nbsp;[&lt;a href="http://code.google.com/p/dex2jar"&gt;dex2jar&lt;/a&gt;]。如其名，該工具能將 DEX（Android apk 的格式）還原成 Java class 檔案，但更有趣的是，反向工程後的結果，不單只是 Binary 或 Bytecode，而是有『相當完整』的&amp;nbsp;Java 原始程式碼。&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;此外，在該 Project 的 Wiki 上，作者用『中文』記載了 [dex2jar] 的設計細節和反向工程所遭遇的問題，並寫了相應的解決手段，對技術有興趣的人可以去看看。 :-P&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;後記&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;如同該 Project 首頁所標註，還是請玩家在把玩這支程式時要『遵循 Google 相關協議與相關法律法規』。&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-2335762796038502650?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/2335762796038502650/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/04/android-app.html#comment-form' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2335762796038502650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2335762796038502650'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/04/android-app.html' title='不要小看華人呀，Android App 的逆向工程！'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-1534591961125602974</id><published>2011-04-17T19:35:00.006+08:00</published><updated>2011-04-18T02:09:35.588+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hacking 心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><title type='text'>Python之我見</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.python.org/images/python-logo.gif" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://www.python.org/images/python-logo.gif" /&gt;&lt;/a&gt;&lt;/div&gt;對一個『慣C』人來說，[&lt;a href="http://www.python.org/"&gt;Python&lt;/a&gt;] 實在是讓人無法去接受的程式語言，無論是效能、速度還是所吃的系統資源，都讓人不滿意。但以一個類 Script 語言來看待它，又是個極度強大又好用的東西，開發時程也比其他傳統語言短相當多，開發完成之後，也有相當大的再擴展和加速的空間。所以，若是開發出來的東西，沒有絕對強烈的『即時』和『精巧』需求，用純 Python 來寫，會相當合理。&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;應用需求導向&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;若您是熟悉 Windows 的開發者，可將 Python 視為 [&lt;a href="http://zh.wikipedia.org/wiki/Visual_Basic"&gt;Visual Basic&lt;/a&gt;]，是一個著重於『立即應用』的存在（當然在本質上不相同，後者相對簡陋且更著重於【可視化程式設計】）。他們最相似之處就是開發模式，因為長久下來，已經有太多人為 Python 寫出無數的模組、功能，以致開發者只需要懂得引入和使用這些模組，就能達成所有能想到的功能，這點與 Visual Basic 的『控制項』開發模式沒什麼不同。&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;在今天，由於太多人的貢獻成果，使 Python 開發者幾乎無所不能，再者，其已經跨足了許多平台。對開發者而言，同一支程式，只要注意引入模組是否能跨平台（大多數功能多半都有解決方案），就能輕易寫出能運行於不同平台上的應用軟體，稱之跨平台的 Visual Basic 可不為過。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;但如同許多前端網頁開發者隨處濫用 JavaScript + HTML，濫用 Python 的人也有不少。由於 Python 過於易用，許多人在開發上只求達成功能，忘了效率的考量（這觸動了『慣C』人最大的忌諱），過去一些比較著名的例子就是： emesene（Linux 上常見的 MSN 軟體） 和 iBus（輸入法系統架構），速度慢或吃光系統資源還不打緊，甚至是造成系統鎖死當機的狀況。&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;獨特的語言特性&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;說到 Python 語言本身，它有極為結構化的設計，又支援各種先進的開發模式，物件導向等技術當然不會少，以致使用 Python 來開發大型專案是非常可行的。若要舉個實例，大概就是 Google 的各項網路服務。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Python 擁有獨特的語言規則，像是捨棄『{};』等包裝語法，並強迫對齊等設計。這使得開發者不得不簡化和編排自己的程式，不能再寫出長又難以維護的程式碼。當然，這會讓已經習慣傳統語言規則的開發者，會有困擾和不習慣，需要一些時間適應。不過，一旦接受了 Python 的設計習慣，便可輕易的使用。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;適用範圍&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;很明顯，Python 相當適用於網站程式上，其高階的包裝，開發時程的優勢，甚至功能性，都讓他方便實作任何 Web 服務。由於 Web 並不需要『即時反應』和『長時間待命』的需求，更不怕缺少在壓力下效能考量的不良設計。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;當然，一般功能性導向的應用軟體也是適合使用 Python 來開發，除了開發時程短之外，也能很容易做出想要的各種功能，日後的維護也非常簡單。唯一要注意的是，要時時考慮 Python 的效能問題，不然設計出來的程式，會經不起長時間考驗。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;雖然 Python 語言看似高階，但 Redhat Linux&amp;nbsp;作業系統從早期開始的圖形化安裝程式，就是用 Python 所撰寫，不難看出它也能勝任系統應用程式的工作。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;如同 Virtual Basic（疑？） 的缺點&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;當然，沒有一樣東西是百分之百完美，Python 大體上和 Visual Basic 有一樣的缺點，如記憶體的消耗、執行效能不如原生的程式快速，雖然可以透過各種手段得到改進，但那已經跳脫出純 Python 開發的範疇。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;如同有人嘲諷 Visual Basic 一般，Python 的使用者若沒有真正低階的開發經驗，也會寫出令人哭笑不得的程式，若遭遇效能問題，其瓶頸將很難獲得解決。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;整體評估是優良的&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;對於需要快速開發的專案和人力不夠充裕的團隊，Python 是很好的選擇，一種語言便可從系統層寫到 Web 和雲端，非常值得花點時間學習。但最好要搭配 C 語言的相關訓練，在必要時可當成許多效能和相關問題的解決手段。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;如果是程式初學者，也推薦選用 Python&amp;nbsp;踏入程式開發之路。&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-1534591961125602974?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/1534591961125602974/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/04/python.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1534591961125602974'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1534591961125602974'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/04/python.html' title='Python之我見'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-6690904601837045284</id><published>2011-03-28T14:09:00.001+08:00</published><updated>2011-03-28T14:10:22.665+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Chewing'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Debian'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='ibus'/><category scheme='http://www.blogger.com/atom/ns#' term='心得分享、講座'/><category scheme='http://www.blogger.com/atom/ns#' term='patch'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>ibus-chewing 單純注音模式 - OSDC.tw 2011 Lightening Talk</title><content type='html'>為了注音輸入法，您是否長久以來也仍在使用 SCIM？每次裝好 Linux 的第一件事就是刪除系統預設輸入法，我們彷彿是外星人一般，一點都沒享有人權。感謝 OSDC.tw 2011（活動期間 3/26 ~ 3/27） 提供好吃的食物和舒適的場地，在活動這兩天筆者花了一點功夫做 patch，修掉了 ibus-chewing 單純注音模式的一些 Bugs，現在基本上 ibus-chewing 單純注音模式已經可用，我們可以丟掉 SCIM + 爛注音 Table 了！&lt;br /&gt;&lt;br /&gt;以下是 Lightening Talk 的簡報檔：&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;object height="344" width="425"&gt;&lt;param name="movie" value="http://www.youtube.com/v/M8cppExxQGQ?hl=zh&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/M8cppExxQGQ?hl=zh&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;由於簡報格式的關係，暫時無法轉成 PDF 輸入，所以目前使用錄影的方式公開，待轉檔程式開發完成再來釋出 PDF 檔。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-6690904601837045284?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/6690904601837045284/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/03/ibus-chewing-osdctw-2011-lightening.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6690904601837045284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6690904601837045284'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/03/ibus-chewing-osdctw-2011-lightening.html' title='ibus-chewing 單純注音模式 - OSDC.tw 2011 Lightening Talk'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-9131289395423831021</id><published>2011-03-18T02:00:00.002+08:00</published><updated>2011-03-18T02:10:40.702+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='作業系統實作'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>Linux Kernel Sendfile() 的提升 Server 效能之路</title><content type='html'>Apache 和 Samba 這類伺服器，主要以傳送檔案資料的工作為主，他們最常做的工作不外乎是開啟檔案(Open)、讀取(Read)、寫入網路連線(Write to Socket)。但是以 Kernel 的角度來說，這樣一個讀取檔案資料和傳送出去的流程相當繁複，並擁有最少兩次的 Kernel/User Space 資料搬移， 導致同一筆資料需要經過兩次多餘的複製。舉例來說，若一個檔案有 1MB，則 Linux Kernel 需要多做 2MB 的記憶體複製，使得效能經常消耗在這種地方，尤以 CPU 不夠快的平台上狀況特別明顯。&lt;br /&gt;&lt;br /&gt;而過去曾有 khttpd 這樣的實作，讓 Linux Kernel 自成一個小型的 Web Server，提供一個極有效率方式的讀取靜態網站頁面和 Server 服務，其加速的方法，便是於 Kernel Space 讀取檔案並直接從網路連線送出資料，目的也在於減少 Kernel/User space 之間不必要的 context switch。&lt;br /&gt;&lt;br /&gt;想瞭解 User Space 和 Kernel 的資料搬移狀況，我們可以來研究應用程式在讀取和傳送網路資料的流程，經簡化後大致上是（以下簡稱 User Space 為 US，Kernel Space 為 KS）： &lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;[US] open()&lt;/b&gt;&lt;/li&gt;&lt;li&gt;[KS] do_sys_open()&lt;/li&gt;&lt;li&gt;[KS] do_filp_open() - 找到檔案，並從所在的檔案系統取得 struct file&lt;/li&gt;&lt;li&gt;[KS] Return File Object&lt;/li&gt;&lt;li&gt;&lt;b&gt;[US] malloc() - 準備一塊記憶體當 buffer&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;[US] read(file, buffer)&lt;/b&gt;&lt;/li&gt;&lt;li&gt;[KS] vfs_read(file) - 標準 VFS 的檔案讀取 API&lt;/li&gt;&lt;li&gt;[KS] file-&amp;gt;f_op-&amp;gt;read() - 使用資料所在的檔案系統(filesystem)，其提供的低階 read 操作&lt;/li&gt;&lt;li&gt;[KS] copy_to_user(buffer) - 將檔案資料從硬碟讀出來後，複製一份到 user space 的 buffer&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;接著是將讀到的資料透過網路傳送出去：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;[US] write(Socket, buffer)&lt;/b&gt; - 將 buffer 內資料傳送出去&lt;br /&gt;&lt;/li&gt;&lt;li&gt;[KS] copy_from_user(buffer) - 將 user space 的 buffer 複製回 kernel space&lt;br /&gt;&lt;/li&gt;&lt;li&gt;[kS] Send data - 送出資資料&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;通常，我們不可能學 khttpd，將 Server 都寫進 Kernel，但如果只是單純讀取並將資料透過網路傳送出去，Kernel 提供了 sendfile()  system call，這是一種可行的手段以減少資料搬移，除 Linux 之外，其他作業系統也都有提供此 API。我們只要指定 socket file description 和將要送出去的檔案給 sendfile()，它便會幫我們在 Kernel Space 將檔案從硬碟讀取複製出來，不再經過任何多餘 Kernel/User Space copy，直接從 Socket 送出。&lt;br /&gt;&lt;br /&gt;sendfile() 在 Linux Kernel 內的運作流程大致上為：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;sendfile()&lt;/li&gt;&lt;li&gt;do_sendfile()&lt;/li&gt;&lt;li&gt;do_splice_direct()&lt;/li&gt;&lt;li&gt;file-&amp;gt;f_open-&amp;gt;file_splice_read()&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;有撰寫過 Filesystem Driver 應該都知道，file_splice_read() 是為了提供管線(Pipe)而存在的機制，使資料可以在管線中傳送（這部份因超過本文範疇，在此暫不多做討論）。而 sendfile() 的實作便利用了 pipe 機制，使檔案的資料能流入 Socket 的檔案中，不用做多餘的複製。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;這次為了某個案子，寫了一支 Filesystem Driver，而該 Filesystem 會被 Samba 存取。實際測試過程中，發現相較於其他常見的  Filesystem(如：FAT)，我們的 Filesystem 讀取速度慢了約 27% 左右，後來才發現是 Samba 採用 sendfile()，但我們的 filesystem並未實作 file_splice_read() ，所以都使用一般的方式讀取檔案。補上相關實作後，速度就提升到與其他 filesystem 一樣了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-9131289395423831021?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/9131289395423831021/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/03/linux-kernel-sendfile-server.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/9131289395423831021'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/9131289395423831021'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/03/linux-kernel-sendfile-server.html' title='Linux Kernel Sendfile() 的提升 Server 效能之路'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-5176322726715132582</id><published>2011-03-05T17:00:00.004+08:00</published><updated>2011-03-05T17:03:50.814+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux硬體驅動'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>在 Linux Kernel 中取得目錄中的檔案清單</title><content type='html'>寫一支程式在 User Space 下列出目錄中的檔案清單相當容易，我們可以用 readdir() 去一項項取得檔案內容，事實上， readdir() 是由 Linux Kernel VFS(Virtual Filesystem) 所提供的 API，真正的實作在檔案系統的核心模組(Kernel Module)中。然而因為 Kernel readdir() 的相關實作牽涉到 Kernel/User space 的資料交換問題，所以如果我們是在撰寫 Kernel 的驅動程式，當然就不能使用這系列的 APIs。不過也因為所有的資訊都存在於 Kernel 的資料結構中，我們可以直接從記憶體中的 Linked list 中快速取得檔案清單。&lt;br /&gt;&lt;br /&gt;在取得某個目錄下所有檔案資訊前，要先得到該目錄的敘述 struct dentry，VFS 用 struct dentry 的串聯組合來描述整個檔案系統的目錄結構，檔案清單則被保存在 dentry 中的 Double Linked List，因此其實只要知道如何使用 Kernel 提供的 Double Linked list，就能得到該目錄下所有的檔案資訊。而這邊要注意的是 Kernel 提供的一個通用 Linked list 結構（struct list_head），用來統一整個核心的 Linked list 操作機制，這檔案清單的 Double Linked List 就是使用這通用的結構。&lt;br /&gt;&lt;br /&gt;這裡是 Linux Kernel 2.6.37 中 dentry 的資料結構（定義在 linux/dcache.h，其中較不重要的部份以『...』做省略，此外，某些定義與較早版本的 Kernel 有所差異，將在文章最後補上說明）：&lt;div&gt;&lt;pre&gt;struct dentry {&lt;br /&gt;...省略&lt;br /&gt;    struct hlist_node d_hash;   /* lookup hash list */&lt;br /&gt;    struct dentry *d_parent;    /* parent directory */&lt;br /&gt;    struct qstr d_name;&lt;br /&gt;&lt;br /&gt;    struct list_head d_lru;     /* LRU list */&lt;br /&gt;    /*&lt;br /&gt;     * d_child and d_rcu can share memory&lt;br /&gt;     */&lt;br /&gt;    union {&lt;br /&gt;        struct list_head d_child;   /* child of parent list */&lt;br /&gt;        struct rcu_head d_rcu;&lt;br /&gt;    } d_u;&lt;br /&gt;    struct list_head d_subdirs; /* our children */&lt;br /&gt;    struct list_head d_alias;   /* inode alias list */&lt;br /&gt;...省略&lt;br /&gt;};&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;由 struct dentry 可以發現，利用讀取 d_u.d_child 這個 Linked List 就可以取得底下所有的檔案資訊。實際做法可以參考範例程式碼，此程式會列出某個目錄下所有的檔案名稱：&lt;div&gt;&lt;pre&gt;struct list_head *next;&lt;br /&gt;    struct dentry *child_dentry;&lt;br /&gt;    list_for_each(next, &amp;file-&gt;f_path.dentry-&gt;d_u.d_child) {&lt;br /&gt;        child_dentry = (struct dentry *)list_entry(next, struct dentry, d_u.d_child);&lt;br /&gt;        printk("%s\n", child_dentry-&gt;d_name.name);&lt;br /&gt;    }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;於 dentry 裡保存檔案名稱的資料結構是 struct qst，其定義如下（定義與較早版本的 Kernel 有所差異，將在文章最後補上說明）：&lt;div&gt;&lt;pre&gt;struct qstr {&lt;br /&gt;    unsigned int hash;&lt;br /&gt;    unsigned int len;&lt;br /&gt;    const unsigned char *name;&lt;br /&gt;};&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;更多操作 struct list_head 請參考相關的書籍或網路文件，這部份很重要，因為在 Kernel 處處都會發現 struct list_head 的蹤影。&lt;br /&gt;&lt;br /&gt;在較早的 Linux Kernel 版本中 dentry 的 d_child 並未使用 union d_u，是這樣被定義的（網路上找到的版本也多半是這樣）：&lt;div&gt;&lt;pre&gt;struct dentry {&lt;br /&gt;...省略&lt;br /&gt;　　struct dentry * d_parent;&lt;br /&gt;　　struct list_head d_hash;&lt;br /&gt;　　struct list_head d_lru;&lt;br /&gt;　　struct list_head d_child;&lt;br /&gt;　　struct list_head d_subdirs;&lt;br /&gt;...省略&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;而早期的 struct qstr 是這樣定義：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;struct qstr {&lt;br /&gt; const unsigned char * name;&lt;br /&gt; unsigned int len;&lt;br /&gt; unsigned int hash;&lt;br /&gt; char name_str[0];&lt;br /&gt;};&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;由於 Kernel 版本數量太多，且定義會不斷被改變，若在實際撰寫時請參考 Linux 核心程式原始碼的『 include/linux/dcache.h』。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-5176322726715132582?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/5176322726715132582/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/03/linux-kernel.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5176322726715132582'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5176322726715132582'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/03/linux-kernel.html' title='在 Linux Kernel 中取得目錄中的檔案清單'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-3626090179577059561</id><published>2011-02-18T14:59:00.002+08:00</published><updated>2011-02-26T15:40:58.872+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><title type='text'>我想做什麼？What Do I Really Want to Do?</title><content type='html'>近來，承蒙一些事業天使（Business Angel）關愛，極為客氣且專程邀我交流意見，長輩們不因我是個年輕小夥子，可能存在著年紀上的宏溝，而難以互相溝通，反之相談甚歡。但研究未來趨勢，研究目前機會，進而相互觸發的火花，卻比不上過程中簡單又普通的一個問句，其當頭棒喝讓我這些日子來不斷自我問之。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;你想做什麼？&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;就是這短短五個字，令我當下訝然失聲，換來多天無法平靜，連睡夢中也在試圖尋一條明確的出路，直到驚醒。&lt;br /&gt;&lt;br /&gt;經這麼多年時日蹧蹋，倒也不是心中無腹案，無法當場說得天花亂墜，而是發自內心回應這五個字的，是一個大藍圖，一個難以說明完整的藍圖。確確實實，我相信著心中那一齣對未來的憧景，那一套事先設計過的必經過程。現在的我，沒辦法三言兩語說明清楚，也沒辦法完整交代想成就的大事。只是因為有些事『微不足道』，有些事又大的『虛無飄渺』，而我手上只有一張地圖，貫串頭尾。靡靡道來，不免枯燥無味。&lt;br /&gt;&lt;br /&gt;或許不少人會嘲弄，請我多方學習演講技巧、說話技巧、表演技巧，學習將最精華的部份講到別人心崁裡。但別人感興趣的可能只是我計劃中的一小部份，那並不能代表我真心想做，試問如何能夠欺己欺人？再說，我也不是要騙人當『金主』，用不著這樣做了。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;革命事業&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;若真的要下一個總結，描述我想要做的事，那我會說：『革命，革我自己的命。如果要走十一步才能到目標，那我一定不會省掉第一步，也不會直接跳第十步。』&lt;br /&gt;&lt;br /&gt;這世界上有太多事不一定是走對的路，多半彎彎曲曲又碰碰撞撞邁向終點，隨著大家起舞，多半也能走到終點，只不過時間也會浪費很多，我只想少做錯事，直接往正確的路走去。但這些所謂未來必定的方向，太直接走去，過程中必定也是眾人所指，在大家眼中你不過就是不循大家規矩的革命份子。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;驚天動地的未來&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;我就是要得到驚天動地的未來，但我不會放棄眼前的現實，你們或許聽過很多突然發光的點子，但也聽過更多被風熄滅的燭火。我寧可多下苦功找遮避，點火不會為風所動。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;天使投資人&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;我並不妄想得到錢就能馬上發光，而是一直在煩腦怎麼把各種資源換成太陽，讓它永續不滅。換句話說，只要能協助我的人，就算出力不出錢，也是我的天使投資人。當然，我也不怕成為自己唯一的天使。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;人生不後悔的一次嘗試&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;我有我想走的路，無論會不會成功，其他人看不看好或能否理解我，唯一試試看的機會就是現在。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-3626090179577059561?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/3626090179577059561/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/02/what-do-i-really-want-to-do.html#comment-form' title='3 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3626090179577059561'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3626090179577059561'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/02/what-do-i-really-want-to-do.html' title='我想做什麼？What Do I Really Want to Do?'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-5357232147852529971</id><published>2011-02-16T06:28:00.000+08:00</published><updated>2011-02-16T06:28:02.804+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Embedded System'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>撰寫跨平台程式需注意的 I/O 和 Offset 問題</title><content type='html'>對於檔案操作，坊間已經有太多 Hello World 程式示範過無數次，往往運用簡單的 lseek() 、read() 和 write() 已滿足大多數需求。但在 ARM 與 x86 架構之間，便有些微妙的差異，讓 Hello World 級的範例程式處處失效。的確，很少人真的動手寫一支程式去處理大型檔案，更少人會將這類程式移植跨平台使用。&lt;br /&gt;&lt;br /&gt;若發現原本在 x86 上可正常使用 write()/pwrite() 等方式寫入資料，但交叉編譯（Cross-Compile）至 ARM 後，始終無法如預期讀寫資料，那意味著你可能掉進 offset 的陷阱了。&lt;br /&gt;&lt;br /&gt;說起來這問題牽涉到 off_t 變數形態的記憶體使用長度，並可分為三個面向探討『Kernel』、『glibc』、『應用程式(Application)』。理論上 Runtime 時，三方對檔案操作的 offset 定義應該是要一樣，但事實上不然，只有在 x86 平台上比較統一。在 ARM 等這類平台，由於各家廠商在製作 BSP 各自定義，各程式和往往預設使用上不盡相同，更主要原因是因為多數應用程式都是從 x86 移殖過來，和 ARM 平台上 32-bit 的預設處理方式會格格不入。&lt;br /&gt;&lt;br /&gt;在 x86 架構上（測試環境為 Debian Sid、 Intel Platform），通常 off_t 被定義為 unsigned long long （無號最長整數），總長度是為 8 Bytes（因長度等同 off64_t，下文將 64-bit 的 off_t 以 off64_t 稱之），在此環境下的 gcc+glibc 會自動使用 off64_t 形態做為 offset 處理參數，當然在編譯程式時也會自動使用相對應的處理函數，實作和定義可參考 unistd.h。&lt;br /&gt;&lt;br /&gt;而在 ARM 的環境上，卻不一定如此，在某些平台和 BSP 中，off_t 預設就會被定為 32-bit 長度，會造成一些可能發生的問題。&lt;br /&gt;&lt;br /&gt;一個例子，若是有寫過 FUSE(Filesystem in User Space) 程式，並移植到 ARM 的經驗，就有機會發現系統上 off_t 定義的大混亂。起因是 libfuse 使用 off64_t 與 kernel/Application 溝通，但若是系統編譯環境預設使用 off_t，我們寫的 filesystem 程式便會不正常。原因在於 lseek()、write()、pwrite() 和 pread() 系列函數只吃 off_t 而不是 off64_t，但同樣的 code ，此問題不會發生在多數 x86 系統上（因為編譯時預設是使用 off64_t 和 lseek64()、write64()、pwrite64() 和 pread64()）。&lt;br /&gt;&lt;br /&gt;解決這問題有兩種做法，一種是在編譯代入 D_FILE_OFFSET_BITS=64 或程式中定義 __USE_FILE_OFFSET64，另一種就是將所有 pwrite()/pread() 等函式強制改為 pwrite64()/pread64() 等處理 64-bit offset 的函式。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-5357232147852529971?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/5357232147852529971/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/02/io-offset.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5357232147852529971'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5357232147852529971'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/02/io-offset.html' title='撰寫跨平台程式需注意的 I/O 和 Offset 問題'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-8258632541245030367</id><published>2011-01-01T22:41:00.002+08:00</published><updated>2011-01-01T22:43:59.888+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='技術新知'/><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Mandice'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='有趣新構思'/><category scheme='http://www.blogger.com/atom/ns#' term='X11'/><category scheme='http://www.blogger.com/atom/ns#' term='User Interface'/><title type='text'>Document Slider 文件滑動閱覽器</title><content type='html'>不知不覺又過了一年，在這幾天假期花了一番功夫，便從去年與廠商合作的 Project 中，拆出了當時設計的UI並重新撰寫成一個新的文件滑動閱覽程式。在移除了和廠商相關的各個部份後，整體介面功能相當單純易用。該操作介面以滑動(Slider)和時間軸(Timeline)為主要操作概念，方便使用者瀏覽需要照時間排列的各類文件和圖檔資料，並以無限延伸的設計回朔歷史訊息，有點類似圖書館內的報紙查閱機器。&lt;br /&gt;&lt;br /&gt;&lt;p align=center&gt;&lt;object style="height: 390px; width: 640px"&gt;&lt;param name="movie" value="http://www.youtube.com/v/zCrmsoN6XnM?version=3"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/zCrmsoN6XnM?version=3" type="application/x-shockwave-flash" allowfullscreen="true" allowScriptAccess="always" width="640" height="390"&gt;&lt;/object&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-8258632541245030367?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/8258632541245030367/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2011/01/document-slider.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/8258632541245030367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/8258632541245030367'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2011/01/document-slider.html' title='Document Slider 文件滑動閱覽器'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-4794739261256642044</id><published>2010-12-17T21:31:00.000+08:00</published><updated>2010-12-17T21:31:45.679+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><title type='text'>Linux 下程序的記憶體映射</title><content type='html'>Linux 下的執行檔為 ELF 格式，其啟動原理與各作業系統上的執行檔一樣，不外乎是載入檔案到記憶體上，並讀取需要的 Shared library link 清單，最後找到於 Filesystem 上對應的 symbol link 和 library，載入外部函式和執行程式。&lt;br /&gt;&lt;br /&gt;這邊以 VIM 為例，我們透過 Linux 下的 ldd 指令可以得知執行檔需要的外部 Libraries：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;$ ldd /usr/bin/vim&lt;br /&gt; linux-gate.so.1 =&amp;gt;  (0xb7837000)&lt;br /&gt; libm.so.6 =&amp;gt; /lib/i686/cmov/libm.so.6 (0xb77f2000)&lt;br /&gt; libncurses.so.5 =&amp;gt; /lib/libncurses.so.5 (0xb77b8000)&lt;br /&gt; libselinux.so.1 =&amp;gt; /lib/libselinux.so.1 (0xb779c000)&lt;br /&gt; libacl.so.1 =&amp;gt; /lib/libacl.so.1 (0xb7795000)&lt;br /&gt; libgpm.so.2 =&amp;gt; /usr/lib/libgpm.so.2 (0xb778f000)&lt;br /&gt; libc.so.6 =&amp;gt; /lib/i686/cmov/libc.so.6 (0xb7649000)&lt;br /&gt; libdl.so.2 =&amp;gt; /lib/i686/cmov/libdl.so.2 (0xb7645000)&lt;br /&gt; /lib/ld-linux.so.2 (0xb7838000)&lt;br /&gt; libattr.so.1 =&amp;gt; /lib/libattr.so.1 (0xb763f000)&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;由以上結果可以看到 VIM 所需的 library，以及在 filesystem 上找到的對應 library ，然後還可以得到當 library 被載入到記憶體上時的起始位置。其中比較特別的是 linux-gate.so.1，實體並不存在於 filesystem 中，這代表 kernel system call 的記憶體映射和其位址。&lt;br /&gt;&lt;br /&gt;Kernel 其實有 Interface 提供我們取得更多 Process 的記憶體映射資料，藉由讀取 /proc/[Process ID]/maps 這檔案，我們除了可以得到 Process 連結的 library，還可以得到映射的範圍和使用權限等訊息，。&lt;br /&gt;&lt;br /&gt;下面這例子是觀察正在執行的 VIM（PID=17605）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;$ cat /proc/17605/maps &lt;br /&gt;08048000-081c0000 r-xp 00000000 08:05 7029211    /usr/bin/vim.basic&lt;br /&gt;081c0000-081ce000 rw-p 00178000 08:05 7029211    /usr/bin/vim.basic&lt;br /&gt;081ce000-081d8000 rw-p 00000000 00:00 0 &lt;br /&gt;089df000-08b30000 rw-p 00000000 00:00 0          [heap]&lt;br /&gt;b739a000-b73a4000 r-xp 00000000 08:05 4202534    /lib/i686/cmov/libnss_files-2.11.2.so&lt;br /&gt;b73a4000-b73a5000 r--p 00009000 08:05 4202534    /lib/i686/cmov/libnss_files-2.11.2.so&lt;br /&gt;b73a5000-b73a6000 rw-p 0000a000 08:05 4202534    /lib/i686/cmov/libnss_files-2.11.2.so&lt;br /&gt;b73a6000-b73b9000 r-xp 00000000 08:05 4202536    /lib/i686/cmov/libnsl-2.11.2.so&lt;br /&gt;b73b9000-b73ba000 r--p 00012000 08:05 4202536    /lib/i686/cmov/libnsl-2.11.2.so&lt;br /&gt;b73ba000-b73bb000 rw-p 00013000 08:05 4202536    /lib/i686/cmov/libnsl-2.11.2.so&lt;br /&gt;b73bb000-b73bd000 rw-p 00000000 00:00 0 &lt;br /&gt;b73da000-b73f7000 r--p 00000000 08:05 7074661    /usr/share/vim/vim73/lang/zh_TW.UTF-8/LC_MESSAGES/vim.mo&lt;br /&gt;b73f7000-b756d000 r--p 00000000 08:05 7045410    /usr/lib/locale/locale-archive&lt;br /&gt;b756d000-b756e000 rw-p 00000000 00:00 0 &lt;br /&gt;b756e000-b7572000 r-xp 00000000 08:05 4194576    /lib/libattr.so.1.1.0&lt;br /&gt;b7572000-b7573000 rw-p 00003000 08:05 4194576    /lib/libattr.so.1.1.0&lt;br /&gt;b7573000-b7574000 rw-p 00000000 00:00 0 &lt;br /&gt;b7574000-b7576000 r-xp 00000000 08:05 4202526    /lib/i686/cmov/libdl-2.11.2.so&lt;br /&gt;b7576000-b7577000 r--p 00001000 08:05 4202526    /lib/i686/cmov/libdl-2.11.2.so&lt;br /&gt;b7577000-b7578000 rw-p 00002000 08:05 4202526    /lib/i686/cmov/libdl-2.11.2.so&lt;br /&gt;b7578000-b76b8000 r-xp 00000000 08:05 4202537    /lib/i686/cmov/libc-2.11.2.so&lt;br /&gt;b76b8000-b76ba000 r--p 0013f000 08:05 4202537    /lib/i686/cmov/libc-2.11.2.so&lt;br /&gt;b76ba000-b76bb000 rw-p 00141000 08:05 4202537    /lib/i686/cmov/libc-2.11.2.so&lt;br /&gt;b76bb000-b76be000 rw-p 00000000 00:00 0 &lt;br /&gt;b76be000-b76c3000 r-xp 00000000 08:05 11665845   /usr/lib/libgpm.so.2.0.0&lt;br /&gt;b76c3000-b76c4000 rw-p 00004000 08:05 11665845   /usr/lib/libgpm.so.2.0.0&lt;br /&gt;b76c4000-b76ca000 r-xp 00000000 08:05 4194402    /lib/libacl.so.1.1.0&lt;br /&gt;b76ca000-b76cb000 rw-p 00006000 08:05 4194402    /lib/libacl.so.1.1.0&lt;br /&gt;b76cb000-b76e4000 r-xp 00000000 08:05 4194310    /lib/libselinux.so.1&lt;br /&gt;b76e4000-b76e5000 r--p 00018000 08:05 4194310    /lib/libselinux.so.1&lt;br /&gt;b76e5000-b76e6000 rw-p 00019000 08:05 4194310    /lib/libselinux.so.1&lt;br /&gt;b76e6000-b76e7000 rw-p 00000000 00:00 0 &lt;br /&gt;b76e7000-b771e000 r-xp 00000000 08:05 4194642    /lib/libncurses.so.5.7&lt;br /&gt;b771e000-b7721000 rw-p 00036000 08:05 4194642    /lib/libncurses.so.5.7&lt;br /&gt;b7721000-b7745000 r-xp 00000000 08:05 4202516    /lib/i686/cmov/libm-2.11.2.so&lt;br /&gt;b7745000-b7746000 r--p 00023000 08:05 4202516    /lib/i686/cmov/libm-2.11.2.so&lt;br /&gt;b7746000-b7747000 rw-p 00024000 08:05 4202516    /lib/i686/cmov/libm-2.11.2.so&lt;br /&gt;b774a000-b7752000 r-xp 00000000 08:05 4202519    /lib/i686/cmov/libnss_nis-2.11.2.so&lt;br /&gt;b7752000-b7753000 r--p 00008000 08:05 4202519    /lib/i686/cmov/libnss_nis-2.11.2.so&lt;br /&gt;b7753000-b7754000 rw-p 00009000 08:05 4202519    /lib/i686/cmov/libnss_nis-2.11.2.so&lt;br /&gt;b7754000-b775a000 r-xp 00000000 08:05 4202515    /lib/i686/cmov/libnss_compat-2.11.2.so&lt;br /&gt;b775a000-b775b000 r--p 00006000 08:05 4202515    /lib/i686/cmov/libnss_compat-2.11.2.so&lt;br /&gt;b775b000-b775c000 rw-p 00007000 08:05 4202515    /lib/i686/cmov/libnss_compat-2.11.2.so&lt;br /&gt;b775c000-b7763000 r--s 00000000 08:05 1799068    /usr/lib/gconv/gconv-modules.cache&lt;br /&gt;b7763000-b7764000 r--p 00175000 08:05 7045410    /usr/lib/locale/locale-archive&lt;br /&gt;b7764000-b7766000 rw-p 00000000 00:00 0 &lt;br /&gt;b7766000-b7767000 r-xp 00000000 00:00 0          [vdso]&lt;br /&gt;b7767000-b7782000 r-xp 00000000 08:05 4194720    /lib/ld-2.11.2.so&lt;br /&gt;b7782000-b7783000 r--p 0001a000 08:05 4194720    /lib/ld-2.11.2.so&lt;br /&gt;b7783000-b7784000 rw-p 0001b000 08:05 4194720    /lib/ld-2.11.2.so&lt;br /&gt;bff9b000-bffb0000 rw-p 00000000 00:00 0          [stack]&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;這些看似複雜且嚇人的訊息，每個欄位已清楚描述著此 process 的記憶體映射和對應的實體檔案，由於數量太多，我們暫且抽出 VIM 本身的映射訊息做說明：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;08048000-081c0000 r-xp 00000000 08:05 7029211    /usr/bin/vim.basic&lt;br /&gt;081c0000-081ce000 rw-p 00178000 08:05 7029211    /usr/bin/vim.basic&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;『08048000-081c0000』和『081c0000-081ce000』代表程式在記憶體上的起始點和終點，『r-xp』和『rw-p』是存取權限，『00000000』和『00178000』是映射記憶體位址在實體檔案中的偏移量，『08:05』分別代表的是 major 和 minor device number，而『7029211』是 device node number，最後一欄則為記憶體所對應的實體檔案。&lt;br /&gt;&lt;br /&gt;此外，在範例中我們看到了幾乎每個程式和 library 都映射了兩個以上的區塊，這意味著第一段是 code segment，而第二，第三段映射是 data segment (data + bss + heap)。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;更多的驗證可以閱讀[&lt;a href="http://www.lisha.ufsc.br/teaching/os/exercise/hello.html"&gt;The True Story of Hello World&lt;/a&gt;] 一文，作者透過簡單的 Hello World 程式驗證 segment 和 memory mapping 的觀念，值得參考。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-4794739261256642044?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/4794739261256642044/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/12/linux.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/4794739261256642044'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/4794739261256642044'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/12/linux.html' title='Linux 下程序的記憶體映射'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-6740455092527024156</id><published>2010-12-12T14:26:00.005+08:00</published><updated>2010-12-12T14:34:30.538+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='X11'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>寫支 C 程式用 XRandr Extension 設定你的螢幕解析度</title><content type='html'>在 X11 下取得螢幕顯示大小，最快的方式就是得到當前的 Screen&amp;nbsp;，然後用 DisplayWidth() 和 DisplayHeight() 得到寬高，如果是在高階的圖形介面架構下開發應用程式，如：GTK+，也有相關的 API 可以取得 display 的大小。然而，要是我們想取得更多關於螢幕和顯示晶片所支援的模式，便要引入 XRandr Extension 來達成。&lt;br /&gt;&lt;br /&gt;若不了解 XRandr 是什麼，可以開啟終端機(Terminal)程式，接著輸入 xrandr 指令，就會看到顯示器的相關訊息，除了可以得到有幾種螢幕可以用，還分別可以看到支援的模式（解析度和掃描頻率），以下是在筆者 X200t （有外接一台支援 1920x1080 的 24" 顯示器）上執行的結果：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;$ xrandr&lt;br /&gt;Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 8192 x 8192&lt;br /&gt;VGA1 connected 1920x1080+0+0 (normal left inverted right x axis y axis) 531mm x 299mm&lt;br /&gt;   1920x1080      60.0*+   60.0     60.0  &lt;br /&gt;   1440x900       59.9  &lt;br /&gt;   1280x800       59.8  &lt;br /&gt;   1152x864       75.0  &lt;br /&gt;   1024x768       70.1     60.0  &lt;br /&gt;   800x600        60.3     56.2  &lt;br /&gt;   640x480        66.7     60.0  &lt;br /&gt;   720x400        70.1  &lt;br /&gt;LVDS1 connected (normal left inverted right x axis y axis)&lt;br /&gt;   1280x800       60.0 +&lt;br /&gt;   1024x768       60.0  &lt;br /&gt;   800x600        60.3     56.2  &lt;br /&gt;   640x480        59.9  &lt;br /&gt;HDMI1 disconnected (normal left inverted right x axis y axis)&lt;br /&gt;DP1 disconnected (normal left inverted right x axis y axis)&lt;br /&gt;HDMI2 disconnected (normal left inverted right x axis y axis)&lt;br /&gt;DP2 disconnected (normal left inverted right x axis y axis)&lt;br /&gt;DP3 disconnected (normal left inverted right x axis y axis)&lt;/pre&gt;&lt;/div&gt;註：Xrandr 除了得到關於當前顯示器的設定之外，也可以設定現在的模式，更多功能可以參考『xrandr --help』的說明。&lt;br /&gt;&lt;br /&gt;當然，XRandr Extension 還支援旋轉畫面、多螢幕顯示等控制，不過不在本文討論範疇。這裡，我們要用 C 語言先來實作一支程式，用 XRandr API 得到目前解析度以及列出顯示器支援的所有模式。&lt;br /&gt;&lt;br /&gt;listmode.c 完整程式碼：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;X11/X.h&amp;gt;&lt;br /&gt;#include &amp;lt;X11/extensions/Xrandr.h&amp;gt;&lt;br /&gt;&lt;br /&gt;void main()&lt;br /&gt;{&lt;br /&gt;    XRRScreenSize *sizes;&lt;br /&gt;    XRRScreenConfiguration *sc;&lt;br /&gt;    int nsize;&lt;br /&gt;    short rate;&lt;br /&gt;    Rotation current_rotation;&lt;br /&gt;    SizeID size_id;&lt;br /&gt;&lt;br /&gt;    int i;&lt;br /&gt;&lt;br /&gt;    Display *dpy = XOpenDisplay(NULL);&lt;br /&gt;    int screen = DefaultScreen(dpy);&lt;br /&gt;    Window root = RootWindow(dpy, screen);&lt;br /&gt;&lt;br /&gt;    /* Get XRandr Screen Configuration */ &lt;br /&gt;    sc = XRRGetScreenInfo(dpy, root);&lt;br /&gt;&lt;br /&gt;    /* Get all Modes of Screen */&lt;br /&gt;    sizes = XRRConfigSizes(sc, &amp;nsize);&lt;br /&gt;    printf("nsize: %d\n", nsize);&lt;br /&gt;&lt;br /&gt;    /* Get Current Rate */&lt;br /&gt;    rate = XRRConfigCurrentRate(sc);&lt;br /&gt;    printf("rate: %d\n", rate);&lt;br /&gt;&lt;br /&gt;    /* Get  current mode ID and rotation config */&lt;br /&gt;    size_id = XRRConfigCurrentConfiguration(sc, &amp;current_rotation);&lt;br /&gt;    printf("size id: %d\n", size_id);&lt;br /&gt;&lt;br /&gt;    for (i = 0; i &amp;lt; nsize; i++) {&lt;br /&gt;        if (size_id == i)&lt;br /&gt;            printf("%d %dx%d *\n", i, sizes[size_id].width, sizes[size_id].height);&lt;br /&gt;        else&lt;br /&gt;            printf("%d %dx%d\n", i, sizes[i].width, sizes[i].height);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;編譯：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;gcc -o listmode listmode.c -lX11 -lXrandr&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;執行結果（在筆者電腦上 1920x1080 60Hz 為當前的解析度模式）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;$ ./listmode&lt;br /&gt;nsize: 8&lt;br /&gt;rate: 60&lt;br /&gt;size id: 0&lt;br /&gt;0 1920x1080 *&lt;br /&gt;1 1440x900&lt;br /&gt;2 1280x800&lt;br /&gt;3 1152x864&lt;br /&gt;4 1024x768&lt;br /&gt;5 800x600&lt;br /&gt;6 640x480&lt;br /&gt;7 720x400&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;若要更進一步更改和設定模式，可在範例程式碼最後加上 RRSetScreenConfigAndRate()：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;XRRSetScreenConfigAndRate(dpy, sc, root, (SizeID)0,&lt;br /&gt;    current_rotation, rate, CurrentTime);&lt;/pre&gt;&lt;/div&gt;註：其中 SizeID 型態指的是模式的編號，同列表中最前面的編號，可擇一使用。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-6740455092527024156?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/6740455092527024156/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/12/c-xrandr-extension.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6740455092527024156'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6740455092527024156'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/12/c-xrandr-extension.html' title='寫支 C 程式用 XRandr Extension 設定你的螢幕解析度'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-8879369152738185917</id><published>2010-12-08T02:22:00.003+08:00</published><updated>2010-12-08T02:27:03.408+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3D'/><category scheme='http://www.blogger.com/atom/ns#' term='技術新知'/><category scheme='http://www.blogger.com/atom/ns#' term='Webkit'/><category scheme='http://www.blogger.com/atom/ns#' term='Mandice'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='X11'/><category scheme='http://www.blogger.com/atom/ns#' term='User Interface'/><title type='text'>Mandice Superted - Non-GoogleTV Web Browser for TV Device</title><content type='html'>由於一些合作廠商們不願意使用 GoogleTV 或 Android 做 TV Devices，最近實作了 Connected TV 專用的網頁瀏覽器(Web Browser) - 『Superted』。他們選擇不走 Google 之路有很多因素，像是 Google 雖有遠大願景，但當前還不夠成熟，所以目前為止 Android 在 Connected TV 上，還未有立即性的應用程式擴充價值。其次，中國大陸的 PPStream Content 和山寨市場之大，讓華人市場不接受只有 Youtube 的 GoogleTV。再來，就是跨平台開發成本與硬體驅動的議題。這也是為什麼我們會被要求寫一個『比較適合』在 TV Device 上使用的網頁瀏覽器，當然，廠商們的聖旨也說要有大又明顯的 UI，又或者是與 GoogleTV 雷同。&lt;br /&gt;&lt;br /&gt;延續過去的 Webkit 網頁瀏覽器實驗品，加上了 3D User Interface 的支援，便完成了 Superted 的原型：&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;object style="height: 390px; width: 640px;"&gt;&lt;param name="movie" value="http://www.youtube.com/v/SaOvO_rzT-4?version=3"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/SaOvO_rzT-4?version=3" type="application/x-shockwave-flash" allowfullscreen="true" allowScriptAccess="always" width="640" height="390"&gt;&lt;/object&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;影片中是使用 Acer AspireOne(Intel Atom N270) 第一代 netbook 做功能演示，也已經在 VIA platform 上順利測試過。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-8879369152738185917?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/8879369152738185917/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/12/mandice-superted-non-googletv-web.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/8879369152738185917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/8879369152738185917'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/12/mandice-superted-non-googletv-web.html' title='Mandice Superted - Non-GoogleTV Web Browser for TV Device'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-2541480982507711137</id><published>2010-11-12T10:31:00.001+08:00</published><updated>2010-11-14T13:22:53.233+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Embedded System'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='有趣新構思'/><title type='text'>Mandice 為您在 Linux 和新產業機會開路</title><content type='html'>近來忙於工作和協助新團隊的建立，付出於 Blog 上的時間也少了許多，不過，雖然在 Blog 上與自己對話的時間減少，但這些日子，卻自我反省甚多。&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;回想起過去的經歷，總讓一波波湧出來的『資訊新名詞』，將自己不停往岸上沖。這就是資訊業，三天一小變，五天一大變，稍不留神，已改朝換代而擱淺在岩岸上。但在這浪花四起的時代，總不曉得是被誰所欺負。有時欲求助卻會惹一身麻煩，每每都問自己，到底要忍到何時？知道被沖上岸者眾，人人都不甘心，卻也莫可奈何世代交替，也在擔心哪一天自己會被衝上岸。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;經過風風雨雨，能體會許多外界不瞭解的心聲；隨『科技業』起舞多時，我們多少也有在第一線立足的經驗和能力。尋思，與其每天趕潮流拼出貨，日日廢寢忘食只為解決沒價值的人為遐疵，何不帶著最新的技術為沉睡多年的前輩們『重新開路』，開一條不孤單的路，開一條喚醒巨龍的路？&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;為此，一個全新的台灣車庫團隊 [&lt;a href="http://www.mandice.com/"&gt;Mandice&lt;/a&gt;] 誕生，宗旨『做正確的事(Do the right thing)』，我們不盲目跟從，我們創造和領導新方向。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;由於團隊的存活與堅顧理想是無法避免的考量，我們目前的經營三大方向為：&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;保本&lt;/li&gt;&lt;ul&gt;&lt;li&gt;以接案、顧問服務、銷售軟硬體和商業合作為主要訴求&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;創新&lt;/li&gt;&lt;ul&gt;&lt;li&gt;建立商業模式，開發有產業價值或有自身創意之產品&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;擴展&lt;/li&gt;&lt;ul&gt;&lt;li&gt;強健內部團隊技術發展和體制&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;我們計畫推出的服務項目：&lt;br /&gt;&lt;ul&gt;&lt;li&gt;各式軟硬體技術整合顧問服務，讓企業精準做正確決策&amp;nbsp;&lt;/li&gt;&lt;li&gt;代理維護底層軟體系統平台，讓企業專注自身優勢發展&amp;nbsp;&lt;/li&gt;&lt;li&gt;伺服器軟硬體建置支援，協助 IT 系統建設&amp;nbsp;&lt;/li&gt;&lt;li&gt;快速供應完全免授權費的商業用 Linux 作業系統，今天下單明天出貨&amp;nbsp;&lt;/li&gt;&lt;li&gt;量身訂做各式專門用途作業系統，使產品效能和品質兼具&amp;nbsp;&lt;/li&gt;&lt;li&gt;協助將 Linux 系統導入自家產品設計，協助業者迎接資訊新世代&lt;/li&gt;&lt;li&gt;設計並生產自己的概念產品，創造新時代&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;此外，我們也將投入網路服務的發展和創新，期望在台灣重建網路泡沫化後，各界對網路失去的信心。&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;當前，如果您有以下需求，您就將會是我們的商業夥伴&lt;br /&gt;&lt;ul&gt;&lt;li&gt;想有劃時代資作為的老闆和企業&amp;nbsp;&lt;/li&gt;&lt;li&gt;想將原本的應用轉移至更有機會的平台&amp;nbsp;&lt;/li&gt;&lt;li&gt;需要隨機出貨的免授權作業系統&amp;nbsp;&lt;/li&gt;&lt;li&gt;不想自己養大隊人馬貢奉底層系統&amp;nbsp;&lt;/li&gt;&lt;li&gt;不想傷腦筋卻又必需追新東西的人&lt;/li&gt;&lt;li&gt;燒錢燒到失望的老闆和企業&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;無論您瞭不瞭解當今的新名詞，無論您是否遭遇過難搞的技術人事，希望您可以再嘗試一次，萬事起步難，這次開路交給我們。&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-2541480982507711137?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/2541480982507711137/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/11/mandice-linux.html#comment-form' title='3 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2541480982507711137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2541480982507711137'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/11/mandice-linux.html' title='Mandice 為您在 Linux 和新產業機會開路'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-1924430606754769343</id><published>2010-10-03T02:38:00.001+08:00</published><updated>2010-10-03T02:39:10.821+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><title type='text'>Linux 上原生的 Google Map 應用程式</title><content type='html'>為了一些想法和方向，最近開始實作 Google Map 應用程式。經過些許研究，得知了如何從 Google 取得 Map 圖檔，然後自己刻了一支簡單的貼圖引擎，便大致完成了這個應用程式。&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;object height="344" width="425"&gt;&lt;param name="movie" value="http://www.youtube.com/v/uIuNS18HxbQ?hl=zh&amp;fs=1"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/uIuNS18HxbQ?hl=zh&amp;fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;br /&gt;或許很多人覺得這種東西只要引入個 Web 瀏覽器引擎，再用 JavaScript 來做就好，但考量到 Web 瀏覽器引擎需要龐大的硬體資源支持，若是什麼小東西都使用它，將可能成為莫大的問題。所以，此次實作使用 C 語言，並在 X11 的架構上繪圖，是一個原生的 Linux Application。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-1924430606754769343?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/1924430606754769343/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/10/linux-google-map.html#comment-form' title='4 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1924430606754769343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1924430606754769343'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/10/linux-google-map.html' title='Linux 上原生的 Google Map 應用程式'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-5631085504087378229</id><published>2010-09-21T15:26:00.001+08:00</published><updated>2010-09-21T15:31:53.923+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><title type='text'>你不需要自由</title><content type='html'>曾幾何時，『自由』兩字變成了信仰，更變成了宗教狂熱，終以救世主姿態降臨。確實，我們都不喜歡被鎖在一片漆黑毫無自由可言的房中，許多心理實驗也證明了這樣做會造成人們發狂，但是自古到今，絕大多數人類被鎖在地球表面上卻也不曾為此發狂，尋思，自由有這麼重要嗎？我們又真的需要自由嗎？或許，我們只需要有能夠發洩的管道，其實自不自由一點都不重要。&lt;br /&gt;&lt;br /&gt;歷史上為了自由而戰的事績何其多，有人為獨立而戰，有人為自己生存權利而戰，更有人為地位而戰，無論如何，大家追求的不過是長久心理壓力的出口。反觀當前科技業，近來開口自由軟體，閉口也自由軟體，暢導『自由』已不是為追求瓶頸出口，而是種貪婪的表現。到最後，雖不花分毫取得和掌控軟體各種權利，卻花了更大的代價去維護，甚至可能因無法控制而走火毀滅。&lt;br /&gt;&lt;br /&gt;說到底，身為科技產業的商人要的是什麼？到底是軟體業合作廠商口袋裡的錢？還是市場上的錢？&lt;br /&gt;&lt;br /&gt;一個通過重重升學考驗，有一技之長的精英，花了數十年成就一身，使用他們身上的東西，都有每個月個把萬的價值，更何況一個通過重重研發關卡的軟體，餵飽這些軟體的龐大成本更不在話下。而將這些軟體成本放在自己身上，更是種風險和壓力。所以，各自放出口袋不屬於自己的餅，丟掉這份不需要的自由，讓所有人共同追求最大利益不是更好？&lt;br /&gt;&lt;br /&gt;一個商人或商業機構，追求利益的出口，無可後非，不過，一個皇帝可以穫得大片江山，卻不能任意奪取民脂民膏，更是不能忘記。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;若自由軟體不能勝任，就算熱愛自由軟體，也不應貿然使用，否則造成的後遺症，可不是打出『義和拳』推廣旗織就能解決的。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-5631085504087378229?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/5631085504087378229/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/09/blog-post.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5631085504087378229'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5631085504087378229'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/09/blog-post.html' title='你不需要自由'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-8308442648150443708</id><published>2010-09-08T08:24:00.000+08:00</published><updated>2010-09-08T08:24:32.953+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Debian'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>用 apt-get 節省系統開發和評估的時間</title><content type='html'>使用 Debian 系統（包括 Ubuntu）的人，應該早就熟於使用 apt-get 去安裝、移除或更新系統，其無痛和方便的操作，帶給 Debian 家族很大的優勢。而對於研發人員而言，我們比較在乎的是如何取得各套件的程式碼，更在乎的是能在『不出錯』的情況下將取得的程式碼完整編譯通過。&lt;br /&gt;&lt;br /&gt;你可能碰到過一種情況，辛辛苦苦從各程式的專案首頁去抓回 Source Code 後，卻怎麼也無法在自己的電腦上編譯，單純點的情況是相依性問題，複雜點則是在不同系統上的相容問題，更誇張的是根本不清楚下載回來的 Source Code 是不是『真的沒問題』。相信很多人早已浪費過不少生命在這些麻煩問題上，導致開發效率低落，不過以上問題，卻在 Debian 裡相當容易解決，因為 apt-get 提供了一系列選項，讓我們輕易從下載原始碼、解決相依性問題、到確保通過編譯一次搞定。&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;pre&gt;# 下載套件原始程式碼：&lt;br /&gt;apt-get source &amp;lt;package&amp;gt;&lt;br /&gt;# 安裝該套件編譯過程必要的東西&lt;br /&gt;apt-get build-dep &amp;lt;package&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;從 apt-get 下載回來的程式碼，會在自動解開時將該 Package Maintainer 所做的 Patch 一併打進程式碼，以此方法解決系統相容性問題，這邊用 lxterminal package 為例，粗字部份就是在解壓縮時上的 patch：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;$ apt-get source lxterminal&lt;br /&gt;正在讀取套件清單... 完成&lt;br /&gt;正在重建相依關係          &lt;br /&gt;正在讀取狀態資料... 完成&lt;br /&gt;NOTICE: 'lxterminal' packaging is maintained in the 'Git' version control system at:&lt;br /&gt;git://git.debian.org/git/collab-maint/lxterminal.git&lt;br /&gt;需要下載 293kB 的原始套件檔。&lt;br /&gt;下載:1 http://ftp.tw.debian.org/debian/ sid/main lxterminal 0.1.8-2 (dsc) [1,372B]&lt;br /&gt;下載:2 http://ftp.tw.debian.org/debian/ sid/main lxterminal 0.1.8-2 (tar) [280kB]&lt;br /&gt;下載:3 http://ftp.tw.debian.org/debian/ sid/main lxterminal 0.1.8-2 (diff) [11.2kB]&lt;br /&gt;取得 293kB 用了 1s (240kB/s)    &lt;br /&gt;dpkg-source: info: extracting lxterminal in lxterminal-0.1.8&lt;br /&gt;dpkg-source: info: unpacking lxterminal_0.1.8.orig.tar.gz&lt;br /&gt;dpkg-source: info: unpacking lxterminal_0.1.8-2.debian.tar.bz2&lt;br /&gt;&lt;b&gt;dpkg-source: info: applying alt-number-key.patch&lt;br /&gt;dpkg-source: info: applying hide-menu.patch&lt;br /&gt;dpkg-source: info: applying fix_shortcuts.patch&lt;/b&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;再經過 apt-get build-dep 指令，會將 package 編譯需要的 library 或 Headers 安裝好，然後就可以接著用 ./configure 和 make 等步驟開始編譯了，如果沒有特殊意外（如：某些 package 需在 ./configure 的階段設定自有的參數），通常都會無痛編譯成功。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;通常在教育訓練或是和朋友談論研發議題時，總是推薦使用 Debian 系列的 Linux 發行版本（Debian 或 Ubuntu），通常原因就是其套件管理軟體能節省我們大量時間，而且其 Package 進入 Repository 的省核和驗證相當嚴格，並不容易得到壞的 source code package 。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-8308442648150443708?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/8308442648150443708/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/09/apt-get.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/8308442648150443708'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/8308442648150443708'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/09/apt-get.html' title='用 apt-get 節省系統開發和評估的時間'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-2013465876388809624</id><published>2010-09-03T20:19:00.000+08:00</published><updated>2010-09-03T20:19:49.375+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><category scheme='http://www.blogger.com/atom/ns#' term='Bash'/><title type='text'>超強大的 Bash - Networking 支援</title><content type='html'>當全世界都在瘋各種擴充性多元的 Script 語言時，所有人便開始遺忘 Unix 上古老的 Shell script，的確，和當今主流的 Python 、Perl 等語言相比，Bash 像個醜小鴨，但是不可否認，其功能和 footprint 的相對價值遠超過其他 script 語言甚多，因此在大多數 Linux 發行版之中，仍然會預設安裝 Bash 。&lt;br /&gt;&lt;br /&gt;也因為 Bash 被太多人忽視了，很少人知道， Bash 其實也可以操作 Networking，舉例來說，可以一行指令便連上時間伺服器，透過 Daytime Protocol (RFC-867) 取得目前的標準時間：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;$ cat &amp;lt;/dev/tcp/time.nist.gov/13&lt;br /&gt;&lt;br /&gt;55442 10-09-03 11:19:58 50 0 0 839.8 UTC(NIST) *&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Bash 內建了這樣的功能，讓使用者可以透過讀寫 /dev/proto/host/port 的方式去操作網路連線，當然這路徑並不真實存在於系統中，所以透過其他的 script 或程式是無法存取。瞭解有這樣的功能後，我們也可以去試著去抓取網頁內容：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;$ exec 3&amp;lt;&amp;gt; /dev/tcp/www.google.com/80&lt;br /&gt;$ echo -e "GET / HTTP/1.1\r\nhost: http://www.google.com\r\nConnection: close\r\n\r\n" &amp;gt;&amp;3&lt;br /&gt;$ cat &amp;lt;&amp; 3&lt;br /&gt;HTTP/1.1 404 Not Found&lt;br /&gt;Content-Type: text/html; charset=UTF-8&lt;br /&gt;X-Content-Type-Options: nosniff&lt;br /&gt;Date: Fri, 03 Sep 2010 11:40:10 GMT&lt;br /&gt;Server: sffe&lt;br /&gt;Content-Length: 1354&lt;br /&gt;X-XSS-Protection: 1; mode=block&lt;br /&gt;Connection: close&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&lt;br /&gt;... 內容省略&lt;br /&gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;使用 Shell script 是一種身為 Linux/BSD 等 Unix's like 系統工程師的基本技能，比起其他語言，其更為重要，況且現在的 Bash 已經有相當多的支援，足以讓我們做各種應用。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-2013465876388809624?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/2013465876388809624/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/09/bash-networking.html#comment-form' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2013465876388809624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2013465876388809624'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/09/bash-networking.html' title='超強大的 Bash - Networking 支援'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-3460836963431300347</id><published>2010-09-02T17:30:00.000+08:00</published><updated>2010-09-02T17:30:23.075+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Autotool'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><title type='text'>為你的程式加上 Debugging Mode</title><content type='html'>使用 C 語言開發程式，往往面對的都是數不盡的奇怪臭蟲，若想為程式除錯，通常會使用很多的 printf function，將所有程式執行的流程以及階段訊息印在畫面上。不過，太多的除錯訊息多半也會造成效能的影響，甚至是造成程式在使用上的不便。尋思，若能在 compile 階段設定是否開啟 Debugging Mode，對程式開發和最後包裝釋出，都可減少不少時間花費。&lt;br /&gt;&lt;br /&gt;本文主要說明，如何利用 Autotool 和 C 語言 Macro，在 ./configure 執行階段決定啟動 Debugging Mode：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;./configure --enable-debug&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;要達成目標，首先必需修改 configure.ac 並增加設定，使之後產生的 configure 檔案可支援 --enable-debug：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;AC_ARG_ENABLE(debug,&lt;br /&gt;              AC_HELP_STRING([--enable-debug], [Enable debugging]),&lt;br /&gt;              CFLAGS="$CFLAGS -g -D_DEBUG")&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;然後在程式中的 C Header （確定該檔案是所有程式碼都會 Include 的 Header），加讓以下 Macro：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;#ifdef _DEBUG&lt;br /&gt;#define DEBUG(format, args...) printf("[%s:%d] "format, __FILE__, __LINE__, ##args)&lt;br /&gt;#else&lt;br /&gt;#define DEBUG(args...)&lt;br /&gt;#endif&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;然後我們就可以在程式中使用 DEBUG() 的 Macro，用法和 printf function 一樣，只是該字串只在 Debugging Mode 被啟用時才會被編譯進程式裡：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;void main()&lt;br /&gt;{&lt;br /&gt;    DEBUG("Debugging Mode was enabled\n")&lt;br /&gt;&lt;br /&gt;    printf("Hello World!\n");&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;該程式執行後，就會看到類似下面的訊息：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;[main.c:3] Debugging mode was enabled&lt;br /&gt;Hello World!&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;由於在 C header 中設計的 DEBUG()，也包括了檔案名稱和程式碼行數，對於開發人員做除錯的工作就相當方便。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-3460836963431300347?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/3460836963431300347/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/09/debugging-mode.html#comment-form' title='3 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3460836963431300347'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3460836963431300347'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/09/debugging-mode.html' title='為你的程式加上 Debugging Mode'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-8791215205348858976</id><published>2010-08-31T02:59:00.000+08:00</published><updated>2010-08-31T02:59:58.699+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='GStreamer'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>GStreamer Debugging 參數說明</title><content type='html'>[&lt;a href="http://www.gstreamer.net/"&gt;GStreamer&lt;/a&gt;] 是一個優異的多媒體處理元件 Library，其架構了最先進的多媒體資料流機制，在目前主流的 Linux 系統中，應用極為廣範。GStreamer 支援以 Plugin 的形態擴充自身功能，可以是編解碼器(Encoder/Decoder)，亦或是效果處理(Processing)，因此，有許多生產硬體解碼晶片的廠商，都會透過提供 Gstreamer Plugin 的方式，支援 Linux 上的多媒體播放。說到多媒體架構，或許讀者也曾聽過 OpenCore/OpenMax，其實 Gstreamer 和 OpenCore 兩者是相類似的東西，只是前者主要被應用在桌面系統居多，後者則常見於嵌入式系統(Embedded System)應用，最廣為人知的便是 Android Multimedia Framework。在此，細節就不多談，本文將要探討 GStreamer Debugging 的一些手段。&lt;br /&gt;&lt;br /&gt;如果曾開發過 GStreamer Application，對初始化 GStreamer Backend 應該很熟悉：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;gst_init(&amp;amp;argc, &amp;amp;argv);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;我們可以理解所有的 GStreamer Application，都會經過這段 Initialization 的動作，因此 gst_init() 會從 main() 得到程式被執行時所代入的後綴參數，換言之，理論上不管是什麼 Application ，我們可以透過這種方式去開啟 GStreamer 的 Debug 模式：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;$ ./totem --gst-debug-level=3&lt;br /&gt;0:00:00.003322140 13127  0x8c530a0 INFO                GST_INIT gstquery.c:105:_gst_query_initialize: init queries&lt;br /&gt;0:00:00.004700946 13127  0x8c530a0 INFO                GST_INIT gstmessage.c:73:_gst_message_initialize: init messages&lt;br /&gt;0:00:00.005529752 13127  0x8c530a0 INFO      GST_PLUGIN_LOADING gstplugin.c:348:_gst_plugin_initialize: registering 0 static plugins&lt;br /&gt;0:00:00.005766514 13127  0x8c530a0 INFO      GST_PLUGIN_LOADING gstplugin.c:254:gst_plugin_register_static: registered static plugin "staticelements"&lt;br /&gt;0:00:00.005795498 13127  0x8c530a0 INFO      GST_PLUGIN_LOADING gstplugin.c:256:gst_plugin_register_static: added static plugin "staticelements", result: 1&lt;br /&gt;0:00:00.006600699 13127  0x8c530a0 INFO            GST_REGISTRY gstregistry.c:1586:ensure_current_registry: reading registry cache: /home/fred/.gstreamer-0.10/registry.i486.bin&lt;br /&gt;0:00:00.029082746 13127  0x8c530a0 INFO            GST_REGISTRY gstregistrybinary.c:601:gst_registry_binary_read_cache: loaded /home/fred/.gstreamer-0.10/registry.i486.bin in 0.022431 seconds&lt;br /&gt;0:00:00.029188137 13127  0x8c530a0 INFO            GST_REGISTRY gstregistry.c:1446:scan_and_update_registry: Validating plugins from registry cache: /home/fred/.gstreamer-0.10/registry.i486.bin&lt;br /&gt;0:00:00.031259140 13127  0x8c530a0 INFO            GST_REGISTRY gstregistry.c:1548:scan_and_update_registry: Registry cache has not changed&lt;br /&gt;0:00:00.031292035 13127  0x8c530a0 INFO            GST_REGISTRY gstregistry.c:1615:ensure_current_registry: registry reading and updating done, result = 1&lt;br /&gt;0:00:00.031311032 13127  0x8c530a0 INFO                GST_INIT gst.c:786:init_post: GLib runtime version: 2.24.1&lt;br /&gt;&lt;br /&gt;0:00:00.031331007 13127  0x8c530a0 INFO                GST_INIT gst.c:788:init_post: GLib headers version: 2.24.1&lt;br /&gt;... 以下省略&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;參考 GStreamer 官方文件，會發現有數種參數可以使用：&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;--gst-debug-level=LEVEL&lt;br /&gt;設定 Debug 級別，LEVEL 範圍從 0 (不輸出訊息) 到 5 (輸出所有訊息)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;--gst-debug=LIST&lt;br /&gt;要求特定的 Plugin 所 Debug 訊息輸出，亦可以分別設定不同 plugin 有的不同 Debug 級別，格式範例：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;--gst-debug=GST_AUTOPLUG:5,avidemux:3&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;--gst-plugin-spew&lt;br /&gt;輸出 Plugin 載入的錯誤訊息&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;References&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;GStreamer Application Development Manual:&lt;br /&gt;&lt;a href="http://www.gstreamer.net/data/doc/gstreamer/head/manual/html/section-checklist-debug.html"&gt;http://www.gstreamer.net/data/doc/gstreamer/head/manual/html/section-checklist-debug.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-8791215205348858976?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/8791215205348858976/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/08/gstreamer-debugging.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/8791215205348858976'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/8791215205348858976'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/08/gstreamer-debugging.html' title='GStreamer Debugging 參數說明'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-8214561275258872470</id><published>2010-08-29T04:16:00.002+08:00</published><updated>2010-08-29T04:19:24.131+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Window Manager'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='X11'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>親手打造 Window Manager - Transient 和 OverrideRedirect</title><content type='html'>若嘗試去讀各個 Window Manager 的程式碼，最大的挫折就是會遭遇其中了龐大數量的專有名詞和屬性，假設沒有對 XWindow 和 Window Manager 整體架構有清楚概念，必定會花不少時間在查詢 X11/Xlib 的官方文件和映證，不過，查證過程雖繁瑣，對瞭解整個實作很有幫助。筆者將在本文記錄幾個比較特別的視窗(window)屬性，以便讀者懂得如何處理一些特殊的 window。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;WM_TRANSIENT_FOR&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;此 Hint 屬性記載著短暫視窗的父視窗的 Window ID，若不是短暫視窗，將回傳沒有父視窗。短暫視窗有與一般視窗不同之特性，其將不會在工作列上被顯示，只是用來做短時間顯示使用，如對話視窗(Dialog Window) 就屬此類。想取得該屬性的設定值，可以藉由此 XGetTransientForHint() 得到：&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;pre&gt;XGetTransientForHint(Display *, Window, Window*)&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;OverrideRedirect&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;此 Window Attributes 參數表明忽略重新定向，若此參數為真(True)，視窗管理員(Window Manager) 將不會為該視窗畫上標題框和邊框，如選單視窗(Menu Window)就屬此種會忽略重新定向的視窗。我們可以透過 XGetWindowAttributes() 去取得該屬性，簡單的範例如下：&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;pre&gt;XWindowAttributes attr;&lt;br /&gt;XGetWindowAttributes(display, win, &amp;attr);&lt;br /&gt;if (attr.overrideRedirect)&lt;br /&gt;    ....&lt;br /&gt;else&lt;br /&gt;    ....&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;暫且撇開一般 X Application 開發者熟知的視窗形態(Type)，如：Dock 、Desktop、Toolbar 等等，Window Manager 在畫視窗時，首先要處理的是 WM_TRANSIENT_FOR 和 overrideRedirect 這類的屬性，而視窗形態應該是考量於 Window Manager 自身的應用後，才有不同的設計和呈現。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-8214561275258872470?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/8214561275258872470/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/08/window-manager-transient.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/8214561275258872470'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/8214561275258872470'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/08/window-manager-transient.html' title='親手打造 Window Manager - Transient 和 OverrideRedirect'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-1172126789292180040</id><published>2010-08-27T05:29:00.006+08:00</published><updated>2010-08-27T06:41:41.106+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Window Manager'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='X11'/><title type='text'>親手打造 Window Manager - 監聽 Screen 上的 XEvent</title><content type='html'>在 Linux 等 Unix's like 的系統上，擁有數十載歷史的 X11 通常為主流的圖形介面支援方案，雖架構看似老舊，卻在世界上眾高手的努力下，成就了現在的各種極絢麗的桌面環境，而最為眾人所知的，便是 Compiz 這類『視窗管理器(Window Manager)』，其運用 3D 技術帶來震憾的桌面體驗，因此在目前主流的 Linux 發行版中，無一不預設搭載。而許多人在此時，才真正了解 Window Manager 的厲害和重要性，新興的系統中，無論是 Moblin 還是 Google Chrome OS，也都特地為自家系統打造專屬的 Window Manager。&lt;br /&gt;&lt;br /&gt;然而，Window Manager 實作細節雖看起來複雜，但實際上沒有想像中這麼艱澀，單純透過 X Protocol 和 API 去控制 window 的行為，這類工作極為簡單，而真正令人感到棘手的，是在事件(event)處理和 ICCCM/EWMH 的部份。ICCCM/EWMH 現在是由 [&lt;a href="http://www.freedesktop.org/"&gt;FreeDesktop.org&lt;/a&gt;] 所維護，其定義了一系列的屬性，用來記錄視窗環境的狀態，並可供所有 X Client 存取，而 Window Manager 要做的就是成為一個常註程式(Daemon)，並隨時去提供和更新這些狀態。不過由於 ICCCM/EWMH 這部份細節繁雜，暫不在本文討論範疇（有興趣可自行參閱 &lt;a href="http://standards.freedesktop.org/wm-spec/wm-spec-latest.html"&gt;FreeDesktop.org EWMH Spec&lt;/a&gt;），我們主要是討論如何監聽畫面上視窗的 event。&lt;br /&gt;&lt;br /&gt;一般 window 監聽自己的 XEvent 是家常便飯，只要有以 Xlib 寫過純 X Application 的人應該都多少有些了解，會比較不瞭解的部份，就是該如何去監聽整個 screen 上的 event，但在這之前，我們有必要先大致瞭解 X window 的架構。通常在 X 上所呈現的桌面環境，是一層層 window 疊起來而成，舉例來說，桌面上常見的工具列(Panel)，上面的狀態 Icon ，如：網路管理、Pidgin Icon 等，都是一個個 window 放在 Panel 的 window 之上，而在 Panel 之後，到最底層便是 screen 的 Root Window，Root Window 在所有 window 之下。&lt;br /&gt;&lt;br /&gt;所以，若要做到監聽整個 screen 下所有 window 的 event，想當然爾就是對 screen 的 Root Window 做監聽，但單單只是監聽 Root Window 並無法取得所有 Sub Window 的 event，必須利用 X 定義的 SubstructureRedirectMask 以及 SubstructureNotifyMask 此類 event mask 達成目的。在程式中，我們只需使用 XChangeWindowAttributes() 去設定 Root Window  的 Attributes，將 event mask 代入就可以。&lt;br /&gt;&lt;br /&gt;這是簡單的範例：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;XSetWindowAttributes attr;&lt;br /&gt;&lt;br /&gt;attr.event_mask = SubstructureRedirectMask | SubstructureNotifyMask |&lt;br /&gt;        ColormapChangeMask | ButtonPressMask | PropertyChangeMask |&lt;br /&gt;        EnterWindowMask;&lt;br /&gt;&lt;br /&gt;XChangeWindowAttributes(display, screen-&gt;root, CWEventMask, &amp;attr);&lt;br /&gt;XSync(display, False);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;當 Root Window 的 Attributes 被設定後，我們的程式便可以去監聽 Screen 下所有 Window 的 XEvent，當有程式被執行要顯示在畫面上時，就會收到 ConfigureRequest 和 MapRequest Event。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-1172126789292180040?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/1172126789292180040/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/08/window-manager-screen-xevent.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1172126789292180040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1172126789292180040'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/08/window-manager-screen-xevent.html' title='親手打造 Window Manager - 監聽 Screen 上的 XEvent'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-389928895541834102</id><published>2010-08-25T05:01:00.007+08:00</published><updated>2010-08-25T14:10:16.089+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><title type='text'>Reverse SSH Tunnel 反向打洞實錄</title><content type='html'>近來經手了幾個案子，其目標都是設計一台做特定用途的系統，但往往這台機器都會被鎖在防火牆後面，甚至不會連上網際網路，是完全封閉的環境。每當接近結案，將系統交到客戶手中以做最後的壓力測試時，便是痛苦的開始。怎麼說呢？因為當面對最後的大量測試，各種大大小小的臭蟲(Bugs)就會原形畢露，一一浮上臺面。而每次問題發生，便要千里迢迢趕到客戶那了解情況、解決問題。如果問題不大倒還好，一旦問題嚴重，被客戶關到三更半夜也是常有的事，更誇張的還必須每天都去報到。所以，為避免車程來回的時間和人力浪費，是否有可以遠端連線做處理呢？便思考起這問題。&lt;br /&gt;&lt;br /&gt;雖然這些機器通常都不會有真實 IP，客戶也不會為了我們特別請 MIS 去開啟 NAT 或防火牆，但還好 SSH 提供了反向(Reverse)的機制讓我們可以連進去。其做法就是讓在客戶那的系統，透過 SSH 先連回我們自家有真實 IP 的主機，然後建立反向的通道即可。如此，我們便可從自家的主機，從 SSH 連回放在客戶那的系統。&lt;br /&gt;&lt;br /&gt;實際的操作步驟：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;# 首先，在客戶那理的機器下指令連回我們自己的 Server，並設定自己 Server 上的 12345 port 會對應到幾器上的 SSH port&lt;br /&gt;ssh -NfR 12345:localhost:22 fred@myhost.com&lt;br /&gt;&lt;br /&gt;# 然後在 myhost 的機器上連自己的 12345 port，就可以連回在客戶那的機器&lt;br /&gt;ssh localhost -p 12345&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;可以將建立 Reverse SSH tunnel 的命令設定在開機後執行，並且透過設定 ssh config 讓斷線時自動重連，如此就可以確保 SSH 連線不會中斷。此外，若是客戶端那的機器是處於完全無法對外連線的環境，則可以考慮使用 3G 網卡，並將網卡暫時借放於客戶那，然後等結案後再取回，雖然 3G 通訊月租不便宜，但和經常來回的通勤費和時間花費相比，可滑算多了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-389928895541834102?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/389928895541834102/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/08/reverse-ssh-tunnel.html#comment-form' title='4 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/389928895541834102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/389928895541834102'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/08/reverse-ssh-tunnel.html' title='Reverse SSH Tunnel 反向打洞實錄'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-6541635714402327315</id><published>2010-08-22T00:39:00.005+08:00</published><updated>2010-08-22T17:56:02.653+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='X11'/><title type='text'>善用 DRI 加速貼圖</title><content type='html'>近日以來，筆者都在著手處理 Linux 下圖形運算的議題，不久前也曾發表一篇『&lt;a href="http://fred-zone.blogspot.com/2010/08/xshm-extension.html"&gt;善用 XShm 加速貼圖&lt;/a&gt;』以探討 X 架構之下的貼圖機制，舊文最後也提出範例，使用共享記憶體(Shared Memory)的方式，達到效能的改善。不過，透過減少資料複製，雖然能有效提升貼圖的效率，但都還只是停留在彌補 X&amp;nbsp;架構先天上的缺陷，令人不禁去想，是否有更直接的解決方案？尋思，現今硬體能力不可同日而語，幾乎每台電腦都具備著基本能力的影像晶片，若運用 DRI 直接對硬體貼圖應該是種可行的手段。&lt;br /&gt;&lt;br /&gt;欲在 X 上透過 DRI 繪圖，最簡單的方法是使用 GLX Extension，藉由建立 OpenGL Window 開啟直接和硬體溝通的管道。我們可以修改與舊文相同的程式碼，並改用 OpenGL 來達成相同的效果：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;string.h&amp;gt;&lt;br /&gt;#include &amp;lt;X11/Xlib.h&amp;gt;&lt;br /&gt;#include &amp;lt;GL/gl.h&amp;gt;&lt;br /&gt;#include &amp;lt;GL/glx.h&amp;gt;&lt;br /&gt;#include &amp;lt;GL/glu.h&amp;gt;&lt;br /&gt;&lt;br /&gt;int main(void)&lt;br /&gt;{&lt;br /&gt;    Window win;&lt;br /&gt;    Display display = XOpenDisplay(getenv("DISPLAY"));&lt;br /&gt;    unsigned char *buffer;&lt;br /&gt;    GLint glxattr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 32, GLX_DOUBLEBUFFER, None };&lt;br /&gt;&lt;br /&gt;    /* Initialize GLX */&lt;br /&gt;    xvinfo = glXChooseVisual(display, 0, glxattr);&lt;br /&gt;    if (xvinfo == NULL)&lt;br /&gt;        exit(1);&lt;br /&gt;&lt;br /&gt;    /* Initial Window */&lt;br /&gt;    win = XCreateSimpleWindow(display, RootWindow(display, DefaultScreen(display)),&lt;br /&gt;                                                        0, 0, 100, 100, 0,&lt;br /&gt;                                                        BlackPixel(display, DefaultScreen(display)),&lt;br /&gt;                                                        BlackPixel(display, DefaultScreen(display)));&lt;br /&gt;&lt;br /&gt;    XMapWindow(display, win);&lt;br /&gt;&lt;br /&gt;    /* Create context */&lt;br /&gt;    glcontext = glXCreateContext(display, vinfo, NULL, GL_TRUE);&lt;br /&gt;    if (glcontext == NULL)&lt;br /&gt;        exit(0);&lt;br /&gt;&lt;br /&gt;    glXMakeCurrent(display, win, glcontext);&lt;br /&gt;    glEnable(GL_DEPTH_TEST);&lt;br /&gt;&lt;br /&gt;    XSync(display, False);&lt;br /&gt;&lt;br /&gt;    /* Allocate image memory for 100x100x32bits */&lt;br /&gt;    buffer = (unsigned char *)malloc(sizeof(char) * 100 * 100 * 4);&lt;br /&gt;&lt;br /&gt;    /* Create texture from framebuffer */&lt;br /&gt;    glEnable(GL_TEXTURE_2D);&lt;br /&gt;    glGenTextures(1, &amp;texture_id);&lt;br /&gt;    glBindTexture(GL_TEXTURE_2D, texture_id);&lt;br /&gt;    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);&lt;br /&gt;    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);&lt;br /&gt;    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);&lt;br /&gt;    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 100, 100, 0, GL_RGBA, GL_UNSIGNED_BYTE, (void*)buffer);&lt;br /&gt;&lt;br /&gt;    /* Loop */&lt;br /&gt;    while(1) {&lt;br /&gt;        glViewport(0, 0, 100, 100);&lt;br /&gt;        glClearColor(0., 0., 0., 1.0);&lt;br /&gt;        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);&lt;br /&gt;&lt;br /&gt;        glMatrixMode(GL_PROJECTION);&lt;br /&gt;        glLoadIdentity();&lt;br /&gt;        glOrtho(-1., 1., -1., 1., -1., 1.);&lt;br /&gt;&lt;br /&gt;        glColor3f(1.0, 1.0, 1.0);&lt;br /&gt;        glBegin(GL_QUADS);&lt;br /&gt;            glTexCoord2f(0.0, 0.0); glVertex3f(-1.0,  1.0, 0.0);&lt;br /&gt;            glTexCoord2f(1.0, 0.0); glVertex3f( 1.0,  1.0, 0.0);&lt;br /&gt;            glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, -1.0, 0.0);&lt;br /&gt;            glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, -1.0, 0.0);&lt;br /&gt;        glEnd(); &lt;br /&gt;&lt;br /&gt;        glXSwapBuffers(display, win);&lt;br /&gt;        usleep(1000);&lt;br /&gt;    };&lt;br /&gt;&lt;br /&gt;    /* Release */&lt;br /&gt;    glXMakeCurrent(display, None, NULL);&lt;br /&gt;    glXDestroyContext(display, glcontext);&lt;br /&gt;    XCloseDisplay(display);&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;編譯 GLX 程式：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;gcc -o glximage glximage.c -lX11 -lGL -lGLU&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-6541635714402327315?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/6541635714402327315/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/08/dri.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6541635714402327315'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6541635714402327315'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/08/dri.html' title='善用 DRI 加速貼圖'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-1526025704120663032</id><published>2010-08-19T17:21:00.002+08:00</published><updated>2010-08-19T17:39:55.067+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='技術新知'/><category scheme='http://www.blogger.com/atom/ns#' term='Chrome OS'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='X11'/><title type='text'>Android is Working on X</title><content type='html'>As you know, Android was designed for mobile device, so there is no large value from Android for desktop environment. But there is no denying that Android has extreme applications resources. If we can combine Android and desktop environment, it will make great experience on Linux. By hacking Android framework, we made Android work on X with success, it is a "real" X application right now. You can see these screenshots:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_Td8NHoYnGW8/TGz65j4TKVI/AAAAAAAAA2s/SKMkbmsnosA/s1600/androidx-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="360" src="http://4.bp.blogspot.com/_Td8NHoYnGW8/TGz65j4TKVI/AAAAAAAAA2s/SKMkbmsnosA/s640/androidx-2.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_Td8NHoYnGW8/TGzz8uISQ6I/AAAAAAAAA2k/kvS8IPDxmaw/s1600/androidx-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="360" src="http://3.bp.blogspot.com/_Td8NHoYnGW8/TGzz8uISQ6I/AAAAAAAAA2k/kvS8IPDxmaw/s640/androidx-1.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_Td8NHoYnGW8/TGzz8uISQ6I/AAAAAAAAA2k/kvS8IPDxmaw/s1600/androidx-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;/a&gt;&lt;a href="http://4.bp.blogspot.com/_Td8NHoYnGW8/TGzz6yRahKI/AAAAAAAAA2c/JBQvURMerDA/s1600/androidx.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="360" src="http://4.bp.blogspot.com/_Td8NHoYnGW8/TGzz6yRahKI/AAAAAAAAA2c/JBQvURMerDA/s640/androidx.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;From screenshots, Android is running on Chromium OS,&amp;nbsp;based on &lt;a href="http://www.android-x86.org/"&gt;Android-x86 project&lt;/a&gt;. Currently, we can use chromium browser to surf internet and use Android application in the same time. In first screenshot, using "ps ax" to show all process on system to prove Android is running on X Server rather than emulator.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-1526025704120663032?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/1526025704120663032/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/08/android-is-working-on-x.html#comment-form' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1526025704120663032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1526025704120663032'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/08/android-is-working-on-x.html' title='Android is Working on X'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_Td8NHoYnGW8/TGz65j4TKVI/AAAAAAAAA2s/SKMkbmsnosA/s72-c/androidx-2.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-3047504739101260680</id><published>2010-08-13T07:44:00.004+08:00</published><updated>2010-08-13T08:06:00.549+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='X11'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>善用 XShm Extension 加速貼圖</title><content type='html'>如今的 Xorg 千變萬化，發展出各種（DRI/DRI2/EAA/EXA/UXA/AIGLX）等加速機制，更有極絢麗的 3D 視窗技術，一點也不讓 Mac OS 和 Windows 上的 3D 視窗特效專美於前。話雖如此，很多人們早已遺忘 X Window System 的歷史原由，我們反觀當年的 XFree86 就有如醜小鴨般，其為 Networking 考量的 Client/Server 架構，就是舊 Unix 終端機時代所留下的東西。到目前為止，隨著硬體速度越來越快，Client/Server 的界限雖被 DRI/DRI2/AIGLX 等技術逐漸打破，但無論如何，Xorg 大底上還是維持著 Client/Server 的本質。只不過應用程式層的軟體，因為經過各種 GTK/GDK/Qt 等 Graphical Toolkits 包裝後，多數開發者和使用者已經不會再看到 X 底層的運作模式。&lt;br /&gt;&lt;br /&gt;這裡記載著一個簡單的範例程式，用來說明 X 如何利用 XImage 做貼圖運算，其主要是將 buffer（100x100x32bits 的影像）畫在視窗上，該 buffer 可以是讀取圖檔或是使用各種資料來源，為一塊記憶體。此程式將會用 XCreateImage() 建立一組 Structure，然後使用 XPutImage() 將該 Structure 和影像資料吃從 XClient 透過 X Protocol(Socket)傳送到 X Server，X Server 再依 XImage 的敘述將圖形畫在視窗上。&lt;br /&gt;&lt;br /&gt;XImage 範例程式：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;void main(void)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;Window win;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;Display display = XOpenDisplay(getenv("DISPLAY"));&amp;nbsp;&amp;nbsp; &amp;nbsp;XImage *ximage;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;unsigned char *buffer;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;/* Initial Window */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;win = XCreateSimpleWindow(display, RootWindow(display, DefaultScreen(display)),&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0, 0, 100, 100, 0,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;BlackPixel(display, DefaultScreen(display)),&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;BlackPixel(display, DefaultScreen(display)));&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;XMapWindow(display, win);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;XSync(display, False);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;/* Allocate image memory for 100x100x32bits */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;buffer = (unsigned char *)malloc(sizeof(char) * 100 * 100 * 4);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;/* Create XImage structure and map image memory on it */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;ximage = XCreateImage(display, DefaultVisual(display, 0),&amp;nbsp;DefaultDepth(display, 0), ZPixmap, 0, buffer, 100, 100, 32, 0);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;/* Put XImage into X Server to display */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;XPutImage(display, window, DefaultGC(display, 0), ximage, 0, 0, 0, 0, 100, 100);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;/* Loop */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;while(1) {};&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;/* Release */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;XDestroyImage(ximage);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;XCloseDisplay(display);&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;不過，眼尖的人或許已經注意到，此程式完全曝露出 X Client/Server 架構所存在的缺陷，無論要貼什麼圖，都必需先透過 X Protocol 傳送至 X Server，如此大量的資料複製，當然取而代之的就是效能低落。一種改善效能的方法就是使用 Shm(Shared Memory)，使 X Client 和 X Server 共享一塊記憶體，讓原先的大量複製資料，改由傳記憶體位置取代，為此，X 就支援了 XShm Extension 來實作此種方法。&lt;br /&gt;&lt;br /&gt;XShm Extension 所提供能函式與原生的 XImage 相關函式相差不大，這邊用另一個範例程式做說明：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;void main(void)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;Window win;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;Display display = XOpenDisplay(getenv("DISPLAY"));&amp;nbsp;&amp;nbsp; &amp;nbsp;XImage *ximage;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;unsigned char *buffer;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;XShmSegmentInfo shminfo;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;/* XShm */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;XShmQueryExtension(display);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;/* Initial Window */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;win = XCreateSimpleWindow(display, RootWindow(display, DefaultScreen(display)),&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;0, 0, 100, 100, 0,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;BlackPixel(display, DefaultScreen(display)),&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;BlackPixel(display, DefaultScreen(display)));&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;XMapWindow(display, win);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;XSync(display, False);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;/* Allocate image memory for 100x100x32bits */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;buffer = (unsigned char *)malloc(sizeof(char) * 100 * 100 * 4);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;/* Create XImage structure and map image memory on it */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;ximage = XShmCreateImage(display, DefaultVisual(display, 0),&amp;nbsp;DefaultDepth(display, 0), ZPixmap, 0, &amp;amp;shminfo, 100, 100);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;/* Setting SHM */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;shminfo.shmid = shmget(IPC_PRIVATE, 100 * 100 * 4, IPC_CREAT | 0777);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;if (shminfo.shmid &amp;lt; 0)&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;exit(-1);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;shminfo.shmaddr = ximage-&amp;gt;data = (unsigned char *)shmat(shminfo.shmid, 0, 0);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;if(shminfo.shmaddr == (char *) -1)&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;exit(-1);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;shminfo.readOnly = False;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;XShmAttach(display, &amp;amp;shminfo);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;/* Put XImage into X Server to display */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;XShmPutImage(display, win, DefaultGC(display, 0), ximage, 0, 0, 0, 0, 100, 100, False);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;XFlush(display);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;/* Loop */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;while(1) {};&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;/* Release */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;XDestroyImage(ximage);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;XCloseDisplay(display);&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;大體上，主要就是&amp;nbsp;XCreateImage 換成 XShmPutImage，XPutImage 換成 XShmPutImage，更多資料可以參考 XFree86 MIT-SHM 文件：&lt;br /&gt;&lt;a href="http://www.xfree86.org/current/mit-shm.html"&gt;http://www.xfree86.org/current/mit-shm.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-3047504739101260680?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/3047504739101260680/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/08/xshm-extension.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3047504739101260680'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3047504739101260680'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/08/xshm-extension.html' title='善用 XShm Extension 加速貼圖'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-5935408303431507137</id><published>2010-07-26T06:59:00.000+08:00</published><updated>2010-07-26T06:59:22.124+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Glib'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><title type='text'>GLib 就是懶．GThreadPool 高效的執行緒池</title><content type='html'>開發複雜的程式時，執行緒(Thread)隨處可見，在高負載的應用程式中，就常會使用到多執行緒所構成的演算法，如 Apache 此類有許多流量及使用者操作的程式，就運用 Thread 做負載的分配。但是，每當&amp;nbsp;Thread 的建立和摧毀，會造成額外的系統資源開銷，若是有大量 Thread 增減將會造成程式效能不彰，所以最好的辦法便是回收並重新運用已經被建立的 Thread。因此，GLib 提供了 GThreadPool 的機制，可重復利用 Thread 以減少不必要的開銷。&lt;br /&gt;&lt;br /&gt;這是一個使用&amp;nbsp;GThreadPool 的範例程式：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;void mythread(gpointer data, gpointer user_data)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;printf("%s\n", data);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;printf("%s\n", user_data);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void main()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;gchar *data = "this is data";&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;gchar *user_data = "this is user_data";&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;GThreadPool *pool;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;if(!g_thread_supported())&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; g_thread_init(NULL);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; /* create thread pool */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; pool = g_thread_pool_new(mythread, user_data, -1, FALSE, NULL);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; if (pool==NULL)&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; printf("ERROR\n");&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;/* start three threads */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; g_thread_pool_push(pool, data, NULL);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; g_thread_pool_push(pool, data, NULL);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; g_thread_pool_push(pool, data, NULL);&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-5935408303431507137?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/5935408303431507137/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/07/glib-gthreadpool.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5935408303431507137'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5935408303431507137'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/07/glib-gthreadpool.html' title='GLib 就是懶．GThreadPool 高效的執行緒池'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-5970877121354858340</id><published>2010-06-18T08:35:00.000+08:00</published><updated>2010-06-18T08:35:03.896+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='旅行(Travel)'/><title type='text'>體驗舊台灣經濟奇蹟之感</title><content type='html'>偶見長輩們提起，台灣早期的繁華和奇蹟，而奇蹟發光時，筆者年幼，懵懵懂懂，卻難以感受一二。如今再從長輩口中傳述，只知，當時台灣人民為錢打拼，不遺餘力。此外，由於當時金融和經濟體制不健全，透過所謂的銀行對保等支付方式相當麻煩，也因為當時國際關係，許多金流是在暗地中轉動，廠商間的往來，往往一句話敲定便算。甚至當下，因為一句信任就交付現額鉅款，也是常見的例子，難以令人想像。只能說，在一切混沌的黑暗時期，人人都為了賺進鈔票而努力，先不論黑白兩道的縱橫交錯，最重要的是誠信便成了當時莫明的默契。&lt;br /&gt;&lt;br /&gt; &lt;b&gt;上有誠意，下有衝勁&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;最近走入南部拓展，因緣際會而接觸了早期的科技產業，卻他們仍保有著台灣早期繁榮的文化，做生意總是滿懷誠意，只要合理，二話也不多說，便開始進行後續流程，用台灣話『阿沙力！』來形容，一點也不為過。但更令筆者感到震憾的，是他們工作伙伴的效率驚人，沒有現代的『工作管理系統』和『協同作業機制』，團隊依然有相當可觀的產能。反觀當今主流資訊業大大小小公司，團隊往往是被流程和管理機制推著走，研發人員已經失去了不畏虎的衝勁。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;解決問題的態度，令人自形慚愧&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;也許是現今產業的專業分工所致，許多人總將問題不分清紅皂白推往別處，只堅守自家陣地。往往工程人員解決問題，都早已忘了初衷，只專注於眼前表面的障礙。久而久之，『會動就好』就變成了一種處理事情的態度。但是態度蔓延，從零組件廠開始，『零組會用就好』就成了最後做產品的態度，所有細節問題通通丟給各大零件廠商去處理。就商業考量上雖沒有不對，但是生產出來的東西就不盡人意了，換言之，要是最後的系統整合商不懂得要求，產品就不會有頂尖的品質。&lt;br /&gt;&lt;br /&gt;而在某公司的教育訊練中，就因為幾句對話，讓我驚醒：&lt;br /&gt;&lt;br /&gt;『這部份的驅動程式官方沒提供程式碼，可能不能移殖』我說。&lt;br /&gt;&lt;br /&gt;『官方沒提供程式碼呀？沒有問題，我們自己重寫這驅動程式』該公司工程師說。&lt;br /&gt;&lt;br /&gt;『這部份的硬體可能會不合用』我說。&lt;br /&gt;&lt;br /&gt;『沒有問題，那我們就改硬體』該公司主管說。&lt;br /&gt;&lt;br /&gt;更令我一再省思的，便是該公司無意間提到一些點子和解決方案時：&lt;br /&gt;&lt;br /&gt;『CPU 架構不一樣呀？那你可以幫我們實做 emulator 嗎？只要給我們介面, 從外部抽出裡面各個 register 的資料即可, 東西放哪我們能 reversing。』該公司主管說。&lt;br /&gt;&lt;br /&gt;先不論技術問題，就出發點而言，他們的技術研發是貼近著產品化而做，所有發想不是純實驗、純好玩，更不是做一個純有遠大目標的玩具。解決眼前阻礙產品化的問題，才是他們第一考量，可以不計一切方法。更重要的，他們工程師解決問題的態度和膽識令人欽佩，要是換成過去的例子：&lt;br /&gt;&lt;br /&gt;『這部份的驅動程式官方沒提供程式碼，可能不能移殖』我說。&lt;br /&gt;&lt;br /&gt;『官方沒提供程式碼呀？那只能請公司和官方要了』工程師說。&lt;br /&gt;&lt;br /&gt;然後解決方案的想法會變成：&lt;br /&gt;&lt;br /&gt;『CPU 架構不一樣呀？如果沒程式碼，那就把程式打掉重寫吧，只要長的像就好。』&lt;br /&gt;&lt;br /&gt;光憑這幾點，無形中就打了筆者好幾個巴掌，令人欲深入檢討自我：『不計一切方法達成目標是對，但不是不擇手段達成假像的目標。』，挑戰自己是否有膽識和態度，正面去面對每個問題，而不是想著應付過關的方法。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;對賺錢的誠意，對產品的要求，工程人員解決問題的態度，都讓人慚愧不已。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-5970877121354858340?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/5970877121354858340/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/06/blog-post.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5970877121354858340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5970877121354858340'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/06/blog-post.html' title='體驗舊台灣經濟奇蹟之感'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-3366767606544788892</id><published>2010-05-26T04:07:00.003+08:00</published><updated>2010-05-26T04:15:33.416+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Web 相關技術'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>fork()、pipe()、dup2() 和 execlp() 的組合技法</title><content type='html'>對一般程式來說，管線(pipe)機制很少會用到，尤其對於在 Windows 底下的程式開發者來說，很可能前所未聞，而在 Unix-like 環境中常見的例子，就是往往在命令後面加上『|』，其意味使用『管子（pipe）』將內容導入另一個程式裡，如：『dmesg | grep ALSA』。在該例中，Shell 有趣的將 demsg 標準輸出（standard output）全數導入 grep 程式的標準輸入（standard input）中，再交由 grep 處理並找出存在 ALSA 字串的句子所在。&lt;br /&gt;&lt;br /&gt;另一個情況，Web Server 在支援 CGI 時，也會使用到 pipe。這是最典型的例子，當 Web Server 欲執行一支外部 CGI Program 時，會利用 pipe 去模擬該 CGI 的標準輸入及輸出（Standard I/O）。以上說明當然只是大致上的做法，細節還需加上 fork() 和 dup2() 的配合，透過個範例可清楚瞭解這部份的實作。&lt;br /&gt;&lt;br /&gt;這是一個簡單的範例：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;void cgi_run(const char* filename)&lt;br /&gt;{&lt;br /&gt;    char buffer[1024] = { 0 };&lt;br /&gt;    int len; &lt;br /&gt;    int pfd[2];&lt;br /&gt;    int status;&lt;br /&gt;    pid_t pid;&lt;br /&gt;&lt;br /&gt;    /* create pipe */&lt;br /&gt;    if (pipe(pfd)&amp;lt;0)&lt;br /&gt;        return -1;&lt;br /&gt;&lt;br /&gt;    /* fork to execute external program or scripts */&lt;br /&gt;    pid = fork();&lt;br /&gt;    if (pid&amp;lt;0) {&lt;br /&gt;        return 0;&lt;br /&gt;    } else if (pid==0) { /* child process */&lt;br /&gt;        dup2(pfd[1], STDOUT_FILENO);&lt;br /&gt;        close(pfd[0]);&lt;br /&gt;&lt;br /&gt;        /* execute CGI */&lt;br /&gt;        execlp(filename, filename, NULL);&lt;br /&gt;        exit(0);&lt;br /&gt;    } else { /* parent process */&lt;br /&gt;        close(pfd[1]);&lt;br /&gt;&lt;br /&gt;        /* print output from CGI */&lt;br /&gt;        while((len=read(pfd[0], buffer, 1023))&amp;gt;0) {&lt;br /&gt;            buffer[len] = '\0';&lt;br /&gt;            printf("%s\n", buffer);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        /* waiting for CGI */&lt;br /&gt;        waitpid((pid_t)pid, &amp;status, 0);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;此範例相當易懂，不外乎是使用 fork() 建立一個新的 Process，再去執行一支外部 CGI，而主程式會等待外部 CGI 的輸出，再用 printf() 印出來 CGI 的輸出內容。而比較令人騷不著頭緒的部份，就是 pipe() 和 dup2() 的關係，使用 pipe() 可建立一組雙向的管線，範例中是一組有兩個整數值的陣列 pfd，這是一條水管，從 pfd[0] 進入的東西會從 pfd[1] 出來，反之亦然，除此之外，它也是可以跨 Process，達成兩個程式溝通的目的。除了建立 pipe，接著利用 dup2()，可以讓管線去取代外部程式的標準輸出（standard output），然後讓主程式用管線接收。&lt;br /&gt;&lt;br /&gt;註：pipe() 回傳的是兩個檔案描述編號（file discriptions），需要用相應的檔案函數去操控它。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-3366767606544788892?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/3366767606544788892/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/05/forkpipedup2-execlp.html#comment-form' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3366767606544788892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3366767606544788892'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/05/forkpipedup2-execlp.html' title='fork()、pipe()、dup2() 和 execlp() 的組合技法'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-8026765376891578221</id><published>2010-05-11T00:48:00.001+08:00</published><updated>2010-05-11T01:47:41.010+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='patch'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><category scheme='http://www.blogger.com/atom/ns#' term='User Interface'/><category scheme='http://www.blogger.com/atom/ns#' term='SCIM'/><title type='text'>SCIM Patch: Auto enable input method when getting keyboard focus for a GTK+ text entry</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_Td8NHoYnGW8/S-g3jrpq-_I/AAAAAAAAA1M/4q_B6bYK9sQ/s1600/ipad_keyboard1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_Td8NHoYnGW8/S-g3jrpq-_I/AAAAAAAAA1M/4q_B6bYK9sQ/s320/ipad_keyboard1.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;As you know, Apple iPad is the latest craze and brings back tablet PC marketing cause most manufactories aim to begin to produce products with touchscreen.  In order to make applications work with touchscreen for tablet PC, implementing on-screen keyboard is the major issue. There are many open source solutions you can get from internet, but you may get a question, what time is better to start the on-screen keyboard? It is a good idea that enable on-screen keyboard when input box get focus, that is just like Apple iPhone, iPod, iPad and a lot smart phone.&lt;br /&gt;&lt;br /&gt;SCIM has panel support, it can provide on-screen keyboard. So I have patched scim-bridge to support that auto enable input method when getting keyboard focus for a GTK+ text entry. If so input method is enabled, SCIM will show on-screen keyboard automatically.&lt;br /&gt;&lt;br /&gt;Here is my patch you can get:&lt;br /&gt;&lt;a href="http://people.linux.org.tw/~fred/patches/scim-bridge-0.4.16_client-gtk-autoshow.patch"&gt;http://people.linux.org.tw/~fred/patches/scim-bridge-0.4.16_client-gtk-autoshow.patch&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-8026765376891578221?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/8026765376891578221/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/05/scim-patch-auto-enable-input-method.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/8026765376891578221'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/8026765376891578221'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/05/scim-patch-auto-enable-input-method.html' title='SCIM Patch: Auto enable input method when getting keyboard focus for a GTK+ text entry'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_Td8NHoYnGW8/S-g3jrpq-_I/AAAAAAAAA1M/4q_B6bYK9sQ/s72-c/ipad_keyboard1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-5450545522273767651</id><published>2010-04-13T08:20:00.001+08:00</published><updated>2010-04-13T08:20:58.103+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Cross-compile'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Embedded System'/><category scheme='http://www.blogger.com/atom/ns#' term='心得分享、講座'/><category scheme='http://www.blogger.com/atom/ns#' term='Beagleboard'/><category scheme='http://www.blogger.com/atom/ns#' term='devkit8000'/><title type='text'>親手打造 HD 多媒體播放器，簡報上線</title><content type='html'>承年初『&lt;a href="http://fred-zone.blogspot.com/2010/01/hd.html"&gt;親手打造 HD 多媒體播放器&lt;/a&gt;』所述，小弟有幸於今年&amp;nbsp;1/23（六）、1/24（日）、3/27（六）、3/28（日），在台中『靜宜大學應數系』開設嵌入式系統實作課程，課程宗旨欲藉由一步步的實作，揭露嵌入式系統開發細節。本課程嘗試避免提及過於深奧的理論和艱澀的名詞，以玩樂中學習並體驗嵌入式系統相關技術。除了實作外，也略微說明相關基礎知識，如：Compiler、&amp;nbsp;NEON&amp;nbsp;intrinsics 等。&lt;br /&gt;&lt;br /&gt;感謝各界參與，本課程已順利結束，有興趣者可自行下載上課簡報檔：&lt;br /&gt;&lt;a href="http://people.linux.org.tw/~fred/slides/training/hdplayer.pdf"&gt;http://people.linux.org.tw/~fred/slides/training/hdplayer.pdf&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-5450545522273767651?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/5450545522273767651/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/04/hd.html#comment-form' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5450545522273767651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5450545522273767651'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/04/hd.html' title='親手打造 HD 多媒體播放器，簡報上線'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-6439534239986342461</id><published>2010-04-02T03:35:00.002+08:00</published><updated>2010-04-02T03:41:32.123+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GSM/GPRS/HSDPA'/><category scheme='http://www.blogger.com/atom/ns#' term='AT Command'/><category scheme='http://www.blogger.com/atom/ns#' term='手機平台'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>自製垃圾簡訊自動發送器</title><content type='html'>這年頭自製廣告簡訊自動發送機相當容易，只要找到一張 3G 網卡，寫幾行簡單的 scripts 程式，就可以達成任務。在開始之前，可以先直接藉由指令對網卡下 AT Command，測試一下使用 3G 網卡發簡訊：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;echo -en "AT+CMGF=1\r" &amp;gt; /dev/ttyUSB0&lt;br /&gt;echo -en "AT+CMGS=\"09xxxxxxxx"\r" &amp;gt; /dev/ttyUSB0&lt;br /&gt;echo -en "You Got SMS.\032" &amp;gt; /dev/ttyUSB0&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;如此，目標手機門號應該能收到封內容為『You Got SMS.』的簡訊。不過這尚只是單純簡訊發送，離『垃圾簡訊自動發送機』仍有段距離，需做些加工使腳本程式可以讀入電話號碼清單。&lt;br /&gt;&lt;br /&gt;garbagesms.sh 詳細程式碼：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;#!/bin/bash&lt;br /&gt;&lt;br /&gt;if [ -n $1 ] || [ -n $2 ]; then&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;exit&lt;br /&gt;fi&lt;br /&gt;&lt;br /&gt;echo -en "AT+CMGF=1\r" &amp;gt; /dev/ttyUSB0&lt;br /&gt;&lt;br /&gt;while read NUMBER; do&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;echo -en "AT+CMGS=\"${NUMBER}"\r" &amp;gt; /dev/ttyUSB0&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;echo -en "${2}\032" &amp;gt; /dev/ttyUSB0&lt;br /&gt;done &amp;lt; $1&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;接著，準備一組號碼清單（例：number.lst），然後對所有號碼發送：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;./garbagesms.sh number.lst "混人百貨周年慶，本日垃圾簡訊大放送。"&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;本教學僅供研究參考，筆者未對程式做過實際測試。如因執行或濫用該程式而導致簡訊費用爆增或其他法律責任，請自行負責。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-6439534239986342461?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/6439534239986342461/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/04/blog-post.html#comment-form' title='3 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6439534239986342461'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6439534239986342461'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/04/blog-post.html' title='自製垃圾簡訊自動發送器'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-5981089146177867302</id><published>2010-03-23T10:03:00.006+08:00</published><updated>2010-03-23T10:29:58.867+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><title type='text'>Google TV 創世？還是 Sony 搞笑？</title><content type='html'>自幾天前 Google TV 被紐約時報揭露後，該新聞在世界各地被各大新聞媒體瘋狂轉述，亦有各式各樣不同的猜想和論點，尤其以電腦族群，一看到 Google 介入這市場，就連忙著拍手叫好，發表支持以及看好的個人論點。許多廠商也都嚇壞了，像無頭蒼蠅般亂竄，不知所措。不可否認，Google 這步棋下的很準確，未來的廣告和作業系統市佔率，勢必提升不少，也一瞬間扭轉了網路影片無版權的情勢。但是另一方面，Sony 大方的與 Google 分享這大餅，究竟所圖為何？『號稱世界上最開放作風的企業』對上『世界上最封閉作風的集團』，無論怎麼看都疑點重重，耐人尋味。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Google 造神運動再一次升華&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Google 近年來成長速度太快，又開創出很多過去被視為不可能的免費服務，如：全球化的極速搜尋引擎、超大的免費信箱、全球衛星空照圖、360度街景圖，一切如同將大海切成兩半般不可思議，讓許多人對 Google 產生崇拜和莫名的期待。因此，Google&amp;nbsp;這兩年挑戰各種霸主，像是激戰多年的瀏覽器之爭、手機產業和作業系統，都受眾人強力宣染之下，而不費吹灰之力蠶食。雖說佈局也花了相當大的功夫，但最後推手還是在於眾人們『對神的無上崇拜』。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;實現數位家庭，Sony 哪裡需要 Google？&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;網路上許多朋友都說著，這是 Google 和 Sony 進軍數位家庭的首戰，也不少報章媒體拿著各家數位機上盒的產品相比較，然後又說 Google TV 因為可以上網、Twitter、Facebook，和安裝眾多的 Android Applications，有著相當大的優勢。&lt;br /&gt;&lt;br /&gt;不過這種說法，似乎是直接遺忘了 xbox360 的存在，上述功能和機制微軟早已默默經營很久，內部的介面和架構，數年內也藉悄悄更新而趨於完善，除了有軟體商店，亦有付費機制，還有數不盡的娛樂資源。微軟已吸取多年前數位家庭失敗的經驗，早就重新振作佈局許久。&lt;br /&gt;&lt;br /&gt;然後，我們是否也忘了更重要的一件事？它的直接競爭對手『Sony PlayStation 3』跑哪去了？似乎也沒在這事件中露面。數位家庭創始者之一的 Sony，在多年後進軍數位家庭，這說法似乎有些荒謬。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Sony PlayStation v.s. Google TV&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;仔細想想，無論 xbox360 還是 PS3，它們在娛樂市場已有著深不可測的軟體資源，更有完整的架構和體系，Sony 何必和 Google 這樣毛都未長齊的小屁孩淌這渾水？Android 的軟體資源，在目前相對來說更是笑話，不足以構成對 Sony 的吸引力，更別說若是 Sony 真想打造硬體，也根本不需要 Intel 的支持。&lt;br /&gt;&lt;br /&gt;這很明顯透露出大公司多頭馬車的運作模式，如果該決策是由 Sony 電腦相關部門所下，這顯示 Sony&amp;nbsp;面對資訊業異常的澎漲而自亂陣腳，讓停滯不前或正在萎縮的電腦產業去決策和主導方向，敵我不分一頭殺進自家市場。當然，Sony 想多跨足資訊產業也可能是原因，反正 Google 和 Intel 也想以電腦廠商身份吃進家電市場，各懷鬼胎。&lt;br /&gt;&lt;br /&gt;而若是該事件是以 Sony 的版權產業主導，很顯然 Sony 也只是想抽回自身的版權費，並沒想這麼多。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;想振作萎靡的電視市場&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;一些報導中寫著，因為電視螢幕越來越不易經營，為突破現況， Sony 計劃在電視後接上 Google TV 裝置而出貨。令人不禁想問，這台 Intel 裝置成本多少錢？附加在毛利已經不高的電視身上，是否有助益？&lt;br /&gt;&lt;br /&gt;而且，若真的是如報導所說，依照 Sony 往例，一定會推個自家規格來個自綁自銷，其他廠商可能仍有相當大的空間。不過，如果這整件事是由 Google 主導，想走開放格式，倒是很令人懷疑 Sony會開放到什麼程度？其他家像 Samsung、LG可以使用這台 Google TV 嗎？身為頭號競爭者的 Sony&amp;nbsp;會願意？&lt;br /&gt;&lt;br /&gt;會的，除非 Sony 想放棄這硬體市場，用版權抽回利潤，畢竟 Sony 也是世界最大版權商之一。&lt;br /&gt;&lt;br /&gt;不過考慮到 Sony 也可能用版權制約其他家廠商搭配使用，其他廠家是否願意跟進？大家不跟進，Google TV 可能死路一條？&lt;br /&gt;&lt;br /&gt;太多可能的後果，都顯示 Sony 做出這決定的詭異，畢竟大家都不明瞭對他們而言，賺哪塊會最有利，至少可以確定的是，照報導上的去實現，會讓 Sony 有很大的損失，但這損失從哪補就不得而知了。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Google Android 的興旺&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;唯一肯定的是，Google Android 會藉此更為興旺，雖不知 Google 是只出了一個名，還是有真正參與開發，不過，這無疑的是 Android 拓展領域的機會。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;整理國內外報導後的心得後，在心中寫下了一個譜，許多尚不明朗的真相釐清之前，有太多疑點。不過不管是用什麼角度來看，這塊電腦業長年殺不進來的行業，不是 Google 和 Intel 隨便說殺就能殺的，就算有 Sony 在撐腰，畢竟產品設計哲學不是家電，沒這容易。反觀微軟的 xbox 也經歷了多少年，才慢慢有所成果，為大眾所接受。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-5981089146177867302?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/5981089146177867302/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/03/google-tv-sony.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5981089146177867302'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5981089146177867302'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/03/google-tv-sony.html' title='Google TV 創世？還是 Sony 搞笑？'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-3622148436113769291</id><published>2010-03-05T05:05:00.022+08:00</published><updated>2010-03-05T08:57:13.724+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='組合語言'/><category scheme='http://www.blogger.com/atom/ns#' term='0xdroid'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Embedded System'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux硬體驅動'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='Beagleboard'/><category scheme='http://www.blogger.com/atom/ns#' term='patch'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='sbc8100'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='devkit8000'/><title type='text'>Add Devkit8000 and SBC8100 initial support to 0xdroid</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://bits.ohloh.net/attachments/28125/0xdroid.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://bits.ohloh.net/attachments/28125/0xdroid.png" /&gt;&lt;/a&gt;&lt;/div&gt;As you know, I've done Android Eclair porting for Devkit8000 in the past, which is based on Embinux. It's a experimental work for passing time, I have no time to maintain and fix bugs friends reported after that. However, I think it is not good because the result will be getting lost as time goes by.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/0xdroid/"&gt;0xdroid&lt;/a&gt; is another Android distribution which is different from Embinux, its developer&amp;nbsp;&lt;a href="http://jserv.sayya.org/"&gt;Jim Huang(jserv)&lt;/a&gt;&amp;nbsp;who has contacted me a few months ago, and he hope that I can try porting 0xdroid on the Devkit8000. Actually, I am glad to make 0xdroid takes over my work, it is the best result for me.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://elinux.org/images/e/eb/SBC8100-DSP.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="184" src="http://elinux.org/images/e/eb/SBC8100-DSP.jpg" width="200" /&gt;&lt;/a&gt;&lt;a href="http://elinux.org/images/4/4d/Devkit8000_lcd.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="173" src="http://elinux.org/images/4/4d/Devkit8000_lcd.jpg" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Currently, I've done most works, 0xdroid can run on Devkit8000 with success. And also, My patches have been committed to 0xlab-devel mailing list.&amp;nbsp;Because I have another platform SBC8100 which is also produced by Embest, I've done works on that as well.&lt;br /&gt;&lt;br /&gt;You can see my patches from &lt;a href="http://groups.google.com.tw/group/0xlab-devel"&gt;0xlab-devel&lt;/a&gt; mailing list, or you can visit my website to download it directly:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://people.linux.org.tw/~fred/patches/0xdroid/embest/"&gt;http://people.linux.org.tw/~fred/patches/0xdroid/embest/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It's based on kernel source is 0xlab-kernel, you can get it from:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://gitorious.org/0xlab-kernel"&gt;http://gitorious.org/0xlab-kernel&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;My works includes:&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Support Embest Boards(Devkit8000 and SBC8100)&lt;/li&gt;&lt;li&gt;OMAP DSS2 Driver for display&lt;/li&gt;&lt;ul&gt;&lt;li&gt;4.3 inch Embest LCD Panel support (480x272 60Hz)&lt;/li&gt;&lt;li&gt;7 inch Embest LCD Panel support (800x480 60Hz)&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Touchscreen Controller support (ADS7846)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Works with correct axis&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Ethernet Device support (DM9000)&lt;/li&gt;&lt;li&gt;Keypad (TWL4030)&lt;/li&gt;&lt;li&gt;Force kernel into using machine ID of&amp;nbsp;Beagleboard&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Recently, I got a news that Devkit8000 has been registered in ARM machine table(&lt;a href="http://www.arm.linux.org.uk/developer/machines/"&gt;http://www.arm.linux.org.uk/developer/machines/&lt;/a&gt;), so Devkit8000 has official machine ID(2330) now (SBC8100 doesn't have yet). It means that kernel can start to support it with standard.&amp;nbsp;That's a good news, however, it will cause complications for us. The platform you have which still has old machine ID by default, you must patch and update the uboot to match official&amp;nbsp;kernel standard for working.&lt;br /&gt;&lt;br /&gt;For SBC8100 and most of Embest platforms, they are not registered in machine table cause it is not easy to maintain. That's why I do dirty hacks, forcing kernel into using machine ID of beagleboard when you selected "Embest board support" option. It's necessary for SBC8100, and it works with Devkit8000. You don't need to worry machine ID problem.&lt;br /&gt;&lt;br /&gt;Besides, it will fix a bug that sound device doesn't work on beagleboard clone.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Known Issue:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;OMAP Multiplexer support has a problem, it will cause kernel hangs, so we must disable OMAP_MUX. Due to SBC8100 has Wifi/Bluetooth module which is using MMC2(SDIO) with OMAP&amp;nbsp;Multiplexer, the module doesn't work right now.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;References:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://fred-zone.blogspot.com/2009/12/android-eclair-porting-for-devkit8000.html"&gt;http://fred-zone.blogspot.com/2009/12/android-eclair-porting-for-devkit8000.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://fred-zone.blogspot.com/2009/12/enable-ads7846-touchscreen-in-android.html"&gt;http://fred-zone.blogspot.com/2009/12/enable-ads7846-touchscreen-in-android.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://fred-zone.blogspot.com/2009/12/add-gpio-keys-support-for-devkit8000.html"&gt;http://fred-zone.blogspot.com/2009/12/add-gpio-keys-support-for-devkit8000.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-3622148436113769291?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/3622148436113769291/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/03/add-devkit8000-and-sbc8100-initial.html#comment-form' title='10 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3622148436113769291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/3622148436113769291'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/03/add-devkit8000-and-sbc8100-initial.html' title='Add Devkit8000 and SBC8100 initial support to 0xdroid'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-2364045156943507268</id><published>2010-03-03T04:24:00.002+08:00</published><updated>2010-03-03T04:27:22.106+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Emdebian'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Cross-compile'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Embedded System'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>Debian/Ubuntu 交叉編譯 - 函式庫相依性速解法</title><content type='html'>從來，交叉編譯（Cross-compile）就是一門苦差事，往往取得 Toolchain 之後，還必須自己編譯所需的所有函式庫，花費的時間甚巨，實在不值得。隨著 Debian/Ubuntu 跨平台支援趨於完整，開發和移植各平台程式之工作，已經不用再經歷過去那不足為外人道哉的編譯地獄。我們可以直接抓取不同硬體平台（如：ARM、MIPS）的套件，安裝在系統上供交叉編譯使用。因此，比起專注於 x86 下的其他系統（如：Fedora），Debian/Ubuntu 優異的跨平台支援和資源，更決定了跨平台開發者的效率以及產出品質。&lt;br /&gt;&lt;br /&gt;而較為傳統的方法，是建立一個新的 Rootfs&amp;nbsp;，包括完整目標平台的函式庫和編譯所需檔案，在編譯自己的程式時引入使用即可。如不想這樣麻煩，Debian/Ubuntu 包括了一支工具『apt-cross』可以將目標平台的套件，轉換成交叉編譯專用套件，然後安裝至目前的系統上。&lt;br /&gt;&lt;br /&gt;如同常見的 apt-get ，apt-cross 的使用方法極為相似，以安裝 ARM 架構下 的GTK+ Library 和開發用檔案為例（使用 Debian Sid 的 ARM 版套件）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;apt-cross -a armel -S sid -i libgtk2.0-0&lt;br /&gt;apt-cross -a armel -S sid -i libgtk2.0-dev&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;如此 apt-cross 會下載 ARM 版本的 GTK+ Library，然後轉換成&amp;nbsp;libgtk2.0-0-armel-cross 和&amp;nbsp;libgtk2.0-dev-armel-cross 兩個套件，並安裝至系統中。隨後，我們便可交叉編譯自己的 GTK+ 程式，arm-linux-gnueabi-gcc 會直接去引用這兩個套件內的檔案。&lt;br /&gt;&lt;br /&gt;隨帶一提，若執行 ./configure 時會發生&amp;nbsp;arm-linux-gnueabi-pkg-config 找不到，而自動選用系統上原生的 pkg-config 程式，常會造成編譯時關聯位置錯誤或找不到檔案。這通常是因為 pkg-config 選錯路徑，參考了系統上的編譯參數定義（正確行為應該去引用交叉編譯用的參數）。因此，我們可以在下 ./configure 前指定參考路徑，以解決此問題：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;export PKG_CONFIG_PATH=/usr/arm-linux-gnueabi/lib/pkgconfig&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;當然別的平台套件也會更新，我們可以用『-u』更新 Source.list，就如同在更新一般系統上套件一樣：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;apt-cross -a armel -S sid -u&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-2364045156943507268?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/2364045156943507268/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/03/debianubuntu.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2364045156943507268'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2364045156943507268'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/03/debianubuntu.html' title='Debian/Ubuntu 交叉編譯 - 函式庫相依性速解法'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-2575916390775865435</id><published>2010-03-01T06:52:00.006+08:00</published><updated>2010-03-01T07:10:57.123+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><title type='text'>夜，寂靜</title><content type='html'>也只有在獨自一人時，才能清醒的與自己對話，於大樹底下偷偷埋藏的思緒，此時會猛然湧上心頭，而靈魂末端的枝葉總自顧掉落。&lt;br /&gt;&lt;br /&gt;夜有多麼靜，心跳的聲音卻如此吵雜。惡耗了一整晚，解不清的工作乾脆直接扔在一旁，開始細數著在微弱燈光下忽明忽現的嗡嗡飛蚊，傾聽自己心中的聲音。&lt;br /&gt;&lt;br /&gt;驚呼，忽然一陣癢感襲來，將一切停滯的夜又搔動了起來。此時怒氣盛起，我面目掙獰如惡鬼一般，非與飛蚊理論究竟不可。&lt;br /&gt;&lt;br /&gt;『唉，你長得比較高大，血多到都可以把我淹死好幾輩子，而我只求貴人賞碗飯，讓我活命罷了，你又何必吝嗇？這世界死氣沉沉寂靜又孤獨，我們相伴不是甚好？』眼前那飛蚊老兄，收起翅膀，坐在眼前電腦螢幕上嘆息說著。&lt;br /&gt;&lt;br /&gt;『我並不介意血被吸，而是介意心情被打亂。平時的一切種種已經令我夠煩燥了，現在，只想不要被打擾的思考著。』我說。&lt;br /&gt;&lt;br /&gt;飛蚊老兄瞥著頭看了看我，似乎看出了什麼端昵。&lt;br /&gt;&lt;br /&gt;『哈哈，你不過就是不相信人而已，不想與外界接觸。就像我，我也不相信你心情好，就會讓我飽餐一頓，還不如我自己找機會大大咬上一口。』飛蚊老兄表現得一付很懂的樣子。&lt;br /&gt;&lt;br /&gt;『我在想的就是要不要再給一次機會，將信任再一次留給一個人。畢竟，曾經能信任，也花去了不少時間培養，但就是因為後來有一連串太多太久的猜疑，才讓我越來越痛苦，變了一個人似的。尤其很多話不敢說，更讓情況惡化。害我現在一切收進心底，只有在這時候，才會拿出來想想。』我說。&lt;br /&gt;&lt;br /&gt;『想通了，隨時都可以重新來過啊。只要你和其他人願意溝通，有什麼不好重建信任，就像現在我和你一樣的交談簡單，你我不都開朗許多。』說畢，飛蚊老兄飛了起來，搖搖晃晃的從燈光邊緣隱沒。&lt;br /&gt;&lt;br /&gt;『若是可以，我也想單單純純、平平淡淡的去維持這關係，不要再有什麼無聊的猜忌亂想。』我邊說，邊伸了一個懶腰，準備開始繼續工作。&lt;br /&gt;&lt;br /&gt;我話還沒講完，又感到一陣騷癢，反手『啪』一聲，滿手鮮血。仔細一看，原來，飛蚊老兄已死於我掌下，身驅四分五裂、鮮血淋漓，這似乎說明了人類永遠不可能與蚊蟲互相信任。&lt;br /&gt;&lt;br /&gt;接著，早晨的陽光也打亂這夜，一切思緒又沉回樹下的時光寶盒，等待著下一次的開啟。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-2575916390775865435?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/2575916390775865435/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/03/blog-post.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2575916390775865435'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2575916390775865435'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/03/blog-post.html' title='夜，寂靜'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-1738257626380866957</id><published>2010-02-21T06:26:00.001+08:00</published><updated>2010-02-21T06:27:10.374+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Clutter'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Embedded System'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='Beagleboard'/><category scheme='http://www.blogger.com/atom/ns#' term='devkit8000'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>Clutter EGLX Backend doesn't work correctly</title><content type='html'>Recently, our team work hard on ARM platform which is TI OMAP 3530, and also it makes us crazy actually. As you know that source code of TI PowerVR driver and SGX is not publicly available, there is no open source solution cause it's difficult to debug graphical stuffs.&lt;br /&gt;&lt;br /&gt;If you have tried to use Clutter with EGLX Backend, you might get only the blank stage and nothing works correctly.&amp;nbsp;It happened due to X server might still have things in its buffer to render when swap buffers.&lt;br /&gt;&lt;br /&gt;Here is a patch to solve this problem:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://people.linux.org.tw/~fred/patches/clutter-1.0_1.0.8-wait-for-vsync-before-SwapBuffers.patch"&gt;http://people.linux.org.tw/~fred/patches/clutter-1.0_1.0.8-wait-for-vsync-before-SwapBuffers.patch&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-1738257626380866957?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/1738257626380866957/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/02/clutter-eglx-backend-doesnt-work.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1738257626380866957'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1738257626380866957'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/02/clutter-eglx-backend-doesnt-work.html' title='Clutter EGLX Backend doesn&apos;t work correctly'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-4949631429320443491</id><published>2010-02-14T07:39:00.002+08:00</published><updated>2010-02-14T07:40:55.354+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='有趣新構思'/><category scheme='http://www.blogger.com/atom/ns#' term='MTK'/><category scheme='http://www.blogger.com/atom/ns#' term='手機平台'/><category scheme='http://www.blogger.com/atom/ns#' term='User Interface'/><title type='text'>模仿且沒有新意的 iPhone-like UI</title><content type='html'>為了應付即將開學的各項開支，到了春節依然不能停滯而必須努力工作。原本，只是為了工作單單在修某支程式的使用者界面，卻一時心血來潮，幫這選單 UI 添上了『加速度』的處理，更沒想到結果居然讓該 UI 的行為幾乎和 Apple iPhone 一模一樣。就這樣，除夕夜一個晚上，都在玩弄這支程式中不知不覺度過了，半點錢都沒有賭到，歲到是守得很徹底。為了紀念這隻小年獸，就用手機錄下成果。（沒有專業器材，畫質不佳還請多包涵！）&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;object height="344" width="425"&gt;&lt;param name="movie" value="http://www.youtube.com/v/2YKN4uIkr0c&amp;hl=zh_TW&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/2YKN4uIkr0c&amp;hl=zh_TW&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-4949631429320443491?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/4949631429320443491/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/02/iphone-like-ui.html#comment-form' title='3 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/4949631429320443491'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/4949631429320443491'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/02/iphone-like-ui.html' title='模仿且沒有新意的 iPhone-like UI'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-8675584483610054940</id><published>2010-02-12T22:11:00.001+08:00</published><updated>2010-02-12T22:12:56.813+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><title type='text'>用 C 語言處理常見的旗標位元運算</title><content type='html'>正如國中理化課所說，電子產品都是由滿滿『0、1』所構成，大家早就都了解這件事。但現實上，由於要求的功能愈疊愈多，低階的運算早就被眾人所忽略。無論大家如何忙著處理物件的繼承問題，又或者是因時間太多而研究『1+1=2 慢吞吞語言』，低階的運算還是依然沒有消失，反而更為重要。&lt;br /&gt;&lt;br /&gt;位元運算不外乎就是『AND、OR、XOR...』等邏輯概念，主要目的是把『1 變 0』、『0 變 1』或有條件維持不變，在程式中比較常看到的地方，通常會在硬體驅動程式（Driver）之中。而在高階應用程式中，也往往因為要旗標條件的判斷，也會看得到其存在，如 Linux 下的檔案權限。&lt;br /&gt;&lt;br /&gt;一個更貼切的例子，假設我們現在寫一個滑鼠驅動程式，我們要怎麼設計資料結構，讓應用程式得知用戶（User）按了哪幾個鍵？用戶可能是一次只按『一個鍵』，也可能一次按『左右兩個鍵』，更有可能按『左鍵和中間鍵』，有多種組合存在。&lt;br /&gt;&lt;br /&gt;一般初學程式者可能會用 boolean 或 int 這樣寫：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;struct _mouse_event {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int&amp;nbsp;button1;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int&amp;nbsp;button2;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int&amp;nbsp;button3;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;...&lt;br /&gt;};&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;但明明只是『0、1』，為何要用到 int 資料形態？除了浪費記憶體，運算上也整整慢了好幾個 CPU Clock。所以，多數程式開發者碰到此類問題，會比較偏好以位元為最小單位來寫：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;enum {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;MOUSE_LEFT_BUTTON = (1 &amp;lt;&amp;lt; 0),&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;MOUSE_MIDDLE_BUTTON = (1 &amp;lt;&amp;lt; 1),&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;MOUSE_RIGHT_BUTTON = (1 &amp;lt;&amp;lt; 2)&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;struct _mouse_event&amp;nbsp;{&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int&amp;nbsp;button;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;...&lt;br /&gt;};&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;當設定哪幾個鍵被按下，只要用位元運算設定旗標就可以了：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;struct _mouse_event mouse;&lt;br /&gt;mouse.button |=&amp;nbsp;MOUSE_LEFT_BUTTON;&lt;br /&gt;mouse.button |=&amp;nbsp;MOUSE_LEFT_BUTTON |&amp;nbsp;MOUSE_RIGHT_BUTTON;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;當然，反向設定也是可以：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;mouse.button &amp;amp;= ~(MOUSE_MIDDLE_BUTTON);&lt;br /&gt;mouse.button &amp;amp;= ~(MOUSE_MIDDLE_BUTTON |&amp;nbsp;MOUSE_RIGHT_BUTTON);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;以前小時候不懂事，又被很多高階 API 保護得很好，常被驅動程式中的位元運算嚇哭，其實，雖然位元運算看起來可以千變萬化，但就那幾種用法最常用而已。在此筆記之，讓大家一起哭。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-8675584483610054940?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/8675584483610054940/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/02/c.html#comment-form' title='3 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/8675584483610054940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/8675584483610054940'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/02/c.html' title='用 C 語言處理常見的旗標位元運算'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-1616902843568670818</id><published>2010-01-28T16:44:00.004+08:00</published><updated>2010-01-29T01:00:15.142+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='心得分享、講座'/><title type='text'>Apple iPad 所帶來的省思</title><content type='html'>就在睡夢中，地球另一端的 Apple 推出了新產品『&lt;a href="http://www.apple.com/ipad/"&gt;iPad&lt;/a&gt;』，傳說中的平板電腦終於亮相，乍看之下 iPhone/iPod 的放大版誕生了，似乎沒什麼特別之處。不過一旦到了這種尺寸，許多人不免會拿 iPad 和國內近來炒翻天的電子書（ebook）相比較。確實，用電腦的思維去看這產品是不太恰當的，會缺少許多電腦狂熱族群要的功能，但若單以電子書的角度來看，這次 Apple 賞了我們一個大巴掌。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;國內廠商依然趕不上的 UI 設計&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;以前電子產品的設計，因為技術限制，只求達到目的，不注重人們的使用經驗。但是，這樣的概念已經慢慢不適用於現在，許多電腦廠商卻仍抱著做出功能即可的心態，才導致功能不斷增加，價格不斷跌落的惡性循環。科幻電影和小說的一切是人們共同忡景，缺少改善使用經驗的努力，就等於跟千千萬萬人們作對一樣。&lt;br /&gt;&lt;br /&gt;不可否認，就算 iPhone 第一代發表至今少說也有三年之久，但仍然沒有第二家廠商能做出能與之相敵的界面。就算單單是將 iPhone 的界面直接放大製成 iPad 而不做任何變動，不論流暢度和使用觀感，依然領先群雄。&lt;br /&gt;&lt;br /&gt;在 iPad 宣傳影片中，展示了幾幕電子書的應用，Apple 嘗試將書本的感覺和閱讀習慣做到冰冷的玻璃裡面去，翻頁操作也好、翻頁過場效果也好，讓人感到不突兀、不陌生、不多餘，令人感受到有其細膩的設計。雖然並不是全部都很完美，但某些部份確實讓人能感受到友善。&lt;br /&gt;&lt;br /&gt;我們可以試想，同樣的硬體，若是交給國內的廠商來設計 UI&amp;nbsp;，最後產品會變得多麼可笑？我們是不是該花點心思在使用者經驗上？難到就連照抄都抄不出來？&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;廠商的藉口：特效不重要！&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;講到 UI&amp;nbsp;、使用者經驗，許多廠商往往會說特效不重要，試圖運用詭辯，一刀將 Apple 的優點通通斬殺。撇開今天的產品，回想第一代 iPod，當時也沒什麼動畫和特效，一個簡單的圓形觸控，就已滿足了許多人的使用經驗，至今回頭來看，我們依然能感受到其 UI 的友善。&lt;br /&gt;&lt;br /&gt;那麼，特效不重要是廠商們做不到的藉口？還是因未深思熟慮 UI 設計的無知之言？&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;專注內容格式的綁定好無聊&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;有鑒於 Microsoft DOC/PPT 和 Adobe PDF/Flash 的成功，全天下的人都妄想製作自家的專利格式，甚至在電子書市場，想要透過格式通殺產業。雖然格式是最後成功和賺錢的關鍵，但尚未被使用者接受前，可是一無是處，與其整天想抽格式費用，還不如先把產品做好。&lt;br /&gt;&lt;br /&gt;我們看到 Apple Store 的成功，格式的綁定成功，不是在於他格式訂的好，而是他產品品質做的好，以致有眾多路人甲接受。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;或許很多人覺得 Apple iPad 是騙錢的東西，但事實上，的確沒有其他產品可與之相競爭，就算只是換個包裝就上市，同業眾廠也只能眼紅看著它搶錢。&lt;br /&gt;&lt;br /&gt;話說回來，因為最近案子太忙，根本沒空將 MTK 接著完成，心中想要做的 Multi-touch UI Toolkits，到現在都沒辦法好好坐下來寫呀！雖有很多自我反省，卻缺少時間和金錢完成，遺憾！&lt;br /&gt;&lt;br /&gt;此外，若有廠商想要做和 iPad 一樣的產品，可以來找 ULLab 呀！身為研發人員，也妄想可以設計些特別又前衛的產品！只可惜總苦無機會！！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-1616902843568670818?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/1616902843568670818/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/01/apple-ipad.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1616902843568670818'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/1616902843568670818'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/01/apple-ipad.html' title='Apple iPad 所帶來的省思'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-5718326350700720233</id><published>2010-01-15T16:50:00.000+08:00</published><updated>2010-01-15T16:50:40.037+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='程式心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux硬體驅動'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><title type='text'>入門級 Mouse Linux Kernel Driver</title><content type='html'>每當說起 Linux Kernel Driver 入門，就不免提到如何寫個&amp;nbsp;Hello World 級的 Module，這樣的第一支程式，除了可供 Linux Kernel 動態載入和卸載，似乎是一點用處也沒有。與一般應用程式不同，開發&amp;nbsp;Linux Driver 最大的門檻不在於如何撰寫出 Module，而是如何設計系統架構與硬體兩者間的橋樑。其中懂得如何控制和結合 Kernel 內各種機制更是重點，最複雜的莫過於此。&lt;br /&gt;&lt;br /&gt;這邊有個 Mouse Kernel Driver，會在 Kernel 上新增一個虛擬滑鼠裝置，然後使用者可從&amp;nbsp;sysfs 控制該虛擬滑鼠（virmouse.c）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;/*&lt;br /&gt;&amp;nbsp;* A Virtual Mouse Driver to send fake events from userspace.&lt;br /&gt;&amp;nbsp;*&lt;br /&gt;&amp;nbsp;* Written by Fred Chien &amp;lt;fred@ullab.org&amp;gt;&lt;br /&gt;&amp;nbsp;*&lt;br /&gt;&amp;nbsp;*/&lt;br /&gt;#include &amp;lt;linux/fs.h&amp;gt;&lt;br /&gt;#include &amp;lt;asm/uaccess.h&amp;gt;&lt;br /&gt;#include &amp;lt;linux/pci.h&amp;gt;&lt;br /&gt;#include &amp;lt;linux/input.h&amp;gt;&lt;br /&gt;#include &amp;lt;linux/platform_device.h&amp;gt;&lt;br /&gt;&lt;br /&gt;struct input_dev *virmouse_input_dev;&lt;br /&gt;static struct platform_device *virmouse_dev; /* Device structure */&lt;br /&gt;&lt;br /&gt;/* Sysfs method to input simulated coordinates */&lt;br /&gt;static ssize_t write_virmouse(struct device *dev,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;struct device_attribute *attr,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;const char *buffer, size_t count)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;int x, y, key;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* parsing input data */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;sscanf(buffer, "%d%d%d", &amp;amp;x, &amp;amp;y, &amp;amp;key);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* Report relative coordinates */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;input_report_rel(virmouse_input_dev, REL_X, x);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;input_report_rel(virmouse_input_dev, REL_Y, y);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;printk ("virmouse_event: X:%d Y:%d %d\n", x, y, key);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* Report key event */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (key&amp;gt;0) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (key==1)&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;input_report_key(virmouse_input_dev, BTN_LEFT, 1);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;else if (key==2)&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;input_report_key(virmouse_input_dev, BTN_MIDDLE, 1);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;else&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;input_report_key(virmouse_input_dev, BTN_RIGHT, 1);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;input_sync(virmouse_input_dev);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return count;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Attach the sysfs write method */&lt;br /&gt;DEVICE_ATTR(vmevent, 0644, NULL, write_virmouse);&lt;br /&gt;&lt;br /&gt;/* Attribute Descriptor */&lt;br /&gt;static struct attribute *virmouse_attrs[] = {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;amp;dev_attr_vmevent.attr,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;NULL&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;/* Attribute group */&lt;br /&gt;static struct attribute_group virmouse_attr_group = {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;.attrs = virmouse_attrs,&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;/* Driver Initializing */&lt;br /&gt;int __init virmouse_init(void)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* Register a platform device */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;virmouse_dev = platform_device_register_simple("virmouse", -1, NULL, 0);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (IS_ERR(virmouse_dev)){&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;printk ("virmouse_init: error\n");&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return PTR_ERR(virmouse_dev);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* Create a sysfs node to read simulated coordinates */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;sysfs_create_group(&amp;amp;virmouse_dev-&amp;gt;dev.kobj, &amp;amp;virmouse_attr_group);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* Allocate an input device data structure */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;virmouse_input_dev = input_allocate_device();&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;if (!virmouse_input_dev) {&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;printk("Bad input_allocate_device()\n");&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return -ENOMEM;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* Announce that the virtual mouse will generate relative coordinates */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;set_bit(EV_REL, virmouse_input_dev-&amp;gt;evbit);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;set_bit(REL_X, virmouse_input_dev-&amp;gt;relbit);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;set_bit(REL_Y, virmouse_input_dev-&amp;gt;relbit);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;set_bit(REL_WHEEL, virmouse_input_dev-&amp;gt;relbit);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* Announce key event */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;set_bit(EV_KEY, virmouse_input_dev-&amp;gt;evbit);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;set_bit(BTN_LEFT, virmouse_input_dev-&amp;gt;keybit);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;set_bit(BTN_MIDDLE, virmouse_input_dev-&amp;gt;keybit);&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;set_bit(BTN_RIGHT, virmouse_input_dev-&amp;gt;keybit);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* Register with the input subsystem */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;input_register_device(virmouse_input_dev);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* print messages in the dmesg */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;printk("Virtual Mouse Driver Initialized.\n");&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;/* Driver Uninitializing */&lt;br /&gt;void virmouse_uninit(void)&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* Unregister from the input subsystem */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;input_unregister_device(virmouse_input_dev);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* Remove sysfs node */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;sysfs_remove_group(&amp;amp;virmouse_dev-&amp;gt;dev.kobj, &amp;amp;virmouse_attr_group);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/* Unregister driver */&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;platform_device_unregister(virmouse_dev);&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;return;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;module_init(virmouse_init);&lt;br /&gt;module_exit(virmouse_uninit);&lt;br /&gt;&lt;br /&gt;MODULE_AUTHOR("Fred Chien &amp;lt;fred@ullab.org&amp;gt;");&lt;br /&gt;MODULE_DESCRIPTION("Virtual Mouse Driver");&lt;br /&gt;MODULE_LICENSE("GPL");&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;然後建立 Makefile：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;obj-m += virmouse.o&lt;br /&gt;&lt;br /&gt;KERNELDIR ?= /lib/modules/$(shell uname -r)/build&lt;br /&gt;PWD  := $(shell pwd)&lt;br /&gt;&lt;br /&gt;default:&lt;br /&gt;        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules&lt;br /&gt;clean:&lt;br /&gt;        @rm -fr *.ko *.o&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;編譯（需要安裝 Kernel header）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;$ make&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;載入：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;$ sudo insmod virmouse.ko&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;測試：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;# 先切換成 root&lt;br /&gt;$ sudo su -&lt;br /&gt;# 滑鼠 X軸移動&amp;nbsp;168，Y軸移動 68，0 代表純移動不點擊&lt;br /&gt;$ echo "168 68 0" &amp;gt;&amp;nbsp;/sys/devices/platform/virmouse/vmevent&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;此 Driver 會先註冊成 evdev input 的滑鼠裝置，然後在 sysfs 並建立 group 和 vmevent 檔，Userspace 下的應用程式可以發送命令到&amp;nbsp;vmevent&amp;nbsp;使滑鼠移動或點擊左右中鍵。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記：&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;此程式極為簡單，因此省略程式碼的說明，讀者直接看 source code 應該就能明瞭。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-5718326350700720233?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/5718326350700720233/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/01/mouse-linux-kernel-driver.html#comment-form' title='3 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5718326350700720233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5718326350700720233'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/01/mouse-linux-kernel-driver.html' title='入門級 Mouse Linux Kernel Driver'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-7006823451840282206</id><published>2010-01-13T07:35:00.004+08:00</published><updated>2010-01-13T07:39:54.461+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Embedded System'/><category scheme='http://www.blogger.com/atom/ns#' term='心得分享、講座'/><category scheme='http://www.blogger.com/atom/ns#' term='Beagleboard'/><category scheme='http://www.blogger.com/atom/ns#' term='devkit8000'/><title type='text'>親手打造 HD 多媒體播放器（上）</title><content type='html'>本月 1/23（六）、1/24（日）兩天，小弟將於台中的『靜宜大學應數系』開設嵌入式系統課程。一如課程名稱『&lt;a href="http://www.excellent.pu.edu.tw/news_detail.php?sid=0&amp;amp;id=1366"&gt;親手打造 HD 多媒體播放器（上）&lt;/a&gt;』，將試圖發揮 TI OMAP 353x 的威力，打造多媒體播放器。近年來『&lt;a href="http://beagleboard.org/"&gt;Beagleboard&lt;/a&gt;』面世，其低廉的價格及強大的硬體效能，在嵌入式系統領域造成不小的影響，使許多人可輕易入手開發板，並在上面做各式各樣的應用。在網路社群中，beagleboard 也因此廣為受歡迎，相關文件齊全，各種技術支援都能輕易取得。&lt;br /&gt;&lt;br /&gt;我們將選用&amp;nbsp;Beagleboard 的複製品『&lt;a href="http://elinux.org/DevKit8000"&gt;Devkit8000&lt;/a&gt;』做為硬體平台，硬體規格和設計幾乎完全與 Beagleboard 相同。之所以選用 Devkit8000，除了因為硬體設計和 Beagleboard 一樣之外，其各種接頭支援相當完整，不用再自行焊接，對於軟體開發人員來說，比 Beagleboard 來的方便許多。&lt;br /&gt;&lt;br /&gt;此課程總共分上、下兩部份，上半部從嵌入式系統基礎和認識講起，將談及嵌入式系統現況與未來展望、開發環境架設、嵌入式 Linux 基礎架構，適合入門者參加。由於嵌入式系統以實作經驗為重，課程將以實作為主進行，如題『親手打造』一詞，藉自己動手做以增加實務經驗。&lt;br /&gt;&lt;br /&gt;註：靜宜大學將提供學生開發板使用，只需帶著玩樂的心前來即可。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;活動詳細訊息&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;活動名稱：嵌入式系統short courses&lt;br /&gt;活動網址：&lt;a href="http://www.excellent.pu.edu.tw/news_detail.php?sid=0&amp;amp;id=1366"&gt;http://www.excellent.pu.edu.tw/news_detail.php?sid=0&amp;amp;id=1366&lt;/a&gt;&lt;br /&gt;活動目標：&lt;br /&gt;&lt;ol&gt;&lt;li&gt;嵌入式系統開發系統介紹，了解嵌入式系統的現況與未來展望&lt;/li&gt;&lt;li&gt;做中學--學習嵌入式系統的開發環境佈署與建置&lt;/li&gt;&lt;/ol&gt;活動日期：1/23　09:00-16:00&lt;br /&gt;演講者：于昌永老師、錢逢祥工程師&lt;br /&gt;地點：靜安425&lt;br /&gt;對象：全校師生、育成培育廠商&lt;br /&gt;人數：30人&lt;br /&gt;承辦單位：應用數學系&lt;br /&gt;參考資料：&lt;br /&gt;&lt;br /&gt;Devkit8000：&lt;br /&gt;&lt;a href="http://elinux.org/DevKit8000"&gt;http://elinux.org/DevKit8000&lt;/a&gt;&lt;br /&gt;&lt;a href="http://fred-zone.blogspot.com/2009/12/android-eclair-porting-for-devkit8000.html"&gt;http://fred-zone.blogspot.com/2009/12/android-eclair-porting-for-devkit8000.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://fred-zone.blogspot.com/2009/12/enable-ads7846-touchscreen-in-android.html"&gt;http://fred-zone.blogspot.com/2009/12/enable-ads7846-touchscreen-in-android.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://fred-zone.blogspot.com/2009/12/add-gpio-keys-support-for-devkit8000.html"&gt;http://fred-zone.blogspot.com/2009/12/add-gpio-keys-support-for-devkit8000.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Beagleboard:&lt;br /&gt;&lt;a href="http://beagleboard.org/"&gt;http://beagleboard.org/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-7006823451840282206?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/7006823451840282206/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/01/hd.html#comment-form' title='4 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/7006823451840282206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/7006823451840282206'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/01/hd.html' title='親手打造 HD 多媒體播放器（上）'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-2494347982796212040</id><published>2010-01-08T23:21:00.005+08:00</published><updated>2010-01-08T23:33:24.881+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ULLab'/><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><title type='text'>長大吧！台客實驗室(ULLab)</title><content type='html'>回顧數個月前『&lt;a href="http://fred-zone.blogspot.com/2009/10/ullab.html"&gt;專做有趣玩夜兒的台客實驗室 - ULLAB&lt;/a&gt;』，幾個朋友因臭味相投而成立了&amp;nbsp;『&lt;a href="http://ullab.org/"&gt;ULLab&lt;/a&gt;』。這是個非營利性質的自發性組織，參與者都希望藉由致力於自由軟體開發，多多少少改變這世界，並以『宅宅發卡給正妹』為目標而努力前進。慶幸，經過數個月的努力，有一些小成果，陸陸續續也有愈來愈多人注意到我們的有趣玩夜兒。&lt;br /&gt;&lt;br /&gt;由於 ULLab 成員似乎人人都有著不為外人而知的經濟壓力，悲慘的背景彷彿已成為必要的履歷項目。過去這些時間，大家總是私下各自尋找賺錢活命的機會，有人接案，有人上班又兼職，更有人大學研究所念不完，欲哭無淚。絕大數時候，每個人都過著自己的忙錄人生，只在空閒時才投入自由軟體的開發。&lt;br /&gt;&lt;br /&gt;當初完全沒有料想到，在近幾個月的社群經營以及國內外活動曝光後（&lt;a href="http://coscup.org/"&gt;COSCUP&lt;/a&gt;、&lt;a href="http://gnome.asia/"&gt;GNOME.Asia Summit&lt;/a&gt;、&lt;a href="http://www.oss.org.tw/contest/index.html"&gt;Open Source Contest 2009&lt;/a&gt;），開始有人想委託 ULLab，其中有一些零星的外包，也有進一步的合作研發，甚至是長期的顧問交流。對於我們這些負有沉重壓力的人來說，未嘗不是一件好事。許多好心的廠商藉由合作和外包，資助我們繼續走下去，替我們免去了不少負擔。也感謝一些學校單位，對我們的 Open Source Project 的贊助，無論是設備還是人力。&lt;br /&gt;&lt;br /&gt;說來慚愧，也許是因為成員們普遍缺錢，人人趕工搶糧，所以讓合作廠商都覺得效率不算差，願意給予更多機會，讓我們貢獻微薄意見，有時甚至讓我們領導其產品發展。而有些廠商常口頭上過於抬舉，其實，我們只是因為過去挫敗的比別人多，現在比其他人更注意什麼應該避免，什麼應該著重而已。&lt;br /&gt;&lt;br /&gt;不過這樣的經歷，使 ULLab 幾乎無所不碰，從 Linux Distribution、Performance Tunning、Application Design、Driver Porting、Customization、Embedded System&amp;nbsp;甚至是 Google Android，除了可以玩到很多『怪產品』之外，更吸收了不少來自世界各地的第一線資訊，大開了眼界，也對許多產品有了重新省思的眼光。真的很開心，因為能接觸到很多特別的新東西，是身為不起眼的宅宅敲鍵盤工人所夢寐以求。&lt;br /&gt;&lt;br /&gt;這兩個月，因為許多的合作計劃和關係成長，其收入已經慢慢的能支持 ULLab 成員們大部份開銷。再者，十二月份天外飛來一筆比賽獎金，促使伙伴們想進一步成為真正攜手努力的團隊，以全心投入初衷。此決定讓 ULLab 開始籌備公司成立，一方面藉由公司提供自由軟體各種服務，讓成員們養家活口，另一方面，也持續經營原先非營利的自由軟體開發，朝『改變世界』之遠大目標前進。&lt;br /&gt;&lt;br /&gt;有幸，隨著 2010 年的煙火綻放，開始了 ULLab 的創始元年，又如年份『2，010』所示，從 ULLab 最早的雙人搭擋演變到今天這番局面，相當值得紀念。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;ULLab 目前的事情相當多，大家都忙到不可開交，我們首先歡迎家境有困難和經濟壓力沉重的伙伴加入，此外，無論你是在學學生或是有志者，甚至是有心創業者亦歡迎加入創意軟體開發的行列。&lt;br /&gt;&lt;br /&gt;當然，ULLab 仍會持續開發自由軟體，歡迎各界加入一同努力。&lt;br /&gt;&lt;br /&gt;再補充一點，基於宅宅們的希望，更期待美女們的加入。:-P&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-2494347982796212040?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/2494347982796212040/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/01/ullab.html#comment-form' title='3 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2494347982796212040'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2494347982796212040'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/01/ullab.html' title='長大吧！台客實驗室(ULLab)'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-7092769264522559471</id><published>2010-01-06T10:33:00.001+08:00</published><updated>2010-01-06T10:34:19.734+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Embedded System'/><category scheme='http://www.blogger.com/atom/ns#' term='Debian'/><title type='text'>Debian Sid nfs-kernel-server 1.2.1-1 重大問題</title><content type='html'>對於長期開發 Embedded System 的人，Debian 真的是太方便了，可以毫不費力的開發多種平台，又可隨自己高興而輕鬆升級該平台上的各種套件，不再只能死板板停留在該平台的官方 BSP 和 Toolchian（有些 Toolchain 充滿了 Bugs，常讓人求生不得求死不能），完全跳出過去 Embedded System 軟體版本總是太老舊的框框。無論缺什麼東西，輕鬆的幾行 apt-cross 指令，就可以確保 corss-compile 的順利，甚至，新版的 GCC compiler 都任君選用。&lt;br /&gt;&lt;br /&gt;開發 Embedded System，最常用到的就是 NFS，在最近的 Debian Sid 中，套件『&amp;nbsp;nfs-kernel-server 1.2.1-1&amp;nbsp;』有重大問題（Grave Bug），會讓 NFS 無法順利啟動：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;$ /etc/init.d/nfs-kernel-server start&lt;br /&gt;Exporting directories for NFS kernel daemon....&lt;br /&gt;Starting NFS kernel daemon: nfsd mountd failed!&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;目前已有人回報此 Bug 至官方（可參閱：&lt;a href="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=562910"&gt;http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=562910&lt;/a&gt;），在尚無解的情況下，可先 Downgrade 先恢復 NFS 的功能，畢竟工作可不能停：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;$ wget http://ftp.tw.debian.org/debian/pool/main/n/nfs-utils/nfs-kernel-server_1.2.0-4.1_i386.deb&lt;br /&gt;$ dpkg -i&amp;nbsp;nfs-kernel-server_1.2.0-4.1_i386.deb&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;該版本是從 Debian Testing 抓回來的舊版套件，在替換後 NFS 就可恢復正常運作。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-7092769264522559471?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/7092769264522559471/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/01/debian-sid-nfs-kernel-server-121-1.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/7092769264522559471'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/7092769264522559471'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/01/debian-sid-nfs-kernel-server-121-1.html' title='Debian Sid nfs-kernel-server 1.2.1-1 重大問題'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-493860776944688097</id><published>2010-01-01T06:19:00.002+08:00</published><updated>2010-01-01T06:24:22.361+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><title type='text'>2010 年的愛</title><content type='html'>一年時間又匆匆而過，09年對我來說是個很特別的一年，因為心境在這年有了莫大的轉變，有特別的際遇，有患難的真情，也有人生不可缺少的挫折。找到了能一同共事的同伴，遇見了值得我在百忙之中還能抽空想念的人，有夢想、有困境、也有快樂，這一年我不缺任何東西，起起伏伏更充實了自己。曾以為世界末日要來臨，曾以為能穩穩走入人生另一個殿堂，曾以為自己正遊戲人間，曾以為誤會永遠解釋不清，但直到最後，依然只覺得在做著不是屬於自己的夢，雖夢見成為一隻蝴蝶，卻也不過是模糊不清的片斷殘影。&lt;br /&gt;&lt;br /&gt;雖然都在年年相同的慶祝活動中渡過跨年一刻，但 2010 年卻是不一樣的意義，它代表了另一個十年的開端，也代表了一段殘章的結束，當回想起千禧年前的事，彷彿其又加上了一層厚重的灰塵，更難以翻塵觸碰。所有看似新的記憶，也隨著09的句點而被包裹起來，隔了一道看不見的煙幕，有莫名的距離感。&lt;br /&gt;&lt;br /&gt;我對2010年有什麼自我期許呢？或許更該說我對這未來的十年有何期望？或許，十年之後，我能抱著已完成的夢回頭看今天的我，又或許我抱著的是白白胖胖的小鬼回頭嘲笑今天的自己，也或許我可能不再有機會複習我的人生，悄悄帶走別人永遠取不走的財富。&lt;br /&gt;&lt;br /&gt;今年，我不給自己過於明確的目標，隨心所遇而隨心所欲，期望找到 2010 年的愛。Find My Way Home! On My Way Home! 行十年路，回家。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-493860776944688097?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/493860776944688097/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2010/01/2010.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/493860776944688097'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/493860776944688097'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2010/01/2010.html' title='2010 年的愛'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-4247679147598183573</id><published>2009-12-26T17:40:00.002+08:00</published><updated>2009-12-26T19:16:49.365+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Chrome OS'/><category scheme='http://www.blogger.com/atom/ns#' term='心情筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><title type='text'>Google Chrome OS 不是長生不老丹</title><content type='html'>回顧舊文『&lt;a href="http://fred-zone.blogspot.com/2009/04/android.html"&gt;Android 不是萬靈丹&lt;/a&gt;』，因為筆者既不是股票分析師也不是專業的市場分析師，所以看見半年前的猜測一一驗證，令自己感到多少有些欣慰。今天，又看著許多廠商就像當初 Google Android 出來一樣，瘋狂投入著這未知的新領域，有多少認同也多少有不同的意見，因此對於 Google Chrome OS 也有著一些想法。而股票部份就不用再說了，有興趣的人可以回顧舊文。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;你的產品是電腦&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;就如同一般人認為『電腦不等於計算機』，既然你的『輕量化』產品有大螢幕、鍵盤還有可開合的機殼，那麼，無論說破了嘴，消費者依然認定這是台『電腦』。所以，對於消費者來說，電腦該要有什麼用途？不外乎上網、文書、玩遊戲。消費者的期望更是能安裝常用軟體，將家中電腦能夠帶著走。那麼 Windows 肯定還是唯一解。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;我的產品是貴桑桑計算機&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Chrome OS 說穿了就是只能上網，看看網頁、收發信、PDA功能、看網路上小影片，講更簡單點就是功能單純的計算機。而再貴的計算機，也不會超過一千元台幣，相信念工科出來的朋友都知道。&lt;br /&gt;&lt;br /&gt;或許有人不滿意這貶低的說法，因為 Chrome OS 可以上網處理公務，它其實更接近 PDA 產品。但是，現在有哪一台 PDA 可以賣到一萬八？那再次思考，這台搭配了 Chrome OS 有著大螢幕、鍵盤、可開合機殼的『計算機』要賣多少錢可以讓人接受？&lt;br /&gt;&lt;br /&gt;&lt;b&gt;電腦廠商賣出來的東西就是電腦&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;無論電腦廠商如何定位自家產品，賣出來的東西，一定會被消費者認定為電腦類產品。真的想賺這生意的廠商，或許跳出來開一家名稱俗氣的『電子辭典』公司，標榜電子辭典來賣，可能比較適合。&lt;br /&gt;&lt;br /&gt;&lt;b&gt;用 ARM 降低成本很有限&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;對於上網功能來說，一個重要的元件就是 Flash，尤其在這 Facebook 風行的時代，沒有 Flash 根本不能稱之為有上網功能。由於 Flash Player 非 Open Source&amp;nbsp;，使得 ARM 上面根本不可能使用 PC 上的 Flash player，若是使用 Open Source 版本的實作，效能又非常低落且支援不完整。&lt;br /&gt;&lt;br /&gt;雖然 Adobe 已經宣布有 ARM 的 Flash Player 支援，但也限制平台在 ARM11 和 Cortex-A處理器系列中的 ARMv6 和 ARMv7（更簡單說法就是&amp;nbsp;Cortex-A8），而這些都是屬於最新的晶片，價格自然不低，雖然最後產品整體成本比 x86 便宜很多，但等到消費者手上，也是昂貴不堪，最少也是 PSP 和 NDSL 的價格以上。如此，消費者會買單嗎？&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;Google Android 沒有&lt;span style="font-weight: normal;"&gt;&lt;b&gt;的優勢&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;Google Chrome OS 不像 Android&amp;nbsp;有著全然不同的系統架構，因此，過去所有基於 Linux 開發的軟體，都能很輕易移植到上面，就某方面看來，Google Chrome OS 更是一個 Embedded System 的不錯選擇，必要時將瀏覽器去除，也可能會是一個好的平台也說不定。&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;很明顯的，這波 Google Chrome OS 並沒有之前 Android 這麼火熱，或許大家都在觀望，不想再重蹈覆轍。&lt;br /&gt;&lt;br /&gt;而最近手上有不少廠商的需求&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;，都是看準 Chrome OS 的輕量、&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;單純或背後的商標&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;，有些人打算把 Chrome OS 的 Chrome 閹掉&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;，有些人想做客制化&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;，也有很多人根本不把它當成 Netbook 的救星&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;。&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;Google 試圖想要所有人幫他推廣自家線上產品&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;，但有很多廠商就不吃這套&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;，有趣的現像&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;。&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;反向思考&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;，Yahoo! 是否也有客制化 Chrome OS 然後 Remark 成 Yahrome OS 的需求呢？&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-4247679147598183573?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/4247679147598183573/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2009/12/google-chrome-os.html#comment-form' title='6 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/4247679147598183573'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/4247679147598183573'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2009/12/google-chrome-os.html' title='Google Chrome OS 不是長生不老丹'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-2350769346498678794</id><published>2009-12-17T06:57:00.002+08:00</published><updated>2009-12-17T06:59:21.632+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Embedded System'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='Beagleboard'/><category scheme='http://www.blogger.com/atom/ns#' term='devkit8000'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>Add GPIO Keys support for Devkit8000</title><content type='html'>Using Android on Devkit8000, we have problem of getting back to previous screen. The touchscreen can only be used to decide whether you select item or not, so a BACK button would be needed absolutely for Android. Devkit8000 board has four buttons on the corner, we can set one of it as Back functionality.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_Td8NHoYnGW8/SyllL47NkzI/AAAAAAAAAyQ/TDlvDl_rJCI/s1600-h/DSC00542.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_Td8NHoYnGW8/SyllL47NkzI/AAAAAAAAAyQ/TDlvDl_rJCI/s320/DSC00542.JPG" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;First step, add a option to kernel config file to enable GPIO keyboard device:&lt;br /&gt;&lt;div&gt;&lt;pre&gt;CONFIG_KEYBOARD_GPIO=y&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Second step, set USER_KEY as ESC Keycode for back functionality:&lt;br /&gt;&lt;div&gt;&lt;pre&gt;diff --git a/arch/arm/mach-omap2/board-omap3devkit8000.c b/arch/arm/mach-omap2/board-omap3devkit8000.c&lt;br /&gt;index e86d254..ec17311 100644&lt;br /&gt;--- a/arch/arm/mach-omap2/board-omap3devkit8000.c&lt;br /&gt;+++ b/arch/arm/mach-omap2/board-omap3devkit8000.c&lt;br /&gt;@@ -462,9 +462,11 @@ static struct platform_device leds_gpio = {&lt;br /&gt; &lt;br /&gt; static struct gpio_keys_button gpio_buttons[] = {&lt;br /&gt;  {&lt;br /&gt;-  .code   = BTN_EXTRA,&lt;br /&gt;+//  .code   = BTN_EXTRA,&lt;br /&gt;+  .code   = KEY_ESC,&lt;br /&gt;   .gpio   = 26,&lt;br /&gt;   .desc   = "user",&lt;br /&gt;+  .active_low  = 1,&lt;br /&gt;   .wakeup   = 1,&lt;br /&gt;  },&lt;br /&gt; }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Here is the full patch you can download directly:&lt;br /&gt;&lt;a href="http://people.linux.org.tw/~fred/patches/devkit8000-gpiokey-android-kernel.patch"&gt;http://people.linux.org.tw/~fred/patches/devkit8000-gpiokey-android-kernel.patch&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-2350769346498678794?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/2350769346498678794/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2009/12/add-gpio-keys-support-for-devkit8000.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2350769346498678794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/2350769346498678794'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2009/12/add-gpio-keys-support-for-devkit8000.html' title='Add GPIO Keys support for Devkit8000'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_Td8NHoYnGW8/SyllL47NkzI/AAAAAAAAAyQ/TDlvDl_rJCI/s72-c/DSC00542.JPG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-546409049829052885</id><published>2009-12-17T02:35:00.000+08:00</published><updated>2009-12-17T02:35:21.004+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Embedded System'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='patch'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='Beagleboard'/><category scheme='http://www.blogger.com/atom/ns#' term='devkit8000'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>Enable ads7846 Touchscreen in Android that works on Devkit8000</title><content type='html'>If you would like to make Android work on Devkit8000, you can follow to patch your kernel which is mentioned in my old article(&lt;a href="http://fred-zone.blogspot.com/2009/12/android-eclair-porting-for-devkit8000.html"&gt;Android Eclair Porting for Devkit8000&lt;/a&gt;). After that you might notice the touchscreen doesn't work, it is a ads7846 kernel driver bug from Embinux. So I modified a few lines of code to fix the bug.&lt;br /&gt;&lt;br /&gt;Here is the patch:&lt;br /&gt;&lt;a href="http://people.linux.org.tw/~fred/patches/devkit8000-touchscreen-android-kernel.patch"&gt;http://people.linux.org.tw/~fred/patches/devkit8000-touchscreen-android-kernel.patch&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-546409049829052885?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/546409049829052885/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2009/12/enable-ads7846-touchscreen-in-android.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/546409049829052885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/546409049829052885'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2009/12/enable-ads7846-touchscreen-in-android.html' title='Enable ads7846 Touchscreen in Android that works on Devkit8000'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-5504129670035410242</id><published>2009-12-15T02:46:00.007+08:00</published><updated>2009-12-17T02:37:38.213+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Linux Kernel'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux硬體驅動'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='Embedded System'/><category scheme='http://www.blogger.com/atom/ns#' term='Android'/><category scheme='http://www.blogger.com/atom/ns#' term='patch'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='Beagleboard'/><category scheme='http://www.blogger.com/atom/ns#' term='手機平台'/><category scheme='http://www.blogger.com/atom/ns#' term='devkit8000'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>Android Eclair Porting for Devkit8000</title><content type='html'>It's not only for fun! Porting Android is a great practice for me as well. &lt;a href="http://www.embedinfo.com/English/Product/devkit8000.asp"&gt;Devkit8000&lt;/a&gt; is a clone of OMAP3 Beagle(Beagleboard),&amp;nbsp;so we can found many porting informations of Beagleboard from internet. It's helpful for us, we only need to deal with a few places which&amp;nbsp;are some differences between Devkit8000 and Beagleboard. Google Android Eclair is working well on the Devkit8000 board now after I tried to port it last weekend.&lt;br /&gt;&lt;br /&gt;Here is the patch:&lt;br /&gt;&lt;a href="http://people.linux.org.tw/~fred/patches/devkit8000-android-kernel.patch"&gt;http://people.linux.org.tw/~fred/patches/devkit8000-android-kernel.patch&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Based on &lt;a href="http://labs.embinux.org/"&gt;Embinux&lt;/a&gt;, I added the Devkit8000 support, which includes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;OMAP DSS Driver for display&lt;/li&gt;&lt;ul&gt;&lt;li&gt;4.3 inch LCD Panel support (480x272 60Hz)&lt;/li&gt;&lt;li&gt;7 inch LCD Panel support (800x480&amp;nbsp;60Hz)&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Touchscreen ADS7846 support&lt;/li&gt;&lt;li&gt;Sound Codec (TWL4030)&lt;/li&gt;&lt;li&gt;Keypad (TWL4030)&lt;/li&gt;&lt;li&gt;Ethernet Device support (DM9000)&lt;/li&gt;&lt;li&gt;Kernel Config for Android&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;Compile Kernel with Devkit8000 kernel config:&lt;br /&gt;&lt;div&gt;&lt;pre&gt;make omap3_devkit8000_android_defconfig&lt;br /&gt;make CROSS_COMPILE=arm-linux-gnueabi- uImage&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Kernel Command Arguments to use LCD Display Output:&lt;br /&gt;&lt;div&gt;&lt;pre&gt;omapdss.def_disp=lcd&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;References:&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Embest DevKit8000 Evaluation Kit&lt;br /&gt;&lt;a href="http://www.embedinfo.com/English/Product/devkit8000.asp"&gt;http://www.embedinfo.com/English/Product/devkit8000.asp&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Android Eclair Porting Guide to Beagleboard - Embinux&lt;br /&gt;&lt;a href="http://labs.embinux.org/index.php/Android-Eclair_porting_guide_to_BeagleBoard"&gt;http://labs.embinux.org/index.php/Android-Eclair_porting_guide_to_BeagleBoard&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-5504129670035410242?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/5504129670035410242/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2009/12/android-eclair-porting-for-devkit8000.html#comment-form' title='19 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5504129670035410242'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5504129670035410242'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2009/12/android-eclair-porting-for-devkit8000.html' title='Android Eclair Porting for Devkit8000'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>19</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-6022893405201099758</id><published>2009-11-26T17:44:00.001+08:00</published><updated>2009-11-26T17:58:49.623+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Git'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>Git 簡記</title><content type='html'>在團隊的多人協同作業時，版本控制系統是很重要的工具，除了要將大家的工作成果彙整起來之外，還要確保歷史記錄不遺失，讓日後的追朔工作有跡可尋。早期的 CVS 到後來的 Subversion(SVN) 都是屬於這類的版本控制系統。不過對於堪稱世界上最大最多人協作的 Linux Kernel Project，CVS 與 SVN 顯然像的玩具，根本不敷使用。而其他商業的版本控制系統，也多少有些缺點，這也是為什麼&amp;nbsp;Linux 之父『&amp;nbsp;Linus Torvalds 』要下海親自打造一套新的版本控制系統『Git』。既然 Git 能勝任於這世界上最大的專案，說它是下一世代的版本控制系統，應該一點也不為過。&lt;br /&gt;&lt;br /&gt;這樣的一個強大的工具，讓很多人都躍躍欲試，但也因為太過強大，網路上長篇大論的文章也讓許多人不敢恭維，有殺雞焉用牛刀之感。回頭想想，若是連如同 CVS/SVN 上的基本功能都無法輕易上手，講再多 Git 的特異功能也是枉然，套句&amp;nbsp;Torvalds 的經典名句：『full of bullshit』，一切都是廢話和放屁！（筆者真的懂每次都聽到一堆所謂的分散式架構等等優點，但還是不知道要怎麼開始用，是多麼令人覺得自己是 git！亦或者是文件撰寫者是 git？）&lt;br /&gt;&lt;br /&gt;從人本考量，我們需要版本控制系統，最初就是要能上傳和提交 source code，使之能放在 Server 上保存。此 Server 可以放在遠端，也可以是自己電腦上，要嘗試架一個在本地端（沒有提供外部連入功能）的 GIT Server 相當容易，裝好相關套件之後，指定一個 Source code 的保存目錄就好：&lt;br /&gt;&lt;br /&gt;Server 端的設定：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;# 建立一個新目錄，用來放 example project 的程式碼&lt;br /&gt;mkdir example.git&lt;br /&gt;cd example.git&lt;br /&gt;# &amp;nbsp;初始化此目錄為 Git 儲存庫&lt;br /&gt;git --bare init&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;到此，Server 的設定已經完成，新的 example project 儲存庫也已經建立，若是有需要，日後也可以加上 SSH/HTTP 等連線支援，讓外部使用者可以遠端存取此 Git server。&lt;br /&gt;&lt;br /&gt;有了 Server 之後，通常真正在做開發工作的，是在客戶端（Client），我們通常會從 Server 上取得一份完整的副本程式碼回家修改，完成工作後再提交回 Git server。在提交之前我們必需先設定自己的一些資料，以便他人知道是誰提交了程式碼。&lt;br /&gt;&lt;br /&gt;Client 端的設定：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;#&amp;nbsp;設定提交者的姓名和電子郵件信箱&lt;br /&gt;git config --global user.name "Fred Chien"&lt;br /&gt;git config --global user.email "fred@ullab.org"&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Client 端的本地工作區建立（從 Server 取回所有程式碼）：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;# 建立一個乾淨的目錄&lt;br /&gt;mkdir git&lt;br /&gt;cd git&lt;br /&gt;# 初始化並從 Git Server 取回程式碼&lt;br /&gt;git clone /home/fred/example.git&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Client 端修改好後提交回 Server：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;# 提交所有程式碼修改和加上說明描述&lt;br /&gt;git commit -a -m "說明描述"&lt;br /&gt;# 將所有提交內容上傳至 Git server&lt;br /&gt;git push&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Client 端從 Server 下載並更新本地工作區的程式碼：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;git pull&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Client 端新增文件並提交和上傳至 Server：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;git add example.c&lt;br /&gt;git commit -a -m "Add a example.c"&lt;br /&gt;git push&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;瀏覽所有開發記錄：&lt;br /&gt;&lt;div&gt;&lt;pre&gt;git log&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;後記&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;一直以來有很多人都來詢問 Git 的用法，網路上的相關文件也似乎都太過『完整』，因此整理了一下筆者過去的私人小筆記，用比較簡單的方式說明如何使用 Git，且避免和省略了許多令初學者摸不著頭緒的部份，如：分散式、離線作業、Branch、Merge 等等。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-6022893405201099758?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/6022893405201099758/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2009/11/git.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6022893405201099758'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6022893405201099758'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2009/11/git.html' title='Git 簡記'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-5812744954745276888</id><published>2009-11-25T17:14:00.006+08:00</published><updated>2009-11-25T17:22:37.592+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hacking 心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='GNOME'/><category scheme='http://www.blogger.com/atom/ns#' term='ULLab'/><category scheme='http://www.blogger.com/atom/ns#' term='LXDE'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='旅行(Travel)'/><title type='text'>Our Happy Travel for GNOME Summit in Vietnam</title><content type='html'>&lt;div&gt;This is first time that we(ULLab guys) make speeches at international&amp;nbsp;event&amp;nbsp;oversea, so we're so exciting on this travel.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class="separator" style="clear: both; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_Td8NHoYnGW8/Swzk12OWSlI/AAAAAAAAAxY/IP8N8csXR-Y/s1600/IMAG0133.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="214" src="http://4.bp.blogspot.com/_Td8NHoYnGW8/Swzk12OWSlI/AAAAAAAAAxY/IP8N8csXR-Y/s320/IMAG0133.jpg" width="320" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;Core Founders of ULLAB&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;Before this travel, in fact that I didn't know anything about Vietnam. I was just under the impression that Vietnam is a highly unstable country in Asia as well as this place is uncomfortable for us. Everyone all over the world always talks about the war and the girls in a bad way when mention Vietnam, so we never get a good impression about this place. However I must acknowledge that I was wrong now, Vietnam is a good place for enjoying our life absolutely, and also there are many people try to be surviving and becoming better in the world. Actually, many students in there have lifelong ambition, it shames me who is a Taiwanese.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_Td8NHoYnGW8/SwzxtU_qt8I/AAAAAAAAAyA/81cFza1ZVeU/s1600/dsc00536.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_Td8NHoYnGW8/SwzxtU_qt8I/AAAAAAAAAyA/81cFza1ZVeU/s320/dsc00536.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;When we arrived Vietnam, the first thing which is&amp;nbsp;traffic&amp;nbsp;made us crazy. The traffic in Vietnam was scaring me, I never see so many motorbikes all over the road. My new friends who are local people in there told me that most people choice to ride , because they doesn't have enough money to buy a car. The crazy traffic looks so dangerous, you never know when cars and motorbikes in front will turn to other direction. Sometimes we could see there are some cars and people to force to cross over crowd of cars, but it is magical that no accident happened.&lt;br /&gt;&lt;br /&gt;In fact there is similar to Taiwan except traffic, we often consider we're standing on the road in south of Taiwan.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_Td8NHoYnGW8/SwzznDbwA-I/AAAAAAAAAyI/DvTp5aKOkTo/s1600/IMAG0190.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_Td8NHoYnGW8/SwzznDbwA-I/AAAAAAAAAyI/DvTp5aKOkTo/s320/IMAG0190.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;For us, the biggest problem is communication. Due to most people do not speak English, it's difficult to do anything something's like taking a taxi, ordering foods and buying something. Fortunately, Volunteers of GNOME Summit help us so much, they are a good tour guide and translator to let us survive in Vietnam. If no those guys, we will get a big trouble I think.&lt;br /&gt;&lt;br /&gt;When I was in Taiwan, I often heard that someone said people in Vietnam is not friendly. After this travel, I don't think so. The truth is there are so many good guys, everything is comfortable for us. We met many new friends in there and exchanged the Facebook and email accounts with each other as well.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_Td8NHoYnGW8/SwzpDq0SvaI/AAAAAAAAAxg/2W9UdSj175I/s1600/IMAG0222.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_Td8NHoYnGW8/SwzpDq0SvaI/AAAAAAAAAxg/2W9UdSj175I/s320/IMAG0222.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;Besides, I think foods in Vietnam is really good excepts uncooked vegetable. Though I like Salad, many uncooked kinds of vegetable in Vietnam I don't like. Because tastes of vegetables is very strong and strange, we cannot adopt that actually.&lt;br /&gt;&lt;br /&gt;This travel we also met a lot foreign people, we had discussions, drinks and fun together. Sometimes we drunk and used English all night cause that when we were back to hotel, three Taiwanese people were still speaking in English for discussing rather than Chinese. So we get a conclusion that if you want to speak English without thinking, you must drink a lot beers to have a fun!&lt;br /&gt;&lt;br /&gt;This is a cool travel I think. I heard some informations about the GNOME.Asia Summit will take place in Taiwan next year. If it is truth, we can meet up again in Taiwan next time. I am looking forward to see you guys very much! :-)&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-5812744954745276888?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/5812744954745276888/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2009/11/our-happy-travel-for-gnome-summit-in.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5812744954745276888'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/5812744954745276888'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2009/11/our-happy-travel-for-gnome-summit-in.html' title='Our Happy Travel for GNOME Summit in Vietnam'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_Td8NHoYnGW8/Swzk12OWSlI/AAAAAAAAAxY/IP8N8csXR-Y/s72-c/IMAG0133.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-4723578462782632059</id><published>2009-11-12T20:57:00.002+08:00</published><updated>2009-11-12T21:00:01.210+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GNOME'/><category scheme='http://www.blogger.com/atom/ns#' term='LXDE'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='XPUD'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='心得分享、講座'/><title type='text'>GNOME.Asia Summit 2009 is coming</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://gnome.asia/wp-content/uploads/2009/10/gnome.asia-logo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://gnome.asia/wp-content/uploads/2009/10/gnome.asia-logo.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;a href="http://2009.gnome.asia/"&gt;GNOME.Asia summit 2009&lt;/a&gt;&amp;nbsp;is one of the top Free and Open Source Software (FOSS) events for developers, enterprises, officials and general users in Vietnam. The event brings together FOSS projects from Asia and around the world.&amp;nbsp;More than 500 participants from 10 countries are expected to participate in the summit, which is the first international community event of its kind in Vietnam. It takes place from Nov. 20-22, 2009, in Ho Chi Minh City.&lt;br /&gt;&lt;br /&gt;As a LXDE Developer, I just got invitation from GNOME.Asia committee last month. They expects that LXDE Team can give a talk to introduce and explain LXDE Development. Actually, we are so glad to have a session to talk about LXDE, especially &amp;nbsp;it can talk at GNOME event. It means we will have an opportunity to discuss with GNOME developer, users and contributor face to face rather than do anything behind closed doors.&lt;br /&gt;&lt;br /&gt;Eventually Andrew Lee, Penk and me will attend&amp;nbsp;GNOME.Asia 2009 in spite of&amp;nbsp;there are a lot of factors make us hard to decide whether to go or not in the beginning.&amp;nbsp;Andrew Lee will talk about libfm(a new library implementation for File Manager as well as it is a core of PCManFM2 which is next generation of File Manager of&amp;nbsp;LXDE) and preside at LXDE BOF in first day. Penk will present his own project&amp;nbsp;&lt;a href="http://www.xpud.org/"&gt;xPUD&lt;/a&gt;&amp;nbsp;which is a small and special distribution to be suitable with netbook of this kind. About me, my topic is "LXDE Development Strategy" to explain how LXDE to work and how to improve &amp;nbsp;desktop environment performance. If time is enough, I will introduce a little bit LXDE new&amp;nbsp;components, talk about&amp;nbsp;current status and roadmap.&lt;br /&gt;&lt;br /&gt;By the way, I think this travel will be so exciting for us, and also this is my first time to Vietnam. Good Luck to us!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-4723578462782632059?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/4723578462782632059/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2009/11/gnomeasia-summit-2009-is-coming.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/4723578462782632059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/4723578462782632059'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2009/11/gnomeasia-summit-2009-is-coming.html' title='GNOME.Asia Summit 2009 is coming'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-4548876677834505116</id><published>2009-11-08T23:07:00.004+08:00</published><updated>2009-11-08T23:37:10.152+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='技術新知'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='Mandice'/><category scheme='http://www.blogger.com/atom/ns#' term='Linux'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='系統研發手札'/><title type='text'>Mandice Installer 嘗鮮預覽</title><content type='html'>感謝各界的關注和幫忙，最近『&lt;a href="http://www.mandice.org/"&gt;Mandice&lt;/a&gt;』頗有進展，繼『&lt;a href="http://mandicenews-zh.blogspot.com/2009/11/mandice.html"&gt;Mandice Repository&lt;/a&gt;』Server&amp;nbsp;啟動之後，現在安裝程式也總算有個雛形樣貌，廢話就不必多言，直接來看一下 Video：&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;object height="344" width="425"&gt;&lt;param name="movie" value="http://www.youtube.com/v/Juvf5Q9eFuk&amp;hl=zh_TW&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/Juvf5Q9eFuk&amp;hl=zh_TW&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;大體來說，這是在開發 MTK（Mandice Toolkits）時的副產品，在做測試時順便打造出來的安裝程式，不過目前還在測試階段，仍有不少地方需要改進。&lt;br /&gt;&lt;br /&gt;PS. 這不是 Mandice 廣告宣傳片！&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-4548876677834505116?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/4548876677834505116/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2009/11/mandice-installer.html#comment-form' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/4548876677834505116'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/4548876677834505116'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2009/11/mandice-installer.html' title='Mandice Installer 嘗鮮預覽'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-6256986231316082784</id><published>2009-11-01T07:51:00.002+08:00</published><updated>2009-11-01T07:55:10.541+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Hacking 心得筆記'/><category scheme='http://www.blogger.com/atom/ns#' term='Clutter'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='C/C++'/><category scheme='http://www.blogger.com/atom/ns#' term='User Interface'/><title type='text'>Clutter Rotation 的惡行</title><content type='html'>由於之前已經寫過太多雜文說明，『&lt;a href="http://www.clutter-project.org/"&gt;Clutter Toolkit&lt;/a&gt;』的威力應該就不必要再多說。雖然說 Clutter 開發上很容易，但在真正開始開發程式後，就會發現有很多地方細節需要注意。&lt;br /&gt;&lt;br /&gt;關於開發 Clutter 程式時，會碰到的大部份問題，都出在於其設計邏輯與其他 3D Engine 不同，而最不一樣的地方，就是演員制度。Clutter Toolkit 特別的演員制度邏輯，使開發者將不再以大場景和 3D 空間定位為考量重點，而是以一個個 Actor 的角度去實作一切行為。因此，通常開發者第一個會碰到的行為就是『向左走、向右走』，單單使 Actor 旋轉到我們要的角度，就會碰到些問題。&lt;br /&gt;&lt;br /&gt;ClutterActor 定義了一系列 function 去實作各種行為，其中旋轉的部份：&lt;br /&gt;&lt;br /&gt;clutter_actor_set_rotation(ClutterActor *self,&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ClutterRotateAxis axis,&lt;br /&gt;&lt;/div&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;gdouble angle,&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;gfloat x,&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;gfloat y,&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;gfloat z);&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;clutter_actor_get_rotation(ClutterActor *self,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;ClutterRotateAxis axis,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;gfloat *x,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;gfloat *y,&lt;br /&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;gfloat *z);&lt;br /&gt;&lt;br /&gt;關於 rotation 的 angle，其範圍在 0 至 360 度之間，若設定超出角度範圍，會有 Warning 出現，有些時候雖然仍可正常執行，但會有無法預期的錯誤行為發生。而有個小問題出在於&amp;nbsp;clutter_actor_get_rotation() 的回傳值，其回傳值將有可能為負數，並不是在 0 至 360 之間，若是直接將回傳值代入&amp;nbsp;clutter_actor_set_rotation()，將會出現錯誤。&lt;br /&gt;&lt;br /&gt;這代表要是你的 Actor 現在已經轉了 315 度，用&amp;nbsp;clutter_actor_get_rotation() 取回的數值將可能是 -45。此時，要先算出正數的角度，才能再代回&amp;nbsp;clutter_actor_set_rotation() 使用。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-6256986231316082784?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fred-zone.blogspot.com/feeds/6256986231316082784/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://fred-zone.blogspot.com/2009/11/clutter-rotation.html#comment-form' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6256986231316082784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4389461234607418203/posts/default/6256986231316082784'/><link rel='alternate' type='text/html' href='http://fred-zone.blogspot.com/2009/11/clutter-rotation.html' title='Clutter Rotation 的惡行'/><author><name>Fred Chien(錢逢祥)</name><uri>http://www.blogger.com/profile/16383759688690536670</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_Td8NHoYnGW8/SYOwYcIW2wI/AAAAAAAAAXk/2Jqufv4GKlQ/S220/MSN2_big.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4389461234607418203.post-6785187830627721595</id><published>2009-10-25T10:42:00.001+08:00</published><updated>2009-10-25T11:11:54.232+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GTK'/><category scheme='http://www.blogger.com/atom/ns#' term='技術新知'/><category scheme='http://www.blogger.com/atom/ns#' term='Moblin'/><category scheme='http://www.blogger.com/atom/ns#' term='開放原始碼'/><category scheme='http://www.blogger.com/atom/ns#' term='自由軟體'/><category scheme='http://www.blogger.com/atom/ns#' term='User Interface'/><title type='text'>GTK+ 全面進化</title><content type='html'>Moblin 帶來的震憾莫過於 3D 樣貌的 UI，其底層 Clutter Toolkits 提供方便易用的 API，確實讓開發者能輕易撰寫炫麗的界面。不過，Clutter 的角色一直被視為一套新的 3D Engine，只是讓人重新打造操作介面而已。這未免小覷了 Clutter 的威力，其真正的好戲，在結合了 GTK+ 之後才正要開始。&lt;br /&gt;&lt;br /&gt;這是一段結合 GTK+ Notebook Widget 的展示，隨著觸發而產生的換頁特效：&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;object height="344" width="425"&gt;&lt;param name="movie" value="http://www.youtube.com/v/lE9JNxpgm2Q&amp;hl=zh_TW&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/lE9JNxpgm2Q&amp;hl=zh_TW&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;object height="344" width="425"&gt;&lt;param name="movie" value="http://www.youtube.com/v/IeV4EOee3CI&amp;hl=zh_TW&amp;fs=1&amp;"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/IeV4EOee3CI&amp;hl=zh_TW&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;借由 Offscreen 的實作，可將各種 GTK+ Widget 畫在 Clutter Actor 之上，以此做各種動畫效果，其架構如下所示：&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://people.collabora.co.uk/~danni/images/clutter-gtk-arch.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="369" src="http://people.collabora.co.uk/~danni/images/clutter-gtk-arch.png" width="640" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;我們可以視為 GTK+ Widget 被轉換成一個個 Clutter Actor，當然這些 Widget 仍然還保留著原本各種 GTK+&amp;nbsp;的性質，包括 Signal 等機制，只不過在顯示上，Widget 並非直接被畫在螢幕上，而是畫在 Clutter 的 Buffer 上，讓最後的繪圖動作都交由 OpenGL 做處理。此外，Clutter-GTK 實作了一個假的 GtkWindow 以騙過 GTK+ Toolkits，達成結合兩者的目的。&lt;br /&gt;&lt;br /&gt;雖然現在許多 UI 設計都是一窩蜂照抄 iPhone，但不可否認，舊有的使用者習慣還是存在，畢竟遵循舊有習慣的軟體數量太多，還是不太可能一時間淘汰掉。但是，&amp;nbsp;Clutter 給了一個新的機會，讓被人稱為極落伍的 GTK+ UI 有再進化的空間，至於能做到什麼程度，就看各開發者的創意了。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4389461234607418203-6785187830627721595?l=fred-zone.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://fre
