發表文章

目前顯示的是 九月, 2011的文章

用 Chrome console 從鎖右鍵的網站中取得文字

遇到鎖右鍵的網站時, 複製文字變得有點麻煩, 要檢視原始碼再去掉 tag。剛從 Shakalaca 那看到《Become a Javascript Console Power-User》, 學到不錯的方式, 比較省事地取出文字: 按 F12 開 Chrome console 點 Elements 選放大鏡 選取要的段落 (html node) 在 console 裡打 copy($0.innerText) 這樣就複製好了, 只剩貼到文字編輯器裡去掉不要的部份即可。

C 的型別宣告

直到看了 Dan Saks 的 const T vs T const, 才(比較)明白 C 的型別宣告, 知道 int const *a 和 int * const a 的差別。原本雖然知道 int (*f[10])(int )、int (*f)(int) 和 int *f(int) 的差別, 但沒有很清楚細部原因, 看了這篇後才懂得更徹底。 C 的宣告分幾個部份, 以 static unsigned long int *x[N] 來說, *x[N] 是 declarator, 剩下的是 declaration specifier。declarator 的部份用運算子優先順序來解讀, 語意清楚許多。即 () 最優先, 其次為 [], 再來為 *。所以: int (*f)(float) 表示 f 是函式指標, 指向一個函式其傳回值為 int, 參數為 float int *f(float) 表示 f 是函式, 傳回 int*, 參數為 float int (*f[10])(float) 表示 f 是一個陣列, 每個元素是一函式指標 令人混淆的部份在於, declaration specifier 的順序其實沒有影響。所以, static unsigned int n 和 int unsigned static n 是一樣的。再加上 const 和 volatile 不同於其它 declaration specifier, 它們可以同時寫在 declarator, 於是產生不易理解的結果。 我還在參透 volatile 的效果, 這裡先以 const 為例: int const n 和 const int n 都表示 n 是指向唯讀的 int int const *n 表示 n 是指標, 指標指向的型別為唯讀的 int int * const n 表示 n 是唯讀的指標, 指向 int int const * const n 表示 n 是唯讀的指標, 且 n 指向唯讀的 int 簡單的判別方式是以 * 為分界點, 由右往左看, 包含 * 的右邊是 declarator, 表示 declarator 的型別, 所以這裡有 const 表示是唯讀的指標; * 的左邊是 declaration specifier, 這裡有 const 表示指到的型別為唯讀。附帶一提,…

用 LD_PRELOAD 替換動態連結的函式庫

換掉動態連結的函式庫有不少用途, 比方說像 Scott 提的「用來驗證是否執行到特定函式」, 或如 jserv 提的「在沒有原始碼的情況下修補執行檔的行為」。最近又看到這個東西, 記一下筆記以免忘了。 來看程式碼和執行效果。 mylib.c#include <stddef.h> #include <stdio.h> int putchar(int c) { printf("call putchar()\n"); return c; } void *memset(void *s, int c, size_t n) { printf("call memset()\n"); return s; } main.c#include <string.h> #include <stdio.h> int main(void) { char s[10]; memset(s, 0, 0); putchar('X'); putchar('\n'); return 0; } 執行結果$ gcc -Wall -fpic -shared -o libmylib.so mylib.c $ gcc -o main main.c # 沒用 LD_PRELOAD 的結果 $ ./main X # 用 LD_PRELOAD 後的結果, 記得加 "./", 不然會找不到 libmylib.so $ LD_PRELOAD=./libmylib.so ./main call putchar() call putchar() $ strings main | grep memset 可以看出 putchar 有被換成自己編的版本, 但 memset 沒有。用 strings 查看 binary 檔 main 會發覺並沒有呼叫 memset 的跡象。猜測是 compiler 發覺 memset 實際上沒任何作用, 所以沒呼叫。 修改 main.c, 將 memset(s, 0, 0) 換成 memset(s, 0, 1) 再來看看:$ gcc -o main main.c $ strings…

安裝 PythonWebkit

偶然看到 PythonWebkit 這個專案, 作者花了兩週左右的時間寫好 WebKit 的 python 介面, 於是操作 DOM 不再是 javascript 的專利, 透過 PythonWebkit 就能用 python 操作 DOM。作者自稱除一些小功能外, 這個專案已到可用的階段:The current status is that the SVG 2D Canvas element is not available, and CSS Styles have to be modified through the style.setProperty function (rather than being accessible as python properties). Other than these gotchas, the Python Webkit bindings are in a useable state, providing full W3C compliant access to the full set of DOM functionality (except SVG Canvas) as provided by Webkit, and ordinarily only accessible via javascript. 不過相關文件超少, 花了些時間才裝成功, 也增加了一些編原始碼的功力。 背景介紹WebKit歷史很有意思, 有興趣的人自行參照連結。在 Linux 上目前有兩種 port, 一個是用 GTK+ 實作的WebKitGTK+, 另一個是 QT 的實作版本。 PyWebKitGtk 是另外一個基於 WebKitGTK+ 的專案, 透過 WebKit 提供的 gobject binding 提供 python 介面, 但沒有提供直接操作 DOM 的功能。雖然有些補救方案, PythonWebkit 的作者覺得直接改出 python 介面比較省事, 效率也較好, 該頁有寫詳細的設計考量。所以, PythonWebkit 是以 WebKitGTK+ 為底, 修改部份內容直接提供 python 的 DOM API。 剛開始作者用 PyWebKitGtk 的 python module "webkit",…

HTML DOM 筆記

有了 pythonwebkit 後, 可以用 python 直接存取 DOM。於是得自己學一下 DOM 的操作方式, 不能再依賴 jQuery 啦。 花個半小時邊看邊操作 《HTML DOM Tutorial》, 很快就有個基本概念了。記一下自己不熟的部份: DOM 的 node 類型有: document, element, text, attribute, comment element node 沒有包含文字, 要從它的 text node 拿: document.getElementsByTagName('p')[0].nodeValue # null document.getElementsByTagName('p')[0].firstChild.nodeValue # the expected texts 操作 iframe 的內容 取得 iframe 的 DOM: d = document.getElementsByTagName('iframe')[0].contentDocument 接著就能用一樣的 DOM API 操作 d 我只有在 Chrome 下試, 畢竟 pythonwebkit 的功能應該和 Chrome 差不多才對。要跨瀏覽器操作 DOM 的話, 得多試幾種變數, 取出 iframe 的 DOM

vim 停住一會兒才啟動的解法

有時用 putty 連到 server, 打 vi 後會停一兩秒才進去。有時在 screen 下甚至會停住不動。參考這篇的說法, 用 vi -X 不要連線到 X Server 就 ok 了。 會有這樣的問題, 是因為我用到 gnome 版的 vim (vim.gnome):$ which vi /usr/bin/vi $ ll /usr/bin/vi lrwxrwxrwx 1 root root 20 2010-05-12 12:17 /usr/bin/vi -> /etc/alternatives/vi* $ ll /etc/alternatives/vi lrwxrwxrwx 1 root root 18 2010-08-06 13:58 /etc/alternatives/vi -> /usr/bin/vim.gnome* $ ll /usr/bin/vim.gnome -rwxr-xr-x 1 root root 2144568 2009-01-08 11:03 /usr/bin/vim.gnome* 若用 vim.tiny 或 vim.basic, 不加 -X 也不會停一會兒。 相關除錯指令: 用 vi -V 會看到「讀取 viminfo 檔案 "/home/fcamel/.viminfo" 訊息開啟 X Window 失敗」 (Reading viminfo file "/home/fcamel/.viminfo" info oldfilesOpening the X display failed) 在 X Window 下無此問題

安裝完 Ubuntu 後的初步設定

2017-04-04 更新記一下個人裝 Ubuntu 後, 會做的基本設定。 sudo apt-get install aptitude sudo aptitude update sudo aptitude install build-essential apt-file checkinstall manpages-dev htop rsync screen cdargs openssh-server mosh vim git subversion exuberant-ctags cscope python-dev python-setuptools id-utils python-pip sudo apt-file update git clone git://github.com/fcamel/configs.git cd configs && ./install.sh # 裝我個人用的設定檔, 如 vim, bash, screen 若需要裝 java, 另外需做: sudo aptitude install python-software-propertiessudo add-apt-repository "deb http://archive.canonical.com/ natty partner"sudo aptitude updatesudo aptitude install sun-java6-jdk若是用 Parallel 的話,裝完 Parallel 附的 Ubuntu 後要作的事:修改網路:Actions -> Configure -> Hardware -> Network -> 選 Ethernet,這樣會自己有獨立的 LAN IP新增硬碟空間:在關閉 OS 的情況下,Actions -> COnfigure -> Hardware -> Hard Disk 1 -> Edit,然後調整大小。作完後重開 VM。再用 gparted 動態調大 partition 大小。需要先刪掉 swap, 再刪 extended partition,才有空間調 root partition。 日後想到什麼再補。

Ubuntu 用 UUID 掛載硬碟的原因

之前看 Ubuntu 的 fstab 改用 UUID 覺得很納悶, 為啥要在 /dev/disk/by-uuid/ 下建 soft link 再指到 /dev/sdXN (X 是 abcd, N 是 1-8), 然後在 fstab 裡用 UUID 而不用 /dev/sdXN。 今天用 VirtualBox 移除硬碟後才發覺它的好處: 加裝或移除硬碟後, 雖然 /dev/sdXN 的 X 會變 (如移掉第二顆硬碟, /dev/sdc3 會變 /dev/sdb3), UUID 卻不會變。所以若 /etc/fstab 用 UUID 來掛載 partition, 可以直接開機, 而省掉進單人模式改 /etc/fstab 的步驟。

tab vs. space

討論 coding style 時, 這個常會戰到爆。記一下在多人一起開發一陣子軟體後的心得。 我後來覺得 space 比較方便, 因為可確保任何地方看到的畫面一致, 且不需另外設定。支援 tab 的人認為只需要一次設定就可以了, 這樣可保留彈性。困難的地方在於有太多地方可能會看到程式碼: IDE、editor、VCS log、issue tracking、e-mail、其它可能的 web-based 工具 (如 code review)。而有些地方無法提供客制化設定 tab 寬度 (如 e-mail)。 以我自己用 Java 來說, 平時可能用 Eclipse, 特定需求時用 vim, 偶而要用 hgtk 看別人的 commit (一些程式碼的 diff), 或用 hg blame 看修改記錄 (輸出到 console 或用 hgtk 看), 偶而寄 code diff 給別人討論。在這些過程中, 會發覺 tab 實在是不太方便。 至於 space 的缺點: 一但定了就很難改, 實務上不是問題, 各個語言都有標準規範 (大概都是四個空白), 照著公定規範做就是了。若不幸地原本已有一大堆其它長度, 讀個一陣也會習慣, 應該會比在不同地方, 縮排亂掉來得好。

MySQL vs. PostgreSQL

去年的隨手心得, 記在這備忘。主要是參考《MySQL vs PostgreSQL - WikiVS》 2010-09 的版本, 後來情況應該也有些變化。另外, 很多東西還是要自己測過才準, 後來和一些很熟 DB 的前輩聊, 發覺實際情況還是和看到的有些出入。需求不同, 又有太多細節可以調整了。 後來覺得選用 MySQL 的好處是: 資源最豐富, 有書有文件, 也有一堆顧問公司 (如 Percona) 有許多大公司實際執行到海量的實例, 不用擔心會流量會卡住 (雖說大部份時候應該要先擔心服務不夠好, 流量太小) 有些 syntax sugar 或特制功能很好用, 像是 insert ... on duplicate update , 或 insert ignore 有趣的是, 該文認為 MySQL 比 PostgreSQL 流行的原因之一, 是因為 PostgreSQL 沒法限制各個 database 的大小, 對於商用服務來說, 這點很重要 (商用服務會在意限制資源、管理權限等, open source 專案先以個人需求為主, 一開始大概都不會重視這些吧)備忘 fcamel 2010-09-01 19:54:43 MySQL vs. PostgreSQL, 有這種對照文真不錯, 書上有看過的相關觀念可以重新消化一次, 之前沒看過的....在這也有看沒感覺 MySQL vs PostgreSQL - WikiVS MySQL vs PostgreSQLFrom WikiVS, the open comparison websiteJump to: navigation, search MySQL Postgr 發表回應 1 fcamel 2010-09-01 19:55:43 PostgreSQL 只有一個 engine, 一般來說在大量同時寫入下會比 MySQL 搭各種 engine 快 2 fcamel 2010-09-01 19:56:36 PostgreSQL 比較穩, RDBMS 功能較齊全, 這點在 stackoverflow 上可找出一卡車支持者。也可找出一卡車 MySQL 使用者說他們遇到 DB 炸了多少次 3 fcamel 2010-09-01 19:57:24 MySQL + MyISAM 有無敵快的 count, 因為它沒 MVCC, …

讓 mysql 使用 utf-8 的相關設定

這對於新手來說應該很有幫助吧 在 [mysqld] 下的相關設定:character-set-server=utf8 collation-server=utf8_general_ci init-connect='SET NAMES utf8' MySQL 的設定檔位置不太好找, 細節參考《fcamel 技術隨手記: 更改 mysql conf 的注意事項》

warm up server 的一般作法

一開始用 MySQL 的 MyISAM 時, 發覺有語法可以事先載入整個 index, 就以為大部份 server 應該有提供這功能。不過後來發覺 InnoDB 沒有, 所以要自己下 SELECT 掃一次 table, 讓 MySQL 自動觸發 cache 機制。後來用 Solr, 查了一陣子, 似乎也沒有這種機制。大概設計 server 的人覺得另外設計語法會增加維護成本, 不如讓大家自己查詢全部要用的資料, 讓 server 自己管好 cache 比較實際吧。

mysql flush key cache

MyISAM 的 index 會暫存到 key cache 裡, 若想預先載入整個 table 的 indexes 到 key cache 裡, 可以用 LOAD INDEX INTO CACHE。但若要 flush key cache 的話, 並沒有像 flush query cache 那樣有 RESET QUERY CACHE 的語法。替代作法是, 改變 key cache 的大小或 block size, MySQL 就會重設 key cache。

使用 ReviewBoard API 刪掉多個 request

ReviewBoard 沒有提供批次刪掉的介面, 測試期間產生一堆 request, 懶得用手一個個刪, 想說用 API 來刪。 使用 ReviewBoardweb api, 需要在連線中的 http header 加上 cookie 資訊用作身份認證。用 python 的 httplib2 做這事也不會太麻煩, 不過若能用 command line 解決, 會更簡單一些。後來我用 curl 做這事, 順便熟悉一下它的功能, 常看文件用 curl 示範 API 用法。 參考《Use CURL to Login to Websites with a Script》的教學, 學會 curl 登入網頁的用法。依我的需求消化後的步驟如下: 用 FireBug 之類的工具找出 login form 需要的欄位。 連到 web server 產生 coolkie: curl --cookie-jar cjar http://myhost/account/login/ 送出 username/password 登入, 並更新 cookie (存到 cjar 裡): curl --cookie cjar --cookie-jar cjar http://myhost/account/login/ --data 'username=fcamel' --data 'password=xxxx' 使用 FireBug 觀察 ReviewBoard 刪除 request 時連的網址 (或是看 web api 文件) 執行指令砍掉編號 1 ~ 10 的 request: for i in {1..10}; do curl --cookie cjar --cookie-jar cjar http://myhost/api/json/reviewrequests/$i/close/discarded/; done備註: 砍 request 要用 http://myhost/api/json/reviewrequests/$i/delete/, 但要有 admin 權限

在同一個 apache 裡跑兩個 port

使用 apache2 + mod_wsgi 的作法架 ReviewBoard 的話, relative path 有 bug, 無法將 ReviewBoard 架在 http://.../reviews/ 這樣的位置。網路上搜搜看到也有人提到同樣的問題。自己試著硬解了一陣子, 沒有很乾淨又一致正確的結果。後來想說, 乾脆在同一台機器的 apache 裡跑聽兩個 port 好了, 這樣就能在用專屬非 80 的 port 來架 ReviewBoard。 查了一下, 架法還滿簡單的: 見 VirtualHost Examples, 另外 CommonMisconfigurations - Httpd Wiki 也滿有幫助的。使用多個 port 時, 記得要加 listen。Ubuntu 的話是加在 /etc/apache2/ports.conf 裡, 它會被 /etc/apache2/apache2.conf include 進去。