一時期、「最強のSSH踏み台設定」という記事が話題になりました。.ssh/configのHost設定でスラッシュを区切り文字とすることで、動的な踏み段設定ができるというものです。 この手法を応用して、基本的にProxyCommandが必要な環境下で動的に変わるIP相手に対し、アドレスにprefixを付けることで常にあるProxyCommandを実行させるような設定を行ってみました。 ssh aws-u_xxx.yyy.zzz.wwwとすれば常に特定のユーザー、鍵、Proxy経由で接続するようになります。区切り文字にアンダースコアを使っているのは、スラッシュを使った場合にscpでホスト名と判断されない場合があったからです。ssh, sftpコマンドではスラッシュでも特に問題ありません。
Category: ソフトウェア
rep2の更新
周りにある大半のDebian環境をwheezyからjessieにアップグレードしたのですが、先日ようやく自宅のPCルーターマシンもアップグレードしました。 合わせていろいろなものが更新されたのですが、phpの変更が大きかったようで、それまで使っていたrep2exがきちんと動作しなくなりました。もともと使っていたのは相当前のコードベースであり、いまどきはgithubで管理されているコード(https://github.com/2ch774/p2-php)があるので、この機会にそちらに移行しました。 基本的にはまっさらな状態でセットアップを行い、一部のデータをコピーすることで、未読情報や画像DBも含めて移行できました。やったことは以下の通りです。 old-rep2/data/2channel ->p2-php/data/dat/2hcannel へコピー old-rep2/data/db -> p2-php/data/db ic2のdsnをp2-php/conf/conf_ic2_inc.phpに記述 幸いic2のデータはMySQLに保存していたので、特に移行上の問題はありませんでした。未読情報もdata/dbにあるSQLite3のデータをコピーするだけでいけました。 ユーザーの設定に関しては新規にやりました。これも頑張れば移行できたのでしょうが、ちょっと面倒に感じたのと設定すべき項目がそれほどないことからやりませんでした。 ユーザー設定の中に、「データ転送量を抑えるためにカタカナを半角にする」というオプションが標準でONなあたり、このソフトウェアの歴史を感じます。思い返せばWillcomの京ポン2あたりから使っていました。 iPhoneが出たぐらいの頃にスマホ用のUIも整備されたので、今使っても悪くありません。
Orange PI PC
g新部さんが強くプッシュしているOrange PI PCを購入しました。実際に購入したのは先月ぐらいだったのですが、最近ようやくまともに使いだしたところです。 Orange PIシリーズは複数あるRaspberry PIのフォロワーの一つです。私は以前秋月電子で同じような”Banana PI”というのを見かけたことがあるのですが、気が付くと手に入らなくなっていました。 g新部さんが最も良しとしている点は、ハードウェアメーカー(Allwinner)が情報開示に積極的にであることだそうです。Raspberry PIはその点で確かに厳しいようです。 そのあたりの話が11月のFSIJ月例会でありました。その時の発表内容をTogetterでまとめたので、興味のある方はご覧ください。月例会のページにもいくつか情報があります。 2015年11月 #FSIJ 月例技術講座 Orange PI PCを使ってみる 私の興味はH.264のハードウェアエンコーディングにあります。g新部さんからお勧めされた時に、Allwinner H3のスペック的にハードウェアエンコーダーを持っていることを確認して購入しました。しかしまだそこを動かすには至っていません。情報はそこそこあるようなので、なんとかしたいところです。
LanguageToolで長音記号チェック
漢字変換ミスで、たまに長音記号がかな文字以外の後に置かれる事例を見かけたので、それをLanguageToolのルールにして取り込んでもらいました。 現状ある日本語のルールをざっと見たのですが、うまい具合に表現する方法が思い浮かばなかったので、思い切ってメーリングリストで聞いてみました。 メイン開発者のDanielさんは親切で反応も早い方で、「正規表現でUnicodeの範囲を使えばできる」という方法を示してくれました。また、過去にも日本語のルールを書いているSilvanさんからは、JavaにおけるUnicodeのクラス表現(\p{IsXxx})を紹介してくれました。 これらを踏まえ、以下のようなルールをpull requestとして書き、無事masterにマージしてもらえました。 カタカナとひらがな以外が長音記号の前にあるとき、LanguageToolは警告を出します。 この機会に、Doc-ja Wikiの”LanguageTool使い方メモ“も若干修正しました。自前のgrammar.xmlを指定して起動する方法と、ソースコード上で変更をしたときにルールのテストをする方法について新た説明を加えています。 LanguageToolのリリースバージョンは現在2.9ですが、次期バージョン3.0ではgrammar.xmlの書式も変わっているため、いずれWiki内の説明もそちらに合わせて修正したいところです。
gensimとword2vec
何かと話題のword2vecですが、自分も使ってみようと思って試行錯誤したことを書いてみます。間違いなどあればぜひコメントください。 GoogleのC実装 https://code.google.com/p/word2vec/にある、C言語による実装は独立したアプリケーションで、Apache 2.0ライセンスで提供されています。 ビルドした状態でword2vecコマンドを使って学習、モデルを作成し、distance等のコマンドからモデルをもとにデータを出力します。以下はword2vecを引数なしで実行したときの実行例です。 各オプションの意味は以下になります。 train: 学習対象のテキストデータ(コーパス) size: 次元数(デフォルトは100) window: skip-gramの対象とする単語の最大数を指定(多分)デフォルトは5 sample: 単語を無視する際の頻度の閾値(デフォルトは1e-3) threads: 処理するスレッド数 hs: Hierarchical Softmax(階層的Softmax)を使う(1)/使わない(0) negative: ネガティブサンプリングに用いる単語数 binary: 出力結果をバイナリ形式にする(1)/テキスト形式(0) cbow: Continuous Bag-of-Words 連続単語集合モデルを使う(1)/使わない(0) iter: 学習する回数(イテレーション)の指定。デフォルトは5 CBOWとSkip-gramについてはFiS Projectの記事がわかりやすいです。階層的SoftmaxとネガティブサンプリングについてはnishioさんによるQiitaの記事が詳しいです。 gensim(Python)実装 gensimはPythonとCを組み合わせて記述された、文書解析ソフトウェアパッケージです。ライセンスはLGPL3+で、ソースはhttps://github.com/piskvorky/gensimで公開されています。 もともと複数の計算モデルを扱えるようになっていたようなのですが、2013年9月ごろにword2vecが追加されたようです。webで紹介される実装はこちらの方が多いようです。 Google実装はサンプル実装という面が強く、コマンドからできることに限りがあります。それに比べるとgensimはできることが多い(任意の数の単語のpositive/negativeな演算ができる)のですが、モデル構築にメモリをより使用します。 1GBのテキストをコーパスとしてgensimのword2vecに与えたところ、メインメモリ8GBのマシンでスラッシングを起こしてしまいました。Google実装であれば、1GB程度のテキストはオンメモリで処理できるようです。また、POSIX threadによるマルチスレッド処理にも対応しています。 幸いなことに、gensimのWord2VecではGoogle実装のモデルを読み込ませることができます。大きなデータを扱う際には、これらを組み合わせるとよい感じです。 pythonで処理したモデルもファイルに保存することができます。 gensimでは、trainメソッドで後から追加学習させることもできるのですが、既に構築したモデルに存在しない単語は扱えない(語彙が増やせない)ようです。これに気付かず、分割したテキストデータをちょっとづつ学習させるというようなことをやらせようとしてはまりました。 結局、大きなコーパスを取り扱う際にはC実装でモデルを構築して、それをgensimで読み込むという使い方をするのが良いようです。 その他参考にした資料 ディープラーニングチュートリアル 応用編 追記(2015/5/20) gensimでword2vecの処理がシングルスレッドでしかできないような表現でしたが、Word2Vecの引数にworker=2等とすることでマルチコア動作することに気付きました。それでも処理速度はGoogle実装の方が早いとは思いますが、記録として残しておきます。
LanguageToolのgrammer.xml
先日の東京エリアDebian勉強会ハックタイムで、もう少しLanguageToolをみて行きました。いくつか誤解があったのと、gitのコードを見ていて気づいたことを記録します。 私が参照していたJapanese.javaがgrammar.xmlでカバーできないケースをソースコードレベルで対応するものだと勘違いしていたのですが、ここは単にテキストの分割と品詞情報の付加を行うための処理を記述するもののようでした。 grammar.xmlはもっと柔軟性が高いようで、LanguageTool Wikiに高度な処理を行う方法も記述されています。一方でやはりgrammar.xmlだけで対応しきれないケースはJavaで書けることも記述されています。 今回追加しようと考えていたのは、長音符「-」の直前の文字がひらがな、カタカナ以外のケースです。基本的にそれはありえないので、LanguageToolが指摘すべき問題とすべきでしょう。 Doc-ja Wikiに書いた方法で-tオプションを利用すれば、そのようなケースの時に「-」はどのような品詞情報が付加されるかを調べることができます。 単独の長音符「ー」は「未知語」と解釈されることがわかりました。単純にtokenがーでPOSが未知語である情報が検出されたら警告すればよさそうです。 しかし現状のLanguageToolはmasterのバージョンが3.0となっており、grammar.xml自体の文法も変わっていることに気付きました。したがって、Doc-ja Wikiの説明も今後は修正が必要になります。 ということを把握したところで先日は時間がなくなってしまいました。grammar.xmlの解説だけでも結構ボリュームがあるので、これを翻訳できると自分を含めうれしい人はいるかなあと思いました。
将軍の名前を補完するshogun-completion
かつて、どこかで「プログラマが徳川将軍の名前を覚えられないのはshellで補完できないからだ」という言説を見かけ、それを解消するべくbashで徳川幕府の将軍名を補完できるshogun-completionというものを作成しました。 当時課題だった問題2点に対応すべく、このたび改良版を公開しました。 鎌倉幕府対応 以前の実装では徳川幕府のみにしか対応していなかったので、オプションにkamakuraを入力した上で補完をすると、鎌倉幕府の歴代将軍を補完できるように修正しました。 shogunコマンドの実装 以前の実装は実在しないshogunコマンドに対する補完、という実装だったのですが、このたびshogunコマンドも実装しました。開発言語にはgolangを用いています。ごーしょーぐんとでも呼んでください。 shogunコマンドの引数に将軍名を入力すると、何代目であるかの情報を出力します。これで以前の実装では対応できなかった、「当該将軍が何代目であるかわからない」という問題にも対応できました。 bashにおける補完の限界 実のところ、zshの補完であればもっと高度なことができます。将軍名を補完する際にそれが何代目であるかの情報を表示するといったことも可能です。 じゃあbashでできないかというと、頑張ればできそうではあります。”bash autocompletion: add description for possible completions“というStackOverflowのやり取りに一例がありました。以下はそのコードの転載です。 ローカル変数completionsに行区切りで補完したい情報を代入しています。その結果を、IFSに改行のみを設定したうえで、compgenに処理させています。これで、入力にマッチする補完候補のみが配列としてCOMPREPLYに代入されます。さらに配列の数が1つだった場合、文字列” – “以下の部分を切り取って返します。その結果、この例では入力したいIPアドレスのみが実際には補完される、というわけです。 このアプローチを自分も試してみたのですが、bashのバージョンのせいか、IFS=”\n”とした状態でもcompgenの出力全体を代入された1個の配列にしかなりませんでした。IFSを使わない方法も試してみたのですが、思うように複数個の配列にできなかったのでそこで断念しました。あと、当該記事にも書かれていますが、IFSの変更は影響が大きいのでむやみにやらない方がいいようです。
CMakeで自動生成ファイルを出力させる
あるソースコードにテーブルが配列として含まれているという状況で、メンテナンス性を高めるためにその内容を別のファイルに分離して、機械処理で配列として出力し、それをincludeするという手段を考えました。 これをautomakeで実現するのはそれほど難しくないのですが、autotools依存を避けるためにCMakeで実現する方法を調べてみました。 最終的に、以下のようなCMakeLists.txtで実現できました。 src/kk2.cがk2rom_hepburn.cをincludeすることを前提としています。k2rom_hepburn.cはperl scriptを通してtable/k2rom_hepburn.txtから生成します。 生成するスクリプトはadd_custom_commandを使います。OUTPUTに出力するファイル名、COMMANDに実行するコマンドを記述します。行が長くなる場合には、改行を任意の箇所で入れられるようです。 出力するファイルk2rom_hepburn.cを直接ターゲットとして扱えないようなので、add_custom_targetでgenerate_headersというターゲットを明示して作成し、その依存関係としてk2rom_hepburn.cを記述します。 最後に、作成したターゲットを依存関係へ組み込むためadd_dependencyを使います。これで、libkakasiの生成にgenerate_headersが依存することを明記しました。 以上のステップを踏むことによって、k2rom_hepburn.txtからk2rom_hepburn.cが生成された上でkk2.cがコンパイルされ、それをもとにlibkakasi.soが出力されます。
VMware PlayerからVirtualBoxへの移行
最近のスラッシュドットの記事から、VMware Playerのライセンスにおける「非商用の解釈がかわった」という記事(ライセンス解釈が変わったようです。)を目にし、この機会にVirtualBoxへの移行を実施しました。 移行対象は違いますが、既にやってみた人の記事(VMware Fusion 5からVirtualBox 4.3への移行)があったので、作業自体はそれほど難しくはありませんでした。ただ、この記事にもあるようにストレージをSCSIからIDEに変更する、という作業はVMware Playerでも同様に必要でした。 自分の場合、もう一点「ホストオンリーネットワークもそのまま移行したい」という希望があったので、そのために若干の作業が発生しました。参考にしたのは「VirtualBoxのネットワーク設定とCentOS6.5のインストール」です。こちらの記事はMacOSXのようですが、Windowsでも行うことはあまり変わりません。 VirtualBox マネージャーからメニューの「ファイル」「環境設定」を選択し、ダイアログを開きます。さらに「ネットワーク」「ホストオンリーネットワーク」を選択し、ネットワークを追加します。ネットワークレンジやネットマスクを、これまでVMware Playerで使っていたものと同じになるよう設定します。 ここで一点注意があります。VMware Playerが入ったままだと、VMwareの仮想ネットワークインターフェースが設定として保持されたままになるので、vmnetcfg.exeで設定を変更するか、VMware Playerをアンインストールする必要があります。そうしないと、同一のネットワーク設定が存在しているとWindows側に認識され、リンクローカルなネットワークが強制的に割り当てられてしまいます。 あとはOVF化した仮想マシンをVirtualBoxからインポートし、ネットワーク設定を先ほど作成したホストオンリーネットワークに指定して、実際に通信ができれば完了です。 NATネットワークの移行も、ほぼ同様の手順で実行し、Window側のネットワーク共有を使えばできると思います。
Web APIのリトライ処理実装
Web系のAPIをたたいていると、たまにエラーが発生することがあります。要因はサーバー側がたまたまおかしかったり、proxyだったりと様々です。 エラー時にはリトライしつつAPIをたたく方法はいろいろ考えられますが、C#でのスマートな実例がStackOverflowで紹介されていました。リトライ専用のクラスとstaticメソッドを実装して、呼出にはデリゲート、ラムダ式を用いるという手法です。 Rubyでも同様の処理を行うコードを考えてみました。