term タグ別の記事一覧

CentOS 5.6上でXenを使って仮想環境を作るための基本設定

 先日MSDNを契約、テスト用に自由にOSを使えるようになったので、テスト用のCore i7マシンにXenを導入して仮想マシン上でテスト環境を作ろう、という話。いままではテスト環境が必要になったら実環境上にインストール→不要になったら削除、を繰り返していたんだけど、仮想環境を使えばスナップショットも取れるし便利だろう、ということで。

 ベースの環境はCentOS 5.6。CentOS 5.6上にXen環境を構築する解説はネット上にたくさんあるわけですが、その多くがGUIを使ったセットアップ方法を解説していて、コンソールベースのCentOS環境でインストールする方法の解説は少なかったので以下に手順をメモしておきます。

 まず、仮想化関連パッケージを導入。

# yum groupinstall Virtualization
# yum install kernel-xen

 Xenを動かすには専用カーネルが必要なので、/boot/grub/menu.lstを確認してXen対応カーネル(2.6.xx-xxx.x.x.el5xen)でブートされるように設定してリブート。また、xendおよびxendomainsサービスを起動するように設定しておく。

# /sbin/chkconfig xend on
# /sbin/chkconfig xendomains on
# /sbin/service xend start
# /sbin/sercice xendomains start

 仮想マシンの作成とOSインストールは「virt-install」コマンドで行える。Fedora 15をインストールするなら下記のような感じに。

# /usr/sbin/virt-install --nographics --prompt
Would you like a fully virtualized guest (yes or no)? This will allow you to run unmodified operating systems. no
 What is the name of your virtual machine? fedora
 How much RAM should be allocated (in megabytes)? 1024
 What would you like to use as the disk (file path)? /var/lib/xen/images/fedora.img
 How large would you like the disk (/var/lib/xen/images/fedora.img) to be (in gigabytes)? 10
 What is the install URL? http://ftp-srv2.kddilabs.jp/Linux/distributions/fedora/releases/15/Fedora/i386/os/
 :
 :
インストールを開始しています...
ファイル .treeinfo を読出中...                             |  906 B     00:00
ファイル vmlinuz-PAE を読出中...                           | 3.7 MB     00:00     TA
ファイル initrd-PAE.img を読出中...                        |  94 MB     00:40     TA
ストレージファイルを作成中...                         |  10 GB     00:00
ドメインを作成中...                                        |    0 B     00:04
Connected to domain fedora
エスケープ文字は  ^] です
[    0.000000] Reserving virtual address space above 0xf5800000
[    0.000000] Initializing cgroup subsys cpuset
 :
 :

 コンソール上で仮想環境上のコンソールが表示され、インストールを行える。

コンソール上でFedoraのインストーラを操作する

コンソール上でFedoraのインストーラを操作する

 インストール完了語は、Ctrl-]でコンソールを抜けられる。稼働中の仮想マシンは「xm list」コマンドで確認可能。

# /usr/sbin/xm list
Name                                      ID Mem(MiB) VCPUs State   Time(s)
Domain-0                                   0     2012     8 r-----    780.4
fedora                                     2     1024     1 -b----      9.9

 仮想マシンのコンソールに接続するには、「xm console <仮想マシン名>」を実行すればよい。コンソール接続の終了は先と同様Crtl-]。

# /usr/sbin/xm console fedora

nuttcpでネットワークスループットを測る

 ネットワークのスループットを測るツールには色々ある。SourceForge.JP Magazineの翻訳記事(ネットワークのベンチマーク・ツールを試す – nepim、LMbench、nuttcp)でいくつか紹介されているのだが、その中でも自分が比較的よく使っているのがnuttcpだ。ということで簡易的な使い方メモ。

インストール

 ソースコードからビルドしても良いが、nuttcpのダウンロードサイトにはRPMパッケージもあるので、こちらを利用するのが楽である。

ベンチマークの実行

 nuttcpはクライアント/サーバー型のベンチマークツールである。つまり、帯域測定をしたいネットワークの片側でサーバーを動かし、もう片側でクライアントを実行してベンチマークを行う。

 サーバー側では「-S」オプション付きでnuttcpを実行しておく。

# nuttcp -S

 クライアント側では、サーバーのIPアドレス付きでnuttcpを実行する。上り速度を測定するには「-B」を、下り速度を測定するには「-D」オプションを使う。「-i<数字>」オプションを付けると、数字で指定した間隔で途中経過を表示する。「-v」や「-vv」で経過や結果の詳細表示。

 次の例はクライアントからサーバーへの上り速度を測定する場合。

$ nuttcp -B -i1 183.181.28.64
    7.1875 MB /   1.00 sec =   60.2683 Mbps     0 retrans
    7.1875 MB /   1.00 sec =   60.2960 Mbps     0 retrans
    7.6875 MB /   1.00 sec =   64.4898 Mbps     0 retrans
    7.7500 MB /   1.00 sec =   65.0148 Mbps     0 retrans
    8.0000 MB /   1.00 sec =   67.1111 Mbps     0 retrans
    8.1250 MB /   1.00 sec =   68.0925 Mbps     0 retrans
    7.8750 MB /   1.00 sec =   66.0627 Mbps     0 retrans
    7.6875 MB /   1.00 sec =   64.4892 Mbps     0 retrans
    7.5000 MB /   1.00 sec =   62.9117 Mbps     0 retrans
    8.1875 MB /   1.00 sec =   68.6899 Mbps     0 retrans

   77.6250 MB /  10.07 sec =   64.6675 Mbps 0 %TX 6 %RX 0 retrans 9.35 msRTT

 下り速度の測定は次のような感じ。

$ nuttcp -D -i1 183.181.28.64
    6.1250 MB /   1.00 sec =   51.3391 Mbps     0 retrans
    7.5625 MB /   1.00 sec =   63.4470 Mbps     0 retrans
    7.3750 MB /   1.00 sec =   61.8740 Mbps     0 retrans
    7.3125 MB /   1.00 sec =   61.3443 Mbps     0 retrans
    6.9375 MB /   1.00 sec =   58.1962 Mbps     0 retrans
    7.1875 MB /   1.00 sec =   60.2891 Mbps     0 retrans
    7.3750 MB /   1.00 sec =   61.8149 Mbps     0 retrans
    7.7500 MB /   1.00 sec =   65.0144 Mbps     0 retrans
    7.5625 MB /   1.00 sec =   63.4413 Mbps     0 retrans
    7.5625 MB /   1.00 sec =   63.4363 Mbps     0 retrans

   73.2500 MB /  10.07 sec =   60.9941 Mbps 0 %TX 5 %RX 0 retrans 9.11 msRTT

Apacheチューニング:プロセス設定を変更

 hylom.netがだいぶ遅くなっていたのでちょっとチューニングした。原因としてはメモリ不足、DBが遅い、I/Oが遅い、ネットワークが遅いなどがあるが、さくらVPSのコントロールパネルを見た限りではCPUやネットワーク、I/Oには余裕がある感じだったので、メモリ不足ではないかと検討をつける。ということで、各プロセスのメモリ使用状況をチェック。

# ps aux --sort -rss| lv

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
apache   28879  0.1  6.6 269404 33728 ?        S    Mar01   9:40 /usr/sbin/httpd
apache   28966  0.1  6.5 269072 33484 ?        S    Mar01   9:54 /usr/sbin/httpd
apache   30532  0.1  6.5 272696 33412 ?        S    Mar02   4:48 /usr/sbin/httpd
apache   30542  0.1  6.2 274072 31680 ?        S    Mar02   4:41 /usr/sbin/httpd
apache   29002  0.1  6.0 274684 30804 ?        S    Mar01   9:31 /usr/sbin/httpd
apache   28868  0.2  5.9 273812 30556 ?        S    Mar01  10:30 /usr/sbin/httpd
apache   28750  0.2  5.8 274168 29964 ?        S    Mar01  10:56 /usr/sbin/httpd
apache   30543  0.1  5.7 274040 29212 ?        S    Mar02   4:23 /usr/sbin/httpd
apache   30529  0.1  5.2 273992 26952 ?        S    Mar02   4:33 /usr/sbin/httpd
apache   28580  0.2  4.8 274152 24852 ?        S    Mar01  10:36 /usr/sbin/httpd
apache   27032  0.1  4.3 273148 22224 ?        S    Mar01   6:06 /usr/sbin/httpd
apache    8773  0.1  3.9 268900 19944 ?        S    Mar03   2:44 /usr/sbin/httpd
apache   27108  0.1  3.7 274016 19224 ?        S    Mar01   6:03 /usr/sbin/httpd
apache   30530  0.1  3.3 273152 17020 ?        S    Mar02   4:45 /usr/sbin/httpd
apache   18789  0.1  2.7 269340 14000 ?        S    Mar01   5:38 /usr/sbin/httpd
apache   28998  0.1  2.6 274204 13616 ?        S    Mar01   9:11 /usr/sbin/httpd
apache    8767  0.1  2.1 273544 10756 ?        S    Mar03   2:53 /usr/sbin/httpd
apache   28976  0.1  1.9 273572  9740 ?        S    Mar01   9:32 /usr/sbin/httpd
apache   28877  0.2  1.4 274668  7308 ?        S    Mar01  10:14 /usr/sbin/httpd
apache   30506  0.1  1.1 273528  5688 ?        S    Mar02   4:12 /usr/sbin/httpd
 :
 :

 見て分かるように、httpdのプロセスが多数走っており、メモリを食いつぶしていることが分かる。そこで、httpdで使用するプロセス数を調整することで対処を図る。

<IfModule prefork.c>
StartServers       8
MinSpareServers    5
# MaxSpareServers   20
MaxSpareServers   16
#ServerLimit      256
ServerLimit      32
#MaxClients       256
MaxClients       32
MaxRequestsPerChild  4000
</IfModule>

 MaxSpareServersとMaxClientsを減らしてとりあえず様子見。

 なお、@ITの「httpd.confによるWebサーバの最適化」という記事などを参考にした。

EmacsでC#(csharp-mode)を使う

 EmacsでC#コードをいじりたかったのでcsharp-modeを導入した。

 csharp-modeはGoogle Codeのcsharpmodeプロジェクトから入手可能。

 とりあえず現時点での最新版「csharp-mode-0.7.6.el」をダウンロードし、csharp-mode.elにリネームして~/.emacs.d/lisp/以下にコピーし、.emacs.elに下記を追加した。

;; C# mode
(require 'csharp-mode)
(setq auto-mode-alist
      (append '(("\\.cs$" . csharp-mode)) auto-mode-alist))

 ちなみに私の場合、.emacs.el中で下記のように~/.emacs.d/lispをロードパスに追加しているが、そうでない場合はsite-lispディレクトリなどロードパスに含まれている場所にcsharp-mode.elを置く必要がある。

;; add ~/.emacs.d/lisp to load-path
(add-to-list 'load-path "~/.emacs.d/lisp")

 最後にEmacs上でM-x byte-compile-fileを実行してcsharp-mode.elを指定してバイトコンパイルして完了。これでC#のコードが色付き(ハイライト)で表示されるようになる。

Maildirでの日本語フォルダの扱い(procmailで日本語フォルダへ振り分ける)

 最近procmailでメールの振り分けをしているのだが、日本語のフォルダへの振り分けってどうするの? と悩んだので調べた。

 命名規則自体はRFC2060に記載されているとおり、UTF-7の修正版が用いられている(UTF-7についてはIT用語辞典を参照のこと)。

 Maildir以下のサブフォルダはこの規則に従って作成されるので、目的となる日本語フォルダ名を修正版UTF-7(IMAP-UTF7などとも呼ばれる)に変換し、それを振り分け先として指定すれば良い。

 IMAP-UTF7への変換は文字コード変換ツールがあるので、こちらを使えばお手軽。たとえば「登録関係」というフォルダなら、「.�dnuTMpWiT8I-」というフォルダ名となる。

Gitでブランチを間違えて作業した上にpushまでしちゃった場合の対処方法

 時間ができたのでHandBrake 0.9.5の日本語化に着手しているのだが、うっかり0.9.4のブランチで作業してしまったあげく、SourceForge.JP上のリポジトリにpushしてしまい途方に暮れる。

 まあこういうミスをやる人は少ないだろうが、何かのヒントになるかもしれないので対処法をメモしておく。まず、「git log」コマンドで巻き戻したいcommitのハッシュを調べる。

$ git log
 :
 :
commit 1485a5a2bbbb43eedbe131c919b7d604bcbd506d
Author: unknown <hirom@.(none)>
Date:   Tue Jan 5 19:19:44 2010 +0900

    update Installer, changelog, readme

 今回は、この「1485a5a2bbbb43eedbe131c919b7d604bcbd506d」というcommitまで巻き戻すことにする。作業中のブランチが操作したいものであることを確認したうえで、「git reset <対象のハッシュ>」を実行する。

$ git branch -a
  jp-0.9.3
* jp-0.9.4
  master
  original
  remotes/origin/HEAD -> origin/master
  remotes/origin/jp-0.9.3
  remotes/origin/jp-0.9.4
  remotes/origin/master
  remotes/origin/original

$ git reset 1485a5
Unstaged changes after reset:
M       Jamrules
M       Makefile
M       win/C#/Installer/Installer.nsi
M       win/C#/InstallerJp/doc/AUTHORS
M       win/C#/InstallerJp/doc/CREDITS
M       win/C#/InstallerJp/doc/NEWS
M       win/C#/Properties/AssemblyInfo.cs
M       win/C#/frmAbout.Designer.cs

 「git log」で巻戻ったことを確認する。

$ git log
commit 1485a5a2bbbb43eedbe131c919b7d604bcbd506d
Author: unknown <hirom@.(none)>
Date:   Tue Jan 5 19:19:44 2010 +0900

    update Installer, changelog, readme

 バージョン管理されているファイル自体は巻き戻されていないので、「-f」オプション付きでチェックアウトしてファイルも巻き戻す。

$ git checkout -f

 ここまでの作業でローカルブランチの巻き戻しは完了。続いてリモートブランチの巻き戻しを行う。ただし、当然ながらそのままpushすることはできない。

$ git push
Enter passphrase for key '/d/Users/hirom/.ssh/id_dsa':
To hylom@git.sourceforge.jp:/gitroot/handbrake-jp/handbrake-jp.git
 ! [rejected]        jp-0.9.4 -> jp-0.9.4 (non-fast-forward)
error: failed to push some refs to 'hylom@git.sourceforge.jp:/gitroot/handbrake-
jp/handbrake-jp.git'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes (e.g. 'git pull') before pushing again.  See the
'Note about fast-forwards' section of 'git push --help' for details.

 そこで、いったんリモートブランチを削除した上で再度pushする。まずは削除。リモートブランチの削除は、「git push <リモートリポジトリ> :<対象リモートブランチ>」で行える。

$ git push origin :jp-0.9.4
Enter passphrase for key '/d/Users/hirom/.ssh/id_dsa':
To hylom@git.sourceforge.jp:/gitroot/handbrake-jp/handbrake-jp.git
 - [deleted]         jp-0.9.4

 あとは再度ローカルリポジトリをpushするだけ。

$ git push origin jp-0.9.4:jp-0.9.4
Enter passphrase for key '/d/Users/hirom/.ssh/id_dsa':
Counting objects: 233, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (146/146), done.
Writing objects: 100% (165/165), 30.48 KiB, done.
Total 165 (delta 119), reused 0 (delta 0)
To hylom@git.sourceforge.jp:/gitroot/handbrake-jp/handbrake-jp.git
 * [new branch]      jp-0.9.4 -> jp-0.9.4

 お粗末様でした。

Pythonコード中のSQL文インデントを考える

 Pythonコード内にSQL文を書くときどうすれば良いのか、いまいち答えが探せなかったのでググって見た話。

 ちなみに、今までは下記のような感じのコードを書いていた訳だが、これ見るからに分かりにくい。

# コード例その1
        cur.execute("""
          create table count (
            sid text,
            count int);""")

# コード例その2
        try:
            cur.execute("""insert into count ( sid, count )
                           values ( :sid, :count );""", d)
        except sqlite3.IntegrityError:
            cur.execute("""update count set sid = :sid, count = : count
                           where sid = :sid;""", d)
# コード例その3
        cmd = """select sid, title, date from stories where date >= ? and date < ? and sid in (
                 select sid from topics where topic == ? and sid in (
                 select sid from topics where topic == ? )) order by date
        """
        cur.execute(cmd, (begin_t, end_t, t1, t2))

 「SQL インデント」でググると、そういう話のネタが一杯出てくるでてくる。その中から拾ってみたのが下記。

 異端だけど、俺的コーディングルール SQL編 – suVeneのアレというのも参考になった。

 で、この辺をまとめたところ、だいたい以下のようなルールに落ち着いた。

  • SQLキーワードは大文字で
  • 括弧挟まれた部分はインデントレベルを+1する
  • カンマ、ANDの直後で改行
  • カンマやANDでつなげられている部分はなるべくキーワード部分でそろえる

 このルールで書いたコードは下記のような感じ。

# コード例その1
        cur.execute("""
            CREATE TABLE count (
                sid text,
                count int
            );
        """)

# コード例その2
        try:
            cur.execute("""
                INSERT INTO count (
                     sid,
                     count
                )
                VALUES (
                    :sid,
                    :count
                )
            """, d)
        except sqlite3.IntegrityError:
            cur.execute("""
                UPDATE count
                SET sid = :sid,
                    count = : count
                WHERE sid = :sid
            """, d)
# コード例その3
        cmd = """
            SELECT sid,
                   title,
                   date
            FROM stories
            WHERE date >= ? AND
                  date < ? AND
                  sid IN (
                      SELECT sid 
                      FROM topics
                      WHERE topic == ? AND
                      sid IN (
                          SELECT sid
                          FROM topics
                          WHERE topic == ?
                      )
                  )
            ORDER BY DATE
        """
        cur.execute(cmd, (begin_t, end_t, t1, t2))

 

 本当にこれで良いのかはまだ自信がないが、おおむね間違ってはいないと思う。ていうかコード内にSQL文を直書きせずO/Rマッパー使え、という話もあるが……。

Emacs 23.2導入

 今までWindows環境での物書きにはNTEmacs JPプロジェクトがリリースしている<a href=https://sourceforge.jp/projects/ntemacsjp/releases/“>Emacs 22ベースのWindows向けバイナリを使っていたわけですが、最新安定版であるEmacs 23系ではマルチバイト文字の扱いを含めた色々な改善が加わっているとのことで、移行してみることに。

 NTEmacs JPプロジェクトではEmacs 23ベースのWindows向けバイナリをリリースしていないのですが、Gnupackというプロジェクトで日本語関連(というかIME)のパッチが適用されたEmacs 23.2のバイナリが公開されているので、そちらを利用。プロジェクトページはこちらNTEmacs 23.2はこちらからダウンロード可能。

 フォントなどの基本的な設定方法はEmacs 22系と同じ模様で、たとえばMSゴシックを使うには下記のような設定を.emacsに記述すればOK。

; 「msgochic」という名前で新たなフォントセットを定義
; 英字フォントとしてMS ゴシック、14ポイントを使用
(create-fontset-from-ascii-font
 "-outline-MS ゴシック-normal-r-normal-normal-14-*-*-*-*-*-iso8859-1"
 nil "msgochic")

; myfont-msgochicの日本語フォントとしてメイリオを使用
(set-fontset-font "fontset-msgochic"
                  'japanese-jisx0208
				  '("MS ゴシック" . "jisx0208-sjis"))

; myfont-msgochicのカタカナフォントとしてメイリオを使用
(set-fontset-font "fontset-msgochic"
                  'katakana-jisx0201
                  '("MS ゴシック" . "jisx0201-katakana"))

; 定義したフォントセットを登録
(add-to-list 'default-frame-alist
			 '(font . "fontset-msgochic"))

 あと、とりえあず様子見とのことでmule-ucs関係はすべて外してみましたが、今のところ問題は見られません。コピペで全角チルダ(~)が波ダッシュ(〜)になってしまう問題も解決されている模様。NTEmacs 22とは別のフォルダにインストールすることで共存も可能なので、ひとまずこれで様子見。

要ログインのサイトにPythonのurllib2でアクセスする

 ログインが必要なWebサイトに対してスクリプトでページを取得/送信したい場合、まずログイン用のURLに対しログイン情報をPOSTしてCookieを取得する、という作業を行うのが一般的だ。しかし、Pythonのurllib2を利用すると簡単にPOSTは行えるのだが、なぜかCookieを取得できない、という問題が発生することがある。

 これはurllib2のurlopen()でURLを開き、帰ってきたオブジェクトのinfo()メソッド経由でSet-Cookieヘッダを取得しようとする場合に発生する。たとえばCMSを使用しているWebサイトで、管理用ページ以外に(正当な)Cookieを持たずにアクセスするとCookieなしでアクセスできるトップページ等にリダイレクトされる、というケース。多くのCMSではログインに成功すると管理ページトップにリダイレクトされるのだが、urllib2のデフォルト設定ではCookie処理を行ってくれない&リダイレクトを自動的に処理してくれるため、「ログイン成功→(Cookieを返すがurllib2はCookieを保存せず)→管理ページトップにリダイレクト→Cookieがないので公開ページのトップにリダイレクト→Cookieは受け取れず」という事態になってしまうことがある。

 この場合、urllib2.HTTPCookieProcessorを使ってCookie処理を行えばよいのだが、なぜかurllib2のドキュメントにはこのクラスの解説が無い。例にも上がっていない。ということで途方にくれるわけだが、実はCookieを扱うcookielibのほうに使い方の例が載っていたりする。

import cookielib
# : 
# (このへんでurlやencoded_data、headersを準備)
# :
req = urllib2.Request(url, encoded_data, headers)
cj = cookielib.CookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
resp = opener.open(req)

 取得したCookieはCookieJarオブジェクトに保存されるので、必要に応じて適宜取り出せばOK。かわりにFileCookieJarオブジェクトを使えばファイルへのsave/loadも可能。

DSエミュで(合法的に)遊ぶ

 最近DeSmuMEなるニンテンドーDSエミュレーターが(一部で)ブームらしい。Googleトレンドの検索結果を見てもその盛り上がりは明らかで、2010年9月中旬(というか9月18日)に大きな山があることが分かる。この9月18日はポケモン新作の発売日ということで、まぁなんだかなぁ、という感じではあるのだが……。

DeSmuMEのトレンド

DeSmuMEのトレンド

 で、ニンテンドーDSエミュレーターというと数年前に触ったときはまだまだ完成度が低く、とても市販のゲームが動かせる状況ではなかったのだが、現在では完成度が上がり、結構色々と動作するらしい。ということで、とりあえず久しぶりに試して見ようと思ったら色々とはまったのでメモ代わりにご紹介。

DeSmuMEほかの入手

 まずはDeSmuMEの入手法だが、DeSmuMEのダウンロードから入手できる。Windows/Mac OS X/Linux/ソースが公開されているので、適当なものをどうぞ。Windows版の場合、ZIPで圧縮されているだけなので適当に展開すればOKだ。

 続いて動かすアプリの入手。最近では完成度の高いHomebrew(非オフィシャルな開発ツールを使って有志が制作したソフトの総称。ほとんどが無料で公開されている)も増えてきており、とりあえず評価の高いペイントソフト「Colors!を試して見ることにした。

Colors!の設定

 Homebrewソフトは拡張子が「.nds」という形式のファイルで配布されており、通常はこれをDeSmuMEにドラッグ&ドロップすればソフトを起動できるのだが、Colors!の場合はファイルI/OにDLDIという仕組みを使用しており、先にこれの設定を行う必要がある。

 DLDIはDS用のストレージデバイス(マジコンなどと呼ばれているもの)用I/Oドライバのようなもので、使用するストレージデバイスに対応した「パッチ」を.ndsファイルに適用しておく必要がある。DeSmuMEの場合、「GBA Movie Player (Compact Flash)」を利用せよとのことなので、まずここからmpcf.dldiをダウンロードする。また、パッチを適用するためのツール「Dlditool-win32-gui」もダウンロードしておく。これはWindows用のGUIツールなので、ほかのOSを使っている場合は適当なものを選んでほしい。

 Dlditool-win32-guiを適当な場所に展開し、「dlditool32.exe」を実行すると「DLDI Patcher v0.32」というウィンドウが表示される。「DLDI File」で先ほどダウンロードしたmpcf.dldiが含まれるフォルダを選択し、「Binaries」でColors!に含まれる「HBMenu.nds」を指定する(ファイルのドラッグ&ドロップでも指定可能)。最後に「Patch」ボタンをクリックすればパッチ完了となる。

DLDI Patcherでパッチを適用

DLDI Patcherでパッチを適用

ディスクイメージファイルを作る

 さて、本来ならあとはHBMenu.ndsファイルをDeSmuMEで開き、メニューから「colors.nds」を選択すればソフトが起動するはずなのだが、DeSmuMEの問題なのかそれともDLDIの問題なのか、Colors!を起動すると「ストレージに書き込めない」という旨のメッセージが出て操作できなくなってしまう。どうもWindows側のフォルダをそのままストレージとして利用するあたりが問題のようなので、ディスクイメージファイルを作成し、ファイル一式をそこに格納することで対処することにする。

 ディスクイメージの作成・操作だが、残念ながらWindowsで動作する適切なものは発見できなかった。しょうがないのでMac OS X上でディスクイメージを作成&マウントし、そこでファイルをコピーしたあとでWindows機に転送する、という方法で対処する。

 Mac OS Xでは、「ディスクユーティリティ」を使用して簡単にディスクイメージを作成したり、マウントできる(Linuxでもルート権限があれば比較的容易に作業可能だが今回は割愛)。

Mac OS Xのディスクユーティリティでディスクイメージ作成

Mac OS Xのディスクユーティリティでディスクイメージ作成

 「フォーマット」で「MS-DOS(FAT)」を、「パーティション」で「パーティションマップなし」を選択するのがポイント。容量はお好みでどうぞ。

 ディスクイメージを作成・マウントしたら、Colors!の配布アーカイブに含まれるファイル一式をそこにコピーし、アンマウントしてディスクイメージをWindows側にコピーすれば作業完了。

ディスクイメージを使用する設定

 あとはDeSmuMEを起動し、「エミュレーション」メニューの「GBAスロット」を選択して「GBAスロット」ウィンドウを開き、「Compact Flash」を選択して作成したイメージファイルを指定すればOK。

「GBAスロット」でディスクイメージを指定

「GBAスロット」でディスクイメージを指定

 ただし、DeSmuME 0.9.6のWindows版の場合、ここで設定した値が反映されないというバグがあるので、ここでファイルを指定した後いったんDeSmuMEを終了し、DeSmuME.exeと同じディレクトリ内にある「desmume.ini」をテキストエディタで開いて次の個所を修正する必要がある。

[GBAslot.CFlash]
fileMode=1  ←「1」に設定
path=C:\work\desmume\
filename=C:\work\desmume\test.dmg

 以上でやっと全作業工程は完了。パッチを適用したHBmenu.ndsをDeSmuMEで開き、メニューから矢印キーで「Colors.nds」を選択してXキーを押せばColors!が起動する。

HBMenuからColors!を起動する

HBMenuからColors!を起動する

Colors!をDeSmuMEで実行

Colors!をDeSmuMEで実行

 ちなみに、実機で動かす場合は自動的にDLDIドライバが選択されるはずなので、パッチ作業は不要らしい(確認していないので本当かどうかは不明)。

x86_64版CentOS 5.5で64ビット版FirefoxでJavaプラグインを使う

 x86_64版CentOS 5.5のFirefoxでのJavaプラグイン導入に軽くハマったのでメモ。

 x86_64版のCentOS 5でFirefoxにJavaプラグインを導入したい場合、ググると「32ビット版Firefox+32ビット版Javaランタイムを使え」という話がぼちぼちとヒットするわけですが、とりあえずJavaプラグインだけを使いたい場合は64ビット版でも可能なようです。ていうか自分の場合、32ビット版を導入しようとしたらうまくいきませんでした……。

 ということで、手順。まず64ビット版Firefoxをインストール。

$ sudo yum install firefox  # 64ビット版Firefoxをインストール

 続いてjava.comのダウンロードページから「Linux x64 RPM」をダウンロード。

「Linux x86 RPM」をダウンロードする

「Linux x86 RPM」をダウンロードする

 RPMと書いてあるが、ダウンロードしたファイルはRPMではなくインストーラなので、root権限で実行してインストール。自動的にRPMがインストールされる。

$ chmod +x jre-6u21-linux-x64-rpm.bin
$ sudo ./jre-6u21-linux-x64-rpm.bin

 続いて設定。インストールしたjreを利用するようalternativesコマンドで指定。

$ sudo /usr/sbin/alternatives --install /usr/bin/java java /usr/java/jre1.6.0_21/bin/java 2
$ sudo /usr/sbin/alternatives --config java

 最後にmozilla用プラグインフォルダにプラグインのシンボリックリンクを張って完了。

$ cd /usr/lib64/mozilla/plugins/
$ sudo ln -sf usr/java/jre1.6.0_21/lib/amd64/libnpjp2.so .

 あとはFirefoxでabout:pluginsを開きプラグインが正しくインストールされているか確認したり、java.comにアクセスして動作を確認するなり適当にどうぞ。

あまり知られてない(ような気がする)sshの多重接続

 OpenSSH 5.6/5.6p1リリースの記事をチェックしているとき、リリースノートの「多重(multiplex)接続」ってなんじゃこれ、と思い調べてみたんですが、なかなかに有用なのでちょいとまとめてみました。というか、元ネタはこちらのSSH: Tips And Tricks You Needという記事です。

 多重接続というのは、1本のSSHコネクションで複数のセッションを同時に張るという感じのもの。たとえば、OS Xでターミナルを複数開き、それぞれのターミナルウィンドウで1つのサーバーに対しsshコマンドで接続を行った場合、通常はサーバー側では複数のsshdが起動し、それぞれのsshクライアントと通信を行います。いっぽう、多重接続を利用すると1つのsshdが複数のsshと通信する形となり、サーバー側のリソースをより効率的に利用できる、というわけ。

 設定は簡単で、クライアント側の.sshディレクトリに設定ファイルと一時ディレクトリを用意するだけ。

$ cd ~/.ssh
$ mkdir connections
$ chmod 700 connections/
$ vim config

 ~/.ssh/configの内容は下記のとおり。

Host *
ControlMaster auto
ControlPath ~/.ssh/connections/%r_%h_%p

 あとは、通常通りsshでサーバーに接続するだけ。これだけで、体感できるほど2つめ以降の接続が高速化されます。下記は5つのSSHセッションを張った状態で、6つめのセッションを張ろうとした際の実行速度ベンチマーク。

多重化なし:
$ time ssh hylom.******.com uptime
 08:13:53 up 22 days, 10:18,  6 users,  load average: 0.00, 0.00, 0.00

real	0m2.123s
user	0m0.015s
sys	0m0.010s
多重化あり:
Last login: Tue Aug 24 17:15:34 on ttys006
$ time ssh hylom.******.com uptime
 08:18:53 up 22 days, 10:23,  6 users,  load average: 0.00, 0.00, 0.00

real	0m0.278s
user	0m0.006s
sys	0m0.007s

 多重化により、だいたい7.6倍くらい速くなっています。ちなみに、この状態で「ps ux」を実行してみるとこんな感じに。

$ ps ux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
hylom    17182  0.2  0.2   8292  1580 ?        S    08:21   0:00 sshd: hylom@pts
hylom    17183  0.0  0.2   2968  1584 pts/0    Ss+  08:21   0:00 -sh
hylom    17188  0.0  0.2   2968  1584 pts/1    Ss+  08:21   0:00 -sh
hylom    17193  0.0  0.2   2968  1584 pts/2    Ss+  08:21   0:00 -sh
hylom    17198  0.0  0.2   2968  1588 pts/3    Ss+  08:21   0:00 -sh
hylom    17203  0.0  0.2   2968  1580 pts/4    Ss+  08:21   0:00 -sh
hylom    17208  1.0  0.3   3484  1856 pts/5    Ss   08:21   0:00 -sh
hylom    17213  0.0  0.1   2432   908 pts/5    R+   08:21   0:00 ps ux

 sshdは1つだけで、接続毎にシェルだけが起動されるようになっていることが確認できます。

gitメモ:ブランチを切ってないのにやばいコードを書いちゃった場合

 gitを使ってコードの管理をしている場合において、実験的なコードを書く場合はソースコードを編集する前にブランチを作成しておくのが基本だ。しかし、ついブランチを作成し忘れたままでコードを変更してしまった、というパターンがある。

 この場合、下記のようにgit stashでいったん変更点を保存した上で直前のcommitに戻し、新たなブランチを作成してそこでgit stash applyを行えばよい。

$ git stash
$ git checkout hogehoge -b
$ git stash apply
$ git add hogehoge foobar
$ git commit

 git stash、便利だ。

iPhone 4およびiPad向け動画をHandBrakeで作る

 先日、私の手元にもiPhone 4が到着。ということで、一部から要望を受けていたHandBrakeのiPhone 4用プロファイルをちょっと調査・研究してみた。

 iPhone 4の動画再生機能については、Webサイトにその仕様が掲載されている(日本語のiPhoneページ)。ただし、日本語ページには一部誤訳というか不明瞭な表記があるたので、英語版iPhoneページを確認するほうが確実。これによると、iPhone 4の動画再生仕様は下記の通り。

  • H.264:最大720p、30fps。Main Profile(レベル3.1まで、音声はAAC-LCで最大160kbs、48kHz、ステレオ)対応。ファイルフォーマットは.m4v、.mp4、.mov
  • MPEG-4:最大2.5Mbps、640×480ピクセル、30fps。Simple Profile(音声はAAC-LCでチャンネルあたり最大160kbps、48kHz、ステレオ)対応。ファイルフォーマットは.m4v、.mp4、.mov
  • MotionJPEG(M-JPEG):最大35Mbps、1280×720ピクセル、30fps。音声はulawもしくはPCMステレオ。ファイルオーマットは.avi

 iPhone 4の画面サイズは960×640。そのため、縦に持った際は幅640に、横に持った際は幅960に自動的に拡大/縮小されて表示される。また、iPhone 4のドックコネクタ経由での出力では1024×768サイズの出力に対応している模様。

 ちなみに、iPhone 4の動画再生仕様はiPadとまったく同一のようだ。なお、iPadの画面サイズは1024×768である。

 さて、iPhone 4で動画を見る場合、わざわざ容量がかさむMPEG-4を積極的に使う必要はない。そのため、下記ではH.264についてのみ考察を行っていく。

 上記のとおり、iPhone 4はスペック上はHigh Profileには対応していない。しかし、試して見たところHandBrake 0.9.4のプリセットである「High Profile」でエンコードした動画も問題なく再生できてしまった。High ProfileとMain Profileの違いは8x8DCTブロックやカスタム量子化マトリックス(CQM)、Cb/Cr別のQP制御、モノクロ(4:0:0)対応だが、実際8x8DCT以外については、設定の難しさの割に効果は微妙なところではある(そのうえHandBrakeでは設定できない)。

 High Profile非対応という機器でも8x8DCT対応のものはあるので、iPhone 4/iPadもそうなのだろう。HandBrakeでは「High Profile向け」と表示される「Pyramidal B-Frames」については、High ProfileでもOffになっているので気にしないことにする。

 ということで、とりあえずHandBrakeでiPhone 4およびiPad向けのエンコードを行う場合、プリセットのHigh Profile設定を利用すれば問題ないようだ。

 対応する縦横サイズやビットレートに関連する「レベル」については次の機会に。

激安・低サポートのVPS「prgmr.com」を借りる

 最近、月額490円からの「ServersMan@VPS」が話題だ。ほかにも980円からの「FC2 VPS」など、低価格のVPSはいくつかあるが、それ以前から存在する低価格のVPSサービスとして一部の間で知られていたのが「prgmr.com」である。

 prgmr.comはXenを使用したVPSで価格は$5/月からと低価格なのが魅力の1つだが、安さだけなら国内のVPSサービスと大きくは変わらない。ではなぜprgmr.comが注目されているのかというと、そのアレなたたずまいと、サポートの簡素さによるところが大きい。prgmr.comのトップページにはほかのVPSサービスのような画像による装飾は一切なく、アスキーアートで書かれた「prgmr.com」というバナーと「We don’t assume you are stupid.」という文言、そして料金やXenベースVPSの特徴が紹介されているのみ。一般人ならとりあえずこのサイトが何であるかも理解できないだろう、という作りである。

 このようにアレゲ感たっぷりのprgmr.comであるが、その一方でかなり自由度は高く、OSはDebian GNU/Linux、Ubuntu 10.04、CentOS 5.5が選択できるほか、AMD64アーキテクチャのXen上で動作するOSなら(自力で)任意のOSがインストールできる(可能性がある)、追加料金なしでグローバルIP付与と、独自のサーバー管理&Xenが分かる人にとってはかなり魅力的であったりする。

 ということで一部の人には魅力的なこのprgmr.com、ちょくちょく新規受付を開始しては定員に達して終了を繰り返しており、いつでも申し込みできるというわけではないのだが、ウォッチしていたらたまたま申し込み可能になっていたため、$12/月でメモリ512MiB、ディスク12GiB、月間ネットワーク転送量80GiBのプランを申しこんでみた。

Webでの申し込み後、メールでSSH公開鍵を送付。サーバー設定は必要十分

 Webで利用したいプランを選択し、オンラインフォームに必要事項を記入して申し込むと、下記のように利用したいディストリビューションとOpenSSH公開鍵を送信しろ、という旨のメールが来る。

you ordered a xen vps, 512MiB ram, 12GiB Disk 80 GiB transfer Xen VPS, $12/month username hylom

Before I can set you up, I need to know what distro you would like and an OpenSSH format public key (on a *NIX, run ssh-keygen and send me either the id_dsa.pub or id_rsa.pub file in an attachment)

 あとはこのメールの返信として公開鍵を添付し、Debian GNU/Linuxを使いたいという旨を伝えるだけだ。

Hi,

I want to use Debian GNU/Linux, and here’s my SSH public key.

Please check it.

 設定が完了すると、その旨がメールで連絡される。また、しばらくすると金払ってねメールがやってくる模様。料金の支払いはPayPal。

 続く。

オープンソースなデバッガのニューカマー「lldb」、LLVMのサブプロジェクトとして登場

 ここ数年注目されているコンパイラ環境「LLVM」が、サブプロジェクトとして「LLDB」なるデバッガを開発するよとアナウンスしている(LLVM Project Blog)。

 LLVMは「コンパイラインフラストラクチャ」という形で開発が進められているのだが、このLLDBは現代的な「デバッガインフラストラクチャ」とのことで、モジュラー化構造や再利用しやすいライブラリが特徴らしい。LLDBはLLVMの技術やAPI、パーサー、コードジェネレータ、JITコンパイラなどを利用して構築されているとのこと。

 現在は開発中の段階で、Mac OS Xでのコマンドラインでのデバッグのみに対応しているとのことだが、scriptableだったり、マルチスレッド対応など面白い話もある。さらに現状ではGDBよりも高速だそうで、特にC++プログラマにとっては使いやすいものになっているらしい。

コンテンツのロードを高速化するHTML5の「link prefetching」機能

 keyboardyによると、HTML5にはlink prefetching機能があり、指定したコンテンツをあらかじめfetchしておく機能があるそうだ。

 fetchするコンテンツはLINKタグで指定する。たとえば、次のようなLINK要素をHTML内に記述しておくと、ロード時に「page2.html」がfetchされる。

<link rel="next" href="page2.html">

 また、次のように明示的にprefetchを指定することもできる。

<link rel="prefetch" href="/img/img.jpg">

 この機能はすでにFirefoxでは実装済みで、OperaやChrome、Safariでもすぐにサポートされるのでは、とのこと。Internet Explorerでは2020年代まで利用できないかも;-) だそうだ。

 ちなみにMozillaのlink prefetchingに関するドキュメントによると、HTTPヘッダーでも次のようにしてprefetchするコンテンツを指定できる。

Link: </images/big.jpeg>; rel=prefetch

 さらに、METAタグでも指定できる。

<meta http-equiv="Link" content="</images/big.jpeg>; rel=prefetch">

 また、 Firefoxの場合、http://で始まるURLのみに対応し、https://はセキュリティ関連の理由のためprefetchされない。また、FTPなどもprefetch対象外。prefetchはブラウザがidle状態で、たとえばコンテンツのローディングやダウンロードが行われている間は行われないそうだ。あとはユーザー設定でFirefoxのprefetchを無効にできるとか、prefetchリクエストは「X-moz: prefetch」ヘッダー付きで送信されるとか色々あるが、その辺は上記のドキュメントを参照。

Pythonで被はてなブックマーク数を取得する

 Pythonのxmlrpclibモジュールで、指定したURLの被はてなブックマーク数を取得する例。簡単ですね。

 server.bookmark.getCount()はURLをキー、被はてブ数の値とするdictionaryの形で返してくれるので、返ってきたデータの参照も楽勝です。URLの一覧を引数の形で与えなければならないのがなんか引っかかりますが……。

#!/usr/bin/env python

import xmlrpclib


def main():
    uri = "http://b.hatena.ne.jp/xmlrpc"
    server = xmlrpclib.ServerProxy(uri)
    urls = ("http://sourceforge.jp/magazine/10/04/26/0244255",
             "http://sourceforge.jp/magazine/10/04/27/0326224",
             "http://sourceforge.jp/magazine/10/04/30/0243232")

    t = server.bookmark.getCount(*urls)
    for item in t:
        print item, t[item]

if __name__ == "__main__":
    main()

Pythonのwith構文と__enter__、__exit__

 Pythonのwith構文がいまいち掴めなかったので、ざっとまとめてみた(いまさらながら)。ドキュメントはPython リファレンスマニュアルの7.5 with 文にある。

 withを使ったコード例は、下記のような感じ。

c = ClassHogeHoge()
with c:
    c.foobar()

 上記のコードは、下記と等価となる。

c = ClassHogeHoge()
c.__enter__()
c.foobar()
c.__exit__()

 つまり、withに続くインデントブロックを実行する前に指定したオブジェクトの「__enter__()」メソッドを呼び出し、実行後に「__exit__()」メソッドが暗に呼び出される、という仕組み。

 __enter__()と__exit__()の定義は、Python リファレンスマニュアルの3.4.9 with文とコンテキストマネージャにある。__enter__()の引数はselfのみだが、__exit__()はself、exc_type、exc_value、tracebackの4つの引数をとる。withに続くインデントブロックが正常に実行された(つまり、例外が送出されなかった)場合、(self以外の)引数にはNoneが与えられる。なにか例外が発生した場合、その例外に関する情報が与えられるらしい。

 また、「with hogehoge as foo:」のような形でwith文を利用する場合、__enter__()の戻り値がfooに代入される。__exit__()の戻り値は例外処理の伝搬制御に使われ、Falseの場合例外が発生た場合でも例外を伝搬させず、Trueを返すと例外が伝搬されるとのこと。

 下記、使用例。

class CacheDB(object):
    DB_FILE = "database/db_dat"

    def __init__(self):
        self.con = None
        self.cur = None

    def __enter__(self):
        self.con = sqlite3.connect(self.DB_FILE)
        self.cur = self.con.cursor()

    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type:
            self.con = None
            self.cur = None
            return False
        self.con.commit()
        self.cur.close()
        self.con.close()
        self.con = None
        self.cur = None
        return True

    def add(self, foo, bar, hoge):
        try:
            self.cur.execute("""insert into data ( foo, bar, hoge )
                           values (?, ?, ?);""", (foo, bar, hoge))

def main():
    usage = "%s logfile" % sys.argv[0]
    db = CacheDB()
    try:
        fname = args[0]
    except IndexError:
        sys.exit(usage)

    f = open(fname, "r")
    with db:
        for l in f:
            term = l.strip().decode("utf-8").rsplit("\t", 3)
            db.add(foo=term[0],
                   bar=term[1],
                   hoge=term[2])

if __name__ == '__main__':
    main()

 タブ区切りのデータファイルを1行ずつ読んでデータベースに突込む、という処理。withを使うことで、データベースアクセスの準備→データ挿入→コミットという流れをきれいに実装できました。

日本語リファレンスには書いてない話:urllibとurllib2の違いってなんだ

 Pythonでは、HTTPやFTPなどでファイルの送受信をするモジュールとして「urllib」と「urllib2」が用意されている。使い方も似ていて、どちらも引数としてURLを与えてurlopen()関数を呼び出すと自動的に対応したプロトコルでURLにアクセスしてデータを読み出せる、というものである。しかし、似たような名前で似たような機能を持つこの2つ、何が違うのかが明確にはドキュメントに記述されていない。そのためどちらを使うべきか迷って、そのたびにGoogleのお世話になるという状況だったのでざっとまとめてみよう。

外から見える違いとしては、urlopen()の引数としてurllibはURL文字列のみを受け付けるのに対し、urllib2ではurllib2.Requestクラスを受け取ることができる、という点がある。urllib2.Requestクラスはリクエストを抽象化したクラスで、これを利用することでたとえばHTTPでのデータ送受信の際、任意のHTTPヘッダーを送信させるようなことが可能になる。また、urllibでは使用するproxyを直接引数で指定できるが、urllib2ではRequestオブジェクトで指定することになる。

 ということで、ただHTTPやFTPでデータを取得したいだけならurllibでもurllib2でもどちらでも対して変わらない、HTTPヘッダーをカスタマイズしたいならurllib2を使え、という話になる。あと、urllibにはurlretrive()という関数があったり、quote()/unquote()/urlencode()などの便利そうなユーティリティ関数がある、というくらい。

独自プロトコルを実装したい場合は?

 いっぽう、挙動をカスタマイズしたい、独自プロトコルを実装したい、という場合は話が変わってくる。urllibもurllib2も独自プロトコルへの対応などのカスタマイズが可能なのだが、urllibはFancyURLopenerクラスの派生クラスで実装を行うのに対し、urllib2はBaseHandlerクラスの派生クラスで実装する。

 まず、urllibの場合。ドキュメントに記載されている例だが、たとえばUser-Agentを変更したい場合、下記のようにFancyURLopenerの派生クラスを作り、その初期化時に指定したいUserAgentをversion変数に代入するようにする。そして、この派生クラスのインスタンスをurllib._urlopenerに代入してやる。

import urllib

class AppURLopener(urllib.FancyURLopener):
    def __init__(self, *args):
        self.version = "App/1.7"
        urllib.FancyURLopener.__init__(self, *args)

urllib._urlopener = AppURLopener()

 これにより、以後はurllib.urlopen()などを呼び出した際、urllib._urlopener()で指定したインスタンスを使用してHTTP/FTPなどの処理が行われるようになる。

 ちなみに、FancyURLopenerとURLopenerの関係だが、HTTP/HTTPS/FTPなどの基本的な通信/データ取得処理はURLopener内で実装されており、FancyURLopenerはそれに各種HTTPレスポンスコードへの対応やリトライといった処理を実装したサブクラスとなっている。

 またドキュメントには記述されていないが、URLopenerにはaddheader()というメソッドが用意されており、ヘッダー名をキー、与えるデータを値にした辞書を引数として与えることで、任意のヘッダーを追加できる。

def addheader(self, *args):
        """Add a header to be used by the HTTP interface only
        e.g. u.addheader('Accept', 'sound/basic')"""
        self.addheaders.append(args)

 たとえばURLopenerの__init__()内では、次のようにしてUser-Agentを指定している。

self.addheaders = [('User-Agent', self.version)]

 なおURLopenerでは、urlopen()でHTTP/HTTPSのURLを与え、かつ第2引数が非Noneの場合(つまり、なんらかのデータを与えた場合)は「Content-Type: application/x-www-form-urlencoded」でのPOSTリクエストを利用するようにハードコーディングされている。そのため、ほかの形式でデータをPOSTしたい場合(ファイルを送信するなど)は、独自のURLopenerを作成する必要がある。

urllib2で独自プロトコルを使うには?

 いっぽうurllib2で独自のプロトコルを扱いたい場合、まずプロトコルを実装したBaseHandler()派生クラスを用意し、続いてそれを引数として与えてbuild_opener()を呼び出してURLハンドラを作成、最後にそれをinstall_opener()引数に与えて登録、という手順となる。下記はドキュメントに記載されている例だ。

import urllib2
# ベーシック HTTP 認証をサポートする OpenerDirector を作成する...
auth_handler = urllib2.HTTPBasicAuthHandler()
auth_handler.add_password('realm', 'host', 'username', 'password')
opener = urllib2.build_opener(auth_handler)
# ...urlopen から利用できるよう、グローバルにインストールする
urllib2.install_opener(opener)
urllib2.urlopen('http://www.example.com/login.html')

 なお、urllib2の(デフォルトの)HTTP/HTTPSハンドラでも、urlopen()の第2引数が非Noneの場合(つまり、なんらかのデータを与えた場合)は「Content-Type: application/x-www-form-urlencoded」でのPOSTリクエストを利用するようにハードコーディングされている。そのため、ほかの形式でデータをPOSTしたい場合(ファイルを送信するなど)は、やっぱり独自のハンドラを作成する必要がある。

 ちなみに、Python3系ではPython2系のurllibは廃止され、urllib2もurllib.requestという名称に変更されている。ということで、Python3系を見据えるならurllibではなくurllib2を利用するのが望ましいようだ。

Mako Templaters for Pythonメモ1:Makoってなに?

 最近Pythonのテンプレートエンジン「Mako」を触ってるんだけど、日本語の情報が全然ないのでまとめてみる。

Mako公式Webサイト

Mako公式Webサイト

Makoは「Hyperfast and lightweight templating for the Python platform.」(Pythonプラットフォーム向けの超高速で軽量なテンプレートエンジン)だ。Pythonのテンプレートエンジンとしては、Python標準ライブラリに含まれているstring.Templateや、WebフレームワークのDjangoに組み込まれているDjangoテンプレートエンジン、そしてCheetahなどが知られているが、Makoはそれらよりも高速で、テンプレート内にPythonコードを埋め込む機能や、キャッシュ機構などを備えてるのが特徴だ。また、文法もPython風であり習得しやすいのも利点だろう。

 いっぽう、特に大きな欠点は(いまのところ)見つかっていないのだが、日本語環境で利用する場合は文字コードをうまく扱うように適切にオプションを与える必要がある。

 ちなみに、MakoのWebサイトにはPython向けテンプレートエンジンのパフォーマンス比較が掲載されているのだが、ほかのテンプレートエンジンと比べてMakoは同等レベル以上に高速、という結果が出ているようだ。

Makoのインストール

 Makoはダウンロードページから行える。配布されているtar.gz形式のソースコードをダウンロードしてインストールできるほか、Pythonモジュール用のインストールマネージャ「easy_install」を利用してもインストールできる。

 ソースコードからインストールする場合は、ダウンロードしたアーカイブを展開し、次のように実行する。

# python setup.py install

 ちなみに、makoはすべてPythonコードで記述されているため、基本的にはPythonが動く環境であればどのプラットフォームでも動作するはずだ。

 つづく。

IE8の検索ボックスから英語版Googleを利用する

 Internet Explorer 8を最初に起動して、真っ先にやるのが検索エンジン(検索プロバイダ)の指定なんですが、日本語の検索プロバイダページにあるGoogleを指定してしまうと、自動的に「日本語のページを検索」になってしまうのが微妙なところ。

ということで、全言語を対象にGoogle検索を行うには、英語版の検索プロバイダページから「Google Search Suggestions」をインストールしましょう。

英語版のIE検索プロバイダページ

英語版のIE検索プロバイダページ

 以上、小ネタでした。

Windows 7の評価版仮想ハードディスクイメージを日本語で使う

 Microsoftが、Windows 7の90日期間限定評価版がインストールされた仮想ハードディスクイメージ(Windows 7 90-Day Eval VHD)を無償公開している。窓の杜の記事などでも紹介されているが、これは同じくMicrosoftがWindows環境向けに無償提供しているVirtual PC上で利用できるもので、(期間限定、評価目的限定ではあるものの)ライセンスの問題なしにWindowsの仮想環境を構築できる。多くのソフトウェアのインストール/アンインストールを繰り返すライターや、クリーンな環境で動作確認を行いたいようなソフト開発者にとって非常に便利なソリューションだ。

ただし、注意しなければ行けないのが、現状公開されているのは英語版のEnterprise Editionのみという点。といっても、インストール後に日本語言語ファイル(Multi User Interface、MUI)をWindows Update経由でインストールし、いくつかの設定を行えば日本語版とほぼ同じインターフェイスに変更できる。ということで、以下ではWindows 7 90-Day Eval VHDを日本語化する手順をメモ代わりに解説しておこう。

日本語化されたWindows 7 90日試用版

日本語化されたWindows 7 90日試用版

Windows 7 90-Day Eval VHDのダウンロードとインストール

 まずはMicrosoftのダウンロードページから、Microsoft Windows 7 90-Day Eval VHDをダウンロードする。なお、ダウンロードには正規版のWindowsが必要で、ダウンロード時に認証がかかるのでIEでダウンロードするほうが良いかもしれない。また、インストーラは3ファイルに分割されていて、合計で約1.8GBと大きいので、ダウンロード時にはHDDの残量に注意。

 ダウンロード後、3つのファイルを同じフォルダに保存して「Windows7Fullx86Ent90Days.part1.exe」を実行すると「Windows7Fullx86Ent90Days」というフォルダが作成され、その中の「Virtual Hard Disks」ディレクトリ内にある「Win7ENT90DAYS.vhd」がWindows 7がインストールされた仮想ハードディスクイメージとなる。

Windows 7 30日評価版の仮想ハードディスクイメージ

Windows 7 30日評価版の仮想ハードディスクイメージ

Virtual PCのインストール

 続いて、Virtual PCのインストールを行う。Windows 7でVTが利用できる環境の場合は、Windows Virtual PCを、それ以外(Windows 7でVTが利用できない環境およびWindows Vista、XP)の場合、Virtual PC 2007を利用する。それぞれのインストールについては割愛(ダウンロードしてインストーラを実行するだけ)。

仮想マシンの作成(Windows 7+Windows Virtual PC環境)

 Virtual PCのインストールが終わったら、仮想マシンを作成する。以下はWindows 7+Windows Virtual PCの場合。それ以外の場合は適当にググっていただきたい(汗)。

 Windows 7の場合、「<ユーザーのホームディレクトリ>\仮想マシン」というフォルダでWindows Virtual PCの操作を行う。まずはコマンドバーの「仮想マシンの作成」をクリックする。「仮想マシンを作成します」というウィザードが表示されるので、仮想マシン名とその保存先、メモリとネットワーク、仮想ハードディスクの設定を行う。マシン名は適当。メモリは1GBくらいは欲しいところ。最後の「仮想ハードディスクの追加」では、「既存の仮想ハードディスクを使用する」を選択し、「参照」をクリックしてWindows 7 90-Day Eval VHDの仮想ハードディスク(Win7ENT90DAYS.vhd)を指定する。

「仮想マシンの作成」で仮想マシンを作成する

「仮想マシンの作成」で仮想マシンを作成する

「仮想ハードディスクの追加」で「既存のハードディスクを使用する」を選択し、Windows 7のVHDファイルを選択する

「仮想ハードディスクの追加」で「既存のハードディスクを使用する」を選択し、Windows 7のVHDファイルを選択する

 以上で仮想マシンの作成は完了。作成された仮想マシンをダブルクリックすると、設定等に問題がなければ英語版Windows 7 Enterprise Editionが起動する。

 続いてWindows 7のセットアップを行う。始めにセットアップ画面が表示されるので、「Country or region」を「Japan」、「Time and currency」を「Japanese(Japan)」、「Keyboard layout」を「Japanese」に設定して「Next」をクリックする。なお、Virtual PCのウィンドウをクリックするとマウスポインタがVirtual PC内のWindows 7に取られてウィンドウ外に出せなくなる。ウィンドウ外にマウスポインタを出したい場合はAlt+Tabを押せばOK。あとは通常のWindows 7のインストールと同様にセットアップを進めていく。

セットアップ画面で「Japan」/「Japanese」を選択する

セットアップ画面で「Japan」/「Japanese」を選択する

統合コンポーネントのインストール

 セットアップが完了したら、Windows Virtual PCの 「ツール」−「統合コンポーネントのインストール」を実行して統合コンポーネントをインストールしておく。これにより、Windows Virtual PC内外でマウスがシームレスに動くようになる。

Virtual PCの「ツール」メニューから「統合コンポーネントのインストール」を選択する

Virtual PCの「ツール」メニューから「統合コンポーネントのインストール」を選択する

 「統合コンポーネントのインストール」を選択すると確認ダイアログが表示され、「続行」をクリックすると仮想PCにインストールDVDがマウントされるので、「Run setup.exe」をクリックする。ウィザードが起動するので、「Next」をクリックしてインストールを進める。完了したら再起動。

仮想マシンに統合コンポーネントが含まれた仮想CDがマウントされる

仮想マシンに統合コンポーネントが含まれた仮想CDがマウントされる

日本語言語ファイルのインストール

 日本語言語ファイルはWindows Updateの追加コンポーネントとして用意されている。Windows Updateを起動し、「optional updates are available」をクリックすると各種言語ファイルなどが表示されるので、「Japanese Language Pack」にチェックを入れて「OK」をクリック、Windows Updateを実行する。インストールの完了後、いったん再起動。

Windows Updateで「optional updates are available」をクリックする

Windows Updateで「optional updates are available」をクリックする

「Japanese Language Pack」にチェックを入れてインストールする

「Japanese Language Pack」にチェックを入れてインストールする

 再起動後、コントロールパネルの「Region and Language」で「Change display language」をクリックし、「Display language」の「Choose a display language」で「日本語」を選択、「OK」をクリックする。ここでいったんログオフが要求されるので、そのままログオフする。

「Region and Language」の「Keyboards and Languages」の「Display Language」で「日本語」を選択する

「Region and Language」の「Keyboards and Languages」の「Display Language」で「日本語」を選択する

 再度ログインすると、UIが日本語化される。続いて、コントロールパネルの「地域と言語」を開き、「管理」タブで「ようこそ画面と新しいユーザーアカウント」の「設定のコピー」をクリックする。「現在のユーザー」および「ようこそ画面」、「新しいユーザーアカウント」の言語を設定するダイアログが表示されるので、ダイアログ下の「ようこそ画面とシステムアカウント」および「新しいユーザーアカウント」にチェックを入れ、「OK」をクリックする。再起動が要求されるので、そのまま再起動を実行しよう。

「地域と言語」の「管理」タブで「設定のコピー」をクリックする

「地域と言語」の「管理」タブで「設定のコピー」をクリックする

「現在の設定のコピー先」の両方にチェックを入れる

「現在の設定のコピー先」の両方にチェックを入れる

 以上で日本語化が完了。日本語版Windows 7と同様のインターフェイスが利用できるようになる。90日という期間限定だが、Windows 7 Enterpriseの全機能が利用できる。

pyblosxom用のブログ記事をWordPressにインポートする

 以前このブログはPythonで書かれたブログシステム「pyblosxom」を使って運用していたんだけど、機能拡張が面倒臭かった(&色々細かいところが気にくわなかった)ので先日WordPressに移行しました。そこで面倒だったのが記事の移行。WordPressではMovableTypeとかBloggerとかからの移行ツールは充実しているんだけど、pyblosxomからの移行ツールは公式には用意されていません。また、参考情報としてWordPressの公式サイトで紹介されていたblosxomからの移行スクリプトはURLやタグ情報を移行してくれなかったため、結局自前で変換スクリプトを用意することに。

 幸い、WordPressのインポート/エクスポートで使われるWXL(WordPress XML)形式のファイルを簡単に生成できるモジュールをGoogle様が提供しているのを発見、そいつを使ってお気楽に作成できました。ということでここでご紹介。

 スクリプト本体はgithubで公開しているので必要な方は適宜どうぞ。「pyblosxom2wp.py」が本体です。このスクリプト内の頭で宣言している変数「title」にブログのタイトル、「link」にブログのリンクURL、「baseurl」をにBase URLが入るように書き換えて、次のように実行すると標準出力経由でインポート用XMLファイルが出力されます。

./pyblosxom2wp.py <pyblosxomの記事ディレクトリ> > output.xml

あとはそいつをWordPressのインポート機能で読みこめばOK、のはず。これで、カテゴリやタグ、URLについてもできるだけ保持する形でインポートが可能です。

TortoiseGit日本語言語ファイル1.2.1.0-r1リリース

 自分が日本語化ファイルを作っているバージョン管理ツール、TortoiseGitの日本語言語ファイルをアップデートしました(プロジェクトニュース)。TortoiseGit 1.2.1.0向けの1st releaseとなります。ダウンロードはSourceForge.JPのプロジェクトページからどうぞ。

TortoiseGit 1.2.1.0

TortoiseGit 1.2.1.0

 開発環境をWindows VistaからWindows 7に変更して、Visual Studioも再インストールして関連ツールを入れ替えて……とやっていたら色々とハマってしまい、リリースが遅れてしまいました。すいません>ユーザーの皆様。

 あと、Windows 7環境では(自分が試した限り)ダイアログが日本語化されないようです。TortoiseGitはTortoiseSVNをベースに作られているのですが、Windows 7 アプリケーション動作報告リストでTortoiseSVNの日本語化もおかしい、という話があがっているので、日本語ファイル側の問題ではない模様。本体に手を入れる必要があるっぽいので、対応にはちょっと時間がかかりそうです。

gitメモ:diffとやり直し

 最近久しぶりにgitを触って色々と忘れていたので再度メモ。

mergeを取り消す

 mergeを実行したらconflictが大量に出てしまったので取り消したい、という場合、下記を実行。

$ git reset --hard ORIG_HEAD

conflictを解決する

 gitにはmergeを実行した場合にconflictを解決するコマンド「git mergetool」がある。conflictしているファイルに対して、順番にdiffツールを実行して編集を促すもの。しかし、Windows上のMSysGit環境で実行したら見事にvimのdiffが実行されたので個人的にはデフォルトでは使えない認定(自分はvimはあまり使えないので)。

$ git mergetool

 .gitconfigの「merge」および「mergetool」項目で起動するツールを設定できるそうなので、今度はEmacsに設定してテストしてみようかな。

diffを使う

 マニュアルに書いてあるけど、「git diff」コマンドの書式は下記のとおり。

git diff <比較元commit> <比較先commit> [<対象ファイルパス>]

 ここで、比較元・比較先commitはハッシュだけでなく、「HEAD」(最新のコミット)や「HEAD^」(最新の1つ前のコミット)、「HEAD^^」(最新の2つ前のコミット)、「HEAD~4」(最新の4つ前のコミット)などのほか、tagも利用可能。

 例えば最新のコミットと、その1つ前のコミットでdiffを取るには次のようにする。

$ git diff HEAD^ HEAD hogehoge.py

python_sqlite3_commit

 Pythonにはsqlite3という、SQLiteのインターフェイスモジュールがあるんだけど、Python 2.5の日本語ドキュメントのとおりやろうとすると微妙にハマる、という話。

 日本語ドキュメントのsqlite3ページには、以下のようなコード例が載ってます。

c = conn.cursor()

# Create table
c.execute('''create table stocks
(date text, trans text, symbol text,
 qty real, price real)''')

# Insert a row of data
c.execute("""insert into stocks
          values ('2006-01-05','BUY','RHAT',100,35.14)""")

 ところが、これだと実際にはinsertがデータベースに反映されない。実はinsertなどの操作を行った最後に、sqlite3.Connectionオブジェクトのcommit()メソッドを行わないとコミットが行われず、変更が実行されない模様。

 で、実はPython 2.5.2ドキュメントのsqlite3ページには、このあとに以下のようなコードが追加されております。

# Save (commit) the changes
conn.commit()

# We can also close the cursor if we are done with it
c.close()

 にも関わらず、「Connection Object」のページにはcommit()に関する記述がないのでさらに混乱は深まる……。ちなみに、Python 2.6.4のドキュメントではちゃんとcommit()メソッドについて記述されており、commit()を実行しないとデータベースへの変更が行われないよ、またrollback()メソッドを実行すれば前回のcommit()までの内容を取り消せるよ、との旨が書かれてます。

 教訓:日本語ドキュメントを当てにせず、ちゃんと原文を読め。

Pythonネタ:クラスメソッドを動的に生成する

 Pythonには動的に関数を作ったり、クラスのメソッド呼び出しをカスタマイズするための機構が用意されています。ということで、それを使って遊んでみた。

 まず、Pythonではクラスで__getattr__メソッドを定義することで、クラスに対する任意の属性値アクセスを横取りすることができる。

 Pythonのクラスやオブジェクトは、それぞれが持つ属性(クラスならメンバ関数/変数)を__dict__というdictionary内に格納している。たとえばとあるオブジェクトaに対し「a.x」という操作を行うと、まずPython処理系はそのオブジェクトが持つ__dict__内で「x」という名前を持つメンバ変数/関数を探し、存在しなければ続いてそのオブジェクトのクラスが持つ__dict__内、続いてそのクラスの派生元クラスの__dict__内、という順でメンバ変数/関数を探索する。

 この作業を行って、通常すべての__dict__内で該当する名前が存在しなければエラーとなり例外を発生させるのだが、もしオブジェクト/クラス/派生元クラス内で__getattr__()メソッドが定義されていた場合、例外を発生させずに__getattr__()メソッドが呼び出される仕組みになっている。

 まぁ、サンプルコードを見たほうが分かりやすいかと。下記は、メソッドを呼び出すと、そのメソッド名を返すというクラス「echo」の例。

$ python
Python 2.6.1 (r261:67515, Jul  7 2009, 23:51:51)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> class echo(object):
...     def __getattr__(self, name):
...             return lambda: name
...
>>> o = echo()
>>> o.hoge()
'hoge'
>>> o.foobar()
'foobar'
>>> o.abcdefg()
'abcdefg'

 __getattr__()メソッドは、あるオブジェクトの属性値/属性メソッドにアクセスしようとした際に、そのオブジェクト/クラス/派生元クラス内で目的となる属性が見つからなかった場合に呼び出される。引数nameにはアクセスしようとした属性の名前が与えられる。ここではlambda構文を使用し、引数nameを返す関数を__getattr__の戻り値とした。

 また、オブジェクトの__dict__属性に値を追加することで、動的に任意の属性をオブジェクトに追加できる。

 下記は、オブジェクトにメソッドを追加するメソッド「teach」を備えたクラス「echo2」の例。

>>> class echo2(object):
...     def teach(self, key, value):
...             self.__dict__[key] = lambda : value
...
>>> o = echo2()
>>> o.hoge()
Traceback (most recent call last):
  File "", line 1, in
AttributeError: 'echo2' object has no attribute 'hoge'
>>> o.teach("hoge", "foobar")
>>> o.hoge()
'foobar'
>>> o.teach("abcdefg", "alphabet")
>>> o.abcdefg()
'alphabet'

 このへんの仕組みがどのような場合に有効化というと、たとえば単純なメソッドを大量に用意したい場合。下記は、「False」を返すis_a()〜is_z()までを一気に定義するというもの。

>>> for i in "abcdefghijklmnopqrstuvwxyz":
...     o.__dict__["is_"+i] = lambda : False
...
>>> o.is_a()
False

 覚えておくと、たまにラクができるかも。

WordPressの記事編集画面を改善する

 Wordpressを導入して困ったのが、記事編集時に勝手に整形されるところ。たとえば、段落の頭の全角アキ(全角スペースね)が勝手に削除されたり、画像を貼りたいときに

で囲っても勝手にタグが削除されちゃったり。

 めちゃくちゃ不満だったので、設定とかで改善できないか、(極端な話、HTMLでのコーディングに慣れているのでビジュアルエディタなんかなくてもOKなので)エディタをシンプルなものにできないかを調べたところ、どうやら「PS Disable Auto Formatting」なるプラグインを導入すれば解決すると判明。

 ということでさっそく入れてみたところ、HTMLエディタでの使えねー整形は見事に無効化されました?(^o^)/。これで段落頭の全角アキも入れられます! ただ、ビジュアルエディタとHTMLを切り替えると段落頭の全角アキがカットされる問題はまだあったりするわけですが、とりあえず問題点は解決。あと、ビジュアルモードで保存してもやっぱりカットされちゃう。ビジュアルエディタは使うな、ってことですね;-)

 あとは、夜間帯に重い問題が解決すれば万事OKなんだけど、こればっかりはなかなか難しそう。

WordPressのアップデートメモ

 Wordpressの新バージョン(2.8.5)が出ていたので、アップデートしてみた。管理画面から「自動アップデート」なるものが実行できるらしいんだけど、謎のログイン(笑)が要求されたので、tarballからのアップデートを試みてみました。

 といっても、スクリプトを書いてほぼ一発。

#!/bin/bash
old=$1
new=$2

if [ "$2" == "" ]
then
    echo "$0 <old> <new>"
    exit
fi

cp -a $old ${old}.org
rsync -av $new/ $old/

 第1引数に旧バージョンのWordpressのディレクトリ、第2引数にダウンロードしてきたWordpressのアーカイブを展開したディレクトリを与えて実行。やってることは旧バージョンのディレクトリをバックアップしたうえで、新バージョンのファイルをそこに上書きするだけ。

 とりあえずこいつで問題無し。あ、一応念のため、実行前にはデータベース等のバックアップはしておきましょう。ちなみにうちの環境はsqliteを使っているので、ディレクトリの全コピーでバックアップ完了というお手軽作業。

WordPress導入

 ブログシステムをpyblosxom+自前のバックエンドから、WordPressに変更してみた。WordPressはデフォルトではMySQLをデータベースとして使うけど、今回はプラグインを入れてsqliteを使う構成でセットアップ。

 sqliteを入れたのは、ファイルのコピーだけでなにも考えずにバックアップができるというのと、パフォーマンス的に有利なんじゃないかなー、という理由。テキストデータしか入れる気はないので、データベースサイズはせいぜい数MBだし、ファイルキャッシュが効けば結構速くなるんじゃないの? とか考えてるんだけど、実際どうなってるかはちゃんと測ってないので不明。

 ちなみに、WordPressをsqliteを使うプラグインはこれ(PDO (SQLite) For WordPress)。基本的には付属ドキュメント通りにセットアップすればOK(WordPressのwp-contentディレクトリ以下に配布ファイルをコピー→wp-config.phpファイルに「define(‘DB_TYPE’, ‘sqlite’);」を追加)。Web上の情報では、ソースをいじったりする必要があるという話が書いてあるものもあったけど、自分が試したバージョン(WordPress 2.8.4+PDO For WordPress 2.6.1)では設定ファイル以外のソースの変更は不要だった。

 ただ、suexecを使っていない環境ではもちろんデータベースディレクトリおよびデータベースファイルを作成できるようにパーミッションを変更しておく必要がある。データベースファイルはwp-contentディレクトリ以下に「database」というディレクトリが作成され、その中に作成されるので、一時的にwp-content内にWebサーバーを動かしているユーザー権限でディレクトリを作成できるように設定しておく必要あり。

pyblosxomの記事のインポート

 でもって、過去のpyblosxomの記事のインポートなんだけど、直接はインポートできないので、過去の記事からインポート用のファイルを作成する必要がある。WordPressの「Importing Content」ページでは変換用スクリプトを用意してインポートする方法を紹介するページが紹介されているんだが、このスクリプトは日本語環境だと微妙な気がしたので、これを参考にPythonで書き直してみた。

 ただしこの変換スクリプト、カテゴリと記事コンテンツ、投稿日はインポートできるのだがタグとエントリのURL情報は無視してくれるのが困りどころ。おかげで過去記事のリンクが切れる……。カテゴリについては、.htaccessに次の1行を追加すれば解決なのだが、リンク切れはさぁどうしようかねぇ。

RewriteEngine On
RewriteBase /
RewriteRule ^(apple|bluegriffon|develop|fsm|handbrake|s|slashdot|twitter) category/$1 [R=301,L]

# BEGIN WordPress
 :
 :

システムファイルの所有権問題でハマる on Windows Vista

 テスト用にVistaのhostsファイル(C:\Windows\System32\drivers\etc\hosts)を書き換えようとしたんだけど、このファイルはシステムファイルなので、当然一般ユーザー権限では書き換えられない。そこで、管理者権限でコマンドプロンプトを実行し、vimで編集したわけなんだが、このときvimは「編集後のファイルを別のファイルに保存→オリジナルのファイルに置き換え」というステップを踏んでくれていたためにファイルのパーミッションが変わってしまうという問題発生。

 編集後のファイルは、自分のみ「フルコントロール」、「Everyone」と「None」にファイル属性の読み取りのみ許可、というパーミッションになっていて、そのためシステムがhostsファイルにアクセスできなくなり、hostsに何を書いてもそれが適用されない状況に。結局、問題がパーミッションにあることに気付いたのは10数分後……。

 公式には「hostsファイルの編集には管理者権限で起動したメモ帳を使え」と言われているのですが、他のエディタを使うとこういうトラブルになるよ、ということで。しかし、「SYSTEM」のパーミッションがないと本当にシステムもアクセスできないのね>NTFSのパーミッション仕様。

Pythonネタ:unittestを使う

 Python標準のユニットテスト機能、「unittest」の使い方メモ。

目的

 unittestはPythonで作成したクラスの特定の関数や、機能の動作確認に利用できる機能だ。詳しくは ドキュメントを読めばすぐに分かる が、unittestクラスの派生クラスを作り、そのクラスの関数としてテストコードを記述してやると、簡単にユニットテストができる、というもの。

 メインの実装コードにprint文などを挿入したり、テストコードを挿入しても良いのだが、それだとテストコードの再利用が難しかったり、いったんバグ修正を行ってテストコードを削除した後に再度バグが発生したりした場合に二度手間になったりする。そのため、テストコードはなるべくunittestにまとめて記述しておくとデバッグや実装、テストが楽になりますよ、というお話。

使い方

 基本的な使い方はこれまたオンラインドキュメントにあるのだが、自分は下記の形をよく使っている。

import random
import unittest

class TestSequenceFunctions(unittest.TestCase):
    def setUp(self):
        # ここに各テスト関数を実行する前に呼び出す処理を書く。
        # 通常は共通のデータの準備とかを書くことが多い


   def tearDown(self):
        # ここに各テスト関数を実行した後に呼び出す処理を書く。
        # 通常は共通のデータの後片付けとかを書くことが多い


    def test_hogehoge(self):
        """test for hogehoge テストの内容をコメントに入れる"""
        # テストコード1をここに書く


    def test_foobar(self):
        """test for foobar テストの内容をコメントに入れる"""
        # テストコード2をここに書く


# do unittest
# テストオブジェクトを作成
suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)

# テスト実行。出力するメッセージレベルはverbosity引数で設定できる
unittest.TextTestRunner(verbosity=2).run(suite)

 テストコード内でテストが期待したとおりの処理を行っているかどうかは、unittest.TestCaseクラス内で用意されているasert/fail関数を使うのが好ましい。詳しくは「pydoc unittest」等で確認できるが、たとえば二つの引数の値が等しくない場合にエラーを出すには「assertEqual(引数1、引数2、エラーメッセージ)」関数を使う。

 そのほか、unittestにはレポート機能などもあるが、基本的には上記さえ押さえておけば事足りるはず。

MSys&MinGWをインストール

  MinGW でのビルドを前提とされたツールをCygwin上でビルドするのが面倒だったので全力で MSys とMinGWをインストールした。MSysGitも入っているので環境汚れまくり。

  SourceForge.JP のミラーからMinGW 5.1.4.exeとMSYS-1.0.11-rc-1.exeをダウンロードしてそれぞれインストール。MSYSは結構下の方(MSYS Base Systemの中)にあるので探す。

 それぞれインストール後、「C:\msys\1.0\etc\fstab.sample」を同じディレクトリに「fstab」という名前にコピー、下記のようにMinGWとActivePerlをインストールしているディレクトリに対応付ける。

c:/MinGW		/mingw
c:/Perl	/perl

 あとはスタートメニューの「MinGW」?「MSYS」?「MSYS」などからシェルを起動。gccがエラーを日本語で吐いてくれるのだがWindowsのコマンドプロンプトだと化けるのでexport LANG=Cを適宜設定。

GCC 4.4系を使う

 GCC 4.4系を使うには別途インストールが必要。「gcc-4.4.0-mingw32-notes.txt」に解説があるが、下記をMinGWのインストールディレクトリで展開すればよい。

GMP Runtime [REQUIRED]
gmp-4.2.4-mingw32-dll.tar.gz
MPFR Runtime [REQUIRED]
mpfr-2.4.1-mingw32-dll.tar.gz
POSIX Threads for Win32 Runtime [REQUIRED]
pthreads-w32-2.8.0-mingw32-dll.tar.gz
Core (C) [REQUIRED]
gcc-core-4.4.0-mingw32-bin.tar.gz、gcc-core-4.4.0-mingw32-dll.tar.gz
C++ [OPTIONAL]
gcc-c++-4.4.0-mingw32-bin.tar.gz、gcc-c++-4.4.0-mingw32-dll.tar.gz

 なお、ドキュメントにはgcc-full-4.4.0-mingw32-bin.tar.lzmaに全部入っていると書いてあるが、GMPとMPFRとPOSIX Threadは入っていなかった……(汗)。

Pythonのクラスの挙動を調べる:class構文の外でクラスにメンバ関数を追加(2)

 今度は、別のモジュールで定義したクラスにメンバ関数を追加してみる。

[Macintosh:~]$ python
Python 2.5.1 (r251:54863, Feb  6 2009, 19:02:12)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

   # importすることで定義されたクラスは、その名前空間内に閉じこめられる 

>>> import foobar
>>> print foobar.FooBar
<class 'foobar.FooBar'>

   # 名前空間が異なっていても、名前空間さえ指定すればメンバ関数を追加できる 

>>> f = foobar.FooBar()
>>> f.show_name()
I'm FooBar.
>>> def rename(self,new_name):
...     self.name = new_name
...
>>> foobar.FooBar.rename = rename
>>> f.rename("john")
>>> f.show_name()
I'm john.

 大体予想通りの結果ですな。

Pythonのクラスの挙動を調べる:class構文の外からクラスにメンバ関数を追加(1)

Pythonのクラスの挙動を調べる:class構文の外からクラスにメンバ関数を追加(1)

 Pythonでプラグイン的な機構を実装する際、あるモジュールで定義されたクラスに対し、ほかのモジュールからメンバ関数を追加できると楽しいのでは?とふと思う。

 ちょっと分かりにくいが、例えばHogeというクラスがhoge.pyで定義されており、Hogeクラスのメンバ関数を追加するコードがplugin.pyで定義されている。そして、plugin.pyで定義されている機能を使いたい場合のみimport pluginすると、その機能がHogeクラスで利用できるようになる、というイメージだ。

 ということで、ちょっと試してみた。

[Macintosh:~]$ python
Python 2.5.1 (r251:54863, Feb  6 2009, 19:02:12)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

   # 適当な関数を定義 

>>> class FooBar(object):
...     def func1(self):
...             print "func1!"
...     def func2(self):
...             print "func2!"
...

   # FooBarクラスのインスタンスを作成 

>>> a = FooBar()
>>> a.func1()
func1!
>>> a.func2()
func2!

   # FooBarは__main___内にクラスオブジェクトして記録される 

>>> locals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__':
'__main__', '__doc__': None, 'a': <__main__.FooBar object at
0x2454f0>, 'FooBar': <class '__main__.FooBar'>}
>>> print FooBar
<class '__main__.FooBar'>
>>> print FooBar.__dict__
{'func2': <function func2 at 0x5e2f0>, '__module__': '__main__',
'func1': <function func1 at 0x5e2b0>, '__dict__': <attribute
'__dict__' of 'FooBar' objects>, '__weakref__': <attribute
'__weakref__' of 'FooBar' objects>, '__doc__': None}

   # FooBarクラスに追加する関数を定義 

>>> def add1(self):
...     print "add1!"
...

   # add1関数をFooBarクラスのメンバに追加 

>>> FooBar.add1 = add1

   # クラスを改変する前に作成したインスタンスも影響を受ける! 

>>> a.add1()
add1!
>>> print FooBar.__dict__
{'func2': <function func2 at 0x5e2f0>, '__module__': '__main__',
'add1': <function add1 at 0x5e270>, 'func1': <function func1 at
0x5e2b0>, '__dict__': <attribute '__dict__' of 'FooBar' objects>,
'__weakref__': <attribute '__weakref__' of 'FooBar' objects>,
'__doc__': None}
>>>

 ということで、少なくともクラスオブジェクトに対して属性を追加することで、クラスにメンバ関数を追加できることは分かりました。なるほどなるほど。

BSD版sedとGNU版sed

 BSD版のUNIX toolsと、GNU版のUNIX toolsでは微妙に受け付けるコマンドラインオプションが違うのは有名な話。たとえばGNU版の「cp -a」はBSD版では「cp -pr」に相当する。

 で、Mac OS XのコマンドラインツールはBSD版なのだが、「sed -e “s/ /\n/g”」が効かなくて困った。Mac OS X付属のsedは置換後の文字の指定にエスケープシーケンスが使えないらしい。

 これの簡単な解決はこちら。

perl -pe "s/ /\n/g"

 「perl -p」でsedっぽい動作をさせられる、という話でした。よくこんなの覚えてたな>自分。ラクダ本の最初のほうとかに書いてあったんだっけ? ラクダ本を読んだのは多分10年くらい前だと思うんだけど、IT業界の進化は早いとか言われていて3年前の知識はもう古いとか言われているけど意外に昔覚えたことってふと全然違うことで役立つことがあるから侮れないね。

gfxbootで日本語表示可能なブートローダを作成しようとする

  GParted Live CD をWindows Vista上でUSBメモリにインストールしようとしたらUAEの仕様がアレでハマる。

 GParted Live CDのUSBメモリ用配布アーカイブにはWindows用のISOLINUXインストーラが付属していて、USBメモリにファイル一式をコピー→バッチファイル実行でブータブルUSBメモリができあがるはずなのだが、VistaだとUSBメモリのブートローダ領域への書き込みには管理者権限がいるそうだ。そりゃそうだ。しかし、かといってバッチファイルを「管理者として実行」するとエラー。なぜかバッチファイルを「管理者として実行」すると、system32ディレクトリがカレントディレクトリになるのが原因。なんじゃそりゃ。

 しょうがないのでバッチファイルをいじくってたらつい日本語化してしまい、ついでにじゃぁほかの部分も日本語化するか、どうせ設定ファイルいくつか書き換えればできるだろと手をつけたのがハマり始まり。そんな簡単なモンじゃなかった。

 Ubuntuのインストーラとかはブート時にブートメニューが日本語で表示されるんだけど、これはgfxbootというものを使っているらしい。gfxbootはSYSLINUX/ISOLINUX/GRUBなどで利用できるプログラムで、それぞれパッチが当てられたSYSLINUX/ISOLINUX/GRUBが必要。原理としてはSYSLINUX/ISOLINUX/GRUBがgfxbootのランタイム(gfxmenu)を起動→gfxmenuがメニュースクリプトを実行、という感じ。このメニュースクリプトは独自言語で記述しておいて、あらかじめバイトコンパイルして1ファイルにまとめた上でブートローダと一緒に置いておくのだが、この独自言語がスタック志向の非常に面倒臭い言語で困る。プログラム中でメモリを動的に割り当てられたり、ファイルのリードもできるのだが、完全に独自仕様(しいて言えばPostScriptに似ているらしい)。

 gfxbootを使っているUbuntuやopenSUSEのブートローダは、基本的にはスクリプト部分は手を加えずに設定ファイルで画像なりメニュー項目をいじれるようになっているんだが、さすがにGParted Live CDを起動したらUbuntuのメニューが、というのはダサいのでざくっと手をいれてみようとしたが2時間くらい格闘して一時中断。これは週末に持ち越しだな。

 ちなみに gfxboot referenceGfxboot – openSUSE あたりが参考資料。日本語の情報はほぼ皆無(笑)。

最近のemacs設定ファイル

 最近の.emacs。とりあえずバックアップ代わりにここで公開。

;; -*- coding: euc-jp -*-(custom-set-variables  ;; custom-set-variables was added by Custom.  ;; If you edit it by hand, you could mess it up, so be careful.  ;; Your init file should contain only one such instance.  ;; If there is more than one, they won't work right. '(c-default-style (quote ((c-mode . "k&r;") (c++-mode . "k&r;") (java-mode . "java") (awk-mode . "awk") (other . "gnu")))) '(case-fold-search t) '(current-language-environment "English") '(save-place t nil (saveplace)) '(tab-stop-list (quote (4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 84 88 92 96 100 104 108 112 116 120))) '(tool-bar-mode nil nil (tool-bar)) '(transient-mark-mode t) '(uniquify-buffer-name-style (quote forward) nil (uniquify)))(custom-set-faces  ;; custom-set-faces was added by Custom.  ;; If you edit it by hand, you could mess it up, so be careful.  ;; Your init file should contain only one such instance.  ;; If there is more than one, they won't work right. );; .emacs.el;; 選択範囲の色を指定(set-face-background 'region "SkyBlue")(set-face-foreground 'region "black");; 起動時のウィンドウサイズ、色などを設定(if (boundp 'window-system)    (setq default-frame-alist          (append (list                   '(foreground-color . "black")  ; 文字色                   '(background-color . "white")  ; 背景色                   '(border-color     . "white")  ; ボーダー色                   '(mouse-color      . "black")  ; マウスカーソルの色                   '(cursor-color     . "black")  ; カーソルの色                   '(cursor-type      . box)      ; カーソルの形状                   '(top . 60) ; ウィンドウの表示位置(Y座標)                   '(left . 140) ; ウィンドウの表示位置(X座標)                   '(width . 50) ; ウィンドウの幅(文字数)                   '(height . 45) ; ウィンドウの高さ(文字数)                   )                  default-frame-alist)))(setq initial-frame-alist default-frame-alist )(global-set-key "\C-h" 'delete-backward-char)(prefer-coding-system 'utf-8-unix);;(autoload 'cperl-mode "cperl" "Perl editing mode." t)(require 'cperl-mode)(setq auto-mode-alist      (append '(("\\.pl$" . cperl-mode)		("\\.pm$" . cperl-mode)		("\\.mm$" . objc-mode)) auto-mode-alist));; Turn on tabs(setq indent-tabs-mode t)(setq-default indent-tabs-mode t);; Set the tab width(setq default-tab-width 4)(setq tab-width 4)(setq c-basic-indent 4);;python-mode(add-hook 'python-mode-hook	  '(lambda();;	     (setq indent-tabs-mode t)	     (setq indent-level 4)	     (setq python-indent 4)	     (setq tab-width 4)));;c-mode(add-hook 'c-mode-hook	  '(lambda()         (setq tab-width 4)         (setq indent-tabs-mode nil)         (setq c-basic-offset 4)));; キーワードのカラー表示を有効化;; 「t」の部分を「nil」にするとカラー表示をOffにできる(global-font-lock-mode t);; テキストエンコーディングとしてUTF-8を優先的に使用する;; 「utf-8」の部分を「cp932」とするとCP932(Windows用Shift JIS)優先となる(prefer-coding-system 'utf-8);; 起動時のメッセージを表示しない;;「t」を「nil」にするとメッセージが表示される(setq inhibit-startup-message t);; 選択範囲をハイライトする;;「t」を「nil」にするとハイライトなしに(setq-default transient-mark-mode t);;; 行番号・桁番号をモードラインに表示する・しない設定(line-number-mode t) ; 行番号。tなら表示、nilなら非表示(column-number-mode t) ; 桁番号。tなら表示、nilなら非表示;; 対応するカッコを色表示する(show-paren-mode 1);; オートセーブOff;; 「nil」を「t」にするとOnに(auto-save-mode nil);; バックアップファイルを作る;; 「nil」を「t」にするとバックアップファイルを作らない(setq backup-inhibited nil);; モードラインに現在時刻を表示する(display-time);; カレントディレクトリをホームディレクトリに設定;; ""内は任意のディレクトリを指定可能(cd "~/"); Emacsバージョン別の設定; for NTEmacs(if (string-match "Emacs 22" (emacs-version))	(progn; イタリックやボールドフォントを標準フォントから作成する(setq w32-enable-synthesized-fonts t); 使用するフォントを指定 for NTEmacs; 「myfont」という名前で新たなフォントセットを定義; 英字フォントとしてメイリオ、14ポイントを使用(create-fontset-from-ascii-font "-outline-メイリオ-normal-r-normal-normal-14-*-*-*-*-*-iso8859-1" nil "myfont"); myfontの日本語フォントとしてメイリオを使用; フォントサイズは英字のサイズに合わせる(set-fontset-font "fontset-myfont"                  'japanese-jisx0208				  '("メイリオ" . "jisx0208-sjis")); myfontのカタカナフォントとしてメイリオを使用; フォントサイズは英字のサイズに合わせる(set-fontset-font "fontset-myfont"                  'katakana-jisx0201                  '("メイリオ" . "jisx0201-katakana")); 定義したフォントセットを登録(setcdr (assoc 'font default-frame-alist) "fontset-myfont"); NTEmacsの設定ここまで	  ) t); for Meadow(if (string-match "Emacs 21" (emacs-version))	(progn; 日本語環境設定(set-language-environment "Japanese")(mw32-ime-initialize)(setq default-input-method "MW32-IME"); フォントセットを追加(w32-add-font     "Meiryo 14"     '((spec	((:char-spec ascii :height any)	 strict	 (w32-logfont "Meiryo" 0 -14 400 0 nil nil nil 0 1 3 0))	((:char-spec ascii :height any :weight bold)	 strict	 (w32-logfont "Meiryo" 0 -14 700 0 nil nil nil 0 1 3 0)	 ((spacing . -1)))	((:char-spec ascii :height any :slant italic)	 strict	 (w32-logfont "Meiryo" 0 -14 400 0   t nil nil 0 1 3 0))	((:char-spec ascii :height any :weight bold :slant italic)	 strict	 (w32-logfont "Meiryo" 0 -14 700 0   t nil nil 0 1 3 0)	 ((spacing . -1)))	((:char-spec japanese-jisx0208 :height any)	 strict	 (w32-logfont "Meiryo" 0 -14 400 0 nil nil nil 128 1 3 0))	((:char-spec japanese-jisx0208 :height any :weight bold)	 strict	 (w32-logfont "Meiryo" 0 -14 700 0 nil nil nil 128 1 3 0)	 ((spacing . -1)))	((:char-spec japanese-jisx0208 :height any :slant italic)	 strict	 (w32-logfont "Meiryo" 0 -14 400 0   t nil nil 128 1 3 0))	((:char-spec japanese-jisx0208 :height any :weight bold :slant italic)	 strict	 (w32-logfont "Meiryo" 0 -14 700 0   t nil nil 128 1 3 0)	 ((spacing . -1)))))); 起動時およびnew-frame時のフレーム(ウィンドウ)の設定。(add-to-list 'default-frame-alist '(font . "Meiryo 14")); IMEのフォントを設定(let ((logfont '(w32-logfont "Meiryo" 0 -14 400 0 nil nil nil 128 1 3 0)))  (modify-frame-parameters (selected-frame) (list (cons 'ime-font logfont)))  (add-to-list 'default-frame-alist (cons 'ime-font logfont))  ); Meadowの設定ここまで	  ) t)

cl.exeの主要コマンドラインオプションメモ

 最近、Visual C++をいじっているのでメモ。昔はVisual StudioでGUIでビルド設定してましたが、最近はもうmakeを使う方になれちゃったんだよね……。

  <th>
    意味
  </th>
</tr>

<tr>
  <th colspan="2">
    最適化
  </th>
</tr>

<tr>
  <td>
    /O1
  </td>
  
  <td>
    コードを最小化
  </td>
</tr>

<tr>
  <td>
    /O2
  </td>
  
  <td>
    コードを最速化
  </td>
</tr>

<tr>
  <td>
    /Ob{0|1|2}
  </td>
  
  <td>
    インライン展開方法を指定
  </td>
</tr>

<tr>
  <td>
    /Od
  </td>
  
  <td>
    最適化を禁止
  </td>
</tr>

<tr>
  <td>
    /Oi
  </td>
  
  <td>
    組み込み関数を使用
  </td>
</tr>

<tr>
  <td>
    /Ox
  </td>
  
  <td>
    最大限の最適化
  </td>
</tr>

<tr>
  <td>
    /GL
  </td>
  
  <td>
    プログラム全体の最適化を使用
  </td>
</tr>

<tr>
  <td>
    /arch:{SSE|SSE2}
  </td>
  
  <td>
    SSE/SSE2を使用
  </td>
</tr>

<tr>
  <th colspan="2">
    作成するコード
  </th>
</tr>

<tr>
  <td>
    /MD
  </td>
  
  <td>
    DLL版ランタイムライブラリを使用。/MDdとするとデバッグバージョンを作成
  </td>
</tr>

<tr>
  <td>
    /MT
  </td>
  
  <td>
    スタティック版ランタイムライブラリを使用。/MTdとするとデバッグバージョンを作成
  </td>
</tr>

<tr>
  <td>
    /LD
  </td>
  
  <td>
    DLLを作成。/LDdとするとデバッグバージョンを作成
  </td>
</tr>

<tr>
  <td>
    /Fe<ファイル名>
  </td>
  
  <td>
    出力するEXEファイル名を指定
  </td>
</tr>

<tr>
  <td>
    /Fo<ファイル名>
  </td>
  
  <td>
    objファイルを出力する
  </td>
</tr>

<tr>
  <td>
    /Zi
  </td>
  
  <td>
    デバッグ情報を生成
  </td>
</tr>

<tr>
  <th colspan="2">
    そのほか
  </th>
</tr>

<tr>
  <td>
    /D<シンボル>
  </td>
  
  <td>
    シンボルを定義(#defineと同等)。値を指定する場合は/D<シンボル>=<値>とする
  </td>
</tr>

<tr>
  <td>
    /I<パス>
  </td>
  
  <td>
    追加インクルードディレクトリを指定
  </td>
</tr>

<tr>
  <td>
    /X
  </td>
  
  <td>
    標準インクルードパスを無視
  </td>
</tr>

<tr>
  <td>
    /w
  </td>
  
  <td>
    ワーニング出力を無効にする
  </td>
</tr>

<tr>
  <td>
    /Wall
  </td>
  
  <td>
    すべてのワーニング出力を有効にする
  </td>
</tr>

<tr>
  <td>
    /link
  </td>
  
  <td>
    リンカにオプションを渡す
  </td>
</tr>
cl.exeのコマンドラインスイッチ
スイッチ
  <th>
    意味
  </th>
</tr>

<tr>
  <td>
    /DEBUG
  </td>
  
  <td>
    デバッグ情報(PDBファイル)を作成
  </td>
</tr>

<tr>
  <td>
    /DEF:<ファイル名>
  </td>
  
  <td>
    モジュール定義ファイルを指定
  </td>
</tr>

<tr>
  <td>
    /DLL
  </td>
  
  <td>
    DLLを作成
  </td>
</tr>

<tr>
  <td>
    /EXPORT:entryname[&#44;@ordinal[&#44;NONAME]][&#44;DATA]
  </td>
  
  <td>
    エクスポートする関数を指定
  </td>
</tr>

<tr>
  <td>
    /LIBPATH:<パス>
  </td>
  
  <td>
    追加のライブラリパスを指定
  </td>
</tr>

<tr>
  <td>
    /LTCG
  </td>
  
  <td>
    リンク時のコード生成を有効化。/GLを指定してコンパイルしたオブジェクトファイルのリンクに必要
  </td>
</tr>
link.exeのコマンドラインスイッチ
スイッチ

PythonでCGI経由でファイルアップロード

 Webベースで記事作ったりサイトデザインしたりしていると、多量のファイルをアップロードする機会も多々あるのでファイルを自動アップロードするスクリプトを書きたい、という話。

 とりあえずググったら「 残高照会メモ: pythonでアップロード 」が出てきたのだが、自前でMIMEエンコーディングしなきゃいけないのがちょっとアレだ。

 ちなみにPerlだと下記のような感じでいける。

sub post_attachment {
    my $self = shift @_;
    my %args = @_;

    my $file_name = $args{file};  # filename

    my $url = "アップロード先URL";
    my $ua = LWP::UserAgent->new( 'agent' => "適当なUserAgent文字列", );
    my $req = HTTP::Request::Common::POST $url, Content_Type => 'form-data',
    Content => [
				file_content => ["$file_name"],
				description => "",
				op => "addFileForStory",   # form "op"の値
				sid => $sid,               # form "sid"の値
				Submit => "Submit",        # form "Submit"の値
	];

    my $resp = $ua->request( $req );

    if( $resp->is_error ) {
	return 0; #print "upload $file_name: failed.\n";
    } else {
	return 1; #print "upload $file_name: succeed.\n";
    }
}

 これをPythonでやりたい。ということで続く。

IE8のテキストエリア内テキストを外部エディタで編集

 Internet Explorer 8がかなり軽快なので、最近はFirefoxと併用している。Firefoxの場合、Google Readerを使って大量のタブを開くと結構な確率でブラウザが落ちるのだが、IE8はそれがないので、最近はGoogle ReaderはIE8で見るようにしているのが大きい。

 ただ、問題なのがテキスト編集。テキストエリアでそこそこの長さのテキストを入力/編集するのはしんどいので、Firefoxでは「 It’s all text 」という拡張を使っている。これをインストールするとテキストエリアの周辺に「編集」ボタンが表示され、これをクリックするとテキストエディタが起動してそこでテキスト編集ができて非常に便利である。

 これに相当するものがIEにもないかと探したところ、 AreaEditor というものがそれに当たるようだ。ということで早速インストールしたところ、IE8でも利用できた。ただ、AreaEditorではテキストをエディタで開いたあと、1回目に保存したものしか反映されず、2回、3回と変更→上書き保存を繰り返した場合は変更内容がブラウザ側に反映されないようだ。自分は1パラグラフを入力したら手癖により勝手にファイルを上書き保存するため、この仕様だととても使いづらい。結局、最後にコピー&ペーストでテキストを流し込んだりしている(汗)。そのほかにもAreaEditorはIt’s all textと比べると劣っているところが多々見られるのが残念。自分で作れということか?

図:AreaEditorの設定画面。Webブラウザからは起動できず、スタートメニューから起動しなければいけないのも面倒くさい

gitで特定のファイルを無視させる

 gitで特定の拡張子などを持つファイルをtracking対象から外すには、.gitディレクトリがあるディレクトリに.gitignoreファイルで設定すればよい、というのはよく聞かれる話。たとえば自分の場合、下記のように設定することが多い。

*.pyc
*~
*.bak

 で、毎回これを設定するのは面倒。そんなときは、適当なところにグローバル用の.gitignoreファイルを作成し、git configで そのファイルのパスを「core.excludesfile」に設定すればOK。

$ git config --global --add core.excludesfile "$HOME/.gitignore"
 

Gitでローカルファイルのバックアップ

 Gitでローカルファイルの差分バックアップをやってみるテスト。

前提:

  • ミラーリングされているファイルサーバーがある
  • いままでは作業用PCがクラッシュしても大丈夫なように、作業後にいちいちファイルをファイルサーバー中のディレクトリに上書きコピーしていた
  • ファイル数が多くなる/容量が大きくなると面倒
  • これだと履歴管理ができない(Emacsの~.1のようなバックアップファイルに頼ることに)

 ということで、下記の手順でGitで差分バックアップをやってみる。

  1. 作業ディレクトリをgitリポジトリ化する。

    $ git init
    $ git add <対象ファイル>
    $ git commit -m “<コメント>”
    

  2. ファイルサーバーにgitのbareリポジトリを作る

    $ cd <バックアップディレクトリ>
    $ mkdir <適当なディレクトリ名>.git
    $ cd <ディレクトリ名>.git
    $ git init –bare
    

  3. ファイルサーバー内のbareリポジトリにコミット

    $ cd <作業ディレクトリ>
    $ git remote add origin <ファイルサーバー上のbareリポジトリのパス>
    $ git push master:master
    

 あとは作業が一段落したタイミングごとにコミット+pushをしていけばいいだけのはず。しかしこういう目的で使い出すとWindows上で動く、使いやすいGUIフロントエンドがほしくなるところではある。

個別記事のタイトル設定ができない件についてorz

 このblog(?)の記事のPermlink、記事個別ページのタイトルがちゃんと設定されていないことに気付く。

 ということでPyblosxomのドキュメントを見たんだけど、なんと(ドキュメントを見る限りでは)標準では記事個別ページのタイトル(タグ内に設定するタイトルね)にその記事のタイトルを入れることができないっぽいorz。自前でプラグインを書けということか。</p> <p> このblog(?)は、記事レンダリングをPyblosxomで、記事編集などのバックエンドはfsmというシステムでやっているんだけど、どちらも良い言い方をすると自由度が高い、悪い言い方をすると色々と面倒くさいけど、まぁ修行wということで(それでで面倒くさくなって修正しないままだらだらと、という話もあるが……)。</p> <p> しょうがないのでとりあえずタイトルを入れないままごまかす。ToDoに入れておこう。</p> </div> <footer> <div class="tag"> Tags: <a href="/tag/pyblosxom">pyblosxom</a> </div> </footer> </article> <article class="post"> <header> <h2><a href="/2009/01/29/090129-puttygit/">Windows環境のGitでハマる</a></h2> <span class="metadata">posted on 2009/01/29 09:56:57</span> </header> <div class="post-body"> <p> なぜかWindows環境のGit(Cygwin使用)でリポジトリにアクセスできなくなる問題発生。CygwinのGitが入っているのに <a href="http://code.google.com/p/msysgit/">MsysGit</a> もぶち込んでしまったからに違いない。</p> <p> ということで色々と格闘したのだが、どうやらPuTTYのキャッシュが悪さをしているような予感だったのでplink.exeでいったんリポジトリにアクセスしてみたら、直った。</p> <pre>c:\Program Files\PuTTY>plink.exe hylom@git.sourceforge.jp Using username "hylom". Linux sf-cvs 2.6.27.2-core2 #1 SMP Tue Oct 21 14:58:29 JST 2008 x86_64 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. This is a restricted shell account. You cannot execute anything here. </pre> <p> 当たり前だが、git.sourceforge.jpにはSSHでログインはできるがすぐログアウトさせられる。</p> </div> <footer> </footer> </article> <article class="post"> <header> <h2><a href="/2009/01/27/090120-cygperl-rebase/">CygwinのGlob.dllで発生する謎のエラー</a></h2> <span class="metadata">posted on 2009/01/27 10:28:14</span> </header> <div class="post-body"> <p> CygwinのPerlで、次のようなエラーが出た。</p> <pre>> perl 5940 C:\cygwin\bin\perl.exe: *** fatal error - unable to remap C:\cygwin\lib\perl5\5.10\i686-cygwin\auto\File\Glob\Glob.dll to same address as parent(0x8C0000) != 0x950000 </pre> <p> この場合、とりあえずよく分からないがCygwin関連のprocessをすべて閉じた後、次のようにすれば解決するらしい。ていうか解決した。</p> <pre>> cd C:\cygwin\bin > ash rebaseall </pre> <p> お困りの方はどうぞお試しあれ。最初はPerl 5.10系のバグかと思った。</p> </div> <footer> </footer> </article> <article class="post"> <header> <h2><a href="/2009/01/21/090121-pysqlite/">Python 2.4のさくらサーバーでsqlite3を使う</a></h2> <span class="metadata">posted on 2009/01/21 11:07:30</span> </header> <div class="post-body"> <p> Python 2.5に標準添付のSQLiteモジュールは、さくらのレンタルサーバーにインストールされているPython 2.4には付属していないので自前でインストールする。</p> <p> インストール方法は <a href="http://oss.itsystementwicklung.de/trac/pysqlite/browser/doc/install-source.txt">http://oss.itsystementwicklung.de/trac/pysqlite/browser/doc/install-source.txt</a> を参照。</p> <p> まず、 <a href="http://oss.itsystementwicklung.de/trac/pysqlite/">公式サイト</a> からソースアーカイブをダウンロードして展開。</p> <pre class="exec">$ wget http://oss.itsystementwicklung.de/download/pysqlite/2.5/2.5.1/pysqlite-2.5.1.tar.gz$ tar xvzf pysqlite-2.5.1.tar.gz$ cd pysqlite-2.5.1</pre> <p> さくらの場合、ライブラリとヘッダファイルが/usr/local/以下にあるので設定ファイル「setup.cfg」中、下記のようにコメントアウトされている部分を有効にする。</p> <pre class="list">#include_dirs=/usr/local/include#library_dirs=/usr/local/lib</pre> <p> 最後にコンパイル&インストール。今回は~/local/以下にインストールしている。</p> <pre clsss="exec">$ python setup.py build$ python setup.py install --prefix=~/local/</pre> <p> ちなみに、このようにしてインストールしたモジュールは「import pysqlite2」のようにしてインポートする。Python 2.5では「import sqlite3」でインポートできるのだが、互換性のためにこうなっているとか。あと、importする前にインストールしたモジュールがPythonの検索パスに含まれているかも要確認。環境変数PYTHONPATHに「~/local/lib/python2.4」を加えておくか、適宜sys.pathにこのパスを追加すべし。</p> </div> <footer> </footer> </article> <article class="post"> <header> <h2><a href="/2009/01/19/090119-poderosa/">Windows環境でのターミナルエミュレータ</a></h2> <span class="metadata">posted on 2009/01/19 09:51:29</span> </header> <div class="post-body"> <p> UNIX/Linuxに慣れた身として、Windows環境で困るのがターミナル。Windows標準のコマンドプロンプトは横幅が制限されるわコピー&ペーストが面倒くさいわで激しく使いにくいので昔はCygwinのX+rxvtという環境を使っていたんだけど、日本語がらみの設定が面倒くさかったりWindowsっぽくなかったり(笑)で、最近はコマンドプロンプトで我慢しておりました。</p> <p> そんななか発見したのが <a href="http://ja.poderosa.org/index.html">Poderosa</a> というターミナルエミュレータ。Windows環境でターミナルエミュレータというと、ほかにもPuTTYやTeraTermなどがありますが、PoderosaはCygwinのシェルを直接開けるという話を聞いて、とりあえずインストール。</p> <p><img src="/img/blog/090119/poderosa.png" width="480" /></img></p> <p> インストールはインストーラを実行するだけ。ライセンスはApache License 2.0。コピー&ペーストもCygwinのbashへの接続も問題なし。もちろんウィンドウのサイズは自由自在に変更可能。エンコーディングもEUC-JP/ISO-8859-1/Shift-JIS/UTF-8に対応している模様。UNIX/Linuxでは全然普通の機能なのだが、WindowsでこれができてかつCygwinのbashが使えるターミナルエミュレータってなかったのでとても感動。</p> </div> <footer> </footer> </article> <article class="post"> <header> <h2><a href="/2009/01/14/090114-modrw/">さくらのレンタルサーバーでmod_rewriteにハマる</a></h2> <span class="metadata">posted on 2009/01/14 04:39:38</span> </header> <div class="post-body"> <p> さくらのレンタルサーバーは、Apacheのmultiviews機能が有効化されている。これにより、たとえば「http://ほげほげ/hoge」というURLにアクセスした場合、「http://ほげほげ/hoge.html」を自動的に返してくれるようになっている。</p> <p> ところが、この機能はmod_rewriteと組み合わせると非常に気持ち悪い動作をしてくれる。たとえば、mod_rewriteで下記のように設定したとしよう。</p> <pre>RewriteEngine on RewriteBase / RewriteRule ^/(.*)$ test.cgi/$1 [L] </pre> <p> この設定は、「http://ほげほげ/foo/bar/」というURLでアクセスした場合、「http://ほげほげ/test.cgi/foo/bar」というURLの内容を返す、という動きを意図している。ところが、この場合なぜかInternal Server Errorになってしまう。どうも、multiviewsが勝手に拡張子を補完してしまうのがよろしくないようだ。しょうがないので、下記のように設定して解決した。</p> <pre>RewriteEngine on RewriteBase / RewriteRule ^/([^.]*)$ test.cgi/$1 [L] RewriteRule ^/([^.]*)(.html|.rss20|.atom)$ test.cgi/$1$2 [L] </pre> <p> 勝手に変な拡張子を加えられるのが問題なので、とりあえず「.」を含むURLはRewriteしないように設定する。これだけだと.htmlや.rss20、.atomといった拡張子付きのURLがRewriteされないので、個別に拡張子を指定してRewriteするようにした。</p> </div> <footer> </footer> </article> </div> </main> </div> <div class="sidebar" class="sidebar"> <div class="sidebar-box"> <h3>site navigation:</h3> <nav> <ul> <li><a href="/about">about</a></li> <li><a href="/tag">tag</a></li> <li><a href="/2020/">2020</a></li> <li><a href="/2019/">2019</a></li> <li><a href="/2018/">2018</a></li> <li><a href="/2017/">2017</a></li> <li><a href="/2016/">2016</a></li> <li><a href="/2015/">2015</a></li> <li><a href="/2014/">2014</a></li> <li><a href="/2013/">2013</a></li> <li><a href="/2012/">2012</a></li> <li><a href="/2011/">2011</a></li> <li><a href="/2010/">2010</a></li> <li><a href="/2009/">2009</a></li> <li><a href="/2008/">2008</a></li> <li><a href="/2007/">2007</a></li> <li><a href="/2006/">2006</a></li> </ul> </nav> </div> <div class="sidebar-box"> <h3>hylom.net:</h3> <div class="box-contents"> <p>ライター/エディター/プログラマー/Webディレクター、hylomのブログです。ご興味のある方は<a href="https://twitter.com/hylom">つぶやき</a>や<a href="/about">執筆記事</a>などもどうぞ。</p> </div> </div> <div class="sidebar-box"> <h3>最近の記事:</h3> <div class="box-contents"> <ul class="unlist"> <li> <a href="/2020/07/20/emacs-magit-git-path/">Emacsのmagitで使用するgitバイナリのパスを指定する方法</a> <span class="timestamp">(2020/07/20)</span> </li> <li> <a href="/2020/05/23/python-binary-indexed-access/">「Pythonではバイナリファイルを操作したい時にバイナリ列をリストに変換して操作した後にまたバイナリ列に戻さなければならない」というのは不正確</a> <span class="timestamp">(2020/05/23)</span> </li> <li> <a href="/2020/05/06/spring-holyday-programming-challenge-result/">GW引き篭もりチャレンジ:React+Electronでアプリを作ってみた総括</a> <span class="timestamp">(2020/05/06)</span> </li> <li> <a href="/2020/05/06/handling-double-click-event-in-react/">Reactでアプリを作ってみる(5日目) - ダブルクリックでファイルを開く</a> <span class="timestamp">(2020/05/06)</span> </li> <li> <a href="/2020/05/06/convert-react-app-to-electron-app/">Reactでアプリを作ってみる(4日目) - Electronを使ったアプリ化</a> <span class="timestamp">(2020/05/06)</span> </li> <li> <a href="/2020/05/06/show-image-dynamically-by-react/">Reactでアプリを作ってみる(3日目) - コンテンツの動的な表示</a> <span class="timestamp">(2020/05/06)</span> </li> <li> <a href="/2020/05/06/generate-thumbnail-image-from-pdf-with-nodejs/">Reactでアプリを作ってみる(2日目) - PDFからのサムネイル生成</a> <span class="timestamp">(2020/05/06)</span> </li> <li> <a href="/2020/05/06/create-react-app-with-openapi-and-nodejs/">GW引き篭もりチャレンジ:Reactでアプリを作ってみる(1日目)</a> <span class="timestamp">(2020/05/06)</span> </li> <li> <a href="/2020/05/03/build-ghostscript-on-macos/">macOSでGhostscriptをビルドする</a> <span class="timestamp">(2020/05/03)</span> </li> <li> <a href="/2019/07/09/kicad-4-to-5-update-notice/">KiCAD 4系からKiCAD 5系にアップデートするときにGitHub経由でフットプリントライブラリを参照するようにしているとハマる</a> <span class="timestamp">(2019/07/09)</span> </li> </ul> </div> </div> <div class="sidebar-box"> <h3>お知らせ:</h3> <h4>技術記事を執筆しました</h4> <div class="box-contents"> <p>技術情報サイト「<a href="https://knowledge.sakura.ad.jp/">さくらのナレッジ</a>」にて、技術記事を執筆しました(<a href="https://knowledge.sakura.ad.jp/author/hirom/">執筆記事一覧へのリンク</a>)。</p> </div> <h4>Git解説本を執筆しました</h4> <div class="box-contents"> <a href="https://www.amazon.co.jp/gp/product/4797380365/ref=as_li_qf_sp_asin_il?ie=UTF8&camp=247&creative=1211&creativeASIN=4797380365&linkCode=as2&tag=hylom-22" target="_blank"><img border="0" src="https://ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=4797380365&Format=_SL250_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=hylom-22" width="126" alt="デザイナーからプログラマーまで 絶対わかるGitバージョン管理" class="block"></a> <p>Git解説本「デザイナーからプログラマーまで 絶対わかるGitバージョン管理」を出版しました。コマンドラインおよびGUIクライアントのSourceTreeを使ったGitによるバージョン管理の流れを解説してします。また、コマンドラインリファレンスも収録しています。</p> </div> <h4>Node.js解説本を執筆しました</h4> <div class="box-contents"> <a href="https://www.amazon.co.jp/gp/product/4797370904/ref=as_li_qf_sp_asin_il?ie=UTF8&camp=247&creative=1211&creativeASIN=4797370904&linkCode=as2&tag=hylom-22" target="_blank"><img border="0" src="https://ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=4797370904&Format=_SL160_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=hylom-22" width="126" height="160" alt="はじめてのNode.js" class="block"></a> <p>Node.jsの解説本「はじめてのNode.js -サーバーサイドJavaScriptでWebアプリを開発する-」を出版しました。Node.jsのインストールや環境構築、パッケージの利用、Webアプリケーション作成、データベースやファイルアクセス、Expressフレームワークの利用、デバッグやテストといった、Node.jsでのWebアプリケーション作成に必要な知識を一通り解説しています。</p> </div> <h4>Mastodon入門書を執筆しました</h4> <div class="box-contents"> <a href="https://www.amazon.co.jp/gp/product/B00W4NAS2Q/ref=as_li_tl?ie=UTF8&camp=247&creative=1211&creativeASIN=B00W4NAS2Q&linkCode=as2&tag=hylom-22&linkId=4577fc1071ccf6d3c534bd5a7bc4fe91" taget="_blank"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&MarketPlace=JP&ASIN=B00W4NAS2Q&ServiceVersion=20070822&ID=AsinImage&WS=1&Format=_SL250_&tag=hylom-22" width="126" alt="Mastodonスタートアップガイド" class="block"></a> <p>分散型SNSであるMastodonの入門書を電子書籍として出版しました。初心者向けにMastodonの仕組み、用語、クライアントの使い方などを解説しています。</p> </div> <div class="box-contents"> </div> </div> <div class="sidebar-box"> <h3>関連リンク:</h3> <div class="box-contents"> <dl> <dt><a href="https://srad.jp/">スラド</a></dt> <dd>セキュリティ関連からどうでもよいネタまで幅広く扱う雑談サイト</dd> <dt><a href="https://osdn.jp/magazine/">OSDN Magazine</a></dt> <dd>オープンソース関連ニュース/情報を掲載</dd> <dt><a href="https://osdn.jp/">OSDN</a></dt> <dd>オープンソースソフトウェア開発支援サイト。私も使っています</dd> <dt><a href="https://github.com/hylom">GitHub</a></dt> <dd>公開Gitリポジトリ。こちらも愛用しています</dd> <dt><a href="https://vps.sakura.ad.jp/">さくらのVPS</a></dt> <dd>hylom.netはさくらのVPSサービスを利用してます</dd> <dt><a href="https://plus.google.com/115759524056726415451" rel="publisher">Google+</a></dt> <dd>hylomのGoogle+ページ</dd> <dt><a href="https://www.facebook.com/hylom">Hiromichi Matsushima | Facebook</a></dt> <dd>hylomのFacebook</dd> <dt><a href="https://twitter.com/hylom" rel="publisher">Twitter(@hylom)</a></dt> <dd>hylomのTwitter</dd> </dl> </div> </div> </div> </div> <footer class="site-footer"> <p>generated by <A href="https://gohugo.io/">hugo</a> at 2020-07-23T16:30:30Z </p> </footer> </body> </html>