Language

Showing posts with label elisp. Show all posts
Showing posts with label elisp. Show all posts

Saturday, February 2, 2013

如何在 GNU Emacs 減少按鍵次數並提升工作效率


GNU Emacs 是一個非常 powerful 的編輯器, 這個就不需要我多作介紹, 但是與 vim 相比, GNU Emacs 有一個比較大的缺點就是按鍵多。只要是採用 modeless 的方式編輯, 又要功能多, 按鍵數很難減少, 但是還是有一些方法, 可以讓我們整體的按鍵數量變少的, 可以減少手的傷害。至於那些買了青軸機械式鍵盤之後, 想辦法多打字讓別人聽按鍵聲音的, 就不在本文的討論範圍內。

GNU Emacs 有兩種方式減少打字數目, 筆者認為值得推薦, 一種是用巨集(macro), 另一種是用 skeleton 套件。當然還有第三種是編寫 Emacs Lisp, 寫點函數, 這個難度比較高, 不太適合初學者。今天筆者介紹的這兩個方式都很適合初學者使用。

Table of Contents


巨集

首先, 我們來看看巨集。要知道 EMACS 這個名字是由 Editing MACroS 來的, 巨集可是 Emacs 的核心價值啊!只要你發現你在做重複性的工作, 就可以把那些一連串的按鍵動作變成巨集。
定義巨集很簡單, 在你的一連串按鍵動作開始之前, 先輸入 C-x (, 然後就開始按照平常的動作按按鍵, 按完所有按鍵之後, 鍵入 C-x ) 就完成巨集的定義了。
要執行剛剛定義完的巨集, 就按 C-x e, 也可以配合 Emacs 的數字前置指令來執行多次的巨集。比如說你想要執行這個巨集四次, 就鍵入 M-4 C-x e 就會執行這個巨集四次。
The quick brown fox jumps over the lazy dog

比方說, 你想要把上面這個檔案改成一個英文單字一行, 可以用巨集來做, 方法如下:
按鍵動作
C-x (開始錄製巨集
M-f把游標往前移一個單字
C-d刪除一個字元
[ENTER]插入換行字元
C-x )結束巨集的錄製

上述的巨集可以讓一個單字單獨存在於一行, 把剩下的文字換到下一行去, 如果要把所有英文單字都單獨存在於一行, 就需要重複作這個巨集。可以先用 M-x count-words-region 來計算這一行的單字數, 九個。所以要處理完所有的單字, 就輸入按鍵 M-9 C-x e, 不過通常我們錄製巨集的時候已經先做完一遍了, 那這時候你只需要執行 8 次就好。執行完結果就會如下所示:
The
quick
brown
fox
jumps
over
the
lazy
dog



Skeleton




如果你的重複性工作, 是經常性的使用到, 比方說寫函數時的註解, 常常需要寫函數名稱、作者、建立的時間等等資訊, 有些是每次都寫一樣的資訊(如作者), 有些則可以由函數執行結果得來(如日期), 有些需要打兩次一樣的字串(如函數名稱), 那麼 skeleton 就是一個不錯的工具, 讓你減少打字數目。


使用 skeleton 的方法如下:

(define-skeleton your-skeleton-name
  "String to describe this skeleton."
  "String that will be inserted when you call your-skeleton")



然後你就可以用 Emacs Lisp 函數一樣的呼叫方式來呼叫:
M-x your-skeleton-name 這函數就會自動從游標位置插入預先定義好的字串。
高階一點的用法就會牽扯到

  • 使用者輸入字串

    • 使用 (skeleton-read)

  • 重複使用者輸入的字串

    • 使用 v1, v2 變數

  • 游標最後所處位置

    • 使用 "_" 來標示

  • 呼叫 Emacs Lisp 函數來插入字串

    • 直接呼叫


筆者就用我自己用的一個例子來說明 skeleton:
; Skeleton for assembly subroutine header
(define-skeleton insert-asm-header
  "Prompt for subroutine name and insert assembly subroutine header"
  "" ?\n
  ";******************************************************************************" ?\n
  "; Name:\t\t" (setq v1 (skeleton-read "Subroutine name: "))?\n
  "; Purpose:" ?\n
  ";   " (skeleton-read "Purpose: ") ?\n
  "; Method:\t" ?\n
  ";   " ?\n
  "; Parameters:\t\t" (skeleton-read "Parameters: ") ?\n
  "; Affected regs:\t" ?\n
  "; Author:\tAlbert Chun-Chieh Huang, " (insert-current-date) ?\n
  ";******************************************************************************" ?\n
  v1 \n
  "" _ \n
  "rts" \n
  )



定義完之後, 我們就可以用 M-x insert-asm-header 來呼叫這個 skeleton, 呼叫之後, 在 mode line 會出現
Subroutine name: 



要求使用者輸入副程式名稱, 除了馬上把這名稱字串放到 "Name:" 之後, 並且存在 v1 這個變數裡。 接下來會要求使用者輸入 Purpose: 說明這個副程式的用途, 並把副程式用途就插入 (skeleton-read "Purpose: ") 的位置上。接下來的 Parameters: 也一樣。到了 Author 的地方就呼叫 Emacs Lisp 函數 (insert-current-date) 把日期填上。
在倒數第四行的 v1 就是把剛剛存在 v1 這個變數的副程式名稱取代 v1 填上去。
倒數第三行的 "_" 就是指示 skeleton 插入完這些字串之後, 游標要回到這個位置來。
所有被雙引號包起來的都是字串, 不會有特殊意義。在雙引號以外的, 就是 Emacs Lisp 函數、變數、或是特殊字元。=\n= 是換行並且依照所處的 mode 縮排, 而 ?\n 則只有單純的換行字元而已。


下面的例子就是執行完後的結果, 游標會停在倒數第二行, 與 rts 同樣的縮排位置上, 方便我打第一個 instruction.
;******************************************************************************
; Name:         Test
; Purpose:
;   Test
; Method:       
;   
; Parameters:           a1
; Affected regs:        
; Author:       Albert Chun-Chieh Huang, 02 February 2013
;******************************************************************************
Test
        
        rts


如果對於 skeleton 想要有更深入的了解, 可以按 C-h f skeleton-insert, 裡面有關於 define-skeleton 的字串該怎麼寫的詳盡說明。






結語




要提升工作效率, 第一要件就是先找出重複的工作, 並且用快速有效率的方法執行這個工作。當你找出重複性的部份之後, 可以把重複不變的部份抽出來變成巨集, 如果有經常性的重複編輯工作, 就可以考慮用 skeleton 來定義, 如果有每一次呼叫變動的部份, 就考慮把這些變動用呼叫函數或是輸入參數的方式來引入, 如此就可以有效的減少按鍵次數, 並且提升工作效率。



--
Albert Huang
Chun-Chieh Huang(黃俊傑)

Friday, October 5, 2012

在 GNU Emacs 的 Help 文件系統


GNU Emacs 有一個功能很好用, 他的 key binding 一般來說是 C-h S, 或是 M-x info-lookup-symbol, 使用的方法是把游標移到你要查詢的 symbol 上面, 然後按下 C-h S, 這時候 Emacs 會自動幫你找到相對應的 Info 文章, 並顯示在另一個視窗(這裡的視窗是 Emacs 的術語) 上。



如果你想要試用這個功能, 可以試著開啟任何一個 Emacs Lisp 檔案, 然後對著任何一個 function 鍵入 C-h S, 就會出現文件, 舉例來說, 如果對著 require 按下 C-h S, 在筆者的 Emacs 24.1.1 就會出現下列的文件:





-- Function: *require* feature &optional filename noerror
This function checks whether FEATURE is present in the current
Emacs session (using `(featurep FEATURE)'; see below). The
argument FEATURE must be a symbol.

If the feature is not present, then `require' loads FILENAME with
`load'. If FILENAME is not supplied, then the name of the symbol
FEATURE is used as the base file name to load. However, in this
case, `require' insists on finding FEATURE with an added `.el' or
`.elc' suffix (possibly extended with a compression suffix); a
file whose name is just FEATURE won't be used. (The variable
`load-suffixes' specifies the exact required Lisp suffixes.)

If NOERROR is non-`nil', that suppresses errors from actual
loading of the file. In that case, `require' returns `nil' if
loading the file fails. Normally, `require' returns FEATURE.

If loading the file succeeds but does not provide FEATURE,
`require' signals an error, `Required feature FEATURE was not
provided'.





上述作法是當你目前的 major mode 有相對應的 Info 檔案的時候, 可以直接使用 C-h S 來查詢, 如果沒有的話, Emacs 會先問你要使用哪一個 major mode 的 help 檔案, 然後再查詢該 symbol 的文件。那麼, 如果要為新的 major mode 增加 Info 文件呢? 這時候你可以在 .emacs 裡加上 info-lookup-maybe-add-help 來把某個 Info 檔案加入 major mode 裡面, 範例如下:





(require 'info-look)

(info-lookup-maybe-add-help
:mode 'asm56k-mode :topic 'symbol
:regexp "[a-zA-Z]+"
:doc-spec '(("(dsp563xx)Index")
("(dsp563xx)Concept Index")))





上述的範例是指定 major mode asm56k-mode 的 Info 文件是 dsp563xx, 這個檔案必須在 Info 系統能找到的路徑上, 透過 Index 與 Concept Index 這兩個 Info node 來查詢關鍵字的 Info 文件, 而可以被查詢的關鍵字的 regular expression 則由 :regexp 來指定, 本範例的關鍵字是由純英文字母組成。上述的範例是筆者為了要在 GNU Emacs 裡面寫 Motorola DSP56300 的組合語言而增加的, 這樣筆者在 asm56k-mode 編輯組合語言的時候, 就可以隨時透過 C-h S 來查詢某個助憶碼(mnemonic) 的用法以及 instruction encoding, 而這些是存在另一個 Info 文件上。



Info 檔案在 GNU Emacs 中是一個重要的文件系統, 可以由 Texinfo 檔案編譯而成, 現在也有很多文件系統也可以產生 Texinfo 的格式, 比如 Sphinx, 對 Texinfo 有興趣的讀者可以參考一下 Arnold Robbins 在 Linux Journal 所寫的介紹文章 What's GNU: Texinfo. 不管是用什麼方法產生 Info 檔案之後, 透過設定, 結合 C-h S 的便利性, 你就可以在 GNU Emacs 裡面很便利的查詢文件。


--

Monday, June 18, 2012

用 Linear Filter(IIR) 來實作 Fibonacci 序列


PyCon.TW 2012 在日前圓滿落幕, 會中的 keynote speaker Travis Oliphant 講
了一個使用 linear filter 實作 Fibonacci 的例子, 在演講中只有一張投影片,
在這裡我嘗試做分解動作解釋一下。投影片內容在 http://www.slideshare.net/pycontw/largescale-arrayoriented-computing-with-python



我們知道 Fibonacci 序列是 x(n) = x(n-1) + x(n-2), 而 x(0) = 0, x(1)
= 1. Fibonacci 序列的產生也常常是教科書介紹 recursive 的好範例, 不過就
如 Travis Oliphant 所示, 用 recursive 實作的複雜度是 exponential 成長的,
而我們也可以用 SciPy 裡面的 linear filter 來實作這件事, 方法如下:




from scipy.signal import lfilter
from numpy import zeros
b = array([1.0])
a = array([1., -1, -1])
zi = array([0, 1.0])
def fib3a(N):
y, zf = lfilter(b, a, zeros(N, dtype=float), zi=zi)
return y




我來慢動作分解一下上面的實作方法。首先 lfilter 在 b = array([1.0]) 以及
a=array([1.,-1,-1]) 的情況下會產生b(0)x(n) = a(0)y(n) + a(1)y(n-1) +
a(2)y(n-2) 的式子, 代入 a,b, 我們可以得到 x(n) = y(n) - y(n-1) -
y(n-2),而 lfilter 的第三個參數就是 x 的序列, 是 zeros(N, dtype=float),
也就是說輸入全為零,上述的式子就會變成 0 = y(n) - y(n-1) - y(n-2), 把 y(n) 移到等式的左方, 就可以得到 y(n) = y(n-1) + y(n-2), 這就是 Fibonacci 數列的表示法啦! 最後的 y(n) 就是 Fibonacci 的第 n 個數列。另外,
zi=array([0,1.0]) 就是當 lfilter 開始執行的時候, delay element 裡面的元
素, 也就是 y(0) 與 y(1) 的值。



以濾波器的角度而言, 這個濾波器在輸入全為零的狀況下, 自己產生
0,1,1,2,3,5,… 這種發散的數列, 等於自己在震盪, 是我們在實際上不會去使
用的濾波器, 拿來實作 Fibonacci 數列, 實在是有趣。



--

Saturday, April 7, 2012

LaTeX PSTricks 訊號處理範例: z-Transform


上一篇的 moving average filter y(n) = (15/16)*y(n-1) + (1/16)*x(n) 的
z-transform 有一個 pole 在 z=(15/16, 0) 的點上, 要畫這個 z-Transform 在
z-plane 上的表示圖, 可以用下列的 PSTricks 來表示。




\usepackage{pstricks}
\usepackage{pst-sigsys}





圖形如下表示:
http://farm6.staticflickr.com/5238/7053583759_5fbddb20fc.jpg





\begin{center}
\begin{pspicture}[showgrid](-2,-2)(2,2)
\pscircle[linecolor=gray](0,0){1} % unit circle
\pspole(0.9375,0){z1}
\nput{0}{z1}{$(\frac{15}{16},0)$}
\end{pspicture}
\end{center}





--

LaTeX PSTricks 訊號處理範例: Moving Average Filter


今天要介紹的是如何用 PSTricks 來繪製訊號處理的 functional diagram, 假設
我們要描述的訊號處理方程式是: y(n) = (15/16)*y(n-1) + (1/16)*x(n). 這是
一個動平均濾波器, y(n) 是目前的輸出值, x(n) 是目前的輸入值, y(n-1) 則是上一次的輸出值,
那他的 functional diagram 會是如下圖所示:
http://farm6.staticflickr.com/5320/6907485526_81ef0d8ab5.jpg



上述圖形使用了 PSTricks 以及 PSTricks 的 pst-sigsys 套件,所以要在 preamble 的部份如下宣告:




\usepackage{pstricks}
\usepackage{pst-sigsys}





描述這個濾波器的 LaTeX source code 如下:




\begin{center}
% To describe y(n) = (15/16)*y(n-1) + (1/16)*x(n)
\begin{pspicture}(-2,-1)(10,2)
\pssignal(0,1){x}{$x(n)$}
\pscircleop[oplength=0.25,operation=times](2,1){op1}
\pssignal(2,0){coefx}{$\frac{1}{16}$}
\pscircleop[oplength=0.25](4,1){op2}
\pssignal(8,1){y}{$y(n)$}
\dotnode(6,1){ydot}
\psblock(6,0){delay}{$z^{-1}$}
\pscircleop[oplength=0.25,operation=times](4,0){op3}
\pssignal(3,0){coefy}{$\frac{15}{16}$}
\nclist{->}{ncline}{x,op1,op2,y}
\nclist{->}{ncline}{coefx,op1}
\nclist{->}{ncline}{ydot,delay,op3,op2}
\nclist{->}{ncline}{coefy,op3}
\end{pspicture}
\end{center}






--

Wednesday, February 22, 2012

gcc for Andes compile 出來的 assembly


為了要做 24-bit signed integer to 32-bit signed integer 的 signed extension 測試,我寫了以下的一小段 code 來測試, 在這裡順便稍微提一下 optimization, 我們先看 c code:




void testSign()
{
unsigned int test=0x00800000;
int test_s;
test_s = ((int)test << 8 ) >> 8;
}





除去 prologue 或 epilogue 的部份,我們來看主體:




00000614 <testSign>:
......
61c: 46 00 08 00 sethi $r0,#2048
620: 14 0e 7f fd swi $r0,[$fp+#-12]
624: 04 0e 7f fd lwi $r0,[$fp+#-12]
628: 40 00 20 08 slli $r0,$r0,#0x8
62c: 90 08 srai45 $r0,#0x8
62e: 14 0e 7f fe swi $r0,[$fp+#-8]




解釋如下:


sethi $r0,#2048

$r0 = 0x00800000

swi $r0,[$fp+#-12]

把 $r0 存回 test 的儲存空間

lwi $r0,[$fp+#-12]

把變數 test 值抓到 $r0

slli $r0,$r0,#0x8

把 $r0 做 logical left shift by 8 bits, $r0 = 0x80000000

srai45 $r0,#0x8

把 $r0 做 arithmetic right shift by 8 bits, $r0 = 0xff800000

swi $r0,[$fp+#-8]

存回 tests 的儲存空間。





而如果我們把這個 c code 改成如下:




int testSign(unsigned int value)
{
return ((int)test << 8) >> 8;
}





產生出來的 assembly 就會變成:




000005f8 <testSign>:
5f8: 40 00 20 08 slli $r0,$r0,#0x8
5fc: 90 08 srai45 $r0,#0x8
5fe: dd 9e ret5 $lp




這個版本完全沒有任何 local variables, 傳入的參數也只有一個, 當傳入參數
只有一個的時候, 會使用 $r0 這個暫存器傳入, 回傳值也是在 $r0 回傳,
所以這樣子最省空間了,也是我們 assembly programmer 會寫出來的樣子。注意
如果沒有做 (int) 的 explicit cast, 編譯器並不會使用 srai45 這個
arithmetic right shift 指令製造 signed extension, 即便是最後的回傳值是
有號數。


--
My Emacs Files At GitHub

Thursday, January 26, 2012

Emacs 的 org-googlecl 會把標題的 $ 吃掉


在上一篇「超便宜的 TI C6670 EVM, 只要 USD$599!」中,原本的文章因為 $ 在標題中被吃掉,所以變成了「超便宜的 TI C6670 EVM, 只要 USD99!」,想必標題相當吸引人,呵呵。


--
My Emacs Files At GitHub

超便宜的 TI C6670 EVM, 只要 USD$599!


參考連結: http://www.ti.com/tool/tmdxevm6670
這是 TI 的 TMS320C6670 EVM 的連結,這一顆 DSP 擁有四個 C66x 的核心,每一個核心都可執行 SIMD 指令,可以同時執行 8 組 32-bit 指令。TI 稱呼這個叫做 static VLIW, i.e. Very Long Instruction Word. 另外, C6670 有 Turbo encoder/decoder coprocessor、Viterbi decoder coprocessor、CDMA 用的 RAKE 加速器,還有 FFT coprocessor 等,頗適合拿來實作 WCDMA/CDMA2000/LTE 等各種 cellular communication 的基地台。當然,要拿來其他通訊模式也非常 powerful. 這麼強大的一顆 DSP, EVM 含 emulator 只要 USD$599 喔!



--
My Emacs Files At GitHub

SimPy slides in our company and PyHUG meeting


This is my presentation on discrete-event simulation given to engineers in our company and PyHUG, which is Python Hsinchu User Group. I think it might be useful for somebody on the Internet.
https://docs.google.com/open?id=0B0rtbYTzCZWN2Y5MmY4M2ItYzJkYy00ZTA2LWI5N2UtNmUxNjI5YzNjZTg0



http://dl.dropbox.com/u/31960195/Introduction-to-SimPy-20111017-PyHUG.pdf



--
My Emacs Files At GitHub

Friday, November 11, 2011

Improvement on matlab-emacs


Modification to matlab-cellbreak-face




Current cvs code for matlab.el does not handle cellbreak-face correctly. It cannot distinguish between %% and %%%%, but matlab-shell-run-cell can function well. But fontifying not well is still annoying, so we need to modify it. In matlab.el, find the following lines to modify from:




;; Cell mode breaks get special treatment
'("^\\s-*\\(%%[^\n]*\n\\)" (1 matlab-cellbreak-face append))




Change it to:




;; Cell mode breaks get special treatment
'("^\\s-*\\(%%[^%\n]*\n\\)" (1 matlab-cellbreak-face append))










Evaluate cell and advance (C-S-return)






In MATLAB editor, we can press C-S-return to perform "evaluate cell and advance" function. Minor modification to matlab.el can make it happen. You can just add the following code snippet to your .emacs file.





(require 'matlab-load)
(defun matlab-goto-next-cell ()
(interactive)
(re-search-forward "^%%[^%\n]"))

(require 'matlab)
(define-key matlab-mode-map [(meta control F)] 'matlab-goto-next-cell)
(defun matlab-run-cell-and-go ()
(interactive)
(progn
(save-excursion
(matlab-shell-run-cell))
(matlab-goto-next-cell)))
(define-key matlab-mode-map [(meta shift return)] 'matlab-run-cell-and-go)





The example for running matlab cell mode is like this:





a = [1,2,3];

c = [4,5,6];

%% This is first cell

d = a * c';

%%%% This is not a cell

b = [3,2,1];

%% Another cell

c = a + b;

kkk





After pressing three <C-S-return>, the matlab-shell screen will look like:






< M A T L A B (R) >
Copyright 1984-2010 The MathWorks, Inc.
Version 7.12.0.635 (R2011a) 64-bit (maci64)
March 18, 2011


To get started, type one of these: helpwin, helpdesk, or demo.
For product information, visit www.mathworks.com.

>> addpath('/Users/jjhuang/elisp/matlab-emacs/toolbox','-begin'); rehash; emacsinit('emacsclient -n');
>> , a = [1,2,3];, c = [4,5,6];,
>> , a = [1,2,3];, c = [4,5,6];, d = a * c';, b = [3,2,1];,
>> , d = a * c';, b = [3,2,1];, c = a + b;, kkk,
??? Undefined function or variable 'kkk'.

>>





Okay, now matlab-emacs for me is more convenient right now. Hope you enjoy it!




--
My Emacs Files At GitHub

Friday, October 14, 2011

悼念 Steve Jobs


第一次知道 Steve Jobs 這個人,是在我大一開始接觸 NeXTSTEP 這個作業系統之後,當時 NeXT 以劃時代的物件導向技術、華麗的視窗外觀、當時時尚界流行的黑色元素、鎂合金的外觀,以及對開發者非常友善的開發工具,在 1990 年代初期登場,而 Steve Jobs 正是生產 NeXT 電腦的 NeXT 公司的 CEO. NeXT 也是他在被自己所創辦的 Apple 解僱之後所創立的公司。



NeXT 是我人生第一次如此著迷的軟體技術,也是我第一次如此深信這產品將會改變這個世界。因此,NeXTSTEP 上的應用程式也是我唯一會寫的視窗應用程式。我總是告訴別人 NeXTSTEP 是世界上最美麗的作業系統。在我大二時接管了一些 DEC Alpha 的工作站,於是我為系上設立了 FTP 站。我選定了 NeXTSTEP 相關的資源映射至 FTP 站裡,到後來系上的 FTP 站成為台灣 NeXTSTEP 資源最完整的 FTP 站,也使得系上的 FTP 站在某個小眾市場裡頗具知名度,而那也是我人生中做的第一個與 marketing 有關的決策。然而,我認為當時不擅長 marketing 的 NeXT 開始出售硬體工廠,而且營收不佳,幸而當時 Apple 正在為他的 OS9 尋著「下一步」,Apple 從 BeOS 與 NeXTSTEP 中選擇了 NeXTSTEP, 也使得 Steve Jobs 後來王子復仇重回 Apple 掌舵。我想 Steve Jobs 在這個時期學會了虛心,也學到了 marketing 的重要性與技巧,此後 Apple 的產品,在我看來,不再以技術上的創新為唯一的依歸,更多是使用者經驗的創新。



在 NeXT 被 Apple 收購之後,我開始接觸與 Steve Jobs 有關的書,有兩本,一本是 "Apple: The Inside Story of Intrigue, Egomania, and Business Blunders" by Jim Carlton, 另一本是由 Randall E. Stross 所撰寫的「電腦金童 NeXT 風雲再起」,分別描述了他在被 Apple 踢出公司前與 NeXT 時代的故事,當這些書完成的年代,Steve Jobs 對這些作者相當的不友善。他從不願提供任何資料,也不讓作者訪問他的家人,因此作者只能辛苦的從旁人口中得到 Steve Jobs 的資料。這個時期他脾氣暴躁,而我其實不太欣賞他。



他回 Apple 之後,開始推出彩色外殼的 iMac 以及貝殼造型的 iBook,但一直到 iPhone 的出現,我才又注意與欣賞 Steve Jobs 的才華。當時我擁有一支 Nokia Symbian S60 系列的智慧型手機,深深知道智慧型手機最重要的就是軟體與使用者經驗。iPhone 在當時並不是第一支智慧型手機,也不是第一支觸控手機,初問世時更因沒有觸控筆或鍵盤而被市場質疑,但當我試用過而且知道 Apple 將當初 NeXT 那一套有名的開發工具流程應用在 iPhone 的開發上,我知道這支手機絕對劃時代。再加上 AppStore 方便程式設計師以及 SOHO 工作室將開發出來的軟體很容易的銷售到使用者首中,iPhone 的軟體便像雨後春筍般蓬勃發展,這絕對是 iPhone 開發者、使用者、Apple 三贏的局面,也使得 iPhone 成為世界上單一機種銷量最高的智慧型手機。之後,Apple 更順勢推出 iPad 這個平板電腦,更帶起來平板電腦的風潮。回顧 iPod, iPhone, Apple TV, iTunes store, 以及 AppStore. 可以看得出來 Steve Jobs 逐步的將他心中的藍圖實現,將 Apple Computer, Inc. 從軟硬體整合製造商轉型為以內容與服務為主的 Apple, Inc. 這樣子的遠見與毅力,才是我佩服與欣賞 Steve Jobs 的原因。我想不可否認的,iPhone 與 iPad 的出現,的確完全改變了你我的世界。



今年八月 Steve Jobs 請辭 CEO, 大家就在猜測他的健康是否出現問題,而當我看到 Steve Jobs 與 Walter Isaacson 合作寫傳記,容許這個作者訪問所有他身邊的人,其實就大概可以猜到他已經在做準備了。但當 10 月 5 日,他過世的消息傳來,我仍然感到悲傷。雖然我總是說我並不是 Steve Jobs 迷,但當他過世時,我深深感到這世界失去了一個有遠見、有創意的奇才。而在他過世之後,我也重新觀看他對 Stanford 畢業生做的演講,裡面我最愛的一段是第三個關於死亡的故事,裡面說到如果你每一天都當做活著的最後一天來活,總有一天你會活出你的生命。當面臨死亡的時候,所有的外界期望、所有的驕傲、所有對於丟臉或是失敗的恐懼,這些都會消失。因為你已經光溜溜了,沒有理由不順從你的心。謝謝你,Steve Jobs,讓我有勇氣順從我的心,做我真正想做的事,而不恐懼失敗。謹以 Robert Frost 的詩來悼念這個不平凡的 CEO.



The Road Not Taken



Two roads diverged in a yellow wood,

And sorry I could not travel both

And be one traveler, long I stood

And looked down one as far as I could

To where it bent in the undergrowth;



Then took the other, as just as fair,

And having perhaps the better claim,

Because it was grassy and wanted wear;

Though as for that the passing there

Had worn them really about the same,



And both that morning equally lay

In leaves no step had trodden black.

Oh, I kept the first for another day!

Yet knowing how way leads on to way,

I doubted if I should ever come back.



I shall be telling this with a sigh

Somewhere ages and ages hence:

Two roads diverged in a wood, and I—

I took the one less travelled by,

And that has made all the difference.



           – Robert Frost







--
My Emacs Files At GitHub

Saturday, October 8, 2011

愛吃信用卡的高鐵自動售票機


有坐過高鐵的人, 有不少的比例會因為售票窗口大排長龍而像筆者這樣選擇自動售票機購票; 自動售票機售票有三種付款機制, 分別是現金、信用卡、金融卡。用現金購票有個惱人之處: 找錢一律用銅板, 就是會掉出一大堆的五十元銅板。再加上信用卡購票可以累積信用點數, 所以有一部分人會採用信用卡付款, 外國旅客來台灣也蠻常用信用卡付款的。


高鐵自動售票機可以說是信用卡吃卡機器, 原因就出在整體的使用者介面設計上。信用卡購票流程是這樣的, 首先先在下方螢幕點選「自由座」或「對號座」, 然後是乘車日期、時間, 選定班次, 接下來選擇付款機制, 如果選擇了信用卡, 這時候你的注意焦點要開始擺在上方小螢幕上, 自動售票機會有語音提示你這點, 但是我也常常看到不熟悉這個購票流程的人不知道該看上面的小螢幕。這個問題就出在使用者在按螢幕這麼多按鍵後, 心中其實是忽略所有語音的提示, 而把焦點放在視覺上, 如果這時候沒有視覺上的提示, 很容易被忽略。


如果使用者有注意到上方小螢幕的話, 接下來是插入信用卡, 等待輸入預借現金密碼或是生日。這部份的問題是按鍵頗難按, 而且如果你慢個二十秒注意到這個小螢幕, 很大的機會會在輸入完密碼後告訴你連線逾時, 一切又得重新再來。


當信用卡密碼輸入正確, 而且連線驗證成功之後, 以下的動作幾乎是同時發生: 1) 上方信用卡退出來, 2) 下方出票口「亮燈」並且送出車票與簽帳單。問題就發生在第二個動作是有亮燈而且有聲音的, 很多使用者都會被下方的事件所吸引, 而忽略了上方無聲無息的事件。也因此, 不少使用者拿了票之後就直接走人搭車去, 忘記了那張信用卡, 尤其是你後面排了不少人的時候。這也就是為什麼常常聽到車站廣播有人遺失信用卡的原因了, 筆者本身就提醒過幾次前方的使用者拿信用卡, 包括外國旅客; 個人也有一次親身經歷, 而且是我常常用信用卡在自動售票機買票搭高鐵好幾年之後, 在某個週日早上剛睡醒不久, 疏於注意就忘記信用卡了。


對於這樣的使用者介面, 我建議的改進方式是這樣: 在信用卡插入口上方加一個 LED 燈號, 要夠醒目, 當第一次要插入卡片的時候閃個四五秒吸引使用者注意。另外當密碼驗證成功之後, 上方信用卡退出來要一直閃爍直到取走, 然後出票口才出票。這樣的缺點當然是要比原先的流程再多個幾秒鐘時間, 但是卻少掉很多信用卡掉卡的機會, 應該也會吸引更多信用卡用戶從售票窗口移到自動售票機購票吧。整體而言, 高鐵的自動售票機已經做得不錯, 若吃信用卡這點能夠改善, 大家(尤其是外國旅客)對台灣高鐵的印象會更好一點。畢竟如果你只搭那麼一次高鐵要去機場, 卻因為售票機流程設計不好, 把你的信用卡而不是你的心留在臺灣, 那就不是我們所樂見的囉。

附記:2012 年 12 月 31 日恰好臨時在台北車站用信用卡買了高鐵票(筆者後來都用 iPhone app 購票), 發現購票機已改成上述的流程, 筆者沒有投書高鐵, 想必是英雄所見略同!

--
My Emacs Files At GitHub