2012年11月26日 星期一

台灣免費網路電視清單 @ Mac OS X、iPad、iPhone

因為一些因素,需要免費的網路電視(直播電視)來解悶,一開始看到"壹電視"網路新聞台還滿黑皮的,只是看久了就發現台灣的新聞播報方式幾乎憂多於喜,看久了會不爽快,漸漸地又想找一些其他台來看看,最後才想起偉大的中華電信 hichannel 頻道,但 hichannel 多只能用 Windows 平台配 IE 瀏覽器 + Windows Media Player 才能觀看,頓時又讓人倒退幾步。


慶幸的找了一會兒,終於找到 iPad 版 XD 看來台灣廠商都對 iPad 比較有愛,像壹電視、Hinet Hichannel 部分頻道有支援 iPad (Safari瀏覽器),但在 Android 上,點開不是不支援,不然就是要用 Flash player (手機 Flash player 已經在 2012.08 月份被 Adboe 拋棄了),真不知該說什麼。


總結一下,免費的網路電視及頻道:



簡單來說,若你是用 Windows 作業系統,那網路上免費的正版網路電視都可以觀看(壹電視+hichannel),若你是用 iPad 的話,那有部分可以觀看(壹電視+部分hichanel,且必須先從hichannel ipad 版廣播進去,不能直接連[須有 http reference 的機制]),最後,若你是用 Mac OS X 系統,用 Safari 則可以透過 iPad 網頁可以看的節目。至於 Linux 的系統就沒研究了 XD 不知裝一下 Safari 瀏覽器行不行。我個人是新聞播膩了,就播播東森亞洲衛視,偶爾有娛樂性質。


至於其他非正統版權的來源,則可以逛逛 justin.tv -> Live Channel > Language (繁體中文) 找找了 :P


2012年11月15日 星期四

[Linux] 快速架設 IMAP/IMAPs/POP3/POP3s - 使用 Dovecot @ Ubuntu 12.04

之前都寫漏漏長的 FreeBSD 架設方式,這次用 Ubuntu 12.04 架一下,果真快上許多(以下設定應該沒有符合 Ubuntu /etc/* 的規範 XD)。


$ sudo apt-get install dovecot-imapd dovecot-pop3d
$ sudo vim /etc/dovecot/dovecot.conf
protocols = pop3 pop3s imap imaps
mail_location = mbox:~/mail:INBOX=/var/mail/%u
$ sudo /etc/init.d/dovecot restart 


 可以用 telnet 和 openssl 測試自家機器:


測試 POP3:


$ telnet localhost 110   (或 openssl s_client -connect localhost:995)
...
+OK Dovecot ready
user username 
+OK
pass password
+OK Logged in.
list
+OK 1 messages:
1  ###
.
quit
+OK Loggin out. 


測試 IMAP:


$ telnet localhost 143 (或 openssl s_client -connect localhost:993)
* OK ... Dovecot ready.
- login username password
- OK .... Logged in
- select INBOX
...
* OK
* 1 EXISTS
...
- OK ... Select completed.
- logout
* BYE Logging out
- OK Logout completed. 


此外,有可能一開始剛裝完後,使用上述指令測試時出現錯誤訊息,這樣的現象是因為使用的帳號尚未有信件進來,以致於 /var/mail/username 並未建立,故只需先寄信給 username 後,系統就會幫你建立對應的 mail service 資料,如此就可以測試了。


[Linux] 設定 static ip @ Ubuntu 12.04

每次要用都又查了一次 Orz 筆記一下吧


$ sudo vim /etc/network/interfaces


auto eth0
#iface eth0 inet dhcp
iface eth0 inet static
address 10.0.0.180
netmask 255.255.255.0
network 10.0.0.0
broadcast 10.0.0.255
gateway 10.0.0.1
dns-nameservers 8.8.8.8


$ sudo /etc/init.d/networking restart


最後一行 dns-nameservers 若不加的話,從開機時 /etc/resolv.conf 會被清空。


2012年11月10日 星期六

iOS 開發筆記 - 使用 Xcode 4 編譯 facebook-ios-sdk 3.1

buildfbsdk01


最近摸摸 facebook-ios-sdk,發現它已經更新到 3.1,且從 3.0 開始架構有不少的變化,像是要求權限時,開始分 read 跟 write 的要求,例如登入時只能要求 read 或 write 類權限,而不能一次要求 read + write 權限,接著要再要求另一類權限時,可以在用 reauthorizeWithPermissions:defaultAudience:completionHandler: 再繼續要求。雖然 Facebook 有打包好一份 FacebookSDK 可下載到 Mac OS X 安裝使用,但有些好玩的架構 hack 則需要 source code (不見得要改 source code,可能是擴充架構時需要參考),所以就來編譯吧!編譯的概念很簡單,一種是編 app 時,要能夠找到 FacebookSDK header,另一種則是 link 時要能找到 FacebookSDK。


[Xcode] -> [Project] -> [iOS Application] -> [Empty Application] -> 隨便一個名字(此例StudyBuildFBSDK(由於個人習慣自己管記憶體,所以我就取消 Automatic Reference Counting)


接著從 github.com 下載 facebook-ios-sdk.git 回來,在此擺在 ~/facebook-ios-sdk-3.1


接著就用 Finder 開起 facebook-ios-sdk-3.1 後,把 src/facebook-ios-sdk.xcodeproj 拖到 StudyBuildFBSDK 裡頭


buildfbsdk01


接著依照 Facebook 的教學,點選 TARGETS-> StudyBuildFBSDK -> Build Phases -> Link Binrary With Libraries 中,在把需要的系統函式庫選一選(AdSupport, Accounts, Social 和 libfacebook_ios_sdk.a),接著再到 TARGETS-> StudyBuildFBSDK -> Build Settings 搜尋 other link -> 新增 -lsqlite3.0


buildfbsdk02


buildfbsdk03


接下來則是新增 header search 位置,即 ~/facebook-ios-sdk-3.1,TARGETS-> StudyBuildFBSDK -> Build Settings 搜尋 header search -> 新增 ~/facebook-ios-sdk-3.1 並設為 recursive


buildfbsdk04


如此一來應該就可以編譯成功了 :P 例如在 AppDelegate.m 中添加 FacebookSDK 相關程式碼:


#import "facebook.h"
...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
   self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];


   if( [[FBSession activeSession] state] == FBSessionStateCreatedTokenLoaded ) {
      NSLog(@"test in");
   }

   // Override point for customization after application launch.
   self.window.backgroundColor = [UIColor whiteColor];
   [self.window makeKeyAndVisible];
   return YES;
}


此外,執行還是會出錯,因為還要去 Supporting Files -> SutdyBuildFBSDK-info.plist 中,新增 FacebookAppID 後才能確保程式可以跑,只是還要補上額外的東西才能正式使用囉(參考 Facebook 教學)。


buildfbsdk05


2012年11月9日 星期五

Android 開發筆記 - 使用 Canvas 畫圖

android_canvas


一年前,我的好同事就一直在用 HTML5 Canvas 做出很多很讚的作品,但那時我的方向不一樣,一直沒有接觸。最近則開始想要在 android 畫畫圖,除了很底層的 OpenGL ES 外,就想到 Canvas 啦。


在這邊簡單筆記 Android 上 Canvas 的使用(最偷懶的使用方式):


public class MainActivity extends Activity {


   @Override
   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      //setContentView(R.layout.activity_main);
      setContentView( new View(this) {
         Paint mPaint = new Paint();
         Path mPath = new Path();


         @Override
         protected void onDraw(Canvas canvas) {
            // TODO Auto-generated method stub
            super.onDraw(canvas);


            // env init
            int width = this.getWidth();
            int height = this.getHeight();
            int radius = width > height ? height/2 : width/2;
            int center_x = width/2;
            int center_y = height/2;


            // prepare a paint
            mPaint.setColor(Color.BLACK);
            mPaint.setStyle(Paint.Style.STROKE);
            mPaint.setStrokeWidth(5);
            mPaint.setAntiAlias(true);

            // draw a circle
            canvas.drawCircle(center_x, center_y, radius, mPaint);

            // draw a rectangle
            mPaint.setColor(Color.GREEN);
            canvas.drawRect(center_x - radius, center_y - radius, center_x + radius, center_y + radius, mPaint);

            // draw a triangle
            mPaint.setColor(Color.MAGENTA);
            mPath.moveTo(center_x, center_y - radius);
            mPath.lineTo(center_x - radius, center_y);
            mPath.lineTo(center_x + radius, center_y);
            mPath.lineTo(center_x, center_y - radius);
            canvas.drawPath(mPath, mPaint);

            // draw some text and rotation
            mPaint.setTextSize(50);
            mPaint.setTextAlign(Paint.Align.CENTER);
            mPaint.setTypeface(Typeface.create(Typeface.SERIF, Typeface.ITALIC));
            mPaint.setColor(Color.RED);


            canvas.save();
            canvas.rotate(45, center_x, center_y);
            canvas.drawText( "Android Canvas" , center_x , center_y, mPaint);
            canvas.restore();


            mPaint.setColor(Color.BLUE);
            canvas.drawText( "changyy.pixnet.net" , center_x , center_y + 70, mPaint);
         }
      });
    }
}


2012年11月6日 星期二

[Python] 讀取 Shapefile 格式(*.dbf, *.prj, *.shp, *.shx, *.sbn, *.sbx) 以臺北市公車站牌位置圖為例

前陣子參加 2012 Yahoo! Open Hack 時,終於有空把玩台北市政府公開資料,碰到了之前一直想解卻沒空解的問題,以 臺北市公車站牌位置圖 為例,其資料格式:


$ ls bus
busstop.dbf busstop.shx 公車站牌匯入.sbx
busstop.prj 公車站牌匯入.dbf 公車站牌匯入.shp
busstop.shp 公車站牌匯入.sbn 公車站牌匯入.shx


一堆很奇妙的格式,感覺就像給你一個加密過的資料,讓人十分不解,這大概就是門外漢的滋味 Orz 回想起來,這種感觸還真像當年自己去刻圖書館 MARC 格式的心情 XD


所幸參加 Open hack 才有時間把玩,當下不知哪根筋被打通,忽然間明瞭這種 *.shp 格式就叫 Shapefile ,如此一來有關鍵字就能解了,馬上找到 pyshp - Python Shapefile Library


廢話不多,用法:


#!/usr/bin/env python
# -*- coding: utf8 -*-
import shapefile
import sys
reload(sys)
sys.setdefaultencoding('utf-8')


#sf = shapefile.Reader("bus/公車站牌匯入") # big5 & TWD67 format
sf = shapefile.Reader("bus/busstop") # utf8 & WGS84 format
#fields = sf.fields
print sf.fields 


records = sf.records()
shapeRecs = sf.shapeRecords()
print "Total: ",len(shapeRecs)
bushash = {}
for i in range(len(shapeRecs)):
   #busstop = records[i][1].decode('big5', 'ignore') # decode from big5
   busstop = records[i][1].decode('utf8', 'ignore') # decode from utf8
   if busstop in bushash:
      continue
   else:
      bushash[busstop] = ''


   print busstop
   print shapeRecs[i].shape.points[0]
   #print = FromTWD67TM2ToWGS84( shapeRecs[i].shape.points[0][0], shapeRecs[i].shape.points[0][1] )


成果:


[('DeletionFlag', 'C', 1, 0), ['SATOPID', 'N', 20, 0], ['STOPNAME', 'C', 20, 0], ['CITYNAME', 'C', 5, 0]]
Total: 5540
101國際購物中
[121.56524, 25.03415]
101購物中心
[121.565389, 25.034183]
8號水門
[121.53166335449, 25.072300254772]
一女中
[121.51507, 25.03828]
二二八和平公
[121.51303, 25.04215]
二二八紀念館
[121.513913, 25.030761]
....


眼尖的大概可以看到,第一筆有漏字,資料原始為 "101國際購物中<E5><BF>",不知是不是 pyshp 讀取錯誤還是原始資料有誤。此外,同一個站名會有多個座標點,在此僅先過濾掉,有興趣的在自行把玩吧!


其他補充:


安裝 GDAL (MacPorts: $ sudo port install gdal)
$ ogr2ogr -f geojson /tmp/output.json busstop.shp
$ enca /tmp/output.json
Unrecognized encoding
$ cat /tmp/output.json


{
"type": "FeatureCollection",

"features": [
{ "type": "Feature", "properties": { "SATOPID": 2028.0, "STOPNAME": "101å<9c><8b>é<9a><9b>è³¼ç<89>©ä¸­å¿", "CITYNAME": "å<8f>°å<8c>" }, "geometry": { "type": "Point", "coordinates": [ 121.56524, 25.03415 ] } }
,
...
]


$ ogr2ogr -f geojson /tmp/output2.json 公車站牌匯入.shp
$ enca /tmp/output2.json
Universal transformation format 8 bits; UTF-8
$ cat /tmp/output2.json


{
"type": "FeatureCollection",

"features": [
{ "type": "Feature", "properties": { "SATOPID": 2028.0, "STOPNAME": "101國際購物中??", "CITYNAME": "台??", "stopNAMEB5": null }, "geometry": { "type": "Point", "coordinates": [ 306245.046938922838308, 2769874.23026815475896 ] } }
,
...
]


2012年11月4日 星期日

常用的座標轉換筆記(TWD67, TWD97, WGS84)

台灣現在常看到的座標系統有三種,分別是 TWD67、TWD97 和 WGS84,其中 WGS84 就是網路應用上常用的 GPS (lat, lon) 格式(歐洲近幾年有在推另一個座標系統)。至於為啥會接觸到呢?實在是這幾年 ITS 的服務越來越興盛,而台灣區的資料慢慢地釋出(如 Taipei Open Data、交通部運輸研究所等),然而就開始碰到資料格式問題,那就是台灣不少資料採用的地理座標系統不是 GPS 格式。如果你不是 ITS 領域,那大概就跟我一樣從摸 Google Maps 而接觸 GPS 座標系統,例如只要在 Google Maps 上打上 25.033661, 121.564815 後,顯示的就是 Taipei 101,但從台灣區取得的地理座標系統,丟到 Google Maps 卻行不通 :P


這幾年都有接觸 ITS 應用,但一直很懶得整理導致每次都花差不多的時間去處理,所以打算來寫篇筆記


目前碰過的座標格式:



  • TWD67 (TM: 2-degree Transverse Mercator, 二度分帶)


    • 採用 1967年國際地球原子參數(Geodetic Reference System 1967,GRS67),早期還未有衛星時,透過天文觀測、三角定位量測,埔里虎子山為測量原點,而 TWD 全名為 Taiwan Datums


  • TWD97


    • 採用 1980年國際地球原子參數(Geodetic Reference System 1980, GRS80),以 GPS 衛星定位重新測量,國內是在 1997 年啟用,所以稱作 TWD97


  • WGS84


TWD67 與 TWD97 轉換:



  • 從 TWD97 轉 TWD67


    • X67=X97-807.8-A*X97-B*Y97
      Y67=Y97+248.6-A*Y97-B*X97
      A=0.00001549, B=0.000006521 


  • 從 TWD67 轉 TWD97


    • X97=X67+807.8+A*X67+B*Y67
      Y97=Y67-248.6+A*Y67+B*X67
      A=0.00001549, B=0.000006521 



TWD67 轉 WGS84 (GPS):


$ echo TWD67_X TWD67_Y | proj -I +proj=tmerc +ellps=aust_SA +lon_0=121 +x_0=250000 +k=0.9999


TWD97 轉 WGS84 (GPS):


$ echo TWD97_X TWD97_Y | proj -I +proj=tmerc +ellps=GRS80 +lon_0=121 +x_0=250000 +k=0.9999


目前測試的心得:


先把 TWD67 轉 TWD97 後,在用 TWD97 轉 WGS84 的成果跟 Google Maps 的標記就接近了不少,但仍差大概約25m的距離,也還有一條街的距離。


Python Code:


def WGS84FromTWD67TM2(x,y):
   out = {'status':False}
   lat = None
   lon = None
   
   # TWD67 to TWD97
   A = 0.00001549
   B = 0.000006521
   x = float(x)
   y = float(y)
   x = x + 807.8 + A * x + B * y
   y = y - 248.6 + A * y + B * x

   # TWD97 to WGS84
   result = os.popen('echo '+str(x)+' '+str(y)+' | proj -I +proj=tmerc +ellps=GRS80 +lon_0=121 +x_0=250000 +k=0.9999 -f "%.8f"').read().strip() # lat, lng 格式, 不必再轉換
   process = re.compile( '([0-9]+\.[0-9]+)', re.DOTALL )
   for item in process.findall(result):
      if lon == None:
         lon = float(item)
      elif lat == None:
         lat = float(item)
      else:
         break


   # result = os.popen('echo '+str(x)+' '+str(y)+' | proj -I +proj=tmerc +ellps=GRS80 +lon_0=121 +x_0=250000 +k=0.9999').read().strip() # 分度秒格式


   # 分度秒格式轉換
   #process = re.compile( "([0-9]+)d([0-9]+)'([0-9\.]+)\"E\t([0-9]+)d([0-9]+)'([0-9\.]+)", re.DOTALL )
   #for item in process.findall(result):
   #    lon = float(item[0]) + ( float(item[1]) + float(item[2])/60 )/60
   #    lat = float(item[3]) + ( float(item[4]) + float(item[5])/60 )/60
   #    break
   if lat == None or lon == None:
      return out
   out['lat'] = lat
   out['lng'] = lon
   out['status'] = True
   return out


更多 proj 資訊:


$ proj -le
MERIT a=6378137.0 rf=298.257 MERIT 1983
SGS85 a=6378136.0 rf=298.257 Soviet Geodetic System 85
GRS80 a=6378137.0 rf=298.257222101 GRS 1980(IUGG, 1980)
IAU76 a=6378140.0 rf=298.257 IAU 1976
airy a=6377563.396 b=6356256.910 Airy 1830
APL4.9 a=6378137.0. rf=298.25 Appl. Physics. 1965
NWL9D a=6378145.0. rf=298.25 Naval Weapons Lab., 1965
mod_airy a=6377340.189 b=6356034.446 Modified Airy
andrae a=6377104.43 rf=300.0 Andrae 1876 (Den., Iclnd.)
aust_SA a=6378160.0 rf=298.25 Australian Natl & S. Amer. 1969
GRS67 a=6378160.0 rf=298.2471674270 GRS 67(IUGG 1967)
bessel a=6377397.155 rf=299.1528128 Bessel 1841
bess_nam a=6377483.865 rf=299.1528128 Bessel 1841 (Namibia)
clrk66 a=6378206.4 b=6356583.8 Clarke 1866
clrk80 a=6378249.145 rf=293.4663 Clarke 1880 mod.
CPM a=6375738.7 rf=334.29 Comm. des Poids et Mesures 1799
delmbr a=6376428. rf=311.5 Delambre 1810 (Belgium)
engelis a=6378136.05 rf=298.2566 Engelis 1985
evrst30 a=6377276.345 rf=300.8017 Everest 1830
evrst48 a=6377304.063 rf=300.8017 Everest 1948
evrst56 a=6377301.243 rf=300.8017 Everest 1956
evrst69 a=6377295.664 rf=300.8017 Everest 1969
evrstSS a=6377298.556 rf=300.8017 Everest (Sabah & Sarawak)
fschr60 a=6378166. rf=298.3 Fischer (Mercury Datum) 1960
fschr60m a=6378155. rf=298.3 Modified Fischer 1960
fschr68 a=6378150. rf=298.3 Fischer 1968
helmert a=6378200. rf=298.3 Helmert 1906
hough a=6378270.0 rf=297. Hough
intl a=6378388.0 rf=297. International 1909 (Hayford)
krass a=6378245.0 rf=298.3 Krassovsky, 1942
kaula a=6378163. rf=298.24 Kaula 1961
lerch a=6378139. rf=298.257 Lerch 1979
mprts a=6397300. rf=191. Maupertius 1738
new_intl a=6378157.5 b=6356772.2 New International 1967
plessis a=6376523. b=6355863. Plessis 1817 (France)
SEasia a=6378155.0 b=6356773.3205 Southeast Asia
walbeck a=6376896.0 b=6355834.8467 Walbeck
WGS60 a=6378165.0 rf=298.3 WGS 60
WGS66 a=6378145.0 rf=298.25 WGS 66
WGS72 a=6378135.0 rf=298.26 WGS 72
WGS84 a=6378137.0 rf=298.257223563 WGS 84
sphere a=6370997.0 b=6370997.0 Normal Sphere (r=6370997)


網路資源: