這艘船載了什麼貨物呢?

在 Hacker News 上面看到這個專案: https://github.com/marcdacosta/ambient-shipping

可以查到過美國海關每一艘船上面的貨物資料,覺得很酷,一時興起來研究了一下台灣有沒有辦法這樣搞。

總之最重要的目標就是要可以查到提單 (bill of lading) 內容,引用自關務署的說明:

大提單屬有價證券,一般商業習慣均稱為提單,係由運送人所簽發,為運送契約之證明文件,是運送人或船長收受貨物之收據,也是確認貨物所有權之權利證券。大提單之格式或有差異,但大同小異,一般記載有託運人之姓名或名稱、受貨人、受通知人、貨物名稱、件數或重量,或其包裝之種類、個數及標誌、裝載港及卸貨港、運費交付、填發之年月日等事項。

試了一下之後發現有時候是真的可以查到貨物內容的:

  1. 先去 MarineTraffic 網站挑一艘你想查的船,記住船名。

  2. 海關通關號碼(原船隻掛號)查詢 (GB330) ,以船名搜尋,就可以搜尋到每個航次的海關通關號碼(原船隻掛號),還有船公司代碼、出口裝船關別(基隆、六堵等等)

  3. 再去 海運進口艙單資料查詢(GB326) 的查詢一,輸入 2 的資訊,然後勾「查詢艙單資料」,就可以搜尋到艙單號碼主提單號

  4. 再去查詢二,用艙單號碼或是主提單號就可以搜尋到報單號碼,可以拿去查這批貨物通關的時間,中間是否有被要求補件等等。但查不到我想要的提單內容。

提單在通關的時候並不是必備的文件,但海關可以要求廠商提供,但台灣關務署收到了之後看來並不會把它變成公開資料。

幸運的是我後來找到一個網站可以方便查詢各大航運公司的提單內容,但全世界的運輸公司太多,所以有很多這個網站查不到的。

在 GB236 查到的主提單號可能會有兩種格式,一種前面包含 SCAC code (像是 HPHCB17003515 ),另一種前面不包含 SCAC code (像是 0317540166 ),查提單的時候就要自己猜是哪一家公司。

SCAC code 是美國某個運輸協會管理的全世界的運輸公司的代號,每個運輸公司會有自己獨有的代號。

部分的 SCAC code 可以從這份文件裡面查到: https://gist.github.com/allada/c10ca4a5751b6546dbec ,但我試過像是 HPHC 就查不到。

有時候運氣好的話就真的可以查到貨櫃內容:

Firefox 57 毀掉分頁群組之後怎麼辦

眾所周知,預計 2017 年 11 月釋出的 Firefox 57 將移除所有舊版附加元件(使用 XUL/XPCOM/Addon SDK 的附加元件)的支援,只支援 WebExtensions 的附加元件。

如此重大的修改將會讓我失去 Firefox 對我來說最重要的分頁群組功能,原本分頁群組功能的開發者 Quicksaver 已經表示不會將原本的 Tab-Groups 插件移植到 WebExtensions API ,等於是宣判了這插件的死刑。

除了分頁群組之外,過去所有使用者熱愛的附加元件都將停止運作,各大討論版上面使用者哀嚎四起,還有 change.org 的連署,可惜沒過。

Mozilla 這個決定蠢斃了:

  • 大部分的使用者不使用附加元件沒錯,但不支援 XUL 附加元件會讓一大群 power user 和死忠粉絲背棄
  • 畢竟 Firefox 雖然比 Chrome 慢,但也只有 Firefox 可以讓你客製化到都認不出來,像我使用的 Firefox-on-OS-X Label 附加元件。 Chrome 你要做這 API ?還要先重新定義一個 Javascript 的界面、新增 API Permission 、一堆重複的工。Firefox?登登!Components.interfaces.nsIMacDockSupport !附加元件直接 tap into 原本就是負責處理這東西的內部界面,不需要重新定義界面巴拉巴拉。附加元件 15 行寫完收工。

好吧抱怨就此結束 :-p 我比較喜歡 Firefox 這樣可以自己自由 mod 的舊架構,而不是開發者爽開給你 API 才能 mod 的新架構。

身為一個分頁群組難民兼任自己要的功能自己寫的開發者,當然想要調查一下有什麼可行的解決方案可以拯救分頁群組功能,我整理出這些方法:

1. build 自己的 firefox fork ,把 legacy extension 直接包進去讓它可以用 legacy API

這會有點麻煩,每次釋出新版的時候要自己 patch 加入想要的 extension ,每個人想要的 extension 可能也不一樣,但這是保留原汁原味 legacy extension 唯二的方法。

挖了一下 Firefox 的 source code,原本內建在 Firefox 的 Panorama (就是分頁群組功能)在 codebase 裡面的這裡(應該是啦我有點不確定):mozilla-esr38/browser/components/tabview ,後來 tabview 被獨立出去成為 tabgroups extension ,所以理論上我只要把這個過程逆向操作,我就可以把現有的 extension 包回去 firefox 。但這 code structure 跟後來獨立出來成為 extension 的 tabgroups 長相實在差有點多,讓我有點搞不清楚到底當時是怎麼整理 codebase 獨立成 extension 的,這還需要更仔細的研究。

這麼做也有極限,因為 legacy API 和 extension 都不會再被維護,所以如果有新的 codebase 影響 legacy API 的運作,也不會被修正,legacy extension 也不會為了 broken API 去 workaround ,所以在更久的未來可能終究無法正常使用。

2. 啟動 legacy API 相容設定

猜測在 57 應該會有個 about:config 設定值可以允許 legacy extension 被安裝並且使用 legacy API 才是,雖然我還沒仔細去看這個設定值在哪裡。(等我找到再來更新這一段)

這個和方法1也有一樣的問題, legacy API 和 extension 都不會再被維護。

3. 使用 /firefox-tabgroups

這個 extension 本來是 tabgroups 的替代方案,也使用 legacy API, 但是和 tabgroups 不一樣的地方是作者 denschub 承諾說會支援新的 firefox ,雖然怎麼做、會有什麼功能他沒有說,但勢必一樣得受限於新的 WebExtensions API 。

4. 使用 contextualIdentities API 的相關插件

Firefox 前陣子新推出了一個 containers testpilot,基本上的概念是「在 Firefox 中透過不同容器來管理不同的線上身分,不論是線上購物、規劃旅遊行程、工作使用,更可以建立其他不同色彩與名稱的自訂容器。每個容器當中的 Cookie 會分開儲存」,它的目標使用情境看起來和分頁群組有些相關,因為分頁群組確實偶爾會被拿來這樣使用,但又有相當不同,containers testpilot 原本不是設計給「分頁管理」的情境下來使用的,所以沒有提供「顯示/隱藏」特定分頁的 API 。

有人去 containers 的 github 開了一個 issue 說,可不可以接受 containers 作為分頁管理工具的用途,獲得超多回應,畢竟現在這看起來是最有希望帶回分頁群組功能的道路了。

基於 contextualIdentities API  的插件目前有 eoger/tabcenter-reduxjonathanKingston/sea-containers ,這兩個是一開始就以 WebExtensions API 開發的插件,另外未來 denschub/firefox-tabgroups 應該也會使用這個 contextualIdentities API 。

contextualIdentities API 的問題

我去看過 contextualIdentities API 之後就覺得這真是個噁心霸道的東西,在棄用 legacy API 之後,插件沒辦法直接修改到 Firefox 的內部,所以照理來說 containers testpilot 是做不出來的,因為原本根本就沒有這種 WebExtensions API ——結果! Firefox 團隊就這樣直接幫 containers testpilot 開了後門,量身打造了一個 API 給他們——就是 contextualIdentities API 。

覺得很噁心,這不就剛好證明了能夠作出重大有意義的功能靠現有的 WebExtension API 根本做不到嗎?以前可以自己直接用 XPCOM ,現在還要先跟 Mozilla 開發團隊搞好關係才能在 core 塞進自己的插件需要的 WebExtensions API 。

撇開這個不說,這個 API 的設計看來也是一個 monolithic piece of poorly designed code 。正常來說 API 的設計應該是先暴露出最基礎的核心功能,然後由開發者自己組裝核心功能調用來作出有意義的插件吧?結果 contextualIdentities 這個 API 裡面直接把幾個在這個用途以外不相干的核心功能綁在一起暴露給 containers extension 使用:

  • 新增、刪除獨立的 cookie 儲存空間,一個新的 contextualIdentities API 會自動建立一個新的 cookie 儲存空間,完全沒有考量到獨立的 cookie 儲存空間可能會有 contextualIdentities 以外的用途,也沒有考慮到新的 contextual identity 想要分享現存 cookies 的狀況(共用一個 cookie 儲存空間)。
  • 更動右鍵選單項目,這個 API 直接自動新增了 “Open Link in New Container tab" 的項目。雖然我們已經有了 contextMenus API 可以新增右鍵選單項目,但顯然我們需要複製一份 code 給 contextualIdentities API 來讓使用者可以輕鬆地在新的 container 分頁裡面開啟連結,這樣複製一份 code 還可以減少 containers testpilot 插件開發者需要寫的 code ,非常棒。
  • 在 tab 頁籤上色的功能,在每個 contextual identity 裡面可以新增 tab ,在 contextual identity 當中新增的 tab 會自動被上色。顯然在分頁上色的功能只會有 containers 實驗會用到。
  • contextual identity 本身的頁籤顏色和圖示都只有固定的幾種可以選,圖示像是 cart, fingerprint, briefcase 等等,顯然不可能會有其他狀況下需要其他的圖示。

……正常的設計應該會是把前面三種功能分成三種不同的 API , 插件作者自己把這三種 API 結合在一起形成 contextual identity 的概念才對啊!!

另外,雖然有了 contextualIdentities API ,但還缺乏很多 API ,導致這些插件的功能還沒辦法實作出完全復刻原本 quicksaver 開發的 Tab Groups 的功能:

  • 如上所述,建立 contextual identity 的時候不能選擇共用 cookie store ,但 quicksaver 的版本裡面所有的分頁群組還是共用同一個 cookie store 的
    • 狀態:沒有查到相關的 feature request
  • 沒辦法選擇性只顯示部分的分頁(也就是只能顯示所有的分頁),quicksaver 的 tab groups 一次只會顯示一個群組。
  • 現在無法把某個 contextual identity 中的分頁移動到另一個 contextual identity ,只能關掉原本的分頁,然後開一個新的
  • 如果要使用類似 tree-style tabs ,把所有分頁和分頁群組放到側邊欄,那原本的橫向頁籤列應該要被隱藏,但現在沒有這樣的 API

相關資料、討論

個人感想

原本我以為沒希望了,更久以前我在搜尋的時候都找不到替代方案,幸好最近有 containers testpilot 所以才有這麼多延伸應用冒出來,有種燃起一線希望的感覺。但上面的那些 bug 大部分都還沒有被 mozilla 批准,我不太有信心 57 出來的時候分頁群組替代方案能夠完全提供舊有的功能,感覺上面當中一兩個還是很有可能會被 mozilla 拒絕…

Android Island work profile apps and AFWall

Island is an app that allows you to isolate, clone, freeze, hide, archive apps.

Unfortunately when you use it with iptables firewall app like AFWall the apps placed in the work profile have no access to the network. (because there aren’t rules allowing them in the firewall)

AFWall doesn’t support multiple profiles – there’s an experimental option called “multi-user support" but only works in mode where selected items are blocked:

 

AFWall doesn’t show work profile apps. So I need a way to allow work profile app traffic.

With a bit of digging, I found the rule for work profile (UNIX) uid : user_id*100000+app_uid , the primary user has user id of 0, the work profile Island created has user id 10.

So you can go look for app uid, add user_id*100000 , and it becomes the (UNIX) uid of the app in that work profile.

A quick way to know app_uid is go to AFWall preferences > User interface > “Show UID for apps".

Then you need to write your own rules that allows traffic to pass through, the number after --uid-owner is the UID you want to change, in this example I allowed 3 apps:

Place it in /data/local/, chmod +x it, add its path to AFWall custom script, then apply rules in AFWall. You should now get internet in work profile apps.

聯邦式 OAuth 構想

剛剛在架 wallabag ,開源的 Pocket / Instapaper 替代品。

然後突然想到,我架一個這個就只有自己用、自己維護耶,而且又是另外一組帳號密碼。

不知道有沒有辦法設計一套聯邦式的 OAuth 認證機制,不同的組織(網域)可以加入聯邦,所有人使用同一個 OAuth endpoint 但帳號的後綴不同,這樣志願的服務供應者(譬如說我很樂意讓別人一起使用我維護的 Wallabag)就可以直接選用這個 OAuth 認證服務,再選擇要讓哪一些組織的人登入。

這樣的話,既能達到單一帳號的功能(在不同服務間可以使用同一帳號,不用記多組帳號密碼),也不像直接採用 Google OAuth 這種任何人都可以擁有帳號的服務,志願的服務供應者就可以只允許他信任的組織的使用者使用他的服務。

可能有點難理解,舉個例子說明:

姑且把這個中央代理 OAuth 服務叫做 Distauth,接下來有志願的服務供應者 A, B 和組織 X, Y, Z,還有組織 X, Y, Z 的成員甲、乙、丙。

A 因為自己的需求,架了一個 Nextcloud ,他願意分享一些伺服器空間給其他人使用,但是又怕有人濫用。

B 為了要自己作筆記,架了一個 hackmd ,他也願意讓其他人使用他維護的 hackmd 服務。

X 組織是某個資訊社群,他們擁有一個 xxxx.tw 的網域,也有一套自己的帳號系統,要申請 xxxx.tw 的帳號需要經過組織訂定的審查流程,並簽署不濫用的同意書,甲已經通過,因此有 jia@xxxx.tw 這個帳號。

Y 組織是另一個鬆散的社群,他們提供所有成員一個帳號,只要填一個線上表單就可以申請,乙擁有 yee@yyyy.tw 這個帳號。

Z 組織是一間大學,所有的在校生都有帳號,帳號會在畢業之後失效,丙擁有 bing@zzzz.tw 這個帳號。

X, Y, Z 都加入了 Distauth 聯盟。

Distauth 是一個特殊的 OAuth 認證伺服器 (Authorization Server) ,任何組織(只要有一套帳號系統)都可以加入 Distauth , 任何服務供應者、應用程式都可以和 Distauth 註冊,成為 OAuth client (application) ,取得獨特的 App ID 和 App Secret 。

A 因為伺服器空間有限,而且他想要確保來使用的人不會濫用他提供的服務,他認為 X 的審查流程足夠嚴格,Y, Z 則不,所以他在 Distauth 取得 App ID 和 Secret 的時候就設定,只有組織 X 的人可以登入。

如此一來,甲已經擁有了 X 的帳號,所以他可以直接使用 A 提供的 Nextcloud 服務,X 組織未來任何的新成員也都可以直接使用 A 的 Nextcloud ;同時,乙和丙雖然可以成功登入 Distauth ,但 Distauth 不會授權乙丙使用 A 的 Nextcloud 。

B 架設的 hackmd ,因為只有純文字儲存功能,所以佔用資源很少,他認為不需要嚴謹限制使用者,但還是希望是認識的社群的成員才能使用,所以他在 Distauth 設定 X, Y, Z 的成員都可以使用,但其他組織不行。

整個概念大概就是這樣,現在看來好像沒有類似的東西,自認這構想還不錯,不過一樣,要獲得廣泛採用本來就很困難 :-p

寫爬蟲絕對不要太客氣也不可以心軟

尤其是要爬像是 Facebook 這種蓄意想要鎖住資訊,把 Internet 變成一個巨大內網的邪惡公司的時候。

之前在 Github 看到 rss-bridge 這個專案,用爬蟲去爬網頁然後產生 RSS/Atom feed ,原本是想要把它用在 Facebook 上面,這樣就可以訂閱粉專的每一篇貼文、照時間排序、不用被 Facebook 的 filter bubble 審查資訊,也不會因為你訂閱什麼就汙染你的 stream 。

架起來試了一下發現效果還不錯,訂閱了一堆粉專就去睡了。

結果隔天早上醒來發現所有 feed 都失效,因為 Facebook 要求 Captcha 驗證。原本的 rss-bridge 會把驗證圖片 proxy 顯示給瀏覽 feed 的使用者,使用者可以解完之後送出,rss-bridge 會再送給 Facebook ,但這功能實測的時候發現無論如何送出都會失敗,把這 bug 解掉之後又發現 captcha 只會當次有效,也就是要發另一個 request 的時候又會被跳 captcha 。

自己開瀏覽器測試了一下發現,瀏覽器的 captcha 只要解一次,未來的 request 就都會過,想說大概是因為 rss-bridge 的爬蟲不支援 cookie 的問題,所以就花了好幾天時間把 rss-bridge 的爬蟲換成 PHP curl (原本是用 file_get_contents() ),因為 PHP curl 有 cookie jar 的功能,管理 cookie 比較方便。

結果新的 code 終於會動,但儘管送了 cookie 還是每次被跳 captcha ,挖到底層去測試了很多東西,檢查 request header 和 response header ,確定不是我實作有問題之後,我發現問題不在 cookie。

問題在於 rss-bridge 的爬蟲預設都會多送一個 GET 參數 _fb_noscript=1 ,有這個參數的時候顯示出來的 captcha 會不一樣!

_fb_noscript=1 的時候顯示的 captcha 會直接是一個 <img src="..."> ,而且這個 captcha 也只有單次有效!下次再請求,就算有 cookie, 也會再被要求解另一個 captcha 。

沒有那個參數的時候的 captcha 圖片會使用 AJAX 載入,然後解開之後設定的 cookie 也會多次有效。

我拿舊的實作改成 curl 的時候沒有特別改這個東西,結果到現在才發現這件事。

所以,這次學到的教訓是,寫爬蟲的時候,不要仁慈,直接開 PhantomJS/CasperJS 吧……

P.S. 我改過的 rss-bridge 在這兒: https://github.com/pellaeon/rss-bridge/tree/enhance

更新:不想用 Javascript 的話 Python 的 Scrapy + Splash (Splash 是 headless browser)看起來還不錯(沒用過)。還有 django-dynamic-scraper 可以直接把爬到的東西結構化成 Django model object ,每一個 field 直接關聯一個 selector ,scrape 的時候讀進去,太神啦。

2017/2/24 更新2:後來又繼續試著解決這個問題。研究了一下 django-dynamic-scraper , 幾乎找不到如何處理 captcha 的說明和範例,雖然說應該是可以解但是感覺又要研究 scrapy 很久,所以還是決定回去幫 rss-bridge 加上 proxy 的功能。改出來的東西在 https://github.com/pellaeon/rss-bridge/tree/enhance2 。然後還花了一些心力研究要怎麼取得免費的 proxy 清單,最後發現 HideMyAss.com 的不錯,寫了個小小的 Javascript 去撈 proxy 清單

計劃太多,徵人(?)

想做的專案太多,時間能力不夠,只好先把想法記下來。更希望可以找到人一起來合作一個專案啦,自己做太容易放棄了。

owncloud-registration

讓 ownCloud/Nextcloud 支援註冊帳號的插件,原本 ownCloud/Nextcloud 只能管理員自己建立帳號然後把帳密交給新使用者。

開發其實很簡單,沒什麼技術難度,知道怎麼接 ownCloud public API (PHP 的 API)和基本的資料庫連接 code 的撰寫能力就可以了。已經很久沒有碰 code,有個 admin-approval 的 branch ,已經拖了兩年多了 :-/ ,要做的功能是管理員審核功能,讓管理員可以審核新註冊的使用者,也沒什麼技術難度,就是 glue code 接一接,所以實在沒什麼動力把它做完。前端部分會用 handlebar.js 去 hook 官方的使用者管理頁,然後去呼叫後端插件內的 HTTP API 。

facebook-not-typing 和 facebook-micromanage

這兩個都在我的 github 帳號底下,facebook-not-typing 應該看了 readme 就知道是幹嘛的。

facebook-micromanage 則是比較有野心的計劃,想要以瀏覽器插件來提供很多 Facebook 不給的功能,現階段已經完成撈朋友清單,接下來利用已經有的基礎建設,也就是撈 cookie 和 localStorage 的 code ,想要突破 Facebook 過濾泡泡,去撈每一個朋友和粉絲專頁的牆,然後存進 IndexedDB (雖然說這已經是 deprecate 的標準,但我真的需要結構化的資料儲存),再依照時間順序顯示出來。現在遇到的問題是撈朋友牆的 request ,分頁的參數不知道怎麼填,有幾個變動的神奇數字還沒有辦法看出產生的方式。

不過或許以後也可以直接開大絕用 phantomjs 撈更快,不過這要跑在瀏覽器插件裡面就比較有困難。不對,開一個隱藏的 content page 應該就可以?

第二個想做的功能是管理朋友清單,可以用交集和聯集產生新的清單,還有朋友清單備份時間點,也就是在每一個朋友清單後面加個時間戳記,最新的則不加戳記,在有變動(譬如說你把人加進那個清單)的時候,加入前的版本會加上戳記(清單重新命名),然後把原本的人加到新的清單,再加入那個新的人,這樣新的人就看不到你以前的貼文。

bsd-cloudinit

  • 弄好 Jenkins… 有夠難 debug 設定,應該接近完成了,等 Github Pull Request Plugin 的那個 bug (在 Firefox 按 Rebuild PR 沒反應)修好應該會比較好 debug,噢,還得再次砍掉 ghprb 。(每次要測試 build 還得去 github PR 下面留言 “retest" 實在有點蠢)
  • 跟上游 cloudbase-init 同步 code (因為他們是一個 framework 了,我們只是加幾個 FreeBSD 專屬的 class 來實作在 FreeBSD 上面的操作)
  • 同步 code 以後,把舊的 code 改寫成符合新架構的形式,然後開始收 PR ,也改成新架構
  • 弄個 cronjob 去檢查 FreeBSD releng 的更新,有更新的時候自動觸發 build

ownCloud Music Koel

從 Koel 幹來的前端,插在 ownCloud Music app 上面,還有很多功能沒有做完:

  • 歌詞,Last.fm,YouTube 整合壞掉了
  • 觸發掃描的按鈕
  • 樂曲長度偵測、顯示
  • 上架 apps.nextcloud.com

中文斷詞加貝式機率過濾垃圾郵件

附中信箱的垃圾郵件自從用了 bogofilter 之後算是蠻少的,不過有時候還是會有一整批的 Spam 抓不到。所以希望可以用結巴斷詞函式庫先把信內容斷一斷然後再進 bogofilter ,當然斷詞之前還有很多麻煩事要做,像是 parse MIME multipart ,幸好發現了個 library 可以解決。

現在是卡在要設計一個有效的 benchmark 方法,測量偵測的準確度。(跟其他專案一樣,就是好像怎麼做都可以,怎麼做都有點問題,沒辦法決定怎麼做,所以先擱置)

筆記會依照相關性記在 CNMC Wiki

要是中文垃圾郵件過濾可以做得好的話希望可以架台 mail server 給認識的人付成本價使用,也可以提供 domain email 代管,help re-decentralize the web

豐原計劃

是個自幹 Google Drive 的計劃,ownCloud 現在還是有很多問題,所以想要重新用 Django 實作,構想都記在 HackMD 裡面了。目前我在弄前端,雖然我跟前端真的沒那麼熟,但 @M157q 更不熟 :-p 所以只好我來弄。週末不定時黑客松。

skicka-fuse

拋棄很久的專案,想要用 skicka (非官方的 Google Drive CLI client,Go 寫的)和 bazil-fuse 重新做一套 Google Drive 的 FUSE, 希望用 Go 會讓一切變得很快,還有計劃要用大量的本地快取增加速度,但快取可以隨時被 free ,類似 ZFS 或 memcached 那樣。

逆向 iCloud Drive

希望可以找到方法 hack ,讓深度整合 Finder 的 iCloud Drive 可以被 hack 成其他 backend ,像是上述的豐原。

裝了 mitmproxy (在 OSX 上面用 pip 裝似乎會爛,放棄了直接裝上游 package),攔截了一些 request ,基本上 iCloud Drive 就是用 CloudKit 實作的,所以得先弄懂 CloudKit 的認證方式。

筆記也在 HackMD

Octowall

某次在 GitHub 亂逛看別人都在幹嘛的時候想到的主意:

//platform.twitter.com/widgets.js

Django 的初始 scaffolding 已經有了,但是埋藏在某個硬碟可能已經損毀的虛擬機器裡面,要繼續的話得設法撈出來。

桌面環境與豐原計劃(GNOME)

希望桌面環境和雲端環境能夠更深度整合,想修改 GNOME apps ,讓它們可以和豐原運作,譬如說 Nautilus 兼雲端檔案瀏覽器,類似 Dropbox Project Infinite 的概念。還有也想改改 Shotwell ,讓它可以做類似 Apple Photos 或 Google Photos 的事情,自動上傳照片,然後可以瀏覽遠端照片,就像在本地。

多虧 lantw ,已經在 Ubuntu 上面弄出 GNOME 的開發環境(這真的是最難的部分,讀懂 Nautilus 的 code 都比這個簡單,大概是因為我用 Ubuntu 的關係,然後官方在不久以前把 Ubuntu 從支援的開發環境中移除了,現在要開發的話,官方支持的就只有 Fedora。但是我不想重新學用 rpm 系的東西啊 :-p )。

第一步就是應該要可以 build 出一個跟 Nautilus 一模一樣但是可以和 Nautilus 獨立運作的應用程式,這樣才能方便開發和使用者測試,否則每次測試我們的東西 Nautilus 就有可能壞掉,多麻煩啊。可能主要是 DBUS 的註冊名稱要改一下之類的,但光是這個就挺麻煩,我跟 DBUS 不熟 :-p

目前擱置中,先做豐原,Web 畢竟還算是我稍微有能力做的事情,桌面環境的 build system 什麼的好複雜啊 @_@

BitTorrent tracker proxy

發現很多環境,像是學術網路,阻擋 BT 的方式多半是用阻擋特定的 port ,UDP tracker 會用的 port ,像是 6969, 1337 。然後 tracker 協定其實支援 TCP, HTTP, HTTPS ,但幾乎所有的知名 tracker 都用 UDP ,而且都用那幾個 port 。

所以想法是,做一個 tracker proxy ,可以在未受阻擋的網路,用 HTTPS tracker 協定和受阻擋的網路內的 client 溝通(計中總不可能 block HTTPS 吧),然後再代理 client 向上游的 tracker 用 UDP 溝通。

這樣有幾個問題,一是計中還是可以擋我們 proxy 的 IP ,但這應該不會那麼快發生,而且我們只是跑普通的 HTTPS 啊,為什麼要擋我們捏?完全杜絕的方法就是用 public cloud, 讓他們一擋就要擋所有服務,不過 Heroku app 沒辦法送 UDP 的樣子,得用其他共用 IP ,又可以送 UDP 的 public cloud。問題二是,這樣使用者每次要新增 torrent 的時候就得手動新增我們的 proxy 到 tracker 清單裡面,很麻煩。這應該可以用在 client 做插件的方式解決,Deluge 是 Python 寫的,也可以用 Python 寫插件,應該不會太難。問題三是代理沒辦法知道要幫使用者代理哪幾個 tracker ,這個解法一是用自訂的協定去溝通,client 端用插件送額外的資訊;解法二是我們就只是 proxy 幾大 tracker ,其他就不管,這樣應該至少可以達到一點點效果吧(其實不算是解法啦…),還可以開個網頁允許使用者自己加入想要 proxy 的上游 tracker 。

本專案還沒有任何 code ,不過我在 trace bittorrent-tracker 的 code 了。

徵人啊

以上專案全部都徵人和我一起做,沒有很懂沒關係,我可以教,不然這些構想真的都沒辦法實現了。

因為找不到人一起寫 code ,所以辦了臺灣程式路跑

臺灣程式路跑是我和子期舉辦的活動(還要靠很多朋友和導師的幫忙啦),希望傳承台灣現有自由開源軟體開發者的經驗給新進者,讓更多人接觸自由開源軟體開發。這篇文章說明一下我為什麼想要辦這個活動背後的脈絡。

——

最一開始其實是我去柏林參加兩次 ownCloud 黑客松回來之後產生的想法。感覺,對於這些歐洲開發者(裡面大概一半是歐洲其他地方來的)來說,寫開源專案好像只是「空閒時間跟朋友進行的休閒活動」而已,可能跟我們會約朋友一起打球很像。就算一開始不認識,也會透過 IRC 上面的閒聊(通常不會在 GitHub 或是 mailing list 上面閒聊)互相認識,而且大概又因為是屬於相近的文化圈和時區,本來的同質性就高,所以到最後多半可以互相認識。——感覺有點像在臺灣參加社群研討會籌辦一樣,大家一開始不認識,但是在為了同個目標工作的過程熟悉了彼此。

「貢獻自由開源軟體在歐洲是一件稀鬆平常的事情」,也跟風氣脫不了關係。很多人都在做,所以不覺得有什麼稀奇。在臺灣除了一開始貢獻的人數就比較少,二方面是,貢獻者之間的連結似乎沒有像在歐洲那麼強,很容易只知道自己的專案,不知道有其他人在寫、在寫些什麼,所以感覺上自由軟體貢獻者更少了。而自由軟體貢獻者在臺灣的稀少性,更強化了「貢獻自由軟體的人都很厲害」、「要很厲害的人才能貢獻自由軟體」的想法,無形中產生了心理上的門檻。

——

我也是那種新奇想法很多,但是很少堅持到底完成一個專案的人。我的興趣變的太快,幾乎每一天都在變,今天想 hack 某個專案,明天想讀另一個專案的程式碼,後天想研究什麼東西的架構。更別說每個禮拜還會突然發現某個功能很重要,為什麼沒有,甚至在洗澡的時候冒出超酷炫新專案的構想。構想的實現速度永遠比不上增加的速度還有在不同計劃之間 context switch 的時間。

計劃這麼多,卻因為自己似乎對什麼都有興趣,什麼都想學,反而沒什麼實際產出。這個問題苦惱了我很久,直到鳳梨酥計劃開始之後我才發現解法就是找人一起來。

鳳梨酥計劃的開始,還有高中的時候和同學整個暑假開發學校網站的經驗很類似。鳳梨酥計劃一開始只不過是因為我們都覺得在 OpenStack 上面跑 FreeBSD 很麻煩,於是隨口在社辦約了黑客松,另一個人看到我們的黑客松也說要加入,就形成了這樣的三人團隊。裡面正好我搞 OpenStack ,負責手動測試我們的 code ,Iblis 寫骯髒的 shell command ,Apua 寫 Python 。我們只花了大概三四次黑客松就把最基本的功能完成。每一次黑客松都很開心,大家遇到哪裡卡住馬上可以問另一個人,馬上測試也可以讓寫 code 的人有馬上的回饋,然後最後大家再說說笑笑去吃宵夜。高中的時候則是,我記得整個暑假我們不是泡在社辦(還用櫃子在角落隔出一個空間,裡面鋪上學校新採購電腦主機的大片包裝用塑膠軟墊,讓我躲在裡面睡午覺),就是整天掛在 Skype 上面 cowork 。

有朋友一起寫程式,不只是比較好玩、有人可以討論,對於我這樣三分鐘熱度每天轉移焦點的人,為了不和朋友失約,可以約束自己專注在一個專案比較久而不會分心去玩其他東西。

所以從這兩次的經驗,我瞭解到要做長久的專案,一定要找到志同道合的朋友。

——

既然如此,下一步很簡單,我就想辦法找人一起寫我覺得很有趣的專案就好了,一開始我一廂情願地覺得我只要跟他們解釋這個專案的願景,還有我發現他們現在沒有的功能、可以從哪裡參考類似的實作、有了這個功能之後世界是多麼美好,就可以說服他們一起來跟我寫 code 。——顯然我錯了,出乎當時的我的意料之外,我講的幾乎每一個構想,朋友們聽了之後的回應大多都是「哦,我覺得還好啊」。

這時候我才意識到,即使同為程式設計師,人之間的興趣還是有如此鴻溝般的差異。

也差不多是同個時期,我正在為自己維護的開源專案感到心煩,一個承諾已久的重大功能。雖說是重大功能,實在提不起動力實作,不是因為難度太高,而是因為完全沒有技術創新性,總覺得不過就是 API 接一接這樣簡單的事情。這樣一拖就拖了兩年了, ownCloud 都裂成兩半變成 Nextcloud 了。

我想到,有這麼多人想要踏入開源軟體的開發,也有許多開發者因為必須要開發那些不算是重複但是技術不有趣的必要功能感到厭煩(像我一樣),這兩者是不是可以結合,讓這些原本的維護者懶得寫的 code 作為新進開發者熟悉專案的練習?

這就是程式路跑活動的初步想像。

——

我和子期也開始進行很多討論,尤其是:我們到底要找哪一些專案的導師來?

一開始的想法很模糊,大概是「不要找那些商業型的開源專案」,有很多公司將專案開源只是為了行銷並且獲得免費的開發人力,舉個最極端的例子就是 MIUI ,早期很熱門的 Android 第三方韌體,一開始是開源的,因為漂亮的界面吸引了很多人,開發者免費幫他們把 ROM 移植到不同裝置上面,使用者則是開開心心地體驗了小米公司的軟體,順便幫忙推廣給親友。後來知名度高了,小米公司就拋棄開源的 MIUI 維護,不再釋出新版 MIUI 的源碼。高明的行銷。(順帶一提,我感覺以後 Deepin Linux 也會這樣,中國沒有什麼軟體公司真的有社群精神或是社會責任的,一切以賺錢為優先,大概是競爭激烈的文化氛圍所造就的吧)

另一種商業型的開源專案則像是 OpenStack ,OpenStack 能夠維持開源同時維持熱門,主要的原因就只是對於這些參與 OpenStack 開發的公司來說,開源是能夠創造最大利益的選項,雖然無法排除競爭者從原始碼得利,但大家一起合作寫 code ,這些比較小的公司也才有機會和大型競爭對手 VMWare 甚至是 AWS 競爭,他們可以基於這個共同的開源平臺開發專屬的、不開源的武器,因為只要是相容於 OpenStack 的就可以使用,拉近了這些小公司和大型競爭對手的距離,然後再用專屬的武器突圍。

OpenStack 這樣的專案絕對堪稱是開源軟體的典範——但我們還是不希望程式路跑納入 OpenStack ,原因是一般的個人使用者幾乎不可能會直接用到 OpenStack ,而既然程式路跑以純粹個人的背景出發,我們考量的也是廣大個人用戶的利益,引用自活動的 FAQ:

有許多 FOSS 軟體背後有企業支持,如 OpenStack, Tensorflow ,有企業支援,這些專案要找到貢獻者相對容易,相對來說有許多得不到企業支持的 FOSS 軟體,只能靠現有貢獻者的熱情,甚至捐獻金錢才得以繼續,身為一個保持自由開源理念、駭客精神的個人,我們(主辦人)想要將我們的一己之力集中在沒有企業支持的 FOSS 軟體。

這樣的選擇,也是出自於一個疑問:臺灣這麼多 Linux/FreeBSD 桌面環境的使用者,其中有不少具有相當的程式能力,為什麼一些重要的桌面環境開源專案,像是 GNOME, KDE, ibus-chewing, Firefox 的臺灣開發者還是這麼少?(甚至是 bug report 來自臺灣的都很少?)

選擇開源桌面環境的使用者,我想或多或少都抱持一點理想性,認為自由軟體才能帶來使用資訊科技時真正的自由。而這點理想性,是我們以學生、年輕人,還不必負擔太多社會現實的身份負擔得起的,所以我們花時間精力舉辦的程式路跑,希望集中力量在這樣的自由軟體上面。

——

這個活動非常高興能夠獲得各方支持,尤其是幾位導師,Tim, Weicheng, 呂行, Mark, Acelan, Franklin, 4$ ,幾乎什麼都沒有問的馬上就答應支持,中華民國自由軟體協會慷慨的經費贊助,還有師大資訊社阿哲幫我們弄到場地。

我覺得活動算是蠻順利,結果也很成功,大家都有作出貢獻,幾個 bug report, patch 。也真的有產生出我想要的那個氛圍——坐在教室,真的有那麼一刻,我以為我回到 ownCloud 黑客松那時候柏林工業大學的教室裡面,大家吃東西討論 code ,很歡樂的黑客松的感覺。

希望真的有幫到臺灣的自由軟體和開發者就是。

(跳過八月的文章沒寫這次居然寫了三千多字,就當作是補償吧,發了之後 WordPress 告訴我這是這個部落格第兩百篇文章啦,真是值得慶祝)