2016年5月30日 星期一

The man who knew infinity (有電)

星期日下午去看了電影<The man who knew infinity>,中譯<天才無限家>,是二十世紀初數學家Ramanujan 的傳記電影。

都是傳記電影,不免要跟2015/2的Imitation game 相比較,這類科學人物知名度不高,也還沒收入所謂<偉人傳記>中,對普羅大眾來說都相當陌生,Turing 因為是電機與資訊界的祖師,至少新聞報個Turing Award還聽過(等等,有新聞會報這個嗎…),Ramanujan則更狹隘,大概只剩下純數領域的人會知道他哪位了。

電影算是平鋪直敘,從Ramanujan 在印度懷才不遇,來到劍橋和Prof. Hardy 工作,證明出一系列公式,最終取得劍橋大學院士資格回到印度,卻英年早逝。
電影集中在他待在劍橋的5年間,要克服種族歧視、生活、戰爭種種困難,取得成就,又要掛心千里外的妻子,整體俐落大方,適時加上Hardy 無神論與Ramanujan 身為虔誠教徒的思想辯證;Hardy為Ramanujan 爭取fellow,以純數領域純粹的美讓眾人跨越種族與人身的岐視,導演在這處理得洽到好處,強而有理卻又不顯突兀。
當Ramanujan接受fellow 資格時,也是回過頭來為數學在科學界至高無上的地位,表達最高的敬意。

在處理上,我認為The man who knew infinity 勝過 Imitation Game,後者畢竟商業氣息過重,為求戲劇化改編了太多東西,多到該片wiki 條目必須加上Accuracy一段,回想起來,就會覺得該片有點假,而傳記電影卻要求那個<真>;The man who knew infinity 就不會有這種感覺。
https://en.wikipedia.org/wiki/The_Imitation_Game#Accuracy

Ramanujan 一生留下大量數學研究,電影並未多加著墨,大部分都是紙上的數學式子帶過,也造成看完後看不出片名knew infinity 是指什麼
畢竟純數學的概念實在不好解釋,導演選擇Hardy 和Ramanujan 合作研究,比較好懂的Partition 問題;利用Hardy展示P(4) = 5和P(100) = 190,569,292,讓大家感受一下問題有多難;不然Ramanujan其他研究…真正讓他贏得knew infinity之名的那堆無限級數,觀眾大概只會覺得「呃…三小?很厲害嗎?」

是說partition 的數列有收錄在oeis 裡呢XD
https://oeis.org/A000041
numberphile 也有相關的介紹:
https://www.youtube.com/watch?v=NjCIq58rZ8I

雖然本片個人評價正向,還是覺得有些敗筆:
  • 翻譯問題,不知道為啥Fellow 都翻譯成<研究員>,雖然說是沒翻錯啦,但這樣就超弱的Orz,明明應該翻皇家學院<院士>,劍橋學院<院士>比較好呀
  • 無法理解的轟炸場景:這段很顯然是改寫史實,一次世界大戰時英國雖然在戰場上損失慘重,但本土轟炸少之又少,遑論劍橋地區,這段來得快去得也快,感覺是為了有點聲光效果加上去,讓學VFX 的血汗工程師糊口飯吃,讓人覺得一頭霧水。
  • 另一個敗筆是結尾,傳記電影到結尾總是要來點真實事蹟作個點綴,展示一下Ramanujan 和妻子的真實照片、展示在圖書館的手稿,旁白字幕大概是這麼寫的:「1976年,Ramanujan 一份手稿被發現,他的數學公式現今被應用到理解黑洞運作上」
結尾來看,這段話還是說了:Ramanujan的天才發現,仍然是「有用的」「可應用的」,可是整部片不斷闡述的觀念是啥?不就是Hardy、Ramanujan等人對數學的追求,不為什麼,為了就是那個純粹超脫世俗的「美」,那個低調卻又凌駕萬物的真理?
正如片頭引用Russel 的話:Mathematics, rightly viewed, possesses not only truth, but supreme beauty
純數學不問有何用,只是欣賞、讚嘆它的規則,明明全片表現得可圈可點,卻在最後錯了一個音符。

總歸來說,這部片大概註定一個小眾片,我看的電影院只用5排的小廳在播,也不像Imitation Game 有Benedict撐腰(?,票房大概也就不上不下,不過如果受夠了充滿了VFX特效電影,想看一點純粹敘事電影放鬆心靈,The man who knew infinity 應該是近期不錯的選擇,就算太無聊,睡個2小時也可以當作休養身心(X。
這倒是讓我想到,之前看美國隊長3,Cast 的部分做VFX 的公司至少有10家以上,The man who knew infinity:兩家XD

從Imitation Game 到The man who knew infinity(其實之前還有The Theory of Everything,不過那部我沒看),都是以特定領域知名科學家為藍本,讓我開始懷疑Hollywood 是不是把目光轉向這類故事了?
自己的感覺,值得搬上大螢幕的,像是那位身處男性強勢的資訊學界,卻一手開啟高階語言,「大家都不相信我,我寫了個編譯器卻沒人要碰它」的Grace Hopper;科技界兩位工程師競爭發明積體電路,二十世紀初太多科學家的故事未被世人所知。
https://en.wikipedia.org/wiki/Grace_Hopper
//美國海軍竟然有一艘驅逐艦(DDG-70 Hopper)以她為名lolololol
儘管科學家的故事通常…有點沉悶,但就如Imitation Game 選用同性戀當切入,The man who knew infinity 選用數學跨越種族與世俗的鴻溝,經過適當改編和潤飾,仍然能讓劇情富有張力,進而讓世人認識他/她們,就讓我們期待編劇們的功力吧。

2016年5月23日 星期一

一樁因為版本升級引發的慘案

Minecraft升上1.9板已經有一段時間了,因為1.9版加入了戰鬥功能,玩家能在左手跟右手上放置不同的物品,也因此造成了一些悲劇。

故事是這樣子的,之前寫的Minecraft plugin fastbuild,放置方塊時可以大量放置的功能
http://yodalee.blogspot.tw/2014/02/minecraft-plugin-fastbuild.html
設計上我是先取得玩家手上的物品,一個ItemStack 的物件。
計算所能放置的數量,從ItemStack 減去放置的數量,再call API將玩家手上的物品設為ItemStack。

問題出在現在Minecraft 1.9允許有兩隻手,如果將物品放在左手,則放置會將右手設為ItemStack,若右手空手就變成憑空複製物品。

解決方式是判斷玩家在放置物品是從左手放還是右手放,在設定手上物品時設定為玩家使用的那隻手,新的API 針對兩種手有不用的設定function,用新的API 解掉即可。
不過在修掉之前,server 上已經有人用這樣的複製功能弄了一大堆鑽石磚,還在我家旁蓋了一座鑽石塔,根本嘲諷點滿了XD (不過這座塔因為衝到旁邊的建案,應該會被我都更掉)


總之,當主程式和API 的不斷更新的時候,自己寫的程式是也要時時跟上最新,否則不知不覺中就會噴出bugs 來。

當然這樣的升級也不是不好,之前每個block 的型態是用 int 來表示,要比對型態就要自己去查每個物品的編號,新版的API 已經將所有物品用Enum 再包一層,使用真實名字來代表物品,撰寫時不再需要自己查編號值,相對來說好寫得多。

2016年5月22日 星期日

使用GAE python自幹Facebook Bot

話說最近各種Bot 的傳聞,又看到如<參考文件1>有人弄了一個建在Flask 上面的Facebook Bot,強者我同學qcl 也弄了傳說中的libGirlfriendFramework,就想來弄一個回應產生器,以下是大概的開發流程:

首先先在Facebook 頁面上申請一個粉絲專頁,可以先使用「未發佈專頁」大家就不會搜到這個專頁;另外要申請應用程式,其實Facebook 的說明文件已經寫得滿清楚了,申請的部分照著做就是了
https://developers.facebook.com/docs/messenger-platform/quickstart

進到應用程式主控板,選左列<+新增產品>並選擇<messenger>,使用Facebook messenger platform。
接著在messenger 裡,粉絲專頁選擇自己的粉絲專頁,拿到粉絲專頁的token,記起來下面會用;下方設定webhook-edit event,回呼網址是你伺服器的網址,必須透過https 連線,驗證權杖則隨你喜好設定一段字串。

如果有看下面<參考文件1>,因為它的server 看來是買自己網域建在自家主機上面,所以在https 的部分比較麻煩,要自己用Let's encrypt 去生一個CA出來,因為我們是用GAE,網域直接走Google 的CA,所以這步可以省下來;這步卡了我卡超久,Let's encrypt 跟GAE 不太合,怎麼裝都裝不上去;經強者我同學qcl 大神提醒才發現根本不用理這個,這時上午已經過去了,當下覺得蠢。

第一步就是把webhook 裝上去,首先連接webhook 的route:
app = webapp2.WSGIApplication([
  ('/webhook', FBwebhook),
], debug=True)

並實作 get handler,所謂verificaion token就是上面寫驗證權杖,寫到這裡可以如參考資料1用Postman去檢驗是否有問題:
class FBwebhook(webapp2.RequestHandler):
  def get(self):
    verification_code = "Verification Token Here"
    verify_token = self.request.get('hub.verify_token')
    verify_challenge = self.request.get('hub.challenge')
    if verification_code == verify_token:
      self.response.write(verify_challenge)

實作完成後連接webhook 的地方應該就能通過了,四個選項依自己的需要選擇:
  • messages:接收訊息的callback,最基本都有這個,這個都沒勾你連接messenger 幹嘛XD
  • message_deliveries:傳送訊息的callback
  • messaging_optins:連接Send-to-Messenger plugin
  • messaging_postbacks:連接postback button的事件
上面四個我只勾了messages 可是也可以正常接受、發送訊息,其他三個光看說明看不懂是要幹嘛,有人知道的話歡迎解惑。

連接了webhook 就能向Facebook 註冊你的應用程式了,依照getting started 的頁面指示發送要求,token請換成你粉絲專頁的token:
curl -ik -X POST "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=<token>

理應會收到
{“success”: true}
現在可以真的在facebook粉絲頁丟訊息了,它會向webhook設定的回呼網址發送Post,getting started 的頁面有介紹傳來的json 格式,可在webhook中建post handler然後 print(self.request.body),就能從google cloud platform 的紀錄中撈到:

以下是撈到的內容:
{
"object":"page",
"entry":[
  {
  "id":"page id",
  "time":1463907808653,
  "messaging":[
    {
    "sender":{"id":"sender id"},
    "recipient":{"id":"recipient id"},
    "timestamp":1463907808591,
    "message":{
      "mid":"mid.1463907808584:503df60b4ad4529365",
      "seq":7,
      "text":"XDDD"}
    }
  ]}
]}

處理訊息用python json 就行了:
message_entry = json.loads(self.request.body)['entry']
for entry in message_entry:
    messagings = entry['messaging']
    for message in messagings:
        sender = message['sender']['id']
        if message.get('message'):
            text = message['message']['text']
            print(u"{} says {}".format(sender, text))

到這裡應該可以在你的google cloud platform 紀錄中找到你發送訊息的內容,下一步就是回訊息,只要向粉絲專頁的網址,搭配token發送post 訊息即可,很容易…個頭:
def send_fb_message(self, to, message):
  post_url = "https://graph.facebook.com/v2.6/me/messages?access_token={token}"
    .format(token=FBtoken)
  response_message = json.dumps(
    {"recipient": {"id": to},
     "message": {"text": message}})
  result = urlfetch.fetch(
    url=post_url,
    headers={"Content-Type": "application/json"},
    payload=response_message,
    method=urlfetch.POST)

  print("[{}] reply to {}: {}".format(result, to.encode('utf-8'), message))

要注意的一個是,因為google appengin python 一直停留在python2.7 ,所以unicode handler不若python3 這麼完整,上面很多encode('utf-8')都是不斷錯誤後加上去的,也曾經發送訊息「太強啦」結果GAE 整個當掉,因為這三個字一直引發handler crash,handler沒有回音導致Facebook又發送一次「太強啦」過來,然後就無限loop 了,這時要用上面的curl 命令,把你註冊的程式refresh 一下,讓Facebook 不要再發訊息過來。

為了這堆unicode 又花掉一個下午,寫這個簡單的Bot 一天就用掉了…寫到這裡我突然想到那篇傳奇文章「軟體工程師的鄙視鏈」裡面那句:
用 Python 3 的工程師鄙視還在用 Python 2 的工程師,用 Python 2 的工程師鄙視遇到 UnicodeEncodeError 的工程師。
完了我要被鄙視了QAQ

總之最後結果像這樣:

我曾經很認真地想過這個功能到底有什麼用,後來我想到,例如中央氣象局的粉絲頁就能加入註冊跟發送訊息的功能,我們可以發送訊息給該粉絲頁:「註冊/台北」或「註冊/高雄」
後端的handler 在接受這樣的訊息時,將發送者的ID跟地點加入後端的資料庫中,如地震通報或是每日當地的氣象預報就能自動發訊息給每位註冊的使用者。

不過目前沒看到非常印象深刻的應用就是了。

Project 放在這裡,星星就…隨便啦,其實沒有很需要=_=
https://github.com/yodalee/IPban-bot

順帶一提,強者我同學qcl 也有一個類似的project,現在亟需開發者貢獻,據說已經辦了兩次全球開發者大會,各種生猛:
https://github.com/libGF/libGirlfriendFramework

參考文件:
1.使用Flask開發Facebook Message Bot:
http://enginebai.logdown.com/posts/733000/python-facebook-bot
2. Facebook message platform 文件:
https://developers.facebook.com/docs/messenger-platform

2016年5月13日 星期五

在X86機器上debug ARM 執行檔

以後有可能會用到,寫這篇純粹做個記錄。

故事是這樣子的,最近閒來無事研究一下傳說中 jserv 大神的amacc,有些地方實在看不出程式執行至此時一些變數的值為何,這時我們就要用gdb 了
不過amacc 是用 arm-linux-gnueabihf-gcc 編出來的arm 執行檔,我們host gdb 是X86 在執行時就會報錯:可執行檔格式錯誤
如果用arm-linux-gnueabihf-gdb 呢:它會寫 Don't know how to run.

我們需要用到server-client 的架構,server 端在實體target 上可以用 gdbserver,這會需要對gdb-server, gdb 特別編譯;gdb configure target 為arm-linux-gnueabi,gdbserver configure host 為arm-linux-gnueabi。
如這篇所述:
https://sourceware.org/gdb/wiki/BuildingCrossGDBandGDBserver

我們可以用qemu 的 debug 來代替gdbserver:
首先執行qemu ,指定debug 的port 為9453:
qemu-arm -L /usr/arm-linux-gnueabihf -g 9453 amacc tests/shift.c

在另外一個終端機,打開arm-linux-gnueabihf-gdb,這是已經configure target為arm-linux-gnueabi 的gdb:
arm-linux-gnueabihf-gdb ./amacc tests/shift.c

在gdb 裡面連接remote target:
target remote localhost:9453

再來就能用c 開始跑了,happy debug。

相關參考:
http://kezeodsnx.pixnet.net/blog/post/31901130-gdbserver-remote-debug-%E6%B8%AC%E8%A9%A6

2016年5月10日 星期二

使用Rust generic 實作九九乘法表

之前看到一些瘋狂的程式設計師,用C++的template實作九九乘法表,大體的概念就是利用編譯器展開template ,並設定特化的template 作為終止條件,像這個:
用 C++ template 實作九九乘法表

我們可以用 Rust 的generic type 做到類似的事情,概念是一樣的
試過用Rust 的Macro 來寫,這樣會遇到問題,如下如果我們接到一個table,對它展開:
macro_rules! node {
  ( $x:expr, $y:expr ) =>; {
    println!("{}*{}={}", $x, $y, $x*$y);
  }
}

這樣一個node 是沒問題的,但在進行row 展開時,macro 並不像template 一樣會對特化優先匹配,因此
macro_rules! row {
  ( $x:expr, 1) =>; {
    node!($x, $y)
  };
  ( $x:expr, $y:expr ) =>; {
    row!($x, $y-1)
    node!($x, $y)
  };
}
是沒有用的,編譯時仍會在展開 row! 那行發出警告recursion limit reached。

用generic 的function 來寫,其實就一般般,我們定義Node, Row, Table function,使用型別T 作為generic型別,Table 在row 不為一的時候會特化為row 少一的 Table 和Row;Row 在col 不為一的時候會特化為col 少一的Row 和Node,反之則只特化為Row 跟Node。
為了特化時的運算,我們對型別 T至少要有下面那一大排的要求:

  • Copy: 可複製,否則類似下面的row 被傳入Row 跟Node function 中,use moved value
  • PartialOrd: 可比較大小,用在 col > T::one()
  • One: T 有定義 one(),對大多數的Rust primitive type,都有定義Zero 跟One 兩種屬性,可以用在Add 跟 Mul,即Add T::zero() 其值不變,Mul T::one() 其值不變,不知道為啥Rust 核心對這部分好像會大改,用了它們也要在程式加上#![feature(zero_one)]才會動
  • Sub<T, Output=T>: T可以減T 得到一個T,為了下面的 col-T::one(),
  • Mul<T, Output=T>: T可以乘T 得到一個T,為了最裡面的 row * col = (row * col)
完整的Row 程式為:
fn Row(row: T, col: T) {
  where T: Copy+PartialOrd+One+Sub+Mul+Debug {
  if col > T::one() {
    Row(row, col-T::one());
  }
  Node(row, col);
  print!("\t");
}
Table function 類似,只是判斷對象變成row;Node function 則是印出結果。主程式就呼叫 Table(9u32, 9u32) 就能看見漂亮的九九乘法表了。

怎麼說呢,感覺跟C++ template 的寫法還是有點不同的感覺呢…

2016年5月9日 星期一

Modern C

本書的全文在網路就下載得到,目前也只有英文網路資源,沒有出實體書和翻譯本的樣子:
http://icube-icps.unistra.fr/img_auth.php/d/db/ModernC.pdf

從書名和它的序言,作者旨在對 C language 有個基礎的介紹,由於C 的<簡單>,能讓程式設計師快速寫出可以動的程式,例如Hello World,反倒使人忽略了存在C 背後種種的議題;同時 C經歷多次標準改進,和當年的 K&R C 已經頗有出入,本書從 level 0 - 4,從簡單到複雜再次檢視C 語言中的概念。

架構其實沒差太多,從控制結構、資料型別、array, struct, enum 等等,書中不時列出一些 <Rule>做為重點提示,像是建議、警告,和一般C 語言的書比較不同是,它會去討論一些背後的概念,例如unsigned int 的值是如何得來;comma operator 回傳最後一個expr 的定義不小心會讓你debug 超久;各種資料型別極限值與轉換時數字的變換…

雖然個人寫C 也有一段時間,不過重新細看書內的介紹,還是會發現一些之前沒想過的陷阱,有些章節例如第九章是C Coding Style,可能會引發宗教戰爭(X,覺得已經純熟的章節可以看過去就好。

最後的 Level 4: Ambition 可能是我目前看過C language 相關最有野心的一章,大多數 C lang 的書只專注在「把C 講好」這件事,Ambition 這章跟現行的C 語言無關,而是提出作者的見解:如何修改標準「讓C 更好」。
如果只是想更親近C 語言的人,可以明正言順的略過這章,畢竟這章節需要對C 標準、編譯-器實作與程式最佳化有更多認識後,才能理解箇中大意與作者意圖,不然只是看著書中列出一段C standard,說應該改成怎樣怎樣,應該不用五分鐘就可以安然入眠了,個人最後也是看得一頭霧水QAQ

要我說對這本書的整體心得,該說隨著C/C++ 標準進化的同時,更適合的寫法也推陳出新,絕對避免的寫法也所在多有,但很無奈的為了相容之前的標準,過去的用法會一直留在那裡,等待天真不知情的新手程式設計師去踩雷然後~~~~~~~~EXPLOSION~~~~~~~~
學習C/C++的問題並不是學不會什麼生猛功能,而是要在各種實作的方法中學習:「怎麼用比較<適合>的方法來實作,避免哪些有問題的寫法,比較好的方法和概念是什麼?為何如此」
像是避免用scanf 造成overflow 的bug,這需要程式設計師去學習正確的寫法;之前所寫的option type,強者我同學的註解:「C++ boost 已經收入option,之後很可能也會收入標準」
但null pointer 在C++中仍然允許,寫出Girl *gf = nullptr 讓 nullptr 把程式炸了無疑是合法的,畢竟C/C++ 都假定程式設計師是聰明人,會對自己寫的code 負責。

這本書前半部未必適合新手程式設計師,比較適合已經有些了解的人,再次檢視自己所學的內容;後半部則適合對C, OS, compiler 都有詳加研究的,栽進去與作者一同讓這款有44 年歷史的語言更加完善。

2016年5月4日 星期三

Python 參數產生unittest

最近在寫傳說中 jserv 大神的amacc,一個奉行「極致的簡」的C compiler
參與專案的第一步當然是先看issues,那時剛好看到這個:
https://github.com/jserv/amacc/issues/13
看起來不算太難,改一下code 執行流程就好了

不過首先,這個project 有點難以測試,的確make check 會嘗試編譯所有tests/*.c 檔,並且用jit 和產生elf 的方式去執行,可是卻不會通知結果是不是正確的,nested for loop 的結果也會和其他檔案混在一起,直接下指令去測又很麻煩(要用qemu,指令好長…)

覺得測試這麼麻煩,連帶著改issue 也好麻煩的感覺,因此決定不想改了先來幫這個project 加上一些便於測試的功能

想到test 就想到python unittest,設計概念是:利用python subprocess 去呼叫amacc跟arm-linux-gnueabihf-gcc 分別編譯執行檔,執行後,直接比較兩者的output,看結果是否相同,如此就能驗證amacc 的行為(這有個問題是gcc 未必遵照C standard,真正正確的答案應該要看C standard 才對,不過我們假定大多數狀況gcc會遵照C standard)

這裡遇到一個問題,在tests 裡面有許多的c files,因為對每個檔案要做的事情其實是一樣的,自己寫只會變成複製貼上,還可能貼錯內容;寫一個test 去跑所有檔案也不行,這樣等於是所有測試混在一起,test 沒過可能是任一個檔案有錯,根本看不出是誰錯了。

所幸這個解法也不困難,簡單google 就找到了:

概念是,本來的module 變成一個容器,裡面要自己寫的function 就不寫了:
class TestAmacc(unittest.TestCase):
  pass

另外寫一個共同的test generator,會傳回測試的function,我這個test function 裡面就是本來要對檔案做的事:amacc編譯、gcc 編譯、執行、比較結果,參數f為要執行的檔名:
def testGenerator(f):
  def test(self):
  # test function here
return test

最後是對每個檔案去呼叫這個generator,利用setattr 的方式,把這個function 督進先前宣告的容器當中,python 的彈性由此可見:
for dirpath, _, filenames in os.walk("tests"):
  for f in filter(lambda name: namePattern in name, filenames):
    testfile = os.path.abspath(os.path.join(dirpath, f))
    test_func = testGenerator(testfile)
    setattr(TestAmacc, 'test_%s' % (os.path.splitext(f)[0]), test_func)
unittest.main(argv=[sys.argv[0]])

如此就能自動產生test case 了,如上所示,還可以幫檔名加上filter,用參數來指定要跑什麼測試,極度方便;這裡遇到一點卡關是,unittest 預設會吃主程式的argv作為要跑的test module 名稱,argv 加上參數的話會讓unittest 炸開,必須要避免unittest.main 吃到不是給它的argv 參數以,免它找不到測試module 直接回報出錯。

2016年5月1日 星期日

退伍感言

原文寫於大兵日記最後一頁,寫作角度其實不全然是當兵,比較像是在部隊的退伍感言,本來應該是退伍當日要PO 的,不過你知道的……懶嘛日記要先打好再來打退伍感言

記得去年5月入伍,正是天氣開始轉熱之時,天氣熱得要死,新訓單位還一堆蚊子,要是有登革熱我敢打賭那裡一定大感染,那時我就對自己說:「天氣越冷越好,因為當天氣冷過開始回暖,就是我要退伍了」,雖然後來冷到2度真的是有點太冷了Orz
很多人會跟我說:「好好我要退伍了」我很懂那個感受,我剛到部一個星期就有人退了,我也跟他怎麼說過,日子就是一天一天過,回頭一看突然就要退了,這就是我對當兵這年的評語:度日如年、度年如日

很幸運當初以四分之一的神抽,抽中金門,前一位抽到東部海巡署一直高興的跟我握手,其實怎麼想金門都比東部好,回台灣搭個飛機噗茲一聲就到了,不像東部搭火車四個小時跑不掉,也沒有離島這樣的長假可以放,軍包機可以搭;抽中的連隊不需要戰備,雖然一到部就連續三個星期沒放假,但任務過後,平常有充分的時間做自己想做的事,伙食也讚
到部前吃過新訓、伙食外包的南通校、罐頭天堂前運隊,沒一個地方的伙食比這裡好,到部第一天早餐吃漢堡,中午進伙房還看到烤盤上滿滿的雞腿都快驚呆了,旁邊忘了哪位還不放過我這個菜逼八,還問:「你看啦早餐吃這樣像話嗎?」請問到部一天的單兵如何回應?這單位的伙食也太誇張了吧

當兵到現在學會:用槍、爬電線桿、在連上當行政學會記帳和財務,曾經拿了兩張紙匯出1,000,000元現金;曾經在大家面前從電線桿上摔下來;曾經在跨年時站哨跨年,看天空隨煙火一明一暗;曾經為了教召2320回營,接著還要站24-02;也曾經情緒失控對著長官大吼大叫;工作壓力太大在被輔導長念到淚灑行政室。
除了部隊的事,在放假期間也沒閒著,感謝班長慷慨借我腳踏車(well 其實班長根本沒在騎,我不騎它就變廢鐵了),它陪我度過無數次島休和洽公,騎著腳踏車環島金門一圈,每日往返部隊與市區;入伍投稿先前量測的電路,利用放假的時間在網咖修改paper,印著reference 跟稿件回營閱讀與修改,終於在3月初將完稿給投出去,只要有心(也許還有沒遇到基地XD),無論看書還是開手機練功,在部隊平時的時間其實很多,可以做到很多平常不會做的事。

當兵一年讓我經歷這些、學會這些,儘管這一年漫長而辛苦,我仍相信收穫多於付出,未來很可能不會再與部隊接觸,這段記憶仍會刻骨銘心
末尾,很高興當初抽中這裡,沒有在海巡署虛度光陰,也要謝謝9個月來大家的關照,今天我要退伍了,明天開始會努力向下個人生目標邁進