年末なのでEmacsの設定ファイルを見直しますよ
年末ですね
大掃除の季節なので、普段使っているEmacsの設定ファイルを整理してみました。 ついでに前から気に入らなかった部分を直したり、便利そうなものを追加したので、いくつかピックアップして書いておきます。
全体の設定ファイルはGitHubに置いてあります。
設定ファイルを分割してinit-loader.elで読み込み
今までは.emacs.elに設定を全部書いていたのですが、いい加減見通しが悪くなってきたので分割することに。
分割したファイルの読み込みのため、指定したディレクトリ内にある設定ファイルを読み込んでくれる便利ツール init-loader.el(オリジナルに改良を加えたもの) を導入しました。 エラーがあったファイルは無視して他のファイルの設定を続行してくれるのが素敵です。
デフォルトでは起動時にログバッファが表示されてエラーなどの状況がわかるようになっているのですが、毎回表示されるのはさすがにアレなので、エラーがあったときだけ表示するようにしています。
(require 'init-loader) (setq init-loader-show-log-after-init nil) ; 起動時のログバッファを表示しない (init-loader-load "~/.emacs.d/config") (if (not (equal (init-loader-error-log) "")) ; エラーがあったときだけログバッファを表示 (init-loader-show-log))
package.elでパッケージ管理
Emacs 24から標準搭載されたパッケージ管理システム package.el を使うようにしました。 GNUのだけだとパッケージが少ないのでMELPAとMarmaladeのリポジトリを追加しているのですが、それでも微妙に欲しいパッケージが無かったりするので、そういうのは手動で。
(require 'package) (add-to-list 'package-archives '("melpa" . "http://melpa.milkbox.net/packages/")) (add-to-list 'package-archives '("marmalade" . "http://marmalade-repo.org/packages/"))
tabbar.elでタブエディタ化
前からEmacsにもタブが欲しいと思っていたので、この機会に tabbar.el でタブをつけてみました。 さすがにバッファ全部がタブで表示されると邪魔なので、*scratch*バッファ以外の * で始まるバッファはタブに表示しないように設定しています。
(require 'tabbar) (tabbar-mode 1) (defun my-tabbar-buffer-list () (delq nil (mapcar #'(lambda (b) (cond ;; Always include the current buffer. ((eq (current-buffer) b) b) ((buffer-file-name b) b) ((char-equal ?\ (aref (buffer-name b) 0)) nil) ((equal "*scratch*" (buffer-name b)) b) ; *scratch*バッファは表示する ((char-equal ?* (aref (buffer-name b) 0)) nil) ; それ以外の * で始まるバッファは表示しない ((buffer-live-p b) b))) (buffer-list)))) (setq tabbar-buffer-list-function 'my-tabbar-buffer-list)
まとめ
そんなわけで、Emacsの設定ファイルを整理しました。
JavaScriptでK-means法してみた
集合知プログラミング勉強会でK-means法を勉強したので
復習とJavaScriptの練習を兼ねて、クラスタリングの定番アルゴリズム「K-means法」をビジュアライズしてみた - てっく煮ブログのJavaScript版を作ってみました。
K-Means clustering Visualiser - jsdo.it
PointsとKの値を適当に変えて[Initialize]ボタンを押した後、[Step]ボタンを押すと各クラスタが更新されていきます。 Firefox 16とChrome 22あたりなら動くはず。
ソースコードはGitHubに置いてあります。 ser1zw/k-means-visualiser-js
PythonでOpenCVを使おうとして ImportError: No module named cv って言われたら
環境
なにごと?
Pythonを覚えたら、やっぱりOpenCVやりたくなるじゃないですか。
で、おもむろにOpenCVを BUILD_PYTHON_SUPPORT=ON
にしてインストールし、意気揚々とPythonを起動して
import cv
ってやるじゃないですか。
>>> import cv Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: No module named cv
エラーになるじゃないですか。
なんでかなーと思ってPythonのモジュールのパスを調べてみると
>>> import sys >>> print sys.path ['', '/usr/local/lib/python2.7/dist-packages/ipython-0.13.1-py2.7.egg', (以下略)]
OpenCVのPythonモジュールのパスが含まれてなさそうです。
OpenCVのPythonモジュールは、OpenCVをインストールしたディレクトリ配下の lib/python2.7/dist-packages
にあるので、
このディレクトリを sys.path
に追加してみます。
>>> import sys >>> sys.path.append("/path/to/opencv/lib/python2.7/dist-packages") >>> import cv >>> cv.LoadImage("lenna.png") <iplimage(nChannels=3 width=512 height=480 widthStep=1536 )> >>>
どうやらできたっぽいですね。
OpenCVのモジュールを使うたびに毎回これをやるのは面倒なので、$PYTHONPATH
にパスを追加しておきましょう。
.zshrcとかに
export PYTHONPATH=/path/to/opencv/lib/python2.7/dist-packages:$PYTHONPATH
って書いておけばよいです。
参考
tmuxinatorのzsh用補完関数
tmuxinatorというのは
tmuxinator とは
tmuxinatorとは、tmuxで起動するセッションを予め定義しておき、コマンド一発でそのセッションを起動できるようにしたものです。ちなみに、screenで同じことをするscreeninatorというツールもあります。こちらが先に開発されたようです。
tmuxinatorで一瞬で開発環境を起動する #Ruby #開発環境 #AdventCalendar #tmux - Qiita
コマンド1発で、tmuxでいつも使っているセッションが開けるようになる便利ツールです。
このコマンドのzsh用補完関数をだいぶ前に作ってあったので、貼っておきます*1。FIXMEとか書いてあるけど気にしない。
zsh completion for tmuxinator — Gist
インストール
まず補完関数用のディレクトリを作って
$ mkdir -p ~/.tmuxinator/completion
gistからファイルを取ってきて入れておきます。
$ wget https://raw.github.com/gist/2242920/c8cd399ec3ae2579cd103206e89d495a27862a05/_tmuxinator $ mv _tmuxinator ~/.tmuxinator/completion
最後に、.zshrcに以下のように追記すれば完了です。
fpath=($HOME/.tmuxinator/completion ${fpath}) autoload -U compinit compinit
使い方
$ mux [TAB]
とやれば、コマンドの候補が出てくるようになります。
$ mux start [TAB]
とかやれば、候補のプロジェクトがずらっと出てきます。
tmuxinator、結構便利なので、みんな使うとよいですよ。
OracleでTwitterのタイムラインをSELECTする
- FDWってなによ?
- FDW(Foreign Data Wrappe),外部データラッパっていうやつで、SQL/MED(Management of External Data)の規格の一つで簡単にいうと、PostgreSQLにQUERYを発行したら、あら不思議、外部の(たとえばMySQLとかCSV)データが取得できるという変態機能。 twitterAPIに変更あるらしいから今後はわからにけど、twitterのデータを取ってくるとかもできる。というかラッパーが用意されてる。(ちなみに使ってみたら楽しかったw)
それはワクテカ過ぎる... だがしかし SQLite3 でも出来る!きっと出来る!
Oracleでもきっとできる!というかできた!
ser1zw/twitter-public-timeline-for-oracle
ご家庭のOracleで、いつでも新鮮なPublic timelineがお楽しみいただけます!
環境
ソースコード
GitHubに置いてあります。 ser1zw/twitter-public-timeline-for-oracle
インストールには、後述の
を行ったあと、SQL*Plusで同梱のinstall.sqlを実行してください。
$ sqlplus YOUR-USER-NAME/YOUR-PASSWORD@localhost:1521/XE @install.sql
インストールすると、TWITTER_PUBLIC_TIMELINEというビューが作成されます。これをSELECT
すれば、Public timelineが取得できます。
SELECT created_at, screen_name, text FROM TWITTER_PUBLIC_TIMELINE WHERE LOWER(text) LIKE '%http%';
アンインストールには、同梱のuninstall.sqlを実行してください。
仕組み
- PL/SQLのHTTP機能でTwitterのPublic timeline APIからXMLデータを取ってくる
- 取ってきたXMLデータをOracleのXML処理機能でリレーショナルデータにマッピングする
- 処理したデータをテーブル・ファンクション(表関数)で返す
という感じで処理をしています。
以下、それぞれどんな感じなのかざっくり解説!
PL/SQLのHTTP機能
OracleのPL/SQLでは、UTL_HTTPパッケージの機能を使うことで、HTTPアクセスができます。
TwitterのPublic timelineからGETするのはこんな感じです。
DECLARE url VARCHAR2(100) := 'http://api.twitter.com/1/statuses/public_timeline.xml'; request UTL_HTTP.REQ; response UTL_HTTP.RESP; buff VARCHAR2(4000); BEGIN UTL_HTTP.SET_RESPONSE_ERROR_CHECK(FALSE); request := UTL_HTTP.BEGIN_REQUEST(url, 'GET'); UTL_HTTP.SET_HEADER(request, 'User-Agent', 'Mozilla/4.0'); response := UTL_HTTP.GET_RESPONSE(request); IF response.status_code = 200 THEN BEGIN LOOP UTL_HTTP.READ_TEXT(response, buff, LENGTH(buff)); DBMS_OUTPUT.PUT_LINE(buff); END LOOP; UTL_HTTP.END_RESPONSE(response); EXCEPTION WHEN UTL_HTTP.END_OF_BODY THEN UTL_HTTP.END_RESPONSE(response); END; ELSE UTL_HTTP.END_RESPONSE(response); DBMS_OUTPUT.PUT_LINE('Fail: STATUS CODE: ' || response.status_code); END IF; END;
ただし、使用するにはちょっとだけ準備が必要です。
utlhttp.sql を実行してUTL_HTTPパッケージをセットアップ
スクリプトを実行するだけです。 $ORACLE_HOME/rdbms/admin に utlhttp.sql というスクリプトがあるので、SQL*Plusなどで実行します。 Oracleが動いているサーバでこんな感じのコマンドをたたけばOKです(パスワードやSIDは必要に応じて変更してください)。
$ cd $ORACLE_HOME/rdbms/admin $ sqlplus SYS/YOUR-PASSWORD@localhost:1521/XE AS SYSDBA @utlhttp.sql
ネットワークのアクセス制御リスト(ACL)の設定
11gから外部ネットワークへのアクセスの際にアクセス制御が行われるようになり、アクセスするユーザやホストを設定しなければならなくなりました。 ユーザ SCOTT が ホスト api.twitter.com にアクセスできるようにするには、こんな感じで設定すればOKです。
DECLARE user VARCHAR2(30) := 'SCOTT'; BEGIN DBMS_NETWORK_ACL_ADMIN.CREATE_ACL('www.xml', 'WWW ACL', user, TRUE, 'connect'); DBMS_NETWORK_ACL_ADMIN.ADD_PRIVILEGE('www.xml', user, TRUE, 'resolve'); DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL('www.xml', 'api.twitter.com'); END;
ちなみに、最後のアクセス制御リストへの追加を
DBMS_NETWORK_ACL_ADMIN.ASSIGN_ACL('www.xml', '*');
にすれば、どこでもアクセスできるようになります。
XML処理機能
Oracle XML DBの機能を使うと、XMLデータをリレーショナルデータとして(テーブルに入ったデータと同じような感じで)扱えます。
今回はPublic timelineのXMLデータから各ツイートをとり出すために、XMLTableを使っています。
これがなかなか便利な機能でして、例えばこんな感じのHOGE_XML
テーブルがあったとして
-- HOGE_XMLテーブル CREATE TABLE HOGE_XML ( HOGE_ID INTEGER PRIMARY KEY, XML_DATA CLOB )
こんなXMLデータがHOGE_XML
テーブルのXML_DATA
列に入っている場合
<?xml version="1.0" encoding="UTF-8"?> <statuses type="array"> <status> <id>123456789</id> <text>ほげほげ</text> <user> <id>12345</id> <name>hoge</name> </user> </status> <status> <id>234567890</id> <text>ふがふが</text> <user> <id>23456</id> <name>fuga</name> </user> </status> <status> <id>345678901</id> <text>ふーばー</text> <user> <id>34567</id> <name>foo</name> </user> </status> </statuses>
こんな感じのSQLを実行すれば、1つの<status>の要素が1つのレコードとして返ってきます。 もちろんWHERE句も使えます。超素敵です。
SELECT X.* FROM HOGE_XML H, XMLTABLE('/statuses/status' PASSING XMLTYPE(H.XML_DATA) COLUMNS ID VARCHAR2(10) PATH 'id', TEXT VARCHAR2(1000) PATH 'text', USER_ID VARCHAR2(10) PATH 'user/id', USER_NAME VARCHAR2(100) PATH 'user/name' ) X WHERE X.USER_NAME IN ('hoge', 'fuga')
テーブル・ファンクション(表関数)
テーブル・ファンクションというのは、
テーブル・ファンクションは、行のコレクション(ネストした表またはVARRAY)を戻すユーザー定義のPL/SQLファンクションです。SELECT文のTABLE句の内部でテーブル・ファンクションを起動することで、データベース表のようにこのコレクションから要素を選択できます。
http://docs.oracle.com/cd/E16338_01/appdev.112/b56260/tuning.htm#i52954
です。 要は、
SELECT * FROM TABLE(hoge_func(123));
みたいな感じで戻り値をそのままSELECTできるストアドファンクションです。処理のパイプライン化もできます。
ただしSELECTするときにTABLE句が必要になるので、今回は、
CRATE VIEW TWITTER_PUBLIC_TIMELINE AS SELECT * FROM TABLE(GET_TWITTER_PUBLIC_TIMELINE);
のようなビューを作成し、毎回TABLE句をつけないで済むようにしてみました。
まとめ
そんなわけでOracleでもTwitterのタイムラインを取ってくることができたわけですが、2013年3月5日でXMLのサポートが打ち切られちゃうので、今回のやつは使えなくなります。認証もしてないし。
元ネタであるPostgreSQLのtwiter_fdwでは、WHERE句に q = 'hoge'
で指定した条件がSearch APIにパラメータとして渡されるようになってるみたいですね。Oracleだとこういう仕組みは作れるのかな…?
YARDで拡張ライブラリのドキュメントを書くときはメソッドの定義のところで@overloadタグを書かなきゃダメという話
はじめに
まぁ表題のとおりなんですが、要は
「YARDで拡張ライブラリのドキュメントを書くときは、@overloadタグでメソッドシグニチャを書かないと正しくドキュメントが生成されないので注意しましょう」
という話です。
環境
- Ruby 1.9.3-p194
- YARD 0.8.0
何が起こったかというと
拡張ライブラリで、Hashを渡すメソッドのドキュメントをYARDでこんな感じで書いてたんですよ。
/* * @param [Hash] opts parameters * @option opts [Number] :arg1 argument 1 * @option opts [Number] :arg2 argument 2 */ VALUE rb_foo(VALUE self, VALUE opts) { return Qnil; }
で、
$ yardoc foo.c
とかやって作成したドキュメントを意気揚々と開いたわけですよ。
そしたらなんと、@optionで指定した :arg1 と :arg2 のドキュメントが出てこないじゃないですか。
で、どうしたかというと
YARDのリポジトリにIssue登録を投げてみたら、
「CのコードでYARDを使うときは@overloadタグでメソッドシグニチャとかパラメータの記述をしないとちゃんと認識できねーよ」
との回答を頂いたので、こんな感じに書きなおしてみました。
/* * @overload foo(opts) * @param [Hash] opts parameters * @option opts [Number] :arg1 argument 1 * @option opts [Number] :arg2 argument 2 */ VALUE rb_foo(VALUE self, VALUE opts) { return Qnil; }
そしたらちゃんと@optionタグで指定した :arg1 と :arg2 の内容が表示されてました。
まとめ
というわけで、YARDを拡張ライブラリで使う場合は@overloadタグをつけましょうね!というお話でした。
HWエンキューでロックされているセグメントを特定する
はじめに
Oracleまわりのトラブルの調査のため、HWエンキューでロックされたセグメントを特定する方法を調べてみました。
環境
- Oracle 10g R2
HWエンキューってなんぞ?
Oracleのエンキューとは
エンキューは、データベース・リソースへのアクセスをシリアライズする共有メモリーの構造(ロック)です。
(Oracleエンキュー名)
です。
HWエンキューは、セグメントのHWM(High Water Mark; 最高水位標)を動かすときに行われるロックです。保持されているロック情報を示すV$LOCKビュー上では、TYPE='HW'のレコードとして表されます。
HWエンキューでロックしているセグメントを特定する
1. ロックされたHWエンキューが待っているデータのファイルとブロックを特定
まず、V$LOCKからTYPEが'HW'の行を探し、そのデータブロックアドレスのファイル番号とブロック番号を取得します。
HWエンキューの場合、V$LOCKのID1, ID2は下記のようになります。
- ID1: HWMが変更されるセグメントが格納されている表領域の番号
- ID2: セグメントヘッダの相対データブロックアドレス
(パフォーマンス・ビューを使用したインスタンスのチューニング - HWエンキュー)
また、ストアドファンクションDBMS_UTILITY.DATA_BLOCK_ADDRESS_FILEとDBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCKにデータブロックアドレスを渡して実行すると、そのデータブロックアドレスのファイル番号とブロック番号がわかります。
DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE
引数 dba にデータ・ブロック・アドレスを渡して実行すると、データ・ブロック・アドレスのファイル番号部分を返す
(DATA_BLOCK_ADDRESS_FILEファンクション - DBMS_UTILITY)DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE ( dba NUMBER) RETURN NUMBER;
DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK
引数 dba にデータ・ブロック・アドレスを渡して実行すると、データ・ブロック・アドレスのブロック番号部分を返す
(DATA_BLOCK_ADDRESS_BLOCKファンクション - DBMS_UTILITY)DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK ( dba NUMBER) RETURN NUMBER;
そこで、V$LOCKのID2をDATA_BLOCK_ADDRESS_FILEとDATA_BLOCK_ADDRESS_BLOCKに渡せばよさそうです。
SQLはこんな感じになります。
SELECT DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(ID2) "FILE_ID", DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(ID2) "BLOCK_ID" FROM V$LOCK WHERE TYPE = 'HW'
結果はこんな感じ。ファイル番号とブロック番号がわかりました。
FILE_ID | BLOCK_ID |
---|---|
20 | 29 |
2. ロックしているセグメントを特定
1.でわかったファイル番号とブロック番号から、HWエンキューでロックしているセグメントを特定します。
こんな感じのSQLを実行します。
SELECT OWNER, SEGMENT_NAME, SEGMENT_TYPE FROM DBA_EXTENTS WHERE FILE_ID = 20 AND 29 BETWEEN BLOCK_ID AND BLOCK_ID + BLOCKS - 1
WHEREの条件の値(上記の20と29)には、1.で調べたものを入れてください。
結果はこんな感じ。
OWNER | SEGMENT_NAME | SEGMENT_TYPE |
---|---|---|
ORACLE | SYS_LOB000001234C01234$$ | LOBSEGMENT |
どうやら SYS_LOB000001234C01234$$ というセグメントがロックされているらしい、ということがわかりました。
この情報をもとに原因を特定して、対策を行いましょう。
まとめ
HWエンキューでロックされているセグメントを特定する方法を調べてみました。
これでHWエンキューでずーっとロックされてエラいことになっても大丈夫ですね!