發表文章

StackOverflow 使用經驗談

圖片
前言 我想大部分的開發者應該都有使用StackOverflow(以下簡稱SO)的習慣,泰勞我也不例外,起初我跟大部分的使用者一樣,遇到問題時上來爬爬文,找到答案複製貼上,問題解決了,程式可以跑了,就將那個分頁給關閉。後來因為一個契機讓我改變了一點想法,進而改變了我的使用方式,我認為這樣的改變對我非常有幫助,有感受到其帶來的正面影響。因此泰勞想藉由這篇文章分享我的使用習慣與經驗,以及我對SO社群的觀察與其潛在價值。 背景 SO是一個全世界開發者聚集的地方,以前我認為所有問題都一定能在上面找到答案,即便是自己發文發問,也都能在很短的時間之內得到回覆。有一次讓我印象很深刻,我在研讀一本探討Android安全的書,其中有一章不太懂,於是上SO搜尋相關問題,意外發現SO上的回答者竟然就是該書作者,當時他的名聲(Reputation)有兩萬九千多分,打從心底佩服這位大師,也是從那時開始,期許自己終有一天要成為SO上的貢獻者。 契機 約莫3年前準備要從學校畢業的某個悠閒早晨,不知道是哪根筋不對,在SO上搜尋了一些跟我所學領域相關的關鍵字,無意間看到一篇沒有人回答的問題,看起來蠻有趣的,而且是個測試一下就能得出答案的題目,並不是那種需要經驗或是著重觀念的問題,想說閒著也是閒著,就來做做實驗吧!經過一個早上的測試,很順利的得出結果,此時心裡有點複雜,因為我在猶豫是否該上SO寫下我的測試結果,我猶豫的原因是SO是全世界開發者聚集的地方,在上面回答一定要非常謹慎,必須確保答案是正確的,否則有可能會誤導其他人,在猶豫的同時感到的是無比興奮,我從來沒有想過我會有機會在SO上回答別人的問題,現在這樣的契機就在眼前,再不快點恐怕就要飛走了。經過幾分鐘理性與感性的糾纏,最後我選擇勇敢的跨出那一步,貼上了測試結果與一點點的文字敘述,此時我的心跳開始加快,血壓飆升,顫抖的右手小心翼翼的按下"Post Your Answer",此時彷彿置身於萬籟俱寂的空城,異常幽靜,映入眼簾的是我的答案出現在SO上面,右下角標示著我的姓名,大頭照以及"answered 7 secs ago",此時我的心情還是很複雜,害怕被其他開發者質問或挑戰,甚至是被扣分檢舉然後帳號被封鎖等等最壞情況,另一方面則是很開心,很開心我能夠為其他開發者解惑,成為SO上的貢獻者,

Docker Prune

圖片
Docker 在清理工作環境這方面,或者是說 Docker 的垃圾回收(Garbage Collection)機制是相對保守的,如果沒有明確指定,Docker 通常是不會主動去刪除不需要和沒在使用的東西。 因此,我們時常需要使用 docker rm 和 docker rmi 來清理工作環境,泰勞本身每天例行性的工作就是清除那些不需要的容器(Container),先列出所有容器,再依序將其刪除,如下列步驟: $ docker ps -a $ docker rm <container-id-1> $ docker rm <container-id-2> ...... 清除不需要的映像檔(Image)也是一樣,先列出所有映像檔,再依序將其刪除。如果需要清除的容器和映像檔很多,一個一個處理實在不是個好辦法。有些人可能會找到一些指令,透過 grep 或 awk 來過濾出想要的資訊,那個方法在很久以前很實用,但是現在已經是西元 2019 年了,當然有更好的選擇~那就是今天的主角 Prune! 參考資料: Prune unused Docker objects    What is a dangling image and what is an unused image ?   清理容器 從Docker 版本 1.13.0 開始,如果需要將所有不需要 、可刪除 、 已停止運作的容器一次清除,指令非常簡單: $ docker container prune 結果如下圖所示,這指令真的讓你瞬間變成清除達人! 雖然這指令很方便使用,不過還是要回到原始問題,如果你的容器在每一次執行結束時,都一定要清除掉,那你應該選擇在啟動容器時就一併使用 --rm 參數,會是更好的選擇喔! 清理映像檔 整理映檔之前,先來了解一下兩種時常需要被清理的映像檔類型。 Unused Images : An unused image means that it has not been assigned or used in a container . For example, when running docker ps –a, it will list all of your exited and curre

Docker Build Context

圖片
建立一個新的 Docker Image 不只需要準備一份 Dockerfile,還需要準備一個 Build Context 給它,放的是一些編譯映像檔所需的檔案或目錄,如此 Dockerfile 才能去 COPY 或 ADD 這些資料到映像檔裡面。Build Context 可以是一個指定的目錄或是 URL,下方是一個常見的編譯指令,最後面那個點的功能就是將 Build Context 設在當前目錄。 $ docker build -t test:1.0 . 當然這是一個理想的狀態,很多時候會遇到一些限制,像是編譯所需的檔案在上層目錄或是其他非常遙遠的地方,那該怎麼辦呢?來看看下面在 Dockerfile 裡面的嘗試。 FROM ubuntu:18.04 RUN apt-get -y update COPY ../test/test.sh /usr/local/bin/test.sh 若事情有這麼簡單就好了,編譯出錯,錯誤訊息如下: 官方文件有提到 ADD 或 COPY 時不允許使用 ../ 這類型的語法,因為指定的資源必須在 Build Context 目錄底下。看來在 Dockerfile 裡面行不通,那就改用其他方法吧! docker build -f 既然 Build Context 的指定方式限制太多,那就反過來指定 Dockerfile 的路徑吧!到 test 目錄底下,透過 -f (--file string) 來指定 Dockerfile 的路徑,這樣就可以將 test 目錄作為 Build Context,然後使用其他目錄的 Dockerfile ,範例如下: context/Dockerfile ............ COPY test.sh /usr/local/bin/test.sh 編譯指令 $ docker build -t test:1.0 -f ../context/Dockerfile . 當然也可以指定當下目錄的 Dockerfile,然後指定 test 目錄作為 Build Context,像是這樣: $ docker build -t test:1.0 -f ./Dockerfile ../test 這裡要小心的是你不能只用 docker

Pygerrit with Gerrit REST API

圖片
Gerrit 是一套開放源始碼 、以 Java 編寫而成的程式碼審查(Code Review)軟體,其功能性質類似於 GitHub,一樣以 Git 作為版本控制的基礎。Gerrit 同時提供了一系列的 API 讓使用者能夠方便讀取和更新資料,其以 REST 風格來做開發,因此稱為 Gerrit REST API 。 Pygerrit 是一個用於與 Gerrit REST API 溝通的 Python 模組,其第一代由 Sony 開發,但目前看起來已經沒有在維護了,幸好有開發者推出了第二代 Pygerrit2 ,讓泰勞可以將很多例行性的工作自動化成 Python 腳本。本文範例所使用的都會是 Pygerrit2 喔! 架設 Gerrit Code Review 在開始測試之前,務必先架設好 Gerrit,最簡單的方式就是使用 Gerrit Docker Image ,只需一行指令,上去建立一個 Repository 再把測試用的專案透過 Git 推送到 Gerrit 即可完成事前步驟。 $ docker run -ti -p 8080:8080 -p 29418:29418 gerritcodereview/gerrit $ git push ssh:// username @ www.gerrit.com :29418/ reponame HEAD:refs/heads/master 安裝 Pygerrit2 $ pip install pygerrit2 --user 撰寫 Python 腳本 先設定待會向 Gerrit 請求資訊時需要的認證。 auth = HTTPBasicAuth('username', 'password') rest = GerritRestAPI(url='http://www.gerrit.com:8080', auth=auth) 若認證沒有問題,就可以開始嘗試請求資訊囉!第一個範例是將所有自己已 Submit 的 Change 列出來,回傳的資訊會是一個 List,稍微處理一下再打印出來。 changes = rest.get ("/changes/ ?q=owner:self%20status:merged

Web Scraping

圖片
泰勞因為好奇,寫了一個 Python 腳本分析這次公投的結果,其實也稱不上是分析,只是很簡單的把同意票與不同意票的資訊抓下來,計算百分比而已。泰勞本身支持以民法保障同性婚姻,因此 公投第14案 是泰勞最關心的議題,本文會以中選會網頁之公投第14案投票結果作為 Web Scraping 的主要範例喔! 聲明:本文章 沒有要討論公投議題的內容。 參考資料: [The Hitchhiker's Guide to Python]HTML Scraping   在開始之前,先安裝 lxml 和 request s 模組。 $ pip instal lxml requests 透過 requests.get 向網頁請求資料,並且確認伺服器回傳的狀態是否正常。 from lxml import html import requests page = requests.get('http://referendum.2018.nat.gov.tw/pc/zh_TW/08/m64000000100000000.html') if page.status_code == requests.codes.ok:     print 'OK!' 再來這步驟比較麻煩,先用網頁的 Inspector 找出你要的資訊所屬的 Elements。 找出對應的 Elements 之後,再用 html 模組和 xpath 函式來解析資料。 # Parse page by using html module tree = html.fromstring(page.content) # Create area list by using xpath function area = tree.xpath('//td[@valign="bottom"]//text()') # Create vote list by using xpath function vote = tree.xpath('//tr[@class="trT"]/td/text()')  印出來看看結果是否正確吧!area list 儲存的要是縣市區名稱,vote list 儲存的

圍凸包(Convex Hull)

圖片
泰勞最近在做一件無聊的事,就是把座標上所有的點,沿著最外圍連成一個多邊形,多邊形內部必須包含所有剩餘的點,同時內部任意兩點的連線不會經過圖形外部,這樣的圖形稱為凸殼(Convex Hull),也有人稱為凸包。 參考資料: [演算法筆記]Convex Hull [Wiki]Algorithm Implementation/Geometry/Convex hull/Monotone chain   泰勞參考了上方網頁的介紹,選了一個自己「喜歡」的方式來實作,代表這絕對「不是最佳解法」,只是其中一個可以解決此問題的方法。如果你有特別的點子,歡迎在下方留言討論,讓泰勞長長知識喔! 泰勞主要參考了 Andrew's Monotone Chain,詳細定義請看上方參考資料,大致上的流程如下所示: 1.將所有點依 X 座標由左至右,再依 Y 座標由下而上排序 2.從最左下方的點開始尋找下半部的凸殼,直到最右上方 3.從最右上方的點開始尋找上半部的凸殼,直到最左下方 下圖是 WikiBooks 提供的 Gif 圖檔,這樣應該比較容易理解。 從程式的角度切入,我們必須先準備兩個物件:點(Node)和線(Line),先來定義這兩個物件所需的內容。 Node類別,包含整數 x 和整數 y,代表座標 (x,y)。 class Node{     private int x;     private int y;     //Setter and Getter     public void setX(int x){       this.x = x;     }     public void setY(int y){       this.y = y;     }     public int getX(){       return this.x;     }     public int getY(){       return this.y;     } }  Line類別,包含兩個 Node 物件,代表線的兩個端點。 class Line{     private Node node1;     private Node node2;     //Setter and Getter     public

Android RenderScript

圖片
上回泰勞介紹了處理圖片特效的方法,這回要來介紹如何提升效能,也許很多人第一時間會想到 JNI,那確實是個不錯的選擇,不過泰勞想介紹一個有點不一樣 、 使用場合跟 JNI 不盡相同的 API,那就是 RenderScript! 參考資料: [Developers]RenderScript Overview [Developers]Type [Developers]Element [Developers]Allocation 使用 RenderScript 最大的優勢在於它可以實現「 平行運算 」,在擁有多核心處理器的裝置上速度一定會快上許多,同時它也支援 GPU。但因為是平行運算,有些場合是不能使用的,當然也有些場合特別適合,像是圖像處理就非常適合使用 RenderScript。 延續上一回的範例,這次改用 RenderScript 來實作負片效果,先準備一個簡單的 Context,作為主程式調用 RenderScript 的中繼站。 RenderScriptContext.java public class RenderScriptContext {   // for RenderScript   private RenderScript rs;   // ScriptC 和底線為格式所需,Invert 是我的 RS 腳本名稱   private ScriptC_Invert scriptC;   // 用於設定 RS 物件類型   private Type rType;   // 將 Java 物件傳給 RS 處理的媒介   private Allocation allocIn;   private Allocation allocOut;   //   private Bitmap outputBitmap;   public RenderScriptContext(Context context, int width, int height) {     // 初始化 RS 的 Context     rs = RenderScript.create(context);     // 建立 ScriptC_Invert 的實例     scriptC = new ScriptC_Invert(rs);     // 定義元素類型與影