Eagleの回路図にgitのコミットハッシュを埋め込む

Eagleを使って回路設計、基板設計などをしはじめています。
*.sch, *.brd, *.lbr を git レポジトリに追加して開発していると、
pdfにしたり誰かに渡すときに、いつのバージョンのファイルを渡そうとしているのか、
ファイルに記録したい場合があります。

そんな時に、gitのコミットハッシュを埋め込めるといいんじゃないかと思いました。
具体的には git rev-parse --short HEAD の結果。

Eagleには User Language Program という仕組みがあり、

The EAGLE User Language can be used to access the EAGLE data structures and to create a wide variety of output files.

C言語ライクな書式で、回路図内のオブジェクトをいじれたりします。

以下のようなファイルを git-revision.ulp というファイル名で
/Application/EAGLE-6.4.0/ulp/git-revision.ulp に保存します。

string cmd, s, version;
int count = 0;
string git_dir       = argv[ 1 ];
string stdout        = "debug.log";
string revision_file = "git-revision.log";

string GitRevision () {
    if ( version ) {
        return version;
    }

    string git_cmd = "git --git-dir=";
    git_cmd        += git_dir;
    git_cmd        += " rev-parse --short HEAD > ";
    git_cmd        += revision_file;

    int result = system( git_cmd );
    if ( result ) {
        dlgMessageBox( "git rev-parse failed" );
        exit( -1 );
    }
    fileread( version, revision_file );

    return version;
}

if ( ! git_dir ) {
    dlgMessageBox( "provide .git directory as an argument", "OK" );
    exit( -1 );
}

output( stdout, "wt" ) {
    if (schematic) {
        schematic(S) {
            S.parts( P) {
                if ( P.device && P.device.name && ! strstr(P.device.name, "GIT-REVISION") ) {
                    sprintf( s, "VALUE %s %s\n", P.name, GitRevision() );
                    cmd += s;
                    count ++;
                }
            }
        }
    }
}

if ( ! count ) {
    dlgMessageBox( "device named \"GIT-REVISION\" not found", "OK" );
    exit( -1 );
}
exit( cmd );

また、nameが GIT-REVISION であるような部品をつくり、frame の右下の方に置きます。
以下のライブラリに入れています。
git-revision.lbr

置くとこんなふうに見えるでしょう。
スクリーンショット 2013-04-22 19.55.48

ここで git-revision.ulp を実行します。
.gitへのパスを指定してください(今見ている回路図のファイルパスを取れる方法があればよかったんだけど、、多分できないんじゃないか)

RUN git-revision path/to/.git

結果はこんな。

スクリーンショット 2013-04-23 9.36.26

よいと思ったら scr ファイルを使うとキーボードショートカットを割り当てられるようなので
そこまでやってもいいかも

RedisのネストしたSETにSADDやSMEMBERSしやすくするluaスクリプトを書いた

Redis v2.6.0からluaスクリプトのロード実行ができるようになっていて、
luaの方に興味があって「いつか…」と思っていた。

ところで、RedisのSETをネストした構造のようなものを使う時の話。
user has many entries.
entry has many tags.
以下のような構造のとき、以下のようになってしまう。

# input:
# my $users = {
#     # user.id
#     1 => {
#         # entry.id
#         10 => [
#             # tag.id
#             100,
#             101
#         ],
#         11 => [
#             110
#         ],
#     },
#     2 => {
#         20 => [
#             200
#         ],
#     }
# };
#
# output (1) - get all tags for user[1]'s entry[10]
# [ 100, 101 ]
#
# output (2) - get all tags for user[1]'s all entries
# [ 100, 101, 110 ]
#
# output (3) - get all tags
# [ 100, 101, 110, 200 ]
#
# output (4) - get all entry ids
# [ 10, 11, 20 ]
 
subtest 'normal' => sub {
    $redis->flushdb;
 
    $redis->multi;
    $redis->sadd( "users"      => "1" );
    $redis->sadd( "users.1"    => "10" );
    $redis->sadd( "users.1.10" => "100" );
    $redis->sadd( "users.1.10" => "101" );
    $redis->sadd( "users.1"    => "11" );
    $redis->sadd( "users.1.11" => "110" );
    $redis->sadd( "users"      => "2" );
    $redis->sadd( "users.2"    => "20" );
    $redis->sadd( "users.2.20" => "200" );
    $redis->exec;
 
    is_deeply( [ $redis->smembers( 'users.1.10' ) ],
               [ 100, 101 ] );
 
    is_deeply( [ $redis->sunion(
                     map {
                         "users.1.$_"
                     } $redis->smembers( 'users.1' )
                 ) ],
               [ 100, 101, 110 ] );
 
    is_deeply( [ $redis->sunion(
                     map {
                         my $user_id   = $_->[ 0 ];
                         my $entry_ids = $_->[ 1 ];
                         map { "users.$user_id.$_" } @$entry_ids;
                     } map {
                         [ $_ => [ $redis->smembers("users.$_") ] ]
                     } $redis->smembers( 'users' )
                 ) ],
               [ 100, 101, 110, 200 ] );
 
    is_deeply( [ $redis->sunion(
                     map {
                         "users.$_"
                     } $redis->smembers( 'users' )
                 ) ],
               [ 10, 11, 20 ] );
};

ネストしたSET構造に直接SADDしたりネストした構造のある深さのSMEMBERSをとろうとするとめんどくさいので、
luaを使えばその辺うまくやれるカスタムコマンドをつくれるんじゃないかと思って書いてみた。

MULTIの中でもEVALSHAできるようだし、
もしかしたら使えるかもしれない。

luaを書いてみる理由ができてよかった。

App::Prove::Plugin::MySQLPool #perl

最初は、テスト用のmysqldを立ち上げっぱなしにしておいて、
それを使うテストを prove -lr t で走らせたものであった。

そのテストに10分以上かかるようになると、我慢がならなくなり、
Test::mysqldを使い、
prove -lr -j4 t で走らせるようになった。

それでも10分以上かかるようになると、また我慢がならなくなり、
App::Prove::Plugin::MySQLPool – github, cpan
というのを書き、
prove -lr -PMySQLPool=MyApp::Test::DB -j4 t
でテストを走らせるようになった。

App::Prove::Plugin::MySQLは、Test::mysqldを使ったテストが大量にある時に、
テストの最初に -j* 分のmysqldを起動し、
それぞれの *.t にはそのmysqld群の中から使っていないものを
割り当てるproveプラグインである。

Test::mysqldを使ったテストの最初では、CREATE TABLEをしまくったり、マスターデータをINSERTしまくったりするだろう。

App::Prove::Plugin::MySQLは、-j*分のmysqldを起動すると、それぞれに対して、
-PMySQLPool=MyApp::Test::DB として指定したモジュールの
prepare関数を呼ぶ。
(指定しない場合には何もしない。)

その中で、GitDDLを使って、

# MyApp::Test::DB
sub prepare {
    my ($package, $mysqld) = @_;
    my $gd = GitDDL->new( dsn => $mysqld->dsn, ... );
    $gd->deploy;
}

というようにしてテストの前準備をすればいい。

これが終わると、私のテストをやっと実行する。
$ENV{ PERL_TEST_MYSQLPOOL_DSN }にdsnがやってくるので
こんなふうにして使う。

my $dbh = DBI->connect( $ENV{ PERL_TEST_MYSQLPOOL_DSN } );
$dbh->do( "TRUNCATE $_" ) for @tables;

... # your test code

同じmysqldが使い回されてくるので、中身を毎度消してやる。

実装には試行錯誤したし、いまいちなところも多い気がする。

テストコードをなるべく変更せずに(%ENVの書き換えだけで)使えるようにするには、POSIX::AtForkを使ってfork後に子プロセス内で%ENVをセットした。
他にproveプラグインでうまくフックできるのだろうか?

1つの *.t ファイルのテストの前にmysqldをpoolから確保し、
テストが終了したら、そこで使ったmysqldは開放して次のテストに割り当てたい。
get_and_setをatomicにできるCache::FastMmapを使って、
確保時にはPOSIX::AtForkで子プロセス内から自分のpidをキャッシュにセットして、
開放時には終了したテストのpidをとれなかったので、死んだプロセスがあるかどうかをpsでまわして調べるなどしている

よくわからないだろうけれど、がんばったし、
テストはまた4分くらいで終わるようになったし、よく眠れそうだ。

nodejsのrequestでログをはく

nodejsを使っているみなさまは
http requestを簡単に発行するために https://github.com/mikeal/request を使っていると思いますが、

そのソースを読んでいると、ふと以下のような行が目にとまりました。

if (process.logging) {
  var log = process.logging('request')
}
... 中略
if (log) log('%method %href', self)

ところが
process.logging の痕跡はどこにもありません。

ということで、 log 関数に渡している引数を眺めて、以下のようなロガーをこさえてみました。

こんなログを吐きます。

// require('request').get( "http://google.com/" );
[request] GET http://google.com/
[request] Redirect to { protocol: 'http:',
  slashes: true,
  host: 'www.google.com',
  hostname: 'www.google.com',
  href: 'http://www.google.com/',
  pathname: '/',
  path: '/' }
[request] GET http://www.google.com/
[request] Redirect to { protocol: 'http:',
  slashes: true,
  host: 'www.google.co.jp',
  hostname: 'www.google.co.jp',
  href: 'http://www.google.co.jp/',
  pathname: '/',
  path: '/' }
[request] GET http://www.google.co.jp/

お手軽かも

zshのregionからpbcopy

zshでCtrl+A,F,B,Eでカーソル移動して
Ctrl+Spaceで範囲指定して
Ctrl+Wでクリップボードにコピーしたい

x-copy-region-as-kill () {
  zle copy-region-as-kill
  REGION_ACTIVE=0
  print -rn $CUTBUFFER | pbcopy
}
zle -N x-copy-region-as-kill
bindkey '^W' x-copy-region-as-kill

NinNin – casual background processing for perl

https://github.com/mash/NinNin というのをつくった。

よくGearman::Workerを使うんだけれど
gearman-starter.plのようなもので
gearmanのworker poolをつくっていて
裏(gearman worker)で動かしたいコードと、
httpリクエストを同期的に処理してるコードの場所が離れるから行ったり来たりしたりするのが嫌だったりする。

もっとカジュアルに裏にまわしたい!

ということで、subroutine referenceを渡すと裏に回してくれるのが NinNin (ニンニン)。

予めgearman worker poolを用意しておけば

NinNin->setup({
  backend => NinNin::Backend::Gearman->new({
    job_servers => [ '127.0.0.1:4730' ]
  })
});

って感じでbackendを指定しておき、
ちょっと時間かかるかもしれないから裏に回したいってコードがあったら

ninnin(
  sub {
    my (@args) = @_;
    # run in gearman worker
    # ...heavy work...
  },
  (@args) # argument for sub
);

のようにして裏に回す。

my $coderef = ninnin( sub { ... } );
$coderef->( @args );

インターフェースは↑の方がいいかも、とtypesterは言った。

実装は
B::Deparse でsubroutine referenceからソースコードに戻して、
ソースコードと引数をまとめてjobにして、

evalしてsubrefを取り出して引数を渡して実行するものを register_function しておく、という感じ。

evalするところでimportしてるのが見えなくなったり、行番号がおかしかったり、その辺大変そうだけど、いいんじゃない?

FaceDetection – Integral Image

昨日、Flashや画像や音声やらいろいろ強い人とお会いするきっかけがあり、
今まで話したことが無かったので
Marilena (OpenCV顔認識のas3実装)をつくった時に感動した、
Integral Imageというアルゴリズムについて話しました。

一文で説明すると、
二次元配列で表されるデータがある時に(この場合は顔検出する対象の画像の明るさ)
二次元配列の中の矩形範囲のデータの合計を、高速に求める手法です。

発表資料を置いておきますのでよろしければ
integral_image_opencv_face_detection.pdf

計算してみるためのスプレッドシート
Integral Image Calculator

こちらの方がわかりやすいかもしれません
integral imageについて調べた

資料の中に数式が入るとどや顔の度が増しますね なおやんは寝てましたけど

UINavigationController pushViewControllerしてpopViewControllerした時のUIViewControllerのメソッドの呼ばれ方

今さらながらmemo

RootViewControllerがapp.navigationControllerの先頭にある

2011-05-28 21:23:43.771 navcontrollertest[12548:207] RootViewController/viewDidLoad
2011-05-28 21:23:43.773 navcontrollertest[12548:207] RootViewController/viewWillAppear:
2011-05-28 21:23:43.775 navcontrollertest[12548:207] RootViewController/viewDidAppear:

そこにSecondViewControllerをpush

SecondViewController* c = [[SecondViewController alloc] initWithNibName: nil bundle: nil];
[ self.navigationController pushViewController: c animated: YES ];
[ c release ];

2011-05-28 21:23:47.191 navcontrollertest[12548:207] SecondViewController/viewDidLoad
2011-05-28 21:23:47.192 navcontrollertest[12548:207] RootViewController/viewWillDisappear:
2011-05-28 21:23:47.192 navcontrollertest[12548:207] SecondViewController/viewWillAppear:
2011-05-28 21:23:47.548 navcontrollertest[12548:207] RootViewController/viewDidDisappear:
2011-05-28 21:23:47.549 navcontrollertest[12548:207] SecondViewController/viewDidAppear:

backボタンを押した

2011-05-28 21:23:53.395 navcontrollertest[12548:207] SecondViewController/viewWillDisappear:
2011-05-28 21:23:53.396 navcontrollertest[12548:207] RootViewController/viewWillAppear:
2011-05-28 21:23:53.749 navcontrollertest[12548:207] SecondViewController/viewDidDisappear:
2011-05-28 21:23:53.750 navcontrollertest[12548:207] RootViewController/viewDidAppear:
2011-05-28 21:23:53.751 navcontrollertest[12548:207] SecondViewController/dealloc

viewDidUnloadは呼ばれないが、deallocはちゃんと呼ばれている。

how twitter @anywhere works

ということでOAuth2のImplicitGrant方式(または古いドラフトではUserAgent方式)ってのはどうなってるのか実例を見ようと、twitterの@anywhereのJSのソース(http://platform.twitter.com/anywhere.js)を読んでみた。

JSがminifyされてるので JsDecoder で読みやすくしたり
ChromeのDeveloper ToolsでどんなURLにアクセスしてるのか見てさらに掘り進んでいったり。

blog.twitter.comに@anywhereがはいってるのでそこで確認してみた。

  1. @Twitter にマウスオーバーするとオーバーレイが出て「フォローする」ってボタンがある
  2. それを押すとポップアップが開き、oauth2の、Clientを認証するか?って聞くダイアログが出るっぽいURL(https://oauth.twitter.com/2/authorize?oauth_callback_url=…略)だが、まずはTwitterにログインするためのTwitterID(またはメアド)とパスワードが聞かれるフォームが表示される、ただしsubmitボタンが「連携する」になってる
  3. 「連携する」を押すと、リダイレクトされ、#以降に何やら入っているURLがちらっと表示された後に、ポップアップが閉じる
  4. 何事もなかったかのようだが、もう一度 @Twitter にマウスオーバーすると、「フォローしている」と表示される

ここでおもむろにConsoleで
localStorage.twttr_anywhere
とうつと、なにやらtokenがあるようだ。
localStorage.twttr_anywhere_expiry
というのもあって、2時間の有効期限を表して自分で無効化したりするのかな

@Twitterをフォローするリクエストは、これを使って行なわれたようだ。iframe使ったクロスドメインかな
Chrome Developer ToolsのNetworkタブに履歴が残っていたのでそれを再現すると、こんな感じ。

OAuth2のaccess_tokenのような権力をもつtokenだがAuthorizationヘッダが必要な何かみたい。

ということで、JSのみでaccess_tokenとってきたらlocalStorageにいれておいてあって、
それをフォローしたりするリクエストで使っていることがわかりました。
localStorageは

User agents must raise a SECURITY_ERR exception whenever any of the members of a Storage object originally returned by the localStorage attribute are accessed by scripts whose effective script origin is not the same as the origin of the Document of the Window object on which the localStorage attribute was accessed.

http://dev.w3.org/html5/webstorage/#security-localStorage

だからaccess_tokenをAuthzサーバからClientにリダイレクトしてきたURLの#から誰よりも早く取り出して、
localStorageに保存して、
他のスクリプトからは取れなく(window.closeなど)すれば
安全だってことでいいのかな?

yokohama.pm #7行ってきた

今日来てた人たちのモジュールやコードを使わせていただいているなー、
っていろんな人の顔を見ながら思った!

発表資料
yokohama.pm slide ナカマップのなにか

最後の方のコードはいろいろおかしいので参考になさらないほうがよいでしょう。
でもSocket.IOはクライアント側すごく短くかけてドメイン超えれるし魅力的だなー
なんとかしたい

なんとかしようと思ったときに、
Authorization Code方式(またはImplicit Grant方式)でaccess_token取得した後に、
そのaccess_tokenをSocket.IOのJavaScriptクライアントに渡せるとよいが、どういう経路で安全に渡すことができるんだろう。

Twitterの@anywhereのドキュメントには、
[code]The higher the anywhere.js file is on the page, the sooner it can process the access token.
[/code]
ってある。

OAuth2のImplicit Grant方式では
Authorization Serverからリダイレクトされてきた時にaccess_tokenが#フラグメント以降に入ってるんだけど
それを他のJavaScriptコードとかから読み取られる前(最初のscriptタグ)にanywhere.jsがあれば
安全ってことなのかな?

上の方にanywhere.js置いてね、って書いてあるけど
スクリプト設置した人が下の方においたら、htmlの上から設置場所までの間にxssでなんか仕込めたらTwitterのaccess_tokenとられちゃうんだよね?

access_tokenの有効期限が短いってことだけどそれでいいのかな?

で@anywhere使ってTwitter認証してリダイレクトされてきたらTwitterにログイン状態で
@anywhereの貼ってあるページ上で誰かをフォローできる、ってことは
access_tokenなのか同様の力を持つものがブラウザにCookieなりlocalStorageなりで保存されてるってこと?
CSRF対策用のトークンみたいなワンタイムな感じなのかな?

わからないことが多すぎる><
anywhere.js を読んでみよう