Emacs キーバインドに関する Windows と Mac OSX の差異

Mac OS X が手元に来て7ヶ月くらい経とうとしてる。そろそろ軽度(!?)Emacs 病を患っている人間から見た Windows と Mac OS X の違いをまとめてみた。

具体的には、Emacs に関わる話としては、

  • Emacs っぽいエディターについて(①)
  • 普段の GUI 操作において、Emacs キーバインドがどのくらい通用するか(②)

という話があります。

しかし①って他探せば幾らでも記事あるだろうから、今回は言及しません。。。というかよくわかりません。普段からローカル環境で開発せず、研究室の Linux サーバや、自宅サーバで開発をしているので、ローカル環境でエディター使わない。

今回は②の話を書いて行こうと思います。少し分かりにくいけど、Windows の話を読めば何となく分かるはず。C-p でフォーカスを上に移動させたり、C-m が改行だったり、C-Space がマークセットだったり、M-v で1ページ分スクロールできたり、といった操作を、webブラウザや、ファイラなどでも使うことです。

Windows

まずそもそも標準では全くサポートされていません。②を実現させる為には、 窓使いの憂鬱Xkeymacsなどのソフトウェアが必要になります。以下、Windows 上での Emacs キーバインド環境の特徴。

  • サポートしている Emacs キーバインド多い!マークセットできるのは windows だけ(?)。C-x から始まる2ストロークキーバインドに対応してるのも特徴。
  • アプリケーションによって、emacsキーバインドを有効にさせるか否かを設定することが可能。ちょうべんり
  • 時々入力キーをフックし損ねて大変なことに(例:C-nでスクロールしようと連打 → フックし損ねまくる → 新規ウィンドウ大量生成 → はんのうがない ただの はこ のようだ)
  • 時々挙動へん。Xkeymacs に限った話ですが、例えば「C-m と入力すると、Ctrl+Return の入力になってる。」とか、「『Shift+Tab』と入力しようと S-C-i とタイプする→Shift キーがロックされて解除できなくなる」など
  • MS Office と相性悪過ぎ。ごくごくタマに Office 落ちる。
  • MS IMEと相性悪い。(ので、MS IME の時は無効化し、MS IME 自体のキーバイン変更機能を利用)

実は、VISTA になってからの状況がよくわかってません。とりあえず Xkeymacs は、VISTA 上で問題なく使えました。

Mac OS X

私が知っている限りだと、二通り存在します。

  • 標準のemacsキーバインド(ただしテキストエリア限定)
  • KeyRemap4MacBook

標準の方も、素晴らしい点があるのですが、テキストエリア限定なのが残念。

KeyRemap4MacBook の特徴を下でまとめます。

  • 安定してる。フックし損ねた経験無し。
  • マークセットできない。。。(標準だと C-i で出来た記憶があるのですが。)
  • 特定ソフトウェアのときは、無効化するという機能がついて入るのですが、無効化できるソフトウェアが予め決まっている。ソースコード書き換えれば可能なようです。iTerm 使えない。
  • 日本語入力システムに対する Emacs キーバインドは、入力対象のソフトウェアに依存してしまう(例:Terminal.app の時だけ Emacs キーバインドを無効化すると、Terminal.app への日本語入力時も無効化されてしまう)。凄く困ってる。

最後のは、OS の構造上仕方の無い問題なんでしょうかね。。。

ついでに Linux(GNOME)

GNOME の標準機能(要設定)keyfake の二通り。

GNOME の標準機能は、Mac OS X の標準機能と似た感じ。テキストエリア限定。

keyfake は。。。うごかにあ!フツーにコンパイルしちゃダメなのかな。

まとめ

Windows、Mac OS X、Linux(GNOME) における Emacs キーバインドの対応状況を確認しました。

Windows
不安定だけど多機能、マークセットできる
Mac OS X
安定してる。日本語入力システム、他アプリケーションとの兼ね合いがうまくいってない
Linux(GNOME)
が、がんばれ!しかし皮肉ですね。。。

ということで、Windows が一番好きです。

しかし。。。

xkeymacs, 窓使いの憂鬱、KeyRemap4MacBook、keyfake のいずれも日本人が開発してる。。。?HENTAI!HENTAI!HENTAI!

Ruby でパイプラインな HTTP リクエスト

HTTP/1.1 の同時接続数について - daily dayflower をみて「おお、こんな事出来たのか。pipelining すげぇ」と思い、Ruby でこれやるのにはどうしたらいいのか 404 Blog Not Found:HTTPサーバーのパイプライン対応 を参考に考えてみました。

どうやら、Net::HTTP は、HTTP プロトコルのパイプライン処理をできるようになってないようす。その為、Net::HTTP の拡張が必要になりました。

メインコード

404 Blog Not Found:HTTPサーバーのパイプライン対応 のパイプラインの例を ruby コード化するとこんな感じ。

require "net/http"
require "pipelinig_http.rb" # Net::HTTP の拡張
 
def main
 
  host = 'b.hatena.ne.jp'
  paths = ['/','/hotentry', '/news', '/entrylist?sort=hot']
 
  Net::HTTP.start(host) do |http|
 
    # リクエストの送信
    paths.each do |path|
      req = Net::HTTP::Head.new(path)
      r_print req
      http.just_request(req)
    end
 
    # レスポンスの取得
    while res = http.fetch_response
      r_print res
    end
 
  end
 
end
 
# リクエストとレスポンスのヘッダを出力する
def r_print(r)
  puts "##### #{r.class.to_s} #####"
    r.each{|k,v| puts "%15s: %s" % [k,v]}
  puts ""
end
 
main if __FILE__ == $0

上記のコードで、require されてる pipelining_http.rb は、今回のために用意したファイルで、次に示す内容になっています。

パイプライン処理のための Net::HTTP の拡張 pipelining_http.rb

Net::HTTP#just_request, Net::HTTP#fetch_response は、次のように拡張される。実質、Net::HTTP#request を二つに分断した感じなってます。一応アップロードしておく。また今回の例では HEAD リクエストしかしていませんが、GETもPUTもできるはずです。(PUTは未確認)

pipelining_http-0.1.tar.gz

class Net::HTTP
 
  def just_request(req, body=nil)
 
    @req_cue ||= []
    @req_cue << req
 
    unless started?
      start {
        req['connection'] ||= 'close'
        return request(req, body, &block)
      }
    end
    if proxy_user()
      unless use_ssl?
        req.proxy_basic_auth proxy_user(), proxy_pass()
      end
    end
 
    req.set_body_internal body
    begin_transport(req)
 
    req.exec(@socket, @curr_http_version, edit_path(req.path))
 
  end
 
  def fetch_response
 
    if @req_cue.nil? or @req_cue.empty?
      end_transport(@last_request, @last_response)
      return nil
    end
 
    @last_request = (req = @req_cue.shift)
 
    begin
      @last_response = (res = Net::HTTPResponse.read_new(@socket))
    end while res.kind_of?(Net::HTTPContinue)
 
    res.reading_body(@socket, req.response_body_permitted?) {
      yield res if block_given?
    }
 
    res
  end
 
end

個人的に、end_transport のあたりの処理が気に入りません。要改善。

実行結果

##### Net::HTTP::Head #####
         accept: */*

##### Net::HTTP::Head #####
         accept: */*

##### Net::HTTP::Head #####
         accept: */*

##### Net::HTTP::Head #####
         accept: */*

##### Net::HTTPOK #####
           vary: Accept-Encoding
            via: 1.0 squid.hatena.ne.jp:3128 (squid/2.6.STABLE14)
   content-type: text/html; charset=utf-8
           date: Sat, 25 Oct 2008 20:01:48 GMT
         server: Apache/2.2.3 (CentOS)
     set-cookie: b=$1$edWQVbYY$4h0bIVtR7RvBTX3ifNcOF1; path=/; expires=Fri, 20-Oct-28 20:01:48 GMT; domain=.hatena.ne.jp
 content-length: 63501
            age: 588
    x-framework: Hatena/2.1

##### Net::HTTPOK #####
           vary: Accept-Encoding
            via: 1.0 squid.hatena.ne.jp:3128 (squid/2.6.STABLE14)
   content-type: text/html; charset=utf-8
           date: Sat, 25 Oct 2008 20:01:48 GMT
         server: Apache/2.2.3 (CentOS)
     set-cookie: b=$1$qYZ0MfS0$aCDFrIOKpp8HayJftFjt/1; path=/; expires=Fri, 20-Oct-28 20:01:48 GMT; domain=.hatena.ne.jp
 content-length: 103301
            age: 1163
    x-framework: Hatena/2.1

##### Net::HTTPOK #####
           vary: Accept-Encoding
            via: 1.0 squid.hatena.ne.jp:3128 (squid/2.6.STABLE14)
   content-type: text/html; charset=utf-8
           date: Sat, 25 Oct 2008 20:01:48 GMT
         server: Apache/2.2.3 (CentOS)
     set-cookie: b=$1$00vjav3o$InTi7h2XFjwllpcFJLnv60; path=/; expires=Fri, 20-Oct-28 20:01:48 GMT; domain=.hatena.ne.jp
 content-length: 52390
            age: 2259
    x-framework: Hatena/2.1

##### Net::HTTPOK #####
           vary: Accept-Encoding
            via: 1.0 squid.hatena.ne.jp:3128 (squid/2.6.STABLE14)
   content-type: text/html; charset=utf-8
           date: Sat, 25 Oct 2008 20:01:48 GMT
         server: Apache/2.2.3 (CentOS)
     set-cookie: b=$1$IZcB88yy$I2jjsa5SWRPLEBT4saLNI.; path=/; expires=Fri, 20-Oct-28 20:01:48 GMT; domain=.hatena.ne.jp
 content-length: 103620
            age: 2203
    x-framework: Hatena/2.1

以上でした。

Fedora 9 に mpg123 をインストール

Fedora 9 に mpg123 入れるのに,

$ sudo yum install mpg123

でいけると思ってた...結果は

Loaded plugins: refresh-packagekit
Warning: No matches found for: mpg123
No Matches found
$ sudo yum search 123
Loaded plugins: refresh-packagekit
================================= Matched: 123 =================================
flac123.i386 : Command-line program for playing FLAC audio files
pastebin.noarch : A collaborative debugging tool
vorbisgain.i386 : Adds tags to Ogg Vorbis files to adjust the volume

どうやら yum には頼れないようです. ってか flac123 があって mpg123 が無いのって何なんだろう...納得いかない.

ということで,RPM Search で見つけた mpg123 の RPM パッケージをインストールすることをする.mpg123 をインストールするに当たって,mpg123 が必要としているパッケージもインストールする.

$ sudo yum install arts portaudio
$ sudo rpm -i 'ftp://ftp.pbone.net/mirror/atrpms.net/f9-i386/atrpms/stable/mpg123-1.5.1-8.fc9.i386.rpm'
$ mpg123 'http://www.nullsleep.com/mp3/8bp077-01-nullsleep-her_lazer_light_eyes.mp3'

....鳴らない...?

と思ったら音量が最小だったという罠.適切な音量を設定して再トライしたところ,問題なく動きました!ってか Gnome 使うと,ALSA から音量のコントロールできないのね.どうしたらいいんだろ.

last.fm のラジオ再生のための Ruby ライブラリを作ってみた

以前のブログの記事で、Google Code 上の thelastripper にて公開されているドキュメント (LastFM12UnofficialDocumentation) の簡単な説明と、スクリプトを公開しました。

Linux を NAS 兼メディアセンターとして使っているので、Linux で X 立ち上げずに last.fm ラジオの再生できたらなぁと思ってたりしてました。

ということで、LastFM12UnofficialDocumentationを元に、last.fm ラジオの再生の助けになるライブラリを作ってみました。

lastfmradio-0.1.tar.gz のダウンロード

本当は、RubyForge なり GitHub になり置いた方が良いかもしれないんですが、どっちがいいんですかねぇ。

同梱されているドキュメント。。英語ですがかなり怪しいですね。

使い方

メソッドごとに説明をするよりも、サンプルコードの方がどんな感じかわかりやすいと思うので、コードで二つほど例示します。
基本的に、ハンドシェイク → ラジオ局の選択 → トラックの取得 → 処理 の流れは変わりません。省かれているように見える場合は、内部で処理をしています。

一番基本的な例

mpg123 を使ってラジオ再生する

#! ruby -Ku
 
# last.fm 上でのアカウント名とパスワード
user_name = 'USER_NAME'
password = 'PASSWORD'
 
# 内部ではハンドシェイクをしている
lastfm = LastfmRadio.new(user_name, password)
 
# electoronic タグラジオに合わせる
lastfm.adjust_station('tag', 'electoronic')
 
loop do
 
  # トラック情報の取得
  # クラス Track のインスタンスの Array を返す
  tracks = lastfm.get_tracks
 
  tracks.each do |track|
 
    # トラック情報の表示
    puts "-"*75
    puts "artist: #{track.artist}"
    puts "title:  #{track.title}"
    puts "album:  #{track.album}"
    puts "length: #{track.length/1000}[sec]" 
 
    # mpg123 を使って現在のトラック再生
    `mpg123 -q #{track.location}`
  end
 
end

LastfmRadio#get_tracks メソッドは要注意。返してくれるトラックの数はまちまちです。ラジオ局によっては、 1 つも取得できない時があります。これは、引数に整数を与えることで解決ができます。たとえば引数に 2 をあたえると、2 個以上のトラックを取得するまでリターンしなくなります。

LastfmRadio#adjust_station メソッドは、第一引数に以下のようなシンボル or 文字列をとります。

tag または globaltags
第二引数で指定されるタグラジオを選択
artist
第二引数で指定されるアーティストに似たラジオを選択
personal
第二引数で指定されるアカウントのパーソナルラジオを選択
recommended
第二引数で指定されるアカウントのおすすめラジオを選択
neighbours
第二引数で指定されるアカウントのお隣さんのラジオを選択(日本語。。。)
group
第二引数で指定されるグループのラジオを選択

一番簡単な例

wget を使ってラジオから流れてくる曲をダウンロード

require "lastfmradio"
 
hash = {
  :user_name =&gt; "SOME_USER",
  :password =&gt; "PASSWORD",
  :station =&gt; ["tag","electoro"], # adjust_station の引数と同じ
  :min_num_tracks =&gt; 2,  # 2 個以上のトラックを必ず取得(optional)
  #:debug =&gt; true # デバグモード(optional)
}
 
loop do
 
  # ハンドシェイク、局の選択、トラックの取得をする
  # 二回め以降は、同じユーザ名・局の場合は、ハンドシェイク、局の選択はしない。
  tracks = LastfmRadio.get_tracks(hash)
 
  tracks.each do |track|
 
    puts "-"*25 + " " + Time.now.to_s + " " + "-"*25
    puts "artist: #{track.artist}"
    puts "title:  #{track.title}"
    puts "album:  #{track.album}"
    puts "length: #{track.length/1000}[sec]"
 
    `mpg123 -q #{track.location}`
  end
end

こんな感じで使えます。

しかしここまで書いたら、アプリケーションとして公開した方がよかったかな。。。気にしない。。。。ruby ライブラリを公開したの初めてですが、インストーラーとかみんなどうしてるんでしょうかね。

Wordpress にコードハイライト機能インストール

前の記事で code タグ使って書いてみたもののさっぱりだった...なので,コードのシンタックスハイライトやその他諸々をやってくれるプラグインが無い分けないので探してみた.

あったあった.ほかにもたくさんあるみたいですね.上から順に挑戦してみました.環境はWordpress 2.6.2 だったはず.

SyntaxHighlighter
→ 動かない.正確には,このプラグインのためのタグ[sourcecoe]を解釈してくれないため,そのまま吐き出される.
SyntaxHighlighter Plus
→ 動かない.正確には(ry
Google Code Prettify for wordpress
→ 動いた!でも,Bashのシンタックスハイライト変.「//」をコメントアウトとして解釈してる..?
WP-Syntax
→動いた!しかもBashもそれっぽくハイライトしてくれる!

ということで,WP-Syntax を使います.

Bashだと

# ついでにプラグインのインストール方法を書く
$ wget http://www.deanlee.cn/downloads/google_code_prettify_v1.1.zip
$ unzip google_code_prettify_v1.1.zip
$ mv google_code_prettify [Wordpressが設置されているディレクトリ]/wp-content/plugins

こんな感じに変換される.インストールはこの後に,管理画面から,プラグインを有効にする操作が必要になる.

前回の投稿の autopagerize の siteinfo に使うと,

{
  url: '^http://libra\.msra\.cn/(IGResult_paper|AuthorResult|authordetail|AuthorDetail|PaperResult|paperresult|ConferenceResult|JournalResult|IGResult|papercited)\.aspx.+',
  nextLink: 'id("pageLst_next")',
  pageElement: 'id("paperRes authorRes confRes jourRes igRes paperList")',
  exampleUrl: 'http://libra.msra.cn/paperresult.aspx?query=association+rules',
}

こんな感じ.あまりサンプルになってないですね.

書き方は <pre lang=”SOME_LANGAGE”>…</pre> でくくればよい感じ.本当は,pre タグで括って例示したかったんだけどどうやら,pre タグの中に今回の記述を入れると正しく動作しない様子.

シンタックスハイライトに対応しているのは(SOME_LANGAGE に入れられるのは)現在のところ以下の言語.

abap, actionscript, actionscript3, ada, apache, applescript, aptsources, asm, asp, autoit, bash, blitzbasic, bnf, boo, c, cmac, caddcl, cadlisp, cil, cfdg, cfm, cobol, cpp-qt, cpp, csharp, css, d, delphi, diff, div, dos, dot, eiffel, fortran, freebasic, genero, gettext, glsl, gml, bnuplot, groovy, haskell, html4strict, idl, ini, inno, io, java, java5, javascript, kixtart, klonec, klonecpp, latex, lisp, lotusformulas, lotusscript, lua, m68k, matlab, mirc, mpasm, mxml, mysql, nsis, objc, ocaml-brief, ocaml, oobas, oracle8, pascal, per, pic16, perl, php-brief, php, plsql, povray, powershell, progress, python, qbasic, rails, reg, robots, ruby, sas, scala, scheme, sdlbasic, smalltalk, smarty, sql, tcl, text, thinbasic, tsql, typoscript, vb, vbnet, verilog, vhdl, visualfoxpro, winbatch, xml, xorg_conf, xpp, z80

おおいなー

Libra の siteinfo を AutoPagerize の wedata に登録

Libra の siteinfo を AutoPagerize の wedata に登録してみた.たぶん Libra 内で対応漏れページがあると思うけれど,とりあえず目立つところと,よく使うページに対応しておいた.wordpress の対応を見てみたいので siteinfo を貼り付けてみる.

{
    url:          '^http://libra\.msra\.cn/(IGResult_paper|AuthorResult|authordetail|AuthorDetail|PaperResult|paperresult|ConferenceResult|JournalResult|IGResult|papercited)\.aspx.+',
    nextLink:     'id("pageLst_next")',
    pageElement:  'id("paperRes authorRes confRes jourRes igRes paperList")',
    exampleUrl:   'http://libra.msra.cn/paperresult.aspx?query=association+rules',
}

Wordpress の諸設定

少し弄った。

  • 投稿するときにユーザ名が admin になるの気に入らないので、ユーザ登録して “管理者” に設定して登録以後 admin 使わない予定
  • テンプレートを Blank Wordpress Themes から頂く。以降これを改造していく。

さーCCSと戦うぞー

テンプレート変更

とりあえず http://burnfield.com/martin/ で配布してるテンプレート採用。
ほんとは「blank theme wordpress」あたりでググって適当なの見つけてCCS弄るってのでも良かったんだけど、手間掛かりすぎるから後日。

さくらインターネットサーバに WordPress 設置

凄い簡単だった。拍子抜け。

解凍ファイル置いて、ブラウザから index.php にアクセス → 指示に従う → 終了

さくらインターネットサーバにインストールするさいの注意点って言ったら、データベースのホスト名が “localhost” じゃない点かな。 “mysql**.sakura.ne.jp” だからね。