その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

相手の GitHub の ID さえ知っていれば暗号化したメッセージを送れる naisho というのを作った

色々な事情があり,秘密のメッセージを送り合う必要性が今年に入ってから多数発生していて,
そのたびに毎度毎度手で暗号化して〜みたいな風にやるのめんどいですね,そうですね,
ということでこの度 naisho というものをこさえました.みんなには内緒ですよ.


これは何かと言うと,やりとりしたい相手の GitHub の ID を指定するだけで

  • その ID のユーザの ssh-rsa の公開鍵を引っ張ってきて
  • その ID のユーザのメールアドレスを引っ張ってきて
  • そのメールアドレスに対して公開鍵で暗号化したメッセージを添付ファイルにしてメールで送りつける

という動きをするコマンドです.
golang で書きたかったというのと golang で書くと便利なのではと思ったので golang で書いてあります.


Wercker で Go のプロジェクトをクロスコンパイルし、GitHub にリリースする - 詩と創作・思索のひろばや,
werckerでgithubにreleaseをdeployするまでの道のり - yuukichiの日記
を参考にすることで、wercker でバイナリをビルドして GitHub Releases に成果物を設置するということも出来ました.
Releases · moznion/naisho · GitHub からお手軽に入手頂けます.


さて使い方としては

$ naisho <Target GitHub ID> <Message>

としてやるだけで,対象の GitHub ID のユーザーに暗号化した Message を添付ファイルにしてメールで送りつける事ができます.
受け取った側は openssl さえ持っていれば良くて,

$ openssl rsautl -decrypt -inkey <Your Secret Key> -in <Attachment>

という感じで,公開鍵と対応している秘密鍵と添付ファイルを指定してやるだけで内容を読むことが出来ます.


中身の仕組みですが,GitHubhttps://github.com/<user-id>.key という所にアクセスすると,
任意のユーザの ssh-rsa 公開鍵の一覧を引っ張ってこれるという機能があるので *1
ここから一番上の公開鍵を引っ張ってきてそれで暗号化しています.
送信先メールアドレスはプロフィールページ (つまりhttps://github.com/<user-id>) に書いてあるメールアドレスを
GitHub API 経由で取得してくることができるのでそれで取ってきています.
従って,当然ですが公開鍵を登録していないユーザや,メールアドレスを公開していないユーザには送ることが出来ません.残念!


使う鍵の鍵長によって暗号化出来るバイト数が変わってきて,

鍵長ビット 暗号化可能バイト
1024bit 117byte
2048bit 246byte
4096bit 502byte
8192bit 1018byte

という感じなので,そこまで長いメッセージは送れないという世界観です (バイト数が溢れると暗号化に際してエラーが出る).

しかしこれは十分な長さです! これで私にクレジットカードの番号や WebMoney のコード等を安全に送り放題ですね!! やりました!!!


今後の予定としてはファイル入力を受け付けられたり,使う公開鍵をインタラクティブに選べたりできたら良いなあとぼんやり思っています.あとエラーメッセージが雑極まりないので直したいですね!
ご利用くださいませ.

*1:ゆくゆくは無くなるらしい……

git でファイルごとのコミット数を取ってきて,プロジェクト中のホットなファイルを割り出すという試み

途中の段階でプロジェクトに入った時などに,「どれがそのプロジェクトの中心となっているファイルなんだろうか」というのを手っ取り早く知りたくなる時があります.僕はあります.


そこで「どのファイルが盛んに変更されているのか」という点を指標として注目すると,良い感じにそこら辺取れるのでは無いかと思って試してみました.
コミット数が多いファイルは多く変更を加えられているということから,そうしたファイルはホットであるということが言えそうな気がしたので,git でファイルごとのコミット数を取ってきて,それをソートして見てやれば良いよな,という意識でやっていきました.もちろんコミットの粒度などもあるでしょうから一概にはそうとは言い切れませんが,参考にはなる気はします.


使うスクリプトは至って簡単.以下の様な感じです.

git ls-files |
while read file ; do
  commits=`git log --oneline -- $file | wc -l`;
  echo "$commits - $file";
done | sort -n

git で管理されているディレクトリ内でこのシェルスクリプトを走らせるとそのような情報を取ってくることが出来ます.
railsリポジトリで試してみました所,以下の様な結果が得られました.

1 - actionmailer/lib/rails/generators/mailer/templates/application_mailer.rb
1 - actionmailer/test/fixtures/anonymous/welcome.erb
1 - actionmailer/test/fixtures/another.path/base_mailer/welcome.erb
1 - actionmailer/test/fixtures/asset_host_mailer/email_with_asset.html.erb
1 - actionmailer/test/fixtures/asset_mailer/welcome.html.erb
<中略>
549 - activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
556 - actionpack/CHANGELOG.md
745 - activerecord/lib/active_record/associations.rb
1134 - activerecord/CHANGELOG.md
1145 - activerecord/lib/active_record/base.rb

なるほどという感じです.正しいのかどうかはよくわかりません.rails 識者の方どうでしょうか.
めっちゃコミット数あった (5万コミットくらい) ので実行に15分くらいかかって大変微妙な心境になります.


よくわからなかったので,なんとなくわかるであろう Plackリポジトリで試してみます.

1 - eg/dot-psgi/Dumper.psgi
1 - eg/dot-psgi/echo-stream-sync.psgi
1 - eg/dot-psgi/runnable.psgi
1 - eg/dot-psgi/static/index.html
1 - eg/dot-psgi/static/test.js
<中略>
113 - Makefile.PL
150 - lib/Plack/Response.pm
178 - Changes
197 - lib/Plack.pm
211 - lib/Plack/Request.pm

なるほど,それっぽい感じがしますね!! (こっちはすぐ実行し終わった)


という感じでまあまあ参考になる情報が取れるのではないでしょうか,という気持ちです.試しに色々なリポジトリに適用していってますが,それっぽい結果が得られてて面白いですね.
逆にコミット数が少ないファイルはメンテされてないから危険,みたいなのも分かるんでしょうか.要検討という感じです.
グラフ等で可視化してやるとまた面白さが出てくるかもしれませんね.

参考


[追記]
歴史が深いリポジトリでやるとめちゃめちゃ時間がかかって大変なので,トラックする log の数を制限するとかが必要になってくるかもわかりませんね.
あと「昔はホットだったけど最近はホットではない」みたいなのもあると思うので,常にすべてのコミット履歴を追う必要は無くて,ある一定のところでバチッと切ってしまうとか,そういうのも考えていく必要があるのかな~とか思った次第です.

こんな風に (この例では -1000 で制限をかけている).

git ls-files |
while read file ; do
  commits=`git log -1000 --oneline -- $file | wc -l`;
  echo "$commits - $file";
done | sort -n

[追記]
log の数に制限かけても処理時間そんな変わらないので,ファイル数の問題であることが伺えます.厳しい……
とは言え「昔はホットだったけど最近はホットではない」みたいなのには関係してきそうなので検討する価値はありそう.

間違っているので見なかったことにしましょう

Groovy 所感

開発のサポートツールやらなにやらで,こまごましたものを Groovy でちょいちょい書いて思ったことです.
Groovy で Web アプリケーションを書いたとかそういうゴツい話ではないのでそのあたりはよくわかりません.
なお本記事中に出てくる Java っていうのは Java 8 以降のことを指していると思ってください.

所感
  • 楽にコードが書けるという点では良い.言語的にそういうところを重視している気がする.
    • defとか.あとは DB 操作とか結構良い.楽.
    • System.out.println() とか書かなくて良いのは本当に良いですね.
    • とは言え,なんだかんだで補完の支援を受けないと記述コストは大きいと思う.賢い補完が要る.
  • gradle は pom.xml 書くよりもストレスが小さい気がする.
    • とは言え maven でもめんどいことは gradle でもめんどい印象.
    • 結局なんか,適宜やっていきましょうという感じになる.
    • つうか gradle はあんまモリモリやってないからよくわからん!
  • 実行速度は特に感想無いです.チョイノリみたいなツールだと全く問題にならない.
    • 重い処理するやつとか,Web アプリケーションとかだと色々あるかも.知らない.
  • 書いたら LL 感覚ですぐ動くので,挙動を確認するための書き捨てのコードとかにはうってつけだと思う.フットワークが軽い.
  • groovysh 便利.Groovy の REPL 的なやつ.挙動をパッと調べたいときに有益.
  • Java と比較した時にコードが簡潔に書ける傾向にあるので,本質的な処理を理解しやすい.
    • サンプルコードとかに向いてると思う.
  • Groovy の便利記法結構あるけど,Java に似たようなのがちょいちょい入ってるから (lambda とか),そこがマッシブな優位点になるかどうかという点.
    • まあ Groovy の便利記法は便利は便利.
    • Java でも8以降は戦えるのでは.
  • 当たり前の話だが groovy の処理系が別途必要となってくる.
    • Groovy のスクリプトJava のプロジェクトの支援ツールとして配布するとなると,その利用者にGroovy のインストールを強制することになる.
    • まあ入れれば良いですねという感じだけど,めんどいですよね.
    • Java のプロジェクトの開発支援ツールに Groovy を含めるのはまま便利だ (った) と思うんですが,21世紀にはなんと CI ツールなどが存在していて,CI 回すたびに jar をパッケージできる感じになってきているので,Groovy のスクリプトではなくその jar を配布すれば良いのではという意識の高まり.
      • 新たに処理系を入れる手間とか心理的なアレとかが消える.
      • そういう jar のパッケージングが極めてめんどい時は Groovy 使うと良いのではという気持ち.
      • ブックマークコメントで便利情報もらったので追記しました.
  • Pivotal がスポンサーから外れるの心配ですね.
まとめ
  • 挙動を確認したりするための書き捨てのスクリプトに使うのは良さそう
    • ついでに言うと groovysh が便利
  • サンプルコードに使うのは向いていると思う
  • それ以外の用途で積極的に使う理由が積極的に無い……
  • Java のプロジェクトの開発支援ツールみたいな用途だったら,Groovy じゃなくて (fat-packed) jar を配ってやっていく方が良いのではないか


という感じです.こういう意識になりました.書き味は気持ちのよい部類だと思われます.
gradle はちょっと評価できるほど使っていないので感想変わるかもしれないですね.


[追記]

Groovy 所感 - その手の平は尻もつかめるさ

Groovyのインストールを強要するのでなく、groovy-all.jarをクラスパスに含めるだけで良いのでは?

2015/01/28 22:12

なるほど.良さそう.ありがとうございます.


[追記]
Java のプロジェクトに Groovy のプログラムを含めるの,まあ自分は良いんですけど他の人にも Groovy の読み書きを強いる事になるので,そのへんはどうなんでしょうね.学習コストが上がるというか,些細なことでもお作法を覚えなきゃ駄目なのは面倒臭いのではと思ってしまう.で,結局 Groovy 読み書きできる人が永劫そのあたりを面倒見る,みたいな事になったら地獄っぽい.まあ普通に Java 読み書きできたら Groovy も読み書きできそうですけども.はい.


[追記]
別の処理系 (つまり今回の場合 Groovy) に依存すると,気を配る対象 (処理系の動向追ったりとか) が増えるためにコストが高まるという見方もあるので,そのコストを Groovy のメリットでうまく相殺できるのかどうか考えていく必要がある (Java も8とかはまあまあ書き心地が軽いのでそこが支配的なメリットになるかどうか.直接実行できるというのも,配布時にコンパイルしたパッケージを置くスタイルと比較した時にどうか.まあトライアルアンドエラーや修正は楽だけれど).
依存が少なければ少ないほどメンテコストは低くなる傾向があるので,依存はバチバチ減らしたい.結局、ソフトウェアのライフサイクルを考えるとメンテフェーズが一番長くなるはずなので,そこでコストがかかるようになるとリソースをどんどん奪われてしまう.総じたコストを低く保つにはなんやかんやで単一の言語でやっていった方が良いのではないかという立場です.
我々はどうすべきか.

CUDA で 2 枚以上の GPU を使って cufft する時は FFT Plan を各々の device に乗せる必要がある

以下は間違い.

cudaSetDevice(devices[0]);
cufftHandle fft_plan;
cufftPlan1d(fft_plan, SIZE, CUFFT_C2C, BATCH); // ここで作られる FFT Plan は device 0 にしか確保されない

cufftComplex *ffted_data[2], *orig_data[2];
cudaSetDevice(devices[0]);
cudaMalloc((void **)&orig_data[0], SIZE);
cudaMalloc((void **)&ffted_data[0], SIZE);
cudaSetDevice(devices[1]);
cudaMalloc((void **)&orig_data[1], SIZE);
cudaMalloc((void **)&ffted_data[1], SIZE);

cudaSetDevice(devices[0]);
cufftExecC2C(fft_plan, ffted_data[0], orig_data[0], CUFFT_FORWARD);
cudaSetDevice(devices[1]);
cufftExecC2C(fft_plan, ffted_data[1], orig_data[1], CUFFT_FORWARD); // ここ (device 1 上) で使っている fft_plan は device 0 にしか乗っていないのでマズい

この場合,fft_plan が device 0 にだけ乗っている為,device 1 で FFT を走らせようとすると変な結果が得られる.
エラーではなく変な結果が得られる!!!!
つらい!!!!!!!!!!!
原因がわかりにくい!!!!!!
あああああああああああああああああああああああああああああああああああああああああああああ!!!!!!


正しくは以下のように,FFT を実行する各々の device 上で FFT Plan を確保しなければならない.

/*
 * ここで各 device 上で FFT Plan を確保する
 */
cufftHandle fft_plan[2];
cudaSetDevice(devices[0]);
cufftPlan1d(fft_plan[0], SIZE, CUFFT_C2C, BATCH);
cudaSetDevice(devices[1]);
cufftPlan1d(fft_plan[1], SIZE, CUFFT_C2C, BATCH);

cufftComplex *ffted_data[2], *orig_data[2];
cudaSetDevice(devices[0]);
cudaMalloc((void **)&orig_data[0], SIZE);
cudaMalloc((void **)&ffted_data[0], SIZE);
cudaSetDevice(devices[1]);
cudaMalloc((void **)&orig_data[1], SIZE);
cudaMalloc((void **)&ffted_data[1], SIZE);

/*
 * 各 device に応じて使用する FFT Plan を差し替える
 */
cudaSetDevice(devices[0]);
cufftExecC2C(fft_plan[0], ffted_data[0], orig_data[0], CUFFT_FORWARD);
cudaSetDevice(devices[1]);
cufftExecC2C(fft_plan[1], ffted_data[1], orig_data[1], CUFFT_FORWARD);

こうするとちゃんと動く.ハマった……

あああああああああああああつらい!!!!!!!!!!!!!!! 勘弁してれ!!!!!!!!!!!!!

mvn test で findbugs と checkstyle を走らせて,1つでも violation があれば fail させるの術

OSSJava をやっていく場合,ロジックのテストだけではなく checkstylefindbugs などによる静的解析を適用して,それを CI で回していかないととてもではないがやっていけない!!! という感じになるので,そこら辺を何とかしたい.
具体的に言うと mvn test でこれらの静的解析をテストと一緒に走らせて,静的解析が1つでも violation を吐き出したら BUILD FAILURE にしたい (もちろんテストがコケても BUILD FAILURE になる).

ということで以下のように pom.xml を記述してやります.

<build>
  <plugins>
    ...
    <!-- findbugs の設定 -->
    <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>findbugs-maven-plugin</artifactId>
      <version>3.0.0</version>
      <executions>
        <execution>
          <phase>test</phase>
          <goals>
            <goal>check</goal>
          </goals>
        </execution>
      </executions>
      <configuration>
        <effort>Max</effort> <!-- ここらへんは好みに応じて -->
        <threshold>Low</threshold> <!-- ここらへんは好みに応じて -->
        <failOnError>true</failOnError> <!-- Error が出た時に build failure にする -->
        <!-- 以下ファイル出力系なのでお好みで -->
        <xmlOutput>true</xmlOutput>
        <outputEncoding>UTF-8</outputEncoding>
        <xmlOutputDirectory>target/site/findbugs</xmlOutputDirectory>
        <findbugsXmlOutputDirectory>target/site/findbugs</findbugsXmlOutputDirectory>
      </configuration>
    </plugin>

    <!-- checkstyle の設定 -->
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-checkstyle-plugin</artifactId>
      <version>2.13</version>
      <executions>
        <execution>
          <phase>test</phase>
          <goals>
            <goal>check</goal>
          </goals>
        </execution>
      </executions>
      <configuration>
        <!-- checkstyle のポリシーファイルの場所を指定した場合はここに書く.この場合はプロジェクトルートにcheckstyle.xml が置いてある -->
        <configLocation>checkstyle.xml</configLocation>
        <violationSeverity>warning</violationSeverity> <!-- warning よりレベルの高い警告を violation にする -->
        <!-- 以下お好みで -->
        <encoding>UTF-8</encoding>
        <consoleOutput>true</consoleOutput>
        <outputFile>${project.build.directory}/site/checkstyle/checkstyle-result.xml</outputFile>
      </configuration>
    </plugin>
  </plugins>
</build>

以上のように書いて,mvn test を実行すると test -> findbugs -> checkstyle という順で実行されて便利な感じです.
<executions> の中身と,checkstyle<violationSeverity> の中身でちょっとハマってアレでした.<violationSeverity> の中身はお好みに応じてという感じだと思いますけど,厳格にやっていくなら warning が妥当ではないかと思った次第.


こうしてやると Travis 等の CI で継続的に回してやることもできるので便利.

capture-output-stream というのを書いた

こちらも温泉で出したやつです.Maven Central にもアップしました.


http://search.maven.org/#artifactdetails|net.moznion|capture-output-stream|1.0.0|jar


標準出力や標準エラー出力をキャプチャする君です.キャプチャしつつ標準 (エラー) 出力にも併せて出すという tee-ing にも対応しています.テストとかに使うと結構便利.
PerlCapture::Tiny からインスパイアされています.


Java の場合,STD(OUT|ERR) のキャプチャはめちゃめちゃ簡単*1 なのでわざわざライブラリ化する必要性も薄そうだったんですが,
AutoCloseable が実装されていると try-with-resource でアレコレできて便利だよなーという意識だったので書いた次第.空前の AutoCloseable 期!



ご利用くださいませ.

*1:perlio をいじったりしなくて良い

javadocio-badges というのをつくった

先週の3連休で温泉シバソンというイベントを有馬温泉でやってきて,そこで書いたアプリケーションがまあまあ使えるレベルに達したので公開しました.


シバソンについての詳細は以下のブログを見ていただけると良いと思います *1.僕はこのハッカソンで MacBook Pro の電源アダプタを栓抜きとして使った結果破壊しました.

本題

さて,Maven Central にアップした package の javadoc を参照する時には javadoc.io というサービスを使うと便利です.
(参考: javadoc.io が便利 - blog.64p.org)

http://www.javadoc.io/


基本的に javadoc.io は Maven Central にアップされたすべての package の javadoc を良い感じに参照できて便利なのですが,あんま皆さん使っていない感じがするというかそもそも導線が張られていないというか,とにかくそんな雰囲気だったので,見た目にも楽しいみんな大好き badge 形式にしたら気軽に使えて捗るのでは! ということで作りました.


Heroku の無料プランでホスティングしてるのですぐ使うことが出来ます.
Markdown を例に取ると,以下のように書いてやることで

[![javadoc.io](https://javadocio-badges.herokuapp.com/net.moznion/mysql-diff/badge.svg)](https://javadocio-badges.herokuapp.com/net.moznion/mysql-diff)

こんな感じの badge が出ます.


javadoc.io


なんだかオシャレ!*2 ご利用下さいませ.
そうそう,Heroku は Maven Plugin が良く出来ていて,Java の Web Application のデプロイが楽にできて良かったです.

*1:見返したけどさっぱりわからん

*2:果たしてそうだろうか