yukke::note

technical note

Perlで相補鎖を返す関数を短く書く

DNAは、相補的塩基対形成という性質があって、AとG、TとCとしか水素結合を形成することは出来ない。つまり、ATCCという塩基の相方の塩基は必ずTCGGとなる。これを出来るだけ短く書きたい。 がんばったら、 で5行で、実質の処理をしているのは1行になる。うーん、ループ使わずに一行にしたいがどうやればよいものか。

$rev .= $_ =~ /[aA]/ ? 't' : $_ =~ /[cC]/ ? 'g' : $_ =~ /[gG]/ ? 'a' : $_ =~ /[tT]/ ? 'c' : '' for split //, my $s = shift;

で、というか、splitの2個目の引数で変数定義しつつ渡せるのか。

my $s = $str =~ tr/AaTtGgCc/TtAaCcGg/r;

でよくねーか......なんで気付かなかったんだろ。。。

githubのwikiエンジン"gollum"の導入と細かい設定

gollumの特徴、良いところなど

  • Markdown, MediaWiki, Textileなど大抵の記法で書ける。
  • 基本的にgitリポジトリ一つで完結しており、MySQLなどのDBが不要で、簡単にprivate wikiを立ち上げられる。
  • セットアップが非常に楽。
  • gitで動いているので、バージョン管理や差分、コミットを遡ってrevertする、なんてこともWebのUIから簡単に操作できる。
  • 全文検索も実装されている。
  • ruby+sinatraで実装されているので、分かる人は拡張を簡単に書ける気がする。

f:id:soh3914:20130502224751p:plain

導入

Python 2.5+ (2.7.3推奨)、Ruby 1.8.7+ (1.9.3推奨)とのこと。なのでpythonbrewなりrvmなりrbenvなりで新し目のpython+rubyを入れます。あとはgemからgollum本体をインストールします。

gem install gollum

rbenvのgemを使った場合は、~/.rbenv/shims/gollumに入るはずです。

gollum --version
=> Gollum 2.4.13

使い方

  • 適当なディレクトリにいって、
mkdir wiki && cd wiki
git init
gollum 

で起動し、http://localhost:4567からアクセス可能です。ポートは--portで任意に変更可能です。

でもそれだけじゃあれなので今は、

gollum --mathjax --no-live-preview --config auth.rb 2>gollum.log &

としてデーモンっぽく起動させています。 mathjax.jsによってTex書式で数式を書くことができ、--configで外部の設定ファイルを読み込めます。

あとは、もうmarkdownですきなことを書いていけば宜しいという感じで。詳しくは、https://github.com/gollum/gollum/wiki を参考にしてみてください。コマンドラインから編集したりした場合は、ファイルをcommitしない限り、gollumには反映されません。

数式を書く

インラインの場合は、\\( \frac{x}{y} \\)とか。そうじゃない普通の場合は、$$ \frac{x}{y} $$と書く。数式(Mathjax)をデフォルトで使えるのは一部の人にはありがたいですね。

画像をはりつける

[[hoge.png]]と書くと、オリジナルサイズで画像が表示されます。urlの場合も同じ記法で書くことができます。また、gollumの拡張として、[[hoge.png|heigh=400px]]とかでサイズ指定、align=centerとかもできます。もちろん、markdown記法である![]()も使えます。

ヘッダやフッタなど

ヘッダーやフッターは、_Footer.md_Header.mdというファイルを作って、コミットしてあげるとgollum側が勝手にそのファイルを全てのサイトに共通のヘッダやフッタとして認識してくれます。例えば、_Sidebar.mdに、_[[toc]]_と書くことで、ページ内のTable of contentsを自動で生成することができます。(TOCは日本語も問題なく使えています。)ただ、日本語は文字化けしてそのままでは使えません(未解決)。

カスタマイズ

  • デフォルトでも基本的にはよいのですが、すこしいじったり書き加えたりしました。rubysinatraもrackも全く分からないのでまったく分からないです。

画像のアップローダ

gollumで一つ問題だったのが画像やpdfをリンクとして貼り付けたい、ということです。これは公式にサポートされていません。なので、~/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/gollum-2.4.13/lib/gollum/app.rbに、

post '/upload' do
  if params[:file]
    new_filename = DateTime.now.strftime('%s') + File.extname(params[:file][:filename])
    save_file = './upload_files/' + new_filename
    File.open(save_file, 'wb'){ |f| f.write(params[:file][:tempfile].read) }
    p "http://hoge.com/yukke/gollum/upload_files/", new_filename
   end
end

とか追記してアップロードできるようにしておきました(http://yusukezzz.net/blog/archives/1388をそのまま参考にしました)。

wikiに認証をつける

パーソナルなwikiなので認証を付けたいです。apache.confで認証させてもいいのですが、gollumには--configというオプションを渡すことで簡単に認証をつけることができます。

module Precious
  class App < Sinatra::Base
    use Rack::Auth::Basic, "This is private wiki" do |username, password|
      [username, password] == ['yukke', 'passwd']
    end
  end
end

をauth.rbとかで保存しておき、gollum --config auth.rbとすることでBasic認証を簡単に実装できます。Rack::Auth::*には、OpenIDによる認証するメソッドもあったりするので、twitterアカウントで認証させるなども出来そうです。あと、auth.rbに平文でpasswdを書くのはアレな気もするので、そのあたりは別のyamlを読むとかそういった工夫をすればよいかと。

ヘッダーをつける

なんとなく殺風景なデザイン(シンプルで良いのですが飽きる)なので、ちょっと変化をつけるためにカスタマイズすることも可能です。rbenvを使った場合は、~/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/gollum-2.4.13/lib/gollum/templates/とかがgollumの検索や各ページのテンプレートになっています。今回、ヘッダを全てのページに付けたいので、この中のlayout.mustacheにちょこっとdivを付け足します。検索ページだけをカスタマイズするには、search.mustacheを編集すればよいでしょう。

<div id="cust-header-wrapper">
     <div id="cust-header">
          <h1>My gollum wiki</h1>
     </div>
</div>

などと書きました。 ここに対応するCSSは、~/.rbenv/versions/1.9.3-p194/lib/ruby/gems/1.9.1/gems/gollum-2.4.13/lib/gollum/public/gollum/css/gollum.cssですが、custom.cssとか別のファイルにして読み込ませるようにしたほうが良さそうです。

#cust-header-wrapper {
    background: transparent url('header.png') top center repeat-x;
    height: 100px;
}
#cust-header {
    width: 85%;
    margin: 0 auto;
    text-align: left;
}
#cust-header h1{
    padding: 1.1em 0 0 0;
    height: 80px;
    font-size: 50px;
    color: #eee;
}

githubへpushする

apacheのDocument rootが例えば/var/www/html/だとすると、権限がrootやwwwになっているかと思います。そのままだと自分のgitの設定などが使えないので、gollum以下のディレクトリをroot権限ではなく、普段のユーザー権限に変更し、githubへpushできるようにしました。例えば、

#!/usr/bin/env perl

use strict;
use warnings;
use Git::Repository;

my $gollum_path = '/var/www/apache/users/gollum/.git';
my $git = Git::Repository->new(git_dir=>$gollum_path);
my $status = $git->run('push', 'origin','master');

このようなperl scriptをcronで毎日1回回せば自動的にgithubへpushされ、バックアップ機能を果たすことができますね。

問題点

  • 基本的に日本語(マルチバイト)が弱い、マルチバイトに対応?してないメソッドが呼ばれたりしてるところでwarningsが出たりするのですが、ruby力低すぎて直せなかった。なんとかしたい。
  • ファイル名やディレクトリ名に日本語を使うと検索でgollumを巻き込んで落ちたり、必ずエラーを吐きます。
  • 日本語でTOCを生成できなく、文字化けします。

追加したい機能

  • もうちょっとマシなファイルアップローダー。画像のギャラリーから編集時に貼り付けるとかしたい。

最後に

gollum、dokuwikiとかmediawikiとかよりセットアップも楽だしシンプルで良いとおもうのだけどいまいち流行ってない気がするので売れてほしいですね。開発もけっこう盛んなようですし、watchしとくといいかもしれません。そう思いながらいろいろ細かいことも書きました。参考になれば。(大事なのは毎日ちゃんと記録をつけたりすることですが、、)

タイムトラッキングツールTogglの結果をR+ggplot2で可視化してみる

 最近、Togglというサービスを使っている。Togglはタイムトラッキングツールみたいな感じで、何にどれだけの時間を使っているのかを記録するサービス。例えば、勉強した時間とか本を読んでいる時間とか、そういうのをログに残すことができて、励みになったり、さぼっているのが一瞬でわかると思った。習慣にしたい。
 Togglのサイトを見ていたら、その結果のファイルはreport.csvとしてダウンロードできることがわかった。せっかくなので、Rで可視化してみることにした。1ヶ月とか、データが溜まってきたら傾向とかそういうのがわかるかもしれない。まだ4日。

 というこで、ざくっとR+ggplot2を使って可視化してみた。

  • ggplot2のgeom_bar()のところで、geom_bar(aes(fill=toggl$Project)としてあげることで、プロジェクトごとに色付けしてプロットしている。
    ちなみに、report.csvは以下のようなデータ構造になっている。
User,Email,Client,Project,Task,Description,Billable,Start.date,Start.time,End.date,End.time,Duration,Tags,Amount()

f:id:soh3914:20130406140635p:plain

  • 縦軸は経過時間、横軸に日付になっていて、4/5はちょっとさぼってしまったな、とかそういうのが把握できる。

  • Pie chartならこんな感じか。

f:id:soh3914:20130406142912p:plain

とはいっても、togglはじめてまだ一週間も経っていないし、がんばって続けたい。なんというか、ライフハック!!!!という感じである。

config file in R

  • $HOME/.Rprofileに書く。
  • .Last()と.First()は、起動時に読み込まれる特殊?な関数名。
  • 起動オプションで、R --quietとすると、startup messageがoffになる。
R>> sessionInfo()
R version 2.15.3 (2013-03-01)
Platform: x86_64-unknown-linux-gnu (64-bit)

locale:
 [1] LC_CTYPE=ja_JP.UTF-8       LC_NUMERIC=C
 [3] LC_TIME=ja_JP.UTF-8        LC_COLLATE=ja_JP.UTF-8
 [5] LC_MONETARY=ja_JP.UTF-8    LC_MESSAGES=ja_JP.UTF-8
 [7] LC_PAPER=C                 LC_NAME=C
 [9] LC_ADDRESS=C               LC_TELEPHONE=C
[11] LC_MEASUREMENT=ja_JP.UTF-8 LC_IDENTIFICATION=C

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base

other attached packages:
[1] BiocInstaller_1.8.3 colorout_1.0-0

loaded via a namespace (and not attached):
[1] tools_2.15.3
R>> R.version
               _
platform       x86_64-unknown-linux-gnu
arch           x86_64
os             linux-gnu
system         x86_64, linux-gnu
status
major          2
minor          15.3
year           2013
month          03
day            01
svn rev        62090
language       R
version.string R version 2.15.3 (2013-03-01)
nickname       Security Blanket

pythonことはじめ

 ちゃんとオブジェクト指向プログラミングを勉強したいなと思ったいたので、pythonを新しくやろうかなと思っている。rubyよりはpython書きたいっていう感じ。bioinformatics向けのチュートリアルやオライリー本もそこそこ充実している。それに、numpy、scipyといった最強なライブラリもあるし、matplotlibやRPyでグラフ書いたりR動かしたり出来るのも魅力的だった。というわけで、perlくらい書けるようになればなーって思っている。ことはじめということで、pythonbrewを使って、pythonをインストールした。

curl -kL http://xrl.us/pythonbrewinstall | bash
[[ -s $HOME/.pythonbrew/etc/bashrc ]] && source $HOME/.pythonbrew/etc/bashrc
source .zshrc
pythonbrew install Python-2.7.3
pythonbrew switch 2.7.3
which python
#=> /Users/yukke/.pythonbrew/pythons/Python-2.7.3/bin/python

コードはまだ書いていない。

perlのGetopt::Longを使った感想

 perlのデフォルトのモジュールには、Getopt::Longが入っており、コマンドラインの引数処理を楽に書くことができるようになっている。
これまでは、自前でオプション名や引数の型チェックなどを書いていたが、いい加減べんりで楽な方法を使ってみることにした。

基本

 ベーシックな使い方は、

#!/usr/bin/env perl

use strict;
use warnings;
use Getopt::Long;

GetOptions ('help|man' => \$HELP,
             'in=s'     => \$INFILE);

のようにオプションを渡していく。

  • perl $0 -in file.txtのような使い方になる。
  • help => \$HELPだと、引数を要求せず単独で動く。
  • |を使うことで、複数の名前を使える。e.g. helpとh、versionとverなど。
  • オプションと値をハッシュにしたり、予め変数宣言のときにデフォルト値をセットしておくこともできる。
  • option名=s(strings)で値に文字列以外が与えられた場合は、エラーを出力する(※プログラム自体はそのまま実行されるので注意)。=iはinteger、=fはfloatになる。このとき、=sで[0-9]をセットしても、文字列として数字が評価されるのでエラーにはならないことに注意。

 これで、楽に引数やセットされる値はチェックできるが、--helpや--manをしたときは、ヘルプを表示してプログラムを終了させることや、実行に必須な引数が不足した場合にはdie()することなどは出来ない。
 そこで以下のようにして書いてみる。

変なオプションが渡されたときは死のう

use Getopt::Long;

## Default value:
my $HELP = undef;

GetOptions ('help' => \$HELP) || die "Invalid options";
  • これで、変なオプションが入った時には、dieするようになる。

--helpした時だけ、ダイイングメッセージ

my $HELP = undef;

GetOptions ('help' => \$HELP);

if ($help) {
    die "Usage: { something... }"
}
  • デフォルトでは未定義なので、--helpされるとdie()する。

オプションの数が足りないときは死にたい

use Getopt::Long;

if (scalar @ARGV<1) {
    die show_help();
}

sub show_help {
    my $help_doc = <<EOF;
this is test program

Usage:
       perl $0 [options]

Options:
         --infile
         --help
EOF
    return $help_doc;
}
  • Getopt::Longは面倒を見てくれない(たぶん)なので、普通に条件を書く。
  • インプットファイルがないときは死にたいなども、デフォルトをmy $infile = undef;としておいて、後でセットされているかをif文でチェックすれば良い。

感想

  • やっぱり便利だった。もっと早くから使うべきだった。
  • なんかいっぱい死にたいって書いた気がするけど、別に死にたいくないです。
  • 最近、らーめん食べてない気がする。

おしまい。