Kan-Ru Chen - 部落格
Kan-Ru Chen 的個人網站
Zola
2020-02-01T00:00:00+00:00
https://static.kanru.info/zh-tw/blog/atom.xml
JSON Web Tokens
2020-02-01T00:00:00+00:00
2020-02-01T00:00:00+00:00
https://static.kanru.info/zh-tw/blog/json-web-tokens/
<p>JSON Web Tokens 是什麼?它真的可以用來取代傳統的 session cookies 嗎?
本篇為研究 JWT 時所做的筆記。</p>
<h2 id="shi-mo-shi-json-web-tokens">什麼是 JSON Web Tokens ?</h2>
<p>JSON Web Token 縮寫為 JWT,唸作 jot,是一個 IETF 標準(<a href="https://tools.ietf.org/html/rfc7519">RFC
7519</a>),定義了不同的群體間可以精
簡且安全的方式交換資訊的方法,這些資訊是包裝在一個 JSON Object 裡面,因
而得名。這些資訊因為經過數位簽章所以可以被驗證是否為可信任的內容,簽章
的方式可以是單一密文(HMAC)或是公鑰私鑰系統(RSA)。</p>
<h2 id="json-web-tokens-yao-zen-mo-yong">JSON Web Tokens 要怎麼用?</h2>
<p>當使用者跟伺服器登錄之後,伺服器可以傳回一個 JSON Web Token,此 Token 可
以存在瀏覽器的 local storage 或是 cookie。</p>
<p>當使用者想要再次存取某些需要認證的資訊的時候,他們需要把這個 JWT 送回伺
服器,通常以 Authorization header 的形式,例如:</p>
<pre style="background-color:#ffffff;color:#323232;"><code><span>Authorization: Bearer <token>
</span></code></pre>
<p>這個方式對於伺服器來說相較於 session cookie 的方式輕量(stateless),因
為伺服器不需要保有相關 session 的訊息,只需要 JWT 內的資訊就可以確認該
使用者是否可以取用相關資源。</p>
<p><img src="https://static.kanru.info/zh-tw/blog/json-web-tokens/mermaid-diagram-20200724102650.svg" alt="Authentication flow" /></p>
<h2 id="shi-yong-json-web-tokens-de-hao-chu">使用 JSON Web Tokens 的好處</h2>
<ol>
<li>可以容易的橫向 scale</li>
<li>維護更容易(沒有需要長期儲存的資料)</li>
<li>跨 Domain RESTful API (不需要 CORS cookie)</li>
<li>可以設定 Token 的有效期限</li>
<li>單一 Token 即包含所有認證需要的資訊</li>
</ol>
<h2 id="chuan-tong-de-session">傳統的 Session</h2>
<p><img src="https://static.kanru.info/zh-tw/blog/json-web-tokens/mermaid-diagram-20200724114359.svg" alt="Session flow" /></p>
<p>使用者認證後伺服器傳回一個 session ID,之後伺服器可以用此ID查訊使用者資訊</p>
<h3 id="chang-jian-wen-ti">常見問題</h3>
<ol>
<li>需要資料庫統一儲存登錄資訊</li>
<li>如何登出使用者?</li>
</ol>
<h2 id="json-web-token-de-qian-zai-wen-ti">JSON Web Token 的潛在問題</h2>
<ol>
<li>XSS, CSRF, Replay attack, MITM</li>
<li>JWT 透過數位簽章跟加密來防止竄改或是竊取裡面的資料,但是 JWT 被儲存在
local storage 或是 cookies 裡面的時候,同一個 domain 的 JavaScript 同
樣都可以存取這些 JWT,因此有潛在的 XSS 或是 CSRF 攻擊的風險。</li>
<li>JWT 的大小比單純的 session ID 大的多</li>
<li>保護簽章用的密文或是私鑰變得非常重要</li>
</ol>
<h3 id="ru-he-ying-dui-zhong-bo-gong-ji">如何應對重播攻擊</h3>
<ol>
<li>使用較短的有效期限</li>
<li>客戶端定期更新Token</li>
<li>伺服器端使用黑名單阻擋有問題的客戶</li>
</ol>
<h2 id="ba-jwt-huo-shi-session-id-cun-zai-cookie-de-hao-chu">把 JWT 或是 session ID 存在 cookie 的好處</h2>
<p>Browser 會自動把 cookie 包含在 header 裡面所以適合用來保護網頁的存取</p>
<h2 id="jie-lun">結論</h2>
<p>Don’t use JWT for persistent, long-lived data.</p>
<h2 id="can-kao-wen-xian">參考文獻</h2>
<ol>
<li><a href="https://ponyfoo.com/articles/json-web-tokens-vs-session-cookies">https://ponyfoo.com/articles/json-web-tokens-vs-session-cookies</a></li>
<li><a href="http://by.jtl.xyz/2016/06/the-unspoken-vulnerability-of-jwts.html">http://by.jtl.xyz/2016/06/the-unspoken-vulnerability-of-jwts.html</a></li>
<li><a href="https://stackoverflow.com/questions/37582444/jwt-vs-cookies-for-token-based-authentication">https://stackoverflow.com/questions/37582444/jwt-vs-cookies-for-token-based-authentication</a></li>
<li><a href="https://dzone.com/articles/jwtjson-web-tokens-are-better-than-session-cookies">https://dzone.com/articles/jwtjson-web-tokens-are-better-than-session-cookies</a></li>
<li><a href="http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/">http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/</a></li>
<li><a href="https://jwt.io/">https://jwt.io/</a></li>
</ol>
Simpler way to load CSS asynchronously
2019-07-28T00:00:00+00:00
2019-07-28T00:00:00+00:00
https://static.kanru.info/zh-tw/blog/simpler-way-to-load-css-async/
<p>在 <a href="https://www.smashingmagazine.com/the-smashing-newsletter/smashing-newsletter-issue-234/#a1">Smashing Newsletter</a> 看到的,只要 <code><link></code> 標籤就可以簡單把 CSS 變成非同步讀取:</p>
<pre data-lang="html" style="background-color:#ffffff;color:#323232;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#63a35c;">link </span><span style="color:#795da3;">rel</span><span>=</span><span style="color:#183691;">"stylesheet" </span><span style="color:#795da3;">href</span><span>=</span><span style="color:#183691;">"/path/to/my.css"
</span><span> </span><span style="color:#795da3;">media</span><span>=</span><span style="color:#183691;">"print" </span><span style="color:#795da3;">onload</span><span>=</span><span style="color:#183691;">"</span><span style="color:#ed6a43;">this</span><span>.media</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#183691;">'all'"</span><span>>
</span></code></pre>
<p>有用過 <a href="https://developers.google.com/speed/pagespeed/insights/">Google PageSpeed Insight</a> 分析網站的,應該都有看過如下的結果:</p>
<picture>
<source srcset="https://kanru.info/blog/assets/content/2019-07-28_17-23-21_screenshot.webp" type="image/webp">
<source srcset="https://kanru.info/blog/assets/content/2019-07-28_17-23-21_screenshot.png" type="image/png">
<img src="https://kanru.info/blog/assets/content/2019-07-28_17-23-21_screenshot.png" width="100%" alt="PageSpeed screenshot">
</picture>
<p>原因是因為瀏覽器在處理 CSS 與 JavaScript 檔案的時候會阻擋其他資源的載入。解決的
方法裡,JavaScript 類型的資源可以標示 <code>defer</code> 或是 <code>async</code> 屬性讓瀏覽器知道我們
希望可以非同步的載入執行此 JavaScript 檔案,可惜 CSS 並沒有類似的屬性可以使用。</p>
<p>一般處理 CSS 的載入有兩個策略:</p>
<ol>
<li>盡量把最重要的樣式內嵌(inline)在 HTML 內,</li>
<li>用 JavaScript 動態的插入 <code><link></code> 標籤。</li>
</ol>
<p>策略 1. 應該不難理解,因為都已經要下載 HTML 了,不如把少部份最重要的樣式直接也寫
在裡面,可以省下一次網路請求。策略 2. 則是把其他剩餘的樣式集中在一起,用
JavaScript 在網頁讀取完畢後再動態的插入 <code><link></code> 標籤讓瀏覽器套用。<a href="https://github.com/filamentgroup/loadCSS">LoadCSS</a>
似乎是個常用的 library 但是我沒有用過,因為我不喜歡這種需要很多 JavaScript 的解
法。</p>
<p>這次看到的這個方法非常簡單,原本的 CSS 標籤如下:</p>
<pre data-lang="html" style="background-color:#ffffff;color:#323232;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#63a35c;">link </span><span style="color:#795da3;">rel</span><span>=</span><span style="color:#183691;">"stylesheet" </span><span style="color:#795da3;">href</span><span>=</span><span style="color:#183691;">"/path/to/my.css"</span><span>>
</span></code></pre>
<p>只要再加上 <code>media="print"</code> 以及 <code>onload="this.media='all'"</code> 就可以讓瀏覽器非同步載入 CSS 了!</p>
<p>原理是,瀏覽器在遇到非使用中的 <code>media</code> 時,只會下載但是不會套用樣式,所以設定
<code>media</code> 為 <code>print</code> 可以避免套用 CSS 的時候延遲其他的資源的載入,而 <code>onload</code> 的部
份則是在等到其他資源都載入完畢後,才把 <code>media</code> 切回 <code>all</code> 或是 <code>screen</code> 讓瀏覽器
套用樣式。雖然還是需要一點點 CSS,整體看起來清爽許多,也不需要額外的 library!</p>
<p>如果需要支援沒有開啟 JavaScript 的瀏覽器,記得加上 fallback:</p>
<pre data-lang="html" style="background-color:#ffffff;color:#323232;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#63a35c;">noscript</span><span>><</span><span style="color:#63a35c;">link </span><span style="color:#795da3;">rel</span><span>=</span><span style="color:#183691;">"stylesheet" </span><span style="color:#795da3;">href</span><span>=</span><span style="color:#183691;">"/path/to/my.css"</span><span>></</span><span style="color:#63a35c;">noscript</span><span>>
</span></code></pre>
<p>完整的範例如下:</p>
<pre data-lang="html" style="background-color:#ffffff;color:#323232;" class="language-html "><code class="language-html" data-lang="html"><span><</span><span style="color:#63a35c;">link </span><span style="color:#795da3;">rel</span><span>=</span><span style="color:#183691;">"stylesheet" </span><span style="color:#795da3;">href</span><span>=</span><span style="color:#183691;">"/path/to/my.css"
</span><span> </span><span style="color:#795da3;">media</span><span>=</span><span style="color:#183691;">"print" </span><span style="color:#795da3;">onload</span><span>=</span><span style="color:#183691;">"</span><span style="color:#ed6a43;">this</span><span>.media</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#183691;">'all'"</span><span>>
</span><span><</span><span style="color:#63a35c;">noscript</span><span>><</span><span style="color:#63a35c;">link </span><span style="color:#795da3;">rel</span><span>=</span><span style="color:#183691;">"stylesheet" </span><span style="color:#795da3;">href</span><span>=</span><span style="color:#183691;">"/path/to/my.css"</span><span>></</span><span style="color:#63a35c;">noscript</span><span>>
</span></code></pre>
<p>我迫不及待的立刻試用了😊 ∎</p>
CSS Text 3: Segment Break Transformation Rules
2017-07-08T18:36:54-07:00
2017-07-08T18:36:54-07:00
https://static.kanru.info/zh-tw/blog/firefox-css-text-3-segment-break-transformation-rules/
<p>去年年底,我利用閒暇時間<sup class="footnote-reference"><a href="#have-time">1</a></sup>修好了 Firefox
的 <a href="https://drafts.csswg.org/css-text/#line-break-transform">Segment Break Transformation Rules</a> 實做
(<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1081858">Bug 1081858</a>)。從 Firefox 52 開始,HTML 裡面中文與中文之
間的換行,瀏覽器排版時不會顯示為空白。</p>
<div style="display: flex; flex-wrap: wrap; align-items: baseline">
<figure style="flex: 1">
<img src="https://kanru.info/blog/assets/content/css-text-3-segment-break-transformation-rules-source.png" style="width: 72px">
<figcaption>Source</figcaption>
</figure>
<figure style="flex: 1">
<img src="https://kanru.info/blog/assets/content/css-text-3-segment-break-transformation-rules-before.png" style="width: 199px">
<figcaption>Chromium 59</figcaption>
</figure>
<figure style="flex: 1">
<img src="https://kanru.info/blog/assets/content/css-text-3-segment-break-transformation-rules-after.png" style="width: 183px">
<figcaption>Firefox 56</figcaption>
</figure>
</div>
<p>使用純文字編輯器撰寫文檔時,為了閱讀的舒適性,常常我們會在行寬
80 個字元的時候換行,這個寬度可以容納四十個中文字,剛好也是可以舒
適閱讀中文的寬度。隨著軟體硬體的進步,顯示內容不再侷限於固定的寬度,
很多排版軟體都可以把內文重新排版後顯示在不一樣的環境。</p>
<p>從原始文檔轉換為螢幕顯示內容的排版過程,這些軟體會把同一段落的文字重組
為文字流,移除換行或是插入新的換行,重新排版於新的容器寬度內;問題在於
很多拼音文字使用空白作為字與字之間的分隔,排版軟體的演算法也如此假設,
結果原本文檔內被移除的換行就預設被取代為空白。</p>
<p>現在很多網路上的內容都是用 Markdown 語法編寫的,大部分的 Markdown 轉譯
程式都會保留原本內文的換行<sup class="footnote-reference"><a href="#markdown">2</a></sup>,所以很多網路上的中文內容都會發
現這樣的問題。不仔細看的話也許不會注意到,但是一旦注意到了就很難忽略這
個排版的瑕疵,如果網頁使用齊頭齊尾排版的話尤其明顯。</p>
<p>這個問題不只出現在網頁上,也出現在很多會自動重新排版文字流的應用程式中,
例如 XeLaTeX 的中文套件 XeCJK 也要處理類似的問題。過去我經常修改程式後
端來解決這個問題,但是也一直在尋找一勞永逸的,直接在瀏覽器裡面修正的方法。</p>
<p>後來找到 CSS Text 3 有這方面的規範。實際開始修改後我發現其實 Firefox
在很早就有針對中文做些處理,但是這段程式碼錯誤判斷中文字的邊界,使得這
段程式碼從寫完開始就沒有任何作用。這段程式原本的寫法就比較難懂(使用負
的陣列索引),缺乏相關的測試導致一直沒有人發現這個錯誤<sup class="footnote-reference"><a href="#coverage">3</a></sup>,結果
甚至在我修好這段程式碼之後還暴露了原本排版引擎的一
些 <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1369985">bug</a>。</p>
<p>同事 Jeremy 後來進一步<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1316482">修改</a>了 Gecko 的演算法,符合目前
spec 規範的行為。</p>
<blockquote>
<p><strong>4.1.2. Segment Break Transformation Rules</strong></p>
<p>When white-space is pre, pre-wrap, or pre-line, segment breaks are
not collapsible and are instead transformed into a preserved line
feed (U+000A).</p>
<p>For other values of white-space, segment breaks are collapsible. As
with spaces, any collapsible segment break immediately following
another collapsible segment break is removed. Then the remaining
segment breaks are either transformed into a space (U+0020) or
removed depending on the context before and after the break:</p>
<ul>
<li>If the character immediately before or immediately after the
segment break is the zero-width space character (U+200B), then the
break is removed, leaving behind the zero-width space.</li>
<li>Otherwise, if the East Asian Width property [UAX11] of both the
character before and after the segment break is F, W, or H (not
A), and neither side is Hangul, then the segment break is removed.</li>
<li>Otherwise, the segment break is converted to a space (U+0020).</li>
</ul>
</blockquote>
<p>其他瀏覽器的話,IE 原本就有部份支援,只要在 Blink/Webkit 也實做同樣的
spec,這樣大部分的網頁就都不會有問題了。Servo 目前在這部份也是只有簡單
的演算法,也是貢獻的機會!</p>
<div class="footnote-definition" id="have-time"><sup class="footnote-definition-label">1</sup>
<p>之前這個 Bug 一直在我的「如果我有時間」清單裡,通常就是不會有時間做啦 😆</p>
</div>
<div class="footnote-definition" id="markdown"><sup class="footnote-definition-label">2</sup>
<p>原本的 Markdown 是用 perl 做簡單的文字取代</p>
</div>
<div class="footnote-definition" id="coverage"><sup class="footnote-definition-label">3</sup>
<p>所以說 test coverage 很重要!</p>
</div>
Source Han Sans & FreeType
2014-08-04T00:00:00+08:00
2014-08-04T00:00:00+08:00
https://static.kanru.info/zh-tw/blog/source-han-sans-and-freetype/
<p>前陣子 Adobe 和 Google 聯手各自用不同的名字釋出了一款新的中文黑體字形,Source Han Sans 思源黑體,也叫做 Noto Sans (反腐字?)。開心試用之後,把系統字形都換過來,也開始想要怎麼樣才可以達到最佳的顯示效果,尤其是 Adobe 和 Google 曾經給 FreeType 貢獻了 CFF 字形引擎的改進,思源黑體也是以 CFF 技術設計,終於可以試試看中文的效果怎麼樣了啊!</p>
<p>我這邊使用 FreeType 的工具程式 ftview 來測試不同參數設定下的顯示效果,同時也附上相對應的 FontConfig 設定。可以發現不同設定下的顯示差距還蠻大的:</p>
<h3 id="auto-hinter-hintfull-grayscale-anti-alias">Auto-hinter, hintfull, grayscale anti-alias</h3>
<p>首先是使用 FreeType 的 autohint, hintfull 其他用預設值,這應該是滿多人使用的設定,可以看到 autohinter 有很強烈的瘦身效果,把 Normal 的字變成幾乎是 Light 了。</p>
<p><img src="https://kanru.info/blog/assets/content/2014-08-05-000917_640x480_scrot.png" alt="Hintfull" /></p>
<h3 id="auto-hinter-hintslight-grayscale-anti-alias">Auto-hinter, hintslight, grayscale anti-alias</h3>
<p>再來是使用 hintslight,許多人用以取得類似 Mac 上面的渲染效果,卻不知道 hintslight 會自動使用 autohint,這張的效果和上面類似但是略為粗了一點。思源黑體使用 hintslight 的缺點是 Normal 變細,導致和 Bold 的粗細相差太多。</p>
<p><img src="https://kanru.info/blog/assets/content/2014-08-05-000930_640x480_scrot.png" alt="Hintslight" /></p>
<h3 id="auto-hinter-hintslight-rgb-lcd-subpixel-aa">Auto-hinter, hintslight, RGB LCD subpixel AA</h3>
<p>這張的效果和上面一樣,只是啟用了 subpixel AA 所以在螢幕是 RGB 排列的 LCD 的時候會有比較銳利的感覺。</p>
<p><img src="https://kanru.info/blog/assets/content/2014-08-05-000944_640x480_scrot.png" alt="Hintslight, Subpixel" /></p>
<h3 id="adobe-cff-native-hinter-hintfull-grayscale-anti-alias">Adobe CFF native hinter, hintfull, grayscale anti-alias</h3>
<p>這張則是使用 Adobe 去年貢獻的 CFF native hinting 引擎,這個引擎的特性是在小字的時候不但不會把字變細,反而還會加深筆劃讓字形看起來更清楚,於是 Normal 變回原本得粗細。</p>
<p><img src="https://kanru.info/blog/assets/content/2014-08-05-001032_640x480_scrot.png" alt="CFF Hinter, Grayscale" /></p>
<h3 id="adobe-cff-native-hinter-hintfull-rgb-lcd-subpixel-aa">Adobe CFF native hinter, hintfull, RGB LCD subpixel AA</h3>
<p>同上,只是啟用 subpixel AA 讓字形在 LCD 螢幕上看起來更銳利。</p>
<p><img src="https://kanru.info/blog/assets/content/2014-08-05-001038_640x480_scrot.png" alt="CFF Hinter, Subpixel" /></p>
<p>最後因為我選擇的設定是 TTF 字形使用 autohint + hintslight,CFF 字形則是使用 native hinter,因為雖然很多 TTF 字形有人工去 hint,可是一般來說 autohint + hintslight 比較可以保留細節,也不比人工 hint 差,而 CFF 字形因為有 Adobe 的加持,所以使用 native hinter 可以得到更好的效果。</p>
<pre data-lang="xml" style="background-color:#ffffff;color:#323232;" class="language-xml "><code class="language-xml" data-lang="xml"><span> <</span><span style="color:#63a35c;">match </span><span style="color:#795da3;">target</span><span>=</span><span style="color:#183691;">"font"</span><span>>
</span><span> <</span><span style="color:#63a35c;">edit </span><span style="color:#795da3;">name</span><span>=</span><span style="color:#183691;">"rgba" </span><span style="color:#795da3;">mode</span><span>=</span><span style="color:#183691;">"assign"</span><span>>
</span><span> <</span><span style="color:#63a35c;">const</span><span>>rgb</</span><span style="color:#63a35c;">const</span><span>>
</span><span> </</span><span style="color:#63a35c;">edit</span><span>>
</span><span> <</span><span style="color:#63a35c;">edit </span><span style="color:#795da3;">name</span><span>=</span><span style="color:#183691;">"hinting" </span><span style="color:#795da3;">mode</span><span>=</span><span style="color:#183691;">"assign"</span><span>>
</span><span> <</span><span style="color:#63a35c;">bool</span><span>>true</</span><span style="color:#63a35c;">bool</span><span>>
</span><span> </</span><span style="color:#63a35c;">edit</span><span>>
</span><span> <</span><span style="color:#63a35c;">edit </span><span style="color:#795da3;">name</span><span>=</span><span style="color:#183691;">"lcdfilter" </span><span style="color:#795da3;">mode</span><span>=</span><span style="color:#183691;">"assign"</span><span>>
</span><span> <</span><span style="color:#63a35c;">const</span><span>>lcddefault</</span><span style="color:#63a35c;">const</span><span>>
</span><span> </</span><span style="color:#63a35c;">edit</span><span>>
</span><span> <</span><span style="color:#63a35c;">edit </span><span style="color:#795da3;">name</span><span>=</span><span style="color:#183691;">"hintstyle" </span><span style="color:#795da3;">mode</span><span>=</span><span style="color:#183691;">"assign"</span><span>>
</span><span> <</span><span style="color:#63a35c;">const</span><span>>hintslight</</span><span style="color:#63a35c;">const</span><span>>
</span><span> </</span><span style="color:#63a35c;">edit</span><span>>
</span><span> </</span><span style="color:#63a35c;">match</span><span>>
</span><span> <</span><span style="color:#63a35c;">match </span><span style="color:#795da3;">target</span><span>=</span><span style="color:#183691;">"font"</span><span>>
</span><span> <</span><span style="color:#63a35c;">test </span><span style="color:#795da3;">name</span><span>=</span><span style="color:#183691;">"fontformat"</span><span>><</span><span style="color:#63a35c;">string</span><span>>CFF</</span><span style="color:#63a35c;">string</span><span>></</span><span style="color:#63a35c;">test</span><span>>
</span><span> <</span><span style="color:#63a35c;">edit </span><span style="color:#795da3;">name</span><span>=</span><span style="color:#183691;">"hintstyle" </span><span style="color:#795da3;">mode</span><span>=</span><span style="color:#183691;">"assign"</span><span>>
</span><span> <</span><span style="color:#63a35c;">const</span><span>>hintfull</</span><span style="color:#63a35c;">const</span><span>>
</span><span> </</span><span style="color:#63a35c;">edit</span><span>>
</span><span> </</span><span style="color:#63a35c;">match</span><span>>
</span></code></pre>
<p><a href="https://github.com/kanru/rcfiles/blob/76e1ac014472ad1193924dfc8bb409f258b1f82a/fonts.conf">https://github.com/kanru/rcfiles/blob/fonts.conf</a></p>
<p>這是我目前的設定,至於你喜歡什麼樣的效果,可以再實驗看看各種不同的參數囉 😉</p>
GCIN in Debian is seeking co-maintainer
2011-12-18T14:07:53+08:00
2011-12-18T14:07:53+08:00
https://static.kanru.info/zh-tw/blog/gcin-in-debian-is-seeking-co-maintainer/
<h2 id="xun-zhao-gcin-co-maintainer">尋找 GCIN co-maintainer</h2>
<p>HIME 的事件鬧的沸沸揚揚,一切的起因之一就是有人認為 HIME 會取代 Debian
裡面的 GCIN,這是什麼狀況呢?因為在 Debian 裡面把 GCIN 棄養 (orphan)
的就是我,似乎也有必要說明一下。以下提到 GCIN 都是指 Debian 裡面的 GCIN。</p>
<p>最早的 GCIN 維護者是 caleb,後來他因為不再使用 Debian 所以開始找其他人
幫忙維護,而我成為 Debian Developer 的初衷就是要幫助本地的使用者有習慣
好用的套件可以用,所以就接下了這個位子。當時我也有使用 GCIN 所以就算劉
老大 (eliu) 每兩三天就有新版本我也還可以跟上,只是沒有辦法把套件整理的
乾淨點,後來不用 GCIN 了,套件的更新就漸漸脫節,因為有 Luna Archiver
的存在也讓我有偷懶的藉口,最後發現花在這個套件的時間與 Debian 的
<a href="http://qa.debian.org/popcon.php?package=gcin">Popcon</a> 統計不成比例,就決定把套件給棄養了。</p>
<p>Debian 對於被棄養的套件的處理方式是,如果沒有出什麼大問題就會由 QA
team 來管理,但是如果有人提出 RM: RoQA 的要求,因為使用者 (Popcon) 少
且無人管理,就有可能被移出 Debian,但無正當理由甚少有直接使用新專案取
代舊專案的狀況,因此 Debian 要使用 HIME 取代 GCIN 純粹是誤解而已。</p>
<p>後來想想也不能把 GCIN 就這樣晾著,所以我決定要再出點力,把 GCIN 納入
Debian IME Packaging Team 的管理,並誠徵對維護 GCIN 套件有興趣的人一起
來 co-maintain,讓 GCIN 的使用者可以直接用到最新、高品質的 GCIN 套件。</p>
<p>有興趣的人請與我聯絡,寄信到 koster@debian.org 或是
630484@bugs.debian.org 都可以。</p>
Not Again, MingLiu!
2011-08-30T20:09:07+08:00
2011-08-30T20:09:07+08:00
https://static.kanru.info/zh-tw/blog/not-again-mingliu/
<p>長話短說,從 FreeType 2.4.4 (2010-11-28 release) 開始,只要編譯的時候有
啟用 BCI (Byte Code Interpreter) ,新細明體就不應該會破掉了,只是因為一
些原因 (下面詳述),一直到 2.4.5 (2011-06-24 release) 才算是完全解決。</p>
<p>這個問題牽扯到許多有趣知識,所以我決定作個筆記以免以後忘掉。</p>
<h2 id="truetype">TrueType</h2>
<p>首先是一些名詞解釋,TrueType 是常見的字型 (font) 格式,由 Apple 發展,
後來被 Microsoft 採用並發揚光大;雖然沒有經過任何國際組織的標準化,在當
時儼然已經成為業界標準 (de facto standard)。</p>
<p>TrueType 使用的檔案格式又稱為 <code>sfnt</code> 格式,由許多不同的表格 (table) 組
成,每個表格由四個字的標籤 (tag) 表示,其中我們最關心的是 <code>glyf</code> 這個表
格,因為所有的字符 (glyph) 都儲存在這個表格內。每個字符僅僅紀錄了形狀,
要知道某個編碼的某個字元 (character) 是對應到哪個形狀,還要透過 <code>cmap</code>
這個表格來查詢;也有一個字沒有相對應的字符,或是沒有任何字對應到某個字
符的情況。</p>
<p>參考資料:</p>
<ul>
<li><a href="https://developer.apple.com/fonts/TTRefMan/index.html">Apple: TrueType Reference Manual</a></li>
<li><a href="https://secure.wikimedia.org/wikipedia/en/wiki/Truetype">Wikipedia: Truetype</a></li>
<li><a href="https://secure.wikimedia.org/wikipedia/en/wiki/OpenType">Wikipedia: OpenType</a></li>
</ul>
<h2 id="hinting-instructing">Hinting (Instructing)</h2>
<p>TrueType 是一種外框字型 (Outline Font),也就是說每一個字符都是以向量圖
形的方式呈現,理論上可以在各種不同解析度下呈現相同的形狀。</p>
<p><img src="https://kanru.info/blog/assets/content/o_dejavu_rasterize.png"
alt="DejaVu.tiff O Rasterize"
style="width:100%"></p>
<p><img src="https://kanru.info/blog/assets/content/mm_rasterize.png"
alt="M M Rasterize"
style="float:right;width:25%"></p>
<p>但是越是在低解析度的時候,由於可用的像素較少,越容易遇到邊界的表達能力
問題,如右圖的 <code>M</code> 字,若沒有對齊像素點的話,呈現出來的圖案就會比較瘦長
且左右不對稱,如果稍微向右移動並加寬一點,呈現出來的圖案就會比較接近原
本向量圖形所預期的形狀;這個動作正是 Hinting 中的對齊格線 (grid
fitting) 功能。</p>
<p>在 TrueType 檔案中,描述 Hinting 的方式其實是儲存在字型的 <code>fpgm</code> 與
<code>prep</code> 表格中的小程式,或是內嵌在字符中。看起來像是這樣:</p>
<pre data-lang="asm" style="background-color:#ffffff;color:#323232;" class="language-asm "><code class="language-asm" data-lang="asm"><span style="font-weight:bold;color:#795da3;"> PUSHB</span><span>[</span><span style="color:#0086b3;">000</span><span>] </span><span style="font-weight:bold;color:#795da3;"># </span><span style="font-weight:bold;color:#a71d5d;">Push </span><span style="font-weight:bold;color:#795da3;">one </span><span style="color:#62a35c;">byte </span><span style="font-weight:bold;color:#795da3;">onto the stack.
</span><span style="font-weight:bold;color:#795da3;"> </span><span style="color:#0086b3;">3 </span><span style="font-weight:bold;color:#795da3;"># Value for </span><span style="font-weight:bold;color:#a71d5d;">loop </span><span style="font-weight:bold;color:#795da3;">variable.
</span><span style="font-weight:bold;color:#795da3;"> SLOOP</span><span>[] </span><span style="font-weight:bold;color:#795da3;"># Set the </span><span style="font-weight:bold;color:#a71d5d;">loop </span><span style="font-weight:bold;color:#795da3;">count to </span><span style="color:#0086b3;">3</span><span style="font-weight:bold;color:#795da3;">.
</span><span style="font-weight:bold;color:#795da3;"> PUSHB</span><span>[</span><span style="color:#0086b3;">002</span><span>] </span><span style="font-weight:bold;color:#795da3;"># </span><span style="font-weight:bold;color:#a71d5d;">Push </span><span style="font-weight:bold;color:#795da3;">three bytes onto the stack.
</span><span style="font-weight:bold;color:#795da3;"> </span><span style="color:#0086b3;">5 </span><span style="font-weight:bold;color:#795da3;"># Point number.
</span><span style="font-weight:bold;color:#795da3;"> </span><span style="color:#0086b3;">46 </span><span style="font-weight:bold;color:#795da3;"># Point number.
</span><span style="font-weight:bold;color:#795da3;"> </span><span style="color:#0086b3;">43 </span><span style="font-weight:bold;color:#795da3;"># Point number.
</span><span style="font-weight:bold;color:#795da3;"> ALIGNRP</span><span>[] </span><span style="font-weight:bold;color:#795da3;"># </span><span style="color:#62a35c;">Align </span><span style="font-weight:bold;color:#795da3;">the points </span><span style="color:#0086b3;">5</span><span>, </span><span style="color:#0086b3;">46 </span><span style="font-weight:bold;color:#a71d5d;">and </span><span style="color:#0086b3;">43 </span><span style="font-weight:bold;color:#795da3;">with rp0 (point </span><span style="color:#0086b3;">8</span><span style="font-weight:bold;color:#795da3;">). This will
</span><span style="font-weight:bold;color:#795da3;"> # </span><span style="color:#62a35c;">align </span><span style="font-weight:bold;color:#795da3;">the height of the two lower serifs.
</span></code></pre>
<p>使用這個小程式的方法是 Apple 的專利,但是因為 TrueType 一開始只是業界標
準,Apple 並沒有在規格書裡面提及專利的相關資訊,造成後來使用 FreeType
啟用 BCI (Byte Code Interpreter) 可能會侵犯專利的問題。(相關專利已經在 2010 年 4 月全數過期)</p>
<p>對每個字符做 Hinting 是個耗時耗力的工作,就算是只有數百個字符的西文字
型也要花上數倍於繪圖的時間來做 Hinting,因此除了少數高品質的字型外,多
數的字型是沒有 Hinting 的。而隨著顯示裝置的解析度越來越高,對於
Hinting 的需求也越來越少,在較新的作業系統上可能會忽略部份 Hinting 的
資訊或是完全關閉 Hinting。而在自由軟體的世界中,大多使用 FreeType
的 Auto-Hinting 技術來支援解析度較低的顯示裝置。</p>
<p>參考資料:</p>
<ul>
<li><a href="https://www.microsoft.com/typography/TrueTypeHintingIntro.mspx">Microsoft: TrueType Hinting Introduction</a></li>
<li><a href="http://fontforge.sourceforge.net/ttfinstrs.html">FontForge: Edit Instructions…</a></li>
<li><a href="https://developer.apple.com/fonts/TTRefMan/RM03/Chap3.html">Apple: Instructing Fonts</a></li>
</ul>
<h2 id="mingliu">MingLiu</h2>
<p>細明體 (MingLiu) 與新細明體 (PMingLiu) 是華康 (DynaLab) 設計的字型,內
建於 Microsoft 的作業系統中,使用非常廣泛。華康的字型使用了特殊的組字
方式,似乎是為了從自有的字型資料轉換到 TrueType 才會使用這樣的方法。</p>
<p>首先,定義一組筆劃的字符,只用來組字,不對應到任何的編碼:</p>
<p><img src="/blog/assets/content/pmingliu_strokes.png" alt="PMingLiu Strokes" /></p>
<p>然後在每一個個別的字符中用參照的方式把筆劃匯入,這時筆劃間的相對位置是
亂的,最後再用 Hinting 的功能把筆劃移動到對的位置去:</p>
<p><img src="/blog/assets/content/pmingliu_uni65b0.png" alt="PMingLiu uni65B0" /></p>
<p><img src="/blog/assets/content/pmingliu_hinting.png" alt="PMingLiu Hinting" /></p>
<p>這樣濫用 Hinting 的方式,也導致如果不開啟 Hinting 就會看到破碎的字符:</p>
<p><img src="/blog/assets/content/pmingliu_broken_glyph.png" alt="PMingLiu Broken Glyph" /></p>
<p>為什麼說是濫用?因為只要沒有打開 Hinting 就會顯示錯誤,表示用錯地方了;
有些時候是不需要,或是沒辦法使用 Hinting 的。</p>
<p>參考資料:</p>
<ul>
<li><a href="http://ubb.frostyplace.com/viewtopic.php?p=92722">老地方冰果室交流區:PDF 裡面新細明體的字會碎掉是因為專利問題?</a></li>
</ul>
<h2 id="tricky-fonts">Tricky Fonts</h2>
<p>除了新細明體,華康還有一些字型也是使用類似的方式組字,同樣很多人使用的
標楷體就是其中之一,還有一些日本字型也是濫用 Hinting 的功能來繪製字符,
所以 FreeType 其實有內建黑名單來對付這樣的字型,遇到了就強制開啟
Hinting。一開始這個名單是用字型名稱來列表的:</p>
<pre data-lang="c" style="background-color:#ffffff;color:#323232;" class="language-c "><code class="language-c" data-lang="c"><span> </span><span style="font-weight:bold;color:#a71d5d;">static const char</span><span> trick_names[TRICK_NAMES_COUNT]
</span><span> [TRICK_NAMES_MAX_CHARACTERS </span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#0086b3;">1</span><span>] </span><span style="font-weight:bold;color:#a71d5d;">=
</span><span> {
</span><span> </span><span style="color:#183691;">"DFKaiSho-SB"</span><span>, </span><span style="font-style:italic;color:#969896;">/* dfkaisb.ttf */
</span><span> </span><span style="color:#183691;">"DFKaiShu"</span><span>,
</span><span> </span><span style="color:#183691;">"DFKai-SB"</span><span>, </span><span style="font-style:italic;color:#969896;">/* kaiu.ttf */
</span><span> </span><span style="color:#183691;">"HuaTianKaiTi?"</span><span>, </span><span style="font-style:italic;color:#969896;">/* htkt2.ttf */
</span><span> </span><span style="color:#183691;">"HuaTianSongTi?"</span><span>, </span><span style="font-style:italic;color:#969896;">/* htst3.ttf */
</span><span> </span><span style="color:#183691;">"MingLiU"</span><span>, </span><span style="font-style:italic;color:#969896;">/* mingliu.ttf & mingliu.ttc */
</span><span> </span><span style="color:#183691;">"PMingLiU"</span><span>, </span><span style="font-style:italic;color:#969896;">/* mingliu.ttc */
</span><span> </span><span style="color:#183691;">"MingLi43"</span><span>, </span><span style="font-style:italic;color:#969896;">/* mingli.ttf */
</span><span> };
</span></code></pre>
<p>但是這樣還不夠,因為很多 PDF 輸出軟體會把字型的名稱亂改:</p>
<pre style="background-color:#ffffff;color:#323232;"><code><span> % pdffonts ~/pdf31yNwCi71d.pdf
</span><span> name type emb sub uni object ID
</span><span> ------------------------------- ----------------- --- --- --- ---------
</span><span> AAAAAA+TimesNewRoman TrueType yes yes yes 9 0
</span><span> AAAAAB+___ TrueType yes yes yes 16 0
</span><span> AAAAAC+___ TrueType yes yes yes 17 0
</span><span> AAAAAE+____ TrueType yes yes yes 18 0
</span><span> AAAAAD+____ TrueType yes yes yes 19 0
</span></code></pre>
<p>遇到這樣的情況就破功了,所以很多人在看 PDF 的時候會遇到字破掉的問題,我
先在<a href="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=591094#186">信</a>中提出可能的解法,後來發現 Suzuki Toshiya 在 2010-11-22 的時候加
入用 <code>cvt/fpgm/prep</code> 表格的加總檢查來比對黑名單,因為這三個表格是只要是
有使用 Hinting 的字型都會有,也不太會改變的。</p>
<pre data-lang="c" style="background-color:#ffffff;color:#323232;" class="language-c "><code class="language-c" data-lang="c"><span> </span><span style="font-weight:bold;color:#a71d5d;">static const</span><span> tt_sfnt_id_rec sfnt_id[TRICK_SFNT_IDS_NUM_FACES]
</span><span> [TRICK_SFNT_IDS_PER_FACE] </span><span style="font-weight:bold;color:#a71d5d;">= </span><span>{
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">...
</span><span> { </span><span style="font-style:italic;color:#969896;">/* MingLiU 1995 */
</span><span> { </span><span style="color:#0086b3;">0x05bcf058</span><span>, </span><span style="color:#0086b3;">0x000002e4 </span><span>}, </span><span style="font-style:italic;color:#969896;">/* cvt */
</span><span> { </span><span style="color:#0086b3;">0x28233bf1</span><span>, </span><span style="color:#0086b3;">0x000087c4 </span><span>}, </span><span style="font-style:italic;color:#969896;">/* fpgm */
</span><span> { </span><span style="color:#0086b3;">0xa344a1ea</span><span>, </span><span style="color:#0086b3;">0x000001e1 </span><span>} </span><span style="font-style:italic;color:#969896;">/* prep */
</span><span> },
</span><span> { </span><span style="font-style:italic;color:#969896;">/* MingLiU 1996- */
</span><span> { </span><span style="color:#0086b3;">0x05bcf058</span><span>, </span><span style="color:#0086b3;">0x000002e4 </span><span>}, </span><span style="font-style:italic;color:#969896;">/* cvt */
</span><span> { </span><span style="color:#0086b3;">0x28233bf1</span><span>, </span><span style="color:#0086b3;">0x000087c4 </span><span>}, </span><span style="font-style:italic;color:#969896;">/* fpgm */
</span><span> { </span><span style="color:#0086b3;">0xa344a1eb</span><span>, </span><span style="color:#0086b3;">0x000001e1 </span><span>} </span><span style="font-style:italic;color:#969896;">/* prep */
</span><span> },
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">...
</span></code></pre>
<p>只是原先這個方法只有在字型沒有名稱的時候才會啟用,我加了 patch 改成無條
件檢查黑名單,從此就應該不會有漏網之魚了。</p>
<p>參考資料:</p>
<ul>
<li><a href="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=591094#186">Re: How to read Chinese PDFs anymore with xpdf?</a></li>
<li><a href="http://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=9f5dd61bf3deee315da14d3aca7f436bbf9cc76a">[truetype] Identify the tricky fonts by cvt/fpgm/prep checksums.</a></li>
<li><a href="http://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=abc47aa1362713192cf8f6747b8de25a3f54e513">[truetype] Always check the checksum to identify tricky fonts.</a></li>
<li><a href="http://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=86b7b2f614873386a3bd56be77c8ba37a69a2a02">[truetype] Revert the reordering of trickyness checking.</a></li>
<li><a href="http://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=1e89d15a2708f98cacb95ec8a0f1386adf062a64">[truetype] Register a set of tricky fonts, NEC FA family.</a></li>
</ul>
<h2 id="sign-extension">Sign Extension</h2>
<p>只是後來我在我的機器上面仍然發現某些 PDF 仍然顯示破碎字型,難道是加總
檢查也會出錯?因為牽扯到<strong>加總</strong>的問題,第一個想到的就是可能跟機器的整
數長度有關,立刻改用 32-bit 的環境測試同一個 PDF,果然就好了。但是計
算檢查碼的演算法很簡單,也沒有溢位的疑慮,那是哪裡出了問題?好在 IRC
上有大大給了提示:</p>
<pre data-lang="irc" style="background-color:#ffffff;color:#323232;" class="language-irc "><code class="language-irc" data-lang="irc"><span> kanru> hum.. checksum *: 0xa344a1eb
</span><span> kanru> checksum #: 0xffffffffa344a1eb
</span><span> j5g> kanru: 哈,因為 init checksum = 0xffffffff, sign extension 變
</span><span> 成 0xffffffffffffffff?
</span><span> j5g> 然後之後都只處理後面 32bit
</span><span> kanru> j5g: 不過有可能是 font 裡面是錯的
</span><span> kanru> 0xffffffffa344a1eb 是直接從 font table 讀出來的
</span><span> j5g> 喔,那就是 0xa344a1eb sign extended to 0xffffffffa344a1eb
</span></code></pre>
<p>原來是 FreeType 在讀入字型資訊的時候,強制把 int 轉型為 uint 結果發生
sign extension 錯誤,之後比對的時候就跟著錯了。送了 patch 之後,應該天
下太平了吧?</p>
<p>參考資料:</p>
<ul>
<li><a href="http://git.savannah.gnu.org/cgit/freetype/freetype2.git/commit/?id=21b1a0de7c052dcd25348c4e3597c8a631108f61">Fix reading of signed integers from files on 64bit platforms.</a></li>
</ul>
<h2 id="pdf-correctness">PDF correctness</h2>
<p>有人問說:那為什麼不乾脆隨時打開 Hinting 就好?據我所知目前的自由 PDF
Viewer 都是預設關閉 Hinting 的,除了上述的理由外,我猜大概是因為
Hinting 有可能大幅度的改變一個字符的寬度,如下圖:</p>
<p><img src="/blog/assets/content/dejavu_ftdiff.png" alt="FtDiff DejaVu" /></p>
<p>可以發現三種顯示方式的寬度都不一樣,而 PDF 是一種接近印刷品質的檔案格
式,有可能在輸出 PDF 的時候已經丟失動態改變寬度的能力,<code>kern</code> 的修正也已
經沒辦法修改,這時候如過還讓 Hinting 去改變字符的寬度的話,很有可能得到
不理想的結果。不過以上只是我的猜想,還沒有找各 PDF Viewer 的作者證實。
至於封閉的商業 PDF Viewer 又是怎麼做的就更不得而知了。</p>
<p>結論:快升級到最新的 FreeType 吧!如果還有遇到顯示錯誤的 PDF 可以寄給
我,如果以上筆記有疏漏錯誤的地方歡迎指正 😋</p>
Speed comparison C vs Common Lisp
2011-08-08T22:28:17+08:00
2011-08-08T22:28:17+08:00
https://static.kanru.info/zh-tw/blog/euler12-common-lisp/
<p>昨天看到有人轉噗一則 <a href="http://stackoverflow.com/questions/6964392/speed-comparison-c-vs-python-vs-erlang-vs-haskell">StackOverflow</a> 上面的問題,內容是問他分別用 C,
python, erlang 與 haskell 寫了 Project Euler 的第<a href="http://projecteuler.net/index.php?section=problems&id=12">十二題</a>,但是
haskell 版本慢得不像話,該如何改進?</p>
<p>以下是苦主的原始 C 語言版:</p>
<pre data-lang="c" style="background-color:#ffffff;color:#323232;" class="language-c "><code class="language-c" data-lang="c"><span> </span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;"><stdio.h>
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">#include </span><span style="color:#183691;"><math.h>
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">factorCount </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">long </span><span>n)
</span><span> {
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">double</span><span> square </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#62a35c;">sqrt </span><span>(n);
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">int</span><span> isquare </span><span style="font-weight:bold;color:#a71d5d;">= </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">int</span><span>) square;
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">int</span><span> count </span><span style="font-weight:bold;color:#a71d5d;">=</span><span> isquare </span><span style="font-weight:bold;color:#a71d5d;">==</span><span> square </span><span style="font-weight:bold;color:#a71d5d;">? -</span><span style="color:#0086b3;">1 </span><span style="font-weight:bold;color:#a71d5d;">: </span><span style="color:#0086b3;">0</span><span>;
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">long</span><span> candidate;
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">for </span><span>(candidate </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">1</span><span>; candidate </span><span style="font-weight:bold;color:#a71d5d;"><=</span><span> isquare; candidate </span><span style="font-weight:bold;color:#a71d5d;">++</span><span>)
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">if </span><span>(</span><span style="color:#0086b3;">0 </span><span style="font-weight:bold;color:#a71d5d;">==</span><span> n </span><span style="font-weight:bold;color:#a71d5d;">%</span><span> candidate) count </span><span style="font-weight:bold;color:#a71d5d;">+= </span><span style="color:#0086b3;">2</span><span>;
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">return</span><span> count;
</span><span> }
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">int </span><span style="font-weight:bold;color:#795da3;">main </span><span>()
</span><span> {
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">long</span><span> triangle </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">1</span><span>;
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">int</span><span> index </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#0086b3;">1</span><span>;
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">while </span><span>(factorCount (triangle) </span><span style="font-weight:bold;color:#a71d5d;">< </span><span style="color:#0086b3;">1001</span><span>)
</span><span> {
</span><span> index </span><span style="font-weight:bold;color:#a71d5d;">++</span><span>;
</span><span> triangle </span><span style="font-weight:bold;color:#a71d5d;">+=</span><span> index;
</span><span> }
</span><span> </span><span style="color:#62a35c;">printf </span><span>(</span><span style="color:#183691;">"</span><span style="color:#0086b3;">%ld\n</span><span style="color:#183691;">"</span><span>, triangle);
</span><span> }
</span></code></pre>
<p>我的執行時間約為 5.48s</p>
<pre data-lang="sh" style="background-color:#ffffff;color:#323232;" class="language-sh "><code class="language-sh" data-lang="sh"><span> % gcc -lm -o euler12.bin euler12.c
</span><span> % time ./euler12.bin
</span><span> 842161320
</span><span> ./euler12.bin 5.48s user 0.00s system 99% cpu 5.484 total
</span></code></pre>
<p>手癢想看看據說可以編譯出不錯的機器碼的 Common Lisp 速度怎麼樣,於是第
一個版本如下 (用 sbcl 執行):</p>
<pre data-lang="lisp" style="background-color:#ffffff;color:#323232;" class="language-lisp "><code class="language-lisp" data-lang="lisp"><span> (</span><span style="font-weight:bold;color:#a71d5d;">defun </span><span style="font-weight:bold;color:#795da3;">factor-count </span><span>(n)
</span><span> (</span><span style="font-weight:bold;color:#a71d5d;">let* </span><span>((square (</span><span style="color:#62a35c;">sqrt</span><span> n))
</span><span> (squaref (</span><span style="color:#62a35c;">floor</span><span> square))
</span><span> (</span><span style="color:#62a35c;">count </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">if </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">eql</span><span> squaref square) </span><span style="font-weight:bold;color:#a71d5d;">-</span><span style="color:#0086b3;">1 0</span><span>)))
</span><span> (</span><span style="font-weight:bold;color:#a71d5d;">loop
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">for</span><span> cand </span><span style="font-weight:bold;color:#a71d5d;">from </span><span style="color:#0086b3;">1 </span><span style="font-weight:bold;color:#a71d5d;">to</span><span> squaref
</span><span> </span><span style="color:#62a35c;">count </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">eql </span><span style="color:#0086b3;">0 </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">rem</span><span> n cand)) into c
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">finally </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">return </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#62a35c;">count</span><span> c c)))))
</span><span> (</span><span style="font-weight:bold;color:#a71d5d;">defun </span><span style="font-weight:bold;color:#795da3;">first-triangle-over </span><span>(n)
</span><span> (</span><span style="font-weight:bold;color:#a71d5d;">loop
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">for</span><span> idx </span><span style="font-weight:bold;color:#a71d5d;">from </span><span style="color:#0086b3;">1
</span><span> </span><span style="color:#62a35c;">sum</span><span> idx into triangle
</span><span> </span><span style="color:#62a35c;">until </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">>= </span><span>(factor</span><span style="font-weight:bold;color:#a71d5d;">-</span><span style="color:#62a35c;">count</span><span> triangle) n)
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">finally </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">return</span><span> triangle)))
</span><span> </span><span style="font-style:italic;color:#969896;">;; (time (first-triangle-over 1000))
</span><span> </span><span style="font-style:italic;color:#969896;">;; Evaluation took:
</span><span> </span><span style="font-style:italic;color:#969896;">;; 11.192 seconds of real time
</span><span> </span><span style="font-style:italic;color:#969896;">;; 11.184699 seconds of total run time (11.184699 user, 0.000000 system)
</span><span> </span><span style="font-style:italic;color:#969896;">;; 99.94% CPU
</span><span> </span><span style="font-style:italic;color:#969896;">;; 30,135,882,489 processor cycles
</span><span> </span><span style="font-style:italic;color:#969896;">;; 32,912 bytes consed
</span><span> </span><span style="font-style:italic;color:#969896;">;;
</span><span> </span><span style="font-style:italic;color:#969896;">;; 842161320
</span></code></pre>
<p>還不錯,11.192s,這個版本採用原文中給 haskell 的建議,使用 rem 而不是 mod,可以
加快一點速度。再給一點關於型別的提示,然後把第一個 function inline,第
二版可以跑出和 C 版本差不多的成績 5.563s :-)</p>
<pre data-lang="lisp" style="background-color:#ffffff;color:#323232;" class="language-lisp "><code class="language-lisp" data-lang="lisp"><span> (</span><span style="color:#62a35c;">declaim </span><span>(inline factor</span><span style="font-weight:bold;color:#a71d5d;">-</span><span style="color:#62a35c;">count</span><span>)) </span><span style="font-style:italic;color:#969896;">;; <----
</span><span> (</span><span style="font-weight:bold;color:#a71d5d;">defun </span><span style="font-weight:bold;color:#795da3;">factor-count </span><span>(n)
</span><span> (</span><span style="font-weight:bold;color:#a71d5d;">let* </span><span>((square (</span><span style="color:#62a35c;">sqrt</span><span> n))
</span><span> (squaref (</span><span style="color:#62a35c;">floor</span><span> square))
</span><span> (</span><span style="color:#62a35c;">count </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">if </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">eql</span><span> squaref square) </span><span style="font-weight:bold;color:#a71d5d;">-</span><span style="color:#0086b3;">1 0</span><span>)))
</span><span> (</span><span style="font-weight:bold;color:#a71d5d;">loop
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">for</span><span> cand </span><span style="font-weight:bold;color:#a71d5d;">from </span><span style="color:#0086b3;">1 </span><span style="font-weight:bold;color:#a71d5d;">to</span><span> squaref
</span><span> </span><span style="color:#62a35c;">count </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">eql </span><span style="color:#0086b3;">0 </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">rem</span><span> n cand)) into c
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">finally </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">return </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">+ </span><span style="color:#62a35c;">count</span><span> c c)))))
</span><span> (</span><span style="font-weight:bold;color:#a71d5d;">defun </span><span style="font-weight:bold;color:#795da3;">first-triangle-over </span><span>(n)
</span><span> (</span><span style="font-weight:bold;color:#a71d5d;">loop
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">for</span><span> idx of</span><span style="font-weight:bold;color:#a71d5d;">-</span><span>type fixnum </span><span style="font-weight:bold;color:#a71d5d;">from </span><span style="color:#0086b3;">1 </span><span style="font-style:italic;color:#969896;">;; <----
</span><span> </span><span style="color:#62a35c;">sum</span><span> idx into triangle of</span><span style="font-weight:bold;color:#a71d5d;">-</span><span>type fixnum </span><span style="font-style:italic;color:#969896;">;; <----
</span><span> </span><span style="color:#62a35c;">until </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">>= </span><span>(factor</span><span style="font-weight:bold;color:#a71d5d;">-</span><span style="color:#62a35c;">count</span><span> triangle) n)
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">finally </span><span>(</span><span style="font-weight:bold;color:#a71d5d;">return</span><span> triangle)))
</span><span> </span><span style="font-style:italic;color:#969896;">;; (time (first-triangle-over 1000))
</span><span> </span><span style="font-style:italic;color:#969896;">;; Evaluation took:
</span><span> </span><span style="font-style:italic;color:#969896;">;; 5.563 seconds of real time
</span><span> </span><span style="font-style:italic;color:#969896;">;; 5.556347 seconds of total run time (5.556347 user, 0.000000 system)
</span><span> </span><span style="font-style:italic;color:#969896;">;; 99.87% CPU
</span><span> </span><span style="font-style:italic;color:#969896;">;; 14,970,270,903 processor cycles
</span><span> </span><span style="font-style:italic;color:#969896;">;; 32,768 bytes consed
</span><span> </span><span style="font-style:italic;color:#969896;">;;
</span><span> </span><span style="font-style:italic;color:#969896;">;; 842161320
</span></code></pre>
<p>純粹湊個熱鬧而已,有興趣的人可以試試看把 loop 改成和原文其他語言一樣使
用遞迴來實做,大部分 Lisp 都有做 TCO,速度應該差不多…</p>
<p>結論:Common Lisp is awesome ;-)</p>
Literate Programming
2011-07-07T01:02:09+08:00
2011-07-07T01:02:09+08:00
https://static.kanru.info/zh-tw/blog/literate-programming/
<blockquote>
<p>Let us change our traditional attitude to the construction of
programs: Instead of imagining that our main task is to instruct a
computer what to do, let us concentrate rather on explaining to human
beings what we want a computer to do.
<br>― Donald Knuth. “Literate Programming (1984)”</p>
</blockquote>
<p><a href="http://www.codemud.net/~thinker/GinGin_CGI.py/">Thinker</a> 的一篇<a href="http://www.codemud.net/~thinker/GinGin_CGI.py/show_id_doc/445">心靈與程式碼的協奏曲</a>提到程式由後往前寫似乎比較符
合思考的方向,不禁讓我想到 <a href="http://www-cs-faculty.stanford.edu/~knuth/">Knuth</a> 提出的 <a href="https://secure.wikimedia.org/wikipedia/en/wiki/Literate_programming">Literate Programming</a> 方
法;其實我們思考的順序有時是跳躍式的,用 LP 的方法可以完全跳脫先後關係,
用自己喜歡的順序來寫,我覺得也可以稱為碎碎唸寫法。</p>
<p>用 Thinker 的同一個例子,改作 <a href="http://www.cs.tufts.edu/~nr/noweb/">noweb</a> 的格式,用 LP 的方法來寫,會變
成怎樣?首先定義問題:</p>
<blockquote>
<p>假設問題是,function 接受一字串,裡面的每一行有兩個欄位,皆是整數。欄
位以一個空白相隔。function 必把每一行的兩個欄位的數字相乘,然後再將每
一行的結果加總。</p>
</blockquote>
<p>我們需要一個接受一個字串的 function :</p>
<pre data-lang="noweb" style="background-color:#ffffff;color:#323232;" class="language-noweb "><code class="language-noweb" data-lang="noweb"><span> <<接受字串的 function>>=
</span><span> def mul_n_sum(data):
</span><span> <<function 內容>>
</span><span> @
</span></code></pre>
<p>這個 function 必須把每一行的兩欄數字相乘,然後相加;假設我們取得每一行
的兩個數字之後照順序存放在 <code>field_lines</code> 這個變數裡面,則用 <code>sum</code> 就可
以把兩兩相乘之後的數字加總:</p>
<pre data-lang="noweb" style="background-color:#ffffff;color:#323232;" class="language-noweb "><code class="language-noweb" data-lang="noweb"><span> <<function 內容>>=
</span><span> <<取得每一行的兩個數字>>
</span><span> return sum([field1 * field2 for field1, field2 in field_lines])
</span><span> @
</span></code></pre>
<p>要怎麼取得每一行的兩個數字呢?首先要把每一行的字串切開:</p>
<pre data-lang="noweb" style="background-color:#ffffff;color:#323232;" class="language-noweb "><code class="language-noweb" data-lang="noweb"><span> <<取得每一行的兩個數字>>=
</span><span> lines = data.strip().split('\n')
</span><span> @
</span></code></pre>
<p>然後被切開的每一行字串經過分割後,會變成依照</p>
<pre style="background-color:#ffffff;color:#323232;"><code><span> [field1, field2],
</span><span> [field1, field2],
</span><span> [field1, field2],
</span><span> ...
</span></code></pre>
<p>順序排列的<em>字串</em>,所以我們還要轉換成數字才能運算:</p>
<pre data-lang="noweb" style="background-color:#ffffff;color:#323232;" class="language-noweb "><code class="language-noweb" data-lang="noweb"><span> <<取得每一行的兩個數字>>=
</span><span> <<分割欄位>>
</span><span> field_lines = [[int(field1), int(field2)] for field1, field2 in txt_field_lines]
</span><span> @
</span></code></pre>
<p>最後,分割欄位有很多方法,因為我們已經知道輸入的格式不會錯誤,所以用簡
單的 <code>str.split()</code> 來切割就可以了:</p>
<pre data-lang="noweb" style="background-color:#ffffff;color:#323232;" class="language-noweb "><code class="language-noweb" data-lang="noweb"><span> <<分割欄位>>=
</span><span> txt_field_lines = [line.split() for line in lines]
</span><span> @
</span></code></pre>
<p>這篇 blog 經過 notangle 的處理,會變成以下的 python 程式:</p>
<pre data-lang="python" style="background-color:#ffffff;color:#323232;" class="language-python "><code class="language-python" data-lang="python"><span> </span><span style="font-style:italic;color:#969896;"># notangle -R'接受字串的 function' literate-programming.mdwn
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">def </span><span style="font-weight:bold;color:#323232;">mul_n_sum</span><span>(data):
</span><span> lines </span><span style="font-weight:bold;color:#a71d5d;">= </span><span>data.strip().split(</span><span style="color:#183691;">'</span><span style="color:#0086b3;">\n</span><span style="color:#183691;">'</span><span>)
</span><span> txt_field_lines </span><span style="font-weight:bold;color:#a71d5d;">= </span><span>[line.split() </span><span style="font-weight:bold;color:#a71d5d;">for </span><span>line </span><span style="font-weight:bold;color:#a71d5d;">in </span><span>lines]
</span><span> field_lines </span><span style="font-weight:bold;color:#a71d5d;">= </span><span>[[</span><span style="color:#0086b3;">int</span><span>(field1), </span><span style="color:#0086b3;">int</span><span>(field2)] </span><span style="font-weight:bold;color:#a71d5d;">for </span><span>field1, field2 </span><span style="font-weight:bold;color:#a71d5d;">in </span><span>txt_field_lines]
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">return </span><span style="color:#62a35c;">sum</span><span>([field1 </span><span style="font-weight:bold;color:#a71d5d;">* </span><span>field2 </span><span style="font-weight:bold;color:#a71d5d;">for </span><span>field1, field2 </span><span style="font-weight:bold;color:#a71d5d;">in </span><span>field_lines])
</span></code></pre>
<p>可以跟 Thinker 的結果比比看 :)</p>
<p>這篇是故意使用類似的思考邏輯來寫,所以會產生相似的程式,且為了展示 LP
我最後還刻意調整了一下順序。只要換一下思考的方向,要寫出 loop 的版本也
是有可能的。重點在於隨想隨寫,邊寫程式邊紀錄思考過程。</p>
<p>碎碎唸的好處是不怕跳躍式的思考,想寫什麼就寫什麼,邊想邊寫,壞處是最後
組合出來的程式一般人可能沒辦法直接看懂,但是這樣寫還真的滿有趣的,有機
會一定要試試!</p>
<p>其他參考資料:</p>
<ul>
<li><a href="http://literateprogramming.com/">Literrate Programming</a></li>
<li><a href="http://jonaquino.blogspot.com/2010/04/nowebpy-or-worlds-first-executable-blog.html">Python 版的 noweb</a></li>
<li><a href="https://github.com/bergie/noweb.php">PHP 版的 noweb</a></li>
</ul>
Android: Wakelocks and TuxOnIce
2011-06-29T00:00:00+08:00
2011-06-29T00:00:00+08:00
https://static.kanru.info/zh-tw/blog/android-wakelocks-n-tuxonice/
<p>最近為了把 <a href="http://tuxonice.net/">TuxOnIce</a> 整到 <a href="https://gitorious.org/0xlab-kernel/kernel/commits/toi/linaro-android.38">Android 上面</a>,著實把 Linux 的電源管
理系統中關於 suspend 與 hibernation 的部份研究了一下。而 Android 為了增
加待機時間加入了 wakelock 的機制,讓情況變得更加複雜。</p>
<h2 id="tuxonice">TuxOnIce</h2>
<h3 id="toi-patch">TOI Patch</h3>
<p>TuxOnIce 簡稱 TOI,前身是 Software Suspend 2,是一個長期在 linux
upstream 以外耕耘的一個休眠補釘,相較於早期整合到 linux kernel 內的
swsusp,TOI 的功能非常豐富,可以指定把記憶體內容儲存到多種不同的位置,
如檔案或置換空間,還可以選擇不同的壓縮方法。</p>
<p>首先幫 ARM 平台加上基本的休眠功能,使用 Hiroshi DOYU 的 patch:</p>
<p><a href="http://article.gmane.org/gmane.linux.power-management.general/20543">http://article.gmane.org/gmane.linux.power-management.general/20543</a></p>
<p>然後到 TOI 網站下載最新的 3.2 補釘,打上去的時候會有一些衝突但是都還滿
容易解決,要注意的是某些衝突是看不出來的,例如因為函式移動位置而造成重
複定義,要小心檢查。</p>
<p>然後因為 TOI 對於非 x86 平台有一些假設現在已經不適用,所以需要修改</p>
<p><a href="https://gitorious.org/0xlab-kernel/kernel/commit/e551caf">https://gitorious.org/0xlab-kernel/kernel/commit/e551caf</a></p>
<h3 id="omapfb">OMAPFB</h3>
<p>使用 Pandaboard 加上 Android 測試才發現從休眠醒來後 LCD 不會自動點亮,
通常在 x86 平台上有 pm-utils 或是 hibernate script 來幫忙處理這種關閉打
開 LCD 的問題,這次我是先在 kernel 內幫 OMAPFB 加上一個電源管理的呼叫,
讓 kernel 醒來的時候自己重新設定 LCD。</p>
<p><a href="https://gitorious.org/0xlab-kernel/kernel/commit/21e0f14">https://gitorious.org/0xlab-kernel/kernel/commit/21e0f14</a></p>
<h3 id="pandaboard-beagleboard-xm">Pandaboard & Beagleboard xM</h3>
<p>在 Pandaboard 或 Beagleboard xM 上面沒有 NAND 可以當作儲存空間,所以一
般都是把檔案放在MMC 上面,第一個 patch 讓 kernel 在開機的時候不要初始化
不存在的 NAND 空間</p>
<p><a href="https://gitorious.org/0xlab-kernel/kernel/commit/3ae6b4c">https://gitorious.org/0xlab-kernel/kernel/commit/3ae6b4c</a></p>
<p>然後因為 MMC 的 probe 需要時間,第二個 patch 讓 TOI 等待指定的 resume
device 已經偵測到之後才開始進行 resume</p>
<p><a href="https://gitorious.org/0xlab-kernel/kernel/commit/1078bd7">https://gitorious.org/0xlab-kernel/kernel/commit/1078bd7</a></p>
<h2 id="wakelock">Wakelock</h2>
<p>wakelock 是 Android 為了讓裝置可以更積極的休眠又不妨礙正常工作的進行而
加入的機制,究竟是好是壞已經在 LKML 與 LWN 上面討論過非
常多次,可以參考:</p>
<ul>
<li><a href="https://lwn.net/Articles/318611/">Wakelocks and the embedded problem</a></li>
<li><a href="https://lwn.net/Articles/388131/">Blocking suspend blockers</a></li>
<li><a href="http://thread.gmane.org/gmane.linux.kernel/985471">Suspend block api (version 7)</a></li>
</ul>
<h3 id="shi-mian-zheng">失眠症</h3>
<p>開始測試 TOI 的效果時遇到的第一個問題就是失眠症,因為 wakelock 從中作
梗,導致每次休眠到一半就被取消掉。原來是因為 TOI 的休眠途徑會先強制檔
案系統把內容寫回,而 MMC 子系統會在寫入/讀取一段時間後嘗試進入低耗電模
式,偏偏 Android 在這裡安插了一個 wakelock,導致之後要凍結所有執行緒的
時候失敗。</p>
<p>解法,首先因為休眠的後半段路徑其實就是要準備進行關機,而一般來說休眠都
是人為啟動,因此可以假設此時使用者了解工作可能還未完成,可以忽略
wakelock,所以第一個 patch 就是讓休眠的路徑不去檢查 wakelock,避免像
MMC 這樣的問題。</p>
<p><a href="https://gitorious.org/0xlab-kernel/kernel/commit/3bb5d6f">https://gitorious.org/0xlab-kernel/kernel/commit/3bb5d6f</a></p>
<p>接下來是一般的待機路徑,似乎是因為新的 kernel 會積極的嘗試把 MMC 變成
低耗電模式,但 OMAP 預設的 MMC timeout 是 100 毫秒,把工作放在 Queue
裡面反而不斷鎖住 wakelock 讓 Android 無法休眠,第二個 patch 就是讓 MMC
子系統在準備休眠的時候就不要作無謂的掙扎,直接進入低耗電模式。</p>
<p><a href="https://gitorious.org/0xlab-kernel/kernel/commit/88823b9">https://gitorious.org/0xlab-kernel/kernel/commit/88823b9</a></p>
<h3 id="shi-shui-zheng">嗜睡症</h3>
<p>解決了失眠症沒想到接下來遇到嗜睡症,因為手機插著 USB 的時候是不會真正
睡著的,所以一直沒機會觀察 Android 睡著是怎麼樣,原來只把 kernel 叫醒
是沒用的,Android 還會檢查目前的 input event 是否屬於 user activity 的
範圍,是的話才會把整個系統帶醒,不然因為 wakelock 的機制,馬上就會又睡
著。</p>
<p>參考:</p>
<ul>
<li><a href="http://www.elinux.org/Android_Power_Management">Android Power Management</a></li>
</ul>
Android 2.3 Introduction & Statistics
2010-12-29T15:41:29+08:00
2010-12-29T15:41:29+08:00
https://static.kanru.info/zh-tw/blog/android23-introduction/
<p>如果你有收看 LWN.net 的話,大概知道每次 linux kernel 有新的 release 前
都會有一次針對這次 release 的統計資料,看看主要的貢獻是由哪些人,哪些
公司完成。藉由這次跟 0xlab 分享 Android 2.3 新特性的時候,我學 LWN.net
做了一些小統計,還滿有趣的。</p>
<h2 id="most-active-android-2-3-organizations-by-changesets">Most active Android 2.3 organizations (by changesets)</h2>
<table>
<tr><td>
<pre>4204 google.com
1354 android.com
98 sonyericsson.com
71 gmail.com
39 codeaurora.org
39 samsung.com
38 intel.com
32 nokia.com
32 holtmann.org
<strong>29 0xlab.org</strong>
25 trusted-logic.com
17 openbossa.org
11 nxp.com
<strong>11 linux.org.tw</strong></pre>
</td><td>
<pre>10 ti.com
10 acer.com.tw
8 themaw.net
8 garmin.com
7 snpe.rs
7 motorola.com
7 mc.pp.se
7 googlemail.com
5 invensense.com
4 mirbsd.org
3 windriver.com
3 realvnc.com
2 teleca.com
2 sharp.co.jp</pre>
</td><td>
<pre>2 nvidia.com
2 motoya.co.jp
2 lge.com
2 broadcom.com
1 yahoo-inc.com
1 xs4all.nl
1 wdsglobal.com
1 uwevoelker.de
1 strongswan.org
1 stericsson.com
1 signove.com
1 saftware.de
1 richlowe.net
1 pv.com</pre>
</td><td>
<pre>1 promwad.com
1 pcc.me.uk
1 padovan.org
1 osbeck.com
1 nii.net
1 martin.st
1 ilovelinux.de
1 happydroid.com
1 droidmod.org
1 cpeterso.com
1 big.or.jp
1 arm.com</pre>
</td></tr>
</table>
<h2 id="most-active-android-2-3-developers-by-lines-changed">Most active Android 2.3 developers (by lines changed)</h2>
<table>
<tr><td>
<pre>Jesse Wilson
Eric Laurent
Dianne Hackborn
David 'Digit' Turner
Nick Pelly
Mathias Agopian
Nick Kralevich
Brian Carlstrom
Eric Fischer
Andreas Huber</pre>
</td>
<td>
<pre>386588
364359
260033
205494
160707
124119
103004
83492
61646
61233</pre>
</td>
<td>
<pre>12.8708%
12.13%
8.65%
6.84%
5.35%
4.13%
3.42%
2.77%
2.05%
2.03%</pre>
</td></tr>
</table>
<iframe src="//www.slideshare.net/slideshow/embed_code/key/dlMOP1jagYENPB" width="595" height="485" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" style="border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%;" allowfullscreen> </iframe> <div style="margin-bottom:5px"> <strong> <a href="//www.slideshare.net/kanru/android23intro" title="Android 2.3 Introduction" target="_blank">Android 2.3 Introduction</a> </strong> from <strong><a target="_blank" href="//www.slideshare.net/kanru">Kan-Ru Chen</a></strong></div>
<p>投影片中還研究了一下各主要開發者主要研究的方向,看 log 的時候依照這個
順序去看,有一定的脈絡可尋 :)</p>
Understanding UUID
2010-11-16T22:16:58+08:00
2010-11-16T22:16:58+08:00
https://static.kanru.info/zh-tw/blog/uuid-el/
<p>通用唯一識別碼 (Universally Unique IDentifier, UUID) 或是全域唯一識別
碼 (Globally Unique IDentifier, GUID) 是一個 128 bits 的整數,並保證其
在時間與空間的分佈都是獨一無二的。UUID 由開放軟體基金會(OSF) 標準化後
用在他們的 DCE 系統上,後來在微軟的 COM 系統上發揚光大。除此之外在許多
地方也都可以看到 UUID 的身影,如 Linux 上的分割表/區塊裝置就是以 UUID
來標示,或是RSS 的 <code><guid></code> 標籤也可以使用 UUID,實際上 UUID 是標準的
URN 表示法之一,你可以在任何需要標示單一物件的地方使用 UUID。</p>
<p>UUID 的文字形式為一個 <code>8-4-4-4-12</code> 的十六進位表示,共有 16 個 bytes,有
人說使用 UUID 不方便人類辨識,但了解 UUID 的組成後你還是可以從這個表示
法看出一些端倪來。本文參考的是 IETF 版本的 RFC4122。</p>
<p><img src="/blog/assets/content/uuid.png" alt="UUID" /></p>
<p>UUID 共有四個版本,第 13 個字元的位置就是表示版本號。第一種是以時間和網
路卡號組成,時間是以一百奈秒為單位,網路卡號理論上是不會重複的,再加上
<code>clock_seq</code> 這個每次開機重設一次的亂數欄位,就算時間回朔了也不會重複,
代號是 <em>1</em>。第二種和第四種是以命名空間加上一個 hash 組成的,分別可以使
用MD5 或是 SHA1 演算法,算出來後就填到空位中,代號是 <em>3</em> 跟 <em>5</em>。第三種
是全亂數組成,代號是 <em>4</em>。</p>
<p>因此我們可以在不同的情境選用不同的 UUID,也可以從 UUID 看出版本跟時間等
資訊,如 <code>4ef17586-f187-11df-8xxx-xxxxxxxxxxxx</code> 看到第三個區塊是
<code>11df</code> 就可以知道是最近產生的以時間卡號為基礎的 UUID,時間
<code>1dff1874ef17586</code> 解出來就是 2010-11-16 13:42:09.173031.0 UTC。而
<code>7c0fdbe4-1b09-4278-9fc9-5f0c6a1f2ae2</code> 就是純亂數的 UUID,沒有任何
意義。</p>
<h2 id="uuid-el">uuid-el</h2>
<p>在轉換 Blog 到 ikiwiki 的時候,為了要整合 Disqus 系統,每篇都需要一個唯
一的識別碼,這樣 Disqus 就只認 UUID 而不是網址,將來網址變了也可以對得
上,而此 ID 也可以用在 RSS, ATOM 上面。研究了 RFC 4122 後,用 elisp 寫
了產生 UUID 的工具,<a href="http://github.com/kanru/uuid-el" title="UUID-el">uuid-el</a>,使用只需要:</p>
<pre data-lang="lisp" style="background-color:#ffffff;color:#323232;" class="language-lisp "><code class="language-lisp" data-lang="lisp"><span> (</span><span style="color:#62a35c;">require</span><span> 'uuid)
</span><span> </span><span style="font-style:italic;color:#969896;">;; Generate UUIDv1
</span><span> (uuid</span><span style="font-weight:bold;color:#a71d5d;">-</span><span style="color:#0086b3;">1</span><span>)
</span><span> </span><span style="font-style:italic;color:#969896;">;; Generate UUIDv4
</span><span> (uuid</span><span style="font-weight:bold;color:#a71d5d;">-</span><span style="color:#0086b3;">4</span><span>)
</span><span> </span><span style="font-style:italic;color:#969896;">;; Generate UUIDv3, v5
</span><span> (uuid</span><span style="font-weight:bold;color:#a71d5d;">-</span><span style="color:#0086b3;">3</span><span> uuid</span><span style="font-weight:bold;color:#a71d5d;">-</span><span>ns</span><span style="font-weight:bold;color:#a71d5d;">-</span><span>url </span><span style="color:#183691;">"http://example.com"</span><span>)
</span><span> (uuid</span><span style="font-weight:bold;color:#a71d5d;">-</span><span style="color:#0086b3;">4</span><span> uuid</span><span style="font-weight:bold;color:#a71d5d;">-</span><span>ns</span><span style="font-weight:bold;color:#a71d5d;">-</span><span>url </span><span style="color:#183691;">"http://example.com"</span><span>)
</span></code></pre>
<p>搭配以下 snippet 就可以快速展開需要的 metadata:</p>
<pre style="background-color:#ffffff;color:#323232;"><code><span> # -*- mode: snippet -*-
</span><span> # name: meta
</span><span> # key: meta
</span><span> # --
</span><span> \[[!meta title="$1"]]
</span><span> \[[!meta guid="${1:$(uuid-urn (uuid-5 uuid-ns-kanru text))}"]]
</span><span> \[[!meta date="${2:`(current-time-string)`}"]]
</span><span> $0
</span></code></pre>
<p>最後補上影片:</p>
<div style="text-align:center">
<video src="/blog/assets/content/uuid-el_in_action.webm" width="478" height="280" controls></video>
</div>
<p>下一集:用 ffmpeg 製作桌面錄影</p>
Blog Redesigned
2010-11-15T22:04:38+08:00
2010-11-15T22:04:38+08:00
https://static.kanru.info/zh-tw/blog/blog-redesigned/
<p>最近又把 Blog 整頓了一番,目標是改用靜態網頁。使用靜態網頁搭配一些網頁
樣板程式不禁讓人想起最初使用 MT 來寫 Blog 的時候,不同的是現在有像
<a href="http://disqus.com/">Disqus</a> 或是 <a href="http://www.intensedebate.com/">IntenseDebate</a> 這樣的動態留言服務,讓網頁可以完全
的只提供靜態內容,不用多一個 cgi 程式來提供留言功能,這隱然成為最近流行
的網頁設計方法之一。</p>
<p>轉換的過程中學到一些新東西,紀錄於此。</p>
<h2 id="wang-ye-bian-yi-qi">網頁編譯器</h2>
<p>現在網頁是用
<img src="https://kanru.info/blog/assets/content/ikiwiki.png" alt="IkiWiki" />
產生的,它是大師 <a href="http://ikiwiki.info/users/joey/">Joey Hess</a> 的作品,大師稱它是一個
<em lang="en">wiki compiler</em>,
可以透過各種規則把網頁的原始碼 (可能是 markdown 的格式) 轉成 HTML 網頁。
因為強大的 inline 規則以及各式各樣的外掛程式,也有許多人把 ikiwiki 當作
Blog 的平台。</p>
<p>轉換的過程其實滿順利的,因為舊的 Blog 都是以 Markdown 寫成,換到
ikiwiki 的 Markdown 引擎只需要一點點修改。要感謝 Wordpress 可以把資料
庫匯出成 XML 格式,轉換只需要簡單的 XSLT 就完成了,我用的
<a href="https://kanru.info/blog/assets/content/wp2txt.xsl">XSL</a> 是參考<a href="http://ikiwiki.info/tips/Importing_posts_from_Wordpress/">這裡</a>修改,去掉
Comment 以及更新 meta的格式而成。</p>
<p>改用文字編輯器來寫 Blog 後,會習慣在 72 行的地方換行,但是在瀏覽器中只
要換行就會多一個空白,以前寫網頁的時候遇到中文都要小心的換行才不會讓不
該空白的地方出現空白,也不能打開 Emacs 的 auto-fill 模式。拜 ikiwiki
強大的外掛程式架構以及 Perl 的 Unicode 正規表示式支援,寫個
<a href="https://kanru.info/blog/assets/content/cjkfix.pm">外掛</a>把不該空白的地方黏起來只要幾分鐘
時間!而 Blog 原始碼則維持容易閱讀的格式。</p>
<p><img src="https://kanru.info/blog/assets/content/2010-11-14-234802_488x420_scrot.png" alt="screenshot" /></p>
<h2 id="html5">HTML5</h2>
<p>既然都換了 Blog 系統,也打算換新的版面,乾脆就升級到網頁標準的新世代
HTML5。在收集 HTML5 相關資訊時發現了 <a href="http://html5boilerplate.com/">HTML5 Boilerplate</a> 這個網頁樣
板計畫,包含了許多目前 HTML5 的 Best Practice,基於這個樣板設計網頁讓
你馬上就 HTML5 Ready ☺</p>
<p>我認為 HTML5 最有趣的一點是帶有語意的新標籤,如 <code><article></code>,
<code><section></code> 等等,搭配新的<a href="http://www.whatwg.org/specs/web-apps/current-work/multipage/sections.html">大綱演算法</a>可以自動產生大綱,運用得當
的話,對於機器或是身體不便的人都能更方便的取得資訊。</p>
<p>ikiwiki 原本就有支援實驗性的 HTML5 模式,但是預設的樣板不是很完美,例如
多層嵌套的 <code><section></code> 與 <code><nav></code> 和 <code><article></code>,都會產生多餘的大綱節
點,若只是需要群組與排版功能的話,最好還是使用 <code><div></code> 就好。如我現在
用的 template 長得就像這樣:</p>
<pre data-lang="html" style="background-color:#ffffff;color:#323232;" class="language-html "><code class="language-html" data-lang="html"><span> <</span><span style="color:#63a35c;">article</span><span>>
</span><span> <</span><span style="color:#63a35c;">header</span><span>>
</span><span> <</span><span style="color:#63a35c;">h1</span><span>>TITLE</</span><span style="color:#63a35c;">h1</span><span>>
</span><span> <</span><span style="color:#63a35c;">time</span><span>>TIME</</span><span style="color:#63a35c;">time</span><span>>
</span><span> </</span><span style="color:#63a35c;">header</span><span>>
</span><span> <</span><span style="color:#63a35c;">div </span><span style="color:#795da3;">class</span><span>=</span><span style="color:#183691;">"content"</span><span>>
</span><span> CONTENT
</span><span> </</span><span style="color:#63a35c;">div</span><span>>
</span><span> <</span><span style="color:#63a35c;">footer</span><span>></</span><span style="color:#63a35c;">footer</span><span>>
</span><span> </</span><span style="color:#63a35c;">article</span><span>>
</span></code></pre>
<p>這裡推薦使用 <a href="http://gsnedders.html5.org/outliner/">HTML 5 Outliner</a> 來檢查網頁的大綱,或是用專門的
<a href="https://chrome.google.com/extensions/detail/afoibpobokebhgfnknfndkgemglggomo">Chrome 擴展</a>,如果網頁設計無誤,應該會看到如下乾淨的大綱:</p>
<p><img src="https://kanru.info/blog/assets/content/2010-11-15-001750_1366x768_scrot.png" alt="screenshot" /></p>
<h2 id="web-fonts">Web Fonts</h2>
<p>使用網路字體可以讓網頁在不同的作業系統、不同的瀏覽器上看起來都是一樣的,
現在有很多提供網路字體的服務,像是 Google 也推出
<a href="https://fonts.google.com/">Google Font Directory</a>,甚至 <a href="http://webfonts.fonts.com/">Fonts.com</a> 還有免費的中文網路字體,
參考 <a href="http://www.typeisbeautiful.com/">Type Is Beautiful</a> 的<a href="http://www.typeisbeautiful.com/files/webfonts.html">測試頁</a>,速度還不錯呢。</p>
<p>我現在用的是從 <a href="http://www.fontsquirrel.com/">Font Squirrel</a> 下載的自由字體,這個網站上不但有大
量的自由字體可以挑選,還有預先整理好的 @font-face Kits 可以直接使用,
或是用 @font-face Generator 產生最佳化的網路字體。</p>
<h2 id="jie-yu">結語</h2>
<p>這篇是心得筆記的性質,因為如果不紀錄一下可能很快就忘了…有許多細節都省
略過去,若是要深入探討則每個主題都可以發展成長篇大論,需要更詳細資料的
網友可以參考引用的連結。</p>
<p>一些眉眉角角的東西希望之後有機會可以再單獨拿出來分享囉 ☻</p>
TOP 20 Space-Hungry Packages
2010-11-14T16:40:13+08:00
2010-11-14T16:40:13+08:00
https://static.kanru.info/zh-tw/blog/gen-top20pkg/
<p>Arch Linux 與 Debian 皆可以在安裝的時候選擇最小安裝,究竟哪一個
Distribution 在使用一段時間之後最佔空間呢? 剛安裝完的時候似乎是 Arch
比較小一點,但是因為 Debian 套件切的比較細,所以最後可能是 Debian 會比
較小。</p>
<p>當初在試用 Arch 的時候寫了小程式來畫出前 20 個最佔空間的套件,並依此來
瘦身,結果如下:</p>
<p><img src="/blog/assets/content/arch-top20pkg.png" alt="Arch Linux Package Size TOP 20" /></p>
<p><img src="/blog/assets/content/debian-top20pkg.png" alt="Debian Package Size TOP 20" /></p>
<p>兩邊因為安裝的套件種類不同因此無從比較,Arch 的 TeXLive 因為沒有切所以
會比 Debian 上較大一點,Debian 上的 ghc6 則是為了測試 xmonad 裝的,
Haskell 本身做出來的執行檔就頗大,ghc6 需要 369MB 實在不意外…</p>
<p>底下是製作圖片的程式,實際上是用 Google Chart API 畫的:</p>
<pre data-lang="python" style="background-color:#ffffff;color:#323232;" class="language-python "><code class="language-python" data-lang="python"><span> </span><span style="font-style:italic;color:#969896;">#!/usr/bin/python
</span><span> </span><span style="font-style:italic;color:#969896;"># -*- coding: utf-8 -*-
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">from </span><span>pygooglechart </span><span style="font-weight:bold;color:#a71d5d;">import </span><span>StackedHorizontalBarChart, Axis
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">from </span><span>subprocess </span><span style="font-weight:bold;color:#a71d5d;">import </span><span style="color:#0086b3;">*
</span><span>
</span><span> </span><span style="color:#0086b3;">TITLE</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#183691;">"Debian Package Size TOP 20"
</span><span> </span><span style="color:#0086b3;">PKGSIZE_PROG</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#183691;">"./dpkgsize"
</span><span> </span><span style="color:#0086b3;">OUTPUT</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#183691;">"debian-top20pkg.png"
</span><span>
</span><span> chart </span><span style="font-weight:bold;color:#a71d5d;">= </span><span>StackedHorizontalBarChart(</span><span style="color:#0086b3;">930</span><span>, </span><span style="color:#0086b3;">320</span><span>)
</span><span> chart.set_bar_width(</span><span style="color:#0086b3;">10</span><span>)
</span><span> chart.set_title(</span><span style="color:#0086b3;">TITLE</span><span>)
</span><span>
</span><span> size_data </span><span style="font-weight:bold;color:#a71d5d;">= </span><span>[]
</span><span> name_data </span><span style="font-weight:bold;color:#a71d5d;">= </span><span>[]
</span><span>
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">for </span><span>ln </span><span style="font-weight:bold;color:#a71d5d;">in </span><span>Popen([</span><span style="color:#0086b3;">PKGSIZE_PROG</span><span>], stdout</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#0086b3;">PIPE</span><span>).stdout:
</span><span> size, name </span><span style="font-weight:bold;color:#a71d5d;">= </span><span>ln.split()
</span><span> size_data.append(</span><span style="color:#0086b3;">int</span><span>(size))
</span><span> name_data.append(name)
</span><span>
</span><span> chart.add_data(size_data[:</span><span style="color:#0086b3;">20</span><span>])
</span><span>
</span><span> max_size </span><span style="font-weight:bold;color:#a71d5d;">= </span><span>size_data[</span><span style="color:#0086b3;">20</span><span>]
</span><span> min_size </span><span style="font-weight:bold;color:#a71d5d;">= </span><span>size_data[</span><span style="color:#0086b3;">0</span><span>]
</span><span> label </span><span style="font-weight:bold;color:#a71d5d;">= </span><span style="color:#62a35c;">map</span><span>(</span><span style="font-weight:bold;color:#a71d5d;">lambda </span><span>x: </span><span style="color:#0086b3;">str</span><span>(x </span><span style="font-weight:bold;color:#a71d5d;">/ </span><span style="color:#0086b3;">1024</span><span>)</span><span style="font-weight:bold;color:#a71d5d;">+</span><span style="color:#183691;">"MB"</span><span>,
</span><span> </span><span style="color:#0086b3;">xrange</span><span>(min_size, max_size, (max_size</span><span style="font-weight:bold;color:#a71d5d;">-</span><span>min_size)</span><span style="font-weight:bold;color:#a71d5d;">/</span><span style="color:#0086b3;">10</span><span>))
</span><span> label.reverse()
</span><span>
</span><span> rev_name_data </span><span style="font-weight:bold;color:#a71d5d;">= </span><span>name_data[:</span><span style="color:#0086b3;">20</span><span>]
</span><span> rev_name_data.reverse()
</span><span> chart.set_axis_labels(Axis.</span><span style="color:#0086b3;">LEFT</span><span>, rev_name_data)
</span><span> chart.set_axis_labels(Axis.</span><span style="color:#0086b3;">BOTTOM</span><span>, label)
</span><span>
</span><span> </span><span style="color:#62a35c;">print</span><span>(chart.get_url())
</span><span> chart.download(</span><span style="color:#0086b3;">OUTPUT</span><span>)
</span></code></pre>
<p>把 <code>PKGSIZE_PROG</code> 代換成自己 Distro 的就可以了:</p>
<p>Debian:</p>
<pre data-lang="sh" style="background-color:#ffffff;color:#323232;" class="language-sh "><code class="language-sh" data-lang="sh"><span> </span><span style="font-style:italic;color:#969896;">#!/bin/sh
</span><span> dpkg-query -W -f</span><span style="font-weight:bold;color:#a71d5d;">=</span><span style="color:#183691;">'${Installed-Size} ${Package}\n'</span><span style="font-weight:bold;color:#a71d5d;">|</span><span>sort -nr
</span></code></pre>
<p>Arch:</p>
<pre data-lang="sh" style="background-color:#ffffff;color:#323232;" class="language-sh "><code class="language-sh" data-lang="sh"><span> </span><span style="font-style:italic;color:#969896;">#!/bin/sh
</span><span> pacman -Qi</span><span style="font-weight:bold;color:#a71d5d;">|</span><span>awk </span><span style="color:#183691;">'/^Installed Size/{print int($4), name} /^Name/{name=$3}'</span><span style="font-weight:bold;color:#a71d5d;">|</span><span>sort -nr
</span></code></pre>
Cool stuff: Pipeline library
2010-11-07T21:37:23+08:00
2010-11-07T21:37:23+08:00
https://static.kanru.info/zh-tw/blog/libpipeline/
<p>如何在 C 程式中方便使用 pipeline 呢?</p>
<p>Unix pipeline 之父說 Unix 程式的哲學就是「只做一件事,並把它做好」:</p>
<blockquote>
<p>“This is the Unix philosophy: Write programs that do one thing and do
it well. Write programs to work together. Write programs to handle
text streams, because that is a universal interface.”
― Doug McIlroy, the inventor of Unix pipes</p>
</blockquote>
<p>平常有在使用 shell 的朋友想必對 <code>|</code> 這個符號不陌生,他可以把多個指令頭尾相接,各展所長,讓我們可以把各程式的力量組合起來成一個強大的 pipeline。</p>
<p>在 shell script 中可以輕鬆做到的事在程式中就不一定這麼簡單了,在 perl 中可以直接用 <code>open</code> 打開程式作為輸出入裝置,在 python 中有 <code>subprocess</code> 模組的 <code>Popen</code> 可以用,但如果只寫 C 呢?你可以用 <code>pipe2</code> 配合 <code>fork</code> 與 <code>exec</code>—沒錯,想起 Unix Programming 課本了嗎 ;-)</p>
<p>用 C 寫這樣的程式既麻煩又容易寫錯,<a href="http://www.chiark.greenend.org.uk/ucgi/~cjwatson/blosxom/">Colin Watson</a> <a href="http://www.chiark.greenend.org.uk/ucgi/~cjwatson/blosxom/2010/10/03#2010-10-03-pipeline-library">寫到</a>他在維護 man-db 的時候為此寫了專用的 pipeline library,現在決定要把 <a href="http://libpipeline.nongnu.org/">libpipeline</a> 獨立以 GPLv3 <a href="http://www.chiark.greenend.org.uk/ucgi/~cjwatson/blosxom/2010/10/29#2010-10-29-libpipeline-released">釋出</a>。</p>
<p>使用 libpipeline 如果我們要產生像</p>
<pre data-lang="sh" style="background-color:#ffffff;color:#323232;" class="language-sh "><code class="language-sh" data-lang="sh"><span> apt-get moo</span><span style="font-weight:bold;color:#a71d5d;">|</span><span>cowsay -n
</span></code></pre>
<p>這樣的 pipeline,可以這樣寫:</p>
<pre data-lang="c" style="background-color:#ffffff;color:#323232;" class="language-c "><code class="language-c" data-lang="c"><span> pipeline </span><span style="font-weight:bold;color:#a71d5d;">*</span><span>p;
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">int</span><span> status;
</span><span> p </span><span style="font-weight:bold;color:#a71d5d;">= </span><span>pipeline_new ();
</span><span> pipeline_command_args (p, </span><span style="color:#183691;">"apt-get"</span><span>, </span><span style="color:#183691;">"moo"</span><span>, </span><span style="color:#0086b3;">NULL</span><span>);
</span><span> pipeline_command_args (p, </span><span style="color:#183691;">"cowsay"</span><span>, </span><span style="color:#183691;">"-n"</span><span>, </span><span style="color:#0086b3;">NULL</span><span>);
</span><span> pipeline_start (p);
</span><span> status </span><span style="font-weight:bold;color:#a71d5d;">= </span><span>pipeline_wait (p);
</span><span> pipeline_free (p);
</span></code></pre>
<p>還可以在 pipeline 中間安插 “built-in” 命令:</p>
<pre data-lang="c" style="background-color:#ffffff;color:#323232;" class="language-c "><code class="language-c" data-lang="c"><span> command </span><span style="font-weight:bold;color:#a71d5d;">*</span><span>inproc </span><span style="font-weight:bold;color:#a71d5d;">= </span><span>command_new_function (</span><span style="color:#183691;">"in-process"</span><span>, </span><span style="font-weight:bold;color:#a71d5d;">&</span><span>func, </span><span style="color:#0086b3;">NULL</span><span>, </span><span style="color:#0086b3;">NULL</span><span>);
</span><span> pipeline_command (p, inproc);
</span></code></pre>
<p>有趣嗎?更詳細的說明可以參考 <a href="http://libpipeline.nongnu.org/libpipeline.3.html">libpipeline(3)</a> 說明文件。</p>
Kindle 來我家
2010-09-22T13:34:56+08:00
2010-09-22T13:34:56+08:00
https://static.kanru.info/zh-tw/blog/kindle-1/
<h3 id="zuo-gong-ke">做功課</h3>
<p>是這樣的,某天在 IRC 上看到某長輩發言 “j5g: Hmm….有點想買 Kindle DX”,小宇宙就有了光,開始上網搜尋 Kindle 相關資訊,經過 Amazon, Wikipedia, Mobile01, MobileRead 無情的生火之後,終於爆炸了啦啦啦!首先是 Kindle DX 的<a href="http://wiki.mobileread.com/wiki/Kindle_DX">規格</a>:</p>
<ul>
<li>顯示:9.7 吋 E-Ink®, 825x1200 畫素,150 ppi, 16 級灰階,大小約比 A4 小一點</li>
<li>重量:536 克,適合坐著閱讀</li>
<li>記憶空間:4G</li>
<li>連線: MicroUSB</li>
<li>網路: 3G 上網</li>
<li>CPU: Freescale 532 MHz, ARM11 (猜測)</li>
<li>作業系統: Linux 2.6.10*</li>
</ul>
<p>嗯.. 作業系統是 Linux!有門!趕緊再搜尋一下,的確已經有許許多多成功 Hack Kindle 的案例,其容易的程度,說他是 Hackable Device 也不為過。</p>
<h3 id="kai-xiang">開箱</h3>
<p>折騰了兩週,訂購的 Kindle DXG 終於在生日當天送達!小小開箱慶祝一下:</p>
<p><a href="http://kanru.info/blog/wp-content/uploads/2010/09/IMG_20100915_193648.jpg"><img src="//kanru.info/blog/wp-content/uploads/2010/09/IMG_20100915_193648-225x300.jpg" alt="" title="IMG_20100915_193648" width="225" height="300" class="alignnone size-medium wp-image-899" /></a>
<a href="http://kanru.info/blog/wp-content/uploads/2010/09/IMG_20100915_193702.jpg"><img src="//kanru.info/blog/wp-content/uploads/2010/09/IMG_20100915_193702-225x300.jpg" alt="" title="IMG_20100915_193702" width="225" height="300" class="alignnone size-medium wp-image-900" /></a><a href="http://kanru.info/blog/wp-content/uploads/2010/09/IMG_20100916_100425.jpg"><img src="//kanru.info/blog/wp-content/uploads/2010/09/IMG_20100916_100425-300x225.jpg" alt="" title="IMG_20100916_100425" width="300" height="225" class="alignnone size-medium wp-image-901" /></a></p>
<p>開箱之後就是充電,開始把各種不同的文件丟進去測試。這個版本的 Firmware (2.5.5) 對於 PDF 的支援其實已經不錯了,會自動裁掉多餘的留白,內嵌字型也都正常顯示,是一開始閱讀中文的方案之一。測試各種檔案之後發現只有一種不太適合放上來看,就是字很多的雙欄格式論文,因為顯示全頁會顯的字太小,偏偏 150 ppi 的解析度看不太清楚,若是放大瀏覽的話,雙欄論文的走向會需要來回拖拉,而拖拉正是目前 E-Ink® 的弱點…</p>
<p>除此之外,在 Kindle 上面閱讀是非常好的體驗,E-Ink® 的特性可以讓人真的進入閱讀的情境之中,內建的 Text-To-Speech 質量非常好,就有如真人在幫你朗讀一樣,新版的 Firmware 還新增了 Collection 的功能,解決 Kindle 以前一直為人詬病的無法分類電子書的問題,Kindle 3 的新 3.0 Firmware 還有直接支援多國語言,內建 Webkit 瀏覽器等。</p>
<h3 id="zhong-wen">中文</h3>
<p>最早是把中文檔案做成 PDF 後再放進去瀏覽,但是 PDF 沒有章節不能做註解不能改變字型大小,就是有那麼一點不方便,如果可以直接看中文電子書多好?一不做二不休參考 <a href="http://www.mobileread.com/forums/forumdisplay.php?f=140">MobileRead 論壇</a>上的 <a href="http://www.mobileread.com/forums/showthread.php?t=88004">Font Hack</a>,先 JB 後安裝字型,之後就可以開始看中文電子書了!</p>
<p>不過因為系統一次只用一種字型,沒有 Fontconfig 的取代機制,所以若是把字型全部直接換為 Droid Sans Fallback,那所有的 Sans, Serif, Mono 通通變得一樣醜… 這時把 FontForge 拿出來,寫個 Script 把原本的 Kindle 字型和 Droid Sans Fallback 合併,就可以保留美觀的英文字跟還可以的中文。</p>
<pre data-lang="python" style="background-color:#ffffff;color:#323232;" class="language-python "><code class="language-python" data-lang="python"><span> </span><span style="font-style:italic;color:#969896;"># merge-fonts.pe
</span><span> </span><span style="font-style:italic;color:#969896;"># Usage:
</span><span> </span><span style="font-style:italic;color:#969896;"># Put the Chinese fonts under ch/ and original fonts under en/
</span><span> </span><span style="font-style:italic;color:#969896;"># Run: fontforge -script merge-fonts.pe
</span><span> </span><span style="font-style:italic;color:#969896;">#
</span><span> </span><span style="font-style:italic;color:#969896;"># Pre-operation for some non-standard Chinese font file
</span><span> Open(</span><span style="color:#183691;">"ch/Droid_Sans_Fallback.ttf"</span><span>)
</span><span> SelectAll()
</span><span> ScaleToEm(</span><span style="color:#0086b3;">1024</span><span>)
</span><span> Generate(</span><span style="color:#183691;">"temp.ttf"</span><span>, </span><span style="color:#183691;">""</span><span>, </span><span style="color:#0086b3;">0x14</span><span>)
</span><span> Close()
</span><span>
</span><span> </span><span style="font-style:italic;color:#969896;"># Open English font and merge to the Chinese font
</span><span> Open(</span><span style="color:#183691;">"en/Helvetica_LT_65_Medium.ttf"</span><span>)
</span><span> SelectAll()
</span><span> ScaleToEm(</span><span style="color:#0086b3;">1024</span><span>)
</span><span>
</span><span> MergeFonts(</span><span style="color:#183691;">"temp.ttf"</span><span>)
</span><span> Generate(</span><span style="color:#183691;">"Sans_Regular.ttf"</span><span>, </span><span style="color:#183691;">""</span><span>, </span><span style="color:#0086b3;">0x14</span><span>)
</span><span> Close()
</span><span> </span><span style="font-style:italic;color:#969896;"># Add more fonts below
</span></code></pre>
<p>不過這樣處理過的字型是不能散佈的,自己使用就好囉 ;-)</p>
<p>現在可以到<a href="http://www.gutenberg.org/wiki/Main_Page">古騰堡計劃</a>下載電子書,或是把<a href="http://haodoo.net">好讀網</a>的 PDB 格式利用 Calibre <a href="http://kanru.github.com/calibre-haodoo">轉成 Mobi 檔案</a>給 Kindle 用。當然若是有出版商販賣 .epub 格式或是其他可以轉檔的電子書,也都可以在 Kindle 上面瀏覽了 :)</p>
<p><a href="http://kanru.info/blog/wp-content/uploads/2010/09/IMG_20100916_221236.jpg"><img src="//kanru.info/blog/wp-content/uploads/2010/09/IMG_20100916_221236-217x300.jpg" alt="" title="IMG_20100916_221236" width="217" height="300" class="alignnone size-medium wp-image-904" /></a>
<a href="http://kanru.info/blog/wp-content/uploads/2010/09/screen_shot-14301.gif"><img src="//kanru.info/blog/wp-content/uploads/2010/09/screen_shot-14301-206x300.gif" alt="" title="screen_shot-14301" width="206" height="300" class="alignnone size-medium wp-image-903" /></a><a href="http://kanru.info/blog/wp-content/uploads/2010/09/screen_shot-14303.gif"><img src="//kanru.info/blog/wp-content/uploads/2010/09/screen_shot-14303-206x300.gif" alt="" title="screen_shot-14303" width="206" height="300" class="alignnone size-medium wp-image-902" /></a></p>
<h3 id="yue-du-zhi-yu">閱讀之餘</h3>
<p>如最前面所說,Kindle 可以不只是電子書,還是台 Hackable 的玩意。諸如用 <a href="http://igorsk.blogspot.com/2007/12/hacking-kindle-part-3-root-shell-and.html">RS232 連線</a>,安裝自己的程式甚至是 <a href="http://hackaday.com/2009/09/03/ubuntu-9-04-on-kindle-2/">Ubuntu</a> 都有人做過了,哪一天 Amazon 真的不再提供軟體升級的時候,我知道我的 Kindle 還是可以繼續帶來不一樣的樂趣 :)</p>
<p>從 Amazon 取得 <a href="https://www.amazon.com/gp/help/customer/display.html?ie=UTF8&nodeId=200203720">Kindle 的 GPL 源始碼</a>,搭配 Firmware Update 的檔案內容,可以發現 Kindle 是相當傳統的 Linux 環境加上 Java 寫的系統程式,因此只要拿到 shell 之後 (無論是透過為裝的 Firmware Update 或是直接拉線開 serial port,或是開 USB Network),就可以作很多有趣的事 :)</p>
<pre style="background-color:#ffffff;color:#323232;"><code><span> 0 ./gplrelease/
</span><span> 368 ./gplrelease/alsa-lib-1.0.13_patch.tar.gz
</span><span> 544 ./gplrelease/alsa-utils-1.0.13_patch.tar.gz
</span><span> 946 ./gplrelease/e2fsprogs-1.38_patch.tar.gz
</span><span> 1529 ./gplrelease/procps-3.2.7_patch.tar.gz
</span><span> 2131 ./gplrelease/module-init-tools-3.2.2_patch.tar.gz
</span><span> 3996 ./gplrelease/base-files-3.0.14.ipk
</span><span> 20480 ./gplrelease/fuse-2.7.1_link.tar
</span><span> 41295 ./gplrelease/picocom-1.4.tar.gz
</span><span> 44398 ./gplrelease/hotplug-2004_09_20.tar.gz
</span><span> 46222 ./gplrelease/base-passwd_3.5.9.tar.gz
</span><span> 55813 ./gplrelease/dosfstools-2.11.tar.bz2
</span><span> 72842 ./gplrelease/powertop-1.10.tar.gz
</span><span> 80630 ./gplrelease/bonnie++-1.03c.tgz
</span><span> 99009 ./gplrelease/sysvinit-2.86.tar.gz
</span><span> 169182 ./gplrelease/module-init-tools-3.2.2.tar.bz2
</span><span> 173558 ./gplrelease/iptables-1.3.3.tar.bz2
</span><span> 194250 ./gplrelease/udev-112.tar.bz2
</span><span> 222558 ./gplrelease/bootchart-0.9.tar.bz2
</span><span> 280041 ./gplrelease/mtd-utils-1.0.0.tar.gz
</span><span> 280938 ./gplrelease/lrzsz-0.12.20.tar.gz
</span><span> 281965 ./gplrelease/procps-3.2.7.tar.gz
</span><span> 345794 ./gplrelease/libol-0.3.18.tar.gz
</span><span> 375416 ./gplrelease/ifupdown_0.6.8.tar.gz
</span><span> 426692 ./gplrelease/lzo-1.08.tar.gz
</span><span> 506312 ./gplrelease/fuse-2.7.1.tar.gz
</span><span> 607442 ./gplrelease/taglib-1.5.tar.bz2
</span><span> 649399 ./gplrelease/klibc-1.5.tar.bz2
</span><span> 709862 ./gplrelease/alsa-lib-1.0.13.tar.bz2
</span><span> 712166 ./gplrelease/syslog-ng-1.6.11.tar.gz
</span><span> 961662 ./gplrelease/readline-4.3.tar.gz
</span><span> 980874 ./gplrelease/alsa-utils-1.0.13.tar.bz2
</span><span> 1195099 ./gplrelease/gst-plugins-base-0.10.6.tar.bz2
</span><span> 1370907 ./gplrelease/util-linux-2.12r.tar.bz2
</span><span> 1735498 ./gplrelease/busybox-1.7.2.tar.bz2
</span><span> 1849092 ./gplrelease/gst-plugins-base-0.10.17.tar.bz2
</span><span> 2167909 ./gplrelease/gstreamer-0.10.17.tar.bz2
</span><span> 2902738 ./gplrelease/glib-2.12.9.tar.bz2
</span><span> 3621193 ./gplrelease/e2fsprogs-1.38.tar.gz
</span><span> 6969637 ./gplrelease/uboot-1.3.0-rc3.tar.bz2
</span><span>13080365 ./gplrelease/binutils-2.17.50.0.5.tar.bz2
</span><span>15321839 ./gplrelease/glibc-2.5.tar.bz2
</span><span>39707720 ./gplrelease/gcc-4.1.2.tar.bz2
</span><span>47285020 ./gplrelease/linux-2.6.22-lab126.tar.bz2
</span></code></pre>
<p>Happy Hacking!</p>
<h3 id="update">Update</h3>
<p>有網友提到有個名為“多看”的自製系統,可以安裝在 Kindle 上和原本系統共存。此自製系統整明了要以 Kindle 硬體為底打造自己的電子書系統是可行的,還支援了中文輸入、直接閱讀 ePub 等,社群討論也很踴躍。<strong>但是</strong> 此系統內許多元件來自 GPL/LGPL 授權的自由軟體,<strong>卻沒有提供相關的原始碼</strong>,此為不正確的示範,希望該團隊不要再自欺欺人…</p>
<pre data-lang="txt" style="background-color:#ffffff;color:#323232;" class="language-txt "><code class="language-txt" data-lang="txt"><span>版权说明:
</span><span> Copyright 2010 DuoKan & www.duokan.com. All Rights Resevered
</span><span> 版权所有 DuoKan & www.duokan.com。
</span><span> 本软件由 DuoKan Dev Team 开发。
</span><span> 多看软件系统未经许可不得商业贩卖。作者对有商业贩卖行为的单位和个人保留追究其法
</span><span> 律责任的权利。
</span></code></pre>
<p>等到哪天被追究才後悔莫及呀…</p>
[非官方] COSCUP 2010 Mobile App
2010-08-14T07:36:53+08:00
2010-08-14T07:36:53+08:00
https://static.kanru.info/zh-tw/blog/unofficial-coscup-2010-mobile-app/
<p>今年 <a href="http://code.google.com/events/io/2010/sessions/android-ui-design-patterns.html">GoogleIO</a> 時 Android team 不斷在推廣一個 <a href="http://android-developers.blogspot.com/2010/05/twitter-for-android-closer-look-at.html">Android UI Pattern</a>,可以觀察到最早利用這個 Pattern 的應該是預設的 Facebook 程式,接下來發展的更為完備的是 Twitter 官方程式,處處可以見到該 Pattern 的影子。GoogleIO 前 Google 也推出一個程式叫作 IOSched 用來顯示議程相關資訊,同樣是使用該 Pattern 的實作。雖然 Twitter <a href="http://blog.twitter.com/2010/04/twitter-for-android-robots-like-to.html">承諾會釋出 source code</a>,但是一直沒下文,因此想要使用這個 UI Pattern 的可以說完全沒有範例可以參考。</p>
<p>今年 <a href="http://blog.coscup.org/2010/08/blog-post_14.html">COSCUP</a> 就參考 IOSched,嘗試從頭打造一個類似的程式,順便練習一下怎麼使用這個 UI Pattern,結果寫好後才知道<a href="http://www.plurk.com/ericsk">上官大神</a>早有 <a href="http://blog.ericsk.org/archives/1416">HTML5</a> 的版本,連 <a href="http://code.google.com/p/iosched/">IOSched</a> 不知道什麼時候也有 source code 了 (汗)</p>
<p><a href="http://kanru.info/blog/wp-content/uploads/2010/08/device1.png"><img src="//kanru.info/blog/wp-content/uploads/2010/08/device1-168x300.png" alt="" title="Home" width="168" height="300" class="alignnone size-medium wp-image-851" /></a><a href="http://kanru.info/blog/wp-content/uploads/2010/08/device2.png"><img src="//kanru.info/blog/wp-content/uploads/2010/08/device2-168x300.png" alt="" title="Tracks" width="168" height="300" class="alignnone size-medium wp-image-852" /></a><a href="http://kanru.info/blog/wp-content/uploads/2010/08/device3.png"><img src="//kanru.info/blog/wp-content/uploads/2010/08/device3-180x300.png" alt="" title="Sessions" width="180" height="300" class="alignnone size-medium wp-image-853" /></a><img src="//kanru.info/blog/wp-content/uploads/2010/08/coscup2010-qr.png" alt="" title="coscup2010-qr" width="148" height="148" class="alignnone size-full wp-image-854" /></p>
<p>無論如何,總算是練習了一下 Android Programming,有參加 COSCUP 的人可以試用看看 :P</p>
<p>Source code 在 <a href="http://github.com/kanru/Coscup2010">http://github.com/kanru/Coscup2010</a></p>
啟用 mobile 版面
2010-05-23T17:38:00+08:00
2010-05-23T17:38:00+08:00
https://static.kanru.info/zh-tw/blog/enable-mobile-view/
<p>偶爾也想在手機上看自己的 blog (?!) 所以裝了個行動版的 plugin <a href="http://www.bravenewcode.com/products/wptouch/">WPTouch</a></p>
<p><a href="https://kanru.info/blog/wp-content/uploads/2010/05/mobile01.png"><img src="https://kanru.info/blog/wp-content/uploads/2010/05/mobile01-180x300.png" alt="Blog 手機版" title="Blog 手機版" width="180" height="300" class="alignnone size-medium wp-image-810" /></a><a href="https://kanru.info/blog/wp-content/uploads/2010/05/mobile02.png"><img src="https://kanru.info/blog/wp-content/uploads/2010/05/mobile02-180x300.png" alt="" title="Blog 手機版" width="180" height="300" class="alignnone size-medium wp-image-816" /></a><a href="https://kanru.info/blog/wp-content/uploads/2010/05/mobile03.png"><img src="https://kanru.info/blog/wp-content/uploads/2010/05/mobile03-180x300.png" alt="" title="Blog 手機版" width="180" height="300" class="alignnone size-medium wp-image-815" /></a><a href="https://kanru.info/blog/wp-content/uploads/2010/05/mobile04.png"><img src="https://kanru.info/blog/wp-content/uploads/2010/05/mobile04-180x300.png" alt="" title="Blog 手機版" width="180" height="300" class="alignnone size-medium wp-image-814" /></a></p>
<p>看起來還不賴!</p>
AndroidDev: Provision the device
2010-05-12T10:39:43+08:00
2010-05-12T10:39:43+08:00
https://static.kanru.info/zh-tw/blog/android-provision-the-device/
<p>在 Devkit8000 上把 HOME key 設定好後卻無法作用,仔細看了下處理 HOME key 的地方是 polices 下的 PhoneWindowManager.java,會去檢查這個 device 是否被 “Provision” 了。</p>
<p>這個 Provision 的動作其實就是 Device 第一次啟用時做初始設定,在 Google phone 上面就是 SetupWizard,在 emulator 裏面則有簡單的 Provision.apk,之前無法作用就是因為一直沒有把 Provision.apk 放進去…</p>
<p>Provision.apk 做了什麼事呢?其實很簡短:</p>
<pre data-lang="java" style="background-color:#ffffff;color:#323232;" class="language-java "><code class="language-java" data-lang="java"><span style="font-weight:bold;color:#a71d5d;">public class </span><span style="color:#0086b3;">DefaultActivity </span><span style="font-weight:bold;color:#a71d5d;">extends </span><span style="color:#0086b3;">Activity </span><span>{
</span><span> @Override
</span><span> </span><span style="font-weight:bold;color:#a71d5d;">protected void </span><span style="font-weight:bold;color:#795da3;">onCreate</span><span>(</span><span style="color:#0086b3;">Bundle </span><span>icicle) {
</span><span> super.onCreate(icicle);
</span><span>
</span><span> </span><span style="font-style:italic;color:#969896;">// Add a persistent setting to allow other apps to know
</span><span> </span><span style="font-style:italic;color:#969896;">// the device has been provisioned.
</span><span> </span><span style="color:#0086b3;">Settings</span><span>.</span><span style="color:#0086b3;">Secure</span><span>.putInt(getContentResolver(),
</span><span> </span><span style="color:#0086b3;">Settings</span><span>.</span><span style="color:#0086b3;">Secure</span><span>.</span><span style="color:#0086b3;">DEVICE_PROVISIONED</span><span>, </span><span style="color:#0086b3;">1</span><span>);
</span><span>
</span><span> </span><span style="font-style:italic;color:#969896;">// remove this activity from the package manager.
</span><span> </span><span style="color:#0086b3;">PackageManager</span><span> pm </span><span style="font-weight:bold;color:#a71d5d;">= </span><span>getPackageManager();
</span><span> </span><span style="color:#0086b3;">ComponentName</span><span> name </span><span style="font-weight:bold;color:#a71d5d;">= new </span><span style="color:#0086b3;">ComponentName</span><span>(this,
</span><span> </span><span style="color:#0086b3;">DefaultActivity</span><span>.class);
</span><span> pm.setComponentEnabledSetting(name,
</span><span> </span><span style="color:#0086b3;">PackageManager</span><span>.</span><span style="color:#0086b3;">COMPONENT_ENABLED_STATE_DISABLED</span><span>, </span><span style="color:#0086b3;">0</span><span>);
</span><span>
</span><span> </span><span style="font-style:italic;color:#969896;">// terminate the activity.
</span><span> finish();
</span><span> }
</span><span>}
</span></code></pre>
<p>因此若要提供一個類似 SetupWizard 的初始化介面在 Devit8000 上面,只要延伸這個 Provision.apk 做的事,提供 GUI 等等,最重要的就是設定這個 “Settings.Secure.DEVICE_PROVISIONED”</p>
The good old xorg.conf and the new xorg.conf.d
2010-04-08T23:38:12+08:00
2010-04-08T23:38:12+08:00
https://static.kanru.info/zh-tw/blog/good-old-xorg-conf-and-new-xorg-conf-d/
<p>自從 Xorg xserver 宣佈要放棄使用 hal 的自動設定機制後,Xorg 開發者們就開始討論與實做各種可能的 config backend。最後定案的是在 Linux 上直接使用 udev 來偵測 input device,在這個後端實做的早期也想把設定的工作一起做在 udev rules 裡,但顯然這樣的做法是有其侷限的。很多人說這只是把 hal 的 .fdi 換個寫法放到 udev rules 裡罷了,同樣是對 user 極不友善的做法,而且使用 udev 在非 Linux 的平台就不能用了。</p>
<p>最後一個很聰明的辦法是把 auto probe 與 config 這兩個行為分開,讓 udev 只管找到新的裝置,config 則集中放在 xorg.conf.d 中。xorg.conf.d 中設定檔的格式和 xorg.conf 是一樣的,因此不但 code 可以重用,使用者也不用學新的語法,其他平台則可以用不同的 backend。</p>
<p>因為 udev backend 是以 Debian Developer - Julien Cristau 為主開發的, Debian 很早就可以使用 udev backend 了,最近 Debian 更從 xorg-xserver 1.8 backport 了 xorg.conf.d 的修改,所以設定方式又不太一樣了。(大概只有 Debian 是這樣一改再改吧,其他 distro 應是無痛升級)</p>
<p>參考 xorg.conf(5),X 在啟動時會去找</p>
<pre style="background-color:#ffffff;color:#323232;"><code><span> /etc/X11/<cmdline>
</span><span> /usr/etc/X11/<cmdline>
</span><span> /etc/X11/$XORGCONFIG
</span><span> /usr/etc/X11/$XORGCONFIG
</span><span> /etc/X11/xorg.conf-4
</span><span> /etc/X11/xorg.conf
</span><span> /etc/xorg.conf
</span><span> /usr/etc/X11/xorg.conf.<hostname>
</span><span> /usr/etc/X11/xorg.conf-4
</span><span> /usr/etc/X11/xorg.conf
</span><span> /usr/lib/X11/xorg.conf.<hostname>
</span><span> /usr/lib/X11/xorg.conf-4
</span><span> /usr/lib/X11/xorg.conf
</span></code></pre>
<p>這些地方的設定檔,因此設定不用全放在一個檔案裡了。這也是近來很多 daemon 要支援多重設定檔常用的方法,可以讓 vendor 或 distro 的設定與 user 的設定可以各自獨立出來。</p>
<p>接下來我們有興趣的地方是 <code>InputClass</code> 這個新的 Section,就是它讓我們可以設定隨插即用裝置。</p>
<pre style="background-color:#ffffff;color:#323232;"><code><span> Section "InputClass"
</span><span> Identifier "name"
</span><span> entries
</span><span> ...
</span><span> options
</span><span> ...
</span><span> EndSection
</span></code></pre>
<p>就像 xorg.conf 內其他 Section 一樣,<code>Identifier</code> 是必需的,我們可以用各種 Match rule 去比對裝置的特性並用 Option 加以設定。所有的 InputClass 都可以被其之後的 InputClass 取代,因此使用者可以用新設定檔取代系統的設定。</p>
<p>現在可以用的 Match rule 有</p>
<pre style="background-color:#ffffff;color:#323232;"><code><span> MatchProduct "matchproduct"
</span><span> MatchVendor "matchvendor"
</span><span> MatchDevicePath "matchdevice"
</span><span> MatchTag "matchtag"
</span><span> MatchIsKeyboard "bool"
</span><span> MatchIsPointer "bool"
</span><span> MatchIsJoystick "bool"
</span><span> MatchIsTablet "bool"
</span><span> MatchIsTouchpad "bool"
</span><span> MatchIsTouchscreen "bool"
</span></code></pre>
<p>前四個可以用來 match 特定的裝置名稱、路徑,其他的則可以用來 match 一般的裝置特性如滑鼠、鍵盤等。如我要設定 touchpad 的話,可以用</p>
<pre style="background-color:#ffffff;color:#323232;"><code><span> # /etc/X11/xorg.conf.d/10-synaptics.conf
</span><span> Section "InputClass"
</span><span> Identifier "Synaptics"
</span><span> MatchIsTouchpad "true"
</span><span>
</span><span> Option "TapButton1" "1"
</span><span> Option "HorizEdgeScroll" "true"
</span><span> EndSection
</span></code></pre>
<p>來設定。再加上 X 會自己找到可以用的 driver,和<a href="http://blog.kanru.info/archives/251">以前</a><a href="http://blog.kanru.info/archives/279">的</a><a href="http://blog.kanru.info/archives/339">方法</a>比起來,是不是簡單很多呢? 😊</p>
Got one A1 from Broncho
2010-03-15T17:50:49+08:00
2010-03-15T17:50:49+08:00
https://static.kanru.info/zh-tw/blog/got-one-a1-from-broncho/
<p>上週末下班前,在桌上發現一個包裹,原來是渡海而來的兩隻 A1!這兩隻 A1 是 Broncho 的產品,詳細規格可以參考 <a href="http://www.broncho.cn/products/a1/">Broncho 的網頁</a>。</p>
<p>大伙興奮的開箱啦!</p>
<p><a href="/blog/wp-content/uploads/2010/03/FxCam_1268373797319.jpg"><img src="/blog/wp-content/uploads/2010/03/FxCam_1268373797319-150x150.jpg" alt="開箱" title="unbox" width="150" height="150" class="alignnone size-thumbnail wp-image-689" /></a>
<a href="/blog/wp-content/uploads/2010/03/FxCam_1268373867309.jpg"><img src="/blog/wp-content/uploads/2010/03/FxCam_1268373867309-150x150.jpg" alt="開箱" title="unbox2" width="150" height="150" class="alignnone size-thumbnail wp-image-691" /></a>
<a href="/blog/wp-content/uploads/2010/03/2010-03-12-14.04.52.jpg"><img src="/blog/wp-content/uploads/2010/03/2010-03-12-14.04.52-150x150.jpg" alt="" title="合照" width="150" height="150" class="alignnone size-thumbnail wp-image-699" /></a>
<a href="/blog/wp-content/uploads/2010/03/2010-03-12-14.06.25.jpg"><img src="/blog/wp-content/uploads/2010/03/2010-03-12-14.06.25-150x150.jpg" alt="" title="真像" width="150" height="150" class="alignnone size-thumbnail wp-image-703" /></a></p>
<p>包裝和 Hero 的很像。3.2 寸 LCD, 480x320 的解析度,200 萬畫素的相機鏡頭,CPU 是 Marvell 300 (624 MHz),記憶體是 256 + 128 MB,支援 WIFI, Bluetooth, FM, GPS。不是使用標準的 USB 接口,但同一個接口可以接 USB、耳機、變壓器。觸控螢幕使用起來的感覺像是電容式的,反應非常靈敏,輕輕的觸摸就有反應。</p>
<p>系統是 Android Cupcake,內建軟體有不少 Google App,最另人驚訝旳是上面有 Android Market 可以用,試著從 Market 上面下載了一些小遊戲下來玩,完全沒有問題,真是太牛了!另外一點就是有內建手寫輸入,速度不快但是準確度不錯。除此之外還有谷歌拼音可以用。</p>
<p>測試的途中無線網路與 GPS 不是很穩,除此之外以一隻中低價位的手機來說表現的相當不錯。</p>
<p><a href="/blog/wp-content/uploads/2010/03/lock.png"><img src="/blog/wp-content/uploads/2010/03/lock-150x150.png" alt="" title="lock" width="150" height="150" class="alignnone size-thumbnail wp-image-711" /></a>
<a href="/blog/wp-content/uploads/2010/03/home.png"><img src="/blog/wp-content/uploads/2010/03/home-150x150.png" alt="" title="home" width="150" height="150" class="alignnone size-thumbnail wp-image-712" /></a>
<a href="/blog/wp-content/uploads/2010/03/apps.png"><img src="/blog/wp-content/uploads/2010/03/apps-150x150.png" alt="" title="apps" width="150" height="150" class="alignnone size-thumbnail wp-image-713" /></a>
<a href="/blog/wp-content/uploads/2010/03/market.png"><img src="/blog/wp-content/uploads/2010/03/market-150x150.png" alt="" title="market" width="150" height="150" class="alignnone size-thumbnail wp-image-714" /></a>
<a href="/blog/wp-content/uploads/2010/03/market2.png"><img src="/blog/wp-content/uploads/2010/03/market2-150x150.png" alt="" title="market2" width="150" height="150" class="alignnone size-thumbnail wp-image-715" /></a>
<a href="/blog/wp-content/uploads/2010/03/market3.png"><img src="/blog/wp-content/uploads/2010/03/market3-150x150.png" alt="" title="market3" width="150" height="150" class="alignnone size-thumbnail wp-image-716" /></a>
<a href="/blog/wp-content/uploads/2010/03/weather.png"><img src="/blog/wp-content/uploads/2010/03/weather-150x150.png" alt="" title="weather" width="150" height="150" class="alignnone size-thumbnail wp-image-717" /></a>
<a href="/blog/wp-content/uploads/2010/03/handwriting1.png"><img src="/blog/wp-content/uploads/2010/03/handwriting1-150x150.png" alt="" title="handwriting1" width="150" height="150" class="alignnone size-thumbnail wp-image-718" /></a>
<a href="/blog/wp-content/uploads/2010/03/handwriting2.png"><img src="/blog/wp-content/uploads/2010/03/handwriting2-150x150.png" alt="" title="handwriting2" width="150" height="150" class="alignnone size-thumbnail wp-image-719" /></a>
<a href="/blog/wp-content/uploads/2010/03/handwriting3.png"><img src="/blog/wp-content/uploads/2010/03/handwriting3-150x150.png" alt="" title="handwriting3" width="150" height="150" class="alignnone size-thumbnail wp-image-720" /></a>
<a href="/blog/wp-content/uploads/2010/03/handwriting4.png"><img src="/blog/wp-content/uploads/2010/03/handwriting4-150x150.png" alt="" title="handwriting4" width="150" height="150" class="alignnone size-thumbnail wp-image-721" /></a></p>