2015年1月8日 星期四

暈眩症的治療方向

最近江蕙因為暈眩症,決定唱最後一次然後封麥。
我也有加拿大的親戚之前暈眩嚴重。根據親戚所述,知道那是很不舒服的。
不止是覺得頭暈,連眼睛看到的景像都會旋轉,尤其是在冬天。

當時得知此一情形,腦海裡浮現傷寒論中的一句:
 「少陽」之為病,口苦、咽乾、目眩也。
小柴胡湯(加減)。

還有金匱的痰飲咳嗽篇:

心下有支飲,其人苦冒眩,澤瀉湯主之。

親戚多處就醫(中西醫)都無效,
所以對於中醫古籍也是半信半疑(因為傷寒論應該中醫都有讀過吧,怎麼沒人想到?)。
他還是把藥帶回加拿大了,那時還是夏天,不嚴重所以一直沒吃。
等到天氣冷了,嚴重的暈眩開始發作時,才想說姑且吃看看吧。
結果發現吃了之後,暈眩很快就緩解了,還要我再幫忙買一些寄過去。

以上,給苦於暈眩的人參考。

2015年1月7日 星期三

喉嚨痛的失治

喉嚨痛,醫生說喉嚨有發炎。
西醫可能開消炎藥,中醫可能開清熱藥。
服用之後,有時卻痛得更嚴重!
是為什麼呢?

這牽涉了簡單又高明的中醫理論。
上方發炎過熱,是因為上方就是太熱? 或是下方太寒所以水無法上行去解熱?
如果是前者,消炎清熱或許有效;
如果是後者,消炎清熱之後,水更無法上行,所以喉嚨更痛。

怎麼辦呢? 使用溫熱脾胃與下焦的藥吧!


2014年12月30日 星期二

Python logging (一)

以下是python logging的徹底研究,大家可以一條一條的讀下去,相信會對logging模組的使用有幫助。
  1. 為何要使用logging?
    • 程式執行中,有時需要輸出一些訊息來記錄執行狀態、錯誤、...
    • 訊息可以寫在檔案中,較緊急的訊息可能同時要寫檔案、console顯示、寄email提醒、(或其它管道)
    • 使用logging模組,可以讓我們方便達成單一訊息送至多個管道的功能(個人覺得是最大的好處)
  2. 只在console顯示 (stderr, 預設等級warning以上才顯示,從輕到嚴重分成debug, info, warning, error, fatal/critical 五級)
  3. >>> import logging
    >>> logging.debug('Hi')
    >>> logging.info('Hi')
    >>> logging.warning('Hi')
    WARNING:root:Hi
    >>> logging.error('Hi')
    ERROR:root:Hi
    >>> logging.fatal('Hi')
    CRITICAL:root:Hi
    >>>
  4. 改成從sys.stdout輸出,層級是debug以上就顯示,可使用logging.basicConfig:
  5. >>> import sys
    >>> import logging
    >>> logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
    >>> logging.debug('Debug Msg')
    DEBUG:root:Debug Msg
    >>> logging.info('Info')
    INFO:root:Info
    >>> logging.warning('This is a warning')
    WARNING:root:This is a warning
    >>> logging.error('錯誤發生了')
    ERROR:root:錯誤發生了
    >>> logging.fatal('快來救人阿')
    CRITICAL:root:快來救人阿

  6. 注意:logging.basicConfig 必須在輸出訊息之前呼叫,而且只能呼叫一次。第二次就沒效了。
  7. logging.basicConfig 的詳細介紹,請呼叫 print(logging.basicConfig.__doc__),可看到它還有哪些參數可以使用。
  8. 如何將訊息輸出至檔案?
  9. # 輸出至 log.txt,如果已存在會接著記錄
    logging.basicConfig(filename='log.txt')
    # 輸出至 log.txt,同上
    logging.basicConfig(filename='log.txt', filemode='a')
    # 輸出至 log.txt,會開新檔案
    logging.basicConfig(filename='log.txt', filemode='w')
  10.  如何同時輸出至console和檔案?下例會同時輸出在console和log.txt中。當只有單一輸出時,可以用filename來指定目標檔案,或用stream來指定目標stream。如果要輸出至多個目標,就要將它們以list of handlers當參數傳入。
  11. >>> import sys
    >>> import logging
    >>> logging.basicConfig(handlers=[logging.StreamHandler(sys.stderr), logging.FileHandler('log.txt')], level=logging.CRITICAL)
    >>> logging.debug("Let's debug")    # 無輸出
    >>> logging.critical("Let's go crazy")
    CRITICAL:root:Let's go crazy
  12.  練習一下,如果要同時輸出到stdout和stderr,可以這麼作(當然我們應該不會真的這麼作):
  13. >>> import sys, logging
    >>> logging.basicConfig(handlers=[logging.StreamHandler(sys.stdout), logging.StreamHandler(sys.stderr)])
    >>> logging.warning('你確定要這麼作嗎?')
    WARNING:root:你確定要這麼作嗎?
    WARNING:root:你確定要這麼作嗎?
  14.  輸出的訊息格式是可以改的。例如我們如果要將訊息放在最前面,可以這麼作:
  15. >>> import logging
    >>> logging.basicConfig(format='%(message)s:%(levelname)s:%(name)s')
    >>> logging.warning('倒過來看會有些不習慣')
    倒過來看會有些不習慣:WARNING:root

  16. format當中,可以使用的參數有:
  17. %(name)s            logger名稱(之後介紹)
    %(levelno)s         10, 20, ... 50 =>DEBUG, INFO, WARNING, ERROR, CRITICAL
    %(levelname)s    DEBUG, INFO,  WARNING, ERROR, CRITICAL
    %(pathname)s    呼叫logging的執行原始碼的完整路徑
    %(filename)s       %(pathnames)s 中的檔名部份
    %(module)s          Module
    %(lineno)d           原始碼正執行到的行數
    %(funcName)s     Function name
    %(created)f         一筆log訊息的產生時間(time.time()  return value)
    %(asctime)s        一筆log訊息的產生時間(文字格式)
    %(msecs)d           一筆log訊息的產生時間的毫秒部份
    %(relativeCreated)d  從logging載入算起,至一筆log訊息產生所經毫秒數
    %(thread)d          Thread ID (if available)
    %(threadName)s      Thread name (if available)
    %(process)d         Process ID (if available)
    %(message)s       log訊息
  18. 時間的格式可以更改,方式是使用 datefmt 參數:
  19. >>> import logging
    >>> logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%Y/%m/%d %H:%M:%S')
    >>> logging.warning('Warning msg')
    2014/12/30 21:51:44 Warning msg
  20. 如果要印出milliseconds,不能使用datefmt='%Y/%m/%d %H:%M:%S.%f',而是要這麼作(參考 10 當中的 %(msecs)d ):
  21. >>> import logging
    >>> logging.basicConfig(format='%(asctime)s.%(msecs)d %(message)s', datefmt='%Y/%m/%d %H:%M:%S')
    >>> logging.warning('印出milliseconds的方法如上')
    2014/12/30 21:58:30.869 印出milliseconds的方法如上
待續.....
(目前個人自己並沒有更進階的需求,所以暫時就到此為止)

2014年12月29日 星期一

林海峰與藤澤朋齋的東坡棋故事

在Wikipedia上的林海峰先生介紹中,看到了他與藤澤朋齋的東坡棋故事。Wikipedia上寫的是錯的。我又試在用Google找了一下,發現看到的內容和Wikipedia上的差不多,也是錯的。Wikipedia寫說:
五勝一敗的林海峰於名人挑戰權中關鍵賽中遭遇藤澤朋齋九段,其師吳清源料中藤澤必以東坡棋(模仿棋)應戰,乃教之搶佔天元的破解法,使藤澤無從模仿。歷經十多小時之纏鬥,藤澤棄子投降。另外,棋界人士發現此戰從第一手至第七十三手竟與八年前吳清源對戰藤澤朋齋之對戰下位完全相同,為棋界至今津津樂道。
小時候在家裡看過三四十年前出版的「林海峰的人和棋」,當中有正確的版本。那本書應該還在,不過要花時間找一下。實際情形是,那一步天元是他自己臨場想的:
林海峰在和藤澤朋齋比賽之前,去找了吳清源。吳清源擺了自己之前和藤澤朋齋的棋,那一局藤澤朋齋下東坡棋,而且最後吳清源輸了。因此,受其思路之影響,林海峰前面下出了和吳清源相同的棋。
但是,林海峰臨場想說:「這樣下去不是辦法。當年老師輸了,我如果照老師的棋繼續下,最後也難逃敗局。」於是,他花了一兩個小時的時間(忘記是一個多或兩個多小時),思考下一手棋。長考後,他下在天元,讓對手無法再模仿。最後仍經過波折才贏得了該局,而非wikipedia所說,好像搶了天元就贏了(棋靈王看太多?)
先記錄在此,哪天找到了書,再去幫wikipedia改一下。

2014年11月23日 星期日

python 3.4 tkinter widgets (整理中)

以下是我用 dir(module name)撈出來整理的widgets資料,人工過濾了一些底層不大會直接用到的 class,仍可能有一些還沒濾掉。目前至少可以看出有哪些可能可以使用的widgets。

在簡易說明中,只有提示簡單的用法。如果完全沒使用過tkinter,可能要先去找Hello world之類的範例來起步。如果要看widgets有什麼屬性,可以用 widget_obj.config() 來顯示。

使用tix的widgets時,要記得使用tkinter.tix.Tk(),不然會有錯誤訊息。

其它可參考之資訊:
http://effbot.org/tkinterbook/tkinter-index.htm (有點舊,但是有助於觀念)
http://www.tkdocs.com/  (有持續更新,如果能夠看英文,建議看它的Tutorial)

tkinterttktix簡易說明或範例(日後補充)
Balloon ✓ 例如滑鼠移至按鍵時,冒出說明文字。
ba = Balloon()
ba.bind_widget(btn, balloonmsg='Hello', statusmsg='Hi')
Button ✓ ✓ ✓ btn = Button(text='Hello')
ButtonBox ✓ 方便一次新增多個按鍵
btnbox=ButtonBox()
btnbox.add('ok', text='OK', command=lambda : root.destroy())
btnbox.add('close', text='Cancel', command=lambda : root.destroy())
Canvas ✓ ✓ 此處有不錯的範例
CheckList ✓ chklist=CheckList()
chklist.hlist.add('choice1', text='This is Choice1') chklist.hlist.add('choice2', text='This is Choice2') checklist.setstatus('choice1', 'on') # or 'off' checklist.getstatus('choice1') # 回傳 'on', 'off'
Checkbutton ✓ ✓ ✓ ckbtn_var = IntVar()
ckbtn=Checkbutton(text='btn1', variable=ckbtn_var)
ckbtn_var.get() # 之後取值,值為 0, 1
ComboBox ✓ str_var = StringVar()
cb = ComboBox(variable=str_var)
cb.insert(tix.END, '一月')
cb.insert(tix.END, '二月')
cb.insert(tix.END, '三月')
str_var.get() # 讀取值
Combobox ✓ str_var = StringVar()
cb = comboBox(textvariable=str_var)
cb['values'] = ('一月', '二月', '三月')
str_var.get() # 讀取值
Control ✓ 一個輸入數字的文字框,附加上下鍵按紐。
v1 = IntVar()
ctrl = Control(variable=v1)
v1.get() # 讀取值
DialogShell ✓ 會跳出一個視窗。 ds = DialogShell() ds.popup() # 跳出 ds.popdown() # 消失
DirList ✓ Segmentation fault....
DirSelectBox ✓ Segmentation fault....
DirSelectDialog ✓ Segmentation fault....
DirTree ✓ Segmentation fault....
Entry ✓ ✓ ✓ 單行的文字輸入框
str_var = StringVar()
entry = Entry(textvariable=str_var)
str_var.get() # 讀取值
entry.get() # 也可以
ExFileSelectBox ✓ Segmentation fault....
ExFileSelectDialog ✓ Segmentation fault....
FileEntry ✓ Segmentation fault....
FileSelectBox ✓ Segmentation fault....
FileSelectDialog ✓ Segmentation fault....
Frame ✓ ✓ ✓ f1 = Frame() # container功用
Grid ✓ Layout manager
gd = Grid()
for x in range(3):
  for y in range(3):
    Label(text='{0}-{1}'.format(x,y), master=gd).grid(row=x, column=y)
gd.pack()
HList ✓ hl = HList()
hl.add('Item1', text='Item1 Text') # 最上層項目
hl.add('Item1.SubItem1', text='SubItem1 Text') # 第二層
# CheckList當中也有HList,可作出階層效果
InputOnly ✓ Segmentation fault....
Label ✓ ✓ ✓ Label(text='要顯示的文字')
LabelEntry ✓ Label + Entry。
le = LabelEntry()
le.label['text'] = '請輸入帳號'
le.entry.get() # 之後用這行來讀取值
LabelFrame ✓ ✓ ✓ Label + Frame
ttklf = LabelFrame()
ttklf['text'] = '標籤'
#### (tix.LabelFrame測試時不大能正常顯示)
tixlf = LabelFrame()
tixlf.label['text'] = '標籤'
LabeledScale ✓ 用Scrollbar的方式讓人輸入數字。
l_s = LabeledScale() # 預設是0~10的整數
l_s.scale['from'] = -10 #改成 -10~10
l_s.scale['to'] = 100        # -10~100
l_s.label['text']                # 取得目前的數字
Labelframe ✓ 參考LabelFrame
ListNoteBook ✓
Listbox ✓ ✓
Menu ✓ ✓
Menubutton ✓ ✓ ✓
Message ✓ ✓
Meter ✓
Misc ✓ ✓
NoteBook ✓
NoteBookFrame ✓
Notebook ✓ nb = ttk.Notebook()
#新增兩個tab
nb.add(ttk.Label(nb, 'Hello'), text='Tab 1')
nb.add(ttk.Label(nb, 'Hi'), text='Tab 2')
#目前所在的tab id
tab_id = nb.index(nb.select())
# 刪除 tab
nb.forget(tab_id)
OptionMenu ✓ ✓ ✓
PanedWindow ✓ ✓ ✓
Panedwindow ✓
PopupMenu ✓
Progressbar ✓
Radiobutton ✓ ✓ ✓
ResizeHandle ✓
Scale ✓ ✓ ✓
Scrollbar ✓ ✓ ✓
ScrolledGrid ✓
ScrolledHList ✓
ScrolledListBox ✓
ScrolledTList ✓
ScrolledText ✓
ScrolledWindow ✓
Select ✓
Separator ✓
Shell ✓
Sizegrip ✓
Spinbox ✓ ✓
StdButtonBox ✓
Studbutton ✓ ✓
TList ✓
Text ✓ ✓
Toplevel ✓ ✓
Tree ✓
Treeview ✓
Tributton ✓ ✓

  • 其它: (root = Tk())
    • 使用 Label 來顯示png檔:
      • 安裝 PIL (for python3)
        • sudo apt-get install python3-pil
        • sudo apt-get install python3-pil.imagetk
      • 程式碼:
        • from PIL import ImageTk, Image
          resized_image = Image.open(檔名) 
          img = ImageTk.PhotoImage(resized_image)
          label = Label(root, image=img)  
      • 注意事項:
        • 上方程式碼中的img,必須要是global variable或是依附在不會消失的物件上(例如 label.image = img),才不會在garbage collection時被清掉,導致無法顯示。
      • 同時顯示圖和文字:Label(text='....', image=img, compound=TOP/BOTTOM/LEFT/RIGHT/CENTER)
    • 修改 Label 的字型、大小、與加強效果
      • label = tk.Label(root, text='Hello')
      • label['font'] = (字型, 大小, 效果)
        • 字型:字串,例如 Times, arial
        • 大小:數字
        • 效果:normal, bold, italic, underline, overstrike,可一次使用多個
      • Example: label['font'] = ('Times', 20, 'bold italic')
    • 視窗最大化/全螢幕:
      • root.attributes('-zoomed', True)  # 最大化
      • root.attributes('-fullscreen', True) # 全螢幕
    •  

2014年8月29日 星期五

紐西蘭開車與台灣開車本質上的不同

在紐西蘭和台灣開車,表面上的不同,是紐西蘭靠左行駛,而台灣靠右。另外,還有幾個口訣, 例如大彎讓小彎、幹道優先行等等。除了表面上的不同,如果能夠認清本質上的差異,在紐西蘭開車就能更得心應手。

開車是一群人的事,那一群人要有共識,才不容易出事。在台灣的市區,因為地狹人稠,大家開車的車速不會特別的快,但是常常會鑽來鑽去、切換車道。經過沒紅綠燈的交叉路口常會減速,以防有其它車子衝出來。有個美國人說:「在台灣,車子都離你很近,但是不會撞到你;在美國,車子看起來離你很遠,但是會撞到你。」大家多少都不大守規則,但是也提防人家不守規則,這就是台灣市區的開車。

在紐西蘭的路上,優先順序是很嚴格的。在行人優先的地方,行人過馬路常是不看路的,因為他覺得司機一定會讓他;在大小路交會處,大路的車優先,經過交會處是不會減速的,因為他覺得小路的車子一定會讓他。台灣人剛去紐西蘭,就算身處幹道,經過交會處仍會減速以防萬一,但是後方的當地人可能就不習慣了,他們不會減速,反而有可能撞上你。另外,紐西蘭人比較少換車道,但是他們在自己的車道上,會習慣性的超速。相對的,他們也不會預期其他人會沒事換車道。在那兒,大家比較遵守規則,但是不大會去提防人家不遵守規則。當你不遵守規則會有危險,甚至你去提防人家不守規則時也可能有危險。當路權是你的,你就是不要減速。

當兩種習慣不同的人,在路上開車時,就容易出事。去紐西蘭開車時,認清本質上的差異,就容易理解他們的規矩,進而以紐西蘭的方式在紐西蘭開車,如此就可以減少出事的機率,可以快樂出門,平安回家。

2014年8月28日 星期四

今天灌了ubuntu14.04...

灌完之後,想要在panel新增一些東西。
發現mouse右鍵按下去,居然沒有反應。
上網路查,發現很多人也有類似的問題。
有人說要按Windows+Alt+右鍵,但是我試了仍然不行。
我的mouse右鍵是好的,在其它地方按右鍵都有用。

現在,決定要改灌 lubuntu 了.....