年末なのでEmacsの設定ファイルを見直しますよ

年末ですね

大掃除の季節なので、普段使っているEmacsの設定ファイルを整理してみました。 ついでに前から気に入らなかった部分を直したり、便利そうなものを追加したので、いくつかピックアップして書いておきます。

全体の設定ファイルはGitHubに置いてあります。

ser1zw/dotfiles - 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

って書いておけばよいです。

参考

InstallGuide : Debian - OpenCV Wiki

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] とやれば、コマンドの候補が出てくるようになります。

f:id:ser1zw:20121008194441p:plain

$ mux start [TAB] とかやれば、候補のプロジェクトがずらっと出てきます。

f:id:ser1zw:20121008194517p:plain

tmuxinator、結構便利なので、みんな使うとよいですよ。

OracleでTwitterのタイムラインをSELECTする

  1. FDWってなによ?
  2. FDW(Foreign Data Wrappe),外部データラッパっていうやつで、SQL/MED(Management of External Data)の規格の一つで簡単にいうと、PostgreSQLにQUERYを発行したら、あら不思議、外部の(たとえばMySQLとかCSV)データが取得できるという変態機能。 twitterAPIに変更あるらしいから今後はわからにけど、twitterのデータを取ってくるとかもできる。というかラッパーが用意されてる。(ちなみに使ってみたら楽しかったw)

PostgreSQLに興味がある人向けにまとめてみた。|PostgreSQL|お仕事メモ|Pictnotes

それはワクテカ過ぎる... だがしかし SQLite3 でも出来る!きっと出来る!

Big Sky :: SQLite で twitter のタイムラインを select する。

Oracleでもきっとできる!というかできた!
ser1zw/twitter-public-timeline-for-oracle

f:id:ser1zw:20121005015127p:plain

ご家庭の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機能

OraclePL/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', '*');

にすれば、どこでもアクセスできるようになります。

参考:DBMS_NETWORK_ACL_ADMIN

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')

f:id:ser1zw:20121005015402p:plain

テーブル・ファンクション(表関数)

テーブル・ファンクションというのは、

テーブル・ファンクションは、行のコレクション(ネストした表または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のサポートが打ち切られちゃうので、今回のやつは使えなくなります。認証もしてないし。

元ネタであるPostgreSQLtwiter_fdwでは、WHERE句に q = 'hoge' で指定した条件がSearch APIにパラメータとして渡されるようになってるみたいですね。Oracleだとこういう仕組みは作れるのかな…?

YARDで拡張ライブラリのドキュメントを書くときはメソッドの定義のところで@overloadタグを書かなきゃダメという話

はじめに

まぁ表題のとおりなんですが、要は
「YARDで拡張ライブラリのドキュメントを書くときは、@overloadタグでメソッドシグニチャを書かないと正しくドキュメントが生成されないので注意しましょう」
という話です。

環境

何が起こったかというと

拡張ライブラリで、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 のドキュメントが出てこないじゃないですか。

f:id:ser1zw:20120430181745p:image

で、どうしたかというと

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 の内容が表示されてました。

f:id:ser1zw:20120430181912p:image

まとめ

というわけで、YARDを拡張ライブラリで使う場合は@overloadタグをつけましょうね!というお話でした。

HWエンキューでロックされているセグメントを特定する

はじめに

Oracleまわりのトラブルの調査のため、HWエンキューでロックされたセグメントを特定する方法を調べてみました。

環境

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エンキューでずーっとロックされてエラいことになっても大丈夫ですね!