2009年12月17日 星期四

利用 cron 與 rsync 備份資料

Reference:
鳥哥的私房菜 - 例行性工作排程rsync manualA turial on using rsyncrsync exampletar - exclude files

上次電腦當機後,決心要幫電腦資料做定期備份,才不會一次打破整籃雞蛋,我的構想是每天晚上利用 rsync 備份更動最頻繁的 home 到另一顆硬碟上,每周五利用 tar 將不見時會搥心肝的重要資料打包成 gz 存到另一顆硬碟,再燒到光碟上,並存入隨身碟,總共存放在三處,如此一來,資料消失在世界上的風險性相信可以大大降低。

不過存放備份的硬碟是 fat 格式,造成 rsync 時沒辦法複製權限和一堆有的沒的東東而錯誤,卡在那邊花了不少時間,後來就隨它去了,不能設權限也沒差,反正資料在就好,而且用 tar 打包時就可以保留檔案權限了,而 tar 時原本想用 bzip2 或 lzma 壓縮,但是所花的時間多到讓我受不了,乾脆用簡單的 gzip ,有壓總比沒壓好,下一步要把 anacron 搞懂,才不會因為有時電腦沒開而少了一次備份。

備份的 script 都是用 python 寫的,rsync 的 exclude 跟 tar 有點不太一樣,為了研究這個還花了不少時間, 不過有了範本後,下次要寫其他 script 應該可以更快上手。
rsync script:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# use 'rsync' to backup files to a fat partition
# write logs into log_file

import time
import sys
import subprocess as sp

# not configure ACL, xattrs currently(can use -AX to sync)
# the same as -va --compress -stats --delete
# args = " --verbose --archive --compress --stats --delete "

# because sync file from ext3 to vfat lead to errors (vfat don't have
# some file attributes), need to remove some args
args = " --verbose --recursive --times --compress --delete "

# need to sync some windows program, so use exclude
# instead of --cvs-exclude
ex_PATTERN = [ "*~", "*.pyc",\
"**cache**","**Cache**","**CACHE**", "**.macromedia/",\
"**.opera/icons/", "**.thumbnails/"]

exclude = ''.join( map( lambda p: " --exclude=" + p, ex_PATTERN))

SRC = " /home/myHome"
DEST = " /mnt/HardDisk/back/sync"
# there is also --log-file=FILE option
log_file = "/home/mylog.log"

def write_log( messages ):
with open(log_file, 'a') as f:
f.writelines("\n***************************************\n")
f.writelines( time.ctime() )
f.writelines("\n***************************************\n")
f.writelines( messages )

try:
ret = sp.Popen(["rsync" + args + exclude + SRC + DEST],\
stdout=sp.PIPE,shell=True).communicate()[0]
write_log(ret)
except OSError, e:
write_log("Execution failed:" + e )





tar script:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# use 'tar' to backup files, save them as my_tar_Year_Month_Day.tar.gz
# write logs into log_file

import time
import sys
import subprocess as sp

# use -f in front of DEST to prevent args mix up
args = " -czv --exclude-caches-all"

SRC = " /mnt/HardDisk/my_precious \
/mnt/HardDisk/rotl "

TIME_STRING = time.strftime( "%Y_%m_%d", time.localtime() )

DEST = " /mnt/HardDisk/bak/mytar_" + TIME_STRING + ".tar.gz"

log_file = "/home/mytargz.log"

ex_PATTERN = [ "*~", "*.pyc",\
"**cache**", "**Cache**","**CACHE**",\
"**.macromedia/", "**.opera/icons/", "**.thumbnails/"]

exclude = ''.join( map( lambda p: " --exclude=" + p, ex_PATTERN))


def write_log( messages ):
with open(log_file, 'a') as f:
f.writelines("\n***************************************\n")
f.writelines( time.ctime() )
f.writelines("\n***************************************\n")
f.writelines( messages )

try:
# use -f in front of DEST to prevent args mix up
ret = sp.Popen(["tar" + args + exclude + " -f " + DEST + SRC ],\
stdout=sp.PIPE,shell=True).communicate()[0]
write_log(ret)
except OSError, e:
write_log("Execution failed:" + e )

2009年12月8日 星期二

Easy iptables log analyzer

之前寫 iptables rule 的時候,偶爾會翻一下 log 來看有沒有哪些設定出問題,可是蠢人如我只會用簡單的 grep ,主要還是靠肉眼檢視,網路上找到的 analyzer 還要架 http 伺服器和 database,想說只是自己單機要用,不必那麼麻煩,也順便練習寫 python ,就寫了這個小程式做篩選,但先天規劃不良,後來反覆改寫花了不少時間,改到現在也沒那個熱血去翻 iptables log 了 XDD~

這程式主要是利用 sqlite3 這個 module 來把分析過後的 log 存在記憶體內,所以每次使用都要分析一遍,並沒有存實體檔案,因為我當初只想說偶爾看一下而已,沒想太多 :)

分析跑完後會出現一個 CLI ,輸入?就會列出可使用的 command list,主要就是送 query 查詢,可以選擇要顯示哪些欄位,也有些暫存的字串可以紀錄,不用每次打一大串指令,查詢完會先顯示有多少符合的 log,然後就可決定要將結果輸出或存成檔案。

分析的欄位有點簡陋,只有 Interface, IP , Port, Protocol, TCP flags ,其他的全包成同一個字串,有很大的改善空間,但是我很懶惰,所以... XD

檔案下載:eila.tar.gz

2009年12月3日 星期四

[Link] Python Speed

Python Speed
PerformanceTips
Python Patterns - An Optimization Anecdote

可以用 profile 來檢視執行效率

看了以上幾篇,讓我想法改變不少,不過如果完全照裡面的作法來寫,程式碼會變得不怎麼好看而且不好維護,感覺跟 zen of python 有相抵觸

另外還翻到在 lambda 裡面用 if / else 的方法:
  1. Boolean Operations:利用 and, or
  2. x if C else y:會先判斷 C ,再決定要執行 x 或 y
感覺上第一個比較不直覺,但是第二個似乎也不怎麼好看...

2009年11月22日 星期日

Superblock last mount time is in the future

今天下午電腦當機後, 等到能重開機起來時出現錯誤,紀錄一下如何解決:

CMOS Check Sum Error - Default loaded,
表示 BIOS 恢復原始設定,如果之前有動過,要重新調整,進入 Linux 開機流程後,又出現

Filesystem Check Error : Superblock last mount time is in the future,
這是因為 BIOS 時間重設所造成的問題,只要 mount -a , 重新掛載磁區,等 ntpd 起來再更新時間即可,

另外為了保險起見,用 fsck 檢查一下各個磁區,
先編輯 /etc/fstab ,將各個磁區的 pass 改為 2 ,
下 shutdown -Fr now ,就會重新開機並執行 fsck 了
如果沒有出現錯誤再將 /etc/fstab 修改為原本狀態

另:
fdisk -l 顯示目前有抓到哪些磁區
blkid 可列印出各磁區的 uuid 供檢查

2009年11月20日 星期五

Play mms streams on linux

自從寫了 hipls 抓 Hinet Radio 位址後,聽廣播的次數就變多了,只是平常都只用 mplayer ,偶爾看完影片想聽點音樂,聽完電波歌想看部動畫,切來切去實在是很煩,就打算找一個播放器專門放音樂,mplayer 就單純拿來播放影片,這時才發現要找個能支援 mms 的播放器還真不簡單...

  1. audacious2:之前用 openSUSE 時所使用的播放器,介面很簡潔,另外在 Arch Linux 上也有 audacious-plugins 這個 package 可增加一些功能,但是安裝後卻發現連一般的網路電台都不能播放... 用 shell 開啟一看,噴了一堆錯誤訊息...

    Failed to load plugin (/usr/lib/audacious/Input/musepack.so): libtag.so.1: 無法開啟共用目的檔: 沒有此一檔案或目錄
    Failed to load plugin (/usr/lib/audacious/Input/wavpack.so): libwavpack.so.1: 無法開啟共用目的檔: 沒有此一檔案或目錄
    Failed to load plugin (/usr/lib/audacious/Input/cdaudio-ng.so): libcdio_cdda.so.0: 無法開啟共用目的檔: 沒有此一檔案或目錄
    Failed to load plugin (/usr/lib/audacious/Input/sid.so): libsidplay.so.1: 無法開啟共用目的檔: 沒有此一檔案或目錄
    Failed to load plugin (/usr/lib/audacious/General/mtp_up.so): libmtp.so.8: 無法開啟共用目的檔: 沒有此一檔案或目錄
    Failed to load plugin (/usr/lib/audacious/Visualization/projectm-1.0.so): libprojectM.so.2: 無法開啟共用目的檔: 沒有此一檔案或目錄
    Failed to load plugin (/usr/lib/audacious/Transport/neon.so): libneon.so.27: 無法開啟共用目的檔: 沒有此一檔案或目錄
    Failed to load plugin (/usr/lib/audacious/Transport/mms.so): libmms.so.0: 無法開啟共用目的檔: 沒有此一檔案或目錄
    LASTFM: (cleanup) Cleanup finished
    WTH...這些明明都是 audacious-plugins 裡的 dependencies 啊!翻 PKGBUILD 似乎也沒問題 (其實我不是很懂,只是裡面有這些 packages ),看到裡面有提到 libmms ,想必就是負責 mms 播放吧?安裝這些 package 後 (libmpcdec, taglib, wavpack, libcdio, libsidplay, libmtp, projectm, neon, libmms ),開啟時一切正常,但是設定內並沒有出現關於 mms 的 plugin,當然也沒辦法播放,然後 freeze 掉...突然有種被耍的感覺..
  2. exaile:介面看起來也很清爽,裝完後連個 mp3 都不給放...後來加上 gstreamer0.10-bad-plugins, gstreamer0.10-ugly-plugins, gstreamer0.10-ffmpeg 看起來應該正常,但在播放 mms stream 時還是一樣會 freeze,必須要用 shell 開啟,送它個 Keyboard Interrupt 才會開始播放,看起來是 exaile 傳給 gstreamer 時出了問題,原本打算勉強用,但是那 CPU 使用率令我打消了念頭...
  3. totem:安裝的時候一併裝了 gstreamer ,還是不能播,但我懶得去找問題出在哪邊...有興趣的人可以試試 totem-xine 看看
  4. vlc:好久沒用,現在已經 1.0.3 了,看起來也挺順眼,最重要的是,播放正常啊!!播放清單也可以正常顯示,雖然安裝所需空間比較大,但這只是小小的缺點,能用最重要 :)
結論:懶人就用 vlc 吧!而且它還可以正常顯示用 UTF-8 存的播放清單,同份檔案在 SMPlayer 裡面則是一片亂碼,堅持 lightweight 的人則可以找使用 gstreamer 或 xine 的輕巧播放器試試。

2009年10月27日 星期二

my iptables rule

網路狀態: 電腦直接連中華電信小烏龜 ADSL 上網,沒有開任何服務,只有裝 openntpd 利用 time.stdtime.gov.tw校時,針對 port scan 作防範,對於 icmp 封包沒有設防,INPUT 預設 log後丟棄

Ref: packet-filtering-HOWTO酷學園翻譯鳥哥私房菜- Linux 防火牆與 NAT 主機
酷學園小州學長範例ArchWiki石牌國小防火牆設定ip-sysctl.txt

Updated 10/30:網路設定 pppoe-setup 時若有選擇防火牆 (Standalone 或 Masq) 也會影響 iptables 設定,記得重跑一次,選擇 None


#! /bin/sh
#
# Create iptables'rules, remember to move it to
# /etc/iptables , then modify /etc/conf.d/iptables
#
# Author : lefthaha (at) gmail {dot} com
# Last Modify : 2009 /10 / 26

# clean current rules
iptables -F
iptables -X
iptables -Z

# set Policy
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# accept traffic from loopback iterface
iptables -A INPUT -i lo -j ACCEPT
# accept ICMP messages
iptables -A INPUT -p ICMP -j ACCEPT
# accept establised packet
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

# create new chain
iptables -N block
iptables -N open
iptables -A INPUT -p TCP -j block
iptables -A INPUT -j open

# log then reject packet for imitate default behaviour
iptables -A INPUT -j LOG
iptables -A INPUT -p TCP -j REJECT --reject-with tcp-reset
iptables -A INPUT -p UDP -j REJECT --reject-with icmp-port-unreachable

#################### block chain rules ###################
# from http://www.study-area.org/tips/iptables_def.htm and
# http://wiki.archlinux.org/index.php/Simple_stateful_firewall_HOWTO
# http://www.spps.tp.edu.tw/documents/memo/iptables/iptables.htm

# Force SYN packets check
iptables -A block -i ppp0 -p TCP ! --syn -m state --state NEW -j DROP
# NMAP FIN/URG/PSH
iptables -A block -i ppp0 -p TCP --tcp-flags ALL FIN,URG,PSH -j DROP
# Xmas Tree
iptables -A block -i ppp0 -p TCP --tcp-flags ALL ALL -j DROP
# another Xmas Tree
iptables -A block -i ppp0 -p TCP --tcp-flags ALL SYN,RST,ACK,FIN,URG \
-j DROP

# nmap-Xmas
iptables -A block -i ppp0 -p TCP --tcp-flags URG,PSH,FIN URG,PSH,FIN \
-j DROP

# Null Scan
iptables -A block -i ppp0 -p TCP --tcp-flags ALL NONE -j DROP
# SYN/RST
iptables -A block -i ppp0 -p TCP --tcp-flags SYN,RST SYN,RST -j DROP
# SYN/FIN
iptables -A block -i ppp0 -p TCP --tcp-flags SYN,FIN SYN,FIN -j DROP
# FIN
iptables -A block -i ppp0 -p TCP --tcp-flags ALL FIN -j DROP

#################### open chain rules ####################
# for opened services

# for the connection close FIN/ACK packet
iptables -A open -p TCP --tcp-flags ALL ACK,FIN --sport 80 \
--dport 1024: -j ACCEPT

iptables-save > my_firewall.rules

echo If No error message, use iptables -L -nv to check,
echo Next move ./my_firewall.rules to /etc/iptables
echo then modify /etc/conf.d/iptables to load the rules at boot

2009年10月26日 星期一

Network basic concept

最近在設定 iptables , 要有一些基本知識,就翻了些網頁,順便做點筆記,以後忘掉時才有東西可查

Ref:鳥哥私房菜 - 網路基礎概念Network Sorcery - IPRFC791酷學園 - TCP 與 UDPNetwork Sorcery - TCPRFC793




A Class :
0xxxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx ==> NetI_D 的開頭是 0
|-Net-ID|-----------Host-ID-------|
B Class :
10xxxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx ==> NetI_D 的開頭是 10
|-----Net-ID-----|----Host-ID-----|
C Class :
110xxxxx.xxxxxxxx.xxxxxxxx.xxxxxxxx ==> NetI_D 的開頭是 110
|----------Net-ID---------|-Host-ID|

三種分級在十進位的表示:
A Class : 0.xx.xx.xx ~ 126.xx.xx.xx
B Class : 128.xx.xx.xx ~ 191.xx.xx.xx
C Class : 192.xx.xx.xx ~ 223.xx.xx.xx

Network : Host-ID all '0' , first IP in that that network
Broadcast : Host-ID all '1' , last IP in that that network
Netmask : Net-ID all '1' , Host-ID all '0'
Network / Netmask : Network / bits , bits = How many Net-ID bits

example.
a.
192.168.0.0 / 24
available ip -- 192.168.0.0 ~ 192.168.0.255
b.
192.168.0.128 / 25 is the same with 192.168.0.128/255.255.255.128
25 bits fo Net-ID , available ip -- 192.168.0.128 ~ 192.168.0.255

private IP
A Class:10.0.0.0 - 10.255.255.255
B Class:172.16.0.0 - 172.31.255.255
C Class:192.168.0.0 - 192.168.255.255

three-way handshake:
1.
Server is listening , Client sent TCP packet (SYN , seq = 1200)
# 1200 is the initial sequence number ,
# server expect the first data byte seq = 1200+1
# server also replies a sequence number to client
2.
Server replies packet ( SYN ,ACK, seq = 2340 ack = 1201 )
# Client will also expect server to sent data for seq = 2340+1
3.
Client replies packet (ACK , ack = 2341, seq = 1201 )

2009年10月20日 星期二

HomeBank 基本觀念翻譯

因為個人對金錢沒什麼觀念,就找了個記帳軟體來警惕一下自己 :)

HomeBank 在 Windows 和 OSX 及 Linux 上都可執行,雖然功能有點陽春,但現在對一個只有支出沒有收入和資產的家裡蹲應該足夠了,或許以後會嘗試看看 GnuCash

翻譯文件來源:HomeBank User Manual

我平常是使用英文版,大部份名詞是參考中文版的 HomeBank 加上一些自己的瞎猜 :)

基本觀念:

錢包(Wallet):最高的資料層級,相當於一個 HomeBanke 檔案 (.xhb),其下可建立不同帳號與交易

帳戶(Accounts):第二層的資料,許多不同的帳戶構成一個錢包,每個帳戶下可擁有許多的交易

交易(Transactions):最下層的資料,許多筆的交易形成了帳戶下的金錢流動,另外還提供了幾筆特別的資料欄位
  • 標籤(tags):每筆交易可擁有許多標籤,以空白來分隔不同的標籤,最後可用來分析或分類
  • 付款方式(payment):顯示付款方式的小圖片
  • 資訊(info):有關付款方式的一些資訊,例如日期或支票號碼等 (使用透支報告時只會顯示敘述,不顯示資訊!)
  • 提醒(remind state):追蹤借出去的款項
  • 統計報告(Statistics report):可依照分類、收/付款人、標籤、月、年來顯示交易總和
  • 透支報告(OverDrawn report):可依時間列出各項交易
  • 汽車報告(car-cost data):包含一些有關車輛資料,如加油、里程數…等

Archives(中文版翻的很怪 -"封存的資料庫"):有規律性的金錢匯入或扣款,例如每個月的薪水入帳、房貸扣款、保險費、稅金…等

收/付款人(Payees):可用來分析或分類交易紀錄,輸入過一次後,會自動儲存在清單內供使用者選取

分類(Categories):一樣可用來分析交易紀錄,並可設定次分類、這分類是否為收入

預算(Budget):可為某些分類設定每個月的預算上限,最後用來比對實際上的花費或收入

結餘(Balances):分成三個部份來呈現不同時間點的結餘
  • 銀行(Bank):"有效交易(validated transactions)" 的金額總和
  • 今天(Today):目前的結餘,交易日期在今日之前(包含今日)的交易金額總和 (包含尚未認証(validate)的交易)
  • 未來(Future):包含所有交易的結餘(可設定某些交易日期在未來發生,如還款或信用卡扣款)

2009年10月19日 星期一

[Python] Slicing on sequences

今天在 comp.lang.python 的討論裡看到一篇 Reverse Iteration Through Integers
,提到 list[::-1] 的用法,就找了一下 python docs

Sequences also support slicing: a[i:j] selects all items with index k such that i <= k < j.

When used as an expression, a slice is a sequence of the same type.

This implies that the index set is renumbered so that it starts at 0.

Some sequences also support “extended slicing” with a third “step” parameter: a[i:j:k] selects all items of a with index x where x = i + n*k, n >= 0 and i <= x < j.



所以 a[::-1]  的 index X 會由 X = 0+1*(-1) = -1,X = 0+2*(-1) = -2 這樣慢慢往回跑

Test code:
#! /usr/bin/env python
# -*- coding: utf-8 -*-
a = 123450
print "a=",a,"\t type = ",type(a)
b = str(a)
print "b=",b,"\t type = ",type(b)
c = b[::-1]
print "c=",c,"\t type = ",type(c)
d = int(c)
print "d=",d,"\t type = ",type(d)

[小程式]hipls

有時候無聊會想聽聽廣播,又懶得多開一個網頁, hinedo 似乎可以直接播放,但之前用 openSUSE 時編不起來,就乾脆自己寫一個,這程式會直接到 hiChannel 抓所有的廣播電台清單,讓使用者選擇想聽那幾個電台,然後再將這幾個電台網址存成一份 playlist ,只要使用支援 mms 協定的播放器播放就可以聽了,目前遇到的問題是用 mpayer 播放會顯示亂碼...

用 python 內建函式庫寫的,照理說 windows 也可以使用,不過我只在 linux 上試過,有問題歡迎回報 :)

Updated 11/05:修改顯示電台清單時,因為中文字元長度問題而無法對齊的狀況

Usage:
1. save as hipls.py
2. python hipls.py

Download:hipls.py

Source Code:

#! /usr/bin/env python
# -*- coding: utf-8 -*-
#
# Author : lefthaha (at) gmail{dot}com
# License :http://creativecommons.org/licenses/by-nc-sa/2.5/tw
# Last Modify : 2009/11/05
#

import sys
import urllib2
import re
import string

def get_html(url):
# must add header to connect hichannel
# http://www.voidspace.org.uk/python/articles/urllib2.shtml
headers = {"User-Agent":" Mozilla/5.0 "}
req = urllib2.Request(url, None, headers)
response = urllib2.urlopen(req)
return response.readlines()

def get_match(pattern, target):
result = []
for line in target:
result.append( pattern.findall(line) )
# strip empty result , able to handle multiple matches
result = filter(lambda x: x is not None, result)
result = [ x[i] for x in result for i in range( len(x) ) ]
return result

def show_all(rlist):
# Updated 2009/11/05
print "目前搜尋到的電台有:"
for num in range(0, len(rlist)-1, 2):
name1 = rlist[num].name.decode("UTF8")
mytab = len(name1.encode("BIG5")) - len(name1)
print "({0:02}) {1:{4}} ({2:02}) {3}".format(num+1,\
rlist[num].name, num+2, rlist[num+1].name, 30+mytab)
print "請輸入你喜歡的電台編號,並且以逗號區別 (ex : 5,4,3,2,1):"

def edit_list(rlist):
show_all(rlist)
inl = re.split(r",|," ,sys.stdin.readline() )
print "你所輸入的電台順序是:"
for num in range( len(inl) ):
inl[num] = string.atoi(inl[num])-1
print "({0}) {1}".format(num+1,rlist[inl[num]].name)
print "以上是否正確?(Y/n)"
if re.match(r"[y|Y]", sys.stdin.readline() ) is not None:
return inl
else:
print "請重新選擇電台順序"
return None

def create_list(all_list, to_save):
entries = len(to_save)
content = "[playlist]\nNumberOfEntries={0}\n\n".format(entries)
for num in range(entries):
content = content + \
"File{0}={1}\nTitle{0}={2}\nLength{0}=-1\n\n".format(num+1,\
all_list[ to_save[num]].get_mms(),all_list[ to_save[num]].name )
content = content + "Version=2"
plsf = open("MyHipls.pls",'w')
plsf.write(content)
plsf.close()

class Radio:
def __init__(self, rid_url):
# strip useless strings
rid_url = re.sub( r".*id=|&lt;", "", rid_url)
rid_url = re.sub( r"\">", ",", rid_url)
# split and assign radio id and name
self.rid, self.name = re.split(",", rid_url)
self.player_url="http://hichannel.hinet.net/player/radio/\
index.jsp?radio_id=" + self.rid
def get_mms(self):
page = get_html(self.player_url)
#?data=mms://bcr.media.hinet.net/RA000007&id=RADIO:206&group="+g);
line = get_match(re.compile(r".*=mms:.*"), page)
line = re.sub(r".*mms", "mms", line[0])
self.mms_url = re.sub(r"&id.*", '', line)
return self.mms_url

def main():
list_url = "http://hichannel.hinet.net/radioRank.do?typeId=99"
list_page = get_html(list_url)
# example : &lt;a href="/radio.do?id=177">ICRT&lt;/a>
rids = get_match( re.compile(r"&lt;a.*\"/radio.+\d\">[^&lt;]+?&lt;"), list_page)
radio_list=[]
for line in rids:
# initialize class Radio
radio_list.append( Radio(line) )
list_to_save = None
while( list_to_save is None):
list_to_save = edit_list(radio_list)
create_list(radio_list, list_to_save)
print "已將所選擇的電台清單儲存至 MyHipls.pls !"

if __name__ == "__main__":
main()

2009年10月14日 星期三

Use XDM with LXDE

ref : Arch WIki Install LXDE on Archlinuxgcin man page XDM Problems kill xconsole after login

因為昨天 system update 後 gdm 跑出一堆錯誤訊息,功能也不太正常,乾脆換成用 xdm 登入,順便將啟動 X11 的方式改成 inittab method,過程紀錄如下

edit ~/.xinitrc
-------------------------------------
#!/bin/sh
#
# lefthaha's xinitrc
# ~/.xinitrc
#
#
export LC_CTYPE="zh_TW.UTF-8"

# for GCIN input method
export XMODIFIERS=@im=gcin
export GTK_IM_MODULE=gcin
export QT_IM_MODULE=gcin
gcin &

#stop system beep
xset b off

exec ck-launch-session startlxde
-----------------------------------------
exit editor
chmod +x ~/.xinitrc (!!!!! important !!!!!)

edit /etc/inittab (remember to backup)
from " id:3:initdefault: " change to " id:5:initdefault: "

edit /etc/X11/xdm/Xsetup_0
comment xconsole

after login , if recieve message "GTK+ icon theme is not properly set"
use lxapperance ,apply again

2009年10月9日 星期五

urxvt 設定

Update 2009/10/26 :用 gcin 在 urxvt 內輸入中文有時可行,有時又沒辦法輸入...不知道問題在哪...
Update 2010/11/14 :修改完 ~/.Xdefaults 還要再用 xrdb -merge ~/.Xdefaults ,接著呼叫 urxvt 才能讀到最新設定

Update 2010/12/26 :設定 geometry,讓內容可以顯示到 80x24

ctrl + shift - down arrow : create new tab
ctrl + shift - left / right arrow : switch between tabs


# lefthaha's ~/.Xdefaults
# after modified, use ` xrdb -merage ~/.Xdefaults ` to reload setting
# then launch `urxvt` again to test

# turn compile xft on
#(copy from arch wiki,may increase performance)
URxvt.buffered: true

# set colors
URxvt.background: black
URxvt.foreground: 7
URxvt.cursorColor: green
URxvt.underlineColor: green

# set transparency
URxvt.transparent: on
URxvt.shading: 40

# set fonts
URxvt.font: xft:DejaVu Sans Mono:pixelsize=16,\
xft:Firefly New Sung Mono:pixelsize=16

# set input method
URxvt.inputMethod: gcin
URxvt.preeditType: Root
URxvt.imLocale: zh_TW.UTF-8

# set tabs
URxvt.perl-ext-common: default,tabbed

# set window size
URxvt.geometry: 86x28

# set clickable URLs
URxvt.perl-ext : default,matcher
URxvt.urlLauncher : /usr/bin/firefox
URxvt.matcher.button : 1

# set misc
URxvt.jumpScroll: True
URxvt.cursorUnderline: True
URxvt.cursorBlink: True



Reference:arch wiki-rxvt-unicoderxvt-unicode man pagefaqArch Linux Forums - Configure My urxvt!

讓 xpdf 能正常顯示中文 (Arch Linux)

除了 xpdf 外,要另外安裝 xpdf-chinese-traditional,修改 /etc/xpdf/xpdf.chinese-traditional ,將 displayCIDFontTT 的字型改成可以顯示中文的字體

範例:


#----- begin Chinese Traditional support package (2004-jul-27)
cidToUnicode Adobe-CNS1 /usr/share/xpdf/Adobe-CNS1.cidToUnicode
unicodeMap Big5 /usr/share/xpdf/Big5.unicodeMap
unicodeMap Big5ascii /usr/share/xpdf/Big5ascii.unicodeMap
cMapDir Adobe-CNS1 /usr/share/xpdf/CMap
toUnicodeDir /usr/share/xpdf/CMap
#displayCIDFontTT Adobe-CNS1 /usr/..../bkai00mp.ttf
#----- end Chinese Traditional support package
#這邊改成 odosung.ttc
displayCIDFontTT Adobe-CNS1 /usr/share/fonts/TTF/odosung.ttc

Arch Linux 安裝筆記

Reference:Official Arch Linux Install GuideBeginners' Guide
  1. /etc/fstab 要以 /dev/disk/by-uuid 來 mount ,否則開機時磁碟編號如果變動,就會出現 check filesystems fail ....
  2. rp-pppoe 設定網路時要先查好 DNS ,手動輸入 (Hinet DNS)
  3. 安裝 alsa-utils ,若 alsa-mixer 設定完依然沒有聲音,可再用 alsaconf 來試看看(Aureon Xfire 1723)
  4. 安裝 xorg,nvidia driver,使用 nvidia-xconfig 來產生 /etc/X11/xorg.conf,接下來starx 可以跑,但是滑鼠鍵盤沒反應;安裝 hal ,並新增到 /etc/rc.conf 的 DAEMONS 部份,使用者加上 hal 這個 group 就可成功抓到鍵盤與滑鼠
  5. 要安裝 vim ,必須先 rm /usr/bin/rview

2009年9月27日 星期日

Using SyntaxHighlighter on Blogger

1. 下載 SyntaxHighlighter
2. 上傳 scripts 和 styles 資料夾內的檔案至網站上(可只選擇自己需要的程式語言主題)
3. Layout -> Edit HTML -> 將下列程式碼貼在 < /head > 前



<!-- Syntax Highlighter Block start here -->
<link href='[ YOUR_SITE ]/shcore.css' rel='stylesheet' type='text/css'/>
<link href='[ YOUR_SITE ]/shthemedefault.css' id='shTheme' rel='stylesheet' type='text/css'/>
<script src='[ YOUR_SITE ]/shcore.js' type='text/javascript'></script>
<script src='[ YOUR_SITE ]/shbrushbash.js' type='text/javascript'></script>
<script src='[ YOUR_SITE ]/shbrushcpp.js' type='text/javascript'></script>
<script src='[ YOUR_SITE ]/shbrushplain.js' type='text/javascript'></script>
<script src='[ YOUR_SITE ]/shbrushpython.js' type='text/javascript'></script>
<script src='[ YOUR_SITE ]/shbrushsql.js' type='text/javascript'></script>
<script src='[ YOUR_SITE ]/shbrushxml.js' type='text/javascript'></script>
<script class='javascript'>
//<![CDATA[
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.all();
//]]>
</script>
<!-- Syntax Highlighter Block End here -->


將 [ YOUR_SITE ] 改成上傳 SyntaxHighlighter 的網址,並注意檔案名稱大小寫,依個人所需增減不同的程式語言(上面是我自己所用的不包含全部)和主題
另外,不要問我為什麼跟一堆教學寫的不同,因為我也是試了一個上午都搞不定,最後複製某網站的原始碼才成功...

使用方法如下:

<pre class="brush: BRUSH ALIASES ">
code
</pre>


把 BRUSH ALIASES 換成要用的程式語言,並記得將 < 換成 &amp;lt; 就行了

Upgrade Comix Bookmarks from 3.x to 4.x

!! Updated 2009/10/07 for comix 4.0.4 have changed the bookmark path

Comix 由 3.x 升級到 4.0時,會自動偵測之前的書籤,但只能選擇刪除,所以就自己寫程式將舊的書籤更新到新格式,順便學一下 Python 。
怠惰的天性使然,這個小程式花了好幾個月才完成(別打我,當兵的時候每次放假只想玩,沒什麼動力寫程式啊...),所以裡面的縮排和註解很亂,請多包涵,有空我會再花時間去看看 Style Guide for Python Code

使用方法:
1. Save as upbmk.py
2. chmod +x upbmk.py
3. ./upbmk.py OLD_BOOKMARK_FILE


#! /usr/bin/env python
# -*- coding: utf-8 -*-
# upbmk.py - Upgrade Comix bookmarks form 3.x to 4.x
# Usage : upbmk.py [ OLD_BOOKMARK_FILE ]

import os, sys, shutil, re
import cPickle
import subprocess

import zipfile, tarfile

if len(sys.argv)==2 :
ob_path=sys.argv[1]
else:
ob_path="./bookmarks_data"

# open current / old book mark file , make backups
# updated 2009/10/07 , for comix 4.0.4 changed bookmark path
# tStr = os.path.expanduser("~/.comix/bookmarks.pickle")
data_path = os.getenv("XDG_DATA_HOME", os.path.expanduser("~/.local/share") )
tStr = os.path.join(data_path,"comix","bookmarks.pickle")
shutil.copyfile( ob_path, "./backup_old_bookmarks_data")
shutil.copyfile( tStr, "./backup_current_bookmarks.pickle")
cbf = open(tStr,'r')
obf = open(ob_path,'r')

#load current and old bookmarks
cbk = []
cbk.append(cPickle.load(cbf))
cbk.append(cPickle.load(cbf))
odata = cPickle.load(obf)
odata2 = cPickle.load(obf)
obk = []
cbf.close()
obf.close()

for num in range(len(odata)):
temp = odata[num],odata2[num]
obk.append( temp )

del cbf,obf,odata,odata2

# distinguish file types
ZIP, RAR, TAR, GZIP, BZIP2 = range(5)
def what_type( filepath ):
try:
if not os.access( filepath , os.R_OK ):
print " You don't have the permission to read ",filepath,\
" ,you better check it out !! "
sys.exit()
if zipfile.is_zipfile( filepath ):
return ZIP
# use magic numbers to distinguish type
opf = open( filepath , 'r' )
magic = opf.read(8)
opf.close
if magic.startswith('\x52\x61\x72\x21\x1a\x07\x00'):
return RAR
if magic.startswith('\x1f\x8b\x08'):
return GZIP
if magic.startswith('\x42\x5a\x68'):
return BZIP2
# this can also read tar.gz , tar.bz2 ,so put it to the last one
if tarfile.is_tarfile( filepath ):
return TAR
# No of above , check it later
else:
return None
except Exception:
print " Error when reading ",filepath
return None

# test if command "rar" ,"unrar" exist or not
rcmd = None
for testcmd in ["rar","unrar"]:
try:
subprocess.Popen( [testcmd], stdout=subprocess.PIPE)
rcmd = testcmd
except Exception:
pass

# count how many image files in the archive
def get_pages( filepath , archive_type ):
all_files=[]
if archive_type == ZIP :
zfile = zipfile.ZipFile( filepath , 'r' )
all_files = zfile.namelist()
elif archive_type in ( TAR , GZIP , BZIP2 ) :
tfile = tarfile.open( filepath , 'r')
all_files = tfile.getnames()
elif archive_type == RAR :
if rcmd != None:
rout=subprocess.Popen([ rcmd,"vb",filepath],stdout=subprocess.PIPE)
# may contain one newline character
all_files = rout.stdout.readlines()
#print all_files
else:
print ' Unable to extract '+ filepath +' with "rar" or "unrar" '
# not an archive , just a image , scan the directory
elif re.search(r"\.(jpg|jpeg|png|gif|tif|tiff)\s?$", filepath, re.I):
all_files = os.listdir( os.path.dirname(filepath) )
# Error on reading files
else:
print ' Unable to handle" '+ filepath +'" , sorry'
return 0
imgs = 0
#count image files
for name in all_files:
if re.search(r"\.(jpg|jpeg|png|gif|tif|tiff)\s?$",name,re.I):
imgs = imgs + 1
# return number of total image files
return imgs

# convert tuple to list for manipulation
# insert filename,total pages,aechive type
obklist = []
for num in range(len(obk)):
obklist.append( list(obk[num]) )
obklist[num].insert( 0 , os.path.basename( obklist[num][0] ) )
file_type = what_type( obklist[num][1] )
obklist[num].append( get_pages( obklist[num][1], file_type) )
obklist[num].append( file_type )

for bmk in obklist:
cbk[1].append( tuple( bmk))

cbf = open(tStr,'wb')
cPickle.dump( cbk[0], cbf, cPickle.HIGHEST_PROTOCOL)
cPickle.dump( cbk[1], cbf, cPickle.HIGHEST_PROTOCOL)
cbf.close()

print " Upgrade Complete !! After Checking the new bookmarks,\n\
remember to delete backup files "

####### print out data inside bookmarks #########

#print len (cbk[1][0]) // 5
#for num in range(len(cbk[1][1])):
# print cbk[1][1][num-1]
#print cbk[1]
#print len(obk)
#print obk

######### bookmark file format ###########

# cbk = [ 'version',('cbookmarks') ]
# cbookmarks = [ (cbmk1),(cbmk2),....]
# cbmk = [ filename , path , bmk_page , total_pages , archive type]
# obk = [ oldbmk1 , oldbmk2 ...]
# oldbmk = [ path , bmk_page ]

2009年9月21日 星期一

Split(Rename) audio files by cue files

Reference:Split lossless audio (ape, flac, wv, wav) by cue file in Ubuntu
Tools: cuetools, shntools,audio file decoder

起因:
有塊 CD 整個壓成一個 *.tta 加 *.cue ,在 Windows 下要播放時,可用 foobar2000 直接讀取 *.cue ,但是在 linux 下似乎沒這麼方便,所以就乾脆把它每首都拆開

過程:
1. *.cue 用 more 下去看是亂碼, 用 gedit 一個個測才查出編碼是CP932
2. 怕命名以後也是亂碼,就用比較笨的方法, tta 先解成 wav,再下 cuebreakpoints *.cue | shnsplit *.tta, 分割成一個個的 split-track*.wav
3. 用 Python 讀 *.cue 進來, str.decode("CP932"), 確定可以正常顯示日文,再找每一首的檔名, os.rename() 重新命名

因為只有一塊要轉,就直接用 Python Interpreter 作業,一首首命名,沒寫什麼程式,單純紀錄一下所用的工具。

自去年入伍服役以後第一次更新 blog, 11 個月的時間總算熬過去了,外面的空氣真好 :)