環境是 python 2.7 下:
import urllib
#測試初始 unicode 字串物件
strUnicode = u"test data"
#字串型態為 UNICODE
type(strUnicode)
<type 'unicode'>
#開始 url encode,先將 unicode 編碼為 utf-8,再 url encode (quote),得到 utf-8 字串物件
strResult = urllib.quote(strUnicode.encode("utf-8"))
type(srtResult)
<type 'str'>
#開始 url decode,將上面的結果進行 url decode (unquote),再解碼回 unicode 字串物件
strResult = urllib.unquote(urllib.quote(u_str.encode("utf-8"))).decode("utf-8")
type(srtResult)
<type 'unicode'>
2016年7月10日 星期日
2016年7月9日 星期六
ubuntu 下改 mysql 編碼
查詢目前資料庫編碼
mysql> status;
...
Server characterset: latin1
Db characterset: latin1
Client characterset: utf8
Conn. characterset: utf8
設定並重啟
$ sudo vi /etc/mysql/conf.d/charset.cnf
[client]
default-character-set=utf8
[mysqld]
character-set-server=utf8
collation-server=utf8_unicode_ci
$ sudo service mysql restart
再查詢一次
mysql> status;
...
Server characterset: utf8
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
mysql> status;
...
Server characterset: utf8
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
2016年7月8日 星期五
deploy django + mysql + ubuntu + apache
sudo apt-get update
sudo apt-get upgrade
安裝 apache
sudo apt-get install apache2
安裝 Django less than 1.9
sudo apt-get install python3-pip
sudo apt-get install python3-pip
sudo python3 -m pip install "Django<1.9"
安裝 apache 模組 - wsgi
sudo apt-get install libapache2-mod-wsgi-py3
安裝 apache 模組 - wsgi
sudo apt-get install libapache2-mod-wsgi-py3
安裝 mysql 過程會設定 mysql root 密碼
sudo apt-get install mysql-server libapache2-mod-auth-mysql安裝 mysql 官方 python-connector
到 mysql 下載 mysql-connector-python-py3_2.1.3-1ubuntu14.04_all.deb
sudo dpkg -i mysql-connector-python-py3_2.1.3-1ubuntu14.04_all.deb
測試登入 mysql
FLUSH PRIVILEGES;
以上為 mysql shell 內使用的命令
新增 django 專案
django-admin startproject my_proj
同步 django ORM model 到 mysql TABLE
cd my_proj
python3 manage.py makemigrations
python3 manage.py migrate
/etc/apache2/sites-available 下新增 my_proj.conf
<VirtualHost *:80>
WSGIScriptAlias / /home/ubuntu/git_code/my_proj/my_proj/wsgi.py
<Directory /home/ubuntu/git_code/my_proj/my_proj>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
Alias /static /home/ubuntu/git_code/my_proj/static
<Directory /home/ubuntu/git_code/my_proj/static>
Require all granted
</Directory>
WSGIDaemonProcess my_proj python-path=/home/ubuntu/git_code/my_proj:/usr/local/lib/python3.4/dist-packages
WSGIProcessGroup my_proj
</VirtualHost>
套用 site 設定
sudo a2ensite my_proj.conf
sudo service apache2 reload
重啟 apache
sudo service apache2 restart
測試登入 mysql
mysql -u root -p
mysql 設定檔 /etc/mysql/conf.d
修改資料庫編碼 文章連結
新增資料庫
mysql>create datebase db_name;
顯示所有資料庫
mysql>show datebases;
mysql 新增使用者與設定權限
以下為 mysql shell 內使用的命令
use mysql;
INSERT INTO user(host,user,password) VALUES('localhost','user_name',password('user_pwd'));
FLUSH PRIVILEGES;
GRANT ALL ON db_name.* TO 'user_name'@localhost IDENTIFIED BY 'user_pwd';FLUSH PRIVILEGES;
以上為 mysql shell 內使用的命令
新增 django 專案
django-admin startproject my_proj
同步 django ORM model 到 mysql TABLE
cd my_proj
python3 manage.py makemigrations
python3 manage.py migrate
/etc/apache2/sites-available 下新增 my_proj.conf
<VirtualHost *:80>
WSGIScriptAlias / /home/ubuntu/git_code/my_proj/my_proj/wsgi.py
<Directory /home/ubuntu/git_code/my_proj/my_proj>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
Alias /static /home/ubuntu/git_code/my_proj/static
<Directory /home/ubuntu/git_code/my_proj/static>
Require all granted
</Directory>
WSGIDaemonProcess my_proj python-path=/home/ubuntu/git_code/my_proj:/usr/local/lib/python3.4/dist-packages
WSGIProcessGroup my_proj
</VirtualHost>
套用 site 設定
sudo a2ensite my_proj.conf
sudo service apache2 reload
重啟 apache
sudo service apache2 restart
amazon web services 修改主機名稱
在 AWS 申請主機登入後,
bash 的提示符號很醜,ex:
ubuntu@ip-123-456-789-012:~
只要修改 hostname 就可以改為較順眼的顯示方式
sudo hostname bennu.com
重新登入後就變成
ubuntu@bennu.com:~
而如果需要更客製化的提示符
就要去修改 ~/.bashrc 的 PS1 變數了
bash 的提示符號很醜,ex:
ubuntu@ip-123-456-789-012:~
只要修改 hostname 就可以改為較順眼的顯示方式
sudo hostname bennu.com
重新登入後就變成
ubuntu@bennu.com:~
而如果需要更客製化的提示符
就要去修改 ~/.bashrc 的 PS1 變數了
2016年6月4日 星期六
用戶密碼加解密概念-client版
client........................network..................................server
step1
................................................................................create
input rawpwd
salt(fixed) + rawpwd ==sha256==> encode1
salt_encode1... .....................https.........................save salt_encode1 to database
step2
.............................................................................. validate
input rawpwd
salt + rawpwd ==sha256==> encode2
salt_encode2... .... .....................https....................load salt_encode1 from database
...............................................................................test if encode2 equals to encode1
step1
................................................................................create
input rawpwd
salt(fixed) + rawpwd ==sha256==> encode1
salt_encode1... .....................https.........................save salt_encode1 to database
step2
.............................................................................. validate
input rawpwd
salt + rawpwd ==sha256==> encode2
salt_encode2... .... .....................https....................load salt_encode1 from database
...............................................................................test if encode2 equals to encode1
用戶密碼加解密概念-server版
client..........network............................server
step1
.........................................................create
rawpwd.................https...................salt(random) + rawpwd ==sha256==> encode1
.........................................................save salt_encode1 to database
step2
.........................................................validate
rawpwd.................https.. ................load salt from salt_encode1 in database
.........................................................salt + rawpwd ==sha256==> encode2
.........................................................test if encode2 equals to encode1
step1
.........................................................create
rawpwd.................https...................salt(random) + rawpwd ==sha256==> encode1
.........................................................save salt_encode1 to database
step2
.........................................................validate
rawpwd.................https.. ................load salt from salt_encode1 in database
.........................................................salt + rawpwd ==sha256==> encode2
.........................................................test if encode2 equals to encode1
2016年5月23日 星期一
[Django] 設定 Django 使用 MySQL 做為資料庫
首先是版本
MySQL 我使用目前最新 社群版(免費版) 5.6.28
安裝時 附帶一起安裝 mysql-connector-python 2.1.3 模組
這是MySQL官方自己出的 connector 但與 Django 最新版 (1.9.x) 不完全相容
因此,我們必須捨棄最新版本的 Django,pip 安裝時加上:
python3 -m pip install "Django<1.9"
這樣就可以安裝 1.8.x 的最新版本 ,需注意後面的 "Django<1.9" 雙引號不可省略,
完成安裝後,在 Django 的 project 目錄下的 setting.py,資料庫設定的部分:
完成後,執行 Django migrate 命令:
python3 manage.py migrate
若成功就會把 Django 的資料庫移轉到 MySQL 下了。
MySQL 我使用目前最新 社群版(免費版) 5.6.28
安裝時 附帶一起安裝 mysql-connector-python 2.1.3 模組
這是MySQL官方自己出的 connector 但與 Django 最新版 (1.9.x) 不完全相容
因此,我們必須捨棄最新版本的 Django,pip 安裝時加上:
python3 -m pip install "Django<1.9"
這樣就可以安裝 1.8.x 的最新版本 ,需注意後面的 "Django<1.9" 雙引號不可省略,
完成安裝後,在 Django 的 project 目錄下的 setting.py,資料庫設定的部分:
DATABASES = {ENGINE 的部分是設定使用 MySQL 官方的 connector
'default': {
'ENGINE': 'mysql.connector.django',
'NAME': 'datebase_name',
'USER': 'datebase_user_name',
'PASSWORD': 'datebase_user_password',
'HOST': '127.0.0.1',
'PORT': '3306',
'OPTIONS': {
'autocommit': True,
},
}
}
完成後,執行 Django migrate 命令:
python3 manage.py migrate
若成功就會把 Django 的資料庫移轉到 MySQL 下了。
[python] regex 群組命名表示法
原本我只會
結果為 "123"
學了一下 Django 意外學到
為群組命名,程式碼可以更容易懂,還不錯。
text = "123 is num"
re.match("^(\d+) is num$", text).group(1)
結果為 "123"
學了一下 Django 意外學到
text = "123 is num"可以透過 ?P<variable_name>
re.match("^(?P<num>\d+) is num$", text).group("num")
2016年5月18日 星期三
[python] OAuth 取得 facebook 使用者的 id name email
1. 到 facebook developers頁面 建立一個 WWW APP ,可以得到一組 client id / client secret
href="https://www.facebook.com/dialog/oauth?
下方填入自己的 WebService 網址。ex:
2.在系統的登入頁加入一個超連結,填入 上一步的 client id ,要向使用者索取的資源 scope, 以及使用者同意授權後,facebook 要將授權碼 redirect 的位址,我們填入自己的 WebService 位址。
href="https://www.facebook.com/dialog/oauth?
&client_id=1730077280596052
&scope=public_profile,email
&redirect_uri=http://bennu-aws.ddns.net:5000/fb_oauth"
3. 設計一個 WebService 接收 授權碼 code,使用 python Flask 框架。
@app.route("/fb_oauth", methods=["GET"])
def fbOauth():
#接收授權碼
strAuthCode = request.args.get("code", None, type=str)
4.將授權碼回傳給 facebook 換取 token,需要 client_id、client_secret、第3步得到的授權碼、以及第2步使用的 redircet_uri,facebook 就會回傳 token 回來
strAccessTokenUrlTemplate = "https://graph.facebook.com/oauth/access_token?
&client_id=%s
&redirect_uri=%s
&client_secret=%s
&code=%s"
strAccessTokenUrl = strAccessTokenUrlTemplate%
(strFbClientId,
"http://bennu-aws.ddns.net:5000/fb_oauth",
strFbClientSecret,
strAuthCode)
responseToken = urllib.request.urlopen(strAccessTokenUrl)
strToken = responseToken.read().decode(responseToken.headers.get_content_charset())
5.使用 token 取得使用者的資料
responseUserData = urllib.request.urlopen("https://graph.facebook.com/me?
&fields=id,name,email
&" + strToken)
strUserData = responseUserData.read().decode(responseToken.headers.get_content_charset())
dicUserData = json.loads(strUserData)
return (dicUserData["id"], dicUserData["name"], dicUserData["email"])
3. 設計一個 WebService 接收 授權碼 code,使用 python Flask 框架。
@app.route("/fb_oauth", methods=["GET"])
def fbOauth():
#接收授權碼
strAuthCode = request.args.get("code", None, type=str)
4.將授權碼回傳給 facebook 換取 token,需要 client_id、client_secret、第3步得到的授權碼、以及第2步使用的 redircet_uri,facebook 就會回傳 token 回來
strAccessTokenUrlTemplate = "https://graph.facebook.com/oauth/access_token?
&client_id=%s
&redirect_uri=%s
&client_secret=%s
&code=%s"
strAccessTokenUrl = strAccessTokenUrlTemplate%
(strFbClientId,
"http://bennu-aws.ddns.net:5000/fb_oauth",
strFbClientSecret,
strAuthCode)
responseToken = urllib.request.urlopen(strAccessTokenUrl)
strToken = responseToken.read().decode(responseToken.headers.get_content_charset())
5.使用 token 取得使用者的資料
responseUserData = urllib.request.urlopen("https://graph.facebook.com/me?
&fields=id,name,email
&" + strToken)
strUserData = responseUserData.read().decode(responseToken.headers.get_content_charset())
dicUserData = json.loads(strUserData)
return (dicUserData["id"], dicUserData["name"], dicUserData["email"])
2016年5月15日 星期日
[python] unicode decode encode 的秘密
python 2.7
u"abc中文" == unicode 物件
"abc中文" == str 物件
python 3.x
u"abc中文" == unicode 物件
"abc中文" == unicode 物件
所以大多數問題出現在 python 2.7
以下使用 2.7 的觀點來看:
encode == 把 unicode 物件轉為 str 物件
strUTF8 = u"abc中文".encode("utf-8") == str 物件
strBIG5 = u"abc中文".encode("big5") == str 物件
strCP950 = u"abc中文".encode("cp950") == str 物件
decode == 把 str 物件轉為 unicode 物件
strUTF8 .decode("utf-8") == unicode 物件
strBIG5.decode("big5") == unicode 物件
strCP950.decode("cp950") == unicode 物件
秘密:
如果 str 物件 執行 encode 相當於 "先 decode 為 unicode 再 encode", ex:
u"abc中文" == unicode 物件
"abc中文" == str 物件
python 3.x
u"abc中文" == unicode 物件
"abc中文" == unicode 物件
所以大多數問題出現在 python 2.7
以下使用 2.7 的觀點來看:
encode == 把 unicode 物件轉為 str 物件
strUTF8 = u"abc中文".encode("utf-8") == str 物件
strBIG5 = u"abc中文".encode("big5") == str 物件
strCP950 = u"abc中文".encode("cp950") == str 物件
decode == 把 str 物件轉為 unicode 物件
strUTF8 .decode("utf-8") == unicode 物件
strBIG5.decode("big5") == unicode 物件
strCP950.decode("cp950") == unicode 物件
秘密:
如果 str 物件 執行 encode 相當於 "先 decode 為 unicode 再 encode", ex:
strBIG5.encode("cp950") == strBIG5.decode("ascii").encode("cp950")
重點在於 decode 過程會使用 python 的預設系統編碼 ascii 而不是使用 big5
造成 明明是呼叫 encode 卻報錯 "無法使用 ascii 進行 decode " 之類的奇怪結果
[python] 使用 pkg_resources 模組存取 package 裡面的檔案
import pkg_resources
strPkgFilePath = pkg_resources.resource_filename("package_name", "resource_file")
當資源存放在 package (含有 __init__.py 的資料夾)裡面時,
一但經過封裝上傳 pip install 之後,檔案路徑會與 os.path 取得的路徑不同,
os.path 是根據 "當前執行的目錄 (cwd)" 去做尋找,也就是說:
在 c:\ 下執行 會尋找 c:\package_name\resource_file
在 c:\dir\ 下執行會尋找 c:\dir\package_name\resource_file
不可能因為執行的 cwd 不同而到處搬移 resource_file
於是會將 resource_file 存放在 package 下,pip install 後
resourc_file 會固定放在 C:\Python34\Lib\site-packages\package_name\resource_file
而要取得該位置,只要使用 pkg_resources.resource_filename 即可。
2016年5月14日 星期六
python 設定 setup.py 及 MANIFEST.in 封裝整個專案 並上傳至 pypi 的設定
setup.py
from setuptools import setup,find_packages
with open("README.txt") as file:
long_description = file.read()
setup(
name = "bennu",
version = "0.3.2.dev2",
keywords = ["bennu", "utility", "muchu"],
description = "muchu's utility module",
author = "MuChu Hsu",
author_email = "muchu1983@gmail.com",
license = "BSD 3-Clause License",
url="https://github.com/muchu1983/bennu",
long_description=long_description,
packages = find_packages(),
include_package_data = True,
install_requires = ["Pillow>=3.0.0"],
platforms = "python 3.3",
entry_points = {"console_scripts":["bennu=bennu.launcher:entry_point"]},
classifiers = [
"Programming Language :: Python :: 3.3",
],
)
重點:
name 之後使用 pip install 要用到的名稱
version 每次上傳不得重覆,否則上傳會失敗,數字越大版本越新。
find_packages() 可以自動找出含有 __init__.py 的資料夾,省去一一指定。
install_requires 指定本專案相依的其他 pypi 專案,用 pip 安裝時也會被加入安裝。
entry_points 指定 專案的執行進入點 並建立 可執行檔 ["execuatable_name=package.package:function"]
MANIFEST.in
include LICENSE
recursive-include bennu_res *
recursive-exclude test *
搭配 MANIFEST.in 可以指定其他檔案是否要一起加入封裝
上傳
1. 登入,首次會問你 pypi 上的帳密,之後可以記錄
python setup.py register
2. 包裝,將你的專案包裝成 zip (windows) 或 tar.gz (linux)
python setup.py sdist
3. 上傳至 pypi
python setup.py upload
成功的話,要先移除專案資料夾內生成的 dist/ 還有 .egg-info/
否則 pip 會以為你已經有最新版本了,若是其他電腦就沒差
之後就可以用
pip install name
來安裝專案
安裝後也可以直接執行 executable_name 來執行
ubuntu 下使用 headless browser PhantomJS
PhantomJS 是一個 無畫面 的 browser
非常適合用來與 selenium 配合進行 自動化測試或是爬蟲程式
例如:
#取得 selenium driver 物件
def getDriver(self):
driver = None
if os.name == "nt":
#chromeDriverExeFilePath = os.sep.join(("bennu_res", "chromedriver.exe"))
#driver = webdriver.Chrome(chromeDriverExeFilePath)
phantomjsDriverExeFilePath = os.sep.join(("bennu_res", "phantomjs.exe"))
driver = webdriver.PhantomJS(phantomjsDriverExeFilePath)
if os.name == "posix":
phantomjsDriverExeFilePath = os.sep.join(("bennu_res", "phantomjs"))
driver = webdriver.PhantomJS(phantomjsDriverExeFilePath)
return driver
selenium 用法 本篇暫不介紹
PhantomJS 下載之後只有一個執行檔,將他放在 selenium 可以讀取到的位置即可使用
在 ubuntu 環境下,有幾點要注意的是:
1. 必須 chmod 755 phantomjs 加入執行權限
2. 必須安裝 apt-get install fontconfig 套件
非常適合用來與 selenium 配合進行 自動化測試或是爬蟲程式
例如:
#取得 selenium driver 物件
def getDriver(self):
driver = None
if os.name == "nt":
#chromeDriverExeFilePath = os.sep.join(("bennu_res", "chromedriver.exe"))
#driver = webdriver.Chrome(chromeDriverExeFilePath)
phantomjsDriverExeFilePath = os.sep.join(("bennu_res", "phantomjs.exe"))
driver = webdriver.PhantomJS(phantomjsDriverExeFilePath)
if os.name == "posix":
phantomjsDriverExeFilePath = os.sep.join(("bennu_res", "phantomjs"))
driver = webdriver.PhantomJS(phantomjsDriverExeFilePath)
return driver
selenium 用法 本篇暫不介紹
PhantomJS 下載之後只有一個執行檔,將他放在 selenium 可以讀取到的位置即可使用
在 ubuntu 環境下,有幾點要注意的是:
1. 必須 chmod 755 phantomjs 加入執行權限
2. 必須安裝 apt-get install fontconfig 套件
2016年5月11日 星期三
windows 下安裝 python scrapy 模組
目前 scrapy 僅支援 2.7 版本 python
安裝前準備:
0. 升級 pip
python2 -m pip install pip --upgrade
1. Visual C++ compiler for python 2.7
https://www.microsoft.com/en-us/download/details.aspx?id=44266
2. lxml 用 exe 安裝 (用 pip 直接裝有點問題)
https://pypi.python.org/pypi/lxml/3.6.0
3. pypiwin32 (用 pip 直接裝就可以了)
python2 -m pip install pypiwin32
準備完成:
python2 -m pip install scrapy
安裝前準備:
0. 升級 pip
python2 -m pip install pip --upgrade
1. Visual C++ compiler for python 2.7
https://www.microsoft.com/en-us/download/details.aspx?id=44266
2. lxml 用 exe 安裝 (用 pip 直接裝有點問題)
https://pypi.python.org/pypi/lxml/3.6.0
3. pypiwin32 (用 pip 直接裝就可以了)
python2 -m pip install pypiwin32
準備完成:
python2 -m pip install scrapy
python 使用 global 時機
當 local 區域 要 assign 資料給 外部區域 的變數時,
就必須先在 local 區域 使用 global 宣告一個相同名稱的 區域變數:
g = 1
def func():
g = 1
def func():
就必須先在 local 區域 使用 global 宣告一個相同名稱的 區域變數:
g = 1
def func():
global g
g = 2若是單純取值,沒有 assign 的動作,則可以不宣告:
g = 1
def func():
print(g)完
ssh key 備忘
ssh key 分為 公錀 與 私錀,成雙成對。
擁有私錀可以產生對應的公錀,但擁有公錀無法反推產生私錀。
公錀放在 server
私錀放在 client
linux 上 ssh-keygen 產生的 公錀 檔名為 id_rsa.pub
linux 上 ssh-keygen 產生的 私錀 檔名為 id_rsa
windows server 不支援 ssh 認証,故 公錀 一般只有 linux 格式
windows 由 puttygen 可將 id_rsa 轉為可在 windows 下 putty 使用的 .ppk 檔
也就是說 .ppk 檔 等於 windows 下使用的 私錀,與原本的 id_rsa 格式有些不同,
但功能相同,若要將 .ppk 檔 轉回 linux 下使用的 id_rsa
sudo apt-get install putty-tools
puttygen key.ppk -O private-openssh -o id_rsa
linux 公錀存放位置 ~/.ssh/authorized_keys (可同時放多組公錀)
linux 私錀存放位置 ~/.ssh/id_rsa
存取權限必須設定為
chmod 700 ~/.ssh
chmod 777 ~/.ssh/authorized_keys (可公開)
chmod 600 ~/.ssh/id_rsa (不可公開)
原因是....文章一開頭有說了:擁有.....吧拉吧拉吧拉。
擁有私錀可以產生對應的公錀,但擁有公錀無法反推產生私錀。
公錀放在 server
私錀放在 client
linux 上 ssh-keygen 產生的 公錀 檔名為 id_rsa.pub
linux 上 ssh-keygen 產生的 私錀 檔名為 id_rsa
windows server 不支援 ssh 認証,故 公錀 一般只有 linux 格式
windows 由 puttygen 可將 id_rsa 轉為可在 windows 下 putty 使用的 .ppk 檔
也就是說 .ppk 檔 等於 windows 下使用的 私錀,與原本的 id_rsa 格式有些不同,
但功能相同,若要將 .ppk 檔 轉回 linux 下使用的 id_rsa
sudo apt-get install putty-tools
puttygen key.ppk -O private-openssh -o id_rsa
linux 公錀存放位置 ~/.ssh/authorized_keys (可同時放多組公錀)
linux 私錀存放位置 ~/.ssh/id_rsa
存取權限必須設定為
chmod 700 ~/.ssh
chmod 777 ~/.ssh/authorized_keys (可公開)
chmod 600 ~/.ssh/id_rsa (不可公開)
原因是....文章一開頭有說了:擁有.....吧拉吧拉吧拉。
2013年1月20日 星期日
高架橋下的相遇
寒冬的夜晚
沒有路燈的陸橋下
我又餓又累己經再也沒有力氣
我慢慢的躺下
只想好好的睡上一覺
才閉上眼睛沒多久
就聽到一個轟隆隆的聲音
聲音越來越近越來越近
吵得我無法乎視
不得不睜開眼坐起身來
是一個騎著打檔車的人類停在我的面前
到底是想幹麻阿
這麼晚了快回去你的家阿
人類催動油門在我身旁騎了一圈
我是犯著你了嗎
走開好嗎
突然 他衝向我
shit 我只好馬上起身往旁邊閃
是想撞我嗎
吃飽太閒阿
人類怎麼都這麼混帳
但我知道我無力對抗
只好慢慢走到路旁的草叢中
從草叢裡看著外面那個發神經的人類
不要再過來了拜託
還好
他真的沒過來了
轉動機車把手慢慢騎走了
這世界到底怎麼了
當一只流浪狗就一定要這樣被欺負嗎
閉上含著不干心而淚濕著雙眼
我沉沉的睡著了
老婆阿跟你說
今天我在回來的路上
看到一隻白痴的黑狗
大半夜的就直接躺在大馬路中間睡覺
還好我有去趕走他
不然阿牠今晚就昇天了吧
有些人對你不好
卻是為你好
沒有路燈的陸橋下
我又餓又累己經再也沒有力氣
我慢慢的躺下
只想好好的睡上一覺
才閉上眼睛沒多久
就聽到一個轟隆隆的聲音
聲音越來越近越來越近
吵得我無法乎視
不得不睜開眼坐起身來
是一個騎著打檔車的人類停在我的面前
到底是想幹麻阿
這麼晚了快回去你的家阿
人類催動油門在我身旁騎了一圈
我是犯著你了嗎
走開好嗎
突然 他衝向我
shit 我只好馬上起身往旁邊閃
是想撞我嗎
吃飽太閒阿
人類怎麼都這麼混帳
但我知道我無力對抗
只好慢慢走到路旁的草叢中
從草叢裡看著外面那個發神經的人類
不要再過來了拜託
還好
他真的沒過來了
轉動機車把手慢慢騎走了
這世界到底怎麼了
當一只流浪狗就一定要這樣被欺負嗎
閉上含著不干心而淚濕著雙眼
我沉沉的睡著了
老婆阿跟你說
今天我在回來的路上
看到一隻白痴的黑狗
大半夜的就直接躺在大馬路中間睡覺
還好我有去趕走他
不然阿牠今晚就昇天了吧
有些人對你不好
卻是為你好
2011年10月6日 星期四
debian 上的 android sdk 安裝BUG
這是 Debian-based 的 Linux 特有的 bug...
事情發生在安裝好 sun-java6-jdk, eclipse, ADT 之後,打開 Window -> Android SDK and AVD manager 時,Eclipse 的 Console 視窗會開始一直跳出下面這樣的訊息
[2010-03-04 23:04:42 - ddms]Failed to reopen debug port for Selected Client to: 8700
[2010-03-04 23:04:42 - ddms]不適用的引數
java.net.SocketException: 不適用的引數
at sun.nio.ch.Net.bind(Native Method)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:119)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:59)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:52)
at com.android.ddmlib.MonitorThread.reopenDebugSelectedPort(Unknown Source)
at com.android.ddmlib.MonitorThread.run(Unknown Source)
[2010-03-04 23:04:42 - DeviceMonitor]Connection attempts: 1
[2010-03-04 23:04:43 - DeviceMonitor]Connection attempts: 2
[2010-03-04 23:04:45 - DeviceMonitor]Connection attempts: 3
拜過谷歌大神後,得到解法如下
sudo sysctl -w net.ipv6.bindv6only=0
重開機後也要保持設定值,則修改 /etc/sysctl.d/bindv6only.conf 裡的的設定值為
net.ipv6.bindv6only = 0
事情發生在安裝好 sun-java6-jdk, eclipse, ADT 之後,打開 Window -> Android SDK and AVD manager 時,Eclipse 的 Console 視窗會開始一直跳出下面這樣的訊息
[2010-03-04 23:04:42 - ddms]Failed to reopen debug port for Selected Client to: 8700
[2010-03-04 23:04:42 - ddms]不適用的引數
java.net.SocketException: 不適用的引數
at sun.nio.ch.Net.bind(Native Method)
at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:119)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:59)
at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:52)
at com.android.ddmlib.MonitorThread.reopenDebugSelectedPort(Unknown Source)
at com.android.ddmlib.MonitorThread.run(Unknown Source)
[2010-03-04 23:04:42 - DeviceMonitor]Connection attempts: 1
[2010-03-04 23:04:43 - DeviceMonitor]Connection attempts: 2
[2010-03-04 23:04:45 - DeviceMonitor]Connection attempts: 3
拜過谷歌大神後,得到解法如下
sudo sysctl -w net.ipv6.bindv6only=0
重開機後也要保持設定值,則修改 /etc/sysctl.d/bindv6only.conf 裡的的設定值為
net.ipv6.bindv6only = 0
2011年3月14日 星期一
星海二-自由之翼遊戲界面缺字問題解法
To add nopat to grub, open a console and edit /etc/default/grub
> sudo nano /etc/default/grub
Change the line:
> GRUB_CMDLINE_LINUX=""
to
> GRUB_CMDLINE_LINUX="nopat"
Save and exit, then run:
> sudo update-grub
再重開機就好了,雖然level不到不知道為何會這樣。
> sudo nano /etc/default/grub
Change the line:
> GRUB_CMDLINE_LINUX=""
to
> GRUB_CMDLINE_LINUX="nopat"
Save and exit, then run:
> sudo update-grub
再重開機就好了,雖然level不到不知道為何會這樣。
2011年3月9日 星期三
youtube to mp3 線上轉換器
http://www.audiothief.com/zh-chs/Video
超方便...
把 youtube 影片網址貼上 按 converter
過20秒就會出現 mp3 連結給你下載了...
超方便...
把 youtube 影片網址貼上 按 converter
過20秒就會出現 mp3 連結給你下載了...
[轉貼] mencoder 和ffmpeg常用命令
mencoder 和ffmpeg常用命令
先从Mencoder这个开始,将所有格式转AVI,
RMVB转AVI
mencoder 1.rmvb -oac mp3lame -lameopts preset=64 -ovc xvid -xvidencopts bitrate=600 -of avi -o rmvb.avi
RM转AVI
mencoder 1.rm -oac mp3lame -lameopts preset=64 -ovc xvid -xvidencopts bitrate=600 -of avi -o rm.avi
MPEG转AVI
mencoder mp4.mpeg -oac mp3lame -lameopts preset=64 -ovc xvid -xvidencopts bitrate=600 -of avi -o mp4.avi
MOV转AVI
mencoder qtime.mov -oac mp3lame -lameopts preset=64 -ovc xvid -xvidencopts bitrate=600 -of avi -o qtime.avi
WMV转AVI 包括WMV7到WMV9,只实验到WMV9
mencoder m7.wmv -oac mp3lame -lameopts preset=64 -ovc xvid -xvidencopts bitrate=600 -of avi -o m7.avi
RV转AVI
mencoder 1.rv -oac mp3lame -lameopts preset=64 -ovc xvid -xvidencopts bitrate=600 -of avi -o rv.avi
等等……格式,参数不变,改文件名就好了。这里参数是什么意思,我目前还不懂,学习中,你可以在网上找找,找到告诉我啊,谢谢。
接下来是FFMPEG上场。
AVI转FLV
ffmpeg -i test.avi -ab 56 -ar 22050 -b 500 -r 15 -s 320x240 test.flv
抓图JPG。
ffmpeg -i 2.wmv -y -f image2 -ss 8 -t 0.001 -s 350x240 test.jpg
3GP转FLV
mencoder -vf scale=320:240 -ffourcc FLV1 -of lavf -lavfopts i_certify_that_my_video_stream_does_not_use_b_frames -ovc lavc -lavcopts vcodec=flv:vbitrate=200 -srate 22050 -oac lavc -lavcopts acodec=mp3:abitrate=56 ok\1.3gp -o ok\3gp.flv
MOV转FLV
mencoder -vf scale=320:240 -ffourcc FLV1 -of lavf -lavfopts i_certify_that_my_video_stream_does_not_use_b_frames -ovc lavc -lavcopts vcodec=flv:vbitrate=200 -srate 22050 -oac lavc -lavcopts acodec=mp3:abitrate=56 ok\qtime.mov -o ok\mov.flv
RMVB转FLV
mencoder -vf scale=320:240 -ffourcc FLV1 -of lavf -lavfopts i_certify_that_my_video_stream_does_not_use_b_frames -ovc lavc -lavcopts vcodec=flv:vbitrate=200 -srate 22050 -oac lavc -lavcopts acodec=mp3:abitrate=56 ok\1.rmvb -o ok\rmvb.flv
WMV转FLV
mencoder -vf scale=320:240 -ffourcc FLV1 -of lavf -lavfopts i_certify_that_my_video_stream_does_not_use_b_frames -ovc lavc -lavcopts vcodec=flv:vbitrate=200 -srate 22050 -oac lavc -lavcopts acodec=mp3:abitrate=56 ok\m9.wmv -o ok\m9.flv
等等等…………
以上的参数通用,只要在输入的ok\m9.wmv换成你自己相应的格式就好,绝对可以,这次测试完全OK,效果点这里,给大家看看,我近期的成果,已实现的。
先从Mencoder这个开始,将所有格式转AVI,
RMVB转AVI
mencoder 1.rmvb -oac mp3lame -lameopts preset=64 -ovc xvid -xvidencopts bitrate=600 -of avi -o rmvb.avi
RM转AVI
mencoder 1.rm -oac mp3lame -lameopts preset=64 -ovc xvid -xvidencopts bitrate=600 -of avi -o rm.avi
MPEG转AVI
mencoder mp4.mpeg -oac mp3lame -lameopts preset=64 -ovc xvid -xvidencopts bitrate=600 -of avi -o mp4.avi
MOV转AVI
mencoder qtime.mov -oac mp3lame -lameopts preset=64 -ovc xvid -xvidencopts bitrate=600 -of avi -o qtime.avi
WMV转AVI 包括WMV7到WMV9,只实验到WMV9
mencoder m7.wmv -oac mp3lame -lameopts preset=64 -ovc xvid -xvidencopts bitrate=600 -of avi -o m7.avi
RV转AVI
mencoder 1.rv -oac mp3lame -lameopts preset=64 -ovc xvid -xvidencopts bitrate=600 -of avi -o rv.avi
等等……格式,参数不变,改文件名就好了。这里参数是什么意思,我目前还不懂,学习中,你可以在网上找找,找到告诉我啊,谢谢。
接下来是FFMPEG上场。
AVI转FLV
ffmpeg -i test.avi -ab 56 -ar 22050 -b 500 -r 15 -s 320x240 test.flv
抓图JPG。
ffmpeg -i 2.wmv -y -f image2 -ss 8 -t 0.001 -s 350x240 test.jpg
3GP转FLV
mencoder -vf scale=320:240 -ffourcc FLV1 -of lavf -lavfopts i_certify_that_my_video_stream_does_not_use_b_frames -ovc lavc -lavcopts vcodec=flv:vbitrate=200 -srate 22050 -oac lavc -lavcopts acodec=mp3:abitrate=56 ok\1.3gp -o ok\3gp.flv
MOV转FLV
mencoder -vf scale=320:240 -ffourcc FLV1 -of lavf -lavfopts i_certify_that_my_video_stream_does_not_use_b_frames -ovc lavc -lavcopts vcodec=flv:vbitrate=200 -srate 22050 -oac lavc -lavcopts acodec=mp3:abitrate=56 ok\qtime.mov -o ok\mov.flv
RMVB转FLV
mencoder -vf scale=320:240 -ffourcc FLV1 -of lavf -lavfopts i_certify_that_my_video_stream_does_not_use_b_frames -ovc lavc -lavcopts vcodec=flv:vbitrate=200 -srate 22050 -oac lavc -lavcopts acodec=mp3:abitrate=56 ok\1.rmvb -o ok\rmvb.flv
WMV转FLV
mencoder -vf scale=320:240 -ffourcc FLV1 -of lavf -lavfopts i_certify_that_my_video_stream_does_not_use_b_frames -ovc lavc -lavcopts vcodec=flv:vbitrate=200 -srate 22050 -oac lavc -lavcopts acodec=mp3:abitrate=56 ok\m9.wmv -o ok\m9.flv
等等等…………
以上的参数通用,只要在输入的ok\m9.wmv换成你自己相应的格式就好,绝对可以,这次测试完全OK,效果点这里,给大家看看,我近期的成果,已实现的。
2010年8月11日 星期三
由 source 安裝特定版本 wine
需先安裝 git - 和svn類似的版本管理工具
#aptitude install git-core
取得wine原始碼
$git clone git://source.winehq.org/git/wine.git ~/git-workspace/wine
$cd ~/git-workspace/wine
切換到想要的 wine branch
$git checkout wine-1.2
編譯 wine
$./configure && make depend && make
安裝 wine
#make install
反安裝 wine
#make uninstall
#aptitude install git-core
取得wine原始碼
$git clone git://source.winehq.org/git/wine.git ~/git-workspace/wine
$cd ~/git-workspace/wine
切換到想要的 wine branch
$git checkout wine-1.2
編譯 wine
$./configure && make depend && make
安裝 wine
#make install
反安裝 wine
#make uninstall
wine 的方便擴充工具 winetricks
安裝好 wine 後,有時仍然不敷使用,如:directx9 , ie6 ...等等 lib 並不容易安裝與設定
只要下載 winetricks 這個工具就可以很容易的安裝各式 windows 工具軟體
下載頁與教學:
http://wiki.winehq.org/winetricks
範例: $sh winetricks d3dx9 ie6
只要下載 winetricks 這個工具就可以很容易的安裝各式 windows 工具軟體
下載頁與教學:
http://wiki.winehq.org/winetricks
範例: $sh winetricks d3dx9 ie6
2010年6月7日 星期一
dvd player gxine
在 debian 上用 mplayer 可以看大多數的影片檔了
可是遇到 dvd 光碟時 常常需要許多的設定
gxine 則比較方便 一安裝好就可以正常播放 dvd 光碟影片
無論是字幕或是選擇語言章節都很順利
可是遇到 dvd 光碟時 常常需要許多的設定
gxine 則比較方便 一安裝好就可以正常播放 dvd 光碟影片
無論是字幕或是選擇語言章節都很順利
2010年1月29日 星期五
maven 查詢點紀錄
Spring EBR:
http://www.springsource.com/repository/app/
maven repository:
http://mvnrepository.com/
maven browser:
http://www.mvnbrowser.com/index.html
http://www.springsource.com/repository/app/
maven repository:
http://mvnrepository.com/
maven browser:
http://www.mvnbrowser.com/index.html
java System.getProperty() 參數紀錄
java.version – Java Runtime Environment version
java.vendor – Java Runtime Environment vendor
java.vendor.url – Java vendor URL
java.home – Java installation directory
java.vm.specification.version – Java Virtual Machine specification version
java.vm.specification.vendor – Java Virtual Machine specification vendor
java.vm.specification.name – Java Virtual Machine specification name
java.vm.version – Java Virtual Machine implementation version
java.vm.vendor – Java Virtual Machine implementation vendor
java.vm.name – Java Virtual Machine implementation name
java.specification.version – Java Runtime Environment specification version
java.specification.vendor – Java Runtime Environment specification vendor
java.specification.name – Java Runtime Environment specification name
java.class.version - Java class format version number
java.class.path – Java class path
java.library.path – List of paths to search when loading libraries
java.io.tmpdir – Default temp file path
java.compiler – Name of JIT compiler to use
java.ext.dirs – Path of extension directory or directories
os.name – Operating system name
os.arch – Operating system architecture
os.version – Operating system version
file.separator – File separator ("/" on UNIX)
path.separator – Path separator (":" on UNIX)
line.separator – Line separator ("\n" on UNIX)
user.name – User's account name
user.home – User's home directory
user.dir – User's current working directory
java.vendor – Java Runtime Environment vendor
java.vendor.url – Java vendor URL
java.home – Java installation directory
java.vm.specification.version – Java Virtual Machine specification version
java.vm.specification.vendor – Java Virtual Machine specification vendor
java.vm.specification.name – Java Virtual Machine specification name
java.vm.version – Java Virtual Machine implementation version
java.vm.vendor – Java Virtual Machine implementation vendor
java.vm.name – Java Virtual Machine implementation name
java.specification.version – Java Runtime Environment specification version
java.specification.vendor – Java Runtime Environment specification vendor
java.specification.name – Java Runtime Environment specification name
java.class.version - Java class format version number
java.class.path – Java class path
java.library.path – List of paths to search when loading libraries
java.io.tmpdir – Default temp file path
java.compiler – Name of JIT compiler to use
java.ext.dirs – Path of extension directory or directories
os.name – Operating system name
os.arch – Operating system architecture
os.version – Operating system version
file.separator – File separator ("/" on UNIX)
path.separator – Path separator (":" on UNIX)
line.separator – Line separator ("\n" on UNIX)
user.name – User's account name
user.home – User's home directory
user.dir – User's current working directory
2010年1月15日 星期五
cx_freeze 將 python 程式轉換成 exe
安裝 cx_freeze 前需先安裝好 python
再根據安裝的 python 版本下載對應的 cx_freeze 安裝程式
下載網站
http://cx-freeze.sourceforge.net/
安裝完成後會在原本的 python 安裝目錄下的 Scripts 目錄出現 cxfreeze cxfreeze.bat 兩個檔案
將要轉換的 python 程式 及 圖示檔 copy 到 Scripts 目錄下,並開啟 dos command line , cd 到 Scripts 下
執行:
C:\Python26\Scripts\>cxfreeze --base-name=Win32GUI --icon=app.ico app.py
--base-name=Win32GUI 是用來使用在執行 gui 程式時不必顯示 console 視窗,和將 副檔名 改為 app.pyw 意思一樣。
--icon 就是用來指定 產生的執行檔 的 icon 圖檔。
完成後,會在 Scripts 下建立 dist 資料夾,並產生幾個檔案,當然也包含 app.exe
dist 下的所有檔案都要有才能執行 app.exe (正常執行)
再根據安裝的 python 版本下載對應的 cx_freeze 安裝程式
下載網站
http://cx-freeze.sourceforge.net/
安裝完成後會在原本的 python 安裝目錄下的 Scripts 目錄出現 cxfreeze cxfreeze.bat 兩個檔案
將要轉換的 python 程式 及 圖示檔 copy 到 Scripts 目錄下,並開啟 dos command line , cd 到 Scripts 下
執行:
C:\Python26\Scripts\>cxfreeze --base-name=Win32GUI --icon=app.ico app.py
--base-name=Win32GUI 是用來使用在執行 gui 程式時不必顯示 console 視窗,和將 副檔名 改為 app.pyw 意思一樣。
--icon 就是用來指定 產生的執行檔 的 icon 圖檔。
完成後,會在 Scripts 下建立 dist 資料夾,並產生幾個檔案,當然也包含 app.exe
dist 下的所有檔案都要有才能執行 app.exe (正常執行)
2009年12月31日 星期四
ivy 指定設定檔位置
ivy 是一個和 ant 配合得很好的 lib 管理工具,簡單安裝及設定後,只要在 ant 的 build.xml 裡加上一個 "resolve" target
target 裡使用 ivy 提供的 <ivy:retrieve> ant task 並配合 ivy.xml 條列出所需 lib 的組織、名稱、版本
就可以由 maven repository 取得專案所需的 lib
但是 ivy 初始預設的設定往往不足以應付專案所需,例如需要對 ivy 另加不同的 repository 站點等等…
這些特殊設定必需由 ivysettings.xml 設定檔來完成,在預設的情型下,只要在 build.xml 同目錄下
加入檔名為 ivysettings.xml 的設定檔,ivy 就會使用這個設定檔覆蓋掉 ivy.jar 裡預設提供的 ivysettings.xml
但如果要將 ivysettings.xml 改名或移到別的目錄,就必須增加 <ivy:settings> task 如以下列範例:
<!-- resolve -->
<target name="resolve">
<ivy:settings id="my-ivysettings" file="ivy/myivysettings.xml" />
<ivy:retrieve settingsref="my-ivysettings" />
</target>
target 裡使用 ivy 提供的 <ivy:retrieve> ant task 並配合 ivy.xml 條列出所需 lib 的組織、名稱、版本
就可以由 maven repository 取得專案所需的 lib
但是 ivy 初始預設的設定往往不足以應付專案所需,例如需要對 ivy 另加不同的 repository 站點等等…
這些特殊設定必需由 ivysettings.xml 設定檔來完成,在預設的情型下,只要在 build.xml 同目錄下
加入檔名為 ivysettings.xml 的設定檔,ivy 就會使用這個設定檔覆蓋掉 ivy.jar 裡預設提供的 ivysettings.xml
但如果要將 ivysettings.xml 改名或移到別的目錄,就必須增加 <ivy:settings> task 如以下列範例:
<!-- resolve -->
<target name="resolve">
<ivy:settings id="my-ivysettings" file="ivy/myivysettings.xml" />
<ivy:retrieve settingsref="my-ivysettings" />
</target>
2009年12月29日 星期二
透過 ant 和 vbscript 合作建立 windows 捷徑檔
先以 vbscript 寫一段建立捷徑的程式
// 讀取參數
Set args = WScript.Arguments
installedFolder = args.Item(0)
// 取得 windows shell 物件
Set objShell = WScript.CreateObject("WScript.Shell")
// 取得 windows fs 物件
Set objFso = WScript.CreateObject("Scripting.FileSystemObject")
// 桌面路徑
strDesktopFolder = objShell.SpecialFolders("Desktop")
// 程式集路徑
strProgramsFolder = objShell.SpecialFolders("Programs")
// 建立資料夾(程式集裡)
objFso.CreateFolder(strProgramsFolder & "\app provider")
// 建立捷徑物件
Set objDesktopShortCut = objShell.CreateShortcut(strDesktopFolder & "\feeler.lnk")
// 設定目標
objDesktopShortCut.TargetPath = chr(34) & installedFolder & "\app.exe" & chr(34)
// 設定圖示
objDesktopShortCut.IconLocation = installedFolder & "\resources\images\app.ico, 0"
// 設定執行工作目錄
objDesktopShortCut.WorkingDirectory = installedFolder & "\"
// 儲存桌面捷徑
objDesktopShortCut.Save
// 依同法再建立程式集捷徑
...
完成 vbscript 後以 ant 的 exec task 執行 (vbscript 程式可透過 cscript 命令執行)
<target name="config">
<exec dir="${install.path.dir}" executable="cscript" os="Windows XP" output="shortcut.log">
<arg value="resources/shortcut.vbs" />
<arg value="${install.path.dir}" />
</exec>
</target>
// 讀取參數
Set args = WScript.Arguments
installedFolder = args.Item(0)
// 取得 windows shell 物件
Set objShell = WScript.CreateObject("WScript.Shell")
// 取得 windows fs 物件
Set objFso = WScript.CreateObject("Scripting.FileSystemObject")
// 桌面路徑
strDesktopFolder = objShell.SpecialFolders("Desktop")
// 程式集路徑
strProgramsFolder = objShell.SpecialFolders("Programs")
// 建立資料夾(程式集裡)
objFso.CreateFolder(strProgramsFolder & "\app provider")
// 建立捷徑物件
Set objDesktopShortCut = objShell.CreateShortcut(strDesktopFolder & "\feeler.lnk")
// 設定目標
objDesktopShortCut.TargetPath = chr(34) & installedFolder & "\app.exe" & chr(34)
// 設定圖示
objDesktopShortCut.IconLocation = installedFolder & "\resources\images\app.ico, 0"
// 設定執行工作目錄
objDesktopShortCut.WorkingDirectory = installedFolder & "\"
// 儲存桌面捷徑
objDesktopShortCut.Save
// 依同法再建立程式集捷徑
...
完成 vbscript 後以 ant 的 exec task 執行 (vbscript 程式可透過 cscript 命令執行)
<target name="config">
<exec dir="${install.path.dir}" executable="cscript" os="Windows XP" output="shortcut.log">
<arg value="resources/shortcut.vbs" />
<arg value="${install.path.dir}" />
</exec>
</target>
2009年12月28日 星期一
pythonw.exe
Windows 版本的 python 安裝後除了有 python.exe 直譯器之外,還有多一個 pythonw.exe
一般的 python 主程式如果副檔名為 *.py 則會預設以 python.exe 執行,執行時會先彈出一個 dos command line
以方便進行 輸入/輸出 ,但是一般的 GUI 程式是不需要用 command line 做 輸入/輸出 的,這樣一來
這一個 dos command line 就顯得多餘了,可以簡單的透過將 python 主程式的 副檔名 改為 *.pyw
這樣執行時 就會以 pythonw.exe 來執行 python 程式 ,也就不會彈出 dos command line
一般的 python 主程式如果副檔名為 *.py 則會預設以 python.exe 執行,執行時會先彈出一個 dos command line
以方便進行 輸入/輸出 ,但是一般的 GUI 程式是不需要用 command line 做 輸入/輸出 的,這樣一來
這一個 dos command line 就顯得多餘了,可以簡單的透過將 python 主程式的 副檔名 改為 *.pyw
這樣執行時 就會以 pythonw.exe 來執行 python 程式 ,也就不會彈出 dos command line
2009年12月22日 星期二
lenny + apache2 + mod_jk + tomcat55 設置
先安裝好需要的套件:
sudo aptitude install apache2 libapache2-mod-jk tomcat5.5 tomcat5.5-admin tomcat5.5-webapps
設定 tomcat:
sudo vim /etc/default/tomcat5.5
JAVA_HOME=/usr/lib/jvm/java-6-sun
TOMCAT5_SECURITY=no
若 TOMCAT5_SECURITY=yes
則會啟用 java 的 security manager 並以 /etc/tomcat5.5/catalina.policy 下的規則為依據
避免複雜設定先設定為 no 待有安全問題再進行詳細設定
tomcat webapps 位於 /var/lib/tomcat5.5/webapps/ 將 war 檔放到此目錄下過一會會自動解壓縮
先連線到 http://localhost:8180/webapp/ 看看是否可以正常連線
設定 apache jk module
在 /etc/apache2/mod-available/ 目錄下建立 jk.conf 檔案 內容如下:
JkWorkersFile /etc/apache2/workers.properties
JkLogFile /var/log/apache2/mod_jk.log
JkLogLevel info
JkMount /webapp/* worker1
這檔案是設定 jk 以 /etc/apache2/workers.properties 的設定建立 worker (可以多個)
接著建立 /etc/apache2/workers.properties 內容如下:
# Defining a worker named worker1 and of type ajp13
worker.list=worker1
# Set properties for worker1
worker.worker1.type=ajp13
worker.worker1.host=localhost
worker.worker1.port=8009
這檔案是建立一個 名稱為 worker1 且 type為 ajp13 的 worker
完成之後就可以 enable jk module
sudo a2enmod jk
完成後可以到 /etc/apache2/mod-enable/ 檢查看看有沒有兩個連結
$ ls -la | grep jk
lrwxrwxrwx 1 root root 25 2009-12-22 16:41 jk.conf -> ../mods-available/jk.conf
lrwxrwxrwx 1 root root 25 2009-12-22 16:41 jk.load -> ../mods-available/jk.load
接著要設定 /etc/apache2/sites-available/default 檔案
vim /etc/apache2/sites-available/default
加入:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/
JkMount /webapp/* worker1
…
</VirtualHost>
最後再重新啟動 apache
sudo /etc/init.d/apache2 restart
這次改以 80 port 連接 webapp
http://localhost/webapp/
順利的話就可以看到和用 8180 port 連接的相同結果
sudo aptitude install apache2 libapache2-mod-jk tomcat5.5 tomcat5.5-admin tomcat5.5-webapps
設定 tomcat:
sudo vim /etc/default/tomcat5.5
JAVA_HOME=/usr/lib/jvm/java-6-sun
TOMCAT5_SECURITY=no
若 TOMCAT5_SECURITY=yes
則會啟用 java 的 security manager 並以 /etc/tomcat5.5/catalina.policy 下的規則為依據
避免複雜設定先設定為 no 待有安全問題再進行詳細設定
tomcat webapps 位於 /var/lib/tomcat5.5/webapps/ 將 war 檔放到此目錄下過一會會自動解壓縮
先連線到 http://localhost:8180/webapp/ 看看是否可以正常連線
設定 apache jk module
在 /etc/apache2/mod-available/ 目錄下建立 jk.conf 檔案 內容如下:
JkWorkersFile /etc/apache2/workers.properties
JkLogFile /var/log/apache2/mod_jk.log
JkLogLevel info
JkMount /webapp/* worker1
這檔案是設定 jk 以 /etc/apache2/workers.properties 的設定建立 worker (可以多個)
接著建立 /etc/apache2/workers.properties 內容如下:
# Defining a worker named worker1 and of type ajp13
worker.list=worker1
# Set properties for worker1
worker.worker1.type=ajp13
worker.worker1.host=localhost
worker.worker1.port=8009
這檔案是建立一個 名稱為 worker1 且 type為 ajp13 的 worker
完成之後就可以 enable jk module
sudo a2enmod jk
完成後可以到 /etc/apache2/mod-enable/ 檢查看看有沒有兩個連結
$ ls -la | grep jk
lrwxrwxrwx 1 root root 25 2009-12-22 16:41 jk.conf -> ../mods-available/jk.conf
lrwxrwxrwx 1 root root 25 2009-12-22 16:41 jk.load -> ../mods-available/jk.load
接著要設定 /etc/apache2/sites-available/default 檔案
vim /etc/apache2/sites-available/default
加入:
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/
JkMount /webapp/* worker1
…
</VirtualHost>
最後再重新啟動 apache
sudo /etc/init.d/apache2 restart
這次改以 80 port 連接 webapp
http://localhost/webapp/
順利的話就可以看到和用 8180 port 連接的相同結果
swing Window 元件置頂
無論是 JFrame、JDialog 均可使用下列 method 將 window 置於最上層,
即使切換視窗也不會被 focus 的視窗所蓋到。
public final void setAlwaysOnTop(boolean alwaysOnTop)
2009年12月20日 星期日
debian 下格式化隨身碟為 vfat
必須使用 mkfs.vfat 來進行格式化
而 mkfs.vfat 預設沒有安裝,查詢他所存在的 deb 套件位置
$ apt-file search mkfs.vfat
dosfstools: sbin/mkfs.vfat
可以發現存在於 dosfstools 下
先安裝 dosfstools 再格式化隨身碟為 vfat:
sudo aptitude install dosfstools
sudo mkfs.vfat /dev/sdb1
而 mkfs.vfat 預設沒有安裝,查詢他所存在的 deb 套件位置
$ apt-file search mkfs.vfat
dosfstools: sbin/mkfs.vfat
可以發現存在於 dosfstools 下
先安裝 dosfstools 再格式化隨身碟為 vfat:
sudo aptitude install dosfstools
sudo mkfs.vfat /dev/sdb1
2009年12月18日 星期五
自定以圖片為背景的 JPanel
繼承 JPanel 並 override paintComponent(Graphics gc) 就可以了:
public class ImageBackgroundJPanel extends JPanel {
private Image backgroundImg = null;
public ImageBackgroundJPanel(String imagePath) {
backgroundImg = new ImageIcon(imagePath).getImage();
}
@Override
protected void paintComponent(Graphics gc) {
gc.drawImage(backgroundImg, 0, 0, this);
}
}
使用 jgoodies 的 look and feel
jgoodies 有許多產品,下載最新版的 jgoodies libraries looks 就可以了,
目前使用 2.2.2 版,將 looks-2.2.2.jar 加到 classpath 下
在執行到 swing 的任何程式之前,先加入以下 code 設定 L&F (look and feel)
// 設定銀色主題,有多種可用,必須在設定 L&F 前設定
// com.jgoodies.looks.plastic.theme - 主題的 package
PlasticLookAndFeel.setPlasticTheme(new Silver());
// 設定 look and feel ,在 linux 下使用 Plastic 系列比較沒問題,三種可用
//com.jgoodies.looks.plastic.PlasticLookAndFeel//com.jgoodies.looks.plastic.Plastic3DLookAndFeel
//com.jgoodies.looks.plastic.PlasticXPLookAndFeel
UIManager.setLookAndFeel(new PlasticXPLookAndFeel());
python 取得 os 的 path 分隔符號
使用 os moudle 取得有關 os 的資訊
import os
javaLibraryPath = "." + os.pathsep + "bundle" + os.pathsep + "lib"
windows 下 javaLibraryPath = .;bundle;lib
linux 下 javaLibraryPath = .:bundle:lib
help(os) 片斷說明如下
- all functions from posix, nt, os2, mac, or ce, e.g. unlink, stat, etc.
- os.path is one of the modules posixpath, ntpath, or macpath
- os.name is 'posix', 'nt', 'os2', 'mac', 'ce' or 'riscos'
- os.curdir is a string representing the current directory ('.' or ':')
- os.pardir is a string representing the parent directory ('..' or '::')
- os.sep is the (or a most common) pathname separator ('/' or ':' or '\\')
- os.extsep is the extension separator ('.' or '/')
- os.altsep is the alternate pathname separator (None or '/')
- os.pathsep is the component separator used in $PATH etc
- os.linesep is the line separator in text files ('\r' or '\n' or '\r\n')
- os.defpath is the default search path for executables
- os.devnull is the file path of the null device ('/dev/null', etc.)
2009年12月12日 星期六
2009年12月10日 星期四
JXTA p2p 協定介紹之資料傳送
啟動 JXTA 網路後可以得到一個 net peer group 實例
而 net peer group 提供了許多 service ,透過其中的 discover service 及 pipe service
即可讓 peer 互相傳遞訊息。
// 取得 discovery service
discoveryService = infrastructurePeerGroup.getDiscoveryService();
// 取得 pipe service
pipeService = infrastructurePeerGroup.getPipeService();
第一個要了解的概念是 PipeAdvertisement ,Pipe 是 JXTA 用來進行 peer 與 peer 溝通
的通道,可以想像成 Socket ,實作上底層應該也是脫離不了 Socket,而傳輸
也是透過 InputStream 與 OutputStream 進行資料傳送。
而 Advertisement 是 JXTA 用來表示資源的定義文件,是一個規範好的 xml 文件
JXTA 為網路中的各式各樣的資源都有定義屬於他的 Advertisement 。
以 PipeAdvertisement 來說,就是用來表示某一個 Pipe 的 Ad 文件。
因此,在資訊傳送前,需先由接收端的 peer 建立一個 PipeAdvertisement ,並且,
綁定一個 InputPipe 到 PipeAdvertisement 上,再由 discovery service 發佈到 JXTA
網路上,而發送端的 peer 再由 discovery service 查詢到 PipeAdvertisement,並綁定
OutputPipe 到同一個 PipeAdvertisement 上,等到綁定完成後,即可開始傳送資料。
建立 PipeAdvertisement
PipeAdvertisement pipeAd = (PipeAdvertisement)
AdvertisementFactory.newAdvertisement(PipeAdvertisement.getAdvertisementType());
pipeAd.setPipeID(IDFactory.newPipeID(PeerGroupID.defaultNetPeerGroupID));
pipeAd.setType(PipeService.UnicastType);
pipeAd.setName("APIPENAME");
建立 InputPipe bind 到 pipe ad 並設定 listener
pipeService.createInputPipe(pipeAd, pipeMsgListener);
listener 是一個 PipeMsgListener 的介面的實例,當完成對方建立了 OutputPipe 並
開始傳送資料時,PipeMsgListener 的 方法:
public void pipeMsgEvent(PipeMsgEvent event)
而傳進來的 event 物件會收到傳送過來的資料。
隨後即可將 pipeAd 發佈到 discover service 上,並設定 life time 及 expiration time
discoveryService.publish(pipeAd, pipeAdLifetime, pipeAdExpiration);
discoveryService.remotePublish(pipeAd, pipeAdExpiration);
而另一個要發送資料的 peer 則必須先以 discovery service 查詢前一個 peer
發佈的 pipeAd
discoveryService.getRemoteAdvertisements(
null, // 指定單一查詢的 peer id,null 則表示查詢整個網路
DiscoveryService.ADV, // 查詢的 type
"Name", // 指定查詢項目
"APIPENAME", // 查詢項目的值
1, // 一次要找多少個 ad
null); // 指定 discovery listener
這樣即會送出一個查詢到 JXTA 網路,最後一項參數的 listener 也可以使用
discoveryService.addDiscoveryListener(disclistener);
disclistener 是一個 DiscoveryListener 介面的實例,當查詢 ad 有結果後會觸發
listener 的 :
public void discoveryEvent(DiscoveryEvent event)
並可以 event 裡取得 ad 物件。因此發送端 peer 就可以得到 pipeAd 了
得到 pipeAd 後,發送端需要先建立一個 OutPipe 並綁定到 pipeAd 上
pipeService.createOutputPipe(pipeAd, outListener);
outListener 是一個 OutputPipeListener 當 OutPipe 綁定完成後,會觸發 listener 的
public void outputPipeEvent(OutputPipeEvent event)
並由 event 取得 OutputPipe 實例,開始傳送資料。
因此總結來說,傳送端在觸發 OutputPipeEvent 後可以開始傳送資料,
而接收端在觸發了 PipeMsgEvent 後可以開始接收資料,至於建立資料的方法則是,
建立一個 net.jxta.endpoint.Message 實例:
Message msg = new Message();
Message 是資料的包裝,裡面可以包含多筆 net.jxta.endpoint.MessageElement 實例
以最單純的 StringMessageElement 舉例:
StringMessageElement sme = new StringMessageElement(
"elemName", // element 的 key
"elemValue", // element 的 value
null // signature
);
將 element 加入到 Message 中,並以 OutPipe 傳送
msg.addMessageElement("msgNameSpace", sme);
event.getOutputPipe().send(msg);
而接收端則由 PipeMsgEvent 取得 Message,並由 namespace 和 element key 取值
Message msg = event.getMessage();
ElementIterator itMsg = msg.getMessageElements("msgNameSpace", "elemName");
while(itMsg.hasNext()){
MessageElement msgElem = itMsgElem.next();
System.out.println(msgElem.toString()); // 印出 "elemValue"
}
JXTA p2p 協定介紹之連線
JXTA 是 SUN 所提出的 p2p 標準協定,可使用各種語言完成,而由 java 完成的,

又可分為給 JavaSE 使用的 JXSE 及給 JavaME 使用的 JXME,也有其他語言的版本,
如: JXTA-C ,有空可以多加研究比較,而目前使用的版本為 JXSE,簡單介紹如下:
JXTA 是一個 p2p 的協定,規範了一個 p2p 網路上的所有 peer (節點) 的溝通標準,
有別於傳統的 client-server 架構,p2p 網路上有許多的新名詞,如:
peer、peer group、ad、RDV…等,在官方的說明文件中都有詳細說明,在此不多介紹,
JXTA 協定中定義了許多 peer 種類,以 EDGE 最常見,另外還有構成 JXTA 網路架構
的 RDV 節點,以及讓防火牆或 NAT 內的 EDGE 可以向外界RDV構通的 RELAY
節點,架構如下列官方文件裡的圖:

JXSE 下載下來解開有四個 jar:
jxse.jar、bcprov-jdk14.jar、javax.servlet.jar、org.mortbay.jetty.jar
其中似乎只要有 jxse.jar 即可 compile 而執行需要 jxse.jar 加 bcprov-jdk14.jar
javax.servlet.jar、org.mortbay.jetty.jar 目前的用處不明。
JXSE 程式以 net.jxta.platform.NetworkManager 類別來啟動及管理 JXTA 網路
建立 NetworkManager 時需指定 peer 種類及相關資訊:
jxtaNetMan = new NetworkManager(
NetworkManager.ConfigMode.EDGE,
FEELER_ENTITY_PEER_NAME,
new File(new File(JXTA_HOME), FEELER_ENTITY_PEER_NAME).toURI()
);
第一個參數為 peer 種類,第二個參數為 peer 名稱,第三個參數為 peer 資料暫存目錄
建立好 NetworkManager 之後可以進行一些設定:
jxtaNetMan.setConfigPersistent(true); // 啟動儲存設定功能
// 使用官方提供的預設 RDV ,但似乎有問題,無法連線
//會不斷連往 http://rdv.jxtahosts.net/cgi-bin/rendezvous.cgi?3 查詢 RDV
jxtaNetMan.setUseDefaultSeeds(true);
jxtaNetCfg = jxtaNetMan.getConfigurator(); // 取得設定物件,以進行更多設定
// 加入自定的 RDV 位址,範例: "tcp://www.bennu.tw:9701"
jxtaNetCfg.addSeedRendezvous(new URI(NetService.FEELER_RDV_URI));
jxtaNetCfg.save(); // 儲存設定到 peer 資料暫存目錄下的 PlatformConfig 檔案
設定之後,即可以 startNetwork() 啟動這一個 peer 的運作。
// startNetWork() 傳回 net group
infrastructurePeerGroup = jxtaNetMan.startNetwork();
每一個裝置或者jvm應該可以同時擁有多個節點,同時扮演多個角色,如:
可以既是某些 EDGE 的 RDV 又是其他 RDV 的 EDGE ,但是目前測試的結果,
無法在同一個 jvm 下啟動兩次 JXTA network
啟動完成後會回傳一個 peer group 物件,每一個 peer 最少都會加入一個 peer group
這個 peer group 稱之為 net peer group,可以想像成整個 JXTA 網路是一個 peer group
而如果要另外建立 peer group 也一定是此 net peer group 的子集,如下圖:
discovery service、pipe service、rdv service、… 等,JXTA定義了許多 service
可以讓 peer 與 peer 進行資料傳遞,而不需在乎每個 peer 所在的網路環境。
其中需先注意 rdv service ,以 RDV peer 來說,除了在建立 NetworkManager 時,
第一個參數給予 NetworkManager.ConfigMode.RENDEZVOUS 仍然無法讓其他
EDGE peer 連上這一個 rdv peer ,還需在 startNetwork() 後啟動一下 rdv service:
jxtaNetMan.getNetPeerGroup().getRendezVousService().startRendezVous();
如此才可以開始提供 rdv 功能。
而 EDGE peer 要連上 RDV peer 則是使用 :
boolean connected = jxtaNetMan.waitForRendezvousConnection(timeout);
waitForRendezvousConnection 是一個 block 方法,會一直嘗試連線到成功或是
timeout 時間到為止,而回傳 boolean 表示連線成功(true)或失敗(false)。
目前 timeout 必須設定長一點,即使是在 local net 也需要 5 分鐘以上比較好。
可能是由於使用廣播的方式,導致連線效率不好,官網上可以看到已有改進的工作
除了 EDGE 可以連上 RDV,RDV 也可透過同一 method 連上其他 RDV,
以構成 RDV 主幹網路,而 EDGE peer 顧名思議就是散佈在 RDV 主幹網路的邊緣。
2009年12月3日 星期四
ivy 加入 java 的 maven 2 repository
直接在 <ivysettings> <resolvers> 下加入
<!-- maven 2 -->
<ibiblio name="java-net-maven2" root="http://download.java.net/maven/2/" m2compatible="true" />
這一個 ibiblio 節點
並在
<chain name="main" dual="true"> 裡補上
<resolver ref="java-net-maven2"/>
範例:
<?xml version="1.0" encoding="utf-8"?>
<ivysettings>
<resolvers>
<!-- spring EBR -->
<url name="com.springsource.repository.bundles.release">
<ivy pattern="http://repository.springsource.com/ivy/bundles/release/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
<artifact pattern="http://repository.springsource.com/ivy/bundles/release/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
</url>
<url name="com.springsource.repository.bundles.external">
<ivy pattern="http://repository.springsource.com/ivy/bundles/external/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
<artifact pattern="http://repository.springsource.com/ivy/bundles/external/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
</url>
<!-- maven 2 -->
<ibiblio name="java-net-maven2" root="http://download.java.net/maven/2/" m2compatible="true" />
<!-- main chain -->
<chain name="main" dual="true">
<resolver ref="shared"/>
<resolver ref="public"/>
<resolver ref="com.springsource.repository.bundles.release"/>
<resolver ref="com.springsource.repository.bundles.external"/>
<resolver ref="java-net-maven2"/>
</chain>
</resolvers>
</ivysettings>
2009年11月28日 星期六
java java.ext.dirs jvm 環境變數設定
在 java 運行時可以透過 -cp 去設定 classpath,
-cp 可以指定多個資料夾做為 *.class 檔的來源目錄,
同時也可以指定多個 jar 檔案做為 *.class 檔的來源,但是,
jar 檔通常很多,如果要一一的指定每一個 jar 非常不方便,
且,一般來說 jar 會被放在一個統一的目錄下:如 lib/ ,
這時可以透過 java -Djava.ext.dirs=lib 來指定 lib 下的所有 jar 檔,
一次就可以把所有的 jar 做為 classpath ,非常方便。
2009年11月19日 星期四
java 透過 PythonInterpreter 執行外部的 py 程式檔
先建立所需要的 java interface
package tw.bennu.feeler.jython.service;
public interface IJyCommand {
public String getName();
}
寫 src/jython/JyCommand.py 去實作 java interface
from tw.bennu.feeler.jython.service import IJyCommand
class JyCommandImpl(IJyCommand):
def __init__(self,cmd):
self.command = cmd
def getName(self):
ret = self.command
print ret
return ret
寫一個 Factory 物件,負責建立PythonInterpreter、讀取*.py、建立及回傳物件實例
public class JyFactory {
// 以 jython 實作的 classes 物件,可用來建立實例
private PyObject jyCommandClass = null;
public JyFactory() {
PyDictionary table = new PyDictionary();
PySystemState state = new PySystemState();
state.setClassLoader(JyFactory.class.getClassLoader());
PythonInterpreter interp = new PythonInterpreter(table, state);
// 讀入 src/jython/*.py
interp.execfile("src/jython/JyCommand.py");
jyCommandClass = interp.get("JyCommandImpl");
}
/**
* 建立一個 IJyCommand 介面的實例 (由JyCommand.py 實作介面內容)
*
* @param name
* @return
*/
public IJyCommand getJyCommand(String name) {
PyObject jyCommandObj = this.jyCommandClass.__call__(new PyString(name));
return (IJyCommand) jyCommandObj.__tojava__(IJyCommand.class);
}
}
JyFactory 解說:先以 interp.get("JyCommandImpl"); 取得 class 物件(只做一次),
再以 class.__call__ 建立實例 obj 物件,最後以 obj.__tojava__轉換回java 物件
public static void main(String[] args){
String name = jythonServImpl.getJyCommand("hello jython").getName();
System.out.println(name);
}
結果會印出 hello jython
jython Embedded 直譯器的 ClassLoader設定
jython 可以 embedded 一個直譯器到 java 的程式裡,叫作PythonInterpreter物件,
透過PythonInterpreter,我們可以寫出python語法的程式碼,同時又使用到java的物件,
PythonInterpreter 在建立時可以指定某個 classloader 做為他在讀取 java class的依據,
在某些Classloader 環境較特殊的情況可以使用,如OSGi的每個 bundle 都有自己的 classloader。
設定方式如下:
PyDictionary table = new PyDictionary();
PySystemState state = new PySystemState();
state.setClassLoader(XXX.class.getClassLoader());
PythonInterpreter interp = new PythonInterpreter(table, state);
其中的 table 是 python 的 key-value namespace 如:
a=1
則 table 裡會加入一筆 key=new PyString("a");value=new PyInteger(1) 的 pair,
傳入 table 可以當做 PythonInterpreter 建立時的預設參數,供 python 程式碼參考使用。
2009年11月17日 星期二
Felix 使用到 rt.jar 裡特殊的 package 設定
在OSGi的環境裡每個bundle都有自己的classloader,因此要使用別的bundle的package
必須透過Import、Export來使用。
Felix是一個java的OSGi實作,jre本身有提供許多官方的package可供使用,因此,
當Felix啟動時,必須啟動一個稱為System Bundle的 bundle,而這個System Bundle即
Export出許多 jre 所提供的 package,然而並非是"整個" jre 的 package 都Export 出來,
如 rt.jar 的一些 com.sun.* 的 package 即有缺少,可以在 Felix 的config.properties 檔裡
加上:
org.osgi.framework.system.packages.extra= \
com.sun.package.a,\
com.sun.package.b,\
....
來將需要的 package export 出來。
2009年11月12日 星期四
java MessageDigest 產生編碼資料
以 java.security.MessageDigest 產生 md5 編碼:
String password = "123";
MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(password.getBytes());
String digest = new String(md5.digest());
除了md5也有rsa等各種編碼詳見MessageDigest javadoc
virtual box 官方版本安裝
http://www.virtualbox.org/wiki/Linux_Downloads
轉載自官方wiki說明如下:
Debian-based Linux distributionsAdd
one of the following lines according to your distribution to your /etc/apt/sources.list:
deb http://download.virtualbox.org/virtualbox/debian karmic non-free
deb http://download.virtualbox.org/virtualbox/debian jaunty non-free
deb http://download.virtualbox.org/virtualbox/debian intrepid non-free
deb http://download.virtualbox.org/virtualbox/debian hardy non-free
deb http://download.virtualbox.org/virtualbox/debian gutsy non-free
deb http://download.virtualbox.org/virtualbox/debian dapper non-free
deb http://download.virtualbox.org/virtualbox/debian lenny non-free
deb http://download.virtualbox.org/virtualbox/debian etch non-free
deb http://download.virtualbox.org/virtualbox/debian sarge non-free
deb http://download.virtualbox.org/virtualbox/debian xandros4.0-xn non-free
The Sun public key for apt-secure can be downloaded here.
You can add this key with
sudo apt-key add sun_vbox.asc
or combine downloading and registering:
wget -q http://download.virtualbox.org/virtualbox/debian/sun_vbox.asc -O- | sudo apt-key add -
The key fingerprint is
AF45 1228 01DA D613 29EF 9570 DCF9 F87B 6DFB CBAE Sun Microsystems, Inc.
(xVM VirtualBox archive signing key)
To install VirtualBox, do
apt-get install virtualbox-3.0
2009年11月10日 星期二
Unit Test 使用 System.in 輸入的物件
有時我們會有程式是需要從 System.in 輸入資料來進行運算的,我們會這樣寫:
BufferedReader inputBr = new BufferedReader(new InputStreamReader(System.in));
String input = inputBr.readLine();
但在寫UnitTest時,不可能測試到一半還要去輸入一些資訊到 console,有違自動化的架構。
且在 ant 結合 junit 時,遇到這種狀況會直接測試失敗,這時我們可以透過 mock System.in 的方式,
完成這一個測試,首先待測物件不可以直接使用 System.in 而是在建構子上加上一個,
傳入 InputStream的建構子,而預設建構子則以 System.in 當作該 InputStream,如:
public LcanorusMain() {
this(System.in);
}
public LcanorusMain(InputStream in) {
this.systemIn = in;
}
真正執行時是使用預設建構子,而測試時就是使用有 InputStream 參數的建構子,
並且傳入假造的 mock InputStream 即可:
@Before
public void before() {
lcMain = new LcanorusMain(new SystemInMockInputStream());
}
假造的 mock InputStream 實作重點就是將所要回傳的資料轉成 byte 再一一由read()方法傳回。
且完成所有 byte 後要傳回 -1 表示結束。
private class SystemInMockInputStream extends InputStream {
private byte[] cmdBytes = "fexit\n".getBytes();
private int readIndex = 0;
@Override
public int read() throws IOException {
if (readIndex < cmdBytes.length) {
int ret = cmdBytes[readIndex];
readIndex++;
return ret;
} else {
return -1;
}
}
}
2009年11月5日 星期四
OSGi 的 Bundle-Classpath header
OSGi bundle 可以透過 Import-Package 及 Export-Package 去使用互相的 Class,
但前提是彼此都是 OSGi bundle 格式的 jar 並完成部署在 OSGi 平台上,如Felix、Equinox…,
如果只是單純要使用到非OSGi bundle的第三方 jar,必須要將 jar 整個放到 OSGi bundle 的 bundle space 裡。
所謂的 bundle space 就是 bundle jar 本身,及 bundle 裡的 META-INF/MANIFEST.MF所指定的位置。
MANIFEST.MF 有一個 Bundle-Classpath 的 Header 可以用來指定引用到的第三方 jar。
需注意,指定時要將 "." 目錄也加上去,這裡的 "." 目錄就是指 bundle jar 的根目錄,再
以 "," 分隔,一一加入所需要的第三方 jar,而jar的位置也是以bundle根目錄開始算起。
範例(加入sqlite-jdbc.jar):
Manifest-Version: 1.0
Spring-Context: META-INF/spring/db-context.xml,META-INF/spring/db-osgi-context.xml
Bundle-Name: [feeler] db service
Bundle-Description: provide db service
Bundle-Vendor: muchu@www.bennu.tw
Bundle-Version: 0.0.1
Import-Package: org.osgi.framework
Export-Package: tw.bennu.feeler.db.service
Bundle-ClassPath: .,
META-INF/lib/sqlite-jdbc-3.6.17.jar
因此這一個 bundle jar的裡面還有一個sqlite-jdbc-3.6.17.jar並放在META-INF/lib/ 下。
另外 Bundle-ClassPath 也可以指定含有 *.class 的資料夾做為 classpath。
用法和 java 的 -cp 完全一樣,只是改以"," 分隔。
而且不需再對Bundle-ClassPath的jar做Import-Package的宣告,Import-Package 是偵對
其他 bundle Export 出來的 Package 使用。有宣告反而會因找不到Export-Package而無法啟動 bundle。
2009年11月2日 星期一
easymock 官方範例
mock 是指當用來被 unit 測試對象的物件,需要相依某些其他物件才能正常運作時,
public interface Collaborator {
import static org.easymock.EasyMock.*;
以一個"假冒"的 mock 物件實作被相依的物件之界面,設定給 unit 測試對象物件,
目的是隔離unit 測試對象物件與部署環境,並於測試後直接檢查mock物件的變化,
達到不需要部署測試對象物件到環境,也可以了解測試對象物件對環境的影響是否符合要求。
easymock api 方便我們建立 mock 物件,官方範例如下:
http://www.easymock.org/EasyMock2_5_2_Documentation.html
以一個被測試的 ClassUnderTest 物件,使用到一個 Collaborator 介面為例,
將要為 Collaborator 建立 mock ,並給 ClassUnderTest 做測試。
public class ClassUnderTest { // ...
public void addListener(Collaborator listener){
// ...
}
public void addDocument(String title, byte[] document) {
// ...
}
public boolean removeDocument(String title) {
// ...
}
public boolean removeDocuments(String[] titles) {
// ...
}
}
public interface Collaborator {
void documentAdded(String title);
void documentChanged(String title);
void documentRemoved(String title);
byte voteForRemoval(String title);
byte[] voteForRemovals(String[] title);
}
測試的 TestCase 實作如下:
import junit.framework.TestCase;
public class ExampleTest extends TestCase {
private ClassUnderTest classUnderTest;
private Collaborator mock;
protected void setUp() {
mock = createMock(Collaborator.class); // 1 建立 mock
classUnderTest = new ClassUnderTest();
classUnderTest.addListener(mock);
}
public void testAddDocument() {
mock.documentAdded("New Document"); // 2 設定 mock 物件將replay後該有的行為
replay(mock); // 3 切換 mock 為 replay 準備狀態
classUnderTest.addDocument("New Document", new byte[0]);
}
}
重點在 replay() 之前 mock 物件運作的行為不是 Collaborator 真正的行為,而是,
"預先告知" replay() 之後, mock 應該要有什麼 method 被呼叫,傳進來的參數是什麼…等。
而 replay() 之後, classUnderTest.addDocument("New Document", new byte[0]);
如果沒有觸發 mock 物件"預先告知"的行為,就會產生錯誤使得測試失敗。
ivy 官方範例
ivy 採用和 maven 相同的 lib 管理機置,也使用相同的 repository,
<ivy-module version="2.0">
...
<!-- =================================
target: resolve
================================= -->
<target name="resolve" description="--> retrieve dependencies with ivy">
<ivy:retrieve />
</target>
</project>
ivy 的 dependency 設定檔叫做 ivy.xml,範例:
<info organisation="apache" module="hello-ivy"/>
<groupId>commons-lang</groupId>
<dependencies>
<dependency org="commons-lang" name="commons-lang" rev="2.0"/>
<dependency org="commons-cli" name="commons-cli" rev="1.0"/>
</dependencies>
</ivy-module>
<dependency org="commons-lang" name="commons-lang" rev="2.0"/>
<dependency org="commons-cli" name="commons-cli" rev="1.0"/>
</dependencies>
</ivy-module>
對應於 maven 的 dependency
<dependency><groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.0</version>
</dependency>
groupId 對應到 org
artifactId 對應到 name
version 對應到 rev
完成 ivy.xml後將他放在和 ant build.xml 同目錄下,並在 build.xml 裡加上 resolve target:
<project xmlns:ivy="antlib:org.apache.ivy.ant" name="hello-ivy" default="run">...
<!-- =================================
target: resolve
================================= -->
<target name="resolve" description="--> retrieve dependencies with ivy">
<ivy:retrieve />
</target>
</project>
執行 ant resolve 時,ivy 會自動到 maven repository 上找到 ivy.xml 裡定義的 library,
並將之下載到 ~/ivy2/cache 下儲存為本地函式庫,再 copy 到 build.xml 同目錄下的 lib 資料夾裡。
spring-DM webcontainer 啟動
spring-DM 以 extender bundle 去偵測install進來的 bundle中
的META-INF/MANIFEST.MF含有:
Spring-Context: xxxxx/xxxx.xml
這個 header 的 bundle 並以這個 xml 為這個 bundle 建立一個屬於他的
ApplicationContext.....
與 war 整合時,則透過類似相同的概念,不過不是用同一個 extender 偵測,
而是要另外再加上 org.springframework.osgi.web.extender 這個 bundle,
他一樣會偵測 install 進來的 war (war 也可以被當做 bundle install),
並看 war 裡面的 META-INF/MANIFEST.MF 的 Spring-Context
但是不為 war 建立 ApplicationContext 而是將 war 丟給指定的 WebContainer,
預設為 tomcat,tomcat當然也是一個 bundle,再由WebContainer去建立ApplicationContext。
tomcat WebContainer 有自己原本的啟勳方式,但現在被當成一個 bundle,
就必須以OSGi的方式啟動,也就是 Activator ,而tomcat bundle本身沒有這一個Activator,
因此,除了tomcat bundle以外,還要再加裝一個Spring-DM提供的catalina.start.osgi-1.0.0.jar
由這個 start bundle 來啟動 tomcat。這裡的 tomcat bundle 和 tomcat start bundle
都可以在 Spring-DM 的 zip 檔裡的 lib 目錄下找到,目前試過只有 Spring-DM 提供的bundle,運作正常。
除了 tomcat WebContainer ,也可以使用 jetty 做為 WebContainer ,只要以 OSGi 的 fragment 機致,
去修改 org.springframework.osgi.web.extender 的設定即可,Spring-DM 文件中有寫:
http://static.springsource.org/osgi/docs/1.2.0/reference/html-single/#web:configuration:changing-deployer
但由於目前使用的 Felix Osgi Framework 未支援 fragment 機致,因此只能先以 tomcat 做為 WebContainer。
jetty 同樣也需要 start bundle,jetty fragment 、 start bundle 在 Spring-DM zip 檔的 lib 裡都可以找到。
2009年10月29日 星期四
ivy 新增 maven repository 以外的 repository
先在 build.xml 所在目錄下加入 ivysettings.xml 覆寫掉 ivy.jar 裡預設的 ivysettings.xml
這裡新增的public和shared resolver 是原本ivy.jar就預設定義的,而新增的兩個 url resolver是 spring 的 SpringSource Enterprise Bundle Repository
僅修改 main-chain 部分內容如下:
<?xml version="1.0" encoding="utf-8"?>
<ivysettings>
<settings defaultResolver="default"/>
<include url="${ivy.default.settings.dir}/ivysettings-public.xml"/>
<include url="${ivy.default.settings.dir}/ivysettings-shared.xml"/>
<include url="${ivy.default.settings.dir}/ivysettings-local.xml"/>
<include url="ivysettings-main-chain.xml"/>
<include url="${ivy.default.settings.dir}/ivysettings-default-chain.xml"/>
</ivysettings>
${ivy.default.settings.dir}的位置就是 ivy.jar 裡的 org.apache.ivy.core.settings package
修改後改為指到 build.xml 所在目錄下的 ivysettings-main-chain.xml
新增 ivysettings-main-chain.xml 其內容如下:
<?xml version="1.0" encoding="utf-8"?>
<ivysettings>
<resolvers>
<url name="com.springsource.repository.bundles.release">
<ivy pattern="http://repository.springsource.com/ivy/bundles/release/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
<artifact pattern="http://repository.springsource.com/ivy/bundles/release/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
</url>
<url name="com.springsource.repository.bundles.external">
<ivy pattern="http://repository.springsource.com/ivy/bundles/external/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
<artifact pattern="http://repository.springsource.com/ivy/bundles/external/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]" />
</url>
<chain name="main" dual="true">
<resolver ref="shared"/>
<resolver ref="public"/>
<resolver ref="com.springsource.repository.bundles.release"/>
<resolver ref="com.springsource.repository.bundles.external"/>
</chain>
</resolvers>
</ivysettings>
這裡新增的public和shared resolver 是原本ivy.jar就預設定義的,而新增的兩個 url resolver是 spring 的 SpringSource Enterprise Bundle Repository
安裝 ivy - 類似 maven 的 java 函式庫管理工具
下載 ivy 後將 ivy-x.x.x.jar 放到 ant 的 lib 目錄下…如:
/usr/share/ant/lib/ivy-2.1.0.jar
即可在 ant 的 build.xml 裡使用 ivy 的 tag
並且編寫 ivy.xml 定義所用到的函式庫,放在 build.xml 檔案的同目錄下。
2009年10月27日 星期二
META-INF/MANIFEST.MF 的最後一行注意事項
要多加一行空白行(多按一次Enter),否則最後一行的參數將無法被 jar 讀到。
如:
========= MANIFEST.MF 開始 ==========
Manifest-Version: 1.0
Bundle-Name: Service listener example
Bundle-Description: A bundle that displays messages at startup and when service events occur
Bundle-Vendor: Apache Felix
Bundle-Version: 1.0.0
Bundle-Activator: tw.bennu.tutorial.example.Activator
Import-Package: org.osgi.framework (<===最後一行參數)
========= MANIFEST.MF 結束 ==========
2009年10月23日 星期五
以 mutt 結合 msmtp 透過遠端 MTA 幫忙發信
mutt 是 linux 下常見預設安裝好的文字模式 mail client
但是,本身預設不但不包含 pop3、smtp 功能,甚至連郵件編輯器也是委拖其他軟體
同樣的我們可以安裝 msmtp ,並讓 mutt 委拖 smtp 功能給 msmtp 就可以寄信了。
安裝 msmtp
sudo aptitude install msmtp
在家目錄下建立 ~/.msmtprc 內容:
# Example for a user configuration file
# Set default values for all following accounts.
defaults
tls on #Gmail TLS有打開
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile ~/.msmtp.log
# A freemail service
account gmail
host smtp.gmail.com
from yourid@gmail.com
auth on #Gmail SMTP要認證
user yourid #gmail 帳號
password secret #gmail 密碼,明碼,記得chmod 600本檔案
# Set default values for all following accounts.
defaults
tls on #Gmail TLS有打開
tls_trust_file /etc/ssl/certs/ca-certificates.crt
logfile ~/.msmtp.log
# A freemail service
account gmail
host smtp.gmail.com
from yourid@gmail.com
auth on #Gmail SMTP要認證
user yourid #gmail 帳號
password secret #gmail 密碼,明碼,記得chmod 600本檔案
account default : gmail
在家目錄下建立 ~/.muttrc 內容
set sendmail="/usr/bin/msmtp"
set from=yourid@yourdomain.com #gmail SMTP會覆寫
set from=yourid@yourdomain.com #gmail SMTP會覆寫
2009年10月22日 星期四
ssh disable 掉 password 登入
注意!進行此動作前需先確定可以透過 ssh-key 登入,
否則…主機最好別放太遠.....
編輯 /etc/ssh/ssh_config 檔
sudo vim /etc/ssh/ssh_config
設定以下三行為 no
ChallengeResponseAuthentication no
PasswordAuthentication no
UsePAM no
重新 reload ssh 服務
sudo /etc/init.d/ssh reload
測試,先將私錀改名
mv ~/.ssh/id_rsa ~/.ssh/id_rsa.backup
以 ssh 登入如果出現以下訊息表示ok (不再要求輸入密碼):
“Permission denied (publickey).”
成功後再把私錀改回來
mv ~/.ssh/id_rsa.backup ~/.ssh/id_rsa
否則…主機最好別放太遠.....
編輯 /etc/ssh/ssh_config 檔
sudo vim /etc/ssh/ssh_config
設定以下三行為 no
ChallengeResponseAuthentication no
PasswordAuthentication no
UsePAM no
重新 reload ssh 服務
sudo /etc/init.d/ssh reload
測試,先將私錀改名
mv ~/.ssh/id_rsa ~/.ssh/id_rsa.backup
以 ssh 登入如果出現以下訊息表示ok (不再要求輸入密碼):
“Permission denied (publickey).”
成功後再把私錀改回來
mv ~/.ssh/id_rsa.backup ~/.ssh/id_rsa
以 ssh-key 代替密碼登入遠端機器
muchu@glory:~$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/muchu/.ssh/id_rsa): /home/muchu/id_rsa
Enter passphrase (empty for no passphrase): #直接按 enter
Enter same passphrase again: #直接按 enter
Your identification has been saved in /home/muchu/id_rsa.
Your public key has been saved in /home/muchu/id_rsa.pub.
The key fingerprint is:
21:02:7e:b1:7d:11:85:26:e7:4b:16:ae:39:d5:79:ed muchu@glory
The key's randomart image is:
+--[ RSA 2048]----+
| . . o+. |
| . . +. =. |
| . + o*oo . . |
| . . o*.o . . |
| *S. . . |
| + . E |
| . |
| |
| |
+-----------------+
muchu@glory:~$ ls /home/muchu | grep id_rsa
id_rsa id_rsa.pub
id_rsa 是私錀,id_rsa.pub 是公錀。
將 "公錀的內容" 附加在 "對方" 主機的 ~/.ssh/authorized_keys 下。
並將私錀以 id_rsa 的名稱放在 ~/.ssh/ 下。就可以不用密碼 ssh 登入 "對方" 主機。
在 debian 系統,放公錀到對方主機的動作可以透過以下命令完成,先將公錀放在 ~/.ssh/ 下
ssh-copy-id muchu@www
Generating public/private rsa key pair.
Enter file in which to save the key (/home/muchu/.ssh/id_rsa): /home/muchu/id_rsa
Enter passphrase (empty for no passphrase): #直接按 enter
Enter same passphrase again: #直接按 enter
Your identification has been saved in /home/muchu/id_rsa.
Your public key has been saved in /home/muchu/id_rsa.pub.
The key fingerprint is:
21:02:7e:b1:7d:11:85:26:e7:4b:16:ae:39:d5:79:ed muchu@glory
The key's randomart image is:
+--[ RSA 2048]----+
| . . o+. |
| . . +. =. |
| . + o*oo . . |
| . . o*.o . . |
| *S. . . |
| + . E |
| . |
| |
| |
+-----------------+
muchu@glory:~$ ls /home/muchu | grep id_rsa
id_rsa id_rsa.pub
id_rsa 是私錀,id_rsa.pub 是公錀。
將 "公錀的內容" 附加在 "對方" 主機的 ~/.ssh/authorized_keys 下。
並將私錀以 id_rsa 的名稱放在 ~/.ssh/ 下。就可以不用密碼 ssh 登入 "對方" 主機。
在 debian 系統,放公錀到對方主機的動作可以透過以下命令完成,先將公錀放在 ~/.ssh/ 下
ssh-copy-id muchu@www
2009年10月19日 星期一
trac 重新同步 svn
如果在 trac 已經指定了某個 svn repository 的環境下,
重新建立 svn repository 導致 repositoy 版本變動,如:
將 rev 101 僅 dump 出第 101 版本,並放棄第 1~100 版。
重新建立 reposiotry load 101 版為新 repository 的第 1 版。
這時連到原本指定 repository 的 trac 時會看到以下的錯誤訊息:
Can't synchronize with the repository
執行以下命令重新進行 trac 與 svn 的同步即可解決:
trac-admin </path/to/projenv> resync
重新建立 svn repository 導致 repositoy 版本變動,如:
將 rev 101 僅 dump 出第 101 版本,並放棄第 1~100 版。
重新建立 reposiotry load 101 版為新 repository 的第 1 版。
這時連到原本指定 repository 的 trac 時會看到以下的錯誤訊息:
Can't synchronize with the repository
執行以下命令重新進行 trac 與 svn 的同步即可解決:
trac-admin </path/to/projenv> resync
2009年10月12日 星期一
apache2 + svn + trac 設置
一、apache2 + svn
#安裝 svn apache2 及 apache2-svn 模組
apt-get install apache2 subversion libapache2-svn
#建立 svn 目錄
mkdir -p /usr/local/svn
#建立 repos svn倉庫
svnadmin /usr/local/svn/repos
#改變 repos 存取權限
chown -R www-data /usr/local/svn/repos
#設定 apache dav_svn 模組
vim /etc/apache2/mods-available/dav_svn.conf
#修改為
<Location /svn>
DAV svn
SVNPath /usr/local/svn/repos
AuthType Basic
AuthName "Subversion repos"
AuthUserFile /etc/apache2/dav_svn.passwd
AuthzSVNAccessFile /etc/apache2/dav_svn.authz
#<LimitExcept GET PROPFIND OPTIONS REPORT>
Require valid-user
#</LimitExcept>
</Location>
#建立 dav_svn.authz 設定帳號讀寫權限
vim /etc/apache2/dav_svn.authz
#修改為 :設定 "/" = /repos 下的資料除了 muchu 帳號可以讀寫,其他帳號均不可讀寫。
[/]
* =
muchu = rw
#建立 dav_svn.passwd 設定帳號密碼 (如果檔案已存在就不需要 -c)
/usr/bin/htpasswd -c /etc/apache2/dav_svn.passwd muchu
#重新啟動 apache2
/etc/init.d/apache2 restart
#以 http co svn
svn co http://www.bennu.tw/svn
二、trac
#安裝 trac 及 mod_python 模組
apt-get install trac libapache2-mod-python
#建立 trac 根目錄
mkdir -p /usr/local/trac
#初始化 trac
trac-admin /usr/local/trac/wiki initenv
#Project Name 指定為
wiki
#Path to Repository 指定為
/usr/local/svn/repos
#設定 trac.ini
vim /usr/local/trac/wiki/conf/trac.ini
#修改 default_charset 編碼
default_charset = utf-8
#修改存取權限
chown www-data.www-data -R /usr/local/trac/wiki
# standalone 執行測試
sudo -u www-data tracd --port 8000 /usr/local/trac/wiki
存取 http://127.0.0.1:8000/ 檢查是否正常運作
#建立 apache2 Virtual Host
vim /etc/apache2/sites-available/trac
#修改為:
<VirtualHost *:80>
ServerName trac.bennu.tw
ServerAdmin muchu@trac.bennu.tw
DocumentRoot /usr/local/trac
ErrorLog /var/log/apache2/trac-error.log
CustomLog /var/log/apache2/trac-access.log combined
SetHandler mod_python
PythonHandler trac.web.modpython_frontend
PythonOption TracEnv "/usr/local/trac/wiki"
PythonOption TracUriRoot "/trac/wiki"
<LocationMatch "/trac/[^/]+/login">
AuthType Basic
AuthName "trac"
AuthUserFile /etc/apache2/dav_svn.passwd
Require valid-user
</LocationMatch>
</VirtualHost>
#啟動 trac Virtual Site
sudo a2ensite trac
#重啟 apache2
/etc/init.d/apache2 restart
#新增 trac.bennu.tw domain
trac CNAME www.bennu.tw.
#存取 http://trac.bennu.tw/trac/wiki
並可以 svn 使用的 muchu 帳號登入
#安裝 svn apache2 及 apache2-svn 模組
apt-get install apache2 subversion libapache2-svn
#建立 svn 目錄
mkdir -p /usr/local/svn
#建立 repos svn倉庫
svnadmin /usr/local/svn/repos
#改變 repos 存取權限
chown -R www-data /usr/local/svn/repos
#設定 apache dav_svn 模組
vim /etc/apache2/mods-available/dav_svn.conf
#修改為
<Location /svn>
DAV svn
SVNPath /usr/local/svn/repos
AuthType Basic
AuthName "Subversion repos"
AuthUserFile /etc/apache2/dav_svn.passwd
AuthzSVNAccessFile /etc/apache2/dav_svn.authz
#<LimitExcept GET PROPFIND OPTIONS REPORT>
Require valid-user
#</LimitExcept>
</Location>
#建立 dav_svn.authz 設定帳號讀寫權限
vim /etc/apache2/dav_svn.authz
#修改為 :設定 "/" = /repos 下的資料除了 muchu 帳號可以讀寫,其他帳號均不可讀寫。
[/]
* =
muchu = rw
#建立 dav_svn.passwd 設定帳號密碼 (如果檔案已存在就不需要 -c)
/usr/bin/htpasswd -c /etc/apache2/dav_svn.passwd muchu
#重新啟動 apache2
/etc/init.d/apache2 restart
#以 http co svn
svn co http://www.bennu.tw/svn
二、trac
#安裝 trac 及 mod_python 模組
apt-get install trac libapache2-mod-python
#建立 trac 根目錄
mkdir -p /usr/local/trac
#初始化 trac
trac-admin /usr/local/trac/wiki initenv
#Project Name 指定為
wiki
#Path to Repository 指定為
/usr/local/svn/repos
#設定 trac.ini
vim /usr/local/trac/wiki/conf/trac.ini
#修改 default_charset 編碼
default_charset = utf-8
#修改存取權限
chown www-data.www-data -R /usr/local/trac/wiki
# standalone 執行測試
sudo -u www-data tracd --port 8000 /usr/local/trac/wiki
存取 http://127.0.0.1:8000/ 檢查是否正常運作
#建立 apache2 Virtual Host
vim /etc/apache2/sites-available/trac
#修改為:
<VirtualHost *:80>
ServerName trac.bennu.tw
ServerAdmin muchu@trac.bennu.tw
DocumentRoot /usr/local/trac
ErrorLog /var/log/apache2/trac-error.log
CustomLog /var/log/apache2/trac-access.log combined
SetHandler mod_python
PythonHandler trac.web.modpython_frontend
PythonOption TracEnv "/usr/local/trac/wiki"
PythonOption TracUriRoot "/trac/wiki"
<LocationMatch "/trac/[^/]+/login">
AuthType Basic
AuthName "trac"
AuthUserFile /etc/apache2/dav_svn.passwd
Require valid-user
</LocationMatch>
</VirtualHost>
#啟動 trac Virtual Site
sudo a2ensite trac
#重啟 apache2
/etc/init.d/apache2 restart
#新增 trac.bennu.tw domain
trac CNAME www.bennu.tw.
#存取 http://trac.bennu.tw/trac/wiki
並可以 svn 使用的 muchu 帳號登入
2009年10月2日 星期五
2009年10月1日 星期四
python 學習資料小集
Python 教學文件
http://www.python.tw/ebook/Guido%20van%20Rossum/tut.html
Python 學習手冊
http://www.oreilly.com.tw/product2_c.php?id=a240
易記學
http://ez2learn.com/index.php/python-tutorials
pydoing
http://pydoing.blogspot.com/
官方 module index
http://docs.python.org/modindex.html
http://www.python.tw/ebook/Guido%20van%20Rossum/tut.html
Python 學習手冊
http://www.oreilly.com.tw/product2_c.php?id=a240
易記學
http://ez2learn.com/index.php/python-tutorials
pydoing
http://pydoing.blogspot.com/
官方 module index
http://docs.python.org/modindex.html
2009年8月28日 星期五
java JVM 增大記憶體配置參數 -X 與 -XX
java OOM 分為兩種:
java.lang.OutOfMemoryError: PermGen space
表示 stack 空間不夠,可能是 static 變數太多,或 class 太多。
java.lang.OutOfMemoryError: Java heap space
表示 heap 空間不夠,可能是建立的物件太多,或是處理資料檔案太大。
-Xms<size> : 初始的記憶體大小 (heap)
-Xmx<size> : 最大的記憶體大小 (heap)
-XX:MaxNewSize=<size> : 初始的記憶體大小 (stack)
-XX:MaxPermSize=<size> :最大的記憶體大小 (stack)
-Xincgc = 讓gc在背景持續執行
例:
java -Xms512M -Xmx1024M -XX:MaxNewSize=256m -XX:MaxPermSize=256m -Xincgc -version
java.lang.OutOfMemoryError: PermGen space
表示 stack 空間不夠,可能是 static 變數太多,或 class 太多。
java.lang.OutOfMemoryError: Java heap space
表示 heap 空間不夠,可能是建立的物件太多,或是處理資料檔案太大。
-Xms<size> : 初始的記憶體大小 (heap)
-Xmx<size> : 最大的記憶體大小 (heap)
-XX:MaxNewSize=<size> : 初始的記憶體大小 (stack)
-XX:MaxPermSize=<size> :最大的記憶體大小 (stack)
-Xincgc = 讓gc在背景持續執行
例:
java -Xms512M -Xmx1024M -XX:MaxNewSize=256m -XX:MaxPermSize=256m -Xincgc -version
2009年8月21日 星期五
spring 的 annotation @Value 介紹
通常在 bean.xml 裡我們常以 value 注入單純的資料,如 int,string、
也會注入 properties 檔裡的變數資料,如:
x-setting.properties -
com.transtep.xdna.doc.projplan.docDirLocation=tpma_doc
x-bean.xml -
<property name="docDirLocation">
<value>${com.transtep.xdna.doc.projplan.docDirLocation}</value>
</property>
但spring 3.0 使用 annotation 的時候,x-bean.xml 有些 bean 就不需要再宣告了,如 @Controller
而是自動讓 spring 去 scan 某 package 找到的,如此一來就無法注入 value
在 spring 3.0.M3 時加入了 @Value 這一個方便的 annotation 讓我們可以重拾 value 注入。
用法:
@Value("${com.transtep.xdna.doc.projplan.docDirLocation}")
private String docDirLocation = "";
也會注入 properties 檔裡的變數資料,如:
x-setting.properties -
com.transtep.xdna.doc.projplan.docDirLocation=tpma_doc
x-bean.xml -
<property name="docDirLocation">
<value>${com.transtep.xdna.doc.projplan.docDirLocation}</value>
</property>
但spring 3.0 使用 annotation 的時候,x-bean.xml 有些 bean 就不需要再宣告了,如 @Controller
而是自動讓 spring 去 scan 某 package 找到的,如此一來就無法注入 value
在 spring 3.0.M3 時加入了 @Value 這一個方便的 annotation 讓我們可以重拾 value 注入。
用法:
@Value("${com.transtep.xdna.doc.projplan.docDirLocation}")
private String docDirLocation = "";
2009年8月9日 星期日
svn merge 合併 用法理解
svn merge 是用來合併 "其他" repos目錄的某段版本之間的 diff 到你指定的目錄(一般為 . )
假設 有 trunk/stable 和 branches/maintain 兩個目錄都是同一個專案的程式碼,
直接以範例來解釋:
一開始,在trunk下已經有一個穩定版本,但是在 ver 27 時發現一個 bug,
於是將 stable 以 svn copy 到 branches/maintain 並 commit 準備進行修正,此時,
ver 28 時 trunk/stable 和 branches/maintain 均為同一版本的程式碼。
maintain 開始修正 bug ...
在 bug 修正的過程中,一共 commit 了10個版本,並將 bug修正完成。
同時 stable 也有做一些新功能開發,但和 maintain 正在修正的 bug 無太大關聯。
此時 ver為 38,但 maintain 的程式碼和 stable 的程式碼,
已經有 28->38 之間 10個版本的落差,
為了將 maintain 做的修正 "補回" 到 trunk 中,我們要做 merge,首先 cd 到 stable 目錄下
執行 svn merge -r 28:38 ../../branches/maintain/ .
結果即是將 maintain 在版本 28->38 之間做的變更(diff) ,合併到目前的 stable 目錄下。
此階段也許會產生衝突,因為trunk也有可能和 maintain 在同一段程式碼有做修改。
解決衝突後,stable的版本就會是 maintain bug 修正 加 stable 新功能開發版本,
但是 "尚未 commit"。
再進行 stable 的 commit 後,stable 即是最新的版本。
假設 有 trunk/stable 和 branches/maintain 兩個目錄都是同一個專案的程式碼,
直接以範例來解釋:
一開始,在trunk下已經有一個穩定版本,但是在 ver 27 時發現一個 bug,
於是將 stable 以 svn copy 到 branches/maintain 並 commit 準備進行修正,此時,
ver 28 時 trunk/stable 和 branches/maintain 均為同一版本的程式碼。
maintain 開始修正 bug ...
在 bug 修正的過程中,一共 commit 了10個版本,並將 bug修正完成。
同時 stable 也有做一些新功能開發,但和 maintain 正在修正的 bug 無太大關聯。
此時 ver為 38,但 maintain 的程式碼和 stable 的程式碼,
已經有 28->38 之間 10個版本的落差,
為了將 maintain 做的修正 "補回" 到 trunk 中,我們要做 merge,首先 cd 到 stable 目錄下
執行 svn merge -r 28:38 ../../branches/maintain/ .
結果即是將 maintain 在版本 28->38 之間做的變更(diff) ,合併到目前的 stable 目錄下。
此階段也許會產生衝突,因為trunk也有可能和 maintain 在同一段程式碼有做修改。
解決衝突後,stable的版本就會是 maintain bug 修正 加 stable 新功能開發版本,
但是 "尚未 commit"。
再進行 stable 的 commit 後,stable 即是最新的版本。
2009年7月31日 星期五
java ee servlet response
HttpServletResponse 物件是用來傳回結果到 browser,有些方法常用的方法:
設定 mime type:以下為 open office 的 odt 文件的 mime type
res.setContentType("application/vnd.oasis.opendocument.text");
設定編碼:
res.setCharacterEncoding("utf-8");
設定元件檔名:
res.addHeader("Content-Disposition", "attachment; filename=project-plan-book.odt");
設定 mime type:以下為 open office 的 odt 文件的 mime type
res.setContentType("application/vnd.oasis.opendocument.text");
設定編碼:
res.setCharacterEncoding("utf-8");
設定元件檔名:
res.addHeader("Content-Disposition", "attachment; filename=project-plan-book.odt");
2009年7月22日 星期三
hql 結合 distinct 過瀘重復的查詢結果
有些情況下,會有查詢到重復物件的問題,
舉一個例子直接說明:
A -> B :1 -> 多
from A as a left join fetch a.b as b
由於A與B是一對多的關係,即許多個B可能以外鍵指向同一個A
以上的hql查詢結果會返回許多重覆的A物件,
假設某A有3個B指向他,則會返回3個某A物件。
這時可以透過distinct將重復的A物件去除,如下:
select distinct a from A as a left join fetch a.b as b
舉一個例子直接說明:
A -> B :1 -> 多
from A as a left join fetch a.b as b
由於A與B是一對多的關係,即許多個B可能以外鍵指向同一個A
以上的hql查詢結果會返回許多重覆的A物件,
假設某A有3個B指向他,則會返回3個某A物件。
這時可以透過distinct將重復的A物件去除,如下:
select distinct a from A as a left join fetch a.b as b
2009年7月6日 星期一
debian 簡易檔案加密解密 ccrypt
安裝:
sudo aptitude install ccrypt
加密:
ccencrypt target-file
Enter encryption key:
Enter encryption key: (repeat)
target-file -> 變成 target-file.cpt 檔案
解密:
ccdecrypt target-file.cpt
Enter decryption key:
target-file.cpt -> 變成 target-file 檔案
顯示加密檔的內容但不解密:
ccat target-file.cpt
Enter decryption key:
.....秘密的資料內容....#@$
target-file.cpt 維持不變。
sudo aptitude install ccrypt
加密:
ccencrypt target-file
Enter encryption key:
Enter encryption key: (repeat)
target-file -> 變成 target-file.cpt 檔案
解密:
ccdecrypt target-file.cpt
Enter decryption key:
target-file.cpt -> 變成 target-file 檔案
顯示加密檔的內容但不解密:
ccat target-file.cpt
Enter decryption key:
.....秘密的資料內容....#@$
target-file.cpt 維持不變。
2009年7月2日 星期四
使用JFreeChart畫甘特圖(gantt)範例
JFreeChart主要分為 JFreeChart 物件表示圖表 及 Dataset 物件表示資料
不同的圖表物由 ChartFactory 不同的 static 方法建立,而不同的圖表物件也需要不同的 Dataset
來儲存資料,如甘特圖的 Dataset 為 IntervalCategoryDataset :
/**
*主程式進入點
*/
public static void main(String[] args){
final IntervalCategoryDataset dataset = createFakeDataset();
final JFreeChart chart = createChart(dataset);
// 輸出圖表成png檔(如果是web servlet可以輸出到response.getOutputStream())
ChartUtilities.writeChartAsPNG(target.getOutputStream(), outputChart, 2000, 600);
}
/**
* 建立甘特圖資料
*
* @return The dataset.
*/
public IntervalCategoryDataset createDataset() {
final TaskSeries s1 = new TaskSeries("計劃");
s1.add(new Task("許功蓋中文測試", new SimpleTimePeriod(date(1, Calendar.APRIL, 2001), date(5, Calendar.APRIL, 2001))));
s1.add(new Task("Obtain Approval", new SimpleTimePeriod(date(9, Calendar.APRIL, 2001), date(9, Calendar.APRIL, 2001))));
s1.add(new Task("Requirements Analysis", new SimpleTimePeriod(date(10, Calendar.APRIL, 2001), date(5, Calendar.MAY, 2001))));
s1.add(new Task("Design Phase", new SimpleTimePeriod(date(6, Calendar.MAY, 2001), date(30, Calendar.MAY, 2001))));
s1.add(new Task("Design Signoff", new SimpleTimePeriod(date(2, Calendar.JUNE, 2001), date(2, Calendar.JUNE, 2001))));
s1.add(new Task("Alpha Implementation", new SimpleTimePeriod(date(3, Calendar.JUNE, 2001), date(31, Calendar.JULY, 2001))));
s1.add(new Task("Design Review", new SimpleTimePeriod(date(1, Calendar.AUGUST, 2001), date(8, Calendar.AUGUST, 2001))));
s1.add(new Task("Revised Design Signoff", new SimpleTimePeriod(date(10, Calendar.AUGUST, 2001), date(10, Calendar.AUGUST, 2001))));
s1.add(new Task("Beta Implementation", new SimpleTimePeriod(date(12, Calendar.AUGUST, 2001), date(12, Calendar.SEPTEMBER, 2001))));
s1.add(new Task("Testing", new SimpleTimePeriod(date(13, Calendar.SEPTEMBER, 2001), date(31, Calendar.OCTOBER, 2001))));
s1.add(new Task("Final Implementation", new SimpleTimePeriod(date(1, Calendar.NOVEMBER, 2001), date(15, Calendar.NOVEMBER, 2001))));
s1.add(new Task("Signoff", new SimpleTimePeriod(date(28, Calendar.NOVEMBER, 2001), date(30, Calendar.NOVEMBER, 2001))));
final TaskSeries s2 = new TaskSeries("實際");
s2.add(new Task("許功蓋中文測試", new SimpleTimePeriod(date(1, Calendar.APRIL, 2001), date(5, Calendar.APRIL, 2001))));
s2.add(new Task("Obtain Approval", new SimpleTimePeriod(date(9, Calendar.APRIL, 2001), date(9, Calendar.APRIL, 2001))));
s2.add(new Task("Requirements Analysis", new SimpleTimePeriod(date(10, Calendar.APRIL, 2001), date(15, Calendar.MAY, 2001))));
s2.add(new Task("Design Phase", new SimpleTimePeriod(date(15, Calendar.MAY, 2001), date(17, Calendar.JUNE, 2001))));
s2.add(new Task("Design Signoff", new SimpleTimePeriod(date(30, Calendar.JUNE, 2001), date(30, Calendar.JUNE, 2001))));
s2.add(new Task("Alpha Implementation", new SimpleTimePeriod(date(1, Calendar.JULY, 2001), date(12, Calendar.SEPTEMBER, 2001))));
s2.add(new Task("Design Review", new SimpleTimePeriod(date(12, Calendar.SEPTEMBER, 2001), date(22, Calendar.SEPTEMBER, 2001))));
s2.add(new Task("Revised Design Signoff", new SimpleTimePeriod(date(25, Calendar.SEPTEMBER, 2001), date(27, Calendar.SEPTEMBER, 2001))));
s2.add(new Task("Beta Implementation", new SimpleTimePeriod(date(27, Calendar.SEPTEMBER, 2001), date(30, Calendar.OCTOBER, 2001))));
s2.add(new Task("Testing", new SimpleTimePeriod(date(31, Calendar.OCTOBER, 2001), date(17, Calendar.NOVEMBER, 2001))));
s2.add(new Task("Final Implementation", new SimpleTimePeriod(date(18, Calendar.NOVEMBER, 2001), date(5, Calendar.DECEMBER, 2001))));
s2.add(new Task("Signoff", new SimpleTimePeriod(date(10, Calendar.DECEMBER, 2001), date(11, Calendar.DECEMBER, 2001))));
final TaskSeriesCollection collection = new TaskSeriesCollection();
collection.add(s1);
collection.add(s2);
return collection;
}
/**
* 方便建立日期
*
* @param day
* the date.
* @param month
* the month.
* @param year
* the year.
*
* @return a date.
*/
public Date date(final int day, final int month, final int year) {
Calendar calendar = Calendar.getInstance();
calendar.set(year, month, day);
Date result = calendar.getTime();
return result;
}
/**
* 產生甘特圖物件
*
* @param dataset
* the dataset.
*
* @return The chart.
*/
public JFreeChart createChart(final IntervalCategoryDataset dataset) {
final JFreeChart chart = ChartFactory.createGanttChart("測試甘特圖 Demo", // chart title
"事件", // domain axis label
"日期", // range axis label
dataset, // data
true, // include legend
true, // tooltips
false // urls
);
//設定各處的字型(需設定為支援中文的字型,才不會造成中文亂碼)
Font font = new Font("標楷體", Font.BOLD, 16);
chart.getLegend().setItemFont(font);
chart.getTitle().setFont(font);
chart.getCategoryPlot().getDomainAxis().setLabelFont(font);
chart.getCategoryPlot().getDomainAxis().setTickLabelFont(font);
chart.getCategoryPlot().getRangeAxis().setLabelFont(font);
chart.getCategoryPlot().getRangeAxis().setTickLabelFont(font);
return chart;
}
結果如下(web)
不同的圖表物由 ChartFactory 不同的 static 方法建立,而不同的圖表物件也需要不同的 Dataset
來儲存資料,如甘特圖的 Dataset 為 IntervalCategoryDataset :
/**
*主程式進入點
*/
public static void main(String[] args){
final IntervalCategoryDataset dataset = createFakeDataset();
final JFreeChart chart = createChart(dataset);
// 輸出圖表成png檔(如果是web servlet可以輸出到response.getOutputStream())
ChartUtilities.writeChartAsPNG(target.getOutputStream(), outputChart, 2000, 600);
}
/**
* 建立甘特圖資料
*
* @return The dataset.
*/
public IntervalCategoryDataset createDataset() {
final TaskSeries s1 = new TaskSeries("計劃");
s1.add(new Task("許功蓋中文測試", new SimpleTimePeriod(date(1, Calendar.APRIL, 2001), date(5, Calendar.APRIL, 2001))));
s1.add(new Task("Obtain Approval", new SimpleTimePeriod(date(9, Calendar.APRIL, 2001), date(9, Calendar.APRIL, 2001))));
s1.add(new Task("Requirements Analysis", new SimpleTimePeriod(date(10, Calendar.APRIL, 2001), date(5, Calendar.MAY, 2001))));
s1.add(new Task("Design Phase", new SimpleTimePeriod(date(6, Calendar.MAY, 2001), date(30, Calendar.MAY, 2001))));
s1.add(new Task("Design Signoff", new SimpleTimePeriod(date(2, Calendar.JUNE, 2001), date(2, Calendar.JUNE, 2001))));
s1.add(new Task("Alpha Implementation", new SimpleTimePeriod(date(3, Calendar.JUNE, 2001), date(31, Calendar.JULY, 2001))));
s1.add(new Task("Design Review", new SimpleTimePeriod(date(1, Calendar.AUGUST, 2001), date(8, Calendar.AUGUST, 2001))));
s1.add(new Task("Revised Design Signoff", new SimpleTimePeriod(date(10, Calendar.AUGUST, 2001), date(10, Calendar.AUGUST, 2001))));
s1.add(new Task("Beta Implementation", new SimpleTimePeriod(date(12, Calendar.AUGUST, 2001), date(12, Calendar.SEPTEMBER, 2001))));
s1.add(new Task("Testing", new SimpleTimePeriod(date(13, Calendar.SEPTEMBER, 2001), date(31, Calendar.OCTOBER, 2001))));
s1.add(new Task("Final Implementation", new SimpleTimePeriod(date(1, Calendar.NOVEMBER, 2001), date(15, Calendar.NOVEMBER, 2001))));
s1.add(new Task("Signoff", new SimpleTimePeriod(date(28, Calendar.NOVEMBER, 2001), date(30, Calendar.NOVEMBER, 2001))));
final TaskSeries s2 = new TaskSeries("實際");
s2.add(new Task("許功蓋中文測試", new SimpleTimePeriod(date(1, Calendar.APRIL, 2001), date(5, Calendar.APRIL, 2001))));
s2.add(new Task("Obtain Approval", new SimpleTimePeriod(date(9, Calendar.APRIL, 2001), date(9, Calendar.APRIL, 2001))));
s2.add(new Task("Requirements Analysis", new SimpleTimePeriod(date(10, Calendar.APRIL, 2001), date(15, Calendar.MAY, 2001))));
s2.add(new Task("Design Phase", new SimpleTimePeriod(date(15, Calendar.MAY, 2001), date(17, Calendar.JUNE, 2001))));
s2.add(new Task("Design Signoff", new SimpleTimePeriod(date(30, Calendar.JUNE, 2001), date(30, Calendar.JUNE, 2001))));
s2.add(new Task("Alpha Implementation", new SimpleTimePeriod(date(1, Calendar.JULY, 2001), date(12, Calendar.SEPTEMBER, 2001))));
s2.add(new Task("Design Review", new SimpleTimePeriod(date(12, Calendar.SEPTEMBER, 2001), date(22, Calendar.SEPTEMBER, 2001))));
s2.add(new Task("Revised Design Signoff", new SimpleTimePeriod(date(25, Calendar.SEPTEMBER, 2001), date(27, Calendar.SEPTEMBER, 2001))));
s2.add(new Task("Beta Implementation", new SimpleTimePeriod(date(27, Calendar.SEPTEMBER, 2001), date(30, Calendar.OCTOBER, 2001))));
s2.add(new Task("Testing", new SimpleTimePeriod(date(31, Calendar.OCTOBER, 2001), date(17, Calendar.NOVEMBER, 2001))));
s2.add(new Task("Final Implementation", new SimpleTimePeriod(date(18, Calendar.NOVEMBER, 2001), date(5, Calendar.DECEMBER, 2001))));
s2.add(new Task("Signoff", new SimpleTimePeriod(date(10, Calendar.DECEMBER, 2001), date(11, Calendar.DECEMBER, 2001))));
final TaskSeriesCollection collection = new TaskSeriesCollection();
collection.add(s1);
collection.add(s2);
return collection;
}
/**
* 方便建立日期
*
* @param day
* the date.
* @param month
* the month.
* @param year
* the year.
*
* @return a date.
*/
public Date date(final int day, final int month, final int year) {
Calendar calendar = Calendar.getInstance();
calendar.set(year, month, day);
Date result = calendar.getTime();
return result;
}
/**
* 產生甘特圖物件
*
* @param dataset
* the dataset.
*
* @return The chart.
*/
public JFreeChart createChart(final IntervalCategoryDataset dataset) {
final JFreeChart chart = ChartFactory.createGanttChart("測試甘特圖 Demo", // chart title
"事件", // domain axis label
"日期", // range axis label
dataset, // data
true, // include legend
true, // tooltips
false // urls
);
//設定各處的字型(需設定為支援中文的字型,才不會造成中文亂碼)
Font font = new Font("標楷體", Font.BOLD, 16);
chart.getLegend().setItemFont(font);
chart.getTitle().setFont(font);
chart.getCategoryPlot().getDomainAxis().setLabelFont(font);
chart.getCategoryPlot().getDomainAxis().setTickLabelFont(font);
chart.getCategoryPlot().getRangeAxis().setLabelFont(font);
chart.getCategoryPlot().getRangeAxis().setTickLabelFont(font);
return chart;
}
結果如下(web)
訂閱:
文章 (Atom)



