2016年10月01日

LINE Notify で line command 作ると便利

インターネット見てたら

って書いてあるの見たので、試しに作ってみました。 動かすと以下の感じです。 LINE Notify さん、めっちゃ簡単で便利すぎないか????!! tweet みてから10分くらいでエントリ書き終わったくらいの手軽さ!
Posted by Yappo at 01:05 | Comments (0) | TrackBack

2016年04月08日

ikachan with Yappocall for LINE BOT API Trial Account

LINE さんから Bot が作れる API がリリースされたということなのでikachanと昔なつかしYappocallの LINE 版を作ってみました。

実物はこちらhttp://yappocall.yappo.jp/
初代 Yappocall は APNs で実装してましたが、今度は LINE を使ってるので僕からのお知らせが表示されてて双方向インタラクションな未来が来てる!

LINE の開発者画面で Bot の作成を行い必要な設定を済ませた後、 Bot 連携するために必要な情報をソースコードに書いて実行するだけで簡単に ikachan のような単純な Web API が設置出来ます。
ソースコードの設定以外にも必要な作業があって、作成した LINE Bot を友だちに追加してから API で利用する appname の登録を行い api_token を生成する必要があります。
ln.yappo を利用した bot は以下の様なコマンドを受け付けているので、 add コマンドで appname の登録と api_token の取得が出来ます。 $SECRET は lnyappo.pl の中で設定した、連携時に使うパスワードのようなものです。知らない人には API の利用をさせないという安全弁です。

ln.yappo Help

1. add
  > $SECRET add $yourAppName

2. delete
  > $SECRET del $yourAppName

3. send message to callback url
  > $SECRET send $yourAppName $message

4. list
  > $SECRET list

5. help
  > $SECRET help

appname と api_token を lnyappo.pl に設定すると本格的に利用可能になるので API を呼ぶでも良いですし、立ち上げた http server にアクセスすると簡単にメッセージを送るフォームが出てくるので、それを利用すると以下の様な感じで LINE にリアルでメッセージが届きます。

これだけでもいいんですが ln.yappo には、LINE で発言したテキストを ln.yappo の Web UI で設定した callback url に送信する事が可能になってるので、より LINE らしいかたちの ikachan になりました。

たとえば

  • 監視アラート
  • Raspberry Pi から LINE にデータを送る
  • 外出先から Raspberry Pi にコマンドを送る
  • ぎっはぶ連携
  • LINE から Twitter にポストする
  • ほかほか
といった活用が考えられます。

特に現状の制限だと、一人あたり1個の Bot しか作れないとのことなので、この ikachan を Hub にして各種システムと連携すると、効率的に LINE Bot で遊べる事でしょう。
という理由もあって appname を登録して一人あたり複数の api_token を払い出し、複数の callback url を設定できる仕組みにしておきました。

ln.yappo を活用したサンプルとして Yappocall という、 Web 上で POST したメッセージを紐付けた人の LINE に送信する。 LINE から送信したお知らせを Web 上に表示するという簡単なアプリも書いてみたので参考にしてください。

ikachan は IRC ベースなので LINE 向けの Bot とは意識する場所が大きく違っていますが、差異に気をつければ古き好き IRC Bot 職人の皆様も簡単に LINE Bot がかけると思います。

  • IRC は irc server と常に接続し続けるが、 LINE は message が callback API に届く、 Bot からの送信は API を叩く
  • IRC は channel 単位に送信すれば全員に送信できるが、 LINE は個別に送信する
  • IRC はいきなり channel に送信しても問題ないが、 LINE だとトークの画面上で利用者の紐付け処理入れといたほうがよさそう
  • というか ikachan 的なの作りたい時は、外の別システムから誰に送りたいかを安全よりな方向で設計しときたい
  • IRC みたいに複数人に同報送信したい時は、複数人の api_token を管理しといて、送信したい人ぶん送っとけば良い

烏賊ソース
https://github.com/yappo/ln.yappo


どうぞご利用下さい。

Posted by Yappo at 16:21 | Comments (0) | TrackBack

2015年12月31日

2015年振り返り #yapcasia

最後の YAPC::ASIA Tokyo 2015 にて 大規模でも小中規模サービスでも捗る microservices な Web サービスのつくりかた という内容で発表してきました。

また LT にて 廃止予定になった $^ENCODING に関する発表もしましたが、諸事情により資料は非公開です。

Have a Happy new year!

Posted by Yappo at 23:18 | Comments (0) | TrackBack

2014年09月29日

#isucon 2014 に参加して暫定圏外になってきました

ISUCON4 の予選やってきました、最終スコアは37000位だったけど本戦足切りラインは45000くらいだと思うので残念でした。
チームメイトは、前回組んだ kamipo さんに加え新メンバー ar_tama さんと共に望みました。
役割としては

kamipo: 司令塔権 middleware 以下全部担当
ar_tama: アプリ担当
yappo: アプリ担当

リポジトリはこちら https://github.com/kamipo/isucon4qualifier

開始前

大体の凡ミスはレギュレーション読まない事に起因するのが、過去の ISUCON の教訓だからひたすらレギュレーション読む。
お陰でリーダの遅刻を見逃した。

10:00-12:00

開始とともにトイレ。この間に kamipo さんが必要なインスタンスあげてログイン出来るようになってた。
うちのチームは1人/1インスタンスという構成で始めた。理由としては去年1インスタンスでやったせいで、気づかない間に環境壊されてたり各人が施した成果のベンチマークを回すのに待ち行列が発生して無駄だったから。
インスタンスを別ける事で他人に影響する事無くひたすら開発を進められた。
ちなみに基本的にサーバのコードは触らずに yappo/master branch に commit してくスタイルだった。

最初に isucon user で直接ログインしようとしたけど、鍵置いても直接はどうしても無理だったから2分くらいで諦めた。ログインし続ければいいだけだし。
そして、標準の ruby でベンチマークを回す。

10:27 < Yappo> 01:26:52 type:score     success:6090    fail:0  score:1316
だった。

その後に ruby を止めて perl を有効にしようとしたら、まさかの forman が死なないトラブルがあったので kill してから plackupしてベンチを取った。

10:37 < Yappo> 01:35:55 type:score     success:7530    fail:0  score:1627
Perlにするだけでスコアが上がった。
workload 4とかにするだけで
10:50 < ar_tama> score 3335いった
でした。

ベンチのスコアを確認した後は、ブラウザで見たときの見た目重視っていうゆるふわルールあったのでちゃんとアプリを使ってみようとしたんだけど、ログインしてから何も出来ない!銀行なのにローン組むリンクすらマトモにうごかない!!!
っていう挙動に不安になったので「いすこん銀行さん Safari でログインするとローン申し込めないんですが、それおっけーですか?」って質問したら問題ないって回答きてひと安心。



その後は benchmarker がどうなってるのかを一通り調べてて

//*[@id='last-logined-at']
//*[@id='last-logined-ip']
//*[@id='notice-message']
って書いてあるのを見つけた。たぶん「DOM を崩さない=このXPathで処理出来る事」だと理解した。
もちろん input 要素や submit 周りの XPath も書いてあったので、ベンチマーク用の UA の時に表示する専用の HTML 返したら良いんだと思ったけど、そんなんおもろくないのでチームメンバーには黙ってた。

その後はテンプレートファイルを見る。

11:06 < Yappo>     <span class="hikaru-mozi">偽画面にご注意ください!</span>
11:06 < Yappo> これに釘付けだった
11:06 < ar_tama> w
11:06 < Yappo> hiraku-mozi
11:06 < ar_tama> hikaru-mozi!!
11:06 < ar_tama> かわいい
いいセンスしてたので余計な所で時間くってた。。

11:08 < Yappo> [isucon@ip-10-127-131-242 ~]$ sudo zcat /var/log/nginx/access.log-20140926.gz | less
11:08 < Yappo> censored - - [26/Sep/2014:09:35:39 +0000] "GET /tmUnblock.cgi HTTP/1.1" 400 172 "-" "-"
11:08 < Yappo> censored - - [26/Sep/2014:10:27:58 +0000] "GET / HTTP/1.1" 200 2228 "-" "() { :;}; /bin/bash -c \x22echo testing9123123\x22; /bin/uname -a"
ヒント探したつもりが全然品とじゃなかった案件もあった。。

その後はベンチ走らせた時のログを集計して top page -> login -> エラーだったら top page に戻る/成功だったら mypage を表示 という固定的なアクセスしかない事を把握した。
top page を開いた時に、必要な static file のリンク先を全部辿ってアクセスしにいく感じだった。
css を gz 化して見たものの当たり前だけどスコア落ちた。これは CPU 食ってて逆効果だったのか md5 checksum が一致してないのかわからんかったけど、余計な事なのですぐにやめた。


12:00-13:00

ここらで作戦タイムしながらアプリのコードを読んでく。
トラフィック的には / へのアクセスが支配的。 /login はクエリが重いので最後のボトルネックは /login 。そして /mypage の内容は実質 /login 時に取得したデータを使い回せる事を把握した。
/ に関しては、ログイン失敗時のエラーメッセージを動的に埋め込んでいるが、実際は5パターンのエラーしかないので、何かしらの状態をクライアント側に保持させて nginx 側で振り分けすれば application が処理しなくても良いはず。
/mypage に関しても /login 時に必要なデータを保持して nginx 側でレンダリングした方が早そう。

という結果を踏まえて、 benchmarker が任意の Set-Cookit を受け取って Cookie ヘッダで送ってくるかを調べ、それが可能である事を把握してから

1. 何も cookie が無い時に / へのアクセスがあったら nginx 側で静的コンテンツを返す
2. ログイン失敗時には error=nanntara という cookie を送信するので、その cookie がついた / へのアクセスは cookie の内容を考慮して適切な静的コンテンツを返す
3. ログイン成功したときは、最終ログイン情報を cookie に入れておくので、 nginx は cookie を元に ssi を使って /mypage のレンダリングをする

という、方針で動く事にした。

kamipo さんが nginx 周りの作業を全面的に行うあいだ、僕は暇になるので、自分は /login の重い処理を片付ける ar_tama さんは逆から攻めてく感じで /report 周りをやる感じになった。
本来は /report はカリカリにチューニングする意味ないんだけど、高スコアが叩けるようになった時に /report の負荷が高過ぎてベンチマーク成立しないリスクもあるので、先回りで。


13:00-15:00

このアプリはログイン時に失敗すると失敗カウントが増えていって、閾値を越えるとそのアカウントがロックされる。または ip address が ban リストに入って、どのアカウントにもログイン出来ない。
という仕組みが入っていたのですが、このログイン時に lock / ban をチェックする為のクエリが面倒いサブクエリで書かれていて index 使われてないので遅い。
これをまずどうにかする為に

CREATE TABLE IF NOT EXISTS `login_log` (
`id` bigint NOT NULL AUTO_INCREMENT PRIMARY KEY,
`created_at` datetime NOT NULL,
`user_id` int,
`login` varchar(255) NOT NULL,
`ip` varchar(255) NOT NULL,
`succeeded` tinyint NOT NULL,

KEY (user_id),
KEY (ip),
KEY (succeeded, user_id),
KEY (succeeded, ip)
) DEFAULT CHARSET=utf8;

という感じで index つけたら、これだけで score:1668 -> score:10027 に上がっていた。

でも index を貼る前に考えてた戦略があったので、一旦この案は取り消しました。

index 貼ってもログイン処理で lock/ban されたかどうか調べるクエリが複雑になるので、それらのクエリが簡単になるように予め失敗回数をカウントするだけのテーブルを用意しました。

CREATE TABLE IF NOT EXISTS `last_login_failure_count_user_id` (
`user_id` int NOT NULL UNIQUE,
`count` int
) DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `last_login_failure_count_ip` (
`ip` varchar(255) NOT NULL UNIQUE,
`count` int
) DEFAULT CHARSET=utf8;

そうすると、ログイン時に login_log テーブルと追加したテーブルに対して3回も insert クエリが走ってしまうので trigger を使ってクエリ数を減らしました。
DELIMITER //
CREATE TRIGGER login_log_insert AFTER INSERT ON login_log
FOR EACH ROW
BEGIN
IF NEW.succeeded = 1 THEN
DELETE FROM last_login_failure_count_user_id WHERE user_id=NEW.user_id;
DELETE FROM last_login_failure_count_ip WHERE ip=NEW.ip;
ELSE
INSERT INTO last_login_failure_count_user_id SET user_id=NEW.user_id, count=1 ON DUPLICATE KEY UPDATE count=count+1;
INSERT INTO last_login_failure_count_ip SET ip=NEW.ip, count=1 ON DUPLICATE KEY UPDATE count=count+1;
END IF;
END//
DELIMITER ;
また、 SELECT クエリが複数飛ぶのも点数下げるだけなので UNION でおまとめしてます。
(
SELECT 'user_id' AS name, count AS count FROM last_login_failure_count_user_id WHERE user_id = ?
) UNION (
SELECT 'ip', count FROM last_login_failure_count_ip WHERE ip = ?
)
違うテーブルを UNION にまとめて結果を取り出すと、どの行が何のデータだかわからなくなるので1カラム目にラベルを入れておいて、それをプログラム側で成形してりようします。

ここら辺ずっと1並列でベンチ取ってたので、基本的にスコアが1万から変わらなくて辛かったけど次なる施策が控えてるので、このまま進んでた。

15:00-16:00

login 周りが一旦落ち着いたので、今度は /mypage で表示させるべきデータを /login で生成する作業に取りかかる。
/mypage で出しているのは前回ログインした時の ip address とログイン日時。という事で /login 叩かれた時点の user_id の最近の成功したログインのテーブルからデータを取れば良いという事になる。
ログイン履歴のテーブル(login_log)は、該当の user_id/ip address がいつログインしたか、それは成功したか失敗したか(succeededカラム)。という情報を入れてるので SELECT * FROM login_log WHERE succeeded=1 AND user_id=? ORDER BY id DESC みたいなクエリになるわけだけど、実は先ほど trigger の仕組みを作った時に

CREATE TABLE IF NOT EXISTS `last_login_success_user_id` (
`user_id` int NOT NULL UNIQUE,
`login_log_id` bigint NOT NULL
) DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `last_login_success_ip` (
`ip` varchar(255) NOT NULL UNIQUE,
`login_log_id` bigint NOT NULL
) DEFAULT CHARSET=utf8;

というテーブルを作ってて
DELIMITER //
CREATE TRIGGER login_log_insert AFTER INSERT ON login_log
FOR EACH ROW
BEGIN
IF NEW.succeeded = 1 THEN
INSERT INTO last_login_success_user_id SET user_id=NEW.user_id, login_log_id=NEW.id ON DUPLICATE KEY UPDATE login_log_id=NEW.id;
INSERT INTO last_login_success_ip SET ip=NEW.ip, login_log_id=NEW.id ON DUPLICATE KEY UPDATE login_log_id=NEW.id;
DELETE FROM last_login_failure_count_user_id WHERE user_id=NEW.user_id;
DELETE FROM last_login_failure_count_ip WHERE ip=NEW.ip;
ELSE
INSERT INTO last_login_failure_count_user_id SET user_id=NEW.user_id, count=1 ON DUPLICATE KEY UPDATE count=count+1;
INSERT INTO last_login_failure_count_ip SET ip=NEW.ip, count=1 ON DUPLICATE KEY UPDATE count=count+1;
END IF;
END//
DELIMITER ;
という定義を作っていたので、それを利用して
FROM last_login_success_user_id JOIN login_log ON last_login_success_user_id.login_log_id=login_log.id WHERE last_login_success_user_id.user_id = ?
のようなクエリを作っていた。
もちろんこれも UNION でむりやり1クエリにまとめてたので
(
SELECT 'user_id' AS name, count AS count, NULL AS ip, NULL AS created_at FROM last_login_failure_count_user_id WHERE user_id = ?
) UNION (
SELECT 'ip', count, NULL, NULL FROM last_login_failure_count_ip WHERE ip = ?
) UNION (
SELECT 'last', NULL, ip, created_at FROM last_login_success_user_id JOIN login_log ON last_login_success_user_id.login_log_id=login_log.id WHERE last_login_success_user_id.user_id = ?
)
みたいにして取ってた。

そして、そろそろ素の file に session data を書いてるのも良く無さそうなので。 /dev/shm 以下に書くようにしてメモリの上に session data を置くようにした。
ここで memcached 入れなかったのは、いきなり新規の daemon 突っ込もうとしてハマったら面倒、今まで1個のプロセスの中だけで session data の読み書きしてたのに突然別のプロセスに tcp socket 経由で処理するのは危険だしコンテキストスイッチやばそう。みたいな素人判断で安全にメモリ上に移行する方法を選びました。

この辺りまでは、ささいな typo でベンチマークがこける事はあったけど、それ以外の大きなトラブルは無く進んでた感じ。

ここで衝撃の事実

15:42 < Yappo> flash まわり kamipo 先生がやってたけど、どうなんだろうw
15:42 < ar_tama> w
15:42 <@kamipo> それは挫折しましたw
15:42 <@kamipo> si
15:42 < Yappo> w
15:42 <@kamipo> し、使ってる / がめっちゃ速いから
flash まわりってのは / とか /mypage を nginx でどうにかするって言ってたやつなんだけど、結局 ssi がうまく動かせなくて諦めてしまったっぽい。

16:00-17:00

という事で /mypage を nignx で処理する事は諦めたけど / は静的に返そうという話になった。
僕は事前の準備でベンチマークは path が不一致だと加点しないが、 query string が url に付与されてても加点対象となる事実をしってたので、 /login でエラーになったら /?error=xxx にリダイレクトして nginx で query string を処理して、全ての / へのレスポンスを静的に返そう!という話になった。

16:30 すぎた辺りから、まだ nginx の設定出来ない感じだったので全員で nginx の設定調べだすことになった。

ここからが真のデスマーチが始まって、だれも / を静的に返す nginx.conf が書けないまま1時間がすぎてしまい。途中経過に名前出てこないまま終わるのだけは嫌だ!というリーダの叫びもあって17時前に3万ちょい越えのスコアを送信してギリギリ名前を刻む事だけは出来たけど暫く進まず。。

17:00-17:40

全員でnginxを調べだして30分がすぎて、このままだともうダメだ!ってなってた頃に、ようやく僕が nginx で動く設定が解ったので、設定を試してベンチを回す事ができた。
まだ / だけ静的化しただけだったけど、すぐに error page を静的にする設定を入れて何とかベンチ通るようになった。

17:39 < Yappo> 08:37:49 type:score     success:68790   fail:0  score:14859
17:39 < Yappo> 08:39:27 type:score success:159410 fail:0 score:34434
上が1並列で下が5並列くらいだとおもう。

このくらいになると、まったく原因解らないけど僕のインスタンスだけが正しく動く環境になってました。
去年の本戦も同じくらいの時刻にもあったのですが、今回も「もう最後の頼みの綱はやっぽさんだけや。。」って発言を頂いてしんみり。

結局、静的ファイル大作戦でスコアが1-2割上がったくらいでまだまだ足りんかった。

17:40-18:00

この後は悪あがきで Starman だったのを Starlet に入れ替えて workload を色々変えて試してみて、だいたい37000くらいのスコアで収束しそうだったので、天にも祈る気持ちでベンチマーク連打を他のメンバーにお願いして僕はトイレに行ってきました。
そして帰ってきた頃に終了です。

やり残した事

みなさんお分かりでしょうが trigger 周りが無駄すぎるので、そこはもっと効率よくする予定で進んでたのですが、さすがは本番でトラブル多発で時間足りなくなって、まともな感じにする前に撃沈でした。
最終的には MySQL の接続は /login のみで 1 write, 2 read クエリのみになってたけど、やはり /login での mysql 処理が支配的になってくるので users テーブルを全部 perl のコードに変換してクエリ数を減らす事もやりたかったです。
最後の手段で、ベンチマークの User-Agent の時だけ必要最小限な HTML を返すという事をやって終了させる目標があったけど、それもやりきれず残念。

スタート時に使ってる midllware を使い続けてキャッシュ戦略も取らなかった割には良いスコアだったのでは???

kamipo さんとか ar_tama さんとか、なんもバリュー出せてない言ってたけど細かい所直したり バグ見つけてくれたり kernel 設定したり middleware の調整したり ami 提出の調整するのとかバリューでまくってたよ!!
最初の戦略がちゃんと当たってれば、それこそすっごいバリューになってたし、今回は惜しい感じだっただけ!!
僕最初と最後に別のバリューだしてたけど。。。

反省点

スタートダッシュをゆっくりしない。最初と最後くらいトイレに行かない。
最後の静的ファイル返す時に Varnish 入れた方が良いと思ってたけど、普段やらない事を本番でやっちゃだめだという学びがありました。

こちらからは以上です。

Posted by Yappo at 19:36 | Comments (0) | TrackBack

2014年07月15日

MySQL Casual #6 で Groonga の話してきました #mysqlcasual

先週末 Oracle で開催された MySQL Casual #6 でBetter Groonga Replication という題名で Mroonga 使わずに Groonga のレプリケーション構成作って便利に使ってるよ!って話をしました。

普通に話したら Mroonga を使えってマジレス返されるので、なんで Mroonga を使わないで Groonga 単独で頑張ったかの理由などの話をしてたら時間かかりすぎたので9月に開催される Groonga のイベントでもうちょっと詳細の実装などを話そうとおもいましたまる

Posted by Yappo at 16:21 | Comments (0) | TrackBack

2014年06月19日

xlsx ファイルを git diff しやすくする為の天才的な wrapper script を書いた

皆さんはプロジェクトのリソースとしてエクセルの xlsx ファイルを使う事があると思います。
何てったって事務職の人ですら楽々使えるスーパー優れた UI なので、 web の管理画面とかを作り込むよりもエクセルでシート作ってもらってしまった方が早いケースも多いんです。現実の世界では。

で、普通の人は TSV にするだの CSV にしてもらうだのすると思うんですが、一方的にデータ貰うだけなら良いんだけど、相手とやり取りする時にはどうしても xlsx ファイル経由とかにしないと相手がこまる!やっぱりエンジニアのエは優しさのエだから相手に優しくしないとだめです。

で、 xslx ファイルでエンジニア以外の人とデータやり取りするとやっぱり、バージョン管理したくなるのが人情です。
でも xslx ファイルはバイナリファイルなので git diff とかが残念です。。。

って事で作っちゃいました。

https://github.com/yappo/p5-git-xlsx-textconv.pl

xlsx2txt みたいなコマンドは結構あるけど、僕が作ったのは git diff した時に見やすさを重視してます。
だいたい下の画像のようになります。

シート名を行頭に持ってくるので複数のシートでもだいじょうぶです。
行名や列名を入れると行挿入で死ぬので入れてません。簡単ですね。

README.md の通りに install して .gitconfig を設定して プロジェクトの .gitattributes を設定すればすぐに使えます。

僕の用途だと1行に意味がある感じのシートだからわりとこれで良いけど、列と行を特定したセルにそれぞれ意味があるなら行列を1行で区切る感じの出力にしたら便利でしょう。

その他

折角だけど git merge も全自動で良い感じにするラッパー書きたかったけど git には良い感じに merge warpper script を指定出来なかったようだ。。

あと .xlsx って実は zip file で中身は XML だったから shell だけで解決させようと思ってたんだけど、データ構造わりと面倒くて諦めた。

もし Perl とか使うだけで発狂するような方がいたら Ruby に移植するなりお好きにしてください。その場合のライセンスも好きに設定していいです。

enjoy!

Posted by Yappo at 21:13 | Comments (0) | TrackBack

2014年03月12日

なぜ SQL_CALC_FOUND_ROWS や LIMIT OFFSET のページングが良く無いのか

ここ最近の大規模サービス関連したデータページング考です。

mysql 5.5.34 で試して記事書いてます。 bigdata テーブルは id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, PRIMARY KEY (id) なカラムがある前提です。もちろん InnoDB です。

2014年なんだからCOUNT(*)とかSQL_CALC_FOUND_ROWSとかLIMIT OFFSETのページングはやめようぜ - Togetterまとめが発端にみえるけど、わりと昔から話されてる事なんだけど、「nippondanji SQL_CALC_FOUND_ROWS」でググっても有用な情報ないし文書化されてないからしとく。

SQL_CALC_FOUND_ROWS

ページング処理で使われがちな機能です。
SQL_CALC_FOUND_ROWS と言うのは LIMIT 付きのクエリでも、そのクエリから LIMIT を抜いたら実際何件の結果が取得できるかを計算してくれる MySQL 4.0 から追加された SELECT 文の拡張機能である。
SELECT SQL_CALC_FOUND_ROWS * FROM bigdata WHERE id > 10 LIMIT 10;
のように使うと、次のクエリでSELECT FOUND_ROWS();と打ち込むと LIMIT なしで得られるはずの行数が貰える。

ある程度のデータサイズのサービスを実践で開発していない人だと SQL_CALC_FOUND_ROWS はとても便利に使えます。しかし bigdata テーブルの中身が膨大になってくると徐々に「あれ、、どっかが重い。。。」っていう異変が出てくるんですね。

理由は単純で SQL_CALC_FOUND_ROWS を付けると、内部的には LIMIT 無しの状態で全てのレコードを読み込むまで処理をして、結果を返す時に LIMIT で指定された行数に絞り込んでるだけなんです。内部処理的には LIMIT してないので遅い。
簡単な理由です。

実際手元に1000万行近くかつ2GBくらいのデータの bigdata テーブルがあったのでSELECT * FROM bigdata WHERE id > 10 LIMIT 10;を実行すると即座に結果が帰るのに対してSELECT SQL_CALC_FOUND_ROWS * FROM bigdata WHERE id > 10 LIMIT 10;は30秒くらいかかってました。

「じゃぁ COUNT() 使えばいいじゃん」っていう突っ込みもあるでしょうがSELECT COUNT(*) FROM bigdata WHERE id > 10;も遅いしSELECT COUNT(*) FROM bigdata FORCE INDEX(PRIMARY) WHERE id > 10;も変わらないです。詰んでます。

両方とも、全ての結果行数を得る為には全部読み込まなきゃいけないのでとても遅い。


それでも何とか早く COUNT() する時にはnipondanjiさんの解説を良く読むといい。小さいサイズの index を読むだけで済むようにしたら早く COUNT() 出来るみたいな話である。
結局は結果の行数が多ければ多い程読む場所増えるので遅くなっていくんですけどね。


LIMIT OFFSET

これは、ページング処理で利用されやすいポピュラーな機能ですね。
というか SQL_CALC_FOUND_ROWS/COUNT() と組み合わせて「全件n件あるうちx行からy行まで表示しています」みたいな UI の為だけに使ってる人も多そう。

まぁこれも、マイクロなデータセットのサービスでは機能するでしょう。これが
SELECT * FROM bigdata WHERE id > 10 LIMIT 10 OFFSET 3000000;
とかになってくると事情は変わってきます。

これも理由は簡単ですが、与えられた条件から300万行目を正しく出す為に mysql は律儀に300万行分のデータに到達出来るまで条件判断していってるのです。
「この条件なら id=3000000 までスキップすれば良いじゃん」とか思う人も居るかもしれないけど、途中の行とか消されてたら無理ゲーすよね?

一つの index でクエリが処理出来れば少しは早くなるけど、それでも index の中を OFFSET の所まで読み進めるのでおそい。

(追記)あと、わりと言及が少ないけど URL パラメータに offset を渡す方式だと、レスポンスの HTML を作った後にユーザがリンクをクリックするまでの間にレコードの削除とか追加が行われて順番が変わった時に対応できないよね。ヘタするとさっき見せた行を次のページでももう一度出しちゃうよねってのある。

落とし穴

SQL_CALC_FOUND_ROWS を使う対象のクエリは件数が1000件以内とかの超小規模なので問題が起きないのは自明。
ページング処理で1000件以上のリクエストは受け付けないから LIMIT OFFSET でもほぼ問題が起きない。

などの意思を持って実装するかもしれませんが、自宅用のプログラムで無い限りは避けるべきです。
なぜなら自分以外の誰かがメンテナンスをする事になった時に、その誰かが良くわからないでコピペで新機能を作ってしまう、その新機能がわりとデカイデータを取り扱う仕様だった!
という状況は日常にありふれていて、そういう時に急にアラートが鳴りだしてオフィスから椅子が無くなってしまう。
そんな悲劇が起こりえるので、業務用のコードではなるべくこれらを使わないように行きていくのが処世術です。

ちなみに 他人=未来の自分 でもあるので、自分で自分の首を絞める可能性も大きい。

解決方法

SQL_CALC_FOUND_ROWS の件に関して言うなら、件数を取りたい WHERE 条件が index だけで済むケース等では、カウント用の別テーブル(例えば bigdata_count)を bigdata テーブルへの WHERE と同じ WHERE を処理出来るカラムと count 用のカラムを用意しておき bigdata 側の TRIGGER を仕掛けておいて、 bigdata テーブルに write 処理をするたびに bigdata_count を書き換えておく。そして検索時に bigdata テーブルへの検索と同時に bigdata_count テーブルも検索かければ時間がかかるスキャン等を行わないで、一度の index 探索で全件数取得が可能になる。
これは、検索条件に対する全件数表示がやむなく必要な時によく使う手段です。
(追記)いわゆるサマリーテーブルってやつです。

LIMIT OFFSET に関しては WHERE 条件の中に必ず PRIMARY KEY を含める事が可能になるような index を貼っておいて
SELECT * FROM bigdata WHERE id > ? ORDER BY id LIMIT 10;
のようなクエリを使います。次ページへのパラメータは上記クエリの最後の行の id の値を渡す事で OFFSET の代わりとなり得るのである。
しゅぱっ!と目的の OFFSET まで index で飛んでってさくっと結果を返すのでちょうはやい!

PRIMARY KEY 以外のカラムで WHERE した場合でも安心で、 WHERE 対象にちゃんと index が貼られてれば(常識的に index 貼ってないカラムに WHERE とかしないよね?) PRIMARY KEY 以外の index 定義では暗黙的に PRIMARY KEY が含まれたと同等になるので、KEY (foo)のような index を貼っておいてもWHERE foo=? AND id > ? ORDER BY idというクエリを投げても処理速度を落とさなくても同等の事が可能です。ただ EXPLAIN でちゃんと確認した上で必要なら FOURCE INDEX とかが必要です。
参考文献: 漢(オトコ)のコンピュータ道: 知って得するInnoDBセカンダリインデックス活用術!

暗黙的に主キーの値が含まれるのである。そのため、次のような検索は自ずとCovering Indexとなるため高速である。そして、ソートにもインデックスが利用される。

逆順ソートにしたい場合は普通に DESC とか付ければいい。

(追記の追記)
これじゃ次にページがあるかどうかわからない!っていう人のために、必要数 + 1 の数だけ LIMIT に指定して、結果が全部帰ってきたら最後の行だけ抜いて返して、 "hasNext":true みたいな response を返すといいと思います。
前のページが有るかどうかは UI 工夫してパラメータ引き回すでもいいし、そんなの信用出来ない場所だったら(SELECT * FROM bigdata WHERE id <= ? LIMIT 1 ORDER BY id DESC) UNION (SELECT * FROM bigdata WHERE id > ? LIMIT 10 ORDER BY id)とかして、前のレコードが存在してたら "hasMaenopage":true とか返せばいいですね。 UNION 使ったらクエリは一個なんでそんなにパフォーマンス落ちない。
(/追記の追記)


ちなみに index とかはりきれないような全文検索とか必要なケースだと Groonga を mysql の外部 index として利用してますね。
Groonga の _key に PRIMARY KEY をつっこんでる。え、ぐるんがってすとれーじえんじんだったけ、そうだっけぼくよくわかんない。

まとめ

SQL_CALC_FOUND_ROWS や LIMIT ? OFFSET ? でのページング処理がなぜ遅いのかと、その代替手段の紹介をしてみました。
もちろん「前へ 1 2 3 4 5 6 次へ」みたいなリッチなページングの実装には役に立たないかもしれません、でも果たしてそういったページング処理は本当に必要なんでしょうか?
「なんとなく Google っぽいのにしたいから」みたいな安易な理由じゃないですか?
正しくスケールするサービスを提供するには、企画書段階から UI の妥当性とパフォーマンスにどの程度影響するかを考えて取り組む必要があります。
UI を工夫する事でサーバ側の処理負担を大幅に減らせる機会は沢山あるので積極的にサービス全体を見ていく能力も2014年代のスケールするサービス構築には必要な能力だと思ってます。
それでもやっちゃいけないのが、技術的にむづいから企画をねじ曲げる事ですね。使える手段は常に多く持っておいて、適材適所できる人間になりたいものですね!

ちなみに SELECT * FROM bigdata WHERE id > ? ORDER BY id LIMIT 10; に一番相性がいいのはスマホのリストビューです。理由はきっと誰かがはてなに書く。

という事を「ISUCON3 の本戦行ったけど見事に空中分解して惨敗したよ」と「 CROSS 2014 コードレビューぶつかり稽古に登壇してきた」という報告の代わりとしてこのエントリを役立ててくださいということをもちまして、このエントリを〆させていただきます。

追記

ちなみにこれが具体的にどんなにコストがかかるかってことを僕は9年くらい前から mysql のソースコードレベルで理解していた。

深遠な理由でこれやって大変な事になってる人が「paging できる API とかは hasNext とかそういうのにすべき」って言ってた。サーバ側で totalRows みたいなのは出さないで hasNext/hasHitotumae みたいなのだけ返せば軽い API 設計ができるとかそういうの。

Posted by Yappo at 13:08 | Comments (0) | TrackBack

2013年11月19日

2014年に向けた JSON API の実装の方向性と X-JSON-Status 改め X-API-Status header のご提案

追記 2014/11/20 14:00:00

わりと JSON やら XML やら各種フォーマットで API を運用している環境がある場合に JSON API の時だけ X-JSON-Status にすると XML とかの時と整合性取れないし、 X-XML-Status みたいのを量産するのは困る的なレビューを頂いたので X-JSON-Status をやめて X-API-Status にしました。

へたに JSON に限定するから REST とか JSON-RPC とかいわれるんや! X-API-Status にしたら全部解決したし MessagePack な API でも使い回せるって songmu さん言ってた! XML とかからどうやって引っこ抜くかまで僕考えられないけど!

ちなみに Amon2 の方も X-API-Status にしたのを merge 済み

始めに

ここ最近の Web 制作の現場ではスマホアプリが主流になってきており、 server side の開発も従来の text/html が主要な content type では無くなり application/json を主に返す server side application を実装する人も増えてきたのではないでしょうか。
いわゆる JSON API ですが、現状これらの仕様は各者それぞれが自由に(ある程度メジャーなサービスの模倣はあるにせよ)行っています。それが良い事か悪い事か僕にはわかりませんが、今回は皆が捗る一つの提案をしたいと思います。

現状の JSON API

一般的な JSON API を作る事を考えた時に、その API が error を発生させる時と言うのは API を使う client の request 内容に不備がある時や、関連する他の API が error を返す時はたまた IO 等がエラーを返した時になると思います。

基本的にはそれらの error 全ては JSON API を開発する人がハンドリング出来る内容なので、適切な JSON を response body として返してる事でしょう。当然 API を利用する client は server side が返す物は全て JSON であるという仮定で実装されてしまってるのかも知れないので(そういう開発者は良く無いけど)、意図しない例外も全て捕まえて JSON にして返す実装もあるでしょう。

HTTP status code

ここまでは割と普通の内容ですね。正常にリクエストが完了する事もあれば error を返す物があります。

これから本題なのですが、もしも認証が必要な JSON API があるとして client からの request が認証を満たさなかった場合の HTTP status code はどうするのが適切でしょうか?
普通に考えると

401 Unauthorized
等を返して {"errorMessage":"unauthorized"} みたいに返してしまうのかもしれません。
そしてちょっと前提が変わりますが、あなたが作っている JSON API が更に他の API を使っていたとします。その API への request が timeout してしまった場合も、同じ方式で行くと
504 Gateway Timeout
を返してしまうのではないでしょうか?

わりとちゃんとしてるサービスの運用をしている人達は全ての HTTP status code を監視して 50x が多く出たら何かの障害がある? 40x が出たらリンク先が切れてておかしいんじゃね?みたいな格闘を日々しています。もし、あなたが書いた JSON API のエラーコードを HTTP status code で表現した場合に運用者にとってのノイズになるかもしれません。ようするにアプリケーションが正しくハンドリングしてレスポンスを返している場合は正常系としておいて本当に問題があった時だけ異常系の status code にする!とかですね。若しくは深遠な理由で通常の HTML application や static contents と同じ host で JSON API をサービスするとかそういう状況も泥臭い世の中には存在するので、そういう時はノイズになりやすいですね。

また、通常 HTTP status code では表現不能な error response を仕様に組み込まれる事も多々あります。そういった場合は結局 JSON の中で {"status":415,"errorMessage":"foo"} とか {"errorCode":415,"errorMessages":["foo","bar"]} などのような表現をするのでは無いでしょうか。

RESUful な人達には怒られるけど、そもそも HTML based な Web Application においては、 client からの入力データの不備は

200 OK
で返した上でエラーの状態を HTML の中に記載して返してるではありませんか。
そういう発想のもと上記の問題を解決する為に「基本的には 200 OK を返して、それとは別に JSON の中で status code を与えて client に処理してもらう」みたいな実装も一つの手段として使われます.

JSON status code の問題

一つ目の問題点としては、ここ最近僕も JSON API を沢山書くようになってきて感じてる事として一般的な web server が書き出す access log に JSON の中の status code が入らない、入れる為には apache の中で JSON をパースするか、 response body 全部をログにつっこむしかない!そんなの現実じゃない!
なぜ欲しいかというと、どの API に大してどんな error を返してるのかを tail log とかして問題解決したい時があったりするんです。現状だと別にログ履くとかしないし一応ログは吐いてるけど通常の access log 以上の情報量のログを常に吐ける程ぼくは人間が出来ていない。

二つ目としては、 response で送られた JSON をパースする必要がないレベルの error があった時に、 client 側に無駄な負担をかけさせちゃう。
これはだいぶ後付けの理由である。

X-API-Status header

そこで導きだされた解決策として JSON の中野 status code を X-API-Status というヘッダで出力するという事。

response header として出力すれば apache の log とかでも

%{X-API-Status}o
とかで出力できるし、 client 側の実装でも header を見るだけで処理の分岐が可能になる。

そして access log に application layer status code が吐き出されるという事は、モリス作の紀香とかを使って直近1分以内に以上系のレスポンスが増えたのでアラートを出すみたいな運用基盤が新たに構築出来る!すべての人類が幸せになるじゃないか!

という事で、皆さんに嬉しいお知らせとして Amon2 で X-API-Status を簡単に出力出来る patch が先ほど merge されたので、これがリリースされればお気軽にこの運用が可能になります。
以下のような簡単な感じで使えます。

    __PACKAGE__->load_plugins(
        'Web::JSON' => { status_code_field => 'status' }
    );
    ...
    $c->render_json({ status => 200, message => 'ok' })
    # send response header 'X-API-Status: 200'

503 などの致命的なエラーはどうする?

それでもやっぱり致命的なエラーは HTTP status code 側で表現されて然るべき、ただし response body は JSON を必ず返す。という感じになってしまうので、 server side で美味しい事だらけなんですが、 client side の実装が負担増える気がしています。
ただ今までも HTTP status code をみてから json.status やら json.error やら、正常系だとそもそも status code がないよ!みたいなカオスだったんで、それが HTTP status code と X-API-Status をみるだけで respnse の状態がわかる感じになっていくから、まだマシになるのかなーとおもいます。

まとめ

  • 近年の JSON API での status code の実装についてまとめました
  • それらにまつわる面倒ごとを改善する X-API-Status header の提案をしました

追記

  • Access-Control-Expose-Headers: X-API-Status は、アプリケーション開発者が状況に応じて返してあげればすむ感じっぽいから、現状大丈夫そうだった


NORIKA―藤原紀香写真集
大沢 尚芳
ワニブックス
売り上げランキング: 34,355
Posted by Yappo at 15:04 | Comments (0) | TrackBack

2013年10月07日

ISUCON3 で暫定で本戦進出らしいです #isucon

ISUCON 3 っていう、インターネット系エンジニアが全ての技量を試されるガチンコバトルなイベントがあって、kamipoさんとgfxが「あと1人チームメンバー募集!」って言われたのでふらっとパーティに入って参加してきました。

暫定順位みると、大体11位っぽい?

前日

僕は金曜の深夜に飲みすぎ+生ものに当たって土曜日は寝込んでて日曜も朝からダメだった、gfxもなんか体調悪かった、kamipoさんもなんかあれらしかった。

当日合流前

kamipoさんだけ、素晴らしいオフィスで有名なフリークアウト入り。僕とgfxは最初から遅刻宣言。

開始直後

kamipoさんだけawsアカウントの準備してて現地ついてたらしい。僕らは遅刻って言ったからおにぎり食べてたらしい。

合流前

おなかおかしいから、フリークアウトのビルの前でやってた丸しぇに玄米リゾット売ってたので買おうとするも、店員さんがコンビニ言ってたらしく10分くらいまってからリゾット買って合流した。

合流後

10:49 <@kamipo> いまの時点まででやったこと
10:49 <@kamipo> percona-toolkitいれた
10:49 <@kamipo> apacheをnginxに入れ替えた
10:59 <@kamipo> webapp以下をgit pushした https://github.com/kamipo/isucon3

ていうログみたから、とりあえず checkout してみる。

すでに nginx にして800くらいのスコアから2000くらいになったとか言ってた。

ポリシー

他の人がどう思ってたか知らないけど

  • どうせ予選なので決勝進めれば順位にこだわらない
  • 普通の仕事と同じ事をする
  • 運用可能な変更だけする
  • ベンチが早ければいいじゃなくて、引き継いだ人が使える物にする
  • プロセスが落ちてデータロストとかしない
  • 余計なミドルウェアとかいれない
  • というか、元々のシステム作った人が逃亡して仕様書が無い状況で、現状のコードから意図を汲み取って同じ挙動で早く動かす
  • そもそも仕様がガチで reject するレベルで糞だけど友達のサービスを助けると思って目をつぶる
  • さっさと帰って寝たい
みたいなポリシーで進めていこうとおもいました。
というか、二人とこれといって打ち合わせとか意識合わせとか何もしてない。

やったこと

foreach (userid IN memos.userid) { db.execute("SELECT * FROM users WHERE id=?", userid) }みたいな糞みたいなクエリを1個に纏めた
たぶん20%くらい早くなった。

アクセスするたびに users テーブル見る糞実装してるので、直すついでに変更が一切発生しないデータをキャッシュに保存してqueryを減らした

kamipoさんが「ORDER BY created_at DESC, id DESC の created_at は自明過ぎて不要だし index ないから ORDER BY id DESC だけにして」って言ったからした
ここで

13:17 <@Yappo> Result:   SUCCESS 
13:17 <@Yappo> RawScore: 3828.3
13:17 <@Yappo> Fails:    0
13:17 <@Yappo> Score:    3828.3
くらいだった。

memos.is_private で、全体公開とプライベート用のメモのリストの出し分けを辞める
memos.is_private=0 かどうかで、メモ一覧を出し分けると is_private には index が貼られていない、そして 0 or 1 なのでカーディナリティが低すぎる。ということで、パーティションにしようかとも思ったんですが、パーティションにすると自分自身のメモを見るときは is_private の値が関係無くなってコストかかってしまうので、 public な memo_id だけを保存しておく public_memos というテーブルを作りました。
このテーブルは後にも活きてきます。

メモ全件数を保存しとくテーブルを作った
public_memos に呼応した kamipo さんのアイディアでメモの全件を保存しとくテーブルを作りました。 trigger 周りは全部 kamipo さんが言ってた奴で僕の中ではすっかり存在忘れてました。
gfx がメモの全件数を cache にぶっ込んで、メモを追加したら incre するやつ入れてたけど INSERT と incre の間に GET がくるとベンチマークが FAIL するような現象があったのでキャッシュ辞めました

OFFSET が糞みたいな感じだったので OFFSET 無くてもサーチ出来るようにした
わりと LIMIT 100 OFFSET 13200 みたいなあり得ない感じのクエリが飛んでて、僕とか Senna+MySQL ハックで OFFSET のこういう感じなのやばいの知ってたんですが、どうこう言ってる間に kamipo さんが前述の新規テーブルを組み合わせて良い感じのクエリ作ってました。

前後のメモのリンクの為のIDを効率よくとる
もとの実装が「そのユーザの作ったメモの全レコードとカラムを全部メモリに読み込んでプログラム側でループを回して前後関係を取る。」みたいな信じられない実装だったので KEY(user_id, memo_id) 的な index を追加して1個のクエリで解決しました。いちおう「自分自身の場合は is_private やつをだして、他人のだったら public なのだけ出す」みたいなロジックだったけど、すでに public_memos ってテーブルが別に作ってたのに UNION して解決でした。

既存の users テーブルの内容を cache に乗せる
うっかり忘れてたけど、初期化 SQL でユーザレコードが結構作られていて、この部分のログイン処理とかでキャッシュが聞いてなかったので、ベンチマーク初期化スクリプトでキャッシュあっためるようにしたら2000位スコア上がって11200くらいになった気がします。

考えた事

割と「どーせ SQ Lがダメで IO おかしくなるだろから、まともな SQL にして様子みよう」みたいなノリで DB schema みてから、ざっとアプリケーションコードみて無駄なクエリとか消してました。無駄なループの中で無駄な重複クエリ消すとかそういうのですね。

kamipo さんは逆に slow query log を実直に解析して僕とかに問題点報告してて「これこれこうしたらいいよ!」みたいに言われてたけど、大体僕もアプリ側のコードみて問題把握してて実装してたりするので「そうそう、かんぺき!」ってかみぽさん言ってました。

gfxは普通にプロファイリング取ってたりとかそれの対応とかしてたけど、どっちかというと僕と kamipo さんの見てる問題領域が近くて gfx の方まで見れてなかった感満載だったのが本線での反省点だった。 gfx は xslate まわりのチューニングとか markdown 周りとか starman/starlet あたりしてたのだけは把握してる。

二人とも「想像するな、計測しろ」を自で生きて来た人間だから、僕はそういうのとくにしないでコード見て常識的な事を常識的にやってました。

最初のほうでザックリ作業終わってからベンチとりながら top してたら mysqld があり得ないくらい120%くらいCPU食ってるし io 全然幸ってないから、こりゃありえんって感じで SQL 頑張ってたな。ある程度回復するとようやく CPU が正常になってきて「これから本番」って感じがしてきてよかった。この辺りから --workload 2 とかが意味でてきたし。

どたばた的なの

インスタンス1個でやってたからベンチ回すのに、アナログな queue が発生してたりとか、開発環境ないがしろにしてて git の作業が各人バラバラでおかしくなってたので本戦でれたらどうにかしよう。

とちゅうのどうでもいいこと

あんま意味ないけど plack process に strace してベンチ回してたら js ファイルとかを app server が処理してたから kamipo さんに「なんで static file をバックエンドに飛ばしてるの!」っていったら、 nginx でそのファイル開けない!とか言い出しててよくよくきいたら /home/isucon が 0777 になってたせいで ssh login できないから 0700 にしてから open できなくなったとかだったので「それ 0711 でできるよ」って言って解決した。切羽詰まるとわりとありがちだなーっていう出来事でした!

おわってから

最後の1時間くらいは、割とデッカいリファクタリングしつつキャッシュしてスコア伸ばそうとしてたけど、なんかエラーでちゃったし焦る場所だったけど、焦ったらアウトだからゆるふわにやってて間に合いませんでした。
いちおう間に合わせようとして、酷いコードで実装始めてたら FAIL がでちゃってて kamipo さんがレビュー始めたけど、よく見るレビューしてる時の kamipo さんみたいになってて大変そうだったw

memcached じゃなくて mysql memcache plugin とか言われて、あわてて memcached のポート使うようにしてテストしてみたけど、特に計測値かわらなかった。 mysql すごい。

ログインした時に最終ログイン時刻を記録する為に UPDATE してるとこあるけど、見えない要件で必要かもしれないしパフォーマンスに大差ないと見込んでスルーした。
もう kamipo さんの slow query プロファイルでも SQL で問題全部潰し終わったの確認してたし。

まとめ

他のチームは、バリバリキャッシュ頑張ったりアプリケーションのメモリの中に全部入れてたりミドルウェア追加したりとか頑張ってたらしいけど、割と最初の構成から殆ど変えないで、普通の仕事のノリで実直に軽いノリでやってても11位くらいの順位になったのは割と満足いく感じだと思います。

言葉では語られない fujiwara さんの苦労が色々と見える題材でほんと fujiwara さん凄いとおもいますが、本戦はもっとがんばってください^^

Posted by Yappo at 02:03 | Comments (0) | TrackBack

2013年06月07日

馬鹿でもわかる Application Server と Reverse Proxy Balancer のお付き合いを考える

一般的な Web Application というのはロードバランサ、Webサーバ、アプリケーションサーバという HTTP を喋るサーバで構成されていると思います。
ロードバランサは高級なハードウェアからソフトウェア(lvs, httpd, etc..)で作るものまで色々ありますね。
アプリケーションサーバでは各種言語に合わせた実装でデーモンが常駐してるでしょう。これはいわゆる普通の Web サーバよりは単純なコンテンツを返す性能が低いです。

そんなわけで動的なアプリケーションサーバが有る構成では js や css や画像など静的なファイルは Apache や nginx などの専用の Web サーバでサービスして、動的なリクエストだけバックエンドのアプリケーションを返す構成を取ります。
構成としては

構成A
  +---------------+
  | reverse proxy |
  +---------------+
          /\
         /  \
        /    \
       /      \
+--------+  +---------+ 
| static |  | dynamyc |
+--------+  +---------+ 
とか
構成B
+------------------------------------+
| static contents with reverse proxy | (Web Server)
+------------------------------------+
                  |
         +------------------+ 
         | dynamyc contents | (application server)
         +------------------+ 
のような二通りの構成が取れると思いますが、このエントリでは後者のシンプルな方で話を進めます。
そしてアプリケーションの種類によっては Web サーバとアプリケーションサーバを一つのインスタンスに同居させる事もあるでしょう。

そして冗長性を考えると、それぞれのパーツが1台づつで運用されてるとかマジありえないので普通のサービスの最小セットは以下のようになります。

構成C
+----------+ +----------+
| balancer | | balancer |
+----------+ +----------+
     |     \  /   |
     |      \/    |
     |      /\    |
     |     /  \   |
+----------+ +----------+
|   web    | |    web   | (Web サーバ)
|    |     | |     |    |
|   app    | |    app   | (アプリケーションサーバ)
+----------+ +----------+

app が落ちたらアウト

上の構成の場合だと app が落ちたら前段の web が 502 を返してしまって、折角 balancer が良い感じにバランシングしてくれてるのに可用性が下がってしまいます。

注意深く balancer をセットアップしていれば、 app のダウンを検知して故障のある app を抱えてる web をはずす事は出来ますが, 検知に時間はかかるし構成にかかる設定が複雑になります。

特にアプリケーションサーバの再起動を伴う作業の時に一瞬止まったりする可能性のあるアプリケーションサーバを使った場合には、再起動のたびに 502 を連発してしまってダウンタイム多発になります。
(この問題は近代的な環境である Unicorn や Server::Sterter などを使う事によりホットデプロイで対応可能になっています。)

app が落ちても平気にする

この問題を解決する手段としては web と app の間で更で以下のようにしてバランシングしてあげるという事です。

構成D
+----------+ +----------+
| balancer | | balancer |
+----------+ +----------+
     |     \  /   |
     |      \/    |
     |      /\    |
     |     /  \   |
+-----------+ +-------------+
|   web (A) | |    web (B)  | (Web サーバ)
+-----------+ +-------------+
     |     \  /   |
     |      \/    |
     |      /\    |
     |     /  \   |
+-----------+ +-------------+
|   app (A) | |    app (B)  | (アプリケーションサーバ) 
+-----------+ +-------------+

# web (A) と app (A) ならびに web (B) と app (B) はそれぞれ同一インスタンス
web サーバが Apache だったり nginx だったりする時は、良い感じにバランシングしながら後ろの web サーバに reverse proxy する方法があるので捗ります。

ただしこの手法でもバランシングの設定が必要になるので、サーバクラスタに web(C) app(C) を追加して balancer で web(C) を追加して満足して httpd.conf などに app(C) を追加し忘れて分散してるつもりが負荷が偏る悲しい問題も発生し得ます。

httpd.conf にちゃんと追加さえすれば、同じサービスの全部の設定は一度書けばかってにバラまかれて良い感じに再起動されるので balancer 側で頑張るよりはだいぶ柔軟な運用ができるがそれは後ほど。

特殊な環境の場合

たとえば JSON API しかサービスしないよ!っていうケースの場合は静的コンテンツをサービスする為の Web サーバが実質不要になるため balancer と app だけの以下の構成を取るかもしれません。

構成E
+----------+ +----------+
| balancer | | balancer |
+----------+ +----------+
     |     \  /   |
     |      \/    |
     |      /\    |
     |     /  \   |
+-----------+ +-------------+
|   app (A) | |    app (B)  | (アプリケーションサーバ) 
+-----------+ +-------------+

# web (A) と app (A) ならびに web (B) と app (B) はそれぞれ同一インスタンス
これの構成だと致命的な問題としてアプリケーションサーバの根っこの設定を変えたいとかで、ホットデプロイ不可能な再起動したい時に balancer 側を相殺してバランシングからはずさないといけないときに面倒いのです。最初から考慮した運用してれば大丈夫なのかもですが。

まとめ

むりやりまとめると構成Dがいちばん安定するという結論に今なってます。

メリットとしては

  • balancer が特殊なハードやソフトウェアで構成されてる時でも、ゆるふわな人がある程度柔軟な運用が出来る
  • ゆるふわな人がアプリケーションサーバのメンテを気楽にできる
  • アプリケーションサーバが死んでも問題起きないので可用性あがる
  • 古き良きアプリケーションサーバ使ってるときの deploy がある程度ゆるふわに出来る
デメリットとしては
  • static contents が無い場合に、一個余分なサーバを挟む事になるのでパフォーマンスが下がる
  • うっかり web サーバ側のバランシング設定書き忘れて悲しくなる
な感じだとおもいます。

ぼくみたいなしろうとが書いてると机飛んで来そうでこわいけどがんばってかきました><

Posted by Yappo at 19:34 | Comments (0) | TrackBack

2012年04月10日

今話題の新言語 Tora を、今話題の さくらVPS で使う方法教えます

2012/04/01 にリリースされた Tora が話題沸騰中なのは記憶に新しいですが、これまた今話題の さくらVPS 2GB プランでインストールする方法をまとめたのでメモしておきます( [f6fa28f2bb6f6fb301c31fee69d2fea0041eaab4] 現在)。

必要なパッケージを入れる

Tora が使ってるライブラリを入れます。

sudo yum install scons
sudo yum install re2c
sudo yum install curl-devel
sudo yum install libicu-devel

libicu-devel は Tora が icu を使っていて icu-config を使うので必要で、 curl-devel は標準添付ライブラリが使ってるので必須です。

ビルドしてテストしてインストールする

git clone git://github.com/tokuhirom/tora.git
cd tora
git submodule init
git submodule update
scons
scons test
sudo scons install

test するには Perl の Test::Harness 等を別途インストールしなければならない所ですが、これらのモジュールが Tora に標準添付されているのでインストールしておく必要はありません。

使ってみる

$ tora
>> say('hello walludo!')
hello walludo!
undef
>> undef

ちゃんとインストールできましたね!

まとめ

新しい言語 Tora をさくらVPSで使う100%提灯記事を書きました。

プログラミング言語を作る
前橋 和弥
技術評論社
売り上げランキング: 16501
Posted by Yappo at 15:34 | Comments (0) | TrackBack

2012年04月02日

Web関連エンジニアなら必ず読むべき本 〜 Webエンジニアのためのデータベース技術[実践]入門 〜 を全部読んだ

2709円でこんなに濃厚なコストパフォーマンスがアホみたいに高い本は読んだ事無いし、Web関連のエンジニアをやっている人は必ず読んだ方が良いし、特にどのレイヤをやるかに関わらずエンジニアを目指す学生さんも卒業までには読んでおいたほうが良い本でした。

なんか誤解が多そうなんで追記しておくと、本書は「カジュアルなデータベース*利用者*のための入門本」ではなくて「本質的なデータベース技術の知見を得る為の入門本」である。ちゃんとタイトルだってデータベース技術って書いてあるでしょ?

明日着でWDP献本先と同住所に送付さ せていただきます。ご一読いただき、コメントなどいただけると大変ありがたい です。 明日発売なので念のためご連絡させていただきました。
というメールを3月8日に頂いて、実物が届いたのが翌日だったのですがチビチビ読んでてやっとさっき全部読み終わって、こんな出遅れたエントリになったよ!

ページが後ろになるにつれて、より実践的な話題になるのですが第一章で「学生の時はデータベース技術の必要性が身体で理解出来ていなかったうんうん」のような事を書いてある通り、最初はデータベースが必要な理由をわかりやすく解説し、DBにつきもののインデックスの必要性やアルゴリズム等の解説、RDBにつきものの正規化の話題も出るけど現実的な落としどころの考え方も一緒に書いているので、これを読んだ学生が正規化厨になるのに歯止めをかけている。
その後、SQLの基本的な使い方を解説をし、レプリケーションの使い方や、 DROP TABLE とか間違えて打ち込んだ時の為の予防策、トランザクションが必要とされる理由、無いとどうなるかと言った話題で導入部は終わります。

後半からはハードウェアの視点から見たデータベースのパフォーマンスに付いて、HDD/SSD/Fusion-IOなどの製品でのパフォーマンス比較「単純にSSDにしたからといって Insert 性能があがらない、ではどうすればよいのか?」といった業務に直結するような知識も網羅されています。

後半は RDBMS だけでは無く NoSQL 製品への言及や産まれて来た背景、松信さんの経歴による MySQL ひいき等も無く、 NoSQL を選ぶ事でのメリットデメリットも言及してあります。全体的な論調としては流行りにただ流されるのではなく、正しく製品の特徴を理解し納得して選定しましょうと口を酸っぱく書いてありますけどねw僕も同意ですが。

終盤に行くにつれて松信さんが MySQL 社や Mobage で培った知見をフル動員した(ソーシャルゲームだとどうなる的なのも多い)、高トラフィックを捌く為のデータベース設計、ハードウェアに合わせたチューニング、運用、トラブルシューティングといった話題がてんこもりです。

僕個人的な見所は、 MySQL hack / debug に関する部分でしょうか。原因不明のトラブルを gdb を用いて順に沿って解説しているのですが、所々に松信さんがどういう思考で手段を選んだのかという解説があるので、ただ単純な gdb デバッグの解説とくらべて万倍参考になります。まるで松信さんとマンツーマンで gdb デバッグ & パッチの書き方講座を受けてる間隔になって、この部分だけでも3000円未満は安いくらいですね。

全体的にどのトピックに関しても「これはこうこうこういう背景(実装/アルゴリズム/IOの最大性能)があるので、こうする理由はこうである」のような形で、松信さんの考察が理路整然と中立的な視点で言及されているので、教科書的な本よりも数段上の知見が得られる事でしょう。

また、本の趣旨としても MySQL 本ではなく将来的にどんな新しい技術が出て来ても普遍的になるような考え方を持って貰えるように作られているので、将来新しい技術が出て来て困った時に、松信さんにカジュアルに相談するかのように本書を手に取れば迷いが解決しそうな気がしています。

まとめ

と言う事でダラダラと書きましたが、Web関連のエンジニアをやる人は必ず全部読んだほうがいいので皆買いましょう!Web関連企業は会社の金でかって5冊ずつオフィスに常備しましょう!
Facebook での知見を元にした松信先生の次回作にも期待してます!

Webエンジニアのための データベース技術[実践]入門 (Software Design plus)
松信 嘉範
技術評論社
売り上げランキング: 3297

追記

この本が id:kumonopanya が軽く数ページ読んだだけって言ってた本の現在の姿になります。


自分が読んで理解出来なかったからといって、そういうよく考えない決めつけはしちゃ駄目だよって松信先生が親切丁寧に書いているので(実際には、自分で正しく物事を見極めてエンジニアリングしろ的な事を随所に書いてます)、エンジニア or 開発する人間であるならば、この本を10回読んで感想を書く事 > id:kumonopanya
最初の頃は誤字脱字系をメモってたんだけど、だんだん面倒くなったw
あと DBD::mysql を DBD::MySQL って書いてあるとこも気持ち悪いからなおして!

Posted by Yappo at 17:11 | Comments (0) | TrackBack

2012年03月11日

InnoDB Deep Talk #1 に参加して来た話または 住所正規化 MySQL UDF を作った話

昨日は起きたら参加申し込みしてたはずの InnoDB Deep Talk #1 が始まってるらしいのに気づいて急いで行ってきました。入館面倒い会場なのに遅刻者対応したりピザとか飲み物調達とか面倒い事をニコニコやってるいちい++だったし、ピザーラのピザじゃなくてサルヴァトーレのピザはやっぱり上手くて沢山くってしまった。

っていう話は置いといて、一通り終わって歓談タイムに突入した時に、もりよしさんが昨夜思いついた inokodb っていう素晴らしいストレージエンジンを、その場で実装してて LT してたのを見て、勉強会に参加して意識が高まる症候群になったのですが、テンプレ的な意識の高まり方で終わってれば良いのに、なんか我慢出来なくなってその場で UDF でも作ろうと思って会場の wifi 探したのですが、電波見つからなくて断念しました。

家帰ってやろうとしたんだけど、僕の mac の brew install した mysql 5.5 だと -lcurl して作ったバイナリを cureate function すると落ちてしまって面倒くさくなって寝てしまって、起きて暫くして linux で環境作って作り始めたら存外簡単に出来てしまったとさ。

で、何を作ったかと言うと金曜日にライブドアって所がやってるロケタッチっていうシャレオツなサービスが住所正規化APIっていう素晴らしいAPIをリリースして下さったので、その API を使って MySQL だけで住所の正規化が出来たら、年賀状作成が捗りそうだったので作ってみました。

https://github.com/yappo/mysql-address_normalize
セットアップの仕方は

$ git clone git://github.com/yappo/mysql-address_normalize.git
$ cd mysql-address_normalize
$ g++ -lcurl -shared -fPIC -Wall -g mysql_address_normalize.cc -o mysql_address_normalize.so
$ sudo cp mysql_address_normalize.so /foo/bar/lib/mysql/plugin/
$ mysql -uroot
mysql> create function address_normalize returns string soname 'mysql_address_normalize.so';
という形でやれば動きます。 5.1.33 で開発しています。

使い方は死ぬ程簡単で普通に address_normalize 関数に返還前の住所を渡せば変換後の住所が帰ってきます。

mysql> SELECT address_normalize('道玄坂二丁目2');
+------------------------------------------+
| address_normalize('道玄坂二丁目2') |
+------------------------------------------+
| 東京都渋谷区道玄坂2-2           | 
+------------------------------------------+
1 row in set (0.09 sec)

既存の address カラムがあるテーブルに normalized_addres みたいなテーブルを増やした上で

UPDATE foo SET normalized_address = address_normalize(address);
のようにすれば、全レコードの住所を元に正規化されたカラムを作成する事が出来ます。

API レベルで正規化処理が出来なかった場合には元々のクエリのアドレスが帰ってきますが、 MySQL レベルのエラー、 HTTP 処理でのエラー、 JSON がなんかおかしかったりする場合には全て NULL を返します。

picojson と libcurl を使えば簡単に作れるとは思ってたのですが、 mac で作ろうとしてハマったのと C++ 力が低くて json parse 後のデータをどうやって取ればいいかって所で少しハマったけどこれみてすぐ解決した。

JSON API 叩く MySQL UDF とかだいぶ書くの楽でビックリしたという休日でした。

Posted by Yappo at 17:54 | Comments (0) | TrackBack

2012年02月07日

「livedoor × DeNA 勉強会」 #LDeNA #1 開催してもらった & 発表資料

先々週にやってたのに書くのをすっかりわすれてた^^;;

livedoor Techブログ : 「livedoor × DeNA 勉強会」 #LDeNA を開催しましたの通り最後なので合同勉強会を開いてもらいました。

IRC で nekokak さんと「やる?やるならマジで専門家にお願いするよ?!!?」とか言ってて、合同勉強会やるかやらぬか見たいな話が出始めて50分もしないうちに kushii++ さんが色々と本格的に動いてくれて、すごい勢いで懇談会までの手配が整って感動の雨霰でした。
このフットワークは凄いです。

僕の発表としては、前回の yokohama.pm の続きの話と YAPC の LT で話せなかった事をやったんですが、 Twitter Streaming API と GrowthForecast を組み合わせて他社サービスと自社サービスを観測するという新しい話を話してるうちに、本題が出来なかったのが心残りです。

http://yappo.github.com/talks/20120127-ldena-folkatdevs2/

やりきれなかった所は、統合後の法人が許すのであればどこかでやりたいですね。

他の人の発表も、誰が何言ったか感想書きたいけどかけなくて残念だわー


何はともあれ関係者の皆様お疲れさまでした。

Posted by Yappo at 19:31 | Comments (0) | TrackBack

2011年12月01日

GrowthForecast ノススメ

みなさん管理画面毎にグラフ作ってませんか?作るのめんどくさくて数値の表だけだして、直感的にサービスの動向掴みにくいとおもっていませんか?
Google スプレッドシートの機能でグラフだせるからいいよ?とかいってませんか?
Google スプレッドシートに吐かせる方法より簡単にグラフが作れたらいいとおもいませんか?

遂に
GrowthForecastというグラフ表示ツールで捗る話 - blog.nomadscafe.jp
リリースされたので、早速僕が GrowthForecast をどんな感じで紹介しようと思いますが、なんか忙しいので便利ツールだけ紹介します。

https://github.com/yappo/grouthforecast-worker

こういうツールを使っているので、グラフ追加したい時にいちいちある程度のボリュームのあるコードとか書かなくても

#!/bin/sh
echo "SELECT COUNT(*) FROM user;" | mysql -N -uroot ninjyatoriai

みたいな一行スクリプトをどんどん追加して行くだけで簡単にグラフが増やせて嬉しいです。

作ってもらった動機

昔の会社は、集計する SQL をちょろっと社内 IRC に張るだけで、自動的にサービスの動向が解る奇麗なグラフが出来ていたんですが、転職したらそういう便利な感じじゃなくて癇癪起こして徹夜でコードを書いたのでした。

世の中にはグラフを作るツールは数多いですが、ちょっと使うのに準備が必要だったりするので すが、 GrowthForecast を入れとくと Web API を叩くだけで良い感じにグラフを作ってくれるので、一度設置すると HTTP しか喋れない環境の人でも簡単に継続的なグラフが作れるので便利です。
この変の思想は Ikachan と同じ物ですね。


元々こういう類いの UI とかメンテとか面倒だし RRDTool とか使いこなすの面倒そうだったので、最初からメンテナンスを kazeburo さんに押し付けるつもりで CloudForecast の薄いラッパーとして ClothForest ってのを作ってたのですが、最初に kazeburo さんに見せた時にやる気だして貰う事ができて、めでたくフルスクラッチで書いてもらう事が出来たのでした。

おすすめの使い方

おススメは、普通にグラフを取りたい数値の総量をグラフして行けば良いです。
差分リストとかを出しとくと、ピーク時間帯が山の頂上になる感じのよくある感じのグラフを出しつつ右肩上がりのグラフとか書けますね。

その他、24時間以内にユーザが増えた数とかのグラフを書くと新規登録のトレンドとか肌身に感じる事が出来ます。

あとは、スマホの何か、携帯の何か、PCの何かの数値をそれぞれ別けて取った上で積み上げグラフを作って合体させると、別の面のトレンドが知れていいですね。

ということで kazeburo++ 先生の新作はインフラエンジニアじゃないアプリケーションエンジニアも便利でディレクターも捗る良いツールのなので是非導入しましょう!

新しい物入れるのが面倒なあなたも、最後に頑張って導入してみたら想像以上に未来に生きれるようになる事が実感出来るので是非使いましょう!

Posted by Yappo at 21:44 | Comments (0) | TrackBack

2011年05月13日

BPStudy#39 で Ficia の UI とテストに関する事を発表してきました

本当に今更で申し訳ないのですが、さる2010年11月30日にBPStudyで発表する機会を頂いて、FiciaのサクサクなUIをどうやって作っているのか?というプレゼンとFiciaで利用しているテストツールのJSTAPdについてのプレゼンの二本を行って来ました。

ベースは、Web+DBの連載の内容になっていて、YAPCやFukuoka.PMでの発表内容に近しい形とはなっていますが、発表する場所も違うので少しだけ構成を変えて発表するというtrue TAKESAKO methodをしました。

発表資料はイカよりそれぞれどうぞ。
http://yappo.github.com/talks/20101130-bpstudy-webui/
http://yappo.github.com/talks/20101130-bpstudy-jstapd/

発表機会を与えて下さった @monjudoh さん、 @haru860 さん有り難うございました。そして馬鹿みたいに発表資料公開遅くなって申し訳ありませんでした。

Posted by Yappo at 02:41 | Comments (0) | TrackBack

2011年04月08日

OSDC.tw 2011 で Groonga 布教してきました/もしくは TOEIC スコア 100 未満の日本人が国外カンファレンスで英語プレゼンする方法

エントリだけ書いててすっかりpostするのを忘れてたんですが、猿先々週にSPM48の中から数名のメンバーを集めたチーム台北2011選抜メンバーがosdc.tw 2011で発表してくるイベントがあったのですが、僕はそこで Groonga の布教をしつつ日本での検索ソフトウエアについての発表をしてきました。
チーム台北2010選抜の時にいったosdc.tw 2010では、日本語でプレゼンして来たんですが今度は英語でしてきました。

すったもんだがございまして、資料の英訳が全く間に合わなくて @__gfx__, @charsbar, @obra のお三方に英訳を助けて頂きました、本当に助かりました!

実際のトークとかは、keynoteの機能を使ってメインディスプレイに台本が出るようにしてたので乗り切れた感じだったけど、ちょくちょく発音のしかたわからない単語とか出てきょどったかんじ。
keynote自体も使い出したのが前日とかだからもうわけわかんなかった><

自分の発表の直前でclkao会場を満席にしていた影響か自分の出番でも残ってる人が多くて「やばいなー」とか思ったんだけど、前日に頂いた「あなたにコンパイルされたいって丸投げすればいいよ」って有り難いお言葉を思い出しながら、話はじめたら実際はどうってことなかった。

英訳のスライドのお陰で、僕が言いたかった事は少しでも伝わったかなーという感触はありました。
質問も3,4個いただいたのですが何せヒアリング全然できなくて質問に答えられなかったのですが、ふと思いついて質問してる人のとこまでPCもってって「たいぷぷりーず!」ってお願いしてexcite先生のtextareaに入力してもらって質問内容を理解しました!(typingしてもらったら翻訳するほどの事じゃなかったけど)。
スピーカーがおもむろに質問者に駆け寄って、文字で質問しろとか言い出したので会場では受けてた。

板抱いた質問は大まかに

Q.1TBとかのデータでも動くのか?
A.indexを分割して複数台のマシンに配布してsearcherを上手く作ればok
Q.どの程度のサイズに分割するの?
A.100GBくらいが限界かなっと
Q.groonga storage engineとか簡単につかえるの?
A.ちょうかんたん!
Q.mysqlでのクエリってどうなるの?
A.mysqlに本来ある構文をhookしてるからmysqlのドキュメント見てね
Q.groonga mysqlはどうやって俺のFreeBSDいれるの!!1ドキュメントとか無さそうだよ!!
A.あー書いてないね、基本的に彼らが必要としてる事しか実装しないからねー
Q.まじで英語のドキュメントないの!11
A.ないの、、日本帰ったらいっとくごめん

とかそういう感じで、やっぱりMySQLに組み込みに凄い興味もたれてたようでした。

英語力なくても、勢いだけでプレゼンの内容に興味もってもらえるもんですね!もちろん翻訳の内容が良かったのは言う迄もありませんが!
という事で国土が終わりそうな日本にとどまるだけじゃなくて、日本で面白い事やってるみなさんも積極的に国外でプレゼンしてくるといいですよ!
とても簡単ですから本当に!

そうそうまだ本の紹介してませんが、moritapoさんから献本頂いた検索本超いいよ!って台湾で宣伝してきました。
本の紹介と、発表以外の話はまた後ほど。

Posted by Yappo at 14:39 | Comments (0) | TrackBack

2011年02月25日

Web+DB PRESS 連載おわりました!

いっつもotsuneさんに、記事書いたエントリみて本屋に行くといつも発売前ってゆわれるので、発売されてからエントリ公開しようと思ってたら、発売日すぎてしいました。

最終回は「HTML5と専用クライアント」というお題目で、#!を使うんじゃなくてHTML5のpushState/popstate回りを使ってpermalinkを作る方法と、専用クライアントを用意すれば良い事あるよっていう話をして締めくくりました。

Perl関連の連載をやると見せかけて「モダンWebインターフェィス構築術」とかいうタイトルで連載したわけですが、当初の予定通りの内容を書き終えて無事連載終了となりました。
当初は、読み物を軽く書くつもりだったのですがいつの間にか実装よりの話ばっかりになっていたという。
言語とか、対象となるレイヤとかも特に限定してなかったので、それなりに広い範囲のネタを取り扱えたかなと思います。こういった記事だと大抵JavaScript&Rubyとか何でしょうけど、そのへんは趣味という事で。

連載でやるなら4ページ分くらいづつ書くのがちょうど良いかなとか思っていたのですが、なんどもページをオーバーしていたりとかすったもんだありました。

そうそう、書き忘れたから追記だけど、この連載の主なターゲットは割とWeb系バリバリやってる感じの人じゃない所にターゲットを向けた感じで題材えらびやら何やらしていたわけですが、そのお陰でぼくの半径1mくらいの人達の興味持てるネタとかあまりやってないせいで、あんまり記事への意見とか見る機会が無くて暗闇の中を歩いている感じではありました。だいぶ考えて暗闇に道を作ってたつもりだったけど、みなさまいかがでしたでしょうか!
だいぶ明確なターゲット設定と、それによってどうなって欲しいかという目標とか、最初っからそういった設定はしていたのですが、それについてはどっかで機会があれば明かしたいなと思うところ。

連載が終わってからなんとも達成感が凄いわけですが、Perlのバトン連載のほうで書く機会があったら、またよろしくおねがいします。

WEB+DB PRESS Vol.61 - 4774145440

WEB+DB PRESS Vol.61


技術評論社 (2011-02-24)
rating:  - WEB+DB PRESS Vol.61
price: ¥ 1,554 at 2011.02.25

連載の裏話的なネタは、後日どっかで取り上げられるかも。

まだHTML5の戦いは始まったばかりだ!

Posted by Yappo at 15:25 | Comments (0) | TrackBack

2011年02月14日

simpleTimeago.js - facebook っぽい "2 minutes ago" みたいな時刻表記を作るjs書いた

表題の通りの物を書きました。
https://github.com/yappo/javascript-simpleTimeago
デモはこちら http://yappo.github.com/projects/simpleTimeago/

同種の物として jquery.timeago.js とかあるんですが、そもそもjQuery pluginである必要がないし、時刻フォーマットの拡張の自由度が小さくて用途に合わないので作りました。

使い方はコードを見た方が手っ取り早いでしょう。

simpleTimeago(epoch_time);
ってだけです。
フォーマットの追加もとても簡単で、コードの下の方にサンプルてきに英語版と日本語版のフォーマットを書いてあります。
だいぶ好き勝手にフォーマット変えられるので、便利に使えるんじゃないかなーと思います。

Posted by Yappo at 15:56 | Comments (0) | TrackBack

jQuery Mobile 所感

しばらくjQuery Mobileを弄ってて思った事をメモ。まだまだあるふぁ何で色々変わるとおもうけど。

ドキュメントがすくないよママン

アルファリリースなんで仕様固まって無い部分もあるから放置され気味なんすかね。
素直に実装読んだ方が速い。

あるふぁ2からあるふぁ3にしたらへんになったよ

アルファリリースっていってんだろがカスが!

標準のCSSだけじゃiPhoneアプリっぽくならない

最初からついてるアイコンとかだけだと、良くあるiPhoneアプリの画面になりません。
Sencha Touchつかったほうがその辺充実してる。
テーマカスタマイズして頑張れって事ですかね。
正式リリースしたらテーマ作成ツールとかちゃんと出してくれるみたいだし、しばらく我慢の子。

heaer/footerの位置を固定にしてもなんか変

なんか頑張って実装してるんだけど、スクロールイベントとか使ってるせいでカクカクする。。。
いまのところjquery.mobile.iscroll.js 的なアプローチを使うと良い感じになる。

UIがなんか物足りないSenchaのが良くね?

足りなければ作りましょう。

jquerymobile.comのデモページ重いよ

あれのページ遷移ってajaxしてhtmlいちいち取って来てるからloadingが長いの。
htmlの中に必要な要素を入れとけば、それなりにサクサクするよ。

いまどきlocation.hashかよ

一応pushStateしてurl書き換えるような実装を書いてるみたい。
ただし、pushStateサポートしてるブラウザだと強制的にpushStateつかうロジックになってしまうので、ユーザが選択権もてるようなパッチ書いておくったら、あとで考えるリストに突っ込んでもらえた。

なんか勝手にDOM構造変わるんですけど。。。

そういう物だと思ってあきらめましょう。

動的にページ書き換えたらスタイルあたってなくて残念

だからといって、jQuery Mobileが書き換えるDOM構造をわざわざ手で作らなくても良いです。

var dom = $('<div data-role="page" id="page-test" data-url="page-test"><div data-role="header"><h1>header</h1></div></div>');
dom.page();
$("body").append(dom);
こういう感じでpageメソッドを呼べば良い感じにしてくれます。
ちなみにid="name"とdata-url="name"に同じ値で入れておかないと、そのページのDOMが存在してない扱いされるので注意。なんかこれバグな気がするけど。

ほかには、全く同じdom要素に.page()メソッドを連続で行えなくて、.removeData("page")ってやってwidgetのインスタンスを決してあげないといけない。


application cache with pushState とかの考察

location.hash 使ってナビゲーションするときには、何も考えないでhtml5 application cacheつかっちゃえますが、pushState使いながらキャッシュしたい時には色々考えないといかんです。
foo.manifest で書かれたリソースのキャッシュは、各ページで使い回し聞くんですが肝心のHTMLそのものは別々のURLなため、別個にキャッシュされてしまってメモリを圧迫するという。
なので各URLが返すHTMLはとても小さくしておいて、メインで使うコンテンツは動的に組み立てる若しくは別ファイルとして置いといて、ajaxとかでゲットして使うとかになるのかなと。
まだ、この変はもうちょっと調べないといけない。

簡単にキャッシュしたいならpushStateするなって話もあるかもだけど。。。

Posted by Yappo at 15:48 | Comments (0) | TrackBack

2011年02月09日

シェルの中からFacebookにポストするbash関数かいたよ

https://github.com/yappo/bash-facebook-status-updater/blob/master/facebook-status-updater.bash
これをどっかに置いといて

$ source facebook-status-updater.bash
$ facebook-status-updater
ってするとURLが出てくるので、それ開いて accept したら「Success」って画面でるので、その画面のURLから#access_token=から&までの間の文字列をACCESS_TOKENっていう環境変数に入れて
$ facebook-status-updater "とうこうしたいことば"
ってやるとシェルの中からふぇぃすぶくに投稿できるbashの関数書いた。

source ~/git/facebook-status-updater/facebook-status-updater.bash
alias facebook="ACCESS_TOKEN='とってきたACCESS_TOKENをここに' facebook-status-updater"
ってやって facebook こまんど作るのおすすめ。

Posted by Yappo at 22:15 | Comments (0) | TrackBack

2011年02月04日

jquery.mobile.useHistoryState.js その後

元々やりかたいかんなーとは思ってたんですが、jqm1.0a3出た時にpushstate branch見つけたので、そっちにパッチを送ってみる戦略にしてみた。

いまのブランチでちょっと挙動が怪しい部分にパッチあててpull reqったのと、今の実装だと pushState 使える端末だと問答無用で pushState してしまって、 html 一枚だけ配信して location.hash 使って管理したい人が泣くので、それを抑制するオプションを作ってpull reqった。
全然空気読んでないんでどうなるかわからないけど。。。

あとは、何でも感でもリンク先が pushState されて矢田なーとか思ってたけど。

          <ul class="ui-grid-b"> 
            <li class="ui-block-d"><a rel="external" href="/index">index</a></li>
            <li class="ui-block-d"><a href="/view">view</a></li>
            <li class="ui-block-d"><a href="/popular">popular</a></li>
            <li class="ui-block-d"><a href="/search">search</a></li>
          </ul>
みたく rel="external" 属性を突っ込めば良いのであった。

ちなみに jquery.mobile.useHistoryState.js は jquery mobile 1.0a3 出た時は動かなくなっちゃったけど、今はエキセントリックな対応したから動くす。
まぁコアでサポートされる迄の寿命だけどね!

ついき:pushstateのサポートをon/offする件は後で考えるリストに入れてもらった。
disableさえ出来るようになれば、好き勝手なプラグイン書けるから嬉しい。

Posted by Yappo at 22:38 | Comments (0) | TrackBack

2011年02月03日

jQuery Mobile の permalink を HTML5 使って location.hash じゃなくする jquery.mobile.useHistoryState.js を書いた

こん

jQuery Mobile使ってますか!1月にリリースされるって噂聞いてるんですがまだ頑張ってるみたいですね!

jQuery Mobile では <A href="#foo"> のようなリンクをクリックすると <div data-role="page" id="foo"> で囲まれた要素を表示して、 http://example.an/oreno/index#foo という URL がロケーションバーに入ります。

時としてPCと須磨補は同じURLを使いたいという要求もあるでしょう。そういった場合に jQuery Mobile で対応するには、それぞれの URI でページを生成してあげて href="/oreno/foo" とかにリンクさせれば、 jQuery Mobile が内部的に http://example.an/oreno/index#/oreno/foo の内容を Ajax で取ってきて画面を書き換えて、ロケーションバーの中身を http://example.an/oreno/index#/oreno/foo って書き換えてくれます。

今の所は location.hash を使ったページ遷移しか出来ないようなので、 SCRIPT タグでロードするだけで location.hash に頼らないパーマリンクになるようにする jQuery Mobile plugin を書きました。

https://github.com/yappo/javascript-jquery.mobile.useHistoryState
デモはこちら

やってる事としては hashchange イベントが発生したら location.hash の内容を元にして history.replaceState 使って現在の URL を書き換えます。
ブラウザの戻るボタンとか進むボタンでは popstate イベントが発生するので、 location.pathname を元にして $.mobile.changePage を使って、表示されるべきページを表示させます。

pushState popstate replaceState に対応してない Firefox 3.5系のブラウザとかでは、このプラグインは動かないようになってますので、必ずしも permalink が同じにならないんですが、基本的によく使われているスマフォでは webkit 系だから気にしなくてもいいかなーという。。。え、おぺら?

ろむ

追記: なんか jquery mobile 側でも実装仕様としてるみたいだけど、 jQuery のフォーラムに投下してみた http://forum.jquery.com/topic/i-made-pushstate-support-plugin-for-jquery-mobile

つづく

Posted by Yappo at 13:09 | Comments (0) | TrackBack

2011年01月27日

iPhone で position:fixed な UIToolBar を簡単に作る jquery.mobile.iscroll.js を作った

iPhoneのWebサイトを作っていて、良くあるアプリの上と下の position:fixed なメニューを実装しようとした時に、iScrollを使えばわりかし楽に実装出来ます。

jQuery mobile (1.0a2) を使ってると header/footer 要素に data-position="fixed" を書いておけばそれっぽい動きになるんですが、スクロールイベントを受け取るたびにレンダリングしなおす挙動なんで、とてもかっこ悪いです。

かといって iPhone とかでは position:fixed 使えないんで iScroll さんの出番となるわけです。

iScroll さんは header, contents, footer という配置にしてて contents さんを overflow:hidden して touchstart event を良い感じにして position:fixed っぽくしてるわけですね。

そんな事で jQuery mobile 使ってる時に iScroll を簡単に適用するラッパーを書きました。
https://github.com/yappo/jquery.mobile.iscroll

使い方はとても簡単で JavaScript のコードは一切要りません。
jQuery mobile のお作法の <div data-role="page" > してる要素に data-iscroll="enabel" を追加して、そのなかの <div data-role="content"> 直下に <div data-iscroll="scroller"> 要素を追加して、今まで data-role="content" の中に入れてた要素を data-iscroll="scroller" の中に入れるだけです。

詳細はデモページや以下のコードを参照下さい。

Posted by Yappo at 20:26 | Comments (0) | TrackBack

2011年01月24日

iPhone とかの フリックで操作するカルーセル UI を jQuery mobile で作ってる話 (jquery.mobile.carousel)

AppStoreとかで、アプリのキャプチャを複数表示したい時にカルーセルなインタフェース(これのAPIの名前わからん)にして画面の高さを節約する事をすると思うんですが、それをjQuery mobileで再現するプラグインを書いてみました。

全画面で画像をプレビューする用途で作ってあります。ポイントは、AppStoreの画面キャプチャ見るやつと同等の動きをするって所です。
画像サイズも画面サイズに合わせて自動的にリサイズして、良い感じに自動的に配置するという。
画面の恥じっこに引っ張ったときの跳ねっ返りも再現してあります。
ぼくAndroidもってないので、Androidな人に是非とも添削して欲しいです。それかAndroid端末下さい。

コードはいつも通りgithubに置いてあります。
https://github.com/yappo/javascript-jquery.mobile.carousel

使い方

カルーセル化したい画像の一覧を<UL><LI></LI></UL>のような感じで作って

$("UL").mobile_carousel();
の用にするだけで使えるようになります。

実際のサンプルはこっちにおいてみたのでiPhoneとかからお試しください。

付属のサンプルコードは以下の通り。

iPhoneのhome画面みたいなのを作りたいとかそういう要望が合った場合には、コードが煩雑にならないならjquery.mobile.carouselに取り込む。そうじゃなければ分離って方針にしようとおもいます。

Posted by Yappo at 17:24 | Comments (0) | TrackBack

2011年01月13日

Pikubo をだら見できる「Pikuboream」を設置してみた

昼、Twitterを見てたら、とある友達がInstagramのだら見サイトを作って公開しているのを発見しました。

ちょろっと見たら、 TwitterのAPIを使った「それのプロキシ経由的な」APIを使って構築しているみたいです。 以下がその解説。

で、友達が作ったInstaStreamではInstagramはでるけど、 Twitterで言う#pikuboがないのがちょっと物足りない気がしました。 そのようなものは、InstagramのAPIでも派生APIでもどうしても取れないみたいです。 そこで、Twitter Search APIから最新のPikuboの個別エントリーpermalinkを取得する方法を試してみた人がいました。 どうも「Twitterに投稿されたPikuboの写真」のみ!ならば、public_timeline的なものは (こぼしがあるかも知れませんが)取れる模様です。

てなわけで、そのコピペ結果からPikuboのタイムラインをだら見する (ただしそこに出てくる写真はTwitterに関連づけられたもののみ!) というサイトを作った人は何秒で改変したのかわからないけど2秒くらいでさくっと設置してみました。 名前は「Pikuboream」です。

Pikuboream - Pikubo photo stream

Pikuboの最新の写真がとにかくだらだら流れます。 よかったら見てみてください!

PCからひたすら閲覧しにくいPikuboなんで、評判が良ければ機能を追加していきたいと思います。 まぁPikuboさんから怒られたらやめますけど! ということでよろしく!

参考文献: パクリブログ管理人( @partnerzu )の開き直り (/togetter.com/li/88486)

Posted by Yappo at 17:10 | Comments (0) | TrackBack

2010年08月21日

ficia uploader for linux

@etolabo 【リクエスト】Linux版のアップローダも作ってください。 #ficia
5:02 AM Aug 18th Tweetie for Macから

nippondanji
Mikiya Okuno
と言われたので、ちょっとだけ作ってみました。

http://github.com/yappo/ficiauploader
perlの無い環境でも使えるので安心だと思います。

ディレクトリ監視して、usb刺したら自動uploadの部分は時間が足りなくてperlで実現してるけど。。。

参考文献: http://blog.yappo.jp/yappo/archives/000715.html


つかgallery2 protocolなライブラリ見つけて作りたかったんだけど。。。

Posted by Yappo at 20:25 | Comments (0) | TrackBack

2010年05月07日

そろそろWEB+DB PRESSについて一言いっておくか

こんにちは、最近 ここ1ヶ月間で映画館に4回行っているYappoです。

さて、ご報告が遅れましたが、先月発売されたWEB+DB PRESS Vol.56より「モダンWebインタフェース構築術」という題名で連載をさせて頂く事になりました。過去に違うジャンルの雑誌で連載していた事があったのですが、技術誌での連載は初めてなので胸がバクバクしています。

内容はというと、今風のWebアプリを作る時に知っておきたい事やらFiciaを実装していく事で得られた知見等を紹介していく方向性になっています。

おもにクライアント側の実装に焦点があたり、JavaScript+Ajaxな感じの連載になるんじゃないかという話もありますが、そこはまぁ特定の言語にフォーカスした感じにはならないかなと、実装例は出るけど本質的には「こういうのが困って、こういう解決方法を取った」という物をベースにした形の設計よりの話題かなーという所です。

第一回は、今時は型にはまったMVCなんか役に立たないよ!こうした方が良いよ!といったお話。第二回はスケールするWebアプリって言うけど、そのスケールってサーバサイドだけの物?的な方向で今書いてます><

なんにせよ@inaoさん、良き友人等のお陰でどうにか新連載にこぎ着けました。今後の展開にどうぞご期待下さいです。

WEB+DB PRESS Vol.56 - 4774142107

WEB+DB PRESS Vol.56

WEB+DB PRESS編集部
技術評論社 (2010-04-24)
rating:  - WEB+DB PRESS Vol.56
price: ¥ 1,554
posted with Amazoon mini icon at 2010.05.07

もう一つの連載

さて、実は今回のWEB+DBの連載リフレッシュでもう一つ僕が関与した物があるので、むしろ言い出しっぺの張本人から意図を行っといた方が良いかなーと思ってついでに書いときます。

それは何かというと「Perl Hackers Hub」です。

まぁ色々とやり取りがあってPerlの連載を書くのか他の適役を捜すのか悩んでいた時期があったのですが、丁度その時って空前のperl advent calenderブームだったのも有るんですが、実は2008年のadvent calenderやった時から「雑誌のPerl連載でリレー形式とかでやったら面白そう」という思いはふつふつあったんですよね。それなんで2009年のadvend calenderの時期と次のPerl連載の話の時期が重なって「じゃぁ次のWEB+DB PRESSのPerl連載はバトン形式にしよう」と思ったわけですね。

もちろん、何となくバトン形式が良い!って言うのではなく次のような利点が有るんじゃないかと思うのですよ。

  • それぞれの筆者が得意な分野を題材する事により、連載の全体を通して深く広い題材を扱える(一人で書くとどうしても得意分野以外が薄くなりがち。例えばXSの話題なんかはXSに精通した人が書くと深い物になるし、Win32に詳しい人が書くWin32の回の方が深みがあるでしょう)
  • 一人一回の制約なので、無駄に助長にならず次回に言い訳を持ち込めないのでクオリティが上がる
  • 後の回の人程よりクオリティを上げるプレッシャーがかかって良い刺激に
  • etc...(すぐに思い当たらなかった^^;)
まぁ、このあたりの事はadvent calenderをウオッチしてた方や参加者には肌で感じ取れるかと思います。

欠点としては、各回の著者の記事にバラツキがおきやすいという事があるのですが、その辺りは全てJPA代表理事のlestrratさんに監修をお願いしました。
そのほか企画が通る前からlestrratさんtypesterさんyusukebeさんに諸々意見頂戴したりとお世話になりました。
他にも企画が立ち上がる前から、もろもろ色々な人に感触を聞いてみたら高感触だったので、(以下省略ワッフル)

僕の想定していた事に比べて連載第一回目のmiyagawaさんは本当に突発だったんですが、WEB+DB PRESSのPerl連載を最初に引っ張ったmiyagawaさん、幅広い話題やアルゴリズムの考え方まで題材にしたnaoyaさんへバトンタッチして、そしてまたmiyagawaさんがバトンを受け取り、日本全国のPerl関連の事に貢献しようとJPAを立ち上げたlestrratさんへバトンタッチして日本屈指のPerl使い達へとバトンをリレーして行くなんて、なんかドラマ性あってカッコいいですよね。というか、僕自身がこういう連載を読んでみたかっただけなんですが!

という事で次回はtypesterさんです。次々回はいったい誰になるんでしょうか!?「Perl Hackers Hub」も要注目です。

Posted by Yappo at 19:05 | Comments (0) | TrackBack

2010年03月18日

特定のフォルダ以下の全画像ファイルを.jpgに変換するsave2jpg作ったよ

Ficiaは写真/動画ストレージという事で現在対応している画像形式が.jpgだけなんですが、やっぱり「いっぱいのpngファイルをあげたい」という需要もあるわけで、なんかそういう需要も微妙に急襲する為にsave2jpgっての作ってみました。mac用です。多分snow leopardでしか動きません。perlとかそういうの使ってないので誰でも使えると思います。

つかいかたはREADME.txtに書いてあって

つかいかた

 1. save2jpg を適当な所に置きます
 2. 画像がいっぱい入ってるフォルダを save2jpg にドラッグ&ドロップします
 3. さっきドラッグ&ドロップしたフォルダの中に save2jpg ってディレクトリが出来てます
   というか、変換成功したら勝手に save2jpg フォルダを開きます

ちゅうい

 ドラッグ&ドロップしたフォルダの中に入ってるフォルダ全部から画像を探します。

 自動的に変換する画像は .jpg ファイル以外全てです。

 元の画像は変更しないので安心してね。変換した画像は全部 save2jpg に入ってるよ。
って感じです。

ユースケースとしては、どっかのフォルダの画像をまとめてficiaにあげられる形式に変換して、その変換した画像をFicia.appのフォルダ丸ごとアップロードでアップロードするような時に使うのを想定してます。
それ以外のユースケースだったらもっと良いツールは一杯あるでしょう。

なんてったてオリジナルの.pngファイルをうpれるわけじゃないので満足のいく物でもないでしょうが、save2jpgで出来る程度でよい方には便利なんじゃないでしょうか。

Posted by Yappo at 18:46 | Comments (0) | TrackBack

2010年03月09日

トランザクションを使用したMySQLのおまとめINSERTはどれくらい速いか

元ネタはMySQL のおまとめINSERTはどれくらい速いか - bonar noteです。

トランザクションでまとめてInsertしてからcommitしたほうが速くなるので、元ネタのベンチマークをベースにして試してみました。

環境は macports で入れた mysql 5.1.44 です。

まぁnormalからbulk(100)くらいの差は出てなくても、トランザクション使ってまとめてコミットしても多少速くなっとりますね。
normal と txn の差よりも bulk(100) と bulk(100)_txn の差が小さいのは、 bulk insert で最初から効率的になってるぶん差が少なくなってるという感じでしょうか。

コードは以下の通り。

Posted by Yappo at 12:35 | Comments (0) | TrackBack

2009年11月11日

Go lang (golang) に Acme::Oppai を移植してみた

取りあえずどんな感じでライブラリ書けるか見る為に Acme::Oppai を移植してみた訳です。
メソッドチェインしてAAが腕を上下してる感じは出来ました。
Go言語は組み込みでライブラリ書く仕組みが一通り整備されてる感じぽいすねContributing to the Go projectにテストの書き方まで書いてあった。
acme/oppai も一応テスト書いてあります。
普通に make && make test && make install してインストール出来るので、あとは貴方のコードからおっぱいおっぱい言うAAを取り扱う事が出来ます。

コードは http://github.com/yappo/Go-acme-oppai
これを使ったコードは以下の通りです。

メソッドチェインの終わりを知る方法がいまいちわからなくてDoneメソッドを呼ぶようにしてあります。
Perlだと""でoverloadさせて、オブジェクトが文字列評価された時に一気にAAを返したり出来たんですけどね。
あと、あんまドキュメント読んでないんですが大文字で始まるメソッドじゃないとpublic methodにならない?

とりあえずgistのGo対応はまだか?

Posted by Yappo at 21:21 | Comments (0) | TrackBack

2009年06月30日

MyISAM/InnoDB で primary key/index/uniqu な複合カラムなインデックス貼って SELECT COUNT(*) FROM table WHERE column = x したベンチマーク

とってみた物の、どれも速度変わらんっぽいなぁ。計りかたわるいかなぁ。

結果は下記の通り
先頭の文字が l = InnoDB, h = MyISAM, 二番目の数字や、最後の文字の意味はベンチスクリプト見てくださいなり。

一応適すとでもこぴえp

[~/perl]$ perl ./sql-count-benchmark.pl
^[[C        Rate l4_i l3_i h2_n l3_n l2_i l4_n h3_n h4_n h1_i l1_n h3_i l1_i h4_i h1_n l2_n h2_i
l4_i 10638/s   --  -3%  -5%  -6%  -7% -10% -10% -11% -12% -13% -14% -14% -16% -17% -18% -18%
l3_i 10989/s   3%   --  -2%  -3%  -4%  -7%  -7%  -8%  -9% -10% -11% -11% -13% -14% -15% -15%
h2_n 11236/s   6%   2%   --  -1%  -2%  -4%  -4%  -6%  -7%  -8%  -9%  -9% -11% -12% -13% -13%
l3_n 11364/s   7%   3%   1%   --  -1%  -3%  -3%  -5%  -6%  -7%  -8%  -8% -10% -11% -12% -12%
l2_i 11494/s   8%   5%   2%   1%   --  -2%  -2%  -3%  -5%  -6%  -7%  -7%  -9% -10% -11% -11%
l4_n 11765/s  11%   7%   5%   4%   2%   --  -0%  -1%  -2%  -4%  -5%  -5%  -7%  -8%  -9%  -9%
h3_n 11765/s  11%   7%   5%   4%   2%   0%   --  -1%  -2%  -4%  -5%  -5%  -7%  -8%  -9%  -9%
h4_n 11905/s  12%   8%   6%   5%   4%   1%   1%   --  -1%  -2%  -4%  -4%  -6%  -7%  -8%  -8%
h1_i 12048/s  13%  10%   7%   6%   5%   2%   2%   1%   --  -1%  -2%  -2%  -5%  -6%  -7%  -7%
l1_n 12195/s  15%  11%   9%   7%   6%   4%   4%   2%   1%   --  -1%  -1%  -4%  -5%  -6%  -6%
h3_i 12346/s  16%  12%  10%   9%   7%   5%   5%   4%   2%   1%   --   0%  -2%  -4%  -5%  -5%
l1_i 12346/s  16%  12%  10%   9%   7%   5%   5%   4%   2%   1%   0%   --  -2%  -4%  -5%  -5%
h4_i 12658/s  19%  15%  13%  11%  10%   8%   8%   6%   5%   4%   3%   3%   --  -1%  -3%  -3%
h1_n 12821/s  21%  17%  14%  13%  12%   9%   9%   8%   6%   5%   4%   4%   1%   --  -1%  -1%
l2_n 12987/s  22%  18%  16%  14%  13%  10%  10%   9%   8%   6%   5%   5%   3%   1%   --  -0%
h2_i 12987/s  22%  18%  16%  14%  13%  10%  10%   9%   8%   6%   5%   5%   3%   1%   0%   --
[~/perl]$ perl ./sql-count-benchmark.pl
        Rate l3_i l4_n l3_n h4_n l4_i h4_i l2_n l2_i h2_n h2_i h1_i h3_i h3_n l1_i h1_n l1_n
l3_i 10753/s   --  -1%  -3%  -3%  -6%  -9% -10% -11% -11% -11% -11% -13% -14% -15% -16% -18%
l4_n 10870/s   1%   --  -2%  -2%  -5%  -8%  -9% -10% -10% -10% -10% -12% -13% -14% -15% -17%
l3_n 11111/s   3%   2%   --  -0%  -3%  -6%  -7%  -8%  -8%  -8%  -8% -10% -11% -12% -13% -16%
h4_n 11111/s   3%   2%   0%   --  -3%  -6%  -7%  -8%  -8%  -8%  -8% -10% -11% -12% -13% -16%
l4_i 11494/s   7%   6%   3%   3%   --  -2%  -3%  -5%  -5%  -5%  -5%  -7%  -8%  -9% -10% -13%
h4_i 11765/s   9%   8%   6%   6%   2%   --  -1%  -2%  -2%  -2%  -2%  -5%  -6%  -7%  -8% -11%
l2_n 11905/s  11%  10%   7%   7%   4%   1%   --  -1%  -1%  -1%  -1%  -4%  -5%  -6%  -7% -10%
l2_i 12048/s  12%  11%   8%   8%   5%   2%   1%   --   0%  -0%  -0%  -2%  -4%  -5%  -6%  -8%
h2_n 12048/s  12%  11%   8%   8%   5%   2%   1%   0%   --  -0%  -0%  -2%  -4%  -5%  -6%  -8%
h2_i 12048/s  12%  11%   8%   8%   5%   2%   1%   0%   0%   --   0%  -2%  -4%  -5%  -6%  -8%
h1_i 12048/s  12%  11%   8%   8%   5%   2%   1%   0%   0%   0%   --  -2%  -4%  -5%  -6%  -8%
h3_i 12346/s  15%  14%  11%  11%   7%   5%   4%   2%   2%   2%   2%   --  -1%  -2%  -4%  -6%
h3_n 12500/s  16%  15%  13%  13%   9%   6%   5%   4%   4%   4%   4%   1%   --  -1%  -2%  -5%
l1_i 12658/s  18%  16%  14%  14%  10%   8%   6%   5%   5%   5%   5%   3%   1%   --  -1%  -4%
h1_n 12821/s  19%  18%  15%  15%  12%   9%   8%   6%   6%   6%   6%   4%   3%   1%   --  -3%
l1_n 13158/s  22%  21%  18%  18%  14%  12%  11%   9%   9%   9%   9%   7%   5%   4%   3%   --
<

Server version: 5.1.33 Source distribution
use strict;
use warnings;
use DBI;

use Benchmark ':all';

my $dbh = DBI->connect('DBI:mysql:test');
sub setup {
    for (1..4) {
        $dbh->do("DROP TABLE IF EXISTS hatena$_");
        $dbh->do("DROP TABLE IF EXISTS labs$_");
    }

    $dbh->do(q{
CREATE TABLE hatena1 (
    id    int unsigned,
    name  char(10),
    primary key(id, name),
    index(name, id)
) TYPE=MyISAM
});
    $dbh->do(q{
CREATE TABLE hatena2 (
    id    char(10),
    name  char(10),
    primary key(id, name),
    index(name, id)
) TYPE=MyISAM
});
    $dbh->do(q{
CREATE TABLE hatena3 (
    id    char(10),
    name  char(10),
    unique(id, name),
    index(name, id)
) TYPE=MyISAM
});
    $dbh->do(q{
CREATE TABLE hatena4 (
    id    char(10),
    name  char(10),
    index(id, name),
    index(name, id)
) TYPE=MyISAM
});

    $dbh->do(q{
CREATE TABLE labs1 (
    id    int unsigned,
    name  char(10),
    primary key(id, name),
    index(name, id)
) TYPE=InnoDB
});
    $dbh->do(q{
CREATE TABLE labs2 (
    id    char(10),
    name  char(10),
    primary key(id, name),
    index(name, id)
) TYPE=InnoDB
});
    $dbh->do(q{
CREATE TABLE labs3 (
    id    char(10),
    name  char(10),
    unique(id, name),
    index(name, id)
) TYPE=InnoDB
});
    $dbh->do(q{
CREATE TABLE labs4 (
    id    char(10),
    name  char(10),
    index(id, name),
    index(name, id)
) TYPE=InnoDB
});
}
setup if $ARGV[0]||'' eq 'setup';

sub apply_insert {
    my @buf = @_;
    for my $num (1..4) {
        for my $name (qw/ hatena labs /) {
            $dbh->do(sprintf "INSERT INTO $name$num (id, name) VALUES%s;", join(', ', @buf));
        }
    }
}

if ($ARGV[0]||'' eq 'setup') {
    my @buf;
    for my $id (1..1000) {
        for my $name (1..1000) {
            push @buf, "($id, $name)";
            if (@buf == 1000) {
                apply_insert(@buf);
                @buf = ();
            }
        }
    }
    if (@buf) {
        apply_insert(@buf);
    }
}

my $coderefs = {};
my $countcache = {};
for my $name (qw/ hatena labs /) {
    for my $num (1..4) {
        my $table = "$name$num";
        for my $column (qw/ id name /) {
            my $testname = join '', substr($name, 0, 1), $num, '_', substr($column, 0, 1);
            $coderefs->{$testname} = sub {
                my $sth = $dbh->prepare("SELECT COUNT(*) FROM $table WHERE $column = ?");
                $countcache->{$testname}++;
                $sth->execute($countcache->{$testname} % 1000);
            };
        }
    }
}

cmpthese( 10000 => $coderefs);

という生魚的エントリ。

Posted by Yappo at 15:48 | Comments (0) | TrackBack

2009年05月19日

yacc と lex で簡易言語の AcotieScript っての作ってみた

そろそろ梅雨入りするので急いでキュウリの苗植えたら安物のせいか根っこが弱っこくて少し心配な金曜日担当Yappoです。

Perlも飽きたし、ふと思う所があって、オレオレ言語を作ってみました。
http://github.com/yappo/AcotieScript/tree/master
たぶんMacでしか動かないんじゃないかなとは思ってますが、普通にmakeすればコンパイルされる筈。

サポートされているシンタックスはコメントとprintとperlにあるような文字列同士のxorです。

"hoge" ^ "ugee"
みたいのですが、これを実行すると死にます。元ネタの人が文字列xorを理解したら正しく動くなる予定です。

printは

print "hello\n"
を実行すると「おうっふー hello」とprefixにおうっふーを追加します。

AcotieScriptの最大の特徴は、コメント構文の豊富さで、次の物は全てコメントとして解釈されます。

//this is comment
#this is comment
/*this is comment*/
"""this is comment
'''this is comment
<!--this is comment-->
REM this is comment
また、実行文の後ろにも次の物はコメントになります。
    print "hello!\n" #    this is comment
    print "hello!\n" //   this is comment
    print "hello!\n" """  this is comment
    print "hello!\n" '''  this is comment
    print "hello!\n" :REM this is comment

その他構文は{}のブロックはサポートしているが意味ありません。
またrubyの用っぽく1行で1つの文になり、一つの行に複数の文を置きたければ;で区切れます。

print "hoge\n" # 1文
print "foo\n";print "bar\n" # 2文

サポートされているリテラルは文字列リテラルのみでシングルクオートとダブルクオートが使えます。
それぞれはだいたいその他の言語のような動きはします。

コマンドラインでもいけます

acotiescript -e 'print "hello\n"'

shebang使えます。

$ cat oufu.acotie 
#!./acotiescript

print "うっ!\n"
$ ./oufu.acotie 
おうっふー うっ!

今後

今のままだと100% CGIとして動作しないので、CGIとして動作するようにするかも。
構文解析した物をスタック詰んだりしないで、逐一実行するだだからifやらwhileやら作るの面倒いのでスタック型にするかなーとか
mod_acotie作ってみるのはどうか?

まとめ

perlとrubyはparserをyaccでやってトークナイザはlex使わないで自前でやってる。
PHPもyacc使ってるが何かスッゲーきたない。
Pythonは全部自前でやっててコンパクトでシンプルでソース量も少なかった。

とりあえずlex使うと楽ですね。yaccは規則がループしたりしないようにするように作らないといけないのだが、気を抜くと循環参照しだしてパースが終わんなくなる。
perl -e 'print "hello"' みたいな -e オプションを実装するのにfunopenを使って、文字列バッファをstdioインターフェィスに組み込めるような機能を関数を使ったがBSDでしか使えなっぽ。
perlとかだとトークナイザは自前なのでどうとでもなるが、lex使うとFILE *なものしかやってくれないので、char *をFILE *にしてくれる汎用的な方法ないかなーと探してる所。

あとコマンドラインオプション解析は getopt を使いました。 argv[1] がファイル名だったらそれスキップします。

そんな感じでfork歓迎push requestも歓迎です!

Posted by Yappo at 11:24 | Comments (0) | TrackBack

2009年04月16日

はてなのお気に入りアンテナをTwitter Clientで見れるゲートウェイ「Hatetter」作りました

注意:ブックマークだけでなく、お気に入りアンテナのフィードを使うようになりました。

はてブのお気に入りリストってRSSリーダとかで見たりするのが多いんですが、もっとTwitterのようにカジュアルにウオッチしたいと思って、お気に入りリストのRSSをTwitter API互換のFeedに変換するサーバを書きました。

Hatter - 太っ腹にソースコードも公開してるので、自宅サーバとかに置いて使うってのもできます。

たとえばid:acotieがお気に入りに入れてる人達のブックマークをTwitter風に変換したい時は

http://hatetter.blogdb.jp/acotie/statuses/friends_timeline.json
もしくは
http://hatetter.blogdb.jp/acotie/statuses/friends_timeline.xml
を使います。一回目アクセスした時は空ですが、1分くらい立つとFeedが出来てきます。
このままだとXMLやらJSONがそのまま出てくるので、何かしら専用くらいんとから見ると良いです。

XMLとJSONに変換するので、たいがいのクライアントで見れるようになるんじゃないかなぁと期待しています。

技術的補足

Hatterでは、Perl以外にもQ4Mとmemcachedを使っています。

最初リクエストがあった時には、空の結果を返しつつQ4Mにキューを詰んで、数十秒後にQ4MのWorkerがFeedを取りに行って、Feedの変換を行い、結果をmemcachedに積み込んでいます。
で、クライアントからの二度目のアクセスの時にはmemcachedに入っている変換結果を出すだけです。
一度キューに突っ込んだらmemcachedに時間を保存しておいて5分以内は、キューに突っ込まれないようにしています。
と言った事を、一つのID毎に行っているので大量のアクセスが来たとしても自分のサーバも、はてなのサーバも大変な事にならない予定です。
Webアプリとしてはmemcachedとmysql(Q4M)との間でしか通信しないので、殆どブロックする事無く高速に応答出来るのではないかと思っています。
また、大量に使われる事になってキューがいっぱいたまってもQ4MなのでFeedの処理で過負荷になることも無くて安心です。やばければworkerのプロセス増やせば良いだけですしね。

キューに関しても3回retryして失敗したらキューを捨てるという事をやっていて、これもData::Model::Driver::Queue::Q4Mのお陰で簡潔に実装が行われています。
Queue::Q4Mとは違って、queue_waitに渡すテーブルに対するコールバックハンドラを渡す感じになっていたり、queue_endやqueue_abortの面倒見なくても良い、また対応するqueueのレコードを予め取得してobjectにしてコールバックハンドラに返す。といった事が効いていると思います。Q4M可愛いよQ4M。

Web周りに関しては、普通にHTTP::EngineとMouseだけでやってます。FrameworkなんかこのレベルだといらなくてHTTP::Engineだけで事足りますわね。
あ、index.htmlだけHTTP::Engine::Middleware::Staticで出してますよ。

ということで、どうぞご利用下さい。

Posted by Yappo at 13:41 | Comments (1) | TrackBack

2009年04月13日

Q4MをMacPortsのMySQL環境に入れる方法

macportsでmysql入れると /opt/local/lib/mysql5/mysql とかいう独創的な所にライブラリが入るので、そのまんまのQ4Mのconfigureじゃ./configureすら上手く動かないし、ググっても良くわからないのでてっとり早くconfigure.inを書き換えたよ。

パッチはhttp://gist.github.com/94339から
実行令とかは下記の通り。

 $ patch < ../for-macports.patch
 $ autoconf
 # include ディレクトリを追加するのが必要
 $ CPPFLAGS=-I/opt/local/include ./configure --with-mysql=/opt/local/var/macports/sources/rsync.macports.org/release/ports/databases/mysql5-devel/work/mysql-5.1.33 --with-mysql_config=/opt/local/bin/mysql_config5

という感じで--with-mysql_configオプションを追加してmysql_configにライブラリパスとかの解決を行わせています。

あとはsudo port install boostとかするの忘れなければはまらない予定。

installおわったら

 $ mysql5 -u root < support-files/install.sql
して、気が向けば perl ./run_tests.pl してチェックすれば無事install完了です。

添削ありましたら、ご指摘くだしあ。

どうでも良いけどQueue::Q4Mのテストデータベースのデフォルトは q4m_test じゃなくて test_q4m が良い。なぜならば mysqld の初期設定で test_% ってのはテスト用として権限設定されてるから。
僕はtest_q4m作って

 $ Q4M_DSN=test_q4m make test 
しました。

Posted by Yappo at 19:22 | Comments (0) | TrackBack

2009年04月02日

Safari3のメモリ管理が何か変?

今のところSafari3限定 (確認したのはバージョン 3.2.1 (5525.27.1))なのだが、IMGタグを追加したりremoveしまくってたりすると、どんどん使用メモリが増えてくる現象を発見した。
Safari4のβ版やらFirefoxではそういった事にならないのは確認したが、単純なDOM操作なのにもりもりメモリを使って行く。
ウインドウを閉じてもメモリは解放されずに、解放しなかったメモリは内部的に再利用してるっぽい。
で、閉じる前に確保してたメモリ領域を使い切ったっぽいポイントでまたメモリをもりもり食べ出す。
まるでメモリプールみたいな感じなんだがウインドウを閉じるまで再利用されてない感じなんだ。

ちなみにSRC属性を指定しないとメモリがもりもり増えなかったりする。

以下のHTMLをローカルに保存して、保存した所と同じディレクトリにdummy.pngという適当な画像を置いてからブラウザで開いて下さい。
メモリが増える様子はアクティビティモニタ等で見るとわかり易いでしょう。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html><head>
    <title>memory leak test</title>

    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta http-equiv="content-script-type" content="text/javascript">

    <script>
        var count = 0;
        var is_run = true;

        var $ = function(id){
            return document.getElementById(id);
        };

        var reload = function(){
            var container = $("container");
            while (container.childNodes.length > 0) {
                container.removeChild(container.childNodes[0]);
            }
            add();
        };

        function add(){
            $("count").innerHTML = count++;
            var i;
            for (i = 0; i < 100 ; i++) {
                var img = document.createElement('img');
                img.src = "dummy.png";
                $("container").appendChild(img);
            }
            if (is_run) setTimeout(reload, 100);
        }

        window.onload = function(){
            $("reload").addEventListener("click", reload, false);
            $("stop").addEventListener("click", function(){
                is_run = false;
            }, false);
            add();
        };
    </script>
</head><body>
    <div id="stop">stop</div>
    <div id="reload">reload</div>
    <div id="count">0</div>
    <div id="container"></div>
</body></html>
きっとamachangなら理由わかってそうだなー。という気はしてる。

おまけ

leaksコマンドと言う便利コマンドがあるので、実行したりウインドウ閉じたり開いたりした時の結果もはっときます。
なんか色々leakしてるけど、今回と関係あるかどうかはわからない。

実行当初
$ leaks  7011
Process 7011: 199039 nodes malloced for 19823 KB
Process 7011: 0 leaks for 0 total leaked bytes.
どんどんメモり増える
$ leaks  7011
Process 7011: 305529 nodes malloced for 30869 KB
Process 7011: 0 leaks for 0 total leaked bytes.
凄い増えた
$ leaks  7011
Process 7011: 1067031 nodes malloced for 107063 KB
Process 7011: 0 leaks for 0 total leaked bytes.
アクティビティモニタのRSIZEももりもり増える
ウインドウ閉じる
$ leaks  7011
Process 7011: 205175 nodes malloced for 20180 KB
Process 7011: 1 leak for 16 total leaked bytes.
Leak: 0x1ca2dbc0  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x15015080 0x00000004 0x00000000 	..[..P..........
mallocedのサイズが減ってるけどRSIZは変わらず。そして1個リーク。
ウインドウ開いた
$ leaks  7011
Process 7011: 205273 nodes malloced for 20262 KB
Process 7011: 4 leaks for 64 total leaked bytes.
Leak: 0x16c0d300  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x02015080 0x00000004 0x00000000 	..[..P..........
Leak: 0x1ca2dbc0  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x15015080 0x00000004 0x00000000 	..[..P..........
Leak: 0x1ca376a0  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x01015080 0x00000004 0x00000000 	..[..P..........
Leak: 0x1cae0120  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x03015080 0x00000004 0x00000000 	..[..P..........
RSIZEかわらず。3個リーク増えた。
再度実行
$ leaks  7011
Process 7011: 269750 nodes malloced for 26522 KB
Process 7011: 4 leaks for 64 total leaked bytes.
Leak: 0x16c0d300  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x02015080 0x00000004 0x00000000 	..[..P..........
Leak: 0x1ca2dbc0  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x15015080 0x00000004 0x00000000 	..[..P..........
Leak: 0x1ca376a0  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x01015080 0x00000004 0x00000000 	..[..P..........
Leak: 0x1cae0120  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x03015080 0x00000004 0x00000000 	..[..P..........
またまた増えた
$ leaks  7011
Process 7011: 1354957 nodes malloced for 131749 KB
Process 7011: 4 leaks for 64 total leaked bytes.
Leak: 0x16c0d300  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x02015080 0x00000004 0x00000000 	..[..P..........
Leak: 0x1ca2dbc0  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x15015080 0x00000004 0x00000000 	..[..P..........
Leak: 0x1ca376a0  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x01015080 0x00000004 0x00000000 	..[..P..........
Leak: 0x1cae0120  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x03015080 0x00000004 0x00000000 	..[..P..........
もっかいウインドウ閉じた
$ leaks  7011
Process 7011: 209735 nodes malloced for 20861 KB
Process 7011: 5 leaks for 80 total leaked bytes.
Leak: 0x16c0d300  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x02015080 0x00000004 0x00000000 	..[..P..........
Leak: 0x1ca2dbc0  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x15015080 0x00000004 0x00000000 	..[..P..........
Leak: 0x1ca376a0  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x01015080 0x00000004 0x00000000 	..[..P..........
Leak: 0x1cadd650  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x0b015080 0x00000004 0x00000000 	..[..P..........
Leak: 0x1cae0120  size=16	instance of 'TSMInputSource', type CFType, implemented in HIToolbox	
	0xa05bcee0 0x03015080 0x00000004 0x00000000 	..[..P..........
リーク増えた

Posted by Yappo at 21:04 | Comments (3) | TrackBack

2009年03月31日

クロスブラウザ対応やってみて思った事

HTMLやらCSSやらJavaScriptやら色々弄った感想

- Firefox, Safari, Google Chrome なんかは割と手がかからない
- Opera も上の3つ抑えてればだいたいok
- なんかSafari4のJavaScriptの挙動が3と微妙にちがう
- IEは死ね、IE7からだいぶ互換性的な物がよくなってるけどIEは死ね。
-- IE6のサポートを切り捨てる時代はまだか?
- IE8は確かにJavaScriptが速くなってるがGoogle Chromeは劣るしSafariとか本当速い、Firefox3.0は結構遅い
- z-indexの事を考えてないで作ってると、いざとなったら本当にびっくりする
- pngの透過画像をあわせるのは案外しんどい
-- DXImageTransform.Microsoft.AlphaImageLoader使うんだけど、background-imageが入ってると混ざる、そしてDXImageTransform.Microsoft.AlphaImageLoaderで出すと画像が背景画像じゃなくなる
-- classにpngimgみたいなのが入ってるときはbackgroundをnoneにするのやってみたけど、#idname:hover {} みたいに hover されたときだけpng画像を変えたりとかenable/disableクラス与え状態によってpng画像のurlを変えたりすると上手くDXImageTransform.Microsoft.AlphaImageLoaderが当たんなくなる
- 元から配布されてるjqueryライブラリを俺俺改造されてると他の人が困るので、元のは弄らずに外部からわかり易くmethod差し替えたりするとよい。
- アンダースコアハックとかCSSの人がハックハック言ってる物はPHPのクラス名の区切りにバックスラッシュ使うようなもんだと思ってるから使いたく無い
-- ブラウザ毎のCSSを吐き出すジェネレータ書いてHTMLから読む時にブラウザによって変えるのが正解なんだろなー

- float: leftしまくった要素を持つ親要素の縦横も、IEだけは float: left してる要素分だけ加算されるので、上のブラウザと全然違う事になったからjavascriptで縦横辻褄合わせた。
-- たいていの非互換製はJavaScript使う力技でなんとかなったり
- IE6なんかはpadding-leftの値を1px変えるだけですっきりしたり

まとめ


たんぽぽを乗せるだけの簡単な仕事じゃないんだけど、殆どの苦労は機械的に解消出来そうな感触を得た春であった

IEを使わないでJavaScriptを書く時に陥る一番の罠としてはハッシュの最後の要素に,を付けてしまうという事(Perlでは皆よくやってる)だが

var hash = {
key: name,
last: value, // ここの ,
};

これはIEでは動かないのだが、コードが多くなると探すのがとても大変である。
が、そんな時はJavaScript Lintを使えば良い。
アプリケーションのユニットテストの中に、これを使ってlintかけるテストなんか入ってると興奮が止まらないだろう。
たとえば
#!/usr/bin/perl
use strict;
use warnings;
use Test::More;
use Text::SimpleTable;
plan skip_all => 'this test requires "jsl" command' unless `jsl` =~ /JavaScript Lint/;

my @files = <htdocs/js/*.js>;
plan tests => 1*@files;

my $table = Text::SimpleTable->new(25, 5, 5);

for my $file (@files) {
# 0 error(s), 6 warning(s)
my $out = `jsl -stdin < $file`;
if ($out =~ /((\d+) error\(s\), (\d+) warning\(s\))/) {
my ($msg, $err, $warn) = ($1, $2, $3);
$file =~ s!htdocs/js/!!;
$table->row($file, $err, $warn);
is $err, 0, $file;
} else {
ok 0;
}
}
diag $table->draw;

こんなのを書いてもらって使ってる。

これ使ってると、「ああ、JavaScriptのスコープってfunction毎なんだな」ってのが良く思い出せて良いです。

(はてなに書こうとしてたフォーマットをそのままコピペしたのでみにくいかなっと)

Posted by Yappo at 13:44 | Comments (2) | TrackBack

2009年01月16日

コードホスティングサイトの比較表を作っています

最近「GitHubみんな使っててCodeReposやばいねー」とか聞かれる時があって、適当に返事するのもアレなんで、客観的に返答出来るように比較してみようかなーと思い、それぞれのサービスの比較表を作ってみる事にしました。

現在http://soozy.org/index.cgi?CodeHostingComparisonにて表を作っています。
現在は、SourceForge, Google Code, CodeRepos, GitHubの4サイトから比較しています。
はてなアカウントがあれば自由に編集出来ますので(まずは左上のloginをクリック)、足りない所があれば、他のサイト追加、比較項目追加、内容修正など行って頂ければ嬉しいです。

比較項目を考えるのがとても大変なので、是非皆様のお知恵を拝借したく思いますです。

Posted by Yappo at 13:39 | Comments (1) | TrackBack

コードホスティングサイトの比較表を作っています

最近「GitHubみんな使っててCodeReposやばいねー」とか聞かれる時があって、適当に返事するのもアレなんで、客観的に返答出来るように比較してみようかなーと思い、それぞれのサービスの比較表を作ってみる事にしました。

現在http://soozy.org/index.cgi?CodeHostingComparisonにて表を作っています。
現在は、SourceForge, Google Code, CodeRepos, GitHubの4サイトから比較しています。
はてなアカウントがあれば自由に編集出来ますので(まずは左上のloginをクリック)、足りない所があれば、他のサイト追加、比較項目追加、内容修正など行って頂ければ嬉しいです。

比較項目を考えるのがとても大変なので、是非皆様のお知恵を拝借したく思いますです。

Posted by Yappo at 13:39 | Comments (1) | TrackBack

2008年12月20日

WEB+DB PRESS Vol.48に寄稿しました

今度発売されるWEB+DB PRESS Vol.48の第一特集にて「[言語別]モダンプログラミング入門」 という記事を書かせて頂きました。

おこがましいようですが僕は特集の総括的な部分とPerlに関して担当させて頂きました。
KENTは悪じゃない!から始まってperldoc, cpan, pauseアカウントの取得, test, shipit そして JPA まで幅広く今のPerlについて書きました。
もちろん濃くて広い事を書くにはページ数の限界もあって「薄く広く足がかりを作る」に専念したため、Shibuya.PMで発表してるような魑魅魍魎が満足するような内容にはなっていませんが、昨今のPerlを見つめ直す流れに乗っ取り、他言語な方や初心者の方でも今のPerlの流れに乗れるような内容になる事を意識しました。

もちろん他の言語(Ruby,Java,PHP,Javascript)でも、似たような構成と主旨で書かれています。
それぞれの章を担当して下さった皆様にも感謝です。

今回はとても幸運な事に、ただ単に特集の一つを担当したわけではなく、コンセプト的な企画を作る所から関わらせていただけました。
というもののきっかけとしてはITmediaで取材して頂いた時の一言

—— 開発系の雑誌で購読してるものはありますか? 雑誌にはどんなコンテンツを期待したいですか?

SoftwareDesignとWeb+DB PRESS。東京IT新聞も速報度の面でがんばっているなと思います。ぶっちゃけ雑誌媒体というのはWebの情報に比べると鮮度が悪いわけですが、紙には紙の良さがあってじっくりと読むのには向いていますよね。言語は問わず(商業的な取捨選択はあるけど)今風のモダンでcoolなコードの書き方などをメインにした「プログラム専門誌」が欲しいですね。月刊で。
がきっかけでした。
流石に月刊はアレですが、夢が叶ったという事でとても嬉しいです。

このへんのやってみて思った事はtakesakoさんすげーって事。

ってことで1家に一冊、1部署に一冊是非どうぞ。

WEB+DB PRESS Vol.48
WEB+DB PRESS Vol.48
posted with amazlet at 08.12.20
WEB+DB PRESS編集部 編
技術評論社
売り上げランキング: 585

そしてやっっぱり相変わらず思う事は、プロの編集者さんはすごいということと、また機会があれば何か書きたいなということでした。

あ、執筆中はwassrでhyoshiokaさんからの貴重なアドバイスも頂きました事を追記しておきます。

otsuneさんに前回の紹介で「もう出てると思って買ったら1号前だった」とクレームが来たので書店に並びそうになるまで待ちました。

Posted by Yappo at 19:08 | Comments (0) | TrackBack

2008年12月12日

このblogとperl-users.jpは移転完了

blog.yappo.jp と perl-users.jp だけは、新環境に移行したのでサーバの物理移動中も止まらないす。

しかしふっるいmtなので関連ディレクトリをrsyncするだけで動くなんてすばらしいなー

Posted by Yappo at 19:32 | Comments (0) | TrackBack

2008年12月10日

サーバ引っ越し計画

すっかり準備するのがギリギリになってヤバイ。
金曜の夜に今置いてる所から物理的にサーバを移動します。
なのでもう今週中はテンパってます。

という事で簡単な計画表

やること

  • DNSのプライマリサーバ移転 (hidekさんの会社のやつ契約ずみ) (jprs/tonic/value domain)
  • mail/irc/plagger環境作る (リアルサーバでOSとかは既に入って稼働してるの使い回し)
  • edge serverでメールを受けてバックエンドに再配送させる仕組みつくる
  • edge serverにマトモなdsn cacheを入れる
  • このblogや軽いwebサービスようのDomU作る
  • perl-users.jp / soozy.org / shibuya.pl / perldoc.jp / yapc.asia などようのDomUつくる
  • 新しい環境の中に25番ポートで繋がるようにする
  • ラックの掃除
  • 新環境を用意するものは、新環境にさっさと移動、用意しないのは金曜の夜に物理マシンの移動
  • 移動中のお知らせメンテナンスページ用意
  • /etc/hosts とか hostname まわり。

異動前の構成とサービス内容

PE750

  • mail - sendmail (virtusertable) - mew - spamd (procmail(hiyoko@twitter, kacotie@twitter))
  • irc - irssi - oppaisan - mobirc
  • plagger
  • private subversion repos
  • dns
  • 以下はweb
  • yappo.jp/yappo.ne.jp (i, 503, moogle, talk, trac, svn, w, dir, search, *.labs, blog, tec)
  • blogdb.jp (bulkya, mfpm, shibuya.burogukyoukai)
  • menulist.jp
  • soozy.org
  • bloxab.org
  • cybozu.co.uk
  • perl-users.jp
  • seiitaishougun.com
  • shibuya.pl
  • yapc.asia

ISP1100

ハードウェアクロックがなんだか年単位でずれてる。といかどっかのDomUに突っ込んで退役希望

  • web crawler
  • hiyoko
  • sendmail virtusertable
  • mobile sns用のメール受信処理
  • moblog & photo storage用のメール受信処理
  • mail配送エンジン(たしかもう使ってない)
  • 以下はweb
  • bp.to
  • m.blogdb
  • 2ch proxy

PE1850

  • mysql
  • mysql with senna

edge server

codereposとacotieへのreverse proxyやらなんやら

SC440 - 1

  • coderepos
  • acotie

SC440 - 2

今なにもない。あ、1000スピーカカンファレンスで使った。

tsukumo

dns セカンダリとblogdb.jp跡地

異動後の構成とサービス内容

PE750

京都行ってる時にとまりやがったのでこわい。

  • private subversion repos
  • 以下はweb
  • yappo.jp/yappo.ne.jp (i, 503, moogle, talk, w, dir, search, *.labs)
  • blogdb.jp (bulkya, mfpm, shibuya.burogukyoukai)
  • menulist.jp

ISP1100

ハードウェアクロックがなんだか年単位でずれてる。といかどっかのDomUに突っ込んで退役希望、というか移動した後bootするか不明。

  • web crawler
  • hiyoko
  • sendmail virtusertable
  • mobile sns用のメール受信処理
  • moblog & photo storage用のメール受信処理
  • mail配送エンジン(たしかもう使ってない)
  • 以下はweb
  • bp.to
  • m.blogdb
  • 2ch proxy

PE1850

平穏無事に動いてるのでこわい

  • mysql
  • mysql with senna

edge server

codereposとacotieへのreverse proxy server 並びに mail forwarder

SC440 - 1

  • coderepos
  • acotie

上のDomUに加えて下のDomU追加

public

  • perl-users.jp
  • shibuya.pl
  • soozy.org
  • yapc.asia (もしくは edge server のみで処理)

private

  • private subversion repos for svn.yappo.jp
  • yappo.jp/yappo.ne.jp (trac, svn, blog, tech)
  • bloxab.org
  • cybozu.co.uk
  • seiitaishougun.com

SC440 - 2

  • mail - sendmail (virtusertable) - mew - spamd (procmail(hiyoko@twitter, kacotie@twitter))
  • irc - irssi - oppaisan - mobirc
  • tig/wig
  • plagger

tsukumo

dns セカンダリとblogdb.jp跡地

hidekさんの会社のVPS

dns プライマリとバックアップ

PE860

状況をみてPE750とISP1100のサービスをこれのDomU複数作って集約。集約したらPE750/ISP1100を退役。余裕があればPE1650も入れたいけど80万くらいしたからどうしようか。

作業する順番

  • VPSにname serverの環境作ってprimary として動かし始める
  • yappo.ne.jpのnsレコード変更。変更出来次第他のドメイン全部のnsレコード変更
  • DomU2個作る(1個作ってイメージコピー)
  • VPSにバックアップしまくる
  • mail/irc/plagger環境作る
  • edge server から SC440-2 にメール流す
  • public servicesの引っ越し (済: perl-users.jp)
  • private servicesの引っ越し (済: blog.yappo.jp)
  • VPSにバックアップ(差分とか)
  • イーサケーブル作ってラックの掃除
  • PE750/PE1650/ISP1100物理移動
  • ラッキング
  • サーバ起動
  • hostname/ip address/ip tables/network環境の書き直し
  • DBの認証設定全部変える
  • アプリケーションのDB設定全部変更
  • アプリケーション稼働確認と広告周りを実機でチェック
  • ISP1100のメール環境整備
  • クロウラー走らせる
時間足りなくてきついわー

来年

codereposとか入ってるマシンに500GのHDDが刺さってるだけなので vgextend VolGroup00 /dev/sdb してパーティションサイズをいつでも増やせるようにしておく。

Posted by Yappo at 18:36 | Comments (0) | TrackBack

2008年09月01日

CodeReposが1年たってGitリポジトリ追加の巻

昨晩は夜9時から誕生日ケーキを探してたけどケーキ屋さん店じまいしてるのばっかで誕生日中にエントリかけなくなった><

YappoLogs: CodeRepos - 個人レポジトリを共有しよう!計画という記事と共にCodeReposが生まれて一年経ちました。
僕は主に460名分のhtpasswdをひたすら登録をするだけのお仕事をしていたわけですが正直ここまで続くとは思っていませんでした。
これも何もひとえにがんがんコミットしてくれる皆様のお陰だと思っています。有り難うございました。
やっぱり折角人様のコードを弄くりまくれる環境があるのだから、皆ももっとコミットしまくれば良いよ。

あと折角一年経ったという事でリリースし忘れてたGitリポジトリを公開しておきます。
http://git.coderepos.org/です。
GitはSubversionとは違って全部を一つのリポジトリに突っ込むととてもとても不愉快な事になるので、プロジェクト毎にリポジトリ作れるようにしました。
create repository のとこに作成したいリポジトリのパスを入れてsubmitすればおkです。
Subversionのリポジトリと同じルールの階層でしか作れないようになってます。
あとは作ったリポジトリに対してgit pushやらすればおkです。
リポジトリ作った時やgit pushした時にFeedを吐くようにしてあり、そのFeedをcodereposbotがircに流してくれるという事もやってます。
もうすこし詳細を見るにはわっふるわっふるしてください。

何はともあれ2年目のCodeReposをよろしくお願いします。

Posted by Yappo at 11:47 | Comments (1) | TrackBack

2008年08月09日

MixiEchoPodというMacからmixiのエコーを快適に使うツールを作ったよ

空前のwassrブームの中皆様いかがおすごしでしょうか。
ついにあのTwitがとくにエコー対応していなくて面白い感じですが、Mac用のいいツールが無さげです。というかAPI解放してないけどEchoPodとかあります。
先週末の、Wassr大会議#2の集いにtokuhiromさんもいらしてたのでエコーに乗り換えてもいいか聞いてみたのですが、「Wassrを末永くお願いします」と言われたので、僕が勝手にTwitterPodをエコー対応しちゃいました。
かいつまむと「mixiエコーをtwitter APIを使うクライアントからアクセスできるコンバータ付きproxy」です。

Macのターミナルとperlが使える環境の人前程ですが、物凄く簡単にエコー対応が出来ます。
TwitterPodをアプリケーションディレクトリに入れておいて下さい。
そして、ここからターミナル操作です。

まずは

svn co http://svn.coderepos.org/share/lang/perl/misc/MixiEchoPod ~/MixiEchoPod
とかで、仕組み一式をチェックアウトして
 $ cd /Applications
 $ ~/MixiEchoPod/install.pl
とするだけでMixiEchoPodがアプリケーションディレクトリに出来上がります。
これでMixiEchoPodのインストールは完成です。
何やってるかはinstall.plでも見て下さい。

次に肝心のproxyですが、~/MixiEchoPod/mixiechopod.plがそうです。
これを使うには各種CPANモジュールが必要なので

 $ sudo cpan
> install MooseX::Getopt
> install HTTP::Server::Simple
> install HTTP::Engine
> install JSON
> install DateTime
> install XML::Simple
> install MooseX::Types
とかして必要なモジュールを全部入れておきます。
あとはsvn headのWWW::Mixi::Scraperも必要なのでsvn.coderepos.org/share/lang/perl/WWW-Mixi-Scraper/trunkからチェックアウトしてインストールです。
ここまでして入れたら
 $ ~/MixiEchoPod/mixiechopod.pl --port 3941
で起動します。3941はproxyのサーバポートです。
起動したらemailとpasswordを聞かれるのでmixiのアカウントに使ってる物を入れて下さい。

ここまできたらあとはアプリケーションディレクトリのMixiEchoPodを起動して、設定画面のアカウントは適当なのを入れて、最後が肝心だけど「Enable Proxy」にチェックをいれて「Server」に「127.0.0.1」を入れ「Port」に「3941」を入れればokです。
結構無理栗なhackなのでMixiEchoPodのアプリケーションが落ちちゃったりする可能性もありますが僕は結構快適に使えてます。

今後の予定はmixiならではの機能をMixiEchoPodから使えるようにmixiechopod.plを拡張してくネタをmixiが実装してくれたらいいですね。
なんでも一から作るのは大変ですが、この程度なら大変じゃなくて良い感じですね。

どうぞご利用下さい。

Posted by Yappo at 18:46 | Comments (1) | TrackBack

2008年07月18日

CodeRepos の引っ越し作業が一通りおわりました

一応、無事に一通りの引っ越し作業がおわりました。
細かい所は週末のうちに全部終わらせる。
実際どういう環境になったのかはあとで書く。

Posted by Yappo at 11:41 | Comments (1) | TrackBack

2008年07月09日

CodeReposのサーバお引っ越し計画

以前予告した通り、CodeReposサーバのお引っ越しを今週中に行います。
とりあえず場所は家に置いて、さっき電力会社に電源工事発注した。
リバースproxyの部分にCentOSの新しいのをいれて、coderepos自体はバックエンドにいるXenのインスタンスで動かそうと思ってます。
QX6600 8G メモリの環境なのでcoderepos以外のインスタンスとかも十分に対応できそう。

既にiscsiの環境もあってライブマイグレーションとか出来るようにはなってるんだけど、それやると別途ファイルサーバ持たなきゃ行けないとかQX6600なCPUのマシンが一台しかないから、別のホストマシンにインスタンス移したらカーネルがクラッシュするとかで、どうしようか悩んでる。
別にこの規模じゃそういうのいらないかなぁ。

で、それらの環境を今晩から1から作ろうと思ってたら、年始に遊んでた環境がそのまま使えそうな事を発見。
xenのインスタンスを新規に作ってしまえばOS環境の設定は楽に終わりそうな気がしたけど、今流行ってるXenの管理ツールを使いたいなと思っていて誰かにおすすめを聞きたい所。

ちなみに良い案が無ければYappoLogs: Cobbler Koan を CentOS な Xen で動かしたよで作った環境でxenのイメージを作る予定。
イメージファイルをiscsiじゃなくてローカルディスクに置いて、iscsiのマシンに依存しない方向で運用しときたい予定。
仮想ディスクはSparseという実際に使ったぶんしか実際のディスクサイズが食われないというwrite性能の低いフォーマットを使う予定で(参考文献)す。バージョン管理システムだから問題無いよね?

ちなみに移行自体は、新しい環境にtracとかもろもろ入れて、svnはdump/loadしてtracはsqliteのファイルをコピペしてくるだけの簡単なお仕事です。

メンテナンス開始日時の具体的な予定は立てられないので、作業直前に各種ircチャンネルやtwitterで告知を行います。

coderepos専用のインスタンス作るので、codereposのadmin的な意味でサーバのログインアカウントを任意の誰かに渡せると思います。
#coderepos@irc.freenode.netではxenとかに詳しいエンジニアを募集します!報酬はありません!!!

EC2でやれって話?とりあえず金曜までにやんなきゃいけないので勘弁してくだちぃ。

Posted by Yappo at 14:51 | Comments (1) | TrackBack

2008年07月07日

WassrPodというMacからwassrを快適に使うツールを作ったよ

空前のwassrブームの中皆様いかがおすごしでしょうか。
ついにあのTwitがTwit4WSとしてwassr対応して面白い感じですが、Mac用のいいツールが無さげです。
先週末の、はてなハイククライアント制作者の集いにdrkinさんもいらしてたのでwassr対応を聞いてみたのですが、ちょっと面倒くさそうな感じだったので、僕が勝手にTwitterPodをwassr対応しちゃいました。
かいつまむと「wassr APIをtwitter APIを使うクライアントからアクセスできるコンバータ付きproxy」です。

Macのターミナルとperlが使える環境の人前程ですが、物凄く簡単にwassr対応が出来ます。
TwitterPodをアプリケーションディレクトリに入れておいて下さい。
そして、ここからターミナル操作です。

まずは

svn co http://svn.coderepos.org/share/lang/perl/misc/WassrPod ~/WassrPod
とかで、仕組み一式をチェックアウトして
 $ cd /Applications
 $ ~/WassrPod/install.pl
とするだけでWassrPodがアプリケーションディレクトリに出来上がります。
これでWassrPodのインストールは完成です。
何やってるかはinstall.plでも見て下さい。

次に肝心のproxyですが、~/WassrPod/wassrpod.plがそうです。
これを使うには各種CPANモジュールが必要なので

 $ sudo cpan
> install MooseX::Getopt
> install HTTP::Server::Simple
> install HTTP::Engine
> install JSON
> install DateTime
> install XML::Simple
とかして必要なモジュールを全部入れておきます。
ここまでして入れたら
 $ ~/WassrPod/wassrpod.pl --port 9277
で起動します。9277はproxyのサーバポートです。

ここまできたらあとはアプリケーションディレクトリのWassrPodを起動して、設定画面からwassrのアカウントを入れて、最後が肝心だけど「Enable Proxy」にチェックをいれて「Server」に「127.0.0.1」を入れ「Port」に「9277」を入れればokです。
結構無理栗なhackなのでWassrPodのアプリケーションが落ちちゃったりもしますが、結構快適に使えます。

今後の予定はwassrならではの機能をWassrPodから使えるようにwassrpod.plを拡張してく感じです。
なんでも一から作るのは大変ですが、この程度なら大変じゃなくて良い感じですね。

どうぞご利用下さい。

Posted by Yappo at 17:51 | Comments (1) | TrackBack

2008年03月03日

誰でも簡単にOpenID 2.0なOPを作る方法 and CodeReposでOpenID(2.0対応)プロバイダの提供始めましたのお知らせ

先週のbuilder techtalkから俄然としてOpenIDが熱くなって来た今日この頃いかがお過ごしでしょうか。
先日参加して来たOpenID Hackathonの成果として、CodeReposがOpenIDのOpenID 2.0 Providerになりましたことをお知らせします。
CodeReposのアカウントをお持ちの方は、fastladderとかLIMLICとかのOpenIDでサインオンできるサービでOpenID URLをcoderepos.orgとだけ打ち込んでログインしてみて下さい。
2.0に対応していない所だったらhttp://coderepos.org/share/wiki/Committers/usernameとでも入れればいいと思います。
はてなもOpenIDでログイン出来るはずなのにOpenID URL入れる所が無くてドン引きした。
暫定でIdentityをhttp://coderepos.org/share/wiki/Committers/usernameという形にしてありますが、もっと良い案がありましたら教えてくださいまし。

OpenID Hackathonに参加するまでは今イチOpenIDの仕様が判ってなかったですがようやく判って来ました。
なんだかPerlでOpenID 2.0 Serverに対応してるモジュールが無かったっぽいんですが、code.sixapart.comのリポジトリkazeburoさんのパッチをあてたら普通に2.0のOP作れてビックリしました。
このパッチもOpenID Hackathonの成果でしたっけ?

本来ならtracにOpenID OP pluginか何かを入れてやるんでしょうが、今回は勉強しながら作ったのでいびつな構成かもしれませんし、きっとZIGOROuさんがDISってくれるので、そのDIS記事見ながら改善します。

超簡単なOpenID 2.0対応のOP作り方

仕様を咀嚼してないのですが、CodeReposではこうやったよ!という例をメモります。
CodeReposのOpenID対応に関しての必要なコードやらテンプレートもCodeReposにコミットされてるので詳細はそっちで。

自分なりの用語の理解として

  • OP=認証サーバ
  • RP=OPの認証を貰う外部サイト
  • xrds=認証に必要な情報を入れた容器
  • Identity=ユニークなIDになれるURL
こんな感じ

server xrdsをRPに見つけてもらう。

RPのOpenID URLにcoderepos.orgとかを入れた時にRPはどうやって認証URLを見つけるかというと、その入力されたドメインのHTTP HEADにあるX-XRDS-Locationというヘッダに入っているURLに書いてあるファイルを見てend pointを探します。
(余談だけどHackathonでDavidに、それDNSのTXTレコードとか使えば良いんじゃないか?と聞いてみたら「更新に時間がかかるでしょ」と。納得。)

Apacheの設定だと

Header add X-XRDS-Location http://openid.coderepos.org/server.xrds
を入れるだけ。
mime typeも合わせとかなきゃいけないので
AddType application/xrds+xml .xrds
も必須。
中身は
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS
    xmlns:xrds="xri://$xrds"
    xmlns:openid="http://openid.net/xmlns/1.0"
    xmlns="xri://$xrd*($v*2.0)">
  <XRD>
    <Service priority="0">
      <Type>http://specs.openid.net/auth/2.0/server</Type>
      <URI>http://openid.coderepos.org/auth</URI>
    </Service>
  </XRD>
</xrds:XRDS>
こんな感じす。

認証する仕組みを作る

さっきのNet::OpenID::Serverにkazeburo patchを当ててhttp://svn.coderepos.org/share/websites/coderepos.org/openid/ここにあるようなコードを書いた。

IdentityのHTML中にメタ情報を入れる

RPはOPから渡されたIdentity URLに実際アクセスをして必要な認証情報の妥当性を見つけようとしてるらしいので、tracのテンプレートに

<?cs if:title ?><?cs if:string.find(title, 'Committers/') == 0 ?>
<link rel="openid2.provider" href="http://openid.coderepos.org/auth" />
<link rel="openid.server" href="http://openid.coderepos.org/auth" />
<?cs /if ?><?cs /if ?>
を追加してCommittersページの時だけlinkタグを出すようにした。
これ書くことでOpenID 1.1のOPにもなれてるんだと思う。
そして、大事な物としてIdentity URLのRespons HEADで吐くX-XRDS-Locationの中身をさっきのとは違うのにしとかなきゃいけなくて
<Location /share/wiki/Committers>
    Header unset X-XRDS-Location
    Header add X-XRDS-Location http://openid.coderepos.org/signon.xrds
</Location>
と書いて対応。
中身は
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS
    xmlns:xrds="xri://$xrds"
    xmlns:openid="http://openid.net/xmlns/1.0"
    xmlns="xri://$xrd*($v*2.0)">
  <XRD>
    <Service priority="0">
      <Type>http://specs.openid.net/auth/2.0/signon</Type>
      <URI>http://openid.coderepos.org/auth</URI>
    </Service>
  </XRD>
</xrds:XRDS>
こんなのになる。
これが良くわかってなくて一番はまった。

認証を実装

さっきPerlで書いたっていった認証 CGIの部分は実際は認証処理をしてません。
というかBasic認証でやっちゃいますので。その認証URLを見るにはBasic認証が必要なように設定します。
svnもtracもBasic認証使ってるからこそできる手抜きですね!
ただ一点気をつけないといけないのはPOSTの時は認証しないようにしとくこと。
何でかって言うとRPが認証URLにPOSTで何かしにくるから!何してるか良くわかんないけど何かPOSTしてる!

おわりに

以上の手順でOpenID 2.0対応のOPを簡単に作ることができました。
CodeReposのアカウントを持っている人は全員プログラムのコードを書けることが保証されていて(ISPのSLA的な意味で)、アカウント持ってる人数も250人を越えているので、CodeReposがOpenIDプロバイダになることは結構面白い試みなんじゃないかと思います。(OpenID Hackathonに参加する口実で作り始めただけだけど)

どう書く?.orgとかCodeGolfとかがOpenIDのRPになって連携出来るようになると面白そうですね。
OAuthとかにも対応するともっと夢が膨らむでしょうか?

海外向けに英語の記事でも書いて自作自演digしたい所だけど、英語で長文書くのがしんどいからAjiajinで英語版の記事を誰かが書いてくれるのを気長に待つ。

という事で、CodeReposのコミッターの方々はどうぞご利用ください。

追記

kazeburo patchは# 2008年03月03日 miyagawa miyagawa openid will commit on Monday. Thanks!!CommentsAdd Starらしいのでpatchもうちょっとしたらコミットされるね。

Posted by Yappo at 16:06 | Comments (1) | TrackBack

2008年01月22日

1000speakersでXenとか話して来ました

先週土曜日に開催された「1000人のダム好きを集めるプロジェクト」にてXenやらCobblerとかの話をして来ました。
発表の様子は↓のニコニコ動画で。というかうまく再生出来ない人が多いからhttp://www.nicovideo.jp/watch/sm2078669からどうぞ。

弾幕とか貼るならこっちから
yappoタグも増えて来たな。

動画環境はcojiさんが私財をなげだして素晴らしい機材を買ってくれたのでとてもかっこ良いustreamが出来ていました。
そして即座にニコニコへuploadするという神業に直立不動が止まりませんでした。

技術系カンファレンスのプレゼン動画がニコニコに溜まって来てるので、そろそろエンジニアMADってジャンルな動画が出て来て欲しいすね。
たとえば今回の発表は全部CCライセンスなのでhttp://www.nicovideo.jp/mylist/4573744ここのエンジニア素材が使い放題!
amachangは大変な強制終了をしていきました的な動画が見たいので誰か作って!

発表時間の30分前まで延々とプレゼンツールの実装をしていて、ネタを確定したのが本番30分前でした。
最初は言語的な話を考えていたのですが、レジュメみたら言語的な発表の比重が多かったので趣向を変えてみました。
デモンストレーションも特に用意していた訳でなく、個人で所有しているXenとかの実験環境にログインしといてそのまま操作しただけでした。

こんなに直前まで話す事を考えていなくても何とかなるとは思っていなかったんですが、結局は自分が面白いと思った事だったら台本が無くても説明出来ちゃう訳なんで、1000speakers dam project でもプレゼン経験無い人がどんどん出て来て成功出来ると思った。
エンジニアとかそういう人種だったら、人に伝えられる引き出しが10個以上常にストックされてて、即座にデモする環境とかを持っているので、トーク経験無い人でも緊張しても良いから出るといいよ。

さて本題ですが、今度の日曜日に鎌倉でSoozy Conference #4が開催されるのですが、懇談会会場予定のお店が最低30名から貸し切りに出来るとの事で、少なくともあと6名くらいの追加参加者を募集しています。
wikiにも書かれていないスペシャルゲストも参加するので、参加制限を緩くしたこの機会に是非ご参加を

関係無いけど

13:14 < t*kuhir*m> ドアドアってなに?
どんびきした

Posted by Yappo at 13:29 | Comments (0) | TrackBack

2008年01月04日

Cobbler Koan を CentOS な Xen で動かしたよ

Xenが熱かった今年ですが皆様いかがおすごしでしょうか。
Koan - mizzy.org - Trac

これで Xen ゲスト OS のインストールがはじまる、はずなんだけど、うちの環境では Segmentation Fault になってしまった。VMWare 上で Xen を動かすというのは無理があるのかもしれない。 実機で試したいところだけど、試せるサーバがないので保留。Yappo さんあたりが試してレポートしてくれるに違いない、きっと。
という牙指令を頂いたので試してみましたよ!

今回の環境をざっと説明すると、Cobblerを入れるマシンはCentOS5.1(i386)な環境で(master server)、cobbler importするディストリビューションはCentOS5.1(x86_64)、koanでネットワークする環境はCentOS5.1(x86_64 xen)な環境(client)です。
Cobblerを入れるマシンでは、元々ネットワークインストールする為のdhcpd,tftpd,httpdなど諸々の環境が入っていたので、とてもとても楽でした。

まず問題なのがmizzyさんはFedora 7っぽいので自分のCentOS 5.1な環境だとmizzyさんの例どおりにはできない!
といってもmizzyさんが参考にした元記事はCentOSでやってるので、そっちを参考にした。
サーバの構築を簡単にするためのステップ (その5:Cobber編 Part1 )
予め/var/lib/cobbler/settiongsで使ってるportを空けておきましょう。

Cobblerが入ったので早速import

master # cobbler import --mirror=/centos/5.1 --name=CentOS5.1
時間はかかるけどimportは簡単に終わりました。
cobblerdとかstartしたりcobbler reportでの確認や、細かい設定はmizzyさんの所を見ながらやって下さい。
Cobbler - mizzy.org - Trac

次はXenゲストOSのインストールです。簡単です。

client # koan --server=192.168.10.1 --profile=CentOS5.1-xen-x86_64 --virt --virtname=koan1
- downloading initrd initrd.img to /var/lib/xen/initrd.img
- url=http://192.168.10.1/cobbler/images/CentOS5.1-xen-x86_64/initrd.img
- downloading kernel vmlinuz to /var/lib/xen/vmlinuz
- url=http://192.168.10.1/cobbler/images/CentOS5.1-xen-x86_64/vmlinuz
- kernel saved = /var/lib/xen/vmlinuz
- initrd saved = /var/lib/xen/initrd.img
reconnect with xm console koan1
installが始まりました。
--virtnameオプションでバーチャルマシン名を指定しておいた方が良いです。
xm console koan1すれば、インストールプロセスを見る事が出来ます。

一件落着の様ですが、xenのimageが/var/lib/xen/images以下に置かれてしまうので、別のディレクトリにxenのイメージファイルを置きたい場合にはストレスが溜まってしまいます。
mizzyさんとこに書いてあるcobbler reportだとvirt-pathみたいな設定があるのですが自分所だと設定出来ません。
どうやらrpmforgeのCobbler/Koanのバージョンが古いせいだったようです。
という事で新しめのバージョンにupdateします。

master # wget ftp://mirror.linux.duke.edu/pub/fedora/linux/extras/6/SRPMS/cobbler-0.6.3-2.fc6.src.rpm
master # rpmbuild --rebuild cobbler-0.6.3-2.fc6.src.rpm
master # rpm -U /usr/src/redhat/RPMS/noarch/cobbler-0.6.3-2.noarch.rpm
client # wget ftp://mirror.linux.duke.edu/pub/fedora/linux/extras/6/SRPMS/koan-0.6.3-3.fc6.src.rpm
client # rpmbuild --rebuild koan-0.6.3-3.fc6.src.rpm
client # rpm -U /usr/src/redhat/RPMS/noarch/koan-0.6.3-3.noarch.rpm
これで新しめになったとおもいます。

準備が出来たはずなので、設定を変更します。

master # cobbler profile edit --name=CentOS5.1-xen-x86_64 --virt-path=/iscsi/xen
master # cobbler sync
master # cobbler profile report
profile         : CentOS5.1-x86_64
distro          : CentOS5.1-x86_64
kickstart       : /etc/cobbler/kickstart_fc6.ks
kernel options  : {}
ks metadata     : {}
virt file size  : 5
virt ram        : 512
virt type       : auto
virt path       :
virt bridge     : xenbr0
virt cpus       : 1
repos           : []
dhcp tag        : default
server          : <<inherit>>

profile         : CentOS5.1-xen-x86_64
distro          : CentOS5.1-xen-x86_64
kickstart       : /etc/cobbler/kickstart_fc6.ks
kernel options  : {}
ks metadata     : {}
virt file size  : 5
virt ram        : 512
virt type       : auto
virt path       : /iscsi/xen
virt bridge     : xenbr0
virt cpus       : 1
repos           : []
dhcp tag        : default
server          : <<inherit>>
無事にXenのイメージファイルのパスが/iscsi/xenに変更されました。

さっそく正しいイメージファイルのパスでinstallできるかやってみます。

client # koan --server=192.168.10.1 --profile=CentOS5.1-xen-x86_64 --virt --virt-name=koan2
- using kickstart from cobbler: http://192.168.10.1/cblr/kickstarts/CentOS5.1-xen-x86_64/ks.cfg
- no virt-type specified, auto-selecting xenpv
libvirt_qemud (pid 2870) を実行中...
downloading initrd initrd.img to /var/lib/xen/initrd.img
url=http://192.168.10.1/cobbler/images/CentOS5.1-xen-x86_64/initrd.img
- using kickstart from cobbler: http://192.168.10.1/cobbler/images/CentOS5.1-xen-x86_64/initrd.img
downloading kernel vmlinuz to /var/lib/xen/vmlinuz
url=http://192.168.10.1/cobbler/images/CentOS5.1-xen-x86_64/vmlinuz
- using kickstart from cobbler: http://192.168.10.1/cobbler/images/CentOS5.1-xen-x86_64/vmlinuz
use virt-manager or reconnect with virsh console koan2
Koanのupdateの影響で--virtnameオプションが--virt-nameとオプション名が変わってる事に注意して下さい。
インストールが終わったらlsコマンドで確認です。
client # ls -l /iscsi/xen/koan2-disk0 
-rwxr-xr-x 1 root root 5368709121 Jan  4 19:13 /iscsi/xen/koan2-disk0
ちゃんと/iscsi/xen以下にイメージファイルが出来ました。

これから更に発展させてDSASのようなネットワークブートするイメージの管理をCobblerを使って実現とかしてみたいよね、とか話していたらmizzyさんにStateless Linuxを教えてもらいました。
どっちにしろinitrdとかイメージとかを自分で作ってかなきゃいけないので、もすこし色々やってみようと思います。

Posted by Yappo at 20:12 | Comments (0) | TrackBack

2007年12月31日

CodeReposへのコミットをリアルタイムに通知する仕組みあります

commit-ping/SITEINFO - CodeRepos::Share - Trac

CodeReposにcommitされるとこのページの Commit Ping Servers 以下にかかれているURLに対してコミットの情報がPOSTされる仕組みです。
yamlというパラメータ名でYAML形式に変換されたコミットデータがPOSTされます。
ということでアナウンスしてないけど、こんな仕組みが有ります。

svnのcommit hookを使って、Commit Ping Servers以下に書かれているURLに対してコミット時のメタデータをPOSTで送信します。
POSTする時に詰まると嫌なのでTheSchwartzを使って非同期的に処理しています。

是非面白いことをやってくださいー

Posted by Yappo at 23:22 | Comments (0) | TrackBack

2007年12月25日

GoogleのMapReduceをいまさら妄想した

ブームとかそういうのはあんまり関係無いけど、MapReduceについての妄想だけしてみた。

主要コンポーネント

MapReduceには大体6つのパーツから構成される。

clientshellから叩かれるコマンド的な何か
manager各種 worker を管理する。といっても投げっぱなしで結果がいつまでも帰ってこなかったらworkerを捨てるだけ。同じjobを複数のworkerに投げてる。
map workermapの処理
combinermapの直後に実行出来るreduceのような物、無くても構わない、出力はmapと同じ?
shuffle(Group by Key)map workerから帰って来たkey/valueを集約する
reduce workerreduceの処理
fs分散システムに対応したfsと、local disk

処理内容

mapに対しては任意のデータが与えられる。 mapはkeyとvalueからなる大量のデータを戻す。 shuffleにて、全てのmapのkeyをまとめあげて、keyごとにreduce workerにkeyとvalue listを渡す。 reduceは、受け取ったkey/value listを処理する。

key/valueなデータに特化したPlaggerってことで間違いないのかなぁ? mapperで大量のデータから必要な物をフィルタリング(Subscription,Aggregator)して、reducerで実際の処理(Filter,Publish,Notify)を行うというPlaggerみたいな感じ。

全てのmapやreduceに大しての各workerの仕事量は平均的になる様にバランス良く配置する。 多分、mapやreduceの直前で、それぞれのjobの大きさを計測してmanagerに渡したりしてるのかな。

shuffuleなんかはBig Tableとか使ってるのかもしれんね。 それか集計処理自体MapReduce使ってたり?

map workerの処理が全て終わったら reduce worker が走り出す。 これは、あるいみ無駄な気もするからmap workerが終わるのを待たずにreduce worker走らせてるだろうなぁ。(どうもそうでもないらしい。) mapとshuffuleは同時に処理出来るけど、reduceは他と一緒に処理出来ないそうな。key/value単位で処理するというMapReduceの設計的な制約かな? map,reduceが終わりそうになったら、まだ終わってないworkerのjobをそのまま空いてるwokerに投げて速く終わったworkerの方のresultを採用する事で、途中でworkerがコケても泣かないですむ。

mapとreduceの粒度は細かくした方がよい。 mapperでserialize、reducerでdeserialize。 mapだけ繰り返し呼びたい時はreduceからmapを呼び出す。

オレオレ実装するとしたら

この仕組み自体は対した事無くて、肝は大量のデータを、たくさんのmap workerやreduce workerへjobを投げたりresultを受け取る仕組みとshuffleする処理にある。 ちゃちいものだったらDanga::Socketとかで実装出来るレベルっぽいな。 もちろんGFSも肝だけど、memcachedとかでとりあえずいい気がする。(可用性おいとくという事) というかMapReduce自体もGearmanで構成出来たりしね?

実際問題としてオレオレでMapReduce作る時に考える事は、データとコードを各worker serverに送る仕組みを真っ先に考えなければいけない。 単純にjobを分散出来た所で、それはMQとかに毛が生えた程度の面白さしかないから、分散ストレージ的な物もセットにしないとオレオレMapReduceもどきとは言えないだろうけど、memcachedとか使えば解決するよね?よね?

CPANにMapReduceってモジュールが有ったんだけど、何故か削除されてる。。。backpanには残ってる。

もっとも忘れてはならないMapReduceの肝は、1 serverで並列処理をしてCPUがmulti coreしてる恩恵を受ける為に有るのではなく、大量のworkerを使う事によって大量のメモリを利用したり、大量のdiskを使う事によるi/o負荷を分散させる事に意味が有る。 それなんで、WebからMapReduce使う用な事はないのかね?

でも少数serverでMapReduceやったって良いじゃないか!

Posted by Yappo at 21:31 | Comments (1) | TrackBack

2007年12月10日

PowerEdge SC440をQuad Core + 8GBメモリで動かす

はてなのnaoyaさんの日記でQuad CPUでxenを動かしてるという事が書いてあったので、自宅でもはてなのサービスをまねた構成をしたくなったので人柱やってみました。
タイトルの通り、1万5千円で買ったSC440をDELL公式のスペックよりもオーバースペックな事をして動かしました。

まずは、メモリから。
ミラクルリナックスの中の人曰くマザーボードの仕様的には8Gまでいけて、8Gちゃんと認識したという事で、以前から買い漁ってたTranscendの1GB DDR2 667MH ECC メモリの 2GB 番の TS256MLQ72V6U 4枚買って来て刺した所 BIOSでは8G認識してるのにOS上げたら3.5Gにも満たなかった、よく考えて64bit番のCentOS入れたら無事8G認識しました。

次はCPU、SC440はXEON 3040 というFSBが1066MHzのCPUが刺さるので、同じFSBの4コアCPUのQ6600をさっき買ってきたら普通に認識して/proc/cpuinfo的にも4CPUの扱いになりました。
ただ、購入したSC440はファン無しのヒートシンクなしマシンなので、調子に乗ると大変な事になりそうで恐い。

そういえば、自宅を整理してちゃんとPowerEdgeを棚に載せました。
PE_SC440_1.jpg
PE_SC440_2.jpg
PE_SC440_3.jpg
PE_SC440_4.jpg

今時のWEBエンジニアは、このくらいの環境を自宅に置いとかないとだめだと思う。

併せて読みたい:お家NOC

インテル Core 2 Quad Q6600 2.40GHz BOX BX80562Q6600
インテル
売り上げランキング: 8565
おすすめ度の平均: 5.0
5 なかなか爆速です。

Posted by Yappo at 00:13 | Comments (4) | TrackBack

2007年12月07日

Tracで自分の追いかけたいディレクトリの変更ログだけを簡単に取り出す為の3個の手順

リポジトリへだんだんと全体のcommit流量が増えて来ると自分の突っ込んだプロジェクトに誰かがpatchを書いても気づかない事が出て来ます。
例えばCodeReposなんかがそうで、困っていた訳です。

さっき知ったんですが、tracは各ディレクトリ毎のコミットログをRSSで出せるので、これを活用して目的を達成します。
具体的にはtracのtemplateを少し追加するとRSS Auto Discoveryできるようになるので、まずはAuto Discovery出来るようにしました。

次は、誰がどのプロジェクトに関わってるかをまとめる訳ですが、これはXOXOというMicroformatsが使えるので、各コミッタページにXOXOで自分のプロジェクトディレクトリへのリンク集を書きます。
自分の場合はhttp://coderepos.org/share/wiki/Committers/yappoこんな感じです。
Tracに生HTMLを書かなければいけないのですが

{{{
#!html
<ul class="xoxo">
 <li><a href="http://coderepos.org/share/browser/lang/perl/Acme-Jyogakusei">Acme::Jogakusei</a></li>
 <li><a href="http://coderepos.org/share/browser/lang/perl/Acme-tsundere">Acme::tsundere</a></li>
 <li><a href="http://coderepos.org/share/browser/lang/perl/Class-Component">Class::Component</a></li>
 <li><a href="http://coderepos.org/share/browser/lang/perl/dan">dan</a></li>
</ui>
}}}
こうする事で生HTMLがかけました。

さぁ準備は整いました、あとはfeedをまとめるだけです。
これはもうPlaggerという優秀な裏ソフトがあるので活用しない手は無いです。
configはhttp://coderepos.org/share/browser/config/plagger/coderepos-commiter-smartfeeds.yamlこんな感じでおkでしょう。
出来上がったFeedはhttp://tech.yappo.jp/coderepos-yappo.xmlにあります。

ね、簡単でしょう?

Posted by Yappo at 16:13 | Comments (0) | TrackBack

2007年10月25日

DELL PowerEdge860届いた

ちょっとまえに投げ売りしてて注文したのがさっき届いた。
IMG_2681.jpg

Xeon 3060 2.40GHz/4M L2 cache
512M ECC memory
HDD 160G
これで7万円切ってた!!安過ぎる!
IMG_2683.jpg

メモリ512じゃ全然足りないので、1Gメモリ4本刺して使う事にした。4本でも22,000円くらいしかしない。
IMG_2686.jpg
あと、HDDは2個目も簡単に付けられそうなので、安い大容量HDDもくっつけておくつもり。500Gで11,000円くらいみたい。
IMG_2682.jpg

約10万円で
Xeon 3060 2.40GHz/4M L2 cache
4G ECC memory
HDD 160G + 500G
な1Uサーバが出来てしまった。DELLすごいよDELL

実際はラックレールマウント17,000円と記念にフロントベゼル3,000円買ったけどね。あと送料5,000円も追加。
それでも安いけど。

デフォルトでついてるメモリがhynix性でちょっと前に大人買いしたSC440と同じ物だったので、SC440に512Mメモリ二枚刺しして3Gで使えるな。
SC440は1Gメモリ4枚刺すとちょっと損した気になるので3Gくらいがちょうどいい。

しかしメインのappサーバよりもハイスペックになってしまうので、アプリケーション構成をどう変えるか悩む。
基本dmaki productsでクロウラーやれば良いのかな?

Posted by Yappo at 15:02 | Comments (2) | TrackBack

2007年10月04日

はてブのエントリページに出て来るクリッピングサイトを消してくれるグリモン書いた

みなさんは、はてなブックマークの「このエントリーを含む日記」をクリックして何か言及があるかと思ったら、クリッピングサイトで特に言及がなかった経験はありませんか?
また、自分のエントリに「このエントリーを含む日記」が付いてて、よく考えたら特定数以上のusersが付いたエントリを自動収集してる日記だったりしてがっかりしませんでしたか?

このはてブクリッピングサイトリムーバは、そんな貴方のお悩みを解決してくれる優れたuserscriptです。
このユーザースクリプトを入れるだけで、これらクリッピングサイトがエントリリスト画面から無くなってしまいます。

hatebu clipping site removerを入れたときのキャプチャ
hatebuclippingsiteremover.png

ちなみに消してるサイトは、ざっくり見てクリッピングサイトっぽいのだけをピックアップしてるので、間違ってる可能性もあります。
最初はsplog removerとかいう過激な名前だったけど、ちょっとやり過ぎなので名前変えました。
ダウンロードはhttp://svn.coderepos.org/share/lang/javascript/userscripts/hatebuclippingsiteremover.user.jsから

XPathの練習かねて作っただけだけど

Posted by Yappo at 23:55 | Comments (0) | TrackBack

2007年09月17日

第2回モバイル勉強会で発表して来ました

モバイルがテーマなので、今回は技術よりの話はしてませんが

  • ThirdForce普及の話
  • メールに件名入ってないの話
  • itkz係数について
  • GopherのPR
  • CodeReposのアピール

をテーマに発表して来ました。

取り急ぎDanさんメソッドで資料を上げときました。
若干修正済。
http://tech.yappo.jp/docs/mobaben2/

ustreamで配信されていてhttp://ustream.tv/channel/mobabenにて録画したアーカイブを視聴出来るようです。

Posted by Yappo at 18:50 | Comments (11) | TrackBack

2007年09月11日

CodeReposのircチャンネルとOhlohの件

ちゃんと告知してなかったのですが、CodeReposのircチャンネル作りました。
普通に #coderepos@freenode です。
codereposbotが常駐していてtimelineをnoticeしてくれます。

typesterさんの提案でOhlohにも登録しときました。
CodeRepos::Share - Ohloh

最初はPerlだけか?と思われ気味でしたが、現在は7言語のディレクトリがあります。
どしどし参加してくだしあ

Posted by Yappo at 22:48 | Comments (0) | TrackBack

2007年09月08日

ITPro ChallengeのLTに出て来ました

インターネットに不自由してる旅先で、つい魔が差してLTに応募したら採用されたので話して来ました。
初の試みとしては、話してる最中の様子をustreamで配信してました、といっても自分の胸ばかり写ってたかもです。そして23viewersくらいあったようです。
内容は、ごにょごにょしたのと、今空前のブームであるGopherのGopperのPRとCodeReposの宣伝して来ました。
あと、はてなスターのTシャツを着てプレゼン中にスターのアピールをしたのに、話し終わった後naoyaさんが怒ってた気がする。
やっぱり、はてなブックマークのアピールをしなかったせいだろうか。ふしぎ!
以外とGopherネタをわかってる人がおおくてよかた。

資料はhttp://tech.yappo.jp/docs/itprochallenge/にて。
キーボードの上下左右キーで操作出来ます。
後日Youtubeとニコニコ動画でプレゼンの様子をアップロードしてくれるそうです。
また、反応リンク集は便利な、はてなブックーマークをご利用ください。

id:amachangのS6を使いました、というかLL魂の資料のコピペです><
今までS6をちゃんと見てなかったんだけど、初めて使ってみようと思ってから直に使えるのはいいっすね。
amachang++

Posted by Yappo at 12:41 | Comments (0) | TrackBack

2007年08月31日

CodeRepos - 個人レポジトリを共有しよう!計画

typesterさんのつぶやき

みんながそれぞれ作って公開してる公開レポジトリを一緒くたにしちゃいたい。参加してる全員がどのファイルもみたり変更したりできるような。

パッチ送られてくる代わりに「後で見とくからコミットしといて」とかいえたりとか、つくりかけで放置したもので他の人が興味もったら続き作ってもらうとか、メンテするのめんどくなったのだれかにやってもらうとか、突発的に誰かと一緒にプロジェクト始めたりとか、できる!
に呼応する形で共有レポジトリを作りました。
http://coderepos.org/share/

特に明確な方向性とかはきまってませんし、決まるかどうかもわかりませんがtypesterさんのつぶやきを現在の方向性という事にしておきますか。
昨日作ったばかりで、今はディレクトリ構成どうしようかとかそういう事をircとかtwitterとかで話し合っているので、ディレクトリ配置が変わっちゃったりするかもですが、落ち着いてきたら配置も固定になると思います。

現在commitしてあるコードはperlの物だらけでperl専用?とかの疑問も出てましたが、どんな言語とか問わずcommitしちゃって問題ないです。
言語とかのレベルを越えて、以前流行ったdot-file公開ブームのようにdot-fileとかplaggerとかのsoftのconfigファイルの共有が出来たら面白そうです。

CodeReposに登録されてるファイルにパッチ書きたくなったり、CodeReposに自分のソースを放流したくなった方はhttp://coderepos.org/share/に記載されてる連絡先までhtpasswdで作ったファイルの中身を送って下さい。

Posted by Yappo at 19:19 | Comments (0) | TrackBack

2007年06月01日

VirtueDesktops の 0.54 Beta 3 (339) が酷すぎた件

Betaリリースなんだから煩いぞ!とお叱りがあるのは分かりますが、ああ、あと自分が使ってるソフトの組み合わせが悪いって事の検証もしてない、する気力も消えた。。
ググっても数件しか、この話題が見つからなかったから書いとく。

初代MacBook上のOS 10.4.9の上でVirtueDesktops の 0.54 Beta 3 (339) を使っていたんですよ。
それは置いといて、ここ最近は1日辺りに500M以上も空きディスクが減ってったわけですよね。
最初は仮想メモリにでも使ってんのかなとか楽観的に見てたんですが、この数日は余計なでかめなファイルを消して行ってギガバイト単位で空き容量をせっせこ作ってたわけです。

昨日、ついに異変に気づきdf -iとかしてたら秒単位でinodeが5づつくらい減ってるんです。
しかも数百KBも要領を消費しながら!
これは明らかに可笑しいので、ここ最近入れたソフトを調べ、VirtueDesktopsを終了させたらディスク消費が収まったので犯人が解ったのです。

で、ググって見て何にディスクを使っているかというとLogファイルらしく

$ ls -l ~/Library/Logs/VirtueDesktops.log 
-rw-r--r-- 1 my my 12082867527 Jun 1 13:15 ~/Library/Logs/VirtueDesktops.log
とかいう酷い事になってました。
このログの中身をheadして見ると5月16日から記録が始まっているので、多分VirtueDesktopを最新のβ版に入れ替えた後からロギングしてるようです。
βなのでデバグ出力かな?

ファイナルリリースでてたみたいだけど、もうこのバージョンの使うの辞めて0.52 (138)を使ってLogも消して奇麗さっぱり忘れてしまおう。

Posted by Yappo at 13:35 | Comments (13) | TrackBack

2007年04月02日

YAPC::Asia 2007TOKYOに出て来ます。

初参戦で、3個発表する事になりました。

長めの内容2本LTです。

頑張って資料作ります。

なんあk昨日の記憶があまりない。ジャガイモの芽が出て来たよ!春っていいですね!

Posted by Yappo at 10:00 | Comments (0) | TrackBack

2006年12月21日

IEがWeb2.0に対応していなかった件

既出ネタかどうか分からないけど、iframe name tagsでググっても情報でて無いので書いておきます。
特定のタグやname属性をHTML中に記載するとIEのCtl-Fでのページ内検索やプリント機能が使えなくなります。

詳細は以下の通り。

iframeタグを使用したHTML内で、name属性が使えるタグのname属性にtagsを指定すると、IE6ではページ内検索を実行したときとページプリントを行ったとき(プレビューだけでも化)にエラーダイアログが表示されてしまい、検索や印刷が出来ません。
IE7で直ってるかと思いきや検索だけは出来ません。
エラーコードがIE6とIE7で違うため、バッファオーバーフロー的な何かがIEの中で起きていると思われます。

再現する最小ソースは

<iframe></iframe><img name="tags">
これだけで再現しました。
サンプルページは下記の通り。
imgタグ
inputタグ
aタグ

なんでこんなんで駄目になるのかは分かりませんが、マイクロソフトはtagを用いたWeb2.0的な物がお嫌いなんでしょうか。
DOM操作とかでiframeを構築して行ったらどうなるかは試していません。
あと、javascript無効にするとどういう挙動になるとかも見てません。


どうにかしてIEのみでしか見れないページを作れば、印刷不可能なページの作成も物理的に可能そうです。

追記:12/22
id:holidaysの人が詳細を追いかけてくれました。
holidays-l開発ブログ - IEで印刷できないページ

としてみたところ、document.all.tagsというnativeな関数を呼び出していました。(document.all.tags = document.getElementsByTagName?)
nameで上書き出来る場所に重要なのを置いていたと言う事なんすかね。
iframeがあっても無くても関係ないみたいです。
iframeを無くすと印刷できませんが検索は出来る様になります。で、iframeを入れると何故か検索が出来なくなると。
やっぱり不思議です。
name使わないでidというのも諸事情で却下す。

Posted by Yappo at 23:09 | Comments (2) | TrackBack

2006年11月20日

the spam退治の能率を100倍うpする方法

最近あり得ないくらいにspamが来てて、過去に行ったアジア全て(台湾、韓国、中国)からのip接続のblockも意味なくなってしまって途方に暮れたのですが
初心に返ってSpammAssassinを真面目に使う事を思いついた。

家はmew使ってて+spam/にspamに振り分けられたメール、+spam/spam/にspamから漏れたメール、+spam/ham/に誤爆したメールを振り分ける様にしてるんだけど。
学習させるたびにコマンドうって、学習させたメールを+trash/にやるのがだるくて使ってなかった。

そこで最近学習した、面倒い事はちょっとしたツールで対処ってのをやった。

$ alias spaml="sa-learn --spam $MAILDIR/spam/spam;rm $MAILDIR/*"
これだけ作ったんだけど、spamlってやれば+spam/spam行きのメールをspam扱いにしてrmしてくれる。
今の所誤爆もないのでhamもやっていない。

これだけじゃ、まだだめでMewの操作も簡潔にしないと漏れたspamが100件とかきたら辛いのでemcasのマクロを登録。
普段だとosp<TAB>s<TAB><RET>な感じでキーを打っているのでこれも楽にしたい。
.emacsをにちょっと追加

(fset 'my-mew-set-spam
"ospam/spam\C-m")
(define-key mew-summary-mode-map "zz" 'my-mew-set-spam)
これでzzで振り分けられる様になった。

意外にspamの認識力が高くなって来て、spamフォルダに毎日500くらい自動的に行ってる。
spam退治が100倍以上効率うpした!

ので、能率が100倍うpした。

Posted by Yappo at 22:15 | Comments (0) | TrackBack

2006年11月15日

悪のりで学ぶsvnadmin/trac入門実用編

とある平和なある週末に事件は起こった
xx:14 ([aopy]+) stfuawsc汚染なコードをciってまった

xx:14 (A) ちょ
xx:14 (B) ww
xx:14 (C) www
xx:14 (D) stfuawsc
xx:14 {[ainOS]+} パネラーディスカッション
という事で、直近のコミットした内容をこの世から抹消しなければならなくなった。
しかもtrac上のデータもあわせて..!
消したいリビジョンは100である。

svnのデータを消す

コマンドだけで直前のコミットを取り消せないものかと調べたが、出来ないという事が分かった。
ちょっと冷静になって、svnadmin dumpとsvnadmin loadの組み合わせで何とか出来ないか?と考え
$ svnadmin dump /svn/public > /tmp/public.dump
して該当データを探してみた
Revision-number: 100
Prop-content-length: 112
Content-length: 112

ここからデータ

最後のほうに、該当するデータっぽいのを発見出来た、Revision-numberも100と書いてあるので、当たりっぽい。
Content-lengthとかもあって大分親切。なんかmailのフォーマットぽい。

って事で、このRevision-number: 100の行からファイル末尾まで削除して

$ cat /tmp/public.dump | svnadmin load /svn/public.new
$ mv /svn/public /svn/public.old
$ mv /svn/public.new /svn/public
した。
そして、手元のcoしたディレクトリでsvn upしてみたら
Reference to non-existent revision 100 in filesystem '/svn/public/db'
と言われたお><
落ち着いて
$ svn up -r 99
したら、エラーが出なくなった。

これでsvnの証拠隠滅は完了した。

tracのデータのつじつまあわせ

気を良くしてtracにアクセスしたら、見た事のないエラーが出てびっくりした。
そりゃそうだ、リポジトリの中とtacの中のデータが不整合してるからだ。

tracはsqliteつかってるので

$ sqlite3 /trac/public/db
してsqlを使える状態にして、あれこれ調べた。
で、大体消す場所を把握したので
sqlite> delete from revision where rev = 100;
と打った、しかしtracがまだ怒ってる!
もう少しデータを漁って、ようやく別の消すデータを発見
sqlite> delete from node_change where rev=100;
これでどうだ!

見事、問題のコミットは帳消しに出来ましたとさ。
めでたBoofyめでたBoofy

追記:
svnのいらないリビジョンはsvnadmin dump -r 0:99 | svnadmin load とかで消せて。
trac-admin resync で同期が取れるそうです。

みなさま突っ込みありがとうございます。

Posted by Yappo at 23:32 | Comments (2) | TrackBack

svk startup memo

生のsvnを使っていて良いのは中学生までなのでsvkを始めました。
といってもmacbookの方にはsvkを入れてたんだけど、あまり使っていなかったのでメインの開発環境にsvkを入れました。

ありきたりでつまらない内容ですがチラシの裏です。

install

SVN::Mirror 0.72 は subversion 1.2 以上を要求してくるので、手元の環境で使えずに0.71を入れました。
LANG=jaな環境でinstallするとtestこけるのでLANG=C cpanな感じでinstallです。

そしてinstall SVKなのですが、06keyword.tでなんかこけるのでforce installです。(SVK 1.08)
こけてる内容もクリティカルじゃ無いっぽいので無視です。
なんかsvk-devにも報告あがってるみたいだけど、よく読んでない。

setup

$ svk mirror http://svn.yappo.jp/repos/public/ //mirror/public
$ svk sync //mirror/public
$ svk cp //mirror/public //public
教科書的にミラーを作ってローカルブランチ作成です。

import to local

importしたいファイルのカレントディレクトリで
$ svk import //public//proj/trunk -m 'proj import'
してがしがしimportしました。
ローカルに連続でimportしてってもいいし、一個importするたびにほんとのリポジトリにうpしてってもいいのかな。
一個一個やってったほうが奇麗かも。理由はあとで。

commit to remote

smerge

ローカルブランチのcommitをリモートの本家リポジトリに反映します
$ svk smerge //public //mirror/public -m 'commit message'
これで、全ての変更内容がhttp://svn.yappo.jp/repos/public/に反映されます。
全部いっぺんがいやなら
$ svk smerge //public/Soozy/trunk //mirror/public/Soozy/trunk
でもいけるはず。まだ試してないけど。
これだと、手元で細かくcommitしてるのに本家は荒くなっちゃうので
$ svk smerge -l //public //mirror/public
として、ローカルのコミットログをまとめて送れるようになります。
いったんコミットメッセージをエディタに流し込んでくれる形なので、任意な形でコメントが書けます。
これでも、diffの内容としては荒いので
$ svk smerge -I //public //mirror/public
として、ローカルの1コミット毎の内容をそのまま本家に転送します。
ローカルで上げたリビジョンの数だけ本家もリビジョン上がる感じです。
これやった瞬間に本家に全部コミットされるので注意です。

で、importしたときにsvk smerge -Iとかしちゃうと、2回分のログが発生するのでimportしたらオプション無しのsvk smergeして2回分を1回にまとめちゃうと奇麗かなぁと思いました。
http://trac.yappo.jp/trac/changeset/178みたいな感じです。
纏めないとhttp://trac.yappo.jp/trac/changeset/181http://trac.yappo.jp/trac/changeset/182のように2回に分かれます。

どうでもいいっすね。

svk push

カレントディレクトリのリポジトリをsmergeするって感じすかね。
ここでは
$ svk co //public ./public
cd ./public
したものとして書いてます。
ローカルの1コミットを纏めてコミットする
$ svk push -l

バラバラでコミットする
$ svk push

svkが付けるコメント

特にオプションつけないでsmerge/pushすると
r196@haruna: ko | 2006-11-15 19:51:20 +0900
みたいなコメントが自動的に付与されますが、これを消したい場合は--verbatimオプションをpush/smerge時に付ければ消えます。

よく考えれば、普通はsvk pushを使うね。
こんかいはimportしまくったからsmergeしただけか。

svk pull

svk co //publicでチェックアウトした先のディレクトリでsvk pullすると、本家リポジトリが変更されてたら、//mirror/publicもupdateした上で//publicもupdateして、手元のディレクトリの内容もupdateしてくれた。
pullした時のmirror/local/currentdirを通したコリジョンとかの扱いはよくわかってない。

push/smergeする前に-Cオプションで変更点を確認しないと高校に入れないので注意。

以上、チラシの裏Boofy

Posted by Yappo at 21:15 | Comments (0) | TrackBack

複数のsvnリポジトリを一つにまとめる方法

うちのsvnリポジトリは、trac等で公開をする前までは、各コンポーネント毎にリポジトリを作るという非効率な管理をしていました。
そろそろ嫌になって来たので、これを全部公開用にまとめようと思い、helpみながら頑張りました。

要件的には、リビジョン番号が変わっても良いから、とにかくlogを含めてインポートしたい!
という感じです。

最初はsvkとか使わなきゃだめなのかなぁ、とか思ってたのですがsvnadminだけで願いが叶いました。
dumpとloadを使います。
loadする時はオプション無しでloadしてしまうと、dump前のファイルパスにデータをぶっ込んでくれちゃうので、trunkとかが混ざってカオスになっちゃいました。
そこで--parent-dirオプションを使って、どのパスにloadするかを明示的に指定してloadします。
--parent-dirで指定するパスは、読み込ませる側のリポジトリ内に予めmkdirしておく必要が有ります。
/svn/Acme-Monta のリポジトリを /svn/public_repos に入れたい場合は

$ svn mkdir -m 'create import dir' file:///svn/public_repos/Acme-Monta
$ svnadmin dump /svn/Acme-Monta | svnadmin load --parent-dir Acme-Monta
のように作業します。
commit日時は引き継がれるので、リビジョン番号と日時の並びが変になりますが気にしない感じで。
影響でtracの最近のtimeline消えた!

これで、作業環境がすっきりしました^^
あとはsvkを本格的につかいまする。

それsvnadminでできるよ
それsvn

Posted by Yappo at 18:44 | Comments (0) | TrackBack

2006年09月28日

価格.com API JSONPと、JavaScriptテンプレートキットの組み合わせ

価格.comのAPIが話題になってますが、APIの結果をJSONPで履いてくれる価格.com API JSONPが公開されていたので、先日のテンプレートの奴と組み合わせて物を作りました。
本来なら価格.com本体でJSONP吐いてもいいんですけどねぇ。。。ケチ。。。

http://tech.yappo.jp/demo/kakaku/
JSONPだけでAjaxの動的検索っぽい事をしています。
作り方は、とても簡単なのでソースを読んでみるといいと思います。

もっともっと単純な方法は

<div class="kakaku">
<table>
<tr>
<td><a class="[% $ItemPageUrl | attr 'set' 'href' %]" target="_new"><img class="[% $ImageUrl | attr 'set' 'src'%]" /></a></td>
<td>
<table>
<tr>
<td>製品名</td>
<td><div class="ProductID"></div><a class="[% $ProductName | inner %][% $ItemPageUrl | attr 'set' 'href' %]" target="_new"></a></td>
</tr>
<tr>
<td>カテゴリ</td>
<td><span class="CategoryName"></span>(<span class="PvRanking"></span>位)</td>
</tr>
<tr>
<td>メーカー</td>
<td class="MakerName"></td>
</tr>
<tr>
<td>最安値</td>
<td class="[% cat $LowestPrice '円' | inner %]"></td>
</tr>
</table>
</td>
</tr>
</table>
</div>
<script type="text/javascript" charset="euc-jp" src="./cjtk.js"></script>
<script type="text/javascript">
var cjtk;
var config = {
classname: 'kakaku',
foreach: true,
url: 'http://jsonp.yatena.com/' + encodeURI('ipod'),
};
cjtk = new Cjtk(config);
cjtk.process();
function kakaku_ws(obj){
cjtk.callback(obj.Item);
}
</script>
のように記述すれば下記の様に表示出来ます。
http://tech.yappo.jp/demo/kakaku/body.html
この方法だとキーワードが固定になるけど、使い出はあるかもです。
これはipodで検索する様になってますが、アップルにしたければ下のJavaScriptの部分を
    url: 'http://jsonp.yatena.com/' + encodeURI('アップル'),
にしてください。

ツールがそろってくるとマッシュうpも楽になりますな。

という訳で、テンプレートキットの販促活動でした。

Posted by Yappo at 19:39 | Comments (2) | TrackBack

2006年09月26日

CJTK - JSONPとJavaScriptを使ったテンプレートキット作った

JSONPなどでデータを取得して、HTML中の任意なAttributeにマクロを埋むタイプのテンプレートキットを作りました。
別にJSONPじゃなくても、staticもデータ構造を定義する事も出来るし、Ajaxサポート書けばAjax経由でデータを取得できます。
マクロ展開はDOM探索で色々処理をしています。 Model = JSONP 、 View = DOM って感じかも。

他にもJKL.Hinaや、JSmartyなどがあります、大きな違いは専用構文を利用しないでテンプレート展開が出来たりと、かなりシンプルです。
他の特徴は
・DOM操作のみでテンプレート展開
・JSONP対応
・テンプレート用のデータ領域を用意する事無く、HTMLに直接テンプレートを記入出来る
・データ展開先を設定不要。class要素などからテンプレートエンジンが、自動的に展開先を選択する
・DOM操作を基本としてる為、if/foreach等のスコープが実際のHTML構造と連動していて直感的
・DOM要素の属性を柔軟にカスタマイズできる
・フィルタチェイン
・フィルタの拡張が可能
などなどです。

デモ用のサンプルはhttp://tech.yappo.jp/demo/simplemacro/
tracはhttp://trac.yappo.jp/trac/browser/javascript/cjtk/trunk
svnは

svn co http://svn.yappo.jp/repos/public/javascript/cjtk/trunk

チュートリアル


simple injection

マクロと言っても、簡単に使う分には専用の言語らしき物は見えません。
たとえばdel.icio.usのJSONPだと(http://del.icio.us/feeds/json/yappo?callback=delisious.callback)

new Array(
{
u: url,
d: タイトル,
n: コメント,
t: new Array(tag1, tag2)
},
{
u: url,
d: タイトル,
n: コメント,
t: new Array(tag1, tag2)
}
);
の様な構造になっているので、これを簡単に展開したい場合には
<javascript>
var config = {
classname: 'delicious', // class属性がdeliciousのDOM要素をテンプレートとして使用する
foreach: true, // 上記で取得したDOM要素を元にして、JSONPで取得じた全レコード分を展開
url: 'http://del.icio.us/feeds/json/yappo?callback=delisious.callback', // JSONPのURL
};
var delisious = new Cjtk(config);
delisious.process();
</javascript>
<div class="delicious">
<div class="u">URL:</div>
<div class="d">タイトル:</div>

</div>

とかけば、「URL:」や「タイトル:」の後に、それぞれURLとタイトルが挿入されます。
と、単純なデータ/展開方法であれば非常に完結にテンプレートを組めます。

attribute injection


さて、単純なのは良いのですが、これではリンクを張ることが出来ません。
そこで、マクロ構文が出て来ます。
リンクを張るためには、HTMLを次のように変更します。
<div class="delicious">
<div>URL:<a class="[% $u | attr 'set' 'href' %][% $u | inner %]</a></div>
<div>タイトル:<a class="[% $u | attr 'set' 'href' %][% $d | inner %]</a></div>

</div>

これで、URLとタイトルそれぞれにURLへのリンクが張られます。
このマクロの構文は微妙にTTっぽい気もしますが、UNIXのpipeの概念の方が近いです。
たとえば
<div class="[% 'D' | $d %][% 'A' | cat 'B' 'C' | cat $d | inner %]"></div>
なんて事が書けますが、これを分りやすくコメントを付けると
<div class="[% 
'D' | $d # $dという変数に文字列'D'をセット
%][%
'A' | # 文字列'A'を次の処理へ転送
cat 'B' 'C' | # 文字列'A', 'B', 'C'を順番に結合して、文字列'ABC'を作成して次の処理へ転送
cat $d | # 文字列'ABC'と変数$dの中の文字列'D'を結合して、文字列'ABCD'を作成して次の処理へ転送
inner # 転送されて来た文字列'ABCD'を、現在のDOM要素の子TextNodeとして追加する
%]"></div>
と、こんな感じになります(実際は#のコメントは書けません)。

if / unless


次に条件によって要素を表示したく無い場合があるでしょう。
たとえばdel.icio.usのコメント何かがそれにあたります。
そんな場合はifやunlessが使えます。
<div class="delicious">
<div class="u">URL:</div>

<div class="d">タイトル:</div>
<div class="[% $n | if %]"><div class="n">コメント:</div></div>
</div>

ifはパイプの前の処理結果があれば(もしくは0でなければ)子要素を表示します。
unlessは逆の条件です。
もしifの条件に一致すれば
<div class="delicious">
<div class="u">URL:</div>

<div class="d">タイトル:</div>
<div class="n">コメント:</div>
</div>

と表示され、一致しなければ
<div class="delicious">
<div class="u">URL:</div>

<div class="d">タイトル:</div>
</div>

となります、defaultではif/unless文のあるDOM要素は削除されます。
もし削除したくない場合にはBKっぽく
<div class="delicious">
<div class="u">URL:</div>
<div class="d">タイトル:</div>

<div class="[% $n | if '1' %][% $n | inner %]">コメント:</div>
</div>

と書くことも可能です。
ifのあとに1を加える事で、ifがあるDOM要素を削除しません。

foreach


del.icio.usの場合はtag要素が配列として渡されます。
配列要素を展開する場合にはforeachが使えます。
<div class="delicious">
<div class="u">URL:</div>

<div class="d">タイトル:</div>
<ul class="[% $t | foreach 'tag' '1' %]">
<li><a href="http://del.icio.us/tag/" class="[% $tag.v | attr 'append' 'href' %][% $tag.v | inner %]"></a></li>
</ul>

</div>

ulというDOM要素を削除しないままtagの数だけliタグを展開します。
attr 'append'することで、aタグ中のhref="http://del.icio.us/tag/"を消さずに、http://del.icio.us/tag/tagの様なリンクを張るようになってます。

応用


レコードIDが確定してる場合

次のようなレコードのIDが固定的なデータの場合にはforeachオプションでテンプレート展開をせずに、レコードIDを指定したテンプレート構築が出来ます。
レコードIDはdefaultではtitle属性に入れます。
例えば

var json = {
hatena: {
url: 'http://www.hatena.ne.jp/',
cto: 'naoya'
},
mixi: {
url: 'http://www.mixi.co.jp/',
cto: 'Boofy'
}
};
なデータの時には
<javascript>
var config = {
classname: 'mixna', // class属性がmixnaのDOM要素をテンプレートとして使用する
params: json // 入力データをJSONをやめてローカルなデータを使う
};
var c = new Cjtk(config);
c.process();
</javascript>
<div class="mixna" title="hatena">

はてな
<div class="url"></div>
<div class="cto"></div>
</div>
<div class="mixna" title="mixi">
みくしい
<div class="url"></div>

<div class="cto"></div>
</div>

という記述が可能です。

ちなみにこの例ではJSONPを使っていませんが、JSONPを使用する場合には該当するDOMのtitleからレコードIDを全てかき集めてJSONPでリクエストする時にクエリパラメータとして送信します。
今回の例だと

json.js?id=hatena;mixi
といった形でクエリを自動的に構成する事が出来ます。
defaultのセパレータは;ですが変更出来ます。

構文拡張

プラグイン機構を使って、マクロを追加出来ます。

Cjtk.register_function(拡張名, function(context, obj, func, stdin, args){});
と拡張を登録する事によって
[% 拡張名.マクロ名 %]
という風に追加したマクロが使えます。
基本のマクロも、これを使って実装しています。

マクロシンタックス

全てのマクロは|(pipe)で処理をつなげる事が出来ます。
マクロの戻り値が次のマクロの入力に使われます。
例外としてマクロの最後に$valueのような変数が指定されていた場合は、変数に文字列が代入されます。

[% 'test' | lc | replace 'T' 'P' | $value %]
だったら、$valueに'PESP'が入ります。

if

分岐条件です。

if 

直前のマクロの結果が真なら、現在のDOM要素以下を表示し、偽なら現在のDOM要素以下を削除します。
偽の場合は、if文以降のマクロは処理しません。
[% '0' | if %] # 条件成立せず
[% '' | if %] # 条件成立せず
[% 'a' | if %] # 条件成立
[% '' | if | cat 'a' | inner %] # cat以降は処理しない
[% '' | if %][% 'test' | attr 'set' 'title' %] # 'test'以降は処理しない
if文に引数を与えると、if文があるDOM要素の削除を行いません。
<div class="[% '1' | if %]">test</div>

これが
test
となるところを
<div class="[% '1' | if '1' %]">test</div>

<div>test</div>
となる

unless

ifの真偽の条件が逆になっただけです。


foreach

入力で与えられた配列データをforeach展開します。

foreach 展開後の変数名 
flagを与えるとifの時のように、自DOM要素の削除を行いません。

inner

子DOM要素にTextノードを作成して、入力のあった文字列を挿入します。

inner <'set|append'>
setを指定すると、子要素全てを削除してから挿入を行います。

attr

自DOM要素の指定した属性を操作します。

attr 'get|set|append' '属性名'
getを指定すると指定した属生の値を取得します。
setを指定すると、入力した値で上書きします。
appendだと追記します。


cat

文字列を結合します。
joinのような感じです。
入力値があれば入力値を第一引数としてあつかいます。

lc

lcです。

uc

ucです。

replace

javascriptのreplaceです。

ret.stdout = typeof stdin == 'string' ? stdin.replace(args<0], args[1>) : '';
こんな実装。


html

htmlエスケープさせるフィルタ。

nop

何もしません。
if文の後にnopを置くと、次のマクロにif文の出力を引き継がないのでcatつか使えるようになります。

コンフィグ

new Cjtk(config);した時に指定出来る設定は次の通り

var config= {
type: 'text/javascript', # JSONP利用時のscriptタグで仕様
charset: 'utf-8', # JSONP利用時のscriptタグで仕様 JSONPのcharsetを入れる
separator: ';', # foreach展開をしない時にレコードIDをクエリパラメータに含める際のセパレータ
foreach: false, # foreach展開をするか
ajax: false, # ajax利用するか(ajaxのコードは未実装)
start_tag: '[%', # マクロの開始タグ
end_tag: '%]', # マクロの終了タグ
macro_attribute: 'class', # マクロを入れる属性名
rowid_attribute: 'title', # レコードIDを入れる属性名
params: '', # JSONPなどを利用しない場合は、ここにデータを指定する
process_callback: function(context){} # テンプレート展開が終わった時に呼び出される関数
};


いかがでしょう?

Posted by Yappo at 13:28 | Comments (1) | TrackBack

2006年09月25日

【GPS】FOMA903iシリーズのP903iをさわって来たよ【ストリーミング】

さらっとググって見たけど情報が見当たらないので書いておきますね。
製品版とがらりと変わっちゃううかもだけど、スケジュール的に無理っぽいからほぼ確定ぽ。

肝心のメニュー周りをさわり忘れてたから、ワンセグ対応だどうだとかは知らないけどテレビは見れないっぽい。
液晶画面上部中央にGPSのアイコンがあったのでP903iはGPS対応してるはず、これもメールメニューとか見忘れてて連携がどうなるかわからん。
もしかしたら903iシリーズ全機種でGPS対応とかやってくるかもね。

基本的にiモードでのブラウジングしかしてなくって、ブラウザ的には902iとかと差はなさそう。
iモードメニューに「iモーション設定」ってのがあって、ストリーミングをどうするかってのがあったよ。
メガアプリとかで大容量ダウンロードさせるつもりらしいから、普通に全機種ストリーミング対応するかもね。

あとiチャンネルwも残ってた。

詳細は、そのうち発表されるのかなぁ。
GPSとストリーミングが全機種搭載されて公式CP以外に機能が解放されていたら、結構なサプライズになりそう。

UAは

DoCoMo/2.0 P903i(C100;TB;W24H12)
アプリダウンロード時とかまで見るの忘れた。

あーNDAとか関係ないから心配しないでね。

Posted by Yappo at 11:13 | Comments (0) | TrackBack

2006年09月24日

使用コマンドランキング

Clouder::Blogger: 使用コマンドランキング
やってみた

$ history | awk '{print $2}' | awk 'BEGIN {FS="|"} {print $1}' | sort | uniq -c | sort -r
236 fg
158 ./script/planetasp_server.pl
95 perl
67 vim
42 ls
37 lv
35 ./script/catpla_server.pl
32 ab
29 cd
28 trac-admin
27 /usr/local/apache/bin/ab
25 screen
21 perldoc
19 emacs
15 grep
14 ./script/jitensya_create.pl
12 bg
11 ~/svn/public_repos/sandbox/PlanetASP/script/planetasp_server.pl
8 cat
7 rm
。。。

fg多いのはemacsでサスペンドしまくるから。
perl多いのはいわずもがな。
vim多いのはemacsは常に立ち上げっぱなしだから。
trac-admin多いのはtracいじってたから。
ab多いのはSoozyのメモリリーク探してたから。
catalyst系多いのはPlaggerのあれ作ってたから。
jitensya_create.plはSoozyのデバグアプリ。

Posted by Yappo at 06:43 | Comments (0) | TrackBack

2006年09月21日

mod_proxy_balancerのretryの件

mod_proxy_balancerのretry : blog.nomadscafe.jp

バックエンドのサーバが十台以上あるようなところだったらいいけれど、2~3台のサービスで間をあけずにデプロイしてしまうと下手するとサービスが数秒間、全落ちになってしまう可能性がある。

ということで、普通にretryを短く(数秒)にすればいいんじゃね。

1.balancerのマネージャにアクセスして該当のサーバをいったん外す
2. httpdの停止
3. rsync
4. httpdの開始
5.balancerのマネージャにアクセスして該当サーバを付け加える

でよくね?
この一連のスクリプトをバックエンドに仕込んどく感じで。
折角のmod_proxy_balancerなんだし。

うちも作ってもらわないとな。。

Posted by Yappo at 19:33 | Comments (1) | TrackBack

2006年09月11日

Re: screen のキーバインド

naoyaグループ - naoyaの日記 - screen のキーバインド

CTRL + A が screen のメタキーに当たってる場合、シェルでカーソル先頭に持ってくときどうしてるんでしょ? シェルが vi キーバインドなのかな。
Ctrl-a + a してます。
ちゃんとタイプしないと、Ctrl-a + Ctlr-aと見なされて後ろ行っちゃうけど、そんなに不自由しない感じです。


なんて返しが出来たらかっこよかったんんだけど、シェルのCtrl-Aなんて初めて知ったよ><
行頭までカーソル戻して作業したいケースは、あんましなくて大体は行の真ん中くらいのを弄りたいから不便してなかったし、行頭持ってく時は左押しっぱで頑張ってました。
もしくはターミナル上でコピペ。

顔真っ赤にしながらman screenしちゃったよ..!

Posted by Yappo at 17:22 | Comments (0) | TrackBack

Developer Enviroments Conferenceの件

ということでDECONの受付で資料配りやって来ました。バタラBoofyTシャツ着て。
開場直後と講演直前にピークタイムが分散してて面白かったです。

折角なんで自分の環境も晒して見るテスト。
普段会社の事は書かないんだけど、問題ない範囲で書いとく。
土曜の昼間に書いた文章だけどうpるの忘れてた。

ハード

PC


・MacBook
・RedHat 9.0(会社)
家とかだとリラックス優先だからノートでソファーみたいな感じでやるんだけど
会社だとノートでの開発効率悪いんでlinuxでkterm立ち上げまくって開発して
MacBookで確認するって感じです。IEとか必須なので、そこはどうにかしてます。

ちょっと前まではWindowsノートだったんですけど、あっさりとMacにスイッチしました。
またWindowsにスイッチするハメになりそですが。。。

マウス/キーボード


特にこだわりなく、標準の機材でやってます。
ハード買えたばっかだと不慣れになるけど直ぐに慣れちゃうので。

これじゃなきゃ駄目だってのがあると非常事態に融通が利かなくなりそうで怖いので、なんでもフラットに使える気持ちで挑んでます。

ソフト

ローカル環境


・kterm
・iTerm

以上。
iTermは文字列をドラッグするのがキモイ。
結構日本語が崩れるので、もっとちゃんとした奴ほすぃ。
ktermが一番しっくりくる。

あーあとMacでalt+tabする為にWitchっての入れてます。

shell


・bash
・screen

.bashrcにちょろっと環境変数かく位で、あとはノーマルです。
screenの切り替えもCtrl-Aです。
なんかemacsの絡みがどうとかでCtrl-Tな人が多数派でしたが、自分意味分かってナス。
全然困ってないし、むしろ多用するからctlキーの横のAのがベンリす。

screenは基本的にscreen -x多用してますな。
emacs -nw -e rieceとかしてるからirc常駐しっぱなしとか。
あとは、ログインして速攻で前回の作業環境を復元出来るってのも便利かなと。
どこからログインしようがセッション復元出来るし。

editor


・emacs
・vim

emacsも特にカスタマイズはせずに最低限

(setq make-backup-files nil)
(display-time)
だけやってる感じです。
.emacsはちょっと真面目に仕込みたい今日この頃。

vimはemacsでいじりたく無いserver系のconfigとかsvn ciしたときとか、emacsあげるのがだるい時とかに使ってます。
これはどノーマル。

mixiで「eclipseとか使ってないの?」って聞かれたけど

仮想デスクトップ


linuxは8個付けてて、メール用,Yappo系用,案件別,sandoboxと用途毎に全部わけてる感じです。
MacBookの方はVirtuDesktopsで6個にわけてて、Firefox,iTerm,その他みたいにわけてる。


全体的に

コードをどこで書くか


あまりMacBookの中でコード書くという事はしない、Macで動くかどうかのデバグとかする時くらいかも。
むしろローカルにコードを持って来て開発するスタイルってのが良くわかってない。
モジュールとかなら良いけど、サービスのコードとか。
たぶんそれは誰のサービスをいじってるのかという所に違いがあるんだろうな。

リモート上の開発環境にログインして開発するってスタイルですね。

Subversion

3〜4年くらい前からつかってるはず。
6年くらい前にCVS試したけど、あり得ない程の使い勝手の悪さだったのでバージョン管理システム使わなかった。
で、Subversionがいい感じになったから導入と。

trac

plagger.orgとか他の人が入れてるのをみて、いい感じだから最近使い始めた。
timelineのfeedをplaggerで読んでPublish::Gmailで社内MLに投げる感じ。
この用途ではPublish::Gmailは使い勝手悪いので、s_nobuさんに作っていただいた奴に入れ替えたい感じ。

フレームワーク


既存の製品を使うと、どうしてもパッチを書かなきゃいけない状況になったり、そのほか運用的に面倒そうなので、あんまりCatalystとかSledgeは使う事ないだろうなぁと。
まぁ、それらをパクったの作って使ってるので、それに勝る道具はない感じではあります。
良いアイデアを誰かが実践してたら、それを吸収してくのも楽ですし。

多分フレームワークは使う物じゃなくて作る物なのかも。
!DRY。

メモ


作業用windowの後ろにいっこkterm上げといて、cat > /dev/nullして、そこにメモはっつけといてる。
すこしヤバメな情報も、ファイルに残す訳ではないから安心。
適当なデータとか捨てワンライナーとかはvim /tmp/hogeみたいなのでやる感じ。

その他


自分もカスタマイズとかしないですね。
多様な環境を触るので、ただでさえストレスが溜まる環境があるのにバリバリにdot-rcとか書いて快適にしちゃうとヤバい事になるし
面倒いしで、デフォルトが一番良いんじゃないのかなぁと思ってます。


というかconfig周りはさぼってる感はあるので、ちょっと改心しますぽ。
あーあとプレゼンの内容からインスパイアされた部分あるので、ちょろっとツール作ってみる。
おっぱいさんを便利に管理出来るようなのとか。

雷鳴ってキターーー!

Posted by Yappo at 04:11 | Comments (2) | TrackBack

2006年09月07日

用途別にapacheのプロセスを分離して最適化

Yappoの本番環境って凄く手抜きしてて、一つのhttpd.confにstaticとmod_perlとcgiとphpな環境がごちゃ混ぜになってるんですよね。
問題ないように見えるようで実はmod_perlなアプリってメモリ食いまくりだから(数十MB)、性的なコンテンツを沢山のhttpdプロセスで処理するって事が出来ないのね。
まぁそんなケースは滅多にないけど。

mod_perlは8個くらい上がってれば十分で、その分メモリに余裕を作って他の事やろうとすると、静的なコンテンツの為のhttpdが足りなくなる。
みたいなジレンマがあって、いいかげんapacheの分離作業をやりました。
分離された物にフロントのapacheがprxoyする感じで。

昔のhttpdな構成をまとめると


+---------------------------------------------+
| apache1.3(static/mod_php/mod_perl/mod_proxy)|
+---------------------------------------------+
|
+---------------+
| |
+---------------+ +-------+
| apache2.0(SVN)| | tracd |
+---------------+ +-------+

#あとも一個別に開発環境

一番上のapacheは30Mくらい物理メモリを使ってます。
まずはmod_perlを全部分離する事から始めました。
この辺の方法論についてはライブドアを参考(WEB+DB PRESSとかオープンソースマガジンの記事参考)にして
apache作る時に--target=modperlしてます。

+------------------------------------+
| apache1.3(static/mod_php/mod_proxy)|
+------------------------------------+
|
+-------------------------------------+
| | |
+--------------------+ +---------------+ +-------+
| apache1.3(mod_perl)| | apache2.0(SVN)| | tracd |
+--------------------+ +---------------+ +-------+

#あとも一個別に開発環境

これでmod_perlが分離され、上のapacheの物理メモリ使用量が10Mくらいに落ちました。
ついでに、今までさぼってたstartup.plもやや真面目に作ったので全体のメモリ効率はかなりうpしました。

ここまで来たら、まだ何かしたくなるのが人の子ってことでphpとcgiも別プロセスに飛ばしたくなりました。
--target=modphpで分離です。


+----------------------------+
| apache1.3(static/mod_proxy)|
+----------------------------+
|
+----------------------------------------------------------------+
| | | |
+--------------------+ +-----------------------+ +---------------+ +-------+
| apache1.3(mod_perl)| | apache1.3(mod_php/cgi)| | apache2.0(SVN)| | tracd |
+--------------------+ +-----------------------+ +---------------+ +-------+

#あとも一個別に開発環境

さらに物理メモリ使用量が減り3Mくらいになりました。
フロントのプロセス上げ放題です。

フロントがmod_perlとかmod_phpに依存しなくなっちゃったのでapache2.2.3を入れる事にしました。preforkです。
これで今っぽい構成になってきました。


+----------------------------+
| apache2.2(static/mod_proxy)|
+----------------------------+
|
+----------------------------------------------------------------+
| | | |
+--------------------+ +-----------------------+ +---------------+ +-------+
| apache1.3(mod_perl)| | apache1.3(mod_php/cgi)| | apache2.0(SVN)| | tracd |
+--------------------+ +-----------------------+ +---------------+ +-------+

#あとも一個別に開発環境

phpとかcgiは
RewriteRule ^(.*\.(cgi|php3?))$ http://example.com:81$1 [P]
みたいな感じでforwardしてます。
ハマりどころはnph-なやつまでproxyすると、リクエストが全部処理されるまでクライアントが表示されなくなるので
RewriteRule ^/nph-ss(.*)$ /nph-ss$1 [PT]
みたいなことしてます。

とりあえず、こんな感じで再構築してちょっとは軽くなった気がしてます。
今後は画像のクライアントキャッシュとか設定をつめてみようかなぁと思います。
圧縮系はやらないです、トラフィックより負荷対策優先で。
mod_phpまでやったのは、折角だからとことんフロントのメモリ使用量さげちゃおうって事と、あんまりphpの為にプロセス上げとくのも無駄だからなぁって感じからでした。

そういえば

ProxyPassReverse / balancer://
みたいな設定書いてるblogを良く見かけますが、それ動かないよ。
ProxyPassReverseってbalancerを展開してくれないよ。
そのかわり複数書けるから
ProxyPassReverse / http://ap1
ProxyPassReverse / http://ap2
ProxyPassReverse / http://ap3
な感じで書こうね。

Posted by Yappo at 20:56 | Comments (1) | TrackBack

2006年06月15日

Control Google Maps via MacBook

Control Google Maps via ThinkPad

Another day, another hack. Here's a demo that controls Google Maps using ThinkPad Hard Drive Active Protection sensor. Pretty cool.

というわけで ThinkPad ハックづいてるこの頃(といっても2日ですが)、また面白いハックを1つ。Google Maps の地図を、ThinkPad を傾けてナビゲートします。まずはデモをどうぞ。

というわけでMacハックづいてた自分も負けてられないと同じような物をMacBookで。

The code is available here in my archive site

AMSTrackerと、このスクリプトを同じディレクトリに入れて起動するだけです。
傾きを検知したらAppleScriptからSafariにJavaScriptを投げつけています。MacOSだからできるワザ。

まだまだ夢がひろがりんぐ。

Posted by Yappo at 04:27 | Comments (1) | TrackBack

2006年06月08日

tracとsvnwebとapache1.3.*でオープンソース開発環境の構築

http://plagger.org/のようなtrac&svn環境を作りたかったので頑張ってみました。
Apache1.3系でtracとsvnwebの構築をしました。
例としてBloxabというプロジェクトを立ち上げる時の構築方法で書いていきます。
ディレクトリとかユーザー名とかは適時書き換える事。
tracの細かい事についてはドキュメントとかを参考に。

svnリポジトリの作成


$ svnadmin create /usr/local/bloxab/repos
普通にリポジトリを作ります。
この作成したリポジトリは、apacheとtracdを動かすuid双方で読み書きできるしておく必要があります。
適切なchownとchmodをしておいて下さい。
以上

tracのインストール


tracを動かす為の各種ソフトをインストールします。
インストール方法は付属のドキュメントなどを参考に。
http://www.sqlite.org/からsqlite3をダウンロードしてインストール
/sbin/ldconfigを実行しておく
http://initd.org/tracker/pysqliteからPySQLiteをダウンロードしてインストール
http://www.clearsilver.net/からClearsilverをダウンロードしてインストール
http://www.edgewall.com/trac/からtracをダウンロードしてインストール

svnweb環境のインストール


mod_davを動くようにしてapache2を入れて、Subversion付属のmod_dav_svnとmod_authz_svnをいれてください。
なぜかapache2.2.2ではうまく動いてくれなかったです。

tracの設定


tracのプロジェクトを作成します
trac-admin /usr/local/bloxab/trac initenv
repositoryは/usr/local/bloxab/reposを指定します。
tracでの権限設定は
$ sqlite3 /usr/local/bloxab/db/trac.db
sqlite> delete from permission where username = 'anonymous' and action not like '%VIEW';
として匿名アクセスは読み込みのみ許可に変えてます。
管理者権限設定は
$ trac-admin /usr/local/bloxab/trac permission add MyName TRAC_ADMIN
してます。

認証ファイルの用意


svnのcommitとtracで使用するパスワードファイルを作成します。
$ htpasswd -c /usr/local/bloxab/trac/htpasswd MyName

tracdの起動


tracdはたまに落ちるという話をmiyagawaさんから聞いたので、mysqlを参考にtracd_safeという落ちてもあげ直すスクリプトを書いたので、これを使って起動します。
$ tracd_safe&
これでport 11001 でtracdがあがりました。

svnwebの設定


先ほどインストールしたapache2のhttpd.confを下記のようにします
LoadModule dav_svn_module     modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so

Listen 127.0.0.1:11002
ServerName svn.example.jp:80

<Location /repos/bloxab>
DAV svn
SVNPath /usr/local/bloxab/repos

# how to authenticate a user
AuthType Basic
AuthName "Bloxab repository"
AuthUserFile /usr/local/bloxab/trac/htpasswd

# For any operations other than these, require an authenticated user.
<LimitExcept GET PROPFIND OPTIONS REPORT>
Require valid-user
</LimitExcept>
</Location>

これでapache2を起動すれば
$ svn co http://localhost:11002/repos/blocab
でチェックアウト可能です。

apache 1.3系用のモジュールを追加


まずmod_proxyを入れておきます。
そして、そのままだとmod_proxyでsvnwebへのリクエストを通せないので、apache1.3系用のmod_davを入れます。
http://www.webdav.org/mod_dav/です。

フロントエンドのapache設定


今まで立ち上げたtracdとsvnwebをまとめます。
普段お使いのhttpd.confに下記の行を追加(もちろんdns周りは設定する事)
#for tracd
<VirtualHost example.jp>
DocumentRoot 適当に
ServerName example.jp

RedirectMatch ^/$ http://example.jp/trac
ProxyPass /trac http://localhost:11001/trac
ProxyPassReverse /trac http://localhost:11001/trac
</VirtualHost>

#for svnweb
<VirtualHost svn.example.jp>
ServerName svn.example.jp
ProxyPass / http://localhost:11002/
ProxyPassReverse / http://localhost:11002/
</VirtualHost>

logとかその他は適当に設定して下さい。


だいたいこんな感じでplagger.orgのような環境が出来上がります。
これでhttp://example.jp/にアクセスするとtracにhttp://svn.example.jp/repos/bloxab/にアクセス/svn coする事が可能になりました。

Posted by Yappo at 13:53 | Comments (0) | TrackBack

2006年05月26日

【デモ動画】MacBookの仮想ディスクトップをモーションコントロールで切り替え

VirtueDesktopsとParallelsを入れてわーい^^わーい^^してたら。
SmackBook Proというのを発見した。
でもこれは、他の仮想ディスクトップソフト使ってるし、パッチ当てなきゃいけないのでめんどくさいし、叩いてると壊れそう(^^;
なので考えたあげくPerlとAppleScriptを組み合わせてVirtueDesktopsでも動くようにしてみた。

goto YouTube
センサーの値が結構狭めなので右に移動しようとしたら左に行ったりとかで、ちょっとコツがいります。

多分、これを応用してMacBook本体をマウス代わりにして絵を描くとかできそう。
需要がありそうだったら、コードを整形して公開します。
多分geekでもhackerでも無い人でも普通に使えると思う。

Posted by Yappo at 03:06 | Comments (9) | TrackBack

2006年02月07日

suggest_ajax.jsのver0.2をリリースしました

id:onozatyさん作のsuggest.jsの拡張スクリプトsuggest_ajax.jsですが。

Enjoy×Study - suggest.jsのver0.2をリリースしました

yappoさんの「suggest_ajax.js - suggest.jsをAjaxなどに対応する等の拡張スクリプト」については、今回、関数名を一部変えた(keyup→keyevent)ので、ver0.2との組み合わせでは動かなくなります(せっかく取り上げていただいたばっかりなのに、、申し訳ござません…)。
という事なので、さくっと対応させました。

ソース
サンプル

主な変更点


  • suggest.js Ver0.2に対応

  • 候補リスト表示中のleft/right/return/esc key以外の挙動を変更

  • 候補リストを非表示中でも入力窓中でreturnを押すとblurイベントを発生させる

  • suggest.js Ver0.2で追加された要素には手を出していません。

    Posted by Yappo at 10:57 | Comments (0) | TrackBack

    2006年02月03日

    suggest_ajax.js - suggest.jsをAjaxなどに対応する等の拡張スクリプト公開

    先月suggest.jsというGoogle Suggestっぽい物を簡単に作れるスクリプトが公開されました。
    ちょろちょろっと自分の使いやすいようにカスタマイズしていたのですが、それを公開してみます。

    最初はAjax化でもしようと思ってたですが、Ajax処理内蔵するのもいけてないので付けるのやめました。
    ソースの中身は、全部なごりなのです。。。

    suggest.jsの思想の真逆を行っているなんて事は気のせいです。

    ソース


    suggest_ajax.js

    サンプル


    ajaxで補完リストを読み込む

    主な変更点


  • 補完リスト上でEnterキーを押して、選択肢の確定を行うことができる

  • 補完リストの作成直前と、選択肢の確定後のそれぞれにフックを行うことができるregister_hook()メソッド追加

  • 補完データを更新するreload()メソッド追加

  • 確定した入力内容を取り出すgetText()メソッド追加

  • 入力エリアの監視を停止するexit()メソッド追加
  • 使い方


    基本はsuggest.jsと同じです。
    <script src="suggest.js"></script>
    <script src="suggest_ajax.js"></script>
    ってな感じでロードしてください。
    呼び出し方は
                var suggest = new IncSearch.Suggest_Ajax(
    "text", // 入力のエレメントID
    "suggest", // 補完候補を表示するエリアのID
    list, // 補完候補の検索対象となる配列
    {dispMax: 10, interval: 1000}); // オプション
    と、同じ呼び出し方ができます。
    listはnew Array()と空の配列を入れることもできますし、オプションが無ければ
    var suggest = new IncSearch.Suggest_Ajax('text', 'suggest');
    と引数を省略できます。

    hookはserachblurに処理を挟む事ができます。
    searchでデータをAjaxかなにかで取ってきて補完リストを更新する処理を行います。

      suggestajax.register_hook('search', function (suggest) {
    var ajax = new Ajax.Request('./suggest_ajax.txt', {method: 'get', onComplete: function (res) {
    var list = eval(res.responseText);
    suggest.reload(list);
    suggest.search();
    }});
    });
    こんな感じで処理を入れます。
    reload()で一覧更新を行った後に必ずsearch()を呼び出してください。
    この呼び出しを行わないとsuggestが機能しません。
    この例ではsearch()をAjax.RequestのonCompleteの最後に入れることがコツです。

    blurについてはサンプルのソースを確認してください。
    exitは動作をとめるだけなので、特に説明しません。

    そのほか


    ライセンスはsuggest.jsと同じく「クリエイティブ・コモンズ 帰属 2.1 日本」
    十数行くらいsuggest.jsからコードをコピーしています。

    Posted by Yappo at 16:12 | Comments (2) | TrackBack

    2006年01月31日

    iアプリでUTF-8なHTTP通信をする方法

    ずいぶん古いネタですが、頼まれ事されたのでコード公開。

    iアプリの仕様としては、内部のエンコードがUCS-2という形式になっています。
    HTTP通信時にストリームをかますとSJIS←→UCS-2変換を行ってくれる仕組みがあるので
    iモードコンテンツと同じノリで、iアプリ向けのサーバプログラムがかけます。
    ただ、それ以外のエンコードの変換は行ってくれないのでサーバ側で吐き出すデータはSJISしか使えないのです。
    もしくはUCS-2を直接吐き出して、生ストリームで読み書きするとか。

    大昔にiアプリで動くBlogクライアントを書いたのですが、サーバ側のエンコードはUTF-8なのです。
    iアプリの機能ではUTF-8←→UCS-2なんて事はやってくれません。

    で、どうしたかと言うと。。。
    生ストリームでHTTP通信をして、ループでまわしてUTF-8←→UCS-2変換するコードで処理する。
    というありえない対処をしました。
    大昔のASCII本に掲載されているRSSリーダのソースには、もっとJavaっぽくUTF-8←→UCS-2なストリームを実装してました。
    というか、携帯でRSS!とか騒いでいる今日この頃ですが、大昔から実装はありましたよっと。

    で、自作のだめだめUTF-8←→UCS-2変換処理を晒します。

    UCS-2をUTF-8に変換しながらサーバに送信するコード

            int body_size = body.length();
    http = (HttpConnection)Connector.open(url,Connector.READ_WRITE, true);

    OutputStream dout = http.openOutputStream();
    for (int i = 0;i < body_size;i++) {
    int w_char = (int) body.charAt(i);
    if (w_char < 256) {
    dout.write((char) w_char);
    } else {
    int tmp;
    tmp = ((w_char & (240 << 8)) >> 12) + 224;
    dout.write((char) tmp);
    tmp = ((w_char & (63 << 6)) >> 6) + 128;
    dout.write((char) tmp);
    tmp = (w_char & 63) + 128;
    dout.write((char) tmp);
    }
    }
    dout.flush();
    dout.close();

    UTF-8をUCS-2に変換しながらサーバのデータを受信するコード
          in = http.openInputStream();
    din = new DataInputStream(in);
    int w_char;
    msg = new String();
    while ((w_char = din.read()) != -1) {
    if (w_char > 224) {
    int w_1, w_2, w_3, w_4;
    w_1 = ((w_char - 224) << 4);
    w_char = din.read();
    w_2 = ((w_char - 128) >> 2);
    w_3 = ((w_char - 128) << 6);
    w_char = din.read();
    w_4 = (w_char - 128);
    msg += (char) (((w_1 + w_2) * 256) + w_3 + w_4);
    } else {
    msg += (char) w_char;
    }
    }
    後は略

    といった感じで適当にビットシフトさせてます。
    まともにJava書いたこと無いので駄目駄目ソースですが、何かにインスパイアしてもらえたら嬉しいです。

    ちなみにライセンスは、この部ログにコメントすることでう。

    Posted by Yappo at 13:48 | Comments (1) | TrackBack

    2005年12月31日

    大晦日だからXangoをhackる

    ライブドアネ連発で年が終わるのもいやな感じなんですよ。
    ってか、ライブドアじゃなくて企業ネタで終わるのがね。


    というわけでXangoハック委員会です。
    だりいからターボールの提供のみで我慢してくらさい。

    ダウンロード

    なんせ年賀状コンテンツを作らんといけない。

    しばらく前に作ったXango製ロボットを公開するよ。
    robots.txtとmetaタグに対応してるはず。
    MySQLで管理してるよ。

    Xango最新版のみでしか動かないからSVNでとってきてね。
    しばらく稼動してると固まるバグもあるよ。


    配布ファイルのinit_db.sqlでテーブルを作ってよ。
    あとは、の

    __PACKAGE__->set_db('Main', 'DBI:mysql:MyRobots', 'user', 'pass');

    の所の場所を適度に変更しろよ。

    正直コードは適当だからな。

    じゃぁ、俺は高尾山で初日の出を見てくる。
    シュッ。

    全国のHackerよ!来年も鍛えような!シュッ!

    残念~Xangoも西村ひろゆきさんの会社ですから~
    2ch.net洗脳切り!

    って人も今年の年末はみないなぁ。

    Posted by Yappo at 23:24 | Comments (1) | TrackBack

    2005年12月16日

    W-ZERO3買った

    自宅に届いてたようなので使ってみました。
    IEはGoogle MapsとかAjax周りは扱えてなさそうだけど、Operaはちゃんと使えてたみたい。
    css周りが変で写真みたいな事になっちゃうけど、ドラッグとかも出来た。
    2005121601.jpg

    ターミナル環境としてはPocketPuTTYがあるようなので0.1を入れてみたが、マルチバイトが考慮されてないっぽ。
    SJISなサーバだったら日本語使えそうだけどね。。。
    あとCtl-Cとかがちゃんと送れてなくてmewツカエナサス。
    キーバインドの変え方調べないと。。。
    緊急時には何とか作業できるレベルかな。。。
    何でもいいから日本語ターミナルが欲しい所。


    とか言ってる間に電源切れないほど固まった。
    どうみてもWindows端末です。
    本当にありがとうございました。

    Posted by Yappo at 18:07 | Comments (0) | TrackBack

    2005年12月06日

    Apache 2.2.0 mod_proxy_balancer hacks of failure.

    mod_proxy_balancerを拡張して動的にごにょごにょしてやろうと思ったのに出来なかったからコアダンプ

    基本的にLinuxとかの環境ではpreforkしてApacheが動いているはずですが
    mod_proxy_balancerの実装がちぐはぐだった。
    主なデータとして、balancer://スキームを取り扱っているproxy_balancerと
    各クラスタの面倒を見ているproxy_workerってのがあるのさ。

    で、バランサ管理画面でApacheの起動中に動的に設定変更出来る機能があるんだけど
    proxy_balancerで管理しているstickysessionとか、リクエスト回数/転送サイズでバランシングアルゴリズムを切り替えるフラグを管理してるのね。

    httpd.confを読み込むフェーズ中ならまだ良いんだけど、一度サーバが回り始めるとプロセス空間が別々になるのよ。
    で、preforkで動いてるのよ。
    メモリ空間がバラバラになってるのにproxy_balancerの中身弄ってるのよ。
    しかも、ご丁寧にapr_pstrdupまでしちゃって…
    変更したこと、他のプロセスから見えないのにね。

    でも、proxy_worker系のパラメタは平気。
    各ノードの重みとか、stickeysessionの値対応付けとか、クラスタの一時停止フラグとかの結構重要そうなやつ。
    何でかって言うと、proxy_worker構造体の中にsっていうメンバがいるんだけど、そのsってのがproxy_worker系パラメータを管理画面から書き換えるときに弄ってるとこなの。
    で、このsってのはスコアボード(共有メモリ)の中にいるので別プロセスからでも変更内容が分かるわけ。

    balancer系のデータもスコアボードに入れればいいんだろうけど、今のcoreの実装上、改造するのがキツイ、書き換え範囲多すぎ。
    そもそも、balancerとworkerの紐付けどうすr?worker新規作成したらどうすりゃいい?
    worker用のメモリも前もって確保しなきゃだめじゃね?
    てか、pre allocしてたら大規模運用じゃ意味ねえyp!pre allocした数以上の追加があったらどうすんの?
    とかとか

    struct proxy_balancer {
    apr_array_header_t *workers; /* array of proxy_workers */
    const char *name; /* name of the load balancer */
    const char *sticky; /* sticky session identifier */
    int sticky_force; /* Disable failover for sticky sessions */
    apr_interval_time_t timeout; /* Timeout for waiting on free connection */
    int max_attempts; /* Number of attempts before failing */
    char max_attempts_set;
    proxy_balancer_method *lbmethod;

    /* XXX: Perhaps we will need the proc mutex too.
    * Altrough we are only using arithmetic operations
    * it may lead to a incorrect calculations.
    * For now use only the thread mutex.
    */
    #if APR_HAS_THREADS
    apr_thread_mutex_t *mutex; /* Thread lock for updating lb params */
    #endif
    void *context; /* general purpose storage */
    };

    のmutexが気になるけど・・・
    mod_proxy系全般でmutex使ってなさげだし

    サーバ追加するだけで、自動的にクラスタ入りできるソリューションがApache 2.2単体で出来たらいいなぁと思ってたけど、もろもろあって実現きついぽ。
    追加されたサーバの検知デーモン中にhttpd.confを書き換えてrestartさせる感じかなぁ。
    てかmod_perlすりゃいいのか。いやプロセスでか過ぎだろw
    preforkやめてworkerにして

    ServerLimit 1
    StartServers 1
    MaxClients 150
    MinSpareThreads 25
    MaxSpareThreads 75
    ThreadsPerChild 25
    とかにして、無理やり改造?

    mod_proxy系のTODOも見当たらないしワケワカンネ。
    なんとなくアーキテクチャの見直しが入る予感。。。

    どうすりゃいいんでしょうね。


    そうそう

    /* The number of dynamic workers that can be added when reconfiguring.
    * If this limit is reached you must stop and restart the server.
    */
    #define PROXY_DYNAMIC_BALANCER_LIMIT 16
    こんなのもあるんですよね。httpd.confの設定数+16個分のメモリ確保は出来てる。

    Posted by Yappo at 05:26 | Comments (0) | TrackBack

    2005年12月02日

    Apache 2.2.0 のロードバランス機能(mod_proxy_balancer)を使いこなす

    Apache 2.2がでました。
    mod_dbdとか、mod_proxy_balancerとか気になる新機能てんこ盛りです。
    ひげぽんさんの所に

    誰か入れてみた人いますか?

    と有ったのでmod_proxy_balancerを試してみました。

    超簡単でした
    mod_proxymod_proxy_balancerを参考にしました。
    既に日本語ドキュメント完備!

    以下から駆け足で、またセキュリティ的によろしくない設定例が多々あります

    とりあえずこんな設定を仕込んでみました

    ProxyPass /lb balancer://TEST stickysession=sesid
    <Proxy balancer://TEST>
    #1
    BalancerMember http://i.yappo.jp loadfactor=10
    #2
    BalancerMember http://www.google.co.jp loadfactor=5 route=2
    #3
    BalancerMember http://www.yahoo.co.jp loadfactor=5 route=3 redirect=2
    #4
    BalancerMember http://127.0.0.1:8081 loadfactor=1
    #5
    BalancerMember http://127.0.0.1:8082 loadfactor=1 route=4 redirect=2
    </Proxy>
    基本的には、リバースプロクシを仕込むのと大差ありません。
    balancer://hogehogeは、複数扱うことも可能です。
    バランシング方法は、転送サイズとリクエスト数のどちらかが選べますが、分かりやすくするためにリクエスト数にしておきました。
    loadfactorというパラメータは、優先順位みたいなもので、今回の設定だと1 1 2 3 1 1 2 3 1 1 2 3 1 1 2 3 4 1 1 2 3 5という感じでバランシングされました。
    細かいパラメータはProxyPass ディレクティブを参考してください。

    mod_proxy_balancerで嬉しい機能は、バックエンドのWebサーバが停止した事を自動的に検知して、止まってるサーバにリクエストを投げないですむ事です。
    また、専用の管理画面も提供しているので、どのクラスタのどのサーバが落ちてるかが一目瞭然です。

    <Location /LBMAN>
    SetHandler balancer-manager
    </Location>
    という設定を仕込むと
    http://localhost/LBMAN 経由から管理画面にアクセスできます。
    また、管理画面にてhttpd.confで設定した内容を動的に変更することも可能です。
    また、指定したバックエンドサーバを利用しないようにする設定も簡単です。
    後ろのサーバ一台だけメンテしたい!って時にも最適です。


    極めつけはstickysessionです。
    これは、CookieもしくはURLの文字列の中に指定したパラメータ名があると、そのパラメータを見てどのサーバを振り向けるかを明示的に指定可能になります。
    今回の例だとsesidというパラメータ名です。
    route=3っていう設定に意味があります。

    具体的にはApacheが

    GET /lb/ HTTP/1.0
    Cookie: sesid=hogegege.3;
    というリクエストを受け取ったらYahooに強制的に振り向けます。
    で、redirect=2についてですが、stickysessionに適合したサーバが落ちていた/管理画面で利用停止した場合に代替的に振り向けるサーバになります。
    Yahooが落ちていたらGoogleに振り向けられるわけです。
    で、代わりのサーバも利用不可能だったらランダムにバランシングされます。

    で、携帯電話とかはCookieが使えないものが有るのでどうしようって、感じですがバッチリ対応しています。
    こんなリクエストがくればおkです。
    GET /lb/?sesid=iofhwehg.3 HTTP/1.0
    POST /lb/?sesid=iofhwehg.3 HTTP/1.0
    GET /lb/hogege/sesid=iofhwehg.3 HTTP/1.0
    GET /lb/hogege/sesid=iofhwehg.3?id=hogaga HTTP/1.0
    GET /lb/dyfoeifYGfiussesid=iofhwehg.3 HTTP/1.0

    ただし、下記の例は動きません。
    GET /lb/?sesid=iofhwehg.3&id=hoge HTTP/1.0
    GET /lb/?sesid=3 HTTP/1.0
    GET /lb/sesid=sddas.3/hoge HTTP/1.0

    これには理由があって、以下の条件を満たすURL文字列でないといけないのです。
    1.stickysessionに指定された文字列がある
    2.stickysessionに指定された文字列の直後が=である
    3.そのパラメータの値には.が入っている必要がある
    4..以降から、URLの末尾もしくは?が出てくるまでの文字列がrouteで設定されてなければならない。

    こんな感じです。
    だからPOSTでも何でも条件さえ満たしてれば携帯でも使えます。
    要はURLの末尾に必ずおけばいいです。

    なんてのは大嘘で、おそらくバグがあって上の例じゃどうやっても動きません。
    GET /lb/?sesid==iofhwehg.3 HTTP/1.0
    のように=を2個つなげればいけると思います。(Cookie使うのだったら問題ない)
    たぶん、なんらかの間違いだと思いPatchを付けたバグレポート出してみました


    Webアプリ側ではstickysessionに配慮した構築を行わないとstickysessionを使いこなせなさそうですが、stickysession使わなければとてもお手軽にバランシング出来るので、あとは安定稼動すればおkなだけ!


    オマケ:管理画面にxmlというパラメータを渡すと…(例: http://localhost/LBMAN?xml=1 )設定がxmlで取り出せます。多分作成中の画面かと。

    Posted by Yappo at 21:48 | Comments (1) | TrackBack

    2005年10月14日

    J-PHONEでのIMGタグとMultiViewsについてのはまりどころ

    j-phoneの端末でimgタグのsrc属性にアクセスを行うときはAcceptヘッダを明示的に指定しています。

    Accept: image/jpeg, image/png

    って感じで、端末が表示可能な画像形式を羅列します。
    これがApacheのMultiViewsとの相性が悪くなるケースがあるというお話。
    1.3系です。

    たとえば/img.phpという画像吐き出しスクリプトがあったとして

    <img src="/img?img=hoge.jpg">

    っていうタグがあったとします。
    その場合には406エラーが発生して画像が出てこなくなります。
    406というのは、リクエストされたURIはクライアントが要求したAcceptとマッチしてませんよ
    みたいな感じのエラーです。

    原因がわからずapacheのソースを軽く調べてみました。

    この時携帯は

    GET /img?img=hoge.jpg HTTP/1.0
    Accept: image/jpeg, image/png
    以下略

    みたいなヘッダを吐きます。
    サーバ上に/imgってファイルが無いくてMultiViewsが設定されている時は
    mod_negotiationのhandle_multiに処理が引き渡されてdo_negotiationに変移して
    406エラーを返しているようです。

    結局、/imgから/img.phpというファイルを探し出して.phpのmime typeを調べた結果
    端末が要求しているAcceptのmimeとサーバで指定されている.phpのmimeが一致しないので
    406エラーを返すという挙動っぽいです。

    .phpのmime関連付けを image/jpegにしたところ406エラーは出ませんでした(代わりにphpのソースコードがダウンロードされるけど)
    .phpのmime関連をなくしたら404が帰ってきました。

    Apacheのマニュアルによると

    MultiViews 探索は、Multiviews オプションにより有効になります。サーバが /some/dir/foo へのリクエストを受け取り、/some/dir/foo が存在しない場合、サーバはディレクトリを読んで、 foo.* にあてはまる全てのファイルを探し、 事実上それらのファイルをマップするタイプマップを作ります。 そのとき、メディアタイプとコンテントエンコーディングは、 そのファイル名を直接指定したときと同じものが割り当てられます。 それからクライアントの要求に一番合うものを選び、 そのドキュメントを返します。

    とありますが、正確にはmime定義されている拡張子しか保管してくれないってこと?

    いや、ソース読めば判ることですが、そこまでは【許してください。】

    Posted by Yappo at 15:50 | Comments (1) | TrackBack

    2005年09月27日

    中国・韓国からのメールを拒否します

    中国(.cn)と韓国(.kr)に割り当てられたip addressからのSMTP要求を全てブロックすることにしました。
    最近ますます無節操なinfo@系のspamerの接続元がこの地域の割合が多い感じだったので
    というのと
    この地域からの人からメール来たこと無いので
    この地域からのSMTP要求を受け付けている事の実害の方が大きくなりすぎているため弾く事にしました。
    TCP全部弾くのは被害でかすぎな気がするのでやめます(中国iモードから見れなくなる)
    MFPM周りで、海外の人のコンタクトも出てきてるのでちょっと怖いですが。

    やり方
    韓国 IP アドレスからのパケットを遮断するから、ご希望の地域のip address listを取得
    リストに下記のスクリプトを通してsmtpのみ弾くように加工


    while(<>){
    s/ -j / -p tcp --dport 25 -j /;
    print;
    }

    あとは、先ほどのサイトの説明どおりに設定を仕込むだけ。

    追記:
    穴があったので、3つルールを追加


    iptables -A KRFILTER -s 58.18.0.0/16 -p tcp --dport 25 -j KRFILTERED
    iptables -A KRFILTER -s 58.180.0.0/16 -p tcp --dport 25 -j KRFILTERED
    iptables -A KRFILTER -s 203.67.0.0/16 -p tcp --dport 25 -j KRFILTERED

    適時増やす感じかな

    Posted by Yappo at 11:01 | Comments (0) | TrackBack

    2005年08月09日

    PowerEdge850がDellみたい

    デュアルコアなP4の搭載が可能で8G間でのDDR-2 SDRAMが乗るE7230チップだそうだ。
    価格は$749~だそうで、$2000くらいの構成を選ぶ感じになるかな。
    早速人柱になってみるか

    むしろ一台あたり10万以下の構成がたくさん欲しいわけだが。

    Posted by Yappo at 11:04 | Comments (0) | TrackBack

    2005年07月13日

    Google Maps APIでつながる世界

    Google Maps APIを使ったphotos@Yappo mapsに色々機能を付け足してみました。

    Nakamura-KU ADDICTさんのinvGeocoder WebServiceを使って、表示中のMapの中心座標に位置する住所表示を行ったり
    Yahoo!MAPSへのリンクをつけて、Google Mapsで対応していない日本地図を簡単に見れるようにしたり。
    Ajaxを使って、他人が表示している座標をリアルタイムで表示するLiveモードをつけたりしました。
    Google Mapsの座標が日本測地系になっていたので、Location::GeoToolを使ってサーバ側で座標変換を行ったりしています。

    Google Maps APIが出たおかげで、普通の人がなかなか活用できなかったGPSメールを簡単に貼り付けたり。
    GPS座標の住所変換も、簡単にGoogle Maps APIと繋げて活用できたり。
    はてなのようなサービスがキーワードなどで座標対応するようになって、その座標つきキーワードをRESTで簡単に取得して自分の所のGoogle Mapsと簡単に組み合わせられたり。
    地図サービスへのリンクを行う事で、楽に地図を探せるアプリケーションが簡単に作れたり。
    Liveモードのような物を作って、他人の興味のあるエリアを簡単に発見できたり。

    と、Google Maps API公開のおかげで、手を出しにくかった位置情報が簡単に扱えて
    今まで単体で機能していた位置情報サービスが、Google Mapsを中心に急速に繋がっていく様は面白い感じですね。

    これがWeb2.0の世界の入り口って所なんでしょうか。

    追記:
    一晩明けたら本家に地図搭載wwwwwwwwww
    おかげでネタ増えたですが、タイミングワルス

    Posted by Yappo at 20:36 | Comments (3) | TrackBack

    2005年07月11日

    はてなマップのデータを引っこ抜いて、自分のマップに貼り付ける

    google maps APIに乗っけるデータが、自分のところだけだとどうしても寂しいので
    はてなマップで使っているデータを表示するようにしてみました。
    浜松町周辺

    はてなマップはAjaxで座標系データを取得していて
    現在表示している座標内のデータのみを取得しています。
    せっかく外部サイトで利用しやすい形になっているから、つかってみちゃえとw

    専用のアイコン作って、はてなデータをわかりやすくしないとなぁ。。。

    Posted by Yappo at 10:46 | Comments (0) | TrackBack

    2005年07月09日

    Google Maps APIおもすれー

    日本のサービスでも組み込んでいる所が増えていて流行の兆しですが。
    ちょうど暖めていたサービスとの相性が良いので使ってみることにした。
    ドキュメント読むのがだるくてよく読んでないけど遊んでみた

    AUのGPS機能が返す座標の度数変換をしなければいけない事が分からずちょっとはまった。

    Posted by Yappo at 14:27 | Comments (0) | TrackBack

    2005年06月29日

    MySQLとSenna+MySQLのメモ

    ただのメモ

    SQL_CALC_FOUND_ROWSを使うと、結局最後までMYDを見ちゃうからパフォーマンスが落ちる
    match文を使いつつfieldに通常のwhereすると結局limitの数だけwhereの条件に一致するレコードを読んで遅くなる。要するにmatch文だけなら、それだけで読むべき行が求まるのにMySQLの通常の演算が入るとまんどい。
    alter table order byして、あらかじめソートしたテーブルも、MySQLのindexをキーにして検索するとselect order byしないと結果にならない。でもSenna+MySQLのfulltextインデックスのみでwhereしたら意図したとおりになる。
    少なくともSenna Rev21のバインディングではこんな感じ

    Posted by Yappo at 03:56 | Comments (0) | TrackBack

    2005年06月03日

    Linux Conference 2005 発表資料

    お話してきました。
    今日の敵は尿意でした。
    いやな汗ずっとかいてました。
    我慢してたら最後の方は収まってきました。

    あと、パワポのリハーサル時のページ切り替えタイミングを保存していたらしく。
    パワポとも戦いました。
    二面楚歌です。

    ということで、発表資料です。
    Yappoの思想すべて見せます
    題名の突っ込みは、本人からのみ受け付けます(え?)
    iYappo/YappoLabsでの実例やアーキテクチャ紹介を交えながら、選定基準や今後の事について話しました。
    正直いうと要求に見合った選定をきちんとする事が大事です。
    終わった後に、とある知人が経営している会社の中の人から、オススメを聞かれたですが機会があれば後日お話できればいいな。という感じです。

    ところどころ、笑われるようなネタを入れつつって感じです。
    途中、サーチストリームのデモを行いました。

    スタート
    スタービーチ(6) アルバイト(24) 任天堂(51) 淫らな告白(7) 着うた フル(151) 恋 画(2383) 翻訳(102) (?) 任天堂(51) 改造コード(14) 画像(1741) ??????(?) 怖い(64) 個人輸入(68)
    --------------------------------------------------------------------------------
    終了。

    狙いどおり、変な言葉が出たです。

    後半は、あんな検索会社検索会社検索会社なんていう凄いところへ言ってきて、お話した内容をサマリーにした感じです。
    検索会議でスルーされたネタの真意でもあります。


    というわけで、お呼びいただいきありがとうございます。

    突っ込み、個別質問なんでもござれ。

    Posted by Yappo at 16:40 | Comments (2) | TrackBack

    2005年05月31日

    既存のページにもんたメソッドを簡単に組み込むツールを作った

    いま巷を騒がせているもんたメソッドですが、あのプレゼンを再現しようとしたツールが2つ登場しています。
    もんたメソッドなプレゼン作成ツール
    もんたメソッドなプレゼンツール in XUL

    miyagawaメソッドとかカカクメソッドとか、○○メソッドという用法が普及しそうな感じですな。

    実は、自分も作ろうとしていた所なのですが、これらプレゼン風のツールとは違い
    簡単にWebサイトに貼り付けられる物を作りたかったのです。
    せっかくなのでサクッと作りました。

    以下もんたメソッド for Webサイトによる説明です(塗りつぶされてる所はクリックです)

    もんたメソッド for Webサイト とは?

    どんなページにも簡単にもんたメソッドを組み込む為の、小さいJavaScriptです。
    このページのように、重要そうな文字を隠しておくことが出来ます。

    貼り付けかたは
    http://tech.yappo.jp/download/monta.js.txt
    からJavaScriptを取得して、適当なURLにファイルを保存します。
    そして、保存したJavaScriptファイルを外部から呼び出すようにHTMLを編集します。
    onLoadに指定するのはちょっとやなので、htmlの後ろの方に<javascript src=" なタグを組み込みます。

    たとえば、このページは


    <script type="text/javascript"><!--
    var monta_close_font = '#00f';
    var monta_close_back = '#00f';
    var monta_open_font = '#f00';
    //--></script>
    <script type="text/javascript" src="http://tech.yappo.jp/download/monta.js"></script>

    で、実際に隠したい文字列を<span monta="on"></span>で囲みます。
    spanタグにmonta属性を勝手に追加した形になります。
    また、いくつかの変数に値を入れて置く事により、色などの変更が出来ます。

    monta_close_font - 文字を隠すときの文字色
    monta_close_back - 文字を隠すときの背景色
    monta_open_font - 文字を表示したときの文字色
    monta_open_back - 文字を表示したときの背景色
    monta_close_img - 文字を隠したときの背景画像


    var monta_close_img = 'url(http://example.com/back.jpg)';

    のように利用する。
    (でもMTで使うとうまく色がつかないorz)

    適当な実装ですが、違和感無くもんたメソッドを組み込めるかと思います。

    Posted by Yappo at 23:23 | Comments (4) | TrackBack

    2005年05月28日

    Blog Hackers Conference 2005 発表資料

    お話してきました。
    唯一笑いが出ないセッションという貴重な体験です。
    何でかというと、初スピーチで必死です。
    最後にnaoyaさんに激しく「必死ですから」と言い放ってしまうほど危なかったのです。
    余裕の無さをアピールしても見てる人にはどうでもいい事なので、淡々と進めたです。
    また機会があったら、も少し余裕出来るかな。
    オファー頂いたmiyagawaさんに感謝の念なのです。

    ということで、発表資料です。
    あなたのHackに検索を
    Hyper Estraier, Senna, Rastの紹介です。
    思ったままに書き綴っています。
    開発者の方々へのネゴ無しの発表なので、とても背中が痛いのです。
    でも、一人でも興味持ってくれる人が増えたら嬉しいなと言う1ユーザの主張として。

    11Pは独断と偏見に基づき評価しています。
    どのソリューションを選ぶかは、本人が決めるべきだと思うので、知らない人が勝手に作った評価程度だと思って見て下さい。

    ?が付いてる分には、未調査などにより評価不能という意味です。
    11P、12Pに関しては詳しい説明が必要だと思いますが、今日は勘弁してください。
    今日ゲッツ出来たお土産写真の準備をしなきゃいけなくて忙しいのです。


    にぽたんさんのおかげで、DBIx::QueryCacheのCPAN登録作業に俄然やる気でてきますた。

    追記:
    たつをの ChangeLog Blog Hackers Conference 2005より


    そういえば、SUFARY ももともと
    Cライブラリがメインなので組み込み用途と言えるかも!

    もちろん存じてるでっす!
    7年くらい前にいじろうとしてたんですが、別の事にはまってて遊ぶのわすr。。。
    とある老舗検索会社さんに採用している事を教えてもらってたです。

    Posted by Yappo at 03:01 | Comments (0) | TrackBack

    2005年05月27日

    今日はBlog Hackers Conference 2005ですよ

    いやはや、どんな事になるやら。

    と思ったら参加エントリー忘れてたorz

    Posted by Yappo at 15:52 | Comments (0) | TrackBack

    2005年05月23日

    ああぁぁあBlog Hackers Conference 2005でお話ししちゃうぅ(><)

    って事で、第一回チキチキBlog Hackers Conference 2005にて5分間話してきます。
    (第二回じゃないよ、2005って付くのは1回目だよ)
    壇上で喋る事なんか初めて、でもないやライブしてたや、じゃぁいいや。

    ネタは検索系で攻めようかと、え?Blog関係ないじゃん?
    まぁまぁまぁ

    今話題の検索周りを使った、Blogにまつわるネタ出しでも出来たらなぁと思いますです。
    実例のスクリプト書こうとも思ったけど高橋メソッドでソースを見せなきゃ
    後ろの人たちが分かりづらいので却下の方向で。

    はてなブックマークを、とある実例として紹介するかも。

    Posted by Yappo at 12:12 | Comments (0) | TrackBack

    2005年03月15日

    BIG-IP v9 memo

    @ITより。
    製品詳細

  • カーネルがLinuxに

  • TMMデーモン

  • フルプロクシアーキテクチャ
    L4以上のデータをいじれるそうで

  • UDP正式対応

  • OneConnect
    Apacheのモジュールに特殊な事やってたら問題ありそうね

  • HTTPリクエストのパイプライン化
    モバイルサイトで絶大な効果かな

  • gzip圧縮
    レスポンスデータを透過的に圧縮するそうで

  • IPv6/IPv4ゲートウェイ
  • BIG-IP側に全部任せちゃうと大変な事になりそうでもあるな。
    最上位モデルで32/64 bit HyperTransport 2.4 GHz x 2と専用ASIC搭載だそうだ。

    ハードはいいから、これらを実現するソフトをだれか作ってないかな

    Posted by Yappo at 16:56 | Comments (0) | TrackBack