<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2604690493777706486</id><updated>2012-02-21T21:53:33.773+09:00</updated><category term='Dev'/><category term='Python'/><category term='Gears'/><category term='Geo'/><category term='Script'/><category term='AIR'/><category term='Nginx'/><category term='Diaspora'/><category term='GAE'/><category term='Wave'/><category term='翻訳'/><category term='Java'/><category term='生活'/><category term='Haskell'/><category term='サッカー'/><category term='awk'/><category term='後で読む'/><category term='Opensocial'/><category term='オリエンテーリング'/><category term='nodejs'/><category term='旅行'/><category term='JavaScript'/><category term='Solr'/><category term='Waf'/><category term='Books'/><title type='text'>Ars longa, vita brevis</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default?start-index=101&amp;max-results=100'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>152</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-4147315660165605619</id><published>2012-02-21T21:52:00.000+09:00</published><updated>2012-02-21T21:53:33.788+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Geo'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>鯖江市のオープンガバメント</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-D7IIEAe3i_Y/T0OTMsTzuTI/AAAAAAAAGfA/scAO8CwL0mE/s1600/sabae-city-landscapes.jpg" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" height="284" width="320" src="http://3.bp.blogspot.com/-D7IIEAe3i_Y/T0OTMsTzuTI/AAAAAAAAGfA/scAO8CwL0mE/s320/sabae-city-landscapes.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;


&lt;p&gt;とりあえずこちらのリリース。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;a class="reference external" href="http://www.city.sabae.fukui.jp/pageview.html?id=11552"&gt;Dataシティさばえ（XML化の推進）&lt;/a&gt; - city.sabae.fukui.jp&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ライセンスは、Creative Commonsの「表示」（CC BY）としています。&lt;/p&gt;
&lt;p&gt;「Dataシティさばえ」のデータを使用していることをアプリケーション内に表示し、
このページ（http://www.city.sabae.fukui.jp/pageview.html?id=11552）や、
各データを公開しているページへリンクを張っていただければ、
データは無料で自由にご利用いただけます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ということで「鯖江百景の位置情報等（XML）」を手元の Google Earth に表示してみました。
公開している XML を KML に変換したものです。
初めから KML で公開してくれても... とかは次のステップだと思いますので、
データフォーマットがどうとか、その中身がどうとかはこれから議論されていくべきことです。
「行政が管理しているデータがオープンになった」という事実がまずは大切ですね。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="id2"&gt;
&lt;h1&gt;ちょっと思ったこと&lt;/h1&gt;
&lt;p&gt;都道府県の数は47だけど、市区町村は？
という問いにサッと答えられる人がどのくらいいるかは分かりませんが、
ゼンリンの方がインタビューで次のように回答しています。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;a class="reference external" href="http://www.1101.com/21c_working/zenrin/2012-01-31.html"&gt;地図調査スタッフ&lt;/a&gt; (21世紀の「仕事！」論。)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;全国1750市区町村のうち1740市区町村の地図を発行しています。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;市区町村は合併することもありますので、この数字は不変ではありませんが、
だいたい 1700〜1800 で考えておくと良さそうでしょうか。&lt;/p&gt;
&lt;p&gt;さて、これらの市区町村が個別に Creative Commons の何らかのレベルでデータを公開してくれたとして、
それぞれの市区町村のページにリンクを張るとなると大変だなぁ、というのが最初に思ったこと。
もちろん、そんなアプリケーションを作るの？と聞かれれば No ですが、
以前に住んでいたところの情報を見たいな〜と思うことはありますので、
複数の市区町村のデータを参照したくなることもあるでしょう。&lt;/p&gt;
&lt;p&gt;鯖江市の今回の取り組みは実証実験の意味合いが強いでしょうから、
そこまで真に受ける話でもありませんが、行政組織は何かと大変なんだなぁ、と思った次第です。
昨年の 3.11 から考えてみると、&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;そういうデータがあるなら早く公開してよ！&lt;/li&gt;
&lt;li&gt;実験とかじゃなくて全部やってよ！&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;という声につながるのは容易に想像できますが、
実際の現場には API エキスパートやデータサイエンティストみたいな人は少ない気がします。
どういう人が取りまとめているのか分かりませんが、
全国を統一的に扱えると嬉しいなぁと感じます。
北海道と沖縄県で XML のタグが違う！とかにはなりませんように。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;アメリカでは &lt;a class="reference external" href="http://radar.oreilly.com/gov2/"&gt;Gov 2.0&lt;/a&gt; というムーブメント (?) が盛り上がってきているようで、
政府系のデータを一般市民が使えるようになりつつあるようです。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.data.gov/"&gt;DATA.GOV&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;また、公務員同士の SNS (&lt;a class="reference external" href="http://www.govloop.com/"&gt;GovLoop&lt;/a&gt; - Social Network for Government)
もあるらしく、情報交換も進んでいるとのこと。
(それが「うまく」機能しているかどうかは別の課題)&lt;/p&gt;
&lt;p&gt;オーストラリアでも &amp;quot;government 2.0 taskforce&amp;quot; という取り組みがあり、
NTTデータが「 &lt;a class="reference external" href="http://e-public.nttdata.co.jp/f/repo/734_a1011/a1011.aspx"&gt;オーストラリア政府による“Government 2.0”の動向&lt;/a&gt; 」としてまとめてくれています。
2010年11月のレポートなので現在はもう少し進展しているでしょうが、
オープンガバメントに関する技術面での課題で、特に次の２点はどこの政府も直面する問題だと
考えられます。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;複数の政府機関の間でデータが個別に作成されているため、重複が多数存在し、一般市民にとっての利便性が低くなっている&lt;/li&gt;
&lt;li&gt;各政府機関の間で使用されているデータフォーマットや規格が統一されていないため、一般市民にとっての利便性が低くなっている&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;話が戻って鯖江市。
XML はマイクロソフト社のソフトウェア (Excel か Access か SQL Server 辺り？)
を使って出力しているようで、名前空間にその名残が見えます。
ベンダーロックオンされないようにどうこうとかは望みませんが、
なんとか RDF などの形式に沿って出力して頂けると嬉しいところです。
ともあれ、緯度経度があって英語表記 (name) と日本語表記 (localname) がありますので
使いどころは多そうですね。
まずは「透明性」ということで。難しいのは継続性。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://fukuno.jig.jp/129"&gt;オープンガバメントの推進！地元鯖江から世界へ #html5 #sabae #opengov&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-4147315660165605619?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/4147315660165605619/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=4147315660165605619' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/4147315660165605619'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/4147315660165605619'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2012/02/open-government-sabae.html' title='鯖江市のオープンガバメント'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-D7IIEAe3i_Y/T0OTMsTzuTI/AAAAAAAAGfA/scAO8CwL0mE/s72-c/sabae-city-landscapes.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-8065328226600638118</id><published>2012-02-21T08:15:00.000+09:00</published><updated>2012-02-21T08:17:17.222+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>デブサミ2012に行ってきた</title><content type='html'>&lt;div style="float:right; margin: 10px"&gt;
&lt;a href="http://www.flickr.com/photos/kookr/5142871626/" title="Agile Wallaby (Macropus agilis) by David Cook Wildlife Photography (kookr), on Flickr"&gt;&lt;img src="http://farm2.staticflickr.com/1242/5142871626_405ff122ff_m.jpg" width="240" height="180" alt="Agile Wallaby (Macropus agilis)"&gt;&lt;/a&gt;
&lt;/div&gt;



&lt;p&gt;デブサミ2012 (&lt;a class="reference external" href="http://codezine.jp/devsumi/2012"&gt;Developers Summit 2012&lt;/a&gt;) に行ってきました。
概要ページには次の記述があります。&lt;/p&gt;
&lt;blockquote&gt;
厳しい経営環境の中で、企業が教育や研修の機会を維持していくのも、非常に困難な状況となっているようです。&lt;/blockquote&gt;
&lt;p&gt;みんなが活き活きとして研修に参加する状況も見たことがありませんので、
研修の機会が減るのは当然の流れなんだろうな、と感じています。&lt;/p&gt;
&lt;p&gt;当日にはたくさんのトラックがありましたが、個人的には角谷さんの話が最も印象的でした。
どうやってソフトウェアを開発していくか？という手法というか心構えのような話です。
こうしたことを常に問い直し続けられると、特別に研修とかしなくても良いのかなと思いました。&lt;/p&gt;
&lt;p&gt;なんとなく動くプログラムを書くには本を読むなりインターネットで調べれば良い話ですが、
製品やサービスを作る、運用して改善を続ける、という話になると、人や組織に特有の事情も関係してきます。
「こうすれば良い！」という回答を求めたがる人もいますが、
基本的には変化に適応していくしかないわけで、後から振り返れば無駄だったとしても、色々とやってみるしかないわけですね。
要するに適者生存。&lt;/p&gt;
&lt;p&gt;以下、自分が参加したセッションのメモや感想などです。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="id2"&gt;
&lt;h1&gt;１日目 - 2/16&lt;/h1&gt;
&lt;div class="section" id="node-js-for"&gt;
&lt;h2&gt;node.jsテクノロジースタック for ソーシャルアプリケーション&lt;/h2&gt;
&lt;p&gt;「ソーシャルアプリケーション」ならではという感じはなく、
Node.js を使ったアプリケーション構築方法の紹介といった感じ。
比較対象として PHP が繰り返し登場していたのが GREE っぽい。&lt;/p&gt;
&lt;p&gt;クライアントサイド、サーバーサイド API、ストレージ (Redis)
とのデータ交換を統一的なコーディングスタイルで扱いたい、という感じの説明が最後にあった。
Node.js を使うと言語は統一できるので、以前にニュースサイトで読んだ
Facebook における Node.js への取り組みと似たような雰囲気。&lt;/p&gt;
&lt;p&gt;Node.js のコア部分まで読んでいるらしく、PHP に疲れたんだろうなぁ、というのが個人的な感想。&lt;/p&gt;
&lt;p&gt;講演中のメモ:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;会場 (100人以上いる) の８割くらいの人は Node.js を書いたことがあるみたい。&lt;/li&gt;
&lt;li&gt;Node は処理が高速でノンブロッキングですよ、という流れ。
Webアプリならクライアントとサーバで同じ言語で書けるよね、という部分は入ってない。&lt;/li&gt;
&lt;li&gt;GREEでは、自分たちでソースコードまで追いかけて管理してるらしい。
低レイヤーまで読む必要があるのは変わらないので、開発者のモチベーションが一番の要因か。&lt;/li&gt;
&lt;li&gt;アプリケーションでデータ制約を課せるように実装。
SQL を文字列で書くとタイプミスが混入してしまうので、DSL でラップしてあげている。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;参考: Facebok における Node.js&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.readwriteweb.com/cloud/2011/05/nodejs-at-facebook.php"&gt;Node.js at Facebook - Why it's Needed and What's Holding it Back&lt;/a&gt; - readwriteweb.com&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="cloud-foundry"&gt;
&lt;h2&gt;Cloud Foundryで変わるこれからのクラウドアプリケーション開発&lt;/h2&gt;
&lt;p&gt;クラウドのホスティング環境としては比較的後発の Cloud Foundry の話。
特定ベンダーにロックインされないようにしてくださいね (ふたつ目の選択肢としてウチを)、
という感じ。
AWS 一択だと AWS に障害があるとサービス全断なので、クラウド環境を複数所有しておけば
可用性の高いシステムを構成できるかも!?&lt;/p&gt;
&lt;p&gt;講演中のメモ:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Cloud Foundry の人の話が交互通訳なので、進行スピードが半分くらいのイメージ。&lt;/li&gt;
&lt;li&gt;会場アンケートだと .NET 開発者が意外と多い気がする。&lt;/li&gt;
&lt;li&gt;クラウドスタックを多角的に眺め直してみる。アナリストだったら？導入数別だと？開発者から見ると？
中立的に考えるとインフラもプラットフォームもサービスも同じようなウェイト。
なお、クラウドスタックは SaaS - Service, PaaS - Platform, IaaS - Infrastructure の３つ。&lt;/li&gt;
&lt;li&gt;ソフトウェアもファッションのようにサイクルが目まぐるしくなってきており、
ソフトウェア開発のサイクルが短くなってきている。
以前はビルドマスター、リリース担当者がいたかもしれないが、
アプリケーション開発者がビルドを意識せずに自分でリリースできると工程を削減できる。
結果として、開発サイクルの高速化を期待できる。&lt;/li&gt;
&lt;li&gt;最後にアンケートに答えて T シャツと USB メモリをもらった。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;プレゼン中に登場した参考リンク:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://wp.me/Peb5Y-eI"&gt;Welcome to the Jungle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.slideshare.net/KentBeck/software-g-forces"&gt;Software G-Forces&lt;/a&gt; - slideshare.net (KentBeck)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="it"&gt;
&lt;h2&gt;3・11から見えた社会基盤としてのIT&lt;/h2&gt;
&lt;p&gt;昨年の震災のクライシスレスポンスの話。
情報を次のようにレイヤー分けしてディスカッションが進んだ。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;情報処理&lt;/li&gt;
&lt;li&gt;情報流通&lt;/li&gt;
&lt;li&gt;情報基盤&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;「人間×情報×社会＝価値」と考え、社会資本における情報という切り口はこのセッションならでは。
ソフトウェア開発が建築から学ぶことはいつまでも多いと思う。
また、情報を伝える (Communication) ことと、情報を処理する (Computing) ことの
両方の話題が絡み合っていることが刺激的。&lt;/p&gt;
&lt;p&gt;どうやって開発するか？というセッションが多い中、そもそも何を作るべきか？という
根本的な話題のディスカッション。
震災から１年が経過しようとしているが、復興への取り組みは始まったばかり。
何が必要とされるか？という問題は現地に行ってみないと分からない。
しかも、課題は非常にローカルな問題に落とし込んで対処しないと意味がない。&lt;/p&gt;
&lt;p&gt;10年前のデブサミでは考えられなかったようなセッションだが、
「10年後も世界で通じるエンジニアであるために」というタイトルの通りだと思った。
今は予想もできないことが10年後には起こるかもしれない。&lt;/p&gt;
&lt;p&gt;講演中のメモ:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;「地震があったらNTTの局社に逃げ込め」という通説があるらしい。
去年の3.11では地震には耐えられたけど津波には耐えられなかった。結果、ケータイでも連絡とれず。&lt;/li&gt;
&lt;li&gt;アメリカの公務員向け SNS として &lt;a class="reference external" href="http://www.govloop.com/"&gt;GovLoop&lt;/a&gt; - Social Network for Government - を紹介。&lt;/li&gt;
&lt;li&gt;「全ての災害は防げるのだろうか。それとも、災害とともに生きるのだろうか。」
建築でのアプローチにおける文脈で登場。特に分野を限定しない考え方である。&lt;/li&gt;
&lt;li&gt;all or nothing ではなく、グレードを区切って意思決定を支援する。
なんでもかんでも防波堤を作れば良いってもんじゃない。
現実的な問題としては、うまくグレードを定義できる人が不足しているかもしれない。&lt;/li&gt;
&lt;li&gt;避難用に作った模型を共有するときに、行政に持って行くと市長室に飾られてしまって誰も見ない。
むしろ神社とかに置いた方がみんなで情報を共有できる。
情報共有を支援するために IT を使えると嬉しい。&lt;/li&gt;
&lt;li&gt;ルールがあって設計するのではなく、シミュレーションしながら設計する。
パラメータのチューニングで試行錯誤していく。ソフトウェア開発の文脈で言うならアジャイルな感じ。&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;２日目 - 2/17&lt;/h1&gt;
&lt;div class="section" id="id4"&gt;
&lt;h2&gt;言語の世界&lt;/h2&gt;
&lt;p&gt;Ruby のまつもとさんの話。立ち見がたくさんいるくらいの大盛況。
Ruby がどうこうという話ではなく、歴史を紐解いてこれからを予測する流れ。
1960年くらいの時代から10年区切りくらいで2000年過ぎまでをタイムスケープ。
これから重要になりそうな考え方としては、並列処理、分散処理、統計処理、宣言的記述を
取り上げていました。&lt;/p&gt;
&lt;p&gt;講演中のメモ:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;AWSに計算リソースが「集中」するけど、その中では「分散」してるよね、という話が分かりやすい。&lt;/li&gt;
&lt;li&gt;今のままで実現できることはそのまま続ければいい。
でも、新しいパラダイムが登場したときは「未来の言語」みたいなものが欲しくなる。
まつもとさんの予想では Erlang, Node.js, R, SQL などが発展したようなイメージ。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;プログラミング言語の歴史に関してはたくさんの読み物があります。
自分が使用している処理系が何に由来しているかを学ぶことで、
得意なこと、不得意なことが分かるかもしれません。
少なくとも、多くのプログラミング言語を習得している方が要所要所の選択肢は増えますので、
知らないよりは知っている方が断然良いでしょう。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://ja.wikipedia.org/wiki/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E8%A8%80%E8%AA%9E%E5%B9%B4%E8%A1%A8"&gt;プログラミング言語年表&lt;/a&gt; - wikipedia.org&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.itmedia.co.jp/enterprise/articles/0703/26/news021.html"&gt;第1回　サルでも分かるプログラミング言語の新潮流【前篇】 (1/2)&lt;/a&gt; - itmedia.co.jp&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://oreilly.com/news/languageposter_0504.html"&gt;The History of Programming Languages&lt;/a&gt; - oreilly.com&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="id7"&gt;
&lt;h2&gt;アジャイルマニフェスト ディケイド&lt;/h2&gt;
&lt;p&gt;アジャイルマニフェストから11年。
これまでの振り返りだけでなく、「どうやって」チームを構成していくか？という話も。
オープンソースの世界からプロジェクトの進め方を学ぶ、という姿勢が鮮明に打ち出されており、
講演内容が非常に具体的で分かりやすかった。&lt;/p&gt;
&lt;p&gt;講演中のメモ:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Christopher Alexander のプロセスに関してはこの本 - &lt;a class="reference external" href="http://t.co/WYlPptvQ"&gt;The Process of Creating Life&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ウォーターフォールからアジャイルへの流れは、
プロジェクトの進め方が違うというだけでなく、個々人が自立しないといけないよね、という話。
やるべきことを自分で考えて漂流しないようにしないと、という言い方に納得。&lt;/li&gt;
&lt;li&gt;「コードがドキュメントだ」のオリジナル記事 - &lt;a class="reference external" href="http://t.co/0WkQo5bM"&gt;CodeAsDocumentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;朝会での報告は単なる問題の羅列でなく、ストーリー性を持たせると各人が考える力を鍛えられる。
「昨日は世界をどう変えたか？」「そのための阻害要因は何か？」&lt;/li&gt;
&lt;li&gt;Q.「ユニットテストは何を書けば良いですか？」A.「変更に適応できるようにしといてね。」&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;「変更に強いソフトウェア」を作るためには、あれこれと考える必要がありますね、という話でした。
自分にとっては何となくモヤモヤっとしていた部分をうまく言葉で表現してもらえた感じで、
とても印象的なセッションでした。
去年５月の「アジャイルスタートアップ」というイベントで Pivotal Labs の
CTO の話を聞いたときよりはイメージが具体化しました。
後は周囲の人とどうやって進めていくか、という部分なのかなぁと思います。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/05/agile-startup.html"&gt;アジャイルスタートアップの後で思ったこと&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="building-scalable-web-apps"&gt;
&lt;h2&gt;Building scalable web apps&lt;/h2&gt;
&lt;p&gt;デモを交えて Heroku の紹介。デモのコードネームは bushido (武士道)。
スピーカーは外国人で英語での発表でしたが、日本でのイベントのために作った、という
点が非常に優しいなぁと思いました。&lt;/p&gt;
&lt;p&gt;講演中のメモ:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Heroku だと logging as a service があるらしい。&lt;/li&gt;
&lt;li&gt;アプリケーションのエラーを適切にレポートしてくれると確かに良い。
ついでに自動的に BTS に登録してくれると嬉しい。&lt;/li&gt;
&lt;li&gt;デモアプリ - &lt;a class="reference external" href="http://devsumi2012-demo.herokuapp.com/"&gt;http://devsumi2012-demo.herokuapp.com/&lt;/a&gt; - ハッシュタグ (#devsumi) を拾う。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;クラウドを使った開発については、こちらの記事を紹介。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.12factor.net/"&gt;The Twelve-Factor App&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id9"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;２日間とも半日ずつの参加でしたが、いろいろと刺激になったイベントでした。
「クラウド」と「アジャイル」は言葉としてもう少しフワフワしているでしょうが、
何年かすれば当たり前のことになっていくと思います。
サイクルを回す、要するにフィードバックを受け入れながら継続して開発する、という
スタイルを無意識に実践できるチームを形成できると良いんだろうなぁと感じました。&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-8065328226600638118?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/8065328226600638118/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=8065328226600638118' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/8065328226600638118'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/8065328226600638118'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2012/02/devsumi-2012.html' title='デブサミ2012に行ってきた'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-1262659048205172369</id><published>2012-02-16T20:33:00.001+09:00</published><updated>2012-02-16T20:38:44.885+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Waf'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>waf を使って Sphinx で生成した HTML を ZIP にまとめる</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://code.google.com/p/waf/logo?cct=1328991713" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" height="55" width="55" src="http://code.google.com/p/waf/logo?cct=1328991713" /&gt;&lt;/a&gt;&lt;/div&gt;



&lt;p&gt;ビルドツールである &lt;em&gt;waf&lt;/em&gt; を使って、 Sphinx で生成した HTML ファイルを ZIP 形式にまとめるメモです。&lt;/p&gt;
&lt;p&gt;コマンドラインで次のように実行すると、Sphinx でビルドして ZIP が作成されます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ waf configure build dist

(出力省略)

New archive created: sphinx-project-1.0.0.zip
'dist' finished successfully (7.701s)
&lt;/pre&gt;
&lt;p&gt;Sphinx に関してはこちらの記事でも紹介されています。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;a class="reference external" href="https://www.ibm.com/developerworks/jp/opensource/library/os-sphinx-documentation/"&gt;Sphinx を活用し、適切に構成されたドキュメントを容易に作成する&lt;/a&gt; (IBM developerWorks)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sphinx は Python で作成されており、元々は Python 言語のドキュメント作成用に作られたものですが、
必ずしもドキュメント作成の対象言語を Python のみに限定しているわけではありません。
場合によってはプログラマーの作成するドキュメントのみが対象というわけですらありません。
Sphinx の利用者は数多くおり、本をまるごと Sphinx で執筆する人もいます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="id1"&gt;
&lt;h1&gt;環境の準備&lt;/h1&gt;
&lt;p&gt;まずは Sphinx と waf を使えるようにします。
&lt;tt class="docutils literal"&gt;virtualenv&lt;/tt&gt; で独立した環境を作成し、ツールをインストールします。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ virtualenv --distribute waf-sphinx
$ cd $_
$ cat &amp;lt;&amp;lt;EOF &amp;gt;requirements.txt
Sphinx
EOF
$ . bin/activate
$ pip install -r requirements.txt
$ curl http://waf.googlecode.com/files/waf-1.6.11 &amp;gt;bin/waf
$ chmod +x bin/waf
&lt;/pre&gt;
&lt;p&gt;Sphinx でプロジェクトを作成したり、何らかのドキュメントを構成する方法は冒頭の IBM developerWorks の記事を参照してください。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="wscript"&gt;
&lt;h1&gt;wscript を書く&lt;/h1&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt; は &lt;tt class="docutils literal"&gt;make&lt;/tt&gt; における &lt;tt class="docutils literal"&gt;Makefile&lt;/tt&gt; のようなものです。
関数がアクションになります。
デフォルトで定義されているアクション名の関数を定義するのが基本的な記述になります。
ここでは次の３つの関数を定義します。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;configure&lt;/tt&gt;: ツールが存在することを確認する&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;build&lt;/tt&gt;: 処理を実行する&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;dist&lt;/tt&gt;: パッケージにまとめる&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt;&lt;/p&gt;
&lt;pre class="prettyprint lang-py literal-block"&gt;
APPNAME = 'sphinx-project'
VERSION = '1.0.0'

def configure(ctx):
    ctx.find_program('sphinx-build')

def build(bld):
    # Sphinx 用のテキストは doc/ ディレクトリにあると仮定。
    bld.exec_command(['make', 'html'], cwd='doc')

def dist(ctx):
    ctx.algo = 'zip'
    ctx.files = ctx.path.ant_glob(['doc/build/_html/**/*'])
    ctx.base_path = ctx.path.find_dir('doc/_build/html')
&lt;/pre&gt;
&lt;p&gt;順番に実行していきます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ waf configure
$ waf build
$ waf dist
New archive created: sphinx-project-1.0.0.zip
'dist' finished successfully (7.701s)
&lt;/pre&gt;
&lt;p&gt;&lt;cite&gt;APPNAME&lt;/cite&gt; と &lt;cite&gt;VERSION&lt;/cite&gt; で指定した ZIP アーカイブができました。
&lt;tt class="docutils literal"&gt;ctx.algo&lt;/tt&gt; のデフォルトは &lt;tt class="docutils literal"&gt;bz2&lt;/tt&gt; なので、
圧縮効率を高めたい場合には何も指定しなければ自動的に処理してくれます。
&lt;tt class="docutils literal"&gt;base_path&lt;/tt&gt; を指定することで、特定のディレクトリ以下のファイルに絞ってアーカイブを作成できます。
何も指定しない場合は、カレントディレクトリ以下のファイルが対象になります。
バックアップファイルやオブジェクトファイルなど、除外するものとして有名な拡張子は対象外となります。 &lt;tt class="docutils literal"&gt;excl&lt;/tt&gt; で明示することも可能です。
たとえば、Sphinx で生成した場合はソースを含めない、といったカスタマイズも可能です。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;探してみると英語のフォーラムにも似たような投稿がありました。
だいたいの人が考えることは一緒、と。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://groups.google.com/forum/?fromgroups#!topic/waf-users/5v5s-EZkvYw"&gt;dist: having trouble creating zip files without the folder&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt; を記述するときは API ドキュメントを読みながら、というのがちょっと大変かもしれませんね。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://docs.waf.googlecode.com/git/apidocs_16/Scripting.html"&gt;Scripting (Waf v1.6.8 documentation)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;サクッと ZIP にまとめられると嬉しいなぁ、と思っていたので、自分としては結構嬉しい発見でした。&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-1262659048205172369?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/1262659048205172369/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=1262659048205172369' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/1262659048205172369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/1262659048205172369'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2012/02/waf-sphinx-dist.html' title='waf を使って Sphinx で生成した HTML を ZIP にまとめる'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-1612233486068305050</id><published>2012-02-07T00:56:00.000+09:00</published><updated>2012-02-07T00:58:52.367+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Buildbot を使ってみる</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://trac.buildbot.net/chrome/site/header-text-transparent.png" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" height="73" width="236" src="http://trac.buildbot.net/chrome/site/header-text-transparent.png" /&gt;&lt;/a&gt;&lt;/div&gt;


&lt;p&gt;Buildbot はソフトウェア開発におけるチェックアウト、ビルド、テストというサイクルの自動化を支援してくれます。
Python 自体の継続ビルドや、Chronium のビルドツールとして利用されています。&lt;/p&gt;
&lt;p&gt;Buildbot の概要についてはこちらの記事にまとめられています。
(実際のコードはちょっと古くなってしまっています)&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.ibm.com/developerworks/jp/linux/library/l-buildbot/"&gt;Buildbot による継続的インテグレーション&lt;/a&gt; - IBM developerWorks&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="note"&gt;
&lt;p class="first admonition-title"&gt;Note&lt;/p&gt;
&lt;p&gt;この記事は、Python の学習資料の中に盛り込もうとしたけど難しそうだからやっぱりやめた、
というもので、結論や発展性はありません。要するに書きかけの没ネタです。
(何かのメモになれば)&lt;/p&gt;
&lt;p&gt;これまでのまとめ :&lt;/p&gt;
&lt;ul class="last simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/12/python-school.html"&gt;Python の学習資料&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2012/01/python-school-2.html"&gt;Python の学習資料 - 2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2012/01/python-school-3.html"&gt;Python の学習資料 - 3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="id1"&gt;
&lt;h1&gt;Buildbot をインストールする&lt;/h1&gt;
&lt;p&gt;まずはソフトウェアをインストールします。
&lt;tt class="docutils literal"&gt;pip&lt;/tt&gt; を使ってインストールできます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ virtualenv --distribute buildbot-sample
$ cd buildbot-sample
$ source bin/activate
(buildbot-sample) $ pip install buildbot
&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;bin&lt;/em&gt; ディレクトリ (Windows の場合は &lt;em&gt;Scripts&lt;/em&gt; フォルダ) に &lt;tt class="docutils literal"&gt;buildbot&lt;/tt&gt; コマンドがインストールされます。&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;virtualenv&lt;/tt&gt; って何？という場合は環境構築の資料を見直してください。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h1&gt;マスターノードを作成する&lt;/h1&gt;
&lt;p&gt;次に、マスターノードを作成します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
(buildbot-sample) $ buildbot create-master master
mkdir /Users/shigeru/projects/buildbot-sample/master
chdir /Users/shigeru/projects/buildbot-sample/master
creating master.cfg.sample
populating public_html/
creating Makefile.sample
creating database
buildmaster configured in /Users/shigeru/projects/buildbot-sample/master
&lt;/pre&gt;
&lt;p&gt;設定ファイルや起動スクリプトなどが生成されます。
&lt;em&gt;master&lt;/em&gt; の中を見てみましょう。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
(buildbot-sample) $ ls master/
Makefile.sample  buildbot.tac     master.cfg.sample       public_html/     state.sqlite
&lt;/pre&gt;
&lt;p&gt;設定ファイルはサンプルになっていますので、 &lt;cite&gt;.sample&lt;/cite&gt; を取り除いたものに変更します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
(buildbot-sample) $ mv master/master.cfg.sample master/master.cfg
&lt;/pre&gt;
&lt;p&gt;このサンプル設定で起動させてみます。
(&lt;a class="reference external" href="https://launchpad.net/pyflakes"&gt;Pyflakes&lt;/a&gt; というツールのレポジトリを監視する設定になっています)&lt;/p&gt;
&lt;pre class="literal-block"&gt;
(buildbot-sample) $ buildbot start $VIRTUAL_ENV/master
Following twistd.log until startup finished..
2012-02-02 23:56:01+0900 [-] Log opened.
2012-02-02 23:56:01+0900 [-] twistd 11.0.0 (/Users/shigeru/projects/buildbot-sample/bin/python 2.7.1) starting up.
2012-02-02 23:56:01+0900 [-] reactor class: twisted.internet.selectreactor.SelectReactor.
2012-02-02 23:56:01+0900 [-] Applying patch for http://twistedmatrix.com/trac/ticket/5079
2012-02-02 23:56:01+0900 [-] Creating BuildMaster -- buildbot.version: 0.8.5
2012-02-02 23:56:01+0900 [-] loading configuration from /Users/shigeru/projects/buildbot-sample/master/master.cfg
2012-02-02 23:56:01+0900 [-] configuration update started
2012-02-02 23:56:02+0900 [-] setting database journal mode to 'wal'
2012-02-02 23:56:02+0900 [-] Using SQLite Version (3, 7, 5)
2012-02-02 23:56:02+0900 [-] twisted.spread.pb.PBServerFactory starting on 9989
2012-02-02 23:56:02+0900 [-] Starting factory &amp;lt;twisted.spread.pb.PBServerFactory instance at 0x107f08488&amp;gt;
2012-02-02 23:56:02+0900 [-] adding new builder runtests for category None
2012-02-02 23:56:02+0900 [-] trying to load status pickle from /Users/shigeru/projects/buildbot-sample/master/runtests/builder
2012-02-02 23:56:02+0900 [-] no saved status pickle, creating a new one
2012-02-02 23:56:02+0900 [-] added builder runtests in category None
2012-02-02 23:56:02+0900 [-] setBuilders._add: [&amp;lt;buildbot.process.botmaster.BuildRequestDistributor instance at 0x107cf6950&amp;gt;, &amp;lt;BuildSlave 'example-slave', current builders: &amp;gt;] ['runtests']
2012-02-02 23:56:02+0900 [-] adding IStatusReceiver &amp;lt;WebStatus on port tcp:8010 at 0x107d43128&amp;gt;
2012-02-02 23:56:02+0900 [-] buildbot.status.web.baseweb.RotateLogSite starting on 8010
2012-02-02 23:56:02+0900 [-] Starting factory &amp;lt;buildbot.status.web.baseweb.RotateLogSite instance at 0x107f590e0&amp;gt;
2012-02-02 23:56:02+0900 [-] Setting up http.log rotating 10 files of 10000000 bytes each
2012-02-02 23:56:02+0900 [-] WebStatus using (/Users/shigeru/projects/buildbot-sample/master/public_html)
2012-02-02 23:56:02+0900 [-] removing 0 old schedulers, updating 0, and adding 1
2012-02-02 23:56:02+0900 [-] adding 1 new changesources, removing 0
2012-02-02 23:56:02+0900 [-] gitpoller: using workdir '/Users/shigeru/projects/buildbot-sample/master/gitpoller-workdir'
2012-02-02 23:56:02+0900 [-] gitpoller: initializing working dir from git://github.com/buildbot/pyflakes.git
2012-02-02 23:56:02+0900 [-] configuration update complete
The buildmaster appears to have (re)started correctly.
&lt;/pre&gt;
&lt;p&gt;マスターが起動すると、プロセスIDが書かれたファイルとログファイル、
レポジトリをポーリングする作業用ディレクトリ、それからテストディレクトリが生成されます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
(buildbot-sample) $ ls master/
Makefile.sample    gitpoller-workdir/ master.cfg         runtests/          twistd.log
buildbot.tac       http.log           public_html/       state.sqlite       twistd.pid
&lt;/pre&gt;
&lt;p&gt;マスターの情報は HTTP で閲覧できます。
&lt;tt class="docutils literal"&gt;master.cfg&lt;/tt&gt; の &lt;em&gt;buildbotURL&lt;/em&gt; というパラメータを確認します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
(buildbot-sample) $ grep buildbotURL master/master.cfg
# the 'buildbotURL' string should point to the location where the buildbot's
c['buildbotURL'] = &amp;quot;http://localhost:8010/&amp;quot;
&lt;/pre&gt;
&lt;p&gt;Webブラウザで確認すると、以下のように表示できるはずです。&lt;/p&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-1ya5FEzJU1w/Ty_2oaf2_jI/AAAAAAAAGJw/82GioT5i8hE/s1600/buildbot-welcome.jpg" imageanchor="1" style="margin:1em;"&gt;&lt;img border="0" height="180" width="320" src="http://1.bp.blogspot.com/-1ya5FEzJU1w/Ty_2oaf2_jI/AAAAAAAAGJw/82GioT5i8hE/s320/buildbot-welcome.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h1&gt;スレーブノードを作成する&lt;/h1&gt;
&lt;p&gt;次に、スレーブを設定します。
まずはスレーブ用のソフトウェアをインストールします。
(&lt;tt class="docutils literal"&gt;buildslave&lt;/tt&gt; というコマンドがインストールされます)&lt;/p&gt;
&lt;pre class="literal-block"&gt;
(buildbot-sample) $ pip install  buildbot-slave
&lt;/pre&gt;
&lt;p&gt;スレーブからマスターに接続します。
ユーザー名とパスワードは &lt;tt class="docutils literal"&gt;master.cfg&lt;/tt&gt; に書かれているものに揃えます。
まずは確認しましょう。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
(buildbot-sample) $ grep &amp;quot;'slaves'&amp;quot; master/master.cfg
# The 'slaves' list defines the set of recognized buildslaves. Each element is
c['slaves'] = [BuildSlave(&amp;quot;example-slave&amp;quot;, &amp;quot;pass&amp;quot;)]
&lt;/pre&gt;
&lt;p&gt;続いて &lt;tt class="docutils literal"&gt;buildslave&lt;/tt&gt; コマンドでディレクトリを作成し、接続します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
(buildbot-sample) $ buildslave create-slave slave localhost:9989 example-slave pass
mkdir /Users/shigeru/projects/buildbot-sample/slave
chdir /Users/shigeru/projects/buildbot-sample/slave
mkdir /Users/shigeru/projects/buildbot-sample/slave/info
Creating info/admin, you need to edit it appropriately
Creating info/host, you need to edit it appropriately
Not creating info/access_uri - add it if you wish
Please edit the files in /Users/shigeru/projects/buildbot-sample/slave/info appropriately.
buildslave configured in /Users/shigeru/projects/buildbot-sample/slave

(buildbot-sample) $ buildslave start $VIRTUAL_ENV/slave
Following twistd.log until startup finished..
2012-02-03 00:21:49+0900 [-] Log opened.
2012-02-03 00:21:49+0900 [-] twistd 11.0.0 (/Users/shigeru/projects/buildbot-sample/bin/python 2.7.1) starting up.
2012-02-03 00:21:49+0900 [-] reactor class: twisted.internet.selectreactor.SelectReactor.
2012-02-03 00:21:49+0900 [-] Starting BuildSlave -- version: 0.8.5
2012-02-03 00:21:49+0900 [-] recording hostname in twistd.hostname

The buildslave took more than 10 seconds to start, so we were unable to
confirm that it started correctly. Please 'tail twistd.log' and look for a
line that says 'configuration update complete' to verify correct startup.
&lt;/pre&gt;
&lt;p&gt;マスターとスレーブのログを見ると、お互いを認識できていることが分かります。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
(buildbot-sample) $ tail {master,slave}/twistd.log
==&amp;gt; master/twistd.log &amp;lt;==
2012-02-03 00:11:03+0900 [-] gitpoller: no changes, no catch_up
2012-02-03 00:16:02+0900 [-] gitpoller: polling git repo at git://github.com/buildbot/pyflakes.git
2012-02-03 00:16:04+0900 [-] gitpoller: no changes, no catch_up
2012-02-03 00:21:02+0900 [-] gitpoller: polling git repo at git://github.com/buildbot/pyflakes.git
2012-02-03 00:21:06+0900 [-] gitpoller: no changes, no catch_up
2012-02-03 00:22:19+0900 [Broker,0,127.0.0.1] slave 'example-slave' attaching from IPv4Address(TCP, '127.0.0.1', 58503)
2012-02-03 00:22:19+0900 [Broker,0,127.0.0.1] Starting buildslave keepalive timer for 'example-slave'
2012-02-03 00:22:19+0900 [Broker,0,127.0.0.1] Got slaveinfo from 'example-slave'
2012-02-03 00:22:19+0900 [Broker,0,127.0.0.1] bot attached
2012-02-03 00:22:19+0900 [Broker,0,127.0.0.1] Buildslave example-slave attached to runtests

==&amp;gt; slave/twistd.log &amp;lt;==
2012-02-03 00:21:49+0900 [-] twistd 11.0.0 (/Users/shigeru/projects/buildbot-sample/bin/python 2.7.1) starting up.
2012-02-03 00:21:49+0900 [-] reactor class: twisted.internet.selectreactor.SelectReactor.
2012-02-03 00:21:49+0900 [-] Starting BuildSlave -- version: 0.8.5
2012-02-03 00:21:49+0900 [-] recording hostname in twistd.hostname
2012-02-03 00:22:19+0900 [-] Starting factory &amp;lt;buildslave.bot.BotFactory instance at 0x105243878&amp;gt;
2012-02-03 00:22:19+0900 [-] Connecting to localhost:9989
2012-02-03 00:22:19+0900 [Broker,client] message from master: attached
2012-02-03 00:22:19+0900 [Broker,client] SlaveBuilder.remote_print(runtests): message from master: attached
2012-02-03 00:22:19+0900 [Broker,client] Connected to localhost:9989; slave is ready
2012-02-03 00:22:19+0900 [Broker,client] sending application-level keepalives every 600 seconds
&lt;/pre&gt;
&lt;p&gt;Webブラウザでマスターを確認すると、スレーブノードが増えています。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h1&gt;ビルドを実行する&lt;/h1&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-t9U9GqRbOCo/Ty_2dcacGLI/AAAAAAAAGJk/sEVcv4h8QuM/s1600/buildbot-runtests.jpg" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" height="223" width="320" src="http://3.bp.blogspot.com/-t9U9GqRbOCo/Ty_2dcacGLI/AAAAAAAAGJk/sEVcv4h8QuM/s320/buildbot-runtests.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Webブラウザの方からスレーブノードを選択して辿って行くと、ビルドできるようになっています。
実際にビルドしてみると、右のスクリーンショットのような結果を得られます。
(よく分からない場合は、リンクをぽちぽちとクリックしてみましょう)&lt;/p&gt;

&lt;p&gt;それぞれのステップの標準出力などは記録されており、後からすべてを確認できます。&lt;/p&gt;
&lt;p&gt;これでセットアップと動作確認は終わりました。
プロジェクト個別の設定は、プロジェクトサイトにあるドキュメントを参照してください。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id6"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;ソフトウェアを開発する上で、CI (Continuous Integration)
をサポートするツールも使えた方が良いことは間違いないでしょう。
しかし、ソフトウェアの依存性が複雑だったり、対象とするツールの範囲が広いことなどもあり、
導入するにはそれなりに知識が必要なだったりもします。&lt;/p&gt;
&lt;p&gt;それでは専任のビルドスレーブな人を育成しましょう、という流れもあるかもしれませんが、
チーム開発における CI は個々のチームメンバーの理解があってこそです。
知識は勉強すれば何とかなりますが、ツールを導入することによってどのような効果が見込めるのか？
という部分を共有できるか否かが一番の肝だったりします。&lt;/p&gt;
&lt;p&gt;このため、トップダウンで開発手法を改善しても早晩に形骸化してしまうのかな、と。&lt;/p&gt;
&lt;p&gt;Buildbot はマルチプラットフォームに対応するソフトウェアの CI には良い選択肢だと思いますが、
そもそもそんなソフトウェアが多くはないかもなぁ〜というのが、没ネタにした理由です。
とりあえずは Jenkins を導入した方が管理やメンタルモデルの適応は簡単そうです。&lt;/p&gt;
&lt;p&gt;あと蛇足になりますが、Buildbot は低レイヤーで Twisted を使っています。
Twisted に関してはこの辺を参考にしてください。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://skitazaki.appspot.com/translation/twisted-intro-ja/index.html"&gt;Twisted 入門&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-1612233486068305050?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/1612233486068305050/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=1612233486068305050' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/1612233486068305050'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/1612233486068305050'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2012/02/buildbot-sample.html' title='Buildbot を使ってみる'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-1ya5FEzJU1w/Ty_2oaf2_jI/AAAAAAAAGJw/82GioT5i8hE/s72-c/buildbot-welcome.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-454803814142108653</id><published>2012-01-30T22:17:00.000+09:00</published><updated>2012-01-30T22:17:45.196+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Python の学習資料 - 3</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://python.org/images/python-logo.gif" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" height="71" width="211" src="http://python.org/images/python-logo.gif" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Python の学習資料を追記しました。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://skitazaki.github.com/python-school-ja/index.html"&gt;Python School 1.2.1 documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;社内で勉強会をやってみるとたまに質問がきますので、
一般的なレベルに落とし込んでまとめた内容になります。
特に連続性はありませんが、知っていると便利なときがあるかもしれない、というものたちです。
基本的にリンク紹介とも言えます。&lt;/p&gt;
&lt;p&gt;個人的には &lt;tt class="docutils literal"&gt;json.dump()&lt;/tt&gt; の &lt;em&gt;ensure_ascii&lt;/em&gt; 引数を知りませんでしたが、
日本語を含んだ JSON を整形するときには重宝すると思います。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="id1"&gt;
&lt;h1&gt;追加内容&lt;/h1&gt;
&lt;dl class="docutils"&gt;
&lt;dt&gt;デコレータ&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;組み込みデコレータ&lt;/li&gt;
&lt;li&gt;デコレータのいろいろ&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;モジュールのインポート方法いろいろ&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;標準モジュールのインポート&lt;/li&gt;
&lt;li&gt;サードパーティモジュールのインポート&lt;/li&gt;
&lt;li&gt;自作ライブラリのインポート&lt;/li&gt;
&lt;li&gt;Python のバージョン違いを考慮したインポート&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;ネットワークプログラミング&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;HTTP でダウンロード&lt;/li&gt;
&lt;li&gt;HTTP のレスポンス処理&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;Web API&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;Twitter API&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;Tips&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;モジュールの実行&lt;/li&gt;
&lt;li&gt;日本語を扱うときに便利なこと&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;「デコレータのいろいろ」に記載したリンク先の記事を読み直してみると、
デコレータの経緯はややこしいんだなぁ、と思いました。
入門レベルからは一気にジャンプアップしてしまいますが、
時間ができたら読んでみると良いのではないでしょうか。&lt;/p&gt;
&lt;p&gt;あと、既存のページもディレクトリレイアウトを変更しました。
これに伴い、各ページの URL は変更になっています。
(個別のページにリンクを張ってることもないだろうけど)&lt;/p&gt;
&lt;p&gt;前の記事:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/12/python-school.html"&gt;Python の学習資料&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2012/01/python-school-2.html"&gt;Python の学習資料 - 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-454803814142108653?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/454803814142108653/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=454803814142108653' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/454803814142108653'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/454803814142108653'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2012/01/python-school-3.html' title='Python の学習資料 - 3'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-4742516422949740824</id><published>2012-01-23T08:23:00.002+09:00</published><updated>2012-01-23T08:24:58.112+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Solr'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>Solr に Wikipedia のデータをインポートする</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-kCbl4D6fXNI/TxrPIeqNg9I/AAAAAAAAGFU/Q6aDk9zbowU/s1600/solr-admin-dataimport-finished.jpg" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" height="197" width="320" src="http://3.bp.blogspot.com/-kCbl4D6fXNI/TxrPIeqNg9I/AAAAAAAAGFU/Q6aDk9zbowU/s320/solr-admin-dataimport-finished.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;


&lt;p&gt;テスト用によくあるパターンですので、Solr に Wikipedia のデータをインポートする手順をメモしておきます。&lt;/p&gt;
&lt;p&gt;方法は大きく３つあります。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;DIH (Data Import Handler) を使う。&lt;/li&gt;
&lt;li&gt;自前で XML を解析して &lt;em&gt;/update&lt;/em&gt; ハンドラに投げる。&lt;/li&gt;
&lt;li&gt;MySQL などに一旦インポートして、そこから DIH を使う。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ここでは Solr Wiki にも記載されている DIH を使ってインポートします。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://wiki.apache.org/solr/DataImportHandler#Example:_Indexing_wikipedia"&gt;Data Import Request Handler &amp;gt; Example: Indexing wikipedia&lt;/a&gt; (Solr Wiki)&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="wikipedia"&gt;
&lt;h1&gt;Wikipedia のデータをダウンロードして解凍する&lt;/h1&gt;
&lt;p&gt;Wikipedia はダンプデータを公開してくれていますので、
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;jawiki-latest-pages-articles.xml.bz2&lt;/span&gt;&lt;/tt&gt; をダウンロードします。
ページの概要だけが欲しい場合には &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;jawiki-latest-abstract.xml&lt;/span&gt;&lt;/tt&gt; をダウンロードします。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://dumps.wikimedia.org/jawiki/latest/"&gt;Index of /jawiki/latest/&lt;/a&gt; - dumps.wikimedia.org&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="literal-block"&gt;
$ curl -O http://dumps.wikimedia.org/jawiki/latest/jawiki-latest-pages-articles.xml.bz2
$ bunzip2 jawiki-latest-pages-articles.xml.bz2
$ ls -lh jawiki-*
-rw-r--r--  1 shigeru  staff   1.2G Jan 18 01:32 jawiki-latest-abstract.xml
-rw-r--r--  1 shigeru  staff   5.7G Jan 18 01:55 jawiki-latest-pages-articles.xml
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="solr"&gt;
&lt;h1&gt;Solr の設定ファイルを変更する&lt;/h1&gt;
&lt;p&gt;Wikipedia のデータを保存するスキーマを定義します。
Solr Wiki を参考にして、次の３つのファイルを編集します。
DIH の設定ファイルは &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;wikipedia-data-import.xml&lt;/span&gt;&lt;/tt&gt; とします。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;solrconfig.xml&lt;/tt&gt;: DIH のハンドラを追加する。&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;schema.xml&lt;/tt&gt;: スキーマを定義する。&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;wikipedia-data-import.xml&lt;/span&gt;&lt;/tt&gt;: Wikipedia のダンプデータを Solr のスキーマにマッピングする。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;solrconfig.xml&lt;/tt&gt; で &lt;em&gt;/dataimport&lt;/em&gt; へのアクセスを DataImportHandler に処理させます。&lt;/p&gt;
&lt;pre class="prettyprint lang-xml literal-block"&gt;
  &amp;lt;!-- Data Import Handler for Wikipedia dump data.
  --&amp;gt;
  &amp;lt;requestHandler name=&amp;quot;/dataimport&amp;quot; class=&amp;quot;org.apache.solr.handler.dataimport.DataImportHandler&amp;quot;&amp;gt;
    &amp;lt;lst name=&amp;quot;defaults&amp;quot;&amp;gt;
      &amp;lt;str name=&amp;quot;config&amp;quot;&amp;gt;wikipedia-data-config.xml&amp;lt;/str&amp;gt;
    &amp;lt;/lst&amp;gt;
  &amp;lt;/requestHandler&amp;gt;
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;schema.xml&lt;/tt&gt; で次のフィールドを定義します。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;id: ページの ID&lt;/li&gt;
&lt;li&gt;title: ページのタイトル&lt;/li&gt;
&lt;li&gt;revision: ページのリビジョン&lt;/li&gt;
&lt;li&gt;user: ページの作成者名&lt;/li&gt;
&lt;li&gt;userId: ページの作成者の ID&lt;/li&gt;
&lt;li&gt;text: ページの本文&lt;/li&gt;
&lt;li&gt;timestamp: ページの最終更新時刻&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="prettyprint lang-xml literal-block"&gt;
   &amp;lt;field name=&amp;quot;id&amp;quot;        type=&amp;quot;int&amp;quot;      indexed=&amp;quot;true&amp;quot;  stored=&amp;quot;true&amp;quot; required=&amp;quot;true&amp;quot; /&amp;gt; 
   &amp;lt;field name=&amp;quot;title&amp;quot;     type=&amp;quot;string&amp;quot;   indexed=&amp;quot;true&amp;quot;  stored=&amp;quot;true&amp;quot; required=&amp;quot;true&amp;quot; /&amp;gt;
   &amp;lt;field name=&amp;quot;revision&amp;quot;  type=&amp;quot;int&amp;quot;      indexed=&amp;quot;false&amp;quot; stored=&amp;quot;true&amp;quot; /&amp;gt;
   &amp;lt;field name=&amp;quot;user&amp;quot;      type=&amp;quot;string&amp;quot;   indexed=&amp;quot;true&amp;quot;  stored=&amp;quot;true&amp;quot; /&amp;gt;
   &amp;lt;field name=&amp;quot;userId&amp;quot;    type=&amp;quot;int&amp;quot;      indexed=&amp;quot;false&amp;quot; stored=&amp;quot;true&amp;quot; /&amp;gt;
   &amp;lt;field name=&amp;quot;text&amp;quot;      type=&amp;quot;text_cjk&amp;quot; indexed=&amp;quot;true&amp;quot;  stored=&amp;quot;true&amp;quot; required=&amp;quot;true&amp;quot; /&amp;gt;
   &amp;lt;field name=&amp;quot;timestamp&amp;quot; type=&amp;quot;date&amp;quot;     indexed=&amp;quot;true&amp;quot;  stored=&amp;quot;true&amp;quot; default=&amp;quot;NOW&amp;quot; multiValued=&amp;quot;false&amp;quot;/&amp;gt;
   &amp;lt;field name=&amp;quot;titleText&amp;quot; type=&amp;quot;text_cjk&amp;quot; indexed=&amp;quot;true&amp;quot;  stored=&amp;quot;true&amp;quot;/&amp;gt;
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;wikipedia-data-import.xml&lt;/span&gt;&lt;/tt&gt; で XML と Solr のフィールドへのマッピングを定義します。
&lt;tt class="docutils literal"&gt;&amp;lt;entity&amp;gt;&lt;/tt&gt; 要素の &lt;em&gt;url&lt;/em&gt; 要素で XML ファイルのパスを指定します。
ここでは自分のホームディレクトリ直下を指定しています。&lt;/p&gt;
&lt;pre class="prettyprint lang-xml literal-block"&gt;
&amp;lt;dataConfig&amp;gt;
        &amp;lt;dataSource type=&amp;quot;FileDataSource&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; /&amp;gt;
        &amp;lt;document&amp;gt;
        &amp;lt;entity name=&amp;quot;page&amp;quot;
                processor=&amp;quot;XPathEntityProcessor&amp;quot;
                stream=&amp;quot;true&amp;quot;
                forEach=&amp;quot;/mediawiki/page/&amp;quot;
                url=&amp;quot;/Users/shigeru/jawiki-latest-pages-articles.xml&amp;quot;
                transformer=&amp;quot;RegexTransformer,DateFormatTransformer&amp;quot;
                &amp;gt;
            &amp;lt;field column=&amp;quot;id&amp;quot;        xpath=&amp;quot;/mediawiki/page/id&amp;quot; /&amp;gt;
            &amp;lt;field column=&amp;quot;title&amp;quot;     xpath=&amp;quot;/mediawiki/page/title&amp;quot; /&amp;gt;
            &amp;lt;field column=&amp;quot;revision&amp;quot;  xpath=&amp;quot;/mediawiki/page/revision/id&amp;quot; /&amp;gt;
            &amp;lt;field column=&amp;quot;user&amp;quot;      xpath=&amp;quot;/mediawiki/page/revision/contributor/username&amp;quot; /&amp;gt;
            &amp;lt;field column=&amp;quot;userId&amp;quot;    xpath=&amp;quot;/mediawiki/page/revision/contributor/id&amp;quot; /&amp;gt;
            &amp;lt;field column=&amp;quot;text&amp;quot;      xpath=&amp;quot;/mediawiki/page/revision/text&amp;quot; /&amp;gt;
            &amp;lt;field column=&amp;quot;timestamp&amp;quot; xpath=&amp;quot;/mediawiki/page/revision/timestamp&amp;quot; dateTimeFormat=&amp;quot;yyyy-MM-dd'T'hh:mm:ss'Z'&amp;quot; /&amp;gt;
            &amp;lt;field column=&amp;quot;$skipDoc&amp;quot;  regex=&amp;quot;^#REDIRECT .*&amp;quot; replaceWith=&amp;quot;true&amp;quot; sourceColName=&amp;quot;text&amp;quot;/&amp;gt;
       &amp;lt;/entity&amp;gt;
        &amp;lt;/document&amp;gt;
&amp;lt;/dataConfig&amp;gt;
&lt;/pre&gt;
&lt;p&gt;余計な記述も多いですが、ファイルは次のリンクにあります。 (github)&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/skitazaki/sandbox/blob/master/src/misc/wikipedia-data-config.xml"&gt;wikipedia-data-config.xml&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/skitazaki/sandbox/blob/master/src/misc/wikipedia-schema.xml"&gt;wikipedia-schema.xml&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/skitazaki/sandbox/blob/master/src/misc/wikipedia-solrconfig.xml"&gt;wikipedia-solrconfig.xml&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="id1"&gt;
&lt;h1&gt;インポートする&lt;/h1&gt;
&lt;p&gt;Solr を起動したら管理画面を表示させます。
4系からは管理画面が刷新されて、マルチコアにした場合の視認性が向上します。&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-yFrjx486iN4/TxrPIqDsuWI/AAAAAAAAGFg/hhRdN9tkvLc/s1600/solr-admin-4.0-SNAPSHOT.jpg" imageanchor="1" style="float:left; margin-right:1em; margin-bottom:1em"&gt;&lt;img border="0" height="130" width="320" src="http://3.bp.blogspot.com/-yFrjx486iN4/TxrPIqDsuWI/AAAAAAAAGFg/hhRdN9tkvLc/s320/solr-admin-4.0-SNAPSHOT.jpg" /&gt;&lt;/a&gt;

&lt;a href="http://3.bp.blogspot.com/-Y70fh_3L3hs/TxrPJD4eroI/AAAAAAAAGFs/reqjz-k926E/s1600/solr-admin-dataimport.jpg" imageanchor="1" style="float:left; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" height="195" width="320" src="http://3.bp.blogspot.com/-Y70fh_3L3hs/TxrPJD4eroI/AAAAAAAAGFs/reqjz-k926E/s320/solr-admin-dataimport.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;div class="separator" style="clear: both;"&gt;
&lt;/div&gt;
&lt;p&gt;DataImport の部分を確認し、entity をしてインポートを実行します。
インポート中はステータスを確認するようになっており、進捗状況が分かります。&lt;/p&gt;
&lt;p&gt;すべてのインポートが終わると処理件数が表示されます。
実際に検索してみて、確かにヒットすることを確認しておきます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ curl &amp;quot;http://localhost:8983/solr/wikipedia/select?q=東京都&amp;amp;wt=json&amp;amp;indent=true&amp;amp;rows=2&amp;quot;
{
  &amp;quot;responseHeader&amp;quot;:{
    &amp;quot;status&amp;quot;:0,
    &amp;quot;QTime&amp;quot;:0,
    &amp;quot;params&amp;quot;:{
      &amp;quot;indent&amp;quot;:&amp;quot;true&amp;quot;,
      &amp;quot;wt&amp;quot;:&amp;quot;json&amp;quot;,
      &amp;quot;q&amp;quot;:&amp;quot;東京都&amp;quot;,
      &amp;quot;rows&amp;quot;:&amp;quot;2&amp;quot;}},
  &amp;quot;response&amp;quot;:{&amp;quot;numFound&amp;quot;:92823,&amp;quot;start&amp;quot;:0,&amp;quot;docs&amp;quot;:[
      {
        &amp;quot;id&amp;quot;:23340,
        &amp;quot;timestamp&amp;quot;:&amp;quot;2003-11-02T01:45:21Z&amp;quot;,
        &amp;quot;revision&amp;quot;:2191172,
        &amp;quot;title&amp;quot;:&amp;quot;東京市と都&amp;quot;,
        &amp;quot;titleText&amp;quot;:&amp;quot;東京市と都&amp;quot;,
        &amp;quot;text&amp;quot;:&amp;quot;#redirect [[東京都]]&amp;quot;,
        &amp;quot;userId&amp;quot;:490,
        &amp;quot;user&amp;quot;:&amp;quot;秀の介&amp;quot;},
      {
        &amp;quot;id&amp;quot;:321811,
        &amp;quot;timestamp&amp;quot;:&amp;quot;2005-09-05T23:11:51Z&amp;quot;,
        &amp;quot;revision&amp;quot;:2899301,
        &amp;quot;title&amp;quot;:&amp;quot;東京都の市区町村&amp;quot;,
        &amp;quot;titleText&amp;quot;:&amp;quot;東京都の市区町村&amp;quot;,
        &amp;quot;text&amp;quot;:&amp;quot;#REDIRECT[[東京都]]&amp;quot;}]
  }}
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h1&gt;マルチコアの設定&lt;/h1&gt;
&lt;p&gt;久しぶりに Solr のマルチコア設定をしたら JAR のパス解決に手こずりました。
個別の &lt;tt class="docutils literal"&gt;solrconfig.xml&lt;/tt&gt; に &lt;tt class="docutils literal"&gt;&amp;lt;lib&amp;gt;&lt;/tt&gt; タグを記述しても良いとは思いますが、
&lt;tt class="docutils literal"&gt;solr.xml&lt;/tt&gt; の &lt;tt class="docutils literal"&gt;&amp;lt;solr&amp;gt;&lt;/tt&gt; タグの &lt;em&gt;sharedLib&lt;/em&gt; 属性でパスを指定することで解決しました。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://wiki.apache.org/solr/CoreAdmin"&gt;Quick Review: What are Multiple Cores?&lt;/a&gt; (Solr Wiki)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;今回は example ディレクトリの隣にある multicore ディレクトリに &lt;em&gt;wikipedia&lt;/em&gt; という場所を作り、
&lt;tt class="docutils literal"&gt;solr.xml&lt;/tt&gt; を編集しました。&lt;/p&gt;
&lt;p&gt;ディレクトリ構成は次のようになります。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ tree -L 1 multicore
multicore
├── README.txt   &amp;lt;-- 配布パッケージに含まれる
├── core0        &amp;lt;-- 配布パッケージに含まれる
├── core1        &amp;lt;-- 配布パッケージに含まれる
├── exampledocs  &amp;lt;-- 配布パッケージに含まれる
├── lib          &amp;lt;-- コアで共有する JAR を置く
├── solr.xml     &amp;lt;-- コアの設定ファイル
└── wikipedia    &amp;lt;-- 自分で追加
&lt;/pre&gt;
&lt;p&gt;他のインデクスデータと混ぜたくない場合 (テスト用など)、
そもそもスキーマが異なる場合には、コアを変えて管理すると便利です。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;Solr に Wikipedia のデータをインポートしました。
データのダウンロードとインポートで、それぞれ数時間くらいはかかると考えた方が良いでしょう。
部屋の掃除などをしながら、気長に作業する感じでしょうか。&lt;/p&gt;
&lt;p&gt;実際にどのような検索軸で遊んでみるかは、こちらの記事が参考になると思います。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.mwsoft.jp/programming/munou/wikipedia_solr.html"&gt;SolrにWikipediaのデータを入れて遊ぶ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;また、別の話題になってしまいますが、
ベンチマークなどではそれなりにたくさんのデータが必要になります。
英語のデータばかりではありますが、こうした記事でまとめてくれるのは嬉しいですね。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.findbestopensource.com/article-detail/free-large-data-corpus"&gt;10 sites to get the large data set or data corpus for free&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-4742516422949740824?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/4742516422949740824/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=4742516422949740824' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/4742516422949740824'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/4742516422949740824'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2012/01/solr-wikipedia-data-import.html' title='Solr に Wikipedia のデータをインポートする'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-kCbl4D6fXNI/TxrPIeqNg9I/AAAAAAAAGFU/Q6aDk9zbowU/s72-c/solr-admin-dataimport-finished.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-1215628878984727060</id><published>2012-01-15T08:49:00.004+09:00</published><updated>2012-01-15T09:11:47.048+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Solr'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>Solr の trunk を使ってみる</title><content type='html'>&lt;p&gt;調べ物をするときにソースコードがあった方が便利な場合もありますので、
Lucene/Solr の trunk のソースコードを取得して動かしてみます。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://lucene.apache.org/solr/"&gt;Apache Solr&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Java と Ant と Subversion はインストール済とします。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;

&lt;div class="section" id="id1"&gt;
&lt;h1&gt;ソースコードをチェックアウトする&lt;/h1&gt;
&lt;p&gt;ASF のプロジェクトのお作法に従ってチェックアウトします。
詳しくはこちらのページを参照。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.apache.org/dev/version-control.html"&gt;Source Code Repository&lt;/a&gt; - apache.org&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="literal-block"&gt;
$ svn co http://svn.apache.org/repos/asf/lucene/dev/trunk lucene-solr

(出力省略)
&lt;/pre&gt;
&lt;p&gt;中身を確認しておきます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cd lucene-solr/
$ ls
README.txt  build.xml   dev-tools/  lucene/     modules/    solr/
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h1&gt;ソースコードをビルドする&lt;/h1&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;build.xml&lt;/tt&gt; のターゲットを確認しておきます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ grep &amp;quot;&amp;lt;target&amp;quot; build.xml
  &amp;lt;target name=&amp;quot;test&amp;quot; description=&amp;quot;Test both Lucene and Solr&amp;quot; depends=&amp;quot;validate&amp;quot;&amp;gt;
  &amp;lt;target name=&amp;quot;javadocs&amp;quot; description=&amp;quot;Generate Lucene and Solr javadocs&amp;quot;&amp;gt;
  &amp;lt;target name=&amp;quot;validate&amp;quot; description=&amp;quot;Validate dependencies, licenses, etc.&amp;quot;&amp;gt;
  &amp;lt;target name=&amp;quot;compile&amp;quot; description=&amp;quot;Compile Lucene and Solr&amp;quot;&amp;gt;
  &amp;lt;target name=&amp;quot;get-maven-poms&amp;quot;
  &amp;lt;target name=&amp;quot;generate-maven-artifacts&amp;quot; description=&amp;quot;Generate Maven Artifacts for Lucene and Solr&amp;quot;&amp;gt;
  &amp;lt;target name=&amp;quot;eclipse&amp;quot; description=&amp;quot;Setup Eclipse configuration&amp;quot;&amp;gt;
  &amp;lt;target name=&amp;quot;idea&amp;quot; description=&amp;quot;Setup IntelliJ IDEA configuration&amp;quot;&amp;gt;
  &amp;lt;target name=&amp;quot;clean-idea&amp;quot;
  &amp;lt;target name=&amp;quot;clean&amp;quot; description=&amp;quot;Clean Lucene and Solr&amp;quot;&amp;gt;
&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;compile&lt;/em&gt; でコンパイルしてくれますので、これを実行してしばらく待ちます。
一応、時間も計測しておきましょう。(Ant 自体が時間を出力するので、 &lt;tt class="docutils literal"&gt;time&lt;/tt&gt; コマンドはなくても良い。)&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ time ant compile

(出力省略)

BUILD SUCCESSFUL
Total time: 58 seconds

real    0m58.528s
user    1m16.734s
sys     0m7.490s
&lt;/pre&gt;
&lt;p&gt;次に、Solr の &lt;cite&gt;example&lt;/cite&gt; 用に必要なファイルをコピーします。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cd solr
$ time ant example

(出力省略)

example:
     [copy] Copying 1 file to /Users/shigeru/workspace/lucene-solr/solr/example/webapps
      [jar] Building jar: /Users/shigeru/workspace/lucene-solr/solr/example/exampledocs/post.jar
     [echo] See /Users/shigeru/workspace/lucene-solr/solr/example/README.txt for how to run the Solr example configuration.

BUILD SUCCESSFUL
Total time: 25 seconds

real    0m26.300s
user    0m36.986s
sys     0m4.495s
&lt;/pre&gt;
&lt;p&gt;最後の &lt;em&gt;echo&lt;/em&gt; 部分で「README.txt を見てね」と出力されていますので、
読んでおきましょう。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;サンプルを動かしてみる&lt;/h1&gt;
&lt;p&gt;&lt;cite&gt;example&lt;/cite&gt; ディレクトリにサンプルがありますので、
これを使って簡単なテストを実施します。
&lt;em&gt;README.txt&lt;/em&gt; に書かれていることでもあります。&lt;/p&gt;
&lt;div class="section" id="jetty"&gt;
&lt;h2&gt;Jetty を使って起動する&lt;/h2&gt;
&lt;p&gt;&lt;cite&gt;example&lt;/cite&gt; ディレクトリに移動して起動させます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cd example
$ java -jar start.jar

(出力省略)

2012-01-14 22:42:16.215:INFO::Started SocketConnector&amp;#64;0.0.0.0:8983
&lt;/pre&gt;
&lt;p&gt;最後に、8983番ポートで待ち受けているログが出力されていますね。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h2&gt;管理画面を表示する&lt;/h2&gt;
&lt;p&gt;ブラウザで &amp;quot;&lt;a class="reference external" href="http://localhost:8983/solr/admin/"&gt;http://localhost:8983/solr/admin/&lt;/a&gt;&amp;quot; にアクセスすると管理画面を表示できます。
設定ファイルの表示や、クエリの確認などができます。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h2&gt;インデクスを追加する&lt;/h2&gt;
&lt;p&gt;&lt;cite&gt;example/exampledocs&lt;/cite&gt; に &lt;tt class="docutils literal"&gt;post.jar&lt;/tt&gt; と &lt;tt class="docutils literal"&gt;post.sh&lt;/tt&gt; というファイルがあります。
これが XML を投げるプログラムになっており、引数でインデクスに追加するファイルを指定します。&lt;/p&gt;
&lt;p&gt;サーバを起動しているのとは異なるターミナルを起動し、
&lt;cite&gt;exampledocs&lt;/cite&gt; ディレクトリまで移動します。
このディレクトリにはサンプルの XML がありますので、
それらのすべてをインデクスに追加します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cd {your-lucene-solr-trunk}
$ cd solr/example/exampledocs

$ java -jar post.jar *.xml
SimplePostTool: version 1.4
SimplePostTool: POSTing files to http://localhost:8983/solr/update..
SimplePostTool: POSTing file gb18030-example.xml
SimplePostTool: POSTing file hd.xml
SimplePostTool: POSTing file ipod_other.xml
SimplePostTool: POSTing file ipod_video.xml
SimplePostTool: POSTing file manufacturers.xml
SimplePostTool: POSTing file mem.xml
SimplePostTool: POSTing file monitor.xml
SimplePostTool: POSTing file monitor2.xml
SimplePostTool: POSTing file mp500.xml
SimplePostTool: POSTing file sd500.xml
SimplePostTool: POSTing file solr.xml
SimplePostTool: POSTing file utf8-example.xml
SimplePostTool: POSTing file vidcard.xml
SimplePostTool: COMMITting Solr index changes..
&lt;/pre&gt;
&lt;p&gt;最後にコミットも発行されています。
サーバ側のログにもコミットされたとのメッセージが出力されています。&lt;/p&gt;
&lt;p&gt;インデクスに追加する XML の書式は、Wiki に記載されています。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://wiki.apache.org/solr/UpdateXmlMessages"&gt;XML Messages for Updating a Solr Index&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;フィールド名などは &lt;tt class="docutils literal"&gt;schema.xml&lt;/tt&gt; と統一しておく必要がありますので、
自分でカスタマイズする場合にはこのファイルも確認しておきましょう。&lt;/p&gt;
&lt;p&gt;なお、インデクスを更新するには、XML 以外にも CSV や DIH (&lt;a class="reference external" href="http://wiki.apache.org/solr/DataImportHandler"&gt;Data Import Handler&lt;/a&gt;) も使えます。
DIH のサンプルは &lt;cite&gt;example/example-DIH&lt;/cite&gt; にあります。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id6"&gt;
&lt;h2&gt;検索してみる&lt;/h2&gt;
&lt;p&gt;&amp;quot;q&amp;quot; パラメータに検索式を記載して検索してみます。
&amp;quot;q&amp;quot; パラメータの記法は Lucene 由来で、次のページに記述されています。
&lt;em&gt;AND&lt;/em&gt;, &lt;em&gt;OR&lt;/em&gt;, &lt;em&gt;NOT&lt;/em&gt; といった条件も確認できます。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://lucene.apache.org/java/3_4_0/queryparsersyntax.html"&gt;Query Parser Syntax&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;実際に、id フィールドが &amp;quot;apple&amp;quot; のドキュメントを検索します。
ヒューマンリーダブルにするため、&amp;quot;indent=true&amp;quot; も追加しておきます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ curl &amp;quot;http://localhost:8983/solr/select?q=id:apple&amp;amp;indent=true&amp;quot;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;response&amp;gt;

&amp;lt;lst name=&amp;quot;responseHeader&amp;quot;&amp;gt;
  &amp;lt;int name=&amp;quot;status&amp;quot;&amp;gt;0&amp;lt;/int&amp;gt;
  &amp;lt;int name=&amp;quot;QTime&amp;quot;&amp;gt;4&amp;lt;/int&amp;gt;
  &amp;lt;lst name=&amp;quot;params&amp;quot;&amp;gt;
    &amp;lt;str name=&amp;quot;indent&amp;quot;&amp;gt;true&amp;lt;/str&amp;gt;
    &amp;lt;str name=&amp;quot;q&amp;quot;&amp;gt;id:apple&amp;lt;/str&amp;gt;
  &amp;lt;/lst&amp;gt;
&amp;lt;/lst&amp;gt;
&amp;lt;result name=&amp;quot;response&amp;quot; numFound=&amp;quot;1&amp;quot; start=&amp;quot;0&amp;quot;&amp;gt;
  &amp;lt;doc&amp;gt;
    &amp;lt;str name=&amp;quot;id&amp;quot;&amp;gt;apple&amp;lt;/str&amp;gt;
    &amp;lt;str name=&amp;quot;compName_s&amp;quot;&amp;gt;Apple&amp;lt;/str&amp;gt;
    &amp;lt;str name=&amp;quot;address_s&amp;quot;&amp;gt;1 Infinite Way, Cupertino CA&amp;lt;/str&amp;gt;&amp;lt;/doc&amp;gt;
&amp;lt;/result&amp;gt;
&amp;lt;/response&amp;gt;
&lt;/pre&gt;
&lt;p&gt;デフォルトでは XML で出力されますが、
&amp;quot;wt&amp;quot; パラメータを指定すると JSON でもレスポンスを取得できます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ curl &amp;quot;http://localhost:8983/solr/select?q=id:apple&amp;amp;indent=true&amp;amp;wt=json&amp;quot;
{
  &amp;quot;responseHeader&amp;quot;:{
    &amp;quot;status&amp;quot;:0,
    &amp;quot;QTime&amp;quot;:1,
    &amp;quot;params&amp;quot;:{
      &amp;quot;indent&amp;quot;:&amp;quot;true&amp;quot;,
      &amp;quot;wt&amp;quot;:&amp;quot;json&amp;quot;,
      &amp;quot;q&amp;quot;:&amp;quot;id:apple&amp;quot;}},
  &amp;quot;response&amp;quot;:{&amp;quot;numFound&amp;quot;:1,&amp;quot;start&amp;quot;:0,&amp;quot;docs&amp;quot;:[
      {
        &amp;quot;id&amp;quot;:&amp;quot;apple&amp;quot;,
        &amp;quot;compName_s&amp;quot;:&amp;quot;Apple&amp;quot;,
        &amp;quot;address_s&amp;quot;:&amp;quot;1 Infinite Way, Cupertino CA&amp;quot;}]
  }}
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id7"&gt;
&lt;h1&gt;おわりに&lt;/h1&gt;
&lt;p&gt;Solr の trunk のソースコードを取得し、自分でビルドしてサンプルを動かしました。
trunk 特有のことは何もしていませんが、とりあえず環境を作っておくと便利かな、と。&lt;/p&gt;
&lt;p&gt;あと、こんなイベントもあったんですね。行けばよかった。。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://blog.livedoor.jp/haruyama_seigo/archives/51861752.html"&gt;2012/01/14 Lucene ソースコードリーディング会を開催&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-1215628878984727060?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/1215628878984727060/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=1215628878984727060' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/1215628878984727060'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/1215628878984727060'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2012/01/solr-trunk.html' title='Solr の trunk を使ってみる'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-2634896608778882555</id><published>2012-01-14T18:29:00.002+09:00</published><updated>2012-01-14T18:32:33.260+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><title type='text'>Haskell 環境の確認</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://www.haskell.org/haskellwiki/Haskell" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" height="100" width="100" src="http://hackage.haskell.org/platform/images/Haskell-Logo-Boxed.png" /&gt;&lt;/a&gt;&lt;/div&gt;


&lt;p&gt;昨年末に安定版がリリースされていましたので、
Haskell Platform を更新しておきます。
主に自分用のメモ書きです。&lt;/p&gt;
&lt;p&gt;手元のマシンは Mac OSX Lion です。
下記のリンクから適当なインストーラーパッケージをダウンロードして
インストールしておきます。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;&lt;a class="reference external" href="http://hackage.haskell.org/platform/"&gt;The Haskell Platform&lt;/a&gt; - hackage.haskell.org&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;Current stable release: 2011.4.0.0 (December 2011)&lt;/li&gt;
&lt;li&gt;Next release: May 2012&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;p&gt;Haskell Platform に関してはこちらの記事が参考になります。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://itpro.nikkeibp.co.jp/article/COLUMN/20100406/346695/?ST=develop&amp;amp;mkjb&amp;amp;P=1"&gt;第39回　一般向けの「Haskell Platform」とインストール・ツールの「cabalコマンド」&lt;/a&gt; - itpro.nikkeibp.co.jp&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="section" id="id1"&gt;
&lt;h1&gt;現在のバージョンを確認する&lt;/h1&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;uninstall-hs&lt;/span&gt;&lt;/tt&gt; コマンドでシステムにインストールされているバージョンを確認できます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ uninstall-hs
-- Versions found on this system
7.0.3
7.0.4
-- To remove a version and all earlier: uninstall-hs thru VERSION
-- To remove only a single version:     uninstall-hs only VERSION
&lt;/pre&gt;
&lt;p&gt;ふたつのバージョンがインストールされています。
古い方はいらないので、 &lt;cite&gt;only&lt;/cite&gt; でバージョンを指定します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ uninstall-hs only 7.0.3
-- Would remove just version 7.0.3
/Library/Frameworks/GHC.framework/Versions/7.0.3-i386
/Library/Haskell/ghc-7.0.3
/usr/bin/ghc-7.0.3&amp;#64; -&amp;gt; /Library/Frameworks/GHC.framework/Versions/7.0.3-i386/usr/bin/ghc-7.0.3
/usr/bin/ghc-pkg-7.0.3&amp;#64; -&amp;gt; /Library/Frameworks/GHC.framework/Versions/7.0.3-i386/usr/bin/ghc-pkg-7.0.3
/usr/bin/ghci-7.0.3&amp;#64; -&amp;gt; /Library/Frameworks/GHC.framework/Versions/7.0.3-i386/usr/bin/ghci-7.0.3
/usr/bin/haddock-ghc-7.0.3&amp;#64; -&amp;gt; /Library/Frameworks/GHC.framework/Versions/7.0.3-i386/usr/bin/haddock-ghc-7.0.3
-- To actually remove these files, sudo run the command again with --remove
-- To generate a script to remove these files, run the command again with --script
&lt;/pre&gt;
&lt;p&gt;何が削除されるかを確認してくれました。&lt;/p&gt;
&lt;div class="section" id="id2"&gt;
&lt;h2&gt;実際に削除する&lt;/h2&gt;
&lt;p&gt;実際に削除するには &lt;tt class="docutils literal"&gt;sudo&lt;/tt&gt; を使って &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--remove&lt;/span&gt;&lt;/tt&gt; オプションを付けます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ sudo uninstall-hs --remove only 7.0.3
Password:
-- Removing just version 7.0.3
&lt;/pre&gt;
&lt;p&gt;もう一度 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;uninstall-hs&lt;/span&gt;&lt;/tt&gt; コマンドを使うと、削除されたことを確認できます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ uninstall-hs
-- Versions found on this system
7.0.4
-- To remove a version and all earlier: uninstall-hs thru VERSION
-- To remove only a single version:     uninstall-hs only VERSION
&lt;/pre&gt;
&lt;p&gt;実際、ファイルシステムからも削除されています。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ ls -l /Library/Frameworks/GHC.framework/Versions/
total 8
drwxr-xr-x  5 root     admin  170 Dec  6 12:01 7.0.4-x86_64/
lrwxr-xr-x  1 shigeru  wheel   12 Jan  6 07:51 Current&amp;#64; -&amp;gt; 7.0.4-x86_64
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;パッケージの一覧を表示する&lt;/h1&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;ghc-pkg&lt;/span&gt;&lt;/tt&gt; コマンドでパッケージの一覧を確認します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ ghc-pkg list
/Library/Frameworks/GHC.framework/Versions/7.0.4-x86_64/usr/lib/ghc-7.0.4/package.conf.d
   Cabal-1.10.2.0
   GLUT-2.1.2.1
   HTTP-4000.1.2
   HUnit-1.2.4.2
   OpenGL-2.2.3.0
   QuickCheck-2.4.1.1
   array-0.3.0.2
   base-4.3.1.0
   bin-package-db-0.0.0.0
   bytestring-0.9.1.10
   cgi-3001.1.7.4
   containers-0.4.0.0
   deepseq-1.1.0.2
   directory-1.1.0.0
   extensible-exceptions-0.1.1.2
   ffi-1.0
   fgl-5.4.2.4
   filepath-1.2.0.0
   ghc-7.0.4
   ghc-binary-0.5.0.2
   ghc-prim-0.2.0.0
   haskell-platform-2011.3.0.0
   haskell-src-1.0.1.4
   haskell2010-1.0.0.0
   haskell98-1.1.0.1
   hpc-0.5.0.6
   html-1.0.1.2
   integer-gmp-0.2.0.3
   mtl-2.0.1.0
   network-2.3.0.5
   old-locale-1.0.0.2
   old-time-1.0.0.6
   parallel-3.1.0.1
   parsec-3.1.1
   pretty-1.0.1.2
   process-1.0.1.5
   random-1.0.0.3
   regex-base-0.93.2
   regex-compat-0.95.1
   regex-posix-0.95.1
   rts-1.0
   stm-2.2.0.1
   syb-0.3.3
   template-haskell-2.5.0.0
   text-0.11.1.5
   time-1.2.0.3
   transformers-0.2.2.0
   unix-2.4.2.0
   xhtml-3000.2.0.4
   zlib-0.5.3.1
&lt;/pre&gt;
&lt;p&gt;&lt;a class="reference external" href="http://hackage.haskell.org/package/utf8-string-0.3.7"&gt;utf8-string&lt;/a&gt; がありません。
以前のマシンでは &lt;em&gt;macport&lt;/em&gt; で用意しましたが、
新しいバージョンでは必要ないそうです。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h1&gt;追加パッケージをインストールする&lt;/h1&gt;
&lt;p&gt;Haskell のパッケージは &lt;em&gt;HackageDB&lt;/em&gt; で管理されています。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://hackage.haskell.org/packages/hackage.html"&gt;HackageDB&lt;/a&gt; - hackage.haskell.org&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;パッケージの管理には &lt;em&gt;Cabal&lt;/em&gt; を使います。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.haskell.org/cabal/"&gt;Cabal&lt;/a&gt; - haskell.org&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;とりあえず &lt;tt class="docutils literal"&gt;cabal&lt;/tt&gt; コマンドを実行してみます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cabal

**********************************************************************


=== Configuration for cabal has been written to
    /Users/shigeru/.cabal/config

=== Executables will be installed in:
    /Users/shigeru/Library/Haskell/bin

    You may wish to place this on your PATH by adding the following
    line to your ~/.bash_profile:

    export PATH=&amp;quot;$HOME/Library/Haskell/bin:$PATH&amp;quot;

=== When documentation is built, a master index to all documentation
    will be placed in:

    /Users/shigeru/Library/Haskell/doc/index.html

    You may wish to bookmark that file once it gets built (after the
    first cabal install).

**********************************************************************

Downloading the latest package list from hackage.haskell.org
cabal: no command given (try --help)
&lt;/pre&gt;
&lt;p&gt;設定ファイルが生成され、パッケージの一覧が更新されました。&lt;/p&gt;
&lt;div class="section" id="id5"&gt;
&lt;h2&gt;インストールしてみる&lt;/h2&gt;
&lt;p&gt;CSV を処理するモジュールを探します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cabal list csv
* bytestring-csv
    Synopsis: Parse CSV formatted data efficiently
    Default available version: 0.1.2
    Installed versions: [ Not installed ]
    Homepage: http://code.haskell.org/~dons/code/bytestring-csv
    License:  BSD3

* csv
    Synopsis: CSV loader and dumper
    Default available version: 0.1.2
    Installed versions: [ Not installed ]
    License:  MIT

* csv-enumerator
    Synopsis: A flexible, fast, enumerator-based CSV parser library for Haskell.
    Default available version: 0.10.1.0
    Installed versions: [ Not installed ]
    Homepage: http://github.com/ozataman/csv-enumerator
    License:  BSD3

* cursedcsv
    Synopsis: Terminal tool for viewing tabular data
    Default available version: 0.1
    Installed versions: [ Unknown ]
    License:  BSD3
&lt;/pre&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/ozataman/csv-enumerator"&gt;csv-enumerator&lt;/a&gt; をインストールします。まずは &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--dry-run&lt;/span&gt;&lt;/tt&gt; オプションで確認。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cabal install csv-enumerator --dry-run
Resolving dependencies...
In order, the following would be installed (use -v for more details):
attoparsec-0.10.1.0
enumerator-0.4.17
attoparsec-enumerator-0.3
safe-0.3.3
unix-compat-0.3.0.1
csv-enumerator-0.10.1.0
&lt;/pre&gt;
&lt;p&gt;依存ライブラリがいくつかあるようです。&lt;/p&gt;
&lt;p&gt;実際にインストールします。ログは長いので省略します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cabal install csv-enumerator

(ログ省略)
&lt;/pre&gt;
&lt;p&gt;ドキュメントも更新されていますので確認しましょう。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ open /Users/shigeru/Library/Haskell/doc/index.html
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id6"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;去年は Haskell を書こうと思いつつも全然書いていませんでしたので、
とりあえず環境を更新して、今年は何とか継続したいなぁ、と。&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-2634896608778882555?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/2634896608778882555/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=2634896608778882555' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/2634896608778882555'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/2634896608778882555'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2012/01/hello-haskell-2.html' title='Haskell 環境の確認'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-8883091480577364220</id><published>2012-01-13T22:54:00.001+09:00</published><updated>2012-01-13T22:58:01.357+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='サッカー'/><title type='text'>FC東京 - ACL2012 のカレンダー</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://www.fctokyo.co.jp/" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" height="100" width="300" src="http://www.fctokyo.co.jp/images/common/fctokyo_logo_header.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;


今年は元旦にFC東京が天皇杯で優勝しました。
天皇杯優勝チームは ACL (=アジア・チャンピオンズ・リーグ) に出場できます。
ということで、ACL2012 におけるFC東京のカレンダーを作りました。



&lt;a name='more'&gt;&lt;/a&gt;

常に３月から５月までの予定を表示させる方法が分かりませんでしたので、手動で読み込む必要がありますが、自分の Google Calendar に取り込んでおくと便利だと思います。
なお、タイムゾーンの扱いが微妙だったので試合の時間は入れていません。
&lt;iframe src="https://www.google.com/calendar/embed?showPrint=0&amp;amp;showCalendars=0&amp;amp;mode=AGENDA&amp;amp;height=600&amp;amp;wkst=1&amp;amp;bgcolor=%23ffcccc&amp;amp;src=nofj8usf6v5lk9urfc9c9hf6ho%40group.calendar.google.com&amp;amp;color=%23182C57&amp;amp;ctz=Asia%2FTokyo" style=" border-width:0 " width="800" height="600" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;

&lt;p&gt;公式スケジュールの Group F の部分から作成しました。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.the-afc.com/en/acl2012-schedule-results?view=Competitions&amp;id=430"&gt;AFC Champions League 
Schedule &amp; Results&lt;/a&gt; - the-afc.com&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-8883091480577364220?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/8883091480577364220/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=8883091480577364220' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/8883091480577364220'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/8883091480577364220'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2012/01/fctokyo-acl2012-calendar.html' title='FC東京 - ACL2012 のカレンダー'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-7653684295047009880</id><published>2012-01-04T16:19:00.003+09:00</published><updated>2012-01-04T16:20:16.373+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Python の学習資料 - 2</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://python.org/images/python-logo.gif" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" height="71" width="211" src="http://python.org/images/python-logo.gif" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;Python の学習資料を追記しました。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://skitazaki.github.com/python-school-ja/index.html"&gt;Python School 1.1.0 documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ファイルシステムとのやり取りに関することがメインとなります。
ローカルのマシンに対しては &lt;cite&gt;os&lt;/cite&gt; と &lt;cite&gt;subprocess&lt;/cite&gt; モジュールを使うと多くの作業をスクリプトで記述できるようになります。
リモートのマシンに対しては SSH を使って操作することが多くなりますが、
Python の &lt;em&gt;paramiko&lt;/em&gt; モジュールや &lt;em&gt;fabric&lt;/em&gt; を使うことで、
ローカルのマシンと似たような雰囲気で作業を自動化できるようになります。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="id1"&gt;
&lt;h1&gt;追加内容&lt;/h1&gt;
&lt;dl class="docutils"&gt;
&lt;dt&gt;コマンドライン操作 - 1&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;ファイル一覧を取得する&lt;/li&gt;
&lt;li&gt;ファイルの最終更新時刻を取得する&lt;/li&gt;
&lt;li&gt;ファイル一覧をソートする&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;コマンドライン操作 - 2&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;パスを連結する&lt;/li&gt;
&lt;li&gt;ファイル操作いろいろ&lt;/li&gt;
&lt;li&gt;ファイルシステムの階層を辿る&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;コマンドライン操作 - 3&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;環境変数の扱い&lt;/li&gt;
&lt;li&gt;設定ファイルの扱い&lt;/li&gt;
&lt;li&gt;HTTP でダウンロード (記述場所を移動する予定)&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;コマンドライン操作 - 4&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;シェルコマンドの実行&lt;/li&gt;
&lt;li&gt;コマンドの実行を待つ&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;コマンドライン操作 - 5&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;リモートサーバの操作&lt;/li&gt;
&lt;li&gt;paramiko を使う&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;dt&gt;コマンドライン操作 - 6&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;fabric のインストール&lt;/li&gt;
&lt;li&gt;fabfile.py&lt;/li&gt;
&lt;li&gt;fab コマンドの実行&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;何となく雑多だなぁ、と思っていたことを集約しました。
改めて自分で資料を書いてみると、やっぱりまとまらないなぁ、と再認識。
しかし、ちょっとしたスクリプトやモジュールは単に知っているかどうかの問題でしかありませんので、
折に触れて使ってみる / 読んでみることも大切だと思います。&lt;/p&gt;
&lt;p&gt;せっかくの新年ですから、スクリプトの勉強がてらファイルシステムを整理するのも良いかもしれませんね。&lt;/p&gt;
&lt;p&gt;前の記事:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/12/python-school.html"&gt;Python の学習資料&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-7653684295047009880?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/7653684295047009880/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=7653684295047009880' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/7653684295047009880'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/7653684295047009880'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2012/01/python-school-2.html' title='Python の学習資料 - 2'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-3012327176496421304</id><published>2011-12-31T09:54:00.002+09:00</published><updated>2011-12-31T09:54:19.184+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='生活'/><title type='text'>2011年の振り返り</title><content type='html'>&lt;p&gt;年末なので2011年を振り返っておきます。
今年は東日本大震災があって色々なことを考えさせられた一年でした。
個人的にも転職イベントがあり、なんか色々と考えた気がする一年です。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="id2"&gt;
&lt;h1&gt;月々の出来事&lt;/h1&gt;
&lt;p&gt;毎月のトピックを二つずつ挙げておきます。
プライベートも駄々漏れですが、来年以降に見直してみると自分で「へぇ～」と思うはずなので書き残しておきます。&lt;/p&gt;
&lt;table class="docutils field-list" frame="void" rules="none"&gt;
&lt;col class="field-name" /&gt;
&lt;col class="field-body" /&gt;
&lt;tbody valign="top"&gt;
&lt;tr class="field"&gt;&lt;th class="field-name"&gt;１月:&lt;/th&gt;&lt;td class="field-body"&gt;&lt;ul class="first simple"&gt;
&lt;li&gt;高校サッカー選手権大会を観に行く。&lt;/li&gt;
&lt;li&gt;Japan Innovation Leaders Summit で MIT Media Labs の石井先生の話を聞く。&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="field"&gt;&lt;th class="field-name"&gt;２月:&lt;/th&gt;&lt;td class="field-body"&gt;&lt;ul class="first simple"&gt;
&lt;li&gt;アジアカップで日本が優勝したのでカップを掲げてきた。&lt;/li&gt;
&lt;li&gt;XMPP の洋書を読み切る。&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="field"&gt;&lt;th class="field-name"&gt;３月:&lt;/th&gt;&lt;td class="field-body"&gt;&lt;ul class="first simple"&gt;
&lt;li&gt;東日本大震災！&lt;/li&gt;
&lt;li&gt;なんか色々と調査しないとな〜と思い始める。&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="field"&gt;&lt;th class="field-name"&gt;４月:&lt;/th&gt;&lt;td class="field-body"&gt;&lt;ul class="first simple"&gt;
&lt;li&gt;Twisted に関する英文記事のシリーズを翻訳した。&lt;/li&gt;
&lt;li&gt;Haskell を触ってみる。&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="field"&gt;&lt;th class="field-name"&gt;５月:&lt;/th&gt;&lt;td class="field-body"&gt;&lt;ul class="first simple"&gt;
&lt;li&gt;新卒で入社した会社を退職。&lt;/li&gt;
&lt;li&gt;アジャイルスタートアップで Pivotal Labs の人の話を聞く。&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="field"&gt;&lt;th class="field-name"&gt;６月:&lt;/th&gt;&lt;td class="field-body"&gt;&lt;ul class="first simple"&gt;
&lt;li&gt;新しい会社に入社。&lt;/li&gt;
&lt;li&gt;検索システム Solr をちょこちょこ触る。&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="field"&gt;&lt;th class="field-name"&gt;７月:&lt;/th&gt;&lt;td class="field-body"&gt;&lt;ul class="first simple"&gt;
&lt;li&gt;女子ワールドカップで日本が優勝。寝不足。。&lt;/li&gt;
&lt;li&gt;DotCloud を触ってみる。&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="field"&gt;&lt;th class="field-name"&gt;８月:&lt;/th&gt;&lt;td class="field-body"&gt;&lt;ul class="first simple"&gt;
&lt;li&gt;自分で夏休みの宿題みたいことをやってみる。(Waf / JavaScript MVC)&lt;/li&gt;
&lt;li&gt;HTML5 のことをキャッチアップし始める。&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="field"&gt;&lt;th class="field-name"&gt;９月:&lt;/th&gt;&lt;td class="field-body"&gt;&lt;ul class="first simple"&gt;
&lt;li&gt;ドラッカーの本を読んでみる。&lt;/li&gt;
&lt;li&gt;Solr の勉強会に行ってみる。&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="field"&gt;&lt;th class="field-name"&gt;10月:&lt;/th&gt;&lt;td class="field-body"&gt;&lt;ul class="first simple"&gt;
&lt;li&gt;Node と Nginx を調べてみる。&lt;/li&gt;
&lt;li&gt;Python の学習資料を書き始める。&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="field"&gt;&lt;th class="field-name"&gt;11月:&lt;/th&gt;&lt;td class="field-body"&gt;&lt;ul class="first simple"&gt;
&lt;li&gt;FC東京の J1 昇格が決まる。&lt;/li&gt;
&lt;li&gt;Google Buzz が終了する。&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="field"&gt;&lt;th class="field-name"&gt;12月:&lt;/th&gt;&lt;td class="field-body"&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;FC東京が天皇杯の決勝に進出する。去年のリベンジ！&lt;/li&gt;
&lt;li&gt;Python の学習資料をひとまず公開する。&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;世界の出来事&lt;/h1&gt;
&lt;p&gt;世界のニュースは The Big Picture (Bostom.com) の132枚の写真が良い感じですね。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.boston.com/bigpicture/2011/12/the_year_in_pictures_part.html"&gt;The Year in Pictures: Part I&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.boston.com/bigpicture/2011/12/the_year_in_pictures_part_ii.html"&gt;The year in Pictures: Part II&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.boston.com/bigpicture/2011/12/the_year_in_pictures_part_iii.html"&gt;The Year in Pictures: Part III&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;個人的な印象として、今年は災害や訃報が多かったような気がします。
来年はもう少し良いことがありますように、と思います。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h1&gt;過去の記事&lt;/h1&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2010/12/2010.html"&gt;2010年の振り返り&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2009/12/2009.html"&gt;2009年の振り返り&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2008/12/2008.html"&gt;2008年の振り返り&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-3012327176496421304?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/3012327176496421304/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=3012327176496421304' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/3012327176496421304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/3012327176496421304'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/12/2011.html' title='2011年の振り返り'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-1971011042998983946</id><published>2011-12-20T23:35:00.003+09:00</published><updated>2011-12-20T23:36:31.496+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Solr'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>第７回 Solr 勉強会に行ってきた</title><content type='html'>&lt;p&gt;Solr の勉強会 (2011/12/19 19:00 to 21:30) に行ってきました。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://atnd.org/events/22329"&gt;第７回Solr勉強会&lt;/a&gt; - atnd.org&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://twitter.com/#!/search/solrjp"&gt;#SolrJP&lt;/a&gt; - twitter.com&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://togetter.com/li/229791"&gt;2011/12/19_第7回 Solr＆検索エンジン勉強会( #SolrJP )&lt;/a&gt; - togetter.com&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://johtani.jugem.jp/?eid=49"&gt;Solr勉強会第７回に参加しました。（発表もしました）&lt;/a&gt; - johtani.jugem.jp&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ので、そのメモ。&lt;/p&gt;
&lt;p&gt;会場を提供してくださった VOYAGE GROUP さん、運営者の方々、ありがとうございました。&lt;/p&gt;
&lt;p&gt;Solr に特化した内容ではなく、ちょっと間口を広げて検索一般の話もあって勉強になりました。
というか、ちゃんと統計とか数学とかを勉強し直さないと先がないなぁ、と思ったり。。。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="id2"&gt;
&lt;h1&gt;発表とか&lt;/h1&gt;
&lt;div class="section" id="solrfess"&gt;
&lt;h2&gt;Solrベースの全文検索サーバFess&lt;/h2&gt;
&lt;p&gt;株式会社エヌツーエスエム　菅谷 信介さん&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://fess.sourceforge.jp/ja/index.html"&gt;オープンソース全文検索サーバー Fess (フェス)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ステータス:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Full tExt Search System から FESS。&lt;/li&gt;
&lt;li&gt;第２回の勉強会で紹介。その後も開発を継続。&lt;/li&gt;
&lt;li&gt;最新バージョンは 5.0 で、Solr は 3.5。&lt;/li&gt;
&lt;li&gt;当初は独立した設計だったが、次第に Solr に依存するようになってきた。&lt;/li&gt;
&lt;li&gt;商用サポートもあるし、個人でも簡単に導入できる。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;機能:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;インデクスを作成するときにロール情報を付加している。ログイン状態によって検索結果が違う。&lt;/li&gt;
&lt;li&gt;カテゴリ絞り込みも可能。デスクトップ検索といった機能も追加。クリックログの統計情報もあり。&lt;/li&gt;
&lt;li&gt;クローリングには &lt;a class="reference external" href="http://s2robot.sandbox.seasar.org/ja/"&gt;S2Robot&lt;/a&gt; を利用。  下位レイヤで Tike, POI などを利用。&lt;/li&gt;
&lt;li&gt;Solr Server Manager -&amp;gt; Solr Group -&amp;gt; Solr Server で段階的に管理。グループAは更新用、グループBは検索用、などのように使い分け可能。&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="lucene-gosen"&gt;
&lt;h2&gt;lucene-gosenの話&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="http://twitter.com/johtani"&gt;&amp;#64;johtani&lt;/a&gt; さん&lt;/p&gt;
&lt;p&gt;lucene-gosen のコミッターのひとり。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://code.google.com/p/lucene-gosen/"&gt;lucene-gosen&lt;/a&gt; - code.google.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;org.apache.lucene.analysis.ja パッケージに日本語処理のソースあり。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;JapanesePartOfSleechKeepFilter ・・設定値の文字のみ残す&lt;/li&gt;
&lt;li&gt;JapaniseBasicFormFilter ・・基本形に変換 例）悲しき＝＞悲しい と変換&lt;/li&gt;
&lt;li&gt;JapaniseKatakanaStemFilter 「ー」変換&lt;/li&gt;
&lt;li&gt;JapaneseBasicFormFilter 悲しき→悲しいなど基本形に変換して揃えるフィルタ&lt;/li&gt;
&lt;li&gt;JapaniseWidthFilter ・・ 半角＜＝＞全角に変換するフィルタ&lt;/li&gt;
&lt;li&gt;JapanisePunctuationFilter ・・ 区切り文字・記号を除く&lt;/li&gt;
&lt;li&gt;JapanisePartOfSpeechStopFilter ・・記載ワード除く&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;lucene-gosen は合成ルールを適用できる。合成ルールは外部ファイルで定義しておく。(compositePOS)&lt;/p&gt;
&lt;p&gt;Q&amp;amp;A:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Q)フィルタをかけると字が詰まるのですが？&lt;/li&gt;
&lt;li&gt;A)enablePotionIncrements=&amp;quot;false&amp;quot; を指定すると字が詰まりません&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;その他:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;転置インデクスを作る話。英語は空白区切りなので割と簡単に処理できる。日本語だと切り方が難しいので形態素解析を使う。ってことで Gosen へ。&lt;/li&gt;
&lt;li&gt;Lucene / Solr のデフォルトは N-グラム。辞書は不要だが、ノイズも多くなる。意味のある最小単位の文字列に区切るのが形態素解析。&lt;/li&gt;
&lt;li&gt;Kuromoji はソースごと Lucene に contribute されたらしい。 (&amp;quot;Kuromoji is a Japanese morphological analyzer.&amp;quot;)&lt;/li&gt;
&lt;li&gt;compositePOS の話。NAIST の辞書だと数字を一文字で登録。「100」が三つの文字になってしまう。&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://atilika.org/"&gt;Kuromoji&lt;/a&gt; - atilika.org&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="apachecon"&gt;
&lt;h2&gt;ApacheCon参加レポート&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="http://twitter.com/Ijokarumawak"&gt;&amp;#64;Ijokarumawak&lt;/a&gt; さん&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.slideshare.net/KojiKawamura/apache-con-2011report"&gt;ApacheCon NA 2011 Report&lt;/a&gt; - slideshare.net&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://na11.apachecon.com/"&gt;ApacheCon NA 2011&lt;/a&gt; - apachecon.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Solr に限らず、全般的な話。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Hadoop のコミュニティがとても大きくなってきた。&lt;/li&gt;
&lt;li&gt;IBM の Watson の紹介など。Watson は ASF のソフトウェアを活用している。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Solr の UI に関するライブラリの話。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Velocity を使った実装も同梱。&lt;/li&gt;
&lt;li&gt;JRuby -&amp;gt; TwigKit, Rails -&amp;gt; Blacklight, PHP -&amp;gt; VUFind&lt;/li&gt;
&lt;li&gt;JavaScript のライブラリもある。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Solr 4.0 に関すること。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;Automaton Query ・・あいまい検索が速くなる&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;性能測定には Wikipedia を使用。&lt;/li&gt;
&lt;li&gt;今）0.1-0.2QPS ＝＞ 50QPS になるらしい。&lt;/li&gt;
&lt;li&gt;あいまい検索 (FuzzyQuery) が100倍高速化。&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;lucene4からファイルに(フラッシュするところまでマルチスレッドでいけるらしい。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;ニュース&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://java.dzone.com/news/lucenes-fuzzyquery-100-times"&gt;Lucene's FuzzyQuery is 100 times faster in 4.0&lt;/a&gt; - java.dzone.com&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.infoq.com/jp/news/2011/12/lucene-3.5-and-solr-3.5"&gt;Lucene 3.5 と Solr 3.5 - 大幅な RAM 削減，SearchManager，ディープページングのサポート&lt;/a&gt; - infoq.com&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h2&gt;サフィックスアレイの話&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="http://twitter.com/nobu_k"&gt;&amp;#64;nobu_k&lt;/a&gt; さん&lt;/p&gt;
&lt;p&gt;Solr ではなく、検索一般のこと。
PFI で Sedue の開発をしている人なので、研究開発の側面が強い。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;一般論として、速度的には 転置インデクス &amp;gt; Suffix Array &amp;gt; n-gram らしい。&lt;/li&gt;
&lt;li&gt;Suffix Array の使いどころは遺伝子やバイナリデータの検索。HPC との組み合わせになりそう。&lt;/li&gt;
&lt;li&gt;ストップワードは二分探索なので、甚大なボトルネックにはならない。&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="p2p-orbis"&gt;
&lt;h2&gt;P2P分散検索エンジン ORBISについて&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="http://twitter.com/ceeflyer"&gt;&amp;#64;ceeflyer&lt;/a&gt; さん&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://code.google.com/p/orbis/"&gt;ORBIS&lt;/a&gt; - code.google.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;開発の動機:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;リアルタイム性の高い検索。&lt;/li&gt;
&lt;li&gt;サーバ増設を簡単に行いたい。&lt;/li&gt;
&lt;li&gt;スモールスタート / 分散型 =&amp;gt; P2P な自律分散ネットワーク&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;機能的なこと:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;1000台未満の小規模ネットワークでフルメッシュを構成する。&lt;/li&gt;
&lt;li&gt;P2P のノード間の通信には Message Pack を使っているらしい。&lt;/li&gt;
&lt;li&gt;結果はXMLで返し、どのノードで追加したかも分かる。&lt;/li&gt;
&lt;li&gt;インデクスはハッシュ値を元にして、一定数のレプリカを分散して保存する。&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;Fess や ORBIS のように Solr をベースにしたシステムも増えてきている印象です。
一方で、Lucene / Solr を中心とした話は lucene-gosen の発表だけ。
Solr はデフォルトでもそれなりに使えるという部分と、
MySQL などの RDBMS ほどにはユーザー数が増えにくいという部分がありそうです。&lt;/p&gt;
&lt;p&gt;形態素解析、Suffix Array、n-gram は文字列検索の基礎的なことですが、
改めてまとめてもらえると勉強になります。&lt;/p&gt;
&lt;p&gt;あと、そろそろ Solr4 (trunk) を使ってみないとなぁ、と思いました。&lt;/p&gt;
&lt;p&gt;前の勉強会の記録:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/09/solr-study-6.html"&gt;第６回 Solr 勉強会に行ってきた&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-1971011042998983946?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/1971011042998983946/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=1971011042998983946' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/1971011042998983946'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/1971011042998983946'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/12/solr-study-7.html' title='第７回 Solr 勉強会に行ってきた'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-1013145319432636659</id><published>2011-12-10T15:24:00.001+09:00</published><updated>2011-12-10T15:27:01.837+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Python の学習資料</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://python.org/images/python-logo.gif" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" height="71" width="211" src="http://python.org/images/python-logo.gif" /&gt;&lt;/a&gt;&lt;/div&gt;


&lt;p&gt;Python の学習資料を公開しました。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://skitazaki.github.com/python-school-ja/index.html"&gt;Python School 1.0.0 documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;対象は次のイメージです。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;何となく動くソフトウェアを書ける。&lt;/li&gt;
&lt;li&gt;自分の環境では動くけど、別のマシンで動かすときは苦労している。&lt;/li&gt;
&lt;li&gt;デグレードに悩まされて仕事から帰れない。&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="id1"&gt;
&lt;h1&gt;資料のアウトライン&lt;/h1&gt;
&lt;p&gt;全体的な内容としては次のものを予定しています。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;環境構築と基本的なスクリプト&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;Virtualenv + pip (Windows)&lt;/li&gt;
&lt;li&gt;Fizzbuzz&lt;/li&gt;
&lt;li&gt;コマンドラインスクリプトのテンプレート&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;CSV ファイルの読み込み&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;zip / dict 関数、クラス定義&lt;/li&gt;
&lt;li&gt;文字コードの扱い&lt;/li&gt;
&lt;li&gt;O/R マッパー - SQLAlchemy&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;コマンドライン操作&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;ファイルシステムとのやり取り&lt;/li&gt;
&lt;li&gt;設定ファイルの持ち方、環境変数&lt;/li&gt;
&lt;li&gt;Fabric によるリモートサーバ操作&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;テストの方法&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;unittest / doctest&lt;/li&gt;
&lt;li&gt;Nose による実行&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;Web アプリケーションの作成&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;Django チュートリアル&lt;/li&gt;
&lt;li&gt;URL のルール&lt;/li&gt;
&lt;li&gt;テンプレートエンジン&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;ドキュメントの構成方法&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;Sphinx と CI&lt;/li&gt;
&lt;li&gt;テーマの作成&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;プロジェクトの構成方法&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;パッケージング&lt;/li&gt;
&lt;li&gt;ビルドツールいろいろ&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;実際に書き終わっているのは CSV ファイルの読み込み部分までです (もう少し更新はあるだろうけど)。
Web アプリに関しては微妙なとこです。やっぱり書かない (or 書けない) かもしれません。
３月くらいまでには書き終えたいなぁ、と。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h1&gt;そもそもの動機&lt;/h1&gt;
&lt;p&gt;ソフトウェア系の会社で働いていると、
ちょっとしたスクリプトを書けば業務改善が図れることは多いと思います。&lt;/p&gt;
&lt;p&gt;標準的なスクリプティング方法が統一されている会社もあるでしょうし、
個人がまちまちに管理していることもあるでしょう。
個人的には、それなりの規模の会社で働く場合は、
周りの人と協力して作業できるように環境を整備しておくことが大事だと思っています。&lt;/p&gt;
&lt;p&gt;当たり前といえば当たり前のことですが、意外とそこは重視されにくいようで、
「XXX というプログラミング言語を使ったことはありますか？」と聞かれたことはあっても、
「XXX で NN 人が効率的に仕事をするためにどうするべきですか？」
といった類の話題は少ない気がします。&lt;/p&gt;
&lt;p&gt;がむしゃらにソフトウェアを書いてみても良いとは思いますが、
せっかく会社で仕事をするなら、協調できる方法を模索するのも悪くないと思います。
自分の手元で動くから完成、膨大な手順書があるから機械的に運用できる、
そうした幻想を抱くのではなく、どこでも気軽に動かせるソフトウェアが増えて欲しいな、と。&lt;/p&gt;
&lt;p&gt;そんなこんなをもう少し現実的な地点に落とし込むと、
基本的なコマンドラインスクリプトを書ける人が増えて欲しいなぁ、
ということで、冒頭の資料を作成することにしました。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;Python を使う&lt;/h1&gt;
&lt;p&gt;管理ツールなどの補助スクリプトとして Python を使う方法を学びます。
テキストファイルに対する処理、シェルスクリプトに代わるものを Python で記述することにより、 チーム開発の生産性を向上させます。&lt;/p&gt;
&lt;p&gt;なぜ Python か？という部分にはいくつかの理由がありますが、
なぞのコーディングルールを定めなくともそれっぽく記述がそろいますし、
記号を多用する必要がなく、多くの Linux にデフォルトでインストールされている、という点が挙げられます。
あと、Windows でも簡単に始められます。&lt;/p&gt;
&lt;p&gt;ともあれ、ひとつの言語でスクリプトを記述できるようになれば、それを他の言語に適用することは簡単になるはずです。
「この言語を使うんだ！」と明確な指針が定まっていない限り、とりあえず Python を勉強してから他のことをやっても、
さほど遠回りにはならないでしょう。
むしろ、あれやこれやと考える前に取り組める人の方が好ましかったりします。&lt;/p&gt;
&lt;p&gt;Python だと実行速度が不安... という話もあるみたいですが、
そもそも性能要求が厳しい部分で使うことは想定していません。
実行速度よりも実装速度が求められる部分で力を発揮すると思います。
乗り物で例えるなら、一方通行の狭い道を移動するときは大型車より自転車の方が速かったりします。
何事も適材適所ですね。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;公開した資料をベースに、社内で勉強会を開催しています。
ちょっとした糊付けプログラムはサラッと Python で実装できる人が増えてくれれば嬉しいなぁ、と思います。&lt;/p&gt;
&lt;p&gt;効率化のためにソフトウェアを開発しているわけですから、
効率的に仕事を進められるようになりたいですね。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;a class="reference external" href="http://sportsnavi.yahoo.co.jp/rugby/text/201111290004-spnavi_2.html"&gt;中竹竜二氏が語る「世界で勝つために」必要なこと （２／２）&lt;/a&gt; (スポーツナビ)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ユース世代がスコットランドに勝ちましたが、当然だと思っています。
ユース世代で世界で一番練習しているのは日本です。
毎日練習して週末も練習している。こんな国はほかにありません。
それでも世界で一番強くなれてないのは練習効率が悪いからです。
忙しいと言うなら練習を減らして準備して振り返って考える、考えさせる時間をつくってくださいと言っています。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-1013145319432636659?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/1013145319432636659/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=1013145319432636659' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/1013145319432636659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/1013145319432636659'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/12/python-school.html' title='Python の学習資料'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-7363670937159969501</id><published>2011-12-06T22:50:00.001+09:00</published><updated>2011-12-06T23:07:32.080+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Gears'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>HTML5 の File API を使ってみる</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-E-ZMLksXnug/Tt4hOtoT7tI/AAAAAAAAEcs/zV0_zA1QiUc/s1600/file-api-sample.jpg" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" height="241" width="400" src="http://2.bp.blogspot.com/-E-ZMLksXnug/Tt4hOtoT7tI/AAAAAAAAEcs/zV0_zA1QiUc/s400/file-api-sample.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;CSV を読み込んで JSON で出力できるようにします。
CSV の仕様は意外と難しいので、単純にカンマで区切られているテキストファイルだけを想定します。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://s.kitazaki.name/apps/html5demo/fileapi.html"&gt;File API Sample&lt;/a&gt; (デモ)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/skitazaki/sandbox/blob/master/src/javascript/simple-usage-fileapi.html"&gt;simple-usage-fileapi.html&lt;/a&gt; (ソース)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;File API の仕様などはこちら。
基本的にこれらのサンプルスクリプトをまとめたものが、上記のデモになります。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.w3.org/TR/FileAPI/"&gt;File API&lt;/a&gt; - w3.org&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.html5rocks.com/en/tutorials/file/dndfiles/"&gt;Reading local files in JavaScript&lt;/a&gt; - html5rocks&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://tmlife.net/programming/javascript/html5-file-api-file-read.html"&gt;HTML5 File API を使ってファイル読み込み&lt;/a&gt; - tmlife.net&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;なお、イベント管理には jQuery を使います。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="form"&gt;
&lt;h1&gt;form を作る&lt;/h1&gt;
&lt;p&gt;まずは &lt;tt class="docutils literal"&gt;&amp;lt;form&amp;gt;&lt;/tt&gt; 要素を作成します。
複数のファイルを選択できるよう、 &lt;tt class="docutils literal"&gt;multiple&lt;/tt&gt; を有効にします。&lt;/p&gt;
&lt;pre class="prettyprint lang-html literal-block"&gt;
        &amp;lt;form&amp;gt;
        Select CSV files: &amp;lt;input type=&amp;quot;file&amp;quot; id=&amp;quot;files&amp;quot; name=&amp;quot;files[]&amp;quot; multiple=&amp;quot;multiple&amp;quot; /&amp;gt;
        &amp;lt;/form&amp;gt;

&lt;/pre&gt;
&lt;p&gt;この要素に &lt;cite&gt;change&lt;/cite&gt; イベントを割り当てます。
コールバックに渡されるイベントオブジェクトの &lt;tt class="docutils literal"&gt;target&lt;/tt&gt; には &lt;tt class="docutils literal"&gt;files&lt;/tt&gt; があり、
これは FILE オブジェクトの配列になっています。
イベント自体と FILE の扱いは分離したいので、別に定義する関数に処理を投げます。&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block"&gt;
                $(selector).bind(&amp;quot;change&amp;quot;, function(e) {
                    var files = e.target.files;
                    handleFiles(files);
                });

&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h1&gt;ファイルを処理する&lt;/h1&gt;
&lt;p&gt;先ほどの &lt;tt class="docutils literal"&gt;handleFiles&lt;/tt&gt; は簡単にループを回すとして、個別のファイルは次のように処理してみます。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;メタ情報を表示する&lt;/li&gt;
&lt;li&gt;CSV ファイルの場合は読み込み処理を実行する&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;スクリプトにまとめると次のような感じ。
関数の戻り値が真の場合のみ読み込み処理を継続します。&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block"&gt;
        function parseFile(f) {
            var dt = [];
            dt.push({Name: f.name,
                     Type: f.type || 'n/a',
                     Size: f.size,
                     LastModified: f.lastModifiedDate ? f.lastModifiedDate.toLocaleDateString() : 'n/a'});
            $(&amp;quot;#file-list-template&amp;quot;).tmpl(dt).appendTo('#file-list');
            return f.type &amp;amp;&amp;amp; f.type.match(&amp;quot;text/csv&amp;quot;);
        }

&lt;/pre&gt;
&lt;p&gt;ファイルの読み込みは次のようになります。
コールバックを設定してから、読み込む文字列を与えます。
&lt;tt class="docutils literal"&gt;opts&lt;/tt&gt; という変数に適当なコールバックが設定されている場合には、
適切なタイミングでそのコールバックが呼ばれるでしょう。&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block"&gt;
        function readFile(readFile) {
            var reader = new FileReader();
            // Handle progress, success, and errors
            reader.onprogress = opts.progress || function(e) {};
            reader.onerror = opts.error || function(e) {};
            reader.onload = opts.load || function(e) {};
            reader.readAsText(readFile, &amp;quot;UTF-8&amp;quot;);
        }

&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;readAsText&lt;/tt&gt; で読み込んだ場合はイベントオブジェクトの &lt;tt class="docutils literal"&gt;target&lt;/tt&gt; を通じて、
普通の文字列を取得できます。
後は自由にその文字列を処理すれば良いだけです。&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block"&gt;
                var fileString = evt.target.result,

&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;ドラッグに対応する&lt;/h1&gt;
&lt;p&gt;ついでにドラッグ&amp;amp;ドロップにも対応させます。&lt;/p&gt;
&lt;p&gt;まずは適当な HTML 要素を準備します。&lt;/p&gt;
&lt;pre class="prettyprint lang-html literal-block"&gt;
        &amp;lt;div id=&amp;quot;drop-zone&amp;quot;&amp;gt;Drop CSV files here&amp;lt;/div&amp;gt;

&lt;/pre&gt;
&lt;p&gt;そこにイベントハンドラを割り当てますが、ここのイベント処理がちょっと曲者です。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;stopPropagation()&lt;/tt&gt; を呼んでブラウザにネイティヴの挙動をさせない。&lt;/li&gt;
&lt;li&gt;jQuery のイベントに未登録のものは &lt;tt class="docutils literal"&gt;originalEvent&lt;/tt&gt; を参照する必要がある。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;詳しくはこちらのスライドで説明されています。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://boazsender.com/understanding-jquery-events.html"&gt;Understanding jQuery Events &amp;amp; working with new HTML5 APIs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;スクリプトにまとめると次のような感じ。
&lt;tt class="docutils literal"&gt;originalEvent&lt;/tt&gt; を介さないと、 &lt;tt class="docutils literal"&gt;dataTransfer&lt;/tt&gt; が見つからない、という理由でエラーになります。
(jQuery のバージョンによって異なるので、新しいバージョンだけを使う場合は気にしなくて良いかも)&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block"&gt;
                    .bind(&amp;quot;drop&amp;quot;, function(e) {
                        e.stopPropagation();
                        e.preventDefault();
                        var files = e.originalEvent.dataTransfer.files;
                        handleFiles(files);
                    });

&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;HTML5 の File API を使って、CSV ファイルの中身を JSON で出力してみました。
CSV と言っても非常に簡易なものしか扱えませんが、取っ掛かりとしては十分かな、と思います。&lt;/p&gt;
&lt;p&gt;File API はテキストデータだけでなくバイナリデータも扱えますので、
様々なリーダーを試してみるとおもしろそうです。&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-7363670937159969501?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/7363670937159969501/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=7363670937159969501' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/7363670937159969501'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/7363670937159969501'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/12/html5-file-api.html' title='HTML5 の File API を使ってみる'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-E-ZMLksXnug/Tt4hOtoT7tI/AAAAAAAAEcs/zV0_zA1QiUc/s72-c/file-api-sample.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-7565889290886810630</id><published>2011-11-26T00:46:00.001+09:00</published><updated>2012-02-18T11:31:17.958+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Geo'/><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>KML ファイルを作成する</title><content type='html'>&lt;p&gt;ちょっと、CSV のデータから KML ファイルを作成してみます。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://code.google.com/intl/ja/apis/kml/documentation/kml_tut.html"&gt;KML チュートリアル&lt;/a&gt; - code.google.com&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kml-samples.googlecode.com/svn/trunk/interactive/index.html"&gt;KML Interactive Sampler&lt;/a&gt; - kml-samples.googlecode.com&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-mDexPiRtKKs/Ts-4na_UYPI/AAAAAAAAEZc/Mnrhkc3NvHU/s1600/kml-popup.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="226" width="400" src="http://3.bp.blogspot.com/-mDexPiRtKKs/Ts-4na_UYPI/AAAAAAAAEZc/Mnrhkc3NvHU/s400/kml-popup.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;


&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="csv-kml"&gt;
&lt;h1&gt;CSV ファイルから KML に変換するスクリプト&lt;/h1&gt;
&lt;p&gt;Python でスクリプトを書いておきます。&lt;/p&gt;
&lt;div class="section" id="id2"&gt;
&lt;h2&gt;KML ファイルのテンプレートを用意する&lt;/h2&gt;
&lt;p&gt;Jinja2 を使ったテンプレートだと次のように記述できます。
名前と緯度経度が必須で、説明文がある場合はそれも出力します。&lt;/p&gt;
&lt;pre class="prettyprint lang-py literal-block"&gt;
TEMPLATE = u&amp;quot;&amp;quot;&amp;quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;kml xmlns=&amp;quot;http://www.opengis.net/kml/2.2&amp;quot;&amp;gt;
&lt;Document&gt;
{% for point in points %}
  &amp;lt;Placemark&amp;gt;
    &amp;lt;name&amp;gt;{{ point.name }}&amp;lt;/name&amp;gt;
    {% if point.description %}
    &amp;lt;description&amp;gt;{{ point.description }}&amp;lt;/description&amp;gt;
    {% endif %}
    &amp;lt;Point&amp;gt;
      &amp;lt;coordinates&amp;gt;{{ point.longitude }},{{ point.latitude }}&amp;lt;/coordinates&amp;gt;
    &amp;lt;/Point&amp;gt;
  &amp;lt;/Placemark&amp;gt;
{% endfor %}
&lt;/Document&gt;
&amp;lt;/kml&amp;gt;&amp;quot;&amp;quot;&amp;quot;


&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="csv"&gt;
&lt;h2&gt;CSV ファイルを読み込む&lt;/h2&gt;
&lt;p&gt;次のフォーマットの CSV ファイルについて考えます。
１行目はヘッダー行で固定とし、２行目以降に同じ並びでデータが続きます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
name,longitude,latitude,description
国立霞ヶ丘競技場,139.714941,35.678160,naash.go.jp

... 同じ形式でデータが続く ...
&lt;/pre&gt;
&lt;p&gt;簡単のために、区切り文字以外にカンマは存在しない、と仮定しておくと、
次のようなコードで処理できます。&lt;/p&gt;
&lt;pre class="prettyprint lang-py literal-block"&gt;
    def process(self, reader):
        header = reader.next().strip().split(',')
        points = []
        for line in reader:
            r = line.strip()
            if not r:
                continue
            row = r.split(',')
            data = dict(zip(header, row))
            points.append(data)
        self.rederer.render(points)

&lt;/pre&gt;
&lt;p&gt;エクセルの CSV と互換性がないとか、ダブルクォートの処理がどうのという話もありますが、
CSV ファイルを真面目に扱うと奥が深いのでやめておきます。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h2&gt;ファイルにまとめる&lt;/h2&gt;
&lt;p&gt;引数処理や入出力のエンコーディング処理を追加して、ファイルにまとめておきます。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/skitazaki/sandbox/blob/master/src/python/csv2kml.py"&gt;csv2kml.py&lt;/a&gt; - github.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;入力ファイル&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cat sample.csv
name,longitude,latitude,description
国立霞ヶ丘競技場,139.714941,35.678160,naash.go.jp
&lt;/pre&gt;
&lt;p&gt;実行結果&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ python csv2kml.py sample.csv
INFO:root:Start processing: sample.csv
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;kml xmlns=&amp;quot;http://www.opengis.net/kml/2.2&amp;quot;&amp;gt;

  &amp;lt;Placemark&amp;gt;
    &amp;lt;name&amp;gt;国立霞ヶ丘競技場&amp;lt;/name&amp;gt;

    &amp;lt;description&amp;gt;naash.go.jp&amp;lt;/description&amp;gt;

    &amp;lt;Point&amp;gt;
      &amp;lt;coordinates&amp;gt;139.714941,35.678160&amp;lt;/coordinates&amp;gt;
    &amp;lt;/Point&amp;gt;
  &amp;lt;/Placemark&amp;gt;

&amp;lt;/kml&amp;gt;
INFO:root:End processing: sample.csv
&lt;/pre&gt;
&lt;p&gt;ヘルプ表示&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ python csv2kml.py -h
Usage: python csv2kml.py [options] file1 [file2 [ ... ]]

Convert CSV file into KML format.
See KML Tutorial
&amp;lt;http://code.google.com/intl/ja/apis/kml/documentation/kml_tut.html&amp;gt;

Input file must contain following header line:

    name,longitude,latitude,description


Options:
  -h, --help            show this help message and exit
  -f FILE, --file=FILE  setting file
  -o FILE, --out=FILE   output file
  --basedir=BASEDIR     base directory
  --input-encoding=ENC_IN
                        encoding of input source
  --output-encoding=ENC_OUT
                        encoding of output destination
  -v, --verbose         verbose mode
  -q, --quiet           quiet mode
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="google-maps"&gt;
&lt;h1&gt;Google Maps で読み込む&lt;/h1&gt;
&lt;p&gt;Google Maps には、ローカルファイルシステムから KML をアップロードする方法と、
任意の URL のファイルを読み込む方法が用意されています。
Dropbox のパブリックフォルダなどに KML を置くことで、URL から読み取れるようになります。&lt;/p&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-Pnyai3TdjZs/Ts-4gK-o22I/AAAAAAAAEZQ/S_mlUxGRmvI/s1600/google-maps-kml-import.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="275" width="400" src="http://2.bp.blogspot.com/-Pnyai3TdjZs/Ts-4gK-o22I/AAAAAAAAEZQ/S_mlUxGRmvI/s400/google-maps-kml-import.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;


&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;CSV のデータから KML ファイルを作成しました。
Google Maps と Google Earth は KML を読み取って地点情報などを表示できます。
何となく地球の地点情報を火星にマッピングしてみると楽しいかもしれません。
まぁ、誰得な話でもでもありませんが。。&lt;/p&gt;
&lt;p&gt;KML には Google の拡張もあり、Google Earth ではツアー機能もありますので、
気が向いたら使ってみようかなぁ、と思いました。&lt;/p&gt;
&lt;p&gt;あと、Google Earth で緯度経度表示の単位を変更するには、
設定画面から選択できるようです。
度分秒からの表示を変更したい場合に便利です。&lt;/p&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-Ue15utDBobg/Ts-4YPEEAII/AAAAAAAAEZE/v5oUdZQPWZU/s1600/google-earth-settings.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="233" width="400" src="http://2.bp.blogspot.com/-Ue15utDBobg/Ts-4YPEEAII/AAAAAAAAEZE/v5oUdZQPWZU/s400/google-earth-settings.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;div&gt;
追記：KML で複数の地点を含めるために Document 要素を追加。
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-7565889290886810630?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/7565889290886810630/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=7565889290886810630' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/7565889290886810630'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/7565889290886810630'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/11/create-kml-in-hand.html' title='KML ファイルを作成する'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-mDexPiRtKKs/Ts-4na_UYPI/AAAAAAAAEZc/Mnrhkc3NvHU/s72-c/kml-popup.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-3054015181621950081</id><published>2011-11-20T16:18:00.001+09:00</published><updated>2011-11-20T16:22:51.407+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='生活'/><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>さよなら Google Buzz</title><content type='html'>&lt;p&gt;Google Buzz に終了宣言が出されましたので、データをエクスポートしておきます。
API 設計がキレイだなぁとは思っていましたが、サービス自体の立ち位置が定まらなかった点が大きかったのでしょうか。
メールシステムとの統合は根深い問題もありそうです。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://googleblog.blogspot.com/2011/10/fall-sweep.html"&gt;A fall sweep&lt;/a&gt; - googleblog.blogspot.com&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://ja.wikipedia.org/wiki/Google_Buzz"&gt;Google Buzz&lt;/a&gt; - wikipedia.org&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-PLPa1tnL3Ss/TsiqL43bN-I/AAAAAAAAEXI/-oRbj_TyWyg/s1600/google-buzz-the-end.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="120" width="400" src="http://1.bp.blogspot.com/-PLPa1tnL3Ss/TsiqL43bN-I/AAAAAAAAEXI/-oRbj_TyWyg/s400/google-buzz-the-end.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="id2"&gt;
&lt;h1&gt;データのエクスポート&lt;/h1&gt;
&lt;p&gt;&lt;a class="reference external" href="https://www.google.com/takeout/?pli=1"&gt;Google Takeout&lt;/a&gt; (データエクスポート) を使ってデータをエクスポートします。
サービスを選択してダウンロードできます。
データ量によっては時間がかかるかもしれません。&lt;/p&gt;
&lt;p&gt;Buzz のデータをエクスポートしてみるとこんな感じになります。&lt;/p&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-JTJLovzchI4/TsiqR3ScGBI/AAAAAAAAEXU/gRSMh2E-Im8/s1600/google-buzz-takeout.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="342" width="400" src="http://2.bp.blogspot.com/-JTJLovzchI4/TsiqR3ScGBI/AAAAAAAAEXU/gRSMh2E-Im8/s400/google-buzz-takeout.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;ファイル名の変換&lt;/h1&gt;
&lt;p&gt;Takeout では日本語のファイル名がパーセントエンコードされていて個人的に好きでありませんので、
もう少し機械的な文字列として日付日時に変換します。
日付はファイルの変更日時にしますが、同じ時間の場合には連番となる数字を付与して重複を防ぐことにします。
複数人のデータだと重複管理にはもっと気を遣った方が良いでしょうが、
一人分のデータで時間が重なることは少ないでしょうから、
それなりに妥当なとこかなぁと思います。&lt;/p&gt;
&lt;p&gt;Python のスニペット:&lt;/p&gt;
&lt;pre class="prettyprint lang-py literal-block"&gt;
def determine_new_file_name(timestamp, suffix):
    mtime = datetime.fromtimestamp(timestamp)
    base = mtime.strftime('%Y-%m-%d-%H-%M-%S')
    c = 0
    while True:
        if c:
            cand = &amp;quot;%s.%d%s&amp;quot; % (base, c, suffix)
        else:
            cand = base + suffix
        if not os.path.exists(cand):
            return cand
        c += 1


def fnameconv(basedir, outputdir=None):
    outputdir = outputdir or basedir
    if not os.path.exists(outputdir):
        raise SystemExit(&amp;quot;\&amp;quot;%s\&amp;quot; is not found.&amp;quot; % (outputdir,))
    for f in os.listdir(basedir):
        # XXX: ignore list should be optional argument
        if f == __file__:
            continue
        fname = os.path.join(basedir, f)
        _, suffix = os.path.splitext(fname)
        cand = determine_new_file_name(os.stat(fname).st_mtime, suffix)
        dst = os.path.join(outputdir, cand)
        shutil.move(fname, dst)


&lt;/pre&gt;
&lt;p&gt;あとは &lt;tt class="docutils literal"&gt;main()&lt;/tt&gt; 関数で引数をそれっぽく解析すれば良いと思います。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h1&gt;スライドショー風に表示&lt;/h1&gt;
&lt;p&gt;まずはファイル一覧をリスト (JSON のリスト形式) にして &lt;tt class="docutils literal"&gt;files.json&lt;/tt&gt; という名前で保存します。&lt;/p&gt;
&lt;p&gt;次に HTML ファイルを作成して &lt;tt class="docutils literal"&gt;files.json&lt;/tt&gt; を読み込めるようにし、
適当なタイマー設定でランダムにファイルの中身を読み込みます。
(jQuery の &lt;tt class="docutils literal"&gt;load()&lt;/tt&gt; を使うとお手軽。HTML が静的なものであると想定)&lt;/p&gt;
&lt;p&gt;たまには自分で選択したいこともあるでしょうから、ランダムに６つのファイル名をタブ表示させておきます。
タブ表示のデザインは &lt;a class="reference external" href="http://twitter.github.com/bootstrap/"&gt;Twitter Bootstrap&lt;/a&gt; を使うととても簡単に実現できますね。
HTML を組み立てる部分は &lt;a class="reference external" href="http://api.jquery.com/category/plugins/templates/"&gt;jQuery Templates&lt;/a&gt; にお任せです。&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block"&gt;
    $(function() {
      $.getJSON(&amp;quot;files.json&amp;quot;, function(data) {
        var slides = [];
        $(data).each(function() {
          // XXX: parse date and time.
          var t = this.substring(0, 19).split(&amp;quot;-&amp;quot;);
          slides.push({&amp;quot;file&amp;quot;: this.toString(),
                       &amp;quot;name&amp;quot;: t[0] + &amp;quot;/&amp;quot; + t[1] + &amp;quot;/&amp;quot; + t[2] + &amp;quot; &amp;quot; + t[3] + &amp;quot;:&amp;quot; + t[4],
                       &amp;quot;date&amp;quot;: this.substring(0, 10)});
        });
        function pickup() {
          var len = slides.length;
          return slides[Math.floor(Math.random() * len)];
        }
        $(&amp;quot;#screen&amp;quot;).load(pickup()[&amp;quot;file&amp;quot;]);
        setInterval(function() {
          $(&amp;quot;#screen&amp;quot;).load(pickup()[&amp;quot;file&amp;quot;]);
        }, 6000);
        function update() {
          var dt = [];
          for (var j = 0; j &amp;lt; 6; j++) {
              dt.push(pickup());
          }
          $(&amp;quot;#slide-list&amp;quot;).empty();
          $(&amp;quot;#slide-list-template&amp;quot;).tmpl(dt).appendTo(&amp;quot;#slide-list&amp;quot;);
        }
        update();
        setInterval(function() {
          update();
        }, 20000);
      });
      $(&amp;quot;#slide-list a&amp;quot;).live(&amp;quot;click&amp;quot;, function(e) {
        e.preventDefault();
        $(&amp;quot;#screen&amp;quot;).load($(this).attr(&amp;quot;href&amp;quot;));
        // XXX: freshen auto update timer.
      });
    });

&lt;/pre&gt;
&lt;p&gt;NOTE:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;jQuery Templates は &lt;a class="reference external" href="https://github.com/BorisMoore/jsviews"&gt;JsViews&lt;/a&gt; に置き換えられる予定 (?) なので、
もう少しちゃんと作る場合はテンプレートライブラリを差し替えるのがベター。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.borismoore.com/2011/10/jquery-templates-and-jsviews-roadmap.html"&gt;jQuery Templates and JsViews: The Roadmap&lt;/a&gt; - borismoore.com&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;出来上がったものを Web サーバのディレクトリに置けば表示されるようになります。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://s.kitazaki.name/apps/buzz-slide/"&gt;Buzz Slide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;Google Buzz のデータをエクスポートして自前のサーバー環境でスライドショー風に表示しました。
有料か無料かを問わず Web サービスは継続されない可能性がありますが、エクスポートできる仕組みを提供してくれているかどうかは大きな違いだと思います。
画面デザインが刷新されて好き嫌いもあるでしょうが、Google はその辺をうまくやってるなぁ、と思いました。&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-3054015181621950081?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/3054015181621950081/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=3054015181621950081' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/3054015181621950081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/3054015181621950081'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/11/goodbye-google-buzz.html' title='さよなら Google Buzz'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-PLPa1tnL3Ss/TsiqL43bN-I/AAAAAAAAEXI/-oRbj_TyWyg/s72-c/google-buzz-the-end.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-2413387575596807258</id><published>2011-11-15T20:50:00.001+09:00</published><updated>2011-11-15T20:53:38.906+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='翻訳'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>OData のための効率的なフォーマット</title><content type='html'>&lt;p&gt;OData のブログに気になるエントリがありましたので、
ちょっと日本語に訳しておきます。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.odata.org/blog/2011/3/25/an-efficient-format-for-odata"&gt;An efficient format for OData&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;ul class="simple"&gt;
&lt;li&gt;&amp;quot;dense&amp;quot; にしっくりくる日本語を思いつかなかったので、そこはそのまま英語表記。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="section" id="id1"&gt;
&lt;h1&gt;日本語訳&lt;/h1&gt;
&lt;p&gt;そろそろ OData におけるもっと効率的なフォーマットが必要になってきており、
このスレッド (&lt;a class="reference external" href="http://mailinglist.odata.org/scripts/wa-ODATA.exe?A2=ODATA;b331dadb.1103"&gt;Why XML&lt;/a&gt;) で直近はやり取りされている。
このトピックについてもっと突っ込んで調査し、問題を文章として表現することで、
考えられる可能性への足場づくりにしたいと考えた。&lt;/p&gt;
&lt;p&gt;OData 用の新しいフォーマットの導入を議論すると、非常に多くのことを考えさせられる。
過去にもこのフォーラムで議論してきたように、閉じたシステムに特化したフォーマットは良かった。
しかし、たくさんのエコシステムにサポートを望むフォーマットについて話すときは別だ。
エコシステムを分断化 (fragment) しないことを保証する必要があり、特定のクライアントや
サーバーを蚊帳の外に追い出してはならない。&lt;/p&gt;
&lt;p&gt;OData は今や膨大なサーバファームでも携帯電話でも使われている。
前者はデータシリアライズにおける CPU サイクルに厳しく、
後者はデータサイズや CPU 効率化、それからバッテリー消費を注意深く管理する必要がある。
よって、どこそこの部分に注力する、と言うのがフェアだろう。&lt;/p&gt;
&lt;div class="section" id="id2"&gt;
&lt;h2&gt;解決すべき問題とは？&lt;/h2&gt;
&lt;p&gt;フォーマットとパフォーマンスについて議論すると、お決まりの質問がやってくる。
「サイズとスピードのどちらを最適化するの？」
おもしろいことに、本当に多くの場合に、サーバ側はスループットを最適化したがり、
そうしたサーバとやり取りするクライアントはバッテリーの寿命を最大化することなら何でも最適化したがる。
そして誰もがサイズのために帯域幅を最適化する。&lt;/p&gt;
&lt;p&gt;ここから分かるのは、バランスのとれた選択肢を模索しなくてはならない、という点であり、
相互運用を認めながら、さらなる改善の機会は常に開かれている。
このもとに、OData のための「効率的」なフォーマットを作成するというゴールを緩く定義し、
更なる効率さが更なるコンパクトさや生成の早さを意味するかどうかを問題定義に埋め込まないようにする。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h2&gt;何を変更できる？&lt;/h2&gt;
&lt;p&gt;シリアライゼーションの準備ができていれば、データの獲得とそれを運搬するプロセスを一定だと考えると、
シリアライゼーションのコストは CPU 時間に支配される傾向にある。
文字列でないデータを文字列に変換する (テキストベースのフォーマットを使う場合)
すべての文字列を正しい文字エンコーディングにエンコードし、すべてのレスポンスを一緒に縫い合わせる。
サイズだけに注目するなら出力を圧縮するだろうが、それでは CPU を二倍も使ってしまう。
一度目は最初のドキュメントを生成するときで、二度目はそれを圧縮するときだ。&lt;/p&gt;
&lt;p&gt;そこで、始めるときから記述量を減らし、何を書き出すかを決めるのに大量の時間を費やさないようにしよう。
このことは比較的明らかな候補を見つけられるし、余分なものを排除することにつながる。&lt;/p&gt;
&lt;p&gt;その一方で、変えたくないこともたくさんある。
帯域外の知識なしに通信できるようになるので、OData のリクエストとレスポンスを自己内法的にすることは大事である。
OData はサーバがなんでもエンコードできるように URL を非常によく使う。
たとえば、エンティティの分散や異なるホストにまたがった関係性、継続的なエンコーディング、
CDN におけるメディアの場所といったものが挙げられる。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h2&gt;読み書きすべきこと、すべきでないこと&lt;/h2&gt;
&lt;p&gt;OData のペイロードを見てみると、すぐに冗長な部分を勘ぐるだろう。
しかし何回か試行するために、多くのデータを持たせるようにしておく
(正確な科学的調査ではなく、大雑把なものだと考えてほしい)。
参考として Northwind データベースを OData サービスとして見せるサンプルサービスから、３つの場合を扱った。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;1 Customer: &lt;a class="reference external" href="http://services.odata.org/Northwind/Northwind.svc/Customers?$top=1"&gt;http://services.odata.org/Northwind/Northwind.svc/Customers?$top=1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;100 CustomersAndOrders: &lt;a class="reference external" href="http://services.odata.org/Northwind/Northwind.svc/Customers?$top=100&amp;amp;$expand=Orders"&gt;http://services.odata.org/Northwind/Northwind.svc/Customers?$top=100&amp;amp;$expand=Orders&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;100 NarrowCustomers: &lt;a class="reference external" href="http://services.odata.org/Northwind/Northwind.svc/Customers?$top=100&amp;amp;$select=CustomerID,CompanyName"&gt;http://services.odata.org/Northwind/Northwind.svc/Customers?$top=100&amp;amp;$select=CustomerID,CompanyName&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これらは、本当に小さなデータセット、やや大きく広範なデータセット、それから大きいが狭い範囲のデータセットである。&lt;/p&gt;
&lt;p&gt;Atom と JSON のサイズを比較すると、JSON は Atom の半分から３分の１になる。
このことの大部分は、JSON の方が冗長もしくは不要なコンテント (閉じタグ、空の必須要素、など) が少ないからだ。
値の型アノテーションの欠如のような、このうちのいくつかは実際に忠実さを損なうけれでも。&lt;/p&gt;
&lt;p&gt;JSON のペイロードをもう少し見ていくと、メタデータとプロパティ名がコンテンツの40%近くになっていて、
システムが生成した URL も40%弱ある。
純粋なデータはコンテンツの20%前後でしかない。
データを視覚的に見たい人も多いだろうから図にしよう。&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://www.odata.org/media/16685/efficientformatpayloadbreakdown_496x280.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="280" width="496" src="http://www.odata.org/media/16685/efficientformatpayloadbreakdown_496x280.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;これについてはかなりの変動性がある。
URLが20-25%近くになるフィードや、メタデータとプロパティ名が65%にもなるようなものも見てきた。
どちらにせよ、これらの両方に言及する確固たる言い分がある。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h2&gt;アプローチ&lt;/h2&gt;
&lt;p&gt;実際の接続フォーマットと、冗長さを減らして記述量を少なくする (&amp;quot;write less&amp;quot;) 戦略を分離しておこうと思う。
まずは後者に着目していこう。&lt;/p&gt;
&lt;p&gt;上述のデータから、構造 (プロパティ名、エントリのメタデータ) と URL の両方をエンコーディングするのが大変な作業なのは明らかだ。
シンプルな戦略は二つの構造をドキュメントに導入することだろう。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;構造化テンプレート (&amp;quot;structural templates&amp;quot;): 含まれるものの構成を記述する。
レコードや入れ子になったレコード、それからメタデータのレコードなどである。
テンプレートは一度記述されれば良く、実際のデータをそれらを参照するだけとなるので、
行レコードにおけるプロパティ名の繰り返しを回避できる。&lt;/li&gt;
&lt;li&gt;テキストテンプレート (&amp;quot;textual templates&amp;quot;): ドキュメント全体を通して何度も繰り返すテキストパターンを記録しておく。
URL などは真っ先に思いつく好例といえる。
(例えば、このようなテンプレートを想像できるだろう
&amp;quot;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;http://services.odata.org/Northwind/Northwind.svc/Customers('{0}')&lt;/span&gt;&lt;/tt&gt;&amp;quot;。
それぞれの行の値は &amp;quot;{0}&amp;quot; を置換するだけでよい。)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;必要とされるときにデータと一緒にインライン化できるので、
本当に必要とされるテンプレートだけが特定のドキュメントに入ることになる。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id6"&gt;
&lt;h2&gt;実際にやり取りするフォーマット&lt;/h2&gt;
&lt;p&gt;接続フォーマットを実際に選択するときはたくさんの観点から検討する。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;テキストかバイナリか？&lt;/li&gt;
&lt;li&gt;どのようなクライアントが処理できるようにすべきか？&lt;/li&gt;
&lt;li&gt;低レベルの転送フォーマットを選び、テンプレートスキームに適用すべきか、
もしくは、冗長性を取り除くメカニズムを持っている既存のフォーマットを使うべきか？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;私が検討したいくつかのことを挙げよう。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;em&gt;EXI&lt;/em&gt;: W3C が推奨するコンパクトなバイナリ XML フォーマットだ。
これの良い点は、単なる XML であり、Atom のシリアライザーを使えることだ。
圧縮効率も満足のいくレベルである。
それでも、すべてのことを高レベルのレイヤーで実現した方が良いのではないかと心配になる
(CPU 使用率に関してきっちり調べていない) し、すべてのクライアントがダイレクトに使用できる
わけでもない。実装するのも一仕事だ。&lt;/li&gt;
&lt;li&gt;&lt;em&gt;「低レベル」のバイナリフォーマット&lt;/em&gt;: BSON、Avro、それから Protocol Buffers について
調べてみた。様々な OData のイディオムを受け渡す部分の上にフォーマットを定義する必要があるため、
「低レベル」と呼ぶことにする。多くの場合に冗長性を減らしたいなら、これを取り扱わなければならないだろう。
(公平を期すなら Avro は構造の面でも自己言及の側面を既に扱っているが)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;JSON&lt;/em&gt;: いつだったか WCF チームの人も言及していたように、これは直感的な考えだ。
構造的でテキストのテンプレートを使って &amp;quot;dense JSON&amp;quot; エンコーディングを定義できる。
ドキュメントは一貫して JSON ドキュメントであり、どのような環境でも通常の JSON パーサーを使って処理できる。
よくできたパーサーなら dense フォーマットから最終的な出力までをダイレクトに生成できるだろうし、
普通のパーサーであってもシンプルな JSON から JSON への変換を適用できる。
これは実際のシナリオで期待する類で、プロパティ名が繰り返し出現するオブジェクトとして JSON を返す。
このアプローチはサイズに対してはそこまで最適化された結果ではない。
しかし、ほどほどな効率性を持っており、極めて優れた相互接続性を持つ。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;バイナリフォーマットと JSON については、圧縮することを脇に置いておいたことに注意してほしい。
OData は HTTP 上に構築されるので、クライアントとサーバはコンテンツのエンコーディングを介していつでも圧縮について協議できる。
これにより、サーバはスループットとサイズに関して選択できるし、クライアントはサイズと CPU 使用率でどちらの最適化が好ましいかを提案できる。
(ポータブル機器の場合はバッテリーの寿命に反映されるかもしれない)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="odata-dense-json"&gt;
&lt;h2&gt;OData 用の dense JSON エンコーディング&lt;/h2&gt;
&lt;p&gt;これらの中では、私は JSON に興味を持っている。
テンプレートに詰め込むのがとても暗号的になるかもしれないが、フォーマットをテキストにしておく考え方が好きだ。
その他すべてのクライアントに加えて、ブラウザーの中で動作するという事実も本当に好ましい。&lt;/p&gt;
&lt;p&gt;ここまでで十分に長文になってしまった。
これが興味深い方向性だと考える人たちがいれば、JSON エンコーディングの実際の定義は他の議論に移したい。
ということで、その動機付けのために一例を示させて欲しい。&lt;/p&gt;
&lt;p&gt;上述の Netflix の例では「タイトル (Title)」型の行データがたくさんある。
典型的には、個別の行データに対して完全な JSON オブジェクトを使うだろう。
すべてが array 型でまとめられ、__metadata オブジェクトを伴ってそれぞれが「自分へのリンク (self links)」などを持っている。
dense バージョンでは、 &amp;quot;control&amp;quot; と &amp;quot;metadata&amp;quot; それから &amp;quot;data&amp;quot; に対して、それぞれ &amp;quot;c&amp;quot; や &amp;quot;m&amp;quot; あるいは &amp;quot;d&amp;quot; オブジェクトなどを持つ。
それぞれのオブジェクトはトップレベルの array 型でオブジェクトを表現し、
その値はテンプレートが定義される順番に一致しており、
新しいテンプレートを導入するメタデータオブジェクトか、テンプレートのある部分の特定の値を表現するデータ値のどちらか。
制御オブジェクトはたいてい最初か最後にあり、件数や array または singleton などを示す。
次のような感じである。&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://www.odata.org/media/16690/efficentformatsample.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="302" width="931" src="http://www.odata.org/media/16690/efficentformatsample.png" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;(そこまで正確さを意識しておらず、単なる手描きの図だと考えて欲しい)&lt;/p&gt;
&lt;p&gt;ふたつの構造化されたテンプレート (JSON スキーマっぽいもの) とテキストテンプレートに注意して欲しい。
単一行データにとってはいささか大きくなってしまうが、大きすぎるほどでもないと思う。
行データが増大するにつれて、圧縮密度が高いオブジェクトになっていくだろう。
属性名がなく、解凍するときに順番が固定されている。
このようなフォーマットだと、&amp;quot;100NarrowCustomers&amp;quot; の例では元の JSON に対して３分の１くらいのサイズになる。
クライアントとサーバーをつなぐデータとして小さいだけでなく、テキストの３分の１はまったく処理する必要がないのである。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id7"&gt;
&lt;h2&gt;次のステップ？&lt;/h2&gt;
&lt;p&gt;複数のフォーマットについてもっと良く評価する必要がある。
個人的には dense JSON フォーマットの考え方が良いと思うが、トレードオフの作業として検証が必要になる。
もう少しよく考えてみてから、また連絡するよ。
dense JSON でもう一段階踏み込んだことを挑戦してみて、どんな感じになるかを見ていこうと思う。&lt;/p&gt;
&lt;p&gt;ここまで読んでくれたなら、新しいフォーマットを作ることに本当に興味があるに違いない。
フィードバックを歓迎する。&lt;/p&gt;
&lt;p&gt;ありがとう。
-pablo&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id8"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;&amp;quot;An efficient format for OData&amp;quot; というエントリを日本語にしました。
OData 自体がどうなっていくかは未知数ですが、
データ構造の設計についてまとまった記事は少ないと思いますので、
クライアント/サーバ間の通信に関して議論する取っ掛かりにはなるでしょう。&lt;/p&gt;
&lt;p&gt;JSON のキー名を個別のデータに含めない、という考え方は JavaScript の本 (&lt;a class="reference external" href="http://www.amazon.co.jp/dp/059680279X"&gt;High Perfomance JavaScript&lt;/a&gt;) でも述べられていますので、
知っているに超したことはないのかな、と。&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-2413387575596807258?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/2413387575596807258/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=2413387575596807258' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/2413387575596807258'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/2413387575596807258'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/11/efficient-format-for-odata.html' title='OData のための効率的なフォーマット'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-9117667791447307052</id><published>2011-10-29T00:34:00.004+09:00</published><updated>2011-10-29T00:36:56.982+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nodejs'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>Nodefest.jp warm-up event に行ってきた</title><content type='html'>&lt;p&gt;Node に関するイベントに行ってきました。
翌日の「東京 Node 学園祭 2011」の前夜祭みたいなものです。
本編には出られませんが、雰囲気だけでも感じておこうかな、と。まぁ、飲み会みたいな感じだったという。。。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://atnd.org/events/20970"&gt;Nodefest.jp warm-up event&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://nodefest.jp/2011/"&gt;東京 Node 学園祭 2011&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Q&amp;amp;A は QLive というサイトでホストされました。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://qlive.co/events/120"&gt;QLive Nodefest.jp warm-up event&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="id2"&gt;
&lt;h1&gt;トーク&lt;/h1&gt;
&lt;p&gt;スピーカーは３人。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://qlive.co/"&gt;QLive&lt;/a&gt; のこと&lt;/li&gt;
&lt;li&gt;Cookpad でアイコンのテストスクリプトを作ったこと&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://ja.mygengo.com/"&gt;myGengo&lt;/a&gt; の中の人が Wii-js について&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;自分がメモしたこと:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;QLive のアーキテクチャの話。Node.js と Rails で構成されてる。&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;初期データは Rails から配信し、POST データもこちらで。&lt;/li&gt;
&lt;li&gt;投稿されたデータは Redis をキューにして Node + socket.io で配信。&lt;/li&gt;
&lt;li&gt;Node と Rails は分離されているのが嬉しいところ。&lt;/li&gt;
&lt;li&gt;Redis が SPOF (単一障害点) にならないか心配だが、daemontools がプロセスを再起動してくれる。&lt;/li&gt;
&lt;li&gt;Ubuntu 11.10 の node は 0.2.6 だから自分でコンパイルしているらしい。&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;クックパッドでアイコンの違いのテスト方法について。&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;アイデアからプロトタイプまで２時間くらい。&lt;/li&gt;
&lt;li&gt;Node, Express, EJS, CoffeeScript, SASS 辺りを使っているみたい。&lt;/li&gt;
&lt;li&gt;StackOverflow でたくさん聞けるから、何かあっても苦にならない。&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;Wii-js を作ったきっかけは、子供にプログラミングを教えることに適している、という理由もある。&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;Wii のブラウザは Opera 9.26 ベースだから古い。&lt;/li&gt;
&lt;li&gt;英語で話しているが、スライドは日本語で読みやすい。&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;残念に思ったこと:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;自分の英語力が足りない。&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;Redis と Rails を間違って聞いていることがあった。&lt;/li&gt;
&lt;li&gt;V8 を vi かと思った。&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="q-a"&gt;
&lt;h1&gt;Q&amp;amp;A&lt;/h1&gt;
&lt;p&gt;QLive の質問に Ryan と Guillermo が答えてくれる流れ。
メモしてないから、断片的に覚えていること。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;try/catch のサポートは、今のところ考えていない。&lt;/li&gt;
&lt;li&gt;スタックトレースが取りづらいけど、関数呼び出しの仕組みを考えると色々と難しい。&lt;/li&gt;
&lt;li&gt;V8 に影響を受ける部分もある。ヒープサイズとか。&lt;/li&gt;
&lt;li&gt;Microsoft からサポートで入ってきてくれた人がいて、とても助かる。&lt;/li&gt;
&lt;li&gt;コマンドラインもサポートしたいね。需要があれば。&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://boxcar.io/"&gt;BOXCAR&lt;/a&gt; は良いと思う。 (聞き間違いでなければ)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;クックパッドでの開催でしたが、きれいなオフィスで立派なキッチンでした。
料理もおいしく、本当にシェフの人がいるんだなぁ、と再認識。
ありがたい限りです。&lt;/p&gt;
&lt;p&gt;外国人が多いとニギヤカな感じがして、
シリコンバレーや TechCity (ロンドンの IT 系の人を誘致しているエリア) だと人の交流が盛ん、っていうのは納得。
知らない人ともすんなり話せるようにならないとなぁ、と思いました。
自分の偏見だと、日本人のソフトウェア系の人はこれが苦手な感じ、と自省。。。
言語なのか文化なのか、性格なのか。難しい。&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-9117667791447307052?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/9117667791447307052/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=9117667791447307052' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/9117667791447307052'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/9117667791447307052'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/10/nodefest-2011-warmup.html' title='Nodefest.jp warm-up event に行ってきた'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-5438147647604828184</id><published>2011-10-13T23:55:00.000+09:00</published><updated>2011-10-13T23:56:36.756+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nodejs'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>CentOS に Node.js をインストールして forever でデーモン化</title><content type='html'>&lt;p&gt;ちょっと作業するときに忘れてしまうのでメモ。
さくらインターネットの VPS で適当なユーザーを作成して sudo 権限を与えてから作業。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://nodejs.org/"&gt;Node.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://vps.sakura.ad.jp/"&gt;さくらのVPS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ちょうど去年くらいの &lt;a class="reference external" href="http://kshigeru.blogspot.com/2010/10/realtime-web-hack-thon.html"&gt;Realtime Web hack-a-thon&lt;/a&gt; で Windows でのビルドとかやってたんだなぁ、と振り返ると、
本体だけでなく周辺ライブラリが充実してきたスピードも目を見張るものがある。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://blog.nodejs.org/2011/06/23/porting-node-to-windows-with-microsoft%E2%80%99s-help/"&gt;Porting Node to Windows With Microsoft’s Help&lt;/a&gt; (node blog)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://blog.nodejs.org/2011/06/23/porting-node-to-windows-with-microsoft%E2%80%99s-help/"&gt;Installing Node.js On Windows&lt;/a&gt; (MOZILLA WEBDEV)&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="id1"&gt;
&lt;h1&gt;Node.js のインストール&lt;/h1&gt;
&lt;p&gt;基本的な環境の準備&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cd /usr/local
$ sudo mkdir src/archive
$ sudo chgrp -R wheel src
$ sudo chmod 775 src src/archive/
$ sudo yum -y install openssl-devel
&lt;/pre&gt;
&lt;p&gt;パッケージをダウンロードして展開&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cd /usr/local/src/archive
$ wget http://nodejs.org/dist/node-v0.4.12.tar.gz
$ cd ..
$ tar -xzvf archive/node-v0.4.12.tar.gz
&lt;/pre&gt;
&lt;p&gt;コンパイルしてインストール&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cd /usr/local/src/node-v0.4.12
$ ./configure --prefix=/usr/local/nodejs/node-v0.4.12
$ make
$ sudo make install
&lt;/pre&gt;
&lt;p&gt;シンボリックリンクを作成してバージョンを確認&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cd /usr/local/nodejs
$ sudo ln -s node-v0.4.12 latest
$ /usr/local/nodejs/latest/bin/node -v
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="npm"&gt;
&lt;h1&gt;npm のインストール&lt;/h1&gt;
&lt;p&gt;Node のパッケージマネージャーをインストールする。
Python における pip みたいなもの。&lt;/p&gt;
&lt;p&gt;パスの調整をすれば、後はドキュメント通り。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ curl http://npmjs.org/install.sh | sudo PATH=$PATH:/usr/local/nodejs/latest/bin sh
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;/usr/local/nodejs/latest/bin&lt;/tt&gt; に &lt;tt class="docutils literal"&gt;npm&lt;/tt&gt; コマンドがインストールされる。&lt;/p&gt;
&lt;p&gt;npm は本体に付属してくれても良いんじゃないかな、とは思うけど、
双方の開発がかなり安定するまでは難しいのかも。
とはいえ、curl コマンドが無い Windows 環境用には同梱されて欲しい。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="express"&gt;
&lt;h1&gt;express のインストール&lt;/h1&gt;
&lt;p&gt;&lt;a class="reference external" href="http://expressjs.com/guide.html"&gt;express&lt;/a&gt; は Web アプリケーション・フレームワークのこと。
ロガーとか、ミドルウェアが色々と実装されているので便利。&lt;/p&gt;
&lt;p&gt;マシンの利用用途にもよるが、モジュールをシステムグローバルにインストールする場合は &amp;quot;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-g&lt;/span&gt;&lt;/tt&gt;&amp;quot; オプションを付ける。
&lt;tt class="docutils literal"&gt;/usr/local/nodejs/latest/bin&lt;/tt&gt; に &lt;tt class="docutils literal"&gt;express&lt;/tt&gt; コマンドがインストールされる。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ export PATH=$PATH:/usr/local/nodejs/latest/bin
$ sudo PATH=$PATH:/usr/local/nodejs/latest/bin /usr/local/nodejs/latest/bin/npm install -g express
&lt;/pre&gt;
&lt;p&gt;たとえば、 &amp;quot;http-proxy&amp;quot; というアプリケーションの作成&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ [ -d projects ] || mkdir projects
$ cd projects
$ express http-proxy
$ cd http-proxy
$ npm install -d
&lt;/pre&gt;
&lt;p&gt;開発用サーバーを起動&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ node app.js
&lt;/pre&gt;
&lt;p&gt;環境を切り替えるには &lt;tt class="docutils literal"&gt;NODE_ENV&lt;/tt&gt; を指定&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ NODE_ENV=production node app.js
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="forever"&gt;
&lt;h1&gt;forever でデーモン化&lt;/h1&gt;
&lt;p&gt;プロダクション環境で最適な方法は分かりませんが、この辺の記事が参考になりそう。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://dragonmind.jugem.jp/?eid=35"&gt;node.js+express-mvc-bootstrapをdaemontoolsでデーモン化&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/indexzero/forever"&gt;forever&lt;/a&gt; - github.com&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/petrjanda/daemon.js"&gt;daemon.js&lt;/a&gt; - github.com&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://stackoverflow.com/questions/7022742/setting-node-env-for-node-js-expressjs-application-as-a-daemon-under-ubuntu"&gt;setting NODE_ENV for node.js + expressjs application as a daemon under ubuntu&lt;/a&gt; - stackoverflow.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;forever&lt;/tt&gt; を使う場合は次のような手順。&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;npm&lt;/tt&gt; でシステムグローバルにインストール。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ sudo PATH=$PATH:/usr/local/nodejs/latest/bin /usr/local/nodejs/latest/bin/npm install -g forever
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;forever&lt;/tt&gt; コマンドの &lt;cite&gt;start&lt;/cite&gt; アクションにスクリプトを指定。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ export PATH=$PATH:/usr/local/nodejs/latest/bin
$ forever start app.js
&lt;/pre&gt;
&lt;p&gt;自前で init.d 用スクリプトなどを書くよりは断然簡単で、
&lt;cite&gt;list&lt;/cite&gt; アクションで稼働アプリケーションを一覧表示できるのも嬉しい。
(ターミナルによっては色付きで表示)&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ forever list
info:   Running action: list
info:   Forever processes running
data:       uid  command script forever pid   logfile                         uptime
data:   [0] XnU4 node    app.js 32290   32291 /home/shigeru/.forever/XnU4.log 0:0:0:17.44
&lt;/pre&gt;
&lt;p&gt;止めるときは &lt;cite&gt;stop&lt;/cite&gt; を使う。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ forever stop app.js
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;たまには JavaScript を書かないとー、というときに、さくらのVPSは便利。
Amazon の EC2 でも変わらないけど、なんとなく SSH のレスポンスが早い気もする。&lt;/p&gt;
&lt;p&gt;「なぜ Node.js を使うのか？」という点では Facebook の中の人の意見に賛成だけど、
そもそも JavaScript をバリバリ書ける人は多いのか、という点が大きな疑問だったり。。。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.readwriteweb.com/cloud/2011/05/nodejs-at-facebook.php"&gt;Node.js at Facebook - Why it's Needed and What's Holding it Back&lt;/a&gt; - readwriteweb.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;じゃ、Dart を使えば解決？かというと、今は微妙だと感じる。
移行できる資産が存在しないのもネック。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.dartlang.org/"&gt;Dart&lt;/a&gt; (STRUCTURED WEB PROGRAMMING) - dartlang.org&lt;/li&gt;
&lt;/ul&gt;
&lt;div style="float: right; margin: 10px;"&gt;
&lt;iframe src="http://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&amp;bc1=000000&amp;IS2=1&amp;bg1=FFFFFF&amp;fc1=000000&amp;lc1=0000FF&amp;t=kshigeru-22&amp;o=9&amp;p=8&amp;l=as4&amp;m=amazon&amp;f=ifr&amp;ref=ss_til&amp;asins=4844318284" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;
&lt;/div&gt;&lt;p&gt;どんなプログラミング言語を使うにしても、プロジェクトのライフサイクルを意識して開発できないと厳しい感じ。
それを支援するツールも必要で、パッケージ管理やテスト、ドキュメンテーションは必須。
誰かが開発するとは思うけど、どれだけ熱意のある人が集まるかでスタートダッシュが変わるので、
単純に構文がイケテル、とかはそこまで重要でもない気がする。
(Google にはソフトウェアエンジニアが多いので問題にはならないかもしれないが)&lt;/p&gt;
&lt;p&gt;ちょっと関係ないけど、「コンピュータの名著・古典100冊」の一節が簡潔で分かりやすい。&lt;/p&gt;
&lt;blockquote&gt;
日本語の場合でも、文法を知ることと文章を書くこととの間には大きなギャップがある。
プログラミングも同じである。
文法を知ることとよいプログラムを書くことの間には大きなギャップがある。&lt;/blockquote&gt;
&lt;p&gt;名著や古典を紹介する本だけど、これはこれで良い本。
面接で何を聞くか？というトピックは紛糾しやすいけど、この中の10冊以上をきちんと読んでいる人ならハズレない気がする。
もちろん Node.js にはノータッチだけども。&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-5438147647604828184?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/5438147647604828184/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=5438147647604828184' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/5438147647604828184'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/5438147647604828184'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/10/nodejs-forever.html' title='CentOS に Node.js をインストールして forever でデーモン化'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-8559288405648359570</id><published>2011-10-02T22:33:00.000+09:00</published><updated>2011-10-02T22:33:19.333+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Solr'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Nginx'/><title type='text'>Nginx でレスポンスヘッダーを追加する</title><content type='html'>
&lt;p&gt;Nginx の &lt;a class="reference external" href="http://wiki.nginx.org/HttpHeadersMoreModule"&gt;HttpHeadersMoreModule&lt;/a&gt; を使うと、HTTP レスポンスにヘッダーを付け足せるようなので導入してみます。
特定の条件の場合にヘッダーを追加できるとクロスドメイン通信を実現できますので、
JSON か XML でレスポンスを返せるサーバーソフトウェアのクライアントサイドを実装する敷居が下がるはずです。
要するに、JavaScript で Solr のカスタムクライアントを実装できるかもしれませんね、という話です。&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-ueigb-NsPIM/TohmbNie7FI/AAAAAAAAEMI/hvB4bkzCfFc/s1600/nginx-headers-more-1.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="240" width="400" src="http://1.bp.blogspot.com/-ueigb-NsPIM/TohmbNie7FI/AAAAAAAAEMI/hvB4bkzCfFc/s400/nginx-headers-more-1.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;&lt;tt class="docutils literal"&gt;HttpHeadersMoreModule&lt;/tt&gt; は追加モジュールであるため、ソースコードを取得して、
Nginx のビルドオプションで明示する必要があります。
自前でソースコードをコンパイルするところから始めますので、すんなりいかない場合もあるかもしれません。
実行環境には Amazon の EC2 を使います。&lt;/p&gt;
&lt;p&gt;この辺の続きです。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/01/getting-started-amazon-ec2.html"&gt;Amazon EC2 を使ってみる&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/10/solr-nginx.html"&gt;Nginx を Solr のフロントに使ってみる&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="id1"&gt;
&lt;h1&gt;Nginx のコンパイル&lt;/h1&gt;
&lt;p&gt;nginx-1.0.8 を使います。
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;headers-more-nginx-module&lt;/span&gt;&lt;/tt&gt; のバージョン 0.15 は 1.0.5 で動作確認しているようですが、
たぶん 1.0.8 でも大丈夫でしょう。&lt;/p&gt;
&lt;p&gt;Nginx 自体をコンパイルするためには
PCRE (Perl Compatible Regular Expressions) も必要になりますので、
合計で次の３つのソースアーカイブを用意します。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;nginx-1.0.8&lt;/li&gt;
&lt;li&gt;headers-more-nginx-module-0.15&lt;/li&gt;
&lt;li&gt;pcre-8.13&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="literal-block"&gt;
$ [ -d src ] || mkdir src
$ cd src
$ wget http://nginx.org/download/nginx-1.0.8.tar.gz
$ wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.13.tar.gz
$ wget -O headers-more-nginx-module-0.15.tar.gz https://github.com/agentzh/headers-more-nginx-module/tarball/v0.15
$ for f in `ls -1 *.tar.gz`; do tar -xzvf $f; done
&lt;/pre&gt;
&lt;p&gt;コンパイラなどをインストールしておきます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ sudo yum -y install gcc zlib-devel
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;configure&lt;/tt&gt; スクリプトにいくつかのオプションを渡してビルドします。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cd nginx-1.0.8
$ ./configure \
        --prefix=/usr/local/nginx/nginx-1.0.8 \
        --with-pcre=../pcre-8.13 \
        --add-module=../agentzh-headers-more-nginx-module-137855d
$ make
&lt;/pre&gt;
&lt;p&gt;コンパイルが通ったらインストールします。
バージョンの違いで嵌まるとイヤなのでバージョン番号も残しておきます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ sudo make install
$ cd /usr/local/nginx
$ sudo ln -s nginx-1.0.8 latest
&lt;/pre&gt;
&lt;p&gt;インストールできたら起動してみます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cd /usr/local/nginx/latest
$ sudo ./sbin/nginx
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;wget&lt;/tt&gt; などでアクセスして、Server が nginx であることを確認します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ wget -Sq &amp;quot;http://localhost&amp;quot;
  HTTP/1.1 200 OK
  Server: nginx/1.0.8
  Date: Sun, 02 Oct 2011 11:56:12 GMT
  Content-Type: text/html
  Content-Length: 151
  Last-Modified: Sun, 02 Oct 2011 11:52:43 GMT
  Connection: keep-alive
  Accept-Ranges: bytes
&lt;/pre&gt;
&lt;p&gt;アクセスログも確認しておきます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ tail logs/access.log
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h1&gt;Nginx の設定&lt;/h1&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;more_set_headers&lt;/tt&gt; を使ってみます。
&lt;tt class="docutils literal"&gt;/usr/local/nginx/latest/conf/nginx.conf&lt;/tt&gt; に次の記述を追加します。&lt;/p&gt;
&lt;pre class="prettyprint literal-block"&gt;
location /search {
    more_set_headers 'X-MyHeader: blah' 'X-MyHeader2: foo';
}
&lt;/pre&gt;
&lt;p&gt;Nginx を再起動します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ sudo pkill nginx
$ sudo ./sbin/nginx
&lt;/pre&gt;
&lt;p&gt;&lt;cite&gt;/search&lt;/cite&gt; にアクセスするとヘッダーが追加されていますね。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ wget -Sq &amp;quot;http://localhost/search&amp;quot;
  HTTP/1.1 404 Not Found
  Server: nginx/1.0.8
  Date: Sun, 02 Oct 2011 12:01:47 GMT
  Content-Type: text/html
  Content-Length: 168
  Connection: keep-alive
  X-MyHeader: blah
  X-MyHeader2: foo
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;クロスドメインの設定&lt;/h1&gt;
&lt;p&gt;サーバー側で Solr を動かして Nginx でプロキシさせるために、
stackoverflow の回答を参考に設定します。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://stackoverflow.com/questions/4994803/apache-nginx-proxy-post-requests-to-remote-server-handle-options-requests-local"&gt;Apache/Nginx: proxy POST requests to remote server, handle OPTIONS requests locally&lt;/a&gt; - stackoverflow.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;nginx.conf&lt;/tt&gt; はこんな感じ。&lt;/p&gt;
&lt;pre class="prettyprint literal-block"&gt;
location /solr {
    if ($request_method = 'OPTIONS') {
        more_set_headers 'Access-Control-Allow-Origin: *';
        more_set_headers 'Access-Control-Allow-Methods: GET, OPTIONS';
        more_set_headers 'Access-Control-Max-Age: 1728000';
        more_set_headers 'Content-Type: text/plain; charset=UTF-8';

        return 200;
    }

    more_set_headers 'Access-Control-Allow-Origin: *';
    proxy_pass       http://127.0.0.1:8983/solr;
}
&lt;/pre&gt;
&lt;p&gt;HTTP の OPTIONS を処理する必要性はこの辺で。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://developer.mozilla.org/Ja/HTTP_access_control"&gt;HTTP access control&lt;/a&gt; - developer.mozilla.org&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://stackoverflow.com/questions/1099787/jquery-ajax-post-sending-options-as-request-method-in-firefox"&gt;jQuery $.ajax(), $.post sending “OPTIONS” as REQUEST_METHOD in Firefox&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="javascript-solr"&gt;
&lt;h1&gt;JavaScript で Solr のレスポンスを表示&lt;/h1&gt;
&lt;p&gt;ローカルマシンで適当な HTML と JavaScript (&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;solr-search.html&lt;/span&gt;&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;solr-search.js&lt;/span&gt;&lt;/tt&gt;) を用意します。
jQuery と jQuery Template、それから Twitter Bootstrap を読み込んでおきます。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/skitazaki/sandbox/blob/master/src/javascript/solr-search.html"&gt;solr-search.html&lt;/a&gt; - github&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/skitazaki/sandbox/blob/master/src/javascript/solr-search.js"&gt;solr-search.js&lt;/a&gt; - github&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;HTML のあるディレクトリで HTTP サーバーを立ち上げます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ python -m SimpleHTTPServer
&lt;/pre&gt;
&lt;p&gt;ブラウザーで &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;http://localhost:8000/solr-search.html&lt;/span&gt;&lt;/tt&gt; にアクセスし、
検索キーワードを入力して実行すると、検索結果が表示されます。(冒頭のスクリーンショット)&lt;/p&gt;
&lt;p&gt;Firebug などでレスポンスヘッダーを確認すると、 &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;Access-Control-Allow-Origin&lt;/span&gt;&lt;/tt&gt; が設定されています。&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-_gQPYcDMGc0/TohmbFbhf1I/AAAAAAAAEMQ/KrIisXW2RpM/s1600/nginx-headers-more-2.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="173" width="305" src="http://4.bp.blogspot.com/-_gQPYcDMGc0/TohmbFbhf1I/AAAAAAAAEMQ/KrIisXW2RpM/s400/nginx-headers-more-2.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;あとは好みに応じて実装すればカスタムクライアントを実装できます。
特定のフィールドだけを一覧形式で表示したい場合には便利かもしれません。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;Nginx でレスポンスヘッダーを追加してみました。
追加モジュールを使う場合は、ソースアーカイブを取得してコンパイルオプションを調整する必要があります。
独自環境を使っている場合にはコンパイルが大変かもしれませんが、たいがいのアーキテクチャではサクッと使えると思います。&lt;/p&gt;
&lt;p&gt;ヘッダーにも多様な役割のものがありますが、ここではクロスドメイン通信に焦点を当てました。
JavaScript によるクロスドメイン通信には色々と難しい問題がありますが、
サーバーサイドにプロキシを追加して実現する方法はとてもお手軽だと思いました。&lt;/p&gt;
&lt;p&gt;なお、Solr の場合は &lt;tt class="docutils literal"&gt;json.wrf&lt;/tt&gt; パラメータを使うことで JSONP を実現できます。
このため、Solr で JSON だけを使う場合にはこの記事の内容は不要です。
たとえば、次のリンクのようにして実現できます。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://d.hatena.ne.jp/tolerance/20080927"&gt;jQueryでsolrクライアントを書いてみる&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://nuggets.comperiosearch.com/2011/03/asynchronous-search-results-jquery-solr-json-ajax/"&gt;Asynchronous search results with JQuery, Solr, Json and Ajax&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Solr の JavaScript クライアントとしては &lt;cite&gt;ajax-solr&lt;/cite&gt; があります。
リクエスト URL とプロキシ URL を設定できるようになっていますので、
きちんとした自前のクライアントページを構築するならこちらを使うべきでしょう。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://evolvingweb.github.com/ajax-solr/"&gt;ajax-solr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://wiki.apache.org/solr/SolrJS"&gt;SolrJS&lt;/a&gt; (以前に実装されたもの)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;用途に合わせて様々な組み合わせや制約がありますが、
何かのときに役立つと良いのかな、と。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-8559288405648359570?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/8559288405648359570/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=8559288405648359570' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/8559288405648359570'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/8559288405648359570'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/10/nginx-headers-more.html' title='Nginx でレスポンスヘッダーを追加する'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-ueigb-NsPIM/TohmbNie7FI/AAAAAAAAEMI/hvB4bkzCfFc/s72-c/nginx-headers-more-1.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-4631578643717510320</id><published>2011-10-02T10:26:00.000+09:00</published><updated>2011-10-02T22:33:40.747+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Solr'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Nginx'/><title type='text'>Nginx を Solr のフロントに使ってみる</title><content type='html'>
&lt;p&gt;Solr のフロントに Nginx を使ってみます。
外部からも &lt;cite&gt;select&lt;/cite&gt; はできるけど &lt;cite&gt;update&lt;/cite&gt; はできないようにして、
&lt;cite&gt;admin&lt;/cite&gt; には BASIC 認証をかけます。&lt;/p&gt;
&lt;p&gt;クリーンな環境の方が分かりやすいので、Amazon の EC2 を使います。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="ec2"&gt;
&lt;h1&gt;EC2 のインスタンスを用意&lt;/h1&gt;
&lt;p&gt;基本的な構成でインスタンスを作成します。
SSH のための 22 番ポートと、HTTP のための 80 番ポートを開放しておきます。
細かい手順はこの辺で。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/01/getting-started-amazon-ec2.html"&gt;Amazon EC2 を使ってみる&lt;/a&gt; (１月の記事)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://blog.withsin.net/2011/02/21/ec2-api-tools/"&gt;ec2-api-tools&lt;/a&gt; - blog.withsin.net&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ローカルマシンから EC2 のインスタンスには SSH で接続しますが、
このときにローカルマシンにポートを転送させます。
Solr は Jetty を使って 8983 番ポートで起動し、Nginx はデフォルトの 80 番ポートで起動させ、
ローカルマシンでは、それぞれを 8080 番ポートと 8000 番ポートに対応付けます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ ssh -L8080:localhost:8983 -L8000:localhost:80 -l ec2-user -i {PRIVATE_KEY} {IP_ADDRESS}
&lt;/pre&gt;
&lt;p&gt;もちろん &lt;tt class="docutils literal"&gt;{PRIVATE_KEY}&lt;/tt&gt; と &lt;tt class="docutils literal"&gt;{IP_ADDRESS}&lt;/tt&gt; は環境に合わせて適当な文字列を使います。&lt;/p&gt;
&lt;p&gt;以降の作業はこのインスタンス上で進めます。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="solr"&gt;
&lt;h1&gt;Solr を準備&lt;/h1&gt;
&lt;p&gt;Solr の 3.4 をダウンロードして展開します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ wget http://ftp.riken.jp/net/apache/lucene/solr/3.4.0/apache-solr-3.4.0.tgz
$ tar -xzvf apache-solr-3.4.0.tgz
&lt;/pre&gt;
&lt;p&gt;&lt;cite&gt;example&lt;/cite&gt; ディレクトリに移動して、付属の Jetty を使って起動します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cd apache-solr-3.4.0/example
$ java -jar start.jar &amp;amp;
&lt;/pre&gt;
&lt;p&gt;EC2 インスタンスの 8983 番ポートはローカルマシンの 8080 番ポートにフォワードされていますから、
ブラウザーで &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;http://localhost:8080/solr/admin&lt;/span&gt;&lt;/tt&gt; にアクセスすると、管理画面が表示されます。&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-TYeD_cWLoIw/Toe8MJhMDYI/AAAAAAAAELo/QkoLZSU_C90/s1600/solr-admin-on-ec2.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="203" width="400" src="http://2.bp.blogspot.com/-TYeD_cWLoIw/Toe8MJhMDYI/AAAAAAAAELo/QkoLZSU_C90/s400/solr-admin-on-ec2.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;div class="section" id="nginx"&gt;
&lt;h1&gt;Nginx を準備&lt;/h1&gt;
&lt;p&gt;パッケージ管理ソフトを使って Nginx をインストールし、起動スクリプトから起動させます。
自動起動を有効にする場合にはその設定もしておきます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ sudo yum -y install nginx
$ sudo /etc/init.d/nginx start
&lt;/pre&gt;
&lt;p&gt;(この記事を書いている時点では nginx-0.7.67 のパッケージを使いますので、
最新版を使いたい場合にはソースコードを自分でビルドします。)&lt;/p&gt;
&lt;p&gt;EC2 インスタンスの 80 番ポートはローカルマシンの 8000 番ポートにフォワードされていますから、
ブラウザーで localhost:8000/ にアクセスすると、ウェルカムページが表示されます。&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-5RUt3T-XwSA/Toe8MBGQPHI/AAAAAAAAELw/MjLIqdlCHOQ/s1600/nginx-welcome-page.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="182" width="400" src="http://2.bp.blogspot.com/-5RUt3T-XwSA/Toe8MBGQPHI/AAAAAAAAELw/MjLIqdlCHOQ/s400/nginx-welcome-page.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;設定ファイル置き場も確認しておきます。&lt;/p&gt;
&lt;pre class="prettyprint literal-block"&gt;
$ tree /etc/nginx/
/etc/nginx/
├── conf.d
│&amp;nbsp;&amp;nbsp; ├── ssl.conf
│&amp;nbsp;&amp;nbsp; └── virtual.conf
├── fastcgi.conf
├── fastcgi.conf.default
├── fastcgi_params
├── fastcgi_params.default
├── koi-utf
├── koi-win
├── mime.types
├── mime.types.default
├── nginx.conf
├── nginx.conf.default
└── win-utf
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="id1"&gt;
&lt;h1&gt;Nginx の設定&lt;/h1&gt;
&lt;p&gt;プロキシの設定をします。
Nginx に &lt;tt class="docutils literal"&gt;/search&lt;/tt&gt; でアクセスされたら Solr の &lt;tt class="docutils literal"&gt;/solr/select&lt;/tt&gt; にフォワードします。
&lt;tt class="docutils literal"&gt;/etc/nginx/nginx.conf&lt;/tt&gt; に次の記述を追加します。&lt;/p&gt;
&lt;pre class="prettyprint literal-block"&gt;
location /search {
    proxy_pass   http://127.0.0.1:8983/solr/select;
}
&lt;/pre&gt;
&lt;p&gt;Nginx を再起動します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ sudo /etc/init.d/nginx restart
&lt;/pre&gt;
&lt;p&gt;ブラウザーで &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;http://localhost:8000/search?q=*:*&lt;/span&gt;&lt;/tt&gt; にアクセスすると
空の結果を意味する XML が返されます。&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-lwQgiaxIHIE/Toe8MUSW9FI/AAAAAAAAEL4/Ik2LTb1xAp8/s1600/solr-nginx-proxy.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="111" width="400" src="http://1.bp.blogspot.com/-lwQgiaxIHIE/Toe8MUSW9FI/AAAAAAAAEL4/Ik2LTb1xAp8/s400/solr-nginx-proxy.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;次に管理画面に BASIC 認証をかけます。
wiki の設定をほぼそのまま適用します。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://wiki.nginx.org/HttpAuthBasicModule"&gt;HttpAuthBasicModule&lt;/a&gt; - wiki.nginx.org&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;/etc/nginx/nginx.conf&lt;/tt&gt; に設定を追加します。&lt;/p&gt;
&lt;pre class="prettyprint literal-block"&gt;
location /admin {
    proxy_pass            http://127.0.0.1:8983/solr/admin;
    auth_basic            &amp;quot;Restricted&amp;quot;;
    auth_basic_user_file  htpasswd;
}
&lt;/pre&gt;
&lt;p&gt;パスワードファイルを作成します。
パスは、 &lt;tt class="docutils literal"&gt;nginx.conf&lt;/tt&gt; ディレクトリからの相対パスで決定します。
nginx のプリフィクスディレクトリからではありませんので、インストール方法によっては注意が必要です。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ sudo htpasswd -c /etc/nginx/htpasswd admin
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;htpasswd&lt;/tt&gt; コマンドが存在しない場合には &lt;tt class="docutils literal"&gt;crypt(3)&lt;/tt&gt; 関数を使って手動でパスワードファイルを作成します。
何らかのツールを使った方が良いでしょうね。&lt;/p&gt;
&lt;p&gt;Nginx を再起動します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ sudo /etc/init.d/nginx restart
&lt;/pre&gt;
&lt;p&gt;ブラウザーで &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;http://localhost:8000/admin&lt;/span&gt;&lt;/tt&gt; にアクセスすると、
BASIC 認証のダイアログが表示されます。
なお、パスを大きく変更していますので管理画面からは検索を実行できません。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h1&gt;Solr のテストデータ&lt;/h1&gt;
&lt;p&gt;Solr の配布パッケージに付属するサンプルデータを登録します。
Solr の example ディレクトリに &lt;cite&gt;exampledocs&lt;/cite&gt; があり、ここにテストデータが保存されています。
&lt;tt class="docutils literal"&gt;post.sh&lt;/tt&gt; に引数で与えた XML ファイルを登録できます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cd apache-solr-3.4.0/example/exampledocs
$ ./post.sh *.xml
&lt;/pre&gt;
&lt;p&gt;続けて、件数カウントのリクエストを投げます。&lt;/p&gt;
&lt;pre class="prettyprint literal-block"&gt;
$ wget -qO - &amp;quot;http://localhost:8983/solr/select?q=*:*&amp;amp;rows=0&amp;amp;indent=on&amp;quot;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot;?&amp;gt;
&amp;lt;response&amp;gt;
&amp;lt;lst name=&amp;quot;responseHeader&amp;quot;&amp;gt;
  &amp;lt;int name=&amp;quot;status&amp;quot;&amp;gt;0&amp;lt;/int&amp;gt;
  &amp;lt;int name=&amp;quot;QTime&amp;quot;&amp;gt;0&amp;lt;/int&amp;gt;
  &amp;lt;lst name=&amp;quot;params&amp;quot;&amp;gt;
    &amp;lt;str name=&amp;quot;indent&amp;quot;&amp;gt;on&amp;lt;/str&amp;gt;
    &amp;lt;str name=&amp;quot;q&amp;quot;&amp;gt;*:*&amp;lt;/str&amp;gt;
    &amp;lt;str name=&amp;quot;rows&amp;quot;&amp;gt;0&amp;lt;/str&amp;gt;
  &amp;lt;/lst&amp;gt;
&amp;lt;/lst&amp;gt;
&amp;lt;result name=&amp;quot;response&amp;quot; numFound=&amp;quot;17&amp;quot; start=&amp;quot;0&amp;quot;/&amp;gt;
&amp;lt;/response&amp;gt;
&lt;/pre&gt;
&lt;p&gt;ローカルマシンの 8000 番ポートで確認します。
ブラウザーで &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;http://localhost:8000/search?q=*:*&lt;/span&gt;&lt;/tt&gt; にアクセスすると
XML で結果が返ってきます。&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-AIyHDD1OMic/Toe8MgTgHsI/AAAAAAAAEMA/OFdD9Q3mQao/s1600/solr-sample-data-response.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="254" width="400" src="http://4.bp.blogspot.com/-AIyHDD1OMic/Toe8MgTgHsI/AAAAAAAAEMA/OFdD9Q3mQao/s400/solr-sample-data-response.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;p&gt;きちんと 80 番ポートが開放されていると、
そのアドレスにアクセスすれば同じ結果が得られますね。&lt;/p&gt;
&lt;p&gt;開放しているポートからプロキシするのは検索用のハンドラだけですから、
ドキュメントインデクスの更新は閉じたネットワーク内で完結します。
間違ってドキュメントを削除することは防止できますから、
URL を公開しても問題ありません。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;Nginx を Solr のフロントに使ってみました。
「それ、Apache でいいじゃん」というのはその通りで、
単純に Nginx を使ってみたかったのでやってみた、という感じです。
実際に手を動かすととても簡単なことが実感できますので、
Nginx ってなんだか難しそう... とは杞憂に終わりました。&lt;/p&gt;
&lt;p&gt;Nginx は Web サーバーというよりプロキシサーバーですから、
複数の Solr サーバーに対してロードバランシングもできます。
アクティブ / スタンバイ構成ではなく、複数台のサーバーを並べて使えると、
マシンが遊んでしまうこともなさそうです。&lt;/p&gt;
&lt;p&gt;EC2 に関しては、ちょっとした動作確認にマイクロインスタンスを使うのは便利だな、と思います。
管理用のコマンドラインツールもありますし、パッケージも不便なく利用できます。
サービスとして動かし続ける場合はそれなりのお金がかかるでしょうが、
学習用にスポットとして使う分には書籍代より安いですし、そもそもダラダラと作業しないようになり、
可能なものは事前に調べるようになる気がします。
なにより、自分のマシンがミドルウェアでいっぱいにならないのは嬉しいですね。&lt;/p&gt;
&lt;p&gt;使い終わったインスタンスは &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;ec2-stop-instances&lt;/span&gt;&lt;/tt&gt; で停止させておきましょう。
インスタンスの ID は &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;ec2-describe-instances&lt;/span&gt;&lt;/tt&gt; で確認できます。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://blog.withsin.net/2011/04/19/ec2-stop-instances/"&gt;ec2-stop-instances (ec2stop)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-4631578643717510320?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/4631578643717510320/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=4631578643717510320' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/4631578643717510320'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/4631578643717510320'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/10/solr-nginx.html' title='Nginx を Solr のフロントに使ってみる'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-TYeD_cWLoIw/Toe8MJhMDYI/AAAAAAAAELo/QkoLZSU_C90/s72-c/solr-admin-on-ec2.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-2707005819266240789</id><published>2011-09-15T22:55:00.002+09:00</published><updated>2011-09-15T22:57:03.121+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>History API を使ってみる</title><content type='html'>
&lt;p&gt;History API を使ってみます。
正確には、History API をクロスブラウザ対応でラップしてある &lt;a class="reference external" href="https://github.com/balupton/history.js"&gt;history.js&lt;/a&gt; を使ってみます。&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;history.js&lt;/tt&gt; は &lt;a class="reference external" href="https://github.com/balupton/jquery-history"&gt;jquery-history&lt;/a&gt; を再実装したもので、
jQuery のプラグインとしてしか使えなかったものを汎用的に再実装し、
各種ライブラリへのアダプタを用意したものです。
アダプタは YUI や Prototype などにも対応しているらしいので、
jQuery 以外の JavaScript ライブラリと組み合わせることもできます。&lt;/p&gt;
&lt;p&gt;なお、ブラウザの履歴に関する操作は Mozilla のサイトで網羅的に解説されています。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://developer.mozilla.org/en/DOM/Manipulating_the_browser_history"&gt;Manipulating the browser history&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="id1"&gt;
&lt;h1&gt;ライブラリの読み込み&lt;/h1&gt;
&lt;p&gt;ブラウザの履歴 (&lt;tt class="docutils literal"&gt;window.history&lt;/tt&gt;) には &lt;tt class="docutils literal"&gt;back()&lt;/tt&gt; や &lt;tt class="docutils literal"&gt;go()&lt;/tt&gt; などの API がありましたが、
いわゆるモダンブラウザには &lt;tt class="docutils literal"&gt;pushState()&lt;/tt&gt; や &lt;tt class="docutils literal"&gt;replaceState()&lt;/tt&gt; という API が追加されています。
このため、ターゲットとするブラウザによって読み込むべき JavaScript ファイルが異なります。
ごちゃごちゃ考えるのが面倒な場合にはすべてを読み込めば動きますが、
HTML5 に関することを HTML4 までの世界に適用させるべきかは一考の価値がありそうです。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/balupton/history.js/wiki/Intelligent-State-Handling"&gt;Intelligent State Handling&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ともあれ、jQuery をベースにしてザクッと全てを読み込む場合は次のような感じでしょうか。
&lt;tt class="docutils literal"&gt;$STATIC_URL&lt;/tt&gt; は適当に調整するか、何らかのビルドスクリプトで置換します。&lt;/p&gt;
&lt;pre class="prettyprint lang-html literal-block"&gt;
  &amp;lt;script src=&amp;quot;//ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script&amp;gt;window.jQuery || document.write('&amp;lt;script src=&amp;quot;$STATIC_URL/js/jquery.min.js&amp;quot;&amp;gt;\x3C/script&amp;gt;')&amp;lt;/script&amp;gt;
  &amp;lt;script src=&amp;quot;//ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script&amp;gt;window.JSON || document.write('&amp;lt;script src=&amp;quot;$STATIC_URL/js/json2.min.js&amp;quot;&amp;gt;\x3C/script&amp;gt;')&amp;lt;/script&amp;gt;
  &amp;lt;script src=&amp;quot;$STATIC_URL/js/amplify.store.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&amp;quot;$STATIC_URL/js/history.adapter.jquery.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&amp;quot;$STATIC_URL/js/history.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;script src=&amp;quot;$STATIC_URL/js/history.html4.min.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;

&lt;/pre&gt;
&lt;p&gt;なお、 &lt;tt class="docutils literal"&gt;jquery.tmpl.min.js&lt;/tt&gt; は他の用途で使っているものなので、History API とは関係ありません。
また、各種ファイルに &lt;cite&gt;.min&lt;/cite&gt; を付けているのは個人的な管理を簡単化するためです。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h1&gt;履歴の変化を追いかける&lt;/h1&gt;
&lt;p&gt;ライブラリを読み込んだら、最初のコードを書きます。
これは &lt;a class="reference external" href="https://github.com/balupton/history.js"&gt;history.js&lt;/a&gt; の README の最初の方にあるものをコピペすれば動くはずです。
とりあえずこんな感じ。&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block"&gt;
$(function() {

    var History = window.History; // 小文字ではなく大文字の H を使います。
    if (!History.enabled) {
         // History.js が無効になっています。
         // HTML4 のブラウザをサポートするかどうかによります。
        return false;
    }

    // StateChange イベントを紐付けます。
    History.Adapter.bind(window, 'statechange', function() { // popstate ではなく statechange を使います。
        var State = History.getState(); // event.state ではなく History.getState() を使います。
        History.log(State.data, State.title, State.url);
    });

    // 状態を遷移させます。
    // 引数は順番に「状態オブジェクト」「タイトル」「URL」です。
    History.pushState({state:1}, &amp;quot;State 1&amp;quot;, &amp;quot;?state=1&amp;quot;);
    History.pushState({state:2}, &amp;quot;State 2&amp;quot;, &amp;quot;?state=2&amp;quot;);
    History.replaceState({state:3}, &amp;quot;State 3&amp;quot;, &amp;quot;?state=3&amp;quot;);
    History.pushState(null, null, &amp;quot;?state=4&amp;quot;);
    History.back();
    History.back();
    History.back();
    History.go(2);

});
&lt;/pre&gt;
&lt;p&gt;「状態オブジェクト」って何？という感じですが、
履歴のある時点に関連付く JavaScript オブジェクト (シリアライズ可能なもの) なら何でも良さそうです。
とはいえデータサイズには上限があり、Firefox の場合は 640k だそうです。
これを超過した場合は例外が投げられますので、大きなデータを保存しておくためには
&lt;tt class="docutils literal"&gt;sessionStorage&lt;/tt&gt; や &lt;tt class="docutils literal"&gt;sessionStorage&lt;/tt&gt; を使いましょう、とのこと。&lt;/p&gt;
&lt;p&gt;さて、HTML ファイルを開いて Firebug などの JavaScript コンソールを開いてみると次のようになります。
ブラウザのアドレスバーも変わっているはずです。&lt;/p&gt;

&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-j50hEsdaV2o/TnIDshyWTUI/AAAAAAAAEIs/4OujSQNdQSY/s1600/history-js-log.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="253" width="400" src="http://1.bp.blogspot.com/-j50hEsdaV2o/TnIDshyWTUI/AAAAAAAAEIs/4OujSQNdQSY/s400/history-js-log.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/balupton/history.js"&gt;history.js&lt;/a&gt; を使ってブラウザの履歴を管理しました。
サーバーサイドから JSON を送るだけにしてしまうと「ページ」という概念が希薄になりがちですので
「戻る」「進む」が思い通りにいかないことが多々あります。
その解決策として &lt;tt class="docutils literal"&gt;pushState()&lt;/tt&gt; はとても良い方法だと思います。&lt;/p&gt;
&lt;p&gt;サーバーサイドで HTML を生成する場合には HTTP の拡張ヘッダーを組み合わせて使う応用もあります。
jQuery Mobile でも使われるらしいので、ちょっと知っておくと良さそうです。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/defunkt/jquery-pjax"&gt;jquery-pjax&lt;/a&gt; - github.com&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://pjax.heroku.com/"&gt;pjax&lt;/a&gt; - heroku.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;自分で Web アプリケーションを作る、という視点では PJAX の方が良いかもしれませんが、
Solr などの JSON ライターが存在するアプリケーションと組み合わせる場合には
&lt;tt class="docutils literal"&gt;window.history&lt;/tt&gt; を管理する方法は有用そうですね。&lt;/p&gt;
&lt;div class="section" id="id4"&gt;
&lt;h2&gt;おまけ&lt;/h2&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;history.js&lt;/tt&gt; にはアダプタが登場しましたが、
JavaScript におけるデザインパターンや実装パターンは英語の記事だとよくまとまっています
(日本語の記事は特に調べていませんが)。
サーバーサイド JavaScript でも基本的なパターンは押さえておくべきなので、
何らかのプログラムを書くなら一読しておくべきなのかな、と。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://addyosmani.com/resources/essentialjsdesignpatterns/book/"&gt;Essential JavaScript Design Patterns For Beginners, Volume 1.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://ajaxpatterns.org/"&gt;AjaxPatterns&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;また、多様なパターンを覚えておくと非同期処理もすっきり記述できるかもしれませんね。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://blogs.msdn.com/b/ie/archive/2011/09/11/asynchronous-programming-in-javascript-with-promises.aspx"&gt;Asynchronous Programming in JavaScript with &amp;quot;Promises&amp;quot;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-2707005819266240789?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/2707005819266240789/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=2707005819266240789' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/2707005819266240789'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/2707005819266240789'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/09/html5-history-api.html' title='History API を使ってみる'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-j50hEsdaV2o/TnIDshyWTUI/AAAAAAAAEIs/4OujSQNdQSY/s72-c/history-js-log.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-171491039176928234</id><published>2011-09-12T23:28:00.003+09:00</published><updated>2011-09-12T23:28:58.564+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Solr'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>第６回 Solr 勉強会に行ってきた</title><content type='html'>
&lt;div style="float: right; margin: 10px;"&gt;
&lt;iframe src="http://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&amp;bc1=000000&amp;IS2=1&amp;bg1=FFFFFF&amp;fc1=000000&amp;lc1=0000FF&amp;t=kshigeru-22&amp;o=9&amp;p=8&amp;l=as4&amp;m=amazon&amp;f=ifr&amp;ref=ss_til&amp;asins=1849516065" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;
&lt;/div&gt;&lt;p&gt;Solr の勉強会に行ってきました。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://atnd.org/events/18637"&gt;第6回Solr勉強会&lt;/a&gt; - atnd.org&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://twitter.com/#!/search/solrjp"&gt;#SolrJP&lt;/a&gt; - twitter.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ので、そのメモ。&lt;/p&gt;
&lt;p&gt;会場を提供してくださった ECナビさん、運営者の方々、ありがとうございました。&lt;/p&gt;
&lt;p&gt;思ったよりも利用事例って多いんだなぁ、というのが雑感です。
とはいえ、解析関係の話はまだ目新しい様子なので、
検索ログを Hadoop に突っ込んでデータマイニングしたらこんなことが改善された、
という流れが増えてくると嬉しいのかなぁ、と。
問題はマイニングの結果に何を求めるかが曖昧ってことだったりしますけど。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="id2"&gt;
&lt;h1&gt;発表とか&lt;/h1&gt;
&lt;div class="section" id="id3"&gt;
&lt;h2&gt;ロンウイット 関口 宏司さん&lt;/h2&gt;
&lt;p&gt;Lucene/Solr 3.2 から 3.4 辺りの話題です。
3.4 では電源断によるデグレ改修が大きなトピックらしいので、
3.4 が出たら 3.3 以前のバージョンは使わないようにしましょう、とのことです。&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;IndexWriter.addDocuments&lt;/tt&gt; という &lt;cite&gt;s&lt;/cite&gt; が付いた複数形の API が追加されました。
コレクションを追加できるようになったのは嬉しいかもしれませんね。&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;TieredMergePolicy&lt;/cite&gt; で文書の親子関係を定義できるようになります。
マージするアルゴリズムに変更があったそうなので、
ドキュメントの登録順に依存しているアプリケーションがある場合は要注意だそうな。
ドキュメントをマージする様子はこちらのブログに掲載されているビデオが分かりやすいと思います。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://blog.mikemccandless.com/2011/02/visualizing-lucenes-segment-merges.html"&gt;Visualizing Lucene's segment merges&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;検索対象はすべてをインデクスに保存しておかなくても良いようで、
&lt;tt class="docutils literal"&gt;ExternalFileField&lt;/tt&gt; を使うと外部ファイルで管理された内容から関数クエリなどを実行できるそうです。
インデクス更新いらずなので、負荷軽減に役立つかも。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://lucene.apache.org/solr/api/org/apache/solr/schema/ExternalFileField.html"&gt;ExternalFileField&lt;/a&gt; (javadoc)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;PathHierarcyTokenize&lt;/tt&gt; はファイルパスなどを分割するためのトークナイザーですが、
分割したトークンを逆順に返すような &lt;tt class="docutils literal"&gt;ReversePathHierarcyTokenize&lt;/tt&gt; が追加されたそうです。
パスで分割するイメージはこちらのブログ記事が分かりやすい感じ。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://t.co/9JExoTT"&gt;Path Hierarchy Tokenizer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;あと、クラスタリングするためのソフトウェアとして &lt;a class="reference external" href="http://project.carrot2.org/"&gt;Carrot2&lt;/a&gt; があります。
検索システムが大規模かつ複雑になってくると役立ちそうですね。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="penguinana-solr-cookpad"&gt;
&lt;h2&gt;＠PENGUINANA_ さん Solr＠cookpad&lt;/h2&gt;
&lt;p&gt;Cookpad での事例紹介でした。
人気順の検索などだけでなく、社内ツールでも使ってるそうです。
３ヶ月くらいで Tritonn からフルスクラッチで移行したとのこと。
なんと Solr 4 nightly を使って。。。&lt;/p&gt;
&lt;p&gt;Cookpad には Ruby 開発者が多いので、バッチ処理はすべて Ruby で記述するそうです。
社内の共通言語だから他の人から意見をもらいやすいんだとか。
Analyzer を自作する場合は Java で実装する必要がありますが、
分かち書き、正規化、同義語展開を事前に Ruby バッチで処理しているそうです。&lt;/p&gt;
&lt;p&gt;運用面では、 &lt;a class="reference external" href="http://t.co/YpPphKx"&gt;munin&lt;/a&gt; でキャッシュのヒット率などをコア別に監視しています。
グラフ化されているとパッと見でもなんとなく分かりやすいですね。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;クエリ: QTime / QPS&lt;/li&gt;
&lt;li&gt;キャッシュ: hit / eviction&lt;/li&gt;
&lt;li&gt;インデクス: サイズ / ドキュメント数&lt;/li&gt;
&lt;li&gt;レプリケーションの所用時間&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Solr はインデクスだけを保存する、というポリシーのようです。
それぞれのスキーマで &lt;tt class="docutils literal"&gt;indexed=true&lt;/tt&gt; と &lt;tt class="docutils literal"&gt;stored=false&lt;/tt&gt; を設定しているため、
ファイルサイズが小さくなり、リプリケーションの高速化に寄与するそうです。
本文情報は MySQL から取得すれば良いので、確かに合理的な感じです。&lt;/p&gt;
&lt;p&gt;ある検索語句にヒットするドキュメントがインデクスに存在するかを確認するためには、
Bloom Filter のコンポーネント (&lt;a class="reference external" href="http://wiki.apache.org/solr/BloomIndexComponent"&gt;BloomIndexComponent&lt;/a&gt;) があります。
何かの機会に知っておくと良さそう。&lt;/p&gt;
&lt;p&gt;その他にも、Cookpad では本番環境で複数のバージョンを持つ仕組みを用意してありますので、
実際のデータを使って新しい手法をタイムリーに検証できるみたいです。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://techlife.cookpad.com/2011/07/15/extension-framework/"&gt;どんどん使う – Extension Frameworkの紹介&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h2&gt;発表いろいろ&lt;/h2&gt;
&lt;p&gt;その他にも充実した内容の発表でした。
詳しい内容は後日に資料が公開されることでしょう。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;データセクション株式会社 高井さん&lt;/li&gt;
&lt;li&gt;&amp;#64;takahi-i さん - mixi での検索システムなど&lt;/li&gt;
&lt;li&gt;&amp;#64;yutakashino さん – solrとRの連携について&lt;/li&gt;
&lt;li&gt;阿部さん – Apache ManifoldCF&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;mixi では先月から検索システムに Solr を投入したそうですが、
こうした複数台の Solr サーバと大量のインデクスデータを管理するために Anuenue が作られたようです。
ナレッジの蓄積と人材の流動性を天秤にかけると、内製検索エンジンから OSS に移行する事例は増えるのかなぁと
ぼんやり思いました。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://t.co/0c1Xekz"&gt;Apache Solr を利用した検索パッケージ Anuenue&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://t.co/gy18RsV"&gt;THEY TYPE IT HOW? ANUENUE, MIXI, AND THE DIFFICULTIES IN JAPANESE SPELL-CHECK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Solr にはファセット検索機能も組み込まれていますので、
多様なシステムと結合していくことも可能だと思います。
プラグインで拡張していく方法、解析用ツールにデータを流す手法、
サーバーサイドで手数をかけずに何らかの表示をさせる方法など、応用事例はたくさん出てきそうですね。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;&lt;a class="reference external" href="http://linkedin.jira.com/wiki/display/BOBO/Bobo+Solr+Plugin"&gt;Bobo Solr Plugin&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;&lt;p class="first last"&gt;Bobo, being a Lucene extension for structured data, can be exposed thru the Solr facet interface.&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;&lt;a class="reference external" href="http://t.co/cV2Dwa2"&gt;ManifoldCF&lt;/a&gt;&lt;/dt&gt;
&lt;dd&gt;&lt;p class="first last"&gt;会社の中にある文書サーバからセキュリティ情報を維持してクローリングできる。ACL も考慮。&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;a class="reference external" href="http://t.co/Dd5PQhx"&gt;SolrCloud&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;&lt;a class="reference external" href="http://evolvingweb.github.com/ajax-solr/"&gt;ajax-solr&lt;/a&gt; (Solr の JavaScript ライブラリ)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-171491039176928234?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/171491039176928234/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=171491039176928234' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/171491039176928234'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/171491039176928234'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/09/solr-study-6.html' title='第６回 Solr 勉強会に行ってきた'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-1837110367289169321</id><published>2011-09-06T21:51:00.000+09:00</published><updated>2011-09-06T21:51:21.469+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Waf'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Waf と YUI Compressor で静的ファイルを圧縮する</title><content type='html'>
&lt;p&gt;Waf を使って JavaScript と CSS を探し、YUI Compressor の引数に渡すことで
静的ファイルを圧縮します。&lt;/p&gt;
&lt;p&gt;Apache Ant で YUI Compressor を使う方法は、次の英語の記事で網羅的に説明されています。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;dl class="first docutils"&gt;
&lt;dt&gt;&lt;a class="reference external" href="http://www.julienlecomte.net/blog/2007/09/16/"&gt;Building Web Applications With Apache Ant&lt;/a&gt; - Julien Lecomte's Blog&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="first last simple"&gt;
&lt;li&gt;Apache Ant&lt;/li&gt;
&lt;li&gt;Build types - 開発用、検証用、製品用に分けてビルドする&lt;/li&gt;
&lt;li&gt;Concatenate your JavaScript and CSS files - 順番を意識してファイル内容を結合する&lt;/li&gt;
&lt;li&gt;Preprocess your JavaScript files using CPP - C のプリプロセッサを使って条件付きビルドを実現する&lt;/li&gt;
&lt;li&gt;Minify your JavaScript and CSS files - &lt;tt class="docutils literal"&gt;yuicompressor.jar&lt;/tt&gt; を使って JavaScript と CSS を圧縮する&lt;/li&gt;
&lt;li&gt;Work around caching issues - 変更のないファイルをキャッシュするためのテクニック&lt;/li&gt;
&lt;li&gt;Deploy your application - サーバーにファイルを転送し、サービスを再起動する&lt;/li&gt;
&lt;li&gt;Conclusion - みんながビルドプロセスを考慮すべき&lt;/li&gt;
&lt;/ul&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;この記事では &lt;tt class="docutils literal"&gt;yuicompressor.jar&lt;/tt&gt; の使い方の部分だけを取り上げます。
なお、Python 関連では &lt;cite&gt;buildout&lt;/cite&gt; も使えます。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://blog.toms-projekte.de/?p=33"&gt;Minifying JavaScript and CSS with buildout&lt;/a&gt; (英語のブログ)&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;div class="section" id="id1"&gt;
&lt;h1&gt;インストール&lt;/h1&gt;
&lt;p&gt;まずはいくつかのファイルをインストールします。
virtualenv を使って Waf を利用可能にし、JAR ファイルを配置します。
PyPI に &lt;a class="reference external" href="http://pypi.python.org/pypi/yuicompressor"&gt;yuicompressor 2.4.6.1&lt;/a&gt; がありますので &lt;tt class="docutils literal"&gt;pip&lt;/tt&gt; で JAR ファイルもインストールできます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ virtualenv --distribute yuicompress-test
$ cd $_
$ source bin/activate
$ curl http://waf.googlecode.com/files/waf-1.6.7 &amp;gt;bin/waf
$ chmod +x bin/waf
$ pip install yuicompressor
$ find . -name yuicompressor\* -type f
./bin/yuicompressor
./lib/python2.7/site-packages/yuicompressor/yuicompressor.jar
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;bin/yuicompressor&lt;/tt&gt; というコマンドがインストールされます。
これは &lt;tt class="docutils literal"&gt;yuicompressor.jar&lt;/tt&gt; ファイルへのラッパースクリプトになっています。
事前条件として、実行環境には Java がインストールされている必要があります。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h1&gt;入出力ファイルの確認&lt;/h1&gt;
&lt;p&gt;&lt;cite&gt;static&lt;/cite&gt; というディレクトリにふたつのファイル - &lt;tt class="docutils literal"&gt;script.js&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;style.css&lt;/tt&gt; - を置きます。
これらのファイルを圧縮し、ビルドディレクトリに出力します。
このとき、圧縮した結果は拡張子の前に &amp;quot;-min&amp;quot; を付けたファイルに出力します。&lt;/p&gt;
&lt;div class="section" id="id3"&gt;
&lt;h2&gt;サンプルの準備&lt;/h2&gt;
&lt;p&gt;まずはサンプルファイルを準備します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ mkdir static
$ touch $_/script.js $_/style.css
$ ls static
script.js  style.css
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="ant-glob-change-ext"&gt;
&lt;h2&gt;ant_glob() と change_ext()&lt;/h2&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;ant_glob()&lt;/tt&gt; を使って、拡張子が &lt;cite&gt;.js&lt;/cite&gt; か &lt;cite&gt;.css&lt;/cite&gt; に一致するファイルを探します。
結果はリストとして取得できますので、ループを回してファイルを処理します。
このとき、 &lt;tt class="docutils literal"&gt;change_ext()&lt;/tt&gt; を使ってファイル名を変更します。&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="prettyprint lang-py literal-block"&gt;
APPNAME = 'yuicompress-test'
VERSION = '1.0.0'

top = '.'
out = '_build'

def configure(ctx):
    ctx.find_program('yuicompressor')

def build(bld):
    assets = bld.path.ant_glob(['**/*.js', '**/*.css'])
    for src in assets:
        dst = src.change_ext('-min' + src.suffix())
        print &amp;quot;%s\n\t-&amp;gt; %s&amp;quot; % (src.abspath(), dst.abspath())
&lt;/pre&gt;
&lt;p&gt;実行すると次のようになります。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ waf configure build
Setting top to                           : /private/tmp/yuicompress-test
Setting out to                           : /private/tmp/yuicompress-test/_build
Checking for program yuicompressor       : /private/tmp/yuicompress-test/bin/yuicompressor
'configure' finished successfully (0.004s)
Waf: Entering directory `/private/tmp/yuicompress-test/_build'
/private/tmp/yuicompress-test/static/script.js
        -&amp;gt; /private/tmp/yuicompress-test/_build/static/script-min.js
/private/tmp/yuicompress-test/static/style.css
        -&amp;gt; /private/tmp/yuicompress-test/_build/static/style-min.css
Waf: Leaving directory `/private/tmp/yuicompress-test/_build'
'build' finished successfully (0.059s)
&lt;/pre&gt;
&lt;p&gt;ループを回すのではなく、拡張子に対してルールを設定することもできます。
この方が依存関係の解析が早くなるから、、、か確証はありませんが、きっと高速なはずです。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://waf.googlecode.com/svn/docs/wafbook/single.html#_name_and_extension_based_file_processing"&gt;8.2. Name and extension-based file processing&lt;/a&gt; - Waf book&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="yui-compressor"&gt;
&lt;h1&gt;YUI Compressor の実行&lt;/h1&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;yuicompressor&lt;/tt&gt; コマンドを引数なしで実行すると、使い方が表示されます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ yuicompressor

Usage: java -jar yuicompressor-x.y.z.jar [options] [input file]

Global Options
  -h, --help                Displays this information
  --type &amp;lt;js|css&amp;gt;           Specifies the type of the input file
  --charset &amp;lt;charset&amp;gt;       Read the input file using &amp;lt;charset&amp;gt;
  --line-break &amp;lt;column&amp;gt;     Insert a line break after the specified column number
  -v, --verbose             Display informational messages and warnings
  -o &amp;lt;file&amp;gt;                 Place the output into &amp;lt;file&amp;gt;. Defaults to stdout.
                            Multiple files can be processed using the following syntax:
                            java -jar yuicompressor.jar -o '.css$:-min.css' *.css
                            java -jar yuicompressor.jar -o '.js$:-min.js' *.js

JavaScript Options
  --nomunge                 Minify only, do not obfuscate
  --preserve-semi           Preserve all semicolons
  --disable-optimizations   Disable all micro optimizations

If no input file is specified, it defaults to stdin. In this case, the 'type'
option is required. Otherwise, the 'type' option is required only if the input
file extension is neither 'js' nor 'css'.
&lt;/pre&gt;
&lt;p&gt;最後の部分を日本語に訳してみると次のような感じでしょうか。&lt;/p&gt;
&lt;blockquote&gt;
入力ファイルが指定されないと標準入力から読み取ります。
この場合は、 'type' オプションは必須です。
そうでなければ、入力ファイルの拡張子が 'js' でも 'css' でもない場合に限り、
'type' オプションは必須です。&lt;/blockquote&gt;
&lt;p&gt;ということで拡張子を気にする必要はありませんので、コマンドラインから次のように実行します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ yuicompressor static/script.js &amp;gt;_build/static/script-min.js
$ yuicompressor static/style.css &amp;gt;_build/static/style-min.css
&lt;/pre&gt;
&lt;p&gt;もしくは、 &lt;cite&gt;-o&lt;/cite&gt; オプションを使って出力先を指定します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ yuicompressor -o _build/static/script-min.js static/script.js
$ yuicompressor -o _build/static/style-min.css static/style.css
&lt;/pre&gt;
&lt;p&gt;&lt;cite&gt;-o&lt;/cite&gt; オプションにはマクロのような機能もありますので、
複数ファイルを一括で指定することもできるそうです。&lt;/p&gt;
&lt;div class="section" id="waf"&gt;
&lt;h2&gt;Waf で実行させる&lt;/h2&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt; に独自のタスクを定義できますので、
先ほどのルールを参考にしてタスククラスを書きます。&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt; にまとめると、次のようになります。&lt;/p&gt;
&lt;pre class="prettyprint lang-py literal-block"&gt;
APPNAME = 'yuicompress-test'
VERSION = '1.0.0'

top = '.'
out = '_build'


def configure(ctx):
    ctx.find_program('yuicompressor')


from waflib.Task import Task

class yuicompressor(Task):
    def run(self):
        return self.exec_command('yuicompressor %s &amp;gt;%s' % (
                self.inputs[0].abspath(), self.outputs[0].abspath()
            ))


def build(bld):
    assets = bld.path.ant_glob(['**/*.js', '**/*.css'])
    for src in assets:
        dst = src.change_ext('-min' + src.suffix())
        t = yuicompressor(env=bld.env)
        t.set_inputs(src)
        t.set_outputs(dst)
        bld.add_to_group(t)


&lt;/pre&gt;
&lt;p&gt;適当なスクリプトとスタイルシートを書いてから実行してみます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ waf distclean configure build
'distclean' finished successfully (0.002s)
Setting top to                           : /private/tmp/yuicompress-test
Setting out to                           : /private/tmp/yuicompress-test/_build
Checking for program yuicompressor       : /private/tmp/yuicompress-test/bin/yuicompressor
'configure' finished successfully (0.004s)
Waf: Entering directory `/private/tmp/yuicompress-test/_build'
[1/2] yuicompressor: static/script.js -&amp;gt; _build/static/script-min.js
[2/2] yuicompressor: static/style.css -&amp;gt; _build/static/style-min.css
Waf: Leaving directory `/private/tmp/yuicompress-test/_build'
'build' finished successfully (0.811s)
&lt;/pre&gt;
&lt;p&gt;生成されたファイルを比較してみると、次のようになります。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ ls -l static/ _build/static/ |
    awk 'NF == 9 { printf &amp;quot;%-20s -&amp;gt; %5d (bytes)\n&amp;quot;, $9, $5; }' |
    sort -r
style.css            -&amp;gt;  1621 (bytes)
style-min.css        -&amp;gt;  1422 (bytes)
script.js            -&amp;gt;   357 (bytes)
script-min.js        -&amp;gt;   215 (bytes)
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h2&gt;注意&lt;/h2&gt;
&lt;p&gt;YUI Compressor を実行すると、解読できない構文エラーが報告されることがあります。
ソースコードのエラーかもしれませんが、YUI Compressor 側のバグかもしれませんので注意が必要です。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://yuilibrary.com/projects/yuicompressor/ticket/2528116"&gt;Reserved words are still valid property names&lt;/a&gt; - yuilibrary.com&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;簡単に空白などを取り除きたい場合は、 JSMin の方が分かりやすいかもしれませんね。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;Waf を使って JavaScript と CSS を圧縮しました。
Ant でいいんじゃないの？と思った場合は、Ant の方が良いでしょうね。
Waf を使うメリットは Python ですべてを記述できることです。
Ant だと XML でルールを書きますが、独自のタスクを定義する場合には Java のクラスを実装する必要があります。
この辺の好きずきかな、と思いました。&lt;/p&gt;
&lt;p&gt;文脈は異なっても、処理系のことはあまり気にせず文法などで選びましょう、
という流れは今後も加速するはずですから、色々と知っておいた方が良いのかな、というのが基本となる動機です。&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://blog.heroku.com/archives/2011/8/25/java/"&gt;Heroku for Java&lt;/a&gt; :&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;A common deployment infrastructure reduces language choice to just a question of syntax and libraries.&amp;quot;&lt;/p&gt;
&lt;p&gt;ソフトウェアを動かすためのインフラが汎化されると、
プログラミング言語の選択は構文とライブラリを選ぶだけの問題になります。
(Java だから特定のベンダーサポートがあって ... という話は意味をなさない)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;なお、 &lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt; のタスクに依存関係を持たせる方法はこちらにも書いています。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/08/waf-validate-and-copy.html"&gt;Waf を使って構文チェックしてからコピーする&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-1837110367289169321?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/1837110367289169321/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=1837110367289169321' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/1837110367289169321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/1837110367289169321'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/09/waf-static-compress.html' title='Waf と YUI Compressor で静的ファイルを圧縮する'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-2821551813543017796</id><published>2011-09-04T16:50:00.002+09:00</published><updated>2011-09-04T16:51:55.284+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='生活'/><title type='text'>プロフェッショナルの条件 - 転職</title><content type='html'>
&lt;div style="float: right; margin: 10px;"&gt;
&lt;iframe src="http://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&amp;bc1=000000&amp;IS2=1&amp;bg1=FFFFFF&amp;fc1=000000&amp;lc1=0000FF&amp;t=kshigeru-22&amp;o=9&amp;p=8&amp;l=as4&amp;m=amazon&amp;f=ifr&amp;ref=ss_til&amp;asins=4478300593" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;
&lt;/div&gt;&lt;p&gt;ドラッカーの「プロフェッショナルの条件」という本を読んでいます。
2000年に出版された書籍ですが、「はじめに」の部分にこんな記述があります。&lt;/p&gt;
&lt;blockquote&gt;
1950年代、1960年代のアメリカでは、パーティで会った人に何をしているかを聞けば、
... (省略) ... 雇用主たる組織の名前が返ってきた。
当時のアメリカは今日の日本と同じだった。
... (省略) ...
ところが今日、アメリカでは「冶金学者です」「税務をやっています」「ソフトウェアの設計です」
と答えが返ってくる。
少なくともアメリカでは、知識労働者は、もはや自らのアイデンティティを雇用主たる組織に求めなくなっており、
専門領域への帰属意識をますます強めている。
今日では日本においてさえ、若い人たちが同じ傾向にある。&lt;/blockquote&gt;
&lt;a name='more'&gt;&lt;/a&gt;&lt;p&gt;出版から10年以上が経過していますので、この傾向はより顕著になっているように思います。
なお、知識労働と言っても色々な種類がありますが、
物理的な機器に依存しない人は特にこの傾向が強いのかな、と感じます。
実験機材の購入に数億円が必要な研究領域では組織への依存度が高いでしょうし、
手術の執刀のように属人性が高い領域では個人への依存が高くなるでしょう。&lt;/p&gt;
&lt;p&gt;自分が中学生だったときの国語の教科書 (出版社は忘れた) に「転石苔を生じず」という諺に関する文章がありました。
「苔」を捉える感覚が異なると諺のニュアンスも変わってしまう、という趣旨の内容だったと思います。
確か、日本人とイギリス人の対比だったはずです。
苔の美的価値を高く捉えれば石を転がさない方が良いでしょうし、
その逆であれば石は転がし続けた方が良いでしょう。&lt;/p&gt;
&lt;div class="section" id="id2"&gt;
&lt;h1&gt;転職&lt;/h1&gt;
&lt;p&gt;何の脈絡もありませんが、ソフトウェア開発者の場合は雇用主にアイデンティティを求める必然性もない、
ということで、６月に転職して、数日前に無事に試用期間も終わりました。
たまには神宮外苑を歩いて通勤するのも悪くないなぁ、と思います。&lt;/p&gt;
&lt;p&gt;実際に転職してみると、定期的な自己評価の必要性を実感します。
多くの会社では年に一度、あるいは半期や四半期に一度は社内の誰かと面談があるでしょうが、
それ以外にも、自分自身が何ができて何ができていないかを考えてみる良い機会でした。
これが整理されていないと、転職活動という側面では職務経歴書を作成できませんし、
通常の業務においてもジリ貧になってしまうでしょう。
10年ひとむかし、と言われることも多いですから、昔取ったなんとやらでは立ち行かなくなっていきます。
プログラマ35歳定年説？の一因もそこにあると考えています。&lt;/p&gt;
&lt;p&gt;「プロ」という軸で考えると、サッカー選手だったら練習以外でもどこかの試合を観るでしょうし、
食事などにも気をつけるでしょう。
同じように、プロ意識に程度の違いこそあれ、知識労働者だったら業務時間以外でも
知識を蓄積/活用する方法を模索すべきだと言えます。
つまり、専門領域への帰属意識をますます強めていくことが、ひとつの競争戦略になります。&lt;/p&gt;
&lt;p&gt;さて、ジョン・F・ケネディのことばに次のようなものがあります。
会社においても個々人が自立しなければならない、とも言えますね。&lt;/p&gt;
&lt;blockquote&gt;
Ask not what your country can do for you, but ask what you can do for your country.&lt;/blockquote&gt;
&lt;p&gt;自分の場合は転職の前も後もソフトウェア開発者ですが、
新しい仕事ではバッチ処理や自然言語処理が必要になりそうです。
ここ数年で実用例が多数紹介され始めた分野です。
業務では使わなそうだけど周辺情報として知っておいた方が良いことはブログにメモしておこうかな、と思います。&lt;/p&gt;
&lt;p&gt;(「業務で知り得た内容」は書きませんので、相変わらずニッチな話が多そうですが)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-2821551813543017796?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/2821551813543017796/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=2821551813543017796' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/2821551813543017796'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/2821551813543017796'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/09/essential-drucker-on-individuals.html' title='プロフェッショナルの条件 - 転職'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-8903276804755361227</id><published>2011-08-30T21:05:00.001+09:00</published><updated>2011-08-30T21:09:06.603+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>JavaScriptMVC +α</title><content type='html'>&lt;p&gt;JavaScriptMVC 以外に、いくつかのリンクをメモしておきます。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;
&lt;div class="section" id="yui-app-framework"&gt;
&lt;h1&gt;YUI App Framework&lt;/h1&gt;
&lt;p&gt;Yahoo の JavaScript ライブラリ - YUI - も
バージョン 3.4.0 から MVC フレームワークを用意し始めました。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.yuiblog.com/blog/2011/08/18/announcing-yui-3-4-0-and-the-new-yuilibrary-com/"&gt;Announcing YUI 3.4.0 and the new YUILibrary.com&lt;/a&gt; - yuiblog.com&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://yuilibrary.com/yui/docs/app/"&gt;App Framework&lt;/a&gt; - API Document&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;YUI を使っている場合には、選択肢のひとつとして挙がってくるでしょう。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="html5-boilerplate"&gt;
&lt;h1&gt;HTML5 Boilerplate&lt;/h1&gt;
&lt;p&gt;何事にもひな形があった方が便利です。
HTML5 Boilerplate は、基本的な HTML / JavaScript / CSS を提供してくれます。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://html5boilerplate.com/"&gt;HTML5 Boilerplate&lt;/a&gt; (本家)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://jp.html5boilerplate.com/"&gt;HTML5 Boilerplate 日本語訳&lt;/a&gt; (日本語訳)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://css.studiomohawk.com/tool/2011/03/15/html5boilerplate/"&gt;HTML5 Boilerplate - CSS Radar&lt;/a&gt; (紹介記事)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.ibm.com/developerworks/jp/web/library/wa-html5boilerplate/"&gt;HTML5 Boilerplate を使用して Web 開発を容易に始める&lt;/a&gt; (IBM developerWorks)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="html-javascript-css"&gt;
&lt;h1&gt;HTML / JavaScript / CSS&lt;/h1&gt;
&lt;p&gt;端末やブラウザーによって表現を揃えるか分離するかは難しいところです。
jQuery Conference の Nicholas Zakas の発表がひとつの指標となるかもしれません。&lt;/p&gt;
&lt;dl class="docutils"&gt;
&lt;dt&gt;&lt;a class="reference external" href="http://www.slideshare.net/nzakas/progressive-enhancement-20"&gt;Progressive Enhancement 2.0&lt;/a&gt; - slideshare.net&lt;/dt&gt;
&lt;dd&gt;&lt;p class="first"&gt;&amp;quot;An escalator can never break; it can only become stairs.&amp;quot;
- Mitch Hedberg&lt;/p&gt;
&lt;p class="last"&gt;エスカレーターは決して壊れない。単なる階段になるだけだ。&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;また、Web ページのメタファーは印刷媒体ではなくテレビだとも主張しています。
無理なく無駄なく最新技術を取り入れることができると嬉しいですね。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Old browsers are like black &amp;amp; white TVs. New browsers are like HD TVs.&amp;quot;&lt;/p&gt;
&lt;p&gt;古いブラウザは白黒テレビのようなもので、新しいのは HD テレビのようなものだ。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div style="float: right; margin: 10px;"&gt;
&lt;iframe src="http://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&amp;bc1=000000&amp;IS2=1&amp;bg1=FFFFFF&amp;fc1=000000&amp;lc1=0000FF&amp;t=kshigeru-22&amp;o=9&amp;p=8&amp;l=as4&amp;m=amazon&amp;f=ifr&amp;ref=ss_til&amp;asins=059680279X" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;このため:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Your site SHOULD look different in different browsers.&amp;quot;&lt;/p&gt;
&lt;p&gt;サイトは異なるブラウザでは違って見えるべきだ。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;コンテンツと視聴端末は別々に考えるべきことだからです。&lt;/p&gt;
&lt;p&gt;なお、Nicholas Zakas さんは &amp;quot;High Performance JavaScript&amp;quot; の著者です。
書籍は日本語にも翻訳されていますので、最近の JavaScript 事情 (と言っても発売は去年なので一昨年くらいの事情)
を一通り眺めるにはとても良い本だと思います。
(自分が読んだときのメモ書き - &lt;a class="reference external" href="http://skitazaki.appspot.com/works/doc/high-performance-javascript.html"&gt;Books - High Performance JavaScript&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;その他に、CSS の使い方や各種のパフォーマンスについては下記の二点も良さそうです。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.slideshare.net/dcneiner/presentational-jquery-7671131"&gt;Presentational jQuery&lt;/a&gt; - slideshare.net : CSS の使い方&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.facebook.com/video/video.php?v=696729990595"&gt;Building with HTML5 Tech Talk&lt;/a&gt; (Facebook Engineering のビデオ)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-8903276804755361227?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/8903276804755361227/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=8903276804755361227' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/8903276804755361227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/8903276804755361227'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc-5.html' title='JavaScriptMVC +α'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-7019305683804856456</id><published>2011-08-29T21:41:00.001+09:00</published><updated>2011-08-29T21:43:25.667+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>JavaScriptMVC でパッケージング</title><content type='html'>&lt;p&gt;JavaScriptMVC で作成したアプリケーションの配布パッケージを作成します。&lt;/p&gt;
&lt;p&gt;一連の記事の最後になります。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc.html"&gt;JavaScriptMVC - 概要&lt;/a&gt; (2011年8月25日)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc-1.html"&gt;JavaScriptMVC を使ってみる&lt;/a&gt; (2011年8月26日)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc-2.html"&gt;JavaScriptMVC でテストを実行&lt;/a&gt; (2011年8月27日)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc-3.html"&gt;JavaScriptMVC でドキュメントを生成&lt;/a&gt; (2011年8月28日)&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;
&lt;div class="section" id="id5"&gt;
&lt;h1&gt;ビルドする&lt;/h1&gt;
&lt;p&gt;StealJS の &lt;tt class="docutils literal"&gt;build.js&lt;/tt&gt; を使ってソースコードを圧縮、結合します。
依存性は StealJS が解決し、内部的には Closure Compiler を使います。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ ./js cookbook/scripts/build.js
Building to cookbook/

BUILDING SCRIPTS ---------------
steal.compress - Using Google Closure app
   steal/steal.js
   ignoring ../steal/dev/dev.js
   cookbook/cookbook.js
   jquery/model/model.js
   jquery/class/class.js
   jquery/jquery.js
   jquery/lang/lang.js
   jquery/view/ejs/ejs.js
   jquery/view/view.js
   jquery/lang/rsplit/rsplit.js
   cookbook/models/recipe.js
   steal/less/less.js
   ignoring ../steal/less/less_engine.js

SCRIPT BUNDLE &amp;gt; cookbook/production.js

BUILDING STYLES ---------------
text/less
../cookbook/resources/example.less

STYLE BUNDLE &amp;gt; cookbook/production.css
Nice! Compressed: 27.1%  Before: 118.0 bytes  After: 86.0 bytes
&lt;/pre&gt;
&lt;p&gt;JavaScript は &lt;tt class="docutils literal"&gt;production.js&lt;/tt&gt; 、CSS は &lt;tt class="docutils literal"&gt;production.css&lt;/tt&gt; にまとめられました。
&lt;tt class="docutils literal"&gt;cookbook.html&lt;/tt&gt; から読み込む JavaScript を変更することで、
開発版と製品版を切り替えられます。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id6"&gt;
&lt;h1&gt;ファイルをコピーする&lt;/h1&gt;
&lt;p&gt;適当な Web サーバーに JavaScriptMVC のフォルダを丸ごとコピーすれば動作しますが、
製品版には不要なファイルが多いことも事実です。
そこで、動作に必要なファイルだけをコピーします。&lt;/p&gt;
&lt;p&gt;「必要なファイル」は次のものになります。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;起動ファイル - &lt;tt class="docutils literal"&gt;steal.production.js&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;アプリケーション - &lt;tt class="docutils literal"&gt;cookbook.html&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;production.js&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;production.css&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;テンプレートファイル - 各種 &lt;cite&gt;.ejs&lt;/cite&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;適当なディレクトリに次の構成でコピーします。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ tree
.
├── cookbook
│&amp;nbsp;&amp;nbsp; ├── cookbook.html
│&amp;nbsp;&amp;nbsp; ├── production.css
│&amp;nbsp;&amp;nbsp; ├── production.js
│&amp;nbsp;&amp;nbsp; └── views
│&amp;nbsp;&amp;nbsp;     └── recipe
│&amp;nbsp;&amp;nbsp;         ├── edit.ejs
│&amp;nbsp;&amp;nbsp;         ├── init.ejs
│&amp;nbsp;&amp;nbsp;         ├── list.ejs
│&amp;nbsp;&amp;nbsp;         └── show.ejs
└── steal.production.js

3 directories, 8 files
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="id7"&gt;
&lt;h1&gt;パッケージにまとめる&lt;/h1&gt;
&lt;p&gt;HTML で JavaScript を読み込む部分を修正します。
&lt;tt class="docutils literal"&gt;steal.js&lt;/tt&gt; ではなく、 &lt;tt class="docutils literal"&gt;steal.production.js&lt;/tt&gt; を読み込ませます。
ディレクトリ構成を変更していますので、 &lt;cite&gt;steal&lt;/cite&gt; というディレクトリ名を取り除きます。&lt;/p&gt;
&lt;pre class="prettyprint lang-html literal-block"&gt;
&amp;lt;script type='text/javascript'
        src='../steal.production.js?cookbook'&amp;gt;
&amp;lt;/script&amp;gt;
&lt;/pre&gt;
&lt;p&gt;あとは ZIP アーカイブなどにまとめます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ zip -r cookbook-0.0.1.zip steal.production.js cookbook
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="id8"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;開発した JavaScript ファイルなどをパッケージングしました。
このフェーズで CoffeeScript と LESS はコンパイルされますので、
実行時のオーバーヘッドは少なくなります。
出来上がったファイル群を ZIP に固めることで、簡単に他のホストに配布できます。&lt;/p&gt;
&lt;p&gt;JavaScriptMVC の紹介はこれでおしまいです。
ベースにした英語のドキュメントはこちらです。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://javascriptmvc.com/docs.html#&amp;amp;who=getstarted"&gt;Get Started&lt;/a&gt; - javascriptmvc.com&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&amp;quot;cookbook&amp;quot; という小さなアプリケーションを作る過程で、
JavaScriptMVC の主要な理念に触れてきました。
コードの分離、テスト、圧縮、そしてドキュメンテーションです。
何もないところから、圧縮されてテストされ、そしてドキュメントも備わったアプリケーションにたどり着いたのです。
この道のりがどんなにシンプルだったか振り返ってみると本当に素晴らしいですね。&lt;/blockquote&gt;
&lt;p&gt;クライアントサイドのカウボーイコーディングから脱却して、
サーバーサイドに引きずられることなく実装を進められそうなのは嬉しいですね。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-7019305683804856456?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/7019305683804856456/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=7019305683804856456' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/7019305683804856456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/7019305683804856456'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc-4.html' title='JavaScriptMVC でパッケージング'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-4942903271794162431</id><published>2011-08-28T17:16:00.003+09:00</published><updated>2011-08-28T17:23:41.592+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>JavaScriptMVC でドキュメントを生成</title><content type='html'>&lt;p&gt;JavaScriptMVC で作成したアプリケーションの API ドキュメンテーションを生成します。&lt;/p&gt;
&lt;p&gt;この記事の続きです。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc.html"&gt;JavaScriptMVC - 概要&lt;/a&gt; (2011年8月25日)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc-1.html"&gt;JavaScriptMVC を使ってみる&lt;/a&gt; (2011年8月26日)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc-2.html"&gt;JavaScriptMVC でテストを実行&lt;/a&gt; (2011年8月27日)&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;
&lt;div class="section" id="api"&gt;
&lt;h1&gt;API ドキュメントの生成&lt;/h1&gt;
&lt;p&gt;JavaScriptMVC でドキュメントを生成するには &lt;cite&gt;documentjs&lt;/cite&gt; を使います。&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;cookbook&lt;/cite&gt; アプリケーションのドキュメントを生成します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ ./documentjs/doc cookbook
PROCESSING SCRIPTS

  cookbook/controllers/recipe_controller.js
  cookbook/cookbook.js
  cookbook/models/recipe.js
  cookbook/resources/example.js
  cookbook/scripts/build.js
  cookbook/scripts/clean.js
  cookbook/test/funcunit/recipe_controller_test.js
  cookbook/test/qunit/recipe_test.js

GENERATING DOCS -&amp;gt; cookbook/docs

Using default page layout.  Overwrite by creating: cookbook/summary.ejs
&lt;/pre&gt;
&lt;p&gt;生成されたものは &lt;tt class="docutils literal"&gt;cookbook/docs.html&lt;/tt&gt; で確認できます。
Javadoc みたいな感じです。&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;td&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-ojBHnM1zGqg/Tln50CyEOiI/AAAAAAAAEG0/oF2Jrp0UYUo/s1600/jsmvc-docs-model.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 136px;" src="http://4.bp.blogspot.com/-ojBHnM1zGqg/Tln50CyEOiI/AAAAAAAAEG0/oF2Jrp0UYUo/s400/jsmvc-docs-model.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5645818280381004322" /&gt;&lt;/a&gt;
&lt;/td&gt;&lt;td&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-LYp0vqDGJFM/Tln5z2X3lLI/AAAAAAAAEGs/QOi283Va-s4/s1600/jsmvc-docs-controller.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 225px;" src="http://2.bp.blogspot.com/-LYp0vqDGJFM/Tln5z2X3lLI/AAAAAAAAEGs/QOi283Va-s4/s400/jsmvc-docs-controller.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5645818277049898162" /&gt;&lt;/a&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;&amp;#64;Static&lt;/tt&gt; と &lt;tt class="docutils literal"&gt;&amp;#64;Prototype&lt;/tt&gt; は明示的に記述しておくと良さそうです。
また、 &lt;tt class="docutils literal"&gt;index.json&lt;/tt&gt; を生成できるようにすると、トップページコンテンツを配置できるようです。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;サンプルアプリケーションの API ドキュメントを生成しました。
メソッドの一覧を確認して、冗長なインターフェイスを作ってしまっていないか確認できます。&lt;/p&gt;
&lt;p&gt;また、引数と戻り値を記述しておくと、しばらくしてからコードを見直すときにもキャッチアップしやすいでしょう。
オブジェクトを渡すのかコールバックを渡すのか、戻り値は undefined なのかメソッドチェーンでつなげるのか。
確認すべきポイントは人それぞれにあるでしょうが、一貫性のある API だと間違いが少なくなりそうですね。&lt;/p&gt;
&lt;p&gt;次は、ソースコードを連結して、プロダクション用のファイルを生成します。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-4942903271794162431?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/4942903271794162431/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=4942903271794162431' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/4942903271794162431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/4942903271794162431'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc-3.html' title='JavaScriptMVC でドキュメントを生成'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-ojBHnM1zGqg/Tln50CyEOiI/AAAAAAAAEG0/oF2Jrp0UYUo/s72-c/jsmvc-docs-model.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-932311613224278775</id><published>2011-08-27T13:20:00.004+09:00</published><updated>2011-08-27T21:49:40.556+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>JavaScriptMVC でテストを実行</title><content type='html'>
&lt;p&gt;実装を進める前にテストを動かしておきます。
あちこちと実装が散らかってくるとデグレードが多くなりますので、
出来るだけ手戻りがないように用意できることが望ましいと思います。&lt;/p&gt;
&lt;p&gt;この記事の続きです。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc.html"&gt;JavaScriptMVC - 概要&lt;/a&gt; (2011年8月25日)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc-1.html"&gt;JavaScriptMVC を使ってみる&lt;/a&gt; (2011年8月26日)&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;２つのテスト方法&lt;/h1&gt;
&lt;p&gt;JavaScriptMVC で利用可能なテストには次の２種類があります。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://docs.jquery.com/QUnit"&gt;QUnit&lt;/a&gt; - jQuery プロジェクトで使われているテストスイート&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://javascriptmvc.com/docs.html#&amp;amp;who=FuncUnit"&gt;FuncUnit&lt;/a&gt; - QUnit 上に構築したテストフレームワーク&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;それぞれのテストはブラウザでも確認できますし、
コマンドラインからも実行できます。
コマンドラインではブラウザをシミュレートするために &lt;a class="reference external" href="http://www.envjs.com/"&gt;Envjs&lt;/a&gt; を使います。&lt;/p&gt;
&lt;p&gt;モデルの取得や生成を確認するためには QUnit を使い、
ユーザーとのインタラクション (e.g. マウス操作、キーボード入力) を確認するためには FuncUnit を使います。
それぞれの方法を順番に見ていきましょう。&lt;/p&gt;
&lt;div class="section" id="id4"&gt;
&lt;h2&gt;QUnit&lt;/h2&gt;
&lt;p&gt;テスト用の HTML ファイルを &lt;tt class="docutils literal"&gt;cookbook/qunit.html&lt;/tt&gt; として用意します。&lt;/p&gt;
&lt;pre class="prettyprint lang-html literal-block"&gt;
&amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
        &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; href=&amp;quot;../funcunit/qunit/qunit.css&amp;quot; /&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
    &amp;lt;h1 id=&amp;quot;qunit-header&amp;quot;&amp;gt;Cookbook Application Test Suite&amp;lt;/h1&amp;gt;
    &amp;lt;h2 id=&amp;quot;qunit-banner&amp;quot;&amp;gt;&amp;lt;/h2&amp;gt;
    &amp;lt;div id=&amp;quot;qunit-testrunner-toolbar&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;h2 id=&amp;quot;qunit-userAgent&amp;quot;&amp;gt;&amp;lt;/h2&amp;gt;
    &amp;lt;ol id=&amp;quot;qunit-tests&amp;quot;&amp;gt;&amp;lt;/ol&amp;gt;
    &amp;lt;div id=&amp;quot;qunit-test-area&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;script type='text/javascript'
            src='../steal/steal.js?cookbook/qunit.js'&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;
&lt;p&gt;テストケースを呼び出すためのスクリプトを &lt;tt class="docutils literal"&gt;cookbook/qunit.js&lt;/tt&gt; として用意します。
&lt;tt class="docutils literal"&gt;steal.js&lt;/tt&gt; に渡している部分のパスです。&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block"&gt;
steal
    .plugins('funcunit/qunit')
    .then('test/qunit/recipe_test')
    ;
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;test/qunit/recipe_test.js&lt;/tt&gt; は scaffold で生成されたものです。&lt;/p&gt;
&lt;p&gt;ブラウザーで &lt;tt class="docutils literal"&gt;cookbook/qunit.html&lt;/tt&gt; を開くとテストが実行されます。
まずはすべてのテストケースが失敗しています。&lt;/p&gt;
&lt;div style="text-align:center;"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-52JHZdOjxIk/Tlhw2Yk119I/AAAAAAAAEGM/BEkSsNlqrHI/s1600/jsmvc-test-qunit-failures.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 130px;" src="http://1.bp.blogspot.com/-52JHZdOjxIk/Tlhw2Yk119I/AAAAAAAAEGM/BEkSsNlqrHI/s400/jsmvc-test-qunit-failures.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5645386212521138130" /&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;テストケースをクリックすると、以下のメッセージを確認できます。&lt;/p&gt;
&lt;blockquote&gt;
Died on test #1: Cookbook is not defined&lt;/blockquote&gt;
&lt;p&gt;モデルモジュールのローディングミスなので、 &lt;tt class="docutils literal"&gt;cookbook/qunit.js&lt;/tt&gt; を次のように変更します。&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block"&gt;
steal
    .plugins('funcunit/qunit', 'jquery/model')
    .then('models/recipe')
    .then('test/qunit/recipe_test')
    ;
&lt;/pre&gt;
&lt;p&gt;再度テストを実行すると、モデルを取得 / 生成するために GET / POST リクエストが発生します。
サーバーサイドは何も実装していませんので、すべてがエラーになります。&lt;/p&gt;
&lt;div style="text-align:center;"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-2jwSa6Bo8DY/Tlhw2XtQg4I/AAAAAAAAEGE/OVB8KsKdAVM/s1600/jsmvc-test-qunit-errors.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 205px;" src="http://4.bp.blogspot.com/-2jwSa6Bo8DY/Tlhw2XtQg4I/AAAAAAAAEGE/OVB8KsKdAVM/s400/jsmvc-test-qunit-errors.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5645386212288004994" /&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;サーバーサイドの実装とクライアントサイドの実装は無関係に進めたいですから、
&lt;a class="reference external" href="http://javascriptmvc.com/docs.html#&amp;amp;who=jQuery.fixture"&gt;jQuery.fixture&lt;/a&gt; を使ってリクエストをエミュレートします。
&lt;tt class="docutils literal"&gt;cookbook/qunit.js&lt;/tt&gt; で fixture プラグインも読み込むようにします。&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block"&gt;
steal
    .plugins('funcunit/qunit', 'jquery/model', 'jquery/dom/fixture')
    .then('models/recipe')
    .then('test/qunit/recipe_test')
;
&lt;/pre&gt;
&lt;p&gt;これでテストがパスします。&lt;/p&gt;
&lt;div style="text-align:center;"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-Ai_PVCLuYoA/Tlhw2mfky6I/AAAAAAAAEGU/N8TIr6GAJLI/s1600/jsmvc-test-qunit-success.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 221px;" src="http://1.bp.blogspot.com/-Ai_PVCLuYoA/Tlhw2mfky6I/AAAAAAAAEGU/N8TIr6GAJLI/s400/jsmvc-test-qunit-success.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5645386216257145762" /&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;div class="section" id="id5"&gt;
&lt;h3&gt;コマンドラインからの実行&lt;/h3&gt;
&lt;p&gt;コマンドラインからもテストを実行できます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ ./funcunit/envjs cookbook/qunit.html
Using Default Settings
MODULE Model: Cookbook.Models.Recipe

--findAll--
steal.js INFO: looking for fixture in ../cookbook/fixtures/recipes.json.get
  PASS
  PASS
  PASS
  PASS
  done - fail 0, pass 4

--create--
steal.js INFO: using a dynamic fixture for /recipes
steal.js INFO: Model.js - publishing recipe.created
  PASS
  PASS
  PASS okay, expected: &amp;quot;dry cleaning&amp;quot; result: &amp;quot;dry cleaning&amp;quot;
steal.js INFO: using a dynamic fixture for /recipes/1867
  done - fail 0, pass 3

--update--
steal.js INFO: using a dynamic fixture for /recipes
steal.js INFO: Model.js - publishing recipe.destroyed
steal.js INFO: Model.js - publishing recipe.created
  PASS okay, expected: &amp;quot;chicken&amp;quot; result: &amp;quot;chicken&amp;quot;
steal.js INFO: using a dynamic fixture for /recipes/25832
steal.js INFO: Model.js - publishing recipe.updated
  PASS okay, expected: &amp;quot;steak&amp;quot; result: &amp;quot;steak&amp;quot;
steal.js INFO: using a dynamic fixture for /recipes/25832
  done - fail 0, pass 2

--destroy--
steal.js INFO: using a dynamic fixture for /recipes/undefined
steal.js INFO: Model.js - publishing recipe.destroyed
steal.js INFO: Model.js - publishing recipe.destroyed
  PASS Destroy called
  done - fail 0, pass 1


ALL DONEe - fail 0, pass 10
&lt;/pre&gt;
&lt;p&gt;10個のテストがすべてパスしていることが分かります。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id6"&gt;
&lt;h2&gt;FuncUnit&lt;/h2&gt;
&lt;p&gt;続いて、ユーザー操作に関するテストを作成します。
クリックすべき要素があるか、入力フィールドが存在するか、といったことをテストします。&lt;/p&gt;
&lt;p&gt;テスト用の HTML ファイルを &lt;tt class="docutils literal"&gt;cookbook/funcunit.html&lt;/tt&gt; として用意します。&lt;/p&gt;
&lt;pre class="prettyprint lang-html literal-block"&gt;
&amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
        &amp;lt;link rel=&amp;quot;stylesheet&amp;quot; type=&amp;quot;text/css&amp;quot; href=&amp;quot;../funcunit/qunit/qunit.css&amp;quot; /&amp;gt;
        &amp;lt;title&amp;gt;FuncUnit Test&amp;lt;/title&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;

        &amp;lt;h1 id=&amp;quot;qunit-header&amp;quot;&amp;gt;funcunit Test Suite&amp;lt;/h1&amp;gt;
        &amp;lt;h2 id=&amp;quot;qunit-banner&amp;quot;&amp;gt;&amp;lt;/h2&amp;gt;
        &amp;lt;div id=&amp;quot;qunit-testrunner-toolbar&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
        &amp;lt;h2 id=&amp;quot;qunit-userAgent&amp;quot;&amp;gt;&amp;lt;/h2&amp;gt;
        &amp;lt;ol id=&amp;quot;qunit-tests&amp;quot;&amp;gt;&amp;lt;/ol&amp;gt;
        &amp;lt;script type='text/javascript'
                src='../steal/steal.js?cookbook/funcunit.js'&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/pre&gt;
&lt;p&gt;テストケースを呼び出すためのスクリプトを &lt;tt class="docutils literal"&gt;cookbook/funcunit.js&lt;/tt&gt; として用意します。
&lt;tt class="docutils literal"&gt;test/funcunit/recipe_controller_test.js&lt;/tt&gt; は scaffold で生成されたものです。&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block"&gt;
steal
    .plugins('funcunit', 'jquery/model', 'jquery/controller')
    .then('controllers/recipe_controller')
    .then('test/funcunit/recipe_controller_test')
    ;
&lt;/pre&gt;
&lt;p&gt;ブラウザで &lt;tt class="docutils literal"&gt;funcunit.html&lt;/tt&gt; を開いてテストを実行します。
ポップアップブロックは解除しておきましょう。&lt;/p&gt;
&lt;div style="text-align:center;"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-zSFmUNOsVjI/Tlhw2ByDXNI/AAAAAAAAEF8/ECnEoJE04aQ/s1600/jsmvc-test-funcunit-failures.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 317px;" src="http://2.bp.blogspot.com/-zSFmUNOsVjI/Tlhw2ByDXNI/AAAAAAAAEF8/ECnEoJE04aQ/s400/jsmvc-test-funcunit-failures.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5645386206402534610" /&gt;&lt;/a&gt;
&lt;/div&gt;
&lt;div class="section" id="id7"&gt;
&lt;h3&gt;コマンドラインからの実行&lt;/h3&gt;
&lt;p&gt;コマンドラインからも確認しましょう。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ ./funcunit/envjs cookbook/funcunit.html
Using Default Settings
Selenium is not running. Please use steal/js -selenium to start it.
&lt;/pre&gt;
&lt;p&gt;FuncUnit をコマンドラインから実行すると、裏側で Selenium を動かす必要があります。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ pushd funcunit/java
$ ln -s selenium-server-standalone-2.0b3.jar selenium-server.jar
$ popd
$ ./js -selenium
$ ./funcunit/envjs cookbook/funcunit.html
&lt;/pre&gt;
&lt;p&gt;たぶんこれで動くはずなんですが、手元の環境では Firefox が何も進みませんでした。
読み込むプラグインが足りないんだと思いますが、深追いしないことにします。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id8"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;JavaScriptMVC を使ってテストケースを動かしました。
２種類のテストがありますので、着目する部分に応じてテストを使い分けられると良さそうです。
ブラウザテストは同じ操作を再現することが煩雑だったりクロスブラウザでの確認を忘れがちですが、
Envjs を利用してコマンドラインからも実行できると、CI ツールに組み込んで使えます。&lt;/p&gt;
&lt;p&gt;先にテストを書いておくと、とりあえず今日はここまで、という区切りを考えやすくなるかもしれません。
また、サーバーサイドの API が未実装でも、わざわざモックを用意することなく、
JSON でなんとなくデータをエミュレートできます。
最近は HTML5 を中心としたクライアントサイドのストレージも使えるようになりましたので、
HTTP をエミュレートしない場合には選択肢のひとつとして考慮すべきだと思います。&lt;/p&gt;
&lt;p&gt;次は、モデルやコントローラーの API を HTML ドキュメントとして出力します。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-932311613224278775?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/932311613224278775/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=932311613224278775' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/932311613224278775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/932311613224278775'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc-2.html' title='JavaScriptMVC でテストを実行'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-52JHZdOjxIk/Tlhw2Yk119I/AAAAAAAAEGM/BEkSsNlqrHI/s72-c/jsmvc-test-qunit-failures.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-3088451478732278294</id><published>2011-08-26T20:23:00.005+09:00</published><updated>2011-08-26T20:48:47.481+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>JavaScriptMVC を使ってみる</title><content type='html'>&lt;p&gt;&lt;a class="reference external" href="https://github.com/jupiterjs/javascriptmvc"&gt;JavaScriptMVC&lt;/a&gt; を使ってプロジェクトを作成します。
この記事の続きです。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc.html"&gt;JavaScriptMVC - 概要&lt;/a&gt; (2011年8月25日)&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;ツールの準備&lt;/h1&gt;
&lt;p&gt;github から ZIP パッケージをダウンロードして適当なディレクトリに展開します。
この記事を書いている時点での最新版は &lt;em&gt;javascriptmvc-3.1.0.zip&lt;/em&gt; です。&lt;/p&gt;
&lt;p&gt;中身を見ておくと次のようになります。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ ls
MIT-LICENSE.txt  documentjs/      jquery/          js.bat*
changelog.txt    funcunit/        js*              steal/

$ ls steal/ jquery/ funcunit/ documentjs/
documentjs/:
README         distance.js    doc.bat        jmvcdoc/       scripts/       showdown.js    test/          update
build.js       doc*           documentjs.js  json.js        searchdata.js  tags/          types/

funcunit/:
README              drivers/            generate_docs.html  qunit/              summary.ejs
autosuggest/        envjs*              index.html          qunit.html          syn/
build.js            envjs.bat*          java/               resources/          template.html
dependencies.json   funcunit.html       loader.js           scripts/            test/
docs.html           funcunit.js         pages/              settings.js         update

jquery/:
README       buildAll.js  controller/  download/    generate/    lang/        qunit.html   tie/         view/
build.js     class/       dom/         event/       jquery.js    model/       test/        update

steal/:
README               coffee/              getjs                parse/               steal.production.js
build/               dev/                 js*                  patchfile            test/
buildjs              end.js               js.bat               pluginifyjs          update
clean/               generate/            less/                rhino/
cleanjs              get/                 make.js              steal.js
&lt;/pre&gt;
&lt;p&gt;単純な JavaScript だけでなく、 &lt;a class="reference external" href="http://docs.jquery.com/Qunit"&gt;QUnit&lt;/a&gt;, &lt;a class="reference external" href="http://jashkenas.github.com/coffee-script/"&gt;CoffeeScript&lt;/a&gt;, &lt;a class="reference external" href="http://lesscss.org/"&gt;LESS&lt;/a&gt; なども同梱されていることが分かります。
また、 &lt;cite&gt;steal&lt;/cite&gt; の中には &lt;a class="reference external" href="https://developer.mozilla.org/ja/Rhino"&gt;Rhino&lt;/a&gt; もありますね。
ちょっと JavaScript を動かしてみるには良い環境だと思います。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h1&gt;アプリケーションの作成&lt;/h1&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;js&lt;/tt&gt; コマンドが &lt;a class="reference external" href="https://developer.mozilla.org/ja/Rhino"&gt;Rhino&lt;/a&gt; へのラッパーになっており、
&lt;cite&gt;steal&lt;/cite&gt; を使ってアプリケーションを管理します。&lt;/p&gt;
&lt;p&gt;&amp;quot;cookbook&amp;quot; アプリケーションを作成してみます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ ./js steal/generate/app cookbook
      cookbook/cookbook.css
      cookbook/cookbook.html
      cookbook/cookbook.js
      cookbook/docs
      cookbook/resources
      cookbook/resources/example.coffee
      cookbook/resources/example.js
      cookbook/resources/example.less
      cookbook/scripts
      cookbook/scripts/build.html
      cookbook/scripts/build.js
      cookbook/scripts/clean.js
      cookbook/test
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;cookbook/cookbook.html&lt;/tt&gt; を開いてエラーが出ないことを確認します。
StealJS がパス解決に失敗している部分があると後で大変なので、
FireBug や開発者コンソールなどで確認しておきましょう。&lt;/p&gt;

&lt;div style="text-align:center;"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-b5SNkeDn17I/TleCjh6aSQI/AAAAAAAAEFU/NtWtC0beqYc/s1600/jsmvc-steal-blank.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 142px;" src="http://2.bp.blogspot.com/-b5SNkeDn17I/TleCjh6aSQI/AAAAAAAAEFU/NtWtC0beqYc/s400/jsmvc-steal-blank.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5645124204842600706" /&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;ファイルシステム上のファイルを直接開くと Cross origin リクエストのエラーになるブラウザもあります。
HTTP サーバを起動しておくと便利です。
&lt;tt class="docutils literal"&gt;js&lt;/tt&gt; コマンドを実行したディレクトリで &lt;tt class="docutils literal"&gt;python &lt;span class="pre"&gt;-m&lt;/span&gt; SimpleHTTPServer&lt;/tt&gt; を実行すると、
8000番ポートからアクセスできます。
Mac OS X の場合は Web 共有で Apache が起動しますので、 &lt;tt class="docutils literal"&gt;~/Sites&lt;/tt&gt; 以下に配置すれば
HTTP 経由でアクセスできます。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;次に、データモデルを定義します。
scaffold を使うことで、MVC で言うモデルとコントローラーを生成してくれます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ mkdir cookbook/models
$ ./js jquery/generate/scaffold Cookbook.Models.Recipe
      cookbook/controllers
      cookbook/controllers/recipe_controller.js
      cookbook/fixtures
      cookbook/fixtures/recipes.json.get
      cookbook/models
      cookbook/models/recipe.js
      cookbook/test
      cookbook/test/funcunit
      cookbook/test/funcunit/recipe_controller_test.js
      cookbook/test/qunit
      cookbook/test/qunit/recipe_test.js
      cookbook/views
      cookbook/views/recipe
      cookbook/views/recipe/edit.ejs
      cookbook/views/recipe/init.ejs
      cookbook/views/recipe/list.ejs
      cookbook/views/recipe/show.ejs
&lt;/pre&gt;
&lt;p&gt;ここでサクッとモデルとコントローラーを使えると良いのですが、
JavaScriptMVC 2 系まであった &lt;tt class="docutils literal"&gt;.models()&lt;/tt&gt; と &lt;tt class="docutils literal"&gt;.controllers()&lt;/tt&gt; インターフェイスは廃止されました。&lt;/p&gt;
&lt;p&gt;そこで、 &lt;tt class="docutils literal"&gt;cookbook.js&lt;/tt&gt; を以下のように編集します。
コードジェネレーターで生成されたファイルは &lt;cite&gt;LESS&lt;/cite&gt; と &lt;cite&gt;CoffeeScript&lt;/cite&gt; を読み込むようになっていますが、
この部分は一旦コメントアウトか削除しておきます。&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block"&gt;
steal
    .plugins('jquery/model', 'jquery/view/ejs')
    .then('models/recipe')
    .then(function() {
        $('#content').append($.View('//cookbook/views/recipe/init.ejs', {recipes: []}));
    })
    ;
&lt;/pre&gt;

&lt;div style="float:right; margin: 10px;"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-S6D3G7PxH_A/TleCj98eUDI/AAAAAAAAEFs/_ySIfeCUIek/s1600/jsmvc-view-init.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 138px;" src="http://3.bp.blogspot.com/-S6D3G7PxH_A/TleCj98eUDI/AAAAAAAAEFs/_ySIfeCUIek/s400/jsmvc-view-init.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5645124212367446066" /&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;まず、モデルとビューのプラグインを読み込みます。
ビューには EJS (&lt;a class="reference external" href="http://embeddedjs.com/"&gt;EmbeddedJS&lt;/a&gt;), &lt;a class="reference external" href="http://ejohn.org/blog/javascript-micro-templating/"&gt;Micro&lt;/a&gt;, &lt;a class="reference external" href="http://api.jquery.com/jquery.tmpl/"&gt;jQuery.Tmpl&lt;/a&gt;, &lt;a class="reference external" href="http://edspencer.github.com/jaml/"&gt;JAML&lt;/a&gt; がありますが、
コードジェネレーターのデフォルトが EJS なので、これをそのまま使います。&lt;/p&gt;
&lt;p&gt;次に、 &lt;tt class="docutils literal"&gt;cookbook/models/recipe.js&lt;/tt&gt; で定義されるモデルクラス (&lt;tt class="docutils literal"&gt;Cookbook.Models.Recipe&lt;/tt&gt;) を読み込みます。
&lt;tt class="docutils literal"&gt;.then()&lt;/tt&gt; で指定する場合には &lt;cite&gt;.js&lt;/cite&gt; の拡張子を省略します。
モデルクラスをここで読み込むのは、後から読み込むテンプレートファイルで参照しているためです。&lt;/p&gt;
&lt;p&gt;最後の &lt;tt class="docutils literal"&gt;.then()&lt;/tt&gt; にはコールバック関数を指定します。
最初に生成した &lt;tt class="docutils literal"&gt;cookbook.html&lt;/tt&gt; には ID が &amp;quot;content&amp;quot; の &lt;tt class="docutils literal"&gt;&amp;lt;div&amp;gt;&lt;/tt&gt; タグがありますので、
そこに HTML 要素を追加します。
&lt;tt class="docutils literal"&gt;$.View&lt;/tt&gt; の最初の引数にテンプレートファイルへのパスを指定し、
二つ目の引数でパラメータを渡します。
パス表記はスラッシュふたつで始めています。
Web サーバ上での配置を考えるのが面倒な場合にはこのように書いておきます。&lt;/p&gt;
&lt;p&gt;HTML ファイル (&lt;tt class="docutils literal"&gt;cookbook.html&lt;/tt&gt;) をブラウザで開いてみると、
レシピの一覧と新しいレシピを登録するフォームのひな形が表示されています。&lt;/p&gt;

&lt;p&gt;これでアプリケーションを実装する準備ができました。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h1&gt;データの表示&lt;/h1&gt;
&lt;div class="section" id="id6"&gt;
&lt;h2&gt;一覧表示&lt;/h2&gt;
&lt;p&gt;サンプルデータを表示させます。
&lt;tt class="docutils literal"&gt;cookbook/fixtures/recipes.json.get&lt;/tt&gt; の中身を &lt;tt class="docutils literal"&gt;cookbook.js&lt;/tt&gt; にコピーし、
テンプレートに渡します。
先ほどのコールバック関数を次のように変更します。&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block"&gt;
.then(function() {
    var recipes = [
        {&amp;quot;name&amp;quot;: &amp;quot;Take Out Trash&amp;quot;, &amp;quot;description&amp;quot;: &amp;quot;To the curb!&amp;quot;, &amp;quot;id&amp;quot;: 5}
    ];
    $('#content').append($.View('//cookbook/views/recipe/init.ejs', {recipes: recipes}));
})
&lt;/pre&gt;
&lt;p&gt;続いてテンプレートを修正します。
&lt;tt class="docutils literal"&gt;init.ejs&lt;/tt&gt; は &lt;tt class="docutils literal"&gt;list.ejs&lt;/tt&gt; を呼び出し、その中で要素をループさせて &lt;tt class="docutils literal"&gt;show.ejs&lt;/tt&gt; を呼び出します。
自動生成された &lt;tt class="docutils literal"&gt;show.ejs&lt;/tt&gt; ではエラーが発生しますので、以下のように書き換えます。&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block"&gt;
&amp;lt;%for(var attribute in this){%&amp;gt;
    &amp;lt;%if(attribute == 'id') continue;%&amp;gt;
    &amp;lt;td class='&amp;lt;%= attribute%&amp;gt;' style=&amp;quot;border:solid 1px gray; padding: 5px;&amp;quot;&amp;gt;
        &amp;lt;%=this[attribute]%&amp;gt;
    &amp;lt;/td&amp;gt;
&amp;lt;%}%&amp;gt;
&amp;lt;td&amp;gt;
    &amp;lt;a href='javascript://' class='edit'&amp;gt;edit&amp;lt;/a&amp;gt;
    &amp;lt;a href='javascript://' class='destroy'&amp;gt;destroy&amp;lt;/a&amp;gt;
&amp;lt;/td&amp;gt;
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;cookbook.html&lt;/tt&gt; をリロードすると次のようになります。
サンプルデータ (&lt;tt class="docutils literal"&gt;recipes&lt;/tt&gt; 変数) を増やすと、一覧表示のデータに反映されます。&lt;/p&gt;

&lt;div style="text-align:center;"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-cMOSgi4Aunc/TleCyghsdkI/AAAAAAAAEF0/F5y78hIw79A/s1600/jsmvc-view-list.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 153px;" src="http://4.bp.blogspot.com/-cMOSgi4Aunc/TleCyghsdkI/AAAAAAAAEF0/F5y78hIw79A/s400/jsmvc-view-list.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5645124462168536642" /&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;div class="section" id="id7"&gt;
&lt;h2&gt;フォーム作成&lt;/h2&gt;
&lt;p&gt;モデルに属性を追加します。
&lt;tt class="docutils literal"&gt;Cookbook.Models.Recipe&lt;/tt&gt; にはスタティックメソッドとプロトタイプメソッドが定義されています。
&lt;tt class="docutils literal"&gt;/* &amp;#64;Static */&lt;/tt&gt; のどこかに &lt;tt class="docutils literal"&gt;attributes&lt;/tt&gt; を追加します。
辞書のキーはデータのキーと合わます。バリューは適当に当てています。&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block"&gt;
attributes: {
    'id': 'integer',
    'name': 'string',
    'description': 'text'
}
&lt;/pre&gt;
&lt;p&gt;ブラウザで確認してみると、&amp;quot;New recipe&amp;quot; の部分にふたつのテキストボックスが追加され、
&amp;quot;recipes&amp;quot; の一覧表にタイトルが追加されていますね。&lt;/p&gt;

&lt;div style="text-align:center;"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-LVTJfg5Iu6w/TleCjeBPCrI/AAAAAAAAEFM/EWuMVVZe75Q/s1600/jsmvc-model-attr.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 256px;" src="http://2.bp.blogspot.com/-LVTJfg5Iu6w/TleCjeBPCrI/AAAAAAAAEFM/EWuMVVZe75Q/s400/jsmvc-model-attr.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5645124203797482162" /&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id8"&gt;
&lt;h1&gt;スタイルシートの分離&lt;/h1&gt;
&lt;p&gt;先ほどはテンプレートファイルの中に &lt;cite&gt;style&lt;/cite&gt; 属性を記述しました。
これを外部ファイル化します。
方法はふたつあり、通常の CSS で管理する方法と、LESS を使う方法です。&lt;/p&gt;
&lt;table&gt;
&lt;tr&gt;&lt;td&gt;
&lt;h2&gt;CSS を読み込む&lt;/h2&gt;
&lt;p&gt;CSS は &lt;tt class="docutils literal"&gt;steal&lt;/tt&gt; の &lt;tt class="docutils literal"&gt;.css()&lt;/tt&gt; メソッドで読み込めます。
&lt;tt class="docutils literal"&gt;cookbook.js&lt;/tt&gt; の &lt;tt class="docutils literal"&gt;steal&lt;/tt&gt; のメソッドチェーンに次の１行を追加します。&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block" width="50%;"&gt;
.css('cookbook')
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;&amp;lt;td&amp;gt;&lt;/tt&gt; 要素に埋め込んだ &lt;cite&gt;style&lt;/cite&gt; 属性を &lt;tt class="docutils literal"&gt;cookbook.css&lt;/tt&gt; に移動してから
&lt;tt class="docutils literal"&gt;cookbook.html&lt;/tt&gt; を再度読み込みます。
デフォルトのデザインもかかってきますので、フォントなどが変わります。&lt;/p&gt;
&lt;/td&gt;&lt;td&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-BvCnx3ytM3c/TleCjvJIM3I/AAAAAAAAEFc/tH6luCT8EXg/s1600/jsmvc-style-css.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 216px;" src="http://4.bp.blogspot.com/-BvCnx3ytM3c/TleCjvJIM3I/AAAAAAAAEFc/tH6luCT8EXg/s400/jsmvc-style-css.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5645124208393991026" /&gt;&lt;/a&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-Btmu7-1kk5Y/TleCj5CPVII/AAAAAAAAEFk/1cE4K_ZWNg8/s1600/jsmvc-style-less.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 194px;" src="http://4.bp.blogspot.com/-Btmu7-1kk5Y/TleCj5CPVII/AAAAAAAAEFk/1cE4K_ZWNg8/s400/jsmvc-style-less.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5645124211049452674" /&gt;&lt;/a&gt;
&lt;/td&gt;&lt;td&gt;
&lt;h2&gt;LESS を使う&lt;/h2&gt;

&lt;p&gt;LESS を使うためには、プラグインを読み込んでから &lt;tt class="docutils literal"&gt;.less&lt;/tt&gt; ファイルを指定します。
先ほどの &lt;tt class="docutils literal"&gt;.css()&lt;/tt&gt; を次の４行で置き換えます。
もちろん、CSS も LESS も両方使う場合には、置き換えではなく付け足しになります。&lt;/p&gt;
&lt;pre class="prettyprint lang-js literal-block"&gt;
.plugins('steal/less')
.then(function() {
    steal.less('resources/example');
})
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;cookbook/resources/example.less&lt;/tt&gt; に &lt;tt class="docutils literal"&gt;&amp;lt;td&amp;gt;&lt;/tt&gt; の枠線を定義すると反映されます。&lt;/p&gt;
&lt;p&gt;LESS を使うと変数を再利用できますので、素朴に CSS を記述していくよりは効率的にスタイルを管理できそうです。&lt;/p&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;div class="section" id="id10"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;JavaScriptMVC を使ってアプリケーションのひな形と、簡単なデータを表示しました。
表示方法は複数のテンプレートシステムから選択でき、デザインには CSS だけでなく LESS も使えます。&lt;/p&gt;
&lt;p&gt;新しいテンプレートや LESS、それから CoffeeScript は、
記法に慣れてしまえばサクサクと実装できるでしょうが、
不慣れな場合には覚えることが多くなってしまうことも事実です。
とはいえ、愚直に JavaScript や CSS を書いてブラウザごとの違いに泣かされるよりは、
最近流行り始めているかもしれない手法を取り入れた方が手っ取り早いと思います。&lt;/p&gt;
&lt;p&gt;次は、QUnit と funcunit を使ってテストを動かしてみます。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-3088451478732278294?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/3088451478732278294/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=3088451478732278294' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/3088451478732278294'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/3088451478732278294'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc-1.html' title='JavaScriptMVC を使ってみる'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-b5SNkeDn17I/TleCjh6aSQI/AAAAAAAAEFU/NtWtC0beqYc/s72-c/jsmvc-steal-blank.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-5130571918290879735</id><published>2011-08-25T22:47:00.004+09:00</published><updated>2011-08-29T22:25:32.247+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='翻訳'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>JavaScriptMVC - 概要</title><content type='html'>
&lt;p&gt;&lt;a class="reference external" href="https://github.com/jupiterjs/javascriptmvc"&gt;JavaScriptMVC&lt;/a&gt; は &lt;a class="reference external" href="http://jupiterjs.com/"&gt;Jupiter&lt;/a&gt; が開発/提供している JavaScript フレームワークです。
jQuery を中心に据えて、クライアントサイドの開発を助けてくれます。
JavaScriptMVC のメリットはこの辺でも触れています。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/01/javascriptmvc-and-list-performance-ja.html"&gt;JavaScriptMVC と一覧表示の性能&lt;/a&gt; - 2011年1月13日の記事&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;使い方をまとめて記事にしようとしたら大変だったので、
５回に分けて書く予定にします。&lt;/p&gt;
&lt;ol class="simple"&gt;
&lt;li&gt;概要                 (この記事)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc-1.html"&gt;プロジェクトの作成&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc-2.html"&gt;テストと実装&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc-3.html"&gt;ドキュメンテーション&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc-4.html"&gt;パッケージング&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Update: 一連の記事を書き終えたのでリンクにした。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;
&lt;p&gt;github に書きかけの gist がありましたので、最初の方を少しだけ訳出します。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://gist.github.com/867069/2286512a6126e06ae78ec271a59496171b5beed6"&gt;JavaScriptMVC Overview&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;github のレポジトリから &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;javascriptmvc-3.1.0.zip&lt;/span&gt;&lt;/tt&gt; をダウンロードしておくと、
フォルダの中身を確認しながら動かせるようになるかもしれません。
(この記事では何も動かさないけど)&lt;/p&gt;

&lt;div style="align:center;"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-8ZSdW5vHbb8/TlZSsReFx_I/AAAAAAAAEFE/FiSVSYKgDGU/s1600/GitHub-jupiterjs-javascriptmvc.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 229px;" src="http://3.bp.blogspot.com/-8ZSdW5vHbb8/TlZSsReFx_I/AAAAAAAAEFE/FiSVSYKgDGU/s400/GitHub-jupiterjs-javascriptmvc.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5644790103512827890" /&gt;&lt;/a&gt;
&lt;/div&gt;

&lt;div class="section" id="id3"&gt;
&lt;h1&gt;JavaScriptMVC の概要&lt;/h1&gt;
&lt;div class="section" id="id4"&gt;
&lt;h2&gt;イントロダクション&lt;/h2&gt;
&lt;p&gt;JavaScriptMVC は jQuery をベースとしたオープンソースの JavaScript フレームワークです。
フロントエンドの開発フレームワークとしては (総体的に) 網羅されており、
以下の有用性のあるものでパッケージングされています。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;テスト&lt;/li&gt;
&lt;li&gt;依存性管理&lt;/li&gt;
&lt;li&gt;エラーレポーティング&lt;/li&gt;
&lt;li&gt;パッケージ管理&lt;/li&gt;
&lt;li&gt;コードクリーニング&lt;/li&gt;
&lt;li&gt;独自イベント&lt;/li&gt;
&lt;li&gt;jQuery 拡張&lt;/li&gt;
&lt;li&gt;ドキュメンテーション&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ライブラリは、ほぼ独立した４つのサブプロジェクトに分割され、
UI ウィジェットを除いたほとんどすべてがあります。
JMVC の MVC 部分は、GZIP 化されるとたったの 7kB しかありません。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h2&gt;プラグインとしての実装&lt;/h2&gt;
&lt;p&gt;JavaScriptMVC は独立した４つのサブプロジェクトに分割されます。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;StealJS - 依存性管理、コードジェネレーター、プロダクションビルド、コードクリーニング&lt;/li&gt;
&lt;li&gt;FuncUnit - Web テストフレームワーク&lt;/li&gt;
&lt;li&gt;DocumentJS - JS ドキュメンテーションフレームワーク&lt;/li&gt;
&lt;li&gt;jQueryMX - jQuery の MVC 拡張&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ダウンロードパッケージは、以下のフォルダから構成されます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
funcunit
documentjs
jquery
steal
&lt;/pre&gt;
&lt;p&gt;それぞれのフォルダ内には、たくさんのサブプラグインがあります。
たとえば、 JavaScriptMVC のコントローラーは &lt;tt class="docutils literal"&gt;jquery/controller/controller.js&lt;/tt&gt; にあります。&lt;/p&gt;
&lt;p&gt;JavaScriptMVC を使うときは似たようなフォルダ構造にすると良いでしょう。
この文章の最後で作成する (訳注:元の記事が終わってないので未完)
ToDo アプリケーションは以下のように構成しました。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
funcunit
documentjs
jquery
steal
todo/
  todo.js
  todo.html
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id6"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;JavaScriptMVC の概要を日本語に訳しました。
JavaScriptMVC 3 系からは、かなり大きく API が変更されたようで、
いくつかの (多くの？) ドキュメントが陳腐化しています。
API を見ていくときには注意が必要です。
特に、非同期に処理する方法を導入したことによって、いくつかの API は互換ではありませんし、
モデルとコントローラーを使うメソッドも変更されています。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://forum.javascriptmvc.com/#Topic/32525000000590273"&gt;New Steal API checked into master branch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;次は、Steal を使ってアプリケーションを作成してみます。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-5130571918290879735?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/5130571918290879735/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=5130571918290879735' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/5130571918290879735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/5130571918290879735'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/08/getting-started-javascriptmvc.html' title='JavaScriptMVC - 概要'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-8ZSdW5vHbb8/TlZSsReFx_I/AAAAAAAAEFE/FiSVSYKgDGU/s72-c/GitHub-jupiterjs-javascriptmvc.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-2844891436491100509</id><published>2011-08-23T00:54:00.001+09:00</published><updated>2011-08-23T01:01:05.261+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Waf'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Waf を使って構文チェックしてからコピーする</title><content type='html'>

&lt;p&gt;インタープリタ型のプログラミング言語では、
ソースコードを記述したファイルをそのまま実行できます。
小さめのファイルなら簡単に動作を確認できて非常に便利です。
しかし、モジュールを区切って管理するようになると複数のファイルに依存関係が発生し、
こまめにテストしながら開発する必要があります。&lt;/p&gt;
&lt;p&gt;ひとくちにテストと言っても様々なレベルが考えられますが、
ここでは、構文だけをテストします。
原理は同じですから、同様にして単体テストやドキュメントテストも実行できるようになります。
設定方法を工夫すれば結合テストもできるようになるはずですね。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;
&lt;div class="section" id="python-pep8"&gt;
&lt;h1&gt;Python で pep8&lt;/h1&gt;
&lt;p&gt;Python には &lt;a class="reference external" href="http://www.python.org/dev/peps/pep-0008/"&gt;PEP 8&lt;/a&gt; - Style Guide for Python Code - という約束があり、
これに沿っているかを確認するために &lt;tt class="docutils literal"&gt;pep8&lt;/tt&gt; というツールがあります。
インデントは空白4文字になっているか、1行が80文字以上になっていないか、
クラス定義の前に2行の空行があるか、エンコーディングは何かといったことを確認してくれます。&lt;/p&gt;
&lt;p&gt;PyPI にモジュールがアップされていますので、簡単にインストールできます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ pip install pep8
&lt;/pre&gt;
&lt;p&gt;Python スクリプトを引数に渡してあげると次のようになります。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cat &amp;lt;&amp;lt;EOF &amp;gt;pep8-test.py
if True is False:
  print &amp;quot;Bad world.&amp;quot;

class True(object):
  pass

False = True
print type(False), True is False
EOF

$ python pep8-test.py
&amp;lt;type 'type'&amp;gt; True

$ pep8 pep8-test.py
pep8-test.py:2:3: E111 indentation is not a multiple of four
pep8-test.py:4:1: E302 expected 2 blank lines, found 1
&lt;/pre&gt;
&lt;p&gt;インデントが４で揃っていないこと、空行が２行あるべき部分に１行しか見つからないことが報告されます。&lt;/p&gt;
&lt;p&gt;コマンドライン引数を渡すことで、 &lt;cite&gt;doctest&lt;/cite&gt; を実行したり、無視するエラーレベルを調整できます。
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--show-source&lt;/span&gt;&lt;/tt&gt; や &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--show-pep8&lt;/span&gt;&lt;/tt&gt; オプションを使うと詳細な説明も表示されますので、
コードスタイルに慣れておらずソースコードが小さいうちは、これらを付けた方が良いかもしれません。
(記述量が多くなってくるとエラーが埋もれてしまうのと、エラー内容を見ればだいたい分かるので、
しばらく使うといらなくなる感じ。)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="waf-pep8"&gt;
&lt;h1&gt;Waf で pep8&lt;/h1&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt; を用意して Waf で実行できるようにします。
先ほどの &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;pep8-test.py&lt;/span&gt;&lt;/tt&gt; をそのまま使い、構文エラーがなくなったら
&lt;cite&gt;_build&lt;/cite&gt; ディレクトリにコピーできるようにします。&lt;/p&gt;
&lt;div class="section" id="id1"&gt;
&lt;h2&gt;ツールとパスの確認&lt;/h2&gt;
&lt;p&gt;まずは &lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt; の大枠を整えます。&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
APPNAME = 'pep8-test'
VERSION = '1.0.0'

top = '.'
out = '_build'


def configure(ctx):
    ctx.find_program('pep8')


def build(bld):
    f = bld.path.find_resource('pep8-test.py')
    print &amp;quot;f                     : %s&amp;quot; % f
    print &amp;quot;f.abspath()           : %s&amp;quot; % f.abspath()
    print &amp;quot;f.get_src().abspath() : %s&amp;quot; % f.get_src().abspath()
    print &amp;quot;f.get_bld().abspath() : %s&amp;quot; % f.get_bld().abspath()
&lt;/pre&gt;
&lt;p&gt;&lt;cite&gt;configure&lt;/cite&gt; で &lt;tt class="docutils literal"&gt;pep8&lt;/tt&gt; コマンドが存在しているかを確認します。
コマンドが見つからない場合は次のようなエラーになります。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ waf configure
Setting top to                           : /private/tmp/pep8-test
Setting out to                           : /private/tmp/pep8-test/_build
Checking for program pep8                : not found
Could not find the program pep8
(complete log in /private/tmp/pep8-test/_build/config.log)
&lt;/pre&gt;
&lt;p&gt;探索しているパスの一覧はログファイル (&lt;tt class="docutils literal"&gt;_build/config.log&lt;/tt&gt;) に記載されています。
環境変数が思い通りに設定できていない場合はこのファイルを確認します。&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;pep8&lt;/tt&gt; をインストールすると次のようにチェックされます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ waf configure
Setting top to                           : /private/tmp/pep8-test
Setting out to                           : /private/tmp/pep8-test/_build
Checking for program pep8                : /private/tmp/pep8-test/bin/pep8
'configure' finished successfully (0.004s)
&lt;/pre&gt;
&lt;p&gt;次に &lt;cite&gt;build&lt;/cite&gt; ターゲットを実行します。
ターゲットとするファイルを &lt;tt class="docutils literal"&gt;find_resource&lt;/tt&gt; で取得し、いくつかのパス表記を確認しています。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ waf build
Waf: Entering directory `/private/tmp/pep8-test/_build'
f                     : pep8-test.py
f.abspath()           : /private/tmp/pep8-test/pep8-test.py
f.get_src().abspath() : /private/tmp/pep8-test/pep8-test.py
f.get_bld().abspath() : /private/tmp/pep8-test/_build/pep8-test.py
Waf: Leaving directory `/private/tmp/pep8-test/_build'
'build' finished successfully (0.002s)
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;get_src()&lt;/tt&gt; と &lt;tt class="docutils literal"&gt;get_bld()&lt;/tt&gt; でノードが異なることが分かりますね。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="pep8-cp"&gt;
&lt;h2&gt;pep8 と cp&lt;/h2&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;pep8&lt;/tt&gt; で構文をチェックして &lt;tt class="docutils literal"&gt;cp&lt;/tt&gt; でビルドディレクトリにコピーするには、
&lt;cite&gt;build&lt;/cite&gt; ターゲットを次のように書き換えます。&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
def build(bld):
    f = bld.path.find_resource('pep8-test.py')
    bld(rule='pep8 ${SRC}', source=f)
    bld(rule='cp ${SRC} ${TGT}', source=f.get_src(), target=f.get_bld())
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;cp&lt;/tt&gt; コマンドを実行するタスクの &lt;cite&gt;target&lt;/cite&gt; 引数を間違えると依存関係がループしてしまいます。
&lt;cite&gt;get_bld()&lt;/cite&gt; を使うことで、明示的にビルドディレクトリのパスを指定します。
&lt;cite&gt;source&lt;/cite&gt; 引数は &lt;cite&gt;f&lt;/cite&gt; でも良いのですが、対称性のために &lt;cite&gt;get_src()&lt;/cite&gt; を明示的に呼び出しています。&lt;/p&gt;
&lt;p&gt;実行してからビルドディレクトリの中身を表示させます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ waf distclean configure build
'distclean' finished successfully (0.002s)
Setting top to                           : /private/tmp/pep8-test
Setting out to                           : /private/tmp/pep8-test/_build
Checking for program pep8                : /private/tmp/pep8-test/bin/pep8
'configure' finished successfully (0.004s)
Waf: Entering directory `/private/tmp/pep8-test/_build'
[1/2] pep8 ${SRC}: pep8-test.py
[2/2] pep8-test.py: pep8-test.py -&amp;gt; _build/pep8-test.py
../pep8-test.py:2:3: E111 indentation is not a multiple of four
../pep8-test.py:4:1: E302 expected 2 blank lines, found 1
Waf: Leaving directory `/private/tmp/pep8-test/_build'
Build failed
 -&amp;gt; task failed (exit status 1):
        {task 4556299536: pep8 ${SRC} pep8-test.py -&amp;gt; }
' pep8 ../pep8-test.py '

$ ls _build
c4che/        config.log    pep8-test.py
&lt;/pre&gt;
&lt;p&gt;どちらのタスクも実行されており、ビルドディレクトリに &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;pep8-test.py&lt;/span&gt;&lt;/tt&gt; がコピーされました。
しかし、 &lt;tt class="docutils literal"&gt;pep8&lt;/tt&gt; では構文エラーが報告されているのにコピーされてしまうのも困りものです。
それぞれのタスクが独立していると並列化させやすいですが、ここではそうではなく、
グループ化されていて欲しいところです。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h2&gt;タスクの順番を制御&lt;/h2&gt;
&lt;p&gt;Wafbook の &lt;a class="reference external" href="http://waf.googlecode.com/svn/docs/wafbook/single.html#_build_order_constraints"&gt;7.2. Build order constraints&lt;/a&gt; で３つの方法が説明されています。
タスクの &lt;tt class="docutils literal"&gt;set_run_after()&lt;/tt&gt; メソッドを呼び出す方法、
タスク定義に &lt;tt class="docutils literal"&gt;before&lt;/tt&gt; もしくは &lt;tt class="docutils literal"&gt;after&lt;/tt&gt; 属性を持たせる方法、
そして、タスクの順番を自前で管理する方法です。
最後の方法は &lt;a class="reference external" href="http://ja.wikipedia.org/wiki/%E3%82%B8%E3%83%A7%E3%83%96%E3%82%B7%E3%83%A7%E3%83%83%E3%83%97%E3%83%BB%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0%E5%95%8F%E9%A1%8C"&gt;ジョブショップ・スケジューリング問題&lt;/a&gt; (JSP) とも言われる問題領域ですから、
クリティカルパスがよほど単純な場合を除いては使わない方が良いと思います。&lt;/p&gt;
&lt;p&gt;さて、タスク定義は &lt;tt class="docutils literal"&gt;waflib.Task.Task&lt;/tt&gt; クラスを継承すれば良いので、
一番最初の方法 - &lt;tt class="docutils literal"&gt;set_run_after()&lt;/tt&gt; - が簡単そうです。&lt;/p&gt;
&lt;div class="section" id="id4"&gt;
&lt;h3&gt;スクリプト&lt;/h3&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;cp&lt;/tt&gt; 用のタスクと &lt;tt class="docutils literal"&gt;pep8&lt;/tt&gt; 用のタスクを定義します。
それぞれのタスクに入出力パスを設定したら、順序関係を設定します。&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
from waflib.Task import Task

class cp(Task): 
    def run(self): 
        return self.exec_command('cp %s %s' % (
                self.inputs[0].abspath(), self.outputs[0].abspath()
            ))

class pep8(Task):
    def run(self):
        return self.exec_command('pep8 %s' % (self.inputs[0].abspath(),))

def build(bld):
    f = bld.path.find_resource('pep8-test.py')
    t1 = pep8(env=bld.env)
    t1.set_inputs(f)
    t2 = cp(env=bld.env)
    t2.set_inputs(f.get_src())
    t2.set_outputs(f.get_bld())
    t2.set_run_after(t1)
    bld.add_to_group(t1)
    bld.add_to_group(t2)
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h3&gt;実行結果&lt;/h3&gt;
&lt;p&gt;実行してみると (&lt;tt class="docutils literal"&gt;pep8&lt;/tt&gt; でエラーの場合は) ビルドディレクトリに &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;pep8-test.py&lt;/span&gt;&lt;/tt&gt; がコピーされないことが分かります。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ waf distclean configure build
'distclean' finished successfully (0.002s)
Setting top to                           : /private/tmp/pep8-test
Setting out to                           : /private/tmp/pep8-test/_build
Checking for program pep8                : /private/tmp/pep8-test/bin/pep8
'configure' finished successfully (0.004s)
Waf: Entering directory `/private/tmp/pep8-test/_build'
[1/2] pep8: pep8-test.py
/private/tmp/pep8-test/pep8-test.py:2:3: E111 indentation is not a multiple of four
/private/tmp/pep8-test/pep8-test.py:4:1: E302 expected 2 blank lines, found 1
Waf: Leaving directory `/private/tmp/pep8-test/_build'
Build failed
 -&amp;gt; task failed (exit status 1):
        {task 4367677712: pep8 pep8-test.py -&amp;gt; }
''

$ ls _build
c4che/      config.log
&lt;/pre&gt;
&lt;p&gt;ソースコードを修正してから改めて実行してみると次のようになります。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ waf distclean configure build
'distclean' finished successfully (0.002s)
Setting top to                           : /private/tmp/pep8-test
Setting out to                           : /private/tmp/pep8-test/_build
Checking for program pep8                : /private/tmp/pep8-test/bin/pep8
'configure' finished successfully (0.005s)
Waf: Entering directory `/private/tmp/pep8-test/_build'
[1/2] pep8: pep8-test.py
[2/2] cp: pep8-test.py -&amp;gt; _build/pep8-test.py
Waf: Leaving directory `/private/tmp/pep8-test/_build'
'build' finished successfully (0.169s)

$ ls _build
c4che/        config.log    pep8-test.py
&lt;/pre&gt;
&lt;p&gt;先ほどの失敗した場合と比べて、２つのタスクの内２つとも実行されていることが分かります。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id6"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;Waf を使って &lt;tt class="docutils literal"&gt;pep8&lt;/tt&gt; で Python の構文をチェックしてからコピーする処理を記述しました。
同様にして &lt;tt class="docutils literal"&gt;nosetests&lt;/tt&gt; などもフックに入れておくと、ソースコードを編集する度にテストを実行できます。
なお、まだ確認していませんが、テストはテスト用の枠組みでも実行できるはずです。&lt;/p&gt;
&lt;p&gt;Waf 自体は Python で記述されていますが、そのターゲットの言語は選びません。
同じ方法は PHP にも適用可能で、 &lt;tt class="docutils literal"&gt;pep8&lt;/tt&gt; の代わりに &lt;tt class="docutils literal"&gt;php &lt;span class="pre"&gt;-l&lt;/span&gt;&lt;/tt&gt; を使うことになるでしょう。
フロントエンドのリソース - JavaScript, CSS - に対しては
YUI Compressor や Closure Tools でミニフィケーションできますね。&lt;/p&gt;
&lt;p&gt;また、ここでは &lt;tt class="docutils literal"&gt;find_resource()&lt;/tt&gt; を使ってノードを探し出しましたが、
&lt;tt class="docutils literal"&gt;ant_glob()&lt;/tt&gt; を使うと Ant の探索パターンを活用できます。
プロジェクトのソースコードが増えてきた場合にはこちらを使ってループ処理を回した方が自然だと思います。&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;Makefile&lt;/tt&gt; でも良いんだけど違う方法も覚えておきたい、
という場合には Waf も良さそうです。&lt;/p&gt;
&lt;p&gt;蛇足ながら、ここではテキスト表記ですが、実際にコンソールで動かすと色が付きます。
意外とこれで導入障壁が下がったりするかもしれませんね。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-2844891436491100509?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/2844891436491100509/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=2844891436491100509' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/2844891436491100509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/2844891436491100509'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/08/waf-validate-and-copy.html' title='Waf を使って構文チェックしてからコピーする'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-549211041404248079</id><published>2011-08-16T22:51:00.004+09:00</published><updated>2011-08-17T00:48:44.246+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Waf'/><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><category scheme='http://www.blogger.com/atom/ns#' term='Solr'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Waf から Solr を起動させる</title><content type='html'>&lt;p&gt;Waf を使うと、Python で色々な処理を記述できます。
Waf は普通は C 言語などのコンパイルに使いますが、
ある条件に従って何らかの処理を実行できると便利ですので、他のことにも流用してみます。
以前に、Solr をダウンロードして解凍できることを確認しましたので、
今回は、そこから Solr を起動させます。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/08/getting-started-waf.html"&gt;Waf を使う&lt;/a&gt; (2011年8月の記事)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://waf.googlecode.com/svn/docs/wafbook/single.html"&gt;The Waf Book&lt;/a&gt; (Google Code)&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;
&lt;div class="section" id="id1"&gt;
&lt;h1&gt;実行環境の準備&lt;/h1&gt;
&lt;p&gt;まずは &lt;cite&gt;virtualenv&lt;/cite&gt; で実行環境を作成し、 &lt;tt class="docutils literal"&gt;waf&lt;/tt&gt; コマンドを実行できるようにします。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ virtualenv --distribute solr-test
$ cd solr-test
$ source bin/activate
$ curl http://waf.googlecode.com/files/waf-1.6.7 &amp;gt;bin/waf
$ chmod +x bin/waf
$ waf
Waf: Run from a directory containing a file named 'wscript'
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt; が見つかりません、というエラーが表示されれば正常に設定できています。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="solr"&gt;
&lt;h1&gt;Solr を起動させる&lt;/h1&gt;
&lt;p&gt;Solr をダウンロードして解凍する処理は、以前の内容と似たような感じです。
Python の &lt;cite&gt;urllib&lt;/cite&gt; と &lt;cite&gt;tarfile&lt;/cite&gt; モジュールを使います。&lt;/p&gt;
&lt;p&gt;Solr の配布アーカイブには &lt;tt class="docutils literal"&gt;start.jar&lt;/tt&gt; というブートストラップが含まれています。
これは &lt;cite&gt;example&lt;/cite&gt; ディレクトリにありますので、そこへ移動し、JAR を実行します。
(その他の基本的な内容物に関してはこちらの記事で触れています -
&lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/07/dotcloud-solr-search.html"&gt;DotCloud で Solr を使ってみる&lt;/a&gt;)&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cd {apache-solr-dir}/example/
$ java -jar start.jar
&lt;/pre&gt;
&lt;p&gt;毎回これを実行しても構わないのですが、Solr の設定を変更したい場合にはちょっと不便です。
デフォルトでは実行したディレクトリ直下の &lt;tt class="docutils literal"&gt;solr&lt;/tt&gt; ディレクトリを見に行きますが、
たとえば、 &lt;cite&gt;/tmp/solr&lt;/cite&gt; から設定ファイルを読み込みたい場合には次のように引数を与えます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ java -Dsolr.solr.home=/tmp/solr -jar start.jar
&lt;/pre&gt;
&lt;p&gt;&amp;quot;solr.home&amp;quot; ではなく、&amp;quot;solr.solr.home&amp;quot; なので、分かっていても間違えてしまいます。
ということで、スクリプトにまとめておきたいわけです。&lt;/p&gt;
&lt;div class="section" id="id2"&gt;
&lt;h2&gt;スクリプト&lt;/h2&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt; にまとめると、次のようになります。&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
APPNAME = 'solr-test'
VERSION = '1.0.0'

top = '.'
out = '_build'

import urllib
import tarfile

from waflib.Task import Task

SOLR_VERSION = '3.3.0'
SOLR_PACKAGE = 'apache-solr-%s.tgz' % (SOLR_VERSION,)
SOLR_MIRROR = 'http://ftp.riken.jp/net/apache/lucene/solr/%s/%s' % (SOLR_VERSION, SOLR_PACKAGE)


def configure(ctx):
    p = ctx.path.find_resource(SOLR_PACKAGE)
    if p is None:
        urllib.urlretrieve(SOLR_MIRROR, SOLR_PACKAGE)
    jar = ctx.path.ant_glob('apache-solr-*/example/start.jar')
    if not jar:
        with tarfile.open(SOLR_PACKAGE) as tar:
            tar.extractall()


def run_solr(ctx):
    jar_dir = ctx.path.find_dir('apache-solr-%s/example' % (SOLR_VERSION,))
    solr_dir = ctx.path.find_node('solr')
    ctx.exec_command(['java', '-Dsolf.solr.home=%s' % (solr_dir.abspath(),),
                      '-jar', 'start.jar'], cwd=jar_dir.abspath())


&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt; においてファイルやディレクトリは「ノード」という単位で扱われます。
ノードの取得方法には数種類あり、上記のスクリプトでは次の４つを使っています。
(使い分けている、というよりは、複数種類を例示している。)&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;find_resource&lt;/tt&gt; : ビルドしたノードかソースファイルを探します。&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;find_dir&lt;/tt&gt;      : ファイルシステムからフォルダを探します。&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;find_node&lt;/tt&gt;     : ファイルシステムからファイルやフォルダを探します。&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;ant_glob&lt;/tt&gt;      : Ant のファイルマッチパターンに従ってファイルを探します。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;「ファイルシステムから」という記述に意味があり、
ビルドの依存関係を記述するためには、
ファイルシステムには存在しないノードを定義することになります。
とはいえ、ここでのスクリプトには関係ありませんので、無視しておきます。&lt;/p&gt;
&lt;p&gt;その他のノードの扱いは、ソースコードを読むのが最も手っ取り早いかもしれません...&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://waf.googlecode.com/svn/docs/apidocs/_modules/waflib/Node.html"&gt;Source code for waflib.Node&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h2&gt;実行方法&lt;/h2&gt;
&lt;p&gt;上記 &lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt; の &lt;cite&gt;configure&lt;/cite&gt; ターゲットを実行して、
アーカイブをダウンロードしてから展開します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ waf configure
&lt;/pre&gt;
&lt;p&gt;次に、設定ファイルを編集できるように、トップレベルにコピーします。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cp -r apache-solr-3.3.0/example/solr .
&lt;/pre&gt;
&lt;p&gt;最後に、 &lt;cite&gt;run_solr&lt;/cite&gt; ターゲットを実行します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ waf run_solr
&lt;/pre&gt;
&lt;p&gt;ブラウザで &lt;em&gt;http://localhost:8983/solr/admin&lt;/em&gt; にアクセスすると、
Solr の管理画面が表示されるはずです。&lt;/p&gt;
&lt;p&gt;あとは、 &lt;tt class="docutils literal"&gt;solr/conf&lt;/tt&gt; にあるファイルを編集することで、Solr の中身をカスタマイズできます。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;Waf から Solr を起動させてみました。
定型の処理ならシェルスクリプトにまとめてしまえば良いのですが、
Windows でも処理を自動化できると便利なこともあります。&lt;/p&gt;
&lt;p&gt;Waf だと単一のファイルを配置すれば良いだけですので、
簡単に手順を共有できそうですね。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-549211041404248079?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/549211041404248079/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=549211041404248079' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/549211041404248079'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/549211041404248079'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/08/waf-solr.html' title='Waf から Solr を起動させる'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-5881633478152863784</id><published>2011-08-14T22:25:00.003+09:00</published><updated>2011-08-17T00:49:25.518+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>Indexed Database API を使ってみる</title><content type='html'>&lt;p&gt;たまには Web 系技術もキャッチアップした方が良いかな、と思っていたら、
Indexed Database API のサンプルがありましたので模写しました。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://raw.github.com/gist/1045816/082e58e074dc6a46c2035e4e5a72c2d129aed1f6/IndexDB-demo3.html"&gt;IndexDB demo&lt;/a&gt; - original gist&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://skitazaki.appspot.com/works/indexeddb-demo.html"&gt;IndexedDB demo&lt;/a&gt; - 模写版&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/skitazaki/sandbox/blob/cf5cbdc877e79470e8060baaff09d2e311138d77/src/javascript/simple-usage-indexeddb.js"&gt;ソースコード&lt;/a&gt; - github.com&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;

&lt;p&gt;HTML5 でクライアント側にデータを保存するための仕様ですが、
この部分はバタバタしている印象があり、ブラウザベンダーによる実装差異も多そうですので、
きちんと動くサンプルを書くのは難しいと思います。
上記の模写版は Firefox 5 では動くはずですが、Webkit 系では動いたり動かなかったり。
(どこかで実装を間違えているっぽい...)&lt;/p&gt;
&lt;p&gt;なお、API の正式名称は &amp;quot;Indexed Database API&amp;quot; ですが、
省略形は &amp;quot;IndexDB&amp;quot; と &amp;quot;IndexedDB&amp;quot; が混在しているのかな、
といった状況です。
関係する仕様としては &amp;quot;Web Storage&amp;quot; と &amp;quot;Web SQL Database&amp;quot; がありますが、
前者は Key / Value を保存するもの、後者は SQL を使う仕様を策定してみたもののボツになったものです。
&amp;quot;Indexed Database API&amp;quot; と &amp;quot;Web Storage&amp;quot; はどちらも NoSQL ですが、
データを一覧表示するかしないかの違いとも考えられます。
IndexedDB を使って Key / Value も実現できますが、本当に Key に対する Value が欲しいだけなら
localStorage (Web Storage の一部) を使う方が簡単です。
どれも名前と使いどころくらいは知っておいた方が良さそうです。&lt;/p&gt;
&lt;p&gt;&amp;quot;Indexed Database API&amp;quot; は基本的に非同期処理でコールバックを多用する必要がありますので、
抽象化ライブラリを作ってメソッドチェーンでつなげるようにするべきなんだろうな、と思います。
jQuery における jqXHR のようなオブジェクトが出てくるかもしれませんね。
(同期処理でデータを操作するのは、ユーザーへの応答性という点でイマイチなはず)&lt;/p&gt;
&lt;p&gt;API の細かい使い方は Mozilla の記事 (英語、下記リンク) に書かれています。
カーソルの受け渡しに慣れてくればサクサク記述できると思いますが、
コールバックのつなげ方は実装の試行錯誤が必要になりそうです。
あと、開発者コンソールかなんかでデータを確認できるようになると嬉しいですね。&lt;/p&gt;
&lt;div class="section" id="id2"&gt;
&lt;h1&gt;リンク&lt;/h1&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.w3.org/TR/IndexedDB/"&gt;Indexed Database API&lt;/a&gt; - w3.org&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.w3.org/TR/webstorage/"&gt;Web Storage&lt;/a&gt; (sessionStorage, localStorage) - w3.org&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.w3.org/TR/webdatabase/"&gt;Web SQL Database&lt;/a&gt; (no longer inactive) - w3.org&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://developer.mozilla.org/en/IndexedDB/Using_IndexedDB"&gt;Using IndexedDB&lt;/a&gt; - MDN&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://code.google.com/p/indexeddb/"&gt;Indexed Database API W3C Draft Implementation&lt;/a&gt; - indexeddb&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://d.hatena.ne.jp/pikotea/20110120/1295494166"&gt;Indexed Database API について&lt;/a&gt; - へっぽこプログラマーの日記&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://blog.livedoor.jp/kotesaki/archives/1605197.html"&gt;indexedDB を触ってみた&lt;/a&gt; - こてさきAjax&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.infoq.com/jp/news/2011/08/LevelDB"&gt;Googleは、Key-ValueデータストアであるLevelDBをオープンソース化した&lt;/a&gt; - InfoQ&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-5881633478152863784?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/5881633478152863784/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=5881633478152863784' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/5881633478152863784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/5881633478152863784'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/08/indexed-database-api.html' title='Indexed Database API を使ってみる'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-1806164063868482837</id><published>2011-08-12T23:02:00.006+09:00</published><updated>2011-08-17T00:50:25.923+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Script'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>docutils でブログ記事作成</title><content type='html'>&lt;p&gt;ブログの記事は &lt;a class="reference external" href="http://docutils.sourceforge.net/rst.html"&gt;reST&lt;/a&gt; (reStructuredText) で書いて HTML に変換していますが、
パソコンを買い替えたので環境を移行しなければなりません。
ということで、メモを書いておきます。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;

&lt;div class="section" id="id1"&gt;
&lt;h1&gt;docutils のインストール&lt;/h1&gt;
&lt;p&gt;まずは &lt;a class="reference external" href="http://docutils.sourceforge.net/index.html"&gt;Docutils&lt;/a&gt; モジュールをインストールします。
&lt;a class="reference external" href="http://sphinx.pocoo.org"&gt;Sphinx&lt;/a&gt; をインストールすれば依存関係でインストールされていますが、
そうでない場合は個別にインストールします。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ site=blog-site
$ virtualenv --distribute $site
$ cd $site
$ . bin/activate
$ pip install docutils
&lt;/pre&gt;
&lt;p&gt;&lt;cite&gt;docutils&lt;/cite&gt; には &lt;em&gt;rst&lt;/em&gt; から始まる Python スクリプトがいくつか付属しています。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ ls bin/rst*.py
bin/rst2html.py
bin/rst2latex.py
bin/rst2man.py
bin/rst2odt.py
bin/rst2odt_prepstyles.py
bin/rst2pseudoxml.py
bin/rst2s5.py
bin/rst2xetex.py
bin/rst2xml.py
bin/rstpep2html.py
&lt;/pre&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;rst2html.py&lt;/tt&gt; を使うと、 reST で記述されたファイルを HTML に変換できます。
たとえば、 &lt;tt class="docutils literal"&gt;article.rst&lt;/tt&gt; というファイルを HTML に変換する場合には次のように実行します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ rst2html.py article.rst &amp;gt;article.html
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;ブログ記事に使う&lt;/h1&gt;
&lt;p&gt;プレビュー用と投稿用の HTML を生成できるようにします。
ブログ投稿用のアプリケーションを使えばそんなものは必要ないかもしれませんが、
HTML をベタ書きできた方が何かと都合が良いこともありそうなので、
この方法にしています。&lt;/p&gt;
&lt;p&gt;プレビュー用の HTML は先ほどのコマンドで生成できます。
しかし、投稿用には HTML の &lt;tt class="docutils literal"&gt;&amp;lt;head&amp;gt;&lt;/tt&gt; タグなどは不要ですので、
これを取り除くことにします。&lt;/p&gt;
&lt;p&gt;２種類のアプローチが考えられますが、ここでは後者を採用します。&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;生成された HTML をパースして、 &lt;tt class="docutils literal"&gt;&amp;lt;body&amp;gt;&lt;/tt&gt; の中を抽出する。&lt;/li&gt;
&lt;li&gt;そもそも HTML の &lt;tt class="docutils literal"&gt;&amp;lt;body&amp;gt;&lt;/tt&gt; だけを生成させる。&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="section" id="rst2html-py"&gt;
&lt;h2&gt;rst2html.py のオプション&lt;/h2&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;rst2html.py&lt;/tt&gt; に &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--help&lt;/span&gt;&lt;/tt&gt; オプションをつけて実行すると、
たくさんのオプションが利用できることが分かります。
なんとなくメモしておくものだけを抜粋して日本語にしておきます。&lt;/p&gt;
&lt;table class="docutils option-list" frame="void" rules="none"&gt;
&lt;col class="option" /&gt;
&lt;col class="description" /&gt;
&lt;tbody valign="top"&gt;
&lt;tr&gt;&lt;td class="option-group" colspan="2"&gt;
&lt;kbd&gt;&lt;span class="option"&gt;--strip-comments&lt;/span&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/td&gt;&lt;td&gt;コメント要素を除去します。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="option-group" colspan="2"&gt;
&lt;kbd&gt;&lt;span class="option"&gt;--leave-comments&lt;/span&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;コメント要素を残しておきます。 (default)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="option-group" colspan="2"&gt;
&lt;kbd&gt;&lt;span class="option"&gt;--input-encoding=&lt;var&gt;&amp;lt;name[:handler]&amp;gt;&lt;/var&gt;&lt;/span&gt;, &lt;span class="option"&gt;-i &lt;var&gt;&amp;lt;name[:handler]&amp;gt;&lt;/var&gt;&lt;/span&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;入力テキストのエンコーディングと、オプションで
エラーハンドラーを設定します。
Default: &amp;lt;locale-dependent&amp;gt;:strict.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="option-group" colspan="2"&gt;
&lt;kbd&gt;&lt;span class="option"&gt;--input-encoding-error-handler=&lt;var&gt;INPUT_ENCODING_ERROR_HANDLER&lt;/var&gt;&lt;/span&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;デコードできない文字に対するエラーハンドラーを設定します。
Choices: &amp;quot;strict&amp;quot; (default), &amp;quot;ignore&amp;quot;, and &amp;quot;replace&amp;quot;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="option-group" colspan="2"&gt;
&lt;kbd&gt;&lt;span class="option"&gt;--output-encoding=&lt;var&gt;&amp;lt;name[:handler]&amp;gt;&lt;/var&gt;&lt;/span&gt;, &lt;span class="option"&gt;-o &lt;var&gt;&amp;lt;name[:handler]&amp;gt;&lt;/var&gt;&lt;/span&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;出力テキストのエンコーディングと、オプションで
エラーハンドラーを設定します。
Default: UTF-8:strict.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="option-group" colspan="2"&gt;
&lt;kbd&gt;&lt;span class="option"&gt;--output-encoding-error-handler=&lt;var&gt;OUTPUT_ENCODING_ERROR_HANDLER&lt;/var&gt;&lt;/span&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;デコードできない文字に対するエラーハンドラーを設定します。
&amp;quot;strict&amp;quot; (default), &amp;quot;ignore&amp;quot;, &amp;quot;replace&amp;quot;, &amp;quot;xmlcharrefreplace&amp;quot;, &amp;quot;backslashreplace&amp;quot;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="option-group" colspan="2"&gt;
&lt;kbd&gt;&lt;span class="option"&gt;--language=&lt;var&gt;&amp;lt;name&amp;gt;&lt;/var&gt;&lt;/span&gt;, &lt;span class="option"&gt;-l &lt;var&gt;&amp;lt;name&amp;gt;&lt;/var&gt;&lt;/span&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;言語を設定します。 (BCP 47 言語表記).
Default: en.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="option-group" colspan="2"&gt;
&lt;kbd&gt;&lt;span class="option"&gt;--no-file-insertion&lt;/span&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;外部ファイルのコンテンツを挿入するディレクティブを無効にします。
ディレクティブは &amp;quot;include&amp;quot; と &amp;quot;raw&amp;quot; です。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="option-group" colspan="2"&gt;
&lt;kbd&gt;&lt;span class="option"&gt;--file-insertion-enabled&lt;/span&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;外部ファイルのコンテンツを挿入するディレクティブを有効にします。
ディレクティブは &amp;quot;include&amp;quot; と &amp;quot;raw&amp;quot; です。
Enabled by default.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="option-group" colspan="2"&gt;
&lt;kbd&gt;&lt;span class="option"&gt;--no-raw&lt;/span&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;quot;raw&amp;quot; ディレクティブを無効にします。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="option-group" colspan="2"&gt;
&lt;kbd&gt;&lt;span class="option"&gt;--raw-enabled&lt;/span&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;&amp;quot;raw&amp;quot; ディレクティブを有効にします。 Enabled by default.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="option-group" colspan="2"&gt;
&lt;kbd&gt;&lt;span class="option"&gt;--template=&lt;var&gt;&amp;lt;file&amp;gt;&lt;/var&gt;&lt;/span&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;テンプレートファイルを指定します。
テンプレートファイルは UTF-8 でエンコードされていなければなりません。
Default is &amp;quot;lib/python2.7/site-packages/docutils/writers/html4css1/template.txt&amp;quot;.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="option-group" colspan="2"&gt;
&lt;kbd&gt;&lt;span class="option"&gt;--stylesheet=&lt;var&gt;&amp;lt;URL&amp;gt;&lt;/var&gt;&lt;/span&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;スタイルシートの URL をカンマ区切りで指定します。
--stylesheet と --stylesheet-path の設定を上書きます。&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="option-group" colspan="2"&gt;
&lt;kbd&gt;&lt;span class="option"&gt;--stylesheet-path=&lt;var&gt;&amp;lt;file&amp;gt;&lt;/var&gt;&lt;/span&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;スタイルシートのパスをカンマ区切りで指定します。
--link-stylesheet があると、出力する HTML の相対パスとしてパスは上書きされます。
Default: &amp;quot;lib/python2.7/site-packages/docutils/writers/html4css1/html4css1.css&amp;quot;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="option-group" colspan="2"&gt;
&lt;kbd&gt;&lt;span class="option"&gt;--embed-stylesheet&lt;/span&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;出力する HTML にスタイルシートを埋め込みます。
スタイルシートファイルは、処理中にアクセスできなければなりません。
This is the default.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="option-group" colspan="2"&gt;
&lt;kbd&gt;&lt;span class="option"&gt;--link-stylesheet&lt;/span&gt;&lt;/kbd&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&amp;nbsp;&lt;/td&gt;&lt;td&gt;出力する HTML にスタイルシートをリンクさせます。
Default: embed stylesheets.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;この中に、 &lt;em&gt;--template&lt;/em&gt; オプションがあります。
ヘルプメッセージに表示されるデフォルトのテンプレートは次のようになっています。&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
%(head_prefix)s
%(head)s
%(stylesheet)s
%(body_prefix)s
%(body_pre_docinfo)s
%(docinfo)s
%(body)s
%(body_suffix)s
&lt;/pre&gt;
&lt;p&gt;見た目のままですが、 &lt;tt class="docutils literal"&gt;$(body)s&lt;/tt&gt; だけにすると、文章部分だけを出力できます。
つまり、次のように実行できます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ rst2html.py --template=blog-template.txt article.rst &amp;gt;article-body.html
&lt;/pre&gt;
&lt;p&gt;これでも目的は達成できますが、出力ファイル名をいちいち入力するのは面倒ですから、
Python スクリプトにまとめることにします。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="python"&gt;
&lt;h2&gt;Python スクリプトで使う&lt;/h2&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;rst2html.py&lt;/tt&gt; は単なるラッパースクリプトで、内部的には
&lt;tt class="docutils literal"&gt;docutils.core.publish_cmdline()&lt;/tt&gt; を呼び出しています。
つまり、 &lt;tt class="docutils literal"&gt;subprocess.call()&lt;/tt&gt; で &lt;tt class="docutils literal"&gt;rst2html.py&lt;/tt&gt; を呼び出すこともできますし、
&lt;tt class="docutils literal"&gt;docutils.core.publish_cmdline()&lt;/tt&gt; を使うこともできます。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;docutils&lt;/em&gt; のモジュールを使う場合は、次のようなスクリプトにまとめられます。&lt;/p&gt;
&lt;div class="section" id="id4"&gt;
&lt;h3&gt;スクリプト&lt;/h3&gt;
&lt;pre class="prettyprint"&gt;
__doc__ = &amp;quot;&amp;quot;&amp;quot;
python %prog {manuscript}

Parse a reST manuscript and write out it in two way HTML formats.
A file whose suffix is &amp;quot;.html&amp;quot; is for preview, and a file whose suffix
is &amp;quot;.txt&amp;quot; is for blogger's article.
&amp;quot;&amp;quot;&amp;quot;

import optparse
import os
import tempfile

from docutils.core import publish_cmdline

# see: lib/python2.7/site-packages/docutils/writers/html4css1/template.txt
RST_TEMPLATE_SOURCE = '''
%(body)s
'''

def parse_args():
    parser = optparse.OptionParser(__doc__)

    opts, args = parser.parse_args()

    if not args:
        parser.error(&amp;quot;no arguments found.&amp;quot;)

    return args


def publish_restructured_text(manuscript):
    fname = tempfile.mktemp()
    with open(fname, 'w') as temp:
        temp.write(RST_TEMPLATE_SOURCE)
    basic_option = ['--strip-comments']
    basename, _ = os.path.splitext(os.path.basename(manuscript))
    source = '%s.txt' % (basename,)
    preview = '%s.html' % (basename,)
    argv = ['--template=%s' % (fname,), manuscript, source]
    publish_cmdline(writer_name='html', argv=basic_option+argv)
    argv = [manuscript, preview]
    publish_cmdline(writer_name='html', argv=basic_option+argv)
    os.unlink(fname)
    print &amp;quot;Write as single HTML page and only body element.&amp;quot;
    print &amp;quot;  single page : %s (%dbytes)&amp;quot; % (preview, os.path.getsize(preview))
    print &amp;quot;  only body   : %s (%dbytes)&amp;quot; % (source, os.path.getsize(source))


def main():
    manuscripts = parse_args()

    for manuscript in manuscripts:
        if os.path.exists(manuscript):
            publish_restructured_text(manuscript)
        else:
            print &amp;quot;%s is not found.&amp;quot; % (manuscript,)

&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;Mac を買い替えたので環境を移行する必要がありました。
整理がてら記事にしましたが、必ずしも &lt;cite&gt;docutils&lt;/cite&gt; で頑張る必要もなく、
&lt;cite&gt;Sphinx&lt;/cite&gt; でラップした方が良いかもしれません。
ともあれ、まずは愚直に移行することにしました。&lt;/p&gt;
&lt;p&gt;その他、テキストファイルで原稿を書いてブログで公開するソフトウェアはいくつかあります。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.moongift.jp/2011/08/20110810-2/"&gt;プログラマ向けのテキストファイル変換型のブログエンジン「Octopress」&lt;/a&gt; - MOON GIFT&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://jekyllrb.com/"&gt;jekyll&lt;/a&gt; (&lt;a class="reference external" href="http://css.studiomohawk.com/tool/2011/06/11/jekyll-101.tool/"&gt;jekyll 日本語説明&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Web サービスを使えない状況や、単一のドキュメントを整形する場合には、
このような方法も便利かもしれませんね。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-1806164063868482837?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/1806164063868482837/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=1806164063868482837' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/1806164063868482837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/1806164063868482837'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/08/docutils-blog-article.html' title='docutils でブログ記事作成'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-4806899874392192861</id><published>2011-08-09T23:03:00.004+09:00</published><updated>2011-08-17T00:52:25.989+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Waf'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Waf を使う</title><content type='html'>&lt;p&gt;Waf を使ってみます。
ここでの Waf とは、Web Application Framework や
Web Application Firewall の略ではなく、
Python で記述されたビルドシステムのことです。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://code.google.com/p/waf/"&gt;Waf&lt;/a&gt; - Google Code&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://waf.googlecode.com/svn/docs/wafbook/single.html"&gt;The Waf Book&lt;/a&gt; - Google Code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ツールの導入部分に関してはこちらの記事で紹介されています。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://d.hatena.ne.jp/tanakh/20100212"&gt;waf チュートリアル&lt;/a&gt; (純粋関数型雑記帳)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;この記事では、何かをビルドする、というわけではなく、
アーキテクチャに依存せずに手続きを実行できるようにします。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;

&lt;p&gt;例として、Solr をダウンロードして解凍する処理を記述します。
Linux では &lt;tt class="docutils literal"&gt;wget&lt;/tt&gt; と &lt;tt class="docutils literal"&gt;tar&lt;/tt&gt; を使うだけですが、
Windows だとコマンドラインでダウンロード処理を記述するのが難しく、
Mac OSX Lion には &lt;tt class="docutils literal"&gt;wget&lt;/tt&gt; は付属していないため &lt;tt class="docutils literal"&gt;curl&lt;/tt&gt; を使うことになるでしょう。
もちろん、Windows に Cygwin をインストールしたり、Mac に &lt;tt class="docutils literal"&gt;wget&lt;/tt&gt; をインストールすれば同じコマンド群を使えますが、
その手間が面倒だと感じられることが &lt;cite&gt;Waf&lt;/cite&gt; を使う動機です。&lt;/p&gt;
&lt;p&gt;とはいっても Python をインストールしておく必要があります。
そこはなんとか乗り越えてもらいたいですね。&lt;/p&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;実行環境の準備&lt;/h1&gt;
&lt;p&gt;Mac OSX Lion での設定例を示します。
Python は元から入っていますので、virtualenv を使えるようにしておきます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ curl -O http://python-distribute.org/distribute_setup.py
$ sudo python distribute_setup.py
$ sudo easy_install pip
$ sudo pip install virtualenv
&lt;/pre&gt;
&lt;p&gt;次に、適当なディレクトリを作成し、独立した Python の実行環境を作成します。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ virtualenv --distribute solr-test
$ cd solr-test
$ source bin/activate
$ curl http://waf.googlecode.com/files/waf-1.6.6 &amp;gt;bin/waf
$ chmod +x bin/waf
$ waf
&lt;/pre&gt;
&lt;p&gt;これでおしまいです。
waf は単体のファイルとして配布されており、最初の実行時に展開されます。
&lt;cite&gt;virtualenv&lt;/cite&gt; を使っておくと、パスの調整も必要ありませんので、便利だと思います。&lt;/p&gt;
&lt;p&gt;Windows の場合はちょっとしたバッチファイルを用意しておくと便利かもしれません。
&lt;cite&gt;virtualenv&lt;/cite&gt; で環境を作成しておくと &lt;cite&gt;Scripts&lt;/cite&gt; フォルダもパスに追加されます。
Windows では拡張子が &lt;cite&gt;.bat&lt;/cite&gt; のファイルは拡張子なしで実行できますので、
&lt;tt class="docutils literal"&gt;Scripts/waf.bat&lt;/tt&gt; として以下のファイルを作成しておきます。&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
&amp;#64;echo off
python Scripts\waf-1.6.6 %*
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="solr"&gt;
&lt;h1&gt;Solr をダウンロードして解凍&lt;/h1&gt;
&lt;p&gt;Solr をダウンロードして解凍する処理を記述してみます。&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;Waf&lt;/cite&gt; では &lt;tt class="docutils literal"&gt;waf&lt;/tt&gt; コマンドを実行すると &lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt; ファイルを探しにいきます。
これはデフォルトのビルドスクリプトで、 &lt;tt class="docutils literal"&gt;make&lt;/tt&gt; における &lt;tt class="docutils literal"&gt;Makefile&lt;/tt&gt; に相当します。
いくつかのルールに注意する必要はありますが、普通の Python スクリプトも記述できます。&lt;/p&gt;
&lt;p&gt;つまり、ファイルのダウンロードには &lt;tt class="docutils literal"&gt;urllib.urlretrieve&lt;/tt&gt; 、
&lt;cite&gt;tar.gz&lt;/cite&gt; の解凍には &lt;tt class="docutils literal"&gt;tarfile&lt;/tt&gt; の &lt;tt class="docutils literal"&gt;extractall&lt;/tt&gt; を使えます。&lt;/p&gt;
&lt;p&gt;実際に書いてみると次のようになりました。
&lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt; として保存し、 &lt;tt class="docutils literal"&gt;waf&lt;/tt&gt; コマンドを実行すると実行できます。
(Solr 3.1 を使うのは、dotcloud のバージョンに合わせるため - &lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/07/dotcloud-solr-search.html"&gt;DotCloud で Solr を使ってみる&lt;/a&gt;)&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
APPNAME = 'solr-test'
VERSION = '1.0.0'

top = '.'
out = '_build'

from waflib.Task import Task
import urllib
import os
import tarfile

SOLR_VERSION = '3.1.0'
SOLR_PACKAGE = 'apache-solr-%s.tgz' % (SOLR_VERSION,)
SOLR_MIRROR = 'http://ftp.riken.jp/net/apache/lucene/solr/%s/%s' % (SOLR_VERSION, SOLR_PACKAGE)

class solr(Task):

    def run(self):
        p = self.inputs[0].abspath()
        if not os.path.exists(p):
            urllib.urlretrieve(SOLR_MIRROR, p)
        d, _ = os.path.splitext(p)
        if not os.path.exists(d):
            with tarfile.open(p) as tar:
                tar.extractall()

def configure(ctx):
    print('configure &amp;quot;%s&amp;quot;.' % (APPNAME,))

def build(bld):
    solr_task = solr(env=bld.env)
    solr_task.set_inputs(bld.path.find_resource(SOLR_PACKAGE))
    bld.add_to_group(solr_task)
&lt;/pre&gt;
&lt;p&gt;慣れないと不思議な記述も多いですが、次の４つの変数は予約語です。
(自分ルールとして、一番上に書いておく)&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;APPNAME : ソフトウェアの名前。&lt;/li&gt;
&lt;li&gt;VERSION : ソフトウェアのバージョン。&lt;/li&gt;
&lt;li&gt;top : 基準とするディレクトリ。普通はカレント。&lt;/li&gt;
&lt;li&gt;out : コンパイルしたファイルなどの出力先ディレクトリ。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;次の２つの関数は組み込みのものを上書きしています。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;configure : コンパイル先ディレクトリの生成など。前処理。&lt;/li&gt;
&lt;li&gt;build : デフォルトのビルドターゲット。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt; の関数は「コンテキスト」を意識して記述しなければなりません。
上記のいずれも引数オブジェクトが「コンテキスト」ですが、
実際のクラス (型) が異なります。
The Waf Book の 2.1.2 の NOTE には次のように記載されています。&lt;/p&gt;
&lt;blockquote&gt;
The context parameter is a new object for each command executed.
The classes are also different: ConfigureContext for configure,
BuildContext for build, OptionContext for option, and Context for any other command.&lt;/blockquote&gt;
&lt;p&gt;日本語混じりにすると次のような感じでしょうか。&lt;/p&gt;
&lt;blockquote&gt;
コンテキストパラメータは、それぞれの実行コマンドごとの新しいオブジェクトです。
クラスはコマンドごとに異なります。
configure には ConfigureContext、build には BuildContext、option には OptionContext、
それ以外のコマンドに対しては Context になっています。&lt;/blockquote&gt;
&lt;p&gt;個人的にはここがちょっとした嵌まりドコロで、ドキュメントの最初の方には
&lt;tt class="docutils literal"&gt;hello&lt;/tt&gt; やら &lt;tt class="docutils literal"&gt;ping&lt;/tt&gt;, &lt;tt class="docutils literal"&gt;pong&lt;/tt&gt; などがありましたので、
名前はなんでも良いのかな、と思いましたが、そうでもないようです。&lt;/p&gt;
&lt;p&gt;関数名は &lt;tt class="docutils literal"&gt;waf&lt;/tt&gt; コマンドの引数に対応しますが、
自由に付けた関数名には BuildContext が渡ってこないために迷いました。
とは言え、タスクは自作できますので、慣れれば自由に記述できそうな気がします。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;Python で記述されたビルドシステム - Waf - を使ってみました。
Python さえ利用可能ならば特別なインストールはいりません。
ここでは、環境による影響範囲を限定するため、パスの設定を簡単にするため、
この２点により &lt;cite&gt;virtualenv&lt;/cite&gt; を使いました。&lt;/p&gt;
&lt;p&gt;&lt;tt class="docutils literal"&gt;wscript&lt;/tt&gt; では Python のモジュールを自由に利用できます。
もちろん &lt;tt class="docutils literal"&gt;Makefile&lt;/tt&gt; でもたくさんのコマンドを使えますので、
表現力はあまり変わらないかもしれません。
しかし、Windows 環境でも使えるのは大きなアドバンテージだと思います。&lt;/p&gt;
&lt;p&gt;Python でのビルドシステムと言えば &lt;a class="reference external" href="http://www.scons.org/"&gt;Scons&lt;/a&gt; もあります。
これはこれで良いシステムだと思いますが、 &lt;cite&gt;virtualenv&lt;/cite&gt; との相性がよくありません。
設定ベースで考えるなら &lt;a class="reference external" href="http://pypi.python.org/pypi/zc.buildout"&gt;zc.buildout&lt;/a&gt; もあります。
ケースバイケースで使い分けるのが良いのではないでしょうか。&lt;/p&gt;
&lt;p&gt;この記事では取り上げていませんが、Waf も他のビルドシステムと同様に、
依存関係を定義すること、ルールを階層化して適用することができます。
ダラダラと記述して大変になってしまう可能性もありますが、
Windows でも処理の自動化を視野に入れると、知っていると便利だと思います。&lt;/p&gt;
&lt;p&gt;蛇足ですが、モダンな Python ハッカーには &lt;a class="reference external" href="http://fabfile.org"&gt;Fabric&lt;/a&gt; が良いそうです。
Python のバージョンもモダンに限定できる場合には便利そうですね。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.clemesha.org/blog/modern-python-hacker-tools-virtualenv-fabric-pip"&gt;Tools of the Modern Python Hacker: Virtualenv, Fabric and Pip&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-4806899874392192861?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/4806899874392192861/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=4806899874392192861' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/4806899874392192861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/4806899874392192861'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/08/getting-started-waf.html' title='Waf を使う'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-3115643350519202157</id><published>2011-08-01T00:12:00.002+09:00</published><updated>2011-08-17T00:53:12.677+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='旅行'/><title type='text'>九州旅行 in 2011</title><content type='html'>&lt;p&gt;サッカーを観戦して新幹線に乗りに九州まで行ってきました。&lt;/p&gt;
&lt;div style="text-align:center;"&gt;
&lt;iframe width="425" height="349" src="http://www.youtube.com/embed/UNbJzCFgjnU" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;a name='more'&gt;&lt;/a&gt;

&lt;div class="section" id="id2"&gt;
&lt;h1&gt;7月30日 (土)&lt;/h1&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;飛行機で羽田空港から福岡空港へ&lt;/li&gt;
&lt;li&gt;車で友達に拾ってもらって、レベルファイブスタジアムを見学してから小倉港へ&lt;/li&gt;
&lt;li&gt;名物「焼きカレー」を食べてから巌流島へ&lt;/li&gt;
&lt;li&gt;小倉駅付近でホテルを探してチェックイン&lt;/li&gt;
&lt;li&gt;本城競技場へ行って J2 観戦&lt;/li&gt;
&lt;li&gt;ホテル付近で晩ご飯&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;北九州市の高速道路が非常にややこしく、運転が大変そうでした。
高速道路のインターチェンジで右から合流するパターンはやめて欲しいなぁ、と思います。
都内の首都高でも怖いパターンです。&lt;/p&gt;
&lt;p&gt;巌流島は宮本武蔵と佐々木小次郎の決闘の舞台として有名ですが、
現在の島の面積は当時の6倍にもなるそうです。
今はきれいな公園風になっており、関門橋を見るには絶好のロケーションです。
なお、決闘のくだりに関しては Wikipedia の記事に詳述されています。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://ja.wikipedia.org/wiki/%E5%AE%AE%E6%9C%AC%E6%AD%A6%E8%94%B5#.E5.B7.8C.E6.B5.81.E5.B3.B6"&gt;宮本武蔵 - 巌流島&lt;/a&gt; (wikipedia)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;J2 の試合ではFC東京が負けてしまいましたが、
翌朝の地元のラジオでは「あのFC東京に勝った！」という扱いだったのが印象的です。
これを機にサッカーの裾野が広がってくれると良いですね。
とはいえ、東京にはそんなこと言ってる余裕が...ぁ&lt;/p&gt;
&lt;p&gt;晩ご飯は現地の居酒屋に行きましたが、価格が良心的でした。
九州と言えば焼酎のイメージしかなく、料理の味付けに関しては身構えずに行きましたが、
関西よりは関東よりの味付けに近い感じでした。
単なるお店による違いかもしれませんが、おいしいお店でした。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://r.tabelog.com/fukuoka/A4004/A400402/40003022/"&gt;とんとん&lt;/a&gt; (食べログ)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h1&gt;7月31日 (日)&lt;/h1&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;ホテルから博多駅へ&lt;/li&gt;
&lt;li&gt;新幹線で博多駅から鹿児島中央駅へ&lt;/li&gt;
&lt;li&gt;路面電車 (市鉄) で中央駅から水族館前へ&lt;/li&gt;
&lt;li&gt;フェリー乗り場まで数分歩く&lt;/li&gt;
&lt;li&gt;フェリーに乗って桜島へ&lt;/li&gt;
&lt;li&gt;桜島でレンタサイクル&lt;/li&gt;
&lt;li&gt;逆順に博多駅に戻る&lt;/li&gt;
&lt;li&gt;地下鉄で博多駅から空港駅へ&lt;/li&gt;
&lt;li&gt;飛行機で福岡空港から羽田空港へ&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;博多駅は数ヶ月前にリニューアルされたそうです。
駅前ではミストシャワーが動いており、涼しげな雰囲気でした。
新幹線乗り場には宣伝も多く、写真を撮っている人もまだまだいました。
車内も快適で、座席がちょっと広々していました。
なお、切符には２枚切符「博多〜鹿児島」というものがあり、当日購入でもちょっとお得なようです。&lt;/p&gt;
&lt;p&gt;九州新幹線の終点である鹿児島中央駅には観光案内所があります。
ここで桜島の観光マップをもらえます。
また、観光案内所から出口方面にかけてコインロッカーが充実していますので、
多少は大きな荷物があっても安心です。&lt;/p&gt;
&lt;p&gt;市電 (トラム) に乗って鹿児島駅の少し手前で降ります。
フェリー乗り場駅と水族館前のどちらでも構いませんが、
水族館前の方が近いよ、と市電に乗るときに観光ガイドの人が教えてくれました。&lt;/p&gt;
&lt;p&gt;桜島のフェリー乗り場を降りるとすぐにレンタカー屋さんがあります。
ここで自転車も借りられます。
借りる目安時間を伝えると、その時間に合わせたコースを教えてくれます。
上り下りがありますが、車の少ない道を走るととても快適で、山と岩と海の景色がきれいでした。
道には時折、灰が積もっており、別世界にやってきたなぁ、という気持ちになります。&lt;/p&gt;
&lt;p&gt;そうこうしている内に帰る時間になりますので、新幹線で博多に戻ります。
航空券を「羽田→福岡 + 鹿児島→羽田」で購入できれば良かったのですが、初動が遅くて売り切れでした。
博多駅と福岡空港は地下鉄で数分ですが、接続を考えると意外と時間がかかります。
複数の経路を扱ってくれる旅行代理店が増えると良いのになぁ、と思いました。&lt;/p&gt;
&lt;div style="text-align:center;"&gt;
&lt;embed type="application/x-shockwave-flash" src="https://picasaweb.google.com/s/c/bin/slideshow.swf" width="400" height="267" flashvars="host=picasaweb.google.com&amp;hl=ja&amp;feat=flashalbum&amp;RGB=0x000000&amp;feed=https%3A%2F%2Fpicasaweb.google.com%2Fdata%2Ffeed%2Fapi%2Fuser%2Fskitazaki%2Falbumid%2F5635898948941077537%3Falt%3Drss%26kind%3Dphoto%26hl%3Dja" pluginspage="http://www.macromedia.com/go/getflashplayer"&gt;&lt;/embed&gt;
&lt;/div&gt;
&lt;p&gt;たまにはフラッと旅行に行くのも良いですね。&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-3115643350519202157?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/3115643350519202157/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=3115643350519202157' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/3115643350519202157'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/3115643350519202157'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/08/trip-around-kyusyu.html' title='九州旅行 in 2011'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://img.youtube.com/vi/UNbJzCFgjnU/default.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-3325352176387959126</id><published>2011-07-27T21:10:00.004+09:00</published><updated>2011-08-17T00:56:01.221+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Solr'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>DotCloud で Solr を使ってみる</title><content type='html'>&lt;p&gt;&lt;a class="reference external" href="https://www.dotcloud.com/"&gt;DotCloud&lt;/a&gt; で Solr 3.1 を使えるようなので、簡単な検索 Web アプリを作ってみます。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;

&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://docs.dotcloud.com/services/solr/"&gt;DotCloud Solr&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="section" id="solr"&gt;
&lt;h1&gt;Solr の基本&lt;/h1&gt;
&lt;p&gt;Solr は検索用の Web アプリケーションで、Tomcat などのコンテナに WAR を置けば使えます。
もっとも簡単な試用方法は Jetty を使うことで、これは Solr の配布用アーカイブに含まれているサンプルで確認できます。&lt;/p&gt;
&lt;p&gt;Solr の最新バージョンは 3.3 ですが、DotCloud で利用可能なバージョンは 3.1 なので、
まずはこれをダウンロードして展開してみます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ wget http://ftp.riken.jp/net/apache//lucene/solr/3.1.0/apache-solr-3.1.0.tgz
$ tar xzvf apache-solr-3.1.0.tgz
$ cd apache-solr-3.1.0/
$ ls . dist example
.:
CHANGES.txt  LICENSE.txt  NOTICE.txt   README.txt   client/      contrib/     dist/        docs/        example/

dist:
apache-solr-3.1.0.war                           apache-solr-core-3.1.0.jar                      apache-solr-uima-3.1.0.jar
apache-solr-analysis-extras-3.1.0.jar           apache-solr-dataimporthandler-3.1.0.jar         solrj-lib/
apache-solr-cell-3.1.0.jar                      apache-solr-dataimporthandler-extras-3.1.0.jar
apache-solr-clustering-3.1.0.jar                apache-solr-solrj-3.1.0.jar

example:
README.txt   etc/         example-DIH/ exampledocs/ lib/         logs/        multicore/   solr/        start.jar    webapps/     work/
&lt;/pre&gt;
&lt;p&gt;&lt;cite&gt;dist&lt;/cite&gt; ディレクトリには JAR ファイルと WAR ファイルがあり、
これをそのままコピーすれば必要なコンポーネントを使えます。
Web コンテナには &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;apache-solr-3.1.0.war&lt;/span&gt;&lt;/tt&gt; を置くことになります。&lt;/p&gt;
&lt;p&gt;&lt;cite&gt;example&lt;/cite&gt; ディレクトリはサンプルを実行できる環境になっています。
&lt;cite&gt;solr&lt;/cite&gt; ディレクトリに設定ファイルを置き、 &lt;tt class="docutils literal"&gt;start.jar&lt;/tt&gt; を実行させると Jetty を使ってサーバが起動します。
サーブレットに関するものは &lt;cite&gt;lib&lt;/cite&gt; ディレクトリに置かれています。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cd example/
$ java -jar start.jar
&lt;/pre&gt;
&lt;div style="float:right; margin:auto auto 10px 10px;"&gt;
&lt;iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=kshigeru-22&amp;o=9&amp;p=8&amp;l=as1&amp;asins=4774141755&amp;ref=tf_til&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;m=amazon&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;&lt;/div&gt;

&lt;p&gt;Web ブラウザで &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;http://localhost:8983/solr/admin/&lt;/span&gt;&lt;/tt&gt; にアクセスすると、Solr の管理画面になります。&lt;/p&gt;
&lt;p style="text-align:center; margin:5px;"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-Di5VEFfgyk0/TjABEIupOWI/AAAAAAAAD4U/b3Xs00kFG1U/s1600/screen-solr-admin.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 197px;" src="http://4.bp.blogspot.com/-Di5VEFfgyk0/TjABEIupOWI/AAAAAAAAD4U/b3Xs00kFG1U/s400/screen-solr-admin.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5634004304414718306" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;どのフィールドでどのような値を管理するかは &lt;cite&gt;SCHEMA&lt;/cite&gt; のリンクから確認できます。
また、検索クエリに対してフィルタをかけたり、コンポーネントを実行させる設定は &lt;cite&gt;CONFIG&lt;/cite&gt; のリンクから確認できます。
これらはそれぞれ &lt;tt class="docutils literal"&gt;schema.xml&lt;/tt&gt; と &lt;tt class="docutils literal"&gt;solrconfig.xml&lt;/tt&gt; に対応しており、どちらも &lt;cite&gt;solr/conf&lt;/cite&gt; ディレクトリにあります。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ tree -L 2 solr
solr
|-- README.txt
|-- bin
|-- conf
|   |-- admin-extra.html
|   |-- elevate.xml
|   |-- mapping-FoldToASCII.txt
|   |-- mapping-ISOLatin1Accent.txt
|   |-- protwords.txt
|   |-- schema.xml
|   |-- scripts.conf
|   |-- solrconfig.xml
|   |-- spellings.txt
|   |-- stopwords.txt
|   |-- synonyms.txt
|   |-- velocity
|   `-- xslt
|-- data
|   |-- index
|   `-- spellchecker
`-- solr.xml
&lt;/pre&gt;
&lt;p&gt;&lt;cite&gt;bin&lt;/cite&gt; ディレクトリはユーティリティスクリプト置き場、
&lt;cite&gt;data&lt;/cite&gt; ディレクトリは Lucene (実際の検索エンジン) のデータ置き場ですから、
「設定ファイル」として必要なものは &lt;tt class="docutils literal"&gt;solr.xml&lt;/tt&gt; と &lt;cite&gt;conf&lt;/cite&gt; ディレクトリ以下のものになります。&lt;/p&gt;
&lt;p&gt;つまり、ちょっと乱暴な表現をするならば、Solr の WAR ファイルと &lt;tt class="docutils literal"&gt;solr.xml&lt;/tt&gt; と
&lt;cite&gt;conf&lt;/cite&gt; ディレクトリの中のファイルがあれば Solr を動かせる、と言えます。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id2"&gt;
&lt;h1&gt;Solr のバージョン&lt;/h1&gt;
&lt;p&gt;Solr は Lucene と密接に関係しています。
初めは別々のレポジトリで開発されていましたが、ある時からレポジトリが統合されました。
それからほどなくして、リリースも一緒のタイミングで実施されるようになりました。
そして、バージョン番号も合わせることになりました。&lt;/p&gt;
&lt;p&gt;統合後の最初のリリースが 3.1 です。
以前の Solr のバージョンは 1.4 でしたが、一気に飛んだことになります。&lt;/p&gt;
&lt;p&gt;バージョンは検索インデクスにも影響があり、Solr は Lucene のどのバージョンを使っているかを把握する必要があります。
これは &lt;tt class="docutils literal"&gt;solrconfig.xml&lt;/tt&gt; の &lt;tt class="docutils literal"&gt;luceneMatchVersion&lt;/tt&gt; に記述されています。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ grep luceneMatchVersion solr/conf/solrconfig.xml
  &amp;lt;luceneMatchVersion&amp;gt;LUCENE_31&amp;lt;/luceneMatchVersion&amp;gt;
&lt;/pre&gt;
&lt;p&gt;設定ファイルと実行環境でこの設定が異なっていると良ろしくありませんので、
最初に Solr 3.1 をダウンロードしたのはこのためです。
特に、Solr 1.4 と Solr 3.1 では Java オプジェクトをシリアライズした形式が異なるため、
クライアント側で Java を使う場合には注意しなければなりません。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;DotCloud への配置&lt;/h1&gt;
&lt;p&gt;DotCloud は WAR ファイルとコンテナ、そして、そのコンテナを監視する仕組みを提供してくれます。
開発者は設定ファイルだけを管理し、
DotCloud 用の設定ファイル (&lt;tt class="docutils literal"&gt;dotcloud.yml&lt;/tt&gt;) を用意してプッシュすれば Solr を使えるようになります。&lt;/p&gt;
&lt;p&gt;一番最初は Solr のアーカイブから &lt;tt class="docutils literal"&gt;example/solr&lt;/tt&gt; を丸ごとコピーするのが分かりやすいと思います。
スキーマ定義を変更したい場合には &lt;tt class="docutils literal"&gt;schema.xml&lt;/tt&gt; 、ハンドラなどを変更したい場合には &lt;tt class="docutils literal"&gt;solrconfig.xml&lt;/tt&gt; を編集します。&lt;/p&gt;
&lt;p&gt;手元のマシンで用意するもの:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ tree .
.
|-- conf
|   |-- admin-extra.html
|   |-- elevate.xml
|   |-- mapping-FoldToASCII.txt
|   |-- mapping-ISOLatin1Accent.txt
|   |-- protwords.txt
|   |-- schema.xml
|   |-- scripts.conf
|   |-- solrconfig.xml
|   |-- spellings.txt
|   |-- stopwords.txt
|   `-- synonyms.txt
|-- dotcloud.yml
`-- solr.xml
&lt;/pre&gt;
&lt;p&gt;DotCloud へのプッシュ:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ cat dotcloud.yml
search:
  type: solr
$ dotcloud push solr .
&lt;/pre&gt;
&lt;p&gt;これで &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;http://{dotcloud-id}.dotcloud.com/solr/admin/&lt;/span&gt;&lt;/tt&gt; にアクセスすれば Solr の管理画面になります。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h1&gt;ドキュメントのインデクシング&lt;/h1&gt;
&lt;p&gt;適当なドキュメント群からインデクスデータを作成します。
インデクスデータを作成するには、Solr の update ハンドラに XML を POST します。
Solr が XML を解釈して、Lucene が文字列を解析してくれます。&lt;/p&gt;
&lt;p&gt;たとえば &lt;a class="reference external" href="http://sphinx.pocoo.org/"&gt;Sphinx&lt;/a&gt; で管理しているドキュメントの場合には、
プレインテキストに変換したものを XML でラップして POST すれば良いだけです。&lt;/p&gt;
&lt;p&gt;今回は、以前に書いた翻訳ドキュメントをインデクシングしてみました。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/skitazaki/twisted-intro-ja/blob/master/solr-document-indexer.py"&gt;solr-document-indexer.py&lt;/a&gt; (github.com)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="literal-block"&gt;
$ cd {SPHINX_DOCUMENT_DIR}
$ make text
$ python solr-document-indexer.py http://{dotcloud-id}.dotcloud.com/solr _build/text
&lt;/pre&gt;
&lt;p&gt;スクリプトには色々とハードコードしていますが、とりあえず目的は達成できたので良しとします。&lt;/p&gt;
&lt;p&gt;最後に、Solr 管理画面の &amp;quot;Query String&amp;quot; に &amp;quot;*:*&amp;quot; と入力してから &amp;quot;Search&amp;quot; ボタンをクリックして確認します。
１件以上のドキュメントが検索結果として返ってくれば成功です。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h1&gt;プロキシの配置&lt;/h1&gt;
&lt;p&gt;Solr は XML で出力するだけでなく、いくつかのライタータイプを切り替えて使うこともできます。
その一つに JSON ライターがあります。
JSON ならば、Web ブラウザまで渡せば色々と操作できます。&lt;/p&gt;
&lt;p&gt;しかし、Web ブラウザがドメインを超えて通信するにはいくつかの制約がありますので、
適当なプロキシを噛ませることにします。
DotCloud では PHP も使えますので、curl モジュールを使って通信を橋渡しさせます。&lt;/p&gt;
&lt;p&gt;先ほどの Solr とは別のプロジェクトスペースを用意し、
次のようなスクリプトを &lt;tt class="docutils literal"&gt;search.php&lt;/tt&gt; としておきます。&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
&amp;lt;?php
header('Content-type: text/json');

const SOLR_SERVER = 'http://{dotcloud-id}.dotcloud.com';
$url = SOLR_SERVER . 'solr/select?';
$keyword = isset($_GET['q']) ? $_GET['q'] : '*';
$offset = isset($_GET['offset']) ? $_GET['offset'] : 0;
$query = &amp;quot;text:'&amp;quot; . $keyword . &amp;quot;'&amp;quot;;
$param = array('q' =&amp;gt; $query,
               'fl' =&amp;gt; 'id,title,url',
               'hl' =&amp;gt; 'on',
               'hl.fl' =&amp;gt; 'content',
               'wt' =&amp;gt; 'json',
               'start' =&amp;gt; $offset,
               'rows' =&amp;gt; 20);
$ch = curl_init($url . http_build_query($param));
// passthru output.
curl_exec($ch);
curl_close($ch);
&lt;/pre&gt;
&lt;p&gt;次に、検索画面用の HTML ファイルを &lt;tt class="docutils literal"&gt;index.html&lt;/tt&gt; とし、適当な JavaScript を書きます。
ユーザーが検索ボックスに入力したものを &lt;tt class="docutils literal"&gt;search.php&lt;/tt&gt; に &amp;quot;q&amp;quot; パラメータとして渡します。
結果は JSON で返されますので、あとはそれを解釈すれば良いだけです。&lt;/p&gt;
&lt;p&gt;なお、サーバ側でセットしている &amp;quot;hl&amp;quot;、&amp;quot;hl.fl&amp;quot; パラメータはハイライト用の設定です。
検索スピードは低下しますが、必要に応じてこれらを使うのも良いと思います。
ハイライトされたフィールドを JSON で扱う場合には ID の参照が必要になりますが、
JSON をその都度確認すれば解釈可能でしょう。&lt;/p&gt;
&lt;p&gt;最後に DotCloud の設定ファイル (&lt;tt class="docutils literal"&gt;dotcloud.yml&lt;/tt&gt;) を用意します。&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
www:
  type: php
&lt;/pre&gt;
&lt;p&gt;あとはコマンドラインツールからプッシュすれば検索画面の出来上がりです。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="reference external" href="http://91e921a4.dotcloud.com/"&gt;In-house Documentation Search&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style="text-align:center; margin:5px;"&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-DHpfxG3jAwQ/TjAAaXflAYI/AAAAAAAAD4M/mfRQUr94vsQ/s1600/screen-inhouse-document-search.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 311px;" src="http://1.bp.blogspot.com/-DHpfxG3jAwQ/TjAAaXflAYI/AAAAAAAAD4M/mfRQUr94vsQ/s400/screen-inhouse-document-search.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5634003586823553410" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;DotCloud には複数のインスタンスを配置できますので、
Solr サーバと PHP アプリで同じ設定ファイルを使うこともできます。
この場合、サーバ側の設定ファイル (&lt;tt class="docutils literal"&gt;/home/dotcloud/environment.json&lt;/tt&gt;) に
Solr サーバの URL が記載されていますので、次のようにして参照できます。&lt;/p&gt;
&lt;pre class="prettyprint lang-php"&gt;
$envjson = json_decode(file_get_contents(&amp;quot;/home/dotcloud/environment.json&amp;quot;), true);
const SOLR_SERVER = $envjson['DOTCLOUD_SEARCH_HTTP_URL']
&lt;/pre&gt;
&lt;p&gt;この辺りは管理上の好みもあるでしょうから、どちらでも良いんじゃなかなと思います。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id6"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;DotCloud で Solr を使ってみました。
課金について何も気にしていませんので、どれくらいのインデクス量ならどの程度の費用がかかるかは分かりません。
とはいえ、プッシュすれば &lt;tt class="docutils literal"&gt;rsync&lt;/tt&gt; で同期され、サーバ類が適切に再起動されるのは嬉しいですね。&lt;/p&gt;
&lt;p&gt;検索に関しては、ちょっと Solr を使ってみる、あるいは、手頃な検索手段が無いドキュメント (*) をなんとかする、
という点ではお手軽な方法ではないかな、と思いました。
また、Solr にはファセット検索などもありますので、
関連する検索キーワードを提示したり、惜しいキーワードを拾い上げることも出来るかもしれませんね。&lt;/p&gt;
&lt;blockquote&gt;(*) Sphinx 1.0 系に組み込まれた検索手法だと、日本語をきちんと検索できません。
1.1 がリリースされれば改善されるかもしれません。&lt;/blockquote&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-3325352176387959126?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/3325352176387959126/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=3325352176387959126' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/3325352176387959126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/3325352176387959126'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/07/dotcloud-solr-search.html' title='DotCloud で Solr を使ってみる'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-Di5VEFfgyk0/TjABEIupOWI/AAAAAAAAD4U/b3Xs00kFG1U/s72-c/screen-solr-admin.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-8043844681685408036</id><published>2011-07-22T00:23:00.002+09:00</published><updated>2011-08-17T00:59:28.302+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Books'/><title type='text'>マサチューセッツ工科大学</title><content type='html'>&lt;p&gt;新潮社から出版されていた「マサチューセッツ工科大学」を読んだメモ書きです。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://skitazaki.appspot.com/works/doc/mit-and-the-technical-imagination.html"&gt;Books - マサチューセッツ工科大学&lt;/a&gt;&lt;/li&gt;
&lt;p&gt;
&lt;/ul&gt;
書籍自体の初版は1995年9月で、2011年現在だと、おそらく絶版になっています。
新潮文庫から出版された &lt;a class="reference external" href="http://www.amazon.co.jp/dp/4102154116"&gt;文庫版&lt;/a&gt; だと Amazon から中古版を購入できるようです。&lt;/p&gt;
&lt;p&gt;読後感が訳者あとがきと一緒だったので抜粋します。&lt;/p&gt;
&lt;blockquote&gt;
「ハイテク」関連の書籍というのは、ある友人の表現を借りると、おおむね「高血圧」の表現をとっている。
騒々しいハイテク・グルーピーとは対照的に、きわめて冷静な、低血圧アプローチをとっていることが、
個人的には本書の最大の美点と考えている。&lt;/blockquote&gt;
&lt;a name='more'&gt;&lt;/a&gt;
&lt;p&gt;時代を順々に追ってくると、エンジニアリングから出発してサイエンスに比重を移してきたことが分かります。
一方で、最近の日本では、大学でも企業の即戦力となる人材を育成すべきだ、という論調も散見される点が興味深いところです。
「歴史は繰り返す」という意味での揺り戻しなのか、もしくは歴史を共有できていないのか、
はたまた、大学や大学院を研究機関として位置付けること自体が意味をなさないのか。
社会的な構造や役割は変わり続けるため、唯一の正解もありませんが、
大学の秋入学 (&lt;a class="reference external" href="http://www.newsweekjapan.jp/reizei/2011/07/post-318.php"&gt;東大「秋入学」の前にやるべきこと&lt;/a&gt; - newsweekjapan.jp) が検討されている昨今、
海外の有名な大学がどのような変遷を辿ってきたかを学んでおくのも良いですね。&lt;/p&gt;

&lt;p&gt;もちろん、工学系の大学についての叙述ですから科学や工学に関する基礎知識があると読みやすいでしょうが、表現が固い以外は、数式などはありませんので気軽に読み進められます。願わくば、高校生のときに読んでおきたかったなぁ、と思いました。MIT への憧れというだけでなく、そもそも大学って何するところ？何を期待されているところ？という点が深堀りできるかもしれません。&lt;/p&gt;

&lt;p&gt;目次は次のようになっています。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;第１章 エンジニアの欲望と動機&lt;/li&gt;
&lt;li&gt;第２章 バランス喪失のユーモア&lt;/li&gt;
&lt;li&gt;第３章 エンジニアの誕生&lt;/li&gt;
&lt;li&gt;第４章 思考をうながす校舎の誕生&lt;/li&gt;
&lt;li&gt;第５章 工学 (エンジニアリング) から科学 (サイエンス) へ&lt;/li&gt;
&lt;li&gt;第６章 鉄道模型クラブ&lt;/li&gt;
&lt;li&gt;第７章 MIT製の義肢&lt;/li&gt;
&lt;li&gt;第８章 メディア研究所&lt;/li&gt;
&lt;li&gt;第９章 10億分の1 (ナノ) メートルのテクノロジー&lt;/li&gt;
&lt;li&gt;第10章 技術のスポーツ&lt;/li&gt;
&lt;li&gt;第11章 脱コンピューターのシステム&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;「理系」と十把一絡げにされることも多いですが、多様な分野があるなぁ、と当たり前のことを再認識できました。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-8043844681685408036?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/8043844681685408036/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=8043844681685408036' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/8043844681685408036'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/8043844681685408036'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/07/mit-and-technical-imagination.html' title='マサチューセッツ工科大学'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-1595021895334631920</id><published>2011-07-18T17:00:00.001+09:00</published><updated>2011-08-17T01:00:04.076+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='サッカー'/><title type='text'>女子ワールドカップで日本が優勝</title><content type='html'>&lt;p&gt;ドイツで開催された女子のワールドカップで「なでしこジャパン」が優勝しました。
FIFA の公式サイトにもきちんと結果が残されているのを確認すると、本当に大きな一歩だな、と実感します。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.fifa.com/womensworldcup/matches/round=255989/match=300144437/summary.html"&gt;Japan edge USA for maiden title&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.fifa.com/womensworldcup/news/newsid=1476593/index.html"&gt;Kaihori and Kumagai, Japan's penalty stars&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;得点王 + MVP の澤選手が最高スコアであることを始めとして、海外での評価も上々でした。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.goal.com/en/match/63474/japan-women-vs-united-states-women/player-ratings"&gt;Japan Women vs United States Women Player Ratings&lt;/a&gt; (goal.com)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;日常的にテレビで扱われないスポーツの選手たちは、日常生活を含めて見えないところで本当に苦労が絶えないと思いますが、
来年のロンドンオリンピックでも、もちろんその前の予選でも、頑張って欲しいですね。&lt;/p&gt;
&lt;div class="center" style="text-align:center;"&gt;
&lt;iframe width="560" height="349" src="http://www.youtube.com/embed/vAQUOTVhPiA" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-1595021895334631920?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/1595021895334631920/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=1595021895334631920' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/1595021895334631920'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/1595021895334631920'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/07/womens-world-cup.html' title='女子ワールドカップで日本が優勝'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://img.youtube.com/vi/vAQUOTVhPiA/default.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-3342957598732075056</id><published>2011-06-27T01:12:00.003+09:00</published><updated>2011-08-17T01:01:03.824+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>エキスパート Python プログラミングの読書会 - 13</title><content type='html'>&lt;div style="float:right; margin:auto auto 10px 10px;"&gt;
&lt;iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=kshigeru-22&amp;o=9&amp;p=8&amp;l=as1&amp;asins=4048686291&amp;ref=qf_sp_asin_til&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;m=amazon&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;「エキスパート Python プログラミング」の読書会に行ってきました。
10章「プロジェクトのドキュメント作成」に関することで、この章は Web でも公開されています。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://atnd.org/events/16717"&gt;エキスパートPythonプログラミング読書会13&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://sphinx-users.jp/articles/expertpython/index.html"&gt;10章: プロジェクトのドキュメント作成&lt;/a&gt; (sphinx-users.jp)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;今回は、ざっくりと次の二点に関して話し合いました。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;業務でどうやってドキュメント (主に IT 業における技術文書) を書いてますか？&lt;/li&gt;
&lt;li&gt;&amp;quot;&lt;a class="reference external" href="http://sphinx.pocoo.org/"&gt;Sphinx&lt;/a&gt;&amp;quot; (&lt;a class="reference external" href="http://sphinx-users.jp/"&gt;日本語&lt;/a&gt;) というツールの使い方、Tips の共有。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;自分のメモによる時系列は、おおよそ次のようになります。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;cite&gt;参加者の自己紹介&lt;/cite&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/83124494763442176"&gt;6/21 19:49&lt;/a&gt; &amp;quot;ドキュメント作成は、開発者、ときにはマネージャもさぼってしまいがちな作業です。&amp;quot;プロジェクトのドキュメント作成 - &lt;a class="reference external" href="http://t.co/pf2y18e"&gt;http://t.co/pf2y18e&lt;/a&gt; &lt;a class="reference external" href="http://www.google.com/search?tbo=1&amp;amp;amp;tbs=mbl:1&amp;amp;amp;q=%23expertpython"&gt;#expertpython&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/83127882947371008"&gt;6/21 20:03&lt;/a&gt; Q. 技術文章を書くためにどんな本を読んで勉強してる？ A. ワインバーグ先生の本、日本語の作文技術、理科系の作文技術、エキPy(笑 &lt;a class="reference external" href="http://www.google.com/search?tbo=1&amp;amp;amp;tbs=mbl:1&amp;amp;amp;q=%23expertpython"&gt;#expertpython&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/83131241074921472"&gt;6/21 20:16&lt;/a&gt; タイトルが明快になれば逸脱した話題はノイズに思えてくるので、情報のスコープが絞られる。後から振り返るときにどのような検索語句を使うだろうか？と問い直してみる。たいていの検索インデクスではタイトルの重みが強いことを利用する。 &lt;a class="reference external" href="http://www.google.com/search?tbo=1&amp;amp;amp;tbs=mbl:1&amp;amp;amp;q=%23expertpython"&gt;#expertpython&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/83131754004758528"&gt;6/21 20:18&lt;/a&gt; レビューするときは見た目を変えてみる。内容を書き出すフェーズと、表示をリッチにするフェーズを分ける。「２つのステップで書く」ということ。 &lt;a class="reference external" href="http://www.google.com/search?tbo=1&amp;amp;amp;tbs=mbl:1&amp;amp;amp;q=%23expertpython"&gt;#expertpython&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/83134767968690177"&gt;6/21 20:30&lt;/a&gt; Sphinx の autodoc を使うと docstring をドキュメントに反映しやすいので、doctest をやる気が上がるらしい。意図と実装が一緒になっているので、変更漏れが少なくなる。これもひとつの TDD。 &lt;a class="reference external" href="http://www.google.com/search?tbo=1&amp;amp;amp;tbs=mbl:1&amp;amp;amp;q=%23expertpython"&gt;#expertpython&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/83136115174948864"&gt;6/21 20:36&lt;/a&gt; Sphinx の便利メモ。 / 逆引き辞典 - &lt;a class="reference external" href="http://t.co/nRuJInz"&gt;http://t.co/nRuJInz&lt;/a&gt; &lt;a class="reference external" href="http://www.google.com/search?tbo=1&amp;amp;amp;tbs=mbl:1&amp;amp;amp;q=%23expertpython"&gt;#expertpython&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/83138434671181824"&gt;6/21 20:45&lt;/a&gt; ドキュメントの「ポートフォリオ」を作りましょう。再利用可能なテンプレートのことで、目的別に保管しておく。完成したドキュメントから作り直すと良さそう。先にポートフォリオを作り始めたら死亡フラグ。 &lt;a class="reference external" href="http://www.google.com/search?tbo=1&amp;amp;amp;tbs=mbl:1&amp;amp;amp;q=%23expertpython"&gt;#expertpython&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;cite&gt;休憩&lt;/cite&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/83148376077635584"&gt;6/21 21:24&lt;/a&gt; &amp;quot;glossary&amp;quot; ディレクティブを使うと索引を生成できるけど、日本語だと Symbols にまとめられてしまう。日本語用パッチを作っている人もいるが、さらっとは取り込めない状態みたい。 &lt;a class="reference external" href="http://www.google.com/search?tbo=1&amp;amp;amp;tbs=mbl:1&amp;amp;amp;q=%23expertpython"&gt;#expertpython&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/83149305879339008"&gt;6/21 21:28&lt;/a&gt; Python も一緒に入るみたい。 / Windowsへのインストール(スタンドアロンインストール) - &lt;a class="reference external" href="http://t.co/rAU10zw"&gt;http://t.co/rAU10zw&lt;/a&gt; &lt;a class="reference external" href="http://www.google.com/search?tbo=1&amp;amp;amp;tbs=mbl:1&amp;amp;amp;q=%23expertpython"&gt;#expertpython&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/83155690679574530"&gt;6/21 21:53&lt;/a&gt; Sphinx の拡張レポジトリ。 / birkenfeld / sphinx-contrib - &lt;a class="reference external" href="http://t.co/xatcvNQ"&gt;http://t.co/xatcvNQ&lt;/a&gt; &lt;a class="reference external" href="http://www.google.com/search?tbo=1&amp;amp;amp;tbs=mbl:1&amp;amp;amp;q=%23expertpython"&gt;#expertpython&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/83159804712988672"&gt;6/21 22:10&lt;/a&gt; linkcheck で外部へのリンクも確認しましょう、ということをみんなで学んで終了。 &lt;a class="reference external" href="http://www.google.com/search?tbo=1&amp;amp;amp;tbs=mbl:1&amp;amp;amp;q=%23expertpython"&gt;#expertpython&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;これ以降では、後からつらっと思ったことも含めて書いておきます。&lt;/p&gt;
&lt;a name='more'&gt;&lt;/a&gt;
&lt;div class="section" id="id14"&gt;
&lt;h1&gt;ドキュメントを書く&lt;/h1&gt;
&lt;p&gt;まずは「技術文書を書くための７つのルール」を確認しました。
誰に向けて何を書くか？という部分は文書一般に言えることだと思いますが、
自分が特になるほど〜と思ったのは次の３点です。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;アイデアにフォーカスして、まずはレビューする。&lt;/li&gt;
&lt;li&gt;意味が分かり、動かせるサンプルを使う。&lt;/li&gt;
&lt;li&gt;ドキュメント・ランドスケープを意識する。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="section" id="id15"&gt;
&lt;h2&gt;作成とレビューのサイクル&lt;/h2&gt;
&lt;p&gt;PowerPoint や Word といった WYSIWYG (what you see is what you get: 作成中の文書と成果物が同じ見た目であること) ツールの場合、
とかく表示の調整から始めがちです。
ページ余白を調整してテーマや色遣いを決めて、フォントは何を使って装飾は... と、だいたい同じことに同じように時間をとられます。
過去のテンプレートを使い回しても、なんとなくアニメーションを追加してしまうかもしれませんね。
何かを書こう、と思ってツールを起動させても、その何かを書く前の準備が終わったら一休み、となりがちです。&lt;/p&gt;
&lt;p&gt;一方で、メモ帳などのテキストエディタは文章に焦点を絞れるため、即座に何でも書き始められます。
とはいえ、読み直したときの抑揚のなさ、図を思い通りに配置することの難しさなどにより、そのままレビューするわけにもいきません。
また、無秩序に書き始めてしまうと、量が多くなったときにアウトラインを把握できなくなります。&lt;/p&gt;
&lt;p&gt;これらの中間 (?) として、テキストエディタで書いて、何らかのツールを使って成果物を生成する方式があります。
数十年前には、書籍を出版するための適したツールがないから作っちゃおう、という著名な先生もいますが、
割と普遍的な課題ですから、現在までにたくさんの文法とツールが開発されています。&lt;/p&gt;
&lt;p&gt;気軽に書き始められて、それなりの見た目 (目次が明快、強調部分が目立つ、図を取り込める、など) でレビューできて、
その結果を反映できる、というサイクルを回すためには reST や markdown、textile は良い選択肢だと思います。
少なくとも、独自フォーマットやローカルルールは控えた方が良さそうです。
日本語の場合はついつい中黒 (・) を使って箇条書きを表現しがちですが、
後からツールで処理する、つまり再利用性を高めるためには、&amp;quot;*&amp;quot; や &amp;quot;-&amp;quot; の方が良いかもしれませんね。&lt;/p&gt;
&lt;p&gt;フィードバックのサイクルを繰り返す中では、変更履歴を追跡できるようにしておくことも重要です。
Word にも履歴管理機能はありますが、きちんと使えない人がいたり、使いすぎると動作がもっさりするなどの問題があります。
特に複数人が編集に関わる場合には、文書自体と履歴管理は分離しておいた方が良いと思います。&lt;/p&gt;
&lt;p&gt;履歴管理されているとレビュー範囲が明確になります。
また、&amp;quot;&lt;cite&gt;文書ファイル名-日付文字列.拡張子&lt;/cite&gt;&amp;quot; というルールでファイル名を変更する必要もありませんので、
どれが最新版か分からなくなってしまう問題が低減します。
ファイル名を変更するルールの場合、&amp;quot;&lt;cite&gt;最新版-課題XXXについて.docx&lt;/cite&gt;&amp;quot;、&amp;quot;&lt;cite&gt;最新版2-課題XXXについて.docx&lt;/cite&gt;&amp;quot; となりかねませんから。&lt;/p&gt;
&lt;p&gt;何はともあれ、「１回書いたらそれでオシマイ！」ではなく、ある程度の期間に渡って継続的に更新し続けることがポイントです。
主要な考えを書き出して、それを他の人に見てもらい、意見を反映させて、さらに考えを書き足していける状態を作ることが目標となります。
要するにソースコード管理と一緒ですね。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id16"&gt;
&lt;h2&gt;実際に動作するサンプル&lt;/h2&gt;
&lt;p&gt;何かの手順書を作成する場合、「ここは手元の環境に合わせて XXX の部分を書き換えてください」と書くことも多々あります。
それ自体は悪いことではないと思いますが、例示が悪いと誤解が生じやすくなってしまいます。&lt;/p&gt;
&lt;p&gt;たとえば、Java のプロジェクトを Subversion からチェックアウトして Maven で Jetty を動かす場合、
次のサンプルでは意図が伝わらないかもしれません。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ svn co {Subversion の URL} hoge
$ cd hoge
$ cd example
$ vi {設定ファイル.xml}
--- サーバ情報を書き換える ---
$ mvn jetty:run
&lt;/pre&gt;
&lt;p&gt;この場合は、Subversion の &lt;cite&gt;trunk&lt;/cite&gt; から引っ張ってくるのか、 &lt;cite&gt;branch&lt;/cite&gt; の場合はどれかが分かりません。
また、設定ファイルがひとつなのか複数なのかも分かりませんし、何のサーバ情報をどのように変更するかも定かではありません。
コピペして動かせませんし、何より &lt;cite&gt;hoge&lt;/cite&gt; って何？となります。&lt;/p&gt;
&lt;p&gt;コマンドサンプルの前後に説明を書き連ねることもできますが、
それよりは、そのまま実行できるように工夫した方が良いでしょう。
もしかしたら設定ファイルの見直しから始めなければならないかもしれません。
しかし、それによって外部への依存性が明らかになりますので、中長期的な観点では、
無駄な作業にはならないと思います。&lt;/p&gt;
&lt;p&gt;サンプルはソフトウェアを客観的に見直すきっかけにもなります。
必要だと思っていたパラメータが実は使われていなかった、
もしくは、設定したつもりだったのに内部での読み取り間違いで反映されていない、
というケースもあぶり出されます。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id17"&gt;
&lt;h2&gt;ドキュメント・ランドスケープ&lt;/h2&gt;
&lt;p&gt;「ドキュメント・ランドスケープ」という言葉を知りませんでしたが、
この言葉は翻訳者の方々が原著者に問い合わせて NOTE に記載したとのことです。&lt;/p&gt;
&lt;p&gt;「あるべきものがあるべき場所に存在する」というようなことで、
家がビルの屋上にあったらオカシイよね、などを判別するために使います。&lt;/p&gt;
&lt;p&gt;たとえば、手順書であれば事前条件や想定読者が実際の手順より前にあるべきです。
先ほどの例であれば、コマンドを実行する前に &lt;tt class="docutils literal"&gt;svn&lt;/tt&gt; コマンドと &lt;tt class="docutils literal"&gt;mvn&lt;/tt&gt; コマンドをインストールする、
あるいはインストールされているマシンを使う必要があります。
そもそも Maven って何？という読者も想定されるなら、別途説明があった方が親切でしょう。&lt;/p&gt;
&lt;p&gt;これまで読んできたドキュメントを参考にすると、こういうことはこの辺りに書いてありそうだ、
と、読者側で違和感なく受け入れられる構成を考えていくことになります。
何らかのテンプレートを踏襲したり、過去のドキュメントからコピーしてくるなど、
いわゆるノウハウを活用する部分と言えます。
「ポートフォリオ」の蓄積とも言い換えられます。&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="id18"&gt;
&lt;h1&gt;Sphinx あれこれ&lt;/h1&gt;
&lt;p&gt;Sphinx はそれ自体が文法を持っているわけではなく、 reST をまとめるツールと言えます。
このため、reST と markdown は比較対象として妥当ですが、Sphinx と markdown の比較には違和感が発生します。
レイヤーが違うわけです。
markdown をまとめるツールとしては &lt;a class="reference external" href="http://jekyllrb.com/"&gt;jekyll&lt;/a&gt; (&lt;a class="reference external" href="http://css.studiomohawk.com/tool/2011/06/11/jekyll-101.tool/"&gt;jekyll 日本語説明&lt;/a&gt;) がありますので、比較するならこちらが適当でしょう。
&lt;cite&gt;jekyll&lt;/cite&gt; で構築されたサイトとしては &lt;a class="reference external" href="http://gitready.com/"&gt;gitready&lt;/a&gt; があります。&lt;/p&gt;
&lt;p&gt;reST が拡張可能な仕様なので、Sphinx を作ることができたとも言えます。
ディレクティブという命令体系を拡張できますので、 reST がそもそも持っているディレクティブに加えて、
Sphinx によるディレクティブ、あるいは自分独自のプラグインでディレクティブを記述できます。
あるツールに対するラッパーという意味では、ラインエディタ ex におけるスクリーンエディタ vi と似た関係となります。&lt;/p&gt;
&lt;p&gt;Sphinx を使って HTML を生成するときには、テンプレートエンジンとして &lt;a class="reference external" href="http://jinja.pocoo.org/"&gt;jinja2&lt;/a&gt; (&lt;a class="reference external" href="http://ymotongpoo.appspot.com/jinja2_ja/index.html"&gt;jinja2 日本語&lt;/a&gt;) が使われます。
&lt;cite&gt;jinja2&lt;/cite&gt; にはテンプレート継承の仕組みがありますから、既存のテンプレートを再利用しながら、
必要な部分だけを自前の HTML で上書きできます。
たとえば、ヘッダーやフッターを書き換えたり、メニューバーをカスタマイズできます。&lt;/p&gt;
&lt;p&gt;出力形式 (ドキュメントビルダー) は複数種類ありますので、表現は HTML だけに止まりません。
PDF や Windows ヘルプ、JSON や pickle にも出力できます。
JSON だけをサーバサイドに保存して Ajax を利用したドキュメントビューアや、
Python アプリケーションにドキュメントを組み込むといったアイデアも実現できそうです。&lt;/p&gt;
&lt;p&gt;その他に、Sphinx でのドキュメント生成時に、ドキュメント内部から外部を参照しているハイパーリンクを確認できます。
これには勉強会参加者一同が驚きましたが、 &lt;cite&gt;linkcheck&lt;/cite&gt; ターゲットで実行できます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
$ make |grep linkcheck
  linkcheck  to check all external links for integrity

$ make linkcheck
sphinx-build -b linkcheck -d _build/doctrees   . _build/linkcheck
Making output directory...
Running Sphinx v1.0.7
loading pickled environment... done
building [linkcheck]: targets for 24 source files that are out of date
updating environment: 0 added, 0 changed, 0 removed
looking for now-outdated files... none found
preparing documents... done
writing output... [  4%] README
(line   5) http://krondo.com/blog/?page_id=1327 - working
(line   5) http://skitazaki.appspot.com/translation/twisted-intro-ja/ - broken: HTTP Error 404: Not Found
(line   5) http://twistedmatrix.com/documents/10.0.0/core/howto/index.html - working
(line  10) http://skitazaki.appspot.com/translation/twisted-intro-ja/ - broken: HTTP Error 404: Not Found
writing output... [  8%] index
(line  11) http://twistedmatrix.com/ - redirected to http://twistedmatrix.com/trac/
(line  43) https://github.com/skitazaki/twisted-intro-ja - working
writing output... [ 12%] p01
(line   8) http://twistedmatrix.com/ - redirected to http://twistedmatrix.com/trac/
(line   8) http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python - working
(line   8) http://twistedmatrix.com/pipermail/twisted-python/2009-May/019706.html - working
(line  16) http://twistedmatrix.com/trac/wiki/Documentation - working
(line  16) http://twistedmatrix.com/trac/browser - working
(line  61) http://en.wikipedia.org/wiki/Locality_of_reference - working

--- snip ---

build finished with problems.
make: *** [linkcheck] Error 1

$ ls _build/linkcheck/
output.txt
&lt;/pre&gt;
&lt;p&gt;存在するものは &lt;cite&gt;working&lt;/cite&gt; 、リダイレクトが発生するものは &lt;cite&gt;redirected&lt;/cite&gt; 、リンク先が見つからないものは &lt;cite&gt;broken&lt;/cite&gt; が表示されます。
ターミナルの設定にも依りますが、それぞれのメッセージは色付けされているかもしれません。
見やすくなっていると嬉しいですね。&lt;/p&gt;
&lt;p&gt;最終的な結果は &lt;cite&gt;output.txt&lt;/cite&gt; というファイルに書き出されます。
ドキュメントのソースコードが階層化されている場合には、出力も階層化されます。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id21"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;エキPy の読書会に行ってきました。
効率的なコードの書き方に関することはありませんでしたが、
ドキュメントを書くことについて再考できました。&lt;/p&gt;
&lt;p&gt;個人的には、多くの日本人ソフトウェアエンジニアに対して、得意なことに関しては次の順序関係が成り立つと思っています。&lt;/p&gt;
&lt;blockquote&gt;
[日本語] &amp;gt;&amp;gt; [業務で使用しているプログラミング言語] &amp;gt; [英語]&lt;/blockquote&gt;
&lt;p&gt;ソフトウェアにはバグがつきもの、という開き直りもあるかもしれませんが、
そもそもそういったソフトウェアの仕様を日本語で書き出してみると、きっと書けないと思います。
馴染みのある日本語で正確に記述できないことを理解に乏しいプログラミング言語で記述しなさい、といっても、
規模が大きくなればなるほど、多様な人たちが混ざれば混ざるほど、それは無理のような気がしてなりません。
(ひとりプロジェクトや、プログラミング言語への理解が日本語への理解と同程度の人たちの集まりは除く)&lt;/p&gt;
&lt;p&gt;英語で書けば論旨が明快になるとの考えは一理ありそうですが、
実際問題として、そんなに英語で読み書き (あるいは会話) できる人は多くありません。
少ない語彙から捻り出した文章はあやふやな表現に終始しがちですので、
まずは日本語で概要を共有してから、なんらかのプログラミング言語で実装するのが良いんだろうな、と思います。&lt;/p&gt;
&lt;p&gt;とはいえ、日本語そのものに対する理解ですら怪しいのは如何ともしがたい、という部分が最大の難関なんでしょうけどね。。。&lt;/p&gt;
&lt;!-- vim: textwidth=120 nobackup nocindent fileencoding=utf-8 : --&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-3342957598732075056?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/3342957598732075056/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=3342957598732075056' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/3342957598732075056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/3342957598732075056'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/06/expert-python-programming-reading-13.html' title='エキスパート Python プログラミングの読書会 - 13'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-3523330910505822515</id><published>2011-06-21T08:19:00.003+09:00</published><updated>2011-08-17T01:04:11.123+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GAE'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Google Tasks API を使ってみる</title><content type='html'>&lt;p&gt;先月、Google Tasks の API が公開されました。
API 公開のアナウンスが出されたときはサンプルがありませんでしたが、
先週末に記事が公開されました。
ライブラリコードのサンプルディレクトリに同様のコードが存在します。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://googleappsdeveloper.blogspot.com/2011/06/getting-started-with-tasks-api-on.html"&gt;Getting Started with the Tasks API on Google App Engine&lt;/a&gt; (Google Apps Developer Blog)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://code.google.com/intl/ja/appengine/articles/python/getting_started_with_tasks_api.html"&gt;Getting Started with Tasks API on Google App Engine&lt;/a&gt; (Google Code - Google App Engine)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;記事/サンプルを読む中では、
&lt;cite&gt;OAuth2Decorator&lt;/cite&gt; クラスが導入されたこと、
コールバック URL のハンドラスクリプトとして &lt;tt class="docutils literal"&gt;oauth2client/appengine.py&lt;/tt&gt; を使えるようになったこと、
この二点が大きな改善点だと思います。&lt;/p&gt;
&lt;p&gt;しかし、それに気付かずに実装しちゃった... という寂しいお話。
いちおう、スクリプトはこちら。。。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://bitbucket.org/skitazaki/google-api-python-client-samples/src/cb18b1b0d088/google-add-task.py"&gt;コマンドライン&lt;/a&gt; (bitbucket)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/skitazaki/cetera/blob/master/src/googleapi.py"&gt;Google AppEngine&lt;/a&gt; (github) - &lt;a class="reference external" href="http://skitazaki.appspot.com/works/googleapi/tasks"&gt;動作用&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;a name='more'&gt;&lt;/a&gt;
&lt;div class="section" id="id3"&gt;
&lt;h1&gt;認証の始まり&lt;/h1&gt;
&lt;p&gt;最近の Google のたいていの API は OAuth 2.0 を使います。
Google が提供している Python のライブラリには &lt;cite&gt;oauth2client&lt;/cite&gt; モジュールがあり、これを使うと簡単にトークンを管理できます。
ちなみに &lt;cite&gt;oauth2&lt;/cite&gt; は OAuth 1.0a 用のライブラリ... というのは蛇足です。&lt;/p&gt;
&lt;p&gt;認証には &lt;tt class="docutils literal"&gt;OAuth2WebServerFlow&lt;/tt&gt; か &lt;tt class="docutils literal"&gt;OAuth2Decorator&lt;/tt&gt; を使うことになりますが、
どちらの場合でも次の４つの情報が必要になります。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;client_id: アプリケーション ID のようなもの。&lt;/li&gt;
&lt;li&gt;client_secret: アプリケーションのパスワードのようなもの。&lt;/li&gt;
&lt;li&gt;scope: アプリケーションがユーザーに許可を求めるアクセス範囲。&lt;/li&gt;
&lt;li&gt;user_agent: アプリケーションの名前。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;client_id と client_secret は &lt;a class="reference external" href="https://code.google.com/apis/console/?pli=1#project:79169647957"&gt;API Console&lt;/a&gt; から取得します。
API Console は画面表示が英語ですが、なんとなくの雰囲気でも使える気がします。
user_agent は適当な名前を付けた方が良いと思いますが、割と何でも動くはずです。
で、おそらく選択肢が存在するのが scope です。&lt;/p&gt;
&lt;p&gt;API を使ったアクセスはユーザーから見えない部分で何をするか分かりませんので、
この範囲内で動作します/させます、と表明します。
最近の話題だと、Twitter が scope の扱いを見直し、ダイレクトメッセージへのアクセス権限を変更しました。
Google の API では、そんな感じの仕組みが細分化されて実現されています。&lt;/p&gt;
&lt;p&gt;Tasks API では、次のふたつの scope から選択できます。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;cite&gt;https://www.googleapis.com/auth/tasks&lt;/cite&gt;: 読み書き (read/write access to Tasks)&lt;/li&gt;
&lt;li&gt;&lt;cite&gt;https://www.googleapis.com/auth/tasks.readonly&lt;/cite&gt;: 読み込み専用 (read-only access to Tasks)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;なんで &lt;cite&gt;https://&lt;/cite&gt; から始まるような長い文字列なのか？という疑問はさておき、
API ドキュメント - Developer's Guide (v1): Using the API - の &lt;a class="reference external" href="http://code.google.com/intl/ja/apis/tasks/v1/using.html#auth"&gt;Authorizing requests&lt;/a&gt; に記載されています。
Google のそれぞれの API には類似のドキュメントがあり、たとえばモデレータの場合には、
tasks の部分が moderator になったような感じで記載されています。
モデレータについては &lt;a class="reference external" href="http://kshigeru.blogspot.com/2011/03/google-moderator-hack4jp.html"&gt;Hack for Japan の Google モデレーターのデータを見る&lt;/a&gt; (過去記事) で同じような認証フローを書いています。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id4"&gt;
&lt;h1&gt;コールバック&lt;/h1&gt;
&lt;p&gt;先ほどまでの部分 (コードを掲載してないけど) で、OAuth 2.0 認証の準備が整いました。
OAuth は、認可するサービス (この場合は Google) と認可されるアプリケーション (この場合は自作アプリ) が別々に動いていますから、
認可が終わったら何らかの方法でユーザーをアプリケーションに戻す必要があります。
Web アプリケーションでの常套手段として HTTP リダイレクトがありますので、
アプリケーションはリダイレクト先のコールバック URL を準備しておきます。&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;API Console に登録する。&lt;/li&gt;
&lt;li&gt;アプリケーションに特別な URL を用意し、GET パラメータを解析する。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;コールバックは、たとえば &lt;cite&gt;flow&lt;/cite&gt; という変数が &lt;cite&gt;OAuth2WebServerFlow&lt;/cite&gt; のインスタンスであり、
コールバック URL のリクエストハンドラを AppEngine の webapp フレームワークの RequestHandler で実装した場合、
次のように記述できます。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
credentials = flow.step2_exchange(self.request.params)
&lt;/pre&gt;
&lt;p&gt;この戻り値がユーザーの認証トークンになります。&lt;/p&gt;
&lt;p&gt;いちいちこのような仕組みを理解しながら記述するのは煩雑なので、
Google API Python Client では &lt;tt class="docutils literal"&gt;oauth2client/appengine.py&lt;/tt&gt; というスクリプトを提供してくれています。
冒頭に挙げた Google Code の記事では、 &lt;tt class="docutils literal"&gt;app.yaml&lt;/tt&gt; に次のハンドラを追加しています。&lt;/p&gt;
&lt;pre class="literal-block"&gt;
handlers:
- url: /oauth2callback
  script: oauth2client/appengine.py
&lt;/pre&gt;
&lt;p&gt;ライブラリの中に実行コードも一緒にして配布しているわけです。
実際にコードを見てみると、最後に次の変数と関数が定義されています。&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
application = webapp.WSGIApplication([('/oauth2callback', OAuth2Handler)])

def main():
  run_wsgi_app(application)
&lt;/pre&gt;
&lt;p&gt;URL が決め打ちになってしまいますが、簡単にコールバックを処理できるのは嬉しいと思います。&lt;/p&gt;
&lt;p&gt;なお、API Console で登録していない URL をコールバックに指定すると認証エラーになります。
AppEngine の場合はローカル環境で開発してプロダクション環境にデプロイしますので、
その両方 (ふつうは localhost と app-id.appspot.com) の URL を登録しておきます。
ホスト名以降のパスも一致していなければなりませんので、最初の登録には注意が必要かもしれません。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id5"&gt;
&lt;h1&gt;タスクリストとタスク&lt;/h1&gt;
&lt;p&gt;認証トークンを使えるようになると、ようやく Tasks API を実行できます。
Tasks にはふたつのデータモデルがあります。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;タスクリスト (task list): 複数のタスクをまとめるカテゴリのようなもの。&lt;/li&gt;
&lt;li&gt;タスク (task): 個別の「やること」。期限や状態を設定できる。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ユーザーはデフォルト (&lt;tt class="docutils literal"&gt;&amp;#64;default&lt;/tt&gt;) のタスクリストを含む複数のタスクリストを持つことができます。
個々のタスクはいずれかのタスクリストに所属します。
つまり、タスクを操作するためには次の二つのステップが必要になります。&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;タスクリストの一覧を取得する。&lt;/li&gt;
&lt;li&gt;タスクリストを指定して、タスクの一覧を取得する。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;実際に API 用のサービスを構築し、タスクリストを取得するコードは次のように記述できます。
&lt;cite&gt;credentials&lt;/cite&gt; は OAuth 2.0 の認証トークンオブジェクトです。&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
http = httplib2.Http()
http = credentials.authorize(http)

service = build('tasks', 'v1', http=http)

tasklists = service.tasklists().list().execute()
for item in tasklists['items']:
    if item['title']:
        print '*', item['title']
&lt;/pre&gt;
&lt;p&gt;&lt;cite&gt;build()&lt;/cite&gt; は JSON のサービス定義ファイルからメソッドを構築するためのものです。
Discovery と呼ばれる仕組みで、要するに以下の JSON ファイルを読み込んでオブジェクトを生成します。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://www.googleapis.com/discovery/v1/apis/tasks/v1/rest"&gt;https://www.googleapis.com/discovery/v1/apis/tasks/v1/rest&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;人間が読むような代物でもありませんが、 &lt;cite&gt;resources&lt;/cite&gt; というキーに対応する値がインスタンス化されます
(表現が微妙な気もしますが)。
いちおう読んでみると、メソッド名やそこで使われる HTTP メソッド、パラメータとして有効なもの、その順番などが記述されています。
メソッドごとのスコープも制限されていることが分かります。
&lt;cite&gt;tasklists&lt;/cite&gt; には &lt;cite&gt;methods&lt;/cite&gt; が定義されており、その中に &lt;cite&gt;list&lt;/cite&gt; があります。
&lt;cite&gt;path&lt;/cite&gt; や &lt;cite&gt;description&lt;/cite&gt; と API ドキュメントを照らし合わせてみると、何となく意味が分かってくるかもしれませんね。&lt;/p&gt;
&lt;p&gt;(JSON を一部抜粋)&lt;/p&gt;
&lt;pre class="prettyprint lang-json"&gt;
&amp;quot;list&amp;quot;: {
 &amp;quot;id&amp;quot;: &amp;quot;tasks.tasklists.list&amp;quot;,
 &amp;quot;path&amp;quot;: &amp;quot;users/&amp;#64;me/lists&amp;quot;,
 &amp;quot;httpMethod&amp;quot;: &amp;quot;GET&amp;quot;,
 &amp;quot;description&amp;quot;: &amp;quot;Returns all the authenticated user's task lists.&amp;quot;,
 &amp;quot;parameters&amp;quot;: {
  &amp;quot;maxResults&amp;quot;: {
   &amp;quot;type&amp;quot;: &amp;quot;integer&amp;quot;,
   &amp;quot;description&amp;quot;: &amp;quot;Maximum number of task lists returned on one page. Optional. The default is 100.&amp;quot;,
   &amp;quot;minimum&amp;quot;: &amp;quot;-9223372036854775808&amp;quot;,
   &amp;quot;maximum&amp;quot;: &amp;quot;9223372036854775807&amp;quot;,
   &amp;quot;location&amp;quot;: &amp;quot;query&amp;quot;
  },
  &amp;quot;pageToken&amp;quot;: {
   &amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,
   &amp;quot;description&amp;quot;: &amp;quot;Token specifying the result page to return. Optional.&amp;quot;,
   &amp;quot;location&amp;quot;: &amp;quot;query&amp;quot;
  }
 },
 &amp;quot;response&amp;quot;: {
  &amp;quot;$ref&amp;quot;: &amp;quot;TaskLists&amp;quot;
 },
 &amp;quot;scopes&amp;quot;: [
  &amp;quot;https://www.googleapis.com/auth/tasks&amp;quot;,
  &amp;quot;https://www.googleapis.com/auth/tasks.readonly&amp;quot;
 ]
},
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="id6"&gt;
&lt;h1&gt;タスクを取得する&lt;/h1&gt;
&lt;p&gt;次に、タスクの一覧を取得します。
すべてのユーザーは &lt;cite&gt;&amp;#64;default&lt;/cite&gt; というタスクリストを持つはず (意図的に削除しようとした場合などは未確認) ですので、
決め打ちにしてしまって一覧を取得します。&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
tasks = service.tasks().list(tasklist='&amp;#64;default').execute()
for task in tasks['items']:
    if task['title']:
        print '*', task['title']
&lt;/pre&gt;
&lt;p&gt;タスクにはタイトルがありますが、空文字でも構わないようなので、if 文で確認しています。
個人的には必須で良いのにな、と思いますが、そこはそういう仕様のようです。&lt;/p&gt;
&lt;p&gt;NOTE:&lt;/p&gt;
&lt;blockquote&gt;
内部的に &lt;cite&gt;uritemplate&lt;/cite&gt; モジュールを使いますが、バージョンによっては &amp;quot;&amp;#64;&amp;quot; の置換がうまくいかないかもしれません。
google-api-python-client に含まれる uritemplate と本家のものは &lt;a class="reference external" href="http://code.google.com/p/google-api-python-client/source/diff?spec=svnb19a82cee67a03db0c6b44bd0c375adbcecd8cfc&amp;amp;r=b19a82cee67a03db0c6b44bd0c375adbcecd8cfc&amp;amp;format=side&amp;amp;path=/uritemplate/__init__.py"&gt;safe が違う&lt;/a&gt; ためです (将来的には統一される？)。&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class="section" id="id7"&gt;
&lt;h1&gt;タスクを登録する&lt;/h1&gt;
&lt;p&gt;登録するときは &lt;cite&gt;insert()&lt;/cite&gt; メソッドを実行 (&lt;cite&gt;execute()&lt;/cite&gt;) します。
&lt;cite&gt;insert()&lt;/cite&gt; の引数には &lt;cite&gt;tasklist&lt;/cite&gt; と &lt;cite&gt;body&lt;/cite&gt; を指定します。
'notes' と 'due' は指定しなくても構いません。&lt;/p&gt;
&lt;pre class="prettyprint lang-py"&gt;
task = {
    'title': 'ファミマカードの支払い',
    'notes': 'そろそろ完済したい。',
    'due': '2011-07-08T12:00:00.000Z'
}
result = service.tasks().insert(tasklist='&amp;#64;default', body=task).execute()
print &amp;quot;Created a new task,&amp;quot;, result['id']
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="id8"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;p&gt;Google Tasks API を使ってみました。
認証部分と Discovery あるいはドキュメントのどこを読むべきかが分かってくると、
どの API も似たようなイメージで利用できます。
ライブラリ自体も着々と改善されていますので、もうすぐ正式リリースとなるかもしれません。&lt;/p&gt;
&lt;p&gt;タスク API は簡単に扱えますが、そもそも Google Tasks の位置付けが微妙... という考えもあります。
とはいえ、AppEngine にメールを送ったら勝手に登録してくれるようにできると、
ケータイメールで受け取ったことを転送するだけでタスク化できます。
また、メールとカレンダーの両方に統合されているため、タスク自体に気付きやすいように思います。
要は、どこまで Google Account に集約するか？という問題になるでしょう。&lt;/p&gt;
&lt;p&gt;なお、最近は API ドキュメントのサンプルに PHP も追加されました。
そこは Go じゃ... という気がしなくもありませんが、幅広くサンプルが揃うのは良いことだと思います。&lt;/p&gt;
&lt;p&gt;おまけとして、過去には、モバイル画面をスクレイピングする、という記事もありました。
もちろん、今となっては非推奨でしょうけど。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://www.ibm.com/developerworks/mydeveloperworks/blogs/pgmrk/entry/google__e3_82_bf_e3_82_b9_e3_82_af_e3_81_ae_e4_b8_80_e8_a6_a7_e3_82_92_e5_8f_96_e5_be_97_e3_81_99_e3_82_8b9?lang=ja"&gt;Google タスクの一覧を取得する&lt;/a&gt; (IBM dW)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-3523330910505822515?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/3523330910505822515/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=3523330910505822515' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/3523330910505822515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/3523330910505822515'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/06/google-tasks-api.html' title='Google Tasks API を使ってみる'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-6696631721974837516</id><published>2011-05-29T01:23:00.005+09:00</published><updated>2011-05-29T01:43:14.308+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><title type='text'>アジャイルスタートアップの後で思ったこと</title><content type='html'>&lt;p&gt;MIT Media Lab新所長、伊藤穰一とPivotalのCTO,Ian McFarlandが語る「アジャイルスタートアップ」に行ってきました。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://atnd.org/events/16029"&gt;ATND のページ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ハッシュタグ &lt;a class="reference external" href="https://twitter.com/search/%23on_lab"&gt;#on_lab&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;自分の認識では &lt;a class="reference external" href="http://pivotallabs.com/"&gt;Pivotal Labs&lt;/a&gt; は &lt;a class="reference external" href="http://www.pivotaltracker.com/"&gt;Pivotal Tracker&lt;/a&gt; を作っている会社でしたが、
アジャイル開発に関するコンサルティングにも取り組んでいるようです (コンサルの方がメイン？)。
&lt;a class="reference external" href="http://pivotallabs.com/clients"&gt;クライアント企業&lt;/a&gt; を見てみると、Twitter、
Best Buy、Groupon、Linden Labs、Salesforce、Alexa などが名前を連ねています。
&lt;a class="reference external" href="http://www.ideo.com/"&gt;IDEO&lt;/a&gt; と協力してコンサルティングに関わることもあるようで、ソフトウェア業界のひとつの最先端、
と呼べる立場だと思います。&lt;/p&gt;
&lt;p&gt;今回はそんな会社の CTO と、 &lt;a class="reference external" href="http://web.mit.edu/press/2011/ito-media-lab-director.html"&gt;MIT Media Lab のディレクター&lt;/a&gt; のトークセッションでした。
セッション内容に関しては Twitter を見るなり、もしかしたらネットメディアに取り上げられるかもしれませんので、そちらを参照、ということで。
この記事では、自分がなんとなく思ったことをツラツラと。&lt;/p&gt;
&lt;p&gt;自分のメモ:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/74051050084122624"&gt;18:55&lt;/a&gt; - 「今日は通訳がいない」と今気づいたw 今さっき相談して進め方を決めるとは、アジリティ高い。&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/74052233670557696"&gt;19:00&lt;/a&gt; - アジャイルのストーリーボードとかスプリントの説明から。方向性だけ決めておく。Pivot で細かい部分はサクサク切り替える。Pivotal の由来はそれ。&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/74053202198274048"&gt;19:03&lt;/a&gt; - 「テストを書く方が実際のコードより多い」。RoR での TDD の実例と絡めた話。テストは自然言語で書くから、ビジネスオーナーとのコミュニケーションやリリースタイミングが分かりやすい。&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/74054443737427968"&gt;19:08&lt;/a&gt; - タスク群に対して velocity を管理し続けるから、開発者の健康には良いかも。締め切りを厳密にするのではなく、このままのペースで進めばいつまでに機能を充足できるかを見積りできそう。&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/74055150720917504"&gt;19:11&lt;/a&gt; - 8時45分に朝ごはんを用意。それに合わせて出社。Pivotal さんは朝早い！125人くらい。&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/74055943960281088"&gt;19:14&lt;/a&gt; - 「コードを書いてるときにイノベーションを生み出してはダメ！」新しいことはストーリーボードを作っているときに。&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/74057044692451328"&gt;19:19&lt;/a&gt; - プロトタイプ (テスト無し) をプロダクション (テスト有り) に書き換えるときはバグも含めてそのままに。ついでに機能追加とかダメ。&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/74059154142134273"&gt;19:27&lt;/a&gt; - 大きな機能や思い入れのある機能を捨て去るのは心情的に悩ましい。ストーリーが細かく分割されていれば、軌道修正 (Pivot) に取り組みやすい。&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/74062347135754240"&gt;19:40&lt;/a&gt; - 「Zynga なんかのプロダクトマネージャーはみんな SQL をたたいて、データドリブン」... えっ(-_-;)&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://twitter.com/kshigeru/statuses/74071901324050432"&gt;20:18&lt;/a&gt; - ペアプログラミングだとふたりで同じことやるから全体の生産性は落ちるのかも、とか思っていたけど、ペアプロ中はメールも YouTube も見ないから集中力が高い状態に追い込まれる、と。。普段がいかにぬるま湯かを思い知らされた感じ。とても勉強になりました。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;朝会 (&lt;a class="reference external" href="http://martinfowler.com/articles/itsNotJustStandingUp.html"&gt;daily standup meeting&lt;/a&gt;) も良いですが、
朝食を用意した方が色々と嬉しい人も多いかもしれませんね。&lt;/p&gt;
&lt;div class="section" id="id13"&gt;
&lt;h1&gt;アジャイルって？&lt;/h1&gt;
&lt;div style="float:right; margin:5px;"&gt;
&lt;iframe src="http://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&amp;bc1=000000&amp;IS2=1&amp;bg1=FFFFFF&amp;fc1=000000&amp;lc1=0000FF&amp;t=kshigeru-22&amp;o=9&amp;p=8&amp;l=as4&amp;m=amazon&amp;f=ifr&amp;ref=ss_til&amp;asins=4839924023" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a class="reference external" href="http://ja.wikipedia.org/wiki/%E3%82%A2%E3%82%B8%E3%83%A3%E3%82%A4%E3%83%AB%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E9%96%8B%E7%99%BA"&gt;アジャイルソフトウェア開発&lt;/a&gt; を略して「アジャイル」で、英語だと &amp;quot;agile&amp;quot; です。
&amp;quot;agile&amp;quot; は日本語だと「機敏な」や「敏捷な」という意味で、
RPG (ロールプレイングゲーム) の「素早さ」を表すパラメータに &amp;quot;AGL&amp;quot; を使うものもありますが、
これは &amp;quot;agile&amp;quot; からの３文字になります。
要するに、高品質なソフトウェアを素早く提供するためにはどうすれば良いか？という課題に対する
ひとつのアプローチと言えます。&lt;/p&gt;
&lt;p&gt;より詳しくは「アジャイルソフトウェア開発宣言」 (&lt;a class="reference external" href="http://www.agilemanifesto.org/"&gt;The Agile Manifesto&lt;/a&gt;) があります。
今年の２月で10年を迎えていますので、この10年の変化を振り返りながらいろいろな記事が発表されました。
個人的に印象に残ったのは次の記事です。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://blog.mountaingoatsoftware.com/reflections-on-the-10-years-since-the-agile-manifesto"&gt;REFLECTIONS ON THE 10 YEARS SINCE THE AGILE MANIFESTO&lt;/a&gt; (Mike Cohn’s Blog - Succeeding with Agile)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ざっくりした内容は次のようになります。(引用や翻訳ではありません)&lt;/p&gt;
&lt;blockquote&gt;
この10年で言葉と考え方が浸透してきたこと、実践すべきだ！との認識も増えてきており、
部門長に提案するときには議題に上げるべきでしょう。
また、- &amp;quot;We stop talking about agile.&amp;quot; - つまり、それが何であるかを議論するフェーズから、
それをどのように実践するか、ベストプラクティスは何か、といったことを議論するフェーズになりつつあります。
例えば、オブジェクト指向プログラミングを語る際に、「オブジェクトとは何か？」を議論するフェーズは過ぎ去り、
OO (Object-Oriented) な考え方は当然ともみなされていますよね？
アジャイルに関しても同様です。もはや実践して然るべき概念なのです。&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div class="section" id="id15"&gt;
&lt;h1&gt;ウォーターフォール開発&lt;/h1&gt;
&lt;p&gt;アジャイル開発と比較してウォーターフォール開発が挙げられます。
&amp;quot;waterfall&amp;quot; は滝のことで、水が溜まったら上から下へと一気に流れる様子から、
要求獲得、仕様作成、システムの実装、検証を順番に実施する開発モデルを表現します。&lt;/p&gt;
&lt;p&gt;滝が勢いよく流れ落ちるためにはたくさんの水を溜める必要があり、通り道に遮蔽物が存在しない方が望ましいですね。
ウォーターフォール開発も同様で、要求が適切に検討されて、実装がスムーズに進むように準備しておく必要があります。
要求 (実現したいこと) が曖昧で、製品開発と技術研修が混在している状態では、勢いよくシステムを開発することは難しいでしょう。
水はいつしか地面に辿りつき、地面に浸み込んだり蒸発したり、あるいは海に流れ出ることもあります。
しかし、コンピュータシステムはそうもいきません。
時流に乗って多くのユーザーを獲得できる Web サービスや、いつまでも使われる社内システムは確かにあります。
それは幸せなことですが、あくまで一握りの成功例。
予算を割り当てて多くの人員を投入し、せっかく作ったものが負債になってしまっても、それを無に帰すことはできません。&lt;/p&gt;
&lt;p&gt;無かったことにはできない、という点ではアジャイルも同じですが、
ウォーターフォールに比べて、こまめにフィードバックを受け取って軌道修正を重ねる、という点が違います。
どちらも一長一短ですし、要は方法論なのでどっちでもいいじゃん、と言えばそうかもしれません。
しかし、いつフィードバックを受け取るか？という部分に心理的な違いがあります。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id16"&gt;
&lt;h1&gt;締め切り意識&lt;/h1&gt;
&lt;p&gt;たいていの受託開発は、契約で決めた納期に成果物を提出し、場合によってはその後の保守を請け負います。
契約開始時点では、期日と何らかの要件を決めますね。
機能の一覧だったり性能要件だったり内容は様々ですが、何らかのゴールが契約書という形で存在します。&lt;/p&gt;
&lt;p&gt;一方で自社製品開発の場合は、社内の誰かしらが製品企画を取りまとめます。
売り上げ予測だったり開発工数だったりを算出し、リリース期日を設定します。
期日に合わせてプロモーションを進めているかもしれません。
これがプロジェクトメンバーのゴールとなります。&lt;/p&gt;
&lt;p&gt;どちらの場合も、締切日が存在します。&lt;/p&gt;
&lt;p&gt;ちょっと話題を変えて、小学校の夏休みの宿題を振り返ってみます。
多くの小学校 (地域により違いはある) は、9月1日が二学期の開始です。
この日が夏休みの宿題の締切日とも言えます (最初の授業で提出する場合もあるが、そこは気にしない)。
さて、宿題の進捗状況はどうだったでしょうか？&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;最初の数日で計画を立て、徐々に進めて、最後の数日で細かい部分を調整する。&lt;/li&gt;
&lt;li&gt;とりあえず最初は何もせず、最後の数日で一気に片付ける。&lt;/li&gt;
&lt;li&gt;時期とは無関係に自分のペースで進めて、夏休みの中盤には終わってる。&lt;/li&gt;
&lt;li&gt;時期とは無関係に自分のペースで進めたものの、全ては終わらなかった。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;「なぜもっと早く着手しなかったの？」と問われれば、「ギリギリの方が本気出せるから」と答える人も多いでしょう。
それはそれで正しいことだと思います。
この場合、締め切りが存在すればその日までに完成するでしょうが、その前には完成しません。
フィードバックを受け取れる状態になるのは、締め切り直前でしかありません。&lt;/p&gt;
&lt;p&gt;一方で、一定のペースで進めた場合には、終わるかもしれないし終わらないかもしれないし、
常に不完全かもしれませんが、いつでもフィードバックを受け取れます。
もしかしたら、スピードを上げるために友達に相談できるかもしれません。
爆発的な推進力に欠けるかもしれませんが、次に何をすべきかの判断材料には事欠かないでしょう。&lt;/p&gt;
&lt;p&gt;夏休みの宿題は個人の話なのでどちらでも構いませんが、関係者が増えてくると状況が異なってきます。
最終成果物の前にレビューを実施するとなれば、その前に途中成果をまとめる必要があるかもしれません。
わざわざまとめる時間がかかるのに、その効果が分かり難い、という理由で、レビューが敬遠されるチームもあるでしょう。
レビュー結果を反映したものを再レビューになれば、もっと時間がかかります。
たとえ実施したとしても、いわゆる「締め切りに追われる」状態に陥ってしまい、体力的にも精神的にも長くは続かないかもしれません。&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="id17"&gt;
&lt;h1&gt;マインドを変える&lt;/h1&gt;
&lt;p&gt;締切駆動に反して、Velocity (速度) という考え方があります。
「いつまでにここまで進める」のではなく、「ここまで進むためにはこれだけ時間がかかった」ことを管理し続けていく手法です。
チームのメンバーが変わらない場合、速度が分かれば将来の予測を立てやすくなります。&lt;/p&gt;
&lt;p&gt;同じ難易度のタスクが10個存在 (実際には有り得ないが) したら、ひとつに1週間かかるなら全部終わるまでには10週間かかる、と言えます。
同じペースで進める、それぞれのタスクが独立している、の二点が大事だと思います。
つまり、全てを実現しなくとも、競合企業に対抗するためやユーザーの反応を見るためには途中でリリースできる状態です。
4週間でリリースして4週間は反応を見ながら開発を進めて、実は不要だったと分かれば、その後の2週間は軌道修正できます。
締切駆動にパレードの法則が重なってしまうと、最後の2週間に全体の8割を実現する計画になるかもしれず、それを修正する術はありません。&lt;/p&gt;
&lt;p&gt;「そうは言っても自分は計画的だ！」と主張する人もいるかもしれません。
ただ、その人の周りにいる全ての人も計画的だとは限りません。
人間がふたり以上集まれば意思疎通が必要です。
目的地を設定して出掛けるのか、とりあえず出掛けてみてから目的地を見つけるのか、その意識合わせが大切になります。&lt;/p&gt;
&lt;p&gt;目標意識を共有せずとも良い、あるいは無計画でも良い、とは違います。
特定の部分 (時期の問題と人の問題) にしわ寄せがいかないようにしましょう、と言えるかもしれません。
極端かもしれませんが、特定の人が特定の工程に責任を持つモデルがウォーターフォール、
みんなが全体に責任を持つモデルがアジャイルとも考えられます。
チームの構成メンバーや何を実現すべきかに合わせて、考え方を切り替えるべきでしょう。&lt;/p&gt;
&lt;p&gt;なお、チームとしての Velocity を維持するためには、そのタスクに要した時間を管理しておかなくてはなりません。
時間管理に関してはポモドーロテクニックなどが役立つかもしれませんね。&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://rashita.net/blog/?p=5894"&gt;ポモドーロテクニックについて４&lt;/a&gt; (R-style)&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="id19"&gt;
&lt;h1&gt;終わりに&lt;/h1&gt;
&lt;div style="float:right; margin:5px;"&gt;
&lt;iframe src="http://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&amp;bc1=000000&amp;IS2=1&amp;bg1=FFFFFF&amp;fc1=000000&amp;lc1=0000FF&amp;t=kshigeru-22&amp;o=9&amp;p=8&amp;l=as4&amp;m=amazon&amp;f=ifr&amp;ref=ss_til&amp;asins=4795296758" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;興味のあったイベントに行ってきました。
簡単に感想でも書こうかな、と思いましたが、ちょっと違う切り口で自分の考えを整理してみることも良いかな、と考え直し、
アジャイルとウォーターフォールのひとつの側面を対比させてみました。&lt;/p&gt;
&lt;p&gt;とにもかくにも、方法論を変えるためには、関係する人たちの考え方も変えなければなりません。
現在実践していることと検討していることを対比させながら、何に似ていて何とは違うのか、
メリットとデメリットは何かを明らかにしていく、という、普通のことを普通に実行する必要があるでしょう。&lt;/p&gt;
&lt;p&gt;「ウォーターフォールは古臭いから、これからはアジャイルだ！」と主張したいのではなく、
いくつかの方法論がありますが、それぞれを使い分けるためにはチームメンバー (もしくは外部の関係する人たち) の考え方を変える必要がありますね、という話です。
どんな病気においても特効薬はありませんので、医師にすがりつくだけでなく、患者と医師が協力して健康を維持できるようになると良いですね。&lt;/p&gt;
&lt;p&gt;まぁ「人月の神話」を読んで実践すれば良いんじゃ... という話なのかもしれません。
出版から数十年が経過しても変わらない考え方が存在することは間違いありません。
表現方法を少しずつ変えながら、多くの人に分かりやすくなっていくと良いのかな。&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2604690493777706486-6696631721974837516?l=kshigeru.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://kshigeru.blogspot.com/feeds/6696631721974837516/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2604690493777706486&amp;postID=6696631721974837516' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/6696631721974837516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2604690493777706486/posts/default/6696631721974837516'/><link rel='alternate' type='text/html' href='http://kshigeru.blogspot.com/2011/05/agile-startup.html' title='アジャイルスタートアップの後で思ったこと'/><author><name>Shigeru Kitazaki</name><uri>https://profiles.google.com/110902178337618378991</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh5.googleusercontent.com/--1WCIaIzLbk/AAAAAAAAAAI/AAAAAAAAAAA/X89pNY72Qjw/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2604690493777706486.post-271809333512821618</id><published>2011-05-01T15:51:00.004+09:00</published><updated>2011-08-23T01:03:17.508+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Books'/><category scheme='http://www.blogger.com/atom/ns#' term='Dev'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>エキスパート 
