2009年5月24日 星期日

透過 GNU Emacs 將 source code 轉成 HTML

有在寫部落或是做網頁的人可能多少都會碰過要將原始碼貼上網頁的清況,不過光是貼上原始碼這一大堆文字確實會讓人讀起來很吃力,現在一般人在看原始碼可能都已經習慣了各種編輯程式所提供的 syntax highlighting 語法標注的功能。可惜這些功能通常只能在本機上使用,一般網頁不太會提供這種功能。還好,網路上有已經有很多人提供解決的方法,有些人是用 client 端的 JavaScript (CSJS) 來實作,而有些人是透過 server 端PHP 來實作 syntax highlighting 語法標注功能。

此外還有另一種方式,就是先將程式或原始碼先透過網路上的服務或是本機的工具程式先轉成 HTML,然後再把 HTML 貼到網路上。這種方法雖然沒有 JavaScript 或 PHP 便捷,但是有些網站基於管理或是安全上的理由,並不允許執行使用者的 JavaScript,有時甚至連 CSS 都無法修改,而 PHP 通常則需要有 server 的管理權限,所以這個方法自然有它的優點。因為 Emacs 是我寫程式慣用的編輯器,它不但對許多原始碼都提供 syntax highlighting 的功能,此外自動縮排的功能也非常好用,所以也使我想開始尋找 Emacs 是否也具有某種機制可以將 buffer 中 highlight 過的文字轉成 HTML,如此轉好後就可以直接貼到網路上去了。然而經過一番摸索後似乎沒有發現這樣的功能,但是我並沒有因此而放棄,因為 Emacs 還有內建的 script 語言叫做 Emacs Lisp (或 Elisp) 是個很 powerful 的工具,可以透過它來存取編輯器內部的物件以及執行一些程式化的動作。稍微思考一下並嘗試一些 function 做點小試驗,發現要寫這樣一個程式並不會很難,buffer 中的原始碼 Emacs 都已經幫你 highlight 好了,所以只要將文字的屬性抓出來再根據這些資訊在文字加上對應的 HTML markup 就行了。下面這段程式就是今天努力的結果,程式很簡單不到 200 行 (這個 highlight 過的程式碼也是用該程式本身轉出來的):

下載 faced-buf2htm.el
;;; faced-buf2htm.el --- convert buffer text with face properties into HTML
;; Copyright (c) 2009 Justin Lee

;; Author: Justin Lee <cf9404@yahoo.com.tw>
;; Created: 24 May 2009
;; Version: 1.0
;; Keywords:

;; This is free software; you can redistribute it and/or modify it
;; under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be
;; useful, but WITHOUT ANY WARRANTY; without even the implied
;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
;; PURPOSE.  See the GNU General Public License for more details.

;; You should have received a copy of the GNU General Public
;; License along with this program; if not, write to the Free
;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
;; MA 02111-1307 USA

;;; Commentary:

(defvar g-r-dat)
(defvar g-g-dat)
(defvar g-b-dat)

(defun get-cdat (cv0 cv1)
  (cons cv0 (- cv1 cv0)))

(defun cv2htmcv (cv cdat)
  (/ (* 255 (- cv (car cdat)))
     (cdr cdat)))

(defun cvs2htmcvs (cvs)
  (format "#%02x%02x%02x"
          (cv2htmcv (nth 0 cvs) g-r-dat)
          (cv2htmcv (nth 1 cvs) g-g-dat)
          (cv2htmcv (nth 2 cvs) g-b-dat)))

(defun faced-buf2htm-init ()
  (let (a-v1 a-v2)
    (setq a-v1 (color-values "black"))
    (setq a-v2 (color-values "white"))
    (setq g-r-dat (get-cdat (nth 0 a-v1) (nth 0 a-v2)))
    (setq g-g-dat (get-cdat (nth 1 a-v1) (nth 1 a-v2)))
    (setq g-b-dat (get-cdat (nth 2 a-v1) (nth 2 a-v2)))

    ;;  Make a face with all attribute values being `unspecified'. It is merely used to be
    ;;  overridden by the inherited face(s) (the last parameter of function `face-attribute')
    ;;  for simulating a merge process.
    ;;
    ;;  Emacs help info: You can specify more than one face for a given piece of text; Emacs
    ;;  merges the attributes of all the faces to determine how to display the text. If a
    ;;  list of faces is used, attributes from faces earlier in the list override those from
    ;;  later faces.
    (make-face 'nil-face)))

;;  <span style='color:red;'><s><u><b><i>txt</i></b></u></s></span>
(defun format-faced-txt (txt face)
  (let (a-v1 a-v2 a-v3)
    (setq a-v1 txt)
    (setq a-v1 (replace-regexp-in-string "&" "&amp;" a-v1))
    (setq a-v1 (replace-regexp-in-string "<" "&lt;" a-v1))
    (setq a-v1 (replace-regexp-in-string ">" "&gt;" a-v1))
    (setq a-v1 (list a-v1))
    (setq a-v2 a-v1)

    (setq a-v3 (face-attribute 'nil-face :slant nil face))
    (unless (eq a-v3 'unspecified)
      (setq a-v1 (cons "<i>" a-v1))
      (rplacd a-v2 (list "</i>"))
      (setq a-v2 (cdr a-v2)))
    (setq a-v3 (face-attribute 'nil-face :weight nil face))
    (unless (eq a-v3 'unspecified)
      (setq a-v1 (cons "<b>" a-v1))
      (rplacd a-v2 (list "</b>"))
      (setq a-v2 (cdr a-v2)))
    (setq a-v3 (face-attribute 'nil-face :underline nil face))
    (unless (eq a-v3 'unspecified)
      (setq a-v1 (cons "<u>" a-v1))
      (rplacd a-v2 (list "</u>"))
      (setq a-v2 (cdr a-v2)))
    (setq a-v3 (face-attribute 'nil-face :strike-through nil face))
    (unless (eq a-v3 'unspecified)
      (setq a-v1 (cons "<s>" a-v1))
      (rplacd a-v2 (list "</s>"))
      (setq a-v2 (cdr a-v2)))
    (setq a-v3 (face-attribute 'nil-face :foreground nil face))
    (unless (eq a-v3 'unspecified)
      (setq a-v1 (append (list "<span style='color: " (cvs2htmcvs (color-values a-v3)) ";'>") a-v1))
      (rplacd a-v2 (list "</span>"))
      (setq a-v2 (cdr a-v2)))
    a-v1))

(defun faced-buf2htm-process (buf1 buf2)
  (let (a-v1 a-v2 a-v3 a-v4 a-v5)

    (with-current-buffer buf1
      (setq a-v1 (point-min)))

    (setq a-v3 t)
    (while a-v3
      (setq a-v2 (next-single-property-change a-v1 'face buf1))
      (unless a-v2
        (setq a-v2 (with-current-buffer buf1 (point-max)))
        (setq a-v3 nil))

      (with-current-buffer buf1
        (setq a-v4 (buffer-substring a-v1 a-v2)))
      (setq a-v5 (get-text-property 0 'face a-v4))
      (with-current-buffer buf2
        (apply 'insert (format-faced-txt a-v4 a-v5)))

      (setq a-v1 a-v2))

    ))

;;  Make sure the text properties are updated by scrolling through the whole buffer.
(defun update-txt-prop ()
  (goto-char (point-min))
  (set-window-start (selected-window) (point-min))
  (scroll-up (1- (count-lines (point-min) (point-max)))))

(defun faced-buf2htm ()
  (interactive)
  (let (a-v1)
    (save-excursion

      (setq a-v1 (get-buffer-create (generate-new-buffer-name "*HtmlFromFacedBuf*")))

      (message nil) (message "Updating text properties of the buffer ...")
      (update-txt-prop)

      (with-current-buffer a-v1
        (insert "<pre>"))

      (message nil) (message "Converting buffer text ...")
      (faced-buf2htm-init)
      (faced-buf2htm-process (current-buffer) a-v1)

      (with-current-buffer a-v1
        (insert "</pre>")
        (html-mode))

      (switch-to-buffer a-v1)

      )))

(provide 'faced-buf2htm)

;;;  Code snippets for experiments.

;; (text-properties-at (point))
;; (goto-char (next-property-change (point)))
;; (goto-char (next-single-property-change (point) 'face))
;; (color-values (face-attribute 'font-lock-type-face :foreground))

;;  (defun update-txt-prop ()
;;    (goto-char (point-min))
;;    (scroll-up (1- (count-lines (point-min) (point-max)))))
;;
;;  (defun update-txt-prop ()
;;    (set-window-start (selected-window) (point-min))
;;    (beginning-of-buffer)
;;    (scroll-up (1- (count-lines (point-min) (point-max)))))
;;
;;  (defun update-txt-prop ()
;;    (beginning-of-buffer)
;;    (set-window-start (selected-window) (point-min))
;;    (scroll-up (1- (count-lines (point-min) (point-max)))))
程式產生出來的 HTML 中,所有的 style 都是內嵌的,因此沒有需要再修改 CSS,不過缺點就是轉出來的 HTML 碼會比較大。

下面是一個由 PHP 所寫成的簡單 hello world 範例其轉換前後的對照。轉換前的 PHP 原始碼:
<?php
echo "Hello, world!";
?>
轉換後的 HTML 原始碼:
<pre><span style='color: #5f9ea0;'>&lt;?php</span>
<span style='color: #a020f0;'>echo</span> <span style='color: #bc8f8f;'>"Hello, world!"</span>;
<span style='color: #5f9ea0;'>?&gt;</span>
</pre>

使用方法

使用方法很簡單,先將上面的 Elisp load 進來:
M-x load-file
上面輸入後會提示你輸入 Elisp 的路徑:
/path/to/faced-buf2htm.el
load 完成後 switch 到任何一個要被轉換的 buffer 然後打:
M-x faced-buf2htm
等程式跑完後就會自動開一個新的 buffer,裡面就是轉出來的 HTML,複製下來再貼到網路上去即可。

實作註記

程式主要的功能是將文字的 face 屬性擷取出來並轉成 HTML,當時寫完後開了幾個檔來轉轉看,但是發現有時開一個大一點的檔來轉,轉完了以後某些文字竟然沒有 face 屬性。再多試了幾次以後發現這些沒有 face 的文字大多是落在檔案的後段,不過也有一些例外。最後發現原來這些沒 face 的文字幾乎都是在檔案開啟後,在瀏覽 buffer 的過程中沒有被瀏覽到的文字,所以如果在檔案開啟後,按住 page down 鍵不放,讓 Emacs 從頭捲到尾把整個 buffer 瀏覽一遍就不會有這個問題了。猜想這個現象應該是 Emacs 為了節省開啟檔案的時間或為了減少一些不必要的工作,因此未被瀏覽過的 buffer 部份它就不作 syntax highlighting 所以這些文字也就沒有 face 屬性了。接下來的重點就是如何讓這個瀏覽的動作自動化,以強迫所有的文字屬性都有被更新到。試了幾種方法後終於試出來了,就是程式中 update-txt-prop 函數,只要三行就可以做到:
;;  Make sure the text properties are updated by scrolling through the whole buffer.
(defun update-txt-prop ()
  (goto-char (point-min))
  (set-window-start (selected-window) (point-min))
  (scroll-up (1- (count-lines (point-min) (point-max)))))
因為轉出來的文字會被當成 HTML 來使用,因此在文字中具有 HTML 意義的部份都要 escape 掉以免這些文字被當作 HTML 而造成轉換上的失真。例如 HTML 中的 tag 都是用角括號 (即 <...> ) 括起來的,因此轉換時要將文字中大於 (>) 及小於 (<) 的符號 escape 掉,以避免包夾在中間的中文字被當作 HTML tag,這裡大於及小於可以用對應的 character entity reference 來取代,分別為 &gt; 及 &lt; 除此之外用來起始 character entity reference 的 ampersand (&) 同樣也要用 &amp; 取代掉,所以這就是函數 format-faced-txt 前面幾行所做的工作:
(defun format-faced-txt (txt face)
  (let (a-v1 a-v2 a-v3)
    (setq a-v1 txt)
    (setq a-v1 (replace-regexp-in-string "&" "&amp;" a-v1))
    (setq a-v1 (replace-regexp-in-string "<" "&lt;" a-v1))
    (setq a-v1 (replace-regexp-in-string ">" "&gt;" a-v1))
;                .                 .
;                .                 .
;                .                 .
小弟目前所想到需要被 escape 的只有這些符號,其它需要 escape 的符號如果各位前輩有發現的話可以跟小弟告知。此外感謝 alan 在這篇文章的意見中提到在 EmacsWiki 上有一個 package 叫 Htmlize 提供類似但更成熟的功能,各位如果覺得 faced-buf2htm.el 的功能不符合需要,也可以試試 Htmlize。

Demonstration of source code to HTML conversion by Emacs

2009年5月20日 星期三

錢從哪裡來?

今天早上莫名奇妙又開始在胡思亂想了
...想到從前國中理化有學到「能量不滅」以及「質量守恆」定律
在金融方面好像也有類似這種守恆的機制

除非自己擁有很多的財產或是有別人的金援
否則每個人都得出去工作來養活自己
而工作這種行為會與別人形成所謂的雇傭關係
員工為雇主提供某些服務而從雇主那邊賺取金錢
而雇主本身 從某一方面來說也算是別人的雇員

舉例來說 你去某家公司幫他們寫程式而從你的老闆那邊賺取金錢
然而老闆為了支付你的薪水 他必需找人或親自出去外面接案子 從這些案子的客戶中賺錢
所以你是老闆的雇員 而老闆 (從某方面來說) 則是這些客戶的雇員

ok
那現在每個人都在向別人賺錢
如果可以一直往上追 追到最上面那一個給錢的人
那麼那個最源頭給錢的大老闆到底是誰?而他的錢又是從哪裡來?

聽說一個國家的財產是由這個國家所擁有的黃金數量來決定的 (...忘了是從哪聽來的)
因此一個國家不可以隨意無限制地生產貨幣
如果不這樣 那今天如果台灣要向美國買飛彈或武器那就好辦了
錢不夠就多印一些鈔票出來不就得了 還是叫銀行在戶頭的存款後面多加幾個零也可以

但是後來想一想這個說法好像也有問題
如果黃金決定一個國家的財產
那麼把世界上每個國家的黃金加在一起就是全世界所能流通的貨幣金額
所以全球所能流通的貨幣金額是一個定值或是具有「守恆」的性質 (除非有人又把黃金挖出來 那另當別論)
意思是前面提到的那個最源頭的大老闆:
第一 他不可能自己生出錢來 (因為有多少黃金才能印多少錢出來 不可以無中生有)
第二 他的錢也不是從別人那邊得到的 (因為他是「最源頭」 所以只給錢 不拿錢)
這樣說起來是不是很矛盾呢?他的錢究竟是從哪裡來?
還有 這個問題和通貨澎漲是不是有什麼關係?

...結論是從這個問題中又得到了一堆問號
可惜小弟是讀工的並不是學商的
對這方面可以說是一竅不通
如果硬要打個分數 大概會得到一個鴨蛋或是負分吧 :p
如果有人能替小弟解答這個問題
應該能帶給小弟不小的幫助吧

2009年5月15日 星期五

修正 Ubuntu 9.04 (Jaunty Jackalope) 中文字型模糊

四月份的時侯更新管理員 (Update Manager) 上提示可以升級到最新版的 Ubuntu 9.04 (Jaunty Jackalope),當時發現後並沒有馬上升級,猶豫了許久直到最近終於從 8.10 升級到 9.04。升級後發現的第一個問題就是中文字型變得有點模糊,而且字體跟之前的版本也不太一樣。用了幾天後還是不太習慣,於是便開始尋找解決方法,讀了幾篇文章後發現這篇 ubuntu筆記:使用自己喜歡的字型可以解決字型上的問題。解決的方法很簡單,只要修改檔案 /etc/fonts/conf.d/69-language-selector-zh-tw.conf 然後再重新登入就行了。

9.04 下面看到的模糊字型是「文泉驛正黑體」即 'WenQuanYi Zen Hei',要修正問題先以 superuser 的身份打開 69-language-selector-zh-tw.conf,然後找出各 edit 區塊中包含 'WenQuanYi Zen Hei' 的那幾行,把它們在各區塊中往下移,移到其它中文字型之後即可。

修改之前的檔案內容

黃色域標示出 edit 區塊,藍字表示中文字型,紅字表示「文泉驛正黑體」。

<fontconfig>

        <match target="pattern">
                <test qual="any" name="family">
                        <string>serif</string>
                </test>
<edit name="family" mode="prepend" binding="strong"> <string>AR PL UMing TW</string> <string>AR PL ShanHeiSun Uni</string> <string>WenQuanYi Bitmap Song</string> <string>Bitstream Vera Serif</string> <string>DejaVu Serif</string> <string>AR PL UKai TW</string> <string>AR PL ZenKai Uni</string> </edit>
</match> <match target="pattern"> <test qual="any" name="family"> <string>sans-serif</string> </test>
<edit name="family" mode="prepend" binding="strong"> <string>Bitstream Vera Sans</string> <string>DejaVu Sans</string> <string>WenQuanYi Zen Hei</string> <string>AR PL UMing TW</string> <string>AR PL ShanHeiSun Uni</string> <string>WenQuanYi Bitmap Song</string> <string>AR PL UKai TW</string> <string>AR PL ZenKai Uni</string> </edit>
</match> <match target="pattern"> <test qual="any" name="family"> <string>monospace</string> </test>
<edit name="family" mode="prepend" binding="strong"> <string>Bitstream Vera Sans Mono</string> <string>DejaVu Sans Mono</string> <string>WenQuanYi Zen Hei</string> <string>AR PL UMing TW</string> <string>AR PL ShanHeiSun Uni</string> <string>WenQuanYi Bitmap Song</string> <string>AR PL UKai TW</string> <string>AR PL ZenKai Uni</string> </edit>
</match> </fontconfig>

修改之後的檔案內容

<fontconfig>

        <match target="pattern">
                <test qual="any" name="family">
                        <string>serif</string>
                </test>
<edit name="family" mode="prepend" binding="strong"> <string>AR PL UMing TW</string> <string>AR PL ShanHeiSun Uni</string> <string>WenQuanYi Bitmap Song</string> <string>Bitstream Vera Serif</string> <string>DejaVu Serif</string> <string>AR PL UKai TW</string> <string>AR PL ZenKai Uni</string> </edit>
</match> <match target="pattern"> <test qual="any" name="family"> <string>sans-serif</string> </test>
<edit name="family" mode="prepend" binding="strong"> <string>Bitstream Vera Sans</string> <string>DejaVu Sans</string> <string>AR PL UMing TW</string> <string>AR PL ShanHeiSun Uni</string> <string>WenQuanYi Bitmap Song</string> <string>WenQuanYi Zen Hei</string> <string>AR PL UKai TW</string> <string>AR PL ZenKai Uni</string> </edit>
</match> <match target="pattern"> <test qual="any" name="family"> <string>monospace</string> </test>
<edit name="family" mode="prepend" binding="strong"> <string>Bitstream Vera Sans Mono</string> <string>DejaVu Sans Mono</string> <string>AR PL UMing TW</string> <string>AR PL ShanHeiSun Uni</string> <string>WenQuanYi Bitmap Song</string> <string>WenQuanYi Zen Hei</string> <string>AR PL UKai TW</string> <string>AR PL ZenKai Uni</string> </edit>
</match> </fontconfig>

因為和楷書比起來我比較 prefer 文泉驛正黑體,所以並沒有把 WenQuanYi Zen Hei 移到 AR PL UKai TW 與 AR PL ZenKai Uni 下方。

重新登入

修改完並存檔後或許會發現有些字型馬上有改變,但是有些字型還是沒變,為了確保所有的字型都依照修改後的檔案顯示,只要再重新登入一次就大功告成了。

69-language-selector-zh-tw.conf 修改前維基百科的頁面快照 (字體較模糊)    69-language-selector-zh-tw.conf 修改前的功能表快照 (字體較模糊)
檔案修改前之快照

69-language-selector-zh-tw.conf 修改後維基百科的頁面快照 (字體較清晰)    69-language-selector-zh-tw.conf  修改後的功能表快照 (字體較清晰)
檔案修改後之快照

p.s. 因為小弟用的是 Firefox,支援包含透明度的 PNG 圖檔 (PNG images with alpha transparency),但是 IE 並沒有這樣的支援,所以上面的圖用 IE 看可能會怪怪的。

2009年5月14日 星期四

KDE 中文化

今天要幫別人裝 Ubunu,因為覺得 KDE 的介面會比 GNOME 的介面好看,應該會比較討喜,所以 Ubuntu 8.04 裝完了以後又裝了 KDE 4 (照理說直接裝 Kubuntu 也行,不過手邊只有 Ubuntu 光碟),不過 KDE 剛裝完後看到的介面都是英文 (之前裝 KDE 就已經碰過這樣的問題,只是一直沒去解決),一般人比較不習慣,在網路上 google 了一下總算找到決解方法,只要利用下面幾個步驟就可以將 KDE 中文化:
  1. 安裝 kde-i18n-zhtw 及 kde-l10n-zhtw 套件。
  2. 在 K 選單中找到並開啟 System Settings,並選擇 Regional & Language > Country/Region & Language > Locale。
  3. 上面步驟完成會開啟一個對話方塊,對話方塊中會有一個 change 的連結,點下去之後選擇 Asia, East > Taiwan,最後按 OK 確定。
  4. 接下來,確定 Languages 清單裡面的「繁體中文」或是 "Chinese" 必需排在第一個 (最上面一個),若不是請移動清單中的項目,最後按 Apply 套用。
  5. 重新登入 KDE 即完成。
步驟 2-4 的細節可以參考安裝 KDE 4 中文語系這篇文章。KDE 中文化後取得的畫面快照 (從自己那一台安裝 Ubuntu 9.04 的電腦取得) 如下:

KDE 中文化以後的畫面快照

2009年5月8日 星期五

事實: Linux 不是玩具 - Linux、Google、超級計算機

之前在 Mobile01 看到一個 thread (討論串) 裡面在爭執 Windows 與 Linux 的優劣,其中一位網友直說 Linux 的不是,說 Linux 下沒什麼 game 的支援,甚至說 Linux 只是個玩具 ... 個人認為,「玩具」這兩個字對 Linux 無非是種莫大的誤解與偏見。雖然 Linux 沒像 Mac OS X 或 Windows 那麼 user friendly、GUI 效能也沒像 Mac OS X 那麼好、遊戲沒像 Windows 那麼多,但光是這樣是否就足以斷定 Linux 只是一個玩具?為了推翻這個說法,以下讓我透過這篇文章來為 Linux 平反。
圖 1: 名列 Top500 超級計算機中所使用的作業系統,Linux (黃色) 佔了大部份的比例。
圖 1: 名列 Top500 超級計算機中所使用的作業系統,Linux (黃色) 佔了大部份的比例。

Linux 與 Google

Google,一個以搜尋引擎起家的公司,因能提供確切與迅速的搜尋服務而廣受大眾的青睞,竄紅為當前全球最大的搜尋引擎。這樣的服務品質完全是藉重於他們所研發的演算法以及背後強大運算能力的支持,而這其中強大的運算能力正是來自其幕後龐大數量 server 所構成的網路。在 Google platform 這篇文章中提到: 「雖然確切的數字並未被正式公開,但有人估計 Google 至少在世界各地維護了共超過 450,000 台的 server ... 每個 Google 的叢集 (cluster) 內包含數以千計的 server,為了平衡 server 之間的流量與負載,當叢集一接收到外部連線就會立刻透過其中的硬體將查詢送到負載最輕的 server 上。這也使得 Google 成為世界上其中一個最大也最複雜的內容傳遞網路 (Content Delivery Network)」 ... 就這些 server 而言,重點當然不在於每台 server 上都必須安裝一套作業系統,而是在於這些 server 上運行的是什麼樣的作業系統。事實上,在 Google platform 中有提到,這些 server 上運行的作業系統正是 Linux。

Google 這個被微軟視為頭號假想敵的企業,竟然是個 Linux 的重度使用者 (這點透過 Netcraft 的查詢也可以證明,網域名稱包含 .google.com 且 Netblock 為 google inc. 的 server 清一色跑的幾乎全是 Linux。Netcraft 提供的服務可以用來查詢一個網站所使用的 OS 以及其它相關資訊)。如果說 Linux 只是玩具,那一個企業要如何透過一個玩具作業系統對微軟造成威脅?
圖 2: IBM Roadrunner,2008 年 11 月 TOP500.Org 公佈世界上最快的超級計算機。
圖 2: IBM Roadrunner,2008 年 11 月由 TOP500.Org 所公佈世界上最強的超級計算機。
或許有人會說 server 本來就是 Linux 的本行,如果不這麼做的話 Google 不知道要付多少授權費或研發費用在作業系統上。然而這是否也突顯了 Linux 基於一個自由軟體的優勢? Google 選擇的不是 Mac OS X Server、選擇的不是 Unix 更不是 Windows Server,而是選擇了 Linux ... 顯然,Google 的選擇並沒有錯。

Linux 與超級計算機

撇開網路伺服器的應用不談,把焦點轉移到 Linux 的高階的應用上。談到計算機的高階應用就不能不談高性能計算機 (high performance computer) 以及超級計算機 (supercomputer)。所謂高性能計算機指的是每秒可以執行 1 兆次以上浮點運算 (1 teraflop 或 1012 flops) 的計算機,而超級計算機則又是高性能計算機中更頂級的一群。高性能計算 (high-performance computing) 歷來備受各國政府、教育機構以及研究人士的關注,應用在石油勘探、氣象預報、地震分析、生物製藥、工程仿真、科學計算、商業計算等 ... 眾多領域,它代表的是一個國家研究水平的象徵。

根據 TOP500.Org 資料所統計出來的趨勢 (見圖 1),近年來 Linux 正以壓倒性的優勢,迅速在高性能計算機中取代其它作業系統的地位。另外,在 <<Unix 失勢 HPC 市場兩年份額下降三分之二>> 一文中對這樣一個趨勢則有更清晰的描述

... 十年前,當 Linux 還在襁褓之中的時候,Unix 已經成了這個市場的主宰。在世界 500 強超級計算機中,採用 Unix 作業系統的超級計算機佔 99.4%,只有 3 台採用其它的系統,一台 Linux 系統,一台基於 BSD 的系統和一台其它的系統 ... 五年之後的 2003 年,Linux 長大了。雖然 Unix 仍佔市場的大部分份額,但是在世界 500 强超級計算機中只有 289 台採用 Unix,佔 57.8%,Linux 佔 184 台,市場份額達到了 36.8%。
...
前幾天,Top500.org 公佈了最新的世界 500 強超級計算機排行榜,Unix 的表現不太好。在世界 500 強超級計算機中,有 439 台使用 Linux 作業系統,佔 87.8%。只有 23 台採用 Unix 系統,佔 4.6%。有 31 台採用 Linux 和 Unix 混合的系統,還有幾台採用 Mac OS 或者 BSD 系統。 但是,即使把這些都算作 Unix 系统,Linux 現在也非常明顯地佔有優勢。 ...

英國記者 Paul Rubens 說: 「Linux 正在越來越多地做過去一直讓 Unix 做的工作」。反觀微軟的 Windows,文中甚至沒有支字片語提到這個作業系統,如果按照上面的數據,Linux 佔 87.8%,Unix 佔 4.6%,Linux 和 Unix 的混合系統有 31 台佔 6.2%,全部加總起來後推算,Windows 所佔的比例還不到 1.4%,這當中還沒有扣掉 Mac OS 以及 BSD 等其它作業系統所佔的部份。
圖 3: Roadrunner (走鵑),一種鳥類,於路地奔跑最快可達時速 24 公里。
圖 3: Roadrunner (走鵑),一種鳥類,於路地奔跑最快可達時速 24 公里。
除此之外,依據 TOP500.Org 的評斷方式,現在世界上最強大的電腦 (2008 年 11 月的排名) 是採用 Linux 作業系統IBM Roadrunner 超級計算機 (見圖 2),因此 Linux 不僅是前 500 大計算機中使用最多的作業系統,它還光榮地在世界第一強的超級計算機上被執行。

如果說 Linux 真的是玩具,而世界上排名第一的超級電腦 Roadrunner 靠的卻是一只玩具來驅動,是否意謂著這台超級電腦本身其實也只是個玩具?此外,超級電腦還被視為一個國家科技水平的象徵,這是否又意謂著一個國家的聲譽可以如此草率地寄託在一個玩具作業系統上?我想,兩者的答案顯然都是否定的吧。

參考文章

Unix 失勢 HPC 市場兩年份額下降三分之二
HPC TOP500 追捧高性能計算進入 AMD 巴塞羅那時代?

2009年5月6日 星期三

SSH 與 SFTP - Samba 以外的遠端檔案存取方式

剛開始用 Ubuntu 的時侯,若想在不同電腦分享檔案時,第一個想到的就是 Samba,但是最近在 GNOME panel 上的功能表上摸索時,發現到一個 Samba 以外的方法。

從 GNOME panel 的功能表選 位置 > 連接到伺服器...

GNOME panel 功能表 > 連接到伺服器...

接著會彈出一個連接伺服器的 dialog

連接伺服器 dialog 的初始狀態

在服務類型右邊的 combo box 點下去以後,可以看到一個連線方式的列表

連接伺服器 dialog 的服務類型列表

在列表中比較引起我注意的是 SSH,之前常常透過 SSH 連到遠端 Linux server 作 shell 指令操作,但是不知道這裡的 SSH 是做什麼用的,因此好奇地點選了 SSH,結果 dialog 的內容變成

服務類型為 SSH 時的連接伺服器 dialog

填入伺服器的位置 (除了 IP 也可填主機的網域名稱,如: mycomputer.no-ip.net) 及使用者名稱 (192.168.2.134 及 remote-user-name 只是範例資料) 按下連接

服務類型為 SSH 時的連接伺服器 dialog (加上範例資料)

接著它會要求輸入 remote-user-name 的密碼,密碼輸入完後按下連線

輸入密碼 dialog

最後會跳出一個 Nautilus 視窗,裡面顯示的就是 192.168.2.134 主機內的檔案

Nautilus 視窗連到 SFTP 時的樣子

原來 Samba 以外 SSH 也可以用這樣的方式透過 Nautilus 存取遠端的檔案。此外,注意在下圖中的位置列

Nautilus 視窗連到 SFTP 時的樣子 (位置列用紅框框起來以強調)

可以發現其中的位置有這樣的格式

sftp://<使用者名稱>@<主機位址>

和我們平常用 Samba 時在位置列中看到的位置很類似,差別只在於它是以 sftp:// 開頭而不是 smb:// 開頭,SFTP 即 SSH file transfer protocol 的縮寫。因此如果想要透過 SSH 連到遠端主機,其實不必經過連接伺服器的對話方塊及上面的一堆步驟,只要直接在任意一個 Nautilus 視窗的位置列中輸入依照上面格式的位置並套入使用者名稱和主機位址就行了。這種存取方式在遠端伺服器沒設定 Samba 或沒安裝 Samba server 的場合可以派上用場,要注意的是 server 端與 local 端必需分別安裝 SSH server (例如 openssh-server 套件) 與 SSH client (例如 openssh-client 套件,一般 Ubuntu 預設都有裝 SSH client),否則要用 SFTP 存取遠端檔案很可能會失敗。

2009年5月1日 星期五

詐騙電話?

今天午飯吃完不久電話就響了
家人連忙跑去接
結果似乎是別人打錯電話了

...過不到兩分鐘 電話又響了
這次是我接的
一接起來就聽到 #@!%%^%&...
一堆聽不懂的話
聽起來有點像是外勞不知道在講什麼
於是用英文告訴他 (不知道他聽不聽得懂英文) 他打錯了
然後就把電話給掛了

接著沒過多久又來電
還是我接
還是一樣 #@!%%^%&... 聽不懂
結果家人跑出來
叫我趕緊掛斷
說那是詐騙電話
是要騙電話費的

雖然滿腦子疑惑
但還是把電話掛了
連電話線都拔掉
省得他再打來

不過聽家人這麼一說
倒是挺讓我好奇的
以前聽到的都是說:「不要隨便回覆來路不明的電話」
因為如果是詐騙電話
你回撥回去的可能是 5~500元/每分鐘 的高額計費電話
這種電話通常是發話方付費
但還沒有聽過別人打來
接電話的一方要付費的
難道電信公司真的有這種服務?

到網路上查好像也查不到
最後打 165 反詐騙專線詢問
把剛才的情況告訴服務員
服務員告訴我對方有可能是打錯了
因為接話方是不需付費的
這才解開心中的疑惑
原來剛才可能只是一場誤會...

各位有碰過這樣的情況嗎?
服務員說接話方不需付費是正確的嗎?

以 fstab 自動掛載 Big5 編碼的 FAT 分割區

在 Ubuntu 要自動掛載分割區可以修改 /etc/fstab,在 fstab 中每一行代表一個檔案系統的設定。而每一行裡面又分為 6 個欄位,欄位之間以空白或 tab 作分隔:

<1 要掛載的裝置> <2 掛載到哪個目錄> <3 檔案系統的型態> <4 掛載的選項> <5 fs_freq> <6 fsck 檢查檔案系統時的順序>

自動掛載 FAT 分割區要在第 3 欄指定檔案系統的型態為 vfat,此外台灣地區 Windows 下繁體中文通常是以 Big5 來編碼,因此在第 4 欄的掛載選項中要加入 iocharset=utf8 以及 codepage=950 這兩個選項,否則掛載上去以後在 Nautilus 裡面的中文檔名可能變成亂碼,底下是從我 fstab 中擷取出來:

/dev/sda2 /media/sda2fat32 vfat owner,exec,dev,suid,rw,auto,umask=000,iocharset=utf8,codepage=950 0 0

其中第 4 欄的 umask 是用來指定檔案及目錄的權限,當 FAT 磁區被掛載上去了以後通常是無法直接用 chmod 來更改磁區內檔案及目錄的權限的,必需從 fstab 中先設好。umask=000 代表打開所有的權限,即 -rwxrwxrwx;而 umask=777 則代表關閉所有權限,即 ----------。所以 umask 的設定方式正好與 chmod 相反,umask=674 相當於 chmod 103,umask=257 相當於 chmod 520 依此類推…。如果檔案和目錄想要指定不同的權限,則可以分別以 fmask 及 dmask 來指定,打 man mount 然後搜尋 umask 可以找到 umask、fmask 及 dmask 的用法。

輸入命令 man fstab 可以看到更多 fstab 的詳細說明,第 4 欄的掛載選項的詳細說明則要打 man mount 去找。下面是我完整的 fstab,最後兩行掛載的就是 FAT 磁區:

# /etc/fstab: static file system information.
#
##  The following description is from 'man fsck':
##  
##    The root filesystem will be checked first unless the -P option is specified (see below).  After
##    that, filesystems will be checked in the order specified by the fs_passno (the sixth) field in
##    the /etc/fstab file.  Filesystems with a fs_passno value of 0 are skipped and are not checked at
##    all.  Filesystems with a fs_passno value of greater than zero will be checked in order, with
##    filesystems with the lowest fs_passno number being checked first.  If there are multiple
##    filesystems with the same pass number, fsck will attempt to check them in parallel, although it
##    will avoid running multiple filesystem checks on the same physical disk.
##    
##    Hence, a very common configuration in /etc/fstab files is to set the root filesystem to have a
##    fs_passno value of 1 and to set all other filesystems to have a fs_passno value of 2.  This will
##    allow fsck to auto- matically run filesystem checkers in parallel if it is advantageous to do
##    so.  System administrators might choose not to use this configuration if they need to avoid
##    multiple filesystem checks running in parallel for some reason --- for example, if the machine
##    in question is short on memory so that excessive paging is a concern.
##
##  Therefore, we should give a value, other than 0 and 1, to the fs_passno (the sixth) of swap, sda2
##  and sda5 if we want them to be checked.
#
#                
proc            /proc           proc    defaults        0       0
# /dev/sdb6
UUID=a0cf5674-f414-4841-b3f4-86a11c6826ce /               ext3    relatime,errors=remount-ro 0       1
# /dev/sdb7
UUID=8dd47df8-8c27-455f-806a-7b663184189d /data           ext3    relatime        0       2
# /dev/sdb5
UUID=f63c79dd-13d2-48f6-817d-7479ef87e0bc none            swap    sw              0       3
/dev/scd1       /media/cdrom0   udf,iso9660 user,noauto,exec,utf8 0       0
#  FAT32
/dev/sda2 /media/sda2fat32 vfat owner,exec,dev,suid,rw,auto,umask=000,iocharset=utf8,codepage=950 0 0
/dev/sda5 /media/sda5fat32 vfat owner,exec,dev,suid,rw,auto,umask=000,iocharset=utf8,codepage=950 0 0