建立一個支援X11的Docker

下面這個Dockerfile可以建立一個具備ssh server及X11 server的docker容器。可以在裡面執行一般的X11的程式並且透過X11 client看到畫面。

FROM centos:centos7
MAINTAINER Gary Lee <garywlee@gmail.com>

# Install ssh server.
RUN yum install -y which openssh-clients openssh-server
RUN ssh-keygen -f /etc/ssh/ssh_host_rsa_key
RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key
RUN sed -i '/pam_loginuid.so/c session    optional     pam_loginuid.so'  /etc/pam.d/sshd

# Set root's password
RUN echo "centos" | chpasswd

# Add user
RUN useradd user1 -p iamuser1

# Install system tools and libraries.
RUN yum -y install glibc.i686
RUN yum -y install libstdc++.so.6
RUN yum -y install net-tools
# Install X Window System
# yum -y groupinstall "X Window System" "Desktop" "Fonts" "General Purpose Desktop"
RUN yum -y groupinstall "X Window System" "Fonts"

# Install other tools.
RUN yum -y install xterm
RUN yum -y install gedit
RUN yum -y install gvim
RUN yum -y install okular

RUN yum -y install vim

# Expose settings.
EXPOSE 22

ENTRYPOINT ["/usr/sbin/sshd", "-D"]

處理在Google Cloud Platform上遇到無法使用Git的問題

在使用Google Cloud Platform所提供的git服務時,遇到了下面奇怪的訊息。

ERROR: (gcloud.auth.git-helper) Invalid input line format: [path=].
ERROR: (gcloud.auth.git-helper) Invalid input line format: [path=].
fatal: remote error: Invalid username/password.

在網路上找了很久才找到一個解決方案。首先開啟一個具備administrator的權限的console。然後輸入下面的命令。

git config --system --unset credential.helper

接著輸入

git config --list

查看credential.helper是不是已經沒有了。如此就可以正常使用Google Cloud Platform的git服務了。

使用golang與vscode時需要安裝的package

下面這些packages是使用golang與vscode前要先設定及安裝好的東西。

setx GOPATH <your go installation path>
go get -u -v github.com/nsf/gocode  
go get -u -v github.com/rogpeppe/godef  
go get -u -v github.com/golang/lint/golint  
go get -u -v github.com/lukehoban/go-find-references  
go get -u -v sourcegraph.com/sqs/goreturns  
go get -u -v golang.org/x/tools/cmd/gorename  
go get -u -v github.com/derekparker/delve/cmd/dlv  

把Ubuntu的使用者目錄改回英文的script

每次安裝完新的Ubuntu都有一個很惱人的問題。那就是使用者的目錄是中文的。command line用習慣的人,都知道打命令的時候輸入中文是一件很討厭的事情。所以,弄了下面這個script來將目錄名稱換回英文的。

#!/bin/sh

# This shell script utilizes xdg-user-dir and xdg-user-dirs-update to 

# change all user dirs back to original name in English.

USER_FOLDERS="DESKTOP DOWNLOAD TEMPLATES PUBLICSHARE DOCUMENTS MUSIC PICTURES VIDEOS"
USER_HOME=`xdg-user-dir`
for USER_FOLDER in $USER_FOLDERS; do
    FOLDER_ABSNAME=`xdg-user-dir $USER_FOLDER`
    FOLDER_DIRNAME=`dirname $FOLDER_ABSNAME`
    FOLDER_BASENAME=`basename $FOLDER_ABSNAME`
    FOLDER_TARGET="$FOLDER_DIRNAME/$USER_FOLDER"
    if [ "$FOLDER_ABSNAME" = "$USER_HOME" ]; then
        # Ignore invalid folder.

        echo WARNING: $USER_FOLDER is invalid.
        continue
    fi
    if [ "$FOLDER_TARGET" = "$FOLDER_ABSNAME" ]; then
        # Ignore the folder which has been matched to target name.

        continue
    fi
    # Uncomment following lines for debugging purpose.

    #echo $USER_FOLDER $FOLDER_ABSNAME "(" $FOLDER_DIRNAME "," $FOLDER_BASENAME ")"

    # Update user dir.

    xdg-user-dirs-update --force --set $USER_FOLDER "$FOLDER_DIRNAME/$USER_FOLDER"
    # Move corresponding folder to new place.

    mv "$FOLDER_ABSNAME" "$FOLDER_DIRNAME/$USER_FOLDER"
done

解決沒有mouse的時候,沒有cursor顯示的問題

透過像是Mouse without border這樣的工具控制另外一台電腦的時候,如果該電腦上面沒有接任何滑鼠或是所謂的指標裝置。你會發現cursor不見了。這是因為Windows預設是會在沒有指標裝置的情況下將cursor隱藏起來。要解決這個問題,只要修改下面的registry的值為0,再重新啟動電腦就可以了。

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System]
"EnableCursorSuppression"=dword:00000000

快速學習一個程式語言

想要快速學習一個程式語言,我會採用如下幾個階段的作法。

第一階段,了解基礎語法:

  1. 先看一個Hello world的範例,了解一個基本的程式的結構大概長怎樣。
  2. 看它的的基本變數用法。像是支援的變數型態,整數,浮點數及字串的使用。
  3. 看他的直述式,條件跳躍,迴圈,函數的語法怎麼寫。
  4. 其他進階概念的語法。像是物件導向的語法,functional programming的語法等等。(如果你之前沒有接觸過這些進階概念,那就跳過第四步,以後再說。)

第二階段,使用編譯環及小範例練習:

  1. 每個語言應該都有一個編譯環境或是執行環境。常見的也有一個語言,但是很多廠商都出了編譯環境及執行環境。就挑一個來熟習。
  2. 找幾個小題目,就像是學校課本裡面那種練習題,磨練一下手感。

第三階段,了解基礎程式庫:

  1. 把基礎程式庫的大分類先整理出來,只需要知道名稱及主要用途即可。
  2. 把所有的函式都看過一遍,只要看名稱跟用途就可以了。

這個階段最忌諱看的過於深入,也忌諱去背誦。只要有名稱跟用途的印象就可以了。

第四階段,找個有點規模的題目來練習:

  1. 找個大點的題目。比如說,數值計算機程式,迷宮程式。
  2. 規劃一下怎麼在這個語言下把程式模組切割。
  3. 規劃一下可能會用到的函式。像是接受使用者輸入,檔案存取。
  4. 開始寫!!因為不熟,會遇到很多困難。或是不知道該用什麼函式庫。不要有挫折感,好好利用網路或是help查詢。

第五階段,進階項目的熟悉:

  1. 如果你前面跳過第一階段的進階概念語法,這個時候你可以開始先進階概念開始了解。再來了解這個語言是以怎樣的語法實現這些概念。
  2. 列出前面所沒有的項目以及一些這個語言專有的特性進行了解。

以上,如果有其他程式語言的基礎,第一~二階段半天就可搞定。沒有的話,兩天也應該可以搞定。第三階段,看程式語言本身程式庫的龐大與否,大約會是兩天到一週的時間。第四階段可能是二到七天。第五階段則不一定,但是也不應該超過一週。所以一個語言,花一個月理解及上手是很OK的。至於要熟悉那就只有不斷的累積了。

整個的重點是『知道』就好,千萬不要花時間死背硬記。不斷練習或實做才能更快熟悉。

使用pefile module顯示執行檔案所需要的DLL

最近才發現原來Python有一個可以讀取Portable Executable格式的module pefile[1]。於是就拿來練習,寫了一個可以顯示執行檔所需要的DLL的小程式。

     #!/usr/bin/env python  
     # coding: utf-8  
     """ showdll.py: show the depedency of given exeutable file. """  

     import sys  
     from os import path  

     import pefile  

     def get_depend(filename, dll_list=[]):  
     """Return the dependency in hierarchical dictionary."""  
     if not path.isfile(filename):  
     return   
     pe_obj = pefile.PE(filename, fast_load=True)  
     pe_obj.parse_data_directories()  
     dlls = {}   
     if hasattr(pe_obj, 'DIRECTORY_ENTRY_IMPORT'):  
     curr_dependency = []  
     for entry in pe_obj.DIRECTORY_ENTRY_IMPORT:  
     if entry.dll not in dll_list:  
     dll_list.append(entry.dll)  
     curr_dependency.append(entry.dll)  
     for entry in curr_dependency:  
     dlls[entry] = get_depend(entry, dll_list)  
     return dlls  

     def print_depend(dependency, depth=0, padding='\t'):  
     prepend = padding * depth  
     for k,v in dependency.items():  
     print "%s%s" % (prepend, k)  
     if isinstance(v, dict):  
     print_depend(v, depth+1, padding)  

     if __name__ == '__main__':  
     dependency = get_depend(sys.argv[1])  
     print_depend(dependency)  
     Usage:           
     > showdll.py foo.exe  

Ref: https://code.google.com/p/pefile/

一個最基本的AngularJS(包含AngularUI)的HTML檔案範本

一個最基本的AngularJS(包含AngularUI)的HTML檔案範本:

[][1]

<!doctype html>  
<html ng-app="app">  
<head>  
 <link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.1.0/css/bootstrap.min.css">  
 <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.10/angular.min.js"></script>  
 <script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.10.0/ui-bootstrap-tpls.min.js"></script>  
 <script type="text/javascript">  
 angular.module('app', ['ui.bootstrap']);  
 ...  
 </script>  
</head>  
<body>  
...  
</body>  
</html>  

[1]:

如何取得利用PyInstaller所包入的資料檔案

PyInstaller可以協助我們將Python程式包裝成單一的執行檔案。同時也可以協助我們程式所需的資料檔案一併包裝起來。資料檔案一般我們都是在PyInstaller的spec檔案中加入如下的敘述:

a.datas += [('images/my.png', '/src/images/my.png', 'DATA'), ('images/other.png', '/src/images/other.png', 'DATA'), ('db/main.db', 'main.db', 'DATA')]  

但是如果你在程式中寫上,像是

fd = file('db/main.db', 'rb')  

或是

fd = file('main.db', 'rb')  

不管是哪一個,你只有在未包裝前可以正確的開啟檔案,一旦包裝起來再執行就無法正確取得檔案了。其原因在於你的包裝好的執行檔案在執行時的時候,所有的東西會被解到一個暫時的目錄去,這個目錄你無法在寫程式的時候就確定好。所以就無法直接取得檔案。

[][1]

還好網路上有人回答了這個問題。作法就是透過PyInstaller所提供的資訊來得到當時的目錄。下面這個function可以很方便的幫助你在程式中取得資料的檔案的路徑。

def rc(rel_path):  
 """Return full path of resource according to rel_path."""  
 if not hasattr(sys, '_MEIPASS'):   
 # for elder PyInstaller.  
 rc_path = os.environ.get("_MEIPASS2", os.getcwd())  
 else:  
 rc_path = getattr(sys, '_MEIPASS', os.getcwd())  
 return os.path.join(rc_path, rel_path)  

dbfile = rc('db/main.db')  
...  

要注意的是,這些資料檔案應該只作為讀取的用途。寫入資料到裡面去是沒有用的。因為下一次程式執行的時候它就不見了。

Reference:

  1. Bundling data files with PyInstaller (--onefile)

[1]:

筆記:TDD三原則

所謂的測試導向開發的三原則

http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd

  1. You are not allowed to write any production code unless it is to make a failing unit test pass.
  2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
  3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test.

翻譯成白話一點的中文就是

  1. 沒有測試單元,不寫程式。
  2. 不寫測試條件以外的測試程式。
  3. 不寫不屬於任何測試單元的產品程式。