2014年12月25日 星期四

Visual Studio - 調整方案組態控制項的寬度

開發環境:Visual Studio 2013

事件狀況:Visual Studio的工具列有很多控制項,其中的方案組態(Solution Configurations)預設寬度太小,只適合組態名稱Debug/Release使用,如果有自訂的組態名稱,容易顯示不完整。

解決方法:
  1. 開啟自訂命令表單,從工具(Tool)→自訂(Customize)→命令(Commands)→工具列(Toolbar)→標準(Standard)。
  2. 在控制項中(Controls)選擇方案組態(Solution Configurations)。
  3. 點選修改選取範圍(Modify Selection)。
  4. 預設寬度(Width)是65,可以調整到更大的寬度。
其他一樣屬於下拉式選單(ComboBox)的控制項的寬度都可以用這種方式做調整。

2014年12月9日 星期二

Git - SSH連線自動登入

若是透過SSH連線使用Git,雖然會記錄帳號,但每次都還是需要輸入密碼。在Ubuntu等Linux環境使用Git時,若有系統服務是需要跟Git整合應用,在需要輸入密碼時就會遇到自動化問題,這時可以利用sshpass這個工具協助解決登入需要輸入密碼的問題。
$sshpass -p 密碼 Git指令與參數
例如:
$sshpass -p password git fetch -q --all -p 

Ubuntu - 建立工作排程

作業系統:Ubuntu 14.04

建立當前使用者的工作排程:
$crontab -e
建立系統使用者的工作排程:
$sudo crontab -e
查詢當前使用者的工作排程:
$crontab -l
查詢系統使用者的工作排程:
$sudo crontab -l

一行就是一個工作排程,格式為
  「分鐘 小時 日 月 星期  命令」,
例如
  「5 * * * * echo task schedule」
為每個小時的第五分鐘時執行echo輸出task schedule字串。
 
 

2014年11月6日 星期四

Visual Studio - 自訂巨集變數

開發環境:Visual Studio 2013

事件狀況:使用QT時,會需要QTDIR這個巨集變數(macro variable),該變數正常要定義在.vcxproj.user這個檔案中,可是在某些狀況下,專案會找不到QTDIR這個變數,QT沒有自動建立。

解決方法:
  1. 開啟屬性管理員視窗,從檢視(View)→屬性管理員(Property Manager)。
  2. 展開專案項目與組態項目,會看到字尾.user的屬性項目。
  3. 開啟.user的屬性項目,點選通用屬性(Common Properties)→使用者巨集(User-Defined Macros)。
  4. 點選加入巨集,就可以自訂QTDIR這個巨集變數,值就是QT函式庫的路徑。

2014年7月29日 星期二

Python - 自訂訊息格式

Python有很好用的logging函式庫,並不必要自己去定義打印訊息的方法。下面僅是提供一個簡單的例子,說明如果想要取得呼叫來源的檔名和行數,可以利用traceback的堆疊訊息。
import traceback
import os, time

def __formalizeMessage(message):
    FILE, LINE, FUNCTION, TEXT = (0, 1, 2, 3)
    stack = traceback.extract_stack(limit = 3)
    return "{file}({line}) - {message}".format(file = os.path.split(stack[0][FILE])[-1], line = stack[0][LINE], message = message)

def printError(message):
    print("{0} [Error] {1}".format(time.asctime(), __formalizeMessage(message)))

def main():
    printError("Hello")  # The line number is 12.

if __name__ == "__main__":
    main()

打印出來的訊息為:
Wed Jul 30 14:56:05 2014 [Error] test.py(12) - Hello

2014年7月24日 星期四

Python - 序數轉換

忘了是在哪裡看到的,不常用,不過是一個滿有趣的寫法,利用python的dict,能將數字1變成1st,數字2變成2nd,數字3變成3rd,數字4變成4th等。
## Returns the ordinal number of a given integer, as a string. eg. 1 -> 1st, 2 -> 2nd, 3 -> 3rd, etc.
def ordinal(num):
    num = int(num)
    if 10 <= num % 100 < 20:
        return "{0}th".format(num)
    else:
        ords = {1 : "st", 2 : "nd", 3 : "rd"}.get(num % 10, "th")
        return "{0}{1}".format(num, ords)

Python - 移除目錄和檔案

不管用什麼程式語言,都會遇到一個狀況,就是要刪除檔案或目錄時,沒有一個簡易型函式能一起處理檔案和目錄。沒辦法,只好自己用已有的函式拼湊一個符合目標的函式。
import os, shutil

## Remove a file or directory.
def remove(path) :
    retval = False
    try:
        if os.path.exists(path):
            if os.path.isdir(path):
                shutil.rmtree(path, ignore_errors = True)
                retval = True
            elif os.path.isfile(path):
                os.remove(path)
                retval = True
        else:
            retval = True
    except OSError as e:
        print(e)
    except Exception as e:
        print(e)
    return retval

Python - URL判斷

Python的urllib能夠容易地處理request和response,也能夠協助URL的拆裝,但似乎少了一個檢查是不是URL的函式,在這裡提供一個簡易型函式,可以分辨是否帶有通訊協定的URL。(不限於http或https,只要有通訊協定的語法都可以)
import os
import urllib.parse

def isURL(path):
    return not os.path.isdir(path)\
        and not os.path.isfile(path)\
        and urllib.parse.urlparse(path).scheme != ""

Python - 檔案IO

Python對於檔案IO很友好,擁有一些常用的函式庫,最基本的莫過於open這個內建函式。
with open("text.txt", mode = "w") as file:
    file.write("Hello")
如果單純使用open,勢必要記得呼叫close關閉檔案串流,而且還要配合一些exception使用try except;但如果配合with ... as ...使用,則close的動作可以交給python,即使有exception發生,python也會呼叫close。

有些文章會說使用with ... as ...等於try ... except ... finally ...,但事實上使用with ... as ...還是有可能會發生exception,關鍵就在於檔名,如果open一個空字串,則整個with ... as ...還是會拋出exception,所以最好習慣上在with外頭加一層try ... except ...。

2014年7月23日 星期三

Python - namedtuple

C++中有struct型態可以快速建立一個輕型類別,在該類別中可以含有一些屬性,並用object.attribute的方式存取。在Python則能使用namedtuple做到這件事情。
from collections import namedtuple

## Component definition
Component_t = namedtuple("Component", ["data", "size", "source"])

## Create a component.
def Component(data, size, source):
    return Component_t(data, size, source)

## Convert a list of parameters into a component of module.
#  @param   array is a list.
def toComponent(array):
    return Component_t._make(array)


## Usage
comp1 = Component(data = "hello", size = 5, source = "test.txt")
print(comp1.data)

array = ["world", 5, "test.txt"]
comp2 = toComponent(array)
print(comp2.data)

Python - 有限狀態機

在撰寫模組時,因為使用有限狀態機來記錄每個模組的運作情況,所以寫了一個有限狀態機的類別供繼承用。
"""""""""""""""""""""""""""""""""""
Library
"""""""""""""""""""""""""""""""""""
from abc import ABCMeta, abstractmethod  # abstract class
from enum import Enum  # constant

"""""""""""""""""""""""""""""""""""
Class
"""""""""""""""""""""""""""""""""""
## Avoids having to specify the value for each enumeration member.
class AutoNumber(Enum):
   
    ## Override.
    def __new__(cls):
        value = len(cls.__members__) + 1
        obj = object.__new__(cls)
        obj._value_ = value
        return obj
   
## Finite state machine.
class FSM(object, metaclass = ABCMeta):
   
    ## State definition.
    class States(AutoNumber):
        Initial = ()
        Ready = ()
        Idle = ()
        Start = ()
        Pause = ()
        Stop = ()
        SendingRequest = ()
        SentRequest = ()
        ReceivingResponse = ()
        ReceivedResponse = ()
        Creating = ()
        Created = ()
        Storing = ()
        Stored = ()
        Reading = ()
        Read = ()
        Writing = ()
        Wrote = ()
        Removing = ()
        Removed = ()
        Parsing = ()
        Parsed = ()
        Finished = ()
        _Error = () # This is not public state.
        _Except = () # This is not public state.

    ## Constructor.
    def __init__(self):
        self._stateProcess = self.StateProcess
        self.__stateIndex = 0
        self._state = self._stateProcess[0]

    ## Get state process definition.
    #  @details  The state process could be a cycle. For example: [FSM.State.Initial, FSM.State.SendingRequest, FSM.State.ReceivingResponse, FSM.State.SendingRequest, FSM.State.Finished].
    #  @note     If there are two cycles with the same states, it is a wrong state process definition.
    #  @return   A list of state.
    @property
    @abstractmethod   
    def StateProcess(self):
        """Get state process definition."""
        return [FSM.States.Initial, FSM.States.Finished]

    ## Get state.
    #  @return   Current state.
    @property
    def State(self):
        """Get current state."""
        return self._state

    ## Get state before except.
    #  @return   The last state.
    @property
    def StateBeforeExcept(self):
        """Get previous state before except/error."""
        return self._stateProcess[self.__stateIndex]

    ## Process definition
    #  @param   skip - number of state to be passes. (optional)
    #  @param   end - if true, the latest state sets the ending state; otherwise, it sets the next state. (optional)
    #  @param   error - if true, the state sets the error state. (optional)
    def nextState(self, skip = 0, end = False, error = False):
        # avoid to reboot
        if self.isStopped():
            return
       
        # The highest priority
        if error is True:
            self._state = FSM.States._Error
            return
       
        # check parameters
        if skip < 0:
            self._state = FSM.States._Except
            return
       
        if end is True:
            self.__stateIndex = len(self._stateProcess) - 1
            self._state = self._stateProcess[self.__stateIndex]
            return
       
        self.__stateIndex = min(self.__stateIndex + 1 + skip, len(self._stateProcess) - 1)
       
        # check cycle
        i = self._stateProcess.index(self._stateProcess[self.__stateIndex])
        if i != self.__stateIndex:
            self.__stateIndex = i
       
        self._state = self._stateProcess[self.__stateIndex]

    ## Reset state to the initial process.
    def resetState(self):
        self.__stateIndex = 0
        self._state = self._stateProcess[0]

    ## Check if state is end or not.
    #  @retval  true if the state is the end.
    #  @retval  false otherwise.
    def isEndState(self):
        return self._state == self._stateProcess[-1]

    ## Check if state is except or not.
    #  @retval  true if the state is the except state.
    #  @retval  false otherwise.
    def isExceptState(self):
        return self._state == FSM.States._Except

    ## Check if state is error or not.
    #  @retval  true if the state is the error state.
    #  @retval  false otherwise.
    def isErrorState(self):
        return self._state == FSM.States._Error

    ## Check if the FSM is stopped or not.
    #  @retval  true if the FSM is stopped.
    #  @retval  false otherwise.
    def isStopped(self):
        return self.isEndState() or self.isExceptState() or self.isErrorState()
有限狀態機裡的巢狀類別States可以定義所有的狀態。繼承這個有限狀態機的類別需要覆寫StateProcess方法,該方法就是回傳狀態機的所需狀態清單。如此一來,使用上僅需要呼叫nextState方法,就能轉換狀態。

Python - 抽象類別

Python的library中,有東西能協助建立抽象類別與抽象方法。
from abc import ABCMeta, abstractmethod  # abstract class

class base(metaclass = ABCMeta):
   
    @abstractmethod
    def foo(self):
        pass
如此一來,繼承base類別就一定要覆寫foo方法。

Python - 不確定參數與屬性

Python傳遞不確定的參數值:
def foo1(opt, *args, **kwargs):
    # expressions
在這裡,opt是確定的參數,不確定的參數有args和kwargs,args的資料型態為tuple, kwargs的資料型態為dict。
foo1(1, True, "hello", data = "world", size = 8)
上面這一行呼叫了foo1,並傳遞五個參數值,進入foo1後,參數分別為:

opt = 1
args = (True, "hello")
kwargs = {"data" : "world", "size" : 8}

在使用繼承類別時,如果有多種形態的繼承類別,利用傳遞不確定的參數值,可以做到彈性的呼叫。



Python也可以傳遞不確定的屬性給物件:
class base():

    def setParameters(self, **params):
        for key, value in params.items():
            setattr(self, key, value)

    def run(self, out, **options):
        data = getattr(self, "data", "")
        length = getattr(self, "len", 0)
利用setattr和getattr這兩個內建函式,做到動態賦予物件屬性。這種寫法也是為了彈性設計。

Python - decorator運用(2)

在撰寫函式時,因為python的特性,不會去檢查回傳值的資料型態是否正確,也不會去檢查是否遺漏回傳值,這對於撰寫複雜一點的函式容易有疏忽的地方,這時候就能靠decorator做一些協助,例如遺漏回傳值時補上預設回傳值,或者回傳值型態錯誤時丟出例外錯誤。
import functools

## Check return type and value.
#  @details The return value could be one following situation:
#            1. value type is specified in the \a cls;
#            2. None;
#            3. value type is not specified and not None.
#   
#            In the 1st situation, return original value.
#            In the 2nd situation, if allow_none is true, return None; otherwise, return \a default.
#            In the 3rd situation, raise SyntaxError.
#  @param   default is the default return value.
#  @param   cls is the specified return value type.
#  @param   allow_none - if true, the return value could be None; otherwise, the return value must be assigned.
#  @exception   SyntaxError

def checkReturn(default, allow_type = None, allow_none = False):
   
    def check_decorator(function):
       
        def decorator_wrapper(*args, **kwargs):
            result = function(*args, **kwargs)
           
            cls = allow_type
            try:
                if allow_type is None:
                    cls = (type(default),)
                elif not issubclass(allow_type, tuple):
                    cls = (allow_type,)
            except Exception as e:
                raise
           
            if type(result) in cls:
                pass
            elif result is None:
                if allow_none:
                    pass
                else:
                    result = default
            else:
                raise SyntaxError("The type of return value {0} is not in {1}.".format(result, cls))
            return result
       
        return decorator_wrapper
   
    return check_decorator

Python - decorator運用(1)

在trace程式碼的時候,尤其是多執行緒的程式碼,想知道函式的呼叫情況,此時會記錄函式的進出資訊。在python,可以使用decorator幫助記錄。
import functools
import time

def logFunc(logger = None):
   
    def log_decorator(function):
       
        @functools.wraps(function)
        def decorator_wrapper(*args, **kwargs):
            if logger is None:
                print("{2} [Debug] Enter {0}.{1}".format(function.__module__, function.__name__, time.asctime()))
                result = function(*args, **kwargs)
                print("{2} [Debug] Exit {0}.{1}".format(function.__module__, function.__name__, time.asctime()))
            else:
                logger.debug("Enter {0}.{1}".format(function.__module__, function.__name__))
                result = function(*args, **kwargs)
                logger.debug("Exit {0}.{1}".format(function.__module__, function.__name__))
            return result
       
        return decorator_wrapper
   
    return log_decorator

另外,有時需要記錄函式的執行時間,一樣可以使用decorator幫助記錄。
import functools
import time

def logTime(logger = None):
   
    def time_decorator(function):
       
        def decorator_wrapper(*args, **kwargs):
            start = time.time()
            result = function(*args, **kwargs)
            end = time.time()
            if logger is None:
                print("{3} [Debug] {0}.{1} spent {2:.3f} seconds.".format(function.__module__, function.__name__, end - start, time.asctime()))
            else:
                logger.debug("{0}.{1} spent {2:.3f} seconds.".format(function.__module__, function.__name__, end - start))
            return result
       
        return decorator_wrapper
   
    return time_decorator

在這裡的logger是指logging.logger。

decorator的使用方式為:
@logFunc(logger)
def foo1():
  # expressions

@logTime(logger)
def foo2():
  # expressions 

2014年5月28日 星期三

C++ - 整數運算之溢位偵測

整數運算中,最容易產生溢位問題的估計是階層運算。設計一個factorial遞回函式來運算階層,輸入是一個整數N,輸出則為N!的結果,輸入和輸出的整數資料型態一致,假設使用unsigned int作為整數資料型態,該factorial函式表示如下:
unsigned int factorial(unsigned int N)
{
    return (N == 0 || N == 1) ? 1 : N * factorial(N - 1);
}
這是很簡單的一個寫法,用unsigned int是因為階層的定義要求為正整數或0。這個寫法並沒考量到溢位問題,當輸入的N為13時,就會產生溢位問題。

如果是兩個整數相加,溢位會多增加一個位元,可以檢查兩個整數相加是否會有進位現象,進位後會不會超出資料型態的位元數,來判斷相加會不會產生溢位。

可是階層運算是乘法運算,無法用相加的溢位判斷方式,而要用其他的方式判斷。

方式一:溢位旗標的判斷。因為暫存器的關係,僅適用於int、unsigned int等32位元的整數資料型態,若用於其他位元數的整數資料型態會判斷錯誤。
unsigned int factorial(unsigned int N)
{
    unsigned int product = 0;
    product = (N == 0 || N == 1) ? 1 : N * factorial(N - 1);
    __asm jo overflowed;
    if (0)
    {
overflowed:
        throw(std::out_of_range("Overflowed"));
    }
    return product;
}
方法二:除法運算檢查。適用各種整數資料型態。
int factorial(int N)
{
    int product = 0;
    if (N < 0) // 限定N為正整數或0
    {
        throw(std::out_of_range("Negative integer"));
    }
    if (N == 0 || N == 1)
    {
        product = 1;
    }
    else
    {
        int multiplicand = factorial(N - 1);
        product = N * multiplicand;
        if (product / N != multiplicand) throw(std::out_of_range("Overflowed"));
    }
    return product;
}
方法三:自訂BigInteger的資料型態。 BigInteger的數字是使用字元陣列來表示,運算採取字元陣列的方式做運算,加減乘除也需要自訂,因為是用字元陣列來表示一個數字,所以該數字理論上可以無限大(實際上會受限字元陣列所能表示的最大長度)。

方法二就已經足夠使用,方法三就留給以後需要的時候再來實作。

2014年5月8日 星期四

Doxygen - 圖形化類別關聯性

Doxygen是一套利用程式註解的方式,建立出程式說明文件的軟體。
Graphviz是一套利用命令和參數畫出關係圖的軟體。
Doxygen產出文件時,可以透過參數設定,使用Graphviz來繪圖。操作步驟為:

  1. 先安裝DoxygenGraphviz這兩套軟體。
  2. 設定環境變數,將Graphviz安裝路徑\bin設定在環境變數path。
  3. 設定Doxygen的執行參數。如果是使用doxygen參數檔的方式,HAVE_DOT這個參數要設定為YES,其他與dot相關的參數則可自行調整。如果是使用wizard圖形視窗的方式,在Expert頁籤的Topics選單中有個Dot項目,點選Dot後,將HAVE_DOT勾選起來,其他相關參數則可自行調整。
最後,建立完文件,在類別分類中就可以看到關係圖了。