maaash.jp

what I create

ダイアログインザダークに行ってきた

image

Dialog In The Dark というイベントに参加した。

真っ暗闇の中に7人で入り、1時間半くらい過ごす。 ほんとに真っ暗だから、目が “慣れる” ということがなく、いつまでたってもずっと何も見えない。

中では最初は音を頼りにボールを転がして受け取ったり、 コミュニケーションをうまくとらないとこなせないグループワークをこなす。

想像に難くないように、チームワークは育まれる。

暗闇の中では、見た目とか上司/部下のような関係性よりも先に、 助け合わないと歩くこともできないから、
“宇宙/海を前にすればこんなちっぽけなことだったんだ” 的な意味で育まれる。

でもそれ以上に、暗闇の中で感じた感覚は、初体験だっただけに衝撃的だった。

せんべいの袋をぎざぎざのところから破いた時に、暗闇の中で手先が光ったように見えたこと。 あれは本当に小さく発光したのか、 それともあまりにも当たり前にせんべいの袋を開けられたから何か脳内で発火したのか。

明るい部屋に出てくる時に世界が構築されていくようにぐらぐらとする感覚。

知識の範囲内からしかアイディアは出ないと思っていて未体験ゾーンは常に攻めたいと思っている人、 UIについて考えている人 にはおすすめ。

目で見えなくてもできること、目で見えないとできないこと、 っていうのは目が見える時には区別できないんだけど、 UIつくるときには意識すると違うんじゃないかなあと思ったり。

arduino development using ino

https://github.com/amperka/ino を使うとArduinoのプログラムのビルドがはかどる。

詳しくは ino使うとCUIでArduinoをビルドできて便利

Arduinoのスケッチ(.inoファイル)にinoがかけるプリプロセスが、 Arduino IDEが行うプリプロセスと異なっているために、

複数ファイルあるプロジェクトが正常にビルドできなかったりして pullreqしつつ自分のforkを使っていたのだが

週末本家のアップデートがあり、 自分のプロジェクトのビルドも正常にとおるようになったのでお知らせ。

便利。

Resize EAGLE windows using Slate

Macな方は EAGLE で回路/基板設計を行う時、

open arduino-leonardo/Arduino_Leonardo-REV3b.sch

などとTerminalから打ち込んでEAGLEを起動することと思う。 この時、画面はこんなふうになると思う。

before

これではだめだ。

同時にボードの方も見たいと思ったら小さなGenerate/switch to boardボタンを押さないといけないし、ウィンドウの端を何度もドラッグしていい感じになるまで左右の回路図と基板図をリサイズすることになる。

期待する見た目はこう。

after

なんで今まで小さなGenerate/switch to boardボタンを押したり、ウィンドウの端をドラッグするなんてことができてたんだろう。

今日、MacOSXで動き、JavaScriptでウィンドウのサイズ変更ができる Slate を導入して、Terminalでお好みの*.schファイルを開いた後、 Ctrl+Cmd+E 一発で後者のスクリーンショットの状態にもっていけるようになった。

Slateは↑のリンクより*.dmgファイルをダウンロードしてさくっと導入できる。

$HOME/.slate.js に以下のような内容のファイルを置く。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
function findAppNamed(string) {
    var found = null;
    S.eachApp( function(app) {
        if (app.name() === string) {
            found = app;
        }
    });
    return found;
}

S.bind("e:ctrl,cmd", function(win) {
    var eagleApp = findAppNamed("EAGLE");
    if ( eagleApp ) {
        var schematicWindow, boardWindow;
        eagleApp.eachWindow(
            function(window) {
                if (window.title().match(/Schematic/)) {
                    schematicWindow = window;
                }
                else if (window.title().match(/Board/)) {
                    boardWindow = window;
                }
            }
        );
        if (schematicWindow && boardWindow) {
            schematicWindow.doOperation(
                S.operation("move", {
                    "x"      : "screenOriginX",
                    "y"      : "screenOriginY",
                    "width"  : 908,
                    "height" : 878,
                })
            );
            schematicWindow.focus();
            boardWindow.doOperation(
                S.operation("move", {
                    "x"      : "screenOriginX+583",
                    "y"      : "screenOriginY",
                    "width"  : 855,
                    "height" : 878,
                })
            );
            boardWindow.focus();
        }
    }
});

微妙に回路図と基板図が中央付近でかぶっているのはお好みで調整してください。 また、Retinaでない人は高さなども調整してください。

Yamaguchi Mini Maker Faire 2013

YMMF2013、行ってきました。 事務局の方、おつかれさまでした。

アイディアは知識の範囲内でしか出ない、というのは真だと思う。 Maker Faireで出会うモノはいつでも自分の知識空間を超えていて、 また新しいアイディアがたくさん湧いてくるような錯覚のような、本物であってほしい感覚が得られて気持ちいい。

IRKit というモノについて話した資料を置いておきます。

MiniとはいえMaker Faireにしてはあまりにも前半の概念部分が長かったか。

でも話す機会が欲しかったのだろう。

ソフトウェアエンジニアとして、自分の書いたソフトウェアが意図通りに動く時、それがある機能として誰かの役に立ったり楽しませたりする時の喜び。

電子回路を設計して基板ができあがり、形をもったデバイスの中におさまって自分の意図通りに動いた時の喜びは、それを軽く超越して神になったような気分だった。

なんだってつくれるじゃないか!

octopress-ing

http://octopress.org/ に移行。

はまりどころがあったとすれば、 jekyll,octopressでは各記事のmarkdownファイルの先頭に yml 形式で記事の属性を設定するが、

wordpressから記事を移行した際には

1
comments: true

というコメントを許可する設定が抜けていたために Disqusが有効にならなかったことくらい。

Octopress/Disqus Issue Resolved にあるように

1
2
3
4
for I in *.markdown; do sed -i '' -e ':a' -e 'N' -e '$!ba' -e 's/\n---\n/\
comments: true\
---\
/' "$I"; done

とsedでcomments: trueを埋めてやった。


記事を書く時のメモ

1
2
3
4
5
rake new_post\[octopress-ing\] # 新しい記事のファイル名
rake isolate\[octopress-ing\] && rake generate && rake preview
open http://localhost:4000
# edit, edit, ..
rake integrate && rake generate && rake deploy

Redisを使ったレコメンド機能の実装

それRedisでできるよ、期でしょうか。 最近Redisでレコメンド機能をつくってみたのでご紹介です。

ここで”レコメンド機能”というのは、 Amazonでいう”この商品を見たお客様はこれも見ています”や、ブログの関連記事を出す機能のこと。

user:1がproduct:Aをみたときに、product:Aに似ているproduct:Bをレコメンドしたい。 product:Aとproduct:Bがどれくらい似ているか:類似度 を算出した後は、 Redis得意のSorted Setを使って類似度のランキングをつくれば 似ているproductを出すことができます。

類似度の算出にはいろいろ方法があるようですが、 Redisのデータ構造と相性のよい Jaccard [wikipedia]という方法を使いました。

この例に適用すれば、 product:Aを見たユーザー群(RedisのSet)と、product:Bを見たユーザー群があった時に、 類似度 = (product:Aとproduct:Bを両方見た人数) / (product:Aまたはproduct:Bのいずれかを見た人数) となります。

productページを見た時に、ユーザーIDをproductのSetに追加しておけば、

1
SADD product:A user:1

類似度は

1
similarity = count(SINTER product:A product:B) / count(SUNION product:A product:B)

となります。

これをSorted Setに入れておきます。 AとBが似ているならばBとAも似ているので逆方向も。

1
2
ZADD similarity:product:A similarity product:B
ZADD similarity:product:B similarity product:A
1
similarity:product:A

には、product:Aに似たproductのIDが入っているので 似ている順に10件とるのはお得意の

1
ZREVRANGE similarity:product:A 0 9

さらに、ただいまなんでもluaスクリプト期でもあるので、Redisのluaスクリプティングを使いたくなる理由を考えます。

SINTERとSUNIONは、Set同士のそれぞれANDとORをとって、その結果得られるSetの要素を返してくれますが、 ここで欲しいのは要素ではなく、要素数。 残念ながら、SINTER,SUNIONした結果の要素数だけとる方法はありません。 しかも要素数は単純に割り算した後すぐにSorted SetにZADDします。 これはアプリケーション側でやらずにRedis側でやった方が速そうです。

下につけたluaスクリプトを書けばこう書けます。

1
EVALSHA {sha1} 0 similarity:product:A product:A product:B product:B

product:A Setとproduct:B Setの類似度を計算し similarity:product:A Sorted Setにその類似度をスコアとしてproduct:Bを追加します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
-- sjaccardstore( 'j:sim:u:1', 'sim:u:1', 'sim:u:2', 'u:2' )
local function sjaccardstore( destination1, set1, set2, member1 )
    local sinter_count = 0
    local sunion_count = 0
    do
        -- minimize scope for tables
        local sinter = redis.call( 'sinter', set1, set2 )
        sinter_count = #sinter
    end
    do
        local sunion = redis.call( 'sunion', set1, set2 )
        sunion_count = #sunion
    end

    local jaccard = 0
    if sunion_count ~= 0 then
        jaccard = sinter_count / sunion_count
    end

    if jaccard ~= 0 then
        redis.call( 'zadd', destination1, jaccard, member1 )
    else
        redis.call( 'zrem', destination1, member1 )
    end

    -- lua number converts to redis integers
    -- we want float, so return string
    return jaccard
end
return tostring( sjaccardstore( ARGV[1], ARGV[2], ARGV[3], ARGV[4] ) )

-- sjaccardstorebothways( 'j:sim:u:1', 'j:sim:u:2', 'sim:u:1', 'sim:u:2', 'u:2', 'u:1' )
local function sjaccardstorebothways( destination1, destination2, set1, set2, member1, member2 )
    local jaccard = sjaccardstore( destination1, set1, set2, member1 )
    if jaccard ~= 0 then
        redis.call( 'zadd', destination2, jaccard, member2 )
    else
        redis.call( 'zrem', destination2, member2 )
    end

    return jaccard
end
return tostring( sjaccardstorebothways( ARGV[1], ARGV[2], ARGV[3], ARGV[4], ARGV[5], ARGV[6] ) )

RedisのCPUがあまってるならluaスクリプティングもいいんじゃないでしょうか。 wallclock timeで10倍くらい高速ですし。

1
2
3
    s/iter jaccard  sunion  sinter     lua
jaccard   3.85      --    -35%    -69%    -91%
lua      0.334   1051%    645%    255%      --

ベンチマークスクリプトはこちら

profiling node.js

# build d8
cd ~/.nave/src/0.8.18/deps/v8
scons prof=on d8

# d8, linux-tick-processor にパスを通す
export PATH=~/.nave/src/0.8.18/deps/v8:~/.nave/src/0.8.18/deps/v8/tools:$PATH

# プロファイリングを取りたいところを限定するモジュール
# https://github.com/bnoordhuis/node-profiler
npm install profiler

# プロファイリング対象をいろいろオプション付きで実行
node –prof –prof_lazy –log –log_snapshot_positions 3.js

# すると v8.log ができる
# それを linux-tick-processor がレポートにしてくれる
linux-tick-processor > 3.js.log

# 元のコードはこんな
cat 3.js

1
2
3
4
5
6
7
8
9
10
11
12
var len = 10000
,   i = 0
, profiler = require('profiler')
;

profiler.resume();

while (++i <= len) {
    Date.now();
}

profiler.pause();

# プロファイリング結果はこんな
cat 3.js.log

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Statistical profiling result from v8.log, (12 ticks, 12 unaccounted, 0 excluded).

 [Unknown]:
   ticks  total  nonlib   name
     12  100.0%

 [Shared libraries]:
   ticks  total  nonlib   name

 [JavaScript]:
   ticks  total  nonlib   name
     11   91.7%   91.7%  LazyCompile: *now native date.js:314
      1    8.3%    8.3%  LazyCompile: ~now native date.js:314

 [C++]:
   ticks  total  nonlib   name

 [GC]:
   ticks  total  nonlib   name
      0    0.0%

 [Bottom up (heavy) profile]:
  Note: percentage shows a share of a particular caller in the total
  amount of its parent calls.
  Callers occupying less than 2.0% are not shown.

   ticks parent  name
     11   91.7%  LazyCompile: *now native date.js:314
     11  100.0%    Script: ~/home/*snip*/3.js
     11  100.0%      LazyCompile: ~Module._compile module.js:372
     11  100.0%        LazyCompile: ~Module._extensions..js module.js:465
     11  100.0%          LazyCompile: ~Module.load module.js:346
     11  100.0%            LazyCompile: Module._load module.js:275

      1    8.3%  LazyCompile: ~now native date.js:314
      1  100.0%    Script: ~/home/*snip*/3.js
      1  100.0%      LazyCompile: ~Module._compile module.js:372
      1  100.0%        LazyCompile: ~Module._extensions..js module.js:465
      1  100.0%          LazyCompile: ~Module.load module.js:346
      1  100.0%            LazyCompile: Module._load module.js:275

see: https://code.google.com/p/v8/wiki/V8Profiler

-–追記
以下も便利

https://github.com/c4milo/node-webkit-agent

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 に保存します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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へのパスを指定してください(今見ている回路図のファイルパスを取れる方法があればよかったんだけど、、多分できないんじゃないか)

1
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を使い、

1
prove -lr -j4 t

で走らせるようになった。

それでも10分以上かかるようになると、また我慢がならなくなり、
App::Prove::Plugin::MySQLPool – github, cpan
というのを書き、

1
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を起動すると、それぞれに対して、

1
-PMySQLPool=MyApp::Test::DB

として指定したモジュールの

1
prepare

関数を呼ぶ。
(指定しない場合には何もしない。)

その中で、GitDDLを使って、

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

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

これが終わると、私のテストをやっと実行する。

1
$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分くらいで終わるようになったし、よく眠れそうだ。