<?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-2101613690891415478</id><updated>2012-02-16T16:59:44.041+09:00</updated><category term='PHP'/><category term='jquery'/><category term='urllib'/><category term='django'/><category term='python'/><title type='text'>hikozaemonchan</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>47</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-8548927040099594822</id><published>2011-01-26T01:00:00.000+09:00</published><updated>2011-01-26T01:00:12.840+09:00</updated><title type='text'>Custom XmlAdapter for Joda Time with xjc</title><content type='html'>JAXBを使ってますか？&lt;br /&gt;JAXBとJoda-Timeを連携してみましょう。&lt;br /&gt;&lt;br /&gt;以下のクラスとXMLをBindするのが目標です。&lt;br /&gt;&lt;pre class="java" name="code"&gt;public class Foo {&lt;br /&gt;  private DateTime bar;&lt;br /&gt;  private DateTime baz;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;foo&amp;gt;&lt;br /&gt;  &amp;lt;bar&amp;gt;2011-2-3&amp;lt;/bar&amp;gt;&lt;br /&gt;  &amp;lt;baz&amp;gt;2010-3-4T05:06:07&amp;lt;/baz&amp;gt;&lt;br /&gt;&amp;lt;/foo&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;JAXBでは面倒な点がいくつかありました。&lt;br /&gt;1. @XmlType(propOrder)にフィールドを列挙する必要がある。&lt;br /&gt;2. xs:dateはXmlGregorianCalendarに割り当てられている。&lt;br /&gt;&lt;br /&gt;うーん、面倒ですね。GroovyだったらとかClojureだったらとか、思わずにはいられない。&lt;br /&gt;それぞれの対策を書いていきます。&lt;br /&gt;&lt;br /&gt;1. @XmlType(propOrder)にフィールド名を列挙する必要がある。&lt;br /&gt;アノテーションでは順序が保たれないため、フィールドとpropOrderの双方に書く必要がある。&lt;br /&gt;とりあえず生成するGroovyコードを書いたのですが、調べたらxjcなんてものがあったので、移植してみました。&lt;br /&gt;かんたんなスキーマを書いてみます。&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"&amp;gt;&lt;br /&gt;  &amp;lt;xs:element name="foo"&amp;gt;&lt;br /&gt;    &amp;lt;xs:complextype&amp;gt;&lt;br /&gt;      &amp;lt;xs:sequence&amp;gt;&lt;br /&gt;        &amp;lt;xs:element name="bar" type="xs:date" /&amp;gt;&lt;br /&gt;        &amp;lt;xs:element name="baz" type="xs:dateTime" /&amp;gt;&lt;br /&gt;      &amp;lt;/xs:sequence&amp;gt;&lt;br /&gt;    &amp;lt;/xs:complextype&amp;gt;&lt;br /&gt;  &amp;lt;/xs:element&amp;gt;&lt;br /&gt;&amp;lt;/xs:schema&amp;gt;&lt;br /&gt;&lt;/pre&gt;生成されたbar,bazの型は、見慣れないXmlGregorianCalendar なんだこれ。&lt;br /&gt;&lt;br /&gt;2. xs:dateはXmlGregorianCalendarに割り当てられている。&lt;br /&gt;&lt;a href="http://weblogs.java.net/blog/kohsuke/archive/2006/03/how_do_i_map_xs.html"&gt;http://weblogs.java.net/blog/kohsuke/archive/2006/03/how_do_i_map_xs.html&lt;/a&gt;&lt;br /&gt;xjcの開発者であるkohsukeのブログでXmlGregorianCalendarを使わない方法があったので参考にしました。&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;xs:schema elementFormDefault="qualified" version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" jaxb:version="2.0" targetNamespace="calendar-schemalet"&amp;gt;&lt;br /&gt;  &amp;lt;xs:annotation&amp;gt;&amp;lt;xs:appinfo&amp;gt;&lt;br /&gt;    &amp;lt;jaxb:globalBindings&amp;gt;&lt;br /&gt;      &amp;lt;jaxb:javaType name="java.util.Calendar" xmlType="xs:date"&lt;br /&gt;        parseMethod="javax.xml.bind.DatatypeConverter.parseDate"&lt;br /&gt;        printMethod="javax.xml.bind.DatatypeConverter.printDate"&lt;br /&gt;        /&amp;gt;&lt;br /&gt;    &amp;lt;/jaxb:globalBindings&amp;gt;&lt;br /&gt;  &amp;lt;/xs:appinfo&amp;gt;&amp;lt;/xs:annotation&amp;gt;&lt;br /&gt;&amp;lt;/xs:schema&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;なるほど。変換するメソッドを呼び出すことができるわけですね。&lt;br /&gt;この例では準備されたメソッドですが、任意のメソッドを呼び出すことができます。&lt;br /&gt;標準のはCalendarなので、java.util.Dateに変換するのを書けばいいだけ。&lt;br /&gt;簡単ですね。&lt;br /&gt;これでどんな型でも自由自在。&lt;br /&gt;xs:appinfoを別のファイルに移し、xs:includeすると共通化できて便利です。&lt;br /&gt;うまく名前空間を利用するとインクルードなしでもいけるんでしょうが。&lt;br /&gt;&lt;br /&gt;ここで一つ別の問題が出てきました。&lt;br /&gt;&lt;br /&gt;3. 余計なAdapterが生成される&lt;br /&gt;Adapter1やAdapter2が勝手に生成されてしまいます。&lt;br /&gt;できればこれらの名前も指定したいところ。&lt;br /&gt;最終的にはこうなりました。&lt;br /&gt;&lt;pre class="xml" name="code"&gt;&amp;lt;xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"&lt;br /&gt;  xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" jaxb:extensionBindingPrefixes="xjc" jaxb:version="2.0"&amp;gt;&lt;br /&gt;  &amp;lt;xs:annotation&amp;gt;&lt;br /&gt;    &amp;lt;xs:documentation&amp;gt;custom datetime adapter&amp;lt;/xs:documentation&amp;gt;&lt;br /&gt;    &amp;lt;xs:appinfo&amp;gt;&lt;br /&gt;      &amp;lt;jaxb:globalBindings&amp;gt;&lt;br /&gt;        &amp;lt;xjc:javaType name="org.joda.time.DateTime" adapter="hikoz.xml.DateAdapter" xmlType="xs:date"/&amp;gt;&lt;br /&gt;        &amp;lt;xjc:javaType name="org.joda.time.DateTime" adapter="hikoz.xml.DateTimeAdapter" xmlType="xs:dateTime"/&amp;gt;&lt;br /&gt;      &amp;lt;/jaxb:globalBindings&amp;gt;&lt;br /&gt;    &amp;lt;/xs:appinfo&amp;gt;&lt;br /&gt;  &amp;lt;/xs:annotation&amp;gt;&lt;br /&gt;  &amp;lt;xs:element name="foo"&amp;gt;&lt;br /&gt;    &amp;lt;xs:complexType&amp;gt;&lt;br /&gt;      &amp;lt;xs:sequence&amp;gt;&lt;br /&gt;        &amp;lt;xs:element name="bar" type="xs:date" /&amp;gt;&lt;br /&gt;        &amp;lt;xs:element name="baz" type="xs:dateTime" /&amp;gt;&lt;br /&gt;      &amp;lt;/xs:sequence&amp;gt;&lt;br /&gt;    &amp;lt;/xs:complexType&amp;gt;&lt;br /&gt;  &amp;lt;/xs:element&amp;gt;&lt;br /&gt;&amp;lt;/xs:schema&amp;gt;&lt;br /&gt;&lt;/pre&gt;Adapterはこんな感じ。&lt;br /&gt;日付の形式も自由自在。ただしおすすめはできないけど。&lt;br /&gt;読みたいこともあるよね。&lt;br /&gt;&lt;pre class="java" name="code"&gt;public class DateTimeAdapter extends XmlAdapter&amp;lt;String, Datetime&amp;gt; {&lt;br /&gt; private static final DateTimeFormatter YMDHMS = DateTimeFormat.forPattern("yyyy/MM/dd HH:mm:ss");&lt;br /&gt; @Override&lt;br /&gt; public DateTime unmarshal(String v) throws Exception {&lt;br /&gt;  return YMDHMS.parseDateTime(v);&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; @Override&lt;br /&gt; public String marshal(DateTime v) throws Exception {&lt;br /&gt;  return YMDHMS.print(v);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;以下はテストコードと、xjcの実行。&lt;br /&gt;Antタスクもあったんだけど、最近build.xmlを書いてないから構文を忘れた。&lt;br /&gt;Gradleかわいいよ&lt;br /&gt;&lt;br /&gt;&lt;pre class="java" name="code"&gt;@Test&lt;br /&gt;  public void readwrite() throws Exception {&lt;br /&gt;    StringWriter sw = new StringWriter();&lt;br /&gt;    Foo foo = new Foo();&lt;br /&gt;    foo.setBar(new DateTime(2011, 2, 3, 4, 5, 6, 7));&lt;br /&gt;    foo.setBaz(new DateTime(2012, 3, 4, 5, 6, 7, 8));&lt;br /&gt;    JAXB.marshal(foo, sw);&lt;br /&gt;    StringReader sr = new StringReader(sw.toString());&lt;br /&gt;    Foo foo2 = JAXB.unmarshal(sr, Foo.class);&lt;br /&gt;    assertThat(foo2.getBar(), is(new DateTime(2011, 2, 3, 0, 0, 0, 0)));&lt;br /&gt;    assertThat(foo2.getBaz(), is(new DateTime(2012, 3, 4, 5, 6, 7, 0)));&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public static void main(String[] args) throws Exception {&lt;br /&gt;    com.sun.tools.xjc.Driver&lt;br /&gt;        .main("-no-header -extension -d src/test/java -p hikoz.xml src/test/java/hikoz/xml/foo.xsd"&lt;br /&gt;            .split("\\s+"));&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-8548927040099594822?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/8548927040099594822/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=8548927040099594822' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/8548927040099594822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/8548927040099594822'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2011/01/custom-xmladapter-for-joda-time-with.html' title='Custom XmlAdapter for Joda Time with xjc'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-5654070203479723669</id><published>2010-12-22T00:01:00.005+09:00</published><updated>2010-12-22T00:21:42.391+09:00</updated><title type='text'>Werkzeugのデバッガ</title><content type='html'>鹿に尻をかじられたりもしましたが、&lt;br /&gt;三日間の奈良旅行で、8万歩以上も歩き、とても充実した休暇をすごしました。&lt;br /&gt;&lt;br /&gt;Python Web フレームワーク アドベントカレンダー2010 のバトンがまわってきたので、Werkzeugの紹介をします。&lt;br /&gt;&lt;a href="http://werkzeug.pocoo.org/"&gt;http://werkzeug.pocoo.org/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Werkzeugはみなさんご存知のFlaskの作者であるArminが作ったWEBフレームワークです。&lt;br /&gt;実はFlaskのベースでもあります。&lt;br /&gt;単体で使っても便利ですが、非常によい機能が詰め込まれているため、各種フレームワークに組み込んで使う人が多いようです。&lt;br /&gt;たとえば、django-extensionsでDjangoに組み込んで使う人も多いでしょう。&lt;br /&gt;私も、どんなWEBアプリケーションでもほとんどの場合、開発時に組み込んでいます。&lt;br /&gt;運用時にも使うケースは少なくありません。&lt;br /&gt;&lt;br /&gt;丁寧なチュートリアルもついているのですが、なにぶん、生のWSGIが露出しているフレームワークなので、&lt;br /&gt;分かりやすいとは言えません。&lt;br /&gt;今回は、便利な機能の一部に焦点を合わせて解説します。&lt;br /&gt;&lt;br /&gt;さて、解説前に少し準備しましょう。&lt;br /&gt;まず、ごく小さなアプリを一つ書きます。&lt;br /&gt;hello.py&lt;br /&gt;&lt;pre class="python" name="code"&gt;#!/usr/bin/env python&lt;br /&gt;# -*- coding: utf-8 -*-&lt;br /&gt;from werkzeug import Response, script&lt;br /&gt;&lt;br /&gt;def app(environ, start_response):&lt;br /&gt;    response = Response('Hello, World!')&lt;br /&gt;    return response(environ, start_response)&lt;br /&gt;&lt;br /&gt;action_runserver = script.make_runserver(lambda: app)&lt;br /&gt;action_shell = script.make_shell(lambda: {})&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    script.run()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;pythonでライブラリを試すときはVirtualenvが便利です。&lt;br /&gt;&lt;pre class="bash" name="code"&gt;wget https://bitbucket.org/ianb/virtualenv/raw/eb94c9ebe0ba/virtualenv.py&lt;br /&gt;python virtualenv.py ~/.virtualenvs/pyadvc&lt;br /&gt;source ~/.virtualenvs/pyadvc/bin/activate&lt;br /&gt;pip install werkzeug&lt;br /&gt;python hello.py runserver&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;http://localhost:5000/にアクセスするとHello, World!と表示されるはずです。&lt;br /&gt;&lt;br /&gt;デバッガ&lt;br /&gt;&lt;br /&gt;JavaやC#ではステップ実行を使ってデバッグするケースがあると思います。&lt;br /&gt;Pythonでもpdbを使ってステップ実行ができますが、ブレークポイントを設定するのが面倒ですね。&lt;br /&gt;WerkzeugではアプリケーションがExceptionをWerkzeugに投げたのを捕まえて、WEB画面上でステップ実行をすることができます。&lt;br /&gt;ためしに一つエラーを起こしてみましょう&lt;br /&gt;&lt;br /&gt;&lt;pre class="python" name="code"&gt;def app(environ, start_response):&lt;br /&gt;    a = 'Hello'&lt;br /&gt;    response = Response('%a, World!'%a)&lt;br /&gt;    return response(environ, start_response)&lt;br /&gt;&lt;/pre&gt;app関数を書き換えてもう一度起動してみましょう&lt;br /&gt;するとおなじみのInternal Server Errorが出るはずです。&lt;br /&gt;これではエラーの原因がわかりません。&lt;br /&gt;ただ、コンソールでは&lt;br /&gt;&lt;pre class="python" name="code"&gt;response = Response('%a, World!'%a)&lt;br /&gt; ValueError: unsupported format character 'a' (0x61) at index 1&lt;br /&gt;&lt;/pre&gt;というように表示されているので、エラーの推測はできるでしょう。&lt;br /&gt;ここで、%aが正しくないことはわかったのですが、なにが正しいのでしょうか。&lt;br /&gt;そこでデバッガです。&lt;br /&gt;&lt;br /&gt;&lt;pre class="bash" name="code"&gt;python hello.py runserver --debugger&lt;br /&gt;&lt;/pre&gt;という引数をつけて起動しましょう。&lt;br /&gt;再度表示してみると、カラフルな画面が表示されるようになりました。&lt;br /&gt;&lt;br /&gt;&lt;h2 class="traceback" style="background-color: #11557c; color: white; cursor: pointer; font-family: 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif; font-size: 16px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 1.3em; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; padding-top: 5px;"&gt;Traceback&amp;nbsp;&lt;em style="color: #a5d6d9; font-style: normal; font-weight: normal;"&gt;(most recent call last)&lt;/em&gt;&lt;/h2&gt;&lt;div class="traceback" style="background-color: rgb(238, 238, 238) !important; border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(204, 204, 204); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(204, 204, 204); border-top-style: solid; border-top-width: 1px; font-family: 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif; font-size: 15px; margin-bottom: 1em; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 10px; padding-left: 10px; padding-right: 10px; padding-top: 10px;"&gt;&lt;ul style="list-style-image: initial; list-style-position: initial; list-style-type: none; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 1em; padding-right: 0px; padding-top: 0px;"&gt;&lt;li&gt;&lt;div class="frame" id="frame-155980940"&gt;&lt;h4 style="font-size: 13px; font-weight: normal; margin-bottom: 0.1em; margin-left: 0px; margin-right: 0px; margin-top: 0.7em;"&gt;File&amp;nbsp;&lt;cite class="filename"&gt;"/home/spam/ws/python/wz/hello.py"&lt;/cite&gt;, line&amp;nbsp;&lt;em class="line"&gt;7&lt;/em&gt;, in&amp;nbsp;&lt;code class="function" style="font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px;"&gt;app&lt;/code&gt;&lt;/h4&gt;&lt;pre style="background-color: #cccccc; border-bottom-color: rgb(250, 250, 250); border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(170, 170, 170); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(250, 250, 250); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-top-width: 1px; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 3px; padding-left: 15px; padding-right: 0px; padding-top: 5px; white-space: pre-wrap; word-wrap: break-word;"&gt;response = Response('%a, World!'%a)&lt;/pre&gt;&lt;pre class="console" style="background-color: #cccccc; border-bottom-color: rgb(250, 250, 250); border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(170, 170, 170); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(250, 250, 250); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-top-width: 1px; color: black; cursor: default !important; display: block; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; max-height: 400px; overflow-x: auto; overflow-y: auto; padding-bottom: 3px; padding-left: 15px; padding-right: 0px; padding-top: 5px; white-space: pre-wrap; word-wrap: break-word;"&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;br /&gt;response = Response('%a, World!'%a)&lt;br /&gt;&lt;br /&gt;と書かれた行をクリックしてみましょう。&lt;br /&gt;これでソースが確認できます。&lt;br /&gt;&lt;br /&gt;さらに、その行の右にコンソールっぽいアイコンがありますのでクリックします。&lt;br /&gt;すると[console ready]と表示されました。&lt;br /&gt;これはPythonのコンソールです。&lt;br /&gt;たとえば 1 + 1とすると2と返答があるはずです。&lt;br /&gt;さて、直したいのは&lt;br /&gt;'%a, World!'%a&lt;br /&gt;の部分です。&lt;br /&gt;まず、dump()とすると、変数一覧が表示されます。&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif; font-size: 15px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre class="console" style="background-color: #fafafa; border-bottom-color: rgb(250, 250, 250); border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(170, 170, 170); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(250, 250, 250); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-top-width: 1px; color: black; cursor: pointer; display: block; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; max-height: 400px; overflow-x: auto; overflow-y: auto; padding-bottom: 3px; padding-left: 15px; padding-right: 0px; padding-top: 5px; white-space: pre-wrap; word-wrap: break-word;"&gt;&lt;div class="output"&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; dump()&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="box" style="border-bottom-color: rgb(221, 221, 221); border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(221, 221, 221); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(221, 221, 221); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(221, 221, 221); border-top-style: solid; border-top-width: 1px; margin-bottom: 5px; margin-left: 25px; margin-right: 0px; margin-top: 5px; white-space: normal;"&gt;&lt;h3 style="background-color: #555555; color: white; font-size: 1em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 5px; padding-left: 5px; padding-right: 5px; padding-top: 5px;"&gt;Local variables in frame&lt;/h3&gt;&lt;table&gt;&lt;tbody&gt;&lt;br /&gt;&lt;tr style="vertical-align: top;"&gt;&lt;th&gt;a&lt;/th&gt;&lt;td&gt;&lt;span class="string" style="color: #30799b;"&gt;'Hello'&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr style="vertical-align: top;"&gt;&lt;th&gt;start_response&lt;/th&gt;&lt;td&gt;&lt;span class="object" style="color: #485f6e;"&gt;&lt;function 0x94b3a74="" at="" start_response=""&gt;&lt;/function&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr style="vertical-align: top;"&gt;&lt;th&gt;environ&lt;/th&gt;&lt;td&gt;{&lt;span class="pair"&gt;&lt;span class="key"&gt;&lt;span class="string" style="color: #30799b;"&gt;'wsgi.multiprocess'&lt;/span&gt;&lt;/span&gt;:&amp;nbsp;&lt;span class="value"&gt;&lt;span class="number" style="color: #9c1a1c;"&gt;False&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,&amp;nbsp;&lt;span class="pair"&gt;&lt;span class="key"&gt;&lt;span class="string" style="color: #30799b;"&gt;'SERVER_SOFTWARE'&lt;/span&gt;&lt;/span&gt;:&amp;nbsp;&lt;span class="value"&gt;&lt;span class="string" style="color: #30799b;"&gt;'Werkzeug/0.6.2'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,&amp;nbsp;&lt;span class="pair"&gt;&lt;span class="key"&gt;&lt;span class="string" style="color: #30799b;"&gt;'SCRIPT_NAME'&lt;/span&gt;&lt;/span&gt;:&amp;nbsp;&lt;span class="value"&gt;&lt;span class="string" style="color: #30799b;"&gt;''&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,&amp;nbsp;&lt;span class="pair"&gt;&lt;span class="key"&gt;&lt;span class="string" style="color: #30799b;"&gt;'REQUEST_METHOD'&lt;/span&gt;&lt;/span&gt;:&amp;nbsp;&lt;span class="value"&gt;&lt;span class="string" style="color: #30799b;"&gt;'GET'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;,&amp;nbsp;&lt;a class="toggle" href="#" style="background-position: 50% 50%; background-repeat: no-repeat no-repeat; color: #11557c; text-decoration: none;"&gt;&amp;nbsp;&amp;nbsp;&lt;/a&gt;}&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/pre&gt;&lt;br /&gt;aに'Hello'が入っているのがわかりますね。&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;ここで、&amp;nbsp;'%a, World!'%a と入力すると先ほどと同じエラーが出ます。&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;a,b,cといろいろ試したり、マニュアルを確認したところ、%sが正しいとわかりました。&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif; font-size: 15px;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;pre class="console" style="background-color: #cccccc; border-bottom-color: rgb(250, 250, 250); border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(170, 170, 170); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(250, 250, 250); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(170, 170, 170); border-top-style: solid; border-top-width: 1px; color: black; cursor: default !important; display: block; font-family: Consolas, 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; font-size: 13px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; max-height: 400px; overflow-x: auto; overflow-y: auto; padding-bottom: 3px; padding-left: 15px; padding-right: 0px; padding-top: 5px; white-space: pre-wrap; word-wrap: break-word;"&gt;&lt;div class="output"&gt;&lt;div&gt;&amp;gt;&amp;gt;&amp;gt; '%s, World!'%a&lt;br /&gt;&lt;span class="string" style="color: #30799b;"&gt;'Hello, World!'&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;これで、正しい文がわかったので、ソースを書き換えて終了です。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;その他、Context LocalsというJavaでいうThreadLocalを便利にした機能から、WEBアプリに必須なルーティング機能まで、すばらしい品揃えです。&lt;br /&gt;そのWerkzeugの機能を丁寧にラップして、高速+多機能テンプレートエンジンであるJinja2と組み合わせたのがFlaskです。&lt;br /&gt;&lt;br /&gt;ぜひ試してみてください。&lt;br /&gt;&lt;br /&gt;次は@lirisさんお願いします。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-5654070203479723669?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/5654070203479723669/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=5654070203479723669' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5654070203479723669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5654070203479723669'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2010/12/werkzeug.html' title='Werkzeugのデバッガ'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-4505753000218336246</id><published>2010-08-19T12:44:00.000+09:00</published><updated>2010-08-19T12:44:15.771+09:00</updated><title type='text'>Why Corel MovieWriter sucks</title><content type='html'>プライベートのDVDを作成していたんだけど、CorelのDVD作成ソフトであるMovieWriterがひどすぎて、怒りが収まらない。&lt;br /&gt;たった一枚のDVD-Videoのために、友人たちが取ってくれた合計40本程度の動画を細かく繋いだところ、&lt;br /&gt;重すぎて映像を選択するだけで3分待たされるのはまだ許す。&lt;br /&gt;映像の再生もしてない、ただタイトルをマウスでクリックするたびになんの計算をしてるんだと考えると腹立たしいけど。&lt;br /&gt;&lt;br /&gt;イライラを抑えながらなんとか最後のDVD出力までたどり着く。&lt;br /&gt;出力開始40分後、今度は突然、異常終了する。&lt;br /&gt;なんのエラーメッセージも吐かないから対応も取りづらい。&lt;br /&gt;MP4からHDまで多様な形式をつないでいるので、相性の悪いフォーマットがあるのかなと、&lt;br /&gt;とりあえずチャプターを減らして、正常に終了したところとかかった時間から、不具合のあるチャプターを特定する。&lt;br /&gt;しかし、不具合のあるチャプターも、本来の3分の1程度の長さでDVDをつくれば正常に出力されてしまうので&lt;br /&gt;特定が難しいのに加えて、テストに時間がかかる。&lt;br /&gt;&lt;br /&gt;つないだ映像の本数が多いし、形式も多様だから難しいのだろうと気を使わせる時点で&lt;br /&gt;すでに値段の価値もないソフトウェアですね。&lt;br /&gt;最初から対応してないって分かっていれば全部一度ffmpegでmpegに統一するよ。&lt;br /&gt;しょうがないから作れる範囲の短いDVDで出力し、あとから自分でインポートしなおせば、&lt;br /&gt;形式も統一だし、ソース本数が減るから焼けるようになるはず。&lt;br /&gt;&lt;br /&gt;しかし、ここでも問題が発生。&lt;br /&gt;チャプターの数も30に満たない数しかないのに、チャプター数の限界に達したとして&lt;br /&gt;DVD書き込み中に中断。&lt;br /&gt;&lt;br /&gt;これも何度か繰り返して特定。&lt;br /&gt;原因は、映像に暗転をいれていたところ、0秒のチャプターが存在していたため。&lt;br /&gt;エラーメッセージ間違ってるよ。&lt;br /&gt;そもそも映像変換中に気づいてくれよ。&lt;br /&gt;DVD書き込み中に中断したらDVDが一枚無駄になるんですけど。&lt;br /&gt;&lt;br /&gt;それまでは警戒して、ファイル出力にしていたけど、今回は映像の編集も変換もないので&lt;br /&gt;問題がないだろうと、つい油断してDVD出力に設定し寝てしまっていた。&lt;br /&gt;信じちゃいけなかった。&lt;br /&gt;&lt;br /&gt;そして、数々の試練を乗り越えて、ついに一枚出力完了。&lt;br /&gt;ここまで2週間もかかった。&lt;br /&gt;しかし、すでに疑心暗鬼の私は安心をしない。&lt;br /&gt;もちろん再生して確認する。&lt;br /&gt;どこでどんなトラブルがあっても驚かないぞと思っていたけどまさかね。&lt;br /&gt;なんとまあ、あきれてしまう。&lt;br /&gt;自分で作ったものをインポートしたら音声が全て消えるのはひどすぎるないか？&lt;br /&gt;&lt;br /&gt;一回出力するのに40分程度はかかるから、一晩なんてあっという間。&lt;br /&gt;あんな重いソフトウェアでも一応映像の切り貼りだけは三日で終わったのにそこからが長すぎる。&lt;br /&gt;結果として、5GのDVD一枚をまともにつくることができずに2週間経過。&lt;br /&gt;これでBlu-ray対応なんて笑わせる。&lt;br /&gt;&lt;br /&gt;ここまでの数々の問題でも使えないことが明白ですが、もっとひどい問題もある。&lt;br /&gt;MTSという形式があります。&lt;br /&gt;HD動画の形式だけど、その動画も読み込んで編集することができるのはすばらしい。&lt;br /&gt;出力も成功するのですが、実際は内部のデコードで失敗していて、映像が乱れてそれ以降の映像はとび、音声がずれるという悲惨な状態。&lt;br /&gt;これを成功として、再生するまでわからないようにするのは良識を疑う。&lt;br /&gt;&lt;br /&gt;金返せじゃすまない。&lt;br /&gt;2週間の睡眠時間とその間の体調不良をどうしてくれる。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-4505753000218336246?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/4505753000218336246/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=4505753000218336246' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/4505753000218336246'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/4505753000218336246'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2010/08/why-corel-moviewriter-sucks.html' title='Why Corel MovieWriter sucks'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-5586225863144141403</id><published>2010-01-22T15:26:00.000+09:00</published><updated>2010-01-22T15:26:01.671+09:00</updated><title type='text'>Play framework is a full stack framework</title><content type='html'>&lt;a href="http://www.playframework.org/"&gt;Play framework&lt;/a&gt;で楽しんでます。&lt;br /&gt;フルスタックとはテンプレート、データベース補助があるだけでは不足&lt;br /&gt;&lt;br /&gt;clean url routing, test, fixture, message after redirect, background job, cache, i18n程度あたりがそろっていないとFullとは言えない時代だと思う。&lt;br /&gt;Playはその点、完璧だろう。&lt;br /&gt;reverseまで持ってるんだから、私は当然お気に入り。&lt;br /&gt;&lt;br /&gt;ただ、欠点もある。&lt;br /&gt;&lt;br /&gt;background jobがスレッドで走ってしまうので、重くなる。&lt;br /&gt;Hibernateとは別れたい。&lt;br /&gt;ほかには、先日書いた内容など。&lt;br /&gt;&lt;br /&gt;やはり私はpublic fieldを積極的に使いたい。&lt;br /&gt;メソッドではなくフィールド&lt;br /&gt;redirect(BookPage.find, 1)とかでリダイレクトしたいし、&lt;br /&gt;tx(BookService.reserve, 2)とかでトランザクションを開始したい。&lt;br /&gt;&lt;br /&gt;Routingもフィールドを使えばリファクタリング効くしね。&lt;br /&gt;&lt;br /&gt;メソッドをフィールド扱いできるScalaには期待しています。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-5586225863144141403?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/5586225863144141403/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=5586225863144141403' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5586225863144141403'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5586225863144141403'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2010/01/play-framework-is-full-stack-framework.html' title='Play framework is a full stack framework'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-1524778104986057218</id><published>2010-01-21T17:41:00.003+09:00</published><updated>2010-09-01T00:51:38.473+09:00</updated><title type='text'>ANA-Amex</title><content type='html'>JALが沈没したのでクレジットカードを整理することにしました。&lt;br /&gt;&lt;br /&gt;次はANA-AMEXにします。&lt;br /&gt;&lt;a href="http://click.linksynergy.com/fs-bin/click?id=Ih8Ygoi9gb0&amp;offerid=191802.10000261&amp;type=4&amp;subid=0"&gt;&lt;img alt="アメリカン・エキスプレス" border="0" src="http://www.americanexpress.com/japan/images/linkshare/aurpcard_170x106_7KB_20100113.gif"&gt;&lt;/a&gt;&lt;img border="0" width="1" height="1" src="http://ad.linksynergy.com/fs-bin/show?id=Ih8Ygoi9gb0&amp;bids=191802.10000261&amp;type=4&amp;subid=0"&gt;&lt;br /&gt;&lt;br /&gt;12月までは大盤振る舞いだったようだけど、まだ大丈夫か&lt;br /&gt;&lt;br /&gt;1. 100円で2マイル&lt;br /&gt;3ヶ月間ポイントが倍&lt;br /&gt;&lt;br /&gt;2. 入会2000+1000マイル&lt;br /&gt;&lt;br /&gt;3. オンライン明細で1000マイル&lt;br /&gt;ただし、入会時は紙にしておいて、入会したあとに変更すること&lt;br /&gt;&lt;br /&gt;4. 公共料金や電子マネー、携帯などの引き落としでそれぞれボーナス&lt;br /&gt;合計すると10000マイルの予定&lt;br /&gt;&lt;br /&gt;5. Edyチャージでポイントがつく&lt;br /&gt;ただし6ヶ月間&lt;br /&gt;&lt;br /&gt;6. 年会費がAMEXにしては安い&lt;br /&gt;5250円&lt;br /&gt;&lt;br /&gt;&lt;a href="http://click.linksynergy.com/fs-bin/click?id=Ih8Ygoi9gb0&amp;offerid=87516.10000025&amp;type=4&amp;subid=0"&gt;&lt;IMG alt="スルガ銀行ANA支店" border="0" src="http://www.surugabank.co.jp/affiliate/ana/468_60_mile.gif"&gt;&lt;/a&gt;&lt;IMG border="0" width="1" height="1" src="http://ad.linksynergy.com/fs-bin/show?id=Ih8Ygoi9gb0&amp;bids=87516.10000025&amp;type=4&amp;subid=0"&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-1524778104986057218?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/1524778104986057218/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=1524778104986057218' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1524778104986057218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1524778104986057218'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2010/01/ana-amex.html' title='ANA-Amex'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-3021901038209283869</id><published>2010-01-15T16:03:00.000+09:00</published><updated>2010-01-15T16:03:48.123+09:00</updated><title type='text'>Hello, Play framework</title><content type='html'>&lt;a href="http://www.playframework.org/"&gt;Play framework&lt;/a&gt;を使ったことがある人はどれぐらいいるんだろうか。&lt;br /&gt;こんなに面白いフレームワークとは思わなかった。&lt;br /&gt;いや、フレームワークというより、プラットフォームです。&lt;br /&gt;&lt;br /&gt;まえにJava on Railsなんて宣伝を見てしまったせいでスルーしていた。&lt;br /&gt;たしかに「Rails使いに媚びてDjangoをJavaにポートした」と言えないこともないけど。&lt;br /&gt;ためしてから宣伝してください。迷惑です。&lt;br /&gt;見所はコマンドラインなんかじゃない。まあ、Python for Windowsがついてくるのは確かに面白いけど。&lt;br /&gt;なんといってもJavaの使い方が革命的に面白い。&lt;br /&gt;&lt;br /&gt;なんと表現すればいいのか。&lt;br /&gt;「コンパイルさえ通せば、あとはまかせとけ」&lt;br /&gt;といったところか。&lt;br /&gt;staticメソッドを積極的に使い、記述をシンプルにすることが使命であるようだ。&lt;br /&gt;&lt;br /&gt;まずはこの三つの機能を見てみます。&lt;br /&gt;&lt;a href="http://www.playframework.org/documentation/1.1-trunk/5things#a1.BindanHTTPparametertoaJavamethodparametera"&gt;1. Bind an HTTP parameter to a Java method parameter&lt;/a&gt;&lt;br /&gt;リクエスト引数をメソッド引数に名前で結びつけちゃいます。&lt;br /&gt;メソッド引数名ですよ？&lt;br /&gt;アノテーションなんて不要です。&lt;br /&gt;まさしく名前つき引数なのです。&lt;br /&gt;&lt;br /&gt;routesに&lt;br /&gt;&lt;pre name="code"&gt;GET  /show/{name}  Application.show&lt;br /&gt;&lt;/pre&gt;とあったとして、&lt;br /&gt;&lt;pre name="code"&gt;/show/Tom?page=2&lt;br /&gt;&lt;/pre&gt;にアクセスがあったならば&lt;br /&gt;&lt;pre name="code" class="java"&gt;public static void show(String name, Integer page)&lt;br /&gt;&lt;/pre&gt;では、nameにTomが入り、pageは2になるのです。&lt;br /&gt;型や順番や偶然を使っているわけではありません。&lt;br /&gt;引数名を見ているのです。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.playframework.org/documentation/1.1-trunk/5things#a2.RedirecttoanactionbycallingthecorrespondingJavamethoda"&gt;2. Redirect to an action by calling the corresponding Java method&lt;/a&gt;&lt;br /&gt;一度でもDjangoのreverseを使ったことがあれば、URLなんて直接書きたくないと思うことでしょう。&lt;br /&gt;この場合ならばControllerのメソッド名で指定したいところ。&lt;br /&gt;しかし、文字列でredirect(reverse("Books.list", page))では芸がない。&lt;br /&gt;redirect(Books.list, page)と書くことができればいいけど、残念ながらコンパイルエラーになるでしょう。&lt;br /&gt;Javaのメソッドとフィールドの名前空間と同じであれば、もっとまともなフレームワークを作れたのですけどね。&lt;br /&gt;そこでPlayは突き抜けました。&lt;br /&gt;Books.list(page)&lt;br /&gt;と書けば勝手にリダイレクトされます。&lt;br /&gt;&lt;br /&gt;staticメソッドだからといって気を抜いてはいけません。&lt;br /&gt;フォワードではなく、間違いなくブラウザにResponseがかえります。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.playframework.org/documentation/1.1-trunk/5things#a3.DontRepeatYourselfwhenpassingJavaobjectstotemplatesa"&gt;3. Don’t Repeat Yourself when passing Java objects to templates&lt;/a&gt;&lt;br /&gt;Spring MVCではデフォルトの名前というものが存在します。&lt;br /&gt;User =&gt; user, List&amp;lt;User&amp;gt; =&gt; userList&lt;br /&gt;というように、型から名前をつけてくれるので、テンプレートに名前をつけながら渡す必要がありません。&lt;br /&gt;しかし、Playでは1と同様に型ではなくローカル変数名を取得します。&lt;br /&gt;ローカル変数名ですよ。&lt;br /&gt;pythonでもrender(article=article, user=user)と書かなきゃいけないってのに。&lt;br /&gt;bytecode enhanceってレベルじゃないですね。&lt;br /&gt;ただ、残念ながら実行時に解決なので、いっそコンパイラを作って変数名をbytecodeに埋め込んでほしいと思います。&lt;br /&gt;&lt;br /&gt;と&lt;br /&gt;以上のようにJavassistの黒魔術を駆使して理想郷を追い求めます。&lt;br /&gt;&lt;br /&gt;だがちょっと待ってほしい。&lt;br /&gt;この黒魔術&lt;br /&gt;まさにDIでやっていることそのままではないか。&lt;br /&gt;DIの黒魔術を許してこれを許さないなんて、なんという傲慢。&lt;br /&gt;フィールドに準備しておくか、staticで呼び出すかの違いしかない。&lt;br /&gt;ルールを決めておけばOKとはどの口が言ったものか。&lt;br /&gt;Mockitoを見て便利だといっていたじゃないか。&lt;br /&gt;staticであればコードがそのまま追えるなんて、いつまで20世紀にしがみついているんだ。&lt;br /&gt;もうそんな時代じゃないんだ。&lt;br /&gt;EJB2信者なんて、もういないでしょ？&lt;br /&gt;&lt;br /&gt;DIに飼いならされた開発者たちなら、ルールだと説得すればすぐ納得するね。&lt;br /&gt;賭けてもいい。&lt;br /&gt;逆に、「Proxyを使って実現できるDIとは違う」と反論するような人が相手なら、&lt;br /&gt;メリットを比較してあげれば、いずれは「ひでえ」といって納得するはず。&lt;br /&gt;&lt;br /&gt;残念なところもいくつか挙げておく。&lt;br /&gt;&lt;br /&gt;1. アプリの構造が貧弱&lt;br /&gt;Djangoのアプリを引き継いでほしかった。&lt;br /&gt;一定以上の規模のものを作れるのだろうか。&lt;br /&gt;心配です。&lt;br /&gt;2. formが貧弱&lt;br /&gt;ModelとはべつにFormクラスを作ってください。&lt;br /&gt;ModelべったりのFormだと画面や権限に応じてValidationや項目を変えづらい。&lt;br /&gt;3. Bytecode拡張される範囲が不明&lt;br /&gt;Bytecode拡張される範囲が明確でないため、自分で拡張しようとすると&lt;br /&gt;なかなか恐ろしい。&lt;br /&gt;たとえば、もう少し複雑で動的なFormがあって、複数のControllerで共有したいとすると、&lt;br /&gt;自分で独自のクラスを作りたくなるけど、どこまで拡張してくれるのか試すまで、&lt;br /&gt;いや、試してもよくわからない。&lt;br /&gt;returnをなくそうとしたり、Javaの言語仕様をとことん無視しようとしているので、&lt;br /&gt;なかなか機能拡張は難しそう。&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;まとめ&lt;/h4&gt;二週間以内で作るものにはちょうどいいかも。&lt;br /&gt;どうしてもJavaがいい。&lt;br /&gt;Javaじゃなきゃいやと根拠なく言われたときに使うことを考えてもいいかもしれない。&lt;br /&gt;Springの起動が遅くて、決別したいとは常々思っているので、&lt;br /&gt;こういうアプローチが流行ってくれば面白いとは思っています。&lt;br /&gt;Bytecode拡張以外は使いやすく、わかりやすい機能がてんこ盛りなのでお勧めです。&lt;br /&gt;Bespinとうまく連携すれば、全文検索つきのCMSが結構簡単に作れるかも。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-3021901038209283869?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/3021901038209283869/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=3021901038209283869' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3021901038209283869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3021901038209283869'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2010/01/hello-play-framework.html' title='Hello, Play framework'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-9094536776478494464</id><published>2009-12-16T16:38:00.000+09:00</published><updated>2009-12-16T16:38:01.155+09:00</updated><title type='text'>aws with python</title><content type='html'>botoがよろしい&lt;br /&gt;&lt;a href="http://code.google.com/p/boto/"&gt;boto&lt;/a&gt;&lt;br /&gt;結構パッチを取り込んでもらったのでだいぶ使いやすくなった。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://beta.paltman.com/"&gt;botoドキュメント&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;amiをEBSへ変換する&lt;br /&gt;&lt;a href="http://coderslike.us/2009/12/07/amazon-ec2-boot-from-ebs-and-ami-conversion/"&gt;Amazon EC2 – Boot from EBS and AMI conversion&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;botoで変換するとこんな感じ&lt;br /&gt;&lt;a href="http://www.elastician.com/2009/12/creating-ebs-backed-ami-from-s3-backed.html"&gt;Creating an EBS-backed AMI from an S3-backed AMI&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;いろいろ自動化できて楽しい。&lt;br /&gt;AMI内でサーバを再起動するより、裏で立ち上げてElastic IPをすりかえてしまうとか&lt;br /&gt;いろいろ試せて楽しい&lt;br /&gt;Spot Instanceにも、とりあえずだけど対応してもらった&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-9094536776478494464?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/9094536776478494464/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=9094536776478494464' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/9094536776478494464'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/9094536776478494464'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/12/aws-with-python.html' title='aws with python'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-3094969059320319588</id><published>2009-12-16T16:19:00.002+09:00</published><updated>2009-12-24T17:50:45.304+09:00</updated><title type='text'>felica with python</title><content type='html'>felicalibが主流。&lt;br /&gt;&lt;a href="http://felicalib.tmurakam.org/"&gt;felicalib&lt;/a&gt;&lt;br /&gt;ただしWindowsのみ&lt;br /&gt;&lt;br /&gt;Pythonからの使用例(ctypes)&lt;br /&gt;&lt;a href="http://takanory.net/takalog/824/"&gt;FeliCa の Id を python で読む(その2)&lt;/a&gt;&lt;br /&gt;&lt;a href="http://handasse.blogspot.com/2008/03/python-pasorisuica.html"&gt;Python: PaSoRiでSuicaの履歴を読み出す&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Javaからの使用例(JNA)&lt;br /&gt;&lt;a href="http://yuuhayashi.blogspot.com/2009/01/pasorifelicaidm_30.html"&gt;'PaSoRi'を使用して、FeliCaカード内の'IDm'を読み取る&lt;/a&gt;&lt;br /&gt;&lt;a href="http://itasan.mydns.jp/wiki.cgi/ASIA?page=Java%A4%CE%B1%FE%CD%D1%A1%A7Felica%A5%AB%A1%BC%A5%C9%A5%EA%A1%BC%A5%C0"&gt;Javaの応用：Felicaカードリーダ&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;libpafe(Linux用)&lt;br /&gt;&lt;a href="http://homepage3.nifty.com/slokar/pasori/libpafe.html"&gt;libpafe&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;2ch&lt;br /&gt;&lt;a href="http://unkar.jp/read/pc11.2ch.net/tech/1100532582"&gt;■◇FeliCa でソフトを作りまくるスレ◇■&lt;/a&gt;&lt;br /&gt;&lt;a href="http://pc12.2ch.net/test/read.cgi/tech/1210717455/"&gt;FeliCa でソフトを作りまくるスレ 2ブロック目&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;追記 12/24 18:00&lt;br /&gt;三者間通信&lt;br /&gt;&lt;a href="http://cgi42.plala.or.jp/~mediware/wiki.cgi?p=%BB%B0%BC%D4%B4%D6%C4%CC%BF%AE"&gt;三者間通信 - 新・招き猫のページ&lt;/a&gt;&lt;br /&gt;&lt;a href="http://jasmine.moe.hm/~tsakura/pasori/"&gt;PaSoRi「パソリ」(RC-S320/RC-S330)三者間通信 サンプル&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;SDK For Felica + AIR&lt;br /&gt;&lt;a href="http://www.sony.co.jp/Products/felica/pdt/adb.html"&gt;SDK for FeliCa &amp; Adobe AIR&lt;/a&gt;&lt;br /&gt;&lt;a href="http://flashdevelop.jp/"&gt;FlashDevelop.jp&lt;/a&gt;&lt;br /&gt;&lt;a href="http://sothis.blog.so-net.ne.jp/2008-03-26"&gt;フリーのFlash統合開発環境 FlashDevelop (+flex 3 SDK)を入れてみました&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-3094969059320319588?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/3094969059320319588/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=3094969059320319588' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3094969059320319588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3094969059320319588'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/12/felica-with-python.html' title='felica with python'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-1876782904120059815</id><published>2009-09-30T12:09:00.000+09:00</published><updated>2009-09-30T12:09:04.204+09:00</updated><title type='text'>String concatenation in Python</title><content type='html'>&lt;a href="http://d.hatena.ne.jp/mopemope/20090929/p1"&gt;文字列連結の効率の話&lt;/a&gt;&lt;br /&gt;addのほうが早かったよなと思って、色々試してみた。&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;def str_mul():&lt;br /&gt;    return name * count&lt;br /&gt;&lt;br /&gt;def str_join():&lt;br /&gt;    lst = []&lt;br /&gt;    append = lst.append&lt;br /&gt;    for i in xrange(count):&lt;br /&gt;        append(name)&lt;br /&gt;    return ''.join(lst)&lt;br /&gt;&lt;br /&gt;def str_map():&lt;br /&gt;    lst = map(lambda x:name, xrange(count))&lt;br /&gt;    return ''.join(lst)&lt;br /&gt;&lt;br /&gt;def list_comp():&lt;br /&gt;    return ''.join(name for i in xrange(count))&lt;br /&gt;&lt;br /&gt;def str_add():&lt;br /&gt;    s = ''&lt;br /&gt;    for i in xrange(count):&lt;br /&gt;        s += name&lt;br /&gt;    return s&lt;br /&gt;&lt;br /&gt;import cStringIO&lt;br /&gt;def cstring_io():&lt;br /&gt;    io = cStringIO.StringIO()&lt;br /&gt;    write = io.write&lt;br /&gt;    for i in xrange(count):&lt;br /&gt;        write(name)&lt;br /&gt;    return io.getvalue()&lt;br /&gt;&lt;br /&gt;import StringIO&lt;br /&gt;def string_io():&lt;br /&gt;    io = StringIO.StringIO()&lt;br /&gt;    write = io.write&lt;br /&gt;    for i in xrange(count):&lt;br /&gt;        write(name)&lt;br /&gt;    return io.getvalue()&lt;br /&gt;&lt;br /&gt;from array import array&lt;br /&gt;def str_array():&lt;br /&gt;    a = array('c')&lt;br /&gt;    add = a.fromstring&lt;br /&gt;    for i in xrange(count):&lt;br /&gt;        add(name)&lt;br /&gt;    return a.tostring()&lt;br /&gt;&lt;br /&gt;from mmap import mmap&lt;br /&gt;def str_mmap():&lt;br /&gt;    m = mmap(-1, count * len(name))&lt;br /&gt;    write = m.write&lt;br /&gt;    for i in xrange(count):&lt;br /&gt;        write(name)&lt;br /&gt;    m.seek(0)&lt;br /&gt;    return m.read(count * len(name))&lt;br /&gt;&lt;br /&gt;def main():&lt;br /&gt;    global count, name&lt;br /&gt;    func_list = (str_mul, str_join, str_add, string_io, cstring_io,&lt;br /&gt;                 str_map, list_comp, str_array, str_mmap)&lt;br /&gt;&lt;br /&gt;    # test&lt;br /&gt;    count = 2&lt;br /&gt;    name = 'hello'&lt;br /&gt;    assert all((name * count).__eq__(f()) for f in func_list)&lt;br /&gt;&lt;br /&gt;    import timeit&lt;br /&gt;    for c in (10, 1000):&lt;br /&gt;        for b in (1, 1000):&lt;br /&gt;            for f in func_list:&lt;br /&gt;                count = c&lt;br /&gt;                name = 'hello' * b&lt;br /&gt;                print '%10s x %4s, "hello"*%4s: %9.4fms'%(&lt;br /&gt;                    f.func_name, c, b, timeit.timeit(f, number=100)/100*1000)&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    main()&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;   str_mul x   10, "hello"*   1:    0.0006ms&lt;br /&gt;  str_join x   10, "hello"*   1:    0.0042ms&lt;br /&gt;   str_add x   10, "hello"*   1:    0.0033ms&lt;br /&gt; string_io x   10, "hello"*   1:    0.0312ms&lt;br /&gt;cstring_io x   10, "hello"*   1:    0.0072ms&lt;br /&gt;   str_map x   10, "hello"*   1:    0.0059ms&lt;br /&gt; list_comp x   10, "hello"*   1:    0.0077ms&lt;br /&gt; str_array x   10, "hello"*   1:    0.0081ms&lt;br /&gt;  str_mmap x   10, "hello"*   1:    0.0180ms&lt;br /&gt;   str_mul x   10, "hello"*1000:    0.0108ms&lt;br /&gt;  str_join x   10, "hello"*1000:    0.0131ms&lt;br /&gt;   str_add x   10, "hello"*1000:    0.0126ms&lt;br /&gt; string_io x   10, "hello"*1000:    0.0411ms&lt;br /&gt;cstring_io x   10, "hello"*1000:    0.0364ms&lt;br /&gt;   str_map x   10, "hello"*1000:    0.0146ms&lt;br /&gt; list_comp x   10, "hello"*1000:    0.0167ms&lt;br /&gt; str_array x   10, "hello"*1000:    0.0377ms&lt;br /&gt;  str_mmap x   10, "hello"*1000:    0.1105ms&lt;br /&gt;   str_mul x 1000, "hello"*   1:    0.0017ms&lt;br /&gt;  str_join x 1000, "hello"*   1:    0.2352ms&lt;br /&gt;   str_add x 1000, "hello"*   1:    0.2235ms&lt;br /&gt; string_io x 1000, "hello"*   1:    2.4272ms&lt;br /&gt;cstring_io x 1000, "hello"*   1:    0.5111ms&lt;br /&gt;   str_map x 1000, "hello"*   1:    0.3591ms&lt;br /&gt; list_comp x 1000, "hello"*   1:    0.2296ms&lt;br /&gt; str_array x 1000, "hello"*   1:    0.5338ms&lt;br /&gt;  str_mmap x 1000, "hello"*   1:    0.4778ms&lt;br /&gt;   str_mul x 1000, "hello"*1000:    8.5971ms&lt;br /&gt;  str_join x 1000, "hello"*1000:    8.3908ms&lt;br /&gt;   str_add x 1000, "hello"*1000:   29.4590ms&lt;br /&gt; string_io x 1000, "hello"*1000:   10.6351ms&lt;br /&gt;cstring_io x 1000, "hello"*1000:   28.7235ms&lt;br /&gt;   str_map x 1000, "hello"*1000:    8.8407ms&lt;br /&gt; list_comp x 1000, "hello"*1000:    8.2300ms&lt;br /&gt; str_array x 1000, "hello"*1000:   38.9228ms&lt;br /&gt;  str_mmap x 1000, "hello"*1000:   18.6053ms&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;addは50kB程度までは、文字列長や回数にかかわらず早い。&lt;br /&gt;'str' * nをjoinが逆転するのは見てびっくり。&lt;br /&gt;StringIOは1MBを超えたあたりで突然加速、理由不明。&lt;br /&gt;cStringIOを余裕で追い抜き、100MBあたりではjoinに並ぶ。&lt;br /&gt;ただし、1MBを超えるようなものはPythonで扱うべきではないかも。&lt;br /&gt;for, map, list内包は勝ったり負けたり。&lt;br /&gt;disってみたところ、早そうなのはfor-join。&lt;br /&gt;psycoも使ってみたけど、速度はあまりかわらず。&lt;br /&gt;&lt;br /&gt;結論:&lt;br /&gt;addでもjoinでも扱いやすいほうを使おう。&lt;br /&gt;速度はPythonを使う上では気にしない。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-1876782904120059815?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/1876782904120059815/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=1876782904120059815' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1876782904120059815'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1876782904120059815'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/09/string-concatenation-in-python.html' title='String concatenation in Python'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-4209645329435487962</id><published>2009-09-14T11:15:00.000+09:00</published><updated>2009-09-14T11:15:43.310+09:00</updated><title type='text'>Interpolation surprise — And now for something completely Pythonic...</title><content type='html'>&lt;a href="http://pythonic.pocoo.org/2009/9/12/interpolation-surprise"&gt;Interpolation surprise — And now for something completely Pythonic...&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;おそろしや&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;class Surprise(object):&lt;br /&gt;    def __str__(self):&lt;br /&gt;        return "[str]"&lt;br /&gt;    def __unicode__(self):&lt;br /&gt;        return u"[unicode]"&lt;br /&gt;&lt;br /&gt;surprise = Surprise()&lt;br /&gt;&lt;br /&gt;print "%s %s %s" % (surprise, u"foo", surprise)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;出力:&lt;br /&gt;   [str] foo [unicode]&lt;br /&gt;&lt;br /&gt;つまり、途中でUnicodeが来ると、それ以降は__unicode__が呼ばれるようになるわけです。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ちなみにPython2.3なら&lt;br /&gt;出力:&lt;br /&gt;   [str] foo [str]&lt;br /&gt;となります。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-4209645329435487962?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://pythonic.pocoo.org/2009/9/12/interpolation-surprise' title='Interpolation surprise — And now for something completely Pythonic...'/><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/4209645329435487962/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=4209645329435487962' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/4209645329435487962'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/4209645329435487962'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/09/interpolation-surprise-and-now-for.html' title='Interpolation surprise — And now for something completely Pythonic...'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-6431701104819188909</id><published>2009-09-03T18:25:00.002+09:00</published><updated>2009-09-03T18:58:30.552+09:00</updated><title type='text'>setuptools</title><content type='html'>&lt;a href="http://opensource.plurk.com/Solace/"&gt;Solace&lt;/a&gt;が&lt;a href="http://plurk.com/"&gt;Plurk&lt;/a&gt;からリリースされました。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://stackoverflow.com/"&gt;Stack Overflow&lt;/a&gt;のクローンです。&lt;br /&gt;あいかわらず仕事が早いしソースが読みやすい。&lt;br /&gt;&lt;br /&gt;しかし今回、最も驚いたのが、setup.pyの使い方。&lt;br /&gt;こんな便利なものだったんですね。&lt;br /&gt;なお、正しい手順は&lt;a href="http://bitbucket.org/plurk/solace/src/tip/README"&gt;README&lt;/a&gt;や&lt;a href="http://opensource.plurk.com/Solace/Installation/"&gt;Installation&lt;/a&gt;を見てください。&lt;br /&gt;&lt;br /&gt;私の手順は以下のとおり。&lt;br /&gt;&lt;br /&gt; $ hg clone http://bitbucket.org/plurk/solace&lt;br /&gt; $ mkvirtualenv solace&lt;br /&gt; (solace)$ cd solace&lt;br /&gt; (solace)$ python setup.py develop&lt;br /&gt; (solace)$ echo SECRET_KEY = \'`mkpasswd -l 40`\' &gt; config.py&lt;br /&gt; (solace)$ SOLACE_SETTINGS_FILE=config.py python setup.py reset&lt;br /&gt; (solace)$ SOLACE_SETTINGS_FILE=config.py python setup.py runserver&lt;br /&gt;&lt;br /&gt;はやい！本当に早い！&lt;br /&gt;setup.pyってこんなに便利だったんだ。&lt;br /&gt;拡張コマンドを追加できるなんて知らなかったよ！&lt;br /&gt;&lt;br /&gt;さて、setup.pyを読んでいきます。&lt;br /&gt;まずはここ。&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;try:&lt;br /&gt;    from solace import scripts&lt;br /&gt;except ImportError:&lt;br /&gt;    pass&lt;br /&gt;else:&lt;br /&gt;    extra['cmdclass'] = {&lt;br /&gt;        'runserver':        scripts.RunserverCommand,&lt;br /&gt;        'initdb':           scripts.InitDatabaseCommand,&lt;br /&gt;        'reset':            scripts.ResetDatabase,&lt;br /&gt;        'make_testdata':    scripts.MakeTestData,&lt;br /&gt;        'compile_catalog':  scripts.CompileCatalogEx&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;コマンドの実装はこんな感じ&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;from distutils.cmd import Command&lt;br /&gt;class InitDatabaseCommand(Command):&lt;br /&gt;    description = 'initializes the database'&lt;br /&gt;    user_options = [&lt;br /&gt;        ('drop-first', 'D',&lt;br /&gt;         'drops existing tables first')&lt;br /&gt;    ]&lt;br /&gt;    boolean_options = ['drop-first']&lt;br /&gt;&lt;br /&gt;    def initialize_options(self):&lt;br /&gt;        self.drop_first = False&lt;br /&gt;&lt;br /&gt;    def finalize_options(self):&lt;br /&gt;        pass&lt;br /&gt;&lt;br /&gt;    def run(self):&lt;br /&gt;        from solace import database&lt;br /&gt;        if self.drop_first:&lt;br /&gt;            database.drop_tables()&lt;br /&gt;            print 'dropped existing tables'&lt;br /&gt;        database.init()&lt;br /&gt;        print 'created database tables'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;わかりやすい！&lt;br /&gt;&lt;br /&gt;もう一つ勉強になったのがtests_require&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;setup(&lt;br /&gt;    name='Plurk_Solace',&lt;br /&gt;    version='0.1',&lt;br /&gt;    url='http://opensource.plurk.com/solace/',&lt;br /&gt;    license='BSD',&lt;br /&gt;    author='Plurk Inc.',&lt;br /&gt;    author_email='opensource@plurk.com',&lt;br /&gt;    description='Multilangual User Support Platform',&lt;br /&gt;    long_description=__doc__,&lt;br /&gt;    packages=['solace', 'solace.views', 'solace.i18n', 'solace.utils'],&lt;br /&gt;    zip_safe=False,&lt;br /&gt;    platforms='any',&lt;br /&gt;    test_suite='solace.tests.suite',&lt;br /&gt;    install_requires=[&lt;br /&gt;        'Werkzeug&gt;=0.5.1',&lt;br /&gt;        'Jinja2',&lt;br /&gt;        'Babel',&lt;br /&gt;        'SQLAlchemy&gt;=0.5',&lt;br /&gt;        'creoleparser',&lt;br /&gt;        'simplejson',&lt;br /&gt;        'webdepcompress'&lt;br /&gt;    ],&lt;br /&gt;    tests_require=[&lt;br /&gt;        'lxml',&lt;br /&gt;        'html5lib'&lt;br /&gt;    ], **extra&lt;br /&gt;)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ここで、テストのときだけ必要なライブラリを書くことができる。&lt;br /&gt;python setup.py test&lt;br /&gt;とすると依存ライブラリをとりにいきます。&lt;br /&gt;すばらしい！&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;setuptoolsをもっと勉強します。&lt;br /&gt;deploy+setup Scriptとして、今後活用していくことを誓います。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-6431701104819188909?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/6431701104819188909/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=6431701104819188909' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/6431701104819188909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/6431701104819188909'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/09/setuptools.html' title='setuptools'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-2333858849940837472</id><published>2009-08-06T10:19:00.002+09:00</published><updated>2009-08-06T11:03:40.747+09:00</updated><title type='text'>eclipse WTP encoding</title><content type='html'>&lt;h4&gt;eclipse&lt;/h4&gt;&lt;br /&gt;&lt;h5&gt;WTP encoding&lt;/h5&gt;&lt;br /&gt;最近、Javaの仕事が増えたせいでEclipseをよく使います。&lt;br /&gt;WTPのencoding設定で困ってほかのプラグインに移ってしまう人が多いので、&lt;br /&gt;まとめておきます。&lt;br /&gt;&lt;br /&gt;その1. JSPがISO-8859-1になってしまって困っちゃう&lt;br /&gt;Window =&gt; Preferences =&gt; General =&gt; Content Types&lt;br /&gt;より&lt;br /&gt;Text =&gt; JSP を選んで"Default encoding"にUTF-8を指定し、Updateを押す。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;その2. HTMLがShift_JISに決め打ちされて困っちゃう。&lt;br /&gt;eclipse.iniに&lt;br /&gt;-Duser.language=en&lt;br /&gt;と書いておく。&lt;br /&gt;&lt;br /&gt;&lt;h5&gt;mercurial&lt;/h5&gt;&lt;br /&gt;http://www.vectrace.com/mercurialeclipse/&lt;br /&gt;ためしにインストールしてみたmercurialプラグインは比較で文字化けしてしまい、&lt;br /&gt;使い物になりません。&lt;br /&gt;&lt;br /&gt;http://bitbucket.org/mercurialeclipse/main/&lt;br /&gt;bitbucketが使われているのならば、対応は私がしようと思って、最新版をとってみたら&lt;br /&gt;あれれ？使える。&lt;br /&gt;というわけで、しばらくmercurial用クライアントとして、Eclipseも使ってみようと思います。&lt;br /&gt;&lt;br /&gt;しかし、他のクライアントを使ってみるとわかるのですが、&lt;br /&gt;Subversiveは本当によくできている。&lt;br /&gt;Syncronize with Repositoryが本当に使いやすい。&lt;br /&gt;あれをmercurialに使えたらどれほど幸せか。&lt;br /&gt;まあ、ほしい機能はIssuesに全て登録してあるので、生ぬるく見守ります。&lt;br /&gt;&lt;br /&gt;&lt;h5&gt;merge&lt;/h5&gt;&lt;br /&gt;分散型にした一番のメリットはマージ。&lt;br /&gt;多人数で開発するときは、最初はpush --forceを使ってもらって、headを作りまくってもらう。&lt;br /&gt;あとはこちらで全部マージできる。これは安心だ。&lt;br /&gt;でも、この方式ならdarcsのほうがいいのかなー。&lt;br /&gt;&lt;br /&gt;まだマージのBest Practiceを見つけられない。&lt;br /&gt;試行錯誤の連続だけど、ツールとしてはextdiff=WinMergeが今のところ楽かな。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-2333858849940837472?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/2333858849940837472/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=2333858849940837472' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/2333858849940837472'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/2333858849940837472'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/08/eclipse-wtp-encoding.html' title='eclipse WTP encoding'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-3590313502171169004</id><published>2009-06-19T19:12:00.007+09:00</published><updated>2009-06-19T19:44:17.565+09:00</updated><title type='text'>Java detect Encoding for Japanese</title><content type='html'>javaにはエンコード自動認識が標準ではなかったので、探し回った。&lt;br /&gt;* &lt;a href="http://jchardet.sourceforge.net/"&gt;jchardet&lt;/a&gt;&lt;br /&gt;* &lt;a href="http://code.google.com/p/juniversalchardet/"&gt;juniversalchardet&lt;/a&gt;&lt;br /&gt;などが見つかったけど、とりあえず、標準で逃げる方法。&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;private final List&amp;lt;CharsetDecoder&amp;gt; decoders;&lt;br /&gt; {&lt;br /&gt; // 色々試した結果、この順序が必須&lt;br /&gt; String[] names = new String[] { "ISO-2022-JP", "EUC-JP", "UTF-8",&lt;br /&gt;   "windows-31j" };&lt;br /&gt; decoders = new LinkedList&amp;lt;CharsetDecoder&amp;gt;();&lt;br /&gt; for (String name : names) {&lt;br /&gt;  decoders.add(Charset.forName(name).newDecoder());&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;public Charset detectEncoding(byte[] bytes) throws Exception {&lt;br /&gt; for (CharsetDecoder d : decoders) {&lt;br /&gt;  try {&lt;br /&gt;   d.decode(ByteBuffer.wrap(bytes));&lt;br /&gt;  } catch (CharacterCodingException e) {&lt;br /&gt;   continue;&lt;br /&gt;  }&lt;br /&gt;  return d.charset();&lt;br /&gt; }&lt;br /&gt; throw new IllegalArgumentException("デコードできませんでした。");&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void testDetectEncoding() throws Exception {&lt;br /&gt; String[] samples = new String[] { "平", "カ", "１", "ひ", "ｂ", };&lt;br /&gt; for (String s : samples) {&lt;br /&gt;  assertEquals("windows-31j", detectEncoding(s.getBytes("sjis")).toString());&lt;br /&gt;  assertEquals("UTF-8", detectEncoding(s.getBytes("utf-8")).toString());&lt;br /&gt;  assertEquals("EUC-JP", detectEncoding(s.getBytes("euc_jp")).toString());&lt;br /&gt;  assertEquals("ISO-2022-JP", detectEncoding(s.getBytes("jis")).toString());&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/charsetdecoder&gt;&lt;/charsetdecoder&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-3590313502171169004?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/3590313502171169004/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=3590313502171169004' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3590313502171169004'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3590313502171169004'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/06/java-detect-encoding-for-japanese.html' title='Java detect Encoding for Japanese'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-4092352829795297687</id><published>2009-05-25T16:01:00.002+09:00</published><updated>2009-05-25T16:07:05.993+09:00</updated><title type='text'>timeit on java</title><content type='html'>SpringのAutoWireの有無による速度差と、CGLIBとProxyの速度差を調べたくなった。&lt;br /&gt;AutoWireの有無による速度差はなし。&lt;br /&gt;CGLIBとProxyも十分無視してよい速度差。&lt;br /&gt;&lt;br /&gt;上の目的のためにtimeitみたいに、適当な回数分だけループして時間を計測してくれるツールを作った。&lt;br /&gt;一定の時間を越えるまで回数を増やしてループし続けます。&lt;br /&gt;最初は500msにしたら、テストスイートが終わらなくなったので、50ms。&lt;br /&gt;比較用に交互に実行する機能があるといいかも。&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public abstract class Timeit {&lt;br /&gt; protected String name;&lt;br /&gt;&lt;br /&gt; public Timeit(String name) {&lt;br /&gt;  this.name = name;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void timeit() {&lt;br /&gt;  int before = 0;&lt;br /&gt;  int count = 1;&lt;br /&gt;  long sum = 0;&lt;br /&gt;  prepare();&lt;br /&gt;  while (true) {&lt;br /&gt;   int loop = count - before;&lt;br /&gt;   long start = System.nanoTime();&lt;br /&gt;   for (int i = 0; i &lt; loop; ++i) {&lt;br /&gt;    this.invoke();&lt;br /&gt;   }&lt;br /&gt;   long end = System.nanoTime();&lt;br /&gt;   long current = end - start;&lt;br /&gt;   sum += current;&lt;br /&gt;   if (current &gt; 50 * 1000 * 1000) {&lt;br /&gt;    break;&lt;br /&gt;   }&lt;br /&gt;   before = count;&lt;br /&gt;   count = count * 2;&lt;br /&gt;  }&lt;br /&gt;  long time = sum / count;&lt;br /&gt;  System.out.print(name + ": ");&lt;br /&gt;  if (time &lt; 1000) {&lt;br /&gt;   System.out.printf("%dns\n", time);&lt;br /&gt;  } else if (time &lt; 1000 * 1000) {&lt;br /&gt;   System.out.printf("%.3fμs %dtimes\n", time / 1000.0, count);&lt;br /&gt;  } else if (time &lt; 1000 * 1000 * 1000) {&lt;br /&gt;   System.out.printf("%.3fms %dtimes\n", time / 1000.0 / 1000, count);&lt;br /&gt;  } else {&lt;br /&gt;   System.out.printf("%.3fs %dtimes\n", time / 1000.0 / 1000 / 1000,&lt;br /&gt;     count);&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void prepare() {&lt;br /&gt;&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public abstract void invoke();&lt;br /&gt;&lt;br /&gt; public static class TimeItTest extends TestCase {&lt;br /&gt;  public void testSimple() throws Exception {&lt;br /&gt;   new Timeit("simple") {&lt;br /&gt;    public void invoke() {&lt;br /&gt;     try {&lt;br /&gt;      Thread.sleep(2);&lt;br /&gt;     } catch (InterruptedException e) {&lt;br /&gt;     }&lt;br /&gt;    }&lt;br /&gt;   }.timeit();&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-4092352829795297687?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/4092352829795297687/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=4092352829795297687' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/4092352829795297687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/4092352829795297687'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/05/timeit-on-java.html' title='timeit on java'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-1514235957838155531</id><published>2009-05-25T15:15:00.002+09:00</published><updated>2009-05-25T15:35:40.457+09:00</updated><title type='text'>Mockito</title><content type='html'>Mockito便利です。&lt;br /&gt;jMockの変態構文に慣れない方は、EasyMockを使ってらっしゃると思います。&lt;br /&gt;EasyMockのスタイルは素敵ですね。&lt;br /&gt;ただ、人に勧めるときに、replayとかverifyとか、定義以外に文をはさむのってなんかいやですよね。&lt;br /&gt;お勧めしづらいですね。&lt;br /&gt;expectLastCallなんかもみっともない。&lt;br /&gt;&lt;br /&gt;そこで&lt;a href="http://code.google.com/p/mockito/"&gt;Mockito&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="java" name="code"&gt;&lt;br /&gt;    // モック作成&lt;br /&gt;    @SuppressWarnings("unchecked")&lt;br /&gt;    List&lt;String&gt; mockedList = mock(List.class);&lt;br /&gt;&lt;br /&gt;    // あらかじめ、何が起こるかを書く&lt;br /&gt;    when(mockedList.add("one")).thenReturn(true);&lt;br /&gt;    // voidはwhenの引数として受け取れないのでdo*で書き直す。&lt;br /&gt;    doNothing().when(mockedList).clear();&lt;br /&gt;&lt;br /&gt;    // モックに対して実行&lt;br /&gt;    assertEquals(true, mockedList.add("one"));&lt;br /&gt;    mockedList.clear();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;事前に定義する方法のほかに、あとからVerifyする方法もあります。&lt;br /&gt;&lt;pre class="java" name="code"&gt;&lt;br /&gt;    // モック作成&lt;br /&gt;    @SuppressWarnings("unchecked")&lt;br /&gt;    List&lt;String&gt; mockedList = mock(List.class);&lt;br /&gt;&lt;br /&gt;    // モックに対して実行&lt;br /&gt;    mockedList.add("one");&lt;br /&gt;    mockedList.clear();&lt;br /&gt;&lt;br /&gt;    // 検証&lt;br /&gt;    verify(mockedList).add("one");&lt;br /&gt;    verify(mockedList).clear();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;呼び出し回数も限定しておきます。&lt;br /&gt;&lt;pre class="java" name="code"&gt;&lt;br /&gt;    @SuppressWarnings("unchecked")&lt;br /&gt;    LinkedList&lt;String&gt; mockedList = mock(LinkedList.class);&lt;br /&gt;    // モックに対してメソッド呼び出し&lt;br /&gt;    mockedList.add("once");&lt;br /&gt;&lt;br /&gt;    mockedList.add("twice");&lt;br /&gt;    mockedList.add("twice");&lt;br /&gt;&lt;br /&gt;    mockedList.add("three times");&lt;br /&gt;    mockedList.add("three times");&lt;br /&gt;    mockedList.add("three times");&lt;br /&gt;&lt;br /&gt;    // 回数指定で検証開始&lt;br /&gt;    verify(mockedList).add("once");&lt;br /&gt;    verify(mockedList, times(1)).add("once");&lt;br /&gt;    verify(mockedList, times(2)).add("twice");&lt;br /&gt;    verify(mockedList, times(3)).add("three times");&lt;br /&gt;&lt;br /&gt;    // 呼ばれてない確認。times(0)でもOK&lt;br /&gt;    verify(mockedList, never()).add("never happened");&lt;br /&gt;&lt;br /&gt;    // 細かい数は不要。一度でも呼ばれたらOK&lt;br /&gt;    verify(mockedList, atLeastOnce()).add("three times");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;すでに存在するオブジェクトに対して、部分的にモックを割り当てます。&lt;br /&gt;名づけて"spy"&lt;br /&gt;&lt;pre class="java" name="code"&gt;&lt;br /&gt;    // 部分的に書き換える。&lt;br /&gt;    LinkedList&lt;String&gt; spyList = spy(new LinkedList&lt;String&gt;());&lt;br /&gt;    when(spyList.size()).thenReturn(100);&lt;br /&gt;&lt;br /&gt;    // addやgetは本来の動き&lt;br /&gt;    spyList.add("one");&lt;br /&gt;    assertEquals("one", spyList.get(0));&lt;br /&gt;    &lt;br /&gt;    // sizeは置き換えました。&lt;br /&gt;    assertEquals(100, spyList.size());&lt;br /&gt;&lt;br /&gt;    verify(spyList).add("one");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Mock作成が楽しくなりました。&lt;br /&gt;Javaの構文による呼び出し順序を利用したマジックですが、&lt;br /&gt;ここまできれいな構文で書けるなら、受け入れるしかないでしょう。&lt;br /&gt;Mock内で引数に加工したり、詳しく検証する場合は、Anythingというインターフェースを使って実装するのですが、そこはまだありがちな構文。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/powermock/"&gt;PowerMock&lt;/a&gt;もMockitoに対応中。&lt;br /&gt;まあ、PowerMockなんて、一時的に使うことはあっても、すぐ書き直してMockitoだけで通るように変更するのでいらないけど。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-1514235957838155531?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/1514235957838155531/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=1514235957838155531' title='1 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1514235957838155531'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1514235957838155531'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/05/mockito.html' title='Mockito'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-6529691741865570384</id><published>2009-04-08T15:18:00.003+09:00</published><updated>2009-04-08T16:23:40.243+09:00</updated><title type='text'>How Fast is JRuby</title><content type='html'>&lt;a href="http://blog.headius.com/2009/04/how-jruby-makes-ruby-fast.html"&gt;How JRuby Makes Ruby Fast&lt;/a&gt;&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;def tak x, y, z&lt;br /&gt; if y &gt;= x&lt;br /&gt;   return z&lt;br /&gt; else&lt;br /&gt;   return tak( tak(x-1, y, z),&lt;br /&gt;               tak(y-1, z, x),&lt;br /&gt;               tak(z-1, x, y))&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;tak(24, 16, 8)を10回分の時間はいかほど？&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; user     system      total        real&lt;br /&gt;0.524000   0.000000   0.524000 (  0.524000)&lt;br /&gt;0.338000   0.000000   0.338000 (  0.338000)&lt;br /&gt;0.325000   0.000000   0.325000 (  0.325000)&lt;br /&gt;0.299000   0.000000   0.299000 (  0.299000)&lt;br /&gt;0.310000   0.000000   0.310000 (  0.310000)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;JRubyはええええええ。&lt;br /&gt;と思ったけど、Rubyの速さをよく知らないので、わからない。&lt;br /&gt;あまりベンチマークに興味を持ったことがない。&lt;br /&gt;&lt;br /&gt;一応、手元のJRubyでも試したよ。&lt;br /&gt;jruby --server --fast tak.rb&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;      user     system      total        real&lt;br /&gt;  1.281000   0.000000   1.281000 (  1.219000)&lt;br /&gt;  0.906000   0.000000   0.906000 (  0.906000)&lt;br /&gt;  0.906000   0.000000   0.906000 (  0.906000)&lt;br /&gt;  0.922000   0.000000   0.922000 (  0.922000)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;とりあえずPythonと比較してみた。&lt;br /&gt;ここはさくっと1秒をきってもらいたいところ。&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;def tak(x, y, z):&lt;br /&gt;    if y &gt;= x:&lt;br /&gt;        return z&lt;br /&gt;    else:&lt;br /&gt;        return tak(tak(x-1, y, z),&lt;br /&gt;                tak(y-1, z, x),&lt;br /&gt;                tak(z-1, x, y))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;python tak.py&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;4.68799996376s&lt;br /&gt;4.67199993134s&lt;br /&gt;4.71900010109s&lt;br /&gt;4.70300006866s&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;。。。&lt;br /&gt;&lt;br /&gt;気を取り直して、Jython。&lt;br /&gt;まあ、期待してないっす。Pythonの倍ぐらい遅くてもぜんぜん気にしないっす。&lt;br /&gt;だって、お金かかってないっすからね。&lt;br /&gt;Pythonと同じソースが走るのは優秀っすね。&lt;br /&gt;jython tak.py&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;12.2509999275s&lt;br /&gt;12.1879999638s&lt;br /&gt;12.2030000687s&lt;br /&gt;12.1879999638s&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;。。。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Ironのじつりきに期待したいけど、ビルドしたことなかった。&lt;br /&gt;いつか誰かがやります。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;ところでさ、Javaだとどんなもんかな。&lt;br /&gt;0.3秒が数倍遅いって言ってるんだから、0.08秒ぐらいか。&lt;br /&gt;そりゃはやいね。&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;    static int tak(int x, int y, int z) {&lt;br /&gt;        if (y &gt;= x)&lt;br /&gt;            return z;&lt;br /&gt;        else&lt;br /&gt;            return tak(tak(x - 1, y, z), tak(y - 1, z, x), tak(z - 1, x, y));&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;java Tak.java&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;0.107289151s&lt;br /&gt;0.107325477s&lt;br /&gt;0.107177706s&lt;br /&gt;0.10697179s&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;JRubyはえええええ！&lt;br /&gt;しかし、ここはJavaのすごいところが見たい！&lt;br /&gt;java -server Tak.java&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;0.094475588s&lt;br /&gt;0.081646268s&lt;br /&gt;0.081483518s&lt;br /&gt;0.08147525s&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;やっぱりJRubyはええええ。&lt;br /&gt;ええい、他にオプションはないのか。&lt;br /&gt;&lt;br /&gt;というわけでJRubyの速さを際立たせるだけでした。&lt;br /&gt;あ、そうだ。&lt;br /&gt;Dubyが早いならGroovyも型を指定すれば早いんじゃね？&lt;br /&gt;cp Tak.java Tak.groovy&lt;br /&gt;groovy Tak.groovy&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;6.369433797s&lt;br /&gt;6.266855432s&lt;br /&gt;6.264844057s&lt;br /&gt;6.277156358s&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;本気か？&lt;br /&gt;事前にコンパイルしないとだめか、そうかそうか。&lt;br /&gt;&lt;br /&gt;groovyc Tak.groovy&lt;br /&gt;groovy Tak&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;6.336249071s&lt;br /&gt;6.235964946s&lt;br /&gt;6.235621352s&lt;br /&gt;6.233301473s&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ち、ちょっと早くなったのかしら。&lt;br /&gt;&lt;br /&gt;型を指定してあげてるのにこんなに遅いって、Groovyは駄目な子なのか。&lt;br /&gt;ちなみに型を指定しなかったらJythonより遅いのか。&lt;br /&gt;SpringSourceしっかりしろよ。&lt;br /&gt;怖いもの見たさでチェック&lt;br /&gt;&lt;pre name="code" class="groovy"&gt;&lt;br /&gt;def tak(x, y, z) {&lt;br /&gt;    if (y &gt;= x)&lt;br /&gt;        return z;&lt;br /&gt;    else&lt;br /&gt;        return tak(tak(x - 1, y, z), tak(y - 1, z, x), tak(z - 1, x, y));&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;3.599673454s&lt;br /&gt;3.504575443s&lt;br /&gt;3.504178545s&lt;br /&gt;3.503208614s&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;おおおおおお！どうなってるんですか？&lt;br /&gt;速くなりました。&lt;br /&gt;倍近く早いよ。&lt;br /&gt;ってか、Pythonより速い。&lt;br /&gt;Groovyやるな！&lt;br /&gt;ってか、なんで？&lt;br /&gt;&lt;br /&gt;ここまできたらScalaも試そうか。&lt;br /&gt;&lt;pre name="code" class="groovy"&gt;&lt;br /&gt;def tak(x: Int, y: Int, z: Int): Int = {&lt;br /&gt;  if (y &gt;= x) z else tak( tak(x-1, y, z),&lt;br /&gt;             tak(y-1, z, x),&lt;br /&gt;             tak(z-1, x, y))&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;scala Tak_scala&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;0.191174899s&lt;br /&gt;0.185557729s&lt;br /&gt;0.18544463s&lt;br /&gt;0.185426475s&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;思ったより少しだけ遅いけど、悪くないね。&lt;br /&gt;serverモードはないのかな？&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;というわけでGroovyの変態さが伝わったかな？&lt;br /&gt;本当はIokeでも試したんだけど、まったく答えが返ってこないのでなかったことにしました。&lt;br /&gt;&lt;br /&gt;このまま終わると晩御飯をおいしく食べられないので、Pythonでもうチョイがんばります。&lt;br /&gt;まずはご存知psyco&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;import psyco&lt;br /&gt;psyco.full()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;と先頭につけるだけ。&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;0.281000137329s&lt;br /&gt;0.296999931335s&lt;br /&gt;0.296999931335s&lt;br /&gt;0.281000137329s&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;おお、いいね。JRubyに勝った！&lt;br /&gt;&lt;br /&gt;つづいてCython&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;cdef int ctak(int x, int y, int z):&lt;br /&gt;    if y &gt;= x:&lt;br /&gt;        return z&lt;br /&gt;    else:&lt;br /&gt;        return ctak(ctak(x-1, y, z),&lt;br /&gt;                ctak(y-1, z, x),&lt;br /&gt;                ctak(z-1, x, y))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;0.155999898911s&lt;br /&gt;0.171999931335s&lt;br /&gt;0.156000137329s&lt;br /&gt;0.155999898911s&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;よし、Scalaに勝った！&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;やっぱりPythonだね。&lt;br /&gt;&lt;br /&gt;ごらんのスポンサーの提供でお送りしました。&lt;br /&gt;java version "1.6.0_11"&lt;br /&gt;Scala code runner version 2.7.3.final&lt;br /&gt;jruby 1.3.0 (ruby 1.8.6p287) (2009-04-08 r)&lt;br /&gt;Jython 2.5b1 (trunk:5903:5905, Jan 9 2009, 16:01:29)&lt;br /&gt;Python 2.6.1&lt;br /&gt;Groovy Version: 1.6.1&lt;br /&gt;&lt;br /&gt;TODO&lt;br /&gt;グラフを貼る&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;結論。&lt;br /&gt;Groovyは型を指定すると遅くなる。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-6529691741865570384?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/6529691741865570384/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=6529691741865570384' title='32 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/6529691741865570384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/6529691741865570384'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/04/how-fast-is-jruby.html' title='How Fast is JRuby'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>32</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-3454687221203682886</id><published>2009-03-31T17:05:00.003+09:00</published><updated>2009-03-31T17:38:41.250+09:00</updated><title type='text'>sax with HTMLParser</title><content type='html'>expatでShift_JISが扱えればベストなのですが、&lt;a href="http://docs.python.org/library/pyexpat.html#xml.parsers.expat.ParserCreate"&gt;どうにもならない&lt;/a&gt;。&lt;br /&gt;&lt;pre name="code" class="xml"&gt;&lt;br /&gt;&amp;lt;?xml encoding="Shift_JIS"?&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;これが書いてあると引っかかるので、本文をutf-8にして回避することもできない。&lt;br /&gt;んがー、どこもめ。&lt;br /&gt;一行目削るしかないかなー。&lt;br /&gt;&lt;br /&gt;2.6のxmlパッケージにはexpat以外のXMLパーサがないのが不思議。&lt;br /&gt;xmllibはdeprecatedついてるけど、パーサはまだ生きている。&lt;br /&gt;ココから引っ張るか、あるいはmarkupbaseからがんばるかな。&lt;br /&gt;xml.sax.saxutils.XMLGeneratorを使いたいから、頭が痛い。&lt;br /&gt;&lt;br /&gt;saxの構文は面倒くさいし、sax風のXMLFilterを書くのが一番早いかも。&lt;br /&gt;&lt;br /&gt;つらい。&lt;br /&gt;意外とPythonは不便。&lt;br /&gt;Jythonに乗り換えたくなってきた。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;あと、なんか知らんけどRailsの仕事が舞い降りてきそうだ。&lt;br /&gt;すべて明示的に書いてきたPython文化から、暗黙文化に移るのはかなり抵抗がある。&lt;br /&gt;でも1.9とcapとmerbには興味があるので、ひさしぶりにRuby触るのもいいのかもしれないな。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-3454687221203682886?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/3454687221203682886/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=3454687221203682886' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3454687221203682886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3454687221203682886'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/03/sax-with-htmlparser.html' title='sax with HTMLParser'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-3093912488805226219</id><published>2009-03-27T20:56:00.000+09:00</published><updated>2009-03-27T20:56:02.267+09:00</updated><title type='text'>Real World Django</title><content type='html'>&lt;a href="http://jacobian.org/speaking/2009/real-world-django/"&gt;Real World Django&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;LJWorldcom運営における体験談か。&lt;br /&gt;Modelをハードコーディングするなとか、拡張性にまつわる話。&lt;br /&gt;スケーリングや構成にまつわる話など、興味深い。&lt;br /&gt;PDFだけじゃなくて、お話も聞きたいなー。&lt;br /&gt;Podcastとか公開してほしい。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;昨日、駅前でホットペッパーの人が武富士の人に怒られていた。&lt;br /&gt;何をしたのか知らんけど、駅前ばら撒きの一日の長というやつか。&lt;br /&gt;けんかするなら端っこでしてほしかった。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-3093912488805226219?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://jacobian.org/speaking/2009/real-world-django/' title='Real World Django'/><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/3093912488805226219/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=3093912488805226219' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3093912488805226219'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3093912488805226219'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/03/real-world-django.html' title='Real World Django'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-1408414208000406195</id><published>2009-03-18T17:16:00.001+09:00</published><updated>2009-03-18T17:17:46.522+09:00</updated><title type='text'>parrot 1.0.0</title><content type='html'>http://www.parrot.org/news/2009/Parrot-1.0.0&lt;br /&gt;&lt;br /&gt;きっと何かが起こっていると思うけど、何が起こっているのかわからない。&lt;br /&gt;早くつながるといいなー&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-1408414208000406195?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/1408414208000406195/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=1408414208000406195' title='1 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1408414208000406195'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1408414208000406195'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/03/parrot-100.html' title='parrot 1.0.0'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-2631297309588548373</id><published>2009-03-12T23:29:00.001+09:00</published><updated>2009-03-12T23:31:34.231+09:00</updated><title type='text'>Seasar2</title><content type='html'>ためしてみた。&lt;br /&gt;軌道に乗れば確かに結構早いですね。&lt;br /&gt;HotDeployすばらしい。&lt;br /&gt;しかし、開発はGroovyで進めて、&lt;br /&gt;後にテストしながらJavaに移行すればHotDeploy同然なのではないかと思うのです。&lt;br /&gt;ずっと書きやすいし。&lt;br /&gt;Groovy大好きです。&lt;br /&gt;&lt;br /&gt;サクサクとそこらじゅうに書いてあるけど、サンプルがちっとも見つからない。&lt;br /&gt;さくさくならそれこそDjangoのように掃いて捨てるほどサンプルが出るはずなのに。&lt;br /&gt;最初のマニュアルはあるけど、何もわからない人向けと、用語がわかる人のどっちつかずで&lt;br /&gt;中途半端。&lt;br /&gt;非常に読みづらい。&lt;br /&gt;だれもサンプルを作ってくれなくても、サクサクならBlogやWikiぐらい作っておいておけばいいのに。&lt;br /&gt;&lt;br /&gt;たとえば、EclipseのPluginで必要なものは何かを一望できる場所がない。&lt;br /&gt;JEE対応Eclipse3.3以降で、&lt;br /&gt;・Kijimuna&lt;br /&gt;・Dolteng&lt;br /&gt;・SAStrutsPlugin&lt;br /&gt;・PropertyEditor&lt;br /&gt;が必要と、さっと書いてあれば進めるのに、インストールの仕方を逐次読まなければならない。&lt;br /&gt;初心者に親切だと思うかもしれないけど、書いてあるとおりに進めても完成しない。&lt;br /&gt;突然、状況にあわせて書き換えろと書かれる。&lt;br /&gt;&lt;br /&gt;どうせならEclipseもDIもわかる人にSeasarはどう便利なのか訴えるページを書けばいいのに。&lt;br /&gt;ない。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Doltengで作ったプロジェクトはFreemarkerでコンパイルエラー発生しますね。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-2631297309588548373?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/2631297309588548373/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=2631297309588548373' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/2631297309588548373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/2631297309588548373'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/03/seasar2.html' title='Seasar2'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-3702142025393024299</id><published>2009-03-12T23:26:00.001+09:00</published><updated>2009-03-12T23:27:17.739+09:00</updated><title type='text'>NetBeansのゆくえ</title><content type='html'>&lt;a href="http://blogs.sun.com/tor/entry/new_job"&gt;Tor Norbye&amp;#39;s Weblog&lt;/a&gt;&lt;br /&gt;JRubyもだめなのかなー。&lt;br /&gt;やっぱりSunってJavaFXに本気なんだね。&lt;br /&gt;NetBeansには期待してたんだけど、完成は遠いですね。&lt;br /&gt;たまにアップデートして試用してますけど、重いし落ちるし。&lt;br /&gt;Torがいなくなるのは残念です。&lt;br /&gt;&lt;br /&gt;さて、いつかの安定のために、みんなつかってフィードバックしてあげてください。&lt;br /&gt;dailyがHudsonから落とせて、すぐ試すことができます。&lt;br /&gt;&lt;a href="http://wiki.netbeans.org/Python"&gt;NetBeans Wiki: Python&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-3702142025393024299?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/3702142025393024299/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=3702142025393024299' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3702142025393024299'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3702142025393024299'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/03/netbeans.html' title='NetBeansのゆくえ'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-917449989091922880</id><published>2009-03-10T18:15:00.003+09:00</published><updated>2009-03-10T18:30:05.994+09:00</updated><title type='text'>good bye fabric</title><content type='html'>paramikoがCTRモードに対応していないので、別れることにした。&lt;br /&gt;&lt;br /&gt;どうしてもparamikoを使いたい人、&lt;br /&gt;あるいはIncompatible ssh serverと出てしまう人のための記録。&lt;br /&gt;&lt;br /&gt;pycryptoを最新版にしましょう。&lt;br /&gt;&lt;br /&gt; paramiko.transport._cipher_info.update({&lt;br /&gt;   'aes128-ctr':{ 'class': AES, 'mode':  &lt;br /&gt;   AES.MODE_CTR, 'block-size': 16, 'key-size': 16 },&lt;br /&gt;   'aes256-ctr':{ 'class': AES, 'mode':  &lt;br /&gt;   AES.MODE_CTR, 'block-size': 32, 'key-size': 32 },&lt;br /&gt;   })&lt;br /&gt;&lt;br /&gt;Capistranoって便利なのかな。&lt;br /&gt;でも、とりあえずbashでいくわ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-917449989091922880?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/917449989091922880/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=917449989091922880' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/917449989091922880'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/917449989091922880'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/03/good-bye-fabric.html' title='good bye fabric'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-6724903044545805775</id><published>2009-03-02T15:30:00.005+09:00</published><updated>2009-03-02T16:04:18.855+09:00</updated><title type='text'>10 minutes topic</title><content type='html'>&lt;a href="http://d.hatena.ne.jp/CortYuming/20090224/p1"&gt;http://d.hatena.ne.jp/CortYuming/20090224/p1&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;def deal(member, data):&lt;br /&gt;    """&lt;br /&gt;    &gt;&gt;&gt; deal(3, "123123123")&lt;br /&gt;    ['111', '222', '333']&lt;br /&gt;    &gt;&gt;&gt; deal(4, "123123123")&lt;br /&gt;    ['12', '23', '31', '12']&lt;br /&gt;    &gt;&gt;&gt; deal(6, "012345012345012345")&lt;br /&gt;    ['000', '111', '222', '333', '444', '555']&lt;br /&gt;    &gt;&gt;&gt; deal(4, '111122223333')&lt;br /&gt;    ['123', '123', '123', '123']&lt;br /&gt;    &gt;&gt;&gt; deal(1, '012345012345012345')&lt;br /&gt;    ['012345012345012345']&lt;br /&gt;    &gt;&gt;&gt; deal(6, '01234')&lt;br /&gt;    ['', '', '', '', '', '']&lt;br /&gt;    &gt;&gt;&gt; deal(2, '')&lt;br /&gt;    ['', '']&lt;br /&gt;    """&lt;br /&gt;    from itertools import izip, cycle&lt;br /&gt;    a = [''] * member&lt;br /&gt;    for d, m in izip(data[:len(data) - len(data) % member],&lt;br /&gt;            cycle(range(member))):&lt;br /&gt;        a[m] += d&lt;br /&gt;    return a&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;見ないようにしたのに、似たような回答になってしまった。&lt;br /&gt;本当は初期値を準備せずにうまいことやりたかったんだけど。&lt;br /&gt;たとえばreduceは、どんな理論か知りませんが、適切に初期値を準備してくれますよね。&lt;br /&gt;文字列の += もいやな感じ。&lt;br /&gt;行数を増やさずにjoinにしたい。&lt;br /&gt;&lt;br /&gt;ワンライナーがかけるようになりたい。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-6724903044545805775?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/6724903044545805775/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=6724903044545805775' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/6724903044545805775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/6724903044545805775'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/03/10-minutes-topic.html' title='10 minutes topic'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-1228709222458500829</id><published>2009-02-17T12:55:00.004+09:00</published><updated>2009-02-20T12:54:50.254+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>python code reading for WEB</title><content type='html'>&lt;a href="http://d.hatena.ne.jp/mopemope/20090217/p1"&gt;Python力を高めるためのライブラリコードリーディング&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;私もDjangoからPythonに入った口ですが、&lt;br /&gt;今もDjangoからPythonにはいる人が多いと思います。&lt;br /&gt;&lt;br /&gt;まず読みたいのがこの記事。&lt;br /&gt;&lt;a href="http://bitworking.org/news/Why_so_many_Python_web_frameworks"&gt;Why so many Python web frameworks?&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;いかにフレームワークを作るのが簡単かがわかり、自分で作ってみたくなる。&lt;br /&gt;「ここで、Djangoなんかたいしたことないじゃん。&lt;br /&gt;もっといいのを私は作れるよ！」&lt;br /&gt;といって色々便利なフレームワークを組み合わせてみると、&lt;br /&gt;ほかのフレームワークのよいところがはじめて見えてくる。&lt;br /&gt;&lt;br /&gt;こうして色々試すとようやく「仕事」で使う上でのDjangoの魅力をようやく理解できる。&lt;br /&gt;もちろん、Djangoには欠点がある。&lt;br /&gt;contrib.authの融通の利かなさとか、&lt;br /&gt;modelsがややお間抜けとか、&lt;br /&gt;Routingのエラーメッセージとか、&lt;br /&gt;templatetagの仕様だとか、&lt;br /&gt;動的なFormとか。&lt;br /&gt;解決したライブラリををそれぞれ作ってみたけど、個人使用ならともかく公開はできない。&lt;br /&gt;ただ、解決方法をIRCでねちっこくつぶやくだけ。&lt;br /&gt;だって、メンテしたくないから。&lt;br /&gt;もっといい方法を思いついたら飛び移りたいじゃん。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;っと、脱線してしまったけど、&lt;br /&gt;とりあえず、最初にDjangoを読むよりは、個別のライブラリを読むほうが入門しやすい。&lt;br /&gt;フレームワーク以前のPythonの言語自体については、&lt;br /&gt;&lt;a href="http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html"&gt;Code Like a Pythonista: Idiomatic Python&lt;/a&gt;を読んでください。&lt;br /&gt;&lt;br /&gt;みんな、Pythonを愛してください。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-1228709222458500829?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/1228709222458500829/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=1228709222458500829' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1228709222458500829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1228709222458500829'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/02/python-code-reading-for-web.html' title='python code reading for WEB'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-1733306316443905532</id><published>2009-02-13T12:40:00.002+09:00</published><updated>2009-02-13T12:54:24.595+09:00</updated><title type='text'>Tag Filesystem</title><content type='html'>stowを使って新しいパッケージなどを試験的に導入したりしていますが、&lt;br /&gt;インストールやらアンインストールって面倒です。&lt;br /&gt;&lt;br /&gt;ふと、ファイルシステムがタグベースならアンインストールが楽なのにと気づいた。&lt;br /&gt;インストールして、依存ライブラリにタグをつけていけば明快です。&lt;br /&gt;reference countingと同じ。&lt;br /&gt;&lt;br /&gt;実行属性やPATHなどの環境変数、シンボリックリンクの問題も解決するのにな。&lt;br /&gt;&lt;br /&gt;まあ、タグだけだとファイルの指定が大変になりそうなので、&lt;br /&gt;適切な解決方法が出るまでは階層構造と併用になりそうですが。&lt;br /&gt;&lt;br /&gt;TagFSなど、すでに実装もあるみたいですね。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-1733306316443905532?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/1733306316443905532/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=1733306316443905532' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1733306316443905532'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1733306316443905532'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/02/tag-filesystem.html' title='Tag Filesystem'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-1176731090793020580</id><published>2009-02-12T10:20:00.002+09:00</published><updated>2009-02-12T11:00:17.434+09:00</updated><title type='text'>Clojure</title><content type='html'>&lt;a href="http://www.infoq.com/news/2009/02/jruby-clojure"&gt;InfoQ: JRuby and Clojure - A Good Match?&lt;/a&gt;&lt;br /&gt;Clojureの1.0が近い。&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://github.com/weavejester/compojure/tree/master"&gt;Compojure&lt;/a&gt; : Rubyの&lt;a href="http://www.sinatrarb.com/"&gt;Sinatra&lt;/a&gt;風WEBフレームワーク&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://github.com/mmcgrana/ring/tree/master"&gt;Ring&lt;/a&gt;: WSGIやRackにあたるもの&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://github.com/duelinmarkers/clj-record"&gt;clj-record&lt;/a&gt;: ActiveRecord-likeなORM mapper&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://github.com/stuarthalloway/lancet/tree/master"&gt;Lancet&lt;/a&gt;: Rakeっぽい&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://github.com/antoniogarrote/clj-haml/tree/master"&gt;clj-haml&lt;/a&gt;: HAML風clojure実装&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;WSGIやRakeみたいなものがあると、俄然やる気が出てくる。&lt;br /&gt;LancetはAntがLisp風になっただけ。&lt;br /&gt;Rakeのインパクトには勝てません。&lt;br /&gt;Ringを見てみたけど、サンプルも少ないのでいまいち。&lt;br /&gt;あまりよさそうには見えない。&lt;br /&gt;&lt;br /&gt;SinatraみたいにRouteが散ると、多人数でカオスになっちゃうんだよね。&lt;br /&gt;&lt;br /&gt;Clojureはまだまだだと思っているけど、使ってみた人いるかな？&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;個人的にはJVM言語はGroovyが圧倒的にお勧め。&lt;br /&gt;Pythonよりも好きかも。&lt;br /&gt;Javaの大規模開発もGroovyで始めて徐々にJavaに移行するようにすればいいのにと思っている。&lt;br /&gt;今度、Javaで仕事がきたらやってみたいな。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-1176731090793020580?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/1176731090793020580/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=1176731090793020580' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1176731090793020580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1176731090793020580'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/02/clojure.html' title='Clojure'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-6417034887156256984</id><published>2009-02-03T00:46:00.005+09:00</published><updated>2009-02-03T03:14:09.580+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='PHP'/><category scheme='http://www.blogger.com/atom/ns#' term='django'/><title type='text'>Django for PHP</title><content type='html'>&lt;a href="http://www.pluf.org/"&gt;Pluf&lt;/a&gt;&lt;br /&gt;出ました。&lt;br /&gt;いや、出てました。&lt;br /&gt;すばらしい。&lt;br /&gt;&lt;br /&gt;テンプレートエンジン以外はPure PHPと言うところがウリの一つです。&lt;br /&gt;&lt;br /&gt;まずURL設定。&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;$ctl = array();&lt;br /&gt;$base = Pluf::f('idf_base');&lt;br /&gt;&lt;br /&gt;$ctl[] = array('regex' =&gt; '#^/p/([\-\w]+)/review/$#',&lt;br /&gt;               'base' =&gt; $base,&lt;br /&gt;               'priority' =&gt; 4,&lt;br /&gt;               'model' =&gt; 'IDF_Views_Review',&lt;br /&gt;               'method' =&gt; 'index');&lt;br /&gt;&lt;br /&gt;$ctl[] = array('regex' =&gt; '#^/p/([\-\w]+)/review/(\d+)/$#',&lt;br /&gt;               'base' =&gt; $base,&lt;br /&gt;               'priority' =&gt; 4,&lt;br /&gt;               'model' =&gt; 'IDF_Views_Review',&lt;br /&gt;               'method' =&gt; 'view');&lt;br /&gt;&lt;br /&gt;$ctl[] = array('regex' =&gt; '#^/p/([\-\w]+)/review/create/$#',&lt;br /&gt;               'base' =&gt; $base,&lt;br /&gt;               'priority' =&gt; 4,&lt;br /&gt;               'model' =&gt; 'IDF_Views_Review',&lt;br /&gt;               'method' =&gt; 'create');&lt;br /&gt;return $ctl;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;うん、まあこんな感じだろうね。&lt;br /&gt;重複も多いし、modelとmethodで分かれているから、少し長い。&lt;br /&gt;あと、分割も標準の方法が見つからないのでもう一工夫ほしいところ。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;viewは見慣れたコード。&lt;br /&gt;名前付き引数がないので$match[1]になることと、&lt;br /&gt;名前空間がないので、名前が長くなることがおしい。&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;    public function updateItem($request, $match)&lt;br /&gt;    {&lt;br /&gt;        $item = Pluf_Shortcuts_GetObjectOr404('Todo_Item', $match[1]);&lt;br /&gt;        $new_data = $item-&gt;getData();&lt;br /&gt;        if ($request-&gt;method == 'POST') {&lt;br /&gt;            $form = Pluf_Shortcuts_GetFormForModel($item, $request-&gt;POST);&lt;br /&gt;            if ($form-&gt;isValid()) {&lt;br /&gt;                $item = $form-&gt;save();&lt;br /&gt;                $url = Pluf_HTTP_URL_urlForView('Todo_Views::viewList',&lt;br /&gt;                                                array($item-&gt;list));&lt;br /&gt;                return new Pluf_HTTP_Response_Redirect($url);&lt;br /&gt;            }&lt;br /&gt;        } else {&lt;br /&gt;            $form = Pluf_Shortcuts_GetFormForModel($item, $item-&gt;getData());&lt;br /&gt;        }&lt;br /&gt;        return Pluf_Shortcuts_RenderToResponse('todo/item/update.html',&lt;br /&gt;                                 array('page_title' =&gt; 'Update a Todo Item',&lt;br /&gt;                                       'item' =&gt; $item,&lt;br /&gt;                                       'form' =&gt; $form));&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;テンプレート&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;{extends 'todo/base.html'}&lt;br /&gt;&lt;br /&gt;{block body}&lt;br /&gt;&amp;lt;h2&amp;gt;{$list.name}&amp;lt;/h2&amp;gt;&lt;br /&gt;&lt;br /&gt;{if $items}&lt;br /&gt;&amp;lt;ol&amp;gt;&lt;br /&gt;{foreach $items as $item}&lt;br /&gt;&amp;lt;li&amp;gt;&amp;lt;a href="{url 'Todo_Views::viewItem', array($item.id)}"&amp;gt;{$item.item}&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;br /&gt;{/foreach}&lt;br /&gt;&amp;lt;/ol&amp;gt;&lt;br /&gt;{/if}&lt;br /&gt;&lt;br /&gt;&amp;lt;p&amp;gt;&amp;lt;a href="{url 'Todo_Views::addItem', array($list.id)}"&amp;gt;Create a new item&amp;lt;/a&amp;gt; | &amp;lt;a href="{url 'Todo_Views::updateList', array($list.id)}"&amp;gt;Update the list&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;{/block}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;すばらしい。&lt;br /&gt;文句のつけようがありません。&lt;br /&gt;まあ、テンプレートエンジンだから当然か。&lt;br /&gt;ところどころPHPの流儀を守っているところがさすがです。&lt;br /&gt;&lt;br /&gt;しっかりテストクライアントが付いているところが粋です。&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;$client-&gt;post('/login/', array('login' =&gt; 'toto', &lt;br /&gt;                               'password' =&gt; 'secret'));&lt;br /&gt;$client-&gt;get('/privatepage/');&lt;br /&gt;$reponse = $client-&gt;get($url, array('optional_get_param' =&gt; 'toto'));&lt;br /&gt;$this-&gt;assertEqual(200, $response-&gt;status_code);&lt;br /&gt;// print $response-&gt;content;&lt;br /&gt;// print_r($response-&gt;template); &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;モデル&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;class Todo_Item extends Pluf_Model&lt;br /&gt;{&lt;br /&gt;  public $_model = __CLASS__;&lt;br /&gt;  // ここに定義を書く&lt;br /&gt;  function init()&lt;br /&gt;  {&lt;br /&gt;    // テーブル名。設定ファイルでprefix設定可能&lt;br /&gt;    $this-&gt;_a['table'] = 'todo_items';&lt;br /&gt;&lt;br /&gt;    // クラス名を書く。PHPって自分のクラス名を取れなかったっけ？&lt;br /&gt;    $this-&gt;_a['model'] = 'Todo_Item';&lt;br /&gt;&lt;br /&gt;    // フィールド定義&lt;br /&gt;    $this-&gt;_a['cols'] = array(&lt;br /&gt;         // 残念ながらID定義は必要&lt;br /&gt;        'id' =&gt;&lt;br /&gt;        array(&lt;br /&gt;              'type' =&gt; 'Pluf_DB_Field_Sequence',&lt;br /&gt;              'blank' =&gt; true, &lt;br /&gt;              ),&lt;br /&gt;        'item' =&gt; &lt;br /&gt;        array(&lt;br /&gt;              'type' =&gt; 'Pluf_DB_Field_Varchar',&lt;br /&gt;              'blank' =&gt; false,&lt;br /&gt;              'size' =&gt; 250,&lt;br /&gt;              'verbose' =&gt; __('todo item'),&lt;br /&gt;               ),&lt;br /&gt;        'completed' =&gt; &lt;br /&gt;        array(&lt;br /&gt;              'type' =&gt; 'Pluf_DB_Field_Boolean',&lt;br /&gt;              'default' =&gt; false,&lt;br /&gt;              'verbose' =&gt; __('completed'),&lt;br /&gt;              ),&lt;br /&gt;        'list' =&gt; &lt;br /&gt;        array(&lt;br /&gt;              // おまちかね。関連設定。verboseがrelated_nameになる。&lt;br /&gt;              'type' =&gt; 'Pluf_DB_Field_Foreignkey',&lt;br /&gt;              'blank' =&gt; false,&lt;br /&gt;              'model' =&gt; 'Todo_List',&lt;br /&gt;              'verbose' =&gt; __('in list'),&lt;br /&gt;              'help_text' =&gt; __('To easily manage your todo items,'.&lt;br /&gt;                'you are invited to organize your todo items in lists.'),&lt;br /&gt;              ),&lt;br /&gt;        );&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;get_ + lower case name of the related model + _list&lt;br /&gt;で関連リストが取れます。&lt;br /&gt;でもどうでしょうね。&lt;br /&gt;定義も単純だし、Selectも弱いので、こればっかりは様子見か。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;FormはDjangoに忠実。&lt;br /&gt;すばらしいです。&lt;br /&gt;これは使いやすい。&lt;br /&gt;ちゃんとFormForModelがあるので安心。&lt;br /&gt;このFormと他ORMのアダプタをいくつか書いたほうがいいんじゃないのかな。&lt;br /&gt;clean_nameなどのValidationも健在。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;middlewareもあるし、&lt;br /&gt;Dispatcherも「おっ！」と思うほどシンプル。&lt;br /&gt;さらになんと、CodeIgniterよりも速い！&lt;br /&gt;残念ながら、Djangoとディレクトリ構成が違うため、&lt;br /&gt;規模が大きくなると散らかってしまうかも。&lt;br /&gt;このあたりはLoaderを書き直してほしい。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;面白いことに、このソースが配布されている&lt;br /&gt;&lt;a href="http://projects.ceondo.com/"&gt;http://projects.ceondo.com/&lt;/a&gt;自体がPlufで書かれています。&lt;br /&gt;git,svn,hgに対応したSourceBrowser,CodeReviewerにIssueTracker。&lt;br /&gt;非常によいサンプルになり、なおかつ、読みやすいことがわかるのでとてもよい。&lt;br /&gt;&lt;a href="http://projects.ceondo.com/p/indefero/"&gt;http://projects.ceondo.com/p/indefero/&lt;/a&gt;&lt;br /&gt;この規模がこれだけ読みやすいなら個人的な用途は十分まかなえそうです。&lt;br /&gt;PHPのソースで読みやすいと感じたのは久しぶりです。&lt;br /&gt;&lt;br /&gt;これが広まれば、きっとPHPからDjangoへ流れる人が増えるはず。&lt;br /&gt;PHP派もDjango派も目いっぱい布教しましょう。&lt;br /&gt;オススメです。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-6417034887156256984?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/6417034887156256984/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=6417034887156256984' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/6417034887156256984'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/6417034887156256984'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/02/django-for-php.html' title='Django for PHP'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-4196728609704732302</id><published>2009-01-27T14:29:00.004+09:00</published><updated>2009-01-27T15:33:51.312+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>web2py</title><content type='html'>これほどまでに万能（変態）の名がふさわしいフレームワークがあるだろうか。&lt;br /&gt;&lt;br /&gt;・フルスタック&lt;br /&gt;・1からアプリケーションを開発できるエディタつき万能WEBADMIN&lt;br /&gt;・GUIでER図を描くSQL Designer&lt;br /&gt;・Stan-likeなHTML BuilderとDjangoとPSPのいいとこどりテンプレート&lt;br /&gt;・とりあえずBEAUTIFY&lt;br /&gt;・Railsのflash&lt;br /&gt;・Model連動Form&lt;br /&gt;・SQLAlchemyに対抗心メラメラなORM&lt;br /&gt;・gae-likeモデル連動自動スキーマ変換&lt;br /&gt;・GQL生成するので、GAEでもModel変更不要。&lt;br /&gt;・ついでにCASも提供しておきます。&lt;br /&gt;・Exceptionから自動Ticket発行&lt;br /&gt;・Rails-likeのURL-RoutingにReverseがつき、Regex機能も併せ持つ完ぺき主義。&lt;br /&gt;・request,responseなど、実用性だけを考えた大量のglobalオブジェクト&lt;br /&gt;・ValidatorまでGlobalはマジでやめてくれ、IS_EXPR … 恐ろしい子&lt;br /&gt;&lt;br /&gt;必要な機能はすべてそろっている。&lt;br /&gt;後は勇気だけ。&lt;br /&gt;&lt;br /&gt;変態だから人に勧めにくい。&lt;br /&gt;GAEで使うフレームワークを探していたときに見つけた。&lt;br /&gt;この豊富な機能は感動。&lt;br /&gt;&lt;br /&gt;個人でいくつかGAEように作ったけど、会社では使いたくない。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;------&lt;br /&gt;ようやく書いた。&lt;br /&gt;書こうと思ってメモ書きだけして、放置してあるのが多数。&lt;br /&gt;ブログの使い方を間違えているな。&lt;br /&gt;&lt;br /&gt;もういいやと思ってメモを消してしまったことも多いし、&lt;br /&gt;メモでもいいからとりあえず公開して、その後追加、あるいはまとめを書くスタイルに変えなければ。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;書きかけで放置してあるメモはあと5つ。&lt;br /&gt;・django command拡張&lt;br /&gt;・django-things&lt;br /&gt;・Seasar2&lt;br /&gt;・ipython&lt;br /&gt;・本文抽出&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-4196728609704732302?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/4196728609704732302/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=4196728609704732302' title='1 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/4196728609704732302'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/4196728609704732302'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/01/web2py.html' title='web2py'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-3211384478243668301</id><published>2009-01-23T01:08:00.003+09:00</published><updated>2009-02-20T10:17:52.331+09:00</updated><title type='text'>download mass images 3</title><content type='html'>&lt;a href="http://hikozaemonchan.blogspot.com/2009/01/download-mass-images-2.html"&gt;download mass images 2&lt;/a&gt;のつづき&lt;br /&gt;&lt;br /&gt;前回で問題としてあがったこと。&lt;br /&gt;1. タプル&lt;br /&gt;2. 出力の乱れ&lt;br /&gt;&lt;br /&gt;まず、q.put((download, urljoin(url, a[-1].get('href'))))を書き換えます。&lt;br /&gt;今は引数ひとつしか受け入れられないので、&lt;br /&gt;q.put(func, args, kwargs)&lt;br /&gt;と&lt;br /&gt;func, args, kwargs = q.get()&lt;br /&gt;になればいいですね。&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;q = Queue()&lt;br /&gt;def worker(func):&lt;br /&gt;    def inner(*args, **kwargs):&lt;br /&gt;        print func, args, kwargs&lt;br /&gt;        q.put((func, args, kwargs))&lt;br /&gt;    return inner&lt;br /&gt;&lt;br /&gt;@worker&lt;br /&gt;def download(url):&lt;br /&gt;    print 'down  '+url&lt;br /&gt;    urllib.urlretrieve(url, url[url.rfind('/')+1:])&lt;br /&gt;&lt;br /&gt;@worker&lt;br /&gt;def parse(url):&lt;br /&gt;    print 'parse '+url&lt;br /&gt;    soup = BeautifulSoup(urllib.urlopen(url).read())&lt;br /&gt;    a = soup('a', href=re.compile(r'^/images/pub/\d+/\w+\.jpg$'))&lt;br /&gt;    download(urljoin(url, a[-1].get('href')))&lt;br /&gt;&lt;br /&gt;@worker&lt;br /&gt;def images(url):&lt;br /&gt;    print 'image '+url&lt;br /&gt;    soup = BeautifulSoup(urllib.urlopen(url).read())&lt;br /&gt;    a = soup('a', {'class':'image_a'}, href=re.compile(r'^/backgrounds/\d+$'))&lt;br /&gt;    map(lambda a:parse(urljoin(url, a.get('href'))), a[:4])&lt;br /&gt;&lt;br /&gt;def pages(url):&lt;br /&gt;    print 'pages '+url&lt;br /&gt;    soup = BeautifulSoup(urllib.urlopen(url).read())&lt;br /&gt;    a = soup('a', href=re.compile(r'^/desktop/\w+\.php$'))&lt;br /&gt;    map(lambda a:images(urljoin(url, a.get('href'))), a[:4])&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    def loop():&lt;br /&gt;        while 1:&lt;br /&gt;            func, args, kwargs = q.get()&lt;br /&gt;            try:&lt;br /&gt;                func(*args, **kwargs)&lt;br /&gt;            except Exception, e:&lt;br /&gt;                print e&lt;br /&gt;            finally:&lt;br /&gt;                q.task_done()&lt;br /&gt;    for i in range(THREAD_MAX):&lt;br /&gt;        w = Thread(target=loop)&lt;br /&gt;        w.daemon = True&lt;br /&gt;        w.start()&lt;br /&gt;    pages(sys.argv[1])&lt;br /&gt;    q.join()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;なんとなく思いついたので、デコレータにしてみました。&lt;br /&gt;これなら、呼び出しがシングルスレッドと同じになります。&lt;br /&gt;引数も可変です。&lt;br /&gt;読みやすいですね。&lt;br /&gt;欠点はシングルスレッドと同じと言うことでしょう。&lt;br /&gt;似たようなものは似た書き方をすべきではないかもしれません。&lt;br /&gt;&lt;br /&gt;表示の乱れに関しては、&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;from threading import Lock&lt;br /&gt;lock = Lock()&lt;br /&gt;def p(s):&lt;br /&gt;    lock.acquire()&lt;br /&gt;    try:&lt;br /&gt;        print s&lt;br /&gt;    finally:&lt;br /&gt;        lock.release()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ロックされた関数pを使って表示するようにします。&lt;br /&gt;あとは、ご存知loggingモジュールはスレッドセーフなので、&lt;br /&gt;loggingを使うのがもっとよい方法です。&lt;br /&gt;&lt;br /&gt;ここまでを統合して、Workerクラスを書くとすれば、&lt;br /&gt;このあたりでしょうか。&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;class Worker:&lt;br /&gt;    def __init__(self, num):&lt;br /&gt;        self.q = q = Queue()&lt;br /&gt;        def loop():&lt;br /&gt;            while 1:&lt;br /&gt;                func, args, kwargs = q.get()&lt;br /&gt;                try:&lt;br /&gt;                    func(*args, **kwargs)&lt;br /&gt;                except Exception, e:&lt;br /&gt;                    logging.exception(e)&lt;br /&gt;                finally:&lt;br /&gt;                    q.task_done()&lt;br /&gt;        for i in range(num):&lt;br /&gt;            w = Thread(target=loop)&lt;br /&gt;            w.daemon = True&lt;br /&gt;            w.start()&lt;br /&gt;    def put(self, func, *args, **kwargs):&lt;br /&gt;        logging.debug(e)&lt;br /&gt;        self.q.put((func, args, kwargs))&lt;br /&gt;    def join(self):&lt;br /&gt;        self.q.join()&lt;br /&gt;&lt;br /&gt;workers = Worker(THREAD_MAX)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;workersになにかputして作業が始まったらjoinで終了を待ってください。&lt;br /&gt;&lt;br /&gt;これも大きな欠点があります。&lt;br /&gt;Ctrl+Cで終了させることができません。&lt;br /&gt;&lt;br /&gt;さてと、最後にeventletバージョン&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;from eventlet import coros, httpc, util&lt;br /&gt;util.wrap_socket_with_coroutine_socket()&lt;br /&gt;pages = coros.CoroutinePool(max_size=THREAD_MAX)&lt;br /&gt;def download(url):&lt;br /&gt;    a = httpc.get(url)&lt;br /&gt;    # aにデータ入ってます。&lt;br /&gt;pages.execute(alljpg, n, depth - 1)&lt;br /&gt;pages.wait_all()&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;ごめん、最後は面倒なんで手抜き。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-3211384478243668301?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/3211384478243668301/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=3211384478243668301' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3211384478243668301'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3211384478243668301'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/01/download-mass-images-3.html' title='download mass images 3'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-978132674721454825</id><published>2009-01-14T13:32:00.004+09:00</published><updated>2009-01-14T15:28:21.786+09:00</updated><title type='text'>django2php</title><content type='html'>PHPの仕事が来てしまったので、&lt;br /&gt;Djangoと似た環境をPHPで探しました。&lt;br /&gt;&lt;br /&gt;Djangoの基本要素は以下の4つかな？&lt;br /&gt;・ORM&lt;br /&gt;・Template&lt;br /&gt;・Routing&lt;br /&gt;・Form&lt;br /&gt;DjangoのFormとRoutingは絶品だと思っています。&lt;br /&gt;実際は両方とも書き換えてしまったので、絶品というのは変だけど、&lt;br /&gt;基本設計は秀逸。今も感動しています。&lt;br /&gt;&lt;br /&gt;あとの認証、セッション、Middleware(Filter)あたりは、&lt;br /&gt;最初に書けば、あとはあまりいじらないから適当なライブラリから引用すればOK。&lt;br /&gt;&lt;br /&gt;あとはディレクトリ構造。&lt;br /&gt;appごとに分けられるDjangoは編集範囲が限定されていて見通しがよい。&lt;br /&gt;rails風はコントローラとモデルが遠くて大変。&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;ORM&lt;/h4&gt;&lt;br /&gt;・&lt;a href="http://propel.phpdb.org/"&gt;Propel&lt;/a&gt;&lt;br /&gt;・&lt;a href="http://www.doctrine-project.org/"&gt;Doctrine&lt;/a&gt;&lt;br /&gt;がいいらしい&lt;br /&gt;&lt;a href="http://redotheweb.com/2008/07/08/comparing-propel-doctrine-and-sfpropelfinder/"&gt;Comparing Propel, Doctrine and sfPropelFinder &lt;/a&gt;&lt;br /&gt;これはよい比較&lt;br /&gt;&lt;br /&gt;YAMLでSchemaを書けて、HQLみたいなのもあるDoctrineがいい感じ。&lt;br /&gt;でもやっぱりDjango-ORMがほしい。&lt;br /&gt;&lt;br /&gt;途中、DoctrineでfindOneByTitleという、いかにもmethod_missingを使いました的な、メソッド名を発見。&lt;br /&gt;調べてみたら、__callなんてあるんですね。&lt;br /&gt;面白い。&lt;br /&gt;&lt;br /&gt;Propelをメソッドチェーンで動くようにするなど拡張したsfPropelFinderもなかなか努力のあとがにじみ出ていていいですね。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/php-django-like-db-abstraction/"&gt;php-django-like-db-abstraction/&lt;/a&gt;&lt;br /&gt;「素晴らしい！」と思って、開いたら空っぽでした。&lt;br /&gt;名前だけ取って手をつけない人は、それがどれぐらい迷惑な行為か早く学んでほしい。&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;template&lt;/h4&gt;&lt;br /&gt;生PHPが流行らしいです。&lt;br /&gt;レイアウトとかどうするんだろう。&lt;br /&gt;ヘッダとフッタを別々に読み込むの？&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;form&lt;/h4&gt;&lt;br /&gt;symfonyのformはDjangoと似ていていいですね。&lt;br /&gt;まだ面倒に感じるのはMetaclassがないからかな？&lt;br /&gt;単体で探したけど、似たものはないので、symfonyを使うか、単体用に取り出すか実装するか。&lt;br /&gt;あるいは別の道を探すか。&lt;br /&gt;inputタグなどを出力するためのHelper関数は多く準備されているようだけど、&lt;br /&gt;ValidationやDBからの出力をこちらで考慮しなければならないのは面倒。&lt;br /&gt;DjangoのFormは優秀。&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Routing&lt;/h4&gt;&lt;br /&gt;Rails-likeが多いですね。&lt;br /&gt;/controller/action/id&lt;br /&gt;というやつね。&lt;br /&gt;正規表現Routing、おまけに間接参照のやつがあれば素敵。&lt;br /&gt;難しいものじゃないし、移植しようかな。&lt;br /&gt;&lt;br /&gt;あと、ほしいのがpythonのimport&lt;br /&gt;パスを考慮しながらのrequire_onceは難しい。&lt;br /&gt;あと、まとめて数ファイルimportしたいときもある。&lt;br /&gt;&lt;br /&gt;統合するとこんな感じか&lt;br /&gt;urls.php&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;import('bloggy.views.*');&lt;br /&gt;import('bloggy.form.EntryForm');&lt;br /&gt;&lt;br /&gt;add_patterns(array(&lt;br /&gt;'' =&gt; 'index',&lt;br /&gt;));&lt;br /&gt;add_patterns(array(&lt;br /&gt;'new' =&gt; 'EntryForm.create',&lt;br /&gt;'entry/(?P&lt;id&gt;[0-9]+)' =&gt; 'EntryForm.edit',&lt;br /&gt;), 'admin_required');&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;forms.php&lt;br /&gt;&lt;pre name="code" class="php"&gt;&lt;br /&gt;class EntryForm extends Form {&lt;br /&gt;    var $conf = array(&lt;br /&gt;        'name' =&gt; Form::TextField(),&lt;br /&gt;    );&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;PHPの構文が分からない、これでコンパイルとおるかな。&lt;br /&gt;EntryFormをimportしたときに継承して拡張したEntryFormを渡すことってできるのかな。&lt;br /&gt;同名だから無理かな。&lt;br /&gt;じゃあ、定義は_EntryFormか。&lt;br /&gt;&lt;br /&gt;やだねー、ほかの言語仕様に縛られて無理やり持ち込む人。&lt;br /&gt;もっと柔軟になったほうがいいと思います。&lt;br /&gt;symfonyおぼえよっと。&lt;br /&gt;&lt;br /&gt;あと、Kohanaも結構優秀でした。&lt;br /&gt;程よいimport(loading)、routing&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-978132674721454825?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/978132674721454825/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=978132674721454825' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/978132674721454825'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/978132674721454825'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/01/django2php.html' title='django2php'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-3177397287924241047</id><published>2009-01-13T17:00:00.002+09:00</published><updated>2009-01-13T18:29:12.543+09:00</updated><title type='text'>download mass images 2</title><content type='html'>&lt;a href="http://hikozaemonchan.blogspot.com/2009/01/download-mass-images-1.html"&gt;download mass images 1&lt;/a&gt;のつづき&lt;br /&gt;&lt;br /&gt;トップページから巡回して4ジャンルから3枚ずつのリストの取得。&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;def parse(url):&lt;br /&gt;    print 'parse '+url&lt;br /&gt;    soup = BeautifulSoup(urllib.urlopen(url).read())&lt;br /&gt;    a = soup('a', href=re.compile(r'^/images/pub/\d+/\w+\.jpg$'))&lt;br /&gt;    return urljoin(url, a[-1].get('href'))&lt;br /&gt;&lt;br /&gt;def images(url):&lt;br /&gt;    print 'image '+url&lt;br /&gt;    soup = BeautifulSoup(urllib.urlopen(url).read())&lt;br /&gt;    a = soup('a', {'class':'image_a'}, href=re.compile(r'^/backgrounds/\d+$'))&lt;br /&gt;    return map(lambda a:parse(urljoin(url, a.get('href'))), a[:3])&lt;br /&gt;&lt;br /&gt;def pages(url):&lt;br /&gt;    print 'pages '+url&lt;br /&gt;    soup = BeautifulSoup(urllib.urlopen(url).read())&lt;br /&gt;    a = soup('a', href=re.compile(r'^/desktop/\w+\.php$'))&lt;br /&gt;    return map(lambda a:images(urljoin(url, a.get('href'))), a[:4])&lt;br /&gt;&lt;br /&gt;print pages(sys.argv[1])&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;前回の設定を引き継ぎ、上記のようなコードを書けば一覧が取得できます。&lt;br /&gt;% python wally.py http://www.backgroundsarchive.com/desktop/|xargs -n1 -P6 wget&lt;br /&gt;このコマンドがが動いて、取得してくるように変更することは難しいことではないでしょう。&lt;br /&gt;&lt;br /&gt;しかし、このコマンドは遅いですね。&lt;br /&gt;ダウンロードリストを生成する時間がかかりすぎです。&lt;br /&gt;Python内でもスレッドを使いたい。&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;そして本題&lt;br /&gt;これが書きたかっただけですが、前置き長い。&lt;br /&gt;&lt;br /&gt;まずは、Queue。&lt;br /&gt;Queue#getが呼ばれると待ちます。&lt;br /&gt;中身が入るまで、死ぬまで待ち続けます。&lt;br /&gt;中身が入ったら、嬉々として値を返します。&lt;br /&gt;格納できる値はひとつずつです。&lt;br /&gt;複数の値を入れたい場合は、タプルを使います。&lt;br /&gt;これを利用して、Queueに呼び出してほしい関数と引数をタプルにして詰め込んでやります。&lt;br /&gt;そして一定数のスレッドを、Queueから取り出しては実行する無限ループにします。&lt;br /&gt;これでThreadPool完成です。&lt;br /&gt;実装してみましょう。&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;import sys, re, urllib&lt;br /&gt;from urlparse import urlparse, urljoin&lt;br /&gt;from Queue import Queue&lt;br /&gt;from threading import Thread, Lock&lt;br /&gt;from BeautifulSoup import BeautifulSoup&lt;br /&gt;THREAD_MAX = 6&lt;br /&gt;class FFURLopener(urllib.FancyURLopener):&lt;br /&gt;    version = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5'&lt;br /&gt;urllib._urlopener = FFURLopener()&lt;br /&gt;q = Queue()&lt;br /&gt;&lt;br /&gt;def download(url):&lt;br /&gt;    print 'down  '+url&lt;br /&gt;    urllib.urlretrieve(url, url[url.rfind('/')+1:])&lt;br /&gt;&lt;br /&gt;def parse(url):&lt;br /&gt;    print 'parse '+url&lt;br /&gt;    soup = BeautifulSoup(urllib.urlopen(url).read())&lt;br /&gt;    a = soup('a', href=re.compile(r'^/images/pub/\d+/\w+\.jpg$'))&lt;br /&gt;    q.put((download, urljoin(url, a[-1].get('href'))))&lt;br /&gt;&lt;br /&gt;def images(url):&lt;br /&gt;    print 'image '+url&lt;br /&gt;    soup = BeautifulSoup(urllib.urlopen(url).read())&lt;br /&gt;    a = soup('a', {'class':'image_a'}, href=re.compile(r'^/backgrounds/\d+$'))&lt;br /&gt;    map(lambda a:q.put((parse, urljoin(url, a.get('href')))), a[:3])&lt;br /&gt;&lt;br /&gt;def pages(url):&lt;br /&gt;    print 'pages '+url&lt;br /&gt;    soup = BeautifulSoup(urllib.urlopen(url).read())&lt;br /&gt;    a = soup('a', href=re.compile(r'^/desktop/\w+\.php$'))&lt;br /&gt;    map(lambda a:q.put((images, urljoin(url, a.get('href')))), a[:4])&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    def loop():&lt;br /&gt;        while 1:&lt;br /&gt;            func, args = q.get()&lt;br /&gt;            try:&lt;br /&gt;                func(args)&lt;br /&gt;            except Exception, e:&lt;br /&gt;                print e&lt;br /&gt;            finally:&lt;br /&gt;                q.task_done()&lt;br /&gt;    for i in range(THREAD_MAX):&lt;br /&gt;        w = Thread(target=loop)&lt;br /&gt;        w.daemon = True&lt;br /&gt;        w.start()&lt;br /&gt;    pages(sys.argv[1])&lt;br /&gt;    q.join()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;これで4ジャンルから3枚ずつ最大サイズを取得します。&lt;br /&gt;&lt;br /&gt;問題がいくつかあります。&lt;br /&gt; 1. タプル&lt;br /&gt; 2. 出力の乱れ&lt;br /&gt;&lt;br /&gt;まずタプル。&lt;br /&gt;読みづらいですね。&lt;br /&gt;私はたいてい括弧を読み飛ばしてしまい、悩みます。&lt;br /&gt;あと、引数の数の変更にも対応できません。&lt;br /&gt;&lt;br /&gt;q.put((func, [a1], {}))&lt;br /&gt;と&lt;br /&gt;func, args, kwargs = q.get()&lt;br /&gt;func(*args, **kwargs)&lt;br /&gt;にすれば引数に対応できますが、煩雑です。&lt;br /&gt;ここは、ラッパーを書きましょう。&lt;br /&gt;&lt;br /&gt;次へ続く&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-3177397287924241047?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/3177397287924241047/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=3177397287924241047' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3177397287924241047'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3177397287924241047'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/01/download-mass-images-2.html' title='download mass images 2'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-4278115980675889794</id><published>2009-01-13T11:54:00.002+09:00</published><updated>2009-01-13T11:57:21.313+09:00</updated><title type='text'>rst2a</title><content type='html'>&lt;a href="http://code.google.com/p/django-lock/"&gt;django-lock&lt;/a&gt;のトップページで使われていたのを見て知った。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://rst2a.com/"&gt;rst2a&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;reStructuredTextをHTMLやPDFに変換してくれるサービス。&lt;br /&gt;&lt;br /&gt;そこのAPIを使ってこんなブックマークがあると便利。&lt;br /&gt;&lt;a href="javascript:location.href='http://api.rst2a.com/1.0/rst2/html?uri='+location.href"&gt;rst2html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-4278115980675889794?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/4278115980675889794/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=4278115980675889794' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/4278115980675889794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/4278115980675889794'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/01/rst2a.html' title='rst2a'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-3775672397009102168</id><published>2009-01-09T20:57:00.002+09:00</published><updated>2009-01-09T20:59:22.239+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>download mass images 1</title><content type='html'>突然壁紙がたくさんほしくなったので、&lt;br /&gt;&lt;a href="http://www.backgroundsarchive.com/desktop/"&gt;壁紙がいっぱい集まっているところ&lt;/a&gt;からちょいといただきます。&lt;br /&gt;&lt;br /&gt;少し眺めていれば、以下のURLのように連番が発見できます。&lt;br /&gt;http://www.backgroundsarchive.com/backgrounds/9124&lt;br /&gt;&lt;br /&gt;まあ、ざっと見て20000以下なので、そこからbashを使います。&lt;br /&gt;まずは10ほどで試してみましょう。&lt;br /&gt;% echo http://www.backgroundsarchive.com/backgrounds/{1..10}&lt;br /&gt;なんかたくさん表示されましたね。&lt;br /&gt;OK、続けて&lt;br /&gt;% echo http://www.backgroundsarchive.com/backgrounds/{1..10}|xargs -n1 echo&lt;br /&gt;Bravo! これで分かりましたね。&lt;br /&gt;&lt;br /&gt;あとはBeautifulSoupでいただいてしまいましょう。&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;import sys, re, urllib&lt;br /&gt;from urlparse import urlparse, urljoin&lt;br /&gt;from BeautifulSoup import BeautifulSoup&lt;br /&gt;&lt;br /&gt;def download(url):&lt;br /&gt;   print 'down  '+url&lt;br /&gt;   urllib.urlretrieve(url, url[url.rfind('/')+1:])&lt;br /&gt;&lt;br /&gt;def parse(url):&lt;br /&gt;   print 'parse '+url&lt;br /&gt;   soup = BeautifulSoup(urllib.urlopen(url).read())&lt;br /&gt;   a = soup('a', href=re.compile(r'^/images/pub/\d+/\w+\.jpg$'))&lt;br /&gt;   map(lambda a:download(urljoin(url, a.get('href'))), a)&lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;   parse(sys.argv[1])&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;wally.pyとでも命名して即実行。&lt;br /&gt;% time echo http://www.backgroundsarchive.com/backgrounds/{1..10}|xargs -n1 python wally.py&lt;br /&gt;echo http://www.backgroundsarchive.com/backgrounds/{1..10}  0.00s user 0.00s system 42% cpu 0.001 total&lt;br /&gt;xargs -n1 python wally.py  1.52s user 0.84s system 3% cpu 1:16.55 total&lt;br /&gt;うーむ、信じられないほど遅い。&lt;br /&gt;ブラウザだと少し早いからUAによる制限でしょうか。&lt;br /&gt;まあ、しょうがない。&lt;br /&gt;&lt;br /&gt;同時にダウンロードしちゃえば早いじゃんというのは自然な発想です。&lt;br /&gt;コネクションが多すぎるとダメって聞いたことがあるので6つぐらいにしましょう。&lt;br /&gt;% time echo http://www.backgroundsarchive.com/backgrounds/{1..10}|xargs -n1 -P6 python wally.py&lt;br /&gt;echo http://www.backgroundsarchive.com/backgrounds/{1..10}  0.00s user 0.00s system 40% cpu 0.001 total&lt;br /&gt;xargs -n1 -P6 python wally.py  1.48s user 1.45s system 11% cpu 26.645 total&lt;br /&gt;これで六本同時に走ります。&lt;br /&gt;うん、多少早くなりましたね。&lt;br /&gt;&lt;br /&gt;念のため、User-Agentをかえてみます。&lt;br /&gt;こんなのをimport urllibの下に書いておけばいいでしょう。&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;class FFURLopener(urllib.FancyURLopener):&lt;br /&gt;    version = 'Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5'&lt;br /&gt;urllib._urlopener = FFURLopener()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;そして実行&lt;br /&gt;% time echo http://www.backgroundsarchive.com/backgrounds/{1..10}|xargs -n1 -P6 python wally.py&lt;br /&gt;echo http://www.backgroundsarchive.com/backgrounds/{1..10}  0.00s user 0.00s system 45% cpu 0.001 total&lt;br /&gt;xargs -n1 -P6 python wally.py  1.52s user 1.32s system 82% cpu 3.428 total&lt;br /&gt;げええ。&lt;br /&gt;というわけで最適化に教科書なし。&lt;br /&gt;遅いところに適切に対応しましょう。&lt;br /&gt;&lt;br /&gt;さて、単純な連番ならこれでいいのですが、今回は全件取るつもりはありません。&lt;br /&gt;序盤を集めたところマーブルばっかりで、動物とか風景がもっとほしい。&lt;br /&gt;トップ画面からクロールしてほしい画像の一覧を作ったほうが好みの画像が集まりそうです。&lt;br /&gt;トップページを見ると21ジャンルほどありますね。&lt;br /&gt;巡回して21ジャンルから100枚ずつぐらいのリストを作るプログラムを書いて、&lt;br /&gt;% python wally.py http://www.backgroundsarchive.com/desktop/|xargs -n1 -P6 wget&lt;br /&gt;でうまくいきそうです。&lt;br /&gt;&lt;br /&gt;予想外に長くなってしまってので次回へ続く。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-3775672397009102168?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/3775672397009102168/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=3775672397009102168' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3775672397009102168'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/3775672397009102168'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/01/download-mass-images-1.html' title='download mass images 1'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-5743109781357007992</id><published>2009-01-08T14:01:00.007+09:00</published><updated>2009-01-08T15:29:33.645+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Ajax file upload</title><content type='html'>&lt;a href="http://hg.piranha.org.ua/byteflow/file/tip/apps/lib/decorators.py"&gt;byteflowのデコレータ&lt;/a&gt;から引用していたけど、FileUploadに対応させました。&lt;br /&gt;&lt;br /&gt;Ajaxでは&lt;br /&gt;request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'&lt;br /&gt;が成り立つのですが、FileUploadはiframeを使いますのでつきません。&lt;br /&gt;iframeでsubmitした場合、application/jsonにすると、ダウンロードが始まってしまうため、逃げます。&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;def ajax_request(func):&lt;br /&gt;    def wrapper(request, *args, **kw):&lt;br /&gt;        if request.method == 'POST':&lt;br /&gt;            response = func(request, *args, **kw)&lt;br /&gt;        else:&lt;br /&gt;            response = {'error': {'type': 403,&lt;br /&gt;                'message':'Accepts only POST request'}}&lt;br /&gt;        if isinstance(response, dict):&lt;br /&gt;            if request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest':&lt;br /&gt;                class JsonResponse(HttpResponse):&lt;br /&gt;                    def __init__(self, data):&lt;br /&gt;                        super(JsonResponse, self).__init__(&lt;br /&gt;                                content=simplejson.dumps(data),&lt;br /&gt;                                mimetype='application/json')&lt;br /&gt;                return JsonResponse(response)&lt;br /&gt;            else:&lt;br /&gt;                # for file upload&lt;br /&gt;                class IframeResponse(HttpResponse):&lt;br /&gt;                    def __init__(self, data):&lt;br /&gt;                        super(IframeResponse, self).__init__(&lt;br /&gt;                                content='&lt;textarea&gt;%s&lt;/textarea&gt;'%simplejson.dumps(data))&lt;br /&gt;                return IframeResponse(response)&lt;br /&gt;        else:&lt;br /&gt;            return response&lt;br /&gt;    return wraps(func)(wrapper)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://malsup.com/jquery/form/"&gt;jquery.form.js&lt;/a&gt;を使うと、具合が大変よろしいです。&lt;br /&gt;&lt;pre name="code" class="javascript"&gt;&lt;br /&gt;    $('#image_form').ajaxForm({&lt;br /&gt;        dataType: 'json',&lt;br /&gt;        beforeSubmit: function() {if (!$('#icon').val()) return false},&lt;br /&gt;        success: function(data) { render(data) },&lt;br /&gt;        resetForm: true&lt;br /&gt;    })&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;dataTypeは'json'で。&lt;br /&gt;beforeSubmitの第1引数のformDataはnameで引けないので不便。&lt;br /&gt;第2引数のjqFormで、jqForm[0].icon.valueでもOK。&lt;br /&gt;もっといい指定方法は知りたい。&lt;br /&gt;clearFormがなぜか効かなかったのでresetForm。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://malsup.com/jquery/block/"&gt;jquery.blockUI.js&lt;/a&gt;で画像選択やアップロード画面を出すときれい。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jquery.com/"&gt;jquery.js&lt;/a&gt;必須&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-5743109781357007992?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/5743109781357007992/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=5743109781357007992' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5743109781357007992'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5743109781357007992'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/01/ajax-file-upload.html' title='Ajax file upload'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-5094861145450723302</id><published>2009-01-08T13:38:00.002+09:00</published><updated>2009-01-08T13:39:07.616+09:00</updated><title type='text'>ブログ作成3個のヒント</title><content type='html'>&lt;a href="http://www.smashingmagazine.com/2009/01/07/10-killer-wordpress-hacks/"&gt;10 Killer WordPress Hacks&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;1. 広告は検索エンジンからの訪問にのみ表示しろ&lt;br /&gt;ブックマークから来る人は広告なんて見ない、押さない。&lt;br /&gt;でもどうせRSSで読むから関係ないけど。&lt;br /&gt;&lt;br /&gt;2. 連投を防げ&lt;br /&gt;連投かっこ悪い。&lt;br /&gt;でもどうせならタイトルをSlugFieldとかにして、同じタイトルのものがないほうがインデックスとかもろもろで気持ちいいな。&lt;br /&gt;&lt;br /&gt;3. NextやPrevはやめて、Paginationにしよう。&lt;br /&gt;1,2,3,...Lastみたいなやつね。&lt;br /&gt;AutoPagerが効かなくなる可能性がありそうだけど、&amp;lt;link rel="next"&amp;gt;とかに対応してくれたら幸せだね。&lt;br /&gt;&lt;br /&gt;など。&lt;br /&gt;ほかはどうでもよかった。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-5094861145450723302?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/5094861145450723302/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=5094861145450723302' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5094861145450723302'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5094861145450723302'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/01/3.html' title='ブログ作成3個のヒント'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-1153000131919256488</id><published>2009-01-05T19:19:00.002+09:00</published><updated>2009-01-05T19:28:08.865+09:00</updated><title type='text'>Waf</title><content type='html'>&lt;a href="http://d.hatena.ne.jp/hayamiz/20081203/1228296644"&gt;OMake つかったらC言語でプログラム書く手間がバカみたいに減った&lt;/a&gt;&lt;br /&gt;いまさらだけど、それWafでできるよ&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-1153000131919256488?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/1153000131919256488/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=1153000131919256488' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1153000131919256488'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1153000131919256488'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2009/01/waf.html' title='Waf'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-5476511040666716874</id><published>2008-12-07T23:53:00.005+09:00</published><updated>2009-01-05T15:43:11.785+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Guido's new method definition idea</title><content type='html'>&lt;a href="http://groups.google.com/group/comp.lang.python/browse_thread/thread/5457b8649040f7ea?hl=en"&gt;http://groups.google.com/group/comp.lang.python/browse_thread/thread/5457b8649040f7ea&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;最近のホットな話題&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;class C:&lt;br /&gt;   def self.method( arg ):&lt;br /&gt;       self.value = arg&lt;br /&gt;       return self.value&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;というシンタックスシュガーを3.1で入れようかっていう話題。&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;self.method = lambda arg: foo(arg)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;に似てていいじゃんってな意見もある。&lt;br /&gt;ただ、そこから、Rubyチックにしろとかみんながすき放題言いまくって大盛況。&lt;br /&gt;とりあえず、現時点ではまとめ人おつ。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-5476511040666716874?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/5476511040666716874/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=5476511040666716874' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5476511040666716874'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5476511040666716874'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2008/12/guidos-new-method-definition-idea.html' title='Guido&apos;s new method definition idea'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-7732279137119844700</id><published>2008-12-04T23:42:00.001+09:00</published><updated>2008-12-04T23:49:04.975+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>Pythonの配列操作</title><content type='html'>&lt;a href="http://d.hatena.ne.jp/tachikawa844/20081204/1228381610"&gt;http://d.hatena.ne.jp/tachikawa844/20081204/1228381610&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;joinについては&lt;br /&gt;",".join(str(s) for s in score)&lt;br /&gt;か&lt;br /&gt;",".join(map(lambda s:str(s), score))&lt;br /&gt;が主流なはず&lt;br /&gt;&lt;br /&gt;あと、&lt;br /&gt;spliceについて&lt;br /&gt;removed = array[1:5]&lt;br /&gt;array[1:5] = xyz&lt;br /&gt;とすれば実現できるはずだけど、1:5の指定を一度にしたいなー。&lt;br /&gt;よく考えたら配列の切り出しと改変を両方行っているわけか。&lt;br /&gt;こんな風に使ったことがないけど、どういうときに便利なんだろうか。&lt;br /&gt;spliceって変な関数だな。&lt;br /&gt;あ、popと一緒か。&lt;br /&gt;でも代入だしなー。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-7732279137119844700?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/7732279137119844700/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=7732279137119844700' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/7732279137119844700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/7732279137119844700'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2008/12/python.html' title='Pythonの配列操作'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-5017928648260455116</id><published>2008-12-04T15:09:00.002+09:00</published><updated>2008-12-04T15:29:11.941+09:00</updated><title type='text'>tailfでエンコード</title><content type='html'>&lt;pre&gt;tailf log|iconv -feucjp -tutf8&lt;/pre&gt;&lt;br /&gt;ではバッファリングされて出力されない。&lt;br /&gt;&lt;br /&gt;nkfがあれば&lt;br /&gt;&lt;pre&gt;tailf log|nkf -wu&lt;/pre&gt;&lt;br /&gt;perlがあれば&lt;br /&gt;&lt;pre&gt;tailf log|perl -MEncode -pe'$_=decode('eucjp',$_)'&lt;/pre&gt;&lt;br /&gt;シェルでがんばるなら&lt;br /&gt;&lt;pre&gt;tailf log|while read LINE;do echo $LINE|iconv -feucjp -tutf8;done&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;iconvにnobufオプションがほしい&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-5017928648260455116?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/5017928648260455116/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=5017928648260455116' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5017928648260455116'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5017928648260455116'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2008/12/tailf.html' title='tailfでエンコード'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-1954291608778173369</id><published>2008-11-21T13:59:00.011+09:00</published><updated>2009-01-05T15:44:06.133+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='urllib'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>python urllib.urlretrieve で進捗表示しつつダウンロードのメモ</title><content type='html'>&lt;pre name="code" class="python"&gt;&lt;br /&gt;import sys&lt;br /&gt;import urllib&lt;br /&gt;&lt;br /&gt;def _reporthook(blocknum, bs, size):&lt;br /&gt;    sys.stdout.write("%4d%%\r"%(blocknum*bs*100/size))&lt;br /&gt;    sys.stdout.flush()&lt;br /&gt;&lt;br /&gt;if __name__ == "__main__":&lt;br /&gt;    uri = sys.argv[1]&lt;br /&gt;    dest = uri[uri.rfind('/')+1:]&lt;br /&gt;    urllib.urlretrieve(uri, dest, _reporthook)&lt;br /&gt;    print&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;参考: &lt;a href="http://subtech.g.hatena.ne.jp/cho45/20081120/1227178806"&gt;http://subtech.g.hatena.ne.jp/cho45/20081120/1227178806&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blog.livedoor.jp/dankogai/archives/51141631.html"&gt;http://blog.livedoor.jp/dankogai/archives/51141631.html&lt;/a&gt;&lt;br /&gt;printfやputsはflushいらんの？&lt;br /&gt;pythonはprintでもダメだった&lt;br /&gt;よくわからない&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-1954291608778173369?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/1954291608778173369/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=1954291608778173369' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1954291608778173369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/1954291608778173369'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2008/11/python-urlliburlretrieve.html' title='python urllib.urlretrieve で進捗表示しつつダウンロードのメモ'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-126397468209927677</id><published>2008-07-30T13:54:00.005+09:00</published><updated>2008-07-30T15:07:04.037+09:00</updated><title type='text'>傷んだ野菜は大嫌い</title><content type='html'>&lt;a href="http://mono.kmc.gr.jp/~yhara/d/?date=20080730#p01"&gt;http://mono.kmc.gr.jp/~yhara/d/?date=20080730#p01&lt;/a&gt;&lt;br /&gt;天才発見。&lt;br /&gt;帰ったら即、携帯メール=&gt;Gmail=&gt;iCalのPyhabuプラグインを書く。&lt;br /&gt;収納場所も書けるかも。&lt;br /&gt;いろいろ応用範囲が広そうだな。&lt;br /&gt;&lt;a href="http://codespeak.net/icalendar/"&gt;http://codespeak.net/icalendar/&lt;/a&gt;&lt;br /&gt;このライブラリは使えるかな？&lt;br /&gt;&lt;br /&gt;RTMみたいなあいまいな日付解析ライブラリはないかな。&lt;br /&gt;数値のみ入力可能にして&lt;br /&gt;2桁以下 =&gt; 当日以降でもっとも近いn日&lt;br /&gt;4桁以下 =&gt; mmdd&lt;br /&gt;5桁 =&gt; Ymmddで、Y年後のmmdd&lt;br /&gt;6桁以上 =&gt; YYmmdd&lt;br /&gt;が妥当かな。&lt;br /&gt;5桁を入れるか悩ましい。&lt;br /&gt;&lt;br /&gt;これを機会にレシート打ち込んで家計簿作るかな。&lt;br /&gt;やっぱ面倒だから無理&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-126397468209927677?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/126397468209927677/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=126397468209927677' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/126397468209927677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/126397468209927677'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2008/07/blog-post_30.html' title='傷んだ野菜は大嫌い'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-2417544872459238685</id><published>2008-07-08T10:39:00.003+09:00</published><updated>2009-01-05T15:44:27.232+09:00</updated><title type='text'>Djangoとメールサーバ</title><content type='html'>簡易なSMTPDを作った。&lt;br /&gt;appname/management/commands/smtpd.py&lt;br /&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;class Command(BaseCommand):&lt;br /&gt;    def handle(self, *args, **options):&lt;br /&gt;        daemon_kwargs = {}&lt;br /&gt;        daemon_kwargs['out_log'] = options.get('outlog', 'smtp_out.log')&lt;br /&gt;        daemon_kwargs['err_log'] = options.get('errlog', 'smtp_err.log')&lt;br /&gt;        from django.utils.daemonize import become_daemon&lt;br /&gt;        become_daemon(**daemon_kwargs)&lt;br /&gt;&lt;br /&gt;        foo = MySMTPServer((settings.EMAIL_HOST, settings.EMAIL_PORT),&lt;br /&gt;                (settings.PARENT_SMTP_HOST, settings.PARENT_SMTP_PORT))&lt;br /&gt;        try:&lt;br /&gt;            asyncore.loop()&lt;br /&gt;        except KeyboardInterrupt:&lt;br /&gt;            pass&lt;br /&gt;class MySMTPServer(smtpd.SMTPServer):&lt;br /&gt;    def process_message(self, peer, mailfrom, rcpttos, data):&lt;br /&gt;        """ なんか素敵なことをする """&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;たった1行でDaemon化できるのが素敵。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-2417544872459238685?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/2417544872459238685/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=2417544872459238685' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/2417544872459238685'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/2417544872459238685'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2008/07/django.html' title='Djangoとメールサーバ'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-5722414119625765248</id><published>2008-07-05T12:40:00.004+09:00</published><updated>2008-07-05T12:45:40.293+09:00</updated><title type='text'>数字キーと記号を入れ替える</title><content type='html'>&lt;a href="http://dev.ariel-networks.com/Members/matsuyama/keyboard-customize"&gt;キーボードカスタマイズの魅力&lt;/a&gt;&lt;br /&gt;数字と記号を入れ替えるとは。&lt;br /&gt;思いついたことはあったけど、やっている人がいるとは思わなかった。&lt;br /&gt;窓使いの憂鬱で設定してみたが、使いづらい。&lt;br /&gt;一週間使ってみる。&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;# SandS SpaceをShiftとして使う。押しっぱなしで取り消し&lt;br /&gt;mod shift += !!space&lt;br /&gt;key R-*Space = &amp;amp;Ignore&lt;br /&gt;&lt;br /&gt;# 数字を記号と入れ替え&lt;br /&gt;key _1 = $EXCLAMATION_MARK&lt;br /&gt;key _2 = $QUOTATION_MARK&lt;br /&gt;key _3 = $NUMBER_SIGN&lt;br /&gt;key _4 = $DOLLAR_SIGN&lt;br /&gt;key _5 = $PERCENT_SIGN&lt;br /&gt;key _6 = $AMPERSAND&lt;br /&gt;key _7 = $APOSTROPHE&lt;br /&gt;key _8 = $LEFT_PARENTHESIS&lt;br /&gt;key _9 = $RIGHT_PARENTHESIS&lt;br /&gt;key _0 = BackSpace&lt;br /&gt;key S-*_1 = _1&lt;br /&gt;key S-*_2 = _2&lt;br /&gt;key S-*_3 = _3&lt;br /&gt;key S-*_4 = _4&lt;br /&gt;key S-*_5 = _5&lt;br /&gt;key S-*_6 = _6&lt;br /&gt;key S-*_7 = _7&lt;br /&gt;key S-*_8 = _8&lt;br /&gt;key S-*_9 = _9&lt;br /&gt;key S-*_0 = _0&lt;br /&gt;&lt;br /&gt;# via t.masui&lt;br /&gt;key semicolon = Enter&lt;br /&gt;# 右下の\をセミコロンに&lt;br /&gt;key BackSlash = semicolon&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="display: none;" id="FLASH_MESSAGE"&gt;&lt;/div&gt;&lt;div style="display: none;" id="FLASH_MESSAGE"&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-5722414119625765248?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/5722414119625765248/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=5722414119625765248' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5722414119625765248'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5722414119625765248'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2008/07/blog-post.html' title='数字キーと記号を入れ替える'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-4137831101198377496</id><published>2008-06-23T13:43:00.001+09:00</published><updated>2008-06-23T13:45:30.141+09:00</updated><title type='text'>ぐぐらんとす</title><content type='html'>&lt;a href="http://satoshi.blogs.com/life/2008/06/post-2.html"&gt;http://satoshi.blogs.com/life/2008/06/post-2.html&lt;/a&gt;&lt;br /&gt;回答を、楽をして手に入れることがなぜいけないの？&lt;br /&gt;&lt;br /&gt;時代が違うから課題の出し方を変えればいいのに。&lt;br /&gt;ぐぐること前提で、それでヒットすることに対する意見とか。&lt;br /&gt;得られる知識の不備を予測して出題するとか。&lt;br /&gt;&lt;br /&gt;出題者がぐぐり不足ではないのかな。&lt;br /&gt;なぜ調べて出てくるようなことを求めるのか。&lt;br /&gt;&lt;br /&gt;&lt;div style="display: none;" id="FLASH_MESSAGE"&gt;&lt;/div&gt;&lt;div style="display: none;" id="FLASH_MESSAGE"&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-4137831101198377496?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/4137831101198377496/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=4137831101198377496' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/4137831101198377496'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/4137831101198377496'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2008/06/blog-post.html' title='ぐぐらんとす'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-5530527197105985379</id><published>2008-06-20T15:06:00.001+09:00</published><updated>2008-06-20T15:09:52.283+09:00</updated><title type='text'>VimのPythonコメント</title><content type='html'>vimでPython編集中にコメントを入力しようと"#"を入力すると、行頭にカーソルが移動してしまう。&lt;br /&gt;&lt;br /&gt;~/.vim/indent/python.vimに以下を入力すれば、適切な位置でコメントを書ける。&lt;br /&gt;&lt;br /&gt; setlocal indentkeys=!^F,o,O,&lt;:&gt;,0),0],0},=elif,=except,0#&lt;br /&gt;&lt;br /&gt;via http://henry.precheur.org/2008/4/18/Indenting%20Python%20with%20VIM.html&lt;br /&gt;&lt;div style="display: none;" id="FLASH_MESSAGE"&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-5530527197105985379?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/5530527197105985379/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=5530527197105985379' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5530527197105985379'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5530527197105985379'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2008/06/vimpython.html' title='VimのPythonコメント'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-5712183483521777963</id><published>2008-06-11T12:40:00.004+09:00</published><updated>2009-01-05T20:52:38.804+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>netmask</title><content type='html'>IPアドレスの制限で、ネットマスクの対応が見つからなかった。&lt;br /&gt;128.255.63.0/24なら&lt;br /&gt;アドレスを16進数に直して80ff3f00と2**24-1&lt;&lt;(32-24) &amp;amp; targetを比較すればいいのかな？ &lt;br /&gt;&lt;br /&gt;式はいくつか思いつくけど、正攻法はどんなものだろうか。&lt;br /&gt;&lt;ul&gt;&lt;li&gt;2**32-(1&amp;lt;&amp;lt;32-m)&lt;/li&gt;&lt;li&gt;2**m-1&amp;lt;&amp;lt;32-m&lt;/li&gt;&lt;/ul&gt;&lt;pre name="code" class="python"&gt;&lt;br /&gt;def ip_valid(addr):&lt;br /&gt;  for s in IP_RANGE:&lt;br /&gt;    t = s.split('/')&lt;br /&gt;    if len(t) == 1:&lt;br /&gt;      ip = t[0]&lt;br /&gt;      mask = '32'&lt;br /&gt;    else:&lt;br /&gt;      ip = t[0]&lt;br /&gt;      mask = t[1]&lt;br /&gt;    mask = int(mask)&lt;br /&gt;    n = ip2num(ip)&lt;br /&gt;    if ip2num(addr) &amp;amp; 2**32-(1&lt;&lt;32-mask) == n:&lt;br /&gt;      return True&lt;br /&gt;  return False&lt;br /&gt;&lt;br /&gt;def ip2num(ip):&lt;br /&gt;    n = 0&lt;br /&gt;    for i in ip.split('.'):&lt;br /&gt;        n &lt;&lt;= 8&lt;br /&gt;        n += int(i)&lt;br /&gt;    return n&lt;br /&gt;&lt;br /&gt;IP_RANGE = [&lt;br /&gt;'210.153.84.0/24',&lt;br /&gt;'123.108.237.9',&lt;br /&gt;'202.179.204.0/24',&lt;br /&gt;'61.202.3.0/24',&lt;br /&gt;]&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-5712183483521777963?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/5712183483521777963/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=5712183483521777963' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5712183483521777963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/5712183483521777963'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2008/06/netmask.html' title='netmask'/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2101613690891415478.post-8868740225132168172</id><published>2008-06-03T15:00:00.003+09:00</published><updated>2009-01-05T20:51:17.632+09:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='django'/><title type='text'></title><content type='html'>&lt;a href="http://code.google.com/p/django-command-extensions/"&gt;sqldiff&lt;/a&gt;が非常に便利&lt;br /&gt;./manage.py sqldiff appname&lt;br /&gt;とすると、DBとappname/models.pyの相違を表示してくれる。&lt;br /&gt;今まで、models.pyを変更すると差分がつかみづらい部分があったのでこれは便利。&lt;br /&gt;Migrationまでの道のりは遠いけど。&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.aswmc.com/dbmigration/"&gt;DBMigration&lt;/a&gt;が使えればもっと便利なんだろうけど、とりあえずはこれでOK。&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2101613690891415478-8868740225132168172?l=hikozaemonchan.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://hikozaemonchan.blogspot.com/feeds/8868740225132168172/comments/default' title='コメントの投稿'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2101613690891415478&amp;postID=8868740225132168172' title='0 件のコメント'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/8868740225132168172'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2101613690891415478/posts/default/8868740225132168172'/><link rel='alternate' type='text/html' href='http://hikozaemonchan.blogspot.com/2008/06/sqldiff.html' title=''/><author><name>hikozaemonchan</name><uri>http://www.blogger.com/profile/07808894042373160017</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
