PageRank



轉移公告

計劃把 http://blog.hoamon.info/ 文章全部轉移至 http://www.hoamon.info/blog/ 這裡,而本 Blogger 站台的文章近 500 篇,我預計在 2014-12-31 前移轉完畢,完成後 http://blog.hoamon.info/ 將只作代轉服務,一律把舊連結如 http://blog.hoamon.info/index.html 轉成 http://www.hoamon.info/blog/index.html ,敬請舊雨新知互相走告。

新文章只發佈在 http://www.hoamon.info/blog/

何岳峰 敬上

2010年9月28日 星期二

使用 Google AJAX Libraries API 時,無法離線撰寫網頁程式?

在網頁程式中,我都是使用 Google AJAX Libraries API 來 host jquery 程式庫的,然而這麼作有一個缺點,如果你是在離線作程式設計時,要手動修改樣版,把 Google 來源的 js 檔改成從本機讀取,是有點麻煩,但致少作得到。

但若是將來在系統上線後,使用者上得了你寫的網頁系統,卻無法連至 www.google.com 呢? 那怎麼辦,雖然這個機率會滿低的,但也是有可能會發生在這個網頁系統屬公司內部系統,而對外連線卻被中斷的情況下。

別怕! 很簡單,下面就是一個範例,第 6、7、8 行改成本機 host 的檔即可。



1 <link rel="stylesheet" title="default" type="text/css" media="screen" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/themes/smoothness/jquery-ui.css"> 2 <script type="text/javascript" src="http://www.google.com/jsapi"></script>
3
4 <script type="text/javascript">
5 if (typeof google == 'undefined') {
6 document.write(unescape('%3Cscript src="/localmedia/jquery-1.4.min.js" type="text/javascript"%3E%3C/script%3E'));
7 document.write(unescape('%3Cscript src="/localmedia/jquery-ui-1.7.2.custom.min.js" type="text/javascript"%3E%3C/script%3E'));
8 document.write(unescape('%3Clink type="text/css" href="/localmedia/smoothness/jquery-ui-1.7.2.custom.css" /%3E'));
9 } else {
10 google.load("jquery", "1.4.0");
11 google.load("jqueryui", "1.7.2");
12 }
13 </script>


延伸閱讀: Using CDN Hosted jQuery with a Local Fall-back Copy

2010年9月26日 星期日

如何處理「合併(merge)錯誤的 hg 儲存庫」? 就是再用「merge」來復原!

學弟把我們已經作好的分枝要合併進主線時,不知怎麼搞地 merge 得非常混亂,而且也 push -f 進 hg 伺服器。

我們總共有三種分枝: 'default', 'Release for XXX', 'convert to InnoDB',這次是要把 'convert to InnoDB' 的成果合併進 'default' ,再合併到 'Release for XXX' 。'convert to InnoDB' 是我們將 django-based 的系統從 MyISAM 引擎改到 InnoDB 所作的程式碼修改。主要的修改是發生在索引上,因為原本有一個地方設定了 unique_together = (('name', 'uplevel_id'), ) ,而它會造成 MySQL Error code 1071錯誤('Specified key was too long; max key length is 767 bytes'),因為 name 的原長度是 256 ,而我們又使用 utf8 ,所以它的實際長度為 256 * 3 = 768 ,但在 InnoDB 的索引中,限制為 767 以下,所以我們必須將 name 的長度限制為 255 。

當我改完程式碼後,就請學弟們在自己的本機上測試,如果沒問題的話,就作合併的動作,並送到實際運作的網站去。

結果,他合出了下面這個東西:



D 版是我的分枝成果,我希望他把 D 合併到 B 跟 C 中。但他生出了 E, F, G, H 。這 4 個版本都不是我想要的。

一開始,我的作法是再次作手動合併,結果我迷失在那些修改的程式碼中,花了快 3 個小時,依舊無法解開,所以我當時用下策來處理,就是以 hg strip 指令把 hg 伺服器上的 E ~ H 的版本洗掉。然後重作合併。

這個方法十分爛,但當下,剛好沒有人上傳程式碼,而我又陷在那堆程式碼中,所以我選了這個作法。

這種作法,會有一個大問題,如果有人在未刪除版本前,就作了 pull, update ,那麼下次他在 push 時,就會出現衝突。他一定會 merge 到亂掉,因為他手上的 E ~ H 版本的程式碼不具含意,所以他也無法以程式碼內含意義來作合併,這樣他會像我一樣陷入毛線當中。

所以,在我解決 hg 伺服器上的亂象後,我靜下心來仔細思考,才發現我何必管 E ~ H 作了什麼事呢! 我只要在 merge 時,忽略它們的修改就行啦!

首先,我 clone 一個 LOCAL 儲存庫,而且只 clone A, B, C, D 之前的版本。作法必須分兩次,因為 clone 只會把該版本的媽媽下載下來,所以像是 A, B, C, D 4 個版本,卻有 2 個 heads ,我就得分兩個指令來下載,指令如下:

$ hg clone https://SERVER/my_software LOCAL -r C
$ cd LOCAL
$ hg pull -u -r D

然後,依我原本想要的合併方式處理:

$ hg ci -m '"convert to InnoDB" branch ...' --close-branch #P.S. 這個作法事後會造成問題 *1
$ hg merge -r B
$ hg ci -m WRITE_f'_COMMIT_MESAGE # 產生 f'
$ hg merge -r C
$ hg ci -m WRITE_g'_COMMIT_MESAGE # 產生 g'

這樣 LOCAL 的版本圖就像下圖一樣。



再來,我把伺服器上的錯誤版本 clone 到本機的 SERVER-FIX ,然後在 SERVER-FIX 中依 branch 作合併,最後合併出 'convert to InnoDB' 及 'Release for XXX' 兩種 heads ,指令如下:

$ hg clone https://SERVER/my_software SERVER-FIX
$ cd SERVER-FIX
$ hg update -C H
$ hg merge -r E
$ hg ci -m WHATEVER_MESSAGE

成果如下圖:



接下來,我回到 LOCAL 儲存庫中,把 changeset push 到 SERVER-FIX 中,成果如下圖:



最後,我要作的就是把 I, G, g' 三者合而為一,而且要在 merge 時,完全忽略 I, G 的程式碼修改,怎麼作呢? 指令如下:

$ cd SERVER-FIX
$ hg update -C g'
$ hg merge -r I
$ hg status
M models.py
$ hg cat -r g' models.py > models.py # I 版的修改,只在 models.py 上,而我又用 g' 版的 models.py 把 I 版修改完全洗掉了
$ hg ci -m MERGE_g'_I_MESSAGE
$ hg merge -r G
$ hg status
M models.py
$ hg cat -r g' models.py > models.py # G 版的修改,只在 models.py 上,而我又用 g' 版的 models.py 把 G 版修改完全洗掉了
$ hg ci -m MERGE_g'_I_G_MESSAGE

最後成果如下圖:



再為各位整理一下,合併「錯誤的 hg 儲存庫」步驟:

1. 在本機上,重作一個完全正確的 LOCAl 儲存庫。
2. 在本機上,重現一個與伺服器相同的 SERVER-FIX 儲存庫,並依 branch 作合併,讓一個 branch 只有一個 head 。
3. 將 LOCAL 的成果 push 到 SERVER-FIX 中。
4. 讓 SERVER-FIX 中的 head 與 LOCAL 的 tip 合併。而且在合併時,完全消除程式碼的修改,讓它們合併完,程式碼是與 LOCAL 的 tip 程式碼完全相同。
5. 確認無誤,就能 push 到 hg 伺服器了。

以這種方式處理完的 hg 伺服器,才可以讓所有人都免去再次合併 E~H 這段錯誤程式碼的痛苦。

基本上, hg 的主要運作方法,就是要讓所有人習慣在自己的本機上, merge 自己與其他人的成果,如果你能順暢地走完 1 ~ 4 的步驟,也代表你足以應用 hg 在大部份的程式碼修改工作了。

註1 我太早在 'convert to InnoDB' 分枝上下 --close-branch ,所以我後來在使用 hg update -C 'convert to InnoDB' 時,它居然是 update 到 I 版,而不是 e' 版。

2010年9月25日 星期六

在 django-based 系統中,將MyISAM 轉換成 InnoDB

詳細請見官方文件

我簡單整理如下:

一、將 settings.py 中的資料庫引擎從 MyISAM(預設值) 換成 InnoDB , 加下以下設定,


DATABASES = {
'default': {
'NAME': 'xxx',
'USER': 'xxx',
'PASSWORD': 'xxx',
'ENGINE': 'mysql',
'OPTIONS': {
"init_command": "SET storage_engine=INNODB",
},
}
}


二、將原來的表格作


mysql> ALTER TABLE ????? ENGINE=INNODB;


至於第二種方法該如何處理,我是使用 mysql 指令手動處理:


mysql> \T /home/hoamon/alter.sql;
mysql> show tables;
mysql> \q;
sh# perl -i -pe 's/| +([^ ]+) +|/ALTER TABLE \1 ENGINE=INNODB;/g' /home/hoamon/alter.sql
sh# mysql -u xxx -pxxx xxx < /home/hoamn/alter.sql


我在將 MyISAM => InnoDB 時,遇到一個問題 MySQL Error code 1071錯誤('Specified key was too long; max key length is 767 bytes')。

因為原本的 models.py 有一個 Model 設定了 unique_together = (('name', 'uplevel_id'), ) ,而它會造成 1071 Error code,因為 name 的原長度是 256 ,而我們又使用 utf8 ,所以它的實際長度為 256 * 3 = 768 ,但在 InnoDB 的索引中,限制為 767 以下,所以我們必須將 name 的長度限制改為 255 才行。

2010年9月18日 星期六

挑戰清境

第三屆挑戰武嵿盃在 2010 年 9 月 5 日舉辦,而我又錯過了報名時間,所以只能在下午出發。而目標也只是清境而已。


花了 1 個小時 45 分後,我抵達霧社鄉公所。上次所花的時間是 1 小時 40 分,不過,這次我多了置物架,所以裝了不少補給物品。


一路上,看到不少上午比賽人員所拋棄的圾垃,像是補給飲料空包、高壓填充空瓶、酸痛貼布空袋等。我不知道主辦單位在事後會不會統一打掃,但就算會打掃,我相信這些比賽人員有能力帶上來,也應該有能力帶下去。


我的補給食品主要是香蕉,帶香蕉有一個好處,如果我真的沒公德心的話,丟在路邊,也會是路旁小樹的肥料。不過,我還是把香蕉皮帶回家了。我怕路樹吃太胖了。


最後在 PM 5:15 時,我抵達清境的第一家 7-11 ,而在這裡我就結束這趟自行車之旅。本來是想到 Starbucks 旁的那一家,不過,我的體力實在不行了,我連最輕段數的齒輪比都踏不下去了,而且再晚點下山,我就無法騎快車衝下山。



騎乘路線示意圖:


View 埔里鎮公所到清境的第一家7-11(花了三小時) in a larger map

我後來在想,這段路上,其實有很多 7-11 ,我應該只帶上 icash 來就行了。

2010年9月17日 星期五

手機(市話)小額付款

手機與信用卡的相同點為何? 都可使用後付制(post-pay),也就是服務/商品先享受,到期才付款,這也代表電信公司與銀行都具備 消費信用 的交易功能。本文要談的手機小額付款是單純指目前以 sim 卡為主的付款機制,不牽扯其他技術,如 NFC 非接觸式手機付款。


那我沒事講這個小額付款幹什麼呢?


原因出在老婆帶了本天下雜誌( 455 期,2010/9/8出版)回來,其中一篇全球視野中提到「手機當銀行 貧富市場通吃」。我非常驚訝,這讓我想起往事,過去在網際網路剛席捲全球的時候,中華電信就有推出以電話帳單代替信用卡帳單的服務,詳細內容在這麼多年後,我已經不太記得了,但目前看來利用電話付費的概念沒造成趨勢。


結果到現在還是有人在提說在偏遠地區沒有銀行服務,一般窮人用手機付款比銀行轉帳容易,而這將是"""趨勢"""。我驚訝的就是,一個本來應該是事實的東西,怎麼還是趨勢? 而且在台灣,電信付款的比例,除了在線上遊戲收款上,有比較明顯的應用,其他商品付之闕如。


目前的電信小額付款服務,運作方式分兩種,首先消費者先向所屬電信業者申請「小額付款」功能,申請時,會建立一組付款密碼,當消費者線上付款時,就以手機、身份證號及付款密碼作為付款的認證依據,成功付款後,會在下期的電信費中繳納;另一種則是消費者不用事先申請,而是在付款時,電信業者傳送一筆付款密碼到消費者手機上,待消費者將此付款密碼輸入付款頁面後,交易始算成立,若是使用市話方式,則是用市話撥打付款專線,並輸入付款密碼,詳細方式可參考 台科大碩士論文闕仁斌所著之「線上遊戲玩家使用電信小額付款服務接受度暨行銷模式之探討」 一文。該文主要以行為科學方法來探討消費者的接受程度,並回饋給電信業者及線上遊戲業者提供行銷策略。我不是學行為管理的人,所以我無從評斷該論文從消費者角度出發是否分析合理,但我以電信小額付款的本質來分析,這玩意的出現根本就是天經地義的。


本文一開頭就提到信用卡與手機都具備消費信用的交易功能,理由就是它們都可使用後付制。如果業者不相信申請人在消費後的一定期限內如實付款,則信用卡業者或電信業者必定終止消費信用的交易功能,此消費信用對信用卡而言,是購物;對電話而言,則是通話。而且經過聯合徵信中心或電信業者分享的資料庫的查詢,這些沒有信用的人,都會成為拒絕往來戶。


再來,信用卡與門號在一定程度上,是可以作到單一個人的認證功能,當我線上刷卡時,有卡號、到期月份、CSC碼等認證程序,實體刷卡時,要有卡片、簽名等認證程序,而電信小額付款時,我得提出手機(市話)號碼、身份證號、付款密碼或實際門號擁有證明(也就是簡訊密碼認證)。就認證功能上,它倆是一致具備的。所以電信門號與信用卡在本質上根本是一樣的,


甚至信用卡會被盜刷的機率還比電信門號高,因為電信門號的付款密碼沒有記在手機的背面,而簡訊驗證還可以證明實際擁有門號,你現在也很少聽說 SIM 卡被偽造的新聞。既然信用卡付費是常態,那電信小額付費沒理由只可應用在小眾範圍,尤甚者,我個人認為「電信小額付款」還可以應用在實體商店的消費服務上。


然而,目前的現實卻不是:信用卡消費遠遠打敗電信小額付款。第一個原因是信用卡經過銀行的徵信工作,可以給予消費者高額的「信用」,而電信業者卻只在初期開放給消費者 1000~2000 元的「信用」,待時間及消費頻率的增加,最多也到 3 萬而已。想當初慶豐銀行在我 22 歲還在唸研究所時,就給我 49 萬的額度,果不期然,它的信用卡部門最後被賣了,整個銀行從此結業。


從信用額度來看,我要繳保費、買電腦、機票,這些動則上萬的商品都無法使用電信小額付款,因為我對電信業者來說,「信用」太低了。這就是小額付款消費金額比例偏小的原因之一。


另一個原因,則是出在電信業者的不合作,就是這兩個原因造成小額付款不流行。第一個原因好解決,兩個手段:一、data mining 一下客戶資料庫,區別一下"好"客戶,讓他們擁有高額信用; 二、納入預付機制,讓消費者可對門號作預繳,像是從超商買來預付卡,並加值到一般後付的門號上,而這預繳的錢除了定期的電信資費扣款外,剩下的金額就是「電信小額付款」的上限,也就是把門號變成借記卡/金融卡(Debit card)。而第二種手段可以先第一種手段施行。


第二個原因,比較不好解決,但理論上卻是可以解決的。


銀行在推出信用卡服務上,並不是由銀行決定一切的,而是透過信用卡國際組織作為中間的橋梁,讓消費者能作輕鬆刷卡消費服務。所有的銀行合作起來,都加入 VISA 、 JCB 、 Master Card 還是中國銀聯等組織,並透過這個橋梁來協調消費者與特約商家之間的買賣關係,才能讓我用玉山信用卡在捷安特自行車店刷卡買一台 TCR1 ,而不會因為它的收單銀行是合庫就不准我刷卡。


然而我們的電信業者卻不是這樣想的。特約商店要收中華電信的用戶錢時,得去申請中華電信的小額付款服務,要收遠傳用戶的錢,得申請遠傳的,當然啦!你會說台灣就那麼三家大家的電信公司,都申傳了,特約商店就能收台灣人的錢。錯! 錯! 錯! 那佳樂福的手機用戶要抗議了,統一電信的用戶也會不爽。除了消費者的差別待遇外,這特約商店最困惱的還是每申請一家小額付款服務,就多一個帳務管理介面,及程式設計的工作,介面多了,管理成本自然提高,既然電信業者對特約商店不友善,那這個「小額付款」就成不了氣候。想想看如果信用卡特約商店全台灣就那麼 100 家,那消費者會去辦信用卡嗎? 辦了去那裡刷呀!


現實中,電信業者的合作早就不是問題,要不然中華電信用戶打電話給遠傳用戶時,電話會不通嗎! 不會呀! 它們早談好拆帳比例了,那為什麼不把這個合作模式放到金流上呢!特約商店只須申請一家電信業者的小額付款服務,消費者只要向他的電信業者申請開放小額付款功能,那須管他們是不是同一家電信業者呢!


甚至,跨國金流都可以一起搞定,現在隨便都可以打國際電話到美國吧!那我一樣可遵循此模式用讓美國客戶利用 Verizon 的小額付款功能,在我的網站上透過中華電信提供的小額付款網頁消費。由 Verizon 收款,然後再拆給中華電信。


跨電信公司收款,那信用違約怎麼辦! 首先信用違約的產生與同不同電信公司無關,是個人信用問題。在同一電信公司中,當消費者違約了,難道電信公司就可據此不撥款給特約商家嗎!如果一樣都要撥款,那在跨電信公司的案例中,消費者違約了,電信公司還是得撥款給收單的電信公司,而收單的電信公司一樣會撥給它的特約商家,這兩種情況中,吃虧都是消費者所屬的電信公司,然而它難辭其疚,是它的徵信能力不佳,給予不對的人,過高的信用,就像發卡銀行一樣,當持卡人擺爛了,吞下苦果的就是發卡銀行呀! 不會是收單銀行的問題。


總的來說,信用卡服務可廣泛使用,那電信小額付款沒理由不行,而我認為出問題的是電信公司對"小額付款服務"的用心程度不足。


與銀行經營信用卡業務相比,電信公司經營付款業務,只差在利息而已,銀行可對信用不佳的消費者收取較高的利率,但電信公司卻只能一視同仁,要計利息的話,也只能算存款利率。但這是沒辦法的事,只有銀行可以算利息。


不過最後這一點我不是很肯定,因為在一般人的借貸之間,是可以收取不同且比銀行存款利率還高的利息,那電信公司為什麼不能針對不同的人收取不同的利息呢?這我得再研究。


最後我期待國內的電信公司能早點合作,推出這種金融服務,一方面讓消費者多一種付款方式(通常此方式的最大收益者是學生,因為他們沒有信用卡),另一方面,則是電信服務在 NCC 的處處掣肘下,電信資費愈喊愈低,早點想點別的賺錢之術,要不然將來還有 VOIP 業者的競爭,我看會愈來愈難過。

Related Posts Plugin for WordPress, Blogger...