公告版位
我是公告

目前分類:電腦筆記 (47)

瀏覽方式: 標題列表 簡短摘要

這篇是當初 2008 年 3 月寫給 aokman 的,好像沒有貼在部落格上,我就把他從 aokman 的個版貼過來留個記錄好了


你的環島之旅,想要多詳細的記錄呢?
希不希望能夠有每天走的路線的完整記錄呢?

http://ronny.wang/blog/category/930494

大家可以看看我部落格裡面,每天走的彎彎曲曲的路線,我都有記錄起來
因此環島的記錄,不只是當天出發和終點的「地名」而已
連「路線」我都記的一清二楚
怎麼做到的呢? 來講一下故事吧

我是個工程師,對我來說記錄是很重要的
再加上我父母其實很擔心我的環島之旅
為了讓他們能夠放心,我跟他們保證我可以讓他們知道我即時的位置
而不是只有每天早晚的報平安電話而已

[GPS定位]

為了達到這個目標,首先我開始研究 GPS 衛星定位
我買了一個藍芽的太陽能 GPS 接收器(一台3000元)
充滿電的情況大概能用 6 個小時,精準度大概在 20~30m 左右

不過這只是純粹的接收器而已,拿在手上沒有任何功用,他沒有螢幕沒有畫面
他唯一的功能只是把你所在的座標位置用藍芽傳到你的籃芽設備上(Ex: PDA, 手機)
而我的手機在開藍芽跟這個接收器連線,大概三個小時就沒電了 Orz
所以這招就被捨棄了

所以使用 GPS 定位大概比較適合單車環島或是汽車環島
能夠隨時幫你的設備充電
徒步環島就不太可能了

正當我煩惱該用什麼方法定位時,結果給我在網路上查詢到 「窮人的定位方式」

[電線桿定位]

有空大家可以看一下電線桿上面的字,除了信耶穌得越南新娘以外
還有一個非常重要的資訊
上面有一串大概長的像 A1234 AB12 的字


PICT0109.JPG 

電線桿上寫著 K3082 AA90


PICT0101.JPG 

變電箱上寫著 G4431 CE38


這一串字,就是最好的定位方式
他是台電的定位系統,是台電在電線桿上標示這根電線桿所在位置的資訊
精準度到 10 公尺,比 GPS 定位還要更準喔!!

我大概講一下他的編碼的原理
台電將台灣每 80公里x50公里 切成一個區塊
每個區塊給了他 A ~ Z 的編號
切法如下圖


所以第一位英文字是用來表示是在哪個區塊裡面
以 K3082 AA90 為例
K3082 AA90 的數字要切成 [K][30][82] [A][A][9][0]
K 就是在雲林那一區
30 表示往東 800公尺,所以是往東加 30 x 800 = 24000m
82 表示往北 500公尺,所以是往北加 82 x 500 = 41000m
A 表示往東 100公尺,所以是往東加 0 x 100 = 0m  (A=0, B=1... H=7)
A 表示往北 100公尺,所以是往北加 0 x 100 = 0m  (A=0, B=1... E=5)
9 表示往東 10公尺,所以是往東加 9 x 10 = 90m
0 表示往北 10公尺,所以是往北加 0 x 10 = 0m
如果後面還有兩位的話,就是往東和往北加上1公尺,精準度更高


合計起來,這根 K3082 AA90 所在的位置就是在
K 區最西南方的那一點,然後往北 24090m,往東 41000m

如此一來,我們就得到了相當精準的位置...
所以我只要每五分鐘打電話跟我媽說
「媽,我看到電線桿上的座標是 K3082 AA90」
我媽就知道我在哪了!

如果下次誰被綁架時,不知道自己被綁到哪,
只要打電話去報警說你看到電線桿上的定位,警察就知道你在哪了!!
多麼好用的定位方式啊!!!

才怪.......我這樣跟我媽講我在哪我媽應該會殺了我吧 XD

所以這個定位方式只是我的輔助方式
我在環島的時候,辦了一隻 3G 上網的門號
然後寫了一個很簡單的網頁,樣子如下

input.jpg 

我只要用手機在 「電線桿座標」 那一欄打入 K3082 AA90 這一串字
然後按下 [送出查詢]
接下來就會我的主機上面就會記錄下來我在哪裡

我再弄了一個網頁像下面這樣 (已經找不到了q_q)
把這個網頁給我家人看就好了
之後我寫部落格文章寫遊記也是完全靠這個圖

這種定位方法很好吧!

成本只有
一隻能上網的手機和上網的費用
我是用遠傳的775元一個月吃到飽方案
而且遠傳可以申請只用一個月的門號
我那個門號在環完島之後就馬上拿去退掉了

不過電線桿定位也只適合徒步環島使用吧
像是騎單車環島的可能一騎就騎兩個小時不會停下來
這樣子根本沒空停下來看電線桿上面的代號吧
不像走路可以邊走邊慢慢用手機打字
我之後還是會研究用 GPS 自動五分鐘定位一次的方法

上面講的定位記錄方法雖然只有我一個人適用
但是我之後會寫一個網頁讓任何想要用電線桿定位的人都可以用手機記錄位置
如果有人急著想要這個功能的,可以寄信跟我說一聲
我會以最快的速度把這個功能完成 :)


榮尼王 發表在 痞客邦 留言(1) 人氣()

GitHub 在今年六月增加了 GeoJSON 的支援 可以直接預覽 GeoJSON
在八月則增加了 CSV 的預覽功能
以及在十月推出了 government.github.com 希望大家把各國政府資料往 GitHub 上丟
看的出來 GitHub 的野心不只是放在程式開發者身上,他也想成為資料的收集者

不過他的 GeoJSON 和 CSV 預覽功能因為是透過 JavaScript 在前端做的,因此有大小限制,超過大小就無法預覽了
只是地理資訊的部份,很多資料是很容易超過大小,為了讓 GitHub 能預覽而故意把精準度壓到很低其實也不是很好的方法
所以我做了一個工具,可以線上預覽超過 10MB 的 GeoJSON 和 CSV。
(不過超過 100MB 可能還是會失敗,畢竟 100MB 的 JSON 要 decode 有時候就會把記憶體吃光光了,這些就要額外再多做些處理)
這個工具在這邊 http://github.ronny.tw
只要進去首頁輸入你的 GitHub 檔案的位置,就可以預覽更大的 GeoJSON, TopoJSON 和 CSV ,甚至是 GeoJSON 和 CSV 的組合喔!
或者是在瀏覽 GitHub 檔案時,將網址的 https://github.com/ 改成 http://github.ronny.tw/ 也可以喔
下面來示範一下支援哪些類型吧!
文章標籤

榮尼王 發表在 痞客邦 留言(3) 人氣()

去年底第一次參加 g0v 黑客松我的作品就是選舉地圖 (2012/12/2 ,今天正好一年 XD)
把各村里投開票所藍綠的得票數配上村里界圖作出的地圖呈現
不過當初做這個有個很大的缺點,就是村里界圖是一個接近 3MB 的 GeoJSON,要 load 進瀏覽器來處理真的會耗掉很多資源
而且 3MB 已經是把精細度壓到很低了,應該是到十公尺以上的精細度了吧,原始資料是 60MB
像是 GitHub 最近有支援預覽 GeoJSON 的功能,也是在瀏覽器上直接計算,但是有 1MB 的限制,要不然真的會很慢又吃掉不少頻寬
所以最近幾個月我開始想要轉換作法,改成在 server 端作出圖片,然後疊在現有地圖的作法

新的成品就在 http://github.ronny.tw/ronnywang/sandbox/blob/master/20131126/2012-president-color.json
這邊是利用 Google Map Javascript API 的 ImageMapType ,他會把顯示出來的地圖上面,切成 256px * 256px 的 tile(大小可自行設定) ,使用者捲到哪裡,API 就自動去呼叫 getTileURL 要去畫出哪些 tile
而 getTileURL 裡面的參數 coord 就可以取出這個 tile 的左上和右下的經緯度分別是多少,所以後端伺服器只要畫出這一塊區域的圖型就行了

我目前寫出來的一個 Tile 的 PNG 依複雜度會是 1kb ~ 50kb 不等(看上面的資訊量)
圖片長的會像下面一樣


網址:d4ru4jg0u8swg.cloudfront.net/wms?Request=GetMap&Layers={"type"%3A"colormap"%2C"set_id"%3A27%2C"tab"%3A"\u85cd\u7da0\u5730\u5716"}&BBox=119.9267578125,23.32208001137843,121.025390625,24.32707654001865&Width=400&height=400

一個 Tile 就會如上,從網址看的出來是要畫出經緯度界於 (119.926E, 23.322N) 到 (121.025E, 24.327N) 之間的資訊,並輸出成 400x400 的圖檔
改用 Tile 真的也能省下不少頻寬,想想看原先 60MB 的 GeoJSON 省下來,就足以傳超過一萬張 tile 的圖片了
再加上 Tile 圖片可以過 CDN cache 起來,這樣子後端 server 就可以很閒只要畫一次就好了

而完成這功能的最主要核心有兩個,一個是透過 PostgreSQL 的 PostGIS 如何快速取得需要的經緯度之間的資訊,以及如何把這些資訊畫成 PNG 傳回來
前者我之後會再找時間寫成文章
後者的話我已經把程式 open source 在 GitHub: https://github.com/ronnywang/geojson2image
只要丟一個 GeoJSON 進去就可以輸入 PNG
唯一用到的函式庫是 PHP-GD
詳細用法我就不在這邊說明了,有興趣的人就翻 GitHub repository 內的說明吧

為了做到這件事我遇到一些問題並且解決掉
遇到的問題包括
1. 地球是圓的
我最早的作法是假如要把 (119.926E, 23.322N) 到 (121.025E, 24.327N) 之間的資訊畫到 400x400 的圖檔上去
就表示目標圖檔的 1 個 pixel 會是 (121.025-119.926)/400 和 (24.327-23.322)/400 的資訊
這作法如果只處理台灣的話沒什麼問題
但是當一處理到世界地圖時就爛掉了
(為什麼地球要是圓的啦~是平的有多好!)

原因是在不同緯度,每1經度的寬度都是不一樣的,像是赤道上的1經度是最大的,而極點上的1經度就是接近0
解決辦法就是要加上 sin, cos 來計算了
這應該是高中三角函數的程度,但是脫離學校太久我已經懶得計算這些 XD
所以直接找有沒有 code sample ,找到了一篇Bing Maps Tile System 裡面有(謝謝微軟 Q_Q)
就解決這個問題了

2. 經度是有可能 +180 跨到 -180 的
如果沒處理到這個問題的話,就會發生明明座標是 +179E => -179W 只走 2 個經度,圖卻畫成走了 358 個經度
這邊我的解決方式是先把經度都加上 180 ,讓他座標系從 -180 => 180 變成 0 => 360 比較好計算
然後如果遇到需要畫的區間經度是在 +XXX 到 -YYY 的話
我就把他分成 +XXX ~ +180 和 -180 ~ -YYY 兩張圖再組合在一起
就解決跨經度的問題了

GeoJSON2Image 這個 PHP class 寫法滿單純的,沒用到太多 PHP 的奇技淫巧,大部份都是 foreach 加上四則運算
所以也歡迎轉換成其他語言喔!

榮尼王 發表在 痞客邦 留言(0) 人氣()

前幾天建了一個 GitHub repository: https://github.com/ronnywang/data.taipei.gov.tw/
裡面把一些臺北市政府資料開放平台的地理相關資料,從原先的 ShapeFile 轉換成 GeoJSON,包括 Big5 的也轉成 UTF-8 了,座標也都統一換成經緯度
列表在 https://github.com/ronnywang/data.taipei.gov.tw/blob/master/geo.csv

GitHub 因為現在有內建 GeoJSON 預覽功能,所以有一些資料就可以直接看了
像是 臺北都會區大眾捷運系統路網圖, 臺北都會區大眾捷運系統車站點位圖, 大臺北地區捷運車站出入口

完整列表可以到
http://ronnywang.github.io/data.taipei.gov.tw/index.html 查看

不過我也沒有轉換全部的資料,如果有需要的資料沒有轉換的,可以有以下選擇:
1. 自行 fork http://github.com/ronnywang/data.taipei.gov.tw/ ,更新 geo.csv (不需要填入更新時間) ,跑一遍 scripts/geo_update.php (需安裝 PHP, PHP-Curl, NodeJS) ,就會轉換好資料並且更新 geo.csv 的更新時間
記得要送 pull request 給我讓我也更新一下喔
2. 送 issue 給我,如果我有空的話也可以幫你抓一下

希望這些資料能夠讓大家更容易使用,這樣才能展現 open data 的力量!

榮尼王 發表在 痞客邦 留言(0) 人氣()

其實地球上根本就不該存在 Big5 JSON 這種東西
RFC 4627 有提到: JSON text SHALL be encoded in Unicode.
所以像是 PHP 在 json_decode 時,如果遇到非 UTF-8 字元,就會直接噴 NULL 給你,並且跳出 「Malformed UTF-8 characters, possibly incorrectly encoded」,連用都不給你

但是假如很不幸的,就真的拿到了一個 Big5 JSON 怎麼辦?
例如像我現在要用 ogr2ogr 把政府 open data 的資料轉成 GeoJSON ,結果因為他的內容是 Big5 ,產生出來就是 Big5 JSON 了
直接用 iconv 轉,就死在台北市內湖區成功路了

昨天找到一個解決方法是

1. env LC_CTYPE=c sed -i 's/[\x81-\xFE]\\\)\\/\1/g' {big5_file.json}
(如果 LC_CTYPE 預設是 UTF-8 的話,就會在 \x81 這邊出現錯誤,所以改成 c 讓他可以處理任何 binary)
2. iconv -f big5 -t utf-8 {big5_file.json}

因為 Big5 的 SPEC 有說雙位元字的第一個位元會是 0x81 - 0xfe 之間 ,所以只要針對 [0x81-0xfe] 和 \\ 連在一起的替換成只有一個 \ 就行了
這樣子許功蓋都可以解決了

(都已經快 2014 年了,還要處理 Big5 問題...)

榮尼王 發表在 痞客邦 留言(0) 人氣()

N5001UWKAP  

求職小幫手也有 WebApp 版本了,用手機也可以使用求職小幫手囉!
網址是 http://jobhelper.g0v.ronny.tw/mobile ,或者可以掃描上面的二維條碼直接進入喔

感謝 nansenat16 花時間製作,nansenat16 也有把他 open source 在 GitHub
另外 nansenat16 也有製作 Android App 在 Google Play ,真的是太感謝了!

因為我只有 iPhone ,我這邊先教一下怎麼在 iPhone 把他作成 WebApp 的方式

1. 先用 iPhone 瀏覽器開 http://jobhelper.g0v.ronny.tw/mobile ,可使用上面的 QRCode,畫面如下:

IMG_2484  
  

2. 點選最下面一排的中間的按鈕

skitch_iphoto.export.skitch 2  

3. 進到動作選單之後,往右拉

skitch_iphoto.export.skitch  

4. 看到求職小幫手圖示和「加入主畫面」了吧,按下去吧

skitch_iphoto.export.skitch 3  

5. 選擇一個你想要的顯示名稱,並且按下新增

4  

6. 成功囉!以後就可以直接使用了!

5  

祝大家使用的開心,並且找到一份好的工作!

文章標籤

榮尼王 發表在 痞客邦 留言(1) 人氣()

投影片放在 slideshare

http://www.slideshare.net/ronnywang_tw/2012-php-conf-slide-pixnet-php-15004028

榮尼王 發表在 痞客邦 留言(0) 人氣()

我寫了一個 Heroku 上跑的 IRC 留言機器人
放在 https://github.com/ronnywang/heroku-ircbot

只要照著 github 內下面的 README 指示,不需要改任何程式也不需要花半毛錢
就可以在 Heroku 上面建立起一個 IRC 留言機器人了
之後只要用 HTTP GET 就可以直接在 IRC 上面留言了

像是 PIXNET 現在內部會把很多系統異狀透過機器人到 IRC 上面回報,PIXNET 的 RD 只要看 IRC 就可以知道系統狀況,不需要一台一台機器來看了。
IRC 是很方便的工具。

榮尼王 發表在 痞客邦 留言(0) 人氣()

PHP 有個 is_a ,主要功用是看某個物件是否是哪一個 class

doc: http://tw.php.net/manual/en/function.is-subclass-of.php

參數
PHP 4.2 以後
bool is_a ( object $object , string $class_name )
PHP 5.3.9 以後
bool is_a ( object $object , string $class_name [, bool $allow_string = FALSE ] )

這個 function 一年來改了兩次啊
在 PHP 5.3.7 以前,第一個參數只能是 object ,因此只要丟了 string 進去, is_a() 就一定回傳 false,如果你有丟 string 的需求,必需要改用 is_subclass_of()
在 2011/8/18 出來的 PHP 5.3.7 加上了第一個參數是 string 的支援,並且會 autoload 該 class 再來做 is_a() 的判斷。如此一來遇到的問題就是如果你有 spl_autoload_register() ,可能會因為第一個字串是不存在的 class 而狂噴 Warning
在 2012/1/10 出來的 PHP 5.3.9 又增加了第三個參數,要給 true 才會 autoload 該 class ,如果給 false 並且第一個參數是字串的話,則這個 function 只會 return false

等於這三次情況預設行為被改了兩次了

如果之前用法是第一個參數是 object 的寫法的話,恭喜你,完全沒有任何改變 (不過因為他的行為跟 instanceof 一模一樣,因此在 PHP 5.0.0 曾被標為 deprecated 過)
但是如果你的需求是判斷該 class name A(string) is a class name B(string)
在 PHP 5.3.7 之前的 is_a() 做不到
PHP 5.3.7 ~ 5.3.9 突然可以做到,而且還關不掉
PHP 5.3.9 以後又預設變成做不到,第三個參數要加 true 才做的到。

所以如果你想要寫一個 PHP 5.0 以後都可以使用的 is_a() 判斷的話
比較保險是改用 is_subclass_of() ,不過 is_a('ObjectFoo', 'ObjectFoo'); 是 true , is_subclass_of('ObjectFoo', 'ObjectFoo'); 是 false
這個需要注意

(今天踩到的雷,特此記錄一下..測試環境和線上環境的 PHP 版本還是要一樣比較好啊)
文章標籤

榮尼王 發表在 痞客邦 留言(0) 人氣()

大概記錄一下需要什麼樣的流程,因為 yum 裡面沒有

1. 先在機器上裝需要的 library 以及 tool
> sudo yum install gcc-c++ openssl-devel make

2. 下載 node-js 最新的 source ,可以到 http://nodejs.org/ 找。
> wget 'http://nodejs.org/dist/node-v0.4.7.tar.gz'
> tar zxf node-v0.4.7.tar.gz
> cd node-v0.4.7
> ./configure
> make
> sudo make install
安裝完成!

3. 來個 hello world 測試一下吧,把 http://nodejs.org/ 首頁的範例拿來用
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/');
把他存入 example.js
> node example.js &
Server running at http://127.0.0.1:1337/
> GET http://127.0.0.1:1337/
Hello World
>
成功啦!

再來用 sudo yum install httpd 裝個 httpd ,不過只是為了用裡面 ab 來測測看效能而已。
> ab -n 1000 -c 10 http://127.0.0.1:1337/
Requests per second: 4199.62 [#/sec] (mean)
Time per request: 2.381 [ms] (mean)
Time per request: 0.238 [ms] (mean, across all concurrent requests)

超級快的, 4000qps 耶~

榮尼王 發表在 痞客邦 留言(0) 人氣()

PHP 有一系列的 Multibyte String Functions ,很適合拿來處理 CJK 這些 Mutilbyte 字元
其中在切字串的部分就有三個不同的 function 可以用
分別是 mb_strcut, mb_substr, mb_strimwidth

mb_strcut($str, $start, $length, $charset); 所切出來的字串,是 byte 數不超過 $length 的字串,所以像是
mb_strcut('我是ronnywang', 0, 8, 'UTF-8'); 出來的就是 「我是ro」
適合用在所儲存的地方空間有限時,確保所占空間不要超過某個數字,但是又不要把 multibyte 字腰斬所使用。

mb_substr($str, $start, $length, $charset); 所切出來的字串,是總字數不超過 $length 的字串,其中中文和英文都分別算是一個字元,所以像是
mb_substr('我是ronnywang', 0, 5, 'UTF-8'); 出來的就是 「我是ron」 (總共四個字)

mb_strimwidth($str, $start, $width, $trimmarker, $charset); 所切出來的字串,是總長度不超過 $width 的字串,另外如果字需要被切到的話,還會幫你補上 $trimmarker (加上 $trimmarker 之後也不會超過 $width) ,而長度的部分,是以半形字是 1 全形字是 2 來計算,因此跟實際顯示出來的寬度會差不了多少。
像是
mb_strimwidth('我是ronnywang', 0, 9, '...', 'UTF-8'); 出來的就是 「我是ro...」 (寬度為 9)
mb_strimwidth('我是', 0, 9, '...', 'UTF-8'); 出來的就是 「我是」(寬度為4,小於 $width 就不會印出 ... 了)
mb_strimwidth('我是ronny', 0, 9, '...', 'UTF-8'); 出來的就是 「我是ronny」(寬度為9,剛好等於 $width 也不會印 ...)
適合用在要顯示一些固定長度的文字使用。

另外還有幾個取得長度的方式

strlen($str); 最原始的,取得就是 byte 數,像是
strlen('我是誰'); 在 UTF-8 就是 9 ,一個字 3 bytes 。

mb_strlen($str, $charset); 出來的是字數,像是
mb_strlen('我是誰', 'UTF-8') 是 3
mb_strlen('我是ronny', 'UTF-8') 是 7

mb_strwidth($str, $charset); 出來的是寬度,一樣是半形字算 1 ,全形字算 2
mb_strwidth('我是誰', 'UTF-8') 是 6
mb_strwidth('我是ronny', 'UTF-8') 是 9

依照不同需求就使用不同函式囉。

榮尼王 發表在 痞客邦 留言(1) 人氣()

javascript 的 location 有兩種跳頁的方法。
location.assign(url);
location.replace(url);

其中 location.assign(url); 跟 location = url; 或是 location.href = url; 功用是一樣的。

那麼 assign 和 replace 有什麼差別呢?

我在 pagea.html 跑了 assign('pageb.html'); 的話,在 pageb 按 browser 的上一頁,會回到 pagea.html,在 pagea.html 按下一頁會回到 pageb.html
但是如果我跑的是 replace('pageb.html'); 的話,上一頁會回到 pagea.html 的上一頁。下一頁的話會跑到 pageb.html 。也就是 pagea.html 被取代掉了無法用上一頁下一頁回到他那邊。

而如果要作重新整理的話
有 location.reload() 可以使用
不建議使用 location = location; ,在網址包含 # 的時候這樣重新整理會失效。

location.reload() 裡面也可以傳入 true or false 的參數(預數為 false)
如果選擇了 location.reload(true); 的話,會加上 Cache-Control no-cache 的 header ,也就是強制去 GET 一次,否則的話就會依照之前的 Cache-Control 去 GET。
有點相當於 F5 和 Ctrl+F5 的差別。

另外值得注意的是 location.hash 的部分。
當現在的網址是 http://ronny.tw/#abc 的時候, location.hash 可以取得 #abc (最左邊一定是 # 開頭)
如果跑了 location.hash='def'; ,網址會變成 http://ronny.tw/#def

在 http://ronny.tw/#abc 的情況下,以下動作都不會重新整理頁面。
location = 'http://ronny.tw/#def';
location = '#def';
location.hash = 'def'
location.hash = '#def'
location = '/#def';
location = location; // 所以有些人用 location = location 來作 reload 動作,在包含 # 的時候會失效
location.assign('#def');
location.replace('#def');

要注意的是,在 http://ronny.tw/#abc 的情況下
location = 'http://ronny.tw/'; 是會重新整理的。
所以在網址已經包含 # 的情況下,是無法作到在不重新整理頁面的情況下把 # 拿掉的。
另外 location.href 是包含 '#' 的網址

location object 內並沒有不包含 # 的完整網址的 property 可以用
所以要取得不包含 # 的完整網址的話,有以下方法
location.href.split('#', 2)[0]
location.protocol + '//' + location.host + location.pathname + location.search

不過如果要跳到沒有 # 的頁面去的話,只需要用 location = location.pathname + location.search 就夠了。

再來一個要注意的
在萬惡的 IE 中
如果你的網址中包含 # 的話
location.reload() 並不會跳到 # 的位置,而是會跳到最上頭。
所以如果你會 care 這點的話,必需要在 reload() 之後再補上一次 location = location; 才會跳到 # 的位置。

另外,在修改或加上 # 的東西的話,會觸發 hashchange 事件
因此可以用 jQuery(window).bind('hashchange', function(){ // ... }); 去補捉 hash change 事件
(IE 是到 IE8 才支援的,IE7 之前是抓不到的)

榮尼王 發表在 痞客邦 留言(0) 人氣()

PHP 5.3 加上了 get_called_class() 這個 function,使得 Rails 上面的 ActiveRecord 在 PHP 的實作成為可行。過去的 PHP 假如遇到了


class Foo
{
public static function bar(){
// ...
}
}

class FooA extends Foo
{
}



這樣子的 code ,在 5.2 以前用 Foo::bar(); 和 FooA::bar(); 是完全無法分辨 bar() 是被 Foo 還是被 FooA 呼叫的。
因此像是 ActiveRecord 的 User::search(1), Comment::find(2) 這種寫法,在 PHP 5.2 完全作不到,除非在 extends 之後還要再自己 implements 一次 find, search 這些 method。

但是 PHP 5.3 增加了 get_called_class() 之後讓一切變的可行了。

我可以在 bar() 裡面呼叫 echo get_called_class()
這樣子 Foo::bar(); 時會印出 Foo, FooA::bar(); 時會印出 FooA
等於我就可以抓出是哪一個 class 呼叫這個 method 了。

而 PHP 5.3 也增加了 __callStatic() 這個 magic method,讓 Foo::any_method() 也可以被使用
使得 PHP 5.3 的彈性大大的增加了。

不過今天在寫 PHP 5.3 程式時,倒是遇到一個靈異現象。


class Test
{
public function test()
{
Foo::bar();
}
}

class Foo
{
public function bar()
{
echo get_called_class();
var_dump($this);
}
}

$test = new Test();



本來預期 echo 的應該是 Foo 這個 class ,沒想到卻出來的是出人意料的 Test 這個 class 。
連下面的 var_dump($this) 都是顯示 Test Object 。

查了一下才知道,在這邊 static 這個 keyword 就很重要了。
如果改成 public static function bar() ,一切就有如預期了
echo 出的 class name 是 Foo ,而且下面 var_dump($this) 是印出 NULL 。

所以使用上要注意,有使用 get_called_class() 的 function ,一定要是 static function ,不然很容易遇到靈異現象。(其實 PHP document 上也寫了這個 function 功用是 「Gets the name of the class the static method is called in. 」,如果不加上 static 造成錯誤的確也是 programmer 的問題啊。

每次看到靈異現象都會讓我想起一句很有道理的話,「程式不會照你所想的跑,只會照你所寫的跑。」

榮尼王 發表在 痞客邦 留言(0) 人氣()

memcache 1.4.4 修改了 delete 的 syntax
從 delete $key [$time] [noreply]\r\n 改成了 delete $key [noreply]\r\n

造成在 pecl-memcache 3.0.4 版以前可能會有 delete 失敗造成後面 memcache 程式都不正常的問題。


暫時的解決方法是在使用 delete 的時候,後面 timeout 的參數原來可以不指定的,現在要改成一定要指定 0。

$memcache->delete($key) 要改成 $memcache->delete($key, 0);

這樣子才可以正常運作。

(這幾天踩到的地雷啊。)


榮尼王 發表在 痞客邦 留言(0) 人氣()

好久沒寫部落格了,身為工程師的我,不寫些跟技術相關的文章好像說不過去。
我就拿這一年來使用 MySQL 的經驗來寫一篇 DRBDMMM  的使用心得吧。

榮尼王 發表在 痞客邦 留言(5) 人氣()

我老爸在 eeepc 剛推出時就想要買一台 eeepc 來用,因為看中了他的便利性小巧方驗攜帶,不過因為家裡買電腦都是透過我來買,在我沒確定 OK 時是不會貿然買下去的,也感謝這次廠商提供了試用的機會,讓我和我爸能夠實際使用一次。

eeepc 真的很小巧,對女生來說幾乎可以塞進隨身的小包包中,而不用為了帶一台筆電出門而帶著一個沒質感的電腦包。而且 eeepc 的外表真的相當有質感,光亮的鋼琴面版一拿出來就會吸引到他人的目光,雖然說很容易就沾滿了指紋,需要再隨身攜帶擦拭布,不過戴眼鏡時不是也一樣很容易沾到油和指紋嗎?眼鏡都可以帶著眼鏡布擦拭了用 NB 不是一樣嗎?

eeepc 還附有 130 萬像素的 webcam 功能,很適合跟別人用 skype 視訊對談,如果沒戴鏡子的話,拿 eeepc 來代替鏡子整理儀容也不錯啊 XD ,不過要習慣左右會相反。另外他的 DOLBY 音響也真的是我用過的 NB 中音質最好的,之前我只要拿我的 NB 的喇叭來播音樂就一定會被人念說趕快關掉 XD。 以下附圖是 eeepc 的 webcam 畫面。

我和小豬在 eeepc 視訊前的合照!

我想 eeepc 也很適合給常常南北跑的學生或上班族使用,號稱八小時的續航力(不過這八小時是在使用文書處理或是上上網頁這種比較不耗 CPU 資源的動作,如果是播放XVid 影音大概就只能撐五六個小時了,只是對於從台南坐到台北就算是坐客運五六個小時也夠用了吧),在上客運前帶個兩三部電影,客運上一路向北的旅程就不會無聊了,而且使用 SSD 硬碟的 eeepc 完全不用 care 防振問題,客運就算遇到顛簸甩尾都不會影響到 eeepc 的運作。內建藍牙的 eeepc 也可以跟 3.5G 手機連結,只要有手機訊號的地方就可以上網。

不過 eeepc 也有些缺點,他的按鍵比較小(這點是無解的問題吧,尺寸小的 NB 鍵盤一定也會相對小,除非之後能推出折疊式鍵盤),尤其他的波浪鍵被移到了 ESC 和 F1 中間之後,感覺數字鍵向左平移了一格,造成數字常常容易打錯。觸碰板的操作也沒有相當順手,可能還需要一段時間來習慣吧。

用 eeepc 玩 Typing of the Dead ! 一個最適合用來測試鍵盤好用度的遊戲!

 另外內建的 10G 硬碟在裝完 Windows 和 Office 之後也沒剩多少,額外再添購硬碟空間也是相當重要的吧,除非你想要在使用 eeepc 的過程中,體驗到空間規劃的重要性。

對於日常工作使用上 eeepc 也許比較不適合吧,尤其是手掌比較大的男生(也許對擁有纖細的手指的女生來說比較適合吧),不過對於通勤時尋找娛樂,或是隨身攜帶以備不時之需來講, eeepc 真的是不錯的選擇。

榮尼王 發表在 痞客邦 留言(6) 人氣()

SyncML 是一個現在大部分新手機都支援的功能
而下個月起在 GMail Contacts 要支援這功能了
到時候可以直接用上網手機跟 GMail 同步聯絡人資料了
以後要管理手機通訊錄就更方便了!!!

消息來源:Gmail and Google Calendar to Add Offline Support

希望之後也會出現 Google Calendar 的 SyncML 支援
可以直接即時更新手機裡面的通訊錄功能~
之前是有個網站叫 GooSync 有提供這功能,問題是你必需要把 Google Calendar 的權限開給他,讓他把你的 Calendar 資料抓下來才能夠使用
感覺隱私都在他手上很不舒服 (不過隱私在Google那邊好像也差不多的樣子)
如果 Google 能夠自己推出 SyncML 功能就太好了!

榮尼王 發表在 痞客邦 留言(0) 人氣()

來點技術性文章
證明我腦子還是行的吧

PHP 有一些 interface ,在寫 class 時非常好用,只是在 php.net 裡面很難找到哪裡有寫
我來列舉一下

interface Iterator {
    public function rewind( );
    public function current( );
    public function key( );
    public function next( );
    public function valid( );
}

implements Iterator 的 class 可以被直接拿來 foreach ( $obj as $key => $value ) { ... } 使用
相當於
for ( $obj->rewind( ); $obj->valid( ); $obj->next( ) ) {
  $key = $obj->key( );
  $value = $obj->current( );
}

===========================
interface IteratorAggregate {
  public function getIterator( );
}
implements IteratorAggregate 的 class 也可以直接拿來 foreach ($obj as $key => $value) { ... } 使用
相當於
foreach ($obj->getIterator( ) as $key => $value ) { ... }

===========================
interface Countable {
    public function count( );
}

implements Countable 的 class 可以直接拿來 count( $obj ); ,相當於 $obj->count( );
===========================
interface SeekableIterator {
   public function rewind( );
    public function current( );
    public function key( );
    public function next( );
    public function valid( );
    public function seek( $pos );
}

implements SeekableIterator 的 class 除了可以被直接拿來 foreach ( $obj as $key => $value ) { ... } 使用 以外,還可以用  $obj->seek($pos) 去取得他的值
(不能用 $obj[$pos] 去取喔,要用 $obj[$pos] 必需要 implements ArrayAccess)
===========================
interface ArrayAccess {
    offsetExists ($offset)
    offsetGet ($offset)
    offsetSet ($offset, $value)
    offsetUnset ($offset)
}

implements ArrayAccess 的 class 可以被當作 Array 使用
Ex: isset( $obj[$i] )   ==> $obj->offsetExists($i);
      $a = $obj[$i] ====>  $a = $obj->offsetGet($i);
      $obj[$i] = $value;  ===> $obj->offsetSet($i, $value);
      $obj[ ] = $value ===> $obj->offsetSet(NULL, $value);
      unset($obj[$i]) ==> $obj->offsetUnset($i);

如果想要 count($obj) 就要再 implements Countable
==========================
interface Serializable {
    public function serialize( );
    public function unserialize( $serialized )
}

implements Serializable 的 class 你可以去 serialize 他
$word = serialize( $obj );   ==> $word = $obj->serialize( );
另外,他會自動把你的 ->serialize( ) 傳出來的 serialize 文字外面再包一層
C:X:"你的Class Name":XX: { 你的 Serialize 內容 }
所以你直接 unserialize( 這個字串 ); 他就會知道要去呼叫哪一個 class 的 unserialize

榮尼王 發表在 痞客邦 留言(1) 人氣()

在 java 有個函式是 equals
功用是可以 overloading  == 這個 operater 的意義
因為有時候兩個 object 是用不同方式產生的,但是他們代表的是相同的東西
如果直接對兩個 object 用 == 做,會回傳 false ,原因是 reference 不同
overload equals 的話就可以讓 java 用你所自訂的方法判斷到底是不是相同的東西

最近寫 PHP 寫很多...
也開始在寫 PHP 的 OOP
也遇到了需要 overload equals 的需求
PHP 裡面習慣上這種功能應該會放在 Magic Methods 裡面
像是 __construct, __destruct, __toString, __get, __set, __isset ...
我就想找有沒有 __equals 這個東西
結果找到一篇 php.net 上面的回應

http://bugs.php.net/bug.php?id=25772
[15 Apr 2004 3:29am UTC] derick@php.net
We're not going to have more magic then there already is; those things
are going to be to complicated and confusing (See the __string()) issue.


不知道來自 derick@php.net 算不算官方回應啊 @_@
只是都已經 2004 年了,當初這樣說不代表現在也是如此吧?

另外我在 php.net 上面對於 Comparing objects 裡面
看到他寫 $object1 == $object2 的實作方式是檢查裡面所有的 variable 是否相同,並且是否是同一個 instance..
真是超沒效率的方法啊
就有人說下面這程式會造成 php 當掉
ronnywang@ronny [/tmp] [16:56/W10] cat test.php
<?php
class Foo {
    public $x;
}
$a = new Foo();
$b = new Foo();
$a->x = $b;
$b->x = $a;

print_r($a == $b);
ronnywang@ronny [/tmp] [16:56/W10] php test.php
PHP Fatal error:  Nesting level too deep - recursive dependency? in /tmp/test.php on line 10

因為他會 recursive 去檢查是不是每個 variable 都一樣...
這樣子 PHP 太遜了啦...
萬一我程式寫法是

class 人類{
  public $配偶;
}
$a = new 人類();
$b = new 人類();
$a->配偶 = $b;
$b->配偶 = $a;

print_r($a == $b);

這樣子觀念完全沒有問題的程式在 PHP 就會 Fatal error 了

PHP 趕快增加  __equals 吧!

榮尼王 發表在 痞客邦 留言(0) 人氣()

之前寫了篇文章評比了幾個之前用過的 MSN library ,沒有一個完全符合我的需求
不是不支援個人頭像,不支援個人訊息,甚至還有不支援更改暱稱的...
抱持著求人不如求己的心態
我看了幾個在講 MSN protocol 的網頁,終於自己刻出一隻可以
「更改個人頭像」、「變更個人訊息」、「傳送接收檔案」的 MSN library...
傳送接收檔案也可以使用 P2P 傳檔,不需要透過 MSN server 浪費一段時間

不過目前還在繼續改進中,等到之後穩定下來後我就 open source 出來吧!

榮尼王 發表在 痞客邦 留言(1) 人氣()

1 23