發表文章

目前顯示的是 2018的文章

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);     // 定義元素類型與影

圖片特效

圖片
一開始以為寫程式製作圖片特效是很複雜困難的事情,最近接觸了一點點之後,發現其實沒有想像中的那麼難,並不是什麼天才科學家才能做的事呢!本章將示範在 Android 上實作修圖特效,並以簡單的負片效果作為範例。 參考資料: [Android Developer]Color 首先介紹一下負片效果,簡單的說就是將色彩反轉,以補色的模式呈現,例如:黑色(0,0,0)的補色是白色(255,255,255),黃色(255,255,0)的補色是藍色(0,0,255)。在 Android 上處理圖片必須先將圖轉為 Bitmap 格式,才能進行處理。 Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.test); 轉為 Bitmap 格式之後,透過 getPixels 方法將其轉為整數陣列,此時圖上的每一個像素都已經分別轉為一個個整數並且存放在整數陣列裡面,而在 Java 裡面一個 int 是 32 位元,所以此時你看到的整數,這 32 位元包含:透明度 ( alpha) 、紅(r) 、藍(g) 、綠(b)。拆解開來之後就可以進行補色的運算囉! public Bitmap invertColor(Bitmap bitmap) {     int width = bitmap.getWidth();     int height = bitmap.getHeight();     int[] pixels = new int[width*height];     // Convert bitmap to int array     bitmap.getPixels(pixels, 0, width, 0, 0, width, height);     for(int i = 0; i < pixels.length; i++){         // Extracted from a color int           int a = (pixels[i]) >> 24 & 0xff ;         int r = (pixels[i]) >> 16 & 0xff ;

Docker 用戶管理

圖片
Docker 容器啟動之後,預設登入的使用者帳號是 root,這會造成一些困擾,像是編譯過程生成的檔案,將會屬於 root 使用者,之後要進行修改或刪除就會碰到權限的問題。因此泰勞找了幾個方式來管理 Docker 用戶與權限設定的問題,在此簡單介紹。 參考資料: [Github]tianon/gosu [Deni Bertovic]Handling permissions with Docker volumes [redbubble]Running a docker container as a non-root user   1. --user 第一種方式,透過參數 --user 來指定容器啟動之後的 UID,這樣一來,在容器內生成的檔案都會屬於特定 UID,方便用戶管理。指令簡短易懂,但也有一些缺點,其中之一就是容器無法得知用戶名稱,如下圖所示。 2. useradd 第二種方式,透過 Dockerfile 建立 Docker 映像檔時,直接新增一個使用者並且將其設定為預設用戶。 Dockerfile FROM ubuntu:18.04 MAINTAINER Kuanlin Chen RUN useradd -ms /bin/bash build USER build 接著編譯 Dockerfile 並且執行 Docker 映像檔,可以看到容器啟動之後,預設的用戶已經不再是 root 了,如下圖所示。 3. gosu 使用 gosu 套件主要目的不僅僅是避免使用 root 帳戶,它最重要的功能是將啟動 Docker 容器的用戶 UID 傳入容器內,意即容器外與容器內的 UID 是一樣的。 撰寫一份 Dockerfile 以及啟動容器時需要的腳本,然後編譯一份新的 Docker 映像檔。 Dockerfile FROM ubuntu:18.04 MAINTAINER Kuanlin Chen RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get -y --no-install-recommends install ca-certificates curl gnupg # Install gosu packa

Docker 圖形界面

圖片
大部份使用 Docker 的時候都僅有終端界面,只能透過指令來操作,但是本人好吃懶做,希望有美美的圖形界面可以使用,因此做了一些功課,發現其實有幾種方式可以讓 Docker 容器運行時具有圖形界面! 參考資料: [Fabio Rehm's Blog]Running GUI apps with Docker Docker這樣學才有趣:從入門,到玩直播、挖礦 Firefox+X11 第一種方式是將 Linux 自身的 X11 分享給 Docker 容器使用,就這麼簡單一句話而已,直接來實作,這裡用 Firefox 瀏覽器作為範例。 Dockerfile FROM ubuntu:18.04 RUN apt-get update && apt-get install -y firefox RUN useradd -ms /bin/bash developer USER developer ENV HOME /home/developer CMD /usr/bin/firefox 接著編譯 Docker 映像檔,然後啟動容器,指令如下所示。 $ docker build -t firefox . $ docker run -ti --rm -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix firefox 若一切順利,就會看到一個貨真價實的 Firefox 被啟動,差別只在於它存在 Docker 容器裡。有沒有覺得很有趣阿! Ubuntu+VNC 這方法是從 「Docker這樣學才有趣 」這本書裡看到的,有興趣的可以去買一本來看。其實原理很簡單,就是安裝一個輕量的桌面環境和一個可以分享螢幕畫面並且遠端操作的軟體,再透過 CMD 指令讓 Docker 容器啟動時執行 VNC Server,啟動之後就可以使用遠端桌面連線工具,連線至具有 GUI 界面的容器囉! Dockerfile FROM ubuntu:14.04 RUN apt-get update && \   DEBIAN_FRONTEND=noninteractive apt-get install -y lxde-core lxterminal tightv

Docker Image Layer

圖片
上面這張圖,如果你已經使用過 Docker,一定不會感到陌生,當我們 Pull 一個 Docker Image 時,時常會看到這樣的畫面,司空見慣 、 不足為奇,那泰勞為什麼要以這張圖為開頭呢?嘿嘿~當然是有其重要之處阿! 不知道有沒有人有過一樣的疑惑,為什麼 Pull 的時候要顯示這些資訊?這些資訊又代表著什麼含意呢?如果你有興趣,那就繼續看下去吧! 參考資料: [StackOverflow]Docker images "Already exists"?   [StackOverflow]What are docker image layers ?   [Docker Docs]Images and Layers   先思考一下,Pull 時顯示的資訊應該跟那個 Image 有相關,而 Pull 的過程列出了很多個雜湊值,這些值所代表的東西,有些已經存在 (Already exists),有些剛完成 Pull (Pull complete),有些還在等待 Pull 的動作 (Waiting),難道這些東西全部合在一起就是一個 Image? 沒錯!這些雜湊值代表的就是一個個 Docker Image Layer ,而一個 Docker Image 就是由數個 Image Layer 所組成!來看一段 Docker 的基本觀念。 (1) Docker container are running systems defined by Docker images. (2) Docker images are made up of one or more Docker layers. (3) Every line in Dockerfile adds up a Docker layer which makes up your Docker image. (1) 如果將 Docker image 比喻成 Java 的類別(Class),那麼 Docker container 就如同在 Java 裡面從某個類別 new 一個實例(Instance)出來。 (2) Docker image 由一或多個 Docker layer 所組成。 (3) 撰寫並且編譯 Dockerfile 可以生成 Docker ima

Git Submodule 除錯

圖片
前言:   網路上已經有很多關於 Git Submodule 的介紹,使用方式 、使用時機等等,都有很可靠的資訊可以參考,因此本篇文章並不會再贅述使用方法,而是著重在泰勞之前遇到的問題,經驗分享以及解決的辦法。   前情提要: 我們先依照下列步驟製造出一個類似的場景,先新增一個 Submodule,然後 接著將 Submodule 裡面的 .git 刪除! $ git submodule add <repository> submodule $ git commit -m "Add submodule" $ cd  submodule $ rm -rf .git 這麼做當然是為了要模擬問題,但是為什麼要這麼做?原因是泰勞曾經拿過一個 Patch,它只是一個目錄,並非 Git Patch,因此我用 cp 將其複製到工作區裡面,並且加入至 Git Stage,就在此時,問題發生了,是我從來沒有看過的錯誤訊息! fatal: Pathspec 'xxx' is in submodule 不管我怎麼做,submodule 目錄都無法被加入!就如同上圖,錯誤訊息顯示此目錄底下的檔案在 Submodule 裡面,泰勞可以合理推測當時那個 Patch,原先在別人手上時,是以 Submodule 的方式做管理,而發出  Patch 的步驟是直接將目錄複製出來給我們,並沒有選擇 Git Patch,才會導致這樣的問題。 解決方式並不複雜,透過 Git 將其刪除,然後再加回來即可。 $ git rm -rf --cached submodule $ git add submodule/ $ git commit -m "Add folder" 這個問題應該不會太常遇到,復現此現象也只是想讓大家知道有這種款式的錯誤訊息,不過,上網查詢資料時,也是有蠻多人表示他們是不小心刪除 .git 造成的 XD 參考資料: [StackOverflow]Git: fatal: Pathspec is in submodule

還原遺失的 Git Commit

圖片
前言: 在 Git 裡頻繁且大量的新增或刪除 Commit 是常有的事,也難免會有些疏失,如果是不小心加入不相關的 Commit,還算是好解決,但萬一不小心刪除,或是不小心遺失了某個重要的 Commit,該怎麼辦呢?除了重新上一個內容一樣的 Commit之外,有沒有其他補救方法呢? 前情提要: 我們 先依照下列步驟製造出一個類似的場景 $ touch abc.txt $ vim abc.txt    ==>  加入字串 defdef $ git add . $ git commit -m "defdef" $ vim abc.txt    ==>  加入字串 ghighi $ git add . $ git commit -m "ghighi" 接著我們將捨棄最新的一個 Commit,並將修改還原為上一個 Commit 的狀態 $ git reset HEAD~    ==>  捨棄最新一個 Commit $ git checkout -- abc.txt    ==>  取消修改 如上圖所示,此時的 abc.txt 裡面沒有字串"ghighi",如果我們想再一次加入字串"ghighi",或者說我想更精準的要求,必須找回剛剛捨棄的那個 Commit 並且將它還原呢? Git Reflog: 答案是使用 git reflog 指令,其實大部分透過 Git 指令的操作,都會紀錄在本地端的倉庫裡,其中包含了 Commit 歷史紀錄,因此 git reflog 非常適用於現在的情況,它會列出本地端目前紀錄過的 Commit,從中找到你想還原的 Commit,透過 Reset 或 Cherry-Pick 將其還原即可! $ git reflog    ==>  找到欲還原的 Commit ID $ git reset --hard <commit-id>    or git cherry-pick <commit-id> 按照上面步驟完成之後,就可以看到剛剛捨棄的 Commit 已經被復原,同時檔案也回復到有字串"ghighi"的狀態囉! 參考

Git 還原特定檔案

圖片
前言: Git 可以透過 Revert 還原某一次的修改,但是以 Commit 為單位去做復原的動作,假如這一次的 Commit 裡面包含了五個檔案的修改,而你只想要復原其中一個檔案,要怎麼做呢? 前情提要: 先依照下列步驟製造出一個類似的場景 $ touch abc.txt $ git add abc.txt $ git commit -m "Add abc.txt" $ touch def.txt $ git add def.txt $ git commit -m "Add def.txt" $ vim abc.txt    ==> 加入字串 $ vim def.txt     ==> 加入字串 $ git add . $ git commit -m "Modify all files" 目前有三個 Commit,其中最新的一個 Commit 同時修改了 abc.txt. 和 def.txt。   假設現在我要還原稍早對於 def.txt 檔案的修改,可以怎麼做呢?我們先來看一個比較不好的操作方式,為什麼不好?稍後會做說明。 $ git reset HEAD~    ==> 復原至上一個 Commit $ git checkout -- def.txt    ==> 取消 def.txt 的修改 $ git add . $ git commit -m "Revert def.txt" 此時 def.txt 已經被還原為原本的樣子,而最新的 Commit 也只有修改 abc.txt,但是,此時的 Commit 歷史紀錄也已經不一樣了 !如果在多人共同開發的情況之下,修改已經 Push 至遠端的歷史紀錄是不被允許的,因此需要特別強調,此方法只能用於本地端,在你還沒將舊的修改 Push 至遠端之前,才可以這麼做喔! 再來要說明的是我比較推薦的操作方式,此方法背後的原理就類似於新增一個新的 Commit,而這 Commit 的內容就是將先前的修改給復原回去,如果修改的內容只有一兩行,直接手動去修改也是沒有問題的,但既然 Git 有提供更方便簡潔的指令,何不嘗試看看呢! Git Checkout:

九州之旅 - 美食筆記

圖片
由於這次九州之旅的景點都比較熱門,網路上已經有很多人分享相關的資訊,因此泰勞就 以「食物 」為主題來撰寫這次的遊記 。有些本來就是網路上的名店 ,有些則是路過嘗試看看 ,總之 ,一定 是 「 我個人覺得好吃 」 的 ,才會分享在本篇文章喔! 1.由布院 - 由布まぶし 心 位於由布院車站不遠處 ,餐點種類不多 ,地雞飯 、鰻魚飯 和豐後牛肉飯。 因為當天排隊人潮眾多 ,老闆說內用最少要等上一個小時 ,建議我們外帶 ,大約只需要等半個小時 ,因此我們選擇外帶回去旅館 。 我們一行四個人 ,點了兩份 地雞飯和兩份 豐後牛肉飯 ,圖片上看起來還好 ,實際上份量是非常可觀的 ,飯給得非常多 ,我們四個人最後白飯都沒有吃完 。地雞跟豐後牛肉都很好吃 ,一定要配上左上角那個醬料 ,兩種哇沙米和蔥 ,加上醬油 ,味道很棒喔!   2.別府 - 地獄蒸し工房 鉄輪 鐵輪算是來到別府必吃的店,但有一道菜一定要特別拿出來講,就是紅色的豬肉,即便蒸熟了仍然是鮮紅色!因為我不知道名稱,所以直接看圖! 為什麼我會不知道它的名字呢?因為這是隔壁桌非常熱心的日本人請我們吃的,那桌日本人不但幫我們挖螺仔肉,還請我們吃這道非常好吃的紅豬肉和蒸南瓜,遞上豬肉時還向我們敬禮!實在是讓人受寵若驚阿!真的非常感謝他們呢!下次來一定要點這個豬肉阿~順便附上我們點的其他菜色。 3.宮崎 - TESHIO(てしお) 這間位在宮崎縣的 人情橫丁 ,是一個藏了很多小型餐館的巷子,我們選了一間看起來有賣拉麵的店走進去,沒想到~真的有賣拉麵,菜單是看不懂的日文書法,幸好老闆有準備一些圖片,一陣比手畫腳之後點了兩晚豬肉拉麵兩晚雞肉拉麵。 這個拉麵的湯頭蠻特別的,豚骨湯底加了一點柚子!?喝起來不會那麼鹹,右上角那顆白白圓圓的應該是雞肉丸,裡面有雞軟骨喔!   4.宮崎 - うなぎ千力 位於宮崎縣青島神社附近,是一間專賣鰻魚飯的店,感覺在日本應該是赫赫有名,店內牆上掛滿棒球明星來訪的簽名照。雖然菜單只有日文,但是店員很努力的為我們解釋,最後我們點了兩份盒裝鰻魚飯(中)和兩份白燒鰻魚組合餐。 白燒鰻魚組合餐,單點白燒鰻魚一份2600日圓,加300日圓變成組合餐(白飯+湯+水果),第一次吃這種調理方式的鰻魚,配上哇沙米很好吃

Java Final Array

圖片
Final是一個修飾詞(Non Access Modifier),可用於修飾類別(Class) 、方法(Method)和變數(Variable)。修飾類別時,代表其類別不能被繼承 ;修飾方法時,代表其方法不能被覆寫(Override) ;修飾變數時,代表其變數是一個常數(Constant),無法被修改。但是,泰勞偶然地發現,這麼解釋並「不夠精確」,為甚麼呢?讓我們繼續看下去。 參考資料: [Ken Yang 筆記]Java final 基本概念 [StackOverflow]final array in Java [SoloLearn]Why can I modify the value of final array ?   廢話不多說,直接看程式碼!(程式碼看多了,反而覺得中文字比較難理解) public class MyArray{     public static void main(String[] args){         final int[] mArray = new int[]{1,2,3,4,5};         System.out.println(mArray[0]);     } } 上面是一個簡單的範例,用final修飾一個名為mArray的整數陣列,第二行則是印出此陣列的第0個元素,輸出毫無意外的是1。接著看下一個範例。 public class MyArray{     public static void main(String[] args){         final int[] mArray = new int[]{1,2,3,4,5};         System.out.println(mArray[0]);         mArray = new int[]{6,7,8,9,0};     } } 大家都知道這一定會出錯,因為mArray是final的狀態,不能被修改,編譯系統也會告訴你「error: cannot assign a value to final variable mArray」。再來看下一個範例。 public class MyArray{     public static void main(String[] args){         final