2012/12/27

宜蘭拜訪神秘海灘

自從用了 Evernote,我的生活變得更輕鬆了,像是旅遊規劃就非常適合,先在電腦上編輯,把火車時刻表,景點、美食搭配 google map 快照,記事本就像旅遊指南,搭配 iPhone 的行動版 Evernote,暢行無阻呀!


宜蘭是我一直想來的地方,這次我試著一個人旅行,從台北搭著慢車,來到外澳車站。
走出車站,跨越一條馬路就來到海邊了,從來不知道有這麼愜意的地方,很久沒看海了整個心都開闊起來

海岸對面就是龜山島


沿著海灘一路往南走,真的蠻漂亮的

映著湖面的蘭陽博物館 是那麼美

沿途還會經過伯朗咖啡服務區,可以停留拍個照

來到頭城車站 從外澳走過來約2公里多
停留了一會 吃個小吃 看看老式的街道


搭上火車來到南澳 準備尋找神秘海灘 是這次來的目的



沒有交通工具 只能靠兩條腿啦
走過海岸大橋 神秘海灘就在出海口右手邊的方向
沿途上還有小黑跟小黃陪伴

就是這邊了吧 佈滿礫岩的海灘
沿著海岸往南走 尋找海蝕洞
陡峭的山壁 上面就是蘇花公路


就是這邊了 海蝕洞
GPS: N24'24'43' E121'47'30''
大浪侵蝕的力量果然果然很驚人

從南澳車站走到海蝕洞要 7 公里,建議還是用開車的
從『旅人Carrie愛漫遊 』得知,最大的海蝕洞有20公尺高,要沿海岸走4.3公里
只能下次再來拜訪了,還有一個湧泉湖這次也沒找到 :P

另外要注意一下季節的潮汐 如果漲潮太高通行就會有困難

2012/10/23

PhoneGap - Cross platform solution for mobile app - Hello world

跨平台的 mobile solution 越來越多種, google 一下就可以找到人家推薦或比較的文章:



其實大部分都是用純網頁的方式來開發:HTML5 + Javascript,好像只有 Titanium 會把 project 轉成 native code 再編譯,而 PhoneGap 則是為每個平台開發了 framework,提供存取硬體資源的界面,而 UI 層一樣用網頁的方式呈現。
效能理論上是 native code 好些,但目前我的需求在於呈現一些靜態的資料,不需要大量的運算或是圖形成像,選擇了 Phonegap + jQuery mobile 來玩玩看。



下列記錄一個專案產生及編譯的過程:

2.1.0 版 (目前最新版)

1. 安裝方式跟以往不同,沒有 dmg 檔,改採 command line 的方式,可以先看一下官網的 Getting Started with iOS,整理步驟如下:
  • 安裝 Xcode Command Line Tools
  • 下載 cordova source,並解壓縮
  • 進到目錄裡執行下列 script,創建 iOS 專案
$ cd ./phonegap-phonegap-26d211b/lib/ios/bin
$ ./create ~/my-phonegap com.phonegap my-phonegap
$ ./update_cordova_subproject ~/my-phonegap/my-phonegap.xcodeproj/

2. 編譯
開啟剛剛產生出來的 xcode project,從圖中可以看到裡面還包含 CordovaLib,先編譯 CordovaLib 再編譯自己的專案

順利的話就會 deploy 到模擬器上了

註:預設是把 ARC 打開的,所以如果 target iphone 上面沒有支援,就會有下面的錯誤發生。Disable ARC 不是一個好方法,如果有需要可以使用舊版的 library。
dyld: lazy symbol binding failed: Symbol not found: _objc_retain
  Referenced from: /var/mobile/Applications/81EB9778-1819-454F-BF09-5D7CA2706A1A/phonegap.app/phonegap
  Expected in: /usr/lib/libobjc.A.dylib
dyld: lazy symbol binding failed: Symbol not found: _objc_storeStrong
  Referenced from: /var/mobile/Applications/81EB9778-1819-454F-BF09-5D7CA2706A1A/phonegap.app/phonegap
  Expected in: /usr/lib/libobjc.A.dylib

3. 再來就可以參考 API 去撰寫自己的 app 了,資料放在 www 這 folder 底下即可



1.8.0 版

1. 下載 source 後直接執行 phonegap-phonegap-2b7ffca/lib/ios/Cordova-1.8.0.dmg 

2. 安裝後開啓 xcode 就可以看到 Cordova-based Application 的專案可以新增

3. 編譯並執行

出現了錯誤?
ERROR: Start Page at 'www/index.html' was not found
原來是 www 加進專案的方式有問題,正確的步驟如下:在專案按右建選擇"Add file to (project name)",選擇 www 資料夾,並勾選 "Copy items into destination group's" folder (if needed)",Folders 選擇 "Create folder references for any added folders"

再編譯一次就沒有問題了!

2012/08/26

Nginx load balance

Nginx 內建的 load balance 規則有 round-robin、weight、ip_hash、fair、url_hash
但如果想更精確的把特定 request 導到特定的 server,可以自己來寫 rule。

例如想用 user id 做 despatch,下面的例子是利用 user id 的開頭第一個字元來做決定
server {
    listen 80;
    server_name www.domain.com;

    location ~* /profile/[a-m] {
        proxy_pass http://server0.domain.com;
    }

    location ~* /profile/[n-z] {
        proxy_pass http://server1.domain.com;
    }    
}

如此一來
http://www.domain.com/brian 就會導向 server0
http://www.domain.com/vicky 就會導向 server1



如果 user id 是流水號,那我們就判斷 id 的個位數字
server {
    listen 80;
    server_name www.domain.com;

    location ~* /profile/[0-9]*[02468]$ {
        proxy_read_timeout 10s;
        proxy_pass http://server0.domain.com;
    }

    location ~* /profile/[0-9]*[13579]$ {
        proxy_pass http://server1.domain.com;
    }
}

http://www.domain.com/2000 就會導向 server0
http://www.domain.com/2001 就會導向 server1



如果 request 是 http long polling,可以考慮用301 Moved Permanently 的方式讓 client 的 connection keep 在 target server,減少 nginx 的 connection 數量
server {
    listen 80;
    server_name www.my-domain.com;

    location ~* /profile/[a-m] {
        rewrite ^(.*) http://server0.domain.com$1 permanent;
    }

    location ~* /profile/[n-z] {
        rewrite ^(.*) http://server1.domain.com$1 permanent;
    }    
}

有關 location rule 可以參考:高飞鸟 – Highbird » Blog Archive » Nginx的location匹配规则

2012/08/22

在 iOS 平台加入 Flurry 廣告

Flurry

1. 註冊後,新增 Application,把 API Key 記下來

2. 建立 Ad space


3. 開始寫程式,先下載 SDK,裡面包含教學pdf 與 library
把 Flurry, FlurryAds 拖曳到 project 內

4. 在 app launch 的時候去初始化 flurry
AppDelegate.m
#import "Flurry.h"
#import "FlurryAds.h"

- (void)applicationDidFinishLaunching:(UIApplication *)application
{
    [Flurry startSession:@"YOUR_API_KEY"];
    [FlurryAds initialize:rvc];
}

5. 在想呈現廣告的 viewController 加入程式碼
ViewController.m
#import "FlurryAds.h"

- (void)viewWillAppear:(BOOL)animated
{
    [FlurryAds isAdAvailableForSpace:@"FrontPage" view:self.view 
        size:BANNER_TOP timeout:1000];
}

6. 加入額外的 framework
  • MediaPlayer.framework
  • SystemConfiguration.framework

7. Run


參考資料
Publisher/GettingStarted/TechnicalQuickStart - Flurry
iPhoneAgent: FlurryAds Class Reference

2012/08/04

工欲善其事,必先利其器:GDB 基本教學

最基本的編譯時要加"-g",把 debugging information 編譯進去,否則印不出什麼資訊來。再來就是不要做 optimize,不然程式碼行數會對不上。
$ gcc -g -o hello hello.c

啟動 GDB
$ gdb ./hello

必要時加入"-d (dirctory)"的參數,指定 source code 的位置
$ gdb -d /home/brian/test ./hello 

若程式已經在執行了,可以先查詢 pid,然後用 attach 的方式。記得 binary 的要跟正在 run 的 program 一致
$ gdb ./hello 12238

進入GDB後執行程式
(GDB) run
若要帶參數的話
run (init parameter)
Ex:
(GDB) run -h localhost -p 8080

Breakpoint
設定中斷點
b (filename):(line num)
Ex:
(GDB) b hello.c:5

列出目前的中斷點
(GDB) info b
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x000000000040049c in main at hello.c:5

移除中斷點
d (breakpoint id)
Ex:
(GDB) d 1

列出當下的狀況
列出 function stack (Back trace)
(GDB) bt
#0  hello () at hello.c:9
#1  0x00000000004004cf in main () at hello.c:14

列出更詳細的資訊,包含 variable 的值
(GDB) bt full
#0  hello () at hello.c:9
        i = 0
#1  0x00000000004004cf in main () at hello.c:14
No locals.

列印變數
p (variable)
Ex:
(GDB) p iValue
(GDB) p *stEmployee

切換 frame。要列印區域變數時,必須要切換到正確的 frame
f (frame num)
EX:
(GDB) f 3

流程控制
Step over (不會進 function)
(GDB) n
Step into (會跳入 function)
(GDB) s
Continue
(GDB) c

Signal Handle
handle (signal) (operation)
Operation 預設為 stop print noignore,也就是遇到 signal 時,GDB 會先攔截,並中斷程式,必要時可以改為 nostop noprint,讓程式本身去處理 signal。若下達 ignore 則是讓程式忽略此 signal。
(GDB) handle SIGUSR nostop noprint

列出目前 signal 設定的狀態
(GDB) i handle
Signal        Stop      Print   Pass to program Description

SIGHUP        Yes       Yes     Yes             Hangup
SIGINT        Yes       Yes     No              Interrupt
SIGQUIT       Yes       Yes     Yes             Quit
SIGILL        Yes       Yes     Yes             Illegal instruction
SIGTRAP       Yes       Yes     No              Trace/breakpoint trap
有關 signal 的部分可以參考 http://sourceware.org/gdb

Thread
查看目前在哪個 thread
(GDB) thread

切換 thread
(GDB) thread 3

列出所有 thread 的 function stack
(GDB) thread apply all bt
(GDB) thread apply all bt full

Ref:
Examining the Symbol Table

在 Mac OS 上使用 Wireshark

Network interface 預設的權限是 root,由於 wireshark 是以 user 的權限來開啓,故無法存取 interface,解決的辦法就是修改權限為大家都可讀。
sudo chmod 644 /dev/bpf*
解決!

2012/08/01

Ignore SIGPIPE in socket programming

通常在寫 socket programming 時,系統對一個 invalid fd (file descriptor) 做寫入時會讓系統丟出 SIGPIPE 的 signal,為了避免程式被中斷,通常都會 ignore 它。

#include <signal.h>
struct sigaction sa;

sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;

sigemptyset(&sa.sa_mask);
sigaction(SIGPIPE, &sa, 0);