類似しているGitHub Issue発見ツール Refissue を作りました

GitHubのIssueは便利ですが、複数人で利用しているとどうしても似たようなIssueが登録されてしまうことがあります。 そこで、類似しているIssueを自動的に検出してくれるRefissueというツールを作りました。

https://github.com/addsict/refissue

このツールを動かしておくと、Issueが登録された時に過去のIssueの中から似たようなIssueを探しだし、下の写真のようにコメントとして残してくれます。

img

本当に同一の内容の場合、登録したIssueをcloseするなり、まとめるなりしてIssueの重複を防げますね。

肝心の類似判定ですが、今はIssueのタイトルと本文を形態素解析したものの中からキーワードとなる形態素のみ抽出し、コサイン類似度法でIssue間の類似度を求めています。

類似判定の精度がまだまだイマイチな所はありますが、是非使ってみてください。

git-add, git-commitを使わずにコミットする方法

cf.) Git Internals - Git Objects

  1. blobオブジェクトを作る
  2. treeオブジェクトを作る
  3. commitオブジェクトを作る

blobオブジェクトを作る

$ echo 'hello world' > test
$ git hash-object -w test
# 3b18e512dba79e4c8300dd08aeb37f8e728b8dad

treeオブジェクトを作る

$ printf "100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad\ttest" | git mktree
# 5b873f747ccb268e4491f289eb37fc675ff5825b

もしくは

$ git write-tree
# 5b873f747ccb268e4491f289eb37fc675ff5825b

commitオブジェクトを作る

$ echo "first commit" | git commit-tree 5b873f747ccb268e4491f289eb37fc675ff5825b
# 6684f9fdfbdd60db2ba2851c97aa08aa76ad9487
$ git log 6684f9fdfbdd60db2ba2851c97aa08aa76ad9487

無限スクロール出来るiOS用のカレンダーUIを作りました

HIScrollCalendarという無限スクロールが出来るiOS用のカレンダーUIを作りました。

f:id:furuyamayuuki:20131028192935p:plain

もともとは個人的に作っていたアプリに使っていたものですが、そのアプリは日の目を見ずに終わってしまったのでカレンダーの部分をOSSとして公開することにしました。

インストール

CocoaPodsを使っている方はPodfileに指定して下さい。

pod 'HIScrollCalendar', :git => 'https://github.com/addsict/HIScrollCalendar.git'

アプリへの組み込み方

ヘッダ "HIScrollCalendarView.h" を読み込み、HIScrollCalendarViewオブジェクトを作るだけで使えます。 ユーザがタップしたカレンダーの日付は - scrollCalendarView:dateDidChange: というデリゲートメソッドで取得可能です。

#import "HIScrollCalendarView.h"

@interface ViewController : UIViewController <HIScrollCalendarViewDelegate> {
}
@end

@implementation ViewController
- (void)viewDidLoad
{
    [super viewDidLoad];

    HIScrollCalendarView *calendarView = [[HIScrollCalendarView alloc] init];
    calendarView.delegate = self;
    [self.view addSubview:calendarView];
}

- (void)scrollCalendarView:(HIScrollCalendarView *)scrollCalendarView dateDidChange:(NSDateComponents *)dateComponent
{
    NSString *date = [NSString stringWithFormat:@"%d/%d/%d", dateComponent.year, dateComponent.month, dateComponent.day];
    NSLog(@"%@", date); // 2013/10/28
}
@end

さいごに

カレンダーUIで使用している各種フォントや配色は全くconfigurableな作りになっていないので、その辺今後直していけたらなと思ってます。このカレンダーUI自体を取り込まなくても、無限スクロール実装の参考にでもしてもらえれば嬉しいです。

機能要望・バグ報告はこちらまで!
https://github.com/addsict/HIScrollCalendar

Google BigQueryのPythonライブラリbqlibを作りました

Google BigQueryをPythonから扱うbqlibというモジュールを作りました。
BigQueryとは簡単に説明すると、テラバイト級のデータセットに対してSQLを使って様々なメトリクスを分析できるサービスです。
競合にはAmazonのRedshiftやTreasureDataなどがあります。

BigQueryのPythonクライアントはGoogle社が提供しているbigquery_client.pyが既にありますが、 プリミティブな操作の集合のようなライブラリとなっており実際に使おうとすると手順が多いので、今回そのモジュールのラッパーライブラリとして簡単に扱えるものを作りました。

インストール

pipやeasy_installで入ります。依存しているbigquery_client.pyなども一緒に入ります。

$ pip install bqlib

使い方

実際にbigquery_client.pyと比較しながら使い方を説明します。

同期型クエリ

最初に同期型クエリを見てみます。
同期型クエリはクエリを開始してから実行完了までブロックされます。

(bigquery_client.pyの場合)

client = BigqueryClient(api='bigquery',
                        api_version='2.0',
                        project_id='my_project',
                        credentials=credentials)
job = client.RunQuery(query='SELECT date, profit FROM sales') # クエリ開始->クエリ実行完了までブロック
fields, rows = client.ReadSchemaAndRows(job['configuration']['query']['destinationTable']) # 結果の取得
print rows # [['2013-10-25','12300'], ['2013-10-26','9340'], ...]

最終的にrowsがクエリの結果になります。

(bqlibの場合)

bqjob = BQJob(authorized_http,
              'my_project', 
              query='SELECT date, profit FROM sales')
job_result = bqjob.run_sync() # クエリ開始->結果の取得
print job_result # [{u'date': '2013-10-25', u'profit': 12300}, {u'date': '2013-10-26', u'profit': 9340}, ...]

bqlibを使うと記述が簡単になるだけでなく、結果セットのスキーマのフィールド型から自動的にPythonに対応する型に変換してクエリの結果を返してくれるのでプログラムから扱いやすくなります。(例:'profit'フィールドはINTEGER型なので数値に変換される)

非同期型クエリ

非同期型クエリはクエリを開始した直後に制御が呼び出しプログラムに戻り、任意のタイミングで結果を取りにいくパターンです。

(bigquery_client.pyの場合)

client = BigqueryClient(api='bigquery',
                        api_version='2.0',
                        project_id='my_project',
                        credentials=credentials)
job_id = client.Query('SELECT date, profit FROM sales') # 非同期クエリ実行。すぐに制御が戻る

#### do something ####

job_reference = client.GetJobReference(job_id)
job = client.WaitJob(job_reference=job_reference) # クエリ完了待ち
fields, rows = client.ReadSchemaAndRows(job['configuration']['query']['destinationTable']) # 結果の取得
print rows # [['2013-10-25','12300'], ['2013-10-26','9340'], ...]

んー、これは結構めんどくさいですね...。

bqlibで書くと非同期型もすっきり書けます。

(bqlibの場合)

bqjob = BQJob(authorized_http,
              'my_project', 
              query='SELECT date, profit FROM sales')
bqjob.run_async() # 非同期クエリ実行。すぐに制御が戻る

#### do something ####

job_result = bqjob.get_result() # 結果の取得
print job_result # [{u'date': '2013-10-25', u'profit': 12300}, {u'date': '2013-10-26', u'profit': 9340}, ...]

基本、run_syncでクエリを実行していた部分がrun_asyncに変わるだけです。

複数クエリの並列実行

ここからはbqlib独自の機能になります。
bigquery_client.pyを使って複数クエリを連続して実行しようとすると、上記の非同期型クエリをクエリ数分だけ書き、それぞれ実行し、1つ1つ実行結果を得る必要があります。
bqlibのBQJobGroupを使えば複数クエリをまとめて並列に実行可能です。

bqjob1 = BQJob(authorized_http,
               'my_project', 
               query='SELECT date, profit FROM sales')
bqjob2 = BQJob(authorized_http,
               'my_project', 
               query='SELECT age FROM customer')

# 実行したいjobをグループとしてまとめる
job_group = BQJobGroup([bqjob1, bqjob2])

# 同期型クエリ
results = job_group.run_sync()

# もしくは非同期に
job_group.run_async()
results = job_group.get_results()

print results # [[{u'date': '2013-10-25', u'profit': 12300}], [{u'age': 23}]]

自動リトライ機能

bqlibが提供するクエリ関数は全てエラーが起きた時に自動でリトライするようになっています。
ただし現時点ではBigQuery側のサーバサイドのエラー以外でも(但しデータセットやテーブルが存在しないエラーを除く)勝手にリトライしてしまうのでこの辺は改善の余地があります。

Discovery Documentの自動キャッシュ

BigQueryのAPIを叩くためにはGoogleAPI Discovery Serviceを使用してBigQueryのAPI仕様が記述されたDiscovery Documentをダウンロードしてくる必要があります(但しbigquery_client.py v2.0.17からは何も指定しなければモジュールにビルトインされているものが使われるようになりました)。 このダウンロードされたDiscovery Documentは、ユーザがbqlibをGoogle App Engineで使用している場合memcachedに自動でキャッシュされるようになっています。

さいごに

以上bigquery_client.pyと比較しつつざっとbqlibの使い方をまとめてみました。
結局のところラッパーライブラリなので元のクライアントライブラリの変更をもろに受けてしまうのが辛いとこですが、まだまだ基本機能しかないので独自機能を入れて今後も拡張していきたいと思ってます。

要望・バグ報告はこちらまで!
https://github.com/addsict/bqlib

Mac OS Xのsayコマンドを使った簡易英語リスニング練習法

自分はいつまでたってもリスニングが苦手です。
特に数字の場合「fourty seven thousand six handred eighty nine」と発音されても
「47689」という数字がすぐには頭に思い浮かびません。

そこでMac OS Xのターミナルから使えるsayコマンドを使って数字の練習を出来るようにしました。

このようなスクリプトを組むと、1秒置きにランダムな数字(0〜32767)をMacが発音してくれます。

Practice for number in English

スピードやスピーカー(say -vで選べます)を調節することで色々な練習法が出来そうです。

BigDataダッシュボード勉強会

SIOSテクノロジーさんとTreasure Dataさん主催で、
ビッグデータをいかに可視化するか」をテーマにした勉強会が開催されたので行ってきました。

以下気になった点をメモとして残しておきます。 間違って解釈している箇所がありましたらご指摘下さい。

Treasure Dataと連携するダッシュボードツール

  • Treasure DataとMetric Insightsを組み合わせたダッシュボードの事例
  • Treasure DataさんはBIツールとしてExcelを使えるよう開発中とのこと
  • Q&A
    • 「Treasure Dataを導入している企業で最も良く組み合わせて使われるBIツールはあるか?」
    • 「最も使われている、というものはない。企業によって組み合わせて使われているBIツールは様々。インタラクティブな操作性ではTableauの右に出るものはないと感じているし、普及面の観点からだとExcelがやはり一番使われているBIツール。」

f:id:furuyamayuuki:20130822184735j:plain

f:id:furuyamayuuki:20130822185247j:plain

スモールデータ回帰分析ダッシュボード "adelie"

  • adelie
    • (重)回帰分析による多変量間の相関関係の計算を行い、可視化するツール
    • 分析するコンサルタントと現場の隔たりが大きい現状を踏まえて、現場の人間が分析できるようにと考えられ作られた
  • インラインで解析するが、気にいったモデル(メトリクス)があったら分析モデルとして保存して以後参照できる
  • 技術的な面
    • Python
      • numpy/scipy
    • Nginx
    • uWSGI
    • Pyramid
    • c3.js
      • D3.jsをラップした独自ライブラリ。対話的なチャートの制御・情報の取得が可能

f:id:furuyamayuuki:20130822191001j:plain

f:id:furuyamayuuki:20130822191040j:plain

Tableau Software

  • Tableau Desktopのデモ
    • 数百万件のデータをインポートしても、とてもスムーズに操作できていた
    • 操作方法を理解したら何でもできちゃいそうな印象
    • OpenGL使って描画しているため、データセットが大きくても描画はめちゃくちゃ速い

f:id:furuyamayuuki:20130822195505j:plain

OSSを活用したダッシュボードの紹介

  • Treasure Dataに蓄積しているデータを時間軸でグラフ表示するためのアプリケーションをrailsで開発
    • githubに公開しているという話だったけどURLがわからない...
  • Treasure Dataには、定期的に集計して結果をプッシュしてくれる機能があるらしく、TDのクレデンシャル情報をアプリ側で管理しなくて済んでいる
    • この定期的に集計してプッシュしてくれる機能はBigQueryにも欲しい・・・
  • GrowthForecastKibanaを使用してダッシュボード的なものを作る話もあったり

f:id:furuyamayuuki:20130822200454j:plain

Happy Hacking KeyboardをBluetooth化する(無改造版)

前回Happy Hacking Keyboard(HHKB)のコントローラから自作してBluetoothキーボードに改造しました。
今回はHHKBには一切手を入れずに、HHKBをBluetooth化してみたいと思います。

f:id:furuyamayuuki:20130817185550j:plain

※当方電子工作は初心者なため、以下の内容の正しさは保証出来ません。
また、改造に伴う機器の故障等も自己責任でお願いします。

必要なもの

ArduinoをUSBキーボードのホストにする

Bluetooth化の大まかな流れとしては、HHKBのUSBケーブルをArduinoに接続し、HHKBから送られてくる信号をArduinoBluetoothに変換してPCに送ります。 Arduinoが一旦PC代わりとなり、本来ならPCが受け取る信号をArduinoを通して送るイメージです。 USBデバイスを操作する側をホストと呼びますが、つまりArduinoがUSBキーボードのホストになればいいわけです。

ArduinoのUSBホスト化はUSBホストシールドとそれに対応したライブラリ USB Host Shield 2.0を使います。 このライブラリにはUSBのHIDデバイスに対応したクラスが用意されており(hidboot.(cpp|h))、その中のKeyboardReportParserクラスをサブクラス化して使います。

HHKB側からUSB経由でHIDレポートが送られてくるとKeyboardReportParser::Parseメソッドが呼び出されます。そのParseメソッドをオーバーライドすれば、送られてきたHIDレポートを自由に扱えます。 今回はそのHIDレポートをBluetoothモジュールに素通りさせればokです。
HIDレポートについては前回のものを参考にしてくだい。

class HIDKeyboardParser : public KeyboardReportParser
{
    virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf);
};

void HIDKeyboardParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) {
    // bufにはHHKBから送られてきたHIDレポートが入っているので、
    // そのレポートをそのままBluetoothモジュールに対してシリアルで送信
    sendKeyCodesBySerial(buf[0], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
}

void sendKeyCodesBySerial(uint8_t modifiers,
                          uint8_t keycode0,
                          uint8_t keycode1,
                          uint8_t keycode2,
                          uint8_t keycode3,
                          uint8_t keycode4,
                          uint8_t keycode5)
{
    Serial.write(0xFD); // Raw Report Mode
    Serial.write(0x09); // Length
    Serial.write(0x01); // Descriptor 0x01=Keyboard

    /* send key codes(8 bytes all) */
    Serial.write(modifiers); // modifier keys
    Serial.write(0x00, 1);   // reserved
    Serial.write(keycode0);  // keycode0
    Serial.write(keycode1);  // keycode1
    Serial.write(keycode2);  // keycode2
    Serial.write(keycode3);  // keycode3
    Serial.write(keycode4);  // keycode4
    Serial.write(keycode5);  // keycode5
    delay(5);
}

全体のスケッチはaddsict/USBKeyboard2BTにあります。 このスケッチをArduinoに転送し、ArduinoBluetoothモジュールをシリアルで接続するだけでBluetooth化の完了です。

f:id:furuyamayuuki:20130817185745j:plain

これでHHKBに限らずUSBキーボード(HID)ならどんなものでも一瞬でBluetoothキーボードにすることが出来ます。 あとはPICやAVRマイコンなどを使用して小型化すれば実用的になりそうです。

*1:秋月で売っているRN-42-EKも同じRN-42が載っているので代わりに使えるかもしれません。HIDプロファイルも設定により切り替えれるみたいですので。