2013年11月16日 星期六

[osx] 軟體 raid 簡單操作 SOP 及軟體 raid 不支援 3T 硬碟?

最近興高彩烈買了 3T 硬碟一顆,準備要跟另外一顆 3T 硬碟合體變成 raid1,但每每在製作過程中會出現無法將硬碟加入 raid 這種錯誤。實在讓人想不通。2T 的硬碟都可以正常工作的,如果真的是軟體限制,希望新版的 osx 可以支援。

順便記下軟體 raid 的簡單操作。

組合成 raid:

  插入兩顆硬碟。

  打開磁碟工具程式

  先隨便點一顆硬碟,再點右邊 RAID 頁籤

  在 「RAID 設置名稱」那一欄填入一個名字,這會是之後掛載上來的磁碟名字。

  「卷宗格式」選 Mac OS擴充格式 (日誌式)

  「RAID 類型」選 映射的 RAID 設置

  按下該頁籤左下方的 + 號,會出現一個灰色的硬碟圖示。

  從左方的硬碟中,把你要的兩顆硬碟拖到灰色的硬碟圖示下方。按下製作按鈕。

  接下來等工具程式,它會把剩下工作做完,然後掛載一個新的磁碟到系統裡,就完成了。

遇到硬碟有問題:

  打開磁碟工具程式,當硬碟有問題的時候,會看到紅色的字。

  點到那紅色字,畫面右邊會顯示狀況,它會告訴你哪一顆硬碟有問題,整個 RAID 設置會進到已降級的狀態。

  在已降級的狀態下,無法新增硬碟。可以做的動作有幾個,結果非常不同,一、對有問題的硬碟做「重建」,重建若完成,RAID 會回到已連線狀態;二、對有問題的硬碟按下 - 號,再按「降級」。RAID 設置會少掉一個硬碟,但還是 RAID 設置,狀態會回到已連線,就可以新加硬碟;三、對有問題的硬碟按「刪除」,這會使用 RAID 設置被取消,會跑出兩個硬碟都是同個名字,但資料都還在。

  所以,最好是先試重建,若硬碟問題不大,就可以再撐一陣子。重建時間很久,2T要等3~5天,若途中還有對該硬碟做動作,會等更久。

  若硬碟真的該換,則是對有問題的硬碟按下 - 號,再按降級,讓 RAID 回到已連線,然後再加新的硬碟,維持 RAID 的設置。

  刪除的動作我以後應該不會再去按了。除非是要把硬碟轉成一般用途。

[python] bit 操作與易經

從沒有機會需要操作 bit,沒想到寫易經的程式非得用到不可。

第一個最需要的是,把數字轉成 0101 的字串。這個內建的 bin() 函數可用,只是它會在字串前多加0b。依實際需要,得把 0b 去掉。

>>> bin(13)
'0b1100'
>>> bin(13)[2:]
'1101'

第二個就是把 0101 的字串轉回數字,這可以用 eval,或是 int('0b1100', 2) 來達成。

>>> int('0b1101',2)
13
>>> int('1101',2)
13

第三個,易經是 6-bits 系統,而且非常需要補 0 在高位數。

>>> bin(13)[2:].rjust(6,'0')
'001101'

第四個,因為我手上的易經參考書,低位寫在前面,高位寫在後面,我得把字串反過來。從字串轉回數字也得一樣照辦。

>>> bin(13)[2:].rjust(6,'0')[::-1]
'101100'
>>> int('101100'[::-1], 2)
13

第五個,對某個 bit 做反轉運算,因為對 6-bits 的操作沒有把握再加上高低位已經反轉,已經夠亂了,所以採取直接對字串操作,但因為 python 的字串沒法單獨對第某個字元操作,所以寫了個函數代替。主要是拆開字串為 list,操作完再組回去。index 從 0 開始。

def _invert_at(s, index):
    ss = list(s)
    if ss[index] == '0':
        ss[index] = '1'
    else:
        ss[index] = '0'
    return ''.join(ss)

>>> _invert_at('101100', 1)
'111100'

更新:經過研究測試之後,相同的功能可以用 bin(int(s, 2) ^ 2 ** (5 - index))[2:].rjust(6, '0') 來解決。

基礎工程結束,接下來應用開始。因為用 bit 來表達了,原本常用的 1~8,都得用 0~7 這種以 0 開始的 index 系統。

一般卜卦是在得到一個卦(叫做「本卦」)之後,都會再求一個「變卦」及「互卦」。在一般簡易數字型卜卦中,本卦、變卦、互卦的求法是:

  • 本卦是得到兩個 0~7 之間的數字,一個代表上卦,一個代表下卦。例如,上卦 1、下卦 7,就是 101100,豐卦。(下卦在前面,低位在前面)
  • 變卦是從 0~5 之間得到一個數字,代表動爻的位置,然後把本卦的對應的 bit 反轉。例如,101100,我們得到 2 爻動,就是得到 111100,大壯卦。
  • 互卦的求法是把本卦234爻做為下卦,把345爻做為上卦。011110,大過卦。

互卦用程式來表示很清楚:

>>> s = '101100'
>>> s[1:4] + s[2:5]
'011110'

接下來,用程式表示八宮卦象變化大概就是這樣:

def get_8_change(s, step):
    if step == 0:
        return s
    elif step == 1:
        return _invert_at(s, 0)
    elif step == 2:
        return _invert_at(s, 1)
    elif step == 3:
        return _invert_at(s, 2)
    elif step == 4:
        return _invert_at(s, 3)
    elif step == 5:
        return _invert_at(s, 4)
    elif step == 6:
        return _invert_at(s, 3)
    elif step == 7:
        ss = _invert_at(s, 2)
        ss = _invert_at(ss, 1)
        ss = _invert_at(ss, 0)
        return ss

拿坎宮的八個卦的程式是

s = '010010'
for i in range(8):
    s = get_8_change(s, i)
    print s, _int_from_bin_r(s), money64[s]

執行結果是:

010010 18 坎
110010 19 節
100010 17 屯
101010 21 既濟
101110 29 革
101100 13 豐
101000 5 明夷
010000 2 師

八宮卦象變化的函式 get_8_change 的 step 0~6 跟京房 16 卦一樣,可以做為基礎繼續改造。

[python] named pipe on windows 7 using ctypes

同樣這篇也是誤入岐途。

原先使用 .Net 的 NamedPipeServer 及 NamePipeClient 好好的。不小心看到網路上有提到 python 也有支援。很開心地就拿來用,結果是失敗。(原po1原po2)

在沒有小心查證之下,又堅信 python 必定可使用 named pipe,嘗試了諸多的 post。都是被無情地打槍。(族繁不及備載) 最後就是看到使用 windows 內 kernel32 的一組 API 達成這個功能(原po):

  1. CreateNamedPipeA
  2. ConnectNamedPipe
  3. WaitNamedPipeA
  4. SetNamedPipeHandleState
  5. ReadFile
  6. WriteFile
  7. FlushFileBuffers
  8. DisconnectNamedPipe

因此,一個很不巧又很湊巧地,讓我必須要去學一下 ctypes 是怎麼回事。

Windows API?

ctypes 是 python 一個很重要的 module,可以用來跟 dll 或 shared libraries 溝通。它提供了一組與 C 語言相容的資料型別(data type),以此做為純 python 的溝通橋樑。也就是說,我這次不小心踩到 Windows API啦…。(我寫 VB6 時最討厭遇到 Windows API)

先從 Windows API 來看,一個 NamePipe 的範例包含兩個部份,一個我硬把它叫 Server,一個我硬把它叫 Client。這是從 .Net 的 NamedPipeServer 及 NamePipeClient 來推論的。

在 server 這邊的流程是(很可惜網路上現在的 MSDN 很少描述這種東西了,或者這些都會在舊的 MSDN 裡,這裡所寫的流程是由網路上搜尋及試誤後得到的可能的一種正確流程。):

  1. 呼叫 CreateNamedPipeA,拿到 handle。
  2. 呼叫 ConnectNamedPipe,等待另一方連上。
  3. 在連上之後,使用 ReadFile 讀取資料,或使用 WriteFile 傳送資料(呼叫 FlushFileBuffers 確定資料沒有留在 buffer)。
  4. 使用 DisconnectNamedPipe 關閉連結,使用 CloseHandle 釋放資源。

在 client 這邊的流程是:

  1. 使用 CreateFileA 得到 handle。handle 有可能是幾種數值。如果 server 已經在等待中,handle 會直接拿到。如果不是 handle 是 INVALID_HANDLE_VALUE,接下來可以從 GetLastError 得到是否為 ERROR_PIPE_BUSY,若是 pipe busy 可以呼叫 WaitNamedPipeA,等 server 開啟。
  2. 成功拿到 handle 之後,可能需要改變 pipe 的傳送方式為 byte。此時使用 SetNamedPipeHandleState。此步驟可省略。
  3. 在連上之後,使用 ReadFile 讀取資料,或使用 WriteFile 傳送資料(呼叫 FlushFileBuffers 確定資料沒有留在 buffer)。
  4. 使用 DisconnectNamedPipe 關閉連結,使用 CloseHandle 釋放資源。

相信老程式人一定會知道,這些 API 在尾巴有 A 的,也有同名但尾巴不帶字的,或者是尾巴帶 W 的。現在 MSDN 不太強調這些資訊,我想這些差異現在應該是被微軟處理掉,開發者可以不用去在乎了。(在 http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx 最下面一行。不懂的人還是看不懂。這告訴我們 .Net 就對了,不要再用 Windows API?)

之所以要先介紹 Named Pipe 的 Windows API,是因為,用 ctypes,就是得按照 Windows API 的規矩來!ctypes 不是一個已經包好(wrapped)的轉接器(adapter),而是要拿來做轉接器的工具。已經打包好的是 pywin32,我自己誤很大。

現在來仔細看 CreateNamedPipe[5] 的定義,進一步了解該從 MSDN 查到什麼資訊,如何用 ctypes 與它溝通:

HANDLE WINAPI CreateNamedPipe(
_In_      LPCTSTR lpName,
_In_      DWORD dwOpenMode,
_In_      DWORD dwPipeMode,
_In_      DWORD nMaxInstances,
_In_      DWORD nOutBufferSize,
_In_      DWORD nInBufferSize,
_In_      DWORD nDefaultTimeOut,
_In_opt_  LPSECURITY_ATTRIBUTES lpSecurityAttributes
);
第一行看到的是 HANDLE WINAPI CreateNamedPipe,知道它會回傳一個 HANDLE 型態的值。
因為我們很取巧地使用 python,所以可以很取巧地不用刻意準備對應的型別來承接。
再來第二行 _In_ LPCTSTR lpName,說明這是一個傳入參數,型別是 LPCTSTR,
這個型別的意義請參考網路上的好文,我這裡也很投機地使用python 的 str 型別來傳。


接下來的 DWORD,應該大家都熟悉地知道是 2-byte bytes 型別。


這些的對應,我也很投機地找到一個地方有記錄,是別人整理好的在 rpython 的專案中。
但是重要的是,dwOpenMode、dwPipeMode 要填什麼值?
這個就要回到 MSDN(參考[5])的網頁裡找到對應的數值。例如 dwOpenMode,有基本的三個數值:


  • PIPE_ACCESS_DUPLEX 0x00000003
  • PIPE_ACCESS_INBOUND 0x00000001
  • PIPE_ACCESS_OUTBOUND 0x00000002

同時可以有下列三個不同的 flag 可調整 pipe 對於資料寫讀時的行為:



  • FILE_FLAG_FIRST_PIPE_INSTANCE 0x00080000
  • FILE_FLAG_WRITE_THROUGH 0x80000000
  • FILE_FLAG_OVERLAPPED 0x40000000

又同時有以下三個 flag,可調整 security access 的模式:



  • WRITE_DAC 0x00040000L
  • WRITE_OWNER 0x00080000L
  • ACCESS_SYSTEM_SECURITY 0x01000000L

所以,從上述三大類中,挑選正確的數值。通常大家都是這麼做的:



PIPE_ACCESS_DUPLEX = 0x3  # 宣告常數
FILE_FLAG_WRITE_THROUGH = 0x80000000
dwOpenMode = PIPE_ACCESS_DUPLEX | FILE_FLAG_WRITE_THROUGH


然後把 dwOpenMode 放進呼叫裡。


假設像我一樣抄完別人的 code,要呼叫 CreateNamedPipe 這個 function 就是這樣:



hPipe = windll.kernel32.CreateNamedPipeA(path,
                                                 PIPE_ACCESS_DUPLEX,
                                                 PIPE_TYPE_BYTE |
                                                 PIPE_READMODE_BYTE |
                                                 PIPE_WAIT,
                                                 PIPE_UNLIMITED_INSTANCES,
                                                 BUFSIZE, BUFSIZE,
                                                 NMPWAIT_USE_DEFAULT_WAIT,
                                                 None
                                                )


在 python doc 的 15.17.1.1. 說到會自動代入兩個物件,windll, oledll,從這兩個物件開始操作。


標準的 c data type,有 python doc 15.17.1.4. Fundamental data types 可以查,
但是對於 Windows API 裡特別的型別(例如 LPCTSTR) 就要試,或著查看 pywin32 之類的程式碼對照。


Array, Pointer 怎辦?


接下來還會遇到的是陣列,指標的問題。通常是為了應付 out 的參數,像是 ReadFile:


BOOL WINAPI ReadFile(
_In_         HANDLE hFile,
_Out_        LPVOID lpBuffer,
_In_         DWORD nNumberOfBytesToRead,
_Out_opt_    LPDWORD lpNumberOfBytesRead,
_Inout_opt_  LPOVERLAPPED lpOverlapped
);

第三行的 _Out_        LPVOID lpBuffer,我們得準備個陣列給它,而且還要是個指標。


首先,我在 python 從來沒想過要宣告陣列。據抄來的 code 是這樣的(我忘記哪抄來的):



buff = (c_ubyte * 4)()  # c_ubyte 型別,長度為 4


要讓它是個指標,就照官方文件給個 byref function 包著或建立一個 pointer 物件(byref 比較 lightweight)



lpbuff = byref(buff)
or
pbuff = pointer(buff)


在第五行的 _Out_opt_    LPDWORD lpNumberOfBytesRead,LPDWORD 的處理方式則是:



cbRead = c_ulong(0)
fSuccess = windll.kernel32.ReadFile(self.hpipe,
                                    byref(chBuf, offset),
                                    rsize,
                                    byref(cbRead),
                                    None)


offset += cbRead.value


如此,在 cbRead.value 就可以看到值。


指標還有個常用到的特色是指標移動,像是上面的第三行,byref(chBuf, offset),
得到的是 chBuf 再往後移動 offset 的指標。常寫 c 或 c++ 的人會了解。


為什麼直接用 ctypes ?


除了誤入岐途之外,也有一個好處,pywin32 真的不小。如果只是想要一個 named pipe,
我自己 285行(特化過的 named pipe server + client)就解決了。
程式碼長度約 12190 bytes。deploy 不用帶 pywin32 或叫 user 安裝。
目前我想到的是這個優點。不過網路上有很多人說,pywin32 解決很多轉換的步驟。
至少少掉很多查文件、設定常數的重覆工作。


 


參考:


[1] http://code.activestate.com/lists/python-list/446422/


[2] http://www.nullege.com/codes/search/ctypes.OleDLL


[3] http://stackoverflow.com/questions/3517159/ctypes-offset-into-a-buffer


[4] http://docs.python.org/2/library/ctypes.html#ctypes-arrays


[5] http://msdn.microsoft.com/en-us/library/windows/desktop/aa365150(v=vs.85).aspx


[6] http://stackoverflow.com/questions/1430446/create-a-temporary-fifo-named-pipe-in-python


[7] http://jonathonreinhart.blogspot.tw/2012/12/named-pipes-between-c-and-python.html

2013年11月5日 星期二

[android] emulator 以為地球在左邊

光看到標題一定不會知道我在說什麼。畫面不就是 portrait 跟 landscape 嗎?反正我就是遇到了像下圖一樣的情況。

 

1

不管怎麼轉都不如意

2

正常不就是要像下圖一樣的畫面。

3

老大說怎麼可以,一定是怎樣怎樣ooxx…。

設定檔東翻西找找不到。

因為英文不好,真的還不知道該怎麼查 google。這英文要怎麼描述?

終於,我在 stackoverflow 找到一篇 post,標題是「

Emulator in landscape mode, screen does not rotate」

http://stackoverflow.com/questions/7394447/android-emulator-in-landscape-mode-screen-does-not-rotate

我總算可以交差,那就是 bug。

後來我是按照底下留言把「Hardware keyboard present」關掉,就正常了。

[python] base64, base32, binascii

base64 的編碼方式,目的在於把 binary 的資料,用可見的 ascii 表示出來。每三個 byte 的資料,用四個 byte 的可見字元表示[1],所以資料會變大 1.33倍。老骨頭們應該有聽過 uuencode,那也是一樣的目的。通常會選擇 64 個可見字元,目前 base64 常見的應用在 MIME's Base64,它所選擇的字有 0-9, a-z, A-Z 再加上加號+ 及除號/ 組成 64 個字元。如果用在 url 裡面,會把 + 及 / 換成別的字,成為 base64 的變形。

在看過實例後,會發現有的 base64 後面會跟著等號 = 那是因為每次資料的 byte 數不一定是三的倍數。那麼少掉的 byte,就用等號來補。

那麼,base32,就是用 32 個字元來取代,也就是每 5 個 bit,就要用 1 個 byte 來表示。也就是 5 個 byte 的資料要 8 個 byte 來表示,資料變大成 1.6 倍,因此不常被使用。

那麼在 python 有兩個模組可以用 base64。一個是 base64 模組,一個是 binascii 模組。在 base64 模組提到它是遵照 RFC3548 來做的,演算法不同於 uuencode,所做出來的字串可以用在 e-mail 傳送任意資料,或是 http post 的一部份。在 html 內嵌圖片資源也是常常看見的。在這個模組也實做 base32 及 base16。

而在 binascii 這裡,有 a2b_base64(string) 及 b2a_base64(data) 兩個函式,非常簡單地就把該轉的轉完。

其實用哪個模組都可以,唯一要注意的是 binascii.b2a_base64(x) 的後面多了一個換行。所以轉成 base64 之後若拿來跟 base64.b64encode(s) 比對的話,要 strip 過才不會中招。

我自己常常遇到的應用是客戶把檔案轉成 base64 的字串放在 xml 裡(SOAP),我們再把它轉回來變檔案。

 

參考

[1] http://en.wikipedia.org/wiki/Base64

[webpy] webpy, django, web2py 的適用性研究

先來研究一下 webpy 、django 及 web2py 的差異。

雖然這三個都自稱 web framework,其中差異卻是很大。

差異的地方在於功能涵蓋率以及如何做到。

我研究的方法是從 hello world 來看它們的做法。

webpy 提到它有以下的功能,而這些都是 web framework 的基本功能:

  1. URL Handling
  2. Web server
  3. Templating
  4. Forms
  5. Database

而 django、web2py 的網站第一句話就說,「high-level Python Web framework」(django)、「full-stack framework」(web2py)。因此相較之下,webpy 顯得是比較手工(輕量級)的 framework。這怎麼說呢?

首先,webpy 最簡單的範例是:

import web

urls = (
    '/', 'index'
)

class index:
    def GET(self):
        return "Hello, world!"

if __name__ == "__main__":
    app = web.application(urls, globals())
    app.run()

執行這段程式

python code.py // 或者 python code.py 1234 以指定 port

之後就可以用 browser 來看執行結果。其他的事情,就自己手工來寫。

web2py 在安裝完之後,直接執行 web2py。進到預設網頁(http://127.0.0.1:8000)
在它的預設網頁先設定管理者密碼,再建立一個 Application,例如 myapp。
之後再進入 http://127.0.0.1:8000/myapp 的 edit mode,針對它提供的各大項目進行程式碼編輯。
這些項目包含:

  1. models
  2. controllers
  3. views
  4. languages
  5. modules
  6. static files
  7. plugins

以最簡單的 hello world 來說,就是在屬於 controller 的 default.py 裡,寫下

def index():
    return "Hello from MyApp"

如此瀏覽 http://127.0.0.1:8000/myapp/default/index 就會看見 hello world 了。

django 在安裝完後(這是一條漫長的道路),要建立網站架構,使用指令

django-admin.py startproject mysite

它會在你的工作目錄產生一個結構:

mysite/
    manage.py
    mysite/
        __init__.py
        settings.py
        urls.py
        wsgi.py

然後再依照 django 規定修改新增相關檔案,啟動開發用 server,就可以看到結果。

由一個 hello world 範例,就可以看出這三個 web framework 的目標族群是不一樣的。
webpy 的確是簡單。若是只有幾頁網頁要展示,沒有複雜權限控管需要實作(例如與桌機整合的 single sign on),對於開發小型網站程式是很好的。不用裝一大包東西只為了幾種單純的網頁。
可以這樣思考,若是裝 apache 都嫌太大的專案,就可以思考用 webpy。類似的 framework 如 http://www.cherrypy.org/。然而是要完整功能,則免不了要自己打造很多功能。選用別的 framework 比較合適。
而 django、web2py,已經有相關許多模組做出權限控管,許多類型檔案支援,session 的支援等等。

這裡粗略的比較只是為了找出各個 web framework 適不適合自己所用的專案而已。 同樣都說是 framework,輕量級跟重量級可是差很多的。

我目前只要小小的 framework。

:p

 

參考:

http://www.cherrypy.org/

http://webpy.org/

https://www.djangoproject.com/

http://www.web2py.com/