iPadで選択した文字列を翻訳するブックマークレットを作りました
昨日はSmiley Hackathon#10 : ATNDに行ってきました。
HackathonではFacebookアプリをつくっていたのですがそれはおいておいて、iPadで選択した文字列を翻訳できるブックマークレットを作ったのでそちらを紹介したいと思います。
作ったきっかけ
iPadでゴロゴロしながら英語のサイトを見たりしたいなーと思ってたのですが、
いざ読んでみると単語を調べる時にアプリを切り替えないといけないので、読むのがつらくなってきました。
iPadのSafariでは拡張機能がまだないそうなので、ブックマークレットを作ってみることにしました。
作り方
ブックマークレットの作成はHatena::Letを使い、
翻訳APIはMicrosoft Translatorを使いました。
(Google Translate APIはもうすぐDuplicateになるようです)
コード
/* * @title translate selected text * @description translate selected text * @include http://* * @license MIT License * @require jQuery * @private */ var appId = 'Bing APIのAppID'; var getText = function() { var range = window.getSelection().getRangeAt(0); if (range.toString()) { var str = range.toString(); $.ajax({ type: "GET", url: "http://api.microsofttranslator.com/V2/Ajax.svc/Translate", dataType: "jsonp", data: { appId: appId, text: str, from: "en", to: "ja" }, jsonp: "oncomplete", success: function (data, dataType) { var fragment = document.createDocumentFragment(); var span = fragment.appendChild(document.createElement('span')); span.style.cssText = "background-color:#FFCACA"; span.appendChild(document.createTextNode(range.toString() + "[" + data + "]")); range.deleteContents(); range.insertNode(fragment); } }); } } document.addEventListener( 'mouseup', getText, false ); document.addEventListener( 'touchend', getText, false );
第三回 ライブドア・テクニカルセミナーに行ってきた
livedoor Techブログ : 第三回 ライブドア・テクニカルセミナーのお知らせに行ってきました。
内容が濃くてメモしきれないところもあったのですが載せておきます。
「クラウド時代のWebストレージ/データベース戦略」
- ライブドアが求めるストレージは?
- 実装
- CAP定理
- Consistency(一貫性), Availability(可用性), Partition Tolerance(ネットワーク分断の耐性)の3つのうちどれか一つを捨てなければいけないというのがある
- 今回は、一貫性を捨てている。物理的には一貫性が崩れている瞬間があるけれどもそこを捨てている
- テーブル構成
- mod_stf_storage.c
- GET/PUT/DELETEメソッドを受け付けてファイルの読み書き
- GETはdefault-handlerまかせ
- PUTはRecursiveにディレクトリを作成
- 同一ファイル名での上書きはできない
- 更新は一回消して内部的には別ファイルを作成
- Queue
- Storage管理用のWebIF
- Catalystベース
- 機能
- ストレージの追加
- サーバをセットアップしてWebIFから追加
- 利用状況の確認
- ストレージのモード切り替え
- ストレージの追加
- 画像加工はImlib2かImageMagickから選べる
- Squidにキャッシュしている
- 現在運用されている状況
- 20TB〜30TBは用意されていて、運用されているのが10数TB
- 1TB/月くらいで増える
「ライブドア流クラウド的サービス」
- 仮想化技術の選定
- ソーシャルアプリ向けに開発した
- 実装
- LVSのサーバの性能は?
- 250台くらいまでは大丈夫だそう。
- 課金形態は話し合い中
- 同じ顧客のインスタンスは同じところに作らないポリシーにする
- フルマネージドホスティングをベースにして、自動化できるところを自動化するというポリシー
「livedoor Readerの新機能とは?」
- 新機能の紹介
- livedoor streaming API
- フィードの更新情報をリアルタイムで取得するAPI
- 外部ドメインでも普通に動く
- 非公開フィードの記事はでない
- ストリーミング、といっても、Readerがクロールしたタイミングにはなる
- livedoor Blog Tumblr Feedburner PubSubHubbub使ってるフィードはほぼ瞬時に出てくる
- Q4m
- TokyoTyrant
- Nginx
- Streaming APIのフロントエンドとして利用
- long-pollコネクション可
- Plack
- そろそろnginx + Plackに変えたい
- Coro AnyEvent
- MySQL
- Perl 5.8.7
- Q4M
- memcachedの代わりにTokyoTyrant
- HashDB7台
- Coroで作られたDOSツール
- 大量のコネクションを張ってテストするのに使っている
- 処理の内容
- Brocker
- クロール対象をキューに入れる
- cronで1分置きに起動
- このとき必要なデータをMemcachedに入れる
- Fetcher
- Parallel::PreforkとClass::Triggerつかっている
- daemontoolsで管理
- 一定件数処理したら死ぬように作っている
- Coroを使って並列処理をしている。1プロセスで50~100(HTTPDのコネクション)くらい。
- レスポンスが遅いものがあってもクローラが遅れないようにしている
- Parser
- XML::LibXMLとXML::Liberal+独自
- 独自、というのは、巨大フィードを途中で中断するなど
- feedburner.origLink保存するなど
- 一番CPUパワーに依存する処理
- 並列数増やしても意味がない
- XML::LibXMLとXML::Liberal+独自
- Updater
- DBの処理速度に依存
- 1台あたり10程度
- Brocker
- 記事の振り分け
- SKIP
- INSERT
- UPDATE
- SILENT_UPDATE
- ちょっとしか更新されてない
- 一定文字数意外更新されたもののみ
- フィードごとに既出フラグを保存している
- 既出フラグの保存をmemcached→TokyoTyrantに移行
- このとき、ストレージとネットワークIOの節約のため、既出フラグをfeedごとにまとめた。
- フラグだけで5億件!→180万件に減った
- XMLとしては変化しているが記事は変更されていないケースが実は非常に多いことが判明
- 配信元サーバがコメントで書かれてるとか
- lastBuildDateがアクセス日時になってるとか
- 独自のネームスペースにアクセス回数やコメント数が含まれているとか
- そこで前回のパース結果をTokyoTyrantに保存
- 前回更新時のフィードに含まれていた記事は既出の記事である
- Parserの段階で不要な記事にはSkipFlagをつける
- updaterキューへの送信数が半減
- Async::Queue
- クライアント側は書けませんでしたごめんなさい><
BPStudy #29 TDD
はじめに
tokuhiromさんとペアを組ませていただいたのですが、本当に何もできず(そもそも緊張しすぎてしゃべることすらできず)本当に嫌な思いをさせてしまって申し訳ありませんでした。
そんなごめんなさいエントリです。
お題
LRUCacheをつくる
Limitを決めておいて、そのLimitの数だけ値をsetする
getをすることもできて、getすると使われる(残る)
値をsetしたときにLimitより多くなった場合、古いものから消える
TDDのサイクル
TDDのサイクルは、「動くものを書いてきれいにしていく」というプロセスだそうです。
1. テストを書き
2. そのテストを実行して失敗させ(Red)
3. 目的のコードを書き
4. テストを成功させ(Green)
5. テストが通るままでリファクタリングを行う(Refactoring)
6. 1〜5を繰り返す
Skeletonをつくります
今回はModule::Starterを使いました。pmsetupじゃなくてごめんなさい
$ module-starter --module=LRUCache $ perl Makefile.PL $ make test
ということでまずテストを書こう
まずまずテストを書いてみます。自信がまったくないのでgetとsetだけ><
$ vi t/01-main.t
#!/usr/bin/perl use strict; use warnings; use Test::More; use LRUCache; my $lru = LRUCache->new(); $lru->set('a' => 'TestA'); $lru->set('b' => 'TestB'); $lru->set('c' => 'TestC'); $lru->get('a'); done_testing;
実行してみます。こけます。
$ prove -lvr t/01-main.t
t/01-main.t .. Can't locate object method "new" via package "LRUCache" at t/01-main.t line 9. Dubious, test returned 255 (wstat 65280, 0xff00) No subtests run Test Summary Report
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
テストに合うように実装してみる
まずは今の状態でテストが通るようにやってみます
package LRUCache; use warnings; use strict; use Moose; has 'data' => ( is => 'rw', isa => 'HashRef', default => sub { +{} }, ); sub set { my ($self, $key, $value) = @_; $self->data->{$key} = $value; } sub get { my ($self, $key) = @_; return $self->data->{$key}; } 1;
いっかい通してみます。
$ prove -lvr t/01-main.t
t/01-main.t .. ok 1 1..1 ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.03 usr 0.01 sys + 0.23 cusr 0.02 csys = 0.29 CPU) Result: PASS
いったんgetとsetはできました。
LRUになるように変更してみる
まずはテストから。
my $lru = LRUCache->new(limit => 2); $lru->set('a' => 'TestA'); $lru->set('b' => 'TestB'); $lru->set('c' => 'TestC'); is $lru->get('a'), undef; # 2こしかないから、cを入れたときにaが消えてほしい
テストを書き始めて、もっと1こずつテストしたほうがいいと気づきました。
いっぱい書いてみます。
#!/usr/bin/perl use strict; use warnings; use Test::More; use LRUCache; subtest 'test1' => sub { my $lru = LRUCache->new(limit => 2); $lru->set('a' => 'TestA'); $lru->set('b' => 'TestB'); is $lru->get('a'), 'TestA'; is $lru->get('b'), 'TestB'; done_testing; }; subtest 'test2' => sub { my $lru = LRUCache->new(limit => 2); $lru->set('a' => 'TestA'); $lru->set('b' => 'TestB'); $lru->set('c' => 'TestC'); is $lru->get('a'), undef; is $lru->get('b'), 'TestB'; is $lru->get('c'), 'TestC'; done_testing; }; subtest 'test3' => sub { my $lru = LRUCache->new(limit => 2); $lru->set('a' => 'TestA'); $lru->set('b' => 'TestB'); is $lru->get('c'), undef; is $lru->get('a'), 'TestA'; done_testing; }; done_testing;
subtestというのは今回はじめて知りました。Test::Moreでできるのですね。
ここでもtokuhiromさんに助けていただくなんて><
http://d.hatena.ne.jp/tokuhirom/20100118/1263800343
ほいで、実装してみました。
教えてもらったのはもっとかっこよかったのですが、申し訳ないです覚えきれなかったのでだいぶひどい感じになっています><
package LRUCache; use warnings; use strict; use Moose; use Data::Dumper; has 'limit' => ( is => 'ro', isa => 'Int', default => 1, ); has 'data' => ( is => 'rw', isa => 'HashRef', default => sub { +{} }, ); has 'used' => ( is => 'rw', isa => 'HashRef', default => sub { +{} }, ); has 'counter' => ( is => 'rw', isa => 'Int', default => 0, ); sub get { my ($self, $key) = @_; return undef unless defined $self->data->{$key}; if ($self->used->{$key}) { $self->used->{$key} = $self->counter($self->counter + 1); return $self->data->{$key}; } } sub set { my ($self, $key, $value) = @_; $self->data->{$key} = $value; $self->used->{$key} = $self->counter($self->counter + 1); if ($self->limit < scalar keys %{$self->used}) { my @store = sort { $self->used->{$b} <=> $self->used->{$a} } keys %{ $self->used }; $#store = $self->limit - 1; my $new_hash; foreach my $k (@store) { $new_hash->{$k} = $self->used->{$k}; } $self->used($new_hash); } } 1;
setしたりgetしたりするたびにカウンタを増やして、
usedという中にいまキャッシュにはいっているべきkeyとカウンタが入るようにしました。
配列の要素数変更とかかなりごりっとしてて目もあてられない><でもうごくのでいったん。。
テストしてみます。
$ prove -lvr t/01-main.t
t/01-main.t .. ok 1 ok 2 1..2 ok 1 - test1 ok 1 ok 2 ok 3 1..3 ok 2 - test2 ok 1 ok 2 1..2 ok 3 - test3 1..3 ok All tests successful. Files=1, Tests=3, 0 wallclock secs ( 0.03 usr 0.01 sys + 0.23 cusr 0.02 csys = 0.29 CPU) Result: PASS
とおりました。
limitが途中で変わっても大丈夫なように作る
まずまずテストから
subtest 'test4' => sub { my $lru = LRUCache->new(limit => 3); $lru->set('a' => 'TestA'); $lru->set('b' => 'TestB'); $lru->set('c' => 'TestC'); $lru->limit(2); is $lru->get('a'), undef; is $lru->get('c'), 'TestC'; done_testing; };
実装を変更します。limitが変更したときにusedにあるものを変更したいので、
Mooseのtriggerを使います。
(変更部分のみ記します)
has 'limit' => ( is => 'rw', isa => 'Int', default => 1, trigger => sub { my ($self, $new, $old) = @_; return unless defined $old; $self->used($self->_used_hash); }, ); sub set { my ($self, $key, $value) = @_; $self->data->{$key} = $value; $self->used->{$key} = $self->counter($self->counter + 1); if ($self->limit < scalar keys %{$self->used}) { my $new_hash = $self->_used_hash(); $self->used($new_hash); } } sub _used_hash { my ($self) = @_; my @store = sort { $self->used->{$b} <=> $self->used->{$a} } keys %{ $self->used }; $#store = $self->limit - 1; my $new_hash; foreach my $k (@store) { $new_hash->{$k} = $self->used->{$k}; } return $new_hash; }
最後にテストしてみます。
$ prove -lvr t/01-main.t
t/01-main.t .. ok 1 ok 2 1..2 ok 1 - test1 ok 1 ok 2 ok 3 1..3 ok 2 - test2 ok 1 ok 2 1..2 ok 3 - test3 ok 1 ok 2 1..2 ok 4 - test4 1..4 ok All tests successful. Files=1, Tests=4, 1 wallclock secs ( 0.03 usr 0.01 sys + 0.24 cusr 0.02 csys = 0.30 CPU) Result: PASS
とおりました><やった!
まとめ
もっと教えてもらったものをメモっておけばよかったとか
そもそも書けよとかありますが本当にすみませんすみませんすみません><
しかも教えてもらったことさえ満足にできているか・・・><。。
そしてもっときれいに書ける方法かんがえます。
YAPCの時にMooseを教えてもらったときにテストを埋めるように開発するスタイルを教えてもらっていたので
なんとか復習することができました。ありがとうございます。
超てんぱっている中優しく教えてくださって本当にありがとうございました。
そういえばTDDで教えてもらったことをメモってたのに全く書いてないですね。
「ふるまいベースのテスト」ということがとても印象的でした。
実装の細かいやりかたのテストはふつうにwarnとかで出して、
入力、出力はこうあるべきというところだけテストで書くんだというのがわかりました。
昨日ちょうど、テストに何を書いたらいいのかということを社内で話していたので今回わかってよかったです><
ねむむい明日合宿なのでもう帰ります@マクド
2009年の振り返り
そろそろ2009年も終わりということで、この1年間であったことを振り返りたいと思います。
チーム結成
2009年のはじめに、それまで仲の良かった開発メンバーとチームを結成しました。
メンバーの中には開発が初めてだった子もいて、
チームの平均年齢が24歳という超未熟者のチームで、
本当にプロジェクトをやりきれるのか不安だったときもありました。
実際やってみると、そんな不安も軽く払拭してくれるくらい優秀なメンバーばかりで、仕事しやすくて楽しくて、あっという間の1年でした。
良いチームを作るために守ってきた2つのこと
チームを結成してから、2つだけ守ってきているものがあります。
それは、チーム定例会議とチームtracの2つです。
チーム定例会議
今までいろんな定例会議をやってきましたが、たいがい形骸化しがちでした。
そこで、チーム定例会議では構成を見直しました。
定例会議の構成
- 先週やってきたことと今週やることの報告(短めに)
- ソースレビューや勉強してきたことの発表、設計の相談など(長めに)
仕事内容の報告は、マネージャたるもの常に把握しておくべきで、他の人も空気感が見えている状態なので、あえて短めに設定します。
現状では4人〜6人報告しますが、いつも30分以内で終わらせるようになっています。
「わかっているけどやらなきゃいけない状況(=省略可能な状況)」というのが形骸化の一番の要因だと思っているので、
他の人と協力したり、見てあげてもらいたいポイントのみ抑えておいて、あとは簡潔に簡潔にします。
残りの時間を使って、ソースレビューをしたり、設計の相談をしたりします。
この時間でソースレビューをすることによって、この1年で確実にソースレビューの機会が増えました。
わざわざ会議を設定しなくても良い手軽さがポイントのようです。
ソースを見ながらみんなでわいわい言い合うのでとても楽しいですし、逆に定例会議自体のモチベーションにつながります。
チームtrac
かねてからチームで見合える自由に書ける場が欲しいと思っていたのでチームtracを作りました。
新しくやったこと、勉強したことを当たり前感覚に書けると良いなと思っていたのですが、
メンバーを絞って習慣化したことで書きやすくなり、その内容を新しいメンバーが見て追記し、、という良い循環が生まれています。
継続すること
定例会議とtrac、これ自体はとても小さいことですが、1年間継続してきたことで良いサイクルが生まれてきました。
忙しくなってくるとこれら以外にも優先順位が高いものが生まれてくるのですが、
そこで意義を見返して、適宜コンパクトにまとめたり意義に合わないものを削いできたことでブラッシュアップされてきたような気がします。
YAPC::Asia2009でうらやましがる→勉強会に行くように
YAPC::Asiaでメンバーが発表させて頂いているのを聞いて、うらやましくって、
2009年後半からは勉強会に積極的に参加させて頂くようになりました。
普段プログラムは書かせてもらえないので、負い目を感じますし、わからないことも多いですが
積極的に恥をさらしに行くんだと思うと、変な気負いがなくなって楽にさせて頂いています。
基本的に、チーム内やプロジェクト内に問題がなければマネージャの負担は減るわけなので、
来年は、良いチーム、良いプロジェクトになるようにがんばっていって、
空き時間をいっぱい作って、いっぱいプログラミングできるようになりたいです!
今年ももうあと数分で終わりますね!
周りのみなさんのおかげで本当に楽しく充実した時間を過ごすことができました。1年間ありがとうございました。
まだまだ足りないところばかりですが><また来年も、どうぞよろしくお願いいたします!!
UnixBenchでベンチマークをとってみる
会社からデスクトップPC+24.1inchディスプレイもらった!!わーい!
Core i7のメモリ8GB!!すごい!
雑用係なのにこんなプレゼントもらってすみません><。。
せっかく頂いたものなのでF12をいれてUnixBenchとってみました。
UnixBenchでベンチマークをとる
googlecodeからダウンロードして展開します。
グラフィックテストはしないので、MakeFileを修正します。46行目をコメントアウト
46 #GRAPHIC_TESTS = defined
あとはRunするだけ。
./Run
結果は以下のとおりでした。
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
前のPCでF12入れたときの結果が338.5だっただけに超すごい><ほぼ10倍!